Repository: cloudflare/cfssl Branch: master Commit: ed8df4971265 Files: 2240 Total size: 34.6 MB Directory structure: gitextract__9id0mvi/ ├── .dockerignore ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ ├── docker-builds.yml │ ├── go.yml │ ├── semgrep.yml │ └── snapshot.yml ├── .gitignore ├── .golangci.yaml ├── .goreleaser.yml ├── CHANGELOG ├── Dockerfile ├── Dockerfile.alpine ├── LICENSE ├── Makefile ├── README.md ├── api/ │ ├── api.go │ ├── api_test.go │ ├── bundle/ │ │ ├── bundle.go │ │ └── bundle_test.go │ ├── certadd/ │ │ ├── insert.go │ │ └── insert_test.go │ ├── certinfo/ │ │ └── certinfo.go │ ├── client/ │ │ ├── api.go │ │ ├── client.go │ │ ├── client_test.go │ │ └── group.go │ ├── crl/ │ │ ├── crl.go │ │ └── crl_test.go │ ├── gencrl/ │ │ ├── gencrl.go │ │ └── gencrl_test.go │ ├── generator/ │ │ ├── generator.go │ │ ├── generator_test.go │ │ └── testdata/ │ │ ├── ca.pem │ │ └── ca_key.pem │ ├── health/ │ │ └── health.go │ ├── info/ │ │ ├── info.go │ │ └── info_test.go │ ├── initca/ │ │ ├── initca.go │ │ └── initca_test.go │ ├── ocsp/ │ │ ├── ocspsign.go │ │ └── ocspsign_test.go │ ├── revoke/ │ │ ├── revoke.go │ │ └── revoke_test.go │ ├── scan/ │ │ ├── scan.go │ │ └── scan_test.go │ ├── sign/ │ │ ├── sign.go │ │ └── sign_test.go │ ├── signhandler/ │ │ ├── signhandler.go │ │ └── signhandler_test.go │ └── testdata/ │ ├── broken.pem │ ├── broken_csr.pem │ ├── ca-bundle.pem │ ├── ca.pem │ ├── ca2-key.pem │ ├── ca2.pem │ ├── ca_key.pem │ ├── cert.pem │ ├── csr.pem │ ├── int-bundle.pem │ ├── leaf.badkey │ ├── leaf.key │ └── leaf.pem ├── auth/ │ ├── auth.go │ ├── auth_test.go │ └── testdata/ │ ├── authrequest.json │ └── request.json ├── bundler/ │ ├── bundle.go │ ├── bundle_from_file_test.go │ ├── bundle_from_pem_test.go │ ├── bundle_from_remote_test.go │ ├── bundler.go │ ├── bundler_sha1_deprecation_test.go │ ├── bundler_test.go │ ├── doc.go │ └── testdata/ │ ├── bad-bundle.pem │ ├── ca-bundle.crt.metadata │ ├── ca-bundle.pem │ ├── ca.key │ ├── ca.pem │ ├── cfssl-leaf-ecdsa256.csr │ ├── cfssl-leaf-ecdsa256.key │ ├── cfssl-leaf-ecdsa256.pem │ ├── cfssl-leaf-ecdsa384.csr │ ├── cfssl-leaf-ecdsa384.key │ ├── cfssl-leaf-ecdsa384.pem │ ├── cfssl-leaf-ecdsa521.csr │ ├── cfssl-leaf-ecdsa521.key │ ├── cfssl-leaf-ecdsa521.pem │ ├── cfssl-leaf-rsa2048.csr │ ├── cfssl-leaf-rsa2048.key │ ├── cfssl-leaf-rsa2048.pem │ ├── cfssl-leaf-rsa3072.csr │ ├── cfssl-leaf-rsa3072.key │ ├── cfssl-leaf-rsa3072.pem │ ├── cfssl-leaf-rsa4096.csr │ ├── cfssl-leaf-rsa4096.key │ ├── cfssl-leaf-rsa4096.pem │ ├── cfssl-leaflet-rsa4096.pem │ ├── client-auth/ │ │ ├── build_certs.sh │ │ ├── int-config.json │ │ ├── int-csr.json │ │ ├── int.pem │ │ ├── leaf-client-csr.json │ │ ├── leaf-client.pem │ │ ├── leaf-server-csr.json │ │ ├── leaf-server.pem │ │ ├── root-config.json │ │ ├── root-csr.json │ │ └── root.pem │ ├── dsa2048.key │ ├── dsa2048.pem │ ├── empty.pem │ ├── forcebundle.pem │ ├── froyo.pem │ ├── int-bundle.pem │ ├── inter-L1-expired.pem │ ├── inter-L1-sha1.pem │ ├── inter-L1.csr │ ├── inter-L1.key │ ├── inter-L1.pem │ ├── inter-L2-direct.pem │ ├── inter-L2.csr │ ├── inter-L2.key │ ├── inter-L2.pem │ ├── intermediates.crt │ ├── nss.pem │ ├── osx.pem │ ├── partial-bundle.pem │ └── reverse-partial-bundle.pem ├── certdb/ │ ├── README.md │ ├── certdb.go │ ├── dbconf/ │ │ ├── db_config.go │ │ ├── db_config_test.go │ │ └── testdata/ │ │ ├── bad-db-config.json │ │ ├── db-config.json │ │ └── memory_db.json │ ├── mysql/ │ │ ├── dbconf.yml │ │ └── migrations/ │ │ ├── 001_CreateCertificates.sql │ │ └── 002_AddMetadataToCertificates.sql │ ├── ocspstapling/ │ │ ├── ocspstapling.go │ │ └── ocspstapling_test.go │ ├── pg/ │ │ ├── dbconf.yml │ │ └── migrations/ │ │ ├── 001_CreateCertificates.sql │ │ └── 002_AddMetadataToCertificates.sql │ ├── sql/ │ │ ├── database_accessor.go │ │ ├── sql_mysql_test.go │ │ ├── sql_pq_test.go │ │ └── sql_test.go │ ├── sqlite/ │ │ ├── dbconf.yml │ │ └── migrations/ │ │ ├── 001_CreateCertificates.sql │ │ └── 002_AddMetadataToCertificates.sql │ └── testdb/ │ └── testdb.go ├── certinfo/ │ ├── certinfo.go │ └── certinfo_test.go ├── cli/ │ ├── bundle/ │ │ ├── bundle.go │ │ └── bundle_test.go │ ├── certinfo/ │ │ └── certinfo.go │ ├── cli.go │ ├── cli_test.go │ ├── config.go │ ├── crl/ │ │ ├── crl.go │ │ └── crl_test.go │ ├── gencert/ │ │ ├── gencert.go │ │ └── gencert_test.go │ ├── gencrl/ │ │ ├── gencrl.go │ │ ├── gencrl_test.go │ │ └── testdata/ │ │ ├── ca-keyTwo.pem │ │ ├── caTwo.pem │ │ └── serialList │ ├── gencsr/ │ │ ├── gencsr.go │ │ ├── gencsr_test.go │ │ └── testdata/ │ │ ├── csr.json │ │ └── test-key.pem │ ├── genkey/ │ │ ├── genkey.go │ │ ├── genkey_test.go │ │ └── testdata/ │ │ └── csr.json │ ├── info/ │ │ └── info.go │ ├── ocspdump/ │ │ └── ocspdump.go │ ├── ocsprefresh/ │ │ ├── ocsprefresh.go │ │ └── ocsprefresh_test.go │ ├── ocspserve/ │ │ └── ocspserve.go │ ├── ocspsign/ │ │ └── ocspsign.go │ ├── printdefault/ │ │ ├── defaults.go │ │ └── printdefault.go │ ├── revoke/ │ │ ├── revoke.go │ │ └── revoke_test.go │ ├── scan/ │ │ ├── scan.go │ │ └── scan_test.go │ ├── selfsign/ │ │ ├── selfsign.go │ │ └── selfsign_test.go │ ├── serve/ │ │ ├── README.md │ │ ├── serve.go │ │ ├── serve_test.go │ │ └── static/ │ │ ├── assets/ │ │ │ └── cfssl.js │ │ └── index.html │ ├── sign/ │ │ ├── sign.go │ │ └── sign_test.go │ ├── testdata/ │ │ ├── bad_csr.json │ │ ├── bad_oid_csr.json │ │ ├── ca-key.pem │ │ ├── ca.csr │ │ ├── ca.pem │ │ ├── csr.json │ │ ├── db-config.json │ │ └── test.txt │ └── version/ │ ├── version.go │ └── version_test.go ├── cmd/ │ ├── cfssl/ │ │ ├── cfssl.go │ │ └── cfssl_test.go │ ├── cfssl-bundle/ │ │ └── cfssl-bundle.go │ ├── cfssl-certinfo/ │ │ └── cfssl-certinfo.go │ ├── cfssl-newkey/ │ │ └── cfssl-newkey.go │ ├── cfssl-scan/ │ │ └── cfssl-scan.go │ ├── cfssljson/ │ │ ├── cfssljson.go │ │ ├── cfssljson_test.go │ │ └── testdata/ │ │ └── test.txt │ ├── mkbundle/ │ │ ├── cert-bundle.crt │ │ ├── mkbundle.go │ │ └── mkbundle_test.go │ └── multirootca/ │ ├── api.go │ └── ca.go ├── config/ │ ├── config.go │ ├── config_test.go │ └── testdata/ │ ├── invalid_auth.json │ ├── invalid_auth_bad_key.json │ ├── invalid_config.json │ ├── invalid_default.json │ ├── invalid_no_auth_keys.json │ ├── invalid_no_remotes.json │ ├── invalid_profile.json │ ├── invalid_remotes.json │ ├── invalid_usage.json │ ├── valid_config.json │ ├── valid_config_auth.json │ ├── valid_config_auth_no_default.json │ └── valid_config_no_default.json ├── crl/ │ ├── crl.go │ ├── crl_test.go │ └── testdata/ │ ├── ca-key.pem │ ├── ca-keyTwo.pem │ ├── ca.pem │ ├── caTwo.pem │ ├── cert.pem │ ├── serialList │ ├── server.crt │ └── server.key ├── crypto/ │ ├── doc.go │ └── pkcs7/ │ └── pkcs7.go ├── csr/ │ ├── csr.go │ ├── csr_test.go │ └── testdata/ │ └── test-ecdsa-ca.pem ├── doc/ │ ├── README.txt │ ├── api/ │ │ ├── endpoint_authsign.txt │ │ ├── endpoint_bundle.txt │ │ ├── endpoint_certinfo.txt │ │ ├── endpoint_crl.txt │ │ ├── endpoint_health.txt │ │ ├── endpoint_info.txt │ │ ├── endpoint_init_ca.txt │ │ ├── endpoint_newcert.txt │ │ ├── endpoint_newkey.txt │ │ ├── endpoint_revoke.txt │ │ ├── endpoint_scan.txt │ │ ├── endpoint_scaninfo.txt │ │ ├── endpoint_sign.txt │ │ └── intro.txt │ ├── authentication.txt │ ├── ca-bundle.crt.metadata.sample │ ├── cmd/ │ │ ├── cfssl.txt │ │ └── multiroot.txt │ ├── errorcode.txt │ └── transport.txt ├── errors/ │ ├── doc.go │ ├── error.go │ ├── error_test.go │ └── http.go ├── go.mod ├── go.sum ├── helpers/ │ ├── derhelpers/ │ │ ├── derhelpers.go │ │ ├── ed25519.go │ │ └── ed25519_test.go │ ├── helpers.go │ ├── helpers_test.go │ ├── testdata/ │ │ ├── bundle.pem │ │ ├── bundle_pkcs7.pem │ │ ├── bundle_with_whitespace.pem │ │ ├── ca.pem │ │ ├── ca_key.pem │ │ ├── cert.der │ │ ├── cert.pem │ │ ├── cert_pkcs7.pem │ │ ├── cert_with_whitespace.pem │ │ ├── ecdsa256.csr │ │ ├── empty.pem │ │ ├── empty_pkcs7.der │ │ ├── empty_pkcs7.pem │ │ ├── emptycert.pem │ │ ├── emptypasswordpkcs12.p12 │ │ ├── enc_priv_key.pem │ │ ├── messed_up_bundle.pem │ │ ├── messed_up_priv_key.pem │ │ ├── messedupcert.pem │ │ ├── multiplecerts.p12 │ │ ├── noheadercert.pem │ │ ├── openssl_secp384.pem │ │ ├── passwordpkcs12.p12 │ │ ├── priv_rsa_key.pem │ │ ├── private_ecdsa_key.pem │ │ ├── private_ed25519_key.pem │ │ ├── rsa-old.csr │ │ ├── secp256k1-key.pem │ │ ├── test.bad.csr.pem │ │ └── test.csr.pem │ └── testsuite/ │ ├── testdata/ │ │ ├── cert_csr.json │ │ └── initCA/ │ │ ├── ca_csr.json │ │ └── cfssl_output.pem │ ├── testing_helpers.go │ └── testing_helpers_test.go ├── info/ │ └── info.go ├── initca/ │ ├── initca.go │ ├── initca_test.go │ └── testdata/ │ ├── 5min-ecdsa-key.pem │ ├── 5min-ecdsa.pem │ ├── 5min-ed25519-key.pem │ ├── 5min-ed25519.pem │ ├── 5min-rsa-key.pem │ ├── 5min-rsa.pem │ ├── README.md │ ├── ca_csr_ecdsa.json │ ├── ca_csr_ed25519.json │ ├── ca_csr_rsa.json │ ├── ecdsa256.csr │ ├── ecdsa384.csr │ ├── ecdsa521.csr │ ├── ed25519.csr │ ├── rsa2048.csr │ ├── rsa3072.csr │ └── rsa4096.csr ├── log/ │ ├── log.go │ └── log_test.go ├── multiroot/ │ └── config/ │ ├── config.go │ ├── config_test.go │ └── testdata/ │ ├── bad-db-config.json │ ├── bad.conf │ ├── badconfig.json │ ├── config.json │ ├── db-config.json │ ├── roots.conf │ ├── roots_bad_certificate.conf │ ├── roots_bad_db.conf │ ├── roots_bad_private_key.conf │ ├── roots_bad_whitelist.conf │ ├── roots_bad_whitelist2.conf │ ├── roots_badconfig.conf │ ├── roots_badspec.conf │ ├── roots_badspec2.conf │ ├── roots_badspec3.conf │ ├── roots_db.conf │ ├── roots_der.conf │ ├── roots_ksm.conf │ ├── roots_missing_certificate.conf │ ├── roots_missing_certificate_entry.conf │ ├── roots_missing_private.conf │ ├── roots_missing_private_key_entry.conf │ ├── roots_no_kdl_private_key.conf │ ├── roots_whitelist.conf │ ├── roots_whitelist_ipv6.conf │ ├── server.crt │ ├── server.der │ ├── server.key │ ├── test.conf │ └── test2.conf ├── ocsp/ │ ├── config/ │ │ └── config.go │ ├── ocsp.go │ ├── ocsp_test.go │ ├── responder.go │ ├── responder_test.go │ ├── testdata/ │ │ ├── ca-key.pem │ │ ├── ca.pem │ │ ├── cert.pem │ │ ├── db-config.json │ │ ├── resp64.pem │ │ ├── response.der │ │ ├── response_broken.pem │ │ ├── response_mix.pem │ │ ├── server.crt │ │ ├── server.key │ │ ├── server_broken.crt │ │ ├── server_broken.key │ │ └── sqlite_ca.pem │ └── universal/ │ └── universal.go ├── revoke/ │ ├── revoke.go │ └── revoke_test.go ├── scan/ │ ├── broad.go │ ├── connectivity.go │ ├── crypto/ │ │ ├── crypto.go │ │ ├── md5/ │ │ │ ├── example_test.go │ │ │ ├── gen.go │ │ │ ├── md5.go │ │ │ ├── md5_test.go │ │ │ ├── md5block.go │ │ │ ├── md5block_386.s │ │ │ ├── md5block_amd64.s │ │ │ ├── md5block_amd64p32.s │ │ │ ├── md5block_arm.s │ │ │ ├── md5block_decl.go │ │ │ └── md5block_generic.go │ │ ├── rsa/ │ │ │ ├── example_test.go │ │ │ ├── pkcs1v15.go │ │ │ ├── pkcs1v15_test.go │ │ │ ├── pss.go │ │ │ ├── pss_test.go │ │ │ ├── rsa.go │ │ │ ├── rsa_test.go │ │ │ └── testdata/ │ │ │ └── pss-vect.txt.bz2 │ │ ├── sha1/ │ │ │ ├── example_test.go │ │ │ ├── sha1.go │ │ │ ├── sha1_test.go │ │ │ ├── sha1block.go │ │ │ ├── sha1block_386.s │ │ │ ├── sha1block_amd64.s │ │ │ ├── sha1block_amd64p32.s │ │ │ ├── sha1block_arm.s │ │ │ ├── sha1block_decl.go │ │ │ └── sha1block_generic.go │ │ ├── sha256/ │ │ │ ├── sha256.go │ │ │ ├── sha256_test.go │ │ │ ├── sha256block.go │ │ │ ├── sha256block_386.s │ │ │ ├── sha256block_amd64.s │ │ │ └── sha256block_decl.go │ │ ├── sha512/ │ │ │ ├── sha512.go │ │ │ ├── sha512_test.go │ │ │ ├── sha512block.go │ │ │ ├── sha512block_amd64.s │ │ │ └── sha512block_decl.go │ │ └── tls/ │ │ ├── alert.go │ │ ├── cfsslscan_common.go │ │ ├── cfsslscan_handshake.go │ │ ├── cipher_suites.go │ │ ├── common.go │ │ ├── conn.go │ │ ├── conn_test.go │ │ ├── example_test.go │ │ ├── generate_cert.go │ │ ├── handshake_client.go │ │ ├── handshake_client_test.go │ │ ├── handshake_messages.go │ │ ├── handshake_messages_test.go │ │ ├── handshake_server.go │ │ ├── handshake_server_test.go │ │ ├── handshake_test.go │ │ ├── key_agreement.go │ │ ├── prf.go │ │ ├── prf_test.go │ │ ├── testdata/ │ │ │ ├── Client-TLSv10-ClientCert-ECDSA-ECDSA │ │ │ ├── Client-TLSv10-ClientCert-ECDSA-RSA │ │ │ ├── Client-TLSv10-ClientCert-RSA-ECDSA │ │ │ ├── Client-TLSv10-ClientCert-RSA-RSA │ │ │ ├── Client-TLSv10-ECDHE-ECDSA-AES │ │ │ ├── Client-TLSv10-ECDHE-RSA-AES │ │ │ ├── Client-TLSv10-RSA-RC4 │ │ │ ├── Client-TLSv11-ECDHE-ECDSA-AES │ │ │ ├── Client-TLSv11-ECDHE-RSA-AES │ │ │ ├── Client-TLSv11-RSA-RC4 │ │ │ ├── Client-TLSv12-AES128-GCM-SHA256 │ │ │ ├── Client-TLSv12-AES256-GCM-SHA384 │ │ │ ├── Client-TLSv12-ALPN │ │ │ ├── Client-TLSv12-ALPN-NoMatch │ │ │ ├── Client-TLSv12-ClientCert-ECDSA-ECDSA │ │ │ ├── Client-TLSv12-ClientCert-ECDSA-RSA │ │ │ ├── Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 │ │ │ ├── Client-TLSv12-ClientCert-RSA-ECDSA │ │ │ ├── Client-TLSv12-ClientCert-RSA-RSA │ │ │ ├── Client-TLSv12-ECDHE-ECDSA-AES │ │ │ ├── Client-TLSv12-ECDHE-ECDSA-AES-GCM │ │ │ ├── Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 │ │ │ ├── Client-TLSv12-ECDHE-RSA-AES │ │ │ ├── Client-TLSv12-RSA-RC4 │ │ │ ├── Client-TLSv12-SCT │ │ │ ├── Server-SSLv3-RSA-3DES │ │ │ ├── Server-SSLv3-RSA-AES │ │ │ ├── Server-SSLv3-RSA-RC4 │ │ │ ├── Server-TLSv10-ECDHE-ECDSA-AES │ │ │ ├── Server-TLSv10-RSA-3DES │ │ │ ├── Server-TLSv10-RSA-AES │ │ │ ├── Server-TLSv10-RSA-RC4 │ │ │ ├── Server-TLSv11-FallbackSCSV │ │ │ ├── Server-TLSv11-RSA-RC4 │ │ │ ├── Server-TLSv12-ALPN │ │ │ ├── Server-TLSv12-ALPN-NoMatch │ │ │ ├── Server-TLSv12-CipherSuiteCertPreferenceECDSA │ │ │ ├── Server-TLSv12-CipherSuiteCertPreferenceRSA │ │ │ ├── Server-TLSv12-ClientAuthRequestedAndECDSAGiven │ │ │ ├── Server-TLSv12-ClientAuthRequestedAndGiven │ │ │ ├── Server-TLSv12-ClientAuthRequestedNotGiven │ │ │ ├── Server-TLSv12-ECDHE-ECDSA-AES │ │ │ ├── Server-TLSv12-IssueTicket │ │ │ ├── Server-TLSv12-IssueTicketPreDisable │ │ │ ├── Server-TLSv12-RSA-3DES │ │ │ ├── Server-TLSv12-RSA-AES │ │ │ ├── Server-TLSv12-RSA-AES-GCM │ │ │ ├── Server-TLSv12-RSA-AES256-GCM-SHA384 │ │ │ ├── Server-TLSv12-RSA-RC4 │ │ │ ├── Server-TLSv12-Resume │ │ │ ├── Server-TLSv12-ResumeDisabled │ │ │ ├── Server-TLSv12-SNI │ │ │ ├── Server-TLSv12-SNI-GetCertificate │ │ │ └── Server-TLSv12-SNI-GetCertificateNotFound │ │ ├── ticket.go │ │ ├── tls.go │ │ └── tls_test.go │ ├── pki.go │ ├── scan_common.go │ ├── scan_common_test.go │ ├── tls_handshake.go │ └── tls_session.go ├── selfsign/ │ ├── selfsign.go │ ├── selfsign_test.go │ └── testdata/ │ ├── extension.csr │ ├── localhost.csr │ ├── localhost.key │ └── sans.csr ├── signer/ │ ├── local/ │ │ ├── local.go │ │ ├── local_test.go │ │ └── testdata/ │ │ ├── build_inter_pathlen_csrs.sh │ │ ├── ca.pem │ │ ├── ca_key.pem │ │ ├── ecdsa256-inter.csr │ │ ├── ecdsa256-inter.key │ │ ├── ecdsa256.csr │ │ ├── ecdsa256_ca.pem │ │ ├── ecdsa256_ca_key.pem │ │ ├── ecdsa384.csr │ │ ├── ecdsa521.csr │ │ ├── ed25519.csr │ │ ├── ex.csr │ │ ├── inter_pathlen_0.csr │ │ ├── inter_pathlen_1.csr │ │ ├── inter_pathlen_unspecified.csr │ │ ├── ip.csr │ │ ├── key.pem │ │ ├── rsa-old.csr │ │ ├── rsa2048-inter.csr │ │ ├── rsa2048-inter.key │ │ ├── rsa2048.csr │ │ ├── rsa3072.csr │ │ ├── rsa4096.csr │ │ ├── san_domain.csr │ │ └── test.csr │ ├── remote/ │ │ ├── remote.go │ │ ├── remote_test.go │ │ └── testdata/ │ │ ├── README.md │ │ ├── ca.pem │ │ ├── ca_key.pem │ │ ├── client-key.pem │ │ ├── client.json │ │ ├── client.pem │ │ ├── config.json │ │ ├── server-key.pem │ │ ├── server.json │ │ └── server.pem │ ├── signer.go │ ├── signer_test.go │ └── universal/ │ ├── universal.go │ └── universal_test.go ├── test.sh ├── testdata/ │ ├── csr.json │ ├── garbage.crt │ ├── garbage.key │ ├── gd_bundle.crt │ ├── good_config.json │ ├── roots/ │ │ └── httplib2_cacerts.txt │ ├── server.crt │ ├── server.csr │ ├── server.key │ ├── ssl-verifier.sh │ ├── temp.crt │ └── test.py ├── tools.go ├── transport/ │ ├── ca/ │ │ ├── cert_provider.go │ │ ├── cfssl_provider.go │ │ └── localca/ │ │ ├── signer.go │ │ └── signer_test.go │ ├── client.go │ ├── core/ │ │ ├── defs.go │ │ └── rand.go │ ├── doc.go │ ├── example/ │ │ ├── README.md │ │ ├── ca.json │ │ ├── config.json │ │ ├── config_auth.json │ │ ├── exlib/ │ │ │ └── exlib.go │ │ ├── genca.sh │ │ ├── maclient/ │ │ │ ├── client.go │ │ │ ├── client.json │ │ │ └── client_auth.json │ │ └── maserver/ │ │ ├── server.go │ │ ├── server.json │ │ └── server_auth.json │ ├── kp/ │ │ ├── key_provider.go │ │ └── key_provider_test.go │ ├── listener.go │ ├── roots/ │ │ ├── cfssl.go │ │ ├── doc.go │ │ ├── provider.go │ │ └── system/ │ │ ├── nilref_nil_darwin.go │ │ ├── nilref_zero_darwin.go │ │ ├── root.go │ │ ├── root_bsd.go │ │ ├── root_cgo_darwin.go │ │ ├── root_darwin.go │ │ ├── root_darwin_armx.go │ │ ├── root_darwin_test.go │ │ ├── root_linux.go │ │ ├── root_nacl.go │ │ ├── root_nocgo_darwin.go │ │ ├── root_plan9.go │ │ ├── root_solaris.go │ │ ├── root_unix.go │ │ └── root_windows.go │ └── transport_test.go ├── ubiquity/ │ ├── filter.go │ ├── performance.go │ ├── sha1.go │ ├── testdata/ │ │ ├── ca.pem.metadata │ │ ├── ecdsa256sha2.pem │ │ ├── ecdsa384sha2.pem │ │ ├── ecdsa521sha2.pem │ │ ├── godzilla.pem │ │ ├── macrosoft.pem │ │ ├── pineapple.pem │ │ ├── rsa1024sha1.pem │ │ ├── rsa2048sha2.pem │ │ ├── rsa3072sha2.pem │ │ └── rsa4096sha2.pem │ ├── ubiquity_crypto.go │ ├── ubiquity_platform.go │ └── ubiquity_test.go ├── vendor/ │ ├── bitbucket.org/ │ │ └── liamstask/ │ │ └── goose/ │ │ ├── cmd/ │ │ │ └── goose/ │ │ │ ├── cmd.go │ │ │ ├── cmd_create.go │ │ │ ├── cmd_dbversion.go │ │ │ ├── cmd_down.go │ │ │ ├── cmd_redo.go │ │ │ ├── cmd_status.go │ │ │ ├── cmd_up.go │ │ │ └── main.go │ │ └── lib/ │ │ └── goose/ │ │ ├── dbconf.go │ │ ├── dialect.go │ │ ├── migrate.go │ │ ├── migration_go.go │ │ ├── migration_sql.go │ │ └── util.go │ ├── filippo.io/ │ │ └── edwards25519/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── edwards25519.go │ │ ├── extra.go │ │ ├── field/ │ │ │ ├── fe.go │ │ │ ├── fe_amd64.go │ │ │ ├── fe_amd64.s │ │ │ ├── fe_amd64_noasm.go │ │ │ ├── fe_arm64.go │ │ │ ├── fe_arm64.s │ │ │ ├── fe_arm64_noasm.go │ │ │ ├── fe_extra.go │ │ │ └── fe_generic.go │ │ ├── scalar.go │ │ ├── scalar_fiat.go │ │ ├── scalarmult.go │ │ └── tables.go │ ├── github.com/ │ │ ├── beorn7/ │ │ │ └── perks/ │ │ │ ├── LICENSE │ │ │ └── quantile/ │ │ │ ├── exampledata.txt │ │ │ └── stream.go │ │ ├── cespare/ │ │ │ └── xxhash/ │ │ │ └── v2/ │ │ │ ├── LICENSE.txt │ │ │ ├── README.md │ │ │ ├── testall.sh │ │ │ ├── xxhash.go │ │ │ ├── xxhash_amd64.s │ │ │ ├── xxhash_arm64.s │ │ │ ├── xxhash_asm.go │ │ │ ├── xxhash_other.go │ │ │ ├── xxhash_safe.go │ │ │ └── xxhash_unsafe.go │ │ ├── cloudflare/ │ │ │ ├── backoff/ │ │ │ │ ├── .travis.yml │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ └── backoff.go │ │ │ └── redoctober/ │ │ │ ├── LICENSE.md │ │ │ ├── client/ │ │ │ │ └── client.go │ │ │ ├── config/ │ │ │ │ └── config.go │ │ │ ├── core/ │ │ │ │ └── core.go │ │ │ ├── cryptor/ │ │ │ │ └── cryptor.go │ │ │ ├── ecdh/ │ │ │ │ └── ecdh.go │ │ │ ├── hipchat/ │ │ │ │ └── hipchat.go │ │ │ ├── keycache/ │ │ │ │ └── keycache.go │ │ │ ├── msp/ │ │ │ │ ├── README.md │ │ │ │ ├── formatted.go │ │ │ │ ├── matrix.go │ │ │ │ ├── msp.go │ │ │ │ ├── number.go │ │ │ │ └── raw.go │ │ │ ├── order/ │ │ │ │ └── order.go │ │ │ ├── padding/ │ │ │ │ └── padding.go │ │ │ ├── passvault/ │ │ │ │ └── passvault.go │ │ │ ├── persist/ │ │ │ │ ├── file.go │ │ │ │ ├── null.go │ │ │ │ └── persist.go │ │ │ ├── report/ │ │ │ │ └── report.go │ │ │ └── symcrypt/ │ │ │ └── symcrypt.go │ │ ├── getsentry/ │ │ │ └── sentry-go/ │ │ │ ├── .craft.yml │ │ │ ├── .gitattributes │ │ │ ├── .gitignore │ │ │ ├── .golangci.yml │ │ │ ├── CHANGELOG.md │ │ │ ├── CONTRIBUTING.md │ │ │ ├── LICENSE │ │ │ ├── MIGRATION.md │ │ │ ├── README.md │ │ │ ├── client.go │ │ │ ├── doc.go │ │ │ ├── dsn.go │ │ │ ├── hub.go │ │ │ ├── integrations.go │ │ │ ├── interfaces.go │ │ │ ├── internal/ │ │ │ │ ├── crypto/ │ │ │ │ │ └── randutil/ │ │ │ │ │ └── randutil.go │ │ │ │ ├── debug/ │ │ │ │ │ └── transport.go │ │ │ │ └── ratelimit/ │ │ │ │ ├── category.go │ │ │ │ ├── deadline.go │ │ │ │ ├── doc.go │ │ │ │ ├── map.go │ │ │ │ ├── rate_limits.go │ │ │ │ └── retry_after.go │ │ │ ├── scope.go │ │ │ ├── sentry.go │ │ │ ├── sourcereader.go │ │ │ ├── span_recorder.go │ │ │ ├── stacktrace.go │ │ │ ├── traces_sampler.go │ │ │ ├── tracing.go │ │ │ ├── transport.go │ │ │ └── util.go │ │ ├── go-logr/ │ │ │ └── logr/ │ │ │ ├── .golangci.yaml │ │ │ ├── CHANGELOG.md │ │ │ ├── CONTRIBUTING.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── SECURITY.md │ │ │ ├── context.go │ │ │ ├── context_noslog.go │ │ │ ├── context_slog.go │ │ │ ├── discard.go │ │ │ ├── logr.go │ │ │ ├── sloghandler.go │ │ │ ├── slogr.go │ │ │ └── slogsink.go │ │ ├── go-sql-driver/ │ │ │ └── mysql/ │ │ │ ├── .gitignore │ │ │ ├── AUTHORS │ │ │ ├── CHANGELOG.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── atomic_bool.go │ │ │ ├── atomic_bool_go118.go │ │ │ ├── auth.go │ │ │ ├── buffer.go │ │ │ ├── collations.go │ │ │ ├── conncheck.go │ │ │ ├── conncheck_dummy.go │ │ │ ├── connection.go │ │ │ ├── connector.go │ │ │ ├── const.go │ │ │ ├── driver.go │ │ │ ├── dsn.go │ │ │ ├── errors.go │ │ │ ├── fields.go │ │ │ ├── infile.go │ │ │ ├── nulltime.go │ │ │ ├── packets.go │ │ │ ├── result.go │ │ │ ├── rows.go │ │ │ ├── statement.go │ │ │ ├── transaction.go │ │ │ └── utils.go │ │ ├── google/ │ │ │ └── certificate-transparency-go/ │ │ │ ├── .gitignore │ │ │ ├── .golangci.yaml │ │ │ ├── AUTHORS │ │ │ ├── CHANGELOG.md │ │ │ ├── CODEOWNERS │ │ │ ├── CONTRIBUTING.md │ │ │ ├── CONTRIBUTORS │ │ │ ├── LICENSE │ │ │ ├── PULL_REQUEST_TEMPLATE.md │ │ │ ├── README.md │ │ │ ├── asn1/ │ │ │ │ ├── README.md │ │ │ │ ├── asn1.go │ │ │ │ ├── common.go │ │ │ │ └── marshal.go │ │ │ ├── client/ │ │ │ │ ├── configpb/ │ │ │ │ │ ├── multilog.pb.go │ │ │ │ │ └── multilog.proto │ │ │ │ ├── getentries.go │ │ │ │ ├── logclient.go │ │ │ │ └── multilog.go │ │ │ ├── cloudbuild.yaml │ │ │ ├── cloudbuild_master.yaml │ │ │ ├── cloudbuild_tag.yaml │ │ │ ├── codecov.yml │ │ │ ├── jsonclient/ │ │ │ │ ├── backoff.go │ │ │ │ └── client.go │ │ │ ├── proto_gen.go │ │ │ ├── serialization.go │ │ │ ├── signatures.go │ │ │ ├── tls/ │ │ │ │ ├── signature.go │ │ │ │ ├── tls.go │ │ │ │ └── types.go │ │ │ ├── types.go │ │ │ └── x509/ │ │ │ ├── README.md │ │ │ ├── cert_pool.go │ │ │ ├── curves.go │ │ │ ├── error.go │ │ │ ├── errors.go │ │ │ ├── names.go │ │ │ ├── pem_decrypt.go │ │ │ ├── pkcs1.go │ │ │ ├── pkcs8.go │ │ │ ├── pkix/ │ │ │ │ └── pkix.go │ │ │ ├── ptr_sysptr_windows.go │ │ │ ├── ptr_uint_windows.go │ │ │ ├── revoked.go │ │ │ ├── root.go │ │ │ ├── root_aix.go │ │ │ ├── root_bsd.go │ │ │ ├── root_cgo_darwin.go │ │ │ ├── root_darwin.go │ │ │ ├── root_darwin_armx.go │ │ │ ├── root_js.go │ │ │ ├── root_linux.go │ │ │ ├── root_nocgo_darwin.go │ │ │ ├── root_plan9.go │ │ │ ├── root_solaris.go │ │ │ ├── root_unix.go │ │ │ ├── root_wasip1.go │ │ │ ├── root_windows.go │ │ │ ├── root_zos.go │ │ │ ├── rpki.go │ │ │ ├── sec1.go │ │ │ ├── test-dir.crt │ │ │ ├── test-file.crt │ │ │ ├── verify.go │ │ │ └── x509.go │ │ ├── jmhodges/ │ │ │ └── clock/ │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── clock.go │ │ │ └── timer.go │ │ ├── jmoiron/ │ │ │ └── sqlx/ │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── bind.go │ │ │ ├── doc.go │ │ │ ├── named.go │ │ │ ├── named_context.go │ │ │ ├── reflectx/ │ │ │ │ ├── README.md │ │ │ │ └── reflect.go │ │ │ ├── sqlx.go │ │ │ ├── sqlx_context.go │ │ │ └── types/ │ │ │ ├── README.md │ │ │ └── types.go │ │ ├── kisielk/ │ │ │ └── sqlstruct/ │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ └── sqlstruct.go │ │ ├── kylelemons/ │ │ │ └── go-gypsy/ │ │ │ ├── LICENSE │ │ │ └── yaml/ │ │ │ ├── config.go │ │ │ ├── doc.go │ │ │ ├── parser.go │ │ │ └── types.go │ │ ├── lib/ │ │ │ └── pq/ │ │ │ ├── .gitignore │ │ │ ├── LICENSE.md │ │ │ ├── README.md │ │ │ ├── TESTS.md │ │ │ ├── array.go │ │ │ ├── buf.go │ │ │ ├── conn.go │ │ │ ├── conn_go115.go │ │ │ ├── conn_go18.go │ │ │ ├── connector.go │ │ │ ├── copy.go │ │ │ ├── doc.go │ │ │ ├── encode.go │ │ │ ├── error.go │ │ │ ├── krb.go │ │ │ ├── notice.go │ │ │ ├── notify.go │ │ │ ├── oid/ │ │ │ │ ├── doc.go │ │ │ │ └── types.go │ │ │ ├── rows.go │ │ │ ├── scram/ │ │ │ │ └── scram.go │ │ │ ├── ssl.go │ │ │ ├── ssl_permissions.go │ │ │ ├── ssl_windows.go │ │ │ ├── url.go │ │ │ ├── user_other.go │ │ │ ├── user_posix.go │ │ │ ├── user_windows.go │ │ │ └── uuid.go │ │ ├── mattn/ │ │ │ └── go-sqlite3/ │ │ │ ├── .codecov.yml │ │ │ ├── .gitignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── backup.go │ │ │ ├── callback.go │ │ │ ├── convert.go │ │ │ ├── doc.go │ │ │ ├── error.go │ │ │ ├── sqlite3-binding.c │ │ │ ├── sqlite3-binding.h │ │ │ ├── sqlite3.go │ │ │ ├── sqlite3_context.go │ │ │ ├── sqlite3_func_crypt.go │ │ │ ├── sqlite3_go18.go │ │ │ ├── sqlite3_libsqlite3.go │ │ │ ├── sqlite3_load_extension.go │ │ │ ├── sqlite3_load_extension_omit.go │ │ │ ├── sqlite3_opt_allow_uri_authority.go │ │ │ ├── sqlite3_opt_app_armor.go │ │ │ ├── sqlite3_opt_column_metadata.go │ │ │ ├── sqlite3_opt_foreign_keys.go │ │ │ ├── sqlite3_opt_fts5.go │ │ │ ├── sqlite3_opt_icu.go │ │ │ ├── sqlite3_opt_introspect.go │ │ │ ├── sqlite3_opt_math_functions.go │ │ │ ├── sqlite3_opt_os_trace.go │ │ │ ├── sqlite3_opt_preupdate.go │ │ │ ├── sqlite3_opt_preupdate_hook.go │ │ │ ├── sqlite3_opt_preupdate_omit.go │ │ │ ├── sqlite3_opt_secure_delete.go │ │ │ ├── sqlite3_opt_secure_delete_fast.go │ │ │ ├── sqlite3_opt_serialize.go │ │ │ ├── sqlite3_opt_serialize_omit.go │ │ │ ├── sqlite3_opt_stat4.go │ │ │ ├── sqlite3_opt_unlock_notify.c │ │ │ ├── sqlite3_opt_unlock_notify.go │ │ │ ├── sqlite3_opt_userauth.go │ │ │ ├── sqlite3_opt_userauth_omit.go │ │ │ ├── sqlite3_opt_vacuum_full.go │ │ │ ├── sqlite3_opt_vacuum_incr.go │ │ │ ├── sqlite3_opt_vtable.go │ │ │ ├── sqlite3_other.go │ │ │ ├── sqlite3_solaris.go │ │ │ ├── sqlite3_trace.go │ │ │ ├── sqlite3_type.go │ │ │ ├── sqlite3_usleep_windows.go │ │ │ ├── sqlite3_windows.go │ │ │ ├── sqlite3ext.h │ │ │ └── static_mock.go │ │ ├── pelletier/ │ │ │ └── go-toml/ │ │ │ ├── .dockerignore │ │ │ ├── .gitignore │ │ │ ├── CONTRIBUTING.md │ │ │ ├── Dockerfile │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── PULL_REQUEST_TEMPLATE.md │ │ │ ├── README.md │ │ │ ├── azure-pipelines.yml │ │ │ ├── benchmark.sh │ │ │ ├── doc.go │ │ │ ├── example-crlf.toml │ │ │ ├── example.toml │ │ │ ├── fuzz.go │ │ │ ├── fuzz.sh │ │ │ ├── keysparsing.go │ │ │ ├── lexer.go │ │ │ ├── localtime.go │ │ │ ├── marshal.go │ │ │ ├── marshal_OrderPreserve_test.toml │ │ │ ├── marshal_test.toml │ │ │ ├── parser.go │ │ │ ├── position.go │ │ │ ├── token.go │ │ │ ├── toml.go │ │ │ ├── tomlpub.go │ │ │ ├── tomltree_create.go │ │ │ ├── tomltree_write.go │ │ │ └── tomltree_writepub.go │ │ ├── prometheus/ │ │ │ ├── client_golang/ │ │ │ │ ├── LICENSE │ │ │ │ ├── NOTICE │ │ │ │ └── prometheus/ │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── build_info_collector.go │ │ │ │ ├── collector.go │ │ │ │ ├── counter.go │ │ │ │ ├── desc.go │ │ │ │ ├── doc.go │ │ │ │ ├── expvar_collector.go │ │ │ │ ├── fnv.go │ │ │ │ ├── gauge.go │ │ │ │ ├── get_pid.go │ │ │ │ ├── get_pid_gopherjs.go │ │ │ │ ├── go_collector.go │ │ │ │ ├── go_collector_go116.go │ │ │ │ ├── go_collector_latest.go │ │ │ │ ├── histogram.go │ │ │ │ ├── internal/ │ │ │ │ │ ├── almost_equal.go │ │ │ │ │ ├── difflib.go │ │ │ │ │ ├── go_collector_options.go │ │ │ │ │ ├── go_runtime_metrics.go │ │ │ │ │ └── metric.go │ │ │ │ ├── labels.go │ │ │ │ ├── metric.go │ │ │ │ ├── num_threads.go │ │ │ │ ├── num_threads_gopherjs.go │ │ │ │ ├── observer.go │ │ │ │ ├── process_collector.go │ │ │ │ ├── process_collector_js.go │ │ │ │ ├── process_collector_other.go │ │ │ │ ├── process_collector_wasip1.go │ │ │ │ ├── process_collector_windows.go │ │ │ │ ├── promauto/ │ │ │ │ │ └── auto.go │ │ │ │ ├── promhttp/ │ │ │ │ │ ├── delegator.go │ │ │ │ │ ├── http.go │ │ │ │ │ ├── instrument_client.go │ │ │ │ │ ├── instrument_server.go │ │ │ │ │ └── option.go │ │ │ │ ├── registry.go │ │ │ │ ├── summary.go │ │ │ │ ├── timer.go │ │ │ │ ├── untyped.go │ │ │ │ ├── value.go │ │ │ │ ├── vec.go │ │ │ │ ├── vnext.go │ │ │ │ └── wrap.go │ │ │ ├── client_model/ │ │ │ │ ├── LICENSE │ │ │ │ ├── NOTICE │ │ │ │ └── go/ │ │ │ │ └── metrics.pb.go │ │ │ ├── common/ │ │ │ │ ├── LICENSE │ │ │ │ ├── NOTICE │ │ │ │ ├── expfmt/ │ │ │ │ │ ├── decode.go │ │ │ │ │ ├── encode.go │ │ │ │ │ ├── expfmt.go │ │ │ │ │ ├── fuzz.go │ │ │ │ │ ├── openmetrics_create.go │ │ │ │ │ ├── text_create.go │ │ │ │ │ └── text_parse.go │ │ │ │ ├── internal/ │ │ │ │ │ └── bitbucket.org/ │ │ │ │ │ └── ww/ │ │ │ │ │ └── goautoneg/ │ │ │ │ │ ├── README.txt │ │ │ │ │ └── autoneg.go │ │ │ │ └── model/ │ │ │ │ ├── alert.go │ │ │ │ ├── fingerprinting.go │ │ │ │ ├── fnv.go │ │ │ │ ├── labels.go │ │ │ │ ├── labelset.go │ │ │ │ ├── metadata.go │ │ │ │ ├── metric.go │ │ │ │ ├── model.go │ │ │ │ ├── signature.go │ │ │ │ ├── silence.go │ │ │ │ ├── time.go │ │ │ │ ├── value.go │ │ │ │ ├── value_float.go │ │ │ │ ├── value_histogram.go │ │ │ │ └── value_type.go │ │ │ └── procfs/ │ │ │ ├── .gitignore │ │ │ ├── .golangci.yml │ │ │ ├── CODE_OF_CONDUCT.md │ │ │ ├── CONTRIBUTING.md │ │ │ ├── LICENSE │ │ │ ├── MAINTAINERS.md │ │ │ ├── Makefile │ │ │ ├── Makefile.common │ │ │ ├── NOTICE │ │ │ ├── README.md │ │ │ ├── SECURITY.md │ │ │ ├── arp.go │ │ │ ├── buddyinfo.go │ │ │ ├── cmdline.go │ │ │ ├── cpuinfo.go │ │ │ ├── cpuinfo_armx.go │ │ │ ├── cpuinfo_loong64.go │ │ │ ├── cpuinfo_mipsx.go │ │ │ ├── cpuinfo_others.go │ │ │ ├── cpuinfo_ppcx.go │ │ │ ├── cpuinfo_riscvx.go │ │ │ ├── cpuinfo_s390x.go │ │ │ ├── cpuinfo_x86.go │ │ │ ├── crypto.go │ │ │ ├── doc.go │ │ │ ├── fs.go │ │ │ ├── fs_statfs_notype.go │ │ │ ├── fs_statfs_type.go │ │ │ ├── fscache.go │ │ │ ├── internal/ │ │ │ │ ├── fs/ │ │ │ │ │ └── fs.go │ │ │ │ └── util/ │ │ │ │ ├── parse.go │ │ │ │ ├── readfile.go │ │ │ │ ├── sysreadfile.go │ │ │ │ ├── sysreadfile_compat.go │ │ │ │ └── valueparser.go │ │ │ ├── ipvs.go │ │ │ ├── kernel_random.go │ │ │ ├── loadavg.go │ │ │ ├── mdstat.go │ │ │ ├── meminfo.go │ │ │ ├── mountinfo.go │ │ │ ├── mountstats.go │ │ │ ├── net_conntrackstat.go │ │ │ ├── net_dev.go │ │ │ ├── net_ip_socket.go │ │ │ ├── net_protocols.go │ │ │ ├── net_route.go │ │ │ ├── net_sockstat.go │ │ │ ├── net_softnet.go │ │ │ ├── net_tcp.go │ │ │ ├── net_udp.go │ │ │ ├── net_unix.go │ │ │ ├── net_wireless.go │ │ │ ├── net_xfrm.go │ │ │ ├── netstat.go │ │ │ ├── proc.go │ │ │ ├── proc_cgroup.go │ │ │ ├── proc_cgroups.go │ │ │ ├── proc_environ.go │ │ │ ├── proc_fdinfo.go │ │ │ ├── proc_interrupts.go │ │ │ ├── proc_io.go │ │ │ ├── proc_limits.go │ │ │ ├── proc_maps.go │ │ │ ├── proc_netstat.go │ │ │ ├── proc_ns.go │ │ │ ├── proc_psi.go │ │ │ ├── proc_smaps.go │ │ │ ├── proc_snmp.go │ │ │ ├── proc_snmp6.go │ │ │ ├── proc_stat.go │ │ │ ├── proc_status.go │ │ │ ├── proc_sys.go │ │ │ ├── schedstat.go │ │ │ ├── slab.go │ │ │ ├── softirqs.go │ │ │ ├── stat.go │ │ │ ├── swaps.go │ │ │ ├── thread.go │ │ │ ├── ttar │ │ │ ├── vm.go │ │ │ └── zoneinfo.go │ │ ├── weppos/ │ │ │ └── publicsuffix-go/ │ │ │ ├── LICENSE.txt │ │ │ └── publicsuffix/ │ │ │ ├── publicsuffix.go │ │ │ └── rules.go │ │ ├── ziutek/ │ │ │ └── mymysql/ │ │ │ ├── LICENSE │ │ │ ├── godrv/ │ │ │ │ ├── appengine.go │ │ │ │ └── driver.go │ │ │ ├── mysql/ │ │ │ │ ├── errors.go │ │ │ │ ├── field.go │ │ │ │ ├── interface.go │ │ │ │ ├── row.go │ │ │ │ ├── types.go │ │ │ │ └── utils.go │ │ │ └── native/ │ │ │ ├── LICENSE │ │ │ ├── addons.go │ │ │ ├── binding.go │ │ │ ├── codecs.go │ │ │ ├── command.go │ │ │ ├── common.go │ │ │ ├── consts.go │ │ │ ├── init.go │ │ │ ├── mysql.go │ │ │ ├── packet.go │ │ │ ├── paramvalue.go │ │ │ ├── passwd.go │ │ │ ├── prepared.go │ │ │ ├── result.go │ │ │ └── unsafe.go-disabled │ │ └── zmap/ │ │ ├── zcrypto/ │ │ │ ├── LICENSE │ │ │ ├── cryptobyte/ │ │ │ │ ├── NOTICE.md │ │ │ │ ├── asn1/ │ │ │ │ │ └── asn1.go │ │ │ │ ├── asn1.go │ │ │ │ ├── builder.go │ │ │ │ └── string.go │ │ │ ├── dsa/ │ │ │ │ └── dsa.go │ │ │ ├── encoding/ │ │ │ │ └── asn1/ │ │ │ │ ├── README.md │ │ │ │ ├── asn1.go │ │ │ │ ├── common.go │ │ │ │ └── marshal.go │ │ │ ├── internal/ │ │ │ │ └── randutil/ │ │ │ │ └── randutil.go │ │ │ ├── json/ │ │ │ │ ├── dhe.go │ │ │ │ ├── ecdhe.go │ │ │ │ ├── names.go │ │ │ │ └── rsa.go │ │ │ ├── util/ │ │ │ │ └── isURL.go │ │ │ └── x509/ │ │ │ ├── README.md │ │ │ ├── cert_pool.go │ │ │ ├── certificate_type.go │ │ │ ├── chain.go │ │ │ ├── crl_parser.go │ │ │ ├── ct/ │ │ │ │ ├── serialization.go │ │ │ │ └── types.go │ │ │ ├── example.json │ │ │ ├── extended_key_usage.go │ │ │ ├── extended_key_usage_schema.sh │ │ │ ├── extensions.go │ │ │ ├── fingerprint.go │ │ │ ├── generated_certvalidationlevel_string.go │ │ │ ├── json.go │ │ │ ├── names.go │ │ │ ├── pem_decrypt.go │ │ │ ├── pkcs1.go │ │ │ ├── pkcs8.go │ │ │ ├── pkix/ │ │ │ │ ├── json.go │ │ │ │ ├── oid.go │ │ │ │ ├── oid_names.go │ │ │ │ └── pkix.go │ │ │ ├── qc_statements.go │ │ │ ├── sec1.go │ │ │ ├── tor_service_descriptor.go │ │ │ ├── validation.go │ │ │ ├── verify.go │ │ │ └── x509.go │ │ └── zlint/ │ │ └── v3/ │ │ ├── .goreleaser.yml │ │ ├── LICENSE │ │ ├── lint/ │ │ │ ├── base.go │ │ │ ├── configuration.go │ │ │ ├── global_configurations.go │ │ │ ├── lint_lookup.go │ │ │ ├── profile.go │ │ │ ├── registration.go │ │ │ ├── result.go │ │ │ └── source.go │ │ ├── lints/ │ │ │ ├── apple/ │ │ │ │ ├── lint_ct_sct_policy_count_unsatisfied.go │ │ │ │ ├── lint_e_server_cert_valid_time_longer_than_398_days.go │ │ │ │ ├── lint_w_server_cert_valid_time_longer_than_397_days.go │ │ │ │ └── time.go │ │ │ ├── cabf_br/ │ │ │ │ ├── lint_ca_common_name_missing.go │ │ │ │ ├── lint_ca_country_name_invalid.go │ │ │ │ ├── lint_ca_country_name_missing.go │ │ │ │ ├── lint_ca_crl_sign_not_set.go │ │ │ │ ├── lint_ca_digital_signature_not_set.go │ │ │ │ ├── lint_ca_is_ca.go │ │ │ │ ├── lint_ca_key_cert_sign_not_set.go │ │ │ │ ├── lint_ca_key_usage_missing.go │ │ │ │ ├── lint_ca_key_usage_not_critical.go │ │ │ │ ├── lint_ca_organization_name_missing.go │ │ │ │ ├── lint_cab_dv_conflicts_with_locality.go │ │ │ │ ├── lint_cab_dv_conflicts_with_org.go │ │ │ │ ├── lint_cab_dv_conflicts_with_postal.go │ │ │ │ ├── lint_cab_dv_conflicts_with_province.go │ │ │ │ ├── lint_cab_dv_conflicts_with_street.go │ │ │ │ ├── lint_cab_iv_requires_personal_name.go │ │ │ │ ├── lint_cab_ov_requires_org.go │ │ │ │ ├── lint_cert_policy_iv_requires_country.go │ │ │ │ ├── lint_cert_policy_iv_requires_province_or_locality.go │ │ │ │ ├── lint_cert_policy_ov_requires_country.go │ │ │ │ ├── lint_cert_policy_ov_requires_province_or_locality.go │ │ │ │ ├── lint_dh_params_missing.go │ │ │ │ ├── lint_dnsname_bad_character_in_label.go │ │ │ │ ├── lint_dnsname_check_left_label_wildcard.go │ │ │ │ ├── lint_dnsname_contains_bare_iana_suffix.go │ │ │ │ ├── lint_dnsname_contains_empty_label.go │ │ │ │ ├── lint_dnsname_contains_prohibited_reserved_label.go │ │ │ │ ├── lint_dnsname_hyphen_in_sld.go │ │ │ │ ├── lint_dnsname_label_too_long.go │ │ │ │ ├── lint_dnsname_right_label_valid_tld.go │ │ │ │ ├── lint_dnsname_underscore_in_sld.go │ │ │ │ ├── lint_dnsname_underscore_in_trd.go │ │ │ │ ├── lint_dnsname_wildcard_left_of_public_suffix.go │ │ │ │ ├── lint_dnsname_wildcard_only_in_left_label.go │ │ │ │ ├── lint_dsa_correct_order_in_subgroup.go │ │ │ │ ├── lint_dsa_improper_modulus_or_divisor_size.go │ │ │ │ ├── lint_dsa_shorter_than_2048_bits.go │ │ │ │ ├── lint_dsa_unique_correct_representation.go │ │ │ │ ├── lint_e_sub_ca_aia_missing.go │ │ │ │ ├── lint_ec_improper_curves.go │ │ │ │ ├── lint_ext_nc_intersects_reserved_ip.go │ │ │ │ ├── lint_ext_san_contains_reserved_ip.go │ │ │ │ ├── lint_ext_san_critical_with_subject_dn.go │ │ │ │ ├── lint_ext_san_directory_name_present.go │ │ │ │ ├── lint_ext_san_edi_party_name_present.go │ │ │ │ ├── lint_ext_san_missing.go │ │ │ │ ├── lint_ext_san_other_name_present.go │ │ │ │ ├── lint_ext_san_registered_id_present.go │ │ │ │ ├── lint_ext_san_rfc822_name_present.go │ │ │ │ ├── lint_ext_san_uniform_resource_identifier_present.go │ │ │ │ ├── lint_ext_tor_service_descriptor_hash_invalid.go │ │ │ │ ├── lint_extra_subject_common_names.go │ │ │ │ ├── lint_invalid_certificate_version.go │ │ │ │ ├── lint_no_underscores_before_1_6_2.go │ │ │ │ ├── lint_ocsp_id_pkix_ocsp_nocheck_ext_not_included_server_auth.go │ │ │ │ ├── lint_old_root_ca_rsa_mod_less_than_2048_bits.go │ │ │ │ ├── lint_old_sub_ca_rsa_mod_less_than_1024_bits.go │ │ │ │ ├── lint_old_sub_cert_rsa_mod_less_than_1024_bits.go │ │ │ │ ├── lint_organizational_unit_name_prohibited.go │ │ │ │ ├── lint_prohibit_dsa_usage.go │ │ │ │ ├── lint_public_key_type_not_allowed.go │ │ │ │ ├── lint_root_ca_basic_constraints_path_len_constraint_field_present.go │ │ │ │ ├── lint_root_ca_contains_cert_policy.go │ │ │ │ ├── lint_root_ca_extended_key_usage_present.go │ │ │ │ ├── lint_root_ca_key_usage_must_be_critical.go │ │ │ │ ├── lint_root_ca_key_usage_present.go │ │ │ │ ├── lint_rsa_mod_factors_smaller_than_752_bits.go │ │ │ │ ├── lint_rsa_mod_less_than_2048_bits.go │ │ │ │ ├── lint_rsa_mod_not_odd.go │ │ │ │ ├── lint_rsa_public_exponent_not_in_range.go │ │ │ │ ├── lint_rsa_public_exponent_not_odd.go │ │ │ │ ├── lint_rsa_public_exponent_too_small.go │ │ │ │ ├── lint_san_dns_name_onion_invalid.go │ │ │ │ ├── lint_san_dns_name_onion_not_ev_cert.go │ │ │ │ ├── lint_signature_algorithm_not_supported.go │ │ │ │ ├── lint_sub_ca_aia_does_not_contain_issuing_ca_url.go │ │ │ │ ├── lint_sub_ca_aia_marked_critical.go │ │ │ │ ├── lint_sub_ca_certificate_policies_marked_critical.go │ │ │ │ ├── lint_sub_ca_certificate_policies_missing.go │ │ │ │ ├── lint_sub_ca_crl_distribution_points_does_not_contain_url.go │ │ │ │ ├── lint_sub_ca_crl_distribution_points_marked_critical.go │ │ │ │ ├── lint_sub_ca_crl_distribution_points_missing.go │ │ │ │ ├── lint_sub_ca_eku_critical.go │ │ │ │ ├── lint_sub_ca_eku_missing.go │ │ │ │ ├── lint_sub_ca_eku_valid_fields.go │ │ │ │ ├── lint_sub_ca_name_constraints_not_critical.go │ │ │ │ ├── lint_sub_cert_aia_does_not_contain_issuing_ca_url.go │ │ │ │ ├── lint_sub_cert_aia_does_not_contain_ocsp_url.go │ │ │ │ ├── lint_sub_cert_aia_marked_critical.go │ │ │ │ ├── lint_sub_cert_aia_missing.go │ │ │ │ ├── lint_sub_cert_cert_policy_empty.go │ │ │ │ ├── lint_sub_cert_certificate_policies_marked_critical.go │ │ │ │ ├── lint_sub_cert_certificate_policies_missing.go │ │ │ │ ├── lint_sub_cert_country_name_must_appear.go │ │ │ │ ├── lint_sub_cert_crl_distribution_points_does_not_contain_url.go │ │ │ │ ├── lint_sub_cert_crl_distribution_points_marked_critical.go │ │ │ │ ├── lint_sub_cert_eku_extra_values.go │ │ │ │ ├── lint_sub_cert_eku_missing.go │ │ │ │ ├── lint_sub_cert_eku_server_auth_client_auth_missing.go │ │ │ │ ├── lint_sub_cert_gn_sn_contains_policy.go │ │ │ │ ├── lint_sub_cert_is_ca.go │ │ │ │ ├── lint_sub_cert_key_usage_cert_sign_bit_set.go │ │ │ │ ├── lint_sub_cert_key_usage_crl_sign_bit_set.go │ │ │ │ ├── lint_sub_cert_locality_name_must_appear.go │ │ │ │ ├── lint_sub_cert_locality_name_must_not_appear.go │ │ │ │ ├── lint_sub_cert_or_sub_ca_using_sha1.go │ │ │ │ ├── lint_sub_cert_postal_code_prohibited.go │ │ │ │ ├── lint_sub_cert_province_must_appear.go │ │ │ │ ├── lint_sub_cert_province_must_not_appear.go │ │ │ │ ├── lint_sub_cert_sha1_expiration_too_long.go │ │ │ │ ├── lint_sub_cert_street_address_should_not_exist.go │ │ │ │ ├── lint_sub_cert_valid_time_longer_than_39_months.go │ │ │ │ ├── lint_sub_cert_valid_time_longer_than_825_days.go │ │ │ │ ├── lint_subject_common_name_included.go │ │ │ │ ├── lint_subject_common_name_not_exactly_from_san.go │ │ │ │ ├── lint_subject_common_name_not_from_san.go │ │ │ │ ├── lint_subject_contains_malformed_arpa_ip.go │ │ │ │ ├── lint_subject_contains_noninformational_value.go │ │ │ │ ├── lint_subject_contains_organizational_unit_name_and_no_organization_name.go │ │ │ │ ├── lint_subject_contains_reserved_arpa_ip.go │ │ │ │ ├── lint_subject_contains_reserved_ip.go │ │ │ │ ├── lint_subject_country_not_iso.go │ │ │ │ ├── lint_subject_public_key_info_improper_algorithm_object_identifier_encoding.go │ │ │ │ ├── lint_underscore_not_permissible_in_dnsname.go │ │ │ │ └── lint_w_sub_ca_aia_missing.go │ │ │ ├── cabf_ev/ │ │ │ │ ├── lint_ev_business_category_missing.go │ │ │ │ ├── lint_ev_country_name_missing.go │ │ │ │ ├── lint_ev_not_wildcard.go │ │ │ │ ├── lint_ev_organization_id_missing.go │ │ │ │ ├── lint_ev_organization_name_missing.go │ │ │ │ ├── lint_ev_san_ip_address_present.go │ │ │ │ ├── lint_ev_serial_number_missing.go │ │ │ │ ├── lint_ev_valid_time_too_long.go │ │ │ │ └── lint_onion_subject_validity_time_too_large.go │ │ │ ├── community/ │ │ │ │ ├── lint_ian_bare_wildcard.go │ │ │ │ ├── lint_ian_dns_name_includes_null_char.go │ │ │ │ ├── lint_ian_dns_name_starts_with_period.go │ │ │ │ ├── lint_ian_iana_pub_suffix_empty.go │ │ │ │ ├── lint_ian_wildcard_not_first.go │ │ │ │ ├── lint_is_redacted_cert.go │ │ │ │ ├── lint_issuer_dn_leading_whitespace.go │ │ │ │ ├── lint_issuer_dn_trailing_whitespace.go │ │ │ │ ├── lint_issuer_multiple_rdn.go │ │ │ │ ├── lint_rsa_exp_negative.go │ │ │ │ ├── lint_rsa_fermat_factorization.go │ │ │ │ ├── lint_rsa_no_public_key.go │ │ │ │ ├── lint_san_bare_wildcard.go │ │ │ │ ├── lint_san_dns_name_duplicate.go │ │ │ │ ├── lint_san_dns_name_includes_null_char.go │ │ │ │ ├── lint_san_dns_name_starts_with_period.go │ │ │ │ ├── lint_san_iana_pub_suffix_empty.go │ │ │ │ ├── lint_san_wildcard_not_first.go │ │ │ │ ├── lint_subject_dn_leading_whitespace.go │ │ │ │ ├── lint_subject_dn_trailing_whitespace.go │ │ │ │ ├── lint_subject_multiple_rdn.go │ │ │ │ └── lint_validity_time_not_positive.go │ │ │ ├── etsi/ │ │ │ │ ├── lint_qcstatem_etsi_present_qcs_critical.go │ │ │ │ ├── lint_qcstatem_etsi_type_as_statem.go │ │ │ │ ├── lint_qcstatem_mandatory_etsi_statems.go │ │ │ │ ├── lint_qcstatem_qccompliance_valid.go │ │ │ │ ├── lint_qcstatem_qclimitvalue_valid.go │ │ │ │ ├── lint_qcstatem_qcpds_lang_case.go │ │ │ │ ├── lint_qcstatem_qcpds_valid.go │ │ │ │ ├── lint_qcstatem_qcretentionperiod_valid.go │ │ │ │ ├── lint_qcstatem_qcsscd_valid.go │ │ │ │ ├── lint_qcstatem_qctype_valid.go │ │ │ │ └── lint_qcstatem_qctype_web.go │ │ │ ├── mozilla/ │ │ │ │ ├── lint_e_prohibit_dsa_usage.go │ │ │ │ ├── lint_mp_allowed_eku.go │ │ │ │ ├── lint_mp_authority_key_identifier_correct.go │ │ │ │ ├── lint_mp_ecdsa_pub_key_encoding_correct.go │ │ │ │ ├── lint_mp_ecdsa_signature_encoding_correct.go │ │ │ │ ├── lint_mp_exponent_cannot_be_one.go │ │ │ │ ├── lint_mp_modulus_must_be_2048_bits_or_more.go │ │ │ │ ├── lint_mp_modulus_must_be_divisible_by_8.go │ │ │ │ ├── lint_mp_pss_parameters_encoding_correct.go │ │ │ │ └── lint_mp_rsassa-pss_in_spki.go │ │ │ └── rfc/ │ │ │ ├── lint_basic_constraints_not_critical.go │ │ │ ├── lint_ca_subject_field_empty.go │ │ │ ├── lint_cert_contains_unique_identifier.go │ │ │ ├── lint_cert_extensions_version_not_3.go │ │ │ ├── lint_cert_unique_identifier_version_not_2_or_3.go │ │ │ ├── lint_crl_has_next_update.go │ │ │ ├── lint_distribution_point_incomplete.go │ │ │ ├── lint_distribution_point_missing_ldap_or_uri.go │ │ │ ├── lint_dnsname_contains_empty_label.go │ │ │ ├── lint_dnsname_hyphen_in_sld.go │ │ │ ├── lint_dnsname_label_too_long.go │ │ │ ├── lint_dnsname_underscore_in_sld.go │ │ │ ├── lint_dnsname_underscore_in_trd.go │ │ │ ├── lint_ecdsa_allowed_ku.go │ │ │ ├── lint_ecdsa_ee_invalid_ku.go │ │ │ ├── lint_eku_critical_improperly.go │ │ │ ├── lint_ext_aia_access_location_missing.go │ │ │ ├── lint_ext_aia_marked_critical.go │ │ │ ├── lint_ext_authority_key_identifier_critical.go │ │ │ ├── lint_ext_authority_key_identifier_missing.go │ │ │ ├── lint_ext_authority_key_identifier_no_key_identifier.go │ │ │ ├── lint_ext_cert_policy_contains_noticeref.go │ │ │ ├── lint_ext_cert_policy_disallowed_any_policy_qualifier.go │ │ │ ├── lint_ext_cert_policy_duplicate.go │ │ │ ├── lint_ext_cert_policy_explicit_text_ia5_string.go │ │ │ ├── lint_ext_cert_policy_explicit_text_includes_control.go │ │ │ ├── lint_ext_cert_policy_explicit_text_not_nfc.go │ │ │ ├── lint_ext_cert_policy_explicit_text_not_utf8.go │ │ │ ├── lint_ext_cert_policy_explicit_text_too_long.go │ │ │ ├── lint_ext_crl_distribution_marked_critical.go │ │ │ ├── lint_ext_duplicate_extension.go │ │ │ ├── lint_ext_freshest_crl_marked_critical.go │ │ │ ├── lint_ext_ian_critical.go │ │ │ ├── lint_ext_ian_dns_not_ia5_string.go │ │ │ ├── lint_ext_ian_empty_name.go │ │ │ ├── lint_ext_ian_no_entries.go │ │ │ ├── lint_ext_ian_rfc822_format_invalid.go │ │ │ ├── lint_ext_ian_space_dns_name.go │ │ │ ├── lint_ext_ian_uri_format_invalid.go │ │ │ ├── lint_ext_ian_uri_host_not_fqdn_or_ip.go │ │ │ ├── lint_ext_ian_uri_not_ia5.go │ │ │ ├── lint_ext_ian_uri_relative.go │ │ │ ├── lint_ext_key_usage_cert_sign_without_ca.go │ │ │ ├── lint_ext_key_usage_not_critical.go │ │ │ ├── lint_ext_key_usage_without_bits.go │ │ │ ├── lint_ext_name_constraints_not_critical.go │ │ │ ├── lint_ext_name_constraints_not_in_ca.go │ │ │ ├── lint_ext_policy_constraints_empty.go │ │ │ ├── lint_ext_policy_constraints_not_critical.go │ │ │ ├── lint_ext_policy_map_any_policy.go │ │ │ ├── lint_ext_policy_map_not_critical.go │ │ │ ├── lint_ext_policy_map_not_in_cert_policy.go │ │ │ ├── lint_ext_san_dns_name_too_long.go │ │ │ ├── lint_ext_san_dns_not_ia5_string.go │ │ │ ├── lint_ext_san_empty_name.go │ │ │ ├── lint_ext_san_no_entries.go │ │ │ ├── lint_ext_san_not_critical_without_subject.go │ │ │ ├── lint_ext_san_rfc822_format_invalid.go │ │ │ ├── lint_ext_san_space_dns_name.go │ │ │ ├── lint_ext_san_uri_format_invalid.go │ │ │ ├── lint_ext_san_uri_host_not_fqdn_or_ip.go │ │ │ ├── lint_ext_san_uri_not_ia5.go │ │ │ ├── lint_ext_san_uri_relative.go │ │ │ ├── lint_ext_subject_directory_attr_critical.go │ │ │ ├── lint_ext_subject_key_identifier_critical.go │ │ │ ├── lint_ext_subject_key_identifier_missing_ca.go │ │ │ ├── lint_ext_subject_key_identifier_missing_sub_cert.go │ │ │ ├── lint_generalized_time_does_not_include_seconds.go │ │ │ ├── lint_generalized_time_includes_fraction_seconds.go │ │ │ ├── lint_generalized_time_not_in_zulu.go │ │ │ ├── lint_idn_dnsname_malformed_unicode.go │ │ │ ├── lint_idn_dnsname_must_be_nfc.go │ │ │ ├── lint_incorrect_ku_encoding.go │ │ │ ├── lint_inhibit_any_policy_not_critical.go │ │ │ ├── lint_issuer_dn_country_not_printable_string.go │ │ │ ├── lint_issuer_field_empty.go │ │ │ ├── lint_key_usage_incorrect_length.go │ │ │ ├── lint_name_constraint_empty.go │ │ │ ├── lint_name_constraint_maximum_not_absent.go │ │ │ ├── lint_name_constraint_minimum_non_zero.go │ │ │ ├── lint_name_constraint_not_fqdn.go │ │ │ ├── lint_name_constraint_on_edi_party_name.go │ │ │ ├── lint_name_constraint_on_registered_id.go │ │ │ ├── lint_name_constraint_on_x400.go │ │ │ ├── lint_path_len_constraint_improperly_included.go │ │ │ ├── lint_path_len_constraint_zero_or_less.go │ │ │ ├── lint_rsa_allowed_ku_ca.go │ │ │ ├── lint_rsa_allowed_ku_ee.go │ │ │ ├── lint_rsa_allowed_ku_no_encipherment_ca.go │ │ │ ├── lint_serial_number_longer_than_20_octets.go │ │ │ ├── lint_serial_number_not_positive.go │ │ │ ├── lint_spki_rsa_encryption_parameter_not_null.go │ │ │ ├── lint_subject_common_name_max_length.go │ │ │ ├── lint_subject_dn_country_not_printable_string.go │ │ │ ├── lint_subject_dn_not_printable_characters.go │ │ │ ├── lint_subject_dn_serial_number_max_length.go │ │ │ ├── lint_subject_dn_serial_number_not_printable_string.go │ │ │ ├── lint_subject_email_max_length.go │ │ │ ├── lint_subject_empty_without_san.go │ │ │ ├── lint_subject_given_name_max_length.go │ │ │ ├── lint_subject_given_name_recommended_max_length.go │ │ │ ├── lint_subject_info_access_marked_critical.go │ │ │ ├── lint_subject_locality_name_max_length.go │ │ │ ├── lint_subject_not_dn.go │ │ │ ├── lint_subject_organization_name_max_length.go │ │ │ ├── lint_subject_organizational_unit_name_max_length.go │ │ │ ├── lint_subject_postal_code_max_length.go │ │ │ ├── lint_subject_printable_string_badalpha.go │ │ │ ├── lint_subject_state_name_max_length.go │ │ │ ├── lint_subject_street_address_max_length.go │ │ │ ├── lint_subject_surname_max_length.go │ │ │ ├── lint_subject_surname_recommended_max_length.go │ │ │ ├── lint_superfluous_ku_encoding.go │ │ │ ├── lint_tbs_signature_alg_matches_cert_signature_alg.go │ │ │ ├── lint_tbs_signature_rsa_encryption_parameter_not_null.go │ │ │ ├── lint_utc_time_does_not_include_seconds.go │ │ │ ├── lint_utc_time_not_in_zulu.go │ │ │ └── lint_wrong_time_format_pre2050.go │ │ ├── makefile │ │ ├── newLint.sh │ │ ├── newProfile.sh │ │ ├── profileTemplate │ │ ├── resultset.go │ │ ├── template │ │ ├── util/ │ │ │ ├── algorithm_identifier.go │ │ │ ├── ca.go │ │ │ ├── countries.go │ │ │ ├── eku.go │ │ │ ├── encodings.go │ │ │ ├── ev.go │ │ │ ├── fqdn.go │ │ │ ├── gtld.go │ │ │ ├── gtld_map.go │ │ │ ├── idna.go │ │ │ ├── ip.go │ │ │ ├── ku.go │ │ │ ├── names.go │ │ │ ├── oid.go │ │ │ ├── onion.go │ │ │ ├── primes.go │ │ │ ├── qc_stmt.go │ │ │ ├── rdn.go │ │ │ └── time.go │ │ └── zlint.go │ ├── golang.org/ │ │ └── x/ │ │ ├── crypto/ │ │ │ ├── LICENSE │ │ │ ├── PATENTS │ │ │ ├── blowfish/ │ │ │ │ ├── block.go │ │ │ │ ├── cipher.go │ │ │ │ └── const.go │ │ │ ├── chacha20/ │ │ │ │ ├── chacha_arm64.go │ │ │ │ ├── chacha_arm64.s │ │ │ │ ├── chacha_generic.go │ │ │ │ ├── chacha_noasm.go │ │ │ │ ├── chacha_ppc64le.go │ │ │ │ ├── chacha_ppc64le.s │ │ │ │ ├── chacha_s390x.go │ │ │ │ ├── chacha_s390x.s │ │ │ │ └── xor.go │ │ │ ├── cryptobyte/ │ │ │ │ ├── asn1/ │ │ │ │ │ └── asn1.go │ │ │ │ ├── asn1.go │ │ │ │ ├── builder.go │ │ │ │ └── string.go │ │ │ ├── curve25519/ │ │ │ │ ├── curve25519.go │ │ │ │ ├── curve25519_compat.go │ │ │ │ ├── curve25519_go120.go │ │ │ │ └── internal/ │ │ │ │ └── field/ │ │ │ │ ├── README │ │ │ │ ├── fe.go │ │ │ │ ├── fe_amd64.go │ │ │ │ ├── fe_amd64.s │ │ │ │ ├── fe_amd64_noasm.go │ │ │ │ ├── fe_arm64.go │ │ │ │ ├── fe_arm64.s │ │ │ │ ├── fe_arm64_noasm.go │ │ │ │ ├── fe_generic.go │ │ │ │ ├── sync.checkpoint │ │ │ │ └── sync.sh │ │ │ ├── ed25519/ │ │ │ │ └── ed25519.go │ │ │ ├── internal/ │ │ │ │ ├── alias/ │ │ │ │ │ ├── alias.go │ │ │ │ │ └── alias_purego.go │ │ │ │ └── poly1305/ │ │ │ │ ├── mac_noasm.go │ │ │ │ ├── poly1305.go │ │ │ │ ├── sum_amd64.go │ │ │ │ ├── sum_amd64.s │ │ │ │ ├── sum_generic.go │ │ │ │ ├── sum_ppc64le.go │ │ │ │ ├── sum_ppc64le.s │ │ │ │ ├── sum_s390x.go │ │ │ │ └── sum_s390x.s │ │ │ ├── ocsp/ │ │ │ │ └── ocsp.go │ │ │ ├── pbkdf2/ │ │ │ │ └── pbkdf2.go │ │ │ ├── pkcs12/ │ │ │ │ ├── bmp-string.go │ │ │ │ ├── crypto.go │ │ │ │ ├── errors.go │ │ │ │ ├── internal/ │ │ │ │ │ └── rc2/ │ │ │ │ │ └── rc2.go │ │ │ │ ├── mac.go │ │ │ │ ├── pbkdf.go │ │ │ │ ├── pkcs12.go │ │ │ │ └── safebags.go │ │ │ ├── scrypt/ │ │ │ │ └── scrypt.go │ │ │ └── ssh/ │ │ │ ├── buffer.go │ │ │ ├── certs.go │ │ │ ├── channel.go │ │ │ ├── cipher.go │ │ │ ├── client.go │ │ │ ├── client_auth.go │ │ │ ├── common.go │ │ │ ├── connection.go │ │ │ ├── doc.go │ │ │ ├── handshake.go │ │ │ ├── internal/ │ │ │ │ └── bcrypt_pbkdf/ │ │ │ │ └── bcrypt_pbkdf.go │ │ │ ├── kex.go │ │ │ ├── keys.go │ │ │ ├── mac.go │ │ │ ├── messages.go │ │ │ ├── mux.go │ │ │ ├── server.go │ │ │ ├── session.go │ │ │ ├── ssh_gss.go │ │ │ ├── streamlocal.go │ │ │ ├── tcpip.go │ │ │ └── transport.go │ │ ├── net/ │ │ │ ├── LICENSE │ │ │ ├── PATENTS │ │ │ ├── context/ │ │ │ │ └── ctxhttp/ │ │ │ │ └── ctxhttp.go │ │ │ └── idna/ │ │ │ ├── go118.go │ │ │ ├── idna10.0.0.go │ │ │ ├── idna9.0.0.go │ │ │ ├── pre_go118.go │ │ │ ├── punycode.go │ │ │ ├── tables10.0.0.go │ │ │ ├── tables11.0.0.go │ │ │ ├── tables12.0.0.go │ │ │ ├── tables13.0.0.go │ │ │ ├── tables15.0.0.go │ │ │ ├── tables9.0.0.go │ │ │ ├── trie.go │ │ │ ├── trie12.0.0.go │ │ │ ├── trie13.0.0.go │ │ │ └── trieval.go │ │ ├── sys/ │ │ │ ├── LICENSE │ │ │ ├── PATENTS │ │ │ ├── cpu/ │ │ │ │ ├── asm_aix_ppc64.s │ │ │ │ ├── byteorder.go │ │ │ │ ├── cpu.go │ │ │ │ ├── cpu_aix.go │ │ │ │ ├── cpu_arm.go │ │ │ │ ├── cpu_arm64.go │ │ │ │ ├── cpu_arm64.s │ │ │ │ ├── cpu_gc_arm64.go │ │ │ │ ├── cpu_gc_s390x.go │ │ │ │ ├── cpu_gc_x86.go │ │ │ │ ├── cpu_gccgo_arm64.go │ │ │ │ ├── cpu_gccgo_s390x.go │ │ │ │ ├── cpu_gccgo_x86.c │ │ │ │ ├── cpu_gccgo_x86.go │ │ │ │ ├── cpu_linux.go │ │ │ │ ├── cpu_linux_arm.go │ │ │ │ ├── cpu_linux_arm64.go │ │ │ │ ├── cpu_linux_mips64x.go │ │ │ │ ├── cpu_linux_noinit.go │ │ │ │ ├── cpu_linux_ppc64x.go │ │ │ │ ├── cpu_linux_s390x.go │ │ │ │ ├── cpu_loong64.go │ │ │ │ ├── cpu_mips64x.go │ │ │ │ ├── cpu_mipsx.go │ │ │ │ ├── cpu_netbsd_arm64.go │ │ │ │ ├── cpu_openbsd_arm64.go │ │ │ │ ├── cpu_openbsd_arm64.s │ │ │ │ ├── cpu_other_arm.go │ │ │ │ ├── cpu_other_arm64.go │ │ │ │ ├── cpu_other_mips64x.go │ │ │ │ ├── cpu_other_ppc64x.go │ │ │ │ ├── cpu_other_riscv64.go │ │ │ │ ├── cpu_ppc64x.go │ │ │ │ ├── cpu_riscv64.go │ │ │ │ ├── cpu_s390x.go │ │ │ │ ├── cpu_s390x.s │ │ │ │ ├── cpu_wasm.go │ │ │ │ ├── cpu_x86.go │ │ │ │ ├── cpu_x86.s │ │ │ │ ├── cpu_zos.go │ │ │ │ ├── cpu_zos_s390x.go │ │ │ │ ├── endian_big.go │ │ │ │ ├── endian_little.go │ │ │ │ ├── hwcap_linux.go │ │ │ │ ├── parse.go │ │ │ │ ├── proc_cpuinfo_linux.go │ │ │ │ ├── runtime_auxv.go │ │ │ │ ├── runtime_auxv_go121.go │ │ │ │ ├── syscall_aix_gccgo.go │ │ │ │ └── syscall_aix_ppc64_gc.go │ │ │ ├── unix/ │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── affinity_linux.go │ │ │ │ ├── aliases.go │ │ │ │ ├── asm_aix_ppc64.s │ │ │ │ ├── asm_bsd_386.s │ │ │ │ ├── asm_bsd_amd64.s │ │ │ │ ├── asm_bsd_arm.s │ │ │ │ ├── asm_bsd_arm64.s │ │ │ │ ├── asm_bsd_ppc64.s │ │ │ │ ├── asm_bsd_riscv64.s │ │ │ │ ├── asm_linux_386.s │ │ │ │ ├── asm_linux_amd64.s │ │ │ │ ├── asm_linux_arm.s │ │ │ │ ├── asm_linux_arm64.s │ │ │ │ ├── asm_linux_loong64.s │ │ │ │ ├── asm_linux_mips64x.s │ │ │ │ ├── asm_linux_mipsx.s │ │ │ │ ├── asm_linux_ppc64x.s │ │ │ │ ├── asm_linux_riscv64.s │ │ │ │ ├── asm_linux_s390x.s │ │ │ │ ├── asm_openbsd_mips64.s │ │ │ │ ├── asm_solaris_amd64.s │ │ │ │ ├── asm_zos_s390x.s │ │ │ │ ├── bluetooth_linux.go │ │ │ │ ├── cap_freebsd.go │ │ │ │ ├── constants.go │ │ │ │ ├── dev_aix_ppc.go │ │ │ │ ├── dev_aix_ppc64.go │ │ │ │ ├── dev_darwin.go │ │ │ │ ├── dev_dragonfly.go │ │ │ │ ├── dev_freebsd.go │ │ │ │ ├── dev_linux.go │ │ │ │ ├── dev_netbsd.go │ │ │ │ ├── dev_openbsd.go │ │ │ │ ├── dev_zos.go │ │ │ │ ├── dirent.go │ │ │ │ ├── endian_big.go │ │ │ │ ├── endian_little.go │ │ │ │ ├── env_unix.go │ │ │ │ ├── epoll_zos.go │ │ │ │ ├── fcntl.go │ │ │ │ ├── fcntl_darwin.go │ │ │ │ ├── fcntl_linux_32bit.go │ │ │ │ ├── fdset.go │ │ │ │ ├── fstatfs_zos.go │ │ │ │ ├── gccgo.go │ │ │ │ ├── gccgo_c.c │ │ │ │ ├── gccgo_linux_amd64.go │ │ │ │ ├── ifreq_linux.go │ │ │ │ ├── ioctl_linux.go │ │ │ │ ├── ioctl_signed.go │ │ │ │ ├── ioctl_unsigned.go │ │ │ │ ├── ioctl_zos.go │ │ │ │ ├── mkall.sh │ │ │ │ ├── mkerrors.sh │ │ │ │ ├── mmap_nomremap.go │ │ │ │ ├── mremap.go │ │ │ │ ├── pagesize_unix.go │ │ │ │ ├── pledge_openbsd.go │ │ │ │ ├── ptrace_darwin.go │ │ │ │ ├── ptrace_ios.go │ │ │ │ ├── race.go │ │ │ │ ├── race0.go │ │ │ │ ├── readdirent_getdents.go │ │ │ │ ├── readdirent_getdirentries.go │ │ │ │ ├── sockcmsg_dragonfly.go │ │ │ │ ├── sockcmsg_linux.go │ │ │ │ ├── sockcmsg_unix.go │ │ │ │ ├── sockcmsg_unix_other.go │ │ │ │ ├── syscall.go │ │ │ │ ├── syscall_aix.go │ │ │ │ ├── syscall_aix_ppc.go │ │ │ │ ├── syscall_aix_ppc64.go │ │ │ │ ├── syscall_bsd.go │ │ │ │ ├── syscall_darwin.go │ │ │ │ ├── syscall_darwin_amd64.go │ │ │ │ ├── syscall_darwin_arm64.go │ │ │ │ ├── syscall_darwin_libSystem.go │ │ │ │ ├── syscall_dragonfly.go │ │ │ │ ├── syscall_dragonfly_amd64.go │ │ │ │ ├── syscall_freebsd.go │ │ │ │ ├── syscall_freebsd_386.go │ │ │ │ ├── syscall_freebsd_amd64.go │ │ │ │ ├── syscall_freebsd_arm.go │ │ │ │ ├── syscall_freebsd_arm64.go │ │ │ │ ├── syscall_freebsd_riscv64.go │ │ │ │ ├── syscall_hurd.go │ │ │ │ ├── syscall_hurd_386.go │ │ │ │ ├── syscall_illumos.go │ │ │ │ ├── syscall_linux.go │ │ │ │ ├── syscall_linux_386.go │ │ │ │ ├── syscall_linux_alarm.go │ │ │ │ ├── syscall_linux_amd64.go │ │ │ │ ├── syscall_linux_amd64_gc.go │ │ │ │ ├── syscall_linux_arm.go │ │ │ │ ├── syscall_linux_arm64.go │ │ │ │ ├── syscall_linux_gc.go │ │ │ │ ├── syscall_linux_gc_386.go │ │ │ │ ├── syscall_linux_gc_arm.go │ │ │ │ ├── syscall_linux_gccgo_386.go │ │ │ │ ├── syscall_linux_gccgo_arm.go │ │ │ │ ├── syscall_linux_loong64.go │ │ │ │ ├── syscall_linux_mips64x.go │ │ │ │ ├── syscall_linux_mipsx.go │ │ │ │ ├── syscall_linux_ppc.go │ │ │ │ ├── syscall_linux_ppc64x.go │ │ │ │ ├── syscall_linux_riscv64.go │ │ │ │ ├── syscall_linux_s390x.go │ │ │ │ ├── syscall_linux_sparc64.go │ │ │ │ ├── syscall_netbsd.go │ │ │ │ ├── syscall_netbsd_386.go │ │ │ │ ├── syscall_netbsd_amd64.go │ │ │ │ ├── syscall_netbsd_arm.go │ │ │ │ ├── syscall_netbsd_arm64.go │ │ │ │ ├── syscall_openbsd.go │ │ │ │ ├── syscall_openbsd_386.go │ │ │ │ ├── syscall_openbsd_amd64.go │ │ │ │ ├── syscall_openbsd_arm.go │ │ │ │ ├── syscall_openbsd_arm64.go │ │ │ │ ├── syscall_openbsd_libc.go │ │ │ │ ├── syscall_openbsd_mips64.go │ │ │ │ ├── syscall_openbsd_ppc64.go │ │ │ │ ├── syscall_openbsd_riscv64.go │ │ │ │ ├── syscall_solaris.go │ │ │ │ ├── syscall_solaris_amd64.go │ │ │ │ ├── syscall_unix.go │ │ │ │ ├── syscall_unix_gc.go │ │ │ │ ├── syscall_unix_gc_ppc64x.go │ │ │ │ ├── syscall_zos_s390x.go │ │ │ │ ├── sysvshm_linux.go │ │ │ │ ├── sysvshm_unix.go │ │ │ │ ├── sysvshm_unix_other.go │ │ │ │ ├── timestruct.go │ │ │ │ ├── unveil_openbsd.go │ │ │ │ ├── xattr_bsd.go │ │ │ │ ├── zerrors_aix_ppc.go │ │ │ │ ├── zerrors_aix_ppc64.go │ │ │ │ ├── zerrors_darwin_amd64.go │ │ │ │ ├── zerrors_darwin_arm64.go │ │ │ │ ├── zerrors_dragonfly_amd64.go │ │ │ │ ├── zerrors_freebsd_386.go │ │ │ │ ├── zerrors_freebsd_amd64.go │ │ │ │ ├── zerrors_freebsd_arm.go │ │ │ │ ├── zerrors_freebsd_arm64.go │ │ │ │ ├── zerrors_freebsd_riscv64.go │ │ │ │ ├── zerrors_linux.go │ │ │ │ ├── zerrors_linux_386.go │ │ │ │ ├── zerrors_linux_amd64.go │ │ │ │ ├── zerrors_linux_arm.go │ │ │ │ ├── zerrors_linux_arm64.go │ │ │ │ ├── zerrors_linux_loong64.go │ │ │ │ ├── zerrors_linux_mips.go │ │ │ │ ├── zerrors_linux_mips64.go │ │ │ │ ├── zerrors_linux_mips64le.go │ │ │ │ ├── zerrors_linux_mipsle.go │ │ │ │ ├── zerrors_linux_ppc.go │ │ │ │ ├── zerrors_linux_ppc64.go │ │ │ │ ├── zerrors_linux_ppc64le.go │ │ │ │ ├── zerrors_linux_riscv64.go │ │ │ │ ├── zerrors_linux_s390x.go │ │ │ │ ├── zerrors_linux_sparc64.go │ │ │ │ ├── zerrors_netbsd_386.go │ │ │ │ ├── zerrors_netbsd_amd64.go │ │ │ │ ├── zerrors_netbsd_arm.go │ │ │ │ ├── zerrors_netbsd_arm64.go │ │ │ │ ├── zerrors_openbsd_386.go │ │ │ │ ├── zerrors_openbsd_amd64.go │ │ │ │ ├── zerrors_openbsd_arm.go │ │ │ │ ├── zerrors_openbsd_arm64.go │ │ │ │ ├── zerrors_openbsd_mips64.go │ │ │ │ ├── zerrors_openbsd_ppc64.go │ │ │ │ ├── zerrors_openbsd_riscv64.go │ │ │ │ ├── zerrors_solaris_amd64.go │ │ │ │ ├── zerrors_zos_s390x.go │ │ │ │ ├── zptrace_armnn_linux.go │ │ │ │ ├── zptrace_linux_arm64.go │ │ │ │ ├── zptrace_mipsnn_linux.go │ │ │ │ ├── zptrace_mipsnnle_linux.go │ │ │ │ ├── zptrace_x86_linux.go │ │ │ │ ├── zsyscall_aix_ppc.go │ │ │ │ ├── zsyscall_aix_ppc64.go │ │ │ │ ├── zsyscall_aix_ppc64_gc.go │ │ │ │ ├── zsyscall_aix_ppc64_gccgo.go │ │ │ │ ├── zsyscall_darwin_amd64.go │ │ │ │ ├── zsyscall_darwin_amd64.s │ │ │ │ ├── zsyscall_darwin_arm64.go │ │ │ │ ├── zsyscall_darwin_arm64.s │ │ │ │ ├── zsyscall_dragonfly_amd64.go │ │ │ │ ├── zsyscall_freebsd_386.go │ │ │ │ ├── zsyscall_freebsd_amd64.go │ │ │ │ ├── zsyscall_freebsd_arm.go │ │ │ │ ├── zsyscall_freebsd_arm64.go │ │ │ │ ├── zsyscall_freebsd_riscv64.go │ │ │ │ ├── zsyscall_illumos_amd64.go │ │ │ │ ├── zsyscall_linux.go │ │ │ │ ├── zsyscall_linux_386.go │ │ │ │ ├── zsyscall_linux_amd64.go │ │ │ │ ├── zsyscall_linux_arm.go │ │ │ │ ├── zsyscall_linux_arm64.go │ │ │ │ ├── zsyscall_linux_loong64.go │ │ │ │ ├── zsyscall_linux_mips.go │ │ │ │ ├── zsyscall_linux_mips64.go │ │ │ │ ├── zsyscall_linux_mips64le.go │ │ │ │ ├── zsyscall_linux_mipsle.go │ │ │ │ ├── zsyscall_linux_ppc.go │ │ │ │ ├── zsyscall_linux_ppc64.go │ │ │ │ ├── zsyscall_linux_ppc64le.go │ │ │ │ ├── zsyscall_linux_riscv64.go │ │ │ │ ├── zsyscall_linux_s390x.go │ │ │ │ ├── zsyscall_linux_sparc64.go │ │ │ │ ├── zsyscall_netbsd_386.go │ │ │ │ ├── zsyscall_netbsd_amd64.go │ │ │ │ ├── zsyscall_netbsd_arm.go │ │ │ │ ├── zsyscall_netbsd_arm64.go │ │ │ │ ├── zsyscall_openbsd_386.go │ │ │ │ ├── zsyscall_openbsd_386.s │ │ │ │ ├── zsyscall_openbsd_amd64.go │ │ │ │ ├── zsyscall_openbsd_amd64.s │ │ │ │ ├── zsyscall_openbsd_arm.go │ │ │ │ ├── zsyscall_openbsd_arm.s │ │ │ │ ├── zsyscall_openbsd_arm64.go │ │ │ │ ├── zsyscall_openbsd_arm64.s │ │ │ │ ├── zsyscall_openbsd_mips64.go │ │ │ │ ├── zsyscall_openbsd_mips64.s │ │ │ │ ├── zsyscall_openbsd_ppc64.go │ │ │ │ ├── zsyscall_openbsd_ppc64.s │ │ │ │ ├── zsyscall_openbsd_riscv64.go │ │ │ │ ├── zsyscall_openbsd_riscv64.s │ │ │ │ ├── zsyscall_solaris_amd64.go │ │ │ │ ├── zsyscall_zos_s390x.go │ │ │ │ ├── zsysctl_openbsd_386.go │ │ │ │ ├── zsysctl_openbsd_amd64.go │ │ │ │ ├── zsysctl_openbsd_arm.go │ │ │ │ ├── zsysctl_openbsd_arm64.go │ │ │ │ ├── zsysctl_openbsd_mips64.go │ │ │ │ ├── zsysctl_openbsd_ppc64.go │ │ │ │ ├── zsysctl_openbsd_riscv64.go │ │ │ │ ├── zsysnum_darwin_amd64.go │ │ │ │ ├── zsysnum_darwin_arm64.go │ │ │ │ ├── zsysnum_dragonfly_amd64.go │ │ │ │ ├── zsysnum_freebsd_386.go │ │ │ │ ├── zsysnum_freebsd_amd64.go │ │ │ │ ├── zsysnum_freebsd_arm.go │ │ │ │ ├── zsysnum_freebsd_arm64.go │ │ │ │ ├── zsysnum_freebsd_riscv64.go │ │ │ │ ├── zsysnum_linux_386.go │ │ │ │ ├── zsysnum_linux_amd64.go │ │ │ │ ├── zsysnum_linux_arm.go │ │ │ │ ├── zsysnum_linux_arm64.go │ │ │ │ ├── zsysnum_linux_loong64.go │ │ │ │ ├── zsysnum_linux_mips.go │ │ │ │ ├── zsysnum_linux_mips64.go │ │ │ │ ├── zsysnum_linux_mips64le.go │ │ │ │ ├── zsysnum_linux_mipsle.go │ │ │ │ ├── zsysnum_linux_ppc.go │ │ │ │ ├── zsysnum_linux_ppc64.go │ │ │ │ ├── zsysnum_linux_ppc64le.go │ │ │ │ ├── zsysnum_linux_riscv64.go │ │ │ │ ├── zsysnum_linux_s390x.go │ │ │ │ ├── zsysnum_linux_sparc64.go │ │ │ │ ├── zsysnum_netbsd_386.go │ │ │ │ ├── zsysnum_netbsd_amd64.go │ │ │ │ ├── zsysnum_netbsd_arm.go │ │ │ │ ├── zsysnum_netbsd_arm64.go │ │ │ │ ├── zsysnum_openbsd_386.go │ │ │ │ ├── zsysnum_openbsd_amd64.go │ │ │ │ ├── zsysnum_openbsd_arm.go │ │ │ │ ├── zsysnum_openbsd_arm64.go │ │ │ │ ├── zsysnum_openbsd_mips64.go │ │ │ │ ├── zsysnum_openbsd_ppc64.go │ │ │ │ ├── zsysnum_openbsd_riscv64.go │ │ │ │ ├── zsysnum_zos_s390x.go │ │ │ │ ├── ztypes_aix_ppc.go │ │ │ │ ├── ztypes_aix_ppc64.go │ │ │ │ ├── ztypes_darwin_amd64.go │ │ │ │ ├── ztypes_darwin_arm64.go │ │ │ │ ├── ztypes_dragonfly_amd64.go │ │ │ │ ├── ztypes_freebsd_386.go │ │ │ │ ├── ztypes_freebsd_amd64.go │ │ │ │ ├── ztypes_freebsd_arm.go │ │ │ │ ├── ztypes_freebsd_arm64.go │ │ │ │ ├── ztypes_freebsd_riscv64.go │ │ │ │ ├── ztypes_linux.go │ │ │ │ ├── ztypes_linux_386.go │ │ │ │ ├── ztypes_linux_amd64.go │ │ │ │ ├── ztypes_linux_arm.go │ │ │ │ ├── ztypes_linux_arm64.go │ │ │ │ ├── ztypes_linux_loong64.go │ │ │ │ ├── ztypes_linux_mips.go │ │ │ │ ├── ztypes_linux_mips64.go │ │ │ │ ├── ztypes_linux_mips64le.go │ │ │ │ ├── ztypes_linux_mipsle.go │ │ │ │ ├── ztypes_linux_ppc.go │ │ │ │ ├── ztypes_linux_ppc64.go │ │ │ │ ├── ztypes_linux_ppc64le.go │ │ │ │ ├── ztypes_linux_riscv64.go │ │ │ │ ├── ztypes_linux_s390x.go │ │ │ │ ├── ztypes_linux_sparc64.go │ │ │ │ ├── ztypes_netbsd_386.go │ │ │ │ ├── ztypes_netbsd_amd64.go │ │ │ │ ├── ztypes_netbsd_arm.go │ │ │ │ ├── ztypes_netbsd_arm64.go │ │ │ │ ├── ztypes_openbsd_386.go │ │ │ │ ├── ztypes_openbsd_amd64.go │ │ │ │ ├── ztypes_openbsd_arm.go │ │ │ │ ├── ztypes_openbsd_arm64.go │ │ │ │ ├── ztypes_openbsd_mips64.go │ │ │ │ ├── ztypes_openbsd_ppc64.go │ │ │ │ ├── ztypes_openbsd_riscv64.go │ │ │ │ ├── ztypes_solaris_amd64.go │ │ │ │ └── ztypes_zos_s390x.go │ │ │ └── windows/ │ │ │ ├── aliases.go │ │ │ ├── dll_windows.go │ │ │ ├── empty.s │ │ │ ├── env_windows.go │ │ │ ├── eventlog.go │ │ │ ├── exec_windows.go │ │ │ ├── memory_windows.go │ │ │ ├── mkerrors.bash │ │ │ ├── mkknownfolderids.bash │ │ │ ├── mksyscall.go │ │ │ ├── race.go │ │ │ ├── race0.go │ │ │ ├── security_windows.go │ │ │ ├── service.go │ │ │ ├── setupapi_windows.go │ │ │ ├── str.go │ │ │ ├── syscall.go │ │ │ ├── syscall_windows.go │ │ │ ├── types_windows.go │ │ │ ├── types_windows_386.go │ │ │ ├── types_windows_amd64.go │ │ │ ├── types_windows_arm.go │ │ │ ├── types_windows_arm64.go │ │ │ ├── zerrors_windows.go │ │ │ ├── zknownfolderids_windows.go │ │ │ └── zsyscall_windows.go │ │ └── text/ │ │ ├── LICENSE │ │ ├── PATENTS │ │ ├── secure/ │ │ │ └── bidirule/ │ │ │ ├── bidirule.go │ │ │ ├── bidirule10.0.0.go │ │ │ └── bidirule9.0.0.go │ │ ├── transform/ │ │ │ └── transform.go │ │ └── unicode/ │ │ ├── bidi/ │ │ │ ├── bidi.go │ │ │ ├── bracket.go │ │ │ ├── core.go │ │ │ ├── prop.go │ │ │ ├── tables10.0.0.go │ │ │ ├── tables11.0.0.go │ │ │ ├── tables12.0.0.go │ │ │ ├── tables13.0.0.go │ │ │ ├── tables15.0.0.go │ │ │ ├── tables9.0.0.go │ │ │ └── trieval.go │ │ └── norm/ │ │ ├── composition.go │ │ ├── forminfo.go │ │ ├── input.go │ │ ├── iter.go │ │ ├── normalize.go │ │ ├── readwriter.go │ │ ├── tables10.0.0.go │ │ ├── tables11.0.0.go │ │ ├── tables12.0.0.go │ │ ├── tables13.0.0.go │ │ ├── tables15.0.0.go │ │ ├── tables9.0.0.go │ │ ├── transform.go │ │ └── trie.go │ ├── google.golang.org/ │ │ └── protobuf/ │ │ ├── LICENSE │ │ ├── PATENTS │ │ ├── encoding/ │ │ │ ├── protodelim/ │ │ │ │ └── protodelim.go │ │ │ ├── prototext/ │ │ │ │ ├── decode.go │ │ │ │ ├── doc.go │ │ │ │ └── encode.go │ │ │ └── protowire/ │ │ │ └── wire.go │ │ ├── internal/ │ │ │ ├── descfmt/ │ │ │ │ └── stringer.go │ │ │ ├── descopts/ │ │ │ │ └── options.go │ │ │ ├── detrand/ │ │ │ │ └── rand.go │ │ │ ├── editiondefaults/ │ │ │ │ ├── defaults.go │ │ │ │ └── editions_defaults.binpb │ │ │ ├── encoding/ │ │ │ │ ├── defval/ │ │ │ │ │ └── default.go │ │ │ │ ├── messageset/ │ │ │ │ │ └── messageset.go │ │ │ │ ├── tag/ │ │ │ │ │ └── tag.go │ │ │ │ └── text/ │ │ │ │ ├── decode.go │ │ │ │ ├── decode_number.go │ │ │ │ ├── decode_string.go │ │ │ │ ├── decode_token.go │ │ │ │ ├── doc.go │ │ │ │ └── encode.go │ │ │ ├── errors/ │ │ │ │ ├── errors.go │ │ │ │ ├── is_go112.go │ │ │ │ └── is_go113.go │ │ │ ├── filedesc/ │ │ │ │ ├── build.go │ │ │ │ ├── desc.go │ │ │ │ ├── desc_init.go │ │ │ │ ├── desc_lazy.go │ │ │ │ ├── desc_list.go │ │ │ │ ├── desc_list_gen.go │ │ │ │ ├── editions.go │ │ │ │ └── placeholder.go │ │ │ ├── filetype/ │ │ │ │ └── build.go │ │ │ ├── flags/ │ │ │ │ ├── flags.go │ │ │ │ ├── proto_legacy_disable.go │ │ │ │ └── proto_legacy_enable.go │ │ │ ├── genid/ │ │ │ │ ├── any_gen.go │ │ │ │ ├── api_gen.go │ │ │ │ ├── descriptor_gen.go │ │ │ │ ├── doc.go │ │ │ │ ├── duration_gen.go │ │ │ │ ├── empty_gen.go │ │ │ │ ├── field_mask_gen.go │ │ │ │ ├── go_features_gen.go │ │ │ │ ├── goname.go │ │ │ │ ├── map_entry.go │ │ │ │ ├── source_context_gen.go │ │ │ │ ├── struct_gen.go │ │ │ │ ├── timestamp_gen.go │ │ │ │ ├── type_gen.go │ │ │ │ ├── wrappers.go │ │ │ │ └── wrappers_gen.go │ │ │ ├── impl/ │ │ │ │ ├── api_export.go │ │ │ │ ├── checkinit.go │ │ │ │ ├── codec_extension.go │ │ │ │ ├── codec_field.go │ │ │ │ ├── codec_gen.go │ │ │ │ ├── codec_map.go │ │ │ │ ├── codec_map_go111.go │ │ │ │ ├── codec_map_go112.go │ │ │ │ ├── codec_message.go │ │ │ │ ├── codec_messageset.go │ │ │ │ ├── codec_reflect.go │ │ │ │ ├── codec_tables.go │ │ │ │ ├── codec_unsafe.go │ │ │ │ ├── convert.go │ │ │ │ ├── convert_list.go │ │ │ │ ├── convert_map.go │ │ │ │ ├── decode.go │ │ │ │ ├── encode.go │ │ │ │ ├── enum.go │ │ │ │ ├── extension.go │ │ │ │ ├── legacy_enum.go │ │ │ │ ├── legacy_export.go │ │ │ │ ├── legacy_extension.go │ │ │ │ ├── legacy_file.go │ │ │ │ ├── legacy_message.go │ │ │ │ ├── merge.go │ │ │ │ ├── merge_gen.go │ │ │ │ ├── message.go │ │ │ │ ├── message_reflect.go │ │ │ │ ├── message_reflect_field.go │ │ │ │ ├── message_reflect_gen.go │ │ │ │ ├── pointer_reflect.go │ │ │ │ ├── pointer_unsafe.go │ │ │ │ ├── validate.go │ │ │ │ └── weak.go │ │ │ ├── order/ │ │ │ │ ├── order.go │ │ │ │ └── range.go │ │ │ ├── pragma/ │ │ │ │ └── pragma.go │ │ │ ├── set/ │ │ │ │ └── ints.go │ │ │ ├── strs/ │ │ │ │ ├── strings.go │ │ │ │ ├── strings_pure.go │ │ │ │ ├── strings_unsafe_go120.go │ │ │ │ └── strings_unsafe_go121.go │ │ │ └── version/ │ │ │ └── version.go │ │ ├── proto/ │ │ │ ├── checkinit.go │ │ │ ├── decode.go │ │ │ ├── decode_gen.go │ │ │ ├── doc.go │ │ │ ├── encode.go │ │ │ ├── encode_gen.go │ │ │ ├── equal.go │ │ │ ├── extension.go │ │ │ ├── merge.go │ │ │ ├── messageset.go │ │ │ ├── proto.go │ │ │ ├── proto_methods.go │ │ │ ├── proto_reflect.go │ │ │ ├── reset.go │ │ │ ├── size.go │ │ │ ├── size_gen.go │ │ │ └── wrappers.go │ │ ├── reflect/ │ │ │ ├── protoreflect/ │ │ │ │ ├── methods.go │ │ │ │ ├── proto.go │ │ │ │ ├── source.go │ │ │ │ ├── source_gen.go │ │ │ │ ├── type.go │ │ │ │ ├── value.go │ │ │ │ ├── value_equal.go │ │ │ │ ├── value_pure.go │ │ │ │ ├── value_union.go │ │ │ │ ├── value_unsafe_go120.go │ │ │ │ └── value_unsafe_go121.go │ │ │ └── protoregistry/ │ │ │ └── registry.go │ │ ├── runtime/ │ │ │ ├── protoiface/ │ │ │ │ ├── legacy.go │ │ │ │ └── methods.go │ │ │ └── protoimpl/ │ │ │ ├── impl.go │ │ │ └── version.go │ │ └── types/ │ │ └── known/ │ │ └── timestamppb/ │ │ └── timestamp.pb.go │ ├── k8s.io/ │ │ └── klog/ │ │ └── v2/ │ │ ├── .gitignore │ │ ├── .golangci.yaml │ │ ├── CONTRIBUTING.md │ │ ├── LICENSE │ │ ├── OWNERS │ │ ├── README.md │ │ ├── RELEASE.md │ │ ├── SECURITY.md │ │ ├── SECURITY_CONTACTS │ │ ├── code-of-conduct.md │ │ ├── contextual.go │ │ ├── contextual_slog.go │ │ ├── exit.go │ │ ├── format.go │ │ ├── imports.go │ │ ├── internal/ │ │ │ ├── buffer/ │ │ │ │ └── buffer.go │ │ │ ├── clock/ │ │ │ │ ├── README.md │ │ │ │ └── clock.go │ │ │ ├── dbg/ │ │ │ │ └── dbg.go │ │ │ ├── serialize/ │ │ │ │ ├── keyvalues.go │ │ │ │ ├── keyvalues_no_slog.go │ │ │ │ └── keyvalues_slog.go │ │ │ ├── severity/ │ │ │ │ └── severity.go │ │ │ └── sloghandler/ │ │ │ └── sloghandler_slog.go │ │ ├── k8s_references.go │ │ ├── k8s_references_slog.go │ │ ├── klog.go │ │ ├── klog_file.go │ │ ├── klog_file_others.go │ │ ├── klog_file_windows.go │ │ ├── klogr.go │ │ ├── klogr_slog.go │ │ └── safeptr.go │ └── modules.txt └── whitelist/ ├── LICENSE ├── README.md ├── example/ │ └── example_whitelist.go ├── http_test.go ├── lookup.go ├── whitelist.go ├── whitelist_net.go ├── whitelist_net_test.go └── whitelist_test.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ cfssl_* *-amd64 *-386 dist/* .git ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: github-actions directory: / schedule: interval: weekly - package-ecosystem: gomod directory: / schedule: interval: weekly ================================================ FILE: .github/workflows/docker-builds.yml ================================================ name: cfssl docker on: workflow_dispatch: push: branches: - "master" tags: - "v*" jobs: build-and-push-image: runs-on: ubuntu-latest permissions: contents: read packages: write strategy: matrix: include: # github container registry - registry: "ghcr.io" username: ${{ github.actor }} password_secret: GITHUB_TOKEN image: ghcr.io/cloudflare/cfssl # docker test publish, todo: switch to service account - registry: "" username: nicky password_secret: DOCKER_REGISTRY_TOKEN_NICKY image: cfssl/cfssl steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to the Docker hub uses: docker/login-action@v3 with: registry: ${{ matrix.registry }} username: ${{ matrix.username }} password: ${{ secrets[matrix.password_secret] }} - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@v5 with: images: ${{ matrix.image }} - name: Build and push uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64,linux/s390x push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} ================================================ FILE: .github/workflows/go.yml ================================================ name: Go on: push: pull_request: branches: [master] jobs: build: runs-on: ubuntu-latest strategy: matrix: # starting with go 1.24 the GODEBUG=x509sha1=1 flag has been removed. # many tests rely on sha1 certificates. After resolving #1413 we can # run these on stable and oldstable again. Min version (1.20) can # always be run. go: ['1.23', '1.22', '1.20'] services: # Label used to access the service container postgres: # Docker Hub image image: postgres # Provide the password for postgres env: POSTGRES_DB: postgres_db POSTGRES_PASSWORD: "" POSTGRES_HOST_AUTH_METHOD: trust # allow no password POSTGRES_PORT: 5432 POSTGRES_USER: postgres # Set health checks to wait until postgres has started options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 5432:5432 mysql: image: mysql env: MYSQL_ALLOW_EMPTY_PASSWORD: yes MYSQL_ROOT_PASSWORD: "" ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 env: GOFLAGS: "-mod=vendor" GODEBUG: "x509sha1=1" BUILD_TAGS: "postgresql" PGHOST: localhost MYSQL_HOST: 127.0.0.1 steps: - run: psql -c 'create database certdb_development;' -U postgres; - run: mysql -e 'create database certdb_development;' -u root; - run: mysql -e 'SET global sql_mode = 0;' -u root; - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} - name: Build run: go build -v ./... - run: make bin/goose; - run: ./bin/goose -path certdb/pg up; - run: ./bin/goose -path certdb/mysql up; - name: Test run: ./test.sh - uses: codecov/codecov-action@v4 golangci: name: lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: "1.20" - name: golangci-lint uses: golangci/golangci-lint-action@v6 with: # There is a breaking change in 1.58 that causes the linter not to recognize # internal imports or standard library imports and results in linting errors # that cannot be ignored. # e.g certdb/certdb.go:5:2: could not import encoding/json (Config.Importer.Import(encoding/json) returned nil but no error) (typecheck) version: v1.57 ================================================ FILE: .github/workflows/semgrep.yml ================================================ on: pull_request: {} workflow_dispatch: {} push: branches: - main - master schedule: - cron: '0 0 * * *' name: Semgrep config jobs: semgrep: name: semgrep/ci runs-on: ubuntu-latest env: SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} SEMGREP_URL: https://cloudflare.semgrep.dev SEMGREP_APP_URL: https://cloudflare.semgrep.dev SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version container: image: semgrep/semgrep steps: - uses: actions/checkout@v4 - run: semgrep ci ================================================ FILE: .github/workflows/snapshot.yml ================================================ name: Image snapshots on: push: pull_request: branches: [master] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: make snapshot - name: Archive snapshot artifacts uses: actions/upload-artifact@v4 with: name: binaries path: dist/ ================================================ FILE: .gitignore ================================================ dist/* coverage.txt profile.out bin *.deb *.rpm test .DS_Store ================================================ FILE: .golangci.yaml ================================================ linters: disable: - staticcheck - govet - gosimple - ineffassign - unused - errcheck ================================================ FILE: .goreleaser.yml ================================================ env: - GO111MODULE=on - CGO_ENABLED=0 - GOFLAGS=-mod=vendor - GOPROXY=off builds: - id: cfssl-darwin binary: cfssl env: - CC=o64-clang - CXX=o64-clang++ - CGO_ENABLED=1 goos: - darwin goarch: - amd64 - arm64 main: ./cmd/cfssl ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-linux binary: cfssl goos: - linux goarch: - amd64 - arm - arm64 - s390x main: ./cmd/cfssl ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-windows binary: cfssl env: - CC=x86_64-w64-mingw32-gcc - CXX=x86_64-w64-mingw32-g++ goos: - windows goarch: - amd64 main: ./cmd/cfssl ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-bundle-darwin binary: cfssl-bundle env: - CC=o64-clang - CXX=o64-clang++ - CGO_ENABLED=1 goos: - darwin goarch: - amd64 main: ./cmd/cfssl-bundle ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-bundle-linux binary: cfssl-bundle goos: - linux goarch: - amd64 - arm - arm64 - s390x main: ./cmd/cfssl-bundle ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-bundle-windows binary: cfssl-bundle env: - CC=x86_64-w64-mingw32-gcc - CXX=x86_64-w64-mingw32-g++ goos: - windows goarch: - amd64 main: ./cmd/cfssl-bundle ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-certinfo-darwin binary: cfssl-certinfo env: - CC=o64-clang - CXX=o64-clang++ - CGO_ENABLED=1 goos: - darwin goarch: - amd64 main: ./cmd/cfssl-certinfo ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-certinfo-linux binary: cfssl-certinfo goos: - linux goarch: - amd64 - arm - arm64 - s390x main: ./cmd/cfssl-certinfo ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-certinfo-windows binary: cfssl-certinfo env: - CC=x86_64-w64-mingw32-gcc - CXX=x86_64-w64-mingw32-g++ goos: - windows goarch: - amd64 main: ./cmd/cfssl-certinfo ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-newkey-darwin binary: cfssl-newkey env: - CC=o64-clang - CXX=o64-clang++ - CGO_ENABLED=1 goos: - darwin goarch: - amd64 main: ./cmd/cfssl-newkey ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-newkey-linux binary: cfssl-newkey goos: - linux goarch: - amd64 - arm - arm64 - s390x main: ./cmd/cfssl-newkey ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-newkey-windows binary: cfssl-newkey env: - CC=x86_64-w64-mingw32-gcc - CXX=x86_64-w64-mingw32-g++ goos: - windows goarch: - amd64 main: ./cmd/cfssl-newkey ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-scan-darwin binary: cfssl-scan env: - CC=o64-clang - CXX=o64-clang++ - CGO_ENABLED=1 goos: - darwin goarch: - amd64 main: ./cmd/cfssl-scan ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-scan-linux binary: cfssl-scan goos: - linux goarch: - amd64 - arm - arm64 - s390x main: ./cmd/cfssl-scan ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssl-scan-windows binary: cfssl-scan env: - CC=x86_64-w64-mingw32-gcc - CXX=x86_64-w64-mingw32-g++ goos: - windows goarch: - amd64 main: ./cmd/cfssl-scan ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssljson-darwin binary: cfssljson env: - CC=o64-clang - CXX=o64-clang++ - CGO_ENABLED=1 goos: - darwin goarch: - amd64 main: ./cmd/cfssljson ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssljson-linux binary: cfssljson goos: - linux goarch: - amd64 - arm - arm64 - s390x main: ./cmd/cfssljson ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: cfssljson-windows binary: cfssljson env: - CC=x86_64-w64-mingw32-gcc - CXX=x86_64-w64-mingw32-g++ goos: - windows goarch: - amd64 main: ./cmd/cfssljson ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: mkbundle-darwin binary: mkbundle env: - CC=o64-clang - CXX=o64-clang++ - CGO_ENABLED=1 goos: - darwin goarch: - amd64 main: ./cmd/mkbundle ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: mkbundle-linux binary: mkbundle goos: - linux goarch: - amd64 - arm - arm64 - s390x main: ./cmd/mkbundle ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: mkbundle-windows binary: mkbundle env: - CC=x86_64-w64-mingw32-gcc - CXX=x86_64-w64-mingw32-g++ goos: - windows goarch: - amd64 main: ./cmd/mkbundle ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: multirootca-darwin binary: multirootca env: - CC=o64-clang - CXX=o64-clang++ - CGO_ENABLED=1 goos: - darwin goarch: - amd64 main: ./cmd/multirootca ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: multirootca-linux binary: multirootca goos: - linux goarch: - amd64 - arm - arm64 - s390x main: ./cmd/multirootca ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} - id: multirootca-windows binary: multirootca env: - CC=x86_64-w64-mingw32-gcc - CXX=x86_64-w64-mingw32-g++ goos: - windows goarch: - amd64 main: ./cmd/multirootca ldflags: - -s -w -X github.com/cloudflare/cfssl/cli/version.version={{.Version}} archives: - format: binary allow_different_binary_count: true # https://github.com/goreleaser/goreleaser/pull/1841 release: github: owner: cloudflare name: cfssl prerelease: auto changelog: sort: asc ================================================ FILE: CHANGELOG ================================================ 1.1.0 - 2015-08-04 ADDED: - Revocation now checks OCSP status. - Authenticated endpoints are now supported using HMAC tags. - Bundle can verify certificates against a domain or IP. - OCSP subcommand has been added. - PKCS #11 keys are now supported; this support is now the default. - OCSP serving is now implemented. - The multirootca tool is now available for multiple signing keys via an authenticated API. - A scan utility for checking the quality of a server's TLS configuration. - The certificate bundler now supports PKCS #7 and PKCS #12. - An info endpoint has been added to retrieve the signers' certificates. - Signers can now use a serial sequence number for certificate serial numbers; the default remains randomised serial numbers. - CSR whitelisting allows the signer to explicitly distrust certain fields in a CSR. - Signing profiles can include certificate policies and their qualifiers. - The multirootca can use Red October-secured private keys. - The multirootca can whitelist CSRs per-signer based on an IP network whitelist. - The signer can whitelist SANs and common names via a regular- expression whitelist. - Multiple fallback remote signers are now supported in the cfssl server. - A Docker build script has been provided to facilitate building CFSSL for all supported platforms. - The log package includes a new logging level, fatal, that immediately exits with error after printing the log message. CHANGED: - CLI tool can read from standard input. - The -f flag has been renamed to -config. - Signers have been refactored into local and remote signers under a single universal signer abstraction. - The CLI subcommands have been refactored into separate packages. - Signing can now extract subject information from a CSR. - Various improvements to the certificate ubiquity scoring, such as accounting for SHA1 deprecation. - The bundle CLI tool can set the intermediates directory that newly found intermediates can be stored in. - The CLI tools return exit code 1 on failure. CONTRIBUTORS: Alice Xia Dan Rohr Didier Smith Dominic Luechinger Erik Kristensen Fabian Ruff George Tankersley Harald Wagener Harry Harpham Jacob H. Haven Jacob Hoffman-Andrews Joshua Kroll Kyle Isom Nick Sullivan Peter Eckersley Richard Barnes Sophie Huang Steve Rude Tara Vancil Terin Stock Thomaz Leite Travis Truman Zi Lin ================================================ FILE: Dockerfile ================================================ FROM --platform=${TARGETPLATFORM} golang:1.20 ARG TARGETPLATFORM ARG BUILDPLATFORM RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" LABEL org.opencontainers.image.source https://github.com/cloudflare/cfssl LABEL org.opencontainers.image.description "Cloudflare's PKI toolkit" ARG TARGETOS ARG TARGETARCH WORKDIR /workdir COPY . /workdir RUN git clone https://github.com/cloudflare/cfssl_trust.git /etc/cfssl && \ make clean && \ GOOS=${TARGETOS} GOARCH=${TARGETARCH} make all && cp bin/* /usr/bin/ EXPOSE 8888 ENTRYPOINT ["cfssl"] CMD ["--help"] ================================================ FILE: Dockerfile.alpine ================================================ FROM golang:1.20-alpine AS builder WORKDIR /workdir COPY . /workdir RUN set -x && \ apk --no-cache add git gcc libc-dev make RUN git clone https://github.com/cloudflare/cfssl_trust.git /etc/cfssl && \ make clean && \ make all FROM alpine:3.11 COPY --from=builder /etc/cfssl /etc/cfssl COPY --from=builder /workdir/bin/ /usr/bin EXPOSE 8888 ENTRYPOINT ["cfssl"] CMD ["--help"] ================================================ FILE: LICENSE ================================================ Copyright (c) 2014 CloudFlare Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: Makefile ================================================ VERSION := $(shell git describe --tags --abbrev=0 | tr -d '[:alpha:]') LDFLAGS := "-s -w -X github.com/cloudflare/cfssl/cli/version.version=$(VERSION)" export GOFLAGS := -mod=vendor export GOPROXY := off .PHONY: all all: bin/cfssl bin/cfssl-bundle bin/cfssl-certinfo bin/cfssl-newkey bin/cfssl-scan bin/cfssljson bin/mkbundle bin/multirootca bin/%: $(shell find . -type f -name '*.go') @mkdir -p $(dir $@) ifneq ($(and $(TARGETOS),$(TARGETARCH)),) GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -ldflags $(LDFLAGS) -o $@ ./cmd/$(@F) else go build -ldflags $(LDFLAGS) -o $@ ./cmd/$(@F) endif .PHONY: install install: install-cfssl install-cfssl-bundle install-cfssl-certinfo install-cfssl-newkey install-cfssl-scan install-cfssljson install-mkbundle install-multirootca .PHONY: install-% install-%: go install ./cmd/$(@F:install-%=%) .PHONY: serve serve: bin/cfssl serve: ./bin/cfssl serve bin/goose: $(shell find vendor -type f -name '*.go') @mkdir -p $(dir $@) ifneq ($(and $(TARGETOS),$(TARGETARCH)),) GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -o $@ ./vendor/bitbucket.org/liamstask/goose/cmd/goose else go build -o $@ ./vendor/bitbucket.org/liamstask/goose/cmd/goose endif .PHONY: clean clean: rm -rf bin *.deb *.rpm # Check that given variables are set and all have non-empty values, # die with an error otherwise. # # Params: # 1. Variable name(s) to test. # 2. (optional) Error message to print. # # cf: https://stackoverflow.com/questions/10858261/abort-makefile-if-variable-not-set check_defined = \ $(strip $(foreach 1,$1, \ $(call __check_defined,$1,$(strip $(value 2))))) __check_defined = \ $(if $(value $1),, \ $(error Undefined $1$(if $2, ($2)))) .PHONY: snapshot snapshot: docker run \ --rm \ -v $(PWD):/cross \ -w /cross \ ghcr.io/goreleaser/goreleaser-cross:latest --clean --snapshot --skip=publish .PHONY: github-release github-release: @:$(call check_defined, GITHUB_TOKEN) docker run \ --rm \ -e GITHUB_TOKEN=$(GITHUB_TOKEN) \ -v $(PWD):/cross \ -w /cross \ ghcr.io/goreleaser/goreleaser-cross:latest --clean .PHONY: release release: github-release BUILD_PATH := $(CURDIR)/build INSTALL_PATH := $(BUILD_PATH)/usr/local/bin FPM = fakeroot fpm -C $(BUILD_PATH) \ -a $(shell uname -m) \ -s dir \ -v $(VERSION) \ --url 'https://github.com/cloudflare/cfssl' \ --vendor Cloudflare \ -n cfssl .PHONY: package package: package-deb package-rpm .PHONY: package-deb package-deb: all $(RM) -r build mkdir -p $(INSTALL_PATH) cp bin/* $(INSTALL_PATH) $(FPM) -t deb . .PHONY: package-rpm package-rpm: all $(RM) -r build mkdir -p $(INSTALL_PATH) cp bin/* $(INSTALL_PATH) $(FPM) -t rpm . ================================================ FILE: README.md ================================================ # CFSSL [![Build Status](https://travis-ci.org/cloudflare/cfssl.svg?branch=master)](https://travis-ci.org/cloudflare/cfssl) [![Coverage Status](http://codecov.io/github/cloudflare/cfssl/coverage.svg?branch=master)](http://codecov.io/github/cloudflare/cfssl?branch=master) [![GoDoc](https://godoc.org/github.com/cloudflare/cfssl?status.svg)](https://godoc.org/github.com/cloudflare/cfssl) ## CloudFlare's PKI/TLS toolkit CFSSL is CloudFlare's PKI/TLS swiss army knife. It is both a command line tool and an HTTP API server for signing, verifying, and bundling TLS certificates. It requires Go 1.20+ to build. Note that certain linux distributions have certain algorithms removed (RHEL-based distributions in particular), so the golang from the official repositories will not work. Users of these distributions should [install go manually](//golang.org/dl) to install CFSSL. CFSSL consists of: * a set of packages useful for building custom TLS PKI tools * the `cfssl` program, which is the canonical command line utility using the CFSSL packages. * the `multirootca` program, which is a certificate authority server that can use multiple signing keys. * the `mkbundle` program is used to build certificate pool bundles. * the `cfssljson` program, which takes the JSON output from the `cfssl` and `multirootca` programs and writes certificates, keys, CSRs, and bundles to disk. ### Building Building cfssl requires a [working Go 1.20+ installation](http://golang.org/doc/install). ``` $ git clone git@github.com:cloudflare/cfssl.git $ cd cfssl $ make $ make install ``` The resulting binaries will be in the bin folder: ``` $ tree bin bin ├── cfssl ├── cfssl-bundle ├── cfssl-certinfo ├── cfssl-newkey ├── cfssl-scan ├── cfssljson ├── mkbundle └── multirootca 0 directories, 8 files ``` #### Cross Compilation You can set the `GOOS` and `GOARCH` environment variables to have Go cross compile for alternative platforms; however, cfssl requires cgo, and cgo requires a working compiler toolchain for the target platform. ### Installation Installation requires a [working Go 1.20+ installation](http://golang.org/doc/install). Alternatively, [prebuilt binaries are available](https://github.com/cloudflare/cfssl/releases) ``` $ go install github.com/cloudflare/cfssl/cmd/...@latest ``` This will download, build, and install all of the utility programs (including `cfssl`, `cfssljson`, and `mkbundle` among others). ### Using the Command Line Tool The `cfssl` command line tool takes a command to specify what operation it should carry out: sign signs a certificate bundle build a certificate bundle genkey generate a private key and a certificate request gencert generate a private key and a certificate serve start the API server version prints out the current version selfsign generates a self-signed certificate print-defaults print default configurations Use `cfssl [command] -help` to find out more about a command. The `version` command takes no arguments. #### Signing ``` cfssl sign [-ca cert] [-ca-key key] [-hostname comma,separated,hostnames] csr [subject] ``` The `csr` is the client's certificate request. The `-ca` and `-ca-key` flags are the CA's certificate and private key, respectively. By default, they are `ca.pem` and `ca_key.pem`. The `-hostname` is a comma separated hostname list that overrides the DNS names and IP address in the certificate SAN extension. For example, assuming the CA's private key is in `/etc/ssl/private/cfssl_key.pem` and the CA's certificate is in `/etc/ssl/certs/cfssl.pem`, to sign the `cloudflare.pem` certificate for cloudflare.com: ``` cfssl sign -ca /etc/ssl/certs/cfssl.pem \ -ca-key /etc/ssl/private/cfssl_key.pem \ -hostname cloudflare.com \ ./cloudflare.pem ``` It is also possible to specify CSR with the `-csr` flag. By doing so, flag values take precedence and will overwrite the argument. The subject is an optional file that contains subject information that should be used in place of the information from the CSR. It should be a JSON file as follows: ```json { "CN": "example.com", "names": [ { "C": "US", "L": "San Francisco", "O": "Internet Widgets, Inc.", "OU": "WWW", "ST": "California" } ] } ``` **N.B.** As of Go 1.7, self-signed certificates will not include [the AKI](https://go.googlesource.com/go/+/b623b71509b2d24df915d5bc68602e1c6edf38ca). #### Bundling ``` cfssl bundle [-ca-bundle bundle] [-int-bundle bundle] \ [-metadata metadata_file] [-flavor bundle_flavor] \ -cert certificate_file [-key key_file] ``` The bundles are used for the root and intermediate certificate pools. In addition, platform metadata is specified through `-metadata`. The bundle files, metadata file (and auxiliary files) can be found at: https://github.com/cloudflare/cfssl_trust Specify PEM-encoded client certificate and key through `-cert` and `-key` respectively. If key is specified, the bundle will be built and verified with the key. Otherwise the bundle will be built without a private key. Instead of file path, use `-` for reading certificate PEM from stdin. It is also acceptable that the certificate file should contain a (partial) certificate bundle. Specify bundling flavor through `-flavor`. There are three flavors: `optimal` to generate a bundle of shortest chain and most advanced cryptographic algorithms, `ubiquitous` to generate a bundle of most widely acceptance across different browsers and OS platforms, and `force` to find an acceptable bundle which is identical to the content of the input certificate file. Alternatively, the client certificate can be pulled directly from a domain. It is also possible to connect to the remote address through `-ip`. ``` cfssl bundle [-ca-bundle bundle] [-int-bundle bundle] \ [-metadata metadata_file] [-flavor bundle_flavor] \ -domain domain_name [-ip ip_address] ``` The bundle output form should follow the example: ```json { "bundle": "CERT_BUNDLE_IN_PEM", "crt": "LEAF_CERT_IN_PEM", "crl_support": true, "expires": "2015-12-31T23:59:59Z", "hostnames": ["example.com"], "issuer": "ISSUER CERT SUBJECT", "key": "KEY_IN_PEM", "key_size": 2048, "key_type": "2048-bit RSA", "ocsp": ["http://ocsp.example-ca.com"], "ocsp_support": true, "root": "ROOT_CA_CERT_IN_PEM", "signature": "SHA1WithRSA", "subject": "LEAF CERT SUBJECT", "status": { "rebundled": false, "expiring_SKIs": [], "untrusted_root_stores": [], "messages": [], "code": 0 } } ``` #### Generating certificate signing request and private key ``` cfssl genkey csr.json ``` To generate a private key and corresponding certificate request, specify the key request as a JSON file. This file should follow the form: ```json { "hosts": [ "example.com", "www.example.com", "https://www.example.com", "jdoe@example.com", "127.0.0.1" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "San Francisco", "O": "Internet Widgets, Inc.", "OU": "WWW", "ST": "California" } ] } ``` #### Generating self-signed root CA certificate and private key ``` cfssl genkey -initca csr.json | cfssljson -bare ca ``` To generate a self-signed root CA certificate, specify the key request as a JSON file in the same format as in 'genkey'. Three PEM-encoded entities will appear in the output: the private key, the csr, and the self-signed certificate. #### Generating a remote-issued certificate and private key. ``` cfssl gencert -remote=remote_server [-hostname=comma,separated,hostnames] csr.json ``` This calls `genkey` but has a remote CFSSL server sign and issue the certificate. You may use `-hostname` to override certificate SANs. #### Generating a local-issued certificate and private key. ``` cfssl gencert -ca cert -ca-key key [-hostname=comma,separated,hostnames] csr.json ``` This generates and issues a certificate and private key from a local CA via a JSON request. You may use `-hostname` to override certificate SANs. #### Updating an OCSP responses file with a newly issued certificate ``` cfssl ocspsign -ca cert -responder key -responder-key key -cert cert \ | cfssljson -bare -stdout >> responses ``` This will generate an OCSP response for the `cert` and add it to the `responses` file. You can then pass `responses` to `ocspserve` to start an OCSP server. ### Starting the API Server CFSSL comes with an HTTP-based API server; the endpoints are documented in [`doc/api/intro.txt`](doc/api/intro.txt). The server is started with the `serve` command: ``` cfssl serve [-address address] [-ca cert] [-ca-bundle bundle] \ [-ca-key key] [-int-bundle bundle] [-int-dir dir] [-port port] \ [-metadata file] [-remote remote_host] [-config config] \ [-responder cert] [-responder-key key] [-db-config db-config] ``` Address and port default to "127.0.0.1:8888". The `-ca` and `-ca-key` arguments should be the PEM-encoded certificate and private key to use for signing; by default, they are `ca.pem` and `ca_key.pem`. The `-ca-bundle` and `-int-bundle` should be the certificate bundles used for the root and intermediate certificate pools, respectively. These default to `ca-bundle.crt` and `int-bundle.crt` respectively. If the `-remote` option is specified, all signature operations will be forwarded to the remote CFSSL. `-int-dir` specifies an intermediates directory. `-metadata` is a file for root certificate presence. The content of the file is a json dictionary (k,v) such that each key k is an SHA-1 digest of a root certificate while value v is a list of key store filenames. `-config` specifies a path to a configuration file. `-responder` and `-responder-key` are the certificate and the private key for the OCSP responder, respectively. The amount of logging can be controlled with the `-loglevel` option. This comes *after* the serve command: ``` cfssl serve -loglevel 2 ``` The levels are: * 0 - DEBUG * 1 - INFO (this is the default level) * 2 - WARNING * 3 - ERROR * 4 - CRITICAL ### The multirootca The `cfssl` program can act as an online certificate authority, but it only uses a single key. If multiple signing keys are needed, the `multirootca` program can be used. It only provides the `sign`, `authsign` and `info` endpoints. The documentation contains instructions for configuring and running the CA. ### The mkbundle Utility `mkbundle` is used to build the root and intermediate bundles used in verifying certificates. It can be installed with ``` go get github.com/cloudflare/cfssl/cmd/mkbundle ``` It takes a collection of certificates, checks for CRL revocation (OCSP support is planned for the next release) and expired certificates, and bundles them into one file. It takes directories of certificates and certificate files (which may contain multiple certificates). For example, if the directory `intermediates` contains a number of intermediate certificates: ``` mkbundle -f int-bundle.crt intermediates ``` will check those certificates and combine valid certificates into a single `int-bundle.crt` file. The `-f` flag specifies an output name; `-loglevel` specifies the verbosity of the logging (using the same loglevels as above), and `-nw` controls the number of revocation-checking workers. ### The cfssljson Utility Most of the output from `cfssl` is in JSON. The `cfssljson` utility can take this output and split it out into separate `key`, `certificate`, `CSR`, and `bundle` files as appropriate. The tool takes a single flag, `-f`, that specifies the input file, and an argument that specifies the base name for the files produced. If the input filename is `-` (which is the default), cfssljson reads from standard input. It maps keys in the JSON file to filenames in the following way: * if __cert__ or __certificate__ is specified, __basename.pem__ will be produced. * if __key__ or __private_key__ is specified, __basename-key.pem__ will be produced. * if __csr__ or __certificate_request__ is specified, __basename.csr__ will be produced. * if __bundle__ is specified, __basename-bundle.pem__ will be produced. * if __ocspResponse__ is specified, __basename-response.der__ will be produced. Instead of saving to a file, you can pass `-stdout` to output the encoded contents to standard output. ### Static Builds By default, the web assets are accessed from disk, based on their relative locations. If you wish to distribute a single, statically-linked, `cfssl` binary, you’ll want to embed these resources before building. This can by done with the [go.rice](https://github.com/GeertJohan/go.rice) tool. ``` pushd cli/serve && rice embed-go && popd ``` Then building with `go build` will use the embedded resources. ### Additional Documentation Additional documentation can be found in the "doc" directory: * [doc/api/intro.txt](doc/api/intro.txt): documents the API endpoints ================================================ FILE: api/api.go ================================================ // Package api implements an HTTP-based API and server for CFSSL. package api import ( "encoding/json" "io" "net/http" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/log" ) // Handler is an interface providing a generic mechanism for handling HTTP requests. type Handler interface { Handle(w http.ResponseWriter, r *http.Request) error } // HTTPHandler is a wrapper that encapsulates Handler interface as http.Handler. // HTTPHandler also enforces that the Handler only responds to requests with registered HTTP methods. type HTTPHandler struct { Handler // CFSSL handler Methods []string // The associated HTTP methods } // HandlerFunc is similar to the http.HandlerFunc type; it serves as // an adapter allowing the use of ordinary functions as Handlers. If // f is a function with the appropriate signature, HandlerFunc(f) is a // Handler object that calls f. type HandlerFunc func(http.ResponseWriter, *http.Request) error // Handle calls f(w, r) func (f HandlerFunc) Handle(w http.ResponseWriter, r *http.Request) error { w.Header().Set("Content-Type", "application/json") return f(w, r) } // HandleError is the centralised error handling and reporting. func HandleError(w http.ResponseWriter, err error) (code int) { if err == nil { return http.StatusOK } msg := err.Error() httpCode := http.StatusInternalServerError // If it is recognized as HttpError emitted from cfssl, // we rewrite the status code accordingly. If it is a // cfssl error, set the http status to StatusBadRequest switch err := err.(type) { case *errors.HTTPError: httpCode = err.StatusCode code = err.StatusCode case *errors.Error: httpCode = http.StatusBadRequest code = err.ErrorCode msg = err.Message } response := NewErrorResponse(msg, code) jsonMessage, err := json.Marshal(response) if err != nil { log.Errorf("Failed to marshal JSON: %v", err) } else { msg = string(jsonMessage) } http.Error(w, msg, httpCode) return code } // ServeHTTP encapsulates the call to underlying Handler to handle the request // and return the response with proper HTTP status code func (h HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error var match bool // Throw 405 when requested with an unsupported verb. for _, m := range h.Methods { if m == r.Method { match = true } } if match { err = h.Handle(w, r) } else { err = errors.NewMethodNotAllowed(r.Method) } status := HandleError(w, err) log.Infof("%s - \"%s %s\" %d", r.RemoteAddr, r.Method, r.URL, status) } // readRequestBlob takes a JSON-blob-encoded response body in the form // map[string]string and returns it, the list of keywords presented, // and any error that occurred. func readRequestBlob(r *http.Request) (map[string]string, error) { var blob map[string]string body, err := io.ReadAll(r.Body) if err != nil { return nil, err } r.Body.Close() err = json.Unmarshal(body, &blob) if err != nil { return nil, err } return blob, nil } // ProcessRequestOneOf reads a JSON blob for the request and makes // sure it contains one of a set of keywords. For example, a request // might have the ('foo' && 'bar') keys, OR it might have the 'baz' // key. In either case, we want to accept the request; however, if // none of these sets shows up, the request is a bad request, and it // should be returned. func ProcessRequestOneOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) { blob, err := readRequestBlob(r) if err != nil { return nil, nil, err } var matched []string for _, set := range keywordSets { if matchKeywords(blob, set) { if matched != nil { return nil, nil, errors.NewBadRequestString("mismatched parameters") } matched = set } } if matched == nil { return nil, nil, errors.NewBadRequestString("no valid parameter sets found") } return blob, matched, nil } // ProcessRequestFirstMatchOf reads a JSON blob for the request and returns // the first match of a set of keywords. For example, a request // might have one of the following combinations: (foo=1, bar=2), (foo=1), and (bar=2) // By giving a specific ordering of those combinations, we could decide how to accept // the request. func ProcessRequestFirstMatchOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) { blob, err := readRequestBlob(r) if err != nil { return nil, nil, err } for _, set := range keywordSets { if matchKeywords(blob, set) { return blob, set, nil } } return nil, nil, errors.NewBadRequestString("no valid parameter sets found") } func matchKeywords(blob map[string]string, keywords []string) bool { for _, keyword := range keywords { if _, ok := blob[keyword]; !ok { return false } } return true } // ResponseMessage implements the standard for response errors and // messages. A message has a code and a string message. type ResponseMessage struct { Code int `json:"code"` Message string `json:"message"` } // Response implements the CloudFlare standard for API // responses. type Response struct { Success bool `json:"success"` Result interface{} `json:"result"` Errors []ResponseMessage `json:"errors"` Messages []ResponseMessage `json:"messages"` } // NewSuccessResponse is a shortcut for creating new successful API // responses. func NewSuccessResponse(result interface{}) Response { return Response{ Success: true, Result: result, Errors: []ResponseMessage{}, Messages: []ResponseMessage{}, } } // NewSuccessResponseWithMessage is a shortcut for creating new successul API // responses that includes a message. func NewSuccessResponseWithMessage(result interface{}, message string, code int) Response { return Response{ Success: true, Result: result, Errors: []ResponseMessage{}, Messages: []ResponseMessage{{code, message}}, } } // NewErrorResponse is a shortcut for creating an error response for a // single error. func NewErrorResponse(message string, code int) Response { return Response{ Success: false, Result: nil, Errors: []ResponseMessage{{code, message}}, Messages: []ResponseMessage{}, } } // SendResponse builds a response from the result, sets the JSON // header, and writes to the http.ResponseWriter. func SendResponse(w http.ResponseWriter, result interface{}) error { response := NewSuccessResponse(result) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) err := enc.Encode(response) return err } // SendResponseWithMessage builds a response from the result and the // provided message, sets the JSON header, and writes to the // http.ResponseWriter. func SendResponseWithMessage(w http.ResponseWriter, result interface{}, message string, code int) error { response := NewSuccessResponseWithMessage(result, message, code) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) err := enc.Encode(response) return err } ================================================ FILE: api/api_test.go ================================================ package api import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "testing" ) const ( ty = "Thank you!" deny = "That's not true!" ) func simpleHandle(w http.ResponseWriter, r *http.Request) error { _, _, err := ProcessRequestOneOf(r, [][]string{ {"compliment"}, {"critique"}, }) if err != nil { return err } return SendResponse(w, ty) } func cleverHandle(w http.ResponseWriter, r *http.Request) error { _, matched, err := ProcessRequestFirstMatchOf(r, [][]string{ {"compliment"}, {"critique"}, }) if err != nil { return err } if matched[0] == "critique" { return SendResponse(w, deny) } return SendResponse(w, ty) } func post(t *testing.T, obj map[string]interface{}, ts *httptest.Server) (resp *http.Response, body []byte) { blob, err := json.Marshal(obj) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } func get(t *testing.T, ts *httptest.Server) (resp *http.Response, body []byte) { resp, err := http.Get(ts.URL) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } func TestRigidHandle(t *testing.T) { ts := httptest.NewServer(HTTPHandler{Handler: HandlerFunc(simpleHandle), Methods: []string{"POST"}}) defer ts.Close() // Response to compliment obj := map[string]interface{}{} obj["compliment"] = "it's good" resp, body := post(t, obj, ts) if resp.StatusCode != http.StatusOK { t.Errorf("Test expected 200, have %d", resp.StatusCode) } message := new(Response) err := json.Unmarshal(body, message) if err != nil { t.Errorf("failed to read response body: %v", err) t.Fatal("returned:", message) } if message.Result != ty { t.Fatal("Wrong response") } // Response to critique obj = map[string]interface{}{} obj["critique"] = "it's bad" resp, body = post(t, obj, ts) if resp.StatusCode != http.StatusOK { t.Errorf("Test expected 200, have %d", resp.StatusCode) } message = new(Response) err = json.Unmarshal(body, message) if err != nil { t.Errorf("failed to read response body: %v", err) t.Fatal("returned:", message) } if message.Result != ty { t.Fatal("Wrong response") } // reject mixed review obj = map[string]interface{}{} obj["critique"] = "it's OK" obj["compliment"] = "it's not bad" resp, _ = post(t, obj, ts) if resp.StatusCode != http.StatusBadRequest { t.Errorf("Test expected 400, have %d", resp.StatusCode) } // reject empty review obj = map[string]interface{}{} resp, _ = post(t, obj, ts) if resp.StatusCode != http.StatusBadRequest { t.Errorf("Test expected 400, have %d", resp.StatusCode) } // reject GET resp, _ = get(t, ts) if resp.StatusCode != http.StatusMethodNotAllowed { t.Errorf("Test expected 405, have %d", resp.StatusCode) } } func TestCleverHandle(t *testing.T) { ts := httptest.NewServer(HTTPHandler{Handler: HandlerFunc(cleverHandle), Methods: []string{"POST"}}) defer ts.Close() // Response ty to compliment obj := map[string]interface{}{} obj["compliment"] = "it's good" resp, body := post(t, obj, ts) if resp.StatusCode != http.StatusOK { t.Errorf("Test expected 200, have %d", resp.StatusCode) } message := new(Response) err := json.Unmarshal(body, message) if err != nil { t.Errorf("failed to read response body: %v", err) t.Fatal("returned:", message) } if message.Result != ty { t.Fatal("Wrong response") } // Response deny to critique obj = map[string]interface{}{} obj["critique"] = "it's bad" resp, body = post(t, obj, ts) if resp.StatusCode != http.StatusOK { t.Errorf("Test expected 200, have %d", resp.StatusCode) } message = new(Response) err = json.Unmarshal(body, message) if err != nil { t.Errorf("failed to read response body: %v", err) t.Fatal("returned:", message) } if message.Result != deny { t.Fatal("Wrong response") } // Be polite to mixed review obj = map[string]interface{}{} obj["critique"] = "it's OK" obj["compliment"] = "it's not bad" _, body = post(t, obj, ts) message = new(Response) err = json.Unmarshal(body, message) if err != nil { t.Errorf("failed to read response body: %v", err) t.Fatal("returned:", message) } if message.Result != ty { t.Fatal("Wrong response") } // reject empty review obj = map[string]interface{}{} resp, _ = post(t, obj, ts) if resp.StatusCode != http.StatusBadRequest { t.Errorf("Test expected 400, have %d", resp.StatusCode) } // reject GET resp, _ = get(t, ts) if resp.StatusCode != http.StatusMethodNotAllowed { t.Errorf("Test expected 405, have %d", resp.StatusCode) } } ================================================ FILE: api/bundle/bundle.go ================================================ // Package bundle implements the HTTP handler for the bundle command. package bundle import ( "net/http" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/bundler" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/log" ) // Handler accepts requests for either remote or uploaded // certificates to be bundled, and returns a certificate bundle (or // error). type Handler struct { bundler *bundler.Bundler } // NewHandler creates a new bundler that uses the root bundle and // intermediate bundle in the trust chain. func NewHandler(caBundleFile, intBundleFile string) (http.Handler, error) { var err error b := new(Handler) if b.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile); err != nil { return nil, err } log.Info("bundler API ready") return api.HTTPHandler{Handler: b, Methods: []string{"POST"}}, nil } // Handle implements an http.Handler interface for the bundle handler. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { blob, matched, err := api.ProcessRequestFirstMatchOf(r, [][]string{ {"certificate"}, {"domain"}, }) if err != nil { log.Warningf("invalid request: %v", err) return err } flavor := blob["flavor"] bf := bundler.Ubiquitous if flavor != "" { bf = bundler.BundleFlavor(flavor) } log.Infof("request for flavor %v", bf) var result *bundler.Bundle switch matched[0] { case "domain": bundle, err := h.bundler.BundleFromRemote(blob["domain"], blob["ip"], bf) if err != nil { log.Warningf("couldn't bundle from remote: %v", err) return err } result = bundle case "certificate": bundle, err := h.bundler.BundleFromPEMorDER([]byte(blob["certificate"]), []byte(blob["private_key"]), bf, "") if err != nil { log.Warning("bad PEM certificate or private key") return err } serverName := blob["domain"] ip := blob["ip"] if serverName != "" { err := bundle.Cert.VerifyHostname(serverName) if err != nil { return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } } if ip != "" { err := bundle.Cert.VerifyHostname(ip) if err != nil { return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } } result = bundle } log.Info("wrote response") return api.SendResponse(w, result) } ================================================ FILE: api/bundle/bundle_test.go ================================================ package bundle import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "os" "testing" "github.com/cloudflare/cfssl/api" ) const ( testCaBundleFile = "../testdata/ca-bundle.pem" testIntBundleFile = "../testdata/int-bundle.pem" testLeafCertFile = "../testdata/leaf.pem" testLeafKeyFile = "../testdata/leaf.key" testLeafWrongKeyFile = "../testdata/leaf.badkey" testBrokenCertFile = "../testdata/broken.pem" ) func newTestHandler(t *testing.T) (h http.Handler) { h, err := NewHandler(testCaBundleFile, testIntBundleFile) if err != nil { t.Fatal(err) } return } func newBundleServer(t *testing.T) *httptest.Server { ts := httptest.NewServer(newTestHandler(t)) return ts } func testBundleFile(t *testing.T, domain, ip, certFile, keyFile, flavor string) (resp *http.Response, body []byte) { ts := newBundleServer(t) defer ts.Close() var certPEM, keyPEM []byte if certFile != "" { var err error certPEM, err = os.ReadFile(certFile) if err != nil { t.Fatal(err) } } if keyFile != "" { var err error keyPEM, err = os.ReadFile(keyFile) if err != nil { t.Fatal(err) } } obj := map[string]string{"flavor": flavor} if len(domain) > 0 { obj["domain"] = domain } if len(ip) > 0 { obj["ip"] = ip } if len(certPEM) > 0 { obj["certificate"] = string(certPEM) } if len(keyPEM) > 0 { obj["private_key"] = string(keyPEM) } blob, err := json.Marshal(obj) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } func TestNewHandler(t *testing.T) { newTestHandler(t) } type bundleTest struct { Domain string IP string CertFile string KeyFile string Flavor string ExpectedHTTPStatus int ExpectedSuccess bool ExpectedErrorCode int } var bundleTests = []bundleTest{ // Test bundling with certificate { CertFile: testLeafCertFile, ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { CertFile: testLeafCertFile, Flavor: "ubiquitous", ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { CertFile: testLeafCertFile, Flavor: "optimal", ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { CertFile: testLeafCertFile, KeyFile: testLeafKeyFile, ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { CertFile: testLeafCertFile, Domain: "cfssl-leaf.com", ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, // Test bundling with remote domain { Domain: "google.com", ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, }, // Error testing. { CertFile: testLeafCertFile, KeyFile: testLeafWrongKeyFile, ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: 2300, }, { // no input parameter is specified ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: http.StatusBadRequest, }, { CertFile: testBrokenCertFile, ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: 1003, }, { CertFile: testLeafKeyFile, KeyFile: testLeafKeyFile, ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: 1003, }, { CertFile: testLeafCertFile, KeyFile: testLeafCertFile, ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: 2003, }, { CertFile: testLeafCertFile, Domain: "cloudflare-leaf.com", ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: 1200, }, } func TestBundle(t *testing.T) { for i, test := range bundleTests { resp, body := testBundleFile(t, test.Domain, test.IP, test.CertFile, test.KeyFile, test.Flavor) if resp.StatusCode != test.ExpectedHTTPStatus { t.Errorf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode) t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body)) } message := new(api.Response) err := json.Unmarshal(body, message) if err != nil { t.Errorf("failed to read response body: %v", err) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess != message.Success { t.Errorf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess == true { continue } if test.ExpectedErrorCode != 0 && test.ExpectedErrorCode != message.Errors[0].Code { t.Errorf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } } } ================================================ FILE: api/certadd/insert.go ================================================ package certadd import ( "bytes" "database/sql" "encoding/base64" "encoding/hex" "encoding/json" "io" "math/big" "net/http" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/ocsp" "github.com/jmoiron/sqlx/types" stdocsp "golang.org/x/crypto/ocsp" ) // This is patterned on // https://github.com/cloudflare/cfssl/blob/master/api/revoke/revoke.go. This // file defines an HTTP endpoint handler that accepts certificates and // inserts them into a certdb, optionally also creating an OCSP // response for them. If so, it will also return the OCSP response as // a base64 encoded string. // A Handler accepts new SSL certificates and inserts them into the // certdb, creating an appropriate OCSP response for them. type Handler struct { dbAccessor certdb.Accessor signer ocsp.Signer } // NewHandler creates a new Handler from a certdb.Accessor and ocsp.Signer func NewHandler(dbAccessor certdb.Accessor, signer ocsp.Signer) http.Handler { return &api.HTTPHandler{ Handler: &Handler{ dbAccessor: dbAccessor, signer: signer, }, Methods: []string{"POST"}, } } // AddRequest describes a request from a client to insert a // certificate into the database. type AddRequest struct { Serial string `json:"serial_number"` AKI string `json:"authority_key_identifier"` CALabel string `json:"ca_label"` Status string `json:"status"` Reason int `json:"reason"` Expiry time.Time `json:"expiry"` RevokedAt time.Time `json:"revoked_at"` PEM string `json:"pem"` IssuedAt *time.Time `json:"issued_at"` NotBefore *time.Time `json:"not_before"` MetadataJSON types.JSONText `json:"metadata"` SansJSON types.JSONText `json:"sans"` CommonName string `json:"common_name"` } // Map of valid reason codes var validReasons = map[int]bool{ stdocsp.Unspecified: true, stdocsp.KeyCompromise: true, stdocsp.CACompromise: true, stdocsp.AffiliationChanged: true, stdocsp.Superseded: true, stdocsp.CessationOfOperation: true, stdocsp.CertificateHold: true, stdocsp.RemoveFromCRL: true, stdocsp.PrivilegeWithdrawn: true, stdocsp.AACompromise: true, } // Handle handles HTTP requests to add certificates func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { body, err := io.ReadAll(r.Body) if err != nil { return err } r.Body.Close() var req AddRequest err = json.Unmarshal(body, &req) if err != nil { return errors.NewBadRequestString("Unable to parse certificate addition request") } if len(req.Serial) == 0 { return errors.NewBadRequestString("Serial number is required but not provided") } if len(req.AKI) == 0 { return errors.NewBadRequestString("Authority key identifier is required but not provided") } if _, present := ocsp.StatusCode[req.Status]; !present { return errors.NewBadRequestString("Invalid certificate status") } if ocsp.StatusCode[req.Status] == stdocsp.Revoked { if req.RevokedAt == (time.Time{}) { return errors.NewBadRequestString("Revoked certificate should specify when it was revoked") } if _, present := validReasons[req.Reason]; !present { return errors.NewBadRequestString("Invalid certificate status reason code") } } if len(req.PEM) == 0 { return errors.NewBadRequestString("The provided certificate is empty") } if req.Expiry.IsZero() { return errors.NewBadRequestString("Expiry is required but not provided") } // Parse the certificate and validate that it matches cert, err := helpers.ParseCertificatePEM([]byte(req.PEM)) if err != nil { return errors.NewBadRequestString("Unable to parse PEM encoded certificates") } serialBigInt := new(big.Int) if _, success := serialBigInt.SetString(req.Serial, 10); !success { return errors.NewBadRequestString("Unable to parse serial key of request") } if serialBigInt.Cmp(cert.SerialNumber) != 0 { return errors.NewBadRequestString("Serial key of request and certificate do not match") } aki, err := hex.DecodeString(req.AKI) if err != nil { return errors.NewBadRequestString("Unable to decode authority key identifier") } if !bytes.Equal(aki, cert.AuthorityKeyId) { return errors.NewBadRequestString("Authority key identifier of request and certificate do not match") } if req.Expiry != cert.NotAfter { return errors.NewBadRequestString("Expiry of request and certificate do not match") } cr := certdb.CertificateRecord{ Serial: req.Serial, AKI: req.AKI, CALabel: req.CALabel, Status: req.Status, Reason: req.Reason, Expiry: req.Expiry, RevokedAt: req.RevokedAt, PEM: req.PEM, IssuedAt: req.IssuedAt, NotBefore: req.NotBefore, MetadataJSON: req.MetadataJSON, SANsJSON: req.SansJSON, CommonName: sql.NullString{String: req.CommonName, Valid: req.CommonName != ""}, } err = h.dbAccessor.InsertCertificate(cr) if err != nil { return err } result := map[string]string{} if h.signer != nil { // Now create an appropriate OCSP response sr := ocsp.SignRequest{ Certificate: cert, Status: req.Status, Reason: req.Reason, RevokedAt: req.RevokedAt, } ocspResponse, err := h.signer.Sign(sr) if err != nil { return err } // We parse the OCSP response in order to get the next // update time/expiry time ocspParsed, err := stdocsp.ParseResponse(ocspResponse, nil) if err != nil { return err } result["ocsp_response"] = base64.StdEncoding.EncodeToString(ocspResponse) ocspRecord := certdb.OCSPRecord{ Serial: req.Serial, AKI: req.AKI, Body: string(ocspResponse), Expiry: ocspParsed.NextUpdate, } if err = h.dbAccessor.InsertOCSP(ocspRecord); err != nil { return err } } return api.SendResponse(w, result) } ================================================ FILE: api/certadd/insert_test.go ================================================ package certadd import ( "bytes" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/base64" "encoding/hex" "encoding/json" "encoding/pem" "io" "math/big" "net/http" "net/http/httptest" "testing" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/cloudflare/cfssl/ocsp" stdocsp "golang.org/x/crypto/ocsp" ) func prepDB() (certdb.Accessor, error) { db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") dbAccessor := sql.NewAccessor(db) return dbAccessor, nil } func makeRequest(t *testing.T, dbAccessor certdb.Accessor, signer ocsp.Signer, req map[string]interface{}) (resp *http.Response, body []byte) { ts := httptest.NewServer(NewHandler(dbAccessor, signer)) defer ts.Close() blob, err := json.Marshal(req) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } func makeCertificate() (serialNumber *big.Int, cert *x509.Certificate, pemBytes []byte, signer ocsp.Signer, err error) { privKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return } serialNumberRange := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err = rand.Int(rand.Reader, serialNumberRange) if err != nil { return } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"Cornell CS 5152"}, }, AuthorityKeyId: []byte{42, 42, 42, 42}, NotAfter: time.Now(), } cert = &template issuerSerial, err := rand.Int(rand.Reader, serialNumberRange) if err != nil { return } responderSerial, err := rand.Int(rand.Reader, serialNumberRange) if err != nil { return } // Generate a CA certificate issuerTemplate := x509.Certificate{ SerialNumber: issuerSerial, Subject: pkix.Name{ Organization: []string{"Cornell CS 5152"}, }, AuthorityKeyId: []byte{42, 42, 42, 42}, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, IsCA: true, BasicConstraintsValid: true, } issuerBytes, err := x509.CreateCertificate(rand.Reader, &issuerTemplate, &issuerTemplate, &privKey.PublicKey, privKey) if err != nil { return } issuer, err := x509.ParseCertificate(issuerBytes) if err != nil { return } responderTemplate := x509.Certificate{ SerialNumber: responderSerial, Subject: pkix.Name{ Organization: []string{"Cornell CS 5152 Responder"}, }, AuthorityKeyId: []byte{42, 42, 42, 43}, } responderBytes, err := x509.CreateCertificate(rand.Reader, &responderTemplate, &responderTemplate, &privKey.PublicKey, privKey) if err != nil { return } responder, err := x509.ParseCertificate(responderBytes) if err != nil { return } signer, err = ocsp.NewSigner(issuer, responder, privKey, time.Hour) if err != nil { return } derBytes, err := x509.CreateCertificate(rand.Reader, &template, issuer, &privKey.PublicKey, privKey) if err != nil { return } pemBytes = pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: derBytes, }) return } func TestInsertValidCertificate(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "good", "pem": string(pemBytes), "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusOK { t.Fatal("Expected HTTP OK, got", resp.StatusCode, string(body)) } var response map[string]interface{} if err = json.Unmarshal(body, &response); err != nil { t.Fatal("Could not parse response: ", err) } responseResult := response["result"].(map[string]interface{}) encodedOcsp := responseResult["ocsp_response"].(string) rawOcsp, err := base64.StdEncoding.DecodeString(encodedOcsp) if err != nil { t.Fatal("Could not base64 decode response: ", err) } returnedOcsp, err := stdocsp.ParseResponse(rawOcsp, nil) if err != nil { t.Fatal("Could not parse returned OCSP response", err) } ocsps, err := dbAccessor.GetOCSP(serialNumber.Text(10), hex.EncodeToString(cert.AuthorityKeyId)) if err != nil { t.Fatal(err) } if len(ocsps) != 1 { t.Fatal("Expected 1 OCSP record to be inserted, but found ", len(ocsps)) } parsedOcsp, err := stdocsp.ParseResponse([]byte(ocsps[0].Body), nil) if err != nil { t.Fatal(err) } if parsedOcsp.SerialNumber.Cmp(returnedOcsp.SerialNumber) != 0 { t.Fatal("The returned and inserted OCSP response have different serial numbers: got ", returnedOcsp.SerialNumber, " but decoded ", parsedOcsp.SerialNumber) } if parsedOcsp.SerialNumber.Cmp(serialNumber) != 0 { t.Fatal("Got the wrong serial number: expected", serialNumber, "but got", parsedOcsp.SerialNumber) } if parsedOcsp.Status != stdocsp.Good { t.Fatal("Expected OCSP response status to be ", stdocsp.Good, " but found ", parsedOcsp.Status) } } func TestInsertMissingSerial(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } _, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "good", "pem": string(pemBytes), "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body)) } } func TestInsertMissingAKI(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "status": "good", "pem": string(pemBytes), "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body)) } } func TestInsertMissingExpiry(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "good", "pem": string(pemBytes), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body)) } } func TestInsertMissingPEM(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, _, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "good", "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body)) } } func TestInsertInvalidSerial(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } _, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": "this is not a serial number", "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "good", "pem": string(pemBytes), "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body)) } } func TestInsertInvalidAKI(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": "this is not an AKI", "status": "good", "pem": string(pemBytes), "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request, got", resp.StatusCode, string(body)) } } func TestInsertInvalidStatus(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "invalid", "pem": string(pemBytes), "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body)) } } func TestInsertInvalidPEM(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, _, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "good", "pem": "this is not a PEM certificate", "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request, got", resp.StatusCode, string(body)) } } func TestInsertInvalidExpiry(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "good", "pem": string(pemBytes), "expiry": "this is not an expiry", }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request, got", resp.StatusCode, string(body)) } } func TestInsertWrongSerial(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } _, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": big.NewInt(1).Text(10), "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "good", "pem": string(pemBytes), "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body)) } } func TestInsertWrongAKI(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": hex.EncodeToString([]byte{7, 7}), "status": "good", "pem": string(pemBytes), "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body)) } } func TestInsertWrongExpiry(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, _, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": hex.EncodeToString([]byte{7, 7}), "status": "good", "pem": string(pemBytes), "expiry": time.Now().UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body)) } } func TestInsertRevokedCertificate(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "revoked", "pem": string(pemBytes), "revoked_at": time.Now(), "expiry": cert.NotAfter.UTC().Format(time.RFC3339), }) if resp.StatusCode != http.StatusOK { t.Fatal("Expected HTTP OK", resp.StatusCode, string(body)) } ocsps, err := dbAccessor.GetOCSP(serialNumber.Text(10), hex.EncodeToString(cert.AuthorityKeyId)) if err != nil { t.Fatal(err) } if len(ocsps) != 1 { t.Fatal("Expected 1 OCSP record to be inserted, but found ", len(ocsps)) } response, err := stdocsp.ParseResponse([]byte(ocsps[0].Body), nil) if err != nil { t.Fatal(err) } if response.Status != stdocsp.Revoked { t.Fatal("Expected OCSP response status to be ", stdocsp.Revoked, " but found ", response.Status) } } func TestInsertRevokedCertificateWithoutTime(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } serialNumber, cert, pemBytes, signer, err := makeCertificate() if err != nil { t.Fatal(err) } resp, body := makeRequest(t, dbAccessor, signer, map[string]interface{}{ "serial_number": serialNumber.Text(10), "authority_key_identifier": hex.EncodeToString(cert.AuthorityKeyId), "status": "revoked", "pem": string(pemBytes), "expiry": cert.NotAfter.UTC().Format(time.RFC3339), // Omit RevokedAt }) if resp.StatusCode != http.StatusBadRequest { t.Fatal("Expected HTTP Bad Request", resp.StatusCode, string(body)) } } ================================================ FILE: api/certinfo/certinfo.go ================================================ // Package certinfo implements the HTTP handler for the certinfo command. package certinfo import ( "errors" "net/http" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certinfo" "github.com/cloudflare/cfssl/log" ) // Handler accepts requests for either remote or uploaded // certificates to be bundled, and returns a certificate bundle (or // error). type Handler struct { dbAccessor certdb.Accessor } // NewHandler creates a new bundler that uses the root bundle and // intermediate bundle in the trust chain. func NewHandler() http.Handler { return api.HTTPHandler{Handler: new(Handler), Methods: []string{"POST"}} } // NewAccessorHandler creates a new bundler with database access via the // certdb.Accessor interface. If this handler is constructed it will be possible // to lookup certificates issued earlier by the CA. func NewAccessorHandler(dbAccessor certdb.Accessor) http.Handler { return api.HTTPHandler{ Handler: &Handler{ dbAccessor: dbAccessor, }, Methods: []string{"POST"}, } } // Handle implements an http.Handler interface for the bundle handler. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) (err error) { blob, matched, err := api.ProcessRequestFirstMatchOf(r, [][]string{ {"certificate"}, {"domain"}, {"serial", "authority_key_id"}, }) if err != nil { log.Warningf("invalid request: %v", err) return err } var cert *certinfo.Certificate switch matched[0] { case "domain": if cert, err = certinfo.ParseCertificateDomain(blob["domain"]); err != nil { log.Warningf("couldn't parse remote certificate: %v", err) return err } case "certificate": if cert, err = certinfo.ParseCertificatePEM([]byte(blob["certificate"])); err != nil { log.Warningf("bad PEM certificate: %v", err) return err } case "serial", "authority_key_id": if h.dbAccessor == nil { log.Warning("could not find certificates with db access") return errors.New("cannot lookup certificate from serial without db access") } if cert, err = certinfo.ParseSerialNumber(blob["serial"], blob["authority_key_id"], h.dbAccessor); err != nil { log.Warningf("couldn't find certificate: %v", err) return err } } return api.SendResponse(w, cert) } ================================================ FILE: api/client/api.go ================================================ package client // SignResult is the result of signing a CSR. type SignResult struct { Certificate []byte `json:"certificate"` } ================================================ FILE: api/client/client.go ================================================ // Package client implements a Go client for CFSSL API commands. package client import ( "bytes" "crypto/tls" "encoding/json" stderr "errors" "fmt" "io" "net" "net/http" "net/url" "strconv" "strings" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/auth" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/info" "github.com/cloudflare/cfssl/log" ) // A server points to a single remote CFSSL instance. type server struct { URL string TLSConfig *tls.Config reqModifier func(*http.Request, []byte) RequestTimeout time.Duration proxy func(*http.Request) (*url.URL, error) } // A Remote points to at least one (but possibly multiple) remote // CFSSL instances. It must be able to perform a authenticated and // unauthenticated certificate signing requests, return information // about the CA on the other end, and return a list of the hosts that // are used by the remote. type Remote interface { AuthSign(req, id []byte, provider auth.Provider) ([]byte, error) Sign(jsonData []byte) ([]byte, error) Info(jsonData []byte) (*info.Resp, error) Hosts() []string SetReqModifier(func(*http.Request, []byte)) SetRequestTimeout(d time.Duration) SetProxy(func(*http.Request) (*url.URL, error)) } // NewServer sets up a new server target. The address should be of // The format [protocol:]name[:port] of the remote CFSSL instance. // If no protocol is given http is default. If no port // is specified, the CFSSL default port (8888) is used. If the name is // a comma-separated list of hosts, an ordered group will be returned. func NewServer(addr string) Remote { return NewServerTLS(addr, nil) } // NewServerTLS is the TLS version of NewServer func NewServerTLS(addr string, tlsConfig *tls.Config) Remote { addrs := strings.Split(addr, ",") var remote Remote if len(addrs) > 1 { remote, _ = NewGroup(addrs, tlsConfig, StrategyOrderedList) } else { u, err := normalizeURL(addrs[0]) if err != nil { log.Errorf("bad url: %v", err) return nil } srv := newServer(u, tlsConfig) if srv != nil { remote = srv } } return remote } func (srv *server) Hosts() []string { return []string{srv.URL} } func (srv *server) SetReqModifier(mod func(*http.Request, []byte)) { srv.reqModifier = mod } func (srv *server) SetRequestTimeout(timeout time.Duration) { srv.RequestTimeout = timeout } func (srv *server) SetProxy(proxy func(*http.Request) (*url.URL, error)) { srv.proxy = proxy } func newServer(u *url.URL, tlsConfig *tls.Config) *server { URL := u.String() return &server{ URL: URL, TLSConfig: tlsConfig, } } func (srv *server) getURL(endpoint string) string { return fmt.Sprintf("%s/api/v1/cfssl/%s", srv.URL, endpoint) } func (srv *server) createTransport() *http.Transport { // Start with defaults from http.DefaultTransport transport := &http.Transport{ Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, DualStack: true, }).DialContext, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, } // Setup HTTPS client tlsConfig := srv.TLSConfig tlsConfig.BuildNameToCertificate() transport.TLSClientConfig = tlsConfig // Setup Proxy if srv.proxy != nil { transport.Proxy = srv.proxy } return transport } // post connects to the remote server and returns a Response struct func (srv *server) post(url string, jsonData []byte) (*api.Response, error) { var resp *http.Response var err error client := &http.Client{} if srv.TLSConfig != nil { client.Transport = srv.createTransport() } if srv.RequestTimeout != 0 { client.Timeout = srv.RequestTimeout } req, err := http.NewRequest("POST", url, bytes.NewReader(jsonData)) if err != nil { err = fmt.Errorf("failed POST to %s: %v", url, err) return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, err) } req.Close = true req.Header.Set("content-type", "application/json") if srv.reqModifier != nil { srv.reqModifier(req, jsonData) } resp, err = client.Do(req) if err != nil { err = fmt.Errorf("failed POST to %s: %v", url, err) return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, err) } defer req.Body.Close() defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, errors.Wrap(errors.APIClientError, errors.IOError, err) } if resp.StatusCode != http.StatusOK { log.Errorf("http error with %s", url) return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New(string(body))) } var response api.Response err = json.Unmarshal(body, &response) if err != nil { log.Debug("Unable to parse response body:", string(body)) return nil, errors.Wrap(errors.APIClientError, errors.JSONError, err) } if !response.Success || response.Result == nil { if len(response.Errors) > 0 { return nil, errors.Wrap(errors.APIClientError, errors.ServerRequestFailed, stderr.New(response.Errors[0].Message)) } return nil, errors.New(errors.APIClientError, errors.ServerRequestFailed) } return &response, nil } // AuthSign fills out an authenticated signing request to the server, // receiving a certificate or error in response. // It takes the serialized JSON request to send, remote address and // authentication provider. func (srv *server) AuthSign(req, id []byte, provider auth.Provider) ([]byte, error) { return srv.authReq(req, id, provider, "sign") } // AuthInfo fills out an authenticated info request to the server, // receiving a certificate or error in response. // It takes the serialized JSON request to send, remote address and // authentication provider. func (srv *server) AuthInfo(req, id []byte, provider auth.Provider) ([]byte, error) { return srv.authReq(req, id, provider, "info") } // authReq is the common logic for AuthSign and AuthInfo -- perform the given // request, and return the resultant certificate. // The target is either 'sign' or 'info'. func (srv *server) authReq(req, ID []byte, provider auth.Provider, target string) ([]byte, error) { url := srv.getURL("auth" + target) token, err := provider.Token(req) if err != nil { return nil, errors.Wrap(errors.APIClientError, errors.AuthenticationFailure, err) } aReq := &auth.AuthenticatedRequest{ Timestamp: time.Now().Unix(), RemoteAddress: ID, Token: token, Request: req, } jsonData, err := json.Marshal(aReq) if err != nil { return nil, errors.Wrap(errors.APIClientError, errors.JSONError, err) } response, err := srv.post(url, jsonData) if err != nil { return nil, err } result, ok := response.Result.(map[string]interface{}) if !ok { return nil, errors.New(errors.APIClientError, errors.JSONError) } cert, ok := result["certificate"].(string) if !ok { return nil, errors.New(errors.APIClientError, errors.JSONError) } return []byte(cert), nil } // Sign sends a signature request to the remote CFSSL server, // receiving a signed certificate or an error in response. // It takes the serialized JSON request to send. func (srv *server) Sign(jsonData []byte) ([]byte, error) { return srv.request(jsonData, "sign") } // Info sends an info request to the remote CFSSL server, receiving a // response or an error in response. // It takes the serialized JSON request to send. func (srv *server) Info(jsonData []byte) (*info.Resp, error) { res, err := srv.getResultMap(jsonData, "info") if err != nil { return nil, err } info := new(info.Resp) if val, ok := res["certificate"]; ok { info.Certificate = val.(string) } var usages []interface{} if val, ok := res["usages"]; ok && val != nil { usages = val.([]interface{}) } if val, ok := res["expiry"]; ok && val != nil { info.ExpiryString = val.(string) } info.Usage = make([]string, len(usages)) for i, s := range usages { info.Usage[i] = s.(string) } return info, nil } func (srv *server) getResultMap(jsonData []byte, target string) (result map[string]interface{}, err error) { url := srv.getURL(target) response, err := srv.post(url, jsonData) if err != nil { return } result, ok := response.Result.(map[string]interface{}) if !ok { err = errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New("response is formatted improperly")) return } return } // request performs the common logic for Sign and Info, performing the actual // request and returning the resultant certificate. func (srv *server) request(jsonData []byte, target string) ([]byte, error) { result, err := srv.getResultMap(jsonData, target) if err != nil { return nil, err } cert := result["certificate"].(string) if cert != "" { return []byte(cert), nil } return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New("response doesn't contain certificate.")) } // AuthRemote acts as a Remote with a default Provider for AuthSign. type AuthRemote struct { Remote provider auth.Provider } // NewAuthServer sets up a new auth server target with an addr // in the same format at NewServer and a default authentication provider to // use for Sign requests. func NewAuthServer(addr string, tlsConfig *tls.Config, provider auth.Provider) *AuthRemote { return &AuthRemote{ Remote: NewServerTLS(addr, tlsConfig), provider: provider, } } // Sign is overloaded to perform an AuthSign request using the default auth provider. func (ar *AuthRemote) Sign(req []byte) ([]byte, error) { return ar.AuthSign(req, nil, ar.provider) } // normalizeURL checks for http/https protocol, appends "http" as default protocol if not defined in url func normalizeURL(addr string) (*url.URL, error) { addr = strings.TrimSpace(addr) u, err := url.Parse(addr) if err != nil { return nil, err } if u.Opaque != "" { u.Host = net.JoinHostPort(u.Scheme, u.Opaque) u.Opaque = "" } else if u.Path != "" && !strings.Contains(u.Path, ":") { u.Host = net.JoinHostPort(u.Path, "8888") u.Path = "" } else if u.Scheme == "" { u.Host = u.Path u.Path = "" } if u.Scheme != "https" { u.Scheme = "http" } _, port, err := net.SplitHostPort(u.Host) if err != nil { _, port, err = net.SplitHostPort(u.Host + ":8888") if err != nil { return nil, err } } if port != "" { _, err = strconv.Atoi(port) if err != nil { return nil, err } } return u, nil } ================================================ FILE: api/client/client_test.go ================================================ package client import ( "crypto/tls" "github.com/cloudflare/cfssl/auth" "github.com/cloudflare/cfssl/helpers" "net" "strings" "testing" ) var ( testProvider auth.Provider testKey = "0123456789ABCDEF0123456789ABCDEF" testAD = []byte{1, 2, 3, 4} // IP address 1.2.3.4 ) func TestNewServer(t *testing.T) { s := NewServer("1.1.1.1:::123456789") if s != nil { t.Fatalf("fatal error, server created with too many colons %v", s) } s2 := NewServer("1.1.1.1:[]") if s != nil { t.Fatalf("%v", s2) } _, port, _ := net.SplitHostPort("") if port != "" { t.Fatalf("%v", port) } s = NewServer("http://127.0.0.1:8888") hosts := s.Hosts() if len(hosts) != 1 || hosts[0] != "http://127.0.0.1:8888" { t.Fatalf("expected [http://127.0.0.1:8888], but have %v", hosts) } s = NewServer("http://1.1.1.1:9999") hosts = s.Hosts() if len(hosts) != 1 || hosts[0] != "http://1.1.1.1:9999" { t.Fatalf("expected [http://1.1.1.1:9999], but have %v", hosts) } s = NewServer("https://1.1.1.1:8080") hosts = s.Hosts() if len(hosts) != 1 || hosts[0] != "https://1.1.1.1:8080" { t.Fatalf("expected [https://1.1.1.1:8080], but have %v", hosts) } } func TestInvalidPort(t *testing.T) { s := NewServer("1.1.1.1:99999999999999999999999999999") if s != nil { t.Fatalf("%v", s) } } func TestAuthSign(t *testing.T) { s := NewServer(".X") testProvider, _ = auth.New(testKey, nil) testRequest := []byte(`testing 1 2 3`) as, err := s.AuthSign(testRequest, testAD, testProvider) if as != nil || err == nil { t.Fatal("expected error with auth sign function") } } func TestDefaultAuthSign(t *testing.T) { testProvider, _ = auth.New(testKey, nil) s := NewAuthServer(".X", nil, testProvider) testRequest := []byte(`testing 1 2 3`) as, err := s.Sign(testRequest) if as != nil || err == nil { t.Fatal("expected error with auth sign function") } } func TestSign(t *testing.T) { s := NewServer(".X") sign, err := s.Sign([]byte{5, 5, 5, 5}) if sign != nil || err == nil { t.Fatalf("expected error with sign function") } } func TestNewMutualTLSServer(t *testing.T) { cert, _ := helpers.LoadClientCertificate("../../helpers/testdata/ca.pem", "../../helpers/testdata/ca_key.pem") s := NewServerTLS("https://nohost:8888", helpers.CreateTLSConfig(nil, cert)) if s == nil { t.Fatalf("fatal error, empty server") } _, err := s.Sign([]byte{5, 5, 5, 5}) if err == nil { t.Fatalf("expected error with sign function") } if !(strings.Contains(err.Error(), "Post")) && !(strings.Contains(err.Error(), "https://nohost:8888/api/v1/cfssl/sign")) && !(strings.Contains(err.Error(), "dial tcp: lookup nohost: no such host")) { t.Fatalf("no error message %v", err) } } func TestNewServerGroup(t *testing.T) { s := NewServer("cfssl1.local:8888, cfssl2.local:8888, http://cfssl3.local:8888, http://cfssl4.local:8888") ogl, ok := s.(*orderedListGroup) if !ok { t.Fatalf("expected NewServer to return an ordered group list with a list of servers, instead got a %T = %+v", ogl, ogl) } if len(ogl.remotes) != 4 { t.Fatalf("expected the remote to have four servers, but it has %d", len(ogl.remotes)) } hosts := ogl.Hosts() if len(hosts) != 4 { t.Fatalf("expected 2 hosts in the group, but have %d", len(hosts)) } if hosts[0] != "http://cfssl1.local:8888" { t.Fatalf("expected to see http://cfssl1.local:8888, but saw %s", hosts[0]) } if hosts[1] != "http://cfssl2.local:8888" { t.Fatalf("expected to see http://cfssl2.local:8888, but saw %s", hosts[1]) } if hosts[2] != "http://cfssl3.local:8888" { t.Fatalf("expected to see http://cfssl1.local:8888, but saw %s", hosts[2]) } if hosts[3] != "http://cfssl4.local:8888" { t.Fatalf("expected to see http://cfssl2.local:8888, but saw %s", hosts[3]) } } func TestNewTLSServerGroup(t *testing.T) { NewTLSServerGroup(t, nil) } func TestNewMutualTLSServerGroup(t *testing.T) { cert, _ := helpers.LoadClientCertificate("../../helpers/testdata/ca.pem", "../../helpers/testdata/ca_key.pem") NewTLSServerGroup(t, cert) } func NewTLSServerGroup(t *testing.T, cert *tls.Certificate) { s := NewServerTLS("https://cfssl1.local:8888, https://cfssl2.local:8888", helpers.CreateTLSConfig(nil, cert)) ogl, ok := s.(*orderedListGroup) if !ok { t.Fatalf("expected NewServer to return an ordered group list with a list of servers, instead got a %T = %+v", ogl, ogl) } if len(ogl.remotes) != 2 { t.Fatalf("expected the remote to have two servers, but it has %d", len(ogl.remotes)) } hosts := ogl.Hosts() if len(hosts) != 2 { t.Fatalf("expected 2 hosts in the group, but have %d", len(hosts)) } if hosts[0] != "https://cfssl1.local:8888" { t.Fatalf("expected to see https://cfssl1.local:8888, but saw %s", hosts[0]) } if hosts[1] != "https://cfssl2.local:8888" { t.Fatalf("expected to see https://cfssl2.local:8888, but saw %s", hosts[1]) } } func TestNewOGLGroup(t *testing.T) { strategy := StrategyFromString("ordered_list") if strategy == StrategyInvalid { t.Fatal("expected StrategyOrderedList as selected strategy but have StrategyInvalid") } if strategy != StrategyOrderedList { t.Fatalf("expected StrategyOrderedList (%d) but have %d", StrategyOrderedList, strategy) } rem, err := NewGroup([]string{"ca1.local,", "ca2.local"}, nil, strategy) if err != nil { t.Fatalf("%v", err) } ogl, ok := rem.(*orderedListGroup) if !ok { t.Fatalf("expected to get an orderedListGroup but got %T", rem) } if len(ogl.remotes) != 2 { t.Fatalf("expected two remotes in the ordered group list but have %d", len(ogl.remotes)) } } ================================================ FILE: api/client/group.go ================================================ package client import ( "crypto/tls" "errors" "net/http" "net/url" "strings" "time" "github.com/cloudflare/cfssl/auth" "github.com/cloudflare/cfssl/info" ) // Strategy is the means by which the server to use as a remote should // be selected. type Strategy int const ( // StrategyInvalid indicates any strategy that is unsupported // or returned when no strategy is applicable. StrategyInvalid = iota // StrategyOrderedList is a sequential list of servers: if the // first server cannot be reached, the next is used. The // client will proceed in this manner until the list of // servers is exhausted, and then an error is returned. StrategyOrderedList ) var strategyStrings = map[string]Strategy{ "ordered_list": StrategyOrderedList, } // StrategyFromString takes a string describing a func StrategyFromString(s string) Strategy { s = strings.TrimSpace(strings.ToLower(s)) strategy, ok := strategyStrings[s] if !ok { return StrategyInvalid } return strategy } // NewGroup will use the collection of remotes specified with the // given strategy. func NewGroup(remotes []string, tlsConfig *tls.Config, strategy Strategy) (Remote, error) { var servers = make([]*server, len(remotes)) for i := range remotes { u, err := normalizeURL(remotes[i]) if err != nil { return nil, err } servers[i] = newServer(u, tlsConfig) } switch strategy { case StrategyOrderedList: return newOrdererdListGroup(servers) default: return nil, errors.New("unrecognised strategy") } } type orderedListGroup struct { remotes []*server } func (g *orderedListGroup) Hosts() []string { var hosts = make([]string, 0, len(g.remotes)) for _, srv := range g.remotes { srvHosts := srv.Hosts() hosts = append(hosts, srvHosts[0]) } return hosts } func (g *orderedListGroup) SetRequestTimeout(timeout time.Duration) { for _, srv := range g.remotes { srv.SetRequestTimeout(timeout) } } func (g *orderedListGroup) SetProxy(proxy func(*http.Request) (*url.URL, error)) { for _, srv := range g.remotes { srv.SetProxy(proxy) } } func newOrdererdListGroup(remotes []*server) (Remote, error) { return &orderedListGroup{ remotes: remotes, }, nil } func (g *orderedListGroup) AuthSign(req, id []byte, provider auth.Provider) (resp []byte, err error) { for i := range g.remotes { resp, err = g.remotes[i].AuthSign(req, id, provider) if err == nil { return resp, nil } } return nil, err } func (g *orderedListGroup) Sign(jsonData []byte) (resp []byte, err error) { for i := range g.remotes { resp, err = g.remotes[i].Sign(jsonData) if err == nil { return resp, nil } } return nil, err } func (g *orderedListGroup) Info(jsonData []byte) (resp *info.Resp, err error) { for i := range g.remotes { resp, err = g.remotes[i].Info(jsonData) if err == nil { return resp, nil } } return nil, err } // SetReqModifier does nothing because there is no request modifier for group func (g *orderedListGroup) SetReqModifier(mod func(*http.Request, []byte)) { // noop } ================================================ FILE: api/crl/crl.go ================================================ // Package crl implements the HTTP handler for the crl command. package crl import ( "crypto" "crypto/x509" "net/http" "os" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/crl" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" ) // A Handler accepts requests with a serial number parameter // and revokes type Handler struct { dbAccessor certdb.Accessor ca *x509.Certificate key crypto.Signer } // NewHandler returns a new http.Handler that handles a revoke request. func NewHandler(dbAccessor certdb.Accessor, caPath string, caKeyPath string) (http.Handler, error) { ca, err := helpers.ReadBytes(caPath) if err != nil { return nil, err } caKey, err := helpers.ReadBytes(caKeyPath) if err != nil { return nil, errors.Wrap(errors.PrivateKeyError, errors.ReadFailed, err) } // Parse the PEM encoded certificate issuerCert, err := helpers.ParseCertificatePEM(ca) if err != nil { return nil, err } strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD") password := []byte(strPassword) if strPassword == "" { password = nil } // Parse the key given key, err := helpers.ParsePrivateKeyPEMWithPassword(caKey, password) if err != nil { log.Debugf("malformed private key %v", err) return nil, err } return &api.HTTPHandler{ Handler: &Handler{ dbAccessor: dbAccessor, ca: issuerCert, key: key, }, Methods: []string{"GET"}, }, nil } // Handle responds to revocation requests. It attempts to revoke // a certificate with a given serial number func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { var newExpiryTime = 7 * helpers.OneDay certs, err := h.dbAccessor.GetRevokedAndUnexpiredCertificates() if err != nil { return err } queryExpiryTime := r.URL.Query().Get("expiry") if queryExpiryTime != "" { log.Infof("requested expiry time of %s", queryExpiryTime) newExpiryTime, err = time.ParseDuration(queryExpiryTime) if err != nil { return err } } result, err := crl.NewCRLFromDB(certs, h.ca, h.key, newExpiryTime) if err != nil { return err } return api.SendResponse(w, result) } ================================================ FILE: api/crl/crl_test.go ================================================ package crl import ( "crypto/x509" "encoding/base64" "encoding/json" "io" "net/http" "net/http/httptest" "testing" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/cloudflare/cfssl/helpers" ) const ( fakeAKI = "fake aki" testCaFile = "../testdata/ca.pem" testCaKeyFile = "../testdata/ca_key.pem" ) func prepDB() (certdb.Accessor, error) { db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") expirationTime := time.Now().AddDate(1, 0, 0) var cert = certdb.CertificateRecord{ Serial: "1", AKI: fakeAKI, Expiry: expirationTime, PEM: "revoked cert", Status: "revoked", RevokedAt: time.Now(), Reason: 4, } dbAccessor := sql.NewAccessor(db) err := dbAccessor.InsertCertificate(cert) if err != nil { return nil, err } return dbAccessor, nil } func testGetCRL(t *testing.T, dbAccessor certdb.Accessor, expiry string) (resp *http.Response, body []byte) { handler, err := NewHandler(dbAccessor, testCaFile, testCaKeyFile) if err != nil { t.Fatal(err) } ts := httptest.NewServer(handler) defer ts.Close() if expiry != "" { resp, err = http.Get(ts.URL + "?expiry=" + expiry) } else { resp, err = http.Get(ts.URL) } if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } func TestCRLGeneration(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } resp, body := testGetCRL(t, dbAccessor, "") if resp.StatusCode != http.StatusOK { t.Fatal("unexpected HTTP status code; expected OK", string(body)) } message := new(api.Response) err = json.Unmarshal(body, message) if err != nil { t.Fatalf("failed to read response body: %v", err) } crlBytes := message.Result.(string) crlBytesDER, err := base64.StdEncoding.DecodeString(crlBytes) if err != nil { t.Fatal("failed to decode certificate ", err) } parsedCrl, err := x509.ParseCRL(crlBytesDER) if err != nil { t.Fatal("failed to get certificate ", err) } if parsedCrl.HasExpired(time.Now().Add(5 * helpers.OneDay)) { t.Fatal("the request will expire after 5 days, this shouldn't happen") } certs := parsedCrl.TBSCertList.RevokedCertificates if len(certs) != 1 { t.Fatal("failed to get one certificate") } cert := certs[0] if cert.SerialNumber.String() != "1" { t.Fatal("cert was not correctly inserted in CRL, serial was ", cert.SerialNumber) } } func TestCRLGenerationWithExpiry(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } resp, body := testGetCRL(t, dbAccessor, "119h") if resp.StatusCode != http.StatusOK { t.Fatal("unexpected HTTP status code; expected OK", string(body)) } message := new(api.Response) err = json.Unmarshal(body, message) if err != nil { t.Fatalf("failed to read response body: %v", err) } crlBytes := message.Result.(string) crlBytesDER, err := base64.StdEncoding.DecodeString(crlBytes) if err != nil { t.Fatal("failed to decode certificate ", err) } parsedCrl, err := x509.ParseCRL(crlBytesDER) if err != nil { t.Fatal("failed to get certificate ", err) } if !parsedCrl.HasExpired(time.Now().Add(5 * helpers.OneDay)) { t.Fatal("the request should have expired") } certs := parsedCrl.TBSCertList.RevokedCertificates if len(certs) != 1 { t.Fatal("failed to get one certificate") } cert := certs[0] if cert.SerialNumber.String() != "1" { t.Fatal("cert was not correctly inserted in CRL, serial was ", cert.SerialNumber) } } ================================================ FILE: api/gencrl/gencrl.go ================================================ // Package gencrl implements the HTTP handler for the gencrl commands. package gencrl import ( "crypto/rand" "crypto/x509/pkix" "encoding/json" "io" "math/big" "net/http" "strconv" "strings" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" ) // This type is meant to be unmarshalled from JSON type jsonCRLRequest struct { Certificate string `json:"certificate"` SerialNumber []string `json:"serialNumber"` PrivateKey string `json:"issuingKey"` ExpiryTime string `json:"expireTime"` } // Handle responds to requests for crl generation. It creates this crl // based off of the given certificate, serial numbers, and private key func gencrlHandler(w http.ResponseWriter, r *http.Request) error { var revokedCerts []pkix.RevokedCertificate var oneWeek = time.Duration(604800) * time.Second var newExpiryTime = time.Now() body, err := io.ReadAll(r.Body) if err != nil { return err } r.Body.Close() req := &jsonCRLRequest{} err = json.Unmarshal(body, req) if err != nil { log.Error(err) } if req.ExpiryTime != "" { expiryTime := strings.TrimSpace(req.ExpiryTime) expiryInt, err := strconv.ParseInt(expiryTime, 0, 32) if err != nil { return err } newExpiryTime = time.Now().Add((time.Duration(expiryInt) * time.Second)) } if req.ExpiryTime == "" { newExpiryTime = time.Now().Add(oneWeek) } if err != nil { return err } cert, err := helpers.ParseCertificatePEM([]byte(req.Certificate)) if err != nil { log.Error("error from ParseCertificatePEM", err) return errors.NewBadRequestString("malformed certificate") } for _, value := range req.SerialNumber { tempBigInt := new(big.Int) tempBigInt.SetString(value, 10) tempCert := pkix.RevokedCertificate{ SerialNumber: tempBigInt, RevocationTime: time.Now(), } revokedCerts = append(revokedCerts, tempCert) } key, err := helpers.ParsePrivateKeyPEM([]byte(req.PrivateKey)) if err != nil { log.Debugf("malformed private key %v", err) return errors.NewBadRequestString("malformed Private Key") } result, err := cert.CreateCRL(rand.Reader, key, revokedCerts, time.Now(), newExpiryTime) if err != nil { log.Debugf("unable to create CRL: %v", err) return err } return api.SendResponse(w, result) } // NewHandler returns a new http.Handler that handles a crl generation request. func NewHandler() http.Handler { return api.HTTPHandler{ Handler: api.HandlerFunc(gencrlHandler), Methods: []string{"POST"}, } } ================================================ FILE: api/gencrl/gencrl_test.go ================================================ package gencrl import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "os" "testing" "github.com/cloudflare/cfssl/api" ) const ( cert = "../../crl/testdata/caTwo.pem" key = "../../crl/testdata/ca-keyTwo.pem" serialList = "../../crl/testdata/serialList" expiryTime = "2000" ) type testJSON struct { Certificate string SerialNumber []string PrivateKey string ExpiryTime string ExpectedHTTPStatus int ExpectedSuccess bool } var tester = testJSON{ Certificate: cert, SerialNumber: []string{"1", "2", "3"}, PrivateKey: key, ExpiryTime: "2000", ExpectedHTTPStatus: 200, ExpectedSuccess: true, } func newTestHandler(t *testing.T) http.Handler { return NewHandler() } func TestNewHandler(t *testing.T) { newTestHandler(t) } func newCRLServer(t *testing.T) *httptest.Server { ts := httptest.NewServer(newTestHandler(t)) return ts } func testCRLCreation(t *testing.T, issuingKey, certFile string, expiry string, serialList []string) (resp *http.Response, body []byte) { ts := newCRLServer(t) defer ts.Close() obj := map[string]interface{}{} if certFile != "" { c, err := os.ReadFile(certFile) if err != nil { t.Fatal(err) } obj["certificate"] = string(c) } obj["serialNumber"] = serialList if issuingKey != "" { c, err := os.ReadFile(issuingKey) if err != nil { t.Fatal(err) } obj["issuingKey"] = string(c) } obj["expireTime"] = expiry blob, err := json.Marshal(obj) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } func TestCRL(t *testing.T) { resp, body := testCRLCreation(t, tester.PrivateKey, tester.Certificate, tester.ExpiryTime, tester.SerialNumber) if resp.StatusCode != tester.ExpectedHTTPStatus { t.Logf("expected: %d, have %d", tester.ExpectedHTTPStatus, resp.StatusCode) t.Fatal(resp.Status, tester.ExpectedHTTPStatus, string(body)) } message := new(api.Response) err := json.Unmarshal(body, message) if err != nil { t.Logf("failed to read response body: %v", err) t.Fatal(resp.Status, tester.ExpectedHTTPStatus, message) } } ================================================ FILE: api/generator/generator.go ================================================ // Package generator implements the HTTP handlers for certificate generation. package generator import ( "crypto/md5" "crypto/sha1" "crypto/sha256" "crypto/x509" "encoding/json" "encoding/pem" "fmt" "io" "net/http" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/bundler" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/universal" ) const ( // CSRNoHostMessage is used to alert the user to a certificate lacking a hosts field. CSRNoHostMessage = `This certificate lacks a "hosts" field. This makes it unsuitable for websites. For more information see the Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org); specifically, section 10.2.3 ("Information Requirements").` // NoBundlerMessage is used to alert the user that the server does not have a bundler initialized. NoBundlerMessage = `This request requires a bundler, but one is not initialized for the API server.` ) // Sum contains digests for a certificate or certificate request. type Sum struct { MD5 string `json:"md5"` SHA1 string `json:"sha-1"` SHA256 string `json:"sha-256"` } // Validator is a type of function that contains the logic for validating // a certificate request. type Validator func(*csr.CertificateRequest) error // A CertRequest stores a PEM-encoded private key and corresponding // CSR; this is returned from the CSR generation endpoint. type CertRequest struct { Key string `json:"private_key"` CSR string `json:"certificate_request"` Sums map[string]Sum `json:"sums"` } // A Handler accepts JSON-encoded certificate requests and // returns a new private key and certificate request. type Handler struct { generator *csr.Generator } // NewHandler builds a new Handler from the // validation function provided. func NewHandler(validator Validator) (http.Handler, error) { log.Info("setting up key / CSR generator") return &api.HTTPHandler{ Handler: &Handler{ generator: &csr.Generator{Validator: validator}, }, Methods: []string{"POST"}, }, nil } func computeSum(in []byte) (sum Sum, err error) { var data []byte p, _ := pem.Decode(in) if p == nil { err = errors.NewBadRequestString("not a CSR or certificate") return } switch p.Type { case "CERTIFICATE REQUEST": var req *x509.CertificateRequest req, err = x509.ParseCertificateRequest(p.Bytes) if err != nil { return } data = req.Raw case "CERTIFICATE": var cert *x509.Certificate cert, err = x509.ParseCertificate(p.Bytes) if err != nil { return } data = cert.Raw default: err = errors.NewBadRequestString("not a CSR or certificate") return } md5Sum := md5.Sum(data) sha1Sum := sha1.Sum(data) sha256Sum := sha256.Sum256(data) sum.MD5 = fmt.Sprintf("%X", md5Sum[:]) sum.SHA1 = fmt.Sprintf("%X", sha1Sum[:]) sum.SHA256 = fmt.Sprintf("%X", sha256Sum[:]) return } // Handle responds to requests for the CA to generate a new private // key and certificate request on behalf of the client. The format for // these requests is documented in the API documentation. func (g *Handler) Handle(w http.ResponseWriter, r *http.Request) error { log.Info("request for CSR") body, err := io.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } r.Body.Close() req := new(csr.CertificateRequest) req.KeyRequest = csr.NewKeyRequest() err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } if req.CA != nil { log.Warningf("request received with CA section") return errors.NewBadRequestString("ca section only permitted in initca") } csr, key, err := g.generator.ProcessRequest(req) if err != nil { log.Warningf("failed to process CSR: %v", err) // The validator returns a *cfssl/errors.HttpError return err } sum, err := computeSum(csr) if err != nil { return errors.NewBadRequest(err) } // Both key and csr are returned PEM-encoded. response := api.NewSuccessResponse(&CertRequest{ Key: string(key), CSR: string(csr), Sums: map[string]Sum{"certificate_request": sum}, }) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) err = enc.Encode(response) return err } // A CertGeneratorHandler accepts JSON-encoded certificate requests // and returns a new private key and signed certificate; it handles // sending the CSR to the server. type CertGeneratorHandler struct { generator *csr.Generator bundler *bundler.Bundler signer signer.Signer } // NewCertGeneratorHandler builds a new handler for generating // certificates directly from certificate requests; the validator covers // the certificate request and the CA's key and certificate are used to // sign the generated request. If remote is not an empty string, the // handler will send signature requests to the CFSSL instance contained // in remote. func NewCertGeneratorHandler(validator Validator, caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) { var err error log.Info("setting up new generator / signer") cg := new(CertGeneratorHandler) if policy == nil { policy = &config.Signing{ Default: config.DefaultConfig(), Profiles: nil, } } root := universal.Root{ Config: map[string]string{ "ca-file": caFile, "ca-key-file": caKeyFile, }, } if cg.signer, err = universal.NewSigner(root, policy); err != nil { log.Errorf("setting up signer failed: %v", err) return nil, err } cg.generator = &csr.Generator{Validator: validator} return api.HTTPHandler{Handler: cg, Methods: []string{"POST"}}, nil } // NewCertGeneratorHandlerFromSigner returns a handler directly from // the signer and validation function. func NewCertGeneratorHandlerFromSigner(validator Validator, signer signer.Signer) http.Handler { return api.HTTPHandler{ Handler: &CertGeneratorHandler{ generator: &csr.Generator{Validator: validator}, signer: signer, }, Methods: []string{"POST"}, } } // SetBundler allows injecting an optional Bundler into the CertGeneratorHandler. func (cg *CertGeneratorHandler) SetBundler(caBundleFile, intBundleFile string) (err error) { cg.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile) return err } type genSignRequest struct { Request *csr.CertificateRequest `json:"request"` Profile string `json:"profile"` Label string `json:"label"` Bundle bool `json:"bundle"` } // Handle responds to requests for the CA to generate a new private // key and certificate on behalf of the client. The format for these // requests is documented in the API documentation. func (cg *CertGeneratorHandler) Handle(w http.ResponseWriter, r *http.Request) error { log.Info("request for CSR") req := new(genSignRequest) req.Request = csr.New() body, err := io.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } r.Body.Close() err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } if req.Request == nil { log.Warning("empty request received") return errors.NewBadRequestString("missing request section") } if req.Request.CA != nil { log.Warningf("request received with CA section") return errors.NewBadRequestString("ca section only permitted in initca") } csr, key, err := cg.generator.ProcessRequest(req.Request) if err != nil { log.Warningf("failed to process CSR: %v", err) // The validator returns a *cfssl/errors.HttpError return err } signReq := signer.SignRequest{ Request: string(csr), Profile: req.Profile, Label: req.Label, } certBytes, err := cg.signer.Sign(signReq) if err != nil { log.Warningf("failed to sign request: %v", err) return err } reqSum, err := computeSum(csr) if err != nil { return errors.NewBadRequest(err) } certSum, err := computeSum(certBytes) if err != nil { return errors.NewBadRequest(err) } result := map[string]interface{}{ "private_key": string(key), "certificate_request": string(csr), "certificate": string(certBytes), "sums": map[string]Sum{ "certificate_request": reqSum, "certificate": certSum, }, } if req.Bundle { if cg.bundler == nil { return api.SendResponseWithMessage(w, result, NoBundlerMessage, errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode) } bundle, err := cg.bundler.BundleFromPEMorDER(certBytes, nil, bundler.Optimal, "") if err != nil { return err } result["bundle"] = bundle } if len(req.Request.Hosts) == 0 { return api.SendResponseWithMessage(w, result, CSRNoHostMessage, errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode) } return api.SendResponse(w, result) } // CSRValidate does nothing and will never return an error. It exists because NewHandler // requires a Validator as a parameter. func CSRValidate(req *csr.CertificateRequest) error { return nil } ================================================ FILE: api/generator/generator_test.go ================================================ package generator import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/signer/local" ) const ( testCaFile = "testdata/ca.pem" testCaKeyFile = "testdata/ca_key.pem" testCABundle = "../../bundler/testdata/ca-bundle.pem" testIntBundle = "../../bundler/testdata/int-bundle.pem" ) func csrData(t *testing.T) *bytes.Reader { req := &csr.CertificateRequest{ Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com"}, KeyRequest: csr.NewKeyRequest(), } csrBytes, err := json.Marshal(req) if err != nil { t.Fatal(err) } return bytes.NewReader(csrBytes) } func TestGeneratorRESTfulVerbs(t *testing.T) { handler, _ := NewHandler(CSRValidate) ts := httptest.NewServer(handler) data := csrData(t) // POST should work. req, _ := http.NewRequest("POST", ts.URL, data) resp, _ := http.DefaultClient.Do(req) if resp.StatusCode != http.StatusOK { t.Fatal(resp.Status) } // Test GET, PUT, DELETE and whatever, expect 400 errors. req, _ = http.NewRequest("GET", ts.URL, data) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } req, _ = http.NewRequest("PUT", ts.URL, data) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } req, _ = http.NewRequest("DELETE", ts.URL, data) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } req, _ = http.NewRequest("WHATEVER", ts.URL, data) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } } func TestCSRValidate(t *testing.T) { req := &csr.CertificateRequest{ Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{}, KeyRequest: csr.NewKeyRequest(), } err := CSRValidate(req) if err != nil { t.Fatal("There should be not an error for missing Hosts parameter") } } func TestNewCertGeneratorHandlerFromSigner(t *testing.T) { var expiry = 1 * time.Minute var CAConfig = &config.Config{ Signing: &config.Signing{ Profiles: map[string]*config.SigningProfile{ "signature": { Usage: []string{"digital signature"}, Expiry: expiry, }, }, Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "43800h", Expiry: expiry, CAConstraint: config.CAConstraint{IsCA: true}, ClientProvidesSerialNumbers: true, }, }, } s, err := local.NewSignerFromFile(testCaFile, testCaKeyFile, CAConfig.Signing) if err != nil { t.Fatal(err) } h := NewCertGeneratorHandlerFromSigner(CSRValidate, s) _, ok := h.(http.Handler) if !ok { t.Fatal("A HTTP handler has not been returned") } apiH, ok := h.(api.HTTPHandler) if !ok { t.Fatal("An api.HTTPHandler has not been returned") } cg, ok := apiH.Handler.(*CertGeneratorHandler) if !ok { t.Fatal("A CertGeneratorHandler has not been set") } if err := cg.SetBundler(testCABundle, testIntBundle); err != nil { t.Fatal(err) } } ================================================ FILE: api/generator/testdata/ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIEmzCCA4OgAwIBAgIMAMSvNBgypwaaSQ5iMA0GCSqGSIb3DQEBBQUAMIGMMQsw CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy YW5jaXNjbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVT VCBSb290IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTIx MjEyMDIxMDMxWhcNMjIxMDIxMDIxMDMxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNV BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoT CkNGU1NMIFRFU1QxGzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqG SIb3DQEJARYPdGVzdEB0ZXN0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsRp1xSfIDoD/40Bo4Hls3sFn4dav5NgxbZGpVyGF7dJI9u0eEnL4 BUGssPaUFLWC83CZxujUEiEfE0oKX+uOhhGv3+j5xSTNM764m2eSiN53cdZtK05d hwq9uS8LtjKOQeN1mQ5qmiqxBMdjkKgMsVw5lMCgoYKo57kaKFyXzdpNVDzqw+pt HWmuNtDQjK3qT5Ma06mYPmIGYhIZYLY7oJGg9ZEaNR0GIw4zIT5JRsNiaSb5wTLw aa0n/4vLJyVjLJcYmJBvZWj8g+taK+C4INu/jGux+bmsC9hq14tbOaTNAn/NE0qN 8oHwcRBEqfOdEYdZkxI5NWPiKNW/Q+AeXQIDAQABo4H6MIH3MB0GA1UdDgQWBBS3 0veEuqg51fusEM4p/YuWpBPsvTCBxAYDVR0jBIG8MIG5gBS30veEuqg51fusEM4p /YuWpBPsvaGBkqSBjzCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju aWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkNGU1NMIFRFU1Qx GzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqGSIb3DQEJARYPdGVz dEB0ZXN0LmxvY2FsggwAxK80GDKnBppJDmIwDwYDVR0TBAgwBgEB/wIBADANBgkq hkiG9w0BAQUFAAOCAQEAJ7r1EZYDwed6rS0+YKHdkRGRQ5Rz6A9DIVBPXrSMAGj3 F5EF2m/GJbhpVbnNJTVlgP9DDyabOZNxzdrCr4cHMkYYnocDdgAodnkw6GZ/GJTc depbVTR4TpihFNzeDEGJePrEwM1DouGswpu97jyuCYZ3z1a60+a+3C1GwWaJ7Aet Uqm+yLTUrMISsfnDPqJdM1NeqW3jiZ4IgcqJkieCCSpag9Xuzrp9q6rjmePvlQkv qz020JGg6VijJ+c6Tf5y0XqbAhkBTqYtVamu9gEth9utn12EhdNjTZMPKMjjgFUd H0N6yOEuQMl4ky7RxZBM0iPyeob6i4z2LEQilgv9MQ== -----END CERTIFICATE----- ================================================ FILE: api/generator/testdata/ca_key.pem ================================================ -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGnXFJ8gOgP/j QGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLzcJnG6NQSIR8T Sgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B43WZDmqaKrEE x2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepPkxrTqZg+YgZi EhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMslxiYkG9laPyD 61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850Rh1mTEjk1Y+Io 1b9D4B5dAgMBAAECggEAKHhjcSomDSptTwDo9mLI/h40HudwSlsc8GzYxZBjinUD N2n39T9QbeMUE1xFenX/9qFEgq+xxnLLJx1EQacSapCgIAqdCO/f9HMgvGJumdg8 c0cMq1i9Bp7tu+OESZ5D48qWlOM2eQRIb08g8W11eRIaFmPuUPoKnuktkQuXpPJc YbS/+JuA8SDwe6sV0cMCQuS+iHFfeGwWCKrDUkhLwcL3waW3od2XFyOeFFWFhl0h HmM/mWKRuRdqR7hrmArTwFZVkB+o/1ywVYXIv+JQm0eNZ5PKLNJGL2f5oxbMR/JI AoK0bAlJmYaFp96h1KpbPwLEL/0hHSWA7sAyJIgQAQKBgQDaEAZor/w4ZUTekT1+ cbId0yA+ikDXQOfXaNCSh9Pex+Psjd5zVVOqyVFJ29daRju3d7rmpN4Cm5V4h0l1 /2ad207rjCAnpCHtaddJWNyJzF2IL2IaoCZQRp0k7zOjBGQpoWDTwBaEin5CCv3P kkdQkKz6FDP1xskHSLZr21/QCQKBgQDP6jXutEgGjf3yKpMFk/69EamJdon8clbt hl7cOyWtobnZhdOWVZPe00Oo3Jag2aWgFFsm3EtwnUCnR4d4+fXRKS2LkhfIUZcz cKy17Ileggdd8UGhL4RDrF/En9tJL86WcVkcoOrqLcGB2FLWrVhVpHFK74eLMCH/ uc/+ioPItQKBgHYoDsD08s7AGMQcoNx90MyWVLduhFnegoFW+wUa8jOZzieka6/E wVQeR5yksZjpy3vLNYu6M83n7eLkM2rrm/fXGHlLcTTpm7SgEBZfPwivotKjEh5p PrlqucWEk082lutz1RqHz+u7e1Rfzk2F7nx6GDBdeBYpw03eGXJx6QW5AoGBAIJq 4puyAEAET1fZNtHX7IGCk7sDXTi6LCbgE57HhzHr8V0t4fQ6CABMuvMwM1gATjEk s6yjoLqqGUUUzDipanViBAy5fiuManC868lN7zkWDTLzQ3ytBqVAee4na/DziP27 ae9YTSLJwskE/alloLRP6zTbHUXE0n7LelmrX1DFAoGBAMFLl+Lu+WFgCHxBjn43 rHpJbQZQmsFhAMhkN4hsj6dJfAGn2gRLRiVRAika+8QF65xMZiVQWUVSUZADWERi 0SXGjzN1wYxO3Qzy3LYwws6fxFAq5lo79eb38yFT2lHdqK3x/QgiDSRVl+R6cExV xQB518/lp2eIeMpglWByDwJX -----END PRIVATE KEY----- ================================================ FILE: api/health/health.go ================================================ package health import ( "encoding/json" "net/http" "github.com/cloudflare/cfssl/api" ) // Response contains the response to the /health API type Response struct { Healthy bool `json:"healthy"` } func healthHandler(w http.ResponseWriter, r *http.Request) error { response := api.NewSuccessResponse(&Response{Healthy: true}) return json.NewEncoder(w).Encode(response) } // NewHealthCheck creates a new handler to serve health checks. func NewHealthCheck() http.Handler { return api.HTTPHandler{ Handler: api.HandlerFunc(healthHandler), Methods: []string{"GET"}, } } ================================================ FILE: api/info/info.go ================================================ // Package info implements the HTTP handler for the info command. package info import ( "encoding/json" "io" "net/http" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/info" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer" ) // Handler is a type that contains the root certificates for the CA, // and serves information on them for clients that need the certificates. type Handler struct { sign signer.Signer } // NewHandler creates a new handler to serve information on the CA's // certificates, taking a signer to use. func NewHandler(s signer.Signer) (http.Handler, error) { return &api.HTTPHandler{ Handler: &Handler{ sign: s, }, Methods: []string{"POST"}, }, nil } // Handle listens for incoming requests for CA information, and returns // a list containing information on each root certificate. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { req := new(info.Req) body, err := io.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } r.Body.Close() err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } resp, err := h.sign.Info(*req) if err != nil { return err } response := api.NewSuccessResponse(resp) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) return enc.Encode(response) } // MultiHandler is a handler for providing the public certificates for // a multi-root certificate authority. It takes a mapping of label to // signer and a default label, and handles the standard information // request as defined in the client package. type MultiHandler struct { signers map[string]signer.Signer defaultLabel string } // NewMultiHandler constructs a MultiHandler from a mapping of labels // to signers and the default label. func NewMultiHandler(signers map[string]signer.Signer, defaultLabel string) (http.Handler, error) { return &api.HTTPHandler{ Handler: &MultiHandler{ signers: signers, defaultLabel: defaultLabel, }, Methods: []string{"POST"}, }, nil } // Handle accepts client information requests, and uses the label to // look up the signer whose public certificate should be retrieved. If // the label is empty, the default label is used. func (h *MultiHandler) Handle(w http.ResponseWriter, r *http.Request) error { req := new(info.Req) body, err := io.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } r.Body.Close() err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } log.Debug("checking label") if req.Label == "" { req.Label = h.defaultLabel } if _, ok := h.signers[req.Label]; !ok { log.Warningf("request for invalid endpoint") return errors.NewBadRequestString("bad label") } log.Debug("getting info") resp, err := h.signers[req.Label].Info(*req) if err != nil { log.Infof("error getting certificate: %v", err) return err } response := api.NewSuccessResponse(resp) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) return enc.Encode(response) } ================================================ FILE: api/info/info_test.go ================================================ package info import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "testing" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/local" ) const ( testCaFile = "../testdata/ca.pem" testCaKeyFile = "../testdata/ca_key.pem" // second test CA for multiroot testCaFile2 = "../testdata/ca2.pem" testCaKeyFile2 = "../testdata/ca2-key.pem" ) // Generally, the single root function and its multiroot analogue will // be presented together. func newTestHandler(t *testing.T) (h http.Handler) { signer, err := local.NewSignerFromFile(testCaFile, testCaKeyFile, nil) if err != nil { t.Fatal(err) } h, err = NewHandler(signer) if err != nil { t.Fatal(err) } return } func newTestMultiHandler(t *testing.T) (h http.Handler) { signer1, err := local.NewSignerFromFile(testCaFile, testCaKeyFile, nil) if err != nil { t.Fatal(err) } signer2, err := local.NewSignerFromFile(testCaFile2, testCaKeyFile2, nil) if err != nil { t.Fatal(err) } signers := map[string]signer.Signer{ "test1": signer1, "test2": signer2, } h, err = NewMultiHandler(signers, "test1") if err != nil { t.Fatalf("%v", err) } return } func TestNewHandler(t *testing.T) { newTestHandler(t) } func TestNewMultiHandler(t *testing.T) { newTestMultiHandler(t) } func newInfoServer(t *testing.T) *httptest.Server { ts := httptest.NewServer(newTestHandler(t)) return ts } func newMultiInfoServer(t *testing.T) *httptest.Server { return httptest.NewServer(newTestMultiHandler(t)) } func testInfoFile(t *testing.T, req map[string]interface{}) (resp *http.Response, body []byte) { ts := newInfoServer(t) defer ts.Close() blob, err := json.Marshal(req) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } func testMultiInfoFile(t *testing.T, req map[string]interface{}) (resp *http.Response, body []byte) { ts := newMultiInfoServer(t) defer ts.Close() blob, err := json.Marshal(req) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } type infoTest struct { RequestObject map[string]interface{} ExpectedHTTPStatus int ExpectedSuccess bool ExpectedErrorCode int } var infoTests = []infoTest{ { map[string]interface{}{ "label": "", "profile": "", }, http.StatusOK, true, 0, }, { map[string]interface{}{ "label": 123, }, http.StatusBadRequest, false, http.StatusBadRequest, }, } var multiInfoTests = []infoTest{ { map[string]interface{}{ "label": "", "profile": "", }, http.StatusOK, true, 0, }, { map[string]interface{}{ "label": "test1", "profile": "", }, http.StatusOK, true, 0, }, { map[string]interface{}{ "label": "test2", "profile": "", }, http.StatusOK, true, 0, }, { map[string]interface{}{ "label": "badlabel", "profile": "", }, http.StatusBadRequest, false, http.StatusBadRequest, }, { map[string]interface{}{ "label": 123, }, http.StatusBadRequest, false, http.StatusBadRequest, }, } func TestInfo(t *testing.T) { for i, test := range infoTests { resp, body := testInfoFile(t, test.RequestObject) if resp.StatusCode != test.ExpectedHTTPStatus { t.Fatalf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode) t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body)) } message := new(api.Response) err := json.Unmarshal(body, message) if err != nil { t.Fatalf("failed to read response body: %v", err) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess != message.Success { t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess == true { continue } if test.ExpectedErrorCode != message.Errors[0].Code { t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } } } func TestMultiInfo(t *testing.T) { for i, test := range multiInfoTests { resp, body := testMultiInfoFile(t, test.RequestObject) if resp.StatusCode != test.ExpectedHTTPStatus { t.Fatalf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode) t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body)) } message := new(api.Response) err := json.Unmarshal(body, message) if err != nil { t.Fatalf("failed to read response body: %v", err) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess != message.Success { t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess == true { continue } if test.ExpectedErrorCode != message.Errors[0].Code { t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } } } ================================================ FILE: api/initca/initca.go ================================================ // Package initca implements the HTTP handler for the CA initialization command package initca import ( "encoding/json" "io" "net/http" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/initca" "github.com/cloudflare/cfssl/log" ) // A NewCA contains a private key and certificate suitable for serving // as the root key for a new certificate authority. type NewCA struct { Key string `json:"private_key"` Cert string `json:"certificate"` } // initialCAHandler is an HTTP handler that accepts a JSON blob in the // same format as the CSR endpoint; this blob should contain the // identity information for the CA's root key. This endpoint is not // suitable for creating intermediate certificates. func initialCAHandler(w http.ResponseWriter, r *http.Request) error { log.Info("setting up initial CA handler") body, err := io.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } r.Body.Close() req := new(csr.CertificateRequest) req.KeyRequest = csr.NewKeyRequest() err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } cert, _, key, err := initca.New(req) if err != nil { log.Warningf("failed to initialise new CA: %v", err) return err } response := api.NewSuccessResponse(&NewCA{string(key), string(cert)}) enc := json.NewEncoder(w) err = enc.Encode(response) return err } // NewHandler returns a new http.Handler that handles request to // initialize a CA. func NewHandler() http.Handler { return api.HTTPHandler{Handler: api.HandlerFunc(initialCAHandler), Methods: []string{"POST"}} } ================================================ FILE: api/initca/initca_test.go ================================================ package initca import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/cloudflare/cfssl/csr" ) func csrData(t *testing.T) *bytes.Reader { req := &csr.CertificateRequest{ Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com"}, KeyRequest: csr.NewKeyRequest(), } csrBytes, err := json.Marshal(req) if err != nil { t.Fatal(err) } return bytes.NewReader(csrBytes) } func TestInitCARESTfulVerbs(t *testing.T) { ts := httptest.NewServer(NewHandler()) data := csrData(t) // POST should work. req, _ := http.NewRequest("POST", ts.URL, data) resp, _ := http.DefaultClient.Do(req) if resp.StatusCode != http.StatusOK { t.Fatal(resp.Status) } // Test GET, PUT, DELETE and whatever, expect 400 errors. req, _ = http.NewRequest("GET", ts.URL, data) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } req, _ = http.NewRequest("PUT", ts.URL, data) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } req, _ = http.NewRequest("DELETE", ts.URL, data) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } req, _ = http.NewRequest("WHATEVER", ts.URL, data) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } } func TestBadRequestBody(t *testing.T) { ts := httptest.NewServer(NewHandler()) req, _ := http.NewRequest("POST", ts.URL, nil) resp, _ := http.DefaultClient.Do(req) if resp.StatusCode == http.StatusOK { t.Fatal(resp.Status) } } func TestBadRequestBody_2(t *testing.T) { ts := httptest.NewServer(NewHandler()) r := &csr.CertificateRequest{} csrBytes, err := json.Marshal(r) if err != nil { t.Fatal(err) } data := bytes.NewReader(csrBytes) req, _ := http.NewRequest("POST", ts.URL, data) resp, _ := http.DefaultClient.Do(req) if resp.StatusCode == http.StatusOK { t.Fatal(resp.Status) } } ================================================ FILE: api/ocsp/ocspsign.go ================================================ // Package ocsp implements the HTTP handler for the ocsp commands. package ocsp import ( "crypto" "encoding/base64" "encoding/json" "io" "net/http" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/ocsp" ) // A Handler accepts requests with a certficate parameter // (which should be PEM-encoded) and returns a signed ocsp // response. type Handler struct { signer ocsp.Signer } // NewHandler returns a new http.Handler that handles a ocspsign request. func NewHandler(s ocsp.Signer) http.Handler { return &api.HTTPHandler{ Handler: &Handler{ signer: s, }, Methods: []string{"POST"}, } } // This type is meant to be unmarshalled from JSON type jsonSignRequest struct { Certificate string `json:"certificate"` Status string `json:"status"` Reason int `json:"reason,omitempty"` RevokedAt string `json:"revoked_at,omitempty"` IssuerHash string `json:"issuer_hash,omitempty"` } var nameToHash = map[string]crypto.Hash{ "MD5": crypto.MD5, "SHA1": crypto.SHA1, "SHA256": crypto.SHA256, "SHA384": crypto.SHA384, "SHA512": crypto.SHA512, } // Handle responds to requests for a ocsp signature. It creates and signs // a ocsp response for the provided certificate and status. If the status // is revoked then it also adds reason and revoked_at. The response is // base64 encoded. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { body, err := io.ReadAll(r.Body) if err != nil { return err } r.Body.Close() // Default the status to good so it matches the cli req := &jsonSignRequest{ Status: "good", } err = json.Unmarshal(body, req) if err != nil { return errors.NewBadRequestString("Unable to parse sign request") } cert, err := helpers.ParseCertificatePEM([]byte(req.Certificate)) if err != nil { log.Error("Error from ParseCertificatePEM", err) return errors.NewBadRequestString("Malformed certificate") } signReq := ocsp.SignRequest{ Certificate: cert, Status: req.Status, } // We need to convert the time from being a string to a time.Time if req.Status == "revoked" { signReq.Reason = req.Reason // "now" is accepted and the default on the cli so default that here if req.RevokedAt == "" || req.RevokedAt == "now" { signReq.RevokedAt = time.Now() } else { signReq.RevokedAt, err = time.Parse("2006-01-02", req.RevokedAt) if err != nil { return errors.NewBadRequestString("Malformed revocation time") } } } if req.IssuerHash != "" { issuerHash, ok := nameToHash[req.IssuerHash] if !ok { return errors.NewBadRequestString("Unsupported hash algorithm in request") } signReq.IssuerHash = issuerHash } resp, err := h.signer.Sign(signReq) if err != nil { return err } b64Resp := base64.StdEncoding.EncodeToString(resp) result := map[string]string{"ocspResponse": b64Resp} return api.SendResponse(w, result) } ================================================ FILE: api/ocsp/ocspsign_test.go ================================================ package ocsp import ( "bytes" "encoding/base64" "encoding/json" "io" "net/http" "net/http/httptest" "os" "testing" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/ocsp" goocsp "golang.org/x/crypto/ocsp" ) const ( testCaFile = "../../ocsp/testdata/ca.pem" testRespCertFile = "../../ocsp/testdata/server.crt" testKeyFile = "../../ocsp/testdata/server.key" testCertFile = "../../ocsp/testdata/cert.pem" ) func newTestHandler(t *testing.T) http.Handler { // arbitrary duration dur, _ := time.ParseDuration("1ms") s, err := ocsp.NewSignerFromFile(testCaFile, testRespCertFile, testKeyFile, dur) if err != nil { t.Fatalf("Signer creation failed %v", err) } return NewHandler(s) } func TestNewHandler(t *testing.T) { newTestHandler(t) } func newSignServer(t *testing.T) *httptest.Server { ts := httptest.NewServer(newTestHandler(t)) return ts } func testSignFile(t *testing.T, certFile, status string, reason int, revokedAt string, hash string) (resp *http.Response, body []byte) { ts := newSignServer(t) defer ts.Close() obj := map[string]interface{}{} if certFile != "" { c, err := os.ReadFile(certFile) if err != nil { t.Fatal(err) } obj["certificate"] = string(c) } if status != "" { obj["status"] = status } obj["reason"] = reason if revokedAt != "" { obj["revoked_at"] = revokedAt } obj["issuer_hash"] = hash blob, err := json.Marshal(obj) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } type signTest struct { CertificateFile string Status string Reason int RevokedAt string ExpectedHTTPStatus int ExpectedSuccess bool ExpectedErrorCode int IssuerHash string } var signTests = []signTest{ { CertificateFile: testCertFile, ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { CertificateFile: testCertFile, Status: "revoked", Reason: 1, ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { CertificateFile: testCertFile, Status: "revoked", RevokedAt: "now", ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { CertificateFile: testCertFile, Status: "revoked", RevokedAt: "2015-08-15", ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { CertificateFile: testCertFile, Status: "revoked", RevokedAt: "a", ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: http.StatusBadRequest, }, { CertificateFile: "", Status: "", ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: http.StatusBadRequest, }, { CertificateFile: testCertFile, Status: "_", ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: 8200, }, { CertificateFile: testCertFile, IssuerHash: "SHA256", ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { CertificateFile: testCertFile, IssuerHash: "MD4", ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: http.StatusBadRequest, }, } func TestSign(t *testing.T) { for i, test := range signTests { resp, body := testSignFile(t, test.CertificateFile, test.Status, test.Reason, test.RevokedAt, test.IssuerHash) if resp.StatusCode != test.ExpectedHTTPStatus { t.Logf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode) t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body)) } message := new(api.Response) err := json.Unmarshal(body, message) if err != nil { t.Logf("failed to read response body: %v", err) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess != message.Success { t.Logf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if !test.ExpectedSuccess { if test.ExpectedErrorCode != message.Errors[0].Code { t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } continue } result, ok := message.Result.(map[string]interface{}) if !ok { t.Logf("failed to read result") t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body)) } b64Resp, ok := result["ocspResponse"].(string) if !ok { t.Logf("failed to find ocspResponse") t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body)) } der, err := base64.StdEncoding.DecodeString(b64Resp) if err != nil { t.Logf("failed to decode base64") t.Fatal(resp.Status, test.ExpectedHTTPStatus, b64Resp) } ocspResp, err := goocsp.ParseResponse(der, nil) if err != nil { t.Logf("failed to parse ocsp response: %v", err) t.Fatal(resp.Status, test.ExpectedHTTPStatus, b64Resp) } // should default to good if test.Status == "" { test.Status = "good" } intStatus := ocsp.StatusCode[test.Status] if ocspResp.Status != intStatus { t.Fatalf("Test %d incorrect status: expected: %v, have %v", i, intStatus, ocspResp.Status) t.Fatal(ocspResp.Status, intStatus, ocspResp) } if test.Status == "revoked" { if ocspResp.RevocationReason != test.Reason { t.Fatalf("Test %d incorrect reason: expected: %v, have %v", i, test.Reason, ocspResp.RevocationReason) t.Fatal(ocspResp.RevocationReason, test.Reason, ocspResp) } var r time.Time if test.RevokedAt == "" || test.RevokedAt == "now" { r = time.Now().UTC().Truncate(helpers.OneDay) } else { r, _ = time.Parse("2006-01-02", test.RevokedAt) } if !ocspResp.RevokedAt.Truncate(helpers.OneDay).Equal(r) { t.Fatalf("Test %d incorrect revokedAt: expected: %v, have %v", i, r, ocspResp.RevokedAt) t.Fatal(ocspResp.RevokedAt, test.RevokedAt, ocspResp) } } } } ================================================ FILE: api/revoke/revoke.go ================================================ // Package revoke implements the HTTP handler for the revoke command package revoke import ( "encoding/json" "io" "net/http" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/ocsp" stdocsp "golang.org/x/crypto/ocsp" ) // A Handler accepts requests with a serial number parameter // and revokes type Handler struct { dbAccessor certdb.Accessor Signer ocsp.Signer } // NewHandler returns a new http.Handler that handles a revoke request. func NewHandler(dbAccessor certdb.Accessor) http.Handler { return &api.HTTPHandler{ Handler: &Handler{ dbAccessor: dbAccessor, }, Methods: []string{"POST"}, } } // NewOCSPHandler returns a new http.Handler that handles a revoke // request and also generates an OCSP response func NewOCSPHandler(dbAccessor certdb.Accessor, signer ocsp.Signer) http.Handler { return &api.HTTPHandler{ Handler: &Handler{ dbAccessor: dbAccessor, Signer: signer, }, Methods: []string{"POST"}, } } // This type is meant to be unmarshalled from JSON type jsonRevokeRequest struct { Serial string `json:"serial"` AKI string `json:"authority_key_id"` Reason string `json:"reason"` } // Handle responds to revocation requests. It attempts to revoke // a certificate with a given serial number func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { body, err := io.ReadAll(r.Body) if err != nil { return err } r.Body.Close() // Default the status to good so it matches the cli var req jsonRevokeRequest err = json.Unmarshal(body, &req) if err != nil { return errors.NewBadRequestString("Unable to parse revocation request") } if len(req.Serial) == 0 { return errors.NewBadRequestString("serial number is required but not provided") } var reasonCode int reasonCode, err = ocsp.ReasonStringToCode(req.Reason) if err != nil { return errors.NewBadRequestString("Invalid reason code") } err = h.dbAccessor.RevokeCertificate(req.Serial, req.AKI, reasonCode) if err != nil { return err } // If we were given a signer, try and generate an OCSP // response indicating revocation if h.Signer != nil { // TODO: should these errors be errors? // Grab the certificate from the database cr, err := h.dbAccessor.GetCertificate(req.Serial, req.AKI) if err != nil { return err } if len(cr) != 1 { return errors.NewBadRequestString("No unique certificate found") } cert, err := helpers.ParseCertificatePEM([]byte(cr[0].PEM)) if err != nil { return errors.NewBadRequestString("Unable to parse certificates from PEM data") } sr := ocsp.SignRequest{ Certificate: cert, Status: "revoked", Reason: reasonCode, RevokedAt: time.Now().UTC(), } ocspResponse, err := h.Signer.Sign(sr) if err != nil { return err } // We parse the OCSP response in order to get the next // update time/expiry time ocspParsed, err := stdocsp.ParseResponse(ocspResponse, nil) if err != nil { return err } ocspRecord := certdb.OCSPRecord{ Serial: req.Serial, AKI: req.AKI, Body: string(ocspResponse), Expiry: ocspParsed.NextUpdate, } if err = h.dbAccessor.InsertOCSP(ocspRecord); err != nil { return err } } result := map[string]string{} return api.SendResponse(w, result) } ================================================ FILE: api/revoke/revoke_test.go ================================================ package revoke import ( "bytes" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/hex" "encoding/json" "encoding/pem" "io" "math/big" "net/http" "net/http/httptest" "testing" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/cloudflare/cfssl/ocsp" stdocsp "golang.org/x/crypto/ocsp" ) const ( fakeAKI = "fake aki" ) func prepDB() (certdb.Accessor, error) { db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") expirationTime := time.Now().AddDate(1, 0, 0) var cert = certdb.CertificateRecord{ Serial: "1", AKI: fakeAKI, Expiry: expirationTime, PEM: "unexpired cert", } dbAccessor := sql.NewAccessor(db) err := dbAccessor.InsertCertificate(cert) if err != nil { return nil, err } return dbAccessor, nil } func testRevokeCert(t *testing.T, dbAccessor certdb.Accessor, serial, aki, reason string) (resp *http.Response, body []byte) { ts := httptest.NewServer(NewHandler(dbAccessor)) defer ts.Close() obj := map[string]interface{}{} obj["serial"] = serial obj["authority_key_id"] = aki if reason != "" { obj["reason"] = reason } blob, err := json.Marshal(obj) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } func TestInvalidRevocation(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } resp, _ := testRevokeCert(t, dbAccessor, "", "", "") if resp.StatusCode != http.StatusBadRequest { t.Fatal("expected bad request response") } } func TestRevocation(t *testing.T) { dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } resp, body := testRevokeCert(t, dbAccessor, "1", fakeAKI, "5") if resp.StatusCode != http.StatusOK { t.Fatal("unexpected HTTP status code; expected OK", string(body)) } message := new(api.Response) err = json.Unmarshal(body, message) if err != nil { t.Fatalf("failed to read response body: %v", err) } certs, err := dbAccessor.GetCertificate("1", fakeAKI) if err != nil { t.Fatal("failed to get certificate ", err) } if len(certs) != 1 { t.Fatal("failed to get one certificate") } cert := certs[0] if cert.Status != "revoked" || cert.Reason != 5 { t.Fatal("cert was not correctly revoked") } } // TestOCSPGeneration tests that revoking a certificate (when the // request handler has an OCSP response signer) generates an // appropriate OCSP response in the certdb. func TestOCSPGeneration(t *testing.T) { privKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatal(err) } serialNumberRange := new(big.Int).Lsh(big.NewInt(1), 128) // 1. Generate a CA certificate to serve as the signing certificate. issuerSerial, err := rand.Int(rand.Reader, serialNumberRange) if err != nil { t.Fatal(err) } issuerTemplate := x509.Certificate{ SerialNumber: issuerSerial, Subject: pkix.Name{ Organization: []string{"cfssl unit test"}, }, AuthorityKeyId: []byte{42, 42, 42, 42}, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, IsCA: true, BasicConstraintsValid: true, } issuerBytes, err := x509.CreateCertificate(rand.Reader, &issuerTemplate, &issuerTemplate, &privKey.PublicKey, privKey) if err != nil { t.Fatal(err) } issuer, err := x509.ParseCertificate(issuerBytes) if err != nil { t.Fatal(err) } // 2. Generate a certificate signed by the CA certificate to revoke. revokedSerial, err := rand.Int(rand.Reader, serialNumberRange) if err != nil { t.Fatal(err) } revokedTemplate := x509.Certificate{ SerialNumber: revokedSerial, Subject: pkix.Name{ Organization: []string{"Cornell CS 5152"}, }, AuthorityKeyId: []byte{42, 42, 42, 42}, } revokedBytes, err := x509.CreateCertificate(rand.Reader, &revokedTemplate, issuer, &privKey.PublicKey, privKey) if err != nil { t.Fatal(err) } revoked := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: revokedBytes, }) revokedAKI := hex.EncodeToString(revokedTemplate.AuthorityKeyId) revokedSerialStr := revokedSerial.Text(16) // 3. Generate a certificate to use as the responder certificate. responderSerial, err := rand.Int(rand.Reader, serialNumberRange) if err != nil { t.Fatal(err) } responderTemplate := x509.Certificate{ SerialNumber: responderSerial, Subject: pkix.Name{ Organization: []string{"Cornell CS 5152 Responder"}, }, AuthorityKeyId: []byte{42, 42, 42, 43}, } responderBytes, err := x509.CreateCertificate(rand.Reader, &responderTemplate, &responderTemplate, &privKey.PublicKey, privKey) if err != nil { t.Fatal(err) } responder, err := x509.ParseCertificate(responderBytes) if err != nil { t.Fatal(err) } // 4. Create the OCSP signer signer, err := ocsp.NewSigner(issuer, responder, privKey, time.Hour) if err != nil { t.Fatal(err) } // 5. Spin up the test server // 5a. Prepare the DB dbAccessor, err := prepDB() if err != nil { t.Fatal(err) } expirationTime := time.Now().AddDate(1, 0, 0) cr := certdb.CertificateRecord{ Serial: revokedSerialStr, AKI: revokedAKI, Expiry: expirationTime, PEM: string(revoked), } if err := dbAccessor.InsertCertificate(cr); err != nil { t.Fatal(err) } // 5b. Start the test server ts := httptest.NewServer(NewOCSPHandler(dbAccessor, signer)) defer ts.Close() // 6. Prepare the revocation request obj := map[string]interface{}{} obj["serial"] = revokedSerialStr obj["authority_key_id"] = revokedAKI obj["reason"] = "unspecified" blob, err := json.Marshal(obj) if err != nil { t.Fatal(err) } // Get the original number of OCSP responses ocspsBefore, _ := dbAccessor.GetOCSP(revokedSerialStr, revokedAKI) ocspCountBefore := len(ocspsBefore) // 7. Send the revocation request resp, err := http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err := io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } if resp.StatusCode != http.StatusOK { t.Fatal("unexpected HTTP status code; expected OK", string(body)) } message := new(api.Response) err = json.Unmarshal(body, message) if err != nil { t.Fatalf("failed to read response body: %v", err) } // 8. Make sure the certificate record was updated certs, err := dbAccessor.GetCertificate(revokedSerialStr, revokedAKI) if err != nil { t.Fatal("failed to get certificate ", err) } if len(certs) != 1 { t.Fatal("failed to get one certificate") } cert := certs[0] if cert.Status != "revoked" || cert.Reason != stdocsp.Unspecified { t.Fatal("cert was not correctly revoked") } // 9. Make sure there is an OCSP record ocsps, err := dbAccessor.GetOCSP(revokedSerialStr, revokedAKI) if err != nil { t.Fatal("failed to get OCSP responses ", err) } if len(ocsps) == 0 { t.Fatal("No OCSP response generated") } if len(ocsps) <= ocspCountBefore { t.Fatal("No new OCSP response found") } } ================================================ FILE: api/scan/scan.go ================================================ package scan import ( "encoding/json" "net/http" "time" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/scan" ) // scanHandler is an HTTP handler that accepts GET parameters for host (required) // family and scanner, and uses these to perform scans, returning a JSON blob result. func scanHandler(w http.ResponseWriter, r *http.Request) error { if err := r.ParseForm(); err != nil { log.Warningf("failed to parse body: %v", err) return errors.NewBadRequest(err) } family := r.Form.Get("family") scanner := r.Form.Get("scanner") ip := r.Form.Get("ip") timeoutStr := r.Form.Get("timeout") var timeout time.Duration var err error if timeoutStr != "" { if timeout, err = time.ParseDuration(timeoutStr); err != nil { return errors.NewBadRequest(err) } if timeout < time.Second || timeout > 5*time.Minute { return errors.NewBadRequestString("invalid timeout given") } } else { timeout = time.Minute } host := r.Form.Get("host") if host == "" { log.Warningf("no host given") return errors.NewBadRequestString("no host given") } results, err := scan.Default.RunScans(host, ip, family, scanner, timeout) if err != nil { return errors.NewBadRequest(err) } return json.NewEncoder(w).Encode(api.NewSuccessResponse(results)) } // NewHandler returns a new http.Handler that handles a scan request. func NewHandler(caBundleFile string) (http.Handler, error) { return api.HTTPHandler{ Handler: api.HandlerFunc(scanHandler), Methods: []string{"GET"}, }, scan.LoadRootCAs(caBundleFile) } // scanInfoHandler is an HTTP handler that returns a JSON blob result describing // the possible families and scans to be run. func scanInfoHandler(w http.ResponseWriter, r *http.Request) error { log.Info("setting up scaninfo handler") response := api.NewSuccessResponse(scan.Default) enc := json.NewEncoder(w) return enc.Encode(response) } // NewInfoHandler returns a new http.Handler that handles a request for scan info. func NewInfoHandler() http.Handler { return api.HTTPHandler{ Handler: api.HandlerFunc(scanInfoHandler), Methods: []string{"GET"}, } } ================================================ FILE: api/scan/scan_test.go ================================================ package scan import ( "net/http" "net/http/httptest" "testing" ) var ( handler, _ = NewHandler("") ts = httptest.NewServer(handler) ) func TestBadRequest(t *testing.T) { // Test request with no host req, _ := http.NewRequest("GET", ts.URL, nil) resp, _ := http.DefaultClient.Do(req) if resp.StatusCode != http.StatusBadRequest { t.Fatal(resp.Status) } } func TestScanRESTfulVerbs(t *testing.T) { // GET should work req, _ := http.NewRequest("GET", ts.URL, nil) data := req.URL.Query() data.Add("host", "cloudflare.com") req.URL.RawQuery = data.Encode() resp, _ := http.DefaultClient.Do(req) if resp.StatusCode != http.StatusOK { t.Fatal(resp.Status) } // POST, PUT, DELETE, WHATEVER should return 400 errors req, _ = http.NewRequest("POST", ts.URL, nil) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } req, _ = http.NewRequest("DELETE", ts.URL, nil) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } req, _ = http.NewRequest("PUT", ts.URL, nil) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } req, _ = http.NewRequest("WHATEVER", ts.URL, nil) resp, _ = http.DefaultClient.Do(req) if resp.StatusCode != http.StatusMethodNotAllowed { t.Fatal(resp.Status) } } func TestNewInfoHandler(t *testing.T) { handler := NewInfoHandler() if handler == nil { t.Fatal("Handler error") } } ================================================ FILE: api/sign/sign.go ================================================ // Package sign implements the HTTP handler for the certificate signing command. package sign import ( "net/http" "github.com/cloudflare/cfssl/api/signhandler" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer/universal" ) // NewHandler generates a new Handler using the certificate // authority private key and certficate to sign certificates. If remote // is not an empty string, the handler will send signature requests to // the CFSSL instance contained in remote by default. func NewHandler(caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) { root := universal.Root{ Config: map[string]string{ "cert-file": caFile, "key-file": caKeyFile, }, } s, err := universal.NewSigner(root, policy) if err != nil { log.Errorf("setting up signer failed: %v", err) return nil, err } return signhandler.NewHandlerFromSigner(s) } // NewAuthHandler generates a new AuthHandler using the certificate // authority private key and certficate to sign certificates. If remote // is not an empty string, the handler will send signature requests to // the CFSSL instance contained in remote by default. func NewAuthHandler(caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) { root := universal.Root{ Config: map[string]string{ "cert-file": caFile, "key-file": caKeyFile, }, } s, err := universal.NewSigner(root, policy) if err != nil { log.Errorf("setting up signer failed: %v", err) return nil, err } return signhandler.NewAuthHandlerFromSigner(s) } ================================================ FILE: api/sign/sign_test.go ================================================ package sign import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "os" "strings" "testing" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/auth" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/signer" ) const ( testCaFile = "../testdata/ca.pem" testCaKeyFile = "../testdata/ca_key.pem" testCSRFile = "../testdata/csr.pem" testBrokenCertFile = "../testdata/broken.pem" testBrokenCSRFile = "../testdata/broken_csr.pem" ) var validLocalConfig = ` { "signing": { "default": { "usages": ["digital signature", "email protection"], "expiry": "1m" } } }` var validAuthLocalConfig = ` { "signing": { "default": { "usages": ["digital signature", "email protection"], "expiry": "1m", "auth_key": "sample" } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } } }` var validMixedLocalConfig = ` { "signing": { "default": { "usages": ["digital signature", "email protection"], "expiry": "1m" }, "profiles": { "auth": { "usages": ["digital signature", "email protection"], "expiry": "1m", "auth_key": "sample" } } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } } }` var alsoValidMixedLocalConfig = ` { "signing": { "default": { "usages": ["digital signature", "email protection"], "expiry": "1m", "auth_key": "sample" }, "profiles": { "no-auth": { "usages": ["digital signature", "email protection"], "expiry": "1m" } } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } } }` func newTestHandler(t *testing.T) (h http.Handler) { h, err := NewHandler(testCaFile, testCaKeyFile, nil) if err != nil { t.Fatal(err) } return } func TestNewHandler(t *testing.T) { newTestHandler(t) } func TestNewHandlerWithProfile(t *testing.T) { conf, err := config.LoadConfig([]byte(validLocalConfig)) if err != nil { t.Fatal(err) } _, err = NewHandler(testCaFile, testCaKeyFile, conf.Signing) if err != nil { t.Fatal(err) } } func TestNewHandlerWithAuthProfile(t *testing.T) { conf, err := config.LoadConfig([]byte(validAuthLocalConfig)) if err != nil { t.Fatal(err) } _, err = NewHandler(testCaFile, testCaKeyFile, conf.Signing) if err == nil { t.Fatal("All profiles have auth keys. Should have failed to create non-auth sign handler.") } } func TestNewHandlerError(t *testing.T) { // using testBrokenCSRFile as badly formed key _, err := NewHandler(testCaFile, testBrokenCSRFile, nil) if err == nil { t.Fatal("Expect error when create a signer with broken file.") } } func TestNewAuthHandlerWithNonAuthProfile(t *testing.T) { conf, err := config.LoadConfig([]byte(validLocalConfig)) if err != nil { t.Fatal(err) } _, err = NewAuthHandler(testCaFile, testCaKeyFile, conf.Signing) if err == nil { t.Fatal("No profile have auth keys. Should have failed to create auth sign handler.") } } func TestNewHandlersWithMixedProfile(t *testing.T) { conf, err := config.LoadConfig([]byte(validMixedLocalConfig)) if err != nil { t.Fatal(err) } _, err = NewHandler(testCaFile, testCaKeyFile, conf.Signing) if err != nil { t.Fatal("Should be able to create non-auth sign handler.") } _, err = NewAuthHandler(testCaFile, testCaKeyFile, conf.Signing) if err != nil { t.Fatal("Should be able to create auth sign handler.") } } func TestNewHandlersWithAnotherMixedProfile(t *testing.T) { conf, err := config.LoadConfig([]byte(alsoValidMixedLocalConfig)) if err != nil { t.Fatal(err) } _, err = NewHandler(testCaFile, testCaKeyFile, conf.Signing) if err != nil { t.Fatal("Should be able to create non-auth sign handler.") } _, err = NewAuthHandler(testCaFile, testCaKeyFile, conf.Signing) if err != nil { t.Fatal("Should be able to create auth sign handler.") } } func newSignServer(t *testing.T) *httptest.Server { ts := httptest.NewServer(newTestHandler(t)) return ts } func testSignFileOldInterface(t *testing.T, hostname, csrFile string) (resp *http.Response, body []byte) { ts := newSignServer(t) defer ts.Close() var csrPEM []byte if csrFile != "" { var err error csrPEM, err = os.ReadFile(csrFile) if err != nil { t.Fatal(err) } } obj := map[string]string{} if len(hostname) > 0 { obj["hostname"] = hostname } if len(csrPEM) > 0 { obj["certificate_request"] = string(csrPEM) } blob, err := json.Marshal(obj) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } func testSignFile(t *testing.T, hosts []string, subject *signer.Subject, csrFile string) (resp *http.Response, body []byte) { ts := newSignServer(t) defer ts.Close() var csrPEM []byte if csrFile != "" { var err error csrPEM, err = os.ReadFile(csrFile) if err != nil { t.Fatal(err) } } obj := map[string]interface{}{} if hosts != nil { obj["hosts"] = hosts } if len(csrPEM) > 0 { obj["certificate_request"] = string(csrPEM) } if subject != nil { obj["subject"] = subject } blob, err := json.Marshal(obj) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } const ( testHostName = "localhost" testDomainName = "cloudflare.com" ) type signTest struct { Hosts []string Subject *signer.Subject CSRFile string ExpectedHTTPStatus int ExpectedSuccess bool ExpectedErrorCode int } var signTests = []signTest{ { Hosts: []string{testHostName}, CSRFile: testCSRFile, ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { Hosts: []string{testDomainName}, CSRFile: testCSRFile, ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { Hosts: []string{testDomainName, testHostName}, CSRFile: testCSRFile, ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { Hosts: []string{testDomainName}, Subject: &signer.Subject{CN: "example.com"}, CSRFile: testCSRFile, ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { Hosts: []string{}, Subject: &signer.Subject{CN: "example.com"}, CSRFile: testCSRFile, ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { Hosts: nil, CSRFile: testCSRFile, ExpectedHTTPStatus: http.StatusOK, ExpectedSuccess: true, ExpectedErrorCode: 0, }, { Hosts: []string{testDomainName}, CSRFile: "", ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: http.StatusBadRequest, }, { Hosts: []string{testDomainName}, CSRFile: testBrokenCSRFile, ExpectedHTTPStatus: http.StatusBadRequest, ExpectedSuccess: false, ExpectedErrorCode: 9002, }, } func TestSign(t *testing.T) { for i, test := range signTests { resp, body := testSignFile(t, test.Hosts, test.Subject, test.CSRFile) if resp.StatusCode != test.ExpectedHTTPStatus { t.Logf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode) t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body)) } message := new(api.Response) err := json.Unmarshal(body, message) if err != nil { t.Logf("failed to read response body: %v", err) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess != message.Success { t.Logf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess == true { continue } if test.ExpectedErrorCode != message.Errors[0].Code { t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } } // Test for backward compatibility // TODO remove after API transition is complete. for i, test := range signTests { // an empty hostname is not accepted by the old interface but an empty hosts array should be accepted // so skip the case of empty hosts array for the old interface. if test.Hosts != nil && len(test.Hosts) == 0 { continue } hostname := strings.Join(test.Hosts, ",") resp, body := testSignFileOldInterface(t, hostname, test.CSRFile) if resp.StatusCode != test.ExpectedHTTPStatus { t.Logf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode) t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body)) } message := new(api.Response) err := json.Unmarshal(body, message) if err != nil { t.Logf("failed to read response body: %v", err) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess != message.Success { t.Logf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess == true { continue } if test.ExpectedErrorCode != message.Errors[0].Code { t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } } } func newTestAuthHandler(t *testing.T) http.Handler { conf, err := config.LoadConfig([]byte(validAuthLocalConfig)) if err != nil { t.Fatal(err) } h, err := NewAuthHandler(testCaFile, testCaKeyFile, conf.Signing) if err != nil { t.Fatal(err) } return h } func TestNewAuthHandler(t *testing.T) { newTestAuthHandler(t) } func TestNewAuthHandlerWithNoAuthConfig(t *testing.T) { conf, err := config.LoadConfig([]byte(validLocalConfig)) if err != nil { t.Fatal(err) } _, err = NewAuthHandler(testCaFile, testCaKeyFile, conf.Signing) if err == nil { t.Fatal("Config doesn't have auth keys. Should have failed.") } return } func testAuthSignFile(t *testing.T, hosts []string, subject *signer.Subject, csrFile string, profile *config.SigningProfile) (resp *http.Response, body []byte) { ts := newAuthSignServer(t) defer ts.Close() var csrPEM []byte if csrFile != "" { var err error csrPEM, err = os.ReadFile(csrFile) if err != nil { t.Fatal(err) } } obj := map[string]interface{}{} if hosts != nil { obj["hosts"] = hosts } if subject != nil { obj["subject"] = subject } if len(csrPEM) > 0 { obj["certificate_request"] = string(csrPEM) } reqBlob, err := json.Marshal(obj) if err != nil { t.Fatal(err) } var aReq auth.AuthenticatedRequest aReq.Request = reqBlob aReq.Token, err = profile.Provider.Token(aReq.Request) if err != nil { t.Fatal(err) } blob, err := json.Marshal(aReq) if err != nil { t.Fatal(err) } resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } return } func newAuthSignServer(t *testing.T) *httptest.Server { ts := httptest.NewServer(newTestAuthHandler(t)) return ts } func TestAuthSign(t *testing.T) { conf, err := config.LoadConfig([]byte(validAuthLocalConfig)) if err != nil { t.Fatal(err) } for i, test := range signTests { resp, body := testAuthSignFile(t, test.Hosts, test.Subject, test.CSRFile, conf.Signing.Default) if resp.StatusCode != test.ExpectedHTTPStatus { t.Logf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode) t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body)) } message := new(api.Response) err := json.Unmarshal(body, message) if err != nil { t.Logf("failed to read response body: %v", err) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess != message.Success { t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } if test.ExpectedSuccess == true { continue } if test.ExpectedErrorCode != message.Errors[0].Code { t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code) t.Fatal(resp.Status, test.ExpectedHTTPStatus, message) } } } ================================================ FILE: api/signhandler/signhandler.go ================================================ // Package signhandler provides the handlers for signers. package signhandler import ( "encoding/json" "io" "math/big" "net/http" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/auth" "github.com/cloudflare/cfssl/bundler" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer" ) // NoBundlerMessage is used to alert the user that the server does not have a bundler initialized. const NoBundlerMessage = `This request requires a bundler, but one is not initialized for the API server.` // A Handler accepts requests with a hostname and certficate // parameter (which should be PEM-encoded) and returns a new signed // certificate. It includes upstream servers indexed by their // profile name. type Handler struct { signer signer.Signer bundler *bundler.Bundler } // NewHandlerFromSigner generates a new Handler directly from // an existing signer. func NewHandlerFromSigner(signer signer.Signer) (h *api.HTTPHandler, err error) { policy := signer.Policy() if policy == nil { err = errors.New(errors.PolicyError, errors.InvalidPolicy) return } // Sign will only respond for profiles that have no auth provider. // So if all of the profiles require authentication, we return an error. haveUnauth := (policy.Default.Provider == nil) for _, profile := range policy.Profiles { haveUnauth = haveUnauth || (profile.Provider == nil) } if !haveUnauth { err = errors.New(errors.PolicyError, errors.InvalidPolicy) return } return &api.HTTPHandler{ Handler: &Handler{ signer: signer, }, Methods: []string{"POST"}, }, nil } // SetBundler allows injecting an optional Bundler into the Handler. func (h *Handler) SetBundler(caBundleFile, intBundleFile string) (err error) { h.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile) return err } // This type is meant to be unmarshalled from JSON so that there can be a // hostname field in the API // TODO: Change the API such that the normal struct can be used. type jsonSignRequest struct { Hostname string `json:"hostname"` Hosts []string `json:"hosts"` Request string `json:"certificate_request"` Subject *signer.Subject `json:"subject,omitempty"` Profile string `json:"profile"` Label string `json:"label"` Serial *big.Int `json:"serial,omitempty"` Bundle bool `json:"bundle"` } func jsonReqToTrue(js jsonSignRequest) signer.SignRequest { sub := new(signer.Subject) if js.Subject == nil { sub = nil } else { // make a copy *sub = *js.Subject } if js.Hostname != "" { return signer.SignRequest{ Hosts: signer.SplitHosts(js.Hostname), Subject: sub, Request: js.Request, Profile: js.Profile, Label: js.Label, Serial: js.Serial, } } return signer.SignRequest{ Hosts: js.Hosts, Subject: sub, Request: js.Request, Profile: js.Profile, Label: js.Label, Serial: js.Serial, } } // Handle responds to requests for the CA to sign the certificate request // present in the "certificate_request" parameter for the host named // in the "hostname" parameter. The certificate should be PEM-encoded. If // provided, subject information from the "subject" parameter will be used // in place of the subject information from the CSR. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { log.Info("signature request received") body, err := io.ReadAll(r.Body) if err != nil { return err } r.Body.Close() var req jsonSignRequest err = json.Unmarshal(body, &req) if err != nil { return errors.NewBadRequestString("Unable to parse sign request") } signReq := jsonReqToTrue(req) if req.Request == "" { return errors.NewBadRequestString("missing parameter 'certificate_request'") } var cert []byte profile, err := signer.Profile(h.signer, req.Profile) if err != nil { return err } if profile.Provider != nil { log.Error("profile requires authentication") return errors.NewBadRequestString("authentication required") } cert, err = h.signer.Sign(signReq) if err != nil { log.Warningf("failed to sign request: %v", err) return err } result := map[string]interface{}{"certificate": string(cert)} if req.Bundle { if h.bundler == nil { return api.SendResponseWithMessage(w, result, NoBundlerMessage, errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode) } bundle, err := h.bundler.BundleFromPEMorDER(cert, nil, bundler.Optimal, "") if err != nil { return err } result["bundle"] = bundle } log.Info("wrote response") return api.SendResponse(w, result) } // An AuthHandler verifies and signs incoming signature requests. type AuthHandler struct { signer signer.Signer bundler *bundler.Bundler } // NewAuthHandlerFromSigner creates a new AuthHandler from the signer // that is passed in. func NewAuthHandlerFromSigner(signer signer.Signer) (http.Handler, error) { policy := signer.Policy() if policy == nil { return nil, errors.New(errors.PolicyError, errors.InvalidPolicy) } if policy.Default == nil && policy.Profiles == nil { return nil, errors.New(errors.PolicyError, errors.InvalidPolicy) } // AuthSign will not respond for profiles that have no auth provider. // So if there are no profiles with auth providers in this policy, // we return an error. haveAuth := (policy.Default.Provider != nil) for _, profile := range policy.Profiles { if haveAuth { break } haveAuth = (profile.Provider != nil) } if !haveAuth { return nil, errors.New(errors.PolicyError, errors.InvalidPolicy) } return &api.HTTPHandler{ Handler: &AuthHandler{ signer: signer, }, Methods: []string{"POST"}, }, nil } // SetBundler allows injecting an optional Bundler into the Handler. func (h *AuthHandler) SetBundler(caBundleFile, intBundleFile string) (err error) { h.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile) return err } // Handle receives the incoming request, validates it, and processes it. func (h *AuthHandler) Handle(w http.ResponseWriter, r *http.Request) error { log.Info("signature request received") body, err := io.ReadAll(r.Body) if err != nil { log.Errorf("failed to read response body: %v", err) return err } r.Body.Close() var aReq auth.AuthenticatedRequest err = json.Unmarshal(body, &aReq) if err != nil { log.Errorf("failed to unmarshal authenticated request: %v", err) return errors.NewBadRequest(err) } var req jsonSignRequest err = json.Unmarshal(aReq.Request, &req) if err != nil { log.Errorf("failed to unmarshal request from authenticated request: %v", err) return errors.NewBadRequestString("Unable to parse authenticated sign request") } // Sanity checks to ensure that we have a valid policy. This // should have been checked in NewAuthHandler. policy := h.signer.Policy() if policy == nil { log.Critical("signer was initialised without a signing policy") return errors.NewBadRequestString("invalid policy") } profile, err := signer.Profile(h.signer, req.Profile) if err != nil { return err } if profile.Provider == nil { log.Error("profile has no authentication provider") return errors.NewBadRequestString("no authentication provider") } validAuth := false if profile.Provider.Verify(&aReq) { validAuth = true } else if profile.PrevProvider != nil && profile.PrevProvider.Verify(&aReq) { validAuth = true } if !validAuth { log.Warning("received authenticated request with invalid token") return errors.NewBadRequestString("invalid token") } signReq := jsonReqToTrue(req) if signReq.Request == "" { return errors.NewBadRequestString("missing parameter 'certificate_request'") } cert, err := h.signer.Sign(signReq) if err != nil { log.Errorf("signature failed: %v", err) return err } result := map[string]interface{}{"certificate": string(cert)} if req.Bundle { if h.bundler == nil { return api.SendResponseWithMessage(w, result, NoBundlerMessage, errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode) } bundle, err := h.bundler.BundleFromPEMorDER(cert, nil, bundler.Optimal, "") if err != nil { return err } result["bundle"] = bundle } log.Info("wrote response") return api.SendResponse(w, result) } ================================================ FILE: api/signhandler/signhandler_test.go ================================================ package signhandler import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "os" "testing" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/local" ) const ( testCaFile = "../testdata/ca.pem" testCaKeyFile = "../testdata/ca_key.pem" testCSRFile = "../testdata/csr.pem" ) // GetUnexpiredCertificates sometimes doesn't return a certificate with an // expiry of 1m as above var validLocalConfigLongerExpiry = ` { "signing": { "default": { "usages": ["digital signature", "email protection"], "expiry": "10m" } } }` var dbAccessor certdb.Accessor func TestSignerDBPersistence(t *testing.T) { conf, err := config.LoadConfig([]byte(validLocalConfigLongerExpiry)) if err != nil { t.Fatal(err) } var s *local.Signer s, err = local.NewSignerFromFile(testCaFile, testCaKeyFile, conf.Signing) if err != nil { t.Fatal(err) } db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") if err != nil { t.Fatal(err) } dbAccessor = sql.NewAccessor(db) s.SetDBAccessor(dbAccessor) var handler *api.HTTPHandler handler, err = NewHandlerFromSigner(signer.Signer(s)) if err != nil { t.Fatal(err) } ts := httptest.NewServer(handler) defer ts.Close() var csrPEM, body []byte csrPEM, err = os.ReadFile(testCSRFile) if err != nil { t.Fatal(err) } blob, err := json.Marshal(&map[string]string{"certificate_request": string(csrPEM)}) if err != nil { t.Fatal(err) } var resp *http.Response resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } if resp.StatusCode != http.StatusOK { t.Fatal(resp.Status, string(body)) } message := new(api.Response) err = json.Unmarshal(body, message) if err != nil { t.Fatalf("failed to read response body: %v", err) } if !message.Success { t.Fatal("API operation failed") } crs, err := dbAccessor.GetUnexpiredCertificates() if err != nil { t.Fatal("Failed to get unexpired certificates") } if len(crs) != 1 { t.Fatal("Expected 1 unexpired certificate in the database after signing 1: len(crs)=", len(crs)) } } ================================================ FILE: api/testdata/broken.pem ================================================ -----BEGIN CERTIFICATE----- MIICATCCAWoCCQDidF+uNJR6czANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB cyBQdHkgTHRkMB4XDTEyMDUwMTIyNTUxN1oXDTEzMDUwMTIyNTUxN1owRTELMAkG A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81 IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt +LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw== -----END CERTIFICATE----- ================================================ FILE: api/testdata/broken_csr.pem ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIFGzCCAwUCAQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJl LWludGVyLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOUKdX6+ PSxU/LxKocsCUj7HCc+FaDOPZV68Po3PVm7UF5DmbnLgJYJ/4aZEZM/v5r8LnXQX DqumYicHQ2DHHBDasLTx8m0KeKOUYf9WMQ8gdjmVFoCiZwzxGDHok66/0Glkkqmv 2nJQxXncl5ZFta4sfmcQx3KT02l61LaBbG3j8PbRCWEr+0eRE6twuYRR13AgZ3AT wnMjzxzvsW67qmAy0cq+XgYYfTK9vhPs+8J0fxXa0Iftu3yuhd30xLIVXLu45GR+ i6KnsSxVERSaVxjkS+lHXjUpdtmqI5CK6wn67vqYRRA2TzAJHX8Jb+KL2/UEo5WN fAJ8S0heODQA8nHVU1JIfpegOlQRMv55DgnQUv1c1uwO5hqvv7MPQ3X/m9Kjccs1 FBH1/SVuzKyxYEQ34LErX3HI+6avbVnRtTR/UHkfnZVIXSrcjUm73BGj33hrtiKl 0ZyZnaUKGZPuvebOUFNiXemhTbqrfi/zAb1Tsm/h+xkn5EZ5sMj5NHdAbpih3TqX 2gRhnFZcFjtJM6zzC5O7eG5Kdqf8iladXTXtWxzrUPkb5CupzFl1dyS3dqdkoIXv kmlScnu+6jBOaYeVvwogxr2Y69y4Zfg/qbPyBOLZquX9ovbuSP1DQmC//LV5t7YH HY/1MXr5U0MMvcn+9JWUV6ou3at4AgEqfK0vAgMBAAGgSzBJBgkqhkiG9w0BCQ4x PDA6MDgGA1UdEQQxMC+CFGNsb3VkZmxhcmUtaW50ZXIuY29tghd3d3djbG91ZGZs YXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQ0DggIBAHtSt/v+IHQmSK5UiQWwjRWA ZezIWVlJuselW8DEPNHzDtnraVhjPSFP995Cqh9fc89kx2Bt9hDhjNteTB+pJW6B aCRRZygJ6/m3Ii1XqTFgfEJBWwuIX1Req0PCW/ayegdLzzYbSZ31wRICCveBQyGw vRtzIBUeMvz9MgLJ8zx7eN7fDhrvy+Y1SkC4g0sAQTYYfM9P/He4k5hx79hmd2YC mUDAlNZV0g0dY0qR4cITmhniIFW5iZBplY7DmqooUXrj5yEga2QMj/RA16lPzHbz 7ceUlcH2L6/V6zMR/rfCiGRoWInxWSuuJhLIVLmoEo0590w6KVEZifHxsRpl4l09 imvzwTSQGIrY8jF9AxOD0rRA9wXCT9h8XtBWyJZ1/DmzJG8+7oZ/HdE9XhzwNujD Q6lBOj+dznju7k/snYCZVq501JLPeql8vQrq0O/xSqSK4yN1IG4NisZeDK2BZEOy QhnKXodIKf+zXnFw86lZ/ZwHQFr6jOSxmbrZ2OiY34m7Yd9oeIaMPviysRih2x4Q O6DFz72f97+xFZuXIbmn8DPQV8U9bk/gbrfUCPnx/icS8UoPsBKc9Gio0FZO4+8A 4/ac3oeN0zy/WjsBP+J50CRUXMrRI9KO+/bI4pcT14B31YbuSo6ygIkIkj7YDh36 +4ZG6HnUPQI8HteF9hzp=BROKEN== -----END CERTIFICATE REQUEST----- ================================================ FILE: api/testdata/ca-bundle.pem ================================================ -----BEGIN CERTIFICATE----- MIIC1jCCAj+gAwIBAgIUJhxh1ENJRZoFuCN+XB0xlP1zgeYwDQYJKoZIhvcNAQEL BQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxhcmUxFDASBgNVBAsMC0RF Vl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NBMB4XDTI1MDIwODIwMTYy N1oXDTM1MDIwNjIwMTYyN1owfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm b3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxh cmUxFDASBgNVBAsMC0RFVl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NB MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbp/6OQ/a3mr+8zRgBRlmSGr8Q BgP4vUIxLn2Mk4uiZ8OcpRY4YqL+TtREGDUc0ve+bv8RINrNlYXL2X+eJtbE2RJQ +RAiu+saw2K+RFTNeTCA1fwg3ws5gBDcFbECqK1dOkuN/gV4JMHobn2/15iUBfeS JxdF1j5yqES8sVu7cwIDAQABo1MwUTAdBgNVHQ4EFgQUuF7vrmdQt9bzB+VqvlWz ZzoNkj4wHwYDVR0jBBgwFoAUuF7vrmdQt9bzB+VqvlWzZzoNkj4wDwYDVR0TAQH/ BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQALmrNPUPlCyhabvgC8RsMZPhJjtxr9 TotLuoa49zsHH18djRZLrm8mNzBwUVVNJ1hgwSpRnyrc7T4HQTTvjpCnyXEVRil/ 9HQbpVPBSw5W6oK3koLG0rFnZXHocqK+Qri4FkbwsTK5qlea35OJWkODiUY/ykVM E4sm6QDE79e0Iw== -----END CERTIFICATE----- ================================================ FILE: api/testdata/ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIEmzCCA4OgAwIBAgIMAMSvNBgypwaaSQ5iMA0GCSqGSIb3DQEBBQUAMIGMMQsw CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy YW5jaXNjbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVT VCBSb290IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTIx MjEyMDIxMDMxWhcNMjIxMDIxMDIxMDMxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNV BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoT CkNGU1NMIFRFU1QxGzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqG SIb3DQEJARYPdGVzdEB0ZXN0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsRp1xSfIDoD/40Bo4Hls3sFn4dav5NgxbZGpVyGF7dJI9u0eEnL4 BUGssPaUFLWC83CZxujUEiEfE0oKX+uOhhGv3+j5xSTNM764m2eSiN53cdZtK05d hwq9uS8LtjKOQeN1mQ5qmiqxBMdjkKgMsVw5lMCgoYKo57kaKFyXzdpNVDzqw+pt HWmuNtDQjK3qT5Ma06mYPmIGYhIZYLY7oJGg9ZEaNR0GIw4zIT5JRsNiaSb5wTLw aa0n/4vLJyVjLJcYmJBvZWj8g+taK+C4INu/jGux+bmsC9hq14tbOaTNAn/NE0qN 8oHwcRBEqfOdEYdZkxI5NWPiKNW/Q+AeXQIDAQABo4H6MIH3MB0GA1UdDgQWBBS3 0veEuqg51fusEM4p/YuWpBPsvTCBxAYDVR0jBIG8MIG5gBS30veEuqg51fusEM4p /YuWpBPsvaGBkqSBjzCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju aWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkNGU1NMIFRFU1Qx GzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqGSIb3DQEJARYPdGVz dEB0ZXN0LmxvY2FsggwAxK80GDKnBppJDmIwDwYDVR0TBAgwBgEB/wIBADANBgkq hkiG9w0BAQUFAAOCAQEAJ7r1EZYDwed6rS0+YKHdkRGRQ5Rz6A9DIVBPXrSMAGj3 F5EF2m/GJbhpVbnNJTVlgP9DDyabOZNxzdrCr4cHMkYYnocDdgAodnkw6GZ/GJTc depbVTR4TpihFNzeDEGJePrEwM1DouGswpu97jyuCYZ3z1a60+a+3C1GwWaJ7Aet Uqm+yLTUrMISsfnDPqJdM1NeqW3jiZ4IgcqJkieCCSpag9Xuzrp9q6rjmePvlQkv qz020JGg6VijJ+c6Tf5y0XqbAhkBTqYtVamu9gEth9utn12EhdNjTZMPKMjjgFUd H0N6yOEuQMl4ky7RxZBM0iPyeob6i4z2LEQilgv9MQ== -----END CERTIFICATE----- ================================================ FILE: api/testdata/ca2-key.pem ================================================ -----BEGIN EC PRIVATE KEY----- MHcCAQEEILOI+Ox7VUA+HaiOuAbBtf1IOXffEsOoI/443rTOPzD5oAoGCCqGSM49 AwEHoUQDQgAEoY1dLpXLl1bN5p8GFqOKrYu8C7QF0OLCMlfoiJInE6XI+PKlxXx+ KlwasHd9zxV1HA4YtHifkrAL9u0CvrbdOg== -----END EC PRIVATE KEY----- ================================================ FILE: api/testdata/ca2.pem ================================================ -----BEGIN CERTIFICATE----- MIICYjCCAgigAwIBAgIIB/ijVOdMMDMwCgYIKoZIzj0EAwIwgYIxCzAJBgNVBAYT AlVTMRUwEwYDVQQKEwxDRlNTTCBURVNUIDIxGzAZBgNVBAsTEkNGU1NMIFRlc3Qg Um9vdCBDQTETMBEGA1UEBxMKQ2FsaWZvcm5pYTETMBEGA1UECBMKQ2FsaWZvcm5p YTEVMBMGA1UEAxMMQ0ZTU0wgVEVTVCAyMB4XDTE1MDQwNjIzNTkwMFoXDTIwMDQw NDIzNTkwMFowgYIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxDRlNTTCBURVNUIDIx GzAZBgNVBAsTEkNGU1NMIFRlc3QgUm9vdCBDQTETMBEGA1UEBxMKQ2FsaWZvcm5p YTETMBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEAxMMQ0ZTU0wgVEVTVCAyMFkw EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoY1dLpXLl1bN5p8GFqOKrYu8C7QF0OLC MlfoiJInE6XI+PKlxXx+KlwasHd9zxV1HA4YtHifkrAL9u0CvrbdOqNmMGQwDgYD VR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFGNz0lWe 3YnOP5PykkQ+ZVcHCZp2MB8GA1UdIwQYMBaAFGNz0lWe3YnOP5PykkQ+ZVcHCZp2 MAoGCCqGSM49BAMCA0gAMEUCIQCuxcZqp9vyJ8mH9eFS9cvMAbTildshZJYn7QB6 8WDscAIga1np4tMDrsIynHrmYI1GnD/TgmUi4ElBNoyUnob+B+U= -----END CERTIFICATE----- ================================================ FILE: api/testdata/ca_key.pem ================================================ -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGnXFJ8gOgP/j QGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLzcJnG6NQSIR8T Sgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B43WZDmqaKrEE x2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepPkxrTqZg+YgZi EhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMslxiYkG9laPyD 61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850Rh1mTEjk1Y+Io 1b9D4B5dAgMBAAECggEAKHhjcSomDSptTwDo9mLI/h40HudwSlsc8GzYxZBjinUD N2n39T9QbeMUE1xFenX/9qFEgq+xxnLLJx1EQacSapCgIAqdCO/f9HMgvGJumdg8 c0cMq1i9Bp7tu+OESZ5D48qWlOM2eQRIb08g8W11eRIaFmPuUPoKnuktkQuXpPJc YbS/+JuA8SDwe6sV0cMCQuS+iHFfeGwWCKrDUkhLwcL3waW3od2XFyOeFFWFhl0h HmM/mWKRuRdqR7hrmArTwFZVkB+o/1ywVYXIv+JQm0eNZ5PKLNJGL2f5oxbMR/JI AoK0bAlJmYaFp96h1KpbPwLEL/0hHSWA7sAyJIgQAQKBgQDaEAZor/w4ZUTekT1+ cbId0yA+ikDXQOfXaNCSh9Pex+Psjd5zVVOqyVFJ29daRju3d7rmpN4Cm5V4h0l1 /2ad207rjCAnpCHtaddJWNyJzF2IL2IaoCZQRp0k7zOjBGQpoWDTwBaEin5CCv3P kkdQkKz6FDP1xskHSLZr21/QCQKBgQDP6jXutEgGjf3yKpMFk/69EamJdon8clbt hl7cOyWtobnZhdOWVZPe00Oo3Jag2aWgFFsm3EtwnUCnR4d4+fXRKS2LkhfIUZcz cKy17Ileggdd8UGhL4RDrF/En9tJL86WcVkcoOrqLcGB2FLWrVhVpHFK74eLMCH/ uc/+ioPItQKBgHYoDsD08s7AGMQcoNx90MyWVLduhFnegoFW+wUa8jOZzieka6/E wVQeR5yksZjpy3vLNYu6M83n7eLkM2rrm/fXGHlLcTTpm7SgEBZfPwivotKjEh5p PrlqucWEk082lutz1RqHz+u7e1Rfzk2F7nx6GDBdeBYpw03eGXJx6QW5AoGBAIJq 4puyAEAET1fZNtHX7IGCk7sDXTi6LCbgE57HhzHr8V0t4fQ6CABMuvMwM1gATjEk s6yjoLqqGUUUzDipanViBAy5fiuManC868lN7zkWDTLzQ3ytBqVAee4na/DziP27 ae9YTSLJwskE/alloLRP6zTbHUXE0n7LelmrX1DFAoGBAMFLl+Lu+WFgCHxBjn43 rHpJbQZQmsFhAMhkN4hsj6dJfAGn2gRLRiVRAika+8QF65xMZiVQWUVSUZADWERi 0SXGjzN1wYxO3Qzy3LYwws6fxFAq5lo79eb38yFT2lHdqK3x/QgiDSRVl+R6cExV xQB518/lp2eIeMpglWByDwJX -----END PRIVATE KEY----- ================================================ FILE: api/testdata/cert.pem ================================================ -----BEGIN CERTIFICATE----- MIIB7jCCAVmgAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTEyMDkwNzIyMDAwNFoXDTEzMDkwNzIy MDUwNFowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGd MAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1C MS59jJOLomfDnKUWOGKi/k7URBg1HNL3vm7/ESDazZWFy9l/nibWxNkSUPkQIrvr GsNivkRUzXkwgNX8IN8LOYAQ3BWxAqitXTpLjf4FeCTB6G59v9eYlAX3kicXRdY+ cqhEvLFbu3MCAwEAAaMyMDAwDgYDVR0PAQH/BAQDAgCgMA0GA1UdDgQGBAQBAgME MA8GA1UdIwQIMAaABAECAwQwCwYJKoZIhvcNAQEFA4GBABndWRIcfi+QB9Sakr+m dYnXTgYCnFio53L2Z+6EHTGG+rEhWtUEGhL4p4pzXX4siAnjWvwcgXTo92cafcfi uB7wRfK+NL9CTJdpN6cdL+fiNHzH8hsl3bj1nL0CSmdn2hkUWVLbLhSgWlib/I8O aq+K7aVrgHkPnWeRiG6tl+ZA -----END CERTIFICATE----- ================================================ FILE: api/testdata/csr.pem ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIB0jCCAVcCAQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJl LWludGVyLmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABCFZIzSRsH9xdF1iR+8k ElbcbqAYnYuSTbEOxYcREHGRJd2/v9YhetEwWNmIuisCbgOpyBO9zyFxsnzYU4cO A/AomW2nJEP7n4M9g8r8clhQz8y6+013jP9MEqf4pqMVnqBLMEkGCSqGSIb3DQEJ DjE8MDowOAYDVR0RBDEwL4IUY2xvdWRmbGFyZS1pbnRlci5jb22CF3d3d2Nsb3Vk ZmxhcmUtaW50ZXIuY29tMAoGCCqGSM49BAMDA2kAMGYCMQD6kSGGc3/DeFAWrPUX qSlnTTm57DpzUoHQE306DfbFB6DFfoORNM5Z98chnZ+Ell4CMQCzYhOvIh3+GPGF MuYYIAfQV2JG+n7pjfpJ+X1Ee2bOtA4ZO39P9/FTEtJUXt+Ivqw= -----END CERTIFICATE REQUEST----- ================================================ FILE: api/testdata/int-bundle.pem ================================================ -----BEGIN CERTIFICATE----- MIIEfzCCA+igAwIBAgIUEvxiFE387bDlHt8NSYEYLPYpJwIwDQYJKoZIhvcNAQEF BQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxhcmUxFDASBgNVBAsMC0RF Vl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NBMCAXDTE2MDIxODA1MjUw MFoYDzIxMTYwMTI1MDUyNTAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNs b3VkZmxhcmUtaW50ZXIuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC AgEA5Qp1fr49LFT8vEqhywJSPscJz4VoM49lXrw+jc9WbtQXkOZucuAlgn/hpkRk z+/mvwuddBcOq6ZiJwdDYMccENqwtPHybQp4o5Rh/1YxDyB2OZUWgKJnDPEYMeiT rr/QaWSSqa/aclDFedyXlkW1rix+ZxDHcpPTaXrUtoFsbePw9tEJYSv7R5ETq3C5 hFHXcCBncBPCcyPPHO+xbruqYDLRyr5eBhh9Mr2+E+z7wnR/FdrQh+27fK6F3fTE shVcu7jkZH6LoqexLFURFJpXGORL6UdeNSl22aojkIrrCfru+phFEDZPMAkdfwlv 4ovb9QSjlY18AnxLSF44NADycdVTUkh+l6A6VBEy/nkOCdBS/VzW7A7mGq+/sw9D df+b0qNxyzUUEfX9JW7MrLFgRDfgsStfccj7pq9tWdG1NH9QeR+dlUhdKtyNSbvc EaPfeGu2IqXRnJmdpQoZk+695s5QU2Jd6aFNuqt+L/MBvVOyb+H7GSfkRnmwyPk0 d0BumKHdOpfaBGGcVlwWO0kzrPMLk7t4bkp2p/yKVp1dNe1bHOtQ+RvkK6nMWXV3 JLd2p2Sghe+SaVJye77qME5ph5W/CiDGvZjr3Lhl+D+ps/IE4tmq5f2i9u5I/UNC YL/8tXm3tgcdj/UxevlTQwy9yf70lZRXqi7dq3gCASp8rS8CAwEAAaNmMGQwDgYD VR0PAQH/BAQDAgIEMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFIhguhik d7hBBBvV73dRwlsUuiA/MB8GA1UdIwQYMBaAFLhe765nULfW8wflar5Vs2c6DZI+ MA0GCSqGSIb3DQEBBQUAA4GBAGIW4csKSyGxYuYUQKtPDVjsy+/bD4cLVm78rO/r Qo5IjkaYvN/R6Y0OWgOLPHaxWfC8TRyyrW8cBZBbUcEhFIm9JCGRU5qctqWGdBo4 X1M9WCQXr7RS0WVEnn+h83Giot5hdOktSNqCO1QuZBxlLUqZEhnA1XnZEEDG/YWi 9JCk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYDCCAkigAwIBAgIUGkS6ZR3pGG1whBdM98/+hASRNpEwDQYJKoZIhvcNAQEN BQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQL ExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMw EQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNv bTAeFw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGMMQswCQYDVQQGEwJV UzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmlu ZzEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wdjAQBgcqhkjOPQIBBgUr gQQAIgNiAAQhWSM0kbB/cXRdYkfvJBJW3G6gGJ2Lkk2xDsWHERBxkSXdv7/WIXrR MFjZiLorAm4DqcgTvc8hcbJ82FOHDgPwKJltpyRD+5+DPYPK/HJYUM/MuvtNd4z/ TBKn+KajFZ6jZjBkMA4GA1UdDwEB/wQEAwICpDASBgNVHRMBAf8ECDAGAQH/AgEB MB0GA1UdDgQWBBQ939xYhpjoyikg7qV0rHv10ukXVzAfBgNVHSMEGDAWgBSIYLoY pHe4QQQb1e93UcJbFLogPzANBgkqhkiG9w0BAQ0FAAOCAgEAr3FzjsRoTUo5WocP xpUaeS5PPIY5uBmMZQU+JQuCzBTGwAONkzwEZUMHW9SNrD9g7qcWouy+1t4Sz6dJ iKa+6vvo60bJvINELLnbu5Z+t99f7R3PAdcIccQVxPIFxKKq6HYhgDx+jOvCTuGA TXIL9vkYL8rR/9YmMJBp6Re4+sWq97kzRJt7zIU4+pL/3Inx8KUuXlh8K/aa4ShY yRIeAYixnGjDQ8YMVLFyjVeg0wiv+qAkgomi81hts7DUhawzMRC81A6oIwvWNBfB 2CUijERzpBjxmMZwaUOj6yKhGbigt7lxvcSkzJZTJ4s+HE05k9OYnJ8+PF+mo3uS nG2dg/NqIipdh8/9fvHubW3QL7cwbaI7T0lVYkopNkL8TP7gOZjkeNCTvhHun4+7 apjbFeylj8kkTaL6+6Y+7JLGmsD8amuy45Qu/NKqIZyYF/vxBSqi3w2Rm8IwYvQ7 ci2jN+RJvPQVy2hioXyOUzoyBED7GhZjV59i7N62clQ8+g3gxjxF5/lYU6Ok3UEg a6JLchBWgq0y/M4cGtidJCGWdLZAldQtnRb7qj0yt64byy+SECZHHlKroGARu0qv osbE6riZvhmUlnrBDS02LGwG0dni21iERJu56I8ltHaJsZUIu4jOEUBENQwIAULo ZPYOEUU9GGgoGpUdqNtpfZZWmvw= -----END CERTIFICATE----- ================================================ FILE: api/testdata/leaf.badkey ================================================ -----BEGIN RSA PRIVATE KEY----- MIIG5AIBAAKCAYEA9xYBDoV2tPx8lqZ/bH/wLvoPsg1/CXeknvRcNuxw1gu6c3IJ BrKZlkFtiU6Y8FADiUBOVab/Y0cQ/9EdeB2srPH4M5KNiPdWZPgxARWnRq5Ez8pv VASP2E2Zya1UnH5iJBau8e6SwBl8UaXnGwcA+CUv+FXcZtdoFh0Lqt3AdItQOkHV jSE6Cfiv5lsSW0ikMcoHFOHNps4/9A4A/griT5lRDqQIycN7WD2k4+aKVreCWxbS teU35yIDJV6PGUtw8k41arJ+kwuwYM3+YklR0Dsj0RxXn07oLqnf6IeNUogGhNVO 7RvLdpfvrhlevHVXmmYj40fkGjU15KkZOKigMw/gDInI6Sc2jp8oPX9tjkaQYkF2 t7AWOq01lh5TleMIoBFUqVcy+X/qejla0JaKCEyt/fiPUo7/SgucyFl8GrKfSdEL UOKx5Vr2ZZ48QSfIlXle+tGtFD0AYUsO0ud0wclW5C+g8E27raTuR4RaZOj8/pmB 7XNDszwxQ/97dBRpAgMBAAECggGAcWoWPhYg8N5cScJPBvyKwOVjQvVS9IOIerXr hgJtoLJteQRFBGACg6ewobAEH3p6xQtRaZtn6qf6M5JHFpV4Z0ICDZodgVsWuu35 gGfyCk1/pGllRIl7hWvJRXtcNSEF507KKp65mZeZKtkeBZfnZ/+Zz0GKE2KYkl3u txVme5he0P7bCRbRTzZpdzEicegcBgaXzYwAG6rcTCgJaJKSYrsbK787kXE7MrvI 7hsqMLe3DByjx35ZdKx2CTcoNBId9RODWnPpANVrlNv7kbaZRqd5OI8b7JfblFsq F6vCzvDq+Quc8ID1zxRZv761pexejtDzghgQy7X2EVvMlHh4//wErgq6WfPjwyvU /zZczO0L/c1XwwkfBU6Yf6UuYCKngwifgvb7aGU4/aGNcD5SHRITwCHK/E9JrkR8 pkqerMxsf9uP5FxGdwOm1k77Lkap7Kx2Utt5l7stOY0fFUFz1YQdAHJUzhmbP3Zy C+TeX2/9+CudXM1parW7HQRlZeMJAoHBAP545khACfRvUWpxdQohp1Ol0FuDosYg NC75q12T8ovllx8Qly3aafJdd0NTvFmrBkBPTL3pCUWCyGZh6/E00fUL4dtD3zwz QUbm6hWGTgKHdeLLdae2wxcZ/NqmTvpY9o/p4jS9+StRKQtdsftLKCmRv7wfYkju UT7O+gRyGat/Rqpr9cTSKBXHUT+WJlITDrwk5QdydF7eKzLT8DROgcRRE1+FMJkj pO5ChuAxZr0Q0fISRm9Lu7aJ3H8QFfboGwKBwQD4kcCkZvRdz8BQsOsyHQ3SlGhx 5nwA7SPadXtfnpoW0ZlEdHwkPJzU1Z50z1ulEQymBTARPUQ4s28MQt8NXuRzHBrW PMUGgsspzT6FjiskhUc8k9PAZbEJE/axLKK2qSKktGuZj+VFih/9XPPTX4xSzlOg ntJEr2tc3TIv+JEOuJX6VT2URFLXgdOHXxAejS0DTGIg1aB4VGQpWzfbcJ6Cyf11 YyoyYWA25wdw7sB9kDHsd0Ej0mld5+l8JOd8hcsCgcA9jCpOcUa3GzF66EQhljAt WB6D89urxeA5OGPNN1pjob0iY1XdXkVfvGF7JEaa/XV+mm96Q2HdsRsdQDPb3CWn +h6/dLQKkG8KYhFd8WTu0aqelw026kpXTQ7OJ4lUna3M8wmmLgiVBIVD3X6NxAjL vRe9vW19LD70TQVFi/9PbnI+B+yilR3i3pl1IrDUCw32TYojefhRdbTHD2G6lP5n 6CAia0ls0KU0h1yt3uT1d5r/zJHCm3OkW8W76b0WQd8CgcEAh0czk4WgiomtPXz7 k3tycV9pdEuewxZMQ/FaIpD7hV2uzy2h/kqqg756jVHoq24a9yOtpEQ2o7Erx32B TRKOvALYrC3IgKGgFfDojODxo9+RBGvjezsc3TbrNEN5jnWAMCkswhcpDO5+OHJl FG1UviAiLTEieFUL1i9fx/G8aEmW/fV0HQQOHdE/INZgvG/Sxo/Ee+AnhDVRiZxm StwAuGdbtI4ygday+U5Eo3acdfmK4gmI/wjdZUj4riKbhQ5/AoHBAI0yzo+PIFi6 HjNYVoC7rZ39oQ0YCrEWrui+DRdEjnjec31Jw02AtKnv5swpDDHjgnIcd9ciQY48 rk7eC6IkVrL9hOxUzC9YQZX/2MBiOLjUkDkSLt+d5PL0OXiSg1O4fGJdGiVPF0Fc sF9p1UNEfGvXjzUB3ay0kMyCLitNe1BCvJlYXdSV9YmAMNvguE7TNU3OPiVv65PK 6OndznX41Pw7OlnLaq1sFQcYBmf5E7QSKYP+4HeV89Sc824VlCNxwA== -----END RSA PRIVATE KEY----- ================================================ FILE: api/testdata/leaf.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA0C6SSsXfuse2IV8+6hSYqSPQdoQwZ5BYQnSxuKylArCrMXx8 JGHrJP6Pj7GxRmH40v9u9VwZvcrQOm8yUTuzAEf2Kd3uvXmVKJb2vc0BopsflpSE OLEuddTSHlHgdVHylqpbzB7ZrmyXXuWTtTFEaGmPVUmWcOBOy6pc/7hZv7HkTjaH LQu/uohic/NjO0oJaaUwds6muwTCNSmMvtvoP51pyQJeuZjYIoWnnu+/DbtZYmH4 4VbHD0U+uSNKLZa4beWqDq5ZDwQvEVkuLqL331awzgIf0a4bhP+uc1kdWXZ8V+8a Bbqtq6g6o9HdrzgNRR+9S3EvEelCrxuWw9FQ3QIDAQABAoIBAQDFQ5vzplQ9lIgM T0g6XpHZk8oww0lqmOhI8HKG33Dsf6N4HNE1WGOMhnpaWrH0U1mH9eqaLE9n/Aob lMpFFyCin42uVlGm0NJ5x7K+Xsex4POpp8kyPxIbLTJ88HCUOrZ39a1OWd1C3jsA /OFdy/VaSsw6sKQRCTsg2amN1o2UibDJYVW47ycv9cwjk/GEzzOSq32a9o6g6Gwd g3ycroIaxhDlGjS5l0IZ/ozhN+AS5dYcPgJRsYD/jTBqTSzIW2ePrcheznoRcgLK bb+UVQC+PZX8kycCcerPbcGc2YcBpZgmIkCj85+ITFt/BhH7+TSH9G7F8LTKAaJg qlYKF14BAoGBAPz8Jx0vAcv/4zIfCckuNy3kVu4PHBTMTBO5+tUg6CZgktRrroiV +Zq1lCuj2/Px3Lx9oaUie52iV5xgmEEax77xa1rVezY1PhGSFmngHqfumUJf8EEB snlAUpwBHvWU9B9OxKOHRrD9Y9ptXcBK30ZHLJT4t5JvbHVrKZF2J82hAoGBANKp ue+dOafhgc1F/ThD2VLuIi6Garf1pqNG3OMugMfieHAmr1RRYWwFErLoijt9dpe9 gXVecUm1KO4/0ZkR+7YDzUSifXvcizaw+XqjrtFerrz+Yao4gZssFnw/sLc2pbWm 1DHWxRnmh6MyHEEiA0KxElgutswhP8GIKN7INOG9AoGAR1sD2Upp8lVBiuCQTQtZ CvutvUXLwN4C00mQw06dzD1PDNU2jFXo6kcu/MQiBQOCJDQ3RLGeNk8U8QmZyDs6 fdPwWNWABEEuOZx/7+sEGo/E8KDIzj0hTuvioRf72H7kAHSiKBG+0asW4AQa/mLf 6R2oKHiipo4BBHluZxXxkiECgYEAuYXnzfH0+LhMi+77VjXKipJVYAvYqDGak2iw 1xH5MA9uabZn6iXRWkQNd6n7MvEHJBMsk6ScuIDmjwt9FwUTW/R1LeC8CfzsTToG O88zAggUczTD5hjlazakhr/AbVmfDh7h+RJferPe+AYFhAbkQDOZKDfbnGIbt+Cl va0rhTECgYAFb38TvJmEIzB1/nZ7sKbFmr2pYgzBqspQcprws6gZlWydd4OoTZiv QzSBDi3tGt07yJuntVlbuI6qejhFMmonGZuntNTvTZMmx2+W/F8EGByfWpLtB9W5 S+tx5/0d4MhOYHlt0EcdC7j881swY9LCrc/EOqg1O4BlTJ5+UJer+Q== -----END RSA PRIVATE KEY----- ================================================ FILE: api/testdata/leaf.pem ================================================ -----BEGIN CERTIFICATE----- MIIDgTCCAwegAwIBAgIUIyiQolnMtXFv0JQk2OTdP28gJ+wwCgYIKoZIzj0EAwMw gYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T YW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0 ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAe Fw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGLMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEG A1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEc MBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBANAukkrF37rHtiFfPuoUmKkj0HaEMGeQWEJ0sbispQKwqzF8 fCRh6yT+j4+xsUZh+NL/bvVcGb3K0DpvMlE7swBH9ind7r15lSiW9r3NAaKbH5aU hDixLnXU0h5R4HVR8paqW8we2a5sl17lk7UxRGhpj1VJlnDgTsuqXP+4Wb+x5E42 hy0Lv7qIYnPzYztKCWmlMHbOprsEwjUpjL7b6D+dackCXrmY2CKFp57vvw27WWJh +OFWxw9FPrkjSi2WuG3lqg6uWQ8ELxFZLi6i999WsM4CH9GuG4T/rnNZHVl2fFfv GgW6rauoOqPR3a84DUUfvUtxLxHpQq8blsPRUN0CAwEAAaN7MHkwDgYDVR0PAQH/ BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFGj8EwH2TRWlwb0GBywqyPxj a3n9MB8GA1UdIwQYMBaAFD3f3FiGmOjKKSDupXSse/XS6RdXMBkGA1UdEQQSMBCC DmNmc3NsLWxlYWYuY29tMAoGCCqGSM49BAMDA2gAMGUCMFZol0PL/HT9mDED5IWr Lxv/dmH5zv6P0ggUjNBo+N2BM/LxiEAUM0o8Ozk7Dr8SuAIxAMQD8FRWdHsvrzE8 ACbAgluce3lTcC2x7BXMPpw3LojAr1+qIKgb++Y+DOs+DROHhA== -----END CERTIFICATE----- ================================================ FILE: auth/auth.go ================================================ // Package auth implements an interface for providing CFSSL // authentication. This is meant to authenticate a client CFSSL to a // remote CFSSL in order to prevent unauthorised use of the signature // capabilities. This package provides both the interface and a // standard HMAC-based implementation. package auth import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" "os" "strings" ) // An AuthenticatedRequest contains a request and authentication // token. The Provider may determine whether to validate the timestamp // and remote address. type AuthenticatedRequest struct { // An Authenticator decides whether to use this field. Timestamp int64 `json:"timestamp,omitempty"` RemoteAddress []byte `json:"remote_address,omitempty"` Token []byte `json:"token"` Request []byte `json:"request"` } // A Provider can generate tokens from a request and verify a // request. The handling of additional authentication data (such as // the IP address) is handled by the concrete type, as is any // serialisation and state-keeping. type Provider interface { Token(req []byte) (token []byte, err error) Verify(aReq *AuthenticatedRequest) bool } // Standard implements an HMAC-SHA-256 authentication provider. It may // be supplied additional data at creation time that will be used as // request || additional-data with the HMAC. type Standard struct { key []byte ad []byte } // New generates a new standard authentication provider from the key // and additional data. The additional data will be used when // generating a new token. func New(key string, ad []byte) (*Standard, error) { if splitKey := strings.SplitN(key, ":", 2); len(splitKey) == 2 { switch splitKey[0] { case "env": key = os.Getenv(splitKey[1]) case "file": data, err := os.ReadFile(splitKey[1]) if err != nil { return nil, err } key = strings.TrimSpace(string(data)) default: return nil, fmt.Errorf("unknown key prefix: %s", splitKey[0]) } } keyBytes, err := hex.DecodeString(key) if err != nil { return nil, err } return &Standard{keyBytes, ad}, nil } // Token generates a new authentication token from the request. func (p Standard) Token(req []byte) (token []byte, err error) { h := hmac.New(sha256.New, p.key) h.Write(req) h.Write(p.ad) return h.Sum(nil), nil } // Verify determines whether an authenticated request is valid. func (p Standard) Verify(ad *AuthenticatedRequest) bool { if ad == nil { return false } // Standard token generation returns no error. token, _ := p.Token(ad.Request) if len(ad.Token) != len(token) { return false } return hmac.Equal(token, ad.Token) } ================================================ FILE: auth/auth_test.go ================================================ package auth import ( "encoding/json" "os" "testing" ) var ( testProvider Provider testProviderAD Provider testKey = "0123456789ABCDEF0123456789ABCDEF" testAD = []byte{1, 2, 3, 4} // IP address 1.2.3.4 ) func TestNew(t *testing.T) { _, err := New("ABC", nil) if err == nil { t.Fatal("expected failure with improperly-hex-encoded key") } testProvider, err = New(testKey, nil) if err != nil { t.Fatalf("%v", err) } testProviderAD, err = New(testKey, testAD) if err != nil { t.Fatalf("%v", err) } } var ( testRequest1A = &AuthenticatedRequest{ Request: []byte(`testing 1 2 3`), } testRequest1B = &AuthenticatedRequest{ Request: []byte(`testing 1 2 3`), } testRequest2 = &AuthenticatedRequest{ Request: []byte(`testing 3 2 1`), } ) // Sanity check: can a newly-generated token be verified? func TestVerifyTrue(t *testing.T) { var err error testRequest1A.Token, err = testProvider.Token(testRequest1A.Request) if err != nil { t.Fatalf("%v", err) } testRequest1B.Token, err = testProviderAD.Token(testRequest1B.Request) if err != nil { t.Fatalf("%v", err) } if !testProvider.Verify(testRequest1A) { t.Fatal("failed to verify request 1A") } if !testProviderAD.Verify(testRequest1B) { t.Fatal("failed to verify request 1B") } } // Sanity check: ensure that additional data is actually used in // verification. func TestVerifyAD(t *testing.T) { if testProvider.Verify(testRequest1B) { t.Fatal("no-AD provider verifies request with AD") } if testProviderAD.Verify(testRequest1A) { t.Fatal("AD provider verifies request without AD") } } // Sanity check: verification fails if tokens are not the same length. func TestTokenLength(t *testing.T) { token := testRequest1A.Token[:] testRequest1A.Token = testRequest1A.Token[1:] if testProvider.Verify(testRequest1A) { t.Fatal("invalid token should not be verified") } testRequest1A.Token = token } // Sanity check: token fails validation if the request is changed. func TestBadRequest(t *testing.T) { testRequest2.Token = testRequest1A.Token if testProvider.Verify(testRequest2) { t.Fatal("bad request should fail verification") } } // Sanity check: a null request should fail to verify. func TestNullRequest(t *testing.T) { if testProvider.Verify(nil) { t.Fatal("null request should fail verification") } } // Sanity check: verify a pre-generated authenticated request. func TestPreGenerated(t *testing.T) { in, err := os.ReadFile("testdata/authrequest.json") if err != nil { t.Fatalf("%v", err) } var req AuthenticatedRequest err = json.Unmarshal(in, &req) if err != nil { t.Fatalf("%v", err) } if !testProvider.Verify(&req) { t.Fatal("failed to verify pre-generated request") } } var bmRequest []byte func TestLoadBenchmarkRequest(t *testing.T) { in, err := os.ReadFile("testdata/request.json") if err != nil { t.Fatalf("%v", err) } bmRequest = in } func BenchmarkToken(b *testing.B) { for i := 0; i < b.N; i++ { _, err := testProvider.Token(bmRequest) if err != nil { b.Fatalf("%v", err) } } } func BenchmarkVerify(b *testing.B) { token, _ := testProvider.Token(bmRequest) req := &AuthenticatedRequest{ Token: token, Request: bmRequest, } b.ResetTimer() for i := 0; i < b.N; i++ { if !testProvider.Verify(req) { b.Fatal("failed to verify request") } } } ================================================ FILE: auth/testdata/authrequest.json ================================================ {"token": "tSU1WTE/322iXrOBfJSQ9/u1dleqpwUmCj1LXYHw07Y=", "request": "ewoJImhvc3RuYW1lIjogImt5bGVpc29tLm5ldCIsCgkicmVxdWVzdCI6ICItLS0tLUJFR0lOIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQoJICAgIE1JSUQwVENDQWpzQ0FRQXdZREVMTUFrR0ExVUVCaE1DVlZNeEVqQVFCZ05WQkFvVENXUnliM0J6YjI1a1pURVEKCSAgICBNQTRHQTFVRUN4TUhRMFl0UTJoaGRERVdNQlFHQTFVRUJ4TU5VMkZ1SUVaeVlXNWphWE5qYnpFVE1CRUdBMVVFCgkgICAgQ0JNS1EyRnNhV1p2Y201cFlUQ0NBYUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0dQQURDQ0FZb0NnZ0dCQU1jQwoJICAgIEdCbDVMVHJla0dGV2hvdGtkYlorUjFNbG9hcld4UXY5alA0QWVrdDhVT2ljeXBIdkZPNnhPdFN3SG8rcjMyaUUKCSAgICBxblM1eXYvMDFQMk1KdXlxbmRuY1RTTXNPbFQvN242N1RNMDB1MDFLLzljL3NvZ0tFS2pseXBsVFA3eUZkRy9jCgkgICAgT3UvOXFLYi9KYWxkMndFTEZZRTZ4cTJSREZ5eHlpWk9CM2c3WjdGeGE1ZDZhZGZHUndaek50VUw0LzhzK0x5aQoJICAgIHFkdzlJMWZrUWQ2MDRwb1pGTjB3clFzNGxmaFdUVWZnMHJIdWg1d2dHS1AzVnpacGJ0OEZiMXZOamZiSHRvaHgKCSAgICBHMlBDVTZKeStEYzFiU2ZVeldjUW5lbnA4NThXNEY4ejdwRjV5YmRuRlIzMTNIam9zcVhuRzI4eklUck9hZE1UCgkgICAgSGFKNnpPaGdFYWZVT1dYT3pqTm9mRkJGYTJJdUNBVCtJVFJZMXRDL2dxcHhHd0gveXVWTjE5Qkc4VXBuMCtIQQoJICAgIGllMm1LQ0hmU0JBS1QvWGU0dW1QZWF4U2JJcVdzVzhjaytkM2I0b3I5Ulp2NWNaUmNUM29pa0p0K1NRRzY5cFcKCSAgICA0T0FiYitBQnNzL05JdXJpNnowZTdERWVJTDV6bXlTSnFkdFlIZE5ZTjcrK3Y5eEJOc0w0SXNVNklFeTMrUUlECgkgICAgQVFBQm9DNHdMQVlKS29aSWh2Y05BUWtPTVI4d0hUQWJCZ05WSFJFRUZEQVNnaEJqWmk1a2NtOXdjMjl1WkdVdQoJICAgIGJtVjBNQXNHQ1NxR1NJYjNEUUVCREFPQ0FZRUFoTUFxQmlySStrMWFVM2xmQUdRaVNtOHl0T3paaWozODloSXIKCSAgICBuVXA4K1duVHVWVGI4WFozL1YrTDlFblRJbUY2dTF3ZWFqWGQzU3VlNDk1NzBMYlltSXV4QmtHcDUwL0JkVUR6CgkgICAgdUI2eHNoaEpXczEySnhVYjkxSW1tMGJUUncyek1xZXdnYTZmdHpaL0FLNG1zeFFBMlVJYmNXWmRzS2J1TTdzbwoJICAgIEpUZlZXOWlPd3FIdC82NFpqNHRCWmY5THpPRHI3a051S0tMbndqaXpIMTg3eGZJSWhkcmpGOFdTN0g5QVBCMU8KCSAgICBTdUVVRGZxaDBTV1IzbHRXdUF1VVdlbzZTS2NIVnVzeS9HNFlFK1BCeXcxZVY3RzRTYmVHNVowbytHT1VVSy9GCgkgICAgYjU1R21XMXhhNExBcnMxQSt6ZUZidkovQkFwc2JVMmI2V1ZtTmE3V3BIejdXWElGT0p1WUpnRWtWS1BKbkt1cwoJICAgIHFxczNGZ1VxejBadjdUSzhtTWlFVEpvWFpzNnpDdk15c1FldTNKL29qZ3RBanZNaHpRYzZQUy9udk90SmRJZysKCSAgICBIMHFYNDlmaHAxQnJZeXNsYWx6UUlGMCtIMHFTVWV5b1V5VjJ3YkxCQUxhcHhNZnZUVmxoTnduYWN0Y0tReHE0CgkgICAgK3dUKzJQVEowYk0vNUFWMFRPMVNQVDBBVmlKaAoJICAgIC0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLSIsCgkicHJvZmlsZSI6ICIiLAoJInJlbW90ZSI6ICIiLAoJImxhYmVsIjogInByaW1hcnkiCn0KCg=="} ================================================ FILE: auth/testdata/request.json ================================================ { "hostname": "kyleisom.net", "request": "-----BEGIN CERTIFICATE REQUEST----- MIID0TCCAjsCAQAwYDELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCWRyb3Bzb25kZTEQ MA4GA1UECxMHQ0YtQ2hhdDEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UE CBMKQ2FsaWZvcm5pYTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAMcC GBl5LTrekGFWhotkdbZ+R1MloarWxQv9jP4Aekt8UOicypHvFO6xOtSwHo+r32iE qnS5yv/01P2MJuyqndncTSMsOlT/7n67TM00u01K/9c/sogKEKjlyplTP7yFdG/c Ou/9qKb/Jald2wELFYE6xq2RDFyxyiZOB3g7Z7Fxa5d6adfGRwZzNtUL4/8s+Lyi qdw9I1fkQd604poZFN0wrQs4lfhWTUfg0rHuh5wgGKP3VzZpbt8Fb1vNjfbHtohx G2PCU6Jy+Dc1bSfUzWcQnenp858W4F8z7pF5ybdnFR313HjosqXnG28zITrOadMT HaJ6zOhgEafUOWXOzjNofFBFa2IuCAT+ITRY1tC/gqpxGwH/yuVN19BG8Upn0+HA ie2mKCHfSBAKT/Xe4umPeaxSbIqWsW8ck+d3b4or9RZv5cZRcT3oikJt+SQG69pW 4OAbb+ABss/NIuri6z0e7DEeIL5zmySJqdtYHdNYN7++v9xBNsL4IsU6IEy3+QID AQABoC4wLAYJKoZIhvcNAQkOMR8wHTAbBgNVHREEFDASghBjZi5kcm9wc29uZGUu bmV0MAsGCSqGSIb3DQEBDAOCAYEAhMAqBirI+k1aU3lfAGQiSm8ytOzZij389hIr nUp8+WnTuVTb8XZ3/V+L9EnTImF6u1weajXd3Sue49570LbYmIuxBkGp50/BdUDz uB6xshhJWs12JxUb91Imm0bTRw2zMqewga6ftzZ/AK4msxQA2UIbcWZdsKbuM7so JTfVW9iOwqHt/64Zj4tBZf9LzODr7kNuKKLnwjizH187xfIIhdrjF8WS7H9APB1O SuEUDfqh0SWR3ltWuAuUWeo6SKcHVusy/G4YE+PByw1eV7G4SbeG5Z0o+GOUUK/F b55GmW1xa4LArs1A+zeFbvJ/BApsbU2b6WVmNa7WpHz7WXIFOJuYJgEkVKPJnKus qqs3FgUqz0Zv7TK8mMiETJoXZs6zCvMysQeu3J/ojgtAjvMhzQc6PS/nvOtJdIg+ H0qX49fhp1BrYyslalzQIF0+H0qSUeyoUyV2wbLBALapxMfvTVlhNwnactcKQxq4 +wT+2PTJ0bM/5AV0TO1SPT0AViJh -----END CERTIFICATE REQUEST-----", "profile": "", "remote": "", "label": "primary" } ================================================ FILE: bundler/bundle.go ================================================ package bundler import ( "bytes" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/json" "encoding/pem" "errors" "fmt" "time" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/helpers/derhelpers" ) // A Bundle contains a certificate and its trust chain. It is intended // to store the most widely applicable chain, with shortness an // explicit goal. type Bundle struct { Chain []*x509.Certificate Cert *x509.Certificate Root *x509.Certificate Key interface{} Issuer *pkix.Name Subject *pkix.Name Expires time.Time LeafExpires time.Time Hostnames []string Status *BundleStatus } // BundleStatus is designated for various status reporting. type BundleStatus struct { // A flag on whether a new bundle is generated IsRebundled bool `json:"rebundled"` // A list of SKIs of expiring certificates ExpiringSKIs []string `json:"expiring_SKIs"` // A list of untrusted root store names Untrusted []string `json:"untrusted_root_stores"` // A list of human readable warning messages based on the bundle status. Messages []string `json:"messages"` // A status code consists of binary flags Code int `json:"code"` } type chain []*x509.Certificate func (c chain) MarshalJSON() ([]byte, error) { var buf bytes.Buffer for _, cert := range c { buf.Write(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})) } ret := bytes.TrimSpace(buf.Bytes()) return json.Marshal(string(ret)) } // PemBlockToString turns a pem.Block into the string encoded form. func PemBlockToString(block *pem.Block) string { if block.Bytes == nil || block.Type == "" { return "" } return string(bytes.TrimSpace(pem.EncodeToMemory(block))) } var typeToName = map[int]string{ 3: "CommonName", 5: "SerialNumber", 6: "Country", 7: "Locality", 8: "Province", 9: "StreetAddress", 10: "Organization", 11: "OrganizationalUnit", 17: "PostalCode", } type names []pkix.AttributeTypeAndValue func (n names) MarshalJSON() ([]byte, error) { var buf bytes.Buffer for _, name := range n { buf.WriteString(fmt.Sprintf("/%s=%s", typeToName[name.Type[3]], name.Value)) } return json.Marshal(buf.String()) } // MarshalJSON serialises the bundle to JSON. The resulting JSON // structure contains the bundle (as a sequence of PEM-encoded // certificates), the certificate, the private key, the size of they // key, the issuer(s), the subject name(s), the expiration, the // hostname(s), the OCSP server, and the signature on the certificate. func (b *Bundle) MarshalJSON() ([]byte, error) { if b == nil || b.Cert == nil { return nil, errors.New("no certificate in bundle") } var keyBytes, rootBytes []byte var keyLength int var keyType, keyString string keyLength = helpers.KeyLength(b.Cert.PublicKey) switch b.Cert.PublicKeyAlgorithm { case x509.ECDSA: keyType = fmt.Sprintf("%d-bit ECDSA", keyLength) case x509.RSA: keyType = fmt.Sprintf("%d-bit RSA", keyLength) case x509.DSA: keyType = "DSA" case x509.Ed25519: keyType = "Ed25519" default: keyType = "Unknown" } switch key := b.Key.(type) { case *rsa.PrivateKey: keyBytes = x509.MarshalPKCS1PrivateKey(key) keyString = PemBlockToString(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyBytes}) case *ecdsa.PrivateKey: keyBytes, _ = x509.MarshalECPrivateKey(key) keyString = PemBlockToString(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes}) case ed25519.PrivateKey: keyBytes, _ = derhelpers.MarshalEd25519PrivateKey(key) keyString = PemBlockToString(&pem.Block{Type: "Ed25519 PRIVATE KEY", Bytes: keyBytes}) case fmt.Stringer: keyString = key.String() } if len(b.Hostnames) == 0 { b.buildHostnames() } var ocspSupport = false if b.Cert.OCSPServer != nil { ocspSupport = true } var crlSupport = false if b.Cert.CRLDistributionPoints != nil { crlSupport = true } if b.Root != nil { rootBytes = b.Root.Raw } return json.Marshal(map[string]interface{}{ "bundle": chain(b.Chain), "root": PemBlockToString(&pem.Block{Type: "CERTIFICATE", Bytes: rootBytes}), "crt": PemBlockToString(&pem.Block{Type: "CERTIFICATE", Bytes: b.Cert.Raw}), "key": keyString, "key_type": keyType, "key_size": keyLength, "issuer": names(b.Issuer.Names), "subject": names(b.Subject.Names), "expires": b.Expires, "leaf_expires": b.LeafExpires, "hostnames": b.Hostnames, "ocsp_support": ocspSupport, "crl_support": crlSupport, "ocsp": b.Cert.OCSPServer, "signature": helpers.SignatureString(b.Cert.SignatureAlgorithm), "status": b.Status, }) } // buildHostnames sets bundle.Hostnames by the x509 cert's subject CN and DNS names // Since the subject CN may overlap with one of the DNS names, it needs to handle // the duplication by a set. func (b *Bundle) buildHostnames() { if b.Cert == nil { return } // hset keeps a set of unique hostnames. hset := make(map[string]bool) // insert CN into hset if b.Cert.Subject.CommonName != "" { hset[b.Cert.Subject.CommonName] = true } // insert all DNS names into hset for _, h := range b.Cert.DNSNames { hset[h] = true } // convert hset to an array of hostnames b.Hostnames = make([]string, len(hset)) i := 0 for h := range hset { b.Hostnames[i] = h i++ } } ================================================ FILE: bundler/bundle_from_file_test.go ================================================ package bundler // This test file contains tests on checking the correctness of BundleFromFile and Bundle. // We simulate various scenarios for Bundle and funnel the tests through BundleFromFile. import ( "encoding/json" "testing" ) // A helper structure that defines a BundleFromFile test case. type fileTest struct { // PEM cert file to be bundled cert string // PEM private key file to be bundled key string // Root CA bundle caBundleFile string // Trust intermediate bundle intBundleFile string // Additional PEM intermediate certificates to be added into the bundler extraIntermediates string // Bundler creation function bundlerConstructor func(*testing.T) (b *Bundler) // Error checking function errorCallback func(*testing.T, error) // Bundle checking function bundleChecking func(*testing.T, *Bundle) } /* ========== BundleFromFile Test Setup ============= For each pair of crypto algorithm X and key size Y, a CA chain is constructed: Test_root_CA -> inter-L1 -> inter-L2--> cfssl-leaf-ecdsa256 |-> cfssl-leaf-ecdsa384 |-> cfssl-leaf-ecdsa521 |-> cfssl-leaf-rsa2048 |-> cfssl-leaf-rsa3072 |-> cfssl-leaf-rsa4096 Test_root_CA is a RSA cert, inter-L1 is RSA 4096 cert, inter-L2 is ecdsa-384 cert. The max path length is set to be 1 for non-root CAs. Two inter-* certs are assembled in intermediates.crt There is also an expired L1 cert, sharing the same CSR with inter-L1. Also the root CA processes the inter-L2 CSR directly to generate inter-L2-direct cert. Test_root_CA--> inter-L1-expired |-> inter-L2-direct Using inter-L2-direct as additional intermediate cert should shorten the bundle chain. */ const ( leafECDSA256 = "testdata/cfssl-leaf-ecdsa256.pem" leafECDSA384 = "testdata/cfssl-leaf-ecdsa384.pem" leafECDSA521 = "testdata/cfssl-leaf-ecdsa521.pem" leafRSA2048 = "testdata/cfssl-leaf-rsa2048.pem" leafRSA3072 = "testdata/cfssl-leaf-rsa3072.pem" leafRSA4096 = "testdata/cfssl-leaf-rsa4096.pem" leafKeyECDSA256 = "testdata/cfssl-leaf-ecdsa256.key" leafKeyECDSA384 = "testdata/cfssl-leaf-ecdsa384.key" leafKeyECDSA521 = "testdata/cfssl-leaf-ecdsa521.key" leafKeyRSA2048 = "testdata/cfssl-leaf-rsa2048.key" leafKeyRSA3072 = "testdata/cfssl-leaf-rsa3072.key" leafKeyRSA4096 = "testdata/cfssl-leaf-rsa4096.key" leafletRSA4096 = "testdata/cfssl-leaflet-rsa4096.pem" interL1 = "testdata/inter-L1.pem" interL1Expired = "testdata/inter-L1-expired.pem" interL1CSR = "testdata/inter-L1.csr" interL2 = "testdata/inter-L2.pem" interL2Direct = "testdata/inter-L2-direct.pem" partialBundle = "testdata/partial-bundle.pem" // partialBundle is a partial cert chain {leaf-ecds256, inter-L2} rpBundle = "testdata/reverse-partial-bundle.pem" // partialBundle is a partial cert chain in the reverse order {inter-L2, leaf-ecdsa256} badBundle = "testdata/bad-bundle.pem" // badBundle is a non-verifying partial bundle {leaf-ecdsa256, leaf-ecdsa384} interL2CSR = "testdata/inter-L2.csr" certDSA2048 = "testdata/dsa2048.pem" keyDSA2048 = "testdata/dsa2048.key" ) // BundleFromFile test cases. var fileTests = []fileTest{ // Input verification { cert: "not_such_cert.pem", caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessage(`"code":1001`), }, { cert: emptyPEM, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessage(`"code":1002`), }, // Normal Keyless bundling for all supported public key types { cert: leafECDSA256, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, { cert: leafECDSA384, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, { cert: leafECDSA521, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, { cert: leafRSA2048, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, /* TODO: Re-enable once leafRSA3072 is regenerated with new expiry. { cert: leafRSA3072, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, */ { cert: leafRSA4096, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, // Normal bundling with private key for all supported key types { cert: leafECDSA256, key: leafKeyECDSA256, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, { cert: leafECDSA384, key: leafKeyECDSA384, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, { cert: leafECDSA521, key: leafKeyECDSA521, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, { cert: leafRSA2048, key: leafKeyRSA2048, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, /* TODO: Re-enable once leafRSA3072 is regenerated with new expiry. { cert: leafRSA3072, key: leafKeyRSA3072, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, */ { cert: leafRSA4096, key: leafKeyRSA4096, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, // Bundling with errors // leaflet cert is signed by a leaf cert which is not included the intermediate bundle. // So an UnknownAuthority error is expected. { cert: leafletRSA4096, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessage(`"code":1220`), }, // Expect TooManyIntermediates error because max path length is 1 for // inter-L1 but the leaflet cert is 2 CA away from inter-L1. { cert: leafletRSA4096, extraIntermediates: leafRSA4096, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessage(`"code":1213`), }, // Bundle with expired inter-L1 intermediate cert only, expect error 1211 VerifyFailed:Expired. { cert: interL2, extraIntermediates: interL1Expired, caBundleFile: testCFSSLRootBundle, intBundleFile: emptyPEM, errorCallback: ExpectErrorMessage(`"code":1211`), }, // Bundle with private key mismatch // RSA cert, ECC private key { cert: leafRSA4096, key: leafKeyECDSA256, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessages([]string{`"code":2300,`, `"message":"Private key does not match public key"`}), }, // ECC cert, RSA private key { cert: leafECDSA256, key: leafKeyRSA4096, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessages([]string{`"code":2300,`, `"message":"Private key does not match public key"`}), }, // RSA 2048 cert, RSA 4096 private key { cert: leafRSA2048, key: leafKeyRSA4096, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessages([]string{`"code":2300,`, `"message":"Private key does not match public key"`}), }, // ECDSA 256 cert, ECDSA 384 private key { cert: leafECDSA256, key: leafKeyECDSA384, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessages([]string{`"code":2300,`, `"message":"Private key does not match public key"`}), }, // DSA is NOT supported. // Keyless bundling, expect private key error "NotRSAOrECCOrEd25519" { cert: certDSA2048, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessages([]string{`"code":2200,`, `"message":"Private key algorithm is not RSA or ECC or Ed25519"`}), }, // Bundling with DSA private key, expect error "Failed to parse private key" { cert: certDSA2048, key: keyDSA2048, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessages([]string{`"code":2003,`, `"message":"Failed to parse private key"`}), }, // Bundle with partial chain less some intermediates, expected error 1220: UnknownAuthority { cert: badBundle, caBundleFile: testCFSSLRootBundle, intBundleFile: interL1, errorCallback: ExpectErrorMessage(`"code":1220`), }, // Bundle with misplaced key as cert { cert: leafKeyECDSA256, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessages([]string{`"code":1003,`, `"message":"Failed to parse certificate"`}), }, // Bundle with misplaced cert as key { cert: leafECDSA256, key: leafECDSA256, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: ExpectErrorMessages([]string{`"code":2003,`, `"message":"Failed to parse private key"`}), }, // Smart Bundling // Bundling with a partial bundle should work the same as bundling the leaf. { cert: partialBundle, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, // Bundle with a partial bundle such that the intermediate provided in the // partial bundle is verify by an intermediate. Yet itself is not in the intermediate // pool. In such cases, the bundling should be able to store the new intermediate // and return a correct bundle. { cert: partialBundle, caBundleFile: testCFSSLRootBundle, intBundleFile: interL1, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, // Bundle with a reverse-ordered partial bundle. // Bundler should be able to detect it and return a correct bundle. { cert: rpBundle, caBundleFile: testCFSSLRootBundle, intBundleFile: interL1, errorCallback: nil, bundleChecking: ExpectBundleLength(3), }, // Bundle with a L2 cert direct signed by root, expect a shorter chain of length 2. { cert: leafECDSA256, extraIntermediates: interL2Direct, caBundleFile: testCFSSLRootBundle, intBundleFile: testCFSSLIntBundle, errorCallback: nil, bundleChecking: ExpectBundleLength(2), }, } // TestBundleFromFile goes through test cases defined in fileTests. See below for test cases definition and details. func TestBundleFromFile(t *testing.T) { for _, test := range fileTests { b := newCustomizedBundlerFromFile(t, test.caBundleFile, test.intBundleFile, test.extraIntermediates) bundle, err := b.BundleFromFile(test.cert, test.key, Optimal, "") if test.errorCallback != nil { test.errorCallback(t, err) } else { if err != nil { t.Fatalf("expected no error bundling %q. but an error occurred: %v", test.cert, err) } if test.bundleChecking != nil { test.bundleChecking(t, bundle) } } if bundle != nil { bundle.Cert = nil if _, err = json.Marshal(bundle); err == nil { t.Fatal("bundle should fail with no cert") } } } } ================================================ FILE: bundler/bundle_from_pem_test.go ================================================ package bundler // This test file contains tests on checking the correctness of BundleFromPEM import ( "testing" ) // A helper structure that defines a BundleFromPEM test case. type pemTest struct { // PEM cert to be bundled cert []byte // PEM private key to be bundled key []byte // PEM intermediate certificates to be considered when bundling inters []byte // Bundler creation function bundlerConstructor func(*testing.T) (b *Bundler) // Error checking function errorCallback func(*testing.T, error) // Bundle checking function bundleChecking func(*testing.T, *Bundle) } // BundleFromPEM test cases. var pemTests = []pemTest{ { cert: GoDaddyIntermediateCert, bundlerConstructor: newBundler, errorCallback: nil, bundleChecking: ExpectBundleLength(1), }, { cert: []byte(""), bundlerConstructor: newBundler, errorCallback: ExpectErrorMessage("\"code\":1002"), }, { cert: corruptCert, bundlerConstructor: newBundler, errorCallback: ExpectErrorMessage("\"code\":1002"), }, { cert: garbageCert, bundlerConstructor: newBundler, errorCallback: ExpectErrorMessage("\"code\":1003"), }, { cert: selfSignedCert, bundlerConstructor: newBundler, errorCallback: ExpectErrorMessage("\"code\":1100"), }, // 121X errors are X509.CertificateInvalidError. This test // covers the code path leads to all 121X errors. { cert: expiredCert, bundlerConstructor: newBundler, errorCallback: ExpectErrorMessage("\"code\":1211"), }, // With a empty root cert pool, the valid root cert // is seen as issued by an unknown authority. { cert: GoDaddyIntermediateCert, bundlerConstructor: newBundlerWithoutRoots, errorCallback: ExpectErrorMessage("\"code\":1220"), }, } // TestBundleFromPEM goes through the test cases defined in pemTests and run them through. See below for test case definitions. func TestBundleFromPEM(t *testing.T) { for i, test := range pemTests { b := test.bundlerConstructor(t) bundle, err := b.BundleFromPEMorDER(test.cert, test.key, Optimal, "") if test.errorCallback != nil { test.errorCallback(t, err) } else { if err != nil { t.Errorf("expected no error. but an error occurred at %d-th test: %s", i, err.Error()) } if test.bundleChecking != nil { test.bundleChecking(t, bundle) } } } } // GoDaddy intermediate cert valid until year 2034 var GoDaddyRootCert = []byte(`-----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h /t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf ReYNnyicsbkqWletNw+vHX/bvZ8= -----END CERTIFICATE-----`) // GoDaddy intermediate cert valid until year 2026 var GoDaddyIntermediateCert = []byte(`-----BEGIN CERTIFICATE----- MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ 6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o 0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV U+4= -----END CERTIFICATE-----`) // This is the same GoDaddy cert above except the last line is corrupted. var corruptCert = []byte(`-----BEGIN CERTIFICATE----- MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ 6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o 0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV CORRUPTED -----END CERTIFICATE-----`) // A garbage cert, which can be decoded into ill-formed cert var garbageCert = []byte(`-----BEGIN CERTIFICATE----- MIICATCCAWoCCQDidF+uNJR6czANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB cyBQdHkgTHRkMB4XDTEyMDUwMTIyNTUxN1oXDTEzMDUwMTIyNTUxN1owRTELMAkG A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81 IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt +LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw== -----END CERTIFICATE-----`) // A expired cert var expiredCert = []byte(`-----BEGIN CERTIFICATE----- MIIHlTCCBn2gAwIBAgIQCgFBPgAAATyS0MsAAAAAAjANBgkqhkiG9w0BAQUFADBY MQswCQYDVQQGEwJVUzEXMBUGA1UECgwOSWRlblRydXN0IExMQy4xFzAVBgNVBAsM DlRydXN0SUQgU2VydmVyMRcwFQYDVQQDDA5UcnVzdElEIENBIEE1MTAeFw0xMzAx MzEyMjUzNDJaFw0xMzAyMDEyMjUzNDJaMIGIMSEwHwYDVQQDDBhleHBpcmVkLmlk ZW50cnVzdHNzbC5jb20xFjAUBgNVBAsMDUlERU5UUlVTVCBJTkMxFjAUBgNVBAoM DUlERU5UUlVTVCBJTkMxFzAVBgNVBAcMDlNBTFQgTEFLRSBDSVRZMQ0wCwYDVQQI DARVVEFIMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMfv32RRW//GXnNRiJAa7oMzKErpKb+AzWOqKaIw1kLwIcRfCZl6ZFVEHBLz L0cAHg2WE5+jEXTlGC8Yitt294cUcuzM/UNR2/oTcviIbGSYyAl1NDbWUPIqrnpJ K/QEMEcV3r2VSGHzgyhBBLrR51CapDYpy1beg7M4oi8535H4waxyTlvrx7YJ5ZnB 0SZNfmAv2UO2WObuFVQP5j+frotJ496ireXydhpseKxG/LZKiAQpHXRNMMu22rwz Wun6wXTQ+rBNHaeLB00Pnd3GrTsdkg5KRqFVyh8+wa0a9Mvptj1PXMjiyb2TLdfd fHmmxC1ueYfFf2bny4Bi/Urm7cMCAwEAAaOCBCgwggQkMA4GA1UdDwEB/wQEAwIF oDCCAicGA1UdIASCAh4wggIaMIIBCwYKYIZIAYb5LwAGAzCB/DBABggrBgEFBQcC ARY0aHR0cHM6Ly9zZWN1cmUuaWRlbnRydXN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9s aWN5L3RzLzCBtwYIKwYBBQUHAgIwgaoagadUaGlzIFRydXN0SUQgU2VydmVyIENl cnRpZmljYXRlIGhhcyBiZWVuIGlzc3VlZCBpbiBhY2NvcmRhbmNlIHdpdGggSWRl blRydXN0J3MgVHJ1c3RJRCBDZXJ0aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQgaHR0 cHM6Ly9zZWN1cmUuaWRlbnRydXN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L3Rz LzCCAQcGBmeBDAECAjCB/DBABggrBgEFBQcCARY0aHR0cHM6Ly9zZWN1cmUuaWRl bnRydXN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L3RzLzCBtwYIKwYBBQUHAgIw gaoagadUaGlzIFRydXN0SUQgU2VydmVyIENlcnRpZmljYXRlIGhhcyBiZWVuIGlz c3VlZCBpbiBhY2NvcmRhbmNlIHdpdGggSWRlblRydXN0J3MgVHJ1c3RJRCBDZXJ0 aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQgaHR0cHM6Ly9zZWN1cmUuaWRlbnRydXN0 LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L3RzLzAdBgNVHQ4EFgQUcXFUZ6wayp6G GAd+34JhzuVAv8MwgeYGA1UdHwSB3jCB2zA3oDWgM4YxaHR0cDovL2NybC5pZGVu dHJ1c3QuY29tL3RydXN0aWQvdHJ1c3RpZGNhYTUxLmNybDCBn6CBnKCBmYaBlmxk YXA6Ly9sZGFwLmlkZW50cnVzdC5jb20vY249VHJ1c3RJRCUyMFNlcnZlciUyMENB JTIwQTUxLG91PVRydXN0SUQlMjBTZXJ2ZXIsbz1EaWdpdGFsJTIwU2lnbmF0dXJl JTIwVHJ1c3QlMjBDby4sYz1VUz9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0O2Jp bmFyeTB6BggrBgEFBQcBAQRuMGwwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLmlk ZW50cnVzdC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9hcHBzLklkZW5UcnVzdC5j b20vcm9vdHMvaWRlbnRydXN0dHJ1c3RpZHNzbC5wN2MwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFBrSOtPUiKDLDl9SWcXcTo5OyAXW MCMGA1UdEQQcMBqCGGV4cGlyZWQuaWRlbnRydXN0c3NsLmNvbTANBgkqhkiG9w0B AQUFAAOCAQEArqD5svgbZCYiApfe5qAKXh96lRfJ1VWO335ZvHWsO6h/aIP2P9nt CZ+wmP2M/EYOgteDgYIzJL1AAQbV/VNhX9kLcASWa5f63+sdmK9cotLwjkcSxCeb a5bFyEpLQWgJLlMoHu2Kj2KHONbzXU2xN3E3dCVFbPVUBswCsPspoMr1JY9k1KLl QDI8IWBbGiJvKcwifWXQ+g2l+NZjG4J0VZ/dwD9XsYqRBCb/1U/vCm+5H2sZ432H JKwzKO81YBVCz/BVX3QWo4sPfTop3LEfVRVdDSBsXGmMqbLp2bTbKKuQ0fMF1g/o vmsS6wZVxsSSna7VkmXdoLZDcf7Dv+yGEg== -----END CERTIFICATE-----`) // A self-signed cert var selfSignedCert = []byte(`-----BEGIN CERTIFICATE----- MIIERTCCAy2gAwIBAgIJAORAsvx6MZO7MA0GCSqGSIb3DQEBBQUAMHQxCzAJBgNV BAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEXMBUG A1UEChMOQ2xvdWRGbGFyZSBMTEMxETAPBgNVBAsTCFNlY3VyaXR5MRQwEgYDVQQD Ewt0ZXN0c3NsLmxvbDAeFw0xNDA0MDQyMjM4MzhaFw0yNDA0MDEyMjM4MzhaMHQx CzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj bzEXMBUGA1UEChMOQ2xvdWRGbGFyZSBMTEMxETAPBgNVBAsTCFNlY3VyaXR5MRQw EgYDVQQDEwt0ZXN0c3NsLmxvbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMKNLxpsnT37jSYkP9LVjw050Nmt1YMcEPwLe8zGUr8QzTWQ194Z9Ik/qYS0 UpQlx7+8UBoCanDTYuNKarHhmj4nZp+gc3mWWlaJKRnCJZ+Ru18x2lg9BzG4MwPQ 63ve0WxZ69/6J3lx53ertDgcD7S4v71BaeE10miBeJLK3JkV6fgGGfGRAGwU9vfm OBbPTAw2SRdB1AaYTHaT4ANwUI7vvkIPrNuneTjOqlN9DAroUNIkXhV+fSmncRxi RCAfP8/4BZdZ9C4TTKUpdAVUe1LUcHygK2f3YtOx8qJLCRMTRMYccSI1Y1idhX1s SKIDDrOuELb+pGgno5PCe6i6MWcCAwEAAaOB2TCB1jAdBgNVHQ4EFgQUCkxuIVbR +I8Z0A547Xj1R57ceXUwgaYGA1UdIwSBnjCBm4AUCkxuIVbR+I8Z0A547Xj1R57c eXWheKR2MHQxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2Fu IEZyYW5jaXNjbzEXMBUGA1UEChMOQ2xvdWRGbGFyZSBMTEMxETAPBgNVBAsTCFNl Y3VyaXR5MRQwEgYDVQQDEwt0ZXN0c3NsLmxvbIIJAORAsvx6MZO7MAwGA1UdEwQF MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKFaOjVRXCNsOznpZe0478mIFK6mNwwi ZrLcrEUZ0FIOcPwsnQXd/HmrR4MVj3z3U62mE6qFo+07yJnnXdKBJ9ThjmNu6c4S dk2xPbKTuACF7UhMgPlac0tEp/KSJTaMcjl23H+ol80LZ/t1113XSAZYHWsAgTjC 905kp66Gcq7c+GBgrBqR4e6Z2GYCeAk5aMy5f5s90teW2bIZE0hG1mFz1e25l9lI SkAp0gZusX4yxqoSBqKmKXBkjrW5vkKJZjP51c7fuhfuAyNfxZF4Cz9SS0YSG8eh H5kVbpLP+eSYMqF110qqjAo4tkgBquF6IppA+HQ66DN64+TeiXb3f2Y= -----END CERTIFICATE-----`) // An expired bundle var expiredBundlePEM = []byte(`-----BEGIN CERTIFICATE----- MIIEezCCAmOgAwIBAgIUUNg8o/9IQGSH6PBBxo06zIJEcaAwDQYJKoZIhvcNAQEN BQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQL ExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMw EQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNv bTAeFw0xNzA1MjIyMjEzMDBaFw0yMjA1MjMwNDEzMDBaMIGLMQswCQYDVQQGEwJV UzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmlu ZzEcMBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABIxG/fG9y/gjlAXvB77beERLbBooN98FGFAxVUA5IglylvgmfNxU mI8mM2Uw9tzOLm9vORAraSSM4/6iSpCJreCjgZ4wgZswEwYDVR0lBAwwCgYIKwYB BQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUqc1Wy6iYDBNjgFSn8WtaWXd3 yK4wHwYDVR0jBBgwFoAUiGC6GKR3uEEEG9Xvd1HCWxS6ID8wNgYDVR0RBC8wLYIT Y2xvdWRmbGFyZS1sZWFmLmNvbYIWd3d3Y2xvdWRmbGFyZS1sZWFmLmNvbTANBgkq hkiG9w0BAQ0FAAOCAgEAFH0prS82UElynKi7ik9gmTyrKz/YWTdXe9tGLPKSr88I vBKMr1TuY13qTYKybTcUq3HTvJEvAyih7VbGQFqPnNpBE6DdE/M+Cfxo0iwM8e+C 49APOcMZKrddNnAfhmQqJuFJUCvHmKQ8p8VXfUm3q6qIwqwKTyubmGvO6b3JUtoD MDOX4GZdYuIp7Q5jNWXDxw0k4ycaE8CZuRpOjVZ75X8OzwRG+ZFkAZlvxs4APpRr n8gQ9U5cy00uLzwCgsNiJbweElcaBAEkurBZzLtXMd3sQKAH5kyqjeZTATb547tq c0ykdcsf6ghBbGmNF+Bg3U7vY6ddep6sj5ifxCdAv9xqDCoKvG2JXYM2N56lFNWv RJLIuB2nru/QeV0Rpq+UADfj3jkfxWk3H7YoOoYQTXllZ6aIfiOb9MqVYQUx1+G2 WV9sG10aRX+nYwvmddsUrkiKLgPhzE7Exn0f+dyN+FROsInniqNO7LC56ICJt72C DPLLg0SQaaXjfEw3hnaf3YOHhP+opl9Q3HfVbe3ftJD1pp5BsK5S/hD/vegQZ3NL MhBvsWX+HW3OuvGbbnLruqcRRH3LA/Pm+8IImAbdFXntcuuuQCb66YT/Gh0bkpoD 8R5sjAanl/EYiQIds4ZUuRrec+90ieceKM+P/b9wwLXHW2/o2s1evg2dGcJ97DY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEfTCCA+agAwIBAgIUFalofeaKAEmnWkBXWu4lkwmmh3IwDQYJKoZIhvcNAQEF BQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxhcmUxFDASBgNVBAsMC0RF Vl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NBMB4XDTE2MDIxODAxMTIw MFoXDTE2MDIxODAxMTIwMVowgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxp Zm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZs YXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91 ZGZsYXJlLWludGVyLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AOUKdX6+PSxU/LxKocsCUj7HCc+FaDOPZV68Po3PVm7UF5DmbnLgJYJ/4aZEZM/v 5r8LnXQXDqumYicHQ2DHHBDasLTx8m0KeKOUYf9WMQ8gdjmVFoCiZwzxGDHok66/ 0Glkkqmv2nJQxXncl5ZFta4sfmcQx3KT02l61LaBbG3j8PbRCWEr+0eRE6twuYRR 13AgZ3ATwnMjzxzvsW67qmAy0cq+XgYYfTK9vhPs+8J0fxXa0Iftu3yuhd30xLIV XLu45GR+i6KnsSxVERSaVxjkS+lHXjUpdtmqI5CK6wn67vqYRRA2TzAJHX8Jb+KL 2/UEo5WNfAJ8S0heODQA8nHVU1JIfpegOlQRMv55DgnQUv1c1uwO5hqvv7MPQ3X/ m9Kjccs1FBH1/SVuzKyxYEQ34LErX3HI+6avbVnRtTR/UHkfnZVIXSrcjUm73BGj 33hrtiKl0ZyZnaUKGZPuvebOUFNiXemhTbqrfi/zAb1Tsm/h+xkn5EZ5sMj5NHdA bpih3TqX2gRhnFZcFjtJM6zzC5O7eG5Kdqf8iladXTXtWxzrUPkb5CupzFl1dyS3 dqdkoIXvkmlScnu+6jBOaYeVvwogxr2Y69y4Zfg/qbPyBOLZquX9ovbuSP1DQmC/ /LV5t7YHHY/1MXr5U0MMvcn+9JWUV6ou3at4AgEqfK0vAgMBAAGjZjBkMA4GA1Ud DwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBSIYLoYpHe4 QQQb1e93UcJbFLogPzAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAN BgkqhkiG9w0BAQUFAAOBgQAnGnLG3r4g+0bLkeeh1Y71pL0Ui1LnvCA1v+yVDCd0 G9pj7cnHHXjnp4Pic6pP9uwxBAiUC6rzjpKrm1ULYMoQPLAYmwJiz+8yiE5vpMCA Ov3LFPDNAbGF2wavwpCVolnVgHzPSFTEXN53DdXdVhcQ207P+zWNCNDF4Q33WSfm Dw== -----BEGIN CERTIFICATE----- MIIEezCCAmOgAwIBAgIUUNg8o/9IQGSH6PBBxo06zIJEcaAwDQYJKoZIhvcNAQEN BQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQL ExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMw EQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNv bTAeFw0xNzA1MjIyMjEzMDBaFw0yMjA1MjMwNDEzMDBaMIGLMQswCQYDVQQGEwJV UzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmlu ZzEcMBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABIxG/fG9y/gjlAXvB77beERLbBooN98FGFAxVUA5IglylvgmfNxU mI8mM2Uw9tzOLm9vORAraSSM4/6iSpCJreCjgZ4wgZswEwYDVR0lBAwwCgYIKwYB BQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUqc1Wy6iYDBNjgFSn8WtaWXd3 yK4wHwYDVR0jBBgwFoAUiGC6GKR3uEEEG9Xvd1HCWxS6ID8wNgYDVR0RBC8wLYIT Y2xvdWRmbGFyZS1sZWFmLmNvbYIWd3d3Y2xvdWRmbGFyZS1sZWFmLmNvbTANBgkq hkiG9w0BAQ0FAAOCAgEAFH0prS82UElynKi7ik9gmTyrKz/YWTdXe9tGLPKSr88I vBKMr1TuY13qTYKybTcUq3HTvJEvAyih7VbGQFqPnNpBE6DdE/M+Cfxo0iwM8e+C 49APOcMZKrddNnAfhmQqJuFJUCvHmKQ8p8VXfUm3q6qIwqwKTyubmGvO6b3JUtoD MDOX4GZdYuIp7Q5jNWXDxw0k4ycaE8CZuRpOjVZ75X8OzwRG+ZFkAZlvxs4APpRr n8gQ9U5cy00uLzwCgsNiJbweElcaBAEkurBZzLtXMd3sQKAH5kyqjeZTATb547tq c0ykdcsf6ghBbGmNF+Bg3U7vY6ddep6sj5ifxCdAv9xqDCoKvG2JXYM2N56lFNWv RJLIuB2nru/QeV0Rpq+UADfj3jkfxWk3H7YoOoYQTXllZ6aIfiOb9MqVYQUx1+G2 WV9sG10aRX+nYwvmddsUrkiKLgPhzE7Exn0f+dyN+FROsInniqNO7LC56ICJt72C DPLLg0SQaaXjfEw3hnaf3YOHhP+opl9Q3HfVbe3ftJD1pp5BsK5S/hD/vegQZ3NL MhBvsWX+HW3OuvGbbnLruqcRRH3LA/Pm+8IImAbdFXntcuuuQCb66YT/Gh0bkpoD 8R5sjAanl/EYiQIds4ZUuRrec+90ieceKM+P/b9wwLXHW2/o2s1evg2dGcJ97DY= -----END CERTIFICATE-----`) ================================================ FILE: bundler/bundle_from_remote_test.go ================================================ package bundler // This test file contains tests on checking the correctness of BundleFromRemote import ( "net" "strings" "testing" "github.com/cloudflare/cfssl/ubiquity" ) // remoteTest defines a test case for BundleFromRemote. Hostname and ip are the test inputs. // bundlerConstructor points the bundler ctor and errorCallback handles the error checking. type remoteTest struct { hostname string ip string bundlerConstructor func(*testing.T) (b *Bundler) errorCallback func(*testing.T, *remoteTest, error) bundleCallback func(*testing.T, *remoteTest, *Bundle) } const ( RSACertSite = "rsa2048.badssl.com" SelfSignedSSLSite = "self-signed.badssl.com" MismatchedHostnameSite = "wrong.host.badssl.com" ECCCertSite = "ecc256.badssl.com" InvalidSite = "cloudflare1337.com" ValidSNI = "badssl.com" ValidSNIWildcard = "badssl.com" SNISANWildcard = "*.badssl.com" InvalidIP = "300.300.300.300" ) func getBundleHostnameChecker(hostname string) func(*testing.T, *remoteTest, *Bundle) { return func(t *testing.T, test *remoteTest, bundle *Bundle) { if bundle == nil { t.Fatalf("Nil bundle returned hostname=%q ip=%q", test.hostname, test.ip) } var found = false for _, h := range bundle.Hostnames { if h == hostname { found = true } } if !found { t.Errorf("hostname expected but not found: %s hostname=%q ip=%q found=%v", hostname, test.hostname, test.ip, bundle.Hostnames) } } } func expectErrorMessages(expectedContents []string) func(*testing.T, *remoteTest, error) { return func(t *testing.T, test *remoteTest, err error) { if err == nil { t.Fatalf("Expected error has %s. Got nothing. hostname=%q ip=%q", expectedContents, test.hostname, test.ip) } else { for _, expected := range expectedContents { if !strings.Contains(err.Error(), expected) { t.Fatalf("Expected error has %s. Got %s. hostname=%q ip=%q", expected, err.Error(), test.hostname, test.ip) } } } } } // test cases of BundleFromRemote var remoteTests = []remoteTest{ { hostname: RSACertSite, bundlerConstructor: newBundler, errorCallback: nil, }, { hostname: ECCCertSite, bundlerConstructor: newBundler, errorCallback: nil, }, { hostname: SelfSignedSSLSite, bundlerConstructor: newBundler, errorCallback: expectErrorMessages([]string{`"code":12`}), // only check it is a 12xx error }, { hostname: MismatchedHostnameSite, bundlerConstructor: newBundler, errorCallback: expectErrorMessages([]string{`"code":12`}), // only check it is a 12xx error }, { hostname: InvalidSite, bundlerConstructor: newBundler, errorCallback: expectErrorMessages([]string{`"code":6000`, "dial tcp: lookup cloudflare1337.com"}), }, { hostname: InvalidIP, bundlerConstructor: newBundler, errorCallback: expectErrorMessages([]string{`"code":6000`, "dial tcp: lookup 300.300.300.300"}), }, { ip: InvalidIP, bundlerConstructor: newBundler, errorCallback: expectErrorMessages([]string{`"code":6000`, "dial tcp: lookup 300.300.300.300"}), }, } // TestBundleFromRemote goes through the test cases defined in remoteTests and run them through. See above for test case definitions. func TestBundleFromRemote(t *testing.T) { for _, bf := range []BundleFlavor{Ubiquitous, Optimal} { for _, test := range remoteTests { b := test.bundlerConstructor(t) bundle, err := b.BundleFromRemote(test.hostname, test.ip, bf) if test.errorCallback != nil { test.errorCallback(t, &test, err) } else { if err != nil { t.Fatalf("expected no error. but an error occurred hostname=%q ip=%q errpr=%q", test.hostname, test.ip, err.Error()) } if test.bundleCallback != nil { test.bundleCallback(t, &test, bundle) } } } } } func resolveHostIP(host string) string { addrs, err := net.LookupHost(host) if err != nil { panic(err) } if len(addrs) == 0 { panic("failed to resolve " + host) } return addrs[0] } var remoteSNITests = []remoteTest{ { hostname: ValidSNI, bundlerConstructor: newBundler, errorCallback: nil, bundleCallback: getBundleHostnameChecker(ValidSNI), }, { hostname: ValidSNIWildcard, bundlerConstructor: newBundler, errorCallback: nil, bundleCallback: getBundleHostnameChecker(SNISANWildcard), }, { hostname: ValidSNI, ip: resolveHostIP(ValidSNI), bundlerConstructor: newBundler, errorCallback: nil, bundleCallback: getBundleHostnameChecker(ValidSNI), }, { hostname: ValidSNIWildcard, ip: resolveHostIP(ValidSNIWildcard), bundlerConstructor: newBundler, errorCallback: nil, bundleCallback: getBundleHostnameChecker(SNISANWildcard), }, } // TestBundleFromRemoteSNI goes through the test cases defined in remoteSNITests and run them through. See above for test case definitions. func TestBundleFromRemoteSNI(t *testing.T) { for _, bf := range []BundleFlavor{Ubiquitous, Optimal} { for _, test := range remoteSNITests { b := test.bundlerConstructor(t) bundle, err := b.BundleFromRemote(test.hostname, test.ip, bf) if test.errorCallback != nil { test.errorCallback(t, &test, err) } else { if err != nil { t.Errorf("expected no error. but an error occurred: %s", err.Error()) } if test.bundleCallback != nil { test.bundleCallback(t, &test, bundle) } } } } } func TestBundleFromRemoteFlavor(t *testing.T) { // This test was crafted for the specific cert bundle that benflare.us was // serving. The majority of the functionality is validated via the other // bundle tests. t.Skip("skipped; need new example site for test") b := newBundler(t) ubiquity.Platforms = nil ubiquity.LoadPlatforms(testMetadata) bundle, err := b.BundleFromRemote(ECCCertSite, "", Ubiquitous) if err != nil { t.Fatalf("expected no error. but an error occurred: %s", err.Error()) } if len(bundle.Chain) != 3 { t.Error("expected 3-cert bundle. Got ", len(bundle.Chain)) } if len(bundle.Status.Untrusted) != 0 { t.Error("expected no untrusted platforms. Got ", bundle.Status.Untrusted) } bundle, err = b.BundleFromRemote(ECCCertSite, "", Optimal) if err != nil { t.Errorf("expected no error. but an error occurred: %s", err.Error()) } if len(bundle.Chain) != 2 { t.Error("expected 2-cert bundle. Got ", len(bundle.Chain)) } } ================================================ FILE: bundler/bundler.go ================================================ // Package bundler implements certificate bundling functionality for // CFSSL. package bundler import ( "bytes" "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "crypto/tls" "crypto/x509" "encoding/pem" goerr "errors" "fmt" "io" "net" "net/http" "os" "path/filepath" "strconv" "strings" "time" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/ubiquity" ) // IntermediateStash contains the path to the directory where // downloaded intermediates should be saved. // When unspecified, downloaded intermediates are not saved. var IntermediateStash string // HTTPClient is an instance of http.Client that will be used for all HTTP requests. var HTTPClient = http.DefaultClient // BundleFlavor is named optimization strategy on certificate chain selection when bundling. type BundleFlavor string const ( // Optimal means the shortest chain with newest intermediates and // the most advanced crypto. Optimal BundleFlavor = "optimal" // Ubiquitous is aimed to provide the chain which is accepted // by the most platforms. Ubiquitous BundleFlavor = "ubiquitous" // Force means the bundler only verifies the input as a valid bundle, not optimization is done. Force BundleFlavor = "force" ) const ( sha2Warning = "The bundle contains certificates signed with advanced hash functions such as SHA2, which are problematic for certain operating systems, e.g. Windows XP SP2." ecdsaWarning = "The bundle contains ECDSA signatures, which are problematic for certain operating systems, e.g. Windows XP, Android 2.2 and Android 2.3." expiringWarningStub = "The bundle is expiring within 30 days." untrustedWarningStub = "The bundle may not be trusted by the following platform(s):" ubiquityWarning = "Unable to measure bundle ubiquity: No platform metadata present." ) // A Bundler contains the certificate pools for producing certificate // bundles. It contains any intermediates and root certificates that // should be used. type Bundler struct { RootPool *x509.CertPool IntermediatePool *x509.CertPool KnownIssuers map[string]bool opts options } type options struct { keyUsages []x509.ExtKeyUsage } var defaultOptions = options{ keyUsages: []x509.ExtKeyUsage{ x509.ExtKeyUsageAny, }, } // An Option sets options such as allowed key usages, etc. type Option func(*options) // WithKeyUsages lets you set which Extended Key Usage values are acceptable. By // default x509.ExtKeyUsageAny will be used. func WithKeyUsages(usages ...x509.ExtKeyUsage) Option { return func(o *options) { o.keyUsages = usages } } // NewBundler creates a new Bundler from the files passed in; these // files should contain a list of valid root certificates and a list // of valid intermediate certificates, respectively. func NewBundler(caBundleFile, intBundleFile string, opt ...Option) (*Bundler, error) { var caBundle, intBundle []byte var err error if caBundleFile != "" { log.Debug("Loading CA bundle: ", caBundleFile) caBundle, err = os.ReadFile(caBundleFile) if err != nil { log.Errorf("root bundle failed to load: %v", err) return nil, errors.Wrap(errors.RootError, errors.ReadFailed, err) } } if intBundleFile != "" { log.Debug("Loading Intermediate bundle: ", intBundleFile) intBundle, err = os.ReadFile(intBundleFile) if err != nil { log.Errorf("intermediate bundle failed to load: %v", err) return nil, errors.Wrap(errors.IntermediatesError, errors.ReadFailed, err) } } if IntermediateStash != "" { if _, err = os.Stat(IntermediateStash); err != nil && os.IsNotExist(err) { log.Infof("intermediate stash directory %s doesn't exist, creating", IntermediateStash) err = os.MkdirAll(IntermediateStash, 0755) if err != nil { log.Errorf("failed to create intermediate stash directory %s: %v", IntermediateStash, err) return nil, err } log.Infof("intermediate stash directory %s created", IntermediateStash) } } return NewBundlerFromPEM(caBundle, intBundle, opt...) } // NewBundlerFromPEM creates a new Bundler from PEM-encoded root certificates and // intermediate certificates. // If caBundlePEM is nil, the resulting Bundler can only do "Force" bundle. func NewBundlerFromPEM(caBundlePEM, intBundlePEM []byte, opt ...Option) (*Bundler, error) { opts := defaultOptions for _, o := range opt { o(&opts) } log.Debug("parsing root certificates from PEM") roots, err := helpers.ParseCertificatesPEM(caBundlePEM) if err != nil { log.Errorf("failed to parse root bundle: %v", err) return nil, errors.New(errors.RootError, errors.ParseFailed) } log.Debug("parse intermediate certificates from PEM") intermediates, err := helpers.ParseCertificatesPEM(intBundlePEM) if err != nil { log.Errorf("failed to parse intermediate bundle: %v", err) return nil, errors.New(errors.IntermediatesError, errors.ParseFailed) } b := &Bundler{ KnownIssuers: map[string]bool{}, IntermediatePool: x509.NewCertPool(), opts: opts, } log.Debug("building certificate pools") // RootPool will be nil if caBundlePEM is nil, also // that translates to caBundleFile is "". // Systems root store will be used. if caBundlePEM != nil { b.RootPool = x509.NewCertPool() } for _, c := range roots { b.RootPool.AddCert(c) b.KnownIssuers[string(c.Signature)] = true } for _, c := range intermediates { b.IntermediatePool.AddCert(c) b.KnownIssuers[string(c.Signature)] = true } log.Debug("bundler set up") return b, nil } // VerifyOptions generates an x509 VerifyOptions structure that can be // used for verifying certificates. func (b *Bundler) VerifyOptions() x509.VerifyOptions { return x509.VerifyOptions{ Roots: b.RootPool, Intermediates: b.IntermediatePool, KeyUsages: b.opts.keyUsages, } } // BundleFromFile takes a set of files containing the PEM-encoded leaf certificate // (optionally along with some intermediate certs), the PEM-encoded private key // and returns the bundle built from that key and the certificate(s). func (b *Bundler) BundleFromFile(bundleFile, keyFile string, flavor BundleFlavor, password string) (*Bundle, error) { log.Debug("Loading Certificate: ", bundleFile) certsRaw, err := os.ReadFile(bundleFile) if err != nil { return nil, errors.Wrap(errors.CertificateError, errors.ReadFailed, err) } var keyPEM []byte // Load private key PEM only if a file is given if keyFile != "" { log.Debug("Loading private key: ", keyFile) keyPEM, err = os.ReadFile(keyFile) if err != nil { log.Debugf("failed to read private key: ", err) return nil, errors.Wrap(errors.PrivateKeyError, errors.ReadFailed, err) } if len(keyPEM) == 0 { log.Debug("key is empty") return nil, errors.Wrap(errors.PrivateKeyError, errors.DecodeFailed, err) } } return b.BundleFromPEMorDER(certsRaw, keyPEM, flavor, password) } // BundleFromPEMorDER builds a certificate bundle from the set of byte // slices containing the PEM or DER-encoded certificate(s), private key. func (b *Bundler) BundleFromPEMorDER(certsRaw, keyPEM []byte, flavor BundleFlavor, password string) (*Bundle, error) { log.Debug("bundling from PEM files") var key crypto.Signer var err error if len(keyPEM) != 0 { key, err = helpers.ParsePrivateKeyPEM(keyPEM) if err != nil { log.Debugf("failed to parse private key: %v", err) return nil, err } } certs, err := helpers.ParseCertificatesPEM(certsRaw) if err != nil { // If PEM doesn't work try DER var keyDER crypto.Signer var errDER error certs, keyDER, errDER = helpers.ParseCertificatesDER(certsRaw, password) // Only use DER key if no key read from file if key == nil && keyDER != nil { key = keyDER } if errDER != nil { log.Debugf("failed to parse certificates: %v", err) // If neither parser works pass along PEM error return nil, err } } if len(certs) == 0 { log.Debugf("no certificates found") return nil, errors.New(errors.CertificateError, errors.DecodeFailed) } log.Debugf("bundle ready") return b.Bundle(certs, key, flavor) } // BundleFromRemote fetches the certificate served by the server at // serverName (or ip, if the ip argument is not the empty string). It // is expected that the method will be able to make a connection at // port 443. The certificate used by the server in this connection is // used to build the bundle, which will necessarily be keyless. func (b *Bundler) BundleFromRemote(serverName, ip string, flavor BundleFlavor) (*Bundle, error) { config := &tls.Config{ RootCAs: b.RootPool, ServerName: serverName, } // Dial by IP if present var dialName string if ip != "" { dialName = ip + ":443" } else { dialName = serverName + ":443" } log.Debugf("bundling from remote %s", dialName) dialer := &net.Dialer{Timeout: time.Duration(5) * time.Second} conn, err := tls.DialWithDialer(dialer, "tcp", dialName, config) var dialError string // If there's an error in tls.Dial, try again with // InsecureSkipVerify to fetch the remote bundle to (re-)bundle // with. If the bundle is indeed not usable (expired, mismatched // hostnames, etc.), report the error. Otherwise, create a // working bundle and insert the tls error in the bundle.Status. if err != nil { log.Debugf("dial failed: %v", err) // record the error msg dialError = fmt.Sprintf("Failed rigid TLS handshake with %s: %v", dialName, err) // dial again with InsecureSkipVerify log.Debugf("try again with InsecureSkipVerify.") config.InsecureSkipVerify = true conn, err = tls.DialWithDialer(dialer, "tcp", dialName, config) if err != nil { log.Debugf("dial with InsecureSkipVerify failed: %v", err) return nil, errors.Wrap(errors.DialError, errors.Unknown, err) } } connState := conn.ConnectionState() certs := connState.PeerCertificates err = conn.VerifyHostname(serverName) if err != nil { log.Debugf("failed to verify hostname: %v", err) return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } // Bundle with remote certs. Inject the initial dial error, if any, to the status reporting. bundle, err := b.Bundle(certs, nil, flavor) if err != nil { return nil, err } else if dialError != "" { bundle.Status.Messages = append(bundle.Status.Messages, dialError) } return bundle, err } type fetchedIntermediate struct { Cert *x509.Certificate Name string } // fetchRemoteCertificate retrieves a single URL pointing to a certificate // and attempts to first parse it as a DER-encoded certificate; if // this fails, it attempts to decode it as a PEM-encoded certificate. func fetchRemoteCertificate(certURL string) (fi *fetchedIntermediate, err error) { log.Debugf("fetching remote certificate: %s", certURL) var resp *http.Response resp, err = HTTPClient.Get(certURL) if err != nil { log.Debugf("failed HTTP get: %v", err) return } defer resp.Body.Close() var certData []byte certData, err = io.ReadAll(resp.Body) if err != nil { log.Debugf("failed to read response body: %v", err) return } log.Debugf("attempting to parse certificate as DER") crt, err := x509.ParseCertificate(certData) if err != nil { log.Debugf("attempting to parse certificate as PEM") crt, err = helpers.ParseCertificatePEM(certData) if err != nil { log.Debugf("failed to parse certificate: %v", err) return } } log.Debugf("certificate fetch succeeds") fi = &fetchedIntermediate{Cert: crt, Name: constructCertFileName(crt)} return } func reverse(certs []*x509.Certificate) []*x509.Certificate { n := len(certs) if n == 0 { return certs } rcerts := []*x509.Certificate{} for i := n - 1; i >= 0; i-- { rcerts = append(rcerts, certs[i]) } return rcerts } // Check if the certs form a partial cert chain: every cert verifies // the signature of the one in front of it. func partialVerify(certs []*x509.Certificate) bool { n := len(certs) if n == 0 { return false } for i := 0; i < n-1; i++ { if certs[i].CheckSignatureFrom(certs[i+1]) != nil { return false } } return true } func isSelfSigned(cert *x509.Certificate) bool { return cert.CheckSignatureFrom(cert) == nil } func isChainRootNode(cert *x509.Certificate) bool { return isSelfSigned(cert) } func (b *Bundler) verifyChain(chain []*fetchedIntermediate) bool { // This process will verify if the root of the (partial) chain is in our root pool, // and will fail otherwise. log.Debugf("verifying chain") for vchain := chain[:]; len(vchain) > 0; vchain = vchain[1:] { cert := vchain[0] // If this is a certificate in one of the pools, skip it. if b.KnownIssuers[string(cert.Cert.Signature)] { log.Debugf("certificate is known") continue } _, err := cert.Cert.Verify(b.VerifyOptions()) if err != nil { log.Debugf("certificate failed verification: %v", err) return false } else if len(chain) == len(vchain) && isChainRootNode(cert.Cert) { // The first certificate in the chain is a root; it shouldn't be stored. log.Debug("looking at root certificate, will not store") continue } // leaf cert has an empty name, don't store leaf cert. if cert.Name == "" { continue } log.Debug("add certificate to intermediate pool:", cert.Name) b.IntermediatePool.AddCert(cert.Cert) b.KnownIssuers[string(cert.Cert.Signature)] = true if IntermediateStash != "" { fileName := filepath.Join(IntermediateStash, cert.Name) var block = pem.Block{Type: "CERTIFICATE", Bytes: cert.Cert.Raw} log.Debugf("write intermediate to stash directory: %s", fileName) // If the write fails, verification should not fail. err = os.WriteFile(fileName, pem.EncodeToMemory(&block), 0644) if err != nil { log.Errorf("failed to write new intermediate: %v", err) } else { log.Info("stashed new intermediate ", cert.Name) } } } return true } // constructCertFileName returns a uniquely identifying file name for a certificate func constructCertFileName(cert *x509.Certificate) string { // construct the filename as the CN with no period and space name := strings.Replace(cert.Subject.CommonName, ".", "", -1) name = strings.Replace(name, " ", "", -1) // add SKI and serial number as extra identifier name += fmt.Sprintf("_%x", cert.SubjectKeyId) name += fmt.Sprintf("_%x", cert.SerialNumber.Bytes()) name += ".crt" return name } // fetchIntermediates goes through each of the URLs in the AIA "Issuing // CA" extensions and fetches those certificates. If those // certificates are not present in either the root pool or // intermediate pool, the certificate is saved to file and added to // the list of intermediates to be used for verification. This will // not add any new certificates to the root pool; if the ultimate // issuer is not trusted, fetching the certificate here will not change // that. func (b *Bundler) fetchIntermediates(certs []*x509.Certificate) (err error) { if IntermediateStash != "" { log.Debugf("searching intermediates") if _, err := os.Stat(IntermediateStash); err != nil && os.IsNotExist(err) { log.Infof("intermediate stash directory %s doesn't exist, creating", IntermediateStash) err = os.MkdirAll(IntermediateStash, 0755) if err != nil { log.Errorf("failed to create intermediate stash directory %s: %v", IntermediateStash, err) return err } log.Infof("intermediate stash directory %s created", IntermediateStash) } } // stores URLs and certificate signatures that have been seen seen := map[string]bool{} var foundChains int // Construct a verify chain as a reversed partial bundle, // such that the certs are ordered by promxity to the root CAs. var chain []*fetchedIntermediate for i, cert := range certs { var name string // Only construct filenames for non-leaf intermediate certs // so they will be saved to disk if necessary. // Leaf cert gets a empty name and will be skipped. if i > 0 { name = constructCertFileName(cert) } chain = append([]*fetchedIntermediate{{cert, name}}, chain...) seen[string(cert.Signature)] = true } // Verify the chain and store valid intermediates in the chain. // If it doesn't verify, fetch the intermediates and extend the chain // in a DFS manner and verify each time we hit a root. for { if len(chain) == 0 { log.Debugf("search complete") if foundChains == 0 { return x509.UnknownAuthorityError{} } return nil } current := chain[0] var advanced bool if b.verifyChain(chain) { foundChains++ } log.Debugf("walk AIA issuers") for _, url := range current.Cert.IssuingCertificateURL { if seen[url] { log.Debugf("url %s has been seen", url) continue } crt, err := fetchRemoteCertificate(url) if err != nil { continue } else if seen[string(crt.Cert.Signature)] { log.Debugf("fetched certificate is known") continue } seen[url] = true seen[string(crt.Cert.Signature)] = true chain = append([]*fetchedIntermediate{crt}, chain...) advanced = true break } if !advanced { log.Debugf("didn't advance, stepping back") chain = chain[1:] } } } // Bundle takes an X509 certificate (already in the // Certificate structure), a private key as crypto.Signer in one of the appropriate // formats (i.e. *rsa.PrivateKey, *ecdsa.PrivateKey or ed25519.PrivateKey, or even a opaque key), using them to // build a certificate bundle. func (b *Bundler) Bundle(certs []*x509.Certificate, key crypto.Signer, flavor BundleFlavor) (*Bundle, error) { log.Infof("bundling certificate for %+v", certs[0].Subject) if len(certs) == 0 { return nil, nil } // Detect reverse ordering of the cert chain. if len(certs) > 1 && !partialVerify(certs) { rcerts := reverse(certs) if partialVerify(rcerts) { certs = rcerts } } var ok bool cert := certs[0] if key != nil { switch { case cert.PublicKeyAlgorithm == x509.RSA: var rsaPublicKey *rsa.PublicKey if rsaPublicKey, ok = key.Public().(*rsa.PublicKey); !ok { return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch) } if cert.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 { return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch) } case cert.PublicKeyAlgorithm == x509.ECDSA: var ecdsaPublicKey *ecdsa.PublicKey if ecdsaPublicKey, ok = key.Public().(*ecdsa.PublicKey); !ok { return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch) } if cert.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 { return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch) } case cert.PublicKeyAlgorithm == x509.Ed25519: var ed25519PublicKey ed25519.PublicKey if ed25519PublicKey, ok = key.Public().(ed25519.PublicKey); !ok { return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch) } if !(bytes.Equal(cert.PublicKey.(ed25519.PublicKey), ed25519PublicKey)) { return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch) } default: return nil, errors.New(errors.PrivateKeyError, errors.NotRSAOrECCOrEd25519) } } else { switch { case cert.PublicKeyAlgorithm == x509.RSA: case cert.PublicKeyAlgorithm == x509.ECDSA: case cert.PublicKeyAlgorithm == x509.Ed25519: default: return nil, errors.New(errors.PrivateKeyError, errors.NotRSAOrECCOrEd25519) } } bundle := new(Bundle) bundle.Cert = cert bundle.Key = key bundle.Issuer = &cert.Issuer bundle.Subject = &cert.Subject bundle.buildHostnames() if flavor == Force { // force bundle checks the certificates // forms a verification chain. if !partialVerify(certs) { return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, goerr.New("Unable to verify the certificate chain")) } bundle.Chain = certs } else { // disallow self-signed cert if cert.CheckSignatureFrom(cert) == nil { return nil, errors.New(errors.CertificateError, errors.SelfSigned) } chains, err := cert.Verify(b.VerifyOptions()) if err != nil { log.Debugf("verification failed: %v", err) // If the error was an unknown authority, try to fetch // the intermediate specified in the AIA and add it to // the intermediates bundle. if _, ok := err.(x509.UnknownAuthorityError); !ok { return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } log.Debugf("searching for intermediates via AIA issuer") searchErr := b.fetchIntermediates(certs) if searchErr != nil { log.Debugf("search failed: %v", searchErr) return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } log.Debugf("verifying new chain") chains, err = cert.Verify(b.VerifyOptions()) if err != nil { log.Debugf("failed to verify chain: %v", err) return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } log.Debugf("verify ok") } var matchingChains [][]*x509.Certificate switch flavor { case Optimal: matchingChains = optimalChains(chains) case Ubiquitous: if len(ubiquity.Platforms) == 0 { log.Warning("No metadata, Ubiquitous falls back to Optimal.") } matchingChains = ubiquitousChains(chains) default: matchingChains = ubiquitousChains(chains) } bundle.Chain = matchingChains[0] } statusCode := int(errors.Success) var messages []string // Check if bundle is expiring. expiringCerts := checkExpiringCerts(bundle.Chain) if len(expiringCerts) > 0 { statusCode |= errors.BundleExpiringBit messages = append(messages, expirationWarning(expiringCerts)) } // Check if bundle contains SHA2 certs. if ubiquity.ChainHashUbiquity(bundle.Chain) <= ubiquity.SHA2Ubiquity { statusCode |= errors.BundleNotUbiquitousBit messages = append(messages, sha2Warning) } // Check if bundle contains ECDSA signatures. if ubiquity.ChainKeyAlgoUbiquity(bundle.Chain) <= ubiquity.ECDSA256Ubiquity { statusCode |= errors.BundleNotUbiquitousBit messages = append(messages, ecdsaWarning) } // when forcing a bundle, bundle ubiquity doesn't matter // also we don't retrieve the anchoring root of the bundle var untrusted []string if flavor != Force { // Add root store presence info root := bundle.Chain[len(bundle.Chain)-1] bundle.Root = root log.Infof("the anchoring root is %v", root.Subject) // Check if there is any platform that doesn't trust the chain. // Also, an warning will be generated if ubiquity.Platforms is nil, untrusted = ubiquity.UntrustedPlatforms(root) untrustedMsg := untrustedPlatformsWarning(untrusted) if len(untrustedMsg) > 0 { log.Debug("Populate untrusted platform warning.") statusCode |= errors.BundleNotUbiquitousBit messages = append(messages, untrustedMsg) } } // Check if there is any platform that rejects the chain because of SHA1 deprecation. sha1Msgs := ubiquity.SHA1DeprecationMessages(bundle.Chain) if len(sha1Msgs) > 0 { log.Debug("Populate SHA1 deprecation warning.") statusCode |= errors.BundleNotUbiquitousBit messages = append(messages, sha1Msgs...) } bundle.Status = &BundleStatus{ExpiringSKIs: getSKIs(bundle.Chain, expiringCerts), Code: statusCode, Messages: messages, Untrusted: untrusted} // attempt to not to include the root certificate for optimization if flavor != Force { // Include at least one intermediate if the leaf has enabled OCSP and is not CA. if bundle.Cert.OCSPServer != nil && !bundle.Cert.IsCA && len(bundle.Chain) <= 2 { // No op. Return one intermediate if there is one. } else { // do not include the root. bundle.Chain = bundle.Chain[:len(bundle.Chain)-1] } } bundle.Status.IsRebundled = diff(bundle.Chain, certs) bundle.Expires = helpers.ExpiryTime(bundle.Chain) bundle.LeafExpires = bundle.Chain[0].NotAfter log.Debugf("bundle complete") return bundle, nil } // checkExpiringCerts returns indices of certs that are expiring within 30 days. func checkExpiringCerts(chain []*x509.Certificate) (expiringIntermediates []int) { now := time.Now() for i, cert := range chain { if cert.NotAfter.Sub(now).Hours() < 720 { expiringIntermediates = append(expiringIntermediates, i) } } return } // getSKIs returns a list of cert subject key id in the bundle chain with matched indices. func getSKIs(chain []*x509.Certificate, indices []int) (skis []string) { for _, index := range indices { ski := fmt.Sprintf("%X", chain[index].SubjectKeyId) skis = append(skis, ski) } return } // expirationWarning generates a warning message with expiring certs. func expirationWarning(expiringIntermediates []int) (ret string) { if len(expiringIntermediates) == 0 { return } ret = expiringWarningStub if len(expiringIntermediates) > 1 { ret = ret + "The expiring certs are" } else { ret = ret + "The expiring cert is" } for _, index := range expiringIntermediates { ret = ret + " #" + strconv.Itoa(index+1) } ret = ret + " in the chain." return } // untrustedPlatformsWarning generates a warning message with untrusted platform names. func untrustedPlatformsWarning(platforms []string) string { if len(ubiquity.Platforms) == 0 { return ubiquityWarning } if len(platforms) == 0 { return "" } msg := untrustedWarningStub for i, platform := range platforms { if i > 0 { msg += "," } msg += " " + platform } msg += "." return msg } // Optimal chains are the shortest chains, with newest intermediates and most advanced crypto suite being the tie breaker. func optimalChains(chains [][]*x509.Certificate) [][]*x509.Certificate { // Find shortest chains chains = ubiquity.Filter(chains, ubiquity.CompareChainLength) // Find the chains with longest expiry. chains = ubiquity.Filter(chains, ubiquity.CompareChainExpiry) // Find the chains with more advanced crypto suite chains = ubiquity.Filter(chains, ubiquity.CompareChainCryptoSuite) return chains } // Ubiquitous chains are the chains with highest platform coverage and break ties with the optimal strategy. func ubiquitousChains(chains [][]*x509.Certificate) [][]*x509.Certificate { // Filter out chains with highest cross platform ubiquity. chains = ubiquity.Filter(chains, ubiquity.ComparePlatformUbiquity) // Prefer that all intermediates are SHA-2 certs if the leaf is a SHA-2 cert, in order to improve ubiquity. chains = ubiquity.Filter(chains, ubiquity.CompareSHA2Homogeneity) // Filter shortest chains chains = ubiquity.Filter(chains, ubiquity.CompareChainLength) // Filter chains with highest signature hash ubiquity. chains = ubiquity.Filter(chains, ubiquity.CompareChainHashUbiquity) // Filter chains with highest keyAlgo ubiquity. chains = ubiquity.Filter(chains, ubiquity.CompareChainKeyAlgoUbiquity) // Filter chains with intermediates that last longer. chains = ubiquity.Filter(chains, ubiquity.CompareExpiryUbiquity) // Use the optimal strategy as final tie breaker. return optimalChains(chains) } // diff checkes if two input cert chains are not identical func diff(chain1, chain2 []*x509.Certificate) bool { // Check if bundled one is different from the input. diff := false if len(chain1) != len(chain2) { diff = true } else { for i := 0; i < len(chain1); i++ { cert1 := chain1[i] cert2 := chain2[i] // Use signature to differentiate. if !bytes.Equal(cert1.Signature, cert2.Signature) { diff = true break } } } return diff } ================================================ FILE: bundler/bundler_sha1_deprecation_test.go ================================================ package bundler // This test file contains tests on checking Bundle.Status with SHA-1 deprecation warning. import ( "crypto/x509" "os" "testing" "time" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/local" "github.com/cloudflare/cfssl/ubiquity" ) const ( sha1CA = "testdata/ca.pem" sha1CAKey = "testdata/ca.key" sha1Intermediate = "testdata/inter-L1-sha1.pem" sha2Intermediate = "testdata/inter-L1.pem" intermediateKey = "testdata/inter-L1.key" intermediateCSR = "testdata/inter-L1.csr" leafCSR = "testdata/cfssl-leaf-ecdsa256.csr" ) func TestChromeWarning(t *testing.T) { b := newCustomizedBundlerFromFile(t, sha1CA, sha1Intermediate, "") s, err := local.NewSignerFromFile(sha1Intermediate, intermediateKey, nil) if err != nil { t.Fatal(err) } csrBytes, err := os.ReadFile(leafCSR) if err != nil { t.Fatal(err) } signingRequest := signer.SignRequest{Request: string(csrBytes)} certBytes, err := s.Sign(signingRequest) if err != nil { t.Fatal(err) } // Bundle a leaf cert with default 1 year expiration bundle, err := b.BundleFromPEMorDER(certBytes, nil, Ubiquitous, "") if err != nil { t.Fatal("bundling failed: ", err) } // should be not ubiquitous due to SHA2 and ECDSA support issues in legacy platforms if bundle.Status.Code&errors.BundleNotUbiquitousBit != errors.BundleNotUbiquitousBit { t.Fatal("Incorrect bundle status code. Bundle status code:", bundle.Status.Code) } fullChain := append(bundle.Chain, bundle.Root) sha1Msgs := ubiquity.SHA1DeprecationMessages(fullChain) // Since the new SHA-1 cert is expired after 2015, it definitely trigger Chrome's deprecation policies. if len(sha1Msgs) == 0 { t.Fatal("SHA1 Deprecation Message should not be empty") } // check SHA1 deprecation warnings var sha1MsgNotFound bool for _, sha1Msg := range sha1Msgs { foundMsg := false for _, message := range bundle.Status.Messages { if message == sha1Msg { foundMsg = true } } if !foundMsg { sha1MsgNotFound = true break } } if sha1MsgNotFound { t.Fatalf("Incorrect bundle status messages. Bundle status messages:%v, expected to contain: %v\n", bundle.Status.Messages, sha1Msgs) } } func TestSHA2Preferences(t *testing.T) { // create a CA signer and signs a new intermediate with SHA-1 sha1CASigner := makeCASignerFromFile(sha1CA, sha1CAKey, x509.SHA1WithRSA, t) // create a CA signer and signs a new intermediate with SHA-2 sha2CASigner := makeCASignerFromFile(sha1CA, sha1CAKey, x509.SHA256WithRSA, t) // sign two different intermediates sha1InterBytes := signCSRFile(sha1CASigner, intermediateCSR, t) sha2InterBytes := signCSRFile(sha2CASigner, intermediateCSR, t) interKeyBytes, err := os.ReadFile(intermediateKey) if err != nil { t.Fatal(err) } // create a intermediate signer from SHA-1 intermediate cert/key sha2InterSigner := makeCASigner(sha1InterBytes, interKeyBytes, x509.SHA256WithRSA, t) // sign a leaf cert leafBytes := signCSRFile(sha2InterSigner, leafCSR, t) // create a bundler with SHA-1 and SHA-2 intermediate certs of same key. b := newCustomizedBundlerFromFile(t, sha1CA, sha1Intermediate, "") if err != nil { t.Fatal(err) } sha1Inter, _ := helpers.ParseCertificatePEM(sha1InterBytes) sha2Inter, _ := helpers.ParseCertificatePEM(sha2InterBytes) b.IntermediatePool.AddCert(sha1Inter) b.IntermediatePool.AddCert(sha2Inter) bundle, err := b.BundleFromPEMorDER(leafBytes, nil, Ubiquitous, "") if err != nil { t.Fatal("bundling failed: ", err) } if bundle.Chain[1].SignatureAlgorithm != x509.SHA256WithRSA { t.Fatal("ubiquity selection by SHA-2 homogenity failed.") } } func makeCASignerFromFile(certFile, keyFile string, sigAlgo x509.SignatureAlgorithm, t *testing.T) signer.Signer { certBytes, err := os.ReadFile(certFile) if err != nil { t.Fatal(err) } keyBytes, err := os.ReadFile(keyFile) if err != nil { t.Fatal(err) } return makeCASigner(certBytes, keyBytes, sigAlgo, t) } func makeCASigner(certBytes, keyBytes []byte, sigAlgo x509.SignatureAlgorithm, t *testing.T) signer.Signer { cert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal(err) } key, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { t.Fatal(err) } defaultProfile := &config.SigningProfile{ Usage: []string{"cert sign"}, CAConstraint: config.CAConstraint{IsCA: true}, Expiry: time.Hour, ExpiryString: "1h", } policy := &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: defaultProfile, } s, err := local.NewSigner(key, cert, sigAlgo, policy) if err != nil { t.Fatal(err) } return s } func signCSRFile(s signer.Signer, csrFile string, t *testing.T) []byte { csrBytes, err := os.ReadFile(csrFile) if err != nil { t.Fatal(err) } signingRequest := signer.SignRequest{Request: string(csrBytes)} certBytes, err := s.Sign(signingRequest) if err != nil { t.Fatal(err) } return certBytes } ================================================ FILE: bundler/bundler_test.go ================================================ package bundler // This test file contains mostly tests on checking Bundle.Status when bundling under different circumstances. import ( "bytes" "crypto/x509" "encoding/json" "os" "strings" "testing" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/ubiquity" ) const ( // from https://github.com/cloudflare/cfssl_trust/blob/master/ca-bundle.crt testCaBundle = "testdata/ca-bundle.pem" // from https://github.com/cloudflare/cfssl_trust/blob/master/int-bundle.crt testIntCaBundle = "testdata/int-bundle.pem" testNSSRootBundle = "testdata/nss.pem" testMetadata = "testdata/ca-bundle.crt.metadata" testCFSSLRootBundle = "testdata/ca.pem" testCAFile = "testdata/ca.pem" testCAKeyFile = "testdata/ca.key" testCFSSLIntBundle = "testdata/intermediates.crt" emptyPEM = "testdata/empty.pem" interL1SHA1 = "testdata/inter-L1-sha1.pem" interL1Key = "testdata/inter-L1.key" interL2SHA2 = "testdata/inter-L2.pem" interL2Key = "testdata/inter-L2.key" ) // Simply create a bundler func TestNewBundler(t *testing.T) { newBundler(t) } func TestNewBundlerMissingCA(t *testing.T) { badFile := "testdata/no_such_file.pem" _, err := NewBundler(badFile, testIntCaBundle) if err == nil { t.Fatal("Should fail with error code 4001") } // generate a function checking error content errorCheck := ExpectErrorMessage(`"code":4001`) errorCheck(t, err) } func TestNewBundlerMissingIntermediate(t *testing.T) { badFile := "testdata/no_such_file.pem" _, err := NewBundler(testCaBundle, badFile) if err == nil { t.Fatal("Should fail with error code 3001") } // generate a function checking error content errorCheck := ExpectErrorMessage(`"code":3001`) errorCheck(t, err) } // JSON object of a bundle type bundleObject struct { Bundle string `json:"bundle"` Root string `json:"root"` Cert string `json:"crt"` Key string `json:"key"` KeyType string `json:"key_type"` KeySize int `json:"key_size"` Issuer string `json:"issuer"` Subject string `json:"subject"` Expires string `json:"expires"` Hostnames []string `json:"hostnames"` OCSPSupport bool `json:"ocsp_support"` CRLSupport bool `json:"crl_support"` OCSP []string `json:"ocsp"` Signature string `json:"signature"` Status BundleStatus } var godaddyIssuerString = `/Country=US/Organization=The Go Daddy Group, Inc./OrganizationalUnit=Go Daddy Class 2 Certification Authority` var godaddySubjectString = `/Country=US/Province=Arizona/Locality=Scottsdale/Organization=GoDaddy.com, Inc./OrganizationalUnit=http://certificates.godaddy.com/repository/CommonName=Go Daddy Secure Certification Authority/SerialNumber=07969287` // Test marshal to JSON // Also serves as a JSON format regression test. func TestBundleMarshalJSON(t *testing.T) { b := newBundler(t) bundle, _ := b.BundleFromPEMorDER(GoDaddyIntermediateCert, nil, Optimal, "") bytes, err := json.Marshal(bundle) if err != nil { t.Fatal(err) } var obj bundleObject err = json.Unmarshal(bytes, &obj) if err != nil { t.Fatal(err) } if obj.Bundle == "" { t.Fatal("bundle is empty.") } if obj.Bundle != string(GoDaddyIntermediateCert) { t.Fatal("bundle is incorrect:", obj.Bundle) } if obj.Key != "" { t.Fatal("key is not empty:", obj.Key) } if obj.Root != string(GoDaddyRootCert) { t.Fatal("Root is not recovered") } if obj.Cert != string(GoDaddyIntermediateCert) { t.Fatal("Cert is not recovered") } if obj.KeyType != "2048-bit RSA" { t.Fatal("Incorrect key type:", obj.KeyType) } if obj.KeySize != 2048 { t.Fatal("Incorrect key size:", obj.KeySize) } if obj.Issuer != godaddyIssuerString { t.Fatal("Incorrect issuer:", obj.Issuer) } if obj.Subject != godaddySubjectString { t.Fatal("Incorrect subject:", obj.Subject) } if obj.Expires != "2026-11-16T01:54:37Z" { t.Fatal("Incorrect expiration time:", obj.Expires) } if len(obj.Hostnames) != 1 || obj.Hostnames[0] != "Go Daddy Secure Certification Authority" { t.Fatal("Incorrect hostnames:", obj.Hostnames) } if obj.OCSPSupport != true { t.Fatal("Incorrect OCSP support flag:", obj.OCSPSupport) } if obj.CRLSupport != true { t.Fatal("Incorrect CRL support flag:", obj.CRLSupport) } if len(obj.OCSP) != 1 || obj.OCSP[0] != `http://ocsp.godaddy.com` { t.Fatal("Incorrect ocsp server list:", obj.OCSP) } if obj.Signature != "SHA1WithRSA" { t.Fatal("Incorrect cert signature method:", obj.Signature) } } func TestBundleWithECDSAKeyMarshalJSON(t *testing.T) { b := newCustomizedBundlerFromFile(t, testCFSSLRootBundle, testCFSSLIntBundle, "") bundle, _ := b.BundleFromFile(leafECDSA256, leafKeyECDSA256, Optimal, "") jsonBytes, err := json.Marshal(bundle) if err != nil { t.Fatal(err) } var obj map[string]interface{} err = json.Unmarshal(jsonBytes, &obj) if err != nil { t.Fatal(err) } key := obj["key"].(string) keyBytes, _ := os.ReadFile(leafKeyECDSA256) keyBytes = bytes.Trim(keyBytes, " \n") if key != string(keyBytes) { t.Fatal("key is not recovered.") } cert := obj["crt"].(string) certBytes, _ := os.ReadFile(leafECDSA256) certBytes = bytes.Trim(certBytes, " \n") if cert != string(certBytes) { t.Fatal("cert is not recovered.") } keyType := obj["key_type"] if keyType != "256-bit ECDSA" { t.Fatal("Incorrect key type:", keyType) } } func TestBundleWithRSAKeyMarshalJSON(t *testing.T) { b := newCustomizedBundlerFromFile(t, testCFSSLRootBundle, testCFSSLIntBundle, "") bundle, _ := b.BundleFromFile(leafRSA2048, leafKeyRSA2048, Optimal, "") jsonBytes, err := json.Marshal(bundle) if err != nil { t.Fatal(err) } var obj map[string]interface{} err = json.Unmarshal(jsonBytes, &obj) if err != nil { t.Fatal(err) } key := obj["key"].(string) keyBytes, _ := os.ReadFile(leafKeyRSA2048) keyBytes = bytes.Trim(keyBytes, " \n") if key != string(keyBytes) { t.Error("key is", key) t.Error("keyBytes is", string(keyBytes)) t.Fatal("key is not recovered.") } cert := obj["crt"].(string) certBytes, _ := os.ReadFile(leafRSA2048) certBytes = bytes.Trim(certBytes, " \n") if cert != string(certBytes) { t.Fatal("cert is not recovered.") } keyType := obj["key_type"] if keyType != "2048-bit RSA" { t.Fatal("Incorrect key type:", keyType) } } // Test marshal to JSON on hostnames func TestBundleHostnamesMarshalJSON(t *testing.T) { b := newBundler(t) bundle, _ := b.BundleFromPEMorDER(GoDaddyIntermediateCert, nil, Optimal, "") expected := []byte(`["Go Daddy Secure Certification Authority"]`) hostnames, _ := json.Marshal(bundle.Hostnames) if !bytes.Equal(hostnames, expected) { t.Fatal("Hostnames construction failed for godaddy root cert.", string(hostnames)) } } // Tests on verifying the rebundle flag and error code in Bundle.Status when rebundling. func TestRebundleFromPEM(t *testing.T) { t.Skip("expired cert https://github.com/cloudflare/cfssl/issues/1237") newBundler := newCustomizedBundlerFromFile(t, testCFSSLRootBundle, interL1, "") newBundle, err := newBundler.BundleFromPEMorDER(expiredBundlePEM, nil, Optimal, "") if err != nil { t.Fatalf("Re-bundle failed. %s", err.Error()) } newChain := newBundle.Chain if len(newChain) != 2 { t.Fatalf("Expected bundle chain length is 2. Got %d.", len(newChain)) } expiredChain, _ := helpers.ParseCertificatesPEM(expiredBundlePEM) for i, cert := range newChain { old := expiredChain[i] if i == 0 { if !bytes.Equal(old.Signature, cert.Signature) { t.Fatal("Leaf cert should be the same.") } } else { if bytes.Equal(old.Signature, cert.Signature) { t.Fatal("Intermediate cert should be different.") } } } // The status must be {Code: ExpiringBit is not set, IsRebundled:true, ExpiringSKIs:{}} if len(newBundle.Status.ExpiringSKIs) != 0 || !newBundle.Status.IsRebundled || newBundle.Status.Code&errors.BundleExpiringBit != 0 { t.Fatal("Rebundle Status is incorrect.") } } // Test on verifying ubiquitous messaging in Bundle.Status. func TestUbiquitousBundle(t *testing.T) { L1Cert := readCert(interL1) // Simulate the case that L1Cert is added to trust store by one platform but not yet in another. b := newCustomizedBundlerFromFile(t, testCFSSLRootBundle, testCFSSLIntBundle, "") b.RootPool.AddCert(L1Cert) // Prepare Platforms. platformA := ubiquity.Platform{Name: "MacroSoft", Weight: 100, HashAlgo: "SHA2", KeyAlgo: "ECDSA256", KeyStoreFile: testCFSSLRootBundle} platformA.ParseAndLoad() platformB := ubiquity.Platform{Name: "Godzilla", Weight: 100, HashAlgo: "SHA2", KeyAlgo: "ECDSA256", KeyStoreFile: testCFSSLRootBundle} platformB.ParseAndLoad() platformA.KeyStore.Add(L1Cert) ubiquity.Platforms = []ubiquity.Platform{platformA, platformB} // Optimal bundle algorithm will picks up the new root and shorten the chain. optimalBundle, err := b.BundleFromFile(leafECDSA256, "", Optimal, "") if err != nil { t.Fatal("Optimal bundle failed:", err) } if len(optimalBundle.Chain) != 2 { t.Fatal("Optimal bundle failed the chain length test. Chain length:", len(optimalBundle.Chain)) } // The only trust platform is "Macrosoft". if len(optimalBundle.Status.Untrusted) != 1 { t.Fatal("Optimal bundle status has incorrect untrusted platforms", optimalBundle.Status.Untrusted) } checkUbiquityWarningAndCode(t, optimalBundle, true) // Ubiquitous bundle will remain the same. ubiquitousBundle, err := b.BundleFromFile(leafECDSA256, "", Ubiquitous, "") if err != nil { t.Fatal("Ubiquitous bundle failed") } if len(ubiquitousBundle.Chain) != 3 { t.Fatal("Ubiquitous bundle failed") } // Should be trusted by both platforms. if len(ubiquitousBundle.Status.Untrusted) != 0 { t.Fatal("Ubiquitous bundle status has incorrect untrusted platforms", len(ubiquitousBundle.Status.Untrusted)) } checkUbiquityWarningAndCode(t, ubiquitousBundle, false) } func TestUbiquityBundleWithoutMetadata(t *testing.T) { b := newCustomizedBundlerFromFile(t, testCFSSLRootBundle, testCFSSLIntBundle, "") L1Cert := readCert(interL1) b.RootPool.AddCert(L1Cert) // Without platform info, ubiquitous bundling falls back to optimal bundling. ubiquity.Platforms = nil nuBundle, err := b.BundleFromFile(leafECDSA256, "", Ubiquitous, "") if err != nil { t.Fatal("Ubiquitous-fall-back-to-optimal bundle failed: ", err) } if len(nuBundle.Chain) != 2 { t.Fatal("Ubiquitous-fall-back-to-optimal bundle failed") } // Should be trusted by all (i.e. zero) platforms. if len(nuBundle.Status.Untrusted) != 0 { t.Fatal("Ubiquitous-fall-back-to-optimal bundle status has incorrect untrusted platforms", len(nuBundle.Status.Untrusted)) } checkUbiquityWarningAndCode(t, nuBundle, true) } func checkUbiquityWarningAndCode(t *testing.T, bundle *Bundle, expected bool) { found := false for _, msg := range bundle.Status.Messages { if strings.Contains(msg, untrustedWarningStub) || strings.Contains(msg, ubiquityWarning) { found = true } } if found != expected { t.Fatal("Expected ubiquity warning: ", expected, " Found ubiquity warning:", found) } // check status code if expected && bundle.Status.Code&errors.BundleNotUbiquitousBit == 0 { t.Fatal("Bundle status doesn't set BundleNotUbiquitousBit :", bundle.Status.Code) } } // Regression test on bundle with all flavors: // Ubiquitous bundle optimizes bundle length given the platform ubiquity is the same; Force bundle // with return the same bundle; Optimal bundle always chooses shortest bundle length. func TestForceBundle(t *testing.T) { // create a CA signer and signs a new intermediate with SHA-2 caSigner := makeCASignerFromFile(testCAFile, testCAKeyFile, x509.SHA256WithRSA, t) interL1Bytes := signCSRFile(caSigner, interL1CSR, t) // create a inter L1 signer interL1KeyBytes, err := os.ReadFile(interL1Key) if err != nil { t.Fatal(err) } interL1Signer := makeCASigner(interL1Bytes, interL1KeyBytes, x509.SHA256WithRSA, t) // sign a level 2 intermediate interL2Bytes := signCSRFile(interL1Signer, interL2CSR, t) // create a inter L2 signer interL2KeyBytes, err := os.ReadFile(interL2Key) if err != nil { t.Fatal(err) } interL2Signer := makeCASigner(interL2Bytes, interL2KeyBytes, x509.ECDSAWithSHA256, t) // interL2 sign a leaf cert leafBytes := signCSRFile(interL2Signer, leafCSR, t) // create two platforms // both trust the CA cert and L1 intermediate caBytes, err := os.ReadFile(testCAFile) if err != nil { t.Fatal(err) } ca, _ := helpers.ParseCertificatePEM(caBytes) interL1, _ := helpers.ParseCertificatePEM(interL1Bytes) platformA := ubiquity.Platform{ Name: "A", Weight: 100, KeyStore: make(ubiquity.CertSet), HashUbiquity: ubiquity.SHA2Ubiquity, KeyAlgoUbiquity: ubiquity.ECDSA521Ubiquity, } platformB := ubiquity.Platform{ Name: "B", Weight: 100, KeyStore: make(ubiquity.CertSet), HashUbiquity: ubiquity.SHA2Ubiquity, KeyAlgoUbiquity: ubiquity.ECDSA521Ubiquity, } platformA.KeyStore.Add(ca) platformA.KeyStore.Add(interL1) platformB.KeyStore.Add(ca) platformB.KeyStore.Add(interL1) ubiquity.Platforms = []ubiquity.Platform{platformA, platformB} caBundle := string(caBytes) + string(interL1Bytes) interBundle := string(interL2Bytes) + string(interL1Bytes) fullChain := string(leafBytes) + string(interL2Bytes) + string(interL1Bytes) // create bundler b, err := NewBundlerFromPEM([]byte(caBundle), []byte(interBundle)) if err != nil { t.Fatal(err) } // The input PEM bundle is 3-cert chain. bundle, err := b.BundleFromPEMorDER([]byte(fullChain), nil, Force, "") if err != nil { t.Fatal("Force bundle failed:", err) } if len(bundle.Chain) != 3 { t.Fatal("Force bundle failed:") } if len(bundle.Status.Untrusted) != 0 { t.Fatal("Force bundle failed:") } // With ubiquity flavor, we should have a shorter chain, given L1 is ubiquitous trusted. bundle, err = b.BundleFromPEMorDER([]byte(fullChain), nil, Ubiquitous, "") if err != nil { t.Fatal("Ubiquitous bundle failed:", err) } if len(bundle.Chain) != 2 { t.Fatal("Ubiquitous bundle failed:") } if len(bundle.Status.Untrusted) != 0 { t.Fatal("Ubiquitous bundle failed:") } // With optimal flavor, we should have a shorter chain as well. bundle, err = b.BundleFromPEMorDER([]byte(fullChain), nil, Optimal, "") if err != nil { t.Fatal("Optimal bundle failed:", err) } if len(bundle.Chain) != 2 { t.Fatal("Optimal bundle failed:") } if len(bundle.Status.Untrusted) != 0 { t.Fatal("Optimal bundle failed:") } } func TestUpdateIntermediate(t *testing.T) { // create a CA signer and signs a new intermediate with SHA-2 caSigner := makeCASignerFromFile(testCAFile, testCAKeyFile, x509.SHA256WithRSA, t) sha2InterBytes := signCSRFile(caSigner, interL1CSR, t) interKeyBytes, err := os.ReadFile(interL1Key) if err != nil { t.Fatal(err) } // create a intermediate signer from intermediate cert/key sha2InterSigner := makeCASigner(sha2InterBytes, interKeyBytes, x509.SHA256WithRSA, t) // sign a leaf cert leafBytes := signCSRFile(sha2InterSigner, leafCSR, t) // read CA cert bytes caCertBytes, err := os.ReadFile(testCAFile) if err != nil { t.Fatal(err) } // create a bundler with the test root CA and no intermediates b, err := NewBundlerFromPEM(caCertBytes, nil) if err != nil { t.Fatal(err) } // create a cert bundle: leaf + inter chainBytes := string(leafBytes) + string(sha2InterBytes) bundle, err := b.BundleFromPEMorDER([]byte(chainBytes), nil, Ubiquitous, "") if err != nil { t.Fatal("Valid bundle should be accepted. error:", err) } if bundle.Status.IsRebundled { t.Fatal("rebundle should never happen here", bundle.Status) } // Now bundle with the leaf cert bundle2, err := b.BundleFromPEMorDER(leafBytes, nil, Ubiquitous, "") if err != nil { t.Fatal("Valid bundle should be accepted. error:", err) } if !bundle2.Status.IsRebundled { t.Fatal("rebundle should happen here") } } func TestForceBundleNoFallback(t *testing.T) { // create a CA signer and signs a new intermediate with SHA-2 caSigner := makeCASignerFromFile(testCAFile, testCAKeyFile, x509.SHA256WithRSA, t) sha2InterBytes := signCSRFile(caSigner, interL1CSR, t) interKeyBytes, err := os.ReadFile(interL1Key) if err != nil { t.Fatal(err) } // create a intermediate signer from intermediate cert/key sha2InterSigner := makeCASigner(sha2InterBytes, interKeyBytes, x509.SHA256WithRSA, t) // sign a leaf cert leafBytes := signCSRFile(sha2InterSigner, leafCSR, t) // read CA cert bytes caCertBytes, err := os.ReadFile(testCAFile) if err != nil { t.Fatal(err) } // create a bundler with the test root CA and the new intermediate b, err := NewBundlerFromPEM(caCertBytes, sha2InterBytes) if err != nil { t.Fatal(err) } // Now bundle with the leaf cert with Force bundle, err := b.BundleFromPEMorDER(leafBytes, nil, Force, "") if err != nil { t.Fatal("Valid bundle should be generated, error:", err) } // Force bundle fallback to creating a valid bundle if len(bundle.Chain) != 1 { t.Fatal("incorrect bundling") } if bundle.Status.IsRebundled { t.Fatal("rebundle should happen here") } } // Regression test: ubiquity bundle test with SHA2-homogeneous preference should not override root ubiquity. func TestSHA2HomogeneityAgainstUbiquity(t *testing.T) { // create a CA signer and signs a new intermediate with SHA-1 caSigner := makeCASignerFromFile(testCAFile, testCAKeyFile, x509.SHA1WithRSA, t) interL1Bytes := signCSRFile(caSigner, interL1CSR, t) // create a inter L1 signer interL1KeyBytes, err := os.ReadFile(interL1Key) if err != nil { t.Fatal(err) } interL1Signer := makeCASigner(interL1Bytes, interL1KeyBytes, x509.SHA256WithRSA, t) // sign a level 2 intermediate interL2Bytes := signCSRFile(interL1Signer, interL2CSR, t) // create a inter L2 signer interL2KeyBytes, err := os.ReadFile(interL2Key) if err != nil { t.Fatal(err) } interL2Signer := makeCASigner(interL2Bytes, interL2KeyBytes, x509.ECDSAWithSHA256, t) // interL2 sign a leaf cert leafBytes := signCSRFile(interL2Signer, leafCSR, t) // create two platforms // platform A trusts the CA cert and L1 intermediate // platform B trusts the CA cert caBytes, err := os.ReadFile(testCAFile) if err != nil { t.Fatal(err) } ca, _ := helpers.ParseCertificatePEM(caBytes) interL1, _ := helpers.ParseCertificatePEM(interL1Bytes) platformA := ubiquity.Platform{ Name: "A", Weight: 100, KeyStore: make(ubiquity.CertSet), HashUbiquity: ubiquity.SHA2Ubiquity, KeyAlgoUbiquity: ubiquity.ECDSA521Ubiquity, } platformB := ubiquity.Platform{ Name: "B", Weight: 100, KeyStore: make(ubiquity.CertSet), HashUbiquity: ubiquity.SHA2Ubiquity, KeyAlgoUbiquity: ubiquity.ECDSA521Ubiquity, } platformA.KeyStore.Add(ca) platformA.KeyStore.Add(interL1) platformB.KeyStore.Add(ca) ubiquity.Platforms = []ubiquity.Platform{platformA, platformB} caBundle := string(caBytes) + string(interL1Bytes) interBundle := string(interL2Bytes) + string(interL1Bytes) fullChain := string(leafBytes) + string(interL2Bytes) + string(interL1Bytes) // create bundler b, err := NewBundlerFromPEM([]byte(caBundle), []byte(interBundle)) if err != nil { t.Fatal(err) } // The input PEM bundle is 3-cert chain. bundle, err := b.BundleFromPEMorDER([]byte(fullChain), nil, Force, "") if err != nil { t.Fatal("Force bundle failed:", err) } if len(bundle.Chain) != 3 { t.Fatal("Force bundle failed:") } if len(bundle.Status.Untrusted) != 0 { t.Fatal("Force bundle failed:") } // With ubiquity flavor, we should not sacrifice trust store ubiquity and rebundle with a shorter chain // with SHA2 homogenity. bundle, err = b.BundleFromPEMorDER([]byte(fullChain), nil, Ubiquitous, "") if err != nil { t.Fatal("Ubiquitous bundle failed:", err) } if len(bundle.Chain) != 3 { t.Fatal("Ubiquitous bundle failed:") } if len(bundle.Status.Untrusted) != 0 { t.Fatal("Ubiquitous bundle failed:") } // With optimal flavor, we should have a shorter chain. bundle, err = b.BundleFromPEMorDER([]byte(fullChain), nil, Optimal, "") if err != nil { t.Fatal("Optimal bundle failed:", err) } if len(bundle.Chain) != 2 { t.Fatal("Optimal bundle failed:") } if len(bundle.Status.Untrusted) == 0 { t.Fatal("Optimal bundle failed:") } } func checkSHA2WarningAndCode(t *testing.T, bundle *Bundle, expected bool) { found := false for _, msg := range bundle.Status.Messages { if strings.Contains(msg, sha2Warning) { found = true } } if found != expected { t.Fatal("Expected ubiquity warning: ", expected, " Found ubiquity warning:", found) } // check status code if bundle.Status.Code&errors.BundleNotUbiquitousBit == 0 { t.Fatal("Bundle status code is incorrect:", bundle.Status.Code) } } func checkECDSAWarningAndCode(t *testing.T, bundle *Bundle, expected bool) { found := false for _, msg := range bundle.Status.Messages { if strings.Contains(msg, ecdsaWarning) { found = true } } if found != expected { t.Fatal("Expected ubiquity warning: ", expected, " Found ubiquity warning:", found) } // check status code if bundle.Status.Code&errors.BundleNotUbiquitousBit == 0 { t.Fatal("Bundle status code is incorrect:", bundle.Status.Code) } } // Regression test on SHA-2 Warning // Riot Games once bundle a cert issued by DigiCert SHA2 High Assurance Server CA. The resulting // bundle uses SHA-256 which is not supported in Windows XP SP2. We should present a warning // on this. func TestSHA2Warning(t *testing.T) { // create a CA signer and signs a new intermediate with SHA-2 caSigner := makeCASignerFromFile(testCAFile, testCAKeyFile, x509.SHA256WithRSA, t) sha2InterBytes := signCSRFile(caSigner, interL1CSR, t) // read CA cert bytes caCertBytes, err := os.ReadFile(testCAFile) if err != nil { t.Fatal(err) } // create a bundler with the test root CA and no intermediates b, err := NewBundlerFromPEM(caCertBytes, nil) if err != nil { t.Fatal(err) } optimalBundle, err := b.BundleFromPEMorDER(sha2InterBytes, nil, Optimal, "") if err != nil { t.Fatal("Optimal bundle failed:", err) } checkSHA2WarningAndCode(t, optimalBundle, true) // Ubiquitous bundle will include a 2nd intermediate CA. ubiquitousBundle, err := b.BundleFromPEMorDER(sha2InterBytes, nil, Ubiquitous, "") if err != nil { t.Fatal("Ubiquitous bundle failed") } checkSHA2WarningAndCode(t, ubiquitousBundle, true) } // Regression test on ECDSA Warning // A test bundle that contains ECDSA384 and SHA-2. Expect ECDSA warning and SHA-2 warning. func TestECDSAWarning(t *testing.T) { b := newCustomizedBundlerFromFile(t, testCAFile, interL1SHA1, "") optimalBundle, err := b.BundleFromFile(interL2SHA2, "", Optimal, "") if err != nil { t.Fatal("Optimal bundle failed:", err) } checkSHA2WarningAndCode(t, optimalBundle, true) checkECDSAWarningAndCode(t, optimalBundle, true) } // === Helper function block === // readCert read a PEM file and returns a cert. func readCert(filename string) *x509.Certificate { bytes, _ := os.ReadFile(filename) cert, _ := helpers.ParseCertificatePEM(bytes) return cert } // newBundler is a helper function that returns a new Bundler. If it fails to do so, // it fails the test suite immediately. func newBundler(t *testing.T) (b *Bundler) { b, err := NewBundler(testCaBundle, testIntCaBundle) if err != nil { t.Fatal(err) } return } // newBundler creates bundler from byte slices of CA certs and intermediate certs in PEM format func newBundlerFromPEM(t *testing.T, caBundlePEM, intBundlePEM []byte) (b *Bundler) { b, err := NewBundlerFromPEM(caBundlePEM, intBundlePEM) if err != nil { t.Fatal(err) } return } // newCustomizedBundleCreator is a helper function that returns a new Bundler // takes specified CA bundle, intermediate bundle, and any additional intermediate certs to generate a bundler. func newCustomizedBundlerFromFile(t *testing.T, caBundle, intBundle, adhocInters string) (b *Bundler) { b, err := NewBundler(caBundle, intBundle) if err != nil { t.Fatal(err) } if adhocInters != "" { moreIntersPEM, err := os.ReadFile(adhocInters) if err != nil { t.Fatalf("Read additional intermediates failed. %v", err) } intermediates, err := helpers.ParseCertificatesPEM(moreIntersPEM) if err != nil { t.Fatalf("Parsing additional intermediates failed. %s", err.Error()) } for _, c := range intermediates { b.IntermediatePool.AddCert(c) } } return } // newBundlerWithoutInters is a helper function that returns a bundler with an empty // intermediate cert pool. Such bundlers can help testing error handling in cert // bundling. func newBundlerWithoutInters(t *testing.T) (b *Bundler) { b = newBundler(t) // Re-assign an empty intermediate cert pool b.IntermediatePool = x509.NewCertPool() return } // newBundlerWithoutRoots is a helper function that returns a bundler with an empty // root cert pool. Such bundlers can help testing error handling in cert // bundling. func newBundlerWithoutRoots(t *testing.T) (b *Bundler) { b = newBundler(t) // Re-assign an empty root cert pool b.RootPool = x509.NewCertPool() return } func newBundlerWithoutRootsAndInters(t *testing.T) *Bundler { b, err := NewBundler("", "") if err != nil { t.Fatal(err) } return b } // A helper function that returns a errorCallback function which expects certain error content in // an error message. func ExpectErrorMessage(expectedErrorContent string) func(*testing.T, error) { return func(t *testing.T, err error) { if err == nil { t.Fatalf("Expected error has %s. Got nothing.", expectedErrorContent) } else if !strings.Contains(err.Error(), expectedErrorContent) { t.Fatalf("Expected error has %s. Got %s", expectedErrorContent, err.Error()) } } } // A helper function that returns a errorCallback function which inspect error message for // all expected messages. func ExpectErrorMessages(expectedContents []string) func(*testing.T, error) { return func(t *testing.T, err error) { if err == nil { t.Fatalf("Expected error has %s. Got nothing.", expectedContents) } else { for _, expected := range expectedContents { if !strings.Contains(err.Error(), expected) { t.Fatalf("Expected error has %s. Got %s", expected, err.Error()) } } } } } // A helper function that returns a bundle chain length checking function func ExpectBundleLength(expectedLen int) func(*testing.T, *Bundle) { return func(t *testing.T, bundle *Bundle) { if bundle == nil { t.Fatalf("Cert bundle should have a chain of length %d. Got nil.", expectedLen) } else if len(bundle.Chain) != expectedLen { t.Fatalf("Cert bundle should have a chain of length %d. Got chain length %d.", expectedLen, len(bundle.Chain)) } } } func TestBundlerWithEmptyRootInfo(t *testing.T) { t.Skip("broken relating to https://github.com/cloudflare/cfssl/issues/1230") b := newBundlerWithoutRootsAndInters(t) // "force" bundle should be ok bundle, err := b.BundleFromPEMorDER(GoDaddyIntermediateCert, nil, Force, "") if err != nil { t.Fatal(err) } checkBundleFunc := ExpectBundleLength(1) checkBundleFunc(t, bundle) // force non-verifying bundle should fail. _, err = b.BundleFromFile(badBundle, "", Force, "") if err == nil { t.Fatal("expected error. but no error occurred") } checkErrorFunc := ExpectErrorMessage("\"code\":1200") checkErrorFunc(t, err) // "optimal" and "ubiquitous" bundle should be ok bundle, err = b.BundleFromPEMorDER(GoDaddyIntermediateCert, nil, Ubiquitous, "") if err != nil { t.Fatal(err) } checkBundleFunc = ExpectBundleLength(1) checkBundleFunc(t, bundle) bundle, err = b.BundleFromPEMorDER(GoDaddyIntermediateCert, nil, Optimal, "") if err != nil { t.Fatal(err) } checkBundleFunc = ExpectBundleLength(1) checkBundleFunc(t, bundle) // bundle remote should be ok bundle, err = b.BundleFromRemote("www.google.com", "", Ubiquitous) if err != nil { t.Fatal(err) } checkBundleFunc = ExpectBundleLength(2) checkBundleFunc(t, bundle) } func TestBundlerClientAuth(t *testing.T) { b, err := NewBundler("testdata/client-auth/root.pem", "testdata/client-auth/int.pem") if err != nil { t.Fatal(err) } for _, leafFile := range []string{"testdata/client-auth/leaf-server.pem", "testdata/client-auth/leaf-client.pem"} { if _, err := b.BundleFromFile(leafFile, "", Optimal, ""); err != nil { t.Fatal(err) } } } ================================================ FILE: bundler/doc.go ================================================ // Package bundler provides an API for creating certificate bundles, // which contain a trust chain of certificates. Generally, the bundles // will also include the private key (but this is not strictly // required). In this package, a bundle refers to a certificate with // full trust chain -- all certificates in the chain in one file or // buffer. // // The first step in creating a certificate bundle is to create a // Bundler. A Bundler must be created from a pre-existing certificate // authority bundle and an intermediate certificate bundle. Once the // Bundler is initialised, bundles may be created using a variety of // methods: from PEM- or DER-encoded files, directly from the relevant // Go structures, or by starting with the certificate from a remote // system. These functions return a Bundle value, which may be // serialised to JSON. package bundler ================================================ FILE: bundler/testdata/bad-bundle.pem ================================================ -----BEGIN CERTIFICATE----- MIICoDCCAiagAwIBAgITCWxPP1OUyLXZWxBBaLbwZxa0sTAKBggqhkjOPQQDAzCB jDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh biBGcmFuY2lzY28xEzARBgNVBAoTCkNsb3VkRmxhcmUxHDAaBgNVBAsTE1N5c3Rl bXMgRW5naW5lZXJpbmcxHTAbBgNVBAMTFGNsb3VkZmxhcmUtaW50ZXIuY29tMB4X DTE5MDUwMTAwMDAwMFoXDTI4MDYxNTA4MDAwMFowgYsxCzAJBgNVBAYTAlVTMRMw EQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYD VQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRww GgYDVQQDExNjbG91ZGZsYXJlLWxlYWYuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEjEb98b3L+COUBe8Hvtt4REtsGig33wUYUDFVQDkiCXKW+CZ83FSYjyYz ZTD23M4ub285ECtpJIzj/qJKkImt4KNmMGQwDgYDVR0PAQH/BAQDAgKkMBIGA1Ud EwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFKnNVsuomAwTY4BUp/FrWll3d8iuMB8G A1UdIwQYMBaAFD3f3FiGmOjKKSDupXSse/XS6RdXMAoGCCqGSM49BAMDA2gAMGUC MQC3oiPOxkBIfMChEqUjKCFwIwRuEyGVr02EXB5reJ0Jtix5ixqykOm8iyd4Afak szcCMBiLGSvek7JGbZRgeWX2J+42Hp0PcV3X1M4Exmjd8rNKWB2LEhqJuaXdidjb itmQYw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC8zCCAnqgAwIBAgIUKVhonSnxAIlmpP3xNH2bQp9xcUMwCgYIKoZIzj0EAwMw gYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T YW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0 ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAe Fw0xOTA1MDgyMjM2MDBaFw0yMDA1MDcyMjM2MDBaMIGLMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEG A1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEc MBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTB2MBAGByqGSM49AgEGBSuBBAAi A2IABNYivDDh3Iikkb+3/Oocity4JQXmxLP2njZThYNtR4y7Bxixp05KLoq8gtaz yccDklueu4OWFnpmkjyqPQ+0MIf/BJKoA4Q4iNiCN/ZfF690LR/pZPrMRZuWSGVb 2890L6OBmzCBmDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFDmNWkY9a2tS8p4M9RGY i2MJRbo/MB8GA1UdIwQYMBaAFD3f3FiGmOjKKSDupXSse/XS6RdXMBkGA1UdEQQS MBCCDmNmc3NsLWxlYWYuY29tMAoGCCqGSM49BAMDA2cAMGQCMBtWvrf8sfPDt5wi VOwDrt75NJOL/ZgJJxtufqpjgH+zdtAyMsoqarTjUAYB9WqoPgIwTAe+wDGT8Jq+ iCXMJ8nddE4P59aNs26VLSnYpyqItyr8QyZwgwtbRk/TJ5Piv/1C -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/ca-bundle.crt.metadata ================================================ [ { "name":"Chrome Browser M39", "weight": 0, "hash_algo": "SHA2", "key_algo": "ECDSA256", "hash_algo_expiry": { "target": "SHA1", "effective_date": "2014-09-26T00:00:00Z", "expiry_deadline": "2017-01-01T00:00:00Z" } }, { "name":"Chrome Browser M40", "weight": 0, "hash_algo": "SHA2", "key_algo": "ECDSA256", "hash_algo_expiry": { "target": "SHA1", "effective_date": "2014-09-26T00:00:00Z", "expiry_deadline": "2016-06-01T00:00:00Z" } }, { "name":"Chrome Browser M41 and later", "weight": 0, "hash_algo": "SHA2", "key_algo": "ECDSA256", "hash_algo_expiry": { "target": "SHA1", "effective_date": "2014-09-26T00:00:00Z", "expiry_deadline": "2016-01-01T00:00:00Z" } }, { "name":"Mozilla", "weight": 99, "hash_algo": "SHA2", "key_algo": "ECDSA256", "keystore": "nss.pem" }, { "name":"OSX", "weight": 99, "hash_algo": "SHA2", "key_algo": "ECDSA256", "keystore": "osx.pem" }, { "name":"Android 2.2 Froyo", "weight": 1, "hash_algo": "SHA2", "key_algo": "RSA", "keystore": "froyo.pem" } ] ================================================ FILE: bundler/testdata/ca-bundle.pem ================================================ -----BEGIN CERTIFICATE----- MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR 4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5 FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx lA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0f zGVuDLDQVoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHi TkVWaR94AoDa3EeRKbs2yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0G CSqGSIb3DQEBBQUAA4GBAFgVKTk8d6PaXCUDfGD67gmZPCcQcMgMCeazh88K4hiW NWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n0a3hUKw8fGJLj7qE1xIV Gx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZRjXZ+Hxb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCEAq6HgBiMui0NiZdH3zNiWYwDQYJKoZIhvcNAQEFBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G CSqGSIb3DQEBBQUAA4GBAIDToA+IyeVoW4R7gB+nt+MjWBEc9RTwWBKMi99x2ZAk EXyge8N6GRm9cr0gvwA63/rVeszC42JFi8tJg5jBcGnQnl6CjDVHjk8btB9jAa3k ltax7nosZm4XNq8afjgGhixrTcsnkm54vwDVAcCxB8MJqmSFKPKdc57PYDoKHUpI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i 2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ 2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY oJ2daZH9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP T8qAkbYp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68 DzFc6PLZ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn jBJ7xUS0rg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ +mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c 2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te 2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO 8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u 7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH 4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er fF6adulZkMV8gzURZVE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtTCCAp2gAwIBAgIIBhDCeat3PfIwDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UE BhMCQ0gxEjAQBgNVBAoTCVN3aXNzU2lnbjEyMDAGA1UEAxMpU3dpc3NTaWduIENB IChSU0EgSUsgTWF5IDYgMTk5OSAxODowMDo1OCkxHzAdBgkqhkiG9w0BCQEWEGNh QFN3aXNzU2lnbi5jb20wHhcNMDAxMTI2MjMyNzQxWhcNMzExMTI2MjMyNzQxWjB2 MQswCQYDVQQGEwJDSDESMBAGA1UEChMJU3dpc3NTaWduMTIwMAYDVQQDEylTd2lz c1NpZ24gQ0EgKFJTQSBJSyBNYXkgNiAxOTk5IDE4OjAwOjU4KTEfMB0GCSqGSIb3 DQEJARYQY2FAU3dpc3NTaWduLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKw5fjnmNneLQlUCQG8jQLwwfbrOZoUwNX8cbNqhxK03/xUloFVgAt+S Te2RxNXaCAXLBPn5ZST35TLV57aLmbHCtifv3YZqaaQGvjedltIBMJihJhZ+h3LY SKsUb+xEJ3x5ZUf8jP+Q1g57y1s8SnBFWN/ni5NkF1Y1y31VwOi9wiOf/VISL+uu SC4i1CP1Kbz3BDs6Hht1GpRYCbJ/K0bc9oJSpWpT5PGONsGIawqMbJuyoDghsXQ1 pbn2e8K64BSscGZVZTNooSGgNiHmACNJBYXiWVWrwXPF4l6SddmC3Rj0aKXjgECc FkHLDQcsM5JsK2ZLryTDUsQFbxVP2ikCAwEAAaNHMEUwCwYDVR0PBAQDAgEGMAwG A1UdEwQFMAMBAf8wHQYDVR0OBBYEFJbXcc05KtT8iLGKq1N4ae+PR34WMAkGA1Ud IwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAKMy6W8HvZdS1fBpEUzl6Lvw50bgE1Xc HU1JypSBG9mhdcXZo5AlPB4sCvx9Dmfwhyrdsshc0TP2V3Vh6eQqnEF5qB4lVziT Bko9mW6Ot+pPnwsy4SHpx3rw6jCYnOqfUcZjWqqqRrq/3P1waz+Mn4cLMVEg3Xaz qYov/khvSqS0JniwjRlo2H6f/1oVUKZvP+dUhpQepfZrOqMAWZW4otp6FolyQyeU NN6UCRNiUKl5vTijbKwUUwfER/1Vci3M1/O1QCfttQ4vRN4Buc0xqYtGL3cd5WiO vWzyhlTzAI6VUdNkQhhHJSAyTpj6dmXDRzrryoFGa2PjgESxz7XBaSI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg /9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch 6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 7CAFYd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2 MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym 1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb 2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2 MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC 206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2 JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9 BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67 Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3 +L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2 LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8 CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw RY8mkaKO/qk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAwMFoXDTM3MTEyMDE1 MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U 0pPlLYnKhHw/EEMbjIt8hFj4JHxIzyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItI TuLCxFlpMGK2MKKMCxGZYTVtfu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAf RC+iYkGzuxgh28pxPIzstrkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqF zQ6axOAAsNUl6twr5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqh BC4aMqiaILGcLCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEA AaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jY PXy+XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/ BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNMeUWn 9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7CegCgTXT Ct8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77BfWgDrvq2g+EQF Z7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oTLW4jYYehY0KswsuX n2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCzvhGbRWeDhhmH05i9CBoW H1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmwX7A5KGgOc90lmt4S -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAwMFoXDTM3MDkyODIz NDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ 7ouZzU9AhqS2TcnZsdw8TQ2FTBVsRotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilb m2BPJoPRYxJWSXakFsKlnUWsi4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOY xFSMFkpBd4aVdQxHAWZg/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZ YYCLqJV+FNwSbKTQ2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbq JS5Gr42whTg0ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fx I2rSAG2X+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETz kxmlJ85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNoKk/S Btc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJKg71ZDIM gtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1ExMVCgyhwn2RAu rda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaAFE9pbQN+nZ8HGEO8txBO 1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAO/Ouyugu h4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0cnAxa8cZmIDJgt43d15Ui47y6mdP yXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRFASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q 7C+qPBR7V8F+GBRn7iTGvboVsNIYvbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKT RuidDV29rs4prWPVVRaAMCf/drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ ClTluUI8JPu3B5wwn3la5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyB M5kYJRF3p+v9WAksmWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQ my8YJPamTQr5O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xO AU++CrYD062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT 9Y41xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOLZ8/5 fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs 6GAqm4VKQPNriiTsBhYscw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl pYYsfPQS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB 8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R 85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm 4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y /X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr 2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s 2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9 BKNDLdr8C2LqL19iUw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq 7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p 26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi 1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu tGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe 3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk 3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz 6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW 1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAmygAwIBAgIBCTANBgkqhkiG9w0BAQUFADAzMQswCQYDVQQGEwJDTjER MA8GA1UEChMIVW5pVHJ1c3QxETAPBgNVBAMTCFVDQSBSb290MB4XDTA0MDEwMTAw MDAwMFoXDTI5MTIzMTAwMDAwMFowMzELMAkGA1UEBhMCQ04xETAPBgNVBAoTCFVu aVRydXN0MREwDwYDVQQDEwhVQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBALNdB8qGJn1r4vs4CQ7MgsJqGgCiFV/W6dQBt1YDAVmP9ThpJHbC XivF9iu/r/tB/Q9a/KvXg3BNMJjRnrJ2u5LWu+kQKGkoNkTo8SzXWHwk1n8COvCB a2FgP/Qz3m3l6ihST/ypHWN8C7rqrsRoRuTej8GnsrZYWm0dLNmMOreIy4XU9+gD Xv2yTVDo1h//rgI/i0+WITyb1yXJHT/7mLFZ5PCpO6+zzYUs4mBGzG+OoOvwNMXx QhhgrhLtRnUc5dipllq+3lrWeGeWW5N3UPJuG96WUUqm1ktDdSFmjXfsAoR2XEQQ th1hbOSjIH23jboPkXXHjd+8AmCoKai9PUMCAwEAAaOBojCBnzALBgNVHQ8EBAMC AQYwDAYDVR0TBAUwAwEB/zBjBgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIG CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcD BwYIKwYBBQUHAwgGCCsGAQUFBwMJMB0GA1UdDgQWBBTbHzXza0z/QjFkm827Wh4d SBC37jANBgkqhkiG9w0BAQUFAAOCAQEAOGy3iPGt+lg3dNHocN6cJ1nL5BXXoMNg 14iABMUwTD3UGusGXllH5rxmy+AI/Og17GJ9ysDawXiv5UZv+4mCI4/211NmVaDe JRI7cTYWVRJ2+z34VFsxugAG+H1V5ad2g6pcSpemKijfvcZsCyOVjjN/Hl5AHxNU LJzltQ7dFyiuawHTUin1Ih+QOfTcYmjwPIZH7LgFRbu3DJaUxmfLI3HQjnQi1kHr A6i26r7EARK1s11AdgYg1GS4KUYGis4fk5oQ7vuqWrTcL9Ury/bXBYSYBZELhPc9 +tb5evosFeo2gkO3t7jj83EB7UNDogVFwygFBzXjAaU4HoDU18PZ3g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB /wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG 9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m 1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH 6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0 MRMwEQYDVQQDEwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQG EwJJTDAeFw0wNDAzMjQxMTMyMThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMT CkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNpZ24xCzAJBgNVBAYTAklMMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49qROR+WCf4C9DklBKK 8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTyP2Q2 98CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb 2CEJKHxNGGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxC ejVb7Us6eva1jsz/D3zkYDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7Kpi Xd3DTKaCQeQzC6zJMw9kglcq/QytNuEMrkvF7zuZ2SOzW120V+x0cAwqTwIDAQAB o4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2Zl ZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0PAQH/BAQD AgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRL AZs+VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWd foPPbrxHbvUanlR2QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0M cXS6hMTXcpuEfDhOZAYnKuGntewImbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq 8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb/627HOkthIDYIb6FUtnUdLlp hbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VGzT2ouvDzuFYk Res3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U AGegcQCCSA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu MQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwx GzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjEL MAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGtWhf HZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs49oh gHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sW v+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ue Mv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr 9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt 6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7 MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNl Y3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58 ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkq hkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7p iL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtC dsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAmlaxMDPWL kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDQzCCAiugAwIBAgIQX/h7KCtU3I1CoxW1aMmt/zANBgkqhkiG9w0BAQUFADA1 MRYwFAYDVQQKEw1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENB IDIwNDgwHhcNMDQwNTE0MjAxNzEyWhcNMjkwNTE0MjAyNTQyWjA1MRYwFAYDVQQK Ew1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENBIDIwNDgwggEg MA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQCwmrmrp68Kd6ficba0ZmKUeIhH xmJVhEAyv8CrLqUccda8bnuoqrpu0hWISEWdovyD0My5jOAmaHBKeN8hF570YQXJ FcjPFto1YYmUQ6iEqDGYeJu5Tm8sUxJszR2tKyS7McQr/4NEb7Y9JHcJ6r8qqB9q VvYgDxFUl4F1pyXOWWqCZe+36ufijXWLbvLdT6ZeYpzPEApk0E5tzivMW/VgpSdH jWn0f84bcN5wGyDWbs2mAag8EtKpP6BrXruOIIt6keO1aO6g58QBdKhTCytKmg9l Eg6CTY5j/e/rmxrbU6YTYK/CfdfHbBcl1HP7R2RQgYCUTOG/rksc35LtLgXfAgED o1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJ/PI FR5umgIJFq0roIlgX9p7L6owEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEF BQADggEBAJ2dhISjQal8dwy3U8pORFBi71R803UXHOjgxkhLtv5MOhmBVrBW7hmW Yqpao2TB9k5UM8Z3/sUcuuVdJcr18JOagxEu5sv4dEX+5wW4q+ffy0vhN4TauYuX cB7w4ovXsNgOnbFp1iqRe6lJT37mjpXYgyc81WhJDtSd9i7rp77rMKSsH0T8lasz Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4 CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICmDCCAgGgAwIBAgIBDjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJVUzEY MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNFQ0ExFDASBgNVBAMT C0VDQSBSb290IENBMB4XDTA0MDYxNDEwMjAwOVoXDTQwMDYxNDEwMjAwOVowSzEL MAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMD RUNBMRQwEgYDVQQDEwtFQ0EgUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEArkr2eXIS6oAKIpDkOlcQZdMGdncoygCEIU+ktqY3of5SVVXU7/it7kJ1 EUzR4ii2vthQtbww9aAnpQxcEmXZk8eEyiGEPy+cCQMllBY+efOtKgjbQNDZ3lB9 19qzUJwBl2BMxslU1XsJQw9SK10lPbQm4asa8E8e5zTUknZBWnECAwEAAaOBizCB iDAfBgNVHSMEGDAWgBT2uAQnDlYW2blj2f2hVGVBoAhILzAdBgNVHQ4EFgQU9rgE Jw5WFtm5Y9n9oVRlQaAISC8wDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB Af8wJQYDVR0gBB4wHDAMBgpghkgBZQMCAQwBMAwGCmCGSAFlAwIBDAIwDQYJKoZI hvcNAQEFBQADgYEAHh0EQY2cZ209aBb5q0wW1ER0dc4OGzsLyqjHfaQ4TEaMmUwL AJRta/c4KVWLiwbODsvgJk+CaWmSL03gRW/ciVb/qDV7qh9Pyd1cOlanZTAnPog2 i82yL3i2fK9DCC84uoxEQbgqK2jx9bIjFTwlAqITk9fGAm5mdT84IEwq1Gw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h /t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf ReYNnyicsbkqWletNw+vHX/bvZ8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf 8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN +lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA 1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ O+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJVUzEY MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMjAeFw0wNDEyMTMxNTAwMTBaFw0y OTEyMDUxNTAwMTBaMFsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRYwFAYDVQQDEw1Eb0Qg Um9vdCBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCzB9o07 rP8/PNZxvrh0IgfscEEV/KtA4weqwcPYn/7aTDq/P8jYKHtLNgHArEUlw9IOCo+F GGQQPRoTcCpvjtfcjZOzQQ84Ic2tq8I9KgXTVxE3Dc2MUfmT48xGSSGOFLTNyxQ+ OM1yMe6rEvJl6jQuVl3/7mN1y226kTT8nvP0LRy+UMRC31mI/2qz+qhsPctWcXEF lrufgOWARVlnQbDrw61gpIB1BhecDvRD4JkOG/t/9bPMsoGCsf0ywbi+QaRktWA6 WlEwjM7eQSwZR1xJEGS5dKmHQa99brrBuKG/ZTE6BGf5tbuOkooAY7ix5ow4X4P/ UNU7ol1rshDMYwIDAQABoz8wPTAdBgNVHQ4EFgQUSXS7DF66ev4CVO97oMaVxgmA cJYwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBAJiRjT+JyLv1wGlzKTs1rLqzCHY9cAmS6YREIQF9FHYb7lFsHY0VNy17MWn0 mkS4r0bMNPojywMnGdKDIXUr5+AbmSbchECV6KjSzPZYXGbvP0qXEIIdugqi3VsG K52nZE7rLgE1pLQ/E61V5NVzqGmbEfGY8jEeb0DU+HifjpGgb3AEkGaqBivO4XqS tX3h4NGW56E6LcyxnR8FRO2HmdNNGnA5wQQM5X7Z8a/XIA7xInolpHOZzD+kByeW qKKV7YK5FtOeC4fCwfKI9WLfaN/HvGlR7bFc3FRUKQ8JOZqsA8HbDE2ubwp6Fknx v5HSOJTT9pUst2zJQraNypCNhdk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS /jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D hNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFlDCCBHygAwIBAgIBATANBgkqhkiG9w0BAQUFADCCATExFzAVBgNVBAcTDkFs dmFybyBPYnJlZ29uMRkwFwYDVQQIExBEaXN0cml0byBGZWRlcmFsMQswCQYDVQQG EwJNWDEOMAwGA1UEERMFMDEwMzAxHTAbBgNVBAkTFEluc3VyZ2VudGVzIFN1ciAx OTQwMUIwQAYDVQQDEzlBdXRvcmlkYWQgQ2VydGlmaWNhZG9yYSBSYWl6IGRlIGxh IFNlY3JldGFyaWEgZGUgRWNvbm9taWExNDAyBgNVBAsTK0RpcmVjY2lvbiBHZW5l cmFsIGRlIE5vcm1hdGl2aWRhZCBNZXJjYW50aWwxHzAdBgNVBAoTFlNlY3JldGFy aWEgZGUgRWNvbm9taWExJDAiBgkqhkiG9w0BCQEWFWFjcnNlQGVjb25vbWlhLmdv Yi5teDAeFw0wNTA1MDgwMDAwMDBaFw0yNTA1MDgwMDAwMDBaMIIBMTEXMBUGA1UE BxMOQWx2YXJvIE9icmVnb24xGTAXBgNVBAgTEERpc3RyaXRvIEZlZGVyYWwxCzAJ BgNVBAYTAk1YMQ4wDAYDVQQREwUwMTAzMDEdMBsGA1UECRMUSW5zdXJnZW50ZXMg U3VyIDE5NDAxQjBABgNVBAMTOUF1dG9yaWRhZCBDZXJ0aWZpY2Fkb3JhIFJhaXog ZGUgbGEgU2VjcmV0YXJpYSBkZSBFY29ub21pYTE0MDIGA1UECxMrRGlyZWNjaW9u IEdlbmVyYWwgZGUgTm9ybWF0aXZpZGFkIE1lcmNhbnRpbDEfMB0GA1UEChMWU2Vj cmV0YXJpYSBkZSBFY29ub21pYTEkMCIGCSqGSIb3DQEJARYVYWNyc2VAZWNvbm9t aWEuZ29iLm14MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwWSg9OdS cLLqkxP0NTof6jocxRuLWOGW1gJBXo6FQP9BZkBT/Ji10TIyl2dAgJ3uID8OVPtC B/t3GpnYhvQcKogl8+lEo07+B76xyO88jYfgHspJEDso7yRRofyIF0rnHMhUZ2Po ajHmQ2z2QBGGxFbuvckdpkY8HkbCgo0uqejudgpD4HJNjPTFBvosAQAzYM44cDRr FxrremRhp5OkZWrXI8d2epRRC+yeqM87olAyHEK9Y+GHy7mFSA7A1Vi29s5L8gfP 4wTVH8LWo26ju7a3bsTxoh8WvLYtsO/0Wpspjbzh/AdbHgkzgnjMQG1xs2MTL9NM Nqw5T8bBsLb1hQIDAQABo4GyMIGvMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9h Yy5lY29ub21pYS5nb2IubXgvbGFzdC5jcmwwRwYDVR0gBEAwPjA8Bghgg2RlCoI8 ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vYWMuZWNvbm9taWEuZ29iLm14L2Nwcy5o dG1sMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMBEGCWCGSAGG+EIBAQQE AwIABzANBgkqhkiG9w0BAQUFAAOCAQEATCp4UwSWc2CrNazAxOPnyHClKS+HGOWo gt4H1Qj0z549nvxKLBZ8n6KdZRDMwRubamfasrMd/81kejhjrUj983Lh+p+7V92/ zMJU2JU8ZtdrBrqvqeBtCO+ktpA9DG4gF6eWp3xoSpyYxAdvwQJikTibneOKeVOd nyR2JfatKFYGqu8HrLr2bOQlMX2IgDp4Rvh54TjgE+dhKUfzyxQA09ri3e1z30vy Y+Qm2HXQTUMUkBaURwH/oVlL5HabWQPe1hf2e9dc+Onjb8hO4EcmseKcfEox5WQR 4LBf2pE2SB/6CYplaPUOwp/vuGrPd/4S7TbaETatGWrC1I5S12jvMQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvDCCA6SgAwIBAgIQAJCLMk/BkBrOtMM4Cc3P5DANBgkqhkiG9w0BAQUFADB5 MQswCQYDVQQGEwJFUzE2MDQGA1UEChMtQ29uc2VqbyBHZW5lcmFsIGRlIGxhIEFi b2dhY2lhIE5JRjpRLTI4NjMwMDZJMTIwMAYDVQQDEylBdXRvcmlkYWQgZGUgQ2Vy dGlmaWNhY2lvbiBkZSBsYSBBYm9nYWNpYTAeFw0wNTA2MTMyMjAwMDBaFw0zMDA2 MTMyMjAwMDBaMHkxCzAJBgNVBAYTAkVTMTYwNAYDVQQKEy1Db25zZWpvIEdlbmVy YWwgZGUgbGEgQWJvZ2FjaWEgTklGOlEtMjg2MzAwNkkxMjAwBgNVBAMTKUF1dG9y aWRhZCBkZSBDZXJ0aWZpY2FjaW9uIGRlIGxhIEFib2dhY2lhMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtLJX7oXwI+gN+7KAhPEQZ6uy+UnfXN5b5I8p GVPJ1egcUGthAoyH8I88wUWSC6yZocYahdY9rX4mph24PbKzPorFCjLTS5HvSXV+ Vvf+oAhiRivO6vJRn2DeMsjtGqfPdVzrPcC9mkilhpTOWFAU6mrhmvSMZZXhYBUl lRL2uniLssDt5myXJFod5HRDyjjENZRYjvWKsGg8KCxElgm/CVtyCudnPJC5VDh0 VLttLWpDyLzvCawfI+hSVl41F18ru17NZVKlFHw7sqrp3Se1NyM7Bg0se4262m9m F4anttceB10ebBmXyOUjc3jRrvkeuqGuSSLtZXEff/dadESNQwIDAQABo4IBPjCC ATowNwYDVR0RBDAwLoERYWNAYWNhYm9nYWNpYS5vcmeGGWh0dHA6Ly93d3cuYWNh Ym9nYWNpYS5vcmcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwEQYJ YIZIAYb4QgEBBAQDAgAHMB0GA1UdDgQWBBT8iEyObQShIJDT+Byas2cEX3mAxjCB qwYDVR0gBIGjMIGgMIGdBgsrBgEEAYGBFQoBATCBjTApBggrBgEFBQcCARYdaHR0 cDovL3d3dy5hY2Fib2dhY2lhLm9yZy9kb2MwYAYIKwYBBQUHAgIwVBpSQ29uc3Vs dGUgbGEgZGVjbGFyYWNpb24gZGUgcHJhY3RpY2FzIGRlIGNlcnRpZmljYWNpb24g ZW4gaHR0cDovL3d3dy5hY2Fib2dhY2lhLm9yZzANBgkqhkiG9w0BAQUFAAOCAQEA mKf6ObVzESZ/vIk/tGslMzEKhjhryR4VlxTg0kwthfQ8dJuNKBH7zA4muYCDFtH5 Rpi2RgeOZoVtcMC6TIDzpPDVN1Qrr2aEcnP5SC8JzuGFAcqP4IfeoJfQlLQNtU0O ZyzIYMQylMBBgQeNur+p6AxAmkJ4BV2B62Ic5E8UCj0LPh/p9M197kW7vN5d85iX JnvGEyn4K38a1Or6sm4gntoX6qGSvTfpDru7kdUl9mBdhSFQW/9UXfVLO7TDKRFY AvYl5OGCgruijeeRJF5AkZ5HB4wzV9RiMVF2dYVDbwmrEaUlKbnY/1+l9z/rZTsd 74blFiLVHsoyaX1+BdcwJw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEezCCA2OgAwIBAgIQNxkY5lNUfBq1uMtZWts1tzANBgkqhkiG9w0BAQUFADCB rjELMAkGA1UEBhMCREUxIDAeBgNVBAgTF0JhZGVuLVd1ZXJ0dGVtYmVyZyAoQlcp MRIwEAYDVQQHEwlTdHV0dGdhcnQxKTAnBgNVBAoTIERldXRzY2hlciBTcGFya2Fz c2VuIFZlcmxhZyBHbWJIMT4wPAYDVQQDEzVTLVRSVVNUIEF1dGhlbnRpY2F0aW9u IGFuZCBFbmNyeXB0aW9uIFJvb3QgQ0EgMjAwNTpQTjAeFw0wNTA2MjIwMDAwMDBa Fw0zMDA2MjEyMzU5NTlaMIGuMQswCQYDVQQGEwJERTEgMB4GA1UECBMXQmFkZW4t V3VlcnR0ZW1iZXJnIChCVykxEjAQBgNVBAcTCVN0dXR0Z2FydDEpMCcGA1UEChMg RGV1dHNjaGVyIFNwYXJrYXNzZW4gVmVybGFnIEdtYkgxPjA8BgNVBAMTNVMtVFJV U1QgQXV0aGVudGljYXRpb24gYW5kIEVuY3J5cHRpb24gUm9vdCBDQSAyMDA1OlBO MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2bVKwdMz6tNGs9HiTNL1 toPQb9UY6ZOvJ44TzbUlNlA0EmQpoVXhOmCTnijJ4/Ob4QSwI7+Vio5bG0F/WsPo TUzVJBY+h0jUJ67m91MduwwA7z5hca2/OnpYH5Q9XIHV1W/fuJvS9eXLg3KSwlOy ggLrra1fFi2SU3bxibYs9cEv4KdKb6AwajLrmnQDaHgTncovmwsdvs91DSaXm8f1 XgqfeN+zvOyauu9VjxuapgdjKRdZYgkqeQd3peDRF2npW932kKvimAoA0SVtnteF hy+S8dF2g08LOlk3KC8zpxdQ1iALCvQm+Z845y2kuJuJja2tyWp9iRe79n+Ag3rm 7QIDAQABo4GSMIGPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEG MCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFTVFJvbmxpbmUxLTIwNDgtNTAdBgNV HQ4EFgQUD8oeXHngovMpttKFswtKtWXsa1IwHwYDVR0jBBgwFoAUD8oeXHngovMp ttKFswtKtWXsa1IwDQYJKoZIhvcNAQEFBQADggEBAK8B8O0ZPCjoTVy7pWMciDMD pwCHpB8gq9Yc4wYfl35UvbfRssnV2oDsF9eK9XvCAPbpEW+EoFolMeKJ+aQAPzFo LtU96G7m1R08P7K9n3frndOMusDXtk3sU5wPBG7qNWdX4wple5A64U8+wwCSersF iXOMy6ZNwPv2AtawB6MDwidAnwzkhYItr5pCHdDHjfhA7p0GVxzZotiAFP7hYy0y h9WUUpY6RsZxlj33mA6ykaqP2vROJAA5VeitF7nTNCtKqUDMFypVZUF0Qn71wK/I k63yGFs9iQzbRzkk+OBM8h+wPQrKBU6JIRrjKpms/H+h8Q8bHz2eBIPdltkdOpQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID+TCCAuGgAwIBAgIQW1fXqEywr9nTb0ugMbTW4jANBgkqhkiG9w0BAQUFADB5 MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xKjAoBgNVBAMTIVZpc2EgSW5m b3JtYXRpb24gRGVsaXZlcnkgUm9vdCBDQTAeFw0wNTA2MjcxNzQyNDJaFw0yNTA2 MjkxNzQyNDJaMHkxCzAJBgNVBAYTAlVTMQ0wCwYDVQQKEwRWSVNBMS8wLQYDVQQL EyZWaXNhIEludGVybmF0aW9uYWwgU2VydmljZSBBc3NvY2lhdGlvbjEqMCgGA1UE AxMhVmlzYSBJbmZvcm1hdGlvbiBEZWxpdmVyeSBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyREA4R/QkkfpLx0cYjga/EhIPZpchH0MZsRZ FfP6C2ITtf/Wc+MtgD4yTK0yoiXvni3d+aCtEgK3GDvkdgYrgF76ROJFZwUQjQ9l x42gRT05DbXvWFoy7dTglCZ9z/Tt2Cnktv9oxKgmkeHY/CyfpCBg1S8xth2JlGMR 0ug/GMO5zANuegZOv438p5Lt5So+du2Gl+RMFQqEPwqN5uJSqAe0VtmB4gWdQ8on Bj2ZAM2R73QW7UW0Igt2vA4JaSiNtaAG/Y/58VXWHGgbq7rDtNK1R30X0kJV0rGA ib3RSwB3LpG7bOjbIucV5mQgJoVjoA1e05w6g1x/KmNTmOGRVwIDAQABo30wezAP BgNVHRMBAf8EBTADAQH/MDkGA1UdIAQyMDAwLgYFZ4EDAgEwJTAVBggrBgEFBQcC ARYJMS4yLjMuNC41MAwGCCsGAQUFBwICMAAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud DgQWBBRPitp2/2d3I5qmgH1924h1hfeBejANBgkqhkiG9w0BAQUFAAOCAQEACUW1 QdUHdDJydgDPmYt+telnG/Su+DPaf1cregzlN43bJaJosMP7NwjoJY/H2He4XLWb 5rXEkl+xH1UyUwF7mtaUoxbGxEvt8hPZSTB4da2mzXgwKvXuHyzF5Qjy1hOB0/pS WaF9ARpVKJJ7TOJQdGKBsF2Ty4fSCLqZLgfxbqwMsd9sysXI3rDXjIhekqvbgeLz PqZr+pfgFhwCCLSMQWl5Ll3u7Qk9wR094DZ6jj6+JCVCRUS3HyabH4OlM0Vc2K+j INsF/64Or7GNtRf9HYEJvrPxHINxl3JVwhYj4ASeaO4KwhVbwtw94Tc/XrGcexDo c5lC3rAi4/UZqweYCw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDzDCCArSgAwIBAgILBAAAAAABBVJkwZUwDQYJKoZIhvcNAQEFBQAwUzELMAkG A1UEBhMCQkUxHDAaBgNVBAoTE0NlcnRpcG9zdCBzLmEuL24udi4xJjAkBgNVBAMT HUNlcnRpcG9zdCBFLVRydXN0IFRPUCBSb290IENBMB4XDTA1MDcyNjEwMDAwMFoX DTI1MDcyNjEwMDAwMFowUzELMAkGA1UEBhMCQkUxHDAaBgNVBAoTE0NlcnRpcG9z dCBzLmEuL24udi4xJjAkBgNVBAMTHUNlcnRpcG9zdCBFLVRydXN0IFRPUCBSb290 IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApdRLQNb78TUYO6Kw Q+TJVaHAB7sIvjoZtSPDHp2zCEr0Q0vpwRlgkN+E11jGOt0KLJUsvZd//qJ12gbj q5ts0bjPRIbBUmC33D47sPLpxFE8SrmDuU5hagObHFKAOlC0ILLb07LGVH/LYJvI JJ6vCcdlDSj22poiwjNu8vMl1KT5lvVvqjxr3EEw5eZvykgfMHgdeX2n0b+uxV5D +cYvg3abNEqkKFgrqIiFRGor8lZCdpmQM6ru+SHP8j35d4TL3SmExNSKKqQ5XD75 HCVoTfXnm12xGjReygJz+QjEDG1e3RIq5XvFNnhSnTLBxSilIKjlmA25b8+5gJ7l vrmb/QIDAQABo4GgMIGdMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ MB0GA1UdDgQWBBRL3r4FMS7zNcjYyqdWxZQNtFplxTBIBgNVHSAEQTA/MD0GCQOQ DgcBAAECADAwMC4GCCsGAQUFBwIBFiJodHRwOi8vd3d3LmUtdHJ1c3QuYmUvQ1BT L1FOY2VydHMgMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA iWPMos74VGp8WTR4qwG0li0qIW5ALV/QliKZgwUc5STN4vU1BL8AlgfssqQ6aisj PskPyhMduCSWCSbYPCqBzuGByMlzPvW7DwgekOCwkrnSOpdQ4AaO5IIwPGAgt6Tu q4kG4fwlu5HU+bdfaGOooGiGa6fskssi+lBbE1gnritDC7YXxjByBDNEJkpEBx9z oINBKeCSBrzVAer+vK9x6yAfCl0NoClezuRBUVWWwx+0MaWj81Pq/8KchnLPNkxW WgYyfl6rSqHOp+ufpIwquSSLuLXzBk2myn2Z+/ZV6q5Iee4mWdMfDFMV92JR+YQN lmxesQjmWQgrJikKwYNAcw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo 19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e 3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 MBr1mmz0DlP5OlvRHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDczCCAlugAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN MAsGA1UECgwES0lTQTEuMCwGA1UECwwlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkgQ2VudHJhbDEWMBQGA1UEAwwNS0lTQSBSb290Q0EgMTAeFw0wNTA4MjQw ODA1NDZaFw0yNTA4MjQwODA1NDZaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKDARL SVNBMS4wLAYDVQQLDCVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 cmFsMRYwFAYDVQQDDA1LSVNBIFJvb3RDQSAxMIIBIDANBgkqhkiG9w0BAQEFAAOC AQ0AMIIBCAKCAQEAvATk+hM58DSWIGtsaLv623f/J/es7C/n/fB/bW+MKs0lCVsk 9KFo/CjsySXirO3eyDOE9bClCTqnsUdIxcxPjHmc+QZXfd3uOPbPFLKc6tPAXXdi 8EcNuRpAU1xkcK8IWsD3z3X5bI1kKB4g/rcbGdNaZoNy4rCbvdMlFQ0yb2Q3lIVG yHK+d9VuHygvx2nt54OJM1jT3qC/QOhDUO7cTWu8peqmyGGO9cNkrwYV3CmLP3WM vHFE2/yttRcdbYmDz8Yzvb9Fov4Kn6MRXw+5H5wawkbMnChmn3AmPC7fqoD+jMUE CSVPzZNHPDfqAmeS/vwiJFys0izgXAEzisEZ2wIBA6MyMDAwHQYDVR0OBBYEFL+2 J9gDWnZlTGEBQVYx5Yt7OtnMMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF BQADggEBABOvUQveimpb5poKyLGQSk6hAp3MiNKrZr097LuxQpVqslxa/6FjZJap aBV/JV6K+KRzwYCKhQoOUugy50X4TmWAkZl0Q+VFnUkq8JSV3enhMNITbslOsXfl BM+tWh6UCVrXPAgcrnrpFDLBRa3SJkhyrKhB2vAhhzle3/xk/2F0KpzZm4tfwjeT 2KM3LzuTa7IbB6d/CVDv0zq+IWuKkDsnSlFOa56ch534eJAx7REnxqhZvvwYC/uO fi5C4e3nCSG9uRPFVmf0JqZCQ5BEVLRxm3bkGhKsGigA35vB1fjbXKP4krG9tNT5 UNkAAk/bg9ART6RCVmE6fhMy04Qfybo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5zCCA8+gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCQ0Ex EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoTFEVj aG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNlcnZp Y2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMjAeFw0wNTEwMDYxMDQ5MTNa Fw0zMDEwMDcxMDQ5MTNaMIGNMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJp bzEQMA4GA1UEBxMHVG9yb250bzEdMBsGA1UEChMURWNob3dvcnggQ29ycG9yYXRp b24xHzAdBgNVBAsTFkNlcnRpZmljYXRpb24gU2VydmljZXMxGjAYBgNVBAMTEUVj aG93b3J4IFJvb3QgQ0EyMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA utU/5BkV15UBf+s+JQruKQxr77s3rjp/RpOtmhHILIiO5gsEWP8MMrfrVEiidjI6 Qh6ans0KAWc2Dw0/j4qKAQzOSyAZgjcdypNTBZ7muv212DA2Pu41rXqwMrlBrVi/ KTghfdLlNRu6JrC5y8HarrnRFSKF1Thbzz921kLDRoCi+FVs5eVuK5LvIfkhNAqA byrTgO3T9zfZgk8upmEkANPDL1+8y7dGPB/d6lk0I5mv8PESKX02TlvwgRSIiTHR k8++iOPLBWlGp7ZfqTEXkPUZhgrQQvxcrwCUo6mk8TqgxCDP5FgPoHFiPLef5szP ZLBJDWp7GLyE1PmkQI6WiwIBA6OCAVAwggFMMA8GA1UdEwEB/wQFMAMBAf8wCwYD VR0PBAQDAgEGMB0GA1UdDgQWBBQ74YEboKs/OyGC1eISrq5QqxSlEzCBugYDVR0j BIGyMIGvgBQ74YEboKs/OyGC1eISrq5QqxSlE6GBk6SBkDCBjTELMAkGA1UEBhMC Q0ExEDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoT FEVjaG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMoIBADBQBgNVHSAESTBH MEUGCysGAQQB+REKAQMBMDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuZWNob3dv cnguY29tL2NhL3Jvb3QyL2Nwcy5wZGYwDQYJKoZIhvcNAQEFBQADggEBAG+nrPi/ 0RpfEzrj02C6JGPUar4nbjIhcY6N7DWNeqBoUulBSIH/PYGNHYx7/lnJefiixPGE 7TQ5xPgElxb9bK8zoAApO7U33OubqZ7M7DlHnFeCoOoIAZnG1kuwKwD5CXKB2a74 HzcqNnFW0IsBFCYqrVh/rQgJOzDA8POGbH0DeD0xjwBBooAolkKT+7ZItJF1Pb56 QpDL9G+16F7GkmnKlAIYT3QTS3yFGYChnJcd+6txUPhKi9sSOOmAIaKHnkH9Scz+ A2cSi4A3wUYXVatuVNHpRb2lygfH3SuCX9MU8Ure3zBlSU1LALtMqI4JmcQmQpIq zIzvO2jHyu9PQqo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg 4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ /L7fCg0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK 8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99 5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3 kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6 Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8 au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2 1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1 Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6 Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8 TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6 g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB 95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvzCCA6egAwIBAgIQANKFcP2up9ZfEYQVxjG1yzANBgkqhkiG9w0BAQUFADBd MQswCQYDVQQGEwJFUzEoMCYGA1UECgwfRElSRUNDSU9OIEdFTkVSQUwgREUgTEEg UE9MSUNJQTENMAsGA1UECwwERE5JRTEVMBMGA1UEAwwMQUMgUkFJWiBETklFMB4X DTA2MDIxNjEwMzcyNVoXDTM2MDIwODIyNTk1OVowXTELMAkGA1UEBhMCRVMxKDAm BgNVBAoMH0RJUkVDQ0lPTiBHRU5FUkFMIERFIExBIFBPTElDSUExDTALBgNVBAsM BEROSUUxFTATBgNVBAMMDEFDIFJBSVogRE5JRTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAIAArQzDoyAHo2P/9zSgze5qVAgXXbEBFafmuV+Kcf8Mwh3q N/Pek3/WBU2EstXXHAz0xJFwQA5ayJikgOgNM8AH87f1rKE4esBmVCT8UswwKvLD xKEsdr/BwL+C8ZvwaHoTQMiXvBwlBwgKt5bvzClU4OZlLeqyLrEJaRJOMNXY+LwA gC9Nkw/NLlcbM7ufME7Epct5p/viNBi2IJ4bn12nyTqtRWSzGM4REpxtHlVFKISc V2dN+cvii49YCdQ5/8g20jjiDGV/FQ59wQfdqSLfkQDEbHE0dNw56upPRGl/WNtY ClJxK+ypHVB0M/kpavr+mfTnzEVFbcpaJaIS487XOAU58BoJ9XZZzmJvejQNLNG8 BBLsPVPI+tACy849IbXF4DkzZc85U8mbRvmdM/NZgAhBvm9LoPpKzqR2HIXir68U nWWs93+X5DNJpq++zis38S7BcwWcnGBMnTANl1SegWK75+Av9xQHFKl3kenckZWO 04iQM0dvccMUafqmLQEeG+rTLuJ/C9zP5yLw8UGjAZLlgNO+qWKoVYgLNDTs3CEV qu/WIl6J9VGSEypvgBbZsQ3ZLvgQuML+UkUznB04fNwVaTRzv6AsuxF7lM34Ny1v Pe+DWsYem3RJj9nCjb4WdlDIWtElFvb2zIycWjCeZb7QmkiT1/poDXUxh/n3AgMB AAGjezB5MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQW BBSORfSfc8X/LxsF2wFHYBsDioG3ujA3BgNVHSAEMDAuMCwGBFUdIAAwJDAiBggr BgEFBQcCARYWaHR0cDovL3d3dy5kbmllLmVzL2RwYzANBgkqhkiG9w0BAQUFAAOC AgEAdeVzyVFRL4sZoIfp/642Nqb8QR/jHtdxYBnGb5oCML1ica1z/pEtTuQmQESp rngmIzFp3Jpzlh5JUQvg78G4Q+9xnO5Bt8VQHzKEniKG8fcfj9mtK07alyiXu5aa Gvix2XoE81SZEhmWFYBnOf8CX3r8VUJQWua5ov+4qGIeFM3ZP76jZUjFO9c3zg36 KJDav/njUUclfUrTZ02HqmK8Xux6gER8958KvWVXlMryEWbWUn/kOnB1BM07l9Q2 cvdRVr809dJB4bTaqEP+axJJErRdzyJClowIIyaMshBOXapT7gEvdeW5ohEzxNdq /fgOym6C2ee7WSNOtfkRHS9rI/V7ESDqQRKQMkbbMTupwVtzaDpGG4z+l7dWuWGZ zE7wg/o38d4cnRxxiwOTw8Rzgi6omB1kopqM91QITc/qgcv1WwmZY691jJb4eTXV 3OtBgXk4hF5v8W9idtuRzlqFYDkdW+IqL0Ml28J6JNMVsKLxjKB9a0gJE/+iTGaK 7HBSCVOMMMy41bok3DCZPqFet9+BrOw3vk6bJ1jefqGbVH8Gti/kMlD95xC7qM3a GBvUY2Y96lFxOfScPt9a9NrHTCbti7UhujR5AnNhENqYMahgy34Hp9C3BUOJW82F JtmwUa/3jFKqEqdY35KbZ/Kd8ub0aTH0Fufed1se3ZoFAa0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHxDCCBaygAwIBAgIIGq+SbI+Tr2AwDQYJKoZIhvcNAQEFBQAwgZUxgZIwCQYD VQQGDAJCRzAVBgNVBAoMDkluZm9Ob3RhcnkgUExDMBUGCgmSJomT8ixkARkWB3Jv b3QtY2EwGgYDVQQDDBNJbmZvTm90YXJ5IENTUCBSb290MBoGA1UECwwTSW5mb05v dGFyeSBDU1AgUm9vdDAfBgkqhkiG9w0BCQEWEmNzcEBpbmZvbm90YXJ5LmNvbTAi GA8yMDA2MDMwNjE3MzMwNVoYDzIwMjYwMzA2MTczMzA1WjCBlTGBkjAJBgNVBAYM AkJHMBUGA1UECgwOSW5mb05vdGFyeSBQTEMwFQYKCZImiZPyLGQBGRYHcm9vdC1j YTAaBgNVBAMME0luZm9Ob3RhcnkgQ1NQIFJvb3QwGgYDVQQLDBNJbmZvTm90YXJ5 IENTUCBSb290MB8GCSqGSIb3DQEJARYSY3NwQGluZm9ub3RhcnkuY29tMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnM2kXh+kfgiCT4B2wSeMRxZgn3Os yZF/LRBsO5RJnEIzX5TxgyEJkfeStw84RYuUB0qr/j82NVvR1VI4QkboR8dKUDPI 5OBztpCauqOIONMrQsBu36ITF/JPuefyId1l+qb9UsJgsstPN72vJ45pazJAU1n1 8jF2iAZtaJ8wvLeBHI5nY8MFZfcz9lmpq7OKRwsUE8c23SL7+EQ0NUEowIG6TrVx E68DqEkKLqSbYXdrHSTSpfEt0Udegv9Ig7AVmEfedvtPTsC/VElmvE8B0Xw6Zf7F rHBbxRUbcqV9pls7F8O+wz9dEn9nLXZHDIu/FiO1g3LNgM3ouq9eaDM41JDtbtLp VgQkofm+bF7KniMgkiuaDUtN46JIj77tqg6Mvqk4cLkQfzJdgCdaA+DURzMlWnap g9mYQO1/dQLv7mGRrDE+gNM0S/DCTjUwSV63Keh9IbD/KnmcNDEZZjMgYRovsILV sWdTkA2dKpcobrdmPxp/psSaaJbmZlt6N99adxXg2eN8s7LQ1WjbPh1YH47KmHRj v9R9Nmju0C+kKvKIL3fDEj+NqCUsBGlYpsu0OfGI0Kbels5zQkbTo/nx2I6KnW6K wFJPRbdw/hx7PQ2W3PmQlm3GGKFCwrbc2SMfl5ObDxn5sLc/JXS9glPsDS9t1j9S L9h20CW90Ln1vQ8CAwEAAaOCAhAwggIMMA4GA1UdDwEB/wQEAwIBBjBEBggrBgEF BQcBAQQ4MDYwNAYIKwYBBQUHMAGGKGh0dHA6Ly9vY3NwLmluZm9ub3RhcnkuY29t L3Jlc3BvbmRlci5jZ2kwVgYIKwYBBQUHAQsESjBIMEYGCCsGAQUFBzAFhjpsZGFw Oi8vbGRhcC5pbmZvbm90YXJ5LmNvbS9kYz1yb290LWNhLGRjPWluZm9ub3Rhcnks ZGM9Y29tMIGqBgNVHSAEgaIwgZ8wbwYJKwYBBAGBrQABMGIwOgYIKwYBBQUHAgEW Lmh0dHA6Ly9yZXBvc2l0b3J5LmluZm9ub3RhcnkuY29tL2Nwcy9xY3BzLmh0bWww JAYIKwYBBQUHAgIwGBoWSW5mb05vdGFyeSBDU1AgUm9vdCBDQTAsBgkrBgEEAYGt AAAwHzAdBggrBgEFBQcCARYRaHR0cDovL3d3dy5jcmMuYmcwDwYDVR0TAQH/BAUw AwEB/zB/BgNVHREEeDB2pHQwcjFwMAsGA1UEEQwEMTAwMDAMBgNVBAcMBVNvZmlh MBMGA1UEFAwMKzM1OTI5ODc1NzE3MBsGBlUECmQBAQwRMTMxMjc2ODI3OkJVTFNU QVQwIQYJKoZIhvcNAQkIDBQxNiBJdmFuIFZhc292IFN0cmVldDAdBgNVHQ4EFgQU 3dROZ0M/0+pi6NqJbo47bgu7lZ8wDQYJKoZIhvcNAQEFBQADggIBABib/A3B+HGs 1MwUtScJwVhKNEDmm2XK4PGLUj2Wfoke3qgV+t2ULoPGNl0bIak2Dlw9SYgMUyFd H21JNm+cUOvbZM+Juq9erRREh2LvMHzAlt9wOcs7Ue4r/AgFh1bNMyXggBrgpucN Q0wAI0NWog4ZVOKN0Q0WuVpvm3flHKmDiyjx4TJ2X0ewmjbqsm/dhjFY/gZpsMNg pvvYKNQI3fFuThq9zbesviKHFkmxOADVjEMp5ylrKxJiWapD8LRyiDjWAl8f2iSS jY18/B99OJBYCx8ctxy7NictWhzHMd20K529R6ExtwkR4s1vp270uKMpj/Ngv6cd 4E+XJSUKMEnH/no5RNTTZe+IXf/Z7lM5vDpEqDE7JZd7mr/R3Wvi1xJq+zK70diO 85azj5DqeFjBCtulJb6KAx/lktK8f6Ry5OtWeqn6fLjxoL8m/ko0zyWqZMS7e+0Y 5Uwsb0Fl7eC7PSx1VW/kFQbFS2yT9g9VzJN1hWEmA9LMlct6ECAnVnq/dVjc9Q2W 2UoHhNgimxDR1gZuFgcDs69546AXurhDCEKdPDsnzHwR1H4x82ZRAhFyOqPpcr2V XaEVf0cTOZWyta728WF0MHjHZgHTsnCXCMkNJPREKnCmnS8SZAZuio0g437a8VS/ DRSsKb59f3+5a0UCUWcVWaIOISfJgmcx -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1 7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn 8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/ 2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3zCCA8egAwIBAgIOGTMAAQACKBqaBLzyVUUwDQYJKoZIhvcNAQEFBQAwejEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUGA1UEAxMeVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMB4XDTA2MDMyMjE1NTgzNFoXDTMwMTIz MTIyNTk1OVowejELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVy IEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUG A1UEAxMeVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAi9R3azRs5TbYalxeOO781R15Azt7g2JEgk6I 7d6D/+7MUGIFBZWZdpj2ufJf2AaRksL2LWYXH/1TA+iojWOpbuHWG4y8mLOLO9Tk Lsp9hUkmW3m4GotAnn+7yT9jLM/RWny6KCJBElpN+Rd3/IX9wkngKhh/6aAsnPlE /AxoOUL1JwW+jhV6YJ3wO8c85j4WvK923mq3ouGrRkXrjGV90ZfzlxElq1nroCLZ gt2Y7X7i+qBhCkoy3iwX921E6oFHWZdXNwM53V6CItQzuPomCba8OYgvURVOm8M7 3xOCiN1LNPIz1pDp81PcNXzAw9l8eLPNcD+NauCjgUjkKa1juPD8KGQ7mbN9/pqd iPaZIgiRRxaJNXhdd6HPv0nh/SSUK2k2e+gc5iqQilvVOzRZQtxtz7sPQRxVzfUN Wy4WIibvYR6X/OJTyM9bo8ep8boOhhLLE8oVx+zkNo3aXBM9ZdIOXXB03L+PemrB Lg/Txl4PK1lszGFs/sBhTtnmT0ayWuIZFHCE+CAA7QGnl37DvRJckiMXoKUdRRcV I5qSCLUiiI3cKyTr4LEXaNOvYb3ZhXj2jbp4yjeNY77nrB/fpUcJucglMVRGURFV DYlcjdrSGC1z8rjVJ/VIIjfRYvd7Dcg4i6FKsPzQ8eu3hmPn4A5zf/1yUbXpfeJV BWR4Z38CAwEAAaNjMGEwHwYDVR0jBBgwFoAUzdeQoW6jv9sw1toyJZAM5jkegGUw DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFM3XkKFu o7/bMNbaMiWQDOY5HoBlMA0GCSqGSIb3DQEBBQUAA4ICAQB+FojoEw42zG4qhQc4 xlaJeuNHIWZMUAgxWlHQ/KZeFHXeTDvs8e3MfhEHSmHu6rOOOqQzxu2KQmZP8Tx7 yaUFQZmx7Cxb7tyW0ohTS3g0uW7muw/FeqZ8Dhjfbw90TNGp8aHp2FRkzF6WeKJW GsFzshXGVwXf2vdIJIqOf2qp+U3pPmrOYCx9LZAI9mOPFdAtnIz/8f38DBZQVhT7 upeG7rRJA1TuG1l/MDoCgoYhrv7wFfLfToPmmcW6NfcgkIw47XXP4S73BDD7Ua2O giRAyn0pXdXZ92Vk/KqfdLh9kl3ShCngE+qK99CrxK7vFcXCifJ7tjtJmGHzTnKR N4xJkunI7Cqg90lufA0kxmts8jgvynAF5X/fxisrgIDV2m/LQLvYG/AkyRDIRAJ+ LtOYqqIN8SvQ2vqOHP9U6OFKbt2o1ni1N6WsZNUUI8cOpevhCTjXwHxgpV2Yj4wC 1dxWqPNNWKkL1HxkdAEy8t8PSoqpAqKiHYR3wvHMl700GXRd4nQ+dSf3r7/ufA5t VIimVuImrTESPB5BeW0X6hNeH/Vcn0lZo7Ivo0LD+qh+v6WfSMlgYmIK371F3uNC tVGW/cT1Gpm4UqJEzS1hjBWPgdVdotSQPYxuQGHDWV3Y2eH2dEcieXR92sqjbzcV NvAsGnE8EXbfXRo+VGN4a2V+Hw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtjCCAp6gAwIBAgIOBcAAAQACQdAGCk3OdRAwDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDQgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDQgQ0EgSUkwHhcNMDYwMzIzMTQxMDIzWhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBALXNTJytrlG7fEjFDSmGehSt2VA9CXIgDRS2Y8b+WJ7gIV7z jyIZ3E6RIM1viCmis8GsKnK6i1S4QF/yqvhDhsIwXMynXX/GCEnkDjkvjhjWkd0j FnmA22xIHbzB3ygQY9GB493fL3l1oht48pQB5hBiecugfQLANIJ7x8CtHUzXapZ2 W78mhEj9h/aECqqSB5lIPGG8ToVYx5ct/YFKocabEvVCUNFkPologiJw3fX64yhC L04y87OjNopq1mJcrPoBbbTgci6VaLTxkwzGioLSHVPqfOA/QrcSWrjN2qUGZ8uh d32llvCSHmcOHUJG5vnt+0dTf1cERh9GX8eu4I8CAwEAAaNCMEAwDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFB/quz4lGwa9pd1iBX7G TFq/6A9DMA0GCSqGSIb3DQEBBQUAA4IBAQBYpCubTPfkpJKknGWYGWIi/HIy6QRd xMRwLVpG3kxHiiW5ot3u6hKvSI3vK2fbO8w0mCr3CEf/Iq978fTr4jgCMxh1KBue dmWsiANy8jhHHYz1nwqIUxAUu4DlDLNdjRfuHhkcho0UZ3iMksseIUn3f9MYv5x5 +F0IebWqak2SNmy8eesOPXmK2PajVnBd3ttPedJ60pVchidlvqDTB4FAVd0Qy+BL iILAkH0457+W4Ze6mqtCD9Of2J4VMxHL94J59bXAQVaS4d9VA61Iz9PyLrHHLVZM ZHQqMc7cdalUR6SnQnIJ5+ECpkeyBM1CE+FhDOB4OiIgohxgQoaH96Xm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0 MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+ +FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1 XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3 R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93 d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0 YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7 R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX UKqK1drk/NAJBzewdXUh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFbjCCA1agAwIBAgIPQupbClERJnzYJ3S3339xMA0GCSqGSIb3DQEBBQUAMDMx CzAJBgNVBAYTAlBUMQ0wCwYDVQQKDARTQ0VFMRUwEwYDVQQDDAxFQ1JhaXpFc3Rh ZG8wHhcNMDYwNjIzMTM0MTI3WhcNMzAwNjIzMTM0MTI3WjAzMQswCQYDVQQGEwJQ VDENMAsGA1UECgwEU0NFRTEVMBMGA1UEAwwMRUNSYWl6RXN0YWRvMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2++iQ27Iqf1u19+sopKEochZoAyaU/7v rswZDXKKpMIzI+/nBnLqbUs6QVIPyUgOLee6ZO6iOkxjXGYpi9+piMW96PH3jkv8 ATxEEjkqcKLA28Wi31/HS8ao3D1hfEpYwUQyk95wmaEjJlY/o+HqXzBG2Hj1MKOW CYmwPfGGkwW2EmoYjfClZDsrh2RePReOC27mmMyXODggjHBaaSu9ZY3NN1lcbNFy dFkGTsi3Add3v/BIhqizGl1B1DcXERBfSm6NdcUDQH0hrgDw2/yfbDpmpN/3yt+A ZlrZ2H8UoiYZ9K4LIeDKPgXdFth+WdqhsGnDnTQT+mVJOYfudi+NvTwnGQNOrQ4L KyzGLnETNSlX6XDcG1HqzZfxlY2yhvomBi+AGpXxmDvu9uWGpc4bAeX06TPKD1VE X2iKLMdbZijdlkuDnV4dfhjV/rJg+5pRaMOWjB9oS1BSCzbmMSfk1ykMG9obL+EE U7jUeUmwO4FeCIgid+IpwK5yqqu0clK9bLv1unjZnLggbzCNSp0y+fQB5mJ5mEJA BXpvHCo/tfvfzRhAjuUQxDlbVvE8VwWr0jlNP/iLI8druUCx4v7/sxwKaR+bjA+0 H+AK3kj9jV+PmfUBdgU2XY7cM45RbhHiQf3Mt40qXz6S5fKx4KQj4qK3xo0YmylK 0UZ/9GQgGN0CAwEAAaN/MH0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFHF/Nd71d3FtHRKc4ZCkuvCpg4+AMDsGA1UdIAQ0MDIwMAYE VR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVjZWUuZ292LnB0L2RwYzAN BgkqhkiG9w0BAQUFAAOCAgEAjK2ccqW1Z3ZnOIfpOoz+nVk1vpDxAwCgWNiY0b/8 /PNQ3LRl1dq68IwufA3mCZFfTaP2XXicWF1qcJSjr9svAMkDQGvfUQMWGYwrvJk2 9sCtkhgTjKftHdLfA5AF7LCTmJv3TVoT+Oeb9zZ23nwm+BE4T0lOs3MfXydb4Z4y HvbAmBvZICxclo2GyQtF15Ktir3qV6KjVrYgPOyyxzl+sID+vVErKrTDcmnD+Ucu bv+ch+3cdcsQiOC0zi4OUx0L6G4eQkzQvjl4dckU3ieRc6rsaoDw8BeWYk++BMvi p+VdD5NFy1lIJhPe3bH1CtoWsagdj35YG7fVCd6Ia86EPqi+UmLK0qGhx8s8FuB2 VjA/5g9rBnf+ZJ1aanN87t4h6ZpJlze2hH+ikT5F+9daBsWHNdy6SEyGAQhHNrY4 UJURmXPRN0kK+kJPLxBU00GQ+sjcuxHcDcx9fJvcDpFxhk248hWaKzgXEaHynqhs nOPOruLmS4vyigY7B3cCEe6D6p1mhsrwYqnVV4OkFfFFFP4adX+lD9xSdFl1Cvj7 VUGpXI0xRN3NlE4z0RtBqtvXoTzwxUhtRUE1tXmD5vlN8VY4179AIvsggOMcwllG B2MCYQA7m1C7Q8Ow6QqauHb0R2FVZHBPN9mcEaMTsuHdQEK7mNegBovmaFdLDjho f7o= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do 0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ 44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN 9u6wWk5JRFRYX0KD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIH/jCCBeagAwIBAgIBADANBgkqhkiG9w0BAQUFADCB1DELMAkGA1UEBhMCQVQx DzANBgNVBAcTBlZpZW5uYTEQMA4GA1UECBMHQXVzdHJpYTE6MDgGA1UEChMxQVJH RSBEQVRFTiAtIEF1c3RyaWFuIFNvY2lldHkgZm9yIERhdGEgUHJvdGVjdGlvbjEq MCgGA1UECxMhR0xPQkFMVFJVU1QgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlMRQwEgYD VQQDEwtHTE9CQUxUUlVTVDEkMCIGCSqGSIb3DQEJARYVaW5mb0BnbG9iYWx0cnVz dC5pbmZvMB4XDTA2MDgwNzE0MTIzNVoXDTM2MDkxODE0MTIzNVowgdQxCzAJBgNV BAYTAkFUMQ8wDQYDVQQHEwZWaWVubmExEDAOBgNVBAgTB0F1c3RyaWExOjA4BgNV BAoTMUFSR0UgREFURU4gLSBBdXN0cmlhbiBTb2NpZXR5IGZvciBEYXRhIFByb3Rl Y3Rpb24xKjAoBgNVBAsTIUdMT0JBTFRSVVNUIENlcnRpZmljYXRpb24gU2Vydmlj ZTEUMBIGA1UEAxMLR0xPQkFMVFJVU1QxJDAiBgkqhkiG9w0BCQEWFWluZm9AZ2xv YmFsdHJ1c3QuaW5mbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANIS R+xfmOgNhhVJxN3snvFszVG2+5VPi8SQPVMzsdMTxUjipb/19AOED5x4cfaSl/Fb WXUYPycLUS9caMeh6wDz9pU9acN+wqzECjZyelum0PcBeyjHKscyYO5ZuNcLJ92z RQUre2Snc1zokwKXaOz8hNue1NWBR8acwKyXyxnqh6UKo7h1JOdQJw2rFvlWXbGB ARZ98+nhJPMIIbm6rF2ex0h5f2rK3zl3BG0bbjrNf85cSKwSPFnyas+ASOH2AGd4 IOD9tWR7F5ez5SfdRWubYZkGvvLnnqRtiztrDIHutG+hvhoSQUuerQ75RrRa0QMA lBbAwPOs+3y8lsAp2PkzFomjDh2V2QPUIQzdVghJZciNqyEfVLuZvPFEW3sAGP0q GVjSBcnZKTYl/nfua1lUTwgUopkJRVetB94i/IccoO+ged0KfcB/NegMZk3jtWoW WXFb85CwUl6RAseoucIEb55PtAAt7AjsrkBu8CknIjm2zaCGELoLNex7Wg22ecP6 x63B++vtK4QN6t7565pZM2zBKxKMuD7FNiM4GtZ3k5DWd3VqWBkXoRWObnYOo3Ph XJVJ28EPlBTF1WIbmas41Wdu0qkZ4Vo6h2pIP5GW48bFJ2tXdDGY9j5xce1+3rBN LPPuj9t7aNcQRCmt7KtQWVKabGpyFE0WFFH3134fAgMBAAGjggHXMIIB0zAdBgNV HQ4EFgQUwAHV4HgfL3Q64+vAIVKmBO4my6QwggEBBgNVHSMEgfkwgfaAFMAB1eB4 Hy90OuPrwCFSpgTuJsukoYHapIHXMIHUMQswCQYDVQQGEwJBVDEPMA0GA1UEBxMG Vmllbm5hMRAwDgYDVQQIEwdBdXN0cmlhMTowOAYDVQQKEzFBUkdFIERBVEVOIC0g QXVzdHJpYW4gU29jaWV0eSBmb3IgRGF0YSBQcm90ZWN0aW9uMSowKAYDVQQLEyFH TE9CQUxUUlVTVCBDZXJ0aWZpY2F0aW9uIFNlcnZpY2UxFDASBgNVBAMTC0dMT0JB TFRSVVNUMSQwIgYJKoZIhvcNAQkBFhVpbmZvQGdsb2JhbHRydXN0LmluZm+CAQAw DwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAcYwEQYDVR0gBAowCDAGBgRVHSAA MD0GA1UdEQQ2MDSBFWluZm9AZ2xvYmFsdHJ1c3QuaW5mb4YbaHR0cDovL3d3dy5n bG9iYWx0cnVzdC5pbmZvMD0GA1UdEgQ2MDSBFWluZm9AZ2xvYmFsdHJ1c3QuaW5m b4YbaHR0cDovL3d3dy5nbG9iYWx0cnVzdC5pbmZvMA0GCSqGSIb3DQEBBQUAA4IC AQAVO4iDXg7ePvA+XdwtoUr6KKXWB6UkSM6eeeh5mlwkjlhyFEGFx0XuPChpOEmu Io27jAVtrmW7h7l+djsoY2rWbzMwiH5VBbq5FQOYHWLSzsAPbhyaNO7krx9i0ey0 ec/PaZKKWP3Bx3YLXM1SNEhr5Qt/yTIS35gKFtkzVhaP30M/170/xR7FrSGshyya 5BwfhQOsi8e3M2JJwfiqK05dhz52Uq5ZfjHhfLpSi1iQ14BGCzQ23u8RyVwiRsI8 p39iBG/fPkiO6gs+CKwYGlLW8fbUYi8DuZrWPFN/VSbGNSshdLCJkFTkAYhcnIUq mmVeS1fygBzsZzSaRtwCdv5yN3IJsfAjj1izAn3ueA65PXMSLVWfF2Ovrtiuc7bH UGqFwdt9+5RZcMbDB2xWxbAH/E59kx25J8CwldXnfAW89w8Ks/RuFVdJG7UUAKQw K1r0Vli/djSiPf4BJvDduG3wpOe8IPZRCPbjN4lXNvb3L/7NuGS96tem0P94737h HB5Ufg80GYEQc9LjeAYXttJR+zV4dtp3gzdBPi1GqH6G3lb0ypCetK2wHkUYPDSI Aofo8DaR6/LntdIEuS64XY0dmi4LFhnNdqSr+9Hio6LchH176lDq9bIEO4lSOrLD GU+5JrG8vCyy4YGms2G19EVgLyx1xcgtiEsmu3DuO38BLQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ 9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst 0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK 1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ 8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm fyWl8kgAwKQB2j8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c 6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn 8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a 77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH 6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ 2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ 6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl +zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO 0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj 7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS 8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ 3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa /FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta 3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk 6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 /qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 jVaMaA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp +ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og /zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y 4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza 8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB 4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd 8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A 4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd +LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B 4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK 4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl 4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi 94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP 9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m 0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4 Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ 54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50 7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6 xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/ Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42 gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0 jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+ XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/ RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk BYn8eNZcLCZDqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI 2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp +2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW /zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB ZQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH /nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGKjCCBBKgAwIBAgIQZgej0p0pVhgO4V5ZmLGEVTANBgkqhkiG9w0BAQUFADB0 MQswCQYDVQQGEwJMVDErMCkGA1UEChMiU2thaXRtZW5pbmlvIHNlcnRpZmlrYXZp bW8gY2VudHJhczEgMB4GA1UECxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAU BgNVBAMTDVNTQyBSb290IENBIEEwHhcNMDYxMjI3MTIxODUyWhcNMjYxMjI4MTIw NTA0WjB0MQswCQYDVQQGEwJMVDErMCkGA1UEChMiU2thaXRtZW5pbmlvIHNlcnRp ZmlrYXZpbW8gY2VudHJhczEgMB4GA1UECxMXQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkxFjAUBgNVBAMTDVNTQyBSb290IENBIEEwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQC66k++hMAZJIohqUyZffcM1aVRkqhl44mjC2bnQvh50g+DI3u3 psEk1jXW2OUBynCxFtZHbr4QbH7pUG529+Xkgw941aBz9Y3RmR+URCOWxu5yWvna XTyRr2zol+iGXfeei/rErGZP5HI/O92eTjXSEx99u0RL9FOs1hTXQDm6wD/8hSDT xADQ59hHmQR5h4ZAsqxeyXUgwwkUrwSOpqKtKleIZaHMKL42yR8lD8NrIoQ5d046 A8Bq2z66tome5NcumrdDAT/52qyprOR3M4ftCzndx8GtDVmDMNE2BFi0ZE7m/wjo QrGAq/iY//MphhYRJE4Joc8wf7xesApqoXFr9ZoSayVtdwKiRl75aS/7OxiVX45c l5RgXh1xqEG0Xc9aemfj1Eo1HzfgdhYDO/RRnJgUKUmIDELQLW2pp0AmOnkAMDvA u0SYrSTO0ZbciXiB9lpbQrx04YfTZchH5jayzMFvwMfcgCVSPDGQ3cnIUKh6u3bg 7xOUzgR+arZOd/mD0G/4OtAKQ8q6ELb/PB2UYJSEbfWlyX1MCn4vj2/93S17Sunv NNu7fv8Mbzf6+cPMyS/R6Sw9KqxsJjvQCV7EgCeL3WHw55VRQ8QN5jHQeNbBxsJm AdHjzMfTHhUFNtuUmuxSw5HHL7H0A/cHrNNLkatWPNCu/V9tLdMAEc+TvQIDAQAB o4G3MIG0MA8GA1UdEwEB/wQFMAMBAf8wPQYDVR0gBDYwNDAyBgsrBgEEAYGvZQEC ADAjMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNzYy5sdC9jcHMwMwYDVR0fBCww KjAooCagJIYiaHR0cDovL2NybC5zc2MubHQvcm9vdC1hL2NhY3JsLmNybDAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMy/3qeQd2JqHXhpLgo4m3dRUwPwMA0GCSqG SIb3DQEBBQUAA4ICAQA+r8ioxzNP8G6aQ+HysFdS4ZyeBl9C1vH9yotRP+HHZWlP dBlQis8Yk0mNoBywOz2OSJPZ6AV+xAmxD1KKa5dv1448gADQQXOtPcNEB3Fqj2J+ BdhTYHKxAekAYqoN2NhJwrR9DVuzlyk2mbmn0UuYa0S8shKOdmR1TA3Nwi6zWPx6 T1WzWX9d4C8wM8+IG2npTYqQnpC5MTrzogW8/vndUI0OlBmdfo2qFX4PUpMl5IEO li0cAxwwgxGWQqmYpJ1fyalcO0lowoRtmdr2/qLy3DdejXrlpVfKI0uTXZIqVYSz lrMemJRJfGw83J4dtqvDrAnFnd4311TEnK0/sNZpAeUQhn25gYNunGZOlQWSkDGH JrLakXS9hORxaOR2AOB2czRHhpVluluQom0FKXhg64b5Ek3oCFakzIyiVkrOgPQU YSLlqx06QTuE14J4BS+sHSNoq3J5hc1G5nqngloo0BU9HduMmFDO+69YO9OproA7 FgB2J9Vw6QmNNpQJf+PvYBBRysZVcGarUW/zUU8SVq7719kN4PqrEN5qgayFdy2s emN7RuE32ldurWX8IQSZhQHPIzoyxe1am9WhggR3EUWOpER9wsvLpw/oErrybrqP MzAb3Sn48EKjbkKlbvpWpalQg9EFZhaLLfvmktHmbAvVWiltK89519naT/Botg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGKzCCBBOgAwIBAgIRAL6SgxjzVYp4o2dZHGkkCT8wDQYJKoZIhvcNAQEFBQAw dDELMAkGA1UEBhMCTFQxKzApBgNVBAoTIlNrYWl0bWVuaW5pbyBzZXJ0aWZpa2F2 aW1vIGNlbnRyYXMxIDAeBgNVBAsTF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYw FAYDVQQDEw1TU0MgUm9vdCBDQSBCMB4XDTA2MTIyNzEyMjI1MFoXDTI2MTIyNTEy MDgyNlowdDELMAkGA1UEBhMCTFQxKzApBgNVBAoTIlNrYWl0bWVuaW5pbyBzZXJ0 aWZpa2F2aW1vIGNlbnRyYXMxIDAeBgNVBAsTF0NlcnRpZmljYXRpb24gQXV0aG9y aXR5MRYwFAYDVQQDEw1TU0MgUm9vdCBDQSBCMIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEAwfNV9UdRTlUXZY2wskEooUrRn0v2c/8+0slNWT/kt8efBl3Y PKOIhOBzXf0F6seO16QEauufvUP9FJJGuMW6qu1g7OzKkI0KcqlBm9SdvLBsohEf ZMvnHdRFZw4Ja+V47PE/BFTzmpnHWdHSeaekGrB8Sfwch1ReeAbV3R3MhaBCeNXQ sIrq6PGhnlbv08F9h6zn2mhPGdZv4JOtSVxzFMFGap33WEDZV1hObDf0ciME+NtK sN7xQZYSQKEVi2e4XnhWy3/kvsBJaJG4RwiTgcG1GzEG04B70UWhzww9YfOS+PGw FQ74LjBbAKNJ923+7ty/iM/wfVc+r8DRiut80m0xVfqEjXNq2nCAxPTCz5COMJrh xjVyAQjmP+ZmAKPy+JIdvFLsj/bc9wrvvBCH+YQYjF4fA7j/NS8BauXwW2J847N/ M6qU105RgbXoV3iPIpapDIlUPrbu2XNfZPRE4fFqGP9SlsQcv4mXpMOnyn4Ybhbc E4y71bUlCYav9i9FlCowwRSUNfZdyiWVnLFYibi1YIXJxr4UGaM++VaFq8ps1pl5 okoUb8M62OdmUQrpHP7MaeY0bPSB232iEfhMxIcFFj3rl3Q/buycubYnjCTfLbOv 3RNhdo//8kzgCBkwMiQyXDaAF+6Gyd8vUeJWroOS8LO92Ic6LJ7E3GmZ+csCAwEA AaOBtzCBtDAPBgNVHRMBAf8EBTADAQH/MD0GA1UdIAQ2MDQwMgYLKwYBBAGBr2UB AgAwIzAhBggrBgEFBQcCARYVaHR0cDovL3d3dy5zc2MubHQvY3BzMDMGA1UdHwQs MCowKKAmoCSGImh0dHA6Ly9jcmwuc3NjLmx0L3Jvb3QtYi9jYWNybC5jcmwwDgYD VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBScA/Co0phyaK7y7eBP4oUOsiVOzzANBgkq hkiG9w0BAQUFAAOCAgEArFy8L/yuASSmED6sqOGnJ5mNyojBHT2R9qJ+pfGYQf+q YfgJvs0aJWF0tMOvQloJD5EBvkiV9Mp3XguDzoSdz0D9gCy942Y1Crix+mDa5dhU tUuXuqIawyBpjbRGc1yqv717/xowNFhA+StgC3lE+feilgtrUnvwK0s70ouga5M9 yVdjimvMUBOPd6hRvhpMLUxdDJBbjvPvUCBtgeZRSavE59ddCCtR/D1GEufRpXbF UyQFyarTjljF84p0kjLt8C/dq63p0jWPdCPjmQDiizDkw0Ku8Lvp4ggbSnAtffjS mieRQnB1egh+vi8cfzc9qIvcRnL16G82aPpujSCd1PUHcb+9J0K5cyjW7Em0BYVP aEj2q5TfDqNGFGDCMSA76y5b3tWhLG3lUvqBX5eIyWO9AezjzWsKNcLJOOMO81gb fdqQbbf1yFhWna4B35GdrVWCAwwRdASRhsd8k4zzJ/vFJFdui9kbmJ2IMfCvd7gN tMzP9gpvEpvsCStTiexE4KFpi6h0hnQYUuDSv6ChZSG5CIN686T1+F43JUeZpl3X Ilrbk2cX2xDjjNESkUeKlaVHoQP4Sy4hxZBisH8no9sVfzh/bH9OBcUDtC3fRV91 LB3xX6a19hc5Qen4ZcIeWBHKfI7itbqSD2e3j+uZ1DH7cntamF+SlMcE6jD2uxo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGKjCCBBKgAwIBAgIQNLkSn6zHklVCXN5X/+PABTANBgkqhkiG9w0BAQUFADB0 MQswCQYDVQQGEwJMVDErMCkGA1UEChMiU2thaXRtZW5pbmlvIHNlcnRpZmlrYXZp bW8gY2VudHJhczEgMB4GA1UECxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAU BgNVBAMTDVNTQyBSb290IENBIEMwHhcNMDYxMjI3MTIyNjMwWhcNMjYxMjIyMTIx MTMwWjB0MQswCQYDVQQGEwJMVDErMCkGA1UEChMiU2thaXRtZW5pbmlvIHNlcnRp ZmlrYXZpbW8gY2VudHJhczEgMB4GA1UECxMXQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkxFjAUBgNVBAMTDVNTQyBSb290IENBIEMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQChRSL6jMypbwSz9GgyFmkRT3nfQ71RYHAamN14eJaYYvdwS4Go 4B0EifSP627p8P+B2C59rxcg8SLv8D9FR0C0y7K4ID8+SmhQ/5oG15fFt4oWLnHS R3NdGGUv7zkz6LZVryatAoDpY9chcAc+zL5ficD4zh0lbsP8f1Y5YdGOwiZ653gC ClndVSOw+DWn4qvzqy/XtYsKKnJUK215vPLZ6UP5z/GOZhL3l1kq2deU3PiUs0Wj rxYts4DKPc7opscKlHT8N5rpPww3FiBDyUdwu4yF/JiJKcuHGX4ZUxCJgHWuE/G/ pF0wBSl8qPe2XgcwFYiuTRWgys3X/6ujBlcPp+OJaRzWGtHUJ9+Wxjhcr3f+FatE QX3TmLuoIBivi23UWsLYlo1I9QcxfmH0YZtSgUCOSicEsgfTAhCU8/vdsXtwuLTI gfUAB6aNiAVNxI+WztS2wMFmjCqsaErJRtwN5i6oeSh9d0NwFn4cGjqmeU8TQImx MrsJRhENdLwn5djtLfpQKdwlypcQ56miYS46iaZEYb5PXpIJ7dwupu9Tu2El2Cel FEYphSYA2Pn5BdV7FjFCQwUXkZxKYEAkbbVtenn7nJpjw5hp5XdiIypRiQ9ssv3D ytj0GkOU0H0L4Vg+Gsh0hJv3rIKuUUWS0gZZ4bPB3qUfkyJ52M3EeWAjlQIDAQAB o4G3MIG0MA8GA1UdEwEB/wQFMAMBAf8wPQYDVR0gBDYwNDAyBgsrBgEEAYGvZQEC ADAjMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNzYy5sdC9jcHMwMwYDVR0fBCww KjAooCagJIYiaHR0cDovL2NybC5zc2MubHQvcm9vdC1jL2NhY3JsLmNybDAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFIgHc/bxvFIaWh09kWLtXaydC+W3MA0GCSqG SIb3DQEBBQUAA4ICAQAfkHFQmNXZNNKWhBjCrEYCIBzLObG3rwWk11jzkVF9joEn nOiSseccnzqLEFJzTMLHQh3Q694qyiJRfYx0ehr8vKTzc8hmI8QuQxBH4IppV+4v 8gBSsDCSqtbUFcVXy2B69A6N/h4JY3SP4P6+UNkBOVa6UEz240Wau1J23n6d+43C VDE+x7E8Pt/jT/3dmyRpfO3ocbZCBscfxV/7IHXbwf3pbKIqkNSG/c0N/+AFilhh PZ/EmS/t23zEDZiYVZx0ohde26oR5DcMJP8gZ9El25qJoGWIMZEEcV8glFgzNh0y 3m/XZwipoDv926RQJZYeqV+JF6WXmVGVadvE8Y/0bzArWfOsdYczfQbd4cFr1sTJ XnBEemrHnHc7Fv7+db6fLNHAA+4ReXXsqVsceoW1KFAgqRod5nuMMxj/we3IdmUf HfBMO6fb6s1W2JRXP+BIqX+MM0u99AxlFICC9DV32AQQcM4PbMFZy5mtge7ePUjQ eogvQJPXnLp5hBiAdd/QWt9Rdz5YiWl1RzHkahZwVATsvVx5U2PS4l69TSXaEbYP quksrvXRqY0CVsv8sCTqjLpw/zLQt8YEKmPVykaR1ZlyCQdeKAOrEhwls2w6WWW0 dG0tLRlyb/3nmBGHHnMjvzXxm7bD2cw7UHxy6M9ewJjMLgP9Hy/KdFyxHNHsaQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIQJAZiXxG2TMzanpxs6gQCaDANBgkqhkiG9w0BAQUFADBF MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL ExNUcnVzdGlzIEVWUyBSb290IENBMB4XDTA3MDEwOTEyMDAwMVoXDTI3MDEwOTEx NTYwMFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc MBoGA1UECxMTVHJ1c3RpcyBFVlMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBANJclMPP3EkLfN8EXAvqebvg0DdbjA7XzTkY3oyXuLQ0EG1n rcSzDu031KW/+kPl2nAnhkef4umygbm+LVu5sSiAMEHfuJSpIKZ+qqzKcEyjEgzP YGKBUnpJgwvIIiBzoJ01PJZv7c49JsJPSMqigqeVBqn2JjL+8sH9I1hfcTv4x9fd TDMfoNbBz3M3q5X+nZ3s7IXD4gm7iVf5lFYqVGKJzARobmSKT7GFe2zUpL0mCvUn /BM+XWozCmc5Yoz+FP2qJNpP3rK18neQoZHvKXcdcZVZtsDjgbj0/4nueqf7Wf7J 1I1u39apn/wLNbXcbqSZefOIMGv6SqlrOMhhS0MCAwEAAaNjMGEwDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHktc5bOsn1acw6HVikx xSjy7aVfMB8GA1UdIwQYMBaAFHktc5bOsn1acw6HVikxxSjy7aVfMA0GCSqGSIb3 DQEBBQUAA4IBAQBDyG/fm8wJr9w4Jh1I+9aWc6Bm3xriwOad0i+JHOg08iI0kfQV ny69tHKq1+08n61Rn38ehWYlakJpgGA3Vka6PFaraoCAmLXKeljbBQjH9geBv6A1 Nck3kr8R8hdBTz9B7RPTrxk9cYp+sGTIO+f6kxNk/lbD3ivZ61fNgtCMnVJSvGET NT9vn2j2afduGs8LOEpDtUAFM9KmKxo2D9OPsfd7Ph3SoG3YQ6orP2kLAH4a5E5v ym0xkf90gfz74kiTdlyLjMPcoQggC1tlNvx2+yM/0dqXwdNakKO/RZvXW4EIpFL8 eH4YLi1x/drvDYFGifBS8gxQaffO1QF8sn8o -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHEzCCBPugAwIBAgIPLeQK4ZvRwqpM9ACsgTX5MA0GCSqGSIb3DQEBBQUAMIGk MQswCQYDVQQGEwJFUzFKMEgGA1UECgxBQ29sZWdpbyBkZSBSZWdpc3RyYWRvcmVz IGRlIGxhIFByb3BpZWRhZCB5IE1lcmNhbnRpbGVzIGRlIEVzcGHDsWExGzAZBgNV BAsMEkNlcnRpZmljYWRvIFByb3BpbzEsMCoGA1UEAwwjUmVnaXN0cmFkb3JlcyBk ZSBFc3Bhw7FhIC0gQ0EgUmHDrXowHhcNMDcwMTA5MTcwMDM5WhcNMzEwMTA5MTcw MDM5WjCBpDELMAkGA1UEBhMCRVMxSjBIBgNVBAoMQUNvbGVnaW8gZGUgUmVnaXN0 cmFkb3JlcyBkZSBsYSBQcm9waWVkYWQgeSBNZXJjYW50aWxlcyBkZSBFc3Bhw7Fh MRswGQYDVQQLDBJDZXJ0aWZpY2FkbyBQcm9waW8xLDAqBgNVBAMMI1JlZ2lzdHJh ZG9yZXMgZGUgRXNwYcOxYSAtIENBIFJhw616MIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEArFAbDpLOuHwVavjkD518fHx25AsmOlEGzSiz7Q8+2ZF7zPyH g0L3e7BduHpn/jQhYr+5KcPeWvED8uvy4hLCZWR2p/XmyzGjaPJ5651UxVL/nz2D Yw7mvx0oAn38I/REk6OpQ5zY6CUaIDX1tbDO61Ur+tlesKFEK+UALCQPN38yNISy yBVvivXy6C73Q44CuDKbgBpTHQGZSGt081pwSqTo9wLRupGja4e+EF5+VLlYsgr2 OwrjDjjzgF33QY74jza5g5sRTOELscWTijOyv5u2nkS3H/4qgSg5fM/UrzVlrmde jSHfAGARK9Q85CdQn5O3BfHSDhTcKYKW8SqiG0MFcLPQXB4DQVX+FjjFUk2TtbQ8 diJNqSusFcSpS3S5pSPYzStIweLvzd74SrDfoOPuhjW/W3KUb7JGSupKU64x5pG1 dJhFmqR97HEq5ZBRNkP5SdTXKAYDsf15h9YG+Kyh+b8UeA3LI0vNuy4y9H28abu2 NX55z71Lcn5hqyp+QMcM5bKQtUwM1lcHfJfM+dl323vnjBN+zH4YT0xLI46uGsfq Xx+mF904tk/eCm5SUFmsbc3WMRm9JOmgWM/Z1LJDeT9f1m+qZchG8tLVfvkuQxjC mORo38HTX0UvadEd7pEkSNLrAA7CEEvSnb2jTRejN5qv75cxgdqJsWF6Y6cCAwEA AaOCAT4wggE6MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud DgQWBBQbjVkcs7dYYmRmrOLkpPaiGRL25TCB9wYDVR0gBIHvMIHsMIHpBgRVHSAA MIHgMDwGCCsGAQUFBwIBFjBodHRwOi8vcGtpLnJlZ2lzdHJhZG9yZXMub3JnL25v cm1hdGl2YS9pbmRleC5odG0wgZ8GCCsGAQUFBwICMIGSGoGPQ2VydGlmaWNhZG8g c3VqZXRvIGEgbGEgRGVjbGFyYWNp824gZGUgUHLhY3RpY2FzIGRlIENlcnRpZmlj YWNp824gZGVsIENvbGVnaW8gZGUgUmVnaXN0cmFkb3JlcyBkZSBsYSBQcm9waWVk YWQgeSBNZXJjYW50aWxlcyBkZSBFc3Bh8WEgKKkgMjAwNikwDQYJKoZIhvcNAQEF BQADggIBAD8f1iwZdkCSnCbmnlgGEj0Swis63uXYiXdAH8ZRqnSJlsXGw53x+rxp E6AGdRcmifxlOY1zeevPd6e71UgmeTGRMCeYQaUX4F9cG1oqfLqtFmUAUX2H3rq6 Y9ZjtDXg104ZRX6/UWlIbz6IblJVg/CLxEz0CtQRIa4pYOhbi5/4wuy3dj+AwnQu R3hiUZ7bjPWtX4UF6P2ae71waAuTwjB+EvRLT3TiiY+5Q3QP1oReet5wVKQTNl9k ftMEDv7dGW8kU5Xt6ckO1Kbxk6FbCeOi0ldOPhrOfazE91PQzaiS7aTJlyJm+Mai 8nXlEX4vdRKW949vzwflyswHPvU8i+28fDJgPuMP1BGDNA12hmS9M5dOcO32IDhf mmnHwE8WyoWCjwG2uhNe0PHt6SjdKr0ljtD6EwwWD3efdik0cGzreUud70408EW7 JSx1kkRfp5vEqtKzby68YeuGAUzZerl1Z4sDS8czUnieBcDtj3R4HRIjtjL8UVBe Ld5QvhA8ju8IhfU6+vLe59hMOuUS6/Q2dJhaUoqUGmapbkU+FCuNNAiq7wUTYRKQ hGgNEVosr3mecJSfxWTLzHj2U1zg1w2xPuMWC/Om7DRCPnUQhKXYvbHj6mHmJJzC gdoe2G/8eC0W40QtwNI9Xn2g0lbUYDdx/kyOZZzWO9o23NgzZ9AB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIJmzCCB4OgAwIBAgIBATANBgkqhkiG9w0BAQUFADCCAR4xPjA8BgNVBAMTNUF1 dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s YW5vMQswCQYDVQQGEwJWRTEQMA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlz dHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0 aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBlcmludGVuZGVuY2lh IGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUwIwYJ KoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTA3MDIxNjE1MzU1 MVoXDTI3MDIxMTIzNTk1OVowggEeMT4wPAYDVQQDEzVBdXRvcmlkYWQgZGUgQ2Vy dGlmaWNhY2lvbiBSYWl6IGRlbCBFc3RhZG8gVmVuZXpvbGFubzELMAkGA1UEBhMC VkUxEDAOBgNVBAcTB0NhcmFjYXMxGTAXBgNVBAgTEERpc3RyaXRvIENhcGl0YWwx NjA0BgNVBAoTLVNpc3RlbWEgTmFjaW9uYWwgZGUgQ2VydGlmaWNhY2lvbiBFbGVj dHJvbmljYTFDMEEGA1UECxM6U3VwZXJpbnRlbmRlbmNpYSBkZSBTZXJ2aWNpb3Mg ZGUgQ2VydGlmaWNhY2lvbiBFbGVjdHJvbmljYTElMCMGCSqGSIb3DQEJARYWYWNy YWl6QHN1c2NlcnRlLmdvYi52ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBALcok9KOeQsz+FEa+MXGdAJVJN63wozmjcrg6uCuKguU9VhnC1UzxQjFsUze rnpGVwX2QYVnA0NJxyzm9fWMSkimcynnpO85uHeFyk8M1DT7WBR8REn50eK9MqVo 8tNXAS80lUxxGdm7dbKY4iL9TL8megLnfNBNSUUaLeq11d1NL47W/uW9+hAzWlu6 aPt3cc/Fpd01XMlGL/K0w9NB5Tv9KQWDerAH6QWIKjMkmxmeQ5USojV55hztS1gP snlcPWk+5oPC9H/MkZxTPn8JK9ATXcOpFMAwNn9jgJL7BMljYzV/cZFHS03aurrz fnb+hI3leMTpCzlnbFAR/eUSN2JIyu/blsHu3S5aXQiDVxNb+q7NCMqACeza38Zd 6ONTyaD8gvAV6JR9rY6wB3SqKWr5Nef0wMn9/EJoGhfTli5SIjYmfjYKWj5gzrDU +vM3gHnlFix6hiskajdswgLEoK+PG7onW2ar6CQpay/U68FcDsn2jIDHhxAIaZIS K6FoecIYvZX6P8SlemDBMxuMaepXR9dFHM9hpyCaqzXbume4bscS8paLWQwMduil oQjOEP0Ocl7Fnuk4w2Kvek+aL69s0ykp6yPoGs0y03S83FmLfwtIt4rT5LfUYQv9 3dDBluLOt++Elw3A3HbajirVPI4lzsLFlirwUXqm/Wf7Gy6PAgMBAAGjggLeMIIC 2jASBgNVHRMBAf8ECDAGAQH/AgECMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52 ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMB0GA1UdDgQWBBRmDZwMrrrR SkMD7hObbfHS1HLVmjCCAVAGA1UdIwSCAUcwggFDgBRmDZwMrrrRSkMD7hObbfHS 1HLVmqGCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRpZmlj YWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAw DgYDVQQHEwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYD VQQKEy1TaXN0ZW1hIE5hY2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25p Y2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5kZW5jaWEgZGUgU2VydmljaW9zIGRlIENl cnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG9w0BCQEWFmFjcmFpekBz dXNjZXJ0ZS5nb2IudmWCAQEwDgYDVR0PAQH/BAQDAgEGMDcGA1UdEQQwMC6CD3N1 c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMFQGA1Ud HwRNMEswJKAioCCGHmh0dHA6Ly93d3cuc3VzY2VydGUuZ29iLnZlL2xjcjAjoCGg H4YdbGRhcDovL2FjcmFpei5zdXNjZXJ0ZS5nb2IudmUwNwYIKwYBBQUHAQEEKzAp MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5zdXNjZXJ0ZS5nb2IudmUwQAYDVR0g BDkwNzA1BgVghl4BAjAsMCoGCCsGAQUFBwIBFh5odHRwOi8vd3d3LnN1c2NlcnRl LmdvYi52ZS9kcGMwDQYJKoZIhvcNAQEFBQADggIBAIIZ7DHkEaEoHIGrJR44YAjG 9wyGXUMOpagwfBUyBmrhUc2sARNuBhmQJkhYGUUnLwDuDZFx7Y3FwjcZoEYzls1n KJM689/pTskFl4gk6xZnRVl8imf2j8P1jWBVzQ+B2AFuuIE0VVHxkya577LkieqR 5AcTbV+93DRdvy/tsgpNaEUdKQmIgZTb+HbzEUxJHNLJSyqctDuTAZi66gQGG/im kSu4raQHHdvcK8XmUoMwwzdhG/vKv6sAfvKTS+lAlZA73lZx8n/0A9wGz8fpEd0A dhhUDH3SAxyETKkrtNp2dsv0E2jbEvC6piAUoYvaJcGhZMMxq4dmAxzzwGFhilxR xDwv4RYJjxV9xHlRmHzViwVI1/NB7Ob8d5bIDc7w417eSIuel//xAIC8ufVzPsoM /12n3mheMLinbec52N0/Wi/gZKbVANl0e/1vWbPd6okO/ou7QE/PGk4aHwq8rA+U 72NM6WATAicV+rZkR0/qlDVkgfWeIg/Spl5/kqrzAHHwT3YQCNEFZGnPy6sVqPbX DQnG50JaARYKLm8z3akalf8gjY5UIJ3PHb39JIqpIKRwU84Q/1RIsqJo9HELd3zM rtcHFBfTfa7dx3DPYo30r4mE7LNT9gZ5f9+Ct8eOAvbQ3WoubQGG5r55+c7FZAU2 EHgFy96xE/FAndEXR872 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG/zCCBOegAwIBAgICcRkwDQYJKoZIhvcNAQEFBQAwWjELMAkGA1UEBhMCRlIx EzARBgNVBAoTCkNlcnRldXJvcGUxFzAVBgNVBAsTDjAwMDIgNDM0MjAyMTgwMR0w GwYDVQQDExRDZXJ0ZXVyb3BlIFJvb3QgQ0EgMjAeFw0wNzAzMjcyMjAwMDBaFw0z NzAzMjcyMzAwMDBaMFoxCzAJBgNVBAYTAkZSMRMwEQYDVQQKEwpDZXJ0ZXVyb3Bl MRcwFQYDVQQLEw4wMDAyIDQzNDIwMjE4MDEdMBsGA1UEAxMUQ2VydGV1cm9wZSBS b290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDD/Fa1KwaL 7Z5Gz8MAeRyAOaLKyhsQbSH5xx8KrPOteYKXnsaxaIhScTjEqkxHb3f95x/3lPZy V59EPGtf0NnOIijNcCMBFCJQEA4ae0sb9IZXj+ovaUC6RXoCQFpfNduguZ4/8D91 zTpFkRNVw0gp87fXFPIDhqPJsFd7PdkqrF7h35U6hcYFTDGi2i2xAI6vUVeewYtF TSkHi6Dl5d8xDH8GbGFPa+IjMsHljCsN2JYGcLMmJ8rPs6gjAMASJIG/rEQ9F5iD iM4JkDcuooAZSdmgCBeGmWrdHkCf0gLns5hWR3YXqk6h19vqpLrVUmdpcy6gJ1Rz rIvQu/BhWCaoankYwQznfFbMz83XBoYiB15zuNDmDCU1YroExPEALM6dSJ1btPbR YphDd1ercv4zgBAqMRvbGVApkqyB4AhpX+ZOPl6tXEh5nsVdsJeRF54W3wf6auGr vCV8OADh1th6nPzc1yIAUmeol7tsDWeZlxC4eThnaGGIKW6Uv1IHiDbC8i/GRmoh HvGa6Luf7bYms4anMEqbMGO85OhCVkQnPFqhDn3OqsMbXmjscz8/s/vEhSwEFfus CjhmMxmVA0vKtAR9534PDZhWPthXX7eZvnoUrcWn25QOBZ4lq7Kr+QmVeKoHi2wF HO5agGHo3742+7PjI9w9jHVm76PkVdCa7wIDAQABo4IBzTCCAckwDwYDVR0TAQH/ BAUwAwEB/zARBgNVHQ4ECgQIS8lOuWexmDUwUwYDVR0gBEwwSjBIBgcqgXoBaQQB MD0wOwYIKwYBBQUHAgEWL2h0dHA6Ly93d3cuY2VydGV1cm9wZS5mci9yZWZlcmVu Y2UvcGMtcm9vdDIucGRmMAsGA1UdDwQEAwIBBjCCAT8GA1UdHwSCATYwggEyMDKg MKAuhixodHRwOi8vd3d3LmNlcnRldXJvcGUuZnIvcmVmZXJlbmNlL3Jvb3QyLmNy bDB9oHugeYZ3bGRhcDovL2xjcjEuY2VydGV1cm9wZS5mci9jbj1DZXJ0ZXVyb3Bl JTIwUm9vdCUyMENBJTIwMixvdT0wMDAyJTIwNDM0MjAyMTgwLG89Q2VydGV1cm9w ZSxjPUZSP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3QwfaB7oHmGd2xkYXA6Ly9s Y3IyLmNlcnRldXJvcGUuZnIvY249Q2VydGV1cm9wZSUyMFJvb3QlMjBDQSUyMDIs b3U9MDAwMiUyMDQzNDIwMjE4MCxvPUNlcnRldXJvcGUsYz1GUj9jZXJ0aWZpY2F0 ZVJldm9jYXRpb25MaXN0MA0GCSqGSIb3DQEBBQUAA4ICAQAbRJZgJFo+a6rezdPY W1LAS/pRJePuzbyMPtO1Hfb8QIOsfuXXBkMtbCdz/r/apIIiUW7+jAymEVJgaAZe M0z6SPhbSCHWDJu+OLnhwEwToVPvIjlu7kZQZQsaHwV+d9nOJc30r8Z8nYyXbGod 9mTtlOHOXe9AHZbLcdVKrXlYOUVNq28HuzN8rj6l6cco2mignlcnZu99l+5pqELr c6pLsVnGjTecqcBGUG+MSVPV5S3hok3L51u/pbs8rFLOGZNkwxCaeUKrqPuEg8JG X7sozA5pT3xfuzxn5g2WHoRMXiAVWzlD5YsrgiSJo6D3EGXTyYnapMFFfYlZkOtB no7QxAlgX5ctIW0EphGBMEyTwlhguGvWeqDlsRGfYrgwcUand2RmOkJZH1VjR9cd oDSOgXJiSNmXrqHxvkDioDF/awDZxwLQaQIO8c4eLaSd78yBO2Oe91Qbzr7ECleb zbFr4qfgqx4eg9jAUhyqOlFGktCf2yHfaagLFU1e5In8W1NIeWutYZ8e5bixMrLb fehHatii4GX1zlYXoBKQuvBLLQEaqWnSp+fHrDSbbaKQwYYmSrIvvftvaGtVu8Vj OMF3YGMtrQycPKqYskOj1EbcDdw2HzIuaLp8ZSFBl5aQZxTWpC/9IT9//CJ7KjVY 9Ubxkw7Z7eA6Jn9uLo+YuE/UmQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2 MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6 dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO 76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj 2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFijCCA3KgAwIBAgIQDHbanJEMTiye/hXQWJM8TDANBgkqhkiG9w0BAQUFADBf MQswCQYDVQQGEwJOTDESMBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdp Tm90YXIgUm9vdCBDQTEgMB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmww HhcNMDcwNTE2MTcxOTM2WhcNMjUwMzMxMTgxOTIxWjBfMQswCQYDVQQGEwJOTDES MBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdpTm90YXIgUm9vdCBDQTEg MB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmwwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCssFjBAL3YIQgLK5r+blYwBZ8bd5AQQVzDDYcRd46B 8cp86Yxq7Th0Nbva3/m7wAk3tJZzgX0zGpg595NvlX89ubF1h7pRSOiLcD6VBMXY tsMW2YiwsYcdcNqGtA8Ui3rPENF0NqISe3eGSnnme98CEWilToauNFibJBN4ViIl HgGLS1Fx+4LMWZZpiFpoU8W5DQI3y0u8ZkqQfioLBQftFl9VkHXYRskbg+IIvvEj zJkd1ioPgyAVWCeCLvriIsJJsbkBgWqdbZ1Ad2h2TiEqbYRAhU52mXyC8/O3AlnU JgEbjt+tUwbRrhjd4rI6y9eIOI6sWym5GdOY+RgDz0iChmYLG2kPyes4iHomGgVM ktck1JbyrFIto0fVUvY//s6EBnCmqj6i8rZWNBhXouSBbefK8GrTx5FrAoNBfBXv a5pkXuPQPOWx63tdhvvL5ndJzaNl3Pe5nLjkC1+Tz8wwGjIczhxjlaX56uF0i57p K6kwe6AYHw4YC+VbqdPRbB4HZ4+RS6mKvNJmqpMBiLKR+jFc1abBUggJzQpjotMi puih2TkGl/VujQKQjBR7P4DNG5y6xFhyI6+2Vp/GekIzKQc/gsnmHwUNzUwoNovT yD4cxojvXu6JZOkd69qJfjKmadHdzIif0dDJZiHcBmfFlHqabWJMfczgZICynkeO owIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUiGi/4I41xDs4a2L3KDuEgcgM100wDQYJKoZIhvcNAQEFBQADggIBADsC jcs8MOhuoK3yc7NfniUTBAXT9uOLuwt5zlPe5JbF0a9zvNXD0EBVfEB/zRtfCdXy fJ9oHbtdzno5wozWmHvFg1Wo1X1AyuAe94leY12hE8JdiraKfADzI8PthV9xdvBo Y6pFITlIYXg23PFDk9Qlx/KAZeFTAnVR/Ho67zerhChXDNjU1JlWbOOi/lmEtDHo M/hklJRRl6s5xUvt2t2AC298KQ3EjopyDedTFLJgQT2EkTFoPSdE2+Xe9PpjRchM Ppj1P0G6Tss3DbpmmPHdy59c91Q2gmssvBNhl0L4eLvMyKKfyvBovWsdst+Nbwed 2o5nx0ceyrm/KkKRt2NTZvFCo+H0Wk1Ya7XkpDOtXHAd3ODy63MUkZoDweoAZbwH /M8SESIsrqC9OuCiKthZ6SnTGDWkrBFfGbW1G/8iSlzGeuQX7yCpp/Q/rYqnmgQl nQ7KN+ZQ/YxCKQSa7LnPS3K94gg2ryMvYuXKAdNw23yCIywWMQzGNgeQerEfZ1jE O1hZibCMjFCz2IbLaKPECudpSyDOwR5WS5WpI2jYMNjD67BVUc3l/Su49bsRn1NU 9jQZjHkJNsphFyUXC4KYcwx3dMPVDceoEkzHp1RxRy4sGn3J4ys7SN4nhKdjNrN9 j6BkOSQNPXuHr2ZcdBtLc7LljPCGmbjlxd+Ewbfr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q 130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG 9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgIQKTZHquOKrIZKI1byyrdhrzANBgkqhkiG9w0BAQUFADBO MQswCQYDVQQGEwJ1czEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQ0wCwYDVQQL EwRGQkNBMRYwFAYDVQQDEw1Db21tb24gUG9saWN5MB4XDTA3MTAxNTE1NTgwMFoX DTI3MTAxNTE2MDgwMFowTjELMAkGA1UEBhMCdXMxGDAWBgNVBAoTD1UuUy4gR292 ZXJubWVudDENMAsGA1UECxMERkJDQTEWMBQGA1UEAxMNQ29tbW9uIFBvbGljeTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJeNvTMn5K1b+3i9L0dHbsd4 6ZOcpN7JHP0vGzk4rEcXwH53KQA7Ax9oD81Npe53uCxiazH2+nIJfTApBnznfKM9 hBiKHa4skqgf6F5PjY7rPxr4nApnnbBnTfAu0DDew5SwoM8uCjR/VAnTNr2kSVdS c+md/uRIeUYbW40y5KVIZPMiDZKdCBW/YDyD90ciJSKtKXG3d+8XyaK2lF7IMJCk FEhcVlcLQUwF1CpMP64Sm1kRdXAHImktLNMxzJJ+zM2kfpRHqpwJCPZLr1LoakCR xVW9QLHIbVeGlRfmH3O+Ry4+i0wXubklHKVSFzYIWcBCvgortFZRPBtVyYyQd+sC AwEAAaN7MHkwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFC9Yl9ipBZilVh/72at17wI8NjTHMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJ KwYBBAGCNxUCBBYEFHa3YJbdFFYprHWF03BjwbxHhhyLMA0GCSqGSIb3DQEBBQUA A4IBAQBgrvNIFkBypgiIybxHLCRLXaCRc+1leJDwZ5B6pb8KrbYq+Zln34PFdx80 CTj5fp5B4Ehg/uKqXYeI6oj9XEWyyWrafaStsU+/HA2fHprA1RRzOCuKeEBuMPdi 4c2Z/FFpZ2wR3bgQo2jeJqVW/TZsN5hs++58PGxrcD/3SDcJjwtCga1GRrgLgwb0 Gzigf0/NC++DiYeXHIowZ9z9VKEDfgHLhUyxCynDvux84T8PCVI8L6eaSP436REG WOE2QYrEtr+O3c5Ks7wawM36GpnScZv6z7zyxFSjiDV2zBssRm8MtNHDYXaSdBHq S4CNHIkRi+xb/xfJSPzn4AYR4oRe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ /jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs 81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG 9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC 4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz rD6ogRLQy7rQkgu2npaqBA+K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8DCCA9igAwIBAgIPBuhGJy8fCo/RhFzjafbVMA0GCSqGSIb3DQEBBQUAMDgx CzAJBgNVBAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXpl bnBlLmNvbTAeFw0wNzEyMTMxMzA4MjdaFw0zNzEyMTMwODI3MjVaMDgxCzAJBgNV BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXplbnBlLmNv bTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMnTesoPHqynhugWZWqx whtFMnGV2f4QW8yv56V5AY+Jw8ryVXH3d753lPNypCxE2J6SmxQ6oeckkAoKVo7F 2CaU4dlI4S0+2gpy3aOZFdqBoof0e24md4lYrdbrDLJBenNubdt6eEHpCIgSfocu ZhFjbFT7PJ1ywLwu/8K33Q124zrX97RovqL144FuwUZvXY3gTcZUVYkaMzEKsVe5 o4qYw+w7NMWVQWl+dcI8IMVhulFHoCCQk6GQS/NOfIVFVJrRBSZBsLVNHTO+xAPI JXzBcNs79AktVCdIrC/hxKw+yMuSTFM5NyPs0wH54AlETU1kwOENWocivK0bo/4m tRXzp/yEGensoYi0RGmEg/OJ0XQGqcwL1sLeJ4VQJsoXuMl6h1YsGgEebL4TrRCs tST1OJGh1kva8bvS3ke18byB9llrzxlT6Y0Vy0rLqW9E5RtBz+GGp8rQap+8TI0G M1qiheWQNaBiXBZO8OOi+gMatCxxs1gs3nsL2xoP694hHwZ3BgOwye+Z/MC5TwuG KP7Suerj2qXDR2kS4Nvw9hmL7Xtw1wLW7YcYKCwEJEx35EiKGsY7mtQPyvp10gFA Wo15v4vPS8+qFsGV5K1Mij4XkdSxYuWC5YAEpAN+jb/af6IPl08M0w3719Hlcn4c yHf/W5oPt64FRuXxqBbsR6QXAgMBAAGjgfYwgfMwgbAGA1UdEQSBqDCBpYEPaW5m b0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBB MDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEG A1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEw IFZpdG9yaWEtR2FzdGVpejAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUHRxlDqjyJXu0kc/ksbHmvVV0bAUwDQYJKoZIhvcNAQEFBQAD ggIBAMeBRm8hGE+gBe/n1bqXUKJg7aWSFBpSm/nxiEqg3Hh10dUflU7F57dp5iL0 +CmoKom+z892j+Mxc50m0xwbRxYpB2iEitL7sRskPtKYGCwkjq/2e+pEFhsqxPqg l+nqbFik73WrAGLRne0TNtsiC7bw0fRue0aHwp28vb5CO7dz0JoqPLRbEhYArxk5 ja2DUBzIgU+9Ag89njWW7u/kwgN8KRwCfr00J16vU9adF79XbOnQgxCvv11N75B7 XSus7Op9ACYXzAJcY9cZGKfsK8eKPlgOiofmg59OsjQerFQJTx0CCzl+gQgVuaBp E8gyK+OtbBPWg50jLbJtooiGfqgNASYJQNntKE6MkyQP2/EeTXp6WuKlWPHcj1+Z ggwuz7LdmMySlD/5CbOlliVbN/UShUHiGUzGigjB3Bh6Dx4/glmimj4/+eAJn/3B kUtdyXvWton83x18hqrNA/ILUpLxYm9/h+qrdslsUMIZgq+qHfUgKGgu1fxkN0/P pUTEvnK0jHS0bKf68r10OEMr3q/53NjgnZ/cPcqlY0S/kqJPTIAcuxrDmkoEVU3K 7iYLHL8CxWTTnn7S05EcS6L1HOUXHA0MUqORH5zwIe0ClG+poEnK6EOMxPQ02nwi o8ZmPrgbBYhdurz3vOXcFD2nhqi2WVIhA16L4wTtSyoeo09Q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIBCDANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJDTjER MA8GA1UEChMIVW5pVHJ1c3QxGDAWBgNVBAMTD1VDQSBHbG9iYWwgUm9vdDAeFw0w ODAxMDEwMDAwMDBaFw0zNzEyMzEwMDAwMDBaMDoxCzAJBgNVBAYTAkNOMREwDwYD VQQKEwhVbmlUcnVzdDEYMBYGA1UEAxMPVUNBIEdsb2JhbCBSb290MIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2rPlBlA/9nP3xDK/RqUlYjOHsGj+p9+I A2N9Apb964fJ7uIIu527u+RBj8cwiQ9tJMAEbBSUgU2gDXRm8/CFr/hkGd656YGT 0CiFmUdCSiw8OCdKzP/5bBnXtfPvm65bNAbXj6ITBpyKhELVs6OQaG2BkO5NhOxM cE4t3iQ5zhkAQ5N4+QiGHUPR9HK8BcBn+sBR0smFBySuOR56zUHSNqth6iur8CBV mTxtLRwuLnWW2HKX4AzKaXPudSsVCeCObbvaE/9GqOgADKwHLx25urnRoPeZnnRc GQVmMc8+KlL+b5/zub35wYH1N9ouTIElXfbZlJrTNYsgKDdfUet9Ysepk9H50DTL qScmLCiQkjtVY7cXDlRzq6987DqrcDOsIfsiJrOGrCOp139tywgg8q9A9f9ER3Hd J90TKKHqdjn5EKCgTUCkJ7JZFStsLSS3JGN490MYeg9NEePorIdCjedYcaSrbqLA l3y74xNLytu7awj5abQEctXDRrl36v+6++nwOgw19o8PrgaEFt2UVdTvyie3AzzF HCYq9TyopZWbhvGKiWf4xwxmse1Bv4KmAGg6IjTuHuvlb4l0T2qqaqhXZ1LUIGHB zlPL/SR/XybfoQhplqCe/klD4tPq2sTxiDEhbhzhzfN1DiBEFsx9c3Q1RSw7gdQg 7LYJjD5IskkCAwEAAaOBojCBnzALBgNVHQ8EBAMCAQYwDAYDVR0TBAUwAwEB/zBj BgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcD BAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUHAwgGCCsGAQUF BwMJMB0GA1UdDgQWBBTZw9P4gJJnzF3SOqLXcaK0xDiALTANBgkqhkiG9w0BAQUF AAOCAgEA0Ih5ygiq9ws0oE4Jwul+NUiJcIQjL1HDKy9e21NrW3UIKlS6Mg7VxnGF sZdJgPaE0PC6t3GUyHlrpsVE6EKirSUtVy/m1jEp+hmJVCl+t35HNmktbjK81HXa QnO4TuWDQHOyXd/URHOmYgvbqm4FjMh/Rk85hZCdvBtUKayl1/7lWFZXbSyZoUkh 1WHGjGHhdSTBAd0tGzbDLxLMC9Z4i3WA6UG5iLHKPKkWxk4V43I29tSgQYWvimVw TbVEEFDs7d9t5tnGwBLxSzovc+k8qe4bqi81pZufTcU0hF8mFGmzI7GJchT46U1R IgP/SobEHOh7eQrbRyWBfvw0hKxZuFhD5D1DCVR0wtD92e9uWfdyYJl2b/Unp7uD pEqB7CmB9HdL4UISVdSGKhK28FWbAS7d9qjjGcPORy/AeGEYWsdl/J1GW1fcfA67 loMQfFUYCQSu0feLKj6g5lDWMDbX54s4U+xJRODPpN/xU3uLWrb2EZBL1nXz/gLz Ka/wI3J9FO2pXd96gZ6bkiL8HvgBRUGXx2sBYb4zaPKgZYRmvOAqpGjTcezHCN6j w8k2SjTxF+KAryAhk5Qe5hXTVGLxtTgv48y5ZwSpuuXu+RBuyy5+E6+SFP7zJ3N7 OPxzbbm5iPZujAv1/P8JDrMtXnt145Ik4ubhWD5LKAN1axibRww= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA 2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu MdRAGmI0Nj81Aa6sY6A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF 9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN /BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz 4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 7M2CYfE45k+XmCpajQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz +uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn 5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G spki4cErx5z481+oghLrGREt -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UE AwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00x CzAJBgNVBAYTAkVTMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEW MBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZF RElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC AgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHkWLn7 09gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7 XBZXehuDYAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5P Grjm6gSSrj0RuVFCPYewMYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAK t0SdE3QrwqXrIhWYENiLxQSfHY9g5QYbm8+5eaA9oiM/Qj9r+hwDezCNzmzAv+Yb X79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbkHQl/Sog4P75n/TSW9R28 MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTTxKJxqvQU fecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI 2Sf23EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyH K9caUPgn6C9D4zq92Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEae ZAwUswdbxcJzbPEHXEUkFDWug/FqTYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAP BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz4SsrSbbXc6GqlPUB53NlTKxQ MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU9QHnc2VMrFAw RAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWIm fQwng4/F9tqgaHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3 gvoFNTPhNahXwOf9jU8/kzJPeGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKe I6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1PwkzQSulgUV1qzOMPPKC8W64iLgpq0i 5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1ThCojz2GuHURwCRi ipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oIKiMn MCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZ o5NjEFIqnxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6 zqylfDJKZ0DcMDQj3dcEI2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacN GHk0vFQYXlPKNFHtRQrmjseCNj6nOGOpMCwXEGCSn1WHElkQwg9naRHMTh5+Spqt r0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3otkYNbn5XOmeUwssfnHdK Z05phkOTOPu220+DkdRgfks+KzgHVZhepA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEfjCCA2agAwIBAgIBADANBgkqhkiG9w0BAQUFADCBzzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOjA4BgNVBAsTMWh0dHA6Ly9j ZXJ0aWZpY2F0ZXMuc3RhcmZpZWxkdGVjaC5jb20vcmVwb3NpdG9yeS8xNjA0BgNV BAMTLVN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 eTAeFw0wODA2MDIwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJV UzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UE ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE6MDgGA1UECxMxaHR0cDov L2NlcnRpZmljYXRlcy5zdGFyZmllbGR0ZWNoLmNvbS9yZXBvc2l0b3J5LzE2MDQG A1UEAxMtU3RhcmZpZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9y aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8sxWKk3mFjdal+pt NTjREJvbuNypBAmVMy4JxQB7GnhCj8j0BY7+0miDHk6ZzRfbRz5Q84nS59yY+wX4 qtZj9FRNwXEDsB8bdrMaNDBz8SgyYIP9tJzXttIiN3wZqjveExBpblwG02+j8mZa dkJIr4DRVFk91LnU2+25qzmZ9O5iq+F4cnvYOI1AtszcEgBwQ4Vp2Bjjyldyn7Tf P/wiqEJS9XdbmfBWLSZwFjYSwieeV6Z80CPxedyjk1goOD2frTZD7jf7+PlDrchW 8pQSXkLrc7gTDcum1Ya5qihqVAOhPw8p6wkA6D9eon8XPaEr+L7QdR2khOOrF2UG UgCvsQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd BgNVHQ4EFgQUtMZ/GkPMm3VdL8RL8ouYEOnxURAwHwYDVR0jBBgwFoAUtMZ/GkPM m3VdL8RL8ouYEOnxURAwDQYJKoZIhvcNAQEFBQADggEBAKyAu8QlBQtYpOR+KX6v vDvsLcBELvmR4NI7MieQLfaACVzCq2Uk2jgQRsRJ0v2aqyhId4jG6W/RR5HVNU8U CahbQAcdfHFWy4lC1L9hwCL3Lt+r83JDi0DolOuwJtrRE9Or0DYtLjqVs3cuFTkY DGm6qoDt8VNOM5toBOKgMC7X0V3UpmadhObnuzyJuzad/BepPVUrivubxEyE/9/S vmkbdLCo9uqwnLIpdIFMaDqaf3MlOfUT4GaRadRXS7furUXgLMOI076USYkf/3DV W205E7Ady5jmZ2MNY/b7w9dhcoOIP3B+U8meiVTWT399cbmu8WCLd2Ds+L/6aqOc ASI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIKbzCCCFegAwIBAgIQAldiBmp1YIdPkAS/ocgoQTANBgkqhkiG9w0BAQUFADCB gzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1OMRQwEgYDVQQHEwtNaW5uZWFwb2xp czExMC8GA1UEChMoT3BlbiBBY2Nlc3MgVGVjaG5vbG9neSBJbnRlcm5hdGlvbmFs IEluYzEeMBwGA1UEAxMVT0FUSSBXZWJDQVJFUyBSb290IENBMB4XDTA4MDYwMzE5 MjgzMVoXDTM4MDYwMzE5MzYwMFowgYMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJN TjEUMBIGA1UEBxMLTWlubmVhcG9saXMxMTAvBgNVBAoTKE9wZW4gQWNjZXNzIFRl Y2hub2xvZ3kgSW50ZXJuYXRpb25hbCBJbmMxHjAcBgNVBAMTFU9BVEkgV2ViQ0FS RVMgUm9vdCBDQTCCAiAwDQYJKoZIhvcNAQEBBQADggINADCCAggCggIBAN54mUOu XmEeLdJ1ePU+LDZCisx8tt8Xd2FWp8zjOoAhgbJu0Ge1z6Whdr4oDRJWg6qWuySB O2v5wQOwi7QHBPmZ0D+0iv7A5RIqlb8VLwreFwFrVcq06LOyk+bjTLwHEXg9//sz dry4MryeFgPc0f1q3VTLJ+BL1DlpkPC6giIPZ3Ula8NiNveYkQTK/xJ0Xsuptndj 8RvkRE6GNtpraC+QXaE1mFylUopwukNeXN8t8TL4rPP27ZLDYmO3VkjHYR4StyGr uN1rZJDQR3AAt2jOlr1PQuULm3pNWbkcpK7vZ7WUtkibP4sESeb8KeP28TmdWkog FOAbwVhDGW26nSJshsu6Gf9YoFZE8W9RW1gL93t3f/ss0Qi6FX506OpnNCm4W5O7 pjDphJGXsCoHqduptYia3JPZZeYbcMzNRY5WkdVbG/PfajXiyIY+reWNegsodA/A fBJoyP2UtohJrFZXAOsMP+VRo5zqNhH9StbyCiDRYBM4w2CsuGdxJeHdBHn2EL9E xfJt0DyV2r3ju40JnaMgdpS1DxGORjM6XpW3hsTj5MgD25yy2ET73j6wZqFADYJJ CRa7eAPmnWeRLOOA6yv3dC+BSPvKJEsEEasZUGYFIsjynOxaWyQyK4ntp6FxtlMO Ofv0rt4Z8+XfAr2k9Ta35j8aCTKtHeMg2ACPAgEDo4IE3TCCBNkwCwYDVR0PBAQD AgFGMBMGCSsGAQQBgjcUAgQGHgQAQwBBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFOUNZHGdyVLpwJsqaTPAk3zzgfXfMHAGA1UdHwRpMGcwZaBjoGGGMWh0dHA6 Ly9jZXJ0cy5vYXRpY2VydHMuY29tL3JlcG9zaXRvcnkvT0FUSUNBMi5jcmyGLGh0 dHA6Ly9jZXJ0cy5vYXRpLm5ldC9yZXBvc2l0b3J5L09BVElDQTIuY3JsMBAGCSsG AQQBgjcVAQQDAgEAMIIDdQYDVR0gBIIDbDCCA2gwggNkBggqhkiG/GYLATCCA1Yw ggNSBggrBgEFBQcCAjCCA0QeggNAAEYAbwByACAAbQBvAHIAZQAgAGkAbgBmAG8A cgBtAGEAdABpAG8AbgAgAHIAZQBnAGEAcgBkAGkAbgBnACAATwBBAFQASQAgAGMA ZQByAHQAaQBmAGkAYwBhAHQAZQBzACAAYQBuAGQAIAB0AGgAZQAgAE8AQQBUAEkA IAB3AGUAYgBDAEEAUgBFAFMAIABTAHkAcwB0AGUAbQAsACAAcABsAGUAYQBzAGUA IABzAGUAZQAgAHQAaABlACAATwBBAFQASQAgAEMAZQByAHQAaQBmAGkAYwBhAHQA aQBvAG4AIABQAHIAYQBjAHQAaQBjAGUAIABTAHQAYQB0AGUAbQBlAG4AdAAgACgA QwBQAFMAKQAgAGEAdAAgAHQAaABlACAAZgBvAGwAbABvAHcAaQBuAGcAIABsAG8A YwBhAHQAaQBvAG4AOgAgAGgAdAB0AHAAOgAvAC8AdwB3AHcALgBvAGEAdABpAGMA ZQByAHQAcwAuAGMAbwBtAC8AcgBlAHAAbwBzAGkAdABvAHIAeQAuACAAIABJAGYA IAB5AG8AdQAgAGgAYQB2AGUAIABzAHAAZQBjAGkAZgBpAGMAIABxAHUAZQBzAHQA aQBvAG4AcwAgAHQAaABhAHQAIABjAGEAbgBuAG8AdAAgAGIAZQAgAGEAbgBzAHcA ZQByAGUAZAAgAGIAeQAgAHQAaABlACAATwBBAFQASQAgAEMAUABTACAAbwByACAA dwBvAHUAbABkACAAbABpAGsAZQAgAE8AQQBUAEkAIAB3AGUAYgBDAEEAUgBFAFMA IABwAHIAbwBkAHUAYwB0ACAAaQBuAGYAbwByAG0AYQB0AGkAbwBuACwAIABwAGwA ZQBhAHMAZQAgAGUALQBtAGEAaQBsACAAeQBvAHUAcgAgAHIAZQBxAHUAZQBzAHQA cwAgAHQAbwAgAE8AQQBUAEkAIABhAHQAIAB0AGgAZQAgAGYAbwBsAGwAbwB3AGkA bgBnACAAYQBkAGQAcgBlAHMAcwA6ACAAQwB1AHMAdABvAG0AZQByAF8AUwBlAHIA dgBpAGMAZQBAAG8AYQB0AGkAYwBlAHIAdABzAC4AYwBvAG0ALjCBhwYIKwYBBQUH AQEEezB5MD0GCCsGAQUFBzAChjFodHRwOi8vY2VydHMub2F0aWNlcnRzLmNvbS9y ZXBvc2l0b3J5L09BVElDQTIuY3J0MDgGCCsGAQUFBzAChixodHRwOi8vY2VydHMu b2F0aS5uZXQvcmVwb3NpdG9yeS9PQVRJQ0EyLmNydDANBgkqhkiG9w0BAQUFAAOC AgEAsFcVBnu/4QCC+58H4Fb0rIQ1nIF1aHhRUNpweD+7Ndc8dmlPRQFtHS2vQrAz bv+cCvup0fyp2o+lS0qHLSKksuD0Fw4EuOsOQnMH79S6j0IS0w4tu21UyQHJP03W 7gxCVonaYjcLoUh9bMSxx6tEYsumPPRloH3f82BixYr4ifXbIYZTnefIME/bJXE5 LYTxKXghVpnWX0hJuzO4yc884ysVakReOglgPsDSIBZ2vGbyWwMZP0q2np7dohpY PnPvt2l7e5AHOZpnM7tWkrr+rp1iS1VhLpYfxlSVLWW+SRgR9/f9tsYGoTIPdW8W 4SRiyA5vOvKVgPGp+6B9TdWiQx+FYNZceSvMNM+hd+/m085zhbTYZ4mZvG/LDgcn LnVRiX/BO98NA7+IF+a8+pQMqBmww9GqgKgZ2bZE0pUrVyJbyC2uDtAIraJ7NADg lv+SyjnNwMPSzLn0N8NWpNemGoAebDNyzVb7X+Xd3DBb7rhMs99asJEk4o0cMQ8p swcghdZ2yj66d4v49VCFDU82cWtVEglAOwMVOP7ll3hLKB24gLuOsvrgsh3CeIkp s44M7ABfTke1ncvcTcLIdcg+UEbYfN+GyvVxKpQKbVdveOry1+XjV1R3W2KX1+yR zkJz3pBKv4IcldkZSND8mycZ+4nz5hATRNkCu8VfY29lmzE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGGjCCBAKgAwIBAgIQAMoieQgjKvD1griF02Pd8TANBgkqhkiG9w0BAQUFADB/ MQswCQYDVQQGEwJVWTErMCkGA1UECgwiQURNSU5JU1RSQUNJT04gTkFDSU9OQUwg REUgQ09SUkVPUzEfMB0GA1UECwwWU0VSVklDSU9TIEVMRUNUUk9OSUNPUzEiMCAG A1UEAwwZQ29ycmVvIFVydWd1YXlvIC0gUm9vdCBDQTAeFw0wODA3MTQxNjUyMTVa Fw0zMDEyMzEwMjU5NTlaMH8xCzAJBgNVBAYTAlVZMSswKQYDVQQKDCJBRE1JTklT VFJBQ0lPTiBOQUNJT05BTCBERSBDT1JSRU9TMR8wHQYDVQQLDBZTRVJWSUNJT1Mg RUxFQ1RST05JQ09TMSIwIAYDVQQDDBlDb3JyZW8gVXJ1Z3VheW8gLSBSb290IENB MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsT3SpyVwl4N4DtcyyWYO eCPkKhvsw+9ThYO7ys9+6lOZbSdVyNE4IUBuSU3DPfYJKwYZQ6mYyQFO9KqAMAdV 8/W3fZm3c4XVHGVWbA0ymwgONGEqQAmEN8Nm7Q1MnAx4QDrs7avMpITydTGVQKiq u5O1d5hs8sjgIVoj5EKnk8ioHTjOpBpAQL88k5CbX9aUwSJbRtfFABXVj8b33guv bosFj1uAlQ6jvZPMkPJ940h+ss0HPRvtFJB08900H3zkA1nxLc3go6A7IS5crqwI BlAVMTXuX/kfDTSlgG5ick/jIbo4QF1f22gqXDTGCDv2fC6ojcS3pq3Zm78ZQQ5I OQlmbg00AcW7BxEjpNr+YJYoR9yPZ5sTr315DnjNwIwvuyEs/HQWHt7AMp36eDqG uj7JeAoA0eTgyRLiW9zru4CaMjWr8DDDDkiEL40ICvYsjE0ygEVVCNvNDai/CHq4 52hdmpSJlbz8mo64fzrYbNX0GKxp4qTBC7Mfo4Kf84o8hUA4CfrCBT7hnIn6wwVs CI9dUfR/u8TzbAG9PU/EGYs52crM6XmIBFWrbbjaFkVlORUFGPsLLHMB7ZRS5X0M ATsJoE3xPQiBZjQ2F0TwZ/Nb8gW2IZhY2fShN9lv5u9WxPu/VmICrDAwtgLW0hb8 TuqHQ5poXYijkUYoK785FRUCAwEAAaOBkTCBjjAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfbtp64hh4UDPRyNkAIaiZmvchJUwTAYD VR0gBEUwQzBBBgRVHSAAMDkwNwYIKwYBBQUHAgEWK2h0dHA6Ly93d3cuY29ycmVv LmNvbS51eS9jb3JyZW9jZXJ0L2Nwcy5wZGYwDQYJKoZIhvcNAQEFBQADggIBAFbf E4m+YrcOgSFzpNQ3yu23L5V014n4S0eB7mftuCnfIaD8VGdnyFcsW6EKdXghIcqg qN9rnNk2Ao24AcFvjntsyaSyxUapykwCgfqje509SObKQGbSRJ124FW5ppyn0UPY 9aC0nfj35aamQvMCMllGcisU7F5l1VGBeM6qL42WiXlq+w/IW8+0rpC2X+N8Ymy3 pv+QgbWYkXMSMK/H6IECaHMpu1h1PbfWQ9WuTfJCufDf2jEAE9rhs7YGi1v9yZi4 ohPRuo/BihqeD/+CvgSC5SuTPh61ogwbxhqwc4l2g7yOO7sXbRTDi759FSa1qZwX elB6LevpmZSumBC97ipdXdaONFusHodga5jHh4/TnLJoBUkH+akxZpz+v6dZ6Czw NtTyqBmCwJ6nOfmxmDSjH/rNyRkteN63/WLwk6P+AFvWCuTzfnyXKOEF7AU0RRP/ KRNhiidP27jSkiEntYh3Z6h+zyQ8hwgEM3OPC7aG+M/vsqYkHguRkQBQFjIS2Akl 2mNO3dst1+cEa+NjH6n+qQFjxMpMFGiDvAWsWRb7bqEHb7tLvm2YSHYle0oRllQI rKnzN6uDw9HNgZjA5UA1uJ+R52/mSyAWilN7rDrRmDVU0NS/rn6aSx7pdaMlsDvn Zb9PlfQdvcS6yU2BUcI/WtkS9CEb1pXqPZD+qZPi -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR 5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s +12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 +HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF 5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ d0jQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r 6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx 3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFezCCA2OgAwIBAgIBATANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJUVzES MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDc0NzEz WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQDLAQxkgbtQSJnzHNkgsIukhxL3rk/OXnPLqIYV4hz5mWMG2hzWCrz+lLreYIFo nLLyS3cB2rcbxvn1YJAgePwxSj41d8AaHoxZVXhVcEGSCZsCSsNvrAuY6bJSfZp/ v10fA4dC/cMc6mMwZdG1jpxpWmvuM42vuvpjJFCJLckFHmzrjl6OAUihgMM4RStO H/QiwvguSnZ+6s6c0RiHV/a2+u3MkFWOgMo1udpkZRbM6WRRWT77is6AsKWSRWP9 m5YAvFxeho7FSd8UqMmRm3j3HIwmhmia+YHDgXs9M9sQXj0EadZm4K453Ini5ib7 UX97qAlrhyY4zdmNLZ49yrHzK5v9Ru2B28+FIb7ARcnlid12l7+0gUQpO7eYFzTy uKqasHtBVSbBPLQkl5atG482cbcr87aDAjD6sgoTvEu2D/mjnWNuIlDTKNxfNgc8 KaxFaOoiQF0/CccKMo/KtOXo19fKi2T/b2Ul7A10qLUcGibmKLJyzs36xCRKNxLi 2LcJzqwuJz3CFOvqMIw3ynMZhYmzu/s4Qx15paWLGSSgphJSGv7RV8GdEnudldZs e0odwa4VAk0sY6B1Jz/+8gAgMkrlsawuE+BIpvROkVQM2XRYPhF17fqcwqq7SH/L 9l9cJrAJh3rE/Zx+rzNnQlcWU/7xPUNAUoq2NXFP/AE85QIDAQABo0IwQDAOBgNV HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyERa/n/9qZuG Nb7ipfYZ+16/b1kwDQYJKoZIhvcNAQELBQADggIBABKL3dUInShvCPGJVm1AB6v7 4QioBKS+132FrlpYtmdMAWnNrIs2jlz9OzYB+dWheyh6TISTzcQLGfASBIlNj+2g mSWFuyyVmWww7W0Eb+Yr+4kQu0yTDL6T1dYJhJMAcM/OxXga7VVU3y8OWVj4NYWu T/gh0pLeIbqZ0ZfxYJ6sREOnYK+J4lHSOYkQlBXPBNIhgu/K7WkVTxmrvJNqmQHg AtEcOp0xyvX7xPZNmrsgjD9vcTJ/J0tEf4FR6ZMbYg6kh1893VRAuSSXYleVjscQ kaeYxVhCUKmWHOVKtray3E6R8oDSkehQCNMWQIkPaBOuw1xXFxMX7TMdsuqR9qou cURAibLgZr2xvRc9TT0PVzklZQRqKoPbOLXOv+QA100oN5CoqabksVXwys/jDGov R5a31OTvyDcDPH/rgZKKKmmYHQE7SIota6/lz7K03dZneoABCwRXJbZlQg9J4SPK QKrCLPyFr2UYqgcx2y2u68Nx5mjfN5f5mj/xJV7w31fp/BLgOQaHdN1jk2uBxPPg 2wkU2L+/QG9xgSZo96WFF0BSA75ckxTlQVIVd7w1oUdzKgyXXIzeMTxjjPCbX1RP 0uJbbDwcw+c0ZnOmQaMgMkR7zeq8aZf9Q3AxvDKComWYo0Avakb0AFAuVeDbek7g bcho4VTolYMYvvrNjx1m -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIICTCCBfGgAwIBAgIQZ9a23dRLHqpL7JR4cjWXZjANBgkqhkiG9w0BAQUFADCB sTELMAkGA1UEBhMCQ0wxHTAbBgNVBAgTFFJlZ2lvbiBNZXRyb3BvbGl0YW5hMREw DwYDVQQHEwhTYW50aWFnbzEUMBIGA1UEChMLRS1DRVJUQ0hJTEUxIDAeBgNVBAsT F0F1dG9yaWRhZCBDZXJ0aWZpY2Fkb3JhMR8wHQYJKoZIhvcNAQkBFhBzY2xpZW50 ZXNAY2NzLmNsMRcwFQYDVQQDEw5FLUNFUlQgUk9PVCBDQTAeFw0wODA5MDUxOTM0 MDhaFw0yODA5MDUxOTM5NDFaMIGxMQswCQYDVQQGEwJDTDEdMBsGA1UECBMUUmVn aW9uIE1ldHJvcG9saXRhbmExETAPBgNVBAcTCFNhbnRpYWdvMRQwEgYDVQQKEwtF LUNFUlRDSElMRTEgMB4GA1UECxMXQXV0b3JpZGFkIENlcnRpZmljYWRvcmExHzAd BgkqhkiG9w0BCQEWEHNjbGllbnRlc0BjY3MuY2wxFzAVBgNVBAMTDkUtQ0VSVCBS T09UIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApICHJduVUuwY Pz4hL5SBnacjGsNqTkZemtgnf/Sk8RiwvZRM1Ir7RIhFxF4nmX5jaoQSVHHXWTu4 qBJOsact4OJ8RxTNtXC0YpTHYqP7bZU6ZlzqfsqM/uofY/XJW+tAnYTYM6jdgax+ ++i4mbuSeWT/Cm+DN43eK60PDbvnw2H9sEqzGuAQ5h0VDDddi9+8PSvy7YoBpEBL /UJoGRRjNDVbxURrzFCYnJ7ta93rB0M7HWwLBH/O4rxiutM+y0sUImw7tFb0uifb IUUPvhaVklS18fkXp+fth8Gd1pK3rGGNF3ZQdh5RM85vfiQrjhRvzXzErWNwntLO 7jxXxhqUQAVdY44l15Fj4sZiWh/Q7PfU3w9NVs1axY0nqnaDjmYaHJXj+YKWnqIT VE3W1lIO7EOGQf9URp6UNaRgELYEy5jZ9nx967OhA+nYuULfb2AmbkfwiRPlgSwH +/1W2PvYae4+h6n5jPLyldF8yIqdw8TBNNMj5Qs4rHIW2sP05nKblJstP1O3XbHc ZBAjiTnGx46Fe398NJiFNvG6x4mHIuLyPqngHecrMGOsdFX34DLJ4y5uiRW+LFHY EAp4qc86DTfpgpIKlYfnAzxOe9vo5nIICNn/nTvZo/fy8hUQnTlO9y5zJcvtv1Mw 1X//GfcXXVQqNkhWzzXrdKzUosa6OFECAwEAAaOCAhkwggIVMA4GA1UdDwEB/wQE AwIBBjATBgkrBgEEAYI3FAIEBh4EAEMAQTAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBRQ3YLRiJItjzzpul3HYmbib3urIDCCARMGA1UdHwSCAQowggEGMIIBAqCB /6CB/IaBumxkYXA6Ly8vQ049RS1DRVJUJTIwUk9PVCUyMENBLENOPXBraS1yb290 LENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxD Tj1Db25maWd1cmF0aW9uLERDPWVjZXJ0cGtpLERDPWNsP2NlcnRpZmljYXRlUmV2 b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3RDbGFzcz1jUkxEaXN0cmlidXRpb25Qb2lu dIY9aHR0cDovL3BraS1yb290LmVjZXJ0cGtpLmNsL0NlcnRFbnJvbGwvRS1DRVJU JTIwUk9PVCUyMENBLmNybDAQBgkrBgEEAYI3FQEEAwIBADBiBgNVHSAEWzBZMFcG CCsGAQQBw1IFMEswSQYIKwYBBQUHAgEWPWh0dHA6Ly93d3cuZS1jZXJ0Y2hpbGUu Y2wvaHRtbC9wcm9kdWN0b3MvZG93bmxvYWQvQ1BTdjEuNy5wZGYwMQYDVR0lBCow KAYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUHAwgwDQYJKoZI hvcNAQEFBQADggIBAHWDlT8h7XR5Lt7bHnbyIcLblmC+m7DFTgtXLkkoorbDpi5Q BIsATKmzcoWk5nRvQm/Sm9Q/+NToMWtXPoHLsYbOsH7Z2OPt7uAE13RwrVUXMbG8 FAVXmVKi53vD7ttKs7P67KdDtMITVl8KMtENWFXgMD9kBwSqz28LKa/tiR0cwOaV AxmBt7Fw7OF6fTg6U8Xc0rnqginxTa5d2ejFnahGJGkLaikpGqnNL9zi6YMZ4nNp 6+ry1tdoFhleymLrSguPBFb17pVdEhHjDVCgzfTrYX6oIKLEUjcx56aFMGPftkop jliIz7V1WGhcm9I/EoasppONh5P3MRipV9LON6UXRV9nPoLb5TpvCpiSBr9gXTqE pEUSQ1BAHFaUJf2nUgpsLcTooM1xQuQ1C6hRiaT5hwj4HQj6rg6dAr0tf1luHQGC o4lwY7RhrmMkNXQgTcDXGHLprCyvmVGDbqN7F9j8chXzxxHES0G0csRw/1hRIaHh K2Nl5XSQom3C/5F9rU8HNyUYqp+cLRwodk7fgq7OQm4Gkjy7h3Fxoe40H+wNDhf1 p/ha+mbkfefR6IIxZUe7cp9UleRHmiBM+vgaRcloy0SYbuyZLRBdy9js+wpUSaWP MNPfhhPQVD/uJLOhJ/wg73jjkbnYlvJEum5fiQnKeidO+/mMrMEXt1iJ/3Y+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4 Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0 aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N 8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K /OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu 7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC 28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6 lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB 0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09 5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q 619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn 2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG 5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0 BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN 8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ 1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT 91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p TpPDpFQUWw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi 1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP BSeOE6Fuwg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHHzCCBgegAwIBAgIESPx+9TANBgkqhkiG9w0BAQUFADCBrjESMBAGCgmSJomT 8ixkARkWAnJzMRUwEwYKCZImiZPyLGQBGRYFcG9zdGExEjAQBgoJkiaJk/IsZAEZ FgJjYTEWMBQGA1UEAxMNQ29uZmlndXJhdGlvbjERMA8GA1UEAxMIU2VydmljZXMx HDAaBgNVBAMTE1B1YmxpYyBLZXkgU2VydmljZXMxDDAKBgNVBAMTA0FJQTEWMBQG A1UEAxMNUG9zdGEgQ0EgUm9vdDAeFw0wODEwMjAxMjIyMDhaFw0yODEwMjAxMjUy MDhaMIGuMRIwEAYKCZImiZPyLGQBGRYCcnMxFTATBgoJkiaJk/IsZAEZFgVwb3N0 YTESMBAGCgmSJomT8ixkARkWAmNhMRYwFAYDVQQDEw1Db25maWd1cmF0aW9uMREw DwYDVQQDEwhTZXJ2aWNlczEcMBoGA1UEAxMTUHVibGljIEtleSBTZXJ2aWNlczEM MAoGA1UEAxMDQUlBMRYwFAYDVQQDEw1Qb3N0YSBDQSBSb290MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqPK9iL7Ar0S+m0qiYxzWVqsdKbIcqhUeRdGs naBh1TX55FqDNmND3jhXFfzwlGL0B4BXg1eosxW8+00jeF/a9seBFr6r3+fcg1Nz K7bdY4iNRfMN3X2/6IiwZsFDXTfSbaGcmkbDsz/QwqCKlC6DpjzDYL0szB6LY4J2 QSjkFWtcDGE5VThByshm6Me4l1IQJnC3B7cJHqYTXq6ZWiZvZD3sxNOluVx2ZK1j fYiD4kvMDd7UxtMIQvVbF/Vx4ZEtA5+eHNyLcqToR2QQh2Qwc9jytPFXJpNXy7bH DYiLHc8FMF0E1nY36CAyV78PnDPGCIz2tMKpBrBbMKEeLRK6PwIDAQABo4IDQTCC Az0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgboGA1UdIASBsjCB rzCBrAYLKwYBBAH6OAoKAQEwgZwwMAYIKwYBBQUHAgEWJGh0dHA6Ly93d3cuY2Eu cG9zdGEucnMvZG9rdW1lbnRhY2lqYTBoBggrBgEFBQcCAjBcGlpPdm8gamUgZWxl a3Ryb25za2kgc2VydGlmaWthdCBST09UIENBIHNlcnZlcmEgU2VydGlmaWthY2lv bm9nIHRlbGEgUG9zdGU6ICJQb3N0YSBDQSBSb290Ii4wEQYJYIZIAYb4QgEBBAQD AgAHMIIBvAYDVR0fBIIBszCCAa8wgcmggcaggcOkgcAwgb0xEjAQBgoJkiaJk/Is ZAEZFgJyczEVMBMGCgmSJomT8ixkARkWBXBvc3RhMRIwEAYKCZImiZPyLGQBGRYC Y2ExFjAUBgNVBAMTDUNvbmZpZ3VyYXRpb24xETAPBgNVBAMTCFNlcnZpY2VzMRww GgYDVQQDExNQdWJsaWMgS2V5IFNlcnZpY2VzMQwwCgYDVQQDEwNBSUExFjAUBgNV BAMTDVBvc3RhIENBIFJvb3QxDTALBgNVBAMTBENSTDEwgeCggd2ggdqGgaNsZGFw Oi8vbGRhcC5jYS5wb3N0YS5ycy9jbj1Qb3N0YSUyMENBJTIwUm9vdCxjbj1BSUEs Y249UHVibGljJTIwS2V5JTIwU2VydmljZXMsY249U2VydmljZXMsY249Q29uZmln dXJhdGlvbixkYz1jYSxkYz1wb3N0YSxkYz1ycz9jZXJ0aWZpY2F0ZVJldm9jYXRp b25MaXN0JTNCYmluYXJ5hjJodHRwOi8vc2VydGlmaWthdGkuY2EucG9zdGEucnMv Y3JsL1Bvc3RhQ0FSb290LmNybDArBgNVHRAEJDAigA8yMDA4MTAyMDEyMjIwOFqB DzIwMjgxMDIwMTI1MjA4WjAfBgNVHSMEGDAWgBTyy43iNe8QQ8Tae8r664kDoSKv uDAdBgNVHQ4EFgQU8suN4jXvEEPE2nvK+uuJA6Eir7gwHQYJKoZIhvZ9B0EABBAw DhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBwRqHI5BcFZg+d4kMx SB2SkBnEhQGFFm74ks57rlIWxJeNCih91cts49XlDjJPyGgtNAg9c6iTQikzRgxE Z/HQmpxpAeWR8Q3JaTwzS04Zk2MzBSkhodj/PlSrnvahegLX3P+lPlR4+dPByhKV +YmeFOLyoUSyy+ktdTXMllW7OAuIJtrWrO/TUqILSzpT2ksiU8zKKiSaYqrEMpp+ 3MzBsmzNj9m0wM/1AsCMK4RbG0C8ENBQ4WHWZlaaBJGl49W9oC4igbHZONrkqIdf PEYElt7Jmju/rXhsHUlJtGm5cA8Fkla2/a+u+CAtRyPPthzNxJuATvm/McBUvrsx f/M+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFhDCCA2ygAwIBAgIQAIG73WskH9q0vo8b2ghVxDANBgkqhkiG9w0BAQUFADA7 MQswCQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xGTAXBgNVBAsMEEFDIFJB SVogRk5NVC1SQ00wHhcNMDgxMDI5MTU1OTU1WhcNMzAwMTAxMDAwMDAwWjA7MQsw CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xGTAXBgNVBAsMEEFDIFJBSVog Rk5NVC1SQ00wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC6cYB6TIZu f8gTbcDGfRwAl48sDCO7EJpAqRq3h4j4m1Zq++Z7jouSjqclXVkR2zYut1EXH6kI HwQXJFiqN0oY3+U51Ff918EskQGR4iLUA8BY/HdH7I8+dEO6rDSNTTh2Z46wyG8w M1hxXLT1a27UAVC4E35sSqNJ0SAZ7rzAKRhlp97+790KkCHnGmeSQhCYX08wvD4c RbQQ12hAFMBA+ud3F3rmC49lWzzZmlLbtb2eRs8965EFAsCWsnZMTRCWO5L6nH8P md++IzVFHgJc/rWom5kl2l7zIsM59eQqLtPGH8RsqsUcagEFSi/SxcGoNCZdZqXS AiH5GLcG9U6Zb6irTFHoz1AYxXfIOQksSZIymai7Fxd5sFrF5qPEWWVHNYNeqeg1 C5m75M0gxptKBjm1aPwiuu5VjCtO6vOx4/y2mZrVQvpxTQjPhx5qcX3507TppXGB e8JOR5al9naFoyiP6YBugVOlbV+4SPnC+TamLkn/uJbCjAezm4hY/OsbHN4tcOKX kjChieO8Vagn1kvtkK2L+mMlWS2oNd3KlzO85c3HndHs714OSpAGJmOtudk1LQe6 dmUsrFePffQHlNeBApZdowdJ1XrQV/kb51NGdaqweULLaHEI6WC9OWnO9K/DVkDH rVKiCeRvhkeKH+soJ12DIK8EyWxWmotG9QIDAQABo4GDMIGAMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBT3fcX9xOiaG3dkp/UdoMy/ h2CabTA+BgNVHSAENzA1MDMGBFUdIAAwKzApBggrBgEFBQcCARYdaHR0cDovL3d3 dy5jZXJ0LmZubXQuZXMvZHBjcy8wDQYJKoZIhvcNAQEFBQADggIBAHa5Jte8YHw7 w8eEUZJZebaNv1PgvIigtdlM6a31Zk7voGDIC7iR7TOOgvGGlf7G0xqJq0872TMf 0AvHsfVPpEu7AwwjXGyw3qxy+mneABDN8dbPNlK+f/wmQfPy/DDiMcbbED6pdLpP 7O0gmcmw4qKjqUKZM8t/96oC6SSWKvjkzl1BoAYJVVra3xpP6zn8X+CpqUTXGOqV sUR72uo4CXQeZyg/4Is5LFP6DOA59ysaDjEB1GZ5iHSdSEiOtJNh5r8pCe++Bqka bAhwBAq/bgl2pGRDzh9XnZeebPh0FxxRA/pgU9RWRpbQUJ/GnTPzQ7Go16LJsMmD sX3H3KyBdteJ7UMm1v+iXKItoCRHqkaaaTEJwf0QebCF7HAg5j1BVKJKYi/W3kzD nI+9y6ZVlBzdvUHPKGWN0E3Xh9FM00NzIezXLhdnMoe20Bt0qmnH5GyH130Zmuw9 RPGqgllyzUXb2mZC4ThsNl9U3SZWV6LZPqQK8u/8GYAf27qqgLzYUc1UatV/2G+1 3Bb7QOJVVJDD3Ycz0f8epWKLNkSsqL/A1sSUd7O9xHUkaen/OZSr/FFnJOpAHuuJ LRMGfa4HocMM9dRask63IR0XxeW58h/jhgFdCwZ5XcnKPxZ+gR5NfvCaPCXFznR5 nkrh8en1JUb2xN7kRGRzHcY5PnrmhXsY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z 374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf 77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp 6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp 1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B 9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C +C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGITCCBAmgAwIBAgIGSUEt7AAQMA0GCSqGSIb3DQEBCwUAMIGtMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE7MDkGA1UEAwwyTmV0TG9jayBQbGF0aW5hIChDbGFzcyBQbGF0aW51 bSkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUxMjQ0WhcNMjgxMjA2MTUx MjQ0WjCBrTELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQK DAxOZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAo Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcykxOzA5BgNVBAMMMk5ldExvY2sgUGxhdGlu YSAoQ2xhc3MgUGxhdGludW0pIEbFkXRhbsO6c8OtdHbDoW55MIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAzfLuxBp663QpTLa95NYKF2xl4mY9xNG8DLZa 1itwXy3MIdFZEOSxE732zCKV1mxGTpEys+v1rMsEAU923VM+eJ/5Xry1ghNGyhDj HS1pK5QyEHMhq6k4xeNuE2TVY6ntCWbsim+JjRGG0PW/MpYLdXD1KFhCXqxptPX8 kTkuopFA0TxUQYcjZFBIeWhLaJNLcuuAabNKHJC+skGjpc0XwNEaaX8CGEq1Yocm Vy1sqCwhOfWXXpuapvjnTHnEeztW3Hr4tFjOdgquIlXrj8eEZHu9a8qVT9i+MRO/ jaEKK9V5t/V2rdpRXIFHYqiq/89T4DRxzw0lU6meY0evhZH4zxkR5U75z+3jNQUB IgPPmnzqHVFay/1zPTkLMevEO8qFKhEUAKAbgaIJiEjzfKJkoexntFiH8BTqqb6l IkFN7L2kDug9h/cvqs41hk8wV5KNNq541v0Y/NclHs96/Bn9oD9yFzYIQT+XNpUM iZVxRfqE1tQgYLNFCvK3lT0L5aTDuBLykWzpbWCD9kURBbrmR4PZkeJu4btGa0gb vMb7z37eLLuQhO62JznnjaIxD9+BtyxsAOKx2CoXXBseR4lLF1EUQEBPxDkYMsKA YDblekdn9qgFVMFdlqAftohSDAK+jVV+FEvDogHunIpBXflflpEJjrTktcUE39Y2 rVm0stcCAwDzkaNFMEMwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFOahE4P+l0vy2P8xoad0M4nOXn+kMA0GCSqGSIb3DQEBCwUA A4ICAQBphELA414TYZcgSfH0FoWln6QRCCXEY4aP8Euvsyn1B1caYscbRW6vXRa3 wdBkgzuX9UO2RZDxZiqDJCr/iOl6C/nCW3qvY/cJeIZIWTRem2oQTvFulYk2SmjQ b5vgfk+3NQ/jebEFryd8qokKQ976DO/ZVy8occ1pa1JCyYowRVmhzPpZSo/31t1E pbMuWxEY4rK15xFTOP6CTNNzvmWSGjqo0tKqvNS+bTZS/2vU0rUbN/MXQvEup9WQ bHSddPX6XyIb09x1qLX/8hrRvCsAXDzFuIYIVEminCP776aNcPRCUk0bIACB+KC4 9HQjnL70uQ7sHmrYZUoVdfF3W27YseYPtJa4HfqGyJJui+l936IO1fHxfK5K42a/ Xfxb70iynmnHfZCgVbaUcIG5Cr2JdVPshKkDpd9RmQjQdAwC1nNyBnuLu12qTvxn Z9iOEAMZLTc61HepOhydwHl7bCl3Mk1KizCIwuc2zmijmpiG+YkVnr+qUX3xUEZU DwIuXJ/j3lczFf4YkmGo0ikFXWVEHpvj7/vcBd8Vq6bYC6Rzskw64J7Us2rlOg4K 8E7PeIEfvqmYb7FHUX1CMzazpqkCUgV0fips1KqSVrA+OyNYsY01pxOPZx5xFaaz tQOGuCBmwEhvuazUSgNVsjffBN0iDFOGKkoqocE4PjzlPN91lw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH WD9f -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni 8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN QSdJQO7e5iNEOdyhIta6A/I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIQLu/b+9iJPY9JHJNy/kXf7TANBgkqhkiG9w0BAQUFADBQ MQswCQYDVQQGEwJMVjEoMCYGA1UECxMfU2VydGlmaWthY2lqYXMgcGFrYWxwb2p1 bXUgZGFsYTEXMBUGA1UEAxMORS1NRSBTU0kgKFJDQSkwHhcNMDkwNTE5MDg0NTU2 WhcNMjcwNTE5MDg0ODE1WjBQMQswCQYDVQQGEwJMVjEoMCYGA1UECxMfU2VydGlm aWthY2lqYXMgcGFrYWxwb2p1bXUgZGFsYTEXMBUGA1UEAxMORS1NRSBTU0kgKFJD QSkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDEBGsAw7DgLjvoUwUF CL7IhCdV1h2KEuIXIlps/7PdtpnDysHq+dgltd86nZ0/UsXp8qy/iXSKVK5Oz27y Xq7avRIHmZXPZKv+mZFkWYzJvkRqMZuY6rrq0SEOKAs5m+PWiqb3Aro/PdlZ9HmZ 3tMkm4twGyqE1uUJDyYmJFiPJV7zxZ10iaU2xeVSsuvohpNHbqcph6R+3LSjyzJW 90WA2lzHL6Cn1+/1/LWozYSVYvipKyM7bdO3ksjqwbwUTehrnBZ60+wH+wclEE8U h3uSNs5WgmVLEyYG2KOjpt/Cevt7NQWiEz0+drwcV4MDUcc03lr1PL02JZwWD03O 6A0ay11DohRvunxg1AKFdsVrKrhFsVx3RxGtoCWpZpGMURdtYVUKGT+bAv/E9dbS s+klU+EEPY8i0KJl5a6ntOAdkWrChpL3Ol0Tp3pMQt9as0qIRCzvR7qpr9bPYnOK BiIWLMLsHwao00dQWTIS5bmdYjWeyl4KtJ0jiMLTTywsyZPofrgJ7KbZ3WPhyahq aNyEUaxaEuc7prUHCrGqTrO0olffN2wWTquZMnrwnCMli8qaqIzgOCG0zvdsYcji DBJZBoEmNloPNXPUFkX93pXe1ktcn3PZvhm957/kVWrIa0T3x7gziHkZDQZk6K8L oXUMUmW6CiOVcfdj/H7ljI/M0QIDAQABo4G1MIGyMA4GA1UdDwEB/wQEAwIBBjAY BggrBgEFBQcBAwQMMAowCAYGBACORgEBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFDsmA7rP41lGQlCtFJy/Azvv1j4xMBAGCSsGAQQBgjcVAQQDAgEAMEQGA1Ud IAQ9MDswOQYLKwYBBAGB+j0BAQEwKjAoBggrBgEFBQcCARYcaHR0cDovL3d3dy5l bWUubHYvcmVwb3NpdG9yeTANBgkqhkiG9w0BAQUFAAOCAgEAheamlOTZRl+dv5O7 +Wt2ZCiuvzxFKoqTeWzTS4iGIGsiJjg9HBOq62GXbC4+V5xsQ6LebUDEMfJtukYW sy3Gu6bc5S+x2MHVkR4Rf/tfodwdYfhtm2Hw4j8rcdUNy97fZT+gb5WbesvbNTcp XV6duVSxrGAS5WPZza9SGwWWE3zaJHUBrdSepcvBEkVPV68jvym86o6tePiHI+hI y0Covl0z1uzGBkPCZyro44UuYJ5ELytPMbEHnZUh1SqSr4CR08cpvc3xFQyfAe74 LTukB3BJeSTtvKHTllGCn8LIvN4jmsdQK5q2eFKqzpX2YDuimfkmZvRHLEElvEH6 1ot/vV+CfNNFhbRM2OyzF+9EOvUoZe/1nnHMId7o1lEcEPtA/EnlXIQXr6oZXqLt Th6i+8pHHBxkPhSRojkZNIh/kcs7nRlw6ij7/FAPzL09XgIDa3k1REF27rYtdITh gnHTJbDTw5lEqz/iDKXuvab8pBEA7py9N9HWYsQwFC0QCpeKiPUlPJa+RkAaisCF dsSgSeBJpecZtQnzzE3tFl6a1NPIadDYijeFa07kqgeSXNRxcYFI03j1VmD+zALU AJMfTJJAl75yU3kuJlK+pqN0sZTZFGM6blvRPJInUpAyWpLSD05bCwY6YuXWJwwB 9iUCuIsQKUKp92nK3OsKkksoMYY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF 6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF 661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS 3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF 3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy 1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 +rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c 2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v 1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgIBATANBgkqhkiG9w0BAQsFADBcMQswCQYDVQQGEwJVUzEZ MBcGA1UECgwQVmVyaXpvbiBCdXNpbmVzczERMA8GA1UECwwIT21uaVJvb3QxHzAd BgNVBAMMFlZlcml6b24gR2xvYmFsIFJvb3QgQ0EwHhcNMDkwNzMwMTQyNzA0WhcN MzQwNzMwMTQyNzA0WjBcMQswCQYDVQQGEwJVUzEZMBcGA1UECgwQVmVyaXpvbiBC dXNpbmVzczERMA8GA1UECwwIT21uaVJvb3QxHzAdBgNVBAMMFlZlcml6b24gR2xv YmFsIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCKAAxw Hb/rNIbDmUU1Hn9D96tvJC3NGcIQu7DKKVupIKurcizE4gI5bYK4xRHq+PuznmL4 Mx6wH8nj9jfbBMg7Y0824oWkJR3HaR8EvWhFE5YHH5RQ9T7FJ1SewElXRI4HY9Sm ru0imcxNlmkEE252iZ90FpT5HVS9ornSgwEiDE1EgKr+NYknJaeGicbVGpLjj8WV oBRymuhWxQJVHJf5IC7Q9TwTGVr24fkLA4Jpp4y31m+cVj6d6CoJYG1L5vuLmRT3 NE9lWYCNuVfIojUh2IhxVl3uglctJpAYn5qcnI/v1MVjp1R9R5GHfRoSqBsYb6lv sSe65AR0zjcef2bFAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgEGMB0GA1UdDgQWBBRMOBG4mABbWitwPqp45NVnZ2enfjANBgkqhkiG9w0B AQsFAAOCAQEAAV+gsQYB9HnXZRhgPs95oLrCI08j34eWX4EOOBUuXMgCaCkg/Ivu pYoYgWRcmDV+OTCCpIKKULW6w+ha1qie4sMX29vE67AKIA3pnuP/YFRH8Tud1Cg8 oq6j+6qLgiIqNYeQuBxZR5DVnS76SeNlqDbrx+QcaNyzMWyrTs4kgBXIEFkQEXJN epyYnMT8YeCzsp1OoMbCWasY1qJVRewpqiU31k5KPQtAweST5PzNkQv45qvMs3bE Yr8Z7Ya2ecMpVFS8mX1GV8+mz/RUKpoDZUcBoUIqyyVHbnxeAEuR2fkbEAZw+UIV pl+q10Ae/clInZeB6lxowqDniaFTTb/H4w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFfjCCA2agAwIBAgIJAKqIsFoLsXabMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJjAkBgNVBAMTHVN3aXNzU2ln biBTaWx2ZXIgUm9vdCBDQSAtIEczMB4XDTA5MDgwNDEzMTkxNFoXDTM3MDgwNDEz MTkxNFowTDELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEmMCQG A1UEAxMdU3dpc3NTaWduIFNpbHZlciBSb290IENBIC0gRzMwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQC+h5sF5nF8Um9t7Dep6bPczF9/01DqIZsE8D2/ vo7JpRQWMhDPmfzscK1INmckDBcy1inlSjmxN+umeAxsbxnKTvdR2hro+iE4bJWc L9aLzDsCm78mmxFFtrg0Wh2mVEhSyJ14cc5ISsyneIPcaKtmHncH0zYYCNfUbWD4 8HnTMzYJkmO3BJr1p5baRa90GvyC46hbDjo/UleYfrycjMHAslrfxH7+DKZUdoN+ ut3nKvRKNk+HZS6lujmNWWEp89OOJHCMU5sRpUcHsnUFXA2E2UTZzckmRFduAn2V AdSrJIbuPXD7V/qwKRTQnfLFl8sJyvHyPefYS5bpiC+eR1GKVGWYSNIS5FR3DAfm vluc8d0Dfo2E/L7JYtX8yTroibVfwgVSYfCcPuwuTYxykY7IQ8GiKF71gCTc4i+H O1MA5cvwsnyNeRmgiM14+MWKWnflBqzdSt7mcG6+r771sasOCLDboD+Uxb4Subx7 J3m1MildrsUgI5IDe1Q5sIkiVG0S48N46jpA/aSTrOktiDzbpkdmTN/YF+0W3hrW 10Fmvx2A8aTgZBEpXgwnBWLr5cQEYtHEnwxqVdZYOJxmD537q1SAmZzsSdaCn9pF 1j9TBgO3/R/shn104KS06DK2qgcj+O8kQZ5jMHj0VN2O8Fo4jhJ/eMdvAlYhM864 uK1pVQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd BgNVHQ4EFgQUoYxFkwoSYwunV18ySn3hIee3PmYwHwYDVR0jBBgwFoAUoYxFkwoS YwunV18ySn3hIee3PmYwDQYJKoZIhvcNAQELBQADggIBAIeuYW1IOCrGHNxKLoR4 ScAjKkW4NU3RBfq5BTPEZL3brVQWKrA+DVoo2qYagHMMxEFvr7g0tnfUW44dC4tG kES1s+5JGInBSzSzhzV0op5FZ+1FcWa2uaElc9fCrIj70h2na9rAWubYWWQ0l2Ug MTMDT86tCZ6u6cI+GHW0MyUSuwXsULpxQOK93ohGBSGEi6MrHuswMIm/EfVcRPiR i0tZRQswDcoMT29jvgT+we3gh/7IzVa/5dyOetTWKU6A26ubP45lByL3RM2WHy3H 9Qm2mHD/ONxQFRGEO3+p8NgkVMgXjCsTSdaZf0XRD46/aXI3Uwf05q79Wz55uQbN uIF4tE2g0DW65K7/00m8Ne1jxrP846thWgW2C+T/qSq+31ROwktcaNqjMqLJTVcY UzRZPGaZ1zwCeKdMcdC/2/HEPOcB5gTyRPZIJjAzybEBGesC8cwh+joCMBedyF+A P90lrAKb4xfevcqSFNJSgVPm6vwwZzKpYvaTFxUHMV4PG2n19Km3fC2z7YREMkco BzuGaUWpxzaWkHJ02BKmcyPRTrm2ejrEKaFQBhG52fQmbmIIEiAW8AFXF9QFNmeX 61H5/zMkDAUPVr/vPRxSjoreaQ9aH/DVAzFEs5LG6nWorrvHYAOImP/HBIRSkIbh tJOpUC/o69I2rDBgp9ADE7UK -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFejCCA2KgAwIBAgIJAN7E8kTzHab8MA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJDAiBgNVBAMTG1N3aXNzU2ln biBHb2xkIFJvb3QgQ0EgLSBHMzAeFw0wOTA4MDQxMzMxNDdaFw0zNzA4MDQxMzMx NDdaMEoxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJDAiBgNV BAMTG1N3aXNzU2lnbiBHb2xkIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAMPon8hlWp1nG8FFl7S0h0NbYWCAnvJ/XvlnRN1E+qu1 q3f/KhlMzm/Ej0Gf4OLNcuDR1FJhQQkKvwpw++CDaWEpytsimlul5t0XlbBvhI46 PmRaQfsbWPz9Kz6ypOasyYK8zvaV+Jd37Sb2WK6eJ+IPg+zFNljIe8/Vh6GphxoT Z2EBbaZpnOKQ8StoZfPosHz8gj3erdgKAAlEeROc8P5udXvCvLNZAQt8xdUt8L// bVfSSYHrtLNQrFv5CxUVjGn/ozkB7fzc3CeXjnuL1Wqm1uAdX80Bkeb1Ipi6LgkY OG8TqIHS+yE35y20YueBkLDGeVm3Z3X+vo87+jbsr63ST3Q2AeVXqyMEzEpel89+ xu+MzJUjaY3LOMcZ9taKABQeND1v2gwLw7qX/BFLUmE+vzNnUxC/eBsJwke6Hq9Y 9XWBf71W8etW19lpDAfpNzGwEhwy71bZvnorfL3TPbxqM006PFAQhyfHegpnU9t/ gJvoniP6+Qg6i6GONFpIM19k05eGBxl9iJTOKnzFat+vvKmfzTqmurtU+X+P388O WsStmryzOndzg0yTPJBotXxQlRHIgl6UcdBBGPvJxmXszom2ziKzEVs/4J0+Gxho DaoDoWdZv2udvPjyZS+aQTpF2F7QNmxvOx5jtI6YTBPbIQ6fe+3qoKpxw+ujoNIl AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBRclwZGNKvfMMV8xQ1VcWYwtWCPnjAfBgNVHSMEGDAWgBRclwZGNKvfMMV8 xQ1VcWYwtWCPnjANBgkqhkiG9w0BAQsFAAOCAgEAd0tN3uqFSqssJ9ZFx/FfIMFb YO0Hy6Iz3DbPx5TxBsfV2s/NrYQ+/xJIf0HopWZXMMQd5KcaLy1Cwe9Gc7LV9Vr9 Dnpr0sgxow1IlldlY1UYwPzkisyYhlurDIonN/ojaFlcJtehwcK5Tiz/KV7mlAu+ zXJPleiP9ve4Pl7Oz54RyawDKUiKqbamNLmsQP/EtnM3scd/qVHbSypHX0AkB4gG tySz+3/3sIsz+r8jdaNc/qplGsK+8X2BdwOBsY3XlQ16PEKYt4+pfVDh31IGmqBS VHiDB2FSCTdeipynxlHRXGPRhNzC29L6Wxg2fWa81CiXL3WWHIQHrIuOUxG+JCGq Z/LBrYic07B4Z3j101gDIApdIPG152XMDiDj1d/mLxkrhWjBBCbPj+0FU6HdBw7r QSbHtKksW+NpPWbAYhvAqobAN8MxBIZwOb5rXyFAQaB/5dkPOEtwX0n4hbgrLqof k0FD+PuydDwfS1dbt9RRoZJKzr4Qou7YFCJ7uUG9jemIqdGPAxpg/z+HiaCZJyJm sD5onnKIUTidEz5FbQXlRrVz7UOGsRQKHrzaDb8eJFxmjw6+of3G62m8Q3nXA3b5 3IeZuJjEzX9tEPkQvixC/pwpTYNrCr21jsRIiv0hB6aAfR+b6au9gmFECnEnX22b kJ6u/zYks2gD1pWMa3M= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgTCCA2mgAwIBAgIIIj+pFyDegZQwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEoMCYGA1UEAxMfU3dpc3NTaWdu IFBsYXRpbnVtIFJvb3QgQ0EgLSBHMzAeFw0wOTA4MDQxMzM0MDRaFw0zNzA4MDQx MzM0MDRaME4xCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxKDAm BgNVBAMTH1N3aXNzU2lnbiBQbGF0aW51bSBSb290IENBIC0gRzMwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCUoO8TG59EIBvNxaoiu9nyUj56Wlh35o2h K8ncpPPksxOUAGKbHPJDUEOBfq8wNkmsGIkMGEW4PsdUbePYmllriholqba1Dbd9 I/BffagHqfc+hi7IAU3c5jbtHeU3B2kSS+OD0QQcJPAfcHHnGe1zSG6VKxW2VuYC 31bpm/rqpu7gwsO64MzGyHvXbzqVmzqPvlss0qmgOD7WiOGxYhOO3KswZ82oaqZj K4Kwy8c9Tu1y9n2rMk5lAusPmXT4HBoojA5FAJMsFJ9txxue9orce3jjtJRHHU0F bYR6kFSynot1woDfhzk/n/tIVAeNoCn1+WBfWnLou5ugQuAIADSjFTwT49YaawKy lCGjnUG8KmtOMzumlDj8PccrM7MuKwZ0rJsQb8VORfddoVYDLA1fer0e3h13kGva pS2KTOnfQfTnS+x9lUKfTKkJD0OIPz2T5yv0ekjaaMTdEoAxGl0kVCamJCGzTK3a Fwg2AlfGnIZwyXXJnnxh2HjmuegUafkcECgSXUt1ULo80GdwVVVWS/s9HNjbeU2X 37ie2xcs1TUHuFCp9473Vv96Z0NPINnKZtY4YEvulDHWDaJIm/80aZTGNfWWiO+q ZsyBputMU/8ydKe2nZhXtLomqfEzM2J+OrADEVf/3G8RI60+xgrQzFS3LcKTHeXC pozH2O9T9wIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUVio/kFj0F1oUstcIG4VbVGpUGigwHwYDVR0jBBgwFoAUVio/ kFj0F1oUstcIG4VbVGpUGigwDQYJKoZIhvcNAQELBQADggIBAGztiudDqHknm7jP hz5kOBiMEUKShjfgWMMb7gQu94TsgxBoDH94LZzCl442ThbYDuprSK1Pnl0NzA2p PhiFfsxomTk11tifhsEy+01lsyIUS8iFZtoX/3GRrJxWV95xLFZCv/jNDvCi0//S IhX70HgKfuGwWs6ON9upnueVz2PyLA3S+m/zyNX7ALf3NWcQ03tS7BAy+L/dXsmm gqTxsL8dLt0l5L1N8DWpkQFH+BAClFvrPusNutUdYyylLqvn4x6j7kuqX7FmAbSC WvlGS8fx+N8svv113ZY4mjc6bqXmMhVus5DAOYp0pZWgvg0uiXnNKVaOw15XUcQF bwRVj4HpTL1ZRssqvE3JHfLGTwXkyAQN925P2sM6nNLC9enGJHoUPhxCMKgCRTGp /FCp3NyGOA9bkz9/CE5qDSc6EHlWwxW4PgaG9tlwZ691eoviWMzGdU8yVcVsFAko O/KV5GreLCgHraB9Byjd1Fqj6aZ8E4yZC1J429nR3z5aQ3Z/RmBTws3ndkd8Vc20 OWQQW5VLNV1EgyTV4C4kDMGAbmkAgAZ3CmaCEAxRbzeJV9vzTOW4ue4jZpdgt1Ld 2Zb7uoo7oE3OXvBETJDMIU8bOphrjjGD+YMIUssZwTVr7qEVW4g/bazyNJJTpjAq E9fmhqhd2ULSx52peovL3+6iMcLl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBV MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNV BAMTIUNlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgw MTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFX b1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvcqN rLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1U fcIiePyOCbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcScc f+Hb0v1naMQFXQoOXXDX2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2 ZjC1vt7tj/id07sBMOby8w7gLJKA84X5KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4M x1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR+ScPewavVIMYe+HdVHpR aG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ezEC8wQjch zDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDar uHqklWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221K mYo0SLwX3OSACCK28jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvA Sh0JWzko/amrzgD5LkhLJuYwTKVYyrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWv HYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0CAwEAAaNCMEAwDgYDVR0PAQH/ BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R8bNLtwYgFP6H EtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1 LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJ MuYhOZO9sxXqT2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2e JXLOC62qx1ViC777Y7NhRCOjy+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VN g64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC2nz4SNAzqfkHx5Xh9T71XXG68pWp dIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes5cVAWubXbHssw1ab R80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/EaEQ PkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGce xGATVdVhmVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+ J7x6v+Db9NpSvd4MVHAxkUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMl OtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGikpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWT ee5Ehr7XHuQe+w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBG MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNV BAMMEkNBIOayg+mAmuagueivgeS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgw MTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRl ZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k8H/r D195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld1 9AXbbQs5uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExf v5RxadmWPgxDT74wwJ85dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnk UkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+L NVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFyb7Ao65vh4YOhn0pdr8yb +gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc76DbT52V qyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6K yX2m+Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0G AbQOXDBGVWCvOGU6yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaK J/kR8slC/k7e3x9cxKSGhxYzoacXGKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwEC AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUAA4ICAQBqinA4 WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6 yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj /feTZU7n85iYr83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6 jBAyvd0zaziGfjk9DgNyp115j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2 ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0AkLppRQjbbpCBhqcqBT/mhDn4t/lX X0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97qA4bLJyuQHCH2u2n FoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Yjj4D u9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10l O1Hm13ZBONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Le ie2uPAmvylezkolwQOQvT8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR1 2KvxAmLBsX5VYc8T1yaw15zLKYs4SgsOkI26oQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk 6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn 0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN sSi6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH /PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu 9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo 2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI 4uJEvlz36hz1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg 8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF 5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI 4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp /hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y Johw1+qRzT65ysCQblrGXnRl11z+o+I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp 3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1 OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/ Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM 0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9 Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K 2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl 6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK 9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR 6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC 9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV /erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z +pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB /wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM 4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV 2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl 0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB NVOFBkpdn627G190 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp 6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ +jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S 5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B 8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc 0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e KeC2uAloGRwYQw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D 0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B 3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT 79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs 8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG jjxDah2nGN59PRbxYvnKkKj9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHDCCBASgAwIBAgIES45gAzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJE SzESMBAGA1UEChMJVFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQ cmltYXJ5IENBMB4XDTEwMDMwMzEyNDEzNFoXDTM3MTIwMzEzMTEzNFowRTELMAkG A1UEBhMCREsxEjAQBgNVBAoTCVRSVVNUMjQwODEiMCAGA1UEAxMZVFJVU1QyNDA4 IE9DRVMgUHJpbWFyeSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AJlJodr3U1Fa+v8HnyACHV81/wLevLS0KUk58VIABl6Wfs3LLNoj5soVAZv4LBi5 gs7E8CZ9w0F2CopW8vzM8i5HLKE4eedPdnaFqHiBZ0q5aaaQArW+qKJx1rT/AaXt alMB63/yvJcYlXS2lpexk5H/zDBUXeEQyvfmK+slAySWT6wKxIPDwVapauFY9QaG +VBhCa5jBstWS7A5gQfEvYqn6csZ3jW472kW6OFNz6ftBcTwufomGJBMkonf4ZLr 6t0AdRi9jflBPz3MNNRGxyjIuAmFqGocYFA/OODBRjvSHB2DygqQ8k+9tlpvzMRr kU7jq3RKL+83G1dJ3/LTjCLz4ryEMIC/OJ/gNZfE0qXddpPtzflIPtUFVffXdbFV 1t6XZFhJ+wBHQCpJobq/BjqLWUA86upsDbfwnePtmIPRCemeXkY0qabC+2Qmd2Fe xyZphwTyMnbqy6FG1tB65dYf3mOqStmLa3RcHn9+2dwNfUkh0tjO2FXD7drWcU0O I9DW8oAypiPhm/QCjMU6j6t+0pzqJ/S0tdAo+BeiXK5hwk6aR+sRb608QfBbRAs3 U/q8jSPByenggac2BtTN6cl+AA1Mfcgl8iXWNFVGegzd/VS9vINClJCe3FNVoUnR YCKkj+x0fqxvBLopOkJkmuZw/yhgMxljUi2qYYGn90OzAgMBAAGjggESMIIBDjAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHSAECjAIMAYGBFUd IAAwgZcGA1UdHwSBjzCBjDAsoCqgKIYmaHR0cDovL2NybC5vY2VzLnRydXN0MjQw OC5jb20vb2Nlcy5jcmwwXKBaoFikVjBUMQswCQYDVQQGEwJESzESMBAGA1UEChMJ VFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQcmltYXJ5IENBMQ0w CwYDVQQDEwRDUkwxMB8GA1UdIwQYMBaAFPZt+LFIs0FDAduGROUYBbdezAY3MB0G A1UdDgQWBBT2bfixSLNBQwHbhkTlGAW3XswGNzANBgkqhkiG9w0BAQsFAAOCAgEA VPAQGrT7dIjD3/sIbQW86f9CBPu0c7JKN6oUoRUtKqgJ2KCdcB5ANhCoyznHpu3m /dUfVUI5hc31CaPgZyY37hch1q4/c9INcELGZVE/FWfehkH+acpdNr7j8UoRZlkN 15b/0UUBfGeiiJG/ugo4llfoPrp8bUmXEGggK3wyqIPcJatPtHwlb6ympfC2b/Ld v/0IdIOzIOm+A89Q0utx+1cOBq72OHy8gpGb6MfncVFMoL2fjP652Ypgtr8qN9Ka /XOazktiIf+2Pzp7hLi92hRc9QMYexrV/nnFSQoWdU8TqULFUoZ3zTEC3F/g2yj+ FhbrgXHGo5/A4O74X+lpbY2XV47aSuw+DzcPt/EhMj2of7SA55WSgbjPMbmNX0rb oenSIte2HRFW5Tr2W+qqkc/StixgkKdyzGLoFx/xeTWdJkZKwyjqge2wJqws2upY EiThhC497+/mTiSuXd69eVUwKyqYp9SD2rTtNmF6TCghRM/dNsJOl+osxDVGcwvt WIVFF/Onlu5fu1NHXdqNEfzldKDUvCfii3L2iATTZyHwU9CALE+2eIA+PIaLgnM1 1oCfUnYBkQurTrihvzz9PryCVkLxiqRmBVvUz+D4N5G/wvvKDS6t6cPCS+hqM482 cbBsn0R9fFLO4El62S9eH1tqOzO20OAOK65yJIsOpSE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrTCCApWgAwIBAgIQPr1DlqNlQqhJtpGoElEmzzANBgkqhkiG9w0BAQUFADBm MQswCQYDVQQGEwJTRTEoMCYGA1UEChMfU3dlZGlzaCBTb2NpYWwgSW5zdXJhbmNl IEFnZW5jeTEtMCsGA1UEAxMkU3dlZGlzaCBHb3Zlcm5tZW50IFJvb3QgQXV0aG9y aXR5IHYxMB4XDTEwMDQxNDEzMzMyM1oXDTMwMDQxNDEzNDMxOVowZjELMAkGA1UE BhMCU0UxKDAmBgNVBAoTH1N3ZWRpc2ggU29jaWFsIEluc3VyYW5jZSBBZ2VuY3kx LTArBgNVBAMTJFN3ZWRpc2ggR292ZXJubWVudCBSb290IEF1dGhvcml0eSB2MTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMocT3QV99VeycBYhDLn3PxR kZDOESLhJXCDQnD7cNwbC2/CLdCK211WKaq3XoW1d+fBWiBiyJdCYcJDcNtYbHXg C7YyiuCkLUW+51s7i3qx/QXMM3+f8Fvtco7NM9PJEovAk0Cjj4Zu342I8+ZqTG+l RvpoplsQloMuV6BPjxVZNqVuaIRFHhCHtuJV1bi/q7euZb9XR4zE4+QCjfPcM9vv J0f47MvyPOcJ8/nl+YvH6VrgLZOrqik2L37GyPbw5oBFMRY0avDoSTlEYQDzm+a+ CmUbMiN5YnesIn8bpF16sOes2OB2Ay9972v3N++jomQczNd92oKizrUBTfgJLDUC AwEAAaNXMFUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYD VR0OBBYEFF0HuveNXUnwXJWQCfNe6qzQ9kO2MBAGCSsGAQQBgjcVAQQDAgEAMA0G CSqGSIb3DQEBBQUAA4IBAQAw36Sc6JRzKWuuHwxwukz+ZH2sT69JD3KLpLIASGlO 1fKEMwuNc9vOaQ63Yr+xkeRq4RJJfEZHm4TYmCksB4Mk8B7rcZ2RaHr3W0OtggQP Q98mvYJdtpG8Yr5DWqNUb35RMS35N5y2H6j75xGbFgvuYRJU1aWE2f+fkiedU/e2 CzMXxuuy6oLy9kN2HLwxkzCd6UhiDj5DO6wpzJTgK2yavxfe8crw5h2F0g+rvYed gk2GMDW0CdNAqLu3Iv54qNvRUGmAM2AtfY+EueyH0pjpC8zbeRhxE1ig+WvWzuRG TAB3ii9cna6JBevqHOCaY/m7RqO5Sr2dGn3KhM3+kPG6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHBDCCBOygAwIBAgIQDziMcP6mlV3pXZyHr3kEmTANBgkqhkiG9w0BAQsFADB1 MQswCQYDVQQGEwJFUzFBMD8GA1UEChM4QWdlbmNpYSBOb3RhcmlhbCBkZSBDZXJ0 aWZpY2FjaW9uIFMuTC5VLiAtIENJRiBCODMzOTU5ODgxIzAhBgNVBAMTGkFOQ0VS VCBDZXJ0aWZpY2Fkb3MgQ0dOIFYyMB4XDTEwMDUyNTE2MzEyMloXDTMwMDUyNTE2 MzEyM1owdTELMAkGA1UEBhMCRVMxQTA/BgNVBAoTOEFnZW5jaWEgTm90YXJpYWwg ZGUgQ2VydGlmaWNhY2lvbiBTLkwuVS4gLSBDSUYgQjgzMzk1OTg4MSMwIQYDVQQD ExpBTkNFUlQgQ2VydGlmaWNhZG9zIENHTiBWMjCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAJ1ScOknGIPK6sSZ2KbhLhSvbh4OZMqBN1UnHBd3WGcfjMn5 wopiZSh0m+LRvlUHdnbufG1OY1seSiV14Aeh0NKCp84PM+u6FMBlskou5WW8ItKv Gg7Ky/NkZSssmaOXi4t1MP5m+sFPSzdQjD/z3pl6ToecIEZyl/5WG2ZOoIJTo1zY KEYMBRdvONZcnw4lIsGG41waVNuunWV9AJLfqCEhxVsQJnThsXNXZHx9FwMM6vcU lw/5xe5ddbDFxgoLtD5J4xnGm0ST/FoVZAqyg/+AXogJ0Mogo1v7283hGncjGHAa i+1EP9YaqDY44Z0vp3fEerPAcrJyzR4/EF4aiHSN8BLF969J3JWvK020kMr57u8M 478WNyNT4yn69HRpaD1XbRRgimRpKGRN+jZH/bgSzsOGqlzcZjkHTzvj48Vors7g OVwggz8SCjizAMFcE5ciXjpLNZn4xB7e+YgRjoTJizLy0te/Igc/YHgudRyiuiMS 0/BPUDnsyXcnx1oqjtO5tXQEmRUvLoZfjwbByuriqB9NfTOEkaSSw9CmSF1mGneE IFCc6gQLDCOWz7Gc/Lm6H5eo06sDZS99rlTHeeIcNt1t0gaYAf3O/D9Lw9Ku/4nY OTED2LFkdwPG+KON/Cp55xC9uW2RHD6dy7xVfyL+YYT42NSnIXo5XnIy60x1AgMB AAGjggGOMIIBijAPBgNVHRMBAf8EBTADAQH/MIIBJQYDVR0gBIIBHDCCARgwggEU BgkrBgEEAYGTaAQwggEFMCUGCCsGAQUFBwIBFhlodHRwOi8vd3d3LmFuY2VydC5j b20vY3BzMIHbBggrBgEFBQcCAjCBzjANFgZBTkNFUlQwAwIBAR6BvABBAGcAZQBu AGMAaQBhACAATgBvAHQAYQByAGkAYQBsACAAZABlACAAQwBlAHIAdABpAGYAaQBj AGEAYwBpAG8AbgAuACAAUABhAHMAZQBvACAAZABlAGwAoABHAGUAbgBlAHIAYQBs ACAATQBhAHIAdABpAG4AZQB6ACAAQwBhAG0AcABvAHMAIAA0ADYAIAA2AGEAIABw AGwAYQBuAHQAYQAgADIAOAAwADEAMAAgAE0AYQBkAHIAaQBkMA4GA1UdDwEB/wQE AwIBhjAdBgNVHQ4EFgQUBW7hoZruB6/O9bTTZT0EUOLQm0QwHwYDVR0jBBgwFoAU BW7hoZruB6/O9bTTZT0EUOLQm0QwDQYJKoZIhvcNAQELBQADggIBAH9UQBkkykwT 9hP5XGKVMNW44JOAbNQVRtQnPpJSqtyBY4ZA29Ulr5+TbAr1TaH+VJZdh68Rkw+L 8uPwH0qf/KnRyVB3X5gICC16i4EQzDsCVFjlxqf098ro9jcGfucR12yFY/eoow7i JWIEpPJiU5xHtKdku4Hl1l5WEb5FEWHCZun0DXSoq/lbv4KykaZQ+4d+b7vI6wWi uRDXG0IHVc+J5r/7ufBqOVdTcIy9S6Npvx+LplxNZYq5AAnoaL8JJwdNXtpSCYzl cZOKzIWO0jdeU9yCbQtWSoR5CvQQJUT1b10aZrXN1RBLh1pO1H/kcazuaJ+8+i5Y wcSef6RZheBSDvLHR3UVLSx2jA9FBTVg+Hs7dzJ/KIAJ2jG8cX3hrJHNYAp5IOxu O7eE4HLzqUrQL+Rb49Ia1Eq89Xb5fyoZSOvdDs+ZVkW4fdYJjg7Os4RoSYRUNUvk mRuv86gU81SYCoB+T7zyZi0m/zCNp/a925qP5eHfu7cyDvmSb2nj5HbTADbxLV7H E1/V2Wot6NEba3bLGG4OBRD1WvJJG1m0herKGXTMu1LiN4zCagIlwtJxpJLbjsnW qW7QhShtXG0IeAKweQxXbwtaAeOEhAL2z/KrY+sCarnLShjVOSI8VkqqlYjmMAAf jSEhyVfuubdEKYhPtiunFO6O7m++FtAT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHEjCCBPqgAwIBAgIQCb1WBSoTFvRoT3QOqX0cSDANBgkqhkiG9w0BAQsFADB8 MQswCQYDVQQGEwJFUzFBMD8GA1UEChM4QWdlbmNpYSBOb3RhcmlhbCBkZSBDZXJ0 aWZpY2FjaW9uIFMuTC5VLiAtIENJRiBCODMzOTU5ODgxKjAoBgNVBAMTIUFOQ0VS VCBDZXJ0aWZpY2Fkb3MgTm90YXJpYWxlcyBWMjAeFw0xMDA1MjUxNjU2MTRaFw0z MDA1MjUxNjU2MTRaMHwxCzAJBgNVBAYTAkVTMUEwPwYDVQQKEzhBZ2VuY2lhIE5v dGFyaWFsIGRlIENlcnRpZmljYWNpb24gUy5MLlUuIC0gQ0lGIEI4MzM5NTk4ODEq MCgGA1UEAxMhQU5DRVJUIENlcnRpZmljYWRvcyBOb3RhcmlhbGVzIFYyMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsua5xh1qKi1Jxfz81GRA0OAULveg wv+S80GmtD/avhkUkZR20xXMXn94UHrb2sVFqsscI3lzkKi7ZwFzjs5A+Rqpqofk k5IPXGhcXvAGYCtY3DxtPMd6MGsFqpKGcyrS8hqIxNvlWmaOdclCP5uIKEAe9alc HvrIQaEwqwuc7haiwS2lhfrtoAzof5ZKe72PmqIYdtKv3bc9EKtSEIiuHeu4MnSW 9LeqJ/elBw3jlFdqVCB3zR28eS3knLTeUYj+VtY9i6HP+lIejAVzd9YFz2MAUYdh 41C+mZfh/B4ReWtOas+chQoclirAIDYUxQkXYjv0rerV1/3QOSp409Ciz8hzMAlH xU4Z/bgw1A+AmIiGwUxBeiPFQ/1eErg+D7G3gWIMfm/je5rCwkcRIR/PntEwzoPB EE1Ad9e1wksyQEL6m7Csz+sh2BnrZMVr3VUtgIdEfEw8qw3YEr80goyxqsS4a+gO RnfSiwYdQvusvcnnM7Mib37VLgPFXwUWhnzt457RFncaRtjJ0IzkXFwhBZHxZOSs xTeutb1nE64p5bNCxHAJo11M6zcg4/D1czM7wvyOUYU2KsuB2w6JI9ni4Wi6LER3 PhxAuvBnjhiH8D3X6T9HWzVCzacEzkhyKQUatNGi5w15ipZtZ1ItOyPm+YKc1rN5 XhTeZUgz/B1C6C0CAwEAAaOCAY4wggGKMA8GA1UdEwEB/wQFMAMBAf8wggElBgNV HSAEggEcMIIBGDCCARQGCSsGAQQBgZNoATCCAQUwJQYIKwYBBQUHAgEWGWh0dHA6 Ly93d3cuYW5jZXJ0LmNvbS9jcHMwgdsGCCsGAQUFBwICMIHOMA0WBkFOQ0VSVDAD AgEBHoG8AEEAZwBlAG4AYwBpAGEAIABOAG8AdABhAHIAaQBhAGwAIABkAGUAIABD AGUAcgB0AGkAZgBpAGMAYQBjAGkAbwBuAC4AIABQAGEAcwBlAG8AIABkAGUAbACg AEcAZQBuAGUAcgBhAGwAIABNAGEAcgB0AGkAbgBlAHoAIABDAGEAbQBwAG8AcwAg ADQANgAgADYAYQAgAHAAbABhAG4AdABhACAAMgA4ADAAMQAwACAATQBhAGQAcgBp AGQwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBT2Ejqre1jBjUNvdoHS8rjT7xfq CzAfBgNVHSMEGDAWgBT2Ejqre1jBjUNvdoHS8rjT7xfqCzANBgkqhkiG9w0BAQsF AAOCAgEAVDXTomXJ2TbFU9G0jXI0ibqnCJ/pNRC5uAwG+WSqlZYoqMijgNxWwL9y TVa/f10E1a0oW02988MPFbBx2laNQFVXpn1ioq0TaVGqlFC6vQAwUPXdpE4JepQx a9tzA73z2hoPjC+yyTe8VNULIzf15Fs3ZolPtMcFpGXcWTCmEyt+Fe3sEBeJUsmd 36JM7fYPHqZJsA1RszGxUZnLtNEjeNJLqLQdFqag0D4HfmU/Jc5kThsuS02ChRpl 2+7iA/BZJAWPme95gt/uKjdow2pQAVlfn2jcLFFgK13gUjw7cLgA0zeoPlsedgha 1Lt2MK75yPKOpI8KdX0amOG/0DaULzzBUtNp6hpgN4yA201txppdjaBhUbs9DeYS oJ9vWVZ0MmcK/DcGwTrkK46EH9ohDEmIQ9Ol9YINdobDLMyQu7O4q8bLrsAXUZ7T gPck2hzszhKDzk42MDl1+HR2kIKePkBMDBS5Gh5IarAx6oh/gEFAU3s4S4eQYHpL zmdGaHV3jgBdILDkkzdtA99YOeiaxaTr7GEzCIUka08G6a2QpTZibOPdfQkfM7+3 u/fJdQX3W6v6h1mvGmcQfoTcjHDWROkQwdibLtHGQGrq5loPEH1s+1WHuk21cQOe F4942lU9V14iCmqY8I0Izd2WQlobzbpvJ7h0J6g/5aDWc8deLyE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF7TCCA9WgAwIBAgIQKMw6Jb+6RKxEmptYa0M5qjANBgkqhkiG9w0BAQsFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMp TWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAw NjIzMjE1NzI0WhcNMzUwNjIzMjIwNDAxWjCBiDELMAkGA1UEBhMCVVMxEzARBgNV BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm aWNhdGUgQXV0aG9yaXR5IDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQC5CJ4o5OTsBk5QaLNBxXvrrraOr4G6IkQfZTRpTL5wQBfyFnvief2G7Q05 9BuorZKQHss9do9a2bWREC48BY2KbSRU5x/tVq2DtFCcFaUXdIhZIPwIxYR202jU byh4zly481CQRP/jY1++oZoslhUE1gf+HoQh4EIxEcQoNpTPUKRinsnWq3EAslsM 5pbUCiSW9f/G1bcb18u3IWKvEtyhXTfjGvsaRpjAm8DnYx8qCJMCfh5qjvKfGInk IoWisYRXQP/1DthvnO3iRTEBzRfpf7CBReOqIUAmoXKqp088AQV+7oNYsV4GY5li kXiCtw2TDCRqtBvbJ+xflQQ/k0ow9ZcYs6f5GaeTMx0ByNsiUlzXJclG+aL7h1lD vptisY0thkQaRqx4YX4wCfquicRBKiJmA5E5RZzHiwyoyg0v+1LqDPdjMyOd/rAf rWfWp1ADxgRwY7UssYZaQ7f7rvluKW4hIUEmBozJw+6wwoWTobmF2eYybEtMP9Zd o+W1nXfDnMBVt3QA47g4q4OXUOGaQiQdxsCjMNEaWshSNPdz8ccYHzOteuzLQWDz I5QgwkhFrFxRxi6AwuJ3Fb2Fh+02nZaR7gC1o3Dsn+ONgGiDdrqvXXBSIhbiZvu6 s8XC9z4vd6bK3sGmxkhMwzdRI9Mn17hOcJbwoUR2r3jPmuFmEwIDAQABo1EwTzAL BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU1fZWy4/oolxi aNE9lJBb186aGMQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQELBQADggIB AKylloy/u66m9tdxh0MxVoj9HDJxWzW31PCR8q834hTx8wImBT4WFH8UurhP+4my sufUCcxtuVs7ZGVwZrfysVrfGgLz9VG4Z215879We+SEuSsem0CcJjT5RxiYadgc 17bRv49hwmfEte9gQ44QGzZJ5CDKrafBsSdlCfjN9Vsq0IQz8+8f8vWcC1iTN6B1 oN5y3mx1KmYi9YwGMFafQLkwqkB3FYLXi+zA07K9g8V3DB6urxlToE15cZ8PrzDO Z/nWLMwiQXoH8pdCGM5ZeRBV3m8Q5Ljag2ZAFgloI1uXLiaaArtXjMW4umliMoCJ nqH9wJJ8eyszGYQqY8UAaGL6n0eNmXpFOqfp7e5pQrXzgZtHVhB7/HA2hBhz6u/5 l02eMyPdJgu6Krc/RNyDJ/+9YVkrEbfKT9vFiwwcMa4y+Pi5Qvd/3GGadrFaBOER PWZFtxhxvskkhdbz1LpBNF0SLSW5jaYTSG1LsAd9mZMJYYF0VyaKq2nj5NnHiMwk 2OxSJFwevJEU4pbe6wrant1fs1vb1ILsxiBQhyVAOvvH7s3+M+Vuw4QJVQMlOcDp NV1lMaj2v6AJzSnHszYyLtyV84PBWs+LjfbqsyH4pO0eMQ62TBGrYAukEiMiF6M2 ZIKRBBLgq28ey1AFYbRA/1mGcdHVM2l8qXOKONdkDPFp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC Q04xMjAwBgNVBAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24g Q2VudGVyMUcwRQYDVQQDDD5DaGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0 aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMgUm9vdDAeFw0xMDA4MzEwNzExMjVa Fw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAGA1UECgwpQ2hpbmEg SW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMMPkNo aW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRp ZmljYXRlcyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z 7r07eKpkQ0H1UN+U8i6yjUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA// DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV98YPjUesWgbdYavi7NifFy2cyjw1l1Vx zUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2HklY0bBoQCxfVWhyXWIQ8 hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23KzhmBsUs 4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54u gQEC7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oY NJKiyoOCWTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E FgQUfHJLOcfA22KlT5uqGDSSosqDglkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3 j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd50XPFtQO3WKwMVC/GVhMPMdoG 52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM7+czV0I664zB echNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrI zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy wy39FCqQmbkHzJ8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGGTCCBAGgAwIBAgIIPtVRGeZNzn4wDQYJKoZIhvcNAQELBQAwajEhMB8GA1UE AxMYU0cgVFJVU1QgU0VSVklDRVMgUkFDSU5FMRwwGgYDVQQLExMwMDAyIDQzNTI1 Mjg5NTAwMDIyMRowGAYDVQQKExFTRyBUUlVTVCBTRVJWSUNFUzELMAkGA1UEBhMC RlIwHhcNMTAwOTA2MTI1MzQyWhcNMzAwOTA1MTI1MzQyWjBqMSEwHwYDVQQDExhT RyBUUlVTVCBTRVJWSUNFUyBSQUNJTkUxHDAaBgNVBAsTEzAwMDIgNDM1MjUyODk1 MDAwMjIxGjAYBgNVBAoTEVNHIFRSVVNUIFNFUlZJQ0VTMQswCQYDVQQGEwJGUjCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANqoVgLsfJXwTukK0rcHoyKL ULO5Lhk9V9sZqtIr5M5C4myh5F0lHjMdtkXRtPpZilZwyW0IdmlwmubHnAgwE/7m 0ZJoYT5MEfJu8rF7V1ZLCb3cD9lxDOiaN94iEByZXtaxFwfTpDktwhpz/cpLKQfC eSnIyCauLMT8I8hL4oZWDyj9tocbaF85ZEX9aINsdSQePHWZYfrSFPipS7HYfad4 0hNiZbXWvn5qA7y1svxkMMPQwpk9maTTzdGxxFOHe0wTE2Z/v9VlU2j5XB7ltP82 mUWjn2LAfxGCAVTeD2WlOa6dSEyJoxA74OaD9bDaLB56HFwfAKzMq6dgZLPGxXvH VUZ0PJCBDkqOWZ1UsEixUkw7mO6r2jS3U81J2i/rlb4MVxH2lkwEeVyZ1eXkvm/q R+5RS+8iJq612BGqQ7t4vwt+tN3PdB0lqYljseI0gcSINTjiAg0PE8nVKoIV8IrE QzJW5FMdHay2z32bll0eZOl0c8RW5BZKUm2SOdPhTQ4/YrnerbUdZbldUv5dCamc tKQM2S9FdqXPjmqanqqwEaHrYcbrPx78ZrQSnUZ/MhaJvnFFr5Eh2f2Tv7QCkUL/ SR/tixVo3R+OrJvdggWcRGkWZBdWX0EPSk8ED2VQhpOX7EW/XcIc3M/E2DrmeAXQ xVVVqV7+qzohu+VyFPcLAgMBAAGjgcIwgb8wHQYDVR0OBBYEFCkgy/HDD9oGjhOT h/5fYBopu/O2MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUKSDL8cMP2gaO E5OH/l9gGim787YwEQYDVR0gBAowCDAGBgRVHSAAMEkGA1UdHwRCMEAwPqA8oDqG OGh0dHA6Ly9jcmwuc2d0cnVzdHNlcnZpY2VzLmNvbS9yYWNpbmUtR3JvdXBlU0cv TGF0ZXN0Q1JMMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEATEZn 4ERQ9cW2urJRCiUTHbfHiC4fuStkoMuTiFJZqmD1zClSF/8E5ze0MRFGfisebKeL PEeaXvSqXZA7RT2fSsmKe47A7j55i5KjyJRKuCgRa6YlX129x8j7g09VMeZc8BN8 471/Kiw3N5RJr4QfFCeiWBCPCjk3GhIgQY8Z9qkfGe2yNLKtfTNEi18KB0PydkVF La3kjQ4A/QQIqudr+xe9sAhWDjUqcvCz5006Tw3c82ASszhkjNv54SaNL+9O6CRH PjY0imkPKGuLh8a9hSb50+tpIVZgkdb34GLCqHGuLt5mI7VSRqakSDcsfwEWVxH3 Jw0O5Q/WkEXhHj8h3NL8FhgTPk1qsiZqQF4leP049KxYejcbmEAEx47J1MRnYbGY rvDNDty5r2WDewoEij9hqvddQYbmxkzCTzpcVuooO6dEz8hKZPVyYC3jQ7hK4HU8 MuSqFtcRucFF2ZtmY2blIrc07rrVdC8lZPOBVMt33lfUk+OsBzE6PlwDg1dTx/D+ aNglUE0SyObhlY1nqzyTPxcCujjXnvcwpT09RAEzGpqfjtCf8e4wiHPvriQZupdz FcHscQyEZLV77LxpPqRtCRY2yko5isune8YdfucziMm+MG2chZUh6Uc7Bn6B4upG 5nBYgOao8p0LadEziVkw82TTC/bOKwn7fRB2LhA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGOTCCBCGgAwIBAgIBAzANBgkqhkiG9w0BAQUFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEWMBQGA1UEBxMNU29tZXJzZXQgV2VzdDEq MCgGA1UEChMhU291dGggQWZyaWNhbiBQb3N0IE9mZmljZSBMaW1pdGVkMRowGAYD VQQLExFTQVBPIFRydXN0IENlbnRyZTEdMBsGA1UEAxMUU0FQTyBDbGFzcyA0IFJv b3QgQ0ExKTAnBgkqhkiG9w0BCQEWGnBraWFkbWluQHRydXN0Y2VudHJlLmNvLnph MB4XDTEwMDkxNTAwMDAwMFoXDTMwMDkxNDAwMDAwMFowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxFjAUBgNVBAcTDVNvbWVyc2V0IFdlc3Qx KjAoBgNVBAoTIVNvdXRoIEFmcmljYW4gUG9zdCBPZmZpY2UgTGltaXRlZDEaMBgG A1UECxMRU0FQTyBUcnVzdCBDZW50cmUxHTAbBgNVBAMTFFNBUE8gQ2xhc3MgNCBS b290IENBMSkwJwYJKoZIhvcNAQkBFhpwa2lhZG1pbkB0cnVzdGNlbnRyZS5jby56 YTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvc7UiaoKOf4BGO2ciS dTpVwVEiygt6pDUNxeZXLYPwKm8iODcxbXyFJKIGL0OCPUUwQCUc7lhHQebwngAe +PQvEbuSsphFLdMfgMl2FBPDzEDmres5YPzPyN8q/YwSUe/PDGTGV+gjUV3nZlLq Zr2Tf516KPEZcG6EnzBHt7A5axMs60tNLq8/v/0CE0o55z4zxRCRUb4PR51NUvws 8+MTogCC4RQMzdKes/Lggdq+mZJT432Zd0Ph4UgpgZ7WBVc6cdw+mK1YcG9Gu34y A+KDm1lX9/izzVQW7LatoRwaktHUKZ6PzbPofVDxwoKsur20dVag9UVdGH0sjPF7 QcyGsZqESwoqXZuW4c36qxYnQeeVNabLiqeW86XMUfktfR5D+9xttbk4vQX7WPou 0+xeZC2vWAFKfCJG00HLPeSWXklDOLuJ6/ScaTkSA1yEu+WMHurgZrvAv4z+ngpN PWg/QHbWMqnqRbhqB1KOzVHxXShjDNNZOPzJ/YLJRSC85ujMogzLe2Q5SUZF9XMc apcg6yFC97QgUrdK/XW8yw8MZxFXH/cw8auQzF08lgVi08pVAUtGxYCHHHLQc1Qh 6tejnNOuf9RT2Sj8V97lP1JKu8gmJEdTHHO6z8a0MM1eccdWvEk4JebFEAl42dQd XM1u7duRXKFTFFaqjSeppo4bAgMBAAGjIDAeMA4GA1UdDwEB/wQEAwIBBjAMBgNV HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQDRC4XUXqaW8JCJEtkBUwjs8u1D OIk+wSlk7lP/T/6LCg6S9P19KIDOAQn8MdFrWwOJsi5gA+XvY5aRKV/gP5j4aJhV Y8pPa1NyurNiGhmewRMdmYL6q6ozgLn3Gvx5TALQ4YOLLHgsL1wwYTJPu9E+lV9g dlXRDm95Tg/6uHWxH/4Ni1uLKELKTUVjUgJJzJ0PX7s5P2GbsVx0Q5pWw5l/n8RN wNOP18tUl/X7SH4ngv66Y+3ob+OE62k+CPLKJKo0jmJAhw3HUdQBddxmev/pujJv T49yNWwJ7Vt4sKlI+nyRQbKsjjE3JZUMRaVVShlRjFWTCRXJ9EABnLV1fKoB/rJp TRiaAut0APt7aPTww3+mnfTs6EK664N5l/yjdhlbcX8mZ+lPKnuzy37z/PWnv/s/ l3V10MvreOMDa46C0BFh+zc9p5gLHv47XtnPAKUX6ez9DLXduMa8vfPSMO6FDoX5 UjNIhufGr7+/DNBLcED1XshVP1AcTwfZZ3YUfWYNwrXKooI0A4b40lq2EpYmeXoX bZipzPngyxpF//PADMVi/hPGLb9qF+pjDX4+JH5iOU4nORtBS8OxYHFR+gmCrA+N 19fv3h2rK1G9+ADz1IHHDZgcPewvowbI9VUApz/9l6uwtUqZWQiIkGwcsP/o7XyZ Py1q7W19ZhLu2OAx7A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGOTCCBCGgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEWMBQGA1UEBxMNU29tZXJzZXQgV2VzdDEq MCgGA1UEChMhU291dGggQWZyaWNhbiBQb3N0IE9mZmljZSBMaW1pdGVkMRowGAYD VQQLExFTQVBPIFRydXN0IENlbnRyZTEdMBsGA1UEAxMUU0FQTyBDbGFzcyAzIFJv b3QgQ0ExKTAnBgkqhkiG9w0BCQEWGnBraWFkbWluQHRydXN0Y2VudHJlLmNvLnph MB4XDTEwMDkxNTAwMDAwMFoXDTMwMDkxNDAwMDAwMFowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxFjAUBgNVBAcTDVNvbWVyc2V0IFdlc3Qx KjAoBgNVBAoTIVNvdXRoIEFmcmljYW4gUG9zdCBPZmZpY2UgTGltaXRlZDEaMBgG A1UECxMRU0FQTyBUcnVzdCBDZW50cmUxHTAbBgNVBAMTFFNBUE8gQ2xhc3MgMyBS b290IENBMSkwJwYJKoZIhvcNAQkBFhpwa2lhZG1pbkB0cnVzdGNlbnRyZS5jby56 YTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMp4Gge89vu0t4m80BlW OCpZnQfqGvn4+GhnXo/vyvf1aonmo5V/qdspJBw10DiWbD5WJP9eYlGQLofonMfa vDPxnqFvC44KJPT4TZCmss1eEdPCl0z1X0AdJiRNjQkQC/+7IBuTJhkMQz/pjrwx NxBukcpIglZGx7y5Op5GgWbP2ehcEM85nmXDnsVa9EvMRJlmhvRyG6NTSequR80y DXDmoKB2B53/WO/kPJHAteTcuAEM0/6zQqA7YQLUN1vXTEWV0nVd9W4wX1dRi7L/ fsiLnKqjQTcMEJGopoVcucePBVGy0HjS4ktJ6dQapzusqjPmmioDQJhvdFITMZTR EsG0yzD5/0S4kltS1jDZM9F14xmlFhW3VFfxVlDOTr4DOy/stjDuFGBeX3o19E5k BxHqpQdmG26T4rBPXtbgROCz3K7vuP2os+zs5TmIRLShuxRgZI/WkpPL88xQ3ekH yGdn+fCHhJGyAGLpv0oVdMW/BEwFRl0Ky+XqYQDhb0GxNI6mAKJ8pqWm+mxMQ+Wo Jpo0mB6HmOdMeNGPnwVVXYpLyc+gC30GkJwYkrLEstfjRdlrc8OXOb8pHgYJVUC6 vNpIdUPt/kR+PSzmYpED/T2J7370XSSPpQsrsz56KSi8uz+/63eFBCaLlLKQ9euN T6JEIlConCpESAB4GaudCJYVAgMBAAGjIDAeMA4GA1UdDwEB/wQEAwIBBjAMBgNV HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQBFyZ6kYCWJ/peZuMLxrtc1EzZ5 0N2CIlHxTPZjNqENWyDyG4XWdo95D6urosg3uClj7OWetniWpv+KEJ4Ubhpt316b uSyFcgnyNxqbebMo7+WW3Uabh4yN+EGMFOGtRV/LpyQMwTe6LALEq4w1OAnpkPFm cqWRQnkJChROmnSWRaEvIKSXdCrLAbPLVireLFhfF2diviu6ERMtEEBFYfDDxe+P GdA6wmUK2WjonAYgN7qfSxY5YHjgdWJVwNnLNyEJEJA5z1yZ7N+s1lpHQSOruKch B5IUrIzaiiQW6xSISLzvgc6OFt890lpvn8BBcSWJBizmvE/tpJHzxu1U3dmTAyKq hAeoc9unWolN9u1ygOuDeESpIiRomLE/qUHy7OkEpCIzX+Z13L2eJfXjZGUewfNX Jy7JwDJ4RNvYOBN24R1/4BeHmn9NSwduuFc4hbnpU06XOg0fU7mBckVG88h+pgnu GDR1fofn6CDu3BbU5seEqtpvX5zM61gGQZOM5cxZDGhlOTwpFmHxaftHucLYZ4Ek C/T8SWIArwej/56gDsMBiyFn1jsbPOCht23cVUvj0C6d1p7KbrqzuvBgfn8FUONB 8b5AOpBX4C1pbAvBvHrBjvsJ3uqVfzmbw2OfSfV4r35JgqyfbowSGlC2wOPchILY 69K7Dl02hgJJKwU7Vw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEOTCCAyGgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEWMBQGA1UEBxMNU29tZXJzZXQgV2VzdDEq MCgGA1UEChMhU291dGggQWZyaWNhbiBQb3N0IE9mZmljZSBMaW1pdGVkMRowGAYD VQQLExFTQVBPIFRydXN0IENlbnRyZTEdMBsGA1UEAxMUU0FQTyBDbGFzcyAyIFJv b3QgQ0ExKTAnBgkqhkiG9w0BCQEWGnBraWFkbWluQHRydXN0Y2VudHJlLmNvLnph MB4XDTEwMDkxNTAwMDAwMFoXDTMwMDkxNDAwMDAwMFowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxFjAUBgNVBAcTDVNvbWVyc2V0IFdlc3Qx KjAoBgNVBAoTIVNvdXRoIEFmcmljYW4gUG9zdCBPZmZpY2UgTGltaXRlZDEaMBgG A1UECxMRU0FQTyBUcnVzdCBDZW50cmUxHTAbBgNVBAMTFFNBUE8gQ2xhc3MgMiBS b290IENBMSkwJwYJKoZIhvcNAQkBFhpwa2lhZG1pbkB0cnVzdGNlbnRyZS5jby56 YTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALd8aXxg9Wwm9KocF39d 1BFL5/Pa53On+qRCSWg/2qVAXAZoX07Mvb6BOCQtzCagRG0DyyPgu96FU0uUX197 qsgal/7XI5PtsGq92PwAPrOSBOBLvk87mKed7c1j8IHnbJjUbGBVAOW5POY0lV3g /XGH6f+B7uV3bxj/88l8pZXdgtwU2aLhvs0nc7tFWz90sWJ4ZhAiLPVo8xeIFjua Gx37FK4NuvKQVaLVMNYrlTLHOW57ZdJ3OM5uVqXZI6s4sjtRhcAdG7cRLwVpR9gC ypKo4TPehQib7ZDV2CGZcb+29XPvZwiYZNLyKnpLIRbhH1hh3pFHHyGfH/6MI4aD GCcCAwEAAaMgMB4wDgYDVR0PAQH/BAQDAgEGMAwGA1UdEwQFMAMBAf8wDQYJKoZI hvcNAQEFBQADggEBACPByWyDecjPhX88XrtWrP9gR1GnnErxh8RNh9/mTA3kM+l+ CFMQoutCPq9I8ccdFZd0dhy9dCJD6FlZPg3Kccbnl6h+91uf3nToG1FCSWPAo+iU j9aets0F1s6g6rGHsLsuCrroXTs8AP9vFl1lZFBQNf8XuHYYx/FrXw3Z6OoTI2F/ Yc5rSQeBMFIh8qHBmO/GQvMv4w5oaUXzkdFkUabaSnmaJFvDTLGHEcfh91z4Il43 1nZHe79pn1XVMCUsSqtMhOQlWqTSYcah4JBzLH+pvjac/m4hV0WRQaoCbVO4MLvc wucgMw5Ve/tCkwcaSF4t/kS3H2S+G8NNnerWMmA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWDCCBECgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEWMBQGA1UEBxMNU29tZXJzZXQgV2VzdDEq MCgGA1UEChMhU291dGggQWZyaWNhbiBQb3N0IE9mZmljZSBMaW1pdGVkMRowGAYD VQQLExFTQVBPIFRydXN0IENlbnRyZTEdMBsGA1UEAxMUU0FQTyBDbGFzcyAzIFJv b3QgQ0ExKTAnBgkqhkiG9w0BCQEWGnBraWFkbWluQHRydXN0Y2VudHJlLmNvLnph MB4XDTEwMDkxNTAwMDAwMFoXDTMwMDkxNDAwMDAwMFowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxFjAUBgNVBAcTDVNvbWVyc2V0IFdlc3Qx KjAoBgNVBAoTIVNvdXRoIEFmcmljYW4gUG9zdCBPZmZpY2UgTGltaXRlZDEaMBgG A1UECxMRU0FQTyBUcnVzdCBDZW50cmUxHTAbBgNVBAMTFFNBUE8gQ2xhc3MgMyBS b290IENBMSkwJwYJKoZIhvcNAQkBFhpwa2lhZG1pbkB0cnVzdGNlbnRyZS5jby56 YTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMp4Gge89vu0t4m80BlW OCpZnQfqGvn4+GhnXo/vyvf1aonmo5V/qdspJBw10DiWbD5WJP9eYlGQLofonMfa vDPxnqFvC44KJPT4TZCmss1eEdPCl0z1X0AdJiRNjQkQC/+7IBuTJhkMQz/pjrwx NxBukcpIglZGx7y5Op5GgWbP2ehcEM85nmXDnsVa9EvMRJlmhvRyG6NTSequR80y DXDmoKB2B53/WO/kPJHAteTcuAEM0/6zQqA7YQLUN1vXTEWV0nVd9W4wX1dRi7L/ fsiLnKqjQTcMEJGopoVcucePBVGy0HjS4ktJ6dQapzusqjPmmioDQJhvdFITMZTR EsG0yzD5/0S4kltS1jDZM9F14xmlFhW3VFfxVlDOTr4DOy/stjDuFGBeX3o19E5k BxHqpQdmG26T4rBPXtbgROCz3K7vuP2os+zs5TmIRLShuxRgZI/WkpPL88xQ3ekH yGdn+fCHhJGyAGLpv0oVdMW/BEwFRl0Ky+XqYQDhb0GxNI6mAKJ8pqWm+mxMQ+Wo Jpo0mB6HmOdMeNGPnwVVXYpLyc+gC30GkJwYkrLEstfjRdlrc8OXOb8pHgYJVUC6 vNpIdUPt/kR+PSzmYpED/T2J7370XSSPpQsrsz56KSi8uz+/63eFBCaLlLKQ9euN T6JEIlConCpESAB4GaudCJYVAgMBAAGjPzA9MA4GA1UdDwEB/wQEAwIBBjAMBgNV HRMEBTADAQH/MB0GA1UdDgQWBBRhs3lSnUqVklGOgiRw045AyMVm0DANBgkqhkiG 9w0BAQUFAAOCAgEAf8azJIRQN/nEsMUwPBbpUA16urQ70iPl6Yl4auXjGwUekRzO BpeNZhYHRO+BuQh+o8c5NLi/mm2NsMEgQi4N9wsGA09uy7y3sC8ZcY2OrwpNWDGL RJkqKGaFx4AmZrBHwjmy+k8+Vb3ciSdLczME/ntHkMkFwC0z+LcIgilBQ/0mU+b6 HzdWjU8Xutj9OoRw2D7wM67EBUhUobnVIT/qPsepMUf3m65KYpjRZyBl3nnhsTIe a9/7gGtHXDnHDgiqx6PuKek04pv5dbgm64idtDkRLnD9UQQyuw95hFAhRXwv5Nn/ JTgGI6tOsQ7cOzEKrdpLAGlrLuLDDMkFAUVm4aWJYRxkmY0LmJCzfmY7C9ir6HUO 2X+abn3JgyfJvOg0OMJahzJyBwz+1ZTR8MB48oCoRvVrmuzi2RaOivqE9tFSyZyy IVZgQ6YQ939Jv74H01BkbQK6KlUsz9nCbq98C0jQ8eGnwq10j4bk7ar6XIN9Quh9 Bx0HVcwraTK5d4JoxnfyImmmyQpdh5nlcZ59LxMe0vT9CXknWCsKh4Eq+2ojLUsk hXQWRxgPCcX+qUgk46zQaT1fU5gyvezgUcFTSrH2O/A0SPWa3tzR4OO9JbNE6Dpz yXnQrNHt4gAKX6EdZllKc2jUBXIzOKdrr5HbDceMQOiekIjJ+/4k14Gs894= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWDCCBECgAwIBAgIBAzANBgkqhkiG9w0BAQUFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEWMBQGA1UEBxMNU29tZXJzZXQgV2VzdDEq MCgGA1UEChMhU291dGggQWZyaWNhbiBQb3N0IE9mZmljZSBMaW1pdGVkMRowGAYD VQQLExFTQVBPIFRydXN0IENlbnRyZTEdMBsGA1UEAxMUU0FQTyBDbGFzcyA0IFJv b3QgQ0ExKTAnBgkqhkiG9w0BCQEWGnBraWFkbWluQHRydXN0Y2VudHJlLmNvLnph MB4XDTEwMDkxNTAwMDAwMFoXDTMwMDkxNDAwMDAwMFowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxFjAUBgNVBAcTDVNvbWVyc2V0IFdlc3Qx KjAoBgNVBAoTIVNvdXRoIEFmcmljYW4gUG9zdCBPZmZpY2UgTGltaXRlZDEaMBgG A1UECxMRU0FQTyBUcnVzdCBDZW50cmUxHTAbBgNVBAMTFFNBUE8gQ2xhc3MgNCBS b290IENBMSkwJwYJKoZIhvcNAQkBFhpwa2lhZG1pbkB0cnVzdGNlbnRyZS5jby56 YTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvc7UiaoKOf4BGO2ciS dTpVwVEiygt6pDUNxeZXLYPwKm8iODcxbXyFJKIGL0OCPUUwQCUc7lhHQebwngAe +PQvEbuSsphFLdMfgMl2FBPDzEDmres5YPzPyN8q/YwSUe/PDGTGV+gjUV3nZlLq Zr2Tf516KPEZcG6EnzBHt7A5axMs60tNLq8/v/0CE0o55z4zxRCRUb4PR51NUvws 8+MTogCC4RQMzdKes/Lggdq+mZJT432Zd0Ph4UgpgZ7WBVc6cdw+mK1YcG9Gu34y A+KDm1lX9/izzVQW7LatoRwaktHUKZ6PzbPofVDxwoKsur20dVag9UVdGH0sjPF7 QcyGsZqESwoqXZuW4c36qxYnQeeVNabLiqeW86XMUfktfR5D+9xttbk4vQX7WPou 0+xeZC2vWAFKfCJG00HLPeSWXklDOLuJ6/ScaTkSA1yEu+WMHurgZrvAv4z+ngpN PWg/QHbWMqnqRbhqB1KOzVHxXShjDNNZOPzJ/YLJRSC85ujMogzLe2Q5SUZF9XMc apcg6yFC97QgUrdK/XW8yw8MZxFXH/cw8auQzF08lgVi08pVAUtGxYCHHHLQc1Qh 6tejnNOuf9RT2Sj8V97lP1JKu8gmJEdTHHO6z8a0MM1eccdWvEk4JebFEAl42dQd XM1u7duRXKFTFFaqjSeppo4bAgMBAAGjPzA9MA4GA1UdDwEB/wQEAwIBBjAMBgNV HRMEBTADAQH/MB0GA1UdDgQWBBQWhC37G+e0HmiY00IgGm5+T5FXAjANBgkqhkiG 9w0BAQUFAAOCAgEAe+MNYzpkIG3M/Cy46dar29erJilHogxW7XXMlZlSNssg+xE0 F0JOdQWw2OS4sIQvmBm5+9A5bHIGGMlcinp0CDdIaf0ioV3F13gT8ChCQcPJwzkJ B9Sh+DciaeTfMlVvwny5k/GyN3XMrtIzlow29wHt42TpC2hbEKoBNpl8z5qUXf0a WWGiZRV9nhdk1J9TmAH9cVfQXUARFj8/RNKvyfwIMn12+NVD6Nw2aAfDTsOWl1fG fTZe23Ct/q7UiJ21pGDWo2K+fPk0Hvy79EpyxYMeRmjDDpeDGD3TDgoRNXxplcWr KvXIORBNDIkwKYlJG0SXkfTqZSEbPwpDcoIcbRFd4CJFX2FMoqb636NGuuGBYGwy tPzk3DYF5DP36493SaqNCu9IiuZBl347q0OH8ghgC2/XWWb9K7svzjNPcuC217NT V4nwO7xu4hC/cz5ij6UI6VNnwU7BLkJDp7Kk+RaLQu7cNH9Is5DbJOLI5FM1U5zq N4XPv5gGNUcm165t3YSpY1gmQfV1Mi5hnk+TUlL2WiPrwaBzJiUiQpGRkYBP/4jO XnPnlsLtCRL3dpapeWKQSYGDnwwyMuJbyt1INKyHjnGVrkzkfHgdp1HDvRH6AtGV iXMIRiKJaQDPT4DBTVuUxMqZUZgvDb19VGTUCtonWac3u1YM0AaicrkSuVs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEWDCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEWMBQGA1UEBxMNU29tZXJzZXQgV2VzdDEq MCgGA1UEChMhU291dGggQWZyaWNhbiBQb3N0IE9mZmljZSBMaW1pdGVkMRowGAYD VQQLExFTQVBPIFRydXN0IENlbnRyZTEdMBsGA1UEAxMUU0FQTyBDbGFzcyAyIFJv b3QgQ0ExKTAnBgkqhkiG9w0BCQEWGnBraWFkbWluQHRydXN0Y2VudHJlLmNvLnph MB4XDTEwMDkxNTAwMDAwMFoXDTMwMDkxNDAwMDAwMFowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxFjAUBgNVBAcTDVNvbWVyc2V0IFdlc3Qx KjAoBgNVBAoTIVNvdXRoIEFmcmljYW4gUG9zdCBPZmZpY2UgTGltaXRlZDEaMBgG A1UECxMRU0FQTyBUcnVzdCBDZW50cmUxHTAbBgNVBAMTFFNBUE8gQ2xhc3MgMiBS b290IENBMSkwJwYJKoZIhvcNAQkBFhpwa2lhZG1pbkB0cnVzdGNlbnRyZS5jby56 YTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALd8aXxg9Wwm9KocF39d 1BFL5/Pa53On+qRCSWg/2qVAXAZoX07Mvb6BOCQtzCagRG0DyyPgu96FU0uUX197 qsgal/7XI5PtsGq92PwAPrOSBOBLvk87mKed7c1j8IHnbJjUbGBVAOW5POY0lV3g /XGH6f+B7uV3bxj/88l8pZXdgtwU2aLhvs0nc7tFWz90sWJ4ZhAiLPVo8xeIFjua Gx37FK4NuvKQVaLVMNYrlTLHOW57ZdJ3OM5uVqXZI6s4sjtRhcAdG7cRLwVpR9gC ypKo4TPehQib7ZDV2CGZcb+29XPvZwiYZNLyKnpLIRbhH1hh3pFHHyGfH/6MI4aD GCcCAwEAAaM/MD0wDgYDVR0PAQH/BAQDAgEGMAwGA1UdEwQFMAMBAf8wHQYDVR0O BBYEFKudI5P9HzNKMi2qJFryLWSpAZpBMA0GCSqGSIb3DQEBBQUAA4IBAQBWUlG5 DwLh9i6csTFapvjOvO4ChBUJ8ShSX+fhLL3beQp6v+tintWGRynudDDsTHW1HuOq M++t4WpMvzcBvlWDTKlS2DeYUG9o3UdBtywwyG5MByzG00m5tVzSy8zUNsYHDRhP P2MAxOy2iPsBZGOt0fd3fGRUKxI9NBWF8KC6eSlfmJtC6q7BqJ8TiYpt6bg4yWHt YOz3KlgFm6FgeIMX4X5f6P144GtWKoZ2rlvCXutF5DC4Me1ksV0uwD2ADccnE9N2 4ob73NuACoHh/Qj5C8QxtGNb54wz5Qa2Umqz1+lr4zJ4MmaUTt2Nd23TJChbVGF3 Amd1lEtXS+ZsxTlv -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDNzCCAh+gAwIBAgICJxwwDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCR1Ix HTAbBgNVBAoTFEF0aGVucyBFeGNoYW5nZSBTLkEuMRYwFAYDVQQDEw1BVEhFWCBS b290IENBMB4XDTEwMTAxODE1NTYwM1oXDTMwMTAxNzIxMDAwMFowRDELMAkGA1UE BhMCR1IxHTAbBgNVBAoTFEF0aGVucyBFeGNoYW5nZSBTLkEuMRYwFAYDVQQDEw1B VEhFWCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzRo9 MLWzOLK/eruuodbXhfAiOqSJacThYgTJcNM8MxLi5jjld6QkRGQNt65MWt3hGAY+ 7ZtaBfXh3hLtNircR9mRUZntsb9qc6EKCCSoio0cC1nTv3AjVUSgjDDFzm1PsOy+ 84wx3wpa3NNXXAWgM5U7l49UC7j1a33Hxay1eY4GOPGoKVU9mjbQJ180ahJ4FyjZ mEns2VpS2iY6+u5MpiaOqD5VH7If4bWb+To19u2RHP0LECT9H/nT4wAlsQslwLd9 mjwHOoAL1qj+kUXowdLFIm/T5XEftiw2tFig7c1KaORqV/ShdezXAJnV9plc607J u9cao0VZAA+MO9t0NQIDAQABozMwMTAPBgNVHRMBAf8EBTADAQH/MBEGA1UdDgQK BAhD4oDou9K3wTALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAD8BY3UH Mitfdf92jtOpuG/MUD2EV08og+h8o26ivPfCuq46q07QD5IouN1bLNvl1h86k+GR DteqXwFhLD5hT96VFU3MPeoy4qP++Bap8rwp/CmefXKlXaFrAtVfSPSgO8sYRvA9 F1WD0ClhkbuaQUnRE75BlPI+wySrn8drQpBCeX5aUfs8XgshH8vZSBMVsWp/A8TR ulHScImqCEqHHPZ6mLHUUQVVxpAXb8PgBMB69C8YolZCcy62spvROb4JwgJKJBf5 96y9cQe/leKX5aGECI2y4kSh3IkwO6gMBXpddgBPHm9xfys52kVCOTHSqTJA1Dhj E5Y3mkld2cf9uEw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX 0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c /3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D 34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv 033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq 4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr 6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN 9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h 9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo +fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h 3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE 1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYDCCA0igAwIBAgICATAwDQYJKoZIhvcNAQELBQAwWTELMAkGA1UEBhMCVVMx GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UE AxMYRmVkZXJhbCBDb21tb24gUG9saWN5IENBMB4XDTEwMTIwMTE2NDUyN1oXDTMw MTIwMTE2NDUyN1owWTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu bWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UEAxMYRmVkZXJhbCBDb21tb24gUG9s aWN5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2HX7NRY0WkG/ Wq9cMAQUHK14RLXqJup1YcfNNnn4fNi9KVFmWSHjeavUeL6wLbCh1bI1FiPQzB6+ Duir3MPJ1hLXp3JoGDG4FyKyPn66CG3G/dFYLGmgA/Aqo/Y/ISU937cyxY4nsyOl 4FKzXZbpsLjFxZ+7xaBugkC7xScFNknWJidpDDSPzyd6KgqjQV+NHQOGgxXgVcHF mCye7Bpy3EjBPvmE0oSCwRvDdDa3ucc2Mnr4MrbQNq4iGDGMUHMhnv6DOzCIJOPp wX7e7ZjHH5IQip9bYi+dpLzVhW86/clTpyBLqtsgqyFOHQ1O5piF5asRR12dP8Qj wOMUBm7+nQIDAQABo4IBMDCCASwwDwYDVR0TAQH/BAUwAwEB/zCB6QYIKwYBBQUH AQsEgdwwgdkwPwYIKwYBBQUHMAWGM2h0dHA6Ly9odHRwLmZwa2kuZ292L2ZjcGNh L2NhQ2VydHNJc3N1ZWRCeWZjcGNhLnA3YzCBlQYIKwYBBQUHMAWGgYhsZGFwOi8v bGRhcC5mcGtpLmdvdi9jbj1GZWRlcmFsJTIwQ29tbW9uJTIwUG9saWN5JTIwQ0Es b3U9RlBLSSxvPVUuUy4lMjBHb3Zlcm5tZW50LGM9VVM/Y0FDZXJ0aWZpY2F0ZTti aW5hcnksY3Jvc3NDZXJ0aWZpY2F0ZVBhaXI7YmluYXJ5MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUrQx6dVzl85jEeZgOrCj9l/TnAvwwDQYJKoZIhvcNAQELBQAD ggEBAI9z2uF/gLGH9uwsz9GEYx728Yi3mvIRte9UrYpuGDco71wb5O9Qt2wmGCMi TR0mRyDpCZzicGJxqxHPkYnos/UqoEfAFMtOQsHdDA4b8Idb7OV316rgVNdF9IU+ 7LQd3nyKf1tNnJaK0KIyn9psMQz4pO9+c+iR3Ah6cFqgr2KBWfgAdKLI3VTKQVZH venAT+0g3eOlCd+uKML80cgX2BLHb94u6b2akfI8WpQukSKAiaGMWMyDeiYZdQKl Dn0KJnNR6obLB6jI/WNaNZvSr79PMUjBhHDbNXuaGQ/lj/RqDG8z2esccKIN47lQ A2EC/0rskqTcLe4qNJMHtyznGI8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIJmDCCB4CgAwIBAgIBCjANBgkqhkiG9w0BAQwFADCCAR4xPjA8BgNVBAMTNUF1 dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s YW5vMQswCQYDVQQGEwJWRTEQMA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlz dHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0 aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBlcmludGVuZGVuY2lh IGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUwIwYJ KoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NDEz NloXDTMwMTIyMzIzNTk1OVowggEeMT4wPAYDVQQDEzVBdXRvcmlkYWQgZGUgQ2Vy dGlmaWNhY2lvbiBSYWl6IGRlbCBFc3RhZG8gVmVuZXpvbGFubzELMAkGA1UEBhMC VkUxEDAOBgNVBAcTB0NhcmFjYXMxGTAXBgNVBAgTEERpc3RyaXRvIENhcGl0YWwx NjA0BgNVBAoTLVNpc3RlbWEgTmFjaW9uYWwgZGUgQ2VydGlmaWNhY2lvbiBFbGVj dHJvbmljYTFDMEEGA1UECxM6U3VwZXJpbnRlbmRlbmNpYSBkZSBTZXJ2aWNpb3Mg ZGUgQ2VydGlmaWNhY2lvbiBFbGVjdHJvbmljYTElMCMGCSqGSIb3DQEJARYWYWNy YWl6QHN1c2NlcnRlLmdvYi52ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBAME77xNS8ZlW47RsBeEaaRZhJoZ4rw785UAFCuPZOAVMqNS1wMYqzy95q6Gk UO81ER/ugiQX/KMcq/4HBn83fwdYWxPZfwBfK7BP2p/JsFgzYeFP0BXOLmvoJIzl Jb6FW+1MPwGBjuaZGFImWZsSmGUclb51mRYMZETh9/J5CLThR1exStxHQptwSzra zNFpkQY/zmj7+YZNA9yDoroVFv6sybYOZ7OxNDo7zkSLo45I7gMwtxqWZ8VkJZkC 8+p0dX6mkhUT0QAV64Zc9HsZiH/oLhEkXjhrgZ28cF73MXIqLx1fyM4kPH1yOJi/ R72nMwL7D+Sd6mZgI035TxuHXc2/uOwXfKrrTjaJDz8Jp6DdessOkxIgkKXRjP+F K3ze3n4NUIRGhGRtyvEjK95/2g02t6PeYiYVGur6ruS49n0RAaSS0/LJb6XzaAAe 0mmO2evnEqxIKwy2mZRNPfAVW1l3wCnWiUwryBU6OsbFcFFrQm+00wOicXvOTHBM aiCVAVZTb9RSLyi+LJ1llzJZO3pq3IRiiBj38Nooo+2ZNbMEciSgmig7YXaUcmud SVQvLSL+Yw+SqawyezwZuASbp7d/0rutQ59d81zlbMt3J7yB567rT2IqIydQ8qBW k+fmXzghX+/FidYsh/aK+zZ7Wy68kKHuzEw1Vqkat5DGs+VzAgMBAAGjggLbMIIC 1zASBgNVHRMBAf8ECDAGAQH/AgECMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52 ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMB0GA1UdDgQWBBStuyIdxuDS Aaj9dlBSk+2YwU2u0zCCAVAGA1UdIwSCAUcwggFDgBStuyIdxuDSAaj9dlBSk+2Y wU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRpZmlj YWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAw DgYDVQQHEwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYD VQQKEy1TaXN0ZW1hIE5hY2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25p Y2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5kZW5jaWEgZGUgU2VydmljaW9zIGRlIENl cnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG9w0BCQEWFmFjcmFpekBz dXNjZXJ0ZS5nb2IudmWCAQowCwYDVR0PBAQDAgEGMDcGA1UdEQQwMC6CD3N1c2Nl cnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMFQGA1UdHwRN MEswJKAioCCGHmh0dHA6Ly93d3cuc3VzY2VydGUuZ29iLnZlL2xjcjAjoCGgH4Yd bGRhcDovL2FjcmFpei5zdXNjZXJ0ZS5nb2IudmUwNwYIKwYBBQUHAQEEKzApMCcG CCsGAQUFBzABhhtodHRwOi8vb2NzcC5zdXNjZXJ0ZS5nb2IudmUwQAYDVR0gBDkw NzA1BgVghl4BAjAsMCoGCCsGAQUFBwIBFh5odHRwOi8vd3d3LnN1c2NlcnRlLmdv Yi52ZS9kcGMwDQYJKoZIhvcNAQEMBQADggIBABxZEOVepFHBR7tlsgtV4i+poye8 4TyKx2wDVqOpKaKbipXYH/e2EmAWvnr0/QOBT/2BgapPgXAeLu/AkhJ7uw+FiMT5 HUG1uiQqwygmE8r5APvXw1z5aOkbwRgiyaJsZMP4OcNOId3Wwt7ltizJXDjw3l5q 5Cf0uDPEy2GSM1OozPydzVP7KAvv7X+wj3QitjVXgKiuBa4pCjuypP0949TBkPY/ zrzkRP7RwX4oL/0AJDIgiMRvGHuRDkiQvJZiYIFtFAAaUbq1XWmNYUccLKxORSCp SEWjh0mjeJDdNkJ/2HZv/W2DAcb5f5ggf5YuImCroifAsDUk0Mm/M5kiUw5uH2JM JvwkM8rBA8ypF2FjMyTMaEDvr6LihcOIMNNFG+5W6lYKDwpHmzBZ2EnRMJAMJyom CChcMh8n160LSeUXUWPP5g07YFEavUMJUOaRtWPmZJeqC5cTAQaGXKUflb5Qjguy 0mR/26tM5kPG5IWNav6N/ruUVR6RUycI07pnPTqhycHFFLr5Q1zFjiGMgqL9KjIl 1RaMFVbAmPwuso4ZpBZxw0vdcf5x7CId8MGMmIGHtL8CuMQwMUfCwLCvezNjCt2s RZvBzICH9NmYXpyG/poE/2ZK/HthVL5XYwUHxqcBdVnkbjk7APSqnfOfiL/P0SUr 339z7RaGqZBlD3Ap -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkDCCAnigAwIBAgIQHKAtwVI7am2LXB+VSu2sMDANBgkqhkiG9w0BAQUFADBi MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp dHkwHhcNMTEwMTAxMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjQjBA MB0GA1UdDgQWBBQhMMn7ANdOmNqHqirQpy6xQDGnTDAOBgNVHQ8BAf8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAwomEoOiMZv3/EwUb wzqOmEmK+KoAXCb9cmqjfhIblK5U+CGPp5NP9xbvubmzMsAlITFmNywJsP4ysDfs PLjOjwiqCJAHXHXV4U4sywIk6aJe6fV4NSIGHPIfiLHhXMyWVPpvScyN8VYD7c8s nyfe5cqDRL5GQPlXLtJ/MS3Og9z+cGuE0KOf/5fQqNcC7LEs8O9zOD2ZrMRPAb/V aurGLjIpFwrL5mme0Uq19t+OGfiV6UWpDs1tQVkgnnPGbHEcnNRNMKhzCaAV86BF JsNb/bu52C3XH/UFMBn2rg+OYo/fyE+G2R1hFrPJ8Lv7x/WvASJH7NjazxzzU2a6 UwkB+Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID0DCCArigAwIBAgIQIKTEf93f4cdTYwcTiHdgEjANBgkqhkiG9w0BAQUFADCB gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xMTAxMDEwMDAw MDBaFw0zMDEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI 2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp +2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O nKVIrLsm9wIDAQABo0IwQDAdBgNVHQ4EFgQUC1jli8ZMFTekQKkwqSG+RzZaVv8w DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBAC/JxBwHO89hAgCx2SFRdXIDMLDEFh9sAIsQrK/xR9SuEDwMGvjUk2ysEDd8 t6aDZK3N3w6HM503sMZ7OHKx8xoOo/lVem0DZgMXlUrxsXrfViEGQo+x06iF3u6X HWLrp+cxEmbDD6ZLLkGC9/3JG6gbr+48zuOcrigHoSybJMIPIyaDMouGDx8rEkYl Fo92kANr3ryqImhrjKGsKxE5pttwwn1y6TPn/CbxdFqR5p2ErPioBhlG5qfpqjQi pKGfeq23sqSaM4hxAjwu1nqyH6LKwN0vEJT9s4yEIHlG1QXUEOTS22RPuFvuG8Ug R1uUq27UlTMdphVx8fiUylQ5PsE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIINDCCBhygAwIBAgIRAP11BI16YIaTaUyqADxl0z0wDQYJKoZIhvcNAQELBQAw gaYxCzAJBgNVBAYTAkNIMTswOQYDVQQKEzJUaGUgRmVkZXJhbCBBdXRob3JpdGll cyBvZiB0aGUgU3dpc3MgQ29uZmVkZXJhdGlvbjERMA8GA1UECxMIU2VydmljZXMx IjAgBgNVBAsTGUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxIzAhBgNVBAMTGlN3 aXNzIEdvdmVybm1lbnQgUm9vdCBDQSBJMB4XDTExMDIxNTA5MDAwMFoXDTM1MDIx NTA4NTk1OVowgaYxCzAJBgNVBAYTAkNIMTswOQYDVQQKEzJUaGUgRmVkZXJhbCBB dXRob3JpdGllcyBvZiB0aGUgU3dpc3MgQ29uZmVkZXJhdGlvbjERMA8GA1UECxMI U2VydmljZXMxIjAgBgNVBAsTGUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxIzAh BgNVBAMTGlN3aXNzIEdvdmVybm1lbnQgUm9vdCBDQSBJMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAyA5y9AEvhnsLwmOwjWjtHz3euYObXKFdug82JxEE rQZUILceoObOvvCZaXIZNWRmMY0svY5CCp/GyqmQLNq8hTAD2TKWlvC+oCINJGzU xn9aTFEkLVRyCHwz6cwox2ZlI2lrlbTrvuOH52PX5PsHrRKS6+fkCkOyqd/HkLwm W5H5o7eHnJS5EI2IxVhcMrwW7A5XT/6nk3iP4MU5uweIYMFUZeuHvp8xl3E8+ovI g2xSluCswO/LaQiVW+Dgu68npMIX8VGfhHZh2CTi/mFtZDVJ6jnEIWK9zOIC/0hr OK9px7mSLYIRjb0LiYUq6re0ss1L69H6qvDgTAk8Td/2MR2GMKhBiFdwLCdR3s+L Tj8C8lClF+BnG3IMQTEfAaKWPjzbAradlOYCTvPwGYKyCCMT65HNUdOqRsJzmJg/ usPumvz6za9yCjcTj/mgULPq+z8svPpjVTX00ry4cdKR6+nKylzsUWaonlkFIi+j GttP4EViIzxdVfswlSs0os+ntEvAM8k0UZ3TsyvfxeosLMffRB+2jbn+81zNNy+w bJxKCL3o9db6cOVpMjdcXwvLP+SIAszKs3gvfb9IsyGwH4h5m1qKcdghhCkPSgQx Kr0NIUTOdJ0m00kd+Iao5RJ3xcBzDFCDapBrocr40JXZNYbHEaM7FMfLhlhWDfuD 9wECAwEAAaOCAlkwggJVMA8GA1UdEwEB/wQFMAMBAf8wgZsGA1UdIASBkzCBkDCB jQYIYIV0AREDAQAwgYAwQwYIKwYBBQUHAgEWN2h0dHA6Ly93d3cucGtpLmFkbWlu LmNoL2Nwcy9DUFNfMl8xNl83NTZfMV8xN18zXzFfMC5wZGYwOQYIKwYBBQUHAgIw LRorVGhpcyBpcyB0aGUgU3dpc3MgR292ZXJubWVudCBSb290IENBIEkgQ1BTLjCB jgYDVR0fBIGGMIGDMIGAoH6gfIZ6bGRhcDovL2FkbWluZGlyLmFkbWluLmNoOjM4 OS9jbj1Td2lzcyUyMEdvdmVybm1lbnQlMjBSb290JTIwQ0ElMjBJLG91PUNlcnRp ZmljYXRpb24lMjBBdXRob3JpdGllcyxvdT1TZXJ2aWNlcyxvPUFkbWluLGM9Q0gw HQYDVR0OBBYEFLUbg7s7T7LS++UDjtRhXdEajrCiMA4GA1UdDwEB/wQEAwIBBjCB 4wYDVR0jBIHbMIHYgBS1G4O7O0+y0vvlA47UYV3RGo6woqGBrKSBqTCBpjELMAkG A1UEBhMCQ0gxOzA5BgNVBAoTMlRoZSBGZWRlcmFsIEF1dGhvcml0aWVzIG9mIHRo ZSBTd2lzcyBDb25mZWRlcmF0aW9uMREwDwYDVQQLEwhTZXJ2aWNlczEiMCAGA1UE CxMZQ2VydGlmaWNhdGlvbiBBdXRob3JpdGllczEjMCEGA1UEAxMaU3dpc3MgR292 ZXJubWVudCBSb290IENBIEmCEQD9dQSNemCGk2lMqgA8ZdM9MA0GCSqGSIb3DQEB CwUAA4ICAQAl2t94sCbcn5nrM5zJRbpcY1KNbgNzqnRIxQ0L0hcMLAvSxiWD1FTN B4FUL2d2Jafp13+WR3ekHZtF//HY9p5HDnSME8TyvtYHKBg8mHXB2+uSiCbmBmSO +dL94pk1gdHYdRe1c+rd6BgilRYZClkqItyGWkNPJWg2qdiTAI9excNhhvDSFAmV UcR+2FLusI2KiHGl1yin9NwGWCVexFUYCJV0fLgB507Y1vZ8IENIDaPg3lTEqF8A SUPTRTuCZW7ui6MBIlaa8c4p5QzEa+3nTvixVYGtcf+E+whX5kfKrYf4Rvj68DWE 7bTYiJcid6SPFsg8Z9HhbgSse482zd6lCKwqjfWnHZ/Hw5EhQqOGgbkq2LHpOB1U CJg5ChHKMg4zzfRM6qhKBukYPkHGz6D24CtrII6nIALrMEGBsOjkrqQYiSvfFPAS KW14+k1E+7I05a/zjjX3w84sCxi00HmPE78Di2a4tWHUrA79eD0JrbXSLE9WQZmI RAx+Z+Nkn/paKlh3UWmxzSyapzQQBXT6bkVjy4tSrUeRohLIoiYExdAiHgOzspI3 VFf9iYN1A20tO7PxpKIQfJyTjaNQhDmLlVlB9gJ2Boq8DpDn2TrrrSZeV1PRb8h1 4KuRe2uhf/kbUKjc/k0G4RWKpBDrHgbPVEgVlii2Ix8a43ylj/o3Vw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIODCCBiCgAwIBAgIQDp8XmaWxPZzL7Abro/AOaTANBgkqhkiG9w0BAQsFADCB pzELMAkGA1UEBhMCQ0gxOzA5BgNVBAoTMlRoZSBGZWRlcmFsIEF1dGhvcml0aWVz IG9mIHRoZSBTd2lzcyBDb25mZWRlcmF0aW9uMREwDwYDVQQLEwhTZXJ2aWNlczEi MCAGA1UECxMZQ2VydGlmaWNhdGlvbiBBdXRob3JpdGllczEkMCIGA1UEAxMbU3dp c3MgR292ZXJubWVudCBSb290IENBIElJMB4XDTExMDIxNjA5MDAwMFoXDTM1MDIx NjA4NTk1OVowgacxCzAJBgNVBAYTAkNIMTswOQYDVQQKEzJUaGUgRmVkZXJhbCBB dXRob3JpdGllcyBvZiB0aGUgU3dpc3MgQ29uZmVkZXJhdGlvbjERMA8GA1UECxMI U2VydmljZXMxIjAgBgNVBAsTGUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxJDAi BgNVBAMTG1N3aXNzIEdvdmVybm1lbnQgUm9vdCBDQSBJSTCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBAKksEu2/wCLphugcN4KDm2gFbxbjiKgBD8txnn9H kEvMJXfI8NdpLpFoVyGysgchM+5MpDclmEy0RjJO1vlri1GK7yw38pjV9dS0t+cA yu/BE16Uq267nL36a4+r+B42Vmk4ZjrQ9DMNADkCqMUcCyG3XCAMYdCtrs6OXtk6 6d7/R3x4Vw4ccfRgHN3bmhgpr9mAo5+FhGMzke+9dO7dA3rI+uCE5tm9Tn76bk92 0V0+qOiHRZB5862u9cJdEU0p94gTydWTcwGr3e39r3f7aU7vj1Icz/UsWmzs/oKb 23w5q3UjfjiQT5SOLWJYnvfncvyUW3JWxZ2jrqu1tsDXdlAAPD9HiJJaYNS/Mhum lEANdnnpPM7ksx3HjPXohjG52CtQSoASidcsUIDmZy+2k5ytrAVSIlMgmQ69l8bh 2nOpHYnyxFnmh+ZWKw6VAhqHxnn+mWrpdOzwEvkUKCCVljovXVe1b/+TvLYoaiyk KHhGYa9BJKTz+gSO8YoZopFz4nePtKf5nP9uUey9H5YT6GORXodob+vYfC4QT1AY kMe3dO8zwIHfM+MakytVBCx80iu3Ywz+rXu9tjqXuT0DI3RzA6YsWQBs1dXo7K9C zNN/cItgYOeyoLaKUkz+CpbLzzqwWAjuHELJhndCbj+0rJAAWEIcQMRuuEXIvDM2 370nAgMBAAGjggJcMIICWDAPBgNVHRMBAf8EBTADAQH/MIGdBgNVHSAEgZUwgZIw gY8GCGCFdAERAxUBMIGCMEQGCCsGAQUFBwIBFjhodHRwOi8vd3d3LnBraS5hZG1p bi5jaC9jcHMvQ1BTXzJfMTZfNzU2XzFfMTdfM18yMV8xLnBkZjA6BggrBgEFBQcC AjAuGixUaGlzIGlzIHRoZSBTd2lzcyBHb3Zlcm5tZW50IFJvb3QgQ0EgSUkgQ1BT LjCBjwYDVR0fBIGHMIGEMIGBoH+gfYZ7bGRhcDovL2FkbWluZGlyLmFkbWluLmNo OjM4OS9jbj1Td2lzcyUyMEdvdmVybm1lbnQlMjBSb290JTIwQ0ElMjBJSSxvdT1D ZXJ0aWZpY2F0aW9uJTIwQXV0aG9yaXRpZXMsb3U9U2VydmljZXMsbz1BZG1pbixj PUNIMB0GA1UdDgQWBBTlhG+JaT12ABd/wau9rl/BfbrhYjAOBgNVHQ8BAf8EBAMC AQYwgeMGA1UdIwSB2zCB2IAU5YRviWk9dgAXf8Grva5fwX264WKhga2kgaowgacx CzAJBgNVBAYTAkNIMTswOQYDVQQKEzJUaGUgRmVkZXJhbCBBdXRob3JpdGllcyBv ZiB0aGUgU3dpc3MgQ29uZmVkZXJhdGlvbjERMA8GA1UECxMIU2VydmljZXMxIjAg BgNVBAsTGUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxJDAiBgNVBAMTG1N3aXNz IEdvdmVybm1lbnQgUm9vdCBDQSBJSYIQDp8XmaWxPZzL7Abro/AOaTANBgkqhkiG 9w0BAQsFAAOCAgEAgzdXdck4UL9BBpZwwtnH17BaAM2jQE/T0vmKh5GyictdpLxv Tz5U9so8s8RMi8c+9NnEYt3HVZ7R+dJE5x5Pz+juKxyoAfAzB/vhOxTTz1CRXtjq QsZ5WIWq+9zbcMqV+fQOYgJwaUQtaE/RcOooUma3cd4l6KGnb7ChJsfXyiBk3MBz PBCiFB70rcE+FJA5NmOIbyjgYKWR92Lkms/StXGeXTv2mSztkToInLSEhUnj4bqm tmiztrZPS1xTCldsoQeS9mKeqPqK1vNrpw+yK2a9r0JHCE/o13yfhg/6WoO+LW8A BLV2hxav3U86lrQ0V7fi/0H/3kIcZsWF68JyH7gcTu4X8mLvCgSsm6uh8u7uokAk HEfeQosYtKlXs088YjIcrWxErbzVHGM4Pckzpvu8KDdERuN6YvqASDXinhuIGUyz Qf3ud+BZgBphHjWkQXqzwY1E6cUhWems00TKdoU2FEYKHhY0psQ0d8OCOEghAv4S bNrX6rDs9s0szPObCmOA0/ULfQQthA3C2Uwrl/HVVPePswrivVg8mfKvORuQ+Tvn t0XnWmp9wZ8UbzBXmBmgB0Pr7tEIhtdJnBIKADsPp0GxSquQs9S9CeeID54kDiv7 YT1VmdNY5LjHffQVTWUOGHlBybvpmsFZGEQ0YtXoOHvKhRiYhnnNfbpH25U= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF7TCCA9WgAwIBAgIQP4vItfyfspZDtWnWbELhRDANBgkqhkiG9w0BAQsFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMp TWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEw MzIyMjIwNTI4WhcNMzYwMzIyMjIxMzA0WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm aWNhdGUgQXV0aG9yaXR5IDIwMTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQCygEGqNThNE3IyaCJNuLLx/9VSvGzH9dJKjDbu0cJcfoyKrq8TKG/Ac+M6 ztAlqFo6be+ouFmrEyNozQwph9FvgFyPRH9dkAFSWKxRxV8qh9zc2AodwQO5e7BW 6KPeZGHCnvjzfLnsDbVU/ky2ZU+I8JxImQxCCwl8MVkXeQZ4KI2JOkwDJb5xalwL 54RgpJki49KvhKSn+9GY7Qyp3pSJ4Q6g3MDOmT3qCFK7VnnkH4S6Hri0xElcTzFL h93dBWcmmYDgcRGjuKVB4qRTufcyKYMME782XgSzS0NHL2vikR7TmE/dQgfI6B0S /Jmpaz6SfsjWaTr8ZL22CZ3K/QwLopt3YEsDlKQwaRLWQi3BQUzK3Kr9j1uDRprZ /LHR47PJf0h6zSTwQY9cdNCssBAgBkm3xy0hyFfj0IbzA2j70M5xwYmZSmQBbP3s MJHPQTySx+W6hh1hhMdfgzlirrSSL0fzC/hV66AfWdC7dJse0Hbm8ukG1xDo+mTe acY1logC8Ea4PyeZb8txiSk190gWAjWP1Xl8TQLPX+uKg09FcYj5qQ1OcunCnAfP SRtOBA5jUYxe2ADBVSy2xuDCZU7JNDn1nLPEfuhhbhNfFcRf2X7tHc7uROzLLoax 7Dj2cO2rXBPB2Q8Nx4CyVe0096yb5MPa50c8prWPMd/FS6/r8QIDAQABo1EwTzAL BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUci06AjGQQ7kU BU7h6qfHMdEjiTQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQELBQADggIB AH9yzw+3xRXbm8BJyiZb/p4T5tPw0tuXX/JLP02zrhmu7deXoKzvqTqjwkGw5biR nhOBJAPmCf0/V0A5ISRW0RAvS0CpNoZLtFNXmvvxfomPEf4YbFGq6O0JlbXlccmh 6Yd1phV/yX43VF50k8XDZ8wNT2uoFwxtCJJ+i92Bqi1wIcM9BhS7vyRep4TXPw8h Ir1LAAbblxzYXtTFC1yHblCk6MM4pPvLLMWSZpuFXst6bJN8gClYW1e1QGm6CHmm ZGIVnYeWRbVmIyADixxzoNOieTPgUFmG2y/lAiXqcyqfABTINseSO+lOAOzYVgm5 M0kS0lQLAausR7aRKX1MtHWAUgHoyoL2n8ysnI8X6i8msKtyrAv+nlEex0NVZ09R s1fWtuzuUrc66U7h14GIvE+OdbtLqPA1qibUZ2dJsnBMO5PcHd94kIZysjik0dyS TclY6ysSXNQ7roxrsIPlAT/4CTL2kzU0Iq/dNw13CYArzUgA8YyZGUcFAenRv9FO 0OYoQzeZpApKCNmacXPSqs0xE2N2oTdvkjgefRI8ZjLny23h/FKJ3crWZgWalmG+ oijHHKOnNlA8OqTfSm7mhzvO6/DggTedEzxSjr25HTTGHdUKaj2YKXCMiSrRq4IQ SB/c9O+lxbtVGjhjhE63bK2VVOxlIhBJF7jAHscPrFRH -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFoTCCA4mgAwIBAgIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTDEZ MBcGA1UEChMQRGlnaWRlbnRpdHkgQi5WLjEkMCIGA1UEAxMbRGlnaWRlbnRpdHkg TDMgUm9vdCBDQSAtIEcyMB4XDTExMDQyOTEwNDQxOVoXDTMxMTExMDEwNDQxOVow TjELMAkGA1UEBhMCTkwxGTAXBgNVBAoTEERpZ2lkZW50aXR5IEIuVi4xJDAiBgNV BAMTG0RpZ2lkZW50aXR5IEwzIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBALgRo0XeAUdWDWK4jrpYZlz6MsZrgG64f/hT337fYqjB V0+aRSXISkUtUzgksyCsT+qt/5oQr3/iDsq0DiQlkc52jhCpL5lTp5BLBItterlB G9MBeYyfQWu5kNeBEhoHltAJr+nkaiFTgLiGnmJoQ62zahX69m0DMmo1sVATSMd6 tSETnASc2pP5aivBpxj99sB+Wfb75w4Rtdwj6hzvZwVXzhfp8Xux0TIkjM9l59S8 NhlwfKInIdaA0i0VT0q14FWQlVGTIYDznEQf/x1VVeTiEBGUFlPQ/q/z75e6RuJ3 W8vWolkRiKbnVUHDkmUdIxRiFH8lciD2pIcpbwf8/uDQGNKX+RSONsboDBiX8XYc 9CTa40r5t0wSGWfz8OFT+13kwHRjXyWRCtk+9DOs5At1X87mmLxUDZ2iMcUVVF0i HIs6VKYN0dcjOqw+qkoXZHYtDftU5euCPDlBQ53hrnlgz2bux3GDewxrCdueok1O RpNot/pn4dq/35GA2qOiia1ebMxLd3Vkb40k44iIC+M/6b+n5VZiDYN/vWphyJCJ eFsMrxIq4pOtZOfZRS72sMirRe5wOG+7NT4W/quew2Yv874JYNVvgL1N26+N/gxg M2sP6J1rxDB3nyxQONCYaew36J4P5GLq+v8RRFTZ782TdZFM4YllppS5U/n5SWPF AgMBAAGjgYkwgYYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFCsjIGC9LYqIR6ytK74CObqY1OyYMEQGA1UdIAQ9MDswOQYEVR0gADAx MC8GCCsGAQUFBwIBFiNodHRwOi8vcGtpLmRpZ2lkZW50aXR5LmV1L3ZhbGlkYXRp ZTANBgkqhkiG9w0BAQsFAAOCAgEAqf3vuo8bfjISZx1BDS2mi8/y9K1WeH4KmNib qNG0SywmrOTSf2c3vQmN5blzETpuCcdXZAchNPgOXSrYkXzxVFG8nPAMakL0PAFO k0VBPazzmEsecR4zWTL/fDDwXOThvi0uterdYiEOPbQNlfzJuNm6oPdip+3DA64I LEHV70NxOLcUcq4/9BR0R9jejFF5zu+xVKxwR5Z+LS7dm+6hAS4Z775YYHEtrZdb WmAwyzKCYk5W5WdqtNIxVHI/AtC8MDmPt0MJKh8mOwzHfB2bgGCEDuku0vkVu1vg iqQA6eMp+yhbvTZFYCFDMf9woV9cg1uXfA23U1nsmLVO4imx1HxG4+jjQ+o6ljUf U/EEFiXjLPNooaaR3xX7vZ/mTp7CVGt+IlfjpJxcIiUfga+ZyN8RFUhD+LMzqSN/ DjOPvEYdQ7Q7YPWXhRmiFrBV3BpwKWXa2X4JFzTribrpYZLY3jRjPEpVar/ahu3O M967U2/PHNqUT3ZUrGVVEFOayLhr3AbmuuVR1UF/H8TAQaFgkTTzE4LRoXfT90zk Gf/XRJqwtbzcyl6P3M7xoGk24ESSLpn6vK+zx3g6VWbHa6XkaSbpNB0fKpcK6Xep d1tzSDKBv//R7IPFcINpnpgbw1ffkZUcgPyN6JaDBdOfeoh7+uhX8cGEKL3N1hzM peJJCnM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ 0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA 7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH 7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDHzCCAgegAwIBAgIEGZk8PzANBgkqhkiG9w0BAQUFADAiMQswCQYDVQQGEwJD TjETMBEGA1UEChMKQ0ZDQSBHVCBDQTAeFw0xMTA2MTMwODE1MDlaFw0yNjA2MDkw ODE1MDlaMCIxCzAJBgNVBAYTAkNOMRMwEQYDVQQKEwpDRkNBIEdUIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv3PGWiuMePZYt/zSF5ClK3TsgSyT zVLMbuQqyyShMeStMG7jmCIx1yGbn9UPNy9auziit3kmZ9YNxRcqnLlUBOENdYZu 2MzFgGcbyIwtACaGPHp5Prapwk4gsDeXxoV2EoIK51S7i/49ruPsa1hD9qU361ii vZDE5fvKa8owbLd7ifYx0oz/T8KWJUOpcTUlCxjhrMijJLZxk4zxXfycEAV7/8Bb 4LGXrR/Y/kX1wB+dW0c5HAb622aF2yQj6nvSOSD46yqyGlHzlFooAk6nXEduz/zZ 6OZhWhYnxxUNmNno0wM1kCnfsi+NEHcjyLh60xFhavP/gZKl7EJLaE6A1wIDAQAB o10wWzAfBgNVHSMEGDAWgBSMdlDOJdN5Kzz0bZ2a4Z4FT+g9JTAMBgNVHRMEBTAD AQH/MAsGA1UdDwQEAwIBxjAdBgNVHQ4EFgQUjHZQziXTeSs89G2dmuGeBU/oPSUw DQYJKoZIhvcNAQEFBQADggEBAL67lljU3YmJDyzN+mNFdg05gJqN+qhFYT0hVejO aMcZ6cKxB8KLOy/PYYWQp1IXMjqvCgUVyMbO3Y6UJgb40GDus27UDbpa3augfFBy ptWQk1bXWTnb6H+zlXhTgVJSX/SSgQLB+yK50QNXp37L+8BGvBN0TCgrdpJpH8FQ kRHFTN4LlIwXg4yvN4e06mtvolo1QWGFL5wXwPu5DqJhBkd2vJAJmHQN0ggvveQN cvGmX8N8wH3qvNOrIJHLXAWMnag1+jZWuwnzhF3W8eIsntl+8YKg4bcvfu35e6AA uLLeHXnhgfNSWZoUXefCEfOawzp4I75OZt6kOWnymDosCgA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBk MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg Q0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2MjUwNzM4MTRaMGQxCzAJBgNVBAYT AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvEr jw0DzpPMLgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r 0rk0X2s682Q2zsKwzxNoysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f 2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJwDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVP ACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpHWrumnf2U5NGKpV+GY3aF y6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1aSgJA/MTA tukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL 6yxSNLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0 uPoTXGiTOmekl9AbmbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrAL acywlKinh/LTSlDcX3KwFnUey7QYYpqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velh k6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3qPyZ7iVNTA6z00yPhOgpD/0Q VAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw FDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqh b97iEoHF8TwuMA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4R fbgZPnm3qKhyN2abGu2sEzsOv2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv /2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ82YqZh6NM4OKb3xuqFp1mrjX2lhI REeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLzo9v/tdhZsnPdTSpx srpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcsa0vv aGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciAT woCqISxxOQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99n Bjx8Oto0QuFmtEYE3saWmA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5W t6NlUe07qxS/TFED6F+KBZvuim6c779o+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N 8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TCrvJcwhbtkj6EPnNgiLx2 9CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX5OfNeOI5 wSsSnqaeG8XmDtkx2Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAw ZzELMAkGA1UEBhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdp dGFsIENlcnRpZmljYXRlIFNlcnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290 IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcNMzEwNjI1MDg0NTA4WjBnMQswCQYD VQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2Vy dGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYgQ0Eg MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7Bx UglgRCgzo3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD 1ycfMQ4jFrclyxy0uYAyXhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPH oCE2G3pXKSinLr9xJZDzRINpUKTk4RtiGZQJo/PDvO/0vezbE53PnUgJUmfANykR HvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8LiqG12W0OfvrSdsyaGOx9/ 5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaHZa0zKcQv idm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHL OdAGalNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaC NYGu+HuB5ur+rPQam3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f 46Fq9mDU5zXNysRojddxyNMkM3OxbPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCB UWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDixzgHcgplwLa7JSnaFp6LNYth 7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/BAQDAgGGMB0G A1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWB bj2ITY1x0kbBbkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6x XCX5145v9Ydkn+0UjrgEjihLj6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98T PLr+flaYC/NUn81ETm484T4VvwYmneTwkLbUwp4wLh/vx3rEUMfqe9pQy3omywC0 Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7XwgiG/W9mR4U9s70 WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH59yL Gn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm 7JFe3VE/23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4S nr8PyQUQ3nqjsTzyP6WqJ3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VN vBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyAHmBR3NdUIR7KYndP+tiPsys6DXhyyWhB WkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/giuMod89a2GQ+fYWVq6nTI fI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuWl8PVP3wb I+2ksx0WckNLIOFZfsLorSa/ovc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ 4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwzCCA6ugAwIBAgISESGFDLOcajL6vmcbgT+khhWPMA0GCSqGSIb3DQEBCwUA MF4xCzAJBgNVBAYTAkZSMQ4wDAYDVQQKEwVBTlNTSTEXMBUGA1UECxMOMDAwMiAx MzAwMDc2NjkxJjAkBgNVBAMTHUlHQy9BIEFDIHJhY2luZSBFdGF0IGZyYW5jYWlz MB4XDTExMDcwODA5MDAwMFoXDTI4MDQxNTA5MDAwMFowXjELMAkGA1UEBhMCRlIx DjAMBgNVBAoTBUFOU1NJMRcwFQYDVQQLEw4wMDAyIDEzMDAwNzY2OTEmMCQGA1UE AxMdSUdDL0EgQUMgcmFjaW5lIEV0YXQgZnJhbmNhaXMwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCqfCifETCYzW9uLIUSJjsIBspB/VJPQ73AJidxdhpZ ltgJ6weqJk5PPkuh45eHhWaBccm5FXZvd1AYkxAtN4hNF7fzRb0iLrcnmFvHBf29 M+2i9VMdKCNlv0A1bs5qC8Op9SUMqyLwuMDEfTcMo2J87rTbPSE5p5yJ45uiEPiK tkovLphpK2qghtrxCOW+TGcWLSVh89UNCxdERwnURgWdD8CITWHkJMTHaAmvrNKv uZUmb4AE/HasqscjtuQGkVVE7GTbmYEc0lZ0/dYyKLvLyTcN+2lsb7qjawaMakAu Fzo56tAM31ocum+kMrC4zD53G9OLH4b6/z4+b1yIRufjD/qrHfN9S/hUbk7M3DJa Y3iiMq8zeOpD4Ux6TdeUBi3mT6VCkq8oik/DFeypa6nf4N0TArzMff8t5gepvnWW 6kJeWxreojOzY72rBfmL5r1N0W1WmuuJPJ/AeOS+JXAGxRFzoMjKFMs61PKcKjza Xxcz2XYUN6pJh2XZ9NkuGV/5oM2ouUEybXGmpMv3YyLQKeS6gRpqKR2apaRcRlQk RdTI7Xp5heyEd25nTWQPQ956g6Sn2Nu1U0z+YsgTw2I2pSgxMpu0lofimcYfVr9G o6lkMeXVsUuoZsxbof8W/Ao4KmiPdyUmrZF0hWjIfxrlWhS4fQ63IzHAZLcFL0FY VQIDAQABo3sweTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNV HSAEDzANMAsGCSqBegGBXwEBAjAdBgNVHQ4EFgQUn6rTKZbfAOVD4PFjrN4SjsIn ePowHwYDVR0jBBgwFoAUn6rTKZbfAOVD4PFjrN4SjsInePowDQYJKoZIhvcNAQEL BQADggIBAHW1ddGONmacSPeFDU4Fu02anLQOKKIEvFAwu/SUTJiQhavgUmRP0tIu YpOQsIUNiFT7xlRsnuuVeYBeopcWH/JndEGcVfS3aptKFoa9BR9mgHB+ydH1LSFx UDmlrYimJhyL1yUcOtbj9MIMn1fBZMhXUSMWI40PI2pWS//6xp81k8YiwGXxr96p bBi+V2VZzfQjVWQh2O2VYWkzcmpR9p/llW2O3mtzJxOUXn6XSMAyFr49N+3W3I68 XC38YqjP9pD3sYsJ6zokYw3IlkXUL3dIQvUtYucnC+ARhhndpxD3YwaRMGladfSs +aGNl8ag7zofkyVIVjoaiCEZk8OVIEkIVUlNolOcmZxzaS6n9cq3DiXvNyNfkNhD fu6EF2onXn/SLT+sPq8wp42RxPSPCR3z95EO4xi63ETJfQVTA7duoPN519EaT9C4 bIh2wYCYVYVTYc9EV0zeTg0WUfE9iYGufQutirXuVsTGzBELGNT8/Xn7/gQRnCPv dnLHjb65Hnh28pocrWNCx9jtbWGQwiEqDwgULSBDJXwYtbegpH25pQwZ/smrPedb 3q/6VxknhecjDvTNDRkwPorkxhEe8LR9aWObDpaGkOD7A29bWT4dIfVXZ1Ym8ocZ B4S6LJA6wyikBVogzalblXU5fyJQCk5/F/ezrNMHpr4tUgowTHgQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGATCCA+mgAwIBAgIRAI9hcRW6eVgXjH0ROqzW264wDQYJKoZIhvcNAQELBQAw RTEfMB0GA1UEAxMWQ29tU2lnbiBHbG9iYWwgUm9vdCBDQTEVMBMGA1UEChMMQ29t U2lnbiBMdGQuMQswCQYDVQQGEwJJTDAeFw0xMTA3MTgxMDI0NTRaFw0zNjA3MTYx MDI0NTVaMEUxHzAdBgNVBAMTFkNvbVNpZ24gR2xvYmFsIFJvb3QgQ0ExFTATBgNV BAoTDENvbVNpZ24gTHRkLjELMAkGA1UEBhMCSUwwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCyKClzKh3rm6n1nvigmV/VU1D4hSwYW2ro3VqpzpPo0Ph3 3LguqjXd5juDwN4mpxTpD99d7Xu5X6KGTlMVtfN+bTbA4t3x7DU0Zqn0BE5XuOgs 3GLH41Vmr5wox1bShVpM+IsjcN4E/hMnDtt/Bkb5s33xCG+ohz5dlq0gA9qfr/g4 O9lkHZXTCeYrmVzd/il4x79CqNvGkdL3um+OKYl8rg1dPtD8UsytMaDgBAopKR+W igc16QJzCbvcinlETlrzP/Ny76BWPnAQgaYBULax/Q5thVU+N3sEOKp6uviTdD+X O6i96gARU4H0xxPFI75PK/YdHrHjfjQevXl4J37FJfPMSHAbgPBhHC+qn/014DOx 46fEGXcdw2BFeIIIwbj2GH70VyJWmuk/xLMCHHpJ/nIF8w25BQtkPpkwESL6esaU b1CyB4Vgjyf16/0nRiCAKAyC/DY/Yh+rDWtXK8c6QkXD2XamrVJo43DVNFqGZzbf 5bsUXqiVDOz71AxqqK+p4ek9374xPNMJ2rB5MLPAPycwI0bUuLHhLy6nAIFHLhut TNI+6Y/soYpi5JSaEjcY7pxI8WIkUAzr2r+6UoT0vAdyOt7nt1y8844a7szo/aKf woziHl2O1w6ZXUC30K+ptXVaOiW79pBDcbLZ9ZdbONhS7Ea3iH4HJNwktrBJLQID AQABo4HrMIHoMA8GA1UdEwEB/wQFMAMBAf8wgYQGA1UdHwR9MHswPKA6oDiGNmh0 dHA6Ly9mZWRpci5jb21zaWduLmNvLmlsL2NybC9jb21zaWduZ2xvYmFscm9vdGNh LmNybDA7oDmgN4Y1aHR0cDovL2NybDEuY29tc2lnbi5jby5pbC9jcmwvY29tc2ln bmdsb2JhbHJvb3RjYS5jcmwwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBQCRZPY DUhirGm6rgZbPvuqJpFQsTAfBgNVHSMEGDAWgBQCRZPYDUhirGm6rgZbPvuqJpFQ sTANBgkqhkiG9w0BAQsFAAOCAgEAk1V5V9701xsfy4mfX+tP9Ln5e9h3N+QMwUfj kr+k3e8iXOqADjTpUHeBkEee5tJq09ZLp/43F5tZ2eHdYq2ZEX7iWHCnOQet6Yw9 SU1TahsrGDA6JJD9sdPFnNZooGsU1520e0zNB0dNWwxrWAmu4RsBxvEpWCJbvzQL dOfyX85RWwli81OiVMBc5XvJ1mxsIIqli45oRynKtsWP7E+b0ISJ1n+XFLdQo/Nm WA/5sDfT0F5YPzWdZymudMbXitimxC+n4oQE4mbQ4Zm718Iwg3pP9gMMcSc7Qc1J kJHPH9O7gVubkKHuSYj9T3Ym6c6egL1pb4pz/uT7cT26Fiopc/jdqbe2EAfoJZkv hlp/zdzOoXTWjiKNA5zmgWnZn943FuE9KMRyKtyi/ezJXCh8ypnqLIKxeFfZl69C BwJsPXUTuqj8Fic0s3aZmmr7C4jXycP+Q8V+akMEIoHAxcd960b4wVWKqOcI/kZS Q0cYqWOY1LNjznRt9lweWEfwDBL3FhrHOmD4++1N3FkkM4W+Q1b2WOL24clDMj+i 2n9Iw0lc1llHMSMvA5D0vpsXZpOgcCVahfXczQKi9wQ3oZyonJeWx4/rXdMtagAB VBYGFuMEUEQtybI+eIbnp5peO2WAAblQI4eTy/jMVowe5tfMEXovV3sz9ULgmGb3 DscLP1I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXTCCAkWgAwIBAgIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJLUjEc MBoGA1UECgwTR292ZXJubWVudCBvZiBLb3JlYTENMAsGA1UECwwER1BLSTEUMBIG A1UEAwwLR1BLSVJvb3RDQTEwHhcNMTEwODAzMDY1MjMwWhcNMzEwODAzMDY1MjMw WjBQMQswCQYDVQQGEwJLUjEcMBoGA1UECgwTR292ZXJubWVudCBvZiBLb3JlYTEN MAsGA1UECwwER1BLSTEUMBIGA1UEAwwLR1BLSVJvb3RDQTEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCh/m8EBbDJhGQyN2+g5dTlsgjtaRKqhgj3gkYK BgtuXsXkaTVxbf99AvbN3QE8+WCIaPJUd0091UGmLzaBVyW4ct+iUNrX/FXyzjaf bNbbl1nfHhaZhkiOTVQhmY5zuj96evEtJMevnxe6iRADOPWnqp+CxT2IzcSFkQCq 7L2qn8hU2/LpXUvnAYglJZi8t6Ef+r03P1r8dA5OzZ8yV3qhD1R1wsNQtCzMgwcE rFRZhFZYuxpfmS5y0fZW0seeTjcdxHiR3whYI5U6AI7DjdWIrT9Cd9ByV4aevkBh qkePPIYGmUPXnnqCkdHdnzkMH0WP9TBhD2jTXZKdcFtTyEJrAgMBAAGjQjBAMB0G A1UdDgQWBBR4A+sMjKbTVXWkh7Tr0ZpmD0xzizAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEARGJWATwo81x7UEQugNbi cL8IWXoV51SZVH3kz49fNUjVoq1n2yzfaMddlblbflDNObp/68DxTlSXCeqFHkgi /WvyVHERRECXnF0WeeelI+Q8XdF3IJZLT3u5Ss0VAB2loCuC+4hBWSRQu2WZu2Yk s9eBN0x6NmtopRmnf2d6VrcFA+WOgUeTjXiDkG52IaPw0w1uTfmRw5epky5idyY2 bfJ1JeVUINMJnOWpgLkOH3xxakoD8F1Fbi6C3t7MmKupojUq/toUDms6zTk3DIkc wd7PALNWL5U8TxNLoroTHSf/lzaOv3o9KDRa0FQo58bPI7MdbRWE4F3mS/ZIrnv7 jQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGMjCCBBqgAwIBAgIQWMv5ZJZxdJVA9K0IrGTk4zANBgkqhkiG9w0BAQsFADBz MQswCQYDVQQGEwJJTDEYMBYGA1UECgwPUGVyc29uYWxJRCBMdGQuMR0wGwYDVQQL DBRDZXJ0aWZpY2F0ZSBTZXJ2aWNlczErMCkGA1UEAwwiUGVyc29uYWxJRCBUcnVz dHdvcnRoeSBSb290Q0EgMjAxMTAeFw0xMTA5MDEwODM1MjFaFw00MTA5MDEwODQ1 MTZaMHMxCzAJBgNVBAYTAklMMRgwFgYDVQQKDA9QZXJzb25hbElEIEx0ZC4xHTAb BgNVBAsMFENlcnRpZmljYXRlIFNlcnZpY2VzMSswKQYDVQQDDCJQZXJzb25hbElE IFRydXN0d29ydGh5IFJvb3RDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAsJWMYP4FDmoz7feL4/LV8nzTVkJU9yvyiKX157dshwErab4FSUTY 2yF6KteKMaEhEJ7T4m5jgoVUhE0oJhviE/dR+y/rEtU9OYxkn6QTh8PYyfopI44J j0lGxNTJV1hpnxfPc3Sl7soYucfBMM1POjUIU/jsGvtvMO32nwnw8NDEjjt5Ti6F IlzUfXDR/5K6H9RVU2e6KFgt9xOM/KULnDimRhwO6Kp4K/UKMNM7YIbIf6WbomMB L9DTEiWFfpbNMbHkm47qLJOkYqg31faP3yGa0z4d4VARcFSbBBedTathzo8qLO95 5ndFWdZo1bZLmquRSw5hF7lYwp5moY+JwUMgQrB/gJxKKrd6IEHGTcSSb3p+XVu5 o8lOyuVQZbwAAHlH8EUEsCL7DpiqYR1PYGNyj7WwBJR/EKwZPydiadYcV905Tzjq AJr9KJ1AJsBAncSgSchBtWc9oEuUKRKpWCdZBH+P0Yx+DLMIFzSsj7lcvelwoX7C pWVh6bYQUI/c5HRh8V9ye39cLy18q9ZDMRAcWXfKSEoYomQLAFlnx9TKw5saCFIV vtfFxrcv5mKcpsfY3vAV+645VS1vUHUu/aAHtF96fgSL9pmide3JO9U9z2dSPT7v H3CaGDynIAZJDLFlrDO71H9HaYj2ioHundS0xy8D6K4ayVYFZ2moyIECAwEAAaOB wTCBvjALBgNVHQ8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQU x38LyC9Xjiny9gGL6yelVo79pB4wEAYJKwYBBAGCNxUBBAMCAQAwagYDVR0gBGMw YTBfBggrBgEEAeEYATBTMFEGCCsGAQUFBwIBFkVodHRwOi8vd3d3LmljYS5jby5p bC9yZXBvc2l0b3J5L2Nwcy9QZXJzb25hbElEX1ByYWN0aWNlX1N0YXRlbWVudC5w ZGYwDQYJKoZIhvcNAQELBQADggIBAEJliyT6khU0Ghz6yM5Nei9739ADQRzUpOH7 6MytCd0dpAjZqCB9l58MSfGlwubVd0aXfqSQonnpvRpeNIJmCVL8UNGP0Kscov// Pe7+I/i/I7PNvuH3z+TYEuOUyE7M13uwN5t36u1cgcjMj8454+RlXd6C2I8jaeFR r1+3T5BppJllU7rm/a94Z5RKyMN/jAJPSuaHmPY4t0j4bSh/98ZsJVT9Ltbq2gbi sf0HaPCvgIy0wul0FaQav7nKQ1sS54VHXlID8JHg6VBx1CECLHuGkXA2xpy2dPkq Vfch+2+gBl3XMBLyUfHJODaPyGZhQdnHS4JoUqP1iQwVvE4qlawxaacb4tTXSPSR 9QN8eRY+LA1p4Yo3Hp98GFVBL1/npHKbVfPjAbACpYQSakCmq+ShrOsD2bxfJFYn rSDgZjVFPUcJ8AWxb3F+QLDQFV4rrFKBqPuD9SxXRIY05BRq4899mnfYbEhcy5rh pvu/EaIG5R9xvTS1z73EQhbFKfjUwEyKst7FlIKGm8zgqQZEMSQkTfrt4UIlZqLB 14AX73qVZUM+ZtMF8QHkQlZEAHhrnTYg+2X/QFzoaDUf4SagggN2A8twRhEkrt8v YP3xJwADvUsn27yclzdRK+V4tME2kBCM/z0A1LpIn0jKhzGa7cSaU9LdcxQ/CYKh XWVOTSbi -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX 4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ 51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICqDCCAi2gAwIBAgIQIW4zpcvTiKRvKQe0JzzE2DAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAxIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAATXZrUb266zYO5G6ohjdTsqlG3zXxL24w+etgoUU0hS yNw6s8tIICYSTvqJhNTfkeQpfSgB2dsYQ2mhH7XThhbcx39nI9/fMTGDAzVwsUu3 yBe7UcvclBfb6gk7dhLeqrWjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRlwI0l9Qy6l3eQP54u4Fr1ztXh5DAKBggqhkjOPQQD AwNpADBmAjEApa7jRlP4mDbjIvouKEkN7jB+M/PsP3FezFWJeJmssv3cHFwzjim5 axfIEWi13IMHAjEAnMhE2mnCNsNUGRCFAtqdR+9B52wmnQk9922Q0QVEL7C8g5No 8gxFSTm/mQQc0xCg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICqDCCAi2gAwIBAgIQNBdlEkA7t1aALYDLeVWmHjAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAyIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAATR2UqOTA2ESlG6fO/TzPo6mrWnYxM9AeBJPvrBR8mS szrX/m+c95o6D/UOCgrDP8jnEhSO1dVtmCyzcTIK6yq99tdqIAtnRZzSsr9TImYJ XdsR8/EFM1ij4rjPfM2Cm72jQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBQ9MvM6qQyQhPmijGkGYVQvh3L+BTAKBggqhkjOPQQD AwNpADBmAjEAyKapr0F/tckRQhZoaUxcuCcYtpjxwH+QbYfTjEYX8D5P/OqwCMR6 S7wIL8fip29lAjEA1lnehs5fDspU1cbQFQ78i5Ry1I4AWFPPfrFLDeVQhuuea9// KabYR9mglhjb8kWz -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0zCCA7ugAwIBAgIVALhZFHE/V9+PMcAzPdLWGXojF7TrMA0GCSqGSIb3DQEB DQUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dp ZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBIDIwHhcNMTExMDA2 MDgzOTU2WhcNNDYxMDA2MDgzOTU2WjCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoT GVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0 d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvfl4+ObV gAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC5SBLm9qbe7mZXdmbgEvXhEAr J9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Vaqp3cKcniNQfrcE1K1sGzVrih QTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ0WeNG0a+RzDVLnLRxWPa52N5 RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet/5oCl8HGUJKbAiy9qbk0WQq/ hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNeGWJoRVfkkIJCu0LW8GHgwaM9 ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcVWiNoidQ+3k4nsPBADLxNF8tN orMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbls+V1e9dBkQXcXWnjlQ1DufyD ljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZbMI28iQzV13D4h1L92u+sUS4H s07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+NqcnoYsylfzGuXIkosagpZ6w7xQ EmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbljnX98sy50IdbzAYQYLuDNbde Z95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUtqFUOQLDoD+Oirz61PgcptE6Dv0wDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBDQUAA4ICAQCdU8KBJdw1LK4K3VqbRjBWu9S0bEuG5gql 0pKKmo3cj7TudvQDy+ubAXirKmu1uiNOMXy1LN0taWczbmNdORgS+KAoU0SHq2rE kpYfKqIcup3dJ/tSTbCPWujtjcNo45KgJgyHkLAD6mplKAjERnjgW7oO8DPcJ7Z+ iD29kqSWfkGogAh71jYSvBAVmyS8q619EYkvMe340s9Tjuu0U6fnBMovpiLEEdzr mMkiXUFq3ApSBFu8LqB9x7aSuySg8zfRK0OozPFoeBp+b2OQe590yGvZC1X2eQM9 g8dBQJL7dgs3JRc8rz76PFwbhvlKDD+KxF4OmPGt7s/g/SE1xzNhzKI3GEN8M+mu doKCB0VIO8lnbq2jheiWVs+8u/qry7dXJ40aL5nzIzM0jspTY9NXNFBPz0nBBbrF qId744aP+0OiEumsUewEdkzw+o+5MRPpCLckCfmgtwc2WFfPxLt+SWaVNQS2dzW4 qVMpX5KF+FLEWk79BmE5+33QdkeSzOwrvYRu5ptFwX1isVMtnnWg58koUNflvKiq B3hquXS0YPOEjQPcrpHadEQNe0Kpd9YrfKHGbBNTIqkSmqX5TyhFNbCXT0ZlhcX0 /WKiomr8NDAGft8M4HOBlslEKt4fguxscletKWSk8cYpjjVgU85r2QK+OTB14Pdc Y2rwQMEsjQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn 0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n 3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P 5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi DrW5viSP -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5DCCA8ygAwIBAgIBATANBgkqhkiG9w0BAQsFADB/MQswCQYDVQQGEwJteTEL MAkGA1UECgwCVE0xNDAyBgNVBAsMK1RNIEFwcGxpZWQgQnVzaW5lc3MgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkxLTArBgNVBAMMJFRNIEFwcGxpZWQgQnVzaW5lc3Mg Um9vdCBDZXJ0aWZpY2F0ZTAeFw0xMTEwMTAwNjIzMzlaFw0zMTEwMTAwNjUzMzla MH8xCzAJBgNVBAYTAm15MQswCQYDVQQKDAJUTTE0MDIGA1UECwwrVE0gQXBwbGll ZCBCdXNpbmVzcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEtMCsGA1UEAwwkVE0g QXBwbGllZCBCdXNpbmVzcyBSb290IENlcnRpZmljYXRlMIIBIDANBgkqhkiG9w0B AQEFAAOCAQ0AMIIBCAKCAQEAxbd1GV7r9EIJjbFqbG4ydqQFBw+PK2Q672vHtxtX WiUzwGEYo4IdgHft7RxkskC6yMJVtV+Owt2RbvPF56M5m0wvfqPm948VXH0bWrqW lpOgYXIgRIgnq0FHdz5eMKWLNegwRqBY6k4CbT1iDTnzZK5m7twSfhlL0b/CgkT6 +deZSOyzDPRiZzWbnUZoR5emIl4TVgALUfX7ZF9b4L/yb+9F1K7Gr9ycH+0UHbKm 7wc45wh3Nqq5qDw5GuWRaKqQjsGYGeTqbYWTGwbm3FELoQDsxK5ypxxpEXI+3M7z OFfXGhpXFE2LUHZFVXMwI29Lr0pIQpNCX/nx2jlcBtUPyQIBA6OCAWswggFnMIGr BgNVHSMEgaMwgaCAFEAa+7SWN5aD3yw7FO0cxsveIG0IoYGEpIGBMH8xCzAJBgNV BAYTAm15MQswCQYDVQQKDAJUTTE0MDIGA1UECwwrVE0gQXBwbGllZCBCdXNpbmVz cyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEtMCsGA1UEAwwkVE0gQXBwbGllZCBC dXNpbmVzcyBSb290IENlcnRpZmljYXRlggEBMB0GA1UdDgQWBBRAGvu0ljeWg98s OxTtHMbL3iBtCDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zB3BgNV HR8EcDBuMGygaqBohmZsZGFwOi8vbGRhcC50bWNhLmNvbS5teTozODkvY249YXJs MWRwMSxvdT1BUkwsb3U9VE0gQXBwbGllZCBCdXNpbmVzcyBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eSxvPVRNLGM9bXkwDQYJKoZIhvcNAQELBQADggEBAECJXpdECqtm MStt3E6m5y2xR/9SefPt26eB6To8VWf1RdHuGXn9N+CupCiiGDjez9KXkqQ5vFSD 7x2hgWfIjCZlhrrKbwBCWE26GWa3G0BRJZLQghWIbGIy4vFAEt2+wO8Q8iaEJfX0 ag9ZPyMZHb0NvDk6vNrcbj8OjCaRJDPM/TM5jF2iu0eX5xAqhCZUsSt+X/mqf+3H /sojplW/38pe4Ps+p1LWKjqle2PyhfwhNCvBrvBBkBg/RcQjjbw7ht2qRmdphyGi Vxamp3w7/okgRxj61XL9XDpotTvhPMIrS3hTVVqy9oa+wD3bSP/wwHoQ1B7f5LYu whrUDnpqoHY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9jCCAt6gAwIBAgIQJDJ18h0v0gkz97RqytDzmDANBgkqhkiG9w0BAQsFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAx IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHOddJZKmZgiJM6kXZBxbje/SD 6Jlz+muxNuCad6BAwoGNAcfMjL2Pffd543pMA03Z+/2HOCgs3ZqLVAjbZ/sbjP4o ki++t7JIp4Gh2F6Iw8w5QEFa0dzl2hCfL9oBTf0uRnz5LicKaTfukaMbasxEvxvH w9QRslBglwm9LiL1QYRmn81ApqkAgMEflZKf3vNI79sdd2H8f9/ulqRy0LY+/3gn r8uSFWkI22MQ4uaXrG7crPaizh5HmbmJtxLmodTNWRFnw2+F2EJOKL5ZVVkElauP N4C/DfD8HzpkMViBeNfiNfYgPym4jxZuPkjctUwH4fIa6n4KedaovetdhitNAgMB AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBQzQejIORIVk0jyljIuWvXalF9TYDANBgkqhkiG9w0BAQsFAAOCAQEAFeNzV7EX tl9JaUSm9l56Z6zS3nVJq/4lVcc6yUQVEG6/MWvL2QeTfxyFYwDjMhLgzMv7OWyP 4lPiPEAz2aSMR+atWPuJr+PehilWNCxFuBL6RIluLRQlKCQBZdbqUqwFblYSCT3Q dPTXvQbKqDqNVkL6jXI+dPEDct+HG14OelWWLDi3mIXNTTNEyZSPWjEwN0ujOhKz 5zbRIWhLLTjmU64cJVYIVgNnhJ3Gw84kYsdMNs+wBkS39V8C3dlU6S+QTnrIToNA DJqXPDe/v+z28LSFdyjBC8hnghAXOKK3Buqbvzr46SMHv3TgmDgVVXjucgBcGaP0 0jPg/73RVDkpDw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9jCCAt6gAwIBAgIQZIKe/DcedF38l/+XyLH/QTANBgkqhkiG9w0BAQsFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAy IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNzOkFyGOFyz9AYxe9GPo15gRn V2WYKaRPyVyPDzTS+NqoE2KquB5QZ3iwFkygOakVeq7t0qLA8JA3KRgmXOgNPLZs ST/B4NzZS7YUGQum05bh1gnjGSYc+R9lS/kaQxwAg9bQqkmi1NvmYji6UBRDbfkx +FYW2TgCkc/rbN27OU6Z4TBnRfHU8I3D3/7yOAchfQBeVkSz5GC9kSucq1sEcg+y KNlyqwUgQiWpWwNqIBDMMfAr2jUs0Pual07wgksr2F82owstr2MNHSV/oW5cYqGN KD6h/Bwg+AEvulWaEbAZ0shQeWsOagXXqgQ2sqPy4V93p3ec5R7c6d9qwWVdAgMB AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBSHjCCVyJhK0daABkqQNETfHE2/sDANBgkqhkiG9w0BAQsFAAOCAQEAgY6ypWaW tyGltu9vI1pf24HFQqV4wWn99DzX+VxrcHIa/FqXTQCAiIiCisNxDY7FiZss7Y0L 0nJU9X3UXENX6fOupQIR9nYrgVfdfdp0MP1UR/bgFm6mtApI5ud1Bw8pGTnOefS2 bMVfmdUfS/rfbSw8DVSAcPCIC4DPxmiiuB1w2XaM/O6lyc+tHc+ZJVdaYkXLFmu9 Sc2lo4xpeSWuuExsi0BmSxY/zwIa3eFsawdhanYVKZl/G92IgMG/tY9zxaaWI4Sm KIYkM2oBLldzJbZev4/mHWGoQClnHYebHX+bn5nNMdZUvmK7OaxoEkiRIKXLsd3+ b/xa5IJVWa8xqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDcTCCAlmgAwIBAgIVAOYJ/nrqAGiM4CS07SAbH+9StETRMA0GCSqGSIb3DQEB BQUAMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGlj emVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIgUk9PVCBDQTAeFw0xMTEyMDYx MTEwNTdaFw0zMTEyMDYxMTEwNTdaMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIg Uk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxHL49ZMTml 6g3wpYwrvQKkvc0Kc6oJ5sxfgmp1qZfluwbv88BdocHSiXlY8NzrVYzuWBp7J/9K ULMAoWoTIzOQ6C9TNm4YbA9A1jdX1wYNL5Akylf8W5L/I4BXhT9KnlI6x+a7BVAm nr/Ttl+utT/Asms2fRfEsF2vZPMxH4UFqOAhFjxTkmJWf2Cu4nvRQJHcttB+cEAo ag/hERt/+tzo4URz6x6r19toYmxx4FjjBkUhWQw1X21re//Hof2+0YgiwYT84zLb eqDqCOMOXxvH480yGDkh/QoazWX3U75HQExT/iJlwnu7I1V6HXztKIwCBjsxffbH 3jOshCJtywcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFFOSo33/gnbwM9TrkmdHYTMbaDsqMA0GCSqGSIb3DQEBBQUA A4IBAQA5UFWd5EL/pBviIMm1zD2JLUCpp0mJG7JkwznIOzawhGmFFaxGoxAhQBEg haP+E0KR66oAwVC6xe32QUVSHfWqWndzbODzLB8yj7WAR0cDM45ZngSBPBuFE3Wu GLJX9g100ETfIX+4YBR/4NR/uvTnpnd9ete7Whl0ZfY94yuu4xQqB5QFv+P7IXXV lTOjkjuGXEcyQAjQzbFaT9vIABSbeCXWBbjvOXukJy6WgAiclzGNSYprre8Ryydd fmjW9HIGwsIO03EldivvqEYL1Hv1w/Pur+6FUEOaL68PEIUovfgwIB2BAw+vZDuw cH0mX548PojGyg434cDjkSXa3mHF -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD 75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp 5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p 6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI l7WdmplNsDz4SgCbZN2fOUvRJ9e4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh 4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc 3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz 8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l 7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE +V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR /xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP 0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf 3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl 8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEBDCCAuygAwIBAgIIGHqpqMKWIQwwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEy MDIwMTIyMTIxNVoXDTI3MDIwMTIyMTIxNVoweTEtMCsGA1UEAwwkRGV2ZWxvcGVy IElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQLDB1BcHBsZSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UE BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJdk8GW5pB7qUj KwKjX9dzP8A1sIuECj8GJH+nlT/rTw6Tr7QO0Mg+5W0Ysx/oiUe/1wkI5P9WmCkV 55SduTWjCs20wOHiYPTK7Cl4RWlpYGtfipL8niPmOsIiszFPHLrytjRZQu6wqQID GJEEtrN4LjMfgEUNRW+7Dlpbfzrn2AjXCw4ybfuGNuRsq8QRinCEJqqfRNHxuMZ7 lBebSPcLWBa6I8WfFTl+yl3DMl8P4FJ/QOq+rAhklVvJGpzlgMofakQcbD7EsCYf Hex7r16gaj1HqVgSMT8gdihtHRywwk4RaSaLy9bQEYLJTg/xVnTQ2QhLZniiq6yn 4tJMh1nJAgMBAAGjgaYwgaMwHQYDVR0OBBYEFFcX7aLP3HyYoRDg/L6HLSzy4xdU MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/ CF4wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5j cmwwDgYDVR0PAQH/BAQDAgGGMBAGCiqGSIb3Y2QGAgYEAgUAMA0GCSqGSIb3DQEB CwUAA4IBAQBCOXRrodzGpI83KoyzHQpEvJUsf7xZuKxh+weQkjK51L87wVA5akR0 ouxbH3Dlqt1LbBwjcS1f0cWTvu6binBlgp0W4xoQF4ktqM39DHhYSQwofzPuAHob tHastrW7T9+oG53IGZdKC1ZnL8I+trPEgzrwd210xC4jUe6apQNvYPSlSKcGwrta 4h8fRkV+5Jf1JxC3ICJyb3LaxlB1xT0lj12jAOmfNoxIOY+zO+qQgC6VmmD0eM70 DgpTPqL6T9geroSVjTK8Vk2J6XgY4KyaQrp6RhuEoonOFOiI0ViL9q5WxCwFKkWv C9lLqQIPNKyIx2FViUTJJ3MH7oLlTvVw -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDHjCCAgagAwIBAgIDB7HTMA0GCSqGSIb3DQEBDQUAMDcxCzAJBgNVBAYTAlNJ MQ8wDQYDVQQKEwZIYWxjb20xFzAVBgNVBAMTDkhhbGNvbSBSb290IENBMB4XDTEy MDIwODA5NTU0MVoXDTMyMDIwODA5NTU0MVowNzELMAkGA1UEBhMCU0kxDzANBgNV BAoTBkhhbGNvbTEXMBUGA1UEAxMOSGFsY29tIFJvb3QgQ0EwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCJuYXK/vR1fX/snUI3urqNvOw9FwP92UVl1s3J Tl+MSFyXCFcUiy2cPJBJmc9pr0mN2xwBsG7p9OqRZ13Ks2lP2MzBDT3uqgN24Mlw op/+65vQtsmW0/D7W9DwB6tMXk2k4kdeBWh0po4iR+5+02eEVDeSRw7zo+wVGvNt e78ZNSGPgkusVJwJzW62wVe90Ek9b59zjrFsfr3+1rs9A+jmTBq07q+0g04ykFT2 ThvhL86lNBqOoyD52T4ia29u4/rZM1wIoPcVAD2cEJJKVc2Asgaq/dePt1qSJyQP MzwouvEfaLV3KV6uwtqNNnDiejIbI6bexWENmqUSILXzllm1AgMBAAGjMzAxMA8G A1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECE6U2Ipjws95MAsGA1UdDwQEAwIBBjAN BgkqhkiG9w0BAQ0FAAOCAQEAKb7nseT6A6IPr3ZZnfhOU008BIOfoeKM9pTZtK5o KlZrMlMogwdyTLBOqB2BgyFnAzfRjMbBToTpNDvT9fUnto0jBVK4TDLyLtrRKn0+ gwMq0rHjmumKg0LwLAqhUw/AK+KPGk6VuUW8S2c6vTLzraWPj8Mu6vb0e2LQbm7F YTETZuZnSZk7L4BPenxzigMNX/WzMigKisDh+bijJu7cG1fPdhpPU772SotXFysv mYaq3ozatqhs32g21mGLbsBzTrc5RfR9zknE8x35qXds7++SFRMnmUbon6mKG58p L6IdPtYrx+RVEDoY97N7Ty7HACLt5DHQ57jkVE/BgEUlbg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDvTCCAqWgAwIBAgIQD2tVL56/kHsPZimpvfTYzjANBgkqhkiG9w0BAQsFADBk MQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xNjA0 BgNVBAMTLVN5bWFudGVjIEVudGVycHJpc2UgTW9iaWxlIFJvb3QgZm9yIE1pY3Jv c29mdDAeFw0xMjAzMTUwMDAwMDBaFw0zMjAzMTQyMzU5NTlaMGQxCzAJBgNVBAYT AlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjE2MDQGA1UEAxMtU3lt YW50ZWMgRW50ZXJwcmlzZSBNb2JpbGUgUm9vdCBmb3IgTWljcm9zb2Z0MIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtT2wcu6R6aVpnBFNevmz+j3ylJsj t6YD7GIY/IUSIv7BcX1Uk7mRfWL2yqg4FWX4dz3lgiA61LXRbo0GSb3fgg4khefv eC0Y8uALaEY+JBDIV+4ObXGm07FWHNcp1bLqVAUKqDyhuCVSBwWg3+fc7lw7QbWr XDMy0s7r6Zb4QPQKujMd+FYDCYL1ZwfEwDTBXfxFu+o8mtV0cW3VhtPC/IW8VOuj 1fJP1UWvV7zwIsCPokXIdTR33qFtN3Kzc40Ma1O6WeGoPoBX0l9Z7mh1z4Gco8pF jDfbBXI0HDIC+NX5LA3aWJ7EF7SbyZDEiFk/cZGQRBi+Iot5ki5CsIuXWwIDAQAB o2swaTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAnBgNVHREEIDAe pBwwGjEYMBYGA1UEAxMPTVBLSS0yMDQ4LTEtMTExMB0GA1UdDgQWBBRN7N8mBtwk EMC2mfTXOcdvGfgmKDANBgkqhkiG9w0BAQsFAAOCAQEAqVdZ0AFUFEavx3lUDGoq W9g6HYHkiKMxtPHzNfFGc1xDyf68omoZwL0vX8s4o21u6BRe8nh+RXrhu/Qum0Xr 4B1QHDRbf5iKhg+H2uRkJnf8Cd8jQU8On/oO+kSF8CmXpJTi9EAtkRx29Khg3nGm sAXiT2nZGQuJOuD6qyv68bMy7fx8cGVe0HsRe53oWxpKdqR7UTmsfakMdDjou1Xf xM7ApyFauBufAcWnEP59+WoImQHR9jVQOOT2Q+QY2IBM7McE4mGMfUntz7Sl8fKQ kgkINXOgIzLK6ZyeHL4LByx3XhdM2pyC4YAbpfPa94i/vzkn+CT+sUvIl+3kEhQl iA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkzCCA3ugAwIBAgIRAJBmYahiPWVEdwQ/cZrDlwwwDQYJKoZIhvcNAQEFBQAw OzELMAkGA1UEBhMCU0UxETAPBgNVBAoMCEluZXJhIEFCMRkwFwYDVQQDDBBTSVRI UyBSb290IENBIHYxMB4XDTEyMDMyOTA3NTQ0OVoXDTMyMDMyOTA3NTQ0OVowOzEL MAkGA1UEBhMCU0UxETAPBgNVBAoMCEluZXJhIEFCMRkwFwYDVQQDDBBTSVRIUyBS b290IENBIHYxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwO3mnqis qP/YNbn8+/CVTz89RyPRksnJ+PDiH4atiD/gAM9PEZVhPaXWIBnRiNLCVglFIKEq 6iLD6rrMQmmeuIWfcMBsp75vo1zdQ4gHzcop32l6Hy2fVmobYiAhYcZQS2V1SUa/ XNcpHsIehULhDjhNwzZxQkRROtFYzMm0qmxAx4PxxwmfSvNr8wcWNfSCjl6LhNxx ebn7bldFt8VwOv9CAtE0v4VwbU+P5x8ZIffVNLzuWeYuIvNxgmIZnwVkfDsicRil LcF4WJnRr96UQAYZdhNQhyPLR1eubMUT6pqFUsPKVyYf3hZtrXF+8thh/eY2TnEa ndMgNa0SIVh1NouJFqQ3KM+ggzpAo8oR77TlkBvjZZJnmG8OKeVnGNeI+o22x3ql oH+RHqu2+XSYdlJgL1o3majb0T7WhGpvUtO02hrHuLLRlBEfxYiJ6Vupo5Tmon1N pzKJod4ma83Vo/IyG9o1E4kRSU2/RjG76S0T+A4Apf4D9VZGPI8TK+Dlxx4D34rq RoVFhtntXgu4ZJP00FguKY1FV02JdZBlzGo7wZyAubSANQOO324qk76mvgoBRG9A c6oqghyEdn9p3bG7kljoQFFyXPc+OUT6pZmgf42LsEFYd60ixaDAuv0xmTVq2ckg Gl7zvbwIf91JLS+dkRANW6g/z7RXcztb4GcCAwEAAaOBkTCBjjAPBgNVHRMBAf8E BTADAQH/MEwGA1UdIARFMEMwQQYJKoVwSggBAgEBMDQwMgYIKwYBBQUHAgEWJmh0 dHA6Ly9jcHMuc2l0aHMuc2Uvc2l0aHNyb290Y2F2MS5odG1sMA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQUMvmdT2npmI2g1ox9+R3Oozy6dhUwDQYJKoZIhvcNAQEF BQADggIBAB8/43hYyArKNCIJ2LIFi9FlnOHX130KwByYpSRSODPaZCIjgK7+PYC+ T4/dg/YNTDNa1aM7UIpSWiYUc1GU5FKXY9u3Bqjvj63i7d6jvyDRRtsteOgsJ0Sc POy3F/yJl/Ojol7CWVPgz+S1ATtjUyjTr2ZLNDmvYQ4+m+6zidaToDsBxLMjVBA8 TdeqsNrZbMowRC3dsihiikFg8kATbLB8PkHgi6Y08eeuUYcDjpl/2Wii9pwNeYKy n98kyGZg6LZIRCfIa1a3RIXOArfTinFcV1FXIYzqwlEPUD+AqwRNyVLd5KXyLh9t dbqHHZAL7hiEgHO7i5WEimENTl1in+NmDPs2DifTSPgGiAalX+5+XN2tCh09HKpA eZh5uFCMNo0LCjYL1T7nXYHdbNxtsW8NdJ4sL8IF8kQRsjP6gcVKbT5F1izia18u 5EOVURuZMQXfJRtz0XucxHNJ+2Jg2Wlj3dE+ZW1H+mRMA1hQ2aa+5Spo6z+LEPHm uyIGKJqgpJhpbza01A0ODH3AKTG7LAMn4WenvdGLLraHxArgCQuCoeZPWJ372Phh 4cqXxLi3UDnMMU79LRwa9kfjbOwbBeh/FzUQhNoz5zTmtaTrxCIHSvabWNgPnED7 sYtfov2Z6qJ7WWLRXq7RSnIYK0s2OXIHmlrwYzrPG/nP3UhzWXDk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIESbY1GDANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJT QTEyMDAGA1UECgwpTmF0aW9uYWwgQ2VudGVyIGZvciBEaWdpdGFsIENlcnRpZmlj YXRpb24xHzAdBgNVBAsMFlNhdWRpIE5hdGlvbmFsIFJvb3QgQ0EwHhcNMTIwNDI5 MDY1NTIwWhcNMjkxMTI5MDcyNTIwWjBiMQswCQYDVQQGEwJTQTEyMDAGA1UECgwp TmF0aW9uYWwgQ2VudGVyIGZvciBEaWdpdGFsIENlcnRpZmljYXRpb24xHzAdBgNV BAsMFlNhdWRpIE5hdGlvbmFsIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDj5CziDK+WOay1n4cRF/Ojv4FFDfMaDLoy4kzop4bbXNK52zVK Ls1+cYIk+twf8uS8zrfG4sreKWjP7yRbv6YVz57jaUuUufz7nNhjpblp383u3Mhc wKD+KRWTvz2Gg1W1lhy9p3DatwXkOZO/pXnk9ZNGGPLbDecqd2YMgCdKPjzdT5A1 xmuBqj1vCaWMLiFXC7AKkOqhHvpYDUmnzyuyqMA46RPalFhAki/lOL22iSZzhIGN 60pZNDB4KuqLFkjBN5J1mI0KSi5/2xKO1ik5MCvuvYC2KOlXcBSCfYST/gk1vGD1 GHVQlBQkWkwYlxNCogT8mb2oWpvRZ7McG/KfAgMBAAGjggGBMIIBfTAOBgNVHQ8B Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYB BQUHMAGGF2h0dHA6Ly9vY3NwLm5jZGMuZ292LnNhMIHkBgNVHR8Egdwwgdkwgaag gaOggaCGKWh0dHA6Ly93ZWIubmNkYy5nb3Yuc2EvY3JsL25yY2FwYXJ0YTEuY3Js pHMwcTELMAkGA1UEBhMCU0ExMjAwBgNVBAoMKU5hdGlvbmFsIENlbnRlciBmb3Ig RGlnaXRhbCBDZXJ0aWZpY2F0aW9uMR8wHQYDVQQLDBZTYXVkaSBOYXRpb25hbCBS b290IENBMQ0wCwYDVQQDDARDUkwxMC6gLKAqhihodHRwOi8vd2ViLm5jZGMuZ292 LnNhL2NybC9ucmNhY29tYjEuY3JsMB8GA1UdIwQYMBaAFPyZmEEX4/M9Hv23cqm/ oxbkKumqMB0GA1UdDgQWBBT8mZhBF+PzPR79t3Kpv6MW5CrpqjANBgkqhkiG9w0B AQsFAAOCAQEALpUOix3h+/qcQm1Ai7/f7DMESwUOXCI2H6QClDh1/AhZm52FvznN m86ATFaGmU1zZvW2Asm0JEiPC2Pzjn8xgZt8WXeRtSMIeXptPsXVD0eCsO+XLic0 uYfR1AV8Xz0hN6R/yavRmJD3S5EYrsTpI4nou2DGS88L2PcrfSWM4DZk5KuqeD02 +qL0SZIDtRnu13JgsP7JB2q4YAWZP31WBHBI3TPGSOkB88LqRXGaQ1r9vhkzM4ne PFjJEodWE2EmHpEQQ3y8Hgw+0Fp8SX523G4BHUuSqdlm5Xod9LiLYC7slSz/TWTI 7CUAD9jzEqpL1/PSBmXeLdniE6YHskWu6g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEHjCCAwagAwIBAgIET7PQ7jANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMC WkExETAPBgNVBAoTCExBV3RydXN0MTIwMAYDVQQLEylMQVcgVHJ1c3RlZCBUaGly ZCBQYXJ0eSBTZXJ2aWNlcyBQVFkgTHRkLjEzMDEGA1UEAxMqTEFXdHJ1c3QgUm9v dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMDQ4MB4XDTEyMDUxNjE1NDAxOFoX DTMyMDUxNjE2MTAxOFowgYkxCzAJBgNVBAYTAlpBMREwDwYDVQQKEwhMQVd0cnVz dDEyMDAGA1UECxMpTEFXIFRydXN0ZWQgVGhpcmQgUGFydHkgU2VydmljZXMgUFRZ IEx0ZC4xMzAxBgNVBAMTKkxBV3RydXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkgMjA0ODCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKTckbEK FR42rhFERZfVJTWHixsK0c9w+iZBsfxKDahatWan3B9uHQjppoYLZkRcuFCiMJYC C4jIFVQXr/rX5GoPgMfO5eimmbJLf5JNNmVU7iEwI+QPx0LnXcwvGz5rCqc+0Y8H Lti3+s8YVTWZs9BSuw3nqUsb+/tG/wEJsjdPsf15Ovg27GMq3Ps48bfoYeCR0rt4 FTZ0vR21Xtm9tm4I/Hn2un/kHC1AvR22A6QCyOtqGNt3ZWe1k2o64N0kV6uB4v1x 19de7Y78YMXnufwjprlr99zTJgKabuADhfvFp8ZR7MlpE/QWC+00ASIje90rQZap Okzqald1KwsPFD8CAwEAAaOBizCBiDArBgNVHRAEJDAigA8yMDEyMDUxNjE1NDAx OFqBDzIwMzIwNTE2MTYxMDE4WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUXN46 MzRJZMSSMXxVXvXyO0/uwx0wHQYDVR0OBBYEFFzeOjM0SWTEkjF8VV718jtP7sMd MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAJYl5BxGneuWSlaE5zbA r7IxxqtnyTv3X3GZZK5U4w1KccxcfNI1u0cSx7PEkW1UCTbFREaCF1InNnmLukSU tIJxZdM1Vf7Drj8j9vpFho1VjvbHmc/PP+RHepzwqVQIuqQ/lIxALIQkAyJFx3Ep GFxV/O9dh/2nmoMD3L++jESN6/FiWlNpjYADYLMP53hDTKnZsXJAy1hEx3Xo1oni Sv73kKyE9ybEQOGUuFPcsgPyJiQXZc2yxtOTncJhG1GfzSQbALNltD5qs98Gha2c h3bc08fCFrHFult+FUU9Nnuc8yanErD2np40mrN3C6pHDoXsFWENtjplBI59Oz+I c88= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF 10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz 0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc 46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm 4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL 1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh 15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW 6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy KwbQBM0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQy MDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjEw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy3QRk D2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/o OI7bm+V8u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3A fQ+lekLZWnDZv6fXARz2m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJe IgpFy4QxTaz+29FHuvlglzmxZcfe+5nkCiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8n oc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTaYVKvJrT1cU/J19IG32PK /yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6vpmumwKj rckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD 3AjLLhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE 7cderVC6xkGbrPAXZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkC yC2fg69naQanMVXVz0tv/wQFx1isXxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLd qvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ04IwDQYJKoZI hvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaA SfX8MPWbTx9BLxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXo HqJPYNcHKfyyo6SdbhWSVhlMCrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpB emOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5GfbVSUZP/3oNn6z4eGBrxEWi1CXYBmC AMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85YmLLW1AL14FABZyb 7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKSds+x DzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvk F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka +elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 /ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp 7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN 5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe /v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ 5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID6DCCAtCgAwIBAgIQXCwtpvvXVopPgEL9qP3rJjANBgkqhkiG9w0BAQsFADCB jTELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJl MRwwGgYDVQQLExNXZWxscyBGYXJnbyBCYW5rIE5BMT4wPAYDVQQDEzVXZWxsc1Nl Y3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAwMSBHMjAe Fw0xMjA4MDkxNjM2NDVaFw0zMDEyMjYxNjQ2MzNaMIGNMQswCQYDVQQGEwJVUzEg MB4GA1UEChMXV2VsbHMgRmFyZ28gV2VsbHNTZWN1cmUxHDAaBgNVBAsTE1dlbGxz IEZhcmdvIEJhbmsgTkExPjA8BgNVBAMTNVdlbGxzU2VjdXJlIFB1YmxpYyBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IDAxIEcyMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAwyWEb3XDCHkxFHAv0geLGyu5Ao0guOzJ+S4atX73DJUc x9qNric9AxqppOpwiThrd45xOhlAjKmzFPwB7Fti2IpnvXT2eFdJ53SATQrXDLM3 RntUn1xBYvIuDifZT4hcuBUa2VvZMJ3Aqag2tdeULyptO19o6yN3Vs4IP/6Y3nuX 8diTmRFCCYUGWwdb9Pkkk9Z6vc//AT6P0/8cvVI7MREroqyvwJHslOf0VAmMB2gN icZ1ub42Zm0jmiZDjbX/gikaU/X3IIJQJBX8t1JGdUdpAwtL1QPvsTx+Hjxk0i2B o2j0VFrXtkFn4u6TTgcoAyVfvFhqGhGHg1+EZd3TFQIDAQABo0IwQDAOBgNVHQ8B Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUIckl02r+pBL/5t1X V8+PPnKECM0wDQYJKoZIhvcNAQELBQADggEBAArE2ntHUGAvYnFg+yWyyCGyui4a YxW+/SR6HI7lr2AZD29yHWLwh8GuPufUesF30mluNZ46GSWZWMrGtvViK4UJAgnf EwvFUo8rEjug+o9EqIormGCHwgbAzNsaXjGi+L5oKbdB64E96EOY1zOH7zUWidaL mWbECjNWzFmuPMeLwAEVkhy7pNyfmvgEdRnquBkSInGX8OAmrWDERyEsQfwWI+sE HC0F6n7eE4QtaItigOdnwzGafqicKT/xQIFJJ0dP8tb4lqjhlqo3Q+j7oore26FH 4K1RoQNutEB2TJM7IbQRx+lKSWDwXResA3FLrQjVeGjNZxomzljPjzjRG2c= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFSzCCAzOgAwIBAgIRALZLiAfiI+7IXBKtpg4GofIwDQYJKoZIhvcNAQELBQAw PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTAeFw0xMjA5MjgwODU4NTFaFw0zNzEyMzExNTU5NTla MD8xCzAJBgNVBAYTAlRXMTAwLgYDVQQKDCdHb3Zlcm5tZW50IFJvb3QgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQC2/5c8gb4BWCQnr44BK9ZykjAyG1+bfNTUf+ihYHMwVxAA+lCWJP5Q5ow6ldFX eYTVZ1MMKoI+GFy4MCYa1l7GLbIEUQ7v3wxjR+vEEghRK5lxXtVpe+FdyXcdIOxW juVhYC386RyA3/pqg7sFtR4jEpyCygrzFB0g5AaPQySZn7YKk1pzGxY5vgW28Yyl ZJKPBeRcdvc5w88tvQ7Yy6gOMZvJRg9nU0MEj8iyyIOAX7ryD6uBNaIgIZfOD4k0 eA/PH07p+4woPN405+2f0mb1xcoxeNLOUNFggmOd4Ez3B66DNJ1JSUPUfr0t4urH cWWACOQ2nnlwCjyHKenkkpTqBpIpJ3jmrdc96QoLXvTg1oadLXLLi2RW5vSueKWg OTNYPNyoj420ai39iHPplVBzBN8RiD5C1gJ0+yzEb7xs1uCAb9GGpTJXA9ZN9E4K mSJ2fkpAgvjJ5E7LUy3Hsbbi08J1J265DnGyNPy/HE7CPfg26QrMWJqhGIZO4uGq s3NZbl6dtMIIr69c/aQCb/+4DbvVq9dunxpPkUDwH0ZVbaCSw4nNt7H/HLPLo5wK 4/7NqrwB7N1UypHdTxOHpPaY7/1J1lcqPKZc9mA3v9g+fk5oKiMyOr5u5CI9ByTP isubXVGzMNJxbc5Gim18SjNE2hIvNkvy6fFRCW3bapcOFwIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBTVZx3gnHosnMvFmOcdByYqhux0zTAOBgNV HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAJA75cJTQijq9TFOjj2Rnk0J 89ixUuZPrAwxIbvx6pnMg/y2KOTshAcOD06Xu29oRo8OURWV+Do7H1+CDgxxDryR T64zLiNB9CZrTxOH+nj2LsIPkQWXqmrBap+8hJ4IKifd2ocXhuGzyl3tOKkpboTe Rmv8JxlQpRJ6jH1i/NrnzLyfSa8GuCcn8on3Fj0Y5r3e9YwSkZ/jBI3+BxQaWqw5 ghvxOBnhY+OvbLamURfr+kvriyL2l/4QOl+UoEtTcT9a4RD4co+WgN2NApgAYT2N vC2xR8zaXeEgp4wxXPHj2rkKhkfIoT0Hozymc26Uke1uJDr5yTDRB6iBfSZ9fYTf hsmL5a4NHr6JSFEVg5iWL0rrczTXdM3Jb9DCuiv2mv6Z3WAUjhv5nDk8f0OJU+jl wqu+Iq0nOJt3KLejY2OngeepaUXrjnhWzAWEx/uttjB8YwWfLYwkf0uLkvw4Hp+g pVezbp3YZLhwmmBScMip0P/GnO0QYV7Ngw5u6E0CQUridgR51lQ/ipgyFKDdLZzn uoJxo4ZVKZnSKdt1OvfbQ/+2W/u3fjWAjg1srnm3Ni2XUqGwB5wH5Ss2zQOXlL0t DjQG/MAWifw3VOTWzz0TBPKR2ck2Lj7FWtClTILD/y58Jnb38/1FoqVuVa4uzM8s iTTa9g3nkagQ6hed8vbs -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFojCCA4qgAwIBAgIGC4LclDN2MA0GCSqGSIb3DQEBCwUAMHAxCzAJBgNVBAYT AkNBMSswKQYDVQQKEyJDYXJpbGxvbiBJbmZvcm1hdGlvbiBTZWN1cml0eSBJbmMu MSIwIAYDVQQLExlDZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRAwDgYDVQQDEwdD SVNSQ0ExMB4XDTEyMTAxNjE4MjgzM1oXDTMyMTAxNjE4MjgzM1owcDELMAkGA1UE BhMCQ0ExKzApBgNVBAoTIkNhcmlsbG9uIEluZm9ybWF0aW9uIFNlY3VyaXR5IElu Yy4xIjAgBgNVBAsTGUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxEDAOBgNVBAMT B0NJU1JDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDEdvFial/N Kc0ENn9uYX5z9J1m3yJamoNEgWb9ThGwPqzoiLJTOf/jur7U/9OF2L1br2hPM6y4 FH0SW3qVa8c2/iuP9IhgiTqqWThMwV1VgaXf2B8xetOjTvBRy8Mxh64L3speG6F0 OPCSd3E8yxN+oMEKmL3YuPhUNJhOZxaaV0smhl8bZnKqwfJogp1YQXxxIuLPATH+ 4uBWqWjgrTOvNTkunG4GTPMjdi9pJugFOWm39Uga99/ZOTcyVREnBIEfnTyLjINS d8GuLM0rKkrlLfEZabqHXoud4HHIdNLN7m44N2pdGQDSdt2i6247qh31NgZPX15s whDz3W+12nla/tVGRDRIr4YANHwkhN1FkPkWgqyokdTpRjNvfrpHH+Hvr+VQ1sb5 p+1sl6orKU5dxfge9nTJqyT4DVPHaBW+/FyrPXIL0nAEtxbjaanxZ7rGAEx7gDQ1 Ll7tH6Al96WCahB/v49Zb8NGpspCTkIjhQY5NYy18dfBI0JF/S8lcfjzB9MHaL7b mGwq9qVH97BlYK2ufOYRHSdUCGWw2ILAYWvpfo8i1nEda0EgZdhXmh98DlpU4JSw bXXvKDI1PFXDbWf4JL37QPNanTbZNUy74mvZsTYP5G8gGsVvesOROa+vzPP2vSCG utMkITwfNynmn/wav5jfPLogIRKpwjoqkwIDAQABo0IwQDAdBgNVHQ4EFgQU6pUV 2lw5AOKa28S6LWf6ofd1NO0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AcYwDQYJKoZIhvcNAQELBQADggIBADXQ2Lie8gn48J+ybkiy1+qhmyiJOc3+Fmod 6ZyCX1FHOvWe0byuH5/iXErI7O1GQvF8QwcV326X9u2G/J/FCF6CDqMuqAouvI4b MRIo9nkowSK20ZVpQOhZCSeikWR26tATjXD8ZcNvEZ8qSMqnYvWDFOUaFseRi7QJ xc574+QdbZei6csmHmu03D6Ddi9eTahoiVT9TtJGqED22Mp4zzYaPVlljJv1Kx9M gt94eE0mSkdprW8zHwMeIk7ZBlmeRvxQNV/GhRvkG/gAyeDTOqsmQ81H+lr4hQvH Mtq1DS0wKTp5sxTppQ9wJdGNCVCU7U2SnjA3QNtaeEmPDzkvvS7XqwiUySmK992M vYJ8MFti6DVGVjhdkfYOb4zulZ/9dJ3t7RCrzouPt61/TWlJ8McRVZuagvei+jPy RBH6FUtGqZtrl0LWtLcJERR5U6bnfy0nOgo0JETOVYx6gHVzAkvi+kaUfTMUDUJW uaDmL4VIkZ9EuqEoqbEfiXomClNchbl8hJiMKGCltnqNPaAAPdx/qkjpqC6sX96H LVykaxbqveiVtc54CfhxNuWQaNIHlrq8AIsOmG1NcFPAw8wbE5xImpk9EsAnjmGS TGhSb40DHIn104bA/3FJTyBr/dFvkST18UcjTVnf0L1JQv1AOD7i8QVcJegQ5FoC A+O7fCUq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICpzCCAi2gAwIBAgIQTHm1miicdjFk9YlE0JEC3jAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAzIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAARXz+qzOU0/oSHgbi84csaHl/OFC0fnD1HI0fSZm8pZ Zf9M+eoLtyXV0vbsMS0yYhLXdoan+jjJZdT+c+KEOfhMSWIT3brViKBfPchPsD+P oVAR5JNGrcNfy/GkapVW6MCjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBQknbzScfcdwiW+IvGJpSwVOzQeXjAKBggqhkjOPQQD AwNoADBlAjEAuWZoZdsF0Dh9DvPIdWG40CjEsUozUVj78jwQyK5HeHbKZiQXhj5Q Vm6lLZmIuL0kAjAD6qfnqDzqnWLGX1TamPR3vU+PGJyRXEdrQE0QHbPhicoLIsga xcX+i93B3294n5E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9jCCA96gAwIBAgIQZWNxhdNvRcaPfzH5CYeSgjANBgkqhkiG9w0BAQwFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAz IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC3DrL6TbyachX7d1vb/UMPywv3 YC6zK34Mu1PyzE5l8xm7/zUd99Opu0Attd141Kb5N+qFBXttt+YTSwZ8+3ZjjyAd LTgrBIXy6LDRX01KIclq2JTqHgJQpqqQB6BHIepm+QSg5oPwxPVeluInTWHDs8GM IrZmoQDRVin77cF/JMo9+lqUsITDx7pDHP1kDvEo+0dZ8ibhMblE+avd+76+LDfj rAsY0/wBovGkCjWCR0yrvYpe3xOF/CDMSFmvr0FvyyPNypOn3dVfyGQ7/wEDoApP LW49hL6vyDKyUymQFfewBZoKPPa5BpDJpeFdoDuw/qi2v/WJKFckOiGGceTciotB VeweMCRZ0cBZuHivqlp03iWAMJjtMERvIXAc2xJTDtamKGaTLB/MTzwbgcW59nhv 0DI6CHLbaw5GF4WU87zvvPekXo7p6bVk5bdLRRIsTDe3YEMKTXEGAJQmNXQfu3o5 XE475rgD4seTi4QsJUlF3X8jlGAfy+nN9quX92Hn+39igcjcCjBcGHzmzu/Hbh6H fLPpysh7avRo/IOlDFa0urKNSgrHl5fFiDAVPRAIVBVycmczM/R8t84AJ1NlziTx WmTnNi/yLgLCl99y6AIeoPc9tftoYAP6M6nmEm0G4amoXU48/tnnAGWsthlNe4N/ NEfq4RhtsYsceavnnQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUOXEIAD7eyIbnkP/k/SEPziQZFvYwDQYJKoZIhvcN AQEMBQADggIBAFBriE1gSM5a4yLOZ3yEp80c/ekMA4w2rwqHDmquV64B0Da78v25 c8FftaiuTKL6ScsHRhY2vePIVzh+OOS/JTNgxtw3nGO7XpgeGrKC8K6mdxGAREeh KcXwszrOmPC47NMOgAZ3IzBM/3lkYyJbd5NDS3Wz2ztuO0rd8ciutTeKlYg6EGhw OLlbcH7VQ8n8X0/l5ns27vAg7UdXEyYQXhQGDXt2B8LGLRb0rqdsD7yID08sAraj 1yLmmUc12I2lT4ESOhF9s8wLdfMecKMbA+r6mujmLjY5zJnOOj8Mt674Q5mwk25v qtkPajGRu5zTtCj7g0x6c4JQZ9IOrO1gxbJdNZjPh34eWR0kvFa62qRa2MzmvB4Q jxuMjvPB27e+1LBbZY8WaPNWxSoZFk0PuGWHbSSDuGLc4EdhGoh7zk5//dzGDVqa pPO1TPbdMaboHREhMzAEYX0c4D5PjT+1ixIAWn2poQDUg+twuxj4pNIcgS23CBHI Jnu21OUPA0Zy1CVAHr5JXW2T8VyyO3VUaTqg7kwiuqya4gitRWMFSlI1dsQ09V4H Mq3cfCbRW4+t5OaqG3Wf61206MCpFXxOSgdy30bJ1JGSdVaw4e43NmUoxRXIK3bM bW8Zg/T92hXiQeczeUaDV/nxpbZt07zXU+fucW14qZen7iCcGRVyFT0E -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs ewv4n4Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc 8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg 515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO xwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgILMTI1MzcyODI4MjgwDQYJKoZIhvcNAQELBQAwWDELMAkG A1UEBhMCSlAxHDAaBgNVBAoTE0phcGFuZXNlIEdvdmVybm1lbnQxDTALBgNVBAsT BEdQS0kxHDAaBgNVBAMTE0FwcGxpY2F0aW9uQ0EyIFJvb3QwHhcNMTMwMzEyMTUw MDAwWhcNMzMwMzEyMTUwMDAwWjBYMQswCQYDVQQGEwJKUDEcMBoGA1UEChMTSmFw YW5lc2UgR292ZXJubWVudDENMAsGA1UECxMER1BLSTEcMBoGA1UEAxMTQXBwbGlj YXRpb25DQTIgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKaq rSVl1gAR1uh6dqr05rRL88zDUrSNrKZPtZJxb0a11a2LEiIXJc5F6BR6hZrkIxCo +rFnUOVtR+BqiRPjrq418fRCxQX3TZd+PCj8sCaRHoweOBqW3FhEl2LjMsjRFUFN dZh4vqtoqV7tR76kuo6hApfek3SZbWe0BSXulMjtqqS6MmxCEeu+yxcGkOGThchk KM4fR8fAXWDudjbcMztR63vPctgPeKgZggiQPhqYjY60zxU2pm7dt+JNQCBT2XYq 0HisifBPizJtROouurCp64ndt295D6uBbrjmiykLWa+2SQ1RLKn9nShjZrhwlXOa 2Po7M7xCQhsyrLEy+z0CAwEAAaOBwTCBvjAdBgNVHQ4EFgQUVqesqgIdsqw9kA6g by5Bxnbne9owDgYDVR0PAQH/BAQDAgEGMHwGA1UdEQR1MHOkcTBvMQswCQYDVQQG EwJKUDEYMBYGA1UECgwP5pel5pys5Zu95pS/5bqcMRswGQYDVQQLDBLmlL/lupzo qo3oqLzln7rnm6QxKTAnBgNVBAMMIOOCouODl+ODquOCseODvOOCt+ODp+ODs0NB MiBSb290MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH+aCXWs B9FydC53VzDCBJzUgKaD56WgG5/+q/OAvdVKo6GPtkxgEefK4WCB10jBIFmlYTKL nZ6X02aD2mUuWD7b5S+lzYxzplG+WCigeVxpL0PfY7KJR8q73rk0EWOgDiUX5Yf0 HbCwpc9BqHTG6FPVQvSCLVMJEWgmcZR1E02qdog8dLHW40xPYsNJTE5t8XB+w3+m Bcx4m+mB26jIx1ye/JKSLaaX8ji1bnOVDMA/zqaUMLX6BbfeniCq/BNkyYq6ZO/i Y+TYmK5rtT6mVbgzPixy+ywRAPtbFi+E0hOe+gXFwctyTiLdhMpLvNIthhoEdlkf SUJiOxMfFui61/0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGgTCCBGmgAwIBAgIEUVLFjDANBgkqhkiG9w0BAQ0FADCBzzELMAkGA1UEBhMC VEgxSTBHBgNVBAoMQEVsZWN0cm9uaWMgVHJhbnNhY3Rpb25zIERldmVsb3BtZW50 IEFnZW5jeSAoUHVibGljIE9yZ2FuaXphdGlvbikxNzA1BgNVBAsMLlRoYWlsYW5k IE5hdGlvbmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxPDA6BgNVBAMM M1RoYWlsYW5kIE5hdGlvbmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMTAeFw0xMzAzMjcwOTQwMjJaFw0zNjAzMjcxMDEwMjJaMIHPMQswCQYDVQQG EwJUSDFJMEcGA1UECgxARWxlY3Ryb25pYyBUcmFuc2FjdGlvbnMgRGV2ZWxvcG1l bnQgQWdlbmN5IChQdWJsaWMgT3JnYW5pemF0aW9uKTE3MDUGA1UECwwuVGhhaWxh bmQgTmF0aW9uYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE8MDoGA1UE AwwzVGhhaWxhbmQgTmF0aW9uYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1rpK5Izxmi6J F8JA84IAMf4TAnplygjYqyKxAppxNEpkWYLlQkbrI/aLWiKxzzbnc20UbfdJlF7v 5zRZZ/aoz1ZZI4RV4vsaEcqj+YqrZx6CE9CLOZq/D8IPPNZh2OqbzxUOvtTwzD9z nAT0onFzfYCwnTHxBvmwE+WISTD2Fn2IVyk6LKKMkJjOERbOTVEP/MeyzPJmGCGA BYitudDFC3gB/k7SCIs28VbPbrpzJgvW96VGamlOlranBlbM5i4xn26L7ZwAVUf0 e6Z6tt8BHUgEC6tCwnBKlL38rFHyqz/W62DfCP/1ErKJKnq5RZklfXzvzxXQSCwQ 1tS8CCe1hinU49PEKpAS9qIq+YuvFv8C83puz6LLarTgcgv7PoV/4ofgL0Mj+IXJ merWQN6g++fedv+PgDnrZxITpvvlo/wmgFlj8tIj6x/GSHNRnbezoFuraoj5v/tx UdxutnbvsFvyy4gwugbbG0HTVbSttOogIfzUd7Y9W6EMLSUhUiNS1zRTbRYEUmb4 1erxLFjyO7HxfkO13IK4XuOH4aOkX+eJDryc6Sk6JafYT2qH1JZElxgWh8JxUoXO eoytHme+ui2/oyEnxecw6QaZG7AM475SZZNNYUvyOOaPGPECUpgupg4dBc8m7AEj Bzb24BM3qUeIA4dHy92yAR9fZBsEm8UCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAUfyN2t4Mqcfcs0YgP3UxfMgpo u38wHQYDVR0OBBYEFH8jdreDKnH3LNGID91MXzIKaLt/MA0GCSqGSIb3DQEBDQUA A4ICAQANZRxaB6merEzJX0/dMWzZ4lMdP5GNWrOMvTSeLk3KWNOvWWJJNnOwYXYR vos2x5Sq+DZpByDfXC8L9o4CFu9SBjjd7TRgqodeF844bVBN5d/lUb4dBJb03Orl 2eqO3p90y4KUU4Fs+14s1aF1lk37MFzNYaCeocyCuVJyC4djYXthNHS2Lt3i4Ye1 SRRhFUdKSz53uQjSNk9YZ0KJgHhaEiPtRTvdvyAmVPxbP2ABGEHjZ3UTtyoVcMzL edIU+PPC4CoQ9/lC2NzaCtMBBdtXmMm26wyZCsqMfe87FijA91/hR1HT+AZFB/AL usKcmOzSf01+/Qb8c8LCVRJi0CNE3yLk+HnnpRBOPsmOqoPpNuqrecYFhM2WaHx0 rD8y/67JQOyPUL9QqLdO1a02atcnM/rn2C3ZN5iFG6YM6nsQE3AenojF3D6OuQ1V 3wHO0El2UdsQYnhBrWljpZUJtxgGb/0EZ9QQD07bO18MY3zrZL1uSwCogfqSMoYw jAm/fVg/ZQ2pN9FF42ZpxGj0YqmoHjfZLplJoLAGjEB/hbH18UxLOKAIzCrZlsDs wA08LkVXw++V2rbL7ltlqCsyr8kn+RVTN3VYH0vql6IiXGdW4qDMNcSswzFAuZwD er3JSA7qahXanLx4b8kV52QD2UkTZkVLLfSEmbPqpxKV5ZMu/A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFyDCCA7CgAwIBAgIBATANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJQTDEk MCIGA1UECgwbVGVsZWtvbXVuaWthY2phIFBvbHNrYSBTLkEuMScwJQYDVQQLDB5T aWduZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFzAVBgNVBAMMDlNpZ25ldCBS b290IENBMB4XDTEzMDUwNjExMzgwNFoXDTM4MDUwNjExMzgwNFowdTELMAkGA1UE BhMCUEwxJDAiBgNVBAoMG1RlbGVrb211bmlrYWNqYSBQb2xza2EgUy5BLjEnMCUG A1UECwweU2lnbmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRcwFQYDVQQDDA5T aWduZXQgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKlk y7gx4rUPgCcGzEVe6g1f13dql2i2XaB4BUSrMLB6h+9i7ghYVVwX+iuADhx1p2d2 SpbDKGt4+Vrf+mp5p4pUHSqWhvG1F9VdGlb3QBC3DuEH3GcLmaIACNQEInemQ46f 1TCq+p2BRvI9zl7CfsF8nzOvJtod3mD3gqc2zPXIwAKPks9uTv/7/mE/rr+9lmf+ 0K8d1iP3MOZ7iF3p9TNEyoq7pztZjnAXaSgXuxBWpcK0Cw37tHeJEERVbYmr1U0y udf3aZz9ta8DsiG2LGD1X9HCVIgvYO+cVIa1QQczLGwLHBLaR5lmNK6g7G3QY5d/ xAWAk/hCLFTY/tqVGGuF8lz5doc2HrGAH0DgCwqT1K5acVcNOu/h7Htd+BCaN3yp FqLEjlc7EBt2rahxQDOFAz9t2B495zBTx+Pq19AwVcSaZ0J8t0Br3KlEUPLjLkVi cby5bigFOXb1WeqhAzB04N+yCiMVTuNYOqJPeMiIW1GSzjoqNg/O37MCTy78hapD 1ga1eLfIuyMbRY+nNTTKqhQ31Z97MFaP6VcKRqcBl5ssp03/WT3unjMsLPMgu1j4 cx8B0EMiwygXtiQAElW4WxO8v9fZvVn7wlNp9a5SJs2sUrfIHVOaoQSgAkNQnRKp wG5Rwe0RTt/vxBQhurqhDpWDNVLQ559S1ZL5IsOHAgMBAAGjYzBhMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFFB7Ca9pLS+14JGv jZITK7Ey6EnQMB0GA1UdDgQWBBRQewmvaS0vteCRr42SEyuxMuhJ0DANBgkqhkiG 9w0BAQsFAAOCAgEAECWnACU9/o1G1kDHL9laJIVImKPg0UCh06PABJU0IXYW6daL KqbRNiY+w+VIjmv4BtPJbSCLwfl4hyztdUEoPnD5wnFtMQw34BXi217wwK5QFeyI UVODyaXyz6zC5swQx2wYd1ZYtSSahwNhdk8eWPPblTJ4ESuxIBOxftLl5Hu0MGUD ixvi6N7qEt6Xal4ARdbgWyqQodAr6NF2SWkW79uCtFMySCVsdPDK987d4UmPUtVU FfQIrwZnU5jnrOw1ipsT9B39gegbMc7z4IWS64NazrQXibBO4WFwX+ixMs6bHgp7 GS3IaDYzpFb1ukm9L/yzCrJrml4++0wYr1zwX9mx2wkdRlLHcNu4mCnUOWpePGKH eoqPdr/cp2i6i8U5xglPb3ZCTM8AUwq0H1jGShX9+uG8t3xUhk+8d3kkEk1kXbR6 22k2dGbofeRbKfIw/bXd3qEhYWZgJTtIb86rj02iTMsM+8E29FDBbCxpXEpEHcRc J00k907hP6tlA9O4kXzwhTjWikdELLAOCaWy0vfq7PR1tmtVS8EpO6ZEm8IQ7HqO TB2joiHcZcaAHtSXT/SAUwq6XY07doAnOllbH/VWhuHoili3mvdC71qoSu5U+iSe n7jM7KII4qyCjdIzI8Ju4+T/mfVcZ8WydiIbbSz2BveONFEi6PYZar9QmoI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFrjCCA5agAwIBAgIQUJZucr0Q1oxPa8diP5xwODANBgkqhkiG9w0BAQsFADBx MQswCQYDVQQGEwJMVDErMCkGA1UEChMiU2thaXRtZW5pbmlvIHNlcnRpZmlrYXZp bW8gY2VudHJhczEZMBcGA1UECxMQQ0EgUk9PVCBTZXJ2aWNlczEaMBgGA1UEAxMR U1NDIEdETCBDQSBSb290IEEwHhcNMTMwNjA0MTMwMDQ3WhcNMzMwNjA0MTMwMDQ3 WjBxMQswCQYDVQQGEwJMVDErMCkGA1UEChMiU2thaXRtZW5pbmlvIHNlcnRpZmlr YXZpbW8gY2VudHJhczEZMBcGA1UECxMQQ0EgUk9PVCBTZXJ2aWNlczEaMBgGA1UE AxMRU1NDIEdETCBDQSBSb290IEEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQCfXEr8HGu3GZfZATc+CukYhtMF6qLa3wmCV+5tK42aFj1VPonXyb7hAaOA NaNG7OER7ag8leU6UoHKTpgIKg+E3LvppPl5tknCFZ6glegPSPdQ1/mmQ9QHCzBB yTYSYrdseAsGPy6znuow/UFjT4QsN84Hpjlke3EVWysB8td9mA0YPtuFmuABUCEk uBujY0PTgVtNDIFOOGvOYMXqB+In4uv2w1SayMmz0SsyNwK8bXuekHcjjZMTJjuH V6NlTyZYFGpjJZrlYfocV/0NLGkPxgrwJjkXAqPWc4FCw0Ixg4vg+ktOWGExKJI8 xskQCMkMW0SsY8LXYhnyce4gt0mDGZ5H2lbFHKykOWgXXxEabKqlko+9G8vF4AKA VdNwU+WLKv5C6r07XONSAH14PybMEa400TIM+Hug0X0944q8vh4ekj84sl8yXjXE fsKSDZ22y1nV6xJq3XIhURGwc+Uy6dbMDt2zOVoi7+T16QZphip8c68YInMsNiXc ValSMbOKjhV9sk4Qe1CKAEy6h+JFU3d+TWUCa4yTtmt17e+Wt0iOqOC6uYKyUm0h /5K60T6wXLGrGQ4Zc0Yr01JIZTTaBDXSeD7PYzWkU+ZL41CDvfObh7Ih2kihekvs suLx1CUFlFMWTCtmJBDI4NecEqSUwgEjk6EApuBuuzni9XpoqQIDAQABo0IwQDAO BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoBF+H+SU ZFE7Ejl6bN1Jk/n9wFwwDQYJKoZIhvcNAQELBQADggIBAAzxS4zhTxYW0upikrat 1FKOCxlkSznwmDlzSlLqTs2OZEewMI88Dy3aImXzGVgyPH+DjwoM5VTmqb64rpdW 5rcNGXy9lyxqKqVWc4LeTpiLPRzE0Csru8UM+E7+La6/qWd/V7Nv7f+L01YM7zCM wV6m6VmKPC7cR8/MlF6DrBR2+n68DKMOXBuI7CsbNWiIsfV7xfOzxRq8+++1Xt/w OR51aO1EwksicD5ca5TJEKzw/cgvfiPigacbzgy6RTInUEU5rOD+ALQqdQcMZxu7 ccCC45dWl9Dkd1m5/3xnXIRluwg2qEtOkcJp/h3smhMfdTMsKcbpsGiQI/8jX3/G O6coELgfoojNZBYlT+OAt8BKgFfwkNs6sgIyINVryNgUQMnZOBlUOOvoZTtvXNVF eq/b2diVnranlc0cCR0CHgHpBJVdhZc4Fb2ox5ne00RCXYaDQSR8UYmqQwknNOjx CrWWS7TzoP7yAI1qO3S5Q7lmuc/q6zfO/5vpI/hs0yP96Ongbvj7DVJAiqyAayAQ XdCo/ao9ORErL/9SkTqg3IrHdjYRWYW7MIqkSDCcYUOr1K927cC/F5R4NdtINwjU jmoA6SLdyvDTEjg8mJ9gTG0/Qv3vjJq3HnF6GknUYMnrj/Tpxr9wVIjSx1c7Vs3X btztDXR+5XVBkVeTNH2p9b2H -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFrjCCA5agAwIBAgIQPoxPvOQpg4JNhFWO1TWAzzANBgkqhkiG9w0BAQsFADBx MQswCQYDVQQGEwJMVDErMCkGA1UEChMiU2thaXRtZW5pbmlvIHNlcnRpZmlrYXZp bW8gY2VudHJhczEZMBcGA1UECxMQQ0EgUk9PVCBTZXJ2aWNlczEaMBgGA1UEAxMR U1NDIEdETCBDQSBSb290IEIwHhcNMTMwNjA0MTQyMDE1WhcNMzMwNjA0MTQyMTU1 WjBxMQswCQYDVQQGEwJMVDErMCkGA1UEChMiU2thaXRtZW5pbmlvIHNlcnRpZmlr YXZpbW8gY2VudHJhczEZMBcGA1UECxMQQ0EgUk9PVCBTZXJ2aWNlczEaMBgGA1UE AxMRU1NDIEdETCBDQSBSb290IEIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQCPlenS68FzJcc4Z/CDjlO8tsvOunPbTyf2IpA/Qr8h1t5igrRvBAVJCTt3 AddLX1LS2RnHbXwMqToJYuQqGGmMoN3rrBO2DjkRgGlOY1/cPA362YxivmSFMjJZ l1CTid/7/9TYZXHHRlWiG5lhH9xQAMgXeehQsAxe5v52pgFOCchwbPqQs17cPQfN SaNOVl4ST2RBf34MFcOg3rOjKQZJRKFfbz+BoERN8HsKOCjtEu5jl8N7XYxPcd2V OtouqAFGCvNs6LXxHwgA8UCSGyYAMXU5RkkmuaTUcXcRpE8zzAnb2dEhS5JErM54 YoIX+/oStH3V8obt9H6WFOaNA1KvzRei1Ryl/oGmmu195NkOMmYQj9vZMzGBfilX 78yyoWDuilu5Zdt/G5osjycxiYoota+xVtQDIu4lT9iavdJsV7yDpkgfLFUHCTQr uXksAqWgX3x2nyQyPC2S3+tIV4eh9v4j+jSrifVoG44fqm4OpdIh0u+50bFJVzVa hNMe4gJtUhB/4oxNIdsyMhx9zJYiAy1qpwZCbW6Qh/ocXLBP0ANBE/oLU+bBEAJI C3dj9KWcUXuYZtfFdjLlb10UYX0Mu22VQNqpJsf3qcvS/ifBK/axaIb+42JSmVCO K95BIQcbh/VAHXCtz/3CQ6g1VhFCxcteZqHIqGj3/kxXYTZSgQIDAQABo0IwQDAO BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUcgNGh2H2 HbPUlWO5UHduDauY/i8wDQYJKoZIhvcNAQELBQADggIBAAjbijKBdDNxFuwhhVNI Cm8fcuPjBPgutz/zJJVPnO0T4YiCAvZm97exLYAnra64bf4jBxEIq3RhjCgS+fYQ NPDPtnyjdS0S1JTfdO6xmKux7iJiS1kff/4aZa1N4qQRPxMhtNg1i3ZApl+9MxHf mOMhXh2ju3g2AjvY/WSE2jfNWe38DNB0pGtxPDYSRJ5+bk8KIRxlH0sSbL+Octbd PgBwmAFFK+yVkOPTaTjnK51+ZVlb4duFymP+q7/k0P3kUroa5v7GkLp7zvGkYsVH viTHoHrlIeHGCOAMiYOPgGn97qDfekw600gqFr+uppW13Wgf+w61BYzRskR8YDBW dhe1NU+o1QrrwrVuAu6cXw6jsQGo5VNvfoNBHxXY/+HCthrxRpxkoBrgSsq4prSJ JO57lZli1OJAu86jmn0dcvMbgUF3AF7sPKIwBTzNfEg2E8gysGtvnzgoOGlce+bi rYO7bRPRLrfRdm9dMF65UEVI1kiAk1HJFqkQXWfGy35nfQVP9CDvJCVe7WdDxvtu efuy8sjJzkF8BeCti80KRS7iYp+XkfT5Y+zywmCK3Bv/Iaj/I4eMc42wOswfjzFy Cv2Wod8aU9M2trB3Rt4D9sKALm+XI+ERzFGYP+5A//Q9m4h/jLvhWYa9CTQnXJ4K kzI7VSqpXgsND6mmUQTimyoR -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIGDCCBgCgAwIBAgIGAT8vMVNvMA0GCSqGSIb3DQEBBQUAMIIBCjELMAkGA1UE BhMCRVMxEjAQBgNVBAgMCUJhcmNlbG9uYTFYMFYGA1UEBwxPQmFyY2Vsb25hIChz ZWUgY3VycmVudCBhZGRyZXNzIGF0IGh0dHA6Ly93d3cuYW5mLmVzL2VzL2FkZHJl c3MtZGlyZWNjaW9uLmh0bWwgKTEnMCUGA1UECgweQU5GIEF1dG9yaWRhZCBkZSBD ZXJ0aWZpY2FjaW9uMRcwFQYDVQQLDA5BTkYgQ2xhc2UgMSBDQTEaMBgGCSqGSIb3 DQEJARYLaW5mb0BhbmYuZXMxEjAQBgNVBAUTCUc2MzI4NzUxMDEbMBkGA1UEAwwS QU5GIEdsb2JhbCBSb290IENBMB4XDTEzMDYxMDE3NDUyOVoXDTMzMDYwNTE3NDUy OVowggEKMQswCQYDVQQGEwJFUzESMBAGA1UECAwJQmFyY2Vsb25hMVgwVgYDVQQH DE9CYXJjZWxvbmEgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgaHR0cDovL3d3dy5h bmYuZXMvZXMvYWRkcmVzcy1kaXJlY2Npb24uaHRtbCApMScwJQYDVQQKDB5BTkYg QXV0b3JpZGFkIGRlIENlcnRpZmljYWNpb24xFzAVBgNVBAsMDkFORiBDbGFzZSAx IENBMRowGAYJKoZIhvcNAQkBFgtpbmZvQGFuZi5lczESMBAGA1UEBRMJRzYzMjg3 NTEwMRswGQYDVQQDDBJBTkYgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDHPi9xy4wynbcUbWjorVUgQKeUAVh937J7P37XmsfH ZLOBZKIIlhhCtRwnDlg7x+BUvtJOTkIbEGMujDygUQ2s3HDYr5I41hTyM2Pl0cq2 EuSGEbPIHb3dEX8NAguFexM0jqNjrreN3hM2/+TOkAxSdDJP2aMurlySC5zwl47K ZLHtcVrkZnkDa0o5iN24hJT4vBDT4t2q9khQ+qb1D8KgCOb02r1PxWXu3vfd6Ha2 mkdB97iGuEh5gO2n4yOmFS5goFlVA2UdPbbhJsb8oKVKDd+YdCKGQDCkQyG4AjmC YiNm3UPG/qtftTH5cWri67DlLtm6fyUFOMmO6NSh0RtR745pL8GyWJUanyq/Q4bF HQB21E+WtTsCaqjGaoFcrBunMypmCd+jUZXl27TYENRFbrwNdAh7m2UztcIyb+Sg VJFyfvVsBQNvnp7GPimVxXZNc4VpxEXObRuPWQN1oZN/90PcZVqTia/SHzEyTryL ckhiLG3jZiaFZ7pTZ5I9wti9Pn+4kOHvE3Y/4nEnUo4mTxPX9pOlinF+VCiybtV2 u1KSlc+YaIM7VmuyndDZCJRXm3v0/qTE7t5A5fArZl9lvibigMbWB8fpD+c1GpGH Eo8NRY0lkaM+DkIqQoaziIsz3IKJrfdKaq9bQMSlIfameKBZ8fNYTBZrH9KZAIhz YwIDAQABo4IBfjCCAXowHQYDVR0OBBYEFIf6nt9SdnXsSUogb1twlo+d77sXMB8G A1UdIwQYMBaAFIf6nt9SdnXsSUogb1twlo+d77sXMA8GA1UdEwEB/wQFMAMBAf8w DgYDVR0PAQH/BAQDAgEGMIIBFQYDVR0RBIIBDDCCAQiCEWh0dHA6Ly93d3cuYW5m LmVzgQtpbmZvQGFuZi5lc6SB5TCB4jE0MDIGA1UECQwrR3JhbiBWaWEgZGUgbGVz IENvcnRzIENhdGFsYW5lcy4gOTk2LiAwODAxODESMBAGA1UEBwwJQmFyY2Vsb25h MScwJQYDVQQKDB5BTkYgQXV0b3JpZGFkIGRlIENlcnRpZmljYWNpb24xEjAQBgNV BAUTCUc2MzI4NzUxMDFZMFcGA1UECwxQSW5zY3JpdGEgZW4gZWwgTWluaXN0ZXJp byBkZWwgSW50ZXJpb3IgZGUgRXNwYcOxYSBjb24gZWwgbnVtZXJvIG5hY2lvbmFs IDE3MS40NDMwDQYJKoZIhvcNAQEFBQADggIBADGB3clTJTMcaGs8j/NktDs2c7HI S3GApxTxog5JuUUUuOmA6Ju0BxXe+f4ZTi/Pb5IZSsBAoM4Gbfn8mkQyfh5BY7iS K3Fnzbl9GGF613eC3T+5Q4DI1lc6n8V+jVRIej9H4nMjH/wzbWmHZcKWA3L/fJXr s8iUrvRacyXx2FyCRUmqHgnca0VNOGt+obz1WUaOCmgWO8Ga06sylddooNLtOIHO vut26a583SDjFbstMWZfz+UD54Jmqr2KnTNmOHHWo/LzbtkErsZNMMlfNn7ri5ek 1NHVrXOB8KaDszxQXxacwSMaXqpUU/X2Tx1DQK+Nb0mEBss9HQu0nfr2OeAxxxrc zt3fLv1Fsy2moQWCAQISMpIF149+VQAOoC5/u06yROCbBtMQniG8Ru8u2f+h5B2+ IT3kJICXTanWfJST0WM3IOJ/efahqPaAMxkc669Zo3+Un9Zb9QfRmLkc/R3LHSFb QngpIwh04MnLhUaOMs4Y38uFUz8XHxJsW7pDxtMZdfGgEx94oNklvzrBP3rxeJxQ 8FknN+Zaf2Lz2T4Q7srTH8ShMddMoiOCRFR5n3DbmamoCeyu5LxbZBud0M99RCoF f4Bov9yNQL8QqnP/ZtcwM2NjbfzYSPqDyt2l5e1oNGdbFewP7N+eaAHpltM7IdHE xJhqqSqPzE7W6RT9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I 0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv 6pZjamVFkpUBtA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI 2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx 1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV 5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY 1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 sycX -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t 9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd +SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N 0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie 4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 /YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGQDCCBCigAwIBAgIIdPhg8eijj0EwDQYJKoZIhvcNAQELBQAwgasxCzAJBgNV BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDE8MDoGA1UECgwzTklTWiBOZW16ZXRp IEluZm9rb21tdW5pa8OhY2nDs3MgU3pvbGfDoWx0YXTDsyBacnQuMUswSQYDVQQD DEJGxZF0YW7DunPDrXR2w6FueWtpYWTDsyAtIEtvcm3DoW55emF0aSBIaXRlbGVz w610w6lzIFN6b2xnw6FsdGF0w7MwHhcNMTMwOTEzMTAyNzA0WhcNMzMwOTEzMTAy NzA0WjCBqzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MTwwOgYDVQQK DDNOSVNaIE5lbXpldGkgSW5mb2tvbW11bmlrw6FjacOzcyBTem9sZ8OhbHRhdMOz IFpydC4xSzBJBgNVBAMMQkbFkXRhbsO6c8OtdHbDoW55a2lhZMOzIC0gS29ybcOh bnl6YXRpIEhpdGVsZXPDrXTDqXMgU3pvbGfDoWx0YXTDszCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBALVCpWRI22SlN/gsuJkCUbmiKMT7cATE2WyKhvcP iRekhMIubE71/0TvW0MOiX83NaVbyOQjW68ZnFvtrNYALttjysNU2K9n1MtgRKJP z6Te/B8xZla34d04ilP8zyMVi4qH/Qkw5ZhHBA4Waa8JBbzH1JBFj2hjvoJYN/vY TG+lrBV3daWIZDhc0mUPUwXOlDCXb3qB6WSYEtEeSp/B8xfbGTYQObgBs7d4TbUM e16qTp25zV04/39J/rdIrwNCbL5kG2H5zmt6m1BxAPNXl8UBdBurySZZbHq/Cpdn lrWARUgBRpxAFORhOCFbiWTiBTYToCrO24gEhkQ13JM0WVdq7VNj+ovCGBY89HHH PgwaEeTODyDDFyOro38TVay0/5bYwC96CZvbHJaNpoz8oWqma9EMnTGsmjH6UvmJ OfovU/PpkS5Qjqq4pCWvG4vZalKIVwrDC5pxn7zKRYrpudWVwbbCztENaUo2PK6N rMt19pAhwwmXzi0SdmJe6w6Pcl8rm7DJChXz/s/3RIRGAf3PZuzQMJd8bazROMFG cgcXDj77MObLNNW1cxNFIQ4dGWtIFtrokakG0Og9b/qM0bj1mQPx69i1abu4iU9S Aqd+PtvsxZcGlftT6+DT58iPiJn/LreXmX2E81H9joND3vOv4DN0xBUcKRenSXPc wE7dAgMBAAGjZjBkMB0GA1UdDgQWBBTVqFEOeTByXrSsFg3TtevqwUvcOjASBgNV HRMBAf8ECDAGAQH/AgEDMB8GA1UdIwQYMBaAFNWoUQ55MHJetKwWDdO16+rBS9w6 MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAYfZkTup7l8LCAtlZ MoBtgpKi+k2Cc2ZanYLSVWIw+CDNp9OJwcZzxNhdST3Ovgx6HchpbD367wD2gZqN O1VPDJ1W2afmTeZrsKK1oP7fXYNbqxHyaxivq2bbG8lLGvdE3fGcgqyaXqioqDGe 3pzBQiKMxBOE5SxDBhspaTPX4AcCH6vuSZ7Xw4iuWRuXy/gbZWABzG3hQCAtSyEB 7B4ssYFr3saM9TSwjMOb3lg+EU3oSEyHlu5aR0tCb57og0iCuZrpPET5UZNUq5RF +aiVrqaIefXmkqhYIi7UlEwYuq39p4VaghNqva5bwCwZXdiTwN11QDNp2U4mCjaH pAEM4d+tDBkYX4jKNbEKe4EHZvl/Dy1tGYrk5IO7Qx1eT9LhKTjBH/Vco1Rg6/hD 3uaVBJmH4cupJDp5LRpwZZ8RJ104LkUNW/gRWS4ONRNq16dUBP5S+EwV5gOZXLKH /KpGCPjTaAdgHC8nUnWTAtjd07GH1P2ZdnzB/AOq78eCSXr6+kvah9sFn1jib75j +hqjNMHPukwiAAcFgF8F5gFzV9SR4dBh74Yo433MyjKX47NtvL/wCaAtxABUM20F h/SHJB2Fzd7DOzeg5Qiv44sBHbgdNmOiEOElK2xS4B3Gx/ZtneDHIuTdsIYupqOY ZTMgdlbbZ/DGXkOCwgptZNXejGw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEDjCCAvagAwIBAgIDD92sMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFkQtVFJVU1QgUm9vdCBD QSAzIDIwMTMwHhcNMTMwOTIwMDgyNTUxWhcNMjgwOTIwMDgyNTUxWjBFMQswCQYD VQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMR8wHQYDVQQDDBZELVRSVVNU IFJvb3QgQ0EgMyAyMDEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA xHtCkoIf7O1UmI4SwMoJ35NuOpNcG+QQd55OaYhs9uFp8vabomGxvQcgdJhl8Ywm CM2oNcqANtFjbehEeoLDbF7eu+g20sRoNoyfMr2EIuDcwu4QRjltr5M5rofmw7wJ ySxrZ1vZm3Z1TAvgu8XXvD558l++0ZBX+a72Zl8xv9Ntj6e6SvMjZbu376Ml1wrq WLbviPr6ebJSWNXwrIyhUXQplapRO5AyA58ccnSQ3j3tYdLl4/1kR+W5t0qp9x+u loYErC/jpIF3t1oW/9gPP/a3eMykr/pbPBJbqFKJcu+I89VEgYaVI5973bzZNO98 lDyqwEHC451QGsDkGSL8swIDAQABo4IBBTCCAQEwDwYDVR0TAQH/BAUwAwEB/zAd BgNVHQ4EFgQUP5DIfccVb/Mkj6nDL0uiDyGyL+cwDgYDVR0PAQH/BAQDAgEGMIG+ BgNVHR8EgbYwgbMwdKByoHCGbmxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQv Q049RC1UUlVTVCUyMFJvb3QlMjBDQSUyMDMlMjAyMDEzLE89RC1UcnVzdCUyMEdt YkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MDugOaA3hjVodHRwOi8v Y3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2FfM18yMDEzLmNybDAN BgkqhkiG9w0BAQsFAAOCAQEADlkOWOR0SCNEzzQhtZwUGq2aS7eziG1cqRdw8Cqf jXv5e4X6xznoEAiwNStfzwLS05zICx7uBVSuN5MECX1sj8J0vPgclL4xAUAt8yQg t4RVLFzI9XRKEBmLo8ftNdYJSNMOwLo5qLBGArDbxohZwr78e7Erz35ih1WWzAFv m2chlTWL+BD8cRu3SzdppjvW7IvuwbDzJcmPkn2h6sPKRL8mpXSSnON065102ctN h9j8tGlsi6BDB2B4l+nZk3zCRrybN1Kj7Yo8E6l7U0tJmhEFLAtuVqwfLoJs4Gln tQ5tLdnkwBXxP/oYcuEVbSdbLTAoK59ImmQrme/ydUlfXA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of 1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L 6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw 3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb 5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ 0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ 8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID2DCCAsCgAwIBAgIQYFbFSyNAW2TU7SXa2dYeHjANBgkqhkiG9w0BAQsFADCB hTELMAkGA1UEBhMCREUxKTAnBgNVBAoTIERldXRzY2hlciBTcGFya2Fzc2VuIFZl cmxhZyBHbWJIMScwJQYDVQQLEx5TLVRSVVNUIENlcnRpZmljYXRpb24gU2Vydmlj ZXMxIjAgBgNVBAMTGVMtVFJVU1QgVW5pdmVyc2FsIFJvb3QgQ0EwHhcNMTMxMDIy MDAwMDAwWhcNMzgxMDIxMjM1OTU5WjCBhTELMAkGA1UEBhMCREUxKTAnBgNVBAoT IERldXRzY2hlciBTcGFya2Fzc2VuIFZlcmxhZyBHbWJIMScwJQYDVQQLEx5TLVRS VVNUIENlcnRpZmljYXRpb24gU2VydmljZXMxIjAgBgNVBAMTGVMtVFJVU1QgVW5p dmVyc2FsIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo 4wvfETeFgpq1bGZ8YT/ARxodRuOwVWTluII5KAd+F//0m4rwkYHqOD8heGxI7Gsv otOKcrKn19nqf7TASWswJYmM67fVQGGY4tw8IJLNZUpynxqOjPolFb/zIYMoDYuv WRGCQ1ybTSVRf1gYY2A7s7WKi1hjN0hIkETCQN1d90NpKZhcEmVeq5CSS2bf1XUS U1QYpt6K1rtXAzlZmRgFDPn9FcaQZEYXgtfCSkE9/QC+V3IYlHcbU1qJAfYzcg6T OtzoHv0FBda8c+CI3KtP7LUYhk95hA5IKmYq3TLIeGXIC51YAQVx7YH1aBduyw20 S9ih7K446xxYL6FlAzQvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P AQH/BAQDAgEGMB0GA1UdDgQWBBSafdfr639UmEUptCCrbQuWIxmkwjANBgkqhkiG 9w0BAQsFAAOCAQEATpYS2353XpInniEXGIJ22D+8pQkEZoiJrdtVszNqxmXEj03z MjbceQSWqXcy0Zf1GGuMuu3OEdBEx5LxtESO7YhSSJ7V/Vn4ox5R+wFS5V/let2q JE8ii912RvaloA812MoPmLkwXSBvwoEevb3A/hXTOCoJk5gnG5N70Cs0XmilFU/R UsOgyqCDRR319bdZc11ZAY+qwkcvFHHVKeMQtUeTJcwjKdq3ctiR1OwbSIoi5MEq 9zpok59FGW5Dt8z+uJGaYRo2aWNkkijzb2GShROfyQcsi1fc65551cLeCNVUsldO KjKNoeI60RAgIjl9NEVvcTvDHfz/sk+o4vYwHg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR 9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az 5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh /WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw 0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq 4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR 1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM 94B7IWcnMFk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c 8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIQDLMPcPKGpDPguQmJ3gHttzANBgkqhkiG9w0BAQsFADBQ MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPV0ZBIEhvdHNwb3QgMi4wMScwJQYDVQQD Ex5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0gMDMwHhcNMTMxMjA4MTIwMDAw WhcNNDMxMjA4MTIwMDAwWjBQMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPV0ZBIEhv dHNwb3QgMi4wMScwJQYDVQQDEx5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0g MDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsdEtReIUbMlO+hR6b yQk4nGVITv3meYTaDeVwZnQVal8EjHuu4Kd89g8yRYVTv3J1kq9ukE7CDrDehrXK ym+8VlR7ro0lB/lwRyNk3W7yNccg3AknQ0x5fKVwcFznwD/FYg37owGmhGFtpMTB cxzreQaLXvLta8YNlJU10ZkfputBpzi9bLPWsLOkIrQw7KH1Wc+Oiy4hUMUbTlSi cjqacKPR188mVIoxxUoICHyVV1KvMmYZrVdc/b5dbmd0haMHxC0VSqbydXxxS7vv /lCrC2d5qbKE66PiuBPkhzyU7SI9C8GU/S7akYm1MMSTn5W7lSp2AWRDnf9LQg51 dLvDxJ7t2fruXtSkkqG/cwY1yQI8O+WZYPDThKPcDmNbaxVE9lOizAHXFVsfYrXA PbbMOkzKehYwaIikmNgcpxtQNw+wikJiZb9N8VwwtwHK71XEFi+n5DGlPa9VDYgB YkBcxvVo2rbE3i3teQgHm+pWZNP08aFNWwMk9yQkm/SOGdLq1jLbQA9yd7fyR1Ct W1GLzKi1Ojr/6XiB9/noL3oxP/+gb8OSgcqVfkZp4QLvrGdlKiOI2fE7Bslmzn6l B3UTpApjab7BQ99rCXzDwt3Xd7IrCtAJNkxi302J7k6hnGlW8S4oPQBElkOtoH9y XEhp9rNS0lZiuwtFmWW2q50fkQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUZw5JLGEXnuvt4FTnhNmbrWRgc2UwDQYJ KoZIhvcNAQELBQADggIBAFPoGFDyzFg9B9+jJUPGW32omftBhChVcgjllI07RCie KTMBi47+auuLgiMox3xRyP7/dX7YaUeMXEQ1BMv6nlrsXWv1lH4yu+RNuehPlqRs fY351mAfPtQ654SBUi0Wg++9iyTOfgF5a9IWEDt4lnSZMvA4vlw8pUCz6zpKXHnA RXKrpY3bU+2dnrFDKR0XQhmAQdo7UvdsT1elVoFIxHhLpwfzx+kpEhtrXw3nGgt+ M4jNp684XoWpxVGaQ4Vvv00Sm2DQ8jq2sf9F+kRWszZpQOTiMGKZr0lX2CI5cww1 dfmd1BkAjI9cIWLkD8YSeaggZzvYe1o9d7e7lKfdJmjDlSQ0uBiG77keUK4tF2fi xFTxibtPux56p3GYQ2GdRsBaKjH3A3HMJSKXwIGR+wb1sgz/bBdlyJSylG8hYD// 0Hyo+UrMUszAdszoPhMY+4Ol3QE3QRWzXi+W/NtKeYD2K8xUzjZM10wMdxCfoFOa 8bzzWnxZQlnu880ULUSHIxDPeE+DDZYYOaN1hV2Rh/hrFKvvV+gJj2eXHF5G7y9u Yg7nHYCCf7Hy8UTIXDtAAeDCQNon1ReN8G+XOqhLQ9TalmnJ5U5ARtC0MdQDht7T DZpWeEVv+pQHARX9GDV/T85MV2RPJWKqfZ6kK0gvQDkunADdg8IhZAjwMMx3k6B/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF /YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R 3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy 9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ 2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 +bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv 8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT 3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU +ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH 6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 +wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG 4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A 7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIIVE2lvEA1VlowDQYJKoZIhvcNAQELBQAwgYUxCzAJBgNV BAYTAlBUMUIwQAYDVQQKDDlNVUxUSUNFUlQgLSBTZXJ2acOnb3MgZGUgQ2VydGlm aWNhw6fDo28gRWxlY3Ryw7NuaWNhIFMuQS4xMjAwBgNVBAMMKU1VTFRJQ0VSVCBS b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IDAxMB4XDTE0MDQwNDA4NTk0N1oX DTM5MDQwNDA4NTk0N1owgYUxCzAJBgNVBAYTAlBUMUIwQAYDVQQKDDlNVUxUSUNF UlQgLSBTZXJ2acOnb3MgZGUgQ2VydGlmaWNhw6fDo28gRWxlY3Ryw7NuaWNhIFMu QS4xMjAwBgNVBAMMKU1VTFRJQ0VSVCBSb290IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IDAxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAztw/9BluuxVp hvTkzec6cDvHmos7gwCBW/sgFlq+v1gAXynmV29+iiwVB1waY4xCXxbd2omERVcX lqCcoXUiQRo6/cUXkRP2vmIKvG4lLVvAjBBm9+LW+9xIMaMaqOVNSMmiHHP+j2ZA Y3dZBzw9FJ/U94WR0MNC9Rths3eAgCptEgKWi1HZwW8nCxoHNAD/0llMKejXGWPY kbQ//I4OJfKhEgdlyjXeq/4WowiMr39+EvRZFgUf6K10eTL3eAK2tMyr2x44YQQZ ekFA2loRZHUC/WTR1pRCDyLnZc2vkA4MWzEBmVHvRYx9pTjannxL5Kbos6SC1gM0 Lk+3Uat3OAn1Bv7cZhsPP/p974xVvuANhpWh3L3EwwjRRR7yvb5w8eYmxrsIsSil wqXtiNahwPsj8Sc5zOGEBxm8fvbMOP9uELtG6SOJJIH/AOJRANxSUH0TUH0WPUCN 07/5imXYYhIpd8K6wkk0T4p5aclLFfM03s+vhuLlyKlWYUwGVFrFbBnq88hEzSQa dtFxAFlr2XWbzv0Q/rGDoqW3koZ2m0r3HdyMhaZYrYqmaGkXyW0bps8nSyks3XFC GokQ5dWbEl9Ji4S82Ahc+884Qq++0W57kapmQMUFfivQZrbH31L+9EVtI5IhnhIB kHOD4qUJDdfA+IWVHmPRPzXalNE32fUCAwEAAaNjMGEwHQYDVR0OBBYEFNU5HJxb bwSqopVM7yDdKXSkxUVxMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1Tkc nFtvBKqilUzvIN0pdKTFRXEwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUA A4ICAQA/51/zIhbeg54g5ILn5Z53yfsrsHQN3xt0Ig9zEKGwF+xMDNQocGpmckRp EJN2Nc8v+I88qxl8cZKVcRs3FcIbKHrvbng43/uPmwEg3K/21o0JZtrERqn8lapE IxLfR8CwFey1sZ5sD5GqpjrlwQ1gbFBAcFxcyM6zzOvtqogZVqWkyAx65XZAZzO0 PZbcd8sjePlTW8+N3rGnjlp6ojJjo4jXJWFaXUk6cubPqpSGbG73guCOZ5MoxagN Te84rXlKZo2EAQgEefNSxkHnmmIGs/USHuzZAEPT65Z3dOF5+RSUhG26VIIFjN8B 8jCIgax6L4tDLHY0zjXnh45OCwqlGlexU1q/a9i+AH7G+e5mMQix35QzhJx3T3tk L++OD1koIsvwXD4r/TXWlf8D7GVSfr7yGfh71VIsUneakWZBcI3VSecLSH+Krt5F Pd3+5tLkksN7zjCgSW43rajTLLY9niHbBlfi8K4G+9nFETehe9sdEXxodiA+9byl 2Wa1Ia1FJsZdHgKjQcTUfYEZyxeXBg/m7HQARsR13T3wQzSvprz89oL7z8X6sw8l pT9mENaegqXbOhN53o2p16aNhtIv2WkN4nV4fklfIquGcChRs3q2oHn61OWDp7B3 ytsBgu/ivk0v08BN0ONpbnwmm+um+0XvsQSKL6ohBvbm1LxBIw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIIAeDltYNno+AwDQYJKoZIhvcNAQEMBQAwZzEbMBkGA1UE AwwSQXBwbGUgUm9vdCBDQSAtIEcyMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMw HhcNMTQwNDMwMTgxMDA5WhcNMzkwNDMwMTgxMDA5WjBnMRswGQYDVQQDDBJBcHBs ZSBSb290IENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgREkhI2imKScUcx+xuM23+TfvgHN6s XuI2pyT5f1BrTM65MFQn5bPW7SXmMLYFN14UIhHF6Kob0vuy0gmVOKTvKkmMXT5x ZgM4+xb1hYjkWpIMBDLyyED7Ul+f9sDx47pFoFDVEovy3d6RhiPw9bZyLgHaC/Yu OQhfGaFjQQscp5TBhsRTL3b2CtcM0YM/GlMZ81fVJ3/8E7j4ko380yhDPLVoACVd J2LT3VXdRCCQgzWTxb+4Gftr49wIQuavbfqeQMpOhYV4SbHXw8EwOTKrfl+q04tv ny0aIWhwZ7Oj8ZhBbZF8+NfbqOdfIRqMM78xdLe40fTgIvS/cjTf94FNcX1RoeKz 8NMoFnNvzcytN31O661A4T+B/fc9Cj6i8b0xlilZ3MIZgIxbdMYs0xBTJh0UT8TU gWY8h2czJxQI6bR3hDRSj4n4aJgXv8O7qhOTH11UL6jHfPsNFL4VPSQ08prcdUFm IrQB1guvkJ4M6mL4m1k8COKWNORj3rw31OsMiANDC1CvoDTdUE0V+1ok2Az6DGOe HwOx4e7hqkP0ZmUoNwIx7wHHHtHMn23KVDpA287PT0aLSmWaasZobNfMmRtHsHLD d4/E92GcdB/O/WuhwpyUgquUoue9G7q5cDmVF8Up8zlYNPXEpMZ7YLlmQ1A/bmH8 DvmGqmAMQ0uVAgMBAAGjQjBAMB0GA1UdDgQWBBTEmRNsGAPCe8CjoA1/coB6HHcm jTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwF AAOCAgEAUabz4vS4PZO/Lc4Pu1vhVRROTtHlznldgX/+tvCHM/jvlOV+3Gp5pxy+ 8JS3ptEwnMgNCnWefZKVfhidfsJxaXwU6s+DDuQUQp50DhDNqxq6EWGBeNjxtUVA eKuowM77fWM3aPbn+6/Gw0vsHzYmE1SGlHKy6gLti23kDKaQwFd1z4xCfVzmMX3z ybKSaUYOiPjjLUKyOKimGY3xn83uamW8GrAlvacp/fQ+onVJv57byfenHmOZ4VxG /5IFjPoeIPmGlFYl5bRXOJ3riGQUIUkhOb9iZqmxospvPyFgxYnURTbImHy99v6Z SYA7LNKmp4gDBDEZt7Y6YUX6yfIjyGNzv1aJMbDZfGKnexWoiIqrOEDCzBL/FePw N983csvMmOa/orz6JopxVtfnJBtIRD6e/J/JzBrsQzwBvDR4yGn1xuZW7AYJNpDr FEobXsmII9oDMJELuDY++ee1KG++P+w8j2Ud5cAeh6Squpj9kuNsJnfdBrRkBof0 Tta6SqoWqPQFZ2aWuuJVecMsXUmPgEkrihLHdoBR37q9ZV0+N0djMenl9MU/S60E inpxLK8JQzcPqOMyT/RFtm2XNuyE9QoB6he7hY1Ck3DDUOUUi78/w0EP3SIEIwiK um1xRKtzCTrJ+VKACd+66eYWyi4uTLLT3OUEVLLUNIAytbwPF+E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwS QXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcN MTQwNDMwMTgxOTA2WhcNMzkwNDMwMTgxOTA2WjBnMRswGQYDVQQDDBJBcHBsZSBS b290IENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9y aXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzB2MBAGByqGSM49 AgEGBSuBBAAiA2IABJjpLz1AcqTtkyJygRMc3RCV8cWjTnHcFBbZDuWmBSp3ZHtf TjjTuxxEtX/1H7YyYl3J6YRbTzBPEVoA/VhYDKX1DyxNB0cTddqXl5dvMVztK517 IDvYuVTZXpmkOlEKMaNCMEAwHQYDVR0OBBYEFLuw3qFYM4iapIqZ3r6966/ayySr MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gA MGUCMQCD6cHEFl4aXTQY2e3v9GwOAEZLuN+yRhHFD/3meoyhpmvOwgPUnPWTxnS4 at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM 6BgD56KyKA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFUTCCAzmgAwIBAgIIAPtxJlitmeUwDQYJKoZIhvcNAQELBQAwNjEWMBQGA1UE AwwNQ0FFRElDT00gUm9vdDEPMA0GA1UECgwGRURJQ09NMQswCQYDVQQGEwJFUzAe Fw0xNDA1MjExMTA2MzVaFw0zNDA1MjExMDIwMDBaMDYxFjAUBgNVBAMMDUNBRURJ Q09NIFJvb3QxDzANBgNVBAoMBkVESUNPTTELMAkGA1UEBhMCRVMwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQDbgMroSXTH0zgu8cUjYvw2jC8efjkL6Qb0 VZulmCmU7YZHMoPzxZJ6BdcpAj4Wwyh/NWQpenm7oeIeYRSN5wDQ3KJUZYrfablx R384OBZGp2kxETVM4Sp//21PlT3jXUhNGVMIWmsh1RIwaZeQry3B9X9BX0k2j024 HhqVX9oPb1wVNcQRvF+Fm72tO1Veu9/Ou69cmWDdH2kaSUgh+QkKz3Kn8PLe5XgZ vhLdzYd5Qc4vRdcLkRARBB4SnfI4A18Waa6gCtrA+eugDRgPeV6RneQfFJw0ExkC RLpRw+55smAUo6+8SC0oOGgBQ2TKDoaDYtCKGaYn8St7SykhW5rMaEIQyEtPDyOy iHzEXG4XcMV3r5XAJaQiCtN8+dhyyNAtvafo0i2LTKFuCvy0QDO7mmv8pOrJ/uA0 iEPMxrw/ddKlqa/6l7k+t85UoE3AXS7BKNhjVHK4rFr1OvsgYQY69KArOKvMgwxJ 1G4+bQ8+cy825vNPs8AA0UVJW4z2o5gdhH+ZCsPqCjzD0yR4SGf1GzsOHQ5DsQR1 waA5dov22QKlHeGeWwe7NldKIU35iWm0bA/Xr6AVJJnn+NdTlOwSv6Sl1+3ujjV3 d9ymfyBUktZj1nKeTSq2j3PzGaHEsB/mNKMLAD6XSSdhqqoEQTM4tVBRzDYV2x// vcpIg0inswIDAQABo2MwYTAdBgNVHQ4EFgQUFM0qWXhjq2EZ6Lg9oeBawHXn+csw DwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQUzSpZeGOrYRnouD2h4FrAdef5 yzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAD0JGQC2kQJs7A73 4eJisL8zDf1VEvQImvcrLa73nEfYHwYBE7WO57KCCz2EWUPUB9grXBB6JCzKjejV ozmcMczr4Drh1b/Px4d7YP9HOdejRNYIJlvPWlTsiNOOD3k8yKNPpsKOJ/DeEq5e Ga3nIlaKWDLg+QbQqSq0NZsMhiZRAJRHUPylxCVh+VjwRXAuSXZ/EdZvtfkpBeEN w05YH68d7DfQSvkGBoHT26CWuA6RMHnmUN+IuAupXNQH9MmozH2Pk2MJZAAFKmhm Q7uiu/6VrvnEpQqIYkh4JXwqPxFkptMiIEedMtby48ikYXTngsJEuqDRXV+88UQO g08cUIXE6eds/Oa4VeGiGoC3kESnhCKXRyLeqzg3z7XyHD5CcLt1tmUoa8t/gjWq 9vMgeChzB5YwcKUqcVyheaQWuUY9XrQASYWJ0w7fga5YjVjW4cVEeC4cILuiR5e/ dhQ7qSiPnwt10qE87SvHjpCheqKZMGL8hR01czvztVkiG80IsQyddWrbhTsOh58y T5IAAQFMSWiCgEFs+f1xvYv0eApgo56xUh3AiuOexb8rGWqYp7HeFVCfqpQlj6mA gqdyuklkCSdhK268IygzXZ5u8Lm9IDKM3aALmbu0hAQkdSmW96elF7hRBet0rVF5 lvy7+98JLQiSRM7A0rMYxxQivyHx -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUA MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy dHBsdXMgUm9vdCBDQSBHMTAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBa MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy dHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB ANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHNr49a iZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt 6kuJPKNxQv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP 0FG7Yn2ksYyy/yARujVjBYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f 6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTvLRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDE EW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2z4QTd28n6v+WZxcIbekN 1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc4nBvCGrc h2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCT mehd4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV 4EJQeIQEQWGw9CEjjy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPO WftwenMGE9nTdDckQQoRb5fc5+R+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1Ud DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSowcCbkahDFXxd Bie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHYlwuBsTANBgkq hkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh 66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7 /SMNkPX0XtPGYX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BS S7CTKtQ+FjPlnsZlFT5kOwQ/2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j 2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F6ALEUz65noe8zDUa3qHpimOHZR4R Kttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilXCNQ314cnrUlZp5Gr RHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWetUNy 6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEV V/xuZDDCVRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5 g4VCXA9DO2pJNdWY9BW/+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl ++O/QmueD6i9a5jc2NvLi6Td11n0bt3+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUA MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w ZW5UcnVzdCBSb290IENBIEcyMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAw MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU T3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+Ntmh /LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78e CbY2albz4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/6 1UWY0jUJ9gNDlP7ZvyCVeYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fE FY8ElggGQgT4hNYdvJGmQr5J1WqIP7wtUdGejeBSzFfdNTVY27SPJIjki9/ca1TS gSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz3GIZ38i1MH/1PCZ1Eb3X G7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj3CzMpSZy YhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaH vGOz9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4 t/bQWVyJ98LVtZR00dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/ gh7PU3+06yzbXfZqfUAkBXKJOAGTy3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUajn6QiL3 5okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59M4PLuG53hq8w DQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0 nXGEL8pZ0keImUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qT RmTFAHneIWv2V6CG1wZy7HBGS4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpT wm+bREx50B1ws9efAvSyB7DH5fitIw6mVskpEndI2S9G/Tvw/HRwkqWOOAgfZDC2 t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ6e18CL13zSdkzJTa TkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97krgCf2 o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU 3jg9CcCoSmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eA iN1nE28daCSLT7d0geX0YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14f WKGVyasvc0rQLW6aWQ9VGHgtPFGml4vmu7JwqkwR3v98KzfUetF3NI/n+UL3PIEM S1IK -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4x CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs dXMgUm9vdCBDQSBHMjAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4x CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs dXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABM0PW1aC3/BFGtat 93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uNAm8x Ik0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0P AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwj FNiPwyCrKGBZMB8GA1UdIwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqG SM49BAMDA2gAMGUCMHD+sAvZ94OX7PNVHdTcswYO/jOYnYs5kGuUIe22113WTNch p+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjlvPl5adytRSv3tjFzzAal U5ORGpOucGpnutee5WEaXw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAx CzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5U cnVzdCBSb290IENBIEczMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFow QDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwUT3Bl blRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARK7liuTcpm 3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5Bta1d oYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4G A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5 DMlv4VBN0BBY3JWIbTAfBgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAK BggqhkjOPQQDAwNpADBmAjEAj6jcnboMBBf6Fek9LykBl7+BFjNAk2z8+e2AcG+q j9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta3U1fJAuwACEl74+nBCZx 4nxp5V2a+EEfOzmTk51V6s2N8fvB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBMTANBgkqhkiG9w0BAQsFADA+MQswCQYDVQQGEwJKUDEO MAwGA1UEChMFTEdQS0kxHzAdBgNVBAMTFkFwcGxpY2F0aW9uIENBIEczIFJvb3Qw HhcNMTQwNjAzMTUwMDAwWhcNMzQwNjAzMTQ1OTU5WjA+MQswCQYDVQQGEwJKUDEO MAwGA1UEChMFTEdQS0kxHzAdBgNVBAMTFkFwcGxpY2F0aW9uIENBIEczIFJvb3Qw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNRT730ZYiXJEvPgoAA8y2 92xU/Cg31AQY7K2Yya/Tpbnn2b9O5qOZPJluoSAeRhvidVW80uz2iBrsNEVLg53T subdB4nBCNn4O4uSZHJdmjvMrTeJx9xgeQjgcKz3K+2fA0kfjj6DqG7iklxU0Xnf 7Bg6fbhtj9ajJU2tH0CmX9SqTrFwGFmZ8gtUaT55KESI93GXzX8F3MrcdkqQTGtg 6PomMdi1+Of8bYskarbvQtcjVMUaY4o7x/yqbTyPy2zaILDyvGUcAUwilQ0cIx+s 1fnOdVvqML1MASQfddRhScMbmWWOCFw5OM0pwzhFzWR5t5tNR+pYMvqm9pLwwbdf AgMBAAGjYzBhMB0GA1UdDgQWBBSpNSpIviw37YbbfFWHACa+GC1cLjAOBgNVHQ8B Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSpNSpIviw37Ybb fFWHACa+GC1cLjANBgkqhkiG9w0BAQsFAAOCAQEAtoK9xUbQcYulkT1+LVr5nIR9 ByeVHedNyHzs5pPoVhp6MEg7DPpO9Qmyr4itlOz9sq0v5gV0IRuEizgqw+3vRmi1 3VL6cMJ1T/+jQS48F5RMCSK0jsF/xKas7YNoz2Ve7Hq9xWbu0KN/8lexCMJ5cOty f0FZCXl18byxIf6Ds0Q9iaO+sXrYncMf5sRU4Y3l2FDc5FY3e74oAPMsd9ojf2CY PQUW8nhprZnDOnRsPpqylO2PqvZTa+fIt+g8jPvHfE8ZXaRmFel/h6DQ1a0gpEYJ RazlyGWHuwbf/NdoVkNzogCZMpLCDqAcDpG9lVi8k5+EwqVm52XNKeJi8gWSYA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDNTCCAh2gAwIBAgIBATANBgkqhkiG9w0BAQsFADA8MQswCQYDVQQGEwJVUzEW MBQGA1UEChMNQ2lzY28gU3lzdGVtczEVMBMGA1UEAxMMQ2lzY28gUlhDLVIyMB4X DTE0MDcwOTIxNDY1NloXDTM0MDcwOTIxNDY1NlowPDELMAkGA1UEBhMCVVMxFjAU BgNVBAoTDUNpc2NvIFN5c3RlbXMxFTATBgNVBAMTDENpc2NvIFJYQy1SMjCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANtCMXsK05wqTce60mQGZLAIL8wT 6i02PnfuPth2FAGDwUtPL4jLHBJW8uVJJEBLom3pyhPpc/jaqd1g6dddKxwK4Y2L vHW/c1j86IMqjXLeE9//u58xND+hiOhBx1QQpO+BFe4jpQW6NRKYqWlz7G5aPO+M fk3zDWEnEWRpoisf2jNOnNYVqRQdEY4+xZ9NHTsATS3NbAGFADRi7Vx0C6dSieI+ CtNsTRG6dMU8x8/IX40VzREyPtIqMSWtGwuz0xk6KayB1ADYuBW8mH5jfufIOLn1 /XSgVz7flasyfJ8iKbW1eoIgpGNyXJGBI39iPWTYZswh+Ok7swZskj0mPzECAwEA AaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FJByBGD93fqE7I5aBFj3z/vDcgkWMA0GCSqGSIb3DQEBCwUAA4IBAQCBDfRhZWOb blcaSjp0A8tREiYjHaDW9oR6Pk3xd5SMYE2axpy45nFjbfXCr9HTBz+mi8SrunUw P4lzgv+P+EyyT/Kmt6KRrm2z+CPr6JUaexYgsennNi/TRmiqdWRXY4gyrYSsCgJB jw3A7srAUvZSma6JEiP2E4skx3KVHmliwyBaK04KSkKKwY4b+oQIZVq2cgySm2bB 1q2+SMI5jMk9pRUh0anImbDyZPCARsIQuhUD5MOSYh+GiG7oTurvsf70H1RxuZrQ /RwhDKseClSVWzBiLtiDW3LOAo5UNjqyQAZgZcS1yhAsGcsPXB7eel783IZDbq7Q kK4RSUNGApEO -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFmTCCA4GgAwIBAgIIcYwvOXxAdEAwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE BhMCR1IxGzAZBgNVBAoMEkJZVEUgQ29tcHV0ZXIgUy5BLjEuMCwGA1UEAwwlQllU RSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IDAwMTAeFw0xNDA5MTAyMjAx NTRaFw0zOTA5MTAyMjAxNTRaMFoxCzAJBgNVBAYTAkdSMRswGQYDVQQKDBJCWVRF IENvbXB1dGVyIFMuQS4xLjAsBgNVBAMMJUJZVEUgUm9vdCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eSAwMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDt Ei4Xc55v9POZ6J4IVwk0JBFAH4whfhuvOMPRx+YU5fobul5m9SVp9+3NboJwr7pC 8LEZXCv8RYQYLHoXT2GFRhl8zsGNn1SedyVmD+D2+JLKKc4nVxUqbII4bSfmvk1z DnOv43E9vAlCD9UNoe19a673wfBszcKXoVj9NRWWF0yfv/XxOUtwt+dKbBw/wXBb z9aL6+9vMOhfyEZ3IWIWXsZURTn1dLpnJGilcVs+wfsJk+simfjS9XsCbI9Y4qvv 3XQh5CRplEDWwQQYDthC8P3XigXAXxuK6y7ADQcGcwGFjh/BwIqhWKZRuViRQg9u 4bwK6LsogxV15Q3+STApKULCwjb/pDx9Lvfa8qIvFrxhqJlYGKRJxmoHEusbfLTO 5/shgCtwpsjOrVUeHx2E0P1UakxWY8jdfqD5OdvvfFr3jDWlbipW+v7jX5NUcg5o 40krk001IpcUlWZPp3c6LiVM9gmLEhtxxXKnm7m86xygpclUg2HcV1WttebaeCt2 p/742/6MM6SKo0ZcrbIKEg6K5FCe8LjLmVNMZCFrijgq4IiGANQXrGay574tOynl +KeU24xY+NJLMJ/yxGJlUEdygM+kcEC2vUT+2b8oKy43x7NRDoIptbFvrX4sk8Cp f5H6xx818LuXyU9hKJCEQeh9IUDFyYY87ZqthZyiUwIDAQABo2MwYTAdBgNVHQ4E FgQUtE1mt9OzyJl8ATLQkTr31qgSMd4wDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME GDAWgBS0TWa307PImXwBMtCROvfWqBIx3jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI hvcNAQELBQADggIBABwa6wauVb07PzYsYZ7qx1P8cKoyb+RCquu9hewbilrylZYp oQQGks4kV/9AI3hOyfgwTUJVRE43on1rjmj+Dv5/37CfY1Hz4cWllJ+KIyhI80GL 0v547dnQCA9tfdWdlazV/hJmGuS+dVTz0U2cThPUnnA0bai6CjOIja0FN/5LeX99 A0F5Ew2fPfc4nDVaRE8+PKLlgcV/X3ZPGztub5ptt+0PyzIfiLRFDJwR0vgEWhM3 WZiBzkz05ZQoBMS1U8lUjXA/aAHbzBMK5CWjbJntELN6IKlJvAX0+Bto1rogHYJn ZuCwn1zKNdJFrtWIGdt6BpuMoDeHUSO+Rdpcs39rz8aoHDOKex2R+p687H07RRVP G6c7NbR581uCUOCcp+0WddtjgGKh2hgCaoDegqpETUQ4KKpu+hhjOWD3QylJWrok wL+zCpcdZ0laIrJnBJxYqfgMNFxAlrSHtUVhGeWO7wbekRXAuIrKlMkKdX1xO1iB M8j3B0FVmClDtcuaQ+ly+s/wizG85++5auNBnSE+DRWohb0bToeOR7IQ/jcYaoTl iRwUY+i5g6m1u+hjmnoZjMt09/gXCPGLGdi07B5uSXM/XCDdNSqWd+lGbxY7y6nv mwohEcjDpMkjRW0/YpWd0yjHnQ+z/jeNHUiyUOYluU4zYTbWFhzKMjcgdhws -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGAzCCA+ugAwIBAgIQL9Z6QyKTMpBF6VM0PuJ0ZjANBgkqhkiG9w0BAQsFADCB kzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE9MDsGA1UEAxM0 TWljcm9zb2Z0IFRpbWUgU3RhbXAgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkg MjAxNDAeFw0xNDEwMjIyMjA4NTdaFw0zOTEwMjIyMjE1MTlaMIGTMQswCQYDVQQG EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMT0wOwYDVQQDEzRNaWNyb3NvZnQg VGltZSBTdGFtcCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDE0MIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArgHUXaBYyu3ozOE3RkYQW3rEUrgL WI8FPV2prVHiA4ngBhL4AnhrXgRQz7bWBAxUHnk3IDzjfmMdRXeYFB2+diLcWqo/ 5G9AYiRjyDzATIcoPWt4a5g5lRpBf3NR/gf8FHzzj4QJ4fjCL6FOvTl9zGNniQyA BM2wgskAiz4JhwOdwnlCxFwhkSuVGmw1R2zIvzwKTur2hXDVxV/BnkfbXMIyYVoI 1nGdLIGffri+baHYZkNpCuTzcvCRSyhgqNXj3YSuKGVVn4QrSnXtJKYsdTHUhXd0 8oBVAmNB8nAI9MjCU5HbFAdlIAmB5orXmw/KDNcbX/3R5XSFXBD7msmmK55Dlsxb cnPQD1WZhxgbPfgpeLBv0XS85SC6Q4sUOGlkoXMPwRYpeU+bhSlosT6ZKo+y3EcG zd/Q6yLcHlccflmQJaMDgr6Myx2buY0quKEQ5/qtFv7s5VPGrcCXfESbgfN6pvn/ rvqsF6mmYL1nPHlshQtVrzHEw1mQDqHVfEg5i63juw7k5frf/dqdnltvGzIOpjfT qqosBBdl08ZORyStglCZQSvWs+cmWrE1m+ZxVeHIb6JEHchchPz5eAF2wT53k/Ki lOHacDDsZAquoqEdP4NDc0DS4IlwWa+NLtTUIQphpPT3I4ZDgCiyHEMMRdr8Bvgl QAd1aXjjphOD15cCAwEAAaNRME8wCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMB Af8wHQYDVR0OBBYEFMvR8s5I/QGf6laqV9F+mVj4P//gMBAGCSsGAQQBgjcVAQQD AgEAMA0GCSqGSIb3DQEBCwUAA4ICAQAT2NPko9gmzv07R++AvvujloXafZWcKQBi Rr5ICsoU7B1Osh71zkavWQEQOP3iZQu/+A/mddncM8qD764gV30n+shcID4Lhiy8 EnYDXNMhU6DPPvdFGSIPbiE3xmiHxJwpVaOQ6KkevrNB549H6R00xWQkW0wy7Laa DLhW4AbkQIvyEAf6jo5mIOYcS+Slo7suBulFe57J/5SKV8Fpo11lWN20wmNKpt1j MRiv7RYY2sFqPx/Sqpa2YW/Vgym0eWbBwVADHNDqLsa6z8aYbdYbxs4QsMnxQxor 1/8VNIY72Uo8bT4juwI9zlTDSiXvRjx5W46zwiqCEkVSlsIJ1Ep4nt1vn/mfcEqa o03vLfqqlvq0fdY2l87w2HzSL1ZUCgBg0DyOaOLNKao9LiCDy7JVRqDfuJF5KJJB Dv4mOEN103el3YdS8U2dv9yjLfIeD0kspRGwijYTObD1G5J3tIPdmJ4Fr6CjCdDf HXaYQkQBc7CyqTtS5bZvq4zy1Rcpf2/45aM0625FkkhNAlW2N6ECsTTfx7KSPQK9 NxoG4aGAjpIlMc72geeu5ZIXrFnEkqzfyCwnUkIeJh14h7lOi/dHescBcNWhyQui Igg4/MqowjtT3As2O+Gjyq33tgjDE1WvAzpptOmk0S3NZ9TDQspjX56ApOxjbHLE WOUH+pb4jQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io 2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV 09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX 1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P 99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw 1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R 8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFrjCCA5agAwIBAgIEVJGosDANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJD QTEVMBMGA1UEChMMTm90YXJpdXMgSW5jMSwwKgYDVQQDEyNOb3Rhcml1cyBSb290 IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNDEyMTcxNTMwNTFaFw0zNDEyMTcx NjAwNTFaMFIxCzAJBgNVBAYTAkNBMRUwEwYDVQQKEwxOb3Rhcml1cyBJbmMxLDAq BgNVBAMTI05vdGFyaXVzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArVK5kig4XFE/X2tRUy/8uc3z573P aPUWc28qWqN+IsxfJjK/0x/HXuexkOvGIvXpXhkSohLzvCL5iNX3O2HFGcjiY2uM 8ds/IqD73Fn6ZvB+dMZKsQ3JUh2Lt05M3ZbLmOYOQPu9Oh6kLJBe3oTWYednACoz DjOD8jeivk6oqkZtGEhGdyY0v2aBbyCT/PEy8WDyFi2fTkQdnes4LW2lWE0B++Jd xB6K/9VC3AwFp/bkhONn7NGpT5nen8YLlB/lMLcHqHnwYOqzoZzCZTea6LnBPFms YAvmBu04B1gBTKV+15zzbDNPIDZrVcpOVm/4OO7PlGXlSC9NPlDMqU45tv6KCBF1 xv17Srqj95O0nXjkoYuo7HeCKPebkSQe8fzPkUR76AZeKm/Kd4mAXRBgubZxolux Zifq92R8d+gKCi+PSFPitC+oNB/y5Mn1S74bcxH2HJlbsRHRRd6uGuGxxUN4Ob3J 6sDcg/sL4sLVyT9KQcWdPuHwJgKaU223hg9yTwxDC67EVGA2SoNOyVCmbQf68A/E 9AXz1WYd6+S/HKX9uOcYNzq7BBobhw3Sknt0joirijo+14CjSFeQKM/UQ1yUNy6L rxISTqo4pg21iRz5eWRtZfcRlD6h3D4ix4MpqWbEmY/NGk35xyWszPer86vmuP3j 6e3PKzkoir8wFJMCAwEAAaOBizCBiDArBgNVHRAEJDAigA8yMDE0MTIxNzE1MzA1 MVqBDzIwMzQxMjE3MTYwMDUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUmckQ Sn14uolWMU717DVzPaQb7W4wHQYDVR0OBBYEFJnJEEp9eLqJVjFO9ew1cz2kG+1u MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAII/6ndKCHTpbRuOrXnd 2bEQ8Z13TBfrLRjoL5TGU2ZeoKWRUrKs/MhQlA7FeaoNJs0VRr2bs7y1eIDfUM1b 3lk/+6a6APlysUPloJvbZJGpvgXXYvrbEr06hvB6YzX82lA0POZvtEIGKoErUh0e T/e1srxsYJrUpyjOpG4Ef+/eRStyMl3mzw1Sjy9AuNPfyYbMCQ5TYAfATzrK9iYG Xkacvw2+HVphJzp9YZO1p1QT3rGgm0lmm7M3vaC6SmXIIuDE7/CVzuifACmk+TIS nHA8ENfrpjx/VVDVQjH7uwnqhErNa3PWjKWUb4Q1mmVaeAgDAvxHs3q+jD4zZy3U AKpqnzgb9U540IvFby8qPYI+W1CAcEG1qGDA/vtYabnYwgwXoBhOBhr/P3KxN+6J b3rcpy+cyVfIgwtLgfHXNi8e7Pe4IGT6iwrmUbgFrFR77DIK484SHVFy+N59201K f5qEsAq4EHHYc3oWrvzF1G3kx58KF2tz4wExbfg6/BySZKXA2KSQwOP5jhkxrTZ2 7Lf7ZTz04PiUm+cYlB8qAnhxnkJdCm29O3vKcEr2xOedos5LmOKW87HWrcAhOKJ5 RkDH30jAB64volYYepq5wxhQFh+j40zDnmAuYC/pDOFZoRszKSuREjx9hTaieBIR 4sBFY8WLdJMuwrRbEWjHccjm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs 1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp 4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj 2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvDCCA6SgAwIBAgIQIWYVBQUnBQW8irAdrwq+xDANBgkqhkiG9w0BAQsFADB4 MQswCQYDVQQGEwJUTjE5MDcGA1UEAxMwVHVuaXNpYW4gUm9vdCBDZXJ0aWZpY2F0 ZSBBdXRob3JpdHkgLSBUdW5Sb290Q0EyMS4wLAYDVQQKEyVOYXRpb25hbCBEaWdp dGFsIENlcnRpZmljYXRpb24gQWdlbmN5MB4XDTE1MDUwNTA4NTcwMVoXDTI3MDUw NTA4NTcwMVoweDELMAkGA1UEBhMCVE4xOTA3BgNVBAMTMFR1bmlzaWFuIFJvb3Qg Q2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gVHVuUm9vdENBMjEuMCwGA1UEChMlTmF0 aW9uYWwgRGlnaXRhbCBDZXJ0aWZpY2F0aW9uIEFnZW5jeTCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBALAH52L70A1Vzme3V41uDKknVB7rqSSrZ4+PnGEP 2ygyLzv4LGWSLa66M5LAK57yH15tI12zWB+NocBtdYUKsBNOW1ZGizm9C4K7OkOb CLpG7vkX683I1+N1E96uUUgKziCVRp8C7FWMdKpa/PzqCTM1bqNHBsfdfoRoDscS ypTD7eZsAm3eAok1swTLRfh8R6TTH9/lXCPi8yJ7uUui/Rc1XUjpv/WzJWOL53jr /HUnvYhcpoU/Qd+VfN16Ro/+Htqxq9jTjs0GjMnYUkIRUqKDj1yDe+Qnto8foF49 0nV9eVOTBpfjA8eWLNoBPHnFO1DosNOhpOLTg31E+BDPoBoq8mWAvXfBmGV2rhIh Yso6vr61mcNbxNG/m8AKylgeFabXIV6xTQrlcHiaaOZ0ZjIUKh4Rvoj3BvZVo8Mf bheQVdGKQIlWQ9VP5qLJiGQABVE/V7Q8tr5qkXFA8aJc8dftnLZX9lnUKhHl1OW/ ux7RyNdfRAWbu4k6radDd34VYHyIXZvspVzSRq0Mi1RF1JRRVUVSqlzYEaz4ViJs 2dIU6bdOQoVURvgBxj0mBnfosjUb8J1CyX/+gCcBUMt/xaxU+mttloxBpKHS57WR SG93HIvCK3T+PFzEXZTOq/EglmvBDFpf+eU1uWyjEGfvkapIDu9It3ZYYtm+nkKz pL01AgMBAAGjQjBAMB0GA1UdDgQWBBTMc8Wjaikxl6eNoNhUwQp1tiM/pjAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEA LvKHSO2Znp8BDDzJCnhTfBg13rblbPQAgOGbi9n6+6r7ZbfSyfXXp8t+ybGicVht WTfW4DMQyrXZcttOJTeqpt0dGL31yYqceojuHwLELZJUfVfiXBkYIwJ6XEmVtpjn wmBBZUC77Fq3cZxQ8nN2+18N7zXPtGmNhehMkBcDC8mzLiA3YxFipk/jNOD7eVXn xsKuQv6wNGxJIw5yB3tmBVVI+xIPoMD6TtH7Pcz+/RZLVlDNESynm/exCs+m6+/d jriuQgh8pIyU6obHQ+P3PIrfR9IwQMgtU/VvEUnMIYyWQ08QoEehVo0fHFvYVlvr NHbhNTpx1MwhL541KPJa3p7k7kdqEOg4vUq0fQR/Ba5ICrQDvy6zChufy63dTdCH IbdHdoKDLcdXvpoVoxswGGyjOnFvZEcoktsRYSCad2Ut+axWE2xLo1//m6To7+dY 6HueO39qp745ChOUyUhOZmTYU0zsQWv9/DYu1w7fYQt7tUCs3UJJbZ6Av2CV8OnA P3u7GOk4tVZOp36KYu+YHvh4QKm72OnltLT542ec7FPPuEK0L5OBNaBs9rogimg9 923/f9NM93qUaAN3Qzs1UapTEj5HExQ5rNZlj6hG/zwh9NK/0EikfqdRm5cS9Zk0 FyNWhBNjyzTKH8q6qAcp80MkCkl//Q7UkPCrQyFinI8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCzCCA/OgAwIBAgIQVBIVn6uKdZNElMp3QFYu7zANBgkqhkiG9w0BAQsFADBm MQswCQYDVQQGEwJTRTEoMCYGA1UEChMfU3dlZGlzaCBTb2NpYWwgSW5zdXJhbmNl IEFnZW5jeTEtMCsGA1UEAxMkU3dlZGlzaCBHb3Zlcm5tZW50IFJvb3QgQXV0aG9y aXR5IHYyMB4XDTE1MDUwNTExMTUyM1oXDTQwMDUwNTExMjQxOVowZjELMAkGA1UE BhMCU0UxKDAmBgNVBAoTH1N3ZWRpc2ggU29jaWFsIEluc3VyYW5jZSBBZ2VuY3kx LTArBgNVBAMTJFN3ZWRpc2ggR292ZXJubWVudCBSb290IEF1dGhvcml0eSB2MjCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMiutUO8QkVLNWM/AkvF/9s2 1yfFwq5FZqNxhxZNiU9hlOBWRrjQRBPmc5DwYXhBiuAafjesAim+6P8CJsYafAqx j2QpotoHitUkhWgZkjLfnylgWG0qhYARNsm2wtOehAy6URHMVOmrBjASjyB3BcDG jZqbWci2hehwBwKxHv/Xac8WRothL0LNUqbYDnovhy3GLzwiQ7GTfsMWdtnM14vs ERvQyXEUwolJfvGkEKo1PKgbu//sMkDlvSrzpgETyIyXGZDOY/mwa333+YrObuCF 59uU1XogJaA18Kn3r1ooWgzI83Q5izE7IsxJJclvuFx6LiyW4y+jPsp5d2mRWvjw xVM3TlNtSSdWYsrl+XNgqRc7W6Ilry17ybfbzxkROjNxOVlaA+nnLAz/bZxyY2OA BVhThtwodRbC5fATWaGB/wUMmai2PGwuxQ4AmIHpg3dmQztajoVFTLLPuT3knDaT QHpTFSnUEZC6oWCKnav0Skpq3Yeqwe0F2p5bVuGITyprlSiGZlCh79pKspAKNjdJ hZdCeAdn5psgoQxsyc/P/neVhFp6Oxew70z3LZGqzxlvxvkSKOceCqaWzSGwA2JQ gwYg5uje30MWFrmBoPCBNFvLwYn28+giuM64Uj5RHrEFuLcDKwusdHVTJOF2uE8l dl3v0Zrzbkq4fEv4isAZAgMBAAGjgbQwgbEwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud EwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFGNrQmBTVxG7yCSJJQJmRHShDSVuMBAG CSsGAQQBgjcVAQQDAgEAMBEGA1UdIAQKMAgwBgYEVR0gADBHBgNVHSUEQDA+Bggr BgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMBggrBgEFBQcD AwYIKwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggIBACMuqoWXS6RcEK/a+D29k1gv ePsZdwM5FkdJclXMh+i9pH/SqySs59RQ7p3Yg8aZIPsWL4jGFzfKix6r0OJsB1i4 ZJGhEKFpN3Ve/tpzFOaKa77CYCEvwPmjBEg2Wze+2mz96ZaOnvFTfI9lRKdVfQuU TlT2/zK9L32cpV5CxEwp4xBkL+bPWjs0VShh0ScSu25Um4FYrNVenVcDoE3R/zd0 po3z+ZX9Kol1enk3/SZ5Lydzf6kZIOXQX5jolgWPmHnpeRBBKQFD9Wk3zFAQaLXY RE4O8pnjJyxqjl+7fbtrcUsGit0q2Ao/W8hyLlhhCg+BaB5Hx+ktuu+N3A6jI8Oy LbVHsYu0PidI59wIYgxU/kPXlUq/By9KQH4GpVGHJokF3TzKT/4cJ+nbiB7Asv7j 7x9+sehZlaBPqwqJAOBzsuccwRdQgIdM0kMZWZXSWxRbClvAfIlxerUKwIpFL+7E wP5ULeeVJHcFLu50xqCQsXPcQtagdclYWQWi3hG/WekNpybCbsBGisYe0/XqD309 cs0ZlUy64GiXjVjAau9597JoarhyNsMkDOgy7b3xn8jv3nXS23aplCc49AFhv2Y4 j2o93ABbs/xE3wNL+fF2JTX/Uh8IHdClFOmLBit4gyxxXE+Rh2PWDA4FiDyUoLFa VBbf3VHDqDYuLIJ8uZqw -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM YyRIHN8wfdVoOw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg 1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K 8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r 2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR 8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz 7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 +XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI 0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY +gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl 7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE 76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H 9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT 4PsJYGw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM 9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L 93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU 5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy rqXRfboQnoZsG4q5WTP468SQvvG5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi 9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW 1KyLa2tJElMzrdfkviT8tQp21KW8EA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ 2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j 5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A 2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS 5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk 2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk 5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGfjCCBGagAwIBAgIEBfXhADANBgkqhkiG9w0BAQ0FADBwMQswCQYDVQQGEwJD WjEtMCsGA1UECgwkUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRhLCBhLnMu MRkwFwYDVQQDDBBJLkNBIFJvb3QgQ0EvUlNBMRcwFQYDVQQFEw5OVFJDWi0yNjQz OTM5NTAeFw0xNTA1MjcxMjIwMDBaFw00MDA1MjcxMjIwMDBaMHAxCzAJBgNVBAYT AkNaMS0wKwYDVQQKDCRQcnZuw60gY2VydGlmaWthxI1uw60gYXV0b3JpdGEsIGEu cy4xGTAXBgNVBAMMEEkuQ0EgUm9vdCBDQS9SU0ExFzAVBgNVBAUTDk5UUkNaLTI2 NDM5Mzk1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqj9VtYmvdhQG KmQmlDgPX/bcBG8xRfUK/Tt/m3Jv+EB8/l39NJkFOJRJurHwvfiZXMBR+qoN++Zx FYVjESp3BpGSBoiz/BThmUa0KYKuhIPutSaHbviLVUSdQNj/Klqq6H/SZeEUR8J8 Mf11YQobjIBKnrTiLhRHMe68BVGupn7PEbjFSL0FVMKE5Kdoa/i4+n4oybnP5CFP ZcmIaKA42XWlETtMHG5LHtSGbMGtBUfTLJQNzIctGi3D1szehP7sa8DhIxOh05wY fuBy11xVvEyzQDEbnEDNmuuADnGu12JuWhZPH/ZlRdGfeoVBGcJ6Os4hkuSUcEy7 qEHGxLs1zfU6nmOpjaBq0SBEqiq2SKVyw86e5FhIRwl/AkHzDRxtCXjw1xTRoFX8 EdZaGgB55TvmCMtSnqQJq2vnbJwqLyJ9+7lQst5Q0y8McrnWs7ezCObre6z0tMX2 wTIfpxkh9dxeN6rHH1ObQz7mnp/aDddWog9TaS1Vv+uGeBG/ptdaTfMOk3Pq/w7Q 54/xyLPw2BhzbKVyiPFwTEdUtpta0bwmN40Y35trLtsLJbOKsuOtBlxtu30XAwcB ijCXiXRtSpR3Luvuz7Aetep29LUUOJXX1dkvP7KkJsxNo1yNCfNeDIUyzlZsAgjx S6Orv8hUoAWFdOR1HXq8nDtgPWr9GZECAwEAAaOCAR4wggEaMA4GA1UdDwEB/wQE AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2uQNI+9UYoaE3oO3MaIJM UjQ2DTCB1wYDVR0gBIHPMIHMMIHJBgRVHSAAMIHAMIG9BggrBgEFBQcCAjCBsBqB rVRlbnRvIGt2YWxpZmlrb3Zhbnkgc3lzdGVtb3Z5IGNlcnRpZmlrYXQgYnlsIHZ5 ZGFuIHBvZGxlIHpha29uYSAyMjcvMjAwMCBTYi4gdiBwbGF0bmVtIHpuZW5pL1Ro aXMgcXVhbGlmaWVkIHN5c3RlbSBjZXJ0aWZpY2F0ZSB3YXMgaXNzdWVkIGFjY29y ZGluZyB0byBBY3QgTm8uIDIyNy8yMDAwIENvbGwuMA0GCSqGSIb3DQEBDQUAA4IC AQAZVAIlg9silosdlZ6Z2zTOk9AfLntcYCRqDNeFRHgfHEnyFPiDVBmmnTJmuCOm O4Yqnzb8F/xQD2DGN/0kqPd5p46/2AcVVF5SDL74ptjIQUTx9hPcgxlbr91k9zMW hw8VWvFkvNTnVT8yOIma88xIxWwxcZKaJhfCfEcCbTUnn/Ma4aodDXQRqZN8Qahv u46cxQHkc/a6UC7mENS8bxOaOLlpRqUG1vJMbDerPPjbGsZV8Mj4HSFuLwBqseJt WgQtfd0JT/bvFC/AEuoJGSsayqBxm7E6Mrz/QxjzfS/1LojpUbbxSZBM/ybHw1nd dF/BUF04XJ1oVWlqtEB3yV8yKUhUk8GzISN2oVUwaSM/MUnEoc07dlmVWoK0rXG1 vqaRzIAVSi/OlK4YVUl1IES48wGbwXgsjhBMp2StrTrrTB1WLn+U1B7QCtXJVIEO Hv73lPlhOj817tNgyftIsm7C2b56bpgFcACj0RfHxjSvbPVNj11SDN2Am3pt55jj OYVcP4vMRKJANjKTElaQAp4+WWgCH1aIHq/B/g97VY2X2bumk0e6fPhHtjnXjPJA bIecDP4t3dxx/A6RCKRDPYpX3d0H66eXUdC6hJmti3n+yQSQgxMr6ZcNZYnyES03 jku4u9J6OSrF3NBdDd0EJ5ifWP2OhrsFf/DtN5KQ3Zy9/A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDDCCA/SgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMCQVQx DTALBgNVBAgTBFdpZW4xDTALBgNVBAcTBFdpZW4xIzAhBgNVBAoTGmUtY29tbWVy Y2UgbW9uaXRvcmluZyBHbWJIMSowKAYDVQQLEyFHTE9CQUxUUlVTVCBDZXJ0aWZp Y2F0aW9uIFNlcnZpY2UxGTAXBgNVBAMTEEdMT0JBTFRSVVNUIDIwMTUwHhcNMTUw NjExMDAwMDAwWhcNNDAwNjEwMDAwMDAwWjCBlzELMAkGA1UEBhMCQVQxDTALBgNV BAgTBFdpZW4xDTALBgNVBAcTBFdpZW4xIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u aXRvcmluZyBHbWJIMSowKAYDVQQLEyFHTE9CQUxUUlVTVCBDZXJ0aWZpY2F0aW9u IFNlcnZpY2UxGTAXBgNVBAMTEEdMT0JBTFRSVVNUIDIwMTUwggIgMA0GCSqGSIb3 DQEBAQUAA4ICDQAwggIIAoICAQDUppeo8vSQEUOttIJGQfEvkW9jos0NINy9DDiK ZUoKKzqodKl3oYuO8i+B94QYza3rYraSfeBB5U5UODeC78vg7c+7ysyjS/db/rh8 pwhty0PETCIUZuOdA7l3IatEayFHI8gg+irLkXYddWz4m+kPJulDL5ogBWgYx46Z hS1BB6ZkjljhjZWApE1f9QLYgXnb1effoiL9FKdnFuzZWEzKqd3qGo6pCGRPUSG2 cqJO/1BxvTtl5L1/UxGu3xA5e132R3AX90ORA3phJV8s/PiJETzsOVQWScQhmnHg eYt2HXY9B1m4B7GM3MfNTuH7rUNNP0DvIWIvMUROacdvIsurVEvowvoRaKzIbg7e bMUnlglRAk0Btle/MijVCUOW98SItflU/ho6arcstSRk+0p4csP82U/ITiO5KdgN oUhBkwJtvxKFm8bFYC3wkfyZ/SCUnnFjq9VJq5DshzmFf42FzAvo20s7DvzCdn1G 5zkmnt9V3x6E+UE2JmwCWSuO+7zpHyckYgRnhOE/2J0YTpagJe7KKANPAlHP9zU3 aaS01tbVHhlDJxYfR1HuSglMEVq2Wz1h6DsQvtZG5vQc/bhFvXz6dVrs4VIjDY4f hpdTkVybmyjWjuVuJ60gjKfBQamXN4ss6m4YBZf2zgNS8b15NJtAxyOSdPNv7aPp WfBVSwIBA6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFMuw3T2MPN9iLCtmPJ486RVtcbTXMB8GA1UdIwQYMBaAFMuw3T2MPN9i LCtmPJ486RVtcbTXMA0GCSqGSIb3DQEBCwUAA4ICAQCifVUEZu4WFLyCgYclGTli 9P47H+HAcwBxynWp4nPxxQ1Bo12OwS3ZZVvZieLwjsWgfb3LzEZTH1/tILYCKtYT 8p19UUpAVXGtnux26kUgjqr6ekOacGd+E96Y6MuN3R+sNNKhte3+uOcWz/jRODCN NInSzn2B0h7/URhTNpPcCcsIFrgI11owkIoK+S+1z8TNVHIqxr0B51gLbgZAtAnO tI6zmumJkZSselTh++OELIOgT/7r6MH067Ym0zjELa2sRYA0bSE9XYU64nv+VLfd 6IVUy6TxqylQeNcktaMvnq8RZq4YuP1dKM9A11XgLOtSMWhDZgWXkrvF8SEs/RJk MZlDb4udS2D+FF5SsyOo4Zh67hTJoeLMP3YhYv1rDdm0SpXmblt6JMPTxtYfous3 a06j32Lr6w5KCL/rGIj7RxqtwlHD1Xz3HyuzyEpQDmlYIGIBSlvKY5YmIq726ZxA rGcDnZ1pFcLA+F2nJLEnPL8F4quiysmwLX6jwTEgRiFlkt3K3t+TG7xtL1+pFqRX hyxymlqCZ9FE4j0JCoGMHhD9xjRo7P93YXZ/Jvfb/BJGEqrA0fh5haICzIuqpK1s FMC9/GiuRH0i+QpFXewE5vrjpMXm+bIZw9mMqJN7OoppO1ITPB0zAk6WQJ+5lf2T FzPByQv2/b1pEPWtKfvj2g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFoTCCA4mgAwIBAgIQLHA+VOkP2ZggzMbZ9UY/NTANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MRkwFwYDVQQDDBBDRkNBIElkZW50aXR5IENBMB4XDTE1 MDYzMDAxMjExMloXDTQwMDYzMDAxMjExMlowWjELMAkGA1UEBhMCQ04xMDAuBgNV BAoMJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEZMBcG A1UEAwwQQ0ZDQSBJZGVudGl0eSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC AgoCggIBAOFRJSx4u/rui1XDTiVkGS2UQqTm3oQPITUo3DKJPvs0c3tX6awSKUoM mCzOyb+kT6VtDs7CzhgJMRBwcg0ia5798whuktLAJc+1s+thfxeE/HVrtaxXF0EZ DDTVL1Fu1fdRa3FvMrHi066g1jsUUEgZdPztr7UgqJLgP64H0VC81d2v1tD5zs6S uMaBjMX5OY2+9hsumjhkv7fNcuf/7YlauKR1WuH+rzIMbSJukzWoYuLArgqX0bCq PvY6UB6bUCoH25eVYAM/o6RdGVUhJzpJnsvI7CzMmxdI0wgQsqlvIQH0WmHd096J XbUK8+AV1wZ3C17YaFjfoHe+XxQKRL0tHxo+8aosXQyFDOej24s4BqVbd0zUyt1X leSj6LJkd9k0r2gdKm0/MkcmmTOfCmBoEVZb1gLxhyrYadhRKZej3vchJozd8yyM BY+ZNkqQsVhpOf2U0xfWpinDUAvVu6MhQE+xBxwAZFfjUVRz4+sZdAKIdw/RflWD AszZzHSlAWyvlbC52RindZoeTo9rXkNHKjGEA6yIETDos7F4x0PhrQWHnGhLI597 ND/M/e+cQsvxNhELNdqaeqGvhU4uWmwneQtFgSV2ZG9k52jKluUEMQVYnqi0j/h9 VsTtKDHNbYnikHh78ZAalERJ04PvGCPHamW+n+q0e7VjBONc4Xf7AgMBAAGjYzBh MB8GA1UdIwQYMBaAFMCsdqLTXf/2zRYAWzinf1V9hVlsMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTArHai013/9s0WAFs4p39VfYVZ bDANBgkqhkiG9w0BAQsFAAOCAgEAfNPmbXRLuY9du1uVIvxlr0psXoETrLoUCE2v 8Hnx0iVCwPjZZCoCNcHhKg86fWoaOhZhG0FGqHVDv9881e1MO0O8LJA5/kyOeetQ vsDNWFihMB46a5GR4TRxlSEUoCASy4MqzIGuRuAebbIMytOCiPpua3i2XK28QSva fkMLgjP9MqwF/KmKfE5YrTcWCfRgdMVT3JNtZYC9cSCF8RCFOGQj0yGCgeu3bSZl TqvQ1hB1huroHTWf6HdWsZO6qfl3BdQeIg1LuIflM58K4QG8kSQurL+hAzASN06V 3rziYz6cM+bYWP5twY+2cwrBGkrB4IsqxzdCZfbFyHXe+UxlqDb/2+ldPczGY/A2 C3sCT89pvcLvpZ4hTl616jBEo4MtMYYJJKRWwYTz63w2czJtF6HnpTCT01q6h2aM BmjJbhNI75kpUd3FBDdj3lY7jKX3XIVAHPDULuM43ojnpoiKkmo7gSehjl/9LIJY lq/asEdwPg4kUwymUeqCo8ttc66xcAeNM4A2P6ywPl8eBrtuVfYZK+xq/ZuaMnqR ortgZGH57BRmxsE3vrrcsNSvGhpdd66EVqGxzGO8kzfDRDi0hDFjuKX4wrGIoNnm RdlHESm7na7pbEGyTl2VwHLlAnbv0NtBPu/gL/ukgvx60RunN4pJo8d/DG9CNhx9 gMl9JH4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA 4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV 9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot 9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 vm9qp/UsQu0yrbYhnr68 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzzCCA7egAwIBAgIUaKX9ptAcXj/P5PmZ33psbzmpf/wwDQYJKoZIhvcNAQEL BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n a29uZyBQb3N0IFJvb3QgQ0EgMjAeFw0xNTA5MDUwMjM0MzZaFw00MDA5MDUwMjM0 MzZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u Z2tvbmcgUG9zdCBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQDicuzwRxAiw0TKBXlbWdg6KyQhJOqviPh9WgVlwxhIAQTBfloDNXlKw8Fi W9JegvcM+7n+0iEdXIe8JuPEpnuZU5cE2N8SSj5lRefOG2WpcDmWFmKBzOngG4K7 7ajgQmvpuskbS0j9nUYSQOUo00xH+mKIZ4QNV0wPcamFf1blFuijQrpHtt3o42r3 Cmnl8xTjXFXdh/9+PFxN+ckbDptO7n6s7E3ToiO3iJt5oIpjRx50V73Hrv2Urh1K RcPH9qVTB9Vp+HPlZje2pTB3qsy68AnFKFeD8KIZ8n5FtGzrSSK6jjojHB2Jso9p RBMoumJVEYKOWX58TbqHt+4z3s3ZwvGULVM7pNAWVA8RIQp+WMOugsHE1SV3D3bb DV73YjO1p/zKHvOGilOI3cIyHz523p+PDIpKUC3IUFEGBUFXm6R20BzGbhZIJs8y R1kWk0tK1J+6fu0f8wV3Q8ctYvFg1Ywo8f4WI4LPWmufbmn81KhJV/c+kglEwl0o vSpUM4ianpdNLK+9C31KO1NEvcLBLdU0zwKgFAlRSorCqgARbprRHdc82fHBftgZ UBLEkSthBW37Mo+HrHrAlbaNB/Uo7r1oi+/+TQZDzRcloP7iVCa05fiQ+w3Yogwx c5RNe/tSFKtlUQoD2vJmA5LffEWXG049exBRp+mDjbk/tJLRHwIDAQABo2MwYTAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBxjAfBgNVHSMEGDAWgBRhteBC 3ravpyDq9iTIp52FoFhT2DAdBgNVHQ4EFgQUYbXgQt62r6cg6vYkyKedhaBYU9gw DQYJKoZIhvcNAQELBQADggIBAHqni9ztZvbdyRDfUPHRkDI9j9qRssdTrnH5p+zE aOIO+o4aXyqS44PR/Nry5XrIrKQXLea43ewqF1GidWkoObpYPx9Qs+3DGbcW9cao Wj2g0Hc/UQdFrG+flMu/bC4PiQmSNBk57XqyWWWwdu0nRh1Dz9Q2vGiKm9Tbwis/ zl1UmcoiwXmEmP+6QVi/RUmZuwkblo5YTPrISEKUG4nJ+VJmy51txA3pvF831boI Yf/VS4xj6P734NwZE+lSaraBLBhkbN7YMFf/ixnHv7dyXlauw/YZ0v2u6balMbgy Tsm8OhspH4lhsPvH+4gGKcNWpk1iEPCrUbdk9CRTkIM6p66pEQLgglQjvQS+NLTO 2ao+VJpIAoshGBL4mOCqqvmrriu/tWuDnyLQWFgFFqfdx5Ppe4Qo4tXuqDX5zM62 8CdQUTOHMtRkcojYNUC3rZvuWhSpfoCYPV3Rd3TK+JGG10Lp3KDvMCWfyDpgaA8t UfjxlrBF9ICotJGHKUMpkTmDNWJtuOn8+P6aTihkfg2QaQPyq00+TtGOJwNEl2Da eIpljRZ1/A4scpt4imdisa4sRgWQEThX13YpI6jAfQnfh6vaWx96EzOBsvf+HO/C nmVf5Bnpcq/INRy++9P43eTYwzlO2UNgq3U2VxvLBVrYQ/w3JVcaPbVW6/Lv2yYw saDu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFqjCCA5KgAwIBAgIQMmmiv0BrjbRHg2Q8iw3JQzANBgkqhkiG9w0BAQsFADBm MQswCQYDVQQGEwJTRTEoMCYGA1UEChMfU3dlZGlzaCBTb2NpYWwgSW5zdXJhbmNl IEFnZW5jeTEtMCsGA1UEAxMkU3dlZGlzaCBHb3Zlcm5tZW50IFJvb3QgQXV0aG9y aXR5IHYzMB4XDTE1MDkyOTExMzIzMloXDTQwMDkyOTExNDIwOVowZjELMAkGA1UE BhMCU0UxKDAmBgNVBAoTH1N3ZWRpc2ggU29jaWFsIEluc3VyYW5jZSBBZ2VuY3kx LTArBgNVBAMTJFN3ZWRpc2ggR292ZXJubWVudCBSb290IEF1dGhvcml0eSB2MzCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALoeomkbaE9cj7r0I8deZgV4 hTZYo6J/Z++iDBaSpEqL4KCSh1U3C8TRxNBAQ5cyUE/slUe3P69DBeWElwnvVlTn QzNH/a3xOpuYpOHkUaO5rIwL7iUGCfLTujVnYYzCvSbL12PM14Mz2Uzi7/kbn6jL DXYBLXLJIrtokd6QDzs9tEK9GX2fhFw8fkI3hrFgwkiHUk5cV/7Okq7KPla3s56V mpT4L6HQoi7CVFpszMzWrUtH0C6HgjOoe1A5pyossVsnCp+t9RTr/I1TsnMrVCP0 jJeZl/s13My1+jMUJo11pySm6BQuLaaAKIOaP7jKO8f1GOD97I55+6pCbEpLFn7z ggNuuucRBqWfhCvSYG3pRu5BWpa5FP0cP4YS8VQmJv1ngC/lqC0oLkO3ZMLv5Ld+ ltyEiyfZdj2YgVMU3EJFoVRn+doYZpAKtEeQPAHlK6Nm72/7MoPxM30yIWylRRU/ L/NVkUiTnyXPLTw5O1INGq/H36tvgNiQy55xcmpCaZPqkgA9SQTZo1y6RfsCEP+t aXRSpThjmmaIBLIRuhOqOdWDX+1lW1PInVyyhaB4cDVNXCQQpPYxKpJVQdnzF2yZ E1j63SjQbBO9W4eNk4OtWClWFbRYJ0qbEWygpmdFOs7Q2M7/kDPsWjFND1IS+632 YV/kL28NZjDloE/Pz/1fAgMBAAGjVDBSMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB Af8EBTADAQH/MB0GA1UdDgQWBBScvAHnq2Q19TGbjbX7F5mIAsub8jAQBgkrBgEE AYI3FQEEAwIBADANBgkqhkiG9w0BAQsFAAOCAgEAh6tq5OdrJFI99iKDT1MERTKc YVoWXJxEtaPRltBA/s9mFV5+QAAgFf2nqmTap2FmaMLdUnEloGq53cDNzoYI1Dw1 ES999G/S2gyXA2WXg7Q+OssJdI3rBcp66YCwt1EtIpPjmhnu7ZcIIYOtxwqRX8TK 216vuOeMujpJ0lUDNRkZUErihqe7eD2V/bEfRvJPZvL7v4VktgojGJIJnklFMbbW FFee/IlFdH85zMBqaMjPR9DhHsfTLy35LCQ7/Gq6lBPezHLyoh3LH5/Vg3cmXn6b oK9pn3jbpcFucVxIQk4r2Hi41Q+lP2zLj5DNR9iQGUmF1mz84quqQr/LE5e/aUR1 YzUt2qDH/WH3ykE9VJz0NsDkbiFIn11xYoHT8iXmWYxZQSZIp+PrZ2rT7DS3mPfM yqM2BpXnyDBZ9//JodHkebzfEx8u2bN10QS3IwkhzB0hHCecDiv6wYcYyfr5SYOM Ehb7xRLOOw9C+vAFZX6ox+tSSvmYXnGjrBLHKHEaWnXPh8ofNygcFJ2QUG/Gv0rM xyXPMd1bkU52qBHVdmbZv4BzYrDsw/5EvM1ZEwsMLdihzKpiTVRFXqRSo4xXPBQx k1TOpRZUXi1Cs+5lqbadP2zOYdlWy97qoFbebYYD+reBaozS2PPXtsCsKYRZIw6b l2rmoM7VKlQY71CYeSA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT 3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw 3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw 8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkzCCA3ugAwIBAgIRANaWLsEKFZMSr49jvNREyVswDQYJKoZIhvcNAQELBQAw YzELMAkGA1UEBhMCVFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBM dGQuMS8wLQYDVQQDDCZlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMjAeFw0xNTExMTcwODIzNDJaFw0zNzEyMzExNTU5NTlaMGMxCzAJBgNVBAYT AlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEvMC0GA1UE AwwmZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCkWR+gL9++4Pvp3LWJ/lqXA8k6d6eO XK/y4xg59ardD0bSaA9XnKdjYNNYzjXCp/aIwk9/Gyjp0KcAxBdNbeIPxQ4mIyCr 9zoookwKC8yOzuYAmlpADdRQGpvRDZyU+dvuXNDxigfNmitALEmkXWJfp2vf7lYI UPNCGGwxsF7lnHOSvA7SDH3FOFe8u1jbJhkC7eNDhIpOVmvbraEx2cwiZ5Z4/3ed zGTFMiBq704w1SQl/Yh5r3Ea/tVLGxWIvBhwqr2tOApmMEbliYXVdiSpqbPmWWAP tKlTwjqdRRrWruN3XsRiNjMvMMS/lfEtOKV16NFqky5Fh0tKot+/WCeaymIZql7U sYBJlt0r7F+Pm+Cdl4j1hAOjr7Olcy1BuuUHt29rcff3yVqvaZmzL8hPQutsa3Fn eN8KrE/XSoUARhrVzbif6pWdD3zRxgWF5gjeiBeB9tW1buqhHNdhquNZQomcWX6x fGQ03WEjKjm1EKv8hqlTGsXrauKATlmRwDiJ/rNd1vuR6dewfdl4CMz1K8wr4aHW lHPB/lH0jH0KtZqKufXa4Mmz2I+qgoONaVMt/QAEGEqg2lTheYyJ63/1gueguXdN rvm6AjuIdut8XbNaE9t8KRZrmdEd5Eghog1eAYjovvGYTT7HFlccX+EIbxxMWENW 94BljHEOogRnTwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRy W7qqcjjuJZAktZQi+gmIyosK+zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEL BQADggIBAAaj8bZzVcZnZiHlnVvWlC5KImDyVAGQof21v8CVvxhfLPZrNQ78Mcjt RA6Sl9yv3VbPtR+6cpwwyJuxkcB2d9QPGpUa6U0UiKHPawKmautkRU1kjd7862zy UwmhhVEV0E+eYvoRuc7IJA5yZIh1NCMwKj+8PDnMzN0LNru9BoKPEgHFcQXRJKGZ bMrk96rtitenCq2v8OCAu6GyP1qHZHCGM3sNHtcAhoNDl3X1O8FI/bYOQ6gCbrg+ f49O4l20fZ4wNC+o8esnh2gNWgpNAdvJFFiV8ppNFqpz2/QliBc4t69ZCQm0Hy0P q/W4J1XuRTAzuO0bjryIbK/4Wipr4KyxBSShCfyjD/OwLXuWuraUBxVFjincWA6p Bdg7OqB7zYrHZoKXz9Yz4Gf8pttALwXlxYt6KnrwsDabDBj2N+lBof2xKPlva73r H0xjcXtQ3Sny/+73x0Vf6DYK6GxbIsPowOcm3OOolYDluToT2wBLGv2uM0d+eJTj sV0rtVa1QoufgcX8k0wQtboKvH434/pUbfUExXCzqQTSUdeFzX1vQ49ZaOUxVhFx +WQpCRP+0B+8iwA4stDKNFZ2EDlWc2bD0UnZvldPPxZ9ani3qIK4W86uhYoKQgwD 0RfEGPfYV4jGgrgHuT79pOku3G+6kJLuZbBQNNMH2gGXD7znc4J7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIClDCCAhmgAwIBAgIQeThLtBkajXQizP+FMvLkujAKBggqhkjOPQQDAzCBijEL MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkZMMRUwEwYDVQQHEwxKYWNrc29udmlsbGUx ITAfBgNVBAoTGE5ldHdvcmsgU29sdXRpb25zIEwuTC5DLjE0MDIGA1UEAxMrTmV0 d29yayBTb2x1dGlvbnMgRUNDIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTEx MTgwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGKMQswCQYDVQQGEwJVUzELMAkGA1UE CBMCRkwxFTATBgNVBAcTDEphY2tzb252aWxsZTEhMB8GA1UEChMYTmV0d29yayBT b2x1dGlvbnMgTC5MLkMuMTQwMgYDVQQDEytOZXR3b3JrIFNvbHV0aW9ucyBFQ0Mg Q2VydGlmaWNhdGUgQXV0aG9yaXR5MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEFOED C2VvrVnWHu7Jv7RMxcZcLzDHn1LbaGHAaRDiknoaw7+SqIk5ivvnoLtxpKDD33fW lDcTX35TXVC640wIx2XiQbDmWfKc+MCyd8EKkSZ38mm2u9BBPCqIGpSRFsY+o0Iw QDAdBgNVHQ4EFgQUm3vryP+D8lKYRzAKVvg4vuPrAM4wDgYDVR0PAQH/BAQDAgGG MA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwMDaQAwZgIxAKlkWPecuRNmIkl/ stEC6RP8HPukNJLkygcNt7FSeCg0y/IhVpGGhsiKC68yhFRliQIxAOx5DZ2J8AwY 6ntXUq0L5tR5W8ub4gZFdRi90Pyn3cfhxyK240EkXSPmqJ8AalAyJQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4jCCA8qgAwIBAgIQTANLrGcYTH+vRAhNgpbHsjANBgkqhkiG9w0BAQwFADCB ijELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkZMMRUwEwYDVQQHEwxKYWNrc29udmls bGUxITAfBgNVBAoTGE5ldHdvcmsgU29sdXRpb25zIEwuTC5DLjE0MDIGA1UEAxMr TmV0d29yayBTb2x1dGlvbnMgUlNBIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0x NTExMTgwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGKMQswCQYDVQQGEwJVUzELMAkG A1UECBMCRkwxFTATBgNVBAcTDEphY2tzb252aWxsZTEhMB8GA1UEChMYTmV0d29y ayBTb2x1dGlvbnMgTC5MLkMuMTQwMgYDVQQDEytOZXR3b3JrIFNvbHV0aW9ucyBS U0EgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAhN+opqOMC3geyE0Zld0pkJIgNZAqlI2CMy1wElilCIqewQjzk9Zo wC8Uvnmk/H3M1bw+j+2cSgJhWT2qw290ANL4GjTUVJ5qdEeaL+DS9w/3w90/pb/B +n1CaWAAgOw85ruBN6QeBhQ9V4+QpDVKNHOHthrDXZDvBk1wdjY8gontz2QZgyVD Thzi8WpShv5R5H443xWNTGxgQUpPsEBVRjl1yYE5AHOKYuoPZbePT5dAzs/uwWoo oHGpmSfRPck1c3qAmfh9hrmdeTrt0yr6fqa4/1cqc7Kmv9qJugYb2mWg5r5glIj2 32bhJ2ob/tBeqY0giwrEH36IQS+ywdDztmjtyDvx76oH3n7XIuCB9qXqexb0QlSd ln72YhZTzf0Kq7JCoU4qiEJ1g72M5U165x3jTLje46tgOC1nKf7kX67CqOi/rmz5 67NS8X/p7MIv2Z3KF55C+jtYwT6IYk9fk8GXbWaPHCLzmsH07blrGn42hMgxuPBe K36V5HnPdUzC2AS/OI4os91btthPI26S6DeVroOu1vw5KkYGH/GEdSHWuE6mKpdY ZfWaGAHX9cN/KckQ7nNKQ3Z70aYwUf/WKx0eYoS++b5pl5nHDed8JFB1F/2kIOc1 aANglKfZDcYaLOXiTtXMDsB6MFbvYJK+2S71x/DoRc/ahq7v2HepEicCAwEAAaNC MEAwHQYDVR0OBBYEFA/xSkp1dAURDB3YW5nrv/6qfV7XMA4GA1UdDwEB/wQEAwIB hjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQA9y9JGePX2Ohfo w3tk0cW7kHiN9U+5xC2X+wvmxbjxturoWEs0rXd5LDUfcn0CPu610BaKBjeWte9D 0AkQLJdmx4EfHuYnxYKRWF7zyFtBaICDkbmcgfgn+kXf7nnyXG1wAlTuwFPYQ+sF esz0Ud2p1CJ9ajvy/ojUUkk6hZJkU/hqU2CIj/Jb1K4rUuDq/1R+oeTvhhungwsG Zl4wgIxVoEcz/2seREhLYaoePuhMZMfYbX0Orjw8Qj3KJBpw8WEUnDoY1fAGKZEi sjo6oRZUYxr5M5VEnySjIWQECOKb1d4IUhxiHFMWRzVCJsenDP3zWxN3Aoxc4hbw GB/ZffXfAiSIevNe/xcOs2JnoauxF449Okaw9UaMq4TY9Q6hIOvC8Jl0PY6zA9gk xWzrawxTv2Bp3YwoxW/Pu9KBdyvGfLHESmwVEDcpXa74sREFxBSN7BOjRP1Ni2i4 wf+d1TcuSPgofNz5c1PZtgF1Qnq/C99RULhTsuHudJDLvKrQcYOiq07JELY9HO9A 109DkDO5AZZUXSrVBluShrgGEIEGyJHbKSCyU73zS1tM22kfiW5UP9eJXee1zQy+ P314OAHStmemz1hIlBpF/ZBzScq1Q6AhYo1JBCaq+B8uP/IuofKr9AYesC3EwXBC Pf3DUUmIAA7Kgg2beQLiwC6T3+Ty8Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcDCCA1igAwIBAgINAJgzyagAAAAAVlS8bjANBgkqhkiG9w0BAQsFADBDMQsw CQYDVQQGEwJIUjEdMBsGA1UEChMURmluYW5jaWpza2EgYWdlbmNpamExFTATBgNV BAMTDEZpbmEgUm9vdCBDQTAeFw0xNTExMjQxOTA3MzBaFw0zNTExMjQxOTM3MzBa MEMxCzAJBgNVBAYTAkhSMR0wGwYDVQQKExRGaW5hbmNpanNrYSBhZ2VuY2lqYTEV MBMGA1UEAxMMRmluYSBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC CgKCAgEAtHPS1mXTAu9YOvSCgtOn4Ipgsjr1sWU4pyQOIWt96aCdM6J0za6RupS1 zMaAtXHfSHHKdUunv/8m64T+uXIWyMJ+htS/r+5jNbnA5NoFT7hIniIo/1UFI2uB TrMXESwqJR/k4d9hyDzyVmnQVX2WELKoe1aQW6ZeU4tB48eHxzG9NDnsGSHZgMTo DdvaAwwA9Kq1ggYlDMXZGmKd/QpJBfwcvpNG/M6Jkf/NzF9IX9w40HVv0i2rzCIS eIgSH+DVTne8LIlNdnqIm10H2rNnmNE5znpGq8/2fVclE/qExANwrwx2DNJAJHxZ 33c3WVCxJUZOQh0IIglyVcRC6m9vZVnUTuA9o6twfOYJMFV2Yonzb9IKprNuGT2W hnpmlM3yzHrwBwizaa4b/xxxGKJE+dvWDYQQgXRJYWLXEPABpkXAtdBS9FGGPeL3 Fila+kqeJ0uORvFyPqf1pAzgCxeaIv/5fqs1jgGE1XWTf+Z1qHpk3mI6AkcaoCPE TD/Q3E4z52y7+vYYECs0MF/HM1CZAumxWUZVZaa6pIMYi83h8coY4tkg5reEhx8L VnxNMVQm8plWyKZZ1oUz8pDMKFrIbKTLpkdGxJpVOYRkjXfnCj3D0BL3dqjMHLMf WIU6xDaN7JrsDuccyZ9P+9B6BwzGBbCrjbpyXU4j2W8MXPimctECAwEAAaNjMGEw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU/hGi bBDu3uIDuFWCTiI8huQ+a1QwHQYDVR0OBBYEFP4RomwQ7t7iA7hVgk4iPIbkPmtU MA0GCSqGSIb3DQEBCwUAA4ICAQCkgIYu56adjf+CV2Ny5xpg36uyubIBEmc4QOZA fFi8zEhxWwGXnHkcHnHSO6PY6KLiGAGlRajj9O+ru4p4/MeIffIFYJrbcMN41av4 LTOMa6L2yQPAijxm3Z3o7qdOJQ8U3/gPFi4eF6dYyNkF05iivGRCU/4kyXWqJu5u MjMIYaA2fcq7nbu1cV4GgWr/Z+6miD+2P9MXTM4EzrMLdTnRwOOcs5qiGVYoi5ak s58WSdyEICLt73JMXxCqHwkBO1XIxmyvp9Iunu2wzJFtZMPsGL46akuuAS4/ec00 HDiuuQ1hBHP3nik7p7aQOrgsIzTDuAwGUcI+IZmfPBSQyqkm9UDjIul9zgMX7P+8 0ZkuxGSPPyxZYCQ8sNvDlQiqAHWynQsgGbT3bqmjvWDwMw/iZr1H9giKkDV9RYZK yZ7Ez1/fcd7MyW45iE25Ss8DdAdZK+386+7V0tU5bXcN2NF/L353vmGYjSxScTCE vqDmsLAHCMW0dLeLsti62ADyGcf4oSIKZkSoFgh1XllESEU0NQhK8HslC6ZLUX93 zQ0zOKsAkWZMiMFOKtQ6wLSG3oSAylBvgPlNZYAJFXUtIlbltZEjne4l2BgwKHLb f8MxTo7YvkP6246aBZn999yUiad42J1r6f71JMe60ulED4NLXZ//JBif0dWE6CFJ t9sg5w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme 9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I /5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN zl/HHk484IkzlQsPpTLWPFp5LBk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq 1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp 2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF 3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh 8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL /V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW 2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp 5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu 1uwJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb 3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi tJ/X5g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh /l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm +Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY Ic2wBlX7Jz9TkHCpBB5XJ7k= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI 7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX 5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGoTCCBImgAwIBAgIBATANBgkqhkiG9w0BAQ0FADCBlzELMAkGA1UEBhMCQlIx EzARBgNVBAoMCklDUC1CcmFzaWwxPTA7BgNVBAsMNEluc3RpdHV0byBOYWNpb25h bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxNDAyBgNVBAMMK0F1 dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBSYWl6IEJyYXNpbGVpcmEgdjUwHhcNMTYw MzAyMTMwMTM4WhcNMjkwMzAyMjM1OTM4WjCBlzELMAkGA1UEBhMCQlIxEzARBgNV BAoMCklDUC1CcmFzaWwxPTA7BgNVBAsMNEluc3RpdHV0byBOYWNpb25hbCBkZSBU ZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxNDAyBgNVBAMMK0F1dG9yaWRh ZGUgQ2VydGlmaWNhZG9yYSBSYWl6IEJyYXNpbGVpcmEgdjUwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQD3LXgabUWsF+gUXw/6YODeF2XkqEyfk3VehdsI x+3/ERgdjCS/ouxYR0Epi2hdoMUVJDNf3XQfjAWXJyCoTneHYAl2McMdvoqtLB2i leQlJiis0fTtYTJayee9BAIdIrCor1Lc0vozXCpDtq5nTwhjIocaZtcuFsdrkl+n bfYxl5m7vjTkTMS6j8ffjmFzbNPDlJuV3Vy7AzapPVJrMl6UHPXCHMYMzl0KxR/4 7S5XGgmLYkYt8bNCHA3fg07y+Gtvgu+SNhMPwWKIgwhYw+9vErOnavRhOimYo4M2 AwNpNK0OKLI7Im5V094jFp4Ty+mlmfQH00k8nkSUEN+1TGGkhv16c2hukbx9iCfb mk7im2hGKjQA8eH64VPYoS2qdKbPbd3xDDHN2croYKpy2U2oQTVBSf9hC3o6fKo3 zp0U3dNiw7ZgWKS9UwP31Q0gwgB1orZgLuF+LIppHYwxcTG/AovNWa4sTPukMiX2 L+p7uIHExTZJJU4YoDacQh/mfbPIz3261He4YFmQ35sfw3eKHQSOLyiVfev/n0l/ r308PijEd+d+Hz5RmqIzS8jYXZIeJxym4mEjE1fKpeP56Ea52LlIJ8ZqsJ3xzHWu 3WkAVz4hMqrX6BPMGW2IxOuEUQyIaCBg1lI6QLiPMHvo2/J7gu4YfqRcH6i27W3H yzamEQIDAQABo4H1MIHyME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcC ARYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYw PwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJy L0xDUmFjcmFpenY1LmNybDAfBgNVHSMEGDAWgBRpqL512cTvbOcTReRhbuVo+LZA XjAdBgNVHQ4EFgQUaai+ddnE72znE0XkYW7laPi2QF4wDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBABRt2/JiWapef7o/ plhR4PxymlMIp/JeZ5F0BZ1XafmYpl5g6pRokFrIRMFXLyEhlgo51I05InyCc9Td 6UXjlsOASTc/LRavyjB/8NcQjlRYDh6xf7OdP05mFcT/0+6bYRtNgsnUbr10pfsK /UzyUvQWbumGS57hCZrAZOyd9MzukiF/azAa6JfoZk2nDkEudKOY8tRyTpMmDzN5 fufPSC3v7tSJUqTqo5z7roN/FmckRzGAYyz5XulbOc5/UsAT/tk+KP/clbbqd/hh evmmdJclLr9qWZZcOgzuFU2YsgProtVu0fFNXGr6KK9fu44pOHajmMsTXK3X7r/P wh19kFRow5F3RQMUZC6Re0YLfXh+ypnUSCzA+uL4JPtHIGyvkbWiulkustpOKUSV wBPzvA2sQUOvqdbAR7C8jcHYFJMuK2HZFji7pxcWWab/NKsFcJ3sluDjmhizpQax bYTfAVXu3q8yd0su/BHHhBpteyHvYyyz0Eb9LUysR2cMtWvfPU6vnoPgYvOGO1Cz iyGEsgKULkCH4o2Vgl1gQuKWO4V68rFW8a/jvq28sbY+y/Ao0I5ohpnBcQOAawiF bz6yJtObajYMuztDDP8oY656EuuJXBJhuKAJPI/7WDtgfV8ffOh/iQGQATVMtgDN 0gv8bn5NdUX8UMNX1sHhU3H1UpoW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl 1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI +Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX UB+K+wb1whnw0A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFPzCCAyegAwIBAgICPs8wDQYJKoZIhvcNAQEMBQAwSDELMAkGA1UEBhMCR1Ix HjAcBgNVBAoTFUFUSEVOUyBTVE9DSyBFWENIQU5HRTEZMBcGA1UEAxMQQVRIRVgg Um9vdCBDQSBHMjAeFw0xNjAzMTUxMTE0MzJaFw0zNjAzMTQyMjAwMDBaMEgxCzAJ BgNVBAYTAkdSMR4wHAYDVQQKExVBVEhFTlMgU1RPQ0sgRVhDSEFOR0UxGTAXBgNV BAMTEEFUSEVYIFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQCv8F+SyvwcsJAt1CaLvyqZeTbHdIwB76G9cvg0hMwtTdfrk5HLCYO2+tRl M12cmBtew+bgQENlZ2OlcKvlqxZgtqsUezqjbvUZbyrEdKBZdJT2ntf8Mn8M+a8U UbiPWrjVdg6n/XEKPgv8EFJL78LEH1Kh8eXpsRAyrKluW68rt4DJUStKA+w//fBT LO++WqbEAfCcBO3g+n1GvxE36w+BrDoZhwed+F5YqP9jvHB1puCrMdGzgoY2aaOx atU2RdWf8IWKCkUOC0GxEZqx7MAmbUuIN1/sFIOF570+ZZ1K0geHbYaDWLplGcww ldusUvq2zH5uHbmwgFV5U1wNCFZTUrfkl4NjarnSH7xqIREiVhzoPRmEzlmGKtEG JxLbRyukp7DD+B68/qw/sp7csCLFT3Bh0/4o4RUZLHg8P8N9mWA2eW5byThmoaXp LYHGUqyezxteyybZ7dQF7VcmdqQC4zbkTkV+NGcY//wUKPX2vANOvIjLegkorQHj cOi5O1WNEMiUJAduG5pyxAsY+21rZXlv6L2MFaDkoBUU6TvJXfph4nnDCzNKBQ9B UQm8YoB3V+C0uxiSBe2OVCHd9YcYHGqosgJqQoxD1R4fZ+HV3QBjj+ALf0GUYQaW fACPoN9TGUe8VDLZGwu+jp89TNygUzyV2FHZp7idkbyDyPHkgQIDAQABozMwMTAP BgNVHRMBAf8EBTADAQH/MBEGA1UdDgQKBAhHo6YEnS2W5TALBgNVHQ8EBAMCAQYw DQYJKoZIhvcNAQEMBQADggIBAIbX9Rko9qewUKpuPSM+Bu/nNHusyYUusKmiwn0k RT+tyNaTJ7XKjyygBDiD2ZrP7lcs7LEJE7LOfCQbZ+BEgszipWRLSzVsZ0Jvc7w4 uX7ARMh1/AVxp/udBcLlJdkssXVntDH3uiUMjp3JfGxK/HUFYKTNz7ufjl+dsiBA S2tuHacQHu+/YA/LN/1MI/pi431dgM2ubMfmp6STGHcfU9Z9qf914yTgT8uiYedm PtS0Ch0MFY46hQbG72xy/dRD0/2MqEOBWTjBhnwgh46oJIpGxAWtbaDVWBBTmZTy rIosVqZSSkw3OVW8wviueay5NoVuYVI+/TTqYWhlgYFM2xT5YI0EdQ8Q30PTJcdA X5vk0DB92gZB9O1m/jgRcyBZ2YB7FeFC1zqebGVfMXahE2XaJzuwEuisSLaZEQd+ LspikapRYfRnyit50o8hWl8WcI5UmJ/281kBba61pBJzn4KfF5/a7YOPI/1izjbe A8HRMKbTou+rXXV699ccLPfZ6WY6l5QpUNv8AgNf8jDXUTKcxC+dStkx8TUPfoOq HeK1xlFBa1ctIhmPO6cjuwN1nrv8+SCHzHBfjiBwLzo+Yg1f0uE2nUbWVbKYCi6c wFXS+x56a0p2KSYS9q+kp7ztMqFw0/mNiweBpX0GwI3xNb62YLJvHiOikcr5YI3m 6JPv -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG4DCCBMigAwIBAgIINJotoYIGsrMwDQYJKoZIhvcNAQELBQAwggEMMQswCQYD VQQGEwJFUzEPMA0GA1UECAwGTUFEUklEMQ8wDQYDVQQHDAZNQURSSUQxOjA4BgNV BAsMMXNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2Fk ZHJlc3MxKTAnBgNVBAsMIENIQU1CRVJTIE9GIENPTU1FUkNFIFJPT1QgLSAyMDE2 MRIwEAYDVQQFEwlBODI3NDMyODcxGDAWBgNVBGEMD1ZBVEVTLUE4Mjc0MzI4NzEb MBkGA1UECgwSQUMgQ0FNRVJGSVJNQSBTLkEuMSkwJwYDVQQDDCBDSEFNQkVSUyBP RiBDT01NRVJDRSBST09UIC0gMjAxNjAeFw0xNjA0MTQwNzM1NDhaFw00MDA0MDgw NzM1NDhaMIIBDDELMAkGA1UEBhMCRVMxDzANBgNVBAgMBk1BRFJJRDEPMA0GA1UE BwwGTUFEUklEMTowOAYDVQQLDDFzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5j YW1lcmZpcm1hLmNvbS9hZGRyZXNzMSkwJwYDVQQLDCBDSEFNQkVSUyBPRiBDT01N RVJDRSBST09UIC0gMjAxNjESMBAGA1UEBRMJQTgyNzQzMjg3MRgwFgYDVQRhDA9W QVRFUy1BODI3NDMyODcxGzAZBgNVBAoMEkFDIENBTUVSRklSTUEgUy5BLjEpMCcG A1UEAwwgQ0hBTUJFUlMgT0YgQ09NTUVSQ0UgUk9PVCAtIDIwMTYwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQDqxqSh1K2Zlsmf9bxQAPQsz/J46PIsAifW g4wEq9MOe1cgydSvZfSH3TAI185Bo3YK24pG5Kb97QjOcD/6EGB5TGuBVIBV5Od6 IbZ1mtxe9g6Z/PjC30GOL6vHW20cUFnA7eisgkL+ua8vDEFRnL0AbmRRsjvlNquV kRL7McdzrBzYZXY7zhtMTrAfIAb7ULT7m6F5jhaV45/rGEuEqzmTzTeD0Ol8CyeP 7UII6YZGMqyaJmlwYS0YvT9Q8J72aFBOaZVwwe2TqZdOKaK63cKfbkkIK6P6I/Ep XrB9MVmb7YzNpm74+PfYGOjaVulI8kB0fp7NIK8UJFnudzWFv0qZSql13bMm4wbO fW9LZKN2NBk+FG+FVDjiiy1AtWRmH1czHHDNw7QoWhQjXPy4vbP+OxJf9rmMHciU Clbbcn7vJwcNALS/fZk/TUWzm/cdGdBPBPrHc5SIfYsUKpng6ZmSCcbWAWu38NtD V2Ibx0RS4pdjus/qzmDmCuUYaC0zgHWgMAdo9tX3Eyw6sJ7oWFVujFZETUMXQQLM d9xfRQVZz81g07/S9uL01dyHcTMHGvVvtH89l/tfZPRODgBECenr7D5xGQQXOUhg uEv/XshlmSumMvJbhqid6CN0EHjvyyedMbpgi04GUOJQHQdgwkGMFbRbNxwK5QkZ cgSKPOMB2wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSeLmVP Plf1q32WxovfszVtSuieizAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQAD ggIBAAVpKoWXJlC6QjkckyzST1vRXUQm2m9pK7V7ntD0Si5Ix+x/n8pZerlE9z69 91BrUZ90/5AaQNCTeZIPiiNei6+BC9CLrWbgKtyaKb012GxAFElCPYkvupsrOLwa owu3iNetxhQM7nxJrK7s8j0YT4xtFF0Oqrffd6s7j2JOiwxlxhmOzcAMoXeqtN16 pxMF5jkYx5VkfgO2i5DB5V8AI5jmc9oR0hD/HlMiJ8fTAckvxTsybvDDOMoSZ7y6 Iym7xJVJWgbd1FqQ1BNt59XCfOJYBMDsxL2iPH7GI4F1fKtwXzSElfez1UeWT3HK eDIIILRCpEJr1SWcsifrwQ5HRAnhKw/QIzZuHLm6TqzM8AyUzkEPa90P1cjgF4ve Ol1Svul1JR26BQfaVhk8jdHX8VE22ZLvonhRBVi9UswKXm+v2tDlDNtswSPvOTF3 FwcAjPa6D3D5vL7h5H3hzER6pCHsRz+o1hWl7AGpyHDomGcdvVlUfqFXFTUHxXLJ Prcpho2f2jJ5MtzbqOUJ/+9WKv6TsY4qE+2toitrLwTezS+SktY+YLV4AZUHCKls 4xza++WbI1YgW+nQXMZKJDu847YiFiqEkv+o/pe/o53bYV7uGSos1+sNdlY4dX5J AJNXyfwjWvz08d8qnbCMafQQo1WdcDwi/wfWK7aZwJfQ9Cqg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG2DCCBMCgAwIBAgIILdIuUDCmXhMwDQYJKoZIhvcNAQELBQAwggEIMQswCQYD VQQGEwJFUzEPMA0GA1UECAwGTUFEUklEMQ8wDQYDVQQHDAZNQURSSUQxOjA4BgNV BAsMMXNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2Fk ZHJlc3MxJzAlBgNVBAsMHkdMT0JBTCBDSEFNQkVSU0lHTiBST09UIC0gMjAxNjES MBAGA1UEBRMJQTgyNzQzMjg3MRgwFgYDVQRhDA9WQVRFUy1BODI3NDMyODcxGzAZ BgNVBAoMEkFDIENBTUVSRklSTUEgUy5BLjEnMCUGA1UEAwweR0xPQkFMIENIQU1C RVJTSUdOIFJPT1QgLSAyMDE2MB4XDTE2MDQxNDA3NTAwNloXDTQwMDQwODA3NTAw NlowggEIMQswCQYDVQQGEwJFUzEPMA0GA1UECAwGTUFEUklEMQ8wDQYDVQQHDAZN QURSSUQxOjA4BgNVBAsMMXNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVy ZmlybWEuY29tL2FkZHJlc3MxJzAlBgNVBAsMHkdMT0JBTCBDSEFNQkVSU0lHTiBS T09UIC0gMjAxNjESMBAGA1UEBRMJQTgyNzQzMjg3MRgwFgYDVQRhDA9WQVRFUy1B ODI3NDMyODcxGzAZBgNVBAoMEkFDIENBTUVSRklSTUEgUy5BLjEnMCUGA1UEAwwe R0xPQkFMIENIQU1CRVJTSUdOIFJPT1QgLSAyMDE2MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA0GvnniIrU3YVVa9MSsBta/v5hEQFoX1gzgXsnphz+luE BzH3/z1rx35WBmKlXJaW0/FeWX7rMRy/d1cwVO8exczEsurb5orQ9CiEyLBILSyW bfsiqDWOvt5wFRD5ZkFGFqBDZD+NSvOAMc+TgH6a26Wvj2ws/Q7vHHncD6JuhFwi iQ5ELkiolHPsOTKRHOIUvX1l5nL+W+dUdS99DuLGymkuXqIO1eiF3j9rf6WCsEZ9 XZ5xuhS06+3HwhRkDFhuT5U2YTZFYDZmGEuVGj5YrIsmHiXm+pUA+60SnvoSYb4a 3qZ86av/15SJckL8u0UR7D9w/BnEmuqXbqzkOAQ74T8BKHGj4q5DZHgWmQJav9fE 77W31cNYgUGG5LKMAKWImJjrCedYMWgx3u3iSTXz0rNX3MRCn/0879D1KzluYa56 4cd6PW0XMGwCrInWWoScKcCeEI64IDYzyoAraH82dWUV+MPa/3Gi/O2bd9wZ+vHI tgX05XCSqcjduLAaVVuR3LjlmrUDwK22rvGZe0u1iQ7eZAtkflTup8OKmBnF/DwT CEU+35/7x32xoII2FD3AYwABZsTk8Jk7HlF4XbkXPFiTFa+o9SUgGY0jPRI8Qusv XUKO8jCoJVrm+vdPbb4mWPWPf/eK+LNuwxvyMYU2cY79O9bmMDXLJY1liVeoM5UC AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU6JvNfoZim3pNjACX OYXPHHiQcDowDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQB7/SrD yxspAhAJresusytt2Uug2zWY9Y8Cp9NCC0Org7V3R4hGhd3Rth59mBuMcb6qyPDv xmotVphS6JaJ+9XqAN/+5iLKp7k+ZUR1w4q/i3eJw2pX+rzI4RDe8dqFJ/HtB//V wkLUomEv34hx4zTmZ2SbxnoZ6znv8+oEqHRpTIC1/K29DQj0yO8oJ4LK3ejzuldn ouopwZnhdmb59nhdnD7w9s+hGTTT8TwzocyCMrZI44M+D79nlcGimXhCQ/cDTRNX b91x3Rbz+3k4G2KapM1eUN4RIJCKIpir2kZ6TDTRSN3ZZmViVAXZdJlndFexOi4Y sK6snz8u6x+ynM2O+Nt4jtQGz6OTMWt/7VJyt4vPKG/J+VRPAdQ6hugu+uHQJYTj FvyMjSTjZMwqjLJgU59ZkkUJlFuoEIUyy3fyjpWKRHLPbhfeRL0Krv0mtj15Zj1N vH4yQ13b4GW1KGm6fJ4ySo/qerA9Fl39PvobBPgQNXjM7cHZLb9r0u/pn8Bbj+q+ etEx5wY9rYSr7DvxEsd/8fhGLwl4l8AnPbE/cSOLGqdc5hYlDiZNuQ5Wp1KkOAmv SQX+f84/wvzm5EqUJ+VTxIg06wJXvM6OK613U3JAu4UWVRkvg3aVo3Y5qLL0faTb AEJ6oHuOGQbkl81bPTq0XMBpHzJmvwifhJsiZQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEijCCAvKgAwIBAgINAJCud3YAAAAAVx3QbzANBgkqhkiG9w0BAQsFADBcMQsw CQYDVQQGEwJTSTEcMBoGA1UEChMTUmVwdWJsaWthIFNsb3ZlbmlqYTEXMBUGA1UE YRMOVkFUU0ktMTc2NTk5NTcxFjAUBgNVBAMTDVNJLVRSVVNUIFJvb3QwHhcNMTYw NDI1MDczODE3WhcNMzcxMjI1MDgwODE3WjBcMQswCQYDVQQGEwJTSTEcMBoGA1UE ChMTUmVwdWJsaWthIFNsb3ZlbmlqYTEXMBUGA1UEYRMOVkFUU0ktMTc2NTk5NTcx FjAUBgNVBAMTDVNJLVRSVVNUIFJvb3QwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw ggGKAoIBgQDTy5wtwuAwQ2UxJP9LsDjZqVPXNdHbt0uTtHKN8cuV0lMrdJsymqQv PgIG3a9wFaGqzxGHimZ7y8wdcERcj6zK5sNbJ7SNo44Qv25UdAhwiiPoysd0xGaR IN1L6KWEdaWYlYKLG+EgJAdGqwxlNkBni3XuqdmRKRvtby1FwtbiYAGx8045Kztv P4W+CPZTK3uiyUWhRIGAZppgOhvEvgzMMBB/ETY4SuaboZZTnJTMEcYETKJVS/+A 4a+MHDX8uZM33/ldPdzrDSdsRMlZZitWb/8EG/f1acNdwxj+vafZZC+in2DZcmw9 PHXyJSeYLjq4yd1Ndb2rsCJhWAE3KKYgnS5gXPuQvEZDuP5t2MBmIiRrNHgi5bni WOlIOO5MvQF7bj5A6tHCCkKTZ8MmLz8HW8+v4x3oOuJl4YSRP/VmAP2qM0ZC7BY+ 0hNlLw4JU/bkKnUUnBkzFppF4dtXz8841Kf37VhD5A6YXMTgMT+UpG9LSqLVSo0m qR1kJQg1DecCAwEAAaNLMEkwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwEwYDVR0jBAwwCoAITKPDaF4IAmMwEQYDVR0OBAoECEyjw2heCAJjMA0GCSqG SIb3DQEBCwUAA4IBgQAmI4W7XUEZbpKDiu4BiwQ1GX+rj9zWM8H5eZZeI/Xwzt3q 22E7Wq/dWOlCiUDv+dlnEX9N8e3pEXuxQQ/tpNIWtu/B/Yv2ESss7/wHBkYMzwIL 7Tvejwm5M6smgFREQmXX56/NUA7KyIihEpwqlTs+VDxIc/Z8eNSb/5P3ReQphGP8 +n4a51zgclewL3gdMMYT/YhfsWWI2l6XE4F7/h7Pe79XMMFwkkOmmfBVn5jFI0K9 dBwxjhKl2UVqKlrIWM291t0+NQsZfwMczgcPh0WTFaFrvTQc4N711LjlkRxLBbUn JrzP0QmYFsbh8VVLOntt3sZntsE3LZ+ojlnHt6bF798W4u3esrfzojakKDI6CpTL P17+blntujayk9bGwxn+9Zl460dH5a1Ceuy8e8kuQU5NDwQOikszh9zxdnxaGIyc ChLXorPChYeubTFQYjIhoGgWX5Q1dFUp0nGBCErh112qVAGzG3xZrr6sDMq4QGRn W53qBgYR1tAwcx7jvCs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF7DCCA9SgAwIBAgIIAlQaqVDXzh8wDQYJKoZIhvcNAQELBQAwYTELMAkGA1UE BhMCQkUxJDAiBgNVBAoMG1pFVEVTIFNBIChWQVRCRS0wNDA4NDI1NjI2KTEMMAoG A1UEBRMDMDAxMR4wHAYDVQQDDBVaRVRFUyBUU1AgUk9PVCBDQSAwMDEwHhcNMTYw NTIwMTMyMzM4WhcNMzYwNTIwMTMyMzM4WjBhMQswCQYDVQQGEwJCRTEkMCIGA1UE CgwbWkVURVMgU0EgKFZBVEJFLTA0MDg0MjU2MjYpMQwwCgYDVQQFEwMwMDExHjAc BgNVBAMMFVpFVEVTIFRTUCBST09UIENBIDAwMTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAKv5lg6EKHY1gSpWPwLt1fFwkQ5AlyJcu5bmmh4OPCuZPC9r NGGrB8xKJhVlngsozAA4D1v2rEZMxVwiiI4j1lYoXnXixE9S4zkEczk55k/386my IOoMJ9LH9HRzO+wkzmFsGpXb3FVCsRaUMfmmfIwU+DiifaC1OZzX1l+VL4VzUb+s qYgcHMkybDgAw6KwK9aPsobKujk4bGeDykeHV4udVqR/dk1IFRazwJeKwgz6ZLAg Q1aMaofDLSEXPl7gCKoat6qEPVYjK4Mx49MC2RIDBcI5r29TVhcDqyMcevC8CheV lyaB73ggPebf9Nq+jl9f0R79mXz3IW1ctwSWYsPTbh3K9++mRZNT3yZ75NRE121/ sFSZfrYn4sO+SmdCBa5qSvLulwZdZ56Bvl/oAFpUSrZM2RUuCPZCGiUZPiuBe1rc GfRqJwLdj5QCl+zilge0VubkLu/dLBaFCPoc9wCWfg7koPopgJC2RFN9O3UV71lG 4crc2JcbkElDly5YBXK0XTEGfTnhdP8aTE2VMuiNpa/0PHv/IBzL8LD3MvPmEsWh 1+SSGelJZ8A8f5u4gt4E8RVX1rAJHjk6a6bi+KafIXCZqLBZeRK6SEbm9XLMzNQP s7dMw6PfLpd4yF97KyEitT6yHNlrQ1GL2yBJjtpqEzQLO071a46HG07GSgArAgMB AAGjgacwgaQwHQYDVR0OBBYEFDi8XDBU3OK7IO/ub0GgMW5c/Yt1MA8GA1UdEwEB /wQFMAMBAf8wHwYDVR0jBBgwFoAUOLxcMFTc4rsg7+5vQaAxblz9i3UwQQYDVR0g BDowODA2BgRVHSAAMC4wLAYIKwYBBQUHAgEWIGh0dHBzOi8vcmVwb3NpdG9yeS50 c3AuemV0ZXMuY29tMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEA nDEKHd7KpKBSsJYq4Pws5aF23BQ4ZYazLtWll/NzYK5GaHWHsTPIEo3ZKaPqH71u /ronUIHhcWzOqzCcJppRcXBnH9FEpxQ0zUbdK+MOZb3GTkNoU7K4sT3wZD0Hh7H5 hzIEepbkQrswKMeaXStrx1AKIbaGIvYSrS4V8LtTqTDKLesCoZRnYxHYt+bzpwsG H5J5ofKrU3s/o0gITPtEAAP/yQDCbMJKxYbEs+pZXA595T+2qU+S4xEEXbd3xjXD sjFz2nfXP38QGa0AIt1DyOASfkSYOFHSOMi2QxpMUV2cOovIPHm43LAe693l5p5E m+lQPcsRvFX+x3RlZQgNpKp3PRwTtpyfFSr5TuE0gnA2c9I0GYRV8w3AT43/Vhaa W2US8DJBnBtYv72vMhB21y0PxTdx5hr9Mea0Nhhs+0v1qjWwbFAt51siSuD6nTkg QcYuACXkkd+bONMFm5z9BGiRuA6CXNg192LcyWAFi5XMP3zrj8b9mp+pbzIBVJpk pN3lxUVe6lXt4UPLreIebgqejjLk4668AdBTBA6dQk02+5nlGukH1FPwRQdCE8dr IT6Et/fFiVdTH/jzTlFb/mcyw1n2kRmIDYBs4d5FCkaZej/MPvAgbPi8z653LPtu 9QsRdouZzq6OM5F4CqUMJLNTD2sR6bOwHWQBLpQdIdU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGbzCCBFegAwIBAgIQQxwoxnQP7SVXRJ/y/Q5eFDANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0 aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMuQS4xIzAhBgNVBAMM GkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMB4XDTE2MDUyNDE4Mzk0NloXDTMx MDUyNDE4Mzk0NlowezELMAkGA1UEBhMCQ08xRzBFBgNVBAoMPlNvY2llZGFkIENh bWVyYWwgZGUgQ2VydGlmaWNhY2nDs24gRGlnaXRhbCAtIENlcnRpY8OhbWFyYSBT LkEuMSMwIQYDVQQDDBpBQyBSYcOteiBDZXJ0aWPDoW1hcmEgUy5BLjCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKtriaNTzEgjCPvDz1GWCC64CHptPJAX hqnp7S4TNEey0HDcyTzQjcruSxer0IWwpyMEy6ii/OV120DKYomPUJ4BPSZbGIQc y3w3t33s039zGbBqstiIii1FdKj3s7jA1NrNIol0TVoVOXMYdE+165mnwR6ItMKT kGOX86enErIJIgcz2ZHNDpwfDiDH7rszjY/C0linX/1lN+KIwtiPhnVe+S2nhzPy eDcvi7wdhjc5sZTy2LxKnIMYWgb889TUuowVCSXw+baNBH4XEjNrV0hMT9smHuvM kOeL+Wh8cA+jKtA6ON83l+Jb3oBh04DYkYNCWkwEiWgRPKxfaIBBzGBCzg1aKgwP mzDApvCG26tJ15dtSIv5A8BSZ5sS98LyLphlQtnWmuPQGTEMrYfVVwJ6MOiGJvuP I4pUh+S/PO7rw3VIXx45b4FibMUtxBdUGbc3jZw3kcj2C9XqY2+DrDjC8z/emvvh I2HwyCbLNsih8zCPpKOiod1Ts97wmjIfg5F5MMGpH1ObU6IVUz/dnbMQO0h9iQ/8 7QP1+yVkdQ4XGQ2PABZneXpA/C1ZB9mQ+pqtPdyAiuZcNaJnTBFrsfiAZAAtbyJh xaxLJuVaEIKbpIN7NPeeiZEgl463Qsdmw9DppNb1II3Ew5WsRAqdW3M8Jj0vSr6n yacQHvufUGnzAgMBAAGjge4wgeswHQYDVR0OBBYEFNEJ0OnXznl0VPk6MLP0bSwD AxtoMIGoBgNVHSAEgaAwgZ0wgZoGBFUdIAAwgZEwMwYIKwYBBQUHAgEWJ2h0dHBz Oi8vd2ViLmNlcnRpY2FtYXJhLmNvbS9tYXJjby1sZWdhbDBaBggrBgEFBQcCAjBO GkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8g c2UgcHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA8GA1UdEwEB/wQFMAMBAf8w DgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQBRG5A+g1oa6Gpwpa1w /hCCYTCtjMO1xtjTMRLJH3lTFeJDx+EO8T1IzmgLFXlt4XaHf3Bm7fUPgqS8ce+x K8yxuusqqWAfQ4C+knJCLp+h/xgIsV5d9WzOKNvAbJrNh16W6cjvNZe6ZKq3fkVA ibBDg0574bT0dglLzFY+IUmyxp9j293wtg8X9bpMcI3VJwDJQ1QPZqq6rrHZdu4D ke2YtxobopZQblV/zV4Y0Gcbv/T6ctm72vvemqpRLgW6ztpqbRhoJmiChTTtTXna mnYN9PHUw/uxKnTskFLjDV31SVhUJwAwl6AjAWyJvx0A8f38GayfOymow4HNknH4 1+Wx2hs6F49T2qauAc6ynhrNCWLPddTXZ1Cin1n2hPPHJzGeqh4mS7oOiqzp9eNc HaEqNzm7NG4zltVxpUM+NjSH/5Kiq+kl4NlRd1Sqe0E0hljxquU+kt7INBCThD8m Rb1Sxjx29yEcruDhxaNT8gmffROeqfOyWYIUlE7fdqqD6SjaiohU+xRxqlA7viT9 xD5E+Jhk82qPYnWwrEdl9psiOiHhtVdBVsUk1hmSd3CwrBf0LpUQThIwmahURWEv N2/6iVdGMvRb6ZvtCSkvla6U4oeqHmpx6W8bOe38fNQNpk4jIjb5Zc9C8ByxM500 1YkkaeYXaKOZ73pcL/0gvXeZYA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFyDCCA7CgAwIBAgIQR0ORJD/Oww1XSChr7oBdqzANBgkqhkiG9w0BAQsFADBd MQswCQYDVQQGEwJFUzESMBAGA1UEBRMJUTI4NjMwMDZJMScwJQYDVQQKDB5DT05T RUpPIEdFTkVSQUwgREUgTEEgQUJPR0FDSUExETAPBgNVBAMMCEFDQSBST09UMB4X DTE2MDUyNzEwNTg1MVoXDTQxMDUyNzEwNTg1MVowXTELMAkGA1UEBhMCRVMxEjAQ BgNVBAUTCVEyODYzMDA2STEnMCUGA1UECgweQ09OU0VKTyBHRU5FUkFMIERFIExB IEFCT0dBQ0lBMREwDwYDVQQDDAhBQ0EgUk9PVDCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBALkrXvU+uokenfXRE8+7o1666d85cmSYUodppbbe4b+URb7F +KRTZxVQ3FJPKnYsLo0gaozmXbnZaL6RG7ppAxitGE42oqxGqyD4A2qqrXnV3x3B 7kVvIXT5TbGxPZA7PDKA7f8Vz1HK16SHLqrlDrbRelrHufhRu9mU3T7Ghk4K/juJ 8vhuJM6RA1gFEkrdUKtBes7tqR8RUx6lE9th8PWqgN50eR2k4ynW++D8l9qiuKsi PmWwIcTlxRBEh7Lj4CqCLn3m9LikEyXzd2BfY1OuLrGdimt2ezpxvZKBNrCcgvH3 xYkoXf+8QgazCGpPYc2kLZDTObh3/8jHo3m7A7mRAwE0Etgwi7aMAsrkSOw4KjJM bcp2KFqGCrrUII6voF8gLWKciPnxFW1bvbEDUMA/NteuP1HRyuNYZkTmo5t3LjH6 2X8ixAVM63QbXGN6pgKTfkMOdhQPTW8ylYiAklKXFPU8/JQH02wpBZVGD+Rx4X/4 bRQSgpK181M+mRGXR3ZKCXLu1MOWCaza//FLS7bXJc8eTJcmCzS7tpTxLGRxX4ny FTs3pwLkDU9IiTOjjGh4MVFnChnbtOJ0Lz1683cAn3ESY/9zKmRpVOysOq7a8lhj NH74PF7AQjql27Oo1FrBTli4abasgmLb0fsaQyEi/B31nE9OO+WN/3ZaI15bAgMB AAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFBpV5BUx4jGbEdSIcXoAPXAoBb/NMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkG CCsGAQUFBwIBFh1odHRwOi8vd3d3LmFjYWJvZ2FjaWEub3JnL2RvYzANBgkqhkiG 9w0BAQsFAAOCAgEAezDKVYbTr+4a17iVmOz5O92QE6OckkWgkolpoXGRvHGFh6At MAnkwlM99Km3aC1Nmc2kz547kJ2aCikNKkLBPVtrQILFixOxQWePvqR34MB25PO2 KVYs73FPwmTx2rQLytA5X1OygwH7sn3Zg3R6NdDBXY+b917nUt/uqjeTq9k9fR7x vRzb6HXduFtM4xaj9nWIDo88wwts22BZ5AWrKEb3Zmkld97KSjPYWF57j5rPUo49 bf3Rsr0+eVeGHkQcB030whCqeMvzURcNdj2NbmhJ6e8HSdG4Fsl5ncyuCwVHev2Y rDGhkFqHYvn4q2Ja4CF20GhC6By+coHwxmd9fnQ81VVvj6VolhHxytMwF71GtjGv cOmkhDdXugk8LtkLE1YHPpXEtXAvk8Kur4FdRhQw+67F85r3QXqx3ksW2UV1RwJ8 FB7VsTugLEG1m0t7o4PwuczOHpS3Xi4jBpWRHDhHHO3EeA6kD/wbfNbya9CKW+qW 8zHUXmrElLgwn5XhB4m4iNInhaRhdOWoRDF6IHXo+Njrs0+q/1M/lu3qu/xRQKYr 7CSh+/lEjSPnppcAD8ukar9QoMpxomyub9/Zg4Jm3FNdr/pU94P/qz+Jlae0bfMP Cg1IMy+BKcdLBcTGV3SEw5g2/++FMqtinBPRIoexvpjbdJqP6sLWk3lFIMM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDgDCCAmigAwIBAgIDDN+bMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAlNJ MRQwEgYDVQQKEwtIYWxjb20gZC5kLjEXMBUGA1UEYRMOVkFUU0ktNDMzNTMxMjYx KjAoBgNVBAMTIUhhbGNvbSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0x NjA2MTAwNzA3NTBaFw0zNjA2MTAwNzA3NTBaMGgxCzAJBgNVBAYTAlNJMRQwEgYD VQQKEwtIYWxjb20gZC5kLjEXMBUGA1UEYRMOVkFUU0ktNDMzNTMxMjYxKjAoBgNV BAMTIUhhbGNvbSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAOlSpsYa72O7rYH0kLJajw3VFjO0HBj7y4kq MLtlgcTh+wKplAd25dcV5HpkEIDqPNCzoq2uHB/qu4FhmNT5jWmVxEUuAwnKhvpc WhEXQDA+8MZjCcnxjUGlVg0FZGlLWKwqKZa7QDMWNEtnbNfxtEal6lmoQ2gPjDgq qjz2RAOG+IrbRSErKR4St/qlZUHeBghYcJU+9EzZ6w8pqZGKnq3KEvXlleY42Rqm i5xPpkgTEKV5RL1qOyn1FndAy36bXN++i+vnoBlvnxU/J54psfUN/F9HojzdLgsC +/SN6uwMsfm0Baz5j6k9biwdOZ/QTp9OyGqegANh3M/4bZTLD88CAwEAAaMzMDEw DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIQq6mQ8eYKLAwCwYDVR0PBAQDAgEG MA0GCSqGSIb3DQEBCwUAA4IBAQBSuXnQ22P+GYH7DPnB5VBZyp2y+1wz0Dioq7Ua TlMldSLTSb/Kgc/T4XujkUZ1yhrr2fVdvHuGNf2Bl5yE1yaYIvyxNdCplbZ8/+SX tEB+SV1oyOLUOXUnTwORsjFXv4bXbcpxACI30DtYJFCgnIyaiY71KEZs5xbtsIGr 9EYmr6boGkV3cBaSsntxcdz330lnwDMIDi5TwXerx0qRTBLv5w4J5XUxIK5u/FqK gJwQsNuoSszzK9w2NKb3qQtnnZDLPSafdc1MyR0GCnWLUsCB8NEmrMySphScXDwW QvuTzAKoE/PargrDuBX0sNDU4BYgT6xQmHgmlB5o65Ry/veL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5 IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu 9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQDEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2 MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UEAxMeU2VjdXJpdHkg Q29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC CgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4r CmDvu20rhvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzA lrenfna84xtSGc4RHwsENPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MG TfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF7 9+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGmnpjKIG58u4iFW/vAEGK7 8vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtYXLVqAvO4 g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3we GVPKp7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst +3A7caoreyYn8xrC3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M 0V9hvqG8OmpI6iZVIhZdXw3/JzOfGAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQ T9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0VcwCBEF/VfR2ccCAwEAAaNCMEAw HQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PA FNr0Y/Dq9HHuTofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd 9XbXv8S2gVj/yP9kaWJ5rW4OH3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQI UYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASxYfQAW0q3nHE3GYV5v4GwxxMOdnE+ OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZXSEIx2C/pHF7uNke gr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml+LLf iAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUV nuiZIesnKwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD 2NCcnWXL0CsnMQMeNuE9dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI// 1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm6Vwdp6POXiUyK+OVrCoHzrQoeIY8Laad TdJ0MN1kURXbg4NR16/9M51NZg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM +SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1 mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K 8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0 kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp 8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk 0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC 5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout 736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4zCCA8ugAwIBAgIEV8fs9DANBgkqhkiG9w0BAQsFADBrMQswCQYDVQQGEwJT RzEYMBYGA1UEChMPTmV0cnVzdCBQdGUgTHRkMSYwJAYDVQQLEx1OZXRydXN0IENl cnRpZmljYXRlIEF1dGhvcml0eTEaMBgGA1UEAxMRTmV0cnVzdCBSb290IENBIDIw HhcNMTYwOTAxMDgyNTE3WhcNNDEwOTAxMDg1NTE3WjBrMQswCQYDVQQGEwJTRzEY MBYGA1UEChMPTmV0cnVzdCBQdGUgTHRkMSYwJAYDVQQLEx1OZXRydXN0IENlcnRp ZmljYXRlIEF1dGhvcml0eTEaMBgGA1UEAxMRTmV0cnVzdCBSb290IENBIDIwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDV39ONmRdqmz3gsGnbtAXMvqUg +E8NB7MZPJeDPey8uVwMrKIDZKN/DHcT5siHq1IYTzDv6g7dgveVDzCKwBlQvGBl odwRxn8W8RuY5CJXUUKMynCWXG4NuY9naloFm98ePzjjqiVGwZwrkn/0grEjPN1s Z2ABVPLkqhD9o4p3JyGe1j3dRlwFPxgIFgplyAxNT2Y9XhZfFw8O/8EXC+cid18a C3hpp8oGj17F30CzDvjg12g+cUHJn41h60uZ4K8zAHetxBZZZgg2p0rkUixZP3t8 OEPkC6PT5Yl4U+ZrvPUnMOggNg6xDI4OFMhUNwd6rujTtsBGTMe1MS51/FHyqmz4 GKsmhWC/ELnDQRNf9HnBCfaRrPeOxY9INakW3R7gX4XzGrM/gVvRfkLu5BtnRGy5 wen7kHQ/lE6TybTpfUJLHfCnlptIfaKQXLQUcCCpCASL0nyy0glMI2ypMZPWKYFF LsPkqqbvvZvxy64Ct2RdgD1BTYlLi5qct4FvX9xoU4aKcXTSVxcyg77V9Hrbmu4N CtVjq9QR5cxdbT7Bj/SPTl0SJkTPLX1XekED2c0eOC8Q1JShNXI6Yd7uQ4tIKdJ2 4S1RLtS+vIDb/02LXw0wraMwpTDr1SRnljz6gW249RiBzMW2QgfzvITmHF6D1Gka uELq29THck1NpZm/owIDAQABo4GOMIGLMA8GA1UdEwEB/wQFMAMBAf8wKwYDVR0Q BCQwIoAPMjAxNjA5MDEwODI1MTdagQ8yMDQxMDkwMTA4NTUxN1owCwYDVR0PBAQD AgEGMB8GA1UdIwQYMBaAFDofR9lvhhjpKfr+Oc7L7YrJVlUrMB0GA1UdDgQWBBQ6 H0fZb4YY6Sn6/jnOy+2KyVZVKzANBgkqhkiG9w0BAQsFAAOCAgEARbJm3IEyIRyA mmkJ9aaUVVkB93asquqINx6sVfVKH26JV6OiBuudmCkasa0EVtruWDtoKm7j+QSP KlKbW+wQ/kwors+qFCzeFgJAU/3XXGAZ5UWWkuzjHhDf+RtK1aS/opcp20BBb9qu 7AmBukLwJDN+wFVssEd2Yo1Y6oG5FpkTBxou/xUqrWW7u9JNjCNVuxYo9SkZnsn8 avw+o+4XAgwTNJkvreeu4kA8dgxKsYQ5Ke3DPbiox5ZA/rK8t3LsoU++Pnf4fY7o Dqa5IsPkt5FkD/2RjaWoL4POYf1Z3mNpo4YwbsXubM+272ZcXvZ1Uf2YSCM4yb/p dQb9cWwhf/zJGceoAMYqXACd+vLkc0i1eIteq+l07Cvjph38Kdbhd1GXikEwzNHM k+rJT8V+caOm2Whsbn9Duxa9RbwBQp4O5x/Zn9q+GDfH1COy7jIMy2/owbhGasW4 BzI5zUq+w757LqLd8qtL2qbOkF49c35RlNLeL8dxFDaRV/VdpMvtxgIxaML7RfVa c/p7oT+o+W3NN9/APyjxvZKAuaCZo5JXcuXrsgXOzEYbobD3w4j1CCR1ZIc/K9MB Z1KPSTADjsdBUW2EmR4blEU+HkRHxSnM+gZp+Usn3GSkFkFrZuPN+c1+9a8nLZ3P 7naLqfk3x/LtOfB6wiMDtoXZPJRBvNM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEIjCCAwqgAwIBAgIUKeuSM0ZPMkH/gxkAqa3E2fjj4n8wDQYJKoZIhvcNAQEL BQAwcTELMAkGA1UEBhMCQVUxDDAKBgNVBAoTA0dPVjEMMAoGA1UECxMDRG9EMQww CgYDVQQLEwNQS0kxDDAKBgNVBAsTA0NBczEqMCgGA1UEAxMhQXVzdHJhbGlhbiBE ZWZlbmNlIFB1YmxpYyBSb290IENBMB4XDTE2MTEyODIyMjUyOFoXDTM2MTEyODIy MTM0OFowcTELMAkGA1UEBhMCQVUxDDAKBgNVBAoTA0dPVjEMMAoGA1UECxMDRG9E MQwwCgYDVQQLEwNQS0kxDDAKBgNVBAsTA0NBczEqMCgGA1UEAxMhQXVzdHJhbGlh biBEZWZlbmNlIFB1YmxpYyBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEA005UBBvQ9JuduCOH4CDHnpixcXoGkC7irUj+kwVs7Ia/KECFs0x5 70dTmBAeVO59eLgYEwxEUv3QgaqTCCM5vl8Pa90ll/MBQt/UgQDEUL56iS0Zr3NK P8w6wL+iqMUV9z58QXSCay53ZuJqpZGIbgYxp68L5lrgrn1ary9H0PL7hHOcRqEe hERRxF8u2pACX4HfEQ7S+7s6F3Oj8o1jqk//cnplYoNaKjzyzSwjjc/rIR+/1ANX 9TcWDF7lVxHCqPr/bDnyPVLmtXnAW+Ky6mMgDA6lKl4S4eavX4t8oK05NTWYX/Gv ONAm0029Ynd1Pa9rFIZ7WvYhj9bq4qcOrQIDAQABo4GxMIGuMA8GA1UdEwEB/wQF MAMBAf8wSwYDVR0gBEQwQjAGBgRVHSAAMDgGCSokAYJOAQEBBzArMCkGCCsGAQUF BwIBFh1odHRwOi8vY3JsLmRlZmVuY2UuZ292LmF1L3BraTAOBgNVHQ8BAf8EBAMC AcYwHwYDVR0jBBgwFoAUrJnhAi/oXEtBtzS4HumbgzYNlLQwHQYDVR0OBBYEFKyZ 4QIv6FxLQbc0uB7pm4M2DZS0MA0GCSqGSIb3DQEBCwUAA4IBAQB4vIFK2DpXu70m v+oqKPCIivJQTJBn2kv1uBQIutt/cqiaWbzxHImo9DoDEFQTel3G2ro+D4jVatMb ly1iYTpv+QCvcgZz7BDAYR7MXE8ZMkY4wd0/0jcapY6GoPAJzDXWGQJ8zTn89/kf 55R5Tj23+JdOO0RqzZSwufd+4uP5mX/F06ZQtEn7Fn5OQSzPPsd5QLqBGCYI+cWd 49jxbxxoP2pbdxdSowbeGcJLbqKV/NUIvyy1aTVR4+PfTxopbYN4PTgkygI/VBDh s2Th1Zre8zf2MxC1drOr18kfUzqtVUEcSMk2nof/ddxp0K/ZelfGyrFD/DmB/Nx6 o5qlmFBU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICvjCCAiCgAwIBAgIEBfXhATAKBggqhkjOPQQDBDB4MQswCQYDVQQGEwJDWjEt MCsGA1UECgwkUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRhLCBhLnMuMRcw FQYDVQRhDA5OVFJDWi0yNjQzOTM5NTEhMB8GA1UEAwwYSS5DQSBSb290IENBL0VD QyAxMi8yMDE2MB4XDTE2MTIwNzExMDAwMFoXDTQxMTIwNzExMDAwMFoweDELMAkG A1UEBhMCQ1oxLTArBgNVBAoMJFBydm7DrSBjZXJ0aWZpa2HEjW7DrSBhdXRvcml0 YSwgYS5zLjEXMBUGA1UEYQwOTlRSQ1otMjY0MzkzOTUxITAfBgNVBAMMGEkuQ0Eg Um9vdCBDQS9FQ0MgMTIvMjAxNjCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAftR Bb2dghxXs6Ux+c+wN9n65c7jLZWUzLty376ONIGEtyRBKRZ6cJRb0nPN7MahIa1r p+62J9aNMH5pabDyMw/aAagmk+jmrpgBSfOx97Rn4Ykjru9oJMYpeC2IoDlPQ9vB 3/JU/EF6lzO/10wdL1vKoOR1BmkYFu6f6wziidk9tmfQo1UwUzAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUddg3MwTzndDrHQqP5+Ym zNBNKyowEQYDVR0gBAowCDAGBgRVHSAAMAoGCCqGSM49BAMEA4GLADCBhwJBGieo oGlHxjtDibWSwrV99tHrZTmU4EsvGb4vctlUlmnhRwEBp4tsf8PF8Ra2TbowhgS0 y/N0XUH9Dn0I7ein2l0CQgGGuyiX8t/fYzue3h+GvevqS0lw2n4E8ea5yLUKNM0A B2eYVTxHkwWvbgOgl8nwCtsTSq1HleJIspSWOPt9F3Mf0g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj 03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE 1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX QRBdJ3NghVdJIgc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDZDCCAkygAwIBAgILMaXzypDqI6zSnr0wDQYJKoZIhvcNAQELBQAwPjELMAkG A1UEBhMCSlAxDjAMBgNVBAoTBUxHUEtJMR8wHQYDVQQDExZBcHBsaWNhdGlvbiBD QSBHNCBSb290MB4XDTE3MDIxNTE1MDAwMFoXDTM3MDIxNTE0NTk1OVowPjELMAkG A1UEBhMCSlAxDjAMBgNVBAoTBUxHUEtJMR8wHQYDVQQDExZBcHBsaWNhdGlvbiBD QSBHNCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr6vH5Yym WJ4v1gXJkXcwvt4a1A5jYtHMLbHRhjiNHYVmU5+qQWXgWNLlKb6UqJWTPF9qxZuf NOhtwcbTp+VDoBIwwDk0YAyL9Gj1SN/pjhyuSKe7qj14t+JJu8EjBFobkAHFfatK AaHCk2rShbO253bra2846yBSMJUI9fks7sjAdbkB7cE3VjBcnX9kwspAILmVhbyl B30Mvi6h3cYm6SopbJ8omClR6HYTG+8uCzdaM57AJWeqDy2o1JImOAGn0GIYLiI4 OHgLulKZoXwmArHixeLezooCRISio+mLiGMxyS84AOnEAk0eIycSSNwRsfDS4g4w Ga8DoQezNZQipQIDAQABo2MwYTAdBgNVHQ4EFgQUbtwKNR8gwuih030FTk9MYOWk xGcwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU btwKNR8gwuih030FTk9MYOWkxGcwDQYJKoZIhvcNAQELBQADggEBAFUz1UC3Gn5P 3HSDDkS6P71SlciTliPyAbkU68oSdM1hiDSvTV70WYqrHtjjWcEe+DC1QMa7uK/R 7T9sqnOYguSYNK6SQQ5ZNhq6UBwW9Bc6LBvil2+yr9Ha3hRS34A8x089h566lb14 vFU8ifYuJtUV5dBAEsWzcT9sZh+j/Eu1TuJu3IAHw/koFHv3XhZqQ6eukQEfT2Wp SLPObhoGIaTTMYiIpUkRgmvruZ1g/p/+xff4f6s37q/nWEa6CeRdOadLBNgDAslg Kl5VaRELYHiBevRx9Y9Gro8EqJccgIkjY9v+66YXDlm2LrmG619ebN2B56swgSOQ J7H3K5A5C7g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV 57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa 4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM 79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz /bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV 9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY 2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG 7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS 3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG mpv0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH 38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo 0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I 36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm +LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX 5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul 9XXeifdy -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ +efcMQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu 7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW 80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W 0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK yeC2nOnOcXHebD8WpHk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF 1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu Sw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGUTCCBDmgAwIBAgIQaF3MJjngI2bkSp1k044ENTANBgkqhkiG9w0BAQsFADCB sTELMAkGA1UEBhMCWkExEDAOBgNVBAgMB0dhdXRlbmcxFTATBgNVBAcMDEpvaGFu bmVzYnVyZzEdMBsGA1UECgwUVHJ1c3RGYWN0b3J5KFB0eSlMdGQxJDAiBgNVBAsM G1RydXN0RmFjdG9yeSBQS0kgT3BlcmF0aW9uczE0MDIGA1UEAwwrVHJ1c3RGYWN0 b3J5IFNTTCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzEyMDUxMDU5 MjlaFw00NzExMjgxMDU5MjlaMIGxMQswCQYDVQQGEwJaQTEQMA4GA1UECAwHR2F1 dGVuZzEVMBMGA1UEBwwMSm9oYW5uZXNidXJnMR0wGwYDVQQKDBRUcnVzdEZhY3Rv cnkoUHR5KUx0ZDEkMCIGA1UECwwbVHJ1c3RGYWN0b3J5IFBLSSBPcGVyYXRpb25z MTQwMgYDVQQDDCtUcnVzdEZhY3RvcnkgU1NMIFJvb3QgQ2VydGlmaWNhdGUgQXV0 aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAldFHKO7wVLzr vdWrBn4lpAOq/WB6zje5adopeXdsPX+CNMJd/kKkDUFaANKDpGptweXIUWL6a9XG R9w4bhGQjGgVz+m6WOaai4WBEC3P51NJ6aM3Igy8dLK2JVIRz6IhPImg16QdIxBr HVk7N/RdNjhAtXVCry0aB7yNYxTYSvgime/AWklvq5I/S+ykahg/US7TIOdPLoMG Ol5/FYvP+jUuU7lqGs+n+Dy5yXMXOv2tDVjNknXqP/+5hvP+1aD1Zepj1vqGEbR0 1bVYhKotXUoXvuymJNegvbcYOBZnbhGFW19gUovRz+VC0Jxe9Y6FvfKGbKhV3Osd ev2sKPDE0sepB9ddPhdWlEbum8rEsIwaatfPm86mTC2A+J3xI0CaQCs4VR41A911 2zHUToonb5eOnMx2mR1WrjJMF9kZr6ikzAvKAnUBTj28FPSqO5vQT7fn/lrEztYM czOsqc0six0NIflh5qF24q7wdEkB/DnfqBOSyGOJXrUQ8R0h9tMY+3dMaeJqzOB5 rE6bZM/o4vMiooeenhskDHFm5el25GRUm80N9lF9u58AWh50tNCrjR2rCO8rwtu9 g2HXyWS8D24XxjLfDPOmXu7sIAwqz3pFUHsY1vsSduGvWR+B2jSCNkW/kslVpdZ1 BlmHm6SD3q14eWw8qI+d7lzsPOOJoisCAwEAAaNjMGEwHQYDVR0OBBYEFEI6XjZa 3Buq0KLq9fFEf3Qlc+m9MB8GA1UdIwQYMBaAFEI6XjZa3Buq0KLq9fFEf3Qlc+m9 MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUA A4ICAQAGOiJqHPwbet1ov9VKqL4LYthqZ0k0YBxbs+0lvjYOIFd1A4foZnesd9V3 YZRt6HRxVGv0/Lbyi4pnXx0ECD/+gSDtjzzXR3ZYQtFqxzF0fjRNpntFUXAT+EZE R88N2pYUxoJWPoUa6LKln3/ND2yDguIYB9xmXIrKXaiEL1SMg/DFPEAgMuJP6Fbr lcLkxlD+IuivAVIrla6GVpWnex7GN+419vf7NtDgKt0wMsNtFCXHVdJrI2+QKgpj lnpm6N2Asnn/k2htD7EUU+XOe0zQwSMLOoPkzI773C7ZdFLgUL26Sfh2NBYfaSv0 KIYdTDQVF9p0qHCWXT/CHccEh1Wia7Gy9TVWYru79UfsgrRmahNIeFRjz1+A7JhG xEnJ9KQrlSXHwKPbVly9qva5N+LaROUNS4d5naadH60P/c7pZq3xBJRVSNerJ5Zh Vfk23TXfiFY19mqxk1hYZSq0pd0PTYsHGb2CqnW0QsxVWd6nciiBfqyrG+yAHJhX EhnftyYpMdL6kA1cHjAvKoYuRWPVnuV8cH8CZS4Z9AFG3ty4V52+eT5Ufy6DTnLF zVlhPfegtpOUa10JMCZzOFb8V3iH7+04wg1WMISJmxaOegi1fyYSw1D1Gyqyb5A4 NuA1EUzZHh774biMRaxg4fm1uey/wQl6KSXD6SHL0O+DrCI8aA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWDCCBECgAwIBAgIRAI5ZQFi3WJ+9F4SSs8w6x5MwDQYJKoZIhvcNAQELBQAw gbQxCzAJBgNVBAYTAlpBMRAwDgYDVQQIDAdHYXV0ZW5nMRUwEwYDVQQHDAxKb2hh bm5lc2J1cmcxHTAbBgNVBAoMFFRydXN0RmFjdG9yeShQdHkpTHRkMSQwIgYDVQQL DBtUcnVzdEZhY3RvcnkgUEtJIE9wZXJhdGlvbnMxNzA1BgNVBAMMLlRydXN0RmFj dG9yeSBDbGllbnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMTcxMjA1 MTE0ODM2WhcNNDcxMTI4MTE0ODM2WjCBtDELMAkGA1UEBhMCWkExEDAOBgNVBAgM B0dhdXRlbmcxFTATBgNVBAcMDEpvaGFubmVzYnVyZzEdMBsGA1UECgwUVHJ1c3RG YWN0b3J5KFB0eSlMdGQxJDAiBgNVBAsMG1RydXN0RmFjdG9yeSBQS0kgT3BlcmF0 aW9uczE3MDUGA1UEAwwuVHJ1c3RGYWN0b3J5IENsaWVudCBSb290IENlcnRpZmlj YXRlIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOrA ZChzgke2wM6tiNzS4e5IUvMQ504IhuAv7zgmShfwe0MbqlFNIjIHU3YKt2Cxqj9H Gkv+mMrz1KhbeN6Tnvw0JXSQ6BbmnWNVPn9Vc6YSb/eoc82WkjGutMQBSF0Rf/Z9 gr5dDemjK+sxLjnmWkqe3AZsKJj2cfzwWkL2u8BBJub5z0Gg+H5swZPF42Pn9pRC JNhrZ9HndRsAjgoEJ8fgGze7XuAuyaUEcw369dY4pKTWBpYWK4AQd9D3afFpkqmq /MMhtv0TMQk4/8P1b+NHsyHo9mXUuNNbLnzdCk+6Sd9qj7BCbLZHaa6zaWuYKGLz /Hf3H3Y0Rji3Ixe51C3aVxgDCaVVnaHyDAC8JTlih9FAB8AOy87UC3pQke+QJw7Y VwCIkuIXyWnBNR6kb8CphjQ3RFK8Q7J9iY+lo1nA0DiMp8tW/RlbwZW15UC9+YLE ySLUMp2Fo+9KdKcVBj5wIkgrDCOs0GJcuXz3hdmN+MXTl49e6vAM0LGaCE+ZBoHk Gil8pPoWJ5tzUanFJPYlGKizMtdK59Na2ZvCMjsEho1Yc1WQLmhISVQ6O+4loJni XANmU8xu1A0RHXmq1PFlC4/NT1QBEAw/XY0AZDQfBiDsodaSC8m+tmKHVAn8/hpz eSERZVye1bOQxaSWviOrfYFZ8TqbV69dgW760UuxAgMBAAGjYzBhMB0GA1UdDgQW BBQ8tpw4Wuy11CILQL5jDwiLKO4MGTAfBgNVHSMEGDAWgBQ8tpw4Wuy11CILQL5j DwiLKO4MGTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG 9w0BAQsFAAOCAgEABTcWLooTAcR8JmnoMwVS/QhaghKNzwoTWXg3usVEFzriFT/z j8zcVy0Toz7leLsrkZ0+4UJsVXVuaCyUP5uCN/w8L34cZvFVyYPSiMCbrJP+2WAv OlMkv7UvVV9hs1NPBNtuNqsdLyjD1SK7GKQnHiun0XxRfoIrd/91dZuJgefQwdvz Gb9LbAcSBA7iBgspSGY6NSbUveEFdCGK9cbPFlArFMVk6hb8TSFVjCjvHMzqEJtN GKqOTdwBxkVN8cdu+0eApzDHJ/ytCoGb91ZV2rsflfdfEHgji6OgZVAEY/M+QXOH FNxagyc40CMPpegsjhYmmevld5V+6Y+Fj0EUkP88icflXIrXYwxpc6U4HW2pYxyV f/filBDQ7VagR6FAJR+5sry6as1eNoAOslWLPEvmgcHKJ2nfsy44/L+zqh2ybSBS 3Iw/G4N6rBt506ToKTAU73iM6T5Y4tnP9XvTYbkcATaw7DCIW5+zGDpG+hbly4S4 OQSXTiQAR10g84zxpG8yA+BKZeWMuhXUVFi8sVB6cC6sQwoN5qbwIi5fShoAbHGT 2xpk7hlxfQW2mIzfgN2KqDooNUMU/vMEOo8hOA9OE4OO39v72drg5fdGPO/a6G5M ngH6MmW7UhMgaTubG3+TzzAzjrOKI/wH02lgEvdEvQMvqPBHFXcn2GG3kLU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDjCCA/agAwIBAgIDAw1AMA0GCSqGSIb3DQEBDQUAMIGWMQswCQYDVQQGEwJG STEhMB8GA1UECgwYVmFlc3RvcmVraXN0ZXJpa2Vza3VzIENBMSkwJwYDVQQLDCBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBTZXJ2aWNlczEZMBcGA1UECwwQVmFybWVu bmVwYWx2ZWx1dDEeMBwGA1UEAwwVVlJLIEdvdi4gUm9vdCBDQSAtIEcyMB4XDTE3 MTIxNDA4NTAzMVoXDTM4MTIxMzA4NTAzMVowgZYxCzAJBgNVBAYTAkZJMSEwHwYD VQQKDBhWYWVzdG9yZWtpc3RlcmlrZXNrdXMgQ0ExKTAnBgNVBAsMIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5IFNlcnZpY2VzMRkwFwYDVQQLDBBWYXJtZW5uZXBhbHZl bHV0MR4wHAYDVQQDDBVWUksgR292LiBSb290IENBIC0gRzIwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQC/1gBKiQ4vIztyf3MgZaBfFsV7XlwG+WZzIIL1 YpYXlFH+mzXo8g5ffyGVHGLA5PmCeFzvVcDH/A1587ZMgjYKsEv8LWGmC4i4T7kF rgbMCdN7Sg1oiRNFAKOdXOZ+pR7nBi/wa0WkotSbh8qYZWDrWsyileyTW0qldn1f ddItlUd6abFziKxlJHkgf4iGRWQS6BTHOJCXHPFB97jgN/+2tcwxWswo/4SoU1ZY ct1jwDtHHYxWQ95UxwjMP3rowgPKNLyFlefD0SDS9Eor8envfXpbtQRgUgR4nejn KUNuOwEA2CrMBiYCaoQ/8wiqPhT99/eOuYAwQqUFfM3zoYQieBFBCdWMgAtOWI2Y 1HM9FfdtmT3khPNHPC9rmRSEITucVmVS9Y+rDaljgsw5UrHqp1njo8APeT7olT5G rLnduFeF9pf/nrMI5jdW3vymMziNvw1rlqaL6XBKt2dEqIkukOaXi+5vnKxzRftp OP1W+AXroxHMyPLyxLD41xn4BuaWYH3U5Lbz1JsZX98xg8644HWWKW08L+hZwEqf uuz6k/aRby0kFJIrvq2dCFg14WEqE9/Y0HzxVvNrdC3E4+6AYSyrCl1VSUthr5VO sbdS1pnT7yTQHAZImhvCF5yy5ov9LXKxlzwYSVFWfFXkEr5QiR1pKBlIw9oigang 4AWqvQIDAQABo2MwYTAfBgNVHSMEGDAWgBTRpwgWB57pvU7T1yBTllkGJ9eITTAd BgNVHQ4EFgQU0acIFgee6b1O09cgU5ZZBifXiE0wDgYDVR0PAQH/BAQDAgEGMA8G A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQENBQADggIBAC1Qj8Fm74llE8N41MzM Wpdv7I9gVN5zZLcN6OE7pazPhbaWOUxEpDtZNwyAQBYzcnRI4IQloxstDQDhM2DC wV92D7OiS3DFJkDNEPpY9IFTj67cJ0iFlaaizkpCGb+VNSBk30JqZnUNVltLdZY1 U4McUKDlx5Sdy9ayPZNKy5SQcchvb2GbbvHQiOvEbz6DNEBUmEf9TMzKHI2D4DFt MDWz3yTEjTbdwNT8WYaso/BQvhhKQHhXoI3cDZK1yZZspzldPryuK9pxVj3RJ1Sq tAZ82MA8bcWd8jxVvvFhDtgc0ah9b9izF0K31RJlJs77lIXGbG1a5W58gD07m84v o/i98pIiXG4NeggKPlzd0//2F9YlZ8H7hnxUV2pzUr0HpUkF2RGLlUby3GIGiqyB BFfJuFRGGInEaB8VHpUCWKrEYZ8uD0TbTAGCaJX7Mf/QwgROfUex95nN5Q7CjBcS RJaCPZGYGpe2Z0Fw0o680WIgdoAS7Q65+Z8miUzXT2upbqXB+rsEE11mR46JqCqx 9l8XFtz9WRJuJ23dvej9xxF98vVWz6p+0P8TIoVi+UfqaO0Pk9hYYcrPdeMUZSfg En8jHtbtDz69AVvmFCYjXeAER3QlrMGVM6gzYCmdnYZj9dC9LxYRJtOZKY+Clnpc r/xS7vOO+Qq8VUHSmfQbp31m -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH 3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 /kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT +xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFlTCCA32gAwIBAgILAIZNvw/jXtd9jtgwDQYJKoZIhvcNAQEMBQAwZzELMAkG A1UEBhMCSU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEg VGVjaG5vbG9naWVzIExpbWl0ZWQxHDAaBgNVBAMTE2VtU2lnbiBSb290IENBIC0g RzIwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBnMQswCQYDVQQGEwJJ TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s b2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMjCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMNwGIWW2kHfHK+sXTNwxF07K+IV ySTuyFM2r1v002wUfcdT+zs5OM5QbMYFFnedXQI6gCFLsjKrcaej48Zt37OyEb3i aPs7CsP4kAyTwzKH9aZe6gXYHrJq40/ZVMNcQVI2PcIp40B/SAN2gUZ+ZaUtIOvV jEx26/ebNaXRIsthlkOG/caB+QRwDw1tl7338Zlv0M2oTBUy4B3e7dGP5pgXH71M jqHPCoNo+xv9f0NTBT+hUDa8h8wUtcGQq9CDeJTpjWcD2bP2AMdVG6oVpMAUeUzo cCyglvtFdUMjggxBbw4qhau1HXPG8Ot9hwL7ZMi8tkTzrvUIxxb8G9LF/7kKeCE7 tGZaVzDTnXuifl3msR4ErHsQ4P7lVu2AIjIAhrAXoedDidb7pMcf7TABdrYUT1Jo G/AiK+J9jO6GTjeADD4LMDSBZhHMuBK/PJ/g0kGBt+/C1L+/HURzQhJkMlRnM6Rv XoCtfKopSlns5trZmTi971Wjbn88QXP61lGpBCUPwCjs7rpOYvSUJtI+lcbF+37q kIqOXYkVT3cupDSpw+H89kFtj5GKY+Xny4LxY+3IvDIRiyd6ky1DPj713DI0yqve EpsIr3A0PdwuyUI7CS1jg0NnGFT6Xxyr0xB+VDt83FJYW8v16k2pbaQ4kVxA3aXd X9dZYyVR1S59KM75AgMBAAGjQjBAMB0GA1UdDgQWBBTt7E1FYRgo57MjKBEcTaUn DV7s9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B AQwFAAOCAgEACFC/ilQg8KTCVBxFJW/sazomkS0kNYbEIZg4B3obqwsJ7SX98z8Z gfzBpz0nYClwwJjWbFN1R2zY8pCEot6/dgmA8Vbq0GxhwPM5YN/SZquNyRIxO3cU dlAcwf+vSezdVCf9wOzvSAF3q0a5ljvbdbNJNpfScQVp7UUd5sBsZk8jXO1KQ/go /Vf/GDPnrIFmxpAIGE3sgnO8lAv9FzUaAeuv7HWe47xN9J7+bQzF93yHuIXACPTL pQHhg2zMv5C7BAbuDHfbj1Cu294Z832yhSfBcziWGskOvl3es2EcHytbS9c9P+0z Mpka7zGC1FHrvLb/FoduH86TeZt0QjZ6pcplNzoaxDnDvzTJ6CC2Eny+qH/APFCu VUv5/wjwF+HPm8Pup2ARj9cEp92+0qcerfHacNq5hMeGZdbA/dzdUR/5z5zXdxAk nl8mcfGb0eMNSTXQmmB/i4AecNnr72uYjzlaXUGYN7Nrb6XouG0pnh0/BBtWWp0U ShIPpWEAqs7RJBj6+1ZUYXZ4ObrCw962DxhN2p19Hxw9LtuUUcLqqTPrFXYvwO4t ouj7KJnAkaTUfXGdEaFVtFig1EA30WzJY2X1vAQ7hVnniCjgaXAGqjsU6sklNM9n xDx5rFCCCEtj9Kh8UHjGK2QqgP5kwgttjOApQMaCoezMfK4KD7WpOXU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c 3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J 0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO 8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH 6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx iN66zB+Afko= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD +JbNR6iC8hZVdyR+EhCVBCyj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIKLwq3aw3LSq8nWDANBgkqhkiG9w0BAQwFADBWMQswCQYD VQQGEwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJ bmMxHDAaBgNVBAMTE2VtU2lnbiBSb290IENBIC0gQzIwHhcNMTgwMjE4MTgzMDAw WhcNNDMwMjE4MTgzMDAwWjBWMQswCQYDVQQGEwJVUzETMBEGA1UECxMKZW1TaWdu IFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxHDAaBgNVBAMTE2VtU2lnbiBSb290 IENBIC0gQzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCMfX1lA+Tb mh9YInmRgOW97IVx4LUJf2DRZfs837Jrml+py64aVnYgWO4t6C78fgjfS7jX+c4T inIzEquWcI+zi0fd4Sc8NDf7JONp27VWX0qwUYqzLDRCt+s7zpLcfx1ky0zVIJj6 L06uPyK3kIr9+YAsrVj+39utm6e2MBQsRNstSI3fCQYAGvoQTQ8fULauTqNWaYAk NYFe6HUHHQPp2u1Ua00odMXiD5oRFxLcDnGAcE1I/9E9mLCdkggXijYUmico7+Xw ZeFoPhva6eIJ5p03Lt3Du5W3EcHR0cJmmY1pyeA36JaXKWRNM9IRjYMVNCcp4jhB 2tIYiZ+LVk8bwQ9/1c23txmv3u97taZlV22NF4ttS1qq3J+MOp0oGULBzpKfRx0q GVqbPukQNGAjOLIN8KDNQNzbR1iAl2d8H+MSoicBo4Aid8TjLWcNv48oCWL53ZrF BMTDjaIA6frG1t4IpbnHadA7qCJJe2qpJN6n2eQKAUn6UiQDHPsSqNBlcUhQ4Y/0 Y0mU5rghm2OB9rXQS1Fb1JRCfJMNnJIm5AUB2+2RWzq5Tgz7SbSho8NsZk0UbQnF xciqQ9uoVTAsK14Sk9oG8Q3zfsM08cdPoRb0WlIZklR6mKD7L8nH/zfGu8PIJv94 GGB9RZ9U4A69r3ePmy8MvrzfNxHKtH6svwIDAQABo0IwQDAdBgNVHQ4EFgQUs/eK pNYPiABZ6FEXT9V+7IYigZ0wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB Af8wDQYJKoZIhvcNAQEMBQADggIBADQlpiWM0cv2nZ0H5jVsBq0x2q62Q0LwqATs CFvyub7gxNCytRuoA8stmPOEu/lg8Igxj4FIjoyhIrWUVxyiLU7No4P+WjEUOwUT xIpkEOtvGUQ9fiOlcGHtIZDNBlZq7WpktXAxeV55RPPsor26p2FNAMRFfZQh0sLX hKgk8iulSSggqx8ezgPye63FaiYEi4c/dzRj3HOCnsZiwZZU02df5YpNFjxSwZvE 41cjGpsrpWMfQFI2s53RbeXp47lSAxYE4NzjBFMe+EwFuEveBCJBEAH5rvYu3pi2 orsJ424TqWEQV1tCsCkQz+Yq/Okal7yHAkKDeOXcP7oN4A+TdXc2pdqxuVCnBO0R mWz2JpGSSeJjiTk/OPwRsPNWtwG/KXL04o2ta3jiPpJuICVtWDAc9R3auBEgJl5r ShRmBdszG0LmzsHuZPCFSYC15RBDCOBsa8bDRJ8pBFU2Wi/CVXCACEuavgoveA4F a5bt38o0PWxsBP+MpocCdVtDMqzQhxy9IohKuXWAGresoIvKDg3xFk6rBOrjfVwJ elwi/xAisojHPJVQv9W1zVIoHp+EQg/4MQC21NbIX2RoioB+V3hK439b/w7deU8x 2M8cl1OG0nPfbnARl5GPM7vJgi470jto4SeMg6HMAW3Egb56tQcNLwI9U8mZnNvR gUMrkAgL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIzCCAqigAwIBAgIQFJgmZtx8zY9AU2d7uZnshTAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE+MDwGA1UEAxM1TWlj cm9zb2Z0IEVDQyBQcm9kdWN0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw MTgwHhcNMTgwMjI3MjA0MjA4WhcNNDMwMjI3MjA1MDQ2WjCBlDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE+MDwGA1UEAxM1TWljcm9zb2Z0IEVD QyBQcm9kdWN0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTgwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAATHERYqdh1Wjr65YmXUw8608MMw7I9t1245vMhJq6u4 40N41YEGXe/HfZ/O1rOQdd4MsJDeI7rI0T5n4BmpG4YxHl80Le4X/RX7fieKMqHq yY/JfhjLLzssSHp9pvQBB6yjgbwwgbkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB /wQFMAMBAf8wHQYDVR0OBBYEFEPvcIe4nb/siBncxsRrdQ11NDMIMBAGCSsGAQQB gjcVAQQDAgEAMGUGA1UdIAReMFwwBgYEVR0gADBSBgwrBgEEAYI3TIN9AQEwQjBA BggrBgEFBQcCARY0aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2Nz L1JlcG9zaXRvcnkuaHRtADAKBggqhkjOPQQDAwNpADBmAjEAocBJRF0yVSfMPpBu JSKdJFubUTXHkUlJKqP5b08czd2c4bVXyZ7CIkWbBhVwHEW/AjEAxdMo63LHPrCs Jwl/Yj1geeWS8UUquaUC5GC7/nornGCntZkU8rC+8LsFllZWj8Fo -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDFzCCAp6gAwIBAgIQFTh14WR+0bBHtO+vQRKCRTAKBggqhkjOPQQDAzCBjzEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE5MDcGA1UEAxMwTWlj cm9zb2Z0IEVDQyBUUyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDE4MB4X DTE4MDIyNzIwNTEzNFoXDTQzMDIyNzIxMDAxMlowgY8xCzAJBgNVBAYTAlVTMRMw EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN aWNyb3NvZnQgQ29ycG9yYXRpb24xOTA3BgNVBAMTME1pY3Jvc29mdCBFQ0MgVFMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxODB2MBAGByqGSM49AgEGBSuB BAAiA2IABN7Nu3Ag8SUgtJTo17Q7D26H3ausz01AL4Eza1kJGNaHDSYjnLSNlZ12 n6W5BkLmrTayxLOuejwI1cudOl5FIWwL4yD1m8LdRDPjQrnq8ihCkqr+DAfKihOZ O2IA7drzNaOBvDCBuTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAd BgNVHQ4EFgQU6EfIQpqwna5vCyg7mBWP47HogLIwEAYJKwYBBAGCNxUBBAMCAQAw ZQYDVR0gBF4wXDAGBgRVHSAAMFIGDCsGAQQBgjdMg30BATBCMEAGCCsGAQUFBwIB FjRodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y eS5odG0AMAoGCCqGSM49BAMDA2cAMGQCMBSGUMAmGuvqoRR3OlvfYzmlM8dQQNVr NWsPtN99VrnhpZ14GYKhQ24a11ijVQNC2wIwGJS0HjqNZPoMJxuHE0rStzoAlMby 5WO/r+P63JPV50aaa4FpPgLfUQ2PKHFBiZEv -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF 8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi 7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR 5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf 5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq 0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP 0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFajCCA1KgAwIBAgIQEoG5GPN5OkKTzpFYYeTtXDANBgkqhkiG9w0BAQsFADBP MSUwIwYDVQQDDBxEaWdpZGVudGl0eSBTZXJ2aWNlcyBSb290IENBMRkwFwYDVQQK DBBEaWdpZGVudGl0eSBCLlYuMQswCQYDVQQGEwJOTDAeFw0xODA3MTAxMDA1NDJa Fw00MzA3MDQxMDA1NDJaME8xJTAjBgNVBAMMHERpZ2lkZW50aXR5IFNlcnZpY2Vz IFJvb3QgQ0ExGTAXBgNVBAoMEERpZ2lkZW50aXR5IEIuVi4xCzAJBgNVBAYTAk5M MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkgc7BfM91cHK5ubHBvp5 qD9oZ0R3M2TDH13YclmDY8+TzKWTEwFBxAoPps9nGjI0oLpAnEe+QqzeGwdcSCMz Up0p87dcxjVCaoZ0Z8jJmhNVk1BfRi9AKfCmnnx7WlTaiiryAZtKje7PbBBF9fAg ETq9jlh6mEKXkwNiDzx8YSia2lVNJMB8zwvL2R3ZzWm6i82ONMX0dVdGK4KNbjzl CJV6b0qLfeOEf35CKtmxIaAm4po4F7Gq3TLkTKar+cQmB14GlbnPrZ/J/8sj0jno JEiIErHVz7TE7D2L/nVvxxFyEui62prSfXFrXtmMfjGG31jdLJlKrLAtzcrcYC9r MKJaizzLGzD8ETNJSdlW1ugh3rS6PHrXGCUegPaL5gWXddR0aIVDCnSLHLEtuZ8E 2KGX1KY0UsyNMoStie3m+EWMc5wdNeYO562Y90nJCpmWUKIujX/uqRoeqawntsxZ y0qS6PLXjqeNXU7VdQeg1Hgj2bUfWuOxQBqg8X5taMR8OVq+StI1k/VmNNb9C5Sq mK6iLS5AcsCrrgBzijeIevxCmoXderIy/t3EhjSEf3saacC3PrST3Aax4Bjifoey KMXVaU7xy8PTUjwFIZzZZawZq/+xZSw4emoEM6esnyguzsJMk5jwwgGqkBhH07or MKnNaVXYH2M8NzM8Ze/v5x0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV HQ4EFgQUwnhnF2uPPk6xWJaOekLaZz/EF10wDgYDVR0PAQH/BAQDAgEGMA0GCSqG SIb3DQEBCwUAA4ICAQAeojNQBng8utKsHlJ2xUc7zr06qqTAr7Vcp3Us4yBks7WF VwnfPpPPlgYyHtZOMxc/6KIIuV2qgC6d71JeFw/gB3yJ40EY7YxUrlayfECIFit8 xUWuwuZPNvhz/bQOmUBJha8hvhKT0/5mQPzRU6Alf512EWBIMEydrInciCS/olMz sYrL4t5hQ3h/euHtJI58CL80zjOUdXNu9M8oMt+9IhjNIbykHN6wpP+OGiPHX3RT ebYAe2wyf1ztO3GwGgTiDuOjb39TvWZ/tbkfG6xz05NSo1kDOK1bZ2hiGifJ9r1/ Ha2dMHYUWDvzMKpCeUcQs3/ZOsrZmUpHnFuEEp9l+MeAtfQ/HNBeWfx4RIGniT6I XZKWsXRipuzpYnVbzelCESyLFCKaB4wG5IOoyleSWQZosjk6mlEIReIGA+U2T4he lL0UPK9V+DJ1M1/LUbsSGUZlAXNBZgWMvxhL/zk5j27g4lnW8Jy8DD46eIFPJFna RErXT7avmuxE9Xeb28MjkPZGGL2/L9F+KEAUMX26IAV4pHbdFg4KeqxpRv7wAe5q 0m0OjjsVLnwjj3fh5X38GAOU3iGUJttGiVT4I7NYK/4v9vSWG5NlrXkDLMTfITh0 5Jod9kVHOXLVcV37vghtFtWot2FjKqcowAemtd6V7ZKqbPvNXE1ZWuZdIJuGlw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHMDCCBRigAwIBAgICD6AwDQYJKoZIhvcNAQENBQAwZTELMAkGA1UEBhMCQ1ox FzAVBgNVBGETDk5UUkNaLTQ3MTE0OTgzMR0wGwYDVQQKDBTEjGVza8OhIHBvxaF0 YSwgcy5wLjEeMBwGA1UEAxMVUG9zdFNpZ251bSBSb290IFFDQSA0MB4XDTE4MDcy NjA5NTYwOFoXDTM4MDcyNjA5NTYwOFowZTELMAkGA1UEBhMCQ1oxFzAVBgNVBGET Dk5UUkNaLTQ3MTE0OTgzMR0wGwYDVQQKDBTEjGVza8OhIHBvxaF0YSwgcy5wLjEe MBwGA1UEAxMVUG9zdFNpZ251bSBSb290IFFDQSA0MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAxmaNgqB+vosiJXgQwAiLmhl/1a0AFA5k3t4hcB3IYUL6 VRyLnjvonYJHfLuOAn6dS9zi++i3PZkRqB1xHkfCJNFClXxk4tfbmhDeTJ6mQjx+ fu2wywPtxrtd/Dn0xO6Kc7Mb/ffwaFSSh6f0bZt61RLov4JPNKOvhq9qjOQgjGZy rBGIle60IppJm8bl0A5bmRL4FQygNwIascskyl0Vy69LHx4CNUIwtgN7b1s++leV NpETeLFpCtPdLoxEswg/kJuMRf8XaBZmGJIYSArCKIVYyC/gO7PRUmiwv2yLYdm7 9xvCd1xoIXHqPd23bqQs4vr5O0QzmYjU6kZbuLV8GIBuVFOH35tjtOUxMrZ+2Dja yuNcNc7OGnAoofqXvD5dfp5snqP+ZZYlVPXi9Y+N5e4PLt0rdud+uiLDW27ekSXR hvJMBxJxSb8XFgKPUbMnatCNTmtFaD9nfv5Uhlx7kfn2XzO61rnzuf2CcgSlNiT7 TQSXepGBIPjg+5QYJlhacazdL7JHdUTjJqYVbnA/Zje68lzDMfL1wDSMExh2HWGL VGJZj6inVKBZB+4suo7FtdqyzT9AmVW9a1ekPlk7g/s93freyoA/EIwHy/Hvosk7 VivLdYwU8IdUbX8JMA1QaxVgkMe6F7A7EKvFujf1L/nAnPt5CC0A2niFS+XBMikC AwEAAaOCAegwggHkMIGlBgNVHR8EgZ0wgZowMaAvoC2GK2h0dHA6Ly9jcmwucG9z dHNpZ251bS5jei9jcmwvcHNyb290cWNhNC5jcmwwMqAwoC6GLGh0dHA6Ly9jcmwy LnBvc3RzaWdudW0uY3ovY3JsL3Bzcm9vdHFjYTQuY3JsMDGgL6AthitodHRwOi8v Y3JsLnBvc3RzaWdudW0uZXUvY3JsL3Bzcm9vdHFjYTQuY3JsMIHVBgNVHSAEgc0w gcowgccGBFUdIAAwgb4wgbsGCCsGAQUFBwICMIGuGoGrVGVudG8gY2VydGlmaWth dCBwcm8gZWxla3Ryb25pY2tvdSBwZWNldCBieWwgdnlkYW4gdiBzb3VsYWR1IHMg bmFyaXplbmltIEVVIGMuIDkxMC8yMDE0LlRoaXMgaXMgYSBjZXJ0aWZpY2F0ZSBm b3IgZWxlY3Ryb25pYyBzZWFsIGFjY29yZGluZyB0byBSZWd1bGF0aW9uIChFVSkg Tm8gOTEwLzIwMTQuMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEG MB8GA1UdIwQYMBaAFJMYNh+paXBRNapPP6yNUH4mBSkKMB0GA1UdDgQWBBSTGDYf qWlwUTWqTz+sjVB+JgUpCjANBgkqhkiG9w0BAQ0FAAOCAgEAO01Radk3mUuojS9G +JksIhH6qWebQZg0UpN2v5H22JEI+HfBat2ept+TMmB9o9D51rhRoC8Y85yS0WB9 JJCMauZcF77PjF2LTT4pO/bvEgI3ahrjf63iJiTNHFNztqyzKuOBGNAqQ2S0bV9a GNcAqvSbF7gJbyDE/74EFz9Qq0BHnmQJH4xQN3uzGJPM8XkRvxRgj+SD/tXnqGGI PWurj4J6GGBsIfr6ecYReq9B2syPC9E4uB8qFfvEQunA9NJ2mLLoCqtTICU3/t95 IvUVOBl1o6q+QmYEfmUg2qJuIBbtXb5WhQ5hkRfIBFlQ8upyZQZaXXqlmJmjZJzk dNk7hstyRP7BhVdgyCyHZtBTX2p+cEO644M0fzw58ORo0s1zvG/tooRm9tWg+5ry hLmG2Xcrll4V+QxjFgmG8wFakq2AqNq4W7PxDHiAl/xqnh/kNgwkI+7VoTHrdqrz CSbyAwzjDd9T2kgRxQG8U6vfuEt84iNtySCdmp6pWPNPkfjNOGCQEv7GamcUlHw4 11SfvD70YnW5nxgNdmqxcDcUtxzGngcXtFa/qAjxWR7TS25ESNkzzKAZELQs9ORy DLQkgzbYhCLdvDolc33xA0+Ge1bjzpH6PbpGDZxmWKTFM2ZJQQYNvWH7P55T3pbE 53TUes0DYl+ICmA+jPmN4YzcGrI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT 7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o 6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ 8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi 0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF 6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er 3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA rBPuUBQemMc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy v+c= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ /W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi 7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud 316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo 0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE +cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC 4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti 2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP 4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ 7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 +RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd 2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB 7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW 5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH 22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGrDCCBJSgAwIBAgIJANLVi0S/gZNCMA0GCSqGSIb3DQEBDQUAMIGYMQswCQYD VQQGEwJCUjETMBEGA1UECgwKSUNQLUJyYXNpbDE9MDsGA1UECww0SW5zdGl0dXRv IE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3JtYWNhbyAtIElUSTE1MDMG A1UEAwwsQXV0b3JpZGFkZSBDZXJ0aWZpY2Fkb3JhIFJhaXogQnJhc2lsZWlyYSB2 MTAwHhcNMTkwNzAxMTkxNTU5WhcNMzIwNzAxMTIwMDU5WjCBmDELMAkGA1UEBhMC QlIxEzARBgNVBAoMCklDUC1CcmFzaWwxPTA7BgNVBAsMNEluc3RpdHV0byBOYWNp b25hbCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxNTAzBgNVBAMM LEF1dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBSYWl6IEJyYXNpbGVpcmEgdjEwMIIC IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAk3AxKl1ZtP0pNyjChqO7qNkn +/sClZeqiV/Kd7KnnbkDbI2y3VWcUG7feCE/deIxot6GH6JXncRG794UZl+4doD0 D0/cEwBd4DvrDSZm0RT40xhmYYOTxZDJxv+coTHdmsT5aNmSkktfjzYX4HQHh/7M em+kTOpT/3E4K6B7KVs9HkOT7nXx5yU1qYbVWqI0qpJM9mOTSFx8C9HiKcHvLCvt 1ioXKPAmFuHPkayOcXP2MXeb+VRNjWKU4E+L2t5uZPKVx1M/9i1DztlLb4K8OfYg GaPDUSF1sxnoGk5qZHLleO6KjCpmuQepmgsBvxi2YNO7X2YUwQQx1AXNSolgtkAR 5gt+1WzxhbFUhItQqlhqxgWHefLmiT5T/Ctz/P2v+zSO4efkkIzsi1iwD+ypZvM2 lnIvB24RcSN6jzmCahLPX4CwjwIK6JsSoMVxIhpZHCguUP4LXqP8IWUZ6WgS/4zB 7B9E0EICl2rM1PRy+6ulv+ZOW256e8a0pijUB+hXM1msUq9L92476FAAX8va3sP7 +Uut94+bGHmubcTLImWUPrxNT7QyrvE3FyHicfiHioeFL2oV4cXTLZrEq2wS8R4P KPdSzNn5Z9e2uMEGYQaSNO+OwvVycpIhOBOqrm12wJ9ZhWKtM5UOo34/o37r5ZBI TYXAGbhqQDB9mWXwH+0CAwEAAaOB9jCB8zBOBgNVHSAERzBFMEMGBWBMAQEAMDow OAYIKwYBBQUHAgEWLGh0dHA6Ly9hY3JhaXouaWNwYnJhc2lsLmdvdi5ici9EUENh Y3JhaXoucGRmMEAGA1UdHwQ5MDcwNaAzoDGGL2h0dHA6Ly9hY3JhaXouaWNwYnJh c2lsLmdvdi5ici9MQ1JhY3JhaXp2MTAuY3JsMB8GA1UdIwQYMBaAFHTzfv/8n1N6 8Xzrqz6kptoYukVjMB0GA1UdDgQWBBR0837//J9TevF866s+pKbaGLpFYzAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQ0FAAOCAgEA eCNhBSuy/Ih/T+1VOtAJju85SrtoE3vET1qXASpmjQllDHG/ph7VFNRAkC+gha+B CbjoA5oJ/8wwl+Qdp1KGz6nXXFTLx3osU+kjm0srmBf9nyXHPqvFyvBeB0A7sYb7 TmII9GKD20oCxsdkccR/oE/JuTaNnGq0GYZ2aDb5v62uLi21Y6P9UBiTxZqQ4ojW ET6kXNjlK238jpXv17FR8Sg3VusCvX7Q8eJkavvHHZDeWck2fSA+ycAc2JeL2Z0B MSxGWpH32WM9J8+6XqCJUXHiWEV0zCE8wDYiYC+047pTxQI/gB/FcU7jvylh98DJ kQPHd/Tp6Og3ynlDA9n9uBbxYHVRZs9vsZ/7xTFaxRe+zk8dhgKgZ/3RrcMFB570 2t8LFbyuUE/kQVY6rZ0QJ9qMWQ7VPLRwRhiMeU3k8WDJb/tBbOXHBqldTbWyQ+mp MEDWhbrzE/IED82wAuO23Tb05cYk2xC7+Izef8fSc3XdJDuPSbcDpWukzyCDtSEH isLiGEtIbYRiPsF3czlQPsnIEVoTTCWxHCH1zYR6zScSv18Qh69qVe2J40K5jZoP GEOhq/oKhVJQAdvAFW5Odp7mF3Tk9nivjjsctJSxY26LFiV5GRV+07SSse4ti0aO jO5PLg5SWjfcOtBG2rz02EIvQAmLcb0kGBtfdj0lW/w= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFrjCCA5agAwIBAgIQTU0GyxRpCYdFVPhZfRsTHzANBgkqhkiG9w0BAQwFADBo MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTkw NwYDVQQDEzBNaWNyb3NvZnQgRVYgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9y aXR5IDIwMTcwHhcNMTkxMjE4MjE1OTU1WhcNNDIwNzE4MjIwOTA5WjBoMQswCQYD VQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTkwNwYDVQQD EzBNaWNyb3NvZnQgRVYgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw MTcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnBEElv+W+kRZBP974 tJEqQz+ojQ/+yJoYdk5gKLn2wHFl1ZWUJ0tNbWz3UyDWoejCgDZgsk00WGAn31g0 n//s3oer16r86HNpME/ETik0DX1EnUrTdW7nwiH9Wt2HpytMyvZ4pIYmAquN3YlA a3bp9rXaYRWHQ121o5OCR7FSoeqXusIF3iHhkHsnnDc1Asv/6xcAh5ZsRDT+57hQ u/lGT5oxj9hUX0bwXsolRDXkVfyUZElNLf4SJvd+chZnmP6SpQM/cFksZF1qY52R vyM7SlWascEkJY1OsB/1Mcgblc5QzEvRLGQYlNEoZ4sKpNkbGJuvqkfGJp4KMTVa xjmjLN2bQ4/69I31I8cHT4lpmtYDbdNjWSDoM5lZsFAp3InvUVRaqNjuLH2q2YmS Ybj/qksMvFP7JkbdUZ08XGAJwAFrWa2DVltT+6CrJq3M2f8+eC47a/NFwQPowpNc /pULklyLnLSz3DpGrAC4JwkKPjXuQwbvGpQIKeZR8eMu+kTjJc2LF/vGywr6DLIe 9G4OC4A76V8CiYu3NL4kjrw961XJsZ0rJTHK/Pct5msBdo7smgDXboc+vBK4JcvJ YQ+FGBGrJ4NMSS4s/Fexx+nCB87rt7XD3ZbvBxLQ3v6EwOeOd/PReLA2XuSALf7a 7VIFAql1sYNS4JfynxdCP+7aawIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYD VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUQcr/FrIJTtwkyEvkXBYlmfgm7zswEAYJ KwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAC1YTkfwguUdJ8YbuW3t X1mCYhL6dtmBHxLZnLeD3FXZqByzi1fFOfDYilOsAfQCwSmQ/6Nq+Hednq2lqa6v nYI9DZieatYYmzsZ8UFERMg2J+b46a4L+todIk0EQgw0VOA/KWxA+NAfDIZYaA/E rhnSj9y7a20ineb2OhYNAfiIyx5OnH51GsV1+xbhGMZ7QqF+EnlVyj7bWYoz6kSi W44lq0p9cGFu+pVe4AkvSKUpav7u6ZpRw7wgKvQio0YtiRKNX4TklUIQTcIXpN9L 5ictFU1zwIgmsva2FLC5hyygu8NwG7csQNNrR944iyIv9Z2we3w/7A+IB8mdU4qp OR+ZiPuuzZa65vPnJzsJaeo5EwkWkQl+rK7c1687JNZMvajZcEinTT8QKkEcIbUO lHz/lRH0SqWFwJL2phWkjg5z56jkjLfT+11nZvR9JiQcwDI/VxmaE1Guvb8Ni5ov NJyhw1pxlqBJIEnMJQiyZ0NK7PAMZoHJMk5i/hadIXsfKeTKhZ1PdJUog1wGjrok MJB+eh6bMEolGD5LS/WTb5sIBBC8Lc7tHXfb8MenfbVDoqCjAImo4NBPff0RZlHn 4/fCQT2Aj65qhHRld+35vpsCJvhkhEzfWHlrsGaE1q3UuwZIc8gpnSVNAuPf2sDm QJ6n4aMj2Bwn9Q/eyd3Sp9+5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICYDCCAeWgAwIBAgIQIq9OUsJgV5tEnB3eAcjjGTAKBggqhkjOPQQDAzBoMQsw CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTkwNwYD VQQDEzBNaWNyb3NvZnQgRVYgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 IDIwMTcwHhcNMTkxMjE4MjIyMjE2WhcNNDIwNzE4MjIzMTQzWjBoMQswCQYDVQQG EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTkwNwYDVQQDEzBN aWNyb3NvZnQgRVYgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ03fnXAKvhJipfmjaLsLzJwAVzzNXWIcv2 V/zPtYu95jSvILE9SarFZ1WC4e0w3WvtRct8LaGsrpcfP3ZgUX+syov/pZtB5dNK 8iXVAdv9+2xOyZaj3fdTNCt3HjFWwr+jVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRj5/TgIgrMsBbPtD8G9YPw3/lbkTAQBgkr BgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNpADBmAjEA3TGYWPADxBwh+2rbOUzD Anq/uihpq4VbMUHY1MPLetkIGBcb+TU8qn4nCY74Y0fdAjEA/KDz7stlJkG4kFf+ U7+zxDvxU2jguTkFYMMbg+BWru/2RuJCYMC7U17GrFLHX4rt -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH +FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB RA+GsCyRxj3qrg+E -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd 6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf +I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn 4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFhDCCA2ygAwIBAgIQdlP+ufXH2+qLpHjUPj1r9jANBgkqhkiG9w0BAQwFADBc MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEyMDAGA1UE AxMpR2xvYmFsU2lnbiBDbGllbnQgQXV0aGVudGljYXRpb24gUm9vdCBSNDUwHhcN MjAwMzE4MDAwMDAwWhcNNDUwMzE4MDAwMDAwWjBcMQswCQYDVQQGEwJCRTEZMBcG A1UEChMQR2xvYmFsU2lnbiBudi1zYTEyMDAGA1UEAxMpR2xvYmFsU2lnbiBDbGll bnQgQXV0aGVudGljYXRpb24gUm9vdCBSNDUwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQC+PrPi5LejQfhLmafaJmRr7a5Jg1F9bGDgnwvvOzrGtOhJO81t pD4a1cpj6oN3AOJavVZsfIHB8NvmWtGbfW0ilijsmuO6t122ET7kesa4Gs8FIeko N2X05Mmt5l0kL0iGPt9vFc4qsqVe3JUEkuV4JvjfXDXhv4ZTZZPLGJjj2ewyDcoK 8P9VeTgfXcyd7c4VtlifTlrgsdNJFBisCGDmz8N9Io5vJnlDcWbmR4+ENqZsAFJ2 tERfGu8ixAY2guMcVpo9UvdTBFEoINGzdC0tYjcpw2S45fqp9UCl/msU4f1zGZoh I7HnzIajHCRItWw8IX8XU+lkriUXLPa7RJ44Z+9Ju1ty0xXdNRMfVUajRkmagvXP fNHseYLOSCvdVvoZrSW4i7Zw14Kj5z2vbkGmPWDOeU9qxMkmOUS9Aa8dYXH29fE1 RiceAxngMXlscVHfw3ZlIpUe02tpvBBZGJFX4p9i6QuOtoeP4b+DzUpYshDd7uP8 DxwBYH72OGpccrl5Hd3XQ0cd7u3v/Mis+1Ihf4OGa7zu6XZ+VQt8nt5kREQUrqrn JSowNhrxJ0Pwrf6jRddHyYF2IlzOjv3qDkEjuPjE9s1ljMt2mjytaoHEUb6tlA2M F5EoASwechJUUUKk6ywPlFQsJTuTwzGGZIahbEjmvVBWzFCnashetvqFrwIDAQAB o0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU dYKqG7azjRmP/Kl5zD8CmvRPy9kwDQYJKoZIhvcNAQEMBQADggIBAAFMXi+4f3I1 vLUYMIB9N3yRb3r0PK0gVhu4qTP3/qhcVFg5VTwz0Hq5NPyNVg3uAaYnG3EvtZp3 RYcE2I9bA3IDOSQdD3iQxcb1+H/6kKkiGw1nxrZSUPSdqOmgxHV6k9qxpWrtDEfO oE6qcrTE5593kWX2awznDQdhCoevRhDV1ACrtbruRdFn5vd4n/l6wsennGwLXQ7F yz/6I9G7n+o1Asg3NUEfmt0cRLqASoDZTgmV0j6yMJI0nO2dID8TDec2vQpRDMNq V4rp2V2votwv1Za8xwjov6IV61QzYeVtzz31iZDiTY+cQL8Ug/KkNnol3njRCY2e hQevcgRUIV0n7eVCEcs61mOs79L7fWrKhIHjCjJbkMDEjZKsCEsK39dW3NtmjHJe PchOl6vLAaC2mLNXgDHvEU5AgmILem7K9SV7Wf/jvp/+/OpA6RogYKyGS6DBqUqx qtTyM/4TObvvrhf5NssQ+3e64ulbA4fxaNzHlhVZ8jhUB0//AtQ48HBooCemDmQR Kom2nr2CykmaRxG8u5h200NwxYhZ/M7nyxAhelShHb3N9+FOsxct6yTGx0pc2pgj i7Jl0l/HfPkqK6VeDVBy1a7c+0iLhWcyQIF+CvIJTXicyU1ozvrhsfzZQf7mCfEi ksRCXNTngVc4/6oai4r3z4f34t95em4E -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICIjCCAamgAwIBAgIQdlP+rhgmQ29p9RzCdxbyXjAKBggqhkjOPQQDAzBTMQsw CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEpMCcGA1UEAxMg R2xvYmFsU2lnbiBDb2RlIFNpZ25pbmcgUm9vdCBFNDUwHhcNMjAwMzE4MDAwMDAw WhcNNDUwMzE4MDAwMDAwWjBTMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFs U2lnbiBudi1zYTEpMCcGA1UEAxMgR2xvYmFsU2lnbiBDb2RlIFNpZ25pbmcgUm9v dCBFNDUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR2GW0DtfWEI6syai5h3YQlL+/o eSeJg8ODdfO2eGoIbaKtISoCkAbsmkCceoaRuViFyCiaLgv34nap37K9qcPpKRl5 CLJQ0MLFnQphDONdNwZKXP6EvcCAhPpLVSPg4j6jQjBAMA4GA1UdDwEB/wQEAwIB hjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSnn93TVM3b+Gy/JmwO5Ndbb4DM QjAKBggqhkjOPQQDAwNnADBkAjBsjFa2xTeuLZAreO2xHkYI0sNKKO94GQiOJDRG T4dxYV+pEUpvMqsc0VJ7qjrq5ZoCMFUrdy/O+D+baEra16hLRQ1+smv2bNqxFeK8 SBl3i1fBXRTXQQDMJlLQILgZT5bnmg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIQdlP+uT3Z5+kmMqzWCr6sODANBgkqhkiG9w0BAQwFADBT MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEpMCcGA1UE AxMgR2xvYmFsU2lnbiBUaW1lc3RhbXBpbmcgUm9vdCBSNDUwHhcNMjAwMzE4MDAw MDAwWhcNNDUwMzE4MDAwMDAwWjBTMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xv YmFsU2lnbiBudi1zYTEpMCcGA1UEAxMgR2xvYmFsU2lnbiBUaW1lc3RhbXBpbmcg Um9vdCBSNDUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC6dDPsJ9wS OCEbxdNhKNZavE/fi8yRhEMkV7xkIbw7HB89T4ytB7fzxdcC6REUgpqqtJRyO3EN Gu9oa4V5jq9m6liYDbrBfHnS/82zbzFF0AV0BAByaid+uDc/Oojtl4P1qzVND59Z O/Uv31nFfKUydmCWyO3u+AR+GVFyqL9EQXq8ex47AJu8uuCWv5D+jZvDcosAEvgg OmA498HMhYr7h3kuoSsg5sughZEjtsQoB1Qo3uwQMU+K8s0UHx7dVRzqKDFM+SFq qM3zlmf6AUGbzQ8LaH+73vFD6hflsNxwIrNpNll0a8bliSp85QuBXas/j7jRdnLz fKKp4pdBv8yMRf5hyfZsBwsABOgVI0+CKi3278P6ETZIodH9ejk6NF2jLA6bd1Ag NEDdsQMxrV/pYodzlgNh95Sw2VxsT+cUxeHxew0jnM1wjB1q3kotiyq720IUBQeq +xTcMdP2H2zLvmhmRHBNbRf5cesFc46RknXraFwe9kRhGCli3RdmiOwouklv2z53 /rkxH3UcGKKmR73Y7kiFO/2z4g8/KpjGmvqCb7GlpYYdWjr6pGx0D3dSYWp/hyne OZuL7rNFYDAklxUSKoUwkyaslqYt6HBtC6kyrSybKAp2QvJVYVGYlN7t9sUXbzwV ELAOrbDexRb0ZdHML1pWCM+ZxPBVkcIseQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC AYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQURrIcd+F7FfClOaFw3tHELupt st4wDQYJKoZIhvcNAQEMBQADggIBABZ8CmdKAzyTKj4cT0ZVsJqeiOHrU/1MVXmE +Wy2n6kKtomrVAcUFkpJWvS4LoYUxH4ZifmHiLzsstKVjOAM+fKUZqaYVxuh39Fx fYy1+HEC3RO2vvqwMcMsZ+saGA4aTdwszzFcYSipneNqLK5QSw460Gn7ijRE335L jhqQCdox2sovpff0Nyw1DRpizTx7PFZ3ZZVclHNwn2EvaWQjHUx5B8IXfDrtqm1x AxRiRcy3PlTYUXFC6juSQqUvVIGjsAxWWFa75JjuZscR+ahFF+JlKore4qjOxS32 9c6t8OMKCd1Te2ypbIZ+od42NQAPX4D9RbtxZkPURCzQuwFOmZ4+TeFeVh8FeoId ssstpTO5OeXEt9pC4b3QlEKA+hiUO5NDqMiUOm1+nfxPoMLT5aWqECZvBiJb4AHi Sr8Z5USesK2rGdLN60fEYoHs8MJ6jUz9wiW3vCxwjqqtUvQUPKp4HQTTydUlgqda y4x8H1cCO4cbyNf5VBodyhpLJ7HiSu/nmkAUT6U8n9WjvpQ1nMLXPyjupBcrQ71k p9ev6VPnp3cexRIbMeJLxn+eHO6jOpRQXaZQBlJeRQMrtADgwe3YDcGuu0kJgYJa QkOvmWO4FNE8i93V8FTtcmfC9so+NYSHgA1SlVBB1rINGUAvthNN97Fg1HbFVzlu WqJeCnnc -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcDCCA1igAwIBAgIQdlP+qExQq5+NMrUdA49X3DANBgkqhkiG9w0BAQwFADBS MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UE AxMfR2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IFI0NTAeFw0yMDAzMTgwMDAw MDBaFw00NTAzMTgwMDAwMDBaMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMSgwJgYDVQQDEx9HbG9iYWxTaWduIFNlY3VyZSBNYWlsIFJv b3QgUjQ1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3HnMbQb5bbvg VgRsf+B1zC0FSehL3FTsW3eVcr9/Yp2FqYokUF9T5dt0b6QpWxMqCa2axS/C93Y7 oUVGqkPmJP4rsG8ycBlGWnkmL/w9fV9ky1fMYWGo2ZVu45Wgbn9HEhjW7wPJ+4r6 mr2CFalVd0sRT1nga8Nx8wzYVNWBaD4TuRUuh4o8RCc2YiRu+CwFcjBhvUKRI8Sd JafZVJoUozGtgHkMp2NsmKOsV0czH2WW4dDSNdr5cfehpiW1QV3fPmDY0fafpfK4 zBOqj/mybuGDLZPdPoUa3eixXCYBy0mF/PzS1H+FYoZ0+cvsNSKiDDCPO6t561by +kLz7fkfRYlAKa3qknTqUv1WtCvaou11wm6rzlKQS/be8EmPmkjUiBltRebMjLnd ZGBgAkD4uc+8WOs9hbnGCtOcB2aPxxg5I0bhPB6jL1Bhkgs9K2zxo0c4V5GrDY/G nU0E0iZSXOWl/SotFioBaeepfeE2t7Eqxdmxjb25i87Mi6E+C0jNUJU0xNgIWdhr JvS+9dQiFwBXya6bBDAznwv731aiyW5Udtqxl2InWQ8RiiIbZJY/qPG3JEqNPFN8 bYN2PbImSHP1RBYBLQkqjhaWUNBzBl27IkiCTApGWj+A/1zy8pqsLAjg1urwEjiB T6YQ7UarzBacC89kppkChURnRq39TecCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgGG MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKCTFShu7o8IsjXGnmJ5dKexDit7 MA0GCSqGSIb3DQEBDAUAA4ICAQBFCvjRXKxigdAE17b/V1GJCwzL3iRlN/urnu1m 9OoMGWmJuBmxMFa02fb3vsaul8tF9hGMOjBkTMGfWcBGQggGR2QXeOCVBwbWjKKs qdk/03tWT/zEhyjftisWI8CfH1vj1kReIk8jBIw1FrV5B4ZcL5fi9ghkptzbqIrj pHt3DdEpkyggtFOjS05f3sH2dSP8Hzx4T3AxeC+iNVRxBKzIxG3D9pGx/s3uRG6B 9kDFPioBv6tMsQM/DRHkD9Ik4yKIm59fRz1RSeAJN34XITF2t2dxSChLJdcQ6J9h WRbFPjJOHwzOo8wP5McRByIvOAjdW5frQmxZmpruetCd38XbCUMuCqoZPWvoajB6 V+a/s2o5qY/j8U9laLa9nyiPoRZaCVA6Mi4dL0QRQqYA5jGY/y2hD+akYFbPedey Ttew+m4MVyPHzh+lsUxtGUmeDn9wj3E/WCifdd1h4Dq3Obbul9Q1UfuLSWDIPGau l+6NJllXu3jwelAwCbBgqp9O3Mk+HjrcYpMzsDpUdG8sMUXRaxEyamh29j32ahNe JJjn6h2az3iCB2D3TRDTgZpFjZ6vm9yAx0OylWikww7oCkcVv1Qz3AHn1aYec9h6 sr8vreNVMJ7fDkG84BH1oQyoIuHjAKNOcHyS4wTRekKKdZBZ45vRTKJkvXN5m2/y s8H2PA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFejCCA2KgAwIBAgIQdlP+sEyg1XHyFLOOLH8XQTANBgkqhkiG9w0BAQwFADBX MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEtMCsGA1UE AxMkR2xvYmFsU2lnbiBEb2N1bWVudCBTaWduaW5nIFJvb3QgUjQ1MB4XDTIwMDMx ODAwMDAwMFoXDTQ1MDMxODAwMDAwMFowVzELMAkGA1UEBhMCQkUxGTAXBgNVBAoT EEdsb2JhbFNpZ24gbnYtc2ExLTArBgNVBAMTJEdsb2JhbFNpZ24gRG9jdW1lbnQg U2lnbmluZyBSb290IFI0NTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AKPQGKqmJaBoxSoYFVYt/dBLfaEecm4xsZ0STDc8LAzKutUukiBLkultAJxEbzgX 7xlg8skghJR6OwgNa0hl/NAeJPXU3NpHUphO342nitTllKh8siw4i+XSLZwAGTM3 irhsZWIblOjjm6R1ay2AGh0b5i+n7HHq6wQPsanAk1JhIC29UptoWDRLa0tbPm1y 1jjYlUGTTnn9T9W1/MiApVkIN+iyet62eQxB4PFg1i7y5KFN2BOrz45kW3zc5jEp Hg2Qtjjo0PY6TTDHePklFWfhz3/3k5B/3kD6aYt9oENfRfnCS5d/UWEuC2LOYNoN X3bMlJwd2IXs70V+vuoq0D8UjWkgfgxW/epp9KlEweatJ/9Ycah9LzufHn/ZcgXo kSSAGtQheY4uWvr5j7AQKDCNquDyk9s9cVGrs553LgaAN4oLTg+YejcboM1JpUEQ hMOfUG0vKI4u88+2x1SBbiychxEN7eP1hIsr/hSQu0ooVDRMZ/viKnN2JpFfx9o/ Np/aJy8nDcDHOf7b4/k2aYKAvfXB8aAz7od2H4gJft3oQbS+DxCkBuXt4Qh7JfdH B7wqJQ8xOpGoqhMzkK8Op2DWgn1nTTQW4We7eeuCMEa0APhZuw78sxCRRSPY8TFC BLFgZ6hjg7KsP5/3GBiETFGFZpoqHNLbKbmbG0Ma6jPtAgMBAAGjQjBAMA4GA1Ud DwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQHQVdLz+EcFlPV veuDbMyLKSGEvzANBgkqhkiG9w0BAQwFAAOCAgEAJJwyIaZykDsC3f64SqaO8Dew W/8uP7Enbtl+nvSPX36/u4OFcMSKj0ZdxgpRKQLIxqBD/cICE/I6IZLdRpXDdLg8 VyIBhGhns1Beem4spPSj9QsM+VoNR4VFGk+bTNGokfOJqj5JqvWEsRe0S+ZeaRT9 RBsK/yDOCP70ZXKtxSJc3PKljMXcHWzb95anN2oaMLxrWTDjDUjxuGS5F5XG5J+D prLujbvhniXMwFaoAQeRa6Qu6hPr2/FJb+U7OpYn/kRQ4Qw0qxgQwaZwieJSyB2/ YtY0guX+x5gAYRCAdyd8rF1yQrgiD3Ig9wpH0FUGVU/vZG2z/DrgoVZPZ8lFVMQT IfurtfoxGlsGaU463x4gvCB/sCt0MtaodrM6PgseIETeh6b3UgsLjxT4MQOq6hHJ 2ZVGwIS72OsrLwpQxDgjf2+zv8Mnt/VMhwFzSQflwIyt7MeBQo/bXWsO2yHystfX kieXNu3GS19zR7kMuA3cSUtFsr8xjuFVhCfpWBoxwg4m01/Ri70gXXHfl2Hd35XJ 4Msv20ScC3QKfRuKtE+MKJZM6CnLilxY8bg9bsLd2myyB6mr6NHR0niwPtPFaY13 54Rk+LFW8fsZ0Yhmbz0bZcglRTwfdDseHDjr8aMsUsG/6CH0Lo4yg58V6vQNo5RH Rn7JhIJYRobXTF+4bZk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICITCCAaegAwIBAgIQdlP+qicdlUZd1vGe5biQCjAKBggqhkjOPQQDAzBSMQsw CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UEAxMf R2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IEU0NTAeFw0yMDAzMTgwMDAwMDBa Fw00NTAzMTgwMDAwMDBaMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxT aWduIG52LXNhMSgwJgYDVQQDEx9HbG9iYWxTaWduIFNlY3VyZSBNYWlsIFJvb3Qg RTQ1MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+XmLgUc3iZY/RUlQfxomC5Myfi7A wKcImsNuj5s+CyLsN1O3b4qwvCc3S22pRjvZH/+loUS7LXO/nkEHXFObUQg6Wrtv OMcWkXjCShNpHYLfWi8AiJaiLhx0+Z1+ZjeKo0IwQDAOBgNVHQ8BAf8EBAMCAYYw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU3xNei1/CQAL9VreUTLYe1aaxFJYw CgYIKoZIzj0EAwMDaAAwZQIwE7C+13EgPuSrnM42En1fTB8qtWlFM1/TLVqy5IjH 3go2QjJ5naZruuH5RCp7isMSAjEAoGYcToedh8ntmUwbCu4tYMM3xx3NtXKw2cbv vPL/P/BS3QjnqmR5w+RpV5EvpMt8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIQdlP+rHVGSJP15ddKSDpO+DANBgkqhkiG9w0BAQwFADBT MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEpMCcGA1UE AxMgR2xvYmFsU2lnbiBDb2RlIFNpZ25pbmcgUm9vdCBSNDUwHhcNMjAwMzE4MDAw MDAwWhcNNDUwMzE4MDAwMDAwWjBTMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xv YmFsU2lnbiBudi1zYTEpMCcGA1UEAxMgR2xvYmFsU2lnbiBDb2RlIFNpZ25pbmcg Um9vdCBSNDUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2LcUw3Xro q5A9A3KwOkuZFmGy5f+lZx03HOV+7JODqoT1o0ObmEWKuGNXXZsAiAQl6fhokkuC 2EvJSgPzqH9qj4phJ72hRND99T8iwqNPkY2zBbIogpFd+1mIBQuXBsKY+CynMyTu UDpBzPCgsHsdTdKoWDiW6d/5G5G7ixAs0sdDHaIJdKGAr3vmMwoMWWuOvPSrWpd7 f65V+4TwgP6ETNfiur3EdaFvvWEQdESymAfidKv/aNxsJj7pH+XgBIetMNMMjQN8 VbgWcFwkeCAl62dniKu6TjSYa3AR3jjK1L6hwJzh3x4CAdg74WdDhLbP/HS3L4Sj v7oJNz1nbLFFXBlhq0GD9awd63cNRkdzzr+9lZXtnSuIEP76WOinV+Gzz6ha6Qcl mxLEnoByPZPcjJTfO0TmJoD80sMD8IwM0kXWLuePmJ7mBO5Cbmd+QhZxYucE+WDG ZKG2nIEhTivGbWiUhsaZdHNnMXqR8tSMeW58prt+Rm9NxYUSK8+aIkQIqIU3zgdh VwYXEiTAxDFzoZg1V0d+EDpF2S2kUZCYqaAHN8RlGqocaxZ396eX7D8ZMJlvMfvq QLLn0sT6ydDwUHZ0WfqNbRcyvvjpfgP054d1mtRKkSyFAxMCK0KA8olqNs/ITKDO nvjLja0Wp9Pe1ZsYp8aSOvGCY/EuDiRk3wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC AYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUHwC/RoAK/Hg5t6W0Q9lWULvO ljswDQYJKoZIhvcNAQEMBQADggIBAF4runSXNERfdkgoQIST7gFu6aGz1oAl5nvk vAmRPQ/8dq3X1DAgu49g0JHWHPKc73gaK5QyAsEkllJSAtDz0fzymzlumeEfjkNB fZoeW8ldmoT8JuaH83RyJq2kG9k9O2pSoDwJHi8ee7MztEXH96yxr5NgrXauuLIV eOuDauv/20arJOXuAvqQH1nAL13Wt12kXBC3clP4QU7M+ngaJUrK/oViQ2HDtDeq gdL01joPvY1ZfjBH3itr5yFQM1/UZ5vUuGefPCeZA/+FQ45zEsogzehh1bFm3BfW OW0P288jN6GCiU4caz/WoM2qB50+Qiaq1wzu+ke/GlJ+0XWB08mKYhdtT4igIaAm Pq9t2WIwH+mYKK5ujdWOTHJmk4CNKuNVx2BnkEJWXCJRD7PcTjnuTd3ZHXgQVDtu 0JdvA7UesiNzxhKymmTQ/JWFJKj/36Gw3JFArt8JM6u53ZK38cyRdDtp62eXG5C/ 58egb3G7V7+3j1rtekBqFs2AhC0v4QLUJJRDsxX8DCsb/XFv/Mu8dRc6XoPSybMv G9WcjX9U/n5+5Fajh6ed4VlSlEGPbVu+hpWa/xp23UDSUUpwtB8zYyN3P+wnHlnk CIftNIJKDz/+oB3B9WdzRYZ49Kop6SeHxhnbxhMUwzlJh02gl+BlE/Wdd1bp2rNY xzrywM2C -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICNDCCAbugAwIBAgIQdlP+urId2CfpaRai64G+WDAKBggqhkjOPQQDAzBcMQsw CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEyMDAGA1UEAxMp R2xvYmFsU2lnbiBDbGllbnQgQXV0aGVudGljYXRpb24gUm9vdCBFNDUwHhcNMjAw MzE4MDAwMDAwWhcNNDUwMzE4MDAwMDAwWjBcMQswCQYDVQQGEwJCRTEZMBcGA1UE ChMQR2xvYmFsU2lnbiBudi1zYTEyMDAGA1UEAxMpR2xvYmFsU2lnbiBDbGllbnQg QXV0aGVudGljYXRpb24gUm9vdCBFNDUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATM zLQ6uxpN+J2RxHeB7RZ/AxF/uOlwhEiWQQmDYF30JJMqMh5eB/tHpIcqJNhXjFzZ qN8ReH+2RNXdr9UB2SY0X30xyMHu49a5/o+TAnCib2A7GXO1i3QKe51CF7wtPqej QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS1 g9ZwBorGnYaCd9WpBWU2E/HGSDAKBggqhkjOPQQDAwNnADBkAjBmpdF/fTQJFg4O ++53h4FKndiAh6BkaMtftnRYrMuymOKSEoktHT2xVGj4kvGNTkoCMBRVMnt2ZnSR ayTUWpTi5WqA9np9zULzWHhjwekCe1TdHAEVncu/BBhVQCT6IvLZXg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICLDCCAbGgAwIBAgIQdlP+sK9LdZCiGuSi1fJ2tTAKBggqhkjOPQQDAzBXMQsw CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEtMCsGA1UEAxMk R2xvYmFsU2lnbiBEb2N1bWVudCBTaWduaW5nIFJvb3QgRTQ1MB4XDTIwMDMxODAw MDAwMFoXDTQ1MDMxODAwMDAwMFowVzELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEds b2JhbFNpZ24gbnYtc2ExLTArBgNVBAMTJEdsb2JhbFNpZ24gRG9jdW1lbnQgU2ln bmluZyBSb290IEU0NTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIblQ9C7AGVe1koK Y4WeRQ+GIzJQVUljapzO96/0fiD5gDJbbrDv8sekLPtqWZAGdrcXjA51RDqAfMjc Aj3yzqGes0tyy8aM/cLJqoyuM1zqeUvcachWpDwoQXB0jmoaSKNCMEAwDgYDVR0P AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFGGZArQQ/xA823ra bDpwJANg8eeOMAoGCCqGSM49BAMDA2kAMGYCMQCP9ck/sU7z99GdtLoPPQqXJxCT 8lB8IonajNTKqWMkJiqLY4JjVMc08NGeehgLp+oCMQCxNY9K8vsmBsHTDY9i0bDE oF3pk9ZhxOGhuVyo9fFnXqIpN8JLxmdy/oyQ+SSAd7c= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW +1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 /q4AaOeMSQ+2b1tbFfLn -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp 15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS +YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU 98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/ca.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQCbp/6OQ/a3mr+8zRgBRlmSGr8QBgP4vUIxLn2Mk4uiZ8OcpRY4 YqL+TtREGDUc0ve+bv8RINrNlYXL2X+eJtbE2RJQ+RAiu+saw2K+RFTNeTCA1fwg 3ws5gBDcFbECqK1dOkuN/gV4JMHobn2/15iUBfeSJxdF1j5yqES8sVu7cwIDAQAB AoGBALZOnnBV3aLRlnw04kar9MCQnvLPeNteHyanQtjg/oxqZ8sR9+J2dFzSSv6u M5bc6Nmb+xY+msZqt9g3l6bN6n+qCvNnLauIY/YPjd577uMTpx/QTOQSK8oc5Dhi WgdU8GCtUmY+LE8qYx2NFitKCN4hubdrI76c+rnezIPVncZRAkEA9T5+vlfwk/Zl DOte+JtbXx3RtXKFJPMirOFqNVp1qnIlUm8XtBW6760ugiNYbVbGHgbd8JsZnkPH NC17TNLVJwJBAKJ7pDlJ2mvVr0cLrFhjAibz45dOipt8B4+dKtDIEuqbtKzJCGuP SCk4X2SgYz0gC5kH62S7rn6Bsa9lM98dztUCQASdLWNFYkhWXWZV006YFar/c5+X TPv5+xAHmajxT79qMFuRrX983Sx/NJ3MLnC4LjgIZwqM0HmSyt+nb2dtnAcCQCKi nIUhuw+Vg0FvuZM1t7W581/DfERckfgJFqFepLmh60eRqtvStR0kSSFYFw9mj1JV n9XfM/j/iHLM7du3rOkCQAw9R64yjcIBwcoSQxW/dr0Q9j+SnYgt+EhyXYXT30DS DdOJ06GXtb/P0peFBp26BnQU4CSS75yseZ1TdB4ZqaA= -----END RSA PRIVATE KEY----- ================================================ FILE: bundler/testdata/ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIC1jCCAj+gAwIBAgIUJhxh1ENJRZoFuCN+XB0xlP1zgeYwDQYJKoZIhvcNAQEL BQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxhcmUxFDASBgNVBAsMC0RF Vl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NBMB4XDTI1MDIwODIwMTYy N1oXDTM1MDIwNjIwMTYyN1owfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm b3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxh cmUxFDASBgNVBAsMC0RFVl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NB MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbp/6OQ/a3mr+8zRgBRlmSGr8Q BgP4vUIxLn2Mk4uiZ8OcpRY4YqL+TtREGDUc0ve+bv8RINrNlYXL2X+eJtbE2RJQ +RAiu+saw2K+RFTNeTCA1fwg3ws5gBDcFbECqK1dOkuN/gV4JMHobn2/15iUBfeS JxdF1j5yqES8sVu7cwIDAQABo1MwUTAdBgNVHQ4EFgQUuF7vrmdQt9bzB+VqvlWz ZzoNkj4wHwYDVR0jBBgwFoAUuF7vrmdQt9bzB+VqvlWzZzoNkj4wDwYDVR0TAQH/ BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQALmrNPUPlCyhabvgC8RsMZPhJjtxr9 TotLuoa49zsHH18djRZLrm8mNzBwUVVNJ1hgwSpRnyrc7T4HQTTvjpCnyXEVRil/ 9HQbpVPBSw5W6oK3koLG0rFnZXHocqK+Qri4FkbwsTK5qlea35OJWkODiUY/ykVM E4sm6QDE79e0Iw== -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/cfssl-leaf-ecdsa256.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBkTCCATcCAQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRwwGgYDVQQDExNjbG91ZGZsYXJl LWxlYWYuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjEb98b3L+COUBe8H vtt4REtsGig33wUYUDFVQDkiCXKW+CZ83FSYjyYzZTD23M4ub285ECtpJIzj/qJK kImt4KBJMEcGCSqGSIb3DQEJDjE6MDgwNgYDVR0RBC8wLYITY2xvdWRmbGFyZS1s ZWFmLmNvbYIWd3d3Y2xvdWRmbGFyZS1sZWFmLmNvbTAKBggqhkjOPQQDAgNIADBF AiEA+hlls8mNtLv47Rr8B7dGGKCDa1/qLHectmhdAnyrTVwCIFnAgTgiPAerNAct KjOJZdHDuaBGeu5o+5SLD232m/2E -----END CERTIFICATE REQUEST----- ================================================ FILE: bundler/testdata/cfssl-leaf-ecdsa256.key ================================================ -----BEGIN EC PRIVATE KEY----- MHcCAQEEIC2qaVydr67HuwWMrPQ3ljCVSsnbV7HbN78KqEX6a0GuoAoGCCqGSM49 AwEHoUQDQgAEjEb98b3L+COUBe8Hvtt4REtsGig33wUYUDFVQDkiCXKW+CZ83FSY jyYzZTD23M4ub285ECtpJIzj/qJKkImt4A== -----END EC PRIVATE KEY----- ================================================ FILE: bundler/testdata/cfssl-leaf-ecdsa256.pem ================================================ -----BEGIN CERTIFICATE----- MIICoDCCAiagAwIBAgITCWxPP1OUyLXZWxBBaLbwZxa0sTAKBggqhkjOPQQDAzCB jDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh biBGcmFuY2lzY28xEzARBgNVBAoTCkNsb3VkRmxhcmUxHDAaBgNVBAsTE1N5c3Rl bXMgRW5naW5lZXJpbmcxHTAbBgNVBAMTFGNsb3VkZmxhcmUtaW50ZXIuY29tMB4X DTE5MDUwMTAwMDAwMFoXDTI4MDYxNTA4MDAwMFowgYsxCzAJBgNVBAYTAlVTMRMw EQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYD VQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRww GgYDVQQDExNjbG91ZGZsYXJlLWxlYWYuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEjEb98b3L+COUBe8Hvtt4REtsGig33wUYUDFVQDkiCXKW+CZ83FSYjyYz ZTD23M4ub285ECtpJIzj/qJKkImt4KNmMGQwDgYDVR0PAQH/BAQDAgKkMBIGA1Ud EwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFKnNVsuomAwTY4BUp/FrWll3d8iuMB8G A1UdIwQYMBaAFD3f3FiGmOjKKSDupXSse/XS6RdXMAoGCCqGSM49BAMDA2gAMGUC MQC3oiPOxkBIfMChEqUjKCFwIwRuEyGVr02EXB5reJ0Jtix5ixqykOm8iyd4Afak szcCMBiLGSvek7JGbZRgeWX2J+42Hp0PcV3X1M4Exmjd8rNKWB2LEhqJuaXdidjb itmQYw== -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/cfssl-leaf-ecdsa384.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBzjCCAVQCAQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRwwGgYDVQQDExNjbG91ZGZsYXJl LWxlYWYuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE1iK8MOHciKSRv7f86hyK 3LglBebEs/aeNlOFg21HjLsHGLGnTkouiryC1rPJxwOSW567g5YWemaSPKo9D7Qw h/8EkqgDhDiI2II39l8Xr3QtH+lk+sxFm5ZIZVvbz3QvoEkwRwYJKoZIhvcNAQkO MTowODA2BgNVHREELzAtghNjbG91ZGZsYXJlLWxlYWYuY29tghZ3d3djbG91ZGZs YXJlLWxlYWYuY29tMAoGCCqGSM49BAMDA2gAMGUCMF4FEJtaKJXcrj6ZHxtFGWp2 IIBmMKRctjcQLm46S6toh9oT/TQGvIYBTiyYmxWhVgIxANsA3GzCIPSiwhKiBFxv 026lKuw4Ci9mlH4pJ7cJnCgSmxHP6jr8O+XovT7SzN1zag== -----END CERTIFICATE REQUEST----- ================================================ FILE: bundler/testdata/cfssl-leaf-ecdsa384.key ================================================ -----BEGIN EC PRIVATE KEY----- MIGkAgEBBDAEwBewBsRvgqvyy/aJ0NsoTqkbwFeu3bL6rLxLGcxCfKzlOYz5te8j BR4cPZbv5WOgBwYFK4EEACKhZANiAATWIrww4dyIpJG/t/zqHIrcuCUF5sSz9p42 U4WDbUeMuwcYsadOSi6KvILWs8nHA5JbnruDlhZ6ZpI8qj0PtDCH/wSSqAOEOIjY gjf2XxevdC0f6WT6zEWblkhlW9vPdC8= -----END EC PRIVATE KEY----- ================================================ FILE: bundler/testdata/cfssl-leaf-ecdsa384.pem ================================================ -----BEGIN CERTIFICATE----- MIICvzCCAkSgAwIBAgIUEOTb+fwacUOxBc1ryZ3YHHR7hYIwCgYIKoZIzj0EAwMw gYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T YW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0 ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAe Fw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGLMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEG A1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEc MBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTB2MBAGByqGSM49AgEGBSuBBAAi A2IABNYivDDh3Iikkb+3/Oocity4JQXmxLP2njZThYNtR4y7Bxixp05KLoq8gtaz yccDklueu4OWFnpmkjyqPQ+0MIf/BJKoA4Q4iNiCN/ZfF690LR/pZPrMRZuWSGVb 2890L6NmMGQwDgYDVR0PAQH/BAQDAgKkMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYD VR0OBBYEFDmNWkY9a2tS8p4M9RGYi2MJRbo/MB8GA1UdIwQYMBaAFD3f3FiGmOjK KSDupXSse/XS6RdXMAoGCCqGSM49BAMDA2kAMGYCMQCKWVbXphd4qec03igIHUU9 lBIUdzWNwlN5Vy2TzwFW4cqdzOCv2FNOGGutweLezjcCMQCJOR7Q3WbWf7wear2i gaoQjQW55KjDYA5bJjbh+x3MCROR+tcnfdT94ALUN2CKxEk= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/cfssl-leaf-ecdsa521.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIICGDCCAXoCAQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRwwGgYDVQQDExNjbG91ZGZsYXJl LWxlYWYuY29tMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBKd1KqqCaXulFe8vW Ed2vEoDKaEaLUijangPSSovty8hOqecN1rBDb8nIdQ0HOE6u57x+II0T6ju+dtXl 7G5qwGMBCtxdUXXsRSSedw2irlJ2DqoiOaXByo0w6pK9ggAYd3BNdR4Nrzx3+N76 TKfNqIyhczbUiQUp51e2m/foPs4r3qigSTBHBgkqhkiG9w0BCQ4xOjA4MDYGA1Ud EQQvMC2CE2Nsb3VkZmxhcmUtbGVhZi5jb22CFnd3d2Nsb3VkZmxhcmUtbGVhZi5j b20wCgYIKoZIzj0EAwQDgYsAMIGHAkFlyII6rIxYiv7S5RwwMi8G0qACjrbb1SMa oZA9vG+3G/SRcr5WmzKYgG09OjLT61KYfXu4mybdXXlXzHbx07llRgJCAKRuWU3O 3elclbkZvAGduasj3sj0Uee3nLG0YmDvz95sZPIp5JH54naeF4KKF6NJQF/rl9TW BHa3MZqM3JM7vMkI -----END CERTIFICATE REQUEST----- ================================================ FILE: bundler/testdata/cfssl-leaf-ecdsa521.key ================================================ -----BEGIN EC PRIVATE KEY----- MIHcAgEBBEIBnn+dzn3tVUMj9s3nRs8I7waob9iLi/QhsIj5leFRj44hbWGwfymm OHLJR1jIG8VzyYaNssSPo7ioMpgOpX+R14+gBwYFK4EEACOhgYkDgYYABAEp3Uqq oJpe6UV7y9YR3a8SgMpoRotSKNqeA9JKi+3LyE6p5w3WsENvych1DQc4Tq7nvH4g jRPqO7521eXsbmrAYwEK3F1RdexFJJ53DaKuUnYOqiI5pcHKjTDqkr2CABh3cE11 Hg2vPHf43vpMp82ojKFzNtSJBSnnV7ab9+g+ziveqA== -----END EC PRIVATE KEY----- ================================================ FILE: bundler/testdata/cfssl-leaf-ecdsa521.pem ================================================ -----BEGIN CERTIFICATE----- MIIC4zCCAmqgAwIBAgIUIvQg58qwdfu6CKACtoMSUpXFw54wCgYIKoZIzj0EAwMw gYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T YW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0 ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAe Fw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGLMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEG A1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEc MBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTCBmzAQBgcqhkjOPQIBBgUrgQQA IwOBhgAEASndSqqgml7pRXvL1hHdrxKAymhGi1Io2p4D0kqL7cvITqnnDdawQ2/J yHUNBzhOrue8fiCNE+o7vnbV5exuasBjAQrcXVF17EUknncNoq5Sdg6qIjmlwcqN MOqSvYIAGHdwTXUeDa88d/je+kynzaiMoXM21IkFKedXtpv36D7OK96oo2YwZDAO BgNVHQ8BAf8EBAMCAqQwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUOV/M hf5Eg/P51ORI9O66j16NOIAwHwYDVR0jBBgwFoAUPd/cWIaY6MopIO6ldKx79dLp F1cwCgYIKoZIzj0EAwMDZwAwZAIwa0PsvEQBCg2QNCuC8MH5sE8tuZwRE2lvm5ZS TmsnU0x3N0w3QbcIpQpAbI7HjXoCAjAI0QWAhoWvJAx3tG4xRsCH8FyATdXkRso2 J2ryeM+8xQ2vDDsJlThXpvT5qLQ/lWo= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/cfssl-leaf-rsa2048.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIDGDCCAgICAQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRwwGgYDVQQDExNjbG91ZGZsYXJl LWxlYWYuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0C6SSsXf use2IV8+6hSYqSPQdoQwZ5BYQnSxuKylArCrMXx8JGHrJP6Pj7GxRmH40v9u9VwZ vcrQOm8yUTuzAEf2Kd3uvXmVKJb2vc0BopsflpSEOLEuddTSHlHgdVHylqpbzB7Z rmyXXuWTtTFEaGmPVUmWcOBOy6pc/7hZv7HkTjaHLQu/uohic/NjO0oJaaUwds6m uwTCNSmMvtvoP51pyQJeuZjYIoWnnu+/DbtZYmH44VbHD0U+uSNKLZa4beWqDq5Z DwQvEVkuLqL331awzgIf0a4bhP+uc1kdWXZ8V+8aBbqtq6g6o9HdrzgNRR+9S3Ev EelCrxuWw9FQ3QIDAQABoEkwRwYJKoZIhvcNAQkOMTowODA2BgNVHREELzAtghNj bG91ZGZsYXJlLWxlYWYuY29tghZ3d3djbG91ZGZsYXJlLWxlYWYuY29tMAsGCSqG SIb3DQEBCwOCAQEAguCRmg2XzRlcq6neK/IdHZb+EeXSPo1BXsXrhzZZTpDTw4pC Kp+L9tG97t46rnlhRpwqY8zL/sXxBAlRB3G+VpsgLQzt18Gq0ZGBTjAHZBOeraKS /GMzig241SNvvvqEQR540TAZnzRgJzGJxCGQkhaXKIrGoh6yqiiTUkn5iu+K737U wX5xa09OdUnOc6MBbHFaynyWHZYjXzKv7zuZE+0VKjyKnLuHtRw8AS7zX/TkRf39 mgIp/hg3ZjWKTKDzudfMRVYS6nsbufViDTsOd7jMJa393H/wtKN2F+GyN8EIvuNt eVECUulWhbugcCAv3qgpiTgyx0eDSLBu9Ct/Kg== -----END CERTIFICATE REQUEST----- ================================================ FILE: bundler/testdata/cfssl-leaf-rsa2048.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA0C6SSsXfuse2IV8+6hSYqSPQdoQwZ5BYQnSxuKylArCrMXx8 JGHrJP6Pj7GxRmH40v9u9VwZvcrQOm8yUTuzAEf2Kd3uvXmVKJb2vc0BopsflpSE OLEuddTSHlHgdVHylqpbzB7ZrmyXXuWTtTFEaGmPVUmWcOBOy6pc/7hZv7HkTjaH LQu/uohic/NjO0oJaaUwds6muwTCNSmMvtvoP51pyQJeuZjYIoWnnu+/DbtZYmH4 4VbHD0U+uSNKLZa4beWqDq5ZDwQvEVkuLqL331awzgIf0a4bhP+uc1kdWXZ8V+8a Bbqtq6g6o9HdrzgNRR+9S3EvEelCrxuWw9FQ3QIDAQABAoIBAQDFQ5vzplQ9lIgM T0g6XpHZk8oww0lqmOhI8HKG33Dsf6N4HNE1WGOMhnpaWrH0U1mH9eqaLE9n/Aob lMpFFyCin42uVlGm0NJ5x7K+Xsex4POpp8kyPxIbLTJ88HCUOrZ39a1OWd1C3jsA /OFdy/VaSsw6sKQRCTsg2amN1o2UibDJYVW47ycv9cwjk/GEzzOSq32a9o6g6Gwd g3ycroIaxhDlGjS5l0IZ/ozhN+AS5dYcPgJRsYD/jTBqTSzIW2ePrcheznoRcgLK bb+UVQC+PZX8kycCcerPbcGc2YcBpZgmIkCj85+ITFt/BhH7+TSH9G7F8LTKAaJg qlYKF14BAoGBAPz8Jx0vAcv/4zIfCckuNy3kVu4PHBTMTBO5+tUg6CZgktRrroiV +Zq1lCuj2/Px3Lx9oaUie52iV5xgmEEax77xa1rVezY1PhGSFmngHqfumUJf8EEB snlAUpwBHvWU9B9OxKOHRrD9Y9ptXcBK30ZHLJT4t5JvbHVrKZF2J82hAoGBANKp ue+dOafhgc1F/ThD2VLuIi6Garf1pqNG3OMugMfieHAmr1RRYWwFErLoijt9dpe9 gXVecUm1KO4/0ZkR+7YDzUSifXvcizaw+XqjrtFerrz+Yao4gZssFnw/sLc2pbWm 1DHWxRnmh6MyHEEiA0KxElgutswhP8GIKN7INOG9AoGAR1sD2Upp8lVBiuCQTQtZ CvutvUXLwN4C00mQw06dzD1PDNU2jFXo6kcu/MQiBQOCJDQ3RLGeNk8U8QmZyDs6 fdPwWNWABEEuOZx/7+sEGo/E8KDIzj0hTuvioRf72H7kAHSiKBG+0asW4AQa/mLf 6R2oKHiipo4BBHluZxXxkiECgYEAuYXnzfH0+LhMi+77VjXKipJVYAvYqDGak2iw 1xH5MA9uabZn6iXRWkQNd6n7MvEHJBMsk6ScuIDmjwt9FwUTW/R1LeC8CfzsTToG O88zAggUczTD5hjlazakhr/AbVmfDh7h+RJferPe+AYFhAbkQDOZKDfbnGIbt+Cl va0rhTECgYAFb38TvJmEIzB1/nZ7sKbFmr2pYgzBqspQcprws6gZlWydd4OoTZiv QzSBDi3tGt07yJuntVlbuI6qejhFMmonGZuntNTvTZMmx2+W/F8EGByfWpLtB9W5 S+tx5/0d4MhOYHlt0EcdC7j881swY9LCrc/EOqg1O4BlTJ5+UJer+Q== -----END RSA PRIVATE KEY----- ================================================ FILE: bundler/testdata/cfssl-leaf-rsa2048.pem ================================================ -----BEGIN CERTIFICATE----- MIIDgTCCAwegAwIBAgIUIyiQolnMtXFv0JQk2OTdP28gJ+wwCgYIKoZIzj0EAwMw gYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T YW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0 ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAe Fw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGLMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEG A1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEc MBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBANAukkrF37rHtiFfPuoUmKkj0HaEMGeQWEJ0sbispQKwqzF8 fCRh6yT+j4+xsUZh+NL/bvVcGb3K0DpvMlE7swBH9ind7r15lSiW9r3NAaKbH5aU hDixLnXU0h5R4HVR8paqW8we2a5sl17lk7UxRGhpj1VJlnDgTsuqXP+4Wb+x5E42 hy0Lv7qIYnPzYztKCWmlMHbOprsEwjUpjL7b6D+dackCXrmY2CKFp57vvw27WWJh +OFWxw9FPrkjSi2WuG3lqg6uWQ8ELxFZLi6i999WsM4CH9GuG4T/rnNZHVl2fFfv GgW6rauoOqPR3a84DUUfvUtxLxHpQq8blsPRUN0CAwEAAaN7MHkwDgYDVR0PAQH/ BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFGj8EwH2TRWlwb0GBywqyPxj a3n9MB8GA1UdIwQYMBaAFD3f3FiGmOjKKSDupXSse/XS6RdXMBkGA1UdEQQSMBCC DmNmc3NsLWxlYWYuY29tMAoGCCqGSM49BAMDA2gAMGUCMFZol0PL/HT9mDED5IWr Lxv/dmH5zv6P0ggUjNBo+N2BM/LxiEAUM0o8Ozk7Dr8SuAIxAMQD8FRWdHsvrzE8 ACbAgluce3lTcC2x7BXMPpw3LojAr1+qIKgb++Y+DOs+DROHhA== -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/cfssl-leaf-rsa3072.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIEGDCCAoICAQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRwwGgYDVQQDExNjbG91ZGZsYXJl LWxlYWYuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA9xYBDoV2 tPx8lqZ/bH/wLvoPsg1/CXeknvRcNuxw1gu6c3IJBrKZlkFtiU6Y8FADiUBOVab/ Y0cQ/9EdeB2srPH4M5KNiPdWZPgxARWnRq5Ez8pvVASP2E2Zya1UnH5iJBau8e6S wBl8UaXnGwcA+CUv+FXcZtdoFh0Lqt3AdItQOkHVjSE6Cfiv5lsSW0ikMcoHFOHN ps4/9A4A/griT5lRDqQIycN7WD2k4+aKVreCWxbSteU35yIDJV6PGUtw8k41arJ+ kwuwYM3+YklR0Dsj0RxXn07oLqnf6IeNUogGhNVO7RvLdpfvrhlevHVXmmYj40fk GjU15KkZOKigMw/gDInI6Sc2jp8oPX9tjkaQYkF2t7AWOq01lh5TleMIoBFUqVcy +X/qejla0JaKCEyt/fiPUo7/SgucyFl8GrKfSdELUOKx5Vr2ZZ48QSfIlXle+tGt FD0AYUsO0ud0wclW5C+g8E27raTuR4RaZOj8/pmB7XNDszwxQ/97dBRpAgMBAAGg STBHBgkqhkiG9w0BCQ4xOjA4MDYGA1UdEQQvMC2CE2Nsb3VkZmxhcmUtbGVhZi5j b22CFnd3d2Nsb3VkZmxhcmUtbGVhZi5jb20wCwYJKoZIhvcNAQEMA4IBgQAKrSiJ qfeYzFQgCx+lj2rTDdGbiB9JoIamyTULWoN4WCxwS8KJWFQXOf4SkibHNLMMqBFY RpU/5mvjXVrKboNgzp6+QoWpdN/AHu6ldFz+o3Imna1yEscGZA7Qfie5hrf9kePe PCPEqnsG8j9qyip3W3p9/SsM2xUaei+YGVmAyzpXlYq0WZGsz+wVJ2zc6ZcxzTsC HN8cYafVR0ZmhruRUjhRM9mI+XXFYjk11lNo907Hue5n1acvqofz4RID2rx4e2nq 2DH4HZ1UvPDx93FJmMu/c8vLyMz17wPXCaC2M1SeVdXQeGg7JETvL95hJ++o3vLL /QJehGooK7Rcht4lc1logn6tQYNyRpIKiN6Bb+lBujTzVT461yPTk8D9xY0+jHIO nKXIXKVkoXXiL70aR0ZCviHx4sNOSZyqwhwiUedNP0rAacbk7AY4cdJWSHvcVH3/ qKlTkwOyr5AGX/SK/JTDvVjQWW95OI4a1xqEMlCN5jMOrQFwa181JMx4cmM= -----END CERTIFICATE REQUEST----- ================================================ FILE: bundler/testdata/cfssl-leaf-rsa3072.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIIG5AIBAAKCAYEA9xYBDoV2tPx8lqZ/bH/wLvoPsg1/CXeknvRcNuxw1gu6c3IJ BrKZlkFtiU6Y8FADiUBOVab/Y0cQ/9EdeB2srPH4M5KNiPdWZPgxARWnRq5Ez8pv VASP2E2Zya1UnH5iJBau8e6SwBl8UaXnGwcA+CUv+FXcZtdoFh0Lqt3AdItQOkHV jSE6Cfiv5lsSW0ikMcoHFOHNps4/9A4A/griT5lRDqQIycN7WD2k4+aKVreCWxbS teU35yIDJV6PGUtw8k41arJ+kwuwYM3+YklR0Dsj0RxXn07oLqnf6IeNUogGhNVO 7RvLdpfvrhlevHVXmmYj40fkGjU15KkZOKigMw/gDInI6Sc2jp8oPX9tjkaQYkF2 t7AWOq01lh5TleMIoBFUqVcy+X/qejla0JaKCEyt/fiPUo7/SgucyFl8GrKfSdEL UOKx5Vr2ZZ48QSfIlXle+tGtFD0AYUsO0ud0wclW5C+g8E27raTuR4RaZOj8/pmB 7XNDszwxQ/97dBRpAgMBAAECggGAcWoWPhYg8N5cScJPBvyKwOVjQvVS9IOIerXr hgJtoLJteQRFBGACg6ewobAEH3p6xQtRaZtn6qf6M5JHFpV4Z0ICDZodgVsWuu35 gGfyCk1/pGllRIl7hWvJRXtcNSEF507KKp65mZeZKtkeBZfnZ/+Zz0GKE2KYkl3u txVme5he0P7bCRbRTzZpdzEicegcBgaXzYwAG6rcTCgJaJKSYrsbK787kXE7MrvI 7hsqMLe3DByjx35ZdKx2CTcoNBId9RODWnPpANVrlNv7kbaZRqd5OI8b7JfblFsq F6vCzvDq+Quc8ID1zxRZv761pexejtDzghgQy7X2EVvMlHh4//wErgq6WfPjwyvU /zZczO0L/c1XwwkfBU6Yf6UuYCKngwifgvb7aGU4/aGNcD5SHRITwCHK/E9JrkR8 pkqerMxsf9uP5FxGdwOm1k77Lkap7Kx2Utt5l7stOY0fFUFz1YQdAHJUzhmbP3Zy C+TeX2/9+CudXM1parW7HQRlZeMJAoHBAP545khACfRvUWpxdQohp1Ol0FuDosYg NC75q12T8ovllx8Qly3aafJdd0NTvFmrBkBPTL3pCUWCyGZh6/E00fUL4dtD3zwz QUbm6hWGTgKHdeLLdae2wxcZ/NqmTvpY9o/p4jS9+StRKQtdsftLKCmRv7wfYkju UT7O+gRyGat/Rqpr9cTSKBXHUT+WJlITDrwk5QdydF7eKzLT8DROgcRRE1+FMJkj pO5ChuAxZr0Q0fISRm9Lu7aJ3H8QFfboGwKBwQD4kcCkZvRdz8BQsOsyHQ3SlGhx 5nwA7SPadXtfnpoW0ZlEdHwkPJzU1Z50z1ulEQymBTARPUQ4s28MQt8NXuRzHBrW PMUGgsspzT6FjiskhUc8k9PAZbEJE/axLKK2qSKktGuZj+VFih/9XPPTX4xSzlOg ntJEr2tc3TIv+JEOuJX6VT2URFLXgdOHXxAejS0DTGIg1aB4VGQpWzfbcJ6Cyf11 YyoyYWA25wdw7sB9kDHsd0Ej0mld5+l8JOd8hcsCgcA9jCpOcUa3GzF66EQhljAt WB6D89urxeA5OGPNN1pjob0iY1XdXkVfvGF7JEaa/XV+mm96Q2HdsRsdQDPb3CWn +h6/dLQKkG8KYhFd8WTu0aqelw026kpXTQ7OJ4lUna3M8wmmLgiVBIVD3X6NxAjL vRe9vW19LD70TQVFi/9PbnI+B+yilR3i3pl1IrDUCw32TYojefhRdbTHD2G6lP5n 6CAia0ls0KU0h1yt3uT1d5r/zJHCm3OkW8W76b0WQd8CgcEAh0czk4WgiomtPXz7 k3tycV9pdEuewxZMQ/FaIpD7hV2uzy2h/kqqg756jVHoq24a9yOtpEQ2o7Erx32B TRKOvALYrC3IgKGgFfDojODxo9+RBGvjezsc3TbrNEN5jnWAMCkswhcpDO5+OHJl FG1UviAiLTEieFUL1i9fx/G8aEmW/fV0HQQOHdE/INZgvG/Sxo/Ee+AnhDVRiZxm StwAuGdbtI4ygday+U5Eo3acdfmK4gmI/wjdZUj4riKbhQ5/AoHBAI0yzo+PIFi6 HjNYVoC7rZ39oQ0YCrEWrui+DRdEjnjec31Jw02AtKnv5swpDDHjgnIcd9ciQY48 rk7eC6IkVrL9hOxUzC9YQZX/2MBiOLjUkDkSLt+d5PL0OXiSg1O4fGJdGiVPF0Fc sF9p1UNEfGvXjzUB3ay0kMyCLitNe1BCvJlYXdSV9YmAMNvguE7TNU3OPiVv65PK 6OndznX41Pw7OlnLaq1sFQcYBmf5E7QSKYP+4HeV89Sc824VlCNxwA== -----END RSA PRIVATE KEY----- ================================================ FILE: bundler/testdata/cfssl-leaf-rsa3072.pem ================================================ -----BEGIN CERTIFICATE----- MIIEIzCCA6igAwIBAgIUL217UgdH/bkOgktlJzArh5mBF/EwCgYIKoZIzj0EAwMw gYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T YW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0 ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAe Fw0xOTA1MDgyMjM3MDBaFw0yMDA1MDcyMjM3MDBaMIGLMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEG A1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEc MBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTCCAaIwDQYJKoZIhvcNAQEBBQAD ggGPADCCAYoCggGBAPcWAQ6FdrT8fJamf2x/8C76D7INfwl3pJ70XDbscNYLunNy CQaymZZBbYlOmPBQA4lATlWm/2NHEP/RHXgdrKzx+DOSjYj3VmT4MQEVp0auRM/K b1QEj9hNmcmtVJx+YiQWrvHuksAZfFGl5xsHAPglL/hV3GbXaBYdC6rdwHSLUDpB 1Y0hOgn4r+ZbEltIpDHKBxThzabOP/QOAP4K4k+ZUQ6kCMnDe1g9pOPmila3glsW 0rXlN+ciAyVejxlLcPJONWqyfpMLsGDN/mJJUdA7I9EcV59O6C6p3+iHjVKIBoTV Tu0by3aX764ZXrx1V5pmI+NH5Bo1NeSpGTiooDMP4AyJyOknNo6fKD1/bY5GkGJB drewFjqtNZYeU5XjCKARVKlXMvl/6no5WtCWighMrf34j1KO/0oLnMhZfBqyn0nR C1DiseVa9mWePEEnyJV5XvrRrRQ9AGFLDtLndMHJVuQvoPBNu62k7keEWmTo/P6Z ge1zQ7M8MUP/e3QUaQIDAQABo4GbMIGYMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU CNwSHt+/vLhSILtfOWUCV+QDIicwHwYDVR0jBBgwFoAUPd/cWIaY6MopIO6ldKx7 9dLpF1cwGQYDVR0RBBIwEIIOY2Zzc2wtbGVhZi5jb20wCgYIKoZIzj0EAwMDaQAw ZgIxAKiloH2RwNibzfTbr0BmPAoXlTnhjn5yfaS0RazsIyP3TRaooZaL60yxovwa X+TamgIxAPQPyJO8pbgDPBwGsTs38PQWVA/wWOyKgX7cvdESfutd2Lq2qhhAAQS7 7Cw0Yjnv4Q== -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/cfssl-leaf-rsa4096.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIFGDCCAwICAQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRwwGgYDVQQDExNjbG91ZGZsYXJl LWxlYWYuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtY3sRFA2 cmwm4bEttx1TVRENJnd1re3fiR8YccUPcnmZ3uNY1sfnaEiHfTsxk10hbLOo24de YAZSC6w4W1ErGZnPO21kTrdlKUysmqfwLcjLGvTj7/3HKnbpfFQx3sV91+InI5HP 141mn78/Zgw22SZizysbn1x0QpnjK9WFZLdY6o7hNkAp53Jx9g85PiRROcLh+EH6 WMkxUUKx9zie0MPydFkiBlR+nGZ9SO5DGPKJGPVk7YF5n2XQNBWUXUq+cLqisAkS Op7FB1AryMiQCLVp6FATt/CRXA0O3d0hd9HirnLU6QMf6SgguYzFw/VjWF7AoCdX gNhtAo8hB5wR3/srInRhDz2YKhcTC8F6gUErCXKY6QF8QV8I8H10/Drp2MJwlxW1 9AfmSFogIs/Y5KPn0kMmcUhtMtMtx1xa21OdmbgD0vbMFE6cqoKdSYfImhK5tKfa xgQu/jPlshBztYp6jXtlfcYVQ4rcnHM/hqm6HJO4hh55U6wrw3OGv/HSfwjs63oS JJgqLzs8WWVJKahWozCotyAGrIF+/mCcsciMm7NsWWWsPizB275nDWh1t4zhUq3W P4A46klZqF2UuNCkxJsh4Dgz8C2xMReRmPkDN/hTE9iOPAunk8xL1dqtooLxGSKf oO4YLlBgEqYottodEFG3LUEycps65m4eIAkCAwEAAaBJMEcGCSqGSIb3DQEJDjE6 MDgwNgYDVR0RBC8wLYITY2xvdWRmbGFyZS1sZWFmLmNvbYIWd3d3Y2xvdWRmbGFy ZS1sZWFmLmNvbTALBgkqhkiG9w0BAQ0DggIBAIry/y2+Q9mLxlNZz7mKemrqj5Iz b+0IyaM6uReys6O1YcRf2KfnZ4TtURRa1ehjqOJsyYpLFEtzvATS9SktrcL/YnvL kWctJWEGJ0PJvhMpAy0uZy9uwI7moltcDtr1HdOG2riqfbhxTY+/g8mFhqWl5vFj S+ok7sSnztN0NQmDpXfuAVZIQQwEioeSDrcT2EcCf4ltuB23wzTMYqhflHZucEB6 eDr+7n8zcv4pXHvING6yR5G8eklR79zjlxO9QadNBjCWVllz9c37FMk6CvANfGLs YbIJTXYVPdmbyKMuYzIzgL1RiqTX4WNUVI1AputdGXytGkNPl7KbVvHsyp/A6tLR fZu6WW2NwjDC2s6HBYseo8huEIwG8zXV2Et1+yGZB6YHsw5Jv6W4UHD7pgpMiacg G4FOex7h66tTPGGHKmuouumCoGf2Zyr7oVeixx8OHwrl/tzoiyRzcmqZ+wW7IJA1 Nx8exenau8Kq+lCkj8dJObYNZNEQ7Hljo5w2ATChTXYaJYc49KOoSKd3d/YyVqIQ Qoeq+MTmxQuDcWbNZCgDnQZEPqW4Imv1cFApPH0t5JCRSutd7WNnNtC+kSPcXYhc NV71ovaHrio/7bXeNYKxJoYrfTe2mxMwrsnfuCwK2TgrfAL9yVQ+pfn2StopJOaN iznpt2q5PEkYOJEj -----END CERTIFICATE REQUEST----- ================================================ FILE: bundler/testdata/cfssl-leaf-rsa4096.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIIJJwIBAAKCAgEAtY3sRFA2cmwm4bEttx1TVRENJnd1re3fiR8YccUPcnmZ3uNY 1sfnaEiHfTsxk10hbLOo24deYAZSC6w4W1ErGZnPO21kTrdlKUysmqfwLcjLGvTj 7/3HKnbpfFQx3sV91+InI5HP141mn78/Zgw22SZizysbn1x0QpnjK9WFZLdY6o7h NkAp53Jx9g85PiRROcLh+EH6WMkxUUKx9zie0MPydFkiBlR+nGZ9SO5DGPKJGPVk 7YF5n2XQNBWUXUq+cLqisAkSOp7FB1AryMiQCLVp6FATt/CRXA0O3d0hd9HirnLU 6QMf6SgguYzFw/VjWF7AoCdXgNhtAo8hB5wR3/srInRhDz2YKhcTC8F6gUErCXKY 6QF8QV8I8H10/Drp2MJwlxW19AfmSFogIs/Y5KPn0kMmcUhtMtMtx1xa21OdmbgD 0vbMFE6cqoKdSYfImhK5tKfaxgQu/jPlshBztYp6jXtlfcYVQ4rcnHM/hqm6HJO4 hh55U6wrw3OGv/HSfwjs63oSJJgqLzs8WWVJKahWozCotyAGrIF+/mCcsciMm7Ns WWWsPizB275nDWh1t4zhUq3WP4A46klZqF2UuNCkxJsh4Dgz8C2xMReRmPkDN/hT E9iOPAunk8xL1dqtooLxGSKfoO4YLlBgEqYottodEFG3LUEycps65m4eIAkCAwEA AQKCAgAAn5EdFu1o7SghBDu08jvUAe/6ntRfmX53+Qxbb6LC8NnvYvZuHleUCxO0 AV0FNX+k4OUGg+t2Bu+HLLswzRGJz/ZfLNv4TTbismmxSjxP2+2elRKnQ0bIxYm9 rIhTTHhHInah76E4Czs79ysfjZEuo6wZK/u3S1j21ZJrFxuTIfIDNCRfzE6YhdMQ VjMLHJLO0PV3pbpXTbGGpuT3hVE+RD3z2k58mROqM8vgUTkXv9VqqYUEL7qcKnxR gXV18IjA2FMwqYdPfjYM9WCBGvcroHvRmVzH9+J332+aoWS5BZZypOBIQIN+iG28 VVhkeNYzenfM1PW+8n9FT/p8DTQegEJItmWOUsf0eNE6beHEOJZAuqnmLoKpD/je 4DXmcWaBxKTyCjLdG6BHPjAoF/XkNIW5gMXO1b3iGDYBWl9ChWfpzwuqVWDJerAy 9UH3VLPEHpZOahs6GKxMkYr3dAQRUDGW/Cj+a28VaAoeI99mszP5t95rUjq9YDx4 FI29BOwQOjTiF8qtjsJujrwjnbYbWV8xDcho4oNPGskzOTIxL5lOzzhWCMdo2qg5 skG6qOmJo1Ccezd2m54njHi46vj0tFePPnYcFtUZjnCxWmh1N4olc5pcmQA+y1j0 516JACIyd1VQ5OzFL/DwYYR5aUekZoDFqr3AEKadMgvC/WTXAQKCAQEA2NWpbe6K tYNvVk4XNyG9IzT/KfJ6uVAbwG5gebVbmNF87H20l9gbzPlZs0hmFw8sYPDVUVx3 OuWD0/ertCrKANX/9cfWa5fk8gmC9ESxOR7qMdiKF/9WUGfgQEfcyXms3L6N/xIv Ds/WOZMBnODHT7Y+th95J3sQqHy/CwYw5k4JIDXjaEVC8LawdkUjIzjnIJN+Rbou CD/5HFOmlg9vRaIXi5UY8lG5g0J0wLNXISF6SS+ROEOD6PKS9+M49vhTcbpOzKOL DkMqnRM8qFw58afX7/g3jNLUZLRRVd4xXsIhTnLe4+117m76cyaqPV7Hq0Ss5ZyD f+oBiv7KTusxqQKCAQEA1ljrKo0BTbzVLlZPb/SGRmHE+W23xYH3Y4P635gzEIRB fqptIvRAWTTC4rC7c2aLat3tlmm2TG2zcOAiDeP1QltEeOCIcOXXNkGjDd0LmaVW utkzMdRhBmK3u0GteZWI8z/G4ZyaddhhzLV9RB5hXcw0g46YLGY/oN+U4VAeypHx nqI181dK+D7L8tJnWkWqqUfHpiNAXPXI56rDbetCv8tU5/WuryaZEPHqbLhbqhdP ovvxcRXG4FzoPc/gY1db7fm46WXQHBJ2cZ0NWc5Clk27VxLzxsptzesCYE+juSKS zldIww9WkAPbvGS5eKgqLqYh/CCSiwjmpDHUQ803YQKCAQBUoVgGsyLqY4lSCxqe hwmWMzogOibSK0UZnzsCZdmBVMpIV2vkFBINt4jeI7TM7Twp/fWUUt2qXChO1Azt PgInv16upDe5OMi/+xxkkGcHX1yS5exIH32l1lU9YY74CAiDA9DSLFu3kUEQqaLo gwbnwr7JQJF96ld/G2lJOTpeuThwnPfMG7Rb1UIcdzGWrr/vBAI13svWpnlpJ/EO AqowaGp+LUxWT7VzWL3O9HBeWv2qkOlCJ3/VrM/V9pamNhgDfG8DChXdFDQOqJJ1 N8HZ4uOyIpQz35nMUGCqfhWQ4X40azs5hNYRoLkZto6dc1/FJgHBgIwGoePGR1nY 4Y05AoIBAGjH/OXHGj0LM1c8gAaljUI4pxabiPt3Bh1Stj+5YjUPwgiOfV1Z817o SOCSLoBCP6MVLACcWq5P7ikel+ccaZdvkDBa6rft01/FhFTRmssYJSaf6MPSI0AA 3/odKBVIgTMQGUPOzz8OcPimO78h7szwdzdcbI0/ypj00w21oee6ole+ygrTwGVM JVzld/qMFdo8qZ9QmjUXPYfqVTCVkgK5/h6KXkNm5ep/p+5PzRd/38E30hZK4/Zn 1GvrA7DsUpcpvTfzOmGOsPHnKVCeYLSi+RKexCaIbFb+LCIyrEFjYkqWJo6cH9+0 0yTsRDJ0WnKFahWbQqfOyRi49x/R4OECggEAGPyBEn6253gPawT87wIEvTlaoowp Of3aqpCVuksb4GinD/jGPmGwUOqrHGD3YEuIPSMQ2oBeEaSMPgMutUwTMt36J8rG L2zG5N4jvj5gv1zStdV03OEAae2QgTwNX6vI5NbQLT4R9yd0CNVsbRJrC0PJjEoi d+SOCU8jiYx7/h68n1xbgtkS7sFzXc4DMc+uUKoprTloZj7pKLX/NqpUKZKiWwAe Ss4mRqFIywC7uyazyr5PwOyuPE02PgUadeAJOsHTVspADf+gMG8R1OppjPs6Lqrj m2k2JUCh7tjMGyePf/HqILgyByWSXXuTlvUXD6i9qDThg+QbyZhGcPOtAA== -----END RSA PRIVATE KEY----- ================================================ FILE: bundler/testdata/cfssl-leaf-rsa4096.pem ================================================ -----BEGIN CERTIFICATE----- MIIEazCCA/KgAwIBAgIUcR0LLDGZDk/UiPGCOW6zwtLHwzIwCgYIKoZIzj0EAwMw gYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T YW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0 ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAe Fw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGLMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEG A1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEc MBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBALWN7ERQNnJsJuGxLbcdU1URDSZ3da3t34kfGHHFD3J5md7j WNbH52hIh307MZNdIWyzqNuHXmAGUgusOFtRKxmZzzttZE63ZSlMrJqn8C3Iyxr0 4+/9xyp26XxUMd7FfdfiJyORz9eNZp+/P2YMNtkmYs8rG59cdEKZ4yvVhWS3WOqO 4TZAKedycfYPOT4kUTnC4fhB+ljJMVFCsfc4ntDD8nRZIgZUfpxmfUjuQxjyiRj1 ZO2BeZ9l0DQVlF1KvnC6orAJEjqexQdQK8jIkAi1aehQE7fwkVwNDt3dIXfR4q5y 1OkDH+koILmMxcP1Y1hewKAnV4DYbQKPIQecEd/7KyJ0YQ89mCoXEwvBeoFBKwly mOkBfEFfCPB9dPw66djCcJcVtfQH5khaICLP2OSj59JDJnFIbTLTLcdcWttTnZm4 A9L2zBROnKqCnUmHyJoSubSn2sYELv4z5bIQc7WKeo17ZX3GFUOK3JxzP4apuhyT uIYeeVOsK8Nzhr/x0n8I7Ot6EiSYKi87PFllSSmoVqMwqLcgBqyBfv5gnLHIjJuz bFllrD4swdu+Zw1odbeM4VKt1j+AOOpJWahdlLjQpMSbIeA4M/AtsTEXkZj5Azf4 UxPYjjwLp5PMS9XaraKC8Rkin6DuGC5QYBKmKLbaHRBRty1BMnKbOuZuHiAJAgMB AAGjZjBkMA4GA1UdDwEB/wQEAwICpDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1Ud DgQWBBSOSNPIMrc1VNbVr/mF3I2ER9gXWzAfBgNVHSMEGDAWgBQ939xYhpjoyikg 7qV0rHv10ukXVzAKBggqhkjOPQQDAwNnADBkAjBHhS1O1+3IqsUjizMdu8emvSjn oEvB/wDNxgxJ6xV5J6dG8iW+DDNU9BLbWPyHezACMCaoKUJxN5DPm8cS/UGypRU4 Qffly9q3INCSfS7LtT9Ld7Ywi/lVvv3hWvfhl5KRdA== -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/cfssl-leaflet-rsa4096.pem ================================================ -----BEGIN CERTIFICATE----- MIIF7TCCA9WgAwIBAgIUWYLzdjKYWwotahY/fUcJs/Lx8TYwDQYJKoZIhvcNAQEN BQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH Ew1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNT eXN0ZW1zIEVuZ2luZWVyaW5nMRwwGgYDVQQDExNjbG91ZGZsYXJlLWxlYWYuY29t MB4XDTE5MDUwMTAwMDAwMFoXDTI4MDYxNTA4MDAwMFowbTELMAkGA1UEBhMCVVMx EzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzAR BgNVBAoTCkNsb3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC13oaBLRtgcGIn3q4mu8D9 E6guY3u9CaeXEvQCqLDSd5ZpJRH5lQBjhde7+HnUaaVf7px/FQYf61W8wgELzhBQ iNyoOgIH+cLTQJ0q5cNxlpkLtF2Yz3qj/xaE/MyuSeAl6SQrxiL3PbHeI6e+CxAz oJi+b1U8yvYFpn/rY98NCtOi1FsA8qr/nlKgS8H/j26yD9//u0jqDwwObKzrbYYT LcigMHfhYbzubhHTA8QtJcpVSqx4QfBSKf6JsusQ4fizviDBTSEIckzkzecubQkE jouBc/2T1KQZ0xP3ZsxbMJ3ljt2ibD760v+1PRN3XmEgGC6JoWaxmjPhp2BQ2jwx nbB+yLEOAOehZh5wr6mD4kuyJ2M4U0oo7fzB0yenOeJmNi8dQFKPsU81CebONJTB 3QKLffqZ1Kp86Bzgnjf3ok0lAJ56KSE4fIy2141msObvKN4LE+BzwsdMYY0AMMLK 9euMZfNpYJyMkBYks/u/1YPS+GddterUZKbOUf0comuooW01qeCOQgvXKt2GvmiC 5nPTzMIFwhlWWTH+9JzXMn/0qSSt2Tk80MICHl1411HSYarfgl3lnHjS5Q5St3se GvKZs4EZX77uVfpUuUk+6By1XKfcTmAczhVj7+wW8ijiXx80OoonciWqQRCr5Fr3 ueSlg93MjQtJa8+UNvhifQIDAQABo2YwZDAOBgNVHQ8BAf8EBAMCAqQwEgYDVR0T AQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUzT0RuIBsuNZ1D9gkJL6imgXpdagwHwYD VR0jBBgwFoAUjkjTyDK3NVTW1a/5hdyNhEfYF1swDQYJKoZIhvcNAQENBQADggIB AAvuIdJvzze6iZCp2pkgRICC77a6AJESYc8lmWByX8daaA+EdRvHoSsk80+55a9w NZi0HR1hClL/gc0cuq1LW2KGtQ0D/WDkJ4EP244bxbE+LZSNVi9RjEZLvI43euF8 NHAyg+LlwjHvaLTbvwt+UmUvrkUAlvp9Y6yyvQNkjusBxuy6DLwSwURoyF3Mevcx 5XnksH7dsdYdO00XF0WmENU2a3VD0vhnsrdHNCW+nvVNa8CeLqi4ZkptMMU0Xk63 nz2tyk0/wl3p9AsQtj3JSaBKrQ8Q8d/2nE4r5PxtrcDxscvpOI77qqserM5enJHR lgK8YZo/vfN0L/u2SWcErl2FO/uiIpWFIzG8g9FrwAz9NpCJ2WeI78GzcOxUvXV+ QLE+FfjFityIwMTegbrU1XK9dXq7Ldy/ZV9sTfF40eYTVoC30npO9fvWwVXn+SIu e3rSpSOcdgIGkPUZCcmlutSIYjFVWev/zWIl7n9Ol7Ngrx7x9m0kBBteqjFFbPki QfgW+6YU1HtFpZV01otosg1mp4FqAf1aTCof4mddZXZaLE2kVEyNVY/Ee4fR74Be 3Uj9FiHb1rgIjH9HzdZVCot3mVpEqGuMSpm++osbFtyYZkYQOVsMQG6fUwJ30CHu YxqvFMy5Vvlpqsmh8p7BjH8F+HNZGvg5dRnTKCRAg8Hv -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/client-auth/build_certs.sh ================================================ #!/bin/sh rm *.pem *.csr cfssl genkey -initca root-csr.json | cfssljson -bare root cfssl gencert -ca root.pem -ca-key root-key.pem -config root-config.json int-csr.json | cfssljson -bare int cfssl gencert -ca int.pem -ca-key int-key.pem -config int-config.json -profile server leaf-server-csr.json | cfssljson -bare leaf-server cfssl gencert -ca int.pem -ca-key int-key.pem -config int-config.json -profile client leaf-client-csr.json | cfssljson -bare leaf-client rm *.csr *-key.pem ================================================ FILE: bundler/testdata/client-auth/int-config.json ================================================ { "signing": { "profiles": { "server": { "usages": ["server auth"], "expiry": "43830h" }, "client": { "usages": ["client auth"], "expiry": "43830h" } }, "default": { "usages": ["server auth"], "expiry": "43830h" } } } ================================================ FILE: bundler/testdata/client-auth/int-csr.json ================================================ { "request":{ "names":[ { "C":"US", "ST":"California", "L":"San Francisco", "O":"example.com" } ], "CN":"Intermediate CA" } } ================================================ FILE: bundler/testdata/client-auth/int.pem ================================================ -----BEGIN CERTIFICATE----- MIIBsDCCAVegAwIBAgIUQ+SzyUX7rjP3Na9pqW9WjfZ++mgwCgYIKoZIzj0EAwIw TDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh biBGcmFuY2lzY28xEDAOBgNVBAoTB1Jvb3QgQ0EwHhcNMjUwMjA4MjE1MTAwWhcN MzAwMjA5MDM1MTAwWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ1aTpusR LupK5Fz1Z3zameCiHaBkmQj7W0RXzr6Z79K56Rpvw26TwLOrBn7TXtxDuWGLMsNo OZkrSrMMEVhKSaNjMGEwDgYDVR0PAQH/BAQDAgIEMA8GA1UdEwEB/wQFMAMBAf8w HQYDVR0OBBYEFEUmFK1ZjWprR7uasbTkKJkRbopDMB8GA1UdIwQYMBaAFH+WjwVZ HowLuyc+wkl/DmRpQNsJMAoGCCqGSM49BAMCA0cAMEQCIBf7y7WJq8Ok5BlmSwuo HfMI99OGo0Yx3o9OgOOGjN+SAiBqZtkw/M457iU0xPq93Ao0sOxQug0hix2B8Hel b65f8w== -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/client-auth/leaf-client-csr.json ================================================ { "label":"client", "request":{ "names":[ { "C":"US", "ST":"California", "L":"San Francisco", "O":"Client Cert" } ], "CN":"Client Cert" } } ================================================ FILE: bundler/testdata/client-auth/leaf-client.pem ================================================ -----BEGIN CERTIFICATE----- MIIBRTCB7KADAgECAhQkohme3ew65nA12dLsCP0HbB10dTAKBggqhkjOPQQDAjAA MB4XDTI1MDIwODIxNTEwMFoXDTMwMDIwOTAzNTEwMFowADBZMBMGByqGSM49AgEG CCqGSM49AwEHA0IABFSTiC6rAR2mPgwHOaE0tWA4VfVFzfEOou2NYsTohznuf38Q yf+EUB8aUtXzpkVyKTA+YMxnb/Dqd/Wwk3FpZlOjRDBCMBMGA1UdJQQMMAoGCCsG AQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAADwiVPrql46XbO5RGejGmw YjrpMAoGCCqGSM49BAMCA0gAMEUCIF8rB8803j76yJgKnxiu8r7k+/FIzXgukxjE HOhwtGVrAiEAzaL/hZTHmUPzc4t3K8fL8IDDlNK2PMf34/wx++zQv9E= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/client-auth/leaf-server-csr.json ================================================ { "label":"server", "request":{ "names":[ { "C":"US", "ST":"California", "L":"San Francisco", "O":"Server Cert" } ], "CN":"Server Cert" } } ================================================ FILE: bundler/testdata/client-auth/leaf-server.pem ================================================ -----BEGIN CERTIFICATE----- MIIBRDCB7KADAgECAhQodna3/WiA0mgCI09unScTMUF5sDAKBggqhkjOPQQDAjAA MB4XDTI1MDIwODIxNTEwMFoXDTMwMDIwOTAzNTEwMFowADBZMBMGByqGSM49AgEG CCqGSM49AwEHA0IABNLlARthGNIzbvAOpbg0VK0kvv0s1H3ouq0TbkVHfNounVBk NhuyJPY6g0FhYOXYUGAe3c/wGzQ9Y8N7oKgznLWjRDBCMBMGA1UdJQQMMAoGCCsG AQUFBwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFcK5HrSaocNvQd8qPj1PhUT N3uoMAoGCCqGSM49BAMCA0cAMEQCICety0pRXbTu47qx+ZXY670lXmKnxWvZDD4b ctUrPi0cAiAgxI6Z8CZsG7DybwMISScDqqIbgBZgr4RUIFOZ4SYP+A== -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/client-auth/root-config.json ================================================ { "signing": { "default": { "ca_constraint": { "is_ca": true }, "usages": ["cert sign"], "expiry": "43830h" } } } ================================================ FILE: bundler/testdata/client-auth/root-csr.json ================================================ { "key": { "algo": "ecdsa", "size": 256 }, "names": [ { "C": "US", "L": "San Francisco", "O": "Root CA", "ST": "California" } ] } ================================================ FILE: bundler/testdata/client-auth/root.pem ================================================ -----BEGIN CERTIFICATE----- MIIB3DCCAYKgAwIBAgIUe9lCrcENqlcuEIfCjz5sYf6G55swCgYIKoZIzj0EAwIw TDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh biBGcmFuY2lzY28xEDAOBgNVBAoTB1Jvb3QgQ0EwHhcNMjUwMjA4MjE1MTAwWhcN MzAwMjA3MjE1MTAwWjBMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5p YTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHUm9vdCBDQTBZMBMG ByqGSM49AgEGCCqGSM49AwEHA0IABHIGkTTSQv2h0/BShHPKSHgmiCWYwZN/ZcTU yOXEpVaWI8LRKkILBn3x9rOo+1+/svphVb0p+pCDRjMcbt/kL7qjQjBAMA4GA1Ud DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR/lo8FWR6MC7sn PsJJfw5kaUDbCTAKBggqhkjOPQQDAgNIADBFAiAiY3W19EHWVz5wHLkR8PlyqF7h a610mibj/x4L3zS3hwIhAMU7W0TWc2KEEvOdWMiqx08cqstq5LZp5C/zlP945XHA -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/dsa2048.key ================================================ -----BEGIN DSA PRIVATE KEY----- MIIDPQIBAAKCAQEA27xa+d5kAGDnxWkmZON9rNHw73/M4cwKpKGMpxGEdMt+u7wB Nt6tCH0v6dHo6726L6YUopxSzKahtzngxmT8G/P2dcbiVUm6r2N1T7zX5+9tnwWY PcpexdX/mXUnoB1yNHSckDiG0k5EGlQTTFXmg22aChvINIFaoEdR5IW3fOdiIX0z NWUBQ6eezsFuoy1anIb9WjOcCtmdvjPFtWdmZwGVfUp/CmJ+720GijTmsRB3dCqp QoxsFC+BtbtOtgX7pKPPsmICaYTgDqaY6Oc2HyWvS6xnl5uaHa33sFz9EisIy48n UbajWnLN8+bqSb+iIbR9xKxe1NRUO5rvJtXCmQIVAK2dU+z5hzWPAnuHp19T9y8J Km8JAoIBABk907ebpqMBTGcJ6kQiJshgmao2zN3uUWiA3GCrdnq8JxumqoRTbsLQ sxh+nvw24U8bK94NhhoUmQHfhl1GWb4seSUygoN7NUOC9wDH9QfrEi9S9eUS07gs LQ4QEYJPbxC1Wu8MIXJ2RpuaSFh+TClsasaGK54JOwNp4Nvh3CXYfwYL1Jtt9vOc tN2tF8Rr9zQrSgZDdsJvr/cIprxhY8JB4D54Bq77D4zzULz792TKTHXyjhObL4XQ cXz8tWloYF/wC8ME64CpVOx6GveN/cy6rINLG4T9epmheVDVmM33Mg2KgY+L+V3l l3QxBX/uygjuzCmK489u+OrP4cnXxJYCggEAVl000S2oxe2zAnt+oaeHc8QUO5B4 pb4k9MoLgM5AXGQQMmZcMwUaiSDe7q7FsM47ARXBI8jZkR/ZEAZuhoK/7qgo9VQV tW95SpMjesaj7LK0ocHU2djvUMzxZDWU+zkd2aJTusnbwWKwTXK64WAv97aKbf+O Avnjln3MkqfMzqR24w0ccdr8pZ9yTRyRyC6tf9G0/vnvSbZEALSsLXjuB6FIrpma 30S5KL4IR6cBIKlUHC9rf6ET3lLDFlM3B7YCVw/8VpENATd+sEez8f96lgQNcWSH 8Us611d7wGOjB6pDe7FueX+CeLFUzBEJ2YdiMRnQMVZ9nFY8i+s/KH2FFgIUeuC2 1y9hgnFoPYic5nnISNkQKP4= -----END DSA PRIVATE KEY----- ================================================ FILE: bundler/testdata/dsa2048.pem ================================================ -----BEGIN CERTIFICATE----- MIIFdTCCBTWgAwIBAgIJAJfyK94Nz1yPMAkGByqGSM44BAMwcDELMAkGA1UEBhMC VVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQK EwpDbG91ZEZsYXJlMRQwEgYDVQQLEwtFbmdpbmVlcmluZzERMA8GA1UEAxMIVEVT VCBEU0EwHhcNMTQwNDEyMDUwMTUyWhcNMjQwNDA5MDUwMTUyWjBwMQswCQYDVQQG EwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNV BAoTCkNsb3VkRmxhcmUxFDASBgNVBAsTC0VuZ2luZWVyaW5nMREwDwYDVQQDEwhU RVNUIERTQTCCAzowggItBgcqhkjOOAQBMIICIAKCAQEA27xa+d5kAGDnxWkmZON9 rNHw73/M4cwKpKGMpxGEdMt+u7wBNt6tCH0v6dHo6726L6YUopxSzKahtzngxmT8 G/P2dcbiVUm6r2N1T7zX5+9tnwWYPcpexdX/mXUnoB1yNHSckDiG0k5EGlQTTFXm g22aChvINIFaoEdR5IW3fOdiIX0zNWUBQ6eezsFuoy1anIb9WjOcCtmdvjPFtWdm ZwGVfUp/CmJ+720GijTmsRB3dCqpQoxsFC+BtbtOtgX7pKPPsmICaYTgDqaY6Oc2 HyWvS6xnl5uaHa33sFz9EisIy48nUbajWnLN8+bqSb+iIbR9xKxe1NRUO5rvJtXC mQIVAK2dU+z5hzWPAnuHp19T9y8JKm8JAoIBABk907ebpqMBTGcJ6kQiJshgmao2 zN3uUWiA3GCrdnq8JxumqoRTbsLQsxh+nvw24U8bK94NhhoUmQHfhl1GWb4seSUy goN7NUOC9wDH9QfrEi9S9eUS07gsLQ4QEYJPbxC1Wu8MIXJ2RpuaSFh+TClsasaG K54JOwNp4Nvh3CXYfwYL1Jtt9vOctN2tF8Rr9zQrSgZDdsJvr/cIprxhY8JB4D54 Bq77D4zzULz792TKTHXyjhObL4XQcXz8tWloYF/wC8ME64CpVOx6GveN/cy6rINL G4T9epmheVDVmM33Mg2KgY+L+V3ll3QxBX/uygjuzCmK489u+OrP4cnXxJYDggEF AAKCAQBWXTTRLajF7bMCe36hp4dzxBQ7kHilviT0yguAzkBcZBAyZlwzBRqJIN7u rsWwzjsBFcEjyNmRH9kQBm6Ggr/uqCj1VBW1b3lKkyN6xqPssrShwdTZ2O9QzPFk NZT7OR3ZolO6ydvBYrBNcrrhYC/3topt/44C+eOWfcySp8zOpHbjDRxx2vyln3JN HJHILq1/0bT++e9JtkQAtKwteO4HoUiumZrfRLkovghHpwEgqVQcL2t/oRPeUsMW UzcHtgJXD/xWkQ0BN36wR7Px/3qWBA1xZIfxSzrXV3vAY6MHqkN7sW55f4J4sVTM EQnZh2IxGdAxVn2cVjyL6z8ofYUWo4HVMIHSMB0GA1UdDgQWBBTdWYYdSWrZr5eD pf3QoSWZz0AbCDCBogYDVR0jBIGaMIGXgBTdWYYdSWrZr5eDpf3QoSWZz0AbCKF0 pHIwcDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRQwEgYDVQQLEwtFbmdpbmVlcmlu ZzERMA8GA1UEAxMIVEVTVCBEU0GCCQCX8iveDc9cjzAMBgNVHRMEBTADAQH/MAkG ByqGSM44BAMDLwAwLAIUP2uvD9JJpn1e7YZ/5QJIjlXhFl8CFGfNcNS49a0bN4Md 2HTcWtoMC+5k -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/empty.pem ================================================ ================================================ FILE: bundler/testdata/forcebundle.pem ================================================ -----BEGIN CERTIFICATE----- MIIFBDCCA+ygAwIBAgISESFHHMk7S+UhnJWGZxPSC9ovMA0GCSqGSIb3DQEBBQUA MFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMS0wKwYD VQQDEyRHbG9iYWxTaWduIERvbWFpbiBWYWxpZGF0aW9uIENBIC0gRzIwHhcNMTQw MjA2MjAzNjIwWhcNMTUwMjA3MjAzNjIwWjBZMQswCQYDVQQGEwJVUzEwMC4GA1UE CxMnRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkIGJ5IE9uZUNsaWNrU1NMMRgwFgYD VQQDEw9kaW5uZXJqZXJrcy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDprf7CgVDQMo/6RRYHNR5CLwzhvtehaNFTMR6jg6o2x0mb5uSBs6KTQZCe ruQE54ob84WkrFesw3+GKWXr0JagznYeOb7E5Kscshmg3sKbR109LRNfknfmyC/3 tNRUJiBQ8kghUAXvo/ITeyPS9oO/jUXJ9moiSn7qYBWiqiFS8ofF5PeD+IqtAyjH rkSUCWGR23wtsfebCX5zutj3agJEKZUx4yoNEh7OhOmolXKh2aaLf752vcHA+3Gk UO56IXLaEgh5Iz+hKR/OOFWL1pPyxXGp24QnQ41llxTvr8UT3cIKUdcTAKDhkc1l Cn9W0mpsUaKaD2wrWZXafXmEeAwLAgMBAAGjggHGMIIBwjAOBgNVHQ8BAf8EBAMC BaAwSQYDVR0gBEIwQDA+BgZngQwBAgEwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93 d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wLwYDVR0RBCgwJoIPZGlubmVy amVya3MuY29tghN3d3cuZGlubmVyamVya3MuY29tMAkGA1UdEwQCMAAwHQYDVR0l BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6 Ly9jcmwuZ2xvYmFsc2lnbi5jb20vZ3MvZ3Nkb21haW52YWxnMi5jcmwwgYgGCCsG AQUFBwEBBHwwejBBBggrBgEFBQcwAoY1aHR0cDovL3NlY3VyZS5nbG9iYWxzaWdu LmNvbS9jYWNlcnQvZ3Nkb21haW52YWxnMi5jcnQwNQYIKwYBBQUHMAGGKWh0dHA6 Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9nc2RvbWFpbnZhbGcyMB0GA1UdDgQWBBRA UKYM4Lxj64fguNZ0V4St1byujDAfBgNVHSMEGDAWgBSWrfqwW7mDZCp2whyKadpC 3P79KDANBgkqhkiG9w0BAQUFAAOCAQEATqaqPSIkvMGPukFvfXGcwjHMh/AmbRXD LBm1S23k4+4cvMowLV0glX9iGSGigfB54RrbsMdaSNK/CN4ok2GBspNYO7n+mpwy OopXHzOZPDZVFko1iqCjMvRLmCi8/iOWNvR+A2Tt4GKU42oEI2n7fTsqaHi+G+AG vti2kdiPj1oOvtwEgGhgY8tg38Q42LeCnNxb9/734PBvZ+Geg9nG9BjpVTRsyc46 tldfHV1I5G4Z6KZ7CZg1Z1IQlCRmVHiTLjWo4gess2Qh5bRZnbrE/Yxwj2u8oL4j kmEGPypraF2LFXmPntiiGnG9tqsp0h7fZA0KtFg4wmHd9YFGaG9wog== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEWjCCA0KgAwIBAgILBAAAAAABL07hQUMwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xMTA0MTMxMDAw MDBaFw0yMjA0MTMxMDAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMS0wKwYDVQQDEyRHbG9iYWxTaWduIERvbWFpbiBWYWxpZGF0 aW9uIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxo83A 3zNAJuveWteUZtQBY8wzRIng4rjCRw2PrWmGHKhzQgvxcvstrLURcoMi9lbnLsVn cZ0AHDK84+0uCEWp5vrdyIyDBcFvS9AmSgv2G0XATX6TvA0nhO0wo+nGJibdLR/Y i8POGdBb/Aif5NjiNeSgaKb2DaN0YEKyl4IkjkGk8i5eto6nbtlsfw07JDVq0Ktb aveXAgA/UaanbnPKdw12fJu2MBoanPcfKHsOi0cf538FjMbJyLvP6dx6QS6hhtrU ObLiE0CmqDr6D1MeT+xumAkbypp3s1WFhekuFrWdXlTxSnpsObpuFwY0s7JC4ffz nJoLEUTeaniOsRNPAgMBAAGjggElMIIBITAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUlq36sFu5g2QqdsIcimnaQtz+/SgwRwYD VR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2Jh bHNpZ24uY29tL3JlcG9zaXRvcnkvMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9j cmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwPQYIKwYBBQUHAQEEMTAvMC0GCCsG AQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjEwHwYDVR0j BBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZIhvcNAQEFBQADggEBADrn /K6vBUOAJ3VBX6jwKI8fj4N+sri6rnUxJ4il5blOBEPSregTAKPbGQEwnmw8Un9c 3qtnw4QEVFGZnmMvvdW3wNXaAw5J0+Gzkk/fkk59riJqzti8/Hyua7aK6kVikBHT C3GnXgYi/0046rk6bs1nGgJ/S/O/DnlvvtUpMllZHZYIm3CP9x5cRntO0J20U8gS AhsNuzLrWVO5PhtWjRXI8UI/d/4f5W2eZh+r2rKDV7QMItKGvNoy18DtcIV8k6rw l9w5EdLYieuNkKO2UCXLbNmmw2/7iFS45JJwh855O/DeNr8DBAA9+e+eqWek9IY+ I5e4KnHi7f5piGe/Jlw= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/froyo.pem ================================================ -----BEGIN CERTIFICATE----- MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf Tqj/ZA1k -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT 1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGujCCBKKgAwIBAgIBFzANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDkwMTAxMDYw MDAwWhcNMTkwMTAxMDYwMDAwWjCBgTELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0 ZC4xKTAnBgNVBAsTIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS8wLQYDVQQDEyZT dGFydENvbSBFeHRlbmRlZCBWYWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBALbD1LIPd205K+OtHnsfOYqXxWNvkrLeQuKp1XPtGzciyynId1iz+VDaAsMe 5GfaA3PPZ798mZkQxKXDVk2idd/fb6ebsuctoY9gN5PJKnor/8+P2EmYA3H28uIa8lFOtol9mYGN giFXldY7k/XWxtoa6YF1BpS3LdRi39Y2sLKegVrsg3BGRobaaCmk8LZCGthYeXChbEy9KReJkY5b diDANxVIoVb4cRSo3uM0EznGfezw4ITVxdzhx7HeNTnIBxlfvrjLlMd0DIYw3P7ZAgGplwjZ+U2w Dy1BTefWu94zgylm0uiqmWLn0XXv8jDVS8Y0ny7lvDtuiQYY1RlUqw0CAwEAAaOCAj4wggI6MBIG A1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSh4Z5FJXlNBtkCF5KC 1TCJciUUoDCBqAYDVR0jBIGgMIGdgBROC+8apEBbpRdphzDKNGhD0EGu8qGBgaR/MH0xCzAJBgNV BAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRhbCBD ZXJ0aWZpY2F0ZSBTaWduaW5nMSkwJwYDVQQDEyBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eYIBATAJBgNVHRIEAjAAMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDovL29j c3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9z ZnNjYS5jcnQwYAYDVR0fBFkwVzAnoCWgI4YhaHR0cDovL2NybC5zdGFydHNzbC5jb20vc2ZzY2Eu Y3JsMCygKqAohiZodHRwOi8vY2VydC5zdGFydGNvbS5vcmcvc2ZzY2EtY3JsLmNybDB1BgNVHSAE bjBsMGoGBFUdIAAwYjAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5 LnBkZjAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5zdGFydHNzbC5jb20vZXh0ZW5kZWQucGRmMA0G CSqGSIb3DQEBBQUAA4ICAQB0t6ovEOfd2LBrVB4iqoVIJoteg8K8OPOtyL5dpCi4aK1bD2LHL+k3 mfrgSRSzDuiG9NMd4XkJLgu0YAA5AujomtweGJMM/ahk1dtCDdnVWHsK7J1+1/l64Mw51WvlzCNZ wvN4y31wOnnmwdLmfsZ3wweuvrtCHXazom2jeKkB1FBnxwadIR4bJBieGIfgDey6OxNsdYehdnuJ xgN4MqTeHlwdE1gBW/CzieUIVl50agm+SiLSsflNBYacE6CJeHjsjLN3fW1R4YyQ+G0r1bAhTqFh UC6UaiFpdHrCImJsXjD7dcVr9aRjR49qVI5Y3/6p+qHyHnuDIBp1bB9v0P6HBYmKSlh1ib7ToBPG HgcoCi6/Xj8YMRPVPjgor5uF2/X+3OFf3M7cv7k7jAfxZwj8Zjbpv38wnYjveHMkFPlL64yQcOFG jho9odymXLY8AkpqnCvp2dBIcJNWBacQbNDpfA0yAEZXmg5Am4C6sKbnLxx3QHAcgNiJ6iQ71uYd FH43R1lodtwWU3QS7e7T26ILkhYZ9VIJthQ1Wr6ryYM4jykN9edEV1h6b3fs9vhwz4wewMZQTj1m 8Z2nCHMDe2ot4mMPQHio5+tA9WGn7h9nB6mCF7D6Wyg3d1Uq+fQaTFQBaVmXHuU2oAryGHVttN9v 7mEIA5DBmuu6mwAfeQZdxQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ 89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ 0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO 9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW /lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF 66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i 8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM //bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 nfhmqA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi 5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi 5nrQNiOKSnQ2+Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr 1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM 43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP Orf1LXLI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW 8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 70+sB3c4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 erfutGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ 1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ KpYrtWKmpj29f5JZzVoqgrI3eQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRFMRAwDgYDVQQI EwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFUQyBUcnVzdENlbnRlciBmb3Ig U2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBD bGFzcyAyIENBMSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05 ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFt YnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3Vy aXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3Mg MiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZI hvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLs qh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5N u6hLVxa8/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRydXN0Y2VudGVy LmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0GCSqGSIb3DQEBBAUAA4GBAIRS+yjf /x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ2 9ELw+HkuCkhcq8xRT3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/Ac ASZ4smZHcFFk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRFMRAwDgYDVQQI EwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFUQyBUcnVzdENlbnRlciBmb3Ig U2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBD bGFzcyAzIENBMSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05 ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFt YnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3Vy aXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3Mg MyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZI hvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN 2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+7 7uMMfTDWw1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRydXN0Y2VudGVy LmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0GCSqGSIb3DQEBBAUAA4GBABY9xs3B u4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm 5gZOngylerpuw3yCGdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQS CdS7kjXvD9s0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv 2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b vZ8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG 1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a 7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O 1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk 7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy +fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA 9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv 33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn 7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW NY6E0F/6MBr1mmz0DlP5OlvRHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC+TCCAmKgAwIBAgIENvEbGTANBgkqhkiG9w0BAQUFADA2MQswCQYDVQQGEwJFUzENMAsGA1UE ChMERk5NVDEYMBYGA1UECxMPRk5NVCBDbGFzZSAyIENBMB4XDTk5MDMxODE0NTYxOVoXDTE5MDMx ODE1MjYxOVowNjELMAkGA1UEBhMCRVMxDTALBgNVBAoTBEZOTVQxGDAWBgNVBAsTD0ZOTVQgQ2xh c2UgMiBDQTCBnTANBgkqhkiG9w0BAQEFAAOBiwAwgYcCgYEAmD+tGTaTPT7+dkIU/TVv8fqtInpY 40bQXcZa+WItjzFe/rQw/lB0rNadHeBixkndFBJ9cQusBsE/1waH4JCJ1uXjA7LyJ7GfM8iqazZK o8Q/eUGdiUYvKz5j1DhWkaodsQ1CdU3zh07jD03MtGy/YhOH6tCbjrbi/xn0lAnVlmECAQOjggEU MIIBEDARBglghkgBhvhCAQEEBAMCAAcwWAYDVR0fBFEwTzBNoEugSaRHMEUxCzAJBgNVBAYTAkVT MQ0wCwYDVQQKEwRGTk1UMRgwFgYDVQQLEw9GTk1UIENsYXNlIDIgQ0ExDTALBgNVBAMTBENSTDEw KwYDVR0QBCQwIoAPMTk5OTAzMTgxNDU2MTlagQ8yMDE5MDMxODE0NTYxOVowCwYDVR0PBAQDAgEG MB8GA1UdIwQYMBaAFECadkSXdAfErBTLHo1POkV8MNdhMB0GA1UdDgQWBBRAmnZEl3QHxKwUyx6N TzpFfDDXYTAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3 DQEBBQUAA4GBAGFMoHxZY1tm+O5lE85DgEe5sjXJyITHa3NgReSdN531jiW5+aqqyuP4Q5wvoIkF sUUylCoeA41dpt7PV5Xa3yZgX8vflR64zgjY+IrJT6lodZPjLwVMZGACokIeb4ZoZVUO2ENv8pEx PqNHPCgFr0W2nSJMJntLfVsV+RlG3whd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl /Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 oKfN5XozNmr6mis= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCBozELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzAp BgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5 WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5T YWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBB cHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZVhawGNFug mliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4Cj DUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXu Ozr0hAReYFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwi P8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7igEL66S/ozjIE j3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8w HQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9j cmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6LzsQCv4AdRWOOTK RIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4Qp xFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAq DbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjisH8SE -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR 5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ 7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW //1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 l7+ijrRU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx NzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhC AQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdER gL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcS o8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z 2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjX OP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDKTCCAhECCF9gWF8AAAAAMA0GCSqGSIb3DQEBBQUAMFcxCzAJBgNVBAYTAkpQMSswKQYDVQQK EyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRswGQYDVQQDExJTZWN1cmVTaWdu IFJvb3RDQTEwHhcNOTkwOTE1MTUwMDAxWhcNMjAwOTE1MTQ1OTU5WjBXMQswCQYDVQQGEwJKUDEr MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEbMBkGA1UEAxMSU2Vj dXJlU2lnbiBSb290Q0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2 aHl6pLrn0syNr+hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5K B12rPdFQuJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/j q1Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCisF5j Spf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3Lg59v5iynD w0orM4mrXCoH/HwjHitPCCL+wQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBV7W97k+VFMU5o1VWB oggfbN0JxXgacFfI3wiBrmZ3xnUP5O9JiwNcbP8ckKRystMWErIG+EaGrr+nFduFTfrCLU2ztbBD 73x+B9tfs1dGUXYHhkT9B+rxy0tFTWanMybE+UOqjRKz1I1otvcCebQtWtcDmAQsaZmv9GY7ZKyy wCvIaVSeTE5IGI3OV7U7UeUb1/o5YNtWRRO+52bVI/Z8SACwTO80jSKssi7RTDjN+lgDBu46c4cK BTrK5K/Uwe4chX8lFs8nAR+EincI0NNG6CDsn6SM8bzNxBI2gB7HCSiv6Ai+wNOyPtcuZz2jzrs0 +uKFzazOVR1FW3iF04V6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc 5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6 otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ 2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMxIjAgBgNVBAcT GUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZp Y2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FA ZmlybWFwcm9mZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTEL MAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMT OUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2 ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20wggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5uCp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5V j1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJH lShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf 3H5idPayBQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8 NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMBAAGjgZ8wgZww KgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lvbmFsLmNvbTASBgNVHRMBAf8ECDAG AQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQAD ggEBAEdz/o0nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36mhoEyIwOdyPdf wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm 7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YG VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 +iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy 2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H 4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y 7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm 8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp 9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu 01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf 8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t UCemDaYj+bvLpgcUQg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEEjCCAvqgAwIBAgIPAMEAizw8iBHRPvZj7N9AMA0GCSqGSIb3DQEBBAUAMHAxKzApBgNVBAsT IkNvcHlyaWdodCAoYykgMTk5NyBNaWNyb3NvZnQgQ29ycC4xHjAcBgNVBAsTFU1pY3Jvc29mdCBD b3Jwb3JhdGlvbjEhMB8GA1UEAxMYTWljcm9zb2Z0IFJvb3QgQXV0aG9yaXR5MB4XDTk3MDExMDA3 MDAwMFoXDTIwMTIzMTA3MDAwMFowcDErMCkGA1UECxMiQ29weXJpZ2h0IChjKSAxOTk3IE1pY3Jv c29mdCBDb3JwLjEeMBwGA1UECxMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEwHwYDVQQDExhNaWNy b3NvZnQgUm9vdCBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpAr3B cOY78k4bKJ+XeF4w6qKpjSVf+P6VTKO3/p2iID58UaKboo9gMmvRQmR57qx2yVTa8uuchhyPn4Rm s8VremIj1h083g8BkuiWxL8tZpqaaCaZ0Dosvwy1WCbBRucKPjiWLKkoOajsSYNC44QPu5psVWGs gnyhYC13TOmZtGQ7mlAcMQgkFJ+p55ErGOY9mGMUYFgFZZ8dN1KH96fvlALGG9O/VUWziYC/OuxU lE6u/ad6bXROrxjMlgkoIQBXkGBpN7tLEgc8Vv9b+6RmCgim0oFWV++2O14WgXcE2va+roCV/rDN f9anGnJcPMq88AijIjCzBoXJsyB3E4XfAgMBAAGjgagwgaUwgaIGA1UdAQSBmjCBl4AQW9Bw72ly niNRfhSyTY7/y6FyMHAxKzApBgNVBAsTIkNvcHlyaWdodCAoYykgMTk5NyBNaWNyb3NvZnQgQ29y cC4xHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEhMB8GA1UEAxMYTWljcm9zb2Z0IFJv b3QgQXV0aG9yaXR5gg8AwQCLPDyIEdE+9mPs30AwDQYJKoZIhvcNAQEEBQADggEBAJXoC8CN85cY Ne24ASTYdxHzXGAyn54Lyz4FkYiPyTrmIfLwV5MstaBHyGLv/NfMOztaqTZUaf4kbT/JzKreBXzd MY09nxBwarv+Ek8YacD80EPjEVogT+pie6+qGcgrNyUtvmWhEoolD2Oj91Qc+SHJ1hXzUqxuQzIH /YIX+OVnbA1R9r3xUse958Qw/CAxCYgdlSkaTdUdAqXxgOADtFv0sd3IV+5lScdSVLa0AygS/5DW 8AiPfriXxas3LOR65Kh343agANBqP8HSNorgQRKoNWobats14dQcBOSoRQTIWjM4bk0cDWK3CqKM 09VUP0bNHFWmcNsSOoeTdZ+n0qA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt 2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z 6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT 37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh 3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl 1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro g14= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEmzCCBASgAwIBAgIEQoctTDANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eTAeFw0wNzAxMDUxOTIwMzlaFw0xNzAxMDUxOTUwMzlaMIGwMQswCQYDVQQGEwJVUzEWMBQG A1UEChMNRW50cnVzdCwgSW5jLjE5MDcGA1UECxMwd3d3LmVudHJ1c3QubmV0L0NQUyBpcyBpbmNv cnBvcmF0ZWQgYnkgcmVmZXJlbmNlMR8wHQYDVQQLExYoYykgMjAwNiBFbnRydXN0LCBJbmMuMS0w KwYDVQQDEyRFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQC2lbZDQvrGbSpvSN+UTDlXBe7DeRFBaDbt7P6aAY+hOCj89xBG Zi5NHhqxGk7G0cCViLDJ/zGLMwPbt4N7PiCEXu2yViin+OC5QHE3xctHDpcqaMAilWIV20fZ9dAr /4JLya0+3kzbkIBQPwmKhADsMAo9GM37/SpZmiOVFyxFnh9uQ3ltDFyY/kinxSNHXF79bucetPZo RdGGg1uiio2x4ymA/iVxiK2+vI+sUpZLqlGN5BMxGehOTZ/brLNq1bw5VHHKenp/kN19HYDZgbtZ JsIR/uaT4veA5GX7NDcOKYBwTa84hi6ef1evnheu6xzLKCFfthzY56IEIvnT2tjLAgMBAAGjggEn MIIBIzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAzBggrBgEFBQcBAQQnMCUwIwYI KwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6 Ly9jcmwuZW50cnVzdC5uZXQvc2VydmVyMS5jcmwwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYB BQUHAgEWGmh0dHA6Ly93d3cuZW50cnVzdC5uZXQvQ1BTMB0GA1UdDgQWBBRokORnpKZTgMeGZqTx 90tD+4S9bTAfBgNVHSMEGDAWgBTwF2ITVT2z/woAa/tQhJfz7WLQGjAZBgkqhkiG9n0HQQAEDDAK GwRWNy4xAwIAgTANBgkqhkiG9w0BAQUFAAOBgQAMsIR8LRP+mj2/GAWVPSBIoxaBhxVQFaSIjZ9g 1Dpv6y1uOoakqdLBnYl6CBykLbNHjg9kSm9mA4M/TzSUNqopbYuNAiIrjM13pXCVhpHRtr9SvjNq a5n5b+ESvgTLM7/1EhpORLpbFk0wufO0dM5u8mhWWN3Yof1UBfQjkYXJ+Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB 7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk vQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP 8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft 3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 W9ViH0Pd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCBPKgAwIBAgIQESoAbTflEG/WynzD77rMGDANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMTYxMTA3MjM1OTU5WjCB vjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln biBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6Ly93d3cudmVy aXNpZ24uY29tL3JwYSAoYykwNjE4MDYGA1UEAxMvVmVyaVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBW YWxpZGF0aW9uIFNTTCBTR0MgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9Voi6 iDRkZM/NyrDu5xlzxXLZu0W8taj/g74cA9vtibcuEBolvFXKQaGfC88ZXnC5XjlLnjEcX4euKqqo K6IbOxAjXxOx3QiMThTag4HjtYzjaO0kZ85Wtqybc5ZE24qMs9bwcZOO23FUSutzWWqPcFEsA5+X 0cwRerxiDZUqyRx1V+n1x+q6hDXLx4VafuRN4RGXfQ4gNEXb8aIJ6+s9nriWQ140SwglHkMaotm3 igE0PcP45a9PjP/NZfAjTsWXs1zakByChQ0GDcEitnsopAPDTFPRWLxyvAg5/KB2qKjpS26IPeOz MSWMcylIDjJ5Bu09Q/T25On8fb6OCNUfAgMBAAGjggH0MIIB8DAdBgNVHQ4EFgQUTkPIHXbvN1N6 T/JYb5TzOOLVvd8wEgYDVR0TAQH/BAgwBgEB/wIBADA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggr BgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL2NwczA9BgNVHR8ENjA0MDKgMKAuhixo dHRwOi8vRVZTZWN1cmUtY3JsLnZlcmlzaWduLmNvbS9wY2EzLWc1LmNybDAgBgNVHSUEGTAXBglg hkgBhvhCBAEGCmCGSAGG+EUBCAEwDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIBBjBt BggrBgEFBQcBDARhMF+hXaBbMFkwVzBVFglpbWFnZS9naWYwITAfMAcGBSsOAwIaBBSP5dMahqyN jmvDz4Bq1EgYLHsZLjAlFiNodHRwOi8vbG9nby52ZXJpc2lnbi5jb20vdnNsb2dvLmdpZjApBgNV HREEIjAgpB4wHDEaMBgGA1UEAxMRQ2xhc3MzQ0EyMDQ4LTEtNDgwPQYIKwYBBQUHAQEEMTAvMC0G CCsGAQUFBzABhiFodHRwOi8vRVZTZWN1cmUtb2NzcC52ZXJpc2lnbi5jb20wHwYDVR0jBBgwFoAU f9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwDQYJKoZIhvcNAQEFBQADggEBAFqisb/rjdQ4qIBywtw4Lqyn cfkro7tHu21pbxA2mIzHVi67vKtKm3rW8oKT4BT+is6Dt4Pbk4errGV5Sf1XqbHOCR+6EBXECQ5i 4/kKJdVkmPDyqA92Mn6R5hjuvOfa0E6NeLvincBZK8DOlQ0kDHLKNF5wIokrSrDxaIfz7kSNKEB3 OW5IckUxXWs5DoYC6maZkzEP32fepp+MnUzOcW86Ifa5ND/5btia9z7a84Ffelxtj3z2mXS3/+QX Xe1hXqtIu5aNZkU5tBIK9nDpnHYiS2DpKhs0Sfei1GfAsSatE7rZhAHBq+GObXAWO3eskZq7Gh/a WKfkT8Fhrryi/ks= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC /tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM 8CgHrTwXZoi1/baI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkTCCBHmgAwIBAgIEOGPFrjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw0wODA4MjUx ODE0MjZaFw0xODA4MjUxODQ0MjZaMIIBNDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3Qs IEluYy4xODA2BgNVBAsTL0FORCBBRERJVElPTkFMIFRFUk1TIEdPVkVSTklORyBVU0UgQU5EIFJF TElBTkNFMUcwRQYDVQQLEz5DUFMgQ09OVEFJTlMgSU1QT1JUQU5UIExJTUlUQVRJT05TIE9GIFdB UlJBTlRJRVMgQU5EIExJQUJJTElUWTE5MDcGA1UECxMwd3d3LmVudHJ1c3QubmV0L0NQUyBpcyBp bmNvcnBvcmF0ZWQgYnkgcmVmZXJlbmNlMR8wHQYDVQQLExYoYykgMjAwOCBFbnRydXN0LCBJbmMu MS4wLAYDVQQDEyVFbnRydXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gTDFCMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3CH1aPl6zofyeN/YO00GfcYk5KnNnQFW5PZxF6p/dSIY 5HRtGz5W1bGmHt1ZJlPKBua6C283u6jGnBU7BhuHDMIaTdOBrttQZaU6ZE8wNJorqR/9K9E4cRlo 8o7re8lAPEjEGbG3ECXvRKfmd5t9Ipre2F7Zw87JcSK7ru8F1vIX51Z44VMFSiZzuMdJZ5MjD1ay j93JWQXlYxW0h35ARum1AHsDtA3klmcs3htZCxofuGNErsHXRIfEkVmcAENtxt8KsLEEzf6+MF46 JXLdoj7tRjrHpFxc5CXyEwfortqbGZui2WCdzpBHamF7QOgUwv4vhFpmF8CX00k43mMCnwIDAQAB o4IBJjCCASIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wMwYIKwYBBQUHAQEEJzAl MCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAyBgNVHR8EKzApMCegJaAjhiFo dHRwOi8vY3JsLmVudHJ1c3QubmV0LzIwNDhjYS5jcmwwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYI KwYBBQUHAgEWGmh0dHA6Ly93d3cuZW50cnVzdC5uZXQvQ1BTMB0GA1UdDgQWBBT18paIfQ3zKvlO 5zSgvUZ+E9YWyDAfBgNVHSMEGDAWgBRV5IHREYC+2Im5CKMx+aEkCRa5cDAZBgkqhkiG9n0HQQAE DDAKGwRWNy4xAwIAgTANBgkqhkiG9w0BAQUFAAOCAQEACyU8WPqO3KJCO3ZxbmzUTyu5U1yyWLmx 3G8a5OPEUPJBgrr0fcfB+fqMU7+5YrdJ4x0K/B/WxHZqk8t3Hix/0D8WY0xyTGdgD/iA1qeayqIz kQ9EsmY9jmgMQIUSN5G5gnc0WS1c34JuLLZ60gSQZ2hLcPwtuP+QZG9+kffRRzPzW7hYLiHYdWAb E8z4sqj6aqkqWk9FhUC03TQFt3DKAe/hgecRUNs+4tcQLmoVf7fUo2KyiWlhV8Z/jp7UJHrzoUNf oHqJ3FnNfdd1p7xT1Uc1xjEwIJ+burWD5olVAU2RO9aJNYc8g2t6KYLUS9TmFnSwARCraQYUN3v3 ZjA6xQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 /Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt 0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH llpwrN9M -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw 8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX 5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g 0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ 6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi FL39vmwLAw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp 8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td 3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs 3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r on+jjBXu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt 66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK +JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II 4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/int-bundle.pem ================================================ -----BEGIN CERTIFICATE----- MIIHaDCCBlCgAwIBAgIQIL094GkEPSU+HAucglL0IjANBgkqhkiG9w0BAQUFADCB 8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD LUFDQzAeFw0wMzAxMDgxMTI5MzJaFw0yNzAxMDcyMjU5NTlaMIHpMQswCQYDVQQG EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g KE5JRiBRLTA4MDExNzYtSSkxLjAsBgNVBAsTJVNlcnZlaXMgUHVibGljcyBkZSBD ZXJ0aWZpY2FjaW8gRUNWLTExNjA0BgNVBAsTLVZlZ2V1IGh0dHBzOi8vd3d3LmNh dGNlcnQubmV0L3ZlckNJQy0xICAoYykwMzEhMB8GA1UECxMYR2VuZXJhbGl0YXQg ZGUgQ2F0YWx1bnlhMRIwEAYDVQQDEwlFQy1HRU5DQVQwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDfskLh9womX5uXcd8X/lkEJSFSN05O8RDoyGrKH9H8 qADjvjZKmKY+4wJrlZpMwZ42UkHfa4qpcBK0x1lH5x3gr6qSpW1XC9PjJLCkUQI4 Uy+CCbINZ2dwwskeLHZJngYm0KlcRLTlzmppjW4YDimLkpRsjP8WDp/l0zaUP2cz fOrIwsor2c6PPQVJ/Oxmi+fcS9rbWTGRf1EzKKGTG1TxoFNvb6bWiYfYj1ILJC+L j39gVDi1JRCbPd+Vl5RCwVXieouKbyWQXc5kW5HUeWAhfnDcHlI4SDLI3u60GpfZ SCwIFKhsvgSJ26EhfJO0bzdyDDBTfVR6NgFMcXZ0f/7jAgMBAAGjggL+MIIC+jAd BgNVHRIEFjAUgRJlY19hY2NAY2F0Y2VydC5uZXQwIAYDVR0RBBkwF4EVZWNfZ2Vu Y2F0QGNhdGNlcnQubmV0MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MB0GA1UdDgQWBBQxalwKRk43r0LjsGArDA8tL5PfFDCCATEGA1UdIwSCASgwggEk gBSgw4tEqjelRb+XgFrR8Xiim+ldjaGB+aSB9jCB8zELMAkGA1UEBhMCRVMxOzA5 BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNh Y2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJh cnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRp ZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVDLUFDQ4IQ7is969Qh3hSoYqwE 893EATCB3QYDVR0gBIHVMIHSMIHPBgsrBgEEAfV4AQMBCzCBvzAsBggrBgEFBQcC ARYgaHR0cHM6Ly93d3cuY2F0Y2VydC5uZXQvdmVyQ0lDLTEwgY4GCCsGAQUFBwIC MIGBGn9BcXVlc3QgY2VydGlmaWNhdCDpcyBlbehzIPpuaWNhIGkgZXhjbHVzaXZh bWVudCBhIEVudGl0YXRzIGRlIENlcnRpZmljYWNp8yBkZSBDbGFzc2UgMS4gVmVn ZXUgaHR0cHM6Ly93d3cuY2F0Y2VydC5uZXQvdmVyQ0lDLTEgMGIGA1UdHwRbMFkw V6BVoFOGJ2h0dHA6Ly9lcHNjZC5jYXRjZXJ0Lm5ldC9jcmwvZWMtYWNjLmNybIYo aHR0cDovL2Vwc2NkMi5jYXRjZXJ0Lm5ldC9jcmwvZWMtYWNjLmNybDANBgkqhkiG 9w0BAQUFAAOCAQEAluCecOaIW+usV6L6Sy1E1kaIbO4Lk9tKRL+cXLj4CuhZTlaB CPCd83y3s49Um8yWnrxmx1Vuc7WVDvuPAxW3FZ/T0kPX0dsdnYa3uNM2VSna+7kt TxvMijJXVLr1Q9843o5fIU/rM0864gsrZxmaShOCGaIKP+EgcVvxQDQTEGzePq69 IFT6fhO7o3qTdYLEO0SgMG6XE1RiFO8AdEG3G2a2C5lfvZWZtw1TLoXoRr8TSiD5 u0E9wD59y9zN7h04i/qWH/CFEU38MDtpZfiHI4vdiA2N5onLWX3oLJcifnJzqWPz F5WbOKP2XcxBOBspQKYM7uRmx6Nn3GNY4CH/+Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq 7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p 26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi 1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu tGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFnTCCBIWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo YW1iZXJzaWduIFJvb3QwHhcNMDMxMTE0MTM0OTA4WhcNMzMxMTE0MTM0OTA4WjCB xjELMAkGA1UEBhMCRVMxKzApBgkqhkiG9w0BCQEWHGFjX2NhbWVyZmlybWFAY2Ft ZXJmaXJtYS5jb20xEjAQBgNVBAUTCUE4Mjc0MzI4NzFDMEEGA1UEBxM6TWFkcmlk IChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRy ZXNzKTEZMBcGA1UEChMQQUMgQ2FtZXJmaXJtYSBTQTEWMBQGA1UEAxMNQUMgQ2Ft ZXJmaXJtYTCCAR8wDQYJKoZIhvcNAQEBBQADggEMADCCAQcCggEAcYlZO6/h24nT orYU6BTdGuIYtxRc6TdV3SAClsN/rZFFVkTjXgfNmnFXZEuSVqAihLOrbtMaCG6l Km5S6bnAckqonY3n9qhbkY4pzqMkltgBL86BhrZehbr+gGWN6mx8RcAXpvj3Vr8h SpWfts0F+5rmJocAC/gEekSYiIvstRErXUke1plsmzpo5i++4YJTI4EQZ8cMwQjt wbHTqe0FR8jcnSU001c031EmXvMje8XtnrfAiSoD4nVq9V0pSZW2kFeDT4JihjZm ly3ec0j8MkcqcY5KBHv+0nuGYRYQSHDl3f2Zu7AnPGbkWhGaBn+SeVbpuCbxk8vy Vp4IptTxFwIBA6OCAd8wggHbMBIGA1UdEwEB/wQIMAYBAf8CAQswPAYDVR0fBDUw MzAxoC+gLYYraHR0cDovL2NybC5jYW1lcmZpcm1hLmNvbS9hY19jYW1lcmZpcm1h LmNybDAdBgNVHQ4EFgQUcMGV+l2lFr5i6KR949RkX8ThPp0wgagGA1UdIwSBoDCB nYAUQ5w2n7CeME3Gzl+tEKvlA6X6qRShgYGkfzB9MQswCQYDVQQGEwJFVTEnMCUG A1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpo dHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1i ZXJzaWduIFJvb3SCAQAwDgYDVR0PAQH/BAQDAgGGMCcGA1UdEQQgMB6BHGFjX2Nh bWVyZmlybWFAY2FtZXJmaXJtYS5jb20wKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25y b290QGNoYW1iZXJzaWduLm9yZzBYBgNVHSAEUTBPME0GCysGAQQBgYcuCgQBMD4w PAYIKwYBBQUHAgEWMGh0dHA6Ly9jcHMuY2FtZXJmaXJtYS5jb20vY3BzL2FjX2Nh bWVyZmlybWEuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEAP9WJ1qa16NtY9/a3dTmC QAVbr6XR2tFA6rleKf/Aa9DMLPAoIOA2rEN80jbT0ajC4LKmCt3lOyCYWg8Tekq8 xj/gANyOD2BKmGsuhLhY/rxuzKUEhxWqqmPmJmDXOGrghHOKhztN/ean5gl+haoO b7XIpxw70vbdYX+b1L19w8An5bqJZfsaQ9u10aolVFWEGDPbRB6Nc7zxILc/Dl4O rjLBmA9ppOcTyiBWhpw607UOt4YVnns1YwlPAoNmMeEVOoDDUAm7Gx53DwSFCs3N 4xTxu3qGLwTVWAxrv/ZjS3fOKzbg1X7ytL4KFdwcftfRexHgfWi9JBb9Uh/495q7 bg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFfjCCBGagAwIBAgIQZ970PvF72uJP9ZQGBtLAhDANBgkqhkiG9w0BAQwFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowgYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1h bmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBM aW1pdGVkMSswKQYDVQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9y aXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTd xc9EZ3SZKzejfSNwAHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH 9IY+Cvo+XPmT5jR62RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Z f7X8Z0NyvQwA1onrayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a 5JtsaZn4eEgwRdWt4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNG N4Tr6MyBSENnTnIqm1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R 7Qu2XK8sYxrfV8g/vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0 Czr56ENCHonYhMsT8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMAR gexWO/bTouJbt7IEIlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMo YX9w0MOiqiwhqkfOKJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKI f6MzOi5cHkERgWPOGHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPyw TEHl7R09XiidnMy/s1Hap0flhFMCAwEAAaOB8jCB7zAfBgNVHSMEGDAWgBSgEQoj PpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQw DgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRV HSAAMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FB QUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEF BQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUAA4IB AQB/8lY1sG2VSk50rzribwGLh9Myl+34QNJ3UxHXxxYuxp3mSFa+gKn4vHjSyGMX roztFjH6HxjJDsfuSHmfx8m5vMyIFeNoYdGfHUthgddWBGPCCGkm8PDlL9/ACiup BfQCWmqJ17SEQpXj6/d2IF412cDNJQgTTHE4joewM4SRmR6R8ayeP6cdYIEsNkFU oOJGBgusG8eZNoxeoQukntlCRiTFxVuBrq2goNyfNriNwh0V+oitgRA5H0TwK5/d EFQMBzSxNtEU/QcCPf9yVasn1iyBQXEpjUH0UFcafmVgr8vFKHaYrrOoU3aL5iFS a+oh0IQOSU6IU9qSLucdCGbX -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID0DCCArigAwIBAgIQFuWGeOBwlDlL39tO/KY73zANBgkqhkiG9w0BAQwFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowgYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1h bmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBM aW1pdGVkMSswKQYDVQQDEyJDT01PRE8gRUNDIENlcnRpZmljYXRpb24gQXV0aG9y aXR5MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEA0d7L3XJghWF+3XkkRbUq2KZ9T5S CwbOQQB/l+EKJDwdAQTuPdKNCZcM4HXk+vt3iir1A2BLNosWIxatCXH0SvQoULT+ iBxuP2wvLwlZW6VbCzOZ4sM9iflqLO+y0wbpo4HyMIHvMB8GA1UdIwQYMBaAFKAR CiM+lvEH7OKvKe+CpX/QMKS0MB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nT eTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zARBgNVHSAECjAIMAYG BFUdIAAwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsG AQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQAD ggEBAHjsU4nMWJ1jJdsVWxa5HLKxt/Sqib3Q3lS5DHsjKGKRfUDdSFnlAiG3Vll+ pX8MHWp4E0PgONUsALAM+7HcSCWDcNnkguU8PovJrH0XMBfXS1Pm3tXpUwBd/sj1 aZUekAaDZ9Ww02ZKaCDON9X/jKsRG6j5koYCtWuS4hH/GEvLDPX+VCPCcC+NKMjU VxP8AzvKBA/5CSp+1C3pXY8X4cRyjCWJFScGWOioc+NAaQZtGrJ5pp0WqASWeQYJ b2uQlNzRYBFWgodwJX8Kx7rSAPJHX3LgVsZtL7a+bOzRKQCoeRmtRo9V9jNJH8HJ MppQ/qXxmyYQTzbZCA3K17HKM8w= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE3TCCA8WgAwIBAgIQcZL75hlfrE0ShXRxNKIYpzANBgkqhkiG9w0BAQUFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowga4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UE BxMOU2FsdCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29y azEhMB8GA1UECxMYaHR0cDovL3d3dy51c2VydHJ1c3QuY29tMTYwNAYDVQQDEy1V VE4tVVNFUkZpcnN0LUNsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgRW1haWwwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyOYWk8n2rQTtiRjeuzcFgdbw5 ZflKGkeiucxIzGqY1U01GbmkQuXOSeKKLx580jEHx060g2SdLinVomTEhb2FUTV5 pE5okHsceqSSqBfymBXyk8zJpDKVuwxPML2YoAuL5W4bokb6eLyib6tZXqUvz8ra baov66yhs2qqty5nNYt54R5piOLmRs2gpeq+C852OnoOm+r82idbPXMfIuZIYcZM 82mxqC4bttQxICy8goqOpA6l14lD/BZarx1x1xFZ2rqHDa/68+HC8KTFZ4zW1lQ6 3gqkugN3s2XI/R7TdGKqGMpokx6hhX71R2XL+E1XKHTSNP8wtu72YjAUjCzrAgMB AAGjggEnMIIBIzAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAdBgNV HQ4EFgQUiYJnfcSdJnAAS7RQSHzePa4Ebn0wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBEGA1Ud IAQKMAgwBgYEVR0gADB7BgNVHR8EdDByMDigNqA0hjJodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA2oDSgMoYwaHR0cDov L2NybC5jb21vZG8ubmV0L0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMBEGCWCG SAGG+EIBAQQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAnZXLPLh+pQnEHr8Lwsd2 jjk8lMYQqk8MyeCrhF2JVOBlO/NtHHw3LCVUX5Yh/DeEkZ0V3BRPgc9UHWtsRWDH LfmXUUz5Zso8oIKMpsjw4unUSvnsP1bJ3XaMw4IBT2wA8x4aYXQERwOpxkBXkbxl IsUnZ09X22Ra2Y0fuoYv9AaunGnt6fTPKRfY4EqfGiAvl0xRu0YHxIo3TiDjCTFo x57Ei53ofhG8MmgQlhGYRNgqUWBNiOt0Ot9DBjLIOVaMOhFS00GkQwP07e8zJ9s5 4BROJsnY9TniibiTXbcpJkHqs5uug/x3dcroyrX+4mVKYz5ExNDDXodzqZgcr38V fw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwDCCBKigAwIBAgIBBTANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdDAeFw0wNDAyMDkxNTQyNDdaFw0zNDAyMDkxNTQyNDda MIHgMQswCQYDVQQGEwJFUzEuMCwGCSqGSIb3DQEJARYfYWNfY2FtZXJmaXJtYV9j Y0BjYW1lcmZpcm1hLmNvbTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBh ZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ QTgyNzQzMjg3MRkwFwYDVQQKExBBQyBDYW1lcmZpcm1hIFNBMS0wKwYDVQQDEyRB QyBDYW1lcmZpcm1hIENlcnRpZmljYWRvcyBDYW1lcmFsZXMwggEgMA0GCSqGSIb3 DQEBAQUAA4IBDQAwggEIAoIBAQCjxnvvj01f36lgGhihRYVf1fAPEXsTJKrY4aLQ cEUSh5szZE7VTtGiyMTMc2uCmnaXafjYHK8Lgmy6T9xxGEZ5OS4x6rgtuPyy13AP tu3X3Y2kPVLu7ZMw5HoQC64wBj6YcnxTnBwmVW05DjzRXp6OyBIEKEaAB9vv2qEl fh/Y234FG6Wd/ut1s0ScRZAo+6CSMNQxaY+ryXKD11uWkzWXJa9UZOasG7z4uPqc Gr4/Hz2/CTLDTgp0xkMJYuzOztpUvOACrxlkS2utKUwVlAikJnboNwf/en94RbHN zkKc5t0SAbzCf57ueawbzxSdPa+SAC25FNur64FKkfdq5PPjAgEDo4IB5TCCAeEw EgYDVR0TAQH/BAgwBgEB/wIBCzA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3Js LmNoYW1iZXJzaWduLm9yZy9jaGFtYmVyc3Jvb3QuY3JsMB0GA1UdDgQWBBS2H06d HGiRLjdyYOFGj1qlKjExuTCBqwYDVR0jBIGjMIGggBTjlPWxTenboSlbV4tNdgZ2 4dGiiqGBhKSBgTB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJz aWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdIIBADAO BgNVHQ8BAf8EBAMCAYYwKgYDVR0RBCMwIYEfYWNfY2FtZXJmaXJtYV9jY0BjYW1l cmZpcm1hLmNvbTAnBgNVHRIEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24u b3JnMFsGA1UdIARUMFIwUAYLKwYBBAGBhy4KCQEwQTA/BggrBgEFBQcCARYzaHR0 cDovL2Nwcy5jYW1lcmZpcm1hLmNvbS9jcHMvYWNfY2FtZXJmaXJtYV9jYy5odG1s MA0GCSqGSIb3DQEBBQUAA4IBAQBl8KoPBYL//EBonqQWS0N+hLfxImP1eQ6nac+v R5QfF/0w+VCTkShfKwHaa6V/W1dPlVwXSECuvXHkX6DYrtxFGGFB6qxuP1rkIpRs sTkAlpvOx3REiFjIkhsijKd/ijvqxjbMbuYU+EFACK/jQIRoj+LEEZ+haiqbALZB Iqq/26HTqX0itDosBj6M94YWcIpbTDefQNWCGsSnZcw2+k+az/wAOZT6xAxlnEim HpDDlgRsmaLrHpDPDoIRYOih0gbJTnn4mKex9Wgr0sZ+XFl03j+bvcXL1tiuQnwb 9dMRDe/OdXABT35W4ZzLbpost65ZW3Tx+oi/bLbmu6pbKCgs -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFIjCCBAqgAwIBAgIBCDANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdDAeFw0wNDA0MjAxNzA1NThaFw0zNDA0MjExNzA1NTha MG0xCzAJBgNVBAYTAkVTMRkwFwYDVQQKExBBQyBDYW1lcmZpcm1hIFNBMS8wLQYD VQQDEyZDQSBDYW1lcmZpcm1hIEV4cHJlc3MgQ29ycG9yYXRlIFNlcnZlcjESMBAG A1UEBRMJQTgyNzQzMjg3MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA uSy+2i/afKJtZnuCh2h01FkAoBwv+IWKxxHRW/F4rrBTxKrz5IkleQejc11S8VM+ 64maXYgzaRsodkkOQb7RSHEZV0a1SFdiyx/D0Qq4FCXUTqHdVD80f7CQ2psb/hIQ tN59mAVSankqsZS/hHVJwWHvcPQ0HDqE+JyB6P7Udx/8rN1PYjC7tVACkdAom0eI isnHg+wrlN0NuBvNig3oXmXonaiQpkTukqCmqlyZxZDNyQSWeZNz0Ln56tTQnHuG JU0YrAI26jqOojxEMaG9aPC7jLX+lpt/xhSsahnTKvgm9hXXjYintVCR1oIepoG3 MFp4yYcwJJYIe/Jzf2Y+wwIDAQABo4IBuTCCAbUwEgYDVR0TAQH/BAgwBgEB/wIB CzA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j aGFtYmVyc3Jvb3QuY3JsMB0GA1UdDgQWBBQNfChpUp8Yr8dNnC5McgVSVtG3pTCB qwYDVR0jBIGjMIGggBTjlPWxTenboSlbV4tNdgZ24dGiiqGBhKSBgTB/MQswCQYD VQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3 MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZ Q2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdIIBADAOBgNVHQ8BAf8EBAMCAYYwCQYD VR0RBAIwADAnBgNVHRIEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3Jn MFAGA1UdIARJMEcwRQYLKwYBBAGBhy4KCwEwNjA0BggrBgEFBQcCARYoaHR0cDov L2Nwcy5jYW1lcmZpcm1hLmNvbS9jcHMvY21mY3MuaHRtbDANBgkqhkiG9w0BAQUF AAOCAQEAVxyJ7YUCTD2zn33oOymb8RqQPgssAlXNd5/82uzjSlEL7y1nstVSdxMB 8+J0xBR1lISn0sfFA9ZHedz3GPD3FOzmzX2ZQ31iTS6B/b7AWdh1GhY094MR3n8S AWTKNvrAYawXyF/HqcNdIbEqa6dRxqR3fcBNiyfb01zUdpidezHShNl8KbaokEW3 HgRlpCBHhiu3uAXflarw7UT9OjUj04fgYSrtOy4xJoZhUCNTVOpCdVTc7YmVuLFi Rh5STyaMLRHkjabYM//udQicSgMrEvj+WBX2GmSmlbk5abVoYUtjDUB7gQ38UMJn cARUSjsyS35DKvZot0YRNcVaGXz+bg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c 6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn 8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a 77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFBzCCA++gAwIBAgICAgEwDQYJKoZIhvcNAQEFBQAwaDELMAkGA1UEBhMCVVMx JTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsT KVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2 MTExNjAxMTU0MFoXDTI2MTExNjAxMTU0MFowgdwxCzAJBgNVBAYTAlVTMRAwDgYD VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTkwNwYDVQQLEzBodHRwOi8vY2VydGlm aWNhdGVzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkxMTAvBgNVBAMTKFN0 YXJmaWVsZCBTZWN1cmUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxETAPBgNVBAUT CDEwNjg4NDM1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4qddo+1m 72ovKzYf3Y3TBQKgyg9eGa44cs8W2lRKy0gK9KFzEWWFQ8lbFwyaK74PmFF6YCkN bN7i6OUVTVb/kNGnpgQ/YAdKym+lEOez+FyxvCsq3AF59R019Xoog/KTc4KJrGBt y8JIwh3UBkQXPKwBR6s+cIQJC7ggCEAgh6FjGso+g9I3s5iNMj83v6G3W1/eXDOS zz4HzrlIS+LwVVAv+HBCidGTlopj2WYN5lhuuW2QvcrchGbyOY5bplhVc8tibBvX IBY7LFn1y8hWMkpQJ7pV06gBy3KpdIsMrTrlFbYq32X43or174Q7+edUZQuAvUdF pfBE2FM7voDxLwIDAQABo4IBRDCCAUAwHQYDVR0OBBYEFElLUifRG7zyoSFqYntR QnqK19VWMB8GA1UdIwQYMBaAFL9ft9HO3R+G9FtVrNzXEMIOqYjnMBIGA1UdEwEB /wQIMAYBAf8CAQAwOQYIKwYBBQUHAQEELTArMCkGCCsGAQUFBzABhh1odHRwOi8v b2NzcC5zdGFyZmllbGR0ZWNoLmNvbTBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8v Y2VydGlmaWNhdGVzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkvc2Zyb290 LmNybDBRBgNVHSAESjBIMEYGBFUdIAAwPjA8BggrBgEFBQcCARYwaHR0cDovL2Nl cnRpZmljYXRlcy5zdGFyZmllbGR0ZWNoLmNvbS9yZXBvc2l0b3J5MA4GA1UdDwEB /wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAhlK6sx+mXmuQpmQq/EWyrp8+s2Kv 2x9nxL3KoS/HnA0hV9D4NiHOOiU+eHaz2d283vtshF8Mow0S6xE7cV+AHvEfbQ5f wezUpfdlux9MlQETsmqcC+sfnbHn7RkNvIV88xe9WWOupxoFzUfjLZZiUTIKCGhL Indf90XcYd70yysiKUQl0p8Ld3qhJnxK1w/C0Ty6DqeVmlsFChD5VV/Bl4t0zF4o aRN+0AqNnQ9gVHrEjBs1D3R6cLKCzx214orbKsayUWm/EheSYBeqPVsJ+IdlHaek KOUiAgOCRJo0Y577KM/ozS4OUiDtSss4fJ2ubnnXlSyokfOGASGRS7VApA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ 6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o 0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV U+4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIETDCCAzSgAwIBAgILBAAAAAABL07hSVIwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0wNjEyMTUwODAw MDBaFw0yODAxMjgxMjAwMDBaMEwxIDAeBgNVBAsTF0dsb2JhbFNpZ24gUm9vdCBD QSAtIFIyMRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAps8kDr4ubyiZRULEqz4h VJsL03+EcPoSs8u/h1/Gf4bTsjBc1v2t8Xvc5fhglgmSEPXQU977e35ziKxSiHtK pspJpl6op4xaEbx6guu+jOmzrJYlB5dKmSoHL7Qed7+KD7UCfBuWuMW5Oiy81hK5 61l94tAGhl9eSWq1OV6INOy8eAwImIRsqM1LtKB9DHlN8LgtyyHK1WxbfeGgKYSh +dOUScskYpEgvN0L1dnM+eonCitzkcadG6zIy+jgoPQvkItN+7A2G/YZeoXgbfJh E4hcn+CTClGXilrOr6vV96oJqmC93Nlf33KpYBNeAAHJSvo/pOoHAyECjoLKA8Kb jwIDAQABo4IBIjCCAR4wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w HQYDVR0OBBYEFJviB1dnHB7AagbeWbSaLd/cGYYuMEcGA1UdIARAMD4wPAYEVR0g ADA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBv c2l0b3J5LzAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmdsb2JhbHNpZ24u bmV0L3Jvb3QuY3JsMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEFBQcwAYYhaHR0cDov L29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIxMB8GA1UdIwQYMBaAFGB7ZhpFDZfK iVAvfQTNNKj//P1LMA0GCSqGSIb3DQEBBQUAA4IBAQCZIivuijLTDAd+3RsgK1Bq lpEG2r5u13KWrVM/fvWPQufQ62SlZfLz4z0/WzEMfHmEOpeMDx+uwbzy67ig70H9 vDGp/MlC5kS+HlbKdYuySTGZ/urpcWSGeo/l1WERQ+hAuzEM4tsYi5l0OGGrJICM +ag710nWZooYc8y8BjmLEDIODdOx9+9mExBZSMjPAcqZzJBymNs67cunu+JscI6m nmhj7Y+3LQWJztlU9k6rHkbbMEk/9mrgAfC8zYTUOfdVjgMVcdOdNO2dxtHIqsWE OTsN/SknUh6Dq0gjhVhQs5XGC7Mm4xYtqDDcA1BtXNEMzSqhR5rPIBvbQ4gfwvzg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIRAMlT/u64lekYhKuyKmikKn0wDQYJKoZIhvcNAQEFBQAw XjELMAkGA1UEBhMCVFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBM dGQuMSowKAYDVQQLDCFlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw HhcNMDcwNTE2MTAxMzU1WhcNMjcwNTE2MTAxMzU1WjBbMQswCQYDVQQGEwJUVzEj MCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xJzAlBgNVBAsMHlB1 YmxpYyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAJbEUbRogBe+Unld424LbzivM4pQdCnV/uNe7S2287+9fqCx njtKfxni/HzwTiShxGlaWcz9oXnnBVgizU1IkGn3U1vbJMaMgOX1CbCYNdj0atYf KuxRmtQfPAP6BmUVF74w5znjDJhzWO0wm15xsx+fhb89HzqUDV9gC9aK1LKgoAFh Ii8nbGxrKEhZchZlzIHNMxQGgdcAJLUCI5EToKh3/xHWv/KCRJVXOD11AtLmwMdB HxGNhIeOUpax0sHRmescUi76tqGp3PDsKz53C2ysLsBf4FykiQSrfKEqyLg+Rxk6 6ultf41cQLAm4+WwXIvxwqtGEGuoEWNWXdylREsCAwEAAaOCASMwggEfMB8GA1Ud IwQYMBaAFB4M97Zn8uGSJglFwFU5Lnc/QkqiMB0GA1UdDgQWBBRxs1AxoBtbe7Km WXz9EIw8rTo9ejAOBgNVHQ8BAf8EBAMCAQYwKgYDVR0gBCMwITAJBgdghnYBZAAB MAkGB2CGdgFkAAIwCQYHYIZ2AWQAAzASBgNVHRMBAf8ECDAGAQH/AgEAMDkGA1Ud HwQyMDAwLqAsoCqGKGh0dHA6Ly9lcGtpLmNvbS50dy9yZXBvc2l0b3J5L0NSTC9D QS5jcmwwUgYIKwYBBQUHAQEERjBEMEIGCCsGAQUFBzAChjZodHRwOi8vZXBraS5j b20udHcvcmVwb3NpdG9yeS9DZXJ0cy9Jc3N1ZWRUb1RoaXNDQS5wN2IwDQYJKoZI hvcNAQEFBQADggIBACCs4ZeBiuv4TX4BOZJnyq6AH6Aq3yAojLj/NbU1O0wMI5y+ qufAxXSCSAnwrdBwAADzYTt5NTBORkkm7q7P1eQlmvT6iqQaIDkpdJsZFjgHQS6a 8xBzT3d5+Sm3jEIQoDFgQ1/E6vBepBLXmrkdSd7NZ8QbEY19ggHNniOreycShkMb UqX5uG1jyvOHuHzsa1BcLQWh2l1myoxTz2X+jJ5f04fmpveVZgb+CxUyMvCQE4Ac wMFU59fxZ8Wkggp6H9bkVrRzXJdS0Su2xK7z5AEW5sf6BbNj8WnfmOejP1nakQdJ B+tEPDlmHtisV8yu0dopN9Z2tbx9aDxMlO1MrKF21bzN2nzl+NTaJ/8wEqVSbtNs UIVV9+eLgbOcrqcfnZgD5aWQVEpvaiBAZqzZGLA/luc+0w2QbqpiZlGAF4Qi4/a0 QbGFsNLCXaZW0ioH/kFmTuL2NSVg2zz2xqhFv+k6GNI4amZqz/eEEk1yBQkX1apc oz+MRgh8khNYZAVIllEhI78o1nKZYDAFY8lQ28b57GmsMi90M9buIfvQnBf0ly/B wGXo/Xpw1mP1oNJCbC/AlfI+Gkfnch/k+SQ5z9Jmwf3ELoY0fE2BxzD49hHDQ+Ah Eeyg+X04q/lrynYbxNJoBBQugIiv0GDzzzuNh4FAMWfEAeKf/xck3ABAgNLb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5jCCA86gAwIBAgIRAJc8yU1Ez+mi4U9S6aWUoVowDQYJKoZIhvcNAQEFBQAw XjELMAkGA1UEBhMCVFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBM dGQuMSowKAYDVQQLDCFlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw HhcNMDcwNTE2MTAxMzU1WhcNMjcwNTE2MTAxMzU1WjBbMQswCQYDVQQGEwJUVzEj MCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xJzAlBgNVBAsMHlB1 YmxpYyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAJbEUbRogBe+Unld424LbzivM4pQdCnV/uNe7S2287+9fqCx njtKfxni/HzwTiShxGlaWcz9oXnnBVgizU1IkGn3U1vbJMaMgOX1CbCYNdj0atYf KuxRmtQfPAP6BmUVF74w5znjDJhzWO0wm15xsx+fhb89HzqUDV9gC9aK1LKgoAFh Ii8nbGxrKEhZchZlzIHNMxQGgdcAJLUCI5EToKh3/xHWv/KCRJVXOD11AtLmwMdB HxGNhIeOUpax0sHRmescUi76tqGp3PDsKz53C2ysLsBf4FykiQSrfKEqyLg+Rxk6 6ultf41cQLAm4+WwXIvxwqtGEGuoEWNWXdylREsCAwEAAaOCAaAwggGcMB8GA1Ud IwQYMBaAFB4M97Zn8uGSJglFwFU5Lnc/QkqiMB0GA1UdDgQWBBRxs1AxoBtbe7Km WXz9EIw8rTo9ejAOBgNVHQ8BAf8EBAMCAQYwOwYDVR0fBDQwMjAwoC6gLIYqaHR0 cDovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeS9DUkwvQ0EuY3JsMIGLBggrBgEF BQcBAQR/MH0wRAYIKwYBBQUHMAKGOGh0dHA6Ly9lY2EuaGluZXQubmV0L3JlcG9z aXRvcnkvQ2VydHMvSXNzdWVkVG9UaGlzQ0EucDdiMDUGCCsGAQUFBzABhilodHRw Oi8vb2NzcC5lY2EuaGluZXQubmV0L09DU1Avb2NzcEcxc2hhMTASBgNVHRMBAf8E CDAGAQH/AgEAMGsGA1UdIARkMGIwDQYLKwYBBAGBtyNkAAEwDQYLKwYBBAGBtyNk AAIwDQYLKwYBBAGBtyNkAAMwCQYHYIZ2AWQAATAJBgdghnYBZAACMAkGB2CGdgFk AAMwCAYGZ4EMAQIBMAgGBmeBDAECAjANBgkqhkiG9w0BAQUFAAOCAgEAoV0YeNQX hgLU24kqlKbLL1e7+mHtwqJYIh2linRcDHvorEvqRttalL/cNRmjMUhFHLTTa+tO 8hh4NRMT4fYOrVdGN0yeKeABNRWORzF5JH+ToxyQYRYvjPNt0JqKCDC4aGWcPjRG msEwlBpFDJgqQouyYSHuneqIw8UzrJD5+UIfCjcdQqbwNVeQ/obRYPftcS+agCuD vI082dfjqM4RAZBW2W34861Bu3VAGL3BFIblMAirIfwXjtR93L8RkYRZla8gIvSN /0pWRhbO5Jmhpww8Q/aqXcm6c/sf3SldjlFAorIp5HHVLmfFsvbsEYcg4SLRl2SC HmI6MX33CBAJKSXR3vGkEp65mDZlf80yLUGST82ClTuwQc9DuBCmb++mTBSQ0N/a SEmXCA3vy/KckgjOO8fFKyV4uHJVWdPiPmpjxzWFmHXBul6KfT5yuSD/xNBVdGQF eJ1+3kEl2oKa3thfFIsSoarfeQiTn3gDl4x+i/chw/iKq0kAs4PeMpn3qYQ03K7e SrsDXWyK586O396tnW2DRJjMNTGcMl/cSN7n6D2ONCriKM4dG7hrfV9kw0CsSqec am2dqEbzre40c64wG2lngTJ2LjpuG4IqpW418IM5Gc4lZnwZHZGhjSBZNIrFeOs1 OzuP1OHS+DCN3s8HfhNNENyew6mywFicjVk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFljCCBH6gAwIBAgIBDTANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdDAeFw0wNzExMTUxMzM5NTlaFw0zMjExMDgxMzM5NTla MIHZMQswCQYDVQQGEwJFUzElMCMGCSqGSIb3DQEJARYWY21mZWNzMkBjYW1lcmZp cm1hLmNvbTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRkwFwYDVQQKExBBQyBDYW1lcmZpcm1hIFNBMS8wLQYDVQQDEyZBQyBDYW1lcmZp cm1hIEV4cHJlc3MgQ29ycG9yYXRlIFNlcnZlcjCCASAwDQYJKoZIhvcNAQEBBQAD ggENADCCAQgCggEBAIg1c+SE9a2pYYPrVGr9c+aEjvoUncE2WhlZhuKzfxwF5YSV 1UfGmPupAgy1yILQcTUd2M2bqCzInVZ0aLJQ5MmmG0dfzq4EFh/apTyTMcNrfoN9 ocafuEwCYxLAyhh9JHqRyOzkjWLpyI2Xw1w5vTWESGVNDVcAm5eEMIGSnWsLqjOJ aXd4QwXvy4CQi//jFRIZD2nP6xyJlLHdYxpbfETAqyea4loU+E0oy5PxJQlB9xE7 BqmmpviV2SHFTPd/VnX9/AAJPOM0bEvVCauDojwLCqp+8N+rEEaAnO8U2c4N3lZV uRXkc9ykg7hSkABhcMDOyMdfS8aeGNdNG7lMzFECAQOjggHCMIIBvjASBgNVHRMB Af8ECDAGAQH/AgELMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuY2hhbWJl cnNpZ24ub3JnL2NoYW1iZXJzcm9vdC5jcmwwHQYDVR0OBBYEFApKwMqYEu+XWd33 pK+wFKQ5rq5KMIGrBgNVHSMEgaMwgaCAFOOU9bFN6duhKVtXi012Bnbh0aKKoYGE pIGBMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJ RiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290ggEAMA4GA1UdDwEB /wQEAwIBhjAhBgNVHREEGjAYgRZjbWZlY3MyQGNhbWVyZmlybWEuY29tMCcGA1Ud EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwQQYDVR0gBDowODA2 BgsrBgEEAYGHLgoLATAnMCUGCCsGAQUFBwIBFhlodHRwOi8vY3BzLmNhbWVyZmly bWEuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQAWYPvxz3Jbda4wVMSSHFCln6cWFOjY /FpDnZGOxP8u6fMAmZwx77WyPdioz6gLZfuzZMqiY9uTceJ7P8bmR+H23d4NbHWS A3bJo0b++cDKYnVFdQc0fpeyry0z+cQKMl1DVlIptM4jqZ7t42+ghlHr/nMh+3pK dY7AHFhh/PElvckxgiNTvufvi7fi/J9QFAq+ZZEVJUTCSp9m6GXEk6pjVRknxxEK ZxjS0WjzyFUz+vqf93gbwsDBbTD/s4wrTA6y29Qiy4N2ny6c59RTbEm3RC2ldxC1 uZExb8cAa3mcc0H4UqrYCGsZQxjXvh5CQvYU6t1qsq18Cdt3zo+cYRr4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFUzCCBLygAwIBAgIOVY8AAQAC0YZ/+kYzFBIwDQYJKoZIhvcNAQEFBQAwgbwx CzAJBgNVBAYTAkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJn MTowOAYDVQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBO ZXR3b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAxIENB MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw0w ODA3MTgxMTM5MTBaFw0yNTEyMzEyMjU5NTlaMH0xCzAJBgNVBAYTAkRFMRwwGgYD VQQKExNUQyBUcnVzdENlbnRlciBHbWJIMSUwIwYDVQQLExxUQyBUcnVzdENlbnRl ciBDbGFzcyAxIEwxIENBMSkwJwYDVQQDEyBUQyBUcnVzdENlbnRlciBDbGFzcyAx IEwxIENBIFZJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOH60nyM y5hvrMv59h6UP1Bc5tHr4yBZSkMRCePPOYD7GH2Gk3EBB/H+pvLsdiR/k3gnRoud voegoe0S7yJnYPLXPY94UezsDCIz3O8teeCd3zpjBz6Cxg0Hd976fpn48Kn4Uuli 04klnljH0lDQAYt8+DTBYMkKIxbkt3qFYXkETerQBw9ODQG7AOsDgMe858Ami0eQ p8ane3CX3H79VE+3+HQ9b8IY96AOzMa1w2SAFyMesJxKZRTxkuZkVwtCV6F2zBbG cGYSE5mvkkaOfv/Aj+2EGAPgzY9Mb+sX+PsSROTawN1NnoBfjQ68TShsy37Na479 ovk38f2m34duCbUCAwEAAaOCAhAwggIMMIGOBggrBgEFBQcBAQSBgTB/MEwGCCsG AQUFBzAChkBodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NlcnRzZXJ2aWNlcy9j YWNlcnRzL3RjX2NsYXNzXzFfY2EuY3J0MC8GCCsGAQUFBzABhiNodHRwOi8vb2Nz cC50Y2NsYXNzMS50cnVzdGNlbnRlci5kZTAPBgNVHRMBAf8EBTADAQH/MEoGA1Ud IARDMEEwPwYJKoIUACwBAQEBMDIwMAYIKwYBBQUHAgEWJGh0dHA6Ly93d3cudHJ1 c3RjZW50ZXIuZGUvZ3VpZGVsaW5lczAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYE FPT5PV5TEXucaWUoPoxvLwB4fuVzMIHsBgNVHR8EgeQwgeEwgd6ggduggdiGO2h0 dHA6Ly9jcmwudGNjbGFzczEudHJ1c3RjZW50ZXIuZGUvY3JsL3YyL3RjX2NsYXNz XzFfY2EuY3JshoGYbGRhcDovL3d3dy50cnVzdGNlbnRlci5kZS9DTj1UQyUyMFRy dXN0Q2VudGVyJTIwQ2xhc3MlMjAxJTIwQ0EsTz1UQyUyMFRydXN0Q2VudGVyJTIw QUcsb3U9cm9vdGNlcnRzLGRjPXRydXN0Y2VudGVyLGRjPWRlP2NlcnRpZmljYXRl UmV2b2NhdGlvbkxpc3Q/YmFzZT8wDQYJKoZIhvcNAQEFBQADgYEAL0wY3X6WsrVR kq7Zrwo7ZxaUaoE/Fjq0jPgZ40GTyLQCTAHqn9ILo8ffTBUhsT/X/gAEqWbK7cQR 3RuPaB+WpPwTbGMnvUIZsqjEjAZiDr2RJ6OPh/c8FFqhziqpwuw5YX4exOipthvt 2qMs8v5a+7TLHr8dHfFoqzsoo6GNUK8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFVDCCBL2gAwIBAgIPAJ6cAAEAAnBcqhh0eZ9GMA0GCSqGSIb3DQEBBQUAMIG8 MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVy ZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEg TmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBD QTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwHhcN MDgwNzE4MTEzOTIxWhcNMjUxMjMxMjI1OTU5WjB9MQswCQYDVQQGEwJERTEcMBoG A1UEChMTVEMgVHJ1c3RDZW50ZXIgR21iSDElMCMGA1UECxMcVEMgVHJ1c3RDZW50 ZXIgQ2xhc3MgMyBMMSBDQTEpMCcGA1UEAxMgVEMgVHJ1c3RDZW50ZXIgQ2xhc3Mg MyBMMSBDQSBWSUkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCniOoD E3aAZQb8Y36Mrx7tyVND6sqIBE/HfajxNRAeavfs5v8Uo/zORyiNP98r83MpWRoX tqOga5gDNJgVACMY23rNRfursynyYiJeqpG3BfSZsxG4U9He6jhmt2LAFDflRCsA I4Aw9i15YnbNchVTZZrJbCmcByaT1ak58sfa6aHXKTD8uVig6OD7OgEzgJzJtBLu pujEvu2CF2b9I056gmW6/bbDNbE1sUOETZRWTgpqxNJms634pTrzf2OB738Uoq3x 3hbdw1SYmwAz7RAKgF1LF67eNlVTm0081215h+OZMzzHV8da2xPS0CL4aq3XQdJd 0+QWK0HIWZ0BKN/xAgMBAAGjggIQMIICDDCBjgYIKwYBBQUHAQEEgYEwfzBMBggr BgEFBQcwAoZAaHR0cDovL3d3dy50cnVzdGNlbnRlci5kZS9jZXJ0c2VydmljZXMv Y2FjZXJ0cy90Y19jbGFzc18zX2NhLmNydDAvBggrBgEFBQcwAYYjaHR0cDovL29j c3AudGNjbGFzczMudHJ1c3RjZW50ZXIuZGUwDwYDVR0TAQH/BAUwAwEB/zBKBgNV HSAEQzBBMD8GCSqCFAAsAQEBAzAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LnRy dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW BBRYV+L8mjsU+LDvpiKUnt5dpLKHpDCB7AYDVR0fBIHkMIHhMIHeoIHboIHYhjto dHRwOi8vY3JsLnRjY2xhc3MzLnRydXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFz c18zX2NhLmNybIaBmGxkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBLE89VEMlMjBUcnVzdENlbnRlciUy MEFHLG91PXJvb3RjZXJ0cyxkYz10cnVzdGNlbnRlcixkYz1kZT9jZXJ0aWZpY2F0 ZVJldm9jYXRpb25MaXN0P2Jhc2U/MA0GCSqGSIb3DQEBBQUAA4GBAFjS4HobIci9 KaCsQdUj27PsV0cLZp1rMPLcvtjgFbEBSXGyAvmGzOwkEQZzLGzXEy5py5QyxK0S C9DHCztJMcEfmyjH3lZ8D6nu5j6ivSnE6cafbsxiHGLnp3VSRlv9uHq42WO1wpvM JcDiQfGAIMPm2r0plCV66tGWfs/0W9zD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFJDCCAwygAwIBAgIRAI3Qi4g3szO2BSUC3JFKN/kwDQYJKoZIhvcNAQEFBQAw PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTAeFw0wODA4MTgwOTExNDZaFw0yODA4MTgwOTExNDZa MEQxCzAJBgNVBAYTAlRXMRIwEAYDVQQKDAnooYzmlL/pmaIxITAfBgNVBAsMGOmG q+S6i+aGkeitieeuoeeQhuS4reW/gzCCASEwDQYJKoZIhvcNAQEBBQADggEOADCC AQkCggEAF7b5RLnMt6TNb2clKItXwckr8g/cZbTEqcdcg3RHspYorO+Djtxac0k/ LUH5EcqqEtieCfQ5mqavNASzlLyslDinUXTkAnWgpKrcgy8GUhEmVWqrikkkR6jf XeoS3TB6QXrUtMunNL4HDtHOWoIYNzD16KH3asNsq0nZooVVDbyfVC8Kp35Y46JT RN+U45jrN6MzFrMzqpWZxhVLzgW/0p5jQLYM9Af00eDttePlTaASyyrWojRq/S3Q y05WMaGT1ocd4Nf/O0GiInJiVp/QKKlJMsg7KmiO+YvumsBi/GdwegJYJrZjsUPW 8Rwdubv3127/UUouTv50pOyUY/sEswIDAQABo4IBFTCCAREwHwYDVR0jBBgwFoAU zMzvzClgpDuxkrY8+jJij6wlFTswHQYDVR0OBBYEFLPIVnJoxoUiC6l5vB0QP3Zx sZTQMA4GA1UdDwEB/wQEAwIBBjAUBgNVHSAEDTALMAkGB2CGdmUAAwMwEgYDVR0T AQH/BAgwBgEB/wIBADA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vZ3JjYS5uYXQu Z292LnR3L3JlcG9zaXRvcnkvQ1JML0NBLmNybDBWBggrBgEFBQcBAQRKMEgwRgYI KwYBBQUHMAKGOmh0dHA6Ly9ncmNhLm5hdC5nb3YudHcvcmVwb3NpdG9yeS9DZXJ0 cy9Jc3N1ZWRUb1RoaXNDQS5wN2IwDQYJKoZIhvcNAQEFBQADggIBABNBrM/Ff9Sw LhNydJJY7tMIbTMY13pLX8f6x+806vSHAqpIPeXFSHEKB+HDRpO/CXG+KvetVgwd BF1jAdIbVJzKPvkNVuLfSBqvm7xSkvndE9mbJNod7YnSfkYjcAkqaqJmeDZuvL3A 2Ei2iX5pYeFbtXevH3tRDqkbI/v1VTIWIq8axpOQcWrJxceU6Bm3azT+wmGz5GP5 5e+gX/DyQMD/ZW1jPl3wHxtwABd7/xv4UVOE3SXVsQBdJMshXj4cLPLDtGlixO75 OtsNxENUtKTJzqfCTgGtxvbmimcExfztsNNkEhUwJmRq6RrChUcqEapKL/jLiSkS DRuT5GlsjhvdN48iIdCyHblgz1B/2ncgUICXHUDjv3gtD1+Fwp2PJnckbbXibRY2 P4XYiVos7GbNSpwFoW4HfrWn3jTzraIWcKCvGj/+MDlhE0Tm9hXSkxQoomepvokJ UqrIjEHStmeSmuD5jz7UqJLDEkgb8ylGz/Yfhmu27wlStfsjKOgDQwGhTohjIxij /xwhX43ueRtkF7FslnBIbebd4FcLDnX/me5mviJdP/MQUbs6pFPS3go0uTsCtlxP bCcXTf/H8ep+o9JlAnpD/ykkBhVPyLsXQ47mxW//aW68E3rEj6aYFT8fjnV0kymv HveM50aXDsoUnpM4xk7gep+J3mcoNw74 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtDCCA5ygAwIBAgIRAJOShUABZXFflH8oj+/JmygwDQYJKoZIhvcNAQELBQAw PjELMAkGA1UEBhMCUEwxGzAZBgNVBAoTElVuaXpldG8gU3AuIHogby5vLjESMBAG A1UEAxMJQ2VydHVtIENBMB4XDTA4MTAyMjEyMDczN1oXDTI3MDYxMDEwNDYzOVow fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAOP7faNyusLwyRSH9WsBTuFuQAe6bSddf/dbLbNax1Ff q6QypmGHtm4PhtIwApf412lXoRg5XWpkecYBWaw8MUo4fNIE0kso6CBfOweizE1z 2/OuT8dW1Vqnlon686to1COGWSfPCSe8rG5ygxwwct/gounS4XR1Gb0qnnsVVAQb 10M5rVUoxeIau/TA5K44STPMdoWfOUXSpJ7yEoxR+HzkLX/1rF/rFp+xLdG6zJFC d0wlyZA4b9vwzPuOHpdZPtVgTuYFKO1JeRNLukjbL/ly0znK/h/YNHL1tEDPMQHD 7N4RLRddH7hQ0V4Zp2neBzMoylCV+adUy1SGUEWp+UkCAwEAAaOCAWswggFnMA8G A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAh2zcsH/yT2xc3tu5C84oQ3RnX3MFIG A1UdIwRLMEmhQqRAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNw LiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQYIDAQAgMA4GA1UdDwEB/wQEAwIB BjAsBgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vY3JsLmNlcnR1bS5wbC9jYS5jcmww aAYIKwYBBQUHAQEEXDBaMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1j ZXJ0dW0uY29tMC4GCCsGAQUFBzAChiJodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0u cGwvY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAI3m/UBmo0yc p6uh2oTdHDAH5tvHLeyDoVbkHTwmoaUJK+h9Yr6ydZTdCPJ/KEHkgGcCToqPwzXQ 1aknKOrS9KsGhkOujOP5iH3g271CgYACEnWy6BdxqyGVMUZCDYgQOdNv7C9C6kBT Yr/rynieq6LVLgXqM6vp1peUQl4E7Sztapx6lX0FKgV/CF1mrWHUdqx1lpdzY70a QVkppV4ig8OLWfqaova9ML9yHRyZhpzyhTwd9yaWLy75ArG1qVDoOPqbCl60BMDO TjksygtbYvBNWFA0meaaLNKQ1wmB1sCqXs7+0vehukvZ1oaOGR+mBkdCcuBWCgAc eLmNzJkEN0k= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuDCCA6CgAwIBAgIQI+gpDXGVBBjACFl+QvdIGzANBgkqhkiG9w0BAQUFADA+ MQswCQYDVQQGEwJQTDEbMBkGA1UEChMSVW5pemV0byBTcC4geiBvLm8uMRIwEAYD VQQDEwlDZXJ0dW0gQ0EwIhgPMjAwODEwMjIxMjA3MzdaGA8yMDI1MTIzMDIzNTk1 OVowfjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVz IFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEi MCAGA1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAOP7faNyusLwyRSH9WsBTuFuQAe6bSddf/dbLbNa x1Ffq6QypmGHtm4PhtIwApf412lXoRg5XWpkecYBWaw8MUo4fNIE0kso6CBfOwei zE1z2/OuT8dW1Vqnlon686to1COGWSfPCSe8rG5ygxwwct/gounS4XR1Gb0qnnsV VAQb10M5rVUoxeIau/TA5K44STPMdoWfOUXSpJ7yEoxR+HzkLX/1rF/rFp+xLdG6 zJFCd0wlyZA4b9vwzPuOHpdZPtVgTuYFKO1JeRNLukjbL/ly0znK/h/YNHL1tEDP MQHD7N4RLRddH7hQ0V4Zp2neBzMoylCV+adUy1SGUEWp+UkCAwEAAaOCAWwwggFo MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAh2zcsH/yT2xc3tu5C84oQ3RnX3 MFIGA1UdIwRLMEmhQqRAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRv IFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQYIDAQAgMA4GA1UdDwEB/wQE AwIBBjAsBgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vY3JsLmNlcnR1bS5wbC9jYS5j cmwwaAYIKwYBBQUHAQEEXDBaMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2Nz cC1jZXJ0dW0uY29tMC4GCCsGAQUFBzAChiJodHRwOi8vcmVwb3NpdG9yeS5jZXJ0 dW0ucGwvY2EuY2VyMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsGAQUFBwIBFhlo dHRwczovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBBQUAA4IBAQBRIGBe Zq1Fsbn2DNEa8X4lqAp6dMtsZdHXlGLBWyKMHtnO8xjJyWxhVe5O2cbo8h67s5b2 XG2q9ikXlPzuyoAlN/jA35DS+Qo9wPbw07O2vvtdgAG19POKOS2AKTtWPfu8UPSV scnBz7GHvBOCkCxGFb3v/AMZnjgExPgtCoIwMlcFFAHCRzUcTT+z9l2zc9aBp2gG 35rI1cW3RlIk7orNZl6awHIV1gFalXHZ+3olO6IRpWClXFTYdnTKxBL8Wq5WLr+l 6Z+V4cIL/T0+BY019U8zYayYZDXb85FQlULTvPcOO3YTaUdwHiCHCiiRKl7pqqky xLYz+f1feWUhrGop -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgzCCA2ugAwIBAgIPDhzYzUUyWkcAUQyqwtseMA0GCSqGSIb3DQEBDQUAMDsx CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z 374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQ0FAAOCAgEAA6kGfD2AupaI v2NYWHer7JvK92qJbn9UhdwED4wvjJ4AfBiGXys7JAP4dfjxUjCHo+siH5mNPrvq gZBF/fxLngMO8D2wQKS2M4N4IzaML4u8nR0fA97caXfR4kD+NzQr5KgKfGR4AJiQ fHPgDPttGmpyPST21rdoJHo4rx78uFVkAoAnPuCfU9IWDoCMp7i0gNtD90C1dRsj nHgiv3U1Lsga9lAaYuDRefPgdppm1oVyrNyjyxQtDNnERdpV4xTYuzW21gSPrGrH 1hEvd9dKQN1ZAqnaZ+GwIeV+l3+J0vPv5mED0VwMUAHwg4euAS7dMO9GhciRvN0z C9wjX1//IerBy4TqALVSfv17PHk5d+WtuImsyZvX0ZjhC9VGk/pGQDn+XVkizcpe /ZAbzpBQj7jY+D7N7rpwxmOswwXSz8g9v0agQ+hvBRqF/zuMkMJB8Z9kB/pSuMQG BEOl7zbbA+PtutS8+Zb+A4uDNmKx2AJqflBwySzpskpK6lvX503hJbcct6BQfBLE zHMKWPxBag4AKlqB4N+hIV7/UuCfm6WssH/JWFsfvSJg30r5mGVJ1LeQ1TquDrMA hJoeio0BGz+Ph/knnebw5ojiXF9ZaVu659DKpUGzwZbkbTskdZMJM01YNFwzqk+m gC3AQfs2sTc9RSk4TP2sxl83jmWuBt0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEajCCA1KgAwIBAgIER4af5TANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQGEwJV UzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNl Y3VyZVRydXN0IENBMB4XDTA4MTIyMjIzNDczOVoXDTI4MTIyMjIzNDczOVowga4x CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJbGxpbm9pczEQMA4GA1UEBxMHQ2hpY2Fn bzEhMB8GA1UEChMYVHJ1c3R3YXZlIEhvbGRpbmdzLCBJbmMuMTYwNAYDVQQDEy1U cnVzdHdhdmUgT3JnYW5pemF0aW9uIFZhbGlkYXRpb24gQ0EsIExldmVsIDIxHzAd BgkqhkiG9w0BCQEWEGNhQHRydXN0d2F2ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDoFO6g2pe9ib0MzI3fCPsGCYOoI1FbAT802h8fbsHjWGXL Cvnzh8jI+qHM9XTiuK4tBoSAKG9awSJckpRCzRkCElwQYn6iRPsWXpxysazqBOYV qpnoWvhYuYck6HXNJYjiWJJehoN/iiNTrorooyF+g69ACRhJr+HQWrBPb+IxrfTx Nx/JKuGL1owSMdQnGt/qa554U+2aGbDORURbG+9kWSH6x7fR0wwey4ja/SM/9Kwr oE1h077K3hlhYSTx9py0lr2d6xefJDl46SNQ0wFQd9hSZC8+GU91uRex2o3g0O3b NxPcL+BfgGjX9Ie6wR8SeNAIJxd6mKaf0iG6Toe/AgMBAAGjgfQwgfEwDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQUXdmWmkDHJ8ssm6LszxmryK/MhkgwHwYDVR0j BBgwFoAUQjK2FvoE/f5dS3rD/fdMQB1aQ68wCwYDVR0PBAQDAgEGMDQGA1UdHwQt MCswKaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NUQ0EuY3JsMFsG A1UdIARUMFIwDAYKKwYBBAGB7RgDADBCBg8rBgEEAYHtGAMDAwMEBAMwLzAtBggr BgEFBQcCARYhaHR0cDovL3d3dy5zZWN1cmV0cnVzdC5jb20vbGVnYWwvMA0GCSqG SIb3DQEBBQUAA4IBAQBT8cigF+xsiIKxwCSv0QhYsyxve8FciZJviPxLwAJQky9a QZhZtuN/jBRjd31FPIhQXqaBUgDIxf5I7h9drd5EC0JYnOFnXEO2oIWY/xbUGii+ duEv4YT0frknqnfLNrP+w/rSF/bhYk7TzMyzGWXTS6jos9VM6vZOrsuuNEgfYMxY 5+d0yQE1/WrgWIrSFuvs6T678B3Ptv8eDLe7Oem3mBvAUiHrOj14OIypGV8npNB/ NmGrJH6f+C0/kiljvssQ2w1ANgKg1BeijX9+fJmvRVpAzaJrXL4O89OH/KEQyqoz t7pLwD2kIYwXnM/Yv+ZX/s3r+jAa1f7oJZepvjvq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEUjCCAzqgAwIBAgIJAOiEljmrZhBaMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTAzMDYxMzI5NDNaFw0z ODAxMTgxMzI5NDNaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 +rUCAwEAAaOByDCBxTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLD8bfQkPM Pcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAO BgNVHQ8BAf8EBAMCAQYwGwYDVR0RBBQwEoEQaW5mb0BlLXN6aWduby5odTBFBgNV HSAEPjA8MDoGDisGAQQBgagYAgEBAQUAMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9j cC5lLXN6aWduby5odS9xY3BzMA0GCSqGSIb3DQEBCwUAA4IBAQBuIO2Pc5wi0aEM ZEFoV+InAwjcwb4u5Bt3gA8BBpk2uRBveX+E5Iu0dNWjcrOQZuSAqndnH5q/OFoW J6uAvbf5YyAdZOGAHPl0RemduOyMG0ex2bpLEv6DqggOzHPI9r2tC0vHYpjdPJw8 w/kNaD6Fgp7J2fKMutUX6zky8beFyRQOTld6UUXQgVfq3PSvf857c3I2xj0Gfkcd fuNLJy3cok3slorMyaLzjtEchP9dGWeovJg5heIl77KWH4LlfZcOQFMoo92zH9k2 suDnM1LNowI/5I1sk6YAevotGgi1uZ0qqDfL5Ygrqr5rYqCmqgImSr0ChKWMe85D 1fmQ39jR -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIPzCCBiegAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBrDELMAkGA1UEBhMCRVUx QzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2Ft ZXJmaXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UE ChMSQUMgQ2FtZXJmaXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNp Z24gUm9vdCAtIDIwMDgwHhcNMDkwMzE2MTcxNjI1WhcNMjkwMzExMTcxNjI1WjCB qjELMAkGA1UEBhMCRVMxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjESMBAG A1UEBRMJQTgyNzQzMjg3MUswSQYDVQQHE0JNYWRyaWQgKHNlZSBjdXJyZW50IGFk ZHJlc3MgYXQgaHR0cHM6Ly93d3cuY2FtZXJmaXJtYS5jb20vYWRkcmVzcykxHTAb BgNVBAMTFEFDIENhbWVyZmlybWEgLSAyMDA5MIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEAmbHxFEYTJmMdPcYiPlWUGZu2+tQo4voohYi3dwCwoVuGdHSp kyoqs1B3YGx4u5KT4n0A7+Bb8YQ/QzbNy7UQ4JXAK+rT8JpNeKIvfN4lHnQJaChE 4fdn0KpvHWymaNq2k+EbQClquZB6OsTLvsivwSuSnyLcUw5rbajj53wq77fwB12y phMjwz2AnD1BvHZd3vLOaH1jRQP3zzNmyjT/Oj6+jdux7SBKlJWgQEaKflwcvYyc DPFPhGM4KPwEGX61PCrS+l8Lw0Kdy6K4lE+GrfgJrXM5m1Ey1R0c9McYQQPAtYcm cOnHHgkJdEAFVDa76T9C+lcMP6DNckbJIyc/ENrmM2v4rq/JnsJKEEx0VLyLizQx cGU3gp4ckg0ImQ9hV3H/DLWEqfrPuD++zaV81gpstnc9+pLg0Jibvwg3qvIr7nS5 acc//qqxH0iJGYoStHW5J5HoM9HcBvhACq5rjzjrNLPYSJqbPJwBHKcql/uUjQ6S SVWe3/CeJp6/vGuY1aRXAk9c/8oO0ZDrLKE8LsUgZesTLnWGd1LQcyQf6UMG1nb9 5C3eZRkCVpKma6Hl/SUQNukerlbLOU9InFGNPdeEVq1Jo62XeEi8KMbTPdXou6Yl rpe99dFnOUjVOdY7gfBGSgIVJjORqf/V70jwsxcYz7j6PKl0XulJs06vpSECAwEA AaOCAmowggJmMBIGA1UdEwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFMgAD/zGUvyf 2ztkLjK5bi5x82V5MIHhBgNVHSMEgdkwgdaAFLkJypwe29NsOmuu7VTxW5MGNS5e oYGypIGvMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwOIIJAMnN0+nVfSPO MH0GCCsGAQUFBwEBBHEwbzBFBggrBgEFBQcwAoY5aHR0cDovL3d3dy5jYW1lcmZp cm1hLmNvbS9jZXJ0cy9yb290X2NoYW1iZXJzaWduLTIwMDguY3J0MCYGCCsGAQUF BzABhhpodHRwOi8vb2NzcC5jYW1lcmZpcm1hLmNvbTAOBgNVHQ8BAf8EBAMCAQYw PgYDVR0gBDcwNTAzBgRVHSAAMCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vcG9saWN5 LmNhbWVyZmlybWEuY29tMH4GA1UdHwR3MHUwOKA2oDSGMmh0dHA6Ly9jcmwuY2Ft ZXJmaXJtYS5jb20vY2hhbWJlcnNpZ25yb290LTIwMDguY3JsMDmgN6A1hjNodHRw Oi8vY3JsMS5jYW1lcmZpcm1hLmNvbS9jaGFtYmVyc2lnbnJvb3QtMjAwOC5jcmww DQYJKoZIhvcNAQEFBQADggIBABNYG4jBwoI7e8pCuUyDc6rwpE9H6AgrUdL7O1xK TgTjDGBrMOBK+ZPS4Si8J3yZngvSrL694a1HmiiblJ+CmCdNGli2nBBM+OPK3tQB 4TW6hgkIe3vSNg/9o9y6+MAJcm8Kn0nPCBkSRME87NwvpehtekuF1G2ng1KDVwAn F+eCXfNanEwY++vWbJAuPE69Z/0+rCgNyH1PzihiNu6vrUlSlLWKaG34O1DEttX+ SsWTpEbpH9w5y9Vmw6WQ/B5nfhPM551HaMbiGgSxT9jHmf8APYQ3iT8EktcdTAdw m1miiyxfKG+WjPT7P/x8Np1spJZw+sNIDTLdZ0T1XQ6obVkBTFUDSULKW8949HDu VSwdl9Hu9lkDzzh9tyVYwwjEWVFZOiD/4TPVLfphf4ZEiyHt5YpNd9kZJIGGDxdc CdtzPm2dQODFpv72LnPQHbuBQPJ71zkoAmyeM/1Qj0DlrFsPcYnbRasck1VmYgDc Xc0+is0wcgCd7Gpx1zpEeVqwMD96am2xZPzd6nsbXvo+6TzsKLRMJo6nOERwrzuI F+/eq3WXxYMt2UenJsHqwSgPJRMdl3SFz0+SZN0viHeLuwb7qaHN74qC6GP8yHGp 2xe6Z11mJDPLDSrQQ2dOceSJ1LurJgLP7amYmFlWwVnmM7LnfShhMWMV+MDrICnL 2ksL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIETDCCAzSgAwIBAgILBAAAAAABL07hS5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0wOTAzMTgxMDAw MDBaFw0yODAxMjgxMjAwMDBaMEwxIDAeBgNVBAsTF0dsb2JhbFNpZ24gUm9vdCBD QSAtIFIzMRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzCV2kHkGeCIW9cCDtoTK KJ79BXYRxa2IcvxGAkPHsoqdBF8kyy5L4WCCRuFSqwyBR3Bs3WTR6/Usow+CPQwr rpfXthSGEHm7OxOAd4wI4UnSamIvH176lmjfiSeVOJ8G1z7JyyZZDXPesMjpJg6D FcbvW4vSBGDKSaYo9mk79svIKJHlnYphVzesdBTcdOA67nIvLpz70Lu/9T0A4QYz 6IIrrlOmOhZzjN1BDiA6wLSnoemyT5AuMmDpV8u5BJJoaOU4JmB1sp93/5EU764g SfytQBVI0QIxYRleuJfvrXe3ZJp6v1/BE++bYvsNbOBUaRapA9pu6YOTcXbGaYWC FwIDAQABo4IBIjCCAR4wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w HQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MEcGA1UdIARAMD4wPAYEVR0g ADA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBv c2l0b3J5LzAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmdsb2JhbHNpZ24u bmV0L3Jvb3QuY3JsMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEFBQcwAYYhaHR0cDov L29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIxMB8GA1UdIwQYMBaAFGB7ZhpFDZfK iVAvfQTNNKj//P1LMA0GCSqGSIb3DQEBBQUAA4IBAQCEoC43NawzW3zon4NAFHyN pYt78OCtkg54Svim/MYJvY8eKFoLqOlXq1Vfgq8X9R8EGPdPZgQEAlaSeI0Kq3tD kDPTszDB/LCPEHQ8YfdD0U79gW/i+qEIxVgWjEI8fkicCoYZ53t+tBA2coWHolAp oVGPjzExxRjr38amGTUASjzUW0Od5S+36Vshf6UF6EkPYhxFR6tDvPOA+l3Xoplu Cpf7CvC062JRhygAcgZLFHDsyleOhej7GfJMo4+H6yZZfWxjXUZPD5ZBF4+dIPG+ 04crOgCISIiXUQa5Xs1DaGQKOw+V7sqCTLXWOcndRhi9jFUaqrJWxHWrFdezCwju -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwKgAwIBAgILBAAAAAABIBnBkGYwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0wOTAzMTgxMTAw MDBaFw0yODAxMjgxMjAwMDBaMFQxGDAWBgNVBAsTD1RpbWVzdGFtcGluZyBDQTET MBEGA1UEChMKR2xvYmFsU2lnbjEjMCEGA1UEAxMaR2xvYmFsU2lnbiBUaW1lc3Rh bXBpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDDLcSDU1o ijPeNgXwPLr12s0OU3tGn4LyYhPXwXetu4E3fk8ek4HBBiLaHVCExpeVkqmTtj2r hnkZVH0OFgRMxIiXLMahqF8VOtJkK8w+DHropFaxHrvPhM6NNTo0nGwtwHe1MKkf Z+Y6CUQ6Q3JBopHDRpoftrmnD68cdRtkJecIbBRH9Uca3o7qomOVffWorVWiZJty b7kCcz85ijlcxP6P+xGcvRAZSWPQQyKL1quSmXQUzzAHvk+9/YqPnlrfbTzMWplQ kLmtwpdDwl/tzTM9h8zBoFupYjt4fWSjrE0fK9cDEWxxVIqwq7Ec1n0j20AHNybb UK84PaYHdW+XAgMBAAGjgekwgeYwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI MAYBAf8CAQAwHQYDVR0OBBYEFOjC8cQy3DM1N7xldvWcFy4XRSz+MEsGA1UdIARE MEIwQAYJKwYBBAGgMgEeMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2xvYmFs c2lnbi5uZXQvcmVwb3NpdG9yeS8wMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2Ny bC5nbG9iYWxzaWduLm5ldC9yb290LmNybDAfBgNVHSMEGDAWgBRge2YaRQ2XyolQ L30EzTSo//z9SzANBgkqhkiG9w0BAQUFAAOCAQEAXfbLKw0BQISfhXpDcGrgxeeq BgDXZxPJCJExZU8UqKkF3DieaqAwCr2Nx4Ao7kJFypTz3lhFqYAyBPVZXGpwADkn lE31tEY06BxTMbKzVBbpzEKr1dlZMBz7RicluIcjseh1iCSDHsh2N3sBSUVIpO3i XdJ8nKLcLboQWhJiZauuAMcQNDvLcr0UJAzcw3YntKf+4Vgp8g4Wn5E5HYmm5g8c h4ziWKySfiQ+quwU5zozNIvGO6yDqw8UYnq6Gi1NSxvFMPALknl9PHjg+ObSFZZZ mTkrMGHouPjAoekiFBF4fcTcib7Au5Thcq7rtUBAT+8XHlhe0KiJlqySKOm6vw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEUjCCAzqgAwIBAgIJAMJ+QwRORz8YMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 +rUCAwEAAaOByDCBxTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLD8bfQkPM Pcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAO BgNVHQ8BAf8EBAMCAQYwGwYDVR0RBBQwEoEQaW5mb0BlLXN6aWduby5odTBFBgNV HSAEPjA8MDoGDisGAQQBgagYAgEBAQUBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9j cC5lLXN6aWduby5odS9xY3BzMA0GCSqGSIb3DQEBCwUAA4IBAQAHRNyl0iqLjWf/ d5WkviojWWucrZVtnhAwzvJTVRZ4ZrQSsh4Uu6/0zr+cOSlX3N32UMm1N9Utyf5N eWy17Ze4o2xfRJEwycDaySaRR3AsBY0NaZsnHsneRvFLYny3qh0azV/6+DfNG2tq 9zY7zc9o6S9hbfoNxdpjffdFsuVqxVmk2TjGa7lZnMJga3JMDxFG4tdRoGhmS68z HDglRrcYPi5zlZeebRyLcTa1J5fc0rkPUYfldnjGyxMc6yBdeTyqU0bbgJvjmJEU ChOvPJUiHUmO8oz7Gb7SkHrhk4apyYClA9rRuxTxXbFPgOnomN/zVIs8zvDLINUW G1jzE3Nh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3DCCA8SgAwIBAgIIUzAV4JqeuGYwDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA4MjUxMDA1NTRaFw0zMDA2 MTYxMDA1NTRaMIIBFjELMAkGA1UEBhMCRVMxJzAlBgkqhkiG9w0BCQEWGGNhMUBm aXJtYXByb2Zlc2lvbmFsLmNvbTEiMCAGA1UEBxMZQy8gTXVudGFuZXIgMjQ0IEJh cmNlbG9uYTExMC8GA1UECxMoQ29uc3VsdGUgaHR0cDovL3d3dy5maXJtYXByb2Zl c2lvbmFsLmNvbTE0MDIGA1UECxMrSmVyYXJxdWlhIGRlIENlcnRpZmljYWNpb24g RmlybWFwcm9mZXNpb25hbDEtMCsGA1UEChMkRmlybWFwcm9mZXNpb25hbCBTLkEu IE5JRiBBLTYyNjM0MDY4MSIwIAYDVQQDExlBQyBGaXJtYXByb2Zlc2lvbmFsIC0g Q0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx6ueMJNjb6i6tdxq 8ak6BWbjlZ23jEFapQyGdYLolQAY94yiPaX/i3XEJEqanwqlfG63okc/PWRl/le8 Q6QhJVTNR4yOaVxbGFvF9nIk9T7425YChgqoru0T/o8iU6ItZJ8byZSHiuZnycOw EFVZ6eQX9CyvJ/vNhCMW1iXTuQKLckU3CSSAPHKYEE0m1FMhbArWazbI0eFk8/9V HFf9/ZyyyaThZEyE+OFs2i8r7fADsd7wzeFxSjajVouFOnOtu0YUV6vpl4hCcNqs N4A5TupRCftPx9l5r4dOguCJLNBq6JEPejb73sFU3HFviXTcVpVhXUxpLQzOf6xN ZD0bUwIDAQABo4HwMIHtMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU Zc3rqzUeAD5+1XTAHLRzRw4aZC8wOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2Ny bC5maXJtYXByb2Zlc2lvbmFsLmNvbS9mcHJvb3QuY3JsMA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUi1BXWsG9kgCmt+WFXcPdtrWGkNIwSgYDVR0gBEMwQTA/Bgor BgEEAYphCgoBMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNp b25hbC5jb20vY3BzMA0GCSqGSIb3DQEBBQUAA4ICAQBVflkYOaplyB9sBjEEfyUz pFFUdI3xVJTBPLLBPz9t/OwfK7Xzfanm/QLQTID5gcOUpPaSUFrh98al+RUSLDHC wKwzniwjQpZs2ggp+n8XNSVeX+oSS+okj4ovOT7JbY0IY9XVt3rhffCvppptEqqP aSqbo6Cq08vZ+lgGRXmekdvT3L44NUQtgfjnF9lUoXoZXiCMPjM0rHzZTFBv0Itw Xjhn6TdZoOUHZJN9LROctr0FuRzOjVfIvInuq+zIqXfzqsLXM8i3ONva+nlmDC/a 2sqkCi2oyAa4OvRAaS4YO6c1PPe2A+JHDuIRjT1u7IDZBQqS1vWsu4r1SnOsjkCt nRzw3ISZXCcP27JpNqyJVti6JwQ0DFetMtalhXDeqRvuTyIdHes3VWDpBw6SRTcc mI6Yz2ZiL2k27fjo4EwoyihMkSXtFkBiTQWym0FoWBZFh436GQlygn5BczHlTHRl vKZ0fx4NcIzr2pYVFqnTSzKFA6a6R30sv7Q2U05GlIsYOpnoraKSahZOIKP0uIG/ e/6JF0j7kyVDl1SvwnSNXY/LM3slsR+c2s+kacIXXO/szON8aszjT5h67sRrl/Su T4SfpWh6pJMD9OLmvtXftJcXEzTMM4b/TyKqPBkzgJd5HPgsVlTJt33u4LYOvS0r b/RBIGXsRG3pC4ihftt6OQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEdTCCA12gAwIBAgIJANjJM0P+XTkpMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV BAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIw MAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eTAeFw0wOTA4MzAwMDAwMDBaFw0zNDA2MjgxODAwMDBaMIGYMQswCQYDVQQGEwJV UzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UE ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZp ZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVDDrEKvlO4vW+GZdfjohTsR8/ y8+fIBNtKTrID30892t2OGPZNmCom15cAICyL1l/9of5JUOG52kbUpqQ4XHj2C0N Tm/2yEnZtvMaVq4rtnQU68/7JuMauh2WLmo7WJSJR1b/JaCTcFOD2oR0FMNnngRo Ot+OQFodSk7PQ5E751bWAHDLUu57fa4657wx+UX2wmDPE1kCK4DMNEffud6QZW0C zyyRpqbn3oUYSXxmTqM6bam17jQuug0DuDPfR+uxa40l2ZvOgdFFRjKWcIfeAg5J Q4W2bHO7ZOphQazJ1FTfhy/HIrImzJ9ZVGif/L4qL8RVHHVAYBeFAlU5i38FAgMB AAGjgfAwge0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0O BBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMB8GA1UdIwQYMBaAFL9ft9HO3R+G9FtV rNzXEMIOqYjnME8GCCsGAQUFBwEBBEMwQTAcBggrBgEFBQcwAYYQaHR0cDovL28u c3MyLnVzLzAhBggrBgEFBQcwAoYVaHR0cDovL3guc3MyLnVzL3guY2VyMCYGA1Ud HwQfMB0wG6AZoBeGFWh0dHA6Ly9zLnNzMi51cy9yLmNybDARBgNVHSAECjAIMAYG BFUdIAAwDQYJKoZIhvcNAQELBQADggEBAFg2BzSkeJ19IPlQijzXPYRZEQnTjtFF a5d5aSZCk6JTcsq9dtgat6bQKkpDz7RETHpz9B7n1LJeLMOAcQuVjF65CCavDmp0 aw17VmC63u7Z4tNWupeSPSuKCGkIwofgBhBC7PsZrszaKHO1TkAcWDGWHnjVTMht 4sfv66jepOqUBClYXmRsCdxXqlKCjJHUptov3ho4ANG9RZXTn13p36AU1tyZ1iFi WghNWnoXQ8UdcIZiX5y7D6HMZ6CcCt59vSLRMsYX8Bw/jWV8M+N4mr+F5ydmSq5J BkV9W9BzwNXiOxwWcLbidb1N28HhoMlQhihpxsUpIgD2WtsQgeaNjUA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk 6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn 0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN sSi6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEdTCCA12gAwIBAgIJAKcOSkw0grd/MA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV BAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIw MAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eTAeFw0wOTA5MDIwMDAwMDBaFw0zNDA2MjgxNzM5MTZaMIGYMQswCQYDVQQGEwJV UzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UE ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZp ZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVDDrEKvlO4vW+GZdfjohTsR8/ y8+fIBNtKTrID30892t2OGPZNmCom15cAICyL1l/9of5JUOG52kbUpqQ4XHj2C0N Tm/2yEnZtvMaVq4rtnQU68/7JuMauh2WLmo7WJSJR1b/JaCTcFOD2oR0FMNnngRo Ot+OQFodSk7PQ5E751bWAHDLUu57fa4657wx+UX2wmDPE1kCK4DMNEffud6QZW0C zyyRpqbn3oUYSXxmTqM6bam17jQuug0DuDPfR+uxa40l2ZvOgdFFRjKWcIfeAg5J Q4W2bHO7ZOphQazJ1FTfhy/HIrImzJ9ZVGif/L4qL8RVHHVAYBeFAlU5i38FAgMB AAGjgfAwge0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0O BBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMB8GA1UdIwQYMBaAFL9ft9HO3R+G9FtV rNzXEMIOqYjnME8GCCsGAQUFBwEBBEMwQTAcBggrBgEFBQcwAYYQaHR0cDovL28u c3MyLnVzLzAhBggrBgEFBQcwAoYVaHR0cDovL3guc3MyLnVzL3guY2VyMCYGA1Ud HwQfMB0wG6AZoBeGFWh0dHA6Ly9zLnNzMi51cy9yLmNybDARBgNVHSAECjAIMAYG BFUdIAAwDQYJKoZIhvcNAQELBQADggEBACMd44pXyn3pF3lM8R5V/cxTbj5HD9/G VfKyBDbtgB9TxF00KGu+x1X8Z+rLP3+QsjPNG1gQggL4+C/1E2DUBc7xgQjB3ad1 l08YuW3e95ORCLp+QCztweq7dp4zBncdDQh/U90bZKuCJ/Fp1U1ervShw3WnWEQt 8jxwmKy6abaVd38PMV4s/KCHOkdp8Hlf9BRUpJVeEXgSYCfOn8J3/yNTd126/+pZ 59vPr5KW7ySaNRB6nJHGDn2Z9j8Z3/VyVOEVqQdZe4O/Ui5GjLIAZHYcSNPYeehu VsyuLAOQ1xk4meTKCRlb/weWsKh/NEnfVqn3sF/tM+2MR7cwA130A4w= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFMjCCBBqgAwIBAgIDCZBjMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMTIxMjQ2NTVaFw0yOTExMDUwODM1NTha MEwxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJjAkBgNVBAMM HUQtVFJVU1QgU1NMIENsYXNzIDMgQ0EgMSAyMDA5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAoal0SyLSijE0JkuhHJmOCbmQznyxuSY7DaEwhUsdUpI+ 2llkDLz6s9BWQe1zCVXDhrt3qz5U5H4h6jxm5Ec+ZbFiU3Gv2yxpI5cRPrqj9mJU 1CGgy1+29khuUnoopzSq66HPuGZGh06I7bJkXTQ7AQ92z1MdL2wATj1UWdNid3sQ NiWIm+69nURHY6tmCNenNcG6aV4qjHMUPsjpCRabNY9nUO12rsmiDW2mbAC3gcxQ lqLgLYur9HvB8cW0xu2JZ/B3PXmNphVuWskp3Y1u0SvIYzuEsE7lWDbBmtWZtabB hzThkDQvd+3keQ1sU/beq1NeXfgKzQ5G+4Ql2PUY/wIDAQABo4ICGjCCAhYwHwYD VR0jBBgwFoAU/doUxJ8w3iG9HkI5/KtjI0ng8YQwRAYIKwYBBQUHAQEEODA2MDQG CCsGAQUFBzABhihodHRwOi8vcm9vdC1jMy1jYTItMjAwOS5vY3NwLmQtdHJ1c3Qu bmV0MF8GA1UdIARYMFYwVAYEVR0gADBMMEoGCCsGAQUFBwIBFj5odHRwOi8vd3d3 LmQtdHJ1c3QubmV0L2ludGVybmV0L2ZpbGVzL0QtVFJVU1RfUm9vdF9QS0lfQ1BT LnBkZjAzBgNVHREELDAqgRBpbmZvQGQtdHJ1c3QubmV0hhZodHRwOi8vd3d3LmQt dHJ1c3QubmV0MIHTBgNVHR8EgcswgcgwgYCgfqB8hnpsZGFwOi8vZGlyZWN0b3J5 LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El MjAyJTIwMjAwOSxPPUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZv Y2F0aW9ubGlzdDBDoEGgP4Y9aHR0cDovL3d3dy5kLXRydXN0Lm5ldC9jcmwvZC10 cnVzdF9yb290X2NsYXNzXzNfY2FfMl8yMDA5LmNybDAdBgNVHQ4EFgQUUBkylJrE tQRNVtDAgyHVNVWwsXowDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwDQYJKoZIhvcNAQELBQADggEBABM5QRHX/yInsmZLWVlvmWmKb3c4IB3hAIVR sAGhkvQJ/RD1GZjZUBBYMWkD1P37fTQxlqTOe3NecVvElkYZuCq7HSM6o7awzb3m yLn1kN+hDCsxX0EYbVSNjEjkW3QEkqJH9owH4qeMDxf7tfXB7BVKO+rarYPa2PR8 Wz2KhjFDmAeFg2J89YcpeJJEEJXoweAkgJEEwwEIfJ2yLjYo78RD0Rvij/+zkfj9 +dSvTiZTuqicyo37qNoYHgchuqXnKodhWkW89oo2NKhfeNHHbqvXEJmx0PbI6YyQ 50GnYECZRHNKhgbPEtNy/QetU53aWlTlvu4NIwLW5XVsrxlQ2Zw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFRTCCBC2gAwIBAgIDCZBkMA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMTIxMjUyNDNaFw0yOTExMDUwODUw NDZaME8xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKTAnBgNV BAMMIEQtVFJVU1QgU1NMIENsYXNzIDMgQ0EgMSBFViAyMDA5MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAygp+ZziakFyPq80fk1QIT9UCcPy0R3UIyq56 hXA6lhgfs1l9R9wRM9/DIVX2olb0gHCXdpnHRm+jwzeL3dHJO8Im5Om/c24ZfSVE zBcgKxS5X7X5e7oCYb9tozd9xs04WqYd5kWrvCJsSQf5gtv5gAeJt+QiU7dtXs3A YDflWv4g9eEaDExxM0VQmceEAo5qc7I7dk5ry356G14zQmr29cxie6YS0kH+7qn5 g+c21M01sENle0tBPxIfkv+nV95Ih3JkpHSPm/wgFKfCtwRtG+5VehUoMEpgfi0X fmVkag558aQpaaeQCtYZnXuq6g1D1LAcjIqMpOP4wNRp1ldLzQIDAQABo4ICJzCC AiMwHwYDVR0jBBgwFoAU05SKTGITKhkuzK9yin0215oc3GcwRwYIKwYBBQUHAQEE OzA5MDcGCCsGAQUFBzABhitodHRwOi8vcm9vdC1jMy1jYTItZXYtMjAwOS5vY3Nw LmQtdHJ1c3QubmV0MF8GA1UdIARYMFYwVAYEVR0gADBMMEoGCCsGAQUFBwIBFj5o dHRwOi8vd3d3LmQtdHJ1c3QubmV0L2ludGVybmV0L2ZpbGVzL0QtVFJVU1RfUm9v dF9QS0lfQ1BTLnBkZjAzBgNVHREELDAqgRBpbmZvQGQtdHJ1c3QubmV0hhZodHRw Oi8vd3d3LmQtdHJ1c3QubmV0MIHdBgNVHR8EgdUwgdIwgYeggYSggYGGf2xkYXA6 Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQvQ049RC1UUlVTVCUyMFJvb3QlMjBDbGFz cyUyMDMlMjBDQSUyMDIlMjBFViUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURF P2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwRqBEoEKGQGh0dHA6Ly93d3cuZC10 cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfZXZfMjAwOS5j cmwwHQYDVR0OBBYEFKztpZ16orZD8RiKJWpsscyo8lrUMA4GA1UdDwEB/wQEAwIB BjASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQA6I3sGyvb4 MdTyEZFBBWBN/5Kx1SVkkPsll8DvgosJiuuK4I7mD6FFKDjKgogr407EoDSS2t1+ pSmQCb0rNXoJT3YIlpZGqPYU2rcwrelabJQZWAfoRnbkDx2aqofhp5u45dyQpM2t R93/oA36iuHYc9Ewq8CaLGolrpT138RD7i4nN7sZFuFH0IseNz0+EZm88NHi9WeJ UyshWFKBKARi+589Y4P/G2XnbckxFKUxa7uEroZcMwvKBy469K0Au0zVTxs1zNtf Ol3QkNgPwzOPeHhOnpzcenyPgNEm+HQ0FPTnB4HeKBqTeLpkM7h4gq5MZ2TPmfuX KDz3AHrWLLdH -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE7TCCA9WgAwIBAgIBGTANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCSFUx ETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3NlYyBMdGQuMScwJQYD VQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkxHzAdBgkqhkiG9w0B CQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMDkxMjAyMTYwMDAwWhcNMjkxMjI5MTYw MDAwWjCBhTELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQK DA1NaWNyb3NlYyBMdGQuMSowKAYDVQQDDCFBZHZhbmNlZCBDbGFzcyAzIGUtU3pp Z25vIENBIDIwMDkxHzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDXfl3YP3Zl5+AG6LZuE2CBicT5 07Cj1q3LlzUc7YIykix/h2k/5E+1dDSO2SPINrfttUvcxp4sbzW7mjXpY+64sdjg DLhEQGbH0oCjDBxcqKtI4zSNrF2uwOx06tkRT5GvZzbBN9aRFj20+HmYdUS+XDRu MKgWXzx/9uvyDNHstyGEQGS280UKjZnuM8TWX53a6aKoVJIHERmK3uqc9BcM0nuA y/tFD8joBtemKZYH4yfnpTteGIRK8Uu0EoPt6kjM6YrgFZ765gsOFU2gZ5QmTmGH HcpM2hX702eRS/pfpqHwsiXdQpRcpfVaBDlzkI1n4IfPMeiXuYcO3UTzgmP/AgMB AAGjggFnMIIBYzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA7BgNV HSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL2NwLmUtc3ppZ25v Lmh1L3FjcHMwHQYDVR0OBBYEFCa3GAGsnHjvwKWHwA0/PJryi0WBMB8GA1UdIwQY MBaAFMsPxt9CQ8w9y7VII6EaeqYquzRoMBsGA1UdEQQUMBKBEGluZm9AZS1zemln bm8uaHUwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5lLXN6aWduby5odS9y b290Y2EyMDA5LmNybDBuBggrBgEFBQcBAQRiMGAwKwYIKwYBBQUHMAGGH2h0dHA6 Ly9yb290b2NzcDIwMDkuZS1zemlnbm8uaHUwMQYIKwYBBQUHMAKGJWh0dHA6Ly93 d3cuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcnQwDQYJKoZIhvcNAQELBQADggEB AAgx8vZl/lgms9yJjqaixckqCnrXbo2IiY+ZgD0dcu/hHpKGiafdSKYE+jXtpbyT 7pbqHKfuC87qK6tbUSo4UViyhBmpITlOfvghyNzHIT5Vbb1rSzPNd4tYBQRI8kZ6 gCZFZ22VR3YZ+yclip6g1a1DY2NSW/asx9mqVWn0D9lMvm6dUMLhmW8lR52KqDWf mROe+APmuxhC78qqOP0tI7HwjvOaYeGzQknJrgj4f2DWLTm8r8zH7CmgmMr1tDWQ BY6nMCPK3lWhxtFwJP48RoZFIX9SmP6oH9gIDNe4WjzZICnhraW0B3t/0D8ZqY+m Y0V57A+i2iwOA/lQBHS2rPw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5TCCA82gAwIBAgIBFjANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCSFUx ETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3NlYyBMdGQuMScwJQYD VQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkxHzAdBgkqhkiG9w0B CQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMDkxMjAyMTYwMDAwWhcNMjkxMjI5MTYw MDAwWjB+MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoM DU1pY3Jvc2VjIEx0ZC4xIzAhBgNVBAMMGlF1YWxpZmllZCBlLVN6aWdubyBDQSAy MDA5MR8wHQYJKoZIhvcNAQkBFhBpbmZvQGUtc3ppZ25vLmh1MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJqmBGY9xZ51zoea/outpBPnSoI/vo/yR+DO m7H846WTrGzry2dCR0rb2wqGY7Sw2UnLOVUANofd/lH1msxRi8NaiJDC7mKOz4MF oXtDQzyC8BedK8sEJgQRe5r7zpujqZ389uab/loufLn06V3/LVP7jbUxf/gX6ovO dvNtG9LEE2V+YuRm46NZbEFytiPls//8eMv+/52noHwrbr+xvHOr4aN7+63FFVRs 1yz2mdEcd74qVAYDylZo0xI042cxkBNdj3ImjgNHhg+vVLiYKbHikAMwxTBzv7ht RmoPMDJID3V9aahTSeCtz3EB3+n+1gDWojmj+RfqNCD1B5J7GQIDAQABo4IBZzCC AWMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwOwYDVR0gBDQwMjAw BgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcC5lLXN6aWduby5odS9xY3Bz MB0GA1UdDgQWBBTRimP+ywj96UoXaAGtPA7V3Zf3BDAfBgNVHSMEGDAWgBTLD8bf QkPMPcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MDYG A1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZS1zemlnbm8uaHUvcm9vdGNhMjAw OS5jcmwwbgYIKwYBBQUHAQEEYjBgMCsGCCsGAQUFBzABhh9odHRwOi8vcm9vdG9j c3AyMDA5LmUtc3ppZ25vLmh1MDEGCCsGAQUFBzAChiVodHRwOi8vd3d3LmUtc3pp Z25vLmh1L3Jvb3RjYTIwMDkuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQB8he+K09wl 6wEpphQvsko9HkVEP3ghRrLV+idNcly83q+ipEtuSUGmnVhDM1K0h+xiLHZuJ694 lj/xwy2n5G36WXP2gG4A3Xciq0FuqV4w/AYRVzkTiwaJhdG2i8SamBgpu4mhwBRm XCRYXzNwTw+/oL43CB2/+0l3LVmhe9DXt30MJ4svN9UKho1h/d11QBCi8WCkdE0W aYYxUXTS3dUBjOFgVwH/Pa6Q+RBVaXhr21YgaFS38ykxF5+KFWxgzqhHTI75lWVi FPDHJJJ0hCClol0cVMai7iQArnSG7ZN7WznPrVU2o2VhQObHu7ANtPNfT5d2EQeQ KJWSNciRog7R -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE7TCCA9WgAwIBAgIBGDANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCSFUx ETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3NlYyBMdGQuMScwJQYD VQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkxHzAdBgkqhkiG9w0B CQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMDkxMjAyMTYwMDAwWhcNMjkxMjI5MTYw MDAwWjCBhTELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQK DA1NaWNyb3NlYyBMdGQuMSowKAYDVQQDDCFBZHZhbmNlZCBDbGFzcyAyIGUtU3pp Z25vIENBIDIwMDkxHzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0T/4LGUJd2jJH4e+s0fdMK9r4 DWRFFCKARQwE+PoeTmNHisCjsXjz7vjgB1ogvoNa4UxycfEKQhXe1MrwC7/17dRG QjLaATTqznUvkb+jZ250ONnu3Q0ble960l5wHS5qOlJOaIa+3eDsYkwxJUy0cYFZ qbVB9Y8FiJTDGnXFi96xz1Hf/JjA8y58tQzlbwAdJR2dszYR2W0wnJ35V4K/PdsB C8XLKZmv8F04it9t4MIJ3YGrDfeam0l0ThBlwEuoihBXB9rKwrtdZubyuXvYAGO9 a94/wYMhd9eflO1B0pWuhDZCY4Fu/+6CHybYT4/fhXXp4Bcl6zbns9I9BTDfAgMB AAGjggFnMIIBYzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA7BgNV HSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL2NwLmUtc3ppZ25v Lmh1L3FjcHMwHQYDVR0OBBYEFD617fKjJSjkAjerFsO1/ZyAv1M4MB8GA1UdIwQY MBaAFMsPxt9CQ8w9y7VII6EaeqYquzRoMBsGA1UdEQQUMBKBEGluZm9AZS1zemln bm8uaHUwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5lLXN6aWduby5odS9y b290Y2EyMDA5LmNybDBuBggrBgEFBQcBAQRiMGAwKwYIKwYBBQUHMAGGH2h0dHA6 Ly9yb290b2NzcDIwMDkuZS1zemlnbm8uaHUwMQYIKwYBBQUHMAKGJWh0dHA6Ly93 d3cuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcnQwDQYJKoZIhvcNAQELBQADggEB AMsiD8NEXtuKGTdw+aZ2fZrc2PKArjTZyqiaUax+4VFl9G+L2gvNNNQVxf3HZBLi S90lDNGvV+zVpZDWKWvhnzqmYaqiTwCaaiOgJTDtffUvGzW9VmKZaEPUfYvP4s+I rlHkT0hwD9nsg+N2PaDLcHzGZUNvDqLxbaKuUqzFVqVAm1upuiX4ZifNNkFZ2faA RNyUVsEWMTMy3k6JKDMix0Qd/xdE2zfNRzI/i8klUJgcJq/VrOpw6nZYKn7n/XFG sGF/Ef2e7kGKeADjjS1yH/3r0Y4wmEZvCaYaOptD6vY3EMiDiFN8VFFe/f+zreR2 WyW2W6T+SGVDfAkacwhekTY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8jCCA9qgAwIBAgIBGjANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCSFUx ETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3NlYyBMdGQuMScwJQYD VQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkxHzAdBgkqhkiG9w0B CQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMDkxMjAyMTYwMDAwWhcNMjkxMjI5MTYw MDAwWjCBijELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQK DA1NaWNyb3NlYyBMdGQuMS8wLQYDVQQDDCZBZHZhbmNlZCBQc2V1ZG9ueW1vdXMg ZS1Temlnbm8gQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANBz0mD8QmA6LJt+YOZY NmD6QwPqdA+VFPdj9kPT+N+fmCTOt0rfOyaEsE8QyglwHCw3ZOop9ftKu18ojHOa RrJSa2klzQv2sHSMhOdC0DMtw8DBjst0q9nNNGFo6dKo8E+7BYb/iCNWjGxncQ67 PUSPuh8bKrk9OnDch70VUk92k/jOS9qXBD0KLwkbUqexZcTF20ZVF1fZuxKvxWZ+ UnxZeUZLJv/C6yv5n8lXUN3uQZkon6oRa8ctZ7xAqdSsmUT2qCbE7/hg9RYbIH+7 lbMqi/wEREzOyHUJfeBVZg47byl1GThtgmRPejcjZMamybbTuti0v5fXN3jz+G3M lNcCAwEAAaOCAWcwggFjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3AuZS1z emlnbm8uaHUvcWNwczAdBgNVHQ4EFgQUo4UxjmMYhi2v2BfNoTfEnOsBHfcwHwYD VR0jBBgwFoAUyw/G30JDzD3LtUgjoRp6piq7NGgwGwYDVR0RBBQwEoEQaW5mb0Bl LXN6aWduby5odTA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmUtc3ppZ25v Lmh1L3Jvb3RjYTIwMDkuY3JsMG4GCCsGAQUFBwEBBGIwYDArBggrBgEFBQcwAYYf aHR0cDovL3Jvb3RvY3NwMjAwOS5lLXN6aWduby5odTAxBggrBgEFBQcwAoYlaHR0 cDovL3d3dy5lLXN6aWduby5odS9yb290Y2EyMDA5LmNydDANBgkqhkiG9w0BAQsF AAOCAQEAQjlh1SGe4j5Iyr9HrwqqI+tgaerQETPhy1cRaDCeCnPT/RveEgyDVhKA mpwZhKAdl+2fRUk+xSI3QFHibUPVoDl3CUNvL9LAMeM2SjsGO9oQDVbjFLzXQ0zL wFDwE4SXzLHZWNCHrIOVzXxAxYogVu4uB0tBQ7TpIO6y1JGkqX0R2coNX0zdPDWF Xerjqe1PT021ju0a41VMFmFX0PNMhr5CfYnSbsRjnM4Ztrk1nMK8VydfXy9CnJ0W wPhb+hFr0XnuKuWEttwg5+STRlpVRhAxmlPUUPplAlw99wv/QCQMDdhniIaYXil+ hpMs7M6BLq0N/u/H9ut/xedcjYCDFA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8zCCA9ugAwIBAgIBFzANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCSFUx ETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3NlYyBMdGQuMScwJQYD VQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkxHzAdBgkqhkiG9w0B CQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMDkxMjAyMTYwMDAwWhcNMjkxMjI5MTYw MDAwWjCBizELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQK DA1NaWNyb3NlYyBMdGQuMTAwLgYDVQQDDCdRdWFsaWZpZWQgUHNldWRvbnltb3Vz IGUtU3ppZ25vIENBIDIwMDkxHzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8u aHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCShR63uLI4AbVP1dmo v12v94KDhTo6BT1sPHTu+qeCmYuu5mcX4YezH4KGy04rimZ24O4g7fGnQUa+Ngq/ ul8J4QgL9v7c9J67I7iFpUA/Jft7ueTpJzgK2+J40qmkkb6gBq3v3zwJz9NZeNMk vpaNHYRFzp8qxHGz5CsJcij8PAYE0bv4ulXm+y2Hxq/9aClJ3CXWDPl+wBYpuUn8 kcEU+pDhVHvXX8CP6PO/AcR5Jpna+pem95CqvjWRO6a4ta7Y4ZdNTvDi5Zqnm2jL DRlKjOL6OrSWDIABmJUnKxlW5sQeYxreoOfk+9lRc6k8/C60f24qO1prH42QzaLp a3jZAgMBAAGjggFnMIIBYzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL2NwLmUt c3ppZ25vLmh1L3FjcHMwHQYDVR0OBBYEFJJ9tkVQDu+WMGe06dDTRHlITyDLMB8G A1UdIwQYMBaAFMsPxt9CQ8w9y7VII6EaeqYquzRoMBsGA1UdEQQUMBKBEGluZm9A ZS1zemlnbm8uaHUwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5lLXN6aWdu by5odS9yb290Y2EyMDA5LmNybDBuBggrBgEFBQcBAQRiMGAwKwYIKwYBBQUHMAGG H2h0dHA6Ly9yb290b2NzcDIwMDkuZS1zemlnbm8uaHUwMQYIKwYBBQUHMAKGJWh0 dHA6Ly93d3cuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcnQwDQYJKoZIhvcNAQEL BQADggEBAHupcutAk0J2U6+1hPGIPiXdolZdJ9lGkVsDivOxuNzKh0Dj61XaVjQr iidBrd+ipNNOCYwUF0nGEPS65Fz3AjIDFg5iADqdmTK4SWe7QvuzW4KNwT7XWmBH MetID0y8Bi7wO7aCh7TQ408U9gSqrw3CCN6kXx/zqqW2CwiO2c+o7ZmREGMxXNHi qNXy2bRd1twSU3VSIcdZ1CSRU+VWxfIg2dmOJJcgHGkLfhVCnLn4k8aA+kxVGEy/ pVD9PSZSj4siECm6gsNLDWD/f0iviVpIL0Pcq15v1n1+uy9tveMjxbSUdxthDNP0 CCmCPJDb1OaJZsrW7ESow42DMZd5Sxo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGbzCCBFegAwIBAgIQANXLicKTAJvtvQFL3BCWAjANBgkqhkiG9w0BAQUFADBJ MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQDExpT d2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjAeFw0xMDAzMDgxNDA1MDRaFw0yNTAz MDQxNDA1MDRaMFcxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcx MTAvBgNVBAMTKFN3aXNzU2lnbiBTdWlzc2VJRCBQbGF0aW51bSBDQSAyMDEwIC0g RzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhxIQRcjI0MdxZiPdC tU7/k4F+shRorhq74URxIV7gy9D3/BXen0MZJN/y+WNyAc08hijiIdiHzElWfscr s8brJL4mehCyXlzwMjtQTllb+SN8ePjlb6sObKGe1CobsWM9lCg9Z2ULaUaRXY0S 16dT5TSNd/Y2lDDcuI+0XcKOWJevwF26wmS9SbQi19olpsXj7KAVr2oCb1gsZhow 1yTXsKgqwJW0N1oUqMGbcKiVl4HkYARlPB0HAWcc2n19e+f5C43CETnAxlPjqlVc 1smUKucR1uWaJYSF6L2MHnfzWFKwpqL/MtqV1VD9pK7XRZiDkoqRR9JZVVJxP6Po +0zZAgMBAAGjggJDMIICPzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHQ4EFgQU6USGgJLqTlB3yeeSCELXX8DCJUIwHwYDVR0jBBgwFoAU UK/MB4cVR284xbRl0d6VqunfnMwwgf8GA1UdHwSB9zCB9DBHoEWgQ4ZBaHR0cDov L2NybC5zd2lzc3NpZ24ubmV0LzUwQUZDQzA3ODcxNTQ3NkYzOEM1QjQ2NUQxREU5 NUFBRTlERjlDQ0MwgaiggaWggaKGgZ9sZGFwOi8vZGlyZWN0b3J5LnN3aXNzc2ln bi5uZXQvQ049NTBBRkNDMDc4NzE1NDc2RjM4QzVCNDY1RDFERTk1QUFFOURGOUND QyUyQ089U3dpc3NTaWduJTJDQz1DSD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0 P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwYQYDVR0gBFow WDBWBgRVHSAAME4wTAYIKwYBBQUHAgEWQGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNz c2lnbi5jb20vU3dpc3NTaWduLVBsYXRpbnVtLUNQLUNQUy1SMy5wZGYwdAYIKwYB BQUHAQEEaDBmMGQGCCsGAQUFBzAChlhodHRwOi8vc3dpc3NzaWduLm5ldC9jZ2kt YmluL2F1dGhvcml0eS9kb3dubG9hZC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVE MURFOTVBQUU5REY5Q0NDMA0GCSqGSIb3DQEBBQUAA4ICAQA6hj4f0Cef1KmpWwcF 7five23ZyhWfnfzoXRSIfUiFpY0xVmirT+wqNe5an6RmuQ0CpbCG+TiqCGWXG2eA jsNIbj7X/1Iael7wNO+eBEd6wDNWRsd8Kg2qUoYGeMKnqL5x2bM5veimPQwJ3mRC Q+SzDdhOQFckOI1pTjdhFFdvW4QCBBuLMqQGDFkamMNrgVKzmvL5iratd5pSU9aY JH3BlLmRnVqfJ/DJFKYVAr9s8yKQLD3JJ7bwO3P2cw3BmYc0a+EZhQX4XRAcxv6x 1sbHpMPjrl+p1h7kzv9ikSVG9LqMo49JypRmirTHGsFqRzhc9CA04KsJG7Q8qBE5 Z5Qa/fNnDy5jlfLkMmh7sXtqfEQmBPD0DjVLRYOHvkjCOv2X3VL0jN6IZHeDpLqG t6T3w9aN0eYB8ij0UcYJJdskV9r3nyHzZAqfJ1TLv16dfBFw9u+XDUWhOQFaBzS5 x4jHeNUyVTs3IT7Q8KIwhYz9gFufQHQqZNhvaF117xgManYz6ptbbBC/WCML2+2b QSezVt6Y3caB5ZDFBcwBhcMlZv50XLWw4jC+HOnfV6LTrHgLcS6JBcg3ORB2A4v/ tvl7mvbczjFZ0hK/0gQfA9zgi5cnY0GsHzOT1GZlFxA6N4d3AMzuf6LcWU+Mvb9K 1Xbyoi4+LDNiNCHNA4FAz7vF3g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHXjCCBUagAwIBAgIQAKsyzbybWZQjBPpthOQNvTANBgkqhkiG9w0BAQsFADBJ MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQDExpT d2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjAeFw0xMDA0MDYxNDAzMzRaFw0yNTA0 MDIxNDAzMzRaMFgxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcx MjAwBgNVBAMTKVN3aXNzU2lnbiBRdWFsaWZpZWQgUGxhdGludW0gQ0EgMjAxMCAt IEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk/Nq1vxVCDLq5FQg +qcam1UZ7venCbHcS92nS1V2uCNfyGed5RNaBYy5fW6SDMUClMcfNGHlMBf2xkje 61jUjkeVghpwbzSiXJHpogZjBbrv5Kfy7J0cuiOT1iNY6XOAXSTXq56S2ySUs6s9 c2D6Sg8AtG0zLgHvBs2zZ8dL934FGN/1cG/8m+QMhvlDHvaAnUTIEi1zUfsWTNO+ vPWONxCFf3Nt59hLCGWf6KsRSj8x89AzZSv8Ih5dTiJLQyvej9f0JRMiPPa9tL0C vYzNK2tgu5DQJcS+NZOODSSB0iDvXI+NyR5CyYpJriXvDrCI6T3nTFyz/QpZ1XfT /S9ONQIDAQABo4IDMTCCAy0wRQYDVR0SBD4wPKQ6MDgxCzAJBgNVBAYUAkNIMSkw JwYDVQQKFCBaZXJ0RVMgUmVjb2duaXRpb24gQm9keTogS1BNRyBBRzAOBgNVHQ8B Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUclHgqp37fjhE 6gJvQMifzii/HHcwHwYDVR0jBBgwFoAUUK/MB4cVR284xbRl0d6VqunfnMwwgf8G A1UdHwSB9zCB9DBHoEWgQ4ZBaHR0cDovL2NybC5zd2lzc3NpZ24ubmV0LzUwQUZD QzA3ODcxNTQ3NkYzOEM1QjQ2NUQxREU5NUFBRTlERjlDQ0MwgaiggaWggaKGgZ9s ZGFwOi8vZGlyZWN0b3J5LnN3aXNzc2lnbi5uZXQvQ049NTBBRkNDMDc4NzE1NDc2 RjM4QzVCNDY1RDFERTk1QUFFOURGOUNDQyUyQ089U3dpc3NTaWduJTJDQz1DSD9j ZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlz dHJpYnV0aW9uUG9pbnQwgeMGA1UdIASB2zCB2DCB1QYEVR0gADCBzDBMBggrBgEF BQcCARZAaHR0cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS9Td2lzc1NpZ24t UGxhdGludW0tQ1AtQ1BTLVIzLnBkZjB8BggrBgEFBQcCAjBwGm5UaGlzIGlzIGEg Y2VydGlmaWNhdGlvbiBhdXRob3JpdHkgdGhhdCBpc3N1ZXMgcXVhbGlmaWVkIGNl cnRpZmljYXRlcyBhY2NvcmRpbmcgdG8gU3dpc3MgZGlnaXRhbCBzaWduYXR1cmUg bGF3LjB0BggrBgEFBQcBAQRoMGYwZAYIKwYBBQUHMAKGWGh0dHA6Ly9zd2lzc3Np Z24ubmV0L2NnaS1iaW4vYXV0aG9yaXR5L2Rvd25sb2FkLzUwQUZDQzA3ODcxNTQ3 NkYzOEM1QjQ2NUQxREU5NUFBRTlERjlDQ0MwIgYIKwYBBQUHAQMEFjAUMAgGBgQA jkYBATAIBgYEAI5GAQQwDQYJKoZIhvcNAQELBQADggIBAHIHWE9BG6AGAhFngTAT KHLed0Hk1+nUUplgpdDB/Ysj5eKyd6i0M3eAEtd5hFjuCBAzZwV5JQEfUQ0Cdqpf nEwG0IzlOeUkmbaBHRtGQalgJZlqYFcr6Wqr5VYF1d3SlaW6o5T3OJUDm6dG2o2J 93OK5aYH930ied4kAebt5Z1U5RZUBS/DANks3A6MHNfbYKanasGeTX5IRA2TpST9 /swvHAihYWFZuRe74d8UuF7ASXf/ierF+/aaCY5htZ3Pqi+tTjUKP5QnO0S5c5b+ R1AUCh02d+XXBMrAtI8BOkLYkmi9LwV4dgXsYZdPsuRHDe3flbJlepxO2t8mQ09m Vo4BOSG6TxwyGOxtsKo/oShFo1FsJwDO7h7s80ueRXG4dCpXl7Kl/LUxz79iWitp QkEwPJp0aOyghqqLS31YvBUBuMqsgRM3T/FUk2zE3VHlXyKFWKjhed4MFeGLqgh9 sjqSv4BNQar+ovgVCEbhtqh1bsNmpFljmYSGTKvjzr+KCHY27xvPCHNvbFAleY+u 1TTj7RHeroLu5vAUd3kanCsSYmDADAu6mOoTSNcN9JfqLbBjE8pQlUOz0imwKTIh zlTU94oHxlorNgvE1ojqnivGtRMYHFw6T6GRb6hoFJxMBsfEaib6rjSHZEANsaKs LTVhkFps6f299VNAZTDZDgs8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFzCCAv+gAwIBAgILBAAAAAABJ/vSI2QwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTAwNDE0MTEwMDAwWhcNMjkwMzEw MTEwMDAwWjBZMRgwFgYDVQQLEw9UaW1lc3RhbXBpbmcgQ0ExEzARBgNVBAoTCkds b2JhbFNpZ24xKDAmBgNVBAMTH0dsb2JhbFNpZ24gVGltZXN0YW1waW5nIENBIC0g UjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD8k6EclXGMvwf0+Qj1 5+ZwJ3O900E7S49V6pX7d665Noa5LSFbENPI1YDUilCR052Z+xkIaZYkU/Bd46NO kaEomDzFgBmC/AFdiuRrcDqWNjKuvwFixNajso0VQNLdxf3XPrUxCuxT73FvXucr P20ZYKtMqJhKK4y8ZUQvoGrf0C6d+dmTPrxLf3taXXMIr75RsZoRwgj4FsUz+2a8 z/262c2zQC1waMrS/Nc8K468iDchEJ65UEX3LtCkHI6M7W6N4adCtTTPaOFhS12d f9J9e9eC7hjEJEcKN1l1ynTF/DGeA4u7DGULrYDGMq/T+FGr/Kd/GZzSg7f3E9pY Tm39AgMBAAGjgewwgekwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0OBBYEFIxaYiyqWtLT8genoZZca4v+n7NlMEsGA1UdIAREMEIwQAYJ KwYBBAGgMgEeMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2xvYmFsc2lnbi5j b20vcmVwb3NpdG9yeS8wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i YWxzaWduLm5ldC9yb290LXIzLmNybDAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj move4t0bvDANBgkqhkiG9w0BAQsFAAOCAQEAKQHfm4Vd3LNlJDsiD41E1M93XoAQ W+SPvs04Kfj8HHBjXPpICm7kcy3laqzOeQNWn+gCeQ2xJ4TquhlLRsfZWX/MjJ/5 SRYFe+JbPMvLj+ewJFRX8bk+eR6jZPkkMLs72sTpOfqB8h+Cr5jyZpiSCnBjY5ib a/gTRidSkwkSZPJfJn1Ph0Emcqzg0wkGdWR9f9xccCkQm7XnCIs7Bn+jks4J0cyo MXMfnuQ77WlJi4TYky9HPE3m85frRZWbZS1LcY+QMLy7giEPvGMiNCiIKJq5X6f1 /D385PMbJTDR6VrpES3q4asOHcU72qgkNf9e3xvoeTtBOV63hjlLjwQ5NA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZDCCA0ygAwIBAgIIKSY1fqXKEz4wDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTEwMDQyMjAyMDgwM1oXDTMwMTIzMTE0MDYwNlowgYox CzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEtMCsGA1UECwwkaHR0 cDovL3d3dy5hZmZpcm10cnVzdC5jb20vcmVzb3VyY2VzMTYwNAYDVQQDDC1BZmZp cm1UcnVzdCBDb21tZXJjaWFsIEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkMcRZDNB2BlxC7SlYaCkiA3eTcQRh Lbri5nbZZZCtm+jJtbBkyv/JjszLZrf6hBtJK0Q8Xx4UDAY1SeW72x/DaLCqnrg2 WG8kKO51ksSZ4/261CXicikFUolHafc6nsMuOLCfsmY0koB2yWd1S2m/ZmswQh0S RxnT/y3zijCrlMXIqNcDWDr3VMD4FcUKfxcQW3kUL4soFDAVB9TnmZiRIAZ/duRX Oqwslo5t3hu3MgKAcLw/r3dvJKrE+GLvVUcn/s0TuZEu07Ae7g/lQ6Qvrosg0f0Q Yej3ajaxhD0EylFgaY4/xz6Pmm1WLqej7WlINr0PmFFt9B75Yst53/jVAgMBAAGj ggERMIIBDTAdBgNVHQ4EFgQUpqEXuOwGuj4hWo64KEDhUS1EJtwwDwYDVR0TAQH/ BAUwAwEB/zAfBgNVHSMEGDAWgBSdk8ZTi17Krz+fHg/lmZW8JPaUjzBdBgNVHSAE VjBUMAwGCisGAQQBgo8JAgEwRAYKKwYBBAGCjwkBATA2MDQGCCsGAQUFBwIBFiho dHRwOi8vd3d3LmFmZmlybXRydXN0LmNvbS9yZXNvdXJjZXMvY3BzMEsGA1UdHwRE MEIwQKA+oDyGOmh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1U cnVzdENvbW1lcmNpYWxDQS5jcmwwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB CwUAA4IBAQBflRDNkvlBqqBeuz162g7ZCP7rRFTIvHCHAEp5XNmxk9gF6ESZPFrD sXUK2XiDSBT6sxUqL0+NqdFPO56zsLXFbbHH5wePFwTFnirj7pipnjUhWHsxhnjY pOjtCr92aJugW9LC50tK3quty3hBaKQcWQRz1aJYdpoVXwzQcD+uwZTOPZ/Z0qFm qDTNKGsoa0cgYhEbSkzA+2JRQhqzoGmMyGiNjoJZCmyZwqEl38/zgY4Fzp7q/DkF mDwF7T224Ha+ciKhsSMOAiuOIZtdlZqNowNVeDyy7I9K0g/jerIZ0vM19FOZgXES +779pDAlZh2PHOXxsUrq56T7iA8DQuza -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYjCCA0qgAwIBAgIIYxv5DIqwLIEwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTEwMDUxODAxMzY0NVoXDTMwMTIzMTE0MDYwNlowgYox CzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEtMCsGA1UECwwkaHR0 cDovL3d3dy5hZmZpcm10cnVzdC5jb20vcmVzb3VyY2VzMTYwNAYDVQQDDC1BZmZp cm1UcnVzdCBDb21tZXJjaWFsIEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkMcRZDNB2BlxC7SlYaCkiA3eTcQRh Lbri5nbZZZCtm+jJtbBkyv/JjszLZrf6hBtJK0Q8Xx4UDAY1SeW72x/DaLCqnrg2 WG8kKO51ksSZ4/261CXicikFUolHafc6nsMuOLCfsmY0koB2yWd1S2m/ZmswQh0S RxnT/y3zijCrlMXIqNcDWDr3VMD4FcUKfxcQW3kUL4soFDAVB9TnmZiRIAZ/duRX Oqwslo5t3hu3MgKAcLw/r3dvJKrE+GLvVUcn/s0TuZEu07Ae7g/lQ6Qvrosg0f0Q Yej3ajaxhD0EylFgaY4/xz6Pmm1WLqej7WlINr0PmFFt9B75Yst53/jVAgMBAAGj ggEPMIIBCzAdBgNVHQ4EFgQUpqEXuOwGuj4hWo64KEDhUS1EJtwwDwYDVR0TAQH/ BAUwAwEB/zAfBgNVHSMEGDAWgBSdk8ZTi17Krz+fHg/lmZW8JPaUjzBdBgNVHSAE VjBUMAwGCisGAQQBgo8JAgEwRAYKKwYBBAGCjwkBATA2MDQGCCsGAQUFBwIBFiho dHRwOi8vd3d3LmFmZmlybXRydXN0LmNvbS9yZXNvdXJjZXMvY3BzMEkGA1UdHwRC MEAwPqA8oDqGOGh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1U cnVzdENvbW1lcmNpYWwuY3JsMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAQEAW76fwA8wBjh0wBk6KcxkZPPh3jbzi2OT9KqisljK0ZOpUQI+sgHydjy7 ecnNwdVtFp7acdOdcIPnREVVP6q7LggsdReN9/SYZAxQgTaBQGhTXJn1e0ZrklZ6 tTpWn8IzfUkYz0PJYtiZJ9okjENaIYQ3xK9Iz+n3wJaYs853+nql6ONXaJu6Db84 6aWZB8abJyeo1gfYr3W/0iSV/UjXFXmjaGzPmWgEWxSXsEtOOvSe+oknn/Z/L9B+ 3xcOSPAJ116rknMiK/vag3aD54JzxVdjmwDKjsnYeQ6JGO1WVDyPzRYbEXFtkaFq 3cG6zepDXVFb2Yzu4cd+io0d4qPU+w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYjCCA0qgAwIBAgIII5AVx/Z4gEYwDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTEwMDUxODAxMzkyNFoXDTMwMTIzMTE0MDgyNFowgYox CzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEtMCsGA1UECwwkaHR0 cDovL3d3dy5hZmZpcm10cnVzdC5jb20vcmVzb3VyY2VzMTYwNAYDVQQDDC1BZmZp cm1UcnVzdCBOZXR3b3JraW5nIEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/c8jCGiQh9gbKEungIHBYD6CzguTV o10soL09wMKO10oeYbh3c/J1Gt6R48WBxosjPBp22jAfLW4xofy6rUtqTVhH6CjV O8mhBsKWwkZ67G+85SrYgHAbcYHJRGm6ietIvZfirwyxpap4DIiSQCxD571X9zaI hY7y7V5eTDbkkUSLKOdBrrCnCJ3bPwsgQe8UR3OZeDTTkm5eErhf6F2Vo+y764Kr HL+21xT7f0Lkt30kBCoBFzBAOjtbN3yfZsjNQgYleVv6dOtz4ssju8I234M/9qiv n1Ebxom3up5uSAhL2bL/2ddPfeMWlK+sTX/VcsTkztZkD6C71RrexZiZAgMBAAGj ggEPMIIBCzAdBgNVHQ4EFgQUffiyTFQlCF1tJ8mrKwHDNXB5gGQwDwYDVR0TAQH/ BAUwAwEB/zAfBgNVHSMEGDAWgBQHH9LnnNrCbqJAtLB6UBBQdMTIvTBdBgNVHSAE VjBUMAwGCisGAQQBgo8JAgIwRAYKKwYBBAGCjwkBATA2MDQGCCsGAQUFBwIBFiho dHRwOi8vd3d3LmFmZmlybXRydXN0LmNvbS9yZXNvdXJjZXMvY3BzMEkGA1UdHwRC MEAwPqA8oDqGOGh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1U cnVzdE5ldHdvcmtpbmcuY3JsMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUF AAOCAQEAAEDMyUi9docIPn2K2htcTCFRShOwzyB+xP65pMDqn1o9jx1Hl9eqgfhl 9wp/LRoAh+mH+xyELI0jy7Cm5A/Thuwgl6200SMW8UW55ab8FErksIj/gVYF+FBq c46J7N3TS/1Ml7YmnlhZXB579/IeGtJjwXGdD09SQ5Ha+LNLpPsXspaY8Kdi8iBe csfCmgK5ahfSh800qnUQXNFfsrzlGG2DdIxzHsNCt8IaiFa5I0eIEuxKi+6wGh3O 61kzf2GAN9RlTNKXaNskxVL/TP23FsKw1kkm7pVsIUl4Y+g8VOaM/OJPjkB3s1/+ kKS+QvtvB4lgd9zC4b2mf48fPcEXqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWTCCBEGgAwIBAgIIC8/PN1nC9YYwDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz dCBQcmVtaXVtMB4XDTEwMDUxODAxNDAzM1oXDTQwMTIzMTE0MTAzNlowgYcxCzAJ BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEtMCsGA1UECwwkaHR0cDov L3d3dy5hZmZpcm10cnVzdC5jb20vcmVzb3VyY2VzMTMwMQYDVQQDDCpBZmZpcm1U cnVzdCBQcmVtaXVtIEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQDIJKKCLrO1P8lH9elhDSFnhkVZBtV9stJEkM6M S4RQfyGJSYZW0r8tzUAoUaLhI2P60R8Y2Dpofzm78QfvDVcleGSCcfaPf7BElECA eb7bNg5ER6erP99pwDXyKs8nh1gCZrvTQhqZY2Ezi9g/SpuE0NhhudBFrGssaRQU tyHijlx5oHgq1yGhZ7cP0Zr6ulGIV8sGvq423NJUsjmt7iNFVEwyBKsmBGMnw3fV 371mfxbZQkmNpOY93qOzRzr+3yRnwV9tqh6ZwJ7g7naBqMKpZnSIwd+1CxkrZmYA GW6tLoIUzz57JA/LVEZb/5NFCQvodE+/6SeTfgl+v8XWXFoK2p57/D90gv2cMjVX QW7b9DD1INaNg+NLXxqWiozzxWte9S3IjJA7Cf7D7uLqFPMyBD8RqGN1u2h/DUnK UQL1dFy++Yovl9chQ67Ga6Ma3x1TVSuCf/gElTGBPzEFenbRUirlgK3n5/XxWe9G BA9ZjQiAkE37+6U+smEossQyEyy/qbBQuwZ9qy6fXbxYJLK5zm2HbxBONOWmWS8n F6aeUUI9D+WU0M0L42xAqdnSm60N2KKAdykGuDjZsIgQ1bxEJdGOYdw3seVuB21G 6arJZfhnbtwptgfTmtxH0yLgKQDf+t0RWuIw2S79uhOYBqQ3oDypzFiWa14HD3c8 BdQjfwIDAQABo4IBDDCCAQgwHQYDVR0OBBYEFLzdRrvkokL9idHmeR/XHkGpR/tQ MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUncBnpgwi2Sb1RaumZVIRJ9hF rGMwXQYDVR0gBFYwVDAMBgorBgEEAYKPCQIDMEQGCisGAQQBgo8JAQEwNjA0Bggr BgEFBQcCARYoaHR0cDovL3d3dy5hZmZpcm10cnVzdC5jb20vcmVzb3VyY2VzL2Nw czBGBgNVHR8EPzA9MDugOaA3hjVodHRwOi8vY3JsLmFmZmlybXRydXN0LmNvbS9j cmwvQWZmaXJtVHJ1c3RQcmVtaXVtLmNybDAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI hvcNAQEMBQADggIBAGaBPQsQqKcobhd3QAn23t9MBfZyFhWXW9bhZNSiqESK7lGw pLT7tb+o7dXJjNMgr3kZTGL1MyTXMPjp6a1S2ZdCkKBrdw/LHGkkFFvJQKDwYtmw HlJHXnvSvo+pHlCXeUsnnvGGN1uO8vN9rP59LEyITlbWP0sdSJ1MJkRk7aRVcIWn g1/EYcTnOu5PQx0PSh33666iNSMixmUf+auyF5hF3kzu9o8KLbSb1wsR7ThzhsoV NIpStx6rEtlFFOpR4oLa7neZPv2DqH1DNLstKs7KsOLMrgxN6vCO4L+I+EpwUphG lveh+/5GXNZnEpK4doWLA0zDvyHo84ktk1p4zqOt3MXtRjNWz0HXHVQ0Acgxg6G0 NTGooZ36WUwXuTpmhcpXDdF2fSQCSqitIPZpkyj02s3DEEtMf1yiDDd0Q62XAMb7 yAdT2fksZ93iO71NWhjhgJwXvf0X/RrjFc7XnfDuS0pZKb8MAQilJGtDS8Yp92fZ YUEPdojmR74Nz2MS9QRNUivdJdFnC4eiOYrRo1IhyONDe3EAo8XkAMi9I/ctcF8m 9jz3BKiLFDnVYi6S/3GORGXzjzPItz8YGAei8cIZckK1mVUUBHdynZ7Z5dbk7oHA Md/n6P40Xc0dTJuNbchtXb/3vzz3wc/CxZsM0/56vxX9F+yh1AU/XY56z3Io -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDFTCCApugAwIBAgIIEHyqEuzWjFQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ cmVtaXVtIEVDQzAeFw0xMDA1MTgwMTQ4MTRaFw00MDEyMzExNDIwMjRaMIGLMQsw CQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxLTArBgNVBAsMJGh0dHA6 Ly93d3cuYWZmaXJtdHJ1c3QuY29tL3Jlc291cmNlczE3MDUGA1UEAwwuQWZmaXJt VHJ1c3QgUHJlbWl1bSBFQ0MgRXh0ZW5kZWQgVmFsaWRhdGlvbiBDQTB2MBAGByqG SM49AgEGBSuBBAAiA2IABMG7lpQW6KCRa0F08QvCChRc+0tN9z9QbOFDq3X7/2hS 4oCHzgAa2TAGTAb/yysYV3AIZwxcN19DmfLueos35w3XHxshgH6HadrmPmAgF5it /izFoUJpCsesqECqTiutuaOCAQ8wggELMB0GA1UdDgQWBBQBBy+KEywCDqBYBkui pr4IIn8mrTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFJqvKXrAETU1JlEw AMNq/kDVrtY8MF0GA1UdIARWMFQwDAYKKwYBBAGCjwkCBDBEBgorBgEEAYKPCQEB MDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuYWZmaXJtdHJ1c3QuY29tL3Jlc291 cmNlcy9jcHMwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2NybC5hZmZpcm10cnVz dC5jb20vY3JsL0FmZmlybVRydXN0UHJlbWl1bUVDQy5jcmwwDgYDVR0PAQH/BAQD AgEGMAoGCCqGSM49BAMDA2gAMGUCMDUYefycOkhRsHyEzock1Azmya7m+kzA+Hfw At7oMsYdOwnNx3sWY7BIm3Z/ZgSxdgIxANDKKBAEejiRfvdjaVa842m5ufhj97oY 592o+UBODYMQ7AE3YnFxDfW7OEh2g83eow== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGbzCCBFegAwIBAgIQAKZAQ5cBE2dWe8qWBnpU7TANBgkqhkiG9w0BAQUFADBJ MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQDExpT d2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjAeFw0xMDA3MDUxMjEzMzVaFw0yNTA3 MDExMjEzMzVaMFcxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcx MTAvBgNVBAMTKFN3aXNzU2lnbiBQZXJzb25hbCBQbGF0aW51bSBDQSAyMDEwIC0g RzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPWbTxjDlowAYuwPYj IVxIyxypG3ub1VcX/9H4235YhTFEURY7r/qjL6vwrm1LvZjdRhGn7VKXRuaSQDCx trFfNb1/gh2pgxcWzNyWK9l6SUdLwlK7FjKANGu3TSNOlJ/Z/tRbM3Fe2HZ6B6FS Bp8V2Y+G7VZ/TkMXpuxJLe4tIayBWwf4d37uTaXmvvjNLEfEZW79fa1Qg9h+fytr PPME5MbEXpjCqkgC3oKR5MsZaMV0mfsdsr5xFFXxbXssicwOwS/fLgEe4EglvL+v iU7sjAkSbwV9Bb0J97UJvl3Lkn1jIlmGHYzWbx9JOwVRAjlPubcXj0xPsPPhPIlE 7wYtAgMBAAGjggJDMIICPzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHQ4EFgQUStQ7hu8QU46v5Ex3WUeC/QARdogwHwYDVR0jBBgwFoAU UK/MB4cVR284xbRl0d6VqunfnMwwgf8GA1UdHwSB9zCB9DBHoEWgQ4ZBaHR0cDov L2NybC5zd2lzc3NpZ24ubmV0LzUwQUZDQzA3ODcxNTQ3NkYzOEM1QjQ2NUQxREU5 NUFBRTlERjlDQ0MwgaiggaWggaKGgZ9sZGFwOi8vZGlyZWN0b3J5LnN3aXNzc2ln bi5uZXQvQ049NTBBRkNDMDc4NzE1NDc2RjM4QzVCNDY1RDFERTk1QUFFOURGOUND QyUyQ089U3dpc3NTaWduJTJDQz1DSD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0 P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwYQYDVR0gBFow WDBWBgRVHSAAME4wTAYIKwYBBQUHAgEWQGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNz c2lnbi5jb20vU3dpc3NTaWduLVBsYXRpbnVtLUNQLUNQUy1SMy5wZGYwdAYIKwYB BQUHAQEEaDBmMGQGCCsGAQUFBzAChlhodHRwOi8vc3dpc3NzaWduLm5ldC9jZ2kt YmluL2F1dGhvcml0eS9kb3dubG9hZC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVE MURFOTVBQUU5REY5Q0NDMA0GCSqGSIb3DQEBBQUAA4ICAQBZiJ342eaawsEV3jtv keLC59c779N81fN78DAmepdcXjwGaHn6Zo5QCCIdJZ7dqfGiRUnfVT1cvV5ISinx kkJPHMBschmJpNCUVmXuSDVHDMblcqpt4SgkMx9wR3NbFqi2+NggudCLHP5tK7sc sglQn0+uC6acAUlcJUGfe9q1YydcLHq5SLvKNPX2L2aaAIEdHOfmWq2AwlEKEiSq M30aM5ZOs5pdoRV+laHv5vlBLoo2iT+X4x7AkZW+I+M6VqTTF1XAsrhmeg0sIl72 isDv27cbcQRR7BCVq1n0yvSqx0gIO29FT3U+CoUSJlDKLZbOidjkmhCGNx7SUE/r FgykHhNiVRE9yolFopyhywKCB/5NjeG4CjCiZx57JDvPLb4maxQi3mGPeTB8x0DX 4jGH2/V0G+BYqBYyGH9JWXcFOoF5VG6zKFHjwJEHoDIGpxasjhnXZSQ9lFeZ5FlI kiD5H0DvrvJZP5W+5Q/gBjSbC8BE7LtxBB9A62qFSMC/3jwWjl4o53x6mOgrZ5gb z35mW0WmU3kKRYYa5XzR4kwqwO248ZuQPf8wm/7V3pSkv4b2YDoDFbgA026LHycc X7Pw/V+aKpYNuG0MZrn8fw8wNMsTXhyObOH3EU/+lBqoUNSiy10GAabhwD4dCU6r nxY8lNMfBYFnBfKPhDjtlL6jpA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHQTCCBSugAwIBAgIQIUXI2bEFUA5MvqVCVTrywzALBgkqhkiG9w0BAQswODEL MAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMRMwEQYDVQQDDApJemVu cGUuY29tMB4XDTEwMTAyMDA4MTYwMloXDTM3MTIxMjIzMDAwMFowgacxCzAJBgNV BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxTlpaIFppdXJ0 YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDSTFGMEQGA1UE Aww9SGVycml0YXIgZXRhIEVyYWt1bmRlZW4gQ0EgLSBDQSBkZSBDaXVkYWRhbm9z IHkgRW50aWRhZGVzICg0KTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AN+nfomB85viwoOjLpT8shBiWUJWJhRoGzHd6yz/6O0ZK9bHrbRdScXLclUA/TnI d2tK8D2WX4LacNQxFap+ZNlXVyORDE6lqDY/3WQg6I2yPGjeCtnJUo3gGUqe6JLg HqDPTemdbtzu3ICYfgYQ43SFM/NNQRbeBuJn68rkITxsj/x60lPsFwCYLDg+TqjB ZSdVTOvjO1rO8+JnVsdnjW9rrpSiubY1Dber/dnWntCg/CWSZg8BXhdAW8N/etZ8 suOTwnKbOTBNOIu2lWDr7JsqtQxViDkBlZCIRnfffn8oQzNLPpOUNbQM1HiwnoEu T8i9xK1XNoJV/W9FKl7xSNJXyrOPgstGd6swXcnsMCufnncXUlBcLP/5XNeFX1sz Yl9bXPOjhFLhRAQUzXjGY72wCMUV8p63g5z0pTHpNCVmJFDR6ionKEtU0zvqAfZn dLuoA+wzaUJGss0n08It4B7E02EVjl/j4/9llooFu/rGIkjk200cZq8V3vFsUbEi vbs/s4quEXMBePOFkOS0mcKM8b+dcinF/2B5/38Xfz2Zry2w91HzK5F7CovDeVQP r3mOiVH3tfzd+QMZg8qw3pVHub47BjqgujPy74C6BiCEaijtr9vgvsePaC3sG1Zy ZK0ISBbWZkvglvXcyQoCxNAT2GuBU4rGyM6eXDJXDo85AgMBAAGjggHZMIIB1TCB xwYDVR0RBIG/MIG8hhVodHRwOi8vd3d3Lml6ZW5wZS5jb22BD2luZm9AaXplbnBl LmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYw LVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBBBgNVBAkMOkF2 ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAxMCBWaXRvcmlh LUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFKQXHU5l1++HlS5/jrh1ywWL04x9MB8GA1UdIwQYMBaAFB0cZQ6o8iV7tJHP 5LGx5r1VdGwFMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsGAQUFBwIBFhlodHRw Oi8vd3d3Lml6ZW5wZS5jb20vY3BzMDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcw AYYbaHR0cDovL29jc3AuaXplbnBlLmNvbTo4MDk0MDMGA1UdHwQsMCowKKAmoCSG Imh0dHA6Ly9jcmwuaXplbnBlLmNvbS9jZ2ktYmluL2FybDIwCwYJKoZIhvcNAQEL A4ICAQA3qh2Msr3tOt6jPt1QYuv8ecbxkHCuxvqnFQSDbp+dRnd5GKJN45emgOkU GKQ6Aq68VSO7060r6PuE0EZKksH9ryRu8x9hSEVSPvgelC95ITxstkM7M39xc1QH tBxkqyHtooDIY3vySOcbFy0AAo/HfSr8HoJJjlDm/Q5MROKvpTBtOhoqLkTHe1uf DtrzZsaCiaozmakGgMDSpipCqI9dLNzdvaXyEbt1gIDIiiAjGv4p/ihJyYxJz0Li D/4OODQ4tqpdvtt6a1lL6BHwoahjaF+5N+/gUlNYVcSDrMOCKBIvg2hmj0lt/UaL nxoL63+D0yAQexCBal3me3/sYHL7WgWrgpKNmqYh+eak5Vnbm4YMcGtkbhwL1v/U zUe4gykBTgKerzAlGCIMN42HIvvJELCZiCrNPkuUnGwM1gEfkBC5jE9LZizS33OO uDhCyrDMRUjnz20BmGwJZ4btNLr5D6/IENsOYWhzfxVIC6t6RgZK9vvBQLqTKVdu H8u9Lz0p3IcrKRSTfxRrVUeTJ5rytX24OkijIMplPohqvjpOZ5QiOoY1GPPgumxO yFHB+7lbc48S5PB/YtoDSHEqpuYJlz5IPbXURkJkyn1YSdrw2lrB3OORqoOKzYdz FArY7jwExjJRvqXTJUlxJ1HpeCZap+lh1m1pH4kd7hxS/bdhiw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHQTCCBSugAwIBAgIQcusrrX2LZeNMvqW/nyrD2TALBgkqhkiG9w0BAQswODEL MAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMRMwEQYDVQQDDApJemVu cGUuY29tMB4XDTEwMTAyMDA4MTgwN1oXDTM3MTIxMjIzMDAwMFowgacxCzAJBgNV BAYTAkVTMRQwEgYDVQQKEwtJWkVOUEUgUy5BLjE6MDgGA1UECxMxTlpaIFppdXJ0 YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDSTFGMEQGA1UE AxM9SGVycml0YXIgZXRhIEVyYWt1bmRlZW4gQ0EgLSBDQSBkZSBDaXVkYWRhbm9z IHkgRW50aWRhZGVzICgzKTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB ALjXOOxJmjkG1L0lIomLiTkQMn+WxJmZ/31IFb6jQkIsa7RwwGPTCkplczdtfwPM h285cOMU1A3fotDs1VxqgUmGHoJiBSmDjY1VbLFJ/N9XCywKJfEFmFp2xcaIqtMM lu7ObemLsooyBINRO9Kqeuid7SwAEqgICpNtcJioy6Jr508EM5H3gqr1F9LPZGLQ bwbZBHsggcW96B0hIstPuWvBqB9IyP3Lg1k6Bzj0CfHLw/8cLwA5tpW1JY7JGZ1F bClyv9/MXhKRXpfYlnviMjh/KOGcWhGJpWqnWVR6VW61LYKrE8GHdTc2EykaLhx8 nLq7X2g1GQlOMoBQ26kpy3VX7LYtJvij4PwljAoDddylgaidkxdtbKIHj57qxZ5x GLNvT++85jvnfJSTpaJKR+p5cS6NQzOqZdMye++BXbaaxhZRK3GClaXZde3GoPZk bsCQNVJ2/joV+at9jpjoJ+dUAZosJ5Gs9ung+g0vCCFxGPa+F6gC3+Bo8TJ66rd9 WtUZPiAvjjER8iR2mIZF1LaT/YqKYjA73a6ZbOrZLN+wVL19Od7Ml/WX7YtvWFYP mFp6cxZ8yhCxxNZ5qsq8XhySMhzf03PYfVvZmmUjjNyMAVXRnGNtf/hhPrnyCJQ4 fVKVb3bwuEitaLhW5pzUiqXiGtnj29S443FuvfCLWLFZAgMBAAGjggHZMIIB1TCB xwYDVR0RBIG/MIG8hhVodHRwOi8vd3d3Lml6ZW5wZS5jb22BD2luZm9AaXplbnBl LmNvbaSBkTCBjjFHMEUGA1UEChM+SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYw LVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBBBgNVBAkTOkF2 ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAxMCBWaXRvcmlh LUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFOyyBPaRvYtSOAaz9AB/sTfbvFGXMB8GA1UdIwQYMBaAFB0cZQ6o8iV7tJHP 5LGx5r1VdGwFMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsGAQUFBwIBFhlodHRw Oi8vd3d3Lml6ZW5wZS5jb20vY3BzMDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcw AYYbaHR0cDovL29jc3AuaXplbnBlLmNvbTo4MDk0MDMGA1UdHwQsMCowKKAmoCSG Imh0dHA6Ly9jcmwuaXplbnBlLmNvbS9jZ2ktYmluL2FybDIwCwYJKoZIhvcNAQEL A4ICAQCXEEinKwcz6xbNrUXfecjMeko7p+taEj1dwTfURUFTQmzwn/oaBWK05AdK pJJdCDgmEtYJEz9HV1oaH5s8Ur07O+qbl19AGX+LGWZ6hRYQ17J/c4hsq7abYhGz XVHslI6cVQb2If3lMsZkKU34DAndyS0A0yvQMDwX5f1NDUwrPnyj1xDZOW3QbKwu BU+N1/kEbu5ldJGSylNud90QfFeUEJ9YhQf/zQe84YtZ6PZo7yG0CkFislN33zEE DuNODzGSng27sSa39HcEX8R5YdoAdNfL6zBJD6J7bnqKl2rBXLhM8lRh7Az9DMAa SaJZaXx6NyC5Zwym5zXlAOkkgfDGrDUkux9EzcPnXPRQEzvphsizxwXROq27wSTU 0TM1xqU6oShqeqj39DC0dZWx1XgbPc+87iHQftxIfYI9dgoLYhqvSHg3nSezcpdk WSxkyHZYj2eBVSjNf1BmNC+g6QgJ5lAODmD3tlCFe7WssIiSRKaZVYesj8wmF6db ux4i8RryZR1jAEiLOgGu0s0r37OfMBQOPOqbDiQqyNa4fF3LzGrhjuI/R0XLVn6T rV1RBOnLOZTqrCBRcAT8mx0vPe5GkxBHjdw0S5NNaYUM+wWcdRp7eFM6gOFfjbsK SDZDdY4JZgXHxUFeQzNuRt/OBQKy79h+TECcVHzS/i3drHsG7A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHPzCCBSmgAwIBAgIQaTqWZ4PiO99MvqbQ2VQ/1zALBgkqhkiG9w0BAQswODEL MAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMRMwEQYDVQQDDApJemVu cGUuY29tMB4XDTEwMTAyMDA4MjI0MFoXDTM3MTIxMjIzMDAwMFowgaUxCzAJBgNV BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxQVpaIFppdXJ0 YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDQTFEMEIGA1UE Aww7RUFFa28gSEFldGFrbyBsYW5naWxlZW4gQ0EgLSBDQSBwZXJzb25hbCBkZSBB QVBQIHZhc2NhcyAoMikwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDV 8HtuuCAU8strFZHCqPk7F2zZbjpzHhdTJjoQ+VHAINei19bWmTmM90ehlzjQKsy2 vGgLT5Z6feJpx687p6aNYvMW/gvtrkvgyTd0TQJn/xO69VYcUwrCriA+zT4QZdRK fS7op9cO/tn1Smph3IvlLxyf5MYcDHXyix5PYaxDf8j4QJ8AeAx5lQNUMn6rhq5t C8Qx44IDvX6PIhqxPk0tXjJWbVFWXpewRDNhLYnnzQI4keDWq+BwUwAin0jx8Pkl Iru5t9pDTraMVuqzfwt8hp19YOo/Lz0vf55E+BH4DESdeiTDkX3QGHcj946XqJ/8 3UZIAHyMcBBSIRu+RaWGU/uYz/CnM7cyS2espqh355VL8nARms8UODLn8YTrfnJl dcXHK2PYzRi9MibuI0YHO+MyggX86OJmToZT3jim2jrrO1+qSqrlW3hb3eSoNfYs tISKGALyoMo03ZH5U1lK2a5LAPHdOCd88GNFg08cOQpyi3S3TEm6wO7lvM91zXDQ wjHH8EYoQjaXyl8AaP0PrBI2HzJBGNnvaRgOI4kzJ675sLIry6hAF0ExVjJP9qKG ISZnwpwynAxlrAFb5NlK6h2IUO7DPO8pWT1c8CxEu9VOp5m4dCUUkoDfguRfA6hk UmzU5Vu9j1VPpAN2X7wGB/4CffyrqcEFe8HuaY6BLwIDAQABo4IB2TCCAdUwgccG A1UdEQSBvzCBvIYVaHR0cDovL3d3dy5pemVucGUuY29tgQ9pbmZvQGl6ZW5wZS5j b22kgZEwgY4xRzBFBgNVBAoMPklaRU5QRSBTLkEuIC0gQ0lGIEEwMTMzNzI2MC1S TWVyYy5WaXRvcmlhLUdhc3RlaXogVDEwNTUgRjYyIFM4MUMwQQYDVQQJDDpBdmRh IGRlbCBNZWRpdGVycmFuZW8gRXRvcmJpZGVhIDE0IC0gMDEwMTAgVml0b3JpYS1H YXN0ZWl6MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQW BBTGr5ZoUL5voeUU3Lmdlz2Nc+d+mjAfBgNVHSMEGDAWgBQdHGUOqPIle7SRz+Sx sea9VXRsBTA6BgNVHSAEMzAxMC8GBFUdIAAwJzAlBggrBgEFBQcCARYZaHR0cDov L3d3dy5pemVucGUuY29tL2NwczA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGG G2h0dHA6Ly9vY3NwLml6ZW5wZS5jb206ODA5NDAzBgNVHR8ELDAqMCigJqAkhiJo dHRwOi8vY3JsLml6ZW5wZS5jb20vY2dpLWJpbi9hcmwyMAsGCSqGSIb3DQEBCwOC AgEAkx3edUCTBGZHCSn9QcOxTT2OvNLgmf/7NThbrPJnQ4FvoowzZ0pf0crubbWl lyEKDAPUnEfa9w9JCCj9OYoOdG75TEw588qs1CacrNTZJR3YGzH2JRT63IBrhe5h jKyAgWl0YoG0theqQr8ry12sACPe+VJw6MA1/34SZTb3KW/t1Qw8TXSM64ldDp3s pfomG51SkE7mh/DYAxr795PZEDvorEox7/TYd2w3rBx1iXmk4CsuCfYnhitbePBM JMPuKfQj9Onqvi7cYByM64W9R8dkgCY7604S8C7ZSXDtNHvCvQmMvRPpsuOW7AuL GAk7zh2Wz8MtOMMMfBNm/Ff2UUZxirt2JdL9UkmwhDSdeebdH21OJria9tmK/AMF ms0YCh+MD+ILaWAudyj9AwDjM5wvzYDCIg2UV2DOEpMq+kylA20s8WmjhsiQ9+Qq BETYKtbJ7pGgcFc5R8faSugeM+AsGOhm4I6mUTaqUmdxVze8Swl2Tx/hqm1k77+I yowzr274KEMEADm2NHQvubuR8UZPzT4VADcIp6qqeiys7a2+FQCw6E5eX2Y4qbzE FN6vnBSzwtOjl5WF/6JdQZj/oPafJ61YkAytx+WLL87xlIvtqYsmpsly5w8iZTz0 rm5dr147DuTSL2xZwemFBuhEMPh5DW+fzunqqCzxYCyjpVM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHNzCCBSGgAwIBAgIQJMXIqlZvjuhMvqcFXOFkpDALBgkqhkiG9w0BAQswODEL MAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMRMwEQYDVQQDDApJemVu cGUuY29tMB4XDTEwMTAyMDA4MjMzM1oXDTM3MTIxMjIzMDAwMFowgZ0xCzAJBgNV BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxQVpaIFppdXJ0 YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDQTE8MDoGA1UE AwwzRUFFa28gSGVycmkgQWRtaW5pc3RyYXppb2VuIENBIC0gQ0EgQUFQUCBWYXNj YXMgKDIpMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoIM7nEdI0N1h rR5T4xuV/usKDoMIasaiKvfLhbwxaNtTt+a7W/6wV5bv3svQFIy3sUXjjdzV1nG2 To2wo/YSPQiOt8exWvOapvL21ogiof+kelWnXFjWaKJI/vThHYLgIYEMj/y4HdtU ojI646rZwqsb4YGAopwgmkDfUh5jOhV2IcYE3TgJAYWVkj6jku9PLaIsHiarAHjD PY8dig8a4SRv0gm5Yk7FXLmW1d14oxQBDeHZ7zOEXfpafxdEDO2SNaRJjpkh8XRr PGqkg2y1Q3gT6b4537jz+StyDIJ3omylmlJsGCwqT7p8mEqjGJ5kC5I2VnjXKuNn soShc72khWZVUJiJo5SGuAkNE2ZXqltBVm5Jv6QweQKsX6bkcMc4IZok4a+hx8FM 8IBpGf/I94pU6HzGXqCyc1d46drJgDY9mXa+6YDAJFl3xeXOOW2iGCfwXqhiCrKL MYvyMZzqF3QH5q4nb3ZnehYvraeMFXJXDn+Utqp8vd2r7ShfQJz01KtM4hgKdgSg jtW+shkVVN5ng/fPN85ovfAH2BHXFfHmQn4zKsYnLitpwYM/7S1HxlT61cdQ7Nnk 3LZTYEgAoOmEmdheklT40WAYakksXGM5VrzG7x9S7s1Tm+Vb5LSThdHC8bxxwyTb KsDRDNJ84N9fPDO6qHnzaL2upQ43PycCAwEAAaOCAdkwggHVMIHHBgNVHREEgb8w gbyGFWh0dHA6Ly93d3cuaXplbnBlLmNvbYEPaW5mb0BpemVucGUuY29tpIGRMIGO MUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBBMDEzMzcyNjAtUk1lcmMuVml0 b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEGA1UECQw6QXZkYSBkZWwgTWVk aXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEwIFZpdG9yaWEtR2FzdGVpejAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUwKlK90cl h/+8taaJzoLSRqiJ66MwHwYDVR0jBBgwFoAUHRxlDqjyJXu0kc/ksbHmvVV0bAUw OgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYBBQUHAgEWGWh0dHA6Ly93d3cuaXpl bnBlLmNvbS9jcHMwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8v b2NzcC5pemVucGUuY29tOjgwOTQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2Ny bC5pemVucGUuY29tL2NnaS1iaW4vYXJsMjALBgkqhkiG9w0BAQsDggIBAMbjc3HM 3DG9ubWPkzsF0QsktukpujbTTcGk4h20G7SPRy1DiiTxrRzdAMWGjZioOP3/fKCS M539qH0M+gsySNie+iKlbSZJUyE635T1tKw+G7bDUapjlH1xyv55NC5I6wCXGC6E 3TEP5B/E7dZD0s9E4lS511ubVZivFgOzMYo1DO96diny/N/V1enaTCpRl1qH1OyL xUYTijV4ph2gL6exwuG7pxfRcVNHYlrRaXWfTz3F6NBKyULxrI3P/y6JAtN1GqT4 VF/+vMygx22n0DufGepBwTQz6/rr1ulSZ+eMnuJiTXgh/BzQnkUsXTb8mHII25iR 0oYF2qAsk6ecWbLiDpkHKIDHmML21MZE13MS8NSvTHoqJO4LyAmDe6SaeNHtrPlK b6mzE1BN2ug+ZaX8wLA5IMPFaf0jKhb/Cxu8INsxjt00brsErCc9ip1VNaH0M4bi 1tGxfiew2436FaeyUxW7Pl6G5GgkNbuUc7QIoRy06DdU/U38BxW3uyJMY60zwHvS FlKAn0OvYp4niKhAJwaBVN3kowmJuOU5Rid+TUnfyxbJ9cttSgzaF3hP/N4zgMEM 5tikXUskeckt8LUK96EH0QyssavAMECUEb/xrupyRdYWwjQGvNLq6T5+fViDGyOw k+lzD44wofy8paAy9uC9Owae0zMEzhcsyRm7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHHDCCBQagAwIBAgIQT9hLGWcHRO9Mvqdq4AgNdzALBgkqhkiG9w0BAQswODEL MAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMRMwEQYDVQQDDApJemVu cGUuY29tMB4XDTEwMTAyMDA4MjUxNFoXDTM3MTIxMjIzMDAwMFowgYIxCzAJBgNV BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxQVpaIFppdXJ0 YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDQTEhMB8GA1UE AwwYQ0EgVGVrbmlrb2EgLSBDQSBUZWNuaWNhMIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEA1dfQ3DEQllKWjQdltruTFccQzHMYzlpvYQJxfWvC7T7cU/jD r56iWo+MZLybgynQah0RWMMkqyFIp9HNxSXiDSQiIaiWWxliuccQUWfEviWHyIye DcnUMpuyBO1wQib3B4JtGpujX2O/PLXzj9uyL9LyN18bvjcxzR7/+8mZiJW3MJ4N K6CecD+rt7FMPc/lSrejkcG60v+sYrQUxZg4nPKswjOJ2NrZ/L/m9uUa9+BPSZCq dBTeeiRoiNBDmLwtdDllMtY2qqxHPrm5amX1T8j0HFouNBRlzAcyjeFSDVHWj3d0 zt80H8TQwPpREKd9adEE7EWWBAmNXV2YdQ+jH10YCFr3buWCAih0PD/ZriUlYY+o nTEkgq17PSxJPqL9HroepaM/G5KVU2FHtq96Hf7opWoBy3aoowHcabUeHkultnXX aTfJRNEGj7zpgjdL7TnfyfF6Kq13VnqpmLqpTKOvOLHESIKI7qPsst++K1NGXtQK FzsYrlqvkCIFvmDcpdrmqfbIfFSPODVJg19CgrRAahQT3cfX7jEcVBvhzVwG8A4P ezbYc+4IcUsiEFv6xyFrdBikhLE7XAzrn9a4EoKBS9tBqPSKEmmtJ0+hFoGH2khH YukKx4U0CGVbrChHCwHCV74p4ytfspkMr6Ht/HXlQIJjPwTGQspNssH0rtcCAwEA AaOCAdkwggHVMIHHBgNVHREEgb8wgbyGFWh0dHA6Ly93d3cuaXplbnBlLmNvbYEP aW5mb0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJ RiBBMDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFD MEEGA1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAx MDEwIFZpdG9yaWEtR2FzdGVpejAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQU1PGqyBSzeD2NtfUdjIajNnl2R+MwHwYDVR0jBBgwFoAU HRxlDqjyJXu0kc/ksbHmvVV0bAUwOgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYB BQUHAgEWGWh0dHA6Ly93d3cuaXplbnBlLmNvbS9jcHMwNwYIKwYBBQUHAQEEKzAp MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5pemVucGUuY29tOjgwOTQwMwYDVR0f BCwwKjAooCagJIYiaHR0cDovL2NybC5pemVucGUuY29tL2NnaS1iaW4vYXJsMjAL BgkqhkiG9w0BAQsDggIBADP5qmdcjmwNN7aOxvwVvCxJXvGnfBNNizlHTD81AqgX QTQ4hvF14VWjy3mnoXLVy2/403vwek8CawSiUKbJm+RwuPqcO/gPrWjEvBQXusRK agi2oW8aF+yqSYsxcbaYjmyRjQ3BIke38oLiv6+GRSJI6beRBoYe61/lxxn7AhKj sdqvpiE2w9bWWUNezCfSqi+d74Pk6Q+Or/66o5tXIwOIYmxh6H1nvOtHEhEdqtWb iHMu11+a2qJs4zTfw1kSBuKNhkTucUtpo6aqxhFCWqPNkuM/Y5KBbHg4z2yIPTKu XBP4DbxAJIDJm3ybKJt93jQGmpA4tvkfzeTvUaDoI4VOkl1ko9OKCb0nLG0lNaHI Oij+JgHzKXJC8YvQXVs+NUtqQ741R7Oz0Bw6VCdlU7VM8wp3t1LfuPe00dAubNNI qBTbvCN9KaijCpEC5D60Pa4Yx9uiw/rWfuT5t5JCxlLr79AAjJ7q29xVRZWE2LOn YqvD4mFYLVUsXXvaX/tt7e3rPAm/KIaj1o71k4m+oXYkdybju9KMCkW71UQqoKR6 7XnLTN8n99RXlf9klno/eg6QJMuaz0tQ4njdf0dDGtKjwmPEPAtT3eDvAXKacs8t etTOeBCj7Bb33fei7IVjxfkmgoxO/OQLu/FpSTBax9p8j4q39e+s+d8O/39JyMvk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFCzCCAvOgAwIBAgIBGDANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA5MTYxN1oXDTMwMTAyNjA5MTYxN1ow SzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0w GwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMjCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAL1OFdoURRXuCuwTBJpuCKDE8Euzcg0AeCRGq3VdagbChyCE CQ5vYWwmpHCyFl1b+r2KyWdQBBdG+msAcIYZal5cjZzrTWvbkfiAD/OneMjhqYB0 pTQIXbTjpPUMOjFM8waNZcqGJqC9H+Z9NkjK5THAK0oOOfKNPHg1MeImbOHVw0fR 48WnNrPpnQDt+SbPFSvw+dACDAybx1XgjMPq7pmZDWbkajOz4yCvrgZm6jvAPeT3 qkBFh7zOZ3IZVdfmRjVahx0iXp5TJ1SsrRr/uCiae1O+NR//XDG3dl9j17HsFlhY Rl6EvEfVV0OcW94Ret9uBUF73ANZl0b+gwCXnV0CAwEAAaOB9jCB8zAPBgNVHRMB Af8EBTADAQH/MB8GA1UdIwQYMBaAFEe4zf/lb+74suwvTg75JbCOPGvDMB0GA1Ud DgQWBBQiMC7S+/ZLysC4O9IExOly5pebDDAOBgNVHQ8BAf8EBAMCAQYwEQYDVR0g BAowCDAGBgRVHSAAMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwuYnV5cGFz cy5uby9jcmwvQlBDbGFzczNSb290Q0EuY3JsMD4GCCsGAQUFBwEBBDIwMDAuBggr BgEFBQcwAYYiaHR0cDovL29jc3AuYnV5cGFzcy5uby9vY3NwL0JQT2NzcDANBgkq hkiG9w0BAQsFAAOCAgEAaOLyxpj2t9k9Rzkxkcj/teTNOWxBLPZDi+eFx3u7laf2 mX/ZUSSE4g7OiKnD7ozWk9Qgocn3rBWGDKsp676RwWV97Elofz73Oebei6P3Gg/9 CD8y6rf8xHRxru5d1ZQ1NkWdPwYI38jlt3LaDjJKZjJW7pOPIMRvw1Y1AY3mYgCJ Qqpw8jgukHIP0454DPzkUXzg/ZVJG0swmFmjYfARleSPidcs5BJx5ngpcUS4745g mN9PQ578+ROIbML4Jx83myivlyTQSPdYSwzSswb1RVBJmiF9qC0B1hivCrs4BATu YeaPV6CiNDr0jGnbxAskz7QDNR6uJSUKX3L9iY2TB/4/5hJ9TZ/YDI6OEG/wVtBz 5FkU0ucztyQa4UG1mXR8Zbs/zt9Fj0Xn8f5IM3dB/s/r8c1AFDIcLRUqP/LkI9Wj XovWr79PEJcIfIln0AfzYfBBxCRE+4QHcVhci6p/mbyl2a+Rf8ZGNTiDLaWSZp5x jqdaq5UQaoZK8XQ+JVR0etep/KPgVMXq5Zv16YEb2vjs//RfxT8psDZLe/37+Bs4 AG9sdT/bsH7HDQwodTon/HvMmxt4EiU/1Sjco4Fok9VmSE2UVjIghajbbTSKR3LV UuU19x12fKp+htO8L+wVlGgxXb9WvDBNHCe6RmR4jqavmvrAyCPtrx3cXwqGmXA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGIDCCBQigAwIBAgIGSUEs5AAZMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTAxMjI3MTUyNDM5WhcNMjYwMzEzMTUyNDM5WjCB qjELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxODA2BgNVBAMML05ldExvY2sgRXhwcmVzc3ogKENs YXNzIEMpIFRhbsO6c8OtdHbDoW55a2lhZMOzMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA8N6/DQoQeT9JT4cyHdV8GAZVUJ5GGDfMMTu9kxSH+Y96eu0U 6MnytHS2byF2Scsd6L9ARaYvPiHRUBIQY7EcMpO/mQ5W3KykyQoXAlXCslowdAsP SfsYk+6Rr5sRvHnVxK5GhLq+n+Ub0ioAiiwucSa4MEreVMgJWu6XFySev553L8kc GzYLI3aI5EGIEUcf4cRmY0DoRZM/D5+j8T2gkYA75Qrxp2gVAxZySCH/tKYiwSLk syNB5SM/o/xIUaeAJk6JIx1Mfs7m+6nUpT+uGV23QLcU5dCtZlRiuD1brAoZm7kj jbpLqwSF7tXHaSFBAfMTKWm2X/Onxrgp8bz0aQIDAKzTo4ICSzCCAkcwEgYDVR0T AQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAUzPpnk/C2 uNClwB7zU/2MU9+D15YwHQYDVR0OBBYEFEm/IUDzU702KyJlqCYS/+TfcfbKMIIB PgYIKwYBBQUHAQEEggEwMIIBLDAsBggrBgEFBQcwAYYgaHR0cDovL29jc3AxLm5l dGxvY2suaHUvZ29sZC5jZ2kwLAYIKwYBBQUHMAGGIGh0dHA6Ly9vY3NwMi5uZXRs b2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRwOi8vb2NzcDMubmV0bG9j ay5odS9nb2xkLmNnaTA0BggrBgEFBQcwAoYoaHR0cDovL2FpYTEubmV0bG9jay5o dS9pbmRleC5jZ2k/Y2E9Z29sZDA0BggrBgEFBQcwAoYoaHR0cDovL2FpYTIubmV0 bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0BggrBgEFBQcwAoYoaHR0cDovL2Fp YTMubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDCBngYDVR0fBIGWMIGTMC+g LaArhilodHRwOi8vY3JsMS5uZXRsb2NrLmh1L2luZGV4LmNnaT9jcmw9Z29sZDAv oC2gK4YpaHR0cDovL2NybDIubmV0bG9jay5odS9pbmRleC5jZ2k/Y3JsPWdvbGQw L6AtoCuGKWh0dHA6Ly9jcmwzLm5ldGxvY2suaHUvaW5kZXguY2dpP2NybD1nb2xk MA0GCSqGSIb3DQEBCwUAA4IBAQBa2rS+9NJ/UUzJbwOSqPYoyRk+L61V/Wd5jWjY MGtoS42gaCy/NTiFnySQhi9Pp9+jSBRmhkRzdwj/+KxwC2r6uZHBu3Agco9dlL5T 9ZGfX3+KW66T5kENW0QL2jpu1nEEb4AL0WdahRyKg8pUBc1sH+lghA6ZMJh5IBXp qfcL7dykIvWpJOmn7Fb8teUeoqTdyzkQgi1mBDYDFrr3vhss8TqO0U+f0lFIT/ws DlnessbD+NeR5IHI47kbuJo5abqP+CNkd5URmtI2q0fCrL6giu55LwJccj/asWzM 17j3ynVWWto+KwhLtVh4Vq4UNMiZo4gwJFO6UzKoYZ4lpwAT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGKzCCBROgAwIBAgIGSUEs5AAaMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTAxMjI3MTUyNTExWhcNMjYwMzEzMTUyNTExWjCB tTELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxQzBBBgNVBAMMOk5ldExvY2sgRXhwcmVzc3ogRWF0 LiAoQ2xhc3MgQyBMZWdhbCkgVGFuw7pzw610dsOhbnlraWFkw7MwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQNEll2RNMz/OAwjKRc2seboOp8qMsnM5A 7nB+kks4JmTSwddHdv1+D5ivJGVzLfLsCPeap5m2nar9YqrKXlNCjBxgblUcjlAW +vhQN4AoGRNmPQuHT+6VugdxzzAWmos2V05jYkNVNXHpiVRCj2ObeLbRuN+Kr1JC bbpobr2REfhM/b9RPJe++M63vCOUxQMgBKvLPlcROubIhCscFSa2b9cl3fkdb+QU NmQUM2Mfs9ZB8X3J307xOactlXmAc652C8oJwZlbPbcEMWOc4KVV8nSeLjweFDcO JClHdl2TUN7nxFbhDeq2oLu6E3Cug+lgN7SAATHcDVPiPoUMT00pAgMA0PGjggJL MIICRzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME GDAWgBTM+meT8La40KXAHvNT/YxT34PXljAdBgNVHQ4EFgQUcUlugYfRCK3xKASh 87//Rm9/tdowggE+BggrBgEFBQcBAQSCATAwggEsMCwGCCsGAQUFBzABhiBodHRw Oi8vb2NzcDEubmV0bG9jay5odS9nb2xkLmNnaTAsBggrBgEFBQcwAYYgaHR0cDov L29jc3AyLm5ldGxvY2suaHUvZ29sZC5jZ2kwLAYIKwYBBQUHMAGGIGh0dHA6Ly9v Y3NwMy5uZXRsb2NrLmh1L2dvbGQuY2dpMDQGCCsGAQUFBzAChihodHRwOi8vYWlh MS5uZXRsb2NrLmh1L2luZGV4LmNnaT9jYT1nb2xkMDQGCCsGAQUFBzAChihodHRw Oi8vYWlhMi5uZXRsb2NrLmh1L2luZGV4LmNnaT9jYT1nb2xkMDQGCCsGAQUFBzAC hihodHRwOi8vYWlhMy5uZXRsb2NrLmh1L2luZGV4LmNnaT9jYT1nb2xkMIGeBgNV HR8EgZYwgZMwL6AtoCuGKWh0dHA6Ly9jcmwxLm5ldGxvY2suaHUvaW5kZXguY2dp P2NybD1nb2xkMC+gLaArhilodHRwOi8vY3JsMi5uZXRsb2NrLmh1L2luZGV4LmNn aT9jcmw9Z29sZDAvoC2gK4YpaHR0cDovL2NybDMubmV0bG9jay5odS9pbmRleC5j Z2k/Y3JsPWdvbGQwDQYJKoZIhvcNAQELBQADggEBAEK8hJUFkVC5Xo9hcdk+XI4l qTXetRatFgppxKjZRRNFaZGkGBD4ucfN7H04Ao+aVwAEupJNzhmT8Z68GR9QbboY sHbUIHwlHiN/mS4isn+TVLRjm4Z9vOFostBSMS+uB6WD7sudbm6rl6xl62Pcvo7m pK7JKIYkoreXAhaDoQAb3diWiqwIvvmTX2nUqN5Gq6JAs+p4GUvh3pIKVA0azJJE 6xE7XSK8RTIpFKvlDrl6EaRcjHHF/IkAX/3upcY33R8bwdb++Rx/gpbY6ByxlxK7 KC/dpX3K7jB8i886Slm+NqsyLj0oIu8icY0yjHfj5DXqFOxf5V5DPuge5UbkuhI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGozCCBYugAwIBAgIQD6hJBhXXAKC+IXb9xextvTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTEwMjExMTIwMDAwWhcNMjYwMjEwMTIwMDAwWjBvMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMS4wLAYDVQQDEyVEaWdpQ2VydCBBc3N1cmVkIElEIENvZGUgU2lnbmlu ZyBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnHz5oI8KyolL U5o87BkifwzL90hE0D8ibppP+s7fxtMkkf+oUpPncvjxRoaUxasX9Hh/y3q+kCYc fFMv5YPnu2oFKMygFxFLGCDzt73y3Mu4hkBFH0/5OZjTO+tvaaRcAS6xZummuNwG 3q6NYv5EJ4KpA8P+5iYLk0lx5ThtTv6AXGd3tdVvZmSUa7uISWjY0fR+IcHmxR7J 4Ja4CZX5S56uzDG9alpCp8QFR31gK9mhXb37VpPvG/xy+d8+Mv3dKiwyRtpeY7zQ uMtMEDX8UF+sQ0R8/oREULSMKj10DPR6i3JL4Fa1E7Zj6T9OSSPnBhbwJasB+ChB 5sfUZDtdqwIDAQABo4IDQzCCAz8wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoG CCsGAQUFBwMDMIIBwwYDVR0gBIIBujCCAbYwggGyBghghkgBhv1sAzCCAaQwOgYI KwYBBQUHAgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3Np dG9yeS5odG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABv AGYAIAB0AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0 AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABl ACAARABpAGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAgAHQAaABl ACAAUgBlAGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0 ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABh AG4AZAAgAGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBl AGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wEgYDVR0TAQH/BAgwBgEB /wIBADB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig NoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v dENBLmNybDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 QXNzdXJlZElEUm9vdENBLmNybDAdBgNVHQ4EFgQUe2jOKarAF75JeuHlP9an90WP NTIwHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQEF BQADggEBAHtyHWT/iMg6wbfp56nEh7vblJLXkFkz+iuH3qhbgCU/E4+bgxt8Q8Tm jN85PsMV7LDaOyEleyTBcl24R5GBE0b6nD9qUTjetCXL8KvfxSgBVHkQRiTROA8m oWGQTbq9KOY/8cSqm/baNVNPyfI902zcI+2qoE1nCfM6gD08+zZMkOd2pN3yOr9W NS+iTGXo4NTa0cfIkWotI083OxmUGNTVnBA81bEcGf+PyGubnviunJmWeNHNnFEV W0ImclqNCkojkkDoht4iwpM61Jtopt8pfwa5PA69n8SGnIJHQnEyhgmZcgl5S51x afVB/385d2TxhI2+ix6yfWijpZCxDP8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwjCCBaqgAwIBAgIQAsTR5YpKaAxWjaMEfn5NXzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTExMDIxMTEyMDAwMFoXDTI2MDIxMDEyMDAwMFowczEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEyMDAGA1UEAxMpRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug Q29kZSBTaWduaW5nIENBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDF+SPmlCfEgBSkgDJfQKONb3DA5TZxcTp1pKoakpSJXqwjcctOZ31BP6rjS7d7 vp3BqDiPaS86JOl3WRLHZgRDwg0mgolAGfIs6udM53wFGrj/iAlPJjfvOqT6ImyI yUobYfKuEF5vvNF5m1kYYOXuKbUDKqTO8YMZT2kFcygJ+yIQkyKgkBkaTDHy0yvY hEOvPGP/mNsg0gkrVMHq/WqD5xCjEnH11tfhEnrV4FZazuoBW2hlW8E/WFIzqTVh TiLLgco2oxLLBtbPG00YfrmSuRLPQCbYmjaFsxWqR5OEawe7vNWz3iUAEYkAaMEp POo+Le5Qq9ccMAZ4PKUQI2eRAgMBAAGjggNXMIIDUzAOBgNVHQ8BAf8EBAMCAYYw EwYDVR0lBAwwCgYIKwYBBQUHAwMwggHDBgNVHSAEggG6MIIBtjCCAbIGCGCGSAGG /WwDMIIBpDA6BggrBgEFBQcCARYuaHR0cDovL3d3dy5kaWdpY2VydC5jb20vc3Ns LWNwcy1yZXBvc2l0b3J5Lmh0bTCCAWQGCCsGAQUFBwICMIIBVh6CAVIAQQBuAHkA IAB1AHMAZQAgAG8AZgAgAHQAaABpAHMAIABDAGUAcgB0AGkAZgBpAGMAYQB0AGUA IABjAG8AbgBzAHQAaQB0AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4AYwBlACAA bwBmACAAdABoAGUAIABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAAUwAgAGEA bgBkACAAdABoAGUAIABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAAQQBnAHIA ZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkAYQBiAGkA bABpAHQAeQAgAGEAbgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABvAHIAYQB0AGUA ZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBlAGYAZQByAGUAbgBjAGUALjASBgNV HRMBAf8ECDAGAQH/AgEAMH8GCCsGAQUFBwEBBHMwcTAkBggrBgEFBQcwAYYYaHR0 cDovL29jc3AuZGlnaWNlcnQuY29tMEkGCCsGAQUFBzAChj1odHRwOi8vY2FjZXJ0 cy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3J0 MIGPBgNVHR8EgYcwgYQwQKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E aWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwQKA+oDyGOmh0dHA6Ly9j cmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5j cmwwHQYDVR0OBBYEFJdIA+sVCGu5slgjzJQu8cZl0mSOMB8GA1UdIwQYMBaAFLE+ w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQBJ63xgvq7vyXyz xbpLZN8WaeKG+inZ3piFfUBmJjMvRFWqqpDpNXAKNL7TrlQujmUA1noyID5sJriY qTmxvJXHqun17kZmxrPoEvizl53/dFiCNJl1UKxEj+iSzn2LDzGWx9zTETCYdBbG 5WtFdqOUAc0zAHpI9m+GMclWKzMi1fgBtkTOjLTKiNLkFuPn9uI+4QnAnXlDQ39V XAWtkxDGLA1rwJ7qeOXSd9a42pqYf7pMkiudvaSIsd2vw0zSl5sDxq5fG0QPMzcV 48v/L1bTFqRbVWedosrbNGwMc0q1e6S2s+k1Anhw7AB6y/xLTyI2uxSEyY+R3Q88 dYzKC4jn -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFDCCAvygAwIBAgILBAAAAAABL07hUtcwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xMTA0MTMxMDAw MDBaFw0yODAxMjgxMjAwMDBaMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMSgwJgYDVQQDEx9HbG9iYWxTaWduIFRpbWVzdGFtcGluZyBD QSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlO9l+LVXn6BT DTQG6wkft0cYasvwW+T/J6U00feJGr+esc0SQW5m1IGghYtkWkYvmaCNd7HivFzd ItdqZ9C76Mp03otPDbBS5ZBb60cO8eefnAuQZT4XljBFcm05oRc2yrmgjBtPCBn2 gTGtYRakYua0QJ7D/PuV9vu1LpWBmODvxevYAll4d/eq41JrUJEpxfz3zZNl0mBh IvIG+zLdFlH6Dv2KMPAXCae78wSuq5DnbN96qfTvxGInX2+ZbTh0qhGL2t/HFEzp hbLswn1KJo/nVrqm4M+SU4B09APsaLJgvIQgAIMboe60dAXBKY5i0Eex+vBTzBj5 Ljv5cH60JQIDAQABo4HlMIHiMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG AQH/AgEAMB0GA1UdDgQWBBRG2D7/3OO+/4Pm9IWbsN1q1hSpwTBHBgNVHSAEQDA+ MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5j b20vcmVwb3NpdG9yeS8wMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nbG9i YWxzaWduLm5ldC9yb290LmNybDAfBgNVHSMEGDAWgBRge2YaRQ2XyolQL30EzTSo //z9SzANBgkqhkiG9w0BAQUFAAOCAQEATl5WkB5GtNlJMfO7FzkoG8IW3f1B3AkF BJtvsqKa1pkuQJkAVbXqP6UgdtOGNNQXzFU6x4Lu76i6vNgGnxVQ380We1I6AtcZ Gv2v8Hhc4EvFGN86JB7arLipWAQCBzDbsBJe/jG+8ARI9PBw+DpeVoPPPfsNvPTF 7ZedudTbpSeE4zibi6c1hkQgpDttpGoLoYP9KOva7yj2zIhd+wo7AKvgIeviLzVs D440RZfroveZMzV+y5qKu0VN5z+fwtmK+mWybsd+Zf/okuEsMaL3sCc2SI8mbzvu TXYfecPlf5Y1vC0OzAGwjn//UYCAp5LUs0RGZIyHTxZjBzFLY7Df8w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMxMDUwMzA3 MDAwMFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UE CxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQD EypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC54MsQ1K92vdSTYuswZLiBCGzD BNliF44v/z5lz4/OYuY8UhzaFkVLVat4a2ODYpDOD2lsmcgaFItMzEUz6ojcnqOv K/6AYZ15V8TPLvQ/MDxdR/yaFrzDN5ZBUY4RS1T4KL7QjL7wMDge87Am+GZHY23e cSZHjzhHU9FGHbTj3ADqRay9vHHZqm8A29vNMDp5T19MR/gd71vCxJ1gO7GyQ5HY pDNO6rPWJ0+tJYqlxvTV0KaudAVkV4i1RFXULSo6Pvi4vekyCgKUZMQWOlDxSq7n eTOvDCAHf+jfBDnCaQJsY1L6d8EbyHSHyLmTGFBUNUtpTrw700kuH9zB0lL7AgMB AAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUQMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0jBBgwFoAUOpqFBxBnKLbv 9r0FQW4gwZTaD94wNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v b2NzcC5nb2RhZGR5LmNvbS8wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5n b2RhZGR5LmNvbS9nZHJvb3QtZzIuY3JsMEYGA1UdIAQ/MD0wOwYEVR0gADAzMDEG CCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkv MA0GCSqGSIb3DQEBCwUAA4IBAQAIfmyTEMg4uJapkEv/oV9PBO9sPpyIBslQj6Zz 91cxG7685C/b+LrTW+C05+Z5Yg4MotdqY3MxtfWoSKQ7CC2iXZDXtHwlTxFWMMS2 RJ17LJ3lXubvDGGqv+QqG+6EnriDfcFDzkSnE3ANkR/0yBOtg2DZ2HKocyQetawi DsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1KrKQ0U11 GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkKrqeKM+2x LXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDAB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIErDCCA5SgAwIBAgICIAMwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMx ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xMTA1MDMw NzAwMDBaFw0zMTA1MDMwNzAwMDBaMIGzMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j b20sIEluYy4xLjAsBgNVBAsTJWh0dHBzOi8vY2VydHMuZ29kYWRkeS5jb20vcmVw b3NpdG9yeS8xMTAvBgNVBAMTKEdvIERhZGR5IFJvb3QgQ2VydGlmaWNhdGUgQXV0 aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/cWII 8fpZNPcbyRij94BJWOkigxOmxSBDATuE8eaFSZ8n6vaEG06gtNtwmMcyAbEFPgdO 7vT6Ty9ZMCLnqxlWa+KAB/zzFnWAOVF75fk1tnROqY2CE+S2P6kDg/qivooVan/e C8O2GRQFyurDqASUO0Z8Mg3zAGYiyI1pbTaMERi307IcYLQ4+gKMztPdRgfeCj7r XXzIfPuwK1OkkmJpUSUFYRpEgYwsqUOWI9+sOoGaDinFHKnpXR62np4wCjnO8YiA +0tdzDLshWJDJTQCVicBkbQ7cCo/brHonIgBfZ/U+dtTbWCdvyznWKu4X0b8zsQb AzwJ60kxXGlGs+BHAgMBAAGjggEXMIIBEzAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUOpqFBxBnKLbv9r0FQW4gwZTaD94wHwYDVR0j BBgwFoAU0sSw0pHUTBFxs2HLPaH+3ahq1OMwNAYIKwYBBQUHAQEEKDAmMCQGCCsG AQUFBzABhhhodHRwOi8vb2NzcC5nb2RhZGR5LmNvbS8wMgYDVR0fBCswKTAnoCWg I4YhaHR0cDovL2NybC5nb2RhZGR5LmNvbS9nZHJvb3QuY3JsMEYGA1UdIAQ/MD0w OwYEVR0gADAzMDEGCCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29t L3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQB982xwFvIna1sf7oELJ4IK tF0hsGasDYOHh9JIr+z46QQCvzyOyyBe5d6ziumlppli6jH6yvq2cTti3OjKhRIm yrR7FyV+tbSM+bNJqcTtaa6ANG9/H5SSHOWbMOEZxEkSDf6Ex47JRR9Q+eW4tMTA Bojy1LG/2UapEc0ZvS4qBZzWJ4ieOXQcRJm8BE6ZfYcmo72G9UeOCf2Bo6I8G8E1 HUamRmJ/11WuO0DQGYm6Yer+icRyw6OFmF679aUUD2wTNJrPd/bblbDrn4oue/pF JQ9dKCX4cYfvnPGupJ5ikeBkmiN76a1P+U3zeKa5QUeKHSjQd5Z3PfjvQxNjMT9o -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFADCCA+igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAw MFoXDTMxMDUwMzA3MDAwMFowgcYxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj aG5vbG9naWVzLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydHMuc3RhcmZpZWxk dGVjaC5jb20vcmVwb3NpdG9yeS8xNDAyBgNVBAMTK1N0YXJmaWVsZCBTZWN1cmUg Q2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDlkGZL7PlGcakgg77pbL9KyUhpgXVObST2yxcT+LBxWYR6ayuF pDS1FuXLzOlBcCykLtb6Mn3hqN6UEKwxwcDYav9ZJ6t21vwLdGu4p64/xFT0tDFE 3ZNWjKRMXpuJyySDm+JXfbfYEh/JhW300YDxUJuHrtQLEAX7J7oobRfpDtZNuTlV Bv8KJAV+L8YdcmzUiymMV33a2etmGtNPp99/UsQwxaXJDgLFU793OGgGJMNmyDd+ MB5FcSM1/5DYKp2N57CSTTx/KgqT3M0WRmX3YISLdkuRJ3MUkuDq7o8W6o0OPnYX v32JgIBEQ+ct4EMJddo26K3biTr1XRKOIwSDAgMBAAGjggEsMIIBKDAPBgNVHRMB Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUJUWBaFAmOD07LSy+ zWrZtj2zZmMwHwYDVR0jBBgwFoAUfAwyH6fZMH/EfWijYqihzqsHWycwOgYIKwYB BQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0ZWNo LmNvbS8wOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5zdGFyZmllbGR0ZWNo LmNvbS9zZnJvb3QtZzIuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUF BwIBFitodHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkv MA0GCSqGSIb3DQEBCwUAA4IBAQBWZcr+8z8KqJOLGMfeQ2kTNCC+Tl94qGuc22pN QdvBE+zcMQAiXvcAngzgNGU0+bE6TkjIEoGIXFs+CFN69xpk37hQYcxTUUApS8L0 rjpf5MqtJsxOYUPl/VemN3DOQyuwlMOS6eFfqhBJt2nk4NAfZKQrzR9voPiEJBjO eT2pkb9UGBOJmVQRDVXFJgt5T1ocbvlj2xSApAer+rKluYjdkf5lO6Sjeb6JTeHQ sPTIFwwKlhR8Cbds4cLYVdQYoKpBaXAko7nv6VrcPuuUSvC33l8Odvr7+2kDRUBQ 7nIMpBKGgc0T0U7EPMpODdIm8QC3tKai4W56gf0wrHofx1l7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE1TCCA72gAwIBAgICIAYwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCVVMx JTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsT KVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEx MDUwMzA3MDAwMFoXDTMxMDUwMzA3MDAwMFowgcUxCzAJBgNVBAYTAlVTMRAwDgYD VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTQwMgYDVQQLEytodHRwczovL2NlcnRz LnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkvMTIwMAYDVQQDEylTdGFyZmll bGQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfK PTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvV dPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uL icFZ8WJ/X7NfZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzR mZTRouNjWwl2tVZi4Ut0HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaOCASkwggEl MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR8DDIf p9kwf8R9aKNiqKHOqwdbJzAfBgNVHSMEGDAWgBS/X7fRzt0fhvRbVazc1xDCDqmI 5zA6BggrBgEFBQcBAQQuMCwwKgYIKwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnN0YXJm aWVsZHRlY2guY29tLzA4BgNVHR8EMTAvMC2gK6AphidodHRwOi8vY3JsLnN0YXJm aWVsZHRlY2guY29tL3Nmcm9vdC5jcmwwTAYDVR0gBEUwQzBBBgRVHSAAMDkwNwYI KwYBBQUHAgEWK2h0dHBzOi8vY2VydHMuc3RhcmZpZWxkdGVjaC5jb20vcmVwb3Np dG9yeS8wDQYJKoZIhvcNAQELBQADggEBADUEaGoCgUXuLmhWo/tWlCpw3vzkSyII u49k7oA7aU2jwDyUZtNW+UTReKEUXwmEIoU27hK7BMLQenYlg9LufrbQHkIxzYGB 1zalW8FoKmzcsFKYtvQpkVWvUmL3bspsCxijyPnhH2SeG3NhoT5UCASj1NGTDSxw TQesNn9DJfQQGgaxf6lRtQAtBoDg/DfjA8hJ4ZLYqkhoshILf57moxztofrLdA4d 1apBUsVAeptzIMVdhH6YaLlH+ulDAkO7umzmQ+0L6QK9blir+2Qj2dFJgkmYQ0xY 38Vq6MNXJZqDN4FtQFdKrozmsdx/o48fJlxID8ZsdLRP3W7lCOZE6gc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgILBAAAAAABMYnGUAQwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTEwODAyMTAwMDAwWhcNMjkwMzI5 MTAwMDAwWjBbMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1z YTExMC8GA1UEAxMoR2xvYmFsU2lnbiBUaW1lc3RhbXBpbmcgQ0EgLSBTSEEyNTYg LSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKqbjsOrEVElAbaW lOJP2MEI9kYj2UXFlZdbqxq/0mxXyTMGH6APxjx+U0h6v52Hnq/uw4xH4ULs4+Oh SmwMF8SmwbnNW/EeRImO/gveIVgT7k3IxWcLHLKz8TR2kaLLB203xaBHJgIVpJCR qXme1+tXnSt8ItgU1/EHHngiNmt3ea+v+X+OTuG1CDH96u1LcWKMI/EDOY9EebZ2 A1eerS8IRtzSjLz0jnTOyGhpUXYRiw9dJFsZVD0mzECNgicbWSB9WfaTgI74Kjj9 a6BAZR9XdsxbjgRPLKjbhFATT8bci7n43WlMiOucezAm/HpYu1m8FHKSgVe3dsnY gAqAbgkCAwEAAaOB6DCB5TAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHQ4EFgQUkiGnSpVdZLCbtB7mADdH5p1BK0wwRwYDVR0gBEAwPjA8 BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29t L3JlcG9zaXRvcnkvMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFs c2lnbi5uZXQvcm9vdC1yMy5jcmwwHwYDVR0jBBgwFoAUj/BLf6guRSSuTVD6Y5qL 3uLdG7wwDQYJKoZIhvcNAQELBQADggEBAARWgkp80M7JvzZm0b41npNsl+gGzjEY WflsQV+ALsBCJbgYx/zUsTfEaKDPKGoDdEtjl4V3YTvXL+P1vTOikn0RH56KbO8s sPRijTZz0RY28bxe7LSAmHj80nZ56OEhlOAfxKLhqmfbs5xz5UAizznO2+Z3lae7 ssv2GYadn8jUmAWycW9Oda7xPWRqO15ORqYqXQiS8aPzHXS/Yg0jjFwqOJXSwNXN z4jaHyi1uoFpZCq1pqLVc6/cRtsErpHXbsWYutRHxFZ0gEd4WIy+7yv97Gy/0ZT3 v1Dge+CQ/SAYeBgiXQgujBygl/MdmX2jnZHTBkROBG56HCDjNvC2ULk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIECDCCAvCgAwIBAgIILu17PatkWxAwDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTExMTAwNDE4MjQyOVoXDTMwMTIzMTE0MDgyNFowQDEL MAkGA1UEBhMCVVMxGDAWBgNVBAoMD1RyZW5kIE1pY3JvIEluYzEXMBUGA1UEAwwO VHJlbmQgTWljcm8gQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC tz7qUBb61DHFYDbRj69nikk/4sbQ53NnPSrOBJEX3E59MAPoEO/biYzoMF4A3UdB LzZsRp4SYJZ0WybyvaExs9FHECfpcXohOCPkG7u1RC4EtUgMjw3lNvu3gDvyi5ut cdKI4uOwIkhD8objKuzSlU4IaUjsTaeIROKQHttkDMw7d8HhORy3QnTSIClZ3hgW DJZZHOyE2xhGhdyG/KfNlw/uXtJ9A5/YUPHp4dDfrQV2PUr+dTgs3BIh9r7dRngl a4BqbvNaH8Yw3fFJ8DqY118JH5GSQ3RQwHpz2f34n0y2PTSMLQlMUC2iRBOd8dhW Je5RGbKfveHXDfBgqdBBAgMBAAGjggEAMIH9MB0GA1UdDgQWBBStMcf6As5n92Uc +7pfwLvFUExnyDAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAcf0uec2sJu okC0sHpQEFB0xMi9ME8GA1UdIARIMEYwRAYKKwYBBAGCjwkBATA2MDQGCCsGAQUF BwIBFihodHRwOi8vd3d3LmFmZmlybXRydXN0LmNvbS9yZXNvdXJjZXMvY3BzMEkG A1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9B ZmZpcm1UcnVzdE5ldHdvcmtpbmcuY3JsMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG 9w0BAQUFAAOCAQEAUFU4RiDe7NdWtQKNH7j8tmOp8myZ91s6p7m1WXj0g6Ja25QB mv8XLVQVpUKd8Oq501DjCaU64E9Ba6K/ltTN/G8jzF/U8uYCFT6DpTDvTUedABjS H0gR74vHsIwz9ibAoTTh45K1T0+8M4PTI6OLTHkbCeg8Udpn9kCpLfqKEgmrf7YF 5v/081M3NzJcg0do9I37rn3OdFxC3/+b1p8bWHbrNYHvQ8CnNugQmyN4+EE8CUMI KbL7otky1Gn1ro/ya3L8gN5jzT7pNmB7N+EUgjr+bIJ4VxVKhVmgEaIT7EYMXvog OFm9oAww5XJiDz+dG0mEsnqRIawxKq0Lg0ZrHQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0zCCA7ugAwIBAgIVALhZFHE/V9+PMcAzPdLWGXojF7TrMA0GCSqGSIb3DQEB DQUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dp ZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBIDIwHhcNMTExMDA2 MDgzOTU2WhcNNDYxMDA2MDgzOTU2WjCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoT GVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0 d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvfl4+ObV gAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC5SBLm9qbe7mZXdmbgEvXhEAr J9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Vaqp3cKcniNQfrcE1K1sGzVrih QTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ0WeNG0a+RzDVLnLRxWPa52N5 RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet/5oCl8HGUJKbAiy9qbk0WQq/ hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNeGWJoRVfkkIJCu0LW8GHgwaM9 ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcVWiNoidQ+3k4nsPBADLxNF8tN orMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbls+V1e9dBkQXcXWnjlQ1DufyD ljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZbMI28iQzV13D4h1L92u+sUS4H s07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+NqcnoYsylfzGuXIkosagpZ6w7xQ EmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbljnX98sy50IdbzAYQYLuDNbde Z95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUtqFUOQLDoD+Oirz61PgcptE6Dv0wDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBDQUAA4ICAQCdU8KBJdw1LK4K3VqbRjBWu9S0bEuG5gql 0pKKmo3cj7TudvQDy+ubAXirKmu1uiNOMXy1LN0taWczbmNdORgS+KAoU0SHq2rE kpYfKqIcup3dJ/tSTbCPWujtjcNo45KgJgyHkLAD6mplKAjERnjgW7oO8DPcJ7Z+ iD29kqSWfkGogAh71jYSvBAVmyS8q619EYkvMe340s9Tjuu0U6fnBMovpiLEEdzr mMkiXUFq3ApSBFu8LqB9x7aSuySg8zfRK0OozPFoeBp+b2OQe590yGvZC1X2eQM9 g8dBQJL7dgs3JRc8rz76PFwbhvlKDD+KxF4OmPGt7s/g/SE1xzNhzKI3GEN8M+mu doKCB0VIO8lnbq2jheiWVs+8u/qry7dXJ40aL5nzIzM0jspTY9NXNFBPz0nBBbrF qId744aP+0OiEumsUewEdkzw+o+5MRPpCLckCfmgtwc2WFfPxLt+SWaVNQS2dzW4 qVMpX5KF+FLEWk79BmE5+33QdkeSzOwrvYRu5ptFwX1isVMtnnWg58koUNflvKiq B3hquXS0YPOEjQPcrpHadEQNe0Kpd9YrfKHGbBNTIqkSmqX5TyhFNbCXT0ZlhcX0 /WKiomr8NDAGft8M4HOBlslEKt4fguxscletKWSk8cYpjjVgU85r2QK+OTB14Pdc Y2rwQMEsjQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHeTCCBWGgAwIBAgIIINxlRne/yBUwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw CQYDVQQGEwJFUzAeFw0xMTEwMTMxMTIyMDRaFw0yNjEyMzEyMzU5MDBaMEMxEzAR BgNVBAMMCkFDQ1ZDQS0xMTAxEDAOBgNVBAsMB1BLSUFDQ1YxDTALBgNVBAoMBEFD Q1YxCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA oHVLyy+miC29v/sQZfjQLLkr3gEHI1cA7Ev0mJkOjx5jkpk7xp7NbROz/EM5VVxZ Vi+mo8Wtkpc8Qzrgm4XQNaJ0IaI4LC8f4boix0mLND0zCnIGNxti15nP4HiqZ7k9 u+YkylL5MX5VNbWl/TgMjxUHzaORYKPbSMRlAQSd1b7OU0PNa7p+WoF2XqbUzMdR 0qw03tsyBvvRXgTFkIKijzHDA5cemDfxdZNP7t6LOxu0JxKDIqgvMFH88FqdeJd8 uYVWpBpohIlZ0Gt7r3K9b6jNzuVAtWlkl4cByw1n5wmMSgxPxX6BtQrFUrvilrgd zDc/8b4IBqFzINjX/P9nErJdd4aQsn62uEomZ8PUwnQ6xhkMSqFjKDqqKUKjl5Cv +PQoBA60WwIhgoxkwC1IYi5V0uciAFams8YJi3U0/ZNttR4g+JUlPjn7Vboi8OW5 YKyxentQ+kDRN6gCQc8Oysx8NJ0wZnyt8MFzb/4OlzsO3vjSl8QEk9F0QF9+3ycm Fz6dBLYQgsZDDyK28DkJbIvwtDevB0S2QrabM3sxyKBImG7rNMm7ZyxpvX9vPXz1 eGgxhJ/pTCZMBe2/ygFRLjoHEJhkSJCiooCFluUcctYlPq1PugwVeIzpZZOVZvwP V0SKAlV+TddvZVW0jF7zi8EoVJpW9z7BiD3GumxZSckCAwEAAaOCAnAwggJsMC8G CCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYTaHR0cDovL29jc3AuYWNjdi5lczAd BgNVHQ4EFgQUklKuRm1bvb6FwbNhR6j/t9mTwA4wDwYDVR0TAQH/BAUwAwEB/zAf BgNVHSMEGDAWgBTSh7Tj3zcnk1X2VuqB5TbMjB4/vTCCAX8GA1UdIASCAXYwggFy MIIBbgYEVR0gADCCAWQwggEuBggrBgEFBQcCAjCCASAeggEcAEEAdQB0AG8AcgBp AGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAEkAbgB0 AGUAcgBtAGUAZABpAGEAIABkAGUAIABsAGEAIABBAEMAQwBWACAAKABBAGcAZQBu AGMAaQBhACAAZABlACAAVABlAGMAbgBvAGwAbwBnAO0AYQAgAHkAIABDAGUAcgB0 AGkAZgBpAGMAYQBjAGkA8wBuACAARQBsAGUAYwB0AHIA8wBuAGkAYwBhACwAIABD AEkARgAgAFEANAA2ADAAMQAxADUANgBFACkALgAgAEMAUABTACAAZQBuACAAaAB0 AHQAcAA6AC8ALwB3AHcAdwAuAGEAYwBjAHYALgBlAHMwMAYIKwYBBQUHAgEWJGh0 dHA6Ly93d3cuYWNjdi5lcy9sZWdpc2xhY2lvbl9jLmh0bTBVBgNVHR8ETjBMMEqg SKBGhkRodHRwOi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRp ZmljYWRvcy9yYWl6YWNjdjFfZGVyLmNybDAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI hvcNAQEFBQADggIBAFCFt2jwiV487rm4tE+VWNX5E6jwD32AXdEw6aDm1A2P4HYN MaQeaB8s7EyL4t2W1mLl+B6ObrwmvD1zbija852KPQ92IUo00cBH0k1agonUUE72 c4pHAHu36qZCYiGyhvAI8A3wlm5l+ow23zkLjL/qfdAFA0Lrh16Sw3PTmMC9LW69 CnzU14XBWtcmaqqqT1aJvoWUufk4703FJOZ+u6l+6l+VsR5IbFIbMOufhxTSVKye It7tpMFMAEK/mkbD8SmWuLGymTtQUqj5pmBPmyZM1d0AvY4Dn9Fw6SOCw+YdkjnA xx5B9SnXBfphA3yMVob26WuWQxd0Oz+ZuyLN4t5jcjl1UdH3wqjuS/UBBnTywVTy jixYB7HYT78yk0zTCNnCBmRkxL/fKzN2yRAr4/NUSilrtejMVQ6fOsfSdalbwK16 myWlxAKZgPi9ZkhZ2hxnFC3EPvp9P9dLA/O+F+iVt4/1vmMfQavJtudM4vUA7ul/ KOYzfLmbnRoj8seiPGJrfLgvs4kXJXL65YMp9F0N/HH+lMZR9SgzyrRPb6V+eUYI u4r9Cn+cC384CCugUgH4iKEKhW8Qe569eJzpjeQYE6qvCDFGfw8BCRN6Yq10W3zh 2zbZ0mVtkRfQFX5aGAvZUMKRJ1PUDOd2apAeux4NhyH+FPbX0qlJ4r7yfR8j -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHkjCCBXqgAwIBAgIIZILEq2VLAKYwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw CQYDVQQGEwJFUzAeFw0xMTEwMTMxNDU1MDRaFw0yNjEyMzEyMzU5MDBaMEMxEzAR BgNVBAMMCkFDQ1ZDQS0xMjAxEDAOBgNVBAsMB1BLSUFDQ1YxDTALBgNVBAoMBEFD Q1YxCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA mwYjFx7SZmarLj0+7DqdJn6qt5EwPpgXxnEzzFfOSQrSm6ylglABjVTEznl9a5m/ ydNAxggVGKNA+hNMFCagFS5P6nJ8bZ4SZbILpZ6egUoXDV/+Iy0FgW7sJLPPh323 2OtevxSiwGE8ipjJBVZVP+qYMFEpedkLRI2HzF0XVrmS9YfWOzK7yh2+d4CqPCfX 1W0aGeBK21skABXEXeRgZDr1U5kmLRZAoG5NZB6XPcVdudBvle3zO2nFPlYeDMsR SOBFwQp0L7tcEZ1dQ2u/uhq3UfJGesWtshn///sQDC8K7TX9whlRkw6Qx5V8TcO5 xQNJaxBQnsNBw41TBX4sglwzF50wfA2Xn0PS4GhT0ms/ijeqIh1ZP7eBKc4psMNJ ZtzhjdUCeK+WbZRDqK78Gv9K995oxFEDmR9Kyb5jDHgGV8qRdiup5g0ianMSg2iU 5RxGzjvdGULDgAmvJ/fBuCMv15rLsz8c4zYxNDbNHRfET6TlxEZtLK1wGL3lrXgX ANXLFWSQzTw5EgBwueCWMZDIlvi4x16oeX5G7QcrKrQS8DCdWhGlhDMVJOcBkkLJ tlRjKitmYiTIoRiFaRt4S4+L+004rHlcbr9Ec76HbSmBYsmuIfrk8nSPDGnv0LOo rMhaXdcn6c5RZpH008lv6fN5wpLeEkQuzGjATLTFbo8CAwEAAaOCAokwggKFMC8G CCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYTaHR0cDovL29jc3AuYWNjdi5lczAd BgNVHQ4EFgQU6ECbjvtmP8FE2KHf1EqBQggXy+UwDwYDVR0TAQH/BAUwAwEB/zAf BgNVHSMEGDAWgBTSh7Tj3zcnk1X2VuqB5TbMjB4/vTCCAX8GA1UdIASCAXYwggFy MIIBbgYEVR0gADCCAWQwggEuBggrBgEFBQcCAjCCASAeggEcAEEAdQB0AG8AcgBp AGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAEkAbgB0 AGUAcgBtAGUAZABpAGEAIABkAGUAIABsAGEAIABBAEMAQwBWACAAKABBAGcAZQBu AGMAaQBhACAAZABlACAAVABlAGMAbgBvAGwAbwBnAO0AYQAgAHkAIABDAGUAcgB0 AGkAZgBpAGMAYQBjAGkA8wBuACAARQBsAGUAYwB0AHIA8wBuAGkAYwBhACwAIABD AEkARgAgAFEANAA2ADAAMQAxADUANgBFACkALgAgAEMAUABTACAAZQBuACAAaAB0 AHQAcAA6AC8ALwB3AHcAdwAuAGEAYwBjAHYALgBlAHMwMAYIKwYBBQUHAgEWJGh0 dHA6Ly93d3cuYWNjdi5lcy9sZWdpc2xhY2lvbl9jLmh0bTBVBgNVHR8ETjBMMEqg SKBGhkRodHRwOi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRp ZmljYWRvcy9yYWl6YWNjdjFfZGVyLmNybDAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0R BBAwDoEMYWNjdkBhY2N2LmVzMA0GCSqGSIb3DQEBBQUAA4ICAQA+fFVGYa3zf/b1 GQ1MTdYUHsSbAlA5esf2htyAzcea/OHu2CRgGXajCbJN7cC2pFuhsiWYXrihjuc/ crzztYYYjzRsO8iQn7+/hg56wzRCQvxMy0lLrwlVPXxtdg8mU1M8Gq13T+Nthkq5 uotXXZgxiJu3Zhvtl9kK2wDVwxfLlp/McQpRcl1VSCSgvGg1teIi7+NQ2wBQPhyj GanigxFI7LDkgjo0sI2K6qV4q43pYpGq3YidDE/ssEBLSkT2IIHLgq2L9An5gVoe r6vCK58XJx9FGCpVtksUQYnm+cAkNxzV/cAfWIZroQwiF+vUSy8bjuPRslpszoWF AFJwg50OHaigUkfT7KMA/2RtpmxaGKB0thURRrczdGB/k1IpKjG8N3zjw2StkWqd GXFnlxdfxv9wrUuIrA7QPT62kWDPY959ZVCOoGxuIz9ExH2NS2twbzHRhQqI8/Vp eSkepE28fjMkq6oU7UxyLCDZ3CqvlbXXsGlW4hvWiV76ttN6b7fEo8NxSkz0FzyA tD/Hf2pdd/RkTL0LSLjTFalowiP6svMeFgxJoecmEt6TrUGfFgQggyLiPdEaIB0z Sbs2m0ErwLbkKkQY1bh+vAoK0bHa35KOFYySijGXbu93Jmz+LaKsARIBqQ/ZPP2e OZ2FWP+k5weZYyxNpeL0dtz7svdTlw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHkjCCBXqgAwIBAgIIUXd8prk4rwYwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw CQYDVQQGEwJFUzAeFw0xMTEwMTQxMDA3MjhaFw0yNjEyMzEyMzU5MDBaMEMxEzAR BgNVBAMMCkFDQ1ZDQS0xMzAxEDAOBgNVBAsMB1BLSUFDQ1YxDTALBgNVBAoMBEFD Q1YxCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA o5KJruh7JPEBxpdC8Pf3qN8vfPR98dCWZynbjLBXv6MTjwAiehTq1X8OzEQNpqWq pNpygo6/YNgf8FMgYWhCsPSDvEmg5Um1xBnLjHBJMSIP7VClMVS9KidVu+nF8PpZ no8hecsfF4yJzLp/MD/lwIsjkh5Zp9e6cVBJsSkRJDY4gWlTWRYO/0e1ZQSmu+2+ YKy2ZRpOPo6k4eGlIsFGz9yIzVii0hasDf43Lv19F515tNGXFIYmNnLjMFlf/LKu Al87jblGqRn5yhMGuJNsP05gH5D/F5YkLqg6A83KmygsIsgYzN72YWiFYNzB6ZzF 0HPM9GX3PuSkKKXyFpUxYL0nHWH7B3Se4F5m+mmFk9GMvJVuoUvktOO2ysFPE3pY tl1iJjrVGBk5cmZHKQbqBw5ZooSEJNbmvtzshUxVEFTDRg+8avleaZFNvl5hilSQ 4c7YlvSnu80AMfhJ/pD6bwA+7BG91elQdcoMuedHyvE3lGqYxuh25a3u//K97joz +qq10hZH5eNrExjWV20DlF6kgZqo6C/2p0zm5eTfbaZ16oVZrpmTeG95dabQzgHD dXP6B4el67G275jQNok2Wu5wT9oKAM6xomNp6zsr0uYI9kQBqMP8BTPliB98rwg9 xmQH4Ss/r1zZK3xt+mYypBo1OR5VvKEEqs1bnVf3LjMCAwEAAaOCAokwggKFMC8G CCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYTaHR0cDovL29jc3AuYWNjdi5lczAd BgNVHQ4EFgQU5Sf9DFi3YMFTV4Yt+1YDi/6fxbIwDwYDVR0TAQH/BAUwAwEB/zAf BgNVHSMEGDAWgBTSh7Tj3zcnk1X2VuqB5TbMjB4/vTCCAX8GA1UdIASCAXYwggFy MIIBbgYEVR0gADCCAWQwggEuBggrBgEFBQcCAjCCASAeggEcAEEAdQB0AG8AcgBp AGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAEkAbgB0 AGUAcgBtAGUAZABpAGEAIABkAGUAIABsAGEAIABBAEMAQwBWACAAKABBAGcAZQBu AGMAaQBhACAAZABlACAAVABlAGMAbgBvAGwAbwBnAO0AYQAgAHkAIABDAGUAcgB0 AGkAZgBpAGMAYQBjAGkA8wBuACAARQBsAGUAYwB0AHIA8wBuAGkAYwBhACwAIABD AEkARgAgAFEANAA2ADAAMQAxADUANgBFACkALgAgAEMAUABTACAAZQBuACAAaAB0 AHQAcAA6AC8ALwB3AHcAdwAuAGEAYwBjAHYALgBlAHMwMAYIKwYBBQUHAgEWJGh0 dHA6Ly93d3cuYWNjdi5lcy9sZWdpc2xhY2lvbl9jLmh0bTBVBgNVHR8ETjBMMEqg SKBGhkRodHRwOi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRp ZmljYWRvcy9yYWl6YWNjdjFfZGVyLmNybDAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0R BBAwDoEMYWNjdkBhY2N2LmVzMA0GCSqGSIb3DQEBBQUAA4ICAQBFS2ILc8ssZCyE XDHjioc2dKd/TbDhwexsPtXmC0MwIEmUl5siPcsZaP+dtYxsxkDk2e2Ikb10Itaw ObpeXRt2v+qJHOs2vQoNszLffviWRo51s+FYHtgT0EieV+VhlQE8MdRS4vBx7VaK vWz9u1LZDoVQaASbeb04IfDTMBMwhxAyN2X6PzcsP0zKPYf3Vt/+g93Wnuuk54uZ BySnbzOL5f29ckED1sfdUzSynSQgxuQH8lQ7V6Scr62X9eFM0i3oZTVLFdMkoiIm YJuZG4zkpdr0qnvB/TOo4MsvvP4GcfU93Q8aQUIkp2NuN84Wrjr49ud4/d/IwWiF Q1iMIMVh8Ij2bIYexzZV5WuD7+MMRBbFO8JB4o4D0XwygRMwiLzEqR2GfV5WjfgV bkqqc5aLnN5EvZPKq2Ic0Ws+pIxcp1ZEeWTx5vS41BTgoYjxQRDAPEloOx9lbHTb uTLYxDG/s4TB4DHDL9WrCCpgWenWFgj6575RwC9Qykk6pNU9FRv+9OztFj0lUEnQ YhptIAptGg813ZN7mNMRGG5y7zPgOItvmGhxnWEZpQsRI28ZwtsG4sKtjcoV5HHl qyzWzhs1TKMaqD+ZDr417oaGKx/kHlG/wMIq4hUjtfyafe5l4648hcY9wkbIzC/1 7UaySDOmW43JJmrOMi15wd6FNxld9A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEATCCAumgAwIBAgIIWvgOmMFTClgwDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTExMTAyMjE5MTQ0MloXDTMwMTIzMTE0MDgyNFowQDEL MAkGA1UEBhMCVVMxGDAWBgNVBAoMD1RyZW5kIE1pY3JvIEluYzEXMBUGA1UEAwwO VHJlbmQgTWljcm8gQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC tz7qUBb61DHFYDbRj69nikk/4sbQ53NnPSrOBJEX3E59MAPoEO/biYzoMF4A3UdB LzZsRp4SYJZ0WybyvaExs9FHECfpcXohOCPkG7u1RC4EtUgMjw3lNvu3gDvyi5ut cdKI4uOwIkhD8objKuzSlU4IaUjsTaeIROKQHttkDMw7d8HhORy3QnTSIClZ3hgW DJZZHOyE2xhGhdyG/KfNlw/uXtJ9A5/YUPHp4dDfrQV2PUr+dTgs3BIh9r7dRngl a4BqbvNaH8Yw3fFJ8DqY118JH5GSQ3RQwHpz2f34n0y2PTSMLQlMUC2iRBOd8dhW Je5RGbKfveHXDfBgqdBBAgMBAAGjgfowgfcwHQYDVR0OBBYEFK0xx/oCzmf3ZRz7 ul/Au8VQTGfIMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUBx/S55zawm6i QLSwelAQUHTEyL0wSQYDVR0gBEIwQDA+BgRVHSAAMDYwNAYIKwYBBQUHAgEWKGh0 dHA6Ly93d3cuYWZmaXJtdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwSQYDVR0fBEIw QDA+oDygOoY4aHR0cDovL2NybC5hZmZpcm10cnVzdC5jb20vY3JsL0FmZmlybVRy dXN0TmV0d29ya2luZy5jcmwwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA A4IBAQCz8LF8s4ueoaZov0/fhVPJlm8flyIa/zxKxR7PK26LXJbV7Z4CL/7Xtp0z VtzAeFhuD11YSkG6BOvBDvozt4rHlLuOj/R+II10sBG4R3Z1iUUeXVLI5e4L0RL8 vb1PNBghUWF7+3W4Ge/CfHjno1V5I293k85otpjgq0MgJsr16oe9vjjOkXSZaG1+ NXshwaqFbDFI70ORCP0HmKADPAGm++sl6hVis1I9fWo9consiYRTHs2ac0f/bAu5 lyDf3OSEtcaYmvMuzwI4BZ7xTmPbx0pFN+dkpS8V2VO1bITrkKBkW6LqlVyDY8al 7Q4eay8hSFJbRBNzyPj+oarZ69Hf -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHTzCCBTegAwIBAgIJANkIP7upZ8oaMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTExMTIwNzExMjgwN1oXDTM4MDcz MTExMjgwN1owga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR 5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s +12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 +HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt IDIwMDiCCQDZCD+7qWfKGjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w DQYJKoZIhvcNAQELBQADggIBAJq8HIZ0d6Pxdaa59IM1hE9MfO37ttdRJUnEggep 0q9GS8qauGtDckmS10t27SwZ0zEGSsNLZvsiG0oW5MGWcW4wA6Z9RajAFMTLvY+w pcZPEtE9Kze6Nc6WvBuwrLhw4DePSYr+G7fAdfgbsDVF1y04eZ0e+Tc9WiO5rqKj bN72NqPEc0ahrtSC3cbXf1XZwiy+vs2uz3uknLl4q08OBrvNHV53R1yH2mBXmr7B tFlWRsgEaZ74r7jHq6rX0wST5xVglaemGi+xjuIBaGt6ZyBNGCZwFrL+PMfgZZz2 caupQxRPSOMhMLSpzA/Xm8blQDP/Uzukv4hgrgZOQmiMaBWprSq9BfmHCUVlG17U JcUNP1L6WLUmjLu35Yh5UYYznoUozlNxix59iyUHoviYRFfJYEstMfvVbJERL7PP 60uqww6G1/mWocfoO/4CwC2b1cFkuRZw8JbFBfQHCWhhb6t4n+Ul4vE5n1+sDSou kxJbZ91DxGokaqGMpI9GWPMUZBDdPQGyZODEPevhlvMzDkGW/kyzBWhU1ObB068Y YZgwB5rer36/EwYN1tEl5lSiDp5nIdOpsQGVwSJ7h+UJZ1tN52IbMmakoa0rdkiA wQXg99ysYHwGWA7rlMJIMvUqBIt6QrCL2B+AKY/7KWvJiC5GeFxkBGdKRg3Pedf5 LZh1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIJAK6CGQU/XoJxMA0GCSqGSIb3DQEBCwUAMIGsMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0xMTEyMDcxMTI5MjFaFw0zODA3MzEx MTI5MjFaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r 6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC CQCughkFP16CcTAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI hvcNAQELBQADggIBAAVYdowzN5EdX8oP0EeXv12Qid5aht15LIKdyjwkzo05bJAr FPMI3f09Xegl9XJjSLUPlwFcAUlAbUUE4tHNRtCGJZhqA/m7xr7u0PNhz5j5j+38 5hUKNYoooZBm1xzJmjYj7mwg1q2XUVUqsFYojn9K5gde1cr4XvMRpIwTSvLN8LW3 ZmNBUAIMLEdurDgAfYxgqIp+liejt/G9Ez0q7wPYcPvdZCvox1yvDJwgi2zQJkCS /vQJh3JTvvZt6Rj1diS4ahfn4z3YptuQfGHYT5NBCPNlytfeq5MKujvtX6Xcyhh8 rwL4yuB7HHzvnsmTMBruSBx5+FB3qWyeXfxrBt6Tmssk94CdVdJ4zdlmD1mBy6yi N8qRyqxXzY2BA6u8H82S/qWU3dbnaqxd3CX+K0952XI6IIwUqMRyMFgIm1MWcaa4 8fK8n7/560NhsyxounDkawhTFYQPQBJUJJkQkjqTxIIdiq60iIlFLu93rMAKByk7 j8stKWFFBw469gThKr/PE3tLeqNsIxpmsSgK4dH/1SvIRlSBF0vh5xBnpYu6LEHH N6IJ8aWHKe6Hl2qpsk6oqJ9hDao0xB94Q5WZ18O9ynd2UtwQDHyVJdgFxYQwVdp4 TOJrEfC8w0IMfJnbMGDUduUUVZlW5kFLNFx6SEltBWn5MXEH1lqShVA0dGh0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGgjCCBWqgAwIBAgIQBxVWH+V/ML4XiYkjwzpEUDANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTExMjA3MTIwMDAwWhcNMjYxMjA3MTIwMDAwWjBhMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNRGlnaUNlcnQgR3JpZDEZMBcGA1UECxMQd3d3LmRpZ2lj ZXJ0LmNvbTEfMB0GA1UEAxMWRGlnaUNlcnQgR3JpZCBUcnVzdCBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAO65BA1JPUZvUOjZf2SNLymSrF3vhYGP XyfUHmsZcgUSZFuwJXhWJMiDkwk1NfQrk0Hy9CyfFAD1z7EiQgOMWWuWQdweBJxw IzK/HQS0nTEwxEqF8O5cAWH478iZbY5sbTn9m5ZmFVRwPp1nh2k0c2mQ50QR078C sAnuzpbzA9nA3uZAX8+txpfBQ9bFsTociALeIYR0FhvHh/RlvLtfHFnxpg6Q/n0r AL9HKEYD+qBaBXtval0ziqRdr0B0yJ/d+inclJVKc/uNxrEjew9nbNMFnaoZ0Nt9 5uzn3qanjLxNmFRwBtvrA6iuJBlZlTjB1RpPu58l3TJ/LniIGPiRGHECAwEAAaOC AzAwggMsMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMHkGCCsG AQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t MEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl cnRBc3N1cmVkSURSb290Q0EucDdjMIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8v Y3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqg OKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS b290Q0EuY3JsMIIBxQYDVR0gBIIBvDCCAbgwggG0BgpghkgBhv1sAAIEMIIBpDA6 BggrBgEFBQcCARYuaHR0cDovL3d3dy5kaWdpY2VydC5jb20vc3NsLWNwcy1yZXBv c2l0b3J5Lmh0bTCCAWQGCCsGAQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAg AG8AZgAgAHQAaABpAHMAIABDAGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBz AHQAaQB0AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4AYwBlACAAbwBmACAAdABo AGUAIABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAAUwAgAGEAbgBkACAAdABo AGUAIABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAAQQBnAHIAZQBlAG0AZQBu AHQAIAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkAYQBiAGkAbABpAHQAeQAg AGEAbgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgAGgAZQBy AGUAaQBuACAAYgB5ACAAcgBlAGYAZQByAGUAbgBjAGUALjAdBgNVHQ4EFgQUYZek mymYAZta/4fmdO8wg8xotMgwHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNt yA8wDQYJKoZIhvcNAQEFBQADggEBAJtEamzsGt7a292/ds4LkJjwyRZ77QcYBns4 yXLuacEmMURsVXABhXcPGLtiy8h3slNSyB7V+mMrpXC1iPRGTSdOlHrkanyqXfDS pjOX1Jn0OtDvLRbHybsI08XIoZCI1SRskt/COlRTfVw7HFOXcsxtN4EvYRtbK/dN Z1zA8uqKPCXGVVhLEzlvoo8OZVVfKGPwqsaWi4SBjZNKWQklB8Pdezh0hOpLwUs8 Mi2YeJSxpfDTiJ5VDAAf9IIMnPouRQcx9KSNQqPAU2/jBt+9k6QpdVqIeC7ZP8Hp 7RdacX/aLOhgTNEwj3Aqgk6RYF8n+xUQe+AOylpgO+zovEWsBWQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG4DCCBcigAwIBAgIQBJs5bzwFPCdTNiFgnspdPzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTExMTIwNzEyMDAwMFoXDTI2MTIwNzEyMDAwMFoweDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTE3MDUGA1UEAxMuRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug SW50ZXJtZWRpYXRlIENBIChTSEEyKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAPV3cVm0AV6S+NNNeEAWTXr2L/bPxehYyaqT+qJXWgg11KqFHYwakBAy +r+GDD43kaQ/9sDXzG460l97g9FubatBdl0rOKBeXcDK62I/yPwSt3O0hUUe7Ryg wAzhOHYy0SYNJklXH40MwHWV3I3IKm3ApvhSpcAXoDztawEa1/xjT1gpruL/vwdI MCptGmzE10f1KjEPxyB/8l1fNy6fHTLBBgWOsZ49X9PryU7LArzwEdT6/AfHUvYp vRPJRJEXcZDA6cjevzEsQ/ZcayAdkd9nViY+vDOlqAhRzaGN5xRO/cdVjmNY5hZO Bg9e/L27YkcLWMRnksSHETq0ZqxYULkCAwEAAaOCA3AwggNsMBIGA1UdEwEB/wQI MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr BgEFBQcDAjB/BggrBgEFBQcBAQRzMHEwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw LmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcwAoY9aHR0cDovL2NhY2VydHMuZGlnaWNl cnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNydDCBjwYDVR0f BIGHMIGEMECgPqA8hjpodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRI aWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMECgPqA8hjpodHRwOi8vY3JsNC5kaWdp Y2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMIIB0gYD VR0gBIIByTCCAcUwggG0BgpghkgBhv1sAAIEMIIBpDA6BggrBgEFBQcCARYuaHR0 cDovL3d3dy5kaWdpY2VydC5jb20vc3NsLWNwcy1yZXBvc2l0b3J5Lmh0bTCCAWQG CCsGAQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAgAG8AZgAgAHQAaABpAHMA IABDAGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBzAHQAaQB0AHUAdABlAHMA IABhAGMAYwBlAHAAdABhAG4AYwBlACAAbwBmACAAdABoAGUAIABEAGkAZwBpAEMA ZQByAHQAIABDAFAALwBDAFAAUwAgAGEAbgBkACAAdABoAGUAIABSAGUAbAB5AGkA bgBnACAAUABhAHIAdAB5ACAAQQBnAHIAZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgA IABsAGkAbQBpAHQAIABsAGkAYQBiAGkAbABpAHQAeQAgAGEAbgBkACAAYQByAGUA IABpAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgAGgAZQByAGUAaQBuACAAYgB5ACAA cgBlAGYAZQByAGUAbgBjAGUALjALBglghkgBhv1sAQEwHQYDVR0OBBYEFLJPiVmK Jf/LxZ6wPaWfJNWGmLInMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9jZCvD MA0GCSqGSIb3DQEBCwUAA4IBAQCIkWB39quTd1vAFRPdrxV6sQvJ/nG/sySB594b oSo/MHP4H1s6E7aEsqVdF1c7nxlfRPUQZEqA6xg5pJO1BQhon6t9PJmq4DcZgbbb n+Dp2tf2QZcyHhDBS0z2XnZ9kVJmoPm3BHUb+DsV2G63UHxSXRXb3OVUr4gPFk/M QpqYwct49DQgv0VJt+CRbrFkVCnQ3eSapaSjlCBOGGJavzRMDvOA1IyuZgHSVDJA dE51dDhXthAkpGlBNb1dET244UWfLgvriDSpUcMDXflLJoogfdIVCyZP1q2s61P2 M6pQqSiXJ4SJ8dSrTsvRKjO4f8PXghmlAsOMIPDUgJ3qPaU4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG5TCCBc2gAwIBAgIQBDg2SqweGZEe3TK+yl8pgzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTExMTIwNzEyMDAwMFoXDTI2MTIwNzEyMDAwMFowfTEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTE8MDoGA1UEAxMzRGlnaUNlcnQgRXh0ZW5kZWQgVmFsaWRh dGlvbiBJbnRlcm1lZGlhdGUgQ0EgKFNIQTIpMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA0wR3ZUFwVvqAMwSmruMs9Uox15uVX1umQ4riFohwlP67Ji5j U/pHezGliChqkkbw9X3NGA7TuaaET0U0vRov1FlD1sc1McgybOCoINx+T/Rp/OXh 4vCIIfPycD8nk+bpT9JL7Yw4yBzEk5lep0Dio50ugTgxUz461TtM7QKm7emasHyh LZxhszCkkQVro85DViEWCO4u4XfXiDyELsi2tN3CTqE0elq7pRgg5eA09W7zlxDz 6enVytBeTWOBNsCQ6jhMIH2lFQy6x/4Uisbps4skhSiNt8OO1UwBGqjNpLMWXIyR EaNgSCTyaQmN29i0wxmmjYg4kpxXDWCKyEsSZQIDAQABo4IDcDCCA2wwEgYDVR0T AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMH8GCCsGAQUFBwEBBHMwcTAkBggrBgEFBQcwAYYYaHR0cDov L29jc3AuZGlnaWNlcnQuY29tMEkGCCsGAQUFBzAChj1odHRwOi8vY2FjZXJ0cy5k aWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3J0MIGP BgNVHR8EgYcwgYQwQKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdp Q2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwQKA+oDyGOmh0dHA6Ly9jcmw0 LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmww ggHSBgNVHSAEggHJMIIBxTCCAbQGCmCGSAGG/WwAAgQwggGkMDoGCCsGAQUFBwIB Fi5odHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRt MIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABo AGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0 AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBn AGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBs AHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABp AGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABh AHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABi AHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCGSAGG/WwCATAdBgNVHQ4EFgQU F0HMBW+uBFMqTKVexlNg1CPltbQwHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC 72NkK8MwDQYJKoZIhvcNAQELBQADggEBAFqM0L0QQWl6Vl5IkVgezOLHYkpf941d on+lbD7qgn4z9DAhvVBZ84/spUi5Oa0FxXsgRYd5Peq8c5auw8Fxl3I3zGnTmzBF Cst+x9/m2O82jZcH3WdolEuY2z553F3B6YgaA0hhSO8ahQ4rn+m37xLRQ+vwW5WL +NUZM7qn+Fs0iVNOVOT/A/fyV51oUOOOvIa6T58Uf6EEdghvycFVDEaZR/da+f3t xExZgDlSfS9dZ+RuII1BTrq+LHFcdgfZMhNyTaxfcpxqiJ0iYAqn89AFI55hTMci gdyNItWHp+NzugB7IqH2E3i354m4+V2xh9ExeSddCcKQoH7hn9QElpw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGyzCCBbOgAwIBAgIQDFWl6NPPT7NZ8Asrci/u+TANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTExMjA3MTIwMDAwWhcNMjYxMjA3MTIwMDAwWjB0MQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMTMwMQYDVQQDEypEaWdpQ2VydCBBc3N1cmVkIElEIEludGVybWVkaWF0 ZSBDQSAoU0hBMikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1Pfaw mfyykGMCYkrzuTq8YyAQRK+0Z3gL/ZgBB61UCuJKTiVk37A/fk6hspBMocyK5vAC Y8qSvRDqWMLwaKgwBFiaZ0L/lXcB5sLfmGhYJ0erdpxkxeeKFKrW9ejuallqtB2P f6cGsF4EuhodC9T/+9qCf12UZxslBKrhJs4GNWrHJF3sPNaa7ya5I6AovvowhQLh VlSBaUk0EgNayCW5XbpY81d8lVZJoDMTHhKCZwF0bHKLrp5bVRPGrYnJXw8gdO1x qIr2L6jVnqL1yx0qj5UpWBr025HsM3ORuJCKkTj9Aj6ufxKZjGEA+iZVR7wrK6x1 e1A21UaG8X+QK8ixAgMBAAGjggNmMIIDYjASBgNVHRMBAf8ECDAGAQH/AgEAMA4G A1UdDwEB/wQEAwIBhjAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsG AQUFBwMEMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au ZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2Vy dC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqg OKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS b290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNl cnRBc3N1cmVkSURSb290Q0EuY3JsMIIB0gYDVR0gBIIByTCCAcUwggG0BgpghkgB hv1sAAIEMIIBpDA6BggrBgEFBQcCARYuaHR0cDovL3d3dy5kaWdpY2VydC5jb20v c3NsLWNwcy1yZXBvc2l0b3J5Lmh0bTCCAWQGCCsGAQUFBwICMIIBVh6CAVIAQQBu AHkAIAB1AHMAZQAgAG8AZgAgAHQAaABpAHMAIABDAGUAcgB0AGkAZgBpAGMAYQB0 AGUAIABjAG8AbgBzAHQAaQB0AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4AYwBl ACAAbwBmACAAdABoAGUAIABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAAUwAg AGEAbgBkACAAdABoAGUAIABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAAQQBn AHIAZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkAYQBi AGkAbABpAHQAeQAgAGEAbgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABvAHIAYQB0 AGUAZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBlAGYAZQByAGUAbgBjAGUALjAL BglghkgBhv1sAxUwHQYDVR0OBBYEFHZlxioFq42GeSV8dFfqsb5artRsMB8GA1Ud IwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQAF JsDacbiTq4/viEvl0MZiFvaT0SvqFj3InYEd1aCCcSja8QccOb6kcv6NR+6NlCBY I/AZAEkwgAMJt1LwrFCKjIHn/K0j39J9MbOPSVqA5CWUx9BdCWNq9mitaBQXcmiB XQDbMVAMftB43hGMkcyL84AwTC3HrAzqvbpsZRLks1oTvArEYaN4vcUyJDIFTpTI oTaTDg002st7JWhcH03rIEVwC0bpWY+eFEUAkkdosrkdjjjMUlPuDusyRnYHx4s6 XG4ueoHKTnPW6BUGFjUlHz6bq6t2uNIkCI5D8I3RuGpsHfW6MquIstjGDc4dJvdy KmbyMb4zizt9jv3AH4FD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDjCCA/agAwIBAgIQBqdDgNTr/tQ1taP34Wq92DANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTIwMjEy MDAwMDAwWhcNMjcwMjExMjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQg VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAlVbeVLTf1QJJe9FbXKKyHo+cK2JMK40SKPMalaPGEP0p3uGf CzhAk9HvbpUQ/OGQF3cs7nU+e2PsYZJuTzurgElr3wDqAwB/L3XVKC/sVmePgIOj vdwDmZOLlJFWW6G4ajo/Br0OksxgnP214J9mMF/b5pTwlWqvyIqvgNnmiDkBfBzA xSr3e5Wg8narbZtyOTDr0VdVAZ1YEZ18bYSPSeidCfw8/QpKdhQhXBZzQCMZdMO6 WAqmli7eNuWf0MLw4eDBYuPCGEUZUaoXHugjddTI0JYT/8ck0YwLJ66eetw6YWNg iJctXQUL5Tvrrs46R3N2qPos3cCHF+msMJn4HwIDAQABo4IBaTCCAWUwHwYDVR0j BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFDna/8ooFIqodBMI ueQOqdL6fp1pMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMD4G A1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5j b21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAERCnUFRK0iIXZebeV4R AUpSGXtBLMeJPNBy3IX6WK/VJeQT+FhlZ58N/1eLqYVeyqZLsKeyLeCMIs37/3mk jCuN/gI9JN6pXV/kD0fQ22YlPodHDK4ixVAihNftSlka9pOlk7DgG4HyVsTIEFPk 1Hax0VtpS3ey4E/EhOfUoFDuPPpE/NBXueEoU/1Tzdy5H3pAvTA/2GzS8+cHnx8i teoiccsq8FZ8/qyo0QYPFBRSTP5kKwxpKrgNUG4+BAe/eiCL+O5lCeHHSQgyPQ0o fkkdt0rvAucNgBfIXOBhYsvss2B5JdoaZXOcOBCgJjqwyBZ9kzEi7nQLiMBciUEA KKlHMd99SUWa9eanRRrSjhMQ34Ovmw2tfn6dNVA0BM7pINae253UqNpktNEvWS5e ojZh1CSggjMziqHRbO9haKPl0latxf1eYusVqHQSTC8xjOnB3xBLAer2VBvNfzu9 XJ/B288ByvK6YBIhMe2pZLiySVgXbVrXzYxtvp5/4gJYp9vDLVj2dAZqmvZh+fYA tmnYOosxWd2R5nwnI4fdAw+PKowegwFOAWEMUnNt/AiiuSpm5HZNMaBWm9lTjaK2 jwLI5jqmBNFI+8NKAnb9L9K8E7bobTQk+p0pisehKxTxlgBzuRPpwLk6R1YCcYAn pLwltum95OmYdBbxN4SBB7SC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE9TCCA92gAwIBAgIMLuujs6+RGksxvbEKMA0GCSqGSIb3DQEBCwUAMIGCMQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEf MB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0xMjAzMzAxMjAwMDBa Fw0yOTEyMjkxMjAwMDBaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBl c3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHlF1YWxpZmllZCBl LVN6aWdubyBRQ1AgQ0EgMjAxMjEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWdu by5odTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANdZaWRow9po+j0m A658maAb6LaU8VYvjXOAxkph0zBNehDWmMjtKufqYULB8NBZ0cwrAW3T/ImzudYI sneP5xV4Ma0frUcdmJn8el4DFgu9/8SN30WKpXvFJH1tYvas/hMtXvc67P/c6ehe 3u8Uhot2v7qT3isGoemXuS3I8E/Z3uEKvvc80zkLHcOjChM8gndJ1M3a4x8d0Hbj EN8HBxys8NgOzFf1DGWGlMZgO4duuoHwFeLBz96WthepVZXqJm0hza38FYYlKLPN TwrXK8NYprSfYwGgxJOkoyUQ9EIgWe0O84DafrTCo54B5pY/HW45HrdjWgrI8h6s 9MdytqsCAwEAAaOCAWcwggFjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD AgEGMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3Au ZS1zemlnbm8uaHUvcWNwczAdBgNVHQ4EFgQUzD1G6GUAu+rDvc+3iOGV/1N5o7Qw HwYDVR0jBBgwFoAUyw/G30JDzD3LtUgjoRp6piq7NGgwGwYDVR0RBBQwEoEQaW5m b0BlLXN6aWduby5odTA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmUtc3pp Z25vLmh1L3Jvb3RjYTIwMDkuY3JsMG4GCCsGAQUFBwEBBGIwYDArBggrBgEFBQcw AYYfaHR0cDovL3Jvb3RvY3NwMjAwOS5lLXN6aWduby5odTAxBggrBgEFBQcwAoYl aHR0cDovL3d3dy5lLXN6aWduby5odS9yb290Y2EyMDA5LmNydDANBgkqhkiG9w0B AQsFAAOCAQEAgaJ7B9CTqKP0UwqUYz0ALi29Xu4n0ls5qhu2/bvmb90/7WLwNLxA PQLkINtaB4HCdhv1WVavZnJznhNaajseJtZ6J4x3GInhBBxspyAQmUdC2nLu0NGM uIS5KbyXo7CdiLyiY+plt1seqVfMlDs9WtXEqg5kvu2DCbwEQ9v0vr5a5SCgqHik Q/uEMyUSAKCYzsd7F8nMaay4r6O5D6Tnzq18i4Hb5jfy3JVYMfzPJxc5ZQrQ4M5t /fb6IJLWhLESze3o47Vag3WjOPXQe97kGOLTQh86hjGbSqj8C0/2isTORVL/vQWX GAGEbZckkjtKwJpSurhpozWCucCQwK7FFg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFUTCCBDmgAwIBAgIQUkslvRLtjP5PjTe7wpuofzANBgkqhkiG9w0BAQsFADCB 8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoMMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLDB9TZXJ2ZWlzIFB1 YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLDCxWZWdldSBodHRwczovL3d3 dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECwwsSmVyYXJxdWlh IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMMBkVD LUFDQzAgFw0xMjA0MTcwOTI4MjdaGA8yMDMxMDEwNzIyNTk1OVowgfMxCzAJBgNV BAYTAkVTMTswOQYDVQQKDDJBZ2VuY2lhIENhdGFsYW5hIGRlIENlcnRpZmljYWNp byAoTklGIFEtMDgwMTE3Ni1JKTEoMCYGA1UECwwfU2VydmVpcyBQdWJsaWNzIGRl IENlcnRpZmljYWNpbzE1MDMGA1UECwwsVmVnZXUgaHR0cHM6Ly93d3cuY2F0Y2Vy dC5uZXQvdmVyYXJyZWwgKGMpMDMxNTAzBgNVBAsMLEplcmFycXVpYSBFbnRpdGF0 cyBkZSBDZXJ0aWZpY2FjaW8gQ2F0YWxhbmVzMQ8wDQYDVQQDDAZFQy1BQ0MwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzIsdP4pdClYhHg0D2HRfzg3Mk HlHzmIrDkrj/QJAFcIdgyQCptZRlGSIVF8JDbGZEmg0EPjlvpUt6qmO3ikSd2WOR hGbgKA+6QuNujvcUJ5Np7pEOo18OsetmonJPEhOGZXo+208H9KcJYNo6QpnHsn+z FpUcx/k0tZSF1ZleoEigfucXZbiidbge8+VCfa/t84pIZF2CFJPYwOT/s1By8nb2 s11CUHnQlD5rDAC+2GsOTirsPtLMgqIYZTMTd56aXRoT2MPbPciXeu5w7afmfNtx zy2UYt9t1vU4vj+lhQoZuKjYCXVCcMTq78sOyDSoEiKYDLgTlLZL7PDQkOcnAgMB AAGjgdwwgdkwHQYDVR0RBBYwFIESZWNfYWNjQGNhdGNlcnQubmV0MB0GA1UdDgQW BBSgw4tEqjelRb+XgFrR8Xiim+ldjTB4BgNVHSAEcTBvMG0GBFUdIAAwZTAtBggr BgEFBQcCARYhaHR0cHM6Ly93d3cuY2F0Y2VydC5uZXQvdmVyYXJyZWwgMDQGCCsG AQUFBwICMCgMJlZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVs MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUA A4IBAQCuCj5s6vy9ssW48Scaqw7OHy0y2j9mOr789BscMkVIcILiu0DORgTi9rh6 UyFkBv+nq0eDW6KMFy+yZ/N4ni0QNr15bM3BYJtIXU8QfAo/GzEmqzzxHN15FKBi j+rnUpNKOoMSWXMTQedoTGfFv0oZDCALOxAOK+DSMV5HO3chfoIWVzy66DvmwtfX NOz3Gdx7UvqiRYj4UqR4rAmmdzF58nYbUgZLE1cbmr3nS3zSuOfOFh6euoaDEDFY rn/1xSXkW4z456p1FWhSb9jxsnXxTcI6wzjzROLdhJ3cr68qXj0aEimYicyF8Sdm 1TYR6egIdfqyT6q8gx0Eac8DeniY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGUTCCBTmgAwIBAgIQIqW4gO46S81PjTpHBA7mUTANBgkqhkiG9w0BAQsFADCB 8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoMMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLDB9TZXJ2ZWlzIFB1 YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLDCxWZWdldSBodHRwczovL3d3 dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECwwsSmVyYXJxdWlh IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMMBkVD LUFDQzAeFw0xMjA0MTcwOTM5MThaFw0yNzAxMDcyMjU5NTlaMIHpMQswCQYDVQQG EwJFUzE7MDkGA1UECgwyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g KE5JRiBRLTA4MDExNzYtSSkxLjAsBgNVBAsMJVNlcnZlaXMgUHVibGljcyBkZSBD ZXJ0aWZpY2FjaW8gRUNWLTExNjA0BgNVBAsMLVZlZ2V1IGh0dHBzOi8vd3d3LmNh dGNlcnQubmV0L3ZlckNJQy0xICAoYykwMzEhMB8GA1UECwwYR2VuZXJhbGl0YXQg ZGUgQ2F0YWx1bnlhMRIwEAYDVQQDDAlFQy1HRU5DQVQwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDfskLh9womX5uXcd8X/lkEJSFSN05O8RDoyGrKH9H8 qADjvjZKmKY+4wJrlZpMwZ42UkHfa4qpcBK0x1lH5x3gr6qSpW1XC9PjJLCkUQI4 Uy+CCbINZ2dwwskeLHZJngYm0KlcRLTlzmppjW4YDimLkpRsjP8WDp/l0zaUP2cz fOrIwsor2c6PPQVJ/Oxmi+fcS9rbWTGRf1EzKKGTG1TxoFNvb6bWiYfYj1ILJC+L j39gVDi1JRCbPd+Vl5RCwVXieouKbyWQXc5kW5HUeWAhfnDcHlI4SDLI3u60GpfZ SCwIFKhsvgSJ26EhfJO0bzdyDDBTfVR6NgFMcXZ0f/7jAgMBAAGjggHnMIIB4zAd BgNVHRIEFjAUgRJlY19hY2NAY2F0Y2VydC5uZXQwIAYDVR0RBBkwF4EVZWNfZ2Vu Y2F0QGNhdGNlcnQubmV0MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MB0GA1UdDgQWBBQxalwKRk43r0LjsGArDA8tL5PfFDAfBgNVHSMEGDAWgBSgw4tE qjelRb+XgFrR8Xiim+ldjTCB2gYDVR0gBIHSMIHPMIHMBgRVHSAAMIHDMCwGCCsG AQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJDSUMtMTCBkgYIKwYB BQUHAgIwgYUMgYJBcXVlc3QgY2VydGlmaWNhdCDDqXMgZW3DqHMgw7puaWNhIGkg ZXhjbHVzaXZhbWVudCBhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpw7MgZGUgQ2xh c3NlIDEuIFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlckNJQy0xMGIG A1UdHwRbMFkwV6BVoFOGJ2h0dHA6Ly9lcHNjZC5jYXRjZXJ0Lm5ldC9jcmwvZWMt YWNjLmNybIYoaHR0cDovL2Vwc2NkMi5jYXRjZXJ0Lm5ldC9jcmwvZWMtYWNjLmNy bDANBgkqhkiG9w0BAQsFAAOCAQEARl4OqmtANC7EilelFfFP9P6VigiBnaSLwR0o KBPKEn79OFDGC5v1d2naoEeU+ftwoLZWl+yBfPztS6FdUWp6ZQDxTKgLKFG2ASj6 0CELWF9NHDZHcEqokBpFXHxIiAZnlsN/PdhSQ8U6Z2fVLa2GwiVm8U9FMnxjtjjN aC7Cp8aHGj8dXtvYM5y0zGE/pzMrBUywDiSpLIsbvkS8aCQIUQJiS1Y9/qIwZlco myg6lGMPegoEZJFyU5uV8AfnmtH6UvF+FIyAjx0/IkX4AyjbnF63kK0BMCEynNnV MZqqGTEkSvWqJDIHbYgfxjBGM95qLVY6D5qNag/Hn89Pd1rfgQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGJDCCBQygAwIBAgIGSUEs5AAkMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTIwODA3MTUxNDQ4WhcNMjcxMDIzMTUxNDQ4WjCB rjELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxPDA6BgNVBAMMM05ldExvY2sgS8O2emplZ3l6xZFp IChDbGFzcyBBKSBUYW7DunPDrXR2w6FueWtpYWTDszCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMN+2w/Zz+1elBNAxiA55+rnStTtvsWXgD8iAjr/nzpN wU//XGOvlfmVuBc8FD64Eq4msk1Ooc6pHKbROwWjMf0jI2hL42T4uWHLbF2uqbYS +VxqLPkng4aRxQawOEdR2oQnPoMZEqeYUnwSF2ws3mY5OuTevPl7OYHFlBroZ1/m R+rWkTn7FdCyADE4yHVpRdaj4eRqEfO8D01+nvbOOcRA/I6Y32phgaeNsK+T9BMw Ug9DE4DXja1D6Nhopjvw/KaVn0BJdfi/xJMJIXTltOXgkqxLDWb92YOrUjNkIlZJ epQm3RQhSPBUe3u2DSnbpN3s3KK+uWkG2PuBO71cHT0CAwDlLaOCAkswggJHMBIG A1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFMz6 Z5PwtrjQpcAe81P9jFPfg9eWMB0GA1UdDgQWBBSIaNg7dzegKUss1glot4CJi1fU 6jCCAT4GCCsGAQUFBwEBBIIBMDCCASwwLAYIKwYBBQUHMAGGIGh0dHA6Ly9vY3Nw MS5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRwOi8vb2NzcDIu bmV0bG9jay5odS9nb2xkLmNnaTAsBggrBgEFBQcwAYYgaHR0cDovL29jc3AzLm5l dGxvY2suaHUvZ29sZC5jZ2kwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWExLm5ldGxv Y2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWEy Lm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0dHA6 Ly9haWEzLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwgZ4GA1UdHwSBljCB kzAvoC2gK4YpaHR0cDovL2NybDEubmV0bG9jay5odS9pbmRleC5jZ2k/Y3JsPWdv bGQwL6AtoCuGKWh0dHA6Ly9jcmwyLm5ldGxvY2suaHUvaW5kZXguY2dpP2NybD1n b2xkMC+gLaArhilodHRwOi8vY3JsMy5uZXRsb2NrLmh1L2luZGV4LmNnaT9jcmw9 Z29sZDANBgkqhkiG9w0BAQsFAAOCAQEAAJi2V4A3lP1g4+aCEn8frKrhS4fhqmPf SCcFoj605cYEAD3/Z594FICYWE9Ij4JefsvGHFotzueSpCVgrwEWFTmbVZJmd4yM +1AnZtvRxLmcolDWOQQngjHi+A+a3BGR4BV2Yyht07yJhVyzBC33nT1KO1K8aaCe ED5KU2chvHruVAIFQlxuujqkL4oHQ3nPNio7hhE2rmxUdnxnGZ9XLzxcLm32saAg XN68PUGsD9uH57nwPhokt/tpu8jhRSsbhPfB817tatL8F2vYx4wh6hQpS0SfbYJb 9Qj/kjLzCNjKasB9OibwkeEdgtFI0qGtMbwcBXedoMaszxAYU5lnvA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGLzCCBRegAwIBAgIGSUEs5AAlMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTIwODA3MTUxNjU5WhcNMjcxMDIzMTUxNjU5WjCB uTELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxRzBFBgNVBAMMPk5ldExvY2sgS8O2emplZ3l6xZFp IEVhdC4gKENsYXNzIEEgTGVnYWwpIFRhbsO6c8OtdHbDoW55a2lhZMOzMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuGgUSEOm5EPaVrTNl/OuWfgmNHAV th/QCdtdCHC2LYgSS+1U5waxj2eM+Kc/1rWzed9uHPCg4RIcKqA4jwWRU2/v4jvP mv94M/n3vZrSkOy8Zvn0TmYmoggtbTZGpti7r6XOfQzWXPudiryrFeifPswsftTU yROo+XIb+OkuQQ1ZMcUzBIQzoYokgTW3PGVKEbGtZzqSSUJlN0OU/bI4UpFvIF6D jec4Ci4I8o0xnoXA2mVaeUEYO694my76nNhY7VqCc7Gp1iixD84AwAfQapByMX4z mH352LCG6y/1Zl0DQA7M9Pti6by8ikSZK9ugKTcWIRnrcScM//oyrjs/qwIDAOQB o4ICSzCCAkcwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwHwYD VR0jBBgwFoAUzPpnk/C2uNClwB7zU/2MU9+D15YwHQYDVR0OBBYEFAxQWx5h6/aP n48rTeWio31HWE8nMIIBPgYIKwYBBQUHAQEEggEwMIIBLDAsBggrBgEFBQcwAYYg aHR0cDovL29jc3AxLm5ldGxvY2suaHUvZ29sZC5jZ2kwLAYIKwYBBQUHMAGGIGh0 dHA6Ly9vY3NwMi5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRw Oi8vb2NzcDMubmV0bG9jay5odS9nb2xkLmNnaTA0BggrBgEFBQcwAoYoaHR0cDov L2FpYTEubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0BggrBgEFBQcwAoYo aHR0cDovL2FpYTIubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0BggrBgEF BQcwAoYoaHR0cDovL2FpYTMubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDCB ngYDVR0fBIGWMIGTMC+gLaArhilodHRwOi8vY3JsMS5uZXRsb2NrLmh1L2luZGV4 LmNnaT9jcmw9Z29sZDAvoC2gK4YpaHR0cDovL2NybDIubmV0bG9jay5odS9pbmRl eC5jZ2k/Y3JsPWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwzLm5ldGxvY2suaHUvaW5k ZXguY2dpP2NybD1nb2xkMA0GCSqGSIb3DQEBCwUAA4IBAQA1wvArJrUDXY5wXOvV mFbw2PAaRfJicuMJw2NMHk3WJgYBI77YG3BHIaV5h1RKmP/VKyfBKU15UjBG+gpw dYQODgNPFWupU+DzdxBStDVMWzoZISAA3nvqoJteqXBmZmyAPXk+KDyLJmUIarWj kLvVmnofnwTyIIRkX5oqoClN+w3naAQ+wOIH1qmAVUbsGaOWi+i8Nqu8ktV4+Rq4 m5g7Or/ZArZZ8hhiwyntsISsXXbFsPMPgJuIwCYf7MV/qBP6ZjHxtGEULQAezxyZ rGTMWvJ1LMWw/7WblPgV739EuMnTsNFtShcZOlL70XbR3eYUIu99Py6lrpr6pniG wc43 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGLTCCBRWgAwIBAgIGSUEs5AAmMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTIwODA3MTUxNzQ4WhcNMjcxMDIzMTUxNzQ4WjCB tzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxRTBDBgNVBAMMPE5ldExvY2sgTWluxZFzw610ZXR0 IEVhdC4gU3BlYy4gKENsYXNzIFEgTGVnYWwgU3BlYy4pIEtpYWTDszCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAOYZUAp5mC9slm3LcctPL8BYsbSxB8T3 Emcl6vDRwIbrZEuNjGOhucK/46K5Xs6xcWFewiyJ5Hg+0PjTYh2bQvOmU6F47qrl EfGdfYBrrI3A5LFj0nISSmlSq2H7Rv17pJPgXAGXAhkM2Xf3zVfA6gAk5yS85Qlz ub9AuisNVRliyzAYUyQQFjlwlsfLmoPDAj7GT5r9XMildLZXv47ZfB2h4Yu68vM8 EgHiS6oi6og6oV329Q4sdkTbm/ojydMEZZeI1msrAxh/wTRIj+S/vgQ1zGCc1Vu1 a/tGqhhi4Bo+fkosx37QrN8fIpeqtCNhoVqa3h8N9cd8cDJJOeq29/ECAwCxZ6OC AkswggJHMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0PAQH/BAQDAgEGMB8GA1Ud IwQYMBaAFMz6Z5PwtrjQpcAe81P9jFPfg9eWMB0GA1UdDgQWBBQlanRbVSu6f2+r Hoso2OjoW76twjCCAT4GCCsGAQUFBwEBBIIBMDCCASwwLAYIKwYBBQUHMAGGIGh0 dHA6Ly9vY3NwMS5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRw Oi8vb2NzcDIubmV0bG9jay5odS9nb2xkLmNnaTAsBggrBgEFBQcwAYYgaHR0cDov L29jc3AzLm5ldGxvY2suaHUvZ29sZC5jZ2kwNAYIKwYBBQUHMAKGKGh0dHA6Ly9h aWExLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0 dHA6Ly9haWEyLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUH MAKGKGh0dHA6Ly9haWEzLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwgZ4G A1UdHwSBljCBkzAvoC2gK4YpaHR0cDovL2NybDEubmV0bG9jay5odS9pbmRleC5j Z2k/Y3JsPWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwyLm5ldGxvY2suaHUvaW5kZXgu Y2dpP2NybD1nb2xkMC+gLaArhilodHRwOi8vY3JsMy5uZXRsb2NrLmh1L2luZGV4 LmNnaT9jcmw9Z29sZDANBgkqhkiG9w0BAQsFAAOCAQEAgk0055TzV0LLTjbYUgY+ iNPubfJI06LNsbXWWpfiRrg04lb4QpQ/zBelr+F8/MFyhqpmg2U9piKbjSuGSGFF 5Ecx9kEEFovsXnpaqwTCuPtjyMyPVSE9q93Wcm/r+gCYIi7eyaEAnZSBRFOOpCKY 92Qn6CLdvQXCUUFiAWKsf7oO4sGWadETaUbd8CEHIxU0wa0p/sPnBXHouhG1ro/+ iVdpyhA9aDhIN+QKYn31bTgfBZKw717aFhNY7DFQDKSDZuCH6gsVW0CaS0yW9rww GnRf1DnMVceB1YuOoc8/0QlCOdJcY0jpcS7I0Wms2gUbwfxBOssyn/3CI/tVeDUr yg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGJjCCBQ6gAwIBAgIGSUEs5AAnMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTIwODA3MTUxOTA2WhcNMjcxMDIzMTUxOTA2WjCB sDELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxPjA8BgNVBAMMNU5ldExvY2sgT25saW5lU1NMIChD bGFzcyBPbmxpbmUpIFRhbsO6c8OtdHbDoW55a2lhZMOzMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA2EBEPugzYpwttDtnOJ+MgN0r+RvJUG9EWFHoEfCN M6z/7C2Iv93dq/wFj38spdjEQvqIZXSoKjN9zPrwDoKtcNTo4/fU+TcbQ9suVqhv f5a5rDDFmrsqnKtS6NGrn3iMcYDa8CN0JOEpZab2Hjge/Z+YhCimOMWqYKWuntsL qmYRsP2W0wf25rhIAR1JIbxzUvhGHhb/USNuM4sfqDFpoTIRQr451FEnxU/Ba5Kf tvQcanSSuIyRx2w4rZNWxdSQ4diLjyOX8Bt1sI5WWk7adG0t4UzyM3KLH//l6+x1 DedWz88LxQCZH9NQMs0yFblxmlIaXBbkKtfyjnHWIPkYZQIDAJOTo4ICSzCCAkcw EgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAU zPpnk/C2uNClwB7zU/2MU9+D15YwHQYDVR0OBBYEFJsVmOqyTPnqzIFXc8LaUel5 jO79MIIBPgYIKwYBBQUHAQEEggEwMIIBLDAsBggrBgEFBQcwAYYgaHR0cDovL29j c3AxLm5ldGxvY2suaHUvZ29sZC5jZ2kwLAYIKwYBBQUHMAGGIGh0dHA6Ly9vY3Nw Mi5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRwOi8vb2NzcDMu bmV0bG9jay5odS9nb2xkLmNnaTA0BggrBgEFBQcwAoYoaHR0cDovL2FpYTEubmV0 bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0BggrBgEFBQcwAoYoaHR0cDovL2Fp YTIubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0BggrBgEFBQcwAoYoaHR0 cDovL2FpYTMubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDCBngYDVR0fBIGW MIGTMC+gLaArhilodHRwOi8vY3JsMS5uZXRsb2NrLmh1L2luZGV4LmNnaT9jcmw9 Z29sZDAvoC2gK4YpaHR0cDovL2NybDIubmV0bG9jay5odS9pbmRleC5jZ2k/Y3Js PWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwzLm5ldGxvY2suaHUvaW5kZXguY2dpP2Ny bD1nb2xkMA0GCSqGSIb3DQEBCwUAA4IBAQATklNgusGMNdhxjqKKmHFFpbMMFq6z +sDCc/flLvX659Z/+JXpIJVjpfqHUR+d44L5HgaPdHcI0dhlvOvlIUKz2MzhVNiK ajJIdJ1Wd9Mf4BV3B3UzphFq1sGkhL0uSqsQ8JTEXi4aekr0Co4VTF2KtEb/wozI GWilyfl4rrXbRMug/AzEjN7qcmRchZKPzsu0AodMEOziRYou+/sfM3IjBa3uXj4u IUKMr+92CI51yMEtyiYinHxsPnnRDOXTpeNyM+FbwxujjQFO2WbbYShrR33zOwld PhDsKH22azkJFcOONZy29ggpabJ+Rf6opJz2ks17jJLQQeEBY7vPNyqb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFTjCCAzagAwIBAgIGALTPlDJmMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNVBAYT AkNOMTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkxFTATBgNVBAMMDENGQ0EgRVYgUk9PVDAeFw0xMjA4MDgwNjA2MzFaFw0y OTEyMjkwNjA2MzFaMFUxCzAJBgNVBAYTAkNOMTAwLgYDVQQKDCdDaGluYSBGaW5h bmNpYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFDASBgNVBAMMC0NGQ0EgRVYg T0NBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA02OMsGFxFQIPMKVP oRaO9rHNX41xbq8jhnbdK0MDVbxfGa3b8QTKxMcmxlRlULfsaie0cIlaRl0AUcJP QH9ftekzh4T287xqsEAydYQHf77arWQ5nY3fR9RcoBq9pTCQbqw49S6/jHA5oPQa EoKbF0G8zfVKp5PrcKSufHMQyKo/Ez2UYT+gut36j4GYpAABuV6PbusPpjufsN9B r9+xqgyz8ubSp1Wl1qSlvQUQBhAJAH+a3NMhD0illaGfTdWbF485a5NilMFGqJBa /kLVEYwG4aoKdV9vG/NFS0LKz3QVnB7bkrLjTkuGN/zQJP0daJ3CGAzmN+Cr2ujt XOfAYwIDAQABo4IBITCCAR0wOAYIKwYBBQUHAQEELDAqMCgGCCsGAQUFBzABhhxo dHRwOi8vb2NzcC5jZmNhLmNvbS5jbi9vY3NwMB8GA1UdIwQYMBaAFOP+Lf0o0Au1 uraixL8GqgWMk/svMA8GA1UdEwEB/wQFMAMBAf8wRAYDVR0gBD0wOzA5BgRVHSAA MDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMvdXMtMTIu aHRtMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwuY2ZjYS5jb20uY24vZXZy Y2EvUlNBL2NybDEuY3JsMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUVQji3MyV bR9d3rNH6OkWxsBFd8QwDQYJKoZIhvcNAQELBQADggIBAMmFEIoCE9UNmb2BYYhT RV12kNVucP6t683BaFTgJizIJw/ebvvTdWNTycyP5MQFlHKrIYwjvFO9Rfw8+yIs sT3JFYiqsLBswvaMr3AIuA2mTnmasvZFe6P19qitzTRkz+TL6TFailrtnzudsvn2 SeVbRiX+6CsyNNMoPsRHTeZAEpkB7J3vh+ZAiv3gsIXtjtz5Y1iWWRZipemJ/qEf W2hDONB+T6lGcEXHDi9dIkWcC/jFT4XPM64pagAz9gEGZg1PzFBE8QMxiwaDAOea G0l0e/HW4wJlo4ZzOELqZGJLlYhQ8AkBYR95NEtR9j5bWK98Lznykldk2MDLBD2m rIfMkVjMwEj4A8ElMXsLnWXXg41NN6gjUm2/IudKOaGqniPs5SZrN36O4B3NzsaZ dLznHH5H0+aksurjgme8RAG0A2OAnRG3VXBWrxud7t0KDINLs+mxY7IR+xVZ2cw6 Cer8HnAVfKPJrbdq7vyJJkIpCll+mLHaGgvv3IqiU4rrrllE3NYjKG4Fk2MiYvZg 10KXA8tlYsLt8I/RcNmC2TvjZHYVE3tanbGw53TRGFk2Vq68XOkvooOardihwRkg qcOgUvouORuvSqTlkQizTFH6FTUt3xuuED4dnn5N/1ijcDt0N3l5ovoyHOVcYiO4 drCN96LHiUoiSfYODmpXG2tl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdzCCA1+gAwIBAgIQQAEzBPcAAAAAAAAMwELNbTANBgkqhkiG9w0BAQsFADBR MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 IENBMRwwGgYDVQQDExNUV0NBIEdsb2JhbCBSb290IENBMB4XDTEyMDgyMzA5NTMz MFoXDTMwMDgyMzE1NTk1OVowczELMAkGA1UEBhMCVFcxEjAQBgNVBAoTCVRBSVdB Ti1DQTEcMBoGA1UECxMTR2xvYmFsIEVWU1NMIFN1Yi1DQTEyMDAGA1UEAxMpVFdD QSBHbG9iYWwgRVZTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7MIaeq4wMnTjA5C2LsR6HJUj6rZbs8Nmq sSqFoqu6LwjrMbzkAg274EL6913MQ6eOy6VUDRzqAfgBEYcwFofe/w8nC7Q6Nrzz xTkl9lovXLJIm0CI44Qk2IhiCkoYaPlIoqexqnm3Fc2QRdRNeLk2pU/s86DpGrwT BqRRRkziBlhcgo7K5Z9ihf+c82DT31iIUIi2nr0ES1eaRR7zpKrzJPZ8foNxRPwT 2D0tJWQJ4hNzbFGSKsSzshdwQ/p4JP9AEjK2eeXXbEePt0/JarwBjO2Lwign38/g 0ZiP3uE47bItxZhgXlnR5L/0bhJitE6U1xgVFbbrQnG2B2kZxVKxAgMBAAGjggEn MIIBIzAfBgNVHSMEGDAWgBRI283ejulJclqI6LHYPQezuWtmUDAdBgNVHQ4EFgQU br2hK87kwtUodFy92YxvBHIqBt4wDgYDVR0PAQH/BAQDAgEGMDgGA1UdIAQxMC8w LQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRwOi8vd3d3LnR3Y2EuY29tLnR3LzBJ BgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vUm9vdENBLnR3Y2EuY29tLnR3L1RXQ0FS Q0EvZ2xvYmFsX3Jldm9rZV80MDk2LmNybDASBgNVHRMBAf8ECDAGAQH/AgEAMDgG CCsGAQUFBwEBBCwwKjAoBggrBgEFBQcwAYYcaHR0cDovL1Jvb3RPY3NwLnR3Y2Eu Y29tLnR3LzANBgkqhkiG9w0BAQsFAAOCAgEAaOmLaZ2+WN2EtB6feuSV5KnL88ck I9jsUTB4YtKsv0ViORkeBMCQur5OoAgRE9VYdRVlWHN0zJAX232fdoZmnajl8gtj u0AOOyDDJ7Vlh38rDMRlX/u+MS2DFcsq5Vd3EMwJsWWFR9D3Dcey+Tu9uEmEdqeB +Erd4YjCeV9PyOW3SzPQ47RdW6XYmHArPh65/LcmSxTn/lxQy/NEBGGWqhm6s6n1 49mPq4MtQcMLo/NBI+8jv7BVjnThbbEh2edHHxMNiAd5kLZFDCyJuFkoezjWL4AH ratXdoHtqvqtPoy97LyGrLrJeh+0hkO9u8QOt2gF7BEhNfid7o5dnsPRk+8l77Hn T1dvBs++M0r0QG4AWMSMj9uUn6rhl4FGTvAsyB1fA8p/xCLoIEetIpKRP3BD+ve2 eYjWPorR/0W77iMTeoQEeuxDIxi2J/U9QLKKvzzqBy1TYrqqPe5YxqHLNAcfHZvo BTPPbtP0WAiXrJiELTYcqFXETvQcGw0XjoUZNvJE8RD7vssSNT17RKU8iBRX7CbL AB3T8gYykPMJTUqQSmdgEdVRBcqRMMdU+XRAEoU/Mz5oHAkm3ZNTDNwsEp2Dg1/b qzfPMhg4/3/YyWzGrzNeCSWZkjYImAzLCvN0D5rbdVHEmFIrEJt+igocGozroq5x DT5KhixlrqexzWE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEyzCCArOgAwIBAgIBHjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMyBSb290IENBMB4XDTEyMDkyNTA4MDUxOVoXDTMyMDkyNTA4MDUxOVow SzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0w GwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMzCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAON6Gk4TsoAn39gyUXBUfjcLNaq1FLlq2mSqt7l4EUALQfwf w//3jcKPb70rGYD1Mw46shRoL2gFJP3mD5FYe+5pAKqJ1VRdFb/qO/HnYPPBx2vz bEJgOafCuBX6wEMJc0O8cTsv/MqLvW8K88S+ziZcTSXMo95XkYGcYyaQiS5PR1mz ATTvA/Xm811oCI8jZD2ZjSQ8KhB8ePaRNJTiOK/xYhqSvU9Un7i83NDSAeliZYW6 asJ7g2DUcFWDytHvRJQtvd6tTxn+PUThC+IlgDJc6riJaIhYBqENID6LsBLdkSGI KsxVDsjDOZ3568D1XaRH9Wlo6Hj0792Ncu7AqZUCAwEAAaOBtjCBszAPBgNVHRMB Af8EBTADAQH/MB8GA1UdIwQYMBaAFEe4zf/lb+74suwvTg75JbCOPGvDMB0GA1Ud DgQWBBTMw/gHt5xtek71pysdBfmzRxyR0TAOBgNVHQ8BAf8EBAMCAQYwEQYDVR0g BAowCDAGBgRVHSAAMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwuYnV5cGFz cy5uby9jcmwvQlBDbGFzczNSb290Q0EuY3JsMA0GCSqGSIb3DQEBCwUAA4ICAQAJ EHvXHhjk5VKHDDvh5R3eaNjLNXwK9FQ65TIjkeciZcO53wHqumFBJX0fI7bYOthY 1RZQElyefhn9SQlNDiPYrGwfbv94A1RQq8WHFpafUHoGjgmorgHoCRm/JKAjuFvE 5NYc1EW2h8rAtg2apNRXe+TrTfLHH4gNYD6+Rd9L7zI6RQRgO11lmaWmC5C6VdBJ fOtX/gCjpjOwhb9RXwKdGXlbCgpLlv5dhMcSjgxz7NJW3sjyWIhelt5vr7iK+3Xq e1mTA869l8rb7eDXHpavH/fOQYlHNWDSJQBkA6nbPpYwTy0FWOEdSTrrsb0NLyiF 6snEzMyoMIfezj1yZJO+ATnZXeIsnrIRW5kL2BmHG0FJ7Up/zq89trNh8eYFE2wP YKhAM3UZNT0jzLLpabJQEFCqoX3XEPYyAIYJzGbvnCYAPesy88MY9gZBVTCfNuyJ r1qrFn2B+fCwwD1ZCOcg3FHr0K601z+v4KWB19T1ui81cNWdadchU3UxH3i5ZJIi 8z8abzj8E8l4sl5SD8iyUW58OF+bScx+P+RG2+DPw7uHbqItCYlpl/+YXhKCeGbZ /mI4xHipWuuamnYzZcD1TJ2g+0J9aqLavrBrnhtR0tWS2gmds5G4yNxROB1uQLZP Fswq7WjfCUK3A8RrnNGcGPaCOf4BAou0GAiGo8kWwg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqTCCA5GgAwIBAgIER/j2qDANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQGEwJV UzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNl Y3VyZVRydXN0IENBMB4XDTEyMDkyNzE4NDIxOVoXDTI3MDkyNDE4NDIxOVowgaox CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJbGxpbm9pczEQMA4GA1UEBxMHQ2hpY2Fn bzEhMB8GA1UEChMYVHJ1c3R3YXZlIEhvbGRpbmdzLCBJbmMuMTIwMAYDVQQDEylU cnVzdHdhdmUgRXh0ZW5kZWQgVmFsaWRhdGlvbiBDQSwgTGV2ZWwgMzEfMB0GCSqG SIb3DQEJARYQY2FAdHJ1c3R3YXZlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBANJCA52vJVwxBsfvUAnJKs41E98ebw0Vip0Uxt/Tyhu1uycZ76sq jSs4OckRo8bL9SHm0M95EHkRCaAVmOlh+a86ZIDfIgILeAvP9Ney6joMY1wk2Qha sl3Pxpjf8EL9tUV4+a9qot4jyTL0xpbIFkyg5ChvLumhX4cT5ht2fFv0fPnnr5Mt ZseUc3+RSIl7sZpPKgvTfzrKgbkvKCr2CZ9R/tQEQBqKUF8vD3+Aewz2W+LVCKqA qqnJQ8emtYRK/8+wQbS3e1Hd8SLnXwvUKJYcDTec6yoGhYYrs9wY0aB8Ti7bm2KP SCS+mX7BvoYbMADqqJ4+QBTA1TPQ9Tc54l8CAwEAAaOCATYwggEyMA8GA1UdEwEB /wQFMAMBAf8wHQYDVR0OBBYEFG4X4K6bYyap10+xw7l4DIHmy/+LMB8GA1UdIwQY MBaAFEIythb6BP3+XUt6w/33TEAdWkOvMAsGA1UdDwQEAwIBBjBmBgNVHSAEXzBd MAwGCisGAQQBge0YAwAwDgYMYIZIAYb9ZAEBAgQBMD0GDysGAQQBge0YAwMDAwQD AzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3NzbC50cnVzdHdhdmUuY29tL0NBMDIG A1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9jcmwudHJ1c3R3YXZlLmNvbS9TVENBLmNy bDA2BggrBgEFBQcBAQQqMCgwJgYIKwYBBQUHMAGGGmh0dHA6Ly9vY3NwLnRydXN0 d2F2ZS5jb20vMA0GCSqGSIb3DQEBBQUAA4IBAQCWJBtuO+PAAUPzc3JNK8TJqtcW +Fj3/lEAUOuoeU3a49aoctBRZsEg2Af5G2EHj9uwtABgMOjJkbCOSw4Tj4+YQNzK sPgOPi6UI9idBPDJZ3EbIDx4yVpelCmB7/cvvWF9ryuRGMgwRgEu4PTozWekiViF U/osnE4hduFMYLSkc97klK0MMXcaSk7ioObpbIp0WyP1IUB4UJNA2oCAuZyGdx41 ImFmA2iOtUU4he3Zvm56wVNmiQHgyR8CyUlMsDUS3ol0ifPoKAgf4Ah0zv/RU8fJ hVBkZWH/eONhLYokvWB1RjyQ7YLZU60FPPuevBBQ5Knvr0Hj1Gf4DMZLrFZ+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ +wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG1jCCBL6gAwIBAgIRAPGHNNSDlYYqDDr25LknOBowDQYJKoZIhvcNAQENBQAw gYAxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJDAi BgNVBAMTG0NlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EgMjAiGA8yMDEzMDEyNDEx MzY1NVoYDzIwMjgwMTI0MTEzNjU1WjCBgjELMAkGA1UEBhMCUEwxIjAgBgNVBAoT GVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTEmMCQGA1UEAxMdQ2VydHVtIEV4dGVuZGVkIFZh bGlkYXRpb24gQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDI5kOI DcunMEVG9qscOcSDPnkoBkkXNyPWO4T9LkQpw0aUIyxmjXYINJrYOs2jLtuq9pai P4pdGbQL7PgSRIMuVo0L7tTDqOQbzIVAD578zoFjrWzwQrutjLhKPeuXJQ5q08YL TX68+HyU3fYkhW4S05XL397/NHUXIC1n/G5DC/dmkMr7fdDnSdBf2ckLILq4xX72 hfbC/soDJ+cpUveswpIlq9eGydCosTWmKYa7kNu4a78qGBVSZUQZmjgxDD90vRu1 DOfByOvSK0eyZuWxhjUAX8hhn6Hh8a+fWUUTXmKCrYz22LRKU1NWeqOQonXQFr1s dhJ8YFAp1eplVLdNID0opjnxJqOIpuMmuRfF9EL0s+WuwL7tHDABcf9Q3XleWVMw jMQPTl8ku/VMmDrMGxBPAiNpZ7WP581QRHIExwHXE17XSGXYZHeq/3DolTYd5EpL d0KAvtrzcfpVtfTLJCZEC25gIc1GQkhO17Cy1ab8UnMU+nmgg/5L8+xyL43YaiWo g+bEPm/wLRp0LsS9NTD9lpKYBC/v3aNtD7OkKzJf0f2k66A3Fhfi9wbirqj6uEhP 3cg0StecW7H3A4I+fEsq6ZJ7jbBM5PmO9WmZjjhYHUpnQVRuYShVWtTdFEQZ3zlk PwrlPtL4awJD7vuIy0wEwJdJWhDOnjpDaMBMWQIDAQABo4IBQTCCAT0wDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQU33bJ6BrC9SdrlIg+4HU2wkRuX2cwHwYDVR0j BBgwFoAUtqFUOQLDoD+Oirz61PgcptE6Dv0wDgYDVR0PAQH/BAQDAgEGMDAGA1Ud HwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHVtLnBsL2N0bmNhMi5jcmwwbAYI KwYBBQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0 dW0uY29tMDIGCCsGAQUFBzAChiZodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwv Y3RuY2EyLmNlcjA6BgNVHSAEMzAxMC8GBFUdIAAwJzAlBggrBgEFBQcCARYZaHR0 cHM6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQ0FAAOCAgEAfo41crfS GIpP+CQuqIGJB1/cMwmgSBORO7Y8FT/5eGYTqO3MMm0/N2xXZpSRkVD9QnY23Zg5 a2RaQoFZTZkBcgC+KUpj8BNCo8SwlgXhunKX8sgkpJanC2Ct9tPjzE0TOuQW3TH8 3hUSf6yltd9CoC3nhqy93LCyQryBMwHb2WnARLl7RKnwYXlE9RY3Q6WXi6nj/JaW JYpMCPGDEJZn4H84tZ1Vco7KjoWiboEgJ6O7pQQQPu0CKQo4kUO4AVBKiL9eraqy EgL2xtqi2X8cOzYSetFW4ramoaW1CmQ6YN4Lu1RKRNpaK12h2zTWg/3AT3WQunrj I00fceBv/iMUmr/8AeDpHCSkAltQbjKeLlPX8dMFSq+nYjGTywc+JvMiMLnxHAu0 k3matX5T44/hyxs5h1a57ezm0SwnayT2I12IGGAt+cKvh6rcMGqzurF3Icd01sUT Jdz3YImhkyiF4lz7yr7HycuhccXcxPoupKNaEqZ3bJli3kD1iEVWLMHrnf46UP8v NiXNg7Nqi5g1ZmMmOOHGU4+DSTEYHWA51Zk9CTJyPXg+HET/O8iJ/Fact8dRk/gT DMwJNyqqub/U9lQ6fpmILe4jZKYPmlMGiBu3BP26TtsLaxyIj3rI5U+hIChmunWz rnBzdw6d3QkzYcVO/U3+U+eXvESn4yx7ltY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGyTCCBLGgAwIBAgIRALR96AuHRYVcbpxOa7GJq7QwDQYJKoZIhvcNAQENBQAw gYAxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJDAi BgNVBAMTG0NlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EgMjAiGA8yMDEzMDEyNDEx Mzg1NloYDzIwMjgwMTI0MTEzODU2WjB2MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MRowGAYDVQQDExFDZXJ0dW0gQ2xhc3MgSSBDQTCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOIcYr0dj2GD1VvlM9ANcpGe eQINXySeBkZvrPHcLlrIMAr0sYXT4osetvQC4jkDlMWV7n/OVoyeGsYoHqiU7HiR MBe517YFzLDJ6OpdgScSYmTE6lZcfKBtUuFc7l0ppt/CJOr9CgEbMFvwD8VSmvEE nWXmnnAY6iurPd+0oSd0V3jyX81+s+Y2nMVSaZC5Wt0J/ZDIbknQPzluG45amzWm HhVjR7Pf/OYqkNW8u4+9j2DGcEGug5dQc7j3ngbf7gxLlRqwuA1Oh57iT3t8ZrNi Sfqnhbi5ObPwmFFjCGGvI8Hr8bd4VaBZgVmj6VYELViCJSvld/TIPF+t+6iJlquZ P77wjU6v4hkQzB/b6hRmnhNJqU4yALrZc8bAkv3MgjzYXe5zYMM59HZZWFGjZxum 9NJFjC5pyNTHYkSEXcAM3LJdhTYkeaT2dpVSL+4dOeSC/v8Ec8APfurlh4MroIYq kiA29mKiT9rFYroMtNozowPpdGyHO3R1uy6ryV/U8oVSk2npgzbW2rHFJgXU9NXG Zi6zmBUtIweq4Vrk6jafD+CSezjtEuqpqojQMACdNycDwN3UOGi9DlvHrSFJlc5r WuK9Zyx7PZqNvwOrKTSdXR+mYnweTTRQxG+ny1A9fPgA31ZgMHmjeRSjQRSj/RsT Tt7WqVamjhYSPIzHqCrJAgMBAAGjggFBMIIBPTAPBgNVHRMBAf8EBTADAQH/MB0G A1UdDgQWBBTg84a5Bwh+pRwBM271dL8qX2bYIzAfBgNVHSMEGDAWgBS2oVQ5AsOg P46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwMAYDVR0fBCkwJzAloCOgIYYf aHR0cDovL2NybC5jZXJ0dW0ucGwvY3RuY2EyLmNybDBsBggrBgEFBQcBAQRgMF4w KAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5jb20wMgYIKwYB BQUHMAKGJmh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9jdG5jYTIuY2VyMDoG A1UdIAQzMDEwLwYEVR0gADAnMCUGCCsGAQUFBwIBFhlodHRwczovL3d3dy5jZXJ0 dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDQUAA4ICAQAZO7ZOVF6EqxmkvQP4tTdFHYLR Mj4ZFg8q810ZIOP8D/kjW/stXvIGq2vtmWRrha2NEfUk4dfPEAEQektjfKHEy2I6 rMnjMyOGDcLzKAYdgTqMNz9L4Qvuq85cnU1SaJHq9TO7z3SrxxN86iVXVqJW+dKb k4aznBdO42jiH+gG6AG0QtRgga0gDdFq0HIF1f8pbndEZA3AHIs4JpsaQ+2ZFuET vTCveJwMDI7xwwtTwvHPK0afA8XeroPF+N4HfqOG0jLZWsgthyIHVERJ9j27gUll d6CLrvSiYecuG1HovSpFZt6NTLagXrFyWkjjpnZo9+QD460XtpjWxYfHGpRQ/Kxe tsXtQTZR9TPqGApZuiB2g6kapXMKoWxpV1HQVvE/rcYbIj0QEnu6e9tJmfD/l7Tg LNlpDFLgHC/QwwVzLBFpchtZDN2eSf0fqmqfr4AX0V1OAGi6v+XCLL2XgvNM+YcC 4RPm6PI7Lr4qw83jth5z+WY6qfhZW4wkb48ndLc7BxdlBXzFg/gaPClw+xAzFk9L YfnrIYsdbnEkArGepbqfjD2/U9LiLuWQpNXqx86L5sHWk3toa+LbeHOjDD4dz6Ex lp/2Cw+lURi3H5aZJzZ9x+M/6ybsKRL6lOlpYSlaDdu3W8PA0fCZcWX7P1C+G4AD 82UVg+nfb2Xv/DwRuQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIQjCCBiqgAwIBAgIII202XeOanEUwDQYJKoZIhvcNAQEFBQAwga4xCzAJBgNV BAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQg d3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcx GzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwHhcNMTMwMjI1MTAzOTQ1WhcNMzcwMjE5 MTAzOTQ1WjCBqzELMAkGA1UEBhMCRVMxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEg Uy5BLjESMBAGA1UEBRMJQTgyNzQzMjg3MUswSQYDVQQHE0JNYWRyaWQgKHNlZSBj dXJyZW50IGFkZHJlc3MgYXQgaHR0cHM6Ly93d3cuY2FtZXJmaXJtYS5jb20vYWRk cmVzcykxHjAcBgNVBAMTFUNhbWVyZmlybWEgVFNBIC0gMjAxMzCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBALpvXZdoh0F//9zTPJF5htYt7dqo+Wf/rHwo JGcov3BPZ/jhukWxzHpriHG8I6w6WAn2Zr6Y1kDvVS/B+i6hhod8zkZg9gWixdEf 10Vm/+YUOsSpWep3ywd9aw0/fRdO2UZmz3LECwG80aoAGPN0dAM57TzkDl3qP2SN jR2EYHmjHWXr9vwCwixMYRBEiWY2E8PGUYoqK1gPZbN6oqSLYl7CS3k5QLR8+ksO i8UpJcLJLXvqmh+c4sBL8NLV60y4Xa+dgQdxpfnk/tPWbHhBsKvy95C634g086Nr 9qnFO0pxGbhKO6XYG0GKXOQJ7TcVGK1z9wHHRfvIvTmcp9gopk99xmed1al+Efzk Mju7lmzCocz4JZ3VyCD3BD3qRx7R6MaPtTLk3XXCbx9QBIjBPIQM654rfYQM/nGZ di+M2wlXWnebxAmF2ubx+hJdGFCjggnHjqg0oG5wrKvCN25iDtCoRaXc7kQ1Vnod PT37XMQkW7bMAWvX6cnfL7UQm3w7eWDFRVlViFsVkxczyCviD9p7wxNe/08506HP pSirrzftgnLvugV7RZQkD1fn9W7FQkLEhX8/qpMdF6ZKJsD+dizGLoqPCWqyo7u9 UZ1PSWAhAf5Q+XDsgIo+0t73r8kaiCcXl+R4BQtiDijdja5qcwZziedCeE1Yy3Cn r+YVJMlFAgMBAAGjggJjMIICXzASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQW BBQOMU1d6eHCXFu89SsFuq9HDRar3DCB4wYDVR0jBIHbMIHYgBT5JKwPsrX4ecD6 YIgbxNlNAp4XGaGBtKSBsTCBrjELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt YSBTLkEuMSkwJwYDVQQDEyBDaGFtYmVycyBvZiBDb21tZXJjZSBSb290IC0gMjAw OIIJAKPaQn6ksa7aMHoGCCsGAQUFBwEBBG4wbDBCBggrBgEFBQcwAoY2aHR0cDov L3d3dy5jYW1lcmZpcm1hLmNvbS9jZXJ0cy9yb290X2NoYW1iZXJzLTIwMDguY3J0 MCYGCCsGAQUFBzABhhpodHRwOi8vb2NzcC5jYW1lcmZpcm1hLmNvbTAOBgNVHQ8B Af8EBAMCAQYwPgYDVR0gBDcwNTAzBgRVHSAAMCswKQYIKwYBBQUHAgEWHWh0dHBz Oi8vcG9saWN5LmNhbWVyZmlybWEuY29tMHgGA1UdHwRxMG8wNaAzoDGGL2h0dHA6 Ly9jcmwuY2FtZXJmaXJtYS5jb20vY2hhbWJlcnNyb290LTIwMDguY3JsMDagNKAy hjBodHRwOi8vY3JsMS5jYW1lcmZpcm1hLmNvbS9jaGFtYmVyc3Jvb3QtMjAwOC5j cmwwDQYJKoZIhvcNAQEFBQADggIBADAL5qPHF+WF8tWNTaqDMNl/Av4dipoH+gNF FTQfY6OGPEFsKYqBBU6HKsOkVnBT0hSAdQTk8fOOifSP39bbs582t6axg+aoPCER y8tL26R8myLwicPjXss3kqW11qJ75jZK1WI3NHD8zyhxlTT5Kfa/xOvSajq0HjCX IIKw+nxrgvmFsphvToVn+rFQzOXmYGT2JZeEVKemMlkeTrQeu674Pk93ueh6F0sD /9IklgTZ5qUSlmec1ilyrE5QEBJrWls8bmymU7oExhiNd0ANjBmcTojYhzpb+1pO JaZcAdb1sTrDgbxtPLOdAZzRxOS5Nlzl1i6i8BLSdrEwk+mUSrpbik6JrvFlFzQ/ oAEGaeHpn7d5rx/7nc8pW+YsAZT70iuUHOSE7hv0pcWYrjgGoDXGA52lGwP8KqMG s/vywoyuFovbZYsHO1TR+XpxAEQ9sTKNW6Ex4en27ClRWBqXGw7uI5wfVkF+dWyi K6P8F49n+Veo7VrLBoe5WATzmkdhFbjKOZZdzdnBRnT3Ehd4ZS4fAXSDP0tmk6oR R0CB3bcVgEm7heIuFI7M1IOutntNHpLGxNPmdGrlBW91qS5M4WEtGpPHX18gIcj1 3+PdH9gDu959oqdH5ukhIJvNy7WFhp7mSdUz5f3gYDDWgRccCPeZ8IjdcA+UKJtQ T09tRmr6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDojCCAyigAwIBAgIQBh1GQ7QStdjXFUmdhVOqAzAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTMwNDE1MDAw MDAwWhcNMjgwNDE0MjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N T0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBFQ0MgRXh0ZW5kZWQgVmFs aWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD QgAEV3AaPyeTQy0aWXXkBJMR42DsJ5pnbliJe7ndaHzCDslVlY8ofpxeFiqluZrK KNcJeBU/Jl1YI9jLMyMZKsfSoaOCAWkwggFlMB8GA1UdIwQYMBaAFHVxpxlIGbyd nepBR9+UxEh3mdN5MB0GA1UdDgQWBBTTTsMZulhZ0Rxgt2FTRzund4/4ijAOBgNV HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADA+BgNVHSAENzA1MDMGBFUd IAAwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNvbS9DUFMw TAYDVR0fBEUwQzBBoD+gPYY7aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RP RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsG CCsGAQUFBzAChi9odHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9FQ0NBZGRU cnVzdENBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29t MAoGCCqGSM49BAMDA2gAMGUCMQDmPWS98nREWdt4xB83r9MVvgG5INpKHi6V1dUY lCqvSvXXjK0QvZSrOB7cj9RavGgCMG2xJNG+SvlTWEYpmK7eXSgmRUgoBDeQ0yDK lnxmeeOBnnCaDIxAcA3aCj2Gtdt3sA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG1jCCBL6gAwIBAgIQNMarBE42mRJRyCULbJTWwDANBgkqhkiG9w0BAQsFADA7 MQswCQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xGTAXBgNVBAsMEEFDIFJB SVogRk5NVC1SQ00wHhcNMTMwNjI0MTA1MjU5WhcNMjgwNjI0MTA1MjU5WjBHMQsw CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xJTAjBgNVBAsMHEFDIENvbXBv bmVudGVzIEluZm9ybcOhdGljb3MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCXVx8rdbF7/xY44CaSqzzGo5BhvzA8knxC/3KJYVzTf+CkOvMxMUDub8b0 h38MDujm/RKZhBNOWbKhxF3U61ZVhcR9xOCciuS/soT80m3BByxAKcZsNka0jCA4 XRkglDaAFxCHEZ06MOnvXsSOZDfPYahbQ3VFCVycJuhlHdAwSpmceQwcRYkR6YgX wTiyzCNGivMKAmRS3dItqDOmDW/nxiDFq/Jd8VWY7GFkwbbAeqYId8FjN8zfvafu nsB9SLFkUjPPMeqfmC7Bdh7HMxLpaOXROwH201cmlebiPkn0xSFxXFqwhhr6yN8U QYZ3O/+xdHLrS6DS9+CJUF6d09ijAgMBAAGjggLIMIICxDASBgNVHRMBAf8ECDAG AQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUGfhYLxTWpsybBJgIDUzX qwCng2UwgZgGCCsGAQUFBwEBBIGLMIGIMEkGCCsGAQUFBzABhj1odHRwOi8vb2Nz cGZubXRyY21jYS5jZXJ0LmZubXQuZXMvb2NzcGZubXRyY21jYS9PY3NwUmVzcG9u ZGVyMDsGCCsGAQUFBzAChi9odHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9jZXJ0cy9B Q1JBSVpGTk1UUkNNLmNydDAfBgNVHSMEGDAWgBT3fcX9xOiaG3dkp/UdoMy/h2Ca bTCB6wYDVR0gBIHjMIHgMIHdBgRVHSAAMIHUMCkGCCsGAQUFBwIBFh1odHRwOi8v d3d3LmNlcnQuZm5tdC5lcy9kcGNzLzCBpgYIKwYBBQUHAgIwgZkMgZZTdWpldG8g YSBsYXMgY29uZGljaW9uZXMgZGUgdXNvIGV4cHVlc3RhcyBlbiBsYSBEZWNsYXJh Y2nDs24gZGUgUHLDoWN0aWNhcyBkZSBDZXJ0aWZpY2FjacOzbiBkZSBsYSBGTk1U LVJDTSAoIEMvIEpvcmdlIEp1YW4sIDEwNi0yODAwOS1NYWRyaWQtRXNwYcOxYSkw gdQGA1UdHwSBzDCByTCBxqCBw6CBwIaBkGxkYXA6Ly9sZGFwZm5tdC5jZXJ0LmZu bXQuZXMvQ049Q1JMLE9VPUFDJTIwUkFJWiUyMEZOTVQtUkNNLE89Rk5NVC1SQ00s Qz1FUz9hdXRob3JpdHlSZXZvY2F0aW9uTGlzdDtiaW5hcnk/YmFzZT9vYmplY3Rj bGFzcz1jUkxEaXN0cmlidXRpb25Qb2ludIYraHR0cDovL3d3dy5jZXJ0LmZubXQu ZXMvY3Jscy9BUkxGTk1UUkNNLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAo2bsQ2xL Dcyodieqjd+uy/lfxDw/MbrAq/ZaNFkIlcypUYamOM4vrm5rz8oLjPCoLkJ48P+n P08Gkcl5Q6q6VFcZLia+U3gfHXrkyqToQlrtViGCGH3xA4u56XtMHGXSdk9vQ0yD nW5f7bUEkp+uvcKewrOvNcpbIAgD4eU7gdOS0w7BagcFRBgTKBw2s3z73fRZtouJ g/atmWYtXbBsfNjph+pCh+h5sbSyZUVzO5AemyjpYYYNMWDQrTXq+7O8zIPuPaNE SjEexuzn+VjHG90RlUK1LygARi+Ir0opD2w6erb/hK8Eea7MFdKQ2ASqNBGJggNo 5vfPVvjHiL+Antmh7mQSKL+4YwFU64d4KK9k0C1mbJethDQFKcjTK1vMvnXFiups IuyTqwKauo7u2zMKzY4r3VYOW9TpMyLPFIY8pII5GyNzXlL0F4nscOvduTEPEYqx eNJfpDDPY/DO8WfxgdRTy2W3D/UoAulb+Y+nuzGGCtFQrsSMQX487R+aY0nWot/h ajef6BcPuxhDfQrg5IafrISVmcJAplb3tXhh0sz7RbYz6jf1bke4eU5fnrTMtGlV teUL2vjrfUPHW07kBJuaQ7sxORNV3bpHisOnHj+AriQzCn5vINpSHW6hTm7IfRkb ltu/aQrsMuUhP7HE/v+uXe5CuboV5ubZhHU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFjjCCA3agAwIBAgIIOyEC3pZbHakwDQYJKoZIhvcNAQEFBQAwKDELMAkGA1UE BhMCQkUxGTAXBgNVBAMTEEJlbGdpdW0gUm9vdCBDQTMwHhcNMTMwNjI2MTIwMDAw WhcNMjgwMTI4MTIwMDAwWjAoMQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1 bSBSb290IENBMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKjyAZ2L g8kHoIX7JLc3BeZ1Tzy9MEv7Bnr59xcJezc/xJJdO4V3bwMltKFfNvqsQ5H/GQAD FJ0GmTLLPDI5AoeUjBubRZ9hwruUuQ11+vhtoVhuEuZUxofEIU2yJtiSOONwpo/G Ib9C4YZ5h+7ltDpC3MvsFyyordpzgwqSHvFwTCmls5SpU05UbF7ZVPcfVf24A5Ig HLpZTgQfAvnzPlm++eJY+sNoNzTBoe6iZphmPbxuPNcJ6slV8qMQQk50/g+KmoPp HX4AvoTr4/7TMTvuK8jS1dEn+fdVKdx9qo9ZZRHFW/TXEn5SrNUu99xhzlE/WBur rVwFoKCWCjmO0CnekJlw0NTr3HBTG5D4AiDjNFUYaIcGJk/ha9rzHzY+WpGdoFZx hbP83ZGeoqkgBr8UzfOFCY8cyUN2db6hpIaK6Nuoho6QWnn+TSNh5Hjui5miqpGx S73gYlT2Qww16h8gFTJQ49fiS+QHlwRw5cqFuqfFLE3nFFF9KIamS4TSe7T4dNGY 2VbHzpaGVT4wy+fl7gWsfaUkvhM4b00DzgDiJ9BHiKytNLmzoa3Sneij/CKur0dJ 5OdMiAqUpSd0Oe8pdIbmQm1oP5cjckiQjxx7+vSxWtacpGowWK8+7oEsYc+7fLt3 GD6q/O5Xi440Pd/sFJmfqRf3C1PPMdBqXcwjAgMBAAGjgbswgbgwDgYDVR0PAQH/ BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wQgYDVR0gBDswOTA3BgVgOAoBATAuMCwG CCsGAQUFBwIBFiBodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZTAdBgNV HQ4EFgQUuLxsAI9bGYWdJQGc8BncQI7QOCswEQYJYIZIAYb4QgEBBAQDAgAHMB8G A1UdIwQYMBaAFLi8bACPWxmFnSUBnPAZ3ECO0DgrMA0GCSqGSIb3DQEBBQUAA4IC AQBFYjv/mKX+VcyxEacckgx4L8XvFkIFPXzjEnDnAtCCkROU/k5n1jjVK+ODOn+Q 4kJg6Nd7K47+zTXcrSe1tB2gVMsyaCN9scy4phLX1qT48sThCjUtooxfIoRycpdl f14HcUPCYlASTCapZU0MnAbzfpzxm49Ik/A2JWxAhxXVRHwOu3TMGiQ4W/VyVawx jwQMO8TneBDombmkXsI9bI0OxWUh2A5dKlqu0sYvE0dz8xDxr9ZkmZqYcPIKizCZ laP1ZsSlCi5S31gn3EUP+fd21q6ZXgU+50/qgoh/0UUaHRpedPQBES/FYc2IQZ2X jhmeTwM+9Lk7tnzHeHp3dgCoOfceyPUaVkWiXMWcNAvvkDVELvXfJpRxwcRfS5Ks 5oafOfj81RzGUbmpwl2usOeCRwdWE8gPvbfWNQQC8MJquDl5HdeuzUesTXUqXeEk yAOo6YnF3g0qGcLI9NXusji1egRUZ7B4XCvG52lTB7Wgd/wVFzS3f4mAmYTGJXH+ N/lrBBGKuTJ5XncJaliFUKxGP6VmNyaaLUF5IlTqC9CGHPLSXOgDokt2G9pNwFm2 t7AcpwAmegkMNpgcgTd+qk2yljEaT8wf953jUAFedbpN3tX/3i+uvHOOmWjQOxJg 2lVKkC+bkWa2FrTBDdrlEWVaLrY+M+xeIctrC0WnP7u4xg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG1jCCBL6gAwIBAgIQPnz9VM3l4W1RzEmOGx7NSDANBgkqhkiG9w0BAQUFADA7 MQswCQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xGTAXBgNVBAsMEEFDIFJB SVogRk5NVC1SQ00wHhcNMTMwNjI3MTQxNzUwWhcNMjgwNjI3MTQxNzUwWjBHMQsw CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xJTAjBgNVBAsMHEFDIENvbXBv bmVudGVzIEluZm9ybcOhdGljb3MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCXVx8rdbF7/xY44CaSqzzGo5BhvzA8knxC/3KJYVzTf+CkOvMxMUDub8b0 h38MDujm/RKZhBNOWbKhxF3U61ZVhcR9xOCciuS/soT80m3BByxAKcZsNka0jCA4 XRkglDaAFxCHEZ06MOnvXsSOZDfPYahbQ3VFCVycJuhlHdAwSpmceQwcRYkR6YgX wTiyzCNGivMKAmRS3dItqDOmDW/nxiDFq/Jd8VWY7GFkwbbAeqYId8FjN8zfvafu nsB9SLFkUjPPMeqfmC7Bdh7HMxLpaOXROwH201cmlebiPkn0xSFxXFqwhhr6yN8U QYZ3O/+xdHLrS6DS9+CJUF6d09ijAgMBAAGjggLIMIICxDASBgNVHRMBAf8ECDAG AQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUGfhYLxTWpsybBJgIDUzX qwCng2UwgZgGCCsGAQUFBwEBBIGLMIGIMEkGCCsGAQUFBzABhj1odHRwOi8vb2Nz cGZubXRyY21jYS5jZXJ0LmZubXQuZXMvb2NzcGZubXRyY21jYS9PY3NwUmVzcG9u ZGVyMDsGCCsGAQUFBzAChi9odHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9jZXJ0cy9B Q1JBSVpGTk1UUkNNLmNydDAfBgNVHSMEGDAWgBT3fcX9xOiaG3dkp/UdoMy/h2Ca bTCB6wYDVR0gBIHjMIHgMIHdBgRVHSAAMIHUMCkGCCsGAQUFBwIBFh1odHRwOi8v d3d3LmNlcnQuZm5tdC5lcy9kcGNzLzCBpgYIKwYBBQUHAgIwgZkMgZZTdWpldG8g YSBsYXMgY29uZGljaW9uZXMgZGUgdXNvIGV4cHVlc3RhcyBlbiBsYSBEZWNsYXJh Y2nDs24gZGUgUHLDoWN0aWNhcyBkZSBDZXJ0aWZpY2FjacOzbiBkZSBsYSBGTk1U LVJDTSAoIEMvIEpvcmdlIEp1YW4sIDEwNi0yODAwOS1NYWRyaWQtRXNwYcOxYSkw gdQGA1UdHwSBzDCByTCBxqCBw6CBwIaBkGxkYXA6Ly9sZGFwZm5tdC5jZXJ0LmZu bXQuZXMvQ049Q1JMLE9VPUFDJTIwUkFJWiUyMEZOTVQtUkNNLE89Rk5NVC1SQ00s Qz1FUz9hdXRob3JpdHlSZXZvY2F0aW9uTGlzdDtiaW5hcnk/YmFzZT9vYmplY3Rj bGFzcz1jUkxEaXN0cmlidXRpb25Qb2ludIYraHR0cDovL3d3dy5jZXJ0LmZubXQu ZXMvY3Jscy9BUkxGTk1UUkNNLmNybDANBgkqhkiG9w0BAQUFAAOCAgEAq8INCAuB 6nx0nnAePRUcqEW8v0QN0kCWvk3+UcrXmL3xMA5Bl19dO46dS37urKzpowoiYST/ w7o0S+V9gVHuAtWJa+8fZUOto7zp2rDZ/H0xYR9ZlG/sKn+c2c5S6vepEUm2lqKy eEvdFA28Qb81p/L3xPwxa4Xh7LnxZMQuMTFYhoXJmfQ6/tDyTjn+fkAH1ivXk7V9 NcQjmkKpFnGew/14hKauJ/GjNte6/DCgyE9aD0Nwf7hugHjxK+e0SrX/5ZjitXzQ a3SAQfFT4aaFIiG7p91C3yQvLW4mnsUEs1cLrlgQJB2rSKPDskO5duRKB9xBd+rj 5dHDPCjvJf1GSC9eojv+wgeBaDieLYKp2ZwpS3A5FlinoP+WRCEM0aD8i7H/jo9L xozHJxIMkTuVVucOvSoLDZTiy+0fmpjJB15uLU/KEy3orgHRTtHJgT+dAZSNJOh/ R9FrxqCP2gGghumL4o4KLcDr+D11D1ZKuO1ocNI3eAbnZdPyZPBAf5P9tzW1AXOm bvRmRWAb3gL9BKilqdSoc8SWFS8zxWujPrkUv9ZGyHVjw2mA7032W9WynLzFJfqf UPA82lHlM1hC2lGBtDYGa2o9jWtyBU7bO2nO3QOfDVLpNRvF00RoJ0uOAacNkp03 TfA6Q8xxD/CQy9SxwOeD5ufRZKg0HsEl+zg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDDTCCApSgAwIBAgIQAQXa4lWqspVKDbLJ5rUyLDAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg RzMwHhcNMTMwODAxMTIwMDAwWhcNMjgwODAxMTIwMDAwWjBIMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSIwIAYDVQQDExlEaWdpQ2VydCBBc3N1 cmVkIElEIENBIEczMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEVubeDDY2iYfznJDE 01D32EdUZD3UjbHGK7V2Tfev3Rqw3U1lT4BEYBfMTxn0nVzFkR0cWePcwQ+al31z pC3zOCg9l+hs2l2/6+Mf5T/r5TKouzBQ0MiNtYQm9DQZwp9do4IBJDCCASAwEgYD VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEEKDAm MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRQYDVR0fBD4w PDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl ZElEUm9vdEczLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUA0a+t1tJcUhP eqKMgehiqcCCb00wHwYDVR0jBBgwFoAUy9C9qeGYBVGhTTeig3nOjR0q5IQwCgYI KoZIzj0EAwMDZwAwZAIwbEDtzp72rHfEHWQSzkOywcS6EdjhwVTx/RQrMnJ7XzRJ utV3ELbyG57vQ8kOmWubAjAEvQWMTmAXaQYSZuPOIDrP3xqBFVts537MnfPbF05n 7wJyFcX8eno5jbCsk9Jp+wM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGXDCCBESgAwIBAgIQA2N+U4z9huFgNSfW8rgP9DANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg RzQwHhcNMTMwODAxMTIwMDAwWhcNMjgwODAxMTIwMDAwWjBMMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSYwJAYDVQQDEx1EaWdpQ2VydCBUcnVz dGVkIFNlcnZlciBDQSBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB ANLHpRlDBxJKtjyOW2ivRldYdpvV7yeibGXtTe7sUEYRHsEhzNgcq65r4zqZlCxQ LR4xd3a8FkSgzAOQjH3thUvmxyqrDmNmS5/A/qg0VGoNYK8dD8PemtQD59OdDlmQ i+Istby0u7/+4GRwJU5xjXVKsaflVRnSN9Wq28Q1DqrTX0wt33wX1wTXodlOq9eD p6Vf/pPhgHuSJkFX6SaWcCL5//U5V4drbNlYCAh8ClCKa4Gi26NFEg/chnOfE8/u 6HZqiz0+XnFkdJfmgpFvh1zALh2Lga7D15ubkSWaLhtNX6GtixEhYUqpSTeIOG/0 R5qDnJHxy49ct/J6zVIL6qHiNaLM7RSITuuHPLm48axhnM+0UIv9PJi5nNCd6O3W CrkEd3FRfzgR2rnHmv+s17dJanp0a5aae8p2wz5K3g5N6XB04WCXyJldNkbmeC7T dT9fiOtpb2zxIITRwAA75Fd7zrKdPor0Cqmte3bdBI6pMSklgp3Afe3mcfq0iAE2 wX1YNOCB4blGgm+A7/VkdcfhS9hJxrUCzCIt8lkUzvzmVWHQxLauuyvj3ZqID25w +7ztdxtm2tVs50m/Zkqe2eLqFCPBx+cIdxwg29kyKQN1jNRYXVWSjNGAsKo9q7fZ HHaWZm5eFUrUqE2Tzuwj5hnHUdSVwlj0x9az+BgqMZoBAgMBAAGjggEiMIIBHjAS BgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjA0BggrBgEFBQcBAQQo MCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBgNVHR8E PDA6MDigNqA0hjJodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz dGVkUm9vdEc0LmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUNtCononygrxr 4lm2o8b3NEaMtC8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJ KoZIhvcNAQEMBQADggIBAEv9/ne9aGqxhJyIhxHWQjAz8g+PKsut3EI7+4qLHTOD bqBpVcY4vDYe8H9MSvtAKCuLzntr/DsP9MM2cvOMZitB7YoFiPYk7Rkq+Pk611VV 2CVehhMIgxq/Y2uU2e3m3TE6Jq1qOaVlZywgqD9E1mU2FVutqqg6Zs6TF+y3n+Sc SaZ1Vnht6VN9seuFvkJKe9ZL+KqBnrLmSArk0200F6CPOppCgiDxlQulJ6/2WK1q 6HZuAwwqeTiUi2T4pzG2CBY7KrfQLW7JUqvKId8G7Lc7PMIVZLvLWjNi1tfSGotl w+cCXuk/Z9XuqQT/z0p2RQqVr+eD98ySiURX+vB9tLOljpgrF2Pfxr156bicysyL sudKyKag1NfDmU8sd1F3SFdiYvSwnoLrH7thapJviH0F6jCAT6t4i2D96OhWFVPG ON57Dpr5wMdNHTdDZsLC93rojKt4uks940Si71SX918F0GgvoVVTgdWg5dRTfOwk XFkJGfdxh7BnvOAk1PoAWAW5UcIEhPRJmvfD6Tg/V6o4wZFZX1yStE9qzenDq7Xj 2jvT17AVA/uANWOHZSJUhDnDc5EyEoLJnan2t6LY8VJEs9dBRkj2/Umr2FwCFpXM 8aiL18pv09XZpGGTVtRnr0Mlgswu5PEUKEBSDHK9JN/NwUW/qH1JJCmEBxsmLJB/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEizCCA3OgAwIBAgIQDI7gyQ1qiRWIBAYe4kH5rzANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xMzA4MDExMjAwMDBaFw0yODA4MDExMjAwMDBaMEQxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFURpZ2lDZXJ0IEdsb2Jh bCBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANNIfL7zBYZd W9UvhU5L4IatFaxhz1uvPmoKR/uadpFgC4przc/cV35gmAvkVNlW7SHMArZagV+X au4CLyMnuG3UsOcGAngLH1ypmTb+u6wbBfpXzYEQQGfWMItYNdSWYb7QjHqXnxr5 IuYUL6nG6AEfq/gmD6yOTSwyOR2Bm40cZbIc22GoiS9g5+vCShjEbyrpEJIJ7RfR ACvmfe8EiRROM6GyD5eHn7OgzS+8LOy4g2gxPR/VSpAQGQuBldYpdlH5NnbQtwl6 OErXb4y/E3w57bqukPyV93t4CTZedJMeJfD/1K2uaGvG/w/VNfFVbkhJ+Pi474j4 8V4Rd6rfArMCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0P AQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29j c3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmw0LmRp Z2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwN6A1oDOGMWh0dHA6 Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwPQYD VR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2lj ZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFCRuKy3QapJRUSVpAaqaR6aJ50AgMB8GA1Ud IwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA0GCSqGSIb3DQEBCwUAA4IBAQAL OYSR+ZfrqoGvhOlaOJL84mxZvzbIRacxAxHhBsCsMsdaVSnaT0AC9aHesO3ewPj2 dZ12uYf+QYB6z13jAMZbAuabeGLJ3LhimnftiQjXS8X9Q9ViIyfEBFltcT8jW+rZ 8uckJ2/0lYDblizkVIvP6hnZf1WZUXoOLRg9eFhSvGNoVwvdRLNXSmDmyHBwW4co atc7TlJFGa8kBpJIERqLrqwYElesA8u49L3KJg6nwd3jM+/AVTANlVlOnAM2BvjA jxSZnE0qnsHhfTuvcqdFuhOWKU4Z0BqYBvQ3lBetoxi6PrABDJXWKTUgNX31EGDk 92hiHuwZ4STyhxGs6QiA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEmjCCA4KgAwIBAgIQD1/M/Ksg89+ObaPYR2fCkzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMjgwODAxMTIwMDAwWjBIMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSIwIAYDVQQDExlEaWdpQ2VydCBB c3N1cmVkIElEIENBIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA tFLF3hmmiyDchhlz2ZMtsf4L23l6z+g5odzcrNDI8QcZTBUm9xV9w5YZ6bRXU7jw ZlKaaVtxrqugWHNdlNfKL27RzC4kn1aKvwdt5Gj9j+UMzc/BMx3ksvGiHwQMBMGF zPAVG9aUpVXCXdUt0vSOLZxzI3x2Oqz2jL9pxc2l/bmgf9uhE4v2noPxViUQ4DF2 h/cDRzV5qyZUq8FPw9y1JUi8Pl6HHAzFei/4OvhAQogerd8lvl8chlkT5h9UNeS0 zdv5uDrNs5C/hJqXidKZU7nZTqh08B/RD8vsu9f66HavmbyrKXa2CveC0uqZvfQZ 0SBCj4ykeElnxyveHfOvUQIDAQABo4IBYTCCAV0wEgYDVR0TAQH/BAgwBgEB/wIB ADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhho dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6 Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmww OqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ RFJvb3RHMi5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFLHP9qHl5oHFZkeN eIR3e/mBy0qmMB8GA1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWXNqfWMA0GCSqG SIb3DQEBCwUAA4IBAQA/C7UkzAlgi5mvLq7ukp0JS9Vg+rMNyx3XVkBF84vz9exk 74Y0vPnniZoy/pAgOaFFGbsVBI7SNf/iGI5x5UG5PKWo+K0AP0fwkZFnfEAN0wJy Dezr2oLi95s2XCoqThxhtJe6t1A8Lh6klGQGkgREdyF7Y6obGQq+7hDz4VRR4MCM m5QHcPcYJzh0pQueTxadgp6AbksehUf/g9eGzwzHqdkkAIQ9mzpRRxjoqkaPTtSd kpPl/ZZcDqPzDzWXhzKfJs90lSuYy1z1fQEgFZP/X1DGT8SGzAlfv83e+FC3ja7w JZJ4ZTqw8UTUUpI52U2HVCMXKNtEFEyMYLeRJe+j -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAzCCAomgAwIBAgIQBYjADIzAxXdmfmTLqIurSTAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xMzA4MDExMjAwMDBaFw0yODA4MDExMjAwMDBaMEQxCzAJBgNVBAYTAlVTMRUw EwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFURpZ2lDZXJ0IEdsb2JhbCBD QSBHMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABGY9nqbRBXwQO+2i5tz0bMPnXF/p aT+G2x/Cfk22Ga8rAP8LlrJaUK8Wguo1B5cq/eQY83hwiTsQgCFz+uSjKbU9TrVt nD+hAsQdmWUlMpzpd1ZwPnCR1+mg4jTsONHa8KOCASEwggEdMBIGA1UdEwEB/wQI MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEF BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOG MWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMy5j cmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFBsAey6NpdNhIQxdVjUDP9LNcZgK MB8GA1UdIwQYMBaAFLPbSKT5ocXYrjZBzBFjaWIpvEvGMAoGCCqGSM49BAMDA2gA MGUCMQDuo99HhMCfVcynjSsjBZR9FDFHzMxl/wEZSg2vdjHyiKYBa52Ok9LWR2WG Ss3h4jkCME8wZqBwYpkfJh9ziZrgEkbUmpsLg6E2DLlOyLfeS/znes2wDjQYaTyh EbyxjtCg/w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE9DCCA9ygAwIBAgIDD+D2MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFkQtVFJVU1QgUm9vdCBD QSAzIDIwMTMwHhcNMTMwOTI3MDczMDQwWhcNMjgwOTIwMDgyNTUxWjBbMQswCQYD VQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMTUwMwYDVQQDDCxELVRSVVNU IEFwcGxpY2F0aW9uIENlcnRpZmljYXRlcyBDQSAzLTEgMjAxMzCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALC/1NRhaNYd26CrWiM6xDD2RxiOBSiyi5I1 iWWIdQkmuFEV/I+dnYjbtbZnE6cCjjIr9N2sGtpRBJb66lRIaTBzsSuNqu1hu3OH dJZHO3fnE63sXmZRgGfKyLF3AErbSH9NdOj5M4x3JSmayeojddU6FpI6TwbBPUxy if9msLURw1UE6uTnXu59Whmst/5zSHjH9QC3uEPd18doJXF1NGYCz37UUCiReapf NNBIFlj3vrRwKzQVsz4fjYaDMyn4IZ0fpD8lIhR3fmc1PhVNVwL66sN1AMz4aeL0 ylV0viIKhPW0WVuQswZ18mTxRbW7gN1CRz8Cp0tGxza8Og8SI68CAwEAAaOCAdUw ggHRMB8GA1UdIwQYMBaAFD+QyH3HFW/zJI+pwy9Log8hsi/nMEIGCCsGAQUFBwEB BDYwNDAyBggrBgEFBQcwAYYmaHR0cDovL3Jvb3QtY2EtMy0yMDEzLm9jc3AuZC10 cnVzdC5uZXQwZgYDVR0gBF8wXTBbBgsrBgEEAaU0AoFIATBMMEoGCCsGAQUFBwIB Fj5odHRwOi8vd3d3LmQtdHJ1c3QubmV0L2ludGVybmV0L2ZpbGVzL0QtVFJVU1Rf Um9vdF9QS0lfQ1BTLnBkZjCBvgYDVR0fBIG2MIGzMHSgcqBwhm5sZGFwOi8vZGly ZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ0ElMjAzJTIw MjAxMyxPPUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9u bGlzdDA7oDmgN4Y1aHR0cDovL2NybC5kLXRydXN0Lm5ldC9jcmwvZC10cnVzdF9y b290X2NhXzNfMjAxMy5jcmwwHQYDVR0OBBYEFBkDqtkiRccaYqnnXJmwnd7t1Li1 MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqGSIb3DQEB CwUAA4IBAQAQjlD4qWkDZE7oZaTTkJPJQwp3TtGPZ7jfPmPfZv6HX3VAzdjJjoNC Aj1VjcoPWyB38crUZDZRcwq3OwfSpszwAIru1MDl5d3Z0axSaZbhnAG5wxka9UrI L29hw5mcJVNiu06TDrel2shZInn8eauFguuwW1XCDw9SGdrXtB0XZnYe84SM9h8N fm37s80jX/PyUWKIyMsHhqvbg7nuOcoVQ5fOjtxiWjqYYw1ZuXO5k3VoNcWyduOD 4ZqUB94dbPpHw++q4OJsACEGt0JH19gajBHPQEolptS/YjQNGeJ4PbYrlZuCySj1 QNpWaace/irZlZr9P5b/vHhisD78NR5V -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtjCCA56gAwIBAgIQDHmpRLCMEZUgkmFf4msdgzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowdTEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTE0MDIGA1UEAxMrRGlnaUNlcnQgU0hBMiBFeHRlbmRlZCBW YWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBANdTpARR+JmmFkhLZyeqk0nQOe0MsLAAh/FnKIaFjI5j2ryxQDji0/XspQUY uD0+xZkXMuwYjPrxDKZkIYXLBxA0sFKIKx9om9KxjxKws9LniB8f7zh3VFNfgHk/ LhqqqB5LKw2rt2O5Nbd9FLxZS99RStKh4gzikIKHaq7q12TWmFXo/a8aUGxUvBHy /Urynbt/DvTVvo4WiRJV2MBxNO723C3sxIclho3YIeSwTQyJ3DkmF93215SF2AQh cJ1vb/9cuhnhRctWVyh+HA1BV6q3uCe7seT6Ku8hI3UarS2bhjWMnHe1c63YlC3k 8wyd7sFOYn4XwHGeLN7x+RAoGTMCAwEAAaOCAUkwggFFMBIGA1UdEwEB/wQIMAYB Af8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp Z2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2Vy dC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2 MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j b20vQ1BTMB0GA1UdDgQWBBQ901Cl1qCt7vNKYApl0yHU+PjWDzAfBgNVHSMEGDAW gBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAnbbQkIbh hgLtxaDwNBx0wY12zIYKqPBKikLWP8ipTa18CK3mtlC4ohpNiAexKSHc59rGPCHg 4xFJcKx6HQGkyhE6V6t9VypAdP3THYUYUN9XR3WhfVUgLkc3UHKMf4Ib0mKPLQNa 2sPIoc4sUqIAY+tzunHISScjl2SFnjgOrWNoPLpSgVh5oywM395t6zHyuqB8bPEs 1OG9d4Q3A84ytciagRpKkk47RpqF/oOi+Z6Mo8wNXrM9zwR4jxQUezKcxwCmXMS1 oVWNWlZopCJwqjyBcdmdqEU79OX2olHdx3ti6G8MdOu42vi/hw15UJGQmxg7kVkn 8TUoE6smftX3eg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2 4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1 itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn 4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly /D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF 0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae cPUeybQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIQa5bmR6QeMhCn0Zuj/APCsDANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xMzEw MjMxMTAwMDBaFw0yNTA2MjMxMTAwMDBaMDUxCzAJBgNVBAYTAkJFMRUwEwYDVQQD EwxGb3JlaWduZXIgQ0ExDzANBgNVBAUTBjIwMTQwNDCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAKyRpr99eRHsEFh+Q2cJKFIIerDMQDQ2l4D+zFuXjveu tkYKIZ7fDrQebL7nS7e34ZtWwMz0jzYtkoZ/ABce1iICIS8MBEEDZLA2BDULlT0Z q6H/pv+ZEUsmh30qjjMPPb+V+syHCSidSxRO04r+pkbC8b2fQH6sZ4oMCo/pqReP 7r8oLYu+iez5ZaHd+RLtXLNAv0R8rWnNl5EP7QsT7DRKidS4uACzxO/k41ktZjDN jbXpYD40H8HnU39knELKbWP0gvNIYTH+JNVkExqzeXuvl05/rxOybdwq86wpvx15 XGSuS8ABmsl/L10CnK1xsTk5qtkiAc9H5AwgLV7cTaRA8gROKMWi+Fx2g8xEeM0D X5LTLt4/JAiF/oRAGNZeSqJ98itQ6eH9KBjvLitVWjhbkUqaef3sLTX6Li7CypZD jtHQ2dhk01eehqAtJf5G2rFqkKcqhN11am2uZY/0grRjCHooLBU1otTEP6hKrHtl Y7YPil5PVwfAnfrMziQlSlUwong2C8VXKcme0jwZvcBlhygRjCiIh7nkQg/PTpig Gw5rkaq8q6I6Fun252baUkDr+yzCBtgGIIE/mNjbm69Pak+IT7JfPaPODfBfiOgG eEr4PXWPvGt1it1WfI7uHFcNo6lG0aOpsHKUhb4GgFGIDRL7cJ/k/0Ih/XTquYLb AgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw QwYDVR0gBDwwOjA4BgZgOAoBAQcwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9z aXRvcnkuZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFO0vBYESmvhU2mkwIMFS42Zb KTVcMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUv YmVsZ2l1bTMuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBS4vGwA j1sZhZ0lAZzwGdxAjtA4KzANBgkqhkiG9w0BAQUFAAOCAgEAgrAjpNP/oh8Gqkp4 O0LXNc+dKdpmht9TA9RUxqSVpzGuXOrU4xxXjsCkZVqlDDk6/lrit2s2yPOV97Z1 RgyERR2jdr1oK0WRitHevScpyH6BBQKnbxLab4ITW9QqRgUFF4q/rt5DGv0c7Um8 3rIk2lZa8HQ+UO4Fk5v4OYyLMWf8aVeaQaJ6H9sLmiKz7TU2Ok8R7vPZxOJRbIef g/NJpnV9P9qDJOc/syXy2QsDg8TSh+2Fcxl704qPrVSXa1r8EPnLi2vUS6GTiOYQ 1xI+HXTcjHnxVSPn+CLhszHf0Zs7ebzQNjDUE/WPrtoMDnN4zkIiY6PUJmTuZ5xY F/4sLy1xyBNHNFUO3Wfb6mnjlEb+EDznhge1pGT8B6Nu1rMQxf6lcyofBbP/Vknc KMxtaI1w1nF+dQzxJxl3gdP0QvFFpKBADxJC1YcewzF0WdCtNzEc396Lte8Si88z TPMO4gEk0iPVLCnUKhCAv+KGQVVMB1aakx/GOKm1WJkhvRSEmBC3/NscYkz0bcnD vMT2c3fikfaoFyXRdKuaBv5I7gV6rc40VL1OUpkOFvGL3KLo+eSJi1bvlcjHL8LI t6mkPyGLORavHiiinlPhCc2mx8rCQjyo0oH7RBbWT1A+uF6G8h1+mi1T7sJokHHO b2DZO5vU+HdJ2bZv7e4HwjJitmY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQSYScnKm3Zu3F9tFkKeBnDTANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xMzEw MjMxMTAwMDBaFw0yNTA2MjMxMTAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE0MDcwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCuwpLG2lDe5G83hrXO8YEzkOS8BUK5lDZA7QnTUXYzPebu OS5yxSVyIvK+pids0l9hmgwCurxMaXQ+DiofKlwG4nfEowkh5wBLCwLzHUAaKV9x Km25S4qgC6lN8COCVhlJLV4n+yJqwCb5HhAaI/JQqvQRKK4AvkFXgKz7irYQnkc8 bAanc3I1qxb0GF3WEaIej41IybU0PxK4ZnUntqAiAJAedymuYjfitLmRjf78gFDD 2MlCmvZJx8AEaPMp1PBCdqtkzXunuclC23MXmOsgfflGicgmr1DSujqoyUtL5Y6N Z10ObFvvPojQIliZOh8ksN/ta3jsfasIQwtpaevfLnbKoQrvKuoBSuDGWkB+rOWt T2vYS6qzSc35X7ZZCbzxz9b/8ePgW0B31DV0vFgTi+Bl84H10FVSGefcO4jGmtlw bNCXoseklA7Be/s0Kn3Gv7X+D8rPM8gXGHrgpKKU7tYLPuqDx6w2Xa/TIEmjqExU dc+6agzeTbg5tNa6MU1OcxwEC5N5zMqpPe3Gnvg/mx/yVfdDmKpAy0j+XRkv0/yL LrvS5i56c6Ar6qp01dgClj/rZtfFEQerZrVZYUQjC5SVjbFrAYe5/Dx4fbwcg7bH gjd/k24KY8GupoUQGTq939tGxlz1HpJWZcphbdnkC5QySDELoOOkzJuRpKidQwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBTEEwdBAicDk2fduz9rPYrXSsGO qTA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAHjZ1fqgC4XwouhTZeAF CEphLaytfIlGtRQeczl/8gmZqS31Ikwsb45HL7BJlhyoOuoRdSeaqV5RKP6/d0em r9uTPo1bUYYu3PVwn33OLzMiRH4u0BfuuAK9j1ZLlDXQp+Zz3otKXU29euuNjxwh QGFt+f35WcCYwAJDS8jDpSuaK/fvKO5FFQFk/Pti2PaqONOa1x4AADNNGDeSRbAr roHUT2dZkIPQvO5ke1S7noUGPr49/bV7qgERxpHeHRG7BBJ14koG8owXHN0Yzl1Q KpBWjKM3FFnBKymSUJe1MEtsPZXemNq36ikXsRxDvvBnsIMw5nIrj9+uduLJ4/Fz ech9UNNMZo6XA5BArjlbSi+WrFlETmpDNdim/nJhCYtiek5/xvrDcQjiedE6W71U qTufATliln6zzjAsNLY5InDzX/ixNhjII+mpKtXBtK6lnadwxmvWdBC127jgzb7a BvczCsWuZ1R043KU75XyaemL2rbSqnOhm8QK8EcY/OZBs26CH7sKqU+W0E3taSA9 rGnylGoP9tPJC+Ptky3ixIw3Cadfuv+hgfIRMsitdkSzdIVdDiQBTYbN/mLi3E/2 5adArWxq+WpeULBTl2/5849Qq/jatUpDLTcaJ6KYtAGgkbaTD/atXARmdwq1M2RJ WVJ1vb3CnHlDuMVDjJjbASU+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQW+ZZeXELLNhcQDLl8PaaFTANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xMzEw MjMxMTAwMDBaFw0yNTA2MjMxMTAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE0MDMwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQC24qA8lmT04/1JqfGR+vxX5VZybG9PWcP8iPN0Aa4WnK3G cpSL35nv208z9yKdNKWk4HnycpVq01kOMRK1QBmjiWN4NJAuW35rP9ZLzmUQA4gc Rkpy3aMJArOfaIYd6R3xe9bksN58ja/O/xGxU/PiJweHmn/zrnVOPqoDD8Vs5G/h LL2svl3z+YfDhb4Winnir0P1g722oxlclmtJJQIamyzIPCJ3kiqbwsbcXyP9PSSj bR9Za6vR+hgNyNT1sBQIuLGBHunQHkLs7+E172S5pNIqCRGdhs0pS+4qTrkCla3A q9J0r4eykbkJ9h+7/JXdUff48vaP6Dsyrf8KnYrRYIoTCmU5Vc5YMo+A/Qn2Hjfd 3J99CD+XQTi9eiDwKOjxDyqBfz3x27o5m1yW/W7xmlBP+nNe5f9QPIfKhX8k4BVu GIjhA/tHVZ5qY6KQtxcYrzRDGgerDD4vZDlnELsrIG3KqhfryXlli9d1L/ePU0dj SpdPTrmi3QN55MGugxtomq1I+WTw6cqjk0PrJ/2wQ6CRwJtFARxyaplVzfXb/9TL gktekV8BWciwEc73Vk7XPr3gCpvVehbLHgCa0G2ZKYX9qKt1EcRhQxKzxiah0hz1 qesAt01ZDLPyDq7wkt3XpU2R1V8oMMhWAIAYjbMG5BhsakYtiiFzem7uNFKoOQID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBTKZejD+gM/CCEWwdFy3mHolPL+ 5TA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAGf7kwWmtFo7Ow3PZyj/ g+5hfPm78w/Px5d0tx/gNb4WVl7BLv+f7vvPeaWDoZ09e2UUOPxsbsI3RIUdZMTM IuLba+67ozsF2WGHdS/nNN2Sw+FvRHlTt2CJ14+iwWHTxR5Ws43uugtdb+Gvns/b BwSb25aGuENZ//Sj9El1c1iQ0P34LEY8LdWFX08w+h52RBD40nkxyQxpRB7/Ez1P YWJ+pME+LPFCfqNAQQvyA5AiWXiDWFvRCYaA+g28lTT040wlGrXzEx9YOYEdBVvm FuU6gMCxMYQnbVr5/hEVolcpPhqX2cMcNCZsOtio0qEQERYbVv62pb9YQG9ThmvU Q9kgE5GhwVsemuTXqbIZOtoW25vM3hZ+l4A3PeVe1aWqY0m0UmQ03ntakbK+d6+x hc7ufCE5d17DG7pWx0H+P3DCNg0a0HeWTd9FH5+jXoQXrHl30+PIrJqnnD/Jftpm cVhp6wrlUReWGJJm1NqGC1o+u+8CIze5nhCfsZ4FrA3eq3ob62cgiZMNahjxkIDV 2RPeWjUZhCwIAocgzLNHTrFxs0Y8pzBXIdJnziAV+6LCxiFN5TmpywgRv4Dq5twq jFNMspHDAIUbeBjRxY6BJPX6ZJyExk6nyTGp+Ol0BBN9KZT9PveeND8Ekh5qgcsP UxcD2Sw7mtw40IuGIaGFRNOM -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQdFqxbPxVc4lsJl+10LS2njANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xMzEw MjMxMTAwMDBaFw0yNTA2MjMxMTAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE0MDUwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDvdw5MyQjeBT3fPmXSlmbnd+ngXi8nWiWl2IV+4xh15vPv /TWgoiqnzF0ERuFHCeEKJez4AUJEDjSGB81ryIxLtIBmKy8L2tOk6u1ure4/U15R MwYcOlm/yv2PJ/AwdVkXIpj/64FJ19ONLP+yd2nHvfOkF7GiSTcseHAySegicExl MrvTWfVKSuttkgiiG9LyQspFPLhTHB9SoGjjaU6Z84mCqO36Zw1T/M5i2wtB5djd +kO+kMRU23TyU2ziq0qNsVtRSv/DA2oGhyoDZxrGr8TFWE2ftJHLKs7wwICX5tbA HbhdUxGbra52s6KZ/NDbtIFlMIoPZ7vd7XcHHrOdq7rEdtciXCx3oifsEztsEB34 szCBZA2TAzMR65ct5aAh9Yyn2P+slXPFGncGkHyRgoyFmFS6g05nnRjSdbo44HbC epDREGYHSpWSf5AIUscGijnrz+teKNHUrXanNcrJSW4UqmTntv7Zl6b+893sm+r0 0Hxw/nyU6hf8FKuzMLvGtsSeS7Bin/s7QklXFyxaun2u4uw+gpqxH/riLpe3dJEO 0OefO6qkuBpZpEwLwZrmOMiLGWMRa/lt1gNnrxvHxsgebUE6rILO2syYRCZQOtj+ T5XKje05c5solo92W1aJQbW4w/jWrW6nALUpgFVXhQnmtcmn6ZCVh03WY850ZQID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSrBLd4QmRecYL2p2RCe+UgDgyh FDA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAIND7bsynMuw+BDdDVpm l0qtYMdc2iODlnHET28v5a2M0cmumJj8132efmEqv/j06/H5XbnBgAVR48X5lveG 7guXDL3gC5NucfnRJFaSA3VLc4R5fyGYTZClcxfxhhsmquviCBZ5C20jb3/Q8K5c /x6eNuzVENw/XzSdWbHN559qD0iuf8jNIRd3mPzq54luMDMSTqGyUXvm/qReTP/y bHRVYXrygxwqYBrr9DnX68ZB/oyFX/0ixgl0f08n1lmJyokHfevFhN0D4nxJX2YH JUCZ86JcXGGrBbhhnSlAVWJvWp2VhCkyUQDP6i8H2e9H6PUaSrCXFxs81yNBcCJu ir8NOcTxnYj/tOkPZ7VPR8KMMG8xdfAsVgz2YnZONp/Ayni76AJwdG7gZA1RAtKt CesGIAdN4XyMwoNEMoW2P7ayAUtXDKj3jPw1vcz57ooyaIklmCK1lWZq+BiVwOV5 6yjoSNG395gsCmkBACataZg3fbP1czVShbhkBy378tpelEPfkzB8uf+VSwQzueDs 9jh6bCGdQaC9F4TSytlS+3i0cVC5YrPuP7hgdx14kZDkqNwDteb609Rf4AH8xNtX VJfTHeF4sQsBqxSeJUsBb7ow79pY9DseoUIMTg4dpyDXsHsAj20PlWDNxUx5oxI6 qYILQ9Hz/ojenK3Z7mshMRKn -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQRarSSc3nGVuzkLWNSlzc5jANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xMzEw MjMxMTAwMDBaFw0yNTA2MjMxMTAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE0MDYwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDweLXIdoGN58Y1ZXVlGdecmnGTO4GvgZNvhC5la3UKo3ck eWDSNnfEoDkVdq1qufxssi8UlyQhSmbWUZ9pIgJF+TthztguFDcSTi3TsNavzNn1 GDPc2G0OV6A9Gm3qTrdBSBJQZOaSqNgF/Px2vAou4PxFjpuo0Ut5yg2bX+s7G6IH eRrW26jx/hz3rgxJ1BuZnfRgKktDN+IUQZRTMoINWo4uK/+kHPETWN9dlzmnQJxA fiEZKVCJKysop7MVeGUj87NmTLAaRlOH+cKK8WgNvNSXRzC6ENyG5lFPCiT2Cy7Y 5yw2wzObivtbTl+QBXbxV4JCacbl1oW0Fh9Gu2V4PKUOESN7PN9Oq8p0eqFE7ARx 1ju8HxrEKjo+18zMC0yIC+3zFNsZV3H8WqqTOUI/uTJroGSeYEBuvJieXW9xitgv fVvygQlzH0p+ph96K/SaL5m+sOyKKN5xZHd3ctH0KRvGFAk5ggP1eAmVxmYgbfMF X8at9kXvcVITzE/bXdO5SXWE6Mkgd2QFTI5wuhWLwTohFTqn8SVF6CpQPNFxn9U5 Ef0V5RSM/n7FjCN+L41uX3vMFLBwUtvnGetiSThLfAnGM6SjFNMfJi3c4ZOtwOKK 2dCCjF8iC1eY8rNQiDWc37thb6S12m/aqREm/GDl9J2nWkvyo8fnb1IrGUOQ/wID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBRK2tOzK/icPgDBLnZLa197ulvj wTA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAHwgFmJQLP0a5r95ZTHh LRtTW23HzSBXDAFg85i86tp+Ts80L/wuTj4/bU2YAilsnifQhZBT/AiTOTZcdBhl UAYilBmc6R7XQ9c9sGVnDsLRyC+rMUlkHX+FZZy/3Lf9868ZQUyrULguxYCSX0w6 Owj9zOSjG/Wd49qCL5Zt6fLGOukKrHrmn2hjRRRGysOGOJiZa8IXm7N7kt9qQ1gu /iaT93/gPh5+mZOJUN99mTd55XG9HCJsyizRSfAI+HOiudCOeZM4mXNdidiBPsHn iRzK2n9ZNw5aEPEbFTl5yuU4OdL1CKwQeCdokTCsV2SrMes9FUU96yAFFIIm2OVh KOECg8frQTVvu9drHqq33O6por7e2BBLQTMW2GoSNxuoxnEjXD167ObPhslN+C2h 97b3xTBLZqPPhFHpfaL0q1g2peq8M64XrJhhz58+Yd2hDhYqclRyNfPMMgroLHPc FAFd2IsGDHE1S1IyokAkA+aegKiba0U8mqLIATCtpzZmYszk1qYdEKW+51YdIq/J iC8NJyA6yYz/BwjZgcyoZYayzMojOD3k1a3WU+w/Q3eJfjczQUmUmctXhJUd5UW4 9AH46xRQNdls0mOctd5PY/nF9C8JFTIolUlzDmRFit4x0vYnqzWWkvzk6RuCj5K7 mmaHVzHc92WR4ZH9hWMCcKIz -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQTY6hgcyOjJHurnso/ASPMTANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xMzEw MjMxMTAwMDBaFw0yNTA2MjMxMTAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE0MDQwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDbks9YvCgav/w+EljODPiIGUkRmlalsRjXt/WTH46dBdY/ TQRm2jKoABwOVkb93uvUhtnVjCBAiunAIOuYF9MM/oQw9OrB2T92oldc0lEmFWBs Qz0LZFI16OVp0DFVaqP40yFIkS2bh4/sgOgIC3sZfueQFhseFXjm7Walex3mk5AQ XmpSfn2JfhWL1pt35PVLGFRewOryz2G9eDlBw4kEn6jchXH0dDZFyIyonPHH3LUX BzrAkzVmgXxq9gj/OpY95AMvCABJuBgj/waJAGyjDVv2pImBrSCF2KUiWe86g7q3 Xh7oTCfWNjB5IUdJpRyeX6ltuEC9rkbK5gj+dt9MnP89Zo0LpjxKiorVP2hsrcyr W9sVL11iqfKOktVm6mtFkciiljFmJGe7BbgVWh3/Iv6WZleF53CsS+OzSBgq/FeB ghydAfgGdcuRY86cRnRdxckU51njtXNaU4oLMC18w5Nmm3jwzbmM4tHNbIYvDEhs XRqF6rIHOj+Q0Or3kP+WJrWPggL2K45s0bSyMOqQZmEalYpo55QlVeCEFBP5ijhT xceTj3K1fMWJDU+/O0wSQpwnC1uIVW0LVEgz21ldR6TqVTejG6FTVBV1FrkhSmza 5Wmlm6paqLt9ZOZQvecEJkSxRDKT4Sc/d79mtBpEC/W4Z6PkuWaDZzcfgibfQQID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBREpAjstLMlSCv8loDTbhUpavZY 9jA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAHGeCu41eyTVAYDctZj4 h/gkv0ncVvlomJAJG/EnVM7kS5Nhvt8fWB6MPcffqmgNhzRxcE6vTeYEtV27Bm8E hSzsp+tXTh23DL4fh0GDOEx9sKJp+YY9cT0cTEgm36Ild/InzMFJk3Vf+uVklQus YuH1VY8LJZ/ilFhUSOBnNvaHuDLPv++RP6ZH838QNC7yddXaGqpcCcjdjIHle0So k4oY/JNJOHlOt1TCzXJbzmdlZzYb4+Vx2MXT0FdQ1i8xujCUM9PWSbpCweKr82zU qJZNjgPWXN1Bq3KqTNH4p5vBIc4xywUt31Hru2o9WQadpZRtTrp4tRwS3uG28ZX+ zR/Ymbnt9pcWZSjcc4YmcOIOJWYciHDwfmz/eeWUiTaf4npwNmZtc7y1zYEP1lM3 fM9Z7o7j75Am8Z3ASv0unUoUR7vByEPsqS1WrGtunatV1WQExC8yadK31EmkGdxA 3go9rR+lGeCM5Sgwe7J6IBNJPJXKge2uDSFsZ/tWSGh9fIMXWPOPdmqnAJS4CTR0 YvXkU0QmNX6mGSC25Kcc/FyCMABP4lzYlgj8TPbzpLwsQNhf5gQ77W+L+pU7hL9t xAHVtOypyOPZwYeemGMSdfXfTHQuOi2YEtsdaoyHE3O1Jn+EnlG0cp0UEV9eWbzT pqwE+N1BqBgNNMgKBeNou4B0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQI3hOeydgmxsa/PfPuiXXLDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xMzEw MjMxMTAwMDBaFw0yNTA2MjMxMTAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE0MjAwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDbHHrbAFYKHPBTsdLdOkl+f0rN0/myCfiW7J2ypUkwShS+ P/1SP+vjWRs7A8miCndvOBKioU/64ZbYIxcG9wiZv/SJ+QNjxAq/hoWPguMsWUED y3lec+1vOmOoagmOrm6Ek3Cdq1Qt01y/4Lq04jTIa8dFsDxi7+E+PjuJymDeto4b Rr9NFEBfnyDLYsHiXl3IiHMeJ3sWvrEHyuAqcz9zXGGBZCJ54zumaSRqj7F79yGM rxyWZdZ07mW1WSgQHYzC7HKCNcgneyjTiTKWmUy4mSjh3UoDzlu0y2X9jepAGpzu Oms/XVCV/sNRWI1L9ofRg5bNXK0hTrJDG0zjTSfpx1H+kqzX8PkfFAXeXrTy3nY1 ghNrBZ/9b9P2tysUk8lsZ1ynvtXICjdK4KVCnZPxx5014TDAz1Qo7kAhlPlzXL9N 0uu8BxLRp50AxvVNkQBvbxGOpJ2K4BEqqS6x4ApRl/DSdf9fBtaRXnMmxChKPnhv TK87h4JOVeeN0v5vWNMbASOPOucRUmAxY0sZjymNxO+n13AgD+Q2DMVSY6uN5u8E eTz981PkRsbBaZSkTS0YmZGGv6kzyMUKeSbTwmUz5vrqlf9vjDkP8RixDst3//KN XoeW21F+GK/SfeLUYK0k6tU4RnfPIk14pgYj5sjuInkjmwb4AE/UbXNli3ftcwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQoSkKR1P6vNwCO54tK+URVUa1j 8jA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW00LmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUZ+jxTk+z tfMHbwicDIPZetlb50kwDQYJKoZIhvcNAQELBQADggIBAArbW86BMRywggDIKNtz lQh1MwHfJQBSMslGFZc0JrWxkG1owvEe/cjiwjVaYPHCpQJLS2uo/Je3eUa2QOjI AwrArbuAEhRneNJOCpWMoGn5W+Dt/wcxsGIMgUuWbp04ER8bsjrFMtZBtSRYz6f6 G+wZufjKxbLgh+mEKxY1IEwkhGBPZEzp8FCv1Wxn+dDEzV8PPvOk6XTHWFFw6aNp 1IcTkD/VlaHAxZureLGy7K48zN3vBFuZlzNKzVDDfG7hbb7NYMQvkRr7PIVUPd0T AjJ/nERwoq3VzEu5CnKHDlj8TwH6k3zRzKKALsYb5c4xBKV/iAA9y/i7UFpyOg32 R0IM2uHL9Qk+9JqPp2xsHIZXGOnsZ72yOsmweNPCs3DGakpe9WnSV9whtjWk4mTy CzQWsS119CprAC0X0itUOZmUr631DmeevKrxMGhRSEGgPlRVYPBYk9CulyAhyhg3 n5Ctq0qF1We4RzXR47n4cK+PQ4d7i9sVtcdtoulhcX8ZKu84v2X4M4ZzAvn/84r/ rNsAILr+SjTGzEJkjKiH8Ws6piDjxEUx5KnBIZOI/sZSLksF610nqhASZA4ebj08 Sd3YbkNtGQCWNmBNnTdhUQxN4NIuO08dTQtiDSViDYnRqWFhFRgNeTqPJlHnnome HTWgo4Zp64FBcZHe603tTP1t -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQC7seFj6kM/ExwjLmQ+XIbDANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xMzEw MjMxMTAwMDBaFw0yNTA2MjMxMTAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE0MDkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDEzstOpvRPr2D7TyYt26x0BC94f7KFDzNcqTt0JVpbOAnk oQFcea53x1ak711tUgbS1hjonoWI18tifIg7UYEn4lRmm1lqtJzbLiYqwbhX/5tg DCFGDMZsL+JdVXZ3WMWX6VcqISoIRkkawo2wj2iYn4t81MDo7RNjxWTHqqJ7ZQHY xPdiie113PPcwZeDnG/cuIr1L5cnYtBsWVs8M5woYoBqzVmfaunc9LuTVkKCo+UY Ock4cTSl1PrKbA8pH2938TivBTArg+8DDptd0yPEvmNcEEH67lGlxFTK+ZIuP/Ac z6cZbxcRAoJMYs2AAeYESlSvxlN1gqXeLMkS7pq5cmBvzTq9U0LaLhDZZlETCRgg mcc54s01nkz8dTsk22CjCvs4Hd+E/LnRDITX/MLqtPy9YLl5TwoeSlRVtJDcDHL0 sK7w3fWcqEROtmKe9eSy5pKfD5Xg0wSC4KwT649TiadW/A3S34Anm1xc8nntR9l1 3Nk6nemRJtz6ykooCDMNvWogvR6hbWW48jz7/RfK5pdF15baGTp48BJ40KF8wKE0 gUU8duySg020hWBAGwjTfssBVbJQ0osNHK0hg/7AK0CmLIvDV1Pw70tgf3sW8Jrt 4CsKyEe19Ra1vUt4T1CAf4yt3qd+06wnaxT2z3HQ3ZZZFrkWJbsAmqNX8MyTMwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQv5uiWPTfxGRSWeIDUEt42BhH6 6DA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAFl1l63t5gqtR+h2jSHA fohjy+GJin19MuJEc2224IEnsbLu99AkhIVS4NU6H9Ag88Yr2vzi1ikizvOUDMRp uf2KtLxJzKNqWYWGRcNnWufq6WPt+eE5lE3Swwz99xkWFx2UTpz4ZmRsYZvZZ6Ik lmO5D3adB8m18M2QC1IDwHfICbYzIPzcyUZxRHiGPjCHZjT3I+bAiSUL+zd8HiVU aYjOUq8JSjOk54NMMsvqMBzWjRqOgQuiQlIJEctKi5pnhONWMnrCuezrUSKWODiM 7EeTB4rs1T5VpRyKP8aKNhiPQ6owghONOUNTX9/CqndU6GnXeGRMRgje1py5kX7I vz89K3fPYtbjyZhW6FsMfTVojpzdT7bI4hs0XriVOrXDGJ/xQSp69hKonPKYdabX p7zPQgNNKjea04xqpgggzNwbkXxGjh27pD9gtBqCbB6Ix6KoY2T9Hy8NvwesIHNb 8ZLW7mVd2/0fX87Y0zjKqXivxq50vgluoUF9ecT5dnCfqH6a8hzSSG9ECMfwZMYJ XiAzBcY5xcmUk/wnLK8mR769VYk4F0fhVs0zABVZvq+nx17ii3EV95AQ1NxYiCwJ t4q/rnFvq11RGD58axa/e2p+qJ97Mlc+XzIhKdMCp1+u4xyvZJMI8N42IoT7jpX3 bk/Mx3ap6NJyWwROxVwvHWAU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQTsmYk45ApNn0l9c9npjfCDANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xMzEw MjMxMTAwMDBaFw0yNTA2MjMxMTAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE0MDgwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCuDOkheTQ7LbBOZr4O4TX2llKeOklDeRjgTsZ75R0Eu9rT run9OzboBXvEaw+Vo0CG4erlsUCL2mXEoJPWnS/3Y6SAiKSi1usIkBppDqEt3HAe tCWqmeszuPIj3fxNOiE5jT6q8P1j3H/+w295pc4Zvxt/KwE80h08gvzpARPobzRA yuC0MHT92o7KrWbnpW9xugm3me7kreF9RypMAdEPbKldVN9cSq9PFQcg1TbmpoSz +F2BAiR+rV3kjEAOe9QxTxONipP+B0b5rlwrx0zVvoyWjaKTo0N3D2K7GDxFfvoo VBsrsjNrfiLNqryC7N1tmq6fYtAz+ONUm1A8qPv+oUkfY7e+Dm86uvdm1h9onvkd XCzTP7/NHNj5aSa7ylFK+sAMhBOie4Z1FrdQjJMoyp9Wic/INWKyCJyzIZkpd07s l4hME1FBi8wU28M+sjyRjLna7vZPWK98u5yR77j92ux8T3GE4u74R/kyLglTd1DS AtdnFiC0/GKXBxvmSQUF1qnGNspK/NhT5dNUkmB+VzJBTo/Xnc5/uDn5nU8uD+PA pUW6KwQ5bwwsl33e8z52P2IrIbnuaiRypuDirW/rv55c0pB9wA9Y98xbJ4KKFNS3 snFWWSLJ3FsIVusWyY9H3Q60REgCsD/RzP5CO+MwmJysj5KNJRZ/lUwUjNbaEQID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSp3th9XFQ1UFAXQn54rta4MAVl GDA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAJp3OMYNr/HRbqiO4c5x qwi6rH/SSKtGd4ag9DgzRku1RLu9jsvYPfFIy8L9ctbCs30fmLwiaiB3xpTRt+lT UWqql+JxDcJhv8s6uHY4OC/JUhEdfRYE+8lMC0ClPmRd/570Op16RtMVqds1aHDb Fmrc5p7RYb4RnSI2Nr1vGVDiZffzsx9o2dIz6HX35LPzzQ0acbO/y+jfprbvhEr9 /2sI52SzN2xURqb4+s1vLX/PX7Hz7rYhsr8iVqzPFye85phH2qYeQ5YBZaTFBbm0 oXCVC2ABmOZl5TUilu8RTmt+c5y4MKX+6xaeSakeUaQL738Nk/mNXH7/8jdkKfS9 ksOrDL/ihIaciUlCn4RsOS27oCTAbDfRhQORcKnqDZiI8Cem7j0r3mGpFoQ4j2w9 FO/21/MLJP4ib5vW691ce4RG2uyzDnDqPHGG8Fvp07NWlwU9OQtVNJlxVmQv4rHT u6CwCZ+Pw4G8EUYc02YoSRL8Z/mcErXpob9SIVv694nqERFkFp4376RXurzD0EuG Nh7VfV76taQAuFv7V6I94dwXjcJYPh5wCWS4b7K6oxFWxEokmGtyacsxPCCW6/OD xHwxw9kCfF7sbYZzLE9rtjkK0hqaVsyMNscWoafADjXbCZIMd5UsnfubkZCxsRGP HnIKfJpHN4ZvmxHyAZzJBsI7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQWvhO1x07aQqjuyq4/vwAeTANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xMzEw MjMxMTAwMDBaFw0yNTA2MjMxMTAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE0MTAwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDbHQVtE6o0ACm+FVUz0D7/KIFdkpZi9U3XPv/r/eKc3VhH f1H70VZoFt3aQ2J8vU4JrcPGVtBJiz/kL7JSYYb4mr9XWWdLAiiLcNVjTbFeNIxi VbzP230r2KWQPKEzIM1FpJA58CTar80Wjb0GF0O40Sp31Wnl9r9W+fYFH5jAyvZg Byu9EUUgOjBFom171IiY1pSAfR2CZezy4pykMZlraloKSrHlH2o13uizGslnsH99 UJAea86h4LC+zaXAetgez/yMQBon80aCkY59mwFnM6ehv87+m1GOxeiYOry7PZ0r H3DI4lA+p7y70ZdZGNm++VByuSsygEAiw6e7ehL0WI4Z/u6pRc3dRRG5xWVHrfiU Q4s4btcO/KUobGIJiPI9lz3nt+Um3tMDS5MSIZIRBGZMWI+6tN9m3dl6l4+1SytT K+8W6zJWP6YWKdUF4DvyQ6sXAEtlMLgOyHMgpbIB+8pZPPE2xZ7fBsFxSU3/6Qyu 345Dolrx8v4DzC3wX5kO9k253H/Am9RQnJcK/kDuLV1meo9gX8/UZhkZ0RkOsxpW sveyUTnM+keElSLUTFtBEqqDCrr39utxmp1kjdWj+vH+/G4VBhKw792ovPGp9Tnj mXXCKA093HbFBCreEr1MDjG0TtGCFJmPt6fOVsQF3/W/6fgSePG/KhKmp6CjcwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQQUQLsZOO2xSS2l5L8MZVeNA81 7DA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBABK+XaDidb2eLjtwL4Qc PHjmCMhiB6glSDWY7acaSsOTF+vfgRAQHaZlzjYch7g5B8/jYTibwFB0x1H+/p52 y0xtYqOAKisul/NvYnyQ8TDZBz9FdZ6XLKk0D2AZR1Y3ZUHj8rbylXc8sWGtvpDA XULN1cp1NJ/eDFQpatjPBL/o+JulBL3wb2YGxvKewUSbGF/qL7jevsKtBSMBI+Hv ToMCqpvuY/zHRAUMUwnMSFx7LUWG1seGvG/AMRgn49fkLnaIfqUvZzCsITmcDr/Z x/1kfkBcunEB6i6D54bqNQy9Y2WgMp/FMHv7lrqStFtUZ+/R6uaSomt+hQBU+AzQ xgI6TWkNCCVizf12mg+igrA+8WExHpTDPpT1G+h6iW4Ejh9Kqng3O4M+k8Bf5wIU 1gtDI2HTQUNiW8yLB5PCLylsxfRvxEaAV8vDme67JPLUKo2PGUtVGl409H9NIeGh jullXP3PQvlIQRxTmPXE7pH4KSJfmasQNZ+jcw70kMJtVafyvCRwOV30YUCfpxoQ sduRAMaslc65/pta9V9VXJhD0tFoEAyF8ct9YvS6fwJAGPRZ/eRIuqv0w5CGIwyt cZKjeXvtfSqcHtJDxuWdYE5hEoLT6xumoGNdJgQTeCSJg9LBjy9UI4OsAStt9ZJD /dpsbpBdSqUMiwzO/HTa76wW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGTjCCBTagAwIBAgIQBK55YGZmkBq5xX+mbFvczTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTMxMTA1MTIwMDAwWhcNMjgxMTA1MTIwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDc+BEjP2q178AneRstBYeiEEMx 3w7UFRtPd6Qizj6McPC+B47dJyq8AR22LArK3WlYH0HtagUf2mN4WR4iLCv4un7J NTtW8R98Qn4lsCMZxkU41z1E+SB8YK4csFoYBL6PO/ep8JSapgxjSbZBF1NAMr1P 5lB6UB8lRejxia/N/17/UPPwFxH/vcWJ9b1iudj7jkUEhW2ZzcVITf0mqwI2Reo2 119q4hqCQQrc6dn1kReOxiGtODwT5h5/ZpzVTdlG2vbPUqd9OyTDtMFRNcab69Tv fuR7A+FEvXoLN+BPy4KKDXEY5KbgiSwb87JzPMGwkp4Yfb2rfcV9CKEswp9zAgMB AAGjggL4MIIC9DASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjA0 BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0 LmNvbTCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29t L0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMu ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDAdBgNVHSUE FjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwggGzBgNVHSAEggGqMIIBpjCCAaIGCmCG SAGG/WwAAgQwggGSMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j b20vQ1BTMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBm ACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABp AHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAg AEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAg AFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAg AHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBu AGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBp AG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMB0GA1UdDgQWBBTnAiOAAE/Y 17yUC9k/dDlJMjyKeTAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAN BgkqhkiG9w0BAQsFAAOCAQEATtSJJ7n9HYd3fg8oBZDxCi/JOz69k5yQxq/6kVGH MlRr6MrBcVFcmY61+uBiGZmmB5p8Eyfb5QKihBLZFfYKRFfENI9tcx861qABPd7j guRFa7LrJf2AXh05kL5bQvbOkWDj+aBWDEgQzjNoe82Tq/Bqy09YD7l7XRsEgZ6n IuJXSSfukpMIvmkIUwI6Ll3IGfRQgE4C2bBdkbSTh/mWloFVQI5m7YLYuyhf7Uxh 7QZYKBlTEUS8RyApsgRs2IlUmTt122d4LB6SeMZVPVgSETJuvUMMTTTbe8ZC2+y+ q5thTAaS447fISpQVwTAYKI11SSeZjcJSc/V+GWz4OJuwg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGXDCCBUSgAwIBAgIQCce327J4JDeRGV5qsTOHEDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTMxMTA1MTIwMDAwWhcNMjgxMTA1MTIwMDAwWjBmMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSUwIwYDVQQDExxEaWdpQ2VydCBEb2N1bWVudCBTaWduaW5nIENBMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylEWOneZ9RYkqbXk5t6VejEN Sp1qy30lfKSbnIT6CDRo9QkmPjFFsCFITNWZlYafGp139rtnD6VanKUP+5vl0hgq 68ZUDGKII2KrYZZuTxdiHoGs6RDmw525tvbl4ezGrkstm0iHY7wdn2ClFo/9kutx NMhexhXYikr8EzYwqg02HC3QDk+1MeRZTvQLMrlibHVl+HqJs5NbNEiw+Ev1IFaD pUj1jZRjTAMnqTBVZ5UVGylAI520qMcNZQCzEegiT29EmOT+cnXiuqwxTV3hD6aU LKDIKN2oRgU4jhAUmqo/hBbiTlqSX4WzRs1BFG/+yvqvva01Ci2BLJ+2/M0O0wID AQABo4IDBTCCAwEwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYw NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy dC5jb20wgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwz LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwHQYDVR0l BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMIIBwAYDVR0gBIIBtzCCAbMwggGiBgpg hkgBhv1sAAIEMIIBkjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu Y29tL0NQUzCCAWQGCCsGAQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAgAG8A ZgAgAHQAaABpAHMAIABDAGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBzAHQA aQB0AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4AYwBlACAAbwBmACAAdABoAGUA IABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAAUwAgAGEAbgBkACAAdABoAGUA IABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAAQQBnAHIAZQBlAG0AZQBuAHQA IAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkAYQBiAGkAbABpAHQAeQAgAGEA bgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgAGgAZQByAGUA aQBuACAAYgB5ACAAcgBlAGYAZQByAGUAbgBjAGUALjALBglghkgBhv1sAxUwHQYD VR0OBBYEFO/ONZPO9obF+IT1DOdab9kvS+NkMB8GA1UdIwQYMBaAFEXroq/0ksuC MS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQBZcM33MOO0+lPLfAGE8hQG CcL7ZEtlXqJe+QxUvd1mrVyE+N+Pemp3s+gskg9FmXKh9nU4kiUphbJuQWsF3f/6 4Z62HMQoXCF/o+fRoTHmBoqfUouM40z6Ier1rc8f2FWN3NQrsXfngxCpt1zCMTmY mAp5dyH199lwXcVmAhGblcDLrYk2CsCD6wqBnb3duPDTB1ESi5ttyu5Eswj0kXn+ 9eBiEfL3eWn7nZnJx68B506D7b4dzBCAxW82zzVU0YtHi3ZZwAwJyWqxZMst90/p O6c2IEnk9xfwew8hT0fTjtKQpGltT9IU4sdl0jqMsU+VFB+ccTNJ9lWsvqCwEeqA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGiDCCBHCgAwIBAgIEAJiiPDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDEyMjc1NloX DTI4MTExMjIzMDAwMFowajELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl ciBOZWRlcmxhbmRlbjE7MDkGA1UEAwwyU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9y Z2FuaXNhdGllIFNlcnZpY2VzIENBIC0gRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDO9dlPSpyVWm/ciVaUkcwhndhhirXpcyHBk1Rz0l4C7I7p3y7p fAIT8udsrfHIeTMwpa8kYSE9RrxlctarPU6KQNmeDj2ESQ5mG0IJl9ROOrDFrGkt qXtbD9ubd7yQiXO1hd1FeDXsxp44EO0332aWX1D/GEmMnuiFrEu0fqZvlbLPpmYv Dk+xBTkDzZtfqT55vtOahT+4/Mmz16EuKbdsc7tMgdMdeFmm+EW2GGz//B5/s98a b7WaZD0QyHT2bO8qJEQZrjeg1la7s1gJG1bOAba2rQ45DznjC0Bl3TqIabSXJuZz oh85IDAaboDnjoBDcJICsoCqG9QqaXuMrLCAqlVt8UT00Tof/q76ugyhy21xB2JY +BlTckCMPcMxglm69feNR352dD8xi5LaDyiq+x+xeO4R3Lxu28hMDz99aEZZtp8t 6vG90CvT8tmRAVV1++xkExMra2SNWrOSrJlsw+SEz50L6mcCXWVna/pZ0rJ6Jcuz 3+xXgbeFU7tP3KIOOOHEh/1Z/Lg2ceOqj7L82CC6Q6DYp2H0cg/EZ25iDdp1SPW1 rFjNEqQohfDzBOd48v0vF2r4xIpQTkwuR1iD+n0NofNyf8Xb/pmUeHvNKHBz/yby jJu4ozlrqNn9zqgZBxBGygRuhXDRROpYHqAhYrgqZrDJvxjh4IRQRdgwswIDAQAB o4IBRDCCAUAwDwYDVR0TAQH/BAUwAwEB/zBdBgNVHSAEVjBUMAwGCmCEEAGHawEC BQQwDAYKYIQQAYdrAQIFBTA2BgpghBABh2sBAgUGMCgwJgYIKwYBBQUHAgEWGmh0 dHBzOi8vY3BzLnBraW92ZXJoZWlkLm5sMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEF BQcwAYYhaHR0cDovL3Jvb3RvY3NwLWczLnBraW92ZXJoZWlkLm5sMA4GA1UdDwEB /wQEAwIBBjAfBgNVHSMEGDAWgBRUrfrHkleuyjWcLhL75LpdINyUVzA/BgNVHR8E ODA2MDSgMqAwhi5odHRwOi8vY3JsLnBraW92ZXJoZWlkLm5sL1Jvb3RMYXRlc3RD UkwtRzMuY3JsMB0GA1UdDgQWBBRD600A05WTzqZ8QA1tEb450TKu4jANBgkqhkiG 9w0BAQsFAAOCAgEAa/1K28scJPeK9DCjkBE+R/XPqFfhozuNd7P19N2IZJhZDaTT 1yfLsAJ4labZlQEDgIQB8uPBFY7ZyxJGX/o1y+qb+43amRmuMZV9ehrfIpNIgLjP EmpWRwv3CNCyj2P5d+rkFtiY7Xt8BRf6Ftvw0+jS7I0J62PqqBuZ9/9+n9TqUzmf fUW14VgaBVKevMsO3jyAsDj1Lpszy6rxN3OI6LY+nYUmKY+4XJqWoA10rDHX/Y48 y854d0ih7p97X9B9/4fZ7Z7v4fJapTOSx3ayIExnOS7Ir0kOKhgriX/bVAVzjqXU cHCuX079fQ3EiBqI0Lqb3gauIBTn5GBis087iieGZ5+HJAfb/13F7WvxW5h0J8BX BO+dCBc1PrzlgGmKwdFkvmVGnt0ZUw+6v7JTTPeMnZh39sFLGIlFzasBW2uMXSZS 8EEeNlXp9m2UFnihMS/axY/nOsavinuXMzVpITHNZy+VlmA1bqggdvP82EUlQQav Y4/sTitHKuVN2RKuk+r43UWId/J8yKBjNZX7IzI/Nc9AjJIxmdJfT3J5kNpMSOzI qHfgR3Fvq3VT7tGVhw/yCAtnHq6pe2uarGHFkik8rCbqlGQktVcdQthJGV1GqBm7 aow+p8lTbpUo3/5HAL8fjVLmsiSsyCviPXDHX/ElBvwxDzu9c1MZJaS1b18= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGSDCCBDCgAwIBAgIEAJiiRjANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDE1MDkzN1oX DTI4MTExMjIzMDAwMFowaTELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl ciBOZWRlcmxhbmRlbjE6MDgGA1UEAwwxU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9y Z2FuaXNhdGllIFBlcnNvb24gQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAL5i6Bk6ei6+96HCdS3EBJGBcN9Zn3vNRRex4IRjbwAWeAVI6SR3 9R6YNiL/lOeTQkvnWsRb1cpWSFCCLExY65UzjwxWUD/Qw55Yx/6uxoJ4bYjI33Ud QZuUyx1vbf97d4KadXLpixkwbswLMuF6o+P4vd8Kl0ZEfoFI7Ky3Lt6Z1V1s3C2D 0sIH+EvxA143s6imwkRFz1ffKEl34D2QAFBcIUt4hRIW88emy0QCDY/rQjOJvfGu BrnSQXDLVDQGh/vAM2nLz9hr9pz7sK+KxJOa4PYqSpwgyPV1O25IQNU8M22OPask Q5DhaW7wahXZVjoBhJJqIwl5CVWTidOh9/N4J9gkfdLj8Um99BApfyTLSZdXzHm9 FOvJB2boXJLsOonpNwWtqd69CDlGqaXVnApUKwWNvA8pul++6J6ErorHlISuSlLD ULlDyAk6K2zdqK9OjYInUY2BkJFkygzTkOjg0oa63ksln1NekN/tyXDFFvFZB1IQ Q24RrXMYqXN8dX/wWuxDDCj+lmQyMjf0j+QzcVJIGmgm1eZLA/9wQWRypzlpbyyh Yp1ShPzzs4CyQB9DqpzAohm39TR0EwN63AaTNlyO7c4z7aIVu2c7bYgJdd30J6MC gW0d6e3d7+jtGtyf4jhOCVK0F+2Vl5HreZIGxTYFDA+FKspOBse7xd6nAgMBAAGj ggEFMIIBATAPBgNVHRMBAf8EBTADAQH/MF0GA1UdIARWMFQwDAYKYIQQAYdrAQIF ATAMBgpghBABh2sBAgUCMDYGCmCEEAGHawECBQMwKDAmBggrBgEFBQcCARYaaHR0 cHM6Ly9jcHMucGtpb3ZlcmhlaWQubmwwDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQY MBaAFFSt+seSV67KNZwuEvvkul0g3JRXMD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6 Ly9jcmwucGtpb3ZlcmhlaWQubmwvUm9vdExhdGVzdENSTC1HMy5jcmwwHQYDVR0O BBYEFO6sbUDq1QRqhyxVe/U/Ldru26ziMA0GCSqGSIb3DQEBCwUAA4ICAQAc0SFs KlBFkqBzLK5lYqEK2QLsFRL8LUs/M0lgPagWV6s821nXdpsizZN5ogXzHwspo+vw wHh0q88CNZ8tsm2pwVNz36eQsPRL2sPlz82VVVZf59gYsfoTcH2ID7n5mtT0YeHT k5ESYIJhQfxv9JGa24QMN3EXPetPNpJYdW0yQUbejwpsE4eSV95FPweb7DqfsEfW 1kNgsZ2lF2CJQ3KvKOlJmuQHRCiS9FC278ysBHQZHUK4WcabDKg2/C3B1JH2QeaI +S1Vdy3hldxgfrhj2jiUGbddDvLah3vxWeu0FuymAfyz1xmPSOsllKqms6aevdF4 JW8kBBUaNI5d8X+9TpRFMrV79udP7amHxpreX3XRBrF4mG1EK4zCVUDxSm+4BjvZ y2cfMdTV6PpAzHI2I2ljqy7eofDphlILUSvKBD/OUmaFvvGmj8/nXWj4lo6Zj8Yw huM3/B/ivITuqgyJkAXsFc4r5135VT+h6UVFk6G9rrMBaqBCO5nSwt8woXs9e85T v7kLA1lSezbKCeJ6QPoKLQbSJL/aVNyv6BAR/1ySUH5jsTeXHg/yEI42KfszLaM6 ckD1Q+nXlqscn0toycwkA93mt7pfHxote8UGv+qyIky8MW1+lDXLjhqfHt7Hkdlv nRbsryYG+8XwaaUqYyo74oTC45c56ey4gAGgBQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGOzCCBCOgAwIBAgIEAJiiRzANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDE2MDgxMloX DTI4MTExMjIzMDAwMFowXDELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl ciBOZWRlcmxhbmRlbjEtMCsGA1UEAwwkU3RhYXQgZGVyIE5lZGVybGFuZGVuIEJ1 cmdlciBDQSAtIEczMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1mSv ha9/607di6OCl05lITaHZo97HY3n/MfkOPZU7N6cnNrqdTqoGBGF5IDvz/BeQ2fh qYpLyLWp0ihNEqJpAgBo3ZesO5cSx7plAIz3/TNUGgIe1QMs3yFhA1/jmzwFrVds R+aaEyAd6a5sx5d/BlejrxulZx/TzlUdpDXguldgeZbIY5N2+YaYF6Dugp2oA1fX jTFJpKkHksb+lawhQbg0i4qz5pAxJBDV96kI5Rhyw/jj8aECFlz8rtnxMWzu1dZU JpwCMFhBgtW8jZB9avkLl478aZXA3lPLJ3d8iqaoa3uwEi2gYIk2Wss2YaWqSH+3 jGe8IQ1g3N84RhFbp6u/oFKCQhdw6Ep+KJVRiVtAJ+f+WysaarUZUnLjSZ7RmisO lKVOjHcM5SAhH1h+CO2TJMb/n5CeJWqsvWzYF8oHkp0CTwGXYwv9AaEIHrLeOsQa O2fQGR3ve2xmTrZ/RsbF3l/4AAxD3zKJR7ZK6Wq//cyfk2eLXte8038GIOuR32yw zq0WaAHiHdSOUwJ9A4ESali8LVkWFb1gB02q48m0etNUS2iLWMpUoNkDPmQDf+zs l41P4hGOGhQHUPaSC8C2ng0ApusCdHRBFfQ5VCxApqVyqtv7qjS0MaO0ZJ/011tz N4wBIUuAimcqHK4aFnqVjXZ/f+b+D3kzAfR81IcCAwEAAaOCAQUwggEBMA8GA1Ud EwEB/wQFMAMBAf8wXQYDVR0gBFYwVDAMBgpghBABh2sBAgMBMAwGCmCEEAGHawEC AwIwNgYKYIQQAYdrAQIDAzAoMCYGCCsGAQUFBwIBFhpodHRwczovL2Nwcy5wa2lv dmVyaGVpZC5ubDAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAUVK36x5JXrso1 nC4S++S6XSDclFcwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC5wa2lvdmVy aGVpZC5ubC9Sb290TGF0ZXN0Q1JMLUczLmNybDAdBgNVHQ4EFgQU/2h1Qn36b8da kzifNUTQqi0AsokwDQYJKoZIhvcNAQELBQADggIBADrRjY3nfuEF6GBlbd+hphQ7 kegKoO9SRtfBmimpMgK+uDdqHAmCC4IXsph2pGhGKSvblVh6jKGKwE964Q0XbHgK dWJZ34M77Wf8uoiZm6h+qVIC6uRM4QpkJzqwMC6hPB95WRqe4V12aCZbUDEUFGwN Rd6TsW4wyV7KIFy46TV+8EeFka+lwEVkt3y8lZ2KBgj6IfUACOOCN/uxNMxAg+f2 nfLzE57JBXkqCb5wNOuccaiqpij/ZDHhmcRfiyQRl0H4XSDR/4JqfSwY8z30oVJg B/QOF8ZSXtdHJIiaSq8Tmp+3vlIi1OpG6/Gc7bd2G2CIDhyb5Hg5wKJVzMpRmMUQ Xn4kQ+CgnNICdFHmda+LPp/8gGwE04a979CV5oBjKL2SBiFZ3KA81F1QKpjjAj0M W65obVOvL1Gq3JezkWK184dMPpxpQBHJyGq8vVpl1e9OzJHT30Vidp+7y6llZ/aV 69w287sr7iDEKlL+RdrXzdXoMlRYm4O6/2KBOingxcDq5XZSecAOTj2eUXSeqUu8 LCRvgWBV/EQlviqbk5d3AG0HxaSCfc3FYmGob8hMWtovvkBddnRSrcSTvqBYbDUN XTqoG0R4MKrzDF387d5Shk7rq78kU0ZRnvgS6ow1bHUtG98piNN4e/zNRxCgnka5 Af4jQMeoZwscW7mBgf2l -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGRzCCBC+gAwIBAgIEAJiioDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNTA5MDQ1OVoX DTI4MTExMjIzMDAwMFowaDELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl ciBOZWRlcmxhbmRlbjE5MDcGA1UEAwwwU3RhYXQgZGVyIE5lZGVybGFuZGVuIEF1 dG9ub21lIEFwcGFyYXRlbiBDQSAtIEczMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAmZ7UyhfSvaAe3Tto1leGvIYl7Uotkg9yy8y0gev/IxOSKx9sLbkj 4vXs7VJBKcqvsyC58lCeVnIHYoNx1k8oChL0vbKfDtzL3Um50t5ZAKz7z0JEfKLN y8q94nU91G58kCB+s2sAZ7YNIjXp8O/0tr117nQhsBp4pEu0A+2ykRkprn588lo3 rxVXZu9Y0yQw1oD5UOsLyMklV+0tQtFB0xpWsvZJoCUR6uGnlMV17rvPa2PN2PgF qs5uEdsbhOhA13TS96nM2WE+e8q75My3mAn5X6rT76wWE5P0SIE9UBQKCtpiHCas 9Ud+e9BGFmIr/dPMxEPxhRN/QHVW4cl7dF9tojuo2Ac6t30jiDQWQyrY6sUoAsOy pOn1LfKhROV999zSZ2hVEHd5ww+vyNed/5/GvKF74+eVX0Ovu2SrXpNyPkwQSwNQ /ShBrnyy2oX10beFUiqaoFOxmnCgfDulA9keE5swDQDkhQzEbLGKU4UB//5rylCB 03vuD6RFHykztglq4xMfHUhiOgO9pcD8zKGdnhCmi9vLaG5aRDsPX4bO4NbOHj1Y LKW3Rem2gEsswYBt20mVoFGNq2B3foJIPWERQWbFm/IXpuJUk3M17RN6TW7KGCbj Trvv921ZRw8kwl0h+OFiioWPopDI8Sh5a8j6hLhcIVONl1miJCgGVJ0CAwEAAaOC AQUwggEBMA8GA1UdEwEB/wQFMAMBAf8wXQYDVR0gBFYwVDAMBgpghBABh2sBAgYB MAwGCmCEEAGHawECBgIwNgYKYIQQAYdrAQIGAzAoMCYGCCsGAQUFBwIBFhpodHRw czovL2Nwcy5wa2lvdmVyaGVpZC5ubDAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgw FoAUVK36x5JXrso1nC4S++S6XSDclFcwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDov L2NybC5wa2lvdmVyaGVpZC5ubC9Sb290TGF0ZXN0Q1JMLUczLmNybDAdBgNVHQ4E FgQUbRslAl3gSPRuE3XiV4SdUPMwFEMwDQYJKoZIhvcNAQELBQADggIBACiGmS3h H32JNER6NkU9vcDxuLkp6aiJuAIIZll9LbMl5mVOU9I706yCj5Wypnf/y6nxuZm9 lNh9ic8fvSr1Jn3Pb1zpe+wXPO0XGy8OFjvsgXySFLDPPOF1PZSUptG/7jaGotfa M1uFHuBBw/0K1GwPJimCI1MAXR+E4SVS6z5WWHAZr/A7xi5qR9HQih7xK6h1+g8f WC4Jdj3QO+kzHt61kEiZn4wE5F6ckLCTYPl6vTXWBsK8/B66R8M0zsANKco6M+D8 dES9DOL/N9h4rExgHXQ1RPZ6Cm0zEHEGlQvHTzZPS3mhBHO1OuAFlUu4J+R5c/cM yZeWb2GbblxYqF4MOXv1NQpnrjvPy7nJFfFRHSITh5QZHQeNyS9c0RZAJxE1ol+T vLaEhnwNqmcJNHJq8c7HC1OK/zIelvvyBmofC+ke3a8DAAWiPeLElbBqQbWsPb4s dryHRNUN+A4pb9vlsT94Fc1VOdU5gHHoMDNM1PwEqg0pxM/k7H53X4J/MoNEx1zg mP9i4WbpfPwJYrHkf5MlvUEXNNS6Km5nIOur5dJ/EnRmuLODTjYOHniHKWv/rhLS CCB9XzOdh1QFAOhJgYqHoAh/epcgaZb7IyYLJv4uSTt+quc40eHH3dagVOHCI+zV jIbY/z8GlY+Rlh67XW2a7PcjDMRmwsilXZ5j -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGMDCCBRigAwIBAgIDD+Q7MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFkQtVFJVU1QgUm9vdCBD QSAzIDIwMTMwHhcNMTMxMjE3MTI0OTEwWhcNMjgwOTIwMDgyNTUxWjBDMQswCQYD VQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMR0wGwYDVQQDDBRFLk9OIEdy b3VwIENBIDIgMjAxMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM8N l0zs0ovThYiSC3PfdeQ02NXu1IypCXOISSmcfU+XFF7bcfmDVECUcBpBpjCU8SCy xCzZnoke095+94T1l5wXaIjVTtx55grkQ5lIzdsEVb9zunDZfPMPRCZDETrcaHkB aMFuu4wamrS0tvBOCoBlHKD0ddJF+m6YDn1odGwAnfFcbMQfs66C8ma5GyZFU4kR IbdTCR5SCjJ9SuV+bFqZzTfgfRqtOLuvdNrOZO2G7LQRie98wh0jcdFyaPEITyr6 +C91zlpBTsesOJGaEPo3wdZ9gZkj0POBR0fMQQzug8W6AQSBYkHYsJuzgD8fchcz DcsR/+fFULu0DL5Br/sCAwEAAaOCAykwggMlMB8GA1UdIwQYMBaAFD+QyH3HFW/z JI+pwy9Log8hsi/nMIIBTgYIKwYBBQUHAQEEggFAMIIBPDAyBggrBgEFBQcwAYYm aHR0cDovL3Jvb3QtY2EtMy0yMDEzLm9jc3AuZC10cnVzdC5uZXQwSgYIKwYBBQUH MAKGPmh0dHA6Ly9wa2kuaW50cmFuZXQuZW9uLmNvbS9jYWNlcnRzL0QtVFJVU1Rf Um9vdF9DQV8zXzIwMTMuY3J0MEUGCCsGAQUFBzAChjlodHRwOi8vd3d3LmQtdHJ1 c3QubmV0L2NnaS1iaW4vRC1UUlVTVF9Sb290X0NBXzNfMjAxMy5jcnQwcwYIKwYB BQUHMAKGZ2xkYXA6Ly9jZHAtbGRhcC5pbnRyYW5ldC5lb24uY29tL2NuPUQtVFJV U1QlMjBSb290JTIwQ0ElMjAzJTIwMjAxMyxvdT1jYSxvPWVvbixjPWRlP2NBQ2Vy dGlmaWNhdGU/YmFzZT8wZgYDVR0gBF8wXTBbBgsrBgEEAaU0AoFIATBMMEoGCCsG AQUFBwIBFj5odHRwOi8vd3d3LmQtdHJ1c3QubmV0L2ludGVybmV0L2ZpbGVzL0Qt VFJVU1RfUm9vdF9QS0lfQ1BTLnBkZjCCAQYGA1UdHwSB/jCB+zBBoD+gPYY7aHR0 cDovL3BraS5pbnRyYW5ldC5lb24uY29tL2NybHMvRC1UUlVTVF9Sb290X0NBXzNf MjAxMy5jcmwwO6A5oDeGNWh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1 c3Rfcm9vdF9jYV8zXzIwMTMuY3JsMHmgd6B1hnNsZGFwOi8vY2RwLWxkYXAuaW50 cmFuZXQuZW9uLmNvbS9jbj1ELVRSVVNUJTIwUm9vdCUyMENBJTIwMyUyMDIwMTMs b3U9Y2Esbz1lb24sYz1kZT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/ MB0GA1UdDgQWBBQu7h/x28HWct1C1TXtzy5RumGyZTAOBgNVHQ8BAf8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAM5zTymCq3p7Qp/2p E37bRNY3XusXxcAMMpebMUARBVVhkrXqYIzlWkaQDwRP67cYOxf53RyHLbGsFwxF FjqLd7u9BRNxJ7ax5bi3Pwkey3Xw+64bAy4nJ59paWtHBS/OtpgPcZS1t7MaB309 kH/qm0oJgO7+jl77OIrtf6QYPwOidhpSQBCzqqmcRfYu6ch77R7eTwjwNfjxr1dJ N8ZCm+yzVUcmXssPZv6kzogRcN+Z9KOhm2wfSwjr4dQPbeyB96sMUeRMjQYku0C5 36w6ygPI58CkgweCpr+Qx+0q13ftIIDuzKOvg4c2HUuEGTayb3fIFak7bjP+DZOU Afxyjg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGAzCCBOugAwIBAgIDEBymMA0GCSqGSIb3DQEBCwUAMEMxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHTAbBgNVBAMMFEUuT04gR3JvdXAgQ0Eg MiAyMDEzMB4XDTEzMTIxNzEzMDcwOVoXDTI4MDkyMDA4MjU1MVowSTELMAkGA1UE BhMCREUxEDAOBgNVBAoMB0UuT04gU0UxCzAJBgNVBAsMAkNBMRswGQYDVQQDDBJF Lk9OIENBIDIgMjAxMyBYWEkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCi0FomtqedrDB17XvBOLHFcmJDv5C+1Is+hVx59CxkYbI7uQ0otPCbwa8BTPSt N8lhFspsak8kA9Iv6ccXSrYF6fL0bG2IryyYQDQEKrbtv9HbBzqCKHtR20B4bXF5 rq5YQof872enbKplBg+9lHaRZWsvJlXwuRIEsdy8cgnIXMLsUclGXaKVvjJVUnq3 S+fNCJzo10etlAzpbGP8iJnumR2+2F7hTaTzNInlJ4HqRV/bSCMK1Fi/TpzuldoN yVBC/V6OgzKurNEIsnW8G9uBEYETEBdbOBWCpozO4m0HOXxBlYLLpuAN2ioKWs4S Abgu2MFAK9BoZz94QwYv9xYZAgMBAAGjggL4MIIC9DAfBgNVHSMEGDAWgBQu7h/x 28HWct1C1TXtzy5RumGyZTCCAUsGCCsGAQUFBwEBBIIBPTCCATkwNwYIKwYBBQUH MAGGK2h0dHA6Ly9lb24tZ3JvdXAtY2EtMi0yMDEzLm9jc3AuZC10cnVzdC5uZXQw RwYIKwYBBQUHMAKGO2h0dHA6Ly9wa2kuaW50cmFuZXQuZW9uLmNvbS9jYWNlcnRz L0VPTl9Hcm91cF9DQV8yXzIwMTMuY3J0MEIGCCsGAQUFBzAChjZodHRwOi8vd3d3 LmQtdHJ1c3QubmV0L2NnaS1iaW4vRU9OX0dyb3VwX0NBXzJfMjAxMy5jcnQwcQYI KwYBBQUHMAKGZWxkYXA6Ly9jZHAtbGRhcC5pbnRyYW5ldC5lb24uY29tL2NuPUUu T04lMjBHcm91cCUyMENBJTIwMiUyMDIwMTMsb3U9Y2Esbz1lb24sYz1kZT9jQUNl cnRpZmljYXRlP2Jhc2U/MD4GA1UdIAQ3MDUwMwYLKwYBBAGlNAKBUgEwJDAiBggr BgEFBQcCARYWaHR0cDovL3d3dy5lb24uY29tL3BraTCB/gYDVR0fBIH2MIHzMD6g PKA6hjhodHRwOi8vcGtpLmludHJhbmV0LmVvbi5jb20vY3Jscy9FT05fR3JvdXBf Q0FfMl8yMDEzLmNybDA4oDagNIYyaHR0cDovL2NybC5kLXRydXN0Lm5ldC9jcmwv ZW9uX2dyb3VwX2NhXzJfMjAxMy5jcmwwd6B1oHOGcWxkYXA6Ly9jZHAtbGRhcC5p bnRyYW5ldC5lb24uY29tL2NuPUUuT04lMjBHcm91cCUyMENBJTIwMiUyMDIwMTMs b3U9Y2Esbz1lb24sYz1kZT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/ MB0GA1UdDgQWBBQda9hLMVeT0Hntfjoe4WEzGo8zJzAOBgNVHQ8BAf8EBAMCAQYw EgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEAhgOnaizY6byc WhAbTZc8CONbIp/iVK04Z0YqSfdHddYIj8XvLqU17p83z2PEJBivggEGs5IgikvM MiAvV+vzPRRW02sU0K/9qCqexWlLtrQ8NXIxPD2o/EmxB9vfkefRaxE3GZYLXpwu yvrmeznzxdOxI1vxNeBO7rtIqhM6cmIkpKgPluBMn4PsOi/Lo/inIEuPHtVYCIfy AvoilwxN8EJR37pvilCL2mwtZRVS3bWdKEjOkbK2MH57yWFFc6EA3+eBwu85u8S7 C4nsEgAb5P0zjc6/ln9qSomiXE0E0BZMaWOErpH5gMBKNk+xz6sGcPcMRFKt5Tg1 C1v/93N0kg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGBDCCBOygAwIBAgIDEByqMA0GCSqGSIb3DQEBCwUAMEMxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHTAbBgNVBAMMFEUuT04gR3JvdXAgQ0Eg MiAyMDEzMB4XDTEzMTIxNzEzMTUwOVoXDTI4MDkyMDA4MjU1MVowSjELMAkGA1UE BhMCREUxEDAOBgNVBAoMB0UuT04gU0UxCzAJBgNVBAsMAkNBMRwwGgYDVQQDDBNF Lk9OIENBIDIgMjAxMyBYWElJMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAxlRFecAGoA9BktESwWToETHSwgEI18ZDW6KUpkg3fSdupCMU9lDdotCOWZyj Eq7rI04A5hcezFhRSu792Tj/adgFyxgqTr94Ree7wEkBPPrCKz0h+FL8YkCoyvsf 7pre0C5dd1w3y3X7TwhOXt+l//AiXSLxg23qDfZY59R6P2l3SFXP48X2pOHTy5PA wj2qVBp2a2+IKM/9ZLa8XQz8P0gOBjnfW02nPAh2xWlRpQynOaI3YkpulCBRuqJ0 zZ0DARqwJuY1OgbHxZDBvRwmkr2EIpIzMgDtaqEcZCwu4pg/4GhZ4eY0wMR5HPAO VFKjDV5CjGhtzhZwcgrb4R+dvwIDAQABo4IC+DCCAvQwHwYDVR0jBBgwFoAULu4f 8dvB1nLdQtU17c8uUbphsmUwggFLBggrBgEFBQcBAQSCAT0wggE5MDcGCCsGAQUF BzABhitodHRwOi8vZW9uLWdyb3VwLWNhLTItMjAxMy5vY3NwLmQtdHJ1c3QubmV0 MEcGCCsGAQUFBzAChjtodHRwOi8vcGtpLmludHJhbmV0LmVvbi5jb20vY2FjZXJ0 cy9FT05fR3JvdXBfQ0FfMl8yMDEzLmNydDBCBggrBgEFBQcwAoY2aHR0cDovL3d3 dy5kLXRydXN0Lm5ldC9jZ2ktYmluL0VPTl9Hcm91cF9DQV8yXzIwMTMuY3J0MHEG CCsGAQUFBzAChmVsZGFwOi8vY2RwLWxkYXAuaW50cmFuZXQuZW9uLmNvbS9jbj1F Lk9OJTIwR3JvdXAlMjBDQSUyMDIlMjAyMDEzLG91PWNhLG89ZW9uLGM9ZGU/Y0FD ZXJ0aWZpY2F0ZT9iYXNlPzA+BgNVHSAENzA1MDMGCysGAQQBpTQCgVIBMCQwIgYI KwYBBQUHAgEWFmh0dHA6Ly93d3cuZW9uLmNvbS9wa2kwgf4GA1UdHwSB9jCB8zA+ oDygOoY4aHR0cDovL3BraS5pbnRyYW5ldC5lb24uY29tL2NybHMvRU9OX0dyb3Vw X0NBXzJfMjAxMy5jcmwwOKA2oDSGMmh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3Js L2Vvbl9ncm91cF9jYV8yXzIwMTMuY3JsMHegdaBzhnFsZGFwOi8vY2RwLWxkYXAu aW50cmFuZXQuZW9uLmNvbS9jbj1FLk9OJTIwR3JvdXAlMjBDQSUyMDIlMjAyMDEz LG91PWNhLG89ZW9uLGM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNl PzAdBgNVHQ4EFgQUdOjKi6wNCmhF5NcNc8tJk15CA6wwDgYDVR0PAQH/BAQDAgEG MBIGA1UdEwEB/wQIMAYBAf8CAQAwDQYJKoZIhvcNAQELBQADggEBAC/2l5Rt3Ato IT5r6wRUQfSnkty30SP5dvQ8AI8K1N1a7Yi2VfAnfrHKf3QMouNGINmcZwCswLoU 0WI80MnE3ey2xMARCgBCwV64anT/P4oK44iKK8o3tpoom2BNTxO4JW3ob0u3Py8Y H0oD6GEkhwk1AGRKfW55sgs5gZgyE0jCDha2Lp1/X6RqEFECxeRRd7WO1O50EjXu 7MPbV/VjeTH7ySx6WAleTMFEa1i3HdwnGTDBmdOJtfd88Je7SdNcGJsBaLKmjk5m hNR3HDZRpxPFHg6URsZAxK7MVJ0Sj7xM4H7yuvGIbF4nMKyAgO5EbTwFjYpqVSgH xbELV69WYxw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGBTCCBO2gAwIBAgIDEByrMA0GCSqGSIb3DQEBCwUAMEMxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHTAbBgNVBAMMFEUuT04gR3JvdXAgQ0Eg MiAyMDEzMB4XDTEzMTIxNzEzMzUwOVoXDTI4MDkyMDA4MjU1MVowSzELMAkGA1UE BhMCREUxEDAOBgNVBAoMB0UuT04gU0UxCzAJBgNVBAsMAkNBMR0wGwYDVQQDDBRF Lk9OIENBIDIgMjAxMyBYWElJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAL1l5NYcgaMN4vJ0OUL+JcPQiW5i4BfZPNn7Amdty6qUnWargDmi8EJRzqFV aeyTPlRD+Ci6WgECwFYJ0nTACGbWW2Dtu2m4UwzpjG2UUtZ7DSfgQBInZkdPNfdZ SigAdr/KXWiwJnxvhOajGZSQvuSspPvQtWIO4xKVSyMkdur9cHKHAiY+kdpoZpk7 mi7L9ZPpUEVMBL1C/COWsHJIrdwsfRyFrWwB9Vxo3sgphAaySVLZO3/wslK8rFz5 cdajwfxIzhpZ1O7FmJKWSb4rWYvF0EVPqBkd1s7fPLuCp/8malZYZm1YChZTz0/Z dYUws6LHhDLf+XQuKo0+mT8dhpECAwEAAaOCAvgwggL0MB8GA1UdIwQYMBaAFC7u H/HbwdZy3ULVNe3PLlG6YbJlMIIBSwYIKwYBBQUHAQEEggE9MIIBOTA3BggrBgEF BQcwAYYraHR0cDovL2Vvbi1ncm91cC1jYS0yLTIwMTMub2NzcC5kLXRydXN0Lm5l dDBHBggrBgEFBQcwAoY7aHR0cDovL3BraS5pbnRyYW5ldC5lb24uY29tL2NhY2Vy dHMvRU9OX0dyb3VwX0NBXzJfMjAxMy5jcnQwQgYIKwYBBQUHMAKGNmh0dHA6Ly93 d3cuZC10cnVzdC5uZXQvY2dpLWJpbi9FT05fR3JvdXBfQ0FfMl8yMDEzLmNydDBx BggrBgEFBQcwAoZlbGRhcDovL2NkcC1sZGFwLmludHJhbmV0LmVvbi5jb20vY249 RS5PTiUyMEdyb3VwJTIwQ0ElMjAyJTIwMjAxMyxvdT1jYSxvPWVvbixjPWRlP2NB Q2VydGlmaWNhdGU/YmFzZT8wPgYDVR0gBDcwNTAzBgsrBgEEAaU0AoFSATAkMCIG CCsGAQUFBwIBFhZodHRwOi8vd3d3LmVvbi5jb20vcGtpMIH+BgNVHR8EgfYwgfMw PqA8oDqGOGh0dHA6Ly9wa2kuaW50cmFuZXQuZW9uLmNvbS9jcmxzL0VPTl9Hcm91 cF9DQV8yXzIwMTMuY3JsMDigNqA0hjJodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2Ny bC9lb25fZ3JvdXBfY2FfMl8yMDEzLmNybDB3oHWgc4ZxbGRhcDovL2NkcC1sZGFw LmludHJhbmV0LmVvbi5jb20vY249RS5PTiUyMEdyb3VwJTIwQ0ElMjAyJTIwMjAx MyxvdT1jYSxvPWVvbixjPWRlP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFz ZT8wHQYDVR0OBBYEFEenCwas1XolknL1kBafZG0PW2IzMA4GA1UdDwEB/wQEAwIB BjASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQBpsLNEbnDn cXsAJvieLktWP8OejDLhOIgJDnAPUJmAg/L43JPeCZUNh4moofRAcWdCXbBaD3xV pDPg5EAe2cT1gg7oKOs4vPjuJT+lISMcV7OgMmrGnGsl5bwFzyxHR07RlrlWSJmB u28t7b3e67UpNgfwH/flUMOR21hRHY617btTqezEmHw9yuLzX6U4wHaWwk5eW2Wz ir78FOCLpJHrvYtEsGEM/H1IuwKg9H6tkm6oxjuT8CLPuq/Lrc8dYDU1JLnJ5QTi MPKCxLFud3RD06MRmIO2h56VDkCI3RJPSZ670fj3Gl1NxVj/cwIKV/fdNpB9lnMO L/oxcsQtZRuC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDDCCBPSgAwIBAgIDEBysMA0GCSqGSIb3DQEBCwUAMEMxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHTAbBgNVBAMMFEUuT04gR3JvdXAgQ0Eg MiAyMDEzMB4XDTEzMTIxNzEzNDUwOVoXDTI4MDkyMDA4MjU1MVowUjELMAkGA1UE BhMCREUxFTATBgNVBAoMDEQtVHJ1c3QgR21iSDELMAkGA1UECwwCQ0ExHzAdBgNV BAMMFlBhcnRuZXIgQ0EgMiAyMDEzIFhYSVYwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDICdXUL8G3wBug1oq2biTWFg3Hb8a9P93tdS5tDpU6h2FMulIQ ykNQRQa0YrBePQUVvg/K6+mhR3FtRFwgK3g40F3kiE6JmHlfJupl5P8n2WCsRMOI 0ehVQ6WzTqGnW9S1rGNYljxU8mLH6QMixKX7MtTLpC8c2MTUVWGY3ixBy95V+hSM 7L6OR/YS0XMl1vDrfwkaLarWmQ718cHkiFUpAkOuY28f+onjtqPnCN1Z6iUjZtv9 lZjguCLwyuIDqcYA2OuDN3cOylsEQBi9KUEelMefNxWBYCiJ7NrQaYSnulMGSloJ kQm9i7dpLW1R4/IqwBrfAZRBXp/YS+S4fHmhAgMBAAGjggL4MIIC9DAfBgNVHSME GDAWgBQu7h/x28HWct1C1TXtzy5RumGyZTCCAUsGCCsGAQUFBwEBBIIBPTCCATkw NwYIKwYBBQUHMAGGK2h0dHA6Ly9lb24tZ3JvdXAtY2EtMi0yMDEzLm9jc3AuZC10 cnVzdC5uZXQwRwYIKwYBBQUHMAKGO2h0dHA6Ly9wa2kuaW50cmFuZXQuZW9uLmNv bS9jYWNlcnRzL0VPTl9Hcm91cF9DQV8yXzIwMTMuY3J0MEIGCCsGAQUFBzAChjZo dHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NnaS1iaW4vRU9OX0dyb3VwX0NBXzJfMjAx My5jcnQwcQYIKwYBBQUHMAKGZWxkYXA6Ly9jZHAtbGRhcC5pbnRyYW5ldC5lb24u Y29tL2NuPUUuT04lMjBHcm91cCUyMENBJTIwMiUyMDIwMTMsb3U9Y2Esbz1lb24s Yz1kZT9jQUNlcnRpZmljYXRlP2Jhc2U/MD4GA1UdIAQ3MDUwMwYLKwYBBAGlNAKB UgEwJDAiBggrBgEFBQcCARYWaHR0cDovL3d3dy5lb24uY29tL3BraTCB/gYDVR0f BIH2MIHzMD6gPKA6hjhodHRwOi8vcGtpLmludHJhbmV0LmVvbi5jb20vY3Jscy9F T05fR3JvdXBfQ0FfMl8yMDEzLmNybDA4oDagNIYyaHR0cDovL2NybC5kLXRydXN0 Lm5ldC9jcmwvZW9uX2dyb3VwX2NhXzJfMjAxMy5jcmwwd6B1oHOGcWxkYXA6Ly9j ZHAtbGRhcC5pbnRyYW5ldC5lb24uY29tL2NuPUUuT04lMjBHcm91cCUyMENBJTIw MiUyMDIwMTMsb3U9Y2Esbz1lb24sYz1kZT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25M aXN0P2Jhc2U/MB0GA1UdDgQWBBTqhGqOyLfWOtXM6Rx98fYPg0W3gDAOBgNVHQ8B Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEA uCNRZdU8gUYxgcfgzf6vnJ4cwVwfKGprt3YuBDoq1oMFa3rXHUK7CQkY73GZsIxB FmoZ5RStZGEjGSnMp3lHhmnKw58BXLJZtAx6kQtziiKXDMFKroxTzDAiqpJrE9UX wEq6w66qvmE6V897/au9QcnkGyro34GrqvCkg+iv0KUiSq/b4xEYoZt5T1RkzyXS DN0xjwlGgs0BBdablWwFGO/KpuhqyjX1Wyqh3EW0ybD/G4howcfQ0bIttTgGsdOj QvhrVq6LJUqttffj2f8Smf6wsvpzSLhFBMCNiaGu/IAF1/VQCKy1BUaD6b76jn/a Naj57srK4yJUi42mdnbU2Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEfTCCA2WgAwIBAgIDG+cVMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVT MSEwHwYDVQQKExhUaGUgR28gRGFkZHkgR3JvdXAsIEluYy4xMTAvBgNVBAsTKEdv IERhZGR5IENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMTAx MDcwMDAwWhcNMzEwNTMwMDcwMDAwWjCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHku Y29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1 dGhvcml0eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv3Fi CPH6WTT3G8kYo/eASVjpIoMTpsUgQwE7hPHmhUmfJ+r2hBtOoLTbcJjHMgGxBT4H Tu70+k8vWTAi56sZVmvigAf88xZ1gDlRe+X5NbZ0TqmNghPktj+pA4P6or6KFWp/ 3gvDthkUBcrqw6gElDtGfDIN8wBmIsiNaW02jBEYt9OyHGC0OPoCjM7T3UYH3go+ 6118yHz7sCtTpJJiaVElBWEaRIGMLKlDliPfrDqBmg4pxRyp6V0etp6eMAo5zvGI gPtLXcwy7IViQyU0AlYnAZG0O3AqP26x6JyIAX2f1PnbU21gnb8s51iruF9G/M7E GwM8CetJMVxpRrPgRwIDAQABo4IBFzCCARMwDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9BUFuIMGU2g/eMB8GA1Ud IwQYMBaAFNLEsNKR1EwRcbNhyz2h/t2oatTjMDQGCCsGAQUFBwEBBCgwJjAkBggr BgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDIGA1UdHwQrMCkwJ6Al oCOGIWh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LmNybDBGBgNVHSAEPzA9 MDsGBFUdIAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2RhZGR5LmNv bS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAWQtTvZKGEacke+1bMc8d H2xwxbhuvk679r6XUOEwf7ooXGKUwuN+M/f7QnaF25UcjCJYdQkMiGVnOQoWCcWg OJekxSOTP7QYpgEGRJHjp2kntFolfzq3Ms3dhP8qOCkzpN1nsoX+oYggHFCJyNwq 9kIDN0zmiN/VryTyscPfzLXs4Jlet0lUIDyUGAzHHFIYSaRt4bNYC8nY7NmuHDKO KHAN4v6mF56ED71XcLNa6R+ghlO773z/aQvgSMO3kwvIClTErF0UZzdsyqUvMQg3 qm5vjLyb4lddJIGvl5echK1srDdMZvNhkREg5L4wn3qkKQmw4TRfZHcYQFHfjDCm rw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEoDCCA4igAwIBAgIDORSEMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAlVT MSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQL EylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x NDAxMDEwNzAwMDBaFw0zMTA1MzAwNzAwMDBaMIGPMQswCQYDVQQGEwJVUzEQMA4G A1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3Rh cmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UEAxMpU3RhcmZpZWxkIFJv b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQC97cED/PaP/AKxb1ufSNmdeeKitwNhVhjDR7bXyj01LolD 96Fpm96KGv0TIJy0SXcyKVb9ueyM3SL6ctwnYZfu9lqE7G4ZuYks3IRb1XT7a1/F iaUQUolGVfS4dRzmf+RUrkv4VXJXAhn4F3FZ6x4oB3TFnUi+bLT0pLDzZDd5ksDs Rl5/4W1TTGKvzR8LY7s6nfv8eQCYYXTPJoJAY/OycmoZDZnK1A51zDf7i4nBWfFi f1+zX2Uw+Ke3TXZaHnZeNMDollaZirPwf6TNvdwyMXyRz+BfEfhrqklc0ZmU0aLj Y1sJdrVWYuFLdB2W1CbUCARZ0JgODube/MPsH5DxAgMBAAGjggEpMIIBJTAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfAwyH6fZMH/E fWijYqihzqsHWycwHwYDVR0jBBgwFoAUv1+30c7dH4b0W1Ws3NcQwg6piOcwOgYI KwYBBQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0 ZWNoLmNvbS8wOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL2NybC5zdGFyZmllbGR0 ZWNoLmNvbS9zZnJvb3QuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUF BwIBFitodHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkv MA0GCSqGSIb3DQEBCwUAA4IBAQCFY8HZ3bn/qb2mGdy/EzoROCJUsawFEPt8s5Y/ MYtm/4jz4b/7xx8A/0Zqi2EyyQFRdvuaxvogUchGxJjXeaPjBHI/i000U2fsMyx7 6JQBKHw6NFsCdxaNQCUzsLxsl9cFev+Mhc5voFMAF24ebL0i1wqIN/Z965lB7yfL jGBrTAF+ZVALT7iVmppuNP1zOjPxkdXzTi106O/TkDXxBmhk1NAT/VLTxm3BOoox 3QUmNUqMZbhSa4Hs0py1NBCXnD7GL+2OQkIkLulzmiX5EfHyI2nL5ZRpoNLcsPxE iawXqMzVN3cWxYC5DI9XAlWZhXtJ8C5boMJXU12i6KY3wwH6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgILBAAAAAABQ3KVa6cwDQYJKoZIhvcNAQELBQAwOzEYMBYG A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh bCBSb290MB4XDTE0MDEwODA4MDAwMFoXDTMwMTIxNTA4MDAwMFowOzEYMBYGA1UE ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBCwUA A4IBAQAq7HRKrzf2QHfa4gILa5Bdq8t6e2+FmbAQkXSE+YhCJ41rzBHdK8kxdQtn xEgi2gzro5s3iZWfW63CRZCkg75ugM1gpYQTn5Q56irogzhG7Vw1hj6mxrS85GKR IYWAI4gXxWqYCd8+mAsd2Z2j2I3rMVGsTPmw7e17nFU9kMYH4zGZltsfXWIb1cM3 CVjxy1/aQXrP0jMum8Qnv3ROPMZhiZUYhM+rg56Eom8JIWwuMCX59RV2P0jTiBbu 8FxsRE8o1h0c1plytUGww3t27m3n5FbnH0XLEfQCuzCX518UBQIVzgVL76f+H+mL VUI6CnXk2kwcttxRDpnXeWW6Uvxx -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFATCCA+mgAwIBAgIQDglHG7EZWmErtKS1sO1WCTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTQwMTA4MTIwMDAwWhcNMjkwMTA4MTIwMDAwWjBkMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNRGlnaUNlcnQgR3JpZDEZMBcGA1UECxMQd3d3LmRpZ2lj ZXJ0LmNvbTEiMCAGA1UEAxMZRGlnaUNlcnQgR3JpZCBUcnVzdCBDQSBHMjCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMsBrEAAXJEFhz/RP7bYE8g8OdVe EOwjrxmg7pXark39WKA7kS10ZPGYaE8W5/mv05ztMgA0J9vym+ZUtfOadVy/JNiH jKZyiauxkh3TCjQhLfb+5fLQ3/XW8YylNzwcTAlQ2/eEaU0KXJmveXYh9+txcrWI m/aIeHo5r8bpgi31jLRWFKeTdmoMQ3JX8sR5Zn9wuaYjokf3tiufCpF6h1lAH27F xTkW5zkZ1RvdcKPnYQPPwquNIT/zIHb3QPNOOB0K0SDc1dPlWjWKeRgm/V7SBFvy TFcj/zxHP8m5mh8D75jsW1AAKh8tnALFZxva5rr9RiHmwmd+mDsEYAt/eVkCAwEA AaOCAawwggGoMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMHkG CCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu Y29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln aUNlcnRBc3N1cmVkSURSb290Q0EucDdjMIGBBgNVHR8EejB4MDqgOKA2hjRodHRw Oi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3Js MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVk SURSb290Q0EuY3JsMEMGA1UdIAQ8MDowOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUF BwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMB0GA1UdDgQWBBThZRoC A5F+15ZtOIiLnhaRaxFsnjAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823I DzANBgkqhkiG9w0BAQsFAAOCAQEAKHBUklU69o1g8x7KNsso5ujW+S6Fw/AXLCCr 1aqkUTQ32hyJjVB0/AOnTIi1lCDKPYXdUDj2TIL9fxsSuj2GxGFEWTz6kW+gyKae MvDJifY4TXmx22Mja4DwBjKgUggzvO5Vmf1gz3IZjv67D9SU0TLOhjbcYWKYu19/ +IDLmwV637KkjUgM1asqqtkutfT/d1+j4COTDWSD48OEOk8BiB9Rh+c17Af3yvRV f90aa9NEStSVevR2h9i9rDrleeGNiKqCInvDa3szREdsT78+l4nITWH6os/iZnI+ 4int+r0ifHJjNfL1b5NAxey8kIfNCESo/RnqktuXNptd7reo9A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCDCCA/CgAwIBAgIQKy5u6tl1NmwUim7bo3yMBzANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMjEy MDAwMDAwWhcNMjkwMjExMjM1OTU5WjCBkDELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxNjA0BgNVBAMTLUNPTU9ETyBSU0EgRG9tYWluIFZh bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAI7CAhnhoFmk6zg1jSz9AdDTScBkxwtiBUUWOqigwAwCfx3M28Sh bXcDow+G+eMGnD4LgYqbSRutA776S9uMIO3Vzl5ljj4Nr0zCsLdFXlIvNN5IJGS0 Qa4Al/e+Z96e0HqnU4A7fK31llVvl0cKfIWLIpeNs4TgllfQcBhglo/uLQeTnaG6 ytHNe+nEKpooIZFNb5JPJaXyejXdJtxGpdCsWTWM/06RQ1A/WZMebFEh7lgUq/51 UHg+TLAchhP6a5i84DuUHoVS3AOTJBhuyydRReZw3iVDpA3hSqXttn7IzW3uLh0n c13cRTCAquOyQQuvvUSH2rnlG51/ruWFgqUCAwEAAaOCAWUwggFhMB8GA1UdIwQY MBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBSQr2o6lFoL2JDqElZz 30O0Oija5zAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgG BmeBDAECATBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNv bS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB AQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9E T1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21v ZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAE4rdk+SHGI2ibp3wScF9BzWRJ2p mj6q1WZmAT7qSeaiNbz69t2Vjpk1mA42GHWx3d1Qcnyu3HeIzg/3kCDKo2cuH1Z/ e+FE6kKVxF0NAVBGFfKBiVlsit2M8RKhjTpCipj4SzR7JzsItG8kO3KdY3RYPBps P0/HEZrIqPW1N+8QRcZs2eBelSaz662jue5/DJpmNXMyYE7l3YphLG5SEXdoltMY dVEVABt0iN3hxzgEQyjpFv3ZBdRdRydg1vs4O2xyopT4Qhrf7W8GjEXCBgCq5Ojc 2bXhc3js9iPc0d1sjhqPpepUfJa3w/5Vjo1JXvxku88+vZbrac2/4EjxYoIQ5QxG V/Iz2tDIY+3GH5QFlkoakdH368+PUq4NCNk+qKBR6cGHdNXJ93SrLlP7u3r7l+L4 HyaPs9Kg4DdbKDsx5Q5XLVq4rXmsXiBmGqW5prU5wfWYQ//u+aen/e7KJD2AFsQX j4rBYKEMrltDR5FL1ZoXX/nUh8HCjLfn4g8wGTeGrODcQgPmlKidrv0PJFGUzpII 0fxQ8ANAe4hZ7Q7drNJ3gjTcBpUC2JD5Leo31Rpg0Gcg19hCC0Wvgmje3WYkN5Ap lBlGGSW4gNfL1IYoakRwJiNiqZ+Gb7+6kHDSVneFeO/qJakXzlByjAA6quPbYzSf +AZxAeKCINT+b72x -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDjCCA/agAwIBAgIQNoJef7WkgZN+9tFza7k8pjANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMjEy MDAwMDAwWhcNMjkwMjExMjM1OTU5WjCBljELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxPDA6BgNVBAMTM0NPTU9ETyBSU0EgT3JnYW5pemF0 aW9uIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBALkU2YXyQURX/zBEHtw8RKMXuG4B+KNfwqkhHc5Z9Ozz iKkJMjyxi2OkPic284/5OGYuB5dBj0um3cNfnnM858ogDU98MgXPwS5IZUqF0B9W MW2O5cYy1Bu8n32W/JjXT/j0WFb440W+kRiC5Iq+r81SN1GHTx6Xweg6rvn/RuRl Pz/DR4MvzLhCXi1+91porl1LwKY1IfWGo8hJi5hjYA3JIUjCkjBlRrKGNQRCJX6t p05LEkAAeohoXG+fo6R4ESGuPQsOvkUUI8/rddf2oPG8RWxevKEy7PNYeEIoCzoB dvDFoJ7BaXDej0umed/ydrbjDxN8GDuxUWxqIDnOnmkCAwEAAaOCAWUwggFhMB8G A1UdIwQYMBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBSa8yvaz61P ti+7KkhIKhK3G0LBJDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRV HSAAMAgGBmeBDAECAjBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAGmKNmiaHjtlC+B8z6ar cTuvYaQ/5GQBSRDTHY/i1e1n055bl71CHgf50Ltt9zKVWiIpYvgMnFlWJzagIhIR +kf0UclZeylKpUg1fMWXZuAnJTsVejJ1SpH7pmue4lP6DYwT+yO4CxIsru3bHUeQ 1dCTaXaROBU01xjqfrxrWN4qOZADRARKVtho5fV8aX6efVRL0NiGq2dmE1deiSoX rS2uvUAOZu2K/1S0wQHLqeBHuhFhj62uI0gqxiV5iRxBBJXAEepXK9a0l/qx6RVi 7Epxd/3zoZza9msAKcUy5/pO6rMqpxiXHFinQjZf7BTP+HsO993MiBWamlzI8SDH 0YZyoRebrrr+bKgy0QB2SXP3PyeHPLbJLfqqkJDJCgmfyWkfBxmpv966+AuIgkQW EH8HwIAiX3+8MN66zQd5ZFbY//NPnDC7bh5RS+bNvRfExb/IP46xH4pGtwZDb2It z1GdRcqK6ROLwMeRvlu2+jdKif7wndoTJiIsBpA+ixOYoBnW3dpKSH89D4mdJHJL DntE/9Q2toN2I1iLFGy4XfdhbTl27d0SPWuHiJeRvsBGAh52HN22r1xP9QDWnE2p 4J6ijvyxFnlcIdNFgZoMOWxtKNcl0rcRkND23m9e9Pqki2Z3ci+bkEAsUhJg+f+1 cC6JmnkJiYEt7Fx4b4GH8fxV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEUzCCAzugAwIBAgILBAAAAAABRE8CNrYwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQwMjIwMTAwMDAwWhcNMjkwMzE4 MTAwMDAwWjBXMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1z YTEtMCsGA1UEAxMkR2xvYmFsU2lnbiBDQSBmb3IgQUFUTCAtIFNIQTI1NiAtIEcy MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+fyemGPTDsow6Pqr0IMY U1E/ko3DG3UPXQOlFMclMbsdM9CpueFB6zg+oUXvNXwtW/CtqOSL4+RfKyzleEuH MoHVFlCTuJbCagyB7VcBhIa5AKM4B5rIRVzAylbcFI6z2pdhqrWZIyKVvnDWEdmD gq6vycUrSwxqzWJWKihhz2SLxe5X2j8Mbi1uMTGXfFSd9hJhTeh3qOgCcyCmTBXo 8SPuhoZSq4O5UjrH562bQB+iGBdT//9vDXT7xdzRalcI3GeB16gsuKO24VSr88X7 5EEhBAbLtG35Q8LZRUyUU8alKO/D3g/a9+o4XCa9VCrq4GC/WJ8sLGBspEB+Ok0Z QQIDAQABo4IBKTCCASUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQEwHQYDVR0OBBYEFGDC8VI+rYwT3NvKDvoK5iosmUvYMEcGA1UdIARAMD4wPAYE VR0gADA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9y ZXBvc2l0b3J5LzA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNp Z24ubmV0L3Jvb3QtcjMuY3JsMD4GCCsGAQUFBwEBBDIwMDAuBggrBgEFBQcwAYYi aHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3Jvb3RyMzAfBgNVHSMEGDAWgBSP 8Et/qC5FJK5NUPpjmove4t0bvDANBgkqhkiG9w0BAQsFAAOCAQEAE6KprnJzWxFf N0fQ//QEguT88TZdsk2nE4eU5D7ac+wnfqihu3oSQSOeNhjdImJWUp0cffOWGCWX EuAu8/hKQjuhHoIc53Pkc3euQCNGII0Q+4061809EC1f8yLaUPsx79dyxFDTlIkA YNreAp2oXpw5eeuyCDzE26wres1h+O78vSC/cZRdCnqZ2nmoPQ6XAT0APD85p2Mf o69P7W8HHX87d8rQQ6ygKUktBCk2wrlEf+ezqfeE1gk/ey6HleO9t/73lovFHEWu DC4phYMwUA86QdtFfU80QH5QzxKieGEWHzc8/lFn4w3WuxRQ85wHQiy9f32QDHDo XBNcWyODBg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEeDCCA2CgAwIBAgIIW0aZkOx1nTQwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTE0MDMwMTIzMTM0OFoXDTMwMTIzMTE0MDYwNlowQzEL MAkGA1UEBhMCVVMxGDAWBgNVBAoMD1RyZW5kIE1pY3JvIEluYzEaMBgGA1UEAwwR VHJlbmQgTWljcm8gUzIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDeaJCJXJpLPXS4LsS//gkuQ7LXI/LkP/Cz1waCxPG4Gq2Q2d1WImoPqONOJ1RG 46SD0wVKJYsywUWCyYN27u/wjDk/pxamZqd/iLffpZyXyuGaHrt6n3pX5iAgPAN8 PCnWwin/7C5QukpD98l5UR0TW8+owCL/5wUONUqskllLEt2uedNFUxhGsXDq5Msv jQy2e0nFBv/GFJLinkL2TfTIZsU5EUfEow7nDmb7KOFZQ+VnuHwinpyqNJ5krWhe 94412rN+m5+ktY7rNEiKZz6SyPQVQmQkKRDvbGa+hLzPkhoLOyx5cXFhMVjZHGWC xrzrE2wLKPdjvgUju765H0MtAgMBAAGjggFtMIIBaTBwBggrBgEFBQcBAQRkMGIw MgYIKwYBBQUHMAKGJmh0dHA6Ly9vY3NwLmFmZmlybXRydXN0LmNvbS9jb21tY2Eu Y3J0MCwGCCsGAQUFBzABhiBodHRwOi8vb2NzcC5hZmZpcm10cnVzdC5jb20vY29t bTAdBgNVHQ4EFgQUsJnhkE7zZWMonBI/eFa6hMDHOj0wDwYDVR0TAQH/BAUwAwEB /zAfBgNVHSMEGDAWgBSdk8ZTi17Krz+fHg/lmZW8JPaUjzBJBgNVHSAEQjBAMD4G BFUdIAAwNjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5hZmZpcm10cnVzdC5jb20v cmVzb3VyY2VzL2NwczBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmFmZmly bXRydXN0LmNvbS9jcmwvQWZmaXJtVHJ1c3RDb21tZXJjaWFsLmNybDAOBgNVHQ8B Af8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBALwsE2GQqK3lRZtEs9GAD3jA3r0g jShmKTc/l8UV4MFlqbm6jIq+fgSme8SjrudZFR7zE2CVYHab7bJyoKXwH5aVVIea fJFQP0BEnuPb6BKglg5mPvcbRGN8NAEBRL5VQa2XoZRLmJvGfy7lraYs7JQ+7rl/ y0be//KfYcCUIzn4p8yXiiE4kFGPA/RBgb+/3AnFl6VRtd1fDxOkzvBP/QmwsvB+ 83t67wjLU0Axv9Q6bYnkQ4mPlZzE28Y/vOOeOq2ZVo1U3ffPE+FbaLUcEPFV41qY dVgSPCvYa7GGG8U43fUASqXwshoOpnbetI+zRN5aH1TtTK71e2kTqcqEckM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnTCCAyKgAwIBAgIQUQYB5jtQZzxV7k4Z2jBMqDAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMzEzMDAw MDAwWhcNMjkwMzEyMjM1OTU5WjCBkDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N T0RPIENBIExpbWl0ZWQxNjA0BgNVBAMTLUNPTU9ETyBFQ0MgRG9tYWluIFZhbGlk YXRpb24gU2VjdXJlIFNlcnZlciBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA BIg2jdgJVPWaKXk+JD06oiTxihgKVH3tQCza8LqO2YT1Rd03cJEkrLoU61FoIN3S SFUAXW9E7ggci/lVXySaVIOjggFlMIIBYTAfBgNVHSMEGDAWgBR1cacZSBm8nZ3q QUfflMRId5nTeTAdBgNVHQ4EFgQUu/oI4L9U7lr9FqQ1AgmppMjs/UswDgYDVR0P AQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMBsGA1UdIAQUMBIwBgYEVR0gADAIBgZngQwBAgEwTAYDVR0f BEUwQzBBoD+gPYY7aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RPRUNDQ2Vy dGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsGCCsGAQUF BzAChi9odHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9FQ0NBZGRUcnVzdENB LmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMAoGCCqG SM49BAMDA2kAMGYCMQDtilgEuIgqZMub1nOMLJwPVr3Lrs/A4RVYuImPsVNTtWG6 5FL7j6YooeQtlSxIViACMQDvavtMsSKuUzwaH3x8vVhGiljleoI0iloIE64Adby0 id6I7ObgYgAsmupHtaSvojI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDojCCAyigAwIBAgIQVVkmuRfCcl/Jg9B/eT1c1zAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMzEzMDAw MDAwWhcNMjkwMzEyMjM1OTU5WjCBljELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N T0RPIENBIExpbWl0ZWQxPDA6BgNVBAMTM0NPTU9ETyBFQ0MgT3JnYW5pemF0aW9u IFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTBZMBMGByqGSM49AgEGCCqGSM49 AwEHA0IABC0pePUFbYxX0bGlua3rVx+plV0KoC+xO8BRZLJ5wZHWjVu3Szl797L5 WOuFofMQk4+/me5EGNP9YllGz8lUJkKjggFlMIIBYTAfBgNVHSMEGDAWgBR1cacZ SBm8nZ3qQUfflMRId5nTeTAdBgNVHQ4EFgQUdr4iSO4/PvZGA9mHGNBlfiKcC+Ew DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMBsGA1UdIAQUMBIwBgYEVR0gADAIBgZngQwBAgIw TAYDVR0fBEUwQzBBoD+gPYY7aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RP RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsG CCsGAQUFBzAChi9odHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9FQ0NBZGRU cnVzdENBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29t MAoGCCqGSM49BAMDA2gAMGUCMQDfd8c+gUlKEIxIQvl3vlrTdyPd4XU+RjoXmvMb mshlbIFDYLrJfcS0mGPEwk0Fm5kCMCrbRm5ONLS18G0NfDYnuGp7ex7i0GUezn5T /QKTj/C/89U3cSp0L2qvkeMN9nsU4w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE/jCCA+agAwIBAgIQCDZl3ED5ayay3q38bUvFbTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTQwNDIzMTIwMDAwWhcNMjkwNDIzMTIwMDAwWjBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBTZWN1cmUgQXV0aCBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBANInLTMklu5GK6yK4LjHA9+yWlLkt3Hx O6eZ/N1FVZRW5BWx2PMI76IIXqDAigcEeJoF+xVhWe0BzEtDtBLnRVINsGpihJ+b ftFuu31KhtLKiyx4c5vjZbOoHBJfYphwqow+e/ILSBb30RBPjrazAZaMEa1Wz1S2 FMHzqtBBSMEm8/EydoxwA7wrnIVNXrk1bd8g7EToBH8HuNy14ovgnD5RXPNGAeb2 nJSFTIaM0Ikb4zzYvnsWlq2xkh6GFi1/TROjhq60cWqs4+8bKox6BKov6taYaaB6 vshWAkBjfhZV0RZDbuC3D0mbp1LuC1Afp8Z5Ol4G+fyRUZNSQsT4gy0CAwEAAaOC AawwggGoMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMHkGCCsG AQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t MEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl cnRBc3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8v Y3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqg OKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS b290Q0EuY3JsMEMGA1UdIAQ8MDowOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIB FhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMB0GA1UdDgQWBBT2k9eyPc7O BLRmVQZEqdvR5e3qxjAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAN BgkqhkiG9w0BAQsFAAOCAQEAEg2IQUfsC/n/rw1WrpOEOqGAfsrulSktrcRV8rMk pDaYwfGbiGVXk2w3RVphJf6BrctOSaDkj1o/UdFRX9MnxoCrmY7mPh6pRl7oOG3g yahSjX3k5FEmf5efSmTpzZQ2o4/Ca1/MT4M25tjIBGGylo49cTCZ6ll0FkL4juGL yCGk+HdL8fIjYE4FOmyizerTL7QXaOMM8ow09yuzQXR1Kr1AttNGVqe1B5X/VxHf xOsxaN53sv53DXyswrAsAWIVKlecpWQSnLhfyQ2wtn/+ZsTokeavELsIvFC8NmQg 1080HqAT4IklRVZCERCk22WKyXHzzU40gSCqRJ/PS5UCMQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIIPYR8G0q7MgIwDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTE0MDQyOTAyMjU1NVoXDTMwMTIzMTE0MDgyNFowQDEL MAkGA1UEBhMCVVMxGDAWBgNVBAoMD1RyZW5kIE1pY3JvIEluYzEXMBUGA1UEAwwO VHJlbmQgTWljcm8gQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC tz7qUBb61DHFYDbRj69nikk/4sbQ53NnPSrOBJEX3E59MAPoEO/biYzoMF4A3UdB LzZsRp4SYJZ0WybyvaExs9FHECfpcXohOCPkG7u1RC4EtUgMjw3lNvu3gDvyi5ut cdKI4uOwIkhD8objKuzSlU4IaUjsTaeIROKQHttkDMw7d8HhORy3QnTSIClZ3hgW DJZZHOyE2xhGhdyG/KfNlw/uXtJ9A5/YUPHp4dDfrQV2PUr+dTgs3BIh9r7dRngl a4BqbvNaH8Yw3fFJ8DqY118JH5GSQ3RQwHpz2f34n0y2PTSMLQlMUC2iRBOd8dhW Je5RGbKfveHXDfBgqdBBAgMBAAGjggFsMIIBaDBvBggrBgEFBQcBAQRjMGEwMgYI KwYBBQUHMAKGJmh0dHA6Ly9vY3NwLmFmZmlybXRydXN0LmNvbS9udHdrY2EuY3J0 MCsGCCsGAQUFBzABhh9odHRwOi8vb2NzcC50cmVuZG1pY3JvLmNvbS9udHdrMB0G A1UdDgQWBBStMcf6As5n92Uc+7pfwLvFUExnyDAPBgNVHRMBAf8EBTADAQH/MB8G A1UdIwQYMBaAFAcf0uec2sJuokC0sHpQEFB0xMi9MEkGA1UdIARCMEAwPgYEVR0g ADA2MDQGCCsGAQUFBwIBFihodHRwOi8vd3d3LmFmZmlybXRydXN0LmNvbS9yZXNv dXJjZXMvY3BzMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuYWZmaXJtdHJ1 c3QuY29tL2NybC9BZmZpcm1UcnVzdE5ldHdvcmtpbmcuY3JsMA4GA1UdDwEB/wQE AwIBBjANBgkqhkiG9w0BAQUFAAOCAQEADPu8ViwJnfsv1a+JcSPldgbVTnWObm8p 26PDohmr3zJOEvz3RRGVz7NWukJw798lIfljV98ev08i+ygs7XbxgO9qqJPQ8ZFN ehMEqlL6IQk8EGa1WSaPN2SW0cY4zvYevE/8Qrl4F6x+QPe+CmsrVLwTdjIGK5pw fwcXx5KrGy1SYXuW2vg5MXzjjABPyN+c3rpYOBAlay2C0A/+uxz+Og9wiTIU3Ywn h2s/NWCNGQ+lqqVXCLZeBZ+zo+FtWizAqzkUIi+3DST5BhLnPUZZb5mFQbwoC61A UXy1sa5T68oU4+2fAw+lF8dVEffcA5mSQUJw/7RRxuOS1Qs9gJ3HpQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGXjCCBUagAwIBAgIMU1zSo6wT2dxKS4MKMA0GCSqGSIb3DQEBCwUAMIGCMQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEf MB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0xNDA3MDgxNDM1MjFa Fw0yOTEyMjkxNDM1MjFaMHgxCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVz dDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEdMBsGA1UEAwwUZS1Temlnbm8gU1NM IENBIDIwMTQxHzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/z1KGU12pZR5il1tkzC8F9itEF/A5 u3FQnzLdPqurZo4o7YTOKdkV/bzRnGf5xphe6LZHhENDZJ78LkSxUNs7jLMnMjp1 UDoW0cREg5nstWDX7heSMD59HBrm1W8sHMvmfwch+wwGaSUhzglff2WzdzCADqaB YkVTgm3XoEpGaoBMYAoyTnVbs2QX40AfGbzcQUDRxm4zcTU5ovfM6c3obQkCp4+s 1K5nsmTzO/MnH1t+eE+0mt58aMwrqTe3vjabnppgDmMN2nXDEErjb9HrD/pv9Yeq XmWPzKTfJ0veEi/xndoeSkQOXETDB0u8vQlu/bmTgBUs3skzWp2X0vLbAgMBAAGj ggLbMIIC1zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA7BgNVHSAE NDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL2NwLmUtc3ppZ25vLmh1 L2FjcHMwHQYDVR0OBBYEFN5qsE5DqghBR3S/pYqBVEwgxXUoMB8GA1UdIwQYMBaA FMsPxt9CQ8w9y7VII6EaeqYquzRoMBsGA1UdEQQUMBKBEGluZm9AZS1zemlnbm8u aHUwgbYGA1UdHwSBrjCBqzA3oDWgM4YxaHR0cDovL3Jvb3RjYTIwMDktY3JsMS5l LXN6aWduby5odS9yb290Y2EyMDA5LmNybDA3oDWgM4YxaHR0cDovL3Jvb3RjYTIw MDktY3JsMi5lLXN6aWduby5odS9yb290Y2EyMDA5LmNybDA3oDWgM4YxaHR0cDov L3Jvb3RjYTIwMDktY3JsMy5lLXN6aWduby5odS9yb290Y2EyMDA5LmNybDCCAV8G CCsGAQUFBwEBBIIBUTCCAU0wLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDA5 LW9jc3AxLmUtc3ppZ25vLmh1MC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAw OS1vY3NwMi5lLXN6aWduby5odTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIw MDktb2NzcDMuZS1zemlnbm8uaHUwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2Ey MDA5LWNhMS5lLXN6aWduby5odS9yb290Y2EyMDA5LmNydDA8BggrBgEFBQcwAoYw aHR0cDovL3Jvb3RjYTIwMDktY2EyLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3J0 MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAwOS1jYTMuZS1zemlnbm8uaHUv cm9vdGNhMjAwOS5jcnQwDQYJKoZIhvcNAQELBQADggEBALEgpxbV/mGh1vWAO8dx ONwv+aP7Nb5dXTP0YjtrIE6a5zV+IpXK+inu+OJftAHV0an32ovpzpta2EvR5ci/ C7o9h8eyforkTxMDndPwZ97ey/5qaz48t7wdz6w6YXCs5LpMzU4BmG+ubTdGNZQv w6cwlxRl3p2KZTZbyJj7t3fM5JcrKVwn8844bfFTKSQni90xzxiO8bz5LjFoDMii vCKKMZXHpZMEi4QsyEKT6sqT+RXp8dsRrdJ/klSu8kUQu4xyWTTTMVs9cCG7ZxzR VyNLg3Rc7vMcYCe5KOiP+H1y0pR9FRSGqMS7Rwa0A4J5nMlGKogQ5R/pp715cMbK mpQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEazCCA1OgAwIBAgIQA9+F79E56kT/uLNjC5PDgTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE0MDczMDEyMDAwMFoXDTI5MDczMDEyMDAwMFowSTEL MAkGA1UEBhMCVVMxEjAQBgNVBAoTCU5DQyBHcm91cDEmMCQGA1UEAxMdTkNDIEdy b3VwIFNlY3VyZSBTZXJ2ZXIgQ0EgRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQC2uZSgRGV3p6PtPGcS0gMV4XWvwL26DDDr7ZxCRg7fztUXmzCnSf7E WfqmH/ocyuuM1lHN1osMq5anqG01JKWGRojF1tVYkkovhS8BuHxOMnogGYfkuJ/b /K4+zbt7/x9VNgfALrNRXYooW6vmtC9KbNBkbqdvbk+AIfBBJifqi62zwzGKZDo6 EuN+EH1PDKKQ5lvqwYxByqUyIB5vuEt1o0rirzhADt9+onZf/xHYniRTLHgzymCu aE1G3zmN2FHvZ0bUsZ7W+jhLGfNpXUlsmF9jSqRBXpbIXstPH0OTFUkQKaSEO+bL r6Ts/hfp8QMvhv8NZ/5YIL6MdMmkUKmzAgMBAAGjggEqMIIBJjASBgNVHRMBAf8E CDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjA0BggrBgEFBQcBAQQoMCYwJAYIKwYB BQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8 hjpodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNl RVZSb290Q0EuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxo dHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMB0GA1UdDgQWBBQ87IfvMZCBDgP/ KweutFOlFaf4AjAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkq hkiG9w0BAQsFAAOCAQEAFCulovpoxglyMzjOuGhhX6ocwXQO8Bt9B4/0i6JYAFxQ 3ODGGgZXvROKcvokQ1Hqu8iyFFhSd1Utn4p0xIXvZ3NadKPg5KGoLZ+SK/B/9ON6 m1JGNW7j2KvTC3hTi+c9uLY1EhaLFmhLYJRCbmsH2x3DnuSqxgZzOktEYiMF89Y+ jTmv0xQDTBeCvowcYH2EIESYqKJZWQv5Zw1YL05gAOsKa5BEzw02mJaBwOnOzmSn I0zCgEq6nt5QvIdQprKmeDymrNyNe2xXtCOUveRBqYJJAcvYTIT+nQE0QLwXyJZb aZCufjoISZ8W32A94SV46772j2OADEsMie1itDOfmw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDCDCCAo6gAwIBAgIQBisUooxA/doqHLuQyWZxhTAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xNDA3MzAxMjAwMDBaFw0yOTA3MzAxMjAwMDBaMEkxCzAJBgNVBAYTAlVTMRIw EAYDVQQKEwlOQ0MgR3JvdXAxJjAkBgNVBAMTHU5DQyBHcm91cCBTZWN1cmUgU2Vy dmVyIENBIEczMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3HjL+h7dpWOWRrjmvW+W EyQkquhBEkJiwwg4fuQHWKc/u9CnyfOD1vEnZXTe9TcUJHFjgc8yDhi5iOhJSzEx NtsmQMAdIWGAw983ZR2jENXX8qyz3e/TgLe+VsFcMQrUo4IBITCCAR0wEgYDVR0T AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEEKDAmMCQG CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0fBDswOTA3 oDWgM4YxaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9v dEczLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6 Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUlr8KhkPeF3L2R/GS3vdz FU6Y/qEwHwYDVR0jBBgwFoAUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0E AwMDaAAwZQIxALPzIzcJdz/2iM3p2/A190jXXlzbylmhR00uPTsC9bfKgvuAVZYL GZZUbATzxV0NCwIwNEpccZ6ZoBgQk/GauEtmSMCTME4bq/Y4Al8LEygff72v+C43 S6wbDy3oYxEK3+hY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWTCCBEGgAwIBAgIQBN0cbUmTeTXHxmJCjRk89jANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg RzQwHhcNMTQwNzMwMTIwMDAwWhcNMjkwNzMwMTIwMDAwWjBJMQswCQYDVQQGEwJV UzESMBAGA1UEChMJTkNDIEdyb3VwMSYwJAYDVQQDEx1OQ0MgR3JvdXAgU2VjdXJl IFNlcnZlciBDQSBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOLZ zAPj2homzi7F4RrdJ6JWg2hooY1vy6r1Ew69ZNana3aVTKyd9KmjJrd37qtdaAyf t+FBytiPtKmcB69U/PqWyHobxcidynU8arUI+2zBrDg0BkcMfoRS6gcY+NC2odHM YiocIpIsEevhyzj5hEv/ZfMBvV855J5PQq/d5v05QukRoxHfXlnogivQFky0tCN/ H65K1unCSXdNNxLcR2OKpUnbXQkS99YMk8z9dcl+AEMPusK8IuINFq/pteaTLxMY +bO/tcrepu084UjEHTLQ8XbBStaWwVV7Ah6+aUFyqMmtPvB85El+qK50IkmtmG7+ m33abIam95LIfx7KZuhJzX9uCQGch4i0MOQuJVmOZ48FKdhOwRbS/QHeN03PYLNB ewspdcnQXqGILhQKZJRQqyqqO3ENcCHbf7eojjpZX9nqEvSHPSs6WL40HYDyYDn+ 44k+mHDlCudxjws5ZaTzFn0xPAtslQBJgdJ8iQbsgb57AjcGD+GYUombYpOiP6Qk 8xE2D+FYqmg9BSS11AmsdAGivK1+lS7U9MlE80GeVBos8xYMnC0sfVJ8+eDVeBLr 9ldm4RKT91Slks9jGBOwPQSoHcigMEf07tCdSYyu3eyqckPpIs5PVgYLfiHEmb2+ XxxIYjG5NCijtQxlOypUd+Snfhckar3DhWgpAnRdAgMBAAGjggEiMIIBHjASBgNV HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjA0BggrBgEFBQcBAQQoMCYw JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBgNVHR8EPDA6 MDigNqA0hjJodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVk Um9vdEc0LmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0 cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUqGIOJHClHiRaeqmZ +RSCXHR7IJcwHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZI hvcNAQEMBQADggIBAFMYiPo5TmPsWU2JM4Wi7BNQA+UvoPSP4ic5fQzZcNW7d2xa mjXgUSxsrdXRQFUEVBlzVYolBfWobjU172cETVkyP+hETDzurgBppGRLOlvMahY9 g9+2ljFjZoVt8dAZjjqPeBCYMBfK7in1coysOYZ1hcFyS9ZpiX1CQ/Xid6XI3S32 oTgsYSkgCpdtt+JVFyNoCReiGL1cnY+BumVE30zW/BiuFia/bChHv2/rcdM6MmFa XfrvHFxSL4WenjujbQbSmxafs0ny/OvEhSwgYkfngwf1QbuzNXeyeG6HWtLBaCNv /AGZGeDFAD1UF9RZhSuZm+mSuoLXnjgOqZUBwhY//Zlr8NLL262a5WGhZBMAsDC4 H4NwB2k3xB6Csqm4GCk48cV51wk/VqgpJcO91ulNJGhv20UXoHL+Zhh5QsGfbiJF wWVEPe6wnQBkf2Zwy12ID+bq5LLYNBnbUb9XBUdUUiV9SQK3DEKjyI8Cgm08ayDW teo1j/EH223H6J4DjIE8SH3pLludwvaKsezLtFH0WNK2hS/6LsyVcMTScZ1CT+/5 nIoY4lj/SW3JQ3uqlsFlL7OLg/r56/kgmdfLvkdkB4tfuCnyXdNuol+7qbWrzWnu 5eVnU93nqwmCppBy6F4TlXXPiAUPA2gFuAjItgATSC5BqprpD4lC7ft3XocO -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFzCCA/+gAwIBAgIQckB41CE86gO/FOVeP1YCNzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQw ODIyMDAwMDAwWhcNMjkwODIxMjM1OTU5WjCBkzELMAkGA1UEBhMCVVMxEzARBgNV BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU aGUgVVNFUlRSVVNUIE5ldHdvcmsxOTA3BgNVBAMTMFVTRVJUcnVzdCBSU0EgRG9t YWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMTDft1Zl+V3Koj2wygf++oaX4pvUTmt0zbGzThksBeN YpMzdR1ahJz9RSsMTsRMuichj06TmJbi91hvyjuX8jrq1Ep0dS27m9ZgVNToClts xAj8diDPs/UyAwMiLCPKldQMf4h0Gnii3pWtKJlJw09OCqiEmFdJg1DXbRFG5N5i SO4fyKAtD4aDEo+BY1qi+uT3X/RzO+T73WO0BpZGL6OH4sVXhKFY+z6qt22LbsTT 2vH0rlFyYav9iZFuZlM0rUYMcLJm9yU8L659pwVdAo0YVfv3x42QsQF9W7qNGCnd hHNIehLGpV7j2KwaBKq9GFD8BxcpxjUAMhuESdWDa80CAwEAAaOCAW4wggFqMB8G A1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBSmwefh9PZH Y9cvfY2Q+LojT2CsnjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRV HSAAMAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0 cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmww dgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVz dC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0 dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAELQvN4F o+l0anb2ajsD/Baf/7IsyDmPEmfYADO2mpz3QWmEOsuc2/jbHyLoryNQq9PHUSng zRmfe7N+iFfqF5p8/sbFUbwQrN4e5yXDagrFakztUlxFXR73fwIk5Rc9KmIDudq7 yqzN68To4sbUpzopPg76AKejfkb3Y8V0yEm2TMsFP2W7d8S6O74TO4PpfR3QEf5K ItzX6cWubJ7e2dpRXMaocoLTzTX8ZJlP52/lUN/ALjMOga4aZkRIMY0S1X8w1ywE Rvkcm63QZnXROlOHmK8cGlHrKaenPnxkipEXhRWoNvlTVVBTH8CjDsaNN+jPMij+ feO6mLvXYlNieyW2YU6/G7lMYVNIDczcFby6xUu1pHuDUAmyS0Qn2snHrevLaFzh 60jQ/gfmWO2K2vtwhFQDnUF/dq7M8tfBvF2g/8yHDsZIJ1t4PGW6sFfqczJhwEf6 LdNn/D/ealgg+IYdixjChRsMd1CaavxPXfD6k7U4aX91sL25B8zQn5/yTpTq0oKT JQgsaQSmB6OYkS8dUIW7Q9XLmSboySMzBNK6MPW24hAsYx2gGTOM1Xtlo/V515Q4 HCaMS6OhVNGJnncATAT/a7FiMeWxe3shQ2pVT4dfiHkHB92qGrLc/aVFJ1lo+vqB 4aqkILjAI7MLPZQY2MnnThQyv6WWAcpxZi4H -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHTCCBAWgAwIBAgIQdehbaKdYlGoY01jU5HUErDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQw ODIyMDAwMDAwWhcNMjkwODIxMjM1OTU5WjCBmTELMAkGA1UEBhMCVVMxEzARBgNV BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU aGUgVVNFUlRSVVNUIE5ldHdvcmsxPzA9BgNVBAMTNlVTRVJUcnVzdCBSU0EgT3Jn YW5pemF0aW9uIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAK6R3mOU+I+sVXWBePIjr679rS3/U30qSlAS 0waZlxC8CvEOGJlmEhwjlMYBpv7NDPkejenZJTF+0/sJeNI/dZa+1DQfvpq0SDUi ZC6VsQAYHhMllY6l0lwpkH8Sdf+eBMM6AN9CkfFdJqIcFDmJmFsVf9t5NO6Y9hHm nOd5OhyuMpC2gbzcthBVu12AoPe8hrMfsv1BpmnzjV1kd85RSyHbQBwCfj/eSzj2 7921kRq2tc4N2boytQKVQx4CeCIxonIzyksBM9PBdtJFZ1Doe4IiEYVn2LPM/Lx2 +V8l7nsiW17KKho6wmcAlYvifW1TyOYbRjEf0Uu0hCajADeL3eUCAwEAAaOCAW4w ggFqMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBSD AVZHpk4wES5tDAWiQpNy0kNNczAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgw BgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQw EjAGBgRVHSAAMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0 eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVz ZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUH MAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIB AGjikUmTPS3DIOjMr75xDPH6Rckp54/NJUFZ+5RD/5QwCVtzjd+ILIWZ1Z6zDJbN LLuZ1H3M0vwLgeC/Blw3RsXJ9042RtxBzPFhHwYWrcmqnxa9atA6FMiVNmQ/00P7 OtqVkVCS13fP/lLL5znQmMsolDBlEXuufiQ+f4n6VPxJnXyxqzhaBBuxRkIkTYT6 H8DKEOakTxHny3ZPkWD3S+tW9/T3zyrWWJNaKZp9IS12rV7gX5khsSQLvh6Wm52K eCwQgeJYcyrkKwWeONeTVuHVGm+kqh4sz22TDYB7r0BQ/ksv/ZwIKUXNpfBqloMG d1V7s0LLnjU0Gk8tlh2Ab/28Ti/jV5MifgVZdLsqOJ3T1N5sAZszdba/v8wfbIoz 26nwAQr4Ucd0eQSpT2xpAcv5xRWYUKb6cfEksF4kcUZ8ypM48sKCpkTU12LSuqhA xue3Sj1FlmFefNZZwiy2yY51OEiQQAG7PpnEQIf6BqVbK/+YcR1uosyuYgb2p0BB oRvTw5uCcXYGCIQUtu6T7hhqMnBzO7XXU09hF8gRrToVsv1kGGUysDlWULfT6Okz f4IBVKdueeVTJml/Ixzf5k8bZ0zKfhJZ4IuUVKxV+jpIX28r9WBYG1ebg7zmv6OG eihe0bB0IaOytrl1dSpUmqHaqPjhM2CJd3sC8rZPZ8rQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEzjCCA7agAwIBAgIQJt3SK0bJxE1aaU05gH5yrTANBgkqhkiG9w0BAQsFADB+ MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B LjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIwIAYD VQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4XDTE0MDkxMTEyMDAwMFoX DTI3MDYwOTEwNDYzOVowgYUxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRv IFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxKTAnBgNVBAMTIENlcnR1bSBEb21haW4gVmFsaWRhdGlvbiBD QSBTSEEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoSVj343kIAfZ VNHRBPYX4j5H+8N0JbjEvxISvOBw0TkFwhez94JwoE4H/hAq/9sNRl4klKOLRZ8Y m85CxK7bgzO8wru0MLanN4d4e0jLJSyCuwpIEmB2ieyOzI8eUkjphgJawrCKfIU9 2f9gTzNspqGgheHXU/LqJz1lqXLBCIPMsCWcEUYk4D70p+/tUbFlk0K09uaGChB5 MjZYsmuo3NV6Hp0U7kDnskZMvZopwuz4MMFiAiriHINi0IU2GoPeEoQpZe/SMr4x YEKoz/jd6tBWRx29dpYkE+e+2Zkr+jBk8Yo4eqbhKpYCsJ262I9tTnqUaX2wk6p0 5ZOQE/qimQIDAQABo4IBPjCCATowDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU 5TGtvzoRlvSDvFA81LeQm5Du3iUwHwYDVR0jBBgwFoAUCHbNywf/JPbFze27kLzi hDdGdfcwDgYDVR0PAQH/BAQDAgEGMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9j cmwuY2VydHVtLnBsL2N0bmNhLmNybDBrBggrBgEFBQcBAQRfMF0wKAYIKwYBBQUH MAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5jb20wMQYIKwYBBQUHMAKGJWh0 dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9jdG5jYS5jZXIwOQYDVR0gBDIwMDAu BgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzAN BgkqhkiG9w0BAQsFAAOCAQEAur/w4d1NK0JDZFjfZPP/gBpfVr47qbJ291R6TDDB mSRLctLK1PoIxpDeiBLt+JD5/KmE/ZLyeOXbySJXq0EwQmsLn9dzM/sBZxxCXI8n Z8duBwONDpbLCgPMPviHPDUwzRiM1XHdzd1hsBOjZEZO/nFOa2XpFATyP6i9DDY9 Kl2eB/LCT5DFXk0YN9EnKICkNuXKk2plDviTua9SWEt6cdi68+/S8/ail+RdFAKa y+WutpPhI5+bP0b37o6hAFtmwx5oI4YPXXe6U635UvtwFcV16895rUl88nZirkQv xV9RNCVBahIKX46uEMRDiTX97P8x5uweh+k6fClQRUGjFA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE0TCCA7mgAwIBAgIRAMWi0/brTRk8F6kKo4opblQwDQYJKoZIhvcNAQELBQAw fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xNDA5MTExMjAwMDBa Fw0yNzA2MDkxMDQ2MzlaMIGHMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0 byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRp b24gQXV0aG9yaXR5MSswKQYDVQQDEyJDZXJ0dW0gRXh0ZW5kZWQgVmFsaWRhdGlv biBDQSBTSEEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwkjZnegj QDnmzVUWTRJjmqhLeUg5+KdA+8O00r5sYK5ZAYXRIaGygJSpI7Xlnc6hVfWebNqk Sropm130IDmyQvYLOr7SFFwkyJpwW0M4ibk/rV9UaVEfsTqmiGNl3+dUX7swDeLf uUoTqXOF52qxBZf1qMfwFPSvBBxCLRQECnNTTHXtEdF00fYGnikgkceuWJfn/0Pk KR7Fo4paMhRtXN1cRKuoMwUaWGRlpZJLztsDUEVpgex1n/PbKI9n/WDif0BceTj0 Yr7D0DDzybS9GniVW9jI406Zbfi5apOLxKIH/Y5d7tLSxlLhV1Dt/ORa3iF+OzxZ 9Bj7ox0rbHhzpwIDAQABo4IBPjCCATowDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUufIi0SCS9aXhE3Wu4Hb4yfGtc48wHwYDVR0jBBgwFoAUCHbNywf/JPbFze27 kLzihDdGdfcwDgYDVR0PAQH/BAQDAgEGMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6 Ly9jcmwuY2VydHVtLnBsL2N0bmNhLmNybDBrBggrBgEFBQcBAQRfMF0wKAYIKwYB BQUHMAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5jb20wMQYIKwYBBQUHMAKG JWh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9jdG5jYS5jZXIwOQYDVR0gBDIw MDAuBgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQ UzANBgkqhkiG9w0BAQsFAAOCAQEAUbDCOxFY2JERv02ZR8fmQelc/AzuQtSLs2MO b/Mz3l9NU3EdsF+Pd9zTr3MZvnw6+QfD+eTgkjNGpMTXRMxtNZahEACjdYftukcP 7sTTYlAa3DjR6h2ayCY5+LCpC9y+agNqnn11DJvwD8Tk0jVuGvWjgPii5zlTG1Cy CWSLvykZQiTA3ffszzcSEGklT+lftAzTqTiC69Ul7J56gZfmwSiK2jiyMcXDVHyB IhWyLCLnD1fA8hYnnSlXKLNKHX0ZLORY585jv1dJ2GHPis42NjE6re+RY+jezTDJ VYpsqEvLOEvf08u5xjzZ6HRX8wD561zNWX1uvFR3JDmyb8eW1g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEzTCCA7WgAwIBAgIRANBLb+XdW9Ih58dM9kaLMUYwDQYJKoZIhvcNAQELBQAw fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xNDA5MTExMjAwMDBa Fw0yNzA2MDkxMDQ2MzlaMIGDMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0 byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRp b24gQXV0aG9yaXR5MScwJQYDVQQDEx5DZXJ0dW0gR2xvYmFsIFNlcnZpY2VzIENB IFNIQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHhvLXeA4kyBVY Dr12JusjW+/HPPWpBmWnSZC9gadbNXCD/GlHrGruRWrKn0YBasbonXi5FLRon717 aCCDt2+7URnJx4mLGt3X73yH3I+T+COuyTFOuLId68jYV4vfBm1N/N1/KohGr8+R 7eT4f4agfXVQ+gDZT3pGTywqc9IId4uHaFjW+mr5vVfu7WjL8A20jOawvlqV2K4/ qSrjPZsqHlzf46LHgbQEK1EjTPsFrfvAQxvGpHiEIAFsS+1d2xPIEJVIxvq+KyGb W/0SJIj7/SfYo+ItvJ2a4/G2JfoPF9wTCC0N8U5I/KXxjYYXBcIE9pQ16T24T+dr MfPG2mYtAgMBAAGjggE+MIIBOjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRU md2b/+inDqMZnVu+QlffMPyPMjAfBgNVHSMEGDAWgBQIds3LB/8k9sXN7buQvOKE N0Z19zAOBgNVHQ8BAf8EBAMCAQYwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2Ny bC5jZXJ0dW0ucGwvY3RuY2EuY3JsMGsGCCsGAQUFBwEBBF8wXTAoBggrBgEFBQcw AYYcaHR0cDovL3N1YmNhLm9jc3AtY2VydHVtLmNvbTAxBggrBgEFBQcwAoYlaHR0 cDovL3JlcG9zaXRvcnkuY2VydHVtLnBsL2N0bmNhLmNlcjA5BgNVHSAEMjAwMC4G BFUdIAAwJjAkBggrBgEFBQcCARYYaHR0cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0G CSqGSIb3DQEBCwUAA4IBAQDRhC+yVHfF/IFcNNKbkxX1aVsCZ0fa2t+MxyFcs7KO qW1fGpOOycughOFnbM+lz4Y3gt5RaOFJTm7YVUZZ3751s5tv8nhXeXfrRIpQN7Cu +Nei457HlDxEUItPlkYnDbdDes/96T19cICd1TmIPekYRXiyuPW4Wgx6vykmk91x LkJ0y74TzVtUofVF446qXvea95zNpzYCVMg+AOX3ZZyy9XfST6g4um+cw/Idv31d bnJdBzMOgHH3uw2YMiZQgDqvNRE+wAs+PTFEIKHmBc/t1n3Shvg9e68M+5ZRM8bE WGqgLqfreTgCsCQcv9MDYw9TFUbS17RdE6NtiPfszTky -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE1TCCA72gAwIBAgIRALWtD2OFTMRiLks5I7KQAhYwDQYJKoZIhvcNAQELBQAw fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xNDA5MTExMjAwMDBa Fw0yNzA2MDkxMDQ2MzlaMIGLMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0 byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRp b24gQXV0aG9yaXR5MS8wLQYDVQQDEyZDZXJ0dW0gT3JnYW5pemF0aW9uIFZhbGlk YXRpb24gQ0EgU0hBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQu 1QDMW2HpTB+NQ14+w+dvSV0k/bXvNTz9K6KrTKgXDm1eJZ44QNMo9Hb5230nvrJh wenVEmOsJRD/Ux/oSGDASK58+ckfgY8CeMMsk7rNkwAlBgDp3mBpdhBADMFevgxb B+ADq01B91Mit5Tbkc2wP1VlMr2bglVZxmGS39NjpwFRmrzEdxpWdWSX48Ksowt7 QH7QGQ0Af/972ZIam1ctsRGcOkA5h6t/iZXlV5Y2+H4/4pcr4uF4z30I5VHyJWqx dhbFlaBnmnj/ChLa4wdpObqZl7IUz3MOBioMzH8DyiuEAZ5O1+wPALidIlc3GbVJ gl6/SwKwh4O4EywWxZMCAwEAAaOCAT4wggE6MA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFO7t6FRgEws1g6D6a3pGOvc+MLtmMB8GA1UdIwQYMBaAFAh2zcsH/yT2 xc3tu5C84oQ3RnX3MA4GA1UdDwEB/wQEAwIBBjAvBgNVHR8EKDAmMCSgIqAghh5o dHRwOi8vY3JsLmNlcnR1bS5wbC9jdG5jYS5jcmwwawYIKwYBBQUHAQEEXzBdMCgG CCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0uY29tMDEGCCsGAQUF BzAChiVodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvY3RuY2EuY2VyMDkGA1Ud IAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5w bC9DUFMwDQYJKoZIhvcNAQELBQADggEBACNWGnCyexPgGwHHefwKh8dJHoTEPxbM M7C2+8tFUiTHKroVdqfPHywdmZ7k0H/0lm0uP1wlcbj1k/dLPb4gugp0UYNB7qk8 os22unSI9Yy/1xpMqNH9Udg7zK4F81YC2YtD942HVWQ1/8GYRNWbMmZmPSJ8ijXz G6xOSIu3WZgh+qm/B5UpdA1kVXeWL6IcGIj5vnNVwVQiSRroPT+qqHcgVxrs5IAj BFUNKdQQrInpvGFqiQ8uwOde6gp58IpH1e1h8DIoc/vNa9v/7lZ5s48Q172lFkug v4FHHMdGV2C1grGQtXyS876ZGk9D5b9Q+SerjBC80hlfGAOt96PK+j0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExDCCA6ygAwIBAgIRANFHqimwQon39cZCRwCf0zkwDQYJKoZIhvcNAQELBQAw fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xNDA5MTExMjAwMDBa Fw0yNzA2MDkxMDQ2MzlaMHsxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRv IFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBDbGFzcyBJIENBIFNIQTIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx18bqyCv0SPWXB4CZgm8QQhAY 8uZiBGDik71soZjQrkqtojt2OshK4D15j5mzJI9fQqvaVfDT/0i7GKtzlnShM/+6 g1nDzw9ZGmqcoItQJKFZRuU7L0W4PsoykHlbWMMTYTUAOsUlQbZutUhb4Kq6ldvX ktzxRaaUntDHuBQKRsp2KLciMfOCMA7p0NFBjGCNovTL7r0Z27S8ROwouCsWeRF9 ZoJp2y5VbGHXtwwuvZD00l6ATOTU80RqEbQ9noNW51yf/HLTKA0VeFkkTXAX/7jF HjYkj94UdQZ53zPjBJ0ZBNmVVsTh4aH/6r+dojKTCFjmv4/KEAM3waQ65fYVAgMB AAGjggE+MIIBOjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRNy7TZu7LjQZge cJtnnyxd9jmcYTAfBgNVHSMEGDAWgBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV HQ8BAf8EBAMCAQYwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2NybC5jZXJ0dW0u cGwvY3RuY2EuY3JsMGsGCCsGAQUFBwEBBF8wXTAoBggrBgEFBQcwAYYcaHR0cDov L3N1YmNhLm9jc3AtY2VydHVtLmNvbTAxBggrBgEFBQcwAoYlaHR0cDovL3JlcG9z aXRvcnkuY2VydHVtLnBsL2N0bmNhLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAk BggrBgEFBQcCARYYaHR0cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEB CwUAA4IBAQCyyIgCHYt2uN9cgDvx0z7TUveOs8ecBZbbMqDuIGqlBLk3YsRvYgKd uJHL7LDHGDUb9XPHApFgm5RDDwgeIaMvj1H9tDJv/S8BoPgzYCTP53gudUX4v24M qC7DmrmaqNAn7QMPs9GrphIoO/zmQZoHltliweeTHfqu5uc40V04tyrQ0mGNvLTx xrAlSouf2Bya8wpLzyfPee1iyEtejMSkDy4J1deJZZcVOH62hvI1NWeL8ZCp/zoW vl2UDNDK8hEJn+QlaQl2dTGWKur/N45emoJKaIkZDFlfeV4pifb/vT/7zGgycgB1 Znr1eU5120hCg+lFD6Y3qDjBTBQX+9il -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFTCCA/2gAwIBAgIRAN9DSK67bcikyUhi80iQC+cwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE0 MDkxMjAwMDAwMFoXDTI5MDkxMTIzNTk1OVowgZoxCzAJBgNVBAYTAlVTMRMwEQYD VQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMV VGhlIFVTRVJUUlVTVCBOZXR3b3JrMUAwPgYDVQQDEzdVU0VSVHJ1c3QgUlNBIENs aWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgdC/hwGVueai+SgFnfi81c7VkUi8/moU z9XqVjJmVujaVO9O60pTVwpsRCgzpnPK5nfzkMi6J78TpRoJqVoXn+KppKoUo2Dj b58Hhp39eV0jdQXDOPa+KMSHp1UjiKqFlDGjF9nkEqx5ghCmEEEfKPbezQM0vf7q zPOkpuYwZpa9qMng3c8UOriJfVxhBcnUqfm1mxrur+VjvzvhUhNDAne9miMIE0JA mMAUxXK2vl0Cn+/EjWrSD4V5pYHgp4Mcam7m9t8UU7x0E3clRPDTtcks/3xlLVMm EtWKNsJQRTOTTlEZQo7betsJpXUBJDl6y60qDnme7X+9FRWbBxqdBwIDAQABo4IB ZDCCAWAwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYE FNHcPiACNgYyUdTArYomkyAL4KXWMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8E CDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDARBgNVHSAE CjAIMAYGBFUdIAAwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1 c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYG CCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3Qu Y29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRw Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBrUYWWWBuT r/95mXaVA9tJe1HHTwhq9yCDah88KjXxsXCye5cOjRGjLbzrUF+BJdpWkdqzLnoy 0FHSldr81AN0rl6h86C8bT9A0NbN8jieAm9N8v/t9/ntybXmQDE+2OK9KVm8RjqA J4DlF8/VdcQaiD/HRKzTv46lEyGcY1+6dZp4UMxgmGDzHUmT8MtcIygTwADl9xio YinqE+zMwcA4JKCal70ZAs2IZMCd4Xdxagsht+M2hML/0EsmMoqk01ZS21rlgLgl clrNhmmT8srCILv8s541jmefMbWkdIR2PBDVP0/YGCr6PMcf8Ra0OCxeT2hvym1U 0p7pEVEg0GoECwRXiT+IpEmfMogr0CTTwjlYrt5q/Q4I1t6lZCxsEp6hQG2gAU0f tsnJSw1zT5MhxS0wJfUpVyp8q7HVgurdcRHw7B9yj3CvuplmfwkkwaScgMigYpPL s19e0tCZYg2ZC2mCoRgqW4mATB5nALLog3VKw4Vb8iVz7Ncjc0YWqCGe5p6qkMhR ziyrQQTmCQt8+GsUmupucH5FJVV0UmjpyqZVkRM2yO7kIxFNnPcABUDv9Bv2MtXr RYwsUHbXHsjklM4IwrzsFHfo8DAF6a/PID3T/m8bzK+4gfmWIA1+ZzLKFsPy9ECH fB3m4iByAmYtX3LcSXLWNcmTYUEYyux45Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqTCCAy6gAwIBAgIQHky+giOEiULGBstThAny0DAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwOTEy MDAwMDAwWhcNMjkwOTExMjM1OTU5WjCBmjELMAkGA1UEBhMCVVMxEzARBgNVBAgT Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg VVNFUlRSVVNUIE5ldHdvcmsxQDA+BgNVBAMTN1VTRVJUcnVzdCBFQ0MgQ2xpZW50 IEF1dGhlbnRpY2F0aW9uIGFuZCBTZWN1cmUgRW1haWwgQ0EwWTATBgcqhkjOPQIB BggqhkjOPQMBBwNCAAQq0y9I3LaaLYihiepvuNnhhTblevh1oocoXZbC5IBFzF7G 8N8/hFdQn4OU2V3kXZJTp/pUy+orhKOq6U6e6gONo4IBZDCCAWAwHwYDVR0jBBgw FoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFIpUVZi84hUR3cMZi2IV xLsCAdvJMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDARBgNVHSAECjAIMAYGBFUdIAAwUAYD VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/ BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVD Q0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1 c3QuY29tMAoGCCqGSM49BAMDA2kAMGYCMQDWod+sgJPP5tpKrp9li9RKH9hKmEDD Tsav1P2emh9NRhVIIejSnNrv30XsrntdvpsCMQD5kjoZRGixq8SnW/mTTppeHJZ7 PuQj0NqM3/eCXi9CkBYK6fejMtW5IF8b1P9mrJk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDmDCCAx+gAwIBAgIQNJSlovoVpFdNsrSitHYjbzAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwOTEyMDAw MDAwWhcNMjkwOTExMjM1OTU5WjCBlzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N T0RPIENBIExpbWl0ZWQxPTA7BgNVBAMTNENPTU9ETyBFQ0MgQ2xpZW50IEF1dGhl bnRpY2F0aW9uIGFuZCBTZWN1cmUgRW1haWwgQ0EwWTATBgcqhkjOPQIBBggqhkjO PQMBBwNCAAR+YWqwbDcJWOGL2KtH77iPpL+aiyqA1ZaCYxAlQADyzluaM94hGP7k 16DPKego5xlOMfhDt/j4+FQa2p1VtQWho4IBWzCCAVcwHwYDVR0jBBgwFoAUdXGn GUgZvJ2d6kFH35TESHeZ03kwHQYDVR0OBBYEFNt7aY3yTA5yV0t+h2auhpayFCLb MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQG CCsGAQUFBwMCBggrBgEFBQcDBDARBgNVHSAECjAIMAYGBFUdIAAwTAYDVR0fBEUw QzBBoD+gPYY7aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RPRUNDQ2VydGlm aWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsGCCsGAQUFBzAC hi9odHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9FQ0NBZGRUcnVzdENBLmNy dDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMAoGCCqGSM49 BAMDA2cAMGQCMBzcd1ZG7oblHyoTthXDJL7Rv+2+5UNDlhf9Zd7u8yI5/gebPCDR JokYOAXK0bt1mwIwVLYvS/EQX4fWo3v3/j/sdDUq1GOV7Z1wjEtrqZ1kFQ3RpXkO JWyGTyrIfpE3Tlet -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGuTCCBKGgAwIBAgIQAIEIODzAB3XEDG1za+MwizANBgkqhkiG9w0BAQsFADBF MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT d2lzc1NpZ24gR29sZCBDQSAtIEcyMB4XDTE0MDkxNTE2MTYzN1oXDTM1MDMwNDE2 MTYzN1owTjELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEoMCYG A1UEAxMfU3dpc3NTaWduIEVWIEdvbGQgQ0EgMjAxNCAtIEcyMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAL+MVu10kh055MUIkpRaC7sfiuFQ4gAYFv4B 5LfsK6NSpTaJybYvrA/lr0JBE/xTsQl3Jrka60FgprSh9pXgE94UVoE2Qb4LiHEo AIYyBQY0aA3nL9GEkT436uXs0tV2Veg6+6CgGRzgaoQtDu3hXWV5GOyNOAtlmzR4 md1JH6oFap9d3kVwJLExUI930Cwjzwt0XAcvjy8+fLheBanG5VFGnRrntRSWiRzY QIjjAkBDTi+lj552h9aKzFvFEQ5NSiBmrGVk2wIlrh+AZe8NYnXrRBzv0Z5SODD4 jxyPkTAX7f9zkJ9s0yMVEmalWnfwXn4K4Rz3x7fmWeyxipUOhSkCAwEAAaOCApow ggKWMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW BBTu/UbK9ydekbxatueHzQr6VQomQjAfBgNVHSMEGDAWgBRbJXuWpGVRfrg588B4 Zl7oOufw7jCB/wYDVR0fBIH3MIH0MEegRaBDhkFodHRwOi8vY3JsLnN3aXNzc2ln bi5uZXQvNUIyNTdCOTZBNDY1NTE3RUI4MzlGM0MwNzg2NjVFRTgzQUU3RjBFRTCB qKCBpaCBooaBn2xkYXA6Ly9kaXJlY3Rvcnkuc3dpc3NzaWduLm5ldC9DTj01QjI1 N0I5NkE0NjU1MTdFQjgzOUYzQzA3ODY2NUVFODNBRTdGMEVFJTJDTz1Td2lzc1Np Z24lMkNDPUNIP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3RD bGFzcz1jUkxEaXN0cmlidXRpb25Qb2ludDBaBgNVHSAEUzBRME8GBFUdIAAwRzBF BggrBgEFBQcCARY5aHR0cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS9Td2lz c1NpZ24tR29sZC1DUC1DUFMucGRmMIHRBggrBgEFBQcBAQSBxDCBwTBkBggrBgEF BQcwAoZYaHR0cDovL3N3aXNzc2lnbi5uZXQvY2dpLWJpbi9hdXRob3JpdHkvZG93 bmxvYWQvNUIyNTdCOTZBNDY1NTE3RUI4MzlGM0MwNzg2NjVFRTgzQUU3RjBFRTBZ BggrBgEFBQcwAYZNaHR0cDovL2dvbGQtZXYtZzIub2NzcC5zd2lzc3NpZ24ubmV0 LzVCMjU3Qjk2QTQ2NTUxN0VCODM5RjNDMDc4NjY1RUU4M0FFN0YwRUUwDQYJKoZI hvcNAQELBQADggIBACVxhUgwnsFZgEmC50cCMExcmvY9OQkPxcQbMMFCYvfvBFNz 65iu0MkXTo0jhaIe8wOOsv230q/zYJbTZOGbMpvUg5MRRIK9DCq3bDwAqN9bIjFw wK1bODt260m9+4gLxJJdt2MH5LAglQ2J0123+RodYxvv3b+5k6/DZ19dJUgXrjbD +0PWuO5+5DRangp3VELIRWjHAAnpmq3guORiLuVDS+PoinFp/CKEFRhgWIhp6sZd yA/9egO+ZH+U7KzLaMuYRNHfJr2UrgQUEufsOM0WUqQXS8RzO7ZGW/argfyc4NdS CivO97xZBroON0XaLOlTAAbubomhzz/K/Uv2S5T+I/AfYWCme7Vx/KyeA9if/eLA jQNn5lIb1cXhompM2M+kLAGjNhdpQvUSkjAhKOkzoeezJEN+RXU4P5tOJxw03LtJ VxmdQxQwgXOR0rBZT+9aFJSX1nIj7zWRnMwFu5w+gBaX1/5MuLP/ThJCckoVgb0o nbFLRn6siH6dNE+gZ5VgiMWeDOkwlR1UMWGMNwoKNExoTKYwKnpuMfv4q7Fx4uI9 qVzGTL6yfW8+SRdxVFQa6K9hekBr2kZyAKBCqz+jpQq1EPCcvn4HiNx81Na++iqe K+d2mfZxdEuAwFoZIcyk1aTWHHT1Cqzys00wlukvSmnXUBbGU5Vpwzjlj3N4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQAMebmQCSGkI6sdFbXfchpDANBgkqhkiG9w0BAQsFADBJ MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQDExpT d2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjAeFw0xNDA5MTUxNjIxMTZaFw0yOTA5 MTExNjIxMTZaMFgxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcx MjAwBgNVBAMTKVN3aXNzU2lnbiBQZXJzb25hbCBQbGF0aW51bSBDQSAyMDE0IC0g RzIyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvtA1UE9m8aLuB413 sMuiIvxI1yEgzUZrUFQOVx5m4I5WtZ0pl+mjzCzZjzxHW8MMjE6uZaGawJxKNU66 7V0QLRIgMaf5V0RcDLa+bki8rI6Z4v+dlwMBowlPbHsqUpw5JZuvGcdOMasNsDl7 8jwODgqQM45uaLzCT1om+4qE4ffZdSTYq//omfZKi3rgZtRCXX2n0zM6+6RMEI2l vZeDkrdV7zSU0mXMNW2/EUHd3eAQt3ElLvLGu7sAp7U7lgXTQZpvjHXvUzZz+sRa 9OsuqGvoBGrM0Lv2jXE2lX8OKDv+l6FnZnixivOD774GyaWO99L0mkE8XCVxIC3Y u5eoXQIDAQABo4ICkzCCAo8wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFFmw2b89wTe23AYUp+GZ40IY2pZBMB8GA1UdIwQYMBaA FFCvzAeHFUdvOMW0ZdHelarp35zMMIH/BgNVHR8EgfcwgfQwR6BFoEOGQWh0dHA6 Ly9jcmwuc3dpc3NzaWduLm5ldC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURF OTVBQUU5REY5Q0NDMIGooIGloIGihoGfbGRhcDovL2RpcmVjdG9yeS5zd2lzc3Np Z24ubmV0L0NOPTUwQUZDQzA3ODcxNTQ3NkYzOEM1QjQ2NUQxREU5NUFBRTlERjlD Q0MlMkNPPVN3aXNzU2lnbiUyQ0M9Q0g/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlz dD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MF4GA1UdIARX MFUwUwYEVR0gADBLMEkGCCsGAQUFBwIBFj1odHRwOi8vcmVwb3NpdG9yeS5zd2lz c3NpZ24uY29tL1N3aXNzU2lnbi1QbGF0aW51bS1DUC1DUFMucGRmMIHGBggrBgEF BQcBAQSBuTCBtjBkBggrBgEFBQcwAoZYaHR0cDovL3N3aXNzc2lnbi5uZXQvY2dp LWJpbi9hdXRob3JpdHkvZG93bmxvYWQvNTBBRkNDMDc4NzE1NDc2RjM4QzVCNDY1 RDFERTk1QUFFOURGOUNDQzBOBggrBgEFBQcwAYZCaHR0cDovL29jc3Auc3dpc3Nz aWduLm5ldC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURFOTVBQUU5REY5Q0ND MA0GCSqGSIb3DQEBCwUAA4ICAQDJExIoZpzxBQgj+rXSsd0Pmp40RBlxtpVFsnZ1 EgXsrsWM4RNbGN1j4e4Gvm+vQ6wnyZkHhR4lJxLbeWyo8l//zcBjJxs+R69qYxPX j5a+ZgJ07lYFyE4YTJ95Niq5qcy0sJRqSBohxhxcsCQ8SyMJtU/Rw6ZRZLmpOMDM 4sN8YyIhlzTfK+Dy7X+sA3I6Y3EfoHBJT2L6Fww1f+65vYRyQjg7cWLJZ7LvTe2X iLGEgy4t9UK04uecDR0E8kY+ctBqhgkRODQ0vI8ZAeYl3mda0eECbmuu4zAWcv78 DY9EjM4mfIjOMw5EJzId7IjcoFPAncEuBy5C3hptdqWrSqHBOYUwW854KUoysHJj 067beDjs3PAv9bKq+EJlh5n/X/OfeKVtE8ALTIjZyYnzem+TIaNPpp44R0YQERCn r6CDvoL9k76rpVedTyrOu3gN+nhBmAqwx1FwgT1s1tfUuCO32qe19+QqL/pX/57A I6RJCZsIn4GGuynHL9LpfNI/bM1SpGO66Nh/q7wESlqfGopMRngAl1Ozfu4zmulR p6aV4gOfqGS4vrTpeeOBmzoaPBsy59qsnuGgEgKtE+CuI1voINaEyHcXERLb+ZuI 4Dp7+zCmcZSoXoSxTILmVbySTSc3zrOm11aDeZbbIVYUd+hIsb2FV+RJeN0JJ6Sg iuAaqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQAOKjZ925iBlAqEheVUGp/TANBgkqhkiG9w0BAQsFADBJ MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQDExpT d2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjAeFw0xNDA5MTUxNjIzMzZaFw0yOTA5 MTExNjIzMzZaMFgxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcx MjAwBgNVBAMTKVN3aXNzU2lnbiBTdWlzc2VJRCBQbGF0aW51bSBDQSAyMDE0IC0g RzIyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApgky7tyv+w2JirbD l30lH5v4JrHDKwU76slAffIE7gy5FiX6EB08/FSAiWkULdkoacAAj8+9ZXOhUJAv id+EVKqS5ccNAlZFTF8r2964fLgiia1MCauqQkyV5pzRAP8s5UzNcfeFw0WfSP6U RirIHEHFqM6G7Up2Nv67WjzmRfSSN/x8womdSsXvSaXweYBt/PX4/Sl893f9UW9j SPz0uUd7m5aW8/z/+vuJAOdSXVBWLi4hN2T9Dvgbuy0n5O0xc6wVnNvZB2fxbEaF LBtJIWu6OcpLpNWFsfyTNiZ9SGklftD5pLWCgyeERuzurdnspdf09GtlSYh0VyZe nOMDqQIDAQABo4ICkzCCAo8wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFPCQTIvh8ALeAAFrmOfu3FGN20CuMB8GA1UdIwQYMBaA FFCvzAeHFUdvOMW0ZdHelarp35zMMIH/BgNVHR8EgfcwgfQwR6BFoEOGQWh0dHA6 Ly9jcmwuc3dpc3NzaWduLm5ldC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURF OTVBQUU5REY5Q0NDMIGooIGloIGihoGfbGRhcDovL2RpcmVjdG9yeS5zd2lzc3Np Z24ubmV0L0NOPTUwQUZDQzA3ODcxNTQ3NkYzOEM1QjQ2NUQxREU5NUFBRTlERjlD Q0MlMkNPPVN3aXNzU2lnbiUyQ0M9Q0g/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlz dD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MF4GA1UdIARX MFUwUwYEVR0gADBLMEkGCCsGAQUFBwIBFj1odHRwOi8vcmVwb3NpdG9yeS5zd2lz c3NpZ24uY29tL1N3aXNzU2lnbi1QbGF0aW51bS1DUC1DUFMucGRmMIHGBggrBgEF BQcBAQSBuTCBtjBkBggrBgEFBQcwAoZYaHR0cDovL3N3aXNzc2lnbi5uZXQvY2dp LWJpbi9hdXRob3JpdHkvZG93bmxvYWQvNTBBRkNDMDc4NzE1NDc2RjM4QzVCNDY1 RDFERTk1QUFFOURGOUNDQzBOBggrBgEFBQcwAYZCaHR0cDovL29jc3Auc3dpc3Nz aWduLm5ldC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURFOTVBQUU5REY5Q0ND MA0GCSqGSIb3DQEBCwUAA4ICAQAwt+R/QMYqzRIatBxAcIQQpCkL18rYBfbFpPWA X62JohEKCrhAVrrP3BFVG0qxtNSe2zgBBh5k48LQ1/FAhsZrw0+HTB9dvtyoTlJ7 IfO0EpiDy8g7i1sjCRNXVJM+sg4t5auyQ0UxdADHBJ4BXI/ie5JmwRicIyb18/ET 7+mr8jPbhvnqcumZndzhrxXiYznw9ZaXldB+BTRAaWnn2hURTVDJZhRRjazax8gX U5FDbYPZizZbZVFY9zPr5FSaMEDo4T1NrXn/Y5J+Yj3J09qs4zdGvVJ8GiYFwBnD CbrqzmQ+rZ+Aw6HjsmljVW/d0yMTwbLhr1QAfZQEYGzKPSU4WAbxMi4YFL6DbiWr BuuJ38YjD+gnUcjb4bx6N6gOVxvm7ECiWsUdfS9+Ojtg1U5ijBOz8jgS2OhtR6Ax FEDk5x3yw1IwwsMpY10Fng+7ugKiTMRTSkgxSWk143qpBGmSdulwqZTUA/YnENo4 1j/CX8W6TakZS0UoFq/dKmRqCYD+egF1AKy41TCotBOc2NV/Xr4W+uNEvYCD8yDV qLghY1G4FHphXVrSEdmEeBqg6jAiRjOHgioCpZIrBSdwNH8qFUUvHtlMH4sJctnG WZrqNoa5nl1wimrx4gjDRiKce2osH57v1BHHou2Cod4Bhqe7D6rqQcdjAnLen3O+ 6NuVmg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4TCCBMmgAwIBAgIQc+6uFePfrahUGpXs8lhiTzANBgkqhkiG9w0BAQsFADCB 8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD LUFDQzAeFw0xNDA5MTgwODIxMDBaFw0zMDA5MTgwODIxMDBaMIGGMQswCQYDVQQG EwJFUzEzMDEGA1UECgwqQ09OU09SQ0kgQURNSU5JU1RSQUNJTyBPQkVSVEEgREUg Q0FUQUxVTllBMSowKAYDVQQLDCFTZXJ2ZWlzIFDDumJsaWNzIGRlIENlcnRpZmlj YWNpw7MxFjAUBgNVBAMMDUVDLUNpdXRhZGFuaWEwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDFkHPRZPZlXTWZ5psJhbS/Gx+bxcTpGrlVQHHtIkgGz77y TA7UZUFb2EQMncfbOhR0OkvQQn1aMvhObFJSR6nI+caf2D+h/m/InMl1MyH3S0Ak YGZZsthnyC6KxqK2A/NApncrOreh70ULkQs45aOKsi1kR1W0zE+iFN+/P19P7AkL Rl3bXBCVd8w+DLhcwRrkf1FCDw6cEqaFm3cGgf5cbBDMaVYAweWTxwBZAq2RbQAW jE7mledcYghcZa4U6bUmCBPuLOnO8KMFAvH+aRzaf3ws5/ZoOVmryyLLJVZ54peZ OwnP9EL4OuWzmXCjBifXR2IAblxs5JYj57tls45nAgMBAAGjggHaMIIB1jASBgNV HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUC2hZPofI oxUa4ECCIl+fHbLFNxUwHwYDVR0jBBgwFoAUoMOLRKo3pUW/l4Ba0fF4opvpXY0w gdYGA1UdIASBzjCByzCByAYEVR0gADCBvzAxBggrBgEFBQcCARYlaHR0cHM6Ly93 d3cuYW9jLmNhdC9DQVRDZXJ0L1JlZ3VsYWNpbzCBiQYIKwYBBQUHAgIwfQx7QXF1 ZXN0IGNlcnRpZmljYXQgw6lzIGVtw6hzIMO6bmljYSBpIGV4Y2x1c2l2YW1lbnQg YSBFbnRpdGF0cyBkZSBDZXJ0aWZpY2FjacOzLiBWZWdldSBodHRwczovL3d3dy5h b2MuY2F0L0NBVENlcnQvUmVndWxhY2lvMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEF BQcwAYYXaHR0cDovL29jc3AuY2F0Y2VydC5jYXQwYgYDVR0fBFswWTBXoFWgU4Yn aHR0cDovL2Vwc2NkLmNhdGNlcnQubmV0L2NybC9lYy1hY2MuY3JshihodHRwOi8v ZXBzY2QyLmNhdGNlcnQubmV0L2NybC9lYy1hY2MuY3JsMA0GCSqGSIb3DQEBCwUA A4IBAQChqFTjlAH5PyIhLjLgEs68CyNNC1+vDuZXRhy22TI83JcvGmQrZosPvVIL PsUXx+C06Pfqmh48Q9S89X9K8w1SdJxP/rZeGEoRiKpwvQzM4ArD9QxyC8jirxex 3Umg9Ai/sXQ+1lBf6xw4HfUUr1WIp7pNHj0ZWLo106urqktcdeAFWme+/klis5fu labCSVPuT/QpwakPrtqOhRms8vgpKiXa/eLtL9ZiA28X/Mker0zlAeTA7Z7uAnp6 oPJTlZu1Gg1ZDJueTWWsLlO+P+Wzm3MRRIbcgdRzm4mdO7ubu26SzX/aQXDhuih+ eVxXDTCfs7GUlxnjOp5j559X/N0A -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4TCCBMmgAwIBAgIQVBy0L8eIKnVUGpY97OXrkzANBgkqhkiG9w0BAQUFADCB 8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD LUFDQzAeFw0xNDA5MTgwODIyMjFaFw0zMDA5MTgwODIyMjFaMIGGMQswCQYDVQQG EwJFUzEzMDEGA1UECgwqQ09OU09SQ0kgQURNSU5JU1RSQUNJTyBPQkVSVEEgREUg Q0FUQUxVTllBMSowKAYDVQQLDCFTZXJ2ZWlzIFDDumJsaWNzIGRlIENlcnRpZmlj YWNpw7MxFjAUBgNVBAMMDUVDLUNpdXRhZGFuaWEwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDFkHPRZPZlXTWZ5psJhbS/Gx+bxcTpGrlVQHHtIkgGz77y TA7UZUFb2EQMncfbOhR0OkvQQn1aMvhObFJSR6nI+caf2D+h/m/InMl1MyH3S0Ak YGZZsthnyC6KxqK2A/NApncrOreh70ULkQs45aOKsi1kR1W0zE+iFN+/P19P7AkL Rl3bXBCVd8w+DLhcwRrkf1FCDw6cEqaFm3cGgf5cbBDMaVYAweWTxwBZAq2RbQAW jE7mledcYghcZa4U6bUmCBPuLOnO8KMFAvH+aRzaf3ws5/ZoOVmryyLLJVZ54peZ OwnP9EL4OuWzmXCjBifXR2IAblxs5JYj57tls45nAgMBAAGjggHaMIIB1jASBgNV HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUC2hZPofI oxUa4ECCIl+fHbLFNxUwHwYDVR0jBBgwFoAUoMOLRKo3pUW/l4Ba0fF4opvpXY0w gdYGA1UdIASBzjCByzCByAYEVR0gADCBvzAxBggrBgEFBQcCARYlaHR0cHM6Ly93 d3cuYW9jLmNhdC9DQVRDZXJ0L1JlZ3VsYWNpbzCBiQYIKwYBBQUHAgIwfQx7QXF1 ZXN0IGNlcnRpZmljYXQgw6lzIGVtw6hzIMO6bmljYSBpIGV4Y2x1c2l2YW1lbnQg YSBFbnRpdGF0cyBkZSBDZXJ0aWZpY2FjacOzLiBWZWdldSBodHRwczovL3d3dy5h b2MuY2F0L0NBVENlcnQvUmVndWxhY2lvMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEF BQcwAYYXaHR0cDovL29jc3AuY2F0Y2VydC5jYXQwYgYDVR0fBFswWTBXoFWgU4Yn aHR0cDovL2Vwc2NkLmNhdGNlcnQubmV0L2NybC9lYy1hY2MuY3JshihodHRwOi8v ZXBzY2QyLmNhdGNlcnQubmV0L2NybC9lYy1hY2MuY3JsMA0GCSqGSIb3DQEBBQUA A4IBAQADuey1NBT9MWWzpxQwwNUN4XZ8nWgd7IZB6Se7TqgcUeO7g1D982bXa8Vr YRFqIx4KuNLDYhq6pKtD8mVIXvpj3WRvwFvv5pHWDSburNcu/Id/q2nkHDlj48QH QqJEjwuuTEdFAHP4c6OsPXTPbDHp3G02+GvJGb2LV959fycwe6YBAF/s+qT8HoZK IHlvHXqd9DALQtjx089Qu4VBHdnPIH3OWlrvUgqAujnvIj1PpYdtFJERSqb8cgLw 6GZ2yN2yHpZtIfpe6YnZVoDA1pn7iWFge6hs6yYgNkR0tGw/FC/r2EhcIZuj6nag wYyJ2hkwawVG6ZjLRevOH1tDEbI3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4zCCBMugAwIBAgIQcbBlOXyOB9JUGpZ/dVk3kjANBgkqhkiG9w0BAQsFADCB 8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD LUFDQzAeFw0xNDA5MTgwODIzMjdaFw0zMDA5MTgwODIzMjdaMIGIMQswCQYDVQQG EwJFUzEzMDEGA1UECgwqQ09OU09SQ0kgQURNSU5JU1RSQUNJTyBPQkVSVEEgREUg Q0FUQUxVTllBMSowKAYDVQQLDCFTZXJ2ZWlzIFDDumJsaWNzIGRlIENlcnRpZmlj YWNpw7MxGDAWBgNVBAMMD0VDLVNlY3RvclB1YmxpYzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMuuTjExvPHbEfGJ3MU9RznScEIL86TETwZTO1GZsF1v RrGAJBV3QcXSXp9/r5h7cyq19DKLTiqRtKmnwSDfQCHbtv4mIJWc8mbEZCRwQ2fp 1TRV1YGFnUZghLh32PjSrjlcZcTH5rAaS8uGXdITf4Amms9wa+Ax705XFCd52sji B4qUJtp6hMC7ECCHjWbLw0Akp4vPiPfbhLAxg400869eaMyEdkQsQYxgzyrEE9mo NFRV66y3iB8env1QmN/NkMqdKlgy86HP22PrSed4fONGSB2mz/Ti4qfGY1eoroPn m5Q8IiWtvfDaBKi/DW5j+ogUJ7+2w6fMAbVZUsHWo8MCAwEAAaOCAdowggHWMBIG A1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRHPN4U d7tqT0eRqQL/1Abhc9zi2TAfBgNVHSMEGDAWgBSgw4tEqjelRb+XgFrR8Xiim+ld jTCB1gYDVR0gBIHOMIHLMIHIBgRVHSAAMIG/MDEGCCsGAQUFBwIBFiVodHRwczov L3d3dy5hb2MuY2F0L0NBVENlcnQvUmVndWxhY2lvMIGJBggrBgEFBQcCAjB9DHtB cXVlc3QgY2VydGlmaWNhdCDDqXMgZW3DqHMgw7puaWNhIGkgZXhjbHVzaXZhbWVu dCBhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpw7MuIFZlZ2V1IGh0dHBzOi8vd3d3 LmFvYy5jYXQvQ0FUQ2VydC9SZWd1bGFjaW8wMwYIKwYBBQUHAQEEJzAlMCMGCCsG AQUFBzABhhdodHRwOi8vb2NzcC5jYXRjZXJ0LmNhdDBiBgNVHR8EWzBZMFegVaBT hidodHRwOi8vZXBzY2QuY2F0Y2VydC5uZXQvY3JsL2VjLWFjYy5jcmyGKGh0dHA6 Ly9lcHNjZDIuY2F0Y2VydC5uZXQvY3JsL2VjLWFjYy5jcmwwDQYJKoZIhvcNAQEL BQADggEBADMRO0eqGiqUdIFFbxqwKXh+K6rXGJAnfgYI4bABMbbIAZaDklfwXj23 BO8JxLPMzgIilTXgswBSZTbTVEujYQfP+lrUjP1ZG2XFPM+vKzsyF4K3s3FyfjdR mj0chun0Flao+gd9nl6j7ySzHspZb1u/i0LSz4/48mY+pTxT1HCVw4zvzm9E9X26 uKxn/UikI9B5EECHGChxw5Cx1RSF7THvhEBXfCQ6wsY632uvhi/H4QAkzmOZkh1P VzzehlsK2telJGfAt+xIxLHYvRUOTC5MRpSt2EzqvTjdsC8gKzGvgqYEhZBqrq7V PnbUX9LuF9aeJlZXPsfNRaIkAJW8smo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGyDCCBLCgAwIBAgIIDQNmRV5uKdQwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MTgxMDAwNTRaFw0zMDEy MzEwNDAyNTVaMIGSMQswCQYDVQQGEwJFUzEeMBwGA1UEChMVRmlybWFwcm9mZXNp b25hbCBTLkEuMSIwIAYDVQQLExlDZXJ0aWZpY2Fkb3MgQ3VhbGlmaWNhZG9zMRIw EAYDVQQFEwlBNjI2MzQwNjgxKzApBgNVBAMTIkFDIEZpcm1hcHJvZmVzaW9uYWwg LSBDVUFMSUZJQ0FET1MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6 cIlUCaCe12gMnFsVFePe9Z52zvebP/J30UrhNH0H4vny6VS7oVOd+aMQvvqW9JmT rYIA1i72jp8TnWNHq0RNlQMzjd+uQkeVSIOrohSHMejah0yx+yUusoWDSXOdhKV+ CCjN+nvcCDUxJW+jmiN/UVZkHzQRK3M0cbQRGRNADeKPsrUrB0028OhBgyPOxM6S x3BIxXz8r2mXXtlFkkgtVYOtU8zyT4OM+c6mPEmnWL+uHpuL4MlzvZ/1RrO+ynyu a54hGkh4iijt1a3PecgdY7269FfhlsIWMSnXvKOeY6u6+F+CkkxwqiRO4xvCEVXY 1ObIHPgXON3VYWIzLxvlAgMBAAGjggJgMIICXDB0BggrBgEFBQcBAQRoMGYwNgYI KwYBBQUHMAKGKmh0dHA6Ly9jcmwuZmlybWFwcm9mZXNpb25hbC5jb20vY2Fyb290 LmNydDAsBggrBgEFBQcwAYYgaHR0cDovL29jc3AuZmlybWFwcm9mZXNpb25hbC5j b20wHQYDVR0OBBYEFIxxzJMHb9HVhmh9gjpB2UwC+JZdMBIGA1UdEwEB/wQIMAYB Af8CAQAwHwYDVR0jBBgwFoAUZc3rqzUeAD5+1XTAHLRzRw4aZC8wggFBBgNVHSAE ggE4MIIBNDCCATAGBFUdIAAwggEmMIHyBggrBgEFBQcCAjCB5R6B4gBDAGUAcgB0 AGkAZgBpAGMAYQBkAG8AIABkAGUAIABBAHUAdABvAHIAaQBkAGEAZAAgAGQAZQAg AEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4ALgAgAEMAbwBuAHMAdQBsAHQAZQAg AGwAYQBzACAAYwBvAG4AZABpAGMAaQBvAG4AZQBzACAAZABlACAAdQBzAG8AIABl AG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AZgBpAHIAbQBhAHAAcgBvAGYAZQBz AGkAbwBuAGEAbAAuAGMAbwBtAC8AYwBwAHMwLwYIKwYBBQUHAgEWI2h0dHA6Ly93 d3cuZmlybWFwcm9mZXNpb25hbC5jb20vY3BzMDsGA1UdHwQ0MDIwMKAuoCyGKmh0 dHA6Ly9jcmwuZmlybWFwcm9mZXNpb25hbC5jb20vZnByb290LmNybDAOBgNVHQ8B Af8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAApS6836yufcnOXxNmxxa80WO3iN TO/xiF1sQH3GfUhNKK9x7QAl2MLTM0FvZ8ZZ23RlLkCnSrYCVI5AJCBvAoE3fxqd V7Q0a45DH7/DNyzTvOEnyUGHsdWCzCSM/XQdi1+fquLny+Dt7q9YkqzHNczOVIGg 9DOPvXHXUWsSc+06I3hM7YNDsJD4hlvo68NEYPVlo4+uN4k+3edfEA9yRCGoDhNl zh1FLQBHZ3Wis9OVH+9xl6oYhYGNzESGYOIewpxLflbF6LdyACipm8ywAZg+NRgd DU4ty/+ddP+oBuiRnuzLZZI9zfylC0DQYElcC69LKQ5jc32oAN/k0m5V35VKqdEc 2JULn0zlTDznp1anr/ulTu6sOLChb7LOhGZjI1BawkMAmZR+2dr1hdVRNJ/hnBhl mspb/o7wI9rzoBYlMpqGIxHBzpVVJhhO5g1YXqq3X12oSL27xY6LS1/8fqwfYLov VOzeegr2SgBNDk7MoIjTJJxoCNG39d+htjTHVeeEzp3z+Oc8HlU0Gf98+OnfjO9T zGAz1PijqXa77m3Iu982gsaJH8qK5DyxGFyMN5CaNq23p/5g/ATzFrTOf++jp85+ MBaQeDT/zC0rq44ewVc2TcxCN6GbieepMDk67nS1HSKCZJE/e29hKuGJp3kd1PO1 WHlC29XOaKRjmyDC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGtzCCBJ+gAwIBAgIQAPodqurJs6X6V5gLmXTaMTANBgkqhkiG9w0BAQsFADBF MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT d2lzc1NpZ24gR29sZCBDQSAtIEcyMB4XDTE0MDkxOTE0MDkxMloXDTI5MDkxNTE0 MDkxMlowUjELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEsMCoG A1UEAxMjU3dpc3NTaWduIFNlcnZlciBHb2xkIENBIDIwMTQgLSBHMjIwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQzxIi30mNQL6Fa6afsl9Fs7it1XQS fLb+T3omoxS2IJiUNVCoyMeBEVSFB2a0tEUnyOjfcSn++++pWoAOkU5wWp7bbNo4 yq/T5LBg1HcuPm+wH94V4IwAFFatfZIIrmaTfVRzrZ26CrEM2vISb/1u2SVzAnmP WoY3JVGbDOXw5HEpI6W/zLnd6cetY/ZPwp/9UICzCQxD5PmPiSP18dhTnm8LP4G/ go5VK5JQu52NvH9iStYs9VVXvHiq7+1RdkQa72CmB9wx6MmXqv3MAde/tt03L9o5 uB6VPx2uJQ6G0S+gpyqwKbeUBhJxBZNRRftXyXnZxg48ZBYb26tiPfTVAgMBAAGj ggKUMIICkDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HQ4EFgQU5/Hn/S5TrRHlgRpXpHOPEn2YyK4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 OfPAeGZe6Drn8O4wgf8GA1UdHwSB9zCB9DBHoEWgQ4ZBaHR0cDovL2NybC5zd2lz c3NpZ24ubmV0LzVCMjU3Qjk2QTQ2NTUxN0VCODM5RjNDMDc4NjY1RUU4M0FFN0Yw RUUwgaiggaWggaKGgZ9sZGFwOi8vZGlyZWN0b3J5LnN3aXNzc2lnbi5uZXQvQ049 NUIyNTdCOTZBNDY1NTE3RUI4MzlGM0MwNzg2NjVFRTgzQUU3RjBFRSUyQ089U3dp c3NTaWduJTJDQz1DSD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2Jq ZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwXwYDVR0gBFgwVjBUBglghXQB WQECAQYwRzBFBggrBgEFBQcCARY5aHR0cDovL3JlcG9zaXRvcnkuc3dpc3NzaWdu LmNvbS9Td2lzc1NpZ24tR29sZC1DUC1DUFMucGRmMIHGBggrBgEFBQcBAQSBuTCB tjBkBggrBgEFBQcwAoZYaHR0cDovL3N3aXNzc2lnbi5uZXQvY2dpLWJpbi9hdXRo b3JpdHkvZG93bmxvYWQvNUIyNTdCOTZBNDY1NTE3RUI4MzlGM0MwNzg2NjVFRTgz QUU3RjBFRTBOBggrBgEFBQcwAYZCaHR0cDovL29jc3Auc3dpc3NzaWduLm5ldC81 QjI1N0I5NkE0NjU1MTdFQjgzOUYzQzA3ODY2NUVFODNBRTdGMEVFMA0GCSqGSIb3 DQEBCwUAA4ICAQCOLN7o1oxUHESHOxMtyaF0+Mehvb5xp+4BL9kuUI7GQdY9HiGZ YLSVhQ+gzKK0/TpxZksZ3klVUpyjqmBZruaTWhd5p0K4hTECK6g3zNG7zDkAR9ZZ S+O991u0FlqASfWNWKc1n6J4Lu/wyGv72NuqNA/SbGscP4+fOX8yelJ2KFONxQNI jftNyHX8lmlUj2YAh49yiWkPY1tsFfKKzqNJlTEIEFkJkOIM7wVRIPgRu23jhlpa jCIayCarJ41gn/UHXVgo4oDmrIA1aE9F2prtHWn+Yd8vtQkixPwJroq1Y0na76WS j7xnQxSEr7/aXUjPn498Pw3iD+76Vub8nislsEFYjn21pXOWGjr5PciCqdivV5kf HWo+p6isSu5hW6lkEzKa9bEKZsiUF4NzZeobDegyer8TYXkEDP91oD1iDum0i87k sljy3pKPKr4Aa5HEDof4Kn2ZWckemrbJwVVxHddoQ3LU004zZUjSAfmmhwcPymCk CnSXAtLkS8Fz40wHvB1HgpBLLu/ds9gmupv3o4ZPlgbYfQelIKes4Vtg8x/23scU bv4vuScmpyzbjYrqhAmGafUoCbamKTv/1KfIcTHJrWV8eakrrqI8aSkmcY5jBSyg IZ+muisznpeXBNZI4fJM/jFJF9W4jqLysCU9w9aDacEsRSLeSVUkc1TN7g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGuDCCBKCgAwIBAgIPGReV3CJ0GxId21RMXMvcMA0GCSqGSIb3DQEBCwUAMEUx CzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3 aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcNMTQwOTE5MTQxMDI1WhcNMjkwOTE1MTQx MDI1WjBUMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMS4wLAYD VQQDEyVTd2lzc1NpZ24gUGVyc29uYWwgR29sZCBDQSAyMDE0IC0gRzIyMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnrf0T2JFsx4NPb+TUBInPgv9nUyF 9dMJh7sQL66HybrB2devqNc1+Gq+fFT4tfBa9hbI+xqRRqCO0LoQOJ3v3XMlOzQ3 zTL+b3wgDvs/d8tZ7LWGOSYF480/rL1aaBIQFlrE62GDQvcmkH/C8QxsSS+T+ga2 FQhC/Br/btveNcP6cz87WyshF8IU/7sOKYqh3o5mbxI641R1u3+zaiGq8A9620pS oW3b9P1Mf5t4z51ifqb+/QsYtDt60dw+mVES6sk8cl9VRLejcuiXFyVJaj7YyITi or33buzheHvzZdxaQSgeq0mIrvmXqtplZoqXQ12irR7xhuf/w9UtFBbqCwIDAQAB o4IClDCCApAwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD VR0OBBYEFNoy+Un4UcyYcWYM2c6225I/CUvvMB8GA1UdIwQYMBaAFFsle5akZVF+ uDnzwHhmXug65/DuMIH/BgNVHR8EgfcwgfQwR6BFoEOGQWh0dHA6Ly9jcmwuc3dp c3NzaWduLm5ldC81QjI1N0I5NkE0NjU1MTdFQjgzOUYzQzA3ODY2NUVFODNBRTdG MEVFMIGooIGloIGihoGfbGRhcDovL2RpcmVjdG9yeS5zd2lzc3NpZ24ubmV0L0NO PTVCMjU3Qjk2QTQ2NTUxN0VCODM5RjNDMDc4NjY1RUU4M0FFN0YwRUUlMkNPPVN3 aXNzU2lnbiUyQ0M9Q0g/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29i amVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MF8GA1UdIARYMFYwVAYJYIV0 AVkBAgEGMEcwRQYIKwYBBQUHAgEWOWh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2ln bi5jb20vU3dpc3NTaWduLUdvbGQtQ1AtQ1BTLnBkZjCBxgYIKwYBBQUHAQEEgbkw gbYwZAYIKwYBBQUHMAKGWGh0dHA6Ly9zd2lzc3NpZ24ubmV0L2NnaS1iaW4vYXV0 aG9yaXR5L2Rvd25sb2FkLzVCMjU3Qjk2QTQ2NTUxN0VCODM5RjNDMDc4NjY1RUU4 M0FFN0YwRUUwTgYIKwYBBQUHMAGGQmh0dHA6Ly9vY3NwLnN3aXNzc2lnbi5uZXQv NUIyNTdCOTZBNDY1NTE3RUI4MzlGM0MwNzg2NjVFRTgzQUU3RjBFRTANBgkqhkiG 9w0BAQsFAAOCAgEArevbqCOPH6va0x4oEb4UviyXJzIokl5MjRADlGMDFXaKm52m U+IZlJ9PjcqBiEXhjjD1oR8uV5aVRWXH+auI6JgQZz5L+u2a309bDu3bcineP45v Z+nAuoDvulmx2nqjloCOturaks727w/nHCoz723eYH46fg//q/a5QnOoBe+WIiZW T71TcycX4hiVcPwVqB53tL9IM2qe2balnCpZKorZWVHQXYWSO5MIBaw/iMOwCCpf lDRU75TruHPjfE4Bu4U9Nm3NBt3zcc5ykcQ8ZbJzkWLnSi2LY8r71Ulc3jxqyWOZ QbgS14x/BzVQj4Rk9+X8KovGpooAFVIBR/bdU/z2IdZlENgoPNpJokuEH5OS6UZS yNmhhXjI2QGXn91G+QV4++kreVz6heVOhDPgOoOfRXLYG9O/9wqPMthmUQgcTrym p57bPpM0zIYpHxcKfxhoYprQdO3LuU1F2xkZE2vFLWVB9ugHzXd1ADIKrrGgJXPf MluXT9wK8BzTcI5cOqhESt4Awq5q9fmiW3OUAROL0Ca0Z/sRQcvvJ/ewlZvLdsym cfjV6JtN7/IBgIJ4D/Js4DRWCwAv1jhBiEGsRAlhiJmep//U1HEaT9oredt9PYS1 iKbkcMuDEtPuYXrQ+8OQmMEwMbOFboZMMTOVNOenLH+EiG6BUnowTwqqjtA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGvDCCBKSgAwIBAgIPa8MYySrNF2PrQchvr0f3MA0GCSqGSIb3DQEBCwUAMEcx CzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxITAfBgNVBAMTGFN3 aXNzU2lnbiBTaWx2ZXIgQ0EgLSBHMjAeFw0xNDA5MTkyMDM2NDNaFw0yOTA5MTUy MDM2NDNaMFQxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxLjAs BgNVBAMTJVN3aXNzU2lnbiBTZXJ2ZXIgU2lsdmVyIENBIDIwMTQgLSBHMjIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDokwjmGAGzVxkPTD8FLdUerBu4 nCwsqp+VK5g3NYSeSAOBGTPoY/YueIkgmjvIfBov2rjhOl5a7oOX2ymM8/hv/99n DxLgi6X6N2+B1MgKcQ0/3KZW5NOI8Ym46nZOjGt3mdMYNf9ORWTXIYLY7skjbLxD qXS6FvrcQrR8A6y5btxyD6jk9KXFpfqHRL9ZdbeBRyPLmOUOHdMqu/8xk6UBeyFo jXRA5wXNZyNkoDvzujGjozOvvWrNYUCyjCoFbrpX/vORJAc8bUONzYWNnm4cFfi7 TG7yKcUkSBp5i16q3G1emHNEDiscX05LlCYVeo/WOriSthL7Q03FJEMO6D5FAgMB AAGjggKWMIICkjAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAd BgNVHQ4EFgQU27y/ghhZ3Gn6+Kuqg013HQuwi9gwHwYDVR0jBBgwFoAUF6DNweRB tjpbO8tFnb0cwpj6hlgwgf8GA1UdHwSB9zCB9DBHoEWgQ4ZBaHR0cDovL2NybC5z d2lzc3NpZ24ubmV0LzE3QTBDREMxRTQ0MUI2M0E1QjNCQ0I0NTlEQkQxQ0MyOThG QTg2NTgwgaiggaWggaKGgZ9sZGFwOi8vZGlyZWN0b3J5LnN3aXNzc2lnbi5uZXQv Q049MTdBMENEQzFFNDQxQjYzQTVCM0JDQjQ1OURCRDFDQzI5OEZBODY1OCUyQ089 U3dpc3NTaWduJTJDQz1DSD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/ b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwYQYDVR0gBFowWDBWBglg hXQBWQEDAQYwSTBHBggrBgEFBQcCARY7aHR0cDovL3JlcG9zaXRvcnkuc3dpc3Nz aWduLmNvbS9Td2lzc1NpZ24tU2lsdmVyLUNQLUNQUy5wZGYwgcYGCCsGAQUFBwEB BIG5MIG2MGQGCCsGAQUFBzAChlhodHRwOi8vc3dpc3NzaWduLm5ldC9jZ2ktYmlu L2F1dGhvcml0eS9kb3dubG9hZC8xN0EwQ0RDMUU0NDFCNjNBNUIzQkNCNDU5REJE MUNDMjk4RkE4NjU4ME4GCCsGAQUFBzABhkJodHRwOi8vb2NzcC5zd2lzc3NpZ24u bmV0LzE3QTBDREMxRTQ0MUI2M0E1QjNCQ0I0NTlEQkQxQ0MyOThGQTg2NTgwDQYJ KoZIhvcNAQELBQADggIBAL9A6sPv+erbRxhzA79b9B8tUFy6cggOHqHHzxDnsFbC UIL98ajLjHdV7+HfKNkNkXxhqIXvbG9Ak2CmF1x1dJtWiWmGRir7BstpcqoAI4Se P2rwGcarCCbrHmpey+5OvdCaPFMJLO1tk/0vukIGMd/dUiceIFN5RLgatbBtgDo9 NKl/GCZE4Ltyz95yILLU4FHUR+VEA/LjEnP/3M+JqoqnvQ77DYmWPVLRGkwKizFQ Xz/1/lYeNr/0WMpPpyvEAA7iMpP2bB1yGr5K8KPnCY82Lqnb3yB2BKIg+gbj4QNQ ifybp+gCu/IYWWWfVHVAqYQurGYBai7wYvYCVedhqRAl/Xh5ny3CiWpKNrce09X9 u/N3kBefCMH2HEipgJAx+2t66Qw+4H70TV/nJoB3w9eTukKRqpDNebdYBR325QHI fiQMc4hs12TLDmpL3tAGdpsKx3/jBfz4qLrr36ZPNO0ost6OCyJH5rsn/ctq6Noc OjMTfJLqZXP8DKVSYRCRxFesNxQXRROx1HfGJus0gB/x30A3c2L6IvKOV+qQgidf vTy3FMK1j4toytXiaafI+Caus+GbmDMCtsEQiwxsNS4HZCVXZXGr84lsfK55CNg8 84npHRtOijniyemc9gsTkT50zf8MkhmSdXo2MJuP2rX7A/WuV2FikJw+O4jRYWeI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGvjCCBKagAwIBAgIPBUTWTq0e0zbVMkBdALk2MA0GCSqGSIb3DQEBCwUAMEcx CzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxITAfBgNVBAMTGFN3 aXNzU2lnbiBTaWx2ZXIgQ0EgLSBHMjAeFw0xNDA5MTkyMDM2NDlaFw0yOTA5MTUy MDM2NDlaMFYxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxMDAu BgNVBAMTJ1N3aXNzU2lnbiBQZXJzb25hbCBTaWx2ZXIgQ0EgMjAxNCAtIEcyMjCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMs5sTmF/vrJobzDg6kOSi2E ch7/aMWnxB3sD9eoixMes9EWi0DcD1NvAT3s6GS1l9uDvKiowIQ4WF4DFCvmyjDv ALLrEzkZkkcqIQDlcs3CMWIOzFYq/3fEY4yYwm9417W2zOl9HzOmkQUq/tFS1vTs nP5NTGpS4YV2Yru5aOZSY/zBIZGSXRnY3IDRGeNJFlcCDhlEhaspyS/6xm1rCqH2 9/9rYTUVJpSUAmklXWn3vV5rgtmQDAb5QwUiSes20CBaYxDjOCHVfxYrQYpGevJn 6KTQuh5/JCd1mJRJLVbEVDORnWL51V/eW6kVmJyUU8GA6QkXFbQbgCkyodCvE6cC AwEAAaOCApYwggKSMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MB0GA1UdDgQWBBTwx6MykbXryrVYdxWnTr4aXWFDJTAfBgNVHSMEGDAWgBQXoM3B 5EG2Ols7y0WdvRzCmPqGWDCB/wYDVR0fBIH3MIH0MEegRaBDhkFodHRwOi8vY3Js LnN3aXNzc2lnbi5uZXQvMTdBMENEQzFFNDQxQjYzQTVCM0JDQjQ1OURCRDFDQzI5 OEZBODY1ODCBqKCBpaCBooaBn2xkYXA6Ly9kaXJlY3Rvcnkuc3dpc3NzaWduLm5l dC9DTj0xN0EwQ0RDMUU0NDFCNjNBNUIzQkNCNDU5REJEMUNDMjk4RkE4NjU4JTJD Tz1Td2lzc1NpZ24lMkNDPUNIP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFz ZT9vYmplY3RDbGFzcz1jUkxEaXN0cmlidXRpb25Qb2ludDBhBgNVHSAEWjBYMFYG CWCFdAFZAQMBBjBJMEcGCCsGAQUFBwIBFjtodHRwOi8vcmVwb3NpdG9yeS5zd2lz c3NpZ24uY29tL1N3aXNzU2lnbi1TaWx2ZXItQ1AtQ1BTLnBkZjCBxgYIKwYBBQUH AQEEgbkwgbYwZAYIKwYBBQUHMAKGWGh0dHA6Ly9zd2lzc3NpZ24ubmV0L2NnaS1i aW4vYXV0aG9yaXR5L2Rvd25sb2FkLzE3QTBDREMxRTQ0MUI2M0E1QjNCQ0I0NTlE QkQxQ0MyOThGQTg2NTgwTgYIKwYBBQUHMAGGQmh0dHA6Ly9vY3NwLnN3aXNzc2ln bi5uZXQvMTdBMENEQzFFNDQxQjYzQTVCM0JDQjQ1OURCRDFDQzI5OEZBODY1ODAN BgkqhkiG9w0BAQsFAAOCAgEAw3mnV7d7rVFo9USMQZUoAXx01jtqvG3vp9dNOZkd aI3KCNnQcbEZNZNvgsYcSbhR7kz5bApv2KX7/vswXgDSlKvEElG6qoqrat0Z1ytK 9xaya1HPdFsponPel/7YTyAhfWkMsFDljViMgC7lFxzdY3qq7wX5w2me5IxxYlxC 7jryzeAS74tc6c5TKDLslQsZVKIhjfp/UKdPvBl7smuMKT93Psojx2laQZ19ZjFv enF52qllOut/1xDVC19UGXzONyUkhFDQr0A0wl+S4nqR8y9CRxufPEL72V+lvHBF ju+gOZD1oXhs18BnWRnhAN5c/HjoT927rJEucov86kdvQyi8u7mOlL76UN1QkxtM GLZ2/8NHClm0zW1V2Gq2X8kvwZQ2Pr6uQDUGIO3gAkwtNEUOQ6+i9NiQFeXQwJtE QK48j5NRvJloc2l7dViZt9QET9/xgnERHXv8Ex13ZVVj11JyfN0xR4anldisJnE9 I+YSO/R/mpaG/ivqoPMmDXXGFowxIOcRR6HnqWqwpbKBHtw90KHjbtXwZqYcfdeS iE0ABwtx53Pnc+RUZWn8N43xHm9w7qdss1JFZ1nWBUixIemXKNnZ9LSmoGcjNrxg Rw5cKH9dk4oxuo0xNhTHekKdbyDBbCr4Fg9q2QCUMrs9VbHFw6ENsXl3VB3gM4J+ 7uo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF 6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV 1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR 5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFMDCCBBigAwIBAgIQVI57oMAwxl2+UxycNi8vbDANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp dHkwHhcNMTQwOTI0MDAwMDAwWhcNMjkxMjMxMjM1OTU5WjB6MQswCQYDVQQGEwJV UzELMAkGA1UECBMCVkExEDAOBgNVBAcTB0hlcm5kb24xITAfBgNVBAoTGE5ldHdv cmsgU29sdXRpb25zIEwuTC5DLjEpMCcGA1UEAxMgTmV0d29yayBTb2x1dGlvbnMg RVYgU2VydmVyIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1 tb9bgjM9hDin3vD49SgUR7Q642a6GuH7I8ewK0K9yT+4W3m1sbbx+aPlVQOAdsMQ w5M5r3O97j4wOTsSInT+DC0Djl8gK7cQjSniowzz+NDoIvZxGHE+23ZSx7HxxXoC SvxhU2mONCChJdVNuWoMcF4N2stLlgIxpSx2kU+5kNHV/bvvfDrsPsQbWsjzFH7M mOIMngesKZLc/fPrJ5X/bckRQ/4LItWfeCylruhQvgLU1MgKoBKpBiaBTmnGnRLp YpArMobxA/OBmnOUHXmYyD5NBjcqfMQwM0i3JhJAln7FnH39AFYKKo6SPQMpsW8e hGfJJItxGicPRurtl7/DAgMBAAGjggHIMIIBxDAfBgNVHSMEGDAWgBQhMMn7ANdO mNqHqirQpy6xQDGnTDAdBgNVHQ4EFgQUjzdKhJz0jsdmlpC0ro+6XqIWqsQwDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMGYGA1UdIARfMF0wWwYEVR0gADBTMFEGCCsGAQUFBwIB FkVodHRwOi8vd3d3Lm5ldHdvcmtzb2x1dGlvbnMuY29tL2xlZ2FsL1NTTC1sZWdh bC1yZXBvc2l0b3J5LWV2LWNwcy5qc3AwUgYDVR0fBEswSTBHoEWgQ4ZBaHR0cDov L2NybC5uZXRzb2xzc2wuY29tL05ldHdvcmtTb2x1dGlvbnNDZXJ0aWZpY2F0ZUF1 dGhvcml0eS5jcmwwgYIGCCsGAQUFBwEBBHYwdDBLBggrBgEFBQcwAoY/aHR0cDov L2NydC51c2VydHJ1c3QuY29tL05ldHdvcmtTb2x1dGlvbnNBZGRUcnVzdEVWU2Vy dmVyQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC5uZXRzb2xzc2wuY29t MA0GCSqGSIb3DQEBDAUAA4IBAQAAuteVfjzepFk9ZHEDVw7b8r+ZPUHC5wKENQXf 8v2pM0SP0VOWrCf3EPu+wmT/m4DVOZpMJyzF3HYcvS7EemtGaBHa5IN9LpyAzT27 hnIM19CS79484wN6K5/zO0nwvabWbQWazzY7kCToyiNay4kadJ95RryTQQ3uhtI2 2w4lozyqdXmcbnNbeiA+CLsTSPCQk/ZYWWs1gKxLBGUk5OkkzDnulwzkBYmsU0pj 27Ms47nUJZbfEI0tlJU8HVzQcrlQRGkUhI1drtC6kyNtfJHcE7iHHBs1l6fLpjzx IpOnYE4BOnawVyDCBmqL32vHIzFlY8cJJyhbKbUjMTea2DkB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnzCCAyWgAwIBAgIQWyXOaQfEJlVm0zkMmalUrTAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwOTI1MDAw MDAwWhcNMjkwOTI0MjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N T0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBFQ0MgRG9tYWluIFZhbGlk YXRpb24gU2VjdXJlIFNlcnZlciBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD QgAEAjgZgTrJaYRwWQKOqIofMN+83gP8eR06JSxrQSEYgur5PkrkM8wSzypD/A7y ZADA4SVQgiTNtkk4DyVHkUikraOCAWYwggFiMB8GA1UdIwQYMBaAFHVxpxlIGbyd nepBR9+UxEh3mdN5MB0GA1UdDgQWBBRACWFn8LyDcU/eEggsb9TUK3Y9ljAOBgNV HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgGBmeBDAECATBMBgNV HR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9FQ0ND ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDByBggrBgEFBQcBAQRmMGQwOwYIKwYB BQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET0VDQ0FkZFRydXN0 Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC5jb21vZG9jYTQuY29tMAoG CCqGSM49BAMDA2gAMGUCMQCsaEclgBNPE1bAojcJl1pQxOfttGHLKIoKETKm4nHf EQGJbwd6IGZrGNC5LkP3Um8CMBKFfI4TZpIEuppFCZRKMGHRSdxv6+ctyYnPHmp8 7IXOMCVZuoFwNLg0f+cB0eLLUg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCzCCA/OgAwIBAgIQC6LQHcvLd3borGUJesElQTANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwOTI1 MDAwMDAwWhcNMjkwOTI0MjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRG9tYWluIFZh bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAu6tLGm5b8m2eTAtPlWDJzV8bcpcw8w/ttjVKAXWd9ObtFQ4T tIjyVhHirwfhPCEoYLhePcwJW9SVwMIsj9Ox+HMD1LTm1gbelT9A3OprIxgzxu// HH1hUryAK1ngv8Vrw+T5cmcOfMOGmqDWxykFCpQSi3UX3d0KZ53vcAdogXIBHIp6 6UuWiec9CN969AGX4mo8/9kKZvSaOxP6JXbMnlxVajvGposEPpI8iZAlXSEUTYIh eUyzwuNwH8+nXBg7mwzhcoKD0BV8wRNyjcYfAOnP16vm0InwIEUvElOdqvisVUvN WrusXglfS8/YZ5Bsj4Okjrrthv7ZUKDejwegdwIDAQABo4IBZjCCAWIwHwYDVR0j BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFNSw9P1PnEKkbNw9 Lu5bQRjJrQP2MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw CAYGZ4EMAQIBMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2Eu Y29tL0NPTU9ET1JTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHIGCCsGAQUF BwEBBGYwZDA7BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09N T0RPUlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLmNv bW9kb2NhNC5jb20wDQYJKoZIhvcNAQEMBQADggIBABAXFDLLULq2T67ml0Ts3U/u K1VCkUf7pl3eEzOuEP0fi96xs7NWVkV3yI1Mwy3lg21BiTxwlbNX5wbejsLIItTn 3vGd05nJ8/cz58uPmWghDdgIrxON3Jl57RrFHJ0oebUbBPE5m9O4ELYavy9Su8p1 9wyHraEFbVVzT8KDlJlDjNM62s2jbt+h8i0RqT0mc89XYxEjLYS6gWZMb2u7ITqI XR/70gq2P5FCF7SiAialW1Bnso6TzTZzgr9G0fMoAeFqZynC+Bf3R+2llm+8CuG9 iym+q7cylcUCsGU+Nb1n2An9vjBYE1X1m1NbAW5Fx9KlK8bP0I4w/DGpFZbHl+fJ ZGm9jL7qfJCjWBp/Sau7UAkfCDA2AWAOsiCaVCn2WDWadIdfb2JrSI+y3MUZremV bMRtilVoZmUWjcF6d2u438kgscUf1nfZxA7NvRrpH4dFrAC13a6pYYHiTVlRdXCE IvFAUyYdBCmqvpdccsKcsvrK9Tl0JXufmOtAmqP/Z6yCHzxORVjc8WDbH1eUNHWB 5AJfvNk6sAYJ5+9iWZpd8wEbnWVw/yZFTliDcpD1QOsWIdWKjBPSM0fof+mkQAzM VSWsErokodPYflsJTHKqRxY3lGqroH0bakT2GdD8REw8IN4D3CJ5JaqpAYVWgc+9 7O7lc82QVOgklrnwCqD3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGAjCCA+qgAwIBAgIRCBeSUjZo9chQAAAAAAAAAAMwDQYJKoZIhvcNAQELBQAw UjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRp c2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIwHhcNMTQxMDAyMTIx OTA2WhcNMjkwOTI4MTIxOTA2WjBlMQswCQYDVQQGEwJTSzETMBEGA1UEBwwKQnJh dGlzbGF2YTETMBEGA1UECgwKRGlzaWcgYS5zLjEsMCoGA1UEAwwjQ0EgRGlzaWcg UjJJMiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCyUskVGBrkooW8zWUYsR8WKNA5baWkD6PKuMXL3mi9lt/u0W1J 5b2FIjtWJt6PBZlMGcnzCQSEC8Ao/9HZQQwwAttLgmcdBSwyIenDMuxiM1WbnZ+5 kmUnKjHs+LaROq3vBCIzdGDQGoJACEFsJuFpDGQXrVDtlzhhRlmM0bsyJRJwp6iL 31OCnGBz/sj5/rugnWFB9XNwUSFcafzTLwlo8OI/gIhhXQSdk8WjrFvQdG1TiqkI ojm9Mz5a6pzfN9NncZbGV4Xa1cV/oMG4fZAqu7+X7tlVPPDF3/7UKzSRGydrShWc 4tPOORPevcT6/XQnpqGrB89sxvtkm2lCsvrDAgMBAAGjggG+MIIBujCBgwYIKwYB BQUHAQEEdzB1MDcGCCsGAQUFBzABhitodHRwOi8vcm9vdGNhcjItb2NzcC5kaXNp Zy5zay9vY3NwL3Jvb3RjYXIyMDoGCCsGAQUFBzAChi5odHRwOi8vd3d3LmRpc2ln LnNrL3Jvb3RjYXIyL2NlcnQvcm9vdGNhcjIuZGVyMB0GA1UdDgQWBBQkpbw6KGIV QjL5MFrJ8T7koQmosTAfBgNVHSMEGDAWgBS1mfivsJT14yDWCq3OTlakLm5C7TAS BgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjB1BgNVHR8EbjBsMDSg MqAwhi5odHRwOi8vY2RwMS5kaXNpZy5zay9yb290Y2FyMi9jcmwvcm9vdGNhcjIu Y3JsMDSgMqAwhi5odHRwOi8vY2RwMi5kaXNpZy5zay9yb290Y2FyMi9jcmwvcm9v dGNhcjIuY3JsMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw Oi8vd3d3LmRpc2lnLnNrL2Nwcy8wHAYDVR0RBBUwE4ERc3ByYXZhY2FAZGlzaWcu c2swDQYJKoZIhvcNAQELBQADggIBAEoFQYsKbtRjEdbWeqZHhJF8cRcg66HUY0zD OksWZpGzTOL7K7PGaJVRrMxIiIiG3hFU/CYWQlVk3NjiUo1T3m02TgkWfcXsyEZ2 MVXpImSl5fgsDfI/5/INCGh39YkN5Y91yE0bDrJUa/uTadpS3fd4vKzmhy5qRsl2 QFt29QDu7p/NUi5rojns1fCqzPserZyvciAG/hYS8t4C3GIOK2rwn09nZK+du5Gq uSX89KaVKM6UySqT+jIXzyhTwnXbEabFGSMVlmW/fKlGGLhET6jYPUnGje/b0qPv GmuvYpNC7ztCHcnNdfGLpB4L6Puxtn5xcYTswh1D8raQvArDFoqPwOQr2XggqU+t 0ktu6IKIfInhB4WjGgAMr3aGyoNqKSv9Qzbh8vkdIe7+lwIBievK/+04q+Fsi5JB zTAUumLQZhS9eXd+065GF/0O90D5fS0Y5Wc7naMQ7/o9T+9hIxC4BIm+2g0KtL43 SPF+jdqrLjUfe7/mWyZIvEKqlk6X6CUjRx9fVc01uO5gUyLHMSoWAtIyGBtmDUVC 7exu4q8BHUDMQdrZyhJOJ9TbN2Xi+z8BhpqosGPe7UTtRB3/UmMsbEgbfIIb5mMw nx6TtnF5r+FLiew8BeQcD7+7768rw0+LaddwiKlmGBjYvNy+e1cSlJl1ZBXtHzlj 57JOD9u0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGAjCCA+qgAwIBAgIRCKI5W6cDr/2sAAAAAAAAAAQwDQYJKoZIhvcNAQELBQAw UjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRp c2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIwHhcNMTQxMDAyMTIy NTE5WhcNMjkwOTI4MTIyNTE5WjBlMQswCQYDVQQGEwJTSzETMBEGA1UEBwwKQnJh dGlzbGF2YTETMBEGA1UECgwKRGlzaWcgYS5zLjEsMCoGA1UEAwwjQ0EgRGlzaWcg UjJJMyBDZXJ0aWZpY2F0aW9uIFNlcnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQC2c8BJaaP1Qhlr6ohEe73Ji8HuJwuHFNZUESykJhsbUeZF6fMB 8V8Q/3YOo/fLpSt1NlYf2o4F8XhZ5bTDEwmk4d+uoskZBSEqf3O57fOuLXXu/DY2 bTM9cGSDhlFdVHdvfoN7b7H/aGtmc/EgyChZdBAmYIPGN2WOSOlasKF2R+SKjH7E b9iX7MdXgXYUKc/peFoz+4Ba+Z/34w9ks1yqTMqsaUee6NATS4rjlGRrAVP06iat 1fgd06ebmdZUbRQ6WdVGyN5muypx+nmpzqHcAnY3efR+1nmWW4mvgu8m7f6YPGek Svh6qHbMQcSOWlgxJAjJZWA02OYh7pPDCKLrAgMBAAGjggG+MIIBujCBgwYIKwYB BQUHAQEEdzB1MDcGCCsGAQUFBzABhitodHRwOi8vcm9vdGNhcjItb2NzcC5kaXNp Zy5zay9vY3NwL3Jvb3RjYXIyMDoGCCsGAQUFBzAChi5odHRwOi8vd3d3LmRpc2ln LnNrL3Jvb3RjYXIyL2NlcnQvcm9vdGNhcjIuZGVyMB0GA1UdDgQWBBSMURytxo/S 7d4sVEDpSslyA8/otjAfBgNVHSMEGDAWgBS1mfivsJT14yDWCq3OTlakLm5C7TAS BgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjB1BgNVHR8EbjBsMDSg MqAwhi5odHRwOi8vY2RwMS5kaXNpZy5zay9yb290Y2FyMi9jcmwvcm9vdGNhcjIu Y3JsMDSgMqAwhi5odHRwOi8vY2RwMi5kaXNpZy5zay9yb290Y2FyMi9jcmwvcm9v dGNhcjIuY3JsMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw Oi8vd3d3LmRpc2lnLnNrL2Nwcy8wHAYDVR0RBBUwE4ERc3ByYXZhY2FAZGlzaWcu c2swDQYJKoZIhvcNAQELBQADggIBAIisFys6Vr64MtyHl4o70cS41eOEPdZa/6vo ZCn3K2zdMX9ccBw5be9DswNVbL5aTrZOfVYEyA24QTrauM10E2MhjHuceeqXU8Sm GFesgmzbqFGLXkysvru3g4tK+DomogKSiGYbl2dEJRQCenNJ1zrT2artrsCp9JjQ NdzY5FV0RltVqHxdOkL4J290m1qxMatKM3jLkMEzrWFgvNq46lifc5Jzw9eAIMvG v6NhH0lPlhOw+C+rnUK93F9V5wtVyfHv1BSYjE2ZU9zUdcdQDQWDf1b4cJ3r79AH 27BUSsfJhaUuuGnYFWS5o05bbchMfGTw5fGyFsES8Jrl6YWm3jbLqd8WeC4QHu5e zg+10r/C+wxopZe7QBLh/m8t70wbQqSGn/afju1pGxfNEaME+jod7f597ghZPixm 99FoRXWkKejz1XwxfkN6fC7lnpYzH37YHD20eLctBMYe9+7n0VehzfSVO29IfC1J fJll3g4Q79b1igb0s4R8Z8WC/qnO3zdWFR6pMw4aCvlo4M0aGUtculLqa2KCSRGc +2kr3b4CAQKtDc1C2t4L8UZNRAp0WQmgluAvDxd1b0umHYqaLRgmumr1WlGtO+yR 9SQkcFow0MU6vHVw4HmcyCn67NdBqPRUwGs9/u3U2OYYOL4XvBl9ly9ynp+5SIev 93IJtVKu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHHjCCBQagAwIBAgIQTEYq9tv794BPhMF8/qlytjANBgkqhkiG9w0BAQsFADA3 MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9v dCBDQSB2MTAeFw0xNDEwMTYwODA5NTdaFw0zMjEwMTYwNTA0MDBaMEYxCzAJBgNV BAYTAkZJMRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEhMB8GA1UEAwwYVGVsaWFTb25l cmEgU2VydmVyIENBIHYyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA rwQN5rfRLbVAiYWLJF9SI4YLm8oqrtf8OjGybgoLyiMIo8nhY/atuGRFWCQNOnUK caZn29C360PlC5yYrsrSHuouROisqHSJcgA7HvV+37Rcry7daeDj6rfyx4yI5dmj LwHkK0j1NzhX1JxFDgPeLNuebgzv/j8OfRhYK/BttpystC4Zgm3gZheKDjYsDS5D gjffuOysP3vewrcuw0EIZFx+HawuwNBLq4tMf4VSitYDHJSLIM2TeXZGGY5slTbT yLnrU5mIzG9WKqxyy7qHuFw1JtlAXkCLmUEVaF9M+dRPiGIjlDrpBgbDD9mT2CSk V/XG1696/voY5xB8KNIC1cOSmSO7kdJyR5tWiDIJiwMXrTwG+kZiqlbcKDsZeJ9p 5bZxXO0pEpde3wgEYRvFr5Cx4vcz4h5pom9coJOCW9tqXU43KcueTrt4Ks9f92q1 ehjyEnCh0BCdrjUOXsUtFosm9qxJnDwVlThYhS9EHuCTNBgj1Yxj6A+8fwwJP9DN CbWQx5afT+h+9FNDNRC/nEcesP1Yh9s15Se270pQW0CejUNziYG7Dft7T+PVH/fU zaWU8g0tJjtuQgiCWVqw4WkUmYY2S0R89zAotcpz2mvNO8ma2iJbubHi3c0ULfHH nkWKsdpzZmK4N0Wi6/V5yWdmL5RFkFecL8r7+9OtCB0CAwEAAaOCAhUwggIRMIGK BggrBgEFBQcBAQR+MHwwLQYIKwYBBQUHMAGGIWh0dHA6Ly9vY3NwLnRydXN0LnRl bGlhc29uZXJhLmNvbTBLBggrBgEFBQcwAoY/aHR0cDovL3JlcG9zaXRvcnkudHJ1 c3QudGVsaWFzb25lcmEuY29tL3RlbGlhc29uZXJhcm9vdGNhdjEuY2VyMBIGA1Ud EwEB/wQIMAYBAf8CAQAwVQYDVR0gBE4wTDBKBgwrBgEEAYIPAgMBAQIwOjA4Bggr BgEFBQcCARYsaHR0cHM6Ly9yZXBvc2l0b3J5LnRydXN0LnRlbGlhc29uZXJhLmNv bS9DUFMwDgYDVR0PAQH/BAQDAgEGMIHGBgNVHR8Egb4wgbswQKA+oDyGOmh0dHA6 Ly9jcmwtMy50cnVzdC50ZWxpYXNvbmVyYS5jb20vdGVsaWFzb25lcmFyb290Y2F2 MS5jcmwwd6B1oHOGcWxkYXA6Ly9jcmwtMS50cnVzdC50ZWxpYXNvbmVyYS5jb20v Y249VGVsaWFTb25lcmElMjBSb290JTIwQ0ElMjB2MSxvPVRlbGlhU29uZXJhP2Nl cnRpZmljYXRlcmV2b2NhdGlvbmxpc3Q7YmluYXJ5MB0GA1UdDgQWBBQvSTwpT9cH JfnGjNVk9WY9EoMilTAfBgNVHSMEGDAWgBTwj1k4ALP1j5qWDNXr+nuqF+gTEjAN BgkqhkiG9w0BAQsFAAOCAgEAg9EVFW6ioZ2ctrX8KqvW9XPYZR01yNgqlO7pwBWf HzuBCbUdyVzumfQnU24Sce92oMtEfyuxIOmhvoXU7LpnYlH3Q29UGP5dL0D3edGz HeU6Tf8bkcOEHtnTrkd+y+rfFSDWYl9r1y993NAcrBHhroQCE53mlrO7TjXa3zDq 6LGR8T8VgvGw0IBz6mzAks0wMYB0b4uREPmWXi+m+RqG3lnpl+eBzz6YVLkxIYMq QIXJIBsu4/ybmadsfdql6E8Lo3dKVD4UG10mtd+iPbJiBiW/a9VbEe3NVKIv4H2y HqYcxDXAeUI66E3K2cjCmKoQaa0Ywt02ikZFd0v1OWNPS7YWbEJWkVR1PcPMESK9 6HKI4xhG2tJesmXjQ8q8aSx2u79Zts3ewjKqTmurf6FXW3u9TpSCUe6Drr/3X7Ve nBy4M0sLwCecD/L9gjTa+EItQTYzCkpxiMO49tQdX/BpwgWju4Kg3qkaBNTzvSlk gdnRJqCUkVuzwK4yBqUoyRz3prlhvvRGdZJKf6IXRDhncpey5pm0PQYQ4cArx7Go AaAKz0ZTHOKjnM2KIdUhBJQybL7oPklSfkeMWoUoYED6R4YMTt/JXX4ixEb5DgDJ 0F+bNcF7qGrJTkTx0Ccy4BuuY05hJckd72E7WdmjN7DDeosghgWZNV/6D7N5tfxo nlU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHIDCCBQigAwIBAgIRAIY8dWQRlYVPtDE4oKDPiqMwDQYJKoZIhvcNAQELBQAw NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv b3QgQ0EgdjEwHhcNMTQxMDE2MDgyMTIyWhcNMzIxMDE2MDUwNDAwWjBHMQswCQYD VQQGEwJGSTEUMBIGA1UECgwLVGVsaWFTb25lcmExIjAgBgNVBAMMGVRlbGlhU29u ZXJhIEdhdGV3YXkgQ0EgdjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQCO+fR8ddbObpVeG/1EgFacy3i/libBYpl3V1UK1yDv8Hhyz1NEODpxTi1nniuf qGQp0bkg0dh8BpyJpJx6xkq67Zuz19UcQTbiEWD/PcOLZBVNyL/aOYHk9E76fcdw UObXqlnBEZcgFwMnG2G1QUxiz1NQE0110d9VvV2ai4f5O1ECHXIuyCtcZUlj0agE bGEUZ4R25OfX9ZoCXvj/X55XZzYhkGdaN8Tj8pweBXwEck+GG3HNuCtQOS/nnDDy 9POBjhMagAR1SjxCB4j9IB1uatofSa+g4jOeGd4KWxuGpVH7VL+Ngn/q6MrFaOyx dfYuYVfzaOkhFUJrickK1Ckt3D+x7OTAlio1TK3+WpZtLZz7G3wdVmjd2v3Ph3Fc JIh4R2l7caPcD3xswwUVGSyniuUPfmOwRfV15Qd5MXkd/CZ+2RjErptqbhRjy8PD xdNVuc2RhsdPCy8zXLdCvTk6s7OYXBoJmaR7yYy/6mLfARGeLWt7i8s4EIsVZSkE OqOuSF8eUOrygZEcV3INvWf1/h8g+0skySQzmfosXpe9BTWiXV19E7GFvuMQoHXB 4sb2oSqt2nFHJDm9qJMNmmFKrJeZqnfaChdwSbe5AvT0y7kcesUwgyRcdf5LnW3J U9q7EXW0+FQcxnuAH5SqmZJ08MR8hkiaZ5pfcRHvN7IYFQIDAQABo4ICFTCCAhEw gYoGCCsGAQUFBwEBBH4wfDAtBggrBgEFBQcwAYYhaHR0cDovL29jc3AudHJ1c3Qu dGVsaWFzb25lcmEuY29tMEsGCCsGAQUFBzAChj9odHRwOi8vcmVwb3NpdG9yeS50 cnVzdC50ZWxpYXNvbmVyYS5jb20vdGVsaWFzb25lcmFyb290Y2F2MS5jZXIwEgYD VR0TAQH/BAgwBgEB/wIBADBVBgNVHSAETjBMMEoGDCsGAQQBgg8CAwEBAjA6MDgG CCsGAQUFBwIBFixodHRwczovL3JlcG9zaXRvcnkudHJ1c3QudGVsaWFzb25lcmEu Y29tL0NQUzAOBgNVHQ8BAf8EBAMCAQYwgcYGA1UdHwSBvjCBuzBAoD6gPIY6aHR0 cDovL2NybC0zLnRydXN0LnRlbGlhc29uZXJhLmNvbS90ZWxpYXNvbmVyYXJvb3Rj YXYxLmNybDB3oHWgc4ZxbGRhcDovL2NybC0xLnRydXN0LnRlbGlhc29uZXJhLmNv bS9jbj1UZWxpYVNvbmVyYSUyMFJvb3QlMjBDQSUyMHYxLG89VGVsaWFTb25lcmE/ Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDtiaW5hcnkwHQYDVR0OBBYEFIeq4xMS nxGLymjNHi3EKaj6EBrLMB8GA1UdIwQYMBaAFPCPWTgAs/WPmpYM1ev6e6oX6BMS MA0GCSqGSIb3DQEBCwUAA4ICAQBOoK2AoSnrz9zfD0WYiPIdv9PB1kLhcLQO1wia 1BNvmaLtWKuPa47aXu7T5dkQzBBg1j55H0WkJ/LIMy1/TIfG1Hn0FWUoR82jiiLv L9bBBl2acNbR/4tjWc9g7vshbyyZFgSa0CFzMlyfgnE0ZllJGIjeY7i53WBMF5Gx XAgKsZCpTQ07K815v7ziwEN4NxY5pP8mxfbm/M3LRTh5tDcw9phsupPQzMllh8Tq 3i8zh3BnficnplY5Es1p/X45wPMF0bZpo/7Y2JGZ9n7fmk2WqqhKrvKOB/cHO0rC AO1AfiBx7mb3wOKvA7BxtPFy3AHhj3g1V9P6BDBJEUwW+pjMMpvRl9aJwDe701X2 5bkIOYA8yNcrNn7We5s3SBMy/LEgdhTFmwBlvEPBcdXfH+6Mfwu3q0EPRrsVehsO 107XtO+kG+4xEuKtRCgHB8IT0rf54PgHm3kvuTHDR+4sCFqAa6TuJEJwdvuyWe3Z L3VpeiSxrLBxdchHk/bZXLMpDCh2cTCMnfOhnmbaLlYzw0QaLFC6zpbyUAA0H+q2 lHDZBwqug1pgoulRfsV8pheBZpnm+/eyfAfsz3Chwms2f98r3t54yh66CwCPzjRH W4DM8tiliF7XFI8L3pFAc1xJZT5w0HG+E5JDPp9GiQeWna+Bzu/wFETztyVyFWjB 5F4U/A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHIDCCBQigAwIBAgIRAP1B3X/Rnz7p+F2eQ3Ez1NswDQYJKoZIhvcNAQELBQAw NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv b3QgQ0EgdjEwHhcNMTQxMDE2MDgzMTUzWhcNMzIxMDE2MDUwNDAwWjBHMQswCQYD VQQGEwJGSTEUMBIGA1UECgwLVGVsaWFTb25lcmExIjAgBgNVBAMMGVRlbGlhU29u ZXJhIENsYXNzIDEgQ0EgdjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQC3rPcJedHv9uiDCJCKtQL6QPRS6Cqxi9N8vM5WIHNxL5jf8JkdIiPrEg6VS0OQ ThGzbfc3TaiX4MC8FU+Bi3MHLnYIZ6xqAQP76QdXLAdCDF2gopIUyhhTmYWdjW61 8dpX5wv2X/LYkHz9qArjw7rXTOXHWg4OWCefyfCYP/ATlFGe4fFR8PRHgiDZ/utt 7GRUAcIIuALB35k0RkOkkht786rxix/7fAJyB49ISmUgXCvfH+YmPtjzc3VjXoZc AgjEld7W+hLlBGVOQMN0PhDjkyCPEzvNcZFAupWs+64WwBm3cQdmzgwXGBKXSXep J76/ydGfPA85n4aT7d2eACSxNM3c5lSdntFq8QiZJxlPfsZhdgshANFIsEaKdil/ v7yQlVes3iBuabYwNzXgusYOpCFpkf02ixecB2x2qNpcAneSDtIJ7f89+Ilx3N03 IOcu5xZuGd37kmMNhEKlZiQ/uDl92IGq62RLQJc9+cEIYPCMObiDxuhY/4CGgXdS VawzJTtotQacIrnQCG5iezpH0VcZ+Up3EBSQvdLewxomHganQYXAkW+82v1xDnr7 u2MQTEegWTNOcT3jGYXKaJvs9rOq5fKmN/Ag861HUg8B8xCVLutY6ZpYWN92iJ0H HFRM9kDY2qLbwLFnDzO73oi2bjNYhXjZ1TScMQTMXt4+LwIDAQABo4ICFTCCAhEw gYoGCCsGAQUFBwEBBH4wfDAtBggrBgEFBQcwAYYhaHR0cDovL29jc3AudHJ1c3Qu dGVsaWFzb25lcmEuY29tMEsGCCsGAQUFBzAChj9odHRwOi8vcmVwb3NpdG9yeS50 cnVzdC50ZWxpYXNvbmVyYS5jb20vdGVsaWFzb25lcmFyb290Y2F2MS5jZXIwEgYD VR0TAQH/BAgwBgEB/wIBADBVBgNVHSAETjBMMEoGDCsGAQQBgg8CAwEBAjA6MDgG CCsGAQUFBwIBFixodHRwczovL3JlcG9zaXRvcnkudHJ1c3QudGVsaWFzb25lcmEu Y29tL0NQUzAOBgNVHQ8BAf8EBAMCAQYwgcYGA1UdHwSBvjCBuzBAoD6gPIY6aHR0 cDovL2NybC0zLnRydXN0LnRlbGlhc29uZXJhLmNvbS90ZWxpYXNvbmVyYXJvb3Rj YXYxLmNybDB3oHWgc4ZxbGRhcDovL2NybC0xLnRydXN0LnRlbGlhc29uZXJhLmNv bS9jbj1UZWxpYVNvbmVyYSUyMFJvb3QlMjBDQSUyMHYxLG89VGVsaWFTb25lcmE/ Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDtiaW5hcnkwHQYDVR0OBBYEFNFHIo/L qF0a/iZBRm7LgktlfYrkMB8GA1UdIwQYMBaAFPCPWTgAs/WPmpYM1ev6e6oX6BMS MA0GCSqGSIb3DQEBCwUAA4ICAQAsYb1oYOoqo04vMV0zHx07oqInbWo6c2fuIXWt ONnwOUPPTkLK+JHdcLPQrSntdrZwyYhVWNR11PDc7Egq1ho4shR5HLGh6Bxz4Arw ZHJRs9G2pzCkKv0ARtavsh/D6YFFSqCZ06aAb/ZsRSEbDHang5b5+EVZ46PW4FZj QBx6MmKqGt7on3j1Oay/RA717/GDCWMrsjslezLc67j/9QiauOqgnATU8FKNJC3F No0sGrcjTAsKsd1qt+duwAo0bHKqur35K685Ucz8ICzEJnsGNiZecuKeKYbYz4PZ u32rsqeRi/TqfwgJL8ctnVpGzuF9xaOSdhwCYVIqyjksX0gzgDNzSAVEiJS9Cmp0 4W1dCeSdToot8+3xVIDkjgWO+SBoITNZoQN+NrwXSL+xMIXUxiVuugwbc4geQeC5 Z5/YWSw63fsQd2sp+jTHBWStnN4L7GYwdbErPakxDazqxZngUz0gqToTAwV+K3DQ 62v7wY//jCISIbiRG0BiIabGbJjkzd2dOagmfEAH7r+XL0FQ1wJMm/vT7As2iAMG 6/64jm0Eh4Bxg/L97QCodXxH87HEFrquhznnMMypYiMK1xhiS1OshfKdImta1lB8 Fsusu0T/osFbm7PRGlR1hncxTo6Z6XoA2x72NGDV4we+1V56gsuuac3XuycJgV3s Ulduxg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHHzCCBQegAwIBAgIQY3wL14WlvynaYC18TXpwsTANBgkqhkiG9w0BAQsFADA3 MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9v dCBDQSB2MTAeFw0xNDEwMTYwODM5MzBaFw0zMjEwMTYwNTA0MDBaMEcxCzAJBgNV BAYTAlNFMRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEiMCAGA1UEAwwZVGVsaWFTb25l cmEgQ2xhc3MgMiBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB ALQ+lbapxYadK2p9rkOOtSLv0rPZLJJSUnWSIRDU938tZuewTAVg+o4nAB/pm0QO 1D/1nVWRU1DoyQP76R6qTvrjzHRgA2AzKImxatt3RMo45u2Vd0mlvmp6wnmc4B1V 4vfPqWCuRnH5+xR9NX6UtEZGHb5FbNlOM8C8qi1jecDBcIe3Ajm/cUq5HXRon34I Q6RrTYpJTMaNwZnAyTaKjQPEsQt/WA9G+oT3GafiKhcuqmW6jNvgWj17DJ259MtB zf8jre49CHwGUs88gbNZviIEOrbNtaVvHQqUf9SVRnt+POno3pwCpnY2cNoI6ech F9Rh41cUbz9qIF4U6kR4SlyWvlBTCv0csovVCLJC1z/BbxpxAWgq4aLybKIByHuT tLSuZTmBPTmN745PNaE5rDuCYN2d1hjWaOQ+TOlD6HHJ+fBSwCK1Sr2PSKYU4vEp YsfhA1vK4Mgy8PJ7PMlbMzLdc8EuItIf0IEtVAdGhD5ZbzEPiuea9C2gZkzvaiDa I1/j8kIcvUAliFC1pGNiCbeuG8A/QeFJUAFnlocznbKUkcLcnBTK4WbxL0DZ99j2 tRN98wtaYMKdfRAA/1sqvr4AKiCbgMFSPd+1ih0jZMPoXz5WNIW4LMYM+4KMr59D ZzfCrOLAWX42CgYj1WBzrHn7ShwqSJAAhgVpDdLIaYjpAgMBAAGjggIVMIICETCB igYIKwYBBQUHAQEEfjB8MC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC50cnVzdC50 ZWxpYXNvbmVyYS5jb20wSwYIKwYBBQUHMAKGP2h0dHA6Ly9yZXBvc2l0b3J5LnRy dXN0LnRlbGlhc29uZXJhLmNvbS90ZWxpYXNvbmVyYXJvb3RjYXYxLmNlcjASBgNV HRMBAf8ECDAGAQH/AgEAMFUGA1UdIAROMEwwSgYMKwYBBAGCDwIDAQECMDowOAYI KwYBBQUHAgEWLGh0dHBzOi8vcmVwb3NpdG9yeS50cnVzdC50ZWxpYXNvbmVyYS5j b20vQ1BTMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MECgPqA8hjpodHRw Oi8vY3JsLTMudHJ1c3QudGVsaWFzb25lcmEuY29tL3RlbGlhc29uZXJhcm9vdGNh djEuY3JsMHegdaBzhnFsZGFwOi8vY3JsLTEudHJ1c3QudGVsaWFzb25lcmEuY29t L2NuPVRlbGlhU29uZXJhJTIwUm9vdCUyMENBJTIwdjEsbz1UZWxpYVNvbmVyYT9j ZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0O2JpbmFyeTAdBgNVHQ4EFgQUnhn/5Q06 /gCXFT9p8dxaPKoMlIMwHwYDVR0jBBgwFoAU8I9ZOACz9Y+algzV6/p7qhfoExIw DQYJKoZIhvcNAQELBQADggIBAHnC5kU1dHmSj1y7s9ykjIfzFqgZ+mKY/YZODupW 4v3YP+J0iWOmoyb3dYL2aAv9TLoMTGgXzFIu6stqJqOhT5UbplaDQXs/UBcBE23R GlYjlKmHEFBgzbvnVLy8L/baTxWL6qlBUhESpA9VcIgQftTp4Jj2ARXN2r2XXI+g jyfQPZrxXoYK/RFWSYilrXqs1gO1PDiPcdrnr9RrfcLep5mHV0h+RpTaHgIYd3YS be/kssywSHx2pR4b3IhwJT7xFSANqE3FYx4wbHOuHCTxYFXrF6hCnbSntxIdtJvI clRELWf6dWuB2HyFvDpY6AWE0Dm0I8NnShIX64d+P5uKhkTcCVh1wSockD0D2w7n wXj9CD/Kn2hi5PRmkpviGbN6oNe+TkpEU18eWFO3fmL6qZqz3AHXUxdth3lbCoSF kfodY7kftcok/uiXGYQLRbc4qWkpp+rWI+wE3nJxF9StcWyzQDHq+kKrRcDcth4+ lDjiE5T6quRHUzRrsSjf77dOk/hxX4VmI7hplhnfJl+1JEfBakaIMF1Y51MpHYYm LtnP87FpyubCYzVn5ZyKCV1sbx/cgyc4srhfS5eOFV4AeuG621C4zyL7hM1eCxlu Z8Qo0NAhA87+VtpywYdYUH9TbLpJdUSRmzbEhyJEDSJk1O/uZsgvxJmZ/nCluMMJ geIK -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHHTCCBQWgAwIBAgIQUuug2LdLRuuFV81toqPd3TANBgkqhkiG9w0BAQsFADA3 MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9v dCBDQSB2MTAeFw0xNDEwMTYwODQ3NDNaFw0zMjEwMTYwNTA0MDBaMEUxCzAJBgNV BAYTAlNFMRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEgMB4GA1UEAwwXVGVsaWFTb25l cmEgRW1haWwgQ0EgdjQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDk FAH1Ng3v+uTKEL33mmY5wcUS9OolNT6w/dwvv99E2nin3ZNXhIZ5Eo+CzSMP3cmc /59MMeUtvIPPbhfRdZQ9en/NG2KB69qzADGE9eSGOnatmKQpZFmqnUeLFYEB/q/c Ukcti1d7/ZpjF05h4wRuxAUtwCEq1E6KZzRrof+K1KmjcGYBBdjRzEkDdKTdGlCd whyNteCcZfi7lxfvT0wo28sTjZq7yWz+FRHPf46xoHbRlhIm6lf1gUHPBCT10V7r 6m90+KkBMqSBUXXmSVSm0Xhv7X2Z63U/XvKABpxnLy7EdHnQeQi2Sw6kyTVKRcO0 Bbs2vdXJnP3eqRwVwOfRZxup+wmY2GrlGxMKn00R+bjXS0nV8jE+td6WkfVrEROo TZ1tPcApWkm9blj+CIvQYht1G8hzhJSOjO33RW1b8HNpsv+X0ZnKxjj/jLS9LYps AsIOssD9RR3bUczDZ/miSB3PJxKGkBxbG2r3so9NWEdkmHHv4UWD2M7irKU/guLP tJOL0q8Wq0orSmXwHzn26rizTSwo8cv9I7ZZ98EuaFREzyHBhk3Dy7QhAPOCxRQQ z2D7X1yZ2WhXcVlTeW6g9lgVE8IvjbjSjhWMgTl/AFeddpZFB8SOT3TGxoQvGUV3 WbP0zpE7f6prp4aVAtHZS47jlQleeSSzXwrD6KRT5QIDAQABo4ICFTCCAhEwgYoG CCsGAQUFBwEBBH4wfDAtBggrBgEFBQcwAYYhaHR0cDovL29jc3AudHJ1c3QudGVs aWFzb25lcmEuY29tMEsGCCsGAQUFBzAChj9odHRwOi8vcmVwb3NpdG9yeS50cnVz dC50ZWxpYXNvbmVyYS5jb20vdGVsaWFzb25lcmFyb290Y2F2MS5jZXIwEgYDVR0T AQH/BAgwBgEB/wIBADBVBgNVHSAETjBMMEoGDCsGAQQBgg8CAwEBAjA6MDgGCCsG AQUFBwIBFixodHRwczovL3JlcG9zaXRvcnkudHJ1c3QudGVsaWFzb25lcmEuY29t L0NQUzAOBgNVHQ8BAf8EBAMCAQYwgcYGA1UdHwSBvjCBuzBAoD6gPIY6aHR0cDov L2NybC0zLnRydXN0LnRlbGlhc29uZXJhLmNvbS90ZWxpYXNvbmVyYXJvb3RjYXYx LmNybDB3oHWgc4ZxbGRhcDovL2NybC0xLnRydXN0LnRlbGlhc29uZXJhLmNvbS9j bj1UZWxpYVNvbmVyYSUyMFJvb3QlMjBDQSUyMHYxLG89VGVsaWFTb25lcmE/Y2Vy dGlmaWNhdGVyZXZvY2F0aW9ubGlzdDtiaW5hcnkwHQYDVR0OBBYEFImGKoLRePrw pilUNYeVb9N3YBnwMB8GA1UdIwQYMBaAFPCPWTgAs/WPmpYM1ev6e6oX6BMSMA0G CSqGSIb3DQEBCwUAA4ICAQC+9cmGCHeuehFZiaYrJnqVBecr7t3oxbHASYfnCVgv aRKJVfPdImtofjdg5gFapHNTCj8oV5whc5zgd4PQsHYKyk4xMi0q3enZerKjFfD2 4IQMhrk595q/f1ShTuVocjvG6lh252idPD0AL2B/8ohGd1WP6cXlDsLtw/yKDY1A uDKaq94TAb7UD/7zEKLO9cj9DMUIlQ3e3aV542KAJ/6eTvp2HemMVhA+ftOmWENC 7GnHHE9wpXicfE5sHUhF1qFOaiYXOkOiGjkBQqFDFwXnLMQn+JTnZ+pG+DTwe9OZ 48AK9Esik8gTgIpowYZPaI0ajh9PMCZlxy4zDT4jJHP1yYOAoSo88oKCwJPPg6WM MaY/HmAA6T+1oLmFzShz1WdHA7gNIneEomWp1nvjJDNpKMZrUV1RoxJb66grrQUZ IldixBtuY+wENdmvd1f2XcvoFoHE2DA5JKMvclu+9OZl20qC5exPrTODC5iAbmmR rqqN1Gsw3D2NVMvcHxyVt9QNkip1uKb2qT34TbJkVeWC3clmFZSMUvwHcT4+I3ac n0jhzMbF6lLPD3gsZGkT7jujVP7BT46LUso7oXrxmdomgbxLktSuGEIUsNlkx67P N1TrA7iXbTMmEQAgYnOJT5omfuBFAjl8fvlKZmrH2makms8OLPBCCF2HLiOa9CLb Eg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQLNHFB/2gwfM5sg3NNT8PaDANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MDEwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDWilKXKoYcdxyUB3tP8Vibt0PKQdvkrb3iYvvS8RNovOtU cc7NaBuXo112h5rEr1wb/Zn0idWHkvlhbXaq6akMwM5YV8zkXfjmEOWLUte/Yb5Q 9xpiUV2CTEYoRp/xh1OCOVkMFFm6eYNqEjKyD0ud1qnsFRRcGlMqysEkPMsZTMvL VCb6bxQmNVkv+w1ihj5EAZDP806se96hu/jpAAYdLC0bwzn9AuTQkBW/usPB58Zw ugZhFILqeFJtXbtkNLsgq+GXHaO+dycDNGS5OoEcgwLs7weSEXopJ38KduOas4/9 yY87ZopCGbS//h+wdwVrqpyzlq/jdzto8DEWzsUtQkNKhXhPmTtOJETI2CE9tv0K eQNaRtZ1eP32ylwMa695AxNNeo53T1T5wLmV1QqsuxJis7UYcTdQmic+anXsxpMl O1eJiXgo92hbmtwMsVBpnMfbwqUfYRTDZM6zxSZxQjtXhDaQgFUQWwSRlyPeJuQS kMJ5CjscTAiSBsSUlDHHBPB+GxqX/nqTqVXyXejzUrKcfQAEXoLAcJFzKGcoJ2ch xq5bg5l/mhQseLfJY5NunwOdq0lrlCgTdYYMHceFgdegtqTEG3l77jm/EgswVprA AXxzd63JQW+mRsdtnML4cpftrrAmmrT86rengKfv/9BWZnU4Meyj2WlNytkh0QID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBTmMuxJ6k3Gfi0Kg5E4Wt91ZSWU tzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAFvF1VPFb4HfQn8cZSan Ivr+5cNHkL6Eq/+wWoQBJUp3YpOxHhef+cDBeiW9ExBNp/bvoB9bJhuzHME6txR8 uY0zJwcqSsnZPYzgENS9xGkDY6Zwgj+lkiha4U8D6qPHvS9XfGnVCZi28lJR8IB7 R77zCLjumtxrv2XfNbHF6z8FghlwfByv2zY09Dii9++XvBqJijsyehmBBbFXvZMj EGDJBwrw72lnfA5nHwM4mrVhzdcoOnQiz+9ZZAcML6EEVLT541737wGCTHj18HvP BHd+HWR1szYIEkRazVk9agr0KImA8UaYvJnED4kWa1+L+tmFdm6gPa3EAUinh2aP AgxTzCO0QUyvDX5+GVyW2fT98yOreNgSg7eqR5PpJEjRQdve8LrZZlIqVj0Nal0v qcXQfqVIdyF4w83F5Mb7xQgZ7mI8EiuQPp3vKk+UAp3b4c5EFy57dzsLMzgfzaki yyLujset0Sygwuwk8XHAekuVTcVFsKR3+Q0uS80/FOtRRy8vQg0+kjFQwVO3RoeS mC6E5W/f3JDJMcn/9U9uiSCQXVzjoGdO4nAv+5wxh6KoCtysAM/FqdAjzNSNkVBb HOoTyarcSK4HbQCrLDni/zCZz5bAhyGvUk5CRBwPeTnW/+/puWnJiq1sdZHXegIe 2I8H0rGWcyFDKFQnn8HtOXQk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQPGKA+pGaksbCjBqfsWtM+zANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MDQwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQC4rhek4Y4p7Wei29+exomReAEaWdipWw1YnJWyYSepPMuG 0aTjkUqhwFfhin72o/6XPLkWoTk2ikQJRlitJ1J4Tm2QPXGc7sromAR++u+V7j4t cIKnQMncXLsiV6LrNBWF6ieuzcQxJUKCNXAiiy2vDLfVGDcaMx1cjn6Ql28SJ/Ca gD8EKPAvtMMGhPBoKtkvUrM6Yc3D1FzxnMtP+dmGLdUYMpEjiQB9UNeLrzcvGGdZ SZmkKRrj4U8X5af/SV7N5OqiOAOfLFxacY0uy0VzjqylPqc2YCQpmf25q0CRvE+s 7Qh5LCBBfnsB+/2IaPHXB51BlR3zE9vdqZScOHbLvhr7fiAyQpNQBr/44Y9wb9/c iEdDm9Xq92wMWFDpBm6s+WH2otsNaVAvbWxHvzyRo2HEgq7ZxguxHOcgfXkqT/Hk jJJme95GS1idIDrlh2cdTrp3eMMgf6JeH5t1yuaQvA4WmkN+vOdW3x5B0Klo/sBP QMRDajH6EzPyjUn2Obvg7KBCQGQE69Hyxp9BMz7PA1vbeWMPU5LCFHtjQG5Xoifs rvHkQLqgZRxaw4Di/0Xzxje1DfACLh/d8WFhb/mtdk8Gs7c6Kzr26qwGn8KFuBm4 xZUu35FOzu0ogVdRNf/xbX2KLMTwb973SnOPATAY/bI40NRllGhLtmWAmgBLgwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSyGpKAG6aTvunnvljgwa/ZMN9O uTA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAGhQ11orB7DVzN8D7wzO 9njDvqsjV9262QG2IzvbCaWrdPkeF3nHqhgYTC2HkJg/inxcHfWKJEYTQ+gjgwJ3 u/5OTBYg/EeKElzUgQ9S03tu+uVOzrgaEoorlhaoCVLoVrmLGBTbi2eE5AEb4BHl dRAetX73ZGiMjx2SQnBZRdBxRFB3NDSMk4I3MBBOc4iRPEwBxD+8XsB5Z5KT34w9 ed+d+7q2Lq79zr9vCE1CNQVtL4VZlh07M4rBstvCcwDKJa2VxiGwAIUy32zKOZKo m37zdQzUwAxfbubjabAQNdTfQA291jHXvPrclZvD3X4YwU0ovLwJM8fHqJTS5k79 SbsbLmWMRc41ixfWLZT91XIjj5Q+TrQ140OY8/x5RlEW2g8cUUR7PgmoN1Ht4UGR /YKObG1i3sS3C0cp2LAq+ovp8mvu4EjeaUCoc4vJcg73dW7N8tEMnEG6eXiU1hT8 Wj9+z2lPULS0nzi9WgenDf3aI/tS4iU76vvEklPTMoYJ2kK/mgrgbCFsIligC/5A +Xyw71zqmexKOjvdgyDUA7ELKLVAbWLf4Uwx4Zm2nDh4nlXGfwMDh3ElKz0PA+G3 D7WsSPe06iMX1OyuX6sMP29BMg/RJhRwlCZMzNGtsgIBe1QaYtdEbyYGDvW3a2Li 4W79B6fLZPq2W3Y1Hzi5aOnK -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQfF3RC6q+IYZzE5qHlej3AjANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MDkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCyBxsscg7W11cIw5Noa1zMuWWxlOOabPsHFAS7PB58Yhgy ibRE3nuTIwaX7WO49ihi6TjnNOybJs2/AV1qFHsJoNRhzaB3W/P+4Tk9xmlqQAwc atltbvyXHq90vJilW4N0n7HDntc4vATM0wDBlT5xEYIuTT3T/jUEG1L82IOtB5cv BMQXcAVWqojZ7ItcBVQH1noZqKHTvByHotcQBgufJn3I/zYU4V1M6lhQzdGe5sTc pVIVo0Kl1EEJVem8EidED0zikFont6hcTnGrryAtVWGxgm6umbY6ex/++ZKGlPK+ 1G+UePz4FZF8OwZYn4jM9bcho6/+Hq2YPEUrkPkJuqURFDNqMiJESIJ7gj4OgWaX 0NPCsW4WTsxBmPKxOwpLkwa4ZgGFOQZk5Vvs1kf2ZJhoFGwV2yyN+HS+DfrvHZEY jtOYw0J4rUVyVQe+iPHW/8+d4I60XINPyby2J/KZeGOCOfFBS8eijTgTXudejc8J 6pZHg/qe/Oa4b0fnklCm1Rut16D6BLDMeGON0XH+Tpd3W3UT4VHL3wuI+0kK1RFU jFxbctvFefrk/Em5GTLB6uwTcKfMUhpx+bLmqPzmVhZf5MdGyzI/rMhgYFqJ6Kki wotLF09x5eKUoql7Y0sEbOVQ9WuhNVfMrWycuInQPQ6Or+zksE2m4eziftJcXwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBT9X0sVjn/8a4VEJFV4wGGbgll1 kDA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAF2Vfnqtam6PVvI/jT7z pI3iDGYDFp9tqP+GSJoB4fCxt6bCTNDRiVDO5YpaPNMstfPJCF7F3U+3wYPLWX4g SJl/YaCMqPlol0hqJ3+s492L8KIv+7dDqcj8L3LJQoECgVTetrz8v4beN9vS2tG6 6l58Dho32amtavFRpi/UFADa3NEoMX1CKwbFGp2kMTARqx1xCK3CXKJ1T7PkQM2n VyrGzfPwAMw7huvyfRGDMBYeyJh7K056Z7OSRmLLpnjb4xrh+QuiaM4aRZAUZsnI WvOvDu/NSY4ggmK2y3PIvF1uOUicSRjcNqwf2yT81lsvjrSNeVEzxTtVq0bZTMcS rjmYAYHJ+4ffXzELu5X04d0XojCywnc14zdIjLRJDRiZZ/M10qm3MpelYrItokiu Hk7p4Lq0Q8+Zup7UxSMZy6+c+IO19nInPdLyoahh7UZ/gC10xKbULHA3wkJdcT/8 AmTuDGEDl2RbE09svvo9lZjzPu4dgY+sN2Kok4SsDX0sBvKhikWS0/WDOmHkRkKG Dm869qVTh2pqCKj/ZNRjvdERDqSd74HraHsGDIbXFLDEDBHCtVRSGHf5C5AZK9Wm LTD7wwzJ1nFmRp9HphkNhxAdJvFc6vyz4yLqDF6r8aPR9Ho3DfvaZXZMEV7xYcLB 4I0MJfdDbibWkqmWmbY259/N -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIQSl6PVisF3L8+zkCSF3xKXDANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDUxCzAJBgNVBAYTAkJFMRUwEwYDVQQD EwxGb3JlaWduZXIgQ0ExDzANBgNVBAUTBjIwMTUwMTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAK4514Boq2hpmGaQJ/fdcuDcn50b5x3WZX0W54OtoISZ crnefeeFwKz/3JNMXO5wPUaFAPbnGjNBRh37BpPlzJRU0pFlDT4DzksntjDNUlD+ xg6dZRPLJLHjxGCgT67P2Exivd/0HNNKBCDl3dSPAETekrMRmRoiiYF4FNhnmrZ8 Hn1DlbrXnU+S2vlJfmvkkvpZdizddkviY5HNrgaLgUpGwXEcTDMQcptlQSKHUeDT YCGuNAhP+gCzAoJlcrOnE/kV3jygAtwJEPIeUNNkV+TYKtxo+W3V52dFOotEUEIE PZ1i5B653w4gy/9ou1RIFBFFbc6sffT+JnL6gAxEnzDeWxfWZsJ+AcM5E6xNnews bD6ZWbJNQyiLhpUJjVrxyjv4nFXINCwMj0FsZPd430LsXS7baYwZ/kT5ADLU3x54 YIj9PXsRP1HMA7idsp9k7WLN4uczzBFU8+Heu2IAwASE1RT0NOXF6T7TPWLNkKtn Tfo7Zs0YMgKJYLs5mrMXyP5SJ5M/gmpoOtZGPpat5UU4kaPsq8iwWcW7y8nLI2V4 mhNIrJ9VYHbcm6TQ6ACqB+l5Goewo+2/CF4asiZLtJSUlq1sT+vFwrOw9ye5OyZR Wyrsl68zAv2LgwYJ8WI39XBNszV9r52VgC5vHWjPy4tmIM/TVIXwtV+P1hZnNxQx AgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw QwYDVR0gBDwwOjA4BgZgOAoBAQcwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9z aXRvcnkuZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFAK/hk0KWAn3qTZBL/hdCfyO fif1MDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUv YmVsZ2l1bTMuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBS4vGwA j1sZhZ0lAZzwGdxAjtA4KzANBgkqhkiG9w0BAQUFAAOCAgEAV645zZWXOK/fpnV7 oC0SnnAZajIMjc1pu7K9ycg8MgipLP7oi8qMuOICAoE60VZ35IxUa0PM1BbZmPDG gRS53YhDQRrGgfo4Zwt7FghNnnHzfYHdol/FPsyzBtkpXfwZsUI7FGqv5XXFPQ1j QTA8p8gsdTHcA2Sr79Zugvw8V4YK0kWuNcSYADyzDK5vMtrFCwhFX0qG/kjWw/B9 jbcirQvxah3ev/6Kqc6HKYjBTY/LklY+CvkaoLp/2gMAJE6Pcl58iKcq/uD+02Dm ZbfLV/yCjONpaollcnqeY6g/RLHtsVnAY2GtItGC+P70zf1d4UaJYl77D778D8+D Sc5kiij7afV4RUkTV/me8wgSJ5fLBJKzt3SUgvCwFp1cph+sJvyj7QLfW8acpgdn mJIrFN75Xn8T4dR7sGzJn7a2N49rEkiOkOVtfDe3zrcU89S13hgqmCoGRAzutHMa HjJqDYARREP6YVtOfPOXdMUXWBC0x1/LXAnhOAFdo+eQxEWbIUyedllnbUu2yqwZ AKA0aIh5xYxmpMeWOHceqpxi7MAFAmv50/TkI/1cur/QuBQ0j971dM2Zn35xdkEI qPeCyhsVcqrvsvCEHANzc2T5r/5aTVKt9f7aZgLH/03wf+ANJ+wpVD5Mjnv7DbXJ D1VkF/cI6eq4Qvhs50P02nz+tew= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQT8AIHISto9VjXMe6kre86zANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MjAwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDW2i6TT2G3DN9scQCmgEllN4c5X3jLMLILNLsrfXTl5Oyl GB7aMxeQ+A7mQayZXqSDYPAdbeMabzjojxp0HKbis6l6RPf8M/37h/UcwNkAlzXR FYgxR/ig6G/DKJz8HVYRx7p8+uV0FpggUCvgG1mzr1Atx5gj1t/2u+QGuPivGJVG qbbxOn/CKOKdGJblMJHEnVnbFz4QGOk+RJqn0jRvKE0hM6L1m+36OJH541F/7XjE nh7fddTEaf7nwPwSJ5xtWH3LEfdTA9VfMSc6zKZ9Mnb9OAdUt6S9BI/HJFXkKTLd Q6eboj5kB1XDN0THCgiSij0TtFwjin+Ego8AEwPcbzWCga7R/ybzcHBxg1iflZVH Zndyb/FncDXO9/66DXXJDRpO5LSOG4RTDPbQHvrjy3Qs0NIdhIhzaooVq+dn82Nb XVmqs2NuH472JBthxaKpy2ySF45HjhLvGbxt1JFqE8uNMKkyRAfbzxYYeavCNv9h KhNfvTkawyr6ZRu6CxZ3JxZa0gelIuZ/jfYcK7GMXdSY30SUSOZ9wvbsxPk94cKT 0mxM8aqOhn/MWh6hTSkf5ats14qVmkuXRVzFRMGvCIx4P+9frnGsj8oRBwwv/j29 BzsMmnKAmEjWwwX2CCWx4b9DhXj4UCh48j3IT49JLTF1diHALfONW+whWGCj1QID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBTHxuTDkE1uTtYKwM6tZ1Ni++id kTA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW00LmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUZ+jxTk+z tfMHbwicDIPZetlb50kwDQYJKoZIhvcNAQELBQADggIBAJXP/dImyGFovB1NKP4s BHQ8DiPANpsQ69seCqX2tmjV9fEUsNGMnQuP05gPJ+8UZJqV/21vbXoTYJ72qYOW SW+d5t5fF/R67hr98yNhaFOUaxX9S6IZxriihVSO1XZmZQ8OLiwlAZaYD2z8qB2P QZzN6ZUz+BGKA6aLC3WtGEqK6WA7HF2+N6MmkJ3m9sJAQxkUec3MAxOaBz+0MWV9 sbm9Hc75QBlvb7yml6m3h97SSpOcNKHtXaOUfT7Gt/AZ3VRvjUImG/YDUuxD3p4V EAjj1UCGuqTxkF23ldacaAxUPrAngIgaTZMcWooYEY1BAm7Sy1MaEYMat4P9S332 54nA3tNyCkN+IJffpE9ZDR/5tOXamVsvc0wRKpbgTq6ieK2ViBjvhclCxuRnWgWx 6lwvT2X7d3dbOVrxkgWfKIb4yxv8xKkjbO4TUQGQnQGQNFovrIlwxZuOqR7HuTOl rOUBQfIRBWS9ZvFtPy3n9jQ2qETe1HH71b0PQIdj/KmnJ5fgeZDpRJjJOT51SfHf GndmhqYv5A8rdc6zMrHibNyRl8KMZMRDYJwgZV6TcbkPwTjoSwxIEYQ4P3JkbQFV 6EU7ugwCbSvUAoH+uKqCjWQW7iJzu0qALKCeldRVqbAjlkXWASqIPYqU2NquCMtu x9x0DDXNmULgmWoGCUhACZOe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQcEazjitCUmQZjhyQxV79zzANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MDgwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCwHfAbDp32j+JxPznA9bvnJr5/JNvx/zG+fMec8umrN3TW o2SXcaEQraly/2TJoXNrhG8IOVARYL5dPVdTzUTbGpr7H5tbv/XsiR8ijIF1ihpv nH4Z++MsZr5vzxLfvJM+NNZN2y2c8UHhKdMCHebgCYLUy4xFgAhALlI9SK0dU2vQ 9kfbHng9ELRViwM6RxS6Q3dgZVCBws3iGLQ2jApDornB4mER0ZNnJs1sYB5O4REq gBSlQade+LmJqX6UD4vJ5me8WESxAEyGL9R0IAiRb63vgEY51/TDZhk6hEkzw2Hm y0QYLvX0fZykpjz7w5VkMHY2321SYZUh+C7srvZ9CW5owNoLUewBnT7xz3990bpp ILVu2M+Dg5mRqvYz+5Rwj4dE9Lc3w+2eFeVZ2BjZJKfBxapvQtftj1ypPgONk+bE piz0caGv8QMRYP4H/AzFPq5OFBxhjwLBimcikfRWxMX3dIQLnbnCD8m6yvyz46yq 9owU2bPkojuGTHmxFC+KnDNspglA0P4LvtG57mCjxUi2qi8g9zspTp8SPE8m9Fp3 ZE+wrCWv5gTz4VVA1DRvdbHOMAwip7BcsfHvN4No69m5LChT4G8SByTZ1/mjaJJT UUfMISdsNMKQyV/veJsjjmMP6/SRJY6NJT7TCU7FPFIMqp+QBW7pXRClhT9/0QID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBRqb1HlzCddZQnuqBsSlAPwQKAI 8jA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAFyye8CDNtXBu11p3E9+ PfxlLtrzFcYTzPgtGyFhyZIhbVNnNniigd8v4y9bYYfXUns/hqNvEiSA7g8IFPMk BCobRAuJnuDWbf0t/q3GacobDnXS2kG9sceJ2patDme9LDgDpes5/v1DlEq1lHpd DF+bfiY5zjcJVn0s9agnStoMoWmNbop8pdQQI82WL2zd4/7YUlf/ppSIT+wC5trI r0afhs6DDKiEHAdU8TWGWSXpu8zzlFtNR4VOk3a3NZwTI19q/0esAqTAj3oqmMUN Wme97zq9eb2RnnAvbr+QnEI6lppE1ap4g00mPlcayRS8uzg9FeMOZ5A5rfdHZziM e8tm+LWkzNUJgHTQyjcHIGOV/pQodYZFLZA/EBPqyrqqWCz64HiKlW+nIM63INPl r0+Y8K+wXjMOqfi/nDixqGRhCKtWW40QA3QaLMQAIdLHQpbvlMwZfWdTiGRhm62A ktNCYUOWtuUfeIlCTyi1eiO/ShxOkAwJLDQUcjPlgyHVhnIRifWwyv+eQDgE9Vpp EkTpr7jDmeQZdBAHs3wIImuygZFKGHPdCuKf3hl1cdvNNIMuYCaLZp5d/QSQz6ZI CoruIGleO2L64J0tze2OWlHJO66/foX2UNi4CpyUKCzhj3X3txWOfuQcW3++jurG QkNnFJ6f/oZyC/SkjIjJVgoV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQabpVXJwRG267/llIMNH13DANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MTIwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQC1L2ICs73/PzNcxEvLVkVwWUCY3F1p48uFcQZgRsScVZWC R+ghFO1SsSCREaTFsijS2jmBoKBrTdBMudUizp7GQSozC096Si1q+xlR56NQPgf0 sr4zRn2Vr8RhnoQgDT2RGmiLV+lo1JRDymtRC86rDyo5TkDWaHt+jKD+j9LONkNa PIqbzUUfOKBu6sg1ViniGU//6wQkg6pNJZf6x8IkbsWUF8QHkMLPkCJaPi+sSNAx K8O0xYelIeGZvULUP0yEhWyjPKingegb9vr0jeaK89jYEqpIXQ0pkCvd/K3t+DHt cvG84uR4f+BRRh7dFE2NGc2OYyU0wJi5kgwnGZ10oc2/XX25tcGD368kbkG3uGuQ Y4v4HWwP+KCW9ixJy/wOAbvo9dMbVMqADODg/Ov8E/2oG+tlfTICgdM4vOo6OveF RIAq/8RA6933OsLU6OOHL98Dema2hmFdTu0zXeBPASQY6EnJnbSlc2YFeqWi0CoQ y+ymYXrUkxNl5hfvy8fmGBxj8y75aviL7xUlzDC/z06WcWr30T54lg/ayjzdyRMY ZACcxKOIKnP6MBphmE7k6bvoGFjMaQaWuIAS/3BFSygdEGg4oBw6/Uv9FLG1pjP8 LOqtaL3iojNqdvsuM7o0ziMcpjeHd7+ZAK7wm+KiFDeBQRSjvoZPr1btKqKXowID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBS+L+agZPZMOV2BVbKnr1ycmuze yDA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAFuOxRiBDz9nqtLLfeHp yRUOgZljT83nZ5IkKYFR8Eu4LABXLJsv7B32Qw5T2jRlRa92zF3Q+3ZgS/bOWOv3 a9c/tBEl9JsNLD2fHPfLzJsMAaMMQm7Cg5CeCscNPaCgKeh3bNJQB0thKYrIz5K9 I9yCBdc/zpYftvNaRKgc7r57eEaLpNf+Lpf/VzP4D4+rDMCXJul8yl5h5tnk0+Jb g/hhouIwXwjqPcYpNq+mIz3Ac2P6ApIX2lyeYH6/CBIMgXkupGrSExMDWVdQqY4u myasWPFyXzk+jSvdxKAgUpxK4O3pOqDNQgBlg/9odXwVIZx/PkY24DOC2Q0sjNMi JDSqJlnn4gJVR19rA+2bwdGqUKoGoQWb/raNLOZxjDhSsm5VG7ZeH5JOHWHlTR14 SuULelEGmodEBCpp5Hj8ik2T2C0I1TBASit+t7buiqPNWVOcoG6S4b9bgBU4apQq 3rPNTWcPMfiG+hnUy9ZcaICCZnDVjQrCRgBCD+anj7TaTYB4xf1X153cbdlUiOhB WWWdEmVGs6jwdbHuI/cpMIXUfJm7MoSWsuxQ8DAwSvS4sGYWkjXi5hduKc0ibO3Q t70demUX3LzZKuI5E524YvdO+5gD7w4YEZ+gkD7CKI2hbBMVsGc+dK9SZWjFoojs FfLU4kMkZ8whCdNiGgzXyU64 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQUq+0G8AvOny0pome6aLgrjANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MTAwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBe4Wh4bEY0S55IXuu28t7KqHnZqtLhGvAOkg8BNASBHz0 sIEIhCT4OG6nbHHZpyvafrzkyK0pPmDM034Zln3LDsFp5dV3vgPOxAuZ/zQSGWR5 NLHf7jS1MQ3agJXNqbP9dPt1dBdxWRdlXGkx/WEx9QhjgAoSkArS2WMHuMtCrtBa o+vKLdJGK9X3ERw0E+QFNOD9rwWpmvYL79eSSqJkvJDiT8L3+MPJ4BBoLReEBjBC mUdWS4GKBTCeBm2gTTBoQs54xRDqHJsYli8RZYJGcbuF9IrhP0+73SIXEtyX17D2 vncZWq57lzpWFtk5cmdIyGAp2QG/Fe5bNRyOAXLYljZ0QoRymEG5JdPFnG2WI5Py C8tOfOC24Dxm4su/trgUagwKSxsG7jpViDpttOaVnoZIzWAqA75wb/6HG/QvFM2b 6KcKxg2dq7PpLJMeq9GPLrBOGMlFVms26Se2b16Wu2sWoNIS16FW87/sY6EDsCZk mG2cFR4S/uYAiyjtJrzaG7tSwnL1ERH2oQzFvvgt9ML6EvALp6TnPKE1PD1/ZQ8P 5HSOBnO8pkJ+SqTFWWWE8W0aIklikDdWzaANHIPhROls9sTPk5ddI3d6LM54FiLO R6B5vsO5Q/F4ZOXXeYEWATZv8aiJLAr70qGVmxBack4K0kUZs8DcE0sX2fXe+QID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBT5SW8MYJrgjAcXrRJtxDFzTZaO AjA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBACvcYRRFxHtc/oUYaKpQ dFS/XGWh1EKwOc6NjyM17h4lcMTBkPZ75+N3wph29x7A7+FE2jDLaKPHS9kMqBCr A09K0gcRVNRTumnlrNG1/RlJe4YweJ7bXG37+C7+c4JV6jq9BMMQhdUGLqXXVMLL f/PWlqGlnI7yCdhTLzslxqPJ5hTLgkcZbJdDswo4NGwLrKJBs8sStPONn5jPIzkE 0CGPnnmeTf8F8UdQN3ioI4KPIO8H+z7jfat3SdNqQvgm0nQUrK5pofIOJLWIbmiS nk4xQHtaDVGd5M7fngPLVY11EP/u4qaslpstIFTbyzn+2HxG6I6dgmlVgsD18CP8 mriz2RyQoF/vBHiGWmDz3o6pisA1Lqly48BbiFZt+iDgXCGRZexd1HWH43jBmRUp tqdhuzO70cza0miLplUZt9d9Y/rSHBC/20B7XDWFRJMzNPxWkjaZPTYPes4KL/dr ROTfVJoiWfCQvqN0/SS8xIYqOvEDo2sdCpQPEM15zapLvbDtrVm5ArVTJJzJVWpn LBv60j4wvvnH1SX/Xr55DcmMfFUlnYjPnHF2lOFnXB3WWEHyqHy4mwELVuthzkK8 UUJAl2w9L49t+XYFiNrhrVrsqKHQCpZ9ZUrOsHUj7Gb5m75HeIq1FrSok3TSaeZR 0Txz7sFzNBQqvdvOY5WuLZUW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIQHsM+sBInuXgjUfT2VmnheDANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDUxCzAJBgNVBAYTAkJFMRUwEwYDVQQD EwxGb3JlaWduZXIgQ0ExDzANBgNVBAUTBjIwMTUwMzCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAI+/Ex1N/pqQrM9JOSgV2yH6InTWSLCF8NtMZOSEXKzY +/9bjnhH84vRJ1QnDJHEzgm45kBI5jYJTn0HTX57wy5eN9XcqrUa2HE5NUb3XIFF pNMt8+BNRZDl7FYW92QJQvzD+AtKzjX1ynoJ2m7EGJVgcmCAhLRG9qNXonubjr9q cKxb7PoIsYKnq3PQxXZx6T7CoGJ+QvthK3NrAdl7HV3ojsRe5+PTBrIAKhU6ki8E L2AkL5FleQaDS+QVrdt7EktaOqRiWebiyUdDgDp9eYdRYh+IWrEx8BUMn5ck4OD6 +N45y/jLmySiBMZU0ocdq//1yHtRnA6yqg4dAz+KxChOllG+9ZUe9EdJcpbHwDdT UJkTAX1F4eZ5912LXy2FxZS4epe/3Kx/Z4p7ZZHbHrp/fNV2488B01qq/js+tv+B 1UQVv/vSWl6z3Nd/rUJY0FgkZ87xbIWhgY0lgdlqZPwjQF6GnCBfCADzabBGDor8 tRKu4xeZ3nFMJeISG7c376J2ntVwd+YN+Oule/Qn5EiGUiCW2fgf66uZhmF5pLsR KZRKwoBf692IU+zxgNwhxo5W3Ubh06oytkGnM5Me/Ki4FAqCxZasu6TjTgvaAurr hVkZMoqQgcDow3AhuK8PTRLRqSOBuycAsi09pW9pO3fgSpWRKkQUFwRiWn8TZ1uT AgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw QwYDVR0gBDwwOjA4BgZgOAoBAQcwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9z aXRvcnkuZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFGk28Kog3QPPCMKtxkxbkdvQ 4DV/MDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUv YmVsZ2l1bTMuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBS4vGwA j1sZhZ0lAZzwGdxAjtA4KzANBgkqhkiG9w0BAQUFAAOCAgEAGitVEnoyewaIfQGI Y82/Tz8HLb/KLZYNHix4dj3aXNEivoDSd6bH3IaeQ24vPttFJu3XOyH+NZULRGmF NpYUGcb6vpQupKQR/07Sl8W+s9blVRpqzyzNH5jUUQ2KK5llezaO+5M4Zrq9wRQ7 4ccXwj0LMyVUah7jbnPqtMKEHQi6U8uMW3+w6h9s+aa0Bbm4oSBJOFagCBcNQG11 NjSeSPJSetZdNTM4PdpSISsE/hrj81VvpqYw1+G0cgkzoGOIPUSHlq38CL7vgk8q K5EtZfDCK6FlSlkklDfdgKiIJk+uRupiApFx1oJgoagVeC45zDyveMwayWgryRlK vbgvjxXtNVyoj3MGzD7x2ijbH/2D/x/jbSo8LTj6nWpzn5Z26bwelh2GEwAQ++gp 8ivQgTEGfjtuGC+tIRF0My2Zy1HRO9WKKfxlZycsTQctxPW/+NymbPBtFstIn841 rYu1luGibykM6Lde082hp1WHc4fOgrV9U1lZAiC3BO2EvefrTIC8oHe0lQ+05krl TxezpumL1ItVTw1gsFnwhUJ3GdjEMYkQUXMK1l766Dr87T2RU+nLRLtYtCOHOAm1 ndjCs1cYCdnwNmTz2bjP4RhlEmY24nh47rqMZsNGyHeblmALNrxCKhyf2CswRAy6 ZWGtyP7GSnlgpfF6ejZZQ/P0+Xc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQJENKZKC7fvL3aFAH9lPOyzANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MDMwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDh6JbaKZB6GhDmuM8PHiyHm6zKRfp95ATiY3PQBHsgt4Zh +N5vuNjWdWANP68VKfCl41iGm4td47TA3MitcVvG1qAvSnWemifa/UVmg7fKqC3b XZThmowlR2ZUPS1gnLR9nX0LoO//hmaoJpxQHfwcG3XGWvODBexwOiIMmnIxwSqF E9scBNOU06YMezQMc7y5itZuHsv23dHg+x7zsqG7iH1DRCjtfydElHzikxuqYxa9 3E09mhYRyFQchSaAc3skWNe9XbDJxOWV0E4uEuolIXmB6Jsl5kd8DD2o9NSHrOU6 yK2DD3RpAIo+R7V4v2/PZCERCpoJ0W5mfNvEhptEvvE47dPSU/VEtJCwcKmar0ig LXnrcTLoiI7iE28zidv+9v6/3ax0uXtgMo21XEvQwpKNzPoG/t7tjm+l70kH1ANR 4ReNIJhEvxFls2jOeicgl4QTGB48FUY4Ty6qt3xH5xAomkAMtdb8JVl6tcJOtwED oX83qo4j0B8VEo8lkOBfMl8mV+nR/sKfvD9wHroEfXNFQ7HET+x1rxG9PVbWfZFd EaFnxQ8YFW2LXJ3wW2EnRYx8n+/6jRj2HHnFD0ycyHX0yN8NSoH/gRlwbi5rAgXW kMgCkOE7eMZcMf96tjOxtzifv8ey9fZ3qxoSFT4lIJYyjkrs3Dt2+EWukcquvQID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBRb6rZjNOjhQyNBJdXY5Rqu4cSw zzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAJSUkvG3rC8MGVqzxTJL 6YWf85tnn4mMMnU692x5pcKQ5DqA0A4+OAwC24b8dwR5R2r7z5HTngWVR2B45Z9q xLxhN7XVEdb/Qtlizxsjp1hdjSUBFPZd7dfQSRbXK4/MJDzhNoIj3YJ8HdzmFkb4 Hx0eUg4JNCZijfgsXBAJvaerkUqUSz4ARgT87LumXIwbChGo7r5wbXfAqmoNf1RQ FgkJNaeceLgRUWSkusmBnvmZlJ1NAeDygC1lbRDfhDLKIlc06qv7FrW8w8AlgzNb RSHKeA5FrPb0PGMrN7azigkg8JVDCbZlJ5K0ITOBJ9Quv03WMowtYZbjdjxvhDyG MBBk7WzzkWD8xfoVIvbQFi47YhOsDyHdCtSAwb5MGZv5YWn4EMMNIfvuAwu+sgpa aFyuhSAP7Gu44L7sW0+5tKmVSis/U80TvKm+OEWulviV/1prUShz/8mSR4jzlC6Z HUP0Ikrf3t2T2dVYtAWh3QhDBVx9O7i6drzzehNnB3iG6SikOAfnYGyEh7F6xLU+ yQNXjkmolgRxPHuFVDE6GeOOmKHXO3LC2L+Spv2lf8TVHVUlqEuzuqpQjOunDyZy zI3CHLUhGd4w16AVFJWQejbxCXTZIp7jfs3jYnUEUwWyPLXso+sO8Cb1y/O6DAGe Og6WgY4yngYWaTAl9/ixjJUO -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQNrAdjvlNHSTwwERy+IS97TANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MTEwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDKXGu1AWVkxHg3eAWrQDfq3nO3NtJ9e1GBoQg/7ZiYfC5H JUDhUdnag7hLvGxqYbElvYWAAa5bQ6C7YwTZQEEzCdgOa1HAUEqat+YEkr1TjNAl hpXOlslOExc2hVQSj9fwKxeId5b4SA/TPUXPUgavWwerpS3A+VzYAQq4h5zIN7Or hCxSsuVIiusMkMod/o9zNiIgzKMMCrXg5ZNXhkDSf8nALUH4rlvimKDc52XhyEsV CXqhrWo/JQeNXPkBSSg+MjBVW1qJ1r08D7cHHolNkGvCFgA3LkFGehJevTZS4oui fIiCTAg1QwQjykObOo2wMDRy4WoBFwDxMfzTjNak6yLPj6YTnQrrcomrqzY7LEx+ zfCJZ2M7dh/1+9n5ibPY2bg2PduoxeDEiuBxqJDj1yQ1R5BES6q18jPXmb/8SHcl QBixWAbVQmROelM2P326UaJbM5/SOkl56Pp3f+8nank5vEbJ8pgC9XnBjfE7F/Fd cR2ziSRotEJoX8DgsWP5DRXRONWHNIazq/png+I0wTiYuTq1cTKFv1b1Xe3MdrGk a2lN+GfNOqPFYUL1CpZl07zWHL/5uNhgv57A6JtWNpAQyYHr1VIeMqUMkr0e7c0V 2Ruo9Y+Wy5y3YmDZllem6zU0cz0gZJsHqgagrXJvK3YZWsHGkunuISSaZ5kigQID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBR5NogwlLwgKDoAVAFrQvXbtmg4 CzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAJOEpWaWoeSlAgCNIZ+X JQNLKipLrc/PK+aABF357otx/fwGJS2A1ew2hTrcITzmto9+6WwvAEJzAjPja2t5 CBbvAOXpluDkqPkVoWEO+KoEwJMOMKmUsk+0fDangjmt9gIJqRMrryYRmwC9DFeL tfvCWeX9poqZzI6B93WnuBbhJR7YsOOJ4pJ0woy49paQTsPfVLLz1Y8HXsr1gCkP VRLxt62aONI/eNVRQR3IzcYKZsD1Rxv3mi7Sday8OztRvh9uELtSbZwa/kTO58qC ZFrieRMNGvoIzFW9OQUM4gyGGhpGurxn9azeYFE2oBt2weIRLrgD8wZ0LtzTEKhp o+Y+uZuBoqsAKZ2Npq5QR6u2L6rO2Yjp/63GizML3IPJIQQJ9cljjHdi0MCEU0zd W+VquxgKnkUdtBmcIrL2s8pu8sYCs/AS/JsFTW7Knlvu8IjdumIY56HSCK9GQaG6 MAkdngHdiE/dMoZAslpyR3iJio14WzAvsHwzOotS832zbK7Xym0VLSpdND7yQ8zZ FtQN5xuGcOjQTHnmxkavRnddrbQPCHAjr2MPCcVGO68O8m2VG4yLDs/KaTLPrnGI k3FlleR+5LDJR38mxrFyfDTLBCbybHQZJQdj5rDeJBQSHKHOfjQR1vKBobA1S79S lQNMu7yGgyfdeyiSb2NeYOxp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQYbAROEzLB00BRBmrIfZ11TANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MDYwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDXzraGdpMpPH1F0kLXffCka8r9kp1oTwrKr2/63O+4yCKb DMvWGEfHPM08VJbxGQqy8lndhoq9OkTfahxAcVrVuTErK2lzuaFKckY55zywfyOL BQKsYOw6Bkb0XIm2YqULe9BjSTssMo6yVUaeYTvfT62K5wSP+WEF7gdbKfiwAAmN NNVsibwL1BJgxTLMcjpLcnReORhFouodpqHizfkIgxuooKi7a/WMoJ1iTLPyTpTv PHKmSvsmOtiCFgMn+lu4TARi8o5WGcFW/RsuGxW8Z/hV7WfaxzfgXD2EBL2fdjXw wApARyhs8QUnxFT5OilrQYsFY9Ldx89cG8w0cWcxk/07WO7MkHYCPujUZRFcCX0F BUrBylpe1NC7nu4X+t55SbYmv648adjKAJkZArhyObKdiBBZH9CGFWd8fHpoG81k ZfROEVrzwXmch7Qa9yA9tuR5wEA4hlLT5HzOVmnEzyskGlQaHaCnXkvawaOkUvBs kFPYz/4wxnyh+6kPQ79n5cIo30D1JepYcnJP92+qPIBvssndusC70zOQwQyJaqYi Z0Tt5toxsIVt1vE4ILcjRjAaVRPxZuZyXqrRojWeEpEpTbg7ZGr6q+QTrA7ajpFQ PPBqqb1nRDv9OQ6TMv3MfC7zMX9k9TcLPy6+Gi+l1HLuKoPRkzGyn9A16fHD5QID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBRS4yh7ifIFxXVT8N571ZBp0+fX RDA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBADEVLfVWW80dHhjYlKDT G5OfPVzzriVLGG5Ryi7ZrkLNnGYoYrL2JG+TO4wwy3+FigH0cHgPDFT+wpD4jddD YBfnzh9Na80WWdZKU7V0dwxPuyt9tP4qNylkuIiV7rNIH9A/FdiymMoM9YzRCYI0 8V3HnTsFfw3hNsMkxhlwMb+WwGmTD3PFteUjSuJNwH/xCZkqYAvxT3PpPZwEalzu C628U3or26KPclZLPqeSChlzFksl1naPwabkIX4IkHHHQdeuJZ4HyTKrLWHwkLR/ Uc4VgVz2MX3ogwnKsfI2L4sLC7jFQxoh69gKitEh6BtUjmdRug6IGV7GWIaKWD59 fjby+9lW3GxRe08OS8B2wJhCtPLG6yQ24t7jyHsWaMkabAXJQjEoU1ZqvcoPV7P4 PVEnyMezFe0UvWmj4Dh6QJscycBT7TpVRA61zLJGxWXDuMuQ7SE0nuwrQdt2NNya toGRFjgI+r9GY1+GWMninGxJaMkq0sz8+4GR5iH4Qhzw51sQpHVTyhW413M6WELa 2IQ4P/9FZC+VOhOWqy4RNITWSjiZvapIrQyv6F9lRrRDZ2Eovr1U1+DEE0HvJyuJ iS0mTNonuI3U0BW1s6I+drNxVZl+zwgo8czGoIxxQPCOGjo9tj3N5eAeSDijfobg SydzS4Yb/iDYebb5Hi591/kE -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIQYF9k4MIhMdHybb9ZYTvJcTANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDUxCzAJBgNVBAYTAkJFMRUwEwYDVQQD EwxGb3JlaWduZXIgQ0ExDzANBgNVBAUTBjIwMTUwMjCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAJ44r0SzJzBms1wdV8O4Q+PoYggvhTbXZmKz34soiE2Q r5gkrJ8fusyIqoBZ76NVcJkwrpND2KO7+e4wwV1nwlosBODksGx5vGC246f8McBf ivGNmNKbHNahjYBpFa3sjSLe14VeMrMVpYUIQcI+81svQIZiJAzGReUinafEHQIV RazwcNWwWpw4GBOxIRNs/3LRbF6N6Dd7cdg4+kQsDV22GOOiD+RSEjZbx144aPl0 dl7Gt7bKYXMAmgIta39hlzoCUln9YCeczjlcivie3vccmLbv/ZY5YPLH73rDzRLz cUeTmr3nPZe6P7OkuystwZOxRCaGeqSOB0gZh1/grEbUfmwlFj3K8gKX9IhZUwFv fa7jVMZ34TCMPe5Z745qvnG5MAh4VvfxezbnHQm/9g2yHbVYa5yn1KhLteCfBl/A 2sEcl7mFaltZ+EmA6tzblEOeNvtiYGd790cz+0Gr9PsPPuwH2nwlOWDM86qBdVvC Gd46uqx1TvT6nFUv9zHsXsIgTbTA6wpESyXmorVAQARjCiKbXzpqYyFXz2CVwER/ v/iMQ8spZqD1dU1uC7YsfWWmQrJOw9+t+LGpPgZ+iYaXSeMxhzsSleaeRiFPL6ku vKF0QKbNvPlhBeiXZ7NgEcfuXXkiaSuY2f/y4VTqtaKZjHzBycJmTR/Rz0kLBA5R AgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw QwYDVR0gBDwwOjA4BgZgOAoBAQcwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9z aXRvcnkuZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFAOOEPaEWaeiQMgT0pzmFFwx Iqf1MDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUv YmVsZ2l1bTMuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBS4vGwA j1sZhZ0lAZzwGdxAjtA4KzANBgkqhkiG9w0BAQUFAAOCAgEAXDiI0OOoHx9EGh/1 HOaKcoiwaUqLv8NGNiG6Rd03/Pg8YA5riOgUC+5mzu1thNlEegEC1UsoZyAYN1mU dm58vHD+tsxCFAfJJmDDgoNe/dlMnSsVJXki5GzNEBEQ5kaWw0PIRaItcMlr6ygn mFwDbGCoXoTRkVKYLcD5GCIN/wH6DwUmpvfvjXRRsWsjT5A5r0u9zv8bVfbNdMJ6 Dx2IPyyhxMp/DyzCsnTre50f1qG2QW+qrj6c4tl+6Zw5mJJsYK08+bfFsxzOHMMx t8dDcMm6RIocnFczLKNM7Go5jrys0rNCUnDzvSLKoATRMDU31nEF/C7ORFrakOiR dTJsdh29pMeLvlHuyu9hslS0L/YwR0DUNcsH6fxvOpgDpImkjUd54o8LRrK5fDEW 3P3yEll3CsV7k9Z5hbsdr3C5HeIZoaPlRcrPj9BMsvSZ4jRVgQmiiPdgne+IBs/C Mw8CkHylx9tZJ6tJlVrbmRMYCOsH1AFcqRY+qMwjn6Sdj55tSO8sgql+zU0OAdzX DbWJBo+1ew4/4KMBILCWnb2Okd6pVYBLxokBK1Uc6F0pqJLZKolYgXhXyU7/oV/2 e9xhEhpiVXrNW+ckLz4IWh9t4ObaB7nMGQWW2CYDe3zZbFteZSbr3ZIt138plG62 i8PpyKKZLi08zIh2ybvI/JDO/gU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQRF/Q5jYX06pX6wO8nwrUaTANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MDUwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDDaOCwbA64iE8wXEiQr3IaNlewwp1bHndFiL/tm5CtPnmh at39AQTQitksfJS/ZxwVBXkk1RqJgh59DpbdWcG85/XHNJV5lolf9p03CFT3kEjW 5+h95VpMz8jCBAat1qvOumES1dx8s322x28IRJYxXxQUru6+jgOhSuYVLh/lMuol WseSPEGmmkwlb28rp3o1Jek+l/CGuFjAkgKFQvdoXv0KID6Tk2SrZmcojFq3G/1W eW9/4XHR74l7LlXO12TXT52PPV0jta4+JfeflHQh6BSWw3Ogi9EOCxcCjuC4t0Em ZxkNZdeHR0pydn1r1KOiH/sN3aCnBqGKYKjfrdvu2Y1D4PpPXRCy6jvkLecAWTso EBVo8XrM3xxVAkopzSV4YjuBXCBqYbdgC/q5yJMJRJGOc0L9+ALWIMaz6eAQb9K8 zMAZQy+xIfY3qUQPgBInIFXQr02eDiztcC1/aPziQW1hsTstO5pP2GgSs1Iswfqq QjVlwFU23yHDw6w7U634vsc1U8tMJ1JfyiuDIfYvQLQkiPQ8v9av5b2qB2eQFglA XbXLSOOGCGEbcyKuS67OitMrEntx4ePXLV236FXdofMhCQ3vEv3MqqxHFTANyqTi rWcLM/o1//Zwk7rfj6qrOFzyBdNrgRqRkEN9a4Wote0Wy9DvStaicVtiDP4HRQID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBRarJPyVxjsRwLKodgw/s+LKia2 PTA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAHCcY3k4R01ASGtQ74xU wEW7c8LVGzcDNhDQnbxAW/zgof7iu5tOEOQvomh4St/4vA9OkHelvVzDiYOmHUMT EgBbMQOEhbiv/bMAZ+zpEV4TzL88GqayJVLAymhfLqf02xHPSJpY2VNGE2e8TOt6 NZjv7vqBsyd1O0BzI3ro+gA2fCMdHXM+xlhlLZtmoC/GwTMjfquy2dowJ0F39k61 i8cGaL2VAXFumCa7noV7B4Zt+MK2p2etjXWgykQ7tR0HQJstEFWMKHS2hfF0vRgH XHLQYekmPEdX9Dz2vsWUwN3HvEw232JGXKKmxfJHfBksg/eKstmGWYhdyhcld1T3 XFhHDs+QAGlbXy0UjUVpaSaii6VXop4dQU5geuEV7LHYEyympfb3v8I2nqYMZ5X4 SOz/gjTRv10QfvH3on12U3mzWOiBqO3SXnt7Wr2ICvclFtu8m7EBsWmBD4O4IhcX Sg8WoawO2R32X43zfq5EGj+ZByeBc4lH30Nn2blbKNCclby1pSqfIKV4dfIc9pZl jcLPUseL3zHG8QCSquP6pcDtNkUzSfQxPnVbJnPYzIEUXmHbpqH9a06QP7Bt2UDy xdqgoh4kJr7O4hNzo0pF5KHEwdBO9br42VKZ1v2An/xzd+1nq/Gdt9V86cj194IE iQlCRnL8bobByhhPXxYRW7KN -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQIoSQxDlWaRqFL2VdcntHZzANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MDIwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCy+Eiq3L1pkmUaj9kPHq40URFQAmEVz/DnBwo86jfatpIS KNcDAu8hNI7PdwHPJRiDMIa0hklSVP2AWg0dk30NUxPQDTpCw7J1+UGbAQGDIggL UIR6rbNxJoyX1KV4SspSys2vP81eBP3CZvhFoGtUd1vqyq8Arus5bhgBhCHohpFj 946PBK4r4NBhBCTsoJ45BACaG4ho470dMiJgGhFFT6vjm5GDW8tVFYtDymGAgz00 E3Enio7GdwVvButr1q6w8LH6H6UJMRExu7b5rsDL5xkmJ1zxJkmNCZg6zpCpyrFw Lgs9Nam2qk5c0AfTVgLBesrvY93HrX/oBbDPhDO9GEMPbkWbWj3duqy+oPFSfeNg RAaFWXvsBGQXu8ED3RtrFGbNzqS92cKU/L2SqUR4U/nqMvLXX7EDdzNMfrxWanmX meNLx8aCz0gDJvlX3WmUl5YTvob8jnXbr1ebvOCoi/qfdTChFiPpzKFsbZXxR/mg TGzY1vHA41gEX3RCEqEkHStTbiqQhodobsv5wntjilAm+aGFOUuksz4CgDpl75oA Ps+kIPthmDDqYK+Bt6u7ve80z381/39QWmaNjFVr2HguP7wK38g5g1sr+T24aY99 vvHXvzCs1/hTEnfWkZkhrfeKk1r2xSPPHwIWLnVlE4Ahd+1GYQDDLWRX0yg71wID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBT7sDL8o7VjKDMS0+6fB/XUsaCL vzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBADsHbIm15FG9zvbvNkyE R/68VI3sa3IWYgrB9gSirsMGuoF+GVnM9RZOR/nAsI3ZRxwZsJUqiJFEHVDh+9AL wX78oTiMamiu4L775oqliL0wSQz03N31RkrNlIJ/gIuv0hEYcV+fFc7E0iaJczLY 5c8q/DNy4XUziXy/kKbnOQOxL7JUi1vmd7XkMpCHGm14XqBcEdMXQKFWsxsbwy/r lmok2EWGfj+vehfz3o0I/uFPfa/f/osUBodr9QePLapW1e4NB1RwmLb3wYTyR6wa NjXaaeA74b1Vq/ERwky5u/2iYo6VNCHUIZNWtHD0Ug/A7n5SF1qkqG5zdbYnEBEb rKh3vA0MElPGi7Opj2QRJH5Vu6yTZgE3LnDnZr7VYSJrJHVvSzrnoM232zl7raN2 lqr3cXUDx8Gndtmb4G6lB686/rX2fo2+G231w0MrQE6L2iuAxgfV9S484hgLiAqr uAsta/bS4xbDjEDd1lt/2M3ET9gn/cDSB8kBhYfH/F4Jp3sLdOAQvGGFYPGlYvt9 KjnAiKXMevHmI0+PYZntAFaf5ol09M6fL6OOxPD6iEbDLwbKzjs7dux4TcBZeAxY AOwpbKfAzpbP0/xnGkRcBYdN72tJRgVC3Dr//Vv4XjGrf+PRGj5oG3EJtKPSjyf5 n3xMTlZ+3kEGTMIB3suZvBUm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQJaNRew3USXMZW3SBQsGgzjANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNDEw MjQxMDAwMDBaFw0yNjA2MjQxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE1MDcwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQC21x/pEGGdgZg7aKAhwz2n+3Jwbxdgt06hLWWq6K9UMz1M /aY3N/kqGK0N5nxie/3Fi4w+4L7EZEnH/3jtiQQHHpStAru+UzHpRxpqTh5x9iiz uogBpXpxX8L+Ee5Z6eV5EZbLWH0hjiNQFaPPwSOitJJxN0wSrsEDu8/XdYRsLMTI wK8RNtRrwfYigU2HBLY7Ad235ax2dD/A70TDjzr1H8gm+pzqBgkYkXZLZxP4BCfW 9+9kkXPmGQcITaLVkWkmiQ3rUlbKP3ljZ7SAbQEtMf75DyxIYHvIR0qIrMiOAEL3 4jBGQXu0tRrStH/7jv5z0G/dX+GNOTpRwCD2Dba0YjKbHoQ8piCAk6k77XQK0TUG /pGpAXalAzx2oUHi48rQys2yedkStJSjVQ/ISb6sonu6Ja4zsZUb1iXAG1n9im1P cbmwHJ72TlMeWXFSjQc1WvU8HM8/4IYvVwc8STl4amf2WHe+J/dG4MY6GkWQ5TJA SxSnRkfs0VuB41gTiRwemTQ2CbgbXxO3AhZUeTMtOQA73JgJgZwNnTCnbl6fCHQA 7+nUxRUS63uOQdaS7GsOBC9jN3m4KPN12qwyThv0vhb/KCLE9YQvtOvgeDQl1n/e 6hRMUJNO/h7lfrFPDTR95GhqaPuWYEDETi+X2D9W8a6Dm/dzPUhT+bshO9p38QID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBTcB4Xzi/U/WtzeIiCVFqhY2+0Q HjA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAHi5rGd8jF9JKvR2JDVj 3woraMC69RF8Gf2t5WfEu0802XvNR+uJOjWi1fy196+t9YAhW+sFJdKt7hO4cUoQ mKQ/3xButaCvBUxA+E19VDl19estHH20ONiOjD6rKQ8p6as+W6FFxzS3tT7KBFWD GhXgYoUdl6RIdHem29EErtVyVUpJ4+Qf5/0hbMOW18Kko/8jrbhqKgON+7R9hjk1 wS7+k52nwH0jeALhacOrmn5VGzvv1W/5ylvTdw3nMB9Bb8rpO3CydhjanRIvkbhx VgmJdmIrdr7tVGcarJWWSNFW8Eay/05EFZM9uNDift7URLd1mZW6DnHvc0EQsNFX HpxlGClYvfN4pMOn9S70Mo2wAR0IBXeXd8silo4I4caNXV+/7SRUhNN68FsO1l4v PFJ+MxEQPNMp1GfFtt1eMApU+g47IZqTD+LbkKutd3ODXebS43Cp9j1s3avRR9Q8 ZpUDw2mzn9Kwiz0sQCnSNAq2TFe7trLKkcVqLvdiKVAwktq5l/G06Neb6VG4o+l0 0ddye45XD/lSYAOG+tICwRx6P7yiDylVUMDfedE9SgI/7+aymdbET8KwveZijlj/ Yd1Qm1/gbnCgkq7hgYu/BuONFgMn+R3osSEVAWp3exw7MzL1sm0hK0sVPbbPg8Qf VV+IM+HHyTwCHwhD92Ms4CjZ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWTCCBEGgAwIBAgIQQAEzU+QAAAAAAAAMyl0baTANBgkqhkiG9w0BAQsFADBf MQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290 IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw HhcNMTQxMDI4MDczODMxWhcNMzAxMDI4MTU1OTU5WjBRMQswCQYDVQQGEwJUVzES MBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRwwGgYDVQQDExNU V0NBIEdsb2JhbCBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC AgEAsAXbyOuMxG6KIe+OTZxxCh9ScO1tgpyXxddMTkVJy0BCtRI0bBnCdKQxX4UC l+xDMwpT0pyMjre4edsr1WryjmbE7isBB5LUs9AC31D2Va9mDsvgR2AvKzI5NVI6 KIP4exbGGLhi1kclkc7wGRJNrWP10z91XynwoTAcKqCYphW97v0ZNvDikUOP+srW ECdJTO/dwfGFcJvK6qhaQ/xthm9z6TdFqfA2x8yIdR67bAb/m2s+F+xhqnF8xh2i 90npFbU81qFh9RH3BW8d/RG+0DAHwimwCU4m3OOiqJFqH8KRRYhc5Zi4caUVGcl8 dRHMcHRPLZsdkUT9Viig/ruGasj6XAtY3MZLdsirItlzD6X0WgKJP0+eIoLuonRT Kj1TJ2kdbI4yLGQAJmNhNk6jRrc/fbMtrG2QopWizs/agucHNBmW6bghqil+pji+ jilKIWZ5H7PDtQln3tbUB0bzKtrmIjdgy4G2D6AP6ciVf79VkQV6zz0VwG/eCZQB g9c0G8xApfC4m2fVmJE7p4R4lSakWgj4K3S0AAQ837gUjujfqY1sZ5IzHcC30uyS yL4JvywpBW8Ca57vvL8qvFvAUI9BcHGHsk23BKmEozKvru5rF4uysf5s4ZCMiKiX SM7ITcvzBs9fagpCsR4edy+OoOaSDgb8BSLSJuExUX0y3A8CAwEAAaOCAR0wggEZ MB8GA1UdIwQYMBaAFGo4WyaN3ota8k96VIMZGOMINaa6MB0GA1UdDgQWBBRI283e julJclqI6LHYPQezuWtmUDAOBgNVHQ8BAf8EBAMCAQYwOAYDVR0gBDEwLzAtBgRV HSAAMCUwIwYIKwYBBQUHAgEWF2h0dHA6Ly93d3cudHdjYS5jb20udHcvMEIGA1Ud HwQ7MDkwN6A1oDOGMWh0dHA6Ly9Sb290Q0EudHdjYS5jb20udHcvVFdDQVJDQS9y ZXZva2VfMjA0OC5jcmwwDwYDVR0TAQH/BAUwAwEB/zA4BggrBgEFBQcBAQQsMCow KAYIKwYBBQUHMAGGHGh0dHA6Ly9yb290b2NzcC50d2NhLmNvbS50dy8wDQYJKoZI hvcNAQELBQADggEBACkLbsSU3GJZk3paTF3cmT6OqPv5oI8b2SdwbfguXkhpYRdA EImqA7gcy9+8bChUH8Uh9UuWv/xMR8oLd8PMZntvuTYIafnBke2P1p6iIuiCt4nI qtAg50qsIysvT/ZPFGvxekWhh8hx56ekuYBryc7NiiWczdMJpTL6JNFRfzwxmUfq H6dvboTNrtiuNWrWy+C+E8GiMcvuH+km37cGxg1FCuerRVcetwGbMfXyBUBFhtgC G9BLIdsgguMi6U/jXSvEORIXKMa5Z7F94bJ8duU2hNp0Xqw4tmv47qEDxLDEXBJM bwbaOkRltjaXDBh50EaXMx+rUqjO3le0KBM4t6w= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG2jCCBMKgAwIBAgIQRV864VwhzbpUT4KqR1Hr2zANBgkqhkiG9w0BAQsFADA7 MQswCQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xGTAXBgNVBAsMEEFDIFJB SVogRk5NVC1SQ00wHhcNMTQxMDI4MTE0ODU4WhcNMjkxMDI4MTE0ODU4WjBLMQsw CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRkw FwYDVQQDDBBBQyBGTk1UIFVzdWFyaW9zMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAnSAEJi37LWkwy9mTf6XlrtRwcu+UvkVr5Y+yC/m6M4Ylr4bxwNjb tj++8b6JBab9wyHhktVSIBa+diYhfsHsWVWgkOlSzNIPqTPKOmjYtL3UJuoW3Abp DNZJEVFgEolkCg51wXKMjO7O5CfJwIA3iV2fbeeR4YAOms/1mqm0LSkrWiwwlYF9 Vn8aqr/eAnT/d8KdYC5Z/9Mc1azWHWN7zJ6MTduZ9PcVjMm70iviHaohgEUu979b y23acx69q7qLPjHkYoGhf2ft1tQqYmjs9icgwPhrzLyy1zzXYy0HoeFns4bi2N+M BTmpf/i8HZOK6By3MS2UlCsjXhHhzamwRwIDAQABo4ICyDCCAsQwEgYDVR0TAQH/ BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLHUT8QjefpEBQnG 6znP6DWwuCBkMIGYBggrBgEFBQcBAQSBizCBiDBJBggrBgEFBQcwAYY9aHR0cDov L29jc3Bmbm10cmNtY2EuY2VydC5mbm10LmVzL29jc3Bmbm10cmNtY2EvT2NzcFJl c3BvbmRlcjA7BggrBgEFBQcwAoYvaHR0cDovL3d3dy5jZXJ0LmZubXQuZXMvY2Vy dHMvQUNSQUlaRk5NVFJDTS5jcnQwHwYDVR0jBBgwFoAU933F/cTomht3ZKf1HaDM v4dgmm0wgesGA1UdIASB4zCB4DCB3QYEVR0gADCB1DApBggrBgEFBQcCARYdaHR0 cDovL3d3dy5jZXJ0LmZubXQuZXMvZHBjcy8wgaYGCCsGAQUFBwICMIGZDIGWU3Vq ZXRvIGEgbGFzIGNvbmRpY2lvbmVzIGRlIHVzbyBleHB1ZXN0YXMgZW4gbGEgRGVj bGFyYWNpw7NuIGRlIFByw6FjdGljYXMgZGUgQ2VydGlmaWNhY2nDs24gZGUgbGEg Rk5NVC1SQ00gKCBDLyBKb3JnZSBKdWFuLCAxMDYtMjgwMDktTWFkcmlkLUVzcGHD sWEpMIHUBgNVHR8EgcwwgckwgcaggcOggcCGgZBsZGFwOi8vbGRhcGZubXQuY2Vy dC5mbm10LmVzL0NOPUNSTCxPVT1BQyUyMFJBSVolMjBGTk1ULVJDTSxPPUZOTVQt UkNNLEM9RVM/YXV0aG9yaXR5UmV2b2NhdGlvbkxpc3Q7YmluYXJ5P2Jhc2U/b2Jq ZWN0Y2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnSGK2h0dHA6Ly93d3cuY2VydC5m bm10LmVzL2NybHMvQVJMRk5NVFJDTS5jcmwwDQYJKoZIhvcNAQELBQADggIBAIw9 KLTgfg3zblzaXHc9gGQeTukSuMnmsv8rgKB4PYRMLGWLL9zxYyvn3VJB26/8FwuM moTyCdRdVqKe+YJmwIVenF7qg+d8Ro5+X+Zj7ati70ZOJ2GVgb1NAj2pNA+Z+eZr VpUDn31L+3ziThLvpAtEtTx6ATFbJmEgkpR1AnbWzvuswwUIMUBspR02niCIzqCJ Vm2u2Uy9kHw+diBJRuwVYppBZavgn7ECNO+vKeIAKZme+WMd0ZQThkDRYIxFFwYh WFoc1TE+Lf0nVbEa5j/v6oVcauP+2dyLjH/rTdVhh4LnI/DKPGKHduQ8qXuhbxgb Iiu8jBT/0n3dWQPFB3ou9+sHllT9uSUVGrtK+KyjgGLH5oe8i4GObH7GJUthkUwE YzGijg/WmKvm+jg0gnlWT7HiU0K4fEWldIBl9nNah12ySPVN63q/8kCXS3JR8cM8 2ZeszLVntPs64itV2WKrkrNA+Ltu4Z/UTY4luH+IRevo9reT6790MQvYrCwjSsuN D4fXI86/mGESGvhbwECmphe8L/jV0uZ01yI5mmghedBr5WqKv64EmIXNFVZ23+mh 8RFCgqPZsatVaVoBQq1FevOhPMjEvxiMgzPXve2A3gSmng/UKDcKGzFbyL+veSZh dP854mPk3IPECYZENqAYWXjBltm8UDRmUBt1wpgR -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFlDCCA3ygAwIBAgIQAViMOjUHs/iXIxx2t++F3TANBgkqhkiG9w0BAQsFADBG MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNV BAMMEkNBIOayg+mAmuagueivgeS5pjAeFw0xNDExMDgwMDU4NThaFw0yOTExMDgw MDU4NThaME8xCzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRl ZDEkMCIGA1UEAwwbQ0Eg5rKD6YCa5YWN6LS5U1NM6K+B5LmmIEcyMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0JMBh1z5ihKZLtSptut+daPq6CIovna/ 2uswQNsecCE4v+pEZ5djMblHQwzu1ciAav06jGTK7c6lRB4Sbb82hoXUUnZ5jBao RDNPM3NagriXz06P3Mm2FJXtzWKT73Nw4gu+TnbdtLildjf7EOCpZFUC76e8svcO tfJpRR0dDSui5xNH7E1zEnJBCL3hvyVnhWu6KWfKyiAHL25IEK1bEQmHAZCePcJp eiSDPE9URMF8iiurgXivk2Hi9NKKHOByKr0AlNUxWM0qjTv5FivrmrqvFnF5+oPV cZUWyDbEocauums8RjgYaqaD2qv7mCU3uaOzCWIijCPadMXtHXUqOwIDAQABo4IB czCCAW8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6 Ly9jcmxzMi53b3NpZ24uY24vY2EyLmNybDBwBggrBgEFBQcBAQRkMGIwJgYIKwYB BQUHMAGGGmh0dHA6Ly9vY3NwMi53b3NpZ24uY24vY2EyMDgGCCsGAQUFBzAChixo dHRwOi8vYWlhMi53b3NpZ24uY24vY2EyZzItc2VydmVyMS1mcmVlLmNlcjAdBgNV HQ4EFgQUMNp0hvMokFae1zExwr1ZzZMSOR0wHwYDVR0jBBgwFoAU4E2/3JtBXRPo ZPCn6RWk4YHBujEwRwYDVR0gBEAwPjA8Bg0rBgEEAYKbUQYBAgICMCswKQYIKwYB BQUHAgEWHWh0dHA6Ly93d3cud29zaWduLmNvbS9wb2xpY3kvMA0GCSqGSIb3DQEB CwUAA4ICAQBbCJgtcYOHa2WELfGAcTXZawWomqwm56yyVnowYt+4F5chlEdx8SRu aYPzurYbMJuY0u1fs7NqmFw/A/oXbNy0j37h2fOWVVVayGQIPtw8i3yAaIGTyEp5 lHQhjKebBq6SyRzSyrzQzWNst8pZlLH51m3KR1vs2zXPWcXmu3zyAc7p+Bghv0N/ /wo98IKJSXHscLMh5bXBVQLyd/et/YnN2MzHXJHN5ZrSby8P4WAWtr2AC0bl3922 KUnzHCBKIM4VAxNXOhuXt5pn1yoyKbFh/xGbpnMtFBud5KEPCPR7umQRiESRYsLy aMx0INAHknGLevWUKdAF9PTX5Yt+LIwNiYmZsIJYCA2vEmhXWoLaz6xKySt6jDhG 2ITIuuz6dY5sJMV5eDFnrWMAR3qTHBy5TGF4nWtsHuADhx0vkTdlodVxZaDI5VuN DjCfhAvMpDvMQc5I4CuSLTtyzUMMsIKSxlG58FQ/S0nVfqQlpJDzt+7pSW1fb0wF tyQjVsUymi/o0Q8CNJxvKGDeQiAvYwsjd1kWxKpiV+uXcqLlPUTdnv5jP7oNE2uL rCk64HjrrqEDIShimAuTKxXpNUbknxGehrtEIQcXfsl6MDJhmPuwx/9tzdu9uOYy E9MX9CFzVIWohrOAOVFtWcYTzi/LhyTDIZebcHNeaxdjedEoLB44oQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFrDCCA5SgAwIBAgIQOPZFweJdkSzOOys5EjF0DTANBgkqhkiG9w0BAQsFADBV MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNV BAMTIUNlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0xNDExMDgw MDU4NThaFw0yOTExMDgwMDU4NThaMFUxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFX b1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhV29TaWduIENBIEZyZWUgU1NMIENl cnRpZmljYXRlIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA47SA DmswUIIvH+edv/h8QiXtrmHE64aHI38RH8CTXxuSkB53jLx29/sKpdV9rNxLGNhY Lt9GazQPRWRghMLrmg5R1CpUUT4nO2Rohm98awA8mfZMqEUnraXLKzftWcNSTE/e NJzyt9H6WMvlYp5VRly3xY04JDXvlyx8ZRAN75+XCNXlsxJ6kt3+iA+PpK+9xdY2 90Eb6Fndhv81v+3k0aCTblGomcvf3b5xiMPasWXMe5XEZo++TgZ/m1OMazzOlyaC Hxcwuj/I3swLobTvEj2Tywgw5xqYl4A6JoSP/nN0lVMPUbKqiVf0lkByEx3kZ5hO j8ZAC/UdDEUt4NWSgwIDAQABo4IBdjCCAXIwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMDAG A1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmxzMS53b3NpZ24uY29tL2NhMS5jcmww cgYIKwYBBQUHAQEEZjBkMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcDEud29zaWdu LmNvbS9jYTEwOQYIKwYBBQUHMAKGLWh0dHA6Ly9haWExLndvc2lnbi5jb20vY2Ex ZzItc2VydmVyMS1mcmVlLmNlcjAdBgNVHQ4EFgQU0qcWIHyv2ZWe60MKGfLguXQO qMcwHwYDVR0jBBgwFoAU4WbPDtHxs0u3BiAU/ocS1fb++z4wRwYDVR0gBEAwPjA8 Bg0rBgEEAYKbUQYBAgIBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cud29zaWdu LmNvbS9wb2xpY3kvMA0GCSqGSIb3DQEBCwUAA4ICAQCWWt+WkRdokF0vtDIVgAMD C+kct3Ns2qj6lN3dPjQrLoCTbPqmZ9MbeoJBzp7/P++yg2qe/DL9RPOCZqrPRC+z N0HweRLjAieGSJK+z1bXy9fnHiWdQdsK5zMSWK2V2J7Ut5Upuv7/34Ckd1sVYg9p +IdtdOqFonZdn5UuA7yK+YqsgWRQ8gtFS+yXMDl05ad+FiRiK1DxXNhPzS6iGCWj zvYfYN0V3iAVGw5/r4XZQKwHKjTdUbAaqOYOn1/bRnDm9dklHPAd5UKhLSKdbhHJ jaZlvA6qdnPIVmAv+z+GuaX1M+/VEx9JTDgHnlkiWsdO2SUkulNw/GMqVFHrw0tB feToPCyldlq/2UyoDa5SbqVdmD1skG14H8NwlYYHP1Tj6oqBZGKajzGveyp+kiLD jsxTrMecmRErSD9ScStuwOGzCuUDYteJGChMCo0/C0WJgYuIpJPCf0TlHltAAPwv zDv4ankx/UQUto9IhUyrCp27Nwr8URng/llqO49gYqcHgq8IZqDy2mAC6tg0fldx obX+adf73Vqc8//E6s10+pRw01iSzq8S5G7r3bivHeJl1EbqCz7jaA4KTCeDUJEG xnv4+psm7SwOZ7hs5SyYbV96KMOEPAMN9+ID4ZTCWCf4TYFZL/F8YclXXb3cnIDQ ZN98h3iF5pSLcIsFR+TIew== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFozCCA4ugAwIBAgIQOW5mXkXjp5e2l/z+MQ2S7jANBgkqhkiG9w0BAQsFADBV MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNV BAMTIUNlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0xNDExMDgw MDU4NThaFw0yOTExMDgwMDU4NThaMFIxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFX b1NpZ24gQ0EgTGltaXRlZDEnMCUGA1UEAxMeV29TaWduIENsYXNzIDEgRFYgU2Vy dmVyIENBIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuP82QaTQ KXvX3KppHmSFAMbUO+FiC5eQifBLLFrJKyLeorXSwNWO05JA947nmX+ryKL03inu EdEWwrbPFHkNVChaOPuM2QAUuX+0Wx40FNl0Gr/ykvEF+WkS3QGDkO5YkwS0qWbM yBAlCetSNTMUJOJnIDr4qIe2z33UWNl6dFmOWE+ML8mR+SIiM0ezwabR9OaKq3IC 6v15FnQyBSuLs5p+CCmPqyBRhD5qEIaxmqOtjU4A7/ZCU9i9q7lJN5U5OBCRMsuw XTp/VImfj+6/VvtcUpiS4KGEOyihYju/PSFPOTI2ujGXw6cnhwW10THPmUCCeYoh QfTBf2zMhx2adwIDAQABo4IBcDCCAWwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQW MBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMDAGA1Ud HwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmxzMS53b3NpZ24uY29tL2NhMS5jcmwwbQYI KwYBBQUHAQEEYTBfMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcDEud29zaWduLmNv bS9jYTEwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWExLndvc2lnbi5jb20vY2ExZzIt c2VydmVyMS5jZXIwHQYDVR0OBBYEFCVj1cFjzeZB4+9lcMETuo0jdIvxMB8GA1Ud IwQYMBaAFOFmzw7R8bNLtwYgFP6HEtX2/vs+MEYGA1UdIAQ/MD0wOwYMKwYBBAGC m1EGAQIBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cud29zaWduLmNvbS9wb2xp Y3kvMA0GCSqGSIb3DQEBCwUAA4ICAQARS3UCfDXiC2ixcpYZsDezmfpAL4G80MrN N4CUYxSlV7icc3rNqGG1tc0THG/PBRPzALWFRJblkcZAaTRugi+HDbo2+Wq8ngoF gd1zGgxprI/EAz2s+wWZUXlZgQ0p4FOC1jdiIna/CKyKliD5LklgPR8ikQS93yE0 A6rnd2Lnt+0XtybOPLxEJzB04gDQUzPNPnhaameUXkwCSRxBP3xqC8z9+9LAvtGv TNLQ1G6pVbQMmecftvWvqCs1WPts0O0hBZaW9ouIRRfUiK0hbVOC98yhXPJlMbTB L3VlnZn3PUdrl6tPb4pQjrLFZLuqcZ8b2TrL8IxXPZwG61qc5KRrmwxHnAjqxnnO 20y0Tis9GYVuDaINrVfkJMhV/K2Ogk12dzOWL4tY2R9mOyVRKMN1OhhZFsO9zqQe O2suDDgReKX/QnXmuCf75UbVG5CrqIORKTgv0Y2OewYFNl4zqnVZ/o6v9/XF0O2i j/eOrubc0g1Yh67LR6ctJUFw1uW+3TSOBqNFPH2HtMfORtoC5Jn0PR7ZbjuCftBV p/Ed6yPB6pJjlEevBL9jTVP7OkMLPBXO7t+8/UTdP2kM9pIBcpoH/KTx2kvHIp8e z4UpWMiVDwTdFqEPtyEbF4dKsSz6/w9wYrOEW/b7rdgtFpFqkkoZFgNI4PeJxcsK Ah9qz1oHfg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9zCCA9+gAwIBAgIQa4Pjthqb7yqHlguFkB5a4TANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQxMTI2 MDAwMDAwWhcNMjkxMTI1MjM1OTU5WjB+MQswCQYDVQQGEwJHQjEbMBkGA1UECBMS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD T01PRE8gQ0EgTGltaXRlZDEkMCIGA1UEAxMbQ09NT0RPL0hQIFNlY3VyZSBFbWFp bCBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzb6lp/a8qlWW /L3U7HrZ9SgdQH0YXJpaIxj4VhR00Puv/lH6lW6Gp8Bapu/yVTupSnKZW2eJJNVf 6iubWKXVKH0eSOsLxuoEW1SxB53cOhc6rH8CyjZa8O9RDixvRXbPw+XB66G0GjWy mhVQPRLBNkbTrHbC17k8g4xoGujoAT4TnZUPNsgy2p5m/+s28twGA7sUq8SDGVo8 vqq0MwG7JOXwnX20oajta3kCB6vf6aujmQW0WhofeLKN4wtaT4j7OwCwXBzHTGGj Vk5LPt5dZXPMYnzxiEhKNboHV/ohf4+l33KZCLVg0UXQty/wyg2vml3R+ekpgWR0 VE3q/moRvQIDAQABo4IBZzCCAWMwHwYDVR0jBBgwFoAUu69+Aj36pvE8hI6t7jiY 7NkyMtQwHQYDVR0OBBYEFASBo7b91XUS6Bv1UIBLvRyINGLTMA4GA1UdDwEB/wQE AwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggr BgEFBQcDBAYKKwYBBAGB5gwBATARBgNVHSAECjAIMAYGBFUdIAAwTAYDVR0fBEUw QzBBoD+gPYY7aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQ2VydGlm aWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsGCCsGAQUFBzAC hi9odHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9SU0FBZGRUcnVzdENBLmNy dDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3 DQEBDAUAA4ICAQAvN/rkC9lJG+TYxrqYx+3PVZhh7XDg7LtK2zQIFh4RN1hOWq8o BUteWtYDcyNSqN2qEMGYsKnq8NpmAT5wNqwRCQitMwI6rxcEUt5zwrpKoSVhEv0W hECrSj9wX1CdaKsE+/IjPevnUT1dXf4PgUHOPyb+zP1A8bhXUhBQrijQ0y6shOtm wKOSPMxng2t+mu32D722Td+WDuaEybUHyGOhcZczrLBNF3CJ6QL6sXuxKWIZ5l8g gtD0GCWLKCZ7e/0jMtoMv1gd3ZY/InG39dPhSaXtTQySyMl270uVwbdFM8XMTlgZ wOCkqbQcHTAeVwPc587dd/iy/eTnxg0GzpLOgcXhBJXtN0OOm7soisG34Wigbswq zUKnB+Q2+N2z6EToaaG7y/h8ApkW2TSfuXqQfG02fKEG4v7pgkTR+9rruepGxivf kTQKG6MyoJnsFtZm4dtxkk3re7zpR7f2ZE8GRPr21jLWsrDdjIm/PYeTtRS+81We 8uN95uh/Z7iCsQ5TtWzDDP83XnFJGrUhBmH0+k6pLFik9qocgqtVeu47jlBsBFqc Svs9dbpWHyZ/4BTkwia0Re2y18fk/EwZA3DzpUrNdDzBdymVZBK5Cm5XoCWwJAu+ J1pGz52EfGlRLXaI3frHrl+Fy2H2+RYCBY2MV804pLbXurQeWmwisZCKog== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3TCCA8WgAwIBAgIINY+ChlzmLbEwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 MTEyNjA5NDUyNVoXDTMwMTIzMDE2MDAwMFoweDELMAkGA1UEBhMCQ04xMjAwBgNV BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMTUw MwYDVQQDDCxHRENBIFRydXN0QVVUSCBSNCBFeHRlbmRlZCBWYWxpZGF0aW9uIFNT TCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcA1Hwmgr2biKZ0 a46bkeXyOruAorQZx779CY9Yq7kUDwW4nPdiTXK1k/xkIJJuwA6xzJOmrCuMzr15 J17LviwOIW6rDBSSOKjR6VoPS2kkVHLigD7n6mpJU22Evjo6gP/NC5maYchbOsoH TA05Yt58qA9qsMpDq9fS/AzYKAVWXBmWXh4xlBOXmGUpjYv3NXAtEznScauk9mgi NzMMyu09iDq8G7c1q5oFd5auRKnbAk1BxvgkdoSjg8w2Q2wem0cbbGgfU8QGAy/+ o/wopiGvmcL+p7b7bgYUaxI9H1mrfhB5ScNK+cEFB8kkW7K/0PpXBd4lRHHWTLkE Z9ieC4ECAwEAAaOCAX8wggF7MIGFBggrBgEFBQcBAQR5MHcwQgYIKwYBBQUHMAKG Nmh0dHA6Ly93d3cuZ2RjYS5jb20uY24vY2VydC9HRENBX1RydXN0QVVUSF9SNV9S T09ULmRlcjAxBggrBgEFBQcwAYYlaHR0cDovL3d3dy5nZGNhLmNvbS5jbi9UcnVz dEFVVEgvb2NzcDAdBgNVHQ4EFgQUHmrq3vUvv6jTbMfGP9tsZGDc40EwDwYDVR0T AQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTiyUCfTc7omqF8zw4/ZcUpiGoZUTBIBgNV HSAEQTA/MD0GCiqBHIbvLwEBBgEwLzAtBggrBgEFBQcCARYhaHR0cDovL3d3dy5n ZGNhLmNvbS5jbi9jcHMvZXYtY3BzMEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly93 d3cuZ2RjYS5jb20uY24vY3JsL0dEQ0FfVHJ1c3RBVVRIX1I1X1JPT1QuY3JsMA4G A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAJ+QTFR1oac6PljrKm58L gIdCKwkybREfAj+QTnDTONNMiapn6mZeuSLHhbZB1oyetddz1OMM8iJyU+ktJIHY mlM3opIt3IuTWBbJobyDZYD+doed6H7gLcp0M1lbDVraXPVCNRTVM70Tfved9oB3 E8BisBTAKV/MPo1tFWBDWK2NV8jHItE650zOMXI+sF9EK0oQwzBBhx3vG1WpeMdY Hpu7z7xdZdYb0MT8Iub+iPh4vVMshXLKohejXByEpWEyVr+L8dE0mdaZzSku/VQm ZQyDfNrHfUm2hH/XhC6IlNMA8/oeW99J/yfc/TNiCpImqHk0XBNeZeqK2HPBKj39 oMGOq5/kMT43jvTpjvjIX3tNnD+nrLcS48IogZ/X2qyGGh7FHkntLC2DBj/ipmHh 4CJt/dxAX0DH/Z/rwhGVciR3zAXaLbZ1tIS+AhUVmcwIrzJC1kI6gU2dcUCkjo5M 1VfTjjyrWxpK7aE1kJpdmL7fcBmUWsJKnzV6H5YETONK2YXSxDjDqrUn1S67qbIB XAYQnEc/MYoispbeYRKsVciKV1D1Dehl/gGQQ80nCwsxj7gUTewVWgON3h/HP/+z W8fh7J1c5YfbjS5zWLOGEEAomWosc0Ba1KHxVR+1yVfn/yxGYpKd4tA+7vRc3GWd blVRfCZEmVBCWTd0BC5ZGxM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5jCCA86gAwIBAgIIIb1iJz+4AagwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 MTEyNjA5NDYwNloXDTMwMTIzMDE2MDAwMFowgYAxCzAJBgNVBAYTAkNOMTIwMAYD VQQKDClHVUFORyBET05HIENFUlRJRklDQVRFIEFVVEhPUklUWSBDTy4sTFRELjE9 MDsGA1UEAww0R0RDQSBUcnVzdEFVVEggUjQgRXh0ZW5kZWQgVmFsaWRhdGlvbiBD b2RlU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM2U MasdiWuALHqFFOcafNr2K5PJ5n6YVU3WyzQShkgpo+aKt6Muc0+U6LoYy1yGJNHG jcNt4LoBwPJ9oQtQs75n85Kl/NiJPYvDEj4eMKgLjL1D8urea+LhmKgJWzHSHj4r 6o+/keWsKsFJNqqkeIJygHfRDB2+XrhsQIztyfAKLy4Rl9LzoMj8WAVRF97pHFgO 3Fxa5WrJne6xewBiZTc6q+SOJAOoUD2wvGRZBap/QGI+sQsUVpwXkKDZcAyJ2mif ZwgRdAyuqvkmdXNd7kz585iu70vq3l2tLTaS09JbpPC8tfTa+B4Ftes1QCxNI8Oz 8ldMxFk0XpK1VCAoMJkCAwEAAaOCAX8wggF7MIGFBggrBgEFBQcBAQR5MHcwQgYI KwYBBQUHMAKGNmh0dHA6Ly93d3cuZ2RjYS5jb20uY24vY2VydC9HRENBX1RydXN0 QVVUSF9SNV9ST09ULmRlcjAxBggrBgEFBQcwAYYlaHR0cDovL3d3dy5nZGNhLmNv bS5jbi9UcnVzdEFVVEgvb2NzcDAdBgNVHQ4EFgQUaGIj06nfxSLRVWVNZHYliaq2 0HQwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTiyUCfTc7omqF8zw4/ZcUp iGoZUTBIBgNVHSAEQTA/MD0GCiqBHIbvLwEBBwEwLzAtBggrBgEFBQcCARYhaHR0 cDovL3d3dy5nZGNhLmNvbS5jbi9jcHMvZXYtY3BzMEYGA1UdHwQ/MD0wO6A5oDeG NWh0dHA6Ly93d3cuZ2RjYS5jb20uY24vY3JsL0dEQ0FfVHJ1c3RBVVRIX1I1X1JP T1QuY3JsMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAhplqmCZC TbWu5oQk0KErZzp399Yj9MyTkkO479dOs7WaJJbeNeI5MprnDjgDloLzKa7d5HyT M5ZCGD4x0SaWr2Utz01bPasfOWoTi8MwEJ2SB9yPoNGrJFPYckQe0x3reFgU3a0s PenORb+/pt1TuB0rOgDPvEkMth4KG1LIKVDD+OfJO8vOspTzffa5HkoyB1vqbUEW 0/hGxCnIsnawAenLr7Tbz5fV4MhYEEe/fKP0h72XMe6NiZJT7yv4hNVyd3EfMGM0 SNAxZNTtyMy1wkSE04QMGRvdP2pMv1i7XJe0YABqBLJy99yN5+sSA8NkhijFIZfv 1y3AS8m0HDo5ZvMYeMstCmpsHFtEZX3pX+fjJS8ZeLpmpU2y3OfRroIkjrUMycRY HdI7oVDldF5ZnrmSgFhEbjRrUn/+0CTPBXXX54ujUJTbMMBrCi92LPzD0V30QNay YSCwU5HvvGlvE7W5OyZhWUr3YSWmEWHDavRqZrd1FpJV0aR9Z5nXINnjwvyiZBEX XeI0OXnFOtVH6uNw2CmLnc0ECEQQ57tvHcqPe7uCXj6VXteZ0dMcDO805DpPRLWB Pe/jBLP7gk6x3lxU0HkbkT7oB0UAbVnYPA4bgh4ezxIS/VWVbNUxdVMgI43zzbwK d2VNzMbyH6OVBOA2I3lnOR3hQBvyFLdQeUE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwDCCA6igAwIBAgIIZAw7M94HPGEwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 MTEyNjA5NTIwMFoXDTMwMTIzMDE2MDAwMFowZDELMAkGA1UEBhMCQ04xMjAwBgNV BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMSEw HwYDVQQDDBhHRENBIFRydXN0QVVUSCBSNCBTU0wgQ0EwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDiiP9kEUe+aly0yS3YvDOQVZee4tH1XRykdZFbMS5T UOZ+UHm50VwQYlbqZMJ/J+sU/oLim82nddlI7eEHuAaUDpKLQhkX+Te42qbLx3SM ynj7g26biM3teX5G86f3VwBPNZRuuFyiuA9/SonU2O3g5YMZPce5rEfTnDxyrQ5s QNwcRhOM99GPQyQfMKP+kBHgnyCnh5Qb3bkWXSs2vj7QVLnw1x4tIUd4HN2UXqkQ K5ARfnc4//zer14enJ/ugV3/8YtzCGwZ221VihvWlslLcRAUj4DxmuLi5U90FNIR hzvJf60iKo0LhNb/3GzbZPSu2XSyuH8C9iHMyDKc6QYrAgMBAAGjggF2MIIBcjCB hQYIKwYBBQUHAQEEeTB3MEIGCCsGAQUFBzAChjZodHRwOi8vd3d3LmdkY2EuY29t LmNuL2NlcnQvR0RDQV9UcnVzdEFVVEhfUjVfUk9PVC5kZXIwMQYIKwYBBQUHMAGG JWh0dHA6Ly93d3cuZ2RjYS5jb20uY24vVHJ1c3RBVVRIL29jc3AwHQYDVR0OBBYE FMD2elu+fAjGrQS7SGFFsPViV6CzMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgw FoAU4slAn03O6JqhfM8OP2XFKYhqGVEwPwYDVR0gBDgwNjA0BgRVHSAAMCwwKgYI KwYBBQUHAgEWHmh0dHA6Ly93d3cuZ2RjYS5jb20uY24vY3BzL2NwczBGBgNVHR8E PzA9MDugOaA3hjVodHRwOi8vd3d3LmdkY2EuY29tLmNuL2NybC9HRENBX1RydXN0 QVVUSF9SNV9ST09ULmNybDAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD ggIBAFC7amLza5axPRcvdwpiEVI8D5C+11XGp8IZunCE1FwyfXWHa2wDPceLV8K2 XZFHEDDp8LuVGnJVFP+1rFlh6tQzpxcH0kSG0Z0jGI5DkairkVkeUp32iP/1pbVT wUaCotcJVLS7bL0i9K+WSLzuZdnNA+TMD6u53+eYWIWJpYhV0F+eNRzcyVH2Wast vsnGyKcejMPWLf0YTHvnbVJ9xEq87nKFkKorTtjWo66zTjNeIKmdgGWEBSSlo1yJ j1HFkCNB+v3sLwN8w4Rb16cjhPxxr8dyPi+uohkrzto0RB3MmlXWbNBpMnwqmYmM A1SUY3nT9XoGbrenACXkoWZKvUSxBycarGy9ukf8QZ3UmCpvuCoCkMwIQbin3sSu VI/h42gQxzF8a/jBC8d7EvYU9QiXVKGgIQudEOFJcHjHYHprGxTu3YSp+NqPakwK /tmSY9iodGqlA/MDAMWzO0/98V6GoX3H99UlViqKjaMXFLhM6p5+Jt2GLf8u0k2i FF+2R0ayHk1J0UogU7xKLA8ML3WVYyn3Q6mNyDb8rvF4P1/171AHb7IraaAZc6RF m0aLs7/5n954TlsieJTOi75JZ99czHZiuy26CfwirXaC4U18OiIjnJfcCDMCrf/M dDjjl9AIteXCarVW14bJfC56KcBUiwWeCsRbNro0dSqlsRs3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFxDCCA6ygAwIBAgIIcSKYO7T4aWIwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 MTEyNjA5NTMwMFoXDTMwMTIzMDE2MDAwMFowaDELMAkGA1UEBhMCQ04xMjAwBgNV BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMSUw IwYDVQQDDBxHRENBIFRydXN0QVVUSCBSNCBHZW5lcmljIENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtju9uNmiLU9Ml/m96XBPIQ9wMVaoZakOC28Y Z6LQtn7+HlGw4llKByEbhqIjAS/jvN7rlUYrh9KMEdusbyjQoajCCFI13VHtq7G9 DKV5PgrvrSYZv2u7o+qmbNeYIknJt+rj7wnePzCl7q61QNKdT4qbHfe6bGMkiDOz qCu8c6uBkt6OT4AYRfjVuY1KjAJHykbedMY5udecJRXVfl83PIEb/P+KZzFeacPx UrkVOk+BB3XtOeM2ShN9tdWzo+yFJAkLqgPieVEBNd3FHi8ePpEgs6Sq6NLXwUJI rF+CAxTLxsdOZUTPrW5hU16jPwzrFaVmxNwOoCjjqU93lzg5dwIDAQABo4IBdjCC AXIwgYUGCCsGAQUFBwEBBHkwdzBCBggrBgEFBQcwAoY2aHR0cDovL3d3dy5nZGNh LmNvbS5jbi9jZXJ0L0dEQ0FfVHJ1c3RBVVRIX1I1X1JPT1QuZGVyMDEGCCsGAQUF BzABhiVodHRwOi8vd3d3LmdkY2EuY29tLmNuL1RydXN0QVVUSC9vY3NwMB0GA1Ud DgQWBBTT/u5hgMCZkFlt1iRV8v/A6ycX7DAPBgNVHRMBAf8EBTADAQH/MB8GA1Ud IwQYMBaAFOLJQJ9NzuiaoXzPDj9lxSmIahlRMD8GA1UdIAQ4MDYwNAYEVR0gADAs MCoGCCsGAQUFBwIBFh5odHRwOi8vd3d3LmdkY2EuY29tLmNuL2Nwcy9jcHMwRgYD VR0fBD8wPTA7oDmgN4Y1aHR0cDovL3d3dy5nZGNhLmNvbS5jbi9jcmwvR0RDQV9U cnVzdEFVVEhfUjVfUk9PVC5jcmwwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB CwUAA4ICAQCnRJIWmfxLFEVBq6tet+FhU3iu0++RFzjmaVPFFKpcpYI9u1A36OJN F/F9e3oqSPtH2PNM67p7x/0xQiresZ49NJg1rNIcVolamcmOipv9jqczrzCpx6mn dxA9zI8LzMHSm2hSCFxsgsKJyLRQq++PfCAOsOKjE4TL7Ai/qsDdVD1B0vT8JxL9 C1ciQgD47zMjwsjBeAh76Cbldf2jF74SEbzxkxTj6NOLvV/Sf94hKMcxqtquSUdO b/r7xxaC3SqBxCTX/r+nHuCPqsES9YFRhI5ta0egpkRWa7YMsOh3CBTWxcSh4Fq6 RY5tWIkAw93QNZ3hBZ+i3rLL7+6VwRoVgpVJDQESCZNKbua4nCgfsI6EJ3EchYHe PBmR3Ezv3XPdNQ8IUBqPDvkwcMCQV4sfII7jLD7qbiO2Qmynj/y/8T9iPGe5+Aao x1OaHprm7l7NwAJe6XUc4v+XNN4cOVpxBEUJeREEBdd3ZLQP2I+zISlQBhV0QVy4 NejrpMowTPHWBa8JaNDO1XZS+XI1uaii4rMPk/PI1Hu7oKzc9VqtatpHNpmhZ8GZ J+1ldPwuOwOmqRqitAdWWZfDVNl1SB6WLRwLqa7hbETGuzLMVtHL8bqMmzxgObmm OAv1FH3tdcaEW7+RIHpfixFAAbOWbMTpZehkxY2VIyLvMPtbuN3ByA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFyDCCA7CgAwIBAgIIJofc/+DvJnowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 MTEyNjA5NTQzNVoXDTMwMTIzMDE2MDAwMFowbDELMAkGA1UEBhMCQ04xMjAwBgNV BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMSkw JwYDVQQDDCBHRENBIFRydXN0QVVUSCBSNCBDb2RlU2lnbmluZyBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKoB4W5bLrIBtdxTGykwm/1iVganSwLm eyKBHVR4c+L21i3vAx1c2c9EFddopBQF2aUaSYo5K9rie4RRHRbF/fR6Fq/GhDb7 w6f8CZ/AYcSBUUxAng8riWOuyZQJpEMzt92irg3zYGl5HzAZVWM7yOk0HVFrHc80 aj52tbvMQDHr0MQpnbHGjo9TPcd12Ny05F3Gb58vYCotBthDxwqs7SYOClS23yIk cJYHUmAPBATSpWtYlW1xYorTz7icrNZQOktp4wsDD3o7YcXGAYC7g7BswOIFZbWT 2eH4eWQQ3gE+NWm3zED2uT4O4+YX+TNm7ATjm4yn982n1ZT0DFcXhHMCAwEAAaOC AXYwggFyMIGFBggrBgEFBQcBAQR5MHcwQgYIKwYBBQUHMAKGNmh0dHA6Ly93d3cu Z2RjYS5jb20uY24vY2VydC9HRENBX1RydXN0QVVUSF9SNV9ST09ULmRlcjAxBggr BgEFBQcwAYYlaHR0cDovL3d3dy5nZGNhLmNvbS5jbi9UcnVzdEFVVEgvb2NzcDAd BgNVHQ4EFgQUSf2eGi1zljZyfV0etuKBI2nPaOQwDwYDVR0TAQH/BAUwAwEB/zAf BgNVHSMEGDAWgBTiyUCfTc7omqF8zw4/ZcUpiGoZUTA/BgNVHSAEODA2MDQGBFUd IAAwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3dy5nZGNhLmNvbS5jbi9jcHMvY3Bz MEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly93d3cuZ2RjYS5jb20uY24vY3JsL0dE Q0FfVHJ1c3RBVVRIX1I1X1JPT1QuY3JsMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG 9w0BAQsFAAOCAgEAxegRcNnjg6RLFuc4np1MsD+ZFh8arDkMlwT9cyNHVWo4eleZ 6uiAKr06F4cVJvllToaEWjq+vHaFZTpnuhAXN66qsDeMx1dBiLStGzOIOH2l1lLl GcZut5Vv+gjrlm/4lVP1T94txJJY7GQr4mb4mUvYODryoK1sOu7Mck6h94M61nxd wyNmY/+7gBHO/Ji03TqKSQK+9V81f3W4s5KtzBoCnEb8sQG8PrIgw2PqSRDfBU8b 5EU81pkNSN/UaYn0DwWJxJF12tSvn5Q9SPY6VK17SVv1rDq5/0XG2c24FMw8sIQX Ff3K/ZnW599w37+lXkS5W3NyrBDzXK/zAdcW30fYuKtAnfSQu/olQpVZxZoNYXRJ CZ7J0r40ENahDEhN8ntmWXz4DGAvoAH3W1URutXaWhsm0aCMbKvZVrhd1skARfLR TBzdM3omrzyqbvU0x7tTQO/fVlmixyKARt42X+USvr0W++Lw9SoSOwZ81Id2JRV8 Z5t+3fU3x9ESxHL/5v0pBV/jfp6HagCEG1D2h1Mn7f9igwu6yvcJ+GvF3yA+nrk9 7BB5zu1Hmn4w1PGUV/ZsC6wWRtmAylU6JjjxrcRCJRDW+kiwauPaS32IO1vQOVqQ 55CICC21ruKRficCTCfHyY3JHouWTAgo6/tAj0Qq8i9uMZ2i0geRHB+9E/A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8DCCA9igAwIBAgIRAMQj0iGRho+sTuL85KAR0acwDQYJKoZIhvcNAQELBQAw XjELMAkGA1UEBhMCVFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBM dGQuMSowKAYDVQQLDCFlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw HhcNMTQxMjExMDg1MTU5WhcNMzQxMjExMDg1MTU5WjBgMQswCQYDVQQGEwJUVzEj MCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xLDAqBgNVBAsMI1B1 YmxpYyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA6GW/UWo7X8suYIMHqHozBGkyigC12vLP0jv5OjWh 9m+eYM90gTGs8llp/K11J3Zv/7dByYmxP5lic21CoZjMbaDjwi+aBk3ZMSrDRHCK oEp1ECIXOB0bk31XCzUu+jGBOh6S5Q8xl+QX1aiHX83vmP09jJu8Qb7cbuPEkvaa Fe/QbD+8O4SFAKO4CwYZ6LzSymihXIv256JNuEf7p+zyh+R9VJYQr4bEsrjLzAi+ 6ZHmp9AmDvrnEyGewqG87s6RrYbcZbfa0kfV6cxymex0q/vw8/4vlBunkOaaRbPo DyEEGQCgblrQjcClvuihHyfpCM+GKiT/2FaS3htEVee4OQIDAQABo4IBpTCCAaEw HwYDVR0jBBgwFoAUHgz3tmfy4ZImCUXAVTkudz9CSqIwHQYDVR0OBBYEFMuDfWUV r6nJ86ip9GR8eVIFdEBhMA4GA1UdDwEB/wQEAwIBBjBABgNVHR8EOTA3MDWgM6Ax hi9odHRwOi8vZWNhLmhpbmV0Lm5ldC9yZXBvc2l0b3J5L0NSTF9TSEEyL0NBLmNy bDCBiwYIKwYBBQUHAQEEfzB9MEQGCCsGAQUFBzAChjhodHRwOi8vZWNhLmhpbmV0 Lm5ldC9yZXBvc2l0b3J5L0NlcnRzL0lzc3VlZFRvVGhpc0NBLnA3YjA1BggrBgEF BQcwAYYpaHR0cDovL29jc3AuZWNhLmhpbmV0Lm5ldC9PQ1NQL29jc3BHMXNoYTIw EgYDVR0TAQH/BAgwBgEB/wIBADBrBgNVHSAEZDBiMA0GCysGAQQBgbcjZAABMA0G CysGAQQBgbcjZAACMA0GCysGAQQBgbcjZAADMAkGB2CGdgFkAAEwCQYHYIZ2AWQA AjAJBgdghnYBZAADMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcNAQELBQAD ggIBAG+egEUMXXGhkQKIkBk0B/byxk8eyJJwwhJIh+KlPSnQU6CCOMtlp/nikEWD hDvVBzdW78XtPeUHIFHaBSPCN1Q8eF26HU/tgs4SQAssLkQvG/EGw1azsaQAvHfm Z7l+Gm6i8YNREPYsov+kYGVG2ekD32Bna9iYPx6LAGRZLUR7IUxG78qN78kkcmLv 4NfJcMs1kIJ4SluLh7bT8yl9bcJP/0o++2J7tNLrYIVLMK/v84/mm4VqcLwggLC1 qUSTz5ftSf+TXjUw2GH3uMtZ940nj/5z/l/23XOVyu4fKmvaJM1a3yQmrLaLxsxU RkS15+agpC/jQjZ4XouirwhiUIBAGrs2Q+/W2Z4OY+cKHrNnqlFX5kivRhKNdwRv sw/ODZxvsnSVxgZawEZHE3cDQYS3bUYh+UHTFBpKf8mKCyHXL6WJ6cqeYPY0xMLy AkP0Dbuw0j7x1deYEeFy1kpzWBtiEQeWsXt2ijtF0Ig//B+04OBF9ySdGEOC4ALI OEQkNdNPeUigZNIYKc9B8+8rsxe1W+Cv6Qx+M3NDchXjXP1W39le4n9hzAJ9iHGg gunVc1CgRmKhY/3Du6z21xDK1Xez4A+s+DGzN5rCjWkfxu9eWNsIjzTtCs9TKF7R S+ehk1McUDqNkkD57i6QPiKMTv5A1i2UXyFuJCG43FWLwmIA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF+TCCA+GgAwIBAgIQFDWW8kQacWeYP/yVl0GbUzANBgkqhkiG9w0BAQsFADBe MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0xNDEyMTEwODUxNTlaFw0zNDEyMTEwODUxNTlaMGAxCzAJBgNVBAYTAlRXMSMw IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEsMCoGA1UECwwjUHVi bGljIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDoZb9Rajtfyy5ggweoejMEaTKKALXa8s/SO/k6NaH2 b55gz3SBMazyWWn8rXUndm//t0HJibE/mWJzbUKhmMxtoOPCL5oGTdkxKsNEcIqg SnUQIhc4HRuTfVcLNS76MYE6HpLlDzGX5BfVqIdfze+Y/T2Mm7xBvtxu48SS9poV 79BsP7w7hIUAo7gLBhnovNLKaKFci/bnok24R/un7PKH5H1UlhCvhsSyuMvMCL7p kean0CYO+ucTIZ7CobzuzpGthtxlt9rSR9XpzHKZ7HSr+/Dz/i+UG6eQ5ppFs+gP IQQZAKBuWtCNwKW+6KEfJ+kIz4YqJP/YVpLeG0RV57g5AgMBAAGjggGvMIIBqzAf BgNVHSMEGDAWgBQeDPe2Z/LhkiYJRcBVOS53P0JKojAdBgNVHQ4EFgQUy4N9ZRWv qcnzqKn0ZHx5UgV0QGEwDgYDVR0PAQH/BAQDAgEGMEAGA1UdHwQ5MDcwNaAzoDGG L2h0dHA6Ly9lY2EuaGluZXQubmV0L3JlcG9zaXRvcnkvQ1JMX1NIQTIvQ0EuY3Js MIGLBggrBgEFBQcBAQR/MH0wRAYIKwYBBQUHMAKGOGh0dHA6Ly9lY2EuaGluZXQu bmV0L3JlcG9zaXRvcnkvQ2VydHMvSXNzdWVkVG9UaGlzQ0EucDdiMDUGCCsGAQUF BzABhilodHRwOi8vb2NzcC5lY2EuaGluZXQubmV0L09DU1Avb2NzcEcxc2hhMjAS BgNVHRMBAf8ECDAGAQH/AgEAMHUGA1UdIARuMGwwDQYLKwYBBAGBtyNkAAEwDQYL KwYBBAGBtyNkAAIwDQYLKwYBBAGBtyNkAAMwCQYHYIZ2AWQAATAJBgdghnYBZAAC MAkGB2CGdgFkAAMwCAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZI hvcNAQELBQADggIBAIfkDpU4Yj1QLp4CTeI1b5Q5xKYsUdaBx1V/VD+F+KV6flV5 mNbiHQ3KA337GC4vQqJBBHM15eaaaPCgci0YnNhi68wWrdetQ9E1zCFZw/HCsnJr dKNgAWjCPe/4tK/AcJyztnMVeU3I+A3ApYVysfu9HhA6V7uAh1AVyrv6Ivlui2tZ amgOgpMd3qirzm4s3LCPTttJ0Q5oAIrxdw+lxPm8/Ef/yR2Dkq2dcrbPO6HdO3Lw bn0/WtZMeWlfU+WuoixM59yCPg72Y/RqAGI2neC3Na3QM+0g08OcBQGtSjQfdyGs a8egWnsDNRunYmTZ13RwVRWKXXeCWFjI+URbErttSTO8sf4mXbIoyCz1JfVfZzVa ZMBN7y0td5JWz1M+L9FMu/cWnuqWPiGc20C11LGjNfG5ejqc15TE7WOeWDPTR1Mo pXM35I4NZKVlxfSR53g87DD1kvjtwxjAGOoqZzpXOoe1GakMRUA2tBd6FG6GttbE l2QZK1w/t/zMlCfpdlTyG7zOcz/lKbn4GEPGwx5FPUPWVpVIZgeeFn5MWru7ts2n vuFULQzP3Cfl94o9IkNHlXEfX0P/vXYjQnsOt3tr70+4ww9yOx3zBcvUNpYnYXDw RLVTe4UDo++xEwimY7U7uEg3ukwCK+mlnsnabQYKflkSTf/EqonpTlEbhZve -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFLTCCBBWgAwIBAgIMYaHn0gAAAABR02amMA0GCSqGSIb3DQEBCwUAMIG+MQsw CQYDVQQGEwJVUzEWMBQGA1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2Vl IHd3dy5lbnRydXN0Lm5ldC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMDkg RW50cnVzdCwgSW5jLiAtIGZvciBhdXRob3JpemVkIHVzZSBvbmx5MTIwMAYDVQQD EylFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjAeFw0x NDEyMTUxNTI1MDNaFw0zMDEwMTUxNTU1MDNaMIG6MQswCQYDVQQGEwJVUzEWMBQG A1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2VlIHd3dy5lbnRydXN0Lm5l dC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMTQgRW50cnVzdCwgSW5jLiAt IGZvciBhdXRob3JpemVkIHVzZSBvbmx5MS4wLAYDVQQDEyVFbnRydXN0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5IC0gTDFNMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEA0IHBOSPCsdHs91fdVSQ2kSAiSPf8ylIKsKs/M7WwhAf23056sPuY Ij0BrFb7cW2y7rmgD1J3q5iTvjOK64dex6qwymmPQwhqPyK/MzlG1ZTy4kwFItln gJHxBEoOm3yiydJs/TwJhL39axSagR3nioPvYRZ1R5gTOw2QFpi/iuInMlOZmcP7 lhw192LtjL1JcdJDQ6Gh4yEqI3CodT2ybEYGYW8YZ+QpfrI8wcVfCR5uRE7sIZlY FUj0VUgqtzS0BeN8SYwAWN46lsw53GEzVc4qLj/RmWLoquY0djGqr3kplnjLgRSv adr7BLlZg0SqCU+01CwBnZuUMWstoc/B5QIDAQABo4IBKzCCAScwDgYDVR0PAQH/ BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8E CDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29j c3AuZW50cnVzdC5uZXQwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2NybC5lbnRy dXN0Lm5ldC9nMmNhLmNybDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcC ARYaaHR0cDovL3d3dy5lbnRydXN0Lm5ldC9ycGEwHQYDVR0OBBYEFMP30LUqMK2v DZEhcDlU3byJcMc6MB8GA1UdIwQYMBaAFGpyJnrQHu995ztpUdRsjZ+QEmarMA0G CSqGSIb3DQEBCwUAA4IBAQC0h8eEIhopwKR47PVPG7SEl2937tTPWa+oQ5YvHVje pvMVWy7ZQ5xMQrkXFxGttLFBx2YMIoYFp7Qi+8VoaIqIMthx1hGOjlJ+Qgld2dnA DizvRGsf2yS89byxqsGK5Wbb0CTz34mmi/5e0FC6m3UAyQhKS3Q/WFOv9rihbISY Jnz8/DVRZZgeO2x28JkPxLkJ1YXYJKd/KsLak0tkuHB8VCnTglTVz6WUwzOeTTRn 4Dh2ZgCN0C/GqwmqcvrOLzWJ/MDtBgO334wlV/H77yiI2YIowAQPlIFpI+CRKMVe 1QzX1CA778n4wI+nQc1XRG5sZ2L+hN/nYNjvv9QiHg3n -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIhzCCBm+gAwIBAgIIFUjQVLioQrowDQYJKoZIhvcNAQELBQAwga4xCzAJBgNV BAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQg d3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcx GzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwHhcNMTQxMjE2MTE1OTAxWhcNMzcxMjE1 MTE1OTAxWjCBxzELMAkGA1UEBhMCRVMxFjAUBgNVBAsMDUFDIENBTUVSRklSTUEx GzAZBgNVBAoMEkFDIENhbWVyZmlybWEgUy5BLjESMBAGA1UEBRMJQTgyNzQzMjg3 MUswSQYDVQQHDEJNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgaHR0cHM6 Ly93d3cuY2FtZXJmaXJtYS5jb20vYWRkcmVzcykxIjAgBgNVBAMMGUNhbWVyZmly bWEgQUFQUCBJSSAtIDIwMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQDF+2P268Q6Gbrsf+dNK9AZI7nvEHs6MSs0gbPcQt4i/psW1rahzNwdfsjuJzY7 n6kRe0d2DkXgo854sNt+G0b0Zyy6gx++NqptRwEDwg/CR2142d9TVplWZA0KhDDB RuOEdDzU3/5vhtLtO8cx+aYt+WJ5pNUaNMdYe7MK1CaJKFCWbX69JdNPUa0saZiE YSijD0l9JCU09hN2cVidW/ZsDVR5+Znz6z+iQFXfzSwRebT2uEFDc1SNiB4jZ09n 83CALULZPWm1JfUGYcei+nQA2ZKZZSZgmmrqsHTUVqC2JzVxkCbxY8vWFyAiE7wk V1S31PBE8AjDYOqi0fRPwWOfd+G8qp0Wo9ofMEBZvw/DEkOBz1vLzo69lOKlxQyP bdbRUvkfvOQoiM0phssbH3H/gqYhs7XrMDTeZKXNX1AsBgf922KWRWbPQ1n4SHUW TmxYf5KCSAVpBOjI9yxu5zRqlM0+/5AeIBwIqIxdseZZUWNIYbXmciHmEzhYzeD2 WILmMjuJQiGXz0cNlIkqXxqCHhtR+hjniptEcdOFhVHB5h/SnfAvN7zARl6yZeQ5 bwoQG7s8DPhXCwNJAD91FTCq2sovjpeoMQhACBvTJNy9uhkxIxw7eEHJzSbPr12i zAtcJr3QbGiwfZaJBk4MRh/HOSs2feE58PcukvPz7utd9wIDAQABo4ICjDCCAogw EgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQUXaFVpNxKrIMR+ao45fdoSv4V FUwwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4x CzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJl c3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3 NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hh bWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiCCQCj2kJ+pLGu2jB6BggrBgEF BQcBAQRuMGwwQgYIKwYBBQUHMAKGNmh0dHA6Ly93d3cuY2FtZXJmaXJtYS5jb20v Y2VydHMvcm9vdF9jaGFtYmVycy0yMDA4LmNydDAmBggrBgEFBQcwAYYaaHR0cDov L29jc3AuY2FtZXJmaXJtYS5jb20wDgYDVR0PAQH/BAQDAgEGMCcGA1UdJQQgMB4G CCsGAQUFBwMEBggrBgEFBQcDAgYIKwYBBQUHAwEwPgYDVR0gBDcwNTAzBgRVHSAA MCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vcG9saWN5LmNhbWVyZmlybWEuY29tMHgG A1UdHwRxMG8wNaAzoDGGL2h0dHA6Ly9jcmwuY2FtZXJmaXJtYS5jb20vY2hhbWJl cnNyb290LTIwMDguY3JsMDagNKAyhjBodHRwOi8vY3JsMS5jYW1lcmZpcm1hLmNv bS9jaGFtYmVyc3Jvb3QtMjAwOC5jcmwwDQYJKoZIhvcNAQELBQADggIBACVw1zHg pXxOlY2c9OTKHwhrzkM1b1hQB+ZXgmjcxnCy0MmCWfK2hs1ydBXzMp/CGXEXGK/p cp8VZO5DA+k9yJnRZzU/0PRcHbQVwUI1D923GmKyi7cjVlts7OImGY2cg7Zod8dJ lXiTB1Yy2mmaePovehyzxwQJx7d4V0b/eHHcJ3lm4YMUiY/3ot+uopPBi7PuJ/FE iCb6j9un5jpXIF5HpaVGpQCv1l+jnx8n2gxcGGbHLYdyrBnLWS96g1IQkRgXXES5 pTy8YUXJM4fNdIP36pAMjXidwPQcXj/IshdG7mHnxqYBtiYiNOgdxOnZRqILOhN9 ObVfKANUUkQeNh1Q2B3PNLHYRgkay7oQn2q6MY7xW0PNY5vlhTb2h71Y06dekLSb z82/8hqZU/JswlPQF00njIcJObxq7GxMEgTEAtvmdXVeVNsVzFux6UPtXYkWXb0c Ou+eTpKq6vMvSbp7U/OxPfpWjniIhIOjHK0LKD+cBlUrjvGwdTTpJ9r9oW/83z+6 c1DGVpsZ+GiiemLqfpqUhsIn0teb51yDH8RNVY18UXkSv13Cea3BLdh/y5rPobu1 GkRJwV+lyt3mSOkE1pRDqCyx14PnZdsBtHlw/KmqqRdONOjmkaxgcp+uvs/z4SJP n6GrY21iwU5qXxCaqaE4ysZEp8L0t9xGbbIB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIkzCCBnugAwIBAgIIYh/zHEiboTYwDQYJKoZIhvcNAQELBQAwga4xCzAJBgNV BAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQg d3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcx GzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwHhcNMTUwMTE1MDkyMTE2WhcNMzcxMjE1 MDkyMTE2WjCB0zELMAkGA1UEBhMCRVMxFjAUBgNVBAsMDUFDIENBTUVSRklSTUEx GzAZBgNVBAoMEkFDIENhbWVyZmlybWEgUy5BLjESMBAGA1UEBRMJQTgyNzQzMjg3 MUswSQYDVQQHDEJNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgaHR0cHM6 Ly93d3cuY2FtZXJmaXJtYS5jb20vYWRkcmVzcykxLjAsBgNVBAMMJUNhbWVyZmly bWEgQ29ycG9yYXRlIFNlcnZlciBJSSAtIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQC3ndKNpFufVq9v+15dRoT9oVkgwEfDdsPw0Ly0R+eM5MOk 35zEil/+hqEMbQmcvosAh6I8iAskkXasqh+SMbMIjvXbDyNILeGzsoP0uz3btHM7 oN3yHXDhhd1NGNocP54Wehe9+RE3WP0yEEo+D2YmMwUHuv4KiXtveiPksv+Xkkz5 auqppPMaYlD6y49AEsGY2zOEUI8PO4+tOxUKhvsiMuW817vH3VdmMwOjRe0SdYAi YLQIiyqJGNdEo3u+fw8UXxaJSRXhmF+jUn5DvdzWWNAxxwAKy95EPlpLQsx/7t2W 2ntoELPHGJk4V+/yA0d2olLEqBADkRtP2HiC0wly+zp7OGmjtfjbqLrVjmo/mLP3 zpmYbpUtubrHiY0rlW6wo5FZLcTUvcAxFjxLWVIELPjnTebOuHvoJTb97rhA1Oqq woq5FWJHFI9idzXzFLO0LX/4ugI9LZWxmvWW0O4CePtnhp0aNE/GgAw6lMx7bjZe DXxxQnUDEE/mAqOHRUCnvRUSKVbuBBE0oz5fz3nUwcWVVgrm/jkgqTX4EqnZe+yB mKV6hFEYV+1oVh7kzNN4Hg7nzGuByS7cCuBEwULFhfUja1Bu9EqgndJ3CV0XCWIA XVhJnPNPi6y4W11jLJ7XSGSz3sCh21g0Gpgi2pXHGDB65Jc/QJHZ5ZaHCrzFnwID AQABo4ICjDCCAogwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQUY+nw8FYA aGWwIWwOXNcZCJ0INGUwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKe FxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiCCQCj2kJ+ pLGu2jB6BggrBgEFBQcBAQRuMGwwQgYIKwYBBQUHMAKGNmh0dHA6Ly93d3cuY2Ft ZXJmaXJtYS5jb20vY2VydHMvcm9vdF9jaGFtYmVycy0yMDA4LmNydDAmBggrBgEF BQcwAYYaaHR0cDovL29jc3AuY2FtZXJmaXJtYS5jb20wDgYDVR0PAQH/BAQDAgEG MCcGA1UdJQQgMB4GCCsGAQUFBwMEBggrBgEFBQcDAgYIKwYBBQUHAwEwPgYDVR0g BDcwNTAzBgRVHSAAMCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vcG9saWN5LmNhbWVy ZmlybWEuY29tMHgGA1UdHwRxMG8wNaAzoDGGL2h0dHA6Ly9jcmwuY2FtZXJmaXJt YS5jb20vY2hhbWJlcnNyb290LTIwMDguY3JsMDagNKAyhjBodHRwOi8vY3JsMS5j YW1lcmZpcm1hLmNvbS9jaGFtYmVyc3Jvb3QtMjAwOC5jcmwwDQYJKoZIhvcNAQEL BQADggIBAKhqaZwalwf89f4wPqfcE/lrsHdx8+q9RG46ouBXhTJMqXjwstXOZSL4 3Dqs3GaVuMPIM9OG7CK0I93mAt+FWtr49ACFTyPBxPg/knrZ4RHyEto+/6w0WZ9H owNw0aUg3ZAkhIvMRPVou8PrVukqj2lGKIh3hRdrbHwYwwmKKNlWBoC9gWk3mTYU zfNt/KTzQCCl5+s6YDa+XInMLWaGd/pE/e++a22vY24cv7kN3NAFMjAMELPwh9ic zLoPX8B52r+GgwpKY0c0hZdVTii6psLQ+BenyMlh+6lHRBOlTCSRtNi16o7H8fRq CY2wyQi7N+EmdY1DhvECCi1nLbOnIx1bSAW0cVwPVrjQ/vsAxPNc3SGe/Xnanm3a zAgFspzeuAhxxG0VKOvtPBnPQNsQ0cK664+IrWRsfa6aYhEfKvfsn5o4HpBWDobf zrtNbqjjOuiM6JkT+DxXo5UK7t2q75KCJiimTtAuPcZ5wErZISLvZ34BodIHL2xK b3Vww7K2FE1QaNsuQkGbUk++B9/+vV3H57vzskObdFWeWKSCpxIil4vZwIIH17zn WU+O2WIY1F0aO9zp3E7qwfmYT4MJ38NF9R7FSlxRlgVc1uUHu/iyUU4N1O6F3VdX P2Y+tgLFZLYV4kApfXk5l9h94dgKyfVcIpvS6yVpLfONPnlCNOxy -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHkjCCBXqgAwIBAgIIU5TkF0ZRnpYwDQYJKoZIhvcNAQELBQAwQjESMBAGA1UE AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw CQYDVQQGEwJFUzAeFw0xNTAxMTUxMDIzMjRaFw0yNjEyMzEyMzU5MDBaMEMxEzAR BgNVBAMMCkFDQ1ZDQS0xMzAxEDAOBgNVBAsMB1BLSUFDQ1YxDTALBgNVBAoMBEFD Q1YxCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA o5KJruh7JPEBxpdC8Pf3qN8vfPR98dCWZynbjLBXv6MTjwAiehTq1X8OzEQNpqWq pNpygo6/YNgf8FMgYWhCsPSDvEmg5Um1xBnLjHBJMSIP7VClMVS9KidVu+nF8PpZ no8hecsfF4yJzLp/MD/lwIsjkh5Zp9e6cVBJsSkRJDY4gWlTWRYO/0e1ZQSmu+2+ YKy2ZRpOPo6k4eGlIsFGz9yIzVii0hasDf43Lv19F515tNGXFIYmNnLjMFlf/LKu Al87jblGqRn5yhMGuJNsP05gH5D/F5YkLqg6A83KmygsIsgYzN72YWiFYNzB6ZzF 0HPM9GX3PuSkKKXyFpUxYL0nHWH7B3Se4F5m+mmFk9GMvJVuoUvktOO2ysFPE3pY tl1iJjrVGBk5cmZHKQbqBw5ZooSEJNbmvtzshUxVEFTDRg+8avleaZFNvl5hilSQ 4c7YlvSnu80AMfhJ/pD6bwA+7BG91elQdcoMuedHyvE3lGqYxuh25a3u//K97joz +qq10hZH5eNrExjWV20DlF6kgZqo6C/2p0zm5eTfbaZ16oVZrpmTeG95dabQzgHD dXP6B4el67G275jQNok2Wu5wT9oKAM6xomNp6zsr0uYI9kQBqMP8BTPliB98rwg9 xmQH4Ss/r1zZK3xt+mYypBo1OR5VvKEEqs1bnVf3LjMCAwEAAaOCAokwggKFMC8G CCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYTaHR0cDovL29jc3AuYWNjdi5lczAd BgNVHQ4EFgQU5Sf9DFi3YMFTV4Yt+1YDi/6fxbIwDwYDVR0TAQH/BAUwAwEB/zAf BgNVHSMEGDAWgBTSh7Tj3zcnk1X2VuqB5TbMjB4/vTCCAX8GA1UdIASCAXYwggFy MIIBbgYEVR0gADCCAWQwggEuBggrBgEFBQcCAjCCASAeggEcAEEAdQB0AG8AcgBp AGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAEkAbgB0 AGUAcgBtAGUAZABpAGEAIABkAGUAIABsAGEAIABBAEMAQwBWACAAKABBAGcAZQBu AGMAaQBhACAAZABlACAAVABlAGMAbgBvAGwAbwBnAO0AYQAgAHkAIABDAGUAcgB0 AGkAZgBpAGMAYQBjAGkA8wBuACAARQBsAGUAYwB0AHIA8wBuAGkAYwBhACwAIABD AEkARgAgAFEANAA2ADAAMQAxADUANgBFACkALgAgAEMAUABTACAAZQBuACAAaAB0 AHQAcAA6AC8ALwB3AHcAdwAuAGEAYwBjAHYALgBlAHMwMAYIKwYBBQUHAgEWJGh0 dHA6Ly93d3cuYWNjdi5lcy9sZWdpc2xhY2lvbl9jLmh0bTBVBgNVHR8ETjBMMEqg SKBGhkRodHRwOi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRp ZmljYWRvcy9yYWl6YWNjdjFfZGVyLmNybDAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0R BBAwDoEMYWNjdkBhY2N2LmVzMA0GCSqGSIb3DQEBCwUAA4ICAQAs1zQb+upsV3E5 Xb2heesc2RLziFGzxBqyRiGgzl7aZBtg4fAwbl6TvjwEtZHhGkW+DxYzJ4EvgI+U 8Cbbwm9GVGUNA5e0l1byywJYgd/y2v8gGX+zM7X8mowih1zPIN6Z5odc2abCNXyl IftLWeGKnOLjizYJ+Jxtv6bWu7Z29ZrUr2+vSSbOwj4SUaEn1zN+OkqzKvTBk4O8 xcgB5c/qRJ9XZFWsoHX+wQpZhUZuIZxYvm4FLXbb+1cHE2rNwkbrBbBM0MNGxP8D FIH8IfEkVDrJgk2sW8drvcbU01D9IwlcP9YVY4Rsq4Qesu8psHyr1HyLr+Ioyqsd KLjUQ4o67o7lTWHhI04mW9wz0kREn/siqR+chY2zRpIO7hGwI64TfBYulWxdOavq DKMeHjLKJVOsYsWK4X9fjnP+5+wFSAM+0zINDbezBAlM1p0sd5DV9KrQZ9TE9PxT 1G0dvWnJRbp6PRVruvvr+iVsZGBLjWY5r8PaKsseAKtjFUi52si2Bf4L10+UMO+q LWVohAyGygNYkv5eVSW3XLri3NzgVb5QZrHs7IalcpHUPayMW1YkN0l+egCXVgTN VFGkJup4TJel2gw1sYi4z7FadKTi9c9JZSuYN4Zb+qtM8ysaB1bg7UfU+dAry8nF xuHeo4MhiF6cx7HxobOy2p7riigccw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHkjCCBXqgAwIBAgIIQfac0r2AwLcwDQYJKoZIhvcNAQELBQAwQjESMBAGA1UE AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw CQYDVQQGEwJFUzAeFw0xNTAxMjcxNDA2NDJaFw0yNjEyMzEyMzU5MDBaMEMxEzAR BgNVBAMMCkFDQ1ZDQS0xMjAxEDAOBgNVBAsMB1BLSUFDQ1YxDTALBgNVBAoMBEFD Q1YxCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA mwYjFx7SZmarLj0+7DqdJn6qt5EwPpgXxnEzzFfOSQrSm6ylglABjVTEznl9a5m/ ydNAxggVGKNA+hNMFCagFS5P6nJ8bZ4SZbILpZ6egUoXDV/+Iy0FgW7sJLPPh323 2OtevxSiwGE8ipjJBVZVP+qYMFEpedkLRI2HzF0XVrmS9YfWOzK7yh2+d4CqPCfX 1W0aGeBK21skABXEXeRgZDr1U5kmLRZAoG5NZB6XPcVdudBvle3zO2nFPlYeDMsR SOBFwQp0L7tcEZ1dQ2u/uhq3UfJGesWtshn///sQDC8K7TX9whlRkw6Qx5V8TcO5 xQNJaxBQnsNBw41TBX4sglwzF50wfA2Xn0PS4GhT0ms/ijeqIh1ZP7eBKc4psMNJ ZtzhjdUCeK+WbZRDqK78Gv9K995oxFEDmR9Kyb5jDHgGV8qRdiup5g0ianMSg2iU 5RxGzjvdGULDgAmvJ/fBuCMv15rLsz8c4zYxNDbNHRfET6TlxEZtLK1wGL3lrXgX ANXLFWSQzTw5EgBwueCWMZDIlvi4x16oeX5G7QcrKrQS8DCdWhGlhDMVJOcBkkLJ tlRjKitmYiTIoRiFaRt4S4+L+004rHlcbr9Ec76HbSmBYsmuIfrk8nSPDGnv0LOo rMhaXdcn6c5RZpH008lv6fN5wpLeEkQuzGjATLTFbo8CAwEAAaOCAokwggKFMC8G CCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYTaHR0cDovL29jc3AuYWNjdi5lczAd BgNVHQ4EFgQU6ECbjvtmP8FE2KHf1EqBQggXy+UwDwYDVR0TAQH/BAUwAwEB/zAf BgNVHSMEGDAWgBTSh7Tj3zcnk1X2VuqB5TbMjB4/vTCCAX8GA1UdIASCAXYwggFy MIIBbgYEVR0gADCCAWQwggEuBggrBgEFBQcCAjCCASAeggEcAEEAdQB0AG8AcgBp AGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAEkAbgB0 AGUAcgBtAGUAZABpAGEAIABkAGUAIABsAGEAIABBAEMAQwBWACAAKABBAGcAZQBu AGMAaQBhACAAZABlACAAVABlAGMAbgBvAGwAbwBnAO0AYQAgAHkAIABDAGUAcgB0 AGkAZgBpAGMAYQBjAGkA8wBuACAARQBsAGUAYwB0AHIA8wBuAGkAYwBhACwAIABD AEkARgAgAFEANAA2ADAAMQAxADUANgBFACkALgAgAEMAUABTACAAZQBuACAAaAB0 AHQAcAA6AC8ALwB3AHcAdwAuAGEAYwBjAHYALgBlAHMwMAYIKwYBBQUHAgEWJGh0 dHA6Ly93d3cuYWNjdi5lcy9sZWdpc2xhY2lvbl9jLmh0bTBVBgNVHR8ETjBMMEqg SKBGhkRodHRwOi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRp ZmljYWRvcy9yYWl6YWNjdjFfZGVyLmNybDAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0R BBAwDoEMYWNjdkBhY2N2LmVzMA0GCSqGSIb3DQEBCwUAA4ICAQAcsICqv3AJB2/Q NQLL2mkFaf0Q/X9uUidWzhEQYHOf+Eh9eojMea/o+6rzgnrXEHOPIyoEOX7vKzAs Qca/w7xM/ldWB4Q3yN6Bv07OyA7EKkTLpLt8X0VSJV2XgxDRpAsvJ+hqPPPIo4DW 7AAk8rZF2+j92OG2WkHEWiEHXA68MsxCzxpcwAYHdRuCsl46CD+dRmODCzCRc9Ns anhiLOX3JPzRhc4itMAR1YK4uHCqj/VwFLd+oT84cAksXpNd2qBsICXgfVV0B1w+ Efj7aaDCw9gY0IbtPMvpadiwjq1mYATBW8+jLb3i2YfRx5fr0YXcv68HjvbSzDex gMdbkqxHjPvmsfkFmzYDRzxZkYhqcMHLxzZlKD7F1Sa2GYM/kuG7n7zHGuodg3sW tZLN16jbaHbupjJT7G6Ll4xVqQVW56wct9zaDD38rI0Nn/u5ch5Koib1IOB2FOmJ H2kA0YMRpPjkvDyZ8QZLVG9SM8GBBVQa97BdY7b3RQr4nYSMLNXgbZPhjuULMg5q OZNuLhrS09nWcyeAYp6pA4KmNgJtLnRBw6+j5b6+RMQpdoxY8AQm301OjK3KsVB+ lktHpcv7aDcwWWup9ZF7SAbgmy0dig0n8+AofQQnYbi0jgcdjguxsvYznwgf+SsI IF+BTEMSGWi5MDbppe3b+TbqsRDXGA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGdzCCBV+gAwIBAgIQDAOugIb7rN3dNa34GPCXnDANBgkqhkiG9w0BAQsFADCB ijELMAkGA1UEBhMCVVMxGjAYBgNVBAoTEU9yaW9uIEhlYWx0aCBJbmMuMS0wKwYD VQQLEyRPcmlvbiBIZWFsdGggRGlyZWN0IFNlY3VyZSBNZXNzYWdpbmcxMDAuBgNV BAMTJ09yaW9uIEhlYWx0aCBEaXJlY3QgU2VjdXJlIE1lc3NhZ2luZyBDQTAeFw0x NTAyMTYxMjAwMDBaFw0yNTAyMTYxMjAwMDBaMIGJMQswCQYDVQQGEwJVUzEkMCIG A1UEChMbSmF4IEhlYWx0aCBSZWNvcmRzIC0gU1YgSElFMS0wKwYDVQQLEyRPcmlv biBIZWFsdGggRGlyZWN0IFNlY3VyZSBNZXNzYWdpbmcxJTAjBgNVBAMTHEpheCBI UiBTYWludCBWaW5jZW50cyBISUUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQC/S1eNdLE/AnpiNJkKxHx2Qz3fyvWIQ73xiyJDcYx+JIl9j4aAaaGX MreT04Or8A3aYgMyiLsQWjiW/MOuv0dtrhUj1Lwk2N2qnnTVa26IO7xDLlrWbewt RCOaZuhiTNY9XPqnsJu4K5BoyQRqxedJJNKFtq4OKJqagWW15BmOSsmjb+4pN7c2 +UGdMFrhDtIHn//zQStEO46gaJbrUVeeo1EA6ErA19ckjlNDWb46PofIbS/bz0gA u48AdaoleXHn2ZXWFZW+XTLoY2z0cNLyt3lVN2ZdD0Ejoof6KHz4cytJVXsOM7eD BGE8MrV+EbF6kTFMezm/h8wmuTrmJAVzAgMBAAGjggLWMIIC0jASBgNVHRMBAf8E CDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjB6BggrBgEFBQcBAQRuMGwwJAYIKwYB BQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBEBggrBgEFBQcwAoY4aHR0 cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL2FpYU9yaW9uSGVhbHRoSXNzdWluZ0NB cy5wN2MwgZkGA1UdHwSBkTCBjjBFoEOgQYY/aHR0cDovL2NybDQuZGlnaWNlcnQu Y29tL09yaW9uSGVhbHRoRGlyZWN0U2VjdXJlTWVzc2FnaW5nQ0EuY3JsMEWgQ6BB hj9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vT3Jpb25IZWFsdGhEaXJlY3RTZWN1 cmVNZXNzYWdpbmdDQS5jcmwwggFSBgNVHSAEggFJMIIBRTA4BgpghkgBhv1sAAIE MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDAYK YIZIAYb9bAQBATAMBgpghkgBhv1sBAECMAsGCWCGSAGG/WwEAjAMBgpghkgBhv1s BAMCMAwGCmCGSAGG/WwEBAIwDgYMYIZIAYb5WwOKIQABMAwGCisGAQQBgsFbAAEw DAYKKwYBBAGCwVsBATAMBgorBgEEAYLBWwECMAwGCisGAQQBgsFbAQMwDAYKKwYB BAGCwVsBBDAMBgorBgEEAYLBWwIBMAwGCisGAQQBgsFbAgIwDAYKKwYBBAGCwVsC AzAMBgorBgEEAYLBWwIEMAwGCisGAQQBgsFbAwEwDAYKKwYBBAGCwVsDAjAMBgor BgEEAYLBWwMDMAwGCisGAQQBgsFbAwQwHQYDVR0OBBYEFA5+DmL5+LcvT8b0eD6s h9IXkM4AMB8GA1UdIwQYMBaAFKVuIv85aToj+4kkF8ZglAAa2o6eMA0GCSqGSIb3 DQEBCwUAA4IBAQAjOFGsWeQiLRjSCEycULjwiExi4enzYS4y8xLlsrkLqZqdXHBq PLbKPd6KG/0mNgIPcqbdq1kb87Ci4fg1yqpJj/YAOqpiXEpC+u0lbYDHVgK52gVD 6OpEnbdkSZChsO5Xq1kMoMo1rUlOnMWDbnN7nnRAaB23lHIIOYegOXPPwFzUHZHc ftKYe1aIJXcvniZYAHRI6F8+UuEyIlEBi4rJiuvrD0D5VsaA6sLA5DKxjvNcCnPN NxPyJD+KM5/cHp7Qyx8OMCdnm1DK69Fx45NtEMnDORq0LrdyHZBaoNoNVWsSIG9q e22KqtFUINaUYiR/JVgBAUhcBrZjprgUqyVC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGiTCCBXGgAwIBAgIQBHk6qjUaYa5/J1al5SSwFDANBgkqhkiG9w0BAQsFADCB ijELMAkGA1UEBhMCVVMxGjAYBgNVBAoTEU9yaW9uIEhlYWx0aCBJbmMuMS0wKwYD VQQLEyRPcmlvbiBIZWFsdGggRGlyZWN0IFNlY3VyZSBNZXNzYWdpbmcxMDAuBgNV BAMTJ09yaW9uIEhlYWx0aCBEaXJlY3QgU2VjdXJlIE1lc3NhZ2luZyBDQTAeFw0x NTAyMTYxMjAwMDBaFw0yNTAyMTYxMjAwMDBaMIGbMQswCQYDVQQGEwJVUzEsMCoG A1UEChMjT2tsYWhvbWEgU3RhdGUgRGVwYXJ0bWVudCBvZiBIZWFsdGgxLTArBgNV BAsTJE9yaW9uIEhlYWx0aCBEaXJlY3QgU2VjdXJlIE1lc3NhZ2luZzEvMC0GA1UE AxMmT2tsYWhvbWEgU3RhdGUgRGVwYXJ0bWVudCBvZiBIZWFsdGggQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLcRnyaNyzuM1sx6fEkyZd1xIHoimK HSLnciLhDUOHfrc2amu/RkvKscLiUVKyildckzevlHt+XLUXrp6JrJ+28/9NOcLq Jg7Qop7r29BFE4IQKtYdzucE1KhlLEyeRX++nGpYPgarIck6T2ZwhdRaNTpbhJTH Kk3vTw5z3A6o7Wf22vIbuGpVMuPAAmDKt5fH1PWTyvl6cmtM4HpoZ8EF3vN7igXZ ieOh1fZx07VGG/Oy0h8LJZgxvau3cHRNCyApnK+ak1bPFDETytcAKMt39K7M2Lhr LpHpj61uWisqBKIY0d8SGwd2CNyHyV7XHRKcw6bg6L221Xv0lFHTvFyPAgMBAAGj ggLWMIIC0jASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjB6Bggr BgEFBQcBAQRuMGwwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNv bTBEBggrBgEFBQcwAoY4aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL2FpYU9y aW9uSGVhbHRoSXNzdWluZ0NBcy5wN2MwgZkGA1UdHwSBkTCBjjBFoEOgQYY/aHR0 cDovL2NybDQuZGlnaWNlcnQuY29tL09yaW9uSGVhbHRoRGlyZWN0U2VjdXJlTWVz c2FnaW5nQ0EuY3JsMEWgQ6BBhj9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vT3Jp b25IZWFsdGhEaXJlY3RTZWN1cmVNZXNzYWdpbmdDQS5jcmwwggFSBgNVHSAEggFJ MIIBRTA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRp Z2ljZXJ0LmNvbS9DUFMwDAYKYIZIAYb9bAQBATAMBgpghkgBhv1sBAECMAsGCWCG SAGG/WwEAjAMBgpghkgBhv1sBAMCMAwGCmCGSAGG/WwEBAIwDgYMYIZIAYb5WwOK IQABMAwGCisGAQQBgsFbAAEwDAYKKwYBBAGCwVsBATAMBgorBgEEAYLBWwECMAwG CisGAQQBgsFbAQMwDAYKKwYBBAGCwVsBBDAMBgorBgEEAYLBWwIBMAwGCisGAQQB gsFbAgIwDAYKKwYBBAGCwVsCAzAMBgorBgEEAYLBWwIEMAwGCisGAQQBgsFbAwEw DAYKKwYBBAGCwVsDAjAMBgorBgEEAYLBWwMDMAwGCisGAQQBgsFbAwQwHQYDVR0O BBYEFAly92V/xm81P7TPE4I4lb4dgKmGMB8GA1UdIwQYMBaAFKVuIv85aToj+4kk F8ZglAAa2o6eMA0GCSqGSIb3DQEBCwUAA4IBAQCVrY18uUZTog5HTu3VEJT6gVaz mO/FdFBsrTqzxhvD3zDHesaerTXaq+zgbDzS+bqwgIqtDgQMNY76ejhNQcrySVra sXEgN+/GoIotHTTYcFSFZmQRWaq2iKerhLkGVOi9B1l/8KsAL3+uoY93oSPEA17Y b+5wbB7BoYkgvmreVBiimHSi5APciBikYYsE7ZP3B6XFKwNbzSnGOc8+lyiUCuKj D036Mgxbck0gpnGyb+SfQxE1Pz11eSNy7uG14b6D1fYnQ2p8jwkYWwT6/Q2JuVHY uPwkv2JK4vhyGN3VHwrRUcRz6cR2kDql17ywXufG8rW8kMQCefC1LcQN6QZp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGozCCBIugAwIBAgIRAIicQfC+tDE/Mw+eLtuCcewwDQYJKoZIhvcNAQELBQAw WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x NTAyMjAxMDI0NDVaFw0zMzAyMTUxMDI0NDVaME4xCzAJBgNVBAYTAkZSMRIwEAYD VQQKDAlESElNWU9USVMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxDTAL BgNVBAMMBEZSMDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzw8qa aXe2F9gVE4zdG386nSqjKdj8g8Jtm2cgNjA/UhAgGyAcx+Dz35QPy6hmonP62oQR Sr7RSNjnTkWpKZ0M6ESK14E4yqx9+I31r88wf4g33dM0TqFuJTojA0qlx0A20WF7 Sbc6/ZXvep9K78SXWYCv2cf0NAdaxYD0A4Ua6CIvimF3OYukU4U6Q0C3zDP3oAZO rDaLweqcpwmTaonwfE5Y5ZHchfeMnNqTHbtOehgUkLual1B6d8wiCHHmj+aKL43Q rLl7YxKYMzlixGGvOx+p9DjfkPVaCSrx2xuoklf398SRvQS4HDx/rOMYq9FAUY1b q8aB8DaERdB14D1tdFkSR3ZdHYq3u762eK+rzBNOlQo1CEkdT2rWNo5miDtezki1 HT+6G6lltXFvDckeGf8aRZG3wf4muc4e5IYFR2K4vEn27zJZ63mKTAVriobeIaFr EiyvmdAII5e8Y6vrYssgJQVBa5wHwdI374OfpnafNfQi1QoU4pLlwV4Mq/CT+fPH DHbAvSAlxYyu1hCKD2+fiESK6ufIYdnYVsGlHo1536aZ8vxl42hz6cgDMTdCBnd0 p9ZI9p+P8327cpmUifBbaElBOrfq/9lQVXhMtlm4kZXv3rZClM2UAK3uutAEdnsX f0peoRB8qtE8KzgYIvWDtfouhjQIXbwpVYJLRwIDAQABo4IBbjCCAWowEgYDVR0T AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFE2DhFDQfaPe 4AKWRiil90ahrSh6MB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of1uHieX4rMEkG A1UdIARCMEAwPgYKKoF6AYExAgABATAwMC4GCCsGAQUFBwIBFiJodHRwczovL3d3 dy5jZXJ0aWduYS5mci9hdXRvcml0ZXMvMEoGCCsGAQUFBwEBBD4wPDA6BggrBgEF BQcwAoYuaHR0cDovL2F1dG9yaXRlLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNh LmNydDBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25hLmZyL2Nl cnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29t L2NlcnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAIAxs7y5+qDc8 7JlW9Lckyrs+qN98Ni8q4cJYRYVzWyfzu+dpMZWvy/bbmUFE0CBQSIiNnBU9iYF2 2IhdnfjWiOcev2xpqNXM7WurBx/KZzTQBpoLY5ZidqgXvMG7FGZnE1vBtJoywLjt ID44PnRq7fFjgDZEuRao2eU5kS0IAnl0DN++qgVX52Z2tyZarlZ/BNSu/Z9ge0dP PTnXjOlrNrJGOFcN5j0iXioFKDnDsBDg6NQJtguz0uMo9nnHirY/l+LrMUzLkl6k BorMDGhL7OII4ccj0RkXUzcnaoQXvoFW6S7bf/yg7FLDuhWSC69a1D8OFtd/xB5o bLxVMH5t7oA3zSSV4gSqp88WU4mzz0bwzLgdg98mJTuNFVC3g/OGBNIdKnvT2qwb GrJ1QxRRdUQDt/yCibPPSXvLyJiW46y5SYYyCcZf1wYZ0FbF21mvdl/sqKMEt71y hrqOOP68aO03vZKZokDbTM+KvdgKT0HPXFi0r/uPNUUancDMFJHc11Ebm7STbebe h7dr/d+Z+M3aLpiePaBcadhCOJcHcJS2VhDUVPF7lLnVilVBWCpQzyyzTOBwERPF w3rLYbfDs/1vtVFI3h5/p4jkfCIPGnP/p0qNcu7XAxGwoipmmPBdOQ9UbsFTYAY1 3wYGeTfR46DBPi7uSpOlMpPla7YawYU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGPDCCBCSgAwIBAgIRAKCjlENSXD0eCU0TsB5PX7MwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE1 MDIyNzAwMDAwMFoXDTI1MDIyNjIzNTk1OVowgbkxCzAJBgNVBAYTAlVTMQswCQYD VQQIEwJUWDEQMA4GA1UEBxMHSG91c3RvbjFBMD8GA1UEChM4VGhlIFVuaXZlcnNp dHkgb2YgVGV4YXMgSGVhbHRoIFNjaWVuY2UgQ2VudGVyIGF0IEhvdXN0b24xSDBG BgNVBAMTP1RoZSBVbml2ZXJzaXR5IG9mIFRleGFzIEhlYWx0aCBTY2llbmNlIENl bnRlciBhdCBIb3VzdG9uIFJTQSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALuLDiYNEgbW3w61b4lo2tSn1HUIwuccBn+lngjsCQBajrLpDrAi9PO4 7RNdif1Q5+LjOi89HJW/Ecyhpzu1+yjABxLKLWQyKlOWfNdkGjypu4PD16ZMawLE NNPr+kfJy9nlLlc4nst7Jb1g6DAmStkirVUdsYd0xbjDlMIu1ekynvexau3q7BON z46BTeqOl9aU3KiGbVIqNep/JS2g8pzqaRoeiyQtqkQE1HCWk9KMMzclY/Mg05O+ NTakVSh1PflvfAAqvLdDdzCcoPSKGBtj7oQBdv/tCcTYUgEvvT3lQnh6th08gfsw SS5FfpsGq7+kDB6+dDynQEKPM/aBSDsCAwEAAaOCAWwwggFoMB8GA1UdIwQYMBaA FFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBS9TdQc254HxFkJHRpoyTrW H6X/wjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUE FjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwGQYDVR0gBBIwEDAOBgwrBgEEAbIxAQIC JAUwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VT RVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEB BGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJU cnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51 c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBMlWncFVBDIz7xzEI5siQj s4HaighdeQONvAYsrZ1v9qAzhHE0lj8+GkGzpYnsScqm2Yvfv27ul0iGTsalw027 dFM0DFIQnwBmdgmjeqxQ2wr8OAKuE9qJwq2sjCs4ka9ykp5TsLyi8adm3UF6gDGR vJ4mUuz/+enH49z40pVZpeE5q+S/rqxP0cySA8VYn1qeTAjxG7IIToLQdwrgc7U2 1RhSQqYpiilAyk5T80RCxRZNt1oaWJ8FhvkzQAB8NarQErgveIf8EWwrfiLGSQ4L IDQ2eHUFsWPCAHSnSk/uSnltE6CAWTouzWk/uBM48ZbYmdv0aoNvAzJ8g+y/E5QU +TIHDZNskswpuO2Ff3rfVNw4/vwMSos5Z0VSm5+9fAd7zRGdrTPLxA2Uqg+QyNau PSudnzuZDMf16NhNex2Ba1CFUmmfb6+V0nSHzkSKF9PZGTa1YmKYrrJ7t4INdEfH snTqULg9iDHnkPdYf75U4Ynn4ehilpGBaUr/mJX1wuxPbIhwOIe6mifST1nB/iy7 b2hAhQhNLdG3Hl/OmuVPfryq3cErrsd1yBqmdkzxxTXP6dKcwjmuWGdJDYYVM9AO OhBc3Bl8TlqvrFWBQ9aKP1QcWQyPmlRbyQV/nAS8/b22vuq/wkwigppMfvxxMEqR BdP5I9qP8jcXQ0nmFcU2BQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFjCCA/6gAwIBAgIRAIriSb1sbY2ZYpQC0sJkYWMwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE1 MDIyNzAwMDAwMFoXDTI1MDIyNjIzNTk1OVowgZMxCzAJBgNVBAYTAlVTMQswCQYD VQQIEwJUWDESMBAGA1UEBxMJQXJsaW5ndG9uMS0wKwYDVQQKEyRUaGUgVW5pdmVy c2l0eSBvZiBUZXhhcyBhdCBBcmxpbmd0b24xNDAyBgNVBAMTK1RoZSBVbml2ZXJz aXR5IG9mIFRleGFzIGF0IEFybGluZ3RvbiBSU0EgQ0EwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQC1DSeZocjHmyVJTZWz588/PJ126SRMpJb2sbHC4Nit 4BoMNR52ONz7/tLvFNHLghUZDL9DqZhDjVfU6b2ImoTchp6UhEjvUUuY7/4FgnxZ q3T+VUaklegBN/3khFQby6QeLwEezqZF4GbUH6c2QLRx+a4Zog8lZCouca5YpJfy 7oZZ2vdEouWPoeASoYdcOVh1IrilEOIgQt82fc+yQoNoWp+bfJ2vzxY+R2fYpdp4 9k2HYCWRhj3LvEnwnOPKWjerc1yt3hOgE5n3XTG9tw/YG3dWaiv1SubRve6zAW3G KOELeJFOQJD5N2GHDHB1RXbdigQV/t7MNWwph1Fh2EDzAgMBAAGjggFsMIIBaDAf BgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUT2xNfX9E 0g1uPpiRYAZ5+IefesMwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBkGA1UdIAQSMBAwDgYM KwYBBAGyMQECAiQGMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2 BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0 cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAJrtn7bh9 fxEMd5JnRz1SpuV8FHMGL+gBjgcTesFqmYRPvRLJTkUNz2FEM68tMWlicvBD7G7i L8g3Sx8IVBYvgQRWCxteoCAUqcyd+BgzxxP3+e0ywoWNFl/BugQoDisVzvpQLVU4 pLYwsbjYc1pUFHBrN3lABnaf22N4dYEl+PfZfSscHiQHnBGCGefOiK7b+GpkbnKT zAgI/WKhZVLa0r0sbJzc5n7MVR+86M0GJ3vwaTvBhen6wBnxz1bEcHlveQ5Y27j3 IxhwdhhAFpXdjOHSCRXJlajXXKSZfwIBNfFo+3nzmQe6V2W18JhpPXyxpxy00P6E y4ZCPW2fb4I4tmMGowxC63gEmGjUv6eI3QD0xGcc4T33dunSk+8mE50RA0jaU5ug 5CYRmD+q1D1GKQbAAOBBLqrwZ+qqUIC/Irnxduaa54s0ZGa+SK8Iv01hZ2bTU5Vx KSYEYSGcAccSSYJ6UOUIGiLdEtOvIOqy0TcMY6x3HisoUeTfJxNX8VfyKeEbTQrg cWxPpdawSyq2CQ4XjJpNHDiRds0RElzT2OdqGodqmE2JbHn3vfs3LOLshxNRFXTD M3TuBbue5K20OLIg6mlLKQivs1mB4N+6MRHjhILlcTwp/RTXZQLVjyTuaiEGSouf /lT1j38eKQu2Qyyy4gnLOwTqSXolzhYtSTM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGQzCCBCugAwIBAgIQSpKN7CX53HrgDnGVn30M/zANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUw MjI3MDAwMDAwWhcNMjUwMjI2MjM1OTU5WjCBwTELMAkGA1UEBhMCVVMxCzAJBgNV BAgTAlRYMRQwEgYDVQQHEwtTYW4gQW50b25pbzFFMEMGA1UEChM8VGhlIFVuaXZl cnNpdHkgb2YgVGV4YXMgSGVhbHRoIFNjaWVuY2UgQ2VudGVyIGF0IFNhbiBBbnRv bmlvMUgwRgYDVQQDEz9Vbml2ZXJzaXR5IG9mIFRleGFzIEhlYWx0aCBTY2llbmNl IENlbnRlciBhdCBTYW4gQW50b25pbyBSU0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQC1PK3pEQ3d4b4VKPPYk+18Cs7b4uwFsu9EG3K14/GfUjBO 5ZGYG5KrQWkOTNT2acgVWRe0iAUNxf14+ut/x5fdG0O18EEbNwSmoTa+9FanYI72 avtNoZh1S+cNXGm8GWmdIcKn6kSS87SSmZK38PJO4yGxrqJezJ69dTA+il8y1/s7 Nrqx/R3P2EOAgQTPbu8ABkR7uJaVdl9ELBgw+XvCNWuNGSDENd70AEL2Fk6zDKJ9 fPoqJGn++d5ovQcQcbNrswFl/t9sb9P6sIAFyv/yiG6/ihAfqscPjy0Jq89gGj/M +s3hk4IXUw+1fPuyTbfcgAGcWkidCcFY4HDvakirAgMBAAGjggFsMIIBaDAfBgNV HSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUNGcFa9QC3aIg Z3IH4p+tXAep/F4wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBkGA1UdIAQSMBAwDgYMKwYB BAGyMQECAiQEMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAI8f8h2sgYJNw 8JBLF0VJu6oZwywySjzRoZLIt+W3KIirptQkj64I02UHOUv2Tp4aSgzIVx6tA/qK EUDQAcDmPpDcdI8dCo85eL/ZLeoWpA9olk8hltzAcbOxQr8JQtwIk67Yd9JWCkib uaPovIQzgccgfF5fAxTE5Gf/pa/D1sp+RjXupjgxfwxJZHcVPDJ1QSMPUVyJfd9p 0ChriTf3e5EeDTqqZvMh57NcV4q+AxJ3Wzg+AWIaYsCtkjDqsNFQ1eZ/XdB52xgA smSrd43e4AiIQf1Rzy5nixTfQJq04EgS6sdyOWB28ZpyKVQtZgfUEDdIrer3+ZBC idDSJvdUZ20zh8eN0Y4A78jKrGU+foQJSZ0kDCVhX9UuvsoBs+3lUP/LHrQQ87a4 03fXH+3rdsjWvGON6NdIa0K6QCM1NYFCzRK9RfwTaG/cW4sSlunPcD9VSw/0lprZ SR9Zw6ZCpBoLrJcfUittS5yxq/Oza3RjsU0vNQ+dAEMYblHKeLHoVok/dUMR0iCv 0tk4J8/QnG0GqA9HCrHjfoVEJlECuWmaY6sU/YDzNHuxzIfrweb2tcCFLQazLIcu 8nIlpwCQkpAMp3ObYRAhLOHvyH/38mvZNmfb+gk7OJgRpU09PBaUQcFi6nD6IRCy Mn11DHl9kFzOdSylgN8ToVimK6FUwZU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGNTCCBB2gAwIBAgIQMEZ284NFzpnxDzDmX2PYITANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUw MjI3MDAwMDAwWhcNMjUwMjI2MjM1OTU5WjCBszELMAkGA1UEBhMCVVMxCzAJBgNV BAgTAlRYMREwDwYDVQQHEwhFZGluYnVyZzEtMCsGA1UEChMkVGhlIFVuaXZlcnNp dHkgb2YgVGV4YXMtUGFuIEFtZXJpY2FuMR8wHQYDVQQLExZJbmZvcm1hdGlvbiBU ZWNobm9sb2d5MTQwMgYDVQQDEytUaGUgVW5pdmVyc2l0eSBvZiBUZXhhcy1QYW4g QW1lcmljYW4gUlNBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA nf3k67v7yjRT0bxGk8uzl4LDOt9LLYXbTQBBArjKtW2oWRcWWT6wVr0D/caTmGAs bIx13Jneefn07E0kAWHiEKrCIVAl0ts4zROem/0DSKe26YTcpwt32TyfvnH4F5Id 2Zq3oA23dzdIWV1tCsm3OviXfBf+puvXUa4dCNORmHunlVLxyJfN+45pqIq8x+u4 ssiYJjfbKs1fHaGJnPQ/wBkCU9naKhYCfyA65mvAHtQS7Bi5BtGeAIPBwDeSgjXU flUhyLgcw/Q1e0KgZdoUkvxL8RHyXM327Za1UJ6jy0+YwhW8t0ndGdgZG4ETqEQP PSfY3Qjc92/IbIuWQqsa1QIDAQABo4IBbDCCAWgwHwYDVR0jBBgwFoAUU3m/Wqor Ss9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFBRrmx2ff9V4vs0JBjtELTC8AbNpMA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsG AQUFBwMCBggrBgEFBQcDBDAZBgNVHSAEEjAQMA4GDCsGAQQBsjEBAgIkBDBQBgNV HR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0 UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8G CCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNB QWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVz dC5jb20wDQYJKoZIhvcNAQEMBQADggIBAA6EY1xkej7fhLGMo4Cw/PgBjIne/NLq 6QKzCJBGWE061eXsPuUK+8+DfC8isgqzTur+m9OkbF2gU80kGY95BkXWQVzGlTSp MAPnjAWfb/NzD+30vcZZItTU6Pns2qOgIwycIsFP9vFGSZm5yK0mDMLTEWYwR2Qc wc/Hnlp8LEUJ1WbFwOe3LIfwsykRzsxOh+l15GXiI73L72B3pLwODvbMZScQpvpL L1F1eocC7hrnYYzmb1Drgpa+80wOib7V4myV5qDkorg2t4gMjjBPaikv0NpAWjhi OZGAaimypY1LSjYzC3Xosdrhp4S4UDmZ7p29IbTOAT9FZJJSghDyTbaPBjpgBRTH GeOvMw+bs9gKfix2oBfpEA7KamrinO3h3HwewMLJAGlYkk8iRUWuvojD6wUBRN3F asBk2IlbOHCOG1qPsg23Pj+YZzeFFsGRZTPIRMPPqo6ZL2d572gWeWrvwAjaBd18 fI1juQMDKd2o6uf2p4Kgg9vug86cg/SnOenNdVVrV9OZQbec5bFg5ajwnrNkWC9R m6db/7TzOqaPe8dA0JL7oM1WruxaFAfLy1Yanj7ML++dLhhOEKsVwajWS4LkVaPe 07gvoQClQBRHG/XNtXBa51pPJiYSJZVWR7ho7e/FLuwFVNLR+F8+d5wSpQWCyfDl XBIg6OTxrx5R -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9zCCA9+gAwIBAgIRALS3J9L4T5h+/sALa+OCnCgwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE1 MDIyNzAwMDAwMFoXDTI1MDIyNjIzNTk1OVowdjELMAkGA1UEBhMCSlAxDjAMBgNV BAgTBU9TQUtBMQ4wDAYDVQQHEwVPU0FLQTETMBEGA1UEChMKU2VjdXJlQ29yZTEy MDAGA1UEAxMpU2VjdXJlQ29yZSBSU0EgU2VjdXJlIENsaWVudCBhbmQgRW1haWwg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCY8TFOtQuJ6eKqmt36 q4wbnsO9IKTcnBvTO2J9VBf/ryY4LFcqOIy83C52/N4IDVahcJDuKdtkin4Rdsot /6YT7Hb0W+MxrOStZiGhptWYQbmgZ6dYyIndVpVruH72GVwJtqM7//d5WMRTnq9l MCCczkb/wOJdOBPHF+LovY59wMCtzKumvbuNnpaVUt7AIwgEa+AKEPEFFUtXZZ8b M/aGef72eQbWLgXRdd/NmK9/ubKUjcxCv2UJzjZLWcyU+aTBMNiGkX7zTC/Nf0e3 iJGo3affpkt2rhw4vwvlsPjgg9Jsj3bIn+v7U5blOyc369PXoj74xdt4LxuN7s+n PetvAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNm yzAdBgNVHQ4EFgQUcgMRe1RGljH3KEDiL09sZ8AsjukwDgYDVR0PAQH/BAQDAgGG MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF BwMEMBgGA1UdIAQRMA8wDQYLKwYBBAGyMQECAjIwUAYDVR0fBEkwRzBFoEOgQYY/ aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRp b25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0 cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0 MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3 DQEBDAUAA4ICAQBlaFMUEl/6RJk7PgGnow8YwAG/vXFbmHDYyn/rh35m2iHhInzd 28HM9tRSWqfi/EM/BVQHJvAg1od4T6gCGxis/hu5kafEOMb5KGTAZn0qeJXNHhyn 5TIbPKaQ+MbuLWsctaoWXedLUmfJ6p6M8yVaqMcq4mnbwGC1WDbAhGAC5FL20xUG 6Je/LEuwyCtK+A/fxwBies5sLmkl3TL7vR0FTiudfg61DpGTBst/O1hEk6xCVGFf fSMu9Qc3zAfwAVsIppaf9fw4EtOXqyVgS3JpaE8SvwWkSXnjZz2ePe6if+6gMwFl f39OUu6ooAqAJNF+APSoUZx86Z97rL2v/CHHWkDmrJaJ281fwMKejpvMa3TiAdH5 4nycxb1dp3JllqaE6LZHXgcA2P4hruIF+dkwmo8Ir0LdYvU6uT4eqf+36Xvjx311 qDydON5VdcQnN1ILCxOQvNzNWpwjm2gQETwE3PeRqNrUb9Hd0hG4oevlKP3V70WA JhsKqOTISo+/WuIPCEkwX/aAa3Yl+F6bLsh5GIm4U6ZG7YmepjUPF8km7DTWPohi tHyXU8SaD1mnhnawjUOq0uZYAbHU5B6SWYzp0j0NXb3E6ddQIb7zj8UO6hIQWqIV 8cMtV0ZwnM6h4e1tUqhHZ4BYUOnw+2VuSfOe2uGfhJvCn3RTIc8KjEVihw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGNzCCBB+gAwIBAgIRANXQCMzVcduZP+838Isw61kwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE1 MDIyNzAwMDAwMFoXDTI1MDIyNjIzNTk1OVowgbQxCzAJBgNVBAYTAlVTMQswCQYD VQQIEwJUWDETMBEGA1UEBxMKUmljaGFyZHNvbjEqMCgGA1UEChMhVGhlIFVuaXZl cnNpdHkgb2YgVGV4YXMgYXQgRGFsbGFzMSQwIgYDVQQLExtJbmZvcm1hdGlvbiBT ZWN1cml0eSBPZmZpY2UxMTAvBgNVBAMTKFRoZSBVbml2ZXJzaXR5IG9mIFRleGFz IGF0IERhbGxhcyBSU0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDXlkSdnMkj8ZmmIetdWChi3JIr6sK3i1sLYfqi1rZLdHYxQt4Lgknp6kMdRM0q plOXzAaHaJBY0xZ2MODOEeOos21NBa3OF77TTnYxhlNmT23/0jKldJ9HVGY3R+WM djyO01cU+Zoyb9D/dbdatouboiamSrrbgFlu05iu6hRkEfnOe2noypqJRw0kYKNJ A2zGFNZKrIQ1GXXC0TLI44QKtnfVoSJ5OXGioScbJHI2hGB24a1ZS9hw3+MwSuNa zgV1TWQKso1zu/nH2jKJLrblzoP3Ftx7NXwmF4wVcevvlwpMz5s9q8EiEiNhSwOF Cixfd4bJhOpRHWCuCegE/qQRAgMBAAGjggFsMIIBaDAfBgNVHSMEGDAWgBRTeb9a qitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUbc0kvWZkjj/QX5mBwbGNocaZhJEw DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI KwYBBQUHAwIGCCsGAQUFBwMEMBkGA1UdIAQSMBAwDgYMKwYBBAGyMQECAiQDMFAG A1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1 c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgw PwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RS U0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRy dXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEANMdPPnFJvqa6vj7yze21Aoxcj2mp bzzpT2yIszZKlokGxp4CU3sB4kaO3yx1Lhwkviab8XUM3hwu3eO4Z7KIse//RgIF gPcS3v9KBOhfJanMBS/f3r1TKSeJzqiZNpGIXSdU41++Fwpbd8efxOJMM27s14Z9 PeUJFpLhSjp0Vak39HdrxBnTwbk+H4ZrO7KyH3V//sZc/0YvJrgEzhR66l+yZXib ekJaeD+2Amhy7jAN3oYuUD4nN+guDBooaM5Kx/sssMIVtZUA98epo0rD+T27WCxW mXnC4TK7JyqQN8zm3HgPGb2LMfOX79DO4n6FM1H/1ykpCxdOD+Tsvw/zcVivKS8x oRLces/yOAgc5cvymbVL8lD1H9nWnnOB+wk/ZpTJ2u2lkHOiZtwY11M2tO4H7oCt OlNFREUMRgs2OHaR8+LvTHrs/d5OCEuMW93hsq+XdIuR9vNnDBgRFt4je+sVbXbL D11TILZxwHIVzn9jvNB2bXRbzuTzee7WTW7CRM52yO7F38wxkeUr0sKJprpT8oVx Pdb1PFbuxPUUi/BE+dht7fq+N20Frtqrsn5l31EFtSzXazdc2eMjrvfsOK47kxyx fg+95sAMc2mDZCWIglNM1O5FjxEAPVnZGk++8PVci8NDtzRlFBxve2jXofAiZI7t mvF8vLmPScb7edE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGMjCCBBqgAwIBAgIQc2R6LY9G4kG32+hHKqs+TzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUw MjI3MDAwMDAwWhcNMjUwMjI2MjM1OTU5WjCBsDELMAkGA1UEBhMCVVMxCzAJBgNV BAgTAlRYMQ8wDQYDVQQHEwZBdXN0aW4xKjAoBgNVBAoTIVRoZSBVbml2ZXJzaXR5 IG9mIFRleGFzIGF0IEF1c3RpbjEkMCIGA1UECxMbSW5mb3JtYXRpb24gU2VjdXJp dHkgT2ZmaWNlMTEwLwYDVQQDEyhUaGUgVW5pdmVyc2l0eSBvZiBUZXhhcyBhdCBB dXN0aW4gUlNBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlmYW KZAM+7UiKzyVLsLC/xPw4o0V8t7zgNctGjz3bHz4oSzj/Nwy36wnC5rMoPHAoUdF 6iHhcwkiyFJSHlLf3Hg9ribcsjv0d90vXlKO1XjnLkJb+yrrdn7zZaY/r7Yfb/es eH6saBSRTMfoV93qkpxbQPgUfZbZ9wPY0s9wcJfPEJUPc+q2KC7HU1h6HTdI2+Y+ 8JwtFI6NY2poe78HmGT0GVvbR3OPooEP5hGz1FRMWV7QbxCPI8b5/nRNWzWqZzva WY64CtRqnRtiwWGr1HZpU4uhbftulAvSOBrpr0GqvVYyyZQc/v4qiyT7UYkwdgDB gCvYwCUugQ975+UYPwIDAQABo4IBbDCCAWgwHwYDVR0jBBgwFoAUU3m/WqorSs9U gOHYm8Cd8rIDZsswHQYDVR0OBBYEFCqrXi6ZyKt1wLy5rIhZeWQwKHWHMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUF BwMCBggrBgEFBQcDBDAZBgNVHSAEEjAQMA4GDCsGAQQBsjEBAgIkAjBQBgNVHR8E STBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNB Q2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsG AQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRk VHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5j b20wDQYJKoZIhvcNAQEMBQADggIBADKTaDfpDaLMo5bYjlknhM4nxsxI1ulTEi1o QUrRhr1XltaG4va59E7OYz8zmxecm5f/FIYeVaUkM1rQsyLBrXJYyYTLtrBlR6YM ju+er3/9LygDkydFFX8103DHGl1s3g6PWkFFAXw5MkkPBtqnkN2WXd49mVPN9HEX psa2Rhbc4mjQjo8QOY5Cw9C54BbOyeyDG5KAbXg5LdzB+VoOtVO17SfjCHMlHJiu LgL6RPkoEAzoSUrDL291QlB8+sdklj/Xk+OtKH1lRqEFw4Ot4b+Y7jtoJMHyOJsg V9XDm4Mh5mu9mvxGkBedjrnHWn6a0ncvOKvGXHfjHhGI3Ew3XajPFNvlQJkKI4Hl 4nkHNJwhe52gDuNPzpzyI5mVO+vjYMmTt1TQol66u2NEGvchhSvWGQxy26/Czhmp EYa9oUuj6JwyJVFcZXrpsS5iR4rttZBkI9MvE0/zveg66BoX6AWNFmTUsdXWxM5E a5N8aIcOh5VFMLQtxgoaQKQke0N/5j49+IY05H2ID2Nriyr0Y6A//xWb5sUdsShZ 9i24Es4mnRoZfjGhLI0fpah3EnxLCXgiZeVrYhfDoyKE6dJBci4YgNiirEtBiHfh z3JS/eLqpZ9+WiME/OyEmOw+ieAQS5sKFs+Ot2I3By5STiRBWtLXm0cFsguBq2RC FRgSM0bQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF+zCCA+OgAwIBAgIRAOEwioIQre9PnXY/ZTsGCqcwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE1 MDMxMTAwMDAwMFoXDTI1MDMxMDIzNTk1OVowejELMAkGA1UEBhMCQ04xETAPBgNV BAgTCFNoYW5naGFpMSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJ bmMuMTEwLwYDVQQDEyhUcnVzdEFzaWEgUlNBIFNlY3VyZSBDbGllbnQgYW5kIEVt YWlsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3BAvUoQ548Oq 4koHxfTdd2M5XZwLzc9QYFDW+dzXRdQf4ntTiJ3D8jp03gS83soco+aCDqdLOmbX PqP+CTOeCYNfXutAbHeFo5xOFJFZPANihBg8k/EqAiboMvT27JKqtj58azuSTuP5 zzSTJZhfn3XxAluw1n5b+5HmpH0Anl2TKtFrc91oJ3+nr9Wy8+oakLhfp6ZRpY6S 9uGwmiF/TciC282d8+/nfhhEfs+CPL2ZnPgDwIF6dFIFABUL2vISEdbMlseV8qQ1 SkRZpFBDjLq6dsdHZbb5sjrw8ZnZCsc/fdgEQT8a1RccM7Sq6uDlZgJEXrL8tWg0 epYGeTzYHQIDAQABo4IBazCCAWcwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd 8rIDZsswHQYDVR0OBBYEFMiYBV/L5UMt1ykx43jj9Ta5uaxbMA4GA1UdDwEB/wQE AwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr BgEFBQcDBDAYBgNVHSAEETAPMA0GCysGAQQBsjEBAgIxMFAGA1UdHwRJMEcwRaBD oEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZp Y2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKG M2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENB LmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkq hkiG9w0BAQwFAAOCAgEAAS5MxWOL1eqreOXw17it2o+TOdxJfhJwaV3gjYdfZUcm EmtCs84ZOPg80RoqWE8Nv4Kkf2A7VkNyY7AbbDfN9LG3vO1VZZFrspkZM/N5d/WB ZMCkgaOvTksbNoirEIxrmpYMy/GHATi1crx/3EaPqNzZvU6LAvdHbySjBESaPNNA 4xealCrJiO4pDrmjD4d+/s/Lp9zYAo8ZTMqsoy0clJ1/tw+d6RoPHGrYpU7wlDcb hAxXMJZbH9NWLJrpAN7CEtpD5HqmmcbTVAOaIbQ9v2l7yMtxtNP4oFOWqPhoLRvF mqbX8PvCPfq4WDkzrAFNBopOVY5Az42JYggaixTr3cK/B0SOPRz6QkjSdiAF1Y8c b7psWFCVWE3+fxwqQQzMmEWeUNlttbRczkdXfJKk2c8OJbVPaMpLqVl6brjHydKe aNDZwWeHQAc1laRQsaGt6powngOeH2xeA6gKBlOGOBjDV7jHDUXgq1S9Q4Oo84mt 5udL8GjE3d6A0tt786B/KZzQa97XnEYDeVLZVU6mb/lk8j6iojaBpQaKx0KzyiLN EdykVUiNLNb5Ox+MXiFgzJvH0kobm0Pj0fk6Ar02p3P/KGx4hovu7n6Csy9wAeYX DWM9/BxpqPn85REvFuPeFUIUuK5kyMhZaWUmzss+Xy1l24fh9PRr+6Xxg+SeExU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFejCCA2KgAwIBAgIQTYuntN+eEVPhyA3uPm9AmjANBgkqhkiG9w0BAQsFADBH MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzAxMjMx MDAwMDAwWjBLMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxKTAnBgNV BAMMIFNIRUNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU1NMIENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0KfgzN6/p5CKNhnzSO1KlnRUgKIMKJsydtjN aphH6UsOfjxMhtt19YSOFUDdBFMn/7I/8jFGBW4xm3waZDxGRmO2giLzDcHr6lui xI7oQd0VyBXek0I6cwLDLRRxBBQ3hViwiHW/KaEEbiEruG0EMsA7cPHg8iiP+hfg o16nWc7BSmVIU6/yRZJDLaFZGdexS6YWYQC1mvU2WY9q+HVGmqtdkcscSTb/amow VNGECN0VrK4gxNIAziuCxd8TL50vdmTZzc9VNL1OPW0EkCeDs/bB7SoXbZoZK2QI NVlfs9gSj0o9LEpu3qZSSB8X3szVMNA1gUR55/XGn2cmq0+G5wIDAQABo4IBXDCC AVgwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly93d3cu c2hlY2EuY29tL3BvbGljeS8weAYIKwYBBQUHAQEEbDBqMDEGCCsGAQUFBzABhiVo dHRwOi8vb2NzcDMuc2hlY2EuY29tL2V2cm9vdC9ldi5vY3NwMDUGCCsGAQUFBzAC hilodHRwOi8vbGRhcDIuc2hlY2EuY29tL3Jvb3QvdWNhZXZyb290LmRlcjASBgNV HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTRQN6mtV nAym4bt76GqWbRdefLUwHwYDVR0jBBgwFoAU2XQ65DA9DfcS3H5aBZ8eNJr34RQw OQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL2xkYXAyLnNoZWNhLmNvbS9yb290L3Vj YWV2c3ViLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAWjqPHv1C83253pheuaQFiXpr mHMqPDu/XpzqAC+lsYOnikPPpG2XvUp2JgmmTpLcTtE10hSU60lD/3/c9qkA3nOU izG7r5kO6Hkw+XqimV1CacJMhNCLw3/APlPdbtTprwYrLAEG/3OUyqTXrep5ffKY JamDc2Rs61e/3ZMWS/yx3mkSNQKMtt9YkeSWLoRT9OEw1esaeMq3OMt+13n7hpP4 jLcKX+K7ZWcU9FuXnKply/iLIfw7dR6QvDYNm3kBmKwFVVAh/8HqQz75CgeCeP2a t+Iz4+7vnpFr/axmI8dWAfOqgd6TATTGgZr8/u36cCE6BQUPvJD0HPjT5KgsXRGS hAnFAddLb9OzMp5SooY6n2oKt3UAu9zVOGCeI54Gotq4YUFlMWg66EO0McXm8sFl QS7o7IKH0yk4O+lezREoPxqCopmWCdV+2b1GcsAKyhuQgQ6Bn/8HXCW943nXaY1/ nBZX4VPwXEpHDrjBgpXsAfxjc3218UW3jBfORkH4qMdt+YGg50L/cBjyb3BPRfOQ k+ytjIh/hRtZRQQmOtb//wDrz+S8mbR2nUzWF6xpnAGJRttWl9Ct6a/aOU2zNaT5 2c2zJkckYxacZ57+MQ8zp6N5JAfgflTvVtceMOcpVcRH1igbEAJulqT7xCEKZ280 v95+eZJ5esOnWSEUGQo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFfDCCA2SgAwIBAgILAPnfat/1ZL6mi4IwDQYJKoZIhvcNAQELBQAwVjELMAkG A1UEBhMCQ04xMDAuBgNVBAoMJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTEVMBMGA1UEAwwMQ0ZDQSBFViBST09UMB4XDTE1MDMyNTAyMDI1 NloXDTI5MTIyNTAyMDI1NlowVTELMAkGA1UEBhMCQ04xMDAuBgNVBAoMJ0NoaW5h IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEUMBIGA1UEAwwLQ0ZD QSBPViBPQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDn14xTy0bH zkaeyACeq6ryfxxG5zZT1fCL4lmw7sk6SVmOKNfE60Gf7W6orksrFVIbIMK+VrYp +aYyhScq8EJT9xXBgXK2HqtpaDGOeclspJvcs+rXn9tlT789NBp3i5U+nLE9M1bR CHSx3Hzu8p7Aeqllou+8nZ2egaVbWFL1zC1JENupSSI9Yjbefhb06y/TVxQ0x4Zt zwPwLcd8NUtSruldolxPbhQeCZNJMPq1GKMxhd5pDwY4mCKxDeraqhTNXui9Aef3 qyi2Ic9EXmdNPARkZJU2XTJ9FJ+DE+ChaIvfJ/VwQfM0eGlBn/SAaav54jBmRnec PeD6YfpuiJ8vAgMBAAGjggFKMIIBRjA4BggrBgEFBQcBAQQsMCowKAYIKwYBBQUH MAGGHGh0dHA6Ly9vY3NwLmNmY2EuY29tLmNuL29jc3AwHwYDVR0jBBgwFoAU4/4t /SjQC7W6tqLEvwaqBYyT+y8wDwYDVR0TAQH/BAUwAwEB/zBEBgNVHSAEPTA7MDkG BFUdIAAwMTAvBggrBgEFBQcCARYjaHR0cDovL3d3dy5jZmNhLmNvbS5jbi91cy91 cy0xMi5odG0wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5jZmNhLmNvbS5j bi9ldnJjYS9SU0EvY3JsMS5jcmwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRm s+/7VJWH6aylllau5n3tOtBD0TAnBgNVHSUEIDAeBggrBgEFBQcDAgYIKwYBBQUH AwQGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQDKER8qcBmZGOG8GOJ670VW OSg3UovOoc7/xz2mE+enyEcSwn/0QrL8C5DSA6nMvBMrCWEytYPofGQUXTwtlu78 GLxYNn3A/RtzczJ+/BXIhoe3aOT4tQ+2s9vrFRfIXs4CkmqHhfYSvArokdayYmBd 78psIwS5LCUzGKSn7y8UmAgoxiy7RtrVt5c1wvJyeuYk1Z1l8MN1szPrmAb4HS/D qnB+0qdhFGvfOyv7lg6/wlIAkN84cHlKNC3JvyFHaCIAyhTPgjUayUvBKFK7XwN9 utIXl2L3IZX7zfxGS/J9+ZeNwyblQKmd/MKydJu9Ak6+ZMLLgjlCFkihJIn9Ur8M 2KQigz7YPDVIJjOtS7ljOQVGh88LPUnQ1fBY7RwagficS/xclIOnaXhoyWzg7EcQ /T1/O4FkpMqKuOreaI5NExjAT8cKizyY2wcOOXKIYri3Ewnbm+00IaYYaiQRGUR6 pzFFKxdFMbStCtI4ObN+A9tB7cnBCW4vz3sAJd/OgmLF38XTa+/km3c1nQOfhCGs 6kx2heN/DgFAc+P7ldObo/kgGQtR6tr02gyXCFWnLMtT0+CoNOY0o3T+LbEqYeKL W7p29G9sgHgoqLFibWNMSKG1QvevkhjUMOD/g48f/nMSYsbU++yEaLvjvRHbb5ON IPkcE28TRhQQKmDKI+DRIg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYjCCA0qgAwIBAgIIXwrMtlpr+AAwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTE1MDQxOTIyMDkyOVoXDTMwMTIzMTE0MDgyNFowgYox CzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEtMCsGA1UECwwkaHR0 cDovL3d3dy5hZmZpcm10cnVzdC5jb20vcmVzb3VyY2VzMTYwNAYDVQQDDC1BZmZp cm1UcnVzdCBOZXR3b3JraW5nIEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/c8jCGiQh9gbKEungIHBYD6CzguTV o10soL09wMKO10oeYbh3c/J1Gt6R48WBxosjPBp22jAfLW4xofy6rUtqTVhH6CjV O8mhBsKWwkZ67G+85SrYgHAbcYHJRGm6ietIvZfirwyxpap4DIiSQCxD571X9zaI hY7y7V5eTDbkkUSLKOdBrrCnCJ3bPwsgQe8UR3OZeDTTkm5eErhf6F2Vo+y764Kr HL+21xT7f0Lkt30kBCoBFzBAOjtbN3yfZsjNQgYleVv6dOtz4ssju8I234M/9qiv n1Ebxom3up5uSAhL2bL/2ddPfeMWlK+sTX/VcsTkztZkD6C71RrexZiZAgMBAAGj ggEPMIIBCzAdBgNVHQ4EFgQUffiyTFQlCF1tJ8mrKwHDNXB5gGQwDwYDVR0TAQH/ BAUwAwEB/zAfBgNVHSMEGDAWgBQHH9LnnNrCbqJAtLB6UBBQdMTIvTBdBgNVHSAE VjBUMAwGCisGAQQBgo8JAgIwRAYKKwYBBAGCjwkBATA2MDQGCCsGAQUFBwIBFiho dHRwOi8vd3d3LmFmZmlybXRydXN0LmNvbS9yZXNvdXJjZXMvY3BzMEkGA1UdHwRC MEAwPqA8oDqGOGh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1U cnVzdE5ldHdvcmtpbmcuY3JsMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAQEAMwRQ3PEqHiajCRbfzHvTnuXCd8PTwb6/jBUocmJym8lk4TaAUdAh7NVu EKYKzw/v53tH6EnF5ckYum/KFhcZqZtMHhtPlCNobPAxCPwdC2kh+Y1uP8aQypVT rKBIfO8MWQBhpONvikqgdiPBXMfuBs8+0Hz32DVqxs2xGicEmVgsQZU9+Z4im07X 8QdHuj31CfCzBlnvvdA73rES8gysg/XEi3EAW8oBuBg+I5BwvRN0RmWKA2ASbgcG KrcnNWDj92g1aRaea0jIAuXI8U+jZzj31yTsf0vTDlc8ZLM8Jx5JzTAsLTr77LMb Qlgtpo36K/WdRXNiPz7au7rtV2fdOA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQZtrvA9uEYZFrJbqD+xdOEzANBgkqhkiG9w0BAQsFADB+ MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B LjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIwIAYD VQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4XDTE1MDQyMTEyNDUyNloX DTI3MDYwOTEyNDUyNlowgYoxCzAJBgNVBAYTAlBMMSIwIAYDVQQKDBlVbml6ZXRv IFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLDB5DZXJ0dW0gQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxLjAsBgNVBAMMJUNlcnR1bSBEaWdpdGFsIElkZW50aWZpY2F0 aW9uIENBIFNIQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDF4Fa7 /gmX4yjanJ5OU71Dp98+qODk8eMgOQVrtwqoFu5hHs+FpRbj3QlU7Ib2ftvGJeZZ md7/+OCfgwiN/51a++9vc2rnCSOFLCVT2JqfuXSX8uDZq2hiq4YXuxksSDxSYoXs TSLSRZd+sI959Rs4IJPNf4ui40+5bA7zon4rgT8Roi+EMTsS+p0JVZsnRzcnasfI QPJ9hkw8SM2ehEUFnDS8SYBwrvgbRDD/i+e5/DRI1W1v9id6VCK0vBLJtq5ZGDxR emiTjeszlr57UNvmnpydMQoqe2Psb7C++PnlXpwCkQVUzMzC3ryGhO/ffuxpH28G Il/Y/xkKKzB0s6NlAgMBAAGjggE+MIIBOjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBQ/yljq8ckJfm4zwSOtTq0+PWxFpzAfBgNVHSMEGDAWgBQIds3LB/8k9sXN 7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYwLwYDVR0fBCgwJjAkoCKgIIYeaHR0 cDovL2NybC5jZXJ0dW0ucGwvY3RuY2EuY3JsMGsGCCsGAQUFBwEBBF8wXTAoBggr BgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2VydHVtLmNvbTAxBggrBgEFBQcw AoYlaHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBsL2N0bmNhLmNlcjA5BgNVHSAE MjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0cDovL3d3dy5jZXJ0dW0ucGwv Q1BTMA0GCSqGSIb3DQEBCwUAA4IBAQALvQnBCZbfwf52SNX18YXpKKzjSEw2+z/d 3BZiu5IGdt/Yi0/NYvNgtIIz3rAkDi+y3o51Zj92zNjUi8GDIlKfqVIG5cigv+Z1 mkQWmpMi/pH2yKXeM5mlR1CvmTIU3JeNBegoBi5rF5R4i6rGwlRKhtWfsD6dyceG jticsmLt3kWW1dxWqQfY1EyhdmDxlNXR207RzT7EisqRxHB4rrm+WDY6kntveHlL qVUEePsBB3sM+DgjYxXM7ydRFI/Zer9BKZfKW/v1f0GQNth2DfsV5MUs8Kyzw6Aq DCRx7HuwAOd9ya7EYbOreMi8Hb2955pmo6Vhaq2KPvjPYoC3KSpl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFATCCA+mgAwIBAgIQAbdO1+G6tU7h4n6cWay1tjANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTUwNDI4MTIwMDAwWhcNMjUwNDI4MTIwMDAwWjBpMQswCQYDVQQG EwJVUzESMBAGA1UECBMJTWlubmVzb3RhMRQwEgYDVQQHEwtNaW5uZWFwb2xpczEO MAwGA1UEChMFT3B0dW0xIDAeBgNVBAMTF09wdHVtIFB1YmxpYyBUcnVzdCBDQSAx MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtxY5lFZFS3GbWVO7aq02 sXy/ujWN0SeXITx2NAVzVroAT9EG+ZUq6zr7V4X+T/+YLbWpDDNraWxvyHFu1hTZ mSHr1KXwXOgp9A5bAj/U/Jcn6tGK6pbTKIrPXXOxpJVz9K97KfJ4W3NZ4fubSNee 7jy+r31B9l0I/LtSAXD/F4O/IWiXFjmZN//sAG9xilUE1YkFbcuzvbC3kd9kpons CyB6OxW4nDqTXpqRgQNR0DBa7tAn1/pbbQAuYjV6bxWIDG7KKOI2JMzMQGNoBwRx r+yVpzwIkbbGyZxWuA6QGOs5cbxUIdkQPNK/6zYg5vEnxCPvfkNIgzRWph72m1If 3wIDAQABo4IBpzCCAaMwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYIGA1UdHwR7MHkwOqA4oDaG NGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RD QS5jcmwwO6A5oDeGNSBodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRB c3N1cmVkSURSb290Q0EuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUF BwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMB0GA1UdDgQWBBT+RWDB /PdHZvA9fuvdEPfiw3cl9zAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823I DzANBgkqhkiG9w0BAQsFAAOCAQEAKjTjm+Nj5mVJUgjKmtfCarN4ZTllitQiixSn smLL2BAxEs2PD3OOci3s34v3qsptTp1rntui9u4jGrJmp6J4Ndl4KxrTuL57hlmO HAZMVbpQUaZeSTKGcycT4rIqzEZZX5wLe7tOu1z/bVvYCR6vGiRZ7p4MRR7DIJV9 SQp2wRq7/beXYsonJkbDp76IshN6k/nuJyvryrTeDs0SC0/YxV9oVtqwsT/WCXaf Sxa1TGCJZmk7T+O8qDKwjw2MKgBY+wKDHBCayIe8Sl10KDCCSyawO7J4xY2vijE+ XChP186VyLElwa+fIvopQM2MEyXdGLZsoPLktd87PSSTipUxvw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGMzCCBRugAwIBAgIQD/zrpkT4Wq//HEW8st10wjANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBGZWRlcmF0ZWQgVHJ1 c3QgQ0EwHhcNMTUwNDI4MTIwMDAwWhcNMjUwNDI4MTIwMDAwWjB4MQswCQYDVQQG EwJVUzEXMBUGA1UEChMOTWVkaWNhU29mdCBMTEMxJDAiBgNVBAsTG01lZGljYVNv ZnQgRGlyZWN0IE1lc3NhZ2luZzEqMCgGA1UEAxMhTWVkaWNhU29mdCBEaXJlY3Qg SW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA tgnBVgPykG/UmHUN0ijRKJ8SckwKFcRWk1GS/kOQeHtJpnCsz9+hAqVN/JXB17yn rqQeCyktiU2HWSwTfJA7PNoh5gOvq42HOE/wRvtn8NBZ8Pj/IPBRZo6z6qyB8erL d31gyW3mSLZzB63GNRfR796Anu9lUzd/WKScg9qTrvN0WKlLk/J5ojFzcfhYj+Ju MLsFtnL77c95SrmQ7RiAgfTgIcPfNMPuT0gnlQjGqkKmyPYRdN2Lj390EG2Cxv0Q A2yzy+dHCotOc4q5NoRHp9hszNPw2hMOTSj9M9aorGCsin4A1xy3s3XI4lFn4NNI wwGjNbUqgsPAM4Fz/MdAlQIDAQABo4ICyjCCAsYwEgYDVR0TAQH/BAgwBgEB/wIB ADAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYY aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2Fj ZXJ0cy5kaWdpY2VydC5jb20vYWlhTWVkaWNhU29mdERpcmVjdEludGVybWVkaWF0 ZUNBLnA3YzCBgwYDVR0fBHwwejA7oDmgN4Y1aHR0cDovL2NybDQuZGlnaWNlcnQu Y29tL0RpZ2lDZXJ0RmVkZXJhdGVkVHJ1c3RDQS5jcmwwO6A5oDeGNWh0dHA6Ly9j cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEZlZGVyYXRlZFRydXN0Q0EuY3JsMIIB UgYDVR0gBIIBSTCCAUUwOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRw czovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAwGCmCGSAGG/WwEAQEwDAYKYIZIAYb9 bAQBAjALBglghkgBhv1sBAIwDAYKYIZIAYb9bAQDAjAMBgpghkgBhv1sBAQCMA4G DGCGSAGG+VsDiiEAATAMBgorBgEEAYLBWwABMAwGCisGAQQBgsFbAQEwDAYKKwYB BAGCwVsBAjAMBgorBgEEAYLBWwEDMAwGCisGAQQBgsFbAQQwDAYKKwYBBAGCwVsC ATAMBgorBgEEAYLBWwICMAwGCisGAQQBgsFbAgMwDAYKKwYBBAGCwVsCBDAMBgor BgEEAYLBWwMBMAwGCisGAQQBgsFbAwIwDAYKKwYBBAGCwVsDAzAMBgorBgEEAYLB WwMEMB0GA1UdDgQWBBQ9scQOTn6Xe6VvhZLgyJaMQqsIljAfBgNVHSMEGDAWgBRG CDhaqY4guwyvXjG6ibMov6yMNjANBgkqhkiG9w0BAQsFAAOCAQEAVEh7vNl5c5av zMqjGrJfinK/mngfrhsK1vERdkqbRJAlc3HcyRvWR1zegQ2eQgPIZhDq1E7eG++M gg/hFjgW7eZRAkFip3qCMPD9oNS7AkBKWVpXfgDpWyMX57OwomjkJWg1kteZ142d UZYONtdHZMfil3Ayti0WHz/m5G7uSKyiASbrEvQYqGA19fMRhASz8XEM1xQcy6w0 GXZuwqlSMau5nflcjS3yUpW1/MMenuVOhkYJBmix2I/dWHD/IR5nWdoHt9Ly6p66 W2SWNSpefMt7ari4UYWvehipwvQo6WBupOHiq91tkKi5bQveelhvxKRffvV8DyqR JdSwxHu/VQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEjTCCA3WgAwIBAgIPIAYFFnADDVRdyGE89xrFMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xNTA0MjkxMzE0MzBaFw0yNTA0MjkxMzE0MzBaMHgxCzAJ BgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEqMCgGA1UECxMhY2VydFNJR04g RW50ZXJwcmlzZSBDQSBDbGFzcyAzIEcyMSowKAYDVQQDEyFjZXJ0U0lHTiBFbnRl cnByaXNlIENBIENsYXNzIDMgRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDkl9cUvyMctGByG+oj7CFqZmRvPkhxqrI6MH+hse38EoOApnsX10mrihyI D3bEvsCMcZiwkNFUI3SeOhXtcmV2vvhpNz1tJ+N2Qbm5FlOFAedv39djCHbBUJrA 6FMx3z0HafQgeA8RpwmaNUyUVIlGwvo6A5Jj3YJfPFbQhE0Ys+rxUc7ix2AM9h0I ry5rD8vrCZoZ7pkwQ7YQxXdextIHLVdtLQz32u0pg3l5TpDgJoO2JDNutJAm0KYi 7HPp1xh3EPqLWLnfnBPHORKpe/11EuQCBf/ObvLYgVMDioPPg5WlPEsiwmkQHIZB eEGmxtpteuUMGQnBdXFHLVcPCcylAgMBAAGjggFPMIIBSzBoBggrBgEFBQcBAQRc MFowIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmNlcnRzaWduLnJvMDMGCCsGAQUF BzAChidodHRwOi8vd3d3LmNlcnRzaWduLnJvL2NlcnRjcmwvcm9vdC5jcnQwEgYD VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwHwYDVR0jBBgwFoAU4Iyb 2yVJs/F8htayQocL0Gug2eQwHQYDVR0OBBYEFPbrmJ5AaatIYJ1GFv+ewDsDupv9 MEkGA1UdIARCMEAwPgYLKwYBBAGBwzkBAQMwLzAtBggrBgEFBQcCARYhaHR0cDov L3d3dy5jZXJ0c2lnbi5yby9yZXBvc2l0b3J5MDAGA1UdHwQpMCcwJaAjoCGGH2h0 dHA6Ly9jcmwuY2VydHNpZ24ucm8vcm9vdC5jcmwwDQYJKoZIhvcNAQELBQADggEB AErvoDlwbU4qC0R+erXB1n6A2X8EAcUD1xyBTKK+4mArU5KY+SMQ+oV+kZZjcf/t 4fVVUYu/bh898jVBksGK/tro1etw75qM4giRxELVjrNzsaRT269dAwdj5Yw/1yyU 4INjhKp1Hsh3KIMZEDy1Dyvj+YpXPylumqA/YNSjhKuHW6ZeAfyQHJ/R+SHkVanA qLn6xmlQenElytmOKtr/doXj6S9RD8J7hVvQ8G1ZjKWj96CQ7Gh+RPNV4h7Sry7+ E3vKzhDAn/Tulg2J9ldLBlmAvosOm6WzutekNRbR7PlnX7iUlDAyt376j6/zHdsE XX3DBwU6knIS5W1eJi2KLZg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEnTCCA4WgAwIBAgIPIAYFFnADDvTSdlPHAaILMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xNTA0MjkxNDMzMzZaFw0yNTA0MjkxNDMzMzZaMIGFMQsw CQYDVQQGEwJSTzERMA8GA1UEChMIY2VydFNJR04xLDAqBgNVBAsTI0NlcnRpZmlj YXQgZGUgdGVzdCBUZXN0IGNlcnRpZmljYXRlMTUwMwYDVQQDEyxDRVJUU0lHTiBG T1IgQkFOS0lORyBRVUFMSUZJRUQgRFMgVEVTVCBDQSBWMzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBALkXqJ/YuagxpqyrISFIqGgQTClNgVdaQCmCQxv+ 19vZViJ77lqV+oICjfuDEsWLBq5dshSv8L31BYRJ7fYiRKuLgoF5ORA1LupWUp50 HwHBVTlyEZWsB8eL9aIMEXIMOU1nizVJ8m1ph7KmJ3dj9Ef0yQ4EZ68EVTpO036h pqZiEiyl1Oaqo/ah19k0dk6Wyh1ysH9OwyDLMSYQu4Pz+BNYudQqEa0byvCWBGM0 0lsO0a09fhYqQIbnfi1nJEtLVVuc4fEE6zBsfdf9d2JldzAx2N2OYm7kNzJb2Sxk 3BurAggHAiO3zfHKV0YdIm2Jum/7/v/TbwlCmpD/ZfOuPeMCAwEAAaOCAVEwggFN MGgGCCsGAQUFBwEBBFwwWjAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuY2VydHNp Z24ucm8wMwYIKwYBBQUHMAKGJ2h0dHA6Ly93d3cuY2VydHNpZ24ucm8vY2VydGNy bC9yb290LmNydDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAf BgNVHSMEGDAWgBTgjJvbJUmz8XyG1rJChwvQa6DZ5DAdBgNVHQ4EFgQUQMQAHiUz vWlgXiHb2IQ95A7FxrgwSwYDVR0gBEQwQjBABg0rBgEEAYHDOQEBAgECMC8wLQYI KwYBBQUHAgEWIWh0dHA6Ly93d3cuY2VydHNpZ24ucm8vcmVwb3NpdG9yeTAwBgNV HR8EKTAnMCWgI6Ahhh9odHRwOi8vY3JsLmNlcnRzaWduLnJvL3Jvb3QuY3JsMA0G CSqGSIb3DQEBCwUAA4IBAQBJxi+FfpdsgZ4QAYRUk2rrGJB65KMJolhoO2JJoE/L B3u3Q9BPcfewohC9xpYYi6bCDP85gshmbbVz3U0zXlRoMqOR2252a5CGsL/vjhfc AuoM73CClD5E6TgPGpCzUCGzict6ACfdKuxbhNXMuj9rJ7W+laPe+P2uBQ5JbraA wBene/0MYsuH5C7x+BrYtAeG7tFY0+2gSFAoJZdJ30wr5VvwD9jMz7DSFbx4muk8 1J4b/MyZ+wtdVDDebpeHcWCl+HZO65CQmxXV8iPB1k3oOS9uP2tCV10VP9hbO+Iw FvRWGnIKMk7M+QBHQvQFf5JDkcwvdhb6XsofWNJ7MOLn -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEmzCCA4OgAwIBAgIPIAYFFnADDwi9Lh4BpHPHMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xNTA0MjkxNDQ1MjRaFw0yNTA0MjkxNDQ1MjRaMIGDMQsw CQYDVQQGEwJSTzERMA8GA1UEChMIY2VydFNJR04xLDAqBgNVBAsTI0NlcnRpZmlj YXQgZGUgdGVzdCBUZXN0IGNlcnRpZmljYXRlMTMwMQYDVQQDEypDRVJUU0lHTiBG T1IgQkFOS0lORyBTSU1QTEUgU1NMIFRFU1QgQ0EgVjMwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQC8KiielH9zrUJmYn0+w0BYjRZURtPK+5bvVbEqu6Qz EjyPwCyiNhwUFUfEn9JRJ3xzEzcYPehBb+xUcjd+bU+ZR+aEDsi5hhzekmxVo74U ZCs82okdS9meoxum/m9sU2nq3zSnmVujRDIgUGoa64CRX+AW0FsjR/lv40Rm7SXW UfLSgqBzDC/hAujl4vkeVMvlCbPyGtnwsdpRXX8fh7YlZ4Zv7DaaCx5TV+vNn3L6 6oR0zbR7kpLoZ2atudcESjmkg6jisCCr9lnmg3KU0Sv810CZc4HAwL7A9cuf8niE hFOfNezIMh25BulSDVAivdWENieLUNoSzxnpshk6QrZHAgMBAAGjggFRMIIBTTBo BggrBgEFBQcBAQRcMFowIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmNlcnRzaWdu LnJvMDMGCCsGAQUFBzAChidodHRwOi8vd3d3LmNlcnRzaWduLnJvL2NlcnRjcmwv cm9vdC5jcnQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwHwYD VR0jBBgwFoAU4Iyb2yVJs/F8htayQocL0Gug2eQwHQYDVR0OBBYEFFd4ux45/Cds phEWX1L6hgqPPwJjMEsGA1UdIAREMEIwQAYNKwYBBAGBwzkBAQIBAzAvMC0GCCsG AQUFBwIBFiFodHRwOi8vd3d3LmNlcnRzaWduLnJvL3JlcG9zaXRvcnkwMAYDVR0f BCkwJzAloCOgIYYfaHR0cDovL2NybC5jZXJ0c2lnbi5yby9yb290LmNybDANBgkq hkiG9w0BAQsFAAOCAQEAfHl0bjGwLSq06kQBHLPpX6ODilE0FxojBbgl7ZTpXIh7 Lkey2ZsLTpNNG0L7uxRyZU2QIlOD+EWAt4QrKckcaoZ8WfboILBWxw2OgdbiBRY7 Uo+zYaPapS/4ysJOc64N0N3RaDahSD3/a6hUGrOZomgLhCc6SJGlPW//4zJrIfOM S0vDYfy9CbB9UTJD0gCvY16a2QuojsvPciNqK2LbMqcfJKuG+fxMmlI9CETqCLpr NTBUFiDyQNeYrwYBg0bmYsVIxI3hjT/H9jWcms+5Q9PnjzMkUPoLyesRy5hU5hoW E+vDNBlelTHL0mmDV4NGTmN0YMUGKdJr2eSJUIrCEA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDJjCCAqygAwIBAgIORnQ3eBYmHQ562+LMtfwwCgYIKoZIzj0EAwMwUDEkMCIG A1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9i YWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTE1MDQzMDAwMDAwMFoXDTI1 MDQzMDAwMDAwMFowUzELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24g bnYtc2ExKTAnBgNVBAMTIEdsb2JhbFNpZ24gRUNDMzg0IEVWIFNTTCBDQSAtIEcz MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEtoR/hAHSDbEH2xfQvCh+we3rFz0vDGZ6 q9WVISPKrhq/RKDz7qbylwu9Dfq+MCT5Jro1xP1cLetNItxUbrfm8ohInpvMXHfH FOrTJwk3KTiUpapxxN3xRtnDwsfFzAbzo4IBSDCCAUQwDgYDVR0PAQH/BAQDAgEG MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/ AgEAMB0GA1UdDgQWBBQ8ePXOXBqHv6/xVOzwq26o3y6x6jAfBgNVHSMEGDAWgBQ9 5ilIm+oHyiFESibebt7Sg9CfWTA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGG Imh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjUwNgYDVR0fBC8wLTAr oCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXI1LmNybDBHBgNV HSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFs c2lnbi5jb20vcmVwb3NpdG9yeS8wCgYIKoZIzj0EAwMDaAAwZQIwCE1ZFOKqFe6t e4Z94aB86sC1F+6CTHVP6nfdJv1LI6OBhOSI+0SMb2ZkFM/tByVCAjEAwEBhgFkv gUdO4GHgjZGBVd1Tlf/bCPSYTH6/bjdk35WcA5oIWVY00rOzbMo0vVeY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEjjCCA3agAwIBAgIORnQ3c1m3p0qL2FCUxcswDQYJKoZIhvcNAQELBQAwVzEL MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsT B1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNTA0MzAw MDAwMDBaFw0yNTA0MzAwMDAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBH bG9iYWxTaWduIG52LXNhMS0wKwYDVQQDEyRHbG9iYWxTaWduIENsb3VkU1NMIENB IC0gU0hBMjU2IC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCj wHXhMpjl2a6EfI3oI19GlVtMoiVw15AEhYDJtfSKZU2Sy6XEQqC2eSUx7fGFIM0T UT1nrJdNaJszhlyzey2q33egYdH1PPua/NPVlMrJHoAbkJDIrI32YBecMbjFYaLi blclCG8kmZnPlL/Hi2uwH8oU+hibbBB8mSvaSmPlsk7C/T4QC0j0dwsv8JZLOu69 Nd6FjdoTDs4BxHHT03fFCKZgOSWnJ2lcg9FvdnjuxURbRb0pO+LGCQ+ivivc41za Wm+O58kHa36hwFOVgongeFxyqGy+Z2ur5zPZh/L4XCf09io7h+/awkfav6zrJ2R7 TFPrNOEvmyBNVBJrfSi9AgMBAAGjggFWMIIBUjAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0OBBYEFKkrh+HOJEc7G7/PhTcCVZ0NlFjmMB8GA1UdIwQYMBaAFGB7ZhpF DZfKiVAvfQTNNKj//P1LMD4GCCsGAQUFBwEBBDIwMDAuBggrBgEFBQcwAYYiaHR0 cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3Jvb3RyMTAzBgNVHR8ELDAqMCigJqAk hiJodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jvb3QuY3JsMFgGA1UdIARRME8w DQYJKwYBBAGgMgEUMAAwPgYGZ4EMAQICMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v d3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IB AQCiJj79nckuXwTF3mZwglD4tpRVOIyjT2E8r5zR+e2wS4RonlTFhDsmC8+2pMAr 7f0CROm4zV1SoOnmEnvQngohyp5faxWOpZ3qVHyU+E24AzcIXmY88+pIMVTW6UgS hBGP3O4YK5jq6R9iV93C2SIMjcpU3z4v+s059NYF8ONHjduERW191KRjWAoaC1ve k8aAP0CIqbp1GxkAMNjbXeCNZ71jw7DNvI/YDpcS3MEwE0hOu5PrREs6Fcw33ymn 3PbyutPXP5Mcg/3UBQqNhG+3H4bvpB8pC0EwfFB4ISCwOrYubvIETuLi7EPYIVnE o3WH27OlZEKVZQw+QOvSOWv0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIjCCAqmgAwIBAgIORnQ3d5IJc/pIL+KNlGIwCgYIKoZIzj0EAwMwUDEkMCIG A1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9i YWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTE1MDQzMDAwMDAwMFoXDTI1 MDQzMDAwMDAwMFowUDELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24g bnYtc2ExJjAkBgNVBAMTHUdsb2JhbFNpZ24gRUNDMzg0IFNTTCBDQSAtIEczMHYw EAYHKoZIzj0CAQYFK4EEACIDYgAEZ83aiKJFxKmhUAp2JBSibN0Zfll9j+i4f3qM yEmMkeHycjRlKijTYVLLzKt42boui5fj5gSiR5CJn2ktgXtA0GJzAGSu2xAo6Suw UtjpVGuK7HPMcU295Xmqlbg6FrCno4IBSDCCAUQwDgYDVR0PAQH/BAQDAgEGMB0G A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA MB0GA1UdDgQWBBT/u8i9ydRX8A3/UKZKRkOvE84CaDAfBgNVHSMEGDAWgBQ95ilI m+oHyiFESibebt7Sg9CfWTA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0 dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjUwNgYDVR0fBC8wLTAroCmg J4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXI1LmNybDBHBgNVHSAE QDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2ln bi5jb20vcmVwb3NpdG9yeS8wCgYIKoZIzj0EAwMDZwAwZAIwPSPgOBjVY4qGtaOF Pz9McX06iFdhUf+A/tZx89y2Xy1eQ9Nh1sj5SM0hfbCTV2nGAjAnYsuqWiLwEzx0 yqrw5nMhvfQ4eszkm7o5TSWvBBg0O8QFrI7l9z4V8CwLeHdjcdo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHkjCCBXqgAwIBAgIIM3VF0i2obk4wDQYJKoZIhvcNAQELBQAwQjESMBAGA1UE AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw CQYDVQQGEwJFUzAeFw0xNTA1MDcxMjI1MzlaFw0yNjEyMzEyMzU5MDBaMEMxEzAR BgNVBAMMCkFDQ1ZDQS0xMTAxEDAOBgNVBAsMB1BLSUFDQ1YxDTALBgNVBAoMBEFD Q1YxCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA oHVLyy+miC29v/sQZfjQLLkr3gEHI1cA7Ev0mJkOjx5jkpk7xp7NbROz/EM5VVxZ Vi+mo8Wtkpc8Qzrgm4XQNaJ0IaI4LC8f4boix0mLND0zCnIGNxti15nP4HiqZ7k9 u+YkylL5MX5VNbWl/TgMjxUHzaORYKPbSMRlAQSd1b7OU0PNa7p+WoF2XqbUzMdR 0qw03tsyBvvRXgTFkIKijzHDA5cemDfxdZNP7t6LOxu0JxKDIqgvMFH88FqdeJd8 uYVWpBpohIlZ0Gt7r3K9b6jNzuVAtWlkl4cByw1n5wmMSgxPxX6BtQrFUrvilrgd zDc/8b4IBqFzINjX/P9nErJdd4aQsn62uEomZ8PUwnQ6xhkMSqFjKDqqKUKjl5Cv +PQoBA60WwIhgoxkwC1IYi5V0uciAFams8YJi3U0/ZNttR4g+JUlPjn7Vboi8OW5 YKyxentQ+kDRN6gCQc8Oysx8NJ0wZnyt8MFzb/4OlzsO3vjSl8QEk9F0QF9+3ycm Fz6dBLYQgsZDDyK28DkJbIvwtDevB0S2QrabM3sxyKBImG7rNMm7ZyxpvX9vPXz1 eGgxhJ/pTCZMBe2/ygFRLjoHEJhkSJCiooCFluUcctYlPq1PugwVeIzpZZOVZvwP V0SKAlV+TddvZVW0jF7zi8EoVJpW9z7BiD3GumxZSckCAwEAAaOCAokwggKFMC8G CCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYTaHR0cDovL29jc3AuYWNjdi5lczAd BgNVHQ4EFgQUklKuRm1bvb6FwbNhR6j/t9mTwA4wDwYDVR0TAQH/BAUwAwEB/zAf BgNVHSMEGDAWgBTSh7Tj3zcnk1X2VuqB5TbMjB4/vTCCAX8GA1UdIASCAXYwggFy MIIBbgYEVR0gADCCAWQwggEuBggrBgEFBQcCAjCCASAeggEcAEEAdQB0AG8AcgBp AGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAEkAbgB0 AGUAcgBtAGUAZABpAGEAIABkAGUAIABsAGEAIABBAEMAQwBWACAAKABBAGcAZQBu AGMAaQBhACAAZABlACAAVABlAGMAbgBvAGwAbwBnAO0AYQAgAHkAIABDAGUAcgB0 AGkAZgBpAGMAYQBjAGkA8wBuACAARQBsAGUAYwB0AHIA8wBuAGkAYwBhACwAIABD AEkARgAgAFEANAA2ADAAMQAxADUANgBFACkALgAgAEMAUABTACAAZQBuACAAaAB0 AHQAcAA6AC8ALwB3AHcAdwAuAGEAYwBjAHYALgBlAHMwMAYIKwYBBQUHAgEWJGh0 dHA6Ly93d3cuYWNjdi5lcy9sZWdpc2xhY2lvbl9jLmh0bTBVBgNVHR8ETjBMMEqg SKBGhkRodHRwOi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRp ZmljYWRvcy9yYWl6YWNjdjFfZGVyLmNybDAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0R BBAwDoEMYWNjdkBhY2N2LmVzMA0GCSqGSIb3DQEBCwUAA4ICAQA8URqZ+fk3fX/4 /gkAdB7/XmRJ+la14fKe9GPflvVVLThvCNrqkn3faW6I2VOBG72XsFstH34VoVs6 vQH+Qu/JCNhpjllxWRV6Do1Fr1o1ogKy2LK6TYUCmHuidw99FnnFfTULk/qCrqeR OeAiRA89X1aAOgRmETA8KqTN5xf08Vns7WOFLlDmCdikh+758TfqUKEfjytaKp41 C3+0hEmQ/GYvzXV793N/Irwb4w6GMIIyr6YPiMRo9QzX604Ap0Tl0RjxLXomnyNO z5jJWtxsxtbmsRrEcG/RT9iOn/KYeYAiZQAV9oem+8hMzo9gwbSsxNXu7vQtBD9u iVwxc7GJflNuQ0y9iTIS2r/0xxUoBJXD+X7V7848f7Y/iQ429a6AjB1PgLuESG/9 t+WDU4KYGYkuhberIsYCDaVC90JCD9c2Bzq2SkPCx0lWdpS6rUq0shU2049yY5yM prjTua0FAflsv4H6fcam1pIZQLHmO4q5IZKfenCCNjgPnYWh8gYPCWZdhDuGfnLo BTRhhQqNkV0KC8lsF+nkYGrt+9jWLMhhcZJSTLvYhQguZa69j/cu4/JhbnoyCXiK iyocXD1mZYKXwshHNga5f5XhDAWUEP72+DVNjSz/zc8dreVDSwc4m2/zBpPzvy4U B2uotlnJjpdeauVu/w46y9nneQXxRQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYjCCA0qgAwIBAgIIX65cxWM8aoswDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG EwJERTAeFw0xNTA1MDcxMzQ1MDRaFw0yNTA1MDQxMzQ1MDRaMFUxNzA1BgNVBAMM LkF0b3MgVHJ1c3RlZFJvb3QgSXNzdWluZyBDQSBmb3IgUHJpbWV0YWxzIDIwMTUx DTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAqBF1eOdBw7S7CI3RyyIHsL2Mt/TTfg7rnmnrxaD4fxO84wXg WokglmSGoEI8gPjZ4AoD7mMhYVjmtLh+rhT/DfU6b/43FzEbFlwI1l1DEuMQMWB1 By5GAvHP6wqX+RbQ6WjGcEMTyQQv3ZbwzSgkZ1V8h+xhSSRU4aJAU8/aqtuKjChK fVMqbIsXotW88euv7s5ZZDeNL6K3Ah7fTe04kKTz5GvYfDrDuY2Hr5+ypj8e7vsC aKMziN8VhpHZxsXC6IcdjDhjjNTq8ukC/XxJ/CMlZKhWey2sTagawkfYl1NOavC6 bYJsPQGXexUgT+6H98kpSRlNEucqajpZKbEgGQIDAQABo4IBTTCCAUkwHQYDVR0O BBYEFKsG6X8510gnrHoVXxlaGWOAyCKJMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j BBgwFoAUp6UGsSymCWDu0ZfpcK68Oxls2yEwGAYDVR0gBBEwDzANBgsrBgEEAbAt BQEBATCBywYDVR0fBIHDMIHAMD6gPKA6hjhodHRwOi8vcGtpLWNybC5hdG9zLm5l dC9jcmwvQXRvc19UcnVzdGVkUm9vdF9DQV8yMDExLmNybDB+oHygeoZ4bGRhcDov L3BraS1sZGFwLmF0b3MubmV0L2NuPUF0b3MlMjBUcnVzdGVkUm9vdCUyMDIwMTEs b3U9Q0Esb3U9QXRvcyUyMFRDLG89QXRvcyxkYz1hdG9zLGRjPW5ldD9jZXJ0aWZp Y2F0ZVJldm9jYXRpb25MaXN0MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF AAOCAQEAJ87LpXbDfkkm1ccKdQ8rzjYluTO+YVW10FCQXJFAXz3/WhQj8FjSVHoS HFHgXxHgeqEW8gMYNHIsCqW6UeTcfQTArQGU7wagS7XmH1S15zRCoykMlNl/4brb VJ+jqub1XDLOAjynKq+CPWs7uUViKkuJ0if8yVP2DKOqJEpC4BpHjhW2uwsPfmi8 Nd7sQPwfglM6yvEgJXenMND4m8qO5Z49j0mxOR3dl9E+aapoms8oS6E7ju0PGmLe lZjdIkHdCKM1mDAQy5K/93RrugNlmbl6P4zCgFHzDaoRo8sVzyWz8gBhK+mgu1np xagt9d2dmk4LYExvSOw2lXO3ZORaHQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXDCCA0SgAwIBAgIIY7ZXliUSllwwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG EwJERTAeFw0xNTA1MDcxNDEyMjRaFw0yNTA1MDQxNDEyMjRaME8xMTAvBgNVBAMM KEF0b3MgVHJ1c3RlZFJvb3QgSXNzdWluZyBDQSBmb3IgV1dFIDIwMTUxDTALBgNV BAoMBEF0b3MxCzAJBgNVBAYTAkRFMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA5yD8eiYuILo6nqF8hSENi9XkfyFKnh4vrfF0f9q9tQJ9yvb5N1yAr1PY a7WMsp2ieXjbOOhoEgV68HvIX1rqgzzYSK4oSkqmonE8MkZLb8kFPWDVal/1kvvL IGaBWVsH0BpuQXLqVTxDn/t677YLurKUEY6QA3fVFC6vom/QrkRWNzNwNfWY2etg XhqXTK58xEWDZvoTd5zEWVrRx4mH3GM0plXFjZgX5Irf8jUnMEg51qAmauxuEkW7 Fykxb0lHwSIpvfKzPvVlaDl8biNFAgGRRgg4tQXBaRy4lRqe98MI62aA30qKBXhZ v56U7NJzIf4j0blvNXiSrE2e+cvl3wIDAQABo4IBTTCCAUkwHQYDVR0OBBYEFDUp gZ+4qKGkqqO4uL7WzkRxhOLhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU p6UGsSymCWDu0ZfpcK68Oxls2yEwGAYDVR0gBBEwDzANBgsrBgEEAbAtBQEBATCB ywYDVR0fBIHDMIHAMD6gPKA6hjhodHRwOi8vcGtpLWNybC5hdG9zLm5ldC9jcmwv QXRvc19UcnVzdGVkUm9vdF9DQV8yMDExLmNybDB+oHygeoZ4bGRhcDovL3BraS1s ZGFwLmF0b3MubmV0L2NuPUF0b3MlMjBUcnVzdGVkUm9vdCUyMDIwMTEsb3U9Q0Es b3U9QXRvcyUyMFRDLG89QXRvcyxkYz1hdG9zLGRjPW5ldD9jZXJ0aWZpY2F0ZVJl dm9jYXRpb25MaXN0MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEA I8fQ/4v3IovJs4MOM02b4RfRZY/rk8CknUv9IZ+uDO5fbnP5ato0kw35NWuYjuCT AsQcsoD7BSNR7c8j0cGDZjCiGQKdghXsTEE56JmmnxfM2QjjBDAG8mpBL4ckMysY ODo25k1UhMCDqJYzAZ4HGQE5ATp1kkhgkDKrqrnjhGm0LfH8QNYk9UsdNllOvVl9 ZPx79FgooDQMpz+6qK5AbUc0QVQPfkLjjzH4n3oOnEwN7eXP0WBC/tPxq+u3AA6Q bIcOm64Wb9ggYEq/4gnwse+6Y39JkeHRZijqJdzo4q8M2CxbYJVwGwLVy24Xko5y brgxo8AmLTPyLYyWf7OUBg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYjCCA0qgAwIBAgIQcSI8pSIYXqxEzxdw0aiqXTANBgkqhkiG9w0BAQsFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMTUwNTEyMDAwMDAwWhcNMjUwNTExMjM1OTU5WjB/MQsw CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNV BAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxMDAuBgNVBAMTJ1N5bWFudGVjIENs YXNzIDMgRUNDIDI1NiBiaXQgRVYgQ0EgLSBHMjBZMBMGByqGSM49AgEGCCqGSM49 AwEHA0IABC93+aAYNSQS+F5P39qxy3AhmkNBfnYME9lyISEJCvfrBSSiVc2ySA6v e6GH2RRknqCtxX85cEyaQgABoxYHiL2jggFXMIIBUzASBgNVHRMBAf8ECDAGAQH/ AgEAMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNvbS9wY2EzLWc1 LmNybDAOBgNVHQ8BAf8EBAMCAQYwLgYIKwYBBQUHAQEEIjAgMB4GCCsGAQUFBzAB hhJodHRwOi8vcy5zeW1jZC5jb20wXwYDVR0gBFgwVjBUBgRVHSAAMEwwIwYIKwYB BQUHAgEWF2h0dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkaF2h0 dHBzOi8vZC5zeW1jYi5jb20vcnBhMCsGA1UdEQQkMCKkIDAeMRwwGgYDVQQDExNT WU1DLUVDQy1DQS1wMjU2LTIzMB0GA1UdDgQWBBRycjbGpzGeh4nHMn3sOvWiZD94 ejAfBgNVHSMEGDAWgBR/02Wnwt3su/AwCfNDOfoCrzMxMzANBgkqhkiG9w0BAQsF AAOCAQEAOiHdrJlwGYxgg+Zh8ePYDYqFuLbuom7+myENWaZ+NIsKAkHheANBJWJA Ot6t8TKkGp7G+YeDQ/oEZRGwYyIrQgi7gyZqmpcojna6Wp1OxF1KHotIDEAh/LBk 73jOaJglZVeodRO40nhARoHHB0eJlIWoA8DybXAjVRMW0fxmAvFb3pjuKjokQtE9 muqFQfr8proZ8BdhmMv41d5IRATmkUU5jGJzAbph4EuypmgXSIES0IHsMxNxwJjU ufpCh8h4dkv/pqkWH3sArdavhoK/NURrDkzPa+EwbIDVooWWBbLCBQ8LGbCyOeKp Gov7Dys9bWC8vFML1cH+QDRfDwymdA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGTDCCBDSgAwIBAgIIMtYr/GdQGsswDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMB4XDTE1MDUxNDA3MDAzOFoXDTMwMDUxNDA3MDAzOFowgYcxCzAJBgNVBAYT AklUMQ8wDQYDVQQIDAZNaWxhbm8xDzANBgNVBAcMBk1pbGFubzEjMCEGA1UECgwa QWN0YWxpcyBTLnAuQS4vMDMzNTg1MjA5NjcxMTAvBgNVBAMMKEFjdGFsaXMgRXh0 ZW5kZWQgVmFsaWRhdGlvbiBTZXJ2ZXIgQ0EgRzEwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQD1Ygc1CwmqXqjd3dTEKMLUwGdb/3+00ytg0uBb4RB+89/O 4K/STFZcGUjcCq6Job5cmxZBGyRRBYfCEn4vg8onedFztkO0NvD04z4wLFyxjSRT bcMm2d+/Xci5XLA3Q9wG8TGzHTVQKmdvFpQ7b7EsmOc0uXA7w3UGhLjb2EYpu/Id uZ1LUTyEOHc3XHXI3a3udkRBDs/bObTcbte80DPbNetRFB+jHbIw5sH171IeBFGN PB92Iebp01yE8g3X9RqPXrrV7ririEtwFMYp+KgA8BRHxsoNV3xZmhdzJm0AMzC2 waLM3H562xPM0UntAYh2pRrAUUtgURRizCT1kr6tAgMBAAGjggHVMIIB0TBBBggr BgEFBQcBAQQ1MDMwMQYIKwYBBQUHMAGGJWh0dHA6Ly9vY3NwMDUuYWN0YWxpcy5p dC9WQS9BVVRILVJPT1QwHQYDVR0OBBYEFGHB5IYeTW10dLzZlzsxcXjLP5/cMA8G A1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbtifN7OHCUyQICNtAw RQYDVR0gBD4wPDA6BgRVHSAAMDIwMAYIKwYBBQUHAgEWJGh0dHBzOi8vd3d3LmFj dGFsaXMuaXQvYXJlYS1kb3dubG9hZDCB4wYDVR0fBIHbMIHYMIGWoIGToIGQhoGN bGRhcDovL2xkYXAwNS5hY3RhbGlzLml0L2NuJTNkQWN0YWxpcyUyMEF1dGhlbnRp Y2F0aW9uJTIwUm9vdCUyMENBLG8lM2RBY3RhbGlzJTIwUy5wLkEuJTJmMDMzNTg1 MjA5NjcsYyUzZElUP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q7YmluYXJ5MD2g O6A5hjdodHRwOi8vY3JsMDUuYWN0YWxpcy5pdC9SZXBvc2l0b3J5L0FVVEgtUk9P VC9nZXRMYXN0Q1JMMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEA OD8D2Z2fw76+GIu+mDEgygH/y7F9K4I6rZOc3LqGBecO3C0fGcIuuG7APtxGGk7Y nk97Qt+3pDoek9EP65/1u128pRncZcjEAeMgKb7UuJxwoR6Sj5zhOadotKcCQqmF Si99ExNo6dTq5Eyp1KrqepLmezbO9owx4Q44mtNpfKLMgzDqOn/dwNMo/pGYbMfP DjhxEnta1HXgcEcgCk1Au16xkdzapwY4sXpKuwB24phfWF+cveKAQ0Rncmvrm34i 9B6leZUkSHDe4mRkbO5nObhKHYRmVSr0Q/wvGCmTgGTKuw/Gj8+RFb5MEkOKEcJn I32CPohpiW/jlpeLaFBIgJnXuZTxmfTX55sqtXDlKxRxFwq1W3kML4UfGZsgjx1l hX5fQ1QlEZeO9CyPpgGO5Py2KXXKhUxCtF7tawAYimWwslxvPCjHDND/WhM1Fz9e 2yqwHcSQAOUVv5mk9uYc6/NSLwLb5in3R728GNEpHHhbx5QZhtdqR8mb56uJUDKI AwnnZckcR+SLGL2Agx7hY7YCMOQhSsO6PA81M/mGW2hGCiZw3GULJe9ejL/vdS0I PWrp7YLnXUa6mtXVSBKGrVrlbpJaN10+fB4Yrlk4O2sF4WNUAHMBn9T+zOXaBAhj vNlMU7+elLkTcKIB7qJJuSZChxzoevM2ciO3BpGuRxg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGRzCCBC+gAwIBAgIILNSK07EeD4kwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMB4XDTE1MDUxNDA3MTQxNVoXDTMwMDUxNDA3MTQxNVowgYIxCzAJBgNVBAYT AklUMQ8wDQYDVQQIDAZNaWxhbm8xDzANBgNVBAcMBk1pbGFubzEjMCEGA1UECgwa QWN0YWxpcyBTLnAuQS4vMDMzNTg1MjA5NjcxLDAqBgNVBAMMI0FjdGFsaXMgQ2xp ZW50IEF1dGhlbnRpY2F0aW9uIENBIEcxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAwPzBiVbZiOL0BGW/zQk1qygpMP4MyvcnqxwR7oY9XeT1bES2DFcz lZfeiIqNLanbkyqTxydXZ+kxoS9071qWsZ6zS+pxSqXLs+RTvndEaWx5hdHZcKNW Gzhy5FiO4GZvGlFInFEiaY+dOEpjjWvSeXpvcDpnYw6M9AXuHo4JhjC3P/OK//5Q FXnztTa4iU66RpLteOTgCtiRCwZNKx8EFeqqfTpYvfEb4H91E7n+Y61jm0d2E8fJ 2wGTaSSwjc8nTI2ApXujoczukb2kHqwaGP3q5UuedWcnRZc65XUhK/Z6K32KvrQu NP32F/5MxkvEDnJpUnnt9iMExvEzn31zDQIDAQABo4IB1TCCAdEwQQYIKwYBBQUH AQEENTAzMDEGCCsGAQUFBzABhiVodHRwOi8vb2NzcDA1LmFjdGFsaXMuaXQvVkEv QVVUSC1ST09UMB0GA1UdDgQWBBR+YPz4bKc9Pdeuk6F5Ao+zdCk79TAPBgNVHRMB Af8EBTADAQH/MB8GA1UdIwQYMBaAFFLYiDrIn3hm7YnzezhwlMkCAjbQMEUGA1Ud IAQ+MDwwOgYEVR0gADAyMDAGCCsGAQUFBwIBFiRodHRwczovL3d3dy5hY3RhbGlz Lml0L2FyZWEtZG93bmxvYWQwgeMGA1UdHwSB2zCB2DCBlqCBk6CBkIaBjWxkYXA6 Ly9sZGFwMDUuYWN0YWxpcy5pdC9jbiUzZEFjdGFsaXMlMjBBdXRoZW50aWNhdGlv biUyMFJvb3QlMjBDQSxvJTNkQWN0YWxpcyUyMFMucC5BLiUyZjAzMzU4NTIwOTY3 LGMlM2RJVD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0O2JpbmFyeTA9oDugOYY3 aHR0cDovL2NybDA1LmFjdGFsaXMuaXQvUmVwb3NpdG9yeS9BVVRILVJPT1QvZ2V0 TGFzdENSTDAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAE2TztUk vkEbShZYc19lifLZej5YjLzLxA/lWxZnssFLpDPySfzMmndz3F06S51ltwDe+blT wcpdzUl3M2alKH3bOr855ku9Rr6uedya+HGQUT0OhqDo2K2CAE9nBcfANxifjfT8 XzCoC3ctf9ux3og1WuE8WTcLZKgCMuNRBmJte9C4Ug0w3iXqPzq8KuRRobNKqddP jk3EiK+QA+EFCCka1xOLh/7cPGTJMNta1/0u5oLiXaOAHeALt/nqeZ2kZ+lizK8o Tv4in5avIf3ela3oL6vrwpTca7TZxTX90e805dZQN4qRVPdPbrBlWtNozH7SdLeL rcoN8l2EXO6190GAJYdynTc2E6EyrLVGcDKUX91VmCSRrqEppZ7W05TbWRLi6+wP jAzmTq2XSmKfajq7juTKgkkw7FFJByixa0NdSZosdQb3VkLqG8EOYOamZLqH+v7u a0+ulg7FOviFbeZ7YR9eRO81O8FC1uLgutlyGD2+GLjgQnsvneDsbNAWfkory+qq AxvVzX5PSaQp2pJ52AaIH1MN1i2/geRSP83TRMrFkwuIMzDhXxKFQvpspNc19vcT ryzjtwP4xq0WNS4YWPS4U+9mW+U0Cgnsgx9fMiJNbLflf5qSb53j3AGHnjK/qJzP a39wFTXLXB648F3w1Qf9R7eZeTRJfCQY/fJU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGcjCCBVqgAwIBAgIBKTANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy dW0gMTAeFw0xNTA1MTQxMzMyMjdaFw0yNTA1MTExMzMyMjdaMIHfMQswCQYDVQQG EwJUUjEYMBYGA1UEBwwPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKDDlUdXJraXll IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU QUsxLTArBgNVBAsMJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT TTFDMEEGA1UEAww6VFVCSVRBSyBLYW11IFNNIFNTTCBTZXJ0aWZpa2EgSGl6bWV0 IFNhZ2xheWljaXNpIC0gU3VydW0gMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAL2/oOCsOs5RrqU5xA8qZuHMy2hujUGeLeY4qcoICE+KuS5bLvexKrmt kZS/wCrWxqOeOriNlC1F7lia4yHMJp39vG8v6zgaixeyyCxeiIt3AFHziOx7xfOI qLS5Ygbm+FyEwSXOLA+wjg7FHoJ50INzm/Y+IeN96jYBA//1H9b76KFIsGtWn1Cp MzglSPqKusmoir4l3NzQEDYf68xmFzB/VDbYPd90j6bzx5T/8Y9RR0CW/m7e6DCf MtBCjCQkum6E9ReSfgGizcDzSGbQQFxVBBYXi/hgBsP6RySuZNB9Pgru6hSxskBp MPoppgeVBBb/+EdSDTbRqth5fVsElEMCAwEAAaOCAkIwggI+MB8GA1UdIwQYMBaA FGU/x4qGxjzdPFRcNfg67VIMR1fIMB0GA1UdDgQWBBT2NTUXri77t333dheKZWTr Z3pAqzAOBgNVHQ8BAf8EBAMCAQYwggEbBgNVHSAEggESMIIBDjCCAQoGBFUdIAAw ggEAMCsGCCsGAQUFBwIBFh9odHRwOi8vZGVwby5rYW11c20uZ292LnRyL2lsa2Uv MIHQBggrBgEFBQcCAjCBwx6BwABCAHUAIABzAGUAcgB0AGkAZgBpAGsAYQAgAGkA bABlACAAaQBsAGcAaQBsAGkAIABTAGUAcgB0AGkAZgBpAGsAYQAgAEkAbABrAGUA bABlAHIAaQBuAGkAIABvAGsAdQBtAGEAawAgAGkA5wBpAG4AIABiAGUAbABpAHIA dABpAGwAZQBuACAAdwBlAGIAIABzAGkAdABlAHMAaQBuAGkAIAB6AGkAeQBhAHIA ZQB0ACAAZQBkAGkAbgBpAHoALjASBgNVHRMBAf8ECDAGAQH/AgEAMD8GA1UdHwQ4 MDYwNKAyoDCGLmh0dHA6Ly9kZXBvLmthbXVzbS5nb3YudHIvc3NsL1NTTEtPS1NJ TC5TMS5jcmwweAYIKwYBBQUHAQEEbDBqMDkGCCsGAQUFBzAChi1odHRwOi8vZGVw by5rYW11c20uZ292LnRyL3NzbC9TU0xLT0tTTS5TMS5jZXIwLQYIKwYBBQUHMAGG IWh0dHA6Ly9vY3Nwc3Nsa29rczEua2FtdXNtLmdvdi50cjANBgkqhkiG9w0BAQsF AAOCAQEArDB3/x+K/9STX/RcVKRPO5mv03Uli+7tiZk51ipo5ItpPpSUbjHrXy4E wtc0Rra/zFFHH7AEFxAUU3SL1M3sZcmTMSvSfVhbNW6kZUE1VRY0ZhnBZe0pY1eA OXxj03FTqEGrushFywTqgrFZdLuQ/4SfY8/8afyI5StH6nAOiMgyDNppl93XIS0U 6zz1iCOwb6ToBYTAIK+BFP04PMA2wqc7ulgQH0uu8pPPzkdRostMaxwtSreedA+c CGExK5OyA/BX0VtjlEUxJcmmoY3fXO6z1q0/G2PWtvlsBZB1kQkWpUgaTcoiWUO/ 8qMZRgLmY+jlCktjqp7mkrwusrzEHg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIRAPAdS+57fKN7PAVmrAWXJFgwDQYJKoZIhvcNAQEMBQAw gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE1MDUx ODAwMDAwMFoXDTI1MDUxNzIzNTk1OVowcjELMAkGA1UEBhMCVVMxCzAJBgNVBAgT AlRYMRAwDgYDVQQHEwdIb3VzdG9uMRUwEwYDVQQKEwxjUGFuZWwsIEluYy4xLTAr BgNVBAMTJGNQYW5lbCwgSW5jLiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIteAVa57GsR70jpQ56byLpTkaW9 qyr6Xjo14Q1cNepSqJk0KA9+WStIa+e010t9L4PP/osmw1l5H2Chaaday583Ie8Y vZv9Qet1fLeW2V6GyyoS4qf3A+TO5gX3QZsevNL20WZpUQzete08CyfPiI4gPeNO lY8VNMYmy/c/ZOn1MCV9zak5mz/qemkri8R9C/hWk7Zrlsrsz9J7vUO+0/WJ2k10 SSHEvfUwvLxJqWUVs9b/vx2QlJwIJbatz/zH2ftV1RnQSr9iRuUk7Y++ZJgMalGe eoBzIKm02b9Dap4QrSugzWStQDnS4rjbwvI6o+K3FpcfHvbP3zweWOkAB2sCAwEA AaOCAWwwggFoMB8GA1UdIwQYMBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1Ud DgQWBBR+A1plQWunfgrhuJ0I6h2OHWrHZTAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYD VR0gBBswGTANBgsrBgEEAbIxAQICNDAIBgZngQwBAgEwTAYDVR0fBEUwQzBBoD+g PYY7aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQ2VydGlmaWNhdGlv bkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsGCCsGAQUFBzAChi9odHRw Oi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9SU0FBZGRUcnVzdENBLmNydDAkBggr BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUA A4ICAQAQn6BgCIF0oaCEeGBMOTnaZHfvGQpyOSOUO5F9fzSLl1hOWQotaMMQQrCg eoGMe6sxMiA55CJz4N7JF12DxXUt4RFHWQGeXcD03RJq0G0wIOizyk/fmuCnF58a L4d+61DhU/P4R9mMYPLJZWWc8NoB5rLy2AeYh983iZhVEkLJ5C3eLb6qZJRO2S7m wtXywObp6hk+NwuJX8k6+E9HQD6vGn+i9oUBiBc2tSPquf66a0gLAiA5rsNh65Wl oXPHHF9UM3NXSzaLm1so4z6xC3hcaxSnEMzl2j+66dayLR1wVLpeq31PKYkQ4DqQ BMXuuY5DouNjWH9Ji3E+V2IjQNFdlmQiYVaflmdHh7zlACCkaOLBoIF7aHMIxG1O cHno3VXXCVy5nQqVpgzZ2+KKVeu54eealRRMWAZBwRCqqrE64qVKSuDZyR/CoJe7 Bu8ZANsCvpbx+1SPk5r6MCI2qXcmH5Qok+kTPUXROjVIHpgNgnDAC1ooh6F4UT+1 p1ymkSIAQky5gBWAKrEtiU/3uh4YxIxZHnNJo6h7vB/3Vk1Qn2cWp8cXSOdtVFd2 bpdYW3hkpO1itAA7Bn55uFhfboTWQ7xP2zmqKPDBiQnF++MYRLflsotdlfkjWgty 92k61leL4en0YL7EUSsRrP5Is3JzyhNQcw0EdsoB4ULC1yHP+Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtzCCA5+gAwIBAgIQC/SnriLlEJ2vk5gjHMPbPDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTUwNTE5MTIwMDAwWhcNMjUwNTE5MTIwMDAwWjBdMQswCQYDVQQG EwJVUzEZMBcGA1UEChMQU29uYXZhdGlvbiwgSW5jLjEXMBUGA1UECxMOc29uYXZh dGlvbi5jb20xGjAYBgNVBAMTEVNvbmF2YXRpb24gSW9UIENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxUzPBidPFEfnr+t8ITuxpwjK2FkxG4QnlPOI +K4Tt5IkVABpqp9G0CpgEHh5DSp8b8L5fzWLVQqT9b+UUqGT6KXi4cichYfUnMTl /ehlemhUobdA1RnnIb9b8u50D4EaqwdjPISuvm0uDtJpvMO25gyKS376G6CZoFAW u3faZwEBwXHioqwpwGtZVBRc0Ckf9NGDZQrKaNqzmOV8mlewsVixomGV/yTNdkrZ xpmiUzTM8kkmAiCk8V41TwdUHbSm+SEOnTh4E+BXOiVrW/4Bc2H20qmqHh0w7JZQ E2VFqI7p8CDLxrZIxOhXMl+18HrIGntpq6DjoKQH8Fipe2l8JQIDAQABo4IBaTCC AWUwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYweQYIKwYBBQUH AQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYI KwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz c3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL2NybDQu ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA9BgNVHSAE NjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu Y29tL0NQUzAdBgNVHQ4EFgQUOjNgKWFClk3CDEFMlkaPw0quWNAwHwYDVR0jBBgw FoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBACBbQH66 +1bUUKMA8SBDjZzlPJJIGt3+wyqPf9FVJ4xbkcgAVWKQwvPR35wjsDvUWqKuMbKm CWJeqt2fEIEf14pvOpjNPUqxQ88AzmrH54L+j+SaVehGKcVxQYOzaFpqfMcwZE9i +qzv4Zz26aKaL9x/VNHKjcYFDCruE1CXtbn92InKGqbzn1N6WYXKmjuG/7AzsOIs T8K2taxWGaOV/k1RVYkYi6HWDuq39AZbeG94SYiqFfgYQxUCMFUguW2bYjzGSO35 EAENF/SL5aN4fleteWZNk7S2QiWVEthSBgm9Lh+WeNA5LCxK0FuPpd3Vh0G7B5zl Xlkgq/EWxjhyQ1A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQDaN4TTAzd/C1C8vO3KqjOjANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE1MDUxOTEyMDAwMFoXDTI1MDUxOTEyMDAwMFowTDEL MAkGA1UEBhMCVVMxEzARBgNVBAoTClBsZXgsIEluYy4xKDAmBgNVBAMTH1BsZXgg RGV2aWNlcyBIaWdoIEFzc3VyYW5jZSBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCpA+uFY2Ff43/ksnI8+y8NQT1If8XnlRxAcXHt1LB4RGe2mota 8wvJcXsZpfoZ8+f1xrmeJFxi9j1fpfUtma/OWuY6HT0ajgfKzKYX/4qdgclLFZfB TWw6YHy7Qit/zCi96y2A0wl1z70q4/41QRtT11fUErEQ6wlsJg/DYJ5uevtosnpW fsBSE3ZNQDVtp1CNkrUfaxl2izYT/rWWZnBkfD41tC1UbdiqqHnidE0Q90AkaDc0 L3v9LumsJnAX3GqjpWnUq+v+JcKGQpI5hd0sn5f+QA1m2efq1s/ggl8LLX89Wkkj byB1zronfOx+lWsq7c1M6FSAAZhOdsvs0JkLAgMBAAGjggF1MIIBcTASBgNVHRMB Af8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjB/BggrBgEFBQcBAQRzMHEwJAYI KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcwAoY9 aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5j ZUVWUm9vdENBLmNydDBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdp Y2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1Ud IAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy dC5jb20vQ1BTMB0GA1UdDgQWBBSUi4n3SHKJ8lFK2Yh75WG1qpzVATAfBgNVHSME GDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAapWH tA4Y6l0SUav52bZT6hf53MbTXR3v12UmbkRIXmhz3EEs+UqCF2YvBQfYtWh1oABp wM/EVzWyPqf1jFUsRVXJZCfaqgRDMRvw3+ez9Tz7Hmj/ojLHVnMhaO7u733KzCcp Hnt4EepFFow2VtEDlNX+TfJKVAglIdrHg44VJ08q0h6gw80apzh6g5+MHn7gSTJn Uz8QbAnJu5QRc5r6rypp73gvz/YCC8ZJ1eAGYfHvxa6kMAgxVNHk7VSwnxtEmdWm H69U1G1qCmz3ap8693qQG8dfxiOtr3tRIcbQDTYBmWQknOQm0YRsxjyOYnB1bJb2 J9dzoLR/bM/X0BDzvA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGDCCBACgAwIBAgIMYT04vwAAAABR03GQMA0GCSqGSIb3DQEBCwUAMIG+MQsw CQYDVQQGEwJVUzEWMBQGA1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2Vl IHd3dy5lbnRydXN0Lm5ldC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMDkg RW50cnVzdCwgSW5jLiAtIGZvciBhdXRob3JpemVkIHVzZSBvbmx5MTIwMAYDVQQD EylFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjAeFw0x NTA1MjAxNTM3NTdaFw0yNTA1MjAxNjA3NTdaMDsxCzAJBgNVBAYTAlpBMREwDwYD VQQKEwhMQVd0cnVzdDEZMBcGA1UEAxMQTEFXdHJ1c3QyMDQ4IENBMjCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAM1vwX9RcVaK4nphvMkAeA3/oEnkCR7l fTiEWipx0m6XjL6P5Vh+A6KmWleps9+NjCP7WXLQn5WX4hJUf06uAKaQK4I4gMUM W12dvDLCeSqYn3zeRWcmQnhbD9LSnElTMc9zXeRn8NT1vSic8zO6lk77Kfp334I9 Qr5wEXk3aD3qLHfwCGpmWwuYwccBPS/se58BeZfp9V7PB4XzIfCX/WsMJF/mVxCS UwuI/WoKoZfnFAG5dVdZGsuqg4inzVvWfhGB9F6KPQkGY0sjJVFMU0tuf0YognU9 NHCD7Ji6iGsF++uVJs50PjvNtY8RQSWNpgp5NL/1ME84bg4Ehl9lVuECAwEAAaOC AZYwggGSMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMIGEBgNV HSAEfTB7MDYGCmCGSAGG+mwKAQgwKDAmBggrBgEFBQcCARYaaHR0cDovL3d3dy5l bnRydXN0Lm5ldC9jcHMwQQYKYIZIAYb6bAoCATAzMDEGCCsGAQUFBwIBFiVodHRw czovL3d3dy5sYXd0cnVzdC5jby56YS9yZXBvc2l0b3J5MDMGCCsGAQUFBwEBBCcw JTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5uZXQwMAYDVR0fBCkw JzAloCOgIYYfaHR0cDovL2NybC5lbnRydXN0Lm5ldC9nMmNhLmNybDA+BgNVHSUE NzA1BggrBgEFBQcDBAYIKwYBBQUHAwIGCWCGSAGG+msoAwYIYIZIhvprKAQGCisG AQQBgjcUAgIwHwYDVR0jBBgwFoAUanImetAe733nO2lR1GyNn5ASZqswHQYDVR0O BBYEFHPcFW2rROaifurp9vC8yPA2FrtLMA0GCSqGSIb3DQEBCwUAA4IBAQByfI1i WRY871GT1nhU9IIkqvL3XpltrlfoymEzahD7iey32yofOH8aPud55eQ27/2EUUUr /6e1isjVjTwAnoVL6HAkjpg9zoKs42ivKxv4FXrzm8DdGzbWBsBRie+nY0osrd+B ofheQeKpoGIO4NnJZNdVhSH3HM2IqtI+INoMlMGRwj21bLBDKTIHg1ZlsVP76w2c 2ckxG6iLL0LQHkKdTsY+TfyKnMjeXAryP3Hvmrrlv8uZIGJqwUmYdEtBrKAtvUEn BhfBN0WAH/k5lW96h7ZXusOFhIKcb1qTfpLph7qzmfsqSx9g1PUc0ArFYyc/Dfep O9/OqIfspIts6Zhn -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkjCCA3qgAwIBAgITBn+USionzfP6wq4rAfkI7rnExjANBgkqhkiG9w0BAQsF ADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNj b3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4x OzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1 dGhvcml0eSAtIEcyMB4XDTE1MDUyNTEyMDAwMFoXDTM3MTIzMTAxMDAwMFowOTEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM 9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L 93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm jgSubJrIqg0CAwEAAaOCATEwggEtMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgGGMB0GA1UdDgQWBBSEGMyFNOy8DJSULghZnMeyEE4KCDAfBgNVHSMEGDAW gBScXwDfqgHXMCs4iKK4bUqc8hGRgzB4BggrBgEFBQcBAQRsMGowLgYIKwYBBQUH MAGGImh0dHA6Ly9vY3NwLnJvb3RnMi5hbWF6b250cnVzdC5jb20wOAYIKwYBBQUH MAKGLGh0dHA6Ly9jcnQucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY2Vy MD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwucm9vdGcyLmFtYXpvbnRydXN0 LmNvbS9yb290ZzIuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQsF AAOCAQEAYjdCXLwQtT6LLOkMm2xF4gcAevnFWAu5CIw+7bMlPLVvUOTNNWqnkzSW MiGpSESrnO09tKpzbeR/FoCJbM8oAxiDR3mjEH4wW6w7sGDgd9QIpuEdfF7Au/ma eyKdpwAJfqxGF4PcnCZXmTA5YpaP7dreqsXMGz7KQ2hsVxa81Q4gLv7/wmpdLqBK bRRYh5TmOTFffHPLkIhqhBGWJ6bt2YFGpn6jcgAKUj6DiAdjd4lpFw85hdKrCEVN 0FE6/V1dN2RMfjCyVSRCnTawXZwXgWHxyvkQAiSr6w10kY17RSlQOYiypok1JR4U akcjMS9cmvqtmg5iUaQqqcT5NJ0hGA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxzCCAq+gAwIBAgITBn+USjDPzE90tfUwblTTt74KwzANBgkqhkiG9w0BAQsF ADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNj b3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4x OzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1 dGhvcml0eSAtIEcyMB4XDTE1MDUyNTEyMDAwMFoXDTM3MTIzMTAxMDAwMFowOTEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv b3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG 8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr Zt6jggExMIIBLTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNV HQ4EFgQUq7bb1waeN6wwhgeRcMecxBmxeMAwHwYDVR0jBBgwFoAUnF8A36oB1zAr OIiiuG1KnPIRkYMweAYIKwYBBQUHAQEEbDBqMC4GCCsGAQUFBzABhiJodHRwOi8v b2NzcC5yb290ZzIuYW1hem9udHJ1c3QuY29tMDgGCCsGAQUFBzAChixodHRwOi8v Y3J0LnJvb3RnMi5hbWF6b250cnVzdC5jb20vcm9vdGcyLmNlcjA9BgNVHR8ENjA0 MDKgMKAuhixodHRwOi8vY3JsLnJvb3RnMi5hbWF6b250cnVzdC5jb20vcm9vdGcy LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBAG5Z+hfC ycAuzqKJ4ClKK5VZUqjH4jYSzu3UVOLvHzoYk0rIVqFjjBJwa/L5MreP219CIdIX di3s9at8ZZR+tKsD4T02ZqO/43FQqnSkzF/G+OxYo3malxhuT9j7bNiA9WkCuqVV bUncQt79aEjDKht7viKQnoybiHB6dtWAXMNObcCviQMqTcoV+sQOpKJMvQanxUk+ fKQLGKlkpu9zKNr2kWdx874JVpYhDCUzW2RX9TtQ04VT6J0xTEew55OJj02jNxHu Gijg0YLZtWLNWEXkNDkVpZozXbhuTM6GJKhwLn2rmgRgtFTWUDbeq3YE/7NHu+3a LOL51JEnEI+4hac= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5DCCAsygAwIBAgITBn+USnERqsPqc7pMrAdXJpbfizANBgkqhkiG9w0BAQsF ADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNj b3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4x OzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1 dGhvcml0eSAtIEcyMB4XDTE1MDUyNTEyMDAwMFoXDTM3MTIzMTAxMDAwMFowOTEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv b3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZL Y7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri 83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKOCATEwggEtMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTT7Mc6ZW7M4dp2mlb7 nPOGbVflgTAfBgNVHSMEGDAWgBScXwDfqgHXMCs4iKK4bUqc8hGRgzB4BggrBgEF BQcBAQRsMGowLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLnJvb3RnMi5hbWF6b250 cnVzdC5jb20wOAYIKwYBBQUHMAKGLGh0dHA6Ly9jcnQucm9vdGcyLmFtYXpvbnRy dXN0LmNvbS9yb290ZzIuY2VyMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwu cm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY3JsMBEGA1UdIAQKMAgwBgYE VR0gADANBgkqhkiG9w0BAQsFAAOCAQEAeyHnnDOGsjKqSrdQibquHlGrrtMjqGnK /m7dZLQCB/VZxYEp2OhR4I/Lf8s9B9WcaGKvyscPiovgVKhwSr5NzEfhqXQE7YT/ bbfVBWqRyfTEZ8x44095xFCPErRpQOddBWmPW4byBwnmUeOlS8tFEdYi9PXD38b5 OY7/j2YRsShyvzKre7+C/8aQBOrt1Q0sfJYDxq4Chx6YWpf1YqikV7DL/AKi2zxm +Vq+Vx7yntdcKzEDKluFweG0OHAHXy6VoVNeifx0gRks5harEpgtibf8dxDWVuRs mWYARW/NX/vSzAG25AaCKROgcXR7gvL9xmDslFGwaO4bgc/Q9IrcUg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCBHqgAwIBAgITBn+USi+ZU51QWu3y3j7YVwHmyjANBgkqhkiG9w0BAQsF ADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNj b3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4x OzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1 dGhvcml0eSAtIEcyMB4XDTE1MDUyNTEyMDAwMFoXDTM3MTIzMTAxMDAwMFowOTEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg 1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K 8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r 2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR 8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz 7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 +XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI 0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjggExMIIBLTAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUsAzwTDD0BVgCSP0z5VKv S4TjZlIwHwYDVR0jBBgwFoAUnF8A36oB1zArOIiiuG1KnPIRkYMweAYIKwYBBQUH AQEEbDBqMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcC5yb290ZzIuYW1hem9udHJ1 c3QuY29tMDgGCCsGAQUFBzAChixodHRwOi8vY3J0LnJvb3RnMi5hbWF6b250cnVz dC5jb20vcm9vdGcyLmNlcjA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnJv b3RnMi5hbWF6b250cnVzdC5jb20vcm9vdGcyLmNybDARBgNVHSAECjAIMAYGBFUd IAAwDQYJKoZIhvcNAQELBQADggEBAEAYjKahC5+1WtSuad6bxr0iozuII35V12r0 0D59cm/zWGLHSsoOcn5NK1vM+0zpUo2npQAG5OvmsBKtBQAZVqIhUdDFW06CQhr/ PERxcFwiNa3FzjJ0eS136pv0GMLKDmMXdpjWNUAcRFMbgHlNNBjoSxTN9SdbD+kr WWjAw1wsDfp8B9lZFfOGX4Op9F1WmY80o+K4gTjXFEqyCDfrvrH3+P6dI2to/LTB dAezXg033EtLUw69atCLtd8r8TIMAE2IGFt5rHg4sEG6NYPXkOrQqs6JLaFxibKq 669TfBlcloGLc80dG96ryjpNIzEUtT5Eyc6KIl1Z/I09iBxEWQM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGLTCCBRWgAwIBAgIQC2lX32EvUZClkNylRLd1oTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBGZWRlcmF0ZWQgVHJ1 c3QgQ0EwHhcNMTUwNTI4MTIwMDAwWhcNMjUwNTI4MTIwMDAwWjB5MQswCQYDVQQG EwJVUzEkMCIGA1UEChMbQW5uZSBBcnVuZGVsIE1lZGljYWwgQ2VudGVyMR4wHAYD VQQLExVBQU1DIERpcmVjdCBNZXNzYWdpbmcxJDAiBgNVBAMTG0FBTUMgRGlyZWN0 IEludGVybWVkaWF0ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AMoshHlbl4BvDMuJxkJK7dYBX+XRHRhvsUp+GIGir2tYzlZmbTkZWc8tRxJ/SjBw eLO+lMvpbtd+u0rq68c8IRnyYNootzodiG82Rj3/GHgWLCu2HON8RGB/mRlcTlOR C5TlNIM4sMb8yovBCCLjFnvXUeF+rdyQk+StrxFhn8628r0gnr8EPTxuQN3U1gUP f6v3/OScHtjUeVV8qQdKurCkTRN2+FmuIp/mgQXK/M1iFZ6l0fT0zGVfbTPK9XPo MpWwE6jnX8rrJoPljmGbn40NZZjh+pmw+gLnrjSWGbb/ZDOqITWsSorBxQpt379y fzjGZOMT+Oi96CRh4v+M0hECAwEAAaOCAsMwggK/MBIGA1UdEwEB/wQIMAYBAf8C AQAwDgYDVR0PAQH/BAQDAgGGMH0GCCsGAQUFBwEBBHEwbzAkBggrBgEFBQcwAYYY aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEcGCCsGAQUFBzAChjtodHRwOi8vY2Fj ZXJ0cy5kaWdpY2VydC5jb20vYWlhQUFNQ0RpcmVjdEludGVybWVkaWF0ZUNBLnA3 YzCBgwYDVR0fBHwwejA7oDmgN4Y1aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0Rp Z2lDZXJ0RmVkZXJhdGVkVHJ1c3RDQS5jcmwwO6A5oDeGNWh0dHA6Ly9jcmwzLmRp Z2ljZXJ0LmNvbS9EaWdpQ2VydEZlZGVyYXRlZFRydXN0Q0EuY3JsMIIBUgYDVR0g BIIBSTCCAUUwOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3 dy5kaWdpY2VydC5jb20vQ1BTMAwGCmCGSAGG/WwEAQEwDAYKYIZIAYb9bAQBAjAL BglghkgBhv1sBAIwDAYKYIZIAYb9bAQDAjAMBgpghkgBhv1sBAQCMA4GDGCGSAGG +VsDiiEAATAMBgorBgEEAYLBWwABMAwGCisGAQQBgsFbAQEwDAYKKwYBBAGCwVsB AjAMBgorBgEEAYLBWwEDMAwGCisGAQQBgsFbAQQwDAYKKwYBBAGCwVsCATAMBgor BgEEAYLBWwICMAwGCisGAQQBgsFbAgMwDAYKKwYBBAGCwVsCBDAMBgorBgEEAYLB WwMBMAwGCisGAQQBgsFbAwIwDAYKKwYBBAGCwVsDAzAMBgorBgEEAYLBWwMEMB0G A1UdDgQWBBRLMi6n/ZVnJtWc2K4lDAwEKE1xrTAfBgNVHSMEGDAWgBRGCDhaqY4g uwyvXjG6ibMov6yMNjANBgkqhkiG9w0BAQsFAAOCAQEAlaoM5Wie2apx2JGQbbK6 TGzGoRJZdMEDdlgOkh+kmPUNjil25kjOoo61RLmCi37OgPuNcoeTmxCO9RSRQBoQ KRFREhAcyfXMl7ZFjPLTQ1XqUBSp3P6CCwHIIhqIsS6WCmgbEdy6Feab5YDs4ydR uBerQmVebmukeC659zsV4b4J5T6jD8L2q/f8iEO9OMm8Do50RI05EAZ2ImRaAc7J 8bjZaQC6wscxiVR1twIlHBn2EFlW+lBc2K7pXhBwZOHXKArGPuAA9VN1jCPAjhnB Fsi9ossVjOUnoPOXPf1TZHkMXJIyXJ+M+Jq543NxcDsubtkVb8LvMxZ+rxd/88B+ Uw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEdzCCA1+gAwIBAgIPIAYFFnADEO88nsbcTPkNMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xNTA2MTAxMzMzNTNaFw0yNTA2MTAxMzMzNTNaMGIxCzAJ BgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEfMB0GA1UECxMWY2VydFNJR04g Q0EgQ2xhc3MgMiBHMjEfMB0GA1UEAxMWY2VydFNJR04gQ0EgQ2xhc3MgMiBHMjCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOLCbShzd+XMXNZfT5ydhBz8 YfRgPE2Dnd0tQ2VmiFIcZmAwZXY8WRdHoYbgZ+lYzlb06vSQWdXW6Q8rhAz6xY1T ONAln1vozA/DLGjMSt81uVVpo8Y/uj+vg7atmKm/wA9bCbmFw4ZqNha83VsZNlDh sAPlbjURW3XfPMNTaKVgkMR2RkN1bnFry0Si8hj8X4s0wx+nCve421qWg3weeLeJ PwO140kb8m6vEKjkkGYtl00Memw3461f1twjIBBVyMvnSkbQq6w4msK0CUf+2Jy1 8rScT4HJH7v6Zg0Et5QTzjceyyisAMu1HvUiXiBJzXrNBbEUecdRdjjQWi/+RcsC AwEAAaOCAU8wggFLMGgGCCsGAQUFBwEBBFwwWjAjBggrBgEFBQcwAYYXaHR0cDov L29jc3AuY2VydHNpZ24ucm8wMwYIKwYBBQUHMAKGJ2h0dHA6Ly93d3cuY2VydHNp Z24ucm8vY2VydGNybC9yb290LmNydDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud DwEB/wQEAwIBhjAfBgNVHSMEGDAWgBTgjJvbJUmz8XyG1rJChwvQa6DZ5DAdBgNV HQ4EFgQURURbBiGqKAiGKa4Jz51Cf1JCexkwSQYDVR0gBEIwQDA+BgsrBgEEAYHD OQEBAjAvMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnRzaWduLnJvL3JlcG9z aXRvcnkwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2NybC5jZXJ0c2lnbi5yby9y b290LmNybDANBgkqhkiG9w0BAQsFAAOCAQEAqf73ZzINq9uEZb47X22nGI3JumQM MZUqmxaNPvCfUBSDwiviZywwFk6gF8BEARUKcekYoQ4u5Jya3xL4ucAhBOZnWRNI CvR8alte5sWEh5mnATep/ygl91qOZUlECLaombvWXL0K/Aq9NDOJ8ruU988PjqEY 6oEps8aATtX3HivuQyfbOIwJeSQuXJxVe9orEmAhASnNe10QjN1QGL2NjAN6/uog ZIGnb20ubapsIoSDxihBAEn94xSKmsLJDUWHtXc9JEVCQ0IUPKnDpXyimELu6CQl vtLJsMRGEAJet7mbvobBNqNcinURml5/AogW958bDPfmP7us7bgYxQvxjQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEizCCA3OgAwIBAgIPIAYFFnADEVSazYKcRyS3MA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xNTA2MTAxMzQ1MDdaFw0yNTA2MTAxMzQ1MDdaMHYxCzAJ BgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEpMCcGA1UECxMgY2VydFNJR04g UXVhbGlmaWVkIENBIENsYXNzIDMgRzIxKTAnBgNVBAMTIGNlcnRTSUdOIFF1YWxp ZmllZCBDQSBDbGFzcyAzIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAwvDg3+dNAm3aON+edf/2+mNhSHBAskfPoIn+6qeYO5S5D5xGXgnSzwwNszBl v0wbb5SEFQ3Ndv0FFf10b7EGTwXbpUPnni0s4eJ9neDY+c8IysxhESSnp9mIzkq3 T9gktKLU3pZpxxHzre5bO49fjsBV7pebUpVJPRz3k6cso0ZqrhgWavCR+WdeQqte 13IeVtKHcheIr3RL1mdki2uU30LSabELAn37ToQFGhBBBccfQ5QDs4tXIfBGHhKa 8aNoKn0yHG010ss+nYZixuSDcXDzVxwGQeGPecAm+1kLoUVKcUcPn6R9U7bE7ldW 5rqfeqp76mUToF9Fz9HyukHnxwIDAQABo4IBTzCCAUswaAYIKwYBBQUHAQEEXDBa MCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5jZXJ0c2lnbi5ybzAzBggrBgEFBQcw AoYnaHR0cDovL3d3dy5jZXJ0c2lnbi5yby9jZXJ0Y3JsL3Jvb3QuY3J0MBIGA1Ud EwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFOCMm9sl SbPxfIbWskKHC9BroNnkMB0GA1UdDgQWBBRQNJ5Tdrlt0rcMHpCDdVruy3QYijBJ BgNVHSAEQjBAMD4GCysGAQQBgcM5AQEDMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93 d3cuY2VydHNpZ24ucm8vcmVwb3NpdG9yeTAwBgNVHR8EKTAnMCWgI6Ahhh9odHRw Oi8vY3JsLmNlcnRzaWduLnJvL3Jvb3QuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAG 1HhtiaZUmm1jERljbfTEr74U6BblpQA44Mg/XVs8OXt/xBcpu1uVb887MRgi+8V7 +Ja8BSaEwFGBadKk7/61e4JBOfOYn6L5uhBwDCa8zuwWazoUfL5gwQSi3IjTcDoj 0D97mb4p+qEDTzNy9UpfsrAxzcWdqmKTyQ9nku22qO09ZlCE+OXFOKN+NhKv3Ecd CozxdDVBCOP7j4JiUzTJGbrs4NPBK4s969VqWrRG58qUnsU8qvKb+Ce3MOMtVCdQ GLfDgVEKCP14V2VqBA3aSnpwGAhwVUvoi1v8QYg6chNkytH7NQAt/9YoyXF1v8oG H/3oT4zo5p5Ncb+TE2Tm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEmDCCA4CgAwIBAgIPIAYFFnADEkP3bl2oXqzzMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xNTA2MTAxMzU0NDJaFw0yNTA2MTAxMzU0NDJaMIGCMQsw CQYDVQQGEwJSTzERMA8GA1UEChMIY2VydFNJR04xLzAtBgNVBAsTJmNlcnRTSUdO IE5vbi1SZXB1ZGlhdGlvbiBDQSBDbGFzcyA0IEcyMS8wLQYDVQQDEyZjZXJ0U0lH TiBOb24tUmVwdWRpYXRpb24gQ0EgQ2xhc3MgNCBHMjCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAL2MtzscYFdc+pReRBwdrw2BkEjasFEOBFsPUTV5ELhi 0fCi063qHS182aw9xF7cbyBYWoPZnzXD6CKDXl/Evd0RwF3HSXwqKfE4sAhOEglw tO6YpnXuoRUaPeJ1wz0HJQoxWWZXvy09y8LzxzqfVe2y/dlytZxGvTxc8N/XBUVZ xc96ey2+URlG0ZFzqK6OIZSEPlyi1ZnILTH17xA3DY0l7cbCaqjz0DvTIWOxLZvm VL2coSyZjLskHHVQQWqM8A47HtVGVpE2nba/m13NEth51wu6fLsvOaU0SKo0voEy RWPPwKXsZHQpPUXhS/YzFUYHKSBqSzCzHwJ3Kp815gsCAwEAAaOCAU8wggFLMGgG CCsGAQUFBwEBBFwwWjAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuY2VydHNpZ24u cm8wMwYIKwYBBQUHMAKGJ2h0dHA6Ly93d3cuY2VydHNpZ24ucm8vY2VydGNybC9y b290LmNydDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAfBgNV HSMEGDAWgBTgjJvbJUmz8XyG1rJChwvQa6DZ5DAdBgNVHQ4EFgQUP8E0mzn2Zd6G MX2rNegZc5Xe8FUwSQYDVR0gBEIwQDA+BgsrBgEEAYHDOQEBBDAvMC0GCCsGAQUF BwIBFiFodHRwOi8vd3d3LmNlcnRzaWduLnJvL3JlcG9zaXRvcnkwMAYDVR0fBCkw JzAloCOgIYYfaHR0cDovL2NybC5jZXJ0c2lnbi5yby9yb290LmNybDANBgkqhkiG 9w0BAQsFAAOCAQEAsedon8cBLcUaYMgy/tvwCGM54zvNSZ4U7IQ699Do3sbMx5MJ hBA72eUp4qEAFhUMHJ6NcydHbvCnAJjmYtyVM0RSzyzspRavsO+Rj9GDqBN8DEDZ qjUKvSnXAeJNCeFQaeOmWkcGlmIZXwKRl+4Q2MgoZTKVBmKpASreKrooXCS5709c 1CxWAeIdQaRHVok19odFKAtX5iInfCk2/eXqstDGSTFVx8otnRnDf6C9MTA8hMnL 10KXCYaS3UKky3RWW8tWEy9FZq03lSxuLoskkhG3MBZKW07Cm4zRoTa1+cbuSbgR lbr7/mlaYcMYumcIsujI2xR2oG1cZ8TVj2M34g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEzDCCA7SgAwIBAgIQESfqNkHGNiMyR3PVI3KyAjANBgkqhkiG9w0BAQsFADCB mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eSAtIEczMB4XDTE1MDYzMDAwMDAwMFoXDTI1MDYyOTIzNTk1OVowbTELMAkG A1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHTAbBgNVBAsTFERvbWFp biBWYWxpZGF0ZWQgU1NMMScwJQYDVQQDEx5HZW9UcnVzdCBEViBTU0wgU0hBMjU2 IENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgTVrNM/J+ l+4Zqt5NlG6Efx4gkAuJRoaEjtok529PhvKJLCzRDyaNsFpil75UTOSJT1dNyP0R Im+5rHQlcIS6fMnY0S+5UkcsdmGePhn4kte2krcE5JcrC4XmKzRcJao64Rac/0/j SG7KXJ58I81xmuuRp6dUnslaSVue+7945PApEDJUP/sa3ptrmR3RyNj0Sf2oBBUg pUJoMmrTpMuPCMRJiNJn+GDzpbHuYHNIrzC6NFa7CJ4X2CguwPrxxcRJ4dJLcOI+ Xt6NYbe2pZVUUchBPGZHPKc/3zdqVlD/FOo0DmttXVm66TSQeMi0hO+Ci0SOKDYe 3uvXzUsbIAaRAgMBAAGjggE6MIIBNjAuBggrBgEFBQcBAQQiMCAwHgYIKwYBBQUH MAGGEmh0dHA6Ly9nLnN5bWNkLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMEkGA1Ud IARCMEAwPgYGZ4EMAQIBMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdlb3Ry dXN0LmNvbS9yZXNvdXJjZXMvY3BzMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9n LnN5bWNiLmNvbS9HZW9UcnVzdFBDQS1HMy5jcmwwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUi8P6vNmoQx6R /AhPms00y5/f/6QwHwYDVR0jBBgwFoAUxHnKjqFOAx0c3GvbMVuUPj8wfy0wDQYJ KoZIhvcNAQELBQADggEBAKeIPWCRYfis6Fftk0dRGWoGXzF1iHP56MOGo07fLyx3 AUvoRTA7PsbL7sK0dk84Ndnpaa6yRTGtnnQK8rGQKBUUxWzEDwXAIKf7yAZF1cn7 oC29FOCBxa7XOZXzJ+2fr2HjBA+peFz64oPbT3RUafmhoGCou5bNvn7y6QtHXhFD IMx19r04VQXOqoVAtnu2iMSvC++S4uyZheLYxJm1g5RuF6gPOvSVN3JSeHbehReD Y4RrQgiHBalOYId+givm/pZz/y+lwInFv8QhNhcgiiJbGZl+NVzLNPrQdWMTRlwY onzbk+QKGwubmz9BInp1oFYCdY4/SSeEMg/uW+tDsTY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpjCCA46gAwIBAgIQKByJKWYUQ4BCY1U6MkCuszANBgkqhkiG9w0BAQsFADCB mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eSAtIEczMB4XDTE1MDYzMDAwMDAwMFoXDTI1MDYyOTIzNTk1OVowRzELMAkG A1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlk U1NMIFNIQTI1NiBDQSAtIEc0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAwJ46D5qyutPS3BXs0DBUWTBNQFGuQnFx0o1Tc4H+uODElsWOfsLxt2NKz6ce P6jnzlOg+i331ubOcBGm7uEDUtJo3j0IDYf9HNcLl2JtgjB2G0c6xPfO7R18jLcX jlOAHh0PXYz5kOQEHgJ+y7BJ79pSJfv7Z+3dhHRZhA7z3nBmjeRSOPdTWjcTZws+ u6hYty7t/7deEXO5d0VSZ0auxNwkgYl2CsqhbGZzBIKq9XBsXxuaAHlG1n96Jhcw zzlLLHTZiUR2ENDt94u7iQV1TQsNs9rpv/FqfSoR2x6fjOPEBmnhHYhFOdFuVdiq t5tv6vTerBcRkl1Am4N7muL3qQIDAQABo4IBOjCCATYwLgYIKwYBBQUHAQEEIjAg MB4GCCsGAQUFBzABhhJodHRwOi8vZy5zeW1jZC5jb20wEgYDVR0TAQH/BAgwBgEB /wIBADBJBgNVHSAEQjBAMD4GBmeBDAECATA0MDIGCCsGAQUFBwIBFiZodHRwczov L3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2VzL2NwczA2BgNVHR8ELzAtMCugKaAn hiVodHRwOi8vZy5zeW1jYi5jb20vR2VvVHJ1c3RQQ0EtRzMuY3JsMB0GA1UdJQQW MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE FPO1VgzECbC0zx+q+d0jVvB36KH5MB8GA1UdIwQYMBaAFMR5yo6hTgMdHNxr2zFb lD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQDDftiDSwRMVSkqTxSdmm7ekHDBpCZM iI54SO+9nLCg9fBm/P5ZJuF578i3YGSoi0fqL+CDmdpBGdfFvgX68pAR8Ar/bNwF tNgGb6Rvjb4gK1Tb+aJFg5oepSGJNR18IFwX/QQuRdiyxvhCmfxUCE5LgF85N7qV TqY3Cp6TXodb6ZDWqLZlCI1hSeuDIKldGxZgYmsvVPtaAg16J+JL4QUUwuTp+XDA 2fc0ZQ6ikUusKPK3CA+Yytc+cLbIC/GLnFH4xhBs0lNPYowRAD6I37/m0sxwve0l nPvdJAq9WZFKQgM4EnEyiHagjny7Mu+IKhvUam9QuVJni6sw+h/94ySa -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG3DCCBMSgAwIBAgIQYcLU1PaprndVkma5ja/WITANBgkqhkiG9w0BAQsFADA7 MQswCQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xGTAXBgNVBAsMEEFDIFJB SVogRk5NVC1SQ00wHhcNMTUwNjMwMDk1MTUzWhcNMjkxMjMxMTA1MTUzWjBNMQsw CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNFUkVTMRsw GQYDVQQDDBJBQyBSZXByZXNlbnRhY2nDs24wggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDCO7E+oUYbuTJaWkEQtIFgcRHD/kHavy+XBFdfCdUzDh9w7Yq4 kYckBPW/YU1QRa4v35HbajEMCs4cyLnoJy8Wyzq7qrSwmNHhMYDjtGywJXbCo5SZ VbIwyagWig8Nb/x9Y5WGWIY76E9agPAoEYOxOG8h1J6ipNoBbq0R+4N4ODaq57AB Y7mUSXb4WgjoVg4WxxZw0GGLuc8R1idoX1G/VqxvNymeCZ7o1bEwbs7X3NhRsK21 w3ju8pkUNZXN6Pkflh9qIslOLiokKbiDwwAZE4nvU//B8Q8FLYk1sgTQTLET2EQZ 308FlECRp3i6Ay4iezc0Yd3FKIDmOxCdDUcDAgMBAAGjggLIMIICxDASBgNVHRMB Af8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU3FCWn9cxickR 5O+WX/ZfglJGYlMwgZgGCCsGAQUFBwEBBIGLMIGIMEkGCCsGAQUFBzABhj1odHRw Oi8vb2NzcGZubXRyY21jYS5jZXJ0LmZubXQuZXMvb2NzcGZubXRyY21jYS9PY3Nw UmVzcG9uZGVyMDsGCCsGAQUFBzAChi9odHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9j ZXJ0cy9BQ1JBSVpGTk1UUkNNLmNydDAfBgNVHSMEGDAWgBT3fcX9xOiaG3dkp/Ud oMy/h2CabTCB6wYDVR0gBIHjMIHgMIHdBgRVHSAAMIHUMCkGCCsGAQUFBwIBFh1o dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzCBpgYIKwYBBQUHAgIwgZkMgZZT dWpldG8gYSBsYXMgY29uZGljaW9uZXMgZGUgdXNvIGV4cHVlc3RhcyBlbiBsYSBE ZWNsYXJhY2nDs24gZGUgUHLDoWN0aWNhcyBkZSBDZXJ0aWZpY2FjacOzbiBkZSBs YSBGTk1ULVJDTSAoIEMvIEpvcmdlIEp1YW4sIDEwNi0yODAwOS1NYWRyaWQtRXNw YcOxYSkwgdQGA1UdHwSBzDCByTCBxqCBw6CBwIaBkGxkYXA6Ly9sZGFwZm5tdC5j ZXJ0LmZubXQuZXMvQ049Q1JMLE9VPUFDJTIwUkFJWiUyMEZOTVQtUkNNLE89Rk5N VC1SQ00sQz1FUz9hdXRob3JpdHlSZXZvY2F0aW9uTGlzdDtiaW5hcnk/YmFzZT9v YmplY3RjbGFzcz1jUkxEaXN0cmlidXRpb25Qb2ludIYraHR0cDovL3d3dy5jZXJ0 LmZubXQuZXMvY3Jscy9BUkxGTk1UUkNNLmNybDANBgkqhkiG9w0BAQsFAAOCAgEA pS/HpvFq3S42VmjXtoNVxdh+m1/NdjoWVY6M2o9c+UZofrZWbaiQ+aNOn6/+Qf/L Zk41jD+nEa/O1GkPyAineYtjyW6Ae7ltVPIVIWQa3fALcgyN7s/U31qPooU7Zv7a 5mghpxapWHvtL9yxpLjrtGsZD32qysIJ2pjDqJa5WeWVKF2RS1zy6Bm/9JzlxzTC H03kivP5ltp+cHik/KzJZ+HgPv6BLwO+OYrJ19vGbPuDGgOj7uJTG3XQIlZchTlt gCmNRPKs/HOGOyDmWxm07FmrADQ1NWag3gjoH8xcfAlp9aBnm/UXFJuAkGOq8ASr +A5dpJeDP/rlKphDdxJpG5YKRwRSb7PnAccstmGxynL+K/0ofxAhbWqC6z7KeGyZ BTeVIilPhp+xZzJnvFVBjN6s2j7W3+esQkiT4SdY9RN+c3tBuWF54UNc7YVe6KVT jzkpev9szp6vUNQ+A45i2KGXRLN6/16nA9fujzITRWmX4tOGABo0aL/wBrf3Po89 gvZwZRaVQ9Bw/KfEF8eZDhA1MgQKSPJLSXSl58elHGFLUR2CQMGl+mgfPB0qZUUk RG/RYpZLocczAz6pfkxA3Mt3DfIyVtA/YJ0O4ZYpdbH9zdJZI1RQEWmFrMOrEAWm GIG0SmNpARqOPJsTQJomUcvd3EvA7so2LzLJ+Sjj2So= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEjTCCA3WgAwIBAgIORsdODEh3IULjetdRFS8wDQYJKoZIhvcNAQELBQAwVzEL MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsT B1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNTA3MDkw MDAwMDBaFw0yNTA3MDkwMDAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBH bG9iYWxTaWduIG52LXNhMS0wKwYDVQQDEyRHbG9iYWxTaWduIENsb3VkU1NMIENB IC0gU0hBMjU2IC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCj wHXhMpjl2a6EfI3oI19GlVtMoiVw15AEhYDJtfSKZU2Sy6XEQqC2eSUx7fGFIM0T UT1nrJdNaJszhlyzey2q33egYdH1PPua/NPVlMrJHoAbkJDIrI32YBecMbjFYaLi blclCG8kmZnPlL/Hi2uwH8oU+hibbBB8mSvaSmPlsk7C/T4QC0j0dwsv8JZLOu69 Nd6FjdoTDs4BxHHT03fFCKZgOSWnJ2lcg9FvdnjuxURbRb0pO+LGCQ+ivivc41za Wm+O58kHa36hwFOVgongeFxyqGy+Z2ur5zPZh/L4XCf09io7h+/awkfav6zrJ2R7 TFPrNOEvmyBNVBJrfSi9AgMBAAGjggFVMIIBUTAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0OBBYEFKkrh+HOJEc7G7/PhTcCVZ0NlFjmMB8GA1UdIwQYMBaAFGB7ZhpF DZfKiVAvfQTNNKj//P1LMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEFBQcwAYYhaHR0 cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIxMDMGA1UdHwQsMCowKKAmoCSG Imh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC5jcmwwWAYDVR0gBFEwTzAN BgkrBgEEAaAyARQwADA+BgZngQwBAgIwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93 d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEB AFKs5a+Ip4BlvENQ6LeK7b20Y3QyVEvopj8DPN6g/qEQBbQLcsK+MoELOV1C2sEW 9e1Dzx2QE41Lpy/njl981Uo+t+I4PtjLJ2HfMXndu1n7dHjUzpFfZZTMXY63lIp0 7Bq3C9wM2Skr2bhTgWDdQIIFGfR4XM/GZW8AFL6leE0v0B2LDQYRbVoBJwEYI403 p+6Vq1L6jKEpctjwZWAllFvaJPNBwC3m4fDtEOV1zSBXvAzzLnR/6dcqU8Gv09mm 9+xq8dFOAhDXK8Z+LvxJBs2oQ+YPmdh4n7LE2xreHjd+BiZ4f4ligqhv4rEccVTS k9PO2ofNurNPMjJ4NcNnPb8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGAzCCA+ugAwIBAgIQcIhUNIlA7DKW9cdlJelVRDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUw NzE3MDAwMDAwWhcNMjUwNzE2MjM1OTU5WjCBgjELMAkGA1UEBhMCVVMxCzAJBgNV BAgTAkNPMQ8wDQYDVQQHEwZEZW52ZXIxGDAWBgNVBAoTD0JsYWNrQ2VydCwgSW5j LjE7MDkGA1UEAxMyQmxhY2tDZXJ0LCBJbmMuIFJTQSBDbGllbnQgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCY RCwJsBjVUn0hhlywkan0YTZHCG4UGEPYAmWeckD4l3yUeR9RQA3t81aOKqI6uWDC 0LcbRVHRikMEjdYLTS1H1esCLORWgLA1in8U3p9w46Hu48Dwmvrqqw/+pPwYREYy 4+K+giT3mJZ4yqVu4/Jj/1uuc9cLuHU52EbFdavZwCGiN1j8g2dbnRNx0QE8aU4g IE5BDCG1XobodGHmL6dKfbIKJaiiAITNyNQxKY/O5bQ+T5ACuImLbnQ1CuEsmYmm aWN6GeKDQ7nCXqxc/dD5O4X6Od94icKVcUd24KuhEfoA7yiim+rEh+Va3BZq37Nt 4Wyvlhou7rcOY0clA3+/AgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRTeb9aqitK z1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQU3wYPY/tUXkbNRf7jjLtERgp0WUMwDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwIGCCsGAQUFBwMEMBgGA1UdIAQRMA8wDQYLKwYBBAGyMQECAjUwUAYDVR0f BEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT QUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/Bggr BgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFk ZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3Qu Y29tMA0GCSqGSIb3DQEBDAUAA4ICAQBuTsgQ6Rhs9rW/Ax7LeBxVHz7aYkqoPv7A U1VR2vs6dnAZva/EuruLmWr/6E1AdyD0jkZeVLgD5Xe2HDbTpXX1oLvMWlxMpgW7 0pZd8kLhzSvcx5y7na1Qfie5gDzVWG3xCkTSiCc2mtMrIKDF0MTq29tfutDH3bCH +VaMR43+WCbcqOnOzzoObP/HSXtSJ4B77bSh9Al19UaXv/vEOJKgJGZNgypJEQFV 2p6YIFyzyrlMc8rxWdtEYZzDvMxmtfBsO84noEcWYNrIfDiE1fcqpYRvZy/B1/Nq Z4XN0ezr6TfKysk96N46Jf9iFsorG7Rgo+ZxAA7aiN3GwWLxghvKYsEpd3IVomBv +EfUUGXhG8D6JKMPMfAK1lDu+873k7bthgGm4/k4hsL//7ZTxqQwrOzgJx+pQLvx iHGGhvciDDSP7qMMEvPihHGZ3+TKOIKsKGD3F5gVMwq2oSMjrrXleMVY23EDgsxA RDsHl9MkX4yiQve/1COLiKxKfy7aQnY67HjmpY7MOILcE8XZVtZ9fY69bVAEp5wc FLL1ASrKLCgLa8tKcwZuv9cyBdIYZfIXj3d3dtcJyI6ibK9f1ijYeW4TH0LSI59R sCGk8SHOAyypyYevmx98LUPQfUicLc2L8/ZdNe6aLrFTlyaDCSAI6R9vxk+T3Q9L VVZN9Y3+Qw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFqDCCA5CgAwIBAgIQTWEN67iDALBpE6dVpBtLRDANBgkqhkiG9w0BAQwFADBu MQswCQYDVQQGEwJOTDEWMBQGA1UECBMNTm9vcmQtSG9sbGFuZDEWMBQGA1UEBxMN SGVlcmh1Z293YWFyZDEVMBMGA1UEChMMRW5zdXJlZCBCLlYuMRgwFgYDVQQDEw9F bnN1cmVkIFJvb3QgQ0EwHhcNMTUwNzIzMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjBu MQswCQYDVQQGEwJOTDEWMBQGA1UECBMNTm9vcmQtSG9sbGFuZDEWMBQGA1UEBxMN SGVlcmh1Z293YWFyZDEVMBMGA1UEChMMRW5zdXJlZCBCLlYuMRgwFgYDVQQDEw9F bnN1cmVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCI 30D/tpNGe4BRbDR3GTKVPlKCEwrp8l9AT59ZjF33CaKxKJAlxNnZvw0YzrNdeI0C vWpJW0z5eGsekROZBI+VEABdMIEwkM5877Mo0CCvCrNlQOg2B3XVBIC0pgcVscsq dpgtsOmTkes01/sxNU8rmP/Lixx6WRqyRVpcpbyG0QJEgmS18laFLD0ScXgZrN5x i3KJ2lxwbml3MH0fvKYaBRJE9DOvFBxy4IHIecm2ZGeHBdt8B7+CLXwRrvBCgZgi CV61arPyRInvgRTY4gTDPs94UeAL5+hRM4VyBZbZgpwQnz+nZjQ9do9eKJccs+jn D+IkBNJb1GeOxQtHPOMjb3U67unElM6oVC2DMe6EyvWHlqFWkAUl13tLsglg/4EZ Xrfg4kSSWBEGfH4kX6rpGvpFG9nFiOnGT1/qBfZqoscWRPxLFOW34UQjNBvexDeq PgEdHijdOzE1RiGpCGLN2zL3//BZ0OXvPGocCV+Kj78QqhzM7I8kzfDSaaRhrCQv B8pLDFxiiy/eUNUS5R42AuVIHYVUBOMsgAX9ex7lPMhGzkzI/s+P5muHVF93OUdS nNrZPpzfcgKT3RGcEJArCAGYsaxGd5f5l07TXIuv2EVWS+tD9+0eZfjEVOkodC7/ 56F8iigrN8lwVnoexUGTlSDKT2XXAm0U518gfafO/QIDAQABo0IwQDAdBgNVHQ4E FgQUiNSY6vpmUPiThd9gS5f+L6kw3VAwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB /wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBADceZHoy8e5bbwkRFr8XtCloGg40 k4mmsVAtIQ9RdWeUWdGx5zdocwxlM88Ve5btEX31hNCLVijXyPVt3G0453XVkZze /xxEi9+ZnmAIa4gVZDvlpJJ89e9L2hr5Lti4xJ3EocVJRYaM1bSSEdtgrKpLOLo2 aVJMbjQxcdurCAMfB5b8VrE3XucrtO5oprCu+ow8l2nssLiKgmG3QX/INjV6DpW9 Aa8ILVUeXrDJN2GmTIYgPXPC/Gx1OSPUMpj00pnzZBPxOhbIYQ0bmghUirXA0G2X BJpGFAmPH5wpa8gU9T5Qal8X0UrcFu1bhmtnxkWbo3ATy5jNktmlfbjlmwyxtnl0 jdnXtrwREdfRjdHbdI30X1XKk9Opaam8xkjkrXN8qlR61Gutwg4zdgAAmOZq24Bq r7tr0FPXBDpMvWNF5nd1PotaM3Lh6PaLwvPWTcUvIMFoFq0v7h3kULqIqi4gud8L xO9A5aKZZuv4mwl8JPSJj1KcF6Ptz6BjVOzCkJJodQTA1YTC6wyLVm0jiROvrNsg XtWb2ZTemYR78ymE3xd5rq/oDTLs+SXCItNZKGkZ6g6zf4D0XSwPDG55L5IHChX3 9RXnzeprzmkMF71xKEJxuEQhvAS3KbMbGHhQvVVagOQo4bHC69i6pPLN+ApX/zPP aHLMvBaQwsVTWox4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkjCCA3qgAwIBAgIQAZ7Bxr0/WXuyDDM45VHYdzANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNTA4MDQxMjAwMDBaFw0zMDA4MDQxMjAwMDBaMEsxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJTAjBgNVBAMTHERpZ2lDZXJ0IENsb3Vk IFNlcnZpY2VzIENBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDR rfaHFHlUJ1fHLwVoPJs8zWfsRRAshPKkR8TZU0JFCbvk/jPB17xGL9GL5re1Z3h8 anC+/bjltlTPTF6suCJ0c1UpCHPIZPfQlQkOeYNQv1/11MybQmGOgAS5QarOThKZ m6zWxb5bAnO1FqSrcWLUmOpAOYWm9rsv6OeHwov2nDLN7Pg+v4nndCOCS9rqv3Om JTz9v6nlaP/4MKJgxzsuo/PFfzs7/Q8xoXx0D9C/FMS9aPGl52un35sAfkYlTubo E/P2BsfUbwsnIEJdYbw/YNJ8lnLJfLCL//lIBVME+iKvt81RXW3dkHQD8DNP9MfA PlZGR69zIIvcej6j8l3/AgMBAAGjggFaMIIBVjASBgNVHRMBAf8ECDAGAQH/AgEA MA4GA1UdDwEB/wQEAwIBhjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0 dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTB7BgNVHR8EdDByMDegNaAzhjFodHRwOi8v Y3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMDegNaAz hjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0Eu Y3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3 dy5kaWdpY2VydC5jb20vQ1BTMB0GA1UdDgQWBBTdUdCiMXOpc66PtAF+XYxXy5/w 9zAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTANBgkqhkiG9w0BAQsF AAOCAQEACCnEyKb+tDgo96MZZ4zqBTsOS0BiYh48FMYF3DanTzJxRgVegB1ca/Bt bdkhdgu9RsS5ZpdN/4AUeodphLLW/8kWcL6jzIshre5cjSStwo+Z4MyeigkDuA+a tVuQKyr316UvSmWoxOTFx3GplkZPq21LKhbL8ak79h8hObTrrWAEgpsSv96r0kYd DA07dgL5C9XOU4VCeylNRtGLzWTsIRZPLwFDWNFl7Vyl+0Sg0lDo3mbEtjGehzMD sMnGSxLnWzWU2UbOMeu/uPaeC4SFgiJWxCOEVOdSMwwlyxrsRFUPY5Zys80ZXn4O J4XVpOqw4qXcBiklkOjOLOnp0Hzvzg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuDCCA6CgAwIBAgIJIrmw4dJJbVfEMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTUwODEy MDQ0ODI5WhcNMjUwODEyMDQ0ODI5WjCBjDELMAkGA1UEBhMCSlAxJTAjBgNVBAoT HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNFQ09NIFBh c3Nwb3J0IGZvciBNZW1iZXIgMi4wIFBVQjEqMCgGA1UEAxMhU0VDT00gUGFzc3Bv cnQgZm9yIE1lbWJlciBQVUIgQ0E1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA1wdiK3zK1kAesoeWXMKKbNwI+XUgENS5nLKgJJuLcwCp38AGQjikW1ab jHOl/JFk9qgHTBAjpJRwWJ6oGqVd+v2/0g9xRKNU0PlUoC4z6gh6nkmmYSdloKzt ViGy7y9Y3IRiprjhHKi39SK/SgHKloZv5Wg6cRv7XozDJGKtv+OJnN1PsmDMXkmN BQoD+wuIj/4hXdzZutebEUzHxxku4nJ3pPgE5d8ReMkCpTDCNC+eRTkYWdaMJMLh 5O3vcgttWWUPJqIvP5HGDkMqIBLJXSTq7zH5W4tp6TmqQEHUlDAM8DQE0+OSpdRT QpVu/jc0jg+5Vb1hFhWW9nbm0AOLcwIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFIk5 QWSR6UakFlkH8iuvUn99S9qSMB8GA1UdIwQYMBaAFAqFqXdlBZh8QIH4D5csOPEK 7DzPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC MEAwPqA8oDqGOGh0dHA6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJv b3QyL1NDUm9vdDJDUkwuY3JsMFIGA1UdIARLMEkwRwYKKoMIjJsbZIcFBDA5MDcG CCsGAQUFBwIBFitodHRwczovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0Mt Um9vdDIvMEAGCCsGAQUFBwEBBDQwMjAwBggrBgEFBQcwAYYkaHR0cDovL3Njcm9v dGNhMi5vY3NwLnNlY29tdHJ1c3QubmV0MA0GCSqGSIb3DQEBCwUAA4IBAQBeIizP GGZp+keyHfEcQZXL+wbKNOoUASTIJ+bMrI6WyXLqC48fVL/b9pVTXr3ntqxuZ0W+ JvcLFk+5wQKjKCaTR8nP8LPMcglWcJZuuqAfQ6d/Evbd09ZvZbJfVVwfOPMuEFya 53pcsLUKbiHjfZCQp26LWxE1KDSJ3rww5Eoa2uUEYoZcTTK/4JKWOaGtHRSD9l7x kYWpnned8c6fIJz1q10jmbymS7GhHB8k2Q/vTdNKhhlCdNi8bsrPz0NuNEcNbBqK i85pLszzo9na1fK3miQniu+ck8tF75g0ACp7wF8qrKCZrWRzHueOADfEU1+HPiEJ /PlWJYKd19uTpg84 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE+DCCA+CgAwIBAgIRAPb2HOSjY1uwyoqs7vyy0PAwDQYJKoZIhvcNAQELBQAw SjELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9u MRkwFwYDVQQDExBTZWN1cmUgR2xvYmFsIENBMB4XDTE1MDgxMjIwMTcyOVoXDTI1 MDgwOTIwMTcyOVowgbgxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJbGxpbm9pczEQ MA4GA1UEBxMHQ2hpY2FnbzEhMB8GA1UEChMYVHJ1c3R3YXZlIEhvbGRpbmdzLCBJ bmMuMUAwPgYDVQQDEzdUcnVzdHdhdmUgU2VjdXJlIEdsb2JhbCBFeHRlbmRlZCBW YWxpZGF0aW9uIENBLCBMZXZlbCAxMR8wHQYJKoZIhvcNAQkBFhBjYUB0cnVzdHdh dmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx6D45slgLGq8 2G/NPFnuFscv7UM1eRoQyx3h0DdSTfoRvHkkNv4Gf6OudZDOXqwV86v/SjcNEP87 njMOEqQ7dKQPtiYzEkK0MOrjbRySFC5dvCTI9T8tnBgFpYA9YXwbpUqXxEi0Ayoq hA7UQhS7Q+YGrVwZaJ6LiWrQw+x8ACPLqEvPmMZhrxagKwrsKbylMsAQ1ljk8X74 J76TSxi/AZpxos7tHD0XbO8elXFZexfsgPLDRpMs6jREVeQj1jVCWLtg9twiXzcI aUCchBsTSc92WGkKwBnH70dlL2N8kT/BNe3tAsXuBpZRILANY59jLrLnHEJNfado t6ZpougolQIDAQABo4IBaDCCAWQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E FgQUx33qXRmrVNT6P+ZKc956sjwdbC4wDgYDVR0PAQH/BAQDAgGGMD0GA1UdIAQ2 MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3NzbC50cnVzdHdhdmUu Y29tL0NBMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9jcmwudHJ1c3R3YXZlLmNv bS9TR0NBLmNybDBsBggrBgEFBQcBAQRgMF4wJQYIKwYBBQUHMAGGGWh0dHA6Ly9v Y3NwLnRydXN0d2F2ZS5jb20wNQYIKwYBBQUHMAKGKWh0dHA6Ly9zc2wudHJ1c3R3 YXZlLmNvbS9pc3N1ZXJzL1NHQ0EuY3J0MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr BgEFBQcDATAfBgNVHSMEGDAWgBSvRATCQX5Ig9tOOQLs7IR65s7JpDANBgkqhkiG 9w0BAQsFAAOCAQEAkn/4wKQRLo41fDRkZtfF+3o8JtUmfQXf2zoo9Ll29hhCiz8k BOpIek9MrFd/cdNgUw1nckIi+J3udyFrbO5p64JBvtc0K4kAOPFSKpHssFcnRLPx FXgGxXq6ohD4Py+xaEApslYFfMy89N6DKs/v/10/+/xD831RFEUMUoQxBimsmmNf +cLoMwF5bpoSz9JcWqCmSlK0Nla1dPphaoA/MObLN2iQPpeM3yF5dTUm1tPxe39W Olr6nLU1xO+yRDrlGLXrVDP1l1/qGVuwi+xufIAcdFycLLBjSSNX7LOIK3tbva7A WctLUs+qhIlUrbPyFERm7YOY4SttWdozeYFNfg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFMDCCBBigAwIBAgIRANPVGcKy61xwQPZMvJV7vSwwDQYJKoZIhvcNAQELBQAw gYIxCzAJBgNVBAYTAlVTMR4wHAYDVQQLExV3d3cueHJhbXBzZWN1cml0eS5jb20x JDAiBgNVBAoTG1hSYW1wIFNlY3VyaXR5IFNlcnZpY2VzIEluYzEtMCsGA1UEAxMk WFJhbXAgR2xvYmFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE1MDgxMjIw MTczMVoXDTI1MDgwOTIwMTczMVowgbcxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJ bGxpbm9pczEQMA4GA1UEBxMHQ2hpY2FnbzEhMB8GA1UEChMYVHJ1c3R3YXZlIEhv bGRpbmdzLCBJbmMuMT8wPQYDVQQDEzZUcnVzdHdhdmUgWFJhbXAgR2xvYmFsIEV4 dGVuZGVkIFZhbGlkYXRpb24gQ0EsIExldmVsIDExHzAdBgkqhkiG9w0BCQEWEGNh QHRydXN0d2F2ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9 AAbj9SknrNJT9pDatGvlR386KRi0SkqIOGr+C5W91+8E8PqydEHwjrnrWt/MTLGO +2kfEO3TEJlWxQQqbHy8SdhjCANefLzOT1cfTfjroWBIS9yiHpBIQytAaz/td95Y +JKrRBVCnIR/wB5qMMQ982RWwqggD763XLma0c1AIndsZL+dXp1zET4KBreoxn3q RYzMIsZIL2mAJoiCOTYuOGrOMVuaQn0HSu3K7bU+CpkdLQ/j+ikcQiI10IL9oOcO U9Gnt/hRyUX66Gk91RIpYXhla2tIYrg7ezrAnFoZIZCb891JjFtbSEOvAAK9F5d6 fkkjPx0432o/v1c5GRFPAgMBAAGjggFoMIIBZDASBgNVHRMBAf8ECDAGAQH/AgEA MB0GA1UdDgQWBBTFzrk7QkXAzQnlaOhIOoNdbI6rGDAOBgNVHQ8BAf8EBAMCAYYw PQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vc3NsLnRy dXN0d2F2ZS5jb20vQ0EwMgYDVR0fBCswKTAnoCWgI4YhaHR0cDovL2NybC50cnVz dHdhdmUuY29tL1hHQ0EuY3JsMGwGCCsGAQUFBwEBBGAwXjAlBggrBgEFBQcwAYYZ aHR0cDovL29jc3AudHJ1c3R3YXZlLmNvbTA1BggrBgEFBQcwAoYpaHR0cDovL3Nz bC50cnVzdHdhdmUuY29tL2lzc3VlcnMvWEdDQS5jcnQwHQYDVR0lBBYwFAYIKwYB BQUHAwIGCCsGAQUFBwMBMB8GA1UdIwQYMBaAFMZPoj0GY4QJnM5i5ASsjVy16bYb MA0GCSqGSIb3DQEBCwUAA4IBAQCA2N/WVTGYRGNTuvF2qKWPrQUx0/6pKmGqELl6 NXs1bwRXCci98SkeNjiaa2dHEwcGR43/M1Y0nekXP8QCEFVqGOwaY0pnTb8wL+CI /HTp1zfmoCYNvtzt1fIq/+9ynLYEjX8rsrf51HIEjJJK8K3k/Ub3cFT+yJKNN2YN JS0IvJYlbpqS6VbcInwLcW7WvJmXUuL7t0Vtt0d2q1h5UdnJQP+skiOmN/B0zPut bRC4v5pNGJJmwbk58UlOSeviH2qzDGutamOJ6dFNWqQFoZorAT7fUsr3WDA4HKtx eraYdCIRJX7weW9xpdMNsVO7Wy/Ma7Fz9fzKnOH5mnInBOof -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCBEigAwIBAgIQAsGuxj2AxcWkuCHrNM0t/zANBgkqhkiG9w0BAQsFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMTk5OSBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzMwHhcNMTUwODE4MDAwMDAwWhcNMjUwODE3MjM1OTU5WjBcMRYw FAYDVQQKEw1DZXJ0aVN1ciBTLkEuMR8wHQYDVQQLExZTeW1hbnRlYyBUcnVzdCBO ZXR3b3JrMSEwHwYDVQQDExhDZXJ0aVN1ciBDbGFzcyAyIENBIC0gRzMwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDe8BidNYO+DWekeA2MkRizK5f49n2O MGhNJmrs+UGA+rSb9uMj+kfneGoOQW1/D0MyGK2eJaf0FSWx9ToxKaj49ZD0aZF1 9IFmbV5OZONiCASPbDx530xUBwBXoizRXpKAtGxgjeW0Y9ELnFNyLwXNpUks5vgU Hk0ZYf2yJtDqEHh++KJKKBLgh1aZlSohgFxzFjqlj0etqOVkLV1/RwnaW/g5s0m7 hEvcBVDSmOjRpSrVtd5U7XeKxoUFx7m9zR3feDots37b0dXRH+PxTqqXn5tNYhHo MX0PX3jEtmVIHfx5XOToB251IKAfPHjMs9xtrG/QJY2wRRqeqpqQXxqhAgMBAAGj ggGtMIIBqTAPBgNVHRMBAf8EBTADAQH/MBgGA1UdIAQRMA8wDQYLYIZIAYb4RQEH FwIwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL3Muc3ltY2IuY29tL3BjYTItZzMu Y3JsMA4GA1UdDwEB/wQEAwIBBjApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRQWZm U0NDMi0yMDQ4LTEtNzEwHQYDVR0OBBYEFOYB4Us3dtaiDnbznXLMlvfLHajOMIHw BgNVHSMEgegwgeWhgdCkgc0wgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJp U2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgG A1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1 c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczghBhcMtJjF+YRSnnsKbZUFt6 MA0GCSqGSIb3DQEBCwUAA4IBAQBzd4BRctJGfaHTdauoZKGqna8jQeH0A2YPRWjW V/Rzhyw+KzDNfSA2g9BJOrx1EmoeefFlqSeFq10GZlDKUgTEH3CCio9oVIpGf0mO iQqcV9QSpqs7QHzGOwrW9r9xYQSps31vuiR13YSjochnEKomBREN0bC07OztErdu QR0oPN93ZWddCYFOem6M3mem9DZ5rTsCVwLJNAk2dbC9RFb2nCpg9P6G7S40I07Z wnPGZ/84eUkLM0bmrUCjDrj2Uw9dA42L4MgpjjkxB6Hci9um22B/TIPPajKTwoQB DHLPraSq9CD4iqPl0FzaI69uDLOqYyGI480QVf7zZl0xhr5K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEizCCA3OgAwIBAgIORvCM288sVGbvMwHdXzQwDQYJKoZIhvcNAQELBQAwVzEL MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsT B1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNTA4MTkw MDAwMDBaFw0yNTA4MTkwMDAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBH bG9iYWxTaWduIG52LXNhMS0wKwYDVQQDEyRHbG9iYWxTaWduIENsb3VkU1NMIENB IC0gU0hBMjU2IC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCj wHXhMpjl2a6EfI3oI19GlVtMoiVw15AEhYDJtfSKZU2Sy6XEQqC2eSUx7fGFIM0T UT1nrJdNaJszhlyzey2q33egYdH1PPua/NPVlMrJHoAbkJDIrI32YBecMbjFYaLi blclCG8kmZnPlL/Hi2uwH8oU+hibbBB8mSvaSmPlsk7C/T4QC0j0dwsv8JZLOu69 Nd6FjdoTDs4BxHHT03fFCKZgOSWnJ2lcg9FvdnjuxURbRb0pO+LGCQ+ivivc41za Wm+O58kHa36hwFOVgongeFxyqGy+Z2ur5zPZh/L4XCf09io7h+/awkfav6zrJ2R7 TFPrNOEvmyBNVBJrfSi9AgMBAAGjggFTMIIBTzAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0OBBYEFKkrh+HOJEc7G7/PhTcCVZ0NlFjmMB8GA1UdIwQYMBaAFGB7ZhpF DZfKiVAvfQTNNKj//P1LMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEFBQcwAYYhaHR0 cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIxMDMGA1UdHwQsMCowKKAmoCSG Imh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC5jcmwwVgYDVR0gBE8wTTAL BgkrBgEEAaAyARQwPgYGZ4EMAQICMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3 Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQCi HWmKCo7EFIMqKhJNOSeQTvCNrNKWYkc2XpLR+sWTtTcHZSnS9FNQa8n0/jT13bgd +vzcFKxWlCecQqoETbftWNmZ0knmIC/Tp3e4Koka76fPhi3WU+kLk5xOq9lF7qSE hf805A7Au6XOX5WJhXCqwV3szyvT2YPfA8qBpwIyt3dhECVO2XTz2XmCtSZwtFK8 jzPXiq4Z0PySrS+6PKBIWEde/SBWlSDBch2rZpmk1Xg3SBufskw3Z3r9QtLTVp7T HY7EDGiWtkdREPd76xUJZPX58GMWLT3fI0I6k2PMq69PVwbH/hRVYs4nERnh9ELt IjBrNRpKBYCkZd/My2/Q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGNTCCBR2gAwIBAgIQDhF/NeaFyDd8ln/gbIzQ2TANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBGZWRlcmF0ZWQgVHJ1 c3QgQ0EwHhcNMTUwODI1MTIwMDAwWhcNMjUwODI1MTIwMDAwWjB9MQswCQYDVQQG EwJVUzEiMCAGA1UEChMZUXVlc3QgRGlhZ25vc3RpY3MgQ2FyZTM2MDEhMB8GA1UE CxMYQ2FyZTM2MCBEaXJlY3QgTWVzc2FnaW5nMScwJQYDVQQDEx5DYXJlMzYwIERp cmVjdCBJbnRlcm1lZGlhdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDYtxBfW+5AsCKKqrpsObrlimrBWGpORJztpwwoHJTsxlLTLxWfAD0m6yHh XwlnqjGqjXXwR9LyV+ZjjxWh7hxfTv1WPMnDQDAkz1bDRq8Tt//CYiFfdeczxPGq a/uNZJXFihHC6IMzfClc3pQLCvAH4t2oMhp5+Supklbv5vlFZIMTXhHWEXd1++NX YR+/6plXOPBkCxxCFp0jPufPAMawgvY0CwXH3/W/lNc24LOJIhi58JQHjj3qu0re LM+lXQhpqmhJyOJxpwNfFNyUQie+m5xELL8IA4PtbovJi+QHRFwFdtyKC5sfMrFX 4b1nt3+0bh+1Zdz8E4Yv9fZVXy05AgMBAAGjggLHMIICwzASBgNVHRMBAf8ECDAG AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjCBgAYIKwYBBQUHAQEEdDByMCQGCCsGAQUF BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSgYIKwYBBQUHMAKGPmh0dHA6 Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9haWFDYXJlMzYwRGlyZWN0SW50ZXJtZWRp YXRlQ0EucDdjMIGDBgNVHR8EfDB6MDugOaA3hjVodHRwOi8vY3JsNC5kaWdpY2Vy dC5jb20vRGlnaUNlcnRGZWRlcmF0ZWRUcnVzdENBLmNybDA7oDmgN4Y1aHR0cDov L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0RmVkZXJhdGVkVHJ1c3RDQS5jcmww ggFSBgNVHSAEggFJMIIBRTA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0 dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDAYKYIZIAYb9bAQBATAMBgpghkgB hv1sBAECMAsGCWCGSAGG/WwEAjAMBgpghkgBhv1sBAMCMAwGCmCGSAGG/WwEBAIw DgYMYIZIAYb5WwOKIQABMAwGCisGAQQBgsFbAAEwDAYKKwYBBAGCwVsBATAMBgor BgEEAYLBWwECMAwGCisGAQQBgsFbAQMwDAYKKwYBBAGCwVsBBDAMBgorBgEEAYLB WwIBMAwGCisGAQQBgsFbAgIwDAYKKwYBBAGCwVsCAzAMBgorBgEEAYLBWwIEMAwG CisGAQQBgsFbAwEwDAYKKwYBBAGCwVsDAjAMBgorBgEEAYLBWwMDMAwGCisGAQQB gsFbAwQwHQYDVR0OBBYEFFaQGmv59EKaZKYHLxUk7owoDipjMB8GA1UdIwQYMBaA FEYIOFqpjiC7DK9eMbqJsyi/rIw2MA0GCSqGSIb3DQEBCwUAA4IBAQBpx8Sb6qgF Q68Zkgs1ZCH7rtPwkCctN3JyjFObh/HlBgHOUT/ypz7s8wGmngGkzUJtNbLHsPMr HBg26Og3GknkFpExhpLNFICHlaQwvofn2R9JFthwK/tXnJdWizOxbXMMbIXErJtC mCeoyjesFv4f0fvaYpnyQmgMGVTM8PV35YVuvFgxAUnXfLBMguVSGQ7G91uqhGDG 16dd4Ze7aLAmXDPfSS2rKB9dKePsvpb+q1/TwrVIO1TMXqNK1iiSpLVEY0D9aet9 2UvvdT1/JgXILu+O35aE9FEmNtJrYB24/o0qkEnpgF+klDWlCxOcbS1P6mdB4mkr H6BqsyQ0XO+M -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuDCCA6CgAwIBAgIQC9E5g/AsZUQf/kndVg5eLDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTUwODI1MTIwMDAwWhcNMjUwODI1MTIwMDAwWjBeMQswCQYDVQQG EwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFTATBgNV BAoTDEdvb2dsZSwgSW5jLjETMBEGA1UEAxMKR29vZ2xlIENBMTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALqWMezVPbG3lsUiEggEQRlDY/2CplKaBcZz PnBcFPfEJt01pPkJJG4Fje0nAagRyh6sB7ejmb5IQhG1dw+wtog5JzPK4iXUeOX/ Zg8x1IjtdgB8samqOeD60hryLpAQsVNATvFFfM4P2QxVKETy+uD5PcVpXfU4c5cL bOgYugpI2ehzORIhYoiHDkr8fLRiB3NP53AQY7KKf3HkSuuNeUXlyqchRxBKh+Nj +uF6xnQ2ElZYtI2YVA0KBwgo2cSKQGoC2DOaa8lb3VgRk7x+J9I9LszyDPK4gvl2 Mhyp6VvyYGq4FwAwULyEcETcBLr3701WuCSJT4QmMDKOKi84cb0CAwEAAaOCAWkw ggFlMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUF BwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMG CCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRB c3N1cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmw0 LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwPQYDVR0g BDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0 LmNvbS9DUFMwHQYDVR0OBBYEFBV/772J7ryuGhmJxSredhbMJsZuMB8GA1UdIwQY MBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQBFZSzB naSkqUajv9RZ2J8kfmzf3BOAZRjeJCBmcQhU14Spat+Q7bFHoTQZWF07VKPEBdj1 egZxdWF4Y/AAYrmX91N2F7AS+h9iI3gQdKVyJLDGxL09QPqaulVtt+ltXPU0KtQy B5czZGzvwKfmD/UCI/aen2VQnRy83weQzgDfxv+zVMb/75sUguaVxXiLaH73Fs7F qUK6uyhnkKFf+b5xZ0dvN3tYSDE7UH1KQHd1nf3iY1l7mz8oTQPRz0pXAF3KCilo cPgNuFf41ExruL+sX7fwWok2rlzrIzHxqnYYiMZnDw1abrGKDw15ohTG+cZCjpJf l4NzPnfo6QDWgin+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE3jCCA8agAwIBAgIQDot1JBtVD+9YhruupOzhwDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTUwODI1MTIwMDAwWhcNMjUwODI1MTIwMDAwWjCBgzELMAkGA1UE BhMCVVMxGjAYBgNVBAoTEUZyZXNlbml1cyBLYWJpIEFHMRswGQYDVQQLExJGcmVz ZW5pdXMgS2FiaSBVU0ExOzA5BgNVBAMTMkRhdGEgTWFuYWdlbWVudCBJbnRlcm1l ZGlhdGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAsTa9wSQ/MxPgpqAWbDCeyYohY8vHnyZ9e2kJQ92/AlPp3tM9 mWL4mvRUzju36KjQD3ROy4mSzmsaQB6uE40YBFTrWIamsPdzHWVcqgN6PX2vo7F6 /VULuVENy1sjvzrcN382M4bsfX6R/mFtl9obz27/t4cWI6OEefGRMx40hshEKOgO SPf7maZHiGrxYMQOpWDO8b5ykXK7bWn8bCb1HqPQBRCzUhcYoRmAA37q/EeduHRo qbST+Yd5xMQy8saer4tKECNOdRyXhclllXi0HrpW5+6gM8tDWRqlRiCEyQh3FlsR NfeonYJ/bCrI2POAKKASeDOnDVYmz/8i8tZ2QQIDAQABo4IBaTCCAWUwEgYDVR0T AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYweQYIKwYBBQUHAQEEbTBrMCQG CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKG N2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJv b3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQu Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUd IAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAd BgNVHQ4EFgQU19+Smg5KuLe5cAm9dmcyd1fJLx8wHwYDVR0jBBgwFoAUReuir/SS y4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAArt1LlZs57P3ANdV14L 7GtYIoTp+17Bny9bGetmAe6fAdRmz/bFc7klhouqCyO9lbHH9BlsPUUPbeiGlj8l VgZBSRb0BfrMUNMbHPpd3X2k6HHONv7UENrwpgQqu4p4dF+2Dt659B+52HLsWKSS MyGfOrnbd4ZoU7iWYg2UthBjNGmc5f+XycTgUi2i9Az0oSIX+nuwTEvvbdAVOitR ZltfawJoXfnXeJ2AhXho1b/fHFBfSSMurYH9dOXn/1mBghWe0jvBBlxbfOD1HvwZ Dw7OMg5JVKYKcgyCtrPkYjkDXtavY6AsOV0Are3cdWqcdrfTSaDTQ5nrYxtTx3AZ tWk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFtTCCA52gAwIBAgIQfgr3g+MTaN10FgQg4sbqcDANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTUwODI4MTYxNjE5WhcNMjUw ODI4MTYxNjE5WjBaMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MRAw DgYDVQQLEwdUcnVzdElEMSUwIwYDVQQDExxCb296IEFsbGVuIEhhbWlsdG9uIEJB IENBIDAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8XLrPqbKqC4Z 4F7FV3zZF5hB2UiVXjLqRT2u4bR5JZ2AliajNwjyQRc3/6McRgM68+W3ML78opun 5QXyv1c91Vxgova50IxIRE3Whc78EcbQ7PvXZVVq3LmCtA/RuG4D+NpAopl1wNql UG42zjsuqXO6T8NECBI7MnA8kCFhFPv/wRj/jloEtfXH02x6Tksqn2QYf8IXcpCK QFHnYpAucwnwaJimsjD3j9joFv2/Gg0aNO1Bia1gBQuU2ZT0uMBNu7ggb5ET+CZK hPft87ivigWczSeWII/RtlzKAHwQbZyjHAMBaYE+OdqujRmixDXOmo9ymmbKr5jw nqtvv3QsbQIDAQABo4IBhTCCAYEwgYkGCCsGAQUFBwEBBH0wezAwBggrBgEFBQcw AYYkaHR0cDovL2NvbW1lcmNpYWwub2NzcC5pZGVudHJ1c3QuY29tMEcGCCsGAQUF BzAChjtodHRwOi8vdmFsaWRhdGlvbi5pZGVudHJ1c3QuY29tL3Jvb3RzL2NvbW1l cmNpYWxyb290Y2ExLnA3YzAfBgNVHSMEGDAWgBTtRBnA0/AGi+6ke75C5yZUyI42 djASBgNVHRMBAf8ECDAGAQH/AgEAMEMGA1UdIAQ8MDowDAYKYIZIAYb5LwAGATAM BgpghkgBhvkvAAYCMA0GC2CGSAGG+S8ABgoCMA0GC2CGSAGG+S8ABgpkMEoGA1Ud HwRDMEEwP6A9oDuGOWh0dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVzdC5jb20vY3Js L2NvbW1lcmNpYWxyb290Y2ExLmNybDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYE FIw9VAnEgAqhSyeJsjnYHPPXyhWVMA0GCSqGSIb3DQEBCwUAA4ICAQBZV3e+iiSw mwvtypFv/zHoZpfDt+psnNIU8SivDTTgzVoZmRnhVrDN0ow9h0A68Up/SvLZYXMf lFepyvpkBmk0bzLedG671LwPSQn0F2FVlbg2dpCR7lkSL7aXfrpoeUAfJwe4GvU3 kF4yTApNxC/xHkRtMmlzb5J4A+unx7ov1xuDyWenZ6ZIRp4rogDvmOwrmb7IBxJb /aNvS11wjiGJBHmXrJTReNracU8A0XWZCeMxjins5tt8Yxf/zOC58GH43dTf+tED gN+TpoCNek4XMKL+PqJzfoxzRBkjk3CegHq66qVchDtEJ60UHOhLt2mv0Ky1ex8I 6ztPr5ePzmPEEWUM9iavVjKsva4EN4lIgCQ0MDJYbS1gb6mIDKlIiC1Z6Q3D0dBG p+P6zutWiNzzjmFjFt04pz/GZ9HOfBhRw1o8nxx9c9u8aG6OVyKjyStKOk/3Zpa7 ZVIoWvJQo2dBr50FuhY3DHQ7okm34ShAJK2xWCuT/QuaeyYW0CKo4nrXgfW5d0sB Iwavec/sg+dR1xUmeIxXaGcBd2b25TTzDdj1HKVs/LSFL5toakS8ALEPvmGMkX07 fbWBz9dG/IhO7duTZ6B1bSu6DX3U3SOf47HyUH4GW+gQtGgF931KNmoXz6YWNq3k pHO7W0CJqRlTvW0qosYXft2SZAIQLf86HQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF/jCCA+agAwIBAgIQZ1HpbrpcDjMNkiFvPDVxBDANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUwOTAx MDAwMDAwWhcNMjUwODMxMjM1OTU5WjCBiTELMAkGA1UEBhMCVVMxCzAJBgNVBAgT AkdBMREwDwYDVQQHEwhEdW53b29keTEkMCIGA1UEChMbU2l4IENvbnRpbmVudHMg SG90ZWxzLCBJbmMuMTQwMgYDVQQDEytJbnRlckNvbnRpbmVudGFsIEhvdGVscyBH cm91cCBSU0EgQ2xpZW50IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAg3cP5LUjYtfpRUPZkZl4k6E1uQ5MlpHHg3Wr+zjzfs2TBg78hOOsv3CasnBd 5YHT2a27nd/474NAWQo8lxWKwaIIhaswWLWNkQm7QhjKv0BUeAf5iwOs+t03Quaj aZ4lzN6jMT4Bt3mg23FtxSf2mpLoq2ewLuvF9sIaY80tzt0H5rRMLWrNdahw792z ZLGBUxm6bYDMEdS8vC/asXhjXR3TherhMoAGtaGObrQPfsq0G2dKrtDQQUp6+7S3 fDAvDvlKI9OaAgsaYa2zRdbWT0Oe6Zy9zShVlGMWZ+03GID+hC/DvsY02U2BmZmN 0qeoj9FwUA0Hk+mvpnlAFr8otQIDAQABo4IBYjCCAV4wHwYDVR0jBBgwFoAUu69+ Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFKm2lXUEATbSlI+M8+pDJMVnVEDL MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQG CCsGAQUFBwMCBggrBgEFBQcDBDAYBgNVHSAEETAPMA0GCysGAQQBsjEBAgI3MEwG A1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JT QUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA7Bggr BgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQWRkVHJ1 c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAN BgkqhkiG9w0BAQwFAAOCAgEAL2G/JPA/ZiwoZD3MAmfKFkv1H/qtxRn4AZkkVycD tyx3u/a+MdKMd7qDqRnvKEQpP+Z7XSzK6UNgl+SVwggd0USDWZnhEi9ZvzuTIFKT r6uV06+UqDFoc7iNLDo+RFBZxw7uwJLZqfOE7wIvGhUi6xi/3ipy29iEAOLY7YFi VavW3DHZdbS5Ywz+jFBj0wjS6rpk+wvfz6LH+YRbb+62Y2HI1FLk9QGCTge1b5I4 2Ljfro1tIzCaRukC2pPcv3ktEPtT9wbvGiZY3GOWbBsZpTRYyxUUeOLZSpXWQ9zB 4mnXUUBURAtTCWFZnWxme12/k8svYLu7Ja5+NppSJA5hTcigUodKTzNKprpZsKSx +VyKQsBae2U/ykiSUD2Npz4yTTWCG6PWm7qQW6kp6mKFAJxvBRCGmatfua3MX7lF kPLvJI5rVuo2kTT3UR4ku08w6A2/iXDLqoI/KgN8/JfsgDCSwYYdbGp0R0O9BdWp XRfudseoUrxb9Jd9MUpT8VD7wy0FscjKf3dMfNRpaRNYo8soSl14BYxcAABK3FB4 NMhyYIbW/F6QNMqTQHj8BqRiE1Z+aG43tJLMao8rSgzsu3p+ojp4VprUvDuQvYpN ZYSOrhu+7381SCtKe66wbbdKABIa570SvOqqwCfTHVWGSlvd1WFk1EE8GraXZy4S tvg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEWzCCA0OgAwIBAgIIdGzXjVnp0YAwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG EwJERTAeFw0xNTA5MDIwNzUzMzdaFw0yNTA4MzAwNzUzMzdaME4xMDAuBgNVBAMM J0F0b3MgVHJ1c3RlZFJvb3QgQ2xpZW50IElzc3VpbmcgQ0EgMjAxNTENMAsGA1UE CgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDJi30L3rFjK1bnqJ480EB/hCFXOFwXpagBJ+Y9ip4CfzXwoyAuXHfZkQYp MAR+cV50g1uYN6ansIczodOg103SOe2jnk+rrjSVnYNwxgN8Z3NGDveprOvgNu8a WDb2GxQWjVhNUYMWsnp4fJw7vPIExgB80ogp3s72R6rLCZfSMN5tL+JjTKqmhpli brBFdoSTh1M7GfXEqSSLZv1RgmcmgYeR7LSEPzzKcM/ardyQptLmR7JR7Vuy17O2 rEMBkQZWSiA4gx4nSygEkJabf03fsb1I6RlmSYnfOTxulD4+kgyVJF3+oJghzJ9j p7pL85KN6MY8fvaBs7cWc0d1ip1DAgMBAAGjggFNMIIBSTAdBgNVHQ4EFgQU2M1w 2wYiB/y5E2t5Oe893Vx11/wwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSn pQaxLKYJYO7Rl+lwrrw7GWzbITAYBgNVHSAEETAPMA0GCysGAQQBsC0FAQEBMIHL BgNVHR8EgcMwgcAwPqA8oDqGOGh0dHA6Ly9wa2ktY3JsLmF0b3MubmV0L2NybC9B dG9zX1RydXN0ZWRSb290X0NBXzIwMTEuY3JsMH6gfKB6hnhsZGFwOi8vcGtpLWxk YXAuYXRvcy5uZXQvY249QXRvcyUyMFRydXN0ZWRSb290JTIwMjAxMSxvdT1DQSxv dT1BdG9zJTIwVEMsbz1BdG9zLGRjPWF0b3MsZGM9bmV0P2NlcnRpZmljYXRlUmV2 b2NhdGlvbkxpc3QwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBr +Rf4GAApAH/Rn1UijJtisayl2UHV4TaVURQcNBWrR1hx8yY2xOE8DbxZ7cv96DC/ 5xrXVP8l7vWrM7bsyxHCieDyBt/d30KmiMgBCqLvli6qyST30Stvna154OxTb8e6 TjgwJ8t+q8QNesXdEQ61Zrp9zSJjfL9AsedQl86BxtBQxQJykT0wDqw689M94S1M uowDLCe4sWU+AetHFYSU+xRZKc6cFM+nEBrcUatW+6dWy6BkRYsGl+CCyF9E/ax2 ysb2Es6Vq/VYgk6zeKI4d56CYs2kG3UXLvILITKB97somRCdHHSQ7+MoQDIijcvl DCY/uf9P5D4Yrk5hLyh9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEhTCCA22gAwIBAgIORwexAPQYIkNOwFuMe38wDQYJKoZIhvcNAQELBQAwVzEL MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsT B1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNTA5MDQw MDAwMDBaFw0yNTA5MDQwMDAwMDBaMGAxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBH bG9iYWxTaWduIG52LXNhMTYwNAYDVQQDEy1HbG9iYWxTaWduIERvbWFpbiBWYWxp ZGF0aW9uIENBIC0gU0hBMjU2IC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDiUIz8j3FQnCTMQDJdH3nQlA180FEmDPeU2dbN4kjIbdTbc+foy1GA legvc46R/8tlh5yAIIpGoW368BeaUv9pY95mhXPOBzVp2IbqN4139fOtDlM1UqPo rLDi0SLaDrdF3bmdw0NU8cEYpROCXu5Er3fN7HDt2f5QBpF1ZHO+WgjNAuRZl7H+ +572vb5NKtxheC+C8DZR4MRtImvPjQrhCWamkmOV0F1A3nuW/wgm0WIKiCeZ9iob l1+kbn54y9jIioSZMNg43Qj7z5EbMVEjyhXBLP3IjKni+SWH7oLPK7XlqOxSGmkc Dz3h+mhGySsFvQ4Cph0pQIHKvQtDBbnzAgMBAAGjggFEMIIBQDAOBgNVHQ8BAf8E BAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI MAYBAf8CAQAwHQYDVR0OBBYEFD2AgnnFSIKjwxLu35kPVzVIntDLMB8GA1UdIwQY MBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEF BQcwAYYhaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIxMDMGA1UdHwQs MCowKKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC5jcmwwRwYD VR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2Jh bHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQAar9p9zzVq dFGRIMbEu0FYLpsML3Z78O81dJlpYv2bh6X1+q/62MiUHsNUef/Byf+o7P1KG/3Z vI6ZIr3B3aop7uUqb9gPG616tbQce3/I1ukYPHKQ4b0p9hOXP913kQi6YH+oMtfv IPjEcsSQ2dFbiKRlJCb/emPGngAH+9dNn6iADHco+EbJ5VfJX9tAzEU377mVpLhT z3aPBMnnDSgAp/I7b5YXo0bYM8fzdbG0aKL4Ilfpis8AzUiamco+f4NtwZlGYaim 2HPen8hyjP15cQ2Skv1k0PFzc7n5R0guScAySHneog5HvRsUY+tXbUSzmpnLLzHm 90QIeZiDU9Am -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEizCCA3OgAwIBAgIORwexAZoMV605s+F9qfkwDQYJKoZIhvcNAQELBQAwVzEL MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsT B1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNTA5MDQw MDAwMDBaFw0yNTA5MDQwMDAwMDBaMGYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBH bG9iYWxTaWduIG52LXNhMTwwOgYDVQQDEzNHbG9iYWxTaWduIE9yZ2FuaXphdGlv biBWYWxpZGF0aW9uIENBIC0gU0hBMjU2IC0gRzMwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDJhqIFPux3TXlCgfLFRqnCm/lXqUjdPDviFkeDFQw2iGGz yLnVIJe2/gcwAZ4BOvlQh6BPYMyQ9t0fpsdVAGxUMV8Cmvd/B5rSIlMFzZ/Hu3tZ O4qyk3gNQwKSdqUp+HydXDqi+FJyIkWR/ZASKE115N2qeVhobyp+e+/Rnn9S3Msc SOI+TVxHerTxzv/ZYCt30WIiLalaBhbuN2pRz46l0W5wSvDYY2BqclXX8Zk4hkRn GOBxjsFAbYXaS90xc7wyzG+Oe7mNS4DaucfGJINeMvuH6YthZ6KZdtulqrTobEGf Xyqz1X3XksgnS+wf2gVtiHOPBrI4PQOi4YeGPMahAgMBAAGjggFEMIIBQDAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1Ud EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFGiGuH162W1Ja4cvGIsVNGzXtHoOMB8G A1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMD0GCCsGAQUFBwEBBDEwLzAt BggrBgEFBQcwAYYhaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIxMDMG A1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC5j cmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3 Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQCa uYIc3YODi5LAxO0BrYT8Tu5tnB0B+lIU29jCEGOfazmaxxw8oKrjGTr8ZEYq7zUm A/YFZ/pudOFG+0DYb64tOSF0hp8ABRo/L5Nb1KRFvD0MKRda0/topg/gAGh5sEyx RYvIhYxnDox9VPiwdc4KrB3Xa0Ss/hvUppghCT6iSzO6uksSqGtXJ536lIC0aEx3 YP/XKVo4Pc4tSwhWn2nLe9jiNvk3acXONpccug0/FbNloOx0Er2zrejenqHs07+p 4KWRbYNZElYvE6Z+eXOho4nV4aWMzi2sis9iFmXN2e6otkAItXxQ+TeCeqQLNGbs 6ZdXH4pnPoG8OzXTKkgM -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIErjCCA5agAwIBAgIPIAYFFnADE4mV+0+/hYvPMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xNTA5MTAxMjMyMThaFw0yNTA5MTAxMjMyMThaMIGWMQsw CQYDVQQGEwJSTzERMA8GA1UECgwIY2VydFNJR04xNzA1BgNVBAsMLkNlcnRpZmlj YXQgZGUgcHJvZHVjdGllIFByb2R1Y3Rpb24gY2VydGlmaWNhdGUxOzA5BgNVBAMM MkNFUlRTSUdOIEZPUiBCQU5LSU5HIFFVQUxJRklFRCBEUyBQUk9EVUNUSU9OIENB IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoCrq4I0dsB4iNj4K YW7qYKkBcmc3+Hk/qONyDj1dTbBszzlbnzvPWnRgNGL3cBorJ3tQhQJV7JPMK9jM XyeAkTfKcjL+CPyS/AaMjRa9BPk5LqLUdqxe33EnOlHLu2jVXv6gFyj4L18Gw9YK miZQjGj4MXbIO89NQUX4fby24eGiH1P//RZdyIqBF/HUD3f8pTnE6w2TFIVgO5Jq CmAoH3c1XftwCSZGjtzMUflrBTswRD1bAf966x0JDxAwaSulO5Ensyxz8fXE78Pg 9wIU4+CP/Esc6aKSknOmRdUwnjhgJSxQbHGiFbOIjwGStSwt2Jg5zDKHZaHjLXbJ qXA1SQIDAQABo4IBUTCCAU0waAYIKwYBBQUHAQEEXDBaMCMGCCsGAQUFBzABhhdo dHRwOi8vb2NzcC5jZXJ0c2lnbi5ybzAzBggrBgEFBQcwAoYnaHR0cDovL3d3dy5j ZXJ0c2lnbi5yby9jZXJ0Y3JsL3Jvb3QuY3J0MBIGA1UdEwEB/wQIMAYBAf8CAQAw DgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFOCMm9slSbPxfIbWskKHC9BroNnk MB0GA1UdDgQWBBSpB0gRuLKVoNVy8S9VK5h87C0pnjBLBgNVHSAERDBCMEAGDSsG AQQBgcM5AQEDAQEwLzAtBggrBgEFBQcCARYhaHR0cDovL3d3dy5jZXJ0c2lnbi5y by9yZXBvc2l0b3J5MDAGA1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHNp Z24ucm8vcm9vdC5jcmwwDQYJKoZIhvcNAQELBQADggEBAGNlAeOVSzJ2GkfaAAVO OLKS1zoE5D+PSzmpvcTk8/rrQWWeijqbxGzSudCmLviNUEsyvcyf3orqqZUfhnZE S3oUl7rUI6NfFgzLyMSBoCE8RkxbxrUWAalisacrDGhhLiuBt/+Cs5wiEQle2A15 1id6dZYunAgmuDuzFMl/1nxsGZ6Ti5sW1sTirnDxFFe7PSg89Sqd4E5Ltn3MRG2X bxVAz5CSg6pDD3WvTAzDW2zi+YQI1nkM6HJvFszefs0s/77fd4K6q4ApOEPg2FpZ m6pWKgpyfcXPCxa7YFAYVWEOlqnz9I9rHyGJKyAwISG8UqnF0K/NYMJzvhTeu0Rw VZ4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIErDCCA5SgAwIBAgIPIAYFFnADFMy2p09D7N+NMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xNTA5MTAxMjQ4MjRaFw0yNTA5MTAxMjQ4MjRaMIGUMQsw CQYDVQQGEwJSTzERMA8GA1UECgwIY2VydFNJR04xNzA1BgNVBAsMLkNlcnRpZmlj YXQgZGUgcHJvZHVjdGllIFByb2R1Y3Rpb24gY2VydGlmaWNhdGUxOTA3BgNVBAMM MENFUlRTSUdOIEZPUiBCQU5LSU5HIFNJTVBMRSBTU0wgUFJPRFVDVElPTiBDQSBW MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANU799+R4U9BdR7FhqSV Isb2HOVR9JZBx6l/7oUqYSYf4GA01A6oeHCO47cZBvicpI7wTAQfOByPjjj3+Q3D 80sCHOPAVAPKlgKDYdd/0qz+6g9XZOLXPeNWbpIvfE7/J+uXFOF5iShqwh2kzKEs Jl0ZN5YN+ZqslxGxkXKmRdVq7FiPKZMqgFm/i5Yp3R6xQ55N+NGFQLLFzWnepsCT 1OcIcUEvEnx0aJy4o6sps85bPZOLAHwd5PxNJ8zM1jEOklT48xW2RXLs6ZjN8Q7/ sqN2YCU3wS8N8fSQFfp28+/AS4gC3gNw5uIUP8LA4qqu0S12aDeNnMjH2c2xb3Us VGMCAwEAAaOCAVEwggFNMGgGCCsGAQUFBwEBBFwwWjAjBggrBgEFBQcwAYYXaHR0 cDovL29jc3AuY2VydHNpZ24ucm8wMwYIKwYBBQUHMAKGJ2h0dHA6Ly93d3cuY2Vy dHNpZ24ucm8vY2VydGNybC9yb290LmNydDASBgNVHRMBAf8ECDAGAQH/AgEAMA4G A1UdDwEB/wQEAwIBhjAfBgNVHSMEGDAWgBTgjJvbJUmz8XyG1rJChwvQa6DZ5DAd BgNVHQ4EFgQUICETMsplqUpbZfhBTh3j+7Vbf2AwSwYDVR0gBEQwQjBABg0rBgEE AYHDOQEBAgEBMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cuY2VydHNpZ24ucm8v cmVwb3NpdG9yeTAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vY3JsLmNlcnRzaWdu LnJvL3Jvb3QuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQBCDjzDgC2NmOP2sslopI50 a+vItiu5cijDyZLa4z1hmllfwC6gd6GF6j9BmegmX6uiYvqJY91fMz5jCxLyz0fd u4IEWZe0Bc+YlNORIRl1+TFqFoU//NV6/bfnPSaXOwu/oHx7ubCZXQ8i9fa5kyfb UKfDARuoEEVO0NyIJniIy3ERKr/v6ILZRXM8zafAhOGrPqRJ9pekAuetnNrZLz1X PQUFKMDLneOO9Bj+WvXIZX/kB3IC+ls/Up1P1eKGQfCPWvxLcgXEHYvSfBTsPBrT 9KYN0gb2Oe63fdZk+OdvrRbAB78SN+6zUW94fG1tM+T+V2SdjNR/0EzsQ2rpOUdD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhzCCAw2gAwIBAgIIK0T3E98XDBYwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ cmVtaXVtIEVDQzAeFw0xNTA5MTYwMjQ5MDNaFw00MDEyMzExMTU5NTlaMIGLMQsw CQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxLTArBgNVBAsMJGh0dHA6 Ly93d3cuYWZmaXJtdHJ1c3QuY29tL3Jlc291cmNlczE3MDUGA1UEAwwuQWZmaXJt VHJ1c3QgUHJlbWl1bSBFQ0MgRXh0ZW5kZWQgVmFsaWRhdGlvbiBDQTB2MBAGByqG SM49AgEGBSuBBAAiA2IABMG7lpQW6KCRa0F08QvCChRc+0tN9z9QbOFDq3X7/2hS 4oCHzgAa2TAGTAb/yysYV3AIZwxcN19DmfLueos35w3XHxshgH6HadrmPmAgF5it /izFoUJpCsesqECqTiutuaOCAYEwggF9MHAGCCsGAQUFBwEBBGQwYjAyBggrBgEF BQcwAoYmaHR0cDovL29jc3AuYWZmaXJtdHJ1c3QuY29tL3BlY2NjYS5jcnQwLAYI KwYBBQUHMAGGIGh0dHA6Ly9vY3NwLmFmZmlybXRydXN0LmNvbS9wZWNjMB0GA1Ud DgQWBBQBBy+KEywCDqBYBkuipr4IIn8mrTAPBgNVHRMBAf8EBTADAQH/MB8GA1Ud IwQYMBaAFJqvKXrAETU1JlEwAMNq/kDVrtY8MF0GA1UdIARWMFQwDAYKKwYBBAGC jwkCBDBEBgorBgEEAYKPCQEBMDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuYWZm aXJtdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwSQYDVR0fBEIwQDA+oDygOoY4aHR0 cDovL2NybC5hZmZpcm10cnVzdC5jb20vY3JsL0FmZmlybVRydXN0UHJlbWl1bUVD Qy5jcmwwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMQDNDZhBT4EN OmFc2+3DQtlzH9riHkeHzOROSuQzH/CgK6WpWDXjou/Hq6j4aAD+FsQCMHE2AOME jvXgg10peS0mXiNUK6U7mPcnV1Vc5cEPL1mY0+e8XGQzcyNxzt8I4s0Z0A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGyzCCBLOgAwIBAgIIXVRFCaDWCqcwDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz dCBQcmVtaXVtMB4XDTE1MDkxNjAyNTAwNFoXDTQwMTIzMTExNTk1OVowgYcxCzAJ BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEtMCsGA1UECwwkaHR0cDov L3d3dy5hZmZpcm10cnVzdC5jb20vcmVzb3VyY2VzMTMwMQYDVQQDDCpBZmZpcm1U cnVzdCBQcmVtaXVtIEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQDIJKKCLrO1P8lH9elhDSFnhkVZBtV9stJEkM6M S4RQfyGJSYZW0r8tzUAoUaLhI2P60R8Y2Dpofzm78QfvDVcleGSCcfaPf7BElECA eb7bNg5ER6erP99pwDXyKs8nh1gCZrvTQhqZY2Ezi9g/SpuE0NhhudBFrGssaRQU tyHijlx5oHgq1yGhZ7cP0Zr6ulGIV8sGvq423NJUsjmt7iNFVEwyBKsmBGMnw3fV 371mfxbZQkmNpOY93qOzRzr+3yRnwV9tqh6ZwJ7g7naBqMKpZnSIwd+1CxkrZmYA GW6tLoIUzz57JA/LVEZb/5NFCQvodE+/6SeTfgl+v8XWXFoK2p57/D90gv2cMjVX QW7b9DD1INaNg+NLXxqWiozzxWte9S3IjJA7Cf7D7uLqFPMyBD8RqGN1u2h/DUnK UQL1dFy++Yovl9chQ67Ga6Ma3x1TVSuCf/gElTGBPzEFenbRUirlgK3n5/XxWe9G BA9ZjQiAkE37+6U+smEossQyEyy/qbBQuwZ9qy6fXbxYJLK5zm2HbxBONOWmWS8n F6aeUUI9D+WU0M0L42xAqdnSm60N2KKAdykGuDjZsIgQ1bxEJdGOYdw3seVuB21G 6arJZfhnbtwptgfTmtxH0yLgKQDf+t0RWuIw2S79uhOYBqQ3oDypzFiWa14HD3c8 BdQjfwIDAQABo4IBfjCCAXowcAYIKwYBBQUHAQEEZDBiMDIGCCsGAQUFBzAChiZo dHRwOi8vb2NzcC5hZmZpcm10cnVzdC5jb20vcHJlbWNhLmNydDAsBggrBgEFBQcw AYYgaHR0cDovL29jc3AuYWZmaXJtdHJ1c3QuY29tL3ByZW0wHQYDVR0OBBYEFLzd RrvkokL9idHmeR/XHkGpR/tQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU ncBnpgwi2Sb1RaumZVIRJ9hFrGMwXQYDVR0gBFYwVDAMBgorBgEEAYKPCQIDMEQG CisGAQQBgo8JAQEwNjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5hZmZpcm10cnVz dC5jb20vcmVzb3VyY2VzL2NwczBGBgNVHR8EPzA9MDugOaA3hjVodHRwOi8vY3Js LmFmZmlybXRydXN0LmNvbS9jcmwvQWZmaXJtVHJ1c3RQcmVtaXVtLmNybDAOBgNV HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEMBQADggIBAHWP+I0+dxmR0G/haN7/+pwY 8W+TM+ao/KCf3sRYWZ0N1cSyRhy2sQJpGcGzDcVEgEd9n4zGDp18FdhZZvAqv8xY xmOBZ4IyNErBFgzxMOX8uG49XvzX+2fUaOyGdCJbI57rwJXLFFzOs4N2VSugHOST xvfz/h4KEN9WAjAvK6KzsXW38d8gkWa6NS+hGlz6na6WDLszGJyjGarMfmYlpjbm 8wukDLFoJkBtay5Ud80MI94OvJHWeYxtp121SH++KLacI4DnLWtidaQNe5ST/oii 4w5+Jh00tyVdEiGQh9+QlXmhYXLMFZYOSAtIPHEeDNwaLf/y/hrpA4gVU2a2hLVD DewLfe9tHl2dvVt3+JQPjPcI6TYTGcta/IC4XImKaXUiLfF/7l3IuYWoOCIoiHwb O+YQqJIoAJkByUywEtLcDuVIttVy3mY02FbbhsTl3AX6h8f8MnmVhFYpPAe5CDfQ 2ZEjadqzZADxYzmkLOTqeVfI6XpKcPpAxoo1UX3xdew9GaRyAHHJJDSo+JUIByoF koqMi/NsHG3rbH4fITXI9/xX5vPVTuuZxjLLOu23Rm1jQEn33zFH0VwGtkMXGd+o /dkkcIhhoqqYsL30CS8ctkZvFCXYZTnXh0CmEQLIrcpIRn37r5o0JzFQVXmihzA+ 8xT6qz7h5DGg4jP7Wyo4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGSjCCBTKgAwIBAgIQBaQqKlSjSO+LEKr8/e27czANBgkqhkiG9w0BAQsFADCB ijELMAkGA1UEBhMCVVMxGjAYBgNVBAoTEU9yaW9uIEhlYWx0aCBJbmMuMS0wKwYD VQQLEyRPcmlvbiBIZWFsdGggRGlyZWN0IFNlY3VyZSBNZXNzYWdpbmcxMDAuBgNV BAMTJ09yaW9uIEhlYWx0aCBEaXJlY3QgU2VjdXJlIE1lc3NhZ2luZyBDQTAeFw0x NTA5MjUxMjAwMDBaFw0yNTA5MjUxMjAwMDBaMIGUMQswCQYDVQQGEwJVUzE+MDwG A1UEChM1TWFzc2FjaHVzZXR0cyBIZWFsdGggSW5mb3JtYXRpb24gSGlnaHdheSAo TWFzcyBISXdheSkxLTArBgNVBAsTJE9yaW9uIEhlYWx0aCBEaXJlY3QgU2VjdXJl IE1lc3NhZ2luZzEWMBQGA1UEAxMNTWFzcyBISXdheSBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBANOfdetY49oziDBfhSUoS/MFnruSfg+ZjpzToUKJ lfY6HZxUxqErlMxTco85zI6EljPekZkTkIXG+qB70+8dU8FfeAssquSM+eHyGjKe BMgX0nZ0f2xGh/fWiCgNpgH3sl9S41vox4Ud3CTbF5Ec7W76xF81ehtYO2YXtdt0 jG8MgVIZn2v16NLyvF62iCCrJlchjOgzATA01zSbBDSZEQV0yYG6wELPx2igdklm tcAOKMmXbJxQ5TwZRtSVkZgcfSBdB+SRH3maB5gJKdeom1+Jf4j+F2mix0vb7kpL mXt+ZgwB/MFHH5zU9LDGDy6D5H+9lZstx/osL4ib8CE3Hs8CAwEAAaOCAp4wggKa MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMHoGCCsGAQUFBwEB BG4wbDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEQGCCsG AQUFBzAChjhodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vYWlhT3Jpb25IZWFs dGhJc3N1aW5nQ0FzLnA3YzCBmQYDVR0fBIGRMIGOMEWgQ6BBhj9odHRwOi8vY3Js NC5kaWdpY2VydC5jb20vT3Jpb25IZWFsdGhEaXJlY3RTZWN1cmVNZXNzYWdpbmdD QS5jcmwwRaBDoEGGP2h0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9PcmlvbkhlYWx0 aERpcmVjdFNlY3VyZU1lc3NhZ2luZ0NBLmNybDCCARoGA1UdIASCAREwggENMDgG CmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu Y29tL0NQUzAMBgpghkgBhv1sBAEBMAwGCmCGSAGG/WwEAQIwCwYJYIZIAYb9bAQC MAwGCmCGSAGG/WwEAwIwDAYKYIZIAYb9bAQEAjAOBgxghkgBhvlbA4ohAAEwDAYK KwYBBAGCwVsAATAMBgorBgEEAYLBWwEBMAwGCisGAQQBgsFbAQIwDAYKKwYBBAGC wVsBAzAMBgorBgEEAYLBWwEEMAwGCisGAQQBgsFbAgEwDAYKKwYBBAGCwVsCAjAM BgorBgEEAYLBWwIDMAwGCisGAQQBgsFbAgQwHQYDVR0OBBYEFEH0hvKcQ8WqnFJa ejx+8YQxvGG6MB8GA1UdIwQYMBaAFKVuIv85aToj+4kkF8ZglAAa2o6eMA0GCSqG SIb3DQEBCwUAA4IBAQAusAW9ek8QKCS6fbXf2C/1oGP/jtBWffE+bHhtq0ZN1rmi /uSZ1k8PF8rP640/GBiqpI3EV5w6bidgOXP+XKXN9eMiLLSbXAKWmpP7SEnGDpSP OA2zq4zo3mKkfcgRXVJ8srqz58x7RhbShoelg26G+GKJQlZwz4IkP/46bgH6ZsCX lgE5Uwe9nQKyEFpUubdChRyzCHSt3ydQbYUOQgywJtQAvpj6Swxvr31/dsaR4Z28 nBdyLlqLgJEjj+E0EWvK3mgpXStPYF59x2p0Uw8kIfPe+H6OU/lfEt3AYOSw4haW mHXux215tZG8GEy+cCRAMszFVwg3Y5nyJkkg1FMU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF6jCCBNKgAwIBAgIQCRasQhL5QBnnNPBjDb8JXzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBGZWRlcmF0ZWQgVHJ1 c3QgQ0EwHhcNMTUwOTI1MTIwMDAwWhcNMjUwOTI1MTIwMDAwWjBpMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSgwJgYDVQQDEx9EaWdpQ2VydCBHb3Zlcm5tZW50YWwgRGlyZWN0IENB MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtLqqXLLxNsN92M7tMY+R NTnF0Fz191GCva7n9FbBbPHckzTzd7pxgDGQwDPvHGs2ysRBao88lOLfLPgh53XN sQfhBrNdqSiFEpkzHYEzAUwzN123HsjvgrAY84/j+AYN+ZoAt/HO4ikvLuQUvOwO viPc7ACUDo8ZbpzLWhScJ9wY8dzliJyu46LAtvYk4+PCDAHGBMG7rcrHGqK8+yVk UiT255zHgoD5TFv5JajoUXKGL6C+aWS/ilkeRan1CohYnLhOkEA7NMHzZttVVkEw z2TgryhBxQNwrR3FhZrrT8Xl6jHYRvLKM0tLvHcLZPaqergMrKFI66ri1NHQUuNc CQIDAQABo4ICkDCCAowwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC AYYwgYEGCCsGAQUFBwEBBHUwczAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln aWNlcnQuY29tMEsGCCsGAQUFBzAChj9odHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j b20vYWlhRGlnaUNlcnRHb3Zlcm5tZW50YWxEaXJlY3RDQS5wN2MwgYMGA1UdHwR8 MHowO6A5oDeGNWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEZlZGVy YXRlZFRydXN0Q0EuY3JsMDugOaA3hjVodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v RGlnaUNlcnRGZWRlcmF0ZWRUcnVzdENBLmNybDCCARoGA1UdIASCAREwggENMDgG CmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu Y29tL0NQUzAMBgpghkgBhv1sBAEBMAwGCmCGSAGG/WwEAQIwCwYJYIZIAYb9bAQC MAwGCmCGSAGG/WwEAwIwDAYKYIZIAYb9bAQEAjAOBgxghkgBhvlbA4ohAAEwDAYK KwYBBAGCwVsAATAMBgorBgEEAYLBWwEBMAwGCisGAQQBgsFbAQIwDAYKKwYBBAGC wVsBAzAMBgorBgEEAYLBWwEEMAwGCisGAQQBgsFbAgEwDAYKKwYBBAGCwVsCAjAM BgorBgEEAYLBWwIDMAwGCisGAQQBgsFbAgQwHQYDVR0OBBYEFHAtS6mEARqEdfd4 qQlJ7DBL+W/rMB8GA1UdIwQYMBaAFEYIOFqpjiC7DK9eMbqJsyi/rIw2MA0GCSqG SIb3DQEBCwUAA4IBAQCu1sc2zU2hkzv2aI2LwPjuU1NsyWyoZYf/5HZv5hTBG7ph TGTGQQpr1yaxyPUAE5iZ2TdqPpC6NFhsqzRgKuA/PgyE+Kb5uonhOeOi2QGAyv8k Ozxki5yLvzikjZPpPwoodXiam7fGoJsdEMUewuDObX49ZlghTZMUr66EPcK/AtTX a55dXJ+OAFDIc/oZIdxabZPuO895GsWxAnSy4IyoqQ4IFCiUEzjxE3XrKeT6ccGB Dc/VMSHPScHNOmgqcs0qfkNYzXQOknbsy6D2HgWEKV8JAR8Eq0tSKHnKCbc1aYaJ F2RDlO0O9tquXZPNt3Ng0fbvPxNbHMNSsNEeDDo4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFDjCCA/agAwIBAgIMDulMwwAAAABR03eFMA0GCSqGSIb3DQEBCwUAMIG+MQsw CQYDVQQGEwJVUzEWMBQGA1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2Vl IHd3dy5lbnRydXN0Lm5ldC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMDkg RW50cnVzdCwgSW5jLiAtIGZvciBhdXRob3JpemVkIHVzZSBvbmx5MTIwMAYDVQQD EylFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjAeFw0x NTEwMDUxOTEzNTZaFw0zMDEyMDUxOTQzNTZaMIG6MQswCQYDVQQGEwJVUzEWMBQG A1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2VlIHd3dy5lbnRydXN0Lm5l dC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMTIgRW50cnVzdCwgSW5jLiAt IGZvciBhdXRob3JpemVkIHVzZSBvbmx5MS4wLAYDVQQDEyVFbnRydXN0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5IC0gTDFLMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEA2j+W0E25L0Tn2zlem1DuXKVh2kFnUwmqAJqOV38pa9vH4SEkqjrQ jUcj0u1yFvCRIdJdt7hLqIOPt5EyaM/OJZMssn2XyP7BtBe6CZ4DkJN7fEmDImiK m95HwzGYei59QAvS7z7Tsoyqj0ip/wDoKVgG97aTWpRzJiatWA7lQrjV6nN5ZGhT JbiEz5R6rgZFDKNrTdDGvuoYpDbwkrK6HIiPOlJ/915tgxyd8B/lw9bdpXiSPbBt LOrJz5RBGXFEaLpHPATpXbo+8DX3Fbae8i4VHj9HyMg4p3NFXU2wO7GOFyk36t0F ASK7lDYqjVs1/lMZLwhGwSqzGmIdTivZGwIDAQABo4IBDDCCAQgwDgYDVR0PAQH/ BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsG AQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAwBgNVHR8EKTAnMCWgI6Ah hh9odHRwOi8vY3JsLmVudHJ1c3QubmV0L2cyY2EuY3JsMDsGA1UdIAQ0MDIwMAYE VR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L3JwYTAd BgNVHQ4EFgQUgqJwdN28Uz/Pe9T3zX+nYMYKTL8wHwYDVR0jBBgwFoAUanImetAe 733nO2lR1GyNn5ASZqswDQYJKoZIhvcNAQELBQADggEBADnVjpiDYcgsY9NwHRkw y/YJrMxp1cncN0HyMg/vdMNY9ngnCTQIlZIv19+4o/0OgemknNM/TWgrFTEKFcxS BJPok1DD2bHi4Wi3Ogl08TRYCj93mEC45mj/XeTIRsXsgdfJghhcg85x2Ly/rJkC k9uUmITSnKa1/ly78EqvIazCP0kkZ9Yujs+szGQVGHLlbHfTUqi53Y2sAEo1GdRv c6N172tkw+CNgxKhiucOhk3YtCAbvmqljEtoZuMrx1gL+1YQ1JH7HdMxWBCMRON1 exCdtTix9qrKgWRs6PLigVWXUX/hwidQosk8WwBD9lu51aX8/wdQQGcHsFXwt35u Lcw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYzCCA0ugAwIBAgIQBdoN7Kc1obxcNtUe1erXujANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE1 MTAxNDEyMDAwMFoXDTI1MDUxMDEyMDAwMFowZDELMAkGA1UEBhMCVVMxFTATBgNV BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEjMCEG A1UEAxMaRGlnaUNlcnQgQmFsdGltb3JlIENBLTEgRzIwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQCcFjx6VK459CTGcFIwL7rt08Qb5VFYmcXUAC/qOayu iOvQzrxOW4xLyNfZLWkJZZgwvupmUeYG8Ao66qi0opqEqWXtGG5eIw99wE0Tg48+ phTB5pP3FgCXiN2RO73R8e6RAAb0thbErY9AKdFesatWCd1M3p1ZWdjvjIthUxe4 mufcPsazFi96oDinM/ORTLeOECAQmXgsXRde2faVEwCU+OqlVTQWng1jfa3cztQ7 aC0fpeDqvEhAuJ6qCM7acZElejJKkkeN0rGb7UOMs7B8dMn8lwPxtKm3efcyXAn3 lybgoOA4so6E1co5LGcQt1QQp2WzxaytwsqUwOCGNgm9AgMBAAGjggEZMIIBFTAS BgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjA0BggrBgEFBQcBAQQo MCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTA6BgNVHR8E MzAxMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vT21uaXJvb3QyMDI1 LmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93 d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUtvlIUEhv85/rvlO6J4lOdZq0 vWcwHwYDVR0jBBgwFoAU5Z1ZMIJHWMys+ghUNoZ7OrUETfAwDQYJKoZIhvcNAQEL BQADggEBAIvMSJv4auzcgy1g2K7t52O931Z3tlb4rVUJNk69wo1dJqEKeVWfr2UP aacS9oBZYATgxjtEHmu8cHBGv6Bex4siT9+UrGdzCnKYtYwas9ZIWkH1EAe53h1k as/t4gQTl/JZNxK8omdUBSd0z/egR8Zlzshg3ySdVd/rcaZWEFa8rRQvAwfoNLoH psecZXmFwFAkmu5odsvdfyXEImGo1gFeLyUOAKJjSMz9zsSXBxVj6j/YglPRsFuV 98a6sKE5Y07vRRWWC/KHFgckqU6hHmk7DpXaIsVsl2UU65W6LdyZ8cDf1DKlOrKq g16c0LkLttQNOnS9jgWJJoJjN0m4eS4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYTCCA0mgAwIBAgIQCczcn5k0S1LTezBTdtbCxTANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE1 MTAxNDEyMDAwMFoXDTI1MDUxMDEyMDAwMFowYjELMAkGA1UEBhMCVVMxFTATBgNV BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8G A1UEAxMYRGlnaUNlcnQgQmFsdGltb3JlIEVWIENBMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAtnSaCvMG9TXrCtbBTUnfoXDA1nxkxYNP5lSxqMwbqxx/ fHivQGfoG6S4yE8xYpFszud0OplTaD1tfDsWJgTgu5k64mZuZ17IVCMVTgBF+bdL DlRV80N4HCw0sNrjgTYDyvBlnrhsqZEtPZfOFstm+6TxV6dG1nTdCiGyC8lQkZ5D 3kV3WVFDgAB2Xrz4gTdQ2NLGqLmmQQvj9snmQ5jsaenX+uYJBpJILEVY4US0YhTL GwynXzkt1c0gblihuYVWC3O7MhMaiJQM08WmLS0rzzm1wggiuLG9TwLm9OJh8dVA X5QNAzPotYEXh0Sm8uMJu6kuuvBafivc0ai97h2v8QIDAQABo4IBGTCCARUwEgYD VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEEKDAm MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wOgYDVR0fBDMw MTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09tbmlyb290MjAyNS5j cmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFBYAcJjh6EVnw5usVJcbzrEqNh55 MB8GA1UdIwQYMBaAFOWdWTCCR1jMrPoIVDaGezq1BE3wMA0GCSqGSIb3DQEBCwUA A4IBAQCbL16pTZZS/LD1hJssG9VpUvlfpoIWpF1vp2uDRL0A5fsBV+1FxcJLO0y1 InK89VNGpPt7GoKF+UQuqa1IWMLjAavrrpyPHxOo17eHLlmpHn4qJSA/pL4V8JFL o9nVXMOEUP+uHIB4282uElsJ7AJWJYKq+QkKnFaeOwhfNq502DnagUDM8ybHGE3k cvmbL+suy0XsRo9ny+tRuoUATscnVI//3r+cCRVQa34Dlksl/yj+2h80saHcSEjp n+YAnvp1YhI+wc1EvvAah+7VN1UFAIRIyQ91hHp0gzZppjmsJYmPfuw6CYzK1LqN FxIihbFnfU8LRCgfrSAmqLs+rFdf -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkjCCA3qgAwIBAgITBntQSu8k7aSeV/dHSEVj9OKhWDANBgkqhkiG9w0BAQsF ADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNj b3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4x OzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1 dGhvcml0eSAtIEcyMB4XDTE1MTAyMTIyMjA0NVoXDTM3MTIzMTAwMDAwMFowOTEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM 9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L 93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm jgSubJrIqg0CAwEAAaOCATEwggEtMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgGGMB0GA1UdDgQWBBSEGMyFNOy8DJSULghZnMeyEE4KCDAfBgNVHSMEGDAW gBScXwDfqgHXMCs4iKK4bUqc8hGRgzB4BggrBgEFBQcBAQRsMGowLgYIKwYBBQUH MAGGImh0dHA6Ly9vY3NwLnJvb3RnMi5hbWF6b250cnVzdC5jb20wOAYIKwYBBQUH MAKGLGh0dHA6Ly9jcmwucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY2Vy MD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwucm9vdGcyLmFtYXpvbnRydXN0 LmNvbS9yb290ZzIuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQsF AAOCAQEAY7ItFmzGZlk1ae7URE8CTUg2qZlmSCFugdXGuQZ+/tFHLxolCdmw2Jfn PX367cbcElUhFvLFRtLwW99VYVqKLA1ypmrs5uuMGOXUUmPA6hU+2dovhh5KuClm 58gz2fH7Gw+V9ko2CRt0XXDmXMJzXxRW1CgcNC05RXnD8J92iMyrok1KnB4+emMU kNBrcaE+XuqRuAc7lJ9qv4t+JYtEszz3k+Q68TlOOIp0W5k5Xvsx0Q+/r6qCOECs JP9dLmsuIA/SrhyqW5qTvul/X7nJLlffGWYsbOdmrUzA6fZR9NeL/Ljlx98/ouE3 4dmgCQgWbRp4XTnGnL3XLbVPUAReEQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCA4qgAwIBAgITBntQUp3WX1ga1fXFWlp5GKFvkzANBgkqhkiG9w0BAQsF ADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNj b3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4x OzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1 dGhvcml0eSAtIEcyMB4XDTE1MTAyMTIyMjIyN1oXDTQwMTAyMTIyMjIyN1owRjEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB IDBBMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQChhTHcMX+WcSKio/2VJ8N0cCpdrUf4oB9V+fx2dFxU+XgRvszhgePcNKv5 d7a0qOWF9uLmYix0BP34xYujNe0TTGBjOdjCWmTLi9mb5gO8Qxe3eaPZFHX2JbA+ GeqyLkv3/Dt4SkggAZX1PvoaPlCytHCW7qDdo+ycuqwrrfl0fYfJrEA+O5x8v+uH UmC5APF5vYE8XdGhGra5JRot2TY3P+Kh1AfuJWPLBRgmmbPscv81zVdl+LzZdGFP dCnCwE9OKd4stKNkO2vTwdJykLgovcF889LQdbPfCx7UaDeHdAcJLyNcS0i5FrHD 7hNfwzfpOORF0+1wF6HdE/GBUJBJAgMBAAGjggE0MIIBMDASBgNVHRMBAf8ECDAG AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUl+rEItIGGO2FBP/cUsJu 2w4G4T8wHwYDVR0jBBgwFoAUnF8A36oB1zArOIiiuG1KnPIRkYMweAYIKwYBBQUH AQEEbDBqMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcC5yb290ZzIuYW1hem9udHJ1 c3QuY29tMDgGCCsGAQUFBzAChixodHRwOi8vY3JsLnJvb3RnMi5hbWF6b250cnVz dC5jb20vcm9vdGcyLmNlcjA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnJv b3RnMi5hbWF6b250cnVzdC5jb20vcm9vdGcyLmNybDARBgNVHSAECjAIMAYGBFUd IAAwDQYJKoZIhvcNAQELBQADggEBAGUFWQnstW12HJoKhJv5R2BqmRMdCrlDmUdc 0LyKXrE5lb8FJVCJcoebwtXhBedaIQxxaDZHXbNOPyMFWhE2j2pLEDTKGY4MQRb/ KAUAR6jncl3MQCmVBvRmA4tzwZtNbqWYhb70YUn4KjP+3O8IV86WwYrLBxIh6sh/ jfWIenw2ipRJJEHk64wBpQIKCpTPgloB8n8u2TbVqbrDefBanajPWWstOPw51YdW 2GSYqbRhIxQnin7WYztBlboIaRxehsftLeShWGokb0yOW5+4pqrw7w7vxv2d/uSl fZx3MqHAesyqNGtcwOuf2tYr/NJZAaXawY3LfNJ4r49K/NwPTlI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIERzCCAy+gAwIBAgITBntQWB5VRYI8C6YvYwneX8pJTDANBgkqhkiG9w0BAQsF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAxMB4XDTE1MTAyMTIyMjM0MFoXDTQwMTAyMTIyMjM0MFowRjEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB IDFBMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCeQM3XCsIZunv8bSJxOqkc/ed87uL76FDB7teBNThDRB+1J7aITuadbNfH 5ZfZykrdZ1qQLKxP6DwHOmJr9u2b4IxjUX9qUMuq4B02ghD2g6yU3YivEosZ7fpo srD2TBN29JpgPGrOrpOE+ArZuIpBjdKFinemu6fTDD0NCeQlfyHXd1NOYyfYRLTa xlpDqr/2M41BgSkWQfSPHHyRWNQgWBiGsIQaS8TK0g8OWi1ov78+2K9DWT+AHgXW AanjZK91GfygPXJYSlAGxSiBAwH/KhAMifhaoFYAbH0Yuohmd85B45G2xVsop4TM Dsl007U7qnS7sdJ4jYGzEvva/a95AgMBAAGjggE5MIIBNTASBgNVHRMBAf8ECDAG AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUYtRCXoZwdWqQvMa40k1g wjS6UTowHwYDVR0jBBgwFoAUhBjMhTTsvAyUlC4IWZzHshBOCggwewYIKwYBBQUH AQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5yb290Y2ExLmFtYXpvbnRy dXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NybC5yb290Y2ExLmFtYXpvbnRy dXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3Js LnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY3JsMBEGA1UdIAQKMAgw BgYEVR0gADANBgkqhkiG9w0BAQsFAAOCAQEAfO6dSZbEgjuEREF/cAS09ZJBmd+3 lH2lkjpULqhxMMSPwe2NxheHJO46hyp2205IcM/+/zlxUIIViissPDXyrEN6WlQa 7Qhu/UcfCsOdCi1zjbG9Oe1Z2UQhQhHhy8zAE0/SsZaxDkQpdgnyI+oI6sEzLXoQ JLgiwoM0F6QzB+n18CJPihdmzqCS2Q57gATLED7umyLD0ULvmr6JRa0HyxNAFOIn YsYBnS9X8mkiVg+1iXsM3GjmownXvCvxG8Wf5DHFhOx9/WaA6C0k+K4tLsO3geYy W/LI5QFZwJMW6+ieFTjhyI6EzEolo7Z6PWaNB4X26611NpZ1IrWn56hFCw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIESTCCAzGgAwIBAgITBntQXCplJ7wevi2i0ZmY7bibLDANBgkqhkiG9w0BAQsF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAxMB4XDTE1MTAyMTIyMjQzNFoXDTQwMTAyMTIyMjQzNFowRjEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB IDFCMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDCThZn3c68asg3Wuw6MLAd5tES6BIoSMzoKcG5blPVo+sDORrMd4f2AbnZ cMzPa43j4wNxhplty6aUKk4T1qe9BOwKFjwK6zmxxLVYo7bHViXsPlJ6qOMpFge5 blDP+18x+B26A0piiQOuPkfyDyeR4xQghfj66Yo19V+emU3nazfvpFA+ROz6WoVm B5x+F2pV8xeKNR7u6azDdU5YVX1TawprmxRC1+WsAYmz6qP+z8ArDITC2FMVy2fw 0IjKOtEXc/VfmtTFch5+AfGYMGMqqvJ6LcXiAhqG5TI+Dr0RtM88k+8XUBCeQ8IG KuANaL7TiItKZYxK1MMuTJtV9IblAgMBAAGjggE7MIIBNzASBgNVHRMBAf8ECDAG AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUWaRmBlKge5WSPKOUByeW dFv5PdAwHwYDVR0jBBgwFoAUhBjMhTTsvAyUlC4IWZzHshBOCggwewYIKwYBBQUH AQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5yb290Y2ExLmFtYXpvbnRy dXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NybC5yb290Y2ExLmFtYXpvbnRy dXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3Js LnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY3JsMBMGA1UdIAQMMAow CAYGZ4EMAQIBMA0GCSqGSIb3DQEBCwUAA4IBAQAfsaEKwn17DjAbi/Die0etn+PE gfY/I6s8NLWkxGAOUfW2o+vVowNARRVjaIGdrhAfeWHkZI6q2pI0x/IJYmymmcWa ZaW/2R7DvQDtxCkFkVaxUeHvENm6IyqVhf6Q5oN12kDSrJozzx7I7tHjhBK7V5Xo TyS4NU4EhSyzGgj2x6axDd1hHRjblEpJ80LoiXlmUDzputBXyO5mkcrplcVvlIJi WmKjrDn2zzKxDX5nwvkskpIjYlJcrQu4iCX1/YwZ1yNqF9LryjlilphHCACiHbhI RnGfN8j8KLDVmWyTYMk8V+6j0LI4+4zFh2upqGMQHL3VFVFWBek6vCDWhB/b -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIESTCCAzGgAwIBAgITBn+UV4WH6Kx33rJTMlu8mYtWDTANBgkqhkiG9w0BAQsF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAxMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB IDFCMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDCThZn3c68asg3Wuw6MLAd5tES6BIoSMzoKcG5blPVo+sDORrMd4f2AbnZ cMzPa43j4wNxhplty6aUKk4T1qe9BOwKFjwK6zmxxLVYo7bHViXsPlJ6qOMpFge5 blDP+18x+B26A0piiQOuPkfyDyeR4xQghfj66Yo19V+emU3nazfvpFA+ROz6WoVm B5x+F2pV8xeKNR7u6azDdU5YVX1TawprmxRC1+WsAYmz6qP+z8ArDITC2FMVy2fw 0IjKOtEXc/VfmtTFch5+AfGYMGMqqvJ6LcXiAhqG5TI+Dr0RtM88k+8XUBCeQ8IG KuANaL7TiItKZYxK1MMuTJtV9IblAgMBAAGjggE7MIIBNzASBgNVHRMBAf8ECDAG AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUWaRmBlKge5WSPKOUByeW dFv5PdAwHwYDVR0jBBgwFoAUhBjMhTTsvAyUlC4IWZzHshBOCggwewYIKwYBBQUH AQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5yb290Y2ExLmFtYXpvbnRy dXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NydC5yb290Y2ExLmFtYXpvbnRy dXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3Js LnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY3JsMBMGA1UdIAQMMAow CAYGZ4EMAQIBMA0GCSqGSIb3DQEBCwUAA4IBAQCFkr41u3nPo4FCHOTjY3NTOVI1 59Gt/a6ZiqyJEi+752+a1U5y6iAwYfmXss2lJwJFqMp2PphKg5625kXg8kP2CN5t 6G7bMQcT8C8xDZNtYTd7WPD8UZiRKAJPBXa30/AbwuZe0GaFEQ8ugcYQgSn+IGBI 8/LwhBNTZTUVEWuCUUBVV18YtbAiPq3yXqMB48Oz+ctBWuZSkbvkNodPLamkB2g1 upRyzQ7qDn1X8nn8N8V7YJ6y68AtkHcNSRAnpTitxBKjtKPISLMVCx7i4hncxHZS yLyKQXhw2W2Xs0qLeC1etA+jTGDK4UfLeC0SF7FSi8o5LL21L8IzApar2pR/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICuzCCAmGgAwIBAgITBn+UV1j+VbnuP3WDHUfwfSJsijAKBggqhkjOPQQDAjA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g Um9vdCBDQSAzMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjELMAkG A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENBIDNB MQ8wDQYDVQQDEwZBbWF6b24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATYcYsK mYdR0Gj8Xz45E/lfcTTnXhg2EtAIYBIHyXv/ZQyyyCas1aptX/I5T1coT6XK181g nB8hADuKfWlNoIYRo4IBOTCCATUwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8B Af8EBAMCAYYwHQYDVR0OBBYEFATc4JXl6LlrlKHvjFsxHhN+VZfaMB8GA1UdIwQY MBaAFKu229cGnjesMIYHkXDHnMQZsXjAMHsGCCsGAQUFBwEBBG8wbTAvBggrBgEF BQcwAYYjaHR0cDovL29jc3Aucm9vdGNhMy5hbWF6b250cnVzdC5jb20wOgYIKwYB BQUHMAKGLmh0dHA6Ly9jcnQucm9vdGNhMy5hbWF6b250cnVzdC5jb20vcm9vdGNh My5jZXIwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC5yb290Y2EzLmFtYXpv bnRydXN0LmNvbS9yb290Y2EzLmNybDARBgNVHSAECjAIMAYGBFUdIAAwCgYIKoZI zj0EAwIDSAAwRQIgOl/vux0qfxNm05W3eofa9lKwz6oKvdu6g6Sc0UlwgRcCIQCS WSQ6F6JHLoeOWLyFFF658eNKEKbkEGMHz34gLX/N3g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIERzCCAy+gAwIBAgITBn+UV1CMZIwJymUucXkYMOclkjANBgkqhkiG9w0BAQsF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAxMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB IDFBMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCeQM3XCsIZunv8bSJxOqkc/ed87uL76FDB7teBNThDRB+1J7aITuadbNfH 5ZfZykrdZ1qQLKxP6DwHOmJr9u2b4IxjUX9qUMuq4B02ghD2g6yU3YivEosZ7fpo srD2TBN29JpgPGrOrpOE+ArZuIpBjdKFinemu6fTDD0NCeQlfyHXd1NOYyfYRLTa xlpDqr/2M41BgSkWQfSPHHyRWNQgWBiGsIQaS8TK0g8OWi1ov78+2K9DWT+AHgXW AanjZK91GfygPXJYSlAGxSiBAwH/KhAMifhaoFYAbH0Yuohmd85B45G2xVsop4TM Dsl007U7qnS7sdJ4jYGzEvva/a95AgMBAAGjggE5MIIBNTASBgNVHRMBAf8ECDAG AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUYtRCXoZwdWqQvMa40k1g wjS6UTowHwYDVR0jBBgwFoAUhBjMhTTsvAyUlC4IWZzHshBOCggwewYIKwYBBQUH AQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5yb290Y2ExLmFtYXpvbnRy dXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NydC5yb290Y2ExLmFtYXpvbnRy dXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3Js LnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY3JsMBEGA1UdIAQKMAgw BgYEVR0gADANBgkqhkiG9w0BAQsFAAOCAQEAMHbSWHRFMzGNIE0qhN6gnRahTrTU CDPwe7l9/q0IA+QBlrpUHnlAreetYeH1jB8uF3qXXzy22gpBU7NqulTkqSPByT1J xOhpT2FpO5R3VAdMPdWfSEgtrED0jkmyUQrR1T+/A+nBLdJZeQcl+OqLgeY790JM JJTsJnnI6FBWeTGhcDI4Y+n3KS3QCVePeWI7jx1dhrHcXH+QDX8Ywe31hV7YENdr HDpUXrjK6eHN8gazy8G6pndXHFwHp4auiZbJbYAk/q1peOTRagD2JojcLkm+i3cD 843t4By6YT/PVlePU2PCWejkrJQnKQAPOov7IA8kuO2RDWuzE/zF6Hotdg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGRzCCBC+gAwIBAgITBn+UV1Xxh6kfgWPz5iRiAXf/ODANBgkqhkiG9w0BAQwF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAyMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB IDJBMQ8wDQYDVQQDEwZBbWF6b24wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQC0P8hSLewmrZ41CCPBQytZs5NBFMq5ztbnMf+kZUp9S25LPfjNW3zgC/6E qCTWNVMMHhq7ez9IQJk48qbfBTLlZkuKnUWbA9vowrDfcxUN0mRE4B/TJbveXyTf vE91iDlqDrERecE9D8sdjzURrtHTp27lZdRkXFvfEVCq4hl3sHkzjodisaQthLp1 gLsiA7vKt+8zcL4Aeq52UyYb8r4/jdZ3KaQp8O/T4VwDCRKm8ey3kttpJWaflci7 eRzNjY7gE3NMANVXCeQwOBfH2GjINFCObmPsqiBuoAnsv2k5aQLNoU1OZk08ClXm mEZ2rI5qZUTX1HuefBJnpMkPugFCw8afaHnB13SkLE7wxX8SZRdDIe5WiwyDL1tR 2+8lpz4JsMoFopHmD3GaHyjbN+hkOqHgLltwewOsiyM0u3CZphypN2KeD+1FLjnY TgdIAd1FRgK2ZXDDrEdjnsSEfShKf0l4mFPSBs9E3U6sLmubDRXKLLLpa/dF4eKu LEKS1bXYT28iM6D5gSCnzho5G4d18jQD/slmc5XmRo5Pig0RyBwDaLuxeIZuiJ0A J6YFhffbrLYF5dEQl0cU+t3VBK5u/o1WkWXsZawU038lWn/AXerodT/pAcrtWA4E NQEN09WEKMhZVPhqdwhF/Gusr04mQtKt7T2v6UMQvtVglv5E7wIDAQABo4IBOTCC ATUwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYE FNpDStD8AcBLv1gnjHbNCoHzlC70MB8GA1UdIwQYMBaAFLAM8Eww9AVYAkj9M+VS r0uE42ZSMHsGCCsGAQUFBwEBBG8wbTAvBggrBgEFBQcwAYYjaHR0cDovL29jc3Au cm9vdGNhMi5hbWF6b250cnVzdC5jb20wOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQu cm9vdGNhMi5hbWF6b250cnVzdC5jb20vcm9vdGNhMi5jZXIwPwYDVR0fBDgwNjA0 oDKgMIYuaHR0cDovL2NybC5yb290Y2EyLmFtYXpvbnRydXN0LmNvbS9yb290Y2Ey LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggIBAEO5W+iF yChjDyyrmiwFupVWQ0Xy2ReFNQiZq7XKVHvsLQe01moSLnxcBxioOPBKt1KkZO7w Gcbmke0+7AxLaG/F5NPnzRtK1/pRhXQ0XdU8pVh/1/h4GoqRlZ/eN0JDarUhZPkV kSr96LUYDTxcsAidF7zkzWfmtcJg/Aw8mi14xKVEa6aVyKu54c8kKkdlt0WaigOv Z/xYhxp24AfoFKaIraDNdsD8q2N7eDYeN4WGLzNSlil+iFjzflI9mq1hTuI/ZNjV rbvob6FUQ8Cc524gMjbpZCNuZ1gfXzwwhGp0AnQF6CJsWF9uwPpZEVFnnnfiWH3M oup41EvBhqaAqOlny0sm5pI82nRUCAE3DLkJ1+eAtdQaYblZQkQrRyTuPmJEm+5y QwdDVw6uHc5OsSj/tyhh8zJ2Xq3zgh3dMONGjJEysxGaCoIb+61PWwMy2dIarVwI r+c+AY+3PrhgBspNdWZ87JzNHii7ksdjUSVGTTy1vGXgPYrv0lp0IMnKaZP58xiw rDx7uTlQuPVWNOZvCaT3ZcoxTsNKNscIUe+WJjWx5hdzpv/oksDPY5ltZ0j3hlDS D+Itk95/cNJVRM/0HpxI1SX9MTZtOSJoEDdUtOpVaOuBAvEK4gvTzdt0r5L+fuI6 o5LAuRo/LO1xVRH49KFRoaznzU3Ch9+kbPb3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC+TCCAn6gAwIBAgITBn+UV1qIYqkHLjI5w3zroSdOGDAKBggqhkjOPQQDAzA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g Um9vdCBDQSA0MB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjELMAkG A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENBIDRB MQ8wDQYDVQQDEwZBbWF6b24wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASRP0kIW0Ha 7+ORvEVhIS5gIgkH66X5W9vBRTX14oG/1elIyI6LbFZ+E5KAufL0XoWJGI1WbPRm HW246FKSzF0wOEZZyxEROz6tuaVsnXRHRE76roS/Wr064uJpKH+Lv+SjggE5MIIB NTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQU pSHN2+tTIZmqytlnQpQlsnv0wuMwHwYDVR0jBBgwFoAU0+zHOmVuzOHadppW+5zz hm1X5YEwewYIKwYBBQUHAQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5y b290Y2E0LmFtYXpvbnRydXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NydC5y b290Y2E0LmFtYXpvbnRydXN0LmNvbS9yb290Y2E0LmNlcjA/BgNVHR8EODA2MDSg MqAwhi5odHRwOi8vY3JsLnJvb3RjYTQuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTQu Y3JsMBEGA1UdIAQKMAgwBgYEVR0gADAKBggqhkjOPQQDAwNpADBmAjEA59RAOBaj uh0rT/OOTWPEv6TBnb9XEadburBaXb8SSrR8il+NdkfS9WXRAzbwrG7LAjEA3ukD 1HrQq+WXHBM5sIuViJI/Zh7MOjsc159Q+dn36PBqLRq03AXqE/lRjnv8C5nj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCA4qgAwIBAgITBn+UV0u3B10+SJZceDIkqnVP7TANBgkqhkiG9w0BAQsF ADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNj b3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4x OzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1 dGhvcml0eSAtIEcyMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB IDBBMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQChhTHcMX+WcSKio/2VJ8N0cCpdrUf4oB9V+fx2dFxU+XgRvszhgePcNKv5 d7a0qOWF9uLmYix0BP34xYujNe0TTGBjOdjCWmTLi9mb5gO8Qxe3eaPZFHX2JbA+ GeqyLkv3/Dt4SkggAZX1PvoaPlCytHCW7qDdo+ycuqwrrfl0fYfJrEA+O5x8v+uH UmC5APF5vYE8XdGhGra5JRot2TY3P+Kh1AfuJWPLBRgmmbPscv81zVdl+LzZdGFP dCnCwE9OKd4stKNkO2vTwdJykLgovcF889LQdbPfCx7UaDeHdAcJLyNcS0i5FrHD 7hNfwzfpOORF0+1wF6HdE/GBUJBJAgMBAAGjggE0MIIBMDASBgNVHRMBAf8ECDAG AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUl+rEItIGGO2FBP/cUsJu 2w4G4T8wHwYDVR0jBBgwFoAUnF8A36oB1zArOIiiuG1KnPIRkYMweAYIKwYBBQUH AQEEbDBqMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcC5yb290ZzIuYW1hem9udHJ1 c3QuY29tMDgGCCsGAQUFBzAChixodHRwOi8vY3J0LnJvb3RnMi5hbWF6b250cnVz dC5jb20vcm9vdGcyLmNlcjA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnJv b3RnMi5hbWF6b250cnVzdC5jb20vcm9vdGcyLmNybDARBgNVHSAECjAIMAYGBFUd IAAwDQYJKoZIhvcNAQELBQADggEBAK/GJ9NNlVof/45Jo9qouxV79fiyONjw5Kym nZpko27O2TQwnSN4xguhR9qPCLJFfzxpybjZK52+bpNpXbWOoZKEsXIFxShocXmx xY3jpQRDijIqyB1wEEYV/0S4J6dGtdx9xb/t1L6/53ogFPa17v+dFhJQ0WwIzfTW R/Vox5ZrJ/sgBIgylEJWsEUX0hc+QwryeGU9Ylv2XIcmANzoH2tQnHs1v8GG3FYY RZ4FeoPETzXfKd98y0l9v6lx2guQ4hNA3vCYDMF+w/2TcVW6YPVMjEkuRN2hypcY uNmaqaMA0K0ZD7nQOedXceNRfr+GruHRduh2EZI0gMxfOpwfn98= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFjCCA/6gAwIBAgIUd1lPuyJwOPtSCX5horf4hQVMT3swDQYJKoZIhvcNAQEL BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMjYx MzExMjBaFw0yNTEwMjYxMzExMjBaMFQxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRswGQYDVQQDDBJTWkFGSVIg VHJ1c3RlZCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRPDG3 TdHUJWZi/x+ncAOe378KXBAsSasFxlqzntuB2EcvzqcuEzuwgftT/JH5vAaz2V57 Q3OW3qc2CCBdIbUQkIu6Rk2Wzjb55tlw4SugjmK3eSwid3e/61P7H3ygvRrDTUfg svUP+h3JYfm31en7+lJrzanLTDmQRgmzscZ1y4LpCq0OUtzUpnpMsXnHBYcbJ2y2 3NCNbYkuoRM1Wt7eHReKMzOlMr4QAIJxVBZDxOhz/HgqVRqX7TqchnhVR2AOm+GZ Kb4CWx2R4GJBTBrxX/4/7o/nGlto9NfrUz/UvptkJ1boCBJvKAsjQlpCmjAKQYXf nb8wc7+wEi+rDMg7AgMBAAGjggHhMIIB3TAPBgNVHRMBAf8EBTADAQH/MHoGCCsG AQUFBwEBBG4wbDAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuZWxla3Ryb25pY3pu eXBvZHBpcy5wbDA6BggrBgEFBQcwAoYuaHR0cDovL2NkcC5lbGVrdHJvbmljem55 cG9kcGlzLnBsL3Jvb3RfY2EyLmNydDBmBgNVHSAEXzBdMFsGCyqEaAGG9yMBAgEB MEwwSgYIKwYBBQUHAgEWPmh0dHA6Ly93d3cuZWxla3Ryb25pY3pueXBvZHBpcy5w bC9pbmZvcm1hY2plL2Rva3VtZW50eS1pLXVtb3d5MA4GA1UdDwEB/wQEAwIBBjB2 BgNVHSMEbzBtoVWkUzBRMQswCQYDVQQGEwJQTDEoMCYGA1UECgwfS3Jham93YSBJ emJhIFJvemxpY3plbmlvd2EgUy5BLjEYMBYGA1UEAwwPU1pBRklSIFJPT1QgQ0Ey ghQ+il0H7FXSMtW347ZfAest3OTW5DA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8v Y2RwLmVsZWt0cm9uaWN6bnlwb2RwaXMucGwvcm9vdF9jYTIuY3JsMB0GA1UdDgQW BBQedbwzox9qzH7P3QU+27vafLzpRDANBgkqhkiG9w0BAQsFAAOCAQEAM2lRxreI lUtwqyOrnuCbUrffRsu5+EAXmsb6FZFo8nXlRVIQINCCEhNh/tn8HgWLdUISwb+k dkjCFdEoC5upvHqINxGAPp6wvQjV4Pmccs/H2miFgQXphw1Pc3P1JDZ3QasftuoF ITWGphhCPc8Yf3h5QeG+O8lGaZCOol8FJoucVPlQnU+wHyc+wwo2h4aYtMapd1br vIyyIG4zI+LFEY7ffaU9hlnhKir/xobW2YvCbqRePMEIxQVvkEIAFZzLdBv33NhJ 5arusk8OcI9ge17maKWWr7C+/oCXXjTWj+ODfJyTvkfHmXylyxK9ZhSU78ccJdaI PI+Mqg6IG8PRAA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwjCCBKqgAwIBAgIQU7h+g+GcmSiTsJtJHOy46zANBgkqhkiG9w0BAQsFADA3 MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9v dCBDQSB2MTAeFw0xNTEwMjcxMjE2NDZaFw0yNTEwMjcxMjE2NDZaMEcxCzAJBgNV BAYTAlNFMREwDwYDVQQKDAhFcmljc3NvbjElMCMGA1UEAwwcRXJpY3Nzb24gTkwg SW5kaXZpZHVhbCBDQSB2MzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AOzy3wAAuFDyp7vYVLfGk/fjwao71MNGNLSzzl5DtjQtMtl2ZLPZyX6ViqzTN9JO b7uZ6KxuGSpReQvt8XOh7iIhkKH9W5hRpbjTsJmUMJd6zifhOpNK6iSU3q44+Fjs QL1lVtcguUuFG6aZN0N3GFVbgt6jRrASF8t/3wy9bHPAIfMyPybpg6Y2PH5/1Nwk TepoDSmK69LGV+lV2IK6U9OWayZXZFIFIDCoGyFlhFxAEgN+qZ2+Rqg/0TM0oCHv KO2ELSGmAdnJkwizR42ji/Y9SYTSuG75mzSe6OfCGWM8Db/xvy/20aLEPXNu1PvO gzY63WZ6cmkWnjMlVJ90pWC2haqDm3Yf8TRdjUvAl7Pz1bTuexwShzIGakL7MkCY rEqHMRaojI/VStloQgW76E76zQ2byw5QxrhOUbisBSKRzlTlOZQgYFFAbG6ViF8D OpJh/ygtQwuTLUM5r15G7eynQV1AMTNCWcX+HUvgArUw6RfW9L58uA68GjktFTV8 s9RlDsUqsNcLqeXaV28S2WMday0YGaq/bloS8AD7KuumUKH+Ri9IGO9mJvP05tvD HjKpLvv80c3WLJnJU/aznYHYEt2+jjKHOTqdGTxL/zMdpRSQFSuu+KM8NoYrkU1V JqKga+QLsgqKghMp99gu1P1e6KsqseWHdXORrMbjqkBXAgMBAAGjggG4MIIBtDCB igYIKwYBBQUHAQEEfjB8MC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC50cnVzdC50 ZWxpYXNvbmVyYS5jb20wSwYIKwYBBQUHMAKGP2h0dHA6Ly9yZXBvc2l0b3J5LnRy dXN0LnRlbGlhc29uZXJhLmNvbS90ZWxpYXNvbmVyYXJvb3RjYXYxLmNlcjASBgNV HRMBAf8ECDAGAQH/AgEAMFUGA1UdIAROMEwwSgYMKwYBBAGCDwIDAQECMDowOAYI KwYBBQUHAgEWLGh0dHBzOi8vcmVwb3NpdG9yeS50cnVzdC50ZWxpYXNvbmVyYS5j b20vQ1BTMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwtMy50cnVzdC50ZWxp YXNvbmVyYS5jb20vdGVsaWFzb25lcmFyb290Y2F2MS5jcmwwHQYDVR0lBBYwFAYI KwYBBQUHAwIGCCsGAQUFBwMEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUHHsZ npecdqwgPdjc45Fq49stplMwHwYDVR0jBBgwFoAU8I9ZOACz9Y+algzV6/p7qhfo ExIwDQYJKoZIhvcNAQELBQADggIBAFBYa/HVjDu0LqtXQ8iMp8PLFpqchf41ksQY 6R1AsoZbaBUu0NQlAQ9GzlC1pmI5s0cJnuaZI0xV6TiWS3/R2p9UgW61XD9CTIUb AL31mY3BdJf3P46gzKgQEca/DlFjq9GVmuPS4q90BLNgvgoxoHubc3C6s0OaY1sb nay5EhnvrAE4Q511FlxmJPLnRmQGpieeXa3cPegFfY1kJDKyyFRypF1RuRLXcdMI gKEy5NX1bS3M9dQ4mgmUmVT2d33UiKSEYQ6s/B+LFaaz4LywXSv2o3W4kbHoQs86 IWst821ww0wxsCpEfClIvF7fBw2QkbG/1PwuzAuLVStEhDzkAqOrMGctKyNEaBsy An7Eq2eCa8QDXnkmagp9QPsNFs/oqnXj9j1cVtH9a4OPzhtg0pd7gd0NzU/5Qxib XqbYvouQgihGXHQDmaL4ruN7C4arMUqRo82YnREsKL7h3j/jtmzcMLc9Q07F04QQ d/iSR1Y5pIi6PdNBiE2/4uyAXS6KOIGZrPbNQUNrZtwiQpqQNl8AUzgegfPwrYFl FocpaF3d1m5r+2VKKqiRQVfYPGYeZnWfkcz06JoAhc/9mjbHXSP9hvWYzeLRuoZq HGUdjOX9DIQb926OneV7C5WMIjSY8ORkamG/HKqngmjypL3gSc6oG/E6B+1i6Ds5 j0Qpj5aQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDKjCCArGgAwIBAgIQBKKQ483uTcbgQukrrTp0djAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xNTExMTExMjAwMDBaFw0zMDExMTExMjAwMDBaMGwxCzAJBgNVBAYTAlVTMRUw EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x KzApBgNVBAMTIkRpZ2lDZXJ0IEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EgRzMwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAAT8d071xn0Q0LeEexGWUZnp7hUk17rmmSKq0pMA 7l756ebtDVOMySTSG1925mDc6ZX96R7M5lUcUloTN6NqQw4pSovflo7fTmSGGnIH 15mNIU3mheZ3c+hmrPJXXOPqjI6jggEhMIIBHTASBgNVHRMBAf8ECDAGAQH/AgEA MA4GA1UdDwEB/wQEAwIBhjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0 dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBCBgNVHR8EOzA5MDegNaAzhjFodHRwOi8v Y3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290RzMuY3JsMD0GA1Ud IAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy dC5jb20vQ1BTMB0GA1UdDgQWBBSZOf9fpLNZX4HAV5nRo6RHrGBjTTAfBgNVHSME GDAWgBSz20ik+aHF2K42QcwRY2liKbxLxjAKBggqhkjOPQQDAwNnADBkAjAXpd16 9v24oZon4J9Q274cuI2+Lbi4BqpizW9QthvsWaTcaINy3iYsgchoiydEeqQCMCl/ k9EL9+hQB5Ex18DrxgLJEXfMGH9KjPXSvdZLDWDRUS/ZnYmOIarXlAWRRgvqAg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGMjCCBRqgAwIBAgIDD+RMMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFkQtVFJVU1QgUm9vdCBD QSAzIDIwMTMwHhcNMTUxMTEyMTY1MjU5WhcNMjgwOTIwMDgyNTUxWjBFMQswCQYD VQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMR8wHQYDVQQDDBZVbmlwZXIg R3JvdXAgQ0EgMiAyMDE1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA 3x/rk3C8aIDKI4vPR8wiLGtn5Syx6b9xSNvkLfSvdaTcu85qgFb49bu342Npck9Z FnfCa7LmBhvCBhgrDZArZkTBoTjbBozW75jAuxsTutQ0UMr4a+6JaZgjLPXg1kP0 trvtHx7ftwn08z3MUOeczwHHYHo0whUJvyW6+0hlrYlhhPXmNs30vx9D7sGv4EZ+ PtFaRYUWHW47Em6RTpCns2oYG9+mRls41K4kmaeLKQpY67yyHXeTSvOsukMxCTwu 2SLBJXqUTDc06/crZMiys21Iw4c8hEUy/sWW4uIN0XbB29G8IDUXnmmhwjqp1kHb yr5b5fvQzgqHt1SaWADhYQIDAQABo4IDKTCCAyUwHwYDVR0jBBgwFoAUP5DIfccV b/Mkj6nDL0uiDyGyL+cwggFdBggrBgEFBQcBAQSCAU8wggFLMDIGCCsGAQUFBzAB hiZodHRwOi8vcm9vdC1jYS0zLTIwMTMub2NzcC5kLXRydXN0Lm5ldDBQBggrBgEF BQcwAoZEaHR0cDovL3BraS5pbnRyYW5ldC51bmlwZXIuZW5lcmd5L2NhY2VydHMv RC1UUlVTVF9Sb290X0NBXzNfMjAxMy5jcnQwRQYIKwYBBQUHMAKGOWh0dHA6Ly93 d3cuZC10cnVzdC5uZXQvY2dpLWJpbi9ELVRSVVNUX1Jvb3RfQ0FfM18yMDEzLmNy dDB8BggrBgEFBQcwAoZwbGRhcDovL2NkcC1sZGFwLmludHJhbmV0LnVuaXBlci5l bmVyZ3kvY249RC1UUlVTVCUyMFJvb3QlMjBDQSUyMDMlMjAyMDEzLG91PWNhLG89 dW5pcGVyLGM9ZGU/Y0FDZXJ0aWZpY2F0ZT9iYXNlPzBEBgNVHSAEPTA7MDkGCysG AQQBpTQCgVQBMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly93d3cudW5pcGVyLmVuZXJn eS9wa2kwggEZBgNVHR8EggEQMIIBDDBHoEWgQ4ZBaHR0cDovL3BraS5pbnRyYW5l dC51bmlwZXIuZW5lcmd5L2NybHMvRC1UUlVTVF9Sb290X0NBXzNfMjAxMy5jcmww O6A5oDeGNWh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9j YV8zXzIwMTMuY3JsMIGDoIGAoH6GfGxkYXA6Ly9jZHAtbGRhcC5pbnRyYW5ldC51 bmlwZXIuZW5lcmd5L2NuPUQtVFJVU1QlMjBSb290JTIwQ0ElMjAzJTIwMjAxMyxv dT1jYSxvPXVuaXBlcixjPWRlP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFz ZT8wHQYDVR0OBBYEFBmN32A20Az5vkfbwLupgOyKBw+QMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBNbcutvBX3SW1O o2HT/RcxmsOoDSnCcn6nX2jrC3aGBYNX1lThK7p9mXcx7e3Vugnu3RJS0YHk2hvI 1OA3PcyAzRELS4dtAPIvCLnvNd09ml7NcTaI1fcf6QpvF9eFOsWdbEF7dN8wH92a IT5IwLCd+J6b7C8TdCovdKwtq0mkUwRBex26riMOUdqBPD611JOdQx8ca1pHFRKa G8GJdv0vbVrPaEDp4UJNF9/HdG9CIw/nFAS2Sro13BoHGk85RpZttlaTTQm6fCUD OdBRgZDOnQqLbQb7uq2RA8jOUY6aJ+POgOAwEXnnhOHZ0+tzUPOmL1uP6JEB+ptS gk1sj7jy -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGUDCCBTigAwIBAgIDFppbMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFlVuaXBlciBHcm91cCBD QSAyIDIwMTUwHhcNMTUxMTEyMTc0NjM3WhcNMjgwOTIwMDgyNTUxWjBYMQswCQYD VQQGEwJERTEcMBoGA1UECgwTVW5pcGVyIEhvbGRpbmcgR21iSDELMAkGA1UECwwC Q0ExHjAcBgNVBAMMFVVuaXBlciBDQSAyIDIwMTUgWFhYSTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBANM/pdg3q0vc1ZLhLW4rNX15rBnM+O6XNPmYBDBc eIZ/7X2+eJU1Rj2RK1PI8/NHlmj4Pjr5m3fFQI1vO9y6btGIjxSqY7a1NBU0xLGM 1Kzkc+tEtS8oUAWNX6odk1EeaRY/QlLhW3HgX3ocv/JjPUh2Cm/VflWRmrqnK0yc qZbvEr0uQhHHMRBgopeBKiqMPgleJ2apY9tGZIU47Y8uI3Nwx283Gvo2ux6AJHJl WnOiqEM8UxZs17/C9ARagnDXa+rPRIGFncrCqqYLufMsUCY+4079xjBEUdDtmCJP +hPLGvd9vKBVEydkdwdG+xCtFXGYAr3L1to+tHnf3INXhMkCAwEAAaOCAzQwggMw MB8GA1UdIwQYMBaAFBmN32A20Az5vkfbwLupgOyKBw+QMIIBZQYIKwYBBQUHAQEE ggFXMIIBUzA6BggrBgEFBQcwAYYuaHR0cDovL3VuaXBlci1ncm91cC1jYS0yLTIw MTUub2NzcC5kLXRydXN0Lm5ldDBQBggrBgEFBQcwAoZEaHR0cDovL3BraS5pbnRy YW5ldC51bmlwZXIuZW5lcmd5L2NhY2VydHMvVW5pcGVyX0dyb3VwX0NBXzJfMjAx NS5jcnQwRQYIKwYBBQUHMAKGOWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY2dpLWJp bi9VbmlwZXJfR3JvdXBfQ0FfMl8yMDE1LmNydDB8BggrBgEFBQcwAoZwbGRhcDov L2NkcC1sZGFwLmludHJhbmV0LnVuaXBlci5lbmVyZ3kvY249VW5pcGVyJTIwR3Jv dXAlMjBDQSUyMDIlMjAyMDE1LG91PWNhLG89dW5pcGVyLGM9ZGU/Y0FDZXJ0aWZp Y2F0ZT9iYXNlPzBEBgNVHSAEPTA7MDkGCysGAQQBpTQCgVQBMCowKAYIKwYBBQUH AgEWHGh0dHA6Ly93d3cudW5pcGVyLmVuZXJneS9wa2kwggEZBgNVHR8EggEQMIIB DDBHoEWgQ4ZBaHR0cDovL3BraS5pbnRyYW5ldC51bmlwZXIuZW5lcmd5L2NybHMv VW5pcGVyX0dyb3VwX0NBXzJfMjAxNS5jcmwwO6A5oDeGNWh0dHA6Ly9jcmwuZC10 cnVzdC5uZXQvY3JsL3VuaXBlcl9ncm91cF9jYV8yXzIwMTUuY3JsMIGDoIGAoH6G fGxkYXA6Ly9jZHAtbGRhcC5pbnRyYW5ldC51bmlwZXIuZW5lcmd5L2NuPVVuaXBl ciUyMEdyb3VwJTIwQ0ElMjAyJTIwMjAxNSxvdT1jYSxvPXVuaXBlcixjPWRlP2Nl cnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT8wHQYDVR0OBBYEFNjDBA5VlnVj TCAOlF8sGtRDJzYDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MA0GCSqGSIb3DQEBCwUAA4IBAQC98WbK/MkD67Nn+pFimzS8TrY/8tNQduCBrJa5 lPCy5E7v9Iuw/0BFMLuTPpJwQIhy/98sHqF/iwWcG5jL+SLouKowQyVRZA3+JKiL 0xH7eSuf1FFcOr9j30R/GpmLIAiF8ZFXEAo+mSGG6cYysSL4EFDJAaJ3e8IG/hrK 7ck2a+5Cku4+xPY+vLBTHvBNojrohJp+/kv6Q0FbXgScsjvBldJzcwJO1JTKSK+v zcalE0zhdpVnwWkY8br/kWqJEcKCInxyxGyQT8C1osVSwzuE8nKemBFzDQh4HTuM gQ4XH/L2km5wPw4kxrkhdzJj1OiDrKusJiUOiVwJ+hpehxBG -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGUTCCBTmgAwIBAgIDFppfMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFlVuaXBlciBHcm91cCBD QSAyIDIwMTUwHhcNMTUxMTEyMTc1NjM3WhcNMjgwOTIwMDgyNTUxWjBZMQswCQYD VQQGEwJERTEcMBoGA1UECgwTVW5pcGVyIEhvbGRpbmcgR21iSDELMAkGA1UECwwC Q0ExHzAdBgNVBAMMFlVuaXBlciBDQSAyIDIwMTUgWFhYSUkwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDMaS2j5UDOxX1uDOVb/1MBRTRl5tbmanlq8H3B /rNoapTxUKNaTrN+sxVQN7tsyo1g4c3C7215X1jy6IJxB9R4ckLDobNI2UeplXp5 S3K7RUB7CtG0EzsqzZe2uGchRZ4wr+c3nzALvX24KHIqMI8Ji+quB1kzov9DZgAT uOqcEsXHNJc4QMSp4eQzaiVjSBot1228x8y9nswAIm74QYq66Hsr0VkUyK95uL1n 1PjRRxa8nvQ3W2Gx/r4msKuwKQ3I7EuMLsynbDTBkyOqrTXjG2xU3lDeMdg6Lgly pP6u3kyhqbzo3/x4L2kZKKbzQM6LRkiTK0DBiISXMIpZOr4pAgMBAAGjggM0MIID MDAfBgNVHSMEGDAWgBQZjd9gNtAM+b5H28C7qYDsigcPkDCCAWUGCCsGAQUFBwEB BIIBVzCCAVMwOgYIKwYBBQUHMAGGLmh0dHA6Ly91bmlwZXItZ3JvdXAtY2EtMi0y MDE1Lm9jc3AuZC10cnVzdC5uZXQwUAYIKwYBBQUHMAKGRGh0dHA6Ly9wa2kuaW50 cmFuZXQudW5pcGVyLmVuZXJneS9jYWNlcnRzL1VuaXBlcl9Hcm91cF9DQV8yXzIw MTUuY3J0MEUGCCsGAQUFBzAChjlodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NnaS1i aW4vVW5pcGVyX0dyb3VwX0NBXzJfMjAxNS5jcnQwfAYIKwYBBQUHMAKGcGxkYXA6 Ly9jZHAtbGRhcC5pbnRyYW5ldC51bmlwZXIuZW5lcmd5L2NuPVVuaXBlciUyMEdy b3VwJTIwQ0ElMjAyJTIwMjAxNSxvdT1jYSxvPXVuaXBlcixjPWRlP2NBQ2VydGlm aWNhdGU/YmFzZT8wRAYDVR0gBD0wOzA5BgsrBgEEAaU0AoFUATAqMCgGCCsGAQUF BwIBFhxodHRwOi8vd3d3LnVuaXBlci5lbmVyZ3kvcGtpMIIBGQYDVR0fBIIBEDCC AQwwR6BFoEOGQWh0dHA6Ly9wa2kuaW50cmFuZXQudW5pcGVyLmVuZXJneS9jcmxz L1VuaXBlcl9Hcm91cF9DQV8yXzIwMTUuY3JsMDugOaA3hjVodHRwOi8vY3JsLmQt dHJ1c3QubmV0L2NybC91bmlwZXJfZ3JvdXBfY2FfMl8yMDE1LmNybDCBg6CBgKB+ hnxsZGFwOi8vY2RwLWxkYXAuaW50cmFuZXQudW5pcGVyLmVuZXJneS9jbj1Vbmlw ZXIlMjBHcm91cCUyMENBJTIwMiUyMDIwMTUsb3U9Y2Esbz11bmlwZXIsYz1kZT9j ZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/MB0GA1UdDgQWBBQL8w02B7li MhAwqXZThnZga0N4TDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB ADANBgkqhkiG9w0BAQsFAAOCAQEAaQOxk1UmKg5Zl2J1czo8zWxPNly1w9pyOlOA Kvz0Y74TkaXYi5CF6mW+YdiPyLDopXo5W/1MSa7C4MbPuR9yjW0w9j9E4zi5R13M Urxi7Qx2mo11JzP6UPDUdvm3Wadd6jUgmg8rbDPfXE3ZofuI63c60W2lpjuf+Oon fWeh2hfdErDUPt/iUgaHfezB5VriJ38F76vcJnx1a+7RrV4jnZnprrG/gY60dOBt jzxoXENzmeLF9yP4siMTJ/Ow6m3CoMWLS8i4dxkFMA6YUiTyT1GSMD6tW3taoThM dC+WlqX4IlEzkJZlq7E3PqIfv4VswSKMzmUIWLwKqvP0+WXgZw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGUjCCBTqgAwIBAgIDFppgMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFlVuaXBlciBHcm91cCBD QSAyIDIwMTUwHhcNMTUxMTEyMTgwOTUwWhcNMjgwOTIwMDgyNTUxWjBaMQswCQYD VQQGEwJERTEcMBoGA1UECgwTVW5pcGVyIEhvbGRpbmcgR21iSDELMAkGA1UECwwC Q0ExIDAeBgNVBAMMF1VuaXBlciBDQSAyIDIwMTUgWFhYSUlJMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAraOZsN9tejelVAXchoAtODelndVWV5kl5rJV RhFJOORamd5kK3VoinCitp3OCy1uoboLtF5s4L31UOb6b3cVCsS5nhy7Y/ApHO2N o6En4GlVFhpKel1A3N9znM0MyCmtzYY0bZgUSCXd3ajJfRJrX0QzHhhLqLZVTNZ8 s5zU047m4zYoYi6M/ZVWxph1j9XB6rexSKaHBjzpMk1Tk+WJacpucpgQrMsewxlR /9Fvoh+ZImnKKN4l0vilR87cKMLbUb66uf6YPsAv0ZFfMkZE2iaPd8WCmbD7rSho pr68Nywa0/yKhYnacPcDqgbo5s+RkR46lFASIznw4A3GRFnFfQIDAQABo4IDNDCC AzAwHwYDVR0jBBgwFoAUGY3fYDbQDPm+R9vAu6mA7IoHD5AwggFlBggrBgEFBQcB AQSCAVcwggFTMDoGCCsGAQUFBzABhi5odHRwOi8vdW5pcGVyLWdyb3VwLWNhLTIt MjAxNS5vY3NwLmQtdHJ1c3QubmV0MFAGCCsGAQUFBzAChkRodHRwOi8vcGtpLmlu dHJhbmV0LnVuaXBlci5lbmVyZ3kvY2FjZXJ0cy9VbmlwZXJfR3JvdXBfQ0FfMl8y MDE1LmNydDBFBggrBgEFBQcwAoY5aHR0cDovL3d3dy5kLXRydXN0Lm5ldC9jZ2kt YmluL1VuaXBlcl9Hcm91cF9DQV8yXzIwMTUuY3J0MHwGCCsGAQUFBzAChnBsZGFw Oi8vY2RwLWxkYXAuaW50cmFuZXQudW5pcGVyLmVuZXJneS9jbj1VbmlwZXIlMjBH cm91cCUyMENBJTIwMiUyMDIwMTUsb3U9Y2Esbz11bmlwZXIsYz1kZT9jQUNlcnRp ZmljYXRlP2Jhc2U/MEQGA1UdIAQ9MDswOQYLKwYBBAGlNAKBVAEwKjAoBggrBgEF BQcCARYcaHR0cDovL3d3dy51bmlwZXIuZW5lcmd5L3BraTCCARkGA1UdHwSCARAw ggEMMEegRaBDhkFodHRwOi8vcGtpLmludHJhbmV0LnVuaXBlci5lbmVyZ3kvY3Js cy9VbmlwZXJfR3JvdXBfQ0FfMl8yMDE1LmNybDA7oDmgN4Y1aHR0cDovL2NybC5k LXRydXN0Lm5ldC9jcmwvdW5pcGVyX2dyb3VwX2NhXzJfMjAxNS5jcmwwgYOggYCg foZ8bGRhcDovL2NkcC1sZGFwLmludHJhbmV0LnVuaXBlci5lbmVyZ3kvY249VW5p cGVyJTIwR3JvdXAlMjBDQSUyMDIlMjAyMDE1LG91PWNhLG89dW5pcGVyLGM9ZGU/ Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlPzAdBgNVHQ4EFgQU+af6WbQn kHY0LSPsrZCoE0qgowowDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwDQYJKoZIhvcNAQELBQADggEBAJCh5Cq7BMoZlQejtrFZUGL2yrktA50IMAwU G9Toks/nxw0p1rCltQMpyAKB5/CVXdobzgRtzcIYHqjugCd4A0GfEuPBgYsdHyJ4 nyFtUEss/ZwgzK6njIRIEoid/QF0geQjWiWF/V6bEtt3yfkDoqHQ5i5rgLx7FTbO he2y095dyv1yv+hI6ro1AVeMbUMHtrqSY5F15ydZdPqTvrsfkEWd8QPIrhyECItO fEoIXppf8vB10x3mNeBW4L+KFVPATupuTQarDILbbpVObH8RtXk6nis3+G1yDn5i nNKFefD+IxxpmvL+aPWgT+IpfdSnWTsviER93t9Z+XTtKie9vSs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHNTCCBR2gAwIBAgIQBVQjPBnG8p6lFfhbaJfb7DANBgkqhkiG9w0BAQsFADBj MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xLzAtBgNVBAMMJmVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt IEcyMB4XDTE1MTExNzA4MzE0MVoXDTM0MTIyMDAyMzEyN1owXjELMAkGA1UEBhMC VFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBMdGQuMSowKAYDVQQL DCFlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQDhJQ/ujduIM3Vnza0ffTpObZ3TLxTzY3TLASFq N+qEUAdLJlsJQ2whnmrI1QP1YGmPzPAi5B/n92oiMbcsFfLg/gBqQ/+HZca1GsGn TG0icCGKMfKXdIkJEiYcnsrZEqKVPNrpZ78IoGTj1kK3Re+X9Pb117VKFQJYfZhY S2C8zdcNmhMzU9Fh+XrV13izmjP3AIbOHU2UOK+o7HhRcIpcEINRIfcRPTSGXuVI zZeBgjVMGexl9mvFBaHuRxPWsyEnlBAK2SQ7ur5EE0YwP5c82NfXau47OOMr1JcO uRvnB0l/Nyr5d3jPVO1bRp2jgA6RQ8HWW18Uup+mjSRHQFm/cjiyNmw3/5nRXQ5Z Cqtp98CyBEV6VACuvlP2tefh+DyjMdKp/iFSZMWmZ/B1BwaUFIFVxifkAY8XwWpx 175L+5RYfX4RM7FC92JsGNbPCWg+f2z2Ho9iraVj2wmnHyJCQR5vmYo+1/k/QHp5 sKUBktKdPQgVpRABLbMydqiVDbN6mvsHEHgRb+GPx7oPJRp0KuUcmEGZ3yGH6JUG agqzakd2ZfY6z49iFxl7CijNGtKDHiHHLL++/2Fot2cbu3hNjc5n5eTBjrcjZuKd kHU0mKk2K4qalLmd7MyKsfgliVxati+MH215JKdSaMOENeJmjWMOJU3VGbLmeTen Ip1UMQIDAQABo4IB6DCCAeQwHwYDVR0jBBgwFoAUclu6qnI47iWQJLWUIvoJiMqL CvswHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMA4GA1UdDwEB/wQEAwIB BjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vZWNhLmhpbmV0Lm5ldC9yZXBvc2l0 b3J5L0NSTDIvQ0EuY3JsMIGLBggrBgEFBQcBAQR/MH0wRAYIKwYBBQUHMAKGOGh0 dHA6Ly9lY2EuaGluZXQubmV0L3JlcG9zaXRvcnkvQ2VydHMvSXNzdWVkVG9UaGlz Q0EucDdiMDUGCCsGAQUFBzABhilodHRwOi8vb2NzcC5lY2EuaGluZXQubmV0L09D U1Avb2NzcEcyc2hhMjAPBgNVHRMBAf8EBTADAQH/MIG0BgNVHSAEgawwgakwDQYL KwYBBAGBtyNkAAEwDQYLKwYBBAGBtyNkAAIwDQYLKwYBBAGBtyNkAAMwDQYLKwYB BAGBtyNkAAQwDQYLKwYBBAGBtyNkAAAwCQYHYIZ2AWQAATAJBgdghnYBZAACMAkG B2CGdgFkAAMwCQYHYIZ2AWQABDAJBgdghnYBZAAAMAgGBmeBDAECATAIBgZngQwB AgIwCAYGZ4EMAQIDMAcGBWeBDAEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFQwADfZ99 HtG9yxM4ll7ky9eZOoLuH+IpuC/F1trdc5oWCR087nOHPkDNRlbQbkZljYTg7qG3 5LgtugFBXc0LPuwAPlKDngdRJguL9vfMDSnisW7JXFsv3ArG5zeyVn+vqK1+cqPa Pd/LdfpL0YFTWHEXyPnOUm7x97Dy9wU9dtE/h1G6L2AQmIkYK+fpIeXEN7uz4vio pcPvxEykO8QkAR74vLrLj87lKJABY6BvRbzkR+mFTvC1u1DOKeyUdSWYnOgVgcpV RXE5IyleB35EcyYSBLw6PAyV9+E4G6Gl3p8AQtD1QpIvMuKKLWqNHIF7fISv3VSj 829LyyqRvPTwBywgYXMYOM2OmiGZYbooBDDsxOefyEPVKfw4vk84JQOoyKV/LtSJ 4KAv1WFWefdoAfSzfK9EgH7q0f4+H0xx1lv4y47gyXyxVBIt0FdXrgsUs0MdCLTe CfB7BIWbofJ6241+ugEa0/JtJM1tUjIL0BeTAws+WFBIr46SeXPitJgQUfvVp7zA 5Pgjmb8robprTMIAv1Hmlz4krE77hydE/APsZGH68gq/n//2CxHrj9qhADleYjNA oZEmf1C9NsaEya7pUzBUwcf/BQidnnAxz+pODwNBUIKC+cwPF+8uFx82AMujEfWz 6WQ3FGbvbR5swAxI2gqIrtbfAmVRxMFvCw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHdTCCBV2gAwIBAgIRAMrh9z78rFuxnIjBxy9vey8wDQYJKoZIhvcNAQELBQAw YzELMAkGA1UEBhMCVFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBM dGQuMS8wLQYDVQQDDCZlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMjAeFw0xNTExMTcwODMxNDFaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYT AlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UE CwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEh ajfqhFAHSyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrB p0xtInAhijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2Y WEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7l SM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SX Drkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fq cde+S/uUWH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6 ebClAZLSnT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iV BmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2bi nZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3 pyKdVDECAwEAAaOCAicwggIjMB8GA1UdIwQYMBaAFHJbuqpyOO4lkCS1lCL6CYjK iwr7MB0GA1UdDgQWBBQeDPe2Z/LhkiYJRcBVOS53P0JKojAOBgNVHQ8BAf8EBAMC AQYwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3Np dG9yeS9DUkwyL0NBLmNybDCBiwYIKwYBBQUHAQEEfzB9MEQGCCsGAQUFBzAChjho dHRwOi8vZWNhLmhpbmV0Lm5ldC9yZXBvc2l0b3J5L0NlcnRzL0lzc3VlZFRvVGhp c0NBLnA3YjA1BggrBgEFBQcwAYYpaHR0cDovL29jc3AuZWNhLmhpbmV0Lm5ldC9P Q1NQL29jc3BHMnNoYTIwDwYDVR0TAQH/BAUwAwEB/zCB8wYDVR0gBIHrMIHoMA0G CysGAQQBgbcjZAABMA0GCysGAQQBgbcjZAACMA0GCysGAQQBgbcjZAADMA0GCysG AQQBgbcjZAAEMA0GCysGAQQBgbcjZAAJMA0GCysGAQQBgbcjZAAAMAkGB2CGdgFk AAEwCQYHYIZ2AWQAAjAJBgdghnYBZAADMAkGB2CGdgFkAAQwCQYHYIZ2AWQAADAI BgZngQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzA3BgVngQwBATAuMCwGCCsGAQUF BwIBFiBodHRwczovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeTANBgkqhkiG9w0B AQsFAAOCAgEAbvb5/9P544BlP4nZKjoQ/tzh5CZ/WUg+JAQgMblhtRa1Zmhpl2HD R1rzt/jRjxOhZMqtO1ogNI6KvESAt0pBBMZv9CTBvZv47p4HnuLxCxgFBk1s73vo uFc13OfAeV3EVAdzSrCZLfJHHfnuvPExW4SlmEzKp3seetbjH4DUSO6ZlwKUCTme p4DzbP82kDnwC7igowL0w+PKZYGiNvyjZr6/V1HLOn6Z6eBqVUeIgoJRxe49PbLc FFKXQdoMzAeElONPUpkv7/AX7CxflnbMWNwOCFrcT6pF3kLErgz8cA0PkW6gObjU zYs9Uk4dGI8AU4DSvamYe6abqPEBDjFec2EbycftofsqfGNF9T8HAZDAT7HnvKnT lRnQU66+IJo4Hw9LNjP/NwH+ZZJaRmyE870f+Lp+I6r/aS3yDARIqK6ZVrXh9VU4 wWNoLRWpvuUIFbVpXl8cNTHgp7QEq6oUTgCDwy9LrinBiV44PGtEHC/2U1zrbuwk uIRo3Dgf+lMYOLbTAYiWm807/P0kJ/fzBO+/0cReN1n1blmMrl1WFJaPRehqL1YU 2BAcJ3TM+E5yQJzQqHPXywTHPnRJO7Nn4iJmR3bSeW1w5GhVdeP69+IO0CM0Au1c U9jG7d32NlY1QTMUJo22nmCCAEJKAEomOyJJ+l7BFmnnYG/UQUWuKGs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHZDCCBUygAwIBAgIRAK/NjWQsYtZFBn3IV/2o8V0wDQYJKoZIhvcNAQELBQAw XjELMAkGA1UEBhMCVFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBM dGQuMSowKAYDVQQLDCFlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw HhcNMTUxMTE3MDg1MTM1WhcNMzQxMjIwMDIzMTI3WjBjMQswCQYDVQQGEwJUVzEj MCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xLzAtBgNVBAMMJmVQ S0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEApFkfoC/fvuD76dy1if5alwPJOnenjlyv8uMY OfWq3Q9G0mgPV5ynY2DTWM41wqf2iMJPfxso6dCnAMQXTW3iD8UOJiMgq/c6KKJM CgvMjs7mAJpaQA3UUBqb0Q2clPnb7lzQ8YoHzZorQCxJpF1iX6dr3+5WCFDzQhhs MbBe5ZxzkrwO0gx9xThXvLtY2yYZAu3jQ4SKTlZr262hMdnMImeWeP93ncxkxTIg au9OMNUkJf2Iea9xGv7VSxsViLwYcKq9rTgKZjBG5YmF1XYkqamz5llgD7SpU8I6 nUUa1q7jd17EYjYzLzDEv5XxLTildejRapMuRYdLSqLfv1gnmspiGape1LGASZbd K+xfj5vgnZeI9YQDo6+zpXMtQbrlB7dva3H398lar2mZsy/IT0LrbGtxZ3jfCqxP 10qFAEYa1c24n+qVnQ980cYFheYI3ogXgfbVtW7qoRzXYarjWUKJnFl+sXxkNN1h Iyo5tRCr/IapUxrF62rigE5ZkcA4if6zXdb7kenXsH3ZeAjM9SvMK+Gh1pRzwf5R 9Ix9CrWairn12uDJs9iPqoKDjWlTLf0ABBhKoNpU4XmMiet/9YLnoLl3Ta75ugI7 iHbrfF2zWhPbfCkWa5nRHeRIIaINXgGI6L7xmE0+xxZXHF/hCG8cTFhDVveAZYxx DqIEZ08CAwEAAaOCAhYwggISMB8GA1UdIwQYMBaAFB4M97Zn8uGSJglFwFU5Lnc/ QkqiMB0GA1UdDgQWBBRyW7qqcjjuJZAktZQi+gmIyosK+zAOBgNVHQ8BAf8EBAMC AQYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3Np dG9yeS9DUkxfU0hBMi9DQS5jcmwwgYIGCCsGAQUFBwEBBHYwdDA7BggrBgEFBQcw AoYvaHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeS9DZXJ0cy9lQ0FHMS5j cnQwNQYIKwYBBQUHMAGGKWh0dHA6Ly9vY3NwLmVjYS5oaW5ldC5uZXQvT0NTUC9v Y3NwRzFzaGEyMA8GA1UdEwEB/wQFMAMBAf8wgecGA1UdIASB3zCB3DANBgsrBgEE AYG3I2QAATANBgsrBgEEAYG3I2QAAjANBgsrBgEEAYG3I2QAAzANBgsrBgEEAYG3 I2QABDANBgsrBgEEAYG3I2QACTANBgsrBgEEAYG3I2QAADANBgsrBgEEAYG3I2QE ATANBgsrBgEEAYG3I2QEAjANBgsrBgEEAYG3I2QEAzAJBgdghnYBZAABMAkGB2CG dgFkAAIwCQYHYIZ2AWQAAzAJBgdghnYBZAAEMAkGB2CGdgFkAAAwCAYGZ4EMAQIB MAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggIBALwy4mxatKA6 X+UM2IDpnWajNmek00EM4qh5E7eiQY0yZV5Eit9D/8q9h0hD77NjVaYPwsOWqWAi VtDAro+nWDHfkAG14ptRNBoGjJjzZi/+OeI2WTc8ZER6C8rAjQ7b/RxMzwxfDjRt gCbT2qq01rPiJ+qDgyUniDstbyQj08bSo3GJWp6ZsSNDAP26ygODpSgL0Ja806By k2b4npQevdkmQ0k43S9IU0MeSlWT8hxzluyFlPRl4yuev5le91outdEdpV98KvYc gLAWwW5UcFOM6SRsYTBS2dfSRgKreDnMNdbUHmbAVsb3wLD6WqLoe6LyRNOeXctK PA6+e5i/JN6NZnqejcMopuS+pyWyrNiHlRShGUfTiXrcbT8fbyOswAT8JsX4fWyZ Yub0kKfFG8hEKQsIxNiyKH4cw6HBih31EYaYS9IEj19NxfHl0KbPm22cpBJoGwkZ Wgg//PflFFHNTdKSalDxPHMKdyZbTBugLtqFVkV+vu1y6WRoGfHwzpa9aQsMWAwL YRnBZnSYzfN9QFZsoHCSDJJVt30Oi6fURJy34+dtvs+sQihiN886uYTJ0Cex1R+O b9HXCKFrGTumgwD+nitt7hwlB74K9lqrKQrtfgfBFFMG9Tu/E/OI6JoST2j8KmSN 1rpcxoMH3tamxqm3+xpLM9HekbBoJ0V2 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHOTCCBSGgAwIBAgIQCFE9WpEE7UIP80unUKjpiDANBgkqhkiG9w0BAQsFADBe MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0xNTExMTcwODUxMzVaFw0zNDEyMjAwMjMxMjdaMGMxCzAJBgNVBAYTAlRXMSMw IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEvMC0GA1UEAwwmZVBL SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQCkWR+gL9++4Pvp3LWJ/lqXA8k6d6eOXK/y4xg5 9ardD0bSaA9XnKdjYNNYzjXCp/aIwk9/Gyjp0KcAxBdNbeIPxQ4mIyCr9zoookwK C8yOzuYAmlpADdRQGpvRDZyU+dvuXNDxigfNmitALEmkXWJfp2vf7lYIUPNCGGwx sF7lnHOSvA7SDH3FOFe8u1jbJhkC7eNDhIpOVmvbraEx2cwiZ5Z4/3edzGTFMiBq 704w1SQl/Yh5r3Ea/tVLGxWIvBhwqr2tOApmMEbliYXVdiSpqbPmWWAPtKlTwjqd RRrWruN3XsRiNjMvMMS/lfEtOKV16NFqky5Fh0tKot+/WCeaymIZql7UsYBJlt0r 7F+Pm+Cdl4j1hAOjr7Olcy1BuuUHt29rcff3yVqvaZmzL8hPQutsa3FneN8KrE/X SoUARhrVzbif6pWdD3zRxgWF5gjeiBeB9tW1buqhHNdhquNZQomcWX6xfGQ03WEj Kjm1EKv8hqlTGsXrauKATlmRwDiJ/rNd1vuR6dewfdl4CMz1K8wr4aHWlHPB/lH0 jH0KtZqKufXa4Mmz2I+qgoONaVMt/QAEGEqg2lTheYyJ63/1gueguXdNrvm6AjuI dut8XbNaE9t8KRZrmdEd5Eghog1eAYjovvGYTT7HFlccX+EIbxxMWENW94BljHEO ogRnTwIDAQABo4IB7DCCAegwHwYDVR0jBBgwFoAUHgz3tmfy4ZImCUXAVTkudz9C SqIwHQYDVR0OBBYEFHJbuqpyOO4lkCS1lCL6CYjKiwr7MA4GA1UdDwEB/wQEAwIB BjBABgNVHR8EOTA3MDWgM6Axhi9odHRwOi8vZWNhLmhpbmV0Lm5ldC9yZXBvc2l0 b3J5L0NSTF9TSEEyL0NBLmNybDCBiwYIKwYBBQUHAQEEfzB9MEQGCCsGAQUFBzAC hjhodHRwOi8vZWNhLmhpbmV0Lm5ldC9yZXBvc2l0b3J5L0NlcnRzL0lzc3VlZFRv VGhpc0NBLnA3YjA1BggrBgEFBQcwAYYpaHR0cDovL29jc3AuZWNhLmhpbmV0Lm5l dC9PQ1NQL29jc3BHMXNoYTIwDwYDVR0TAQH/BAUwAwEB/zCBtAYDVR0gBIGsMIGp MA0GCysGAQQBgbcjZAABMA0GCysGAQQBgbcjZAACMA0GCysGAQQBgbcjZAADMA0G CysGAQQBgbcjZAAEMA0GCysGAQQBgbcjZAAAMAkGB2CGdgFkAAEwCQYHYIZ2AWQA AjAJBgdghnYBZAADMAkGB2CGdgFkAAQwCQYHYIZ2AWQAADAIBgZngQwBAgEwCAYG Z4EMAQICMAgGBmeBDAECAzAHBgVngQwBATANBgkqhkiG9w0BAQsFAAOCAgEAkSUX zwsdegsqsfgqXDSr0MQVv4MtQs5Nydg/NQ+Ed6bQvpdtSNkCtpGq+WsewlSDmt+K 3cpCgX11V5M8j920etgfjQOxl2Q0a7sQXcBQo+15JFnxQF3DYqcpOWwy+deUIYPn 7MlOeMbtnR76F0DJTOKTqKNHUK+F0ZV1Ezi87/qW47OcZzDmP0X+DYxEXUNzCU1v 91vTB5xOd6fXYQ9bfGuBLOcJhMqJfrp4c8LHFaO52ifBeLeIj8CzhT+xOqRV1au7 1sZ16NMQqrdHC39c6kt6wHzHTt8simwdrjtxskLud55TwmHuDw9VJpABqkF7Kg/S DMbtobxp1QJsRM1TDXqDEelGJtEKsKp6tjc5qny4NcdF4CDO3P+C75T4jsFCx66a 6AUNKQlsVhf4osvXuGyRi0uaYAXFZuKnwWv0rqyW5RPHhxn+D/aeETrbGEVkGxaD zcttfNluK/P05jWFjZQLzU/+tNpki2RsfIArCpG9q1A4jWgO9PNDLn4m8aZkEyIf 0Tqo2WWCKfEHFAJnrMHB0+Ky0PaE7SYnQJFndYSJKc0//+Nhh4YpgvXrZmUxvqd1 dq5yguGVIaAq9MOID9n8nRwEmipyPSK42UsnINbsrTALYD8mrMBCRP2cpJSCnqm8 mzE0NJn8kYXnqgYoQxzOZZCkt2mbh/HjzvrwcVY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHeDCCBWCgAwIBAgIQO+7gkY6Ihq1GD+iukQycujANBgkqhkiG9w0BAQsFADBe MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0xNTExMTcwODUxMzVaFw0zNDEyMjAwMjMxMjdaMGMxCzAJBgNVBAYTAlRXMSMw IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEvMC0GA1UEAwwmZVBL SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQCkWR+gL9++4Pvp3LWJ/lqXA8k6d6eOXK/y4xg5 9ardD0bSaA9XnKdjYNNYzjXCp/aIwk9/Gyjp0KcAxBdNbeIPxQ4mIyCr9zoookwK C8yOzuYAmlpADdRQGpvRDZyU+dvuXNDxigfNmitALEmkXWJfp2vf7lYIUPNCGGwx sF7lnHOSvA7SDH3FOFe8u1jbJhkC7eNDhIpOVmvbraEx2cwiZ5Z4/3edzGTFMiBq 704w1SQl/Yh5r3Ea/tVLGxWIvBhwqr2tOApmMEbliYXVdiSpqbPmWWAPtKlTwjqd RRrWruN3XsRiNjMvMMS/lfEtOKV16NFqky5Fh0tKot+/WCeaymIZql7UsYBJlt0r 7F+Pm+Cdl4j1hAOjr7Olcy1BuuUHt29rcff3yVqvaZmzL8hPQutsa3FneN8KrE/X SoUARhrVzbif6pWdD3zRxgWF5gjeiBeB9tW1buqhHNdhquNZQomcWX6xfGQ03WEj Kjm1EKv8hqlTGsXrauKATlmRwDiJ/rNd1vuR6dewfdl4CMz1K8wr4aHWlHPB/lH0 jH0KtZqKufXa4Mmz2I+qgoONaVMt/QAEGEqg2lTheYyJ63/1gueguXdNrvm6AjuI dut8XbNaE9t8KRZrmdEd5Eghog1eAYjovvGYTT7HFlccX+EIbxxMWENW94BljHEO ogRnTwIDAQABo4ICKzCCAicwHwYDVR0jBBgwFoAUHgz3tmfy4ZImCUXAVTkudz9C SqIwHQYDVR0OBBYEFHJbuqpyOO4lkCS1lCL6CYjKiwr7MA4GA1UdDwEB/wQEAwIB BjBABgNVHR8EOTA3MDWgM6Axhi9odHRwOi8vZWNhLmhpbmV0Lm5ldC9yZXBvc2l0 b3J5L0NSTF9TSEEyL0NBLmNybDCBiwYIKwYBBQUHAQEEfzB9MEQGCCsGAQUFBzAC hjhodHRwOi8vZWNhLmhpbmV0Lm5ldC9yZXBvc2l0b3J5L0NlcnRzL0lzc3VlZFRv VGhpc0NBLnA3YjA1BggrBgEFBQcwAYYpaHR0cDovL29jc3AuZWNhLmhpbmV0Lm5l dC9PQ1NQL29jc3BHMXNoYTIwDwYDVR0TAQH/BAUwAwEB/zCB8wYDVR0gBIHrMIHo MA0GCysGAQQBgbcjZAABMA0GCysGAQQBgbcjZAACMA0GCysGAQQBgbcjZAADMA0G CysGAQQBgbcjZAAEMA0GCysGAQQBgbcjZAAJMA0GCysGAQQBgbcjZAAAMAkGB2CG dgFkAAEwCQYHYIZ2AWQAAjAJBgdghnYBZAADMAkGB2CGdgFkAAQwCQYHYIZ2AWQA ADAIBgZngQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzA3BgVngQwBATAuMCwGCCsG AQUFBwIBFiBodHRwczovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeTANBgkqhkiG 9w0BAQsFAAOCAgEAKoxjhLg2AmSPebJThQ8d25w0xTAYN3iI4ZA7YjaazonVuF+/ tPz3oZIMCIcYacVXIoAYOZBigkwlWHgYety17DSplY4DSBAct2V6YhnBmLYUfsdf YXJQRjbYNaNMrz2bORikq0VH5PyPZd3nQpXL7O+mqYsmakrjbCej2oL7Ma6lLxdw Ty3kdCOuaaUBCT2f7uFGr6wMSZUD82ZUJ0enY8oAfRw94kA/TUtkuNNbxCwsr7Dy +nlWI328n1VgnjcwFGUAbCRcmdufhHqe05Lvv1HABw5lsu6lHAfmiB1xc2akdA/e hDd5BdcpUiZpFF9Cx1JhR7yvTGoYKFsmL2GSxG9DBr0jFjn+nXy8pg7abPJDk8n7 /RjPvmPr/G9PLrQctIb7Jgs5PODpR5okfXdZ93udP24X2IDMDCUme9S9YeoLL1+5 3LANfxwC83QVZubLbcbdhnqkIbu/wwmuZQc3/jsQ4uEbVy9XX9ufi3Eg9hHSGOeK v9hAoqaw+xgdrG2+h0UUa4cTo1EuQ3/m/MUfz/g0JCLgAtn/n0f3WGuO+eQWB/Tf o4++0BY0PhpFBcUj9LqMsVffYY4sPQVJFRHBhuAUgi9B8jsT2cNYNfTTzGSRpNs9 UigmFl5yxI7NSIZXftM2mdbT3pr5nB6sLkYxeqmQFArAKhm0SzNm8ClmgFg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIRzCCBi+gAwIBAgIIBHlvYTIsFqIwDQYJKoZIhvcNAQELBQAwgawxCzAJBgNV BAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQg d3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcx GzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEnMCUGA1UEAxMeR2xvYmFsIENo YW1iZXJzaWduIFJvb3QgLSAyMDA4MB4XDTE1MTExNzA5MjU1NloXDTM3MTEyMTA5 MjU1NlowgasxCzAJBgNVBAYTAkVTMRswGQYDVQQKDBJBQyBDYW1lcmZpcm1hIFMu QS4xEjAQBgNVBAUTCUE4Mjc0MzI4NzFDMEEGA1UEBww6TWFkcmlkIChzZWUgY3Vy cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTEmMCQG A1UEAwwdQUMgQ2FtZXJmaXJtYSBQb3J0dWdhbCAtIDIwMTUwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQDaKgpFvqOOjala5PnTmVey0q3lyi8RfWnFJUFi TOwlxo1YhkBXaEwp8LGRTCNnc/2r0pzZomF4XmWlg9YSsJ4ASY+Lr29w8m/UHIuf vk3u16Y+SUOwkMoGk+sbZBQ2kCyUWTrUu4sjKpQ+1sgJa4n5QObAP6ZCv31UNdCo /W7e3FDo1Ps5EqHetlUxTYGV4fuosSURI4zVytilJfjTZ3e00Gr5ONREwPvIqU8L 16geZETpMv2AC0Q7I/9zTtRDw0LEZCu6vG9D+ayOHLLPE/QC+euyE5vtYljerR/3 HGu1itmh1tZs1nUmCntAGrfIvByMIBXg4x7cqIqyk8LKa/RWxFUu8vtN0ue+AZZF vm6J7CywyYvLQ24txS7PS4N1/63ZdRUT0WLOAgn5IQLMRPB8DbtbZnIz7Ef5gXiZ R2AjULcrxPV5aqPVziKODScvDVuvJhLvdDF8KiJ+txRWe05MWGOOjVDfhhXgbzE3 j68cnqbKN87RwHIHwtGJE7TpAzj4ZvGQDMoMXBui6lh8Fa81N+BcePk4vmOjxCaR 9rWvPaaGvblA0XlBdxFK7+nGOHFg1jPvK9TK+piEhcPcP10wRnB5O8q+4Iw99uTM UY+uPq4vaN9rMHCvAjO5qIRIyLkJlyxnwykPnGPoOMmajckx4OP/b2zKW8OrT4Pu GRpiXQIDAQABo4ICajCCAmYwEgYDVR0TAQH/BAgwBgEB/wIBAzAdBgNVHQ4EFgQU IGmabGRRm+JMYMrj6FjCheckDXowgeEGA1UdIwSB2TCB1oAUuQnKnB7b02w6a67t VPFbkwY1Ll6hgbKkga8wgawxCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQg KHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJl c3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEg Uy5BLjEnMCUGA1UEAxMeR2xvYmFsIENoYW1iZXJzaWduIFJvb3QgLSAyMDA4ggkA yc3T6dV9I84wfQYIKwYBBQUHAQEEcTBvMEUGCCsGAQUFBzAChjlodHRwOi8vd3d3 LmNhbWVyZmlybWEuY29tL2NlcnRzL3Jvb3RfY2hhbWJlcnNpZ24tMjAwOC5jcnQw JgYIKwYBBQUHMAGGGmh0dHA6Ly9vY3NwLmNhbWVyZmlybWEuY29tMA4GA1UdDwEB /wQEAwIBBjA+BgNVHSAENzA1MDMGBFUdIAAwKzApBggrBgEFBQcCARYdaHR0cHM6 Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wfgYDVR0fBHcwdTA4oDagNIYyaHR0cDov L2NybC5jYW1lcmZpcm1hLmNvbS9jaGFtYmVyc2lnbnJvb3QtMjAwOC5jcmwwOaA3 oDWGM2h0dHA6Ly9jcmwxLmNhbWVyZmlybWEuY29tL2NoYW1iZXJzaWducm9vdC0y MDA4LmNybDANBgkqhkiG9w0BAQsFAAOCAgEAu0GATqbLQ+Q/QL/XwDlvZ6BOitu8 vFlkA6NtWuX4TiTLcxHWqk17s2j0ud5Qx4rcOatVsgcTPtevSz/XrI8gTDkLTo2z lTQpKQFUaqG0Rw6R0EwLoPUjeKKJiU1FDr5/pZ3sIL+DWux4CjYiyzq7XIlvDHUe Mc4PXKPavRjox+IrOJgeL3Y3iSscKb5MrmcZGsU6bCaKOxkeTUFoHIChWZVLtEvi XbKGexu/qj7unexLIdj2uHfQyiWJlpzEfPrzkDZEvZ+nVb89I27vbY/SY6vau0l+ dyZ3hovkramxYSbCKmWSR+ksbYclObEv8jLugGTXnny9bogudHlqK/OvDyy6iXEA xtY6qAok679dwa252e5DBUTnuO1yF56csZzibfFCsCA4beel7ii8umKdENzTbd69 s94eFm4sUnUoNoeNzq864vDcT2ODmxzhsIHWF1m9YNDkn1NfU7wpFEjGw6LrmtYJ QbSd6IDqJ0CpR/rctjBic+iLdo03qaZevQFjhZZ7V72VX+REkVawoJP5bb+QAYIf ERjQIlsz4Ejto3x2UfmnPqWyBNjPd/po2NddI5YQ55Jb7lzSNTx8qErEDPzutTWp PRF8gtsTIQoMYNUaiKMqLz02vIa883WK6NahlBI4Uy/FE5DHmWkcZU56CYA4rqrv XZJt2zyxCI5FPKw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIajCCBlKgAwIBAgIIBLwHIkVpZ5QwDQYJKoZIhvcNAQENBQAwgasxCzAJBgNV BAYTAkVTMRswGQYDVQQKDBJBQyBDYW1lcmZpcm1hIFMuQS4xEjAQBgNVBAUTCUE4 Mjc0MzI4NzFDMEEGA1UEBww6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTEmMCQGA1UEAwwdQUMgQ2FtZXJm aXJtYSBQb3J0dWdhbCAtIDIwMTUwHhcNMTUxMTI1MDkwNzQ0WhcNMzcxMTA5MDkw NzQ0WjCBsDELMAkGA1UEBhMCUFQxKjAoBgNVBAoMIURpZ2l0YWxTaWduIENlcnRp ZmljYWRvcmEgRGlnaXRhbDEUMBIGA1UEBRMLUFQ1MDcwMTU4NTExPjA8BgNVBAcM NUd1aW1hcmFlcyAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuZGlnaXRhbHNp Z24ucHQpMR8wHQYDVQQDDBZEaWdpdGFsU2lnbiBQcmltYXJ5IENBMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyOJ6Caq/UPeIAOnHYjy8itVreO1n/VRi qOnuTmlYfkpG8oqTr7WBkwOO9x+WhHh1n2tGrXeLg3NdAkmjg6/aYUzd5/ZYfwiQ r9dsCMqh5Uz6wk9e7sBQ1GqrLzM8zJwaLMVB24wITZt/kJnq0+6Q8UMGlLSZhcG6 fhLR7MKHMIzwMGsv0vnvF7o4BRdtfi1iwV2X/E8cm10UGkKgQw85RvGXQWPArsFl C2mHcKRiNRzjo1d358zfcOnH06SXMxVvxkkHOm7nF7tPz9nbNatPHgjnPqvmVro8 uAfb6aUyscK2qqMQeUwF0XdLaPDoK+v54mUa+u1bialItnVuJf0Thext3N1D6I4P 4Yob//gXLh5RLsuLYAvUmaAlOGiYkpNyF/4xbmF2XKgWmPXsyT9YUKpaLvFywIi4 7Kxh5x3Y2ZD9Ot9S3U+bIOMKP723GecvvWTnuoGFHS3tSNUiyb925BAZQgpI8dA5 J8z7j9aDUltU/7p2JnFuknH4VEuIsLXM//JlOhSfhVhVNa04xYS84+YHveUXVYke KDaqUhNo4v0kuWY+jc+6NpRFsYaigEkIU9qkiXl7Va9Wsii1lF5egm/igNe50bVx NyYM/08rzi1bXOcAlKg6+KRLqVLlNEQYCDqMaNK0OCUyi6FtWNkzWuuwmPmbm6s8 bad1wyDpUJkCAwEAAaOCAokwggKFMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0O BBYEFKhV8DPDTiLMaByhGazRKhM9JWBhMIHgBgNVHSMEgdgwgdWAFCBpmmxkUZvi TGDK4+hYwoXnJA16oYGypIGvMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFk cmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9h ZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZp cm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAw OIIIBHlvYTIsFqIwgYMGCCsGAQUFBwEBBHcwdTBLBggrBgEFBQcwAoY/aHR0cDov L3d3dy5jYW1lcmZpcm1hLmNvbS9jZXJ0cy9hY19jYW1lcmZpcm1hX3BvcnR1Z2Fs LTIwMTUuY3J0MCYGCCsGAQUFBzABhhpodHRwOi8vb2NzcC5jYW1lcmZpcm1hLmNv bTAOBgNVHQ8BAf8EBAMCAQYwRgYDVR0gBD8wPTA7BgRVHSAAMDMwMQYIKwYBBQUH AgEWJWh0dHBzOi8vd3d3LmRpZ2l0YWxzaWduLnB0L3JlcG9zaXRvcnkwgY4GA1Ud HwSBhjCBgzA/oD2gO4Y5aHR0cDovL2NybC5jYW1lcmZpcm1hLmNvbS9hY19jYW1l cmZpcm1hX3BvcnR1Z2FsLTIwMTUuY3JsMECgPqA8hjpodHRwOi8vY3JsMS5jYW1l cmZpcm1hLmNvbS9hY19jYW1lcmZpcm1hX3BvcnR1Z2FsLTIwMTUuY3JsMA0GCSqG SIb3DQEBDQUAA4ICAQCULBt1/fEgh+u64isYs56a8Pw3sp4CRh2K04tXzOPRkkAZ CChOaETS4as1dwxpNE/acnQ1Ie2DddJ8MGIza5YNdCrLLxGmkWTNy3Oi3+9ENWqY h87OcLN8enbhJZ60kyEAb7FiXszIxx36AxWA3/cdTNeroZoIkak5cD2Y2UwZuCTW 7//PBcbgElAP4kX+dwlA1//LdHWtAbbbq0fCS7RQk1I3fU2K8LDHg4CAmNAffNqB tlSVfrT4vLDLJCE9vpGLXJpEec2jKiGTCuZgCUW8LHMRmaUKDD7k0dB2dcqg1v+U 1KXxGfO/glnSdWZZ/fkyOu32JA0yNmh0JFLp093m3/helmCgO+AKmgIMzAMKrNRf jvBKUhc/c/r8vDWmia6h5DvHdcSJpXdfWqDOf0EPRQ2VyLloJkN5fnu++P8DOz/a yU/3aKwybcxrgWZ5W/FdiGXbIcGSSJxBBve3Cpn6VDgiRQhWp/trZuuoZ3n/hJsK Cs7U2pdUAF1kJMWbYxdKwjI+6JLOKB+JX8bNwRYskt6AUP4am9VywpHx9Pvk0zpq 9qzTmnofJ8srJXcDcyRAk7Icr6GrvaGiH8HR9zbxh9NU8W+vXIGELyb6CCLIdKPf 7SVA4Wn7AA1viANwmGSp9n8aOec1bsp3V4m+WicJQIGbZwahawSwq95aGBiYVA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHDCCBQSgAwIBAgIQLxPa8YcM1DOPGNv8N2uyezANBgkqhkiG9w0BAQsFADA0 MQswCQYDVQQGEwJGUjESMBAGA1UECgwJRGhpbXlvdGlzMREwDwYDVQQDDAhDZXJ0 aWduYTAeFw0xNTExMjUwOTIzMjVaFw0yNTExMjIwOTIzMjVaMIGCMQswCQYDVQQG EwJGUjESMBAGA1UECgwJREhJTVlPVElTMRwwGgYDVQQLDBMwMDAyIDQ4MTQ2MzA4 MTAwMDM2MR0wGwYDVQRhDBROVFJGUi00ODE0NjMwODEwMDAzNjEiMCAGA1UEAwwZ Q2VydGlnbmEgSWRlbnRpdHkgUGx1cyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAMfolTzFjsvedPYwvO3ph5U+t8tmXWjPCSg7pRdR7Ip5dhBqmdEN IQ2THhBQKzjEX9fdwHQr9EUxUtZMWF93HAlj03o2ZgNtLUblObru+LwA/DObWQVn dKMGmd6NKFUA23YcaLwe2/nNUdjV7caK0o95Ret5UZ4nVoeP9JBgTtwiPHu09x3n psSJ3mlOB754RKbKJdbDkJOFAiJOxfBiGuLsztrwHtPDWHP3JkAg87gNMl9WyWGd nOnrexcbqUgG10Gufh5L7WuKmKogU6UEK2Fsu6pUbc8M90x6Ft26UeRPgbC3cI0q uO66dm/zi06zXsefWcjee7QfwLbSALJBBXO3IfbRnhknphhMhHR4IsHZYiUMzvrn 35iOGawPv82fBHJj9IlXH42IwMALW82559r4nXT/mGg3yR7NFqJ9JUwvJVSKZIgD QXBM2i5qjw0vq6qu9w3+2nWZ9XmGEYDuqPswy8C9LGCN27teASRFuL2J6+yJDmvX sXjl3AWibJG9Q4xEYu+H2N4fh1XEFfctgPNnOGcs85t3PAO6zJOxPeESljc/8sFx Z3N1LSzUOJYQphDNevIB91WGF27v1siGHlEJB+lwfuumx9I2/+YF8M8S1UFhHpJi /nz9mvkeFKz/Y01tr7Xyn/JL/i3rRX9oqdDwgzZqMF2KneQAzxf6CtstAgMBAAGj ggHZMIIB1TASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUZjjzwlqN3683rWHZPBodPhdnB3UwZAYDVR0jBF0wW4AUGu3+QTmQtCRZ vgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90 aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/JSP8wSQYDVR0gBEIwQDA+Bgoq gXoBgTEBAAECMDAwLgYIKwYBBQUHAgEWImh0dHBzOi8vd3d3LmNlcnRpZ25hLmZy L2F1dG9yaXRlcy8wfAYIKwYBBQUHAQEEcDBuMDQGCCsGAQUFBzAChihodHRwOi8v YXV0b3JpdGUuY2VydGlnbmEuZnIvY2VydGlnbmEuZGVyMDYGCCsGAQUFBzAChipo dHRwOi8vYXV0b3JpdGUuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYS5kZXIwYQYDVR0f BFowWDApoCegJYYjaHR0cDovL2NybC5jZXJ0aWduYS5mci9jZXJ0aWduYS5jcmww K6ApoCeGJWh0dHA6Ly9jcmwuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYS5jcmwwDQYJ KoZIhvcNAQELBQADggEBAK05XoyuwD1xY8gkIri3eb/mk0rVyRp6Pa9VA8hDNiZq z2ZaVAOKZYP3tvRXTz/vOMlDVO9i66MBqADiG9smLFB2dWQVojALSbX52V5gyKPg lfqY99YPLwuihlrOYSDsuooEc6qZ3RKgK3HnbLAlhTNRljgcOkKFYmnMXggsUA5Z hL0fntu+b89FCSbtth3nhoL1gVYZg54ZtyzMi8VmJTMUDk/2nXuzIan6dZByWdcU fwHj5iGyAnXs09+iQA0q+EyqxKG/7ovWpOndOJIZ576bEy3+WcnxWAdYiBV8tA1S njit91RkThbjIz+nzuVJOvYwQwJdBp9lBJoFK2zKHy4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHFzCCBP+gAwIBAgIRAMZSQoyDlJwTf12f6/JxZE0wDQYJKoZIhvcNAQELBQAw WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x NTExMjUwOTMwNTFaFw0zMzA2MDMwOTMwNTFaMIGCMQswCQYDVQQGEwJGUjESMBAG A1UECgwJREhJTVlPVElTMRwwGgYDVQQLDBMwMDAyIDQ4MTQ2MzA4MTAwMDM2MR0w GwYDVQRhDBROVFJGUi00ODE0NjMwODEwMDAzNjEiMCAGA1UEAwwZQ2VydGlnbmEg SWRlbnRpdHkgUGx1cyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AMfolTzFjsvedPYwvO3ph5U+t8tmXWjPCSg7pRdR7Ip5dhBqmdENIQ2THhBQKzjE X9fdwHQr9EUxUtZMWF93HAlj03o2ZgNtLUblObru+LwA/DObWQVndKMGmd6NKFUA 23YcaLwe2/nNUdjV7caK0o95Ret5UZ4nVoeP9JBgTtwiPHu09x3npsSJ3mlOB754 RKbKJdbDkJOFAiJOxfBiGuLsztrwHtPDWHP3JkAg87gNMl9WyWGdnOnrexcbqUgG 10Gufh5L7WuKmKogU6UEK2Fsu6pUbc8M90x6Ft26UeRPgbC3cI0quO66dm/zi06z XsefWcjee7QfwLbSALJBBXO3IfbRnhknphhMhHR4IsHZYiUMzvrn35iOGawPv82f BHJj9IlXH42IwMALW82559r4nXT/mGg3yR7NFqJ9JUwvJVSKZIgDQXBM2i5qjw0v q6qu9w3+2nWZ9XmGEYDuqPswy8C9LGCN27teASRFuL2J6+yJDmvXsXjl3AWibJG9 Q4xEYu+H2N4fh1XEFfctgPNnOGcs85t3PAO6zJOxPeESljc/8sFxZ3N1LSzUOJYQ phDNevIB91WGF27v1siGHlEJB+lwfuumx9I2/+YF8M8S1UFhHpJi/nz9mvkeFKz/ Y01tr7Xyn/JL/i3rRX9oqdDwgzZqMF2KneQAzxf6CtstAgMBAAGjggGtMIIBqTAS BgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUZjjz wlqN3683rWHZPBodPhdnB3UwHwYDVR0jBBgwFoAUGIdW4G537iQ1PE5zmh/W4eJ5 fiswSQYDVR0gBEIwQDA+BgoqgXoBgTECAAEBMDAwLgYIKwYBBQUHAgEWImh0dHBz Oi8vd3d3LmNlcnRpZ25hLmZyL2F1dG9yaXRlcy8wgYgGCCsGAQUFBwEBBHwwejA6 BggrBgEFBQcwAoYuaHR0cDovL2F1dG9yaXRlLmNlcnRpZ25hLmZyL2NlcnRpZ25h cm9vdGNhLmRlcjA8BggrBgEFBQcwAoYwaHR0cDovL2F1dG9yaXRlLmRoaW15b3Rp cy5jb20vY2VydGlnbmFyb290Y2EuZGVyMG0GA1UdHwRmMGQwL6AtoCuGKWh0dHA6 Ly9jcmwuY2VydGlnbmEuZnIvY2VydGlnbmFyb290Y2EuY3JsMDGgL6AthitodHRw Oi8vY3JsLmRoaW15b3Rpcy5jb20vY2VydGlnbmFyb290Y2EuY3JsMA0GCSqGSIb3 DQEBCwUAA4ICAQC75ZUBBzkUGAgcPanEMIYXFQaMMbdkRqW2jnGZTCKn7ahguFGl 4/VwDN7oT9Yw7LqFLNZumbKFR+QUOlFi4DiqWUqFbYle8ir3gZBLMiGpD8fO4qbh DfMRLJytJ1UWZN0zHov5KC6w14SQVoyUH6tbq7FYX99KqQ5Twjq2Z8+pVQGiz7ca y107Hod/86gl9SAEq+YIdKlgfax+GKi6wo18m1Z6NuGQp1SYfVnO1eWdPyNRAIv9 Y4N/vZkxV6ct9KuNAv1DB4CSjuYJVyO1UIk2LNqYTZUQPEXUpdgXFoiLKqWgvysg xh0nr+IrzblClUusEpOOIPVCRTlkLQNKLXh6rTglItjeqIF16ksYjag0Km7qSP4d LK9+vQ6y38YfTE3ZPjH6inK5o9jU+3bgch7sY8whZzm57768SZXSndRS4DSaMlUi eZV4flCAKQ0I85Bu7tSAIPtdT0XO5gquusAW1fTclq2Z7JBOBdlMjsRG9ZIq9cZ9 tCt1Pty43D6I/GGQXAP/hri47oquz2pSqDwOqt7tGvPP+pSYDEgRFJ5WcrwAAl/j 9kIBteCSveZMaRo5esXgFbzafIXDPh0pPpUGdp8Q2opiWv4OpIBXPnQZXI1iMnOF BLQyzO+oYV1u3Gbjul8Y3xlst/mB/3KXXEVWUaKp9OXNa2MZkHqEkHinHQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIczCCBlugAwIBAgIIA5gfUeLWjjIwDQYJKoZIhvcNAQENBQAwgbAxCzAJBgNV BAYTAlBUMSowKAYDVQQKDCFEaWdpdGFsU2lnbiBDZXJ0aWZpY2Fkb3JhIERpZ2l0 YWwxFDASBgNVBAUTC1BUNTA3MDE1ODUxMT4wPAYDVQQHDDVHdWltYXJhZXMgKHNl ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmRpZ2l0YWxzaWduLnB0KTEfMB0GA1UE AwwWRGlnaXRhbFNpZ24gUHJpbWFyeSBDQTAeFw0xNTExMjUwOTM3MThaFw0zNzEw MzAwOTM3MThaMIGoMRQwEgYDVQQFEwtQVDUwNzAxNTg1MTELMAkGA1UEBhMCUFQx PjA8BgNVBAcTNUd1aW1hcmFlcyAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cu ZGlnaXRhbHNpZ24ucHQpMSowKAYDVQQKEyFEaWdpdGFsU2lnbiBDZXJ0aWZpY2Fk b3JhIERpZ2l0YWwxFzAVBgNVBAMTDkRpZ2l0YWxTaWduIENBMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAwIyfzHgjHAySoIsQMItLlEXb8bKeKGT46cmC IlhtWstWqTDro67oBz2so9EqO7nIryY05dE2UJEDO03lFM4KFPZCtojxqi/8KMHn dmW+NJO3wiikIaRtg/AZfuOXf6rVwp0fCA6ROgOFvideXRFpH+bvV5LOm3uH7gp/ KSkktrWRYUKZwD60XJmAWvVEmtR4ydakTdoEpmZ7x6VaxCA+Jm7NlbpnxBCM+MXs rmFB9At7uEO5t0M/cAcgijyvIbZMwiklEXw+FJlt+8O67nZ0M53i0W77gdL11M18 XNqVil9qjRTE+DpnoUAwE1e65uGaAcytbo2Aafp8w4CaS3CV8hSgqDlYdR+iD8GC ouicpl8INZjQzd67y++4p3K2AS4h1uuuzC4Sg6Deg5KTNOa47l0UI60hFB1KxD5I Uk/V58glRUEuUhpDu8BX/JorqesaHXLaUHpeS+cZXp+kiD8NqU7suNTwEGRgtutf Mi4rfLfGlDxO6/U6NPbYM4RKhepTYglAn3bkGFZzRHsBdulIQ82ZhAB9gJ1K2Q32 z5mkucnXOncGTaQ+/9T2MgfbH8P/plHsruKbLRl4NgAjN5xpvdx9S5rqvGv1SIGx b7v5D6IwU5Op2tMPceww1LezJBWa515c09/D/roI7d7XQG7KhIg9WCHQWCfW4s6P myb5pdsCAwEAAaOCApUwggKRMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE FHKWHH7TrTRo2085TJM2McOZZ616MIHfBgNVHSMEgdcwgdSAFKhV8DPDTiLMaByh GazRKhM9JWBhoYGxpIGuMIGrMQswCQYDVQQGEwJFUzEbMBkGA1UECgwSQUMgQ2Ft ZXJmaXJtYSBTLkEuMRIwEAYDVQQFEwlBODI3NDMyODcxQzBBBgNVBAcMOk1hZHJp ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk cmVzcykxJjAkBgNVBAMMHUFDIENhbWVyZmlybWEgUG9ydHVnYWwgLSAyMDE1gggE vAciRWlnlDB+BggrBgEFBQcBAQRyMHAwRgYIKwYBBQUHMAKGOmh0dHA6Ly93d3cu Y2FtZXJmaXJtYS5jb20vY2VydHMvZGlnaXRhbHNpZ25fcHJpbWFyeV9jYS5jcnQw JgYIKwYBBQUHMAGGGmh0dHA6Ly9vY3NwLmNhbWVyZmlybWEuY29tMA4GA1UdDwEB /wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDBAYIKwYBBQUHAwIwRgYDVR0gBD8w PTA7BgRVHSAAMDMwMQYIKwYBBQUHAgEWJWh0dHBzOi8vd3d3LmRpZ2l0YWxzaWdu LnB0L3JlcG9zaXRvcnkwgYIGA1UdHwR7MHkwOqA4oDaGNGh0dHA6Ly9jcmwuY2Ft ZXJmaXJtYS5jb20vZGlnaXRhbHNpZ25fcHJpbWFyeV9jYS5jcmwwO6A5oDeGNWh0 dHA6Ly9jcmwxLmNhbWVyZmlybWEuY29tL2RpZ2l0YWxzaWduX3ByaW1hcnlfY2Eu Y3JsMA0GCSqGSIb3DQEBDQUAA4ICAQAN4INvwXXElWPJW4qJjoToMV1jg93i407+ 0tfeZt0o74miysPGMAj9WDswwfAiIVe/76/z3bmb+Nlk0aDIO1erpa+N5Y+zm9by 7VtGm17ARP0CIdhY31gAkeysxHpowEdg0Xk3NULFT7NrS3b5FCp4LFH14p6xqp1Q mJD8GIx77qy2AMFLm7pg9f7i2w00JbPWnYbAncEoYF2MFnhGMA8Q1xMsSkAbYauM lrzau0YfefnWXmkyyqnVoS/F6SMyclsSbVj2uNDpTI3B9N4ruCzO7PChO3uFKaiO O9fnUo85orYSMG4Cjz5U/ntSx2oIHLMICFFbZ2V/QHcW4/bP857vIvE1UAQoThNB DIE/Xkz45FUfIfPFlpCHkcVOSa4mjvwB7irndszQsAIDhiLZ46TQhL5bUCpuk6xQ +OZKx/Sy0L6sm/LclKgjLTJC4Fdlpyz2THCuxVnrIpQWpixRxHTRHQevM9LULLxb xmTeZKGKpx78PlE1m35rFNRAKgMbsdFwOKVih0SL3/ASQ6/dmXsmu5I67RFO+1F5 vBncCgT6jUMUqP1HLm7G855l8i5KxUbHTytgkxpWModeyYzL5HP04S0/F55yV3pB Gk1itzEeDdfIy6oPCx4xDxy4Pt1+e/6PYFZ/QZ4dWyKqDWu0bFzNn05x9AGS3XpN nsAYudtUwg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQNltLwL1YIjH3ZS7td6XSADANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE2MDUwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCivukyg8lINO7BT6xOk1ShSc9m3j65VmVghSckGTSSgIqt YOxu4OaQSbT5CeulIPoDaIB11LynN2xpZznUczhYYrw6/wuPTDqHo2+rxWZVi4ru XpkdknecE+97RhpuiyoB/eWjR1uvfkstJIVS9qTn1E65sVd/YKOz3caECfc/Yu91 GWgoJzRDYKY9wBQwEeST16GGQedw7pdF2+LUDc0Km9bqVxmv5f875t1CwUjrP1GS bA+EA00JRiy7e9nRfkBtB7p6Hy1iPWQM7BTqhwErPuDnnv7Lrq181d3CkEXAZFnF w0Z+NCl5ANTQXPUF/txn0DpNkA/wV9zQLwrVeloEWyTSGPfQQHYKRMS8/G5KaSwx 4c64Q5f69oRyH6aTKXIZDTsMaiEaLPH7oDgGfNtDEiv8MMv4EWcjF4UhX9h1zby1 /Gyd1EMg+QorXCvhUlORxhc2TPtTRtSWDLUmFXpGccNyiOr3RlqhrOtfrjb3eALt Ajbo9b3xcybs+rKCGPRJWFMqP4eRDEBYCBJKqYV+nAJNHAYyf9OYDvuzHHlzaTqC 1VejYkaIQljCoJzkIsnRu4cGLgDqgOVZ8kG36DCpwEzYwI7tX8G/6dX6U8UQRZCr +4pFB7JetnsEuDWmpIPJa2gRQuptWHwONXChitFuq0Ww1fSjljGjzWSkzATvnwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBRuBdrvOYTWzjNZTlnb08pNsUh/ iDA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAAsugrI3LaOko8wnakZe v/umF6DOLxbTLrg+bF6QbcGicET8euJje2cSmCa5P81ID+N9RV/kLO5GT1zY9nBw pqQOxG8bO9OCB6ElXV7ftjhxwQf9tRVAhAo78xMaCZMKJgdoYB5tsodhOWAaXbsL LxMiOOWVBqCQpQbpbV9FP2d+XvJmycpy0ZqAJYfD3e9gBkODXNf2QC1mH89q6tBg N+fKTCfpodHsFVNsDgobv1jCozJY8nEclxfvsKU/LQp+dRGgyFq3wSDEbdteKYG0 4ynozuesVkJIKn7DuEFtAT3C6R9Dt/d5VYgx4EGgVnKrZlAV/Sxl27OWRWsbuqZy iCCDcYAMCp+w7oTjqgjPWACQjxEFNqfcH6ZaWU6ggZTT2LvnQhp6hn4fc5/nBG/O /H/BQwcHxAqA5IqjgRSjd/43gjAtd7HknCY3wHiP+XJnzc7pdFZm+i6IvDyGQxUG CVxUpPYR+5tocJJzsG4FUw6APLewxv1ZySXAIkApmRMlCS+IJZKAZHeOz5A9pzzr OKCJdbaDSjBRFVserNyb8g3+FNAboY0BQParFRnWIQB8tM2Cvs/shGlKtMvoq+p8 ndM4Ns2ojoEStFpYQmHTLJ6fWvRpamp1UGDhUlPfZECgq5rJOR+fs/xqaOR+C9op N2Chz8h1nXQltUW7PlfIOawR -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQahh6hwIzogPw64yM/Mj8vzANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE2MDgwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCys/lpJ3OHjyAWbqY9yfCC3UooHpcc1b4ZowVPZIwwYyyE tzuM5Ka71KhbNeKLtvmZ7/bplR7o1f9PAHHBJlid9w7NQQVY3tn38SqZA2yrANZ0 cLMcF48N2hZEDkH0D9GiHx/vVu/QyoHYRckD/aO2NOsKEHDD3HfZ74BxBd2aQ5Zi S4h01JXKoBQdCjJ7uakADIym+nKNWoylvxvDCbOUEuQNf1y7OPbxj9n86HMYNCd/ Bf0mqo6IcuCVoDgrksTubEPnpTlbjKuRFQhdF5AOyq+T9f25Jo4F3qxIpOdOBb7W 4E/P8HVvAjgUACnVQtq4WODhm36H1Voctyq+mvnV3ZYtdhlKT28fW8RWBBOEA/qg JP8kjLFeb/zsUkrjIhLR6cbbLeFaTP3Xw0tj4hq1BtgzeWcp1UulAsJNKgqR9N75 I6H9QN3Y0Ch2waKUrYvfQV0ea8/iAj/ewi455Kg+ah1QQstEbBbw9N39PexhPlBk E+2ICbBRypzUh7xnWhho9LsiQT4RwNfJlijMObSKjuNK4WuSZcr9FVRM3IX71Afi 6jSoFGRDa4umoB7Gjq8k/zTKKDtvhvAk1qwVjmnCzdvVswNYDL5SKd6eneuN9IRW iLfAl1PL1OW7qqbQMv7NJ7sCOY4MBurUSV7p+4z+LTWB89mEBrtBkUz2fQfJ+wID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBST8KOBktl5Lj97ipAk406e5tAU JDA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBABxPYaBt8xE3g59Tagp2 QqdXG1T0TZT+atmR+ZJdyZ5nKY3TWE/EMWkzVuxJxlxqDjj/E4+k4Zcd0dP/Fs9F fboOQolsLfrtE9qFVU/OljCnO8NNnUK85bM3rqnvoJ0+bmTxO9QU2bNiK6WclVKS rkuuvptuibGkC5dGGvTPsMhkyw71yuS3w16uD1Xj0P4IqGRTT7gT6KZa3U/QA+xx QQjA1nFXbXOKoDQcHZkbfxbPrKhuXv21fw55QTXIWtDAxawNkBpZiEbFxOKloJPv dnk4OYiGQkXtFV/hlbnpBkVLtivzCqLRzXGB1ia9OkDGJ3xtd1AhMJlNB8PVOiwv GL2SyUK/oZnj8zY8TKNYc6dq0x0xDsm9VdR1ku/22CEMQOZj0hfgHJ6sgNYw4Xyq vdJRHsGeUcttQ7L+5wlB769KzvgZgN4Wx12V0omCrc3tMcUfPMEJQJX7XMvWAs3e lKYI6nMuprOGuXSPvM1A67jal8+DitD8IcUdrRy/r2Migkm0lgMZtQRS6qT36CvK JnP3HTULCdAyA/DcpDNOijTr9YdQgQ8T+MwMp5tJ4T6f1CAhufy5aGd1LrKlTSO9 RdpXNHhu/B3Uk3gmD8IHgmDuWMcQbbpts6SKbWVnJK67G2Srk2h+pCfoulmAe5qy UCjkeDr50Li4tEbCHc5L0+U/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIQUgxs76R+AW4hFw/sdbn2eDANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDUxCzAJBgNVBAYTAkJFMRUwEwYDVQQD EwxGb3JlaWduZXIgQ0ExDzANBgNVBAUTBjIwMTYwMTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAKIaeJces26JUCHmo1KPXCXJPbwc3IR2AiAHT/FdNB8m BRshfj738CT2wBnqapU2jUg1P7hvWzfdV8B5e+KMHN1T4AHxu5jqwok/AQo9CbFI YDuWZ/zxnL4NkQjYufaIUYfBEoUugCZE9qkQmvKMryodAfNfSvrzndxdEQsqCAYy B+WHcHGeA80gE+s8xM2eLnKerX/1lxRZC7q3D0Pb/v/zwnE2AujL906xa2+louCh pRTILuKn0yPhf3NcrlB43AZtMIKf5jDPM7+VuF1rZhbSC+N41R7Ei7LJeM5q1IJI 0PHU4ta7CzsGito5BjqWUKwEoZNqT7Qr1JW9wKvw41it8ZvVRLxg9NaFhcD8yNre WWJEYY00/u4c0nHSys5MfBLSNHgh5fT4xR007jvBkPaxMI1jks7yMcLDjxNaFsdn vabalm+en9CQVYz4VvXLTvG6COdphxx5SxtllT//U4+W6NtvsptwHmXLcM9o6tQy kGf96HKZng+ucWf7DT5JbTIXrrO3/lgHZAeGTh8XoO5M01NTJVSsjjSzxCoFjPm1 N7E54/qALFiRmujeQdo3/wf2U/5Zgf6cl1lq8BXdeNw74NzAcCMh7iwbNJEAP8fM bjJ+EoIAxY21wExKz4pFmgZTLuz+sQRjH+C/5HV8MxtKP7qe7wUbz3ROiEw/00XL AgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw QwYDVR0gBDwwOjA4BgZgOAoBAQcwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9z aXRvcnkuZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFGdPtklOsTLfKmmJYdcjHja8 PpZQMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUv YmVsZ2l1bTMuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBS4vGwA j1sZhZ0lAZzwGdxAjtA4KzANBgkqhkiG9w0BAQUFAAOCAgEAed6oj1TKUvU9m8E9 KGogIYj1mdjrtuCnkFbWi+yl3Vqdpp8+Fujip/VliWFamDuYJ4lr3eNYWU8SMwE4 6ykieiCq/mz1ggfIptpitAxU1kB7oJNDdpmDyMBxnAt+OrkzbrqoKBg7fC2B6Z4G ycQxw/MLYoLC/8vQOPnXcsj26gNqU5ByEvUO9S0m+cr99TirXsacna7cZQxHGvB0 TDFmvvQPcnEpO7tAMF8DrcH8j1mF+3/7GWOz3e8NH3skXhpBkdmg+j4ftG5miNY/ ShjkIeOZKLKW+Tu0ka2sqvuqbqhh+6wYd2d6vRNz69t17jPSXsLkxz2IyXBHMrZt lQzmu2zEUM0/jCAhnkoH/14k+tnBT7orfonL8mMZy7C3ZGw4TxEY5uHNL7xquZpL MRD3Bc1rbXYwWKwKP0dwU0ua/S3re8uoHEY4HAMS5LB+qohxBPkUkct/41FmsB/6 XRgDOjH3fJtLaEDj3pb5Qa6wt3vjyZtPdIK2NvHfszL5cEHEinlQ/OMuKopbWPSP Kz5/l2JgpvnTKG52qawNTf5Xcid5YNRThvJj8S6w+gGDyy+zFYimjKCgQv5XYabI cNn/iJkfSvYKUFEYLxENtbV3MuSO+iVMD82/VEK/s0u5zT9M8u/EKDrEP4elYWks xY7ui5mkF7yn4wegOpAw6IFv53E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIQesd2natGXpyCFkq8vakoeDANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDUxCzAJBgNVBAYTAkJFMRUwEwYDVQQD EwxGb3JlaWduZXIgQ0ExDzANBgNVBAUTBjIwMTYwMjCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAKJHqls+7+STbQ+Hnn4vIeXFMgTyn29YztzDJ3AkPWBF b6yfwkvpZIQ4px7VAf5+W2hUKmH/pjB7GioR7Dfl6y27IV+nE+VwZeHNsOalIl9s WzU97rR2DjdWgJQJ/wqGt/z2W7bE+Rih0UJMcrqvzPaNDpOFAkQO28Q4WIAWRAZC 7g5w84hD/4KMJEbObWcX6U5Hinn7lkq1fqLzO9RIgRsyHnXHZBEode+EKDln+QyM i/jPKM/HxmVKDTTPvEWrEl6KG9z1eb1/7lMhIuhaUTExzYbmwmUn9YqKNoKDwBqM 8vzBE6+SzqrH56iIb7zNd0YBfPp9NtlMY2czvI9peUIfy4D1K2JjvgM7VLGZ7T43 6ndjy2mH7YG0tha64LgSQi6ZzHePMnvn3UlGpTxghXP4AoHZ2W5GHVKqVR8HgjZY R/j0sZpa36AfmrJHxugQmdE5xc9rrW32oaACzXjl06Zkgm9Hk3iwAu7I6ipueoRv yqqGnzeUwY8Klt6GxZ4ZinOaolAHH0TTN3TVfg9Vcbu4rD7hnbucdQsnnprwcmSd KTGHm+3DKZB/bK1m5IMMi6p/dmtPWJ9UlZ9AXbULquU3DIVM+KgEq4PTGX34PeZH KtoowzV2mM/F4cUbHGoDQloC4ESHnGia0HUbCqTdMy/nQGfD5cSTRJqwPk57HncH AgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw QwYDVR0gBDwwOjA4BgZgOAoBAQcwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9z aXRvcnkuZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFPpX1r6j0y8C5vPMujm0FAq1 eJ3gMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUv YmVsZ2l1bTMuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBS4vGwA j1sZhZ0lAZzwGdxAjtA4KzANBgkqhkiG9w0BAQUFAAOCAgEAlg1M+7T3LGYUyCJX OYOTRzuaNdP7cU5ARsGmvtbDLNsJvU8/zPvIDdY/Zor99yP7W3+BY1XRC0A39akD 8M0rcB+7fbW9G+/fe7PxiMCnXnhEXm65nHdmGk9EBnVcd2sAAon9Q+LfQgAwxNez C9il0LJXkSa3pIeTEmxbEbj6MP7kE67j2B4kG7MZJdhdf+WEs7b47wrqiahXFUk4 5PDb5f3atXDMQAwwUgOu1/Xh5YwzD2eAgftN01SwyDnETstjGWbjbfXQXbGu1pU/ 4nzBxDwtCpbPkULAXi+oyhweLOOEzblTihh9vVA58mlWcnlFPzgwFKGvcXMsRcfH CLLOIOIJvFF+QTrCtsivU4Z9ZRjTWESKgPhzoAtF8is6wJMXuO4/WWrtBlJ5tV6T tgXBOPCJL0jcYz98gE+WEYOXYZlCWmp6L6VHLATGGT9Aut86scybtqHJAGiAJIla b3kIzj4ykRiglyMjQe1DQ95kWwEimE/ZH0VrePSzw/9nu+2Z7YdQhyGEzfaqr98r nf98M/rJK2z7lQgwverGB1ALgVoJzsJ/7jfWsQdjY8pxQTM6wFmTldQQbtxg/icd 6r9BzZ1H0BpRfMRd3PNootcz3SLkqiINTsJ1MF1PykaCl0u7wYmfDPbuUto4Rbzw 3wMlnTAXgqe2toFyncoi47RAqgo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQYFlylQbZNl3qzjpiRoJHBjANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE2MDQwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBAWds3m1bHw+QQNNNzlewCpJS29L+7AOcz+AAlATA9vb5 MTAo0RXt+dGiJtCaj2Aw42OQNxcoiWprPLta3cV58tXONTfjSlMoYxoRH0SS+MBS +FGF6q0Ue7ulbkwVbejnJc+Ls+ieO5gwKJRpMmno2/ikXMZOHN+QVqzY+ss28mgZ 2qcTuwGmkX1oHzpIi4tUflxnesPfiDQP33gSzBw2mlBlvrLq9tshYAJE9NMdxcwX 7LzOD7lN1rSTlTt0enHPvfoViXDs1cQHAIKXLziz77L9oL4FDyd2aGSksdHVVnEF 4ixWPrqRPFoNOjBcwHvCbTrOLJb3Zm0ASoUdWfLhpxeUXeZZqQ0MK7OEYwuKlQ3i MELo8mW15Fc7SxNHmkbAtuRTeUliedtWSY7AfqIHdZOocXYGKTtHjDBLraYd2Nv7 cCtwj8Hi6abv6UCPoKzw1tkOH22pTB56WJ0U+c2taNggL9YjvZFgUXxHt1yEfqUv bk7+Hx0KC0o4ftfgNeJfEL7BnDVFLETmcHSafGs3ieGFzZMk1LSq/3sJTm7mpPdW XsyQSSAxOnWJmJJJdnAfPW0KbmP5nsCZ3CW53lwaEF6fG1OlPSyOsBc3JTAduTdj VVCTJM4ul4udnXXBxpEGD8bzQftd68ntC4dcJrUHEhciJqh9i9bCQYUN/XuA/QID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSvAHYgqxuc9NMDNogzvLoLhmxv ZzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAFCy7Zv5oIjyzB+jobjA /NHiqL00HPF6vFmlCrAMwoKR5O+eCmBuJZnq4jKwRDg5yp9pC67q+h5kO7rEOO1o cMMY1H4k9XYr881lamtplMC+v8ZxYPP2n61kRLUycFaoUhHojzXj9QPmWcq7WKLx pS1+O5RORtOue+aJd/k/eb4BwHIv27fZTJYCxIUXJlam0O91gcF1MA/19Bd9FAfb afhiRKQ7htZjQIx7sGeZF12dRNdSc9RmaRlKcMJsGK2RI5G1VEXMzzj7w70v/jTg bunbrQTypz9N1pk0CMUWBAAT7lHSccYYk5FUffeZA/GsAoXNB+TB9qodLJOLLO2b vP3MzqBqQ4R+7kW3OqnXPx+WvBL6KXoCQAQQIzjMZk3leyKrhJGCwS+k7+sXWcB0 Rzc9U7PamBtX+he4pzzjwhhKECdMikweeeiF4uCoH+c7I2aal+e7+TZ9EANAxsd6 1FV64HlAOob8pRckDuTDCI3EKG76wn14H1w/0PZxQ61zhQjlkRYXkNCiO1vKqb/Q 1hugW/Mr2WXYr0Ogv/jxz0YAqnhHzEnrTQYIvNatLBwix19S+9q2U/rsmg2Mwx0d exgJOK3LJBt/jllb3Ubutu25UByzUUblO0lctMiCztMwPCJflb5A/3xUwCTBBJHZ rmdOGKLlAPXoaEjcnQQzJ7PJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQT48BYZKuQrZih6HCZTX19zANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE2MDkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDAhtAKVTzvrAjszwmGxisT/S/rX7xGQflsEypGxqjqR8mU XLzlwgl4Kpqr5UILVnOm6l5UO7crTw7THie7G2qOiRqKXbexRWPcc2V0i2FcYBq2 HKttpV+Bwd56DorKHbKg1dxsiQXjtIU5DIgX/N4DGz2IM3AcJk9n4uKZrScKnkcW /JmP9YfvUQoNx36dK/ol21WuO8NvJz+PieILfkE9fwoxu13yUrT7AAv5/serZArN QnQhMwctQCKoLUXTuWTr9MstHIg6Mq39rl3hjL1q1FpKEOpRBGLoB5HCtd8hvDl+ t8NdFdjUEnxPL+KVohv2/ufo8RnJC0GK1Z+hMhMGVx1YLNyzcdkcSIF9Z1Q5S4T7 Y4s/BeAsCp+KBoGcI9IGX+NfSgVrHFYoGF7sNk5nAWj/AODtaB4+r1syu3dFs1Ef y2uUoBUCzP4wC878ZO8mQjcd1qlzyGeZgc/I10pA3R/TJUal7Ydf5Vp4U7jbiql1 rQLznmNq6dV8mzGBljjFLryQkVMHNfBSaWTkAouITBKkYYGJPD2qgipNUEsOMpZz SuAQwY8SpyQcgZyYdPSeA1UHwzYQPo8n8HbTMrsG38+IwojERt1Q0F2/uw2LHHSq o4jc4QhT0U4ScGplPC64KdTQ8aNX0TTZXbRsda7A2crcPBWAWqumqMfzho3UEQID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSRn4m6YgWiu4GZvoP2UHU7ZsgS jjA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAEfvuGAZjs/tTA7n+Dgn HBRgS7606Fzv6x2QhqnDmbTL87CePDcIWoRiaE42deaI9gV6f0aJLMP1k3SlJq74 oP3eS29fYwQO+JzBDhnjudMnJnVYaslmIJ6G71Cwv4LNMsiBIAGzpvNp8lfInXfP PF7mPCdt+D4rMAt3066zv+QtYYbNF9eMLS8Cs4eYEhxStzWl/ZDv5FuR1kFe/6Vy Yx73KMV4TN4qk74E/sIHSvRIcIRG41s/t+Ow7jtHvYW+NiMK/w8bDovN9WqKmArS zCMAUXpdahPNlhUPel1kYg7/3qWY0CXKfwXJ9ElzoYsm9y3LrA0ypi8Frr+cEdww adDCXaBlDWgeoBPQiljy0aN9wrUTL1fm13027BrBr2d88tIv+iycQiX7WgbzEnAX JS2e+Z5b5trDq3PHtb5fesZBCsDGlpTptQkqFuDzUt1Y3svrnsIQ5VFC7fMPkL1j ygDDY8xNaJY/pf+Y+Gk5sx19H/dF9JPjWjmSGjvdw/kLT8aIdFXBLjRpQ25ZGTWT eSgZLZFoySxI3FyhGAc+tIIvrpvYFhejzaPloVquPkjAEdgJpccoqxLbUr59XtzJ 3rZyj6w+euJwSfLabHLE3uqMHJ4XCNTMOrNfcE690HJwDjPjzlNemBvAwSqV4yu0 iEEo2tV3QeE44zPo40v5BpWs -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQevZAn/ZUHrMNEK8TNdA3zTANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE2MDYwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCy0FolXWtdYazuIAlL9/qGTPGpYaKydPSgQZERv5P1W8xk qnBxeaqgigmQxvCsImLZTMOz9pt5vZsiaT1lkpXUbWClzqo++fH+cxULNGI9Hd0j wvXAAffMynVUZoHwAF66inbQ39NDkhY688y0aJGx5IzNXknl+s9dtD/+4TpAzCCd qsznvivJVv6wvoT96JrjtqoZvEyFhe+JqdPtT0/r0xHAW1QPXKid5YDlqUy6rjrl uBLSkK79KLImCRsnyku3VDYptEFK0pxGqpm8Tv8HBSYNmaHuAPsRBpEESHOfzmXK WDMnkKi4YcAOKaPNLGXOLC+zZrLXIboc/y8scEpJAijPJ4RD59pkedkemjNOx3aO 7gagWCy4GKyiQAn0A8SXQ2LJCYLileU64VsjIsgHlobIw8e2TDgc9CCVV8YuhfuL kKmZQJX8kXcgsF05yP4Yc4vXh6Cl0tmqPAv47Xxc9Vv6pUhfKf1lTdTtQdwVUCR8 ZXW1tk4mGpMb7T8xjqdE+g96CPMWr1nbnB8Yn1UIF7pkG68bIwNv4qdbn4Bc/bSp JoW7eIdLNfJIIuuqZ8TpoU4SJgBOhqRqj/RGGc21BfYdLNyHbiWvRD8YmiQ+WO3/ vR6VHyWTrftP/WgBRxpSwFGU5rruumQ9sVZ4geTG1GuXQTlmlfqGrV1TVCm6XQID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBTN8J8fmnuKG6nDxlaYT8pmAji3 WzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAB9wa97cfqOP43jFFGhs cGzB7EvDOVMAuY2rwbnlaR5vskeolQ6KzwO6DjL++D7FIdt4+UUemZH3BhKrDx+9 NZPQoZxthGmhr7+jY89/A8RuASINBQIPqZpPAa3++A5fFPkD/O75LoFrNlWdW1pG kFHJPC3xrz1//N4rW2aYmqFX9dipo602vP6UnC5tBx03qyRM3PdGOkMw4/w+KPD3 Z9sXfpj+LFmUzApZWOtnZ5VQdaQvtss39ZRctWM8Z+5UR7kL4wK4Q+XFsO3rpDsa ax6SM6hspSVX4g1WzqA5b684cHQWHjubcx58XJC2Z5XRQPq96iQrrqlcPRte/n2O OUymo9cv0/ataLezUvrfbxk2BM2bIAWN06rGqNxb79ocqr/7f8/3nEiXhYxPxksc TJgsW2V2Qioy1aMkM8NUFwM2+j3gOdXiesYR3M5NlYyng+5i6WwK1AsdRynlEYqN lmDErACsjLct+LbZ8nLd3cLvS5gDLul6VU4/lWz1huzblfwBynd1NA/DR3fs1gk3 htRh8CzWdyLmv/mA5SyZNLOa9gkaHzLdFf1k48rYlach+Ml9Bkc4/wvbnKSrw1Wv EHJ3Qif5sBW0z4vgaE2zni4vOGMumJ3sGQcykdLFBYnCDwkdmed2ExaeabIsWlfy SbovYPCYOBOnXjDEF0TZxT7E -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQMJPXXlwBrWoB2Iy4yTyagTANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE2MTAwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDFOLceZ3G7F0HRPd5wGxLxdjDNlTSFkexNG499+JujliH+ jh8bMea8zUM4bu8cq7y3kMNiJ197ooMlG7oWWkbVvj1TEtTI/ePE1kpHh6/EHdSQ LxmeT2P4A3j6XnIbJWk6KOMUwOxw41OF4pCL23cGYSK4BcnJ2LKt43XkwfBHZyM0 0u1S307LJtJfOdpldOl1afKuEiZbDzP3XoPTTO/ANzqhmEaBQZiFw5ytY1pVBzOM WxKUG/zp29C7OSjcAZSNyRbF+8l73J5C+BDiEe35Ov6RYMVxLRvdqRNO37VgJ1G3 53uyIExFj/PyzFrN86GNpdoY4RKOvwm2jr4B2pkI4hLwBjqQbgL9Y+pX1+rh0YQ9 zyQHFy9KjJCJ0/AKx8Yd89jLhaUxT0TwcqmNYDVebzP/2OhBs4hAbwlqu+MB5LZI jJWvcQI+PRMgXzT7ZPkDxqONxrCotUgOnxUN/QMjxw4ZSxca4p9HVsh7Mij38KPz fambCkltKm1GMVJ21GxAnsiljoeDrBUeZumJTBUeWx4ETY6MYhtpXE7uNYdLNdci b6mQc/JrldbFc4aYYjTM7k937ZDOwti5V3FyoSmSnjorb2AJTLmcKgD5ObdPdiM3 hv/cJnCKQInN0zhbp/cC6w1OSfFLi1fivrmZyLUSeqpQVI7tBOJyBwFME+UNBwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBTHrnqvQbtL60AQR+SplHiWWV/E 7zA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAHUiltQfdiOFEJFZNPOP 9h5gZL4ejeD8epagmsBLvR8rPYAUU+JcbaCf88j1ndz/9S4lOBzijmfb1Slbduyz LTVJpKfrrPvfzWn9VdTuzp2calejVu2m0+Sm9jnNYf+dn6jNfKSaK9x9pf2uYPV3 +SdzOCnRoQ7xxqZ0NeIlDoL61+IVMhCl/wignAsOY6+j2RXVQGO7MeM1GsfS4oA0 YmWAn04vd/iIE4ZEjFMEW0JEUH+TC0CsdpVNaUIo/S+5bCi+N/MOonuB+YCV6ivB GARbgRhlS9rB8vmKuHlyUJQf+A5noNr0eXC+4W4h2u0NnCRRWM7ZO0LFd5EuJe92 AOdTR7aX7zHyqtKItv+2zjVGbKyzkDCfSn8n7QNqEfHcFbk8eyLL1/xE6RPGxIbZ rH2F5cvZ4fGGLkXAoqz/ygF2g88DxAlWrgBRQqbTUVJRgo54clNViKVeMG9osXgG DtwxBG/F6eBNVaYwFmb3pusK4VFD2Or8DUpwvqUFtF7FA6/+hScfVSfJ2ypeB4+h 0EK6abIdryoNLpOlUq9a/vNXtsQiDFijZSq1191xvqlZJpAQb/zTZyzrr+Jaun2d Gw68y738e1/BE+eoUej4RPokJGOggYS1xliZlEBRoFFU/0eti7VdmPk0Ia4iAlJU OOUqLcBDG703dip44geF1LmU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIQQwlYfi2LQn+k7fBD8x8fujANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDUxCzAJBgNVBAYTAkJFMRUwEwYDVQQD EwxGb3JlaWduZXIgQ0ExDzANBgNVBAUTBjIwMTYwMzCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAIjjuy21rUbvTGKdgWkqkPWFJkpa5ChLV4Zi7KMkElzI izgSgk1/iLZrw25faRMWG3hIpvDhAnUwFb/sTq0AI2mb9qIWFB0NqPu0vKY5dfM0 lu9uzOVxaCe360c9ncR8rKoJAiGRv+HUmqsl0qgFfkX2obit/r2W2glrNN87QE3M WOWLj9cn/C1Uofpuzz+ItPZBkk9l0clAx5P8wg8kUHN9EkITOOWljzJ2prnrhOlF BEzfcanoBqDwXYHMWQyyMMP8/R6G1bGSfFkHEaVxsoIFaoSoDHCcwE962wVU82mQ qghQWh+J1VcxRFWFsV7HJrb4A/xcC465hGcnl1iQ2Ncg/UAF153b84En/KL/ezVt +J/oMc56ewjm8seoT6BX2XTCJZRFgx9LCEWIn9rl4LM0ezW5y/0pmHk8uKznb1lV H4W4DfuZkwNOG7pZnJv/73pldEqvDe7gjCOYm/PMOVL1G/+95NHYNfN83x3JoHYR b0xcPqk53g942ZLzwjiU/wflyLlMMADCFrpDtrzbDig+IAW5kmklZtRTSq53R2ZQ cPhb9ZrXmWE09SOB33Ylpuk0TPGF2w0Q2i+8klA62AnkFoB/pZa2pkQvtQTVCc8x TanJG7Wd6aGCXYOpRSOVUUISVmE1PaCW2aRI7lO6tnnFiOKXgXujgLOhaXGULTkh AgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw QwYDVR0gBDwwOjA4BgZgOAoBAQcwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9z aXRvcnkuZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFO/YANFtla1hXeOL5IT+P3dY Cm8nMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUv YmVsZ2l1bTMuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBS4vGwA j1sZhZ0lAZzwGdxAjtA4KzANBgkqhkiG9w0BAQUFAAOCAgEANaTTqnUIKl8cltzo DnEJfXzq5N8CbT5hy3mqa7XK2SwjoFACMfFcLjJao9ybYLhmADSpNT8N5I5pqew1 C+V6K7U99ycEA+ghYgI7Kqxd8Gu+XrR8rCXL6a1v3Brbqf4thIEEKivtIAO9j2xe SiRC7HRLIoUEzeSeMCJLhfpWQ/mWg814T7quwkNmthz9n6uJkCom4ZiD3bVt3+wm iVRELMqhrMpA+IFQXqFfCbRwK4esfghXYAn7y/1pS+4Q2tpHkBiychnyvK9u9ukm VnBWHPgLQFBZ5vdnVUOA+/nSB6OEfZFczSV0ChX0b6qE5o/Jv7QgCuct0EQtducN K/aJm0o8BITYgLZQNa5B84eMwpQWE4MycvI1/W1FRXUdDhfIJFJ8A5wAFLkDveVK bVyAGyDV8YXIcvhudQjLICpeyHALJQpmObHool8FLJPl7Te4N+OjNuDESF9CeBrn ff8MIwRl3k5gEEOPom199Pl+Kp+yc1p7XY9mUDp1kQ5GrhGUIwfPeUCL8YpMHrAx uD9bFxradTExpsOH9PHJtKUPvK6VqRL2KtiTW00iBUnInFUu5mSNHMabjEG26wVP NzQraaQLrI9Tn53jfHEsyWppHp+S693GllD5XK9pXEtQQ2nasdE4yI73i0kn3gqV 2rvcg6zvsc5CqSGWqBlA0gfqnwk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQXiJEkYkR59wVC9/jJhcOpjANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE2MDMwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCIwEF6bWkkuKmXtnRqC72xqDcYF76rvS2HXqBOi1y7rzLj Io7pLjacCWnPVEkNtnSfGFh3US3kdJnt01OaczCqp6QTAHOae12E/5uQezYBMVWM z2OCkykYJowmJdAURy5Zip+RN7A+GAKtzYIdsDpCvPwFnkPlmFSdePQO602JQXLM 6BCFXNaHM3Z8Qdk9XRp2n4bPqUo/Wp9RGRkGoKZVJ97Ci2jP4SePcEQk2JG1ZaQt LwvSuNHPQ4QL9UDI0M+H6zxElhQLdsZWwsSinxw9M5D1ouErFjWpDAKBPFCP6sbd gVn5pIhHowYNtbxYmFoBc6a4cKrMoe/lE1Lq6YLlrPfsDUWrLta4V6PYs17MejlW Z7fIp+UAdntbjeYPxyoZ4WtPUm07ZaYb0YZK88Kdj0gfWJDCbcYhzsfX3yKy+/yU 0f2Q3EjSpTEkCNZKxfKPAv2JR2/acWARX65lqF16CSEZ3V+U55H3T1aLCgc34Y+4 BHfvk10V4EzRp2CcXlBWu6H04rsml0Zugv2MQa8Erj/oii9fK/S9Zt5keXYhOX7v JMc4npIVT6/H6PJRVlozvXGkORBSVaEsK36Pdf65zfpuTvOHeMEM6Oete1zUAQLB wPICKBpRq7AaAFFEnr//WbRwDfAGehVfOK8wnyGON6/T3fnVpwTvmWlRQqb4iwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQWX+CW5TUe8v2depOjqnbVYyip qTA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBADKLODFWsLNeAfkV+JEd bIk2LzaQfa8WVYPCU4k5wfi0QCy8oQnHlmPcFBPgJIVu+iHDdcU4iY/4GVQRL2jN 7vA0dP/sNPm/3vNKV+ScZ92Jv4TRSQiyg8/LlJ3amATuRMyAhW6/RwcBmUJgIqIQ dJyxgH044LAWrZgbLLEW72G6U/Heh/p8ynVy/uvugXkYq6zSL8KbAOXeitUQU2fZ r3lw9i57qLUbTQ6VvXycr9o2FEQZh88JfApG6RIzLDrXtG7dl5UkN7/zJWWWYMUr OuCWKMYmvQU+bgBz+951F1o07TBh2OHMQXlxYkdlXhEc/Ouf2w9PFeFctBPlraCo SkbE+98jF84sw0hs59nB91+ZroTjxO9p44u3XPtTGqv+8dL+hoFOy1+TrS1M4Ebz PG92x5doV0fg+/yfCj7Coq4gpEeOCYVw3koQiafOaqzbjViJ1W9kfm+wHT5y0jFL yfQWnB2vpiT8NeLRpzeYP/VCjmkq4BIyXgyFB1hcnOyObW4KyRKsTViH6zJduMcA 2lYxRiUduHkxeIVZBV6T28ekf222hgYBAD8dj+bzdZiOTpEOKIzJdvbrmG1+LOB9 QhcePpbJOs8WcNdXUriMQWHXazj3mMtnVoPazR72Oz4SFoK2AdintK9aA7zCZ6a5 OC510Qd91F+fA3pQRcp9tEUz -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQF28JJOwI7p/WsFllzAW53TANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE2MDcwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCNKlh3nj6C82utJM4HlBey45QT3E+TCzajxzfgxjsHN1ac wP11YAGvRgJ8nGdi81zLU8z+7Qi+kdlpo4SL5Bh3+OO3eR/S57CufRXf/WkXiP7S 6Y1G+FMk/np0m/L3sV3S5qSt7ec0WanqtM+Z6E5p6kf1+s0/DV26hxN1+cE+k51A wS4f7MTk4QOZC3Fdf41WsZiOSFzRpQavKqq7DN3KB377zdoXUhY0q5+1Kc/jA0xu R0TlsKY2k5N5ZUKgUr6Q4CMcUZwV6PQveJraALGKnpbRI3uEygSt3UuJ82xA9U5A Fvo/IuZFWugB887Ue50FlVisllo1e/pSjRx9yKbJqop0Nr39fRK8aMhuR5aevIOw QgOk1dSsU0lMSB0DVeL+gJIj+D0EjzdoDRdaZGseKbVvukGZVfTVpnx6D+n+IuHD TrRqMTQZBQMkEdXOOqAQiGmTgJLlJoYEWsfsn+UCeLH/2+w8kIuMIMU+TLFXqThY tWkBfPR9e4PZXlGvfHggar2Y77c69lQdHA8JFcYcPbdY7rls9kvzdwI/MvsAIl6D P7+NEzCxwR1cwV/iW+yrg5KCHcznYqqhIRmWWa2C+G3qdydiAYs8zJ0MzUMLnkR4 xE1PLhPWHF/aAWOkpZGE2Y3tyaTwmHSspRHtGJ7GCKReerT8urreNm1FiRr+SwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSMg++gD//8qW/zMIFjMxpb0VWz qzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAAVaA+rNxWO+hgB6ukBM 5cKqnQ84aQaFk9tpAP6E/77tBuA4UeqpY6NktGKZaPa04PPmcz6f3cnyM1ydGLtJ ozMc2ABFJHswU0T4gN/sMNNqhAt9A+lCFFpwxH4LIoOV3S68mTIcoONwqY9zRC3r qGqno/zEw3xfVWgRAIQy7daTt9yBY0+TCytKWZkVYdQD2PHUbdxbk7n1yx+u5fQ4 YBItY8Aw08u9gDqcLUm8teI2SkeBXXirSnBePtU5szNsaZDI1bB9fsGpIovkFjrL AY6ltLqbtI07181kOgxYARJvv73ig9qsPKi1uYCtYbG5MCnPFFc5sDFPLWfUX4vh cJGNW8HJdZqE+y/uhw6WX3NdLB/PzXJQ9CPGUiq7M8+pghihIEBtgEjn2ZTQqxPY 1ZqrXtaJEAmk5rwwLV5BQQ6ZwFJLyq6zxBfX9tEUIGaU5TRz9jHTM1ckjtf+U3HC 4YxwhIxSEE/gylePaPTDcTAiDNu6vCx6zQSD9GQQvUKL8mHZJRzk2wSuR34bXV2I v533SIo8pkCaWka5Lb9CBvxAmshLXJQWOUBPVG7Nsx1HZuHT8v6s3z082B87x2lT 49J6RItwaCvkN6Z1jC6FWWWyHtu2v1SXaIwXWS2sITFvYNfamfhU0a12WfWuvIfW Zf4NPU7ZHaZq3x1B79mapuE2 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQRz2maXwXx5KSQZSUoOrCKjANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE2MDIwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDHGC4Cpvlt3sbAmTf2gEn6wYXCaBTwmGytrIpFlz9kucAI ajU1wtlWXdhDdchtgjwxUmNq1sWknOuSAyS6iecOkAS2WPWuwaFy1ByaDZ+9o5Cw 2diUQq1WgC1oPbvr4ipD2otPhDBlcU0+povo+1Q5McYtjW/Lf1z2B+2hL4WaSsrl 7QrUOCXCeFgQRA+Zmyco+llYonN9I2pGg2KTrie/yysO/Ay/0XJ9DBR+g6tKFn66 uZiUTsopmGy2UjsKBD4uzx5RgotIptw8V0Zcps5i3TkU+BSnHLZoS73m2McJdwFO kXgoj/8bOM6PCiV1M5ImYybRp+0axnfQKnMgCNA8xtaIIqk5TLmwtmqZUMVpjfik ztpOun0QzC2rJFFqdkoI5rq8RT4hxzgAmv+9gGoj+OueMJUrlXUeE87jB2903hab WzSj5oIy+zOohrqAToJaE5IWQwLsomeVRWhSN52OtQdz5H9jUf3T7V4jXUbFEEAX rd/qyvdzDxidOrrXYw1oaA1q9OVN47Yhi8kcjvmAK+RIX3ygDn9eW6Y+h4001Diq +uIt95T4YH/f09Vgh5bppmbQeRob5ZCx5Ry1desYpoFlCQwH3Q+TWkrXiTyWlQIp d47/xwtoj+6rHE9cxKU5DiHNLVkxJ7NflpcjbCqo825v21eNgI3m26ULohYMCwID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBRhneFJhmLJtfaYaVsXhapRNOQQ ITA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBACU9AYG84FY+Risl+7hv hm/unaL1VLxu01wc2qyCRhYij1YO53rVVk/vRYVZ2Z6to30CRdP4rpIjNdn/udxp Foq6sSu/hqKouHqyNlU/J3xjWI8TtCNwXMzHXPshnTbHCf+lrIvGIEXGttHYNi/r J5cT0FrY2OxgFCFVRG9HMGopL1UWl2GcjF4vNlDPfrMIHrOeI7u0Oe/O3m9i4ZQ9 UmbhuyHnq1W3U2B5ctJalVLOb+iplVT6lZub5p8IHdHHBOnzmR4F+8YIDwu3TaVR VtIIixCDq4reG/Ve4P94HtH0IAAUsP884Ny5/qLDJnqhjtCU/tvcnz0UbduYdXBw RhMe+t+eV1PJq6IeOMKrFofXgFKYRIRO8flE0iioH7eG/+aqmv7ajxK6q54HiHgs cLclIoYh3Mz1XFijaQ+vKLEWYS6iE6bGFhBtCNtq7q7EYEr5skWdbZm+GxUdd82r wobxtVoQjahsBVyVh9SGGvYSGel/cqxOWkU8MSSmdtwp3pXYK7kDD73IzNAEVmmi ApeUO8i8cb+2bn/GPY8dJA7nEtoICR5WXjNz5y4qCfEzTIcqbUr+rYjCH22sxo0m Yj5Tc8xedUrxHRdniUDwjVSkuf8TzgSnE1EQPNyZO3usdlo6ePlSiygZx78v+LQb m38/YzhLY3QMxPXOrcmiUb5n -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQepvq/VwAqUhlX1z0GIblPjANBgkqhkiG9w0BAQUFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBMzAeFw0xNTEx MjUxMDAwMDBaFw0yNzA3MjUxMDAwMDBaMDMxCzAJBgNVBAYTAkJFMRMwEQYDVQQD EwpDaXRpemVuIENBMQ8wDQYDVQQFEwYyMDE2MDEwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQChrIe6Jm5Q76czOTG4QMTzpo5yi17ZDQelWqH2OuH4yC/z +SXXD+IZxn0F1HPbHaHlpkgEsAz9/1XvArXJVEkv6qo8vXqQuSUZ85pH2NYkYfJN NiBLFhdEQeftudIE473Y7JWzNcknW6auP4wQCDyJca6jjNUWB9nU1NjwcLRRtFsW rtOHiluD6ONaGACLrB+25yxsf5vowgvAYACp+NGxF/u5+mME8jBSuRwpyAN0HV1m rc0pK6P/mZ3npVm7aHSh9nqfeWI4IRWKTEO72Xodl2cD3nhupNQ3YRYJ7NC6LeZh lUMdt4jkMRY6B/ahhRE7EUjko1Mr58Q54ghOQfXQxZi38QWH6S72lgkaR5zeEWEN JS/KAujWP1u/epCRiUZIcX92UaOxhKecV0y0w8vXg7xNyIDOKLSu97PbJul42ufv d0vZ1wZYGnmxYZ2G1H3wGXLgruVVQSgn07Y8YysRjzcysBX57Y82YnjVd1m6QfPW HejxqBBXflmpwmQru9XeAF27YMF4Kqw3x0FmyWJa3X8z/wulY3wOWv7xfyaDskQf VfAjCN4DuTmXQTf62bBs6uOv6zBvTxyRlgq1ZfNPhMRa6sKEg7dzRbMIuwwXkSl7 zz5k4uWuONycSmzGyFbmvCEgVvEorgq/d80iWmHDXaXzCpSpz1DP85w9pNZPZQID AQABo4H4MIH1MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMEMG A1UdIAQ8MDowOAYGYDgKAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0 b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQIawhY4uLXdDbFQEpysTq8mXOe 8DA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVpZC5iZWxnaXVtLmJlL2Jl bGdpdW0zLmNybDARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUuLxsAI9b GYWdJQGc8BncQI7QOCswDQYJKoZIhvcNAQEFBQADggIBAKQBjZoHYc8f1VY50EUt WA89h0t4Z0dZZsbSXYFof+2kSjVirA14GN+4cijJXaF/n/lOJlDWH9Zxlv8b/4Zp IqxGaVtW0gqCUEO5N/PINe5HGlMSOIveiOWvR2NbsM1Okn2nnExbkseF8CCwoWYE PgPZgbhJuSAHNhlIi0N7iswu+DjJH4xNFCltv8hK5fGA+27lJ4cuP9tbZbiNNuMM K/1QY/2YfdYpxXOdNfUCmxgeZf6qwk5WoattZ7PGgtHimBfez0dwUTzxo+kZym3s iuhBsmmoxhQArWqhL9oFWtJOSFTe7klJSqdwRjq+LiZCBD0SKEkozqktPfGLFHT8 docerbsJSNABAAGVT4/nVGNEk8hDGINRdugKcYOybzMkzb8/428zT6IW3CnyqlX4 YvRkM7c8WPRoNoIqLXhVenowlWO+/NLvJvonXHSiSxxZjdYkhKwnrPhEs8qpYdNE ZoEQk059K2aqIP6UCEWHC2FC8bNeOAH2Zdvl/kNvaWp5wt2MaLeAKfNR0t49+yu4 8h3CkCmETqF2he2tW3tmFD0znypjNT2aQbnj0wZbdDTseEf7Q1rlPFdmBCc6LNSn 7p1W3sP+iczoXSgwBUMdMwZOY/Y++ZqdQxzpLdDiEOis7byuyw0HudNqApKaCl9X YHT5d1GDGtkrGx0b+63N8WSG -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFTCCBP2gAwIBAgIRAPlPiLTzBzmpCdNvjtZMWaYwDQYJKoZIhvcNAQELBQAw NDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2Vy dGlnbmEwHhcNMTUxMTI1MTAyNDA3WhcNMjUxMTIyMTAyNDA3WjB7MQswCQYDVQQG EwJGUjESMBAGA1UECgwJREhJTVlPVElTMRwwGgYDVQQLDBMwMDAyIDQ4MTQ2MzA4 MTAwMDM2MR0wGwYDVQRhDBROVFJGUi00ODE0NjMwODEwMDAzNjEbMBkGA1UEAwwS Q2VydGlnbmEgRW50aXR5IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC AgEA0lTrAwYaOJpvbeSPdj8l4DVUCP2td5ZpJ6YBETkj0DEyairmzh+QdoqJusE0 bPu7DeivGYLaIfZP53fVi+OM8/TfiQK61B53kgwI1tL1nEhdLd7G8G7SrKs0HGSo fk6KMWqn4t2kVkkvotuH5RzxW/TrYyF9kUrBvqcAqUigpPtNv2w6JRmEN3QpYYDj G4Bwz4J3RMRMtq5z6T1F55hX1hFP7FcavN+q4GiJ6m7LMhwiwh7nHU71lmLhUrYH AIrygN/eQobCnV8HiSxBm0eFtnJDXWUd7KdkdJ02E67aclV625Vwzw+0OKH20XBq O4tO8Yy0TuJnZQGfA/tSxdfp7hxNWlXFHvkaRGTfj9y6tv9WVZrgcNbaXR4c3gjE /GuhGDCqt32ogTKu37cHMBxCRXCgMWEAyz4tBDVT8/UZzDbyFJOe63aroZdoohI4 XkEj50fYT6+AoEl0UoctswbPzq1PdIzXb+u8ki4FZK/2sTwCKJxifplzj9eFcv0m cEVyYozVPAPzAo1aksK1/KWSCdHB2Odo5dhLlyiG/AmVcdA7NlQEPg6fSkJcbZV5 kNnmkI9bgQv0iVFO9y0s1AlzfFcIrFCLS/A1UsL6+59H1ifSubehmD4ms8At83/N jyAjEJCs7UvIGkSFe54ifSnIdB03KZaz6cnFIwPy7ThPU4kCAwEAAaOCAdkwggHV MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSl Px4kTGz4i9IbcphGUMrohlW52DBkBgNVHSMEXTBbgBQa7f5BOZC0JFm+AfJS1UX2 WjncEaE4pDYwNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8G A1UEAwwIQ2VydGlnbmGCCQD+3OMBD8lI/zBJBgNVHSAEQjBAMD4GCiqBegGBMQEA AQIwMDAuBggrBgEFBQcCARYiaHR0cHM6Ly93d3cuY2VydGlnbmEuZnIvYXV0b3Jp dGVzLzB8BggrBgEFBQcBAQRwMG4wNAYIKwYBBQUHMAKGKGh0dHA6Ly9hdXRvcml0 ZS5jZXJ0aWduYS5mci9jZXJ0aWduYS5kZXIwNgYIKwYBBQUHMAKGKmh0dHA6Ly9h dXRvcml0ZS5kaGlteW90aXMuY29tL2NlcnRpZ25hLmRlcjBhBgNVHR8EWjBYMCmg J6AlhiNodHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hLmNybDAroCmgJ4Yl aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hLmNybDANBgkqhkiG9w0B AQsFAAOCAQEAq05OtV0WmCyLpzxxcw98xPV8OiY56TQch4KEGotY1Dfw7H0nM7la p/6kAZkUwfI4WJt4piRedJHgasQOj+aJbpxCYX7Hv7vCnGDKZFC6c/vY3B/stbQR GTl//7+iKB2fgB/FoQOohrZqO77C0tqp1KuTfCSq/XAyZNtXoVn+YDaILMUHp2vs lSHh131XPGjkloeXTMLf/+RcVVimMyAUjwdfcIUQEGU4Z5suQNWiwCU89l1UY7qa WC9As/GqWo3vqQG9ALG+HBFBr1HSPnUjW88J6CYUVxOcTDfAj3eJtvUF/3dFjPl6 jM4rAJNeg+LqU6kQ+z/50yhrdgJ/A8cZiQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHDzCCBPegAwIBAgIRAJVIG2zmMiFC/oSZgw58WuUwDQYJKoZIhvcNAQELBQAw WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x NTExMjUxMDI3NTRaFw0zMzA2MDMxMDI3NTRaMHsxCzAJBgNVBAYTAkZSMRIwEAYD VQQKDAlESElNWU9USVMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxHTAb BgNVBGEMFE5UUkZSLTQ4MTQ2MzA4MTAwMDM2MRswGQYDVQQDDBJDZXJ0aWduYSBF bnRpdHkgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDSVOsDBho4 mm9t5I92PyXgNVQI/a13lmknpgEROSPQMTJqKubOH5B2iom6wTRs+7sN6K8Zgtoh 9k/nd9WL44zz9N+JArrUHneSDAjW0vWcSF0t3sbwbtKsqzQcZKh+Tooxaqfi3aRW SS+i24flHPFb9OtjIX2RSsG+pwCpSKCk+02/bDolGYQ3dClhgOMbgHDPgndExEy2 rnPpPUXnmFfWEU/sVxq836rgaInqbssyHCLCHucdTvWWYuFStgcAivKA395ChsKd XweJLEGbR4W2ckNdZR3sp2R0nTYTrtpyVXrblXDPD7Q4ofbRcGo7i07xjLRO4mdl AZ8D+1LF1+nuHE1aVcUe+RpEZN+P3Lq2/1ZVmuBw1tpdHhzeCMT8a6EYMKq3faiB Mq7ftwcwHEJFcKAxYQDLPi0ENVPz9RnMNvIUk57rdquhl2iiEjheQSPnR9hPr4Cg SXRShy2zBs/OrU90jNdv67ySLgVkr/axPAIonGJ+mXOP14Vy/SZwRXJijNU8A/MC jVqSwrX8pZIJ0cHY52jl2EuXKIb8CZVx0Ds2VAQ+Dp9KQlxtlXmQ2eaQj1uBC/SJ UU73LSzUCXN8VwisUItL8DVSwvr7n0fWJ9K5t6GYPiazwC3zf82PICMQkKztS8ga RIV7niJ9Kch0HTcplrPpycUjA/LtOE9TiQIDAQABo4IBrTCCAakwEgYDVR0TAQH/ BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFKU/HiRMbPiL0hty mEZQyuiGVbnYMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of1uHieX4rMEkGA1Ud IARCMEAwPgYKKoF6AYExAgABATAwMC4GCCsGAQUFBwIBFiJodHRwczovL3d3dy5j ZXJ0aWduYS5mci9hdXRvcml0ZXMvMIGIBggrBgEFBQcBAQR8MHowOgYIKwYBBQUH MAKGLmh0dHA6Ly9hdXRvcml0ZS5jZXJ0aWduYS5mci9jZXJ0aWduYXJvb3RjYS5k ZXIwPAYIKwYBBQUHMAKGMGh0dHA6Ly9hdXRvcml0ZS5kaGlteW90aXMuY29tL2Nl cnRpZ25hcm9vdGNhLmRlcjBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNl cnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5k aGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOC AgEArfWJJUSj21DuIP7q021HUkYV6dXH1FN9sEaOD5156JHV7M4FqkyubCjgfswL 6NwW0UO2xanxFdcKPfx14M+H6JgwqilzW3InAwevKIx8+UivCpV47rDQe4/Yd//x bG0sd7+dMCvCAj7gOtlap/h1VJhwip6YVkaCp+q0nBbOhEx+azqdc9Urh7eyj3no /4uJogc79vhrZ3QYm0AfAqosjH0IekZblyNOrqKR6NiMqGGNuWRJlg8rpkEEakeT wIofh2lByrvlKIGcXRdl/oFhxDiC7Q3sCCpwq2VEmNAxg+ZWh4OnJxLx2uC8tDgN 6IIH+4TztUyO+KUG1Xnw1Mlg2dQKqt1B5/xvVKPOG2LNcUCeNAt7QmgkIvefsuxr HcFI2qZ7I9spo89wje2BCY1ey0lkePGyzX8jy2CLTrFvfGhtw/S28L9oryrW5XS8 J5ebAS+w+G2lda4rowb8EOjhXDVYpA93yAB5SWjwWLzjcVn2WcJGOhEp9iZsVUDn i/0b/JL7ovqtcPlY7Z9RtAg1SXY0SUc/CEVCbQM25EPcoNryEj7RivjYSZeJdwZ9 /UoKq/be9dHqssrr1PusyLptEmUjV9a4d91NHiRwbHboyX77LJXj9M0jc0WCwSbA yViEXJZx1jLAjakWnh5bTrmipLf7Mc8Fk3xw61zpX9ow1gc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGEzCCBPugAwIBAgIRAKsHje7d2scjBfXtjFCE+JUwDQYJKoZIhvcNAQELBQAw NDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2Vy dGlnbmEwHhcNMTUxMTI1MTEwNjM1WhcNMjUxMTIyMTEwNjM1WjB5MQswCQYDVQQG EwJGUjESMBAGA1UECgwJREhJTVlPVElTMRwwGgYDVQQLDBMwMDAyIDQ4MTQ2MzA4 MTAwMDM2MR0wGwYDVQRhDBROVFJGUi00ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQ Q2VydGlnbmEgV2lsZCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AMKObo8+zKbR8c72LGVWbQkbBefXUKiFNfBqfAiXvq8sI1DA5eVfbtPyoZUng34X P2I4kAfOe4aHkWnN9vNZUwUlYTnJa8qK9bBGdz63j1MOV7WCf4jRRhnRmx6NHH2M e7xzmbYitcg0rKmhz9CnDSBWqhtgHkgjtFFiUteSCMB1hb3f+dfdGFl464HCwxff nJaKC3Htm/j320eopRPO8BvzRo1DnC9u28l51wI9qAC2FZD5tQ5uAqZImj7o4HdL EqA5ziEyYLHa7nNwM6jmGrhp6D7uGVAhQxereOCH7U3Ge1I+iBjGqw4sMtPduCc+ 1ikDXnod8M4t4bvg5YykFmzkNKL9XcohRv5DsV4ce9Z+aGlC9c8cREHd13I2epK7 XmIAA93NhOHQ88p+FRFWhOEvRZGejs+KYkq1/usNE+EqJQ1TJZ9SeeRGSV3Ytbw1 Xn7IqqpwMpJCmAcHLyXL/9Z2hFXDiKI6wnn7eaKWELNRIHoIaviLpQKOPn9V73Qr vk/ywMIGQlzkU9kemgVneG6fW8FRp7Hmi7NM4D9OJDBMun1K2W+KTpwTHX6W5iA3 4yiPsFTHIreipI8GXx1enz8PYxreaMANEC55uMRJE689jYRRg0dM2ixuLRhsiS8X 6hZWEfl3If4MAA4N9VyJSAGQMlZyxWszCcSPRlrDLSEXAgMBAAGjggHZMIIB1TAS BgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUjnwX t7z3w7SY1rY1mSIqxMOeJGcwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo5 3BGhOKQ2MDQxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNV BAMMCENlcnRpZ25hggkA/tzjAQ/JSP8wSQYDVR0gBEIwQDA+BgoqgXoBgTEBAAEC MDAwLgYIKwYBBQUHAgEWImh0dHBzOi8vd3d3LmNlcnRpZ25hLmZyL2F1dG9yaXRl cy8wfAYIKwYBBQUHAQEEcDBuMDQGCCsGAQUFBzAChihodHRwOi8vYXV0b3JpdGUu Y2VydGlnbmEuZnIvY2VydGlnbmEuZGVyMDYGCCsGAQUFBzAChipodHRwOi8vYXV0 b3JpdGUuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYS5kZXIwYQYDVR0fBFowWDApoCeg JYYjaHR0cDovL2NybC5jZXJ0aWduYS5mci9jZXJ0aWduYS5jcmwwK6ApoCeGJWh0 dHA6Ly9jcmwuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYS5jcmwwDQYJKoZIhvcNAQEL BQADggEBAAl2DvdTzWlpYnL+s6vfAgpnRFL0mLIXpIP692SVPznffIyWyEhdGg/x NCylrNjouJK+aMZKCMVP22GOtQnGo7ANQHd5TWeulrose/XYSqCKNnhybEuclivO SzahUacthq10KqLGGvookK+vSVNu7bfsrQK+1aLcd3tA+tmRPTqx7IYoyMr3Syv6 MCLWO1tuwa4UEWyDZxzqSxaf8zmz+l5iURjcIn5Qthgu/PC+tA/LjioQ8+okV6qC 4CRLkW4wgUH3Ss09tkCBrpr+PJo02Ktrj1VsJd42CKElsFlXoHxwye05K8mMm8Wt E/GOkOnWICpBAaQT0na2YmgUXrmyjdo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHDTCCBPWgAwIBAgIRAONy6RsZtvwn4cQxjMaNCeswDQYJKoZIhvcNAQELBQAw WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x NTExMjUxMTEwMDBaFw0zMzA2MDMxMTEwMDBaMHkxCzAJBgNVBAYTAkZSMRIwEAYD VQQKDAlESElNWU9USVMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxHTAb BgNVBGEMFE5UUkZSLTQ4MTQ2MzA4MTAwMDM2MRkwFwYDVQQDDBBDZXJ0aWduYSBX aWxkIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwo5ujz7MptHx zvYsZVZtCRsF59dQqIU18Gp8CJe+rywjUMDl5V9u0/KhlSeDfhc/YjiQB857hoeR ac3281lTBSVhOclryor1sEZ3PrePUw5XtYJ/iNFGGdGbHo0cfYx7vHOZtiK1yDSs qaHP0KcNIFaqG2AeSCO0UWJS15IIwHWFvd/5190YWXjrgcLDF9+clooLce2b+Pfb R6ilE87wG/NGjUOcL27byXnXAj2oALYVkPm1Dm4CpkiaPujgd0sSoDnOITJgsdru c3AzqOYauGnoPu4ZUCFDF6t44IftTcZ7Uj6IGMarDiwy0924Jz7WKQNeeh3wzi3h u+DljKQWbOQ0ov1dyiFG/kOxXhx71n5oaUL1zxxEQd3XcjZ6krteYgAD3c2E4dDz yn4VEVaE4S9FkZ6Oz4piSrX+6w0T4SolDVMln1J55EZJXdi1vDVefsiqqnAykkKY BwcvJcv/1naEVcOIojrCeft5opYQs1Egeghq+IulAo4+f1XvdCu+T/LAwgZCXORT 2R6aBWd4bp9bwVGnseaLs0zgP04kMEy6fUrZb4pOnBMdfpbmIDfjKI+wVMcit6Kk jwZfHV6fPw9jGt5owA0QLnm4xEkTrz2NhFGDR0zaLG4tGGyJLxfqFlYR+Xch/gwA Dg31XIlIAZAyVnLFazMJxI9GWsMtIRcCAwEAAaOCAa0wggGpMBIGA1UdEwEB/wQI MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOfBe3vPfDtJjWtjWZ IirEw54kZzAfBgNVHSMEGDAWgBQYh1bgbnfuJDU8TnOaH9bh4nl+KzBJBgNVHSAE QjBAMD4GCiqBegGBMQIAAQEwMDAuBggrBgEFBQcCARYiaHR0cHM6Ly93d3cuY2Vy dGlnbmEuZnIvYXV0b3JpdGVzLzCBiAYIKwYBBQUHAQEEfDB6MDoGCCsGAQUFBzAC hi5odHRwOi8vYXV0b3JpdGUuY2VydGlnbmEuZnIvY2VydGlnbmFyb290Y2EuZGVy MDwGCCsGAQUFBzAChjBodHRwOi8vYXV0b3JpdGUuZGhpbXlvdGlzLmNvbS9jZXJ0 aWduYXJvb3RjYS5kZXIwbQYDVR0fBGYwZDAvoC2gK4YpaHR0cDovL2NybC5jZXJ0 aWduYS5mci9jZXJ0aWduYXJvb3RjYS5jcmwwMaAvoC2GK2h0dHA6Ly9jcmwuZGhp bXlvdGlzLmNvbS9jZXJ0aWduYXJvb3RjYS5jcmwwDQYJKoZIhvcNAQELBQADggIB AJ2q+ozadUwF/b3DvAUsSI71ztZiyZIQq25MpNbj9mtFHq9IByAXj1XTEBDSVmnZ qQcFFKyDcSlrwyTUaNyC2Up1OAA/S13ssTuLwW7vW4SmEIj1nAKenm1BwbRj4ksB 9ZizAYE0CVMdIDzFqtYFGUyqTO/QF4oiDPoZ4g4yI+6TnFwXqfl5lPBgYCZ/FvoL 9NfysZaBpFPHgwUJeoq9sRrLIQ97rg+e1Ro5eNpyNg+tjI7QCwoVOIItGgW+0oxE aTlf8BEqU4+49e/mqjrvB+SI4pR/gRMjCkAmsO/tQnxN6EG9tMMUPOVckfRLA4kE tVeUjyG2P+c3RhfBcZLwNYIV3JynXPbncfM+3OYjkluDInekepy1dMUs5fgWodc0 HIp7l7ebdEIoxAXXuBroJF/i1U1SsJ4oSKeiRcBG1iZI2LHa5oOkK4RJqjlLMqH+ OgfKP1i78GNESodWYe+yude8QuA3ema/RlbKYCxdkzHr1jSDUP/xWluV9/if44fs W/f34OIHcJH2zSBbPfqhhLO0rQbYxBIbyvEjnkAV5kaybC+fOiVjAbh2x+ofb8WP m9/3TZ9K5Xpg61tgOHcu6/DEgTDn4AwzomJ0NnKGjqmkYG+mZjeedGq5l4mQNUvK REJrdo9jxImhbHZW/GWHkUSHWHIhKbvBk2JHz8O+r328 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFjCCBP6gAwIBAgIQb4L6KKzW94S7WxILqHNnrTANBgkqhkiG9w0BAQsFADA0 MQswCQYDVQQGEwJGUjESMBAGA1UECgwJRGhpbXlvdGlzMREwDwYDVQQDDAhDZXJ0 aWduYTAeFw0xNTExMjUxMTMzNTJaFw0yNTExMjIxMTMzNTJaMH0xCzAJBgNVBAYT AkZSMRIwEAYDVQQKDAlESElNWU9USVMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgx MDAwMzYxHTAbBgNVBGEMFE5UUkZSLTQ4MTQ2MzA4MTAwMDM2MR0wGwYDVQQDDBRD ZXJ0aWduYSBTZXJ2aWNlcyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBALPM+7LpWBz9wFcPaTc3xnB+5g0XrnptB0EPPfrR04vO52Ykm4ky1d4ZLd10 tbM1fa1RqNSOVWWg93O4pL7zCFKlz6JV74ZZVhHpEAwzBwv2oPnxvVbxtSN67xsS Y66ahUYxjzs8+3FhmsiRxqwnTYvK2u70uglUvRisOKyTL/M6JnrC4y8tlmoz7OSa 5BmBMVplJFQtvmON6N9aHLvYMz+EyJPCbXL6pELxeHjFT5QmIaRamsr2DOTaCjtB ZKI1Wnh3X7lnbjM8MESJiV2t7E9tIQNG0Z/HI3tO4aaUMum3KysY5sC8v3vi7rry GidgzHQhrtP0ZXWW5UH/k7umLS/P/XXWnCFpc2Lxa1uDGfc2im7xibRoPP+JNZsz N76euFlls6jyEXAiwnVr14tVVTewLK0OWs5SJHpEKp8PGMZRDj59EmMvokWwzL6Q zNZ6vVAp00oOm05sbspNY9+MFqGKKUsKvhFGEa4XmRNxDe6KswLcjPZB+NKHZ0QW Fd4ip5C5XmEK/8qIPjwVr9dah9+oiHGGO8Wx7gJAMF5DTmkvW7GhqCKj1LmHnabj zc8av6kxWVQZi/C7HCm9i/W4wio+JA2EAFLqNL3GPNbK9kau4yPhQt/c7zxzo0OH nlsV4THCG7oOCd3cfCiyfQcb3FBt6OSpaKRZxjCLBwP00r0fAgMBAAGjggHZMIIB 1TASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU rOyGj0s3HLh/FxsZ0K7oTuM0XBIwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF 9lo53BGhOKQ2MDQxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAP BgNVBAMMCENlcnRpZ25hggkA/tzjAQ/JSP8wSQYDVR0gBEIwQDA+BgoqgXoBgTEB AAECMDAwLgYIKwYBBQUHAgEWImh0dHBzOi8vd3d3LmNlcnRpZ25hLmZyL2F1dG9y aXRlcy8wfAYIKwYBBQUHAQEEcDBuMDQGCCsGAQUFBzAChihodHRwOi8vYXV0b3Jp dGUuY2VydGlnbmEuZnIvY2VydGlnbmEuZGVyMDYGCCsGAQUFBzAChipodHRwOi8v YXV0b3JpdGUuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYS5kZXIwYQYDVR0fBFowWDAp oCegJYYjaHR0cDovL2NybC5jZXJ0aWduYS5mci9jZXJ0aWduYS5jcmwwK6ApoCeG JWh0dHA6Ly9jcmwuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYS5jcmwwDQYJKoZIhvcN AQELBQADggEBAGLft7gIuGPZVfg0cTM+HT2xAZFPDb/2+siH06x+dH044zMKbBIN bRzhKipwB1A3MW8FQjveE9tyrfyuqZE/X+o2SlGcdNV44ybYkxo4f6kcLEavV/IW +oFEnojZlhpksYcxrvQoEyqkAwshe8IS2KtZHKVACrt+XSs0lwvy7ALGmHaF7A4b y6cZWItA7Lhj8XWp+8tBJDj7HocRbWtxzEODdBuyMgJzFrNjc+97J0vH/K0+3yjm kczpKshMA0tM+MF9XDMN/MuwrPmUWGO/fHiqHgUp8yqeWtl1n44ZxkkK1t9GRwhn DWLv73/xhTmdhWYQ/reo0GbgBoLiltKmIJQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHETCCBPmgAwIBAgIRAP0wzwQ0T8ON2QxOcHU9BiMwDQYJKoZIhvcNAQELBQAw WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x NTExMjUxMTM3MjFaFw0zMzA2MDMxMTM3MjFaMH0xCzAJBgNVBAYTAkZSMRIwEAYD VQQKDAlESElNWU9USVMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxHTAb BgNVBGEMFE5UUkZSLTQ4MTQ2MzA4MTAwMDM2MR0wGwYDVQQDDBRDZXJ0aWduYSBT ZXJ2aWNlcyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALPM+7Lp WBz9wFcPaTc3xnB+5g0XrnptB0EPPfrR04vO52Ykm4ky1d4ZLd10tbM1fa1RqNSO VWWg93O4pL7zCFKlz6JV74ZZVhHpEAwzBwv2oPnxvVbxtSN67xsSY66ahUYxjzs8 +3FhmsiRxqwnTYvK2u70uglUvRisOKyTL/M6JnrC4y8tlmoz7OSa5BmBMVplJFQt vmON6N9aHLvYMz+EyJPCbXL6pELxeHjFT5QmIaRamsr2DOTaCjtBZKI1Wnh3X7ln bjM8MESJiV2t7E9tIQNG0Z/HI3tO4aaUMum3KysY5sC8v3vi7rryGidgzHQhrtP0 ZXWW5UH/k7umLS/P/XXWnCFpc2Lxa1uDGfc2im7xibRoPP+JNZszN76euFlls6jy EXAiwnVr14tVVTewLK0OWs5SJHpEKp8PGMZRDj59EmMvokWwzL6QzNZ6vVAp00oO m05sbspNY9+MFqGKKUsKvhFGEa4XmRNxDe6KswLcjPZB+NKHZ0QWFd4ip5C5XmEK /8qIPjwVr9dah9+oiHGGO8Wx7gJAMF5DTmkvW7GhqCKj1LmHnabjzc8av6kxWVQZ i/C7HCm9i/W4wio+JA2EAFLqNL3GPNbK9kau4yPhQt/c7zxzo0OHnlsV4THCG7oO Cd3cfCiyfQcb3FBt6OSpaKRZxjCLBwP00r0fAgMBAAGjggGtMIIBqTASBgNVHRMB Af8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrOyGj0s3HLh/ FxsZ0K7oTuM0XBIwHwYDVR0jBBgwFoAUGIdW4G537iQ1PE5zmh/W4eJ5fiswSQYD VR0gBEIwQDA+BgoqgXoBgTECAAEBMDAwLgYIKwYBBQUHAgEWImh0dHBzOi8vd3d3 LmNlcnRpZ25hLmZyL2F1dG9yaXRlcy8wgYgGCCsGAQUFBwEBBHwwejA6BggrBgEF BQcwAoYuaHR0cDovL2F1dG9yaXRlLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNh LmRlcjA8BggrBgEFBQcwAoYwaHR0cDovL2F1dG9yaXRlLmRoaW15b3Rpcy5jb20v Y2VydGlnbmFyb290Y2EuZGVyMG0GA1UdHwRmMGQwL6AtoCuGKWh0dHA6Ly9jcmwu Y2VydGlnbmEuZnIvY2VydGlnbmFyb290Y2EuY3JsMDGgL6AthitodHRwOi8vY3Js LmRoaW15b3Rpcy5jb20vY2VydGlnbmFyb290Y2EuY3JsMA0GCSqGSIb3DQEBCwUA A4ICAQCI5QbprXJ93L+JWHYpUTinXAMSvXMx2dmNm4mIiJRAbGnBOoEYx7M61fbL L5EJIYZhw8jLmeYVFuMao5OJLwda+RMmVzE7lyTGsY64IDKdwogByNCqbKzrlhnU 8myyMNB0BDs2jgwQe2Dj9v+MddeHr7sDqvs7R1tSS5hoASLtdQhO7oxUzr3m7M8q +lh4jszli+cjfiPUVS2ADFu4ccQIh4OsIX6SWdU+8R+c/fn0FV6ip4SAVbNyCToz 0ZbZKO8YTJgORxRmvrop9dPyuLWjaRrZ0LMx4a3EM3sQDPDqmsG0lHtfFj2PiJvq 4lEYA+gDiLKODI+3DJMqo559m3QSS52DsShomHX/Txd0lJoZwepCE6X4KkG9FHjV WXyLgYFwCOcn+hkLhdpblms0wtjeSPITGOioSkefzhleJnDgJ9X4M3svd0HLTpJi lC1DmDZgdrXWITVdOoCogr2LFKNiGd0tbpKG533eKpfBALlm+afc6j73p1KhJEAn AfydDZqBRqv6+HHYplNDn/K2I1CZdkwaGrx3HOR/voGUi1sUI+hYbsPAFu8ZxrhD 9UiysmLCfEUhqkbojony+L2mKsoLqyd24emQzn7GgMa7emlWX2jQUTwrD4SliZ2u OetVaZX5RLyqJWs4Igo/xye0xtMQN8INJ4hSZvnMQ1qFtuSRcQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF6DCCBNCgAwIBAgIGSUEs5AA6MA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTUxMTI2MTU0OTAzWhcNMjgxMDA4MTU0OTAzWjB2 MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExv Y2sgTHRkLjEfMB0GA1UECwwWQ2VydGlmaWNhdGlvbiBTZXJ2aWNlczEcMBoGA1UE AwwTTmV0TG9jayBDb2RlU2lnbiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAOvWqIh0tUVnMOi/GJNc7WkuuDZLXJidt/Ub5R8FQ5o7fS1t+/rTIYRb fMmz9Gm6hW46E5BWeWUKzuG+1Z/a/G86QQByrBdbRCnhTaGQb3YPH2VaN+EOM5aK VD9iVVpnX5l0gUJfk2jQZCReP2vItR8Qyzjee4uy//VhVE3cJkn5/wf2zIqD27nn OLdrTbspJCeV5myerhbo69LlOS2Z7wmnxEfbjdtYYGz51J/3TVTfcMYUJxH7XuWP lGsoj5uB2B5Kb9q3X5ZdKJOby4+0u5Tt0u3Lk7PVZl19FQFV0bJSL2Pj9u9Fvjd2 1nAtSMHkRHVvQn9+Z0/1Khfxgc6n4f0CAwDp3aOCAkgwggJEMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFMz6Z5PwtrjQpcAe81P9 jFPfg9eWMB0GA1UdDgQWBBQ3msee456wtKHDYDYyNkejxYwG6TCCAT4GCCsGAQUF BwEBBIIBMDCCASwwLAYIKwYBBQUHMAGGIGh0dHA6Ly9vY3NwMS5uZXRsb2NrLmh1 L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRwOi8vb2NzcDIubmV0bG9jay5odS9n b2xkLmNnaTAsBggrBgEFBQcwAYYgaHR0cDovL29jc3AzLm5ldGxvY2suaHUvZ29s ZC5jZ2kwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWExLm5ldGxvY2suaHUvaW5kZXgu Y2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWEyLm5ldGxvY2suaHUv aW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWEzLm5ldGxv Y2suaHUvaW5kZXguY2dpP2NhPWdvbGQwgZ4GA1UdHwSBljCBkzAvoC2gK4YpaHR0 cDovL2NybDEubmV0bG9jay5odS9pbmRleC5jZ2k/Y3JsPWdvbGQwL6AtoCuGKWh0 dHA6Ly9jcmwyLm5ldGxvY2suaHUvaW5kZXguY2dpP2NybD1nb2xkMC+gLaArhilo dHRwOi8vY3JsMy5uZXRsb2NrLmh1L2luZGV4LmNnaT9jcmw9Z29sZDANBgkqhkiG 9w0BAQsFAAOCAQEAZH0bdaARPA7+CsdYan33MQTrXOjcxLKfBGp7VU9mUB/kDyDU aKhhy6jtz6Zai7jSnZjp35oWyYbq0+o8k3lxdKxEgCJ/Rs3gH4fVQvGm79g1TcQ/ bvbMIcPJg9bomLh/RwSg18ntEgIdE4ZJzgVs8zAWqzeBkZFw3/ofa3DQEVuUmldO /uWxCEilaTvJW9ZZj3KodeZrbTq3Dc7iAXT2YKBRsM/Lx+mJqAwpmzwnB5Lx5Lmq JdlhS7FxY2quK0jXPe9w3AGIDdK09RbAGOGMVuo7zCyLMATfE+72KwOKa/+PjfkQ KYmRklLOjd21u6BmmGIhhZJxwo9x7zqjS+Za7A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYzCCA0ugAwIBAgIQAYL4CY6i5ia5GjsnhB+5rzANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE1 MTIwODEyMDUwN1oXDTI1MDUxMDEyMDAwMFowZDELMAkGA1UEBhMCVVMxFTATBgNV BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEjMCEG A1UEAxMaRGlnaUNlcnQgQmFsdGltb3JlIENBLTIgRzIwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQC75wD+AAFz75uI8FwIdfBccHMf/7V6H40II/3HwRM/ sSEGvU3M2y24hxkx3tprDcFd0lHVsF5y1PBm1ITykRhBtQkmsgOWBGmVU/oHTz6+ hjpDK7JZtavRuvRZQHJaZ7bN5lX8CSukmLK/zKkf1L+Hj4Il/UWAqeydjPl0kM8c +GVQr834RavIL42ONh3e6onNslLZ5QnNNnEr2sbQm8b2pFtbObYfAB8ZpPvTvgzm +4/dDoDmpOdaxMAvcu6R84Nnyc3KzkqwIIH95HKvCRjnT0LsTSdCTQeg3dUNdfc2 YMwmVJihiDfwg/etKVkgz7sl4dWe5vOuwQHrtQaJ4gqPAgMBAAGjggEZMIIBFTAd BgNVHQ4EFgQUwBKyKHRoRmfpcCV0GgBFWwZ9XEQwHwYDVR0jBBgwFoAU5Z1ZMIJH WMys+ghUNoZ7OrUETfAwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC AYYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp Y2VydC5jb20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQu Y29tL09tbmlyb290MjAyNS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYB BQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQEL BQADggEBAC/iN2bDGs+RVe4pFPpQEL6ZjeIo8XQWB2k7RDA99blJ9Wg2/rcwjang B0lCY0ZStWnGm0nyGg9Xxva3vqt1jQ2iqzPkYoVDVKtjlAyjU6DqHeSmpqyVDmV4 7DOMvpQ+2HCr6sfheM4zlbv7LFjgikCmbUHY2Nmz+S8CxRtwa+I6hXsdGLDRS5rB bxcQKegOw+FUllSlkZUIII1pLJ4vP1C0LuVXH6+kc9KhJLsNkP5FEx2noSnYZgvD 0WyzT7QrhExHkOyL4kGJE7YHRndC/bseF/r/JUuOUFfrjsxOFT+xJd1BDKCcYm1v upcHi9nzBhDFKdT3uhaQqNBU4UtJx5g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGQDCCBSigAwIBAgIQCi9olhzfWnIFzIIK0hK/ITANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBGZWRlcmF0ZWQgVHJ1 c3QgQ0EwHhcNMTUxMjA4MTIwNTUyWhcNMjUxMjA4MTIwNTUyWjB/MQswCQYDVQQG EwJVUzEdMBsGA1UEChMUQWxsaW5hIEhlYWx0aCBTeXN0ZW0xHTAbBgNVBAsTFElu Zm9ybWF0aW9uIFNlcnZpY2VzMTIwMAYDVQQDEylBbGxpbmEgSGVhbHRoIENvbm5l Y3QgSElFIEludGVybWVkaWF0ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALLxi7jT48441GdGYh3Ur5QccpDyJc7b3Mmf29mYtLTBfmAGlwON1YRW 6kI/a4OppEV1AEO0Sl63N1500Wc1Z2qj0YicgFS/YwZQRi+05ULgDM6IjTHlTXuf cxZrEtKQJtO8Kkm5ZVu6BYZP/qgUbVTjCtYlhawLsQF+sUqhBveAWE764sTHr1Xb QmcnjWzTRY1+bEAwetIdofKPg9pGc1FZH2hnCTsEpXnIry4OJTnYsNDh++R4xtoE cLyEZNHFU4kJKWEIMnlO6PBHmhHMh446SZ/cUOZ3nzStuIh0wZuWUPaBpNyv68bR pwOSr0kqUvQokChaLsBYlAouv9F4+10CAwEAAaOCAtAwggLMMB0GA1UdDgQWBBSw Ufl9VeS4cp/ROmgK0IXa2oUPkDAfBgNVHSMEGDAWgBRGCDhaqY4guwyvXjG6ibMo v6yMNjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjCBiQYIKwYB BQUHAQEEfTB7MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20w UwYIKwYBBQUHMAKGR2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9haWFBbGxp bmFIZWFsdGhDb25uZWN0SElFSW50ZXJtZWRpYXRlQ0EucDdjMIGDBgNVHR8EfDB6 MDugOaA3hjVodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRGZWRlcmF0 ZWRUcnVzdENBLmNybDA7oDmgN4Y1aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp Z2lDZXJ0RmVkZXJhdGVkVHJ1c3RDQS5jcmwwggFSBgNVHSAEggFJMIIBRTA4Bgpg hkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNv bS9DUFMwDAYKYIZIAYb9bAQBATAMBgpghkgBhv1sBAECMAsGCWCGSAGG/WwEAjAM BgpghkgBhv1sBAMCMAwGCmCGSAGG/WwEBAIwDgYMYIZIAYb5WwOKIQABMAwGCisG AQQBgsFbAAEwDAYKKwYBBAGCwVsBATAMBgorBgEEAYLBWwECMAwGCisGAQQBgsFb AQMwDAYKKwYBBAGCwVsBBDAMBgorBgEEAYLBWwIBMAwGCisGAQQBgsFbAgIwDAYK KwYBBAGCwVsCAzAMBgorBgEEAYLBWwIEMAwGCisGAQQBgsFbAwEwDAYKKwYBBAGC wVsDAjAMBgorBgEEAYLBWwMDMAwGCisGAQQBgsFbAwQwDQYJKoZIhvcNAQELBQAD ggEBAHYz4XCrGd8wt3Q+kTjQhFUk9/7JgZQyZHYhiz7yge0jTV/QAfbfM7rGkiKT q096ZMKcG1T/8cUeZ4lKoFVGlvVamxLXgsjdQDO2hK+gAMWnKJ8n2/NH/O22Cp3V bjQUIYfRksS+Jxs1m2AvZvkoV8TkhmXn+G5KFiEqVK+cYrbQ1hAe8oDk+EHRtHyq QQ0UG0X5vo1piJqQs4Q1HfvuKRS/x793TqTYISPTQp82N55bjEhDMih2kXNFWGfq 2QXoV/xuqvviIpRwLGEF9GvnHcHVZ63FcweKaSk4UKJrczIT7IblVhqvez5shVbe EOm/S5R5oUPBK/sUG0l2xFsz1tM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGMTCCBRmgAwIBAgIQCJiDDe0ZV6cqsF8oNjJB1TANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBGZWRlcmF0ZWQgVHJ1 c3QgQ0EwHhcNMTUxMjA4MTIwNTU3WhcNMjUxMjA4MTIwNTU3WjBvMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXQ29tcHVncm91cCBNZWRpY2FsLCBJbmMxCzAJBgNVBAsT AklUMTEwLwYDVQQDEyhDb21wdUdyb3VwIE1lZGljYWwgQ2VydGlmaWNhdGUgQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0/O6rzwG1/Q8 odPVQocNF9yn49y6jJKBg7DnXJLaGlncQaoIrwStU5t4o/u0myv/rTTT85zYNMHZ TdL1AH5TcuZv186KY7OpFdyZc00G36dJAdwjWkSXlHHbvIG6LDxQvvjopLfLSBfF V47sGuVamIOu+pEQ2oyjAd6Yk4MRI7031CYLZ3tnlK7uFMRUBjt2ki40CKoGk8Bn A2bmLYnvfEZbAzm4ptpoczrZeJ91Q2uKUkMUxBOJMeD/VhJXp48wHdlO7aOZRJM7 PDI5nPYTvPA9VuSOhhT9KONKN5uIGL17xXtVZQxAaoMSQZZzOEjpTu9+gWkxAL5k iqAUH3wEZQIDAQABo4IC0TCCAs0wHQYDVR0OBBYEFA0Xf0pYbrQPFdGq89Hkhnhs Z+I2MB8GA1UdIwQYMBaAFEYIOFqpjiC7DK9eMbqJsyi/rIw2MBIGA1UdEwEB/wQI MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMIGKBggrBgEFBQcBAQR+MHwwJAYIKwYB BQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBUBggrBgEFBQcwAoZIaHR0 cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL2FpYUNvbXB1R3JvdXBNZWRpY2FsQ2Vy dGlmaWNhdGVBdXRob3JpdHkucDdjMIGDBgNVHR8EfDB6MDugOaA3hjVodHRwOi8v Y3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRGZWRlcmF0ZWRUcnVzdENBLmNybDA7 oDmgN4Y1aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0RmVkZXJhdGVk VHJ1c3RDQS5jcmwwggFSBgNVHSAEggFJMIIBRTA4BgpghkgBhv1sAAIEMCowKAYI KwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDAYKYIZIAYb9 bAQBATAMBgpghkgBhv1sBAECMAsGCWCGSAGG/WwEAjAMBgpghkgBhv1sBAMCMAwG CmCGSAGG/WwEBAIwDgYMYIZIAYb5WwOKIQABMAwGCisGAQQBgsFbAAEwDAYKKwYB BAGCwVsBATAMBgorBgEEAYLBWwECMAwGCisGAQQBgsFbAQMwDAYKKwYBBAGCwVsB BDAMBgorBgEEAYLBWwIBMAwGCisGAQQBgsFbAgIwDAYKKwYBBAGCwVsCAzAMBgor BgEEAYLBWwIEMAwGCisGAQQBgsFbAwEwDAYKKwYBBAGCwVsDAjAMBgorBgEEAYLB WwMDMAwGCisGAQQBgsFbAwQwDQYJKoZIhvcNAQELBQADggEBAIG2zPh5A6lzr9UZ ZN19o9iAnNMuy3+uk/xY/HiTf4fkksg0CuXVL83VLqzXjEgc1z5eFEnDjUSfCf5X Gkc49KzrUn+fQM23M/mM49gUEWoAnVz/q7uCtVQDDg7K4ErhrqYvxRGKWJAsC4EI eLUBsNx3HrSusK2u0VMB24O9BBlSzpqVU/T+GGIQkYhenUUvcjBQkrtyUiMPe8Jc Wy3d2LNpvGElZHBBuWwp8HQ38MKEl+wCnnhTprJG9HidEbzumG47aVFXK0n3cH29 dOdrtWBmgXV8hGMjtK9RYAGJKSEHQ/hT73O8u2ez1n4u/HDQYZAI1jMY7/9Hatza 41fg2EY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEyDCCA7CgAwIBAgIQYu9jivsE8WLzpAPYtf8baDANBgkqhkiG9w0BAQsFADBY MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNV BAMTJENlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNTEy MTYwMTAwMDFaFw0zMDEyMTYwMTAwMDFaMHgxCzAJBgNVBAYTAklMMRYwFAYDVQQK Ew1TdGFydENvbSBMdGQuMSkwJwYDVQQLEyBTdGFydENvbSBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTEmMCQGA1UEAxMdU3RhcnRDb20gQ2xhc3MgMyBPViBTZXJ2ZXIg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvZxxv5UXg10ZLdSy2 gPKaF00t/96u0tQAijq4Mf6ON576qtWjWxYSwRk+NIWWw77Ts0P0jW8WvTC6B/zY msF5iYBtoIy+3Tf36wXTU39XWHZVtqiohkS4u9AT2v2P4fLNoBU4VVbOJs98k3Up egqr+7oJOCARVwddf0mfKkpnHp5Y6cd/+cPt/l9Nr7hPnd9pLWkbOliBaWMw6oeN D1KdWto5RLqfiZ82tsIZXNkmeNmuXvyVkL/oEcBHD3eJ3WooTwq8MmRXQz0IZZPl Ra7dKAwnLI6mKwkDXaF40oyrtmu5RskZADm5v8YTK3NyH/I+N7jouRRliE3i8RvY pR07AgMBAAGjggFsMIIBaDAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYB BQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYBAf8CAQAwMAYDVR0fBCkwJzAl oCOgIYYfaHR0cDovL2NybHMxLndvc2lnbi5jb20vY2E2LmNybDBqBggrBgEFBQcB AQReMFwwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwMS53b3NpZ24uY29tMDUGCCsG AQUFBzAChilodHRwOi8vYWlhMS53b3NpZ24uY29tL2NhNi1zdC1zZXJ2ZXIzLmNl cjAdBgNVHQ4EFgQUsT8cknuSsFolszj7nAekJlAy41EwHwYDVR0jBBgwFoAU+mCp 62XF3RYUCE4MD42b4Pdkr2cwRQYDVR0gBD4wPDA6BgwrBgEEAYKbUQYDAgEwKjAo BggrBgEFBQcCARYcaHR0cDovL3d3dy53b3NpZ24uY29tL3BvbGljeTANBgkqhkiG 9w0BAQsFAAOCAQEAj1hUq27mu2EKDoktiXt/iHa0YeU/OyX5TfQ5z5LF7Sntmyzu G/d0s3uYk4lDylDyWOCFB6fcaRiQ/wo6I/ee1JoSALpQqWVpe6g+SabGhnsXbIRc dtEbhcD72SbtIKa/O6upZThXQcLi4BPHjRn98QRPCxPkyv8e6KyQ3IpJzszGzYtB W914Huoh4/JYyylhhhllkuJ/8mP71jgCjjwIPPVFlbqasrQvHCa5rbXVxTP+kAfW g1PKZLWf09SZ1+SfddQGHkABVsbiXXLnqXF94uzKyO2NuHZ4GbIkkwLtQG1elWtZ V0r2fV/w7r6zsXSa8NV7Y/hsOeYfitjjDX6Fpw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5TCCA82gAwIBAgIQal3D5TtOT9B7aR6l/OxkazANBgkqhkiG9w0BAQsFADB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUxMjE2MDEwMDA1WhcN MzAxMjE2MDEwMDA1WjB4MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20g THRkLjEpMCcGA1UECxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx JjAkBgNVBAMTHVN0YXJ0Q29tIENsYXNzIDEgRFYgU2VydmVyIENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2uz0qohni7BLYmaWv8lEaObCK0ygM86s eeN2w9FW4HWvQbQKRYDvy43kFuMmFD4RHkHn1Mk7sijXkJ/F8NH+5Tjbins7tFIC ZXd+Qe2ODCMcWbOLoYB54sM514tsZk6m3M4lZi3gmT7ISFiNdKpf/C3dZwasWea+ dbLpwQWZEcM6oCXmW/6L3kwQAhC0GhJm2rBVrYEDvZq1EK3Bv+g5gAW8DVfusUai oyW0wfQdnKtOLv1M4rtezrKtE8T5tjyeKvFqMX93+LYVlT8Vs+sD12s3ncldqEDL U89IiBjg6FsbLfM2Ket/3RbfvggfQMPQshipdhrZL8q10jibTlViGQIDAQABo4IB ZDCCAWAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6 Ly9jcmwuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDBmBggrBgEFBQcBAQRaMFgwJAYI KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbTAwBggrBgEFBQcwAoYk aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvY2EuY3J0MB0GA1UdDgQWBBTX kU4BxLC/+Mhnk0Sc5zP6rZMMrzAfBgNVHSMEGDAWgBROC+8apEBbpRdphzDKNGhD 0EGu8jA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3 dy5zdGFydHNzbC5jb20vcG9saWN5MA0GCSqGSIb3DQEBCwUAA4ICAQCO5z+95Eu6 gog9K9e7DatQXfeUL8zq1Ycj0HKo3ZvFhRjULAVrMj7JrURtfoZziTDl39gvMDhL voN5EFEYQWyre5ySsFgGeZQHIC0zhETILSyAE7JCKaEJ//APnkcQfx458GOuJvi+ p2JpRxa8Sc/HVJ9HqA687QbbJFFZlUP5IqLtCb8yZVBURd4Nm/+01DXBzomoQPwA K3cYl9br6Q+eKmCKPKN6X4IT1gwtwXuca1f3OpZTbUFPdPz1KvP1qCFt+rNieSmO BN76Xa9ffzoBByzVdnvk2OHuopmJq/eHF+E3s+GFYT6Oxjrez/lEbBvgEmGyXZOZ aj6XeDnBxOIYRODfnZG99cy2q5WtDLHKuiMogJGO89PWaI2jK1Aq5sa0j55jp2Je FXbRieKw5CKreCIiNR9MpaffieLgbTcK1BSKjxUZtd7BqJ3x1lvD2jbe7WKqzusZ btPhFgrDDsgdw27zQokNYBZZaa1LwYZGZgddiAcLcYkilGobA2wLKk6eYz6VnatD dI4aQx6FkHWvKU0e7s/cUym6Px3vXrC4z6woAztC98XaorPO0pkL73P4dKSjnKYY rYsqe7BnBGtANf1XaG5Pm8BUWJ9WZAWin6KsJXTo8Nj0G4CRq7dq17LBnCbi9Qmp Szc2kuPNbrV8PvbTLIXupfZFFj0d9mpaFg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5TCCA82gAwIBAgIQJkO7MqFmSHrhnWx5xD/iZjANBgkqhkiG9w0BAQsFADB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUxMjE2MDEwMDA1WhcN MzAxMjE2MDEwMDA1WjB4MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20g THRkLjEpMCcGA1UECxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx JjAkBgNVBAMTHVN0YXJ0Q29tIENsYXNzIDIgSVYgU2VydmVyIENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnL29gjx6E467y4OsHo42TCn1rC7JXUnv epzPE9KLbJiQi63JSLTr/QVGjhWFQBhqwXKlyTyBNGoOuV+yRoimqkPDdV6ZdnIn RwmKAnVhvMVd2WXeqSJtq5STa2nuOnLTwYBnyVsOIo9YdnvFhDXAGjQ3hXWQIq00 f43XE8Fik+9EUG/oF7VLlIACAJnhotAj2dR2TvQmyBbEEN2PhLH3WANZklMbao2c sASqSwyOmAB5+35nSagpMYuuVa4ZSnm2EaF8emLxiiFK5InCBZjRG4u+YLrEv7+m KrnHOMVWkOE7mzKxtuHFYW2LRB++eJGLUdn1KiviZDS/ofOhIhfstwIDAQABo4IB ZDCCAWAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6 Ly9jcmwuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDBmBggrBgEFBQcBAQRaMFgwJAYI KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbTAwBggrBgEFBQcwAoYk aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvY2EuY3J0MB0GA1UdDgQWBBSU 3oVBKqXZRfZgLC5MkwmmLCN+PjAfBgNVHSMEGDAWgBROC+8apEBbpRdphzDKNGhD 0EGu8jA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3 dy5zdGFydHNzbC5jb20vcG9saWN5MA0GCSqGSIb3DQEBCwUAA4ICAQC16kMuZh8h lVsgzybaIix2qySQFU+rPgqSqeyrDSmJwpDbaKjwakm6LJ2DLX5MRFjNPCh+ArQf CU1UUJa65n7UaQWt6q8kUwifHcIn+fFJdNV3N4zdvlKxwveqBSQZiXeIUO/hHr1U i7Gw6s0On+K0fD9oNcgCRR3vPicB2frK7BhOFje6xowsWexxPfJHI69lCq73O7Ke xXqp/V8f8uGF8L4KU3xW6RDG57RrXh5+LNxUQmZ2tIAaPyHTND5zbxff8Z/ZbgGG HKbsuPkAUIG+bHpq5b6bf2x2NxMhqYSMI+GJJ9FmmiCV+P3+0ywBYGNhJkcFUYvo SUduHz+/RXd6G/ejrvKp58rbZ9iCISLZjpo5gYEfLIl6IQJcZPM8FIWKLKhtIoKX 5ctNL3epV4DzIDZxLaSruEBQFeDQj6p/74pUYLQBP523anf6StXBtYgbfImRoIh4 I8L85aB/TUyLOJA/sKx/WFrXOxE9K4q+Pf5tq3gzZEchM/btMYn1cw1GPUt4nHya zS52LrP0+Q77ao1Gza9svd8HE1NZ9NIVJO71QskqjxvGiTt048r4gLSXaM1zP2w9 nMsIw1IpxXE8h9UHAllgh8oNHno5I9nLfynbEhXxGy9RlfcLN/J8iOqyagfgxrUy DPKMh5xGeLKMQSzjyQ1bV0WGC1JmJp+QDQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5TCCA82gAwIBAgIQE4v+8zKU+dgW+UXCcZUpmDANBgkqhkiG9w0BAQsFADB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUxMjE2MDEwMDA1WhcN MzAxMjE2MDEwMDA1WjB4MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20g THRkLjEpMCcGA1UECxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx JjAkBgNVBAMTHVN0YXJ0Q29tIENsYXNzIDMgT1YgU2VydmVyIENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr2ccb+VF4NdGS3UstoDymhdNLf/ertLU AIo6uDH+jjee+qrVo1sWEsEZPjSFlsO+07ND9I1vFr0wugf82JrBeYmAbaCMvt03 9+sF01N/V1h2VbaoqIZEuLvQE9r9j+HyzaAVOFVWzibPfJN1KXoKq/u6CTggEVcH XX9JnypKZx6eWOnHf/nD7f5fTa+4T53faS1pGzpYgWljMOqHjQ9SnVraOUS6n4mf NrbCGVzZJnjZrl78lZC/6BHARw93id1qKE8KvDJkV0M9CGWT5UWu3SgMJyyOpisJ A12heNKMq7ZruUbJGQA5ub/GEytzch/yPje46LkUZYhN4vEb2KUdOwIDAQABo4IB ZDCCAWAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6 Ly9jcmwuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDBmBggrBgEFBQcBAQRaMFgwJAYI KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbTAwBggrBgEFBQcwAoYk aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvY2EuY3J0MB0GA1UdDgQWBBSx PxySe5KwWiWzOPucB6QmUDLjUTAfBgNVHSMEGDAWgBROC+8apEBbpRdphzDKNGhD 0EGu8jA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3 dy5zdGFydHNzbC5jb20vcG9saWN5MA0GCSqGSIb3DQEBCwUAA4ICAQCF8ugU0xvB oRYdpPRNulGLXFKxVFQSFheclnhv07/fQzb1EolhckTfHJsJT2AmaMHmZlBws2rx qGoMHi6T8e4HPgndMEWyVo7cLFyrSfq5BANAFXq1MOAdkY+m1m8fmaCElTm9rHd/ ckvdLa7/qFgdRifUg8dpZJ8ZuxD4BEKHWV0CsdblyNpDMKPoN6XSSAuig06dT4NY nddHIrGJ8Ik7PShDLJsXfAPunSYl4AS4HQRXQkfaWGnw0ymrEgKZKyrYnaAfVF4j mgzSmVjEoeVJwiWnZCBSLueJ9RnAi9BjsXgevgFHvnaBRvGZH5SavvqCFbWEhHl1 k7qfteSbwstpXL0fVQqnJjAFUb5l7lepat+9+TYvrR5GQSuxiNCIJYVAF3m/PY3i 9C3qMDHfoUDLNf+Cn/WZPEr9naHRVcwgqBzYIAWrsxRllVPY6I5XxXdrLU2I6V1i 1aL4cOFw60UjDvAARsJIMejnNoA2LSLyASdT686naUmCv+cPnPMgLvX6Xc7qWDqP 2Kp9MLd0lnw9brTsSjtZtqlQDQ8FBnAmuZWR0V4kjI/KdFeXkItat/6Nrdjowga8 CFYhAhJTxp+GBFjKLfgDDVcLHDe98Fo18v471qQ3Fen4CJKWPXTItVxuZQjn32lz nOzjMFqm31y+2n8A7qXaK1weKmrAo64e8Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5TCCA82gAwIBAgIQd2dvyPqWCLp22vyI5wUXdDANBgkqhkiG9w0BAQsFADB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUxMjE2MDEwMDA1WhcN MzAxMjE2MDEwMDA1WjB4MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20g THRkLjEpMCcGA1UECxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx JjAkBgNVBAMTHVN0YXJ0Q29tIENsYXNzIDQgRVYgU2VydmVyIENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr0gsshD4y+My30tBHenjJEUa+HsO92a1 LbYcEvvHqLe64HmxT8mvz7oiH6KpVbVs74Wb5k6v750k9WjOhp4dAi43iOFJUxfa MgJyB+6kdoFavXn7x2P6ug/aLqEx7syoiD66fVDLv1XMYUnI3jZnqQTWPPZ1o97k wZCIIOM+tUpGnDMXXmbeYq1TqsxuMBWfjMwtWSeBV3EMETsdmPgv89Dsso7hgiRp bJvJCH9G5KstAOt5L9rLX8LDbgHkJQlpHrgY57iGch0PQgT6jA4tA7Xtowde+AtC OGMyzB43hWxkgSy0mqbMrjji1rl+2S36G4qMlnssBcol6kbn9Rz6EwIDAQABo4IB ZDCCAWAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6 Ly9jcmwuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDBmBggrBgEFBQcBAQRaMFgwJAYI KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbTAwBggrBgEFBQcwAoYk aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvY2EuY3J0MB0GA1UdDgQWBBQO 2A3SZh2rcraJZUtkPX4YJ9SM3jAfBgNVHSMEGDAWgBROC+8apEBbpRdphzDKNGhD 0EGu8jA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3 dy5zdGFydHNzbC5jb20vcG9saWN5MA0GCSqGSIb3DQEBCwUAA4ICAQBD4zqpCMSi HMuNArGLUtiyrzzrPjPYuU8bEVhQSMu99S4GqiI816LQqT/OwcsCjUhbU36Vk4u+ /9gWJJCmPuibypFqlAO99K6r3Zl3qDQYBwNpgw1fzv2l3J6G0oScf8YMxPYfSZug IRtz8yb2hTLCOKBb49/yeSw2/+WUNvIZqXUdjIdWlntux4meIYhQBlrCt17nAz4t 7QLfcZh5s6dRLkpdxNICzoM5N7f0MzmAbmhDv4e3eC9mhvAq+772xB0Hcg4oMSIH CgOsAbDTvC030+BLNHoPd6rRY38FgPxywFomfHwQ5DZu0HMreXpzbKUu0+xXzI6y SN62p1BgbJpTyuuiVC233jnkh9LCYCiFwgdoaMm99HAje0gDPa+kVsG8sMbLQ2qT afhAf91oOtTVyxZpaYtyvcOk/+qI4y6rkmuR4lxM50EQ3ZR0guvsp7+9rOYBGUp9 r4/UXRAYfnk3uB/mDWrLcLAJQu7UHu4Mm1K3JL9PiDax6Hv3Xf9ELKaZNS2hoPzx xmo6R/E7xyFCrkzU8RlTs47Ukfj9rU/uMzc+xnRgbiKIMo2kkXG0rtH+O6mBV3xs Q0xBQGumZatOOgHOI+s1jfCzzRgbt4dpYZ17a4C0jzi+YMXGbH/aNZQi3UFtq007 s7PvS/9Lq2E4nxKDPlyhdVq1Z6s3OeYSTw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIQYGxi3JfRoDku6csSsh1t2TANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE1MTIzMTEw MDU0MloXDTI1MTIyODEwMDU0MlowWDELMAkGA1UEBhMCUEwxHDAaBgNVBAoME25h endhLnBsIHNwLiB6IG8uby4xGDAWBgNVBAsMD2h0dHA6Ly9uYXp3YS5wbDERMA8G A1UEAwwIbmF6d2FTU0wwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDd Udm8QIU7rEuPXzdpMrPQ7b8oFcnTcLnwax4ktbppbkge8Yw9mW93JBBE7wxG5HlU 5IwA3FWqDgZ9ikjp4kalUjDEKJBMRjxYvRf0cshgZOtw8ZMp3KylskJIYjcy4rlF tshnUvJVk3hQW8iLYGwNEPD+kf7ixPAWPXm6vh/4RFExTj4aUDfjMZZ3cNxGEsca 109j/oWHcLX565MRkkBe7EuxuZeQIsIIzosY0P6MZWeBFCH8pPXRn2Oq3SrpnMUh uaPeqQ/WElwd4wndQouUZ1K4duYNb1EiKKfX24eiUboejEBgcmwjhBmvllHoE7Tv juNd5vgpxpS2Bh4HmFfLAgMBAAGjggEMMIIBCDASBgNVHRMBAf8ECDAGAQH/AgEA MDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9jcmwuY2VydHVtLnBsL2dzY2FzaGEy LmNybDBuBggrBgEFBQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5v Y3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNl cnR1bS5wbC9nc2Nhc2hhMi5jZXIwHwYDVR0jBBgwFoAUVJndm//opw6jGZ1bvkJX 3zD8jzIwHQYDVR0OBBYEFFTckLudRxlRw3loLITtLt9fRrrHMA4GA1UdDwEB/wQE AwIBBjANBgkqhkiG9w0BAQsFAAOCAQEANwuNWA0q74QoHr114Qp0eCcWarw7iWgR 5vTNMzfx40TGZrOdnTr8KDBspLvsscs6O33WW+qz0GzY/0Dw0ZWdZPZ32h5GcPMM sCTlqnzDvKTEADI7wDMPqlgBVI+px61/0MVZ+lw+MR9xs2QFS2NfGs8hbRp6agDF UVepiuxfOVfl2GK83gNhW7Xbf2fxZ4sRujhVTZk+VHbX2RS1nTxRCTQRd4YiFyFR 1c7DYfp5+Pr2y7IV9CV2HlSbELzWbfg85hg5YHMs+nCb5wLRizecvKQ4w0p9kQbZ 8b57tMZj64p+UI2S6bmTQYk2jqLHE7yJj3PdRA9bsDIFlGqcjDEcMg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHDCCBQSgAwIBAgIQQRINIAAuS2+fR9NVc+eKdzANBgkqhkiG9w0BAQsFADA0 MQswCQYDVQQGEwJGUjESMBAGA1UECgwJRGhpbXlvdGlzMREwDwYDVQQDDAhDZXJ0 aWduYTAeFw0xNTEyMzExMDQyMzZaFw0yNTEyMjgxMDQyMzZaMIGCMQswCQYDVQQG EwJGUjESMBAGA1UECgwJREhJTVlPVElTMRwwGgYDVQQLDBMwMDAyIDQ4MTQ2MzA4 MTAwMDM2MSIwIAYDVQRhDBlOVFJGUi0wMDAyIDQ4MTQ2MzA4MTAwMDM2MR0wGwYD VQQDDBRDZXJ0aWduYSBJZGVudGl0eSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAJx9cXGt5mJyMYRwIoNl0Hxn0PH8WRehC4ZQyDA0LyEqaNGjE8Po Jkc1yEz12yQ6B2VWjoXpxNRJlBUiabhPrmAO6fyJpyuielSFPVhDPff6HQCe3pgO txpFcEmLCaISZlE6hPes+64Lhplhxmz1zxXvH4b87MVmCzT30iTv0e6DCZWjavzO /7wuJubV1GUGoBQGEND1Il8cUF+/w1UcNdrj7L4LbIhYdSSqnKfMd+WR49B9qoBZ O7s2S+q/3ITOjmIu5IaUCcxdDoiIf6PLgIjBXIdK773yyws41ePZ6GEnOXy0McGN l2PlUmeIEn3PNzLjQIoh03jaM6vsLt7iJiv4ZJo3JotwzLeA4DCo8/v+H3YTS0IP rqgsdN4opR4GnN+8CZih9LuIBPMnZexzZWsfz0VeyxbbdyNsjtABQL0ahMrtZAHD Si6KSHo/mszE5HANA1ztGSvSHOmY3aTKQ4fdDYXXCmq5K0T6NCyjmn5Y8u4yuLrF 7eBgvXp/X/i+3WdfXsMnK2UhxcsKLZT1MB99OCWoFeGsYwiWtru89fLoIfgCYDMJ AV/WS7aW7Gj9wS97WfyYQnJS4Xo30foEmlEHsGjdFTlGM+bX4SIjXnMPwpFC0tAv Sv+BoJlu3Va8XgB2s0QRS/9pAZWQOq+ARBdgeKZorC3wm9gVEYBSKC/XAgMBAAGj ggHZMIIB1TASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUwzn8Z2iusxHWGYB2s9W6CF4ZxdQwZAYDVR0jBF0wW4AUGu3+QTmQtCRZ vgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90 aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/JSP8wSQYDVR0gBEIwQDA+Bgoq gXoBgTEBAAECMDAwLgYIKwYBBQUHAgEWImh0dHBzOi8vd3d3LmNlcnRpZ25hLmZy L2F1dG9yaXRlcy8wfAYIKwYBBQUHAQEEcDBuMDQGCCsGAQUFBzAChihodHRwOi8v YXV0b3JpdGUuY2VydGlnbmEuZnIvY2VydGlnbmEuZGVyMDYGCCsGAQUFBzAChipo dHRwOi8vYXV0b3JpdGUuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYS5kZXIwYQYDVR0f BFowWDApoCegJYYjaHR0cDovL2NybC5jZXJ0aWduYS5mci9jZXJ0aWduYS5jcmww K6ApoCeGJWh0dHA6Ly9jcmwuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYS5jcmwwDQYJ KoZIhvcNAQELBQADggEBACtN6si8Dg8rt0+vHdpsBVD64h23iKcBipbw+j7MSrFJ GPxMixckWfzalg/sj7jMSY4Pm7pMAJo/3DKda8Boewz7Vfxg0jBZ8t/zlaH5x1zK e6SYxp/CcOqeotgg0B0s4su2A6SuUU0BFUd9ydF2PMH46xYvHqskWycBVlIhdCS7 h3Q1X16vS+wrWYjvj2+UzBiiB1CBJgHX/RZeOj9uDvBDPiUSMae0dUsAQ/czP8jg 4A4gBKkobuHibVFUHfStsnnCB4WUIIX2FCPxFOIA6yz5YTletvrkQ3oyzGdzemo4 Oy6W/IIjibmuU37EK0p9c2OPhtbLsn+mgaRUtjUnwEM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHFjCCBP6gAwIBAgIQWUTLLb5q3qUTTpoyGUEMrjANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJGUjESMBAGA1UECgwJRGhpbXlvdGlzMRwwGgYDVQQLDBMwMDAy IDQ4MTQ2MzA4MTAwMDM2MRkwFwYDVQQDDBBDZXJ0aWduYSBSb290IENBMB4XDTE1 MTIzMTEwNDYwNVoXDTMzMDcwOTEwNDYwNVowgYIxCzAJBgNVBAYTAkZSMRIwEAYD VQQKDAlESElNWU9USVMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxIjAg BgNVBGEMGU5UUkZSLTAwMDIgNDgxNDYzMDgxMDAwMzYxHTAbBgNVBAMMFENlcnRp Z25hIElkZW50aXR5IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA nH1xca3mYnIxhHAig2XQfGfQ8fxZF6ELhlDIMDQvISpo0aMTw+gmRzXITPXbJDoH ZVaOhenE1EmUFSJpuE+uYA7p/ImnK6J6VIU9WEM99/odAJ7emA63GkVwSYsJohJm UTqE96z7rguGmWHGbPXPFe8fhvzsxWYLNPfSJO/R7oMJlaNq/M7/vC4m5tXUZQag FAYQ0PUiXxxQX7/DVRw12uPsvgtsiFh1JKqcp8x35ZHj0H2qgFk7uzZL6r/chM6O Yi7khpQJzF0OiIh/o8uAiMFch0rvvfLLCzjV49noYSc5fLQxwY2XY+VSZ4gSfc83 MuNAiiHTeNozq+wu3uImK/hkmjcmi3DMt4DgMKjz+/4fdhNLQg+uqCx03iilHgac 37wJmKH0u4gE8ydl7HNlax/PRV7LFtt3I2yO0AFAvRqEyu1kAcNKLopIej+azMTk cA0DXO0ZK9Ic6ZjdpMpDh90NhdcKarkrRPo0LKOafljy7jK4usXt4GC9en9f+L7d Z19ewycrZSHFywotlPUwH304JagV4axjCJa2u7z18ugh+AJgMwkBX9ZLtpbsaP3B L3tZ/JhCclLhejfR+gSaUQewaN0VOUYz5tfhIiNecw/CkULS0C9K/4GgmW7dVrxe AHazRBFL/2kBlZA6r4BEF2B4pmisLfCb2BURgFIoL9cCAwEAAaOCAa0wggGpMBIG A1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTDOfxn aK6zEdYZgHaz1boIXhnF1DAfBgNVHSMEGDAWgBQYh1bgbnfuJDU8TnOaH9bh4nl+ KzBJBgNVHSAEQjBAMD4GCiqBegGBMQIAAQEwMDAuBggrBgEFBQcCARYiaHR0cHM6 Ly93d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzCBiAYIKwYBBQUHAQEEfDB6MDoG CCsGAQUFBzAChi5odHRwOi8vYXV0b3JpdGUuY2VydGlnbmEuZnIvY2VydGlnbmFy b290Y2EuZGVyMDwGCCsGAQUFBzAChjBodHRwOi8vYXV0b3JpdGUuZGhpbXlvdGlz LmNvbS9jZXJ0aWduYXJvb3RjYS5kZXIwbQYDVR0fBGYwZDAvoC2gK4YpaHR0cDov L2NybC5jZXJ0aWduYS5mci9jZXJ0aWduYXJvb3RjYS5jcmwwMaAvoC2GK2h0dHA6 Ly9jcmwuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYXJvb3RjYS5jcmwwDQYJKoZIhvcN AQELBQADggIBAA5JR+3YJHDCciJERONFIywpLaDAWVJ9RefkH/89HieRApLpfSaf rsKn3JFGbBVgKQgPbvdEBTAGj4KrDFAExBjiZqvZboCTAAqJplDoOxCJVk1I0LTT Amw1bVLk1JiR/PYMXbU2hW8UJneeaEQdI9wDbVgOVtf/lrAFVv7Gc2ypsZIIRBgZ AcJt9JxkrjSSnjlcR2LTzr8RFUeYeDA5x96E5Ze9lg9BAc48pIQTedZBqC4tHeT5 j3s7zqnQDgPLGOaOP0yw0QWBnZE0zTVqO6y/jzwt2sV9kXBPfNaw0A0D6lenU7Wd OL+e3Nd9Godeb215eGdvEblpOzlMoSXgQaSLf3Vy/mlwigi3WlKD9JEz7vvg+aZS ZODMyftfvohmPaVsZG9YhrDa1zSF1i180CGrAQ5c+MdcszXB1lTMH4IfIjVUvjx4 hFsQvyD1slzLla+enYOVT6oE5s07YxGPB2o267cX71JLQvgGhO7tH4gwOF4ub0Hn X1UiXw3VM7aP9m0mjjbSnqY1fswzb7YZKQ2GBZgojBU6fPyaCZ6+QwGt9huG7SCq gVA3BGAfbjl4qC+Tm8C0GTJNyZKHWCZ+nz/70xLmljlHFeDwpBVgIFTZl47tMg63 4GlcAg89JJRqyKRcvplTJKWeBOo8nZXs4F3YCdjyF05fotJfSsPMf7WJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEzTCCA7WgAwIBAgIPIAYFFnADFaURrma5fvkVMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xNjAxMjYxMzA4MDhaFw0yNjAxMjYxMzA4MDhaMHwxCzAJ BgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEsMCoGA1UECxMjY2VydFNJR04g Q29kZSBTaWduaW5nIENBIENsYXNzIDMgRzIxLDAqBgNVBAMTI2NlcnRTSUdOIENv ZGUgU2lnbmluZyBDQSBDbGFzcyAzIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAgkaLuPUX9i8MwmQukn7Yr55busmNx5sA90+WJUCw66aTDh7LocvU 8gstVKeVQuiF5mYQxvrtXGK48W28NustQ+7/d9dmTfyC5lMzlXR6sfoHs+oBee6l GdvCOVKmaTOHlwPIL85hiz7alwZg4ioEilVlbABomoNzBx7c0PpfMBpH8TYG7EJL cw0Ha90M/Fic4eT858yV5nEI7uXGhKcWADsu2tx05z/VwPmM2GjWHg0jkA3oDgPw 6WA6XFfmZtA5xatg8bKHdffzWkUzPqGKNQwhgmaMBueVwlu/uB4q2mPS1pOAvj9X cbD0/1V0aGbtOn9k6pbSPYsqVkYa5XQmmQIDAQABo4IBizCCAYcwaAYIKwYBBQUH AQEEXDBaMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5jZXJ0c2lnbi5ybzAzBggr BgEFBQcwAoYnaHR0cDovL3d3dy5jZXJ0c2lnbi5yby9jZXJ0Y3JsL3Jvb3QuY3J0 MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaA FOCMm9slSbPxfIbWskKHC9BroNnkMB0GA1UdDgQWBBS7pk52a6qEcBPCp+hoRx1o w34+bzCBhAYDVR0gBH0wezA+BgsrBgEEAYHDOQEBAzAvMC0GCCsGAQUFBwIBFiFo dHRwOi8vd3d3LmNlcnRzaWduLnJvL3JlcG9zaXRvcnkwOQYGZ4EMAQQBMC8wLQYI KwYBBQUHAgEWIWh0dHA6Ly93d3cuY2VydHNpZ24ucm8vcmVwb3NpdG9yeTAwBgNV HR8EKTAnMCWgI6Ahhh9odHRwOi8vY3JsLmNlcnRzaWduLnJvL3Jvb3QuY3JsMA0G CSqGSIb3DQEBCwUAA4IBAQBEvh9hw2G7De0tPq34G94Iz3iexKrDbcch1/MTS8JH Fbn3EA/S0vFyUFcFx/hlolA0Nb9+UoAQyztg9rjBMlOdQcwwpGEXQr4CKWAwgo8B KqIgu0W1XHjo3Qs2h2dQk6jU7EE7xB86znYGjcS5xfM5JKXYA8AsQYnYs7v5XMaX Cp4Hs7IyMMMnac2S2FxTKPZ9bbwTOSpFX6J/Jv6KivwoAhf16UbPIv9KVUzbM6uc iZg43S0Jolh5iasz7kdfFXDQpj8xm9/nQ8pYcpoIzqF65lgZ+Q/H9fD6/H/k1WxX w0VJyGSkFMe8P8l/CR/XKPjeuqaeuIyrh/jNDU1zFDt4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHHDCCBQSgAwIBAgIQHTLS1yBHGnaRVupojsVS4DANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJGUjESMBAGA1UECgwJRGhpbXlvdGlzMRwwGgYDVQQLDBMwMDAy IDQ4MTQ2MzA4MTAwMDM2MRkwFwYDVQQDDBBDZXJ0aWduYSBSb290IENBMB4XDTE2 MDIwNDExMTA1MFoXDTMzMDgxMzExMTA1MFowgYgxCzAJBgNVBAYTAkZSMRIwEAYD VQQKDAlESElNWU9USVMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxHTAb BgNVBGEMFE5UUkZSLTQ4MTQ2MzA4MTAwMDM2MSgwJgYDVQQDDB9DZXJ0aWduYSBF bnRpdHkgQ29kZSBTaWduaW5nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC CgKCAgEAw5yYR0QpkhFkNlq6J0LVJt38Ylrq2bTZjPpGkQSzgLuyzjrh6IeBmiPT YYnP2Yy2QMFeVdlPD/nEq5j11lz1R3CFfP9Cg9jQFhgYdEoVCcQBw9iTao4bCN1x owXwn/dNjagVQxMULCjV6PelU9pu/bsJGbdAMujD2Ihu/zhvXhgdc8s80XuHACOO 7Sz4MdiN1MhDI3rPYQfV83q0R68JtMLPb+shAsqttjbjkU1i9q2LGfmkFyv/k8GC x4wQwohWTaU5ALbRxjpr/TCt75KoVA2R4Zb69qOsA//S27oeqwoHPoyETeQ7y721 gTFMtm0oOJlBe2XKiL5Yg8aRfDA1Dg3g6BVJDYXr//Hui0kuIEvqficqrl9HUEuU gI//Flug5bwqQ1z9SeCOSvgxnAYoOUM40jLkKK5nN59M7aDENXV4Lpq7TIwQsyOM MAdnhp/gVYQ2eaInD7JFURTZ13sZyVS+QNfOorWZOr90UhucqAz6NYA0Mb1domXn lz4OLKag9vCNBmdJtjYUzXVPXJqxb89Zngle8MPlXE2vjcAp8AXCdFtYaJw6Ae9r R3OhUhWppyq+wzy3Lu8v3913NsU8oo1YhXw0oK9t3prpUfk19FUNuaXfiKs6P971 DJUwoSsx4q2zrsBcWUfZc02pvkjDbPOPRiO5A1CziUcXYG87jG8CAwEAAaOCAa0w ggGpMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQW BBRxkMWZyggSyUDzmNOmsw/J/arH1jAfBgNVHSMEGDAWgBQYh1bgbnfuJDU8TnOa H9bh4nl+KzBJBgNVHSAEQjBAMD4GCiqBegGBMQIAAQEwMDAuBggrBgEFBQcCARYi aHR0cHM6Ly93d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzCBiAYIKwYBBQUHAQEE fDB6MDoGCCsGAQUFBzAChi5odHRwOi8vYXV0b3JpdGUuY2VydGlnbmEuZnIvY2Vy dGlnbmFyb290Y2EuZGVyMDwGCCsGAQUFBzAChjBodHRwOi8vYXV0b3JpdGUuZGhp bXlvdGlzLmNvbS9jZXJ0aWduYXJvb3RjYS5kZXIwbQYDVR0fBGYwZDAvoC2gK4Yp aHR0cDovL2NybC5jZXJ0aWduYS5mci9jZXJ0aWduYXJvb3RjYS5jcmwwMaAvoC2G K2h0dHA6Ly9jcmwuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYXJvb3RjYS5jcmwwDQYJ KoZIhvcNAQELBQADggIBAK1sWN4vvkkxUBYlSl+sVxuF0uPkx3/pHngQXF+fYSub GQ0Z7JPOpWZ8/nWyjE8jV/Ps6qam3UZ13G/8EqU1mDvKo9eb76TxxUtJF74mmkZT JDGa6c6MP0fHlcDuZsvCKoZbHOLutItRs7JMz/8WxB9T5oIZs4Ejv3MNuFrnG2Td VtMc3P/NVMMNrMJ6oYhjS49XVWOVPqgrPx6oAmErulVhVR4JoPpYFRP2MpHsOfBW 2MRJMDa7ZCd5WQfKvbBkb9v107B2htlywYsmZGTo/brwxcU3IUs660xHglnlitaF nZR0EPDjWAyHFm5qamwrukWqFYYu1MwgmuMvSqGBQZfCCMFsUdvAspnCiCeXkygo YVbWPqoQX7XVquGhrC1Or8h6ZnysMfHniilKvgwM9mxocTZbg8iK5G7yCEzz6Fw8 ZEES3LLcOQV6nYpNnxhbgklEKgJIpZkdeURL7h6MZsGv2kE+t1Jqpfch3ij6P46A 4tCdnPkuSHWSV06Uy8V//s5kf7FmhcvOAQHRciHBJXSWVFoxPMboPoPtXnp390UU M1FLpW9inQAtcDnTYqB0M/HzAiv36cCuY6TEdvaUHT+RYlzIDMvz0jEBgcH4kII9 pwLbmT0WulrsOhZFwa1xXg014Ga2Htu2W4MPeO9JXTKQClk5IePocjogvR5OgSDK -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGIjCCBQqgAwIBAgIQde9eZ3B27Q+W+pWi7G7w1zANBgkqhkiG9w0BAQsFADA0 MQswCQYDVQQGEwJGUjESMBAGA1UECgwJRGhpbXlvdGlzMREwDwYDVQQDDAhDZXJ0 aWduYTAeFw0xNjAyMDQxMTEzMzNaFw0yNTEyMTMxMTEzMzNaMIGIMQswCQYDVQQG EwJGUjESMBAGA1UECgwJREhJTVlPVElTMRwwGgYDVQQLDBMwMDAyIDQ4MTQ2MzA4 MTAwMDM2MR0wGwYDVQRhDBROVFJGUi00ODE0NjMwODEwMDAzNjEoMCYGA1UEAwwf Q2VydGlnbmEgRW50aXR5IENvZGUgU2lnbmluZyBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAMOcmEdEKZIRZDZauidC1Sbd/GJa6tm02Yz6RpEEs4C7 ss464eiHgZoj02GJz9mMtkDBXlXZTw/5xKuY9dZc9UdwhXz/QoPY0BYYGHRKFQnE AcPYk2qOGwjdcaMF8J/3TY2oFUMTFCwo1ej3pVPabv27CRm3QDLow9iIbv84b14Y HXPLPNF7hwAjju0s+DHYjdTIQyN6z2EH1fN6tEevCbTCz2/rIQLKrbY245FNYvat ixn5pBcr/5PBgseMEMKIVk2lOQC20cY6a/0wre+SqFQNkeGW+vajrAP/0tu6HqsK Bz6MhE3kO8u9tYExTLZtKDiZQXtlyoi+WIPGkXwwNQ4N4OgVSQ2F6//x7otJLiBL 6n4nKq5fR1BLlICP/xZboOW8KkNc/Ungjkr4MZwGKDlDONIy5CiuZzefTO2gxDV1 eC6au0yMELMjjDAHZ4af4FWENnmiJw+yRVEU2dd7GclUvkDXzqK1mTq/dFIbnKgM +jWANDG9XaJl55c+DiymoPbwjQZnSbY2FM11T1yasW/PWZ4JXvDD5VxNr43AKfAF wnRbWGicOgHva0dzoVIVqacqvsM8ty7vL9/ddzbFPKKNWIV8NKCvbd6a6VH5NfRV Dbml34irOj/e9QyVMKErMeKts67AXFlH2XNNqb5Iw2zzj0YjuQNQs4lHF2BvO4xv AgMBAAGjggHZMIIB1TASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUcZDFmcoIEslA85jTprMPyf2qx9YwZAYDVR0jBF0wW4AUGu3+ QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlE aGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/JSP8wSQYDVR0gBEIw QDA+BgoqgXoBgTEBAAECMDAwLgYIKwYBBQUHAgEWImh0dHBzOi8vd3d3LmNlcnRp Z25hLmZyL2F1dG9yaXRlcy8wfAYIKwYBBQUHAQEEcDBuMDQGCCsGAQUFBzAChiho dHRwOi8vYXV0b3JpdGUuY2VydGlnbmEuZnIvY2VydGlnbmEuZGVyMDYGCCsGAQUF BzAChipodHRwOi8vYXV0b3JpdGUuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYS5kZXIw YQYDVR0fBFowWDApoCegJYYjaHR0cDovL2NybC5jZXJ0aWduYS5mci9jZXJ0aWdu YS5jcmwwK6ApoCeGJWh0dHA6Ly9jcmwuZGhpbXlvdGlzLmNvbS9jZXJ0aWduYS5j cmwwDQYJKoZIhvcNAQELBQADggEBAGYlp9+MguDNmi4/pkAWtjRMYYT95Gwq73YS 9SCckEaUDvVwyURgdvuW3Nf3Tv5v54H2ZNNPRWlVrCyL9dyFZEN+g4DdAAEDUhQw 9GzqiELKw0HmqN7XG9Q3YbMZ8sHXu/FWK425pFDBfZJUpn5MZkiqsDlxCsuunb13 6TbFU5S3ESsNf6CQlgQUFx/AGYY5DduS92UfaBZMnPKvr6tDK/jsIBS0otB0nMK6 U+wje3M9WkS30r/uFJoTcaVLayk6eWUZxQLvZSCiBQx2rykhds4Ew1vlHgHnKn9R FnPSu2VwXWTFWBwRCuIYK/66wOo97Snq79/RTkEeVDCFMd62FHI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGNTCCBR2gAwIBAgIJAP8EO59nfNxJMA0GCSqGSIb3DQEBDQUAMIGkMQswCQYD VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTMwNTIxWhcNMjkxMjMwMTYyMDEwWjCB ijELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEkMCIGA1UECgwbVHJ1c3RD b3IgU3lzdGVtcyBTLiBkZSBSLkwuMRkwFwYDVQQLDBBUcnVzdENvciBOZXR3b3Jr MSkwJwYDVQQDDCBUcnVzdENvciBCYXNpYyBTZWN1cmUgU2l0ZSAoQ0ExKTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAP2LqguM36LmFQpiSNxsIiYi07Xq gJk9iNS115KGWuPjGLlrAshx01oLy+q93RQ0gG7Bi+KXeej0B7NCIzFQKGS9St5/ FZPF4GH9ji9MioO8SKZyiLOwJrZyfV1J71ov5sLU/b01/jHnVKAXCTx6QD6EpuMw nMSs4ZSa+LlztQviYK3obgte19ciTq75QlM/a2VnBSjPmgnOc/0yObyu3tvqIA9c EHnoCzDJDZMKg7wnL2yJa5ckjzEiOCczJXealKj2YaW4zDFJ8uBpaGDrFQr5FNs6 T197ptikG4rG4Wl9YM6lmtjyqNTns04C4GX7uARdeheNp8FXLoDedCptSg65UnDd Gi9hqIB0FDvHy7dzHfdRrWMLozrRIjPkV87veA4HdFsG63jZQMDn6kv90h0aZx3K xefewicoD6O9VO374+SIBS7m7seMWaLZa++muX0rEOem9UhSpwt2UwYJDCp77AWQ A/7AQ+l+USs/tzO5kpNQT7wTRs12gmzwyUmCTLw+LuzW/lUReiVPFbADjc7X73Qn NBtCZnsJaOenY/yZwIyuv2ORQRMIoC7ay54myj8GZrcqXsmtnyP5spdt6fpTwwmL l332CUsGrYYQUiLspF7rSNhJ5a9SbdHQQTUeBl/j9az39F0ZdhxDfoiUy+WcoQJs j1Q5iKCL89T13jWDAgMBAAGjggGAMIIBfDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBhjAdBgNVHQ4EFgQUtzinmZLXxqpO+z7THE69Gcjpkk0wHwYDVR0j BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwWAYDVR0gBFEwTzBNBgsrBgEEAYLX fwEBATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vd3d3LnRydXN0Y29yc3lzdGVtcy5j b20vcmVzb3VyY2VzL2Nwcy5wZGYwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL2Ny bC50cnVzdGNvci5jYS9yb290L2NhMS5jcmwwgYgGCCsGAQUFBwEBBHwwejAsBggr BgEFBQcwAYYgaHR0cDovL29jc3AudHJ1c3Rjb3IuY2Evcm9vdC9jYTEwSgYIKwYB BQUHMAKGPmh0dHA6Ly93d3cudHJ1c3Rjb3JzeXN0ZW1zLmNvbS9jZXJ0cy9UcnVz dENvcl9Sb290Q2VydF9DQTEucGVtMA0GCSqGSIb3DQEBDQUAA4IBAQCidSqv6qQ4 5cbef/GbMcLxw6r+7V2StOLwXpJoeEopsuaWMMWtV5FhfWhXK74Vfuq94nXif6CR 3TLUGRQ29dQA50XjTVcs/9IPb8HasbAAKsAPfBAL+Xd6TVVXdR1s1sJlEmX+Vak0 d6TUyFXLCubPsZ1yLZ97ZMPNrNq7va0Fctg1CdqFK95v3fIxyf4B0xWvy+kwE3pA yY/ogkM2sATvaNZQ9kDEtyzS1QhaklIN624pGisD4KP7m9MTov2jHgzwZ+H4Io7V 0owgMbTTs7n7/GSAsqYT0bcocGjbCA5O6/fJcUOlksL2j8m9jZUlJ8ZOpR8T/kfg B1IC08vuANAh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFOTCCBCGgAwIBAgIIYLmmFnDdSPkwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig Um9vdENlcnQgQ0EtMTAeFw0xNjAyMDUxMTQ3NTlaFw0yOTEyMzAxNjIwMTBaMIGP MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMSQwIgYDVQQKDBtUcnVzdENv ciBTeXN0ZW1zIFMuIGRlIFIuTC4xGTAXBgNVBAsMEFRydXN0Q29yIE5ldHdvcmsx LjAsBgNVBAMMJVRydXN0Q29yIEJhc2ljIFNlY3VyZSBTaXRlIDIwNDggKENBMSkw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDObYRhPlcMtsEa8jXfpkHs 8dhidUskXFe2jDOfAyvusLBTJSrOxnAL6i9+qYIcyZHyP3dx2x3cwxugwMdIjM8U w8lfpgUry0NjidocMZ6YaiJVTarC9LJO4Gy/bwsn039EFaIozAc57ctW8I+ECbdg YMvdOSS0dkSOgQWSbNdEzAr+VTcI8lnIkCSFbAXfhj0OaUT3nriwywHQA1RDiJ8S FUvN5E3rWYkHggAuHt6j59f3gYvy+IVFhdXf5DSZm9EoNj3Bu8jU/YxZBEbM8XSo kJ/dzSRN9JDnhEwnM7F2D+/3VTC1YwfJsskvQXJK8fMUzO/JLCcbh4ZPnTGS0wLR AgMBAAGjggGAMIIBfDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd BgNVHQ4EFgQUcIknZtQTu+4DVx2JUpSJCRl7bRcwHwYDVR0jBBgwFoAU7mtJPHo/ DeOxCbeKyKsZn3MzUOcwWAYDVR0gBFEwTzBNBgsrBgEEAYLXfwEBATA+MDwGCCsG AQUFBwIBFjBodHRwOi8vd3d3LnRydXN0Y29yc3lzdGVtcy5jb20vcmVzb3VyY2Vz L2Nwcy5wZGYwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL2NybC50cnVzdGNvci5j YS9yb290L2NhMS5jcmwwgYgGCCsGAQUFBwEBBHwwejAsBggrBgEFBQcwAYYgaHR0 cDovL29jc3AudHJ1c3Rjb3IuY2Evcm9vdC9jYTEwSgYIKwYBBQUHMAKGPmh0dHA6 Ly93d3cudHJ1c3Rjb3JzeXN0ZW1zLmNvbS9jZXJ0cy9UcnVzdENvcl9Sb290Q2Vy dF9DQTEucGVtMA0GCSqGSIb3DQEBCwUAA4IBAQBxVQ/eZPp1x4iqmfgU77tY2K87 g3wwpz8yFtTbn1Au6h7ElcngjRdHqjIBbRm0BZJ7lIRpOO0JjOp+OqWAh5F7TxQ0 oGo4RBM9zVkgSkFzk+0TxM34gdWtgW6C0e2Ix8G91X35UoZgzEWGdTTETce2OWcm vHBPrY5LQWrs+6V031SbgOSfWNGJwbYZ4uz45UbsoFAHWhEWC2W7Tz7UQ9RUGkq7 mz7phE9NqzpfyoIW8qo7mO7lovBd8MMX1ie1fPq4D+d1neo12u1s3/pOEtP3qAC1 JeeGKcTyLJSlu7xa2Cktd3c6J0zPEiENmurFYjud7zKEo+WLWFj41EuXa4hl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHODCCBSCgAwIBAgIJAJZr5ZC7I+8qMA0GCSqGSIb3DQEBDQUAMIGkMQswCQYD VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y IFJvb3RDZXJ0IENBLTIwHhcNMTYwMjA1MTIwNDA1WhcNMjkxMjMwMTYyMDEwWjCB jTELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEkMCIGA1UECgwbVHJ1c3RD b3IgU3lzdGVtcyBTLiBkZSBSLkwuMRkwFwYDVQQLDBBUcnVzdENvciBOZXR3b3Jr MSwwKgYDVQQDDCNUcnVzdENvciBFbmhhbmNlZCBTZWN1cmUgU2l0ZSAoQ0EyKTCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANdOQOhmRcvwK1pV5N+3zowr TqPuak2/9cTRMnN/Nh7tiRf6XralicXrNXP+CaLPdYT577pDmxD8GSS1VZf0Fvu/ ynh3WOgf8GQEfs/0hwtQA8gzUidN+BWFE7NPoRJJzezZgUsmK9jNeCCHKc/Cj6uK drWmc0nayLKgq01Rp9JwDfO1Kc1wDsAGbYzDBZGBlgN0oMinxhg0SXkDdoajUeHD ZOnmqeQeLKfwCisXMEcxxgwaB1BEHguprb3h6J9mkMz01n9qzrn/uuxcb1Zihh+J gySSh7qGjqmPzVKHr+HAlfgj9sKKW5E48iqX7dw71QSKfdICckdVlXHJiJq5r8cK 8HcLWL2i0AB3V+Hafx+USynO5hkyeqFJulUz9xWvt4fgQ36YOQIv0HTPgl0RK/my hVko+kloI1ytu3QDtHr2cnC4WpQC2cZoLIDaCOWURWppmry00jJ3EXxYiLF19QBu L9wctL92TXcGEszHBM5rnYKgwnuHOGs6IGDyOJd21KVyDUrv5MuwarDVBo+lSEd7 M2CIUtvoVYNUCZJ4k8oNzdERQ2gk0rHJCXzPn8mpOIbvWjky0CeTQWaZrL2p4ZEs eFVS1S1QbZZq6owX4cIa1xp9Z0JpHR+XyXcqa7IN/xlllbnPnO2np8hfVc5AC+Vg MRTCp5OWs7gPssxaW5aLAgMBAAGjggGAMIIBfDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUkffx/I4Kdr765gAFr9cCoiTNWp4wHwYD VR0jBBgwFoAU2f4hQG6UnrybPZx9mCAZ5YwwYrIwWAYDVR0gBFEwTzBNBgsrBgEE AYLXfwEBATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vd3d3LnRydXN0Y29yc3lzdGVt cy5jb20vcmVzb3VyY2VzL2Nwcy5wZGYwNAYDVR0fBC0wKzApoCegJYYjaHR0cDov L2NybC50cnVzdGNvci5jYS9yb290L2NhMi5jcmwwgYgGCCsGAQUFBwEBBHwwejAs BggrBgEFBQcwAYYgaHR0cDovL29jc3AudHJ1c3Rjb3IuY2Evcm9vdC9jYTIwSgYI KwYBBQUHMAKGPmh0dHA6Ly93d3cudHJ1c3Rjb3JzeXN0ZW1zLmNvbS9jZXJ0cy9U cnVzdENvcl9Sb290Q2VydF9DQTIucGVtMA0GCSqGSIb3DQEBDQUAA4ICAQCYOSRa V6reKei9mI3C6gdtGQuWzr8dDbzP1zfhAi/Eb0jSvcFcpUT24OhjWdSLdIMjAO8X 45TUr7W3/UhSsmRFO1ziv93X0aP63nto3H0b3YCioCoshDLzyCegUyUxRUaZh4U3 /SLYu0dLnEX22Ezup/ORZW5w2Os1PjU/F4s4HDqVTs74nFn7kb71z7kAsAshWXQn YiRam0Qo8+F0tFdURT0yVMsmFnfiZphDklT+Y+AV6x78czLYtsJFiGk2GJoTqWYr Hsy9aZiOTJI5bKJpR4kMmb6p5ZZZSEMXoE+syo00sCJvH6JCiJeP+71mN3p4ISUt 4jdx5OO4v3vHOVXqdVUccuENpx2yreAXFUbZyjtcc31Z9DRmhj7jDdoyhZJxMdfK +MQZWWsIiq9Vv6UV7adciGfxZ6NlLgple5b50jI5nWLHWvGGt6wQQKCIVgUi3FlJ F+QdgT5LyoSx+vuWarFJb3m45WLX90XSqCpNFEmYReitJV1OBrrQ3U1FcqGqD0wE TFfSxr14AEEHZqSqLGk8S+C2TAblKeBzX0zFuMWgjh0WCguKpeFJwWKXxtGGwsQb xwJpSPvH0/5yavkoNuxyweBbOKZf4pDUZtE7hWrgGDkU1U7ZVsmVXT4z1r3eXs1/ NCFo5pXxvhAPwTMtdquQEVjDSqJjd2fuJsmH2w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFIzCCBAugAwIBAgIJAIIlXQS/ZP6dMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y IEVDQS0xMB4XDTE2MDIwNTEyMTA0NloXDTI5MTIzMDE2MjAxMFowgYYxCzAJBgNV BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExJDAiBgNVBAoMG1RydXN0Q29yIFN5c3Rl bXMgUy4gZGUgUi5MLjEZMBcGA1UECwwQVHJ1c3RDb3IgTmV0d29yazElMCMGA1UE AwwcVHJ1c3RDb3IgRXh0ZXJuYWwgUEtJIChFQ0ExKTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAL3Pyqh0dJY3wkNodP5XxI0ue6Vzq7Gswyv/EYADedt0 9Cv+vwhUU3p6CcUF8V/Or6vLKkTIEInLKdmFbIW6WW1/jbTFNPBzY0LBREpO/cSy B9kI+8rPZ41/Hu2+TtXyo6CXVoESRC9hDAseuCTIC6eZFJi+0cWVTCwD/9fhlfBZ 9ryj6Zqn2H27XGFHZ16LpVPgXhmxxqMcvLIqAKfVq0NsVdq0C5Rv6/mer+/K4yCR LL3z9PvEvcPASl7OuxFO3XVI6KbAEyOjZVAoO0xKFIhL6mOFRAQZ3z4iGihf21Fc fJDHO6uzrSjEKcr4tlN8GZ52wBl8qtOjJiNcgjh6FcMCAwEAAaOCAXowggF2MA8G A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBRmydJEzK2l 1pbTBBLfHcWID1yNujAfBgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjBY BgNVHSAEUTBPME0GCysGAQQBgtd/AQEBMD4wPAYIKwYBBQUHAgEWMGh0dHA6Ly93 d3cudHJ1c3Rjb3JzeXN0ZW1zLmNvbS9yZXNvdXJjZXMvY3BzLnBkZjA1BgNVHR8E LjAsMCqgKKAmhiRodHRwOi8vY3JsLnRydXN0Y29yLmNhL3Jvb3QvZWNhMS5jcmww gYEGCCsGAQUFBwEBBHUwczAtBggrBgEFBQcwAYYhaHR0cDovL29jc3AudHJ1c3Rj b3IuY2Evcm9vdC9lY2ExMEIGCCsGAQUFBzAChjZodHRwOi8vd3d3LnRydXN0Y29y c3lzdGVtcy5jb20vY2VydHMvVHJ1c3RDb3JfRUNBMS5wZW0wDQYJKoZIhvcNAQEL BQADggEBAF8LomkYI0Qu3F6UBZQ+FepuO0fm2r2D74ehw+XKkyCawO3KLBPdSyZL qg3kFll7FnSkFpev3dCT/MAQmRvjmxQ9wRYV2y7vUpjARV2PJAG8P1cQwu1KYrRU JU/hplOKwfSxaiL0t2Ye+2Og2A9B6ccpBvIgk0tbITNsXtOKyDMBtj1i1G8HmOey 8Zw+JUrsj0r2jxi2gqguLAcY0PqDYRlv0UQCKOEI3BVwmDGF+4RL1L9Ns+Blh8+S /f/CDSjwJGhb2q5K3pwNv2Qulh1LoqQVmfcaCOBHDVVYTmgBLahNEo1rJWJBgz27 n/gi9zWmPJgUf+zWvTSBX6Cn54HHwr8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFNDCCBBygAwIBAgIKOfs4FwAAAAAADTANBgkqhkiG9w0BAQsFADCBijELMAkG A1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAo YykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYG A1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0xNjAyMTAx NjUzMjRaFw0zNzEyMTExNjA5NTFaMIGSMQswCQYDVQQGEwJDSDEQMA4GA1UEChMH V0lTZUtleTEmMCQGA1UECxMdQ29weXJpZ2h0IChjKSAyMDE2IFdJU2VLZXkgU0Ex FjAUBgNVBAsTDUludGVybmF0aW9uYWwxMTAvBgNVBAMTKFdJU2VLZXkgQ2VydGlm eUlEIEFkdmFuY2VkIFNlcnZpY2VzIENBIDQwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQC2L9X7Ban4aQ6ilphaaAFk5SCf+bnLfsdJdjzOYGexsY7ZIdiU SyU6bx8u7AZ9InzYm/0AQ2+UfxhtO+hRpMMyF60zbIEEz8jF7+RFiZauM8Tu6GR+ t2+MEDVFzCRCiBVm6iCLusHQ6oBjbtzgNWeezKpXBW5f8e0GWmf05HtLw0m6050I mk7I6+XYhRUruVWS1U8kQom1qXp86OoSS+eRqZAFiXB2h10A94wdrosHwl3vClBX RF7pa+gK5j7bB5F9w4bWVX/a41J+Y8WihanlVASRkzhnt5Jf+cRBCOhppjt57uBv OnpX9IHdv6KpWiB27ycmYQrXDJTEab6FFWwJAgMBAAGjggGQMIIBjDAOBgNVHQ8B Af8EBAMCAQYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFPTkm1fSrsKeiE0A uiuvZcljqYebME4GA1UdIARHMEUwOwYIYIV0BQ4EAwEwLzAtBggrBgEFBQcCARYh aHR0cDovL3d3dy53aXNla2V5LmNvbS9yZXBvc2l0b3J5MAYGBFUdIAAwGQYJKwYB BAGCNxQCBAweCgBTAHUAYgBDAEEwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSME GDAWgBSzA36uNrywedHclCa2Eb4hsmmGlDA7BgNVHR8ENDAyMDCgLqAshipodHRw Oi8vcHVibGljLndpc2VrZXkuY29tL2NybC9vd2dyZ2FjYS5jcmwwbAYIKwYBBQUH AQEEYDBeMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC53aXNla2V5LmNvbS8wNgYI KwYBBQUHMAKGKmh0dHA6Ly9wdWJsaWMud2lzZWtleS5jb20vY3J0L293Z3JnYWNh LmNydDANBgkqhkiG9w0BAQsFAAOCAQEAZcx6VSBW+3JeiwtMNKtmzzHomn8jW5xm TxydkPzpxbhLqxl4bc3pbT7oxQOZSYRQbClpuUO7i3id9yy/fuFFTP8jYnLU3GA2 jKiDISQ30lVnIdMxstUz/nWzzH4M9iW6pZ7qN+RWB5ypLQTrvCFyuSNg5P1vWTMP 34Ri1yvW8xVvDr3o5FjOm+pNeJgx9+iuWQbPvp7gKYVURLDKp/+qTrcLWtRHxO1y HP7B+0QyKcZ+0BBKgHFt+3LtJb0SaQzZa3+mNJdD0dEQauUfwuHQOM8D5ytxQ7OY ISHgrJwe50m1deYYpK6lif6C3dTzp0nhZtDBsrEGxbDJvquSYYPU2g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGbzCCBFegAwIBAgIICZftEJ0fB/wwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTg0ODUyWhcNMzEwMjEyMTg0 ODUyWjBpMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjEeMBwGA1UEAwwVU1NMLmNv bSBSU0EgU1NMIHN1YkNBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA hPYpOunhcxiF6xNzl6Tsm/Q89rnu2jVTXTBOZPaBkSD1Ic4lm7qkYwlZ/UgV5nn1 5ohhceYDC2AlR9RvGbP+26qrNcuE0XOdHJOB4SoY4d6OqLAQ6ZB0LdERK1Saa5lp QlqHE8936dpr3hGWyqMb2LsdUuhQIzwNkLU/n9HO35irKCbKgS3FeejqkdqK5l6B b11693o4bz9UZCUdBcQ/Xz06tA5cfnHvYkmmjxhj1lLTKwkQhWuIDrpbwWLO0QVO c29s9ieomRKm8sYMyiBG4QqRQ/+bXwp48cF0qAByGWD6b8/gG4Xq1IBgO5p+aWFS 0mszkk5rsh4b3XbTHohP3oWQIOV20WWdtVWXiQuBB8RocAl0Ga//b+epiGgME5JX LWXD1aDg/xHy8MUsaMlh6jDfVIFepkPnkwXDpR/n36hpgKa9dErMkgbYeEaPanLH Yd0kv4xQ36PlMMs9WhoDErGcEG9KxAXN4Axr5wl6PTDn/lXcUFvQoIq/5CSP+Kt5 jq9tK/gRrAc4AWqRugDvQPYUm00Rqzj5Oxm5NVQYDzbyoA66CD68LETuVrfa9GuW 9MAZRO6CDzonAezIdNHsslDb1H8VN/k0zMxjI+0ub4IAmc3I5GfZtvYcpjtMj8L4 2TDS34/COov/Pf2HZ/XXGlzjZ7WPmLl4fdB6hhjs2BsCAwEAAaOCAQYwggECMDAG CCsGAQUFBwEBBCQwIjAgBggrBgEFBQcwAYYUaHR0cDovL29jc3BzLnNzbC5jb20w HQYDVR0OBBYEFCYUfuDc16b34tQEJ99h8cLs5zLKMA8GA1UdEwEB/wQFMAMBAf8w HwYDVR0jBBgwFoAU3QQJB6L1en1SUxKSle44gCUNplkwEQYDVR0gBAowCDAGBgRV HSAAMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmxzLnNzbC5jb20vc3NsLmNv bS1yc2EtUm9vdENBLmNybDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4ICAQAi6e/iSV5DEqDO6XjQ SIIzXgc255yv6Oc2sqZnvRyVBHtHvo62jMoHY3Xunc/EofbeS4aHdYBvgkn6CNTj VkCU+psWwcT3Pg83uP4k4Thu7bXvrClfS+XBlbJiCF/PSJxLrKnxRn+XIGiYl62H glBhq9K8/fZrI2Qh1mZJmWE0FlxEDCb4i8SBNi8lmDogaFi8/yl32Z9ahmhxcLit DU/XyKA0yOqvIrOGKH95v+/l8fQkzE1VEFvj+iyv4TXd7mRZDOsfqfIDZhrpou02 kXH/hcXlrR++t8kjj9wt8HHQ+FkryWI6bU3KPRJR6N8EH2EHi23Rp8/kyMs+gwaz zMqnkNPbMME723rXk6/85sjOUaZCmhmRIx9rgqIWQesU962J0FruGOOasLT7WbZi FsmSblmpjUAo49sIRi7X493qegyCEAa412ynybhQ7LVsTLEPxVbdmGVih3jVTif/ Nztr2Isaaz4LpMEo4mGCiGxec5mKr1w8AE9n6D91CvxR5/zL1VU1JCVC7sAtkdki vnN1/6jEKFJvlUr5/FX04JXeomIjXTI8ciruZ6HIkbtJup1n9Zxvmr9JQcFTsP2c bRbjaT7JD6MBidAWRCJWClR/5etTZwWwWrRCrzvIHC7WO6rCzwu69a+l7ofCKlWs y702dmPTKEdEfwhgLx0LxJr/Aw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFIDCCBAigAwIBAgIOR8MP/NQCAYElup+26MkwDQYJKoZIhvcNAQELBQAwYzEL MAkGA1UEBhMCQkUxFTATBgNVBAsTDFRydXN0ZWQgUm9vdDEZMBcGA1UEChMQR2xv YmFsU2lnbiBudi1zYTEiMCAGA1UEAxMZVHJ1c3RlZCBSb290IENBIFNIQTI1NiBH MjAeFw0xNjAyMjQwMDAwMDBaFw0yNjAyMjQwMDAwMDBaMIGDMQswCQYDVQQGEwJC UjEPMA0GA1UECAwGR29pw6FzMREwDwYDVQQHDAhHb2nDom5pYTE3MDUGA1UEChMu U09MVVRJIC0gU09MVUNPRVMgRU0gTkVHT0NJT1MgSU5URUxJR0VOVEVTIFMvQTEX MBUGA1UEAxMOU29sdXRpIENBIC0gRFYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDfSHqaA6r8TlKODVnmmc0FmtGbOikRqwkjm5ILI5uyI3tAyKCQR0ED 7liWcDdHCwaGjFIpJcFVCYXkMMvlm81y5iuKWnI04ocrgePKc+Ar4HtAPqYst8ut GH0qoeEogTHI2u6bO1lkv5P6A/GAwG9xLsR+31vuCXXidDM6+A0DS0NsDJelHOGd obdlp88Yr4cz692zZ2ZmU1CP7wAadzVuYZWhky9xfVoa32vU/OrYmpGIY3Ye8poE oDFbYR9V/9xgj+HmCkJZV6WR4RQd6nqctkCn+nVLhzdCb2XCNZWoH6Cvvarla8pD UICTLVEvlgK0vN5oUpqGUiAVBnOpZ8/NAgMBAAGjggGvMIIBqzAOBgNVHQ8BAf8E BAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI MAYBAf8CAQAwHQYDVR0OBBYEFIfhAyBlC/oDSaT2czPJoGa/14dSMB8GA1UdIwQY MBaAFMhjmwhpVMKYyNnN4zO3UF74yQGbMIGNBggrBgEFBQcBAQSBgDB+MDcGCCsG AQUFBzABhitodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290c2hh MmcyMEMGCCsGAQUFBzAChjdodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2Nh Y2VydC90cnVzdHJvb3RzaGEyZzIuY3J0MD4GA1UdHwQ3MDUwM6AxoC+GLWh0dHA6 Ly9jcmwuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290c2hhMmcyLmNybDBWBgNVHSAE TzBNMEEGCSsGAQQBoDIBCjA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9i YWxzaWduLmNvbS9yZXBvc2l0b3J5LzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQAD ggEBAF7Op6aMHPlVRz2dJxX0XLPHo+Ws1prelFH9KbLSK/HkEy6SubdAKIKI837/ kLyFC/t9FfnGDp3iFf4yMbP1XWMfS5EhkRvqwnqgUGWH1pV1evObyMEIzaWp+r5b LFMMza5xujqqce1ynLwngDqluLm9UJRewKXJeRPc6szFNianCxmkiTQn/nBeopBx wxSqA6Ts+OQC3U8+rsUOYueLdoaStnVa1kIjgwj0vfQhaMsf/K66GDz0UNIOu5bH /iTKSrNgIj6NNeC/q0xIm3Ktg+/GtRQY4Usqw2vAHGPvjkMGeuer6Jds5Qsty1Y+ stxbttVBDzR1ObV9X3ZsLcE9+lU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFHzCCBAegAwIBAgIOR8MP/enKcGhLiHpXDd8wDQYJKoZIhvcNAQELBQAwYzEL MAkGA1UEBhMCQkUxFTATBgNVBAsTDFRydXN0ZWQgUm9vdDEZMBcGA1UEChMQR2xv YmFsU2lnbiBudi1zYTEiMCAGA1UEAxMZVHJ1c3RlZCBSb290IENBIFNIQTI1NiBH MjAeFw0xNjAyMjQwMDAwMDBaFw0yNjAyMjQwMDAwMDBaMIGDMQswCQYDVQQGEwJC UjEPMA0GA1UECAwGR29pw6FzMREwDwYDVQQHDAhHb2nDom5pYTE3MDUGA1UEChMu U09MVVRJIC0gU09MVUNPRVMgRU0gTkVHT0NJT1MgSU5URUxJR0VOVEVTIFMvQTEX MBUGA1UEAxMOU29sdXRpIENBIC0gRVYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDRrAkXiaEMqbWuTbA14L9TBdVppjMF9fKPfMs1sd7mUgL7Bbrf2rs1 oeXVM6UyjvsNxe4BfLp+z3fkHEXiyRYu22P4iyT23suaGMp47BErHGh4bBn4cBIM XrAW7wrhzhBLUEVuMfkhU2sZyK9Ci6PLnHH4jE1Phu1Ql+HZkswE4cn4bUImSb+9 L9449gg9Jvyok4xvEcnKg9RCtlWxXCG34Cz3o/417Ud0cWMK289AA9SPZbf7s5Eb fJBe39XVvCwEhZM6i7FyYOQ31V/PjZ2bVM18UuHC6qdtNBV30TC9G0ZNga9bNTUs GQqgv3vNScm0Afg7hh21jAMBU40z0UFnAgMBAAGjggGuMIIBqjAOBgNVHQ8BAf8E BAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI MAYBAf8CAQAwHQYDVR0OBBYEFCQIvAqAXDm6uBZ3fpKRSjLyuskqMB8GA1UdIwQY MBaAFMhjmwhpVMKYyNnN4zO3UF74yQGbMIGNBggrBgEFBQcBAQSBgDB+MDcGCCsG AQUFBzABhitodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290c2hh MmcyMEMGCCsGAQUFBzAChjdodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2Nh Y2VydC90cnVzdHJvb3RzaGEyZzIuY3J0MD4GA1UdHwQ3MDUwM6AxoC+GLWh0dHA6 Ly9jcmwuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290c2hhMmcyLmNybDBVBgNVHSAE TjBMMEEGCSsGAQQBoDIBATA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9i YWxzaWduLmNvbS9yZXBvc2l0b3J5LzAHBgVngQwBATANBgkqhkiG9w0BAQsFAAOC AQEAA6cXqLoUNtT7pkG4MUoxDEtJozQpnSSHAcylSxDz5K9WeJjSQ/Wije8uKDW4 FJEIjsBq5hHJMcDe9QU7dymUVnQvgUcrUrCO99V4hKPVCGprWU31bG5ifSJ9UjU5 tp9qoUYVHISmHkKVfy4v2hkqXpeFRpfC9QC4zdvgslpWKsDHJgsjuCXHS4EnNeDH UY16BsqQXxRJKmtnRz9B17GU3yp3yC7Z1/50bUa9NOhpsAdl1TtIxcBmN8HLaFax e6Whd8yqm+vQkJvAdoR+5N6o+EbBC1DLgdvbzSBsB1LiPaY9PJCzR1eolCyxcK4N maySrGARfLUDiu2+arpMILDf5A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFIDCCBAigAwIBAgIOR8MP/VnSdoH2bvnFoHUwDQYJKoZIhvcNAQELBQAwYzEL MAkGA1UEBhMCQkUxFTATBgNVBAsTDFRydXN0ZWQgUm9vdDEZMBcGA1UEChMQR2xv YmFsU2lnbiBudi1zYTEiMCAGA1UEAxMZVHJ1c3RlZCBSb290IENBIFNIQTI1NiBH MjAeFw0xNjAyMjQwMDAwMDBaFw0yNjAyMjQwMDAwMDBaMIGDMQswCQYDVQQGEwJC UjEPMA0GA1UECAwGR29pw6FzMREwDwYDVQQHDAhHb2nDom5pYTE3MDUGA1UEChMu U09MVVRJIC0gU09MVUNPRVMgRU0gTkVHT0NJT1MgSU5URUxJR0VOVEVTIFMvQTEX MBUGA1UEAxMOU29sdXRpIENBIC0gT1YwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDeVNxdmst2nKvut2N5tLzCGgcCVLEm3S6Qja9jC5N3XmwBjdu53tDR FplNeI1P3Di6682foY9VmP2pkGGCONV6QvLiX290N9DPnPesEE+GAClYrT1NdkB4 XfniD3H4XZt8nJVarvnfD7/MwWklTutbFhLyVg38ttJ1GLJz6riyYaShwlZRKJuU zx5qlUd+hHdMvYg6oI3UpW2UPHi4ge41Bqv2apntVI1cxNR4pH/CDhDGYZXitqpn CukcwB9J2EtdDe4EprjS8tlKsHMIgaKWFsgoF90WdWgZk0Sa64b2N6TfFZCncXaa oMikntyPgi7xjlhP+8Wr7QTmYuhBn0FvAgMBAAGjggGvMIIBqzAOBgNVHQ8BAf8E BAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI MAYBAf8CAQAwHQYDVR0OBBYEFIl0C7uxUXURk+5LSyDvYW64oQfmMB8GA1UdIwQY MBaAFMhjmwhpVMKYyNnN4zO3UF74yQGbMIGNBggrBgEFBQcBAQSBgDB+MDcGCCsG AQUFBzABhitodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290c2hh MmcyMEMGCCsGAQUFBzAChjdodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2Nh Y2VydC90cnVzdHJvb3RzaGEyZzIuY3J0MD4GA1UdHwQ3MDUwM6AxoC+GLWh0dHA6 Ly9jcmwuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290c2hhMmcyLmNybDBWBgNVHSAE TzBNMEEGCSsGAQQBoDIBFDA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9i YWxzaWduLmNvbS9yZXBvc2l0b3J5LzAIBgZngQwBAgIwDQYJKoZIhvcNAQELBQAD ggEBAFTUYjeQTMXmxSYyyK8Bju+3wlk11QWE+v+vR7eUSYicJ4mfsh6w33CDhZcG BdY9Lc9ejNEDT/HIP4yx9p6GdxFaadPfg7IkxcvybrMNUs7FW7XeqtI9cDqPUbqn 3dxdL+vZdLK7LTLHi4eYK8aA5YeF7j01sHLxBX7EXucZOYwxL8B8QaY73NzpfjKK IrjsySNsO1MKAis/RfIAqXfQ9qmTIhi3CsU8vi0p4NKhnHcDAyv1XNWB46pWxP4S AgZkrt6gkcU5tDUEZ/h/HkfBQrPA15WRqB+P144zF59aSMHXZHX4O+h1ql1APplX WhXfPgbDsUxceymgUTRnqLmsbxA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFOTCCBCGgAwIBAgIMVRYVFQAAAABRzhYOMA0GCSqGSIb3DQEBCwUAMIG0MRQw EgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQ U18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMB4XDTE2MDIyNTE4MDgx NloXDTI5MDYyNTE4MzgxNlowgbcxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRy dXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRl cm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxKzApBgNVBAMTIkVudHJ1c3QgQ2xhc3MgMyBDbGllbnQg Q0EgLSBTSEEyNTYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGnEvB T0qd2X3TO1eRq83pdhUtwCAvLDGGxQk9sB+RhJhDlS7UnqraVeLgYOi7B+/Lg+0u Xxny0CjtOmQ/y64wYCHmZqtYTmJndk5SjNx7mEQODi2QULUh+42xza8hByWXz7oP GEcZTnHLabj6I20aBhE1wVa6n2Ih8bDxAY9ez/EiosFCDvXNMugrJ/SSbwsVXvz6 aVKwjn6ky3W5RYS1kwMLcitAs25DQqETGRhkRNSmIAlFsDpkD1b95IUojrjUOCPH LuKw+5r7GjiBkzLnLR+ujjcXzvzCFD993yTsseygqo4jBIEce68pztTn1OFm6W5k 6eEFsiqRmHBY2PILAgMBAAGjggFEMIIBQDAOBgNVHQ8BAf8EBAMCAQYwNAYDVR0l BC0wKwYIKwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMBglghkgBhvprKAsw OwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuZW50 cnVzdC5uZXQvcnBhMBIGA1UdEwEB/wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAl MCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAyBgNVHR8EKzAp MCegJaAjhiFodHRwOi8vY3JsLmVudHJ1c3QubmV0LzIwNDhjYS5jcmwwHQYDVR0O BBYEFAafb06iKU4PDK4Xv7aYRu+tuDtyMB8GA1UdIwQYMBaAFFXkgdERgL7YibkI ozH5oSQJFrlwMA0GCSqGSIb3DQEBCwUAA4IBAQB8eBvEzfG7ciGMiBdPtSqio/2d h+DXHDyC2Z6Vkzd305spuLwA0olAKJKZgKFM804XffTDY4zCTvY3sX9gMvHUk1ut lt2Kt8KPDfFLrfxL21sNyj79WG99p7vrzVlsO+8AFZU2AdTLPLVjz9/Tmqr5RRKy q4IPZg0uaAM4+m6VIOceWnYEI2A9S+XpEHWqF9vbCevuF0iLnZalaqPdTBkfYkAu D/T6AOZabkbolo2bjssLzYsHOZExFCFu37kJZTw/JaDlC7o6A0r0QaZojaXqYM0j SfppwIWH58keRNVFyBIApO0GmIpBSieh8hZlo1X6K0yukH+M53cikOr4IS/F -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF/DCCA+SgAwIBAgIRAMsDASzttFrEDbmOhA+2mf8wDQYJKoZIhvcNAQEMBQAw gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE2MDIy NjAwMDAwMFoXDTI2MDIyNTIzNTk1OVowgYYxCzAJBgNVBAYTAlVTMQswCQYDVQQI EwJHQTEQMA4GA1UEBxMHQXRsYW50YTEkMCIGA1UEChMbVW5pdGVkIFBhcmNlbCBT ZXJ2aWNlLCBJbmMuMTIwMAYDVQQDEylVbml0ZWQgUGFyY2VsIFNlcnZpY2UsIElu Yy4gUlNBIENsaWVudCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AKpd1Pa2WtdW/kTnGMnhCKROf/rJhzXdC/d6z+s2bYDeeB452YFKrwZ0u4ILhBYA uXvcJAdXFFv4qGNZljrAME1D+8XmmOCbUT3XW2D7D0oiXAaGvtyfk7geO7Ngq7sQ taOfchSRPLtwBkzpkhOjRXgRJ8xdNkiIbSFFTVnJw5ORsTbiPz+VZA1u0ULTrUHS y4zB1EJk4CbeT2Iev4RPF00X4LGdHW68c1LmPB890avuOTjJc8/vMq0iHmmUWvTg bVzUb3bpWVa4Dr5sewMyDRrPA5Yd9wxL7ZUC+eDt7BmHO+UZXvaBtE7xmGJ37tMH CNKwthmuMDI5yEuBUC1lCX0CAwEAAaOCAWIwggFeMB8GA1UdIwQYMBaAFLuvfgI9 +qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBRM2cUxk9ZG55upTTCODLR2gx4/XjAO BgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggr BgEFBQcDAgYIKwYBBQUHAwQwGAYDVR0gBBEwDzANBgsrBgEEAbIxAQICODBMBgNV HR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FD ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOwYIKwYB BQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET1JTQUFkZFRydXN0 Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJ KoZIhvcNAQEMBQADggIBAIxU5qb0sw6nQn5Gv+gQMxe2/KoyHAVEI5KN8VEHKdxH zI7V2bJHJ78QQc2i5ZzHwpOaA76RNqiTCDQejSnPo2Y1VY+P9Pd0rJDjJNDRCKAf luG22rCFqQxJw5JTFlS+kMQPo/cd5SabCODZr/YO+ydBfS3JLhvIbzk+powJ1Qa9 rATOPllhgxtTCEjc3FBRoy7J4uGubMbVLhMuCib5nQoquuNRh8F02V2ACHr12nWW AjVKOyrZ6kzQXN1Dhkxtkx7o20qxrSEE95NAUSG+jYyEVKntIxgk9xmr/7VQaYLw TkMtA3+NS0J+TJ6DLfCSBh3wKSd9K3klX8KFO2pAHCMYVa58lDBPbmREt8UlAAhX j6x+uF+e37Vik7EJ8hGmNuYQTIpHTpTELbx8+XWIMOXG7y4sEku4q2P7ZXI4DbXM BzXCmOtbPmwLGJiwCHUIKXb1OKMkH4UcFxMV9X4WPKXkyGUhF7WJdaOzjQSpZgKG cIhz83jYNvPJ1XCpVPS5AXJInDLNVoHTqVszlMqiUZFn8Q7ADfvYrXGCjPS/Qf1q rTvD9dFenvFINMl0LkBfl0KW0HrJt0x11529lKbFvHpHDGQlcGZLXe/O9rl7BhX1 SJam725pCcQtipGfRn43tVh/KZbpe+E/zTznjWv04I7c09SQMzs5JrkicPcqhvrd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGVjCCBT6gAwIBAgIQB08tBK3r/BmIT0IP/53yzzANBgkqhkiG9w0BAQsFADCB ijELMAkGA1UEBhMCVVMxGjAYBgNVBAoTEU9yaW9uIEhlYWx0aCBJbmMuMS0wKwYD VQQLEyRPcmlvbiBIZWFsdGggRGlyZWN0IFNlY3VyZSBNZXNzYWdpbmcxMDAuBgNV BAMTJ09yaW9uIEhlYWx0aCBEaXJlY3QgU2VjdXJlIE1lc3NhZ2luZyBDQTAeFw0x NjAzMDExMjM0MDVaFw0yNjAzMDExMjM0MDVaMGkxCzAJBgNVBAYTAlVTMRMwEQYD VQQKEwpPcHRpb25jYXJlMS0wKwYDVQQLEyRPcmlvbiBIZWFsdGggRGlyZWN0IFNl Y3VyZSBNZXNzYWdpbmcxFjAUBgNVBAMTDU9wdGlvbmNhcmUgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbC/sJMYCq40V/18U8EOBG6ulx+4QLeUuw WbFrNb8wZ/hznX7AJJ2xWysQrmdd1cX0mlS8qU24/J3l+YZZxyfwc6vvJQIU6YMK h3jbhnQuJbg5Ze8QoQpBKf17A6K4SNMd8XDVUs1BPPNRuzloJpgzbY77m2Gg5zti lzfzIlGyR8wI53+iEiDRGevD3hKNeKT33IL8YjfyV8nvbrPfNk/3tI8PHaVZLWfx aomBnPfpPU47xkGJ0jRBU88kUKX0rppF961eEd+ZJ+fSwG8SGYArcmXqZ1gMqAyM 8zrs2QOwIAXBuFCB56OaBTTeGLOLVUCWcgVRJkYHAgINgz/F3s/tAgMBAAGjggLW MIIC0jAdBgNVHQ4EFgQUrXWO+6UVi1FWUZVFDRpxS+xPPmMwHwYDVR0jBBgwFoAU pW4i/zlpOiP7iSQXxmCUABrajp4wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8B Af8EBAMCAYYwegYIKwYBBQUHAQEEbjBsMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5kaWdpY2VydC5jb20wRAYIKwYBBQUHMAKGOGh0dHA6Ly9jYWNlcnRzLmRpZ2lj ZXJ0LmNvbS9haWFPcmlvbkhlYWx0aElzc3VpbmdDQXMucDdjMIGZBgNVHR8EgZEw gY4wRaBDoEGGP2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9PcmlvbkhlYWx0aERp cmVjdFNlY3VyZU1lc3NhZ2luZ0NBLmNybDBFoEOgQYY/aHR0cDovL2NybDMuZGln aWNlcnQuY29tL09yaW9uSGVhbHRoRGlyZWN0U2VjdXJlTWVzc2FnaW5nQ0EuY3Js MIIBUgYDVR0gBIIBSTCCAUUwOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxo dHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAwGCmCGSAGG/WwEAQEwDAYKYIZI AYb9bAQBAjALBglghkgBhv1sBAIwDAYKYIZIAYb9bAQDAjAMBgpghkgBhv1sBAQC MA4GDGCGSAGG+VsDiiEAATAMBgorBgEEAYLBWwABMAwGCisGAQQBgsFbAQEwDAYK KwYBBAGCwVsBAjAMBgorBgEEAYLBWwEDMAwGCisGAQQBgsFbAQQwDAYKKwYBBAGC wVsCATAMBgorBgEEAYLBWwICMAwGCisGAQQBgsFbAgMwDAYKKwYBBAGCwVsCBDAM BgorBgEEAYLBWwMBMAwGCisGAQQBgsFbAwIwDAYKKwYBBAGCwVsDAzAMBgorBgEE AYLBWwMEMA0GCSqGSIb3DQEBCwUAA4IBAQANXpIq2tvvveTSeyFqxsGOwJLxxcXS nP3cJFlHcLj6Xzx2Vri2tXLdnPrDSn6OHz1TAm0q4Fy47LUCJjx7Us5hewck3z5S 1krALEY8QpFSBBMy/KUw0pfBSWullzYujbF+2cXV3rf/KI7xkJCJkpO2aQX0uXW6 xZazM+DItJGEhS0bS3DKC8bvjsV9pppz+frXVGMs/PHqj8E57gskkiIS521icQbi IVMkmaGnWNptfC2SgEDN9NS+/z4jcwS9l6kWGBEV6iOsGhokn8OroOaujaJdKagR /etkoDdEwd1StUBIHSCh2nqnUnACJqxWgmo866oLkfbG15wGN75SDkNa -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFmDCCA4CgAwIBAgIQVHq45lkYorm/2hSmjcWOsjANBgkqhkiG9w0BAQsFADA9 MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw0zMDEyMzEwMDAwMDBaMFEx CzAJBgNVBAYTAkNOMREwDwYDVQQIDAhTaGFuZ2hhaTERMA8GA1UECgwIVW5pVHJ1 c3QxHDAaBgNVBAMME1NIRUNBIEdsb2JhbCBHMyBTU0wwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDNNXHvq6LbIgVNrbtvR1nxRMdDwsNyqnFpyEJzJ5le rDU3oxldM+v3qOyUcvFNLTdAX8uW7lQCL7BMXpkXYhcaK3E2oEhOpmiDrdWH6N/A Akb5zyOEipHV61dJ806K1Hv0onR99Zat4aWxuyQplVDE8cECj8njUJiU3/1hHjxc pj9Rr+moHfHI/Wqt5lw+rFXZ78H8babQTvZYjFhqRi8Ilynt4+UFX6W2iknkkNot bt4+0A7nF//F9bBw0auLnIhUjv6y9yqtMymgc3umWju2ytrCuhiJ0cST85Jjj46i nVfmIm+quRVMpYJfRkKpulTpOxGmaD4jFH92Bm6d+JPRAgMBAAGjggF+MIIBejA9 BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cDovL3d3dy5zaGVj YS5jb20vcG9saWN5LzCBlgYIKwYBBQUHAQEEgYkwgYYwRwYIKwYBBQUHMAGGO2h0 dHA6Ly9vY3NwMy5zaGVjYS5jb20vdWNhZ2xvYmFsZzJyb290L3VjYWdsb2JhbGcy cm9vdC5vY3NwMDsGCCsGAQUFBzAChi9odHRwOi8vbGRhcDIuc2hlY2EuY29tL3Jv b3QvdWNhZ2xvYmFsZzJyb290LmRlcjAdBgNVHQ4EFgQUmCDw8dlCpt6DP5kQGQA9 aGjSAYEwHwYDVR0jBBgwFoAUgcSMzPXkMP+lDAhfjBVnIXQB398wPAYDVR0fBDUw MzAxoC+gLYYraHR0cDovL2xkYXAyLnNoZWNhLmNvbS9yb290L3VjYWdsb2JhbGcy LmNybDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG 9w0BAQsFAAOCAgEAvs4b2dHa0pfkuWpkTDvwwQbSPdeeR+ju0SajEmvaBeCEvKx6 8n3Tq0RSkbni1LUJfphDRDy3Hsv8H6GqJmQWO7ej6oGRy40Oy+EW5tuHZ7berh/6 NXCR3oOV/2gm+IWDHKrU8ROtBliz1rCuFidLOrNKe7hRUHxWlPjUT4WJED+pjkOg VSXHlyguxmy1MQULA0AqAJtiArbBd8TjGkvP250tksI1p4x0Ay9MB3FiKItGZjGH PkCqXojPKQmGSvObyxbDr/qr+6sWu+69DJbpkR22zNwV6PvgkIfG+iA9FaPjtdLl s2hpqJqmiw8S9JVgRg9n6Gj3q09juOIR08n/EzBqoh4WtWLEK9oaJ3fOzyht5GBq /5P0v8QRjq81RBqgfUJ/ASoZ/pd/952r9Nu+jY7Akh+iP6sjLnVdEr8W1OzjTNgU tKSkJfJcCVBGnqrGiO7bIrj9cnbsUBk2Ca+BpJLyZT/KFcJc/vJaO9I/KySzYNTV cREYDeac08wbR0u85HEMBfJQ/unGdcKq/dcqUsilHa2PTrbxNgDuL3N980m0teeV ZXGyLsTxNC4TEs2pecGVcqi5DtT6OFs+q7B1sPcSCzzCK4NxeNCI0mSre+5ApEHX rYsx1I2utRbDvSO9NlfVifY67u548epDDNnbkgo92kl2+h6sOiZU73CgZj4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGGjCCBAKgAwIBAgIQO2AJMwhEWunXUblxcXybuTANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTYwMzIz MDAwMDAwWhcNMjYwMzIzMjM1OTU5WjCBpDELMAkGA1UEBhMCVVMxDzANBgNVBAgT Bk9yZWdvbjEOMAwGA1UEBxMFU2FsZW0xHjAcBgNVBAoTFU9yZWdvbiBTdGF0ZSBU cmVhc3VyeTEmMCQGA1UECxMdT2ZmaWNlIG9mIHRoZSBTdGF0ZSBUcmVhc3VyZXIx LDAqBgNVBAMTI09yZWdvbiBTdGF0ZSBUcmVhc3VyeSBSU0EgQ2xpZW50IENBMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxmATDxWciBKT7gx0UoiDAsaJ 9NWwrLsILNTq7efm5U80jFFeESg+1B0zoOABH7uN1hSx43HyebQTHDxB0l/SkkV9 MGaAzZGHg40dWWXiAOLSoTwBQWp4l8juGPlZN2T0pt95sqc7AebAKh6B6K1E1Wep hx6pl8wBcgzCJYDsCrAPyB3wi4T3gOpWaigccb9K141b1g8M3zZh0kIyHzkwWcWW WMGYs9V1ZzM60dAPTxQPqfrv2SEvuBPIbkt1w7am+oag6OhbWu4V3cfTUW2MgZOk FJV1zP3mo64neDpM8mYbrtkM9oIWzixXKPprDHXEhQDSatYjnrV5OR8VaS1qzwID AQABo4IBYzCCAV8wHwYDVR0jBBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYD VR0OBBYEFDTjVWvMm2CYPrH/FzY8OHItJuJFMA4GA1UdDwEB/wQEAwIBhjASBgNV HRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAZ BgNVHSAEEjAQMA4GDCsGAQQBsjEBAgIXATBMBgNVHR8ERTBDMEGgP6A9hjtodHRw Oi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9y aXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQu Y29tb2RvY2EuY29tL0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzAB hhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAHOO x6054rJUBuixZD5TopNmdF22bf3/sTY6T+0rYUgKaP/vziOFrQcdYC3n//p2k3Aq AXRYIP8V9Bs4su638vs6WpxULLEtEcAv3S4ANOBslUypIYGylxSeLZJvoJ6D3KBi Cvnq4G/MzqpOaSOVynT9WZ2u3HSHGrqNkhx7NKTcAW792Qj0kuo607WwZdPRRnOS FpKwKGUnsggqTSG9pC0mnXzdB73qShXDuKlQ6UrTnkG7Gce9U4jUR1sypLC/wCda N1YFyts/ImETOZz/r96ag8g4SU7LuEmLMC7zcBfm6UwsWRbNvraVpDbPb0DHqoNC JYgobpnd2IDGjcs1f+ECR4Hecwr7jE1LoO528/3Tgu5fSYvd4mlb7vEPSPSr1j6Y O4pjwFyKV5Mr1qOqU2/yUot5tF/UlC+Sf3wxCUW8/hOCZRmMDS8mwmARy4AR3i7S flODxkZxiUK2gAQmTGXQlsfkPEtOCYYDEoF/hgfhCqoW9jX7IT3vB1OaE7Tz4j3V hcVjst9n7PGDUYGrG48JJns8ru+9ZFoDyb90LLY3IT3sUz56irrq85MsIXGPo3YV 3QBMTId8fOZyj7s1NKjQYFN2mAiVvO0DKmIN4U+2P39GAiRiwkga8P/QtFZ8YzDa MAT+mPb1K86NBM0KByjuzJOJDSK8ep5i93tnl2vO -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF+TCCA+GgAwIBAgIRALEh69i9ODvCDLdUvBhDX/swDQYJKoZIhvcNAQEMBQAw gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE2MDMy OTAwMDAwMFoXDTMxMDMyOTIzNTk1OVowgYAxCzAJBgNVBAYTAkdCMRswGQYDVQQI ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoT EUNPTU9ETyBDQSBMaW1pdGVkMSYwJAYDVQQDDB1VYmlxdWlUTFPihKIgRFYgUlNB IFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL23CxiN bAfZclMlGi9tHpl6dCSxT4yRM79i/h3u/HbErdS+3jiq9oPZfCqgbJ0PVIOBelGb EhvBBbkW/wPlDq3vEEt9nP/P3cRVGu+i0X/puXA51E5TgrEn5/jdorBANmhItrG4 uZietPJmFx6awA3ANC2MVnvmT1s5qS0cnrdFh2rLRwfANm4S0UbJNpHSItFinh0J XtQFyc/QE+fGAH1sC8aW34Rt+qQ1+msY7hvNpXKZLR8Fy5AVi089iv5cK8bqzVaQ F8kJTiukJ9vQ/e9CC7x9/TxX/oYn5bIejxsaoGPi1BgeRkS7J42MeNpYmh7kUFN6 ZZm5Yh8OB571L30CAwEAAaOCAWUwggFhMB8GA1UdIwQYMBaAFLuvfgI9+qbxPISO re44mOzZMjLUMB0GA1UdDgQWBBQ4EsZ5AmY4AuM3JOWLD/9FlWnmMTAOBgNVHQ8B Af8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgGBmeBDAECATBMBgNVHR8E RTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDZXJ0 aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOwYIKwYBBQUH MAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET1JTQUFkZFRydXN0Q0Eu Y3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI hvcNAQEMBQADggIBAC3C7NUxneoMxtAT5QcdKTxVO2TmjbQtmYaZ6b06ySZC+RZm GrktbzTwGh0jb33K/Wx9X1GXhsZIACgZM9bbeopskqlg/x5UDtHzaDWs+XtWMhET aRtQRyRJ6bxTU64DSjnHbgLedToXmA2H8BF+DrRwEGG0twg9EjhIOJbvJ8Jcsdzh b2hE4w48VwpQzH+Sg78TnGr6MimbnkFpuE+DO5q/x2AmeuOdmcl/3ufs3EjKeJTr ybyjutGfI+LM3UTw1FhVzeMUPJBrebiy8tTP2/Rn8sJRdK3J+lmfY+sgfkcpXjMO PA8esFM43Wawn2fLaQALi0Vpm36oc9ECIqjAunxQ/OmLl2uSvERNln/hmSlKvPEY vA7lUXzRAxbpR0K7n+GBOMvkT9n1JGscHR9Oy3QGVksCT5bVvuGhH9m6BM3lnskp 3eyOXy0PpT9eJVflrpA8HVcJXGNCFDBT3iWUtHXXfopJvBe6RcEyu7aLWPNJ0/wM n+EdLjUShlFqczNfw15eAdnTHkPCFW588pj7Hz0MaTeIqOBZWTHvc/BADJbRZuh7 jVXvr24Pv15WVEt/GKqm+VkvusRTVMVQm9fDH8rBIxBmpzt0uBTcg8IWY8HtGfEt 5R+qkfsm6EWtj4APtivR5qC2mzEDxbZSlduxifzG194rAGGbcn2KeOA0QwNE -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvzCCA6egAwIBAgIIdjnjgJxiHiYwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE2 MDMzMTAzMjQyNFoXDTMwMTIzMDE2MDAwMFowbjELMAkGA1UEBhMCQ04xOTA3BgNV BAoMMEdsb2JhbCBEaWdpdGFsIEN5YmVyc2VjdXJpdHkgQXV0aG9yaXR5IENvLiwg THRkLjEkMCIGA1UEAwwbR0RDQSBUcnVzdEFVVEggUjQgRFYgU1NMIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArVOKUxZ0oo2zfYVU8orGMMOdENvt 1HLjdCYMmSyhNIwFHrER/R84+028lbE9rOlOm2Dur91sqJwOYXajnH5Tmuay6E6I iED2M4W6tDp4/8dAVPoeTjf314wMpi+dLseyvstGDbRhJDCRDsDNCi9SHjtit1XO qk8imiLJEvbF4QG6PAb3S3eCWTSKFo5zsJGJZsOVns3whqbkJsxzbfqTWPqL/J7s PPs+LN+t4U5UwztItH6YFay3LtMXefTuysCB89H4xkCPo90EyhAzHfx6nQ7mTbOo Crw+FsRmiFrcRL72ysADQm1KMB87r2lZ8aOhdN1SuDGGBfsA8iMVWg0R9QIDAQAB o4IBazCCAWcwewYIKwYBBQUHAQEEbzBtMEIGCCsGAQUFBzAChjZodHRwOi8vd3d3 LmdkY2EuY29tLmNuL2NlcnQvR0RDQV9UcnVzdEFVVEhfUjVfUk9PVC5kZXIwJwYI KwYBBQUHMAGGG2h0dHA6Ly9vY3NwNi5nZGNhLmNvbS5jbi9kdjAdBgNVHQ4EFgQU cxPOg8YMKqAmkq4/e0B0tTALNZUwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAW gBTiyUCfTc7omqF8zw4/ZcUpiGoZUTA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggr BgEFBQcCARYeaHR0cDovL3d3dy5nZGNhLmNvbS5jbi9jcHMvY3BzMEYGA1UdHwQ/ MD0wO6A5oDeGNWh0dHA6Ly9jcmwuZ2RjYS5jb20uY24vY3JsL0dEQ0FfVHJ1c3RB VVRIX1I1X1JPT1QuY3JsMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC AgEAPupT0bWAb8gV8z6meQ8WFnuxlPnlgqSIUN2Fa+/acx1bmxZ93iJDfQ/lmB5Z Q1VtNVkmRXMktBagpCenbFxb8+Dt1ZXDt57lUBZdjX32EYkA5rw2oeUIAKJqxqI2 sWEwS0fQsB6Yqyzdz8gF/PmuXWf77d5YtRb0U9lt5XRFHkf4mi606uHJtiJ0w9R5 zwXURLibLMDAlnWdWHvVKppWECD2HJ0kpwqVGGdhSCQiAGgJ6VfTBiXsQgtVA4KR eMSElRy0n7M2LYZ8uG/Tf2l76FkavjmPzODV9Hb9TPbMBa9mnKcVt478+/76goNL nh/VeUWWn9FXF8moCGsKq1u52cjk5KD1sj1yCiCcE+qpepXGdCLk2cgvdFABQOE2 TzXjjruOrMhMUQlA/s23BXhWhyC9o3jnelVTzpVSxwt9htvwN1MR6ZUBJ/EPuRsG 2drpTEwsQ0NgODGnfvcVCUqSihXiJzl//B5jLa5YoonLNAExu/oqQ3WbHFxuT/g7 CCmCq3PAF/wFAjKQI5RWALuG9xxAgp1BoP+Z/DKNNfKoxT1iqN8nY0ofE5b0FlTM IqO6IeXLWkjsaeA0wA8+PnpO9k0GsxJWtZ5fjz0UJ1TyeBE8cKmA0CWrymbyjb1z s4LazxgYMJ/i3djAEC9cfS/OvOWvvqKGv4czH00Pr93BOVA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvzCCA6egAwIBAgIIKDRS9HM/JqYwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE2 MDMzMTA3MTUwM1oXDTMwMTIzMDE2MDAwMFowbjELMAkGA1UEBhMCQ04xOTA3BgNV BAoMMEdsb2JhbCBEaWdpdGFsIEN5YmVyc2VjdXJpdHkgQXV0aG9yaXR5IENvLiwg THRkLjEkMCIGA1UEAwwbR0RDQSBUcnVzdEFVVEggUjQgSVYgU1NMIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwO0vwYGFXVZaBmTU5NinuGMY+myY ERMw4jjZAp7vMwxme1e51tC6Bw2+kSeNOiGy7/UTEKOb0Ynw1SoP6KkiFCrqejlx M687HFbiZlCFj3aSxBJ5H6ibpB4CnQm/rnOFK7bF1y/cRMA1xSwxZZRV3wO3iqOt B+6DvftUCxshIrULp2tP+F2aGvGemBH5R8lK4LuOYPRfPcRZKVDccyUhSnDvGtK9 UIRFCaVuhOcUluLAiWH5KhtOfSMHj961KP/1J1P23UGHypCbvpsBb4ZR1BkRBWwC j8JmWRfCePde+6b3MX3JpQIlYCONf3OdWnx+PGiZOJXHlJ7T3oo3NKCZeQIDAQAB o4IBazCCAWcwewYIKwYBBQUHAQEEbzBtMEIGCCsGAQUFBzAChjZodHRwOi8vd3d3 LmdkY2EuY29tLmNuL2NlcnQvR0RDQV9UcnVzdEFVVEhfUjVfUk9PVC5kZXIwJwYI KwYBBQUHMAGGG2h0dHA6Ly9vY3NwNS5nZGNhLmNvbS5jbi9pdjAdBgNVHQ4EFgQU VQOujgc1qBdj28nWHj5jnd3GF9AwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAW gBTiyUCfTc7omqF8zw4/ZcUpiGoZUTA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggr BgEFBQcCARYeaHR0cDovL3d3dy5nZGNhLmNvbS5jbi9jcHMvY3BzMEYGA1UdHwQ/ MD0wO6A5oDeGNWh0dHA6Ly9jcmwuZ2RjYS5jb20uY24vY3JsL0dEQ0FfVHJ1c3RB VVRIX1I1X1JPT1QuY3JsMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC AgEAhUXqHJC9kuRt5zwUB9AE/5GBI0MmHrNAmseRMv754c4hiDPABuZf0gl5GYsA v0T7T3+TlHmdbUoUCMOiWOxQrxk+8qeOJwg8WV9rUhWlYY/i7GFRWK+6S+EsFARG f31zqTInM1GbjvdcBz3mgqNe8QslfCjiD9XmZwoHNwSVZ+olb6ywT9JQBA2AS1rN tHN/gfNZHdwO0Qbg/YQGMaa2HnvGImfHeVxlZEMe2MSC2lvJOsf6RejeKtzm0lE8 lPysb/ftitc/vI8kOfAm7xiZ7ay2lT02lSPuZhZMOy/BtFidm4SToshPhhEFNFZH +Rv1rhwgVT7/wkx7LwEp1gH0r7aMS/KQIMbFhJYDTAf14pFixtxwF7HO6Tk4fD/f uPEnwvwyHysZjxpkSsDsxSTd5NzhAS296Iq/dhzXRBXxhag8OFKW4ajdFqIPkDPh ZO5QECj1CUYHVy8QyJw8Z2O1pMxqhJpXcjt9LgnDUMe5q8IK6TkX4qVaM4C5aFAN 60e9x/+ujZ5uDyTi3XuZK/lHjlTQf+6gI/z86VLEBA2orlOKxNOS93BBlnuR7MoM kgZdB6OUJbIKh/VwSQg/+lhu4iSy2YLjS6LopT+rvxPXe3AJYSnbDH9PWfX6q7PG A09nXiC4C/ez9dSbMStwGVlGEUm77bR7C+EYS9NiVFQCIm8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwTCCA6mgAwIBAgIIeqchX4m3GQIwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE2 MDMzMTA3MTkyMloXDTMwMTIzMDE2MDAwMFowbjELMAkGA1UEBhMCQ04xOTA3BgNV BAoMMEdsb2JhbCBEaWdpdGFsIEN5YmVyc2VjdXJpdHkgQXV0aG9yaXR5IENvLiwg THRkLjEkMCIGA1UEAwwbR0RDQSBUcnVzdEFVVEggUjQgUHJpbWVyIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8TIlk/hFDTpazhQb0t4o5m9tILf0 93S1NJ4ckyU70dbwIqM8BtezbcAMWo06puZS8fovheBbw6efUS6IHL2+dODs/SA7 qjLMfrrBhuJNU+tiYTOGnIZ+mI5kru5owjgxOz+7HqTe9lbsJfKWnvoeSKjumCzj AMQde+pv0J4URj/lMBixgZr5z5nxubDSzLwjJSYXAkFnrNmnGSj2ABIbaATBsMvu eyqL48KiM+Upa7eW6deKpv23FucskW/Y7i07+nAOoN0z2pY4qj114Bn1Zc16EsYu nudSTp9fII41a9SAn4ZKaviCFbvmUDuXTIaYNwDymhzwrKDAx+jqKQR3AwIDAQAB o4IBbTCCAWkwfQYIKwYBBQUHAQEEcTBvMEIGCCsGAQUFBzAChjZodHRwOi8vd3d3 LmdkY2EuY29tLmNuL2NlcnQvR0RDQV9UcnVzdEFVVEhfUjVfUk9PVC5kZXIwKQYI KwYBBQUHMAGGHWh0dHA6Ly9vY3NwMi5nZGNhLmNvbS5jbi9vY3NwMB0GA1UdDgQW BBQRZJKuoEFiHCCEt9OIgdHNgHLHfzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQY MBaAFOLJQJ9NzuiaoXzPDj9lxSmIahlRMD8GA1UdIAQ4MDYwNAYEVR0gADAsMCoG CCsGAQUFBwIBFh5odHRwOi8vd3d3LmdkY2EuY29tLmNuL2Nwcy9jcHMwRgYDVR0f BD8wPTA7oDmgN4Y1aHR0cDovL2NybC5nZGNhLmNvbS5jbi9jcmwvR0RDQV9UcnVz dEFVVEhfUjVfUk9PVC5jcmwwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUA A4ICAQCPLqmgzsr8t/yqXKsQocpswQ15OovqF4HpSVkGbC6ds/lJx5IonuGhJ8ux WR+S1lDF+dMHuI6Z1N0pn1EgAVIyhabzeO7k9bW2cuV7dp5JwQhUqYJcrIwryTFf itWO/8a7AxyRvn09RklsETfDn4zPl9tUkpV6H27qy5CpLfMzpFdkrWuhabeX4ZZS +SMh0iXr+6z9BERKZAHIPRvEc7KxmeNZdv7l0cPk/JxWd9YsAEzXHTtftIndwYIE odIvm8owS9hugFtr6dZaxddNHYP+zNHUFvRX7GvlbJCkVCpdUkQ7eYQ0K0PwnhCw fJhWvPbu26S92OSERV3sJqbp9TyBKi+LlxawbQDyGYHjSaYCLX9IYIOyZDk4EqR/ 5SMwRSHYRA+MjDzzsGGXcW01XwrtYWYpLWJJ2VJM5Q2kRses+G+wCikfCyif/C8P caQQqfhHMg//UJitNKiGrAXlbnpv9MLCpuC0ES43LYxTDM0Yq2tVIdjE8XvWz83A 6wJEayhUrZrK0a44zmZfnzIsIo7WEDz0sZfYt7ClBJ3B95whxRJQUjKHlfyYtod6 T6Bn/SVdO4n/6KI3VtPjh0Og6cW3QUl3V62ljp77hQJ+rS+VYfsO2yc3qcvThOWD Hui5dpmRvkJRtlsrkG4sO0H6tPuZvAhUUpp3DGXqE58fXosRLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvzCCA6egAwIBAgIIOcB3/B7WFeMwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE2 MDQwNTA5MzYyMFoXDTMwMTIzMDE2MDAwMFowbjELMAkGA1UEBhMCQ04xOTA3BgNV BAoMMEdsb2JhbCBEaWdpdGFsIEN5YmVyc2VjdXJpdHkgQXV0aG9yaXR5IENvLiwg THRkLjEkMCIGA1UEAwwbR0RDQSBUcnVzdEFVVEggUjQgT1YgU1NMIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4oj/ZBFHvmpctMkt2LwzkFWXnuLR 9V0cpHWRWzEuU1DmflB5udFcEGJW6mTCfyfrFP6C4pvNp3XZSO3hB7gGlA6Si0IZ F/k3uNqmy8d0jMp4+4Num4jN7Xl+RvOn91cATzWUbrhcorgPf0qJ1Njt4OWDGT3H uaxH05w8cq0ObEDcHEYTjPfRj0MkHzCj/pAR4J8gp4eUG925Fl0rNr4+0FS58Nce LSFHeBzdlF6pECuQEX53OP/83q9eHpyf7oFd//GLcwhsGdttVYob1pbJS3EQFI+A 8Zri4uVPdBTSEYc7yX+tIiqNC4TW/9xs22T0rtl0srh/AvYhzMgynOkGKwIDAQAB o4IBazCCAWcwewYIKwYBBQUHAQEEbzBtMEIGCCsGAQUFBzAChjZodHRwOi8vd3d3 LmdkY2EuY29tLmNuL2NlcnQvR0RDQV9UcnVzdEFVVEhfUjVfUk9PVC5kZXIwJwYI KwYBBQUHMAGGG2h0dHA6Ly9vY3NwNC5nZGNhLmNvbS5jbi9vdjAdBgNVHQ4EFgQU wPZ6W758CMatBLtIYUWw9WJXoLMwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAW gBTiyUCfTc7omqF8zw4/ZcUpiGoZUTA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggr BgEFBQcCARYeaHR0cDovL3d3dy5nZGNhLmNvbS5jbi9jcHMvY3BzMEYGA1UdHwQ/ MD0wO6A5oDeGNWh0dHA6Ly9jcmwuZ2RjYS5jb20uY24vY3JsL0dEQ0FfVHJ1c3RB VVRIX1I1X1JPT1QuY3JsMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC AgEAhWNOGhhEtGDEd2mjNC9qqPG8Nce/iOUTVHHpXJq2jiw7D0QON8FKvRv38Ey+ nNFGAN19EYwJ9TP6G0RDTVEFwmAp1SvAZw2Z4gnub7jVdeQo4UORt1s/dRP448XB ujDbP3QLIAqkegBrEwDvnyTjY15yjUG9sx3WAxfnWihhf0IaNVRmQxYXVs0YR8jw Nx8iJcghFjpZ0Dc1aFpDx8cyVqyYMme8jHWK9w5WAhv/4Kh9x/XFgAu//iKy71Aq 8J/a3u/Jzgj/Yod3KPRciGTs1/bJhlta/1gc8aCeIWwN2iC5QD94cveuqVDLmnde Ja6fUSsZzJzM3Cpx7Dbq2R4+zsvwAr2u+GRu+XfZQOp4Vuu0plIVr3c2+S2PvaZ4 cn3+2K5HLwnws9rEjxeN/SIYDkzib1bslevTYzNjTTULjnKpqQ1ekkOLzbdJE6Cw x9Az3u+OzU20Z5ArvlRTUhr3IMBfue8LvdKaXIG2vXRrBxDu5mkdN3Aryd3tn1En Ih5Mts7MN9CIqOlkQ2HONHzuXv0uo+9mCFTcHCOdhWM+jD1ACUsI0XtqzLpDIVQT Eimin1irVeb2KKVD09n7zUIwY/RU7rEY/++LD4mBCCPSuogFigazw8XMLh49/9He cdFjQi2D4YvF1P/s6h4W7EPX/2Cje62fPlMtJQ0fzyq2dNw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCA22gAwIBAgIRALYBkT2FU7r6AAAAAFHUwfYwCgYIKoZIzj0EAwMwgb8x CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9T ZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAx MiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNV BAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTAe Fw0xNjA0MDUyMDE3MjlaFw0zNzEwMDUyMDQ3MjlaMIG6MQswCQYDVQQGEwJVUzEW MBQGA1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2VlIHd3dy5lbnRydXN0 Lm5ldC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMTYgRW50cnVzdCwgSW5j LiAtIGZvciBhdXRob3JpemVkIHVzZSBvbmx5MS4wLAYDVQQDEyVFbnRydXN0IENl cnRpZmljYXRpb24gQXV0aG9yaXR5IC0gTDFGMHYwEAYHKoZIzj0CAQYFK4EEACID YgAERH30xyio+YKd0SQEqsKhKlWeAkNYBUGrBS2kSJ8xh9aeiNANaAmPRCcBzvpi szqLh63Bt6WleEb7bJztcykgabYQxFavAPggWgeGzVxq2f07t5daKVoV6dZnHqag 1+eCo4IBLjCCASowDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw MwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0 Lm5ldDAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1c3QubmV0L2Vj MXJvb3QuY3JsMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpodHRw Oi8vd3d3LmVudHJ1c3QubmV0L3JwYTAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB BQUHAwIwHQYDVR0OBBYEFC5i8BTuh82zNQM97+S5nv07uKPJMB8GA1UdIwQYMBaA FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMFIliTW5jfYd +emGKAyib9/O/zMtzg4PPBwu5IzN9qY/P+8TfxlCkFq+Dn/+1JcoQgIwGSCyqHM9 X8q5V9bLbhjZg5GoAFPgdhvIlxCaq4IqV6MkxjfTKD5sKsRqHtgwYFzr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5zCCA2ygAwIBAgIQCoPUgD5+n1EAAAAAUdTB9zAKBggqhkjOPQQDAzCBvzEL MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1Nl ZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEy IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UE AxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4X DTE2MDQwNTIwMTk1NFoXDTM3MTAwNTIwNDk1NFowgboxCzAJBgNVBAYTAlVTMRYw FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNiBFbnRydXN0LCBJbmMu IC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxLjAsBgNVBAMTJUVudHJ1c3QgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkgLSBMMUowdjAQBgcqhkjOPQIBBgUrgQQAIgNi AAT14eFXmpQX/dEf7NAxrMH13n0btz1KKvH2S1rROGPAKex2CY8yxznbffK/MbCk F7ByYXGs1+8kL5xmTysU/c+YmjOZx2mMSAk2DPw30fijJ3tRrwChZ+TBpgtB6+A5 MsCjggEuMIIBKjAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAz BggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3Qu bmV0MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW50cnVzdC5uZXQvZWMx cm9vdC5jcmwwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6 Ly93d3cuZW50cnVzdC5uZXQvcnBhMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjAdBgNVHQ4EFgQUw/lFA77I+Qs8RTXz63Ls5+jrlJswHwYDVR0jBBgwFoAU t2PnGt2N6QimVYOk4GpQQWURQkkwCgYIKoZIzj0EAwMDaQAwZgIxAPnVAOqxKDd7 v37EBmpPqWCCWBFPKW6HpRx3GUWc9caeQIw8rO2HXYgf92pb/TsJYAIxAJhI0MpR z5L42xF1R9UIPfQxCMwgsnWBqIqcfMrMO+2DxQy6GIP3cFFj9gRyxguKWw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwjCCA6qgAwIBAgIIApIzJGvGMUswDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE2 MDQwNjAzMzUwOVoXDTMwMTIzMDE2MDAwMFowbjELMAkGA1UEBhMCQ04xOTA3BgNV BAoMMEdsb2JhbCBEaWdpdGFsIEN5YmVyc2VjdXJpdHkgQXV0aG9yaXR5IENvLiwg THRkLjEkMCIGA1UEAwwbR0RDQSBUcnVzdEFVVEggUjQgRVYgU1NMIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxwDUfCaCvZuIpnRrjpuR5fI6u4Ci tBnHvv0Jj1iruRQPBbic92JNcrWT/GQgkm7ADrHMk6asK4zOvXknXsu+LA4hbqsM FJI4qNHpWg9LaSRUcuKAPufqaklTbYS+OjqA/80LmZphyFs6ygdMDTli3nyoD2qw ykOr19L8DNgoBVZcGZZeHjGUE5eYZSmNi/c1cC0TOdJxq6T2aCI3MwzK7T2IOrwb tzWrmgV3lq5EqdsCTUHG+CR2hKODzDZDbB6bRxtsaB9TxAYDL/6j/CimIa+Zwv6n tvtuBhRrEj0fWat+EHlJw0r5wQUHySRbsr/Q+lcF3iVEcdZMuQRn2J4LgQIDAQAB o4IBbjCCAWowewYIKwYBBQUHAQEEbzBtMEIGCCsGAQUFBzAChjZodHRwOi8vd3d3 LmdkY2EuY29tLmNuL2NlcnQvR0RDQV9UcnVzdEFVVEhfUjVfUk9PVC5kZXIwJwYI KwYBBQUHMAGGG2h0dHA6Ly9vY3NwMy5nZGNhLmNvbS5jbi9ldjAdBgNVHQ4EFgQU Hmrq3vUvv6jTbMfGP9tsZGDc40EwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAW gBTiyUCfTc7omqF8zw4/ZcUpiGoZUTBCBgNVHSAEOzA5MDcGBFUdIAAwLzAtBggr BgEFBQcCARYhaHR0cDovL3d3dy5nZGNhLmNvbS5jbi9jcHMvZXYtY3BzMEYGA1Ud HwQ/MD0wO6A5oDeGNWh0dHA6Ly9jcmwuZ2RjYS5jb20uY24vY3JsL0dEQ0FfVHJ1 c3RBVVRIX1I1X1JPT1QuY3JsMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEArUQN5juKmBKonTeSMNnDDEnbgUb5c8UMEdpBgL4rn1vDCYXbReZQdEI3 CyBChDpDfggWwG8Za/kAEThnsTEDxBMbWVuDYmJW5OWOVpBHsGboYiQ6veKD53MQ Vm/UTWwUOficJUDZmsn7khKxqC6jrlygapvqwbxpeXXcxMmytcafcWDqVuyb28dQ vk0U5JxDBTiMlGxSkzqpUuk49hh90mTE5o2+fS/paqqYOhCSu2Yn+ewekJJbJpMz KpIgje3EePUcnoYzUjzEZgujYpSfXy44Mx9JlMvWVTR1cFbofPoQfiRX4kb4R2HC JAsR5k6XZsAGLR13h9ttpwHRZUficCj0aE52CNJU08WJXpmWLVVLXJ7b7RgbEGsz 00z8d5Szivnypj1IraNMM4XTpArhflyku2h/1ku06u8FPn137xuHDfboFH2aU+og 0cj5LsiHoDDyeAa9+fz6ycv4/cbMQvM9IXv2xJKwkf0mzW488gSCIQXLSgAF+t/B 0eP+KxZsoXQfwqlkw0zql6YBduX+vmMXfWzMVHQYmSY6QdLWObpd9zXyzug6mbc1 3p6vw+MB5rzDkZV3R2Uy03OBuM5UK7uRtgCVxMvn9GDcDDbv4LJRdmawHiZAoyVL 0BI7sFfapY4G2MiqHBnJAghuSnyV1u/hNUznRgXLfAhEiNRC8lI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzDCCA7SgAwIBAgIIY1SwpvX/WSowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE2 MDQwNzA5MzI1MVoXDTMwMTIzMDE2MDAwMFowdjELMAkGA1UEBhMCQ04xOTA3BgNV BAoMMEdsb2JhbCBEaWdpdGFsIEN5YmVyc2VjdXJpdHkgQXV0aG9yaXR5IENvLiwg THRkLjEsMCoGA1UEAwwjR0RDQSBUcnVzdEFVVEggUjQgRVYgQ29kZVNpZ25pbmcg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNlDGrHYlrgCx6hRTn Gnza9iuTyeZ+mFVN1ss0EoZIKaPmirejLnNPlOi6GMtchiTRxo3DbeC6AcDyfaEL ULO+Z/OSpfzYiT2LwxI+HjCoC4y9Q/Lq3mvi4ZioCVsx0h4+K+qPv5HlrCrBSTaq pHiCcoB30Qwdvl64bECM7cnwCi8uEZfS86DI/FgFURfe6RxYDtxcWuVqyZ3usXsA YmU3OqvkjiQDqFA9sLxkWQWqf0BiPrELFFacF5Cg2XAMidpon2cIEXQMrqr5JnVz Xe5M+fOYru9L6t5drS02ktPSW6TwvLX02vgeBbXrNUAsTSPDs/JXTMRZNF6StVQg KDCZAgMBAAGjggFwMIIBbDB9BggrBgEFBQcBAQRxMG8wQgYIKwYBBQUHMAKGNmh0 dHA6Ly93d3cuZ2RjYS5jb20uY24vY2VydC9HRENBX1RydXN0QVVUSF9SNV9ST09U LmRlcjApBggrBgEFBQcwAYYdaHR0cDovL29jc3AyLmdkY2EuY29tLmNuL29jc3Aw HQYDVR0OBBYEFGhiI9Op38Ui0VVlTWR2JYmqttB0MA8GA1UdEwEB/wQFMAMBAf8w HwYDVR0jBBgwFoAU4slAn03O6JqhfM8OP2XFKYhqGVEwQgYDVR0gBDswOTA3BgRV HSAAMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cuZ2RjYS5jb20uY24vY3BzL2V2 LWNwczBGBgNVHR8EPzA9MDugOaA3hjVodHRwOi8vY3JsLmdkY2EuY29tLmNuL2Ny bC9HRENBX1RydXN0QVVUSF9SNV9ST09ULmNybDAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQELBQADggIBABd5x6mQ1k7xhTfpaGAwIqomgeDrh/5S4eoGfz9Y/oa1 EmYump3bs2b4neJoLiYATq3n5WlyffJq/Z1XmpaD6Negm+Q6J3N7iRugDeP8qKlv fQornkpsi3Z7RKG/JqevHULaEmHb2NX0juK9mMvqiO2/pJu3znTGK6LSxO+FsN+v 6OG1juPlrJdPQ/oAMhxqNjmo25Y5DZs7Co2YLMktUUrt6bwr5HCnIWjEEFdB0QG0 +PN1FaBvTJZGQMJefg3ksVhYrzZDY0Lk76KtQPfZv79Ph5gr0Fr/RpVhcbGsyKuS LY2gVCMuYq1eZdX13uGT8LeoO95FmkUSa4L9M0SNUcUe5E6IGQz8jk4+jotMgRak bM42+DBhwTe0z5OnWiksXT90t41kniiV3iHD1ccg9AV9oufbTyzMOvVWYcszWoz8 tJy3VCWw4daiIrXyRUIN/Bbj98AF/5z/CpnLpGhC3nhv8G/UUGFjmNsKy86SyBNy 8mI/B63mOtQUHt3foQAccbGWrLo7Q5hIVftxxkmi5reHw3O+K4wReWxhWmm1ZE7R sEz2wBVpVcZwUJ9BXZGdYOxzFRtiN1Xk2jVl/nFogrxv13aCBLi8T+B8Ec5am5jH 05RH4ajd1dzNHaJ1QzGQggPREnNFotHnvLuZihItqnfzmyBW+jutdk6+yZ4F3r16 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFxjCCA66gAwIBAgIIF7Ot0kCjuSAwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE2 MDQwNzA5NTAwNVoXDTMwMTIzMDE2MDAwMFowczELMAkGA1UEBhMCQ04xOTA3BgNV BAoMMEdsb2JhbCBEaWdpdGFsIEN5YmVyc2VjdXJpdHkgQXV0aG9yaXR5IENvLiwg THRkLjEpMCcGA1UEAwwgR0RDQSBUcnVzdEFVVEggUjQgQ29kZVNpZ25pbmcgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqAeFuWy6yAbXcUxspMJv9 YlYGp0sC5nsigR1UeHPi9tYt7wMdXNnPRBXXaKQUBdmlGkmKOSva4nuEUR0Wxf30 ehavxoQ2+8On/AmfwGHEgVFMQJ4PK4ljrsmUCaRDM7fdoq4N82BpeR8wGVVjO8jp NB1Rax3PNGo+drW7zEAx69DEKZ2xxo6PUz3HddjctORdxm+fL2AqLQbYQ8cKrO0m DgpUtt8iJHCWB1JgDwQE0qVrWJVtcWKK08+4nKzWUDpLaeMLAw96O2HFxgGAu4Ow bMDiBWW1k9nh+HlkEN4BPjVpt8xA9rk+DuPmF/kzZuwE45uMp/fNp9WU9AxXF4Rz AgMBAAGjggFtMIIBaTB9BggrBgEFBQcBAQRxMG8wQgYIKwYBBQUHMAKGNmh0dHA6 Ly93d3cuZ2RjYS5jb20uY24vY2VydC9HRENBX1RydXN0QVVUSF9SNV9ST09ULmRl cjApBggrBgEFBQcwAYYdaHR0cDovL29jc3AyLmdkY2EuY29tLmNuL29jc3AwHQYD VR0OBBYEFEn9nhotc5Y2cn1dHrbigSNpz2jkMA8GA1UdEwEB/wQFMAMBAf8wHwYD VR0jBBgwFoAU4slAn03O6JqhfM8OP2XFKYhqGVEwPwYDVR0gBDgwNjA0BgRVHSAA MCwwKgYIKwYBBQUHAgEWHmh0dHA6Ly93d3cuZ2RjYS5jb20uY24vY3BzL2NwczBG BgNVHR8EPzA9MDugOaA3hjVodHRwOi8vY3JsLmdkY2EuY29tLmNuL2NybC9HRENB X1RydXN0QVVUSF9SNV9ST09ULmNybDAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcN AQELBQADggIBAAbHQTdTEqWeRI3Iy0Nu8i1/+9Vu0UvKBvAP5oSyxScaR4IsE9JV xAQTc9/pEIHHkNDOAaRDu4Obyq+bpvDp9c7mVV51oLKHWQ94UP587Wuwk2aIvnfH n9ZbnsLHdSyir6PZYuJEo/t/1Z8MbMnNaSy7gOq9wfrX+PC143kGtRFs6Dyw8TIt 2HS1uYmuGBY73bATyjjPK5FY+1l041ZJmbTHQaDI3ezXvtwA4t4Dpb0e8O1WmeZu RnUyQVEDh1V13kKgjp3T3GcFJHuV2LhWxy9ac4NCJwqSpNeoVHOHQO1Y9wcfFfyO CKH9uKKqRPqivDdI+M7sZTM8wo6FlvHnLqU01dVAvizZ9Qxoc7mshJNCblA28DDk qofeYJfXrwKO2mz01P/7VkrhOZCUL+N+AGcZ2vFlHes067jkOk5VcKKF7XOU8+9N v2MCjSEbYgNkjuVWeeUArSWIGOpkIpuIHudYo1lJkpmYWlMqHaQD95WQ3E0KxFLR hYY9u4KyGCRvOU2hQbNcdBhF1VedmCjl9VazmHbuENO1AhE3wHVQqrnbtAWU4Q2b c++ZVXKvM+bMuD7gLGOxNKr02s3S4T5rVvlgG6W1Dl6L6IF9rCcGkVlwM9efy3AC 5/tpog/BL9IBrYdRyvshGkjlq8DT3gZrIbD7+AfY0n/1OTrDsVtsqdt3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwjCCA6qgAwIBAgIIKDVqnHC0VXgwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE2 MDQwNzA5NTg0NFoXDTMwMTIzMDE2MDAwMFowbzELMAkGA1UEBhMCQ04xOTA3BgNV BAoMMEdsb2JhbCBEaWdpdGFsIEN5YmVyc2VjdXJpdHkgQXV0aG9yaXR5IENvLiwg THRkLjElMCMGA1UEAwwcR0RDQSBUcnVzdEFVVEggUjQgR2VuZXJpYyBDQTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALY7vbjZoi1PTJf5velwTyEPcDFW qGWpDgtvGGei0LZ+/h5RsOJZSgchG4aiIwEv47ze65VGK4fSjBHbrG8o0KGowghS Nd1R7auxvQyleT4K760mGb9ru6PqpmzXmCJJybfq4+8J3j8wpe6utUDSnU+Kmx33 umxjJIgzs6grvHOrgZLejk+AGEX41bmNSowCR8pG3nTGObnXnCUV1X5fNzyBG/z/ imcxXmnD8VK5FTpPgQd17TnjNkoTfbXVs6PshSQJC6oD4nlRATXdxR4vHj6RILOk qujS18FCSKxfggMUy8bHTmVEz61uYVNeoz8M6xWlZsTcDqAo46lPd5c4OXcCAwEA AaOCAW0wggFpMH0GCCsGAQUFBwEBBHEwbzBCBggrBgEFBQcwAoY2aHR0cDovL3d3 dy5nZGNhLmNvbS5jbi9jZXJ0L0dEQ0FfVHJ1c3RBVVRIX1I1X1JPT1QuZGVyMCkG CCsGAQUFBzABhh1odHRwOi8vb2NzcDIuZ2RjYS5jb20uY24vb2NzcDAdBgNVHQ4E FgQU0/7uYYDAmZBZbdYkVfL/wOsnF+wwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME GDAWgBTiyUCfTc7omqF8zw4/ZcUpiGoZUTA/BgNVHSAEODA2MDQGBFUdIAAwLDAq BggrBgEFBQcCARYeaHR0cDovL3d3dy5nZGNhLmNvbS5jbi9jcHMvY3BzMEYGA1Ud HwQ/MD0wO6A5oDeGNWh0dHA6Ly9jcmwuZ2RjYS5jb20uY24vY3JsL0dEQ0FfVHJ1 c3RBVVRIX1I1X1JPT1QuY3JsMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAmAoh0jabJLR7Bh/mVv4H7Vf3ypdeFbovRLtY291zRHc+oG4dBc/7kSie OvJJs3EKRw9KQB6+W3pShshm/Tl1HjcWaLHEnewCakTujTJwQ9OwgtRMokBec/TH Kp576T3NMIg0OgrCC98mhGWxbhLz8IU06978hZ1JOIBOdqTACMDvCDOdRvaHuFBv fJ6rTIQwYhSZdZ1Bmo4x3WOHiiogwiOlkqMjiyLE3Bloj47Xefl1hmJazoI9sa5h kCvimshfZOo/Zkxipr7p1KUFliLsOMsWBU+YCvZtdDnFaPkPvj+OnUBAs5wESHM+ m0LiDUuRXZhqoQax21zpQcEN0cPQJbLZp9wak21puxVdiu1OpW6Y/w8sZhtPdu3u Q5BiY4wzBRCwR07qN+L79zhI3Gh3Ev38vRLqa15WAnumrZJQWY947yTA+47Zj8bO DHLIWDe9sJ86li1V4m4P5nn4u5CRKcuQ2jscCiGssYh91yFt/E7VZbXNnfjIGKiH rAmTvEKaBfzNqPGrJQDITiADpuIAG6gXav9deW1WiKCbAgXt04K16l8r1958m1NS t74qZBMkSnRSKgU6MG3woZCWGbQVuzDSuNiFsEDK+HoC4305X/OT73rtoa2akopJ j0mpUKPklUF03P5UBtDZbdSY6+w8V0ER921AeC0LPrjiKl+OhJo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFxDCCBKygAwIBAgIGSUEs5AA8MA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTYwNDE0MTQwNzU5WhcNMjgxMTE3MTQwNzU5WjBS MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5FVExP Q0sgTHRkLjEZMBcGA1UEAwwQTkVUTE9DSyBUcnVzdCBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBANbJDh2dpmc3KZryFQ5r+2vpd1OdMarHD5VOOL/t aCpus9rkiE+fxLMfl/hXfTwMNwPig3q2af01eimKDCmnLCSBtGDjywPcq5FpHkm8 1tTGyCi8FxW96q3cObiN2fFfSgxGvRUXzo7Tivunx/N9ve3OsT31MKlRDrc/BSDX alRYuHOewlWsYD7XFrrkxBN7gAXhl3UNBZi4vOFglZG3Q1zQ+xMZfomXu9OA8uuE 1l5NdgUTFIXyKFkey/5BiNnfR2OkjdTo5+9cBehSmz+d2XUHXaf8w7ZC0uH5HICa cgoqV3L7UBvSyC43R/P7QnI1V1G2G/Lr5bJK1SR3rUiHTzkCAwC2R6OCAkgwggJE MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFMz6 Z5PwtrjQpcAe81P9jFPfg9eWMB0GA1UdDgQWBBRTuaqqduIBINrHUUU8VumWXtpc 5TCCAT4GCCsGAQUFBwEBBIIBMDCCASwwLAYIKwYBBQUHMAGGIGh0dHA6Ly9vY3Nw MS5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRwOi8vb2NzcDIu bmV0bG9jay5odS9nb2xkLmNnaTAsBggrBgEFBQcwAYYgaHR0cDovL29jc3AzLm5l dGxvY2suaHUvZ29sZC5jZ2kwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWExLm5ldGxv Y2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWEy Lm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0dHA6 Ly9haWEzLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwgZ4GA1UdHwSBljCB kzAvoC2gK4YpaHR0cDovL2NybDEubmV0bG9jay5odS9pbmRleC5jZ2k/Y3JsPWdv bGQwL6AtoCuGKWh0dHA6Ly9jcmwyLm5ldGxvY2suaHUvaW5kZXguY2dpP2NybD1n b2xkMC+gLaArhilodHRwOi8vY3JsMy5uZXRsb2NrLmh1L2luZGV4LmNnaT9jcmw9 Z29sZDANBgkqhkiG9w0BAQsFAAOCAQEATdoIdLEMX7yC897m0MY9t72XS4LlVRq/ z5GgViKPCG/KgXaTNepAlvKC+KyssqO+qGr7iKyCLsduvaOvmSpztqkn0ZMh0Yce OI7iV9YVqFJDI7rOWpxAvBP3iXu1hslV6vhNmTkYJu1wD51e78mLenMcX+n3d17T gZ5gsYRmqplyLgEO4DtXEv2e8bnYZ/ngDCCewUxFdiMZyepNYDIbSei3uEqGmMl5 208b2FyLYnSmG5R0j77VTxGIeRcpDY/qrx/3wQ4NuWFXq6hQ9nhPcKKgVn5yUgn0 h123m3VcoYpob5OKpPoRm2mxkPHUkNZ2e+iimh5nZN/mZee+fIr6/w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzTCCBLWgAwIBAgIGSUEs5AA9MA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTYwNDE0MTQxMDQ4WhcNMjgxMTE3MTQxMDQ4WjBb MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5FVExP Q0sgTHRkLjEiMCAGA1UEAwwZTkVUTE9DSyBUcnVzdCBBZHZhbmNlZCBDQTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPIo9P4wlXm+to+T5+Et2aSkGZm PnzWEt18o5ZbivdvnmdBjqcVbgpd/ACzsZQuC1EK/YPa7+j1JXKoZUhX2EtWoN7T Sl9Y2BunbCK4zYX1nPp0AJ4XYBKtarHBkDEnTNgKg8FihxwZZeDm6uzKQNg5Y4w2 l2RSJj9+dgJIy3nuOQWIUMvCPoWQLjk1cssLE4obDJmYU+/Xl7dgXHfSPiZWXY1f RKmH2SvH7ejzTDglIqInEICsBWmVK0wl/bletfyM0nXryOypnTNp0XiQ+caO7acj nJapMi0C1Y0XbcmMknj8mU4+9Vo1ik3arj+NU+YgPqMpZkQkZrVASbgP/JUCAwCf P6OCAkgwggJEMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB8GA1Ud IwQYMBaAFMz6Z5PwtrjQpcAe81P9jFPfg9eWMB0GA1UdDgQWBBRqnQv4imTIeg4l ZL+wPmG4G/+8gDCCAT4GCCsGAQUFBwEBBIIBMDCCASwwLAYIKwYBBQUHMAGGIGh0 dHA6Ly9vY3NwMS5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRw Oi8vb2NzcDIubmV0bG9jay5odS9nb2xkLmNnaTAsBggrBgEFBQcwAYYgaHR0cDov L29jc3AzLm5ldGxvY2suaHUvZ29sZC5jZ2kwNAYIKwYBBQUHMAKGKGh0dHA6Ly9h aWExLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0 dHA6Ly9haWEyLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUH MAKGKGh0dHA6Ly9haWEzLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwgZ4G A1UdHwSBljCBkzAvoC2gK4YpaHR0cDovL2NybDEubmV0bG9jay5odS9pbmRleC5j Z2k/Y3JsPWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwyLm5ldGxvY2suaHUvaW5kZXgu Y2dpP2NybD1nb2xkMC+gLaArhilodHRwOi8vY3JsMy5uZXRsb2NrLmh1L2luZGV4 LmNnaT9jcmw9Z29sZDANBgkqhkiG9w0BAQsFAAOCAQEAu/WWlFq6e/Tjqs8NmHbZ TsPAYhOCCAnP/G4p5rElF4qCktg/Pudw17odnvrcFLr+ZqSI7KQcNfSlh915nU9Q UBv4lSLE/yP1fr1QRihxM/MWnA39s754cVW5gCc/DoHu9ZkOw+KkYz+BSDHsGj6o 7D4YSjRt9jv4ETz26QkPQ1MjVEUOLbSWh3B7qYCIvdg9sB1d8RfcE9JM5eXeVkkr TWUneN01WAKCY7tVIP0NW+QayIcV5a7btpjRshyZFI4l+008ld38o/nUwhIz6f+t F+jGCaHo3v7u7gjHiRyPA70vcfOsfQBU/UaK4bz1rBX+D0GwLYJwREya7uzOLf7o Uw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0jCCBLqgAwIBAgIGSUEs5AA+MA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTYwNDE0MTQxMTMzWhcNMjgxMTE3MTQxMTMzWjBg MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5FVExP Q0sgTHRkLjEnMCUGA1UEAwweTkVUTE9DSyBUcnVzdCBBZHZhbmNlZCBQbHVzIENB MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz9wEDOSDa1yQem8gwquI CkhDuJrHf2R1X2lzMGGWavhAM0fJNEG0E90v+Y5cLq30pNXC5I/ISXXdGM/s8/85 2JKH0206rR3yFsXJ15yVTGforVOjzVr6bATbDNBFRoj8JMO9YS1NPB7BlMl+X//6 wvnxgHtw66ORfD59W4PSfz1wMjxoQJ503mkm2JbBbHlrvJS5xdImHfVAFDgOhUAZ PfFjD0nPf032LCtWOw4APCWC8Js09u3B7KIdmAXOviJGD1VPRtPKonej53WTMsuC tPHJKGnL3UySRVaVhfky+p76AHy2HsvxDi2UHEMliQmFBaAZc4f086D2j4a/xoWn wwIDAN0To4ICSDCCAkQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw HwYDVR0jBBgwFoAUzPpnk/C2uNClwB7zU/2MU9+D15YwHQYDVR0OBBYEFNkF9UWo xMOT5IKYtwl58vct6rz3MIIBPgYIKwYBBQUHAQEEggEwMIIBLDAsBggrBgEFBQcw AYYgaHR0cDovL29jc3AxLm5ldGxvY2suaHUvZ29sZC5jZ2kwLAYIKwYBBQUHMAGG IGh0dHA6Ly9vY3NwMi5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBo dHRwOi8vb2NzcDMubmV0bG9jay5odS9nb2xkLmNnaTA0BggrBgEFBQcwAoYoaHR0 cDovL2FpYTEubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0BggrBgEFBQcw AoYoaHR0cDovL2FpYTIubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0Bggr BgEFBQcwAoYoaHR0cDovL2FpYTMubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29s ZDCBngYDVR0fBIGWMIGTMC+gLaArhilodHRwOi8vY3JsMS5uZXRsb2NrLmh1L2lu ZGV4LmNnaT9jcmw9Z29sZDAvoC2gK4YpaHR0cDovL2NybDIubmV0bG9jay5odS9p bmRleC5jZ2k/Y3JsPWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwzLm5ldGxvY2suaHUv aW5kZXguY2dpP2NybD1nb2xkMA0GCSqGSIb3DQEBCwUAA4IBAQBmR21cDtqRhEN+ SEYA3QGJDNZBIE3JkbDe5vUUsCqRUyniWSkATg78PaUtT7+J9AZPljoh3L7wLAli 2Et3Hwi8P2krt9l3Kw7enU8XQlBOyn0nbDI8Kw9gC5lNgRga1N4g83EIP5N45cjp GAthkpZDkLGE5bck3aw+6uljySlvPDtvuRDJFehWiHT0DX4re4DRyF/8G8a/o/tk n5Va672SZ/5Hs1nBMdU565TS/HO8DXoLynbFvgonIOgMH9MrOLKS0mabV4Lh9psc MDPINWPWB2rK12xOhinQ1gc6HWdD3aGAibq1dr14EutnOIVOVyvtHBxpVMDUQRrT W+9QnVk5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEjjCCA3agAwIBAgIUbQuQ8uGIeft/zUwWey2FwrvgrRIwDQYJKoZIhvcNAQEL BQAwgYsxCzAJBgNVBAYTAlVTMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMTQw MgYDVQQLEytDbG91ZEZsYXJlIE9yaWdpbiBTU0wgQ2VydGlmaWNhdGUgQXV0aG9y aXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlh MB4XDTE2MDUyNjEyMDcwMFoXDTMxMDUyMzEyMDcwMFowYjEZMBcGA1UEChMQQ2xv dWRGbGFyZSwgSW5jLjEdMBsGA1UECxMUQ2xvdWRGbGFyZSBPcmlnaW4gQ0ExJjAk BgNVBAMTHUNsb3VkRmxhcmUgT3JpZ2luIENlcnRpZmljYXRlMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6rH3rfd9zGhI6hF5i28Z0QUEB/+kYrf6No3L +8WeBousorIUbNYHDP7C5bzGPFkjUdbXY98yeCzFGqxNeQnkUFAzQy0nbAr21GBk SC6Fm5O6OTpNRdO28k2dkuRMGCLpJKdZyNvIMt3A3RJPzj/Texag08sENyHTWJ43 lsMe6u+4h3pgBDBqe1CVpI8K5/C+Ki9TTg2XnjjIgSUs+Q6F3hMyriTxEdDSwQt3 2GKaLQSajzqiTYf2WhlxFcBkEE5955CyWQc6FEDZTgsyVaOnxIx+KTneuWVzPY+V bLVC3FS1jiTJx6ipyWwlix3cPRd9/Ea2BYW2Gy20UndTEv32/QIDAQABo4IBEDCC AQwwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB /wQCMAAwHQYDVR0OBBYEFN8hpdpliQr1Ly5pn1hj5dnmd5mAMB8GA1UdIwQYMBaA FCToU1ddfDRAh6nrlNu64RZ4/CmkMEAGCCsGAQUFBwEBBDQwMjAwBggrBgEFBQcw AYYkaHR0cDovL29jc3AuY2xvdWRmbGFyZS5jb20vb3JpZ2luX2NhMBsGA1UdEQQU MBKCCCouMjRoLmFlggYyNGguYWUwOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL2Ny bC5jbG91ZGZsYXJlLmNvbS9vcmlnaW5fY2EuY3JsMA0GCSqGSIb3DQEBCwUAA4IB AQBiTE3Kt1CGi2k4DTtSMNltuzwfaRX6vh0QRENwfOmma6HwW4x1E92H/5qzy7m3 CE97evyE0mecdimG/xWDJPJ9EAqT4r7+8S6di8ZzbgMBO+roAXgaov9D3VGjrC3d 6LMg+GAm7sdE/gythCgQEyHw3yXqlYERGHvIcttHn3DTsgChQuAcK+fECG2PtU9g wVx01AGmY1EI+nOYWp7RoT7n6Zh2kAotAWnr5ttnPMtDXqpul7UX0k6Y+Kzwsu+F 8R9uNfLE/CZj8ZEVVH2DFhSSL5nlRqt4xQwXVxqj6+KaaodHhMxYgcvVuF6cB7sK F1vFHS+K61xgcfX1i/ygWMFY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIUXu60SnDhjmPJiY8gLLrBZJFO3AUwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xNjA2MDYxNDE2NDBaFw0z MTA2MDYxNDE2NDBaMFQxCzAJBgNVBAYTAkJNMRkwFwYDVQQKDBBRdW9WYWRpcyBM aW1pdGVkMSowKAYDVQQDDCFRdW9WYWRpcyBFbnRlcnByaXNlIFRydXN0IENBIDIg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC8uNEaRwSSvuZABUo+ RKza7R61thEWOwCPJF/TjUr2+3p290tjYCfOrBxLcBRhaGgd/edePwXUkjYZy4uO 5IWeR92VqUaJtK5nkOe9OS1GxD6I+DCs2xL+VRf3RQvPVUP79v9lVVrsGfUq6j4K UXgE+heAokZScee6vC2pyVJ63QK+KOVT8dTKj1Ee0FlYhoxxrIuRB/3Suf22X9wQ o85pDkC+AGwIeqqLGYsIDFxtPX0Byphd1BLjur9SimTb/ePsSgAONCno+mNu7h9S VYqIF4/5nxu91MfQeF9mG+BS+gCTTygmJXCHNR4QYJg10DzmOhYC4wt5re5eyxvj CF8vbczE0OFqPrtX1OZdqHqDLCajgLiVrwtqj4TzUqPhOMvZE/aqQtQ0UoC3Hods fv73pRdZTt2mQjY5DA4uyZRNa8y67nHl75noop59MszWHBJU8GPdcF36Vkxz4z0N GykiIEAqZQR7lH1gjhGA3odGTmW08HlXJHcWoMbV2pjpKR3TV6FhQveBR9mqpEOn gYmMqDMbV0KsAiWWGv9T/yM683J2hdXmJrbtGPb33/D/mkT4QBCK1ge8UOvGewFF bcEI5A53aX4+krPeY6Dun4+XUpRDSBEac8De/FEq2MifDKjF0SDopSkm8AHVtTnw 2wuXnylA3Q/mvaHm1VzQmwrAqwIDAQABo4IBYzCCAV8wDwYDVR0TAQH/BAUwAwEB /zBJBgNVHSAEQjBAMD4GBFUdIAAwNjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5x dW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeTB0BggrBgEFBQcBAQRoMGYwKgYI KwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3ZhZGlzZ2xvYmFsLmNvbTA4BggrBgEF BQcwAoYsaHR0cDovL3RydXN0LnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTJnMy5j cnQwDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFO3nb3Zav2DsSVvGpXe7chZx m8Q9MDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmwucXVvdmFkaXNnbG9iYWwu Y29tL3F2cmNhMmczLmNybDAdBgNVHQ4EFgQUZOMFiya+8zX1nzESCPjkFpwqqGIw DQYJKoZIhvcNAQELBQADggIBADM+g0rlluBUFB4HaUHedhagCTVVgYVmzwS4AGKS Q0xLTE5R7VSRk+AjNlIibUcE9cA4epExPW4H1nuz5B3NTPKUMaoFU1rr3wdF1BW/ 0zF/0YKfoPm8JugmhmBZLxSGF9f2V1eOVMCNNu3qOex6Yd3kd74C5/zALtlQArii R9AG95vsjrQNNJliRCWC0QP/Lgh4938CKesW+uSiuMvjL90hsxILNzGdkQ4xyfZW J1CDqY8r8qWGzN6d0lFmKFH5suIcGduzbOkxEyPFTbm4j5ZlYDegpp/8fYJgRe5N NLUjYH3D4wZfU/E3v+8CUnOgqli2QYtKhs1B52yjcXmKaZTeGs+faQIMuDFOvNR0 NS8X+E/53Xt4+ZnQx9C6jZNjMSE1uAyzLvqI9szs0eg8FnnzqCkPEGd061YE3OHX hz/mGQO72lS/tt9ZHoIUCHN+L5csDztzmgxD8GQK/GirV3SYjVnP0QGIiAFaaK0b HpE6+Qfug9A5CGq0RfgpC81i5kgaECZJrCUij761pctVkPOCsFShaqAEi8OZhb5M SDZ+NZngPqtKgkiw7XejyJgls4d00zE6o5lRq1aVhHwT1aPNyNvu5531MvfdfvBm vHXwLnE22twvirWXO6FW5OAZijIX/asy2iyWNFXYffrl3LcTBXlXwxWvmBMiAq66 aeRG -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIUDCFjpEkk/7f822dazcrucgjMqVowDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xNjA2MDYxNDQzNTlaFw0z MTA2MDYxNDQzNTlaMFQxCzAJBgNVBAYTAkJNMRkwFwYDVQQKDBBRdW9WYWRpcyBM aW1pdGVkMSowKAYDVQQDDCFRdW9WYWRpcyBFbnRlcnByaXNlIFRydXN0IENBIDMg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCg0K/WvJDU6qlk20m/ wAaKwqlLSj2TlQp53Tn2WDJaRp88Dc4mqsjPMIy5HDsU+8VXzqS6mCDGSbN4zyoT R+pj3PDWE8Bk5CAHJ+ub/t00eYtGepbUvQk2Mh0GChlOwYEHFFKhIRbNmgLvYGkH DtkauqXOgBtdXSmBgFC1s4lHU3XDHrHzTdqzijBgIiWVrhpPJLqGb0WiFK/O7qMd cdUmUjYpx73/AgYFd+XfLNPIxVvNMT/9wJHS0g0fq0KXeE1A3okihMsc3Si6n6g3 NU6LQ+dh42r9W79qj1nc+oL/6Ze2G/RWzXK7wUTFM0Fs9AROldnIeQneoRvy6Evr Anxe+IszXZrp9E+DVAL48k6dC+DozmirKuefEMl0BLEKAm0y5JeQXDi+aiTiZqdV hO5HBQRBexp1R7dX2wmH0SscMpHNChrG99fu4c8EUh4b4WNZHPkuKV+rxChtUVUG az5SNIaNXKwb9DrLqaJzvKM+TMvAqD1m+2TYG3iXADy7sYOyx9u+WlPABoKyDUi2 R7vUzhECrEPmYt40yWGsWi/UO74Uopzr8gmonzMrMEmDUiWdSwC36vaVJxJz5vHM 1qo2QkD5+15OKTg9/2hYfOLl/3V9G0+15Dgk3gIbFTiuvJJmTltJVB+ITFMUwGbA aNZ0dLgxETBSxWKI+cXF/fjhKwIDAQABo4IBYzCCAV8wDwYDVR0TAQH/BAUwAwEB /zBJBgNVHSAEQjBAMD4GBFUdIAAwNjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5x dW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeTB0BggrBgEFBQcBAQRoMGYwKgYI KwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3ZhZGlzZ2xvYmFsLmNvbTA4BggrBgEF BQcwAoYsaHR0cDovL3RydXN0LnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTNnMy5j cnQwDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFMYX0Lyo6gJD8hsGmV0rkCC5 15zkMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmwucXVvdmFkaXNnbG9iYWwu Y29tL3F2cmNhM2czLmNybDAdBgNVHQ4EFgQU8BZgIpg1iS+G/M3ZhxwNY1VtOkcw DQYJKoZIhvcNAQELBQADggIBACdwumyuq9gROaXXpgSImSL2ydweQUJxqvcKHzUm lbyhgA+aTp7uNMHcc172rVlssuq2O9pQt8Eq2IE21zYcGivhREjs3ZoSLHs04gSP 8mNB77i7EMhmHgCYjeb7gNffXc9RCskdNCDbBFl5huybGhmnJ7t5e1VzPZ+sNjWg mNXcXp9z8NUJBoPZkm3f8C7ntJkN94EHSScq/hbOScMn9laDJtouS7W+AzD91r3R 4qU0g6PYPOnTQaKwZRR7S4C1HgVMm/CJPZ1aiLnf6TxdfLuor03kYptZSj487XCs G2sFxYHG4kg3J+Krw7euLFaZipozgtQGV9M2DXeY9mBz/Jt+eYnWv8yDDGnFxZZm e0AqE4UFyZ+95/DeMn+NFSxo/YoiR5eTDzGqNQjsocUmcdttK1umyPeL4jxiZjPj VsDle3h/Duzz37m7Vn2LTJGC4JZHlHEkkZ5r8O0vDaWsUgEwL8Utw67wWNkRSkLO 8gNZxoU+Ck59JfIQYjgXLhN0CvubHslqOsR8H2DfXGChuI98MFgsLkl8s4Jyriph 3CeROeyaMlosLOkDSP4pY/02i3Aktpd9hmDhIJxTNdhhxBLGpbZeIh9PrF49T4na P0nSYaTMAhhSvRy4qpzsw9ds5GTruEZfpz1hqaoS96F7xkyHur4BEVskLCcDFWKQ RwpJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIUCthvozW5PvSMjjv3fUxjFDZDrbkwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xNjA2MDYxNDU0MjdaFw0z MTA2MDYxNDU0MjdaMFQxCzAJBgNVBAYTAkJNMRkwFwYDVQQKDBBRdW9WYWRpcyBM aW1pdGVkMSowKAYDVQQDDCFRdW9WYWRpcyBFbnRlcnByaXNlIFRydXN0IENBIDEg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDqL3pDpaiJseEm9psn mngjKR/pfNjNNggII9br+6xSPuqg/Lik/ai1KG5ECbVbuFr98WzdiJ3D4qF9SDGC zFPl3FmIVn27u3kzXCbgLnG5Key9tk+oRhFvGqu6+LRBfpUXaM/NUH2YvuX1ZP8E zPCNmoH8TFjh9sken2pUxjje/wU2rsJvwa7D5rwHKipZM5a6+vsrYXA0DHnL8Jr+ tSGZxwMtMXSy1Kn60E83TJnY/kxiSUuKj+Gw1qq5Eq7S3mQngUaSoRnBVDcAYYv6 lj9JR7/NO74Kq5Aaa86FPqFfC2EiVvTTXh8WXzssNYVsVszX9M/3VMq+68W5RCLW YpH+hgFjw0B9dPJRtOfKzvGdDtmMnyCLbuXC/nfcv35TJO/YnoIBYqQHeUVngUue munp6q32U3mVHbYvGSmvhOEqCa59xfPq2jC+ZRJ2UWkP+iVLrY4lmfwbslRJXYzV Dk2HoWxPVX/HNY8EGbooaB2loVTeK1HCKCuRQVGQpqtn47Ny8ZU/3AfCK4KoXBKn ZjKoW/+RxcHwJuM8ee4zia441VA3w+fIBYQjvfwDUI9M5d6QNzdUOZknDpMlTDst h5epvtLUteY0MPvJkHeh4s/8oYVDzdJjIlo+mntlxqXFAJASpSjHeH+GDSM24Qif MEKmwruyNU0YVzQMRKMX1yeVswIDAQABo4IBYzCCAV8wDwYDVR0TAQH/BAUwAwEB /zBJBgNVHSAEQjBAMD4GBFUdIAAwNjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5x dW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeTB0BggrBgEFBQcBAQRoMGYwKgYI KwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3ZhZGlzZ2xvYmFsLmNvbTA4BggrBgEF BQcwAoYsaHR0cDovL3RydXN0LnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTFnMy5j cnQwDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFKOX1vNeohDhq0WfPBdkPO4B cJzMMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmwucXVvdmFkaXNnbG9iYWwu Y29tL3F2cmNhMWczLmNybDAdBgNVHQ4EFgQUbCa9YFUpKU5mMgeg/2OLg1pLNMYw DQYJKoZIhvcNAQELBQADggIBAGzIGsi4MPWp48gM6raw58xey8JfbjenYVggC3Nv xOJYKVrJTK+oERQHXDSDyjBt8uV91JKb5FsD3vtJc8nkNT1BTVObR8wvoqj9JEui vxkE8klxG/2mG6A2ZkoM6GH8V3Bad1TOZ4fz1vTnUtU5qNmLgb+ngoSAsl2J3fKa aXdMS+OpNCuDgPG6BX9yJ4jziqR4FtDsfgshVrhjee34Si2xdQVc6zaMuP/ZweEC Bfxju6D2hCN3iTf6HJtj8JfavHerUuzZr2Ibvk/rpy9UbHehmQ1SfxSh5xr6XzW6 83JzOUqpkD17+WezKqH0XOyN3xzq8GB2Tg8NYLyd3zsSfABR/MeOBVfZEZDFRIV3 cH8c+J+T7TlObLNxzsBCG5UKJKpVvEmHbZ2gFQAEODK1fAAa/hN+60Jc69AHZvZw uRj+Tak/yOjer/B4kbHXElRYfmBUuzqEJE49t2Zskf2L6UI1FoUKOG6ZnSoTpVcl TnmuZeuJWorzG/hHaVydd4rYicj2U3AozYrTghSiBMVYaJhhv4J/8JPa5Xa0giko llgVigCTRYWpu200/N1IZNpIomYzei9g7RaXGBSiju7KNyWC385fvM/yi3tx1JDr dokV+D24qm4YVpVlxkXRY8WOZAqTP+M1Md7COG7fEkPavaPqCa+KvkoX8QiFuqZM wdjq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYjCCBEqgAwIBAgIQTEzYoPxP6q4VVKh/CQ7ahzANBgkqhkiG9w0BAQsFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMTYwNjA3MDAwMDAwWhcNMjYwNjA2MjM1OTU5WjCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMR0wGwYDVQQLExREb21haW4gVmFs aWRhdGVkIFNTTDEmMCQGA1UEAxMdU3ltYW50ZWMgQmFzaWMgRFYgU1NMIENBIC0g RzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCkN8hYylrZCZihZgN2 5FsiT+qfOv8rKi3MbRIsZ2TUqsS5e1eDLPXI8IP4XXUZLWt9hlqmDpqiZa5mLSBj KDX3iWq/FaOc8l1AsbeOhr9ZESCoEorqm6S9wAL+HX7hLY/7p03SSNSAO+/gr2o7 ciWu3jhd+H4dzGNNDN0nCuRIOX7rTGYI5mOb8QWJRC6H/3MlUYpBt9VV+l2FVNhB LJuofF3TNJojVHximZnTEkybg/r9AZc2TkDHJX1BA6rNjXG8l5iSCL9ICJCBUPB5 z/s3hQBQkOALXN88QTIrlj53XpWpqxYdQJrOFbtWi18WW3ZAnGAscd8vZ5UIg3KL AmoBAgMBAAGjggF2MIIBcjASBgNVHRMBAf8ECDAGAQH/AgEAMC8GA1UdHwQoMCYw JKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNvbS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8E BAMCAQYwLgYIKwYBBQUHAQEEIjAgMB4GCCsGAQUFBzABhhJodHRwOi8vcy5zeW1j ZC5jb20wYQYDVR0gBFowWDBWBgZngQwBAgEwTDAjBggrBgEFBQcCARYXaHR0cHM6 Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGRoXaHR0cHM6Ly9kLnN5bWNi LmNvbS9ycGEwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCkGA1UdEQQi MCCkHjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0yLTU1NTAdBgNVHQ4EFgQUXGGe sHZBqWqqQwvhx24wKW6xzTYwHwYDVR0jBBgwFoAUf9Nlp8Ld7LvwMAnzQzn6Aq8z MTMwDQYJKoZIhvcNAQELBQADggEBAGHqRXEvjeE/CpuVSPHyPKJYFsqWxP/a4quX cRCRsy+ki4EP8qT7NfPnkEogxZvlMctHsWgdtTbp9ShXbqCnqXPCw575BZH2rEKN xI30CWr6U47n4h2hSnaJxJeeA+xKsA1Vk4v8eLu7xwRlBwhZEsYNFAVpD3YEToek H877QzZrZ6EdG/3Vg6sdtHDQ4i/U87syTmyM2l8vXOGIZDd1Wr6dqee2FtCfhvAc WMbvh/J6sBOHMq0Vn5G8Tp6iUwsRlY1z7LaQKAlnlOiiZVhhe+1gvzJBHC0t+Hr2 2YHwaoKDLhSB0F/gGkziNQ+py1hFne4MEOuvzOxJpjn0+wRIbBk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFXDCCBESgAwIBAgIQGHf2ZWingrup+0La5E4z1zANBgkqhkiG9w0BAQsFADCB vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0xNjA2MDcwMDAwMDBaFw0yNjA2MDYyMzU5NTlaMIGUMQswCQYDVQQGEwJVUzEd MBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVj IFRydXN0IE5ldHdvcmsxHTAbBgNVBAsTFERvbWFpbiBWYWxpZGF0ZWQgU1NMMSYw JAYDVQQDEx1TeW1hbnRlYyBCYXNpYyBEViBTU0wgQ0EgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALBoKGatE+oJe9ZT5t7YXUWn15vacpx+XFcf xIhQRX75qaio8fgcsmQkY2zNyWRickmM5laehuW7rE2uZzeaKEeYEiCsNGhtTk8X d3subeM1AINYEregPSuFlDpn+h7Cyw8au/pH6z/lGRRAA7LCsgDjMMreDrq0WKqt xtoZ6Q9DExdztytlCMFhEWOS/AixMmI/4Gu7S/wGD0dg86i8J0DRjdPq+NDbzk/+ vQsBEh0hGbsTKYi0owy23REgytHWMsZi+s6JXAW3eI0fgZ2bynaALE4GVu0tj8hk wEqD0KWQ1Ay4M2z/3Jv17lZumTtv+qEH2aq8ayPIpqJ0qcdctrECAwEAAaOCAX0w ggF5MBIGA1UdEwEB/wQIMAYBAf8CAQAwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDov L3Muc3ltY2IuY29tL3VuaXZlcnNhbC1yb290LmNybDAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwDgYDVR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEBBCIwIDAe BggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMGEGA1UdIARaMFgwVgYGZ4EM AQIBMEwwIwYIKwYBBQUHAgEWF2h0dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsG AQUFBwICMBkaF2h0dHBzOi8vZC5zeW1jYi5jb20vcnBhMCkGA1UdEQQiMCCkHjAc MRowGAYDVQQDExFTeW1hbnRlY1BLSS0yLTU1NjAdBgNVHQ4EFgQUyqxd4ZAv8e+M 1J81AeEBO6DOwXcwHwYDVR0jBBgwFoAUtnf6aUhHn1MS1cLqBzJ2B9GXBxkwDQYJ KoZIhvcNAQELBQADggEBAJRdaWPJpyEdGNMxyRkR93sap0nmeN3WoBUOJlb6lCbu EX/5zhB1Yu9RNqdIFlVYUX/gEURpNDqKQb90xJq3jdfg3z/bQ90beLuohBLREcCm nz78sfnyp7Z6gfXxyOYfy/MTA7866NFN5GEcQiGEBWdcitUhBPLuxzFUUGuGhiR7 f0cUVPq6ADcCDpqOwnFbFFuJ7c+RGz/HG0pqxC0dPiHo1NIF7XK23l12nurVXOmc FJ31PEqFT0Rcd2fs+vkuVfpN+EBI+SY/gHiCOx/BvsgWiE4VXHTYIL36PUKecCQ+ +y9RlQ60UOqmSTQEQkkAUAn7w/0LjXEnfwfMhPABUcU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGEjCCBPqgAwIBAgIQBeIff+l1JPJbhO/CkYj+uDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBGZWRlcmF0ZWQgVHJ1 c3QgQ0EwHhcNMTYwNjA3MTIyNjU0WhcNMjYwNjA3MTIyNjU0WjBoMQswCQYDVQQG EwJVUzELMAkGA1UECBMCU0MxDzANBgNVBAoTBlNDSElFeDEgMB4GA1UECxMXU0NI SUV4IERpcmVjdCBNZXNzYWdpbmcxGTAXBgNVBAMTEFNDSElFeCBEaXJlY3QgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0anB2c2gTBvvvgrkI0diV xnwGNMMYqrlnCpoB/h3+fhfz/C4FbWLXJPEFYRoRdtKgmjHkUk+VIMN8QhB32b6Y cT+o80mF7ngiluK8xulLAoGPcXnqpqFjWhKt7Zj9/n+j6EGtovL+Kl0stdWr12XZ VM/ON6ap9k6d5x/wAaehPJImOL4FEz+1z755u/Bxh2+hG06wxLeJtaQSvykfAjXr 61j0Sb6SJYn1U7+Fa2Sr62fIMWhjO1n/XD6kv/t2IRtRMEZLA60jAAm4r6HNbanE /+VV3IA14BtQh4tCV9DeXDTJBTBxnmZMUaaYDaJ7hpK3vPNqUusu5Z1pVnegqd3n AgMBAAGjggK5MIICtTAdBgNVHQ4EFgQUzukCNH2qBjhBbQTVz7ry8DqkQ1wwHwYD VR0jBBgwFoAURgg4WqmOILsMr14xuomzKL+sjDYwEgYDVR0TAQH/BAgwBgEB/wIB ADAOBgNVHQ8BAf8EBAMCAYYwcwYIKwYBBQUHAQEEZzBlMCQGCCsGAQUFBzABhhho dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wPQYIKwYBBQUHMAKGMWh0dHA6Ly9jYWNl cnRzLmRpZ2ljZXJ0LmNvbS9haWFTQ0hJRXhEaXJlY3RDQS5wN2MwgYMGA1UdHwR8 MHowO6A5oDeGNWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEZlZGVy YXRlZFRydXN0Q0EuY3JsMDugOaA3hjVodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v RGlnaUNlcnRGZWRlcmF0ZWRUcnVzdENBLmNybDCCAVIGA1UdIASCAUkwggFFMDgG CmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu Y29tL0NQUzAMBgpghkgBhv1sBAEBMAwGCmCGSAGG/WwEAQIwCwYJYIZIAYb9bAQC MAwGCmCGSAGG/WwEAwIwDAYKYIZIAYb9bAQEAjAOBgxghkgBhvlbA4ohAAEwDAYK KwYBBAGCwVsAATAMBgorBgEEAYLBWwEBMAwGCisGAQQBgsFbAQIwDAYKKwYBBAGC wVsBAzAMBgorBgEEAYLBWwEEMAwGCisGAQQBgsFbAgEwDAYKKwYBBAGCwVsCAjAM BgorBgEEAYLBWwIDMAwGCisGAQQBgsFbAgQwDAYKKwYBBAGCwVsDATAMBgorBgEE AYLBWwMCMAwGCisGAQQBgsFbAwMwDAYKKwYBBAGCwVsDBDANBgkqhkiG9w0BAQsF AAOCAQEAAdJq9Bgqa3r/WqAAIj+DGU9uS96aac5V/+g7JR8s5r0vNGTHgSy/j4M1 S8DPpaiUQAnu65/M+A88XE4nhLfk94q+F9xOmbbsG8LAPJDVvfSdoNy4Yy7TG9yE nGZdFFBhYwj6Aeh3mH1NKPvop+HNTBlojGwD10wWhQa7BSsJzOeKdeVfJIrnzGEK f9NeMMszypLRXh0/m4dBnX2IRcRbOXdj6gIOEpYzJmRvA7tPIqAD+ox9MYCT1xGC RF3LfadgoIO4aM7CaDFM3mpP7pQYQnUflVk/9KYvu1tvyMkMtuQ219ifBC5rQLge xO1gXHZsyLik21PZsDZb+tB84WDiqw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEWDCCA0CgAwIBAgIPMR1+3eSSAgi72F73Jiu6MA0GCSqGSIb3DQEBCwUAMIGD MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B LjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MScwJQYD VQQDEx5DZXJ0dW0gR2xvYmFsIFNlcnZpY2VzIENBIFNIQTIwHhcNMTYwNjA4MDgw MTI5WhcNMjYwNjA2MDgwMTI5WjA9MQswCQYDVQQGEwJQTDEVMBMGA1UECgwMaG9t ZS5wbCBTLkEuMRcwFQYDVQQDDA5DZXJ0eWZpa2F0IFNTTDCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBALDozq2WteNT2CsyO5CY9rCN4neWGyj+26XUYS5o oM+tzFlMrbdNk3J+aI7P8Ab29qlSuPRgpHMi++AopeaOYsiwuVJZqnN2W1PC6huf b9mVMv3mcxYLCmuEiY4k9N7L4SUMLxPrRlb7ksD/ogaEgMEYHf5QJyEdp2z4Qy2u C4K/+zpyKpsBeihk5NGnoqTL4LmKNZWyGvJXwq3INuhd4hCpdMgEtX1Mo2TYa8bc amo02VhHHX875TjxC/l3nEKXNcddLN3VvlnYGu7xvIwmCB0P9VDIB53MofqlN+lM zcx8XelCSSWiJKFKXCv4bsvqJOTHuejmi6yDZF8icM8zdVsCAwEAAaOCAQwwggEI MBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYDVR0fBCswKTAnoCWgI4YhaHR0cDovL2Ny bC5jZXJ0dW0ucGwvZ3NjYXNoYTIuY3JsMG4GCCsGAQUFBwEBBGIwYDAoBggrBgEF BQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2VydHVtLmNvbTA0BggrBgEFBQcwAoYo aHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBsL2dzY2FzaGEyLmNlcjAfBgNVHSME GDAWgBRUmd2b/+inDqMZnVu+QlffMPyPMjAdBgNVHQ4EFgQUPZG2zBF76+RmEazS 0gfLqaSAczEwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQBBGurH V6ciSTVqiNgltiQilglZfJcBo9MpMYDIFUnPvZKLjeMYYgbySA77cEyevma053Nm leNWr9burXQqbZ8P9n4iJh3n20E+A6048bsH+0mMY2Xyc1AGy4pclIUNRlPNtYpA H2jndvUoZP+4RwUjiGLEtX1jhORw4rZb6j+UXVWTBssj7Y+8GBp9MXl9ShIpb3Vb DIRnxv2KcydLRRAb4pP3mw0rHWLmAZ3UY1Aj6aeeoWh5sKZbmHOpjelwaGyiojSm dg0GZufYhBeYxQNXpdhWxDRIzAT890wqp77PXKTFMZaS0QaZz7k4o/K/VGJVWWkY 1xuL4Zl8WvEcVWEK -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVDCCAtugAwIBAgIQE1Iuv8HdXOEe8nZAdR/n3zAKBggqhkjOPQQDAzCBmDEL MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEcyMB4XDTE2MDYwOTAwMDAwMFoXDTMxMDYwODIzNTk1OVowYjEcMBoGA1UE AwwTQXBwbGUgSVNUIENBIDggLSBHMTEgMB4GA1UECwwXQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAELVSOaLAQE+/0LdvYCbJD6J1lmW40uNSXyY7J 1qgiNzLIcWDusPHyxWT2ukdf/OYHeDIt9sqAIMn9cPhykyGIRaOCATowggE2MBIG A1UdEwEB/wQIMAYBAf8CAQAwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2cuc3lt Y2IuY29tL0dlb1RydXN0UENBLUcyLmNybDAOBgNVHQ8BAf8EBAMCAQYwLgYIKwYB BQUHAQEEIjAgMB4GCCsGAQUFBzABhhJodHRwOi8vZy5zeW1jZC5jb20wSQYDVR0g BEIwQDA+BgZngQwBAgIwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2VvdHJ1 c3QuY29tL3Jlc291cmNlcy9jcHMwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF BwMCMB0GA1UdDgQWBBTDxKRYBWPXgwa6lo3cso8y9ru3QTAfBgNVHSMEGDAWgBQV XzVXUVX7JbKtA2n8AaP6vhFV1TAKBggqhkjOPQQDAwNnADBkAjBH2jMNybjCk3Ts OidXxJX9YDPMd5S3KDCv8vyTdJGhtoly7fQJRNv5rnVz+6YGfsMCMEp6wyheL7NK mqavsduix2R+j1B3wRjelzJYgXzgM3nwhQKKlJWxpF7IGHuva1taxg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXzCCA0egAwIBAgIRAIARGW3mE9sWAAAAAFHTV14wDQYJKoZIhvcNAQELBQAw gbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkwNwYDVQQL EzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVu dHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNjA2MTAxNDU4 NTVaFw0yNjExMTAxNTI4NTVaMIG/MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRW50 cnVzdCwgSW5jLjEoMCYGA1UECxMfU2VlIHd3dy5lbnRydXN0Lm5ldC9sZWdhbC10 ZXJtczE5MDcGA1UECxMwKGMpIDIwMTIgRW50cnVzdCwgSW5jLiAtIGZvciBhdXRo b3JpemVkIHVzZSBvbmx5MTMwMQYDVQQDEypFbnRydXN0IFJvb3QgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgLSBFQzEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASEE8nQ um1Be+Js0OtVX2YCGiT0W4lpR+O4wn3x8gLFn6D2W9WLBhmGT1MQbQckJ6Gg+NVH GWFMfcqTJ+p0DO9vlgn+Y+xwXTatZ3euyZ18VUQ6omNRH/XjYtSpRwc+zCCjggEP MIIBCzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAzBggrBgEF BQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDMG A1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW50cnVzdC5uZXQvcm9vdGNhMS5j cmwwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cu ZW50cnVzdC5uZXQvcnBhMB0GA1UdDgQWBBS3Y+ca3Y3pCKZVg6TgalBBZRFCSTAf BgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTANBgkqhkiG9w0BAQsFAAOC AQEAByx83MyDCRFVriDsLb8T4nBITSzMsZ7NPz3qNZ9YsPA5ZSijRZW5V9/zFhaV PAy0qAQdaatPfGtJXaykRfZYiPBZr90bdsofJ1in3osPpUn2yu32Vj0slz/qQ724 ao6jmaLemPYedVJRhVDmJyddva2LSbpyGRP3cO/c/Sh9UOHo4F+pv/vwEZhYL9GY 7EusxyHM7KhgrHMKNe34qF995Uibs4aaWURNACi/wxwWe/SrWJ0W8riguH4ihqnd 6MGCMmMuKdFn9lnKYZyAH0L9ZJbTNDPixcC78M0dVzXV/83Ao5hliMQkfaYFbqGh jwwKBwiKwfUHHDANKk0txicHhg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFfzCCBGegAwIBAgIMG4CdusjxlOvdXSeoMA0GCSqGSIb3DQEBCwUAMIGVMQsw CQYDVQQGEwJERTFFMEMGA1UEChM8VmVyZWluIHp1ciBGb2VyZGVydW5nIGVpbmVz IERldXRzY2hlbiBGb3JzY2h1bmdzbmV0emVzIGUuIFYuMRAwDgYDVQQLEwdERk4t UEtJMS0wKwYDVQQDEyRERk4tVmVyZWluIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IDIwHhcNMTYwNjE1MDkzMDE4WhcNMzEwMjIyMjM1OTU5WjBcMQswCQYDVQQGEwJE RTEpMCcGA1UECgwgVGVjaG5pc2NoZSBVbml2ZXJzaXRhZXQgRG9ydG11bmQxIjAg BgNVBAMMGVRVIERvcnRtdW5kIENoaXBjYXJkIENBIDIwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDbHdQiPJe51+lEgl4cwznHMv+wr+NiDewvx9IbqOIo aS5vxQz/fur6M6jyoj9lUP92UbKpxvFPrHyT8aePQ/fZbsMw2eLgEIMdJRDzSFjC Id1ufksGLYw1NOcbl2cfnMu6nl4Y5m5Fq9uc70KPQRim4C66G2ZW1KoCgJ6Pd19l S3IA85hu+g9Wmm1NRHhccgb+tYYMmM77wW0OZiJT02t/lAYH6982v+/RJ0NKCEFf aTfwFegzFNdzLMGzYkpWejmM8+t1dJPRJBAaPPujd2E7qEbnqhjERBsEFzGs2LHn SaWlGnraJoSRffECQ6pGkZ478zuUxlQebRSFv7OHmSdnAgMBAAGjggIFMIICATAS BgNVHRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBBjApBgNVHSAEIjAgMA0G CysGAQQBga0hgiweMA8GDSsGAQQBga0hgiwBAQQwHQYDVR0OBBYEFCdxRlRpU29i JvzdVa2f8Ppa78f1MB8GA1UdIwQYMBaAFJPj2DIm2tXxSqWRSuDqS+KiDM/hMIGP BgNVHR8EgYcwgYQwQKA+oDyGOmh0dHA6Ly9jZHAxLnBjYS5kZm4uZGUvZ2xvYmFs LXJvb3QtZzItY2EvcHViL2NybC9jYWNybC5jcmwwQKA+oDyGOmh0dHA6Ly9jZHAy LnBjYS5kZm4uZGUvZ2xvYmFsLXJvb3QtZzItY2EvcHViL2NybC9jYWNybC5jcmww gd0GCCsGAQUFBwEBBIHQMIHNMDMGCCsGAQUFBzABhidodHRwOi8vb2NzcC5wY2Eu ZGZuLmRlL09DU1AtU2VydmVyL09DU1AwSgYIKwYBBQUHMAKGPmh0dHA6Ly9jZHAx LnBjYS5kZm4uZGUvZ2xvYmFsLXJvb3QtZzItY2EvcHViL2NhY2VydC9jYWNlcnQu Y3J0MEoGCCsGAQUFBzAChj5odHRwOi8vY2RwMi5wY2EuZGZuLmRlL2dsb2JhbC1y b290LWcyLWNhL3B1Yi9jYWNlcnQvY2FjZXJ0LmNydDANBgkqhkiG9w0BAQsFAAOC AQEAecguhuIR4nh/Ff+UwdW++MEjYeoQkHTKqzalUxJZwuILhgBdX4BC8yf17bSA vpi9oPzEBm10aCynR/RRIZahfRH5IRR798V2egPbKtkFzHJmsivccPpsaYBanJP5 uBQmNSfmiDK7jwbTmZSPDmRz0fXrxdi1W101ShJdmLxTQkuzYWRtrYhJ6YgTcjvK i7W07uFuzKUZWZApgcydXbI0wAXw4/BgcfQzvIvm08uEVQaTUrI7VrxEOoVfQ4Ci x/YAQ9QIC3I5pIQZqshqNEH1QwEtW0+iy/g2jq4w4AzXzDpGkP4OgFYSfbwBHoHO FXsHRyRwzmPejMZxo53WGt/TXw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGZTCCBU2gAwIBAgIQAbxreRRHzakKihToIElX/TANBgkqhkiG9w0BAQsFADCB ijELMAkGA1UEBhMCVVMxGjAYBgNVBAoTEU9yaW9uIEhlYWx0aCBJbmMuMS0wKwYD VQQLEyRPcmlvbiBIZWFsdGggRGlyZWN0IFNlY3VyZSBNZXNzYWdpbmcxMDAuBgNV BAMTJ09yaW9uIEhlYWx0aCBEaXJlY3QgU2VjdXJlIE1lc3NhZ2luZyBDQTAeFw0x NjA2MjExMjUzNTRaFw0yNjA2MjExMjUzNTRaMHgxCzAJBgNVBAYTAlVTMR0wGwYD VQQKExRUaGUgS29ibGUgR3JvdXAsIExMQzEtMCsGA1UECxMkT3Jpb24gSGVhbHRo IERpcmVjdCBTZWN1cmUgTWVzc2FnaW5nMRswGQYDVQQDExJUaGUgS29ibGUgR3Jv dXAgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHhI202lbZFrj/ bJbjNqiCydU8oQyIpgb0glqhhDgxWqgi5w8bckCeVHLlUqSV078xKeKp1lFpUmdO RmR7No5LK7SfdF7kCDQ3cLwzz0ENqRxhdK/6Hxpk+IBWuSEbqdsvAftDdnl5p4Ck SdKho/ZIk3WRvVt32vHH4cOsmkbRHPK2j14q8PR/pOVuhKukFliqXASm3TTkOrj/ HQSs87DsxWfbCaYRkNHfI7C+iSaDap50rRxY5IJj0PChEgC/BCUkdXXkXE8yt+kV eBF7Lz7f8TKrfnSSImq3Azk+Ruv3MbLYiBeraSRexYdLTllAZl7wqnW+jIl4UwlD B5qjLhknAgMBAAGjggLWMIIC0jAdBgNVHQ4EFgQUz2BKxu29xQTZyWoXmjT80/nU 3nkwHwYDVR0jBBgwFoAUpW4i/zlpOiP7iSQXxmCUABrajp4wEgYDVR0TAQH/BAgw BgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwegYIKwYBBQUHAQEEbjBsMCQGCCsGAQUF BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRAYIKwYBBQUHMAKGOGh0dHA6 Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9haWFPcmlvbkhlYWx0aElzc3VpbmdDQXMu cDdjMIGZBgNVHR8EgZEwgY4wRaBDoEGGP2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv bS9PcmlvbkhlYWx0aERpcmVjdFNlY3VyZU1lc3NhZ2luZ0NBLmNybDBFoEOgQYY/ aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09yaW9uSGVhbHRoRGlyZWN0U2VjdXJl TWVzc2FnaW5nQ0EuY3JsMIIBUgYDVR0gBIIBSTCCAUUwOAYKYIZIAYb9bAACBDAq MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAwGCmCG SAGG/WwEAQEwDAYKYIZIAYb9bAQBAjALBglghkgBhv1sBAIwDAYKYIZIAYb9bAQD AjAMBgpghkgBhv1sBAQCMA4GDGCGSAGG+VsDiiEAATAMBgorBgEEAYLBWwABMAwG CisGAQQBgsFbAQEwDAYKKwYBBAGCwVsBAjAMBgorBgEEAYLBWwEDMAwGCisGAQQB gsFbAQQwDAYKKwYBBAGCwVsCATAMBgorBgEEAYLBWwICMAwGCisGAQQBgsFbAgMw DAYKKwYBBAGCwVsCBDAMBgorBgEEAYLBWwMBMAwGCisGAQQBgsFbAwIwDAYKKwYB BAGCwVsDAzAMBgorBgEEAYLBWwMEMA0GCSqGSIb3DQEBCwUAA4IBAQBI9pPEUfME Li1zMi/91touHZPZbCw+E5KYxthwzG1CCKr5aLEVTwXewNKZRD58ESy8V4nHdoR9 ESrg8CefmMEmJkNDNGEym2sQEm7r58MPqp0qYecCeghof4cd8FbSqjqcxa0AGhYK HkNrCzfe3FkBk2xqJkI5t5YTum8zO12isqSqcMNqLegSqwOpikaleTvv0iW3aWZ/ Gipaz137e4TkzlYWFvNoyWPslItrn5Y9MNGYQYJz3DoWKFHZwU9x7FfPIsyRVUhY O2hAQvZA2En+c9Yd+fMbqnF1/C2xqQc5jFhd23HSpW0HT8eQjAKC1UHfESXO/9GV LfK5WXTtPEkp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID6DCCAtCgAwIBAgIQApcHVgzUqeu/4nLx4JbYgjANBgkqhkiG9w0BAQwFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE2MDYyMTEyNTQyN1oXDTMxMDYyMTEyNTQyN1owdDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEzMDEGA1UEAxMqRGlnaUNlcnQgRUNDIEV4dGVuZGVkIFZh bGlkYXRpb24gU2VydmVyIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEsTD18xEd L37yf0fDgxZc5SDwkFtw1X0lLq1xZ63sdy7bUN3a9SFQQlRMBLVTA6n6DYEYaCx9 Gm4T5/4BDxOJ/nbehfBhePGJYa8ArSeEBU6AfwKkzLvhYnoJ9yliA+Yto4IBKjCC ASYwHQYDVR0OBBYEFPgl2aY5x8OBhyU+MFSRGCFAmxedMB8GA1UdIwQYMBaAFLE+ w2kD+L9HAdSYJhoIAu9jZCvDMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/ BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au ZGlnaWNlcnQuY29tMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2lj ZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwPQYDVR0g BDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0 LmNvbS9DUFMwDQYJKoZIhvcNAQEMBQADggEBALbraarwzbiGdA9tu6hU0fPGkXOn CdzP6ihrGZVQVrijJgOvlbFaUmDWBmZV8t6VW6QBkSG4p4xy74bUO2tLcV52PVyo kJFaj6v8x3MNr5u592xYI8LNMVSht8hBCLbhEfo6UB6MgdVTcslwSdnwhzGFdWN3 RWKVPPFBAexMXgalK/fwNkISaldkyklivD/PHcRWQ4QZYfFdFgWrVEHsbjyuRg4q TMbH9pR4k/TuJARSDvjfdw7ASRnaEOOZl6Qc2L2Jp9sZGCCoxTtI0DCbwdTZze46 pu84/0KdHzY3cLcmAJL4tXqHNeExugHCPaRAQO41oiE+ZCOEFcwvl+NPrdI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D 9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY 6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV +3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV 7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl 6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo 27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT 6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ 0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm 2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHWTCCBkGgAwIBAgINAIxV2GZScC7xGzOuCjANBgkqhkiG9w0BAQsFADCBgjEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMScwJQYDVQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkx HzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMTYwNjIyMTAwMDAw WhcNMjkxMjI5MjAwMDAwWjCBjjELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFw ZXN0MRYwFAYDVQQKDA1NaWNyb3NlYyBMdGQuMRwwGgYDVQRhDBNWQVRIVS0yMzU4 NDQ5Ny0yLTQxMTYwNAYDVQQDDC1BZHZhbmNlZCBDb2RlIFNpZ25pbmcgQ2xhc3Mz IGUtU3ppZ25vIENBIDIwMTYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQDMbS8Y4YyYZVdUexAFgwX7qN1tKTURIe4VnDQfctsUO0+QI5y6m5XeMGIHnfeY dPS3keA674GXrwII6h61FtVWlSXL48IPsSXoZIxA3ikxV393ptAPxK8bejbTf9Te aBr8OCkB4yNt/n3r89Ky3Artl2MB+nbeuGLfY1UGQ6uwOUoyOuBg6dE06w+elgH7 WSwl3983j5NQr0I+z2nJ9XoIB8wiwjTtHg2nRGDWyzKslkSdAweW+srX8MnStLtp szWeOKrt8B342sFjluP6iSi4A/rgix7AHg4qDvp74nBQj6pfmPazmcsXN0NG6MK4 uBlNXe17xtVARVCCv8b9DRkCXfot7CGuZNUNITzcmpwxUOtLjUThcWS8O7+rS+L7 lREl8NNJ2zt43AHCeSh67fJPYxbURIr8O/vjfd26+2qEswhbT+0v1Jy29P+S94BA 7p3+fGXyyTZ3CPC+WdpzfGY7rccc8Qfe2cJL+DFNxSi19qxznFC6KI6r3zIhOlcw ueUECkcTFxBDJaquhlSxeKqh+u9d/CUc1XQmY3obs3NnHTI99euCnzRj8oQg4n/0 Lh4KrcaD6oy4sqPVVGs97+1uehjAxYA1KPQRLk9MuxhxRnjqq4wg3utIu37D9lji mv9k4rqYrcrsjfRjATy0DiSqanNI5Vi2ASIxTcV8WmC9TwIDAQABo4ICvjCCArow DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwOwYDVR0gBDQwMjAwBgRV HSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcC5lLXN6aWduby5odS9hY3BzMB0G A1UdDgQWBBROSlPE2OB/EfyGBHnoKErjOSuGfzAfBgNVHSMEGDAWgBTLD8bfQkPM Pcu1SCOhGnqmKrs0aDCBtgYDVR0fBIGuMIGrMDegNaAzhjFodHRwOi8vcm9vdGNh MjAwOS1jcmwxLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3JsMDegNaAzhjFodHRw Oi8vcm9vdGNhMjAwOS1jcmwyLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3JsMDeg NaAzhjFodHRwOi8vcm9vdGNhMjAwOS1jcmwzLmUtc3ppZ25vLmh1L3Jvb3RjYTIw MDkuY3JsMIIBXwYIKwYBBQUHAQEEggFRMIIBTTAvBggrBgEFBQcwAYYjaHR0cDov L3Jvb3RjYTIwMDktb2NzcDEuZS1zemlnbm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6 Ly9yb290Y2EyMDA5LW9jc3AyLmUtc3ppZ25vLmh1MC8GCCsGAQUFBzABhiNodHRw Oi8vcm9vdGNhMjAwOS1vY3NwMy5lLXN6aWduby5odTA8BggrBgEFBQcwAoYwaHR0 cDovL3Jvb3RjYTIwMDktY2ExLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3J0MDwG CCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAwOS1jYTIuZS1zemlnbm8uaHUvcm9v dGNhMjAwOS5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2EyMDA5LWNhMy5l LXN6aWduby5odS9yb290Y2EyMDA5LmNydDANBgkqhkiG9w0BAQsFAAOCAQEAlch1 fWW2UPpLfYqNDAUutHLXIgNa0e3Za4UDnQ9MovQ5NCHsx6CpokicZ9VnRvv0ASvg dK6PcgTyRrkY1ZUo/1hVwxIIX+5Z3TAAMUX8C852g9dOPS9peeelR4oRJ0uB36+c c9/SsgM5dV3aJSBR8/+Oiz7o6Ri7GMkJ9JuIFKzxAjk0ZU8vQRbX6TmTi8E57rRh eamA6GMeAHtps4M49YrInenou1hDisBNXbUncesK3iEOX8iv9Z0RSuUdMA4HLPU5 PeXWAci69fghVfDJIC+0CfGuP4A0cZuoP7LCwEECp8Vi0mQdYkaOWw8UKnGsXBM5 pUcfm4LxKgdNS9dZJg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHUjCCBjqgAwIBAgINAIsoit2Yr3kbAiB/CjANBgkqhkiG9w0BAQsFADCBgjEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMScwJQYDVQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkx HzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMTYwNjIyMTAwMDAw WhcNMjkxMjI5MjAwMDAwWjCBhzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFw ZXN0MRYwFAYDVQQKDA1NaWNyb3NlYyBMdGQuMRwwGgYDVQRhDBNWQVRIVS0yMzU4 NDQ5Ny0yLTQxMS8wLQYDVQQDDCZBZHZhbmNlZCBlSURBUyBDbGFzczIgZS1Temln bm8gQ0EgMjAxNjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIZXPNOf mYYattCLCu6LAQ04Tvwep6v4WsoAUC7VxiiTartm9qBDL7L5gJYv1D5djc/5ze1E j+z+djom0mCBEYAlHAXMMwmdeHpSWdcJaGZv/3LTsp0Ot2fnTxrJ9GKTfk04A6X/ o5K+wHBfJa+YKdOCmQ6ZXue/UurEd//pBanFPgWIK99gqzR0WhiBO6R014hfnoob 8zd2vfA6dMW3MZ7KLMchwOQY2fSGhgaXL5yrWYBAr3s3WWXvQF75vY8oH4YmVtr/ 12GWyrbl1dFD8X68yjTKD9I6z3+i88xyuHTmLQlj0xyKp3RLjnXCHNlABx4L3hif CoiWeDChzDBbhBn83/GHu4p5XlnNsnT948dmvXwT/mNglV/eOw95clTSjn8Guc2+ smNfA2LEsyBoH25a75Pu7XqQBw0J/XJiOYjdRzo8g3t0LPrdx8IiIFgoI7AfSeZN rzRgq2m+BPt2CvsFwJZAkgoEXSMke31am1Eo+EQ/cRPd3aMGX9KU8/ScseghFIbo M7OEYnne/k12oY3rBNncE2dlZKwDzvt5pvk+kWD4F1bX5AOCNGCJF/XxzgKnNNPP E7hBv86kPv5DsrAqx0a4sz4Z71sN4yUKqqMaAN2R5rue+/VO0MqW1PKARlk5IVhD L6wXSYpEhCweHWvNV0SoXbF9ubqGQAgEFZo/AgMBAAGjggK+MIICujAPBgNVHRMB Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA7BgNVHSAENDAyMDAGBFUdIAAwKDAm BggrBgEFBQcCARYaaHR0cDovL2NwLmUtc3ppZ25vLmh1L2FjcHMwHQYDVR0OBBYE FG5nLVHi2b4xD+Sv2/yVjABlrg3BMB8GA1UdIwQYMBaAFMsPxt9CQ8w9y7VII6Ea eqYquzRoMIG2BgNVHR8Ega4wgaswN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNy bDEuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcmwwN6A1oDOGMWh0dHA6Ly9yb290 Y2EyMDA5LWNybDIuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcmwwN6A1oDOGMWh0 dHA6Ly9yb290Y2EyMDA5LWNybDMuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcmww ggFfBggrBgEFBQcBAQSCAVEwggFNMC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNh MjAwOS1vY3NwMS5lLXN6aWduby5odTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3Rj YTIwMDktb2NzcDIuZS1zemlnbm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290 Y2EyMDA5LW9jc3AzLmUtc3ppZ25vLmh1MDwGCCsGAQUFBzAChjBodHRwOi8vcm9v dGNhMjAwOS1jYTEuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcnQwPAYIKwYBBQUH MAKGMGh0dHA6Ly9yb290Y2EyMDA5LWNhMi5lLXN6aWduby5odS9yb290Y2EyMDA5 LmNydDA8BggrBgEFBQcwAoYwaHR0cDovL3Jvb3RjYTIwMDktY2EzLmUtc3ppZ25v Lmh1L3Jvb3RjYTIwMDkuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQCcSRwLtW2Jlqfd g0T4ex1xkOFAh8AHy6JkpAHD9bZjxuXurZRbdLk9A/1PRTkHL8ycQI5WCZPKVLjd eO8I/uiu77Q2c3cDaFw4gDPfToKm+4upOcsyJK+7i4GsskpcegnqHfdtAeL4SZN3 F/ITYN3qd2au6kzodvFKCpmRFS6t1bLVWQgl/falx0lUSSXJj0TYz5m0QtQ9tQJb UGNeuRZrRL/W3ui26WvbTWAtRMn3qNxO7X+EryIOB2kwerg8/O70p0233/YUhdT8 kQR0wkimOAj+UKKFmiKvcx35Qy+9l5UeNIY8zBUFLEGC8SqsF3COCNWR38fJJxFo jeIMdvoN -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdTCCBF2gAwIBAgIMG53NioT2UXtHWMz0MA0GCSqGSIb3DQEBCwUAMIGVMQsw CQYDVQQGEwJERTFFMEMGA1UEChM8VmVyZWluIHp1ciBGb2VyZGVydW5nIGVpbmVz IERldXRzY2hlbiBGb3JzY2h1bmdzbmV0emVzIGUuIFYuMRAwDgYDVQQLEwdERk4t UEtJMS0wKwYDVQQDEyRERk4tVmVyZWluIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IDIwHhcNMTYwNzA3MTI1MDAyWhcNMzEwMjIyMjM1OTU5WjBSMQswCQYDVQQGEwJE RTEoMCYGA1UECgwfVGVjaG5pc2NoZSBVbml2ZXJzaXRhZXQgSWxtZW5hdTEZMBcG A1UEAwwQVFUgSWxtZW5hdSBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAOcUMAABmqyHKHNeaKsx1PjhhY915G7vkJFHhN5aOl02fYAdClHgY5C5 TW63HG7n8sRPqgnh+vlpIJRvmBN2C5z2MNzuqqZoVor/HtnQROYuxQFLW5UE6Pij VRQnxBd6VCyb0MkmaPgXd8PYHU+Qp/qeIoAaMkbDlilLahkI2ZjCfISBsL73MYGw Fh1hBw8B+GUU/HAObB0GOe8U8OqjKKhOEFjKw6u3eMoLXC4ZXb0n0DPKckij8/mv mVTOzpMpJrbwMr0MB+cUPzbzgHm6KZdGTA/mpznPWs/46ZRCwdCC9zxkh3yLCcLk eBwCoL6N3LnwfcnAeqBOit8CdnI/ysECAwEAAaOCAgUwggIBMBIGA1UdEwEB/wQI MAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMCkGA1UdIAQiMCAwDQYLKwYBBAGBrSGC LB4wDwYNKwYBBAGBrSGCLAEBBDAdBgNVHQ4EFgQUZNFiW2re410Zk3uia6chNOkG 3yEwHwYDVR0jBBgwFoAUk+PYMiba1fFKpZFK4OpL4qIMz+EwgY8GA1UdHwSBhzCB hDBAoD6gPIY6aHR0cDovL2NkcDEucGNhLmRmbi5kZS9nbG9iYWwtcm9vdC1nMi1j YS9wdWIvY3JsL2NhY3JsLmNybDBAoD6gPIY6aHR0cDovL2NkcDIucGNhLmRmbi5k ZS9nbG9iYWwtcm9vdC1nMi1jYS9wdWIvY3JsL2NhY3JsLmNybDCB3QYIKwYBBQUH AQEEgdAwgc0wMwYIKwYBBQUHMAGGJ2h0dHA6Ly9vY3NwLnBjYS5kZm4uZGUvT0NT UC1TZXJ2ZXIvT0NTUDBKBggrBgEFBQcwAoY+aHR0cDovL2NkcDEucGNhLmRmbi5k ZS9nbG9iYWwtcm9vdC1nMi1jYS9wdWIvY2FjZXJ0L2NhY2VydC5jcnQwSgYIKwYB BQUHMAKGPmh0dHA6Ly9jZHAyLnBjYS5kZm4uZGUvZ2xvYmFsLXJvb3QtZzItY2Ev cHViL2NhY2VydC9jYWNlcnQuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQCZXmIQVpPh oY0ObBsAcwdsT6gKzQ1jCf0b2liPdUzjcn/KK72RE2NCUkIADEjBXl8KC2yiNvWN RN1H4ZZQRTOUPXHSDrh9xSqtWzaxxJF6xyMR+CE23obt/FDS2J1TKbBRFullXEn8 PzL1SattopnVyQyxHTc+vAFLIl0YASiMFhuqB3ntZe4gBIbBpApNBq/MDJPTNlMA HUCL5F8ukLl8GZ1IQTyVHZ+P4qmNiEoTElx/rlDA7CQQPxKcyW/ZiAdZZZxjuSeG TJ/gVP0aAeH7TWiKxXd4YnT1am1mPKrKill2tCA/S1iKf524flYq7pSF+uIMRRN7 2by6ZbF/aVyu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcDCCBFigAwIBAgIMG53NoKG7INzWWM//MA0GCSqGSIb3DQEBCwUAMIGVMQsw CQYDVQQGEwJERTFFMEMGA1UEChM8VmVyZWluIHp1ciBGb2VyZGVydW5nIGVpbmVz IERldXRzY2hlbiBGb3JzY2h1bmdzbmV0emVzIGUuIFYuMRAwDgYDVQQLEwdERk4t UEtJMS0wKwYDVQQDEyRERk4tVmVyZWluIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IDIwHhcNMTYwNzA3MTI1MDI0WhcNMzEwMjIyMjM1OTU5WjBNMQswCQYDVQQGEwJE RTEhMB8GA1UECgwYUnVoci1Vbml2ZXJzaXRhZXQgQm9jaHVtMRswGQYDVQQDDBJS VUItQ2hpcGNhcmQgQ0EgRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDq7tdaUsUTPZzHRMMAuzUqMp2LuvfmYG0PRMnMEPFnBXWJq6XiXM6M0YOWqad4 Csw6KtiN/BDQ9wEvQihRSqyhqyJn7GO49oKkUHWX5kGzvDpHJ4+6auXTlqvWKv2j muTz4fEqodQ90Jmqo0pNLlIZjXZ9RtXCko+VXzk+vpjrME4/xVNfVkhYzLhYWd+Z 8aQ4yRWCvqqnz2VqHQp01lNSiYfVLV9jzQOnVB/cJ/kQab0jwDW3oMuyoiUziHwL dvE0RtJu/TJ8XXgMM23I+VvOhQoqgp+SHx7Syus9Ztezw/0QUqGVAmNsrAiuKjTn bJwdDFhHhOzY34ksyWrl5UDtAgMBAAGjggIFMIICATASBgNVHRMBAf8ECDAGAQH/ AgEBMA4GA1UdDwEB/wQEAwIBBjApBgNVHSAEIjAgMA0GCysGAQQBga0hgiweMA8G DSsGAQQBga0hgiwBAQQwHQYDVR0OBBYEFOnXJ6Mspcahk2fNOtVQdkg0wsBmMB8G A1UdIwQYMBaAFJPj2DIm2tXxSqWRSuDqS+KiDM/hMIGPBgNVHR8EgYcwgYQwQKA+ oDyGOmh0dHA6Ly9jZHAxLnBjYS5kZm4uZGUvZ2xvYmFsLXJvb3QtZzItY2EvcHVi L2NybC9jYWNybC5jcmwwQKA+oDyGOmh0dHA6Ly9jZHAyLnBjYS5kZm4uZGUvZ2xv YmFsLXJvb3QtZzItY2EvcHViL2NybC9jYWNybC5jcmwwgd0GCCsGAQUFBwEBBIHQ MIHNMDMGCCsGAQUFBzABhidodHRwOi8vb2NzcC5wY2EuZGZuLmRlL09DU1AtU2Vy dmVyL09DU1AwSgYIKwYBBQUHMAKGPmh0dHA6Ly9jZHAxLnBjYS5kZm4uZGUvZ2xv YmFsLXJvb3QtZzItY2EvcHViL2NhY2VydC9jYWNlcnQuY3J0MEoGCCsGAQUFBzAC hj5odHRwOi8vY2RwMi5wY2EuZGZuLmRlL2dsb2JhbC1yb290LWcyLWNhL3B1Yi9j YWNlcnQvY2FjZXJ0LmNydDANBgkqhkiG9w0BAQsFAAOCAQEAKdi4J+Hk39theEHM Ye1zWcYoNk4JNIr7HDxMwA8w1sYxETxhbCzOYG/aNpgqaEBjaroHbQgyWlbrTx8e DAtSX5HwqfvPS+sCiBLqvXeAXIewQMM86UynG0GvPPOGOc/bMx2toZYYP/2/SGd4 C/TCtTlGAV/AINXFKzvv/hwePqc3wML+R1LF7dO0U2uxsZ/yhykRAXKPiv3nES9Y ZEu3rJsjrs9Y4m093+sF0MKqUbiZdOpQzIfDQXI2djSucblxBinuA5lHVjnMgPc/ g4jQLSaRsdHJSc1ZH0PL9Xzz31MQwBQQtWU5i/Km2X5GwVIhoiGJ/2WTAvHDXxS3 CDCTmQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpjCCA46gAwIBAgIQCxOqaybbtZYT5zagRFO4KDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNjA3MTIxMjI4MDhaFw0yNjA3MTIxMjI4MDhaMF8xCzAJBgNVBAYTAlVT MSEwHwYDVQQKExhBYmJvdHQgTGFib3JhdG9yaWVzIEluYy4xLTArBgNVBAMTJEFi Ym90dCBMYWJvcmF0b3JpZXMgU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAOsYZNkCD3YspXjsl5BXaPGtVFtI7T3XDuQ5Z0Fb Mxy2bI+UN2FsRpCV9zs6AwMos/LfZidFbL+kDWlUEsji+kcs3vgsoUpFeYB+9/1z XzkmWYYpzl+869xevpoKGYBcma5FWrjWCQXJmtJ9BHg+qafzGppOuxi7F5lH7+wk Il5mz2MfxY8XTk69xEtwB/WGcAeSXfG6c+qq0wOfIHYYwB72owUALgB7GOrfEu2k di3qhzLbJZ2mF4eVza20txyLlblt4C/QNS8PkATm6QqbY8UR7r094Wr/9ZcnIkv0 Mf7hSiiqI6OfNG1iWJen0px/0rpq0J4Zs1Gftw4wXNt83MECAwEAAaOCAVowggFW MB0GA1UdDgQWBBSgJWm6Mhw8j+ChXo2r5NqwrTIlOzAfBgNVHSMEGDAWgBQD3lA1 VtFMu2bwo+IbG8OXsj3RVTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQE AwIBhjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp Z2ljZXJ0LmNvbTB7BgNVHR8EdDByMDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2Vy dC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMDegNaAzhjFodHRwOi8vY3Js NC5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMD0GA1UdIAQ2 MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j b20vQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQDb6jnKvBVLvBxAtWLDjfeC4XmRj1wF yuCwLxjZ8AYBurQnShWYYaDQuDx3JJAu0PXqLxIVntIaKNszVNOzqGOt/MuGxSS/ iDXTBMwDBPhVcVKaClOQXTAxKNIxMuS43gupyBsynGpOJ9W28PgCCVlJgI6fOlKR s8sWqiO7FEPc8TRCGie9HghDEHXr8pZxvPqABtaT0jE3uea9I5yXJ37ghwbdDKaD Z+uNzEApHNALtj2vDYIjybeOQJl0FhGOtTseD4pePjVoJVbBZmOSpYqc4gU1K0FA jjcorQXolJqnIlrbNdVbchETS/S7yXIiKl2N5n30Dxo9fUFNgstSc+CZ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEjDCCA3SgAwIBAgIQCaW/BJJxwqNC7pChvyBVbjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNjA3MTIxMjI4MjhaFw0yNjA3MTIxMjI4MjhaMEUxCzAJBgNVBAYTAlVT MRwwGgYDVQQKExNDaXNjbyBTeXN0ZW1zLCBJbmMuMRgwFgYDVQQDEw9DaXNjbyBN ZXJha2kgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD5zj/Lmt79 uZVU+7h4bQMbAdKfKogEwYIVTqgsJbvVKRsUv66DqSW8Yi4E42gKw7gCAsO7XVrw YmS8P2Cu8rnyKNF+MnF6Mp0b0+bPWvxE2C9uVpToIhb8ro2i84DO27B8OYE7MRtf J5gooqV5seJtNpCTujWcU8emxHWQIYxkIcwQwajngEEAkrjQRyb45HRTWnNto2KO QCKbjaKAjkiJ99oFulujtNmLLSsYr04iCCMN3lCah564jlj9YcmM2L12I0a2cbgz +XfOTNM2kKcH146xZfnMrQLSi3cP8IYSKmg5NIIdG+DyJVoQvg0og/G98FG99I79 mMZoEjOJ1kz3AgMBAAGjggFaMIIBVjAdBgNVHQ4EFgQUY2GVVXb0FBalNOOwPXMQ N/zKg40wHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwEgYDVR0TAQH/ BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEEKDAmMCQGCCsG AQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wewYDVR0fBHQwcjA3oDWg M4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENB LmNybDA3oDWgM4YxaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xv YmFsUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEA kw+KKqwWKJXLD/SDaElw8neXB2sdB41k+TlUw9f0AGpP41C7fqLpAaf1rBOtnhnu gd2kPeIQPRGc2VNBSwTsJ6GkydGiEh6ULhhiSsiQ00+iUjyRigCXpkchPyeaeMCp Sx+IKOm/W7z4rBgdZY+kxN53Fj0k6cI7nTtFRXsiNdo6iAjwbaRM0x02DXwct79z cdz//q87XL2O4rvlByaWyIgSJiavbG4bZv3mP0HQY+B7cDi3l+/6yvOFTK1CTp98 3RYh+rV+TAaAkT9bkql0yIIXlHcVI+pxaMu/6Plm6Izhe+ABgh/ANq8vmqVHbx7c 82QEPYp4t5pNu/7WkJ060w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGdTCCBV2gAwIBAgIQBOmcO+o168nJMRW7WHP3aTANBgkqhkiG9w0BAQsFADCB ijELMAkGA1UEBhMCVVMxGjAYBgNVBAoTEU9yaW9uIEhlYWx0aCBJbmMuMS0wKwYD VQQLEyRPcmlvbiBIZWFsdGggRGlyZWN0IFNlY3VyZSBNZXNzYWdpbmcxMDAuBgNV BAMTJ09yaW9uIEhlYWx0aCBEaXJlY3QgU2VjdXJlIE1lc3NhZ2luZyBDQTAeFw0x NjA3MTIxMjI4MzdaFw0yNjA3MTIxMjI4MzdaMIGHMQswCQYDVQQGEwJVUzEyMDAG A1UEChMpQ2FsaWZvcm5pYSBJbnRlZ3JhdGVkIERhdGEgRXhjaGFuZ2UsIEluYy4x LTArBgNVBAsTJE9yaW9uIEhlYWx0aCBEaXJlY3QgU2VjdXJlIE1lc3NhZ2luZzEV MBMGA1UEAxMMQ2FsIElOREVYIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAyPJ/Sb3ZIQ5jTvsNpkE4I8x1rHilh/qzuKGvJrKkzf/60LtUfj294zXk iF7wkf9YUzlUueB1Ow3HBkMfyVxI5mEnD3niLBCMtoYNu/BZH0qLb3AIy9yP1U0I ZiTX8fKpAio3mk9v6XqhRfNR4YQM5MNS+jwLnY/f2iE6IebZ6fG47avU5t8b3Fpn zQ6j64wIbs06pJdySswqRabGPPA3pqbCzpHcDy9AwP5mWCQf57/4cvnU1yKhJ2TS 5zyrwXm2/Bpc2pQkPG1xCmzgueMxeXqiAC1u60FMr4sAGqBOh1kjK1zLVe2bRzlu T931pBNx5gyesVvaTOoTOgUTz+ZnxQIDAQABo4IC1jCCAtIwHQYDVR0OBBYEFIpx MDDBlQfnMxiH0RdWVkh4lOYIMB8GA1UdIwQYMBaAFKVuIv85aToj+4kkF8ZglAAa 2o6eMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMHoGCCsGAQUF BwEBBG4wbDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEQG CCsGAQUFBzAChjhodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vYWlhT3Jpb25I ZWFsdGhJc3N1aW5nQ0FzLnA3YzCBmQYDVR0fBIGRMIGOMEWgQ6BBhj9odHRwOi8v Y3JsNC5kaWdpY2VydC5jb20vT3Jpb25IZWFsdGhEaXJlY3RTZWN1cmVNZXNzYWdp bmdDQS5jcmwwRaBDoEGGP2h0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9Pcmlvbkhl YWx0aERpcmVjdFNlY3VyZU1lc3NhZ2luZ0NBLmNybDCCAVIGA1UdIASCAUkwggFF MDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl cnQuY29tL0NQUzAMBgpghkgBhv1sBAEBMAwGCmCGSAGG/WwEAQIwCwYJYIZIAYb9 bAQCMAwGCmCGSAGG/WwEAwIwDAYKYIZIAYb9bAQEAjAOBgxghkgBhvlbA4ohAAEw DAYKKwYBBAGCwVsAATAMBgorBgEEAYLBWwEBMAwGCisGAQQBgsFbAQIwDAYKKwYB BAGCwVsBAzAMBgorBgEEAYLBWwEEMAwGCisGAQQBgsFbAgEwDAYKKwYBBAGCwVsC AjAMBgorBgEEAYLBWwIDMAwGCisGAQQBgsFbAgQwDAYKKwYBBAGCwVsDATAMBgor BgEEAYLBWwMCMAwGCisGAQQBgsFbAwMwDAYKKwYBBAGCwVsDBDANBgkqhkiG9w0B AQsFAAOCAQEAqakDhBps4qi1PVvcxDW/ord53ouieZwBiyiRvQTAv855uIaTIuMm gFwpomCawvBPUDKxM2q0w675VZ4lPPG682WlKCIX6yK8XUAIAkBTfP3cGxrHfV5w 0shrzJ/scc2Hhn2SY77LSI1jKqSgoXu5Qb5b/6ehGm9gmmS2wYQCD0RFHKFBZzoU 5xJTrewS0q9Ip39l4oF+bEvcazWTQwYLdYFv9f0jZzNte52fc2J71vfCBH0/FqdL QK5VL7a8GBFxF8zKybb50q1c5X+nyZDpculqUPcE2YdJPTieIuBE6j617oQw4Vdz 3mYUu4rlnAqddyronHRmLVgcb6KPdjn5kw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFZTCCBE2gAwIBAgIQOhAOfxCeGsWcxf/2QNXkQjANBgkqhkiG9w0BAQsFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMTYwODExMDAwMDAwWhcNMjYwODEwMjM1OTU5WjCBlzEL MAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIElu Yy4xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxHTAbBgNVBAsTFERv bWFpbiBWYWxpZGF0ZWQgU1NMMSEwHwYDVQQDExhUcnVzdEFzaWEgRFYgU1NMIENB IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC39aSJZG/97x3a 6Qmuc9+MubagegRAVUmFYHTYTs8IKB2pM7wXN7W8mekdZaEgUjDFxvRBK/DhTb7U 8ONLsKKdT86aOhzbz2noCTn9wPWnGwkg+/4YKg/dPQQdV9tMsSu0cwqInWHxSAkm AI1hYFC9D7Sf7Hp/5cRcD+dK454YMRzNOGLQnCVI8JEqrz6o9SOvQNTqTcfqt6DC 0UlXG+MPD1eNPjlzf1Vwaab+VSTgySoC+Ikbq2VsdykeOiGXW/OIiASH7+2LcR05 PmQ7GEOlM8yzoVojFpM8sHz+WxI05ZOPri5+vX3HhHHjWr5432G0dVmgohnZvlVZ oy8XrlbpAgMBAAGjggF2MIIBcjASBgNVHRMBAf8ECDAGAQH/AgEAMC8GA1UdHwQo MCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNvbS9wY2EzLWc1LmNybDAOBgNVHQ8B Af8EBAMCAQYwLgYIKwYBBQUHAQEEIjAgMB4GCCsGAQUFBzABhhJodHRwOi8vcy5z eW1jZC5jb20wYQYDVR0gBFowWDBWBgZngQwBAgEwTDAjBggrBgEFBQcCARYXaHR0 cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGRoXaHR0cHM6Ly9kLnN5 bWNiLmNvbS9ycGEwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCkGA1Ud EQQiMCCkHjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0yLTYwMTAdBgNVHQ4EFgQU bVjHfxrn4T8upoyXNUK79NM4rD8wHwYDVR0jBBgwFoAUf9Nlp8Ld7LvwMAnzQzn6 Aq8zMTMwDQYJKoZIhvcNAQELBQADggEBABUphhBbeG7scE3EveIN0dOjXPgwgQi8 I2ZAKYm6DawoGz1lEJVdvFmkyMbP973X80b7mKmn0nNbe1kjA4M0O0hHaMM1ZaEv 7e9vHEAoGyysMO6HzPWYMkyNxcCV7Nos2Uv4RvLDpQHh7P4Kt6fUU13ipcynrtQD 1lFUM0yoTzwwFsPu3Pk+94hL58ErqwqJQwxoHMgLIQeMVHeNKcWFy1bddSbIbCWU Zs6cMxhrra062ZCpDCbxyEaFNGAtYQMqNz55Z/14XgSUONZ/cJTns6QKhpcgTOwB fnNzRnk+aWreP7osKhXlz4zs+llP7goBDKFOMMtoEXx3YjJCKgpqmBU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFXzCCBEegAwIBAgIQFcILcawsNlJ6B2Z9hxvG2DANBgkqhkiG9w0BAQsFADCB vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0xNjA4MTEwMDAwMDBaFw0yNjA4MTAyMzU5NTlaMIGXMQswCQYDVQQGEwJDTjEl MCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEfMB0GA1UECxMW U3ltYW50ZWMgVHJ1c3QgTmV0d29yazEdMBsGA1UECxMURG9tYWluIFZhbGlkYXRl ZCBTU0wxITAfBgNVBAMTGFRydXN0QXNpYSBEViBTU0wgQ0EgLSBHNjCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6PcUG/2YcVEtzwDU9yj/F5Ed4M5LBW 8ln6HwMRuXuDgKIz6t6OBeF7tqaZPwZ8NRgwwhtEcnyeuDPjS/HYvQqEZZWQpnut njNGniplXkOngD48f0Bhdo5Rwtqv13UiV59gfP/PSy81atddMqgtt5WeITaseddh 4sVZV0bj2b37lJ0w/2TRm+gzIp12lzliIkZr9OdgAKRWpITs0TtU0jJq6gXR5fe7 aut4GOVov5SZHJorXJSTkhdEIyoYWgUxNAIu83Ykw91/bjeXKFVvq8+tZZN3ct5F I7qbHRgcrLqRdZQPkKjQWC9hXFrQVZUSwRMjRN2O3TXvmtprFr4od+0CAwEAAaOC AX0wggF5MBIGA1UdEwEB/wQIMAYBAf8CAQAwNgYDVR0fBC8wLTAroCmgJ4YlaHR0 cDovL3Muc3ltY2IuY29tL3VuaXZlcnNhbC1yb290LmNybDAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwDgYDVR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEBBCIw IDAeBggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMGEGA1UdIARaMFgwVgYG Z4EMAQIBMEwwIwYIKwYBBQUHAgEWF2h0dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUG CCsGAQUFBwICMBkaF2h0dHBzOi8vZC5zeW1jYi5jb20vcnBhMCkGA1UdEQQiMCCk HjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0yLTYwMjAdBgNVHQ4EFgQU3qQwrOQ/ 9ScrMXyvkGcdriKe7GQwHwYDVR0jBBgwFoAUtnf6aUhHn1MS1cLqBzJ2B9GXBxkw DQYJKoZIhvcNAQELBQADggEBAMS+q79V8jm2p5T8pdMCS8XuYjCVpsJuXh4QqegO Ors1D4nVEE0Thm7V6fy60UgOxsjXayauQonRoCdApv6bziW9USmUK2qQ5xFsgBBD LzwJnQd7FDUW9ngDNCo/377J2CLqiVsYFqNnpuVzbbWF/6UR+AxGwFzzAgx9QOLP Qucpx6kV+d0Ht2cm/+mwGlzmdr/RwcT5iLW0oAQZkcfzbi+s9bBaIprMOCiyvO/F Gf1YDO4KQHMfda+GO6HpmPl8nDFgP17Bi3QgRjr1kjpZ9WvnPQha1wZLel+VGm/e xOXNrbei6P5U58U0Hy3GsO5r/IxRE5k55tR5o5E2EB0ilSg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFBDCCA+ygAwIBAgIOSETc1VvQKA4Lb2oRaIEwDQYJKoZIhvcNAQELBQAwYzEL MAkGA1UEBhMCQkUxFTATBgNVBAsTDFRydXN0ZWQgUm9vdDEZMBcGA1UEChMQR2xv YmFsU2lnbiBudi1zYTEiMCAGA1UEAxMZVHJ1c3RlZCBSb290IENBIFNIQTI1NiBH MjAeFw0xNjA4MTcwMDAwMDBaFw0yNjA4MTcwMDAwMDBaMGgxCzAJBgNVBAYTAklM MREwDwYDVQQIEwhUZWwgQXZpdjEXMBUGA1UEBxMOVGVsIEF2aXYtSmFmZmExFTAT BgNVBAoTDEJlYW1lLmlvIEx0ZDEWMBQGA1UEAxMNQmVhbWUuaW8gQ0EgMjCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANYxDx4s9D2TDkzyOF8y1FqRTt3u owDUXAzbxvpAfcYK5+QEdkit0VRhHIHvvbd+tuU8B0fQ55J/jvkS0q0E2xoZI2Qd RuJpTYVomRmyVlvjjJVF2uFiQCTLO7YPXdVx1SQpPd87b51SWP8pGHxj3JiIzB9V A1MV/EI/QruuIUl6a47FCaRXOxTqCVVGcK1yVNZ0kVzkWgK7m7FZBXUX8i+nB3Eu rUGSkwK7a93BW5Pdia0VEkvIumZaagikVPhHIYpvvpnV8gaSTC7Z1FGz+TAtcbuZ a8QwSPpTtS9shVyEyaGAvC/fWANpjNsjEP8FMmLgzgFH1akSX+DbH1lPkh0CAwEA AaOCAa8wggGrMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUjtzM1mWQfqg4 X+TeAz0HG8wV8IUwHwYDVR0jBBgwFoAUyGObCGlUwpjI2c3jM7dQXvjJAZswgY0G CCsGAQUFBwEBBIGAMH4wNwYIKwYBBQUHMAGGK2h0dHA6Ly9vY3NwMi5nbG9iYWxz aWduLmNvbS90cnVzdHJvb3RzaGEyZzIwQwYIKwYBBQUHMAKGN2h0dHA6Ly9zZWN1 cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3RydXN0cm9vdHNoYTJnMi5jcnQwPgYD VR0fBDcwNTAzoDGgL4YtaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS90cnVzdHJv b3RzaGEyZzIuY3JsMFYGA1UdIARPME0wCAYGZ4EMAQICMEEGCSsGAQQBoDIBFDA0 MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0 b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAVghgTClfJqshfcCa7nFZfcZcHLa4U6Fy tOnsoIuKINuSP02oTSqHcy3nw6+QNS2pIuUIQF6Ok3qiN8YJsH9u/UaICD3LHsMg WG5na32LBnHaOJeir2dzz78cAUwYukOyUyYEY1WpbfkZO3rEuW05j9uD7S/bwAz0 Tlm7GYdDCcdmLJWnhDbHb5WoOHMEahbPG3S9GPP08E3gTRDJVe5iEoeGQIc1RK8E EhW2PzYGu6knCIUHerDdgN2vUOx2fD9HPAiKlnqnHwezZqefIH3N/yTweohAuMnG ODVdAh2Qun2nqlnCv4LQgcfVxchfTstivEpiOaBquiz+r+g1W7joVQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8DCCA9igAwIBAgIQCkWP1jUP2kJIgVpgCrPMnDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNjA4MjMxMjQ5MzhaFw0yNjA4MjMxMjQ5MzhaMGcxCzAJBgNVBAYTAlVT MSEwHwYDVQQKExhBYmJvdHQgTGFib3JhdG9yaWVzIEluYy4xNTAzBgNVBAMTLEFi Ym90dCBMYWJvcmF0b3JpZXMgU2VjdXJlIEF1dGhlbnRpY2F0aW9uIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwz0g98P3Yadw20QCWIp9MTLdsQBD 1AB6ClyR70MTA/MVve5Jv62CN6EH7MbfnXjgl+daO95waXFgQb3leiUnnAh1ouiW pOmFrvuipifneOp+1Te3IpnS1sW5fX9H59Y6Ebslko4kNxBivS1MgRa6sEtzEjIG F5P6ZO49E2A7VaiVfen5J10ZYnb0sttAKdp0CBOX7yqrD75eiVFXUIVJvp3YUEH4 TK50roqHCfb9Sex04Em/tNv00mVMSO1Wc4wrF61MrEPcOaBTBvysF2QFxWdKT9v8 EbbWmAsyvm1dXEPNUyaMfenKtVIQI50YB0N8d3arDjPExrT+8GItNlNAPwIDAQAB o4IBnDCCAZgwHQYDVR0OBBYEFFwViJBtJSLzzxItbmEhzgeWskAGMB8GA1UdIwQY MBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYD VR0PAQH/BAQDAgGGMHYGCCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDov L29jc3AuZGlnaWNlcnQuY29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5k aWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3J0MHsGA1UdHwR0MHIw N6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJv b3RDQS5jcmwwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy dEdsb2JhbFJvb3RDQS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQAD ggEBAHywyzOoZ7TD5HzcZbUkSAjSeFPaUDE1SXE8cfjN6bS3Uc4OulRQh05Lzaml PuHfOT43B5rhDbhHpZzDJGIRuhaLCdLSW1PmObrSSjLZUq4LYw34HT198K0WibJJ j8SHdw1LfDXZOMLTI6LY78es6NbgkAqMLq91uzoV/TCzkktuFSeM+vf5Riw4aog0 cK5GUja2+petzhwALsW/6MSbU2EH/PfwM8zJEBiBJar+O7N33jEygoEDNyjVHJ/I VL/5UKVXum20rD6AbjYNzcA5LsaRM6UQZycCfsA3KeEh9ko//AfSbC2Bmx7+qCUs 7wCUJTqOaZDjUukXXhYpsJtRt/o= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHRjCCBi6gAwIBAgINAI+BbtVRyZJO14+xCjANBgkqhkiG9w0BAQsFADCBgjEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMScwJQYDVQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkx HzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMTYwODI5MDIwMDAw WhcNMjkxMjI5MjAwMDAwWjB8MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBl c3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xHDAaBgNVBGEME1ZBVEhVLTIzNTg0 NDk3LTItNDExJDAiBgNVBAMMG09ubGluZSBlLVN6aWdubyBTU0wgQ0EgMjAxNjCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIhNFrNXAnBScDoQE0hY/e/a tUt3FMpH/rQp/nJMSJNGjYZlCbTyhF7R1SPx0gOtwXSp2nFKiALLkkI/G0i2LZ7J 3d0bGBI6ZcPbPm3NGgOanuol63Mp//gzIT1ZuNKVW4csWKEg5yMEMIdYzy1iD53U r//66Xhk55He6FIgXYqNqA43rolqfmbaWKCsKFopWysNQWXExy4uRNV6T7gTY0t8 fnGd2mUXKAascoNCD9vONaAlhf3C4Wz0oC1aD5PqKH3S2pQJLuke7TdSQYHxFmBF jVHZbguuJkq7wMlJSm9RKeeF7oH3VL/Gu4HcDIx2DtgJSwwzB3TsZO560aAtcoQx 3LOcuRo4sMt3VrcIr/HPWuScOyKcCN0MqEUgfsl+NfGMNm32wk5+mSEgtw93EG9T VM+SJI9UuRuRd5r3dWY7Iee3Nr8S+jmoHQVMXFeffgIfmHxdyW4XxCuNT1LRO6o2 aCRsDo6DHjNLSNTA03NcKTJvp1C+O7iq2B1jhIWS+DFdh48xH6DKonjEqdi94qjv qLcz/O4mhqByqv/EB3PXUMJ5TmQFY4bXMfXfhE0bOtlpsAJvlb6g+LKD0lT4lhjH 1FIaYIAm2Adzr25pxf7lo0jswu8tmGV50m9morYZJ4G5+5bZoOOuum91CC/vLjOu mjzUCwpHckCG2wsUOB91AgMBAAGjggK+MIICujAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYa aHR0cDovL2NwLmUtc3ppZ25vLmh1L2FjcHMwHQYDVR0OBBYEFJNwk5Vj/7E0Aq92 mxAaFNjv4tv8MB8GA1UdIwQYMBaAFMsPxt9CQ8w9y7VII6EaeqYquzRoMIG2BgNV HR8Ega4wgaswN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNybDEuZS1zemlnbm8u aHUvcm9vdGNhMjAwOS5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNybDIu ZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2Ey MDA5LWNybDMuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcmwwggFfBggrBgEFBQcB AQSCAVEwggFNMC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAwOS1vY3NwMS5l LXN6aWduby5odTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMDktb2NzcDIu ZS1zemlnbm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDA5LW9jc3Az LmUtc3ppZ25vLmh1MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAwOS1jYTEu ZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9y b290Y2EyMDA5LWNhMi5lLXN6aWduby5odS9yb290Y2EyMDA5LmNydDA8BggrBgEF BQcwAoYwaHR0cDovL3Jvb3RjYTIwMDktY2EzLmUtc3ppZ25vLmh1L3Jvb3RjYTIw MDkuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQBUP2Z9eLSODxVVS7j89wOxJBOwe3f/ 9iqhmnWCQbQ7ktEX87Me9PT8MQgrAS57TBDdnc37hdCpXcbT+SvhaxVFoCxTxa6S 3WK2xBWsLQqVzjLaPPjaHTOC8lBguUZaBA4Gx3XMQWGiKhedNXkdSRd5o7QnQ6Cc 33VnxmKj7qHkJDoKqPUJqprFYxogyFJ7HVwyPxxU9WZZX5fdLeXeZNTOAVnxnb2x 9U8I4u+O+Y5K2B/6oAy2+G9IwpuDjxcqV65jSGFxyZs9mmUxyTrD0IXdkfl+hayQ BqCXgDhsAl47JGi3EcfjBLwbkZ82jREllH8XGla9jYhcErbLiltP/Zl/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHRjCCBi6gAwIBAgINAI5fRu8exOEPyggWCjANBgkqhkiG9w0BAQsFADCBgjEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMScwJQYDVQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkx HzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMTYwODI5MDIwMDAw WhcNMjkxMjI5MjAwMDAwWjB8MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBl c3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xHDAaBgNVBGEME1ZBVEhVLTIzNTg0 NDk3LTItNDExJDAiBgNVBAMMG0NsYXNzMiBlLVN6aWdubyBTU0wgQ0EgMjAxNjCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK02eJ7dzwuDzRpqee7eEFOi r6UH89xkXEb/n38YGAYpXYMLezDUmkoWEWOuJdOO5ThYEb3miVAdbm6wWKSLKJSo 6JwX3FS7r5WLkkFDKCUGMmVqzHfLQ0CnmH2SW4F1j5SeFIzpUV2SjlLXSnSr+ddi 2vyCYm08QFj8MMjeSIA92mMPrQBIF9CJuBVpzeq7HMO9CxzHgzCTKgI6qb/DbFBf KPBV4LWRxLiyzvirDKszCufLf36dLTm4Dje/Qs2/MvI4UsvZB662RYIeQggC6aIx jt6NooL20/b2TotRE0lC44P6V4H0njmHVhKJ6dB06w6n6qLmNv6+S6EATzaBNVl8 rCkFOAwvNU0uNDamt+hi3nXS7kxNv1Li3gi+MNF13+UtwVudxZlkmHb/vUvpLNJ8 TfB9Doe2XpoUrevt7wsszs178+XTv4c6Gyg4tgwOb9QNuzKWNXTlF7B6/jotGoL2 tD/8SRj1selkJAiIHdHX6M0D6MYMtjGI4te4gL+NjhG2gAykR7ycpy4eS+DquEn2 6HTy6VfsTgFoThHIlWGjOI3tO7q3wCKFa0X/u1a4nty+dPooJBvEsrhdvGjoWY0x bRm80ZXFRwbNGYXn3SK2BlQEkR3Q3Xq1fiyyZEVWgqOIQY5GxUh+/NtcH3cHcvD6 oLR9Ao7BbmhXnf5RVBLzAgMBAAGjggK+MIICujAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYa aHR0cDovL2NwLmUtc3ppZ25vLmh1L2FjcHMwHQYDVR0OBBYEFGbBftlD0CJCtL6W eJacTkR2FFtMMB8GA1UdIwQYMBaAFMsPxt9CQ8w9y7VII6EaeqYquzRoMIG2BgNV HR8Ega4wgaswN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNybDEuZS1zemlnbm8u aHUvcm9vdGNhMjAwOS5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNybDIu ZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2Ey MDA5LWNybDMuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcmwwggFfBggrBgEFBQcB AQSCAVEwggFNMC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAwOS1vY3NwMS5l LXN6aWduby5odTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMDktb2NzcDIu ZS1zemlnbm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDA5LW9jc3Az LmUtc3ppZ25vLmh1MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAwOS1jYTEu ZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9y b290Y2EyMDA5LWNhMi5lLXN6aWduby5odS9yb290Y2EyMDA5LmNydDA8BggrBgEF BQcwAoYwaHR0cDovL3Jvb3RjYTIwMDktY2EzLmUtc3ppZ25vLmh1L3Jvb3RjYTIw MDkuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQBTeghijPntCnam9WIq3IqUXw3zEcqj dxl9yK+J/HxlGm8VmMytaKULR4uF4mQdv4adqYXyun8mUZdWOJh+I2S9dzAAU6cf gKw+oM5yPWnSNsbCICI1/uyEF/fodir3aLsfqycPJXXWKSjymq+lij9/xObwd+Oh BZoP5PWp9FaxdLQ1BhmhN6C9m7IWkcPGWo46L6Dmk5pRMDqU9lqxCMvA+qvZXnuP +r1m0hpeJlDyccoJMevjEWdb/xympIjpLZbj+FxRnxFFYB2dRlNYcG2/tPOi9LQ3 bifXaHTjqmOtid/5yB+RCW8HYAEfQhSmRlHtAytAQXH7o3qhXJsdobJE -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHUzCCBjugAwIBAgINAJAnSYTL8NLZr6/zCjANBgkqhkiG9w0BAQsFADCBgjEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMScwJQYDVQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkx HzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMTYwODI5MDIwMDAw WhcNMjkxMjI5MjAwMDAwWjCBiDELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFw ZXN0MRYwFAYDVQQKDA1NaWNyb3NlYyBMdGQuMRwwGgYDVQRhDBNWQVRIVS0yMzU4 NDQ5Ny0yLTQxMTAwLgYDVQQDDCdRdWFsaWZpZWQgZS1Temlnbm8gT3JnYW5pemF0 aW9uIENBIDIwMTYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDnYM62 VkK02hmttEVk8BTm2zaUKuD5TGUyNtmunoj9SNRHaHWfDIE0voHnOfVKImEz4ks4 l20fUP73OwgwIHnjPkYKi8sXExuH1wLD3d/hVM+KmBbS5cpTeB7f0YyJxw02Cj3N ApgI3320lzFZNrYg0+m7zCKarMMCY4eL+llS4MLiNnH00Bqe/IvpKzt5T6wlqP5U C3ttVRpkFzjX/Ao93x1m6+iOxntnXsFtTGiLN/ZtJTqThWuupYFuaFc2qAZfytXG SrBCUpZTrqgE7KvHyXGn7mQGoGVWtTCSdOxqOy3eLWJzHZ/6rzalRwyD1rUq5yIY SrUqwpnD8l4z/4WYq2j2zk6hRQP7FgLLakx8xcdLMb4zpCzyt2vy4k+8Jo7QghE/ d45o5lcEChIvHKimu30IgePzcwaC23Zjd2pI/5oZRtybio1+ZWIyWFseRPNLQh0H TJa3+jsOhAbBc91qwLPo7x0dv61GgPilrc3F+KCeduBplt983T750f3VYMqcOW6n LNdds5mM208i/ODmTBvaHVWotJdTQxQ7OI94A2e9T0S2pwDr4O0w7cfNsXVw2NLb fmc0As4Bufjua01mKPDitcJDktM88FI1pbUrSmm2z6vwli1StZUtQ75b+2friKzn ftsPfRv5EqC5r2Wr8BxwlmrT5UL7djfZ1rBIJwIDAQABo4ICvjCCArowDwYDVR0T AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwOwYDVR0gBDQwMjAwBgRVHSAAMCgw JgYIKwYBBQUHAgEWGmh0dHA6Ly9jcC5lLXN6aWduby5odS9hY3BzMB0GA1UdDgQW BBSxGI+yuTjSnmc3e3gVWTuv+gAXsjAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOh GnqmKrs0aDCBtgYDVR0fBIGuMIGrMDegNaAzhjFodHRwOi8vcm9vdGNhMjAwOS1j cmwxLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3JsMDegNaAzhjFodHRwOi8vcm9v dGNhMjAwOS1jcmwyLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3JsMDegNaAzhjFo dHRwOi8vcm9vdGNhMjAwOS1jcmwzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3Js MIIBXwYIKwYBBQUHAQEEggFRMIIBTTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3Rj YTIwMDktb2NzcDEuZS1zemlnbm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290 Y2EyMDA5LW9jc3AyLmUtc3ppZ25vLmh1MC8GCCsGAQUFBzABhiNodHRwOi8vcm9v dGNhMjAwOS1vY3NwMy5lLXN6aWduby5odTA8BggrBgEFBQcwAoYwaHR0cDovL3Jv b3RjYTIwMDktY2ExLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3J0MDwGCCsGAQUF BzAChjBodHRwOi8vcm9vdGNhMjAwOS1jYTIuZS1zemlnbm8uaHUvcm9vdGNhMjAw OS5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2EyMDA5LWNhMy5lLXN6aWdu by5odS9yb290Y2EyMDA5LmNydDANBgkqhkiG9w0BAQsFAAOCAQEAxqY1rcxnTkQF U/sgEh4TE2rjdIHUS0hmVylcXiArtfS0RPlx+09BlRWHGB3kxb8sTcHqjnVyDyQE h31NLE7O8dfDKZ85vxZRRzd6eSNKRhm0vyxo7JSW0HfbCcliuq2a4DkxhaczAc1x C23j58U983V5gw9uIRKe/XISRD7JzRjriPg1V6ywgHVdSI6RJ0djrwO49m1c51lm EPVb9U0ibH6HZc+oTX3XloUMLkHKOkqnrAhD8R+OmlMJ+c+hKUfUUY1lb9RJYSHJ /hqiqyHM3uE4Ek1Bc12lApR5e+LbMrSqxnSdfNaPjn9BuFcnlkI04N7PnKftuf5T 8Ow2sbss1A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHWTCCBkGgAwIBAgINAI2N0iHu0lNbhD4eCjANBgkqhkiG9w0BAQsFADCBgjEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMScwJQYDVQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkx HzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMTYwODI5MDIwMDAw WhcNMjkxMjI5MjAwMDAwWjCBjjELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFw ZXN0MRYwFAYDVQQKDA1NaWNyb3NlYyBMdGQuMRwwGgYDVQRhDBNWQVRIVS0yMzU4 NDQ5Ny0yLTQxMTYwNAYDVQQDDC1BZHZhbmNlZCBDb2RlIFNpZ25pbmcgQ2xhc3My IGUtU3ppZ25vIENBIDIwMTYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQDP0wXIoXMFKapJoP+KpEbAZLe+YcHB5OS+kJovgjFXHzKAUYILvCZlHQ6ZpgEE MRj/x4KD407kgZytnG7Ni8Bp9YxWRlFGlz7fRWMW4wWYyIhJmXAXeyTPSdcmI8/Z 2rgB+ZNyds31ODpg5Wem5SyEpbvVv+GoTx1Gjn2FQ1mhMkI9J1eReOcfZOqGZV1Z 0okXjaw3eCnt6o+U/7KlSCK5OLRwnm53WOXw1iqayjGDiBD8GmBKI0Hb4pk04EWE wVs4pXTI2c4qqims52FFQa6JhuvlyR3sGQXzx7tNGLsYBAaB5XPtmI2RpidYHgHz FDfKZiM5+GSaEHKEnlaI0R2IEkjzsh/QIndCaPQaryaP/Lxn/r3Yd9mMkTyww9kZ qFWYpyBotJTknfzsgW5ZhRaUuBwy3Q++QVdaf2CglHMUPwoG/AXWeu4zRf0NXj8h zTGZPwi4cfN6pVUjGwXNfRXPoyP2MLLI5+6I/lv23TBMBCtlajdiKEPIghb5QgUT ziprBwUDDHLVKlmRFyYCJJV2PyFotfTe0GVeWnkFLPRHMS+9YVK0cU5FminPCPyk K3UmIuv5nxgF2VOpljavX11nwAGKo2adV0izay1xvccRTf6grPkx/s03Suv4oFDB IENdYMlgqLeMI0gzt1vlD34h3hTk6LajjGqA/Kihn9k/9wIDAQABo4ICvjCCArow DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwOwYDVR0gBDQwMjAwBgRV HSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcC5lLXN6aWduby5odS9hY3BzMB0G A1UdDgQWBBTICZq+B0E4pSZo1jLAgg5K/+ZedDAfBgNVHSMEGDAWgBTLD8bfQkPM Pcu1SCOhGnqmKrs0aDCBtgYDVR0fBIGuMIGrMDegNaAzhjFodHRwOi8vcm9vdGNh MjAwOS1jcmwxLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3JsMDegNaAzhjFodHRw Oi8vcm9vdGNhMjAwOS1jcmwyLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3JsMDeg NaAzhjFodHRwOi8vcm9vdGNhMjAwOS1jcmwzLmUtc3ppZ25vLmh1L3Jvb3RjYTIw MDkuY3JsMIIBXwYIKwYBBQUHAQEEggFRMIIBTTAvBggrBgEFBQcwAYYjaHR0cDov L3Jvb3RjYTIwMDktb2NzcDEuZS1zemlnbm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6 Ly9yb290Y2EyMDA5LW9jc3AyLmUtc3ppZ25vLmh1MC8GCCsGAQUFBzABhiNodHRw Oi8vcm9vdGNhMjAwOS1vY3NwMy5lLXN6aWduby5odTA8BggrBgEFBQcwAoYwaHR0 cDovL3Jvb3RjYTIwMDktY2ExLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3J0MDwG CCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAwOS1jYTIuZS1zemlnbm8uaHUvcm9v dGNhMjAwOS5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2EyMDA5LWNhMy5l LXN6aWduby5odS9yb290Y2EyMDA5LmNydDANBgkqhkiG9w0BAQsFAAOCAQEAvLnM FIqdEbM2J1zfO/XaXJxjY7Uzg1QPfXdazoaOnDvx9rSc/QTALWDunn0ONN+E1gFA TfOlf437efEcYxY/kncwuXH5NrfhFAS7xRIjJ2lHJGa0VO7v1R7bDyA6pIOnnCdt fUCzcTaZ5g0tTFjZMaLhUgk/VsilspMDmPVFtfNlwCiIprmMfit7M2mcTpW9MB3H KJgpCwtYDtCkhr22UIqBPw2w5ykapFOuk+KYUXpMbfREvCjMEag/fi5lWVyGBcK6 1M7iTYBs2JUbygkI+JprYOIhIZjcHUeSxo7Bp2GFv1vUUuCYA8eTfN9C0Dux5oXB vnFB3RZCsrE6epGuKQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHuDCCBaCgAwIBAgIPWyQANk6dlfPocBGKvX0JMA0GCSqGSIb3DQEBCwUAMEkx CzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxIzAhBgNVBAMTGlN3 aXNzU2lnbiBQbGF0aW51bSBDQSAtIEcyMB4XDTE2MDkxMzA4NTE0MloXDTMxMDkx MDA4NTE0MlowVzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEx MC8GA1UEAxMoU3dpc3NTaWduIFF1YWxpZmllZCBQbGF0aW51bSBDQSBHMjIgMTYt MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKSt5TJWWDUKMIDdWaDS oATM+McP6v6FJ7UdtgZjdRCXRnQ8X7WxA66WIeHCn4Wiysf/Nbx7EYVwVKHchmlR xDqjfWkDtMWNb+pGV+FEgVZMTHejaMmJlzlLbvE1F7eIcTDhvSwaJAnfIfp95cLp IEZ6AYt6EKuvt9PaT5W+8vKZHNwHMA5kJ+N9O4QZgLqXho+pWtQx1n+D+ka2lDop eOpOxw/lCO+K3egVkeQ8xzAC9gmcCH7YHfd02nrYNqY6kp/k641rkFGnhAx7jz+y 1M14Drs8YP7GTgTG7r3D+5oZnSX/qOyK/aQ4wBaenIfgC1bjvSV8NStFpYM76SiP xRECAwEAAaOCA40wggOJMEUGA1UdEgQ+MDykOjA4MQswCQYDVQQGEwJDSDEpMCcG A1UEChMgWmVydEVTIFJlY29nbml0aW9uIEJvZHk6IEtQTUcgQUcwDgYDVR0PAQH/ BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFF0z8lExm+OK0Fjr t6nSi0sUAV8EMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0ZdHelarp35zMMIH/BgNV HR8EgfcwgfQwR6BFoEOGQWh0dHA6Ly9jcmwuc3dpc3NzaWduLm5ldC81MEFGQ0Mw Nzg3MTU0NzZGMzhDNUI0NjVEMURFOTVBQUU5REY5Q0NDMIGooIGloIGihoGfbGRh cDovL2RpcmVjdG9yeS5zd2lzc3NpZ24ubmV0L0NOPTUwQUZDQzA3ODcxNTQ3NkYz OEM1QjQ2NUQxREU5NUFBRTlERjlDQ0MlMkNPPVN3aXNzU2lnbiUyQ0M9Q0g/Y2Vy dGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3Ry aWJ1dGlvblBvaW50MIHgBgNVHSAEgdgwgdUwgdIGBFUdIAAwgckwSQYIKwYBBQUH AgEWPWh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vU3dpc3NTaWduLVBs YXRpbnVtLUNQLUNQUy5wZGYwfAYIKwYBBQUHAgIwcBpuVGhpcyBpcyBhIGNlcnRp ZmljYXRpb24gYXV0aG9yaXR5IHRoYXQgaXNzdWVzIHF1YWxpZmllZCBjZXJ0aWZp Y2F0ZXMgYWNjb3JkaW5nIHRvIFN3aXNzIGRpZ2l0YWwgc2lnbmF0dXJlIGxhdy4w gdIGCCsGAQUFBwEBBIHFMIHCMGQGCCsGAQUFBzAChlhodHRwOi8vc3dpc3NzaWdu Lm5ldC9jZ2ktYmluL2F1dGhvcml0eS9kb3dubG9hZC81MEFGQ0MwNzg3MTU0NzZG MzhDNUI0NjVEMURFOTVBQUU5REY5Q0NDMFoGCCsGAQUFBzABhk5odHRwOi8vcGxh dGludW0tZzIub2NzcC5zd2lzc3NpZ24ubmV0LzUwQUZDQzA3ODcxNTQ3NkYzOEM1 QjQ2NUQxREU5NUFBRTlERjlDQ0MwIgYIKwYBBQUHAQMEFjAUMAgGBgQAjkYBATAI BgYEAI5GAQQwDQYJKoZIhvcNAQELBQADggIBAJ3CXiaHty0ED3Qod7ELia8RSkGK +Z59rcZLI0eNLjJ1AJriZkQJDByq0BaIiwgXLSBWEQoBEZppP3E99suJqLnSU4Bl 9Zzhb66NwudQImPxPZYEfmHT4WGqU8kMENH0X5KaHZ1RlmxRZto4TnVl5O2BaOAJ Jpy2zOZTkEa5i01gWJ1ypfhSidcXUNeIyVNyqAbYN9dXoEtBGJdGp1E4qaGk1lsA CVTSBsnI1qLKyZhElMMcBSeJ7GHR91Yz2Exi2QF9Z/cAmkuOSVuXtybSmMqFBTj4 w+LbeZndaQYL3hXM/57Th89KLhJXUM3hiBoDltPrv612TJ6iyzs/vB4eP/5m6d9y 2+3RrrpK0NNmpYXARWSjBKmMn8JEH5ZInhzfwZdhYE/4rXjhzql2eRTCBz3J4QHP 2V9D3MAZTpPgaTC52P0VIgqfyzo4kw2Fn8cq9b4dWGrBxsIj2HEGUkeFNrnjeIL2 9bMEyXbng0SQerMn3BWWLisdMK4b2ElvU+uHEELld2ks4dk1mlBv5AbQRs0neu65 ixo01Wg/3/6zRfJ0ald12oDuxtv/FLLVnFiFPun64iK6bb5wp5W40tf7lRfVEzRB t6++DTATVizjPtXR2Y3DnsAX6NvL92de+xTdkVHKI0AH2+avHsnK2YObwXNn8aKZ fw2GiyZrmnswI4+i -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqTCCA5GgAwIBAgIQA3lT8810fj7nG3NAfz6FVTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNjA5MjAxMjA4MDJaFw0yNjA5MjAxMjA4MDJaMGIxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xITAfBgNVBAMTGERpZ2lDZXJ0IFNIQS0yIFJBRElVUyBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANHdTmgMpxz5oYGoSO5gEC2m/ThfHFaNTxhj wTk0m1Ykr+3Pi+rB8IpHuQFRc7/BetUXi5vvWjcoTzEYm8++WQbl5flsLVrxQpZO f09E3VPhlc6Lwfq+8znkCyktPUCRdIhVPjcYWHPafFMTQXyiJQ/du1dIF4qceK4F cI3R0L7Q+JEuuqHScL0LCst3TcPJ7Ul5AEBduGyY2ZUMkHg7j1Niy80j8gKL2jc9 SeFuxl0Yw1Yl89KkFy8Mag9V4/ZNZ6k4KK+Yne+k2nUyn1C57osF3E9g2ZlTtZV5 l+Rrdx3EYOko5OLbovpQr1qJWl5hQ7sMp0Dnp/s28WuQvllRp6sCAwEAAaOCAVow ggFWMB0GA1UdDgQWBBRM/LeIQVn0ZsmFwVPbYAP/syZtqjAfBgNVHSMEGDAWgBQD 3lA1VtFMu2bwo+IbG8OXsj3RVTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB /wQEAwIBhjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw LmRpZ2ljZXJ0LmNvbTB7BgNVHR8EdDByMDegNaAzhjFodHRwOi8vY3JsMy5kaWdp Y2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMDegNaAzhjFodHRwOi8v Y3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMD0GA1Ud IAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy dC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQCBgljwkhevsU7wZ5JdPSiZJ0iw bSGgYu6Kl+gp4qf8ZSIpqpTBpksrAW440eHGtYWvI5fat+/UgGVhM4NkUlSJC80x KkJIcV2xVtl/75ecVc7PDWWhR95dGZaOVcMbHuK2U8X0YSuHBsnV1LnVkWQ3RoFQ da2XM/bkjrlP3ZJBAR/nYMHXesFFThMt2ijR616xBPj+ZEQSj3Xa9YsOtHaZ3zaI lBoQalgK4h+hyL70sAQGHChyhd0wfRE0qoa5FN5ZuEbTNNyTyFbyNElOHKFdHWG1 98l++MBrH+koUffNMOl3D6NvlA4u24GkPb141+qRBykLfueB4px8jpm+fpSa -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYTCCA0mgAwIBAgIOSKQC3SeSDaIINJ3RmXswDQYJKoZIhvcNAQELBQAwTDEg MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTYwOTIxMDAwMDAwWhcNMjYw OTIxMDAwMDAwWjBiMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBu di1zYTE4MDYGA1UEAxMvR2xvYmFsU2lnbiBFeHRlbmRlZCBWYWxpZGF0aW9uIENB IC0gU0hBMjU2IC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCr awNnVNXcEfvFohPBjBkn3BB04mGDPfqO24+lD+SpvkY/Ar5EpAkcJjOfR0iBFYhW N80HzpXYy2tIA7mbXpKu2JpmYdU1xcoQpQK0ujE/we+vEDyjyjmtf76LLqbOfuq3 xZbSqUqAY+MOvA67nnpdawvkHgJBFVPnxui45XH4BwTwbtDucx+Mo7EK4mS0Ti+P 1NzARxFNCUFM8Wxc32wxXKff6WU4TbqUx/UJm485ttkFqu0Ox4wTUUbn0uuzK7yV 3Y986EtGzhKBraMH36MekSYlE473GqHetRi9qbNG5pM++Sa+WjR9E1e0Yws16CGq smVKwAqg4uc43eBTFUhVAgMBAAGjggEpMIIBJTAOBgNVHQ8BAf8EBAMCAQYwEgYD VR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU3bPnbagu6MVObs905nU8lBXO6B0w HwYDVR0jBBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7wwPgYIKwYBBQUHAQEEMjAw MC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHIz MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9v dC1yMy5jcmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBz Oi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUA A4IBAQBVaJzl0J/i0zUV38iMXIQ+Q/yht+JZZ5DW1otGL5OYV0LZ6ZE6xh+WuvWJ J4hrDbhfo6khUEaFtRUnurqzutvVyWgW8msnoP0gtMZO11cwPUMUuUV8iGyIOuIB 0flo6G+XbV74SZuR5v5RAgqgGXucYUPZWvv9AfzMMQhRQkr/MO/WR2XSdiBrXHoD L2xk4DmjA4K6iPI+1+qMhyrkUM/2ZEdA8ldqwl8nQDkKS7vq6sUZ5LPVdfpxJZZu 5JBj4y7FNFTVW1OMlCUvwt5H8aFgBMLFik9xqK6JFHpYxYmf4t2sLLxN0LlCthJE abvp10ZlOtfu8hL5gCXcxnwGxzSb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzjCCBLagAwIBAgIGSUEs5ABFMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTYwOTI4MTcyODMzWhcNMjgwNzA3MTcyODMzWjBc MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5FVExP Q0sgTHRkLjEjMCEGA1UEAwwaTkVUTE9DSyBUcnVzdCBRdWFsaWZpZWQgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDo0wKRbbCHmWOD64vZj7wvwlmI +6KwJNmA8xDjdgVbvlPzj/paQLT46a+x4tQ/ZvbQn7zqdtim7Q7cxoAPEAX2kVra Y4HKiLhi0FA03AuAFeSUkK6Lg6sESpPnfcZ6LTMoRyKYodpFcQqkbUDFFfLoV701 ICy+cjXKnWpb8J3vYaOw5LJ1UOPTybd3vlDXQzQPhrpV1+Or+NEuJ/yaLegPeqoJ 4nK7zE5/Ln1wk+wfqiyzrPaWmUh+stKRqxW4hiHk1BX9M8yeHLAzOVtzvg0GfHYR wWF+pa3FtyGHGJ/ookvZn/cN3e92RLHXFoQU7f1dCswLZv83QQAmomQgKfhHAgMA 8wGjggJIMIICRDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNV HSMEGDAWgBTM+meT8La40KXAHvNT/YxT34PXljAdBgNVHQ4EFgQUUjpVthlqi3Ny xV08C2CHlFDwbOcwggE+BggrBgEFBQcBAQSCATAwggEsMCwGCCsGAQUFBzABhiBo dHRwOi8vb2NzcDEubmV0bG9jay5odS9nb2xkLmNnaTAsBggrBgEFBQcwAYYgaHR0 cDovL29jc3AyLm5ldGxvY2suaHUvZ29sZC5jZ2kwLAYIKwYBBQUHMAGGIGh0dHA6 Ly9vY3NwMy5uZXRsb2NrLmh1L2dvbGQuY2dpMDQGCCsGAQUFBzAChihodHRwOi8v YWlhMS5uZXRsb2NrLmh1L2luZGV4LmNnaT9jYT1nb2xkMDQGCCsGAQUFBzAChiho dHRwOi8vYWlhMi5uZXRsb2NrLmh1L2luZGV4LmNnaT9jYT1nb2xkMDQGCCsGAQUF BzAChihodHRwOi8vYWlhMy5uZXRsb2NrLmh1L2luZGV4LmNnaT9jYT1nb2xkMIGe BgNVHR8EgZYwgZMwL6AtoCuGKWh0dHA6Ly9jcmwxLm5ldGxvY2suaHUvaW5kZXgu Y2dpP2NybD1nb2xkMC+gLaArhilodHRwOi8vY3JsMi5uZXRsb2NrLmh1L2luZGV4 LmNnaT9jcmw9Z29sZDAvoC2gK4YpaHR0cDovL2NybDMubmV0bG9jay5odS9pbmRl eC5jZ2k/Y3JsPWdvbGQwDQYJKoZIhvcNAQELBQADggEBAAZKg60kuK/y8TGXo/gk ZAwVIQFPhD+3TLmXjKtde3y5VwloBilf9OuA+pUznUHj2pZ23w7HyRiPp8FNOX7Z VBq+4S9me0kaZ+JWEOmStJDa5HuwqitVFUFAcR+HJvMncFccEFIVYzSzNLJWADKn ibmou3xO8C7b+6cmvYg/osVWLx1uVI2XPm/ij/Ndp5PaV2kqLkb09f7WMgsIat34 ISb9DchEZ7k2tYVoS+fpz2+8pvlDn6LM3mRfI0wxg9wikqzERsx5GOYRyfyUdU1q 0Axh0CRC++6mSmjIOomBK235tdHBtHh3+3J8A1OFLruRoNZA2atJZADy/1yURQRK S/8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0zCCBLugAwIBAgIGSUEs5ABHMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTYwOTI4MTczMDE3WhcNMjgwNzA3MTczMDE3WjBh MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5FVExP Q0sgTHRkLjEoMCYGA1UEAwwfTkVUTE9DSyBUcnVzdCBRdWFsaWZpZWQgUVNDRCBD QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANIrMYoNSqTKcqIoE0iv jTOCCiX1LLubuqbcVUpof19DWJOFitkBC6AWaPT3aiEkvuytUxT83hDlEKKIsPqQ nWAouzIY4XoWYrWfXpYoE1j+Dh2LsyCrGZN4bh7f+SI3sL0s3lOMNZ6VDTrGLl4e SW0U8aPUStbs2l5n/ixl8pIXDCsbU2lxkpWNdHMTHsk0HFtJeWm2BB0DyAQxd6c/ bkfoMx0Jh79hdN05sJknI/ACn+AKlYWpyUIGlTn6wmN0SmDjSrW+4+UM7EblWoHn IqoEaynRoKYRCoLMShTGB4BcWM584IKipz+zKsxtGLXrNV5/CjKw1YlmXQmA1CDb fOsCAwCVcaOCAkgwggJEMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MB8GA1UdIwQYMBaAFMz6Z5PwtrjQpcAe81P9jFPfg9eWMB0GA1UdDgQWBBRFmGyZ hpWmCCttZah4YKY+iMLkgTCCAT4GCCsGAQUFBwEBBIIBMDCCASwwLAYIKwYBBQUH MAGGIGh0dHA6Ly9vY3NwMS5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzAB hiBodHRwOi8vb2NzcDIubmV0bG9jay5odS9nb2xkLmNnaTAsBggrBgEFBQcwAYYg aHR0cDovL29jc3AzLm5ldGxvY2suaHUvZ29sZC5jZ2kwNAYIKwYBBQUHMAKGKGh0 dHA6Ly9haWExLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUH MAKGKGh0dHA6Ly9haWEyLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYI KwYBBQUHMAKGKGh0dHA6Ly9haWEzLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdv bGQwgZ4GA1UdHwSBljCBkzAvoC2gK4YpaHR0cDovL2NybDEubmV0bG9jay5odS9p bmRleC5jZ2k/Y3JsPWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwyLm5ldGxvY2suaHUv aW5kZXguY2dpP2NybD1nb2xkMC+gLaArhilodHRwOi8vY3JsMy5uZXRsb2NrLmh1 L2luZGV4LmNnaT9jcmw9Z29sZDANBgkqhkiG9w0BAQsFAAOCAQEAKYfSeD3HDwyt TqaQgWGeF1NFoQ1UI2+AN8oeI7bppkTjD/pbstOhmGtfpfi12BViMVRPNGqtp68E VX56GLvnQPj9n3+ofP2EJVP87HczLgx6FLn4AjwJjjilOBkJYaFqfbvbQzodQ3dh 2hK6GOg032D2nxQXZHFBr9F0As4Ot3O1DVeu1x/MF7b1wmj5KjWw0F0oZfJs3GCH VWIc4RZ6QjH08aTjl4o5ci27G06iqmrahdli8f/PU9+49lLXH/VmwjY8wUmemXnf VzI2xN3LaC+fOljD3yKCy3u+NkDQ0YNY1U+FGfMTsJL4xyUF4YT6jy8RM15SAkbH qXkpkdoOkg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0jCCBLqgAwIBAgIGSUEs5ABJMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMTYwOTI4MTczNzM0WhcNMjgwNzA3MTczNzM0WjBg MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5FVExP Q0sgTHRkLjEnMCUGA1UEAwweTkVUTE9DSyBUcnVzdCBRdWFsaWZpZWQgU0NEIENB MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAznScZXd2hQbasNu4mNuW NQebFapwA05KYkVrZUzqN9rpnFc4BkYkQQ54dhuWAry4fLP91GP7CZ4u98VJZBv3 MRDshew1iXZ7XvOYA/MUqO8rory+2akWY4pVJgzyNEH1vW1Bw5g6dCS8hNzEUfDe EE+AjbQdK92+6B076Nax0PZVXrw+5Cuw6uZC5mAdUCyEvih07alv3ZDPC6RYnZlz X343VhV6BYPKTWcTCRHvl8QAxkLv8wlMnGLB6ghMnh/Bv658ls2RKmywtKv1BX0c EqAkKr9zxr/q8vaVGyXKggnYqMU7CmUp230BxzeuvrSrR75Em/rGaj9nYJ/XM7cD 4wIDAK4No4ICSDCCAkQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw HwYDVR0jBBgwFoAUzPpnk/C2uNClwB7zU/2MU9+D15YwHQYDVR0OBBYEFFR+7KQe GFu717N5g/T712e7KZX8MIIBPgYIKwYBBQUHAQEEggEwMIIBLDAsBggrBgEFBQcw AYYgaHR0cDovL29jc3AxLm5ldGxvY2suaHUvZ29sZC5jZ2kwLAYIKwYBBQUHMAGG IGh0dHA6Ly9vY3NwMi5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBo dHRwOi8vb2NzcDMubmV0bG9jay5odS9nb2xkLmNnaTA0BggrBgEFBQcwAoYoaHR0 cDovL2FpYTEubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0BggrBgEFBQcw AoYoaHR0cDovL2FpYTIubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0Bggr BgEFBQcwAoYoaHR0cDovL2FpYTMubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29s ZDCBngYDVR0fBIGWMIGTMC+gLaArhilodHRwOi8vY3JsMS5uZXRsb2NrLmh1L2lu ZGV4LmNnaT9jcmw9Z29sZDAvoC2gK4YpaHR0cDovL2NybDIubmV0bG9jay5odS9p bmRleC5jZ2k/Y3JsPWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwzLm5ldGxvY2suaHUv aW5kZXguY2dpP2NybD1nb2xkMA0GCSqGSIb3DQEBCwUAA4IBAQC14xxjVyoKWGUZ PfdVrmeCOpc4INeN5NeIahHmYXTYUWbkWIN4LNUiEQXtTcUhRZddSifG4MGJHCMl m2YTaL879IMsj2NOouwEDO+CKKh/6/UrbLxmzWeBHVMn/GJaKpv9rQgMyj1pG9iH 1iy34BZG5TZ2zE/qSgG2SQ8IT6UtYLFCg4PpH6MOiGX/XSWI3K2wH5Kvuvyewt4e E7Y9qbhQM2X5KdLlGIh43hw/unao2kdKAcfLYzXCPbKSwgqeh7kXNTtaaYg4Uk8E zGfoYEy7dLypUTjItRr6nJoaB9ZGgKx3I6lNym1oNffxhXXdIq+dRE4k+IRUvYLM eY02/X1L -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGVTCCBD2gAwIBAgIIW0naHidw4rowDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMB4XDTE2MTAwNjA3NTUyOVoXDTMwMDkyMjExMjIwMlowgZAxCzAJBgNVBAYT AklUMRAwDgYDVQQIDAdCZXJnYW1vMRkwFwYDVQQHDBBQb250ZSBTYW4gUGlldHJv MSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEvMC0GA1UEAwwm QWN0YWxpcyBEb21haW4gVmFsaWRhdGlvbiBTZXJ2ZXIgQ0EgRzEwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDlkElR2SqCmSVd56Wxsbd5JpuuZa/kBlHK gFHUYgrW2s+2STvJbGrlZ+mu4TxkBsgYBOWHOfRf0UzGItofDhknUR/mxLQBEIYx 9GM0lCQrddJ7eOHsg4tu/2u8RajzSArGgHm4OYKvIrZv0aXpHE2LD8xl+UC0SODI DxHxkKLTztZECnPJ/IW02r1fAkxtZREARILMnbq3/PUorCA38pZMMp2oX3K/hNT+ y6KR1bWakSh39hLefJtFs+w8mhHNynO7Gqsvk77j10aNAEeXz8UCvj5ytGRV2kIu sjItkmbvbLi7e7PA7Q9eSvgIwKj2wN0KXrwMHbJ1ujfLB+M2bG9zAgMBAAGjggHV MIIB0TBBBggrBgEFBQcBAQQ1MDMwMQYIKwYBBQUHMAGGJWh0dHA6Ly9vY3NwMDUu YWN0YWxpcy5pdC9WQS9BVVRILVJPT1QwHQYDVR0OBBYEFBtCf1xFfv9+Hh5BnPOt rjXGZevFMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbtifN7 OHCUyQICNtAwRQYDVR0gBD4wPDA6BgRVHSAAMDIwMAYIKwYBBQUHAgEWJGh0dHBz Oi8vd3d3LmFjdGFsaXMuaXQvYXJlYS1kb3dubG9hZDCB4wYDVR0fBIHbMIHYMIGW oIGToIGQhoGNbGRhcDovL2xkYXAwNS5hY3RhbGlzLml0L2NuJTNkQWN0YWxpcyUy MEF1dGhlbnRpY2F0aW9uJTIwUm9vdCUyMENBLG8lM2RBY3RhbGlzJTIwUy5wLkEu JTJmMDMzNTg1MjA5NjcsYyUzZElUP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q7 YmluYXJ5MD2gO6A5hjdodHRwOi8vY3JsMDUuYWN0YWxpcy5pdC9SZXBvc2l0b3J5 L0FVVEgtUk9PVC9nZXRMYXN0Q1JMMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B AQsFAAOCAgEAUx5FiRZr/apzRYJXmvDAg3R8+m3kZsA+uw6YVfc3ecAg6yxCpOiE GDY4nsVLaWkU/3tjB/JZzBvA4b3e+yskqcawGWpumK47MIJWPiE5PvWSYBpAcyJ2 wn9R8sGo9dmiemq3PVH8YRBYiWXmcF4hX/qtRgCY5AAXN/CCKYeeWnRDRS7w1csv K4viW9ZH2gEqhZ9AHrwXlGUh3dVOeLu81ac70kqfjnl7dn0bFQaKWhj2s+PItoBs S9f+FeS+eivTL4J70hLIyg5hCF7/OLAQc+k1re+WpnLtJ+p1S8CnqBm9IYZmOFlE zLUYj3JV+zzdmwdZZhV+VS+cjlsoHgscwpX59xXs64NsXicmGDHxEgKp+S7SXMrP MVk69msokKAhC/x9VYosmyqogG3SKm6n4lK5Xtvy/Za0gME8uyBGcxGpCo/Q3YSK eN9YwwajGn9F5n+djPLV/Lcq16K0FvGsPPK2REFxDD9jraX8dis2iEW/iNoVeJWC XeY8gSgqWXbW1aEhlWIiaF8KYnOaxiZ0oYS5sT/isDRKVx+h82GyvcXMR+HxP6AD 94Zsn0w3YbapRJFtErsJ094QEN0QgkJR+edyPgUeMyKtUY7XfsF2lAvQFNPOrQ5E pzdCnp1mL3I1P6Ct17Nxxe84l2mo62EU5BYpAwQa9Yk2RcuO4gNkOSY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEhDCCA2ygAwIBAgIOSMqBesbcf1a2gLtDNiUwDQYJKoZIhvcNAQELBQAwTDEg MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTYxMDE0MDAwMDAwWhcNMjUw ODE5MDAwMDAwWjBXMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBu di1zYTEtMCsGA1UEAxMkR2xvYmFsU2lnbiBDbG91ZFNTTCBDQSAtIFNIQTI1NiAt IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo8B14TKY5dmuhHyN 6CNfRpVbTKIlcNeQBIWAybX0imVNksulxEKgtnklMe3xhSDNE1E9Z6yXTWibM4Zc s3stqt93oGHR9Tz7mvzT1ZTKyR6AG5CQyKyN9mAXnDG4xWGi4m5XJQhvJJmZz5S/ x4trsB/KFPoYm2wQfJkr2kpj5bJOwv0+EAtI9HcLL/CWSzruvTXehY3aEw7OAcRx 09N3xQimYDklpydpXIPRb3Z47sVEW0W9KTvixgkPor4r3ONc2lpvjufJB2t+ocBT lYKJ4Hhccqhsvmdrq+cz2Yfy+Fwn9PYqO4fv2sJH2r+s6ydke0xT6zThL5sgTVQS a30ovQIDAQABo4IBVzCCAVMwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSp K4fhziRHOxu/z4U3AlWdDZRY5jAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpjmove 4t0bvDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwMi5n bG9iYWxzaWduLmNvbS9yb290cjMwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2Ny bC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBWBgNVHSAETzBNMAsGCSsGAQQB oDIBFDA+BgZngQwBAgIwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFs c2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAEfBQv988oIO c41SQdlhXTaW7haaTzLrypxvjCKXc+m5Vwp6LzbZTrqYxf5aJkbOKtetCOv9H4JG AGkfaluwtI5zQC28JMVxHG/XtUDxaIT7ACyGloa6begkWi59pavkjI4ZSUmq1Uqq YImx3YX+jGdwtdR0QcopvKzto7Ywcu7m7SgYmJQzrRZoZepKzG2uBURya9WqCxfg U53N/sXVM1L7p8SoLESDtAnFbg+fEqQnCzFDPoozoEtNiM5GF8W/mx0pVy6JUPk1 CItc+0EnTdPoJQX6nq4wIrrgFYlXGeGxuC0VNoTdIiAILA3LulfBhhKDUzGj2BJf jRml/QCDUB0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGxzCCBK+gAwIBAgIQfcTKHu/M2eXO+lUrqJeIezANBgkqhkiG9w0BAQwFADBu MQswCQYDVQQGEwJOTDEWMBQGA1UECBMNTm9vcmQtSG9sbGFuZDEWMBQGA1UEBxMN SGVlcmh1Z293YWFyZDEVMBMGA1UEChMMRW5zdXJlZCBCLlYuMRgwFgYDVQQDEw9F bnN1cmVkIFJvb3QgQ0EwHhcNMTYxMDI1MDAwMDAwWhcNMzExMDI0MjM1OTU5WjB6 MQswCQYDVQQGEwJOTDEWMBQGA1UECBMNTm9vcmQtSG9sbGFuZDEWMBQGA1UEBxMN SGVlcmh1Z293YWFyZDEVMBMGA1UEChMMRW5zdXJlZCBCLlYuMSQwIgYDVQQDExtF bnN1cmVkIERvY3VtZW50IFNpZ25pbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDhcstW78TigQeMEoIeJiCO9i/5FBnCIvbmhXnFZHq4swmEEX/U ZumJCR7gzGiX3fTZcrgEp9sKSjEh07uqUoQLwQerfWEsA6yTx8sjd5Vh090DaAB6 /0Mp5FLHXs9IUVaxt4KNUc5JY/YGOGRKivnotyJGWe/WM2sgHuVBZVXQgBzNKhiF 5030Hf5VH/zDHeriNKqA8fVnU5jBsyGwb7hgo0hsQ7ZTMsuXc8L3jbHx6r2FifOt DeMOUWFF0C2ejfpKiXAxKratrgxy2jsL3HMcAcOAgE1dUjmQC2YLTp9BCCTPI1gm n2m8Szqxtex8m+b4EZx+cG7rSe9hs7qoJvpMDzFhZlHr2NZCLwlzCqsfVecVLMld 8TARV0UoQOdcktPKlH9dhqbedQWgVR0hNBfKCYrVq5kTQcIntgSQ83/p1pGGjf7v 4JOz8l1FX08g9uYusKWUP2SSTcVshv4XyFNQsUD4XnJTgBMDvaDS4asDFu/ub2Lc AfljZ7iW6fm8WjiMKFHBMGtM/YJHLub3LMKdjtO3V8v77KcLws6AYk1/Q7yfOSkZ fi3isDJBZhbLTTnvoKR4OL+oTGc+KjKKVeID3Spy2YbnIDTL8d/8uObvUfus7ubR DsaDyq1kQlQBvtNbN3O0DrmfM1olNVWbXnz+uxyn2IFYqq2BVD1rP3y+cwIDAQAB o4IBUzCCAU8wHwYDVR0jBBgwFoAUiNSY6vpmUPiThd9gS5f+L6kw3VAwHQYDVR0O BBYEFMoJHMMqhSWNWr8uD5aAfUz9zB9SMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMCAGA1UdJQQZMBcGCSqGSIb3LwEBBQYKKwYBBAGCNwoDDDAX BgNVHSAEEDAOMAwGCisGAQQBgt0mAgEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov L2NybC5lbnN1cmVkY2EuY29tL0Vuc3VyZWRSb290Q0FfMi5jcmwwbwYIKwYBBQUH AQEEYzBhMDgGCCsGAQUFBzAChixodHRwOi8vY3J0LmVuc3VyZWRjYS5jb20vRW5z dXJlZFJvb3RDQV8zLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AuZW5zdXJl ZGNhLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEATasrJezt7zsSfykKLX7B/cBRBgDs 4jMD7qY8ZzbBW5V3ZGZpoRvyEqQvu5sJ4IZpzRITHS4pvmj1a2j5cfJ9z0p0izzl WorQQIzMQYHYDkdtT/BVVD22Dyr8pVz2VAqb/5bBOvr2ydLiTX1Ut6DVjtZ0Snib M+uk1Xl8vVUYsur4BMYHn6//1JODaPItpznBipI0SmOGrgJyVlN5KLB3Lf9k8P1+ RhjJ/Wd7WqplfON2nyoJmhkb+6+gS4yOz76HNtf4aXIhy7FG2oHQy95CbnYZYL4f GNfYiRpeO5BMeFbD2SVHBCCixfS0DAXRCRW/Y0X7xOoY/kz4VNdFLdnxEoieYlne COegOBbrskw4UXWNc2Xu/oHOnQcA+iQyiJ96q3htYesy1cD6rmRGciP/lKwxXc7y wq6W1LQvVPn303GwWUeehw2JJlMsW4CoXZo1/VYpg4UuVyEi/Nt95A01bGGPVJc/ N6tCTs2jT8CamXuNuoVi8lygoPgwGvWYJoA4XmKjc7coZuHGOAo/L0fsBow1SfH/ YhlDez+QahiUF8+52shUSwlkCZA/4/cIeSu5710hh9n1hlCRIPPgRLcV38QOoJA3 U6X4g2kHJBDE6UWLwC8kauk9IrvuCPkDTRStVTT17y8H6UWSeKvpIWVuUA14DZwJ M+6F9F69PMpdeAs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIIJKeitiD5A+MwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjE6MDgGA1UEAwwx U3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFBlcnNvb24gQ0EgLSBH MzAeFw0xNjExMDMxMjM5NDFaFw0yODExMTIwMDAwMDBaMIGDMQswCQYDVQQGEwJO TDEgMB4GA1UECgwXUXVvVmFkaXMgVHJ1c3RsaW5rIEIuVi4xFzAVBgNVBGEMDk5U Uk5MLTMwMjM3NDU5MTkwNwYDVQQDDDBRdW9WYWRpcyBQS0lvdmVyaGVpZCBPcmdh bmlzYXRpZSBQZXJzb29uIENBIC0gRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQC/WmIMjjnDP86Vbq0B8wyr4/EfZZETCUlGEbo8b898pUDjEplrNN89 vkv6iFfywtmojbN18D+oXC/uiSSdQzczBgMDsTv5w5oI/uKuaSR45m6r35tsDRQt JEqRyYAG+kvOrKxbjLdZiVgSm2QEKsAXXzuFQph/SWB/t57mBqrZEPyd0/Rm27vq YUPskzJlYT0fyI2W1gbLXTluHu3/BrkZlzIoWr1+msqcTJLcrYiFtMRnoObzGgNz 6noM4JzU/wP+3jztu+2RTOXR8QXUmFBIDqyuDkhnt5ZwiApnslEBTZcGeX9rHZs6 fDIo4MxjeuoNtrde4hGbOx4F8tBPeFmhrH0GZtNCAFprsRDHFRYd3XDrCOdLXLab fovNwDtkHtbvxNboBQb4kU/29floR5Q4Jm/k+T/ZX8O6PYAkjBnLxCoP2aM8c4/E kAO/ao6323MVKe5KOEXcYzxHg6gCXzoWDkK7wpAJ4hMSj0GaTmBmbrvhtrcJLmRu 72EUqSzPM1cOO+ujq2xJPMuj7ppXGBDZXVuXWaUxnHvuxb7OHDz6jk7yTYlTu1zj WK5itTu9DCPzz3Xh1mHOfIdYfY/I/dN2lZPif+yfWhUvU8Kxi1otQW7eG+rT2CBx 6RZT7BQ4S2O+ooQy7U7E8PZltj9m60taBA6iijDbwoaZWkE0i94YpwIDAQABo4IB 2DCCAdQwVQYIKwYBBQUHAQEESTBHMEUGCCsGAQUFBzAChjlodHRwOi8vY2VydC5w a2lvdmVyaGVpZC5ubC9Eb21PcmdhbmlzYXRpZVBlcnNvb25DQS1HMy5jZXIwHQYD VR0OBBYEFFGoa/eCJJToi6O2KTuOtrKdKPmLMBIGA1UdEwEB/wQIMAYBAf8CAQAw HwYDVR0jBBgwFoAU7qxtQOrVBGqHLFV79T8t2u7brOIwJQYIKwYBBQUHAQMEGTAX MBUGCCsGAQUFBwsCMAkGBwQAi+xJAQIwXQYDVR0gBFYwVDAMBgpghBABh2sBAgUB MAwGCmCEEAGHawECBQIwNgYKYIQQAYdrAQIFAzAoMCYGCCsGAQUFBwIBFhpodHRw czovL2Nwcy5wa2lvdmVyaGVpZC5ubDBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8v Y3JsLnBraW92ZXJoZWlkLm5sL0RvbU9yZ2FuaXNhdGllUGVyc29vbkxhdGVzdENS TC1HMy5jcmwwDgYDVR0PAQH/BAQDAgEGMD8GA1UdJQQ4MDYGCCsGAQUFBwMCBggr BgEFBQcDBAYKKwYBBAGCNwoDDAYKKwYBBAGCNwoDBAYIKwYBBQUHAwkwDQYJKoZI hvcNAQELBQADggIBAJSe1OBYX+B28BEY5FIBufwGhbIuBBpKl5DL2WufIlWWqcQE 651unVsEWaWpcSEtbBGYOssjFtSfAg92lLnBk5xUk6QzxWQTz81vHepmieOVW2Kg tr7ZfQxszIyM27ow2WBcP3tWQKpJHf1/YPshM7j3ioTYRO3pPTF2f7uhT8Tr2jAI rkpg0PG0WZKexZ6tJrwDDYJCfLY7LGYiNjjpi6S4w+SB8mwUETrqVvjbwRREPN2V IG7ZS6+YAN9WV7nJfJ+NQI8vM0gxjf9+/2sd+bfG6Kv/a6eiSqGaSuITx1EVW3/6 zPHuV9Rh9kXBdewE0T+pzT6XSKlHV9SZt1Oh9YQLg8qkp70gs3spBKzO5cPHdiqc eGEzyY+gff3QBM9Q4QZ9gFtMaKS+i7gpTbJJlk0sFdh92NK7LkmW28L6qGlGbI+p 6KyIuTnl9ZSLiAEmHqlM7xO/uSRYHkvbdA7CpEC1CIuhUbDTGUsiS7s1Q/bQJKh7 LmkV9WlcInuqHsTluERw1JobwoSTMq6p1xDEKAS1DqNFwYnybE+GT1RYy6W9ph+7 +auARKh32+bdmZAsmAreUhqvuUVOVZbgbEW++zZNegAolozyezYU46D/t8jODY8F UoGLZfctZZ9+BqskLhI7314Otqa/t8kNCTFrMMsqeT7Ce9MDaGI4GuJxFLLk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHkTCCBXmgAwIBAgIISyLfJHCSd+kwDQYJKoZIhvcNAQELBQAwajELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjE7MDkGA1UEAwwy U3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFNlcnZpY2VzIENBIC0g RzMwHhcNMTYxMTAzMTQwMzI2WhcNMjgxMTEyMDAwMDAwWjCBhDELMAkGA1UEBhMC TkwxIDAeBgNVBAoMF1F1b1ZhZGlzIFRydXN0bGluayBCLlYuMRcwFQYDVQRhDA5O VFJOTC0zMDIzNzQ1OTE6MDgGA1UEAwwxUXVvVmFkaXMgUEtJb3ZlcmhlaWQgT3Jn YW5pc2F0aWUgU2VydmljZXMgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBALlzUulTS5bMKKM1zNn8n98qxKnLQdU/DU4HR3ugqxN9gnne3rE8 NawxVqLEfYwE5c9ovWRes5MJTNj6wpU4lvvkH8/jyKk0ZgioROviu4T/Nah8Qz3c TWauMEtRaLTcemhdAHu8UTAy8sVeyx/NpnmfHVRKHjdF8U3uDCYMsqTymj4n/rYp tAa5N7JLH3hAwrx3UTIGI2UpVLhSUvzMNa1hu2ChITUG/DSpGul6LTzaH00nkrRO iYq1wrvO9119aAlzmorOFzNmo7pZ+sxfOg7b0OecmisFYO/7qBK5f3gFn6FLW6+U 57f3iIraOETCGPfzFTC0mhTKQ2XjqOnC1/Jvg8okbQlCptutgpFuVqh5Xgm0w8Sm 2NQpE7OcHk6l0ZnMiCs9ooMgg1sO10Pdm5jD3rV5sSKhEQ8K5cS9xgVKHgSHnC3e fCv/7tH/Dw1JZJ2yIbeae9COhrmCGLclObJQ1BNb2mfIXcG/IaHMpAsB84Io5Rb4 aLg8JxM8FA3DaK21X3ff+5s2sBxiWJXfDYDIlKWx3reMT3BVa3V73tclPO21AsXW y7dGURo1zGDY6ZcsJVwFFlbPWwRn0dqwfr1JwvXWdgTBUPujOOSmgockxSQaqA23 OAMQJMpayBoL4CwsfIzW1AFSQ8xDM0kH1rkjGW8mNNn26ChnNga3hV8lAgMBAAGj ggIeMIICGjCBmQYIKwYBBQUHAQEEgYwwgYkwRgYIKwYBBQUHMAKGOmh0dHA6Ly9j ZXJ0LnBraW92ZXJoZWlkLm5sL0RvbU9yZ2FuaXNhdGllU2VydmljZXNDQS1HMy5j ZXIwPwYIKwYBBQUHMAGGM2h0dHA6Ly9kb21vcmdhbmlzYXRpZXNlcnZpY2Vzb2Nz cC1nMy5wa2lvdmVyaGVpZC5ubDAdBgNVHQ4EFgQUyuIr7JU+WqFIjMfkvNJUbMbr ZS8wEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRD600A05WTzqZ8QA1t Eb450TKu4jAlBggrBgEFBQcBAwQZMBcwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjBd BgNVHSAEVjBUMAwGCmCEEAGHawECBQQwNgYKYIQQAYdrAQIFBTAoMCYGCCsGAQUF BwIBFhpodHRwczovL2Nwcy5wa2lvdmVyaGVpZC5ubDAMBgpghBABh2sBAgUHMFEG A1UdHwRKMEgwRqBEoEKGQGh0dHA6Ly9jcmwucGtpb3ZlcmhlaWQubmwvRG9tT3Jn YW5pc2F0aWVTZXJ2aWNlc0xhdGVzdENSTC1HMy5jcmwwDgYDVR0PAQH/BAQDAgEG MD8GA1UdJQQ4MDYGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDDAYKKwYB BAGCNwoDBAYIKwYBBQUHAwkwDQYJKoZIhvcNAQELBQADggIBAFhySKzrcYym+x4R OIForpbq9bSkzrxl7za2251FG3uRkF2GCBIJO50WB4arC+C+rbo8zJ3F09bJbXOL yhWvb7gdUD/nt98qntiQ01hu+vXysg5T58cKco7oz4pMfdO1YE63kZsioVuwC/y7 FLwjpHwbct/pzhtUNdZrnycFSCVYh9fpwD9wyW2PXKpRD/8dLm4+zKmeU1L5qm66 SLOvhffTwRWStgOaKIFXRAcy4OtJQdrr94C8dMqMT8LrXpCdHsRFzYW/U8QSPxwT RSnwSWDdttz4uInvT5Rcv+3W7KGdDfbrUjCtuC89GCbxVofzVDmiDN495tSmTUQr LEelJqwBf2quOTCaicpYn9U2FBOG9aKVJQzHSUKZWoNu5u203PS8UgcFTN4fMPk+ jSLzArtmDDJfk682/Gq3aqQO6GMpeKjcFvi5dhdPh+80FOHK4AnC20/+fSoD8odT 24CPafZM+o2xBUFjPJm36gCgBHteSmxw/O18RNPGwsru9WimCe9XlGiu9uTpjo5p X5M2LtAVcOeeXKYHR/RnOwksDV3GgdC/oigw2enxJYe86hNjkOLNZ0UoZ37gieDi asLoADPsXixHUAFwsxtGqfe0w3xo5o3E1mhDBZXg2lCBSbGUPltvcwuCa5KxfYbn ilCoKYBjQblxUa+v2+SQD/d+S3cO -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHWzCCBUOgAwIBAgIINBHa3VUceEkwDQYJKoZIhvcNAQELBQAwajELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjE7MDkGA1UEAwwy U3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFNlcnZpY2VzIENBIC0g RzMwHhcNMTYxMTAzMTQxMjExWhcNMjgxMTEyMDAwMDAwWjCBgjELMAkGA1UEBhMC TkwxIDAeBgNVBAoMF1F1b1ZhZGlzIFRydXN0bGluayBCLlYuMRcwFQYDVQRhDA5O VFJOTC0zMDIzNzQ1OTE4MDYGA1UEAwwvUXVvVmFkaXMgUEtJb3ZlcmhlaWQgT3Jn YW5pc2F0aWUgU2VydmVyIENBIC0gRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQCif59yx1tCrQUccIYzyvfDNVoASBFIeaftj+3nGru7Uxv88hTN57qq NogGzIvQ7gX/nm450qQ1FK6yS41AZbXJeW/xwpxwvurF4PatK02OEyGC4Gema4ma PwXKKVr56KOBxO+fxDw1UzkxL5e3cYj9Qju1R4rj58I4/pyGsz087iBPiNPVBpR4 edVj5M+NQZ4i2+242uyTyaZOwRftR58I/qKGBdhFb9J0RH8cT9ucRAsgzD+LK5h0 dJ8F7j0z95lgh3addM0mjAMqlDyU3JfRJ7BblD3p9PulX/PwwB/idRUpMKEc2ZV0 J5kICLu/5UiS6nQJzrXkEGpXrLH5iwf3uPK0X/XFCW4Cs1vxHJ1zonw/rmVDRVYa p0lK4Bw5vIbMYPfNATu02198knQpFV+PoUvQnx3gNCAADzM/LLryDrb5x1wIV9wx 7nPktCnRu0MnhtafwwEyTioyP+v/5QryJDaiQR2FdR6eHXEy6mCoDDUKHoYfzkWp YRd0iQwrDNbx0mF/+mU4rvtqwJusv6IYFMftN8OVR6Ju7oVXFMa53fmcnBxiWtPN 3FZQBWhctYKVtv31PQDRD/qa5TkkkvAAflc51VqsaJAq2hJQUZw6vQVNyO3i41+6 3ZbOSNykBJEONkBfqBuxMFBDqCYS7f2v5bzgsGxt+XZLTlg+wzoV3QIDAQABo4IB 6jCCAeYwgZkGCCsGAQUFBwEBBIGMMIGJMEYGCCsGAQUFBzAChjpodHRwOi8vY2Vy dC5wa2lvdmVyaGVpZC5ubC9Eb21PcmdhbmlzYXRpZVNlcnZpY2VzQ0EtRzMuY2Vy MD8GCCsGAQUFBzABhjNodHRwOi8vZG9tb3JnYW5pc2F0aWVzZXJ2aWNlc29jc3At ZzMucGtpb3ZlcmhlaWQubmwwHQYDVR0OBBYEFLfp0On/Zw7ZnAwHLpfUfkt5ePQg MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUQ+tNANOVk86mfEANbRG+ OdEyruIwJQYIKwYBBQUHAQMEGTAXMBUGCCsGAQUFBwsCMAkGBwQAi+xJAQIwQQYD VR0gBDowODA2BgpghBABh2sBAgUGMCgwJgYIKwYBBQUHAgEWGmh0dHBzOi8vY3Bz LnBraW92ZXJoZWlkLm5sMFEGA1UdHwRKMEgwRqBEoEKGQGh0dHA6Ly9jcmwucGtp b3ZlcmhlaWQubmwvRG9tT3JnYW5pc2F0aWVTZXJ2aWNlc0xhdGVzdENSTC1HMy5j cmwwDgYDVR0PAQH/BAQDAgEGMCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcD CQYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggIBALOmq26D30gr6hSIAdEihFWL dCkMvRXpESpH4P3Pj9QFHl/WmghNYXFY3AJR4GAg7iFK2/K/rb2vjYLQmCAkQubt IflqXI7Xy3VRI3StcKUi1IfP5mi3DBQL8035Ch3akBDLppyvBzoARnoETpcnRROP EM0Mi1shwjChj3J2AIF5kfwvl0o278cJwhZql2OFApiznVp+iWvyQ2FR7ybMiAPn 0N7RewtcZL31MTcqC6eOWTobnHcEAbHdqIq7fm9UGk9HWqvK+hBn9S8PqFXux5W5 D7P4O7VoJt03KljyBA7jqOWJZQK3O6XD5uEmZy3wjs0I58Jqvl8xcmxgviL20ZBz kxhX3uPMsaP6DoQNZX4EWWlrYtS1jSbuB/WNLcoExLKYT2vdOhJHyxiLnw3Va+KR ae1BV44dimiz4QGvbB2Ugk9IsthpIVlnIjGFIqBYIY0dTvjLAWxc6/fqe3QPPp/X M8lQzMC0/H7kgmIJYd/yt/0Cgg55MQlWlHX9atZCrBl4LKoxQ4D2kJcOiXpSZXc7 uRMsq7MQRs7Bwe1OXhQYgp8YoraboE0a2lLrERBYLtbbKSaGZkkiBBt1aRDdsM6r HbOwC/lygnBm5K0bmGiLop1xMgfscVSzRIIB7Xodi6q8MlFUtK9851SeY1yyz0wI SFfzGre9T6yBL4I+6nxG -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFjTCCBHWgAwIBAgIMHDrUUIR+7vNY+I53MA0GCSqGSIb3DQEBCwUAMIGVMQsw CQYDVQQGEwJERTFFMEMGA1UEChM8VmVyZWluIHp1ciBGb2VyZGVydW5nIGVpbmVz IERldXRzY2hlbiBGb3JzY2h1bmdzbmV0emVzIGUuIFYuMRAwDgYDVQQLEwdERk4t UEtJMS0wKwYDVQQDEyRERk4tVmVyZWluIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IDIwHhcNMTYxMTAzMTUyNDQ4WhcNMzEwMjIyMjM1OTU5WjBqMQswCQYDVQQGEwJE RTEPMA0GA1UECAwGQmF5ZXJuMREwDwYDVQQHDAhNdWVuY2hlbjEgMB4GA1UECgwX TWF4LVBsYW5jay1HZXNlbGxzY2hhZnQxFTATBgNVBAMMDE1QRyBDQSAtIEcwMjCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ4ceOfS4eFqoDrPzHdOF8VN shbXzNeWbiVdD2T+wZqkiSiyz8qpjqwA3zXSeTyBgbaNiQYbUUQR3RtBkTjr00R4 8zoGveVjk3rq2u/U9tRVsMAMGtvThZw92aZULOh4HcEK2VjYtVhzScZ/+JgNfazR AVHObq0iKWT72YuV5pRd79yRzpcdylle5lLXgeKcBBHxk4OJ6TwCW6dqO2q8UHaC Kvj7tjrL6oQ+0ZOEHml/hDNUEuJandaLVuIRO9Ifzgz8tcX34G2YrqLVkCwupyMG uuUL+m8qpSF9KmbrvfVbLvq97FmLC+UgZIHnDSO3zCebXx646MX6ypfxK0wLfBkC AwEAAaOCAgUwggIBMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEG MCkGA1UdIAQiMCAwDQYLKwYBBAGBrSGCLB4wDwYNKwYBBAGBrSGCLAEBBDAdBgNV HQ4EFgQUxIilB+64e6oME7/aKXRjUhtJcBYwHwYDVR0jBBgwFoAUk+PYMiba1fFK pZFK4OpL4qIMz+EwgY8GA1UdHwSBhzCBhDBAoD6gPIY6aHR0cDovL2NkcDEucGNh LmRmbi5kZS9nbG9iYWwtcm9vdC1nMi1jYS9wdWIvY3JsL2NhY3JsLmNybDBAoD6g PIY6aHR0cDovL2NkcDIucGNhLmRmbi5kZS9nbG9iYWwtcm9vdC1nMi1jYS9wdWIv Y3JsL2NhY3JsLmNybDCB3QYIKwYBBQUHAQEEgdAwgc0wMwYIKwYBBQUHMAGGJ2h0 dHA6Ly9vY3NwLnBjYS5kZm4uZGUvT0NTUC1TZXJ2ZXIvT0NTUDBKBggrBgEFBQcw AoY+aHR0cDovL2NkcDEucGNhLmRmbi5kZS9nbG9iYWwtcm9vdC1nMi1jYS9wdWIv Y2FjZXJ0L2NhY2VydC5jcnQwSgYIKwYBBQUHMAKGPmh0dHA6Ly9jZHAyLnBjYS5k Zm4uZGUvZ2xvYmFsLXJvb3QtZzItY2EvcHViL2NhY2VydC9jYWNlcnQuY3J0MA0G CSqGSIb3DQEBCwUAA4IBAQAS6Xg+RcoM6jo4/v5QDsttFEDhlpcdETLj3COJ7shU /EhpivZQ+0AoPx6GiZX1P6+/HsfkhInXt9unr5RQKCVyBY1cszZbQ4aTCqzyA7od jdds8p9RLWoKjy+obuKVUc3AaZfxdhwr7ZjMeSuFjdS9X5h1i3EmqXYVy7wGfURv wd66slCy0jTfMR12F6ZrbxtFRiQJ3WfpY/gR+7r3d5x1p1xBwtqu4kJQ1KoNGsCK liYHS5cdUPA4P7KHb9JvizdJDsxr1Q0QpqMAXVhoYbrA/nbileuqQZfqoQvuC4qW q4lmjKiuaaTEETgE42HjUb8CPpw3BF69rw2ipnW8YA1c -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFlzCCBH+gAwIBAgIMHDrUb+yCwCXK21qNMA0GCSqGSIb3DQEBCwUAMIGVMQsw CQYDVQQGEwJERTFFMEMGA1UEChM8VmVyZWluIHp1ciBGb2VyZGVydW5nIGVpbmVz IERldXRzY2hlbiBGb3JzY2h1bmdzbmV0emVzIGUuIFYuMRAwDgYDVQQLEwdERk4t UEtJMS0wKwYDVQQDEyRERk4tVmVyZWluIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IDIwHhcNMTYxMTAzMTUyNTE5WhcNMzEwMjIyMjM1OTU5WjB0MQswCQYDVQQGEwJE RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xHDAaBgNVBAoME0Rl dXRzY2hlciBCdW5kZXN0YWcxJTAjBgNVBAMMHERldXRzY2hlciBCdW5kZXN0YWcg Q0EgLSBHMDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOO74lqz6X /fpFYCX0bIJw3Uqb26QLIYx5aLS/jQsoFGwm0KpHrFIEERg0HCiF0KqB8XmzbhXE jzhFcfWq5vu7Tr75zownBGllkMzSIGbGH0vyPRppYpVYtt+LWZgJqmf180Ut8i9f BnJigE2KhDKe7AAJw3w1D8qvtnKJnO7bO7GBg1U5YudQ1auTEnxvWoR8mY7DwcVl J7AtTeEbo11gO9+9XCYOZoEqXPLtZGaCNbZ2D35xi7Fnw9Ooi0n15mTEe8KDQQLV 0r856WXU1ACTDYpolXkQkyhhfZgA8gHe705DPDNYSE4dMv7WKVOXQvUpdPSNLAFe Ithun+5Sa8g/AgMBAAGjggIFMIICATASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1Ud DwEB/wQEAwIBBjApBgNVHSAEIjAgMA0GCysGAQQBga0hgiweMA8GDSsGAQQBga0h giwBAQQwHQYDVR0OBBYEFDWtxMz/TyDqnDre+5zd+T3EfbqPMB8GA1UdIwQYMBaA FJPj2DIm2tXxSqWRSuDqS+KiDM/hMIGPBgNVHR8EgYcwgYQwQKA+oDyGOmh0dHA6 Ly9jZHAxLnBjYS5kZm4uZGUvZ2xvYmFsLXJvb3QtZzItY2EvcHViL2NybC9jYWNy bC5jcmwwQKA+oDyGOmh0dHA6Ly9jZHAyLnBjYS5kZm4uZGUvZ2xvYmFsLXJvb3Qt ZzItY2EvcHViL2NybC9jYWNybC5jcmwwgd0GCCsGAQUFBwEBBIHQMIHNMDMGCCsG AQUFBzABhidodHRwOi8vb2NzcC5wY2EuZGZuLmRlL09DU1AtU2VydmVyL09DU1Aw SgYIKwYBBQUHMAKGPmh0dHA6Ly9jZHAxLnBjYS5kZm4uZGUvZ2xvYmFsLXJvb3Qt ZzItY2EvcHViL2NhY2VydC9jYWNlcnQuY3J0MEoGCCsGAQUFBzAChj5odHRwOi8v Y2RwMi5wY2EuZGZuLmRlL2dsb2JhbC1yb290LWcyLWNhL3B1Yi9jYWNlcnQvY2Fj ZXJ0LmNydDANBgkqhkiG9w0BAQsFAAOCAQEAETxNcbMk6rbnrLzRQT6qj4iDJTM5 n8EjeLPDeZli3rronlGBkDzcAdttMA3cdRCnDDvE8tjpIG/mnwe/gQvNqpy4vS5S KdD08F3/6Yo/uqt8gcGkLlKvPVmGlPGwdNQiV2At1JcGRYDcJ6t+1c7Yw1OgqaTW mtJlf8r7RunOpNW+ry0JIWye5ByikkNxITJSBHn4qPP7iY2L2WIoIxGWCNzFo//Y wOz4agGc4A2aI9s95F+vENuZwqWp4ttlrgrKLYM1/sV6OQcESQeIeX9bke06MCLJ VvRD2PhV4e/4vZzL/UliBUyvskK2lEFwmmmRK45h/yEcM8+KzFyEdIXXqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFnjCCBIagAwIBAgIMHDrUjCTtki6w9JCuMA0GCSqGSIb3DQEBCwUAMIGVMQsw CQYDVQQGEwJERTFFMEMGA1UEChM8VmVyZWluIHp1ciBGb2VyZGVydW5nIGVpbmVz IERldXRzY2hlbiBGb3JzY2h1bmdzbmV0emVzIGUuIFYuMRAwDgYDVQQLEwdERk4t UEtJMS0wKwYDVQQDEyRERk4tVmVyZWluIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IDIwHhcNMTYxMTAzMTUyNTQ4WhcNMzEwMjIyMjM1OTU5WjB7MQswCQYDVQQGEwJE RTEbMBkGA1UECAwSQmFkZW4tV3VlcnR0ZW1iZXJnMRIwEAYDVQQHDAlLYXJsc3J1 aGUxKjAoBgNVBAoMIUthcmxzcnVoZSBJbnN0aXR1dGUgb2YgVGVjaG5vbG9neTEP MA0GA1UEAwwGS0lULUNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA 1cwA90GCGWXXCQ+V4MkCc9CaPcYU0hrUc0mTyvbQ3DuOMey+w5aFI8JkmAD5CHsj jDWe/uuANc6OR828xLoN6EV4AsNMhD9HMelYZrGuBS2nsOVlGzIIf8t+RX7pDVQg Dc/UvczziO45HmLCoYeUDcqn9Qho8Jnuh4nXJdPCRB4UvcwtRCpYkgCeC+Llxfe4 IpdnvABTX1kwYR4TVmnAg3Mel5tLoV+WcxTdwJMpsbjFz8P11qMta53Nactef4gx BWMSEpDlnGL+swzkUfd1s+3NQkFKBbAZ6ehZivOZc4ah4iRxB1T/5v2Tza+Hyao0 4f5SbkkD2Y1p0Z5vdMVEPwIDAQABo4ICBTCCAgEwEgYDVR0TAQH/BAgwBgEB/wIB ATAOBgNVHQ8BAf8EBAMCAQYwKQYDVR0gBCIwIDANBgsrBgEEAYGtIYIsHjAPBg0r BgEEAYGtIYIsAQEEMB0GA1UdDgQWBBQEGr8ck5E909k9sN4TI+WacPQuCDAfBgNV HSMEGDAWgBST49gyJtrV8UqlkUrg6kviogzP4TCBjwYDVR0fBIGHMIGEMECgPqA8 hjpodHRwOi8vY2RwMS5wY2EuZGZuLmRlL2dsb2JhbC1yb290LWcyLWNhL3B1Yi9j cmwvY2FjcmwuY3JsMECgPqA8hjpodHRwOi8vY2RwMi5wY2EuZGZuLmRlL2dsb2Jh bC1yb290LWcyLWNhL3B1Yi9jcmwvY2FjcmwuY3JsMIHdBggrBgEFBQcBAQSB0DCB zTAzBggrBgEFBQcwAYYnaHR0cDovL29jc3AucGNhLmRmbi5kZS9PQ1NQLVNlcnZl ci9PQ1NQMEoGCCsGAQUFBzAChj5odHRwOi8vY2RwMS5wY2EuZGZuLmRlL2dsb2Jh bC1yb290LWcyLWNhL3B1Yi9jYWNlcnQvY2FjZXJ0LmNydDBKBggrBgEFBQcwAoY+ aHR0cDovL2NkcDIucGNhLmRmbi5kZS9nbG9iYWwtcm9vdC1nMi1jYS9wdWIvY2Fj ZXJ0L2NhY2VydC5jcnQwDQYJKoZIhvcNAQELBQADggEBAH+/QKluUYGThHAZeh5I erhZdIN9B488jjjexsfs1p0IHjKAElUaxHdjTfHc2zENqfPtc+EKRJL04MOUWJj7 8BSR2MOWu8WrOVXYmIZAJAzH1L1eFNR6cem3d1nsnjqtqw21EQ+/O/kXb9lIK/sv YDwudINFcdWE5UmOic9ZHSwFPb4oEeM97tG18WQkiVzKF1cM6nzLHWp78uRLwD1Q ek1y7eX5gc8iQSvv33wTlh0ppmbDqfaMTR/X/ED7SFfd5S9CF07EXj/XWlv7ps2g afR793FaPrPloGvghtC7pKT8uOMNBXC02Xq6drN6JlU+5k+bbSRcAd40Bqn6vyYA RKQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtTCCA52gAwIBAgIRAO8FGnQaHZQJ/KXkZA+NPJswDQYJKoZIhvcNAQELBQAw fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xNjExMDkwODMzNDRa Fw0yNjExMDkwODMzNDRaMEQxCzAJBgNVBAYTAkNOMRowGAYDVQQKDBFXb1NpZ24g Q0EgTGltaXRlZDEZMBcGA1UEAwwQV29TaWduIE9WIFNTTCBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKRzU7QtbSdi6uUiqewzx81eEdrg0RROHTs1 eXndSwxxUAVDC+FPYvpgWc+bYMVjUJQEIP+SNzsIGvB/YoabRoN7cLBDzPTgYnW8 Pl/wYWXuGNyr1E7bV9Fec37HlvhE39Ntwp31gjMFwTOZ7Zw0QzS7w9PjO4A4anwb maBJgrRa3GFSgoJ+WIr5brQ6hEgm7rKRNPx6L9Sj2aSl/EWRPPv73j5xeWGcgOPp U+8eZmqpX+XfCl34o5OQJWi/F7bACetVhvFtWGuLNcZ0eYwU13jOEx3NNsILzIYP oWJztxd3aPkQOX6cNbJGTvLRcfmGDM0ASq3/BsCrR0o/ruCcd6cCAwEAAaOCAWYw ggFiMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFKETVNxWcywngsrIhO/u vwD9X6tWMB8GA1UdIwQYMBaAFAh2zcsH/yT2xc3tu5C84oQ3RnX3MA4GA1UdDwEB /wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwNQYDVR0fBC4w LDAqoCigJoYkaHR0cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwvY3RuY2EuY3JsMGsG CCsGAQUFBwEBBF8wXTAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2Vy dHVtLmNvbTAxBggrBgEFBQcwAoYlaHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBs L2N0bmNhLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0 cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQCLBeq0MMgd qULSuAua1YwHNgbFAAnMXd9iiSxbIKoSfYKsrFggNCFX73ex4b64iIhQ2BBr82/B MNpC4rEvnr1x0oFv8DBO1GYimQaq8E9hjnO1UYYEPelVsykOpnDLklTsBZ4vhhq/ hq1mbs+6G+vsAjO9jVnuxP6toOTNBqvURRumMF0P165MoFdh0kzSjUts+1d8Llnb DJaZht0O19k1ZdBBmPD3cwbTI+tChOELAVt4Nb5dDGPWqSxc5Nl2j95T3aK1KL2d 2vV16DSVShJIz04QHatcJlNZLJDbSu70c5fPU8YiJdRpfkubANAmwcDB+uNhtYz+ zEji0KnE2oNA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtDCCA5ygAwIBAgIQUgo6Rp0UayApev0BXmSr9TANBgkqhkiG9w0BAQsFADB+ MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B LjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIwIAYD VQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4XDTE2MTExMDExMDMxOVoX DTI2MTExMDExMDMxOVowRDELMAkGA1UEBhMCQ04xGjAYBgNVBAoMEVdvU2lnbiBD QSBMaW1pdGVkMRkwFwYDVQQDDBBXb1NpZ24gRVYgU1NMIENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm0jH2RyFdaiFSKRvlSrJJOGxqPtsSYQnc9KQ p28ze/jEndY0bBrpbigBwVgykS9V1letXCmBhERn6JvIoQcS+SWTe7M8T57nOtqF cvcsI97qsO9j9sfYGh0vKrPDBKHbQVc1UtSiltwEKj50QzU5wHoKtw9YOXU4sYPJ Tnnlu26Z9YjwFLa8kTpRk/2tpAZzDkwRM9wEdd+nnK2hZckhTNr2sEI1VFmtz/zp 2Z5V2FROCAsSma8g3SPWthltbW/9uMIhMVzjYdD0BW6hiXKvfBHyEbKWohM6vf76 727YhrCGviVTtZ4W4jut3zFD+ys26/Rk/GpexXt10VKPjHDsOwIDAQABo4IBZjCC AWIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU3pcIWb+UaR0laNzsdtAm ekyX+xowHwYDVR0jBBgwFoAUCHbNywf/JPbFze27kLzihDdGdfcwDgYDVR0PAQH/ BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA1BgNVHR8ELjAs MCqgKKAmhiRodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9jdG5jYS5jcmwwawYI KwYBBQUHAQEEXzBdMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0 dW0uY29tMDEGCCsGAQUFBzAChiVodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwv Y3RuY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAA1z75lQZ9Gt 53l0lPctrZpL0wL8NcMCGywDBZmd7PzWw91EaQWfPO+wY5sA3fHuysru7GEgOJ44 6rIgw0gLZvEdoWHQOUEQNdL/ewdV8ahf94wZ+TsECEhRUH8Ow0VB09xCt8lXjO3g Gy4822dx1W8dPcX3R43xrxVkpxjhnW1YjfieMsl6dHGnm4MpdsyQaOdf83ah8Txg HI0sez3RGijUw42yqR1wKD6RNpl09quMamutReK3X6FRMb23eNtg2wthP161xWiP X5IqKQP63RKT8C93qGOk412uKl2KGrg10hV2ssPitaDlxMnEzPSmaUEAJ8tds4yS pgd9Eo38RbE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEWjCCA0KgAwIBAgIQBUNA0KLEzIER+qg3fUbgbzANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE2 MTExNTEyMDMzMVoXDTI1MDUxMDEyMDAwMFowWjELMAkGA1UEBhMCSlAxIzAhBgNV BAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMSYwJAYDVQQDEx1DeWJlcnRy dXN0IEphcGFuIFB1YmxpYyBDQSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAJRWo0VEVKpgZL+4V59O29R5aF8TBfQ/zSXdPF5Ydxyd5p/jMknvAjo0 U41S5eM5Zh/nM2G2J8YkVVAnAmXwsIxBjTBeR1uCb8ecoyhDbVh7yBWYTiVvy3Yn WwssLLWYI+eLfP13GsRSul0Z7nghTSGa2RJ8MxVrGsmB6traV7fVL84fS/y0M+Cg yZQnuydAtpDbrJ51phErSRktw8JDBwm7PW6Io+OKxdKG9mVbNMOfTALlCbosxnZm 69F2JfQwE/tYYKhY41FvSwgEYY2sqTAvUkGjIsEzWat7WfmTZ0vJiXVS7ylJNJMc nJNznBnOXBjNTAknwT/1Sez04t9Lr48CAwEAAaOCARowggEWMB0GA1UdDgQWBBRz qAhTKbgV+5mA5cU32Pg5e6QTBjAfBgNVHSMEGDAWgBTlnVkwgkdYzKz6CFQ2hns6 tQRN8DASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjA0BggrBgEF BQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTA6 BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vT21uaXJv b3QyMDI1LmNybDA+BgNVHSAENzA1MDMGBWeBDAECMCowKAYIKwYBBQUHAgEWHGh0 dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEBABqR cPGWxhjLeEP8gzZ29OHVpL8EFWNvpnEbpnAWa1uYmFNf0fsSoibP04UCB0Ye21KA jPNuTE2OWpgxlTVvl99sIJFKhXCIn6OWCLQpbjFMu8Ro5rdzg4ekedsihWN9NMwU +K8DqO+oukIYjF2zPnnwcSykKaUhdi0BqUtmzJhHkFjoslJllOXiJ4DQkbpjiQpR yjPfliI1wzAcOM3xxswHAxOq8BVHKErKYUqHkHgHFZ6Ycts+sShKqVf+Zdx9zYJV pItiSs0DDCCFapxWACouIVY+xPYG8EMUWXz0gK8SAwNHXLRxBtjNWhCGOiSN+ihp 277L8LbKp8eA8OlOMiU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCBMGgAwIBAgIDD+SMMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFkQtVFJVU1QgUm9vdCBD QSAzIDIwMTMwHhcNMTYxMTE2MDg1NDI2WhcNMjgwOTIwMDgyNTUxWjB0MQswCQYD VQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMTUwMwYDVQQDEyxELVRSVVNU IEFwcGxpY2F0aW9uIENlcnRpZmljYXRlcyBDQSAzLTIgMjAxNjEXMBUGA1UEYRMO TlRSREUtSFJCNzQzNDYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDf rxSj1ErmVWKj29MkGAfv0bcJ+DqtjWUK8++lCS91uPbnwhIFrGlHLLI5u8lKBAnh j7FlCUbLAlF15pCxRn78XhOhhRcaiBOvbKflsAZSgjncNhSQwCzsIO3QuEaKZ6FY UZwRFuvuISpzwvIovVsIn/fzyNHs91TfrL61AFjY5saIM7Kep5AqGwJ3oW+mXVci XqIdqmdeBjJxyEMlQa0cFeovvwu85l5DQN7T8xdDjnS2dqL9Wh8i7CpkHt7CkmIS nv1nGzDLZpDIfxPiLCUtcTea/QiFl+EHElqBhHyaxxJPXwflqFZuYAYSMt0Rk6xa Wb2uXtA1k9Db7wsZBr/HAgMBAAGjggKhMIICnTAfBgNVHSMEGDAWgBQ/kMh9xxVv 8ySPqcMvS6IPIbIv5zCCAQEGCCsGAQUFBwEBBIH0MIHxMDIGCCsGAQUFBzABhiZo dHRwOi8vcm9vdC1jYS0zLTIwMTMub2NzcC5kLXRydXN0Lm5ldDBFBggrBgEFBQcw AoY5aHR0cDovL3d3dy5kLXRydXN0Lm5ldC9jZ2ktYmluL0QtVFJVU1RfUm9vdF9D QV8zXzIwMTMuY3J0MHQGCCsGAQUFBzAChmhsZGFwOi8vZGlyZWN0b3J5LmQtdHJ1 c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ0ElMjAzJTIwMjAxMyxPPUQtVHJ1 c3QlMjBHbWJILEM9REU/Y0FDZXJ0aWZpY2F0ZT9iYXNlPzBxBgNVHSAEajBoMAgG BgQAj3oBAzBcBgsrBgEEAaU0AoFIAjBNMEsGCCsGAQUFBwIBFj9odHRwOi8vd3d3 LmQtdHJ1c3QubmV0L2ludGVybmV0L2ZpbGVzL0QtVFJVU1RfQ2xvdWRfUEtJX0NQ Uy5wZGYwgb4GA1UdHwSBtjCBszB0oHKgcIZubGRhcDovL2RpcmVjdG9yeS5kLXRy dXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENBJTIwMyUyMDIwMTMsTz1ELVRy dXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwO6A5oDeG NWh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jYV8zXzIw MTMuY3JsMB0GA1UdDgQWBBRqF8nR4bDH7A1PXpoQhikz6YXRRzAOBgNVHQ8BAf8E BAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEARCPc wLJ2JMlAhkBNmpKJptGYMMldD3OXLsZ/sxsQrvJPEvVlPon6ylJJmHTW66FQYBQe eMDtbQFZMO7+F9HmepB5VmOwX8KzBX3gqf8VJQlFB1c5iOPl8Z7nUOEG0ivogfaT UFfWnXPKc7usKhqQZETqk7oX4HBdP+w1YQ4royLTi5J4EBhD+CTL6pRbneb6m2pN ep4gvahyQXuhz4TfBseuwbmOC+SmY3TSpS6AMVJHqomhFCf3wkuxyCj3LJY/XRfL nFoglWxOa4iyKUl7ESqHkKp3DPRKzM7QRKGFQeW9jM1R+ROvBL49YoHFQ3rhj3Y6 eKIik0cnkIAEyplgiA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHzCCBQegAwIBAgIDD+SOMA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0xNjExMTYwOTQ2MTlaFw0yOTExMDUwODUw NDZaMF4xCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxELVRydXN0IEdtYkgxHzAdBgNV BAMTFkQtVFJVU1QgQ0EgMi0yIEVWIDIwMTYxFzAVBgNVBGETDk5UUkRFLUhSQjc0 MzQ2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4PbGGVT4nCH+CzaZ kZDWqXWiXbBu3UEpSPBmAKDepwkoc7b13vVlRrvehBm11yUNzaN7thsqB+VXEyF4 OuxkCJkZRCJUfrS1zdnZXptf361oahCX+ch2E4Hdedeet45mypwKsD7FqSdz01KY o6wFQMnnZsRQtamilglAgT03iTUf+Yn8a5msV7fscpfkLUGCtjeM2eWgfZ2I0pqi m3DYrQU5/8in6DtZLrIAgZpnQsgJiB3glx0YcBXs5YZR9bfhOP71nLvM+9vkxNR4 V90SOnwEzCbj5VforuNgP0sptC2TSPiqNG9sgdySBobz9aO5ryqG21GXMcfFp0vC z2kxrwIDAQABo4IC8jCCAu4wHwYDVR0jBBgwFoAU05SKTGITKhkuzK9yin0215oc 3GcwggElBggrBgEFBQcBAQSCARcwggETMDcGCCsGAQUFBzABhitodHRwOi8vcm9v dC1jMy1jYTItZXYtMjAwOS5vY3NwLmQtdHJ1c3QubmV0MFAGCCsGAQUFBzAChkRo dHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NnaS1iaW4vRC1UUlVTVF9Sb290X0NsYXNz XzNfQ0FfMl9FVl8yMDA5LmNydDCBhQYIKwYBBQUHMAKGeWxkYXA6Ly9kaXJlY3Rv cnkuZC10cnVzdC5uZXQvQ049RC1UUlVTVCUyMFJvb3QlMjBDbGFzcyUyMDMlMjBD QSUyMDIlMjBFViUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NBQ2VydGlm aWNhdGU/YmFzZT8wfwYDVR0gBHgwdjAJBgcEAIvsQAEEMA0GCysGAQQBpTQCgRYE MFoGCysGAQQBpTQCgUoBMEswSQYIKwYBBQUHAgEWPWh0dHA6Ly93d3cuZC10cnVz dC5uZXQvaW50ZXJuZXQvZmlsZXMvRC1UUlVTVF9DU01fUEtJX0NQUy5wZGYwgd0G A1UdHwSB1TCB0jCBh6CBhKCBgYZ/bGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l dC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMEVWJTIw MjAwOSxPPUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9u bGlzdDBGoESgQoZAaHR0cDovL2NybC5kLXRydXN0Lm5ldC9jcmwvZC10cnVzdF9y b290X2NsYXNzXzNfY2FfMl9ldl8yMDA5LmNybDAdBgNVHQ4EFgQUIa9qJphx6SYK 1duhjPfbpp2lJVwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw DQYJKoZIhvcNAQELBQADggEBAEITrEZFU4bOy+274S2THOe9lewgYy+5OYh/Wr7Q WzRi/bMU6GRtag9fCnIsXon3+2wKGL22JgjI+WnZa5TRiazUOdtOjCEuwxXXMYH/ PaBBb/BXmfGlEHGHL/ljNQauOrsfIQXXDYTfZk9jwLQgPmF54Ulm6oLsUrvYp1nq 4jSAyWOY+mcxFlGgZPt5jdL1DSkzdLtdWfGs+1USqmx/IBZLfCwavdk0Dm5fwQSG iI+av54kU0E4ziDEOJ25rfiOBGqjh+4NFegAaQlTeVp1zOCjtKCf9YWDS8BgJT+O Ri2UKV/O8WaWZ3qRLuVavpng14sx4oa8FLM9sKBWvI+H5XU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCA/KgAwIBAgIQHcbTUEroVK5ze23iskO63TANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMF8xCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xEzARBgNVBAMTCkNp dGl6ZW4gQ0ExDzANBgNVBAUTBjIwMTcwMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBALfxK9W6qwb/MnEzDMxVqC/4pLUfPJDXY3un1BGP+X4RlK558rs/ DxOgLjCB91lu4wEtElhj2ii/GKn28csza070I3hy3ZSR4lscSc1iiqm6kGHcg8AY B8IewLgpBtW9MuFqkxQwtMIz15iGdA0Burw88faAfocbibWvl9NJB4kO73oiJmWS r5SFu+3sSjIsys4cTLJ4zxbqmXaiPUO56HOUAjCkQb5wMh0tVCSaX64j+j5KvHT6 m1KbqwkL04aPFa7CqVUm4UyQOAWjthBb4QKwDsU8U8yn5XrtiEkmLvep9+jlcLCN y2sTeBrHpL3yWmqm826qUiK/XvIt5AWzZ4LLGDh67WuZpowE3u6o0kSpmw+gtoBx 51WXHEUBMZgOV5frzD1AciL2/sFiNK8zi7pTyiFXQOj0/p7Jn/WvSmdO26ppQ4Tg KQ3G8S+xLgW8hTnUzF7a5aQC/xat1MLDFRqVhDHBLMXw4mpJfChBlS+5AgKMEQmM AyFEYNETD8LtHigvt8q1jykSybt1Uo3vjhTc20yyAslj10c7busbZMdSoItOk9Qn z9o1WqVt8DUnSXp+4p4u8+czcXD6Nz/gB7sIl35A7pvduuqktRj89FxnrzCt9/j8 wgdEljQKZbaeyO04NYACENmOclTHe64k70Um218wMkLMVSDd/qbBIyipAgMBAAGj gfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0g BDwwOjA4BgZgOAwBAQIwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnku ZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFJ4x6xXiksWm1L4xIucLguKdIWNNMDcG A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1 bTQuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRn6PFOT7O18wdv CJwMg9l62VvnSTANBgkqhkiG9w0BAQsFAAOCAgEAF2ej7deYgM+jJvZ+7GuCyN7U DJ+N7EcEEx1yqiXHG3wRfGoy/j8/SL1awLD84JQfTNQYJm6WrfsWPH6O3A1Wm2Xe /D4ss+GUIPStOpxZFzhRMdI/RTjH7YwGiqRDSG2bkS36zlpwk+NlrFNutN/Y3JFa N6nj3gIf4lDfmCiLO9F2A2xZ5Kbo/gU0WXbShcBKw21rfhuY2lKCespOCES1JzUy Br3s09feUwXW5hjhlci2YqVRbvIjN1iZkfsf8TTYlu2o56EH72/6nlkGqXqYbF6o YsWNIfAqbJ54optZAPnEdnZd+cQAL67FtUgV/pla8O+DT28zQTHt0/yK4nQAKR1N ReZfNRCOt7McO4iTU+3Epq+VRr/c4eSYdwWIc/zp73mtLSnhI3sJ/7km5DOqftPz C7/ND26oUmt+Q6odrglTCsutTxid/Ym/n5By7IY8tnM6OUmRuJjJQyvHJ+8RyvlC tbT5LeONHhT4jtmGq7gw7ELCvOgcuo55sSaXbWxdpmGlA3Detq3rOdr3+jB0J84F uOvzbB7THfnxEIl+WHumvsEHLkU74bzL7EI2ujXitQz72xAiEVw3iuX0DDex5xPn fLoUmcxSWmMRjH80qvuEtEtzlEEBepg/vog79bszBxwAJ42rIVtNp0A1qS7G6c77 9Ww4qws6H2KHOG/x5LU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCA/KgAwIBAgIQbMYMMd6xhhj11yWx/jbkSzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMF8xCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xEzARBgNVBAMTCkNp dGl6ZW4gQ0ExDzANBgNVBAUTBjIwMTcwMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAJYpniDx9+w8WkQdSF/GEyeaUUncmWB/AHMuKPahpmwsB8SyZca7 /in9X7mgheUbGCC9N8ETATYwuItqh1UdWNd7Oeh3z5TMRNFxv9Vga5BTO17PPNHS uiB5fvwePurWlHYr5/krraVTJppXep7JcQb5g3ka+n4i1h4NVuruJDOoMOLf7JJ6 ZKYcVkPqFHmFvt0EbKg/yWAiPRl6OnnnEVTQjx7KGb8tnWYv2E1dq6OLzuoEtkxO vUoFvSLtt244m5o1sG3fKbBqQDcjGS7tb+2HeMu74n4Dkov+r7Ztux59XIDC3qnM XLCvNI+YV/T/idRDstMrpzY3nGZqGN8H4dLr5v9EGqhiUJaPQOi11dHSUBUof7lj 1ju3LSVcowBcgonOnLkIO4xU+07TWg+VCGJbAgk4z3SczsJqfppLF1915PBEW1Yn DyX57nHdL1zgaHD2wSJPrVJBjEENPMx2kpum3xP9ffu4uZugNmX2dBN4CtG8fFXe sGob7EV6W3ENCu3e9ETAcQ3skgLb7FqvP/nIet3ICfVCrXSWtA/IPczdMK4ibc74 oI3xJPSVb6Kxun/NCJrc1facLYDPEhpWOoSIOJR6VQnecVDZYaSJcquQ21ue9eUa hgGh4u3k3MWb2xtCF8/anaFGA4RXbwfajNLsmO0kb87X+IBFGH0jUHVVAgMBAAGj gfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0g BDwwOjA4BgZgOAwBAQIwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnku ZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFGUOeUxXjm2va1oJNDkQykeHSaTBMDcG A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1 bTQuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRn6PFOT7O18wdv CJwMg9l62VvnSTANBgkqhkiG9w0BAQsFAAOCAgEAOAmz/n/0u06/+F9n3/d2VYdg g2yo+JUpAtXdqTLaidz0e55o8uEygB0xe3CEWlIMOHE87+DoIPk9UQLh3Yeb69d+ NZH+TNZiTVPsaHRn3hGTAVDJx/074eyOcBNz5bqI3T7mvrvk5nv3QMbMV1j3WipQ 2jQzVEY/n+cSkhv4LofLuGWA9O4ZxZLU3b/xTtuXoOw5lIXjl69y2ivxprsxRflB 1EsnBa4+SJBBiQ3y9Nww5b2lMD9f8pSCAvnOjDsOX1lvUvxMtBPKXru3jdvViBz6 bnkh8lxUPrtISxUxZwWaR8BN2m3vIrPhzzrzLswRvfsy5CPFu3eD3MsI/JoJe433 HOnCwbVqoZ5iMJIh2735P/bQucdSJl+1zvfjspLC2IlcHOgoJ/1Iq6RleILOJFq5 ETw1kN5mT7e5xhHBYEgTkhSiJCCIin7dSPl94uZasrAGvQYPkVxu9UMhFnhzRpmS n+7athxaq5/QvHfw/PSdtha1nmT2ELTjzxFMHUHjHoRtPN/I1a3r7foCBNHy2zV8 PHvOKDxXQVFX4KzePy/GeDo1c8/cZn8zgEcj1GLc9zXaVtIFekELIsfMSEOkvxBf ENehZKxg77vjJBheSOKC5BtTZxYuskMg3Ezdi6xLOm/wnTd0n1hFoKHcjBEEeuwo Ex5+zkeqll/YhFhujEw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCA/KgAwIBAgIQUGbyTAF/32p7j7+9Cl/RxDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMF8xCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xEzARBgNVBAMTCkNp dGl6ZW4gQ0ExDzANBgNVBAUTBjIwMTcwOTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAL0Yz2w+hpbW5mB2fnun70+MeN+T8xUS2+8uy6BAD2aKg0UHweD1 Eah4S9hfIqyAjijWm2FXn+gfJ6m0tFYXB6bJmU22nmmcLvRLpp0mSGv2CEu2DeAh tDU67RQIEMlXf8MZj58cRqO/W/PRfCri6mRX43qs97hlcQJmUaWGVLl5X8dLHbhX XwXtsXaKwKWfLMYH2qULP0L0we8uprQ9FhikRa6oslLS1x8CNheJEUUS3jI+qUah /4u9Q4vuWAkIuk5RVZ+cRFUtzk0c2wuY6rQm1pf46DPNgLd7t6wQpLSAkSIrrOvh chY8Ae6tXU8RVYZ1leUHTC4P2g6CD9hBR9hCf4JRTdTI8tp9yM0jkjxFs9nBdAyW hSGMHtcqzSKDPq891OF0bwVYSY1QYZRp3ViQGJyMnochrz91TpDSX8O5Af7u6ra+ NB/Damvdogv+3S9ycCju99H3TKZ3nbJHGzFgRizN9TM5kgI68vGuA91UsRbA5b/g AcR0b3kjFvuNmjkrrKfTjWdP/lco1Bv1Tou5aBr4AaXcfqwlM0NkTKizFiKjrljk vtmnY21WkSaJ5IhHdE16ukr66F8e4xtVdbNmuxhyupqAuNh/5aOSdX4mxSXc/PkE 5Hy4m19K7xMDthC3ZpASwvFIQmMYBVgoZqWlZY+0BbkFU6CdyH/EUNFVAgMBAAGj gfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0g BDwwOjA4BgZgOAwBAQIwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnku ZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFINimHCc2JjWG2gXqtkjIXHTD898MDcG A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1 bTQuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRn6PFOT7O18wdv CJwMg9l62VvnSTANBgkqhkiG9w0BAQsFAAOCAgEAkb/zHGCmO6G7oW3PflPgXFfh ggugQjzh15fMIyFJZZWpULpPcLoN/BIL4yZxbQU+knJujhMgV8VFL6t+aaW0Qdry jmED4KB8B9YaciEXaVmNppdGHmrqk7DH+c7e+/Sse3/AegJdeUQqgOolPNbvZcPn 4CKtnlD+j1WRBgIyhXhQGjuEfQfr4l/ljlS4rA0KyMpFWWKce3mCEsJWpyFifWEN OS+oKxMEaFnYw0miSe40FTewSGbawFrazH6CNIgLaUUhC4ei8AG1rwmsRYfLopQj VqUShrk5SHVNI/dONFB93MIxVy/ZBHn9aDYHQMs5J1IbLJkBBlm46Mo5FuQZTf0b jhqzlKBi1qa0B+RJhkLq2mJ5lSadpxvxofzR+9QLvp9IeHnUcdNRXLtz0lQt9Q1D KHPh1ZqZnaDItTiwHPhhEkxZEg7Ri1GDGIivRchZoxnt5nxDa2GGXWHjZUzEgUbD Vuw4quJxPxColadLuNJ98AKpUz2u8MmsaAi3/imVBNzn6+t+DEUYg0kduVMqIy9C 4AJ7YNac9DT19ORSUlABcs5L/HqC/A7+WY2TNCfI85OKRJ0Mef2te7CA4n7strdM lBwWqXcBqynb5/t6LVtfWLRDCQfC40U51ZFwoWHmDLDehtzWFzw7w87/kgJ5BCep tlmiYUPGZXsjwlx4ACQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCA/KgAwIBAgIQKQc4XqZ44yAMYQqZCbnP6zANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMF8xCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xEzARBgNVBAMTCkNp dGl6ZW4gQ0ExDzANBgNVBAUTBjIwMTcwNzCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAMdeB0IJn58nBmeeUAS7xHysk8OQySgOC3zxy7P7lKmG4phcDbhD drI2y3NPE8cSMdFFDbztCVM3eud3Sroq38AGfxPCQ3xteHTI392kxVXiIPjZyEh7 YOPOhAVEtnZSmFQk8zoYIl6/nJihGmyFwTyyCeQHZoknjZZKBT9/TA8elRAJpwbt 5Am+PQSdBs95GHVCP+kziMigo46l5UxiIHGr8/W7kJTpUuyo0o4/ruvoBpMIslz6 IeWWOAjilm6z7Yq3eZvmZV3dEKnePGKBkJmoNJqYBI2LyTs7BdNQ0tK0J+PdEGp6 v4B+FsJN713t4l93VaHIxIEc7P5Y9QX5dUjfELkqSFsY+wKPiDJWhLEMKbT+BG7Q 17rl0YAFELk/CwrD4qbN/SVo5OugKQdEmbnBtGYbCoW8mDXJ1DHcuFWZh3tDTvuI n84OFDDqKHcDJKMDau7AqmedbK1rmRoUCR3+OC5xvlxF3Ukhgxs2eVcRAKVaWJPp eWl9aqOda1gN+Y0Uk7KRzoJ2heglzXZmtAdWBxpW8RMNGd0Z/tkEDvlEwN8wrTB9 SSO2kn4Jis0RTJbyhbPaCEdn2P/MNXUI7V6yvNR3rvA3byimYi5WvswfGaU+FdRr hB1iRBiPOVGUu2S2ZsxFWbwDTThLeBEeRvSetXoSP/Tbx9DQwux9vke3AgMBAAGj gfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0g BDwwOjA4BgZgOAwBAQIwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnku ZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFKj0gpCDd3149nEe+9mJu2C8NQoWMDcG A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1 bTQuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRn6PFOT7O18wdv CJwMg9l62VvnSTANBgkqhkiG9w0BAQsFAAOCAgEAjJHyzcbo7r/ZTujHJsn7JJGV 23qWk9pGUq7JTRFaiEJTyqa0kfPbIipwxMALiwlmIF0FOLhE7UjjzHpm8sgf5TIp XM4XYD/tISod/AAeuecGcWU9sO3I+f2QXXR4RifgXvdfezQKQ+S47vS8slQgckE4 xib2nw1LQY1Psgvbe8KizT5UtNZPOz9p5XdyrLPcJQpmxW6uPYLbkuub2s0qDDYc YxLPJWZRtjr5uM13LyvhPcMh0c/LZ2f2Cc1PW4PltvEKr0hsidceFxBr9na4F0Yq UbhmhhphvaWyGJmes87F37a2mHX8S3B6Z3dTNaqRSZtkobYZxK1HOBSUsJPVgwSp JoHcV8gd+H9a+W4B7S0CMhakgP+fVY5pAvDcC8qTKOLTmeRyzb2EIWipSZ2GeRJH wUlDK2n5o7kLojO3bU6pBtiltJz6gFgNwuv5Pz2SaeUwULMtcdpB8sfYY9g4AelR GeEPlKsYRHOLjQhCnSxBH732snLGt1RDVibTao4Gj9EJ/MIJ7IvfH31d3ghje3pT Hb3byOLjxBWzXn9F4wXmuA51glbzCcvhdTszcQeXQ/gBT4RZ7uHue5eCoiQUjqoV o2NM76XbXbFkKlbe3YqcVem1Gkk8Tk2yrN8LCTU4C6YR+NzgNCA1l8bzsrrV1PKr ihsFFBS8B8uob7uSPs0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCA/KgAwIBAgIQD4STyoyv03d0x67bvHQ9tjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMF8xCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xEzARBgNVBAMTCkNp dGl6ZW4gQ0ExDzANBgNVBAUTBjIwMTcwNDCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAOo2n/TtqHItz07Yml6/wDDdDQbSVspRxysCkZsIMBfUO1RuHgiB RU5gpJZMlRDvcEoicJQfeHOo0CntlsbTqwi0NbMEr+erCCwvxor3aIHcGm9ox0DL qEAt0KbjAPemXKGRLG6vreyiSx+ozGhG1TkzYE4tDISox90vB0fYMcndRACvkfiV wQnxm/UCRD5H8Woi7CM/m+Jc3e+epNrAxI3S9sEQPkbezESnec/AHukWETypRE10 ONo2qkIQsF+wZksYHZRlFIeor+kq0YIC769hdK0etlrMMnw3FxFKy8w3f+VWRzWf 5+0fWIhF+J9qkSKyl4TFaZiS3xuSch2uft9ddduVIQk3Vd87XlEzioJAXRei8kY0 zAbvd+vLl1ljifefgJ4JOMKkQdo5ZO1fuuap3dL0+srcByCLINJSFTeTw8Lb0JdU Szw9W5va2DUsBJb1AeUn5NY046CVOPN45saISKeMLEzcjTLjq1cmrDs4cfGr11qG GYc7IhMovbtMN/zalAZBRWDxoJ9OwFBQ2VKAPW2S1P/cqVfY4FqjgAfNtlLbmfJa uEQW//JhJZJdsPwkW1+WeZ0rdZ+SbJTgqveOQLmUvAVMP2bKDm9HwhHxeK6+BlvL rJ2XCcmqlE+8wp9zZEm+kuA0SLA0cWCl18OKD1U129eabO2MJwuJOAyTAgMBAAGj gfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0g BDwwOjA4BgZgOAwBAQIwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnku ZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFJ0eVZjapHeEVJK0EAE0yQh9kkgcMDcG A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1 bTQuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRn6PFOT7O18wdv CJwMg9l62VvnSTANBgkqhkiG9w0BAQsFAAOCAgEAKqagIHWXGthtNzIxnPawG06T LKLhi4xOmCONAuVvkRrbaNejOxwe+N7o94GSr5EYwkQOLTtmKSopGxWNwBMeFgFg 0tA98tmmRgLDcnlwZBgutRviZb3n4h2d7Bt6QAlf+mzdkCPPi33JLvEeEeVFhVZO ZnLzFS8Vd34jZMRywRkH/CdZm7m15ixLy0vDszHQl5IxQPzhoKz8EcPQAVG+SzkN f05g3R2o4klsRZpXxbHJzLJBZMWNgu188jlq3cT1Gcp4STYKZ6+cnRI5ThD45KdK PHtlVyLOOckadNd1Vm7teM4VplN3HDqyXpFe0xUogJ7h+GG1OwOIjRT9opVQAQVb z8vvL2X8UR0kkb3Np9oKkjFpc+cIobwBKRToWOWZV0Ifjgk9RTYQGrEQ3n6XpbIg mQScTrik8CXSGsDPvxrfktI/1EVbH536FAnDMFWmsm7JNFZOxR0T7oUxfCArZLcM Xw+ygStFVwpGgTmV3Pk/EyZdIjKHO0vhZCLHrTgVo9ICJvUZCGMLh28l5CPzkDba h+RBAmK2R3EAtu7sYKPw5CECz50WFcRB0OcswdxSFT5yBV3UXwePaL9p6N9164GT wVCdieMwOC9lOR5N8g95R19oFDRZITu3f8MNdlwkRUMfZnyVccsihZT4DPfynFKg bZlKM2gBLxHLRI383go= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCA/KgAwIBAgIQE685K8QdXAR185WZ5mGXpDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMF8xCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xEzARBgNVBAMTCkNp dGl6ZW4gQ0ExDzANBgNVBAUTBjIwMTcwNjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAK0AmSph3ppg4B4pfk1iea1XNZEsjBhy5J5DHTVyz+878PpeFuax QQjaPl8NyyeTCPhChb9H66xKFODkfbr5OOfC7pCmQ0ehoLOCfATJhfExo3sFcABI /pNTPgPnrmZq10S7mD/o5mMmRvBHw/G53zZ7P7TEdumLKebLmmL+2VKXw3TN3BoS woD0czdn5LCKpQVVqfUtAzctBPwbmwrZ5NV3tvvMlSWh+3+HbcwORLFZ8eq+4tNY Njd7lVeORVFpOIazhosSRjpPfaC52Abf/Em0qvOZgN4lDLez6mBVAYSD8LI+7/Ef 8Ekm5AEHlGqx8KAEoCEixyr6U+ZfBQWZTpuu/bCFvuLeEbNNZn7N2HBytmiatODq NVLLVoO7xNz51LZqNDnH55HA+jK2nmRBn8RQglJWFy2VLbEVVhQKek+huhKW+1F5 F2alcTofeS7NyxkKnHx3QT8dKCuJSnd4zVvQ2zO21OKGszq5qkit3h/JOz9CHUgF RFMgMOLN0geqbsG6kQHvyYRaZyjZaUE6ncNM58vkC/Dy8o1yMJxEPWrtMEU6BUj9 N3Um4WHEXqxaGdgpg4URrPN/mCO5UAww3i+Ym/zNouLf6g1V+7cVT6fzRuzE1FmU i5l4YDGKFd4Cuyh9nOQSYbqgtrhUkMcRKO6Y03P76P0SIWsd7WmeqNorAgMBAAGj gfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0g BDwwOjA4BgZgOAwBAQIwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnku ZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFFOSKl19WAIl5g9npDGSgwb8BSC/MDcG A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1 bTQuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRn6PFOT7O18wdv CJwMg9l62VvnSTANBgkqhkiG9w0BAQsFAAOCAgEAaQMdraDZGlH9NCrfW1Hh9ezh SDMJwRbNoSdjqAP8DwCRciumOywcXhnzTkyNcvRJSsiPK8P72ifSMKMMzfkyyYcN 8BlyAikUHHJtiirkUYU1WWxFr8jqNGbmbR9kqzgRPXAq04WqlsgrGaCeBOgWPjvv +SLDqOu7hrbLs8BzuxEOeDscI+UxAygAV+SgQp+hmQszpsq1wvFAm8azwjvcMJad WqqN5hX1ms4gFwU2TDPb/YfTs3nH3dvRngCjGkzlXgDLByJhSxiEQz1iY2A6D2+i w0jQE7aLDlPdGpnVaJ7ch2ATbLriaFMCwq2ddVcCjMtF2Y+vshurtTwOMsJtZ4UT xp5ywEBWpzCLRRV/6XHJsd5QwKxQPSnKr8riwkVDNQBewnqQI3EmI7I92Uji3FmM Fl4sigVZDhZhUnR2VAqJLfQl4w4Uz2cJEXYIRgmfaFBwIXIIYBkyy+yKKPuN4Im/ o3Q5E8qjw7zC4u3iliYC+JpFNXf158hqAgNKvNJb84SX4xDL1EPLx/+GOu0Opu3i Gh68hftxb65SfU901rf6AfygZifLEaCi2SmQAEPHKpHOlCZvwlXStT8W3w24rfFl GbLWGBzju05CZ9vLRYdf/fUwfePfdVy9T/vOyFWmfSjAyDrgu/ZkGbhQ8GY4ROk0 YZkeycS76Wfia/IwSjA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCA/KgAwIBAgIQOQc4XqZ44yAMYQqZCbnP6zANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMF8xCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xEzARBgNVBAMTCkNp dGl6ZW4gQ0ExDzANBgNVBAUTBjIwMTcwNTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBALWLE/VMuLUvtU7JicRn0l5tnc2Ur7c2K9BmE3i1Ffa4BtXvHgge jtX6qFMvCLt1V13Q2NBg+1eZiLLLk2FnO9fA2Xz/wlFoWgR2cbdRUcc2C0iDA3zV iy49lqae+OQKseGJHyJo+Ot6pQXJCNtl/eIkya9x2bG/xn2tbSGmdhnBs8hUk5LQ LbJGQQDqxWBTsfdbqb8Kv5LyGNPiAzOHfxRfyG8pWcLDh0w1v5mJPMVdFZgdPjIK aEKNDgDMsjr6lvElaXkEo+mr0nDIyT69PgPpr+f8Y4j9oyjGHH8szUrinTtw8K02 QZqVXTkgEJrOCN5JVUjhIuAE0T+43MGEHCuilc1pOyOcuR2kP6kLyDYYQxevpHlB lcsi/shf6qQgNHpBPS/rVz8l4z+QCyZ/ktNVxnf3SX4ZUTeHSN5jVxi+sJdcqiZD G7psLdAKhGD/l1J8IVTYxKbmKSvQbsZW/GtYx35XmTBlNMk/o3O1mOwgZmM8U0Bu sjgkRfjvlCwQYF3aKfa+J3Qiif0pGsT5fxTtbwEd4epgIruTrfJtruGX+HA43P8G SbpNWMy1fR23S6qDCavc0yaSkyq4p1d9DSGFGQ7s8x5jBAsH9mpXwuaedBNh49bz XRwS9xrG6L7YESXiKx7bjcwfXufuiBjG3dcnngD5DV5kD3DcWQr7HaAnAgMBAAGj gfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0g BDwwOjA4BgZgOAwBAQIwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnku ZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFP83jncpdjiVAQHsjfwoDTAjusFNMDcG A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1 bTQuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRn6PFOT7O18wdv CJwMg9l62VvnSTANBgkqhkiG9w0BAQsFAAOCAgEAQB1BcrT9sPdpS3UyfW964gIJ RpGdfIv+ON/cEgqu/bLpDcncJAILWCsC3IXAt5y1GVyRPZ73b6H28ienSYtYdx6p CuP0Y5yOvoDl8MWwKscbivBzN/TGQ1COaMuBo6ZtX/EE/F98jPfSu04pGLfn87nA evxOSUtnSOS6/1w8V6XI46D9ONauvzpMifWZ9c0ZBkBsvAILjG0mY1R0kEGKIYVw 3uBtx1GpbDDtrHiai1Yj1WvamDCg5X8lAMX73vm/zxWkvCvzZUn3Iy0/CU/ZhefP 0Byr4GJYaTPvki0+X9vG2PvAfevaBeHOe4hJQp+NfqnU2qlxNN+NYzmnbSwR9P4P FTqShB5KX0sTWJaA2DxpJ2941OkdBNqtP3EGiysBIjHP7HZdVgqxdAsqgURJM0lx UK1o4euKCkMs1ZAJDpKFeW4mvDO5Uh2SIsb84JAnkg8UbBT4QvsA8y9bMzPRjFsT kVTJwAE53lOBYnFfAX2Cpc7UW61VlwZP5SIAcesb1aVQJE8L85lYojcnbuU5F0Xa uxtcU0dbIfBu+CCV1cuDfBLOF1rMRijc5/On/UIAM5EyiW+pyCU1+4qJYqCgTt8m Lx4mZQz5T9nb1xcNPMUiUb2SwxGpyr8liJG5NgK7tSXoXF9c/Mj4nw0RMkg346Am aju3NbwjyG26u5AHX0o= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCA/KgAwIBAgIQTCLOWPWydrJeCTp85e6DDTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMF8xCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xEzARBgNVBAMTCkNp dGl6ZW4gQ0ExDzANBgNVBAUTBjIwMTcwMzCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBANMJ5YuHRrBM5KHt9RvZv0fylEK22/jT/WB51s2Zd34aYh3MGMHD qrXKZfwM38Vs98a52237aq2jH9O8bXJoqIMuqsRHG2n91INxYdc5wTuPNKrY5Wgu L7vv2JDQTMmYHbLyOxBR5DPbrWiTnV9/iYRIc1ZRSDibfhswyg5UULif8J3HczQ3 0OjtK2bIBTZJ50f2xyUhQydK2yUgVQTQLjyz11/01Neal/OhMmsrGqBb3LP0JRXC JpufhV052TnP+tfZe92YWRJHUi3qV+fsCp61QhTTRyGRSJrOkHBup3QEtFqZjunP iCWdSMQL1l/F6359qRVMMMR2L3gCT6q7AyfQflQs+pX/8VvzAFA+zpie2JcgQ9tL Wp2r38pE4vR4LEXQMKQZoy6//yPsRgovNG8iRdtb163ijkr9zOWfSzmtWuoiC5tJ Ux3yORe0U3ZneJQ9+bIgrPF5RPaB3dQv6m0fdnbdRRye1X6GkU9i7x/xoubm2sNa Iu00IASapLWXCZ071GgqOnZz2p7lxmscP8uS2GyCt4WdH44LoEYHwguicZgyG6Ec p1g9KXSiEJTdlLBZsVxGd+VhjeJeKsCBdlATMCzq5SND5y4HqyikiqRehHGUDd32 4LoVBrMUCtYDez9cfMu7oYy/bVzra2GYdD/CFjmhl2sAajQw+madkOv5AgMBAAGj gfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0g BDwwOjA4BgZgOAwBAQIwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnku ZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFNiImzxV700/+6mOq1HnamfeBk9zMDcG A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1 bTQuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRn6PFOT7O18wdv CJwMg9l62VvnSTANBgkqhkiG9w0BAQsFAAOCAgEAOQmnKI7lgZtjKfCodLlHtnRe g3+Quu194RKimPNJohUDdnVAr5II3S4WJItASnTtBCsPP8gJcsX1x1g3CpHHtvTl WLCf3irxsFD2djtL5EI5vmAfmE3dq3S6laam0gKEqGEjil3t3QCQ1hlX6Cl6DAFB eb6Peajn6xWh7aKDFc5UW+dllnacQQkfEDZdhrUrawRk9zNcpTFOdG9QDT0n0pfW 2kVMmp4XvCI+RJ6jsWPon2kyKy4wDI8ENDePM67vYHD0eEsAxGZuyuc+3casLDQN lvn9wwuLmQ+tf2RT5C74lzK8MuXCDZAwTa1PdgPv5O8YxzxFS+aKHtxUq3PSVjIT IA6MXCrepJZpkDnH7o/vHZRl/r+7QAsQ3/Qh3D5rJbYWwoZVELid4SqdaqxmQMYZ GjIL2tzzW/ohusdZsy+Rhzlok8vHoTB6pRS2TClFxX1E49MgiBAHLXCZ6biN3kpt uoO9n+KQJ+vc78CazR/a4IpyAi7R3vWv/9WfISbabdBAbfWMcg8GvMiF8aEmYytn 9ren7qWvBQsE36bMyGoEn1xEYTvKmFMXvh+TZWxR2hHgru6BQOv1r3FWy8V01kK8 6LHjxbGwbijkQERIYTF5YKbuis1htVng+4E6Aq6N7+UWy0piaT/QY34zQOwpStVu 1lA0O21DxBaYAviwoV8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCA/KgAwIBAgIQFs1LNXWijD8GRkg7oPN6QTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMF8xCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xEzARBgNVBAMTCkNp dGl6ZW4gQ0ExDzANBgNVBAUTBjIwMTcxMDCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAJ4IHbaLsIunjjh7RLh2DE7BYGiShiFUVeuSc9ksuWhzXVkvwpRx qVl7cgNVjaQ4W1XRBcZE8gXhU/sesDhSWL8wG2QsVm9tNoIIdpw1/0LqNDU3T/7E c/oyCg55DpHs7WleJ1mhFRwJyo/IJnFrWaFMbYGICg+xMT5j+I/7jIeMcXyh4O01 i5zxzPm769IzZldaQMnGz2T3L6573iX1MM7NgARaz5JmJVO5+jFFzov2ldkaEMeH Xubw46Z8FS7kTjhwjH+rfnXSeUKspP0ExKTWl5W1Yr7OEWMt54xhftlsQTHem1b/ F3IOYEhgxpQyGVWsExRcaRK25oh9tY71V4u+ji7r7RDBNFT0q3WfxSkxGk85bCUf rxa5LsNYujYQ5jfOgf1iFnn+HBo3nvQylztksmaicc9WOg2EJpYsYkcilnaBMhSk NSaBuYDMOZVPBxlMrzfg/yDAa14xlRugglbahfk2ESw+ecBdUKG4wwvABohaHIZC RfMCGAZjvaEz+wH4hxfZTI0m5U70xnXQKHD9etBEl9+lEpAttJMbd3Nh/HhpF1Da Fyr20TDHy6cTdmxaHEiP+NIukC5APUFFOvRv2GF+S29NPr/kkjxXrnwv6e4SwyuI BlXIWIeLXssVtfKkVKcT9Vl+t6+OA+8/X/SoFJDrAWLHldhF7WxarbiRAgMBAAGj gfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0g BDwwOjA4BgZgOAwBAQIwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnku ZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFEJrg9QF0ZRpHWvlJMWKaHCe7+RpMDcG A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1 bTQuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRn6PFOT7O18wdv CJwMg9l62VvnSTANBgkqhkiG9w0BAQsFAAOCAgEAeiA+ouaHL7bUJKc33C5jVhte nCvWvYTnFciug4wbC3CVK86TSZaI+V/9eIauYfX7y6trcyZ9BaUbdgBjHYb89rZn D04kkM1tSeg/DS8PZ0rNY6couxkQt+kJ7ajxeJV36p8WNB5pkMXNf486ly1w7Pyt FRo5WtNnrLoMi+osPbIBISacsjdnXEGZn2pSEDyM5MYpiWVr5PLwzlnUkwNIxoAA ugs9nH27X8gumgRAT2cVxgZwdC/qFkyesIx6LgHZdGhXJTicnm4y3pmHOkgPXdzS bDBIqlKFmQvZD8k5fBhzEnkA79UBvgJD1epxMAoYaixowapT34Dtx+p1Gi1T39P0 U4CYzKJdvXhIu/4MGnU1ayXHX74qTCyo+2ZSmeFG0dEvFgRPUGtkTEK/RGAtAPt1 CsutzFvdqO59hSmj/WHFh2nfv5iYIXE6dnnK1cmgfdVFAY9YfOLeQCwlg63f/yp7 wWhpYvBihjO6wRXZkA5m18qusU9mjwb4B8iy5+9cyX627CUPBhJ+szW6Tez9gDcx i7X98cLIWwitV3Rse3MJhRhmfL35cq59SDTOz/TBGTmuF7ySMBlhS18waxBkAOjn /7Uf2u9n+KYXdxNPlquPRrsMqI3Z7svgmSzhlxc4v1XcDcgmtT4/2L4XS65chrM7 ZkOFk0kEkYw6DhJG9Qw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDDCCA/SgAwIBAgIQHfjlMOQz6C6i/PNzJhy0rjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGExCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xFTATBgNVBAMTDEZv cmVpZ25lciBDQTEPMA0GA1UEBRMGMjAxNzAyMIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEAm91a05fw/BWKbWHsp89rFqJFw2S1cET9ghrZlDIyadFKtW/i G6OEr61QQ/OLF9uxX6Fxat8OdGxCEVBVrpM0Lo/etNNywhiPNjpYcLteuTDaGGSY 8een4FMDEHVrt0RDcaQlzBou20NTLcabNrZMYaXuCxzIsJrKMxkCRdWaaP8KFjxO S3F7skx1SfI59xZXx45bcUe3YYEVrEe3j0VPx0jFGyMRFMug9pDK9eEddMEztarn +sjT8R7Z3hupGtn1e00q+mFRNUDzWoRlhF9DDS5D67zESWcnXEL2D/lT3BzNty+j 43orIVXMSSwjzRym+Qx3aDm7sR4TyW1cAoU2RduvNpejvafmKjcUpMjmDBjd2Qh7 Fdr3144+4EO/2ibUirOCVg7xC6XaSsS0c/mPhx6v8nP9UmcBfyUDA5cR+TILFeTB 5hlOoZKli3gJdtwD8vNF6i7sVh3AXd6ceUfYF/E8cNBLKgIwwLaCR61+cySZ/Z3L 3jxL6MbWoIC5Dq1fupNkSyTwtvwMf2WjgiAGCChezsH5UNyVsSLNsTGNVaTL5/a/ VUiQw52aCiaOvcPR/Imo4hJRowBWVOQPMbAvyeg2foCILKxOtd6QI1Lrpw7Mpngq bluT/K+twsYCnGoNLqze7rtuAvdTGOZEV7jgQmCPOe6RZZtzfFO29bieYT0CAwEA AaOB+DCB9TAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADBDBgNV HSAEPDA6MDgGBmA4DAEBBzAuMCwGCCsGAQUFBwIBFiBodHRwOi8vcmVwb3NpdG9y eS5laWQuYmVsZ2l1bS5iZTAdBgNVHQ4EFgQUfUSMBomNifGem/jYGu+SlU0faXIw NwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxn aXVtNC5jcmwwEQYJYIZIAYb4QgEBBAQDAgAHMB8GA1UdIwQYMBaAFGfo8U5Ps7Xz B28InAyD2XrZW+dJMA0GCSqGSIb3DQEBCwUAA4ICAQBAHJFIRMmY4loynDB5GtXj NTM8atHJafyBAcNcD+ZLT940FeXpQts1R8L3vEKktCAHWvtse+CesTtgAsX93hkJ k81gMMzcxFKk2jOnV/wg3nuHeP7Px7ITaCwBkvHcPfG2QUyFEm4bIkPlLBriTbBY Bmw833A62n1kfcPFhXpBWO3LnA4NimlUR8k7EaGgO+IFGYriKtpdsOMxgWfaUSId dDJ4hUAUJ4tfRdR6EfzhcPKVQNNJPva48C4WGRXZWt5+Ep/lhdPoc35Jd0ftknNo +z624RxDyrqO99HIv4KWuej/EVKVeEzOHw3eItazp1EfCyQoFgmmjnnUIVhkRIW+ 3JXHP9drdvC/Rj+nmiK/B6d+XqR+g6awLGpG1LE3F/5Bl8TAsCxSXJb7kpl9fWPR 3hL51RJ28l1fXOKyRLeLD3B9PXVCRDh45v9dZxyd6SaM13Z4HxiPmW2OL3qcYRED eOQ+KAvZzjzJSKwTD1uZae0Drf3fPjeb5ITNzQZDzfIl4Q1X3wBDHOhW2daNnnuW oPlIM81oS+IGZo3XzKcg9OPbvOmPUE5CTNo42m5CwgSVVZhH15D6lDMC1GxBAJCg gWpd2aOWXRZ1N5qmxZqqW+8AU1dCblNBoz4cyWewnh3tjxajY2IaNBU6SDIfFiD/ 8G5XG8RgdvK96mpDm9ckEw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDDCCA/SgAwIBAgIQZg3asK4FaFPE65YagOSFJDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGExCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xFTATBgNVBAMTDEZv cmVpZ25lciBDQTEPMA0GA1UEBRMGMjAxNzAxMIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEAs233fH4flZIGF/odJHTydTPi4EVQnVUqCOhf3U1PWHgXljMw S/bLsUxdAT1JwwrYDz4yfPzv1/pGMKRrOxOF7pNzLDei3S0FBzQoHqcVL5Fd0J6a q2cBtT4cQXl8UUKENkyOsmAHagvdvXE01DW1/BeXYCzQ8GzQesO1/PTL66VEppTQ 3tyOkXyyPwoCcuIJ+C1lel3CURB94fdvz2qjPNjJc3fUHyQ4zxCjPayRhrnFH3Sn Ph7ZWrVdl3R4a6/Tt8iLC6d2uAfPhCqxkxUCdhpeA+qRpMEdzD0hcXMT6o3Ekj3E 9obrw4nUIBMrNXZeSjEJjQ1OEF8vP3Y5Y41LHy7iB6ZLeGtm3B9NHzi2K1qpUYTB 4Ul+bUsZG3jSNifS60efvp0SemgJ1e1nCRCspZcOTdKHWCFxXIkswKgrYGY0xT2M XhfpQZBjPuBYCZILTM4TY1EQXf+ZVh/+9mlaEBr657IutGGC9lxLDkxSRtr/oiaT bnEylOUBK4okS5lpQCUCtc1+uIFkdNmWLoeimu3D4ifgAQF2LjTAvjEOZV2nHa3l msZtY73CoiPQ6s3lcB/ft2ugnzlkpwfQ9adRFZPkq+eU6qA4Oy8z7SckF+0ky5qW f7qQvgwBZR3d529DVcPEgt3wkFx+S4HGGpspUIWqRODe/uoiiQ5JTGCJvYUCAwEA AaOB+DCB9TAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADBDBgNV HSAEPDA6MDgGBmA4DAEBBzAuMCwGCCsGAQUFBwIBFiBodHRwOi8vcmVwb3NpdG9y eS5laWQuYmVsZ2l1bS5iZTAdBgNVHQ4EFgQUcBUSN5jvwUkF2bv1DL//ZJGPw54w NwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxn aXVtNC5jcmwwEQYJYIZIAYb4QgEBBAQDAgAHMB8GA1UdIwQYMBaAFGfo8U5Ps7Xz B28InAyD2XrZW+dJMA0GCSqGSIb3DQEBCwUAA4ICAQA58+uc4WhT0sMzLz2lbYfr ISgjVN2AZkPgDlTAXoQUXgSHrRR1w4+9RF+9K/itF58KKvaZ892GJ6YdgjBndWhm NUwhNAIkCAUrQNZo3DeGHNoSCbuSZEzab3bA/MxwA2TN1AYaf65+WM2Q+32q4fo6 coykCOhjL8Wgy2i7RC3JGX0JMm/axcetf4xacini0VPci10vzJf4F0o5S5MQqI8+ hw+IGtgXn1TfcaZiXfxyEaLRnVvWlYAzv5My/mRK3hjpl67DASQvB+17z2wph9jb r/mak5xJKTVCFjDX/eLhPFbpP72l2rQAtheNYN6cBAxG9eAhTCfW9OpT9PYsrsbU xfYzwKg+dK9TGWxlmQgile/LAtcbaJyanu+VBLgokObjJ14dath9LqS0mHNxq65R OnFNHr8X4lgwWQ2R7pLVOaNcZKUpm00H5hdEanjD+G9X8Gf/90UWHmdUCLmO4vIP 6oLK7Mwo2uQP8aTFQep7TzR6luqSPNATSGcuR2H2GKXaovbeFUkTKFzcCTi5r5Qa nA6C+0Sv5rtzRS+x2L1O0cr+OFwrUUrs7JrkUKB7J3UaWyh+KO/ojz7XuAVddoqB yMKL5Hx6bcVsIhkLQQXm92DJA4Uinpd5/YuEPGSRrtVVm687zXCoOOnfTv3UMpuB ANaigWj/QHuJkdQclGJESw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDDCCA/SgAwIBAgIQcmIHngajtSyDvskdVtL58jANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGExCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xFTATBgNVBAMTDEZv cmVpZ25lciBDQTEPMA0GA1UEBRMGMjAxNzAzMIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEA4aiFnDtIh8RpFk1PbzOJoFFJ9AueQwesAGYFaJRz3oFTny+m TWYsC+ki+56e7xERBcrBznhhZgKPxHLiRsu8tzQExXqm8ibWj/TUNBRkJTc5Mz7t o3OCwCJZSYTsraJDLTZORXgcE+lI4eLnSuAJ4zdaVeHXUiDB/r37GNZL6Fwuy2ev hTGYq5tVdRAR5dUmANpy7Oz55gNcl8Nms5xLsHbJuRuOtW9bQ5bOcsdfQDwgsyJn o1JzORIA6WR1QTdeey5y1lBMP3pv5Gb19KdG6NYyRKNlEoIKLruA95MG93wogBZT gWFDg/5ZkTiHad928h+kek7Xcj1/jjOvTCaOv16ZUXrZ3dgeMruTv0IMb8AuA9SD HrhYmR4TCboI6gJ+BRx6CTuJMgB6Inus288PEALochuYKUdaP2gAUahawkE7z08u aJzPGQk68QmCKS7BJH55XoEVFOfdGIFgm0aCakbLp+qLiLZOaEjzWw5m8YEgXMjH x87ylqiG2AzjNTNPdMBcSVpVDEtU3yUHnmzWzyup303iwRX+j5DqNWUSOD5QXgNc +tnYywnM+UFXBbCcloe5dm8FtaIxXzhcPMGonHvTWV4klEKn27MMW+VIA9tZttu9 PkomcRlioRbjfHzG3J7eL7M2i2fHrWbon9je8fp4c3z+/EVEjjHBYbr7uhkCAwEA AaOB+DCB9TAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADBDBgNV HSAEPDA6MDgGBmA4DAEBBzAuMCwGCCsGAQUFBwIBFiBodHRwOi8vcmVwb3NpdG9y eS5laWQuYmVsZ2l1bS5iZTAdBgNVHQ4EFgQUYHS/c8MHzU+be56rF3vD0BCjmjQw NwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxn aXVtNC5jcmwwEQYJYIZIAYb4QgEBBAQDAgAHMB8GA1UdIwQYMBaAFGfo8U5Ps7Xz B28InAyD2XrZW+dJMA0GCSqGSIb3DQEBCwUAA4ICAQAeUzvjn1ro+ODPNRxjUsI9 0H4arWJWn4Wg7wFRaV4o1BF19doPv6ejUSjXLuIUKViffNsE1ve/dvTDK3G2CGqm WDEMKJwo3gxCAr0SOneqfAex64H2g36y59BDWyDz9vDUk9cwpTYuCDDGhITBCWkg QMw1Et3NmIsrJdFhMgka1NP5VVFcbANag1G6iqD9hKa+MRSYJYfxMoV9L3mwQYm0 RMHyDkFN4la+4Je3d54E1oCGr/lgJ95lhmSnqx9xI94bX+qj/LOjydhQIdjFR2xi 1v2FymwcKH3Ty4iK1JTn10wyhte162eShi4fX/YMtI+g09R3XDWwNBh4CxQdo/V7 GoPIb+dHSPKdaR4Q2A0ymQTyq/XBrf8Ek1XAE5CcLKpv5HPPeyWnuzE29d6BehEF P5c9+bfDvHeIuIY/I0c4NzI4LbbupTVeGzUdjAtI8V5CNoxUWIet04/Mc8L+5+w5 3IstNk8NKF3i7eahTSwC0wdFHB96mfS0lX4s8+AAbF0jhamHTlmQekrEo6VkMr/L 39KQwbwmUSoa991QJeItBsKFCadSLMSkneb/6PR+vnmDJv3aMrG+5uE1fWL3qEXt yKSpZ9S13X7eYNp/DwD4XJvkTBHEGmKhBBelRCOb/25ERWoLtm764eiFda85kBgm XyVSCmnenB8IVIlP7gG2kg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCjCCA/KgAwIBAgIQVfUdjEI2ajACaS79rkWRVzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNjEx MjgxMDAwMDBaFw0yODA3MjgxMDAwMDBaMF8xCzAJBgNVBAYTAkJFMSowKAYDVQQK EyFodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8xEzARBgNVBAMTCkNp dGl6ZW4gQ0ExDzANBgNVBAUTBjIwMTcwODCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAPDhDSQveqMheoZ3jJwYxQUu/XsSDspvpfMOIaKnK9Xg1Q2Sf1br jZ7WQnaRh75Uig9qpnj7FPG209h69Pp7xqvAiFWVxu9PfjeEzmUFozEOI8j1SuzW rkNMxRrZUlybqGgOG8/9On5G7pblOYaQz6obFcz2CZ704xt35jqXVLQ0/OZ1asd3 O45xl9R0Us6Vp8O1ZU3dTXOXc0bI4aeIzcocGozTtWmETnBV/e9EKb3rfS0Eug8U gb999OBf2C0jMQ+OyxmaSl9e4vMOiKN65mGX9pElAUWoj0DuFsm2HUZt0kEEysM3 An8wDgL8O5WVNmHHqvr3ZlEJVeeE4/MhJ2oJSyu+xQzQPOU92m2snwJB/P6SJIJK Ns2JSzZW9qHZobAAap7ua1Pw+lkG1KKa+CR+M5lEy/09q1Bj2cCJ2/0+6PYToNeA E7WSPUvXdo+WWEqfQO5X3L8aUn1YNmZGS8BGnUy838rJtQCrkdhFAy7ka+/c2Nvp /0FFXEZcpyvhf2jJWL6N3/Qb94bcj1T/W5DYQ9jXrShrnAyyDiVD7RLafP0AZkRb Y9N5SGcBA0Q42fbhbRdIUqac6aHlBPsmMgSLHXRDZ4IhWQZg8LOf8hwPbz4wfjs7 kowiNPtNqvRzcVSlh85KS7PW/WJNwk63h8Y27ds9YUlFowoiTpZu2+1xAgMBAAGj gfgwgfUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0g BDwwOjA4BgZgOAwBAQIwLjAsBggrBgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnku ZWlkLmJlbGdpdW0uYmUwHQYDVR0OBBYEFErrkPgkeQ5eP4GzMj3syEYN2cuxMDcG A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1 bTQuY3JsMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRn6PFOT7O18wdv CJwMg9l62VvnSTANBgkqhkiG9w0BAQsFAAOCAgEAcOBkM5l4DnDjca+tLZEZZBlT hwUtA8/5GDat1oFiWjBXvyXhqpwVAOFTpwh3OhEm0tQFaqxmnXZ0n9lzNFCrzJG7 Ne65cWWh8ZfmDruHPpwxiG7NJNkEzBALTzompabdo7oC4rjov96bmsqZvQdKtOvB ssp92P1CQooT9SBLbN1HJIbt3kRu3VKiTtaA1hBs4/cMMLwiWrYAaw1MujCOtEXt Lw44jorxn14oRiH4aSxquEHtmT2q68/hn9qPdHQJein8b0YonBzE4n+2OZx0A1nN Hk2Ipamz56lmgUahzjC11KE7Sj4eeAhAeeXgQW513DuxHpNRAbDnpaSIELCNGcD/ Lbs9nAGU67lreYIjn+Uv9S8aB4FEOR0ZBERpTKXEUzZupcBsLj0SH00Nl5awm1oA rdPfy3bRDlfsWi95guMn7xSiN49D396RRDfNbz4qCCRjJUG1JOhsntqjf0eKxBF/ 7BZ/kvsouD+9mvme1iLl8ejCDs8FSAljTDOSjfELeGfWxoiJkFZcKjJfHl7Pkpnm D3IZ72391kpnt6rPNrt+QKt9uajdR3ayZsv087tPKTUcYxgQX32qf52efpyGr4m+ gEEnu35AxWzML2qmj55qaZS/2hMiENOpSOfPYEcKnDbP4HCiqgpeqemW/qytdWY4 h27X2kG5qdorWl5ANO4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEoDCCA4igAwIBAgIIQPC7qorgwJgwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTE2MTEyOTE2NDIxN1oXDTMwMTIwMjA0MDAwMFowgYMx CzAJBgNVBAYTAkNBMRQwEgYDVQQKEwtBZmZpcm1UcnVzdDErMCkGA1UECxMiU2Vl IHd3dy5hZmZpcm10cnVzdC5jb20vcmVwb3NpdG9yeTExMC8GA1UEAxMoQWZmaXJt VHJ1c3QgRXh0ZW5kZWQgVmFsaWRhdGlvbiBDQSAtIEVWMTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBALjwTCGvVblyRgMNDB74nhnIjxQNdW/U+PWCe0/s 1aaDDEDvrnlClR29pduqHgosCIVzEOS6rjlXMfq6H6Ls3Cl2N8Cg2cxyDpwJFPtt 1HJ/93UR+2hyVC7Abn2avjb8IGEoCSRAyn6ryFf3OR4kcmdh/pwCOddENsQtFMYE gbLn3HEPhcJIOgQBg5U1674vMIu+VGhrnuo7/6nCi8m3lVK4KihOuHfaGvTxuf4P PUMEnbCEBHVUhcxbxaThvWISWyde+2YOgxgsVNJVsBa1ach/9r515Y4TEEnJ/FMc wiXQ4NxA6o4GldCR9sqC7oPkFWIFET7uQRG+brfbwHT+3C8CAwEAAaOCAVQwggFQ MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuYWZmaXJt dHJ1c3QuY29tMB0GA1UdDgQWBBTb72U3C+VHyzXRkB8DwbyIx6fqgDASBgNVHRMB Af8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFJ2TxlOLXsqvP58eD+WZlbwk9pSPMEcG A1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5hZmZp cm10cnVzdC5jb20vcmVwb3NpdG9yeTBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8v Y3JsLmFmZmlybXRydXN0LmNvbS9jcmwvQWZmaXJtVHJ1c3RDb21tZXJjaWFsLmNy bDAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MA0GCSqGSIb3DQEBCwUAA4IBAQAiGxxj79nQE1q9ks9a13qcObtYLrDij8LG7OnC M6K84OOi9qv3PMH5+6z9usoHO+vSsWmhREdBxh0CjP2JlG8V87YzmST+1XVcc4Vl RcsCHM2jwCkQksGDBPCk8tyF4ezxX6bEnLuKGoJxEZBiwpVUw/6zedLfoRtGjUof 9kbDjRIm1pMzUmFbarLbwc+TgpqPAFSKNrF2z1qHsuLuO9lLlGMevxT7LitO7kY3 9WK27jdSVuVF/SnQ97r4k99gn/NPzrLKnTesNdInVdTX/CJx4l6mWIBhlkp4A31D phEslDlncRRLsvVRRrCtTZgcw8I9QGF5jGPPsatB5UR6Zj/g -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEnzCCA4egAwIBAgIIGH5/O/ZvI80wDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTE2MTEyOTE2NDkyOFoXDTMwMTIwMjA0MDAwMFowgYIx CzAJBgNVBAYTAkNBMRQwEgYDVQQKEwtBZmZpcm1UcnVzdDErMCkGA1UECxMiU2Vl IHd3dy5hZmZpcm10cnVzdC5jb20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnQWZmaXJt VHJ1c3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gT1YxMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAwr3KOw3nm/6fLxr2vgIlw/mPgrtB4gOGqSeBkDTW y0hZEPT3aDb4xZQjx/YCFSX3NvCa7fO9XeCD4a8aMHst6mvhzxzJjaIsAHI18YrL Agauza2YJEl0TIYmuhbtzbxYBamTZe829Rk6QkopWIhyBP1v7R7W3JZ9W5yyJOwD MtmUthILJiclO8lW5hKPGNtH9wN1gyHGVc4zkBiW/HWMYXAbNTFsA3qIWrwYTAhY tiA13wWY2w9gegYqu/o2SbT6NOssg7Atn3i+f3pe89Q+oE1HKAgZU+WOsz57AQfd Fdb1R1U3qKXZ4T+LnHKlZZ+NCIAACrGt+XELLcamYSzYSQIDAQABo4IBVDCCAVAw NwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5hZmZpcm10 cnVzdC5jb20wHQYDVR0OBBYEFP5gww2kop0hT3p4TGLF2xT8OXjEMBIGA1UdEwEB /wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUnZPGU4teyq8/nx4P5ZmVvCT2lI8wRwYD VR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3LmFmZmly bXRydXN0LmNvbS9yZXBvc2l0b3J5MEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9j cmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1UcnVzdENvbW1lcmNpYWwuY3Js MA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw DQYJKoZIhvcNAQELBQADggEBAM4spvJgKpvTy45G09Ktya08cgHfs5zuyKHr4bWL 3ZpXjIPoAY85XUP+BBhL6+LuB8rbF8k49wyA9M5qWoqIdFDp7urMwMtWvN2Z00B6 e44deKa/3tnqnVY5sIMoUg7rm5ZGn1mYGK2PBmAHjqxJhtbX4eohhYwHGSv7FkwE I4r9yhwTpCeuglpL2tPlqLIx5o64/aIkOsrTZxgR7qDgjNrnDYmyE1pQp5lYY6A1 83OGQ3S0nIt6Tx4oBwPzVkxdh4olYkmQQDaZbltLPS6yXELvehMOcQMp91Z/xqCJ S7H91E9HzZOxWfV7EHFc81xRxMg8cDPUFxh9XbuFAUBzXgc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEazCCA1OgAwIBAgIQA7rR0/Vs8SGOje9X3EGVuzANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE2 MTIwNzEyMTYzMloXDTI1MDUxMDEyMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNV BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkG A1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2UgRVYgUm9vdCBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0tMqbf5YE/yc0lSbZx KsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMSOO7z SW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9 vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu 5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8 J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsgEsxBu24LUTi4S8sCAwEAAaOC ARkwggEVMB0GA1UdDgQWBBSxPsNpA/i/RwHUmCYaCALvY2QrwzAfBgNVHSMEGDAW gBTlnVkwgkdYzKz6CFQ2hns6tQRN8DASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1Ud DwEB/wQEAwIBhjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v Y3NwLmRpZ2ljZXJ0LmNvbTA6BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3JsMy5k aWdpY2VydC5jb20vT21uaXJvb3QyMDI1LmNybDA9BgNVHSAENjA0MDIGBFUdIAAw KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzANBgkq hkiG9w0BAQsFAAOCAQEAY2QWVTXl9fY4q8BuACRml6gNXtOegB7tNUJvPU7b+rGf N0EeSfBUfR6y4VupnwLLFZ87c99d588GvyrRzdK8qR+MLjKSR0fuzcmzTz0TPoKe XJel6qMozcQHC1piAXP2+Ao6rb/H6EtRM7qep63m2HFyLgqvlQS1mcCF8vFwLPOU MhpsJ8LyZ4DQWaOWDVKQS7sESzot0gLE1lZPTxLTKKhCgS3X7h+ybG/aKKFsh2ZZ AD+MTmyBjFcGYbF4+CD2jb9me7Mxl3dgsveSJvrBRUjLTL0d8c0H4Zo88P2OVJnT BA/C+YbnrZNDXnagal7H+UILnayhivUvYoXapBqvTQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYDCCA0igAwIBAgIQD1vDoXbLeJ4gIMeJPIFntDANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE2 MTIwNzEyMTczNFoXDTI1MDUxMDEyMDAwMFowYTELMAkGA1UEBhMCVVMxFTATBgNV BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEgMB4G A1UEAxMXRGlnaUNlcnQgR2xvYmFsIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDiO+ERct6opNOjV6pQoo8Ld5DJoqXuEs6WWwEJIMwBk6dO MLdT90PEaQBXneKNIt2HBkAAgQnOzhuDv9/NO3FG4tZmxwWzdicWj3ueHpV97rdI owja1q96DDkGZX9KXR+8F/irvu4o13R/eniZWYVoblwjMku/TsDoWm3jcL93EL/8 AfaF2ahEEFgyqXUY1dGivkfiJ2r0mjP4SQhgi9RftDqEv6GqSkx9Ps9PX2x2XqBL N5Ge3CLmbc4UGo5qy/7NsxRkF8dbKZ4yv/Lu+tMLQtSrt0Ey2gzU7/iB1buNWD+1 G+hJKKJw2jEE3feyFvJMCk4HqO1KPV61f6OQw68nAgMBAAGjggEZMIIBFTAdBgNV HQ4EFgQUA95QNVbRTLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAU5Z1ZMIJHWMys +ghUNoZ7OrUETfAwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAYYw NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy dC5jb20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29t L09tbmlyb290MjAyNS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQAD ggEBAJpjvIPfXiuDFKs7G+h76taX2ng1O+Xvso30ZOdkK3BxeQdlK0sEvgirezuU 20S65oIsvWUwbDY0Um79fgqvCOig0TfuYmz/jwQ0T+BcccaGDUGZZLbHbx1nb3uj zvb/suLwN8tfwfSCvue+8aNoucVyDtpSS5ecbcaYYL/rjOQWeiMSj6bREEM2jz7q MgQTlIZcus2tqWuOMyXUI/ibz31TWGiMBGu9jkybdV5LYiKUWxCA7kxqiUDHeBH8 dQt6sFgaFjiUki4bSNrRevngFmMSUYGMkLGELj//so6ofkw4av9cXBZYqIX/XcCj +KgVQK8z7A0yUhkfMgnzZT6StIQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExDCCA6ygAwIBAgIQDa1DJgJFuipAM/L/5Ra8pjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNjEyMDcxMjE4MjBaFw0zMTEyMDcxMjE4MjBaMF4xCzAJBgNVBAYTAkpQ MSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEqMCgGA1UEAxMh Q3liZXJ0cnVzdCBKYXBhbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAxbd410u2vb6y/npnJauO6ZmfBL9MOpLnuRDgLPy0 UbW3UR0eNZyzSJDP9DLZzkYJMOQMR1Xrp5y2/8E7KDZk/EzO8mUgO7YmVf4af9AE tg1/BiYM8sblPOMcqgiWBSHwNrBNeA9ccy0vPXt+SwGwoD+B6sQPGV+CcRX/MQmp PshByH743MuomhlieuHz5ZaYwztFPSNpRwDWN9jFSjNRJiFbIzMMJGEQyLUG5IZf G70h75LAV/3wvBIMUGSET/+RIbNlZYCSfhOjGpFLYxkdBzGuKPF8fdy+faZirui0 ynme9BjPCwIAc7lhuSEj5zKevou5kyVSIiIR6ydZXEcSGwIDAQABo4IBeTCCAXUw HQYDVR0OBBYEFInuPx/KekyE3KCdbar57EcwXd1VMB8GA1UdIwQYMBaAFAPeUDVW 0Uy7ZvCj4hsbw5eyPdFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQD AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA0BggrBgEFBQcBAQQo MCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTB7BgNVHR8E dDByMDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9i YWxSb290Q0EuY3JsMDegNaAzhjFodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGln aUNlcnRHbG9iYWxSb290Q0EuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsG AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEB CwUAA4IBAQBx1l92N4K1xtz3VhWMa6yme+Q0QKe/bipmkj1RMfqz/3FeYV+fMKu2 JafvN0tNe2JgdIGF1M91vFtsirMNjW7lQUZjq94+k91oCtdAEOnBT8tyRswSk7mc YWVA6i4Vr5XQ3EMhAFIq0GAPLOz5MSqkRQJu22+G7NY0invFCjhjwYa4B/88c3TO SD5UFTVBaDQrIgxQaGs4MSTTeFfWLdEUDqhlhpAP5GkjaTr+tfIIPtEOyAX6N8oT IXF8hVcUu/3dYRErE6JHC2oaJEUXRv6OhtiF3HAUqFuB7JiSRT0REwFqOaxlE+1n fNIk4DLhBTrxA1nkENU3fMNyF/+tWnAb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIErDCCA5SgAwIBAgIQDsBAwuDdovF0dwI0fvY9mzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE2MTIwNzEyMTg0MVoXDTMxMTIwNzEyMTg0MVowazEL MAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQu MTcwNQYDVQQDEy5DeWJlcnRydXN0IEphcGFuIEV4dGVuZGVkIFZhbGlkYXRpb24g U2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy33s6hbX f1BDKseqBiu79+iRs+l7JNd7ad2nSWTZ5OmR5RZipBS4FJli5OHi1ZQB1XnYRmAf HjMg6d9WPUajwDXoRDbB4EcbCY0A8iNVFBh37lpFBLxnvwu+A3xzuYfMwn88iQ24 4fGeZ4Z083A2wkAeADd5BF6zwzhtihUXgKmhKcxhbKq74BlSv+79bCVHEd74CcLx F+pZp8uTMQm2k8TTdZBbEMVHIvgn6FpQ0eHS4W6/xt0XWPy9wDEO7Vv3oJ77XbJD mcxgx6x9iJFQr89dHjd7EXEQ4IieYhEAaMHD5A3rbggjUxE1jH0BUUysgvPbH4NX NO1tZ68sbLCa3QIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFIp3LSM3fuJx+OS/StDy BqGWKhTiMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9jZCvDMBIGA1UdEwEB /wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v Y3NwLmRpZ2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5k aWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0G A1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdp Y2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQBLpBD6QtiuumLIcVU1ajaZ ZvvmcBEMKyoYVELQEtlIekY9yVvw1EyGhOnGI4J8TcjqvmHmGKZqQ6F+bXMrOppF uFPepObZAvA8M8YWtf7wwZxGmBfTuKYeW+JpLCwxgeECj9UYWg9bMB7zK8zN6np7 1w6dxVcRNG68DWDQ/02AimM+MVENo5o1GCE2aWcsI25iKTgOtaNx/PxmVMRQhHcK aZPVbhF9jpa+XT3cExYI9Uy83PDdy9GfUMYhUvPbu6iNLG5bkOL9m7wPa5WrENbS JFgw6oEhJ74hEofKxxfmnEytPjUT6/ExBwm77nJG77UrOBKnxH0M0UUi8X70vYNN -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHfzCCBWegAwIBAgIIQ/BcvGDLYfEwDQYJKoZIhvcNAQELBQAwajELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjE7MDkGA1UEAwwy U3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFNlcnZpY2VzIENBIC0g RzMwHhcNMTYxMjA4MDk1MDEwWhcNMjgxMTEyMDAwMDAwWjBzMQswCQYDVQQGEwJO TDERMA8GA1UECgwIS1BOIEIuVi4xFzAVBgNVBGEMDk5UUk5MLTI3MTI0NzAxMTgw NgYDVQQDDC9LUE4gQlYgUEtJb3ZlcmhlaWQgT3JnYW5pc2F0aWUgU2VydmljZXMg Q0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANS9rKExVLXk 7mQI2i3WNRLuCgkVlvjZnI6QyOTIaPgju9IUBm0q3f81Mw8pl40xsY2V9vZcOa8D pXT1QgLlBD89V1E9r2eTaFx4VK5Z0MSEjiQ2hlTf4KEu3jTNjvgNAWjpOgg14nHa 0LoJA/EveRMTlbjJz+JSKgm+LutVfYJHY8I3eMcLwJVo5IYldyqSe4qpQijFiG74 VTBiVU7UDqtQJEgKOqcLjSNfe1n2gN2mlrtsPbFMtxmoXa2U/nFitxgfSVJF8G/G 4ocZnd1aN4kbGTAEAe8btIy8bUWds3Bu4gMC07NUifQftWP/RQ1MwhFfcWJs5gDV BnsW4VUvUVU8RvXfCASdDVQQj2wNoeRtNiCvjsU9pqHe8/7SwtFmw7zpnEZLJgiY j1gOe44ffMJWlh98QSiGpqLdbvsAhhqntq9rz/HlgFvemUNrzxdQBPdvlxRGDI4j Tp0juj+Ucq2NtHTprdHi9lEn4hCvmcWSI6wL+n+kYySLHSF4l3tFBVL4k/BDPYN2 RWFwjB8lULKZT1i6j0p93/DCTRX9iwXnoODUyp7lsB648lRPCHb31O8y2yCb4B77 r4o9o/pkuKq6ff3UFEU7k/3jlVQcijCCE7IcXCD0hvfd4Er36Zh52iyPCgonnNuA 4tbLBfSd3XcD1YtcsLBEk62PVoeNkxxLAgMBAAGjggIeMIICGjCBmQYIKwYBBQUH AQEEgYwwgYkwRgYIKwYBBQUHMAKGOmh0dHA6Ly9jZXJ0LnBraW92ZXJoZWlkLm5s L0RvbU9yZ2FuaXNhdGllU2VydmljZXNDQS1HMy5jZXIwPwYIKwYBBQUHMAGGM2h0 dHA6Ly9kb21vcmdhbmlzYXRpZXNlcnZpY2Vzb2NzcC1nMy5wa2lvdmVyaGVpZC5u bDAdBgNVHQ4EFgQUFAC4s29zDcGF6iYWKyXikQgVvbswEgYDVR0TAQH/BAgwBgEB /wIBADAfBgNVHSMEGDAWgBRD600A05WTzqZ8QA1tEb450TKu4jAlBggrBgEFBQcB AwQZMBcwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjBdBgNVHSAEVjBUMAwGCmCEEAGH awECBQQwNgYKYIQQAYdrAQIFBTAoMCYGCCsGAQUFBwIBFhpodHRwczovL2Nwcy5w a2lvdmVyaGVpZC5ubDAMBgpghBABh2sBAgUHMFEGA1UdHwRKMEgwRqBEoEKGQGh0 dHA6Ly9jcmwucGtpb3ZlcmhlaWQubmwvRG9tT3JnYW5pc2F0aWVTZXJ2aWNlc0xh dGVzdENSTC1HMy5jcmwwDgYDVR0PAQH/BAQDAgEGMD8GA1UdJQQ4MDYGCCsGAQUF BwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDDAYKKwYBBAGCNwoDBAYIKwYBBQUHAwkw DQYJKoZIhvcNAQELBQADggIBAC37bRzZF82BciGTI344Sstv4NiT2/Jb4TTUfdVz o/sZX1Tynli8uaUAXVEKzJKjd1Sn8lBcJrDm8EkJQid9HzzAVBTMoccvCMJg3nel 8SNkPKoIxi5R2aUlw9FLZKhzADarZcppHi9L5N5NK1wtyO7ySbs8l2IrhwY0xC7J PFO1gqfsBbVJ23DnYbrTQA9Q5PPeKpCfz+CmMOnKJXo9CwvtXt/HNhWuTIDJW+rM kcZGFE5VSCwS04D2EdDCV3FzGubjVa5FOOnWxKRsXygMeus/uAlBx8kKlO0vsAxl Ze59nExHGdgxxPXVm+yxrxh9QYLOLjwggtQFG+tIiUqdHOFWmjRNvsH67UJm9Nb0 QOwSuhY/1mK8Orpg5OBOTgr0sdDAhtjRpnTBj/laSf6HoLwZUejl3yLV0a7WPans kxtddppAmBzNO4BcQkgItnVflK9a/d5BDb7fPRDbJsMENuk7J2HEgyJOzDpuQ3ZE VEC9Vl/tF75qnz9HFuX37Abd9Thehg/MuNSAvHdj2nytFjP4g8MfTYQu6rVcoW2j +e0gtkyS93jdg9ta3k+ZnQ3lnpdPiy1mpTSTkDNXDQ99PnlmmqkoniV7deVzy0oT ptQgJiuT/Am/vOXbc1LCu7Sk8A3Np2k+uSxFOIjU/SvKRR+MXPXDrfdepqxJUVYR 7Bp/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIIYcUvWFWYUlwwDQYJKoZIhvcNAQELBQAwajELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjE7MDkGA1UEAwwy U3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFNlcnZpY2VzIENBIC0g RzMwHhcNMTYxMjA4MTAxMzU1WhcNMjgxMTEyMDAwMDAwWjBxMQswCQYDVQQGEwJO TDERMA8GA1UECgwIS1BOIEIuVi4xFzAVBgNVBGEMDk5UUk5MLTI3MTI0NzAxMTYw NAYDVQQDDC1LUE4gQlYgUEtJb3ZlcmhlaWQgT3JnYW5pc2F0aWUgU2VydmVyIENB IC0gRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDNZfwvQT6bhd9J wjU5SOrZd0Fe3Fmcftf2KIGrbBgIjJZKkiRximQqWZtfwyzhby/Pyli8HAQVsXNP KHPqrJ/iv1YtTlDntuRk+w8IaZzWo0Rf4IO5VmrnjFUGkmvSQcTyCN1LdNBoHI18 5aa3Br7lGUltBv86Q+nlymHJmMKjC0y6C0+Xpt7SuWr0nO15wqiBZdUlFF05XcxX bTOG9UouVhlSKU9ujnkfNSKw7N3x4gqJNQ9C0W5O2zVO2jWyBaK20vnbN955FQM8 4O2prhMFQrCi3e6lVvtTamxlnzVOiVUpH+59Rh0PeOw8OwCnk8GLXwkvIrxPgi3M FIpVy30q52eGHwzEkvExTHkuTm4pUSKI3N8zypfKBkfPUCnFk6PluFkQZYvZSVWM NbLst6DOuStKSgsWtH3lQGz3qNgyLgtWjFBS6S7+lgb06On9SadJ7MgLTyvaPXGO ieDwEq3BhjTnioNswPjIJCKjGad6EtnFaK+kG0wzE2v+gger4shh72Vj7GM4305U PBCEIlvmafyCHSD8r2lMBX1bqnbp2aw9ocdDbkCTzJ+N2DkmKkAp87NFRsFXgfnq gOjG50owXLNaEsXhOwI3lBOCCz8FG7u0jD44k67lU8n3LvKhBenixXYylak9vulc 1q13uICa04NbMKegL0uW7Wb2anw1+QIDAQABo4IB6jCCAeYwgZkGCCsGAQUFBwEB BIGMMIGJMEYGCCsGAQUFBzAChjpodHRwOi8vY2VydC5wa2lvdmVyaGVpZC5ubC9E b21PcmdhbmlzYXRpZVNlcnZpY2VzQ0EtRzMuY2VyMD8GCCsGAQUFBzABhjNodHRw Oi8vZG9tb3JnYW5pc2F0aWVzZXJ2aWNlc29jc3AtZzMucGtpb3ZlcmhlaWQubmww HQYDVR0OBBYEFMOapntedCuCtsZy/XROhdKXzf0YMBIGA1UdEwEB/wQIMAYBAf8C AQAwHwYDVR0jBBgwFoAUQ+tNANOVk86mfEANbRG+OdEyruIwJQYIKwYBBQUHAQME GTAXMBUGCCsGAQUFBwsCMAkGBwQAi+xJAQIwQQYDVR0gBDowODA2BgpghBABh2sB AgUGMCgwJgYIKwYBBQUHAgEWGmh0dHBzOi8vY3BzLnBraW92ZXJoZWlkLm5sMFEG A1UdHwRKMEgwRqBEoEKGQGh0dHA6Ly9jcmwucGtpb3ZlcmhlaWQubmwvRG9tT3Jn YW5pc2F0aWVTZXJ2aWNlc0xhdGVzdENSTC1HMy5jcmwwDgYDVR0PAQH/BAQDAgEG MCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDCQYIKwYBBQUHAwEwDQYJKoZI hvcNAQELBQADggIBABT77hX9j6stfJyzjcoRaYiUzI9zQCfeISzKj3+pEOFrJlOv TFppD0PrDMA3gxeHWTHPEPF5YZdvn5PTzaC/OicadjR9ocbUXMDHQIOZKdSyFuxK cR4zGmeiG6xg+7lc7dn77d6xA7gQ/Pdyob2VBfLdq9pYHUvRko53klRtYvAv+66+ i3uHfyqdet9024hikR/Iyad5DzKnLDdQQ8GDVYhBYVhVq2J83QWOEojGDRwXD0Fp s1BFpYNWydkPBKdUiuKfLP4i2dwTfH4jdAP+LwE/54Qi9OgMJ5Zppnb/wo95dYlz SA0vCh6a5+c6jTqnFr8vU8zAh7WQJr5ZDeW1YlNmTqUg16gZifn2EQe3ezBi31hL +HMFCNHFIElGqzzFCJOezNp+tg5z08/CecFLsP7SUgHXZbFwNq93BA1r1vaE6HuP 6fHj6Anj0YdxV/SSDns7+vuOxDlYV7yzs81+VMH4GsLj6grHzpW894MSPooDEAAP QYNlfu2QngpiaL07rqTpBTdy3XgL0ZlPvm6i/FagGhkVYvTmiBSWV95+0rRwdCVE VVSxp/9HaJKk3g2OKblPeNOHjZU9VRLV5CAw4Ay1gwslhZw3QIfZ+BULIo9kVjtw f0WHvTVBdr1fN9Bcjrvgu6ekontYb2+vyPKmEDfPAexrL6ZXpUpeBC3ReOFk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHNzCCBR+gAwIBAgIIDwg4fdXfS5kwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjE6MDgGA1UEAwwx U3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFBlcnNvb24gQ0EgLSBH MzAeFw0xNjEyMDgxMDMyMTFaFw0yODExMTIwMDAwMDBaMHIxCzAJBgNVBAYTAk5M MREwDwYDVQQKDAhLUE4gQi5WLjEXMBUGA1UEYQwOTlRSTkwtMjcxMjQ3MDExNzA1 BgNVBAMMLktQTiBCViBQS0lvdmVyaGVpZCBPcmdhbmlzYXRpZSBQZXJzb29uIENB IC0gRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7+jED2/e+e5rv 1NELEgpO5frmkvro5jgFXXD4kow9aIKhFtC+Jjvn65SQGyeRcF8K9+NyPKweiP+t 7LWTMB6d3RmKs3FD9xJj7Y1/Sl0DskUP6JUFZOEOwyoFAIfAp20V0WJ9FNMvmZr1 ZYcEcA0PrvuuuQuqVq0Fk65ZSQf/4L9pUW11MWR++OTJaQPzmwBkopsXZAka+gxi g9V6p2cWEBYcYMbIntbZk+6wfU3XrhC9ZwGHs0F4RPnYVOjSScfQkNnuRTQUiyU0 C5XmPEupjJcN8VXisTQfyylH3dtGMvxbVULxqFk73UMYS+G/BdwEmoCYkump3IK1 Fs1AHiorS3kmjm2nl7DoUiWfbWALn3kDkpyM+FgolbezVq4fxJMJCbfP1qJsLRAo FaYToaj1K5cBU0QCqwUW61vS6rurM4GhvSNxyiUAe4mrzSmV3H31t8slObs95lBP 5Ehty4P6ksj7jTx/EXK/dbid1/AwyXsx7/JiBP3Gqx6zKcvE7lTaQLa2DnLK590y rJCMlKU/OEjwdK0qcdUd4+YYJmic33rHZFR83CbLsrvaTTM3uCZPyeM2wYrgkPQ5 o0TTLxcaRlTPA7tQ5irmbmKcHlaS+9Kw1d6S5jQ9TBO1Hd1FGVrC7X9k7AK1PJUp vEbL38okjZBUMhkqRDyaLJqxGSLFxwIDAQABo4IB2DCCAdQwVQYIKwYBBQUHAQEE STBHMEUGCCsGAQUFBzAChjlodHRwOi8vY2VydC5wa2lvdmVyaGVpZC5ubC9Eb21P cmdhbmlzYXRpZVBlcnNvb25DQS1HMy5jZXIwHQYDVR0OBBYEFHcXSO4bfW582lzc DJgwGOYNdtMwMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU7qxtQOrV BGqHLFV79T8t2u7brOIwJQYIKwYBBQUHAQMEGTAXMBUGCCsGAQUFBwsCMAkGBwQA i+xJAQIwXQYDVR0gBFYwVDAMBgpghBABh2sBAgUBMAwGCmCEEAGHawECBQIwNgYK YIQQAYdrAQIFAzAoMCYGCCsGAQUFBwIBFhpodHRwczovL2Nwcy5wa2lvdmVyaGVp ZC5ubDBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnBraW92ZXJoZWlkLm5s L0RvbU9yZ2FuaXNhdGllUGVyc29vbkxhdGVzdENSTC1HMy5jcmwwDgYDVR0PAQH/ BAQDAgEGMD8GA1UdJQQ4MDYGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoD DAYKKwYBBAGCNwoDBAYIKwYBBQUHAwkwDQYJKoZIhvcNAQELBQADggIBAGDX7Dq/ 2P2TpdYmgv8NmkWbprraSsAsv2iloW8da0URjqBxXHLVmbCtqRe38S/qlCNwIduY QUlNAHH8nkvyuPDc8oLgHSfgA+ogg1Or/a5cOjq64a+jxET2l7oMmnkV4USGYOzK 0ZhOjJvYy5ggvSnZV+H23Vu3e/jk4IIj+oxx7qOAfj8YpKuHXivaRLKAVHlReQoQ Ckz42gg7U050/raicazbF1R1u7qLcsud7dG/PqSxZnLHpM8Uit//xZnYV51UaB34 rYU+AXO3ifSAZFtEvHuuOEoTOjNhTvE6JHgHvUWErrcPb/Pz34tMqqrSX+KVfJof iUEt9bLV5VmC5sInUZEFIUruhOaVanSISU46N8eYmLeZPztbClrU/U75HaeuFWx7 UyeaSNRhYrasnFBjxpyxnTj7LVhS0UNj41tlgivQW/YAHT9CtybcAXLKVI4FjPzc p6viJo8UiHiqD5IoZdMrq7idf1FcOax0QOARdV+8EUvWQ/ltZ+RPSbl6ppBUIjyt sAxGOREqt7T4xWOCpPt/27+TfjLeVrKl3SZFo4bN009t3NzjbfYRr4q6rYmzl8xq WFHN112iNnOsXgTQYtlcrRj4S6KJOrVGBWlAknkl1GittgY2Wc9mgGrT5H/uI8Bx KfE0sEm4TAMt64tk1MMP4SLiOCJKZtm1JGYd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFljCCBH6gAwIBAgIMHG40JD862CwbzJE1MA0GCSqGSIb3DQEBCwUAMIGVMQsw CQYDVQQGEwJERTFFMEMGA1UEChM8VmVyZWluIHp1ciBGb2VyZGVydW5nIGVpbmVz IERldXRzY2hlbiBGb3JzY2h1bmdzbmV0emVzIGUuIFYuMRAwDgYDVQQLEwdERk4t UEtJMS0wKwYDVQQDEyRERk4tVmVyZWluIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IDIwHhcNMTYxMjEyMTQzOTE2WhcNMzEwMjIyMjM1OTU5WjBzMQswCQYDVQQGEwJE RTEQMA4GA1UECAwHU2FjaHNlbjEQMA4GA1UEBwwHRHJlc2RlbjEoMCYGA1UECgwf VGVjaG5pc2NoZSBVbml2ZXJzaXRhZXQgRHJlc2RlbjEWMBQGA1UEAwwNVFUgRHJl c2RlbiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOfggnONmNft CebaQElj0mMf9D8ao/ez9Q3cwm04d18KaUbADLajcEvLE8YBzJmzQKJdfLdxKiJE x/4klxIXeXH+jksh7plW4L2U74zIf3O0d1RmYsKoppYZOP1CVfJ1T76y9uBrpA9e 0bL/oi3uTLHuxyDCe3vXIgK3QgVeVupJP+TtuP2YbbSBLP9iN4vDE5RqAWnrDYJF Mv3EWgNIcNQQU6w23ytb4W8Vfwlm/nM8tBdDOVt9S06Bq17sKBa4YIJ+V/y6xV7w m/P/cPo0pPFsxrycOjJTxlx8Lk343+6Hov0tI+4h6uX8iB95RLOfDOJMMZS1Yr9q 3NyiZE1+cZkCAwEAAaOCAgUwggIBMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYDVR0P AQH/BAQDAgEGMCkGA1UdIAQiMCAwDQYLKwYBBAGBrSGCLB4wDwYNKwYBBAGBrSGC LAEBBDAdBgNVHQ4EFgQUUv6+tyTCGwodRlKORCQq9EhAPQEwHwYDVR0jBBgwFoAU k+PYMiba1fFKpZFK4OpL4qIMz+EwgY8GA1UdHwSBhzCBhDBAoD6gPIY6aHR0cDov L2NkcDEucGNhLmRmbi5kZS9nbG9iYWwtcm9vdC1nMi1jYS9wdWIvY3JsL2NhY3Js LmNybDBAoD6gPIY6aHR0cDovL2NkcDIucGNhLmRmbi5kZS9nbG9iYWwtcm9vdC1n Mi1jYS9wdWIvY3JsL2NhY3JsLmNybDCB3QYIKwYBBQUHAQEEgdAwgc0wMwYIKwYB BQUHMAGGJ2h0dHA6Ly9vY3NwLnBjYS5kZm4uZGUvT0NTUC1TZXJ2ZXIvT0NTUDBK BggrBgEFBQcwAoY+aHR0cDovL2NkcDEucGNhLmRmbi5kZS9nbG9iYWwtcm9vdC1n Mi1jYS9wdWIvY2FjZXJ0L2NhY2VydC5jcnQwSgYIKwYBBQUHMAKGPmh0dHA6Ly9j ZHAyLnBjYS5kZm4uZGUvZ2xvYmFsLXJvb3QtZzItY2EvcHViL2NhY2VydC9jYWNl cnQuY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQBM2ET8sDhpf8GfzHc9oCwzGzt/X+/o kHK1T0cv5W44y7ftG6LmovMU49SPTfluGToRsMOeYFzDTpwYiqLjg3TXGs08Vuvo JQOPuSvW8ZACrvZJfSdns6XDMNTzUxRXEtchvrYRkE7bsvt0t3yOlSH8YvkWsBa4 vbAu9NdKkt0cDkoZobC5N4hI5Q0NfNM5Ac7HXr1h7dbLwC6arHPuw3B7j/jIGL5K MP9bsh6d78nkxPSu4XcXH18EUPSJHgqPcSyVHspLqLKq0zkDXuGMOIT4ayX0baMh /dkhanXmXp1XlOvq5Krnr+tV93z4vv8kqVDhslj3YIDeuW0PNRPJyxWF -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF/TCCA+WgAwIBAgIQF7RoshGLxBEfv5iK5HeZxjANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTYxMjEz MDAwMDAwWhcNMjYxMjEzMjM1OTU5WjB/MQswCQYDVQQGEwJVUzELMAkGA1UECBMC VFgxEDAOBgNVBAcTB0hvdXN0b24xFTATBgNVBAoTDGNQYW5lbCwgSW5jLjE6MDgG A1UEAxMxY1BhbmVsIEhpZ2ggQXNzdXJhbmNlIFJTQSBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMMBCiDsVQqC ly94e00lj7lwnvMYwpjmmLNYIfwH8u3V/2fP6UL4xqRR0/APWu2PgJGXHqsbNJja dd3VWs6VWyB5nYrU5AkgpZzr00cUUy7yStVC/18hbeZjN7s19ICHOJTa+c4AltcN 62sNfku8rk4B+PrkJq4kwDLk3Xw/Kc10ENOpCviHk27VQAkXk4l9OSOdzPgrk2M4 tAj/G/sB2jciREVyzVOIuPElOLQGVgK+c1C0hT8EYD4l+2H1EKlxQ0n1GyBlAtN9 QRtYhX2oJw6uC986sKSZuFzOgisuIxRvLA3i8hsRZMY47/nabE6EHsJFEVgT8Iqw AJc8tvXEl5sCAwEAAaOCAWwwggFoMB8GA1UdIwQYMBaAFLuvfgI9+qbxPISOre44 mOzZMjLUMB0GA1UdDgQWBBQ9OEQQLwt/i1EDPp5z9wNPX+vcWzAOBgNVHQ8BAf8E BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICNDAIBgZngQwBAgIwTAYD VR0fBEUwQzBBoD+gPYY7aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RPUlNB Q2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsGCCsG AQUFBzAChi9odHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9SU0FBZGRUcnVz dENBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0G CSqGSIb3DQEBDAUAA4ICAQA3JHbJkI2LaVdeT9MxXz4iXR/NUhHpNDgM/Lx1Uxm6 Tj26nCiiA2gVXih7ss+dhtNhCi3MK6v7/XX11L0ytTQl4jda+KXj7PIyrIIG/q04 p4viJ9BNx6hG7EasqfHT43HsviJTPJPZfje2DXDgDCRRrkJ4kR6Iq0OWZJ+92au1 S2PdkAsUIYNx/JAjEWJHNgfjebCSBUmTINAgFECTHlSKhaUOZGqz5LkKK8YOw19L xdUhKmcH+BEn+GhgZ0qPmAs22DWJLQ7Yxib+61mPy5/ZmHi2ECzK9L87ybDCJzNR GdCloDBw6t4o6ovCNohDJGpNYpqCM1i2DCg5bJhJIanQ2lAYFBFjBT7z5L0qx5sN uBcbHPQ1ba3XQLcMZng1Wd/MJyDJiIgyZaVMl/p9QKp5VzA7vI9UtKtFU1+2/cpy OZTcyEymj0hLxkGE4ApX7cJlTRk+MXQHR4NvkFN2oJIS4iNcbFP1/qcvW/059rOM ZTGS2uW+pklzDom1wqQb2bSfjw6Y5SJRiJX+2Wxdnqj2bFb2/o7MoZ58jyC/xzzx VHXHbmDQpMFILbJw5UI5q/FPFmTzyiQ7huMAeGN1kassKnCpPMhA+wsc3hfpfKUx S71GfvrjShWUOZCMbxmdnaBwsc3h5B5dHFzhcI6uiHdA7zGZVnm8jo+wS3/Xp2pS iA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWzCCBEOgAwIBAgIQE+GX0rScvXNx4EKWKvshGTANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTYxMjEz MDAwMDAwWhcNMjYxMjEzMjM1OTU5WjCBwDELMAkGA1UEBhMCVVMxCzAJBgNVBAgT AlRYMRAwDgYDVQQHEwdIb3VzdG9uMRUwEwYDVQQKEwxjUGFuZWwsIEluYy4xOjA4 BgNVBAsTMUNvbnRyb2xsZWQgYnkgQ09NT0RPIGV4Y2x1c2l2ZWx5IGZvciBjUGFu ZWwsIEluYy4xPzA9BgNVBAMTNmNQYW5lbCBFeHRlbmRlZCBWYWxpZGF0aW9uIFJT QSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBANfbFlJp4foFVwgOGEkglIEZG2RuvaGFxMPMD7WPRHMvZbAiwiMh r42mbBldzTj31/g78v3yNprXInOFOc7vAsCNNht2Bm/n2lH1FABrtKI83d+feZum N2GIcUyyFoIU7BotECeNdjUxgWUQBCSGR4Lfpk42y5HPePTESSbPUZT5bxX3Rkye gy7UZsceOZqIR00bb+LczTl+Vfyqg0hjmSrbcPMx7xYLHXjJOjWiHzmKo7XTyxvQ JyzlNPwXYIogXn14JWjAo/QdJCeIwTUNlV7kgYKJVggBgLpM8Y3vHAXyg7lDq5tL 2UqreFeFnLtecQZBH2xjqKZ9tOMWlQnjyd0CAwEAAaOCAYgwggGEMB8GA1UdIwQY MBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBQmVr2VcPIQ3RILLJ+p UeAaouEUrjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwPgYDVR0gBDcwNTAzBgRVHSAAMCsw KQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMEwGA1Ud HwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JTQUNl cnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA7BggrBgEF BQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQWRkVHJ1c3RD QS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkq hkiG9w0BAQwFAAOCAgEAdcbry9Igx7lW5ZHqj1Ux0kIXe/GO1jSJMW3uBGnREsdJ 8yU37aqW2KmtjJPtp1qjSDaFxnEfwEYPtOY7Q+Hzv7PquB+MSUACmabGVhRsiUiZ EO+VGSoZhBU+oufLnyznpk1yEct8N33eXLfZDfIxjNcdL9b0rNlQ3JDzB/7/u1+e hRGAgxEdFC35nRwfFDTkkw3rFB2waulE6xnrR5Lso9flex8hsPQYfTsEQYzAFqEN A74SWsTnoDsXolBbWvp16x7DCs95kQaF7ikLh43qq/9WhlyERzKk/dYWy/6v6m2D KhHsrxE0fme3gLLtWppPzYFku0vxtMT7rO6txGZUgVo/IiNnKbxJoAdXtRes+hcQ 3OYpXoRT2sGLcE2CRrEzX30E0Yokm+zwt3rb4ti5b+FuSoXhAo9NO2fUrqbz/Rz0 GaSZDm/GckUrtSzBlRr3MkpfVMMgBLnBu7thjQhXRwdGadein2JmzW5BJxCV3mqj 8sdviLlue0bRZv+ErRqeLA/xEhvv3EDeYdqi/qavjArr7M7rQQbeTnpVdPSVDLaL 3SEPX9A3PAa3bM5yS71dlkM2UKfFZknb1PgFTCofMSfpwl2vID0dhDwhcl7ZBSiA sMz4mNgVbzErIFMwIinIKJoQFfw+goLRuFCgEEcvDCKHbD9hofTxT+onlR4trMI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID8DCCA3agAwIBAgIRAOZ079Ushn9VAOfDXPFFl2YwCgYIKoZIzj0EAwMwgYUx CzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNV BAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYDVQQD EyJDT01PRE8gRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE2MTIxMzAw MDAwMFoXDTI2MTIxMzIzNTk1OVowgcAxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJU WDEQMA4GA1UEBxMHSG91c3RvbjEVMBMGA1UEChMMY1BhbmVsLCBJbmMuMTowOAYD VQQLEzFDb250cm9sbGVkIGJ5IENPTU9ETyBleGNsdXNpdmVseSBmb3IgY1BhbmVs LCBJbmMuMT8wPQYDVQQDEzZjUGFuZWwgRXh0ZW5kZWQgVmFsaWRhdGlvbiBFQ0Mg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC AATXjBeChjf07ykPL0Z4P/PCO5zuz/k/TC0by3F6bkE4TwVKKITTm+szhC+GFDbX J7tfK1pm6isuhD2kS2PLltLWo4IBiDCCAYQwHwYDVR0jBBgwFoAUdXGnGUgZvJ2d 6kFH35TESHeZ03kwHQYDVR0OBBYEFL6KM8VMfhgRgCDzzHdGXyw75SFqMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjA+BgNVHSAENzA1MDMGBFUdIAAwKzApBggrBgEFBQcCARYd aHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNvbS9DUFMwTAYDVR0fBEUwQzBBoD+gPYY7 aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RPRUNDQ2VydGlmaWNhdGlvbkF1 dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsGCCsGAQUFBzAChi9odHRwOi8v Y3J0LmNvbW9kb2NhLmNvbS9DT01PRE9FQ0NBZGRUcnVzdENBLmNydDAkBggrBgEF BQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMAoGCCqGSM49BAMDA2gAMGUC MGDiACaq19vlLN+janVSYMAnHD0idorYTwb32WQJsyYqYEZKaod6eWZawrttWfwO dQIxALSzWZyyQgkSh/Wrz9a4zFXaaua4jlKcLkBiKh49P58jLbAL8QO9/JbHeDxv SV1OTQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkDCCAxegAwIBAgIQNAhsIM7ejUlvD4HVEhIoTTAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTYxMjEzMDAw MDAwWhcNMjYxMjEzMjM1OTU5WjB/MQswCQYDVQQGEwJVUzELMAkGA1UECBMCVFgx EDAOBgNVBAcTB0hvdXN0b24xFTATBgNVBAoTDGNQYW5lbCwgSW5jLjE6MDgGA1UE AxMxY1BhbmVsIEhpZ2ggQXNzdXJhbmNlIEVDQyBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAZOsqY68mNhxhR7yqa8qTmX /IBB11Ma9wVKeYdXwJsywJAzlipb8eJFrORij1UVo506qYMrRQWMB2w7vMhGr1qj ggFsMIIBaDAfBgNVHSMEGDAWgBR1cacZSBm8nZ3qQUfflMRId5nTeTAdBgNVHQ4E FgQUIGBIwE1djDdd+SS42xm9lICCml8wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1Ud IAQbMBkwDQYLKwYBBAGyMQECAjQwCAYGZ4EMAQICMEwGA1UdHwRFMEMwQaA/oD2G O2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET0VDQ0NlcnRpZmljYXRpb25B dXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA7BggrBgEFBQcwAoYvaHR0cDov L2NydC5jb21vZG9jYS5jb20vQ09NT0RPRUNDQWRkVHJ1c3RDQS5jcnQwJAYIKwYB BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAKBggqhkjOPQQDAwNnADBk AjA8Yh8mBBP4Ny5op5m0iC6SUBHZlVd63OeDDwCwgM+X5vFBL9m0k2XmsfoliXE1 tFoCMAmrAFxn4iaOL5kNZS7IA15p6SyZv+yBVbCZsu6aVZjHqXjeAZNmfI8ptuD8 CHdyUw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGEjCCA/qgAwIBAgIQUQ4MOS1WahdBnAAlNFXvsDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTYx MjIwMDAwMDAwWhcNMjYxMjIwMjM1OTU5WjCBhzELMAkGA1UEBhMCVVMxCzAJBgNV BAgTAkRFMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSQwIgYDVQQKExtDb3Jwb3JhdGlv biBTZXJ2aWNlIENvbXBhbnkxMDAuBgNVBAMTJ1RydXN0ZWQgU2VjdXJlIENlcnRp ZmljYXRlIEF1dGhvcml0eSBEVjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAJvf/26whXZW5F4v9rhqnMaPl2NUsgU4M1Li74S0lu9bX8AuSeCTw3zmjTiN dI1KIEgsyoowRw0J41Ujn2/7xUyQdbwBiuaSTKCa44H8mVbJPWjW33qvpD1HxzJw gRC/XYMf0IE1wKwDpS5XDlaCy0hNdRfF1I6Hsc3lxLteaSdq+IXxPNhSoRHXOY9y vYcSOIU+O+VJmzrWJZ2H6TLL+ejKr+CxD9XUE4lA/1uD1rn+mHZpkrWJPfVi+bJ1 XIgFS6Da888PxigVU0bHp1D1Fql5NhbljvkdUWzr4PU4L6PFzcdJQMj1WBJnpZKJ Ywjji6ur4vKnbks01S3ZpAxvOUECAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5 v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBQEWUkqQVueCyM67ud2clmsPExa MzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAU BggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICCDAI BgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3Qu Y29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsG AQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29t L1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8v b2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAjIHsMGzyG0HSh 7+kwDyffMC0xm+XmRF8rq9GrckLXoV2Q120OURRFkPxSZj04yu34GcgVw9MultSY B9I89MoW7IYzPb24Bj2v9Aj2DPa9OKtzIeKk3pRNHH5VxgnLqtUUa/7oHOr3Hug1 NisINEBdjI4SpCvSGvFX4ti8DXQZOUBng+WYx3PEasLDtYs4LoGjFgSZLKqKpOL6 Jn1xM+Eh2a29PwsfKgFjYOvfHnczrxNmOnls+fRzBoMfF8URqB2cB4wN7lnxo+pe E1gBIfmfY82DQknyYj/NsP+8YelBb0glCwTFsBdYV/FJ6Bx38H2lCz7OT8/i3+C6 4eDM9xMOJYHq7stIZboqBLK426KKZrdDJ0g+J+c0PjrJp8PTSCh+BZAErUnmPsNr OHL3eQFPKGF5bD5LmM5qjxG8uvnrokLcPFysy3vYCakaU2EFKM8fFDcSYlGmHOw0 m856MpR7Z5hssVPL6AqLouhX71JkbPzJgqBbFQL9heSn1f1HQnLJMDIXLv7xXtbK 9w29TiL92QWVZm89lOmpjsgNpKYsa393OwUbSfsgyN42XzkjeMREWIyEQuKkIYxN 8yOwjNltJ6egEkMr1ktJByOFCz23QKrkV4b2RzSAQwzhPEKHGuS8Txx6mvA6dFgP 1I150U0DEaAMmD1HkrbeEYqhI1lJIA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqzCCAzGgAwIBAgIRAIUk7fFt/bnLwmjJsvue2XowCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE2MTIy MDAwMDAwMFoXDTI2MTIyMDIzNTk1OVowgYsxCzAJBgNVBAYTAlVTMQswCQYDVQQI EwJERTETMBEGA1UEBxMKV2lsbWluZ3RvbjEkMCIGA1UEChMbQ29ycG9yYXRpb24g U2VydmljZSBDb21wYW55MTQwMgYDVQQDEytUcnVzdGVkIFNlY3VyZSBFQ0MgQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5IERWMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE Bbnr5nLYjgKTUQG9uetBPuCxQoySjK51gblUDBRwjMGgeba/wVBDJw4Ur5xMlaar 0k8P5qjtcidYynJloPFz2KOCAXUwggFxMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0 SXbc4DXGY2OaMB0GA1UdDgQWBBRv7CzeZyiu3YJ3O3ZuFD/V9jsvpjAOBgNVHQ8B Af8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICCDAIBgZngQwBAgEw UAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJU cnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGow aDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2Vy dHJ1c3QuY29tMAoGCCqGSM49BAMDA2gAMGUCMQCWTJMBbSKUkmy8loWppEL58k56 gWHDDC3Iq349jOsVv+Xsocck97EK9/VfT7/V18ICMHUvN0Jf/CP8hmd38t2qcl4H cALKGBAhHzY6+BYCorJPQGEJZdBPPE2yUuBkLZYOJg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpzCCAy6gAwIBAgIRAI9j3zQJKTVSnUFrzlx38eMwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE2MTIy MDAwMDAwMFoXDTI2MTIyMDIzNTk1OVowgYgxCzAJBgNVBAYTAlVTMQswCQYDVQQI EwJERTETMBEGA1UEBxMKV2lsbWluZ3RvbjEkMCIGA1UEChMbQ29ycG9yYXRpb24g U2VydmljZSBDb21wYW55MTEwLwYDVQQDEyhUcnVzdGVkIFNlY3VyZSBFQ0MgQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjOdV PXG2HmsSJelWbv1sEaNOE233+XRaYdliCPJjib034Wvf9OUbCA7sIvVgYLnx6LXi ReRKZmJTInpDEPi4fKOCAXUwggFxMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc 4DXGY2OaMB0GA1UdDgQWBBQdFqwlaQDIg0G2S/+XyA0zRsgVAjAOBgNVHQ8BAf8E BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICCDAIBgZngQwBAgIwUAYD VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/ BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVD Q0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1 c3QuY29tMAoGCCqGSM49BAMDA2cAMGQCMFEmR5OU9rlIzKeBBXxshI5lzcS/GPeX odqHKlNnr/ui7Nq7KXQh+0oyzgbIpysahwIwK4+WPw2Xsyb2JUg5VgIUrtaVDVI0 02e0e+qo9g9KCcEOuWKhUwbpiMnqeTcD83I0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFczCCA1ugAwIBAgIQCNLhLSSNdqQnILOHCbgh1DANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg RzQwHhcNMTcwMTE3MTIyNzA0WhcNMzIwMTE3MTIyNzA0WjBjMQswCQYDVQQGEwJV UzEWMBQGA1UEChMNRGlnaUNlcnQgIEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0 LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgRVYgU2VydmVyIENBIEc0MIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3yoFqzAeuKh+QKRmYe9XEoRAyYUN20XF gnCJ4HcY1AxL5bSyvxDrp6EZC/U169o2/orr3nCmmV6S/MUMbUW26S19jag9KbjQ Tg+11UdeSdkq0Wx7Fi2eCOc4DGHsiSDWJ3vrt7ZMLMn4ZH/y+//TQvlqVoOSDg/+ vy7TKrkn2y8yCpmWeBOC03lORpyNSRLK085Mm70qJlxjhvPQwNzoh9ltKkgwFulR K/kYfZ1vtA/gRoeZbcZMxx4po93t10wwMo4R4c5selG1o+/R66n5/aZ1D+JDbEEV YwxhedSx1svFmL+vXw0jl2dm4UD62/AT+owBHYdjvqq8Otfz+Qu4SwIDAQABo4IB IjCCAR4wHQYDVR0OBBYEFPAdooeeuF5by2AF9ySxau5tfPb1MB8GA1UdIwQYMBaA FOzX44LScV1kTN8uZz/nupiuHA9PMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0P AQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29j c3AuZGlnaWNlcnQuY29tMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmw0LmRp Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMD0GA1UdIAQ2MDQw MgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v Q1BTMA0GCSqGSIb3DQEBDAUAA4ICAQB5rbCHwHbK1fgtHoq2RuvLLRZ2C3zLdaCM 9O4ja/r9Mx6vbSKxfJ+RGNT6XMLn4uGsnwSWHemi4GAIfi3wwt/IJxXVrOTTVAmN 10YBA3D4Kic3i4AsyNROnfTe0aXjvEcVblbVmZ/moZtKr+A3H5zYn2IcH6xifwqU McFCyzUSvP6KsqJcU/72DZ589vdgcWHlUry48nyoAc+EHD37hiI1HcaQkHFimaTx Panjxs+KIA/vvgm1eVNp+QydKFUU3VxnNnzQf8r1Pmkeusb2ZEIpccK6O8eO7Ytm oqAM1+mtsXlZqbpad8Tw4qmNKZitIEFK66ZWSLs9jiMtXOTSsFel+97oTsoxg2MD LaG9qYX4KS1wABqNGOkBKaHqmJv5V84fhBcbdEyU6dKiVEwzAlqpGiAIGqRUxiVz lI7KlfD/jmJKSkfDXDCPXConlNJnq6EL6GdQPU8lIKLU0heVwNof3snk8ubWgv5L AhrNoXqMhUgqb/3BsjzOczAzHTXvT0JvxL0h9K/HHAGu2A+uSkDUe3t17ZB9xze1 x+Txtaz3Nboji/o7eYE7yZr51OlzxsOXbe9Wsc5VuDEWNcfQ4S5+1x9wPyEbZzxr 1fp6cGlqDjekb7w2GdNvUXqAiP4Ckc8yerdGB2DaVCNGOx/o8flF4ktJL9BWtsW0 dT4BzapIpw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGfjCCBGagAwIBAgIKEAFmA0XdBoDjIjANBgkqhkiG9w0BAQsFADBBMQswCQYD VQQGEwJSTzEUMBIGA1UEChMLQ0VSVFNJR04gU0ExHDAaBgNVBAsTE2NlcnRTSUdO IFJPT1QgQ0EgRzIwHhcNMTcwMjA2MDk1MjQ5WhcNMjcwMjA2MDk1MjQ5WjBZMQsw CQYDVQQGEwJSTzEUMBIGA1UEChMLQ0VSVFNJR04gU0ExGzAZBgNVBAMTEmNlcnRT SUdOIFB1YmxpYyBDQTEXMBUGA1UEYRMOVkFUUk8tMTgyODgyNTAwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQC4SNnRN4MIUC5faRPsLPQ9ZBX+Nm3PNwrs 2RumMczs//qH6tgRZnom62qtPuCwV0sZQ5lGFGWggbEAfF6iaiZvGsbxfBT0dERl LSALU0FEty+kKVQ3AsKyylhwysci1t9fB+zL4lTVRamiX8Dtrwlm78QAvFyCAmaI GNaPICXU5exzNGj+H/+DRv03Q1CvDJ9HdCVvIIHSeZxStIxWhdNK4bCK31g8DU88 +SR/DBa6HSmkjHFl6tOVebXP3/fgpSg7PiXo9SVEPW6uBeQrISkzktvmjvoMOATn OkZzHoLmrLlaa/tbpG5CT+oRsfpFtYBZyyOQfLHvexztoRvqafH9gi19wxYIr20P vFIsMo2eTa3DSv4BTgCTn8Csy9/oEfxANDaUh5xX+2yKm4jJCmZInRfNLjJRsaf4 hLwowf5ogerSANzjuqm4JLQgx/uTUmxuflHHhshmW2QPTF9IAupj8EUc66xmD057 y8I8rUHHE1L1PtNtSLTufM16rpOgyE+GDanOkVe6LUMtf/bKQUxZUlAvI2jBKfc3 ACHao0zwJBjM0mIz/h4yMSr46toggkLSlaIZRKN1dNFhFaM2WqcCPoATbC6fTrI8 rcDNINZ2T56PBrn+8V2GjGbGGnmoom9P27KSs8F605IO1DLqNXmtCcaKt6mrnUcc ku91bectJQIDAQABo4IBXjCCAVowcwYIKwYBBQUHAQEEZzBlMCMGCCsGAQUFBzAB hhdodHRwOi8vb2NzcC5jZXJ0c2lnbi5ybzA+BggrBgEFBQcwAoYyaHR0cDovL3d3 dy5jZXJ0c2lnbi5yby9jZXJ0Y3JsL2NlcnRzaWduLXJvb3RnMi5jcnQwEgYDVR0T AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAUgiEtZsbX oOAV685MCXfEYJ5UbgMwHQYDVR0OBBYEFLOFnLCN9NBvVMCBCLr8/X5TX6mIMEIG A1UdIAQ7MDkwNwYEVR0gADAvMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnRz aWduLnJvL3JlcG9zaXRvcnkwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5j ZXJ0c2lnbi5yby9jZXJ0c2lnbi1yb290ZzIuY3JsMA0GCSqGSIb3DQEBCwUAA4IC AQCKAMoW4Fyy3C+iLMy6puE77QgSqKsaGlbMk9xguNcecwZmZH8HkNakvC/MBJO7 Hp5/0wnJ0uxADw5tnliXo1yDuSmkGDaQ6C+itdmafe0yAKZu2A2wZ2KJkoFs1sMo suuqsl3Kdxb9oQpsrPSbY5xurhNlRXc/aAZlWbVfDN9VlESaz/oII1ErES77zD2Z oGZY14lkfblWr2QEqDVnpWsLr7hL9in65j3eQjQWFPcCwC8NvP29EbdzzSxLAO/O CLwuyr30BYUMEOOSQfu/Q75UC/G3yCRuHQG0nfHRakFHXDwJJ90oQfGJ/MtlMapf M9RqeVjuw4No7MeRyaoEVZ7teSyrGcrYIVJ0/ZYAUHqmTdU5eqOFd8WlEi/Y1t57 FwYNH8MJVWvWEdD+jPOatWFII0FvmGmPxV7+VjF31RGpStsFTNWguGB68q4Ujc7v zdmAbMd2hGzNtNawaDoVMxB4kLjmw83mNOubZolG9dKg6Cy1cuGcdWneuHTV7gsW 9eEiyD/YlbF11tdTLVzsXfZ7Lj9/K8PFNwpkEumlBvd0re74PfQ0uZVF3srpTnfV ojmkYJZLP40pYKKYZK69KxLZs04i082ui36v3rXBGeNR5+yl7a7JUS73JJKBSCf1 jh1uzQMCXLutirDYLPbU4+P4XSMO8p/1wME6/etJ57zY4A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGgTCCBGmgAwIBAgIKEAKpgPtfRYXdCDANBgkqhkiG9w0BAQsFADBBMQswCQYD VQQGEwJSTzEUMBIGA1UEChMLQ0VSVFNJR04gU0ExHDAaBgNVBAsTE2NlcnRTSUdO IFJPT1QgQ0EgRzIwHhcNMTcwMjA2MTAwNjAzWhcNMjcwMjA2MTAwNjAzWjBcMQsw CQYDVQQGEwJSTzEUMBIGA1UEChMLQ0VSVFNJR04gU0ExHjAcBgNVBAMTFWNlcnRT SUdOIFF1YWxpZmllZCBDQTEXMBUGA1UEYRMOVkFUUk8tMTgyODgyNTAwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCd9bJaGqh3+GST+b3neWPc0+BIPIV/ bZm3NB0gYhacZlxHKTiiYsj5/e4GxPUrbYmEvVKnfP5lJ1kpr9rMskmBYaduzo0f c5Z3vWS8Uy2ZT4GZ0pvqgaHNM0mPD1tT0X6xDSy2CDkZ0jaWU1s+cWSwrgh2c9JO nQegn4jgQLDPFGmdDs+7fews2BfGShcqyRK3u9hoSABL4wJJWclXxVRHiY1Az0gh Z1LAPoc/+v+pel+ofdZZPiaMLk1N58A2ci6GesVASRPfUxDwoeOkVWMZt1r2JMYh 06nSy/ww/9lMEqAqiseW2BKoDRmCY4e1+cPB4dOJ5UE0XRJLEy7t994P6BHrPI4v i9Hjer970pDZb8OwlHfZLSu/s5QJITrIjsRIaJBzV7cYgEkeXdyv3Ps1SbaxZWpv zRjmQSs/kdB+k5KfSqdPkweSSmDZP49Y5Mab4l/KclqdBnR9++IC4PE5B944dYhu x4Q9id2h+y8c9k9K9JYFFbNmyfduTajk3FpKsvskmvOIG56ShCIfVkUTat7o25nd HLEdgeOox1gUV7adf1NsVMgwNNxcu2Ltzkto+gjbe/Qt8LF26L1hkcCA+jIjL504 HmRoGJ9t5VCxyvySOCb5PqjbLl9mx2+FAHF82CrO9D3XA2mtfyoZEWe12TVCfMbB iU6KyL4VL4lftQIDAQABo4IBXjCCAVowcwYIKwYBBQUHAQEEZzBlMCMGCCsGAQUF BzABhhdodHRwOi8vb2NzcC5jZXJ0c2lnbi5ybzA+BggrBgEFBQcwAoYyaHR0cDov L3d3dy5jZXJ0c2lnbi5yby9jZXJ0Y3JsL2NlcnRzaWduLXJvb3RnMi5jcnQwEgYD VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAUgiEt ZsbXoOAV685MCXfEYJ5UbgMwHQYDVR0OBBYEFI9Nh1FeEX/hmcOR8WhMP6xZBLGL MEIGA1UdIAQ7MDkwNwYEVR0gADAvMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNl cnRzaWduLnJvL3JlcG9zaXRvcnkwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2Ny bC5jZXJ0c2lnbi5yby9jZXJ0c2lnbi1yb290ZzIuY3JsMA0GCSqGSIb3DQEBCwUA A4ICAQC5Kle7JamsjB2fgwlH1em6ay5IldIjVbbIo5UrbRW7MR1YpULwmS3dEura Dp0JzFv4xwhpXMnlQCyfwBTzUpTIuRHU71AeNsip0G62kg8GoVXZOT8fFcQZnfQ4 oN3FhMxgkUKhbkILqPJFgcCN+P3mQYZnIRk4LWS9dem6F6CoIdcTefVRmNM41FjY coPpV799oBxnbuxOOsi0PocF4ki+2uC+xUBgRfyrVL+OiXivssDA7phVdezK397w 4CRxSM6GXSoYLa8rYuXBSkX4loSy9mLDLj/5aAO68gtunHCJxnxnAW7m2c3X9Qmf WHvwzKfxiLwxgX92k3cUnontQAvpi55cumxKqV/APOr44h6Fkpoh+qSkMAmTMgUU uIyD8s5Lr5bqkQI8R3DtRPku7a2xrJcqH6i4GyvS8yvljINgmxUxFFpu0s3+VR5D widLT71h+RL0HtQUXqpD/iHU/tEiK1Ku/T7vyabSkDdli3qxAqCb8pD8Nf0qZ5i0 3SOES0mjIV+yLWtQnCHf8WUXsoqmCtyLuNg3wQfB2Qg6Bh8UdzJPFKSd31R6e6XD fr4ZvrOGEIdRqUTIo5TfREkYQ8vTo0WTW26Krt8PRt2T5hEuNUt6hcROVt9fKTtO k2UZW3jW2eRsyfpIM6umnP8lyuoj3kZ0eefZM5PmoLeVS8DX5g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGezCCBGOgAwIBAgIKEANLjmb1CSD2xTANBgkqhkiG9w0BAQsFADBBMQswCQYD VQQGEwJSTzEUMBIGA1UEChMLQ0VSVFNJR04gU0ExHDAaBgNVBAsTE2NlcnRTSUdO IFJPT1QgQ0EgRzIwHhcNMTcwMjA2MTAxODE2WhcNMjcwMjA2MTAxODE2WjBWMQsw CQYDVQQGEwJSTzEUMBIGA1UEChMLQ0VSVFNJR04gU0ExGDAWBgNVBAMTD2NlcnRT SUdOIFdlYiBDQTEXMBUGA1UEYRMOVkFUUk8tMTgyODgyNTAwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQDLA0KYYGdTEPoULlPB6njtxH5Yxp6yhuThQv2U 8QATCAix3LChaZgNTqhYzhx3fndczjuRrBKbyLPZxwtRJtroXKEwOzDq2xKXSCVi 5rEPTHcGlAhHqP57844r3TqQ3t08MJBxVgxhkhs54HZUIw0OfqJy2F2OSI/K3PVr 4fOWcoQ7IljkxwjXj0t1Q4kn7zvHRv9rsXjqH/Qqe5Gkh48XWd/hEz4taQZNAQBj GibbctXIYqe4Qs4NjfQqs2Pv3MTfLl7P1UGRiIY5YoCyhOW1Is+L/iNPqxB1JXSv b6US44+AruNc8DI5l/7D95O2WEFcbwI1poGl0Aki87mVxcaxkW9KZARLZ1ASVTFU 75R/wW94ICyoW6cLhQ8/8hLUXwNaTDRFp/G7qex6QNvKLCHBB++tQ8IW3UZU2QZh es+wu0tFYq/R7+vbJ08eVbPx0+xJdiH8oRK0C0+OZoRourYHN7GFEUArCe4ni8mq wZLxDd9gpEi9K4nfHRbX7NSbtuhYak0rhX7i5xLiJWP+hLsJUZN2mE4QRtzFa+g7 I+Y84saYi1dZDjArMV1smt6r+tSdBfSGg9tnbnkjnYDeM5vvxUKZa0IUoEu/85xg ncoba0ABIGJ1yFhlY1w6ElcgC8gqzSDxl1aSiyrojaUKcuTr32MMyxPdCDFfpKUj AIvlHwIDAQABo4IBXjCCAVowcwYIKwYBBQUHAQEEZzBlMCMGCCsGAQUFBzABhhdo dHRwOi8vb2NzcC5jZXJ0c2lnbi5ybzA+BggrBgEFBQcwAoYyaHR0cDovL3d3dy5j ZXJ0c2lnbi5yby9jZXJ0Y3JsL2NlcnRzaWduLXJvb3RnMi5jcnQwEgYDVR0TAQH/ BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAUgiEtZsbXoOAV 685MCXfEYJ5UbgMwHQYDVR0OBBYEFGUpKxkrWkHTAWKbe0cA4hgIccNBMEIGA1Ud IAQ7MDkwNwYEVR0gADAvMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnRzaWdu LnJvL3JlcG9zaXRvcnkwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5jZXJ0 c2lnbi5yby9jZXJ0c2lnbi1yb290ZzIuY3JsMA0GCSqGSIb3DQEBCwUAA4ICAQB4 +iAcmuf4p/KOwYKFa5USNZ8v7Q/mahjlpEmwZPtnNRYEmzxLeX2/KR6zlBtm20M+ r47lB1YzRMBLmGP45SZveLSejN3QuYyLEkg9yPS/R9UQKPJH2fa/7bFCT0cEAhqq JQXp6S55beLKuggccBa8RINV7+iG9PpUy8zno15nREWc/81n6q3F4pYiys54nKF+ EaydPNdz9I+mAbX4GwOOXxmu6g0PTUoRahxwO2OWG9ZHVVQfdDhvZ13sddp7d4YT Ed9bUdCa5DPA0yc77YDHbw2EGAy/GVHN6K+oAK/sBzv2b1724lZTeHbeV2vq0Mrt d1sKdOvEoxI+t/+qmGKJ0c3rmMIMyNTPWG4ODU56RUumosRxvPzIjcoqyAZMoZhu sXfP6GEQoAFyjYilSdC8pV5PND1St7/HrfPkHlya4r7js31eh+UQZFGULj6yBW/2 L0/1lew3dxYpozckVIC6pJt+rWQR1CRjNKQDCjyQP8uZdm6Aoea2foI6B5SXrbGu YqvaQ6iPuqPQ4/a9qVkIKl6U5cmWO+jTZlQofQY0kPKi51mB6yltt2ksyqmJBU8a Hloc31nUZVvDv/1uda8zRKq7CJ8SyUqiI0WA3LjJmZiTOSfBKzw0qj8I9GF26gu0 tAeYhZndeblh5f7xLKdoNOR3EX62fnt8izYJur0xaQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFejCCBGKgAwIBAgIOSPWzg48IYKQ5SX8AAQ0wDQYJKoZIhvcNAQELBQAwYzEL MAkGA1UEBhMCQkUxFTATBgNVBAsTDFRydXN0ZWQgUm9vdDEZMBcGA1UEChMQR2xv YmFsU2lnbiBudi1zYTEiMCAGA1UEAxMZVHJ1c3RlZCBSb290IENBIFNIQTI1NiBH MjAeFw0xNzAyMjIwMDAwMDBaFw0yNzAyMjIwMDAwMDBaMFwxCzAJBgNVBAYTAkpQ MQ8wDQYDVQQKEwZKSVBERUMxHTAbBgNVBAsTFEpDQU4gUHVibGljIENBMSAtIEc0 MR0wGwYDVQQDExRKQ0FOIFB1YmxpYyBDQTEgLSBHNDCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMrq3JgbD++QXP5p/hgPR0xz8mrqc/kEU6ELXKywMmwo /+urkQfJPpR0jmpZX20yqBvwnjW5EQK/Hyv3wl8ULLAAbVRIJYqU1SBhmagEvaow TxO5Gt6Y1vVJY++Z0XxZCN8hJhJMBvMPThAGjeysFOHRSg6zbJJXFSrj7ES2lSc8 deyPpIbuE4xQeUSlG/ptQO38Hf+G7HQw8T7pIc3Bvuw+VHx5GB4vS7r17/CGCkDQ c38bzUmYiR76VeZK06kFCaoD3Z9i4Fa4h3e+qFfw5Ln1UkDeSWee8/mHXEYU/X4u 5WmBL8hGYQyohOcsmu/xcCYVnqBidiHBwo0Vzp2jkO0CAwEAAaOCAjEwggItMA4G A1UdDwEB/wQEAwIBBjCBpwYDVR0lBIGfMIGcBggrBgEFBQcDBAYIKwYBBQUHAwIG CCsGAQUFBwMJBgorBgEEAYI3CgMEBgsrBgEEAYI3CgMEAQYKKwYBBAGCNwoDCwYK KwYBBAGCNxQCAQYKKwYBBAGCNxQCAgYJKwYBBAGCNxUTBgkrBgEEAYI3FQUGCSsG AQQBgjcVBgYKKwYBBAGCNwoDDAYIKwYBBQUHAwcGCCsGAQUFBwMOMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0OBBYEFLmOzfHsei6cuetvCxzE1KwZrqFUMB8GA1Ud IwQYMBaAFMhjmwhpVMKYyNnN4zO3UF74yQGbMIGNBggrBgEFBQcBAQSBgDB+MDcG CCsGAQUFBzABhitodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290 c2hhMmcyMEMGCCsGAQUFBzAChjdodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29t L2NhY2VydC90cnVzdHJvb3RzaGEyZzIuY3J0MD4GA1UdHwQ3MDUwM6AxoC+GLWh0 dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290c2hhMmcyLmNybDBNBgNV HSAERjBEMEIGCisGAQQBoDIBKBQwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cu Z2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAKyc 4WX95701EgfaSuH9UVrUheyYhoSwwgo5i7f1rqdEq1m0fIieynpj5RIcZWLTtr0d OmuzBaUvNojbx4jwokj+dR+GUNmoXA/MozukJE4iWAWT7j1xNZHgVHFbd7nFvBfo qnRJuY5xVAxSD7hdWEpsriIpBt4c8RCWEuAxWqxNm9a1YJd7pYiImrpMrs3zV5kE FR8rPtwFM35wgXHpNXp2Cws7O+6D2oH6gHFt4yQi3dFR+eb58TlyFlAV39lzcor2 zUYuMAHXibsQh+jm+foI2+zuDeZFc06ZT+bget3Rpxb0S9s3RMiSvyyGRbbYWSaZ QB5sckV1ZhlVaaiqj5w= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG0zCCBbugAwIBAgIQc2gOvSe6bcTfHuL72QD1ZTANBgkqhkiG9w0BAQsFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTcwMzAyMDAwMDAwWhcNMjUwMzAxMjM1OTU5WjCB5zELMAkGA1UE BhMCRUwxFDASBgNVBAoTC0FEQUNPTSBTLkEuMR8wHQYDVQQLExZTeW1hbnRlYyBU cnVzdCBOZXR3b3JrMTUwMwYDVQQLEyxDbGFzcyAyIE1hbmFnZWQgUEtJIEluZGl2 aWR1YWwgU3Vic2NyaWJlciBDQTEeMBwGA1UECxMVQWRhY29tIFRydXN0IFNlcnZp Y2VzMRgwFgYDVQRhEw9WQVRFTC0wOTk1NTQ0NzYxMDAuBgNVBAMTJ0FEQUNPTSBD QSBmb3IgRVUgUXVhbGlmaWVkIGUtU2lnbmF0dXJlczCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAKY8ErGgOX+mdyMGIqvDkIfzGh4eN4GzJfqnEnURUylY A1Fx2bdepctAbZZSxcOjFBonBhqqaM+1+MqJEBTu+dRi8P7EZaWIZuLPVZLSps1k GlhCG6z2uNg3mYUFEOjmigySIe2Md0IUwjwc7mqKm6Vd/Jttp8cbz/4AF4EU6pIw etLEbI0Qt8rgPOt4TC8zVyS9mAYkcxOSm/bPVg6XX/WSR6qUw0kzTb8/7koNID7P 1W/W3KMy7kYii6eBSQBo3clFmVkfTXJbRJE12KxGiQDvPXlppePo4U0zaaWFEiUe Vr4TsDsGi03Fk9L8iASwIB9ixaKLIL9pfhRvW8x8BQw3rORWxNHs8FurQDxzQMU3 5o1S2t7u98nGRx5ORy++Gq1589LDNwUdzYx6xn9XxfdC9iBGzF0BqUceOSIaPB9J 9JBenFI6i0uTNQIeiUJ7I0KtGII2xzhzJgu95RMNqVQ7ic9KFlfwhC+7Cj9peBw2 iJd+fqaJxZFzo8f+HP7GrDskpPFEc9dHVGnMw04otC1D0Exo9WhUu+Fr1ZA3Pl++ npsxFOMOFDdXOmEIp7KIdCfm906DRICSPp9zOlLxKHVjn06OGgBVTChMgIUPrM0o moVLi9ThQqCkHKBZViqc4JscUsV2ZYpnxIFvCDUzPoOx9qrat9UDn7iYHgkTnO9h AgMBAAGjggHKMIIBxjASBgNVHRMBAf8ECDAGAQH/AgEAMIGBBgNVHSAEejB4MGEG C2CGSAGG+EUBBxcCMFIwJgYIKwYBBQUHAgEWGmh0dHBzOi8vcGtpLmFkYWNvbS5j b20vY3BzMCgGCCsGAQUFBwICMBwMGmh0dHBzOi8vcGtpLmFkYWNvbS5jb20vcnBh MAkGBwQAi+xAAQIwCAYGBACPegECMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9z LnN5bWNiLmNvbS9wY2EyLWc2LmNybDAOBgNVHQ8BAf8EBAMCAQYwIwYDVR0RBBww GqQYMBYxFDASBgNVBAMTC0MxQzItNDA5Ni0xMB0GA1UdDgQWBBSNnwb0uqjLlhlG +a+tFL5TUMUCiDAfBgNVHSMEGDAWgBSHjCCVyJhK0daABkqQNETfHE2/sDBnBggr BgEFBQcBAQRbMFkwVwYIKwYBBQUHMAKGS2h0dHBzOi8vcGtpLmFkYWNvbS5jb20v cmVwb3NpdG9yeS9lbi9jZXJ0cy9wcm9kdWN0aW9uL2ZpbGVzL3BjYS0yLWc2LWVu LmNydDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQEL BQADggEBAAugEr5cuj5Wdf8MwUsaNM60OV7Hqz7xRwukM0jApZRua8rcTQ5eUHB+ 9r+O3PTWxcGQx1YCjhYtFTluNWv74tgwrGt/uXcCqeYsA7VsgQQwMagOt5HZ1Bcf pfuKrcX9XOW0e81Ah/EZPPcghiN4cN5mglQlnFMpsYPxQk24YRRrG/6rlT6WlRUm SAnEy+eBYmfDYUomnxBkp7tYo10T9hOw79oZP2WA1GqbFbbkIK/pGnHiGoMQ6RJI K4NQvzEvxPStObLPX3SExfv+/vwDBBmcmFzegR8/Y6OvkJGtu1oY/YjRnC3p2Jia WaykaLP7F3pLHV94Y/afC7WEZMq3jsU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGzjCCBbagAwIBAgIQCoC8dJ8/yPbFC94jGvcBpjANBgkqhkiG9w0BAQsFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTcwMzAyMDAwMDAwWhcNMjUwMzAxMjM1OTU5WjCB4jELMAkGA1UE BhMCRUwxFDASBgNVBAoTC0FEQUNPTSBTLkEuMR8wHQYDVQQLExZTeW1hbnRlYyBU cnVzdCBOZXR3b3JrMTUwMwYDVQQLEyxDbGFzcyAyIE1hbmFnZWQgUEtJIEluZGl2 aWR1YWwgU3Vic2NyaWJlciBDQTEeMBwGA1UECxMVQWRhY29tIFRydXN0IFNlcnZp Y2VzMRgwFgYDVQRhEw9WQVRFTC0wOTk1NTQ0NzYxKzApBgNVBAMTIkFEQUNPTSBD QSBmb3IgRVUgUXVhbGlmaWVkIGUtU2VhbHMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCuoNs3GyqhKmdIkt7A837+N6BwCKvheLsEml7ULWyUjYz9RSem 6I1mYhoyAsXqNDSm2SeMjrXUhyV4KpgoVAgp6xIR/TGHfRV3oIUakvQpw+12iZIy JChzesVheeganNjydYvjJ2PLfxdY2EFnxE/fQVD0kvLhotkxQGvTjk06A0lD22bo o6UYzW2Fyvld1UsQ9IcgMqB5suD5ztPZo/Y32i7Dyt8pAnxfYwjQJ/AxauRC9bUs 3CgAX6NI27abdPKKPK7VPrU7MJogrMMNg5Q6JR5O3dZ81yQypP4qHYaMWzDqGW/c kihMg6y2AH3DipRa8E8Mc2zjp8vW90nWmVXIamGEtLMDsaWT5dwalqHErRaRWva5 JGa1OsBu7nXs9AkuJkpHBjndArCZuZHpmO8ulHv9ybmcSjRIJ/upzvonvJPUlAQ4 Hq8ZhrRi+DXBUxtK8h4LWSFXhh7Buz4CqKLAiIjfu9ZJxflCC8Qe+OnVCUKrxIKP 4yW1rpELEBpoTH1SEYbDHkGmZI3hxZVgwPJ864/9QPrPij1f6Qv8mhS71CGpmWt7 JDtHQK4jdJYC1cVmnQEW3xWH7qSnew4CYGvytbO27psEZo3yo9oAOrYVxnIW59Kw clgC7/3sjtpeoz5422Fl7ZeEOOzd8P6ZtQAD7bxvg8y3snmVzLhegQumSQIDAQAB o4IByjCCAcYwEgYDVR0TAQH/BAgwBgEB/wIBADAvBgNVHR8EKDAmMCSgIqAghh5o dHRwOi8vcy5zeW1jYi5jb20vcGNhMi1nNi5jcmwwDgYDVR0PAQH/BAQDAgEGMIGB BgNVHSAEejB4MGEGC2CGSAGG+EUBBxcCMFIwJgYIKwYBBQUHAgEWGmh0dHBzOi8v cGtpLmFkYWNvbS5jb20vY3BzMCgGCCsGAQUFBwICMBwMGmh0dHBzOi8vcGtpLmFk YWNvbS5jb20vcnBhMAkGBwQAi+xAAQMwCAYGBACPegECMCMGA1UdEQQcMBqkGDAW MRQwEgYDVQQDEwtDMUMyLTQwOTYtMjAdBgNVHQ4EFgQUbjP/zNWQjlu+XMsj0M8h PFHmtyAwHwYDVR0jBBgwFoAUh4wglciYStHWgAZKkDRE3xxNv7AwZwYIKwYBBQUH AQEEWzBZMFcGCCsGAQUFBzAChktodHRwczovL3BraS5hZGFjb20uY29tL3JlcG9z aXRvcnkvZW4vY2VydHMvcHJvZHVjdGlvbi9maWxlcy9wY2EtMi1nNi1lbi5jcnQw HQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IB AQCfv9lDDvcwrktxZUzLyNviqv/eC5KCBPeZSOVD12l/XmC9MknM65lQZpD2jg6d lq2agpBApKuXEwf01WREkt+ZDXcMhVscXD42DibVfa4214chXkpi9Wi82KfEIajp 4RkMfif1/YBaNYk2VZNWxnBdPur7j6+0fzamK5U9GWkzdkiL1cVDvqObzCd8pNHN jL1+TGzM9fnmCML1RGmFq6k7Dk1hfO6JU9d58rSCEzuImCUk9vTAwB/MWOsgV054 2ZKXPNm/q+S8d0rFEae5b4+LqxIHbnoVzmKJgDvgn2XYvdSwEa0TEHdwSGEicWqy 0wfj0vCceedt2EtSo6unWvbo -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF6zCCA9OgAwIBAgIITvIyF22b6hQwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDQwNjE2MzkwN1oXDTQy MDQwNTE2MzkwN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa 4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQCE bDsNKn8UqMQ4vI0B9pLrHrTAOhxpfGGypTl5Uexh23OJBgmsg/fArRqW0+rFf/j8 aBAcn5dxYqK3469cZ8ILsVko7sCZpP9uaxSJmWZ/K+ObMqFoY+rl0t/XTYSO0AD9 y47xhcjI8r5/CsPABTPhfSRI1v4gsX2ulvwY91TzQBAtrj/j4P/l4bTx6RuU/af+ 07X5/ISKaOvNMEbpeJMvUZs3T/M9hfdf00pkUB9Qyf1iDbqOBDJSWqnZQ0KBwlbB O1nIP6uBHqP3C/UCWgU9gEHLDfvwQ4mddFeYeVDiK0+oiaTjtqXzdVVrQqTPZGoW LA6ywP79lud6rvFwehjr9OawGMFrWEEVdwV7hncrwkYW7rIvW2xMvjVJO2noQiwR p61chGs5vigIm9INwSUb9F1kgdHsOg/4m3kknOtMgIbfOL9GalCFmL1X4PxL3zTg mVNc1te1s9j4kTshdfS/Q4M6XLDpZ7tx5cQeYBxzoDyrxs4JN0hF03vjI/v4YyYX v45KNhr3plQWDqkVg8Sx5HSsajIO59DbPWncyfLRcQAsFPkCCPBkp4gWiap1VAQJ JvnpGo+TyX/HIgZsE7t6iCPyJK7OjSYAvMSJKqMVrbbOu6b+eCUHYhNwvXv9DaaJ 6NFjcxoVkAHbOQw7vTuo5CKZLA/D1wql4DOPDruPWA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEnzCCA4egAwIBAgIIWA4AsU6GzjUwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTE3MDQwNzE1MTA1NloXDTMwMTIwMjA0MDAwMFowgYIx CzAJBgNVBAYTAkNBMRQwEgYDVQQKEwtBZmZpcm1UcnVzdDErMCkGA1UECxMiU2Vl IHd3dy5hZmZpcm10cnVzdC5jb20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnQWZmaXJt VHJ1c3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRFYxMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA2S09g4nW7MJXvjg4CDx2/w15zGQ33aTqLVCG2BzI VtR4gIexpA9TIK0yNQMz+pY+gzE8YlVIuDfDivRCOF2XTIt7FquTqZAaFePZZp7k hfy4uXZ8mrNiLbgRZs6ohJMY+NxWrOtu6iFj8F+DB8gzfNeCueKZlP6IQIJRB+uu W/tQKw89b8RBKRREeiPC/3012ARrP8AiSFeV5wSl45Dpfei0f0Q1apPpFenPROP0 4bOCFWHi4sxbpHu3zaImcr1kPh/7VCGVhqMqmdmQiF6TyjSOpLeaBSyV3x3Lu5Q0 DOVMY1Zc1Q2yRXkw+Sxxw+1MJURAiWPBgt/XUNcJNSTihQIDAQABo4IBVDCCAVAw NwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5hZmZpcm10 cnVzdC5jb20wHQYDVR0OBBYEFDPfej4CeZbrtgzAY/p1v5IizZH6MBIGA1UdEwEB /wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUnZPGU4teyq8/nx4P5ZmVvCT2lI8wRwYD VR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3LmFmZmly bXRydXN0LmNvbS9yZXBvc2l0b3J5MEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9j cmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1UcnVzdENvbW1lcmNpYWwuY3Js MA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw DQYJKoZIhvcNAQELBQADggEBAEHyhz3o5NBAdMuE3xCOXmsoJjQE7u7qYtVALMkO PFG33/BT2TSCfWmZNDHdvdpUdaiQyD/RMQJEvbVQtmG0Faz+eAATKN1kc6ut/4A2 BsQBQWuq7mhMtmV3JDsc1Bole0/AHzmjRfNwV9iuZ3rWQwit76hpdn6GbWPA+DPZ X61p+bAYfFLtQoENwdPgRwTMmz5Is6rY3lAbb2dHrcwCpmptI90cY3V/1wJtQ+U0 jyMk/JY0JuWVDLcS6lURUBHQJ8VT8hPtugfWGxo0ATnXSxfrx6aNcXcI2pqa2eel +g6rI8GpT0RzPCFHokoGR9aMbxG1k8nt0q0O7V9J65LCp14= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEhzCCA2+gAwIBAgIQfAh2rlH1LxJ6lTJHtINLYjANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE3MDQxODEw MDkzNloXDTI3MDQxNjEwMDkzNlowWDELMAkGA1UEBhMCUEwxGDAWBgNVBAoMDzNT Mk4gU3AuIHogby5vLjEYMBYGA1UECwwPM1MyTiBTcC4geiBvLm8uMRUwEwYDVQQD DAw0ZmFzdHNzbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDg ymOpAywva4kCvaEMzpCB4hjrihUXs6M5uIBI+Yg9A/bDNe44JbtT/0T5VRkdykgG SQW23IvW4ZbJO+Zfw04EoMY2xeIlUqkoMvJn/L4mwwkh1IUFpoDaCgablsIag3Vl DL23NnXAkZ9sMEv1fsnsuArjKXqXOZYTrw+EzZu+AvfnwYNu3EIRnL2VEbA2ztSZ busiZLbF9eeK7W1zYO6NACcnayMwGVmtrgG8Fs5CynY7WA8sxYgp+6Uy5iJz1Cqi DqDPJ0NO+M5JcPFWUyfEBbW2pYqVP3jPjRVyyNvDl7ZSWiYDO92Miauerv9uONDp E4sihtcjj7WJRgKYf0hVAgMBAAGjggEfMIIBGzASBgNVHRMBAf8ECDAGAQH/AgEA MDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9jcmwuY2VydHVtLnBsL2dzY2FzaGEy LmNybDBuBggrBgEFBQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5v Y3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNl cnR1bS5wbC9nc2Nhc2hhMi5jZXIwHwYDVR0jBBgwFoAUVJndm//opw6jGZ1bvkJX 3zD8jzIwHQYDVR0OBBYEFA6tVcqw205fK/8+cG/xbNfSc+VEMA4GA1UdDwEB/wQE AwIBBjARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBAHypaB4Q uLNVqLAAQzeVQ6m1n8yOUnA8ACAG6A9KXIn+ptotPku5Qg4Gr8xHmFLXCRNWWPYI 2/G94gcAsDgC9AHCQAOaMXRNqfd1h0+X2NvxNVaWF/BW/vhqnYy0EgKiNs3QNDUv XtGbJOySyDcggemJclWOwGSx3qtjMgy2dBH5iH4s/Yw2M72JLE6IFOU/WXdtbFOj xDXdpCnSasnBkaDzE/Y8LOyGnduZg+Zb+G13/VM+Iv4jGtiUIgjLzFy4o5o2aZyI FgHHgIIu1QWX5G8DSq/c2CJTfuib7S2+yBLyX/CFVSX7jRdzttzj8/E0lyu++J5z JLS4h8tbZUofhho= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHdjCCBV6gAwIBAgIIXOQFBbX8I1IwDQYJKoZIhvcNAQELBQAwajELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjE7MDkGA1UEAwwy U3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFNlcnZpY2VzIENBIC0g RzMwHhcNMTcwNTA5MDgyNjE5WhcNMjgxMTEyMDAwMDAwWjBqMQswCQYDVQQGEwJO TDENMAsGA1UECgwEQ0lCRzEXMBUGA1UEYQwOTlRSTkwtNTAwMDA1MzUxMzAxBgNV BAMMKlVaSS1yZWdpc3RlciBNZWRld2Vya2VyIG5pZXQgb3AgbmFhbSBDQSBHMzCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO2QTjta47kdkgQdFCE75qNE PJDvB1xQ+PP9v7Hez8VmrOUW+r3Sjp1K4z9c0k4KTUNRZpeWo+Jkqrg8P5OzQ1V6 a1vqIZEdCcERI+nR9/0ZRqpc6ZVUHQGZ1pm8wxTj2hbfbIEkbHfDaaXrlE8UWbMY qlD7/shhiiUhm03yEPI5VFhZXk1W8dT11fagYBJLWr5A0jXSAQ9OOBuGY+bv6hWp oON61ANgwoTDzN7a5/mYvYZ+ICV/iGaOXJAoDplaYW2ycrTLS/HlCIPHfqtqTbkP rqdY4/PN1RNYr/+JcoFVHkk75JrcIRZ1Afyyk8l9JX+DpIIbLS7LQVzFlzwQ3A94 wJ8Q3hrfnEWQ32rvzE2+8aTBf+8adsTnnIUFWy2cHi/b1vUK7E2P06KHcbkRmD83 7qwRkBDDCMQHO0ochfpxfen5eRFRT6JNmxskClk9A+JguJeYGxyNM+kRCqN2YLGb IoUmaVC3U/L14bkHzZtgNwRN4trB9yGkI1VfzBEpqxQyr9/F7uu9T1iFjhP1KWSK aTDUU5BafeCVbWaq/95/BubTGsQi2XNyoAPIE+0EhmgLpNdLlCfbI0F0Hj5Jchrz EoYJxk9ohi0ZuNDm5xmOR6OZpPM8iwf+M17VeP9lFb/7Tkw8O1e4UcYfjF/RuXUO PDh5GNH24iTSnjfjC3WhAgMBAAGjggIeMIICGjCBmQYIKwYBBQUHAQEEgYwwgYkw RgYIKwYBBQUHMAKGOmh0dHA6Ly9jZXJ0LnBraW92ZXJoZWlkLm5sL0RvbU9yZ2Fu aXNhdGllU2VydmljZXNDQS1HMy5jZXIwPwYIKwYBBQUHMAGGM2h0dHA6Ly9kb21v cmdhbmlzYXRpZXNlcnZpY2Vzb2NzcC1nMy5wa2lvdmVyaGVpZC5ubDAdBgNVHQ4E FgQUQ+41v2d0P5/MZRXi2cVXJdhBiNIwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNV HSMEGDAWgBRD600A05WTzqZ8QA1tEb450TKu4jAlBggrBgEFBQcBAwQZMBcwFQYI KwYBBQUHCwIwCQYHBACL7EkBAjBdBgNVHSAEVjBUMAwGCmCEEAGHawECBQQwNgYK YIQQAYdrAQIFBTAoMCYGCCsGAQUFBwIBFhpodHRwczovL2Nwcy5wa2lvdmVyaGVp ZC5ubDAMBgpghBABh2sBAgUHMFEGA1UdHwRKMEgwRqBEoEKGQGh0dHA6Ly9jcmwu cGtpb3ZlcmhlaWQubmwvRG9tT3JnYW5pc2F0aWVTZXJ2aWNlc0xhdGVzdENSTC1H My5jcmwwDgYDVR0PAQH/BAQDAgEGMD8GA1UdJQQ4MDYGCCsGAQUFBwMCBggrBgEF BQcDBAYKKwYBBAGCNwoDDAYKKwYBBAGCNwoDBAYIKwYBBQUHAwkwDQYJKoZIhvcN AQELBQADggIBAE0I9e5Jih8/6tGfQfIavZ/4quQh0StA+NsU6HT6fCQ3lVtwQOrw /0ZLuCKMC3/R4nCGXCF7UPjDvoHdLkUweNcwK/4QwO15dzTN8EEDy5nXWMkIxSZT TGS9zkRf2TQhBrhvbFZm0otWDRYFIPX1H2uJg9jAyiaWuPmydLCyH//Robb4wLk6 OIfCqnu7UOjywVvLhbtnvntcf2hE034qX7SuxI5uGCrYMr0nzvyQYhnd6WKP6ro/ zK5YPa0htjgSoXaZcXGPDzwSW85Whwk9l0iBEZVGNOwfEzYsL2ZYx0jcspcmL5BR 16DywtqA6CirxgLFgHn11U7bWBYu1qRYqObZqtjvVMx5ix/pOIsL0Ft2s0+UNPRg 7NcZZPaXDheqkooi3LBeuuykMEfOcEeCyy+BqtPzN4ZouBXL0undPfl0cGPC6/Az eSOuYBjHA52g1Gu66I0tvzAuufqsPQcpL3cNVpnVycQtkgctvasarvalF9JcUuqX zgmdMQLxZTVKnEtv0i9RsggXK6/cjO3eYzSPjoo2zljwbYW7GzKTdhBq6qKgzY2D qa3/GoNpcQXukIDvQc4q+cAeyBcUDbhIBcURaY3fEBwWx2KgMv2dDHYcDd8Y/7yz +jsuj/YVuIQcPrsm1LXsi2MzEppR1seEx8UpCg6Hn6of94m24lDX2BW4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHKjCCBRKgAwIBAgIIHYV9nrmWIAswDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjE6MDgGA1UEAwwx U3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFBlcnNvb24gQ0EgLSBH MzAeFw0xNzA1MDkwODQ3MDFaFw0yODExMTIwMDAwMDBaMGUxCzAJBgNVBAYTAk5M MQ0wCwYDVQQKDARDSUJHMRcwFQYDVQRhDA5OVFJOTC01MDAwMDUzNTEuMCwGA1UE AwwlVVpJLXJlZ2lzdGVyIE1lZGV3ZXJrZXIgb3AgbmFhbSBDQSBHMzCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBANEmRf9a6VvvUfEdQycq0IJzCoixl2o/ BK5t4BsQfe/Gk3EMUFPoTI6MStZ0JtdE/D/90GMkX6BduLC5+eHGuYhCPQE06vKL txjwRg/n9s24nTRwgE0bcsyDaIQvK0CC8Mm+CY6uQXAIFr1S/Djm+RCl5AxJdUKO QyfCYO6mTtxRR+3/7rllCBCr1HehIASROlFE+C8SSSJd/tBIno6oRfS48KuekzIW y9uuUD7VyE/xLmOG40dEZLDi7jFE06VYny1MYxGzlpnllgYJCvqpUpEJLZi+Zj+4 PfiXLIBCkyOJXX310N9Db+Zy5knYQyD/6X5U3poxuudHeHbBQJQUW1IzwnjBTKWf AO2TdXhmGAse4Cjmqw5HJBmflh0k6kJ96j+FurnFCyXLfEDLvDSaghtOBQeDG3yr W1mgu2Ts7aFmDUZ2SesdhdJ3HYGlKXiSbLl3Q/qBji6TXa84disSpnnLQBWJ8URq cD6P6oQfav8wmKxnmxObGQYVP/OPlpowoBJ0hw5e45nT4B2JKY+4ObW2Iu673MTo Oi/2jftxSixKf2ALOGLS/DWtcove9eMztdsDl1G0cNSm2JO0ui+HmDp1BFgY2EdI HlJBdhATMiXLSz61RBVd4M0J8dovRXi8qvt3LyQ2F9UkaOhckSFNAz9KvsC9LSTD AVFitjUPmXyfAgMBAAGjggHYMIIB1DBVBggrBgEFBQcBAQRJMEcwRQYIKwYBBQUH MAKGOWh0dHA6Ly9jZXJ0LnBraW92ZXJoZWlkLm5sL0RvbU9yZ2FuaXNhdGllUGVy c29vbkNBLUczLmNlcjAdBgNVHQ4EFgQUoNJNB+c0pkpaSwmr1Fgb7UkbgdQwEgYD VR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBTurG1A6tUEaocsVXv1Py3a7tus 4jAlBggrBgEFBQcBAwQZMBcwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjBdBgNVHSAE VjBUMAwGCmCEEAGHawECBQEwDAYKYIQQAYdrAQIFAjA2BgpghBABh2sBAgUDMCgw JgYIKwYBBQUHAgEWGmh0dHBzOi8vY3BzLnBraW92ZXJoZWlkLm5sMFAGA1UdHwRJ MEcwRaBDoEGGP2h0dHA6Ly9jcmwucGtpb3ZlcmhlaWQubmwvRG9tT3JnYW5pc2F0 aWVQZXJzb29uTGF0ZXN0Q1JMLUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwPwYDVR0l BDgwNgYIKwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMBgorBgEEAYI3CgME BggrBgEFBQcDCTANBgkqhkiG9w0BAQsFAAOCAgEATsbPEGnVr5GNNwKmxVATKScA vSi5HXqVS4VAQpHuJuUk+BfvRRcipkdtm9Uwsp3RvMImrCbzkTLlgHrNIaCfbhWS xj+fCDhPwXgVLIY55IGDmA1iuuULa4B6n9uvVPTKJG02ux8odD5082AWFEec5iBB EvGPiwFkVpWZwMotdJDteH4XloP9GGyDIoqO/4KwT+JWz3E7/vDzBPpugkHnqLQk 4CvKgiWSsFW3+G5toMbHe23UZqx5JYRd0hpXkpKWsvfpbkc6nH46mKXEdInIkWgb xkUJpiyhW7rNOqOnGSpEZGDbkKUKmdaYBjH4qZY7c5KRFpnV/00Uhg6t2L9yMaBw Kf+2BVlS5fg9TouS8kY8Nqae4BJ/dpA7k6bQR0c4XB8JlTz35q+F6/Fx9I9GH5Ci DJyYLkDO9wAOC6+lQ70cRZ6uC3W0h3xKAQi46gFbkGVJyqgzgHNXgl7/P3XwJUb2 /61pBbxoGM875gth7gO6zRoStUNbaQNYp8Ze1ZapwiqySim8dfZdHM9gtGCLGvE7 RAXWHNp7D/Oq4TrkZ3CdehEqkrmjY8KpezAks/24KSvI0SMDojQhJ3+9ErNIKO7r Gf7VFnS3HwxFp9Cobebm2L6HZdx82N0lhPxAEWK1c0pHtVbJwpemR5EQX+ff+uIT y7PsFalycqZgcmu+8Jk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHJDCCBQygAwIBAgIIIiFqlCnqUjQwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjE6MDgGA1UEAwwx U3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFBlcnNvb24gQ0EgLSBH MzAeFw0xNzA1MDkwOTMyNTlaFw0yODExMTIwMDAwMDBaMF8xCzAJBgNVBAYTAk5M MQ0wCwYDVQQKDARDSUJHMRcwFQYDVQRhDA5OVFJOTC01MDAwMDUzNTEoMCYGA1UE AwwfVVpJLXJlZ2lzdGVyIFpvcmd2ZXJsZW5lciBDQSBHMzCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBANOTYjTlxWK4W34n65zmWrFli9i13cE1lXd7oLUQ hydE7Y+zZOe2KfXPMq4pGJfa0/EELppt4Flny7GBTnc/N+E5zcHV8Rawhi8qmoHS m+LY3J6cJzKWGYKnezV8CIOD3x7DxNBV3BxkyegXF+gwgdAkFeAO/1ddVTXq0BjW QvEOkfJuQ3Vo7bsG5+YmyBBjXroHN2xLGWtdWZJIjem7OvC6kYMJkdtz/AsfLFFq C4KoKYysSZ1VD3IxSjulc878vDpAuQZRLBTUyQL+blMggFDwWZp6MUsHFUaNeWWW 0pNfS9VTfmBYdSUxEwRCewUm0EFBrKUxnSORkD18q5MhdVt7tB33zvw/SlQYpF8Q Zp/TR4uXc4EobYiRz912URkTmcD1v7cETFOHiSQyGrh9BU3ragEdzBh6CGQarLcL FhA9XOSxkN2xF8R9jBPdxIHDJBMv941XqK6wfrKn73WNAfSHo7pniPn242lmivqe lTBiSCicr68jYkHmTpSYWPoXCW6LMHM+cJKwSv86uzuFuIMjSkeVuyiiNB4nlvKW 3EqgE1gxolOxQE8aglzpENXYgGSnyl4kSp80kpiiUakDH0dYLnbhMGL8vhr07ze9 mU1H7vgpumBP/j+0idWURA9BpVNfuDZ1AenirsOuiYHcxfGpOZ/XnWndAi7YkQuN 4tR/AgMBAAGjggHYMIIB1DBVBggrBgEFBQcBAQRJMEcwRQYIKwYBBQUHMAKGOWh0 dHA6Ly9jZXJ0LnBraW92ZXJoZWlkLm5sL0RvbU9yZ2FuaXNhdGllUGVyc29vbkNB LUczLmNlcjAdBgNVHQ4EFgQUxPx31QhImBKHt/ZRE8XLrvs1g0owEgYDVR0TAQH/ BAgwBgEB/wIBADAfBgNVHSMEGDAWgBTurG1A6tUEaocsVXv1Py3a7tus4jAlBggr BgEFBQcBAwQZMBcwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjBdBgNVHSAEVjBUMAwG CmCEEAGHawECBQEwDAYKYIQQAYdrAQIFAjA2BgpghBABh2sBAgUDMCgwJgYIKwYB BQUHAgEWGmh0dHBzOi8vY3BzLnBraW92ZXJoZWlkLm5sMFAGA1UdHwRJMEcwRaBD oEGGP2h0dHA6Ly9jcmwucGtpb3ZlcmhlaWQubmwvRG9tT3JnYW5pc2F0aWVQZXJz b29uTGF0ZXN0Q1JMLUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwPwYDVR0lBDgwNgYI KwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMBgorBgEEAYI3CgMEBggrBgEF BQcDCTANBgkqhkiG9w0BAQsFAAOCAgEAZgzR8oMXotCK0GmqhCJLLUxKvXdFN55v 7fWYx1yNM3VnzPhsr0ozlGI1qzv0wEOjYWrM0rUCKRExHRpCe9Z3If/v9fXtFXbx kxvOSRfD82WUaDwUKyBOMh08Upgn0g7r8En4k4FDX0oOXBt3tQOgaZXjHLbYcjrV ykXhur3fR5lME4Mm1xK+8VQLQxFE3wkCtzvJoa/K94c1K+Dp9vpqtbWTCZUx0Ort 3dqWHdFGwivTfFf4pwkD/EWAx6HuwcidXibfCrduHPShHeK0EBTlNZiph9VnpHxu 6+fNdzIXwzuU23r3FtwAf3yOhwnCEA8oLENOJtgf0sq9QKkwW1wlXlcaILkrDj4+ RpkLfEz8N0mbGTHSQmBLrOaEhU0sAmdjxfzlzNcSXwdbJyKfHx6Ihm86gW6wPfkR GvTjc6x3U4m2vsHiS6Ox6GjTkQO83Ra+8MJNFDGfHzZ3Q0XYe1OwR56/ZvjQw5bC J9B41M/cY49udffmH1or2y/UjCVvbeqR8s3QZFWMX5IyAYAf53J5WzgQRsTTH1Sk ov+etZ1ThYIZU3z60ZDISlQ0YtSuDI6SDC97HI1PVARFtQm6meQbtyuLdxQUMDPO g6HXFo99W/cODZPf95Ekxlv7vk9jBGGMBPvx3vQuhL3AdMlgKmzJTV4oSEe6w1Za EnS7RNdtnmo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG0zCCBLugAwIBAgIUNbuSZPZgyb0J+MCzRhfcKxNB4FwwDQYJKoZIhvcNAQEL BQAwVDELMAkGA1UEBhMCQk0xGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxKjAo BgNVBAMMIVF1b1ZhZGlzIEVudGVycHJpc2UgVHJ1c3QgQ0EgMyBHMzAeFw0xNzA1 MTIwNTQ4MjNaFw0yNzA1MTAwNTQ4MjNaMG4xCzAJBgNVBAYTAkNIMR4wHAYDVQRh DBVOVFJDSC1DSEUtMTAzLjQ4OS4yMTgxGzAZBgNVBAoMEkhlYWx0aCBJbmZvIE5l dCBBRzEiMCAGA1UEAwwZSElOIEhlYWx0aCBJbmZvIE5ldCBDQSBHMjCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBAI6vtWZMlXxByjEA8SDws5Aobi/XbucU eM3obGC675b0LufqkhJYfa9RHRqjRejpwcxrTSNGWZWb6GEXLNqrCCe5aDpq4WVJ BKR0kV6jjKRKmiZCw3vNoHAM8kftMR+g9gvOA6gcVwu05NvGXhlGV5EPIx1enB9l UgyBcLM1hhHa+8DQi3FINduWKAFcr2nHfonpgX4KtR7aKkZl/rCitpVzZN9fpton XvG12Q198IuM9iiRAc/egElDHn46M0hFotB3/a0o5GHUvA+NmhsLlOfyTWWPkD4N 5EiDxG6b1x+HQja6wj6qpq0kWCrGun4JBY04axMkczlzQWxHG6rHGnar5Tb8mx7q ddK6cyl07jq5Ps4HZPMr69c2DfXZLom+pMILFmtcUcsFZuYzT/N/gc8ZX9Ty0J6I 1ld0BCXdY60Gv7dM4L5463mfugRBUw1hecigyAzTazveL6DUjKgk9bQvTzkxHudS WufbuYOSe0J+eedg1YfuFTuM0t5qoLj9AqRWQ9dGACpDB/zQ9i17H/eAs/cwaGV3 a8ND4XLIrqeVExCzntpGA1cgHZiNoSJB+VXZQcWy92iFaSvjaH2PxUCDIqEsXGCv t6lWNeP77jSAbXGZejYCVQyKPGNiAZJq2JexuoZTStRZk/51I3jkDUTSrN1jqP3u Lko9MxBNgUhBAgMBAAGjggGBMIIBfTB2BggrBgEFBQcBAQRqMGgwOgYIKwYBBQUH MAKGLmh0dHA6Ly90cnVzdC5xdW92YWRpc2dsb2JhbC5jb20vcXZlbnRjYTNnMy5j cnQwKgYIKwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3ZhZGlzZ2xvYmFsLmNvbTAd BgNVHQ4EFgQUaBHaB6dtobtArU2/Mq9wEKGLzxowEgYDVR0TAQH/BAgwBgEB/wIB ADAfBgNVHSMEGDAWgBTwFmAimDWJL4b8zdmHHA1jVW06RzBBBgNVHSAEOjA4MDYG DCsGAQQBvlgAA4YgADAmMCQGCCsGAQUFBwIBFhhodHRwOi8vd3d3Lmhpbi5jaC9k ZS9wa2kwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybC5xdW92YWRpc2dsb2Jh bC5jb20vcXZlbnRjYTNnMy5jcmwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQG CCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQsFAAOCAgEAaq4zhzMgG7qP lwUogEy9QX29RZlVWx/LCQs99RKEFmgyVUBiez63KM4fm++T2o7vNu9QgAJ30bZR 61BTQXks6XmtVuqezTmO01KARzZb39O5A+8Fx7RAKAQGIfbLtMlvXKG7qXENS7yL 0vyBk0CYxDkV96mJUFokbwY6Y3PzSCMDx2SslVR9+1Jgsv7iM2oyZmN6RMOuuHNs RVKGFd11xTsKzmYt2kJGkDLk9lrwV6/eeOp1/j5BPk45ihU4oU+8JTEdGt1d37l2 ywLFd0ZhClxoiLPRBuGDugSKZ0ztlv25rpnW0hMDoFPyJN1cTyqTebMs3IfA8hpz 4cp2e9Drik88OWf9H70FYBM4i+5vPvq9KBb1eS7Ors99i8p6T5D4tmMeDJ8H1xlf w6FW3K3KVws94bsZfeJ438ndCMKjf7tIYK28lto/jRiYG9iu0y4IuyjmsS117W46 QXNJV85iQqwfrW7/kjFxvPWQEVOGzrhPttpt1IqclyLpqwal/ZFvLmbNU8QDZfbj e4GWKJpLixvYaDZm2ElJuPEX+R1U+V2yq4fOIWp3rirlVtxPtHCDOSUKDY1ELr/Z Aks1kggV/p/yxlwnzr81GochPW0U7K7Wkg/K+T/csgnfNvFr0LZj8C9jJo6sv0is CikTAgWPbJ17Vk1DOhkQ6zsSuVj8qT8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQKc49w3zIKiovAW9Q5FKrdjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxNzI1MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAxxznx2P8VpQ98KUYtCnTJbSB6PeJV69ilPFWVkoWUAKv HPc/cU2Fw4zriIUl057yVYSVGNdb/l4nNyT2kNDjtD6p/85BjPm3d4CwUU20nYvR NDc0OZKLdQwAv+63gSy7Jz0JF2xDL8HeqOuVeQvXzzsFMWoBEXwaJgzvRqmkDdfd JWd+1fmtR2XHTnG4gjZsjOmMuWHTnPgm8Hdbhz5z2OkwmOyILaiOwW8W1BBnMnPc hSIhLWmHEqLL1CBfmOsxqFlIM6W6VjEC/gvy3ko40HAQG8R0Vul6JYnRp1MMUHOB JSyNurWKsVkP8CtguZYGaJALroRkwBH3Yo/NMjb0XOEi1+3rMox2CKjIZxI9QoBM FyZMiovVXf0rwgdI3yyxnietLYOgT1S4ZS1r8Ti90FW/MCgPQl5S89nj2kFv/uGH cTJ4m7jkzWj/AzLPgXi72kd4u9Nv14CItwLdpBeSj+92faU1fIMBVMlTiJ7jQHXA SEmvdnUNFX9Di3MeV27u9WU9xogMqmA8SV3Nqx98yP7dJr7oA9t5XkQrorfCUZtO YHMhvr1/3AlPzrEUpC0uGn9ms+WR/1D5nibRTQfXAb5sfNnoV8UikJ/7gRdNxYnS 4iQ6D+DMJeUJPWPPCc7Eky4+I9N5GVG6FkxjK7RTwCggRfnow8swZqwNqrnVqzUC AwEAAaOCAagwggGkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSVqcUc /Ey33ASMlPLBqvatLd1CYjBOBggrBgEFBQcBAwRCMEAwCAYGBACORgEEMDQGBgQA jkYBBTAqMCgWImh0dHBzOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8TAmVu MA0GCSqGSIb3DQEBCwUAA4ICAQAWIkuCO+ik04ghdU0/6hhXUiQamaebPqWhsXgd Ad52S98bMytvMj/va2UAYQ3KDbti8OLv13V4eYKamP1JiqTlxbDZ3VDovwDNzA0n sH2/scexaG5fbu8wRlDPqlp/wuso0HzgkMo/lOovSbWe8P5WwCY1C4+p3LSjgwRQ Xsuh7zJKoVlKOvd4HVhXqOfPoYVM4KwYWBBimU4WwuFqHP7cFhCH0BDgVtClcSJG O7Of0BFdJZO5rj62dbWV7Tz3f954Gz0o/5rkPC8LgepPgCiinJpnojKHEDSHjwKn HdkTheMN9xmfgZciyaq6E4iqh3PxH2vGJco064qKe4OIYz58XiW3X6aLDuywpCLs BcW+yKV70nXmW+Q8gHzoymiRpKTao4HMuYVz4kHzDV257meoCeZWibeOAYs2ScaD V9SP70JHranxmxpgIaCBBXtiY6FPU6k3TIyzDRU71Fs+3iM/G/0Bxd151qlsSSbA 9JEDvzLQwlnKcxSjyn95KvvLgmev7EQYloFW3AYBRNIEBPndshiPFzn3Ux35XzBe i3EMs+QbLwfGd/X80JQLzkYHxHzgv78Ipx4YgzR9n7w5PfyhQrr4bWni6+FIOpIq hD8kWFu8FtIMfTdTnoXCPSKaU3LMcgS2h3nphomo/Rws8CVMBuaSWj1Vqt+/mR5r W16Adg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQOSZ2s50Tgu2WiX9m10Y7XTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxNzI5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAjyVfekvL+2mFwl9jqy43Dud8SGFu5wLqeBycBYM+63hQ 9XhlLYMHtk2lyNjZjPQk6ixjtRvQITd/2cMF/A18xk2iYvNJXRy7bNlU2DC6ZRvl DObANfRce/C4f7jKV9x0TI3EJWB9epxuiJLNFgKFb3vuJU+QHS02pTX6LUnkTKng Cd1CLjiEjcomdLNAZ+Os+1g2nM1kqtwpZbUt1W0ST89jMNrsYiuWuASJeVZmtJLI bmkH9xeCYaprl3IhHP3kke4Sqrm6Tk4QVfvRbAgPF8xG5ewWnNBFkBjkjn9/8EoY 5QTpIT7NWgIStoUdYbYa39lI2ff90PMxc07tnFtC1gf1RyR2uWF7PM68SeUm4q9x AcSQHAwhYNV5es7rb0PdCZIG2m6aw7YoLPpcKeGVJmnTEPVZQMwk1S1Uqu7bm4Wr qnD2Ov2JvLbMOB2c5SCznYCac01UJoRNLMOOMce8ytbWZfo+LTle39QYSIu1iBF9 gt+hvRuq42ijA2d5SkABmHS+9mNUy6Gl1ucX6LxRSxrD8FASUs3C9dV+3Ov2Y+BV j4l+xhOulIsDzEfkjk9MzBv2XLVrPac3gbJvP3PqHNqAPhdjyEAmId/1g7gJsa/7 7flgnYYwthro/MP8+YYKr54jYR5paGawirWGgRGUW5kT1snrQ1VCzU4HWZVpWH0C AwEAAaOCAagwggGkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQoRMe3 Nx1wrZcfKDKVZTd/VObskTBOBggrBgEFBQcBAwRCMEAwCAYGBACORgEEMDQGBgQA jkYBBTAqMCgWImh0dHBzOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8TAmVu MA0GCSqGSIb3DQEBCwUAA4ICAQBmJcVG5Fqg+/b3lNuMmzZqHH/C6FMq7otR+EH4 GJT7ALBrtpSV/HRS+WPqDxNX567brILNJ2bhNb1octlGXimNOb3v6+4TreNs/URD T2ODIMT6GchiHdrquJIPkyH1kUZeAlEu1YgCzdo+9MixvoHlQBli7gNRxAzEzM1I zuAP0bG+GmAmR+em6psvFaypqYX7LciRRLvkV8p93+NhJFJVsp3q4Kt1w4KSMD4k Qi5ry3BXh2ncpkz+kYXFKkT5QOP4x/UQai1AvM3t1Cien0NW+UyA19+d3/HujAja 4aQy/y3o19Npx/np4oKvboV6XKgq3ger/iPs/UDLJtr6jM8kUub0RmkWy/2saG48 rc8dMXsxnGNZSoPSZnNyN1ex7zG2pWHppGocdgxFK1N+Fj9TvoUJcqv/NevVRgBa QgawfaFsCHEZ7TQNfe9FTWs+49558Kfoc86EJzpGTsvzqb8mYRdeA/m2ddP2RiEe 2o0BeVo3qOb82nL9QSDvrI0iCH8pQ6ZWKKlewh0Dk4jLmtlwCKEpJbeJETtid824 Zl96/MjDi4GqK/7qjWCmoX9McaljHOjDij5AK8/KxFJcKWoD1OC/KEgiCpwprfqJ mquKrv3weNvcQVxripSyPws0wc+y2+Y2qaRo4sq357ROXUXfqVG5MznUifI8Hekf 6XF12Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQGHXUFsKXJfCmQNYlMA3OPDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxNzIzMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAoSNxo6lftOMfH7pxyQHFqkpPAVi3tbnyhOxu7+MJQpMd PI8XzI4DKtBKD7NhCcP38hVBgtiiw/q29kVh3KxDCtHtVpE4YN7bD/iqDKm4rtfI DswPIpfp3tC/pFcoDI1RR7bQebNt/gi302Y/j9KXZiJf6zwJArDIKzSFK+/JfeOB JnPNWyCeHTcIo/ozV7tTYkITQyls9l8FNmoZqDI2/AzKvteHbN8970F2KvhFqvzW 3gqGdN4+WKF28lr/bgDlLzxTgRUSb0Z9wC6DWz0FSUjDRbOCvvMd969Cb2Rwq/k0 n181b6H3JPhyzyvJakr3MHbpNQmcoLmtiRuK2gdQRf7G9EMBc6vZdA9PRt32RFwh djHcjd2A1OCvyzFJHxWalfy6vVoaAUO18Wev0yDDmxwae3yM/dffqG07dEU/zbqR 9YLD14KwACFhbM8weWFnGkLonCoaNxfwwL+0F5t90H01xTM4kGYB9Je4dNmp8JGW r3kBJWdIZwGe//WRq9EMURJAHWmlbNpblU7HPxQLjFkrjgqPDffCbeuWJxVtFzr1 0TSWkYsiTLNU7U8hFYtZCf9six+nRelNwnc4WefFRLoh/Q0GbRnKPV1Ajxd7Z9TT 67roUEPF9RQTzBDDrjHuMsNnNO1bvTIcfycOX6whDk5/iKlfsQvbPDhzko+nSkEC AwEAAaOCAagwggGkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQqKbVH FFQk9TTz9wYbzufb9BiUbzBOBggrBgEFBQcBAwRCMEAwCAYGBACORgEEMDQGBgQA jkYBBTAqMCgWImh0dHBzOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8TAmVu MA0GCSqGSIb3DQEBCwUAA4ICAQBVj+1ZJybYpqSe0iYajPGwm6kxgEGOz6z0CEYF snRh43rOQxwVaKWoPs0oEfK9gXYz2a1Ocqib7YedPmww/J26pfGMlxz+zobE84rG hbG/zhPNZqWsJ405EKocTgfxqKPBUwWu06Q6Hb5O/5WGB9goU2DoKSnI6+gGU7YY Ksveg++zFP2D+Mdmb7NpY66uZJpAFw0WeZChZqYkA/4ARPeAF8T9BWDBCTiUx/mT xaIZQiddkvKVutR1ZGfq2exVR6TuqlUd+5G2m3TDXjv0gCRnaehINKMAQusm5S/O 5s08xVGtaS0EZc0NcES685ehzkZmgoUBV7BflclLbgNI+sw9pzEtuURzRzThQ3W8 uN/oUb94oYxQflRQTnqiIq21/qd6CWzWXPxY7pjS6l8i6t5uIA9Qitswgj2v7bPF mA1bkv6C2xzTWH0Z3hRniKZOUlkRsoMvLtAX+F66v+BfGW3gmWDOv7f/XxXg99yr RBfAJW5UNFnafMJb+99et/Fn+J1pRsn3+wqW7yJwTQI1V+3oRfOErn4qPZi/nwf4 JAR6Kp7rUGs7GzxyLUmZZdIgUWTA4LabUElX1l0+NxM+nQ+fP1D4UJEN2uMBSMPD gpc2TTk2Il+ZZNJM7sAG8KoLD8POEdnoCwxYS9MyrVSDsSbR2qhWJT68W6Vv6A0l Y8mlpA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwjCCBKqgAwIBAgIQPMOb/Sqs3NBD+BLR94zv0zANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE3MjEwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDGKsC2WqbdZxYIu+3aQZLqTYSWjGXmPsqji1apKmSR 37r3mWK29NK76LBVf3/QyIUiGpPqWsXRhH2QRAPvo6QGWCEfLNeLqWV+sxxtRim8 3DEGdavuRni7oD0qPF4TLtjxAIggjocGzdIihbdXIWNM8PDA4JkQYcxGA93lSfZJ 0L1ewnvAPeV82KB8GCfa2RdSDh/CCzHOEBjmDWMrOJst4NGsPT3mhRK2pnSeoArw 9SnRm4GVRaFiD6HMb2Pvamv9D0hljCnIFB8RywIz/pKwCcZL7q0D/fZp/ihR8oh0 N27500bQBKgmZ9KrbronEDKffMWGcj8P6HDBqegzDEU4w669F3lBFBeDunGQX9OW qrSP0d8MTQLpC/LRNvrBfJ1ytA3knJ57byLDATb9gSRMXx6yaj9D6q5Mi3ArjK2H AKsLZ7gMXB60+6RVWhuA2PyTmbBTCjQJsTbIS+JxVmqTwf8vgBoRkXPJAM3t8bW0 rv6NhYv8QkJh5RZxXGl7uFTAcCAvfhaUKKs5VCx27d0JVQCLZa6uPShi25fXw2jX P/4MysdBsip8X1NGJQBCDdT2E/v/x9Coi4XEzw4k0Cgy8oEv6EYme2zpMlYPPrJJ iOxrR+9MchdLVDZkJFy/GPeC+a7cl6SnYO40mDQ8aFtW3fmkcXIbSQpbzhuHVurS bwIDAQABo4IBqDCCAaQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFAE8 2F26WsHs2xXu538CuiRV1XOUME4GCCsGAQUFBwEDBEIwQDAIBgYEAI5GAQQwNAYG BACORgEFMCowKBYiaHR0cHM6Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlLxMC ZW4wDQYJKoZIhvcNAQELBQADggIBAIcYYJOt6kcwHtIadibK+eaLQCqv+golFPYl T3OG4CNL/Jb1DUYOUWvkieFfyNYZN4c/TfBQQFbciKQ1nnGDSa60nFV4mLiXmFbH oje+696nEqiiu/gMVYq2X8jjAAarorgjgwt8E1ey9M1ZECc/kfvGrvIWOJVCFRxu tdLjKl9Q27BVrJKsCkAi4jgjEvyoyW80hOL4/ZCaMQqCPA++pPwBGot3f0qABpaZ llZBEZON2vDaqPeQD/Tp+KaX7K/1dpuQ4ZQ5TDd2I/lE/3uXPMXfiUyV7kytUQYg XqtC8geYSiKP8D7RRcoK23PoyDqsnBWaKKJPbmAtdM29kCCHMXrdJzr72XHyz/oH s2qEKw7HNBZad9Fl2ApxE4FLFG2yeKGG5RNMfoAcukUfFkh+Fc+LRUDYFsrDRR89 vfwxud1qeNmKJYVh+CnYbMLT+nMGb7Dmrhw0zyOxQsACVarEHdIn+t6e4l3oXMDO 48s5fFNTNA9cXBNzM3zBKxoLwNO+3rvcobMy0DhbhfSbgyNxAKkIYILVTHySBMNI 7vp9MrIz6sTdmUnED++ZDdIVYmAROu0Tuz64/5tuETuwAaFagdg1fggHT+gEJHtF E4EwHim16Xj27rW1YJfFRQ2O0Is0IRfalb+9J2IUq/fTJH8FDU0LW5qxvrWkTYHQ BoG4PB4q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQKbFezyeL2nKL0Do9P759aTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxNzIxMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAyOK2X7Qh4xTHZcQ8uYRFK96t3wuYGlyhtatAGgP6q/xQ a7j03R+fZjGiF8C336G/SQS46w+k49RhNwVrgNRRSC59686fYYBnBeoRsbXOVEt2 zEriClySR2sCIKw5P4TauZs+iZbf3z9bQoM3cPKq7qDVsyyXlcM+wpKP1SmeliSH BphqCeCxAZGeezv7dp44yS3Rz0RZki1rtQO9aYRYOfe+uEM59cH9dyYMO/dgReZh yg2xKhPX5rQNr555AMmuKICQaWFFB9/uByzdLZfEGl8/kMDYOWjv6wEwaSljRtVV xM25H8fK/Q0YDvXiyp4CiHYyaMucfxhaWhPG5M0T8tCd1gaEGLYROH5RMaFO9yTn QkDXupLeey1bWY4/APaAhSbWcJ0DhX+qN5njUX/yP1BVV8QiRB6EsalkOilYiyMT 7UK9pAg2RP8QO9dkoEVlnErf4cY1ZPovfvjU7rbXxaay2xvHf0/V3Y9HuWzzv+4U ZNx5Flz/rwZJXpUMFPr/sU5NFVWMk15rQcdV28gNJfalYw+8Jvx6hv0RVw9MpSpV 2bXLSL2oy1W4vGEUZ2fxj6t3zEDQ94yfO553J7RBrpk4LRrorWZ+dIzpLsyClEn4 upwNokMih9GeLdHOixhPFFkEMRtKZ2NTzjeiDIplmVwypRX4W25Xje0G21GOBT0C AwEAAaOCAagwggGkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTkG+2q QRueVn3kXZ8RV3asKZSJNjBOBggrBgEFBQcBAwRCMEAwCAYGBACORgEEMDQGBgQA jkYBBTAqMCgWImh0dHBzOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8TAmVu MA0GCSqGSIb3DQEBCwUAA4ICAQAD4K9ia0MJ+1rsN3SKprwOZaKZkYtRArM0Ql3b Ynpy4FFFi7trsFhTuD7AYt91SZNNK8ENf2Mt3OUBbarOCEOU0QmgVcpfRsiL9Gp5 eU0AKVPOH+sUJ5i1Isjy93W4aViyfuN1HuAnGz8Ab+mg0Hyj5tIx2Q8ATA6vtr03 ka8qhQUX0Pi7SsafFAlwQzkhyGzG7/uj/T2gH4VKYjm27J5tDgjTeO6PF0dzia9E Vd2pLMVyAwkkkyCbs2rOQvEN7AdO8Iq98oN7r0uZSHaOPd8QQ7KBpbIz5fdPpRyR O5qZjjsS5PzefpWvcGo/pXzd9LpNn9VF4Urx0Lju3QuzOmI0aFleWEY10UWOqgm8 tubYTevJ/CeR70Yk4V17duyfrp6NzGS1k6UXQYNcz+XAdU3dLCT1n6Tx0WdACK8p ir26wEUOsPtkJIJCD0hl0olHrh69jO4VgbrctvI/9XgjvmRfMAeslD+8xSWD6ux7 uU977Nl5G0twiplcJX6Ej23ZnekCt8y2ZHZXLBdTYKxk/EXU9r5DNL9QOCvG967T D/IgAiS4m3NxYSJljTg90StTLpcMssgfWSAcIAY27G/mkDUJjI8iTCmwvDj8vQQ5 5eF/aPJPVFOGYWBGtB+MyJAhUDMIKyNvhSxWf+NqinfdyZbbUi+sE96HEkjq9L9W kOktBg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQbc2CUY8y8/vQDMjRliimKDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxNzMwMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAiuhLdvmwa9/nEv0aiwFCdzRcYtH3MUrdmDewzWXtlty6 dvjUROQmVOdH1c+wWhA0tlek2I2CNl/krVNw9xYghN65sigIT5ddsTbvfV5xwyHg SIr/eZ8EvwB/MZj6jHFzfcSrFuvy3izwaXf62MrUv+OudwBJIiHjlCuLd5C6AX0e ETWFGRR2wiLjHHYeGlxZzPQ/BATioEyMSmmwKIjQpUCGrcmQaWJvESqwFwnIKJwH Lr2holp57+wEiwyBJ3Lmbm6KWRLGkFRooHtyxk06eZqHErWsa9pvZtokyUJCEHXH YFWvyOCX8aJgw+iwJOSUPDYfS17DQSzxDruddubc79NmPEMq4PIngYKlzF0U4mJj cnUzzXwVBZP0Qva2DxxkfDR+SPc63UmXmON5ISj/XYuHQ4l9pWJgf4eO7UYRXUB5 nxM6v9oXd/H8UDYYj9Xg7eI2Ps1gBCK88Wno1py+Fc025Jk0U0R1y2zNyagJeY0f oofQPsTBKxLWzMHJUpb1iLgdmhxaAWSuFT1TV+XcPjIXfhuilVtvEP6+s7gwyfLZ KTeDRX3hYNBN8p5i0eJW8qeUyO9JYN0O0GwVXHQgltqX0tqi+m+2Y6Yz9RFwCgs/ 3hyPouxbCgYgghM1ncEjMDZsnMBHpZptdXTGUDFB9PYWCZD56mkfRm1E6FHoD8kC AwEAAaOCAagwggGkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQGiOvW 6MxbAR4glj+E1tTsPDf3kTBOBggrBgEFBQcBAwRCMEAwCAYGBACORgEEMDQGBgQA jkYBBTAqMCgWImh0dHBzOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8TAmVu MA0GCSqGSIb3DQEBCwUAA4ICAQAoIuoRv5KJ2KFONuy+pibaV3w86ZnbNOkOnnCB 16stVSnLxOeJisetwB+thWmCFg5E6PW20TXSLBV5NI3E5Hw+31XEnFdq7IhS58vp OUZWLhTkPQpV/7PL/cxy67kLhym98wgozr+ptSCaNW7WY0+hyaovbqbr6YusWBoj nSMvlKRI+ES5mPjke7fSmyEE9+BQH7++WBtHUe5Db04sPHuDH87Fu/LbbFJt3i+a 7Jbl+Nk9rmWxKneGGYzjy/Vdny5nq7NAPjmnYIstyOT1lIk2fOyUSHHnzs0HzLPV /t5Fu8IIxth5kv2opd4MMTKPiALxnIEXYVpVf5/K8r8QNrzxH7W/g7/uteuIdrp+ HwaLguMDQS6Euq3eQDo76cU5JB2oIRAbxErNPHFzG0K2r4/JOfB1Mn12FNiUZrZl S1PT8SKlOKXmViyAcobqHAStjIuUlM0Qy/KjgC0plmbEtc4PthLXI0g4VFNTNiBu 9WgOvYM03y2cCRh1Bb13ep2jwEBEH9vX+bXLlQI3e75zPYGmbSPAkr3BrByZtQdT fQPpzdz6rejwOxL5wTaaRvEOXWsYFYVVZ7lL7sYdtUcakBagF7qSba9Lkn85MwnM VT+m2rGDfJ3yVFBkxnqbx5EIrZEz+vsnPu0+9DVwcjLbkTsUzBL0jBwE4JRfYtJq tzm9jg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQWdXPfohSKfZvzo1vv+16ADANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxNzI3MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAqUC1IgyS3LEv1UvOdc5RBkd3eo7IxK+hQ0dEvEaYn+rS Vll8dqoC7Mbkvz4MsRTm8JgNXWnAM/10VJf33M5tIrFoUPdslqPE+iiUPsdN0XSZ OqIwICBBg6NNW+ynE6Kp7Ulvp17UftwJeQL8O9QaBU2aiOTknIYFmyhS2tAB/eL5 jhCkK0koMA3wcOHp1Y4Qd9X2hoEzOFau5oEpOA50ovvWDfB4NpQSEiDPy0ifRaRY A7FfC2pL8oYFDmQWKriLXNF8x7DRHKJt/wVVuEx6FoSJIYGN/aIkE1yLHf57O8q2 6+GV6X+Pp906XWDyZ52EydHnXmJ+et72/t6kdPT//3xwxsgRiWWugMqNflyDSA9S zDOnfvXjp/xLPbhWC1B/wWBGMViKHMah7qsHZpJJrZYA/4pkwtqJS7pJRI49udJF XZJLMkppcQQCMO5bteNitPH1DoeNCLDnBa9lajuaEWL/A0rh77Y+tTJ7NNUQMyNs OYmhZmRbYsrl/A+3X7yZJ+O3hfm/sMzfkts902oWlEtqslj6WzKF/UxbPU1tq8Ze EwpgCy6m4rM9M7wKkboveT69efEMgVlwiiDfcTgToaTUq0/nd0Fp6Lvq8ZQ3+cQm QXgaMkrB15vz/xCqGOq+Dh+WrQJLosXbIadD6+Noi2fPTl593r7u4qTipikpRuEC AwEAAaOCAagwggGkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRF9whg WkZ6QYsoyAU27EIuGQkMhTBOBggrBgEFBQcBAwRCMEAwCAYGBACORgEEMDQGBgQA jkYBBTAqMCgWImh0dHBzOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8TAmVu MA0GCSqGSIb3DQEBCwUAA4ICAQBaKxErkBjewWslgD0iJiNYkrvWXy+jgo4aJkAp fi80Hu+tPwjlJib1YUbKQ+IWfzcwkGb6tEK0KkzSA2DyKfeimXWBPod1jxeLd2ZQ pfaABODlULDKc5j/0nfNDip9VXsQ6U+MmprTH0jfZqTH3mw7l3HeMYVheaM1apOK s+X77z+Y3Cw45PzG3ivhRvwDDKycbPx1xiZLbA7Sbh6HP9rp2m3cu3Cl3y7fehKZ S5XG2FclfJISvNAcSWPa5eTnO0EuZ4gIfCnMSQcjsVN5YsUHZCyDDeTPnwcq9roY zh47fksXgYNWBkdM6I5ZUyAKHSZ6s6a87vYpriZQpZZYLHf4gpJd3KQk0U/gMu32 6N5IQZTQGcdiyNpDWbvJ/j42TibLeSDw4Cf4sVYrhC3HNeA/6iBrpHyt23Vo8EPl ko0jowi4hDa8KPmf3ZbW1xpJx4q+sO8squ3cHn8YJdi6UB5xcLHDQfGq7GX6ggsZ /IQYun5cMPDcjoYFglRlDqup7qtkg61a9dA3oX4wTxXoOOsM9KzWiIXHHOSAcBu6 Fth+eUxhlH2Y0+Nq5WLRKMpuis+vcGuXLKJKIAyQhaVuntT5u6IiDJq0pw4sGfVX 28eWh7fecQ2CxOQab+BrVrZIjBK5IJpUdsrdQiZtw8y3vm0SDYzZhLoNKzIskDCO Nk9tOA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQHbY6J4nSm228Isifiui/iTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxNzI2MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAlvksvFHQfD3YJ0k4yFhO9IAPk2RQpIUBIdVZG4A/cq7b 97Fg9e8yftBP0Hcmgae8tMzCc65IPv7JfoNvxdZjxQclkREG38AFpbfOMrhuuFby OHLfNOM4vyVrJgqRUfcDzGxji620ufpyfK40Nb+mT/mgSNY2O0/Quh4CKkNmIUBg MCMfdbnnuoLcdEK5PT9Z1ZBxIQ40tB6WFciv9pARtS99Tb1u6Tp9UGRfc7j/et2J yWoeOzXSsuO1hMrWDQxvIAHs6iRRs3KVrr4CUpbcB8ZsE8ixRPUn/kAFrZte8CnL tHD4ESf4dW7EQ8ci8m1Pic7KKL7jiLTSxo6kBWiFyvYmqLX433BvI2OTtPKXHvUo Tjp3VQ3c305NygAmamkkGhSTYE5LqJyXBeRHMSWv4LKF1Nzl+sxalUNwcB+tVwyO t9E1UVBKox9HBlOqTNzYXuFO0SYHM6+JLJ9UNX7Txbh+Qnnng4Ker2a1qk+1sjQ5 Jrpk/BAQGfOWd2CWIXYzRFBQkdyL1UiUwquWcBAKo2W3uYr0elfyZrdVy9fOOkU5 MgxHe8l1NCIE/WSH0FmVt5oWoojk6A5kaTJrXXnuwy0NBg3TaRUB4FW7ass958YA QgNy8uF9T+mfkCtF2Ql0PEOKXGqICohIRqV9pu6bZi7JT/hTuQC1kkybkakrojcC AwEAAaOCAagwggGkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTZFlmU KUTMQn00Cp2koNppEwantzBOBggrBgEFBQcBAwRCMEAwCAYGBACORgEEMDQGBgQA jkYBBTAqMCgWImh0dHBzOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8TAmVu MA0GCSqGSIb3DQEBCwUAA4ICAQBKnwc5bGF6Axi4lpgysu44h3IHlzhlax+AuPkW bs2TXHv+zyzWHrimwU4R6n4WPIDdFnclFVlUHmYpBOoj6QfZ/XS3MenWUpZ7pSsa cccfv6wrs79xJFLhAp+f2+xjL01k1ww1t2idu7yhdCuVyUKwp8hL3TqtgR0OCYEj 5sQRTW13748+i76hGMDZX4SQEv+N+PTeja+ZJdBGpA8tIfu29KRYaq8gKd0Dp26A lkaz9pmPUy9n7JonYBjn1XSYOfTdua+AGvQj8POacCFBfUPsCFaO0RZvs5reFpsl Jiqy2K4uNUYl4kkw9AX8HM9tkz4LblY5+LJlg9UdqF2HdjLOrWPOG9j+c31qi0A/ Q0OOlxCSjcYsYYcaMPxEhCOGJeDeijMfnAaptB4SB+WjMR9rVp9fxa/erxSyJk1r yGvTiQcs28ZtCDwJwJX8AY5QdDHR0lsq7fo6e1DQdlDMf043pkLPhTFd9ARWZ9jv beEvE0K+eO4X5mfhRxYEy3LOoILdI4UWxE3LbYOGtoKZxIBgHEEkpXc2i7GzMzvA aP2rPC+vzFzhPwOu+PCy2H3azEZPbNnpS+nfH2z4B3cpo1NCRvT5o+0NI2UZCzmP dUZkc6JF2wxe3PmfupOu6zUkHNClRXczPFUaTbpYVVFqXgkE9+O5bT9umKu9YO1G qMrWhQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQNeR/PYxJ81eC5JqFp0bz9zANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxNzI4MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA27L7orAnythfJ/oxpEbAg515JiqUFw8vTHKWxVjEm86W oy5BlbVGOdXy1O996qlChTqqKELXzV4x0+2ZT0ITmCghGn39CLMfm16JjfhzjzUo I4E/aZcXusj9r0O4tlS8aXu2IyivbXNysJsk7KIGzYriEIeNuRU41HhQGphBdsC+ Jem57xvib91M57jRw65TNO/AOF+QgHjQCXgoqBMCaqzwkjoE3uHTj54Y4Zq6ZfBP fNBLsBkiAahQLXTjQXH9GhsKRZ/FQz1mj2ZZ08IvWXgJ3mSilC6krUGCmwIjzYYF tgiMI7oKklqP5bD4PXZqyrVkE/PkWiVuCDr/5b1JbaFATkwK4N7E0BwEKYHOa/bQ KXcd+wj0YxlURzJyu0C36P9pP0onEtSOPq1aMFQqApLTSj1U4t8TEpx9cyYbvvdB 3I7bsAW2rVnAC61gl2x/RdhVSeyKgfW1GOpDRKrc9xqQE+i+EDZQHwTIuEcBPj01 KF+Q75pCljN0mnRDMLOzsx6OLLHoclpcTKZa/AKOdYCgwUbgE4tJSgU0FKY+4o9O rt+XTpuPNZUZmfsHOoUzrpUOhyORMB1ZBUUk/w3I2AwD/65DtoilAp2uBhZ5EwPz iK/I10UFJBnr42vd9fizoektSCOAljt9qDwbhdHXbZ8yFo1B0ZFU7Poxt25tKbMC AwEAAaOCAagwggGkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTKn5KU wxV1UUp88AYWhqKdGATBpjBOBggrBgEFBQcBAwRCMEAwCAYGBACORgEEMDQGBgQA jkYBBTAqMCgWImh0dHBzOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8TAmVu MA0GCSqGSIb3DQEBCwUAA4ICAQBlv2HG50tiHZdR4d2Phc8NUsLlw0apDH/d6uGY vHUKPa1RTowp3YzlFYD4iPIjnZTNfmRKfGtKN0Nk8t2yHcEt9NvRsXelppr/cxw1 2jcbv79th2ZreO2EDToHBpOBaCL3Po32T0ECKj+rNi8TlIVHV6G6kL8HjXqxhRL1 owBfaKwll5dalq1qfCLJUQamxWNS3jpx0u/erZRbeITYF/pPe81OnJfx0nDJqKnI BnvhagIG2wvzijS4BtqeX2r3Ynbxh3Hopn+Kej6oumwklyM4f3d8eqf2koORWgnH /o0dgeG9SCWYcTikaSt3dLNdi0vn8sENNHPnZacgXqN6A+AQWUwjSlawBNwoLEBH lfK+PbUlAeljfGAGjdT7E1t3/QhT+klpFDw1FrBwOMNV7oqyW6D1Nrwy5PZaXajP fGpOQkUXYjoJktCCKnvn2T71j8eneT+OIgPmYSQWBTtIgoQ8EuUubW7WtIivrJyo 3B7ANundbtnZywXTZdUe5hQNMxN5/EqYl6t4PpsYIq9nvkX3GXGdp/v5me54P1IG JPCgEBMhhG9r1+2uhAwTcx+c9fngO6D8L6duYImxZoEg2GqdHH8Lua3+8LYL90x4 Mlg04HaUUbE2qCrRpHv6Zw0C6GmoQg6KWeWF0YWO88wu+WA1NNQM18xlVdCmbcXt 90zH6g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQZN3AIQZueU8uSJhVj20XWzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxNzI0MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAqX3RiYC/su9hJNanJWn7nLvN26rK6eorNcKQaAuAmhk6 enGxzb6mn7i+k19ZcorpgOk0Qfm4p63FY2b/0CpLPAlApucDc6eUfMrJ89xzNUn3 WvoQ4+2oo4BqEiAE8QX6Aq4vskC44/dNMatJJlWo6SXh+W01m9c95w0X7AfFeDkq 5W0zUTKD02xQ54FD3ZF0DXZLZfmuVa4ro0nfXsCpQtwxkQTE6P9FElTJEcgDAzS/ AppULoaVRr4LCNgwCBtbhoX2og93okVP1kPWK2XWIsbNgtxmYji3cxZ37KP+ou+A umzmB+bIID2zZmxrIG82YFWHcha7h6IT+p5O/U7MFRv5qHSx3w1Pylu8ZLY6htBo e6nL7vgUKYWrFraDXj1qGHhRHRa6jWeH7O/Z28Y2L7QCed2keKcNZtGNJZ/u2dKK k5tSgC88fbw5twqJN4BuanCIkqZasIdv/y1G9+csV7Ikg4Izi2vSprLsL2FwTew9 HNN3qdvv1W+SWtSED5w8XIbXcnqUBewzC/h3DtGjvNE50RCvyLXC7aRUpfaPwfQO Ua4XA14e0Vuccwmz5/x+CA8hq2J/m0FINr3xyQKewXCw5StHLyYMXLzPv48FgQ68 cxos0Y+JsDny5MFYx/9LfNV6F8BkH0x1BN7HhxHxA5ku5i0A5XOjLZY6UZCycokC AwEAAaOCAagwggGkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQ7UjKn iZbydmMRHZFyHbAwHGj/5TBOBggrBgEFBQcBAwRCMEAwCAYGBACORgEEMDQGBgQA jkYBBTAqMCgWImh0dHBzOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8TAmVu MA0GCSqGSIb3DQEBCwUAA4ICAQA1v3w26vqUZWS2q5MSmYs8vzvdTOpGNU8xiAsE K+o7qm0CocutRgEDhuI01/vXornU0/lOV26eqeKdtz+sL5/b5RNlFL3ydfZBJpbv ZnXpLS6uzWyvHltZJCKhEf9o9ZlykOZhsXDHSL6DNKgCspwb1tLlw+m2xsncab6m HV996N27xTQTENbkixFhRDgXbRJeNRGvbOMf7nvPx8iKqaMf7ufkpu7dXzmtokhE IcN/e0Jl3PJWsu7/uNw8bYoEJm7j9QHJchuNHPedAe4Vv1VGpN22TFKp7D6sHmvL fRcaDKCYIAm40ob3AXlZJZcUir7bEDFYW7MmMM3uONZeo5PVBiqLC+ae+04zZySL oIGW0NA1g6Gf8Cwh7Rf0WXjEKZ2b3TWyl3mxArf1/5VH/jFS/oqDRchFLJiPdSiM 3U4Aq25zOVfZOtxYiB7uEGOcQC4v1umXRZ86ikf1KEidwNBkw7ooTXpXbzgDIoqL GaFqGw/2UMF5KGWGf4iGRVxIVbT9W3L2cAm+zCnB+hRi4esWSXiXfhO7B1zcQt/w 7jYYPuqcbtdjb3gzB9RmwEsg4hkPBYxRikg7mBF4jhhZ6bJvPW8zEktAFsQnKMKw Ae/Ar9yVxguIHKbFm5xwOFVg9xy1W/v7EKZS8B8YzW5EXgaVrHO/lE8IwjsCzvp0 V8HiMg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQFkV8MWb/GCVSTM0hAqj/ATANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxNzIyMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAqNNXhsg2winZykBEM5/lDH+Nr45GHEzWkiE5jLewHWgP NEQGcg7NejX4cFZ1aeVKsYc10EgJq3X9iUIw7YcglITlki9t6KpbxaWBAHhoHqGm OwA/2IirTYOEy21YJtL+ASvTD4nJn9hHWlLdl+CfK/raocjcqq9JW/wx91hbfFck uAY1cOgwbDVFVVhB+9wzBEnY+5bd2Rntbr+6HWUVbcu7Tilm4w29lFUaICkgwiTW UE3NWRLH+TfWp+SwjXFbji/Yk2RqTq7Ec2Am51NilNmZlDtIJYKzLHLlklUjW2bP qEUHC0B6PxjPXxZBS6uIIAxCmQzykRCA0Z/MWnfh3esU9IIU5I8eDUrT+TKobpTR t7H/UVvx68TCs9jFfGq5Ch3EyIHNl6ApYcHP77Tp2rym8bMjUnXpZfMXQ5h3emG3 eND10Ppf5rvoXBmgFS6/jyGiD1SS0WniO4U8XBoBwJYIScGhfTJEU90e3/lqoWu8 /o11LKZOuwQzIbMM405F9l2Hy4SUBEYBhjajxglJiLPyGhXaKMht4z2vk7CVwPuQ gJ7o9LxN+CC1cyBJzI92+BtePeKje+Fjv2mX5l8X1MN4LYODYMX+qTL7NaDLDEQt W7LeKpbzuOuwbsemcChd0hfJ+SBHC4+0YjHU18cnNui+pldE93h4WFmspJuWS70C AwEAAaOCAagwggGkMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQ/K/7L 9rbPG9V/bj4WQhb+jIGRazBOBggrBgEFBQcBAwRCMEAwCAYGBACORgEEMDQGBgQA jkYBBTAqMCgWImh0dHBzOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1bS5iZS8TAmVu MA0GCSqGSIb3DQEBCwUAA4ICAQBA0Q7/jw3ltYitmfo2w78P08h0w4teJhO8J40H sM/kS6GLOebiIPBfKWz6z3/kwTBrXA2mkJAIYQhOhxkZmBUd96IjmA740k7LQCwD 2pmmhJeKttXmk0vzG5wgAB84801sqCqajOkN323B1iLC+Sl3gicROMGFENtbb65q OrWBdDF0/HEGR4nzngvHIvfdLsdUqeluoyZwHhTWa4ecUFvQGiVvWWfX/GqybknQ mJNGVo7fXbyVUSTEBzLqftKam0pn2RZ3OPIzo2ne6TY4JaIDiyXHnUUfJGMctdoO ZGsxIvvds17vTf1Gq3tyav+ApPhAbee7vr0wYabpKUkbmerLnf7La++O0/tJmh4O PNaP3P4Xc/5XbVdEego1JpvPw903GBzLJlUG7A0FN2qD+tz3VCthF/58oU/Kxpux RlGfJlBMRfBCv3HEubfNIy74HjN8o3PXR9z43P3kfzZkOLYKySfA7tVQfizyo0+d O3+H+oSpY6JPYbyZ1fvPdxlgV5RM2pHHebKRD2CrrjJnoW2XLxCsdmQDmhBq2fD0 lIRAc9YYzn3+r96vQg2vSY51VhQejaiTZgCJ/h3JOIUCWr+tY9k0IsfkZyeVznfh qYAxE6m7JXkFFfic6yXGvGqkVmQukV2eBSRN7kZqLrWDrYsnFo+7qNl6p0zldOfl lJ1kqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwjCCBKqgAwIBAgIQOzyS79nOF2k3+jcPNIaCITANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzA1 MTIxMDAwMDBaFw0yODA3MjgxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE3MjIwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCxbLB6dAAzLvbZUZUaJSAgAXdoOSzc3bcxdbnUScjF RCJPWjs7LOKmMd7XmEs9y8yNNxSxH5yqh+gFU9TVYcd0/q1UPqeVWzWAS65vFA/f 7e4Alum/yFEm6ciXPOHtn+xGPkfI+eUS8oJ95ya4UPcsGYTUrD/VkhWMw4xWzeSP 3iVC9+Ae26xIdfAB6eYqDfYEsvVKXBnJQ5YuUw5ebzZoqO8c0pim7EirPayRudE/ MR0QYoB2DWK9fbB9+MosbAqXPKZTHE10+86mXf91KMr14hdcvPyHzVIsa07i+0Jf gKFFN6JkJwOQGMuuT+DeLTROaiejWO0k5FO+E8cnAdfo2FeXz0H27K3+lt2asWVm 3lxnUQIgo0a+jElHGJOe7Zrl4QCvLJuC9sBkZnAxyl0NXu+OtKpsiTHROz7Md7rG XMpdvl/3ixzPZpVNsr0OgeINDFmgq3CpcQl0Zoea/JcI7/orAD8xhiuPDLmAEKiY wT31QprVJkQ7ne2K5k+JWqTkC+9pTvhZp/4N1XYZsYp7Nc2tMyNrTubFms+Hp3mf ZgLc1vER7NvDwhEPDUvHyC6Iyu6Pbe7Jpsirn0tAM+ZEjxk4+T91soEnGpCjEQ8V RS7HlnAhw61p8n/H+HHIgiOHOp5TTuqRQfYtz5bgZKWPa6YtmGnJYlO52FGd7mDT jQIDAQABo4IBqDCCAaQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFPvj d03TRCPoJkPi+SD+Th4FuLU1ME4GCCsGAQUFBwEDBEIwQDAIBgYEAI5GAQQwNAYG BACORgEFMCowKBYiaHR0cHM6Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlLxMC ZW4wDQYJKoZIhvcNAQELBQADggIBAGW4jfHxD4JtAF8x8cD6/ISEWb9sLsGn+PxY nk2JnJm+6fswR86aGcsZsNo/SuuPBu8PJETRVbY9xrrGsaz1misQ/vtQ71cSUK1p PIhxzchPXR1kT8/T/9+qrHt71pAoQayrC2qUULxsGkH3+bWjL11Fw8aGea3br+SY dJCO/386CqrvNMz8OaKPZrom1BOS7by5k9ZCEkAXSKv7bmgEzDhjY9MWWJpaz8w0 IOB4q9r+zC4pz9sNKPfFWy92u6ZrCSiFhx18dwPyHfwkm4O63Mz6SM+vpy/Ti1RJ qVMK9umIVgf7jTavaqJWsQ+FlD7vztYzATn68a5Yhwffr8suhDft3wTOCOZUgBff 7VX2/DL0bnKCGl+tOLdm4Vm+Lp89ZEMbm81WdRfy40s+2iNdq4alKNSuSXbMdikK obEIoJh81LSs0pyC7RzLzcFEzwQHn5++ajIW526m3ufAGcediPCQPn0UThmYkPjL tuTTmB2Dbt41dmGNRLEXnx24cQvyNEK4/qZE3hX5ybhF6SajLVd0zIgD2vbSVyQE JnOIS9l/yrd/UI6JGzsfLhdHmDg+Z1c8Fr50l5eOv0CwYHAp45UGyNUfCLtQ8LMq DK42oFvJ7w32JA0EAAkwzKI3AHdAtA/ysEX1rHCK8oEP6OtaqFLpJxqvz86WtDXp Hy5J8nuS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtTCCA52gAwIBAgIRAOIaIRqokeLTVFn/020nxCYwDQYJKoZIhvcNAQELBQAw fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xNzA1MTgwNzQ2MTRa Fw0yNzA1MTgwNzQ2MTRaMEQxCzAJBgNVBAYTAkNOMRowGAYDVQQKDBFXb1NpZ24g Q0EgTGltaXRlZDEZMBcGA1UEAwwQV29TaWduIERWIFNTTCBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAMhQeIUezKdIBlpnoWm0+HG5nu8859lksQEG OIeNiayAqhlxG5b4+wVEJ8DmCP77qDOoKVjW5owTIvZHc4F2MEqTOt6/XL3+P6an bKdPN5/nhKghN+45ywgFYn1AcI5kYdPFQmNfNYGC3jaHISHttC2xz8NQHyHRI3sy g3hkPdyNeLC+4rTOLs5SYZT+vHr3biOipBO5n68A0Ho86RQ6d0RmBRArAJskD+U/ Qco3F2pl7T0CDOuCXZ/ld3Ga7Bvb1G/lAbM/cEr6endnaLaHmI+6gYWRZVqOELVi T9dkYnpspHxtcgsVUl1lFf3GSfWAX/Jvnd3IstCa9E3dmAWm8IUCAwEAAaOCAWYw ggFiMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFMqbjS5EUEKK2QJlMhqe gPOIBCq1MB8GA1UdIwQYMBaAFAh2zcsH/yT2xc3tu5C84oQ3RnX3MA4GA1UdDwEB /wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwNQYDVR0fBC4w LDAqoCigJoYkaHR0cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwvY3RuY2EuY3JsMGsG CCsGAQUFBwEBBF8wXTAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2Vy dHVtLmNvbTAxBggrBgEFBQcwAoYlaHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBs L2N0bmNhLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0 cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQAAn17fM+SE dRJdtuP6BtLY4kfJu/xPVpFlTpl1Wq2GlzSOBWEIvqsrvSz141D5mmPZ1hqMIdbn 4uq0sC48tAD3Mi18RLbfitm3o0tjYxsbI27tltVMbvyld/k3JOyj0wVljju9fDHc yIK6akmE/C6UDLtqvRAx0m7xc5z+YIJRabXi33x4AmV7HTyVs6Lm6AGb+KqaJzDd X9Qqj24EuP/noicvKYP9g9Uf6aGPB5TWliIoEpJWz6qD/PophMB4nuj3ccO0LMJ+ k5QFRWs2hZmev1M8hpqBoMwpoG/jy5AOwntqRqRsSkbR+6tZ3aCWKU1hNnkZcfHJ 11ozB0OSfC7K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEiTCCA3GgAwIBAgIQC3+VkOWE0G8LcWoF7Z/i/DANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE3MDUyMzEyMDQwN1oXDTI3MDUyMzEyMDQwN1owSDEL MAkGA1UEBhMCQ04xGjAYBgNVBAoTEVdvU2lnbiBDQSBMaW1pdGVkMR0wGwYDVQQD ExRXb1NpZ24gRVYgU1NMIFBybyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBANmDz1NN4EL1KzW0T6fOkR7IQSXAc28dqEHAJs67wM5LnI71rGWHJ4dY FvDW4RaQMwNq5Q7r6s6TIM+iH+dTPs6qFiEO8HqbrgVD0zHBfqtzhNUt2OTnNfe4 npAH6U1zX+Oi6736U0CLawu6mz5BUGcH+0FoOe4suB9DTB/tZpmjPkg+2Cr7pmTG dBVhd4jG0a+kM79wykUvr08IOWBB25nUGc/12fLM7B3oItKZ3vaPuEnlGvA0Kp2u W+NcayG6wmJDA4FXQdWBnStKXJFvJsXu22mGKcLsxWYNTZcsa2Z/rOSRdVb1SJ3G wWqWcHDNmil9ySZohNXpAov0IFutpJ8CAwEAAaOCAUkwggFFMB0GA1UdDgQWBBSu D77DDWUUIl3SUSi2oAyMWfTjGzAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALv Y2QrwzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF BwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUF BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6 aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVW Um9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0 cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEApREf v9/3Dv4T70+xHfRWXxF7VautSJxPNVUhr/vuvqRqQVXJs8WZ0eJWk01kiM7yfzrn BV1EMsc9E26A95X9/LzA+5xQfVD7Wh+Ww/ErE1mW5AEBu+ElYtrtyTKStTi+RUEB DzJ6q8PySaJpi6xad1LCBmribNvVK1t45lCPj2fnOVPybmWsblDR6WQmpFBuYIBi EwDHbqXbXRF/XiSeJLIU8FtqsPu+wGAefviaIoa+EAw34QF9oD5xQUznoIrZEJxC lE+nP+7K2GhtKQtSK5EdiopZy6xsERubQVabApgm1CVdrEl8IGdUlvheooz6I5/F 9xYIvypgbmpLkt8IOw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCA4qgAwIBAgIQD3n7xF3POv1XMKV6tQQxrzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE3MDUyMzEyMDUwN1oXDTI3MDUyMzEyMDUwN1owSDEL MAkGA1UEBhMCQ04xGjAYBgNVBAoTEVdvU2lnbiBDQSBMaW1pdGVkMR0wGwYDVQQD ExRXb1NpZ24gT1YgU1NMIFBybyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALaf5hv57NOAg0yG6DUHknMGzfiI1lmO7g4JaGV7pSoAjyTyAbIdG17/ 1xSCafAqZjxVG7PU35idDpL3wzj7Q4bCZd6EtmT8F5yan02NzzylHirPh4iItIsy C5SL5NbRZcnZA0i8f5aMxMpyHHtizOnUQjQiMllsC60HLV3ujnCRTkfV176vdz/1 uKyplWPDe8LC+bA8llzKj3A6tZl/Jf0X8PEgnr0rZwklWF5fPKT65j2PFzs9rxgK 8EZqwxZtN5zf5pS2zN/Jzsug5h/mHjYZFfZTVrBW1H0aFTg4o1+nEzP/IDiViiCq zIbu1nU1fFQx5mA7uOTNyzMsMXaYvjECAwEAAaOCAWIwggFeMB0GA1UdDgQWBBQm QFoFw2DncxT2XOK+bF2MV4/eZDAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALv Y2QrwzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF BwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUF BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6 aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVW Um9vdENBLmNybDBWBgNVHSAETzBNMAgGBmeBDAECAjAIBgZngQwBAgMwNwYJYIZI AYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9D UFMwDQYJKoZIhvcNAQELBQADggEBACxqK4/6E0z4jjjrVovMW8V4uQLifYr9XRMA jPTSe38WYzYYEXriQrxSZF2k2mKq7S+YqFuv6BAvLaCLlVPa1uQpBhQFL/aFB2eF YGiHX46GRp9sUkXEZNt/eRtqKwOiVj8tdBhMjTB3rmX6kD+/nZZ2C4Z8C9jtHZu4 Y2VR59TL2G85IUbsTOcUjqXEO7gQhW2CXBbJyO+2DMrFaRCWtDienWUsJzLIbI2N XdQ69dCh3zhNqn8GK8fRv9BU4LpRRBK8AGt1IUzZKJ8iAaAwU861QzAbvaY/ON2P 0qDvdnacU5gw/3St648rQZuUlQOtuUok9HIjyPlToW4KCZxME/Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFjCCA/6gAwIBAgIJMvoIN2vyPCATMA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV BAYTAk5PMR0wGwYDVQQKDBRCdXlwYXNzIEFTLTk4MzE2MzMyNzEgMB4GA1UEAwwX QnV5cGFzcyBDbGFzcyAyIFJvb3QgQ0EwHhcNMTcwNTIzMTI1NzM4WhcNMjcwNTIz MTI1NzM4WjBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwUQnV5cGFzcyBBUy05ODMx NjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSA1MIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAu5hBKP7+r8dtoZT14U1OKtTBSzI+U3nUC4p5 ht3kD/DR9hWPB6/2Kljii7Ft4AXTSxS30YGwBpqEtIHzxjfgf/fuTb/eBx5wWhxz v0RWosEhUwyQqYX0lVEqHruRV6rjlkvtNYkhdEU2kmQs6j4T66p8AbgZLZSq42k+ lEU3hGQ8NpDiKSvxX5aVorxsRel98AP0VaRVMZfeMYI5DkTcfWkTMrD+dDqGejOB S3V1+EstPV1Auf85LiUo0jbwy1ZOppVFftUczMyBwOENOrUwfjDyQnQrn4qhq+TD qAMua2/2+gX0jHZ/wwdP4mhSPjmlpNejMmzXbykDu74BJqWfBvz9fpG6C344M0Hv WZ4QLOTP5dKwMVTGF6S/QK3jJb8SdB0cDMCzsLBagC/F56+cLMntOXsv4DOvD3HG rmrEZKsjJB+0XWIVwdPif4ItQm6MJZq4rGkPymaKsaKAes7OpFflFj7ruQIuc380 l7c98uVpIuszMTak3L8CaPN6nrpmIUGAaOT1fDdfANKnb5vVosSr6W/ETkF8gFsP Ljy09wzrUKH/Gnk7EdoBNwdy5zwP8z1F99j8QUjVVQwckBO/YsgJI6MOXoHqeHS3 LVT18dZ66FJLYZTIXZQTtLDo3eQ6eL+vSNnakxMjO4nH90BQGy6l0CRPCIi0+a0A 8HaUbA8CAwEAAaOB+TCB9jAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFMmA d+BikoL1RpzzuvdMw964o605MB0GA1UdDgQWBBQnUqRvLSqrQJOQ7NZpy/58YTt8 QjAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0gBBgwFjAKBghghEIBGgECBzAIBgZngQwB AgEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybC5idXlwYXNzLm5vL2NybC9C UENsYXNzMlJvb3RDQS5jcmwwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdo dHRwOi8vb2NzcC5idXlwYXNzLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAvrrbRl50 56kq5vOKuWUcazLEHuJlVyjr1QBpLoq1dZNjpmIFLjOmG7LLMv83Hs2d5Ww0H6Sg NlloNjp9JYo5PCruL+djEb5Ct787d0dD+sQ9wkEQNK/fgQ6hqef4Z/lYxmtNqCyR xxuK8LcgvMG5D3W9CLZYIqCyGgKZqAE0FtWyinPTzCdvxzCMRZz2dYJLN+2nejMs z1+FswjSnOyva0XegBZnjhrHNI3ZyB7nPILephet0AiYyXpXUuEvBXa6qVkeK8mf 6uGgq+zTXqK52cKu2woOa9TV2/oyC1DzVNoZbfOgJ0Geh2TWeJn8rL+W4VrvxT6K w2+lk/YeyXgFd6km3FgEQk4pRnzuV3OtDErdQRW2lssR3gl9u2DF9IJYbzoRiVvy 7wTHuchTygpG8n/K9ajaWDdEL7+jSvPjU5+HBcHwgcxDSYF3QSLNIsOaBS5O1Hob 440ryhvw5lGgzqkVsToXJCaaSziOmqbzzNPHgQ0HM+vzvDTzC0Z6ikF0LGjkPSML a4qKpyJzIjLOjqPVnI51920yg/zZuN5nz1lQcH+0q7GVeoRaHE2iFyJnHXR+Ljl9 2SHWMrw1jbhk7D5/u1XmtsS0r1oeHgbF7zi7ESOVLFs2Zcm5kewkPDljznSJTE94 1YS4d5yABnRwkq6PSaKEvBRshdl84c/Fd7Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIPjCCBiagAwIBAgIIRIQedGGfUsswDQYJKoZIhvcNAQELBQAwgawxCzAJBgNV BAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQg d3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcx GzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEnMCUGA1UEAxMeR2xvYmFsIENo YW1iZXJzaWduIFJvb3QgLSAyMDA4MB4XDTE3MDUyNTE1NTE1OVoXDTM3MDUyMDE1 NTE1OVowgaUxCzAJBgNVBAYTAkVTMUMwQQYDVQQHDDpNYWRyaWQgKHNlZSBjdXJy ZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRswGQYD VQQKDBJBQyBDYW1lcmZpcm1hIFMuQS4xEjAQBgNVBAUTCUE4Mjc0MzI4NzEgMB4G A1UEAwwXR0xPQkFMIENPUlBPUkFURSBTRVJWRVIwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQC9/oTZfflU1uAvn2PW3R17P4fo4d/Pb/ypfOchdNrYgp0o nTjvKsT0wucZwkQOIiS1MTE5BWcPdpm2aeUzOfJ8unRu5v0EDybh9xrN2Tp+pxP0 6moaPagIRns06zfdkhLIV4HeL+NCr9N5lEtlNaUBpgyL3FzQEpOYkz9msqB8y3g9 +7PAcBr1EXxOxJhjcYn9oI+pIiM49m7XS9pKrHdJ0/FaTC763CLF1LlLxmGManpE CMO4VacQasEUVF7YtFAd9zNy4GHZLa2yf6cMjxfEWXWvCSx23LQzObTOWjQ0veeh NPvXv9VnXfumx9OxiC0KvWI4J4grzjWsVw6VWdGlfCCIe3JVEVSXLCub+hbwNAF2 oRbw5cVSn6f2QEoLJdaZZPCy20ksNySB9BsUfk0M+06AKCUXMcybB6YMpMrA+xmV 5i7ZmQKXEObgFt40Gh7NfoZdFgCXizIg8+/gTR9LtwUx1mjfDtl6jaNAUa7ZS4Hh h7ws6cT08mdtGCO+3lcxxz4IpWOwMq9YhFAHTWFboPqXFdDgM7tIwwZQ1TpI5lDT h7qBZRSGY+QfE9yXiSQBOzPTF2sMXTAv+cNWK/i9DcfgmTlH85dqK4U0iYTaXk2v FLx2p4zIp9Mm7USrfgtHgYVvo/5GE2MJEScry8Y7HhFRAmMykV07RsNg6J101wID AQABo4ICZzCCAmMwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWxvuA3ui2+dG wMJUq6FQKV/xVtcwgeEGA1UdIwSB2TCB1oAUuQnKnB7b02w6a67tVPFbkwY1Ll6h gbKkga8wgawxCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJy ZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYD VQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEnMCUG A1UEAxMeR2xvYmFsIENoYW1iZXJzaWduIFJvb3QgLSAyMDA4ggkAyc3T6dV9I84w fQYIKwYBBQUHAQEEcTBvMEUGCCsGAQUFBzAChjlodHRwOi8vd3d3LmNhbWVyZmly bWEuY29tL2NlcnRzL3Jvb3RfY2hhbWJlcnNpZ24tMjAwOC5jcnQwJgYIKwYBBQUH MAGGGmh0dHA6Ly9vY3NwLmNhbWVyZmlybWEuY29tMA4GA1UdDwEB/wQEAwIBBjA+ BgNVHSAENzA1MDMGBFUdIAAwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9wb2xpY3ku Y2FtZXJmaXJtYS5jb20wfgYDVR0fBHcwdTA4oDagNIYyaHR0cDovL2NybC5jYW1l cmZpcm1hLmNvbS9jaGFtYmVyc2lnbnJvb3QtMjAwOC5jcmwwOaA3oDWGM2h0dHA6 Ly9jcmwxLmNhbWVyZmlybWEuY29tL2NoYW1iZXJzaWducm9vdC0yMDA4LmNybDAN BgkqhkiG9w0BAQsFAAOCAgEAd5djb341DHmtupmToETVhwpmAw6TmHboPjpQ5FlV DFlKvjmdPhxph919a+aPgiAnGLJA89xfsIzihefLP0DdVI39SZ0bTawaIobxEzmp zK3JmQNy+ETHWnodJOaw5M8VdzKpa9ycjaZaX3lWWoweD+S6q1qZKUPfBH+MSUxc BkuYFR42Q45BOtwwR+AxN0LZTK2R5ohq89lxJ7GtS9Y929KndD++gwot6kaiMMws Glfu95BFwdpstF7wOX3fOnwjENmXt/gZjo6oTP1p7zMqKp6praE8mvm/KraxEKWH BXz3XH/Kf1LU65G/VeadUQ+eLXRTGNxnyTvHodZYSDEtkcPT3daiMSJ+5sfm92nf 653iDsfGjbMfshMWvK65ACEnZIfEXuLUlelUbEjir6iV2HUCeb1Fz86vskkbrOOp XN+X1AsNcpKDWBKeExLpI0FGia6PhM1dbgozh5AxG6N7LvIPiLml1eJLPqMsA3xL 5le46AIDV7wLUCR5aUWgNIiHeXsE2jqGpL4XCNbaALfxQh5vfrDiR5jp6NBWHe6m JRv51UXsklfUUXsejSom0YkpZ1+orlshq/UZCJ3N1X0Z22v8vIlKKYMSu+x0OxuN x/Hce43AdsgI6UTcF4p0B+7Ma2OxsOJPuPh0HOK1N/+ygBGASW+sNhyI/Lpueznm onY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIUY/4DvYu7lRKkCR7ZPF/tFMDhgdUwDQYJKoZIhvcNAQEL BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwNDA3NTBaFw0zMjA2MDMwNDA3 NTBaMHoxCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDErMCkGA1UEAxMiSG9u Z2tvbmcgUG9zdCBlLUNlcnQgU1NMIENBIDMgLSAxNzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAIagJaH0N6+HN+9jlWGSk8cajAmkcma40f97saznEfrH 1H1boG6FWDSRZ4Gc0AbPVS3PWEW1nMX9DujF5fnhRYQZeuwviJGbIlEhTYuvF7N/ TXPQN1SP+bq1eJIkn0kdhtaWOIajq5vGEHvQ6CFZEE/yEWlrKnH0FNXpRx2Yj7bN +UKOTz5XkABuSV0QYqm6UDt5kRDFE9t/ChshTABxGsEM2vpe9LvKemsuOBtw0lee 0I6MOsl0/kSN4kpoLjPeqqGHai3nUXCA+qWp+m+zwdR2OYTxl/TDBZp8wDLKhJTk /AFayjUwl1I+qTnU0WjppV5vwhc5vFBdZGM+RtrFPlkCAwEAAaOCAWUwggFhMBIG A1UdEwEB/wQIMAYBAf8CAQAwfAYIKwYBBQUHAQEEcDBuMD4GCCsGAQUFBzAChjJo dHRwOi8vd3d3MS5ob25na29uZ3Bvc3QuZ292LmhrL3Jvb3Qvcm9vdF9jYV8zLmNy dDAsBggrBgEFBQcwAYYgaHR0cDovL29jc3AxLmhvbmdrb25ncG9zdC5nb3YuaGsw OAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEWF3d3dy5ob25na29uZ3Bv c3QuZ292LmhrMA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0ei9Y5K3DT XNSguB+wAPzFYTBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMS5ob25na29u Z3Bvc3QuZ292LmhrL2NybC9Sb290Q0EzQVJMLmNybDAdBgNVHQ4EFgQUkjewcJyO eduzGRO4m6UywLfWJ2IwDQYJKoZIhvcNAQELBQADggIBAIXSFgE04Z6AcMFFUWPz e4ZuBav4xr8tbAEDDSbaPRinQ2HZFpw0aIhAG4h4WaDD0dDrNs/w8XrWQY+YngTw 6z/cta+ByVu4kGFKGRYLl9tWX8a1oWhETHcQ5uAUf+rT94gv4DWnSKDDNrT0AaGj bo//IF0UdQIBbCsZj0NQCgMouOgYC6zCUv4JO4tgwBwAVEXbFUyXH+rXtE1ZKSs1 2XOnIeA8TCvPht5FJm8RPJNSu3QHYMdvle8ZJ7/Sa0uZMvpdMHT4OfQEO0UhP3MS flYUMfUhu6MIQqjSjwjHq9LyJvg0ehunFRot/d98LtApyRecd+sjNcLDf6EGqydE RAGub5g63McG9Lhz/85dSGTNIOjrD8qQyLxchmdvq2FQcsomTVlMXtlM8NXLDmPn Qjyue8q9Q+QO8BTDMSkmFYi5ss7ZzR8d3m4INx08g9TBY3J7iYTXppkputbu+6SF bR26v3uPz89u2L9bnnLBZglcJlDO7jpcGvCy07L5dQE015xsWq8txgC2Esf82HPt wludZKyEPpkqSwtOhpUy/4pnW9Nezj+BPLrgdkmkugwQtfsV/j6LPNdY43/10kz0 OQVDufIavloNdaiv+8ATXEq1LXzSuOun4SPYmLNLqS590IGxjRuJe4DlRxeIJpEA HAiv/TLU/E8/SU/AWcwH0ZEz -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4TCCA8mgAwIBAgIUaO1J3aN5JZJXjDJRINoi6fHhC9QwDQYJKoZIhvcNAQEL BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwNDEwMjVaFw0zMjA2MDMwNDEw MjVaMH0xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEuMCwGA1UEAxMlSG9u Z2tvbmcgUG9zdCBlLUNlcnQgRVYgU1NMIENBIDMgLSAxNzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKp7LYoCH28yQ0mF1pjAbLQlH35nknzTCzHfv//y br2g+L5IKuAnGW2PJS4JsOTYTJzWg76lzBRTSBe0sj0wRIanDzbL8WxIXaGfPv6L VcnNnG+ZqvkBHyhnjdwNztKdaPKGkxX75APV5f1zrLW6OfKZ2AMUPYY4fRFPPpuE oQyOB6PspKtMI+BBRGlQr+CtFQ4Lntej1eyyUh70i5oaR8hi2dQmMY4Dg+AD4UoG bN4mW5iyfjo9zs0ywf+D2onX5kfVHHhBsAO/xD3NLynSJnJ8rCrxvmCRAoKMacQw ia40n8XgSDSkiwDwLzSvo7SGSVNd3a9MYyry+a2/3u9b3CUCAwEAAaOCAWUwggFh MBIGA1UdEwEB/wQIMAYBAf8CAQAwfAYIKwYBBQUHAQEEcDBuMD4GCCsGAQUFBzAC hjJodHRwOi8vd3d3MS5ob25na29uZ3Bvc3QuZ292LmhrL3Jvb3Qvcm9vdF9jYV8z LmNydDAsBggrBgEFBQcwAYYgaHR0cDovL29jc3AxLmhvbmdrb25ncG9zdC5nb3Yu aGswOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEWF3d3dy5ob25na29u Z3Bvc3QuZ292LmhrMA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0ei9Y5 K3DTXNSguB+wAPzFYTBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMS5ob25n a29uZ3Bvc3QuZ292LmhrL2NybC9Sb290Q0EzQVJMLmNybDAdBgNVHQ4EFgQUfzGN banFByJg+hkfhkDpB6/p4EEwDQYJKoZIhvcNAQELBQADggIBAHhcRfrSp2PLYo+5 Vf81GatkgG01g/fAU3Ndz6VZ5xD6QXWX2lRSGtKpno9YJ9ZA9GHhIfTfUHvj6NaG G/94Hcchcfk0OW+SydtDQgQTVipweXEojzcjQZYySP1cquziI+fhfnBotqnIjWK+ kQV/8ZGTpEJ/bICUMmgYmpQW1CiP62eCFlnyEz0x9pNBih4I2KwzdHRbUr96zhuk 7FXb1pdcIDYqjkp9pE+2jh63N5ZaGj8eQYK8vjV6cVinV6mvwdI4/cG92hLjnuy1 mcd+da6itN5V7Wwul4BJdQ4JOtrdvPbzcCSCMf2tT3prD2/dqPE71wpwnqrP/tbf hffR1baHcx0wFnvQyB97gslSrD8wwv4TfRDp6vQRmnikddRFPIcYpYUiIPTJxXwG 2XCEqMMLwcf1fZoMBNZexAeLnPJSs2dSze/8mlRrhMX7DscJ8iZS/+Y60Q+dm3OF 5TuLyHvy7j+iHvB2mgx2ifDKqghY1qWgv3DwuRGWYVb5BQBw9ZZTEKcdTiNN++X1 cd22JuNuhK1+tvGS4oNFBrRRawDqA8DnWUVBF1tTRRq2aW6Cvu1Qmbjp6LuhPjsa 8m2RqxQhpJHdKni+6jsRCwjVo9quvQDOWLR9N6xAv/0kHL7zTSVcowZK+r084CPI uX3C3WmSX8UXTHJRGpc3SrYaXXvZ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG2TCCBcGgAwIBAgIQNVQWJLE+V0a1YEDNhGhU2jANBgkqhkiG9w0BAQsFADCB lTELMAkGA1UEBhMCR1IxRDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBS ZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdI ZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RD QSAyMDExMB4XDTE3MDYwNjEyNDkwNloXDTI1MDYwNDEyNDkwNlowgZcxCzAJBgNV BAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFjYWRl bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MTEw LwYDVQQDEyhIQVJJQ0EgUXVhbGlmaWVkIExlZ2FsIEVudGl0aWVzIFN1YkNBIFIx MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvjOPdN8BjJTj+2dZiDW/ 0v5zblNcCyBZQnBm1PT/ejatEAaV8cKhzWCD7PHwahve6Dm75QjLtDkUXOPqmhfA rdMx5Y6ur/2y2DtxJ0KAuz/4S8VzKeWa2JjjOCe7QlMrDPsCX18YcLuoOYT6nx/q 0Xb6SPfh0A3jCLoS7SWw1V/y+2yMqPHDKdjXjbgrrx1GLzC1ddFnC1BVKJf1eUYa Ycow+4Ac9mKCUxwgrXDLUFuy+1tUANoGx4iqIl5V0Do0f3oQuYkne5FBvHftplDa 6IDRAy9YcqqR4nJoKJdmFqbQLoxrZjbFiqynPgimRV6biGRwCYZKE0bqcOiv2MLE B5il7QJaw5axalBAhf0xTAW+rJqj2FVz+mo+q8oVw3S2nMeZdNjSECFagZzHmnsM +H9ULiy+/bW1eN2gD7T1iLGHPP4DvSWZNV26Sa7lepejBlRfSpsqGHbCx67qybmT m5oUxm4mQydXoUoptBDiIp08DHqV8H6Oji4MbH7cPHfaZgTTVcw7jOhRYwqVDVrK iNGTAGgED6KMirqDcpX7cKeenXwrhn1wdSUjRnbZVm0JnB8b2QX/9y24YF30ZioB CU1001oNHmnarKlAfJ8lRqKkSp5kLboN8ZbK0IqB7j26h4lFNm/jq3w5QiOTK2yQ zkZOuaidGDFS9OqMkIpRSMkCAwEAAaOCAh8wggIbMBIGA1UdEwEB/wQIMAYBAf8C AQAwDgYDVR0PAQH/BAQDAgGGMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggrBgEFBQcD BAYKKwYBBAGCNwoDDDAdBgNVHQ4EFgQU5KXK5AFAXqwg5iqi87sxIUp8SHEwRgYD VR0fBD8wPTA7oDmgN4Y1aHR0cDovL2NybHYxLmhhcmljYS5nci9IYXJpY2FSb290 Q0EyMDExL2NybHYxLmRlci5jcmwwHwYDVR0jBBgwFoAUppFC/RNhSiOeCKQp5dgT BCPuQSUwbgYIKwYBBQUHAQEEYjBgMCEGCCsGAQUFBzABhhVodHRwOi8vb2NzcC5o YXJpY2EuZ3IwOwYIKwYBBQUHMAKGL2h0dHA6Ly93d3cuaGFyaWNhLmdyL2NlcnRz L0hhcmljYVJvb3RDQTIwMTEuY3J0MIGQBgNVHSAEgYgwgYUwgYIGBFUdIAAwejAy BggrBgEFBQcCARYmaHR0cDovL3d3dy5oYXJpY2EuZ3IvZG9jdW1lbnRzL0NQUy5w aHAwRAYIKwYBBQUHAgIwOBo2VGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRv IEdyZWVrIGxhd3MgYW5kIG91ciBDUFMuMD8GA1UdHgQ4MDahNDACggAwCocIAAAA AAAAAAAwIocgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwDQYJKoZI hvcNAQELBQADggEBAH0QKQqKXsRFVwhRHXLW2FgBK99YnsWJeLudiBm2D15AJ26O INVkUOxSRZwuKBOz/wLDjNTNicYD0lvLf75v4VcCTgH9JzE1gTLESzk5TCZjMTUS /Do8p1Zl/81L+7pfa9jI9CX39cr06L2N0eFmfn/bhv8rTGoLcmyqM0OJzZq82hux 6EMmOBEfm3CCKcp3ITdTahEZ9lN/YImGvzVwPGQemude7VZy8f0moLuFpaAGdJw3 FupEMbtuotIdFtp9m/JHnNn2ksCZKb7dzmGPJWCKRMuXqAXpHKxaexAdczwhV1Zs omlOcVdLUMXyv582PnzbwShL29A4U6qklPoFjWc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG2zCCBcOgAwIBAgIQcTzUzhFn3QgaTa7SsgUa1TANBgkqhkiG9w0BAQsFADCB lTELMAkGA1UEBhMCR1IxRDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBS ZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdI ZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RD QSAyMDExMB4XDTE3MDYwNjEzMDMzOVoXDTI1MDYwNDEzMDMzOVowgZkxCzAJBgNV BAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFjYWRl bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MTMw MQYDVQQDEypIQVJJQ0EgUXVhbGlmaWVkIE5hdHVyYWwgRW50aXRpZXMgU3ViQ0Eg UjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDbwABPipg5OXMq6Ofn uUMkd0+Ec8v3PqiO+FEYaCdCZ/e8YIHWEwT7/M5FxwA3aiWqRxTbFMabRMvQxXqx BAx62drH8BMU1Hp7w7AdX07l3gsjmi3toi1720tKIELUae1LjIuxYTgT6eIZ8X03 hwexeVbRz3luz4O3rN0QjffA2n3L8dEHnDd1lru2qXUuqfKlwIrHy4Im6x0ZN6Um vZz/xblPXIljYg0qh0TcUycBYuOGTSGfnLa8xCy/hb1emSajKnXYjSPDh39vO7bW Q9GQkDBli1mN5Sp/IyzW+5v5nYSMkrjPrERGqPNGXfBSn5yXdV12/9TFZ6lbWFtc GN2AeOcDsvLTeISuoKtVzvdu1QVMQPIE4/x8SubzmxEn4mGtepaEbkWKKz8AKqnX 0l0aDcrQlBH0wXtepMbBbbpD/ELwaZU/hYYBLu4liT5foocLUSo1pqrPVRYjIf6U Rmn2wbWC1XCnNwftzLYtYtDiPsLtQBoOqcvNEBcpTfICPhhlj1jpYQ5lDb/9Zk7R PjVJFkSH0bjqz+nXdR8Cp/wWThsdIo6EmvT7gBkdRjVhyKKWVEq0BbAR1zJNOwJX Ucb2CsIl6T83uFqJocoSu5hEZIn6tsC1Z/QUjhBGLhleAL/gPq3gIp4dR1VCevFU fxjoujXgrO3571eZm79moLUZpwIDAQABo4ICHzCCAhswEgYDVR0TAQH/BAgwBgEB /wIBADAOBgNVHQ8BAf8EBAMCAYYwKQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUF BwMEBgorBgEEAYI3CgMMMB0GA1UdDgQWBBRzdapdJSbybcDrbNL0arXScim0CjBG BgNVHR8EPzA9MDugOaA3hjVodHRwOi8vY3JsdjEuaGFyaWNhLmdyL0hhcmljYVJv b3RDQTIwMTEvY3JsdjEuZGVyLmNybDAfBgNVHSMEGDAWgBSmkUL9E2FKI54IpCnl 2BMEI+5BJTBuBggrBgEFBQcBAQRiMGAwIQYIKwYBBQUHMAGGFWh0dHA6Ly9vY3Nw LmhhcmljYS5ncjA7BggrBgEFBQcwAoYvaHR0cDovL3d3dy5oYXJpY2EuZ3IvY2Vy dHMvSGFyaWNhUm9vdENBMjAxMS5jcnQwgZAGA1UdIASBiDCBhTCBggYEVR0gADB6 MDIGCCsGAQUFBwIBFiZodHRwOi8vd3d3LmhhcmljYS5nci9kb2N1bWVudHMvQ1BT LnBocDBEBggrBgEFBQcCAjA4GjZUaGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg dG8gR3JlZWsgbGF3cyBhbmQgb3VyIENQUy4wPwYDVR0eBDgwNqE0MAKCADAKhwgA AAAAAAAAADAihyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADANBgkq hkiG9w0BAQsFAAOCAQEAd3Zvo63EybJGxlZGf2NDonU2rGl34HsFmAhSBb/l79+f 3u4Mnk58axdbOA/E0SRLbFemth7/AK905MSlsX3Zq9S+TW5rB6g7LJUnh/tQqqJ4 FrY0dwKsuppXpasbLyjYuuF87NJ5zOErkf2nIwcQYl2sewsisCHouy+y3XpDuXZL Mq7u+rv8JfeSJpTqrqhyblCwpXmq6/0g5QfAh4N8f/28f2zhZsBdsA33BfwtOiTL Yw3wFKGWO2BcnuWLttRCZrC+XUI7OaSPFEDcnxx+xVxhdThTQ88tUGwYPDgnYMze qC45lC/ZNL9HIDSRTSvVxV9zXCxmEspq8wcaNZ0IwA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEyDCCA7CgAwIBAgIRAIJ/R7U230nBEq0f/V7vYQwwDQYJKoZIhvcNAQELBQAw gYExCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMScwJQYD VQQDEx5DT01PRE8gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTcwNjEzMDAw MDAwWhcNMzIwNjEyMjM1OTU5WjCBnTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N T0RPIENBIExpbWl0ZWQxQzBBBgNVBAMTOkNPTU9ETyBTSEEtMjU2IENsaWVudCBB dXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBIDIwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCddbPnFRa2XIrVQpAFRBZt7xa7ft6/5hl+fUDc k0lLegbg/nNWDlIHqAHNb5kQuvMs6m+TKb8N0PhWE6UMFd0i4yIsnutwLyUlaE6N 3aiyniPPggzDXETueHwZV8OyfEkm2WENjmJc1nx/Wxiluo9nqgxx4/ix8bDXcPcy +y+SVjUrGdyiQtONODAr4r7niZc5EYnDZmxbq5xvxYa9ssgKMbiCl9u7PrFmbu76 4Fx6DORKftpCPeVlGrbgfurIlQ0oQIj0h2HkSnOoTABwT3gph/gq6ZnZ6jF7y6IG vDTtaAA7YQQQt6soXEBRFbsyf5PGkwdlufSPJvXgujMoooMFAgMBAAGjggEbMIIB FzAfBgNVHSMEGDAWgBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAdBgNVHQ4EFgQUOPtT yu90tuiSd9guc4CfmYhjqMMwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBEGA1UdIAQKMAgw BgYEVR0gADBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNv bS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDA0BggrBgEFBQcBAQQo MCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG 9w0BAQsFAAOCAQEAFDIKD54/ZDEckUUyIjFqLt03IHj8mU5vLR/krEBSAb5NWH9m FxXmfj52ln+wraZlSscV/2TAdKspFcW2caaDbKcZRM3QLrhb7EUmmnMie3KBs9JD koSAvfsosRXKO6Dgv6ptzwWdJxotCiEVf8idIgIXq5nUZ6c1xcMGpaS7lWCfqmWv 4g4v/PdURNW85g35XD+D5Rxmvlveil6zQMbPQ+aj9Y9Gg7WIzwUzY4Tjn8Rue4ra lBsvsYpOgbQK6tNobNS5PrKxfeTbKqFnMGAjNaAlRylz7vd5va4nZ7ORiKihPK7p +WaGDhIIBZaqeChvRatk1cY7lXSsc3nPeoJGbw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFDCCA/ygAwIBAgIQC2fJNaFyfIMAAAAAUc4XCDANBgkqhkiG9w0BAQsFADCB tDEUMBIGA1UEChMLRW50cnVzdC5uZXQxQDA+BgNVBAsMN3d3dy5lbnRydXN0Lm5l dC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNV BAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1 c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw0xNzA2MjAy MDMwNTVaFw0yODEyMjAyMTAwNTVaMIGlMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN RW50cnVzdCwgSW5jLjE5MDcGA1UECxMwd3d3LmVudHJ1c3QubmV0L0NQUyBpcyBp bmNvcnBvcmF0ZWQgYnkgcmVmZXJlbmNlMR8wHQYDVQQLExYoYykgMjAxMCBFbnRy dXN0LCBJbmMuMSIwIAYDVQQDExlFbnRydXN0IENsYXNzIDEgQ2xpZW50IENBMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqWD8gC5icJOM9hliS602WJcO Tv6djwAuP/5sgg1BhiMj1pPNg/6PQ+Hi620oGxG7AfrrgE5zXt5axao6M7GL3njS JPvRFL2UTZJfmDRZ/9iGNhx3uGFiVlj7gFUPAymEfejQs6bf9SK4JL/kA6x5LE1+ WqgSDwH4zRCTzy0cs3Rrh9u+wrFnIw7o48cQxQM4t8gFRaCL7CQV3cscOF9mmQiz 99eR3F+XB2LcQZyO0cY19lOnd65oFDWkZxM+SY1uvp8go5+odxm8OLtV02DOoP6v t9xMGZqTc+iXvgU/f3fyaaX3nV704PgOsCL7Pqg2Gm5ExI+katW2pYzcnPOwBwID AQABo4IBLTCCASkwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwME BggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAj BggrBgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5uZXQwMgYDVR0fBCswKTAn oCWgI4YhaHR0cDovL2NybC5lbnRydXN0Lm5ldC8yMDQ4Y2EuY3JsMDsGA1UdIAQ0 MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0 L3JwYTAdBgNVHQ4EFgQUR5CkoQpDIL/QdFS4lPrEe7W2HAUwHwYDVR0jBBgwFoAU VeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQELBQADggEBAAZRHzVkV7eD yEBH/+nEAkzO8JCBAD36X+E1YFUUrxbKPwZhE+qAuQOHfK1hyh3YSF8u5yragUZ5 nHFVOJMNxMyKQvqyso9LsYr3h7jF9jgQVDSyyvKGrisbp5dotcwjrE5ctdXtF/kt 3BknDBburFn7VjPJLdw9YEakv4+ut8oEsO67XGjBgxh+awbKMBzPg6lHKUyh2I0Q 71pkxxlcARAY/kWoK2abCzntedR7T3NW79200QLFQSqOI4jbn5BeJ8DRLLV125rl MNpDZf62iPhlvGByh1UcQiKow0/B1JP3IzYMxpV4fN8Q6qWE+FBzuPBQorzHqqmY q60WGPOKmZ8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFTCCA/2gAwIBAgIRALy02EMDW3WfAAAAAFHOFwkwDQYJKoZIhvcNAQELBQAw gbQxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAwPgYDVQQLDDd3d3cuZW50cnVzdC5u ZXQvQ1BTXzIwNDggaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYD VQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRy dXN0Lm5ldCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAoMjA0OCkwHhcNMTcwNjIw MjAzNDMzWhcNMjgxMjIwMjEwNDMzWjCBpTELMAkGA1UEBhMCVVMxFjAUBgNVBAoT DUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMg aW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMTAgRW50 cnVzdCwgSW5jLjEiMCAGA1UEAxMZRW50cnVzdCBDbGFzcyAyIENsaWVudCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQyjULQnhmdW5BaEEy1EAAh uQdI3q5ugNb/FFAG6HWva0aO56VPrcOMsPp74BmR/fBjrXFJ86gcH6s0GSBOS1Tp AJO+cAgx3olTrFe8JO8qj0LU9+qVJV0UdtLNpxL6G7K0XGFAvV/dV5tEVdjFiRk8 ZT256NSlLcIs0+qDMaIIPF5ZrhIuKgqMXvOzMa4KrX7ssEkJ/KcuIh5oZDSdFuOm PQMxQBb3lPZLGTTJl+YinEjeZKCDC1gFmMQiRokF/aO+9klMYQMWpPgKmRziwMZ+ aQIyV5ADrwCUobnczq/v9HwYzjALyof41V8fWVHYiwu5OMZYwlN82ibU2/K9kM0C AwEAAaOCAS0wggEpMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcD BAYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAzBggrBgEFBQcBAQQnMCUw IwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDIGA1UdHwQrMCkw J6AloCOGIWh0dHA6Ly9jcmwuZW50cnVzdC5uZXQvMjA0OGNhLmNybDA7BgNVHSAE NDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL3d3dy5lbnRydXN0Lm5l dC9ycGEwHQYDVR0OBBYEFAmRpbrp8i4qdd/Nfv53yvLea5skMB8GA1UdIwQYMBaA FFXkgdERgL7YibkIozH5oSQJFrlwMA0GCSqGSIb3DQEBCwUAA4IBAQCPZu3famx2 OlWN4DOF2xAiuC5yViOf1O7AT3+8/osjR96zY7jC1gUxmOjFykGgkGoCleJlT0br 40RCQ4g7ZvsUEclXojEowvQEQdnCuraZtZ7sCzvMupphNdYQy0YPlGZkZGr+texL 0QMZvz2CTvt5U+LrpXIm7ZmHbWnjG0BT6GHTUNQrGZy4WoC6016m+1gQs21VMh/j +h469twl+aLY8ReyI3yX11tT90VCGUjh1lcVdljc1nVMt4xelbbwVbslHil+/zQu dIPY+tKNG2dk0IDE/frAjLu/xMNClsAozoK1LkJ+FtjbWa6dzpEJ0cSzocuIIzDJ BJv0fKno1rgQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID2TCCAsGgAwIBAgINAeJyuF2IBXDU/b3DQzANBgkqhkiG9w0BAQwFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFs U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MjEwMDAwMDBaFw0yNzA2 MjEwMDAwMDBaMFsxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52 LXNhMTEwLwYDVQQDEyhHbG9iYWxTaWduIEVDQyBDbG91ZFNTTCBDQSAtIFNIQTM4 NCAtIEczMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE87ptRJaRgkxj4hA0gkfA0k2e Tx/9pM/Mk/5vGOC8gdMkJm9wo/nOI270X4GyZJkwE8HLkk1T2lTSUWfb8NCMXa9V JwkSHyJz1Jnla69Czc7lwbPC2RQ2WGo9eWmpKZz1o4IBVzCCAVMwDgYDVR0PAQH/ BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8E CDAGAQH/AgEAMB0GA1UdDgQWBBR3MiqDistg+LsbRqkoJ5cyD/zdXzAfBgNVHSME GDAWgBSP8Et/qC5FJK5NUPpjmove4t0bvDA+BggrBgEFBQcBAQQyMDAwLgYIKwYB BQUHMAGGImh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjMwNgYDVR0f BC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNy bDBWBgNVHSAETzBNMAsGCSsGAQQBoDIBFDA+BgZngQwBAgIwNDAyBggrBgEFBQcC ARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZI hvcNAQEMBQADggEBAIG7uZYDXvAgQaAOXuDQpaz8sH/NxDnxDbtsl4C8AkOG8SO8 qjk2qoYkTPXdsv8Mni/SD02SeQYXOPDYKtAjazTx9bfNhz5qwbdnLHSYgJEw00rY jS3JQ9sn2PlHi/X/PZ+9T12G75w34WA/48YKoKTC7RZ7mYGzZrEybB7ENqItFnM3 b0Wx8qJvMebkxAnnYMkRdSjzdi1EmtI0wzF7jAUv78ssRPgik1mXP+tPsX90fDhG nzYeJhMEqFGaDEmE3XXHP91t7aI5uWHUfv9BdI4hcZPSdxtgQwrAqFlpu9kf5ukK YbbKs1ktItGIBGiMCANYP24fC8iKwEGiX8wBcAw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuzCCA6OgAwIBAgIRAP6z1iISG5JGOEZiOKLjAIMwDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0xNzA3MDYwMDAwMDBaFw0y ODEyMzEyMzU5NTlaMIGdMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBN YW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0Eg TGltaXRlZDFDMEEGA1UEAxM6Q09NT0RPIFNIQS0yNTYgQ2xpZW50IEF1dGhlbnRp Y2F0aW9uIGFuZCBTZWN1cmUgRW1haWwgQ0EgMzCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAI73aWA/XLQXKBh/ahXYl49o1PN22uV/cd3LvZCGHeXfZsCM mUQyMhxQvTjjKPccuNOmdZtYNakTF3dxEyhkn8uFgG5E0FWLi8qZR6kj2NsmKOXS n9ZHhGOicLfJ/R9STkryKKTWnIPbbLm+mq63Lt2dCuKq4v5S4PTHZn++v97eay2r NTV8P/U/e46HDEv1/+j3jlZgJgtcuYwWFTrVHH7mviSzrZDnWIpBj69t1L4M4ZRD DO1uHq5k6StofU0llbOnhTYrbGdgw7eKDkFAugr7Fcuwz8xvOOy7CvJaGQeP9bQY YnIzM5eucE7PNv2eeVkyRJglV5vcLh6u1J3I03ECAwEAAaOCARUwggERMB8GA1Ud IwQYMBaAFKARCiM+lvEH7OKvKe+CpX/QMKS0MB0GA1UdDgQWBBRsl7WY9Re4+b1i bA9KTnlJzYK1ZzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAd BgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwEQYDVR0gBAowCDAGBgRVHSAA MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNl cnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcw AYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBc rlbxm34isUwPGOLpQqNM3gWGObKert7GZG3Hj8/uQ8UicwrY0n20UysUTakrCYx9 w2iLHfyz3mc9pAlo17Vh7R8AC/AXCs84BrPr0l6Lf2dkvxhlz/YkS0BpmU3ZXArr 1PB2v1AmwtszL/GlgpVUcVFRXJnjvz1XhBm84lXhI1MmGhZUL0q1FZdgPm95xa9i capwW/NbYsJWkXtmJDf9BD6W8V5tAaWQqUELCAwORiN+j+zjJ8YK6ZHttr/oWUS6 momqigO3ZroVjLp26/vODOH9lEMmnLNoFOwN+wcnJGrA5KGFs3a8w6y/kRceyFrm 0+FO9zxlNMwGMmUM8f9K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIUDCCBjigAwIBAgIIAklSi/v/fd8wDQYJKoZIhvcNAQELBQAwgaUxCzAJBgNV BAYTAkVTMUMwQQYDVQQHDDpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQg d3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRswGQYDVQQKDBJBQyBDYW1lcmZp cm1hIFMuQS4xEjAQBgNVBAUTCUE4Mjc0MzI4NzEgMB4GA1UEAwwXR0xPQkFMIENP UlBPUkFURSBTRVJWRVIwHhcNMTcwNzA2MDg0NDU1WhcNMzUwNzAyMDg0NDU1WjCB kjELMAkGA1UEBhMCSVQxGDAWBgNVBAoMD0luZm9DZXJ0IFMucC5BLjEjMCEGA1UE CwwaV1NBIFRydXN0IFNlcnZpY2UgUHJvdmlkZXIxFDASBgNVBAUTCzA3OTQ1MjEx MDA2MS4wLAYDVQQDDCVJbmZvQ2VydCBPcmdhbml6YXRpb24gVmFsaWRhdGlvbiBD QSAzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnReJEy7VPsENjXww eHiOaHiOnZyTKSO3siTMJ16K8Sj7e39JMr/dRUIIv2QNc3m3yZC9YYP6amtIEae9 iiroOiU5mMNdVbFQHE6hCOg3sG/Jd47K4hvQXAhS0q5VQ+ZZtj3ULi+ETZEtJQPi wLdWrA6ce0doi/2v8VboNEOxU16kKQlnQrtHQmxYTlpipoOjlRc7XZbo0H3gK31Y yVwEtuDCBLLPLMx7m+YUKBSlmdqZq7dMVkpr2JcUW3H+/E2GiE1VORmyuPowpQVT LuK7NEB2v/pnkDOk3NqGoXJ8bQNHn94AfDJPfZm44iKmtEkXpj0AyrgMkAE1Fqe6 55XmStsX3blinVA+t0AxI2VUAYtyTgvxCQmMJVnk37uVCE3QdyC/yn7S1akIVB7k PZBvILjwjEmijzzb6BlG2VLzAvH4RM/SQt8cT8wBuuGy6jQYJHCAxMW4FERZBJr6 lhAZoGB6XqkU3jlWJnmt8R9xqn41yr3nnXzkC+5PR/5xUbWiis2iNOrnUyMMeGhj AFRBqR7jJj2u4m4oQ8TMYU035+3lD7kHN5Wjx4BsKmjiaDI0WPRM3dUkDpYJajwy RvitrYuJxEh3l8Iw3DWfUl2u9CCddV/xgak412I4SIAF4P9bTD7VHuWUEmrx+wTm Q8CHipGeKLJF51dROHIJq5ZKpPkCAwEAAaOCApMwggKPMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFF8Ou7nPR5IMJjRWBb/cnZ4YvcklMIHgBgNVHSMEgdgw gdWAFFsb7gN7otvnRsDCVKuhUClf8VbXoYGypIGvMIGsMQswCQYDVQQGEwJFVTFD MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1l cmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQK ExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2ln biBSb290IC0gMjAwOIIIRIQedGGfUsswfwYIKwYBBQUHAQEEczBxMEcGCCsGAQUF BzAChjtodHRwOi8vd3d3LmNhbWVyZmlybWEuY29tL2NlcnRzL0dMT0JBTF9DT1JQ T1JBVEVfU0VSVkVSLmNydDAmBggrBgEFBQcwAYYaaHR0cDovL29jc3AuY2FtZXJm aXJtYS5jb20wDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr BgEFBQcDATBABgNVHSAEOTA3MDUGBmeBDAECAjArMCkGCCsGAQUFBwIBFh1odHRw czovL3BvbGljeS5jYW1lcmZpcm1hLmNvbTCBhAYDVR0fBH0wezA7oDmgN4Y1aHR0 cDovL2NybC5jYW1lcmZpcm1hLmNvbS9HTE9CQUxfQ09SUE9SQVRFX1NFUlZFUi5j cmwwPKA6oDiGNmh0dHA6Ly9jcmwxLmNhbWVyZmlybWEuY29tL0dMT0JBTF9DT1JQ T1JBVEVfU0VSVkVSLmNybDANBgkqhkiG9w0BAQsFAAOCAgEADMydG0cvMs0XMhPl 9MhFhfFzsAGk2ZpmEZj2Q1Z5WpbJRG6KpbuSpGZS7S1lSki1drgOoXIQyadc/6EC QsmDEMPHeGW+B4LuA4EkwwMa6RVq5o1tSZk1IVZfiAPNabDTvUzbD/d10fkV0rTd N5akiOZ05fWFSI/VedNfTLgwzUbIVYO2foaCxAWWjJNf8UzlFLA2UWJTWWiixiGf YCTaUU40Szjsj8FiGVK62PpBI2m7GGqKIWK9Eip9btn2MfU/PsfcvzIyulHGJlYu lBC1JO8EdERO00vE+mjmDjdNspuYVUYO3Ew6R0XVZUKe1ryeAEj4GG3ABLUzW9IY hsqC5Zr80/RHKVBkaT5mu1Dvms2D4wcYQPstShOCVXfMYQulB/yGrwxIR/oy+tRX mk1gf9Fru5QznslGkn/UifECrjJLD4eY72ZsTEP2jQINw5zf+mSUMhaEKlqmfheX wuWgvQCffWhMeK/4KHK9FFSnRu2IT6L06KXOE3cn00Uu2Aff+BD5vkUM9813e8GA bxeCdypfU4fxdUkl2syq8E46LUge+qGKfHAZ16lqi4kDxHIFWGiIiuB2UTPw+7eA QTi+8e0zPYhAzYvMueGETAM/8/J5xaedvRs6ZLUUBXl/d1ZF0G1FT9f6Zm1XtFsS Tkd3YwUT4mqCQn2Yu/PWKNVX4ME= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIXDCCBkSgAwIBAgIIB9mxhOTwQxAwDQYJKoZIhvcNAQELBQAwgaUxCzAJBgNV BAYTAkVTMUMwQQYDVQQHDDpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQg d3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRswGQYDVQQKDBJBQyBDYW1lcmZp cm1hIFMuQS4xEjAQBgNVBAUTCUE4Mjc0MzI4NzEgMB4GA1UEAwwXR0xPQkFMIENP UlBPUkFURSBTRVJWRVIwHhcNMTcwNzA2MDg1OTE3WhcNMzUwNzAyMDg1OTE3WjCB njELMAkGA1UEBhMCSVQxHzAdBgNVBAoMFkludGVzYSBTYW5wYW9sbyBTLnAuQS4x IzAhBgNVBAsMGldTQSBUcnVzdCBTZXJ2aWNlIFByb3ZpZGVyMRQwEgYDVQQFEwsx MDgxMDcwMDE1MjEzMDEGA1UEAwwqSW50ZXNhIFNhbnBhb2xvIE9yZ2FuaXphdGlv biBWYWxpZGF0aW9uIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA 1vAv01w5OR5rrdjTYynPiyq6QHtYPyMrurxfWwGmJ+Xm8oUa0aUjC3E5+iDI6ZTz bWZ8d6bHFnPfmyEQelxypkviLN+37b49nRBYBqKdgSl5rrpEmPa1NgUC96sdpDoa +sR67B1uGuwRK8G+1h6gHPxNsCSPyMGmxDLSFRqovJTV5HdZqQ6uqS9YayIw9sag /j9Qb6NdgJV+pxaIGbAN9eeus/EJ9odxqds+DXLB5/z6U5hBf+UX+rpzCXV2s2d2 Q9VEeH1kOtuqQIxq7K4AcdISJQmTFoYrYXYsAJTWOw0GslpBqIYl8MScVWwDmH6c rdC6vOlOeYep4q6tupk0WQIhj+3v7rpRKIGaXEaMeT8Ki0M/t7qVzC4u+3ei9yYw Set3fYt3ihyWc+zZT777BwQynvFn+ku5N2y3S4ba06iOphjS9vpfPwShNvO70fQn BtNb3iye/Tkdtda6Z5WLwx5YEnvdHLUoDjsJafMB+6+jpQ6uHFa1986hH0t6WjD4 xJMkNZJcNVzW6ozH2qx7Wp1fBb9/Y8hBHldFR6BMyxc6G6n4BVFhVd1F2t/SlV/R H+LNpLmoRuLBDoGrUHYUgz0F/i3uQoQTi3G9HeZTYjNypxO85uVFB4kUPnps4ov+ 7HHedvOGvsiCBjKkB1YFbhFJIV05mdGP60M+aXKgA2ECAwEAAaOCApMwggKPMBIG A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHGK8B1yEdc5AMKg+QFnp0UHDNND MIHgBgNVHSMEgdgwgdWAFFsb7gN7otvnRsDCVKuhUClf8VbXoYGypIGvMIGsMQsw CQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNz IGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQz Mjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2Jh bCBDaGFtYmVyc2lnbiBSb290IC0gMjAwOIIIRIQedGGfUsswfwYIKwYBBQUHAQEE czBxMEcGCCsGAQUFBzAChjtodHRwOi8vd3d3LmNhbWVyZmlybWEuY29tL2NlcnRz L0dMT0JBTF9DT1JQT1JBVEVfU0VSVkVSLmNydDAmBggrBgEFBQcwAYYaaHR0cDov L29jc3AuY2FtZXJmaXJtYS5jb20wDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQG CCsGAQUFBwMCBggrBgEFBQcDATBABgNVHSAEOTA3MDUGBmeBDAECAjArMCkGCCsG AQUFBwIBFh1odHRwczovL3BvbGljeS5jYW1lcmZpcm1hLmNvbTCBhAYDVR0fBH0w ezA7oDmgN4Y1aHR0cDovL2NybC5jYW1lcmZpcm1hLmNvbS9HTE9CQUxfQ09SUE9S QVRFX1NFUlZFUi5jcmwwPKA6oDiGNmh0dHA6Ly9jcmwxLmNhbWVyZmlybWEuY29t L0dMT0JBTF9DT1JQT1JBVEVfU0VSVkVSLmNybDANBgkqhkiG9w0BAQsFAAOCAgEA nBHB//Sjc5UsZbAH1yiYkDSGGNcbbWqPG7OgMPTCDjUBFU2/Wvk3zvrm97LdLWuk a1PG6BLV6BDVAsZHYjjC76Q79y1PNuHMj+bV4Nq8POwe+W3428tWjQqDSQLzbjb2 enxhLUv/DrKPs1e734BLsRmvL6vjlpax94d1zmolPXQnrhU5HRerJo4Msg4NleRq Nl7CHxLXF7JhzMswwt7HSV+MSBXW2cmnRKaAEjLsrOXVG5F5aH92uUm+KOtbbCLi LAUBWucJZ8FoAtyw+/Dmbt/C4jtZj7k/wwVvnwnxoDvgNDZpsWe+x4tURUYu48iS iE/IhON3MW7EgMBrAT9OeqypKVBInwFpufYtk3S3slW5Nb01mfWavBf9YSpzU8RO GZ8b3kTpgteclIJPNYlLLF1O6Tk5pl4B1+h8DnNcOnZtfU0UcCfS+Fe2I9Xr28mi ssqMdzn8pFX0RC9XDPJ8M46ED3zIKIrWVlyQaJtzLCNvOF73mgkgHNggKBJVFpsw 9jcT49B63KLiTyGylMpXN9DsuVa029TaOYCm2H3OL1+HZtxlHm7ORV1sh3RXSRA+ E6mhxMCRoAkZl7ZfkPjiamY2A8J4nQVwAlDLF/R05IJkV14GU/mAud9wYTxwKxWn trB/oDD1QeUepMtchfjeqiAvY4IUSG/c2ow4Z0pogus= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzzCCA7egAwIBAgIQDirzLp49cVXaiArw3DQknjANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg RzQwHhcNMTcwNzEzMTIxMDU3WhcNMjcwNzEzMTIxMDU3WjCBnzELMAkGA1UEBhMC VVMxLzAtBgNVBAoTJkdvdmVybm1lbnQgb2YgdGhlIERpc3RyaWN0IG9mIENvbHVt YmlhMS8wLQYDVQQLEyZPZmZpY2Ugb2YgdGhlIENoaWVmIFRlY2hub2xvZ3kgT2Zm aWNlcjEuMCwGA1UEAxMlREMgR292ZXJubWVudCBTSEEyIEVWIEludGVybWVkaWF0 ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM1pKsPqL9jLqs1g JbBX1mahy4LBmZr3CEfaEfqiNKedzcfsVpB8v06SjtVjA6GHPcDY6x2j8hMBO9LS PaeTvrGJdI8RQzFcz/XAOeHyWkmN5sqwisgR7PzJ2/p7oAuFONeoRKO+xV2k9vIm vmtfywv57pSBXrfZLcV0Zz15z5X3KR0T7/KqfExGZGcgLkpCr4CeQ9JMfxBGLdvM oOv/6PzzRiomty6+Xrr7tY/UIVl8/s2uxCf+lwExEQb4+AJ5nivmdcKoXYJy09uD 5M3xQb5AfnhdpqTENrrTjG2DiQEcZz4ZLuWJ2NZBgSu9umE40ptJLRcJr5L99oLG 3NZlXQ0CAwEAAaOCAUEwggE9MB0GA1UdDgQWBBRQriizz/ztSwtG0YB+Ewn230vm kDAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYB Af8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k aWdpY2VydC5jb20wQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDQuZGlnaWNl cnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwPQYDVR0gBDYwNDAyBgRV HSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMw DQYJKoZIhvcNAQEMBQADggIBAJESYX/xMSCVhjZskRWaroVgxCKarUm+NIcpDgp5 ElrbNiKCYfJLIveKdYbjbtlmdbV0tsTnZ0Qyd1cWXDiaJF8AsJOfUunxrj/k5Elr UhgCNyIfXgvsREPIoIlepHU/g2JJ0kd7qj2nYKixlxR+qrth0RMMhUS9lh2hAatD i9w+EalFXXD15XEheOjqmcYOUhlm83rW3M+ogV6VkDm8EjZWE/3YVMJqsH3J1Oh1 e4XI77YQm+R84XwTgPMMf/HKKSTgvT3j+xAIrTgn6lXOl6lZ2xQtJ26DXUI1BaR9 cX1BJ9pV3hzlhoHV3n47XQHYBFbJ7+KNLrCQ0X9dhO1UQR1k7Y6YZDcM+p/Uih5u pBMFzr8lxLhsqhJKANs9M0NJ+3CcX/tDO2PTcCv5gURrx2JplPP7UU8pEYjPJady 2aupqT2Z5TBPzO+jiAVbVIYiSsIKjqA1RzrmZpB98sU2TDzVlUpdxf0tTp7zNINn CtkEi6x6CTtbOduK0gCJbbFg4H0uIggmdFU0KojOgu18yU4p8qPHGkOgt9BxgP8W C3EiNaJZGiT5R8+NfCh5P8Yh2Rc0PodLH0IgKeC2TNLr8Me10Sh9xSmDh2LdZ+wg PGjQVHlrU88jbE1b3EqfvM27yKlcRsVJwqkPnMqmxZA683+vmJIb5OG7klMVeT47 h5w3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFajCCBFKgAwIBAgIQB0C2gzlz3cwpiBXDbAgxCzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTcwNzEzMTIxMTI5WhcNMjcwNzEzMTIxMTI5WjCBpzELMAkGA1UE BhMCVVMxLzAtBgNVBAoTJkdvdmVybm1lbnQgb2YgdGhlIERpc3RyaWN0IG9mIENv bHVtYmlhMS8wLQYDVQQLEyZPZmZpY2Ugb2YgdGhlIENoaWVmIFRlY2hub2xvZ3kg T2ZmaWNlcjE2MDQGA1UEAxMtREMgR292ZXJubWVudCBTSEEyIEFzc3VyZWQgSUQg SW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA rVjSP5CFAbatTwFRXPfNkPMQytXUY2cmxVRcWxDWJIWzC+GjMi+vDsPnV1pI39ZB irWCdbdFvy8wlGBoWedxCKZ8R0WLPhOAeAAMUByQVMF8EsnuHvQEv4bxku3IiYyZ lPPjv8btZ5n8mZknjemY6A2wqO5yhZn1iSrEH6hYcq0OHo1dOu7wbx2CZ/6+SY48 myTbJc7m9iBc7Ayvkg00PVPuSefH7BPz7ZmQRwaVbdfBcfBsplyjJVHLFomMNEjr 72XBfs841dE4OAMaayZJx4bsnlKuMAFD+pENxZndwJ3J7JIPJtoaetGyL67L8SVH Ro9lu4jvuedor8jkEOZvqQIDAQABo4IB0TCCAc0wHQYDVR0OBBYEFNO7OCm57iSC 8WWb6sOzyMkmIlNoMB8GA1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWXNqfWMA4G A1UdDwEB/wQEAwIBhjApBgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisG AQQBgjcKAwwwEgYDVR0TAQH/BAgwBgEB/wIBADB5BggrBgEFBQcBAQRtMGswJAYI KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3 aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v dEcyLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQu Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNybDA6oDigNoY0aHR0cDovL2Ny bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNybDA9BgNV HSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl cnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAfRK3SzWx7tbwsly/JgYREJyq ZBjbCNGSgbId00i3ihXCYWzKft1XUw9vzE0izvwu64ZtpAEfn48UCIGf1dvK8UFi rH4EvuGXZYOiJHBWeVg5BIEBjtCVy3w/HJ6F8we13BFVDC7fJG4Vc/qSyQdZFp+v nUvmkRbYovtbYDmRmlX+U6ua4+oaTjzN5hgeARxd9Rc5O8LfnC4bgKTLugMt2NgC tM1OJQ1rMNekAKIWnhqne/PwrelbJTKWj64AcktNB3JeB9C+qRIbVhCZatAThEPh jgNgACUy6s9s3GEK3lKEPCfTsaqKxNrI3mJJ+rzX+LHvdKxIuWlfpaNmVSJMHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDQDCCAsagAwIBAgIQBYyZnhdRmwe+ee1HtSJ55DAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xNzA3MTMxMjExMzhaFw0zMjA3MTMxMjExMzhaMGIxCzAJBgNVBAYTAkpQMSMw IQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEuMCwGA1UEAxMlQ3li ZXJ0cnVzdCBKYXBhbiBTZWN1cmUgU2VydmVyIEVDQyBDQTB2MBAGByqGSM49AgEG BSuBBAAiA2IABPe2wOV65TSl70whDiXdDnV4eDL596G/v+4wdmrIfo5NvsW5UHZQ du4PPfEPwItOwnRKMyQJgiHyrt6q5g5CqKx62n2A5VTGH18/0i7c06Z/pTaW4oBi fUpxdONLepuW5qOCAUAwggE8MB0GA1UdDgQWBBRt8TlJmXMOk6N2hxhWwe+/iusx NzAfBgNVHSMEGDAWgBSz20ik+aHF2K42QcwRY2liKbxLxjAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYB Af8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k aWdpY2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDQuZGlnaWNl cnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEczLmNybDA9BgNVHSAENjA0MDIGBFUd IAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAK BggqhkjOPQQDAwNoADBlAjEA+ds1/rgj0x7Lg5a+YMSI2spZJnaUONJ/2usyA/Y1 hOpMk8mLhZSv3/No70llYB0mAjAYVivVa67crkk0z+OI7vgZCDVHnuwQLf6ERcoF zUmhqKNq85ZTuwZzpkNIknmdbpY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkzCCA3ugAwIBAgIUBgRiM6WCVXakgnJpRxioAA8vAA0wDQYJKoZIhvcNAQEL BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgxMDA1NTVaFw0yNzA4MTgyMzU5NTlaMGYx CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD b3JwLjEvMC0GA1UEAwwmTkFWRVIgU2VjdXJlIENlcnRpZmljYXRpb24gQXV0aG9y aXR5IDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCcoYfPwTh5jkAm 85tcMFJJQNn+EP1REHQoSQoXe6bLjKSdU5mrShIU7qMAYXtTAvWO51RgeovgNPrB dMBhttI2Ia+E0Mi2Ii0WLOLVKn58UK7zKvCi1Ip+geTEWxHnLx74zCCq+TnKS5WA AH4XuTK29ZQT0i0ee+4KWOYJooUjS/vzfyXU2HvDm0qh8k/SDa+F5zTX1C7Uq7AQ edXKaRr6sYPDMNlz5i4IW5rjswQrjywp1OdwtvVn4n/ZWN2LbbCuCE/lEyj/K3Ds pikpKsqbSLhsSICu2063yXdcTMUCsS0aXSUlFnTt4HsxFtBefEMhUG63R7spiVQX /ME1rwEHAgMBAAGjggE0MIIBMDAfBgNVHSMEGDAWgBTSn4jfoc0svez1OwEBkzMn sutgSzAdBgNVHQ4EFgQU6fnrl74h8lTH6SY3Ajm6/LGbDOkwDgYDVR0PAQH/BAQD AgEGMBYGA1UdIAQPMA0wCwYJKoMajJsRAgEBMBIGA1UdEwEB/wQIMAYBAf8CAQAw OQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL3JjYS5uYXZlcmNvcnAuY29tL2FybC9B cmwxRHAxLmNybDB3BggrBgEFBQcBAQRrMGkwLgYIKwYBBQUHMAGGImh0dHA6Ly9v Y3NwLXJjYS5uYXZlcmNvcnAuY29tL29jc3AwNwYIKwYBBQUHMAKGK2h0dHA6Ly9y Y2EubmF2ZXJjb3JwLmNvbS9jZXJ0L25hdmVycmNhMS5kZXIwDQYJKoZIhvcNAQEL BQADggIBAFIIaVQ8K1E2iYWnVX6jBrtXqBxKoBy2Vci1eaDjGJwWPoT/Yq7Rx+Jq Sxre6AG8rE7ddMn4duQh32LPHkMNjH7yuqN9RDn2Ig7yVNZzLLv3MKjcauPx6821 r7mJO2ecRaNzZIN5Vt6l2hvn3x5LA0XycUDn5YtcaZMnR3Re2Cz+ohRvDk+eUG1H 1rRrt31PNK1CX7wjtAUo2tH8HZqgQaNe2xGjHvLg5kR8fn+Md+PeEfvnmxUg7dHV lIE8FhAPIGjyQ5o/4iiTiI3sdCx7Ryi4fJpukkYDMc5xPbCFYRqZXjzeNA/JyrxN DfwWSAa26/Ou6FLR0BsrYUwK4Kx/TlMX88w6mGl6/POJ2zuxTSeccDiYobu6ocUo wcEW9Naxfu9H4CJMIjA++YC2XgnpBmakbjXgRkKOoM8oDaEdnajhc996f+HKkzd9 EBgRFmkOyqLRhb7XpBqM7ssPB9yGEkr3vk6Au56Qv/HtU679OCSXDbp6kYlZM3PD BrlX48QAq2C4WgS58IHAOpvA/6g7/aI2cKknRZKhFfUoUx3c4ALEXjRImeR6QNZt GLxmuptkxPCEtcsdZn/sN0MryETnOldB5TdgizUpu6NrAgnb9k9ptEvwjewQlgty O4oY6CwLXPrnu3Vk60t8/koeBh3+Tmj/Yv3UqF9VgLJmVUsylyFd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFmTCCBIGgAwIBAgIQZtLmSeR1il7Xk4ZiWfQOuTANBgkqhkiG9w0BAQsFADCB vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0xNzA4MjIwMDAwMDBaFw0yNzA4MjEyMzU5NTlaMIHMMQswCQYDVQQGEwJVUzEd MBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVj IFRydXN0IE5ldHdvcmsxPDA6BgNVBAsTM1VuaXZlcnNhbCBSb290IE1hbmFnZWQg UEtJIEluZGl2aWR1YWwgU3Vic2NyaWJlciBDQTE/MD0GA1UEAxM2U3ltYW50ZWMg U2hhcmVkIEluZGl2aWR1YWwgRW1haWwgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy9xv1UNkZk37AyVjXVxbIhWf +/eBhH9YHFhu0SWKexQlJzv6Zbowf8NZB6ty4uwLTPs93uP8J8MPVm8MEo+B5A3a unr43MXp7plnP/sCpctz9E1V7MH/pTii/mpgsOOJONX2F//h4eYd7QSWqTcm/2eC 1Lc3nU0nmFoCfvTSmXHodS8edUe/1R2X/Ut3aCfbnNnorHjLqXaSX+4GPepx6swt 0Y+aaJh7yjFf0Rhe1q+sxUifFuCILgsDFNpjLn+r3hKpvPSedC0tpPr6Z9UCK11K vwfOiaIksM9JiIU0nme3Hduwi3LMkyJYRtm7nGnKcGkLh1AybHmxhWQSmQXIAQID AQABo4IBgjCCAX4wLgYIKwYBBQUHAQEEIjAgMB4GCCsGAQUFBzABhhJodHRwOi8v cy5zeW1jZC5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADBmBgNVHSAEXzBdMFsGC2CG SAGG+EUBBxcCMEwwIwYIKwYBBQUHAgEWF2h0dHBzOi8vZC5zeW1jYi5jb20vY3Bz MCUGCCsGAQUFBwICMBkMF2h0dHBzOi8vZC5zeW1jYi5jb20vcnBhMDYGA1UdHwQv MC0wK6ApoCeGJWh0dHA6Ly9zLnN5bWNiLmNvbS91bml2ZXJzYWwtcm9vdC5jcmww HQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA4GA1UdDwEB/wQEAwIBBjAp BgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRU3ltYW50ZWNQS0ktMi04MDAwHQYDVR0O BBYEFF2wre2AKUkPJ3XE5sov10eTBvneMB8GA1UdIwQYMBaAFLZ3+mlIR59TEtXC 6gcydgfRlwcZMA0GCSqGSIb3DQEBCwUAA4IBAQBip8AB9eIHiYTfM7xJttmdVETo /Cl7cT6GF60A1peW3U6iDsNIFAd2gHsD2OSMHY5nmpqCvo15k4ZzlMMhvtCWhdn9 Z5v1/QA1D8PJ5bzmnqbzMIhVX/mWZQRAML6z5hVrftTLy6jnPVqggQ5QrCLvPinF ppcBWhOZvbJvn3desmizI0v7RN45enAr7tOJHXsFmAIpUto4KRE8bxTL4kfIsoh5 1W/HfN3dOdQdlClrUnGUWJQBnDA48KFDk/i6tbwWg5KjA9fLfXa4DbKxOGC0Xx95 LrNnBswRv4Gr4SzbgjvGILQJKIChqQ4+4PEyO+b/qoujUOeeg5obZqM5ivc7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDJzCCAq6gAwIBAgINAeUosrp260WT1agwBTAKBggqhkjOPQQDAzBQMSQwIgYD VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjUxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTcwODIzMDAwMDAwWhcNMjcw ODIzMDAwMDAwWjBQMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBu di1zYTEmMCQGA1UEAxMdR2xvYmFsU2lnbiBFQ0MgSFYgUy9NSU1FIENBIDEwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAARiwqNuJIv/39NfELib9OCeMck+4qKh9PmyRQLL SAUGBdOMfSJDcrTKP1rXF91LQgZBK/bCv8LiqzE+e/GVTU8kpycxnKC9whj48Gx8 qBVV8QxU3y9GHeRtzmOhdboH0cqjggFOMIIBSjAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0OBBYEFHBQdfkVLkVsaK7xUlvIvpxwm+U5MB8GA1UdIwQYMBaAFD3mKUib 6gfKIURKJt5u3tKD0J9ZMD4GCCsGAQUFBwEBBDIwMDAuBggrBgEFBQcwAYYiaHR0 cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3Jvb3RyNTA2BgNVHR8ELzAtMCugKaAn hiVodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jvb3QtcjUuY3JsME0GA1UdIARG MEQwQgYKKwYBBAGgMgEoCjA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9i YWxzaWduLmNvbS9yZXBvc2l0b3J5LzAKBggqhkjOPQQDAwNnADBkAjA8mZfkofuf ROqbf4m3CMSfiaQymu3sWLyhftjsFfWhO6oagvcQ4meqwqT25bo5rCACMFdqikTd +phL5EJ0hfjo6Y35jifL35DaoroXSRNsSUe7YXnla+GGYXV7FM84q2utsg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjTCCAxKgAwIBAgITHwAAAAfDD7xDFE07ggAAAAAABzAKBggqhkjOPQQDAzBt MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i YWwgUm9vdCBHQyBDQTAeFw0xNzA4MjMxNDEzNThaFw00MjA1MDkwOTU4MzNaMEwx CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSswKQYDVQQDEyJXSVNlS2V5 IENlcnRpZnlJRCBBZHZhbmNlZCBHQyBDQSAxMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEU7Z9s3TGlT7UMM+zP5+ypsVKfh+jjlj0LkgJ7PJ1c4FnzbqERTMoBS7B srrRwAFsH5O8VEEKorF1DtpYMh+PhqOCAbAwggGsME4GA1UdIARHMEUwOwYIYIV0 BQ4EAwEwLzAtBggrBgEFBQcCARYhaHR0cDovL3d3dy53aXNla2V5LmNvbS9yZXBv c2l0b3J5MAYGBFUdIAAwDgYDVR0PAQH/BAQDAgEGMBAGCSsGAQQBgjcVAQQDAgEB MCMGCSsGAQQBgjcVAgQWBBS7+baRi2PktBM2aQ/WkiE8GV85QDAdBgNVHQ4EFgQU OAxEX6pKi37GW+0PrKjRWE8xfsIwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEw EgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRIhxSs48OekGA618qJ7tOt jLRQZjA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vcHVibGljLndpc2VrZXkuY29t L2NybC9vd2dyZ2MuY3JsMGkGCCsGAQUFBwEBBF0wWzA0BggrBgEFBQcwAoYoaHR0 cDovL3B1YmxpYy53aXNla2V5LmNvbS9jcnQvb3dncmdjLmNydDAjBggrBgEFBQcw AYYXaHR0cDovL29jc3Aud2lzZWtleS5jb20wCgYIKoZIzj0EAwMDaQAwZgIxAL+C 2S0OPTLshBE70bdxEK6eR+OOW0v9N914tpQNOqX3cxDsuVDf6GABgXSLkUvRuAIx AP+vhaZRfCui4cbzYhyPsKdYfNuFpHSYy2jJOjOLc21azpK/I9lkdymep34o8rH2 TQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIErjCCA5agAwIBAgIQBfLX79jGu+0toi7o3HSzDzANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE3 MDgyNDEyNDEwN1oXDTI1MDUxMDEyMDAwMFowgY8xCzAJBgNVBAYTAklUMTEwLwYD VQQKEyhUZWxlY29tIEl0YWxpYSBUcnVzdCBUZWNobm9sb2dpZXMgUy5yLmwuMSYw JAYDVQQLEx1EaWdpdGFsIElkZW50aXR5IGFuZCBTZWN1cml0eTElMCMGA1UEAxMc VHJ1c3QgVGVjaG5vbG9naWVzIEdsb2JhbCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAODFNbSBS0Bd0ARG7HuVejfFdwHt5bxubDmerRXUlf7S6yeF 2LNx1vY9q453W77ATTSwkk1xJdi2LYGALwLNOvlgUdcEtHe195M7Rf4Pjn3j+xcP hnWZfzHZ8oUJ39gDjzP/C3/O695xE1Y0R4jaZsHfBwySkMFxVNR2xFENt1uSfQvr vOX4/5HKTHoaWOBiHLmgexYuHpUphHPVbnrmgyIAlPhI6f0Q9oObDlG3FRz9NQqg 6uY1URfBlkVvVQpQ6zmuFvGUPynhvCmbB/mokF6UmwWXa9IzOHtuzAzwwINBjjGr U1/doJEfgD6WIpxMGuszjGLeZOYMtglRE6wJlhUCAwEAAaOCATgwggE0MB0GA1Ud DgQWBBTGBwkSpTaGP3dZoWhXEKrYY9aHxDAfBgNVHSMEGDAWgBTlnVkwgkdYzKz6 CFQ2hns6tQRN8DAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQG CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wOgYDVR0fBDMwMTAv oC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09tbmlyb290MjAyNS5jcmww PQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRp Z2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEBAEqQw886vk8aTSPskm9n 5CXJqPCUIYMZKP++fYUBWuPbCDmCy3WjaThoUIL0MSuSKnyxgwZwYjYex/JhTSJG D7EOb+po12VrCkU0jGK6NEGCjl0irXcJ2x8aixXaxDegtzJ2zcpoXiSHi7VGfDxk aXw6IP5n6lKMDjGBjcB4jcNUH4c0ilM3tAh3r4Onyw7PkstpbTBp8OyQLiwdH0+V G//l/zeLwmzjMbnJ8TudwmgIAg1huArrOJc+dDke1uNsv6IY4o2LDwMEivjD6M76 6Bb6qMIpWUWFVmUuLTe6eYjyKIH3l3Sv9p+dzlKOg9azlCgIbsZwHQjphWNtqtdD a28= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEwTCCA6mgAwIBAgIQAVxw2vIiOEPUONjwBNkAwjANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE3 MDgyNDEyNDIwNloXDTI1MDUxMDEyMDAwMFowgZYxCzAJBgNVBAYTAklUMTEwLwYD VQQKEyhUZWxlY29tIEl0YWxpYSBUcnVzdCBUZWNobm9sb2dpZXMgUy5yLmwuMSYw JAYDVQQLEx1EaWdpdGFsIElkZW50aXR5IGFuZCBTZWN1cml0eTEsMCoGA1UEAxMj VHJ1c3QgVGVjaG5vbG9naWVzIEdsb2JhbCBDbGllbnQgQ0EwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDJko5r/DUplcUNDY1rK6tuLOSaiom5exxRDFKQ N4pZbGfLi86Fbel3NpjgyXLQ6J9xO4Fp6T47o6o8x8i46QUyIfCqYzO1oPKlcCXW 58Wudp1m6QTDcViOuqxUEwqxTiG5OvMfCT++7Vvwo51JdOFd1B9y3bXr/tZ2MV97 daV0BzunAhCee1m3w37u54RCUNN55ga9ww3Z37LvKZptPdNx3YzJWcBkfee6kmWe cW1n01albonzy8oQ19thfFxaAuQg56HOPc4qmrwuNL9gKNMqaHU8zQfQYyBn973A MHHH2bjsn879+VDJzt5cXAUZq+LUYM/H1F4p/BJoA3PE6M7HAgMBAAGjggFEMIIB QDAdBgNVHQ4EFgQU3N+jvg1kHjMuEqSAu2sCveU9BoYwHwYDVR0jBBgwFoAU5Z1Z MIJHWMys+ghUNoZ7OrUETfAwDgYDVR0PAQH/BAQDAgGGMCkGA1UdJQQiMCAGCCsG AQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDDDASBgNVHRMBAf8ECDAGAQH/AgEA MDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl cnQuY29tMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv bS9PbW5pcm9vdDIwMjUuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUF BwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUA A4IBAQBdpmEsaqKx0NCpqAG1q9+xdM0KPcnaLgjtF8V4JG62ci6MONS1ROFz5Np4 3YFkshCe8QzSM6PU3XHeeN2MgFKuKurxSoUWDcArqXAsf9fgtVgQJpCRWyLlEyl7 5Xx2yRbQORCLjApGnmpojrJKgJZDL3R6s/CBzUNV28V4biIyz3orR6wfIELCxije Qvvn3NvrIP+DenLhv8PkNM1Lm1QVYJAh9hXraN31VG8AGIDjAQMoy8kFMvO6LNf7 P60CfC7KSvS3VUSCJrf2FvrpWQia8s8K2FPLT+s9eAprLhcLZz8WXhH1falPWGGp ToPs0WY8IPKCcfUqiMPII8gCip89 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDNDCCArugAwIBAgIQDWqQjXwuiWFi22ChybOF+DAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xNzA4MjQxMjQzMjhaFw0zMjA4MjQxMjQzMjhaMFcxCzAJBgNVBAYTAkpQMSMw IQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEjMCEGA1UEAxMaQ3li ZXJ0cnVzdCBKYXBhbiBFQ0MgRVYgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASE b9AdJ59uU3/h/N+WS5RjbPvVQfWS503n1dOZB8l8tTbMecabudx/fNkd38dBKZJo bricDVPWvw5XkpK8xc5YEVCcmYIZLIudnZhKELpqpVB9NzZUmpInW//qTcvqis6j ggFAMIIBPDAdBgNVHQ4EFgQUo/c+oxu3V1NJEyu3M7Xz6znLkiIwHwYDVR0jBBgw FoAUs9tIpPmhxdiuNkHMEWNpYim8S8YwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQW MBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsG AQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t MEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdp Q2VydEdsb2JhbFJvb3RHMy5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYB BQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIKoZIzj0EAwMD ZwAwZAIwZk5Ef9BUU4vySOkCiqy1+oocw6leJ8nAbZShAvMGQx6iiz1Q0EBS9Dkq AOX8W2BSAjAgLRSWAIuJ9ncp8Fc1cJYq3InC0nUZMQh7wXAZyaLJM83eYdr0whmb 76i9NnEWkbs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIfzCCBmegAwIBAgIIAcUjhpoeshEwDQYJKoZIhvcNAQENBQAwgbAxCzAJBgNV BAYTAlBUMSowKAYDVQQKDCFEaWdpdGFsU2lnbiBDZXJ0aWZpY2Fkb3JhIERpZ2l0 YWwxFDASBgNVBAUTC1BUNTA3MDE1ODUxMT4wPAYDVQQHDDVHdWltYXJhZXMgKHNl ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmRpZ2l0YWxzaWduLnB0KTEfMB0GA1UE AwwWRGlnaXRhbFNpZ24gUHJpbWFyeSBDQTAeFw0xNzA4MzAwODE4MTZaFw0zNzEw MzAwODE4MTZaMIGyMRQwEgYDVQQFEwtQVDUwNzAxNTg1MTELMAkGA1UEBhMCUFQx PjA8BgNVBAcTNUd1aW1hcmFlcyAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cu ZGlnaXRhbHNpZ24ucHQpMSowKAYDVQQKEyFEaWdpdGFsU2lnbiBDZXJ0aWZpY2Fk b3JhIERpZ2l0YWwxITAfBgNVBAMTGERJR0lUQUxTSUdOIFFVQUxJRklFRCBDQTCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN4SHFBxmwJYClfYbD3+rqNp C6yuVdjbirnuJ2n8sPUcDEVxo5UGBC5pMMHdQExcGGjysTy5eowxpQ1+/H5KvSvX R9vYMx1vrCnq3ababyLrub+H+gUMk74qwsltHAmsLkaYIf4TFbpqjxsgxtccNN5x YRJ9pFkLZY2b+p7CYc447kE8pRTBrSCyZUhl0/667fsgSsD5+JtoIBvYn0lB7ivh Gu8Xco7/OiMhNrDkW6q0EzAPd/P49ww6OBmSqejLJR5fH3Ymr4KVEuPQDYs+IErJ uf5XT8B1RPw5ysxWxiymrpI4MQ3H2Ac0Z8vIDgSnjZVntHa7E55Wbp0o2mXQ29Cp WfbngdpwB+HMQc94cVXIkR8YpGJp9IBWLWuBZzjE3vmgpBtfgiZis4Gnjd1Cnic6 dAyatVNCMbor3LgAHrD0B1Mb40me5yIpxf7qDyU/FkyK6E88vi/nRXFt0QM24+2x URGqV1qUsKIoJyJj4CFD2fDd3Ezdq0HpDkz7P0BWCNk411zCKufebnwk4sz23Vsb RfFp/cssG4xnA8V//0MEiUMD68iVb3X90EwPxyd3GzOHoCofwHm1Y7AMX3HfV0PE UilykMOBUVe7BD+phT6R2Un7K578yT4AwwnS8NLwm/Nt0YkVzMrdbAK8la2mlp+M 9vt0SADkf7ksBsqq/PADAgMBAAGjggKXMIICkzASBgNVHRMBAf8ECDAGAQH/AgEA MB0GA1UdDgQWBBT/4cWxgifEQ5VMfJIBZ+xMVN7tjzCB3wYDVR0jBIHXMIHUgBSo VfAzw04izGgcoRms0SoTPSVgYaGBsaSBrjCBqzELMAkGA1UEBhMCRVMxGzAZBgNV BAoMEkFDIENhbWVyZmlybWEgUy5BLjESMBAGA1UEBRMJQTgyNzQzMjg3MUMwQQYD VQQHDDpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmly bWEuY29tL2FkZHJlc3MpMSYwJAYDVQQDDB1BQyBDYW1lcmZpcm1hIFBvcnR1Z2Fs IC0gMjAxNYIIBLwHIkVpZ5QwfgYIKwYBBQUHAQEEcjBwMEYGCCsGAQUFBzAChjpo dHRwOi8vd3d3LmNhbWVyZmlybWEuY29tL2NlcnRzL0RJR0lUQUxTSUdOX1BSSU1B UllfQ0EuY3J0MCYGCCsGAQUFBzABhhpodHRwOi8vb2NzcC5jYW1lcmZpcm1hLmNv bTAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMC MEgGA1UdIARBMD8wPQYGZ4EMAQICMDMwMQYIKwYBBQUHAgEWJWh0dHBzOi8vd3d3 LmRpZ2l0YWxzaWduLnB0L3JlcG9zaXRvcnkwgYIGA1UdHwR7MHkwOqA4oDaGNGh0 dHA6Ly9jcmwuY2FtZXJmaXJtYS5jb20vRElHSVRBTFNJR05fUFJJTUFSWV9DQS5j cmwwO6A5oDeGNWh0dHA6Ly9jcmwxLmNhbWVyZmlybWEuY29tL0RJR0lUQUxTSUdO X1BSSU1BUllfQ0EuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA4rR8mBGjzcdXkJrpG 1JHMOiH6LnQzJ7BJF1qHooe0cMVY29IN0GGAFqT0WS2qC9MbuObuGUPU/tgcsil9 hkZyDV201Io0/L5vGT+ptHnP58K9YqFrjrtHbwIOPGgvQQRfW1W6IaoZtV1tbcqF B0wtKl+9RFUrTv2L+6TB3Ne3CLZc0jzacqUH4rrzw97M/u+2456UX67sWvUV+Kvp eGbpWGpSAJ2xnXU26zZW2q03MQ3wViu56NVye4YDPMzp/bYNwhpj7jinsUBQqC7l JJUysXhtuWqP7gVfO8S/VwFvckfPpVYi1wH6w6m4C842mXO6Eak2XAprPat097Nh mjr7rNyQ8sq1hJ0WDYzIyZ4C2RGZ3+8FJIChCGYjtmFWHGA/a2AHxhzISX2fNZ7p LJZuGse1K6VOIxlf9LNWBcKbjDH6AlNghvsnZ10J4amh/nXDF7B3T0qkVS1ZKsLb ZqLQQZYyVYRxD9tF9OHw4phAhCnREAYdKB7NlXzfgin/3jpd+6DqhPm7h8sLc35u e3+2H0klEsDFkgMBaDoe4xwq0takDu2VC338qcoHI8id5AvyKFjKlrP/3/8LzOax mdzd1e2WNM5sAeKIUz4maRe4Rkw50/RDhcF/fRMNOn30BglXHFgMl7xRjEvQrX5N N8UunfM5ds6vmg6RHuLh1Q5Q+w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF7TCCA9WgAwIBAgIRAMCmDN8jqjVlXjJpEDBR8PswDQYJKoZIhvcNAQEMBQAw gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE3MDkw ODAwMDAwMFoXDTI3MDkwODIzNTk1OVowbjELMAkGA1UEBhMCR0IxDzANBgNVBAgT BkxvbmRvbjEQMA4GA1UEBxMHQ3JveWRvbjEfMB0GA1UEChMWVGhlIFRydXN0aWNv IEdyb3VwIEx0ZDEbMBkGA1UEAxMSVHJ1c3RpY28gUlNBIERWIENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAngzvmYftbW4/GMXiMEmP3igo6fXRKgtu 0RV0NNnEv8RSxZ7dVc3drGEWsvJq65Gs9GCwZAn5sRUfbb+ECGfts4fK4zEN3AzA 82xwrDM7xANYSgnM7ASC3Mgm4BlJsIRWt5UFVCECZtMWFURku5EXGra6v8RYx7mz DlHLLNItsmlJGd+TPgHA7PPbVkiHnZDHPARJIURMEN6WCOte9TWWU8Mn33sB4L7O /0KcN0EZXbr+KbVk9h1ECT3b6v96hHtJpkGebI5puiccQ/WPPoevY1XhNfAdGiPF YWpuvWNVLkR2+JJszeEjGMMFxeWqLSqBG3g7yCnH/SqIbWqYoi0bsQIDAQABo4IB bDCCAWgwHwYDVR0jBBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYE FF2K0SMIL+Gdgc7ZLHAoupcfrhg1MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8E CDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAE GzAZMA0GCysGAQQBsjEBAgI6MAgGBmeBDAECATBMBgNVHR8ERTBDMEGgP6A9hjto dHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0 aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9j cnQuY29tb2RvY2EuY29tL0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUF BzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIB AGy1WTIYN/X9cVXJl11gC3mYfXZniNMq3u49K+/0+GJiAZB1PfXtP+kQhwQp3F5F YxN2OhPu7C8Db1ML8CTwzCGK8r/m5O3SwINSdLqCmX5/j2LUDrnCQQf3jcETdaZU +HmFWpUdRL7DD6/hUDsGEVPNxgARdtFSz78WlsvdCd7K+XWhteoQAMNIw8EdXrcI YSfxo3rHh/t4BfEm/N1VWavip59qa7A5HvBuGTA4Xg08hSsTVQOEMSzKSe+cpNwV mzrTuiMuIzwAzbAJoTaYF4q3+l10OegBDJQvG0b4a43mRhiVyZ4B/AkTt+it3HpU 0FGcK/WwvJKNH5EkZ4cJMo//+mqbeg8KeDpL38r1IlqSjWTsNnSwYlxhCNvcMCYB WtamCiKd401QZqD5uwzxslmj4n+aCETqF+0JUeda3pR44w7xwSavGLzlMlmIMQ/1 fa2i7QA+a2N2sL2VHsF2KQ2eShBAccHAhMgQSAlWfz/fWIXFdZIk/i/05FTgGqc+ xlPXLWR/Chch5Nrb8M0bTsYYqQUUDSYlg6Jm4VcV0tTZO+632ZlhPWnebQdFew5G Z7KbhTyF/NOkaz3b0n29XYDW2VQi/JV07AYmbTHgoIh9KvrxNauJTWpZ2WH69nNJ ufKYwKWgXcz1Gdj87G6isak26Skc/sH8u8GqhRBI51uP -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfzCCAwagAwIBAgIQDlqKcUcL09Vv7lj1gaoYIjAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTcwOTA4MDAw MDAwWhcNMjcwOTA4MjM1OTU5WjBuMQswCQYDVQQGEwJHQjEPMA0GA1UECBMGTG9u ZG9uMRAwDgYDVQQHEwdDcm95ZG9uMR8wHQYDVQQKExZUaGUgVHJ1c3RpY28gR3Jv dXAgTHRkMRswGQYDVQQDExJUcnVzdGljbyBFQ0MgRFYgQ0EwWTATBgcqhkjOPQIB BggqhkjOPQMBBwNCAARnVFJNb8Yj/Ce4fjW/oc3/icpEozgeJMAkKwMq7LuVALmv l1rN5807sGQCS0TAkcNczcvzVjAXefMhx/1y7BUFo4IBbDCCAWgwHwYDVR0jBBgw FoAUdXGnGUgZvJ2d6kFH35TESHeZ03kwHQYDVR0OBBYEFJLYluI54EfoZENNm9/m 0qgWKZdmMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEB AgI6MAgGBmeBDAECATBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9DT01PRE9FQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t L0NPTU9ET0VDQ0FkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5jb21vZG9jYS5jb20wCgYIKoZIzj0EAwMDZwAwZAIwI/nutGtn+PaYTAwuN/V4 Dvg3BvGv2B24N7dEsZSrgHytxLb4muS/SLILN6Yzke7DAjA/lr8DJMPlWBSfV+xT qJnNYjtX8vjQWpCmdoKK2/7kWNDNEoxZy4lRR9ERjhBOXes= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDgDCCAwagAwIBAgIQXlTSWnOAKPvsBNqtJQ5I6TAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTcwOTA4MDAw MDAwWhcNMjcwOTA4MjM1OTU5WjBuMQswCQYDVQQGEwJHQjEPMA0GA1UECBMGTG9u ZG9uMRAwDgYDVQQHEwdDcm95ZG9uMR8wHQYDVQQKExZUaGUgVHJ1c3RpY28gR3Jv dXAgTHRkMRswGQYDVQQDExJUcnVzdGljbyBFQ0MgT1YgQ0EwWTATBgcqhkjOPQIB BggqhkjOPQMBBwNCAARDnsiaKW9/ceim9aM6lcVCjkIK9TNDIj4tIvXCVoOzpUyB EY6xG+bibsuNJd2jPtnWAMO1qtdp96r0a7aB4m8Io4IBbDCCAWgwHwYDVR0jBBgw FoAUdXGnGUgZvJ2d6kFH35TESHeZ03kwHQYDVR0OBBYEFFxeRTg3GahXbNEM2To6 PK6m4Z9bMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEB AgI6MAgGBmeBDAECAjBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9DT01PRE9FQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t L0NPTU9ET0VDQ0FkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5jb21vZG9jYS5jb20wCgYIKoZIzj0EAwMDaAAwZQIwHio63VPvGQ5lXTUBiErC WEQHH9li8jnvRkdf7JNWb2/7JkL9Pp55JXAup3MlQ9+JAjEApswYaCf/exDD4/M4 E222bB3z68KNU3+2Sb/H8sXt6rg+a4CesPjh0jOIWjncVUvW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4zCCA2mgAwIBAgIQCH+r7PWwb7m2UcD3+HlbYTAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTcwOTA4MDAw MDAwWhcNMjcwOTA4MjM1OTU5WjCBtDELMAkGA1UEBhMCR0IxDzANBgNVBAgTBkxv bmRvbjEQMA4GA1UEBxMHQ3JveWRvbjEfMB0GA1UEChMWVGhlIFRydXN0aWNvIEdy b3VwIEx0ZDFEMEIGA1UECxM7Q29udHJvbGxlZCBieSBDT01PRE8gZXhjbHVzaXZl bHkgZm9yIFRoZSBUcnVzdGljbyBHcm91cCBMdGQxGzAZBgNVBAMTElRydXN0aWNv IEVDQyBFViBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIwL7VzFJL7MY9wW 3iMt0CgPaVa9Ocl1yATOiX5422ap0hR1a7B8Y+IcYkmqN2DA1HHtxA12pOyPKQdN BkfY2xijggGIMIIBhDAfBgNVHSMEGDAWgBR1cacZSBm8nZ3qQUfflMRId5nTeTAd BgNVHQ4EFgQUDS6MAXBc5OacMPoQyc63D4CyUDYwDgYDVR0PAQH/BAQDAgGGMBIG A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3Vy ZS5jb21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNv bW9kb2NhLmNvbS9DT01PRE9FQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBx BggrBgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2Eu Y29tL0NPTU9ET0VDQ0FkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8v b2NzcC5jb21vZG9jYS5jb20wCgYIKoZIzj0EAwMDaAAwZQIxAImL3o2NuMAX50oW 8yq4Fn60uEe/KdRYVKJ/WW+2xNhV33tctGWqqtg3SK8cs7eipAIwK7PhO09AtJlp EibGqRkZnNztdN1NHw1DlSjNPbKpwVRdHaNCSO7OvzDuGw5UmaJB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGTzCCBDegAwIBAgIQYa5ngpFKTlew0jj/wt6AlDANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTcwOTA4 MDAwMDAwWhcNMjcwOTA4MjM1OTU5WjCBtDELMAkGA1UEBhMCR0IxDzANBgNVBAgT BkxvbmRvbjEQMA4GA1UEBxMHQ3JveWRvbjEfMB0GA1UEChMWVGhlIFRydXN0aWNv IEdyb3VwIEx0ZDFEMEIGA1UECxM7Q29udHJvbGxlZCBieSBDT01PRE8gZXhjbHVz aXZlbHkgZm9yIFRoZSBUcnVzdGljbyBHcm91cCBMdGQxGzAZBgNVBAMTElRydXN0 aWNvIFJTQSBFViBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIYa qP3zl3whJ6IL6X1wjUDwTxc5TsGBuEZnNkY0RqRgJ5w0Rlls/N6x6ddY9Cq6bPx7 5mBoJDmDyU+DkI1K82icElEa9Gv9JadGHD6cYPltIHToQjJuftyr5HH7Q+0ZlvXH REbC/7LFDNtRP0MILyZHJIO+AQOTE5U9sj3nxdhdfhmPFjG7QV4U1sD7w6w2+3DN DSmySyJa053d6bQARB0ZIdbsc9wFxBUT2X4jVeSj4cYUk1Yn1UUu8tvZW6B+Prms B5jRhbbdgTBDIyscxjrce/I61KOZC8pWPTORV5XkIiAz8+uzR2aKzVwOi7bRM965 9O/cGzfW1Wct+KcR7P0CAwEAAaOCAYgwggGEMB8GA1UdIwQYMBaAFLuvfgI9+qbx PISOre44mOzZMjLUMB0GA1UdDgQWBBSJKwRxsCGiKFg1WPeVQtvFOBz4xTAOBgNV HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwPgYDVR0gBDcwNTAzBgRVHSAAMCswKQYIKwYBBQUHAgEW HWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMEwGA1UdHwRFMEMwQaA/oD2G O2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JTQUNlcnRpZmljYXRpb25B dXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA7BggrBgEFBQcwAoYvaHR0cDov L2NydC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQWRkVHJ1c3RDQS5jcnQwJAYIKwYB BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQwFAAOC AgEAVWgP0O5hmT8laZJS4aeGwboEOOVgCP861lBDSPSItcKpOy95oZC6ZpWZTBO4 AQJqLjnmArAu+3If8h5xXzXpsvqpDGAjKzXDnrF5erZQlQGTaQMjqRKERejun7vq jmZR9uQd/feuqPzrM4FusdxZoeT88igLqiIZ4KnPcCm848+O+/1U5iTUm62xZVyn 4XD+ZIKKSXMl6O8m7TU151ZeFaHo27Q4dm19z4v2SXF3UmW91C0I6avqUeFn7UQg 64N3vcktJFtCAUCCl2QAfw+3MPMTwhOWaS1o/A6Xo/ha5uahnhS8W9mTPhZvd7Y5 tvi5vLwUA4EYqLXTcW/NF687/WZg71e6OpQPUg9yhNH7kpUGzkpMY87S3jaWyfB5 xoatEHZLUUfURLFX34Ib3m+eC5V/Oj3bZ+zfU2QowdtW95ho5HJu23KV3HLok4XQ XBt9JvG67wM7Pbu44SoLyqN4CyyoLRCWfd0OkHe77ceFTGS1HdyQiFVyfMka/tWp hKS7qhx/KU2SqIbO2sZF8Wbi62ndrUv0dkCNYvfeETTmnnqazQjBPoslUIq0th1f O7SYJoQJYh4uyRHwbR8geB4x3scQOupESDrERoOkkONiO+HNQ3c6/c7wSZEZQxAF EaGdixQqtYgVRiwiz/RaSJcfgmkbU19fgzvmxNMUNVZlB1E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5zCCA8+gAwIBAgIRAMFUDtuhvh9VjdJmQznvHvAwDQYJKoZIhvcNAQEMBQAw gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE3MDkw ODAwMDAwMFoXDTI3MDkwODIzNTk1OVowcjELMAkGA1UEBhMCR0IxDzANBgNVBAgT BkxvbmRvbjEQMA4GA1UEBxMHQ3JveWRvbjEfMB0GA1UEChMWVGhlIFRydXN0aWNv IEdyb3VwIEx0ZDEfMB0GA1UEAxMWVHJ1c3RpY28gUlNBIENsaWVudCBDQTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPn7I66JPWuDjO5cUw14YolBNaLc UNj8qsjCghZI3ICQeaC46fdUCpVMVMYpa0t/dirr7+8zNJ0TLzx+ZvzhLDex72Eo s+TI7U5feLCR5vogYAFzHNAM2DzJoypk2+o2hnE6FdwBLcIq7/HYMQ7UZT8Il2R/ t2Jsju/t6MHnQN6qcB3JgEQBcMvPrhI+gYbKtJSjAKk2k9btnhs6yFWM9Xsenxvb k3epvYPMSiBYdGrbBjQE4QI0T8Q99A1RcsfeJN+sSAxKeaDoAozMZC+RBB+RCBQw 9kLQXI49oxDemNXF6jZbQO3xqApd0wVssBgF2tLQScyp8XlYjt4BFbq5ZakCAwEA AaOCAWIwggFeMB8GA1UdIwQYMBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1Ud DgQWBBTFTxKDkBX3DQhhjO1H6WPbTpe69TAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwGAYD VR0gBBEwDzANBgsrBgEEAbIxAQICOjBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8v Y3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5 LmNybDBxBggrBgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29t b2RvY2EuY29tL0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhho dHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAEHYuGKv 39+q0RyFajWrXEluASRpLmnoggqmFSeJbGbRIEpbUmJwmu4T7G1wzrsz1FXHwMSn VxJGkVcZsi567R309oLplpioYlRcsVhUuQg6gwgDdLeIKkmh46BFZ8lvOvK3jGSy RM0mCtWdLo4PN2829Y+QvH3BGZJkkL48QdW7xL08D+Ux/fqh21w+E+SKnCkR+Glx Yn+mWTv6ueiYMhRyTq0eV8W2FzfV8LRlHIHjpIme+M10xhg0VNXGI4pzVRrSFoxW RPVSQzBHLvcHIt42Cy35oWBoHuwhgkODlX04xKUX9OZtahXpIls0/Ft08EYYOWMv u/2Ela6f1V/umW43LgcLa1rQwn242bUY9v8uDn/E+xIZnmoAnmT534Rrz8MhdRi4 VAn87Pze5ZrUsxLx1mXBnRCyrS/1QLk0kKoEYYju+tA7kLp5zekm1wmJJ9I6EpW5 eRWf2+LHKRqKiueLEH8A3tse9+Ypbq6g8PgWrwz7Rf5dL9dXVLIliURyuirm3A/n jMNN0wKuv0kMdmqhlbCU/7+n9ycBleTx0hVO7O5KiT6grQkWZcDrIQV4efWGw+ca y6ckfHaFsxd1ReGZiMfcly4ILhZC3BoiWYyXioJhm5bnJvT6eIoPzLICZWBz0iwX PCsu/n69kuxkKVyHsCJLxPNcO/RvJARPSDJU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF7DCCA9SgAwIBAgIQeFyaRqCtyDXTuZngovv6QjANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTcwOTA4 MDAwMDAwWhcNMjcwOTA4MjM1OTU5WjBuMQswCQYDVQQGEwJHQjEPMA0GA1UECBMG TG9uZG9uMRAwDgYDVQQHEwdDcm95ZG9uMR8wHQYDVQQKExZUaGUgVHJ1c3RpY28g R3JvdXAgTHRkMRswGQYDVQQDExJUcnVzdGljbyBSU0EgT1YgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJujZ0PBovqARYCWjRtqej2Fq02KjOw/ro W52YJgxfpKkxHIV5QB9s72mCM7GZJlN8AlmFl5OmDFj9WLhiTVXG2blTM51k8zXC 4L7i2xGjB/i3MOtCOfp2EQ0iN5lId5JtOaom8RVO/wSsZ9O+IS1opOCtaBr+q/K2 77GZA67QHgjZuLcy6P+ksiGqJRPIxh+IvkD8jURYk3ZN9sXOwKFC2hFXT6/3FJJt NmFhWGupvHQDCRkIoV9YbEZIIwXsh5Eqpx/oKMmGcjlxhuQOpGmGTU46JQUpghr0 Y2zHOloLUsiWZOqpq3mPNQ7DUMTUuqKZimn8OFaO4UZU5y3rRog7AgMBAAGjggFs MIIBaDAfBgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs2TIy1DAdBgNVHQ4EFgQU mApc1MXlVCnAZQRHuiJW0dwwPDQwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQI MAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQb MBkwDQYLKwYBBAGyMQECAjowCAYGZ4EMAQICMEwGA1UdHwRFMEMwQaA/oD2GO2h0 dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JTQUNlcnRpZmljYXRpb25BdXRo b3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA7BggrBgEFBQcwAoYvaHR0cDovL2Ny dC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQWRkVHJ1c3RDQS5jcnQwJAYIKwYBBQUH MAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEA cn00ZPrP4EfYBIwiA+sZKSgGlVbgodL3IyFVztKY+oi+AkV4Er6HR5rL3vHK4hzE PibvKwH2/03oHLjDFd6QL3WI/EfyPsnwEveFc8Ks0OUqzaYHTmPBLGUsPsDirrKX SGCA28dpEEaBQ0uyzsHPUsoUDF6Vt8M2WSCf7jZcv+HghUJfHGWz1eMOIILqZk3N 1Iuw1MTXhg2CK8RjTh5vO9cj6CVRFmL37/9A4rk+K+ycxRvQsl6lMlZM94Pm6j8i eVuCTNgCzTXz9hTK4NIUiinL/BYCVXRk2l+wKsu05OX3ka34ZS2dN0m/8o8McG7W Y4SykDZXKaPifJdIkTKNh3HdfSKYMo+lXza7UU9zKYXgP/bd4wv4ikGFdrC8C5vY PDmiAMtR4V6nSa8cNA897JSnbUu5S3Gn6Io8KMG/ztrsVaFkL94834X2Bu2HwF56 MYlwugBr462vQ7nAAh2LCmrvo6sJT4rpUqHaZWVTQHJAG9EMUqzKmKp3kGj+2l20 oQKOKSFYAbFGlFv0DIP5sjSpejmDWVDGPXuZoe2iLw0V02dcsY7wgt/LSZjC7wt3 YI3FphhLNZ8UybwZJnuEz04fZc2jQRifis9gXXOiaFrQOr77wVDCCJJO9NK93p7K UqUZuvWyFIqimH831D7pQD6AfXf6hIM7zsxjLgXTCMc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEsDCCBFagAwIBAgINAJ1tPv915g//LKEGCjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTcwOTE3MjEwMDAwWhcNNDIwODIyMDkwMDAwWjCBgzEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMRcwFQYDVQRhDA5WQVRIVS0yMzU4NDQ5NzEwMC4GA1UEAwwnZS1Temln bm8gUXVhbGlmaWVkIE9yZ2FuaXphdGlvbiBDQSAyMDE3MFkwEwYHKoZIzj0CAQYI KoZIzj0DAQcDQgAEIuIIRyz1yEaN+jDybgIydL8DJNHtFeL9g14X1F0JWBu+mGmt xxRTV4HIQ/gh0ciuIqM2LNe9wivgUM857jqkCaOCAr4wggK6MA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgEGMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsG AQUFBwIBFhpodHRwOi8vY3AuZS1zemlnbm8uaHUvYWNwczAdBgNVHQ4EFgQUg3kC uHEVeH8K3W+apTjWnno37qUwHwYDVR0jBBgwFoAUhxEVCNGqwXgMsa/OxsmQ778w BMAwgbYGA1UdHwSBrjCBqzA3oDWgM4YxaHR0cDovL3Jvb3RjYTIwMTctY3JsMS5l LXN6aWduby5odS9yb290Y2EyMDE3LmNybDA3oDWgM4YxaHR0cDovL3Jvb3RjYTIw MTctY3JsMi5lLXN6aWduby5odS9yb290Y2EyMDE3LmNybDA3oDWgM4YxaHR0cDov L3Jvb3RjYTIwMTctY3JsMy5lLXN6aWduby5odS9yb290Y2EyMDE3LmNybDCCAV8G CCsGAQUFBwEBBIIBUTCCAU0wLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3 LW9jc3AxLmUtc3ppZ25vLmh1MC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAx Ny1vY3NwMi5lLXN6aWduby5odTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIw MTctb2NzcDMuZS1zemlnbm8uaHUwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2Ey MDE3LWNhMS5lLXN6aWduby5odS9yb290Y2EyMDE3LmNydDA8BggrBgEFBQcwAoYw aHR0cDovL3Jvb3RjYTIwMTctY2EyLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3J0 MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAxNy1jYTMuZS1zemlnbm8uaHUv cm9vdGNhMjAxNy5jcnQwCgYIKoZIzj0EAwIDSAAwRQIhAKYoloLSQEP4qVWWJpnM Cx/x7r3PmuRrFHt0gZz8aKz6AiAKTvab447X3TVaZHAOeM6zuMDu9I8f0zMLOXLK Hh3T1Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEsDCCBFagAwIBAgINAJ8dVmIgseQU+5E9CjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTcwOTE3MjEwMDAwWhcNNDIwODIyMDkwMDAwWjCBgzEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMRcwFQYDVQRhDA5WQVRIVS0yMzU4NDQ5NzEwMC4GA1UEAwwnZS1Temln bm8gUXVhbGlmaWVkIFBzZXVkb255bW91cyBDQSAyMDE3MFkwEwYHKoZIzj0CAQYI KoZIzj0DAQcDQgAELd33IkIm1fD5GcMIN2Mw+6hmxMzOMmok+t4NXyXHReqgs+Cv P+LBKqX8ppZ0N5FigJ8PIAm/pM/MWbyw8l4sSKOCAr4wggK6MA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgEGMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsG AQUFBwIBFhpodHRwOi8vY3AuZS1zemlnbm8uaHUvYWNwczAdBgNVHQ4EFgQUGdiP NUL0WS7kQ1SP7yP99Tmj6vEwHwYDVR0jBBgwFoAUhxEVCNGqwXgMsa/OxsmQ778w BMAwgbYGA1UdHwSBrjCBqzA3oDWgM4YxaHR0cDovL3Jvb3RjYTIwMTctY3JsMS5l LXN6aWduby5odS9yb290Y2EyMDE3LmNybDA3oDWgM4YxaHR0cDovL3Jvb3RjYTIw MTctY3JsMi5lLXN6aWduby5odS9yb290Y2EyMDE3LmNybDA3oDWgM4YxaHR0cDov L3Jvb3RjYTIwMTctY3JsMy5lLXN6aWduby5odS9yb290Y2EyMDE3LmNybDCCAV8G CCsGAQUFBwEBBIIBUTCCAU0wLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3 LW9jc3AxLmUtc3ppZ25vLmh1MC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAx Ny1vY3NwMi5lLXN6aWduby5odTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIw MTctb2NzcDMuZS1zemlnbm8uaHUwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2Ey MDE3LWNhMS5lLXN6aWduby5odS9yb290Y2EyMDE3LmNydDA8BggrBgEFBQcwAoYw aHR0cDovL3Jvb3RjYTIwMTctY2EyLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3J0 MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAxNy1jYTMuZS1zemlnbm8uaHUv cm9vdGNhMjAxNy5jcnQwCgYIKoZIzj0EAwIDSAAwRQIhAPTj0/aBtD2vlslkkjWh zMbk3dER06+QXZuc5DVD3/yTAiApd5ZWWnePLWYo+fPHR+JNvYaSuzCU8ImldHZd pPmRtg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCBEmgAwIBAgINAKbpTQSzvKLcGtadCjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTcwOTE3MjEwMDAwWhcNNDIwODIyMDkwMDAwWjB3MQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MSQwIgYDVQQDDBtlLVN6aWdu byBDbGFzczIgU1NMIENBIDIwMTcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASe fnt2xrEmQD/M4zSDuT+IqoyC2hAAQGZpvORTxTNxmUg2UAZkygJuZbl0LmsAFL6R 5Mx0z+Ac84riTTz+3W6co4ICvjCCArowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B Af8EBAMCAQYwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6 Ly9jcC5lLXN6aWduby5odS9hY3BzMB0GA1UdDgQWBBTfOWgtjqTTNOXFLxoBeMTD FtslKzAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDCBtgYDVR0fBIGu MIGrMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1jcmwxLmUtc3ppZ25vLmh1L3Jv b3RjYTIwMTcuY3JsMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1jcmwyLmUtc3pp Z25vLmh1L3Jvb3RjYTIwMTcuY3JsMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1j cmwzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3JsMIIBXwYIKwYBBQUHAQEEggFR MIIBTTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMTctb2NzcDEuZS1zemln bm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3LW9jc3AyLmUtc3pp Z25vLmh1MC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAxNy1vY3NwMy5lLXN6 aWduby5odTA8BggrBgEFBQcwAoYwaHR0cDovL3Jvb3RjYTIwMTctY2ExLmUtc3pp Z25vLmh1L3Jvb3RjYTIwMTcuY3J0MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNh MjAxNy1jYTIuZS1zemlnbm8uaHUvcm9vdGNhMjAxNy5jcnQwPAYIKwYBBQUHMAKG MGh0dHA6Ly9yb290Y2EyMDE3LWNhMy5lLXN6aWduby5odS9yb290Y2EyMDE3LmNy dDAKBggqhkjOPQQDAgNHADBEAiBpTP2hrUdw6wUaFKam/nScFsNPR09o/3tpUaar pLoyhQIgTmEWFEUFD3iK6i9/7RWaHwGQooZ42Du59Co4jFKZ9AE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEnzCCBEWgAwIBAgINAKFaIuncA1vv6P2ZCjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTcwOTE3MjEwMDAwWhcNNDIwODIyMDkwMDAwWjBzMQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MSAwHgYDVQQDDBdlLVN6aWdu byBDbGFzczIgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCAJGh/U Ss0co1ZUidrjWSGiCFq/fj4W5sPhiO5qhLgVG0/Aoyr51CG0d+JaIybhZmTvJp3p 9Sp8crRV2e9KfoKjggK+MIICujAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nw LmUtc3ppZ25vLmh1L2FjcHMwHQYDVR0OBBYEFDP8BGn8ZbNpQ1LxF/6v0cREgHGI MB8GA1UdIwQYMBaAFIcRFQjRqsF4DLGvzsbJkO+/MATAMIG2BgNVHR8Ega4wgasw N6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNybDEuZS1zemlnbm8uaHUvcm9vdGNh MjAxNy5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNybDIuZS1zemlnbm8u aHUvcm9vdGNhMjAxNy5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNybDMu ZS1zemlnbm8uaHUvcm9vdGNhMjAxNy5jcmwwggFfBggrBgEFBQcBAQSCAVEwggFN MC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAxNy1vY3NwMS5lLXN6aWduby5o dTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMTctb2NzcDIuZS1zemlnbm8u aHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3LW9jc3AzLmUtc3ppZ25v Lmh1MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAxNy1jYTEuZS1zemlnbm8u aHUvcm9vdGNhMjAxNy5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2EyMDE3 LWNhMi5lLXN6aWduby5odS9yb290Y2EyMDE3LmNydDA8BggrBgEFBQcwAoYwaHR0 cDovL3Jvb3RjYTIwMTctY2EzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3J0MAoG CCqGSM49BAMCA0gAMEUCIQCVLi6Lg6Ct9DmIj166E2QZO3gdNUYdH/6WBIxXNzNo OQIgZ6yV4Z3a4T44CCtr3pkuEOmshXhrxCVM8Rq8ds1Ij+0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEnzCCBEWgAwIBAgINAKKmkr+OWWtWAuqLCjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTcwOTE3MjEwMDAwWhcNNDIwODIyMDkwMDAwWjBzMQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MSAwHgYDVQQDDBdlLVN6aWdu byBDbGFzczMgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDSXXF3C 7MHWjHPbCW8TGODxajoiDPPhTi8/OSCivIYN7hEkV7ocLTcjUdvDNdNzNXYq62OK IyQbCz2/pwivkFGjggK+MIICujAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nw LmUtc3ppZ25vLmh1L2FjcHMwHQYDVR0OBBYEFKRrPOS+dzzFY+q2ownfK63QRQaI MB8GA1UdIwQYMBaAFIcRFQjRqsF4DLGvzsbJkO+/MATAMIG2BgNVHR8Ega4wgasw N6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNybDEuZS1zemlnbm8uaHUvcm9vdGNh MjAxNy5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNybDIuZS1zemlnbm8u aHUvcm9vdGNhMjAxNy5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNybDMu ZS1zemlnbm8uaHUvcm9vdGNhMjAxNy5jcmwwggFfBggrBgEFBQcBAQSCAVEwggFN MC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAxNy1vY3NwMS5lLXN6aWduby5o dTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMTctb2NzcDIuZS1zemlnbm8u aHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3LW9jc3AzLmUtc3ppZ25v Lmh1MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAxNy1jYTEuZS1zemlnbm8u aHUvcm9vdGNhMjAxNy5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2EyMDE3 LWNhMi5lLXN6aWduby5odS9yb290Y2EyMDE3LmNydDA8BggrBgEFBQcwAoYwaHR0 cDovL3Jvb3RjYTIwMTctY2EzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3J0MAoG CCqGSM49BAMCA0gAMEUCIQC8MRsVpik+qzWhJ34e55wRcfkN+X9xsXNSSbpEftSu kwIgMoSvKh28gOHlgaKHwwnPG9MYRzhLWXlisAQ4B12Ij/4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCBEigAwIBAgINAJxoCVhJ4IvqtEfvCjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTcwOTE3MjEwMDAwWhcNNDIwODIyMDkwMDAwWjB2MQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MSMwIQYDVQQDDBplLVN6aWdu byBRdWFsaWZpZWQgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBt3 AUl32FU6leFbtdsmqRhtnr5LSy+g92MgIEJ+lCsqotcfU5cZLMPldeSjgA8hJzeb jStBITy6MDIfeJZal0GjggK+MIICujAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB /wQEAwIBBjA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDov L2NwLmUtc3ppZ25vLmh1L2FjcHMwHQYDVR0OBBYEFMYT+zydtLauL8bef5VP8x6p 08b5MB8GA1UdIwQYMBaAFIcRFQjRqsF4DLGvzsbJkO+/MATAMIG2BgNVHR8Ega4w gaswN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNybDEuZS1zemlnbm8uaHUvcm9v dGNhMjAxNy5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNybDIuZS1zemln bm8uaHUvcm9vdGNhMjAxNy5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNy bDMuZS1zemlnbm8uaHUvcm9vdGNhMjAxNy5jcmwwggFfBggrBgEFBQcBAQSCAVEw ggFNMC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAxNy1vY3NwMS5lLXN6aWdu by5odTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMTctb2NzcDIuZS1zemln bm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3LW9jc3AzLmUtc3pp Z25vLmh1MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAxNy1jYTEuZS1zemln bm8uaHUvcm9vdGNhMjAxNy5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2Ey MDE3LWNhMi5lLXN6aWduby5odS9yb290Y2EyMDE3LmNydDA8BggrBgEFBQcwAoYw aHR0cDovL3Jvb3RjYTIwMTctY2EzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3J0 MAoGCCqGSM49BAMCA0gAMEUCIQCFadTwtoGjDi8TcT0wqbuSviFaE7oC3iMQKq2R E/fHkQIgNbsqwa96nrL3hElurUmULqMC5E2oXdaXrkdaXW+M944= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpzCCBEygAwIBAgINAJ4sXrlZ/XdM3YZqCjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTcwOTE3MjEwMDAwWhcNNDIwODIyMDkwMDAwWjB6MQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MScwJQYDVQQDDB5lLVN6aWdu byBRdWFsaWZpZWQgUUNQIENBIDIwMTcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC AASkLCREhsR4UUgppCQtg+HjcUjwsdK/j8s46Lq+vV80F5gmTxklJWLGA1ctRNFF SXpL+TWseaI7HJ6iRCnUz0qzo4ICvjCCArowDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAQYwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0 dHA6Ly9jcC5lLXN6aWduby5odS9hY3BzMB0GA1UdDgQWBBQH9izCA0NfdmcXt6SB h5rMRTB93jAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDCBtgYDVR0f BIGuMIGrMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1jcmwxLmUtc3ppZ25vLmh1 L3Jvb3RjYTIwMTcuY3JsMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1jcmwyLmUt c3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3JsMDegNaAzhjFodHRwOi8vcm9vdGNhMjAx Ny1jcmwzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3JsMIIBXwYIKwYBBQUHAQEE ggFRMIIBTTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMTctb2NzcDEuZS1z emlnbm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3LW9jc3AyLmUt c3ppZ25vLmh1MC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAxNy1vY3NwMy5l LXN6aWduby5odTA8BggrBgEFBQcwAoYwaHR0cDovL3Jvb3RjYTIwMTctY2ExLmUt c3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3J0MDwGCCsGAQUFBzAChjBodHRwOi8vcm9v dGNhMjAxNy1jYTIuZS1zemlnbm8uaHUvcm9vdGNhMjAxNy5jcnQwPAYIKwYBBQUH MAKGMGh0dHA6Ly9yb290Y2EyMDE3LWNhMy5lLXN6aWduby5odS9yb290Y2EyMDE3 LmNydDAKBggqhkjOPQQDAgNJADBGAiEA3U9F2Hi0oY7uCbLoUv6RA9pQCiqEfz75 ad2K33FAeKsCIQDF/7RMDBvY9IsXvPYJR9Bm/4wGFRE+cNElXL55j/uXnw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpDCCBEugAwIBAgINAKimIH4HXOeNkjr3CjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTcwOTE3MjEwMDAwWhcNNDIwODIyMDkwMDAwWjB5MQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MSYwJAYDVQQDDB1lLVN6aWdu byBQc2V1ZG9ueW1vdXMgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA BNxhGPPumC3jvmsBBM8Dbf1ebLPcksNdl0JSUCIePPdKNIKkTUeNhW0qSXAdnsTk DsTBLQrNDbJge5KOL0BIOwSjggK+MIICujAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBBjA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0 cDovL2NwLmUtc3ppZ25vLmh1L2FjcHMwHQYDVR0OBBYEFI639mkaEMCaiEIxBDZQ TB8SbBQqMB8GA1UdIwQYMBaAFIcRFQjRqsF4DLGvzsbJkO+/MATAMIG2BgNVHR8E ga4wgaswN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNybDEuZS1zemlnbm8uaHUv cm9vdGNhMjAxNy5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3LWNybDIuZS1z emlnbm8uaHUvcm9vdGNhMjAxNy5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDE3 LWNybDMuZS1zemlnbm8uaHUvcm9vdGNhMjAxNy5jcmwwggFfBggrBgEFBQcBAQSC AVEwggFNMC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAxNy1vY3NwMS5lLXN6 aWduby5odTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMTctb2NzcDIuZS1z emlnbm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3LW9jc3AzLmUt c3ppZ25vLmh1MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNhMjAxNy1jYTEuZS1z emlnbm8uaHUvcm9vdGNhMjAxNy5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290 Y2EyMDE3LWNhMi5lLXN6aWduby5odS9yb290Y2EyMDE3LmNydDA8BggrBgEFBQcw AoYwaHR0cDovL3Jvb3RjYTIwMTctY2EzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcu Y3J0MAoGCCqGSM49BAMCA0cAMEQCIF+gFmZF22F6Ml0mo3AlS4UkOSyedR1mswao wwf8YuJqAiAQOfYQcWlKsyGvIGAzCa53ukqQYs8wpUc8AzMsJVHRtw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCBEmgAwIBAgINAKeZ6aG58ZBbm4zmCjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTcwOTE3MjEwMDAwWhcNNDIwODIyMDkwMDAwWjB3MQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MSQwIgYDVQQDDBtlLVN6aWdu byBPbmxpbmUgU1NMIENBIDIwMTcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQJ 1qga+lYlSy1gfiq/9HyOsioA+w7z88DQk/QKsrBHiEsT5eslU5Bl2e+3A9uxXVZs GlVMc6zz5V4O6PmSYgf4o4ICvjCCArowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B Af8EBAMCAQYwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6 Ly9jcC5lLXN6aWduby5odS9hY3BzMB0GA1UdDgQWBBQVb5jhJ9vIuZCXHZJtm2If Yj2kOTAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDCBtgYDVR0fBIGu MIGrMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1jcmwxLmUtc3ppZ25vLmh1L3Jv b3RjYTIwMTcuY3JsMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1jcmwyLmUtc3pp Z25vLmh1L3Jvb3RjYTIwMTcuY3JsMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1j cmwzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3JsMIIBXwYIKwYBBQUHAQEEggFR MIIBTTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMTctb2NzcDEuZS1zemln bm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3LW9jc3AyLmUtc3pp Z25vLmh1MC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAxNy1vY3NwMy5lLXN6 aWduby5odTA8BggrBgEFBQcwAoYwaHR0cDovL3Jvb3RjYTIwMTctY2ExLmUtc3pp Z25vLmh1L3Jvb3RjYTIwMTcuY3J0MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNh MjAxNy1jYTIuZS1zemlnbm8uaHUvcm9vdGNhMjAxNy5jcnQwPAYIKwYBBQUHMAKG MGh0dHA6Ly9yb290Y2EyMDE3LWNhMy5lLXN6aWduby5odS9yb290Y2EyMDE3LmNy dDAKBggqhkjOPQQDAgNHADBEAiB6udqEIv8fhy8Lj17/RiRcTJurpx9He4ZqUuAr oRNY8gIgNWJ6shyKD2OPz4riZc99Xcs8uWDKdrJqCrpE/UA6xho= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpDCCBEmgAwIBAgINAKPxyZ1SVp2NmS5MCjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTcwOTE3MjEwMDAwWhcNNDIwODIyMDkwMDAwWjB3MQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MSQwIgYDVQQDDBtlLVN6aWdu byBDbGFzczMgU1NMIENBIDIwMTcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASt b9h8yBr4lF4CCD1Xl8tlJEReTfLNHTQ/KfIwWxg2eX2XQOcU6urnTbo0U1lYtm6e WUkIGIGWLFNgPQc8jWf3o4ICvjCCArowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B Af8EBAMCAQYwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6 Ly9jcC5lLXN6aWduby5odS9hY3BzMB0GA1UdDgQWBBSKpTW4ktWmvPnOgeqnlhx7 3iDn4DAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDCBtgYDVR0fBIGu MIGrMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1jcmwxLmUtc3ppZ25vLmh1L3Jv b3RjYTIwMTcuY3JsMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1jcmwyLmUtc3pp Z25vLmh1L3Jvb3RjYTIwMTcuY3JsMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1j cmwzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3JsMIIBXwYIKwYBBQUHAQEEggFR MIIBTTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMTctb2NzcDEuZS1zemln bm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3LW9jc3AyLmUtc3pp Z25vLmh1MC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAxNy1vY3NwMy5lLXN6 aWduby5odTA8BggrBgEFBQcwAoYwaHR0cDovL3Jvb3RjYTIwMTctY2ExLmUtc3pp Z25vLmh1L3Jvb3RjYTIwMTcuY3J0MDwGCCsGAQUFBzAChjBodHRwOi8vcm9vdGNh MjAxNy1jYTIuZS1zemlnbm8uaHUvcm9vdGNhMjAxNy5jcnQwPAYIKwYBBQUHMAKG MGh0dHA6Ly9yb290Y2EyMDE3LWNhMy5lLXN6aWduby5odS9yb290Y2EyMDE3LmNy dDAKBggqhkjOPQQDAgNJADBGAiEAx/iA2F8RvKlWsXCy8cPV2WKs+wtMmzTYExMP JThwvVcCIQCAsH68XelsytoCfYrmGDIAmfK4jLSTsiFm7cCX4I4Lrw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFuDCCA6CgAwIBAgIQLZrQ4529La6DX0Rvu2T9KDANBgkqhkiG9w0BAQsFADB2 MQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd BgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxJzAlBgNVBAMTHlN5bWFudGVj IFdlYiBQS0kgUlNBIFJvb3QgLSBHMTAeFw0xNzA5MjEwMDAwMDBaFw00MjA5MjAy MzU5NTlaMHYxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh dGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEnMCUGA1UEAxMe U3ltYW50ZWMgV2ViIFBLSSBSU0EgUm9vdCAtIEcxMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAxBgbleGJpbLe/M8836WNu0w2YTgGUk6bo9IP+7BNpXbA SqYwm/wvg/LMoy9dT1j7NFIq9gQ7WMoORvMI97FqhK2qxQmoZ0fRJMCPIYGNlD4/ jaEzDDHHSZyytjlor0na0FVlKs4JbR7gIyVe+c0+ZC+Aw63Hi7I7cbo6lAZ5wUX4 Fn2waaI7/eIT6L8QPvt4+h8OGyoRsHUSLagAhqiVZYkXegb6izLZSouDpy0O1/QB +4jrQxFm6EGkkF3KOrD5YLROy85r8+yy95/WyzmM3TuuvFolW83sMiLoSFWA3udY ipDw8TBGLp9+O1JtgoDUZV2H5NsIZ781uWXsOiSfxOLZYcJGXOdqgG4QCVoAHC3F xnEnJ1tVYrIv0lNTq3Sc0fIbtUitXyykyM5Xd6wzYsInd9Mcvtuf/ukthB5bHZh0 LZrcwpHZchJ0qihIwLGXkzzmKjeUf/QrI7MNfC1QcWR2sPV1+oNCvBrpMxrtzh2a X2yioUOfEi0pRVFK5q4Nb0YV9lMHX41eK49fFwu9wqPpy3lqEjD+o21u93ZINuVh 3jt0W4DP5vZQn2WixtVUXMkBbEZ1OoUBOzetC0YaGfiJ/hbbfQideO6ZMS/EtD1J AsUAPMWf87fiRRppu3eB9rJSAa07gXs7TiyAJlcBRL3yoPuVTFFNMRIBRnsBRlcC AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFFykSk0SoSakEIUoYa4CEoHZ6nd7MA0GCSqGSIb3DQEBCwUAA4ICAQA8YcyA VniGkCIGcBlgNosktHgYlMlkKxaPoiGyqgj0r/6UIOkAblSZMnDY2g3rTjGCrahc n5qV+FxRfN9o2tPDJB8cV364vXXNiND0M50Utt4I39xP2+RSW/JhQOjxsHvGv2NN ++6K6HfkaJk5yYHMO6K0gZIpgKhOlLDvVQOBXwKdOxRV0sSMaJ3n8cWlYshoafbJ 9Osnocbnl0oorDnovy9FYCywa5PYuO52GBxURDHTDkh3nsXeWrs3I0PtUVYuKHcg mpuzRWY7rjkMbV+VHi0INp5ok4MvpHJUm+Y822AJ9X5iIJUVjt+zU8NnSnUaL1cS JmB6V/r/e/hfXOsmpUiHutHiHCO7+ir1SHscaR0Ks0sOBsM3wExczJt8aPDiL2LA e4k4Hc8mpJffMPepv+h78GitL9ms2cxtYN3KFCPpnT//uT5jQCmio9k07KB9Sy3u bDYnrqA1w47vUmMunZvUAhq8Twca+p5SMos68eLaUtGiR2LHSVIMJx/6XiFzPeXE DMTxCVqnMIsie5ea9mkB5XT7urIZRBMSDVe8VbLqeHBixv8n6LCYqfoHZ6qXn9wA fS03yuaCHBo73HxbI+nW9l7qG6Ca0+8T6I0kWTeekzB123S/KgZJ7t5U71OkBCRv XBmPp6b0QQ+l9ltr75G4XZarNBrtZPgZhZAZ3A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtDCCA5ygAwIBAgIRAPFcwJwtzGECCLgOowVyQ6kwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xNzEwMjMw NzE2NDRaFw0yNzA1MTQwNzE2NDRaMFYxCzAJBgNVBAYTAkNOMSQwIgYDVQQKDBtU cnVzdEFzaWEgVGVjaG5vbG9naWVzIEluYy4xITAfBgNVBAMMGFRydXN0QXNpYSBE ViBTU0wgQ0EgLSBDMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO6i OtJJcAdBTP8kqisZXwVvBbenSIOTSLcfpaeuWSD8aaAPJS26U2L8Boo2yQMq+bKI mue2rbRfdhKoB3N8UqkbUOKFYyH10ty6IcusOskqIpKanho+8+91YnXYkd997mkg tr9wkBKUWE1EIeVBFI2f335txIGl0rEL6ogL57mfMwS7sSyE0pk4WhDa1zLkhVgb 4916MLb6v4eIamcv0xTdWS8sHGRIt8bjspuV+76+m+1lubvpzEJ9pmgtRYkHzL+b SpvPe96x4aW8TZE/v2+AHRaetiSmLA79ojgFkq62oHUMPIR/w+RuWrPY6+NWmMAR lAmVY3ztmGZxjkiJYc8CAwEAAaOCAU0wggFJMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0OBBYEFBHvA1BNJoEcesfb368b7cAmBNZIMB8GA1UdIwQYMBaAFFSZ3Zv/ 6KcOoxmdW75CV98w/I8yMA4GA1UdDwEB/wQEAwIBBjA4BgNVHR8EMTAvMC2gK6Ap hidodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9nc2Nhc2hhMi5jcmwwbgYIKwYB BQUHAQEEYjBgMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0u Y29tMDQGCCsGAQUFBzAChihodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvZ3Nj YXNoYTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBACNvgM8cibla jzBhUhlNRA2ozF6+ZIZklQQNMkCSf4TT2hkEdgBmbUofS/aKkA58v6JvF0kBHmzB 47DGorMkgUISFsA3a3eHub9jKO1hQSVC8JTcPT6z7FgeocQyNPTrRKG+4m752aXT O1Mne70OUxcDTpgtkIgg9a6hTuA3Z9j283U7MQveq1tAUuf3nNrPL0I5CkVu/AHY ij/2Kf1zzHC5MfkeyWW9ff3BKD4+nWRbvmHdAlN7wKka5Efx5BoGfbySmTALPRs6 OKL/R6ty0FC9kfEsIJ+/wWaOZcGY8RQCGXJXZpN3Pg2Ia2qxBmlKXSO6s/uegLrs T6PF3T2wvMw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEszCCA5ugAwIBAgIQMJ6XtszYZyhC+iBZWSkgqDANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE3MTAyMzA3 MjAxNFoXDTI3MDUxNDA3MjAxNFowVjELMAkGA1UEBhMCQ04xJDAiBgNVBAoMG1Ry dXN0QXNpYSBUZWNobm9sb2dpZXMgSW5jLjEhMB8GA1UEAwwYVHJ1c3RBc2lhIE9W IFNTTCBDQSAtIEMzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2AHi qiuGv2g9YAJPiD8whhvGnF56uTPsYMREWjXveFFxFI74YAUzmyq+XvI9/7S7B8SI a3Sp/BcPB4r4AQVyLVwWTOM24nrVhIu5ZmUnHDbHRFD7qbuB/hYlu5AElGIK7rD0 dZp9A2Q4Lzv1eoBJR6MDqGO2ocfhwA/XezbIO8wWs2YGVXc0+FMs/vR0laRyb0Cl S0lUJrG1gIZSx18aMOUFACSiB+4/9C2jkHG5L0hz0FaU+BFLQclCliVvTWHgFO2k /+b23HjR9pqvbyjv0GAcFArHqLED7dWAh3fEBehzCkrTz1HCl+xhmjj2TDnHKuBt 1uCU8iUdYY0frDnuVQIDAQABo4IBTTCCAUkwEgYDVR0TAQH/BAgwBgEB/wIBADAd BgNVHQ4EFgQUhmenbIBkMiH1IFz9AgzX3h2HmGIwHwYDVR0jBBgwFoAUVJndm//o pw6jGZ1bvkJX3zD8jzIwDgYDVR0PAQH/BAQDAgEGMDgGA1UdHwQxMC8wLaAroCmG J2h0dHA6Ly9zdWJjYS5jcmwuY2VydHVtLnBsL2dzY2FzaGEyLmNybDBuBggrBgEF BQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5j b20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9nc2Nh c2hhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6 Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEApBKZ1NcNEVmK zEJCbpMnQeU2DnoVcNrm5ORH47umuq45FhfJjF/siKhY+YEUF8GEYdE2ny2NWcP0 WbOPV+QfpC7WJkNXJPUej3Kukr3i17YUo+inO7mD/i6sg1CLUB4AS30oB4FOIj7c I0aH9D2Jb2e0miXGBZa/BVZUujd6HIfY7Ga86FO+U4fzW+kBNsAZIVelw9X4K38N VmxNaxPXm4ThqxqHnSnw/zdMmvpPhSJo8761NJf8DQDFmLBz2sKlyCibRsX6hKAR 0Sq7qMVWWingBILWrhbKiyLFdF7XoFXuosyLGcFq/ks28NPGzzi6jwHNxrJ46IqY wUy0NiasOQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEszCCA5ugAwIBAgIQF4ZmqFVKzL/nNFfmRRpobDANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE3MTAyMzA3 MjIzNloXDTI3MDUxNDA3MjIzNlowVjELMAkGA1UEBhMCQ04xJDAiBgNVBAoMG1Ry dXN0QXNpYSBUZWNobm9sb2dpZXMgSW5jLjEhMB8GA1UEAwwYVHJ1c3RBc2lhIEVW IFNTTCBDQSAtIEMzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp8q0 4UjkDDb3qdo6V3vFc+d01YpayZXQ+xgy0y6eToNUdesISCL/ueFhU1mYzH+27yy+ pgYPL6tQXFNGjPnTF9MFOH0L4d+OJIx/DT8yWAGD2rAzryJc4ALOkM8iaGNYIiLZ Ntpt5IkpkKs+VOP9/HbHlBUeTKMct010VNMc0/Sf8tlULZxYveoOHxkgzqUvVB49 Ad4Jfmy3QKn5x9+rPOMuhfg8+FhPVDaUtDOa/+jj9py6fmzxFAxBh9zVKiZvzYeN cOINr2Mp5/idTQf95H4gF+wBiz6wR40p7NZHGomzQ6mONVWUnOLSBoDobbOmo5jI VOKQL86W4V5cv1y+BwIDAQABo4IBTTCCAUkwEgYDVR0TAQH/BAgwBgEB/wIBADAd BgNVHQ4EFgQUYRZtmcVC9JMBmQfOkad+xqxM/DMwHwYDVR0jBBgwFoAUVJndm//o pw6jGZ1bvkJX3zD8jzIwDgYDVR0PAQH/BAQDAgEGMDgGA1UdHwQxMC8wLaAroCmG J2h0dHA6Ly9zdWJjYS5jcmwuY2VydHVtLnBsL2dzY2FzaGEyLmNybDBuBggrBgEF BQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5j b20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9nc2Nh c2hhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6 Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAmliPPV5HexXt JjzfuBXFrH3SLG1/26Le2JKLk/cV6ASUmeBmJRb+paCPGKyF27wbzlOktyO1diWy 1TcnksteVlxAfTHiqkhJSh0/zgOFuk7OZyhJfQNfNjlIMim7wGRrMRcEcPrieD39 zyClkK5wANU/9FSjN4KXv5Nixqu/cdq0GwYowPN+JU9+SPht6XRyBxD+xh+d2Cmy 2tKpkyISVwh60lJVvEYjMLOappPf5f7YOZw6dMNl65RcYl3pROWrE0LJSXvhYV1T DaOLsA3kn8IZA1qJ8iuadM1omfq5xI2B+gaN0RMn9htLYz6556X+pdxK28THsHcB LWvD5TnbgA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvDCCA6SgAwIBAgIQFQmzs1LWaJtacnLzcufgKDANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE3MTAyMzA3 MjYwOFoXDTI3MDUxNDA3MjYwOFowXzELMAkGA1UEBhMCQ04xIzAhBgNVBAoMGlFp YW9LciBDb3Jwb3JhdGlvbiBMaW1pdGVkMSswKQYDVQQDDCJUcnVzdE9jZWFuIENl cnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAuu7d+ATXwddHEVHoFcR2SjIvj2KjyfiRbTkMq5inhGgiBR3GfO6543XK GQHeOvRWZ6JkghFmxlkxBll6NBiEc4GeotdZELOu5TvaBKP8/A2VLqIGNr6knEeY hAYixWDuS/FpzlOKNKzk3iAxfx0C0a7sbJByih8KQC+7OJr+pQhbh0XamaAmSL5X ZIjEBaHG6HHIsZRavq+CGZ9XBizvUyq1jhBHsIHiZqFp5Ysc3TyAFXy0fmwOoLxS Tp5r2nSol8yiOtDDt/FDLmE3II9xmA3Hqs3gBBix6Z5o7zAwZMtexhU0Dt7lsBsj SZUMJVt9XFi6UfF3HxqrB1MK3tyxKwIDAQABo4IBTTCCAUkwEgYDVR0TAQH/BAgw BgEB/wIBADAdBgNVHQ4EFgQUQ+FMxzoCryvsJ/W1cIW0gqTQsZ8wHwYDVR0jBBgw FoAUVJndm//opw6jGZ1bvkJX3zD8jzIwDgYDVR0PAQH/BAQDAgEGMDgGA1UdHwQx MC8wLaAroCmGJ2h0dHA6Ly9zdWJjYS5jcmwuY2VydHVtLnBsL2dzY2FzaGEyLmNy bDBuBggrBgEFBQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5vY3Nw LWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1 bS5wbC9nc2Nhc2hhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYIKwYBBQUH AgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEA vjmXSgFHk8JOk3qUAtuYnNztSMhyknaH/JesctUvwKeA06RfVufFuH8k99bHqjYp LrWdj9b2LvlOdl/DezY7PCzmWOLjA99oI6QusRx0VS2Ba4jcU3QsHuQKLqtyLYxA ErHBvkKHaizbW2P8I1eqjBkXF3BieL5XbHH7BEaIPamK6beNY4gBVV1NIFn2tIJr yZbOeTxe+bGE+BC/90JYEK9CtLkEIhuYmMgk+TbUSfCohTZfzdWDJorgc2BJeLuI RRLQYt2BmDdQw/+UlhfmGeUOGetgMs3CA+DsDgS4hmdeh5xcEEl53oUDX0ei3vME JySOSZQaut4nPSlkM9djHQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEjTCCA3WgAwIBAgIQDQd4KhM/xvmlcpbhMf/ReTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xNzExMDIxMjIzMzdaFw0yNzExMDIxMjIzMzdaMGAxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xHzAdBgNVBAMTFkdlb1RydXN0IFRMUyBSU0EgQ0EgRzEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQC+F+jsvikKy/65LWEx/TMkCDIuWegh1Ngwvm4Q yISgP7oU5d79eoySG3vOhC3w/3jEMuipoH1fBtp7m0tTpsYbAhch4XA7rfuD6whU gajeErLVxoiWMPkC/DnUvbgi74BJmdBiuGHQSd7LwsuXpTEGG9fYXcbTVN5SATYq DfbexbYxTMwVJWoVb6lrBEgM3gBBqiiAiy800xu1Nq07JdCIQkBsNpFtZbIZhsDS fzlGWP4wEmBQ3O67c+ZXkFr2DcrXBEtHam80Gp2SNhou2U5U7UesDL/xgLK6/0d7 6TnEVMSUVJkZ8VeZr+IUIlvoLrtjLbqugb0T3OYXW+CQU0kBAgMBAAGjggFAMIIB PDAdBgNVHQ4EFgQUlE/UXYvkpOKmgP792PkA76O+AlcwHwYDVR0jBBgwFoAUTiJU IBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEB BCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEIGA1Ud HwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEds b2JhbFJvb3RHMi5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEW HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEB AIIcBDqC6cWpyGUSXAjjAcYwsK4iiGF7KweG97i1RJz1kwZhRoo6orU1JtBYnjzB c4+/sXmnHJk3mlPyL1xuIAt9sMeC7+vreRIF5wFBC0MCN5sbHwhNN1JzKbifNeP5 ozpZdQFmkCo+neBiKR6HqIA+LMTMCMMuv2khGGuPHmtDze4GmEGZtYLyF8EQpa5Y jPuV6k2Cr/N3XxFpT3hRpt/3usU/Zb9wfKPtWpoznZ4/44c1p9rzFcZYrWkj3A+7 TNBJE0GmP2fhXhP1D/XVfIW/h0yCJGEiV9Glm/uGOa3DXHlmbAcxSyCRraG+ZBkA 7h4SeM6Y8l/7MBRpPCz6l8Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCA4qgAwIBAgIQA/7vG7W2SDSaIJUPi8aXUzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE3MTEwNjEyMjI0NloXDTI3MTEwNjEyMjI0NlowYTEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEgMB4GA1UEAxMXR2VvVHJ1c3QgRVYgUlNBIENBIDIwMTgw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMHEZtLyqMmwFteOLrh+fy Nso8PDp2wa60VzzJU50Xnh5u0J3enXoseXERhyu+M+twXDMu33luqy4AJO7yLO+y iQw83xGGHmct7nifbf7xGOpC8NLP2Pz4bq/JfW+BWHVUS2j2mfOrVUSOaFuzjr9m 08eHh0UgdvmhUgwvov6E7E8Db4+5Mf3yF2KUaNHHCSOQPmN6rw7v79PrqaSI9usc 1tbjE6aIIcDbR2ORhMIubidx+4pj4uMaf/btEeX/ykfsdgqJYfL+Kk4OmwL9vJ6W pWe93YMu0E/xCA8rgK8KU5D9RZEpzejTVhVRGI+fuddQA8U4aV6P2sCrRoS2kZxR AgMBAAGjggFJMIIBRTAdBgNVHQ4EFgQUypJnUmHervy6Iit/HIdMJftvmVgwHwYD VR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDgYDVR0PAQH/BAQDAgGGMB0G A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA MDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl cnQuY29tMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv bS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwPQYDVR0gBDYwNDAy BgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9D UFMwDQYJKoZIhvcNAQELBQADggEBAMKOez279PqxlaLhDi4xvQj5BrpidHx0sBBZ DWtCnvvAbTOsZNORGjtLkQR4IFoZZt8QiJRjPsLdwzjx5Q9xjt+Xy8YiXo8JCWqB v7eeGzmb9Vn3wMf7eH22K/M2PcpDG/AgNjzL9nbJZhpI+OHbk4ohiD/oovX9hyFG 2Ns0y80qGctffopsBzfTMxHC5TwNGWybPg6UAHgvQviitOpPlMkdPEcutSqsvEFc L2x9f7ZbFIP2Ie0EcuVNgX6jFj7EKfKFHn8apJdtGhUJZq4mablNm+3ixPkdVr5f 71aaFFvfKi824S12PbLs+k5iSr7uE3taQB2yE1umOs9OJ4X9Yvk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEsTCCA5mgAwIBAgIQCKWiRs1LXIyD1wK0u6tTSTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNzExMDYxMjIzMzNaFw0yNzExMDYxMjIzMzNaMF4xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xHTAbBgNVBAMTFFJhcGlkU1NMIFJTQSBDQSAyMDE4MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA5S2oihEo9nnpezoziDtx4WWLLCll/e0t1EYemE5n +MgP5viaHLy+VpHP+ndX5D18INIuuAV8wFq26KF5U0WNIZiQp6mLtIWjUeWDPA28 OeyhTlj9TLk2beytbtFU6ypbpWUltmvY5V8ngspC7nFRNCjpfnDED2kRyJzO8yoK MFz4J4JE8N7NA1uJwUEFMUvHLs0scLoPZkKcewIRm1RV2AxmFQxJkdf7YN9Pckki f2Xgm3b48BZn0zf0qXsSeGu84ua9gwzjzI7tbTBjayTpT+/XpWuBVv6fvarI6bik KB859OSGQuw73XXgeuFwEPHTIRoUtkzu3/EQ+LtwznkkdQIDAQABo4IBZjCCAWIw HQYDVR0OBBYEFFPKF1n8a8ADIS8aruSqqByCVtp1MB8GA1UdIwQYMBaAFAPeUDVW 0Uy7ZvCj4hsbw5eyPdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQo MCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBCBgNVHR8E OzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9i YWxSb290Q0EuY3JsMGMGA1UdIARcMFowNwYJYIZIAYb9bAECMCowKAYIKwYBBQUH AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCwYJYIZIAYb9bAEBMAgG BmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcNAQELBQADggEBAH4jx/LKNW5ZklFc YWs8Ejbm0nyzKeZC2KOVYR7P8gevKyslWm4Xo4BSzKr235FsJ4aFt6yAiv1eY0tZ /ZN18bOGSGStoEc/JE4ocIzr8P5Mg11kRYHbmgYnr1Rxeki5mSeb39DGxTpJD4kG hs5lXNoo4conUiiJwKaqH7vh2baryd8pMISag83JUqyVGc2tWPpO0329/CWq2kry qv66OSMjwulUz0dXf4OHQasR7CNfIr+4KScc6ABlQ5RDF86PGeE6kdwSQkFiB/cQ ysNyq0jEDQTkfa2pjmuWtMCNbBnhFXBYejfubIhaUbEv2FOQB3dCav+FPg5eEveX TVyMnGo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEizCCA3OgAwIBAgIQBUb+GCP34ZQdo5/OFMRhczANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNzExMDYxMjIzNDVaFw0yNzExMDYxMjIzNDVaMF4xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xHTAbBgNVBAMTFEdlb1RydXN0IFJTQSBDQSAyMDE4MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAv4rRY03hGOqHXegWPI9/tr6HFzekDPgxP59FVEAh 150Hm8oDI0q9m+2FAmM/n4W57Cjv8oYi2/hNVEHFtEJ/zzMXAQ6CkFLTxzSkwaEB 2jKgQK0fWeQz/KDDlqxobNPomXOMJhB3y7c/OTLo0lko7geG4gk7hfiqafapa59Y rXLIW4dmrgjgdPstU0Nigz2PhUwRl9we/FAwuIMIMl5cXMThdSBK66XWdS3cLX18 4ND+fHWhTkAChJrZDVouoKzzNYoq6tZaWmyOLKv23v14RyZ5eqoi6qnmcRID0/i6 U9J5nL1krPYbY7tNjzgC+PBXXcWqJVoMXcUw/iBTGWzpwwIDAQABo4IBQDCCATww HQYDVR0OBBYEFJBY/7CcdahRVHex7fKjQxY4nmzFMB8GA1UdIwQYMBaAFAPeUDVW 0Uy7ZvCj4hsbw5eyPdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQo MCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBCBgNVHR8E OzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9i YWxSb290Q0EuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxo dHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQAw 8YdVPYQI/C5earp80s3VLOO+AtpdiXft9OlWwJLwKlUtRfccKj8QW/Pp4b7h6QAl ufejwQMb455OjpIbCZVS+awY/R8pAYsXCnM09GcSVe4ivMswyoCZP/vPEn/LPRhH hdgUPk8MlD979RGoUWz7qGAwqJChi28uRds3thx+vRZZIbEyZ62No0tJPzsSGSz8 nQ//jP8BIwrzBAUH5WcBAbmvgWfrKcuv+PyGPqRcc4T55TlzrBnzAzZ3oClo9fTv O9PuiHMKrC6V6mgi0s2sa/gbXlPCD9Z24XUMxJElwIVTDuKB0Q4YMMlnpN/QChJ4 B0AFsQ+DU0NCO+f78Xf7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEiTCCA3GgAwIBAgIQAlqK7xlvfg1sIQSyGuZwKzANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNzExMDYxMjIzNTJaFw0yNzExMDYxMjIzNTJaMFwxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xGzAZBgNVBAMTElRoYXd0ZSBSU0EgQ0EgMjAxODCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMoIXuVTipccHkMvtoqnVumLhEOorJ16VYJ6FEuGty+P Up8cyrEgW2+6It2mnC142ukGCE6+E6bry7s+uQUMPkrh8DIfE071BsVHc4k+gKOL 8QEkm6OZZpJraK0NLbTNcqL0+ThaZaa0jFPBCBqE+P0u8xF1btxqMSmsDYfMk2B4 3yW6JlmRxoNSNabKnLgoGs7XHO4Uv3ZcZas4HnnpfMxJIyaiUlBm0Flh/6D+mkwM n/nojt4Ji7gVwaQITCacewbb/Yp0W1h+zWOkkS9F8Ho8lAuKfLIFqWeTn2jllWNg 2FiVX+BV75OnETt85pLYZkTgq72nj82khXhBJFTn2AMCAwEAAaOCAUAwggE8MB0G A1UdDgQWBBSjyF5lVOUweMEF6gcKalnMuf7eWjAfBgNVHSMEGDAWgBQD3lA1VtFM u2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAm MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0fBDsw OTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFs Um9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0 cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEARE2F 5d0cgozhZNWokCLfdhhl6mXSOyU3SoPamYcWfLH1CzMwD8a1+pFvwHIQfvlwXFH8 MrjB3C+jVobNbVWRrgqS3Jsa0ltRH/Ffs6ZTgP4WJYm1SNpUbgR7LWUD2F+PTvKB M/gf9eSyqP4OiJslYaa38NU1aVAxZI15o+4xX4RZMqKXIIBTG2V+oPBjQ1oPmHGA C/yWt2eThvb8/re7OpSpUdJyfGf97XeM4PiJAl6+4HQXhjwN7ZPZKrQv9Ay33Mgm YLVQA+x9HONZXx9vvy8pl9bu+NVYWKGxzGxBK0CBozmVUCeXQPJKPTZleYuNM18p U1P8Xh1CDguM+ZEoew== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQDV4OHeIxocEKHPxpzeO3fDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNzExMDYxMjI0MDNaFw0yNzExMDYxMjI0MDNaMF4xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xHTAbBgNVBAMTFFJhcGlkU1NMIEVDQyBDQSAyMDE4MFkwEwYHKoZIzj0CAQYI KoZIzj0DAQcDQgAE8vSkFSXxMMZzAR1H30FRmNzcc7/Nz9XPyJsq3ACnY4zchQwR ATY0q14ImfSpFXViI9R/rdJa/coxlAUUZ+CGg6OCAWYwggFiMB0GA1UdDgQWBBRC YLWzSU6610OoPWjn1ZokJflm0zAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OX sj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF BwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUF BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4Yx aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNy bDBjBgNVHSAEXDBaMDcGCWCGSAGG/WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczov L3d3dy5kaWdpY2VydC5jb20vQ1BTMAsGCWCGSAGG/WwBATAIBgZngQwBAgEwCAYG Z4EMAQICMA0GCSqGSIb3DQEBCwUAA4IBAQDVzlWMtXWb43Saad6ZvqgQR6rINawx yTBtZgmA6s8p1F22fQknc50IWlS7fSVIXaDP13z+eCoL60yRbFXIKaM3UdhIurd1 mtx+nwD+u9N7ePtZVhM0sjoEdLTZAkwwRN+LiiZnUR6g3xoBAwKbDpvXRDVdaR5p BFOmXQo85oFKbHk8YIpAbCX6mPViBw5DEKs7XJAkc9Bq4J5lpMMJB/9U70gHZpFI aw7PcOHiWc4UymczUtqsCm5SP0gFlPNT0hr9qcycVgE/c4Vw/CfgBKhmIcM9Hmt8 MbhFyi0muQmuK4UPx9XDkg4uEasLyx1iRiNPIBFSJur/dRGjDHDnaQUu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwDCCAqigAwIBAgIQDxwgJzseM0ItZzOBF4ndWjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNzExMDYxMjI0MDlaFw0yNzExMDYxMjI0MDlaMF4xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xHTAbBgNVBAMTFEdlb1RydXN0IEVDQyBDQSAyMDE4MFkwEwYHKoZIzj0CAQYI KoZIzj0DAQcDQgAEvqMJfrdNSTVlTAIilcyon2KL2FEfNFcX9V7DHgnP5cCk2vFW F1koDlue9TxLALBDeD/MEObw9Xe8936amo/qVqOCAUAwggE8MB0GA1UdDgQWBBTu mi5G8MLaPFzHjNakdZjeqBkKZTAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OX sj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF BwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUF BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4Yx aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNy bDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu ZGlnaWNlcnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAb+kWfrVbdvLX/OQd m190NansWxYlaLC7X+mc4iX5XR0fojsJmCxCBdYGcvaLbBHEgkAMOhAHo/Vjq+qI 91PKv9tHDY8lL9awRF6IU2eF0vTsR4vCo5KLAEBowDUWOYFI/BVCf80TF7AsLhgC 6tFw9AcTa6t413fmAvy8wKWakauKaQI5aipGlAJ/xEZTnDaTETrmAB3feRX43tIY d+XPDNk1L9LIO/WNbVfS5bUA2hN3z5O1vkaEsmbgUB0VSlIlSeAmwjg/btCOljW2 pWj7nw4k8q4N1inLJHOpaMGz7IdfYfF4tfVmTJsUgCIJs7TM3+x2ktBnlepvMLZh Q8qWaQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDvjCCAqagAwIBAgIQD2f48sica/VaGe9r5Cwz1zANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNzExMDYxMjI0MTVaFw0yNzExMDYxMjI0MTVaMFwxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xGzAZBgNVBAMTElRoYXd0ZSBFQ0MgQ0EgMjAxODBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABP+e+mF53FsjNP4frhLe//huaJSrDp8WansKmkyyzn/OqoIAqlkC hkpbBmUL9QOoO/CWvB7C5jab6COizIPdnYGjggFAMIIBPDAdBgNVHQ4EFgQUBK9P bgo2psIngg6c/rkCQkk79bkwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I9 0VUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD AjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcw AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0 dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmww PQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRp Z2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEBAIXPfJVi7DCZ58wfJYlx rOWB4avmGI+b0H3nCFucVJkAFK5bcu+gpNqlbn1HDLJCOnpubLtFf8dD8jXSQI2c d3cec09HP3qi3zLUr1JpZjBmh/WEYPUSjbnRSiq+2DlJHTBcnGIFJKQ/YfcCLjGp 8GXFH1e5wCD8UFCToFRgm1WCfTCe7Li9IJTBtUOmtj1hrslQxI99AvfmKGRFlIYb g5lsEChXK/VlOdWdiixUKbHjezE9g7SUv/OZpayY0AVTJzxxLi9akRCpXgndqZCD OY1xZ1Ut2k0Lt8y4Hwu6DX0KOYR4Qr5Dx4+vJ8bkAcIVF1GZwWoyUA1HESvRwx/g lh4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE0DCCA7igAwIBAgIQB2eo6PAkBD4mjnT5XupWKTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xNzExMTUxMjMxNTJaFw0yNzExMTUxMjMxNTJaMIGTMQswCQYDVQQGEwJV UzEeMBwGA1UECgwVV2VsbHMgRmFyZ28gJiBDb21wYW55MSMwIQYDVQQLExpPcmdh bml6YXRpb24gVmFsaWRhdGVkIFRMUzE/MD0GA1UEAxM2V2VsbHMgRmFyZ28gUHVi bGljIFRydXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IDAxIEcyMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyoN8m2F+5vays9Lek9yy/bQMXtygq8Ut JHik0kC1EAfbEZnAt2WXhv2mnpedIF9p7ECFQ7257DR/sH/tRBHeAkkhAzctyxHw bFtmfeGSNun/RUkyyypplop/rYr/IhVK5m2stDPlrkW80VXFdwNABQF4KEN+cMmC qfZUXNHeOTkod8ajAiOY0F3Shze3s0j4kXXddjqJkCiu2/9upACN1VmIEZ2Xl1M2 kVGIO2e68ZJiXFpE8KgrcNpDVmpxS9DUXr17sdWWQe/wQ5aJpJQL69aLy8vcu7mj Z/fncAQg7qqOFdOoHsNArAt6tkbGgdLu3E7WAzaMh0jMtjHEmAfJWQIDAQABo4IB TzCCAUswHQYDVR0OBBYEFDkTnuFB0jpFCziAYK+1IUF8AYl9MB8GA1UdIwQYMBaA FE4iVCAYlebjbuYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAU BggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEF BQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBC BgNVHR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNl cnRHbG9iYWxSb290RzIuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYI KwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQIC MA0GCSqGSIb3DQEBCwUAA4IBAQC6Ujs43uZubjQ93QW6tttg2VDG3ztlszR4XpQ2 gWjAi+WsD3vazX27ts2XDrO/Be/+6jCfv8O+/TN4wWvmUc8Zek70GBs10IEeu4n5 LL7OGUGvBRb3WOQYouVlKR5AZk7u86fXp7TvrtlvGuW2Ph7FIwWLHMDsPbwLrTvg 1whjlB8nC6tGi7IB2jnkfYSfk8Y1FvS3ud6r2af7ThU2UlelaISZPaqNd6nGTVD0 DDb6jmPaq/3Va4BJjBIP1GkkDSZ40BurcoMeE2D/RcHa88dPyjpBJ145otXcIOUK RyGmDsMQG1E6AWFl3HCHvwHcZtIA2f9bkUYK1HG9ek75m7KA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQIcvMOA2tLHYPX6t4Vqb7rzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODEzMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAzsw9/pnRrgbXKzxlHO7WA0w/djyY5xyJOAX9FQYRSeIK AHDlMM4C/YCVCGFHLQnms9ztE9dYUvDeovSNjx1FF9TA9NPahLzOJ3ptGVy/rTJS OEknippKdAuhjDHV6UO7g8QkdbOsNSIRznIhqyETBMeEGBZyA3TlCj/BaV05GFS1 Y8T9NTpX6zuS/25wS8VRnaoKMaX6XmDZJ5gwJ6YifR1rlZLquuNYDwidS1BvFY2f wQkLklwWGUGugEMnzrfUoPa4PvdAMZ3Nt+m2bMTJG16pkd7JsG126zGLcvo19J+C MOB4kV8w5VPJY3/GOrij+0eccSqXCbPuGmKKOYYFmuRNMxBRyFAr+Ad+POMACo6d LI0P+U//QHsxu+06WEJtpoqtK7EVpkWErlTlYcZLiKjNnemXJp311og0msBGEQmL zlHIiWGN1Hj8E5bPrZNewHpMRpvVHTnR8dJEcW66GiqEX8dGjTZiscMhx24VP4a6 Zkh6sFMw2m4HFtp1EYfvYkh7901FUk43gBXd5DYsORJVbYmExgscs6SbiC/WLCFO u4geiq1DHp7q8kjAjd+QWWBfdIO2iSyJ61xOVm3Fta4XYtRUrysUMSmNCqK6QQtZ xCGkEnXjOj8wqFTJsLYhBwndS2TMd/9u5UaChhrZMzRrHTYF6ZwaMtCTGu0SW8UC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQeqiod RuSAzIdIxuAFBGe9a7mIQTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAJd0odOH8xGi5GU3jqfte2M2wxN9L237aaSi2XUU mxtxsMdOPl7vnlNhrYmtvBQ9va+IXqDqmaJkgoxGFtCoiZFe8cIva67FaDgsCa7y mMaiR4NSU2rLvcCc97xQb6qj2oItoOrG8FAvHi1e4fWW8LuTakeOs5ysEnamhMU+ zvVM/lEBq5N8dZcX9y6FFQhcvw3LixMO0fi3Y6dB2YT+xUSmlqX1bkiQD5aVMOVw gGhFhbntsTj7PM73Xz73S3Vauqahkgklvo9QsT6WMDAVylZRb++OsQ59S5BEL32T lf5wN072P4zl6vwGvcE9lGL4R8kq5XIi44cu+Mmmv0/dTl3wp2HhTbjJsy9Qmge+ qOZ6WrocxzUgB0XJe3tpFESfIYbSFH14G8PpxVcAmS35sw8PVkT4zkKzst8XVBOP t3ioMeOw+KNgsK75IQYe18smmBcN1nOVEGjJ030NBqfX85IPlp7UDoG4Qd5vWqr0 l9bajF6LOEdV2qonBQBYUugTlct9tn9C175Uoa/8a0rKb6Xo61SYMYL2CuKv3/5/ BgwVmCfczQCg8q6eJapwJyJG4dBAXSmKNZSXdvdX76zsanJnoSjLTB91/USZF0T+ 3g6L7UZaTZc+Vzrv68c5+nLD2g7rKGoVg+A/S3/F8pvNcl/GE6L+2aVGyGRcKMoL MG/C -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQXh8tIPyKnFy/9o9+/M2RrTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODAzMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA3qHulx/7LvzTQKfLxLlHEcKco2n1Xfy47Z8Kqjt/ECvV FQxmFNa9X78O/EBttg2dLJgxKGhHOo0UtJAszF9872Z/SDQxV+DnfpLE0rew7Y65 MDzCT6F0d2Yirett8TVIUVzuHDGmPeVixTvqrdK6xjsmJ98Hfe0kxfFEw8zh3gky 7E7d4Sn9IF0sTbOlgFDmnGU/d5XxBdtlMYVTT2I22kYz5Q97Rm2Hx+GTf7fvNsg/ eUpAlvNBIz9s8q+lK/MjN+gt8dA6Ec0S9bY/tocUwSEIf84vnPoS0u7HGt1gERvY Or5zoCC2TEcP++nHR+I8asriJA7/j/3Jza6qz/ioV7nCEHQ3jt9+jrwG1AnxQni6 RHpRCL9KYx2Riwk4aAsjstuI2b501LONbEC8C1wBqi53sgbHS3xl5L8EA1iy78rE AW5bimF3HWYSa5U5deiUCcMZVKY3ts6lXGqiPBUqQG/Ug5gazIkDsijJ4On+oUoG 5KFQ7UhDHj7AtP77iqlBtRB97VI7amRyOLoYbENFPqZOm/EHSRpo/C0dSBQDGg83 iSge67Kn14Al5Zw7BefrSN6rUC6BsioxukDi+7WOztqiYme3UVpQl+WOeE7Z7g/y tcyZ+4Sl/TRqOa9YCS1S925kxq7+QXW2TozgqQOac06V+4H9Oi2c8okWqekJDWMC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTZNCE+ OkIlbeG7v75HTPgCreMvVDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBADiZCmd+Gol1t9GxK+vf9eii1oiXDYqIOJAgCiXR 9S+d5CN0KMwXGczlVySKEjCVyjkWPXAqj/pb1gbI9GDNNlD3lNadnwNwaIiJYVcN X9eip2V70JEzvJ6OQoQUjPtbsKgeYo/S8IjJ6YsSFYf+Bt6oWBa1getGAJNvaCHD M9mnmKyQNW6cu/qWPnRBAY1wwX7b3+OtP9wkOrqflUlCKmJ3SzxaPM3B/nft3Qso T6pvKekZxo+Bq1Ae2sAqC1IswqEunXVKKHllHz3HIKNLHVPPjKaMMVAGJj73A5BK mXRHwskccN8FxioY6Xav+putUVg/IialA7UBiQQZF3udm+vTBiIXQhwjNnbmI5k3 naJH54R0tlxWMoV8gX6s7zZR4GKX+elTTBdvI+FRCsAOJ0ApVckDRcq0g+uAPwYQ 9YvaSeBHr9DoYT/4MwkiOwgtdXe83EPQioNy4JntDxLh/9VbVJqDXJghmxDoOOtf 5CwmkYMJCiET6+G61tBIRclo4CUy7GW56PYgS98V8ZEro33llB74ew9+EH6nw6Ef Ncf216PfVC6dDN905MWxWIPv4lYitLK2168nkIj2CXcGACt58bszr+kM6GEJv1qP HQ2zoR+nY7fJjNSB3JxBkKJ3HTlV9SzJ0UULUoLfW6iMN2r/pHAO/Nq32ajAFQyy SjpI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQWkzvBIEpUha5VwXHcwUb3zANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE4MDIwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDCrRNoGIfRm79jnV5QX6m9xVU/14ajq7DySYSwDSOt hNerWelN3limhyA+ncgLmZE1bTvRMmS55Q5JnGsio5JvAgjh6XkLqM/tkkw6a2kT n2N3RNJn45mTp6IUVI+FxxWElryn/dahIrJi9dMiM3j/DwDZ1WcrXM9qD0HWZllQ 2baPn5AoxDjPNI+qvgUmk+iaPjhs8+vUOp5KYSsdYajrzQ3G1WS+DHsy/ArjX0R2 4wmHk/y6DF7LM3E5Utq6Go244B2DIf03u0spqdYpfwTgTeeLfCbhGU5bkJ6VhFT3 2TuhRfsNQ52Tx8yWgy4JfzBJVMOqDFfIoiZT6H+pdzqBqoqolUDkDIi2yAwPYMtr 6hAjTM4yiymyUSLxHS0ZPT09/s80HopfjL6+XmETuKHA0/nzjDfps8P48EUye2DH +kbqY1RdrJ8oE212JjatMupruZelNRORVJdkfoCUIPr56tt81tZrzJBTbZjbU3O6 bl5GY/0gKWTz46fNcVT0F/XiqmjH9d6qXUof0KyZJmBdFRQmydnouvPNLVAy3qt+ y9enB2F3iovH8kNAK4akbq/rYAAuMwFyXknPqDSTxI8RKPcLVsFY02te6pU0gALr LJTbTSMh4kdwSyc6vsNCul04KTLyPtzuxcG0EJ5g730r2FMMeMQsjZS0qbeft0kL EwIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFNPd NkySavp90qA1Hz6VNibR2ImFMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAEAtBhYTnu4nUXntASw/4pDczbrl2kqNtnYtu HZvcWZlU/caVpizYWPdoxiUc8nGpEVU+2HZ9JoY9gWaiaBJXhcghDN5QX6HU+wf5 sO2Z+kWQtaye1RqkxSmBOceCZsKNArdv6CBVPh9L2LIlCd3e2ZYD7ygIFw6Nmck8 EBfqvFpw2L7RpVVVa+1KrrsDuDm3gyd89uyycCVtNA4PgWvcLmhstJ8hLdE4PDnC D6nL6ycs+Kcf0WltcXZBtQ5F+i0N6jsa1/v1G+QEU2hfeVaT/8wK1l2gasGjW69O aC2FxrGxyioIN71p9ZARSVGOoBvxgpXgSAQET3MIw9SX6XfmdxCWV8HlnI4PUPuI FfsEylQa/8aiLYuOwjIx6bTOYwR9MYszzSRbPdKUntlxGcC14yOZeGf1sLbakHzE Pmj/redxsr//sJeJGjbxsnaSq+/fnEcOPEryHy9LZbo2qd3JpMiNudkD1T03YrqA MKBHp0g4BZuv5H/f//Z845Gjt2MzSe1n3HRceMT1dTQveuqXBUia6n3eZn3gbFhE Up3b9++Kzl6BfNf3JETukYxCrcmUwSPFISgSVgVc5AHCeZJ5o0bI/u/QuE4wl0va 2EVKevvHHLwjnDY3k/nNWmfnCQRnnIGfULjcY536xNCyVCgTQg6LYalm62rFH6SW pv29+qk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQKeFD5m32xRriux/5SSAksTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE4MDEwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDTK2OzCutj6BKuHZtaOvH8fwnTe7MCD4w5a/wgYSPi dvvZZbkuUVEpTeNx/ksV++20IpqY6ObCxnS98iu8bC/CWYzI+MJvx2TvyivO+qEu lRYxPgSFr3OJpLi1dikSIqFji4dMA4QmQ9ualxuuvZ+bSrHOB+teq7KC2yDbb8jD ba06hbRPc9YIQw+sH4ATsN/x+cT2XN2JJPFeohConTkGIGDq2Y1Jg2rHLRof0k0y YRtbUlRBXEkeUl6D9HEWNyK8i+/YlXwTcFZX7KgRiyRdkiOJ86MVrlRUtyhKB4Fs BC7tAmloeuc6C4UusPJN+sTGQJVUigJnyIEboiSGrU0wI98kP9U0THh3a9cWIQND S8Y1R2kPYq1Afa58ZLXUmmnqvoAfrs0TbFRAoSbyxxnvrTy4jfQv8Zgs/9gRQ7zy TSq28ooFdXYPlU4SR8Duwh8nem6UYu2DzR7bvbPr/fdDy4PPcSUk6o58RWk8MFpI 2KDJgvagQz4efhzYJ/reJZweRpbRMZn7YL8NsrMdATsEpD4adqMD20g9wCVQRr4d c9C/ElD/aZtIV41JyKP/35hg1flrW4aAmy3kzyYD+W7UL47K36mgODypipjXJgsa a0ZBv3+nlbF1ELjF4bnDZ7sc1CrI332Qi5wTfgoINaJ6S7VaQMZOY69B1515Yvhg dwIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFMkz WZUxGCe3QkXFX0pTOA5q5eJLMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAk5Pp3940sRyUuAxMu3kVf3UUt205f+g0/2fR ry/X6lMZ7/wv/ZctGYNhhLf2RrJmJEKxtJYR/oGkfW+h0TSu1inGky5WEnN7w7Oy E5Udf2Y+HTufOnzqCpOYywDm6NXfbZ2FYT+f+CulHT9dOnuUrxuK0zrJQWSJYIsO xlDFFHyzbFG6QMMohKcy0a7N9WQTEdgl4q/AfO+As6msvjsYh9ie0nVe2WG+lBJ8 AX2Ewt8PNLg7O7YnnI01AIAoNi/pkedqJSTZCE5JpQy34QIa3aoBGpn6B4M0bcBU tAzdQ5J0+Uh+RWDYjPs55m+mCgNmTxI9M0r7m4xWaN+BIMcKB5sj4PQIDSv3MbPQ ciJl6tCG4QjLlMVRe9d8aAHmVS9URqzkmF4ooG5jbEjUVUSCp5hxdev7Y66aipnr eXdhQUamyGktKjQtheWT2gixs5eNeRZtoyFYZgSOi/9m3KY7xAwifyOHNFpJV9FE b5HIIOGvlhGGyQEiyie3B1umT931GxdcyF3+C0RhGyU2CGGhVNLPhIpIUtB2gBpZ kuiOTpyPVKMT76oIhDVhuxToG/gxBo450GGYgaJDx019mVgucp45rCHk6AnU5Rtt zT1z221SHCJPcpEqnp/z+t9GJ3SV3Zb0RnllFP5xXzJsqv5WVtYOvSjOQmlYlAYP CdUP/Cs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQZgVQaqJRfCqnRL7eNgMv4TANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODE4MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAmEuXGi6x0Su0O7ReL+o2lmnHZ9Z6f2cOqvSl8ed5/huu oL9g6Ci6RMYqjjsJKMaR8KfGe0PqLVaQppp+DEmg2y1TvAIdwtTbpFFZht/W57Kv WwajKPFV4i8HdM+0jSRUvuDNvxIN0PZLHRYMB7cJzRLZ4fNBJG/dkw+v5T/JWj/l L/+XyuJE9sU/lcy/l72gi/TxDVsCVlaHf5LL2XgfRgBPbow6Z8hQQQtpACOTnvJ2 k8NU/BI4F7hW2SSzuj3HkLJJHC7L/o2VuY3k5NXIONC0OjRkKamet6f/PcT5q4c3 5yXP9ylVCoFmYv+mfuKwj6tRjm3iGNRG7VQx/gjTmz+vLrZA5PW9YhluzMQ6wgaG Dh6beq+LTuWuXoWT0eKkE+DN2qE2Mq2WU1h3Bh1pXcj0tsd1JxbY+XE2tV44KlF2 aUEWwYV2Rpuz2x03x85SljyCX3PrVFqB3K0WJWSaBXbqiSbnWbenJfadOFr+CHSd w4SUaGNMB8ZDXvrCi5hhI8mEX5rZWsSbhILF1sO+2lomtCsCy/qOc30+/6Wg9Djy TyhCngcmTE9jq78DlGNn9EeZcX7lGkM+g4VpOJJ9WVpaDrstpOrn95tEmfuFU3N0 bUybCqrdYnBe9zamP+qeLdEHa3mWZ4OkhlLgUAv26qrdUzq/sDGoQH3aR1Ret8EC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQQoDjL Ql+/lzijUfrmvK5WwzuRnzAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBABNRfMBV+MqzUir+vRnThYTIzJZic3fcm6UbH0kN /loVRopFTIGEfqKGCIPpmCv5chDoUs9InI9n0WRM0pvPGswpY2yTSj0xDcUGgvAj veD57bVqevDL/hY6eJbrZvbRTuNKqsuUhbN8fPU/nB+DEAO/TSjJtvh+yLnN1Op1 XtSDqpfBK9LAv/rZNx4Cd79A0yfHPWtdalkU1bQCs54RK5RHwPXrDCueIo2eJxls lVOPxG2wxH+bx6thtdM0HBxFJJuPDWQ+N3qMdV8NwsGdRm8qKXJQ813fPfph3J9E jxYcfQaexUi6E9LqRHt0yGEsK0EPuGcr/NSnRjTMVV0hBhBxqwlX8EIHI4wW8K5D Fv8ZDlV45SMicNXShcAiHa+XiNKA4gQSqQi6DXbblOIrqeSvVMaTCei9Hza5COH1 mfBvuKA1FbOEqsfbzhMp+5piA+g1Rjc3M9Omq616TIFbIbgGz2C/mH8GE2eXr/MF baRI7k4fIV3LPhtig4qJFlC0sB3Nkw5pWY/GarHi8tBi5Vu8arab+FsnSpVHX+Ul qjQgcJxIFCnYD9b/PbLprG9OnIRbGuR5mqcX5ZIwJbsmZVkvXGXbW01BHrRnE6aO fs+0rROIm++ATPZZ9mloVS36KUfSzCnctnIdBujtH7chwTTcrSZTSgO/2/1NJ2Tw 3XTX -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQEuF0mA5fDp1x2/9AnIRP6zANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODE0MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAt1ugBv4VQAurYjlhUSCrroBZJXFpnutZES23CawtEQem iIGJSRVYlNbhIhSmd//79f564Xyv9uumJr4j2Q2u3qYTi2iUVmlN2Igyf12JgaF+ QvdMVudJr4QsI00ZzMI0pd3wuNqlWjBtkkICGgZzv37hwfISqzmY7S+z/p2SuMQu VLs65YAPc1WZNrM/+iLSCEA3zjwBPVyux1tMyhyBtB8L+3eQDannMQk/qeyh26tu 6y1t3zfQUNyoU8NGDpykmMBkPVjs+FlertGEpcO/Y+Et+7jJQBGWWS4coEMsOvOS mI36fgpXQBpQJwKzya7pw8+jqqOpwA+2oDSqtY0TOXbFost5uUUVD02UrpCNPugr WgysTE7u9YOkMZJtC41vHC/tpv4tsV2gJ7pRgNdfdRU34LN+BP7uFsY7C/YEr0XO YTilaVzv+3Y0n090g5lL2QhfgR3Cb6ffaM5vDoUjONNbmN+7PiqtQr1eoKd+Qy7O U/q2+Wd0cvkn+WBHzr9mN088wyQR8TsFEP9qf5odtCIwicV+KxaaswdIxk40kY/w 7uWY7ixUthCWnMbnN9tLT5DzOINof6j4yxQ6DW6expBvh6mK37HC25Udhoc0ayWZ 206K/Ubn2Vh2VHPf/4PL7JzoPUnTt0fk1Pr8Aftp2B5YZIx4ySOC8SxIZqRtPTkC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTM/kzu t85TqPsdR1kC+5avsht0QDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBABcbdEdhJFXUoknlaKuji+HkhMNEGgCegJMqQmtA C0X6tRiX0AcjRvO/8rpozmXlQWjMfe9pCuZ/CHyLqbBpIcyWIGQR6wSJhC537U/R 2XqJyaHoXNr6r6C3kaStVebeY71ZiSAiRngQq0xOsqrOeByTpX0pgPnvhFgYOUbz oMeZMD5MjlTdJMbYGeUKgA9xliIrMeYtGwXYM5MxALxzNwdLOIE9K1/VG+J6CVqJ MTnEI3+HhQV4cMZ13acpayczrYOXhBVX0Ej7GgC8TjEPypQHRrRKkTzWNn+D9LZp 9HoZFlswjPQ1iGU36V8QZVRC77Cl3uS2Tq4FJNTOoVkBD+ypg8o6s3YIwqsEMWRK QlC3FiSFIel4eLD8r8sxG4C/ay44IHkg9K/LKmV15dynPhHPC/Ngo3T8WMW2v/ym tZrcJgqCywy3plDZjiU4nhFSe/bdPNFCLHzuR7+sIIb1AqtzMlaYkxLMMRpeEFSp nr4/jfNARzWQ39/WL/KYANEu7Iw/Pigzbvg9a9zYMbiBXsw/mt9BGr7tQ0fisCJI XmhJ2lAT6wi6u/OcQqcwgUDDSPc+XhYe5t1vVOhsCLCLKY06EewsZ9ZWwW0FIrCV V0UMzV+HNAbatiJETiSwqRBniOrGds6h7ZL1dnxNXIIqnVVdW6XcHROr9OUCNH8U ewSc -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQbJf3i9Mme54iJBBBNS/k+TANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODEyMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA4W9BKB9m+h+Y4DJQRD86c7oIRyrnkkUPVtjlv55uZZtt PIudTEAIQqf4Ntr22baq+MjKeok8Rj9Taq0PbrVYKl0520qNgv4KrwMuMIAXH+FK VH8n41/OT62TRwRx/cOLgFrJjUokOOlKHJD9grt6IFKPGodMzrosRwvNth2Bgn3Q s0TdlBFcanyKS4S7vqEaSyv8+l7coUk7M45LFbuc4ePpR1SHbTmz4RmVJTUj80PJ LCRJKdgo1eYj4PN8KbIo82sEPpGW671LSQ7g0NZCV2gJLCktFYJx6c50mpwjPPcC Y2XiDlRm02xDZI8S87PMO7y9zAN+qGHqTBGX2FGzw2ovCqyiacGFiJcBBRc3YsGa l6H6+mdyfrw0jqUiFRYgwBacTi/IiT0vafrjlmGoxg3fpr+Ay/mVpPbLqqMqe38i cUxEmAvM1430IE8nlOhoSu4VBgHceA9kKF5jH5oGxIB4LLDMsSZRd6C+VVg2BjR1 yUsDbp6i7a/kffrCSGLdvk1dT1HS3cjWF1GPDsTH8i5XJz2B3SWnwzCLAhOYgZEI 3FhbylvMvzC+dc6GGAZPLuzDHfVh3j/4YWlp8OKHcCleNvSqDOKs5tWbxnJ2Tau/ InaNeyzNSxcEQNZ3YPMOEB5Xt/FX2a1AwNFFcXEen9ZoNOz5r7svkUec/OHIarkC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBT9CGNX 298ygHtkFZVj139XTk9LRDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAGVAY4iy+P3kNCrFB1uEw+w+z6rhkgv0TUHpBc2m rSYJBvcOKHiN8c00P1HNiH/lCo/R+4KHYaC1Cw3C6isBsH9ZQAg5gpY2EW4obMhf 8Ly+EPzKZz0KZMzKek8hl/4WyLnyDmlLp0HDLKsyHSeew1C08PHg1W7fTLUeirk7 N8bA0YayqDuXh1AG9FYUazsr+PqcTfLWD/waOx5kd9Lf6lUmsPMbYYrCZXKCyWGC zi/GkD/rZDcppxa0A7kEjl4lwvqFafPRY+qJbfxqjQq/NN1vkppw4GsWfeIcW6c5 LboEv7lWe/FfIzafgzrCJ3VqCsfb6tC/qpXmxCC7pFkPip07UfTIx3xiYJynAGa2 ULgqvFWF19HZpwjgzZLXcCejMkqcpx8wGGtEwfrcedIUTH+XpAyp+Oi7TMrLHejU RAxOexldxOuOBf3Tbh2G7Kk9h665GCC5hHldzHmaiY1ObliZMkACHK88dBiuCPVx qUUAOWsXoOSlrS5c/UQg9wM4JQM9wuJYIoJQCYlrRwuAZPJrQayXsVaOuN15afPE nMXpZbUtDD4DXIVCGY/Ezjati1WVspg6DLUxtpMIu9Rt0ZSuXco9sVTKZFIP/6o7 gdbBJOgTedqX41avVg0WSPHjGcntZSDR7ya8g7eYaqqbFdouTZzIn9Y3irGJbOsX b6PT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQK2670Rm5dlkZ14ShQdiitTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE4MDUwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDLPgEI2vC4xN5AoK5nFnjtRjiPdbVIDc1SPpy6+JfN t1a4Q59W6k/9XKgmFoUVql6XmmaMJkuqdlUjC0asQln4ZuztHo74ggp5OSjvZrbW qVe+qSt+Minhj4JUwKF0rMJeGctdSrMXwxlRFQmycV6Op29KQUcFz636+PxnSaEv E2kSciz2CJYpuG5ceaFTDAxts5juLEEwhv2LBVr4W8rz1xEwTFZaMSdPN5aOtncY R6HaNZ0VkEkEU5d3JYU5z8al1HG5Ebaie42Rgu+ePzuvg1y1muNcVrBPLQFl5d5m ycUtjCJ9W1wz8wQEZGOMQ/9CJI2EZxtL+ChROD5WQ4hJ6mmmdf5yJyxL50vIV9a9 sHN3J+dhTISNQj+tQ0M0usBUTA0HWpl52mJElnbetuOnvD1dINS9dxglA60hWck+ Y234VtZBBL6iidXg0y0nyx2TW7euW2xVe49cj1Xx2iwkBvDFAwz/GvZAbd0tk+UC 8QH0YxDzfT1KA5Xexh3Y7EwRrcrs7y7MyOIrMp8V7xiyV4376UQnh3bQryMgKudB TsxUUlYZHxy3eQV0gdFm8EHA+89zHiGnb9EWS30iIANy9h/mCqtEiB7gbVH3yvA1 tmYbrM6ES5r/PKSVpyfSzFYLD9ZaYMUe2ILtxZP8ofVuJK5ax2TqioJ0CFXTOMT8 qwIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFH8Z aiTZNdvxs2FduEAvEmYHwbpaMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAaa1fk6B5Zf5kr/JrRRa7W9ncsy5eSF9WUBXy uyGnptInvN1fUYtrISIAdEgc7DYWYBtDmXm4nqtHf3n56iEuDi4YXQ7EuD9fW7l7 yECPO3VMK3RqZdIB9fDCXpMsta2YAmZKi6CWkuGTOEM0uByJOBRjNz93wRTibw8b 9frGNYmw10abseccEEKNYW+IOGPrI6ncZkHQd464Q3KVgRZwqA+BtCp9PZT+5soX EiPBv8gcWuQ8mnEGWDLwH9foHMCT4NGZLc4ZSA7VDCTxXRiTJ2ihSwwbtlAlka7j JxwtwsbBlUzyupm22BqjiA3fjDk1ge2UITOPpRe0bxjYdrP+WbsaMqZwvWxqJLR/ aTaVTM4s92bjl4V0Yck1dV2Dk8dKUfdJQPreQ1fjnmcgPa+IsWas8Fwpqc8/t+U6 KDQwXWLl8VPzBylaNBYVxaNpTjFn8U234sNiO6vOsKzNJHOL0xeprFTIHtrhE8i9 bLdFBzk47RrF/dQ8JQeXS8dpckwpMFd2yTSFFKqhEjHC9sN3SinssW45pg40nIqs T6fGLpjTll2f1sLTujB8wz24FkK+D/mjiWAKJbac0/v8pDhqBkAmyewAJnUTfLY1 O8a4qPgTjzt/068OAhiZ1xtvZLMIgMuRXuB9ynDWhVBhxh33/wS4D4aVX24+4lq7 AywdH4g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQHj0ILv/2dUc3lvufVLta5TANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODA1MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEArT/8OMQYgVmEWcprYF16Y98VO7eGE2IF338YVTzlEpRP 8RxGk60KkQCM1UOOEDjOAI22YA/B4khZTwCSJCIcG8qOzdvnsf9yt/+8MO6212rf WA2uyYQTPe2MXRTpLZ1icj9imPy/K/y4C2CGm80rs6XVwSyRRCNHIRIm12WIRkcd bWm2e/hnWoHQL8rBhJmdOXSCnZIAlqtmQlJYgGWJhysYIcUAj69aJKEglDM9GCHN 2AeAbi0JEafa5kAza4wH6LnA8ZJ9DQYf93P0Fi8hBPft45HiXC0KBpNUFWzcUH5R HUN61XF3v0dqrlHaYcM9jBFMXxGioO9Mh4dpYjBtm1UKFJcpoe77XcGYE+q2n/gG /xejhMhKWywyM+sCZWYkfqZKZT7eKZ0TURTcFllUibgE9ooy/iwSNKTo+VXqtv87 mnQCeKmkwiUXuHo4qFVtR3E0ln2i4a73MlFZup8dMxJ1THFEH8R66DWCnTe4ArGB hz6NVHy9HHaQloMuZUnrLK1YRe0W87ohaNjDImjiNO+vKMMWHQfdJLOXh/v9MsIq t1rus3gJbuBjgE0gPyqQI2ndruFLuzrvPV+311h4dnY44MvHEvgmgIrPlF/wDwic EEziWJNOoT0rCHeB8nLY3LeYeqOEbWXvLBzDo04dzfJY3kgB71o2NdCXs4SZWTcC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSkMAbb eRjKGSePRIW5DQb8loRvoTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBADy1IxGKAOGRGXjSJK3GLTmeZAS/y88RJHdae/DP /XVq82xT1aeW40r0N8RBwJrKCTcqN5zpznQJFJTrr31zMYzD+v3hjKDWjEM35jVh S7tMl8eafj0QwgmzFooFN2O0Ml2gkTuwV2nj5ad6yTpJGmwh5mXce+zrkVWdz9Iq OdXrJeHuxongnluN01x/CuAgt8dAZGGscyeczZT02Mk+fRuVqBzeObtgR9riAgyy jurEF617TusH+G1aHi98G4Hg2aJTFEvKT3HWItQxoVaMPotU4zbsF5Xb8yHFiORn bshQuIf6JVB0arLo2EVTOhuoiE2sTiobm71PEK9l6Vwz33n56B3NdACFVFQc3mc6 U9LbytKjW58kS1VmnuhyfA9/OFaAW0mDd4b1qBJwMSTAGTs3bydmqydjMq6rttu7 6ACx0vx3Alyc+cVV8VYlms+EB+ilfhJxuEf8qTQbjshqkpIkiLulT3UJssVTeUCA MHs1nf+HJhz594TGQzvsfwek8YcC8ZP5OkTElKcFI2P/FUpt7IVjFCElE2EptJWW ROSn51zMR7KxJ7GzvKSSm4Zq52Q50PgdaSR4LFAnNQQ7m86HU5PKuOqmamaQchOg keQnsLcU8WrKzLLU+iqKM8RN0FdHl/E41EKG4XKB//svKJDESOWVfhhs9RGj+CjF P8d6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQYrKuQ7P1LD6Ws9Jfq+/F4DANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE4MDMwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDCogcNtGqome2CGDpnjJJdR3R/kLyzLNHD14it9q5p WmrnV0woXE0U9RkT8iqNsYa5bpLeFUPihoX3m/mHkc7e6eKWRmj9NJBGLj9X5r6/ ZByu4jPVpsSTI4BMAVR+5Ohan2/B5i1VkRZNxHcpmmFTjFUEvhNybaIHfTPud5KT suHtYAmQOVNHx5yzEMwIP6pguyw98yILEbxNrbBIRTchZpwUTwROBzBivAj68bMe vlGV67eKJX1igt/wg4QC3jj7kWtB96v4NrP4NFFX8GBTGimlLhIi+tLZxWK8SZkd 8/Bp170XqrsRo3sG9abXdXIhPUjMFM6rMduBhKDgoaqPuyYL4pd+XMJSg24hPQGX w6QGGmj07hLotTwK7d8oLwbI6z/VnYtluR+dqEMKv7rwVunXlVwqc8l34Cx5Tl2s JZFmg/6CMb2i2DJwFOAM0zdkamJFIAJpo41oQOEZPs5W3WJdVTkI0m/+voMN6TmA 2Tj/N5fheAWsc6MzXCx9XtFbPWSR8JFqzg8g2a8/gBd3gQqhehode+uPJvm2CSrV vEKoZVfg8caWylIS5uwy2Qt4Agh/N/j5zobt+AfEp5s+w3nfCw/HOyjUZKheITk4 7njQVZ53gYrEpXgCunuBVzrSdz2gaipl4DpODMe5gZVCi/MYU63CRmHX6K0z1b5W 3QIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFMSM iqkg3RgLuzhkIeR+BgH0gzTDMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAS4PrnfM4i1PnbebpO2nZqDCmanO6AVjD9Ru8 Nq/uiZ95k9iD8G2islqfgvAEbH7w8mVPNTqpZNhLTtpc/Uw3lMfZPiUbuDKssBXD Sl3D6y1mSP4ayUCLQcF3mnMhT7P4esyR5FZwy0G7UTijfnygV7FOEDKHXXkTljiJ Ak6zb6ilRB28hwIcC7wi1YnLuE/1RG5vnTFgbHcqG0tu0yAcsszdZNFLgvxn7C6T wTOPbcgUQJGQ9nMd4ZWa62FTcRKmzQ6JK3JAcDFPiYZFrs/oYK9mN0fS2VERTY2E lM4ulsLEJr7GJ4kLjOPVSsUx4JcQ0y4KRabs9HewgpegROUtjpxIlcaADQltwIZ8 Sds984bL+zzAOL7j7MHFWUTeJIj2LzNYoSPGVvyOEBEQUBkylMpqJ0H4froKbiiR TdusDb0AIBtJ/MO5H1zDhl33IbxkBsLcReHX616fj+WSPcfZhzz2vEK8WXtP/26T eQx0l3PYAc/tV4Yt7/WQuzTcHIaLlkeTMFilCYtsIrXWIwf+m+wUSvh2LI8RVqX1 dRGEhHE6kPHNzvkTlL3GStfdTkWSyMgNDN9YUf8mjvIrLI7FadjjNB284d+v3HDk K+Vk24rmvKGHpNXfoDGEFz2Ln1IW9KFroFAjCqdYd1GwXRznIQDWdzcLhYtdCLOZ 7GZ1h8s= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQHQ4LD4nZG2JuzFTheUiKnDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE4MDQwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCnFoNtfg9rUzsG+Rem6MfZ8pvH37CoAZkHgfyGKKXP MbM29dqt40kLax8BZpVEhDLJe5vf/7UtmZ/CeTYXKuSSK51w8uxe84KYNedjEQk3 2aJ7EaSu9zB7UOUe43TQ9n8HNNvoPEG6ZoueG9rFgJtu4kGyS30WThHy5xPEpGYv aviukA06ocIuJkOPV3Jdzm2UYd9gc2vFoLSnAKy7fWbWvE9IY/LQwwW+jzkqjf75 VLe+yMUg1eMnxAfZsYQm+CeXx+5FgtUujBph2KmjIg85I4/Vwn6RfZ9WqU323h2V 6TaWqO+UEOby5TUDaobQ3YWMLotfMXkMowZTnxGpQJx87lNndeG0fB8ihQf9bUwB Hp+frCoQpVtW6t/kUWX4HQcmPvW5p0hP4mnCp5VK7vhXVGuCToHRg5nfJi2ycdoW 72qobLjnu2zruZhZJdOfqQRJBrk3aRRMHkDyFdrKskha+13jzMHLTuSf+p80ycOj jmYZOlV9xByMz6DrzQbLG8LoQfVlIaTNu2Hzui9sBfQyxwPV3oysBskWoTZ0JEvT XqMQRgMyuB8qLoKW++/vW1paAbxmkhY8rGJMZ50aVfHkrzQWIY3MMWfD9RfUPHpL dl8pvYDKGFo4MFrOAAyODwCbD+4db0lIS0J8z3AbJzno2oMQxSywSRs0lC2op7lX 5QIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFIhu 6wGZI/GW/l+PD/6w8NZtvzO6MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAbIxhiNgmFup1BFlrmkjGlTAQz7IqpvY2eaTg QyRWdosxYVhAFiibTFyod4Xe7tAP4+4uYZxUwbee0UUdQLs1Ed4WMMdZro6q1VPM P2FzQQyQnCqM/FHmFiKAqpgmg3IDYLjbzH0Gx14Cjugnxg1ln5U9JEPYOoKUJjjO ywaokuTuPP6DdG6Z3TAIS3PtbM/Rl8gsOchvVaWYtT+NqAjfDdQmXuObl/qIgWQ/ FjTl09fNe+z9m29/c2swOPuOSA1DxzeXNyvkXncN52gdgmmvYHjCLqnE9W/S4iNQ xqFAP6mxs5DdYrv+D9+xh+Ri5e5dAJoGzK+YqACZijGqZEGqPrnWIUz/TTtNAGWO p7afIbRxzwa7z9VN+ymhvjJCaCbopJhDb/MPeHJp4+sDvPIY9qCQFlORW5I/I3bz 4bXOx8auSODQ35Z2/4eQyJIMVxnADtjQdcPCLD0KZUXITknte9Bv7v1lQdSotnJ0 1SVAWBA61lWlEmq31moDlxtYojQ879EQrZMQZVjKzCMg4iVLylVg3oUvOAdRDz+h um95huLQVF/aLzChsMtaBFibG5nwek5bu1+l3ox1/Ni1sNMb60UHB0nAnIR7uDES dtXdq7/rW4MBe0aSon/4ZEvuSMvTU13CXVi7vVVYEWt2sALtoFp7HceR/SRDqdiB dQLmVkY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQefPuFWnF7CRiIwiAJDIiwzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODA2MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAlaODjXXTB0UNJXDboTU0ARizbPGut94TEkWSsLBP7FYL tvyvhZkIr7j+i0x8q3gWFfG8WNH+aOYBwNMfg6+wxCy3xkPBrw1BygVFXvFuPQc0 t2qeV44Y43YY++azJEB5oJQiEFomcca+iBs6FnXOJaabaPJPtzGiYaSbbelQ4hdZ B7Pa4C0dnAofp0ZE0dEKXhVz4xCS/KEf8Cxx69E18wNuTaqPUBGnEaUFlvMoIkT0 o8tBPGWcCHc0RrgsxyjU6E9GRPIKbX0SAxFihW8DMfpLrkXTXZiQxiWmfXCo+i9s 9AVex/DXVpp3lWiH4PqjV+HQsHhQh77X6VHLwr0qT13BPTMiQyLjNzW7+GPyJ1kB DIdRRmHUNKC2U4uwj8CwdW/n3kOPj1Iv+iVwOHE/rizOUUpH4nguvIPwxnqr5qWt GsrN5yta7AqWsBQollNPaTjREjQyD/HF7ndVllnMPFlujVWUQXG0SEYSuT25vu/t Yv53ccwb9Osv1kmgUvR/hKNP5VAzlw9uqa5xUCB8zXtvbEIVnaG2FWYLXJBFmPB5 wP8GQbDDGIolYeZbl5Ipsgqm3lgDcPX5pAAq8R+IDyUdz3IZUOFeT/jXboKeh2Lm MeLG6dbqBqOfDoDZ1I31ZmGRcC8vKntimE0LH77jeWaNfEBnCX8PzSvz/E6hW1MC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQjxR5u jHvf+FI8VAHbfqMEjvL7ODAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAJXUx8I4DUavs7DiriC1Pp7/53APXLs+8YwBUS6q VomBBsD+YTGOOj0ryO/pjaUxY3fcl5L5mcYKE6CXEd7wQvnh5NuxxQJmbMtXTc3c td6tV5HNxJsFrfl50EzklJ24eW81mUHHVMgSA/NhESshukRo11pd4rdPOGv4lVj9 nVD8mG45maejxwlx5adifMs4CdVAmD5Z2kTIMFcZPa57LQhur2hSpsofgtSrMiKv W1kksti4b7MbVbQTjkI79wD7+FP6IKUZQAluu3yk+9YYyVzkMC22izWHLue0JYfL C1eonL+YTcaC//xKRSW5FOrspKN6wZCiVOpfco3IH/U6e2E3xJ6GUTY46ASdP4ws tFDcybkvc8Q364xmJ4RAh5qfrwQ1dKsblWLKPQ6lmTPWD09J3hEM58C0UQ2lRPl8 bkc8wY8yyaalQ5VSSZ0BjqN3aRQVQHCyjkgOilzqFf5kHsnCvgPuNG629xWroOkH 4lXmfzFUeJDAP20v3yMAs03b/4Y6yHu5iQlLYnD8+KCgZ/RiDA4Bmwv4skNCJpfI yZTiC/dCXkgwKenoERLtHAqkII+tREOghmGzY8F2GtTfzfVm0YNGRlQUH0XOnD1n NAwVPdH5/aSfMrI5/0U6tDd3P2olVzu7ula7r5Oz/1WWIFhNemyh9I9AanPsdGxA pZQD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQESBuuxYRg/FlcLlC60CdajANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODEwMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA8nvtl7Deap3Z/Me5h56tLxJ83L61C0Q5kYYZYXvQoM/v HKX1bitzn/hinDgtrQ62pFYZfLocF5f49on76CFUWDMr8oxkWfZ/4T6gu8rGN5KY afVpL1qlxshxsTygCDFmazmrkJ08hqmLPwDED/eoNe6wfTsQBpmJGfq5pZthu+IZ +B1zV2g2YY7XDxpnaO4G80pWELciDSXM+z3RbMzfCVUUzyJ3tzxJyr+q+dmvZIHL KavTEc4q7FG+kGCBl9TVCj+Mnrs3Nt36uzI71I/B2TRwYGiUaH584e+MgaRjRpau 5ygGby0r5/b56IvFiM6RV9QEPtmHGYwVnYZXZ+yZMZDu3ZUkFyAIFJx9D8gQSR9I ustGRptXlc5jlIcHWS98BN4Pas3+nqvt7EsqQ2t8Rwt6Y/rgL75wVpcf2kgdpJ/k xCKMt9sVsSBz3DaD7NuLWZZ8vM2T+u9FB+U3bbUzPnEPonX5Rz3zF9/4cumOIzC1 cnaYbBR2sm4AmKqnaBYkK3vRHo6aTWcRoxBFOFMIRssZBidWSAxQj+Nvq6pcHXGN d26nCfk1Z8OChb2fK9EYaqwaTy9RUU309Vdw92QzCxny6T6gQqPLa9zpX7H7HD23 Bp4QAqeSQ5Jf0epNbHn98Up5BVTKvmCi2lqucEZdsjRURnsZZEmfh1XuzuNuAUUC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTu2Vb+ EzOEDWHzOq4lDAGsj7PhxjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAAbAN96JQSUQgxs3oZVoJIo39fxfMmUw39ZqYUds BGGkVA+CVz+WgSHcKhljYHwvUP8ijvbWEbCSD+hjchY4vE15OMz2by77b3RaCljg QwAvywY99E/ZR3Z4TY0BOLAppqla4V2UnE8OfKjgaphuP6Bzq+4YliZzpeChcOC8 0+5mxoNa17pkv3p4nevyXvBrfLQA04jHX+7WpuO8mIEYU4L4T+ZbKT9a9oiTWZbM X/CHrZTAQJyPO2gpWe9TFp2YQKE4XRtpjBHqQnbeKChefzLbXRijsT2jUE1ZN6be Tjzg8M/rqneeq8hrJ7F1U14yjBOFhIbrOXrXky9Vl9mjLL05dOWXX4MBzAUryMz4 Ln35Slx49axpCGXE9ul1UJNm5Pl/79BIsJ36N6afDn6gN0PkVedxI1/AIBPFv+Ao C4FjuDbdl9uuKqeshEIXlMN2izQhZ3HhV4tJ0w+oXhHJQtRChyEuz/Y4CsYTycUD tdBMTvFLVUpNQnoOMxdEC7XsrXMjeVA5jsYRAS5GOd8Fh7jZzIFMTenmOOMWwvxv P4t6PqMiaqFhzA5rf2dmVV1mCMNAlZo5k09SQ07V1wdo46wCppsIhIHobW+qdoy0 trpZ8mGJEKhHVdbtgj4aGU1H8VO1TCOQK0SDgfOZEpDXeAVRLG+OP7PQvvDOd8Uh UOXe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQZaWki3nV2iKbGpAkhkanRDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODAyMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA6gJDsq9U589KcPUMhGAFTjNyT3ycskIHGuUYdvDM5wOq u0I18d5HasGci2HWq+NZexVz64cGef9Ha5DRz2RVabl/bOxv5ITzIhdbHt6vRyjK 8IEFkp0uVrns8cQm6bn9D/ZF4URiiB18iR2XyvRsbhvOcOiaGy5vniMU4FE4rNPP AdJqzKRkwJvscrkPT6m0VPPS0oVSQvOXY9yu7VTc3j3GNQrNKL0UW26iuJnJ5O31 8DXTRlX5Vd+CNW+aq2L971t5Sfp+nOg55fhfofOgLIj+kCH0bUwKD9rdMcJZVeXm 86mNZyOW6ta96Oq2VL+PUKXyqMCqbNaNHsZmbdyFlxLQwBQNIcgxJ9ALOdplFWck o9tlnGszlC8qF7PyVTJmxbZNVTeCWr1hZUi2ZwcJ9FH6AZU74sC62tYH/NFl2Tzp /hkbv1S+0HdQ9QhcN9dXpvfEezooliaqZ8OuCvu7kw9DrdFe3NigcEK0AdY8scsW yIf5n8qvm9hS2Lv+BSslq2e67e3+jiCMP2KaLsmfp1K8kgp11sV2kaSZ5ls/drdK 33hZ0P58vDZ6425erquzpaoW4VwYs51PWOKzFtPvc7xjSggt5+eUYu68YMCqpX/N CMej3RfIpkB/Q1uLvbUG+fRJVSQzDGM0w+wLyO3A+IiwPYr/NQvIVZQkc17/WVMC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRHUGRE 5eDPiZwPi8Mttb61id29dDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAHU188B9yX1bnUE5TDhDzH5xPjteG9Y1o5xUpEIm Ki0921Z+6Xej57Ls64htwY7pqR81k9hiFfLJERgo37vb+T1Tjwg7IuyWVJjALv8/ NkcwCR4cXsPa+q1Khozzm+Jl5nn1JS0QDMgMyXg48H2VnFrRUAJX1dsBrZZsvzmi ER3TDGAAxRxHigVXSPsn9mfwfMQ2tWmyLPDDw7yVbxLnjTLgmjzFUsuG2GxyEzjH 3Ks2QhkM6NEHHY4Qqo0lN+1cCmnsqtG+2hAxgNgZQq3aFSyiboJS+ovJ4a099HU8 jYyQrD1Dt0e6m0uh0F/SFdUNrYCCViOWsdb+yBJT3Iaqr+29Wp6+1wLgLDR7SqPW nZX125bsT2jDmtl85jjw3kGVY1BjLMnZ42UR3kvam1XAQIgtXKR29e0GdshFKemc +A/MpsZB1h4KXcb7J9LDFQKSb6pwDlU3YOvgpib2cZ0CzMPl2SOadZ4+QJHakr2o zfOzRUUbuwwwDNoXtkliDjNQbzfohCFtg8yodUjU5Lm8utD9dfrx0TNu7/YsC9iR pO4t7dTydL9wGIfiMFVzFbSEy9u6bJQkFVZlqfPuAdA6p11PwkR0b+4I4alu6nQJ Z9Y6WYSt5Az5Lbawv8x55V1bG83UDkCKe9NQnA6ahhpifhC/KzBDAcdc4ZksDZFK zcTC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQY3cNEmBXWJa7Np1gL4vFYTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODE3MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAv37lGjz0wGMVsL5YqyKPDDzdYAsbXFVCz1Db6v/mhj3B +naq1tvDzM5cd/wSie3aIj5W3DTiFPGNm537YQMWdRjf9i1CacdbBSM8LtTIJ75i 4keSwj//jAxioFIOgBXBUFZg+cvAhrYbkUvw2qLHWNrIBZo7kn/RA7B7Sazw+q5e /qf+0vVuY4eqjwVVGfG/0/nW50rpD4t7vzrQs/6+Pb+vidXl/m5rvGvuvQgLWNrm ykBoonktifIWSckgCQHC1hwilNI9wtrWjZmrQvoCbZSqyJtNhDmiVV4a8nN97WNs wim3pqHfBolZ2vjpkDQgGMJDbWYIceA4IX2pfW61ZZxonZuQX3Cl9j9Sm598Z//Y C28EhSQrcGEBaCMr4OZmNowYGk8XrhnA4/HC9UpmeHZNQmLatHIM/JUY3YrYRypE bi1vP5/HdtoanSUXWqwVMu1NSFkGZrGHdEzLFgqCj/xYQ2433gf98SPXs949Bkw9 rhdtp0/a73Q+cCFlWDePLDoiXvCgJrr2TxiX3VXwF4GGjj2Wm0Oq2/00ktw/nt1a tmw9XA09gQO54T6g5lUKAlcoMJj/Ejx2Rz8xv5vxu+S2N+O39Vv+cXV7AzlDhjAZ fx7BHvj0Pq/jqMNOWa38Za1VNfTYcAlbv6jQ0/re5tn1yqvPRMPC7X534Qp8bnsC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBR13Km0 JMD3uLNl2ljM8dmQIjwOajAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBABubOaHQVOmZRsdgVUBLB1S5yn2QTRBxK9jB2az8 x8r/fWZAtPxrATV+Aom8+NKoekxU9EKmkXMuqLAsByT8xp6YNB7mxwIqKT04DVFJ tnEP38um/K3Xp+WH76dr1GJpCf0cSYoJNhUdd6jiUWeCPQvUAz0n2E6FymbeN6fX EB04X2l+OBN73YY1zUI+28lcHX7SoUOO5LEPEgGaOuwfUr8YTOKCXdW8wkG7JdhS dsFaRtwXWDoAXYHrxN1S2lEUi8F0jfhQJGOjSu7XOJh18gbMjTlEd4f7RovuOkbq HOZHCeZOBNuihQqasaPui+YouwSelgqt1eLtW5uDvRXsY7bs6MhK5X6p1T3gw+mV Fg4Y2qATCarJsmyu1ZuKHeJj6fN/c7clFJEy1KKnEOmsBKuGRyG1osHPQRvj4kII Q3XmotqmBaHIth683+p0LdaEvW7lvD8TxcrDrz3y7VngGY2iGFyM+jXvaFLb7CKC OEcg+EulDwpxdMW7PGQ8hUglReaNdeeP8ESP1sMOidX3l2pqf5zvehFd5IyMYS9s ipUpA7iQG0SvOLCx6j8g8Z64/16u+njxTfe5tcXpGt2FuXinI0/BqX42v+t9Oldg nwqf6IKEVWnAhoZN9ij+auETL4PyBx3xc/3Z5ymfWUHfzb9kogK45L9YG7/Cp8AI qiv+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQByhegEIrjyhCRL87/UvuojANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODA3MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAtUYOqUJNoAPB93mKE4w9TQFvNzAFo1t0WgF3ReJ0QFuc 9H0o2nDlDOLt4c1ajAj1TPe9/n1XBnHigbdaI043IwUKQYV0FpqywG5UNyBN0PKR rEgL+08ULPLJmBuA7I95Vlj41bPVAs9JghXolsNcmS94CkJLvFPWuhyPeCMiswUW Er80rlIOfbnvF7SfgZHp2TKzrDfmIEhAEOZnBWu3ZWK1xuUtbSq1YJ8qGkYuawkp aiUzw7ECMlLeGPDBVSJmZOHzIPpLlVFcThySrwpu9IBvhhY/TJ5nsnS59wpAkctN k2+ARDnSp05aX3hREwZgjj768W9fwtpDOdqGW3iyze1OXfIyIIbmE5ADBV1Dh9ht qCZu5lmFCsW0xLYiTY77uop/YJkMeeaV+UrXja5by1iOJ1xYUQEHC8T6fW3E8r50 MWo6p11Ypq9xiG5hkCdUQdNkg0BsW2FHksXPyopdTUc3ao5BBGChCU0PYhPHFh5f RO0XESill9D464+ZDQNPgnOTWDjK1FN9hLUzdZHZQg8GF9qI/SvS125AWWKY4etT M0Gikj4oBzSVjrqwZ25nXH4F+cs9iH++45wBYVYtwUIEb1Dh1q6UjP9X7Jic7Pah kDFhYOSLjBjF9xwZNNsh4a6AaNrXmRzgnTSyacaS8gI9x3M5cge9EQRc4w+ES4cC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRpPVki 0vJT2EG6tAh13r/fCK4nHTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAFpcqh0/E0QJRu+aTY/m3Jd9ryCOuKJ7JsE4CMcy 97UCcBaek3d+4LRw6zRZxVdYz7KI9fgawXCRSFsPfEN2SaCe++fLB94S1WDg3oTn RHSx/lxU7LsKn8guVUcR8Kan4MgBuEOUry5+0OWxgi/+0pHHUbj5DouTT53YmlqS LbCdJlpY49Lv8LOqyQ4gd634fPIc9onur0Tt0APW8csP6jM4HrGystI/ys1ejSd4 KSGAs1s1Nns4rn+k3TBiwnPeflbwtJGkUD6r+1PQ+9A+Y5/S5BZasQUPRhKD5UiD g/EFN114NliXqVBCDmzNF3ewlYG9Cxi8aykqys+3HPUZ+26wHGQ1L7o7yR+G5qQH VqOdf7dd+q+0zJ95iJD7JoZYFdvVWiAehBPtm7QAHYlQ3DguqbBGPsOkEI5FVHSK NKSxrBXhVJ3MhzIZNdzE6iqCIbk0a7wuLsINTOVtQKUzQRS8CNl/81E0odLayJdn AfvD9MBGcqVGk1xvn2DysQ0zTz2FbBz1OpT/WbDkL9XfWLRw+zpVLz3B0dn6XEdQ MTxdHah50DCqZmNc1yt5hvGkbGGdoA/j0U3AYh/9NGFvtxSLwzn9lmJxeAAMlCmD eJCKv9QAd2E255s3WmXVjF5pURMznTr5sZPedRpaZQk/HR5sY7oqXWnlPumIIVhI zQlb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQJAM72cHZ9aPMuVIUtrMyNDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODE1MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAiiFnoZ4KzK19mtN1zyvbEs++BPhNJoyIPPpXNHXgR9OR op0pggMV0GOdd0XWaK5bPbZxUQnz/OyDu6SnnM/87tjPD3H1ffFvV/ri10O80nFu s28GuslM/9Ne8XTHoXzuS4xF4WATUaVM8MFBDiSuqMdSvFe493iFTAuyZwseBN8P RFRboPvx8Uvt9oT/AMBpDDUozI6zkAUsvsOX+ia0K2b0ETwI/yOUKKycTltDPhVy QXbZxuz0dMN33x+DKW82dkb3OzFiAtmpGWv1YXosHpzlVjGBLN6C0tWXFKdnnxWP vQA226a5c7HAakoKRahgwpkubf6B6Pms+nDcRpy2Sm+bS9snrU8V5rojLSP5FJuG BiEnYolzRbxbdhivTgK5stkLtpwaOv0zoHA/S6LLUXKPuzGb6sMXEx8SQgEQozDS rDQ9XlOYs0o03Dj1NUTuN7V5H3Us5WnrWiK4mU/Qurrk+MkL5zWdNmJSFWfAMAkC VhUdAgqo5U4EJ4ebWBeM4nMu9lB6vPb8zdimZSaYuOqf2NtGOeAMkCUBDOqXTEYd oJN8Ng3Ca+uAY8UoUfB+D73E+HRG67Pk1pbw9t+Ex9cGQO7veZfw04KEvkA7R8lb LEJnYQ3YY6W807rig6xd39czU/28Odq01+yl9oWJl4RiyNbGrBAgXGZOEIwq2v8C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQ9Jnu6 T3Ui+1ZC8J/Vp1BMRgzarjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAC7w7/vnH5yivDE1VKyX0tAsY0E3gGGC+ruQVwI7 99dQA8A3sxuLODVn88C96qt0hNJUXmfe0Wu5/LdxoB3WiFmos9xDwltcgKKwwCYZ VPsRkfWk2MsOna1j6u0jr7eQ9EU3ALqy2IancokdqtL4+Ju/ul03eeOwxxhazvfP p+9lZh9jXRJIcoKdm2nbqualrXAThjtUtD//FoAx8uylDPEg9Ilk1ec4/371t5IM NA0zm/vangijAle0yOrhqRK73/RoJFgTf/rsAvU7y5I5+bgHtLL8o3yWhmT8949V 3fR6Re6rvOes6Czee5pP6GEvbvD3VCjGZ2BfLCcCrZv/IWYNXNqVsYkgG5Cm1UHJ GEHEigJqOaPrGd8vaqu15l7qNMp+bwRL8uCV7oCiXUKpajCCfK0+T9pq0yBucedp fesKzqjqJjhfftn5Ju2yEpOu2QLM2J2DAqTbZuXUqpcxsUrRhI9Wv+CzWuZas1b4 PpLD2vmaOVCHEgvFU5RR4X1xcO1AtEwUvdjZgGgpXRBMYlmNGh/d0DU/n626MJWH 4udUAchUYDbL3bKs874L3IlU9N88PeXv0Qm1qY8MiSB5x1MC9xQkezpP6WoqiDOz k4pfdD0CbYI/iAw5RCoocvZ3PTz4WdEdHEP9oTD/+mZqbBPgZd5aYMKG75j1kjeq ETmz -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQNAfThzxbv8HvJT/MMGVKTDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODA0MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAv/X1gJb7SA09We/eVAoE3V7v9wMvMKvDfWE8BtKDtogf hlEkZCXeKYGuqsT1duDwd2N891uR6MupnE2XFx/zmexbjkhDaR1tsNYDHU600o2W ebssOdIwXrGf8726IuDfknuQvXUuAAd6eRcAfdk40wSIfmmCkMCXYC9SfjqfEfJd KTPVSA39emnMsh5wo5W7AIk8oVRIF0ePxHmvBxl+UccDSxIjl0261Db2p1ul0+Yr UatUlWsGJwAoZgkxFHsmpLzuEVDW9ib/JlhqhreqQOwY0isJzql6XXyyRby9V9AW Pd0V0+jD5vbl8e8tzLhEE6gxjiHihSGHOmyxConWjd1CLQ6VS+GoukHBxNjf02wl d3uYH7+jSyaI2eBDu1iZalld/pS0i6LWpcmJYx7Csw4s35TWKD3WepyFtgfj5vgu 2Rw+eESYceuwcELTjpwYkCkqn7K5uZ7/wGt0leIt15a+1ruPsS11eIAVeOHMYeMM McC2L0DrERG/Skj166MvBEuyO/PmlzcuMr1ZP5Yd7gyAP3/8VUxE5hp7YUyR/AML bstOLYPdDVdNfc2bDRFzxvK53G8vcE3VP+Z4P54mf1UYMBx29gNTponS2cOXg/ZN DCl2rYvNto0Um+ERIaSdDOqwROSrMgqNZ/Pkju0CAIj8JLEhj0tFa2e3/IS+5j0C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSQgA8l vIpORZ3HY/pP/Z4luOa42TAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAIcJjQ9r/c5/rooXNNqAgPA2ecyDz/K/mcb6XsTl ZisYm+JHb/xy4wEI/HfP8GtPnDqyHmkLbUWUKxeeL6DiDIfh8UP/Yy2T4qFxlaEo MlTtTLmYK9qY0dARX8F0VY+lL2r6jvURknQHlXoLb4Am0Y0NyQ0osxkM5yMt2hAY +2rF1+yycS8/LPLZDbO5tCYXcYYs5hPpE+QnTkEgMD1NM25Jjs2gjfUeA1zsh4K1 R4chM1to9cOqKH2EMIiIqJObPiX5r0/W3nZhrpONiydc29juNgn5XD9+m+IELL7G ByJCRyKrlOBCvMfG7sE/5uMJ5eWJsG7LOiYr2GqdXRD3z7vnJ1D2PwzKhgTB5jo/ 3m/JzmgteZSEO+dlgC2ONr0XXochuO8trsPEB84fpDjI8j2h0k/h/210anmJotr0 0A85726nmU5VNX/JluZjGAExYjFN1x4f/1TNvH90OqpYWaaX/eSQZcEkP8U0fS5S xDAXLJ7Owve7p+3KvVtb5d19QUhgT9gKy71gtS7I7OIuDaWsl1NzwGF8raFtTqPd AxDYUF6EvQTtiEk5JOacV+eWJYdqAR3cM5Nkl/J35cN238zwmCG+goJdH+cRWoSq dHxLUPkE8YjqiFzYMuvXMnbkt+8Xdee7/9MvoCQezrlMTumzdykeCTTjzqoGlJxV pU3C -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQHuWj0XilBq3bgPmnKsr1KTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODAxMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEArGKKopMj5Gs+buliJvSjk704TTJWKTfgWjLwQqdfu60L Mb4gx3uZ2wHwIggRmdbLXVi9YLnp8GoUk6CnjqNLargL/hPY0Xxjw1G0B7Oetrdu p1PKvFfwIpQwmxI/w2mqhSM64nlvi8apYDB+MMDl0BFG+TwrDnlhORx0O+1sq52h syOnmSXuuLjCICLOI5uj5KxmlfonWSP0LaibqLW6ErOg4Bum+ldeUQykUykDDIgm Sr5bYclIwnvnUi7kkWFLCt3sCfaEshUQWq+fDr6nIW3vw/stkN1J+w4K7sxexk2C Ot2GRGZZtVHwMVJOL1LrMRL1jO8eZWA3cpdOMITUt2ztZcmg6+URu/wwwHV6tZcS wGN3IzYhryYSfMUsNdsAPPIvIavGCiYSQY0ruXC2Slo0Y+ClUAH9PmtgetcOE6zL 0S0QuqHbgYQ5h10J7O4J3rG1abRwonDKB7W9LHoW7BD3ebwMpCqzRZpN9ky4ZVoZ yr+mO3HGViQN/nUaAFCud9ckxH4NchHz38G164G9JaheM9JuMKJRcpbqAmedugOS BkOdYDRaHNowwFZpS53eAZuzWNFDskxce3tTqlyFRlqA5duuxod3eW0WPhFRSdFS C7IGNSqRZvYbExRDMTJbOleZlW8Js6NAA7BKbMgw/CTju+EN3EU/RNJPdoYfl/EC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBT2fU2J PEMlnXAmDodKqpgqTJcYSzAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBABrHDR1LPNA4WV3xB466FOR9zkG5lwr/UBSts7Ng gJUOH/WtQTkzmHDnkTG0blZRf13nqnVBmnvVHO5+ush0Tvw0CJu7bomUn6hCRCwY HnQ8i1uelLaCYa8Pn3Ye6xOsaPoxjOKQGz68qoR6zGKKbamHpobYdQmlsBIXaiYd IVNAxdx5zArw/akpzhfYUWzgds4A3cRue/YfRtUwyeUHJt9f9M5u1T0av1w8fSF0 zTLeJLJUsnY1AJu1eBOo15Mm1Xu+2vnofzbyIEJ0KlDdciY1/i48v+dErNSvR5nB vW/9eOCPTa13K5Eir0VxAvew3xQrmf+ivLZ6JtUWVfpUixCM09zoE2Uq5KkC5aAZ 3hSm+Kfk5dmbCiaClKufoC+oV/XtedCDkDvuU67rSXdif2nyG/Gijcct6Om6iHkr lQCBcga02Nci7Fj2IQ57jpAfswM53aCxh6HGfS8tMWRPi6ey3knC7uxh/yIkJnxw HOHbsgiZPAZ+mcva0S6r020NIBI/x+4ck6elqUKsJaHVPkOWZtwrbnpeM68PGk2Y qDdYqh7Nag7X1tusGId0e/hL8IUU8vwcers+QKaiS2LQwD5H5SP/p9laDd5D+XAf ics0yNd1MnTtrTHknTvKHdnM/BNSdZORzRLWD9Lb/gorp5lpHoWZ+pud1moBi9R9 XVLt -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQIycfL8b+HEF1SLjJI6+anTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODE2MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAzjXL4nnTBkb3wq+A/Atk2C1/lJa10O1VxBil5VhMUVdT HkXFlZKyrzX9V5cx8PoJssmnegScexFhhAJIQukG8Bneq3CqLsEdQApcsEQEDFdA 6PYSCt4ESi0oUVmrUxuGRId72VRMu3pyD1w+NG281OOyn/kbD+1W9tMxhH7hJUvu wX8MGlcSPH8FO+8WVPjrRuGAmj460fZV6cImTC5V6WqBJaxtGIC3JEqPquOxZI5s AxKcMKyCNOzTcWYfp9xqYW+knSYrQR52Kh2Jz5oVoER/h5a9cA+2kO4ZrQiNP80h cKeeHrVrDg+qUxOVsoOb3q6LRr7ii5MD2Mp7iUqveA9k4B/iIDsOL099VzHlPpvc RjGIuOgGYU/mWLj/u5HzL69yE7z4GdL9rPiRiUY+03QrDTEzpr0BMpR9rR4hLPMI /Q9nvQ+luYF17RQqHLOc+Rcm6aDHzsDXLrHH3xQv4fC10I34ql0HapzYFEzBFaya 43wi6YYiboGJPZjfVeJuspfdltpcZxdzJ/2icShKntSLFheeE1y3qk3Tg8CPNpjN zAOZcs5NouK18Qcj73j/EXrugNiSNrR8Zy2vtB4vKdpBb48pUKODS5/WMNfktCBu iKzxZr2qIGS94UTbBOzdYQQY3vNaPHzyOrs53vEhYGANRF6L/6iInB1lMJe8ZD0C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTknypL 78+cu4l+VE37fR36ofCSHTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAH9TvFhsjGvdBLEFlcevmiDpnWf/XjhGPJn2FqRF hdoKxnqY9SsdQ5fgdO//xtEGVjXS6QTyUaoUrirhpIMiZfHP3BjkuT6Wzk3YgZYB L9I01YrdKQrcEUZt3FTL3roVosaK5p1iE29Xcd1F8rED679QWbi9ASDCcDbTCFTo 6n13ZSSpNofBzKsuDp6t8EbzK3rbwkS0c8CZTwDCG8h3Sd73evjFWes+SxbZyg7t 7EVm1WMZzJgN6BEeiLdC3bcYhgxHHi1f++VVc9SVtnTF9ScpG5ot8f2sLQXAdPD0 L8JlmWHC0wnqoY2qHK5spZvbZbtrisLq92j9RLCztZBee+HRE8BxYRcP+zYWq5pN nkH88epLuAod8YU8fxuqtJWABWWSLWzvQnoXnx8p8zTj1VCSgQPzKR1XaruFgaFL PQn4xRtNGGCBj3OTGj8J9CJdxLlElmZT6yeKlg+NylWHFygzp8xZGQ6rytPCcT8F /qgaBIj9DtVheCDM4XzEEwFdcobqQ4uetntZ4YKCpGxwQIWfYP3oTIVhNTsNg+/j 1G8/PkB8YT84QlUFdx4kHHXpHAnisrdPppx80L8Pyy4EsQTrZzkFw7JU6LA4UXvI jSyjdLkkXWNAvs9DvG83/Sbxt3yHHqcneFxIoWJfLg8cZA9FO99KSJ1fnpPL63r5 55Th -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQeOuFBnqXDtW5OVK5wPQmqTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODA4MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAzPPM0A3ZxQvPYcqkfj78cpdsbz2no3ZMIP/a869Exd4P FE3mfW48b3QFKALu1EcqnGqc0mW3uzVLKeHJk3Y3/kK4+I5ibyNsYcSwn0dDcPHK Y6cc9BcktqrhEquhivq6bLAcyxVPZPtq9Ao/dVfIfWYNGKll5N7UrywXXmhmAmji Mi+8f8hoUSWYMUNmrS4weWRk2PIwaj9gdCcGCr7AIqcDnAA2bAdvBkzkWm0x0AYo 2QF13NGnIuOqMSEs03s56Kg7oXl0cF3+6zi/z1RoABroN9yB4J2/wm2ueyjyj+Q1 Q1tZqZlt/9Qv7LZS6wZ9IaaLs6LWyqOCJvroMOOg0O2gRtK+7+o8ZtXX+6BBBoVp 1e6EkL1d8AEl6WmmoHUe73Y6n0XM/aMC8PJufR+4y8mz5s30axtqOuElhZBDuo7Q 2BfKnd7gs+wQyzQZJtYXR+7RJ/4MLgP887TZ+q4BVAcY6Bw2kK/4b20MuP3RpviW wm4YaONRoSEq7xXbpWB8LRupHi0RXa+sUHQfLr9PtARWsiX3ZWGo9RFaFcfugTEX 6zx3WtVoR7Y2toBDnNGbCLESYadyxunQqoXEAnNdMYY9JTv49DZG1172H4qpbjGo UCUbjYeqSkmZ7QDzo1Sr8QGYboruEv44cw7de1gY9kKN0j1LIWQj922idqjNEmMC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQ9hSl3 I1e6zV5endihqb35jfI+xTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAGReJEV/xrD9969lWq1b3VDmLq7ASZohAMZC6yav ZymfhpboPLi34z63xFw9IjWAuJ9tt1k6aBY+yv8Xyd/ZTCeBYzIPkm9CUj5KzzfM P4f0agiTTAa5GyX4ZIenvTw+qD+F5L5Tvvyw+fkzp+2Z8yHu9ACLS5+34y1TPvri SfJIntxQVN6ZJMcdCjjc9E2ejb0Dg7cPe3Z8Ca/PU0gVcu7K/YmQ9xKLjUKD2GM2 dq668lsc91CJsd0JVP7y+MVkQPZaPMWsCpLsjkafivHq14sIQiOWyvTrPfeUXDqS TigMUjVgr+ydmUhBUX41jHEwjIFJaRCtWLZbcJnhzzeYxbakwm10o13eR/JfeoIN bGQXAtbuAOtDFax0bSrlb5ofvYSWCGCC1iP85D/xZaAZKvXFy/BCqBmDiM03H3vw h/xCesLbdgYMuCtnkjxm+pKxqT+R9bCux8iuzRT57M76GFQbFGiYFXuSF8Bcpluu tx30EjBx2eV6S+X1kK+Guozt0VNlU0EXfrmT3i4I5gFt9nMDGQ7l0aeA+2QgvPEp blUpImK+qrJdHsgP06FbqmntfG5oRqbHP33w2zaEHvgoJtYsCUWOjuhc35LvSlm1 BsGq1V8YH9KvckodhY1JWT68uhlhcd+FXBx7QsOUrriGfcBbWfO3CFuIvA0EkK9R IfGi -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQXwbuxOe8lq6muQ5dlxroWTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODIwMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA8210KpmoSkcaB7e383UNN7+ia6IuHK4f5UkeKflv+jYq AaH9UhxBHyPZs6HhdDWPM79iDhmBzxmNj+RVFSN9kAN7qJnon09UWze7WE7MDeyt yFOWY4NgjxEHz0NwdRVE2k2eVKgCe/8jsOHCzUqU740WOE7FGmkwS7XlWy9qYT8i /bLRvG7GX3VBVzeWGZgM20D+W1Ht2+ZMDH0pEakhl2MX+l61uDEyaLmaQg6nhePo hd25VQio2qEKSnserVNGKfoEr7wqwVg4n3FC0Mp+8K2r1U2/ts6bld8HAEuHHG8p YYWu0DFZnjQdV42Itum1pWO4fGjByX/+Dr9JiFOmh4PLT3zs2ChP1To1qCZAuTqV hmGGc2BiQmKajnHPAILovl7LvZX4nUUyrkai3EXh3QQklXHW0vhLTENYdSAvMj7w KRopQKr8N2ZmnvAfGx5yBNq9pXPD7jo9464Dx6qteLWbk0yynqr2Z106XqyC395c uBAY4lJT9lzZDx6DDZQBGFxMbKzqusg9QgTCkQWh9hy8WLH13lPn2Bkp98f674qP ejIfGJ8JU+ercizg+AWyj9wvmAxEoAPFkg/hIIXxJuFjse/ZuTF+tUZEzqVcR2S/ NTalE9Rvj4XcwIXMfFcPCQIdlrhn6m2INUuWPgyfETkdNJFLe4fb2Ai3nZPOHycC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQJ175F 7oXQjoEiT1Hf+KdSGYPGkDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBABa06tb5jQKlfUb9A8TJRZpHpiSY213kcIByrhPs PNJ7WWc3m0Aq9NKhKNoDCuU5FzxNFWbLRUURXOBZ3fMxfP/G1Rm191FxoxOiGwls RMTpC5pleRPAj2t11Jwn6WfUICOxyWV2HAiLAusNY/g7Gp+nbwfwxzDMtQdPOVxK HFzo6ZQ2JMOHTImFWOpOD4Xh92kotsP95p259/Q/U+Yth/asrRcqWpPPubKsc1pM eIu9gVvKX9q4PwAxUS7yYtKmtvxzkZR08QS/kcWObUnchV8D1zHP8nQkZxuvgR0g Y0gUqrWniE8udYPgpzMFojqBm4Nuan6hbcpDWOJHlQ/vFLPX0IPsbEmpVvBHOqBk gVvXsZbKxe0GuUeputHSx3+eciQP8d2o7rmuvqYwMav7OxKqL/zWDGRajFm5He7W LUyBWSHlnqELQr+3Pkz0dtPUm6Revkooz53ny/vUsAWB/0WexAwH1idueAVFinNE l991KNW3nueIxpgdNmqwKZBuywHZwFEB+jH8PDUeYJyDHhsz691o9HGzflXyZT4r y5/pvWyu6FPysjJ7Yaxc0eq4/tATBbSc8FfaHeRQZodA54FTtc8klMj5TbvEUWcm KyKWagJ2qZfYbli8EhG9H2LmVUg+pPCSagoYSYtCPjmbJOE4KwNSTaKx6EKu7+/3 irxW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQRNcwtUlD1ghwIBT9BIrPfDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODA5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAzDv/vF44iZ2mD/oM/l38AvRyzu6xI/BikocuHcTfZaYc 9TlePfH49mc1epV7Swmz0qbApDilmD7Ph4kIJoG6vzQyeq3q9XgQF3d4H4vitHRH JN+s5Ejm6Zk/ODJYNtUeBLueRudlLQkXws5iAEH4TSi0bLPIwASiacK7dMdYh0Ei PP0/99XGZO5zdN+GtbDH7DfnkicdN+RHhE6e/p+oecZgf3gEi0rTP5kXmecL6f/c jaZmeeM1UOFQDWlMSiFUqD/lkjjrZAofNpQL8SOqELBNZbnVJXduAzHBFnFzvFH0 aT89pBnKh6q20rYjoqhELzdIHJUUyuYZR/AR3gAcpuhic5hQu8F4APyT3PHQS3cd nMhbVviHs4l7aCc/GVOi09LO/W8pb/5SNVr/YhPtyVBqRIS3JQjGXGoMBCIGRvDm YTkcB4bNHGyZCP8BE7kErSV5dmArtx6EHR2lmtrf6qs0j8lVRAPdm33bQT3uFTdR gKvnQuQ4DeNcs3HcetZ/q2d4CydUR5ycaND6nmBaj8+Tzebky61dInryFDo+5J+L Q2WkAZB14aV/w64vaY8l4letOpYfL+uQqUzP0lwfH9gCInrkZLfHslxxxUKms4DH 3derrGzvx4aNe7CXs34mLKAIAXQPDv7ZM/LVxuRhd9otPIRo6xkPPUSqDhQVjnUC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQKzWG5 6xh+eajKhxXNdMhQh9mzQTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBACXcItDF1xCjw2Ruqx3gIfDtqybPYzSJ1whIYYU1 MGTkKZe4nS/4W6Isq0FdnMBFZGU9TnoSgbC/8IqlJCaQHcpZmtd2MBxqTLCa4EoC UCqUxHaBKjCi9Yw6BwVMYesXIvRxiw3Xr4mMkS3mUhaSccxqgpswn0SLUIWagGeV YfxXFGLz6ROEGNP80Nmysp8T1dMdfels6uvF3cc2cZ/U1Y7QUqca4c002JzO7Xvv 2MWsm8gMONciX+/80WUGrglUzyeGT8mQFWTMeonsBH1NiS5imqRwL4e5ASoeXNXi zFfPo0P+fDyKJQxgtCDCWhwxzVRoKzh+TsNHFnSPSTsYG7T8Im6jKFCNqEPHqCi4 jrnFqgsPV0fbPTIbOBdcW8IntWylX9toSiDVGeNdee5/LobIHFzPcYgLZF86Jijo kpvLiGFXHLsKe36fWNC1j+/RaaJn0PqAD/i9slaTR99C3Dc5m3riwV09eJauo3H3 hwNf2yMySR6yDCfBIUa3iwJEoeDM4BlAN3GkVloN3pEDoKsKL2fewn9ERG44TSBc Q864HpI05xyK5Hpuy9EYTz6oNq7v317VIiasi/r5r3axxc9GNxOeV0Hzv8+oUYM8 Cb/bhohlkXHkACEBruaEMbRsClPCWfVFx7isKHW7qEIvCkJQoGD59Vk+XE+tWbrZ xndJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQfwk3xCRS3WXiPkY2XUh7PDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODExMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAtV3OmY6FWo7tVyR9lzkapDniJBwNoVYdkMvJd4b820QC UMmbtYmrLLdDtAVMfDE2CHuxH4Pcx02lgO+lBBPFBg0+M5uYW4cNTP2hSXk8TY5d yIByNjZQssPVx1GUvM0ciVE5Ega9a42U8ZgP60o6gmQbZh8OH3f/r9A90N0vu3at fuM7YEsE/VnP5vYSdmpEOGbB39DDqWM6dlk7B+imUTalaSHxZJpaoj+kDVxjCD+O hwXQ5Si9g7nGPfY32TniG0HrFld72YVb0sVFmw8ZsBrSItxfyBy46asD/DqOqz3e zStN5BLEUq5pY7FAH5NNaMKNGRa0jgTsuO0xI2akzhWd/i9pi3iWU3fJ1lGtZUn4 Q/zleMKv1g71g/y2x1nyGX0z5XRx1vs5TPRgS82N6MxnesuLBJUYcXnzWftAYZl4 jCPgcYFibQJs9g4Rq0yMFbH00tpDmRZdckxxh78hM3GR3qr4yOqvDAssegQHdtwj weHNy5i3t6a3C3aeZdxyF9UB3FQDqBHXTgnX4PfdGzCo4nzfdWBFi75fCMOAcv7S qklB3thXaIGF3F0+6PNXTFYgAgsyhanpFvTXRCR7HX8uAm8ixwTfUO9hX/AW8DXy ix9Hc+MzO5xGG7qBraMpGKXU2Tjb5qOAHqNRitC+gqiQ25snAP5I5f9xd9+E7tEC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSm+TgG 91DSzsKeUOBXqon5zpmLZDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBADUbj2lblbxKNEMNzZigLF7FL1wcYCoUXWNY4k2t vi4U4z7U4K7hChjT9Tqc0elUc1uezf5/t/GDdbzAQy7ffA6jDuELYghuLxp1bzBx 0b7E1SlTY2XsERGlr3jHGp8OLkvURWCBltHoAfx1nmZ7g3eeUYXHlFcBilJ4Miu1 fHN1DajMTkivD7KAc1XqGv80jYrMEH/Nr10akVQyoHVHlYRHgp579AeGrGIJG8+4 zzIaD45/+e1JSySHF0P+/SYSNe9XZNcyEfC9bhaIWuPcnqaG9ZHLiMctJ1vwSAnQ JUL0EuSW611tB0AiLr85CneVA3PCuln0bvn/VtQRU5qqRCKfPtqfjdZ0CNuGR9UC KZR2sto05ZQpFVt2YmgjZ0lih++LfgPLnyfnWwcRvALm1naYA97QBF4uBeer+YPl beslY0bsiD+Vh85ugMeYETjSCe9WaotYRCPzo3QQNjci05a2VoWRQ5XR8rNZOMIL 3VLnbCotBoS0B6QQbGKUT40+zVJaYi9tywbSOlnUoCLunLYeDLciIF90Nr4uHntd LJdkAa37GRkBCX7xa+Dgd3Fgz54OoHPt3jkz4tdokE+ORosxFhbuUthPFZspiWYE scgUnpOz6aUolYp+GD+hjLaoPb0uh5G7MbEJyCVozAXJib+uVhF/RmmBXeAwWVEO mBBg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQGIrwEQWKt4s8VlI92Z4EJjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xNzEx MTcxMDAwMDBaFw0yOTA3MTcxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxODE5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA1pKzdjLJCeyTbDhaS4ToZBnmZ3SumUoZqjCe7cFLJO1A BB0ZL/rJjkzF2ayfVsHIjgt1iha+NX1yljLDLbSYMf7Qz/4Mq3yHls42I25jGooS klpwtNr/6w2S+/BuatEH+4ZtS59EnU1acEBeDvuqWgO1nwG4/iHMfoVXNTlbXaB5 Ibh0yiiAqIdRS2Bx4Ys/vS7SfWqkb2tZgb1PN5ON0wlc4sw+kyKdxfGbAhV5hfM9 3TGKzKLcgL+jMbDsI1HV1/Dlt+XddgGqDkXdHlUkAX0IcD5CLg9qYJJJ5x67jw03 psTt2l9ciPbMCYcljiKaRlru/N7Ava4E6pK4OhoDyuuJi97MHaWNYs6rzYrHFZU/ AnE12V8Woe5MShQuYtHqG5ba+UyknxirCh0zRA2Pa0WST6zTV3yhCPu/Nh9cOHOu G0ad1R18sRlsBGGLKJhJwG1GPlUAiGfiOxaNneqNarQn4TWsxsd8C4fsmi0TsInQ T9FrsMqRRPHzgXnkWge3ptw6GRz0ujW+dJhs2jQ66v7xwuHUC0GWjfOTlGXPJ6Pj hr2wZX+Ym7nVQMEWezbUrj38QKZuEq0PGk18ezmfxNmOj64YQsjIAbgOjpRK/zGc 4ys2noW7g/sbrBjK+APPwdcNn4NxyTmPff0Tk0hFzqkl1bNWZsnAVeZ0avTCAKMC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQsVinu pC+OrDAaamSyBDCK5eVrHDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAICy0mX3KzhrECxLACOcMt7ffyuvuTm6mvfVeT4C 1b0/7Ch2Pac1DrLhW79rAfw6BxdbPwPDTgbL76PwD7hOB9Elr1wubRY+40cB7BAE reqROB5WYQIzqrH6zUegdBosTEogM7Bs9tOCrZ+12SLYSVVzNpGcADtpToFv9Z0O 0DxU9TKWplB8exvHloUbE/Fy/8XFDMXacG7z77da2Cc+YI8ad4ZPHEwDCd2cyTZT XMh3AMfHvqraHoW/AfYKPHFlx16BysdsXKd8FMJX+sGvELsTo7b0FNXvOgpuvzvH 7Ava59+HthYoCju0i55HzzjXzq/sLjfvlkhachIXTE6NBTalxfVHcTTfzHY49lQi hwff3n3+2IHkDIcJePb8LsI8d9lWQDLem3PvVGmIFrbxW3tBx9sm2ep5mpHN7p1h fDGf6NF3wVxERbpbqELqOLj9ZUJQmKBz/Nx+FbQUqDUtece9QUDOP20tLCcGp7jD GJ8sEZwgB8iSapEawvmgwQJvYDBACIDoNn4C99Poav3w9v6PiYyyxNN6oPly6kQa d8kuhOxrLpjQ3pM2zGttsbwUu+IvQNSif9vRxr44eFK51TGhPCpL83OkfNh2vl0O D07t6WEFqngqx0we9ZwqpLhY8EZFBCoB0QIasDr3KMHlyj8a2RUzgwqsFj20aR8w EdqH -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGMjCCBBqgAwIBAgIRAKvsd/8bQQwHAAAAAFVl2AUwDQYJKoZIhvcNAQELBQAw gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 MB4XDTE3MTEyMjIwMDQyMFoXDTMwMTIyMjIwMzQyMFowgboxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNCBFbnRydXN0LCBJ bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxLjAsBgNVBAMTJUVudHJ1c3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBMMU4wggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDcSG+caYQ4xcvf+dt8bgCEHorO0g5j0H1NOtQzRXgUoG8y QuRbJX9swyKqQZbsc18YvTV8OKA/uSNE46Jvq47TFPojWWTVLbNDqpM07e4EFYKs A9NFzAUngijnf3ivnXA6iNPAMXaEhXmhY/YFjk8NoM7Y1PFsA0oj5hamKQ06iO/j gvBScLmnQ1ju9Qj9IGIg18UL5AJNw0frspLUQBYVrLGaqAy5Nl2BUJKaZ4vnSLvP nk6YrB15mo1phHae10Ba4fx7R3z8IZ/hby4OXTy/KZpu107VEQPAwTuDK8ZXxB5y 0DSzi4vaw27aLrUsq4aFqUo03gEfC31vWW76TNkFAgMBAAGjggErMIIBJzAOBgNV HQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEW Gmh0dHA6Ly93d3cuZW50cnVzdC5uZXQvcnBhMDMGCCsGAQUFBwEBBCcwJTAjBggr BgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5uZXQwMAYDVR0fBCkwJzAloCOg IYYfaHR0cDovL2NybC5lbnRydXN0Lm5ldC9nNGNhLmNybDAdBgNVHQ4EFgQU7kfR hXHx/S23P7s+Y1h3F0lADpUwHwYDVR0jBBgwFoAUnzjEViPDOeigcWzoVEzk6Dqx v2cwDQYJKoZIhvcNAQELBQADggIBACMeFFgsWmC7h6D1v8DJUkOpm/m5UhVhO0hb pQMQKMhKkl744Y9SWG4WNmpQy743TTciEJPZFhc7ke2R6VmK8ZJUqro2awOw1RWZ OtHla59Btf1NQd41vOVdU+qFhs8lFfXg9sK7YHTrfxHtMXLoGnkkamK3xJgn7sXa /zUvUDBTpDCXcpO9SyHoKIQswmkIPpRyIdPF4biRdR3N+9MYmlfqN/Nk3OEZ73xZ AUZP6Gu+f9cEiHTA8NdYHCPLJWyFnIHWK+QuTFEnKYnOYxCeroLBNOO64e8JWZ39 kZ22BBXhHzqOCCczS7JOJTRF+JgvWuxbFwRstj8qf3fE+JndWmq2FC4hTHtpuK5K ENuiRm5gdkXfsXmB+qB6y5gaajiTIMscGIcZIKTe2YdKrLoicvEz8k+loM7favik vzFioTNTDHYGx3mkfElBE7ycY8n+jZE3QBBv33k28MeQi7XNgEaMc4tYwoZIdE9A xVccXTzEQzka82dOkRB1dU0XZId9XAWv+CtNc2TjF6Wgx2seA/c6H8S0IfgQBIV2 8iN2wZns2QFdawkdy3hMUqPnA++kuGhLW3GemsIY5dP/WxY8rd+OfLb/Ks9T1pCd 28t7PQRcQsgkYmouzrOW9ASBvYqLLdhl4y+fFXff8RkPIKMNoYP06WJvRKmky9R/ 41/nXRas -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIQAnmsRYvBskWr+YBTzSybsTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNzExMjcxMjQ2MTBaFw0yNzExMjcxMjQ2MTBaMG4xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xLTArBgNVBAMTJEVuY3J5cHRpb24gRXZlcnl3aGVyZSBEViBUTFMgQ0EgLSBH MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALPeP6wkab41dyQh6mKc oHqt3jRIxW5MDvf9QyiOR7VfFwK656es0UFiIb74N9pRntzF1UgYzDGu3ppZVMdo lbxhm6dWS9OK/lFehKNT0OYI9aqk6F+U7cA6jxSC+iDBPXwdF4rs3KRyp3aQn6pj pp1yr7IB6Y4zv72Ee/PlZ/6rK6InC6WpK0nPVOYR7n9iDuPe1E4IxUMBH/T33+3h yuH3dvfgiWUOUkjdpMbyxX+XNle5uEIiyBsi4IvbcTCh8ruifCIi5mDXkZrnMT8n wfYCV6v6kDdXkbgGRLKsR4pucbJtbKqIkUGxuZI2t7pfewKRc5nWecvDBZf3+p1M pA8CAwEAAaOCAU8wggFLMB0GA1UdDgQWBBRVdE+yck/1YLpQ0dfmUVyaAYca1zAf BgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp Y2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQu Y29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG /WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAK3Gp6/aGq7aBZsxf/oQ+TD/B SwW3AU4ETK+GQf2kFzYZkby5SFrHdPomunx2HBzViUchGoofGgg7gHW0W3MlQAXW M0r5LUvStcr82QDWYNPaUy4taCQmyaJ+VB+6wxHstSigOlSNF2a6vg4rgexixeiV 4YSB03Yqp2t3TeZHM9ESfkus74nQyW7pRGezj+TC44xCagCQQOzzNmzEAP2SnCrJ sNE2DpRVMnL8J6xBRdjmOsC3N6cQuKuRXbzByVBjCqAA8t1L0I+9wXJerLPyErjy rMKWaBFLmfK/AHNF4ZihwPGOc7w6UHczBZXH5RFzJNnww+WnKuTPI0HfnVH8lg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS U0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8 Yh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa e+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO JcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA zjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK ZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe 3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K AYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au ZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg hkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t L0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233 lDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ DSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP ISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F UQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C qnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY RmE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEhTCCA22gAwIBAgIQCDURfR0sdaS2BlhIFGs/XjANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE3MTIwODEyMjg0OFoXDTI3MTIwODEyMjg0OFowRDEL MAkGA1UEBhMCVVMxEjAQBgNVBAoTCUFldG5hIEluYzEhMB8GA1UEAxMYQWV0bmEg SW5jLiBTZWN1cmUgRVYgQ0EyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAvJSDKSNujcBjBxc7yeP1SmjOzg5+j9f3uA/JNc4McAMN9i3POwUfTaS6P5u6 vtlAqJ75MmsFsWVDoLvfxvbAKQGdT1iN01Pwuo07fyQYEkHoxwx6oEo3QpcGYGJ5 y86z9dfYr/bj0L2sjFeEQxntsTRj/fgeK2EIAq5pqsQsZE4DWPnaS+a2rpYbfBzw P+IYQ/6qVPstPp1FrBTnlDPI6IejBeuMg9sRVJNcNFv9FByltWW+8hBUVnTEsT8a QTVhmdn5zyxRG3VDQ6YACumLXVybAugEavug7qhJ6BFMntzDucXhzEMlegVwLkZn XdVJRHqd6wbZoScITy7TEjTSUQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFAaZSaf2 Py2A9FXVzgkhHOVSXr9MMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9jZCvD MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw EgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGG GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRw Oi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290 Q0EuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczov L3d3dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQC6LCak90i8 lsmNoZlJRFwEZwy08X19BvMtiyJXyGMH+HA9Mh4whEnFvzdYPA0vORjztYG86Wkk GP/1F5m16N552xxQHXV0Sh+n+63j59la9bIMJ1L7WiEYUHfh+vJ6Vj+Owvr97TaT +U+A+doy4b3oES58Zb/jarUVXrxMOIAsIhI98PW+o+lyTrHBvlcQnxZagicKCWHk zvrBocfs0KZochHhIQ8fpycqN4T4PD0QHL2ig0RqB55ZRxL/nwI1l2ardGLtb/UG Dq2du6WRoE0GDBo6CBVn3hlw5DH4c3+J6+R1uRkajCLRiCdJ7sgoOIG4ue00hSti PQApp7+N9Ilr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4zCCAsugAwIBAgIQBz/JpHsGAhj24Khq6fw+OzANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNzEyMDgxMjI4NTdaFw0yNzEyMDgxMjI4NTdaMHIxCzAJBgNVBAYTAkNO MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBF Q0MgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASdQvDzv44jBee0APcvKOWs zZsRjc4j+L6DLlYOf9tSgvfOJplfMeDNDZzOQEcJbVPD+yekJQUmObCPOrgMhqMI o4IBTzCCAUswHQYDVR0OBBYEFBKGRGYmCFQmj2U3silOJiHgk77bMB8GA1UdIwQY MBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0Bggr BgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNv bTBCBgNVHR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGln aUNlcnRHbG9iYWxSb290Q0EuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAECMCow KAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EM AQIBMA0GCSqGSIb3DQEBCwUAA4IBAQBZcGGhLE09CbQD5xP93NAuNC85G1BMa1OG 2Q01TWvvgp7Qt1wNfRLAnhQT5pb7kRs+E7nM4IS894ufmuL452q8gYaq5HmvOmfh XMmL6K+eICfvyqjb/tSi8iy20ULO/TZhLhPor9tle52Yx811FG4i5vqwPIUEOEJ7 pXe6RPVoBiwi4rbLspQGD/vYqrj9OJV4JctoIhhGq+y/sozU6nBXHfhVSD3x+hkO Ost6tyRq481IyUWQHcFtwda3gfMnaA3dsag2dtJz33RIJIUfxXmVK7w4YzHOHifn 7TYk8iNrDDLtql6vS8FjiUx3kJnI6zge1C9lUHhZ/aD3RiTJrwWI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpjCCAo6gAwIBAgIQAWMjSO/7fdqiydqdnkLg9jANBgkqhkiG9w0BAQsFADBt MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRGlnaUNlcnQsIEluYzEZMBcGA1UECxMQ d3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgVW5pdmVyc2FsIFRy YW5zaXRpb24gUm9vdDAeFw0xNzEyMDgxMjI5MDRaFw0zNzEyMDgxMjI5MDRaMG0x CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1EaWdpQ2VydCwgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBVbml2ZXJzYWwgVHJh bnNpdGlvbiBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsD7Y RmMy30kfYW2u38l/K7FjoafmRjU0DtSlPRKvBGrV+LqnZZPsZsXK62gBJGkfr7Cj Wa88WzlEKWBui0GYSSHYGBPTQVX+qiJ+p1FKptAjX3OEopy0yxfQZSSH6YDLtzyh EPWXtQ2d7Pe6W6MLZesSdalGdA2A1wgTkyFXxjg9qEs7C28Y5bNM98LNGPlYLQMz G/wW3ZBOwh83nNZ7YZbxxSaHUuPipPgV5Uwi6QkrldGT+To5dnQqC4C+vg7TEAvi 4UimJAVpPRf9xzchsrDjd0c5hwHgTtsj6Pk5nzZGZiMexyJRRD8zxfV2qfgGsHnM 7kHccY4NUI6wPEir9QIDAQABo0IwQDAdBgNVHQ4EFgQUm134UlTQ5rEsvI8qc9lk PL5S/OIwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN AQELBQADggEBAKAHElE4ZmAdgru4N9fau79s6RIVRkWFGBOsB1+vixlz5dI5jWIW wJBURGUAQXyV9oZUEk4Si2OQGED4kByePlXfDl/GaGwcu5K9SP075E4M6xDG3ngD b0oPDMWV2YngQ95PbNmzotlMl3lSNmIo+2HjExD76CRx4fnD0ZuNn7Jd0X7Ff9UG XF4Ha4pxVynZUVYgvTSze/GCZBFI4nPXwOY01dQuRg43v1WjmaauqQALMusdi6IL S/WGxwg4Vamw3XW2szaYKllxYeadPhVu9qS5L+4qMPJXpcPtU6LUarTVOfZJOxAR dr0I4oj1vYJxA7k50nMo1qaevFqPOsh4FVI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIErDCCA5SgAwIBAgIQDTE8pDfmOGWiRNq3KgBFqDANBgkqhkiG9w0BAQsFADBt MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRGlnaUNlcnQsIEluYzEZMBcGA1UECxMQ d3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgVW5pdmVyc2FsIFRy YW5zaXRpb24gUm9vdDAeFw0xNzEyMDgxMjU0MDZaFw0yNzEyMDgxMjU0MDZaMGgx CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1EaWdpQ2VydCwgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSYwJAYDVQQDEx1EaWdpQ2VydCBVbml2ZXJzYWwgSXNz dWluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANrvr0Opo9Mv OxUJnPFMFbyjkENqUx+3eddhRouIYeledhTOv/rFVaEWJUuXfpWRFKSbtOONyOjj WcuUmRYvUSlwaB9L4UXQuztyE8dGXITQKLoy8J2zG2eUUMOq3bA07yuUZsQ6bBy+ LgoDJcTSTpcK17FLgB7aAYcxl4FIln6MYRy7l2VXyGxw2q6QdtDD7pGs7y9/nw7O SqnA3R8SLDo4fyNPfgvQdsKaQz7x4P1+c75jbtHHs4mbn8YIWlUQ3Y+6s4krW9L9 qOPgranY/uOcwTh1y6T6qa/UFw2+xwt3QanLi8torw32DcogalIfTjRixv7ic+xW WWr720jO9o0CAwEAAaOCAUswggFHMB0GA1UdDgQWBBQsICAvGHMr8TtLkgTIy336 ycL0BTAfBgNVHSMEGDAWgBSbXfhSVNDmsSy8jypz2WQ8vlL84jAOBgNVHQ8BAf8E BAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI MAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5kaWdpY2VydC5jb20wTQYDVR0fBEYwRDBCoECgPoY8aHR0cDovL2NybDMuZGln aWNlcnQuY29tL0RpZ2lDZXJ0VW5pdmVyc2FsVHJhbnNpdGlvblJvb3QuY3JsMD0G A1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdp Y2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQButvojvf4fdcBTbarlLg1W 4ipsBEw8aXVhNmU80gDB85qQlqgY09T9bwjSUWDFk+ouzGzGKcSgcJoyp1VRhJfr Sp3Clu8+tjPbT6V7HzP1N1ORRb+VGwzkWxY2p5RvF1ryfLBtz4iLph4Lmeswayt2 HeECMPt7Te16sKvOrFxKL9PAJHyJWyR9RWSxwTV4CSW0jmOAkifpZmKj39eDJS+G 8isFYmsZQoDyEdIp/YYMpBBnKqxPA2ecs75bZkDdxg8UCa1aItWw/9S/JaxnB3GO LN30AKOpEfkT5W2nyWNerUw8YCNcpf4IU28ikkxigW4MRlYD8NbUoIfYJ2QUHhNy -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG8jCCBNqgAwIBAgIPZFbPgPnHoDNUN/U3JQcFMA0GCSqGSIb3DQEBCwUAMEkx CzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxIzAhBgNVBAMTGlN3 aXNzU2lnbiBQbGF0aW51bSBDQSAtIEcyMB4XDTE3MTIxODA2MjUzNloXDTMyMTIx ODA2MjUzNloweTELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEz MDEGA1UEAxMqU3dpc3NTaWduIENIIFBlcnNvbiBQbGF0aW51bSBDQSAyMDE3IC0g RzIyMR4wHAYDVQRhExVOVFJDSC1DSEUtMTA5LjM1Ny4wMTIwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDP4eh7M8UJfdm4LJGKXpmg7MiwOqa1+XVYi5um 65UoGtikYXFDa9kIihcOOg3/nOxDJ8j02lf6vx2c/FfCVG0PT1hQfLiP3lRlVnhY ovx7k6o47iqDOUrW9173EmsduhoO1NmxlmBFxg6XdsKJwHK+atT4Un5DxSNuqTen Z49H5o1UFTT5YMz+F9DJR0EbuQ+Mfo3FBNdg2G3RQD75I65E6THdrG8rdGiFN817 x1EhN269auMRUjnYlYC2IPFsOUFpxJmaomxPEo8vxFL3bWRh9NUk0eIkPL0RNTx+ oEhuLy00LhAFSvlVjKXSKRCcq/iwPFjPY+PEyz7rVU4MqyijAgMBAAGjggKlMIIC oTAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU HsgEbftyYlFgonMkb77yX000kvwwHwYDVR0jBBgwFoAUUK/MB4cVR284xbRl0d6V qunfnMwwgf8GA1UdHwSB9zCB9DBHoEWgQ4ZBaHR0cDovL2NybC5zd2lzc3NpZ24u bmV0LzUwQUZDQzA3ODcxNTQ3NkYzOEM1QjQ2NUQxREU5NUFBRTlERjlDQ0Mwgaig gaWggaKGgZ9sZGFwOi8vZGlyZWN0b3J5LnN3aXNzc2lnbi5uZXQvQ049NTBBRkND MDc4NzE1NDc2RjM4QzVCNDY1RDFERTk1QUFFOURGOUNDQyUyQ089U3dpc3NTaWdu JTJDQz1DSD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xh c3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwZAYDVR0gBF0wWzBZBgpghXQBWQEBAQEH MEswSQYIKwYBBQUHAgEWPWh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20v U3dpc3NTaWduLVBsYXRpbnVtLUNQLUNQUy5wZGYwgdIGCCsGAQUFBwEBBIHFMIHC MGQGCCsGAQUFBzAChlhodHRwOi8vc3dpc3NzaWduLm5ldC9jZ2ktYmluL2F1dGhv cml0eS9kb3dubG9hZC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURFOTVBQUU5 REY5Q0NDMFoGCCsGAQUFBzABhk5odHRwOi8vcGxhdGludW0tZzIub2NzcC5zd2lz c3NpZ24ubmV0LzUwQUZDQzA3ODcxNTQ3NkYzOEM1QjQ2NUQxREU5NUFBRTlERjlD Q0MwDQYJKoZIhvcNAQELBQADggIBAHPgWaDtoRXD/UeOCPeqbJNmHz2Y1IkuulXt UP1B9g/+9s9rw/E3DGa6Z7iLqzK0EEhfQKBZpJirEu6EDR023IQhzRh/lI7BcjMP OfEUM6E00rIS8UZrRW9SnymNrbYTWE8FS8jsfFd/pppY22NolKn3UlUH1RYupDOG Wj/TMxtMmMG7HMQeLj74sK8pEnQSt+VLHWUYabW7VnO/DcZrrw9FPMHUyJElxWgP wngl48Dm/tkTsXwOpnTiZ5XmEEwNC24yLG2y8+QMxCt3Nacrqv5s5PTbsr23BkTl Owy5BwN99ZfmeCcUI8egA4gH3EzAV1a5ONwaIvvODXr1RIwTWiV8WLLSWLywLP/2 m+GUZYLpjMUmLq/qtBGT+KBHGbSjd0fwOysKIN9d2eA0xZwziXBCIhDT+1B4S2U0 dwaZBje6OMo+toMeBPsDtBTuoKFdfq9O9KFTHsnMaHh4YeR3SYzhPoemRpaB4hvX +evVKXQKvtOnATPAzFCQwv10qt3xlREhq8NJOgV0YvELz1LPD1n/VUQU1UW/IjC9 /igroSCAPaZh4krhypMWTifbRl5pymP9njZZOlaTwMnZya9e5+tzuyZ4nBP3dYJf peTjabxa3mNOC1+pXX2LZLdlRyA5s0um58mOUKzTQKJnX1dv050EjBADTBh4P2FR Tlj5QwBS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG/DCCBOSgAwIBAgIQAPWIniGIYRfiVdZFgQVW+DANBgkqhkiG9w0BAQsFADBJ MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQDExpT d2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjAeFw0xNzEyMTgwNjI5NTVaFw0zMjEy MTgwNjI5NTVaMIGBMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFH MTswOQYDVQQDEzJTd2lzc1NpZ24gQ0ggUXVhbGlmaWVkIFBsYXRpbnVtIENBIDIw MTcgLSBHMjIgMTctMTEeMBwGA1UEYRMVTlRSQ0gtQ0hFLTEwOS4zNTcuMDEyMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtJsL6WuEG97ZSgGAL/+zO5PL /hqpD5gDpuI7lGypmuI52v2/H9KDJ2DjHQjw5sk6vwdJ/mqFyHzuMTvywwCd2FQR C9Rhd7G3EbNAkj2AU2sIFhiLI6CaVmOXEwS5igw2Txb15xVXqjyHwOHaUdX007zy 8i7rlSqFdrcDSFxZfVhHcyhE54vbDqgYzcd2D8kCQsjn0nuUXTYXUHGgvFoiLrX7 ITTQPp7bWbsdGNOv7S6tgscdFony4u0JVHH525FbUUuf90+GQ78Imwt1KTa2Tlpv bHYxRUEmxWuqJw27zY8Lixdz3b/6/GvVf5n7k+av9AlHXQhifHUSO0SGZHZ2ZwID AQABo4ICpTCCAqEwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0OBBYEFP3+/Y6c9H4tKdEoYW2g3KdQduP+MB8GA1UdIwQYMBaAFFCvzAeH FUdvOMW0ZdHelarp35zMMIH/BgNVHR8EgfcwgfQwR6BFoEOGQWh0dHA6Ly9jcmwu c3dpc3NzaWduLm5ldC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURFOTVBQUU5 REY5Q0NDMIGooIGloIGihoGfbGRhcDovL2RpcmVjdG9yeS5zd2lzc3NpZ24ubmV0 L0NOPTUwQUZDQzA3ODcxNTQ3NkYzOEM1QjQ2NUQxREU5NUFBRTlERjlDQ0MlMkNP PVN3aXNzU2lnbiUyQ0M9Q0g/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNl P29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MGQGA1UdIARdMFswWQYK YIV0AVkBAQEBBzBLMEkGCCsGAQUFBwIBFj1odHRwOi8vcmVwb3NpdG9yeS5zd2lz c3NpZ24uY29tL1N3aXNzU2lnbi1QbGF0aW51bS1DUC1DUFMucGRmMIHSBggrBgEF BQcBAQSBxTCBwjBkBggrBgEFBQcwAoZYaHR0cDovL3N3aXNzc2lnbi5uZXQvY2dp LWJpbi9hdXRob3JpdHkvZG93bmxvYWQvNTBBRkNDMDc4NzE1NDc2RjM4QzVCNDY1 RDFERTk1QUFFOURGOUNDQzBaBggrBgEFBQcwAYZOaHR0cDovL3BsYXRpbnVtLWcy Lm9jc3Auc3dpc3NzaWduLm5ldC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURF OTVBQUU5REY5Q0NDMA0GCSqGSIb3DQEBCwUAA4ICAQAXV/Z7yw0Z0R7pZ3jQPbw5 r7KKLka8XZBV6l3PAsqxPhaWOkpNf7VbQE9sbKMCpqV9TdZ0wPMjekXS1Ii9xRbU REz8sCKMlfQGtpiDzttKi88+ss79+1rulmIBWqBQN6ubf7b+LZjKroraLljv+Kp7 Z6vZ34lLQKRSCzNo8xg04/VtQwKfd8c1tMavtc0Su0R276wF8ix9Ddi8rmPBwmKv jP/bCQwBVgFuVUGInFeUsn/S4svs5YjhCBTfz9Xsqx4riAyCDV+z+CigCTFk6GwP lxoshOfC686DlYAa4oJVSCJ8wtSUos+yY696mv8Zn05Cs+De8zfxTxsA+yJW6t7F uCh6vf3cULBh9PkmG2jGHu9PvMZ1JGp+gq3DqRUWhPYbsDUHT7vC7s9RYi5IPqTw Qhsf5YdM/Uq5lrlu67sXKqBhlU8TXS76ESU+76SKJ1Ub3l1nWv9IcJfetC/fnZnb +Wz5rst/qsWONVcWkY7DczQy0D4UUSsLcV0HjbsqotZyhGa+mBKBOKKC2c8pYYvk lOIHTOiDpSMF+6S2UW0VVpdDqq4CKHRkOjEI8oySryww5Yf9A9Fkc+Ki6RZPwwoh pQATKSkgGFB21zTtCa7+G3AghNAmPzPLGW6Ivx/NFVJgdzp3b4Dz/JROWShVmjAf xrlvJs5aAyn240Dd8T7F0Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG9jCCBN6gAwIBAgIQALjfg3D6pU52wIhjWom9rjANBgkqhkiG9w0BAQsFADBJ MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQDExpT d2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjAeFw0xNzEyMTgwNjMxNTlaFw0zMjEy MTgwNjMxNTlaMHwxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcx NjA0BgNVBAMTLVN3aXNzU2lnbiBDSCBRdWFsaWZpZWQgUGxhdGludW0gQ0EgMjAx NyAtIEcyMjEeMBwGA1UEYRMVTlRSQ0gtQ0hFLTEwOS4zNTcuMDEyMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAugv1YdAdGpjKgjiMSYTduGb+3XDhI2cm gTcm0EGEIOhR3YiEsJIQfG3e7GqTvbkkBEaxt5IBnehz2gcIkUlo4LYfi1shUzCu PLvy1T463uWbC8fIe23JzW4ck6wHPGOQm4sIKyLfZnmKdwoOiULUNY1dJxOr3GTZ 1rK+Ef242kbSwNw0yXolVgfqjMOkatBPJkpofXpPGB/PNTokHNzN0I/9ljzcEoPs ArJh0+OzZZcdQt3hjxzpDg+WHcFViuZcssPuUpi/RADGis/k0ntnA8AAN3T0p8B0 10Zmkpro5fBGT0VVKNzlcByBHIfj9x4iHZRI9UXTWdxzmoEVDd66fQIDAQABo4IC pTCCAqEwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0O BBYEFFTwW1IK0IwJ2wfltremwnXruLkFMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 ZdHelarp35zMMIH/BgNVHR8EgfcwgfQwR6BFoEOGQWh0dHA6Ly9jcmwuc3dpc3Nz aWduLm5ldC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURFOTVBQUU5REY5Q0ND MIGooIGloIGihoGfbGRhcDovL2RpcmVjdG9yeS5zd2lzc3NpZ24ubmV0L0NOPTUw QUZDQzA3ODcxNTQ3NkYzOEM1QjQ2NUQxREU5NUFBRTlERjlDQ0MlMkNPPVN3aXNz U2lnbiUyQ0M9Q0g/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVj dENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MGQGA1UdIARdMFswWQYKYIV0AVkB AQEBBzBLMEkGCCsGAQUFBwIBFj1odHRwOi8vcmVwb3NpdG9yeS5zd2lzc3NpZ24u Y29tL1N3aXNzU2lnbi1QbGF0aW51bS1DUC1DUFMucGRmMIHSBggrBgEFBQcBAQSB xTCBwjBkBggrBgEFBQcwAoZYaHR0cDovL3N3aXNzc2lnbi5uZXQvY2dpLWJpbi9h dXRob3JpdHkvZG93bmxvYWQvNTBBRkNDMDc4NzE1NDc2RjM4QzVCNDY1RDFERTk1 QUFFOURGOUNDQzBaBggrBgEFBQcwAYZOaHR0cDovL3BsYXRpbnVtLWcyLm9jc3Au c3dpc3NzaWduLm5ldC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURFOTVBQUU5 REY5Q0NDMA0GCSqGSIb3DQEBCwUAA4ICAQAZHgH/iFsDsxi3ug0fs/Ck3+s+WyA5 jauQb6HEjsSTK9sCtfl6tVhtz6KWVg14DmHeORwKPxrsVcnJGhkr8eaxhMsR2XEl Y81gs68myFzp9iLFe0tUpC8L1EZtRjIx6tP2O8nq/2UI+2njp9PFdGEPpRGHNM2+ rEJG4tScrxFqbGpgsf78btdNNX4zTyWGCmx8cXc++j0vcIV71fRO+gAZT7lg+TMh nUA5E1ikWUhrRIlFKYYQABOzfAbTLhu6gOTQk3G6cjAtvIqYhEd7pVmzZB9Xoo+S ggWM/gKNbF+pW+sVgDLw1WFnTKfhgoMYa+H5RDTATgi45RneqCHuvPuFJWRBPDft n3f3X2M8ao5oSavHQc2CHEB5Aijca8AtJojln0YKr3La0JU8NexigyXQ9eNxejWY 98OUQCxNMx5PACHOSYTMZlThqag/qT4gltjFd3Dmpy0m/I3MjTQskkdfGdgBRaDF J/uSwCg+GKyNGePgRti91rVGNnzbp9LtncFF6/stRFxBKmxeL0TgNhBLsz0fyZGt yodxxwFJwrsnMJxaDxrdfcBbz6NCgRq1aJjAZIwD9LHV9qEus90d1UEwr0FeyKCA sAN2o9FlrPyKF2Cwz1Jm1cub17M0kjgHuPtPi/OrH+wlcIRlKeSle87ZtiDvtF9q D93wxpQiQGv+eg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuDCCA6CgAwIBAgIJIrmxKyiKBBiXMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTgwMTA5 MDYwMTI5WhcNMjgwMTA5MDYwMTI5WjCBjDELMAkGA1UEBhMCSlAxJTAjBgNVBAoT HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNFQ09NIFBh c3Nwb3J0IGZvciBNZW1iZXIgMi4wIFBVQjEqMCgGA1UEAxMhU0VDT00gUGFzc3Bv cnQgZm9yIE1lbWJlciBQVUIgQ0E4MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAsiqUtMxdh/F9QLu+PFoglmnAVs8CZiZIwPdnlgrJMrpzwLYSnxHDI7Xf ugTGnvIESjyiSgrEiVK9iMHKBkYXNKjrMsf+zgUJ/d3VwyPtTBwVU57q2B50Hkco uBnC+6SqsF8Os6ier2DPhDF5WbQzj64QzALBor8j+1ZtV62hGc5JQHUmdX6XoVc8 WYDui+1/VtayTAfUHCahC6LYP/JYx9P1OjCCCz8k+yhwoS1CrDxKVU/5QhAoekW+ THjjSVuveZTtvmcuGpPbVN5PMS+LGth84h8l23cNlUnp0O+OQMpobqh3ATk8xIqO kUnNbAh2Z3o6/EXhwXNOJTE4w2A/sQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFHYr 2Y3MNTYyRQXfnoxqF9Ez3AMHMB8GA1UdIwQYMBaAFAqFqXdlBZh8QIH4D5csOPEK 7DzPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC MEAwPqA8oDqGOGh0dHA6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJv b3QyL1NDUm9vdDJDUkwuY3JsMFIGA1UdIARLMEkwRwYKKoMIjJsbZIcFBDA5MDcG CCsGAQUFBwIBFitodHRwczovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0Mt Um9vdDIvMEAGCCsGAQUFBwEBBDQwMjAwBggrBgEFBQcwAYYkaHR0cDovL3Njcm9v dGNhMi5vY3NwLnNlY29tdHJ1c3QubmV0MA0GCSqGSIb3DQEBCwUAA4IBAQBriuNr L5Sm0k0lEW+36t6reGcrsHZo5pKjLCF4Dp5v8TRKBlM3vXPc4+ULhK3m9JHye44k oB3n3qTVxFncJOnBM5sj54waW50yg3pLDkyiI0heLuuTBBUlkEksuHmc+579XJJS qgribsqw6cSYL/x+v+VUqtTmSP+BRhiaF1E2n/bKRjoLSJW7+KbtSNw98XkfZen7 JCq4asaAIP2xRpunJu9bpGBNbntQjf7n/M7sVFiPJHqpZ80ankQ/awW14cyV6Wyh unOomQZKtLrvbjrO69Tqz1lE8Fr1v9SG3HME88fNTC1qntNJBRuoR030f+aVYM78 Hlv1/LRHrGB+iwfC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWjCCBEKgAwIBAgIIC1C7rAKtMNUwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMB4XDTE4MDExNzA4NDMyMloXDTMwMDkyMjExMjIwMlowgZUxCzAJBgNVBAYT AklUMRAwDgYDVQQIDAdCZXJnYW1vMRkwFwYDVQQHDBBQb250ZSBTYW4gUGlldHJv MSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzE0MDIGA1UEAwwr QWN0YWxpcyBPcmdhbml6YXRpb24gVmFsaWRhdGVkIFNlcnZlciBDQSBHMTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALlRIuDw2gAphmPncXt4pu+NFPBX 8wpI1uCd+a8WXy9IXt+scnHZYwaX7geJ9AYAG59o+oW9IOeeYLvMSC9g/CNgZb3M d1QJuk4jzasBuBO3/Pq5MEM0eylrGgBiMjKBFeysJgxUy/dM2Zan4hecDxhJfkas Qqq3X3wNw914sgvAehfb2bWGlaYuDtA2sjK8piLR30qeMJS9ZTEHOnlX2fFHs3Yd JLFpGsou11c2OskWOnhHhtVtHWj/jzVo0/v5WCDTUzv7FvEPGSpMXvIbRJTRfhJN 6p+YF58rsfrQwFmGUhgf4RHR9qG869JsGS16/2IfixVOwiLriKZJS+A2zD0CAwEA AaOCAdUwggHRMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAYYlaHR0cDovL29j c3AwNS5hY3RhbGlzLml0L1ZBL0FVVEgtUk9PVDAdBgNVHQ4EFgQUI7TMjr4g+STV qZClCiY5jtWVBZYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRS2Ig6yJ94 Zu2J83s4cJTJAgI20DBFBgNVHSAEPjA8MDoGBFUdIAAwMjAwBggrBgEFBQcCARYk aHR0cHM6Ly93d3cuYWN0YWxpcy5pdC9hcmVhLWRvd25sb2FkMIHjBgNVHR8Egdsw gdgwgZaggZOggZCGgY1sZGFwOi8vbGRhcDA1LmFjdGFsaXMuaXQvY24lM2RBY3Rh bGlzJTIwQXV0aGVudGljYXRpb24lMjBSb290JTIwQ0EsbyUzZEFjdGFsaXMlMjBT LnAuQS4lMmYwMzM1ODUyMDk2NyxjJTNkSVQ/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdDtiaW5hcnkwPaA7oDmGN2h0dHA6Ly9jcmwwNS5hY3RhbGlzLml0L1JlcG9z aXRvcnkvQVVUSC1ST09UL2dldExhc3RDUkwwDgYDVR0PAQH/BAQDAgEGMA0GCSqG SIb3DQEBCwUAA4ICAQBcH7Skuw1LBX3VYD2PCU8XOPYkdD6ydHs5HpzGg6YMji7L cFagKZpl+G28jXlrOMFwev9uxWXwx81LXYdS7bk2C+WqOra8/ztEKZ+ikUnqfn7b Ft3BWwdSZvo68eO4q2u2OR/pdHT9HDKishdJvsy3OlfwMubJ/e4F+XFldnZLlLcO WORPjpqPWmJJzMl4ZE5/xlU7oya1+TZEuzidiVcjOrMQNxD3y+YlLx4TQsdWgTMK AVLvqf6R1yeJwqaf3b50qX/phc2Jb0faQsQJzNMYEm6IwfO0WRcdNhwetVujAtrB /BMMVP99x27EUwN7qJu+mILHRJFFqMnKcrj1lmA//15cqR1Z3c7FA56Qi89CQ84P E0RX2xwgvyTH+vgS6ZK5R8DkdpgrYq8wGrmMCb1wDXY7YwrLpUUWBkA3dj4LLaIX bsvwtyEamx5gL8YJzjgeW/XjOwZnFsqRjVEequ8BzogpsU/J8pUEiJestK43QiAk g0Vnprp8ApJ8f25jtw1AMBpqmmckVrXYa4+HB/1+0uM3/7Bj1Bxkq4Cc+fb9QWOA VOFi1IR9VO757ZdhzdR7qEdCkAfpru4czq2RaKhIhSPY80puCYbm3SrKKeMI6I4W kddgKIGdlAa0H97YIZAL1a+w/UN0zF8LjtW7HidKKFyCtIimFuD7Lhr2EqoLcw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHFjCCBP6gAwIBAgIIXSPE7q6H9uIwDQYJKoZIhvcNAQELBQAwXDELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjEtMCsGA1UEAwwk U3RhYXQgZGVyIE5lZGVybGFuZGVuIEJ1cmdlciBDQSAtIEczMB4XDTE4MDEyNTEw MDQzOFoXDTI4MTExMjAwMDAwMFowdjELMAkGA1UEBhMCTkwxGzAZBgNVBAoMEkNs ZXZlcmJhc2UgSUQgQi5WLjEXMBUGA1UEYQwOTlRSTkwtNjc0MTk5MjUxMTAvBgNV BAMMKENsZXZlcmJhc2UgSUQgUEtJb3ZlcmhlaWQgQnVyZ2VyIENBIC0gRzMwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC1eMhxwuN0wuOHZ4BKXo/1Jar/ 1cepiIFcOYt1Gs5s5KLyUDnM+dYABhUz0WIf7vauVvPcjxs8Nd++Zimfg7siGwu+ 1bImvRYGpIs2iFtGomnQK2n/mN3Wiuzwbc9KqVOBvkQPC7X/TaNrKzmIJetBsbQt mILsCgv91vObjRoQZlKul250jZiAaWAuycC4FcPYDd0tTk1yUx0q/1+uR1fNBVMR a9TeR+uovy2XHZmrxND0M1w4KZ2EoaTT/XP6bNxK9K3907LPytkdUQ8zCyOV6/mJ YLyoytLPTT4lUqtpY/ij7yvEN0DtQmeukmVSuwnaVLYPHETDKlpzbfZXy+Y1PT1x zz99Yi0LiX49uUZj+G3t9SrocL3NJIca2KoYxLM7JQOaqEkZeTWwD3ieHMp6OvEk j4w+7qUN0hTZ7zzkW6mSdO8gKRmSOfCvyC+0N3vGQcSgrgS8rOB+FuoLgqMWmrsw ZhxCxi3f+Vjt7u5kcjb/RTkpJf4RkBKMVeEB52EaBZcpUOhnIkeO8XZh+sywZV2b Wsc3mpuXAnk7fkg+UQLzXjLycQIpRWvj/M0PYMxenBWf7NAYCMsFkBsoz9QVguxA jFHONpue0Z9y+/8/Phtnb9w8XB9mEiemeS5wqorCViKfV999I3AgVZHxenrebsFs 6cmZPEuSvEWfIhkytwIDAQABo4IBwDCCAbwwSQYIKwYBBQUHAQEEPTA7MDkGCCsG AQUFBzAChi1odHRwOi8vY2VydC5wa2lvdmVyaGVpZC5ubC9Eb21CdXJnZXJDQS1H My5jZXIwHQYDVR0OBBYEFPGOaY4+TmFUGs7WkpTSgoV9+rlAMBIGA1UdEwEB/wQI MAYBAf8CAQAwHwYDVR0jBBgwFoAU/2h1Qn36b8dakzifNUTQqi0AsokwJQYIKwYB BQUHAQMEGTAXMBUGCCsGAQUFBwsCMAkGBwQAi+xJAQIwXQYDVR0gBFYwVDAMBgpg hBABh2sBAgMBMAwGCmCEEAGHawECAwIwNgYKYIQQAYdrAQIDAzAoMCYGCCsGAQUF BwIBFhpodHRwczovL2Nwcy5wa2lvdmVyaGVpZC5ubDBEBgNVHR8EPTA7MDmgN6A1 hjNodHRwOi8vY3JsLnBraW92ZXJoZWlkLm5sL0RvbUJ1cmdlckxhdGVzdENSTC1H My5jcmwwDgYDVR0PAQH/BAQDAgEGMD8GA1UdJQQ4MDYGCCsGAQUFBwMCBggrBgEF BQcDBAYKKwYBBAGCNwoDDAYKKwYBBAGCNwoDBAYIKwYBBQUHAwkwDQYJKoZIhvcN AQELBQADggIBABdi9GVB0mEyyIPp4zJ6HOx4pASw2ar7CJ72LhXcFB41TAnIIppH rjRLGLSpaG0gjMN1Sc+dYG2jtxjX1CXyw7Ubt+6DLKkDJxQBmFAx3/f5MGTigklT AwTEk8qw+YS0yiUaF11n0zeU00CfWskB5mPpE8jiVHkkPDB+g0SDyneW9Zxqp6Uv l+wxnSkFZUBKNru0WM6MDxZ/VsMgOlozsuK2oX4sVJB5ZVykQRfV8WdoyB02OADT 5NLu9BAYeG5p9EuO7hS4Y/9iNUFwE7lMb4kEnlmoW6AIzLculLhNyXDRd26GK8v+ Nq4ItHjxN/RxEfvBTPyUGi40DrdYDdJvnBlcPJLq64MHrF9hYdf85bpCJPWvJsfr 7TsBmqRKNSVqSG1KGUWAlzotbj+lLwRllHXt+ztFXRBLI5FitLmLhXlkecMyRbm2 +MGVLgvoabMdCV84z55ZTjGOBIS8y/0zlNsALCLWbIQkUQeUZ8R2in2bp/L7YPMW uZmbBcrqqatQW9RzXFabjHKMYAoqplZ8MyKO8CoTmU6Hse60OARkoY1uUvdZKdfq dQg4rqIiOXkv1W0wXDP9yaFd+IJ0ADj4Z+Kg6Jui6YRw03MKK6y8o7dc9G1YESIT NAasDxIwJ6+M7cDxfIjnFEhvt+H+CuSJ5r4DlNMzDYFr4oanQVUVzZhj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE3zCCA8egAwIBAgIRALCiDACdpLXrpkTHnCKCcMUwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xODAxMjYw OTA1MTZaFw0yNzA1MjAwOTA1MTZaMIGAMQswCQYDVQQGEwJMVjEZMBcGA1UECgwQ RW5WZXJzIEdyb3VwIFNJQTEpMCcGA1UECwwgR29HZXRTU0wgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxKzApBgNVBAMMIkdvR2V0U1NMIERvbWFpbiBWYWxpZGF0aW9u IENBIFNIQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChNYfMeoqz Yfk4VROgMsgwrPjg5JxBvFQW1JywczszE5CThoywHoPbcgbPWMRzLcHMWoc3YmNj 7Tf/qtLoBRLwmCRo1XkioYc4HvAqlkgsYcS13rhaipbwaYuGRXcGMCFmrGrs41ix TWkdz/y05wp6GupSluOqyDLlI2w6KqEsOlnYPR1tOXT8N4YOZt0ARQvXavglRuVB OpyCBxoLYR53A8+k4oos44L+iXmZgANIljHEcK8bUQ7FLCW2mpnh7BKGmBVtLJEt gh1wH7/dqDsJNDaRGkaPuFR5aEvW4cWzXMwBUcnUP/FKa8FFacm0PurUijH7rQDH 2MzNfhZLV9pHAgMBAAGjggFNMIIBSTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud DgQWBBR4XZFct6cbR4Dm55xCqJTdWd9OpDAfBgNVHSMEGDAWgBRUmd2b/+inDqMZ nVu+QlffMPyPMjAOBgNVHQ8BAf8EBAMCAQYwOAYDVR0fBDEwLzAtoCugKYYnaHR0 cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwvZ3NjYXNoYTIuY3JsMG4GCCsGAQUFBwEB BGIwYDAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2VydHVtLmNvbTA0 BggrBgEFBQcwAoYoaHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBsL2dzY2FzaGEy LmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0cDovL3d3 dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQAy2CwO+CxF2Dfe0g5y A4N1cbsvXdhg75TrAeqRinO0NFg1sD7L59fMgCadbJ4UWXlJob5gQ/rEr5d+MxMy tQh62LTPoYXivu2203H/fHaskjZ1YjAwdskl/myo/2GgYmfp4Kpw5ObRl5hzBCTI 0c8HCb6F1RbJ+6YoZB9ePMtiG4TuDfi7IswNUtfTDuG1Bdn1rJyTL/sbHjlku1Uj NmKzezqQzxfy0iyy5Ts2YQeCD+ekjh9b0i0HgH4x4ZW4Edn0B/t2qhqkoVwjbhwR HbRqnbFbqBSJxYfwXKrFJDeH005tYK4ifGs60J1ByOfmiwAT59HI2peNOLNRumbs /VEO -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE4DCCA8igAwIBAgIQJ8bJgdPRXQ94N3Eh+CM+ADANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE4MDEyNjA5 MDk0NVoXDTI3MDUyMDA5MDk0NVowgYIxCzAJBgNVBAYTAkxWMRkwFwYDVQQKDBBF blZlcnMgR3JvdXAgU0lBMSkwJwYDVQQLDCBHb0dldFNTTCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTEtMCsGA1UEAwwkR29HZXRTU0wgRXh0ZW5kZWQgVmFsaWRhdGlv biBDQSBTSEEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzVnLdFqd FjZLYAyHaJmzIY02q8GO6lRuNDNd8CP8goZB6MVHinMZIW9aqAVM5vmISvIaCEYz c10nSRJ+/W3s1o1WJuw1E6BgDUczgilkUPz1F2h9LBI/0J1zYBNxwZCe6vPBlWj5 qLgz4zNXq4yCVW+4996hwgsMq0aklmP1YUD1mp71kPO/IeZ4SffQVn66A+gA7aHG 397Ub0d0v0zAP1+OEDM2eTba5KhDQI3ylGR7o//B9KSiYWilhQHDnp+cU9vsjp2C DLbgOxkofYa74ZZBBXEtaOxgJgOzH+lMI0UPpL/wTDdP+VOPRuBPz2Gn/gWDDvqx WVwWlxmIJANBVQIDAQABo4IBTTCCAUkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HQ4EFgQUDGqlqb1t5zgV0p9yOK1sdimARZUwHwYDVR0jBBgwFoAUVJndm//opw6j GZ1bvkJX3zD8jzIwDgYDVR0PAQH/BAQDAgEGMDgGA1UdHwQxMC8wLaAroCmGJ2h0 dHA6Ly9zdWJjYS5jcmwuY2VydHVtLnBsL2dzY2FzaGEyLmNybDBuBggrBgEFBQcB AQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5jb20w NAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9nc2Nhc2hh Mi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6Ly93 d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAN4vdz1dJ+7Qu5L2Z dJs4J2SJn2SEjXGJYq2WQgoJ2G7EYjxDJU1KjsjJWzArn8Pjq4ZQmZ4zAq16O4TL FfYKhc2MjmBXq/qkyn8PkH1HymrMsGxZnRjnSusAPEBaaEfYWy2H6vCVVYtKmN13 qXlENdru0k5KyxmXbJQfLk02fjmlFYiN3xtlF/ZVJpWjMCJ6spi/wsQXLidWO3my 0scMWxHaeMTkhta7zNw72fjxu358zIYH6buGD7kUySM3ZVdY94cRwdn3fIddXvkD JsmsA2u9/9TcQ5pngkLzkVSuEM+Jf9QMc+gZV03HpofFVnCQHhY218CZFWky2M3I MOB5Jg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE4TCCA8mgAwIBAgIRAMVX6sMefiH7Am8g4Ja2utQwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xODAxMjYw OTE1MTBaFw0yNzA1MjAwOTE1MTBaMIGCMQswCQYDVQQGEwJMVjEZMBcGA1UECgwQ RW5WZXJzIEdyb3VwIFNJQTEpMCcGA1UECwwgR29HZXRTU0wgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxLTArBgNVBAMMJEdvR2V0U1NMIEJ1c2luZXNzIFZhbGlkYXRp b24gQ0EgU0hBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMm7v3EQ +7OZa8dXKt662wIHQ6TX7XxCIbZ83jCBGUgZL3NO5Z0J+BtUwlidEFw/Wn2OKPqe qndHhHyJR5GG556gLdCxYqVj9IBSvJYTJfXdlqSlByE3RAp0tFn7bnfjW8MqUJm0 p+P+GSWeH4mSNToP/xtnhW8h994TrJVnt4LQz3gLh3TG6ynLT00vlNeaGOAXnIii EGiZ33W3eiI4OMh/9M9twZ6SOUE47E+Y462xI0zWHw6AKytnHV0EbDz2iDJCjW7r IjK9yDf3e/jQj8+OqLUObhZol0FUwnCQEoqwqAj50030o2vwOlDEd4IekrpAmfeV f+lM9pCIaokGdvECAwEAAaOCAU0wggFJMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD VR0OBBYEFDgtueEnJwEqmCoK8Mz5NswwS7CPMB8GA1UdIwQYMBaAFFSZ3Zv/6KcO oxmdW75CV98w/I8yMA4GA1UdDwEB/wQEAwIBBjA4BgNVHR8EMTAvMC2gK6Aphido dHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9nc2Nhc2hhMi5jcmwwbgYIKwYBBQUH AQEEYjBgMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0uY29t MDQGCCsGAQUFBzAChihodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvZ3NjYXNo YTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRwOi8v d3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBALDhLZHooMj/f7hv 7HxQC1XVyBGflU4/cDT1wPYdb0PxKZFSR0UInCg0SKn38hvcuvJ4buUpb/jpaMjN LB7PoikICc/INwiNEEBZ2SR0I/MdujmQRgKnxPuklhpQLKlmE1ED5BsjEm5oMzim MN59j6I23EHQ1BE+M3Hd93NMkXtSl0rHY1RQUn8XP6nE9zU6BlGeDK0dvYf0Vome ZJhhsL3F97O6/pEEGltEX/HF6yVQsr7hQIIjQiww10rCFu/0jTL0rjZt7GbnKncU Thu5gjQxhp3EeeXfrZAnVUrhxFKyxi6tBvrSPTf6r7UxpPjGH5jnJ5azSL/LyRIK cMu0PIc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEzzCCA7egAwIBAgIRALDv0CqBvxzon3oYwpTkwzwwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xODAxMjYw OTIwMTRaFw0yNzA1MjAwOTIwMTRaMHExCzAJBgNVBAYTAkNOMTkwNwYDVQQKDDBH bG9iYWwgRGlnaXRhbCBDeWJlcnNlY3VyaXR5IEF1dGhvcml0eSBDby4sIEx0ZC4x JzAlBgNVBAMMHkdEQ0EgVHJ1c3RBVVRIIFI0IE9WIFNTTCBDQSBHMjCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAJcB/96FVLcfbrXt1DCD8q2AL2W3ZYWp SVTAKQwYIDT3h1tDwC2amGQgtXImPMO2w2/1ALZsKrsQp34m9W7YQMrsh/OIiutG Hl5VuDSEfSEJfk4N9m6lj8OEiYW0rOHKidH+OOhKU/D2yzM9I2x0JCXAaKhot42F yHWKO1+TOOVXF4pgFVnLgmiSYmUP5D/dlgMuxaDs+JdVX4Yg5NTwztHA1eWmkIyV 7hxW3sjsOtKkCE53N2S8fAZ7zmH1yQ3mMqsyAnPupa99dcMXWDrZrYFqp09SF+15 FCWB7B7811aUkgMtAtH43kyqux2NdNdUFgFu67cljaImqj084I7SDNMCAwEAAaOC AU0wggFJMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFIf+cKksRTX/4Qo2 HdJlyk31neeFMB8GA1UdIwQYMBaAFFSZ3Zv/6KcOoxmdW75CV98w/I8yMA4GA1Ud DwEB/wQEAwIBBjA4BgNVHR8EMTAvMC2gK6AphidodHRwOi8vc3ViY2EuY3JsLmNl cnR1bS5wbC9nc2Nhc2hhMi5jcmwwbgYIKwYBBQUHAQEEYjBgMCgGCCsGAQUFBzAB hhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0uY29tMDQGCCsGAQUFBzAChihodHRw Oi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvZ3NjYXNoYTIuY2VyMDkGA1UdIAQyMDAw LgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMw DQYJKoZIhvcNAQELBQADggEBAC6NUsN0v8zzs20WzQvQSH2O/ZgKb2iPJjQHYs4d PEDZCw/i8uXq3juDv223U85QMXbXq9Cz3lsmbhoyI1flABaOdeyAbaWuTcTC2e47 HCJ9eRHe07HZjUHXoKKl7h3WN59C7CQF9ZO1WeSjKgGPYKNte2FBnwx0n+4xwsHf PDjs3GcWml0R6Ciw5zeycStQFe9Tthpe1NvoLGZwKd5Wq5/vh5fKfC/1+GYrSybK LUGZNMhjHfU2IQ2FV3xbfclEtkmI+03RvcfmnqJnPMX+dIWevODk71+8Myl6kQ17 GgkxQCU+5yPgFGXCCG9jS2U4bsmr0ipftj4Tb1/XabrQHgo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEzzCCA7egAwIBAgIRAJ6ctpQmxFzEMG0+HMKnnvwwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xODAxMjYw OTIxMjlaFw0yNzA1MjAwOTIxMjlaMHExCzAJBgNVBAYTAkNOMTkwNwYDVQQKDDBH bG9iYWwgRGlnaXRhbCBDeWJlcnNlY3VyaXR5IEF1dGhvcml0eSBDby4sIEx0ZC4x JzAlBgNVBAMMHkdEQ0EgVHJ1c3RBVVRIIFI0IERWIFNTTCBDQSBHMjCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMDLbbV1dYvEftQMNfTaz2J+Vb7YW6eG h7vQoLFXmltElELtbNFxu+shcLWMiFLjSfcaXc0r8bGq3VW9kok0N3J/Apc90onm eUfbCBZBXAEyIUeu8LsU8naac6uAYSNQAL4eeXQ4fjoQCAU1dPyHx9OSS4ypuMe6 QTXAlvGYq2cskHQE7W7JeakPl3zks8R8ZEjbZbM3PXneBjphV4eagOqTTg06fmjZ NN95oryp0gNiC3Z3vJ2cKSmbcbQnXpRLo5+h1E0llyP4FP4EuLG7k8u7WL0x/5P/ 8kKycx7zv2vR7oPLkfJQs4clpFxS/pV1gQ/N7ytaoNz0SCco52qFjk0CAwEAAaOC AU0wggFJMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFCJLk+U7Rq+pAesD 28qag7hcrw3xMB8GA1UdIwQYMBaAFFSZ3Zv/6KcOoxmdW75CV98w/I8yMA4GA1Ud DwEB/wQEAwIBBjA4BgNVHR8EMTAvMC2gK6AphidodHRwOi8vc3ViY2EuY3JsLmNl cnR1bS5wbC9nc2Nhc2hhMi5jcmwwbgYIKwYBBQUHAQEEYjBgMCgGCCsGAQUFBzAB hhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0uY29tMDQGCCsGAQUFBzAChihodHRw Oi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvZ3NjYXNoYTIuY2VyMDkGA1UdIAQyMDAw LgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMw DQYJKoZIhvcNAQELBQADggEBAKLTpe4QKlf4Vi4Of9lC6UWcxuT5q9sh+7rzmLrK jIiHvfen2ecxvylGGBhfkUXDArCVrNfKfQsPrtGXPnJHy5h8TgItDWOrfcQlm60r yxK3mCaVHFQFZKZ3LIyV92VoMnA265QKISLonbeYtGwz47Tc0avHBbBMQB6C+pHQ cR8VpwghvgB8Lxnoa3+TQ1gpFNxr58h4V3nxlnHTZCoQo496Kk1OCO1I4vH3pamV oeMWCotR1lOI8wS1eLyDNJlVYDBhr4mVQxjgzNkeXeH9G5qTbOr+CrO9mBK6XQ++ 4fNdvEratxOMwiBsDgAm+qx+uSG3+nK7IZNgFMc6aCG2Vhw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEzzCCA7egAwIBAgIRANX4Po3a9nyIKeiQFreHfRMwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xODAxMjYw OTIxNThaFw0yNzA1MjAwOTIxNThaMHExCzAJBgNVBAYTAkNOMTkwNwYDVQQKDDBH bG9iYWwgRGlnaXRhbCBDeWJlcnNlY3VyaXR5IEF1dGhvcml0eSBDby4sIEx0ZC4x JzAlBgNVBAMMHkdEQ0EgVHJ1c3RBVVRIIFI0IEVWIFNTTCBDQSBHMjCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALNPfXyROlIMdwEmVT0Nu3eQlWj6+Hty 73vWjqUWUVOfWdGFWstQ8jvy6unc1G6b81v1+er9viceJLhVttPBxQ5l4ekWO+wT kATYKDRM1e529qFI+rEjOwCQz7lwYA7nLXhfpv6ml068tSarpgr+sLyY8UyhUT4q jtSRfR7U4Uq3afGgCFzDirPJI/0GjvBo1v9fqtyvBwAl5LddhmN0T5u2ufTRs3tN IAxcWFyWe618/s+ZNA5DTNo+onBJTZ1Dxb/a90moZzyfP7niQ2Q//2s+f4DlNDQ4 moI0M/xg5vwQQ/CKW5ofxB86TDrNrvcHvo8yieWN1uTp/SvEnbEvXBkCAwEAAaOC AU0wggFJMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLNjEYy6JTesOKDc N0TrbQ49PMiLMB8GA1UdIwQYMBaAFFSZ3Zv/6KcOoxmdW75CV98w/I8yMA4GA1Ud DwEB/wQEAwIBBjA4BgNVHR8EMTAvMC2gK6AphidodHRwOi8vc3ViY2EuY3JsLmNl cnR1bS5wbC9nc2Nhc2hhMi5jcmwwbgYIKwYBBQUHAQEEYjBgMCgGCCsGAQUFBzAB hhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0uY29tMDQGCCsGAQUFBzAChihodHRw Oi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvZ3NjYXNoYTIuY2VyMDkGA1UdIAQyMDAw LgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMw DQYJKoZIhvcNAQELBQADggEBAISNtyVOURlXscYXg5hahYysadf0abiUpMmREnu5 rYx4asAdLMncnVyUGFgfn/2cQXoZROnWGcYmvtEJbLaAK9k/CcZZFLC+JTJpdLw1 lxW0KFCqhEl6O1vu0YkzCaTpKw+9jm+AJvsxBHIJgk3v1h+aO7eAskM+PWjIMI86 6M5wM7CAESLJ8E+gps9jX3uYeb/9O3HLTUucvgBxAxiRNu/FloX3bbc1VmB6q1pH wntPTTyqntFt30Kss0b2veA0JcPF0YMXotRYYeFRf9KeY629IBN/f30uYfN8XmaG nM7ukUvdQSMgrLQYuRR+FA20Z9DRqMl2IBo51/ddvYFHbAo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEhTCCA22gAwIBAgIPIAYFFnADF4h6C+DTSsOvMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xODAxMzAwOTQ0NDRaFw0yODAxMzAwOTQ0NDRaMHAxCzAJ BgNVBAYTAlJPMREwDwYDVQQKDAhjZXJ0U0lHTjEmMCQGA1UECwwdY2VydFNJR04g U1NMIERWIENBIENsYXNzIDMgRzIxJjAkBgNVBAMMHWNlcnRTSUdOIFNTTCBEViBD QSBDbGFzcyAzIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvhdn ADWMXBV7FNWXbuDJb/ArPMpquqv+BIGQxjyylMz/zxJ79eMMQ7ZbkeYWBbuKE4Oy MlvIWjIFRhK2E5Q0RZ5sIlJAte/ERwEWX8RWwDFaMeXnPqKUxQzW4PHtuczrKxZ4 XhPwmsXeDCQBi8lRfFvuJtPXMTOlFMcFshPbv1F9Tw658X2KYG/JJdDJgE4Tk6iK dbvzbdAZUthSj9H9ivu0VhfsXRIPgBMkoHtKc6M1Qb9f0t384WXO/0yh583Ro1Tw ZBh5uuZwhlM+Xedk9x2Y8lxQ5t1DdciByDuMcnqktM07/QLIM2o/6hLKQgVFSdHt ItdJQY0+x+XuQ2kpIQIDAQABo4IBTzCCAUswaAYIKwYBBQUHAQEEXDBaMCMGCCsG AQUFBzABhhdodHRwOi8vb2NzcC5jZXJ0c2lnbi5ybzAzBggrBgEFBQcwAoYnaHR0 cDovL3d3dy5jZXJ0c2lnbi5yby9jZXJ0Y3JsL3Jvb3QuY3J0MBIGA1UdEwEB/wQI MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFOCMm9slSbPxfIbW skKHC9BroNnkMB0GA1UdDgQWBBT13Lv7iR7KeIF0bLZKbCVNVIF+BjBJBgNVHSAE QjBAMD4GCysGAQQBgcM5AQEFMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cuY2Vy dHNpZ24ucm8vcmVwb3NpdG9yeTAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vY3Js LmNlcnRzaWduLnJvL3Jvb3QuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQALeM3tQ0MW nhrYrVM60Qb3GQDNluO2jLatYyrIIhUHez8niUoYKgOHP0BPET1MTzN2GhcaJNTn hmaJMaNBvomyjp40uzpohzt0Id8jXMvMiJ7qlIxnBJVhraiJV7Bh2qG/nMplulO4 7st8bAZQPyzS2krXyrKQZfIdwmzPVfbMPrlWEU0TTeIgU8vcrcrVotpjqyKG34Iq uPTsxCYYc7C3sNb6Kc3tuDmH0KrPKOK/rxU6QLB1G/eRPToBhpOsp7Z5bAvpBlR/ OejWJ3UBGFMTg+KrnIm0T9gV+b35P7quMvj5UBPAU6ABrCQhZqsrljMaj86q1g8p wCmpQ97elXf1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEhTCCA22gAwIBAgIPIAYFFnADGFeSYBrLdeEnMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJ R04gUk9PVCBDQTAeFw0xODAxMzAwOTQ2NTVaFw0yODAxMzAwOTQ2NTVaMHAxCzAJ BgNVBAYTAlJPMREwDwYDVQQKDAhjZXJ0U0lHTjEmMCQGA1UECwwdY2VydFNJR04g U1NMIEVWIENBIENsYXNzIDMgRzIxJjAkBgNVBAMMHWNlcnRTSUdOIFNTTCBFViBD QSBDbGFzcyAzIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyXLW SO9JeHURmd0Grn1Mf2zZFymVCmWxH/JykD09GZga6uDoc3A7xt3f1TxCng/YHVCu QCOOl+UbqKDtbNyCecaw6yU0F/6Fy7pcDGXuWiGwA3oi4LixbDfV7Sh3C7447GBK AzzlMXIfprTUI6Sb/Q1IU52TZq5U6bWS2QdZq2uYC02sbi24eCIjnvKTLvKuj+Fw 3Nwvzkt1EswtKVEmNHAmY/bgZQMLxu6xJGb3cKd4SPrgNRJ9eriQwpg212EQyUXN wZy2sCwHKCE3X3HR1wGxzKBcNEAjdUrt2Hi7PANZslreXyrOspVqTiES2hr6Oje5 mB+ZmXigcO+FXq0QYQIDAQABo4IBTzCCAUswaAYIKwYBBQUHAQEEXDBaMCMGCCsG AQUFBzABhhdodHRwOi8vb2NzcC5jZXJ0c2lnbi5ybzAzBggrBgEFBQcwAoYnaHR0 cDovL3d3dy5jZXJ0c2lnbi5yby9jZXJ0Y3JsL3Jvb3QuY3J0MBIGA1UdEwEB/wQI MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFOCMm9slSbPxfIbW skKHC9BroNnkMB0GA1UdDgQWBBQ2O6KeJYcqD/2aSjwn2sunecMMfzBJBgNVHSAE QjBAMD4GCysGAQQBgcM5AQEGMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cuY2Vy dHNpZ24ucm8vcmVwb3NpdG9yeTAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vY3Js LmNlcnRzaWduLnJvL3Jvb3QuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAoNFaGOZjP 60JD4jFr6tsb8zknLClE+jzOrehP6oCoIPr6vKsCxwUTKKoYlKBHGcn/OlsgIMFE kFs/qVSZFYwSMxnmk12PEYP8NzPCKk/Dvx7eAS6ZfrdbkkfKh8mABYx5QOwegFeV yvyxwPM5CirRrGoD/IvW+B62oaW30dKYxCudPTfrFTJP8/U/Ye5jVoq+sg8UcxZ7 OEntwU5rcNaXgcElfx2cKbOl6PfbN8ojaZmRfuiODv2z33otg3rg+nbNDo1/lx/b U1nB8DvtkF+EXB0Sh4EZeTrbRO5KwDa+G7LLNdOORzOxZXlAdwXsNsbC+xFg3+q8 5paQwSQvbyl1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHFDCCBPygAwIBAgITBs6C2Z+zsYDCgQIDFKLRx2QAFzANBgkqhkiG9w0BAQsF ADCBiDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAwDgYDVQQHDAdD aGljYWdvMSEwHwYDVQQKDBhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xMTAvBgNV BAMMKFRydXN0d2F2ZSBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN MTgwMjA2MTIyMTIwWhcNMjgwMjI0MDUwMTIwWjCBkDE5MDcGA1UEAxMwVHJ1c3R3 YXZlIEdsb2JhbCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBLCBMZXZlbCAxMSEwHwYD VQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xEDAOBgNVBAcTB0NoaWNhZ28x ETAPBgNVBAgTCElsbGlub2lzMQswCQYDVQQGEwJVUzCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAMRO7orfWjfmz6Y6qoAmDp2lqCJcdvbRQ8w18rl1JE3j f/1CScZLrnLg4RDm8JiRcvFuvoMXn/XNUWy5ICG57tjG2nO7jvBuXfvbdkGA+foN 3yJKMTX/PmmGlN4qpzFtsB0kLrP14/0TRGeJB7qDfAFH0ReFk0ftQobLBGBOpEca +bv+LhcTe40/uNUSK2yQ9GpIw200mcsD3B9c29Im4tSZFuA2o1vnEeizYW5M4sPX Hu7p5ZCxjJrXVNqWUPM38rShhMUNL5uaVYWoi7TG5JXbg0Lmt2nq1k5nnig9Yp/W lAFooWXjKQzHf/z+XZ57bqPe7SzLW5pzpZdSmY2VRybAwEmzMjCXgHiP2ru3TpAD +giakPDoz3ZmbKjwYKZ5PmnOmXx0Z2GloO37MjamjPor/+fZohfyma7VAQE8znJt I9MVoRN3G3gW/tuT3jXfzYdFBlfGoO7OYyLN1LK5YBKH2qXrCHD8rG2DauBt7U+w fOvwfkp8FcdTnfQ92Xe65U3Xdu0eCgQJbChxZtWhhLnbY6xhmwAWyJ1my+Im72Kx GP/XcA8SH2sz6/k0782BjRckDuFpVVpTNYl9wqe/tuOrZhWPapOsRlfsDTuhgGu5 2inM9sU3CAzmFE85zoRQFZQSof3kFN2rUZF20bmTak99cBNLli6/ja3+KntpZ08d AgMBAAGjggFrMIIBZzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIB hjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwHQYDVR0OBBYEFHM4IMZH babGL3tQ4EDe3sedR958MB8GA1UdIwQYMBaAFJngGWcNYtt2s9o9uFvo/ULSMQ6H MD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3NzbC50 cnVzdHdhdmUuY29tL0NBMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwudHJ1 c3R3YXZlLmNvbS9UV0dDQS5jcmwwbgYIKwYBBQUHAQEEYjBgMCYGCCsGAQUFBzAB hhpodHRwOi8vb2NzcC50cnVzdHdhdmUuY29tLzA2BggrBgEFBQcwAoYqaHR0cDov L3NzbC50cnVzdHdhdmUuY29tL2lzc3VlcnMvVFdHQ0EuY3J0MA0GCSqGSIb3DQEB CwUAA4ICAQBwnSHECaf+hfGrm3Cg+aRr57ytoOSzI1DjlTNcM7k4uSt6kJRPHJ4c ldIujMaETV52RgE6ykaMGkuIwQOIsLI6SXwjU1f5gXFUbDTS3KTWc/jwQeyLmdOe hvc+wBSFv8d10Sx/Qiti8mqsTqr0+N94Cx01+SkiWxWWoSZOAPkz8DMQGlD4yndK ceTMGtQ03cLnD/36Mv6tz/Ds9l/OExrJGGxHD0tmYwYwBZpPHm7BBY2ZzycVxLcg +uuggcX1pg5MhJ1rDyod+7X+ilvTgH7ftHCmxvR7viMLwSUuytZ05zb2teRQgU+8 iWnPEHO/ADm5VD1Zb5Rx0579/YEENBJtGUPPJzo+JEpiZIOIlwZ69ETWWNCLZr0V voi+SDl65cr+dgR9JreJ2I4W9FzS45ruxYEC8LGKEmV46sAk1YLbnIBmhehAKy9t P8RVz3QXYJ6rLOAuXF7R2eVV0SqfivW9bVzvBZTUTFsbdSMBAAF1BJjdRqYR63DI cQASY7CRoUiak1NTgPkzeV8VcNJmUt8c2eKJIifqBAjquH6+6UXs9Ol0aMPn6v0y B+TSuxhX2sSrpna9QcOh/QyoR5Hvcd81rZSbMc7yasKoUMXviotV1SfEqs3RU5Ts wnU4NHPn5ITRiuh5VMuvB/VnjnPC953u5uqAGtZ8BkC7X9cu5E0rMQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpjCCA0ugAwIBAgITBs6C2aIKN5fNh46z2qQdCGgK9zAKBggqhkjOPQQDAjCB kTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGlj YWdvMSEwHwYDVQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xOjA4BgNVBAMT MVRydXN0d2F2ZSBHbG9iYWwgRUNDIFAyNTYgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwHhcNMTgwMjA2MTIyMTIwWhcNMjgwMjI0MDUwMTIwWjCBnDFFMEMGA1UEAxM8 VHJ1c3R3YXZlIEdsb2JhbCBFQ0RTQSBQLTI1NiBFeHRlbmRlZCBWYWxpZGF0aW9u IENBLCBMZXZlbCAxMSEwHwYDVQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4x EDAOBgNVBAcTB0NoaWNhZ28xETAPBgNVBAgTCElsbGlub2lzMQswCQYDVQQGEwJV UzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKXHfFxFDVI6uYWZlWciFFKtYzuJ +IBhot3PQGikE3sjU8d9dARkZCkInqmDyP/+XiLzgrYPMy7NS8lZcRsE5p2jggFz MIIBbzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUE FjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwHQYDVR0OBBYEFAwlVqqzYgakv+7gGxtX zC8s9g1QMB8GA1UdIwQYMBaAFKNBBqyQbdFK63WlShCZs7Ghi0r3MD0GA1UdIAQ2 MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3NzbC50cnVzdHdhdmUu Y29tL0NBMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwudHJ1c3R3YXZlLmNv bS9UV0dQMjU2Q0EuY3JsMHIGCCsGAQUFBwEBBGYwZDAmBggrBgEFBQcwAYYaaHR0 cDovL29jc3AudHJ1c3R3YXZlLmNvbS8wOgYIKwYBBQUHMAKGLmh0dHA6Ly9zc2wu dHJ1c3R3YXZlLmNvbS9pc3N1ZXJzL1RXR1AyNTZDQS5jcnQwCgYIKoZIzj0EAwID SQAwRgIhALahroq1NScrFeCvG5uMgMKH/bo190D+Mkh2ZIojrUOfAiEAosFXFE73 0WLRPjX2uOkLhXuA4cQEb1R1oeGDH4MNVOo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4zCCA2igAwIBAgITBs6C2aMxWUUwAGeBgpOH5A28tjAKBggqhkjOPQQDAzCB kTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGlj YWdvMSEwHwYDVQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xOjA4BgNVBAMT MVRydXN0d2F2ZSBHbG9iYWwgRUNDIFAzODQgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwHhcNMTgwMjA2MTIyMTIwWhcNMjgwMjI0MDUwMTIwWjCBnDFFMEMGA1UEAxM8 VHJ1c3R3YXZlIEdsb2JhbCBFQ0RTQSBQLTM4NCBFeHRlbmRlZCBWYWxpZGF0aW9u IENBLCBMZXZlbCAxMSEwHwYDVQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4x EDAOBgNVBAcTB0NoaWNhZ28xETAPBgNVBAgTCElsbGlub2lzMQswCQYDVQQGEwJV UzB2MBAGByqGSM49AgEGBSuBBAAiA2IABKcVGieqBjW3BuVza9VhkBlpGLHLZqQg I0GXaTpt5CogNWz6BmlZ1yAPjRnDUVfVwl57ATRtV7u+5TPFzKZ+RheFVc0iA8vl Q2JINGRz8XLDaivvuygQtFKSzCWn4e66cKOCAXMwggFvMBIGA1UdEwEB/wQIMAYB Af8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATAdBgNVHQ4EFgQUMFfit09gayJACkNfT/oNzXO8JCcwHwYDVR0jBBgwFoAU VamEidLBMr0Yy2ymB07I552+gpAwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYB BQUHAgEWHGh0dHBzOi8vc3NsLnRydXN0d2F2ZS5jb20vQ0EwNwYDVR0fBDAwLjAs oCqgKIYmaHR0cDovL2NybC50cnVzdHdhdmUuY29tL1RXR1AzODRDQS5jcmwwcgYI KwYBBQUHAQEEZjBkMCYGCCsGAQUFBzABhhpodHRwOi8vb2NzcC50cnVzdHdhdmUu Y29tLzA6BggrBgEFBQcwAoYuaHR0cDovL3NzbC50cnVzdHdhdmUuY29tL2lzc3Vl cnMvVFdHUDM4NENBLmNydDAKBggqhkjOPQQDAwNpADBmAjEA6pScrGT+SruK7iON 7iDJZfhQsjfQIhaq9sHiEXd89B8ibWOb57no/K265dPxeuALAjEA27NTMZM344eT X3df9B22dY5ZshsUMIiRcMo1K4B/GBO8SIA0jParkHS5g4WO5K7O -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHGDCCBQCgAwIBAgITBs6C2aaXA67+XTfRiFjHQCawBDANBgkqhkiG9w0BAQsF ADCBiDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAwDgYDVQQHDAdD aGljYWdvMSEwHwYDVQQKDBhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xMTAvBgNV BAMMKFRydXN0d2F2ZSBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN MTgwMjA2MTIyMTIwWhcNMjgwMjI0MDUwMTIwWjCBlDE9MDsGA1UEAxM0VHJ1c3R3 YXZlIEdsb2JhbCBPcmdhbml6YXRpb24gVmFsaWRhdGlvbiBDQSwgTGV2ZWwgMTEh MB8GA1UEChMYVHJ1c3R3YXZlIEhvbGRpbmdzLCBJbmMuMRAwDgYDVQQHEwdDaGlj YWdvMREwDwYDVQQIEwhJbGxpbm9pczELMAkGA1UEBhMCVVMwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQC8BzZtA3eWejFOGHc2DLgex6P471dLWIIHSlrF Y4a2BCtzAd/VlpQ3gslWnTgthOmK2/hCc+WSaOLPVZzZf3lGnxbb0+Y87Kx+nS1m IfJ/4OR6o8XLMLoCTAI1jsWxggiB4NBMqsW2xXQ5VAvBb66KEQYbshNlRpTbtBFq Eed4YIvCdjbnCUOy1zubgVHUVyCFHzN4XPjEQCtT5vZM576Lt10Je9COnqG0CtPU QNP2tjnSmOOYdWcVRZ0UqXUl2fMBfmSDHd8902foigjpP04AYYbq6AetqEgqdvQP xz5pVbZqzy8UrE/s/raJLFyTuIAYVt18M0whSgWzGgUWkq2xRqbfn7b1hd56dwRb R7pKc51FyTbeocnKlYLC+Dlzp7iKQ3Pb7WHRwLhaJB7u4CzwqhUxHc0xplMYsq92 MbZ6WN5L5mI7hxY8gLMOR7vNX9CKz9XcYRS01iCDe5Y/9muW8bzGyNXLX1YaHAy4 +6ncksb3Y3RUKj3f0+T4nbiRISmGazravJKSssBLP3kPa9h5aX+Vd00eL+Q7sXrh FO7xz+oWtOL5rfVszyc87JQvjw1sDHA710nViqzUE1bJZNe61EXdCb/RV+Wsu+rO cAMSr5x2j/wW875sh+U3EJmTzdEBUBxHnBD2mDTyonT7wL47TRXTEO1IaS4mVbnv o0jWvQIDAQABo4IBazCCAWcwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E BAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMB0GA1UdDgQWBBS3 /VNzOCaKcKuTyoupCOrH07fj/TAfBgNVHSMEGDAWgBSZ4BlnDWLbdrPaPbhb6P1C 0jEOhzA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9z c2wudHJ1c3R3YXZlLmNvbS9DQTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js LnRydXN0d2F2ZS5jb20vVFdHQ0EuY3JsMG4GCCsGAQUFBwEBBGIwYDAmBggrBgEF BQcwAYYaaHR0cDovL29jc3AudHJ1c3R3YXZlLmNvbS8wNgYIKwYBBQUHMAKGKmh0 dHA6Ly9zc2wudHJ1c3R3YXZlLmNvbS9pc3N1ZXJzL1RXR0NBLmNydDANBgkqhkiG 9w0BAQsFAAOCAgEAFXwfmELpEGKUguzVTMix79XbUnkfLa7IXcqBOrwOWEF1V8F1 xGY6jLlUTtoEXRYZwCpqOK/i4m4nmWCYE45O7URR8nqeFffceTi62t4Yvh6LkC9g Unj3aChLiO/Zdxilq6vfsXO0mKafrGtZXwjyskS250Pj9DsANs57QqvYN4hqbplJ zc95p09OUvEhPiyRyx6FyY28U+3X6+mSNMJWd4Nhr+3HtvmItLIXP2JCLxuYtu/K 6nKcpFCFFKeF8K3PWpjsAb0hfXL4vc3WfyCYsQnvJeisyAh7yEuge2iDwl1/xXIo EOAyyYAxvy5UnzcAa0Z2lwjptve+jZ4gQ+A1ioYUavR3pSfBNzuJW30nZCWFadKc NXOPoAPkK8JLxgRBH3JboeBCXG6xgy/pXrTjyhW7/SS+Z+7eKkp9jgdTVQ12yUtc CiYWUuM4l240D/z+s03WOEcLTluESwFkJhzs3D9i5crTL72uSkDDmlh8HXoPAyYO l3Mn9cGWhd8M8IeQRXmb6O7gvvQZDoSXDVDbjBKcW1lFpi0wBxIBzLaOi4CX4OhI JHJ/H3duOMaltuzXLSLkc26jwHzMeq8seQRSXraXJi1t5oBKlmEWFEgq6xlH7mLW 3TOqS19cuiSWl/CsnlLGaW8MH5YHmk+MJxQE1BcLBs6ciapvHlhLEd9EUpU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqDCCA0+gAwIBAgITBs6C2ai1fBBIQ5lNrNeeKGM+XzAKBggqhkjOPQQDAjCB kTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGlj YWdvMSEwHwYDVQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xOjA4BgNVBAMT MVRydXN0d2F2ZSBHbG9iYWwgRUNDIFAyNTYgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwHhcNMTgwMjA2MTIyMTIxWhcNMjgwMjI0MDUwMTIxWjCBoDFJMEcGA1UEAxNA VHJ1c3R3YXZlIEdsb2JhbCBFQ0RTQSBQLTI1NiBPcmdhbml6YXRpb24gVmFsaWRh dGlvbiBDQSwgTGV2ZWwgMTEhMB8GA1UEChMYVHJ1c3R3YXZlIEhvbGRpbmdzLCBJ bmMuMRAwDgYDVQQHEwdDaGljYWdvMREwDwYDVQQIEwhJbGxpbm9pczELMAkGA1UE BhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQmHWo0mogvX1J61xysTqsn 6qV06wxUH68/QJ2aDIka6beTrDoTZv3mIkyPxFTPy+9idjgSAERlBsDirgO2/NiY o4IBczCCAW8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwHQYD VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMB0GA1UdDgQWBBSv+Ju8XTSl3tA+ FCldDY4lrbClhTAfBgNVHSMEGDAWgBSjQQaskG3RSut1pUoQmbOxoYtK9zA9BgNV HSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9zc2wudHJ1c3R3 YXZlLmNvbS9DQTA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLnRydXN0d2F2 ZS5jb20vVFdHUDI1NkNBLmNybDByBggrBgEFBQcBAQRmMGQwJgYIKwYBBQUHMAGG Gmh0dHA6Ly9vY3NwLnRydXN0d2F2ZS5jb20vMDoGCCsGAQUFBzAChi5odHRwOi8v c3NsLnRydXN0d2F2ZS5jb20vaXNzdWVycy9UV0dQMjU2Q0EuY3J0MAoGCCqGSM49 BAMCA0cAMEQCIGa3JyBYlXxRN5GIIulLaDxnANNRnY4j1Et166CCC5h+AiAVUlzJ IJTfUDBU7jnSTKSw/F+bLIPvaC6frMZv0h+RTA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHCDCCBPCgAwIBAgITBs6C2a0wRlzyJpfyRrEB7JKVOzANBgkqhkiG9w0BAQsF ADCBiDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAwDgYDVQQHDAdD aGljYWdvMSEwHwYDVQQKDBhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xMTAvBgNV BAMMKFRydXN0d2F2ZSBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN MTgwMjA2MTIyMTIxWhcNMjgwMjI0MDUwMTIxWjCBjjE3MDUGA1UEAxMuVHJ1c3R3 YXZlIEdsb2JhbCBEb21haW4gVmFsaWRhdGlvbiBDQSwgTGV2ZWwgMTEhMB8GA1UE ChMYVHJ1c3R3YXZlIEhvbGRpbmdzLCBJbmMuMRAwDgYDVQQHEwdDaGljYWdvMREw DwYDVQQIEwhJbGxpbm9pczELMAkGA1UEBhMCVVMwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQChh5brvvk/kFUZwhlUhqdsUmsMCBjzYqBBLnTyNrKPr4nd S9s2h2JvA+9TY7NnJc/Mq1eN5V6zqvbn/LN3c8W06f76xrVvFEKs5SzCefUS/V3Z C18dgwXXFrP+RgfK2kqfTHGIPrWoRSnUiLn3iUNEBtJ06oXjAqAMnAyL5AzD+eHm ZzRK/yCw/gMPnVp2S7Dstka607fS4fW9Sl33mOMNwJRxEjQWHHR25PAb4muP6wjN vmoLMgiDMKseHSFVtC7SpmO89PsrUV6MahKJrZcAfquAyoO1zR2c2eGaCI/m8oSx 3B7KiMZJ3NZims/siMp/5szemsutf36WJ31nmr7PqLJGJdVpoxbLckWIhZnNYSFm /pTutpNONqpyYC2gGSXdw5LuxU61913SbAPpk8DZiHi3WslHBo26ghXG++sgJUGj htKZhiYlp8uD21WTP6/60wngpXyCtt9cpHxW1lXmqcxwe2J4/2S3xjHz1dC6BKxb r61HCPVrbTD90CZUpMI8JPdsVbz5eegv+SIyybHxZe4S0D9Kv5pgWfqdXf0BAiJC TbGwYmFr4uisKhkfMThyOgWEH+CRBzQqdZREQ5lTIlVyzi3jGPuu9Q6brAS9U9Ue QhUwX8TtY8Igfo8HlhjugDpy6WvDYQ9i+tG3AC6v8sJLdOOU83Lr+2C1LEF5ZwID AQABo4IBYTCCAV0wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYw EwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFIaZQQzOP7aMcEnlkwfwhgcd LXqVMB8GA1UdIwQYMBaAFJngGWcNYtt2s9o9uFvo/ULSMQ6HMD0GA1UdIAQ2MDQw MgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3NzbC50cnVzdHdhdmUuY29t L0NBMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwudHJ1c3R3YXZlLmNvbS9U V0dDQS5jcmwwbgYIKwYBBQUHAQEEYjBgMCYGCCsGAQUFBzABhhpodHRwOi8vb2Nz cC50cnVzdHdhdmUuY29tLzA2BggrBgEFBQcwAoYqaHR0cDovL3NzbC50cnVzdHdh dmUuY29tL2lzc3VlcnMvVFdHQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQAmn0jp +lNp188KxjKQZtpJ3mixLmuqGdH6SVpRs40BYQg/68xOPH3C6AJ17tqE6IwZMW9s lgiO4B7khR3ESA6Sct3zmkA8woR/KJVzzegjscHhtQUifQ+Eb9Gi0ORNnetGV+5g 5vlrFZMptBRGUxXMo2xa+Z/NTyimpMopfXj7qCW/nQWQbzvkQGchK9IokyqV2wra tX68/P3zleG+LLwzoJd5AhHYSXWrIRJpClZHN+LQKkbI3MYW7+upo/1e9HEmFKxu 5SFV3nuQm5wSOsz/ZtIL1AS8IoZYxcSe1Q/yuV9GjnxtL1jkPbzsBx4eBGxUrcIe sBat6SI8G58uHTpIPpqUxRYsg8w0FdjK3kNBB5QWDeXiDxzqIRzA0iE1kHeTXRZ3 7qgGXUcce7ciW5KqeRApjQbD5BSZG2EKkQ7aaOhvxK0LiuxHZnjPW4/fdEcaCuku MT5qMDiF2U85V9BvanEy/xkYn4I2UeK4EdSXe7q6j+CIJz9WnoLQDbIS04GqIWe0 VRQUlx3idUWYSJU/SG8KrEHhlJLmgSjshCwtT6qo4vHwT5WcWDLIbjMqgL1iQ6JS 4gxXuOGia3d0I4/wec5x23EWwx9V8BtDJ8N7NDeRNmZ8RXOHSYJsVQYIQuFUEXE1 v3WMSIxuyQMyR5FYSCG9xnKRFzNmiPngDil5IA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCA2ygAwIBAgITBs6C2anY4pg375C+r1ncZVG+1jAKBggqhkjOPQQDAzCB kTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGlj YWdvMSEwHwYDVQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xOjA4BgNVBAMT MVRydXN0d2F2ZSBHbG9iYWwgRUNDIFAzODQgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwHhcNMTgwMjA2MTIyMTIxWhcNMjgwMjI0MDUwMTIxWjCBoDFJMEcGA1UEAxNA VHJ1c3R3YXZlIEdsb2JhbCBFQ0RTQSBQLTM4NCBPcmdhbml6YXRpb24gVmFsaWRh dGlvbiBDQSwgTGV2ZWwgMTEhMB8GA1UEChMYVHJ1c3R3YXZlIEhvbGRpbmdzLCBJ bmMuMRAwDgYDVQQHEwdDaGljYWdvMREwDwYDVQQIEwhJbGxpbm9pczELMAkGA1UE BhMCVVMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATvG09PrsO8UQZhH5Zw54rwgcUw KjC9D2V3myjD5WOa8uxdTL8PzdwPk4TCcSf6UUG1Tt74j/I+vBOi2tgMcDt68Zld vTj+jZT1BBYTQtYh6/dOUjmiapQU5XqoFMRNubGjggFzMIIBbzASBgNVHRMBAf8E CDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAgYI KwYBBQUHAwEwHQYDVR0OBBYEFDoXwH5iO1eguEDKzDRHzZZ+/AmIMB8GA1UdIwQY MBaAFFWphInSwTK9GMtspgdOyOedvoKQMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgG CCsGAQUFBwIBFhxodHRwczovL3NzbC50cnVzdHdhdmUuY29tL0NBMDcGA1UdHwQw MC4wLKAqoCiGJmh0dHA6Ly9jcmwudHJ1c3R3YXZlLmNvbS9UV0dQMzg0Q0EuY3Js MHIGCCsGAQUFBwEBBGYwZDAmBggrBgEFBQcwAYYaaHR0cDovL29jc3AudHJ1c3R3 YXZlLmNvbS8wOgYIKwYBBQUHMAKGLmh0dHA6Ly9zc2wudHJ1c3R3YXZlLmNvbS9p c3N1ZXJzL1RXR1AzODRDQS5jcnQwCgYIKoZIzj0EAwMDaAAwZQIwMyHlVCVMacxP O0fC+uc4M7Eq1F9woaWBmLSSNC6EWe3nShMqsR9HrNWrOHBHucNWAjEArwrzEM8g JkR4iZxbyYNIn2sNEkNZt2pxqJn4G2cDDDFfOarykKVzP1aJ9OMdYUvs -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID1TCCA1ygAwIBAgITBs6C2bB6F8xTdhV4EziaKTCkSjAKBggqhkjOPQQDAzCB kTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGlj YWdvMSEwHwYDVQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xOjA4BgNVBAMT MVRydXN0d2F2ZSBHbG9iYWwgRUNDIFAzODQgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwHhcNMTgwMjA2MTIyMTIxWhcNMjgwMjI0MDUwMTIxWjCBmjFDMEEGA1UEAxM6 VHJ1c3R3YXZlIEdsb2JhbCBFQ0RTQSBQLTM4NCBEb21haW4gVmFsaWRhdGlvbiBD QSwgTGV2ZWwgMTEhMB8GA1UEChMYVHJ1c3R3YXZlIEhvbGRpbmdzLCBJbmMuMRAw DgYDVQQHEwdDaGljYWdvMREwDwYDVQQIEwhJbGxpbm9pczELMAkGA1UEBhMCVVMw djAQBgcqhkjOPQIBBgUrgQQAIgNiAASxlBEflNumTKsypgdOscM2x6ZRpQGSyB4B hJScRQI81UhZvzYSwxPWcxNZwFQoV457HfqR51pviJnHltRS8MJhJ9Q9Rf1sSmy4 W6SPsM9qnBjwfBRxghByIsEIaTW/PKyjggFpMIIBZTASBgNVHRMBAf8ECDAGAQH/ AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4E FgQUp6etGGS1u/oGGEfIwJ68Zf9pAWAwHwYDVR0jBBgwFoAUVamEidLBMr0Yy2ym B07I552+gpAwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBz Oi8vc3NsLnRydXN0d2F2ZS5jb20vQ0EwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDov L2NybC50cnVzdHdhdmUuY29tL1RXR1AzODRDQS5jcmwwcgYIKwYBBQUHAQEEZjBk MCYGCCsGAQUFBzABhhpodHRwOi8vb2NzcC50cnVzdHdhdmUuY29tLzA6BggrBgEF BQcwAoYuaHR0cDovL3NzbC50cnVzdHdhdmUuY29tL2lzc3VlcnMvVFdHUDM4NENB LmNydDAKBggqhkjOPQQDAwNnADBkAjA6fS1jRjt+DvnWSI58v4lX+8DCXbdEhDaB bBOS/rXwS/ntsFXqTf0B90GPv3AWlFMCMBbz6nXMwX0jKRkaFZOZx9tvwUapdq7M 6jYpT/NnAzH68x1t3/7ysZ8lPuKIqAwdKQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDmDCCAz+gAwIBAgITBs6C2a9TFCOEe4X7Z3kyqvgFCDAKBggqhkjOPQQDAjCB kTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGlj YWdvMSEwHwYDVQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xOjA4BgNVBAMT MVRydXN0d2F2ZSBHbG9iYWwgRUNDIFAyNTYgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwHhcNMTgwMjA2MTIyMTIxWhcNMjgwMjI0MDUwMTIxWjCBmjFDMEEGA1UEAxM6 VHJ1c3R3YXZlIEdsb2JhbCBFQ0RTQSBQLTI1NiBEb21haW4gVmFsaWRhdGlvbiBD QSwgTGV2ZWwgMTEhMB8GA1UEChMYVHJ1c3R3YXZlIEhvbGRpbmdzLCBJbmMuMRAw DgYDVQQHEwdDaGljYWdvMREwDwYDVQQIEwhJbGxpbm9pczELMAkGA1UEBhMCVVMw WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATWpfTIQFPkZIoXXMDN9utRU+AbLGcg BmLA06x2qqdcpCMlYFoJhuRWzYCiqz1mKrAvNlQYkgoHfemk92sf8iaro4IBaTCC AWUwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAww CgYIKwYBBQUHAwEwHQYDVR0OBBYEFA/DUGGZflb1xtmcOeiDWJAHuhq0MB8GA1Ud IwQYMBaAFKNBBqyQbdFK63WlShCZs7Ghi0r3MD0GA1UdIAQ2MDQwMgYEVR0gADAq MCgGCCsGAQUFBwIBFhxodHRwczovL3NzbC50cnVzdHdhdmUuY29tL0NBMDcGA1Ud HwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwudHJ1c3R3YXZlLmNvbS9UV0dQMjU2Q0Eu Y3JsMHIGCCsGAQUFBwEBBGYwZDAmBggrBgEFBQcwAYYaaHR0cDovL29jc3AudHJ1 c3R3YXZlLmNvbS8wOgYIKwYBBQUHMAKGLmh0dHA6Ly9zc2wudHJ1c3R3YXZlLmNv bS9pc3N1ZXJzL1RXR1AyNTZDQS5jcnQwCgYIKoZIzj0EAwIDRwAwRAIgICvA5ttD 0oeUcd37iYvoQ7iMIpZINp4e1j5NrlI3UnYCIEZhimm9+1dUWAfx9ZkGmIu0HiHR zEZifAHbPM3SJbRu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE1DCCA7ygAwIBAgIQA1VnVdetA7HTEgPR8rdfYzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTgwMjA5MTIzMjA3WhcNMzAwMjA5MTIzMjA3WjBkMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSMwIQYDVQQDExpEaWdpQ2VydCBBc3N1cmVkIElEIFRMUyBDQTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANk0lpEHpyv4ILDp4VhfYBN2hTae Msg3ZlO+FkWUfTWSoSF7eP2WWvy9DzSXVtmDwRG0kint16jgmz0nZD1nWS//JnMr DXeVpDxzqGzJQO1lC2aQOlNFCDEPeuwZJbqOcIyKiaXSklJlQRsurKWOnzl227Zd bDArMg/+9+4Ada3ueOdrfi4XkqVOTv9D1ii+A4r2J3VTDkg8PiX0e6/mo9e5yBaj 7ZIr2HuMwVQAmfMnp1nVBK29FTXA24bTauAdfGRG35DfbZniUZe/7r8+dMfgqZPN 1JayEnEZLXRT6nVuxjTWiqEwLHusmVfkNr4KHd5lM79dcW687YWTInuhHOkCAwEA AaOCAX8wggF7MB0GA1UdDgQWBBQW0njk6IONw24BffnOO82DlQoE4DAfBgNVHSME GDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYI KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j b20wgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E aWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRp Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwPAYDVR0gBDUw MzAxBgRVHSAAMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29t L0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAEhMTW9GZhsiO66D+Doceu2BRamZpaFj/ HiJbDcX224h2RVyfNn4WnLLKsXcKU5AatoXaDwTnrkoRdDiIPq23yk7Or6+54ikZ nrII/NqOImq//WL5yFytrm5pWcOxTjF5aIBFeJyZBZ4W+kFF5GVvUupJKnOFoMh+ PyRtXgH3rwZ7BToOXPs7H69MgBjovfGJZXT3RWKC4nvw08I7T0E/bT6XYIJ/z5/l qu/LAp+IF1lTIc+XImQpKRSXVJUNsbZB19AjFaNzT51ZELpOq7Qqmy4Psc79F5+g IisW4BM41cu43RuqtvjZJ8KRkOGMc5xIpKZVGGTQG6xzNFkoxbHf0A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFJzCCBA+gAwIBAgIQBrytuehQBysrKDIQVF8fGzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE4MDIwOTEyMzIyM1oXDTI4MDIwOTEyMzIyM1owSDEL MAkGA1UEBhMCQ04xGjAYBgNVBAoTEVdvVHJ1cyBDQSBMaW1pdGVkMR0wGwYDVQQD ExRXb1RydXMgRVYgU1NMIFBybyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALNu+EJh4IFRwb+NSkUA2PuSgGBJX7Dv0WHF1UnHGTaxvNrKypQ2Y4YM 8UWBN6GtERHYnVPFREbMZm7rH57JfSqCRQh/fnZIW8YKQKye3LTQ9RDCe1tqUnr7 q4dPHGhtJPc0ysDZOhxdvxf6bkDZWpejXwzDIVyPG89tGEgl6eISrg96MOOUDcln 762bSBVzozcYRrCiaPWipEzo+38LbqnDhSDPAH1AnkTofeTJ+K45xVja4kovzOKh EaSNL79fUMsfN0A57Xdgoykl8EnoG5qFk2mSCGruZVRhvU3p9/hlI3s5yvnS32k+ 9Dun/Ns/lTmoOsZiGVw1e2/F3eAHweECAwEAAaOCAecwggHjMB0GA1UdDgQWBBTW kdAnx/cYVmiiUv1ydKSbO2eUyTAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALv Y2QrwzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF BwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwfwYIKwYBBQUHAQEEczBxMCQGCCsGAQUF BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSQYIKwYBBQUHMAKGPWh0dHA6 Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJv b3RDQS5jcnQwgY8GA1UdHwSBhzCBhDBAoD6gPIY6aHR0cDovL2NybDMuZGlnaWNl cnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDBAoD6gPIY6 aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVW Um9vdENBLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG/WwCATAqMCgGCCsGAQUFBwIB FhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMA0GCSqGSIb3 DQEBCwUAA4IBAQC9xqN5M4SnTGzIEl2GKm7+3OLikAmlts8dinuT5KndrKq9sygQ T6MYUR1Giwd7jUl9zq5X8edd2z/p41GqWkWhKpMiqImqB9iua7MPmQKGMd/9czDU d4wIBpBUQVNWK+VXLxRuk7iDIKkSIUThDwijFRUjEsBEsLFDqkckTGofLPSjq6f8 It/QpiwtuGwimXuzoNqRFaeGq8OW41I+sCXHxLLDBE9lPjvGIE6GlxVFtbfTBFLr qi7grcgwZKTxLncZzSxmJHseQKDrac/GQbBdd2c0OrRGiExvLfzg101q5U8qm0vk OCfj6hSHTRvUzHYXylh1Y1RB4J2IUiA0AsUn -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFMjCCBBqgAwIBAgIQBR/neNfhzLm5bSsraBQBZDANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE4MDIwOTEyMzIzNFoXDTI4MDIwOTEyMzIzNFowSDEL MAkGA1UEBhMCQ04xGjAYBgNVBAoTEVdvVHJ1cyBDQSBMaW1pdGVkMR0wGwYDVQQD ExRXb1RydXMgT1YgU1NMIFBybyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBANxDU4l5cxvhArWAZ5ftOjc+q6/e4+BtBFQcW4mNMQntGmso7IZQSwIP Tq4ha/PizRaCq4D3OV7jIMYiUWqzECoKnVLPHP+ADmbyB/mhBcreIWqgbqnD+cji 6SBtfOCHYRHMFqxCfsAWEUeJjdB/PvuojXGfgjDHx+/hiUQDBWMA7L64+K1yw5Rn xGcVIu2eb9wxWlApVpnLG9E3p05mZVvSyaFJt/RVnrpxp4cWD8hmFyJE9Hkcy9Bh 3snRJd5Z4c5ZU33b+njh82zg4STj6rMxAb8ffpxM6s/iOOVd2I8tbjxo2YvqXwMN kn4hM4SxFmyTjLdfMvVhGAIkCviIeNMCAwEAAaOCAfIwggHuMB0GA1UdDgQWBBRM B1veei9nivmCjU0AD/r7xpcZRDAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALv Y2QrwzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF BwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwfwYIKwYBBQUHAQEEczBxMCQGCCsGAQUF BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSQYIKwYBBQUHMAKGPWh0dHA6 Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJv b3RDQS5jcnQwgY8GA1UdHwSBhzCBhDBAoD6gPIY6aHR0cDovL2NybDMuZGlnaWNl cnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDBAoD6gPIY6 aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVW Um9vdENBLmNybDBWBgNVHSAETzBNMDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIB FhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAgGBmeBDAECAjAIBgZngQwB AgMwDQYJKoZIhvcNAQELBQADggEBABPPQ71emxJtMWMKbpoKySHWp4rTQcUbEr9g oQoTq25fupbiWuK2Yth71ILk6HFSIKWNg02t0mGsE+en4CN9xtuq36zmvjr3O6Aj H8wYk2NKa2kZQ5FoPbNbAQlwzzQGIO1NUiHP/dzTvJlOnMDxfy+HU3BcDbvMdgfw zHyt33+zqx5pUeU1yt/fiIoqiZfdZCX8CYVpbkUoeGUmr9RTk0wIdpJnvOktla1D i9TtCbxDmcdjpA185SBJVYRIuXSdojabJ1WWR2JSDncJkEy0x1U02oTEkIivegOH EaR0EQCeJKv+jPaag/uX/h7pqiWz8WNv1DLIrqssOlZjVYAVQOM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEgjCCA2qgAwIBAgINAenYnwmFxcytZnCU3DANBgkqhkiG9w0BAQsFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFs U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODAyMTMwMDAwMDBaFw0yODAy MTMwMDAwMDBaMGUxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52 LXNhMTswOQYDVQQDEzJHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBWYWxpZGF0ZWQg Q0EgLSBTSEEyNTYgLSBHNDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANjgsiwRN8SjdU/Gq9Pbqk0xKH+dkNKPOcGWl13NWL1w2Tb+HYpyP/8qGpeyioM9 i3/lnGqBaJRRhKkc8s0lyLH8SDOuJyk7TvjeqxpArPpfeNoF9dHjraHcrH44x9Kb s8oS0RVmNpvNOUj8r+I363Fnrdn+KRlI2jiQLjHnS8lVkHLMA2ofH+gnoamP6yD8 prSoaIJ1BQvI6xpn5lK+BtufkgmfqR8Yyb6Lb8ZdgLiWutTQRIcJnePVl5/k7Ls9 EeObjvdKRFiM1xINug9Y6iN8IFjBnjxIDpHRTbayKut312ZQkBBB2X+qYkPKnpgW sNdZdWHXk26C8d8JXPbVuuUCAwEAAaOCAUgwggFEMA4GA1UdDwEB/wQEAwIBBjAd BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHQ4EFgQUYRizXWjUntkv61FcA7cKQMbubbQwHwYDVR0jBBgwFoAUj/BL f6guRSSuTVD6Y5qL3uLdG7wwPgYIKwYBBQUHAQEEMjAwMC4GCCsGAQUFBzABhiJo dHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHIzMDYGA1UdHwQvMC0wK6Ap oCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwRwYDVR0g BEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNp Z24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQA68cucSH/1u6kx SA+5rEo20zkgeTVayLnmN1vV0/oXoBh36VE825+m9GdQHVLbmreJeXIrARZWYCuK A9JaS75LKO+GkeyXisP8e8I4tOSvWPV17dfBXbcBz4A09Ws91OUwfQlmOdzTa94l vD4PBhLNTYi087pmA5k0tP+VqIC4CJb3Yr+/qjL+VAs8M6v2v4VfHBt0uPSVlNHg cI/TcrId1tDKlRBFgFcWsvjFecYdish8Y92KxwfRzo3QBp3O/iFvz/47lvvQ7P8v kBIjgIMpSm/3TDrTJojBZm7BlWOaykr+3hbzWmwXgjzhOsLLRv9JGt1+rvnN+viS +ArY2j8T -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID2DCCAsCgAwIBAgINAenYn0U21hXlJO2hXTANBgkqhkiG9w0BAQsFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFs U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODAyMTMwMDAwMDBaFw0yODAy MTMwMDAwMDBaMGkxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52 LXNhMT8wPQYDVQQDEzZHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBWYWxpZGF0ZWQg RUNDIENBIC0gU0hBMjU2IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARapvEs /9/n+OTfWwcIBna/fuJNcy/3gSb6v4m40ZAAKHhn30gKKbR4NNk+2J1gOxpRCOWh iJhk0na0khPBJc45VPPGnvcyb9wGTT9eo6OUURvg9hU5JAkzJkjqhTotZ+ijggFI MIIBRDAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF BwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFDnMgof9nbH9PpxwcXMj LIMu7kUNMB8GA1UdIwQYMBaAFI/wS3+oLkUkrk1Q+mOai97i3Ru8MD4GCCsGAQUF BwEBBDIwMDAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29t L3Jvb3RyMzA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24u Y29tL3Jvb3QtcjMuY3JsMEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIB FiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG 9w0BAQsFAAOCAQEAriBUq/ySmeZQnV3hoFMJWSNMpLYJYcaIwJq+qjCUxPUYTqsR gd51wL2NFfVMGvPRXejePtvd8vdRk0NceE+vSaWo4yU5/nmwqWWPBfUWY5tYCA0R LXqOSOfEh4qbceiueFaKg2h+r+QggYQLmVUuBL+pM7ZsAooDIGPz3wL301eHwcdt XYROdiREbxTu+GjttCxoAk3LTgsX/uqBUCN7lKOn4zsQn/2ngq3Og94wvpRzN7yE CZ3qg3zTouJQfqv3ZMn+Mp2UnFwroFmoZhfTnyCYpQSLCz5IrCi/IPDREsbWe6ZO vfRWM/0etBvDg4g1mt8zOqtwYVk9qcZSztn/4g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFzCCA/+gAwIBAgIRAP0Zx6ZI8jCFNBvJb8ngVsgwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MDIxNjAwMDAwMFoXDTI4MDIxNjIzNTk1OVowgYsxCzAJBgNVBAYTAkVTMRYwFAYD VQQIEw1JbGxlcyBCYWxlYXJzMRAwDgYDVQQHEwdNYW5hY29yMScwJQYDVQQKEx5T b2x1Y2lvbmVzIENvcnBvcmF0aXZhcyBJUCwgU0wxKTAnBgNVBAMTIERvbiBEb21p bmlvIC8gTXJEb21haW4gUlNBIERWIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAkHd28rhMbD0D9amcKwVe8zK6RC0cfLw53pibu9eUwe7Z0O2V90GZ EWd295IR8l7uIqkujFEQZC52B9ZaWIbGir5/y66kMe7Yr6axNoIjqWE71F8DOT8A iXggwo3bF/f2IvclHggIPsySH400bxqjuqPnuCUtAQK9OvwPdepWR0D/ADAbkgec VoGpWZFBjyRSsd8dK0/IK4qjFlE/zB+nHIr4HQj38eShpOrkXI2SsINDE2fUVVpX D0w556yNTvexU4dYQQqIw4zhZjN+9lBXweBsr3trxQIvVPuZ79KW5diVPqfCE1n7 hOqFhOqk4VFrztBARtxiU6fZ1Sczt0DwUQIDAQABo4IBdTCCAXEwHwYDVR0jBBgw FoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFDoKjBx3WSnqFvaZP6MX s98pEZM6MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEB AgI7MAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0 cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmww dgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVz dC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0 dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAHho1J2s RsWr4DFlKERthYckzxE1m/HDlRIqiE8h+KnG8142rAT7hnjiqL39NkhrHF5swB3/ BPw4TV67GAfCu4BUJH2bYAWSFaLz+hXjn/vVMnpdLlwFi5/Fg5qb9cjCXV36xW+Y uaehUdZg1DLasj28hoIdqD+jTE9seUQHZjU+HDCVKev0lcFzztcmGBIUSwZ4XF1R Ke2bPYw+QgFXWIEGQ8dBaBDGvunaP4U8P76YXvdjOhbMLQ0zHJH/5A8qM7wF3TRW Nm36+vrXuGCarsbO9fPj4s0rbhGQ7mGYrebIyLVIOy+Dnk7qWfxRbQAkFISik2hs 1OhBSLWIkKDkwrFn8lv0rdTrux9NLqE4i9cbMnQsiuqDdumR/YNX/4fRVVRLgyvw Byz1t4vjkzfXkvpIzUTEKiHzyFFRB71uovzK7T7NMKsk/ytZi/Sv5PzUzhjERv+U I708qx1HwOvva5hcnft8oQDybHbO4Fz59pg29HMvw36YWJ8G9Elpc+SORCmgp1kd bVuKHo8JYvd9lfJ6BvVINkFfOR9duWjpFMicAmPwT+xzsg3T63JBSvQPqHniIrIG YMbj8AOzEJJHRDwZkyvOGx+wKXynIPn0WvB87SnDpJoj+G4xRDmuPnAnC4ZwB00W kfxEERJIT5jo3mcnz6GLAQGM4IMo879uBZ1+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFjCCA/6gAwIBAgIQXS2dry+yCFwjbe1PwA8HrzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgw MjE2MDAwMDAwWhcNMjgwMjE2MjM1OTU5WjCBizELMAkGA1UEBhMCRVMxFjAUBgNV BAgTDUlsbGVzIEJhbGVhcnMxEDAOBgNVBAcTB01hbmFjb3IxJzAlBgNVBAoTHlNv bHVjaW9uZXMgQ29ycG9yYXRpdmFzIElQLCBTTDEpMCcGA1UEAxMgRG9uIERvbWlu aW8gLyBNckRvbWFpbiBSU0EgT1YgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDDUkdMFy+NIrq+NSXmlGPU5+MQdAXlUi1pm+dWTLzEBcjlAO5NWdQB Zq5Z8lGsxNmhL93S3S48YdyyP3nPv4Wh3duxospUuNWIQNKL7mls2vz/sFVuVksx XOy8tkG1k/OXLTPHQbbuNZa1w0d+nOJmRdI2OaFNQ01nSJoIWWkACSM4C7lPiGX7 Xjmr4dWNKQollkFTJFLw/IEsiqWzuCePBrYzWGC5h8gebSwnJe2d9/EYOYFv+jXX bbNs3JYDbrjF9JfzCW266c9mqD2FwxweObK5K7RZMxpTn0mqa3Z0fPRb5/Wr8z5i c0mVa5w8x6vCGbQ9MuBfS9nMdEESbf4BAgMBAAGjggF1MIIBcTAfBgNVHSMEGDAW gBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUPoqLDWUT7tNbvz7OJIbo TMFMZEswDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0l BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQEC AjswCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2 BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0 cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAGIDVmE06 PrjvqtgQ799jmuYQPT/5FBevsxQiaC964eHHN3sUyqtIyjcmKJojZ8kkggH/jJDd 7ZwF3FYZl4zjuD1D8tmsONpDZ1nv5Q75n/y1cMYWlc+KqEb11qRhuVZLAZI1lZzT lDQVv0u4EArS7Rl6MgNHX5modVVUVSs50subkR0wVyc5TvG1lDaVuq7btgmDxJI4 pbFobA9le//um3rUQa+I1l+FL3zPNHc3HQwCRrZNsk6D9y9vEc4tr/xsxkGOBiKE UZRHJMpgeHBsyTnYNeAma0l78DY4YgNuzN71mpkQFDmX0nzmTbG/K6HgGEpPZI9N 1OfV6WlRIHbMehqGYR3PB7NnDqtv2hhgk8WImVgS0Lx+iGMARhV0PZfNPfLSOZYT fwQSNm9dXV6EbYvsn5557Kg2MbQW7SYq8BXeV0hUenxVtLj4gyb6d4IPStyM+nzU a34CwrjcUp0KhPRqkM10y887I62liUbx0gpgT+3Hn7y+pLAqxUzo+xxdGUKy8XY7 HXw/19ufVx1XCjt8wADovJDO8VfRpqf9zOkC//Dqazid+ew6QTkP5KfJNfzScRVm Aiz7F4Fnw3b9gy93T6qhR+NqBYL/rS75/BddhqLOAbb0G5DyId/QJsGt3yvL799f nl4pJGBcsP+yMR1vPwNS2MhimYNY2kyLjaI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGdDCCBFygAwIBAgIRAKOcGTKlQZcrOChuzHbElDAwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MDIxNjAwMDAwMFoXDTI4MDIxNjIzNTk1OVowgdAxCzAJBgNVBAYTAkVTMRYwFAYD VQQIEw1JbGxlcyBCYWxlYXJzMRAwDgYDVQQHEwdNYW5hY29yMScwJQYDVQQKEx5T b2x1Y2lvbmVzIENvcnBvcmF0aXZhcyBJUCwgU0wxQzBBBgNVBAsTOkNvbnRyb2xs ZWQgYnkgQ09NT0RPIENBIGZvciBTb2x1Y2lvbmVzIENvcnBvcmF0aXZhcyBJUCwg U0wxKTAnBgNVBAMTIERvbiBEb21pbmlvIC8gTXJEb21haW4gUlNBIEVWIENBMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxYIuqCyfnye/8qNg3IefuP67 MIBik4A/JUjoXfPrYUEhoDmaQHqHYXWcf6ptdcDY8cKWTxQRj6ao5ZDj1LE+6py6 UqMWuEBBfzKljb/QxkG9HrnzinCPdf7hN3CZa12kr8eui5B8xm9BrjSRUeZmgMW5 4ZfuQ8SuPLACrD9CQCqDzbPUCuhZ40CGnY9MALyTkAg1HYBAPAF4z+CBsb2U+jmO NbgIn/HQbhw9/YH+x21L4l2HbjDEnj16O1+JvzHIBRhyPXflQfRBSFMUX844aLdv rzszJcmVO4erDnJWr9fHCXlmj0d7mt+d32vZtSeUmTnixXbSJeUPFs6Z6MwXYwID AQABo4IBjTCCAYkwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYD VR0OBBYEFJcrjZVt9ruB862i7gggBV5EzRZ2MA4GA1UdDwEB/wQEAwIBhjASBgNV HRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA6 BgNVHSAEMzAxMC8GBFUdIAAwJzAlBggrBgEFBQcCARYZaHR0cHM6Ly9jcHMudXNl cnRydXN0LmNvbTBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVz dC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYI KwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5j b20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6 Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAHRRGIP+DMgl 5RDFWcJ8szeQa2jXIbbWotMjcK3QhipafesGsmhVka4HxTgIfTXbt5xTl63DJMBh JkXzsjiOSlXaOgCNE2mUPlNCJDwbWsiU4kiv5sBa0fH0ZYDZDjuLfiFGSm84owNK 8C5v5QXRBBtIlLZocZf52X8K2PL5VaV/zE/kcBDVJpTDJqRpWiZGpCqjflfTSTrR UUhYMfM7kyQkYXzGoUw0+YLTQM5mpXEpyKH+MLf2v9U/+++xkhMoUgHKgz4QZWUT lrBlf7c3WzxyiCsS+rU4zljYOyRb0qoiL9R4/CGGLANZg5fBuLBvAugkWDcy9vQC mFc1xzq+5EdWxTmazm9VO32XF6shWmagt6aYY+IoRy8qKemUyjA7t/k3WZca3yCe K1GZuzLnmBuf9X7Kl0I8Nv16c9aa1aKZ6cYpgIYymxtlmtreZCnjr/aB1CcVW6JP 0aqMJL37NH80AB36z4w2Ck623DYi71jJH0YM394D1rELopHoFjCb+z+20AnPmUx4 R6/u+oAeQHW9GjeA6kMclfOQTjymjALrNmR/FKwgtft74JCbN96q4piSp2JXwJIH NkxpURrL6XNXQ4mYtO1VTq1/2B28YfSZkvbR1FJO4zi04U4OwHCxvN1kXf/YyXdD nRyJpafRMoslNFGXYVJBvi2OKIhA7Qk6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGEDCCA/igAwIBAgIQUh4EnqMavUrWDXS4cpIcdjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgw MjE2MDAwMDAwWhcNMjgwMjE2MjM1OTU5WjCBjzELMAkGA1UEBhMCRVMxFjAUBgNV BAgTDUlsbGVzIEJhbGVhcnMxEDAOBgNVBAcTB01hbmFjb3IxJzAlBgNVBAoTHlNv bHVjaW9uZXMgQ29ycG9yYXRpdmFzIElQLCBTTDEtMCsGA1UEAxMkRG9uIERvbWlu aW8gLyBNckRvbWFpbiBSU0EgQ2xpZW50IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEApdRvn9I/mUYOaN0lrfIlJm+3EamPhecBExMMsLwr34NTwqlC VI7AS+i+MdGlRFy/zPZc8J1J3JR5+PzGumVKJ5DYKDpOOrYWNXoGbabqoRwiQ3Ws OByaDOgm7Enrt388+6jJmwfpvZc46VKIBtowyyYMUD8Bf6CWCaLrVYtR/g8ZDO3g +mLjxa6PVxQQwX56SpTNPMJH9IL6S5uJdSpT3d14X9d6E5KZJAwu9PhXrMBx/nKP njze1XQopHAsi++zgemi9Dz1Ramovjv/UTL1/qaWeRftepXzKyFU1dx8+n6MpQoW bp/ccp5skwb+F33/3mzutlzzGIhA9sElXh9FHQIDAQABo4IBazCCAWcwHwYDVR0j BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFC1q35538vTPR3U7 AE0jPwHuDgy8MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAYBgNVHSAEETAPMA0GCysGAQQB sjEBAgI7MFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNv bS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEF BQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9V U0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29j c3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEANA7pYZNMWYwEM1/D CtwSmbpgtYCnKzSFUQc4+/xP36CZGhxtG3+wl95ZO8IMWX1+WOlsN5ruebJg1Jrd AymWWPPFLZZNqKYpqbpdBRn020ZyN61TMnCRvcIWXx50YTzkP6407ILhyL6S/cnm mYxF/wTfmtdFi1b2M/ARfoQHq5Zc2baNmgrkITK8ocfSgs/pXVCSuZ9PvUS75xVY CHbXtOB1oofshhSJaxr15p31IFjWNLTta81nN/wPd6JRwFgnXHdirVMoQcDIHXDi PfIh+JBVH3moLCc9F6IKZ9UvHNYb/hi59ROxnRezK92FUQXInnJu4VMcm4/zqknB X+g+px1YZ7Suhz5EQ8Ib+lyVJEEzsndZhrUD3N+HYXOE9ixH3h4wct6osbWM64ia LXNFKPmjUrDw83B9eOr8rxFGe2dqMvjEUEB3HG+ABwfPCfgul2+20C3ElN5uXkRh wymlvK+8ccyQgd5fVNLe+qtU1Ng403aSKnCYOl0ubPeJbiWbTdUoHgC1ilIc6Xp6 C0+qf2ZWD0YNsGriQ6fK0XXHBBJ1yVfzkgooFzs2Dqa3xs5bZc2QS66iyLmcDk5u AALKxDoYKYYUeVJ48v9YxxKLJNCzlm/lxDXH26CyeASpobxFsm7HYM6yJFfBoGkQ beMgnDT8X9ST0EhbYTmviY3R20Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDPjCCAsSgAwIBAgIKAf4+bGjeu+wmPjAKBggqhkjOPQQDAzBrMQswCQYDVQQG EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g RzMwHhcNMTgwMjE4MTgzMDAwWhcNMzMwMjE4MTgzMDAwWjBtMQswCQYDVQQGEwJJ TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s b2dpZXMgTGltaXRlZDEiMCAGA1UEAxMZZW1TaWduIEVDQyBFViBTU0wgQ0EgLSBH MzB2MBAGByqGSM49AgEGBSuBBAAiA2IABLZXoamhYa/WwWE0nrNCo2lczaM2A35u 59TmOxsIbT3s4bb5KkXPt3x/5Aa79uxf+m3gc3fFPxbe3FjvZXY2eNvbNGW4CX/p QdNpbwVxpMg6/F+oF9OMHk9vq94KQ1+UYKOCAS8wggErMB8GA1UdIwQYMBaAFHxd AoQT1MyKm4HOFxwuKR6cSGNCMB0GA1UdDgQWBBTRqrTS0iWCTrPwk2AXSptjevkf DTAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3Np dG9yeS5lbXNpZ24uY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYIKwYBBQUHAQEE JjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5lbXNpZ24uY29tMDMGA1UdHwQs MCowKKAmoCSGImh0dHA6Ly9jcmwuZW1zaWduLmNvbT9Sb290Q0FHMy5jcmwwCgYI KoZIzj0EAwMDaAAwZQIxAPOSHbUT2M805KMjMEor2epuLoycKuwnsGmtixn+ozlv CuJS+sq+9onRDkgwtG3iqAIwAYlrF96JmhW7JN5JyYl/C8tK0d30N8s/Pk3Denh3 KyPhSif7POMc82DvHqWLL+S0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIERTCCAy2gAwIBAgIKGlyC3ty8ahUwMDANBgkqhkiG9w0BAQsFADBWMQswCQYD VQQGEwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJ bmMxHDAaBgNVBAMTE2VtU2lnbiBSb290IENBIC0gQzEwHhcNMTgwMjE4MTgzMDAw WhcNMzMwMjE4MTgzMDAwWjBZMQswCQYDVQQGEwJVUzETMBEGA1UECxMKZW1TaWdu IFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxHzAdBgNVBAMTFmVtU2lnbiBDbGFz cyAyIENBIC0gQzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCnrOVb uDTs2A73pwkDb8H9Fa0WP7sHPAv2EiQrF824Yythyjstd3QPux41oK10Ef8C7ZG0 ScM+kSIG2/oW2xY1nJQzSKUwE2sAi8S46q9rJFCn3Gvm3yyouBBkZTCEEHOvVTzR 5e3bk4Ic6ImdrfVsXXS+uuzuEkQw5MxhBeFUzx9/ns6KBMH7l5k9xeh41bNwj2NA hpAB4dwTEZqq3T+G/gYuMBY1QmKbq7+XbbGqh867/DO3Fsn3UTzgYTrBdrsUFOZi j2k1ck5I1BAiwE/vNg/jqe+fpMdWE1kru0cE4jjIQglfl+oMa0r217f9MAt+BcR8 kT2nqz2S4aYn8wtDAgMBAAGjggEQMIIBDDAfBgNVHSMEGDAWgBT+oeBwHioDOVJa Qr5ckYV6GKpNtTAdBgNVHQ4EFgQUJmjA8/xAHPfKEktPksOLFJRIO/0wDgYDVR0P AQH/BAQDAgEGMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRw Oi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYI KwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5lbXNpZ24uY29t MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW1zaWduLmNvbT9Sb290Q0FD MS5jcmwwDQYJKoZIhvcNAQELBQADggEBAMcT849Ry1ywXIrZqLO522l9kj+6mVB4 24tJr6QBOyTo99QBL+v0Ekddn4EQ2cXDEIVG8p9sDxLxg+dE3j+5NBIIfYTyk5ff kf9dTcnJNwY5dmvmy+YC036hVT3wJju2K7d+9bDXq6bAk61AxJGrdIJ5s2DIQjYv 8lHF07oh+dCOxlfReVi/ksbCTLRnP2aQjVoFYklAQZaaWzVAH9EFmoS9vtIXvxcF fp6Hfdoh6a7dcdndq3PfC0wH8rBL7pUqFgFPZuKuqSicMDKbHizRnf1c7IB+j4B7 HPO6mFktvKO/t4wGyidj5pAxy4z86910LA/rnhdysUch2LG/keSEoIs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIERTCCAy2gAwIBAgIKfgZTNsB1x5mLYzANBgkqhkiG9w0BAQsFADBWMQswCQYD VQQGEwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJ bmMxHDAaBgNVBAMTE2VtU2lnbiBSb290IENBIC0gQzEwHhcNMTgwMjE4MTgzMDAw WhcNMzMwMjE4MTgzMDAwWjBZMQswCQYDVQQGEwJVUzETMBEGA1UECxMKZW1TaWdu IFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxHzAdBgNVBAMTFmVtU2lnbiBDbGFz cyAxIENBIC0gQzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAvfte UE7HwR4RPxGoFruaQ6YKrb3cSVGrRs/lZtD8pWchBZvkiT7EYt/Vplrs3+4ctlVf mihqYzfckUrUexJa/D/L3Gm4mwAWPzh3xkbIB87NgeZ8ljWQXSzm1kcuVRE3kMMr rgiz01nQTJ0Dbde10wPfH+8Gl+2pJpeHDKXzuVwcwPUOSLp1XAtBOxKm9ggBdyd4 JxmwvxGFwz/TSOaYisaOL211p30QK7b1+SRWgbSRN9NPYhlQeiPsMGnQJKfGq2RF 7jSkEuKoUP4UBxRVcwFe2prkdbmdTbrpMr6KueGa5yf/pg6QaIA273JfZIRMWqLk hTSFA2tqCWu9BVNlAgMBAAGjggEQMIIBDDAfBgNVHSMEGDAWgBT+oeBwHioDOVJa Qr5ckYV6GKpNtTAdBgNVHQ4EFgQUOw7vKTsRSCksARXRjnt5aQV7yVIwDgYDVR0P AQH/BAQDAgEGMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRw Oi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYI KwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5lbXNpZ24uY29t MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW1zaWduLmNvbT9Sb290Q0FD MS5jcmwwDQYJKoZIhvcNAQELBQADggEBAMJ2XCF9zHpkyniCfrwc541PjaeofwvT 9fklKtciWNCYhgfEf9KEljVVPCyGnYN6iDcLcBFSbKIkIiEDXVdYdsZtEGBJLkDj g1FIijfaEaOBKKObTcazm0nhNn6NxmQ+VTfqaHYDSMN3HQjnMOX63U0YLny+0v+P 4+0VqVMhlPqPQ7Xog3FuOvofVKTCy8vbp55FVoyCN48xa2I/MXOK9wPTNqNomKxa M2F9nxzuek1PM1t1hJBqbZoD7nj3kb2BJXPFpNqUO8IH4FITpSNteCb6te2fl++a D4ReS84rSCb7TIhjwayaCVNOnJvdr7GKQ3XQDUW/ZToiBwpMMptHsY8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC/jCCAoSgAwIBAgILANk2XxWEKh0GicMwCgYIKoZIzj0EAwMwWjELMAkGA1UE BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5j MSAwHgYDVQQDExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzAeFw0xODAyMTgxODMw MDBaFw0zMzAyMTgxODMwMDBaMFwxCzAJBgNVBAYTAlVTMRMwEQYDVQQLEwplbVNp Z24gUEtJMRQwEgYDVQQKEwtlTXVkaHJhIEluYzEiMCAGA1UEAxMZZW1TaWduIEVD QyBEZXZpY2UgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABEZY+jc4QJlK GWGc1FqdAbUQcaFiR06wyL2JHEytm/PkgllFNIZ7uyD58iJY6wosJ1NC8TAkEqEg 4JOC8AyYNNlyv0BGiBHz6EAKArUeS5idNucCuU3UexFxrKbVQt2ZZKOCARAwggEM MB8GA1UdIwQYMBaAFPtaSNCAIEDyqOkAB2kZd6fmw/TPMB0GA1UdDgQWBBQE9lSv LrTdp0QeyvBjnCQVQ1gvzzAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20w EgYDVR0TAQH/BAgwBgEB/wIBADAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGG Fmh0dHA6Ly9vY3NwLmVtc2lnbi5jb20wMwYDVR0fBCwwKjAooCagJIYiaHR0cDov L2NybC5lbXNpZ24uY29tP1Jvb3RDQUMzLmNybDAKBggqhkjOPQQDAwNoADBlAjEA 1C2gncdHPhUIubMCSCf4KW1rr34jWRdiBGRFLoBDtL002fXfcuLLxpgPSAS8vwpE AjA9YEhR1Smk9APIglUMjAWxRX2vps4q7k6pJ/hKHkukINVikBlNxRy/GXP1Kzmu 2qs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEaDCCA1CgAwIBAgILAKCIcIJaMmvtlhEwDQYJKoZIhvcNAQELBQAwZzELMAkG A1UEBhMCSU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEg VGVjaG5vbG9naWVzIExpbWl0ZWQxHDAaBgNVBAMTE2VtU2lnbiBSb290IENBIC0g RzEwHhcNMTgwMjE4MTgzMDAwWhcNMzMwMjE4MTgzMDAwWjBqMQswCQYDVQQGEwJJ TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s b2dpZXMgTGltaXRlZDEfMB0GA1UEAxMWZW1TaWduIENsYXNzIDMgQ0EgLSBHMTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANZ4SolaBS+w84RMOCt4ZKVg xMJyR7eykXtyP6Q4NNAnWMpKnUuk3bCY3l0hUvr8F8VZJuyPRQx7XyMhDc/KawCu lqnh9Cr1WKEFBoUsZlaejIBk8hB4PtwKITDa82q9rTxyzW+mt/16JI/cS35sIQJB TIxriSDa2tHmlkKmExizbmqUCf2NTGZ/KaUcL87IhM9coFVWzTLXqEhkXgFsXWj+ AHk2aROD5lowKP/0rbIA3vVCm5jmREckFNYwEiAztLI6ZcsuTWY33BbduxZFETtG pFUvw6s8ulYlyo9IzVZoQrSngQwDMZ1B/Z7a9fXApZO1XlemzMeo55kvHglRV5MC AwEAAaOCARAwggEMMB8GA1UdIwQYMBaAFPvvDYaesOPdqbnxIRd/PvzwdysaMB0G A1UdDgQWBBRcpZxB725BYUZ5LN/YVUUF1acahjAOBgNVHQ8BAf8EBAMCAQYwPQYD VR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5 LmVtc2lnbi5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADAyBggrBgEFBQcBAQQmMCQw IgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLmVtc2lnbi5jb20wMwYDVR0fBCwwKjAo oCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29tP1Jvb3RDQUcxLmNybDANBgkqhkiG 9w0BAQsFAAOCAQEAYctjwH3uHKgDKOlhyjwV5BU5BRyFI4dRhkClor/HcftlqmrM 4tDAs4rjgoQyUUaeRHMZCLLpT+geNu6Q1CwBCpwtOehbmcB/rKLs4x0BeEkyCKWe DIV+B5EupDUtc2iy6Z/ayaZDbBkw271Gb4enscExgGordjgS+smpLR0WoQnRWRqZ DF+Xea5rX2Q21qkYGoqX48L1zslI3wQvVm+c9vhWaPmfmZMlxeKuf+hlvM57qGrt 7bpCoLuzy+s2qj8ihN0bdU0MQ0sGh7vZwrVdtEBS5kKs/1i9M6R7lCIqNV2NSThY eRGVf81T5WPf9Rbtd363vkFck0JGIoT80JqSmQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEhTCCA22gAwIBAgIKYmy5KyN/+C4/UDANBgkqhkiG9w0BAQsFADBnMQswCQYD VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH MTAeFw0xODAyMTgxODMwMDBaFw0zMzAyMTgxODMwMDBaMGkxCzAJBgNVBAYTAklO MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv Z2llcyBMaW1pdGVkMR4wHAYDVQQDExVlbVNpZ24gRVYgU1NMIENBIC0gRzEwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWF1wRluuWpE1fd8hS/hP6IeRs /pHB1dFbSzlWKMXxgfd5l71liosvLmJAXPxaky2dVfV3wa/5ObUOwk9mbg2eZvZo MAtoU5UguN/iotBHycy2Z4wg2p9JM6UKd4/W1Hgue091XhBpQOpgIHNC6VuLzP0G KWQirZQkZysfXwXbwfhPSbjkbCzQvI5la6px9vr6asPejkhN6rAco7/Z0GdpHOKD Ki86UlrZXKi46unqV+VtLaaQz0lI+Vk0FCevISrriH3CWCbzwD1U0/f0o/2L60+w HZ+9Busk8UTXkyEjkWOPN/8rHDXOO78fFtFL5nKTuiOInM7XlRQ/v2hv+pg7AgMB AAGjggEvMIIBKzAfBgNVHSMEGDAWgBT77w2GnrDj3am58SEXfz788HcrGjAdBgNV HQ4EFgQUsp3PQafpw+CFVkCYS/aPfFUp534wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA9BgNVHSAENjA0MDIGBFUdIAAwKjAo BggrBgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTASBgNVHRMB Af8ECDAGAQH/AgEAMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDov L29jc3AuZW1zaWduLmNvbTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVt c2lnbi5jb20/Um9vdENBRzEuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAk8oWFJ3nW TZ1ssW1PBGFYXjGLURdZ7/q+Zu8cQlbZE0fygEp4bYEwrr9gXekwE8qutiHEbQau 71JuR2X/s7rAaLT0a3FZEg1h6+lpqy+WyJaEYgR0HLOkoynkm5ZgbxR/LgJMazOm fSGEgVFRxBU6Tj3/llL9c0dBJ9VeDfad4FlUMtx8Wz60lVuH953C1+MuiiS2MRgb W+zxJO/RZEq7uPNdXhlhERZiLJ4odAMNHrWItmOIgFafs+FCz2jCHRB6Bjt/DNBh 7kh2Zh9M63/1sTtIAVN7ZCOEFUOXrJfQAQM4RJrZV8ufIGTPCosO9KcAlLUEasN5 SNEuIgkDS1Pu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEgjCCA2qgAwIBAgIKIXrVixxxPAAgkTANBgkqhkiG9w0BAQsFADBnMQswCQYD VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH MTAeFw0xODAyMTgxODMwMDBaFw0zMzAyMTgxODMwMDBaMGYxCzAJBgNVBAYTAklO MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv Z2llcyBMaW1pdGVkMRswGQYDVQQDExJlbVNpZ24gU1NMIENBIC0gRzEwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCU1fhvfUV6OJOhMHAzBZDvxxpa5bvT S1x6S4rVQmP/+125Wj2gpxvtII2RyqXQFlZd3qAKMLgqgHGzeJcyjw6CXbzJHmri liVGWmuLn/NUKjKJgP9zd6eGOHe6mT1WjB9ZZEFLsDYoXBthTwcHdLWK2quJrHgS 3hZiJnpkX+hmaY7DX89oUMI1uvCQaPljgTvtiR9vtmeg/GgyePX8K5EUMozX8ElR DMWkzdFUYv0DVcSQcbN1R/IDhWW1vPHzU8kexAMO4B/E5sj6FGrAeMM36/uZ3AmF 4mt/0Ia2BKPsW/K2T3hkaNSTr2BKlUm6bRccONcNAyzyN258xcUcX+RJAgMBAAGj ggEvMIIBKzAfBgNVHSMEGDAWgBT77w2GnrDj3am58SEXfz788HcrGjAdBgNVHQ4E FgQUNNH3OTJFQEqZK32JaldprZWv4zcwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQW MBQGCCsGAQUFBwMBBggrBgEFBQcDAjA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggr BgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTASBgNVHRMBAf8E CDAGAQH/AgEAMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29j c3AuZW1zaWduLmNvbTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVtc2ln bi5jb20/Um9vdENBRzEuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQAaBDZfBK+cP9Zk lI7QN3mkpgD+mYfp/03P51cUNlfAFoYd1G/4lU468rg7JLTwqFXcDzcmrWt8lmdi AMflxwLGeNObNS9RkpdiMDCdRItCHq00IMbbzj5rz+HSzAn6WsbLn9efn9WhO1MO 72d1SsEbVOTw/Z3sfPpWS8DSp91TRZuRKReVmD967QnsQGYNKUG6esTV73dOigHC ndwglIXCUkaxTroFn7wT6Sqt9pklaqxBkEx/yzp0HxpZtC8uK6aOFx624S9yF8nk 6U7rbscn4kJYOF+0U9JshFkQ4+cx5kKd3cGNtmaTzemoZSGn+Aty6H6/oDPteLpE cUPckzSa -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZjCCA06gAwIBAgIKBGWDUkc2SpBKjjANBgkqhkiG9w0BAQsFADBnMQswCQYD VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH MTAeFw0xODAyMTgxODMwMDBaFw0zMzAyMTgxODMwMDBaMGkxCzAJBgNVBAYTAklO MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv Z2llcyBMaW1pdGVkMR4wHAYDVQQDExVlbVNpZ24gRGV2aWNlIENBIC0gRzEwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCX9SkTbGs60ZpHTqRXWRHOOMUZ ZAINbzBhS3OdXHoaEQ2I/HOqurYQO3zE35X9uXJWKnHRWl6ZS/H22pPLVMfL4PrK da3UhoMkGGDnkCcaf0vGkfxAN0svDd4r4LH9h7lhoX+8tBCUdEEZ1daRS05dxP5w JNOBg7aEVlF9oiAnpRPe7/eP1q7rVUF2bN0GNSYrWumZDD68HpdctIg46ORbk3/C jGNMPAN5mdOX2WzhNx/z+gC+9mU0qOzgViptNnHLxs3Q3UcWAGMsuYMUOgCZh6dc OaQOURGoAPoiCvXj+ccINm+7tP0OWsWGFFKWhmbmX4LLI9Nbwaehz4lx9ja3AgMB AAGjggEQMIIBDDAfBgNVHSMEGDAWgBT77w2GnrDj3am58SEXfz788HcrGjAdBgNV HQ4EFgQUC5N44uA1B23fhnePjFGN4zV8qXcwDgYDVR0PAQH/BAQDAgEGMD0GA1Ud IAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3NpdG9yeS5l bXNpZ24uY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYIKwYBBQUHAQEEJjAkMCIG CCsGAQUFBzABhhZodHRwOi8vb2NzcC5lbXNpZ24uY29tMDMGA1UdHwQsMCowKKAm oCSGImh0dHA6Ly9jcmwuZW1zaWduLmNvbT9Sb290Q0FHMS5jcmwwDQYJKoZIhvcN AQELBQADggEBAA2Wfa1hvlkem10OxKaGP5yo4Q+rSMYMgCvbWYIZDx5qefWK39h9 aCOz2omM8KsCeYukVdjxCmTUHumcimb+zNCIariDfBfefLgvviPVqcy/KH+n2uBE CW3t2ZLp8FEOTgc00byFRWrkSOgYKeUDfJHXkX74pty5/36hYTyOhwQHozdHCCAj QTqxbzciMDRdfGJiaAIzTHb9OrKm/5MlfVUK2gH/Uy2RbLSvEDyTG/1RI/OkRuJG lnZt1P85Ey8Ney4vS/sCiwd2qzsnclJ3ZqHLjCpvUgvzeP3Z8st6dGnKByV1Q1Zd FqC7Bs43V6c+D62dSjTdXWBHJbqM71UJG6w= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAqagAwIBAgIKI+G6At/z6QDt3TAKBggqhkjOPQQDAzBrMQswCQYDVQQG EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g RzMwHhcNMTgwMjE4MTgzMDAwWhcNMzMwMjE4MTgzMDAwWjBuMQswCQYDVQQGEwJJ TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s b2dpZXMgTGltaXRlZDEjMCEGA1UEAxMaZW1TaWduIEVDQyBDbGFzcyAyIENBIC0g RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASt0tTBgfEcQDnhwd1qvjyypyFq4kKi 3+Nw+UflaTgNrjD939y+XHaZMxGXJ8cMN28rfPl6x6TaScH7W8rQkRAWXN9xtTlb toTLlKqgEO4rNtq/qnk6BRwMIiTdj1TXAm2jggEQMIIBDDAfBgNVHSMEGDAWgBR8 XQKEE9TMipuBzhccLikenEhjQjAdBgNVHQ4EFgQU4Bb+vcThZcalmUyJXnGO1F1n 8f0wDgYDVR0PAQH/BAQDAgEGMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUF BwIBFhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMBIGA1UdEwEB/wQIMAYB Af8CAQAwMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5l bXNpZ24uY29tMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW1zaWduLmNv bT9Sb290Q0FHMy5jcmwwCgYIKoZIzj0EAwMDaAAwZQIwGzEuvlR0hO3AV5IsUNAL 35TiHMHusf0lwxFIJv0XZQY5opx9f4FUFfUnRXEYXKxCAjEA6mo32Hc+R+Jgpcdd GtaU+sZM9yhSS+TSGEn7hKHbXk0Bd0ApOg5Yd3HnOAFdWJTx -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC/TCCAoSgAwIBAgIKPRKhz3gljVgIVDAKBggqhkjOPQQDAzBaMQswCQYDVQQG EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw MFoXDTMzMDIxODE4MzAwMFowXTELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSMwIQYDVQQDExplbVNpZ24gRUND IENsYXNzIDMgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABKsVY5O2xPYp BqcOQKC8r71cXmv87bD5OgshY5S2ySOJP3Whdu25JJ2nEdh0VTPPBwCBc4zgVI7Y 99+WuX+OxFYmrS5aGs0Bg9hrbL8EjZ6RtFHosppOWu9WxHPx/elObKOCARAwggEM MB8GA1UdIwQYMBaAFPtaSNCAIEDyqOkAB2kZd6fmw/TPMB0GA1UdDgQWBBTxZquW jKQN0iZiMy+aVQld2eZISjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20w EgYDVR0TAQH/BAgwBgEB/wIBADAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGG Fmh0dHA6Ly9vY3NwLmVtc2lnbi5jb20wMwYDVR0fBCwwKjAooCagJIYiaHR0cDov L2NybC5lbXNpZ24uY29tP1Jvb3RDQUMzLmNybDAKBggqhkjOPQQDAwNnADBkAjBs /jtoTdEKKX+0knGdkaWlpybcPr4zK4xGERFGBzsHzp2ICpjxbJVBPfntkazaBUoC MEh5c0r35dVtpp4Lp5MuVlYujIrCk9TcHMGip9i9QIIOHaQRkD5wFU5uZUtZeLRB Xg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZzCCA0+gAwIBAgIKPFvaVcCiNqdEzTANBgkqhkiG9w0BAQsFADBnMQswCQYD VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH MTAeFw0xODAyMTgxODMwMDBaFw0zMzAyMTgxODMwMDBaMGoxCzAJBgNVBAYTAklO MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv Z2llcyBMaW1pdGVkMR8wHQYDVQQDExZlbVNpZ24gQ2xhc3MgMiBDQSAtIEcxMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1gZ1TdwRDB3ua++szG548V1 ISoEPlKHXGRqFoL09ivQSzyzUXbwDJ8g0iskj8LroIJnTQFympUZZeaZAUV55Hdt R8347u3UqwozUZRRVmAZUVuPKLehAuVbcRtbil+4f+XbsABFuq6R4p4GIfLv6Ztr wcpJ8KaGqor+t2q4hWBbuJWVgNd3rE0wMYuw36Me8YP3v9ONhdJbcWRhzkfDelSu 8MU8aCujsZ9g/OvYre8d8fhNmTq+mS99TNuqDsZ8ieW1OI4x/gGksCCgxEYdmPWa wFC0BMkzwA1p8FTF3y8S3iVq1sa04AQZHMxXuHnjahVyLnL7ibxXaDLjqCZX/QID AQABo4IBEDCCAQwwHwYDVR0jBBgwFoAU++8Nhp6w492pufEhF38+/PB3KxowHQYD VR0OBBYEFObdDbmb0hVAzyMILWwZuFxoMlIyMA4GA1UdDwEB/wQEAwIBBjA9BgNV HSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnku ZW1zaWduLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMDIGCCsGAQUFBwEBBCYwJDAi BggrBgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTAzBgNVHR8ELDAqMCig JqAkhiJodHRwOi8vY3JsLmVtc2lnbi5jb20/Um9vdENBRzEuY3JsMA0GCSqGSIb3 DQEBCwUAA4IBAQAfkiWA3dGojWbT9FskfUTekEgYp1i5g5/oBngPbug8JMgizH/e YeshF0+DVi+cxvXq/J6qoHL5ihe6K9Wc6wOXQAfq8g4aXC0OUhZN29QFNRzwWvSq 4HtpDkIOb9SNGW7KMaHPRyN3juun/wElp5Chp8iejsbE4cf5YcBQYpzcGXW5IktT 9k6tHS499J+SXu0BQGtMw78AUFdvqpSFpJr6MZWKQtHRz35gHMMqXGhFSVKbAYGW YoXa4udBcmpnQ86a9gYYLw9uA+XUayCar9bmu6XqjQ+RX9wXn4pn+BryHbbxSG0d HlrvB8UnCHx4bA2DLomVJyN+WoGfnkd2CT7K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIERjCCAy6gAwIBAgILALR09k2GOSGJSW4wDQYJKoZIhvcNAQELBQAwVjELMAkG A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw MFoXDTMzMDIxODE4MzAwMFowWTELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMR8wHQYDVQQDExZlbVNpZ24gQ2xh c3MgMyBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzY6S gZflKotvv/PRuvsXsSmOGbTUCWcQk65ZNvKXPi30WgBjCmugQNx+9anV6TSTYm+s pLpPI5TEEw+JFROYDrylT5NQ1AQkBcD8lSl1oyydJLlVwiYIGHf+Dh/DNYHAvS1/ VPieDtOdQ0ApoQdc9NB4ogURvBu60g0IlWTwGsAJlUIy9scXhXY/yDszE+uw+xcw oNAHUmShaQFndamaFCAeqb1XckI4TgMHIxB/F8zsj37S4LLZcm/vFJ5toKSfbHVo 5Y+ys7WfFgYzQgKU1kdxlmuQ0WxL0qSMYpwHlT/rGzvvkKUAfB1d7xcRpKojucCc xUHGkYyDeUc6Oc2ULwIDAQABo4IBEDCCAQwwHwYDVR0jBBgwFoAU/qHgcB4qAzlS WkK+XJGFehiqTbUwHQYDVR0OBBYEFHuepsUnfmSXq4QBOuomlmuSTofhMA4GA1Ud DwEB/wQEAwIBBjA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0 cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMDIG CCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNv bTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVtc2lnbi5jb20/Um9vdENB QzEuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQB4jFM8EfFdad4cWPuihvDqPsH1BWBJ TdNf9zIpBt9u8HQevk/OtlK/3AoIXudzlTH8GK6hkshupL/ccdBhrTRPzWZTxQUt WDWUc2Waa9SV/I7t8X3yhFAlPPhm5bCxegGAAV8icOwlMBZS3r3BvP6iOcfzNqpZ jJ6oDzjqJ7Gvbar6Ao0EtEhMQ8XnJCz7XWNwOLqE/laqZ4jb7dN9XXu9s1eNhLLQ EA1nHUWz8OyQu5nljCqmVT+fG4lvr3pJ6za+4vyNht+QdaX5rKzbtc6tZLv2MJ7t zEQFW0OfgKQYTZrNKxBYGhqOeu4Necdbyf5wvKqGV4Fm/+ZbBxzvFVGW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDPDCCAsGgAwIBAgIKct3H6dzpsNz/xzAKBggqhkjOPQQDAzBrMQswCQYDVQQG EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g RzMwHhcNMTgwMjE4MTgzMDAwWhcNMzMwMjE4MTgzMDAwWjBqMQswCQYDVQQGEwJJ TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s b2dpZXMgTGltaXRlZDEfMB0GA1UEAxMWZW1TaWduIEVDQyBTU0wgQ0EgLSBHMzB2 MBAGByqGSM49AgEGBSuBBAAiA2IABBWwpaaD8WGEIlx1uQ6G9FY35y+AJ0ewgoXe ZPXcz2OkkD6WNqITMSn+Nzl2489ITUU5GH0EpjWuujQv6stEYule7AVb7OolZsvz eMXdq/2g5DHXGlW1FGc10DYx+9xynqOCAS8wggErMB8GA1UdIwQYMBaAFHxdAoQT 1MyKm4HOFxwuKR6cSGNCMB0GA1UdDgQWBBQTjUwomeFit9LgU+MY0WLcHMpm+jAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMD0G A1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3NpdG9y eS5lbXNpZ24uY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYIKwYBBQUHAQEEJjAk MCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5lbXNpZ24uY29tMDMGA1UdHwQsMCow KKAmoCSGImh0dHA6Ly9jcmwuZW1zaWduLmNvbT9Sb290Q0FHMy5jcmwwCgYIKoZI zj0EAwMDaQAwZgIxAP0zh/Pwvs1KWlruB+iqwSXWXUXxJ5RcvNhoMoT5Hq164K8i 4lb4tfVNV4Hb89HfugIxANXUFpJ5DvDugBmGsWIh3UDLY/MaIJr0LCyB3vebwqGw eYppriQcyxqeG4xCXYLOcg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIjCCAqegAwIBAgILALjrJYMk2wiswvUwCgYIKoZIzj0EAwMwazELMAkGA1UE BhMCSU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEgVGVj aG5vbG9naWVzIExpbWl0ZWQxIDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAt IEczMB4XDTE4MDIxODE4MzAwMFoXDTMzMDIxODE4MzAwMFowbjELMAkGA1UEBhMC SU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEgVGVjaG5v bG9naWVzIExpbWl0ZWQxIzAhBgNVBAMTGmVtU2lnbiBFQ0MgQ2xhc3MgMyBDQSAt IEczMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEt/kiu55eyuZ/oAxsR1UMkQ9ytN3x wX/7w2eOL1+R9TafuuD9YRcVK6oFadIw/ar5I0I22WAw9/Gwd9zI0DPTe/2Zho6m TMNIH3LFgdRX5g7+hTH1vBv8UHqXXqiR1ys2o4IBEDCCAQwwHwYDVR0jBBgwFoAU fF0ChBPUzIqbgc4XHC4pHpxIY0IwHQYDVR0OBBYEFCJiSrx+baEwtyrJlX4qI949 J/ONMA4GA1UdDwEB/wQEAwIBBjA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEF BQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTASBgNVHRMBAf8ECDAG AQH/AgEAMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3Au ZW1zaWduLmNvbTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVtc2lnbi5j b20/Um9vdENBRzMuY3JsMAoGCCqGSM49BAMDA2kAMGYCMQCfcM3DXIEnxOkAE4co /IRvdClPVNvHbO1eSrrH7tYklqpCoPbFlm6wwuj5JTXPJvoCMQCzTp1mDKZnJwbr gDOCrI0PYxWGPWpI9g/YRh83rrsb8XmDdPrtOWZBRifZu4v0o+4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAqagAwIBAgILAIdigqj9dYw5HsMwCgYIKoZIzj0EAwMwazELMAkGA1UE BhMCSU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEgVGVj aG5vbG9naWVzIExpbWl0ZWQxIDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAt IEczMB4XDTE4MDIxODE4MzAwMFoXDTMzMDIxODE4MzAwMFowbTELMAkGA1UEBhMC SU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEgVGVjaG5v bG9naWVzIExpbWl0ZWQxIjAgBgNVBAMTGWVtU2lnbiBFQ0MgRGV2aWNlIENBIC0g RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ5qPpBiN5BbQSUldNBlP6FO5jLtouf abBDLwXTXzcgFwakNh89uO5ug1m0M6QhLIZRkLOMxH4BMJ+rMb1lHnryjrp2i7la XdsPk2ZCGLzcUnp3QA8ZBzzJhfHYSo1m8eujggEQMIIBDDAfBgNVHSMEGDAWgBR8 XQKEE9TMipuBzhccLikenEhjQjAdBgNVHQ4EFgQUpaz5H1oljhCwKdoZACaG6KHm 6NkwDgYDVR0PAQH/BAQDAgEGMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUF BwIBFhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMBIGA1UdEwEB/wQIMAYB Af8CAQAwMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5l bXNpZ24uY29tMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW1zaWduLmNv bT9Sb290Q0FHMy5jcmwwCgYIKoZIzj0EAwMDaAAwZQIwF7tFSgQvVGC3YidTEIxu 26OnAEvCij1ebFju9WG0Nc0eQG3pPqdnh0OgixpWv+cXAjEA9ksmCrk3ZASLdG7y WDeiPyvdwWWx0Xuj5hKEnm8U7GbtQ7BSFKMJ6kjRqlmb1GlX -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDGTCCAp+gAwIBAgIKW32bsf0zubwdhDAKBggqhkjOPQQDAzBaMQswCQYDVQQG EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw MFoXDTMzMDIxODE4MzAwMFowWTELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMR8wHQYDVQQDExZlbVNpZ24gRUND IFNTTCBDQSAtIEMzMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyEjAcnMq9drjRUIE hxpHjSAZxpZwTa3qXZ6THcyfjQIldowaWIyyKMxvAjWYZl3GC9XEJILaz5iUaXr1 Gy0q1SsIE+gPg1LnGVLDXOcSU3MbBoBgZoL5yPiScUvSeGIgo4IBLzCCASswHwYD VR0jBBgwFoAU+1pI0IAgQPKo6QAHaRl3p+bD9M8wHQYDVR0OBBYEFOPolx6/xD06 sNz3HZ0/XyyxbetsMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADAy BggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLmVtc2lnbi5j b20wMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29tP1Jvb3RD QUMzLmNybDAKBggqhkjOPQQDAwNoADBlAjEA/HGlD9A9u6B0MR2YaPa+6epy4Kou oK7En7a0p3ESe/DroYG48ys9SUGAZ3+gr4OnAjAIbqwFSaxsvNTrolD0mI99iDA7 sranVo+LcI5dCGkaCSNzr7m1eJVLIUi/s7Su2PQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDITCCAqegAwIBAgILAPseIZgusbVcWSUwCgYIKoZIzj0EAwMwazELMAkGA1UE BhMCSU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEgVGVj aG5vbG9naWVzIExpbWl0ZWQxIDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAt IEczMB4XDTE4MDIxODE4MzAwMFoXDTMzMDIxODE4MzAwMFowbjELMAkGA1UEBhMC SU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEgVGVjaG5v bG9naWVzIExpbWl0ZWQxIzAhBgNVBAMTGmVtU2lnbiBFQ0MgQ2xhc3MgMSBDQSAt IEczMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEOReHn35H+3QHeBQoo2GaV/M5/wJ3 /l+RYkEm6Asuf2xUlYCMZmokaSzC3Z05V2kf9LAevtB0dSecVMz8l3XGVoaIaaLO fxmAIPPlvVyMCJ3EgnCAGH+1ZONRf35995B5o4IBEDCCAQwwHwYDVR0jBBgwFoAU fF0ChBPUzIqbgc4XHC4pHpxIY0IwHQYDVR0OBBYEFEa+gMPIJ/7sm1grGmJdstXR AjhoMA4GA1UdDwEB/wQEAwIBBjA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEF BQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTASBgNVHRMBAf8ECDAG AQH/AgEAMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3Au ZW1zaWduLmNvbTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVtc2lnbi5j b20/Um9vdENBRzMuY3JsMAoGCCqGSM49BAMDA2gAMGUCMQC+j9TyTWudMq4HdKE/ 1ib6vzapfBmQ/8Vbu3PHCMWPdpfLCcBSwh24bUOxKeVlGx4CMHfW32Xd+90Z/5IB A6lkX+6E1Tl588OddGhKwsLq3T3CVjwcIZMBWhRh84fcqIAdaQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDHTCCAqKgAwIBAgIKG1BYH3M0swsnIzAKBggqhkjOPQQDAzBaMQswCQYDVQQG EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw MFoXDTMzMDIxODE4MzAwMFowXDELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSIwIAYDVQQDExllbVNpZ24gRUND IEVWIFNTTCBDQSAtIEMzMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEDv1Ol3bDxlGB ala4t3g3KFCZ0xD+OutvrHBHwGpGbdAB1Xc9VvwVnL411pQ3BU3E6cqj0ZOzTetb 8qW0rRWKl+hIo0Zq+nAV5S/M41t/N5t37cQkJv2tnSTwSnAUM/CQo4IBLzCCASsw HwYDVR0jBBgwFoAU+1pI0IAgQPKo6QAHaRl3p+bD9M8wHQYDVR0OBBYEFEi3aOg8 suaxEkRMxNfTmgtv6VrGMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEW HGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wEgYDVR0TAQH/BAgwBgEB/wIB ADAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLmVtc2ln bi5jb20wMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29tP1Jv b3RDQUMzLmNybDAKBggqhkjOPQQDAwNpADBmAjEA4rW0NYDpnpfRcmVfGS0SD5il apt0hqCSJeE1OctiXrn22WtIIjOERmOUD3AHXYPiAjEA1wNB4UxxrucJVDiGcRCi skqSL+BnLAoomcPYC9ETImRiChgpdGzelBT14bB0HKXT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEaDCCA1CgAwIBAgILANWbfJs2otRJIuowDQYJKoZIhvcNAQELBQAwZzELMAkG A1UEBhMCSU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEg VGVjaG5vbG9naWVzIExpbWl0ZWQxHDAaBgNVBAMTE2VtU2lnbiBSb290IENBIC0g RzEwHhcNMTgwMjE4MTgzMDAwWhcNMzMwMjE4MTgzMDAwWjBqMQswCQYDVQQGEwJJ TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s b2dpZXMgTGltaXRlZDEfMB0GA1UEAxMWZW1TaWduIENsYXNzIDEgQ0EgLSBHMTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxsGEyj1Ff+Jf3rXeVJfQQL xWijpNKSYaKfLwClLWuVgDMdL1vBVpMy3MCrcYKlLvGsET/6CFzYdqdamP7P5N6C D7BXQkYGVvzJimPtO/eaj46YdDSx91/FAxRkJQNVargAqbCQiYZVZrZe13x9FtIs Wc+wiAAIvyaDnfl5Uc7srAYRPpxbwUBvsKL0P5sX1vNKaCz/wxRARMRfg13OzuOw +jrVkF/y/7bfhxie6K2/d0A/em3rmmfsrDzFUwge9rI4QohUnJngVST9zUMTGKbj +QKSijdenYiJu/LFNm8bEg4Vn6tM19rgbb3LH8wwF9wS2IcDzX0Xz/KRJROXogUC AwEAAaOCARAwggEMMB8GA1UdIwQYMBaAFPvvDYaesOPdqbnxIRd/PvzwdysaMB0G A1UdDgQWBBTcYI8K3rGZhJuEQAPjdQMyA4AAkDAOBgNVHQ8BAf8EBAMCAQYwPQYD VR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5 LmVtc2lnbi5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADAyBggrBgEFBQcBAQQmMCQw IgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLmVtc2lnbi5jb20wMwYDVR0fBCwwKjAo oCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29tP1Jvb3RDQUcxLmNybDANBgkqhkiG 9w0BAQsFAAOCAQEAMFYsJUg/auGHNrj+JJi+xv7f5etIB/NXArZLnBsi68WBx3hv 3Vxng658w6WCEc8GeJesEZrP9pbClWMLSikhb7VHc0lVROdOE4VlZvgSiHzRvM6h m8RTiN9rRLTt06zC/PYAOgi5KavCRaWptPh95EUp+lcvlK040obb6BGimoYsX2gl hzOQcCgRBgApCNYwUbR2QLK5qGbt0Nyidwe5Iut7mwDat2ElFOeUQ3HWr20+vHfp PT+X7+DwPmIzRS9fuq1er42SwiJd+0BdUCjlecevaZG4wbVMTFxycLw72e7gcDss OagPoy4AoaUbnMY4VKvDSpVjRSZ23SRY8ZQOxg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIERTCCAy2gAwIBAgILALGb4wgeLZe1v8swDQYJKoZIhvcNAQELBQAwVjELMAkG A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw MFoXDTMzMDIxODE4MzAwMFowWDELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMR4wHAYDVQQDExVlbVNpZ24gRGV2 aWNlIENBIC0gQzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCl9ip 9fb81Ji5Q4IYdmGd7/W07NiBwVc88fio32d+fFhqy8RcdOQnuxNy4IPVaEkybu7T xIRFqsKkJeuOugeVSxHW901zor5tcB41M2Qoc9UHsLN0YccirTO7J5a9ZCX6f665 wl8vwCrxkS9bYbCtzTPlzD3JZYviySklUvViqL5VIBgfhC1xip/8NsJr6UOVSxqN mP7C9RPRGGA+TXf2r7/lJmN0bGQZMQXkvTjXW3ByWiQ2IIbv3eo8YL8ZQa/F6ngc jl+8axlGwkjIQW59UJuT7J4g4Yq4oBIlPQGD9lZdGalXxQv9S0u0ObrTmNTHo8co +69knHPdf/oafdWJAgMBAAGjggEQMIIBDDAfBgNVHSMEGDAWgBT+oeBwHioDOVJa Qr5ckYV6GKpNtTAdBgNVHQ4EFgQUksV8rWMg5Uwjz2kRz6eH+4H0kfgwDgYDVR0P AQH/BAQDAgEGMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRw Oi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYI KwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5lbXNpZ24uY29t MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW1zaWduLmNvbT9Sb290Q0FD MS5jcmwwDQYJKoZIhvcNAQELBQADggEBABdsR/hE2wna+7CC1mCXRJGQE9Rlreg/ /hsyKY7Y0vf/BHZk57YYY725lRg9mCESnNaapHcW6vpHlMF8kNN/bpcP7AKPG93T ePGF4k8oy1ME4/L6hpy+HYku56Pp7EgMFOxAX+q7g12cQlZN0laQjlSv87CQuQ8Q Vy5bZkK4Zof4fc72WyBXC2RKldeCk7zZ4h8qlPqIxJZGDRIdL8NylKkuzKfEF7Hf FXQbjMofLOjJHp88FAuOVCcO/YHSqvfLzcZPtkAsdtTJsFXqp+ePAtyq20YufMVv /AndNbcn69bKGqCFyeZTTB4YG3sNG4Dj+QoAyJZ3L/67XmHE4vEXv/U= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC/zCCAoWgAwIBAgILANEUJ2Zpi/ze2gIwCgYIKoZIzj0EAwMwWjELMAkGA1UE BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5j MSAwHgYDVQQDExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzAeFw0xODAyMTgxODMw MDBaFw0zMzAyMTgxODMwMDBaMF0xCzAJBgNVBAYTAlVTMRMwEQYDVQQLEwplbVNp Z24gUEtJMRQwEgYDVQQKEwtlTXVkaHJhIEluYzEjMCEGA1UEAxMaZW1TaWduIEVD QyBDbGFzcyAyIENBIC0gQzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQX0DJDuDta mLJE7/IRFQFlTcXslMujGM5ctACM/HD9I1Tofl9Ln9qaUyxsttbv65dLd791Y410 1h9g94JqhvlPBubcMCcY0+BjvVmO7P05KeEpwcmktfnYAXofOupFc4ijggEQMIIB DDAfBgNVHSMEGDAWgBT7WkjQgCBA8qjpAAdpGXen5sP0zzAdBgNVHQ4EFgQUVkyJ uCXImO698nxiLa5pOTq2FywwDgYDVR0PAQH/BAQDAgEGMD0GA1UdIAQ2MDQwMgYE VR0gADAqMCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29t MBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzAB hhZodHRwOi8vb2NzcC5lbXNpZ24uY29tMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6 Ly9jcmwuZW1zaWduLmNvbT9Sb290Q0FDMy5jcmwwCgYIKoZIzj0EAwMDaAAwZQIx AMOYzD9ECUONHwtVYK4aLJUsxYhrks75+3XEPWDz2vIXnKMD7mgY+7zEo8fRSrYO eAIwATmREIgZsvhS85StHYHvw5GuYl6D5o1GQcAvcF5d6CcvYVJZKI6WigV08+36 h6eA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZDCCA0ygAwIBAgILALrf0ps/HmeMaWAwDQYJKoZIhvcNAQELBQAwVjELMAkG A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw MFoXDTMzMDIxODE4MzAwMFowWDELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMR4wHAYDVQQDExVlbVNpZ24gRVYg U1NMIENBIC0gQzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmkb1L x0+6eN56d3D9Afd0fc/Qp5U2YAv+58LT7MdksmffNOU0Eh5lD/87lnFH89Dfb0D9 ru9P0cuvllMJoQIJzEGShiZ1K50XZKz/xTUwYsQHYL4KtAKCTHdZjy6WsKS8VAoi aqHJAxmlI1vEXGESsGzCmy6TQyjNpIXRrHHlSFMtNn6NUllARATWjmm1vXqeh4M4 ru48RuFJ/AvKLQwXWHHTfUNBEI9gSwmLTfenUBKUeLHnSJFPR3mSuEgg/Q1+Y2bG HHpe1IBy1Qg9M0UZMMeQhiy7SLvRu18MTJ8NcvDmpaKnrfO6+QLmwMl65/wdnz4i u2bpYzFR8mQveFtLAgMBAAGjggEvMIIBKzAfBgNVHSMEGDAWgBT+oeBwHioDOVJa Qr5ckYV6GKpNtTAdBgNVHQ4EFgQUyXEWRUM7Fl5fRv3uNU1Ee32udQcwDgYDVR0P AQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA9BgNVHSAE NjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1z aWduLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMDIGCCsGAQUFBwEBBCYwJDAiBggr BgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTAzBgNVHR8ELDAqMCigJqAk hiJodHRwOi8vY3JsLmVtc2lnbi5jb20/Um9vdENBQzEuY3JsMA0GCSqGSIb3DQEB CwUAA4IBAQAzd2UxT3MCEOyLiutoG4mkAo6UGNooruBKvRMfAx0IWndWqt9rIIMv pOFvvuCWAxVILnEWihw1MCBka08EzEBVJq1SWffJZ51YmyZrlvuJhoipaA7KRGet DzFBdGF86BG4dFVRbgMtfAen8YkkHMMfvL1+mP75Vq3vMm4E+LkIgjUlPzy0h5Xb l31QmWBgz87v/MC2ICLBaWVi45/yNA60Rcu1+Xf5C6WBjPLRHgcDPEbXWm5QmCpG 0Is6WQHHGux8m6d4/1OQ6eftBPSahqPBbFtWhBsac3mdPubbMd2QPOmIUv/BCU+z eRRgbcq+KBV0blu2NkktFW/LhsAlcl+E -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYTCCA0mgAwIBAgILAIZ2a3+W32DEb4swDQYJKoZIhvcNAQELBQAwVjELMAkG A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw MFoXDTMzMDIxODE4MzAwMFowVTELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRswGQYDVQQDExJlbVNpZ24gU1NM IENBIC0gQzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCLGiQaEHp 3ZpW+vTk4Jj6i2KGMMHtHtCBrarQ/A2xLQYKsk7/8Y8aA0X6KfHnHzD6AhUCIn2w KF9J08YVqFEtxqzHIR2v6zHNdeDlBi8XJk+5Ip/+G0Vs7d0pcF+bvBknvnDLBN3N EE2eP9NCQgHtP7Sa2VKTKQAGcytyi7J13nOsvYJTdrbNaxijt35FnWAjo5OBlMch FVgCFWZI0zowacJ7juV7ebzFZpSvbThBsDKlN6k0DTpatG/xhC8kSMnCnwqdwyXw o2Zj3iVrbSa0TLA7Q2B9pjKEmKXYWYwTQ+ZWFWDYR3bdHjksKJ7VZ3JhG4997LHE NIVX86JupgJPAgMBAAGjggEvMIIBKzAfBgNVHSMEGDAWgBT+oeBwHioDOVJaQr5c kYV6GKpNtTAdBgNVHQ4EFgQU/MUVQPGvTxOymPJxDmMVN9GUa3QwDgYDVR0PAQH/ BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA9BgNVHSAENjA0 MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1zaWdu LmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEF BQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTAzBgNVHR8ELDAqMCigJqAkhiJo dHRwOi8vY3JsLmVtc2lnbi5jb20/Um9vdENBQzEuY3JsMA0GCSqGSIb3DQEBCwUA A4IBAQBmHDB5OlNSjHXmRh7L/Z2Mpfdn9uFd6HsQPefkcNiTfI5Cn4P7UkS6qaxO znuuZUxKYlJQIhnFPgpndyBRDsTF+tJfH9KzdIKZMz12hsINphQ7I1XiqZtUusZ6 Gg7mS6+P8d7m5BvwJVvTlLVv6eWacQdY5HCloh8I6QOZM0TMVqkM+aWtMyoqx0FR MUBN1vHFxYID2TRMPxkDAst0a3jeTAf3NfN49zcG7XFAkhiCZ7a/+Kzh4DD4VXkO KCaRsIMyAVG9gVmDDZGtXaOP84tYKau15V7mPSQ3LySNu7k/yfz+0PdiSkVyJqAr wxcLVB190uhSK8ZkIF/0Vd7rGSfN -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC/zCCAoWgAwIBAgILAL1qB5arP4lVUh4wCgYIKoZIzj0EAwMwWjELMAkGA1UE BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5j MSAwHgYDVQQDExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzAeFw0xODAyMTgxODMw MDBaFw0zMzAyMTgxODMwMDBaMF0xCzAJBgNVBAYTAlVTMRMwEQYDVQQLEwplbVNp Z24gUEtJMRQwEgYDVQQKEwtlTXVkaHJhIEluYzEjMCEGA1UEAxMaZW1TaWduIEVD QyBDbGFzcyAxIENBIC0gQzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASoJc/giurH D7w9ijG388IiMnqoVAnpOyBrSXjcm45/m/T7ALE8Rg9/SqyNtzFbY+na42cTbydv b7AmTe+p1ExAuJ3Ny8VhXNOoKVidL3bbJuPhSrGFcEfZuJZ+m9CxkNCjggEQMIIB DDAfBgNVHSMEGDAWgBT7WkjQgCBA8qjpAAdpGXen5sP0zzAdBgNVHQ4EFgQUjNmf oCE1Pvy0OplsLvIKKW/w7JIwDgYDVR0PAQH/BAQDAgEGMD0GA1UdIAQ2MDQwMgYE VR0gADAqMCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29t MBIGA1UdEwEB/wQIMAYBAf8CAQAwMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzAB hhZodHRwOi8vb2NzcC5lbXNpZ24uY29tMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6 Ly9jcmwuZW1zaWduLmNvbT9Sb290Q0FDMy5jcmwwCgYIKoZIzj0EAwMDaAAwZQIx ANsPTeeAHls5YkdQsmtqCJaDb67/euMmVnZs3mX47ZkZwNEkR4mK3gZQXHDso6pD BQIwN2+5oFgzWnl40VFSJ+ERw0u+9Pe1peo/FRMMg/ofrNXfyjIYBOq63AdqSK/y 3k73 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDTCCA/WgAwIBAgIQdD3vyniwkl6U207/6YfgmTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgw MzE2MDAwMDAwWhcNMjgwMzE1MjM1OTU5WjCBgjELMAkGA1UEBhMCSlAxDjAMBgNV BAgTBVRva3lvMRMwEQYDVQQHEwpDaGl5b2RhLWt1MRQwEgYDVQQKEwtHZWhpcm4g SW5jLjE4MDYGA1UEAxMvR2VoaXJuIE1hbmFnZWQgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkgLSBSU0EgRFYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc dVshOzy6xhF2FG2o/Pwt1ffvFz9YY/DKfyJSZFLOPSRmP7ZmoOgAvzTINNWQvzLM 9iZRUwGGbr/c+OtMtb7KGqEnTmkP0fhLHXesLuUTmrCbmV6VzL5VijXDsfjlrn43 xA/ymUcEdfBYNLX58FH6mzTgsmeh6QOITSv6rSFDSydMDIxfKbhaTszreIOZwsdp Af98tSKWPYC2yTrBuYyJgl1dUEvLqIu2Hl2fZvh3Gmsfl21raXDKdOe3X9pLnM3W n+P7F+maxBWMnl3Shr171aRUtUycDd0jOSKsR1/cGWBWBmHtnCh/DgUS1nG77Y32 MZeU5NBXqf9Mb+HB++UzAgMBAAGjggF1MIIBcTAfBgNVHSMEGDAWgBRTeb9aqitK z1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUEuZqJYZx7cyOaQxZGcAHvByorUswDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAjwwCAYGZ4EM AQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V U0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcB AQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VS VHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3Au dXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEATR9krPFDiZuXi+hX78Ee 815XzEkjohsaiBT88hkZ+7oz/7CQYRedRnm+/IixHj44KGWKTeltDhNcpW+h6iar gYo3HLrCYuYKFRZYZCNXM5aPe3qGHrhEkN81MA5a+YIZAgfGhvSWV7tMPLS3LRei vIeq/TyGrH+vYswmme1AMBJ5wV7zuUfO4kpHchTuyMROFd4nTTLbvuzBcybG94Sg tzlQgGoHxFXzGnP8ItH+O+GyN1HQLSCFeU1vb7SOj3dBWq1y9Rhx7EWPAUv/R6/u FEJleLjfLuH8a6na2hAV9w5ju/L+7eJDK4Jqg6mj6M0WVKQHoxgdtV7Uks2EHZHz EJ52qEr6GCCH+N2t6+lgX70QTPd3HTrBHq3+gt1Texkc5HcxNleMNTapdnYLAgbH lV/+dAzDdOstgJxuKUTTbHkQq9PsK9D3B6YSLE77uMB8CYIz4cMMXSyl6eYW/AcN w5nhdYaya9/qln8wsjwHpcIyMm6VDZ56YUO9+lYlTWckoYUbFfYycu1vjBGk3jwO lv25gzKLkCGB/U5lzjZiOFpdTWR2RWETaF1jj3WZ7eq5U85U1hKQcyjhhW17eztv JbSjfvEVpi43tDzWmuiV0AQwhsZDzQxiijlkxEGSzR/cr95iqTwYpJI514ebJYKM cy5eYlU0tPBtcpF1t46HmAk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID+DCCA32gAwIBAgIQWdjqmvmL2NcDgGC3KHivgjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgwMzE2 MDAwMDAwWhcNMjgwMzE1MjM1OTU5WjCBwDELMAkGA1UEBhMCSlAxDjAMBgNVBAgT BVRva3lvMRMwEQYDVQQHEwpDaGl5b2RhLWt1MRQwEgYDVQQKEwtHZWhpcm4gSW5j LjE8MDoGA1UECxMzQ29udHJvbGxlZCBieSBDT01PRE8gQ0EgZXhjbHVzaXZlbHkg Zm9yIEdlaGlybiBJbmMuMTgwNgYDVQQDEy9HZWhpcm4gTWFuYWdlZCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSAtIEVDQyBFVjBZMBMGByqGSM49AgEGCCqGSM49AwEH A0IABGMD1olt9hRphcDEBFNLSznWEGNp396VDjIwKXFEHTefBb8XXufyJrG8iB3Q Lx9prjBdzVYm54VirqLrernwLX+jggGNMIIBiTAfBgNVHSMEGDAWgBQ64QmG1M8Z wpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQUsfUQuAp/XwlKeIXBoMFX1IisKlAwDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsGAQUFBwIB FhlodHRwczovL2Nwcy51c2VydHJ1c3QuY29tMFAGA1UdHwRJMEcwRaBDoEGGP2h0 dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6 Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAl BggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQD AwNpADBmAjEArVSob+U7lXhMJ50k644j6ozzVVmsKqrQ19m3ShK9mVrjUljo3pik UwzArP72JpR5AjEAocbFI1NxqReXrs+NwPZOmEkaa5JlcUutG30d9ilvMTirjRD4 rsBrAjrEYh5vb6GB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDojCCAyegAwIBAgIQVcqTCol49JA5uqgS43fjJjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgwMzE2 MDAwMDAwWhcNMjgwMzE1MjM1OTU5WjCBgjELMAkGA1UEBhMCSlAxDjAMBgNVBAgT BVRva3lvMRMwEQYDVQQHEwpDaGl5b2RhLWt1MRQwEgYDVQQKEwtHZWhpcm4gSW5j LjE4MDYGA1UEAxMvR2VoaXJuIE1hbmFnZWQgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBFQ0MgT1YwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQWaOsTMpJVnIu9 sAg9gQ32Nh/7thi++Kl521U+IcnUSYs6jTPiGh3bV+Z35ydIsC/OsIpnHkK3kMe7 /cI53v+Do4IBdTCCAXEwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5ow HQYDVR0OBBYEFI7U+CGHuP7kGXUSYs6J5qL6A+1+MA4GA1UdDwEB/wQEAwIBhjAS BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD AjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgI8MAgGBmeBDAECAjBQBgNVHR8ESTBH MEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2Vy dGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUF BzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQWRkVHJ1 c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w CgYIKoZIzj0EAwMDaQAwZgIxAPsDjoxk6+DiC5m8OqOYv21U8FnXyoNvpM4d3xwS DZrIfnyd1Kfbu+UOSXY/3ZO1dQIxAImlru2i9AfI7yr/SG2B07yXB+yOFZRxomKk 3FUVs/ZDIeCH7HpHvKDj0ItaSC/BXw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGYzCCBEugAwIBAgIQJ+vDeJVmhqHyso4U7nc2gzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgw MzE2MDAwMDAwWhcNMjgwMzE1MjM1OTU5WjCBwDELMAkGA1UEBhMCSlAxDjAMBgNV BAgTBVRva3lvMRMwEQYDVQQHEwpDaGl5b2RhLWt1MRQwEgYDVQQKEwtHZWhpcm4g SW5jLjE8MDoGA1UECxMzQ29udHJvbGxlZCBieSBDT01PRE8gQ0EgZXhjbHVzaXZl bHkgZm9yIEdlaGlybiBJbmMuMTgwNgYDVQQDEy9HZWhpcm4gTWFuYWdlZCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSAtIFJTQSBFVjCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAOR14div88TwD7xKrgvxrp5JNl5YGeInbA4FFUF5tx5Y4btV Fpf3tzJzyhrYdDL17y6AxTCH5w50OF5GeUcAIz3duDZ9/7IsbV5Al3jO/SY7QEgj hs85bXKd2rR5NiOCGqYA6BFNIMrA+ZsJN65aTq5W3KkpZ+U3Kz1lAH0ka9rf6HhN MYkP7DaEXNfXoouC2HIq3zAG3gEhEjCb5ERJXgzZBHz0ug2gmTo3yFkqQa0qe4CA leaAEPQ3Rqh46o0BoH0FCC4zi60k3OR8CxpJfFb0u51k5+1rDmxeYqdkueXgDBBV sqPGNn1JTLUyx3ThszvYp9b2z2FvkzfYYxTKzFUCAwEAAaOCAY0wggGJMB8GA1Ud IwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBQWrDmdJ1Ix/DS/ lhm7liH2TUBWCzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAd BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwOgYDVR0gBDMwMTAvBgRVHSAA MCcwJQYIKwYBBQUHAgEWGWh0dHBzOi8vY3BzLnVzZXJ0cnVzdC5jb20wUAYDVR0f BEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT QUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/Bggr BgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFk ZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3Qu Y29tMA0GCSqGSIb3DQEBDAUAA4ICAQA/oS5oI0iLE8FocdcGhMP4DkUYlNefQyjV O+0l7M9x997EwgfJUiBRU18dJVSNxwSqT4gNMv9KoBH3vS+ozbbh5i46wPf6Vx9A ihqGnv6OK4lgHuRrKwfIqJ74gWSj0mznGhcTEDbm2XDfJ9ok/+70WnJFKGssvA+t Y/Y8EuQGi8ue2lZZkvrnVraNAnWq0NgtHZMWmJi108BS9OYAp7Br2r10SpGM1noG uB0OgFv+OjxYt1uFArTY6k94h+c5QPfoYi1BeDbe6BLSd7/k6ekZHCHttb/wuP7u r56066ZiTT8yyMeDQiUFcdBUv/Kr57I5Tj6aRM7egEdzxYjIn6THEd9s7XwQZBy/ e6V8kZzGk5NpR3L1n+VgUdUaRa0SjN8eTav98PE1CSO66xDXHgNBaXlrrDKnh5b0 may6dKEZPLTymQXAZFZrKlq3+25akd3O3P6Wg39pWgNefCJZiRMYAKN9md3AHWpN VKRPr5mOj3oRH3DevRvRoZTNvG3kkArphpr957Taaqio8J/362+hG0T4KjrWMq/H UKhvDpxQQAqrwz0JTxPc+DsWS4TKgNtRxKSB8Qgj21J1skKNsOSFX3uJn1V6KiiH tALvG8wa2DovFMB/l7aoUvuXvqFSdklTvgG3dM1WtkiJVkrLX19Q6PtmyCctrhwL CvhVBCVzPQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDDCCA/SgAwIBAgIRAJO88SPcY1wBm065Y1j/9EcwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MDMxNjAwMDAwMFoXDTI4MDMxNTIzNTk1OVowgYoxCzAJBgNVBAYTAkpQMQ4wDAYD VQQIEwVUb2t5bzETMBEGA1UEBxMKQ2hpeW9kYS1rdTEUMBIGA1UEChMLR2VoaXJu IEluYy4xQDA+BgNVBAMTN0dlaGlybiBNYW5hZ2VkIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gUlNBIERpZ2l0YWwgSUQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCJqfDP1RG1UldfC9g1tOO48ejxRfEYdd3p5l9IVWBDK/PykMGInHLO 6BQCY7B4+aMHhZODrUrgRWHhpnX+BdUKS18twOuqt0/6ySZ5M2to8oHBM3637f7Y Qvc7zl004L6HFbV/K1981SugG8BGv5rjWeMkCzDHL3P9E5RwXh2htCzLlK823/bI tXlSZoWT92T24X6d6qta78/tqTdmYW5TxbyGw01Lh/LLVhBXetGmmLD9YU9MUiH4 ikp6Sgjwf1Y9O2G7MRI0EKS8/I2dboP35e0AI3yu7AVDZNFaB+FeLSQKNfQDApfw uyTJv3VptXcZ7SzX6eJX7lcJbNTelretAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAW gBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUK2048SABXiCO/JyjboZp Z9xQrcMwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0l BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBgGA1UdIAQRMA8wDQYLKwYBBAGyMQEC AjwwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VT RVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEB BGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJU cnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51 c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQADsdND8yK3sGG5DfpdeBDR 9NAo03bylItUruwVaDcAoOPv6oOH0c7dc/flB58IFzL/qFCOkaxw/1i3tB8+TgdA PG2qZb6RLHiytBuTgO6H37PcPh0ntg7oEejIMIR2TANTiZEhu4OQV2ay31K9+LkL EsWbnJa1yK0ut4l/sTT0WZk1wbfZvTzBpaQMHtxz/r7fK77CtOHL3zZm2lETpURT EVlR4FAKPXktYFz8oKY0F52SLfqqV1jIWD2RHSUwFp/8qnB5639YoXPCqtmJezC3 IarLPUgCuTR8pvurYG8Dj3dTmOxHJ6qX/IKsk14CE7UHJ529GoU1w8OpG9dX2+t3 vWmuux5WYwsysk7wDFxkz6vXOAmsQwl4mY/F6GQ+MD2t5k6kZdOUE5Qml758NtDl LqTCc8wprrYlpv6IM0ywxTjqJ7BprE9gDLui0AmlZLDYAO30OG1iPWQue7A1Z1RT UfIq/1CpJS48NrgQThfpQIvN4ruWdS+VXU3Bz1klTL12pCvM2IyGdGmzLYtWYCve PcanZm0YAxvq3hGjAfZKr2m1NgnnFM2w50qhSZTxoPHm0vUhaUSciStcqUcJPzLT 3flR5NwDZwlz71sRKCUR3hQxFq4C7f8XC+Y+GKFzZlIj+QrMW1uUoA/cJJAQNVVo JOK1P2l8uSVau6OPwUGqNQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDjCCA/agAwIBAgIRAIqhu/+4JDcehmfy1fL4MLYwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MDMxNjAwMDAwMFoXDTI4MDMxNTIzNTk1OVowgYIxCzAJBgNVBAYTAkpQMQ4wDAYD VQQIEwVUb2t5bzETMBEGA1UEBxMKQ2hpeW9kYS1rdTEUMBIGA1UEChMLR2VoaXJu IEluYy4xODA2BgNVBAMTL0dlaGlybiBNYW5hZ2VkIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gUlNBIE9WMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA g8JgAdvuvU6oyP1QTla7SgHIA7AB1oMxKtpMSwJxte8p0oHmET9MwguZ3LTB3fE9 Q23s4OIuLtCdR22IJyziDFJCV7arHZvKMuQzfcHyh/h9/u4uu/5LnO1uzTI/uDNN SAOD//ecQqCK0wR1ZpoSyTIHO1bW4Ptj+zz3Tc9ipyzbCkZW4vYh9IlJaqDLArgH dGIUt9OTLKw2Mxi/SAVhy1M+C6xPdtiwp+LJh7FTmAxFlCOmgRySg286l+pQJo0+ aqUviExBJMINmNN56yQ45rG6mij5gXEoM0R5doEYVwMRLoHYcTBMrZpajYvXd5nZ rKozYdLXGjzuBFbEJQp7hQIDAQABo4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/Wqor Ss9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFGvX7LQGKtw/seXgX+uhorCLZIimMA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgI8MAgGBmeB DAECAjBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20v VVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUH AQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3Nw LnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBACd4AZHxx4CFaviVeida HiA3fwMfTY3IKyrVWDB9BXMI1SCuVTtVe2QY+3QZgS/XRoKLANc6jc5RpxjFdMZi 7NSgUN5sr9e0TZ3CO+jqlQoWDYmbThdWxif6mBlfnNWQBvBv8J7acnf7H90MIFXp eu/0++awDI7YNQmK+1VYizR3jattvj5sspx8ae6IlgRHfpGs7yT5dDcjGfE8RQ2Z J5AP0Iffkkc8SnejunPPjpM7qgl+wRDK1Lfp8MthSEn21zBzGDLIIc6R+CRvBvBw cHTIUXKt8FRPE28z1vCueIlbtmT1S2ITax1kkdwe/gg76IUvkovixUe/YGzuUk8c 2O5KB3qlkfqZuj5kMS6IRQ56uG4BdWzG5PZdxnGu1fk63QjZU8qluyZoLhTT/OL3 CITS2STxWTg/zpifL/lnQ1MFoFoP6TzSQO/UwdGcnlyHSsChJ3TGvJY8jTC34HpI fS1WaOqb08qIDOExTQ1bVbVmXs2rswarBvFGoGtNDfKjMa7zSzuAYxg3P1qRTdks oEQ+jqOmUMPdT4tzHhIxSbb01W4VTuhHRaK1R2ChHN516DTMeJk5TsQy/vEwhur8 lmL1V1F8czhZnURtlce57ByDbnbVEVeTmlT6ka09Q0tJb/lwYZa24t5erJFgK26l 7PPMRjdIg7fCdU4y8Gd9bBIu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDojCCAyigAwIBAgIRAJLbl17KKwqyzn31vkoa2DgwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MDMx NjAwMDAwMFoXDTI4MDMxNTIzNTk1OVowgYIxCzAJBgNVBAYTAkpQMQ4wDAYDVQQI EwVUb2t5bzETMBEGA1UEBxMKQ2hpeW9kYS1rdTEUMBIGA1UEChMLR2VoaXJuIElu Yy4xODA2BgNVBAMTL0dlaGlybiBNYW5hZ2VkIENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRUNDIERWMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5le9RFTiN4Qu aUJa6g5FK0eJR9vWQniDm1VHA/KhzxSSnNkFGLR7nOyg2Gi+VbgBkJu7GwF9HkdC nLDMZkadKKOCAXUwggFxMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2Oa MB0GA1UdDgQWBBQgjEj5wT+vkFXrTlj3NzjMSCyYJjAOBgNVHQ8BAf8EBAMCAYYw EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICPDAIBgZngQwBAgEwUAYDVR0fBEkw RzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0Nl cnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEF BQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRy dXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29t MAoGCCqGSM49BAMDA2gAMGUCMGF8B1NMSVXoOqC6ap0vUfi0DRC9fxuaoDZsFdLz XIPJ1K4HZShRLAI2KWmoCDT8SAIxALdUxWo4S29b2fdqM1DSR9QoDRqHzCv+a9cu Ov6QUJpUqc6szZsd+2jbxP+2vmQ6WQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEijCCA3KgAwIBAgIJIrmxL00F+e0TMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTgwMzE2 MDU0OTEyWhcNMjgwMzE2MDU0OTEyWjBfMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEpMCcGA1UEAxMgU0VDT00gUGFz c3BvcnQgZm9yIFdlYiBTUiAzLjAgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQC/NKS4RcW1bUr4urkpXCbWvTCjbfonQSWl0osrF4KyQMPmhSwSIe5h VbkxjXJNIa+xyWT60rlU1w5rQWD2tTd9unXB1H3SgFwHqlgFLwkh28WSo8uKz/fr VP5sv3VCEkuJxUglSj8D11H3ZxImUYNyvL0FpxfBfqZLbZSg4/Lv0hytwoIwfR3V JyXbdi4dgCKuBar/ky8/JBPNVgsyxFLEVMD2o9rC0WhlHZZkDRlNtl0mJxoYKe3R ephuZmMbqS+eAMdNeKCBeOmJmoUe3qNPkY44+CdpxHLluwn3GP6lTyp7NhCJWK8q lRrvIR9i+TQ1envWX3t+fcgTUeLvHNg1AgMBAAGjggFJMIIBRTAdBgNVHQ4EFgQU y+8974N0oahC8DtANvptgpSpJzYwHwYDVR0jBBgwFoAUCoWpd2UFmHxAgfgPlyw4 8QrsPM8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwSQYDVR0f BEIwQDA+oDygOoY4aHR0cDovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0Mt Um9vdDIvU0NSb290MkNSTC5jcmwwUgYDVR0gBEswSTBHBgoqgwiMmxtkhwUEMDkw NwYIKwYBBQUHAgEWK2h0dHBzOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9T Qy1Sb290Mi8wQAYIKwYBBQUHAQEENDAyMDAGCCsGAQUFBzABhiRodHRwOi8vc2Ny b290Y2EyLm9jc3Auc2Vjb210cnVzdC5uZXQwDQYJKoZIhvcNAQELBQADggEBACxo n3N8Hb+9TV54ifrP7lf/O9OPvFwjECLgwSo+dQ5q43MT0sqDgHMhMZnxlqXdSyx9 jINinyLFDqS8DwpB/DxWVnNcpCKVDLyB8l0G5XICJys8qQv4D2wwcj9bDqchy+sJ gx3gigDgUQUCG0Jiw/42tbeNT0VrFbobujWosSYFvCeEdizS4IdbGf/gRBv21d4y s56hd9Sxw7DmU5cE8na6aNwWNgmyp2Wylbep+ZhCYVdRpSn8SzadqmNc2Yo6AkgT kLeeaUBYEjuZWa+tpvuQ4Zs/D4zXbaktVYjCIABvY/qVYMlXCsT8nl+mS8xwyt2s wf3q8ImxiBdrmEBYV6s= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEhjCCA26gAwIBAgIJIrmxMewN/wn+MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTgwMzIy MDYzMzI5WhcNMjgwMzIyMDYzMzI5WjBbMQswCQYDVQQGEwJKUDEqMCgGA1UEChMh TmF0aW9uYWwgSW5zdGl0dXRlIG9mIEluZm9ybWF0aWNzMSAwHgYDVQQDExdOSUkg T3BlbiBEb21haW4gQ0EgLSBHNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMvHidrFR7CRsutS5ioQCQBe5mtBfm1o7d5Hu111so+QrOMzZqtXMFTppYAG qTWst4HW6nNIKgoFcbngQ2motJ44P57oTXu4kUHJO9qti/l9VVU+IIwPgb/xJk6R jp5OcJfg5OPmDc6f3qmzl9803mKO1OO3ldDBGqq430cb1e6EfAD4xw+Rpr7fq5g3 PwW1v6cylM6ivOYxYwKhioPUFigzomVNSnCZMzZcsvIjsm+q0UkiCdJf9UcK8/uV tW/3RWLO4SmqAxe+IMnjMO54Bpx1vyLm3jzDC3s4ndtAadQ7+GIvan9RsalRIhjM e851BiXf1URA6BJAVW6bDVOS9ycCAwEAAaOCAUkwggFFMB0GA1UdDgQWBBRnOjrB a7ccpkFGOTCEyGkAWRFYwTAfBgNVHSMEGDAWgBQKhal3ZQWYfECB+A+XLDjxCuw8 zzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjBJBgNVHR8EQjBA MD6gPKA6hjhodHRwOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290 Mi9TQ1Jvb3QyQ1JMLmNybDBSBgNVHSAESzBJMEcGCiqDCIybG2SHBQQwOTA3Bggr BgEFBQcCARYraHR0cHM6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJv b3QyLzBABggrBgEFBQcBAQQ0MDIwMAYIKwYBBQUHMAGGJGh0dHA6Ly9zY3Jvb3Rj YTIub2NzcC5zZWNvbXRydXN0Lm5ldDANBgkqhkiG9w0BAQsFAAOCAQEAVRMs/1m4 BpEywQWRpNzsii76IdwI1b4h4a5Rb/n3UckdZYh+jWzADIGUWy0D4g2PY3Uz9SXR 4f+T31hlDEfWEd7QZGCRe39/RRyxeRaLtBpldWNIDDci39ykURNcOSRDqou8+TaO vFzqqhqR7SZ6M3E4KmkTSfNlLtx0agUXxQoryGh2TtLf3yDaQpHCHE3qLEhXQMVS ij+wmoaB10kaXIB/m1KHWvxYNbehww2c3QAVyF7XWvk6rm4w2WzC6TaGaID8Yiei Cw+lIAx2cA/Rb1AdlJGclb9NIwJ7XBq+XGiBrWi7iwAp0CoNqLQQWote6rLpy9Bm wy6x003kcI6jZw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtDCCA5ygAwIBAgIQBe2I2AiNEevd1iOWPLrtQjANBgkqhkiG9w0BAQsFADB+ MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B LjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIwIAYD VQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4XDTE4MDQxNzA4MTUwM1oX DTI3MDUxODA4MTUwM1owRDELMAkGA1UEBhMCQ04xGjAYBgNVBAoMEVdvVHJ1cyBD QSBMaW1pdGVkMRkwFwYDVQQDDBBXb1RydXMgT1YgU1NMIENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw3bDSXQGHkyoG7eDKKPzHRoQ/Gz4Xd3g+v0T hYSF0Xzk9aJtZ3eW08OoRO4DWYdPfMlxeinBtNFnvk4vXNg5ozkipW3+PNGnY9cG ApDCkCtXp/OWHzSUZ+t4M5b7qLLNX6P/F+PGAu2YofVJRUjeeZunjfxpCUBiOZbP f/oW89VYk0mPyXDth2LBu06OZKb5gxbLOXTQTrc4CMoco+cjd1biGX6pOx+Q2oW4 S0v1i8s01bKNdRzz8viCnSEQU4PumjmbRns3gp3a8sR0DSeQcNofXeQXG/6Ar+O6 igpxPLWffKScbXwOliMS7VJlndGog/l006YZq2PntBjKPeNTzQIDAQABo4IBZjCC AWIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUasBJGVKf6gFeRQyx8A9+ oF9tj+UwHwYDVR0jBBgwFoAUCHbNywf/JPbFze27kLzihDdGdfcwDgYDVR0PAQH/ BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA1BgNVHR8ELjAs MCqgKKAmhiRodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9jdG5jYS5jcmwwawYI KwYBBQUHAQEEXzBdMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0 dW0uY29tMDEGCCsGAQUFBzAChiVodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwv Y3RuY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAA+GSfjo/dLY crpFOsGSFIp72D+pXBL4RHmPY19Aq5YTckBb8aGinUS0cUDduZRWALlzAM6JT2YB NWNngIDW+bXpVgl+9EU35OdsRQ1sTUQEVJz4IIllcguNVkURrGZ1g07crqm24Nlg Hz+O76TNGQCyl5iE0tm/6W8yIHYs0H7FYPfSsN6QQoCsfqKilM146Kg8IDVdw1hp 8qc3gnyrxSf5/2HHrThm6jnZbvqVf7oe5COCFZOkbQvfUz1z/oCwIJcFqtZD66Ba 09UpHIb+0bJ7dH/z6RXEtXLouOI2rwuMcIoPmt8sPm2EVlCi1DV9dFUe35AKz7f7 N4mHRMuw44g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtDCCA5ygAwIBAgIQB93tZ04qLAjJ3mZmyXFUHzANBgkqhkiG9w0BAQsFADB+ MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B LjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIwIAYD VQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4XDTE4MDQxNzA4MTc0OFoX DTI3MDUxODA4MTc0OFowRDELMAkGA1UEBhMCQ04xGjAYBgNVBAoMEVdvVHJ1cyBD QSBMaW1pdGVkMRkwFwYDVQQDDBBXb1RydXMgRVYgU1NMIENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA53L1DVH9SsTSZGmdR4B3J8Dd6Z68JGyPnoGm BWsgeYw5IhVeRxYjZ2TP9kUB5H/Iz2sqKzcX6pIb7eHuQeMmojas6gmmqm+ZZmR5 LixWfK/JYdJHHAIglZWG4HfQfQnfl6QK3efRL39VFzwV/AyUKQhD9lT13nMSrj/t E7CiMxMY5ndxp5G0vS3T3R38KMCRSmuvvMm5yeYWEyNeRi3wVASlcF7/xIoPxDSC mOJKHXTth6oz7EJ+hEUG9rpXV+Hsuojyn44d82IK2qP6Fy0vLxPT1ncTvKC5bm9Y 5GULoG8j+y5M510yXygmiWHjeVjozLXaOoLDT+eG0GMpEeXWRQIDAQABo4IBZjCC AWIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUN+0f31saT4cl4EnGbXMC OBJIFGMwHwYDVR0jBBgwFoAUCHbNywf/JPbFze27kLzihDdGdfcwDgYDVR0PAQH/ BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA1BgNVHR8ELjAs MCqgKKAmhiRodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9jdG5jYS5jcmwwawYI KwYBBQUHAQEEXzBdMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0 dW0uY29tMDEGCCsGAQUFBzAChiVodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwv Y3RuY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAOHwsrFlEhMq bFyZ+lRLOBYwPOdZn9hin3ZC0qw4Qsllz1vUbf2N+v8xSSyw3NyzvpsXNbfld4PL u75Gj5WrVJ167usGhadnEa4fQKTkCIhCYff+y5NbYxq1QykPZtBSyXzK1vJ5LkRM BMeENIVt92xmY1G88gBHOpwMMMdBVAk60wNTC5lZ9Ltj95vwDI36PX2RNbVLUTIq 5cWIrDbEMMmSb2s4ZZFBeFZnkNWJzYY++MYW/jlnFxK4Rib+e9cldnyXekQcETXh PJElZFjoVh+MJYKLzJS+aBPKrwNsYiXBR+UZeZZV48KiFeJr7CsiE3SoVH9543do AlzeB17MwSQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtDCCA5ygAwIBAgIQNJuxRK5WEemb9DRcf8mu/DANBgkqhkiG9w0BAQsFADB+ MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B LjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIwIAYD VQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4XDTE4MDQxNzA4MTg1NloX DTI3MDUxODA4MTg1NlowRDELMAkGA1UEBhMCQ04xGjAYBgNVBAoMEVdvVHJ1cyBD QSBMaW1pdGVkMRkwFwYDVQQDDBBXb1RydXMgRFYgU1NMIENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw67Kp7Ex6gJWNZ/TlTw0+LYZmXEkXsZCzUI4 B8hvMvA1w1aomgWDJmKCAhbi7NXAgJNfNov3xBz8IcK5uR94m6D1RfdR+kWPMTxu 2s4uOJ3ZnFrl+20UIOE5b+tfDssJXexBJI0VFY20TKi9Uu1UNHSPN52zJUm7dbai Hm31Jhhmepbua3PHH0juJBxuusxxH294pKc1R/Xfj8LyaHOwDTZs8LdF9qGPZMsb IhbxBC+y2bnOlWQqBsTNSSaJ8dcdBf1XnGMrrocxuKGOt/DMMuO1T+G0XSKbOTVn Tz8oXNZTKkaoDdk1OMPWWxFPp/8v0R0mbgNgqXNGda9Jy48R6QIDAQABo4IBZjCC AWIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUc6j4jqRUTYECchxOybKo xTSTE24wHwYDVR0jBBgwFoAUCHbNywf/JPbFze27kLzihDdGdfcwDgYDVR0PAQH/ BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA1BgNVHR8ELjAs MCqgKKAmhiRodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9jdG5jYS5jcmwwawYI KwYBBQUHAQEEXzBdMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0 dW0uY29tMDEGCCsGAQUFBzAChiVodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwv Y3RuY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBACEJ41laE9F4 /w1eq0jyW88LZT4e3pWrUVSvlsfxqE6vfs3uR5Jgq50j2tnl61KQySo9djPU3+QP aFI3c8ktRJH2zZvfaBS+6osCUpU4nK9yeQTcylATzdufHu/vhTjmgr1JJhqm0Ckn 77zctm1qjt6YIqZs6yyGKXoMJgGmL8b4lZvnTN0gqQMRahKinH+aB8647td3ufdt FLRYOF2HCdjmzVH6YIeFIS/o+JfQXO3FRQtUDWaMkbNUj6yY8/PtQYKsedm8bshx KKB9kTp5pMI9EsZ1awBbRdthH0LvZW88fBdTm2YyPyFvd1GlqSc1S8R4w4qqU85X lKP8UgR+amU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFqTCCA5GgAwIBAgINAenYpMwYI2wqWMGvjDANBgkqhkiG9w0BAQwFADBXMQsw CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEtMCsGA1UEAxMk R2xvYmFsU2lnbiBDQSBmb3IgQUFUTCAtIFNIQTM4NCAtIEc0MB4XDTE4MDQxODAw MDAwMFoXDTI5MDUxODAwMDAwMFowTTELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEds b2JhbFNpZ24gbnYtc2ExIzAhBgNVBAMTGkdsb2JhbFNpZ24gVFNBIENBIGZvciBB QVRMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm47K/WPMAJCbDPsC KjXoongnobvDIM5MZtWqqge2lJo6JGddSyoRv10p2ptJTP1x2bQkVTuLUS4Wt2ky 0mRTic16jixUYJODUS3sidE4CswZspPsWGQ6qYfFKiUSwo9cDICTvj2Erua1iw/u aCVx9s4KEUgHOt6Z49IOJQWRhCtCqO5yp4Vd/qgRZ+cZ6iAjN0nWtphcOtrfX1oJ R5yIVH3NkT8vDyWizGeXC/iC4cCWTQyljzi1Y7m+1DE/LKCm4wmnULYXcqnBoEJC ocJvNoCIYtTdsAFUNXXKeIgKxDPFkozh6U4P7DBfscVZ6bpjiza4fBpelMUzgTL8 vtb/iQIDAQABo4IBfDCCAXgwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFD6z7Q4zTgYe4JWyfRKfuApHgKenMB8GA1UdIwQYMBaA FInvdXF6X0cblyPckErL/8AmNgjVMIGIBggrBgEFBQcBAQR8MHowNgYIKwYBBQUH MAGGKmh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29tL2NhL2dzYWF0bHNoYTJnNDBA BggrBgEFBQcwAoY0aHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQv Z3NhYXRsc2hhMmc0LmNydDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLmds b2JhbHNpZ24uY29tL2NhL2dzYWF0bHNoYTJnNC5jcmwwRwYDVR0gBEAwPjA8BgRV HSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3Jl cG9zaXRvcnkvMA0GCSqGSIb3DQEBDAUAA4ICAQB4ODWDOTBktFTpBK0tttngAi9i qUto8Yet77L1lNmJtq7cywDPd1FAT1R3PDYryz3P/y46l2UMTBbq8NssO4Cyq6CK Bcfl4APHuiMSTGmo6LFa6vQTCsSBzJ4+ZuYonQh3mrjmgN7B01z7gb90uerbOTE5 YyodkDseAiLAR3rBJIxY+0Es7Md5eTQUuSV/Ncd77fwVafg2WbMssBIiuU7ERpo8 DSG37qLswNwSkYQ8KN0whjGo1EdFoEhRqSVLaJIeNqJnufIQFBUjzJ+O17yk484h lbMuJfrXKC5hB6oi9xn6R6JWMMeAoKEbYy5pNc0LH3rqRfm64ue8WvWcTdzVsmzY rMDJr/S07XDLEHcqsCbPiww4ObT7fPUD5lT83Z7ld2+URdFbYckO3HVSYEUz5Vte K7WPbflGgW7kwm4a+UtHZimscI61HO7gRNpVIBrIXyls1TZ66DoExI4siPx3hqt1 eJo0l0S04IxHRdamWmAGZxAD+5SMcV39KJlo9V7b59ofrjOoqPxl8vIHDG94/Gk3 P0B+v6h+5tq8mx4IO3daubAibLcih9PDqREE/t+sjnSxLk7Vb4TLSMRn0NwWzZKc /MZ5+hU9Tfb5uie411V/TW8qSrhA8Dz/6nAtGZUZwo4wNoCXlVuHOVJm+4nYpRL5 /VZLVJQF/CqJcXodYA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGUjCCBDqgAwIBAgINAenYpKYtKygROYKpTTANBgkqhkiG9w0BAQwFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFs U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODA0MTgwMDAwMDBaFw0zNDEy MTAwMDAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52 LXNhMS0wKwYDVQQDEyRHbG9iYWxTaWduIENBIGZvciBBQVRMIC0gU0hBMzg0IC0g RzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvcD3GkMoJwy76jKZW uyMoHz9kjGDbV5td/aJzH6qHqGwOTlD+cfYpd0HYP021757wOkwueD1yniqcsDY0 8CqVDuUPOB9H5R5TLWQ0VKYLqjphqap+mKTRGmQyl50OKk46S+Y+76/cZGVnImX7 zTmzODpJBC4xhjodNO01HboRS2M+cuLWnZTWmF0iGxp3Gj1AfkTUA4TV/vaBCuTO +LrM6MjXy3D7/x+MQtnpniplgDWJvEX503rUIfqfXRxwe2dLHASiHOZI63INsxUN oa3dMHfmEmYXNIn2wxRJru6/ZHhS8aT9+4xJS7eukjz7PkcAgYT9TL104vDVOi3A 1VeGkiZN5J1AG8F/zIHX4H6JAQUZG1sNCNXMC70Xg8CCoShWzLeojG/wkEEFLgbR aqpN0fs76HO6V7OUyPdCZw9/LRRy011w+GmkGdoe6F389oPtw+jDeOjJcCkJflhg QtgY+CjCD9uMDDzA7J1WM5kgZyxAcqB6DJ6NrSgaaMnLeGijZeOXUpw1SSXT17G4 dUjQA1iYbHPEHv1LUz1ah6WwCBi8aE74zqE3gRKYV8ygPhFIpr/vJz4ZSUKcaHEx OukkfsDSKwySOyiGk+x3YFvMOrcV3AVf7+uSN5N6Zws4e6zX1anmx8XRin2KwvTE DD0oxZQYQPMbQKrlpu71PcNFKwIDAQABo4IBJjCCASIwDgYDVR0PAQH/BAQDAgGG MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFInvdXF6X0cblyPckErL/8AmNgjV MB8GA1UdIwQYMBaAFK5sBaOTE+Ki5+LXHNbH8H/IZ1OgMD4GCCsGAQUFBwEBBDIw MDAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3Jvb3Ry NjA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jv b3QtcjYuY3JsMEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIBFiZodHRw czovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQwF AAOCAgEAPNOVRXNenNevDd11a4NdldtLhsOxP9Xn4GY8RuYhZw4Iae7l4C7hTjZS i8R3Cbci2DSFtKOjPUw9TJHH4WBIqJxnOXNDIqyEVK7ciLiMnKOGbZsVt9v/zAHB CFcOHyOTXebOdthV3iIi6twleNSlwh66izJ7CgKCk1YZRQx/TdHELW6a3rnYvLcj ggSxkoLzUYqYcKLj+cbByLDrIJDKrFjEYLSI44iy6UFLRuPuyH69GjS2ewtAKDHA 0zKCUaOOmRHLqw9g9TZEYxyUdFUlVmWazqQQryQjyc7QDjNOMsDVn8k3tqhqJyLY QabNmD1QNyGXG5thHf3O/CPvzrEQstA+eL/2zxupiONvyw2uqBEMfcHAMqWgUbmY 6xFTbH3x1NDeZ+/IyeLg7qxltC7iOZM7RimTRkeUiuAeNF5n2t9JSoPCLjGHgUOK leK6Loug6pFAgVlFyaWcmT0ur56CAoi0ia98OjeoRPS7bk8cwYTHyuV+54yJjC0o l4vmPGZvrShC55oABswRll3XOQU6wjzqZvdBAyP7XcURrm6plC5WDTfw2FuK11MF KyYzCbRFyWVt6ubvaaRvKhDBQUkJwasEHQQpYBYFjD1gpDqAEZq04FFK1fRATwjD RlgutBJ0TicBTMXBJXFLQxOZxh2ikhUkdAobtCtMAq9wy2GXcUE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEoTCCA4mgAwIBAgIQAW6T0Y/Xc0xSPNwz7ToIWTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xODA0MjcxMjQyNTFaFw0yODA0MjcxMjQyNTFaMFYxCzAJBgNVBAYTAkNO MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSAwHgYDVQQD ExdUcnVzdEFzaWEgT1YgVExTIFBybyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBANi3V94eezo83efo/Dt5k4znCiM/hKssy0J3Ws4d3F8hM4z5OhtI Y8YBlKfl1gqmBmqOgd3HwyCmXbx2Reud3nT++GVp9T5diT6AKSnKTwpTBjipcJ6G RsCy4dqs2DOx6zBI4Dj2LlYhShW1pH8VzDmmtSfUEF5lOTV7iJ8PPiBws37TlPw7 Bb36llnwtXGlYr5zVxrYI3WatYLJHXywPtixs4EgtG7a/OpsDWtGqmkDf3use13B twoBorvFtUdCPaPHGgiRX3seDm2KauZcH/ejITrl+8jEEghd01o3kPgiMud/wpGS qb+dGsRyX20h0+/jgFNPSCv/eqW3V1Nqo5UCAwEAAaOCAV4wggFaMB0GA1UdDgQW BBRPhfybWdPGU5ePvB6D8x6CJRS8eTAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+Ib G8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNwYIKwYBBQUHAQEEKzApMCcGCCsG AQUFBzABhhtodHRwOi8vb2NzcC5kaWdpY2VydC1jbi5jb20wRAYDVR0fBD0wOzA5 oDegNYYzaHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vRGlnaUNlcnRHbG9iYWxS b290Q0EuY3JsMFYGA1UdIARPME0wNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEW HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMAgGBmeBDAEC AzANBgkqhkiG9w0BAQsFAAOCAQEAaqLjCAyDjq4ZURIxxWXCP/TFtruMFbqJL8ol eQjhgjWNH4G/dFcNPwhGZUTf1qDEHMBJ9B8BhBzbXaEZ3YwP4MIFokWd8jcMvkTM 4J9Twaz1SoWsjG8KaC3dqAaiEXXliNlOwmmO68Or2UqPVjLVlypLMZaIEP/KHORG qaMWX3JHIPVgsM7tOH9Wh38+9PLipj5uZbzQSTHUQePhFZX/pH3PtVogTHKhYqa0 k8eDmEawtwiy4QiUMGadcS8aqwjeiACY03MkpZS4kinRdzry7MI2bCx5UDEGTloN z5boCQoCM0yhBl+ITHn6esJDDHrX0VTgI8rST8eyQCmSrfan7w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgIQC965p4OR4AKrGlsyW0XrDzANBgkqhkiG9w0BAQwFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xODA0MjcxMjQyNTlaFw0yODA0MjcxMjQyNTlaMFoxCzAJBgNVBAYTAkNO MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQD ExtUcnVzdEFzaWEgRUNDIE9WIFRMUyBQcm8gQ0EwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAAQPIUn75M5BCQLKoPsSU2KTr3mDMh13usnAQ38XfKOzjXiyQ+W0inA7meYR xS+XMQgvnbCigEsKj3ErPIzO68uC9V/KdqMaXWBJp85Ws9A4KL92NB4Okbn5dp6v Qzy08PajggFeMIIBWjAdBgNVHQ4EFgQULdRyBx6HyIH/+LOvuexyH5p/3PwwHwYD VR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0G A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuZGlnaWNl cnQtY24uY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZGlnaWNlcnQt Y24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBWBgNVHSAETzBNMDcGCWCG SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v Q1BTMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQEMBQADggEBACVRufYd j81xUqngFCO+Pk8EYXie0pxHKsBZnOPygAyXKx+awUasKBAnHjmhoFPXaDGAP2oV OeZTWgwnURVr6wUCuTkz2/8Tgl1egC7OrVcHSa0fIIhaVo9/zRA/hr31xMG7LFBk GNd7jd06Up4f/UOGbcJsqJexc5QRcUeSwe1MiUDcTNiyCjZk74QCPdcfdFYM4xsa SlUpboB5vyT7jFePZ2v95CKjcr0EhiQ0gwxpdgoipZdfYTiMFGxCLsk6v8pUv7Tq PT/qadOGyC+PfLuZh1PtLp20mF06K+MzheCiv+w1NT5ofhmcObvukc68wvbvRFL6 rRzZxAYN36q1SX8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID8jCCAtqgAwIBAgIQAg5+swR+u9EqPlzmK+DZjTANBgkqhkiG9w0BAQwFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE4MDQyNzEyNDMxMloXDTI4MDQyNzEyNDMxMlowWjEL MAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIElu Yy4xJDAiBgNVBAMTG1RydXN0QXNpYSBFQ0MgRVYgVExTIFBybyBDQTB2MBAGByqG SM49AgEGBSuBBAAiA2IABDBUoetY1B0PqJGvAm4ABeWV7gkgmZmIZ7+X1e5z+/wP mfhuPhZYCyDuc531VEvjgx6OwE5RLW5zX/0Cij/TnrD+4tBZfkggdhkGGj30K/OT dGQCvu5YNBALcgF0Or9Eb6OCAU4wggFKMB0GA1UdDgQWBBT/FwTzA6I+lkDktTYm 5wfrqfGZFzAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAOBgNVHQ8B Af8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB /wQIMAYBAf8CAQAwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8v b2NzcC5kaWdpY2VydC1jbi5jb20wTQYDVR0fBEYwRDBCoECgPoY8aHR0cDovL2Ny bC5kaWdpY2VydC1jbi5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0Eu Y3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3 dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBDAUAA4IBAQAlr3UbqMBq37fo UQFTYLLWbFcLDBv/QTe/WJRRgF44vTY8iGFSn0Z5WQSDKONa8E7MAxkDXIBgt3OE osTUSnnvIs3sfm8m2E4hc7azJclZT5oa5GU/Jw7m5dZ9kBJrozZNfOZ5uAE68RgA 3NhYN+cuC8SpchaLXiXW9/cc/4urIrSSrYAX4UIM+I+4Bwc2bJ6h1Cfbur+8TodG PcMMdT4RB3Hy4DPo6UX5h7GxwltrDOLA3e+oMQgHj9P6HWPucwf7O3u8RZGuzMVX VGg55EUmYkg2JF5S0Asa9pRw4cqOouHYT/R26UEMbTgSoDsMTPqcdgRPSrzP1EQU k1qXXwno -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQBbY2B01sW7EoRlgIyCy6mjANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTgwNDI3MTI0MzI4WhcNMjgwNDI3MTI0MzI4WjB0MQswCQYDVQQG EwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEaMBgG A1UECxMRd3d3LnRydXN0YXNpYS5jb20xIjAgBgNVBAMTGVRydXN0QXNpYSBTZWN1 cmUgRW1haWwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzpLTL wSAp4YH+3rRD22/DUfSsAqFuOGQUa/SQXdeVKe1Bu1apdZAAUpJek73o7gPY4yvp +J2w8P5AVoLAuBMxdKvk4rT97kqezfmA+o2Tjoa8WNX/cjWI2S5VmaofBW0zg+L2 GJFZelDezWmm9hX3e205+cepkAzU7YYZp/VyFf4mj4jsWdoFFpJfDWPEGTPUpbF/ Vo38p6NM2SzupO1079L5CsPvDL7Lm2Q7wslLYWlUP8FQlHaBPsJIOrBwajRUodoT PLZTWrbb8GH7GUH7UK56/cnRalfmLm7DXuw+5IOMkIkD/mL67jYWesQBwvgAE6YO 2Q9We/bJgEASNC5HAgMBAAGjggFUMIIBUDAdBgNVHQ4EFgQUtEr1/aqLeyHCJIIv tmgIZh8S9c8wHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0P AQH/BAQDAgGGMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGC NwoDDDASBgNVHRMBAf8ECDAGAQH/AgEAMDcGCCsGAQUFBwEBBCswKTAnBggrBgEF BQcwAYYbaHR0cDovL29jc3AuZGlnaWNlcnQtY24uY29tMEcGA1UdHwRAMD4wPKA6 oDiGNmh0dHA6Ly9jcmwuZGlnaWNlcnQtY24uY29tL0RpZ2lDZXJ0QXNzdXJlZElE Um9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0 cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAQG8d 1Fntcg1TxRgpyW92I8j7v3mKJwnnkwUEnWoiYISHjy+OntmahIz5uz4YWdzJN1XT Wc5kS/8nf06UkQYjRimYp0i2tKCuKZTyLrM1JjWbHkAJug1REHIxiwoNC21YyT3C nqt63fPAlVDZk7hU/nbtTKjHU32L8gJz979fg1pK3vEl6ZTmb1g5klK5hEpHYYoc BRTYFTlBz+QASAyyIHzr/0eivGx4ioYbEkSuXtw24ysJfT0pnO1KpxredRy9rNSu BjC/iDXZac5xh9Ta25pJXOpPtNHV+BnhaAExl9rasKOG4GPvNdrOhdNb8VQ1KkzR wy/8e9o9AkLqde+A2A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExDCCA6ygAwIBAgIQBgiAIQOaACR6WFGIcDvS+jANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTgwNDI3MTI0MzMzWhcNMjgwNDI3MTI0MzMzWjB/MQswCQYDVQQG EwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEaMBgG A1UECxMRd3d3LnRydXN0YXNpYS5jb20xLTArBgNVBAMTJFRydXN0QXNpYSBTZWN1 cmUgRW50ZXJwcmlzZSBFbWFpbCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALdl7ckzzOBg4W/cdzAO7iOauzDGvo19uBN2wFbOOlyuWlrkBxaAt5iM 5aWXMwXuO0Nu+k3TTFZ3zfxZ0eM7ujXnhKkH2rjOYv//d/AH0Isx15oenlWNPGS+ WJqmzSCXuprKFogO0pC4KGuAK0V7GCXDpIw+a7Gw5PnXL7eqF/uG80okZcr3Ve9k ptlLOyFYBoXhIWVh6ADBhuNpfIPl5U/tlBv9dPGGZ5sQQRV3CDOHmkWxGLVMEgt8 VdhEecx2EHC42vGSYkjih+WovYusx0SCtqf1C5gFgS1RNvy2lsC02/yheWLUGas9 6zalrCce3kQhFQJoEIMntSaqvKvQRMUCAwEAAaOCAVQwggFQMB0GA1UdDgQWBBTj 6WlG7Ng1+zOof2nqEYPYhDF3hzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd 823IDzAOBgNVHQ8BAf8EBAMCAYYwKQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUF BwMEBgorBgEEAYI3CgMMMBIGA1UdEwEB/wQIMAYBAf8CAQAwNwYIKwYBBQUHAQEE KzApMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5kaWdpY2VydC1jbi5jb20wRwYD VR0fBEAwPjA8oDqgOIY2aHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vRGlnaUNl cnRBc3N1cmVkSURSb290Q0EuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsG AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEB CwUAA4IBAQBdfIiI9V+FON4X2xAZvuolXaJa2moeFNBCeY7tp1zrOjdR8chYX2R9 LCEjnqvWjZQx76Bekpny6ikP0xuoOnKqt2neeSEUykhaJDzC0MszO+8ruN9emBH7 58AY4ZJl1TzB+Yii7cdHT/0DTlsV5G9beMqCsbUOv9wEfpeNaZ5zMPKxxu8kwEps qfYbcvjHJ3UOZyXQR4RInM5fIGVsDFwvIlg6bg+ZU/1gvp9SJTIzb7OnI25KIwut SSKmEP8UmefwTpuUeZxfOXWPwn3D8Vyj+iLgIlYErSOLs6D4RV1R0B56/zrVyYnN sUf7hQSTkAyvundemyaPELC5mx035fLe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpzCCA4+gAwIBAgIQCPQ5QYSAOE3LQgnl4IornTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xODA0MjcxMjQzNDZaFw0yODA0MjcxMjQzNDZaMFwxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xGzAZBgNVBAMTElNlY3VyZSBTaXRlIFBybyBDQTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAJ/5VnZVJh4MqHMX9J60c7O4Gm16uxwK8OKj+o0phxSI gI++7rY1y6DOs3TCS7ZQMtsNHaHFcwywzhj/2ElWkW7rS9DTmI7TiyFdhejTWF8V IihNem1sv3faxeRbGpV7KDU+yjJ8FmYSD/6nPF5Juq0ei25yhzxNEsNS0/h5BqwZ GskmMSTworFkr6k8eSNvKXUw1mdpxcUAfIMn4YgyG+HKmgGJPWk4Y0Vchjv3RFvz sdktrNJOl2l86LQC/bhmL0petbpnDtSJADfb8xp0UThqMC1UhyJn7seERANw2Ss5 c/wYrsr/xllMLnJLFQnQaz50r+Vie6S8gduxI4KusbsCAwEAAaOCAV4wggFaMB0G A1UdDgQWBBRFQeOTVHC46aW3lrwmsVh1Qpc+8zAfBgNVHSMEGDAWgBQD3lA1VtFM u2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNwYIKwYBBQUHAQEEKzAp MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5kaWdpY2VydC1jbi5jb20wRAYDVR0f BD0wOzA5oDegNYYzaHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vRGlnaUNlcnRH bG9iYWxSb290Q0EuY3JsMFYGA1UdIARPME0wNwYJYIZIAYb9bAEBMCowKAYIKwYB BQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMAgG BmeBDAECAzANBgkqhkiG9w0BAQsFAAOCAQEAI4JOgmYUHk+M75FR6Q1W+rc3c/YM p245VPwdzcPUcGbocwo8gfyGnuuw3o+HUetQDymSb+S6uFa3+mq02jj6Bi6FKFzA 9LNJTFfbJlDCjcBARzHpsou3vIA0Aa0UBAh0jXe72mDCu+l0Om8YOaEeBJg5xVrL iKo4SQojUvgCwUQneuivJ0syEyWMe6mkp9TpaZhae5PkoO3g/RUdJ6sS1YF2koyn fILNBPvcTCt8zeRyy7yX9PX3HZUpSGvAIv/DXVDoA7VF4em3/alkctp/yOZs6O9q Q46+WiJO7T384bZZdq64WEp+hIE5aJtwD+pFCKzXRb//UX7i9+cfQk5GHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID/TCCAuWgAwIBAgIQDiwRY99LBgGnLoRshQdnBjANBgkqhkiG9w0BAQwFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xODA0MjcxMjQzNTFaFw0yODA0MjcxMjQzNTFaMGAxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xHzAdBgNVBAMTFlNlY3VyZSBTaXRlIFBybyBFQ0MgQ0EwdjAQBgcqhkjOPQIB BgUrgQQAIgNiAATjgVwG2r/E7XruDPJZr65IdJwZX7zkNHGOx6esC+QC3iXHGOd2 QPa9p/uGlEUcQWHdhuHwRfQk2cWxsk3Do/Tn/20UnksyX9VRGl9b6mpmvCIncd/L 3R5GPIyJYfOsCt6jggFeMIIBWjAdBgNVHQ4EFgQUrIShsZvxSiwHrvhswdFxcNi2 XrwwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG AQH/AgEAMDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3Au ZGlnaWNlcnQtY24uY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZGln aWNlcnQtY24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBWBgNVHSAETzBN MDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy dC5jb20vQ1BTMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQEMBQADggEB AEer9dy35qp1bfN9ZdiWIb+d5/I29NfVJR0tj3+tdiwpdhLc6jjFJ6E+YL6EDY7A Vaec6zGghhgCIi5PPCjNhBoVJnn/6n1sewfHNX3h240cQgWxNKV0mYRJBeuF6hYH jK4yeq4Z5ofH8v5Y+jqte9yFzvST0O4blT+GdbZz6q2sWm9Y7MwGQ5xpBm78HjYv iGUZkV1FC4JF+A1VWp+EX1RnsxXeh7Chp08uBgL2YXG/X8a/xKSrktYj8f18DKFl oHPcHgS4Cn4BhhrD1ABqjYIjYANHkjrgf5POVZavmw8KlKoCdhByjIACD8EHqBuL sfk1cW3AuMNayRQQv1P2bYQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFnzCCA4egAwIBAgIQRbw6WjuXYmYHkr+VBZ3r0TANBgkqhkiG9w0BAQsFADA9 MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH bG9iYWwgRzIgUm9vdDAeFw0xODA0MjcxNjAwMDBaFw0zMzA0MjcxNTU5NTlaMFMx CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDExMC8GA1UEAwwoU0hFQ0Eg UlNBIERvbWFpbiBWYWxpZGF0aW9uIFNlcnZlciBDQSBHMzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAL3v2Jgp69IP3ZVPObX0lPeQrzYV+CotQALoC1gr Qb9xobQdXKpjm+bhOFd7hanKJ5OGk0kniV+jLu02FmFmZjVoQNUW2n2GvbnYhXI8 +WR/5GwbwIUVZl66sxbEmfFlhMv786NUrDZvHgCiNmG8aIv+Y6RbkKnfinYWvw37 /EKULxFFijACtHpej0Rb/Z4HN/iFcsk/pNmYPpvnuJWgECL2xUi6DMDkkabDfb8h iKPph8cQqErbpE7Nl3P6JSmzfrfE3Ej0RKEsXDHKie/g+yEFql/5h3DmTrQZglvK AUW6loQ38T+R6MOk/DmSCd6DMJdiPFKb4gFiCkakrzEwigUCAwEAAaOCAYMwggF/ MA4GA1UdDwEB/wQEAwIBBjBBBgNVHSAEOjA4MDYGBFUdIAAwLjAsBggrBgEFBQcC ARYgaHR0cHM6Ly93d3cuc2hlY2EuY29tL3JlcG9zaXRvcnkwEgYDVR0TAQH/BAgw BgEB/wIBADB5BggrBgEFBQcBAQRtMGswNgYIKwYBBQUHMAGGKmh0dHA6Ly9vY3Nw My5zaGVjYS5jb20vb2NzcC9yb290L3Jvb3Qub2NzcDAxBggrBgEFBQcwAoYlaHR0 cDovL2NlcnRzLnNoZWNhLmNvbS9yL2dsb2JhbGcyLmNlcjAdBgNVHQ4EFgQUBXpN dW/9CoOxZxZ1dz4UxfU8VI4wHwYDVR0jBBgwFoAUgcSMzPXkMP+lDAhfjBVnIXQB 398wIAYDVR0lAQEABBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDkGA1UdHwQyMDAw LqAsoCqGKGh0dHA6Ly9sZGFwMi5zaGVjYS5jb20vcm9vdC9nbG9iYWxnMi5jcmww DQYJKoZIhvcNAQELBQADggIBAKxEvE1IdNUzIYgIydX4B383TkQLNjiqVqOWlbSe VTVUfCAf27IuSlJpO+/hlVXTEpzswkH0xZ7hoO9ZcWJNOl3Jj9hfe/KjqtVvv81g Bf77KrV3dIlOTxArhHR6f8rjmrZphPSorUVSIxwnyibgd4iLisI6I85aOX+V6ntQ 4U38OZNLADZU9SPLqyU/nEzU6WlLEwyru/4X2gLKnW2PPUkAH8kF0mv0dvpJJe7N WUT1tC3Rabbt0qyd+1vi7zzrYNcZDRLXvNS9i90B5fqdD5qFAGut6NarbzMCzrTa tVCepnkDqKCPhfGcZDd8afj8wBuH0cltdnZWlBAceeVDZ+xWxMbTW5t2wtunZrul hiLD6G5ZkGT+NatLHrTKEqvGWXOUz6vh7lfXAZ+/uEFOJ6G5cUcg48PBtUu+xTqF DSBzH8Uj7H22I7oSYo0/pRNBgvx5dx6Dd9DfJeczRMGBEK+C5wDUVEnLU9twMtK3 oNVk8PlOcqsgU5FT+FBwxhaO3Z9U5k6j+pzwq3Efxv4y22YTp4MCWnnbrfLPmI87 MyEkLUZOVde0saz9n7FXN0ZXbxMUjPMc6yyvnVzdhPbwUDjGyT1wKSi9R/Jt8IXR GmIMyw1Gj4dUVplhrG0JDrcVXSyTnCwnDn996HkDVDuu3DU36ULQViE+cd68OK6X Nw4k -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFpTCCA42gAwIBAgIQdGUXetoc8PMhu+yUKqxr+zANBgkqhkiG9w0BAQsFADA9 MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH bG9iYWwgRzIgUm9vdDAeFw0xODA0MjcxNjAwMDBaFw0zMzA0MjcxNTU5NTlaMFkx CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDE3MDUGA1UEAwwuU0hFQ0Eg UlNBIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIFNlcnZlciBDQSBHMzCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAOSZCorBHU6Ff3LCRP6tpWb2z2UXU69P eQrks3FSD6aGk9dgO2UxxGgxG1TjLUzuyc3CKMk1//9zZagi2o+TNUNJbZPdu3mz lpfD4cjFupPq0B60iHkptaU565Oo8E2aX+Is/5i4T4u8QEFX0YhinLHAOhG/6OAZ 4rR7AK0CYCgB8sJZFHRgsi/lj1sSQRU8nOgtZLzQ89RZ9cXcpWk43XPGbMLrB7XD kVfdpamnOPJocl7urJTyHrsG3GMKVzVgpA0R1rE75txhV4vXe/nwv+MlC+hIzSsm HCIRy2ff2NkQXgV1cqWX32kQ1zfsBkGjNon3tyV47xEL/+LmjeQlKTkCAwEAAaOC AYMwggF/MA4GA1UdDwEB/wQEAwIBBjBBBgNVHSAEOjA4MDYGBFUdIAAwLjAsBggr BgEFBQcCARYgaHR0cHM6Ly93d3cuc2hlY2EuY29tL3JlcG9zaXRvcnkwEgYDVR0T AQH/BAgwBgEB/wIBADB5BggrBgEFBQcBAQRtMGswNgYIKwYBBQUHMAGGKmh0dHA6 Ly9vY3NwMy5zaGVjYS5jb20vb2NzcC9yb290L3Jvb3Qub2NzcDAxBggrBgEFBQcw AoYlaHR0cDovL2NlcnRzLnNoZWNhLmNvbS9yL2dsb2JhbGcyLmNlcjAdBgNVHQ4E FgQUMWBoCR4y+fbMwGIVqnuRr0wRnUAwHwYDVR0jBBgwFoAUgcSMzPXkMP+lDAhf jBVnIXQB398wIAYDVR0lAQEABBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDkGA1Ud HwQyMDAwLqAsoCqGKGh0dHA6Ly9sZGFwMi5zaGVjYS5jb20vcm9vdC9nbG9iYWxn Mi5jcmwwDQYJKoZIhvcNAQELBQADggIBAFhp4dOuGtRPb5NXVgZsgiK64Ebppg7m RrwP3/oPk0wMyx/xVL+ap0PtiOwbPdy0YIHpeWdL3QRiHZKHeJZE84rujYuzSOxY EgsO4sZ0KI6QMzDFBCkOhfQTcemUwpWo7gAVMXfBBMdfAQacvLtayh0pX+KeJBcG hK4noNN9A6qRnxMorU3RbTYvyAM1xSm0dHWpqSXHMyYmVnLsRaQt9sN2xhqKz/pC qdqaHCpXbzGRqTyegJ5xkG3hLBjodNHObrG5LSqsgwKeXS5Mmmgja7hJDYkULB1+ TKbWD/MwfvIgd3RWigsG06sa3Jc42rTARBuBQq21jMF9QO6aefpEAlCujSUK43Rz 2O0QkIhUPqC74ba7lrlQs5hAC7orCTNn3SUUS8eDk2qo0eX5RDFvVznfsVftYU15 BF/D34nyXpD+DEkqGDPzJtMOwJ5ZNEGK4oG2zgJRXOi5HRIeyfYqgCLx4Jz/W2m/ Th2N0KWXLxX80Kizw6SPQCMZ5/ZBs2ZKV9K+/rl+JyNv3Z7v0RXjhRKUCc36LW0N 8Ot1PEMDy6B9Q4et9on833w2HIwWQY0bVSlTbUaRfy4llyZcPQ2bMgjhkBbe5VWo SDNdpJ4BBvpKhtPyJ7ubdFwP3egEiwauLw9HwnQiV0H6kl6O9uDMncNImrqPpu8p GBqTDyC3Ruak -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFoDCCA4igAwIBAgIQUuhDsZZ+VM6gWSw3oW+alDANBgkqhkiG9w0BAQsFADBH MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTgwNDI3MTYwMDAwWhcNMzMwNDI3 MTU1OTU5WjBSMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxMDAuBgNV BAMMJ1NIRUNBIFJTQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFNlcnZlciBDQTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrO2TwT/q2v7fcZfa0lkJ9pE8IH qVZXzLayN6CMEucJ0pJUjsnpt8SOMYhefJ/gpwtZOKasfY7vc0EOwd7IZEPco5yn 0ERh9y/o53G2RICEopGpWoOMKYtfw+YCkes5P4ucMCJfwlH3YRUb8bko5QCO84Y3 kI6oIaHp7+gY9vwmwKXp2FH4bG/V2SxHhSCW9tUSoTzd0rxGAlq2Sd2GyzJnmWnh G4fWvgC+NZfwxc+REMy5OCJ3PxT+F98FlG2t9bpw00RVi8g7O03RYOqT0nzbSUvX tuKaQTiXYtfqayJuVa7MpOy0w2P1NP/aslHxdvsjiUEeOhhHLJplavB/+s0CAwEA AaOCAXswggF3MA4GA1UdDwEB/wQEAwIBBjBBBgNVHSAEOjA4MDYGBFUdIAAwLjAs BggrBgEFBQcCARYgaHR0cHM6Ly93d3cuc2hlY2EuY29tL3JlcG9zaXRvcnkwEgYD VR0TAQH/BAgwBgEB/wIBADB1BggrBgEFBQcBAQRpMGcwNgYIKwYBBQUHMAGGKmh0 dHA6Ly9vY3NwMy5zaGVjYS5jb20vb2NzcC9yb290L3Jvb3Qub2NzcDAtBggrBgEF BQcwAoYhaHR0cDovL2NlcnRzLnNoZWNhLmNvbS9yL2V2ZzEuY2VyMB0GA1UdDgQW BBQ7SyUqdzcq/Ll/7ai9ryKZ/F3F9DAfBgNVHSMEGDAWgBTZdDrkMD0N9xLcfloF nx40mvfhFDAgBgNVHSUBAQAEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwNQYDVR0f BC4wLDAqoCigJoYkaHR0cDovL2xkYXAyLnNoZWNhLmNvbS9yb290L2V2ZzEuY3Js MA0GCSqGSIb3DQEBCwUAA4ICAQAceBs7lYtmgYahhFm+pZPEo3k2khX5NsQtA8rW vtkyQ54YNJaMCy72lW/FAwC4NnTxPiwOeVSH10kPyRVYBelHs7D6MR19ZV98i+Lz TgSYxyFh9wvGl4pML+anNZk0yjLlkYRcCiWAql9Q205FmUcgZ8KnzFN+J8li8Ia0 C1jYKjMGVcGHD+/RoV9eLLpdeqj4Ez8XLzth09m7DFEe+F17yeXTZRmn3yO4ErKm cVApwQOpibIeqW/eht8bpesvfL4WbnJPchw5w7/ed4mQ498SYxtHvD4b+7U4WyVp Bev+RylreBxxxtThD/++PTGNb3pxzPM56Ff6uHHrTTzWdSt0u5tSdESkUfbJt0fR ggSD32YA8Oo3C179cYbYEgskYfXXyePe00Yr5drfKfujAlvrO7fD7Zf/U6xFFwWB sw7PRYd9HSlttOc1MdWzcn1BvB9+8lQ1Q1mUBxryROd5DgbJoAKa7e7dF4ONCVt4 zvzIOpYMrflIoeoFM8YWC7xP9Bj/YyRbqm8WLJ8rQSavrORLqpBKp/FKmyQ9LzoS W9e3c57wydKsUKN+9ckPVMHA0lHg4E1Afm+AXKqcbtnFe8TVvT1hEm2Ht1QAFQBt GCfhREAyjEQwz04LLjzOsIKtqT/dp4PoKPVki71V2E1AgyrxhJi2DI2x6v2kl89z XbDMqg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHWjCCBUKgAwIBAgIIeGx8Wfx8oMAwDQYJKoZIhvcNAQELBQAwajELMAkGA1UE BhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjE7MDkGA1UEAwwy U3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFNlcnZpY2VzIENBIC0g RzMwHhcNMTgwNTE3MTAxMDU4WhcNMjgxMTEyMDAwMDAwWjCBgTELMAkGA1UEBhMC TkwxGTAXBgNVBAoMEERpZ2lkZW50aXR5IEIuVi4xFzAVBgNVBGEMDk5UUk5MLTI3 MzIyNjMxMT4wPAYDVQQDDDVEaWdpZGVudGl0eSBCViBQS0lvdmVyaGVpZCBPcmdh bmlzYXRpZSBTZXJ2ZXIgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC AgoCggIBAL+smIBJEbwtr7PT83fssJvDlLaYAOYxrIqTL1leDVliLiIJFCfFWwC1 V5UiGFHckvIFir7bH7zcb8fmfRozrZriAoqWXns2NbNyBLolVml4R59aI5ojkPFw I/rrQiwuyRlfx8TRJnUsLCyyT6IZgfjCNjbdzLy6WyQdsnleiLNu+LiMFxOa9yVE LXK5uPx5yThzUfDN4yCadY+s0c76x+I9yp/aiIHoy585l3IG5DsRbwEL6LotGUR8 fYR3ibu0Cw1nRp+FaCekeuRX/WYkQG8kAtP9z8600km8lT9o+i6rER0FffhXUxB7 VkufhO1oj2HXPW11pubU9mWjCaQa4UTHTElv2fdUu4vPnpQBEYlxbV8c20oruytB qlOpu8n4muuC+LQO/La4Jg7l/rukk5Z0e50FhX+9QNQD46m2QSRiEEWyYAejdCZS fmEBpi6zJMH10luhiLBd7yOu1x3bkpqvAHCfwrAaawBV5LrL/ul20zRmxwbMMw+1 46iNw1iEgr3u1CcGGDbovTbM2gXUnadRfQeWmQixXEdFMhcNvOYmSlSkE+4DJKLk Hj5DwUsATiECflOyTQlQVCo3KCiQUQ01DWo296ic2vnk58ot/jx1vFVvNskBGjez jo2c+q0YzGkO2qip+HF3Kare8DFKtPEiNqdjKEPOc2oVl3CD/Is5AgMBAAGjggHq MIIB5jCBmQYIKwYBBQUHAQEEgYwwgYkwRgYIKwYBBQUHMAKGOmh0dHA6Ly9jZXJ0 LnBraW92ZXJoZWlkLm5sL0RvbU9yZ2FuaXNhdGllU2VydmljZXNDQS1HMy5jZXIw PwYIKwYBBQUHMAGGM2h0dHA6Ly9kb21vcmdhbmlzYXRpZXNlcnZpY2Vzb2NzcC1n My5wa2lvdmVyaGVpZC5ubDAdBgNVHQ4EFgQUFNpISXBRtDQSeOaKwBV72Br3H+ow EgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRD600A05WTzqZ8QA1tEb45 0TKu4jAlBggrBgEFBQcBAwQZMBcwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjBBBgNV HSAEOjA4MDYGCmCEEAGHawECBQYwKDAmBggrBgEFBQcCARYaaHR0cHM6Ly9jcHMu cGtpb3ZlcmhlaWQubmwwUQYDVR0fBEowSDBGoESgQoZAaHR0cDovL2NybC5wa2lv dmVyaGVpZC5ubC9Eb21PcmdhbmlzYXRpZVNlcnZpY2VzTGF0ZXN0Q1JMLUczLmNy bDAOBgNVHQ8BAf8EBAMCAQYwJwYDVR0lBCAwHgYIKwYBBQUHAwIGCCsGAQUFBwMJ BggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAgEAOXuKqcHtxMHAaXimWcRkrvBn limAgSrQFkTGuiLRYdh6Hkkqob2bs8UGmqH3wfjtFQ+FJ6knlWmc1nIgpOZUBNwj X/546ai1SvGhE9X1PJeP6KpAXtAbYsjWec7Yu9erC8XbraOWG8MpfYMtDQ1zp2Uv LRkHR6cekqHdFi57AegzYbvjNJme1qAkhayKizmGptBcLf7p5UJn7ARFBhocSL8X 7mlSO6wfqMNbNqpDhEU1C2eyHMrSvG663oZ/WCPXrzVzLZfoMdybzVISMKjUU8WU giT6qpQPSDtVWJjq6HH1cyFP3VgsJcsLDPoDEMxQcjwi74U7wUSjRzY/Vp+HmTHt 55yo1NldgYpYk2kowYXfu2PDCK9HEbVh8WJ8F8X919cOkY+cSrLwzJGqd2y4aGk8 Pg/KDP+sjst6qF9mbdRA6USssFcN57PfpXq53pcVwK6BhbjG0CvuKGGFyadNAdHG ins8O+TXkxkH2NzBgrm/0ahaYF+RIffnXd5dmhnrVmIO0emfi1yG56QYH9FLiPHJ wGDBPht5H99SeH03WVkrkPa9c+1K8H0M1EpMfDSrFBqdRsMgWZlUFrHT+/5NLEds TQiqoiaQEte2WJPPXa9o5PHv1gPapWKw/wz5ldmsSQ5hFU8dTQkUM3tWLiPeWWWD AhDzPxAzH33NazHssMM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEozCCA4ugAwIBAgIQBdH8WS5y3RzQI80YGNqnHzANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xODA1MTcxMjMwMTNaFw0zMDA1MTcxMjMwMTNaMFgxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xFzAVBgNVBAMTDlNlY3VyZSBTaXRlIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAx7s903fR6SgpA08UdhKEUIZHa2Ig7KPNkTtwMS1+08YS5QSE DM4DQxy48jP8dZkyyU9J/0WCm8Nlv5ga7HOAxhdJcv+CPP4oadx8EbdrmjAHrGOv 64oHvt7Ina7uzLd3krqxd0doeuxRpTHvFAyjaUhxjSfZx0wh1f6W7prPm7V50VcT udj4rI+xtHXUcFAuFz4bcapTcru5aaZ1v6F2usMCMVM+xJxEZcsUM4uTxdIfW5FU TI0dbP8NyZkr/WVzL59aGwBE4ZU0JKBlgEmtkFpLPR7JCzYunafu7nMk5YY26WDO mezpWDjzDxJ8xakizykWYT5gdJYE3ULlUe31WQIDAQABo4IBXjCCAVowHQYDVR0O BBYEFMQRfohAhsJBv2XzGuG0U0Cjq+x9MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj 4hsbw5eyPdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA3BggrBgEFBQcBAQQrMCkwJwYI KwYBBQUHMAGGG2h0dHA6Ly9vY3NwLmRpZ2ljZXJ0LWNuLmNvbTBEBgNVHR8EPTA7 MDmgN6A1hjNodHRwOi8vY3JsLmRpZ2ljZXJ0LWNuLmNvbS9EaWdpQ2VydEdsb2Jh bFJvb3RDQS5jcmwwVgYDVR0gBE8wTTA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcC ARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwCAYGZ4EM AQIDMA0GCSqGSIb3DQEBCwUAA4IBAQDIiGcy9AiAa0e41RwQxUUs9uukRK8H5ekg gREh38fJ4vAjYliu6t5VjNSI4+yzXVw0sy8JmaHzOs5A7AqqOsovIwJxP5/MMAh7 U/K9QWeD5mqRpWUi9vluwqQPEtK4tgZt1s99RezAUK8Jtjfn5UmUxUh6ET4lxyDe 0NhgxpfsWsgeYgwYEGrODa6fHQTpmxGTzyNvjUIR4de09NfRoCUWUumjNMLdaLqf Vv6kRihaDDZc2bjoANtTUJ2lyHZJqo0mAVs6gZJ4Jl7SgtdxfnkxHuzDrjWxwo98 VueqqRBUewSmweO+btngjVd6Gj3E99EGIJq3k9k4HXPUaRJLQ3qY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEnTCCA4WgAwIBAgIQWTF/amkEEUMds1dG+OqyMTANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE4MDYxNDAwMDAwMFoXDTI4 MDYxMzIzNTk1OVowcDELMAkGA1UEBhMCSlAxDjAMBgNVBAgTBVRva3lvMRMwEQYD VQQHEwpDaGl5b2RhLWt1MRswGQYDVQQKExJDb21vZG8gSmFwYW4sIEluYy4xHzAd BgNVBAMTFkNvbW9kbyBKYXBhbiBSU0EgRFYgQ0EwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQCFZZ3ZKbX5tLhPBbotlpsf67GaL2Zavrm6d4iixF4HOjdW fGIef9usFDnQ/9LZfwFUvBR3Zftp9LODgEu2Y6AUasIy71P4sNpQtJopPc6WxvWN F17OC4fNDpexFS7cNJkmPCTSUaLsy8vUPm0Fliza+rbgT8VEFkq25QOIXbX7Sf2C Dr12g4Ov9PLqF/FvmBlD+Z8dtjcWSDafERsgSHaVLOH5DD13GOsPzzu6w73+Hfdg GvT+LgpJsAdt5l9diMS9nNfaYZN8UGoi8Sq07zDNpKM7EV+MqRomSwXbLTrcOIGx LCfjibr7gnGQj0GyaiNR2hawVHVUkqqgGXvJoSwJAgMBAAGjggEmMIIBIjAfBgNV HSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUIZEBzIgfs+Yu Q/R88TCJi0FsHUowDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYB BAGyMQECAj0wCAYGZ4EMAQIBMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwu Y29tb2RvY2EuY29tL0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUF BwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0G CSqGSIb3DQEBCwUAA4IBAQAEolN/OqKPWfzwfTRTdC1OIps5VQoJnVQD6hCOkcfR 1nQGmQpe96CnQNxbfu5SszjGBaImtJOEt5L61kG24jJwQNvQyYAGWxAYHD6+CozB SXMn2q68j6fQxlD64om74TXnD3Z4skX7zuPbYchevQ/BHKFFAkh6vJJ91ppz/WfF SldW3aVWpLcB3CZqZCpmRiIpqK3dDW7Rue4kt/y/woJ1eiWkC17+bCepN9WiOj8P GFc1t8tyrAZzq8+2IXeIpZJMIGP8+6SWZdUBxRFyIuOxMyWhSlx+OFYDjOo+wQsd eF9tlPKYiqJ7/G4HVhad0mWlh10pn0IZjlWwhh6ESs2s -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWTCCBEGgAwIBAgINAewckkDe/S5AXXxHdDANBgkqhkiG9w0BAQwFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFs U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODA2MjAwMDAwMDBaFw0zNDEy MTAwMDAwMDBaMFsxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52 LXNhMTEwLwYDVQQDEyhHbG9iYWxTaWduIFRpbWVzdGFtcGluZyBDQSAtIFNIQTM4 NCAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA8ALiMCP64Bvh mnSzr3WDX6lHUsdhOmN8OSN5bXT8MeR0EhmW+s4nYluuB4on7lejxDXtszTHrMMM 64BmbdEoSsEsu7lw8nKujPeZWl12rr9EqHxBJI6PusVP/zZBq6ct/XhOQ4j+kxkX 2e4xz7yKO25qxIjw7pf23PMYoEuZHA6HpybhiMmg5ZninvScTD9dW+y279Jlz0UL VD2xVFMHi5luuFSZiqgxkjvyen38DljfgWrhsGweZYIq1CHHlP5CljvxC7F/f0aY Doc9emXr0VapLr37WD21hfpTmU1bdO1yS6INgjcZDNCr6lrB7w/Vmbk/9E818ZwP 0zcTUtklNO2W7/hn6gi+j0l6/5Cx1PcpFdf5DV3Wh0MedMRwKLSAe70qm7uE4Q6s bw25tfZtVv6KHQk+JA5nJsf8sg2glLCylMx75mf+pliy1NhBEsFV/W6RxbuxTAhL ntRCBm8bGNU26mSuzv31BebiZtAOBSGssREGIxnk+wU0ROoIrp1JZxGLguWtWoan Zv0zAwHemSX5cW7pnF0CTGA8zwKPAf1y7pLxpxLeQhJN7Kkm5XcCrA5XDAnRYZ4m iPzIsk3bZPBFn7rBP1Sj2HYClWxqjcoiXPYMBOMp+kuwHNM3dITZHWarNHOPHn18 XpbWPRmwl+qMUJFtr1eGfhA3HWsaFN8CAwEAAaOCASkwggElMA4GA1UdDwEB/wQE AwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTqFsZp5+PLV0U5M6Tw QL7Qw71lljAfBgNVHSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDA+BggrBgEF BQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNv bS9yb290cjYwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWdu LmNvbS9yb290LXI2LmNybDBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcC ARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZI hvcNAQEMBQADggIBAH/iiNlXZytCX4GnCQu6xLsoGFbWTL/bGwdwxvsLCa0AOmAz HznGFmsZQEklCB7km/fWpA2PHpbyhqIX3kG/T+G8q83uwCOMxoX+SxUk+RhE7B/C pKzQss/swlZlHb1/9t6CyLefYdO1RkiYlwJnehaVSttixtCzAsw0SEVV3ezpSp9e FO1yEHF2cNIPlvPqN1eUkRiv3I2ZOBlYwqmhfqJuFSbqtPl/KufnSGRpL9KaoXL2 9yRLdFp9coY1swJXH4uc/LusTN763lNMg/0SsbZJVU91naxvSsguarnKiMMSME6y CHOfXqHWmc7pfUuWLMwWaxjN5Fk3hgks4kXWss1ugnWl2o0et1sviC49ffHykTAF nM57fKDFrK9RBvARxx0wxVFWYOh8lT0i49UKJFMnl4D6SIknLHniPOWbHuOqhIKJ PsBK9SH+YhDtHTD89szqSCd8i3VCf2vL86VrlR8EWDQKie2CUOTRe6jJ5r5IqitV 2Y23JSAOG1Gg1GOqg+pscmFKyfpDxMZXxZ22PLCLsLkcMe+97xTYFEBsIB3CLegL xo1tjLZx7VIh/j72n585Gq6s0i96ILH0rKod4i0UnfqWah3GPMrz2Ry/U02kR1l8 lcRDQfkl4iwQfoH5DZSnffK1CfXYYHJAUJUg1ENEvvqglecgWbZ4xqRqqiKb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGKTCCBRGgAwIBAgIIWA60NaoYF7swDQYJKoZIhvcNAQELBQAwgZUxCzAJBgNV BAYTAkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2gg SW5zdGl0dXRpb25zIENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMg QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTAe Fw0xODA2MjcwOTU5NThaFw0zMTEyMDExMzQ5NTJaMIGJMQswCQYDVQQGEwJHUjEP MA0GA1UEBwwGQXRoZW5zMUQwQgYDVQQKDDtIZWxsZW5pYyBBY2FkZW1pYyBhbmQg UmVzZWFyY2ggSW5zdGl0dXRpb25zIENlcnQuIEF1dGhvcml0eTEjMCEGA1UEAwwa SEFSSUNBIFMvTUlNRSBSU0EgU3ViQ0EgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCIymFucfh2tIrX/DgYGH3MdDXEBjZEENYeEEHjCgexPps9tWz+ oTudWpgcWjj0gCmpBUiwCemwE9xTrvcdr+6eQglHxmhfXnsxlLwHZhxpuP6+smnG T9rTRhP5bsHp5ohzzuA3IrIugElgetTXIt4VXznf42kBcEO4lQ1S1U/z49TSEbyy CanIoirjeyuk5Nn6KN9p9ytFwRQi0/umb8Drx65ds4gEe4B5+HizeH9SsegWPL4p N2yqwN4KkB93QG2u+IBBS4U9Ouz3gImStRORgzowZfvjQAAM7fFfmfyTV4JOiz8M OacDPmGX/kZL3V0pZLmklDcyi9da2kP3rJMOpvo4NhI2jDZM5pTGOMc8RuQeNtZB uQacJYgfPxIE/7dfF0JLhEIhUlAcoGrbw5Y0PC3UFiiLr16UQ5kjbx2kiUQZa1fi YTU+UzYbzpmYXiktduQhkKpmFLPDcmOQhAGU0cs82yanT4Ld5WFULWE2WoJF8rtS JdzzLLIF/DS4VopiMDozLjLJ9nfMHTkp7tuwSIu21Wa+qZ7YC7K5RxZ6h1rQi3WV TZk+ZMxOLhCFHlO13VMNtzvFDR61jQ7PRBtCOj9Nvm1rjyU53UH/1/SlOSbASk1j tRudbXWgjsnfNn6kpWbYdNm5bKjkibU5TQ/S6p+vmjus7MA2qNjje2wPpQIDAQAB o4IBhTCCAYEwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSmkUL9E2FK I54IpCnl2BMEI+5BJTBvBggrBgEFBQcBAQRjMGEwPAYIKwYBBQUHMAKGMGh0dHA6 Ly9yZXBvLmhhcmljYS5nci9jZXJ0cy9IYXJpY2FSb290Q0EyMDExLmNydDAhBggr BgEFBQcwAYYVaHR0cDovL29jc3AuaGFyaWNhLmdyMEMGA1UdIAQ8MDowOAYEVR0g ADAwMC4GCCsGAQUFBwIBFiJodHRwOi8vd3d3LmhhcmljYS5nci9kb2N1bWVudHMv Q1BTMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDBGBgNVHR8EPzA9MDug OaA3hjVodHRwOi8vY3JsdjEuaGFyaWNhLmdyL0hhcmljYVJvb3RDQTIwMTEvY3Js djEuZGVyLmNybDAdBgNVHQ4EFgQUWtM9TvoN+06dKIZSRWLElShB/tEwDgYDVR0P AQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBWEu9/OW3AO5vvTpd2lFzRGtmj DpQiOM1Lfu1zBkS1owRlqmQHciJy0LgOWt6hh1HSXARbIPdnd2YeL9Qw5CNvwBrl B6xd02nidsiDiaJGFwwq8/8nbHxKvxV94A84UYfDbzX1YuJF0r1Qs/Bz0xXj59fZ pyviH9TKeEa6SnzfXyaIxWaDjPMPGZ6dka2pjY4EWUx5Qs2Pl7eSz4MG+NNhcUDC 7UJA5iLRuLidYMhzWW/ECOZJgzfNAZ0fj7pjDD9d9mdACtDK4tPvm7QvD2/eSwOm m7ab9h5oK4TcVWDJ0M8n9RsRQmpRoihmL4SLQPvB3U1EgGGXggPr9lj/K8rW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHOjCCBSKgAwIBAgIINbikuOiUIbswDQYJKoZIhvcNAQELBQAwgaYxCzAJBgNV BAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFjYWRl bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAw PgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRp b25zIFJvb3RDQSAyMDE1MB4XDTE4MDYyNzEwMDQzMloXDTMzMDYyMzEwMDQzMlow gYkxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHDAZBdGhlbnMxRDBCBgNVBAoMO0hlbGxl bmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0 aG9yaXR5MSMwIQYDVQQDDBpIQVJJQ0EgUy9NSU1FIFJTQSBTdWJDQSBSMjCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAI4SdW6h/TbHOmX/wxztizhbtHtC 74urzSJVQTiK8pmhY2OdukR3/QBM0O+3+90ZF4zC3JQifHcXiICwwRk+1uI49ryz dj1xghGqRmt7wIKgnNrH4/39SaSQuhirwCxug0bstZFA5JvGXNMDbEEExUGK2M2O Rq2zNz0gvqmQ/PoANaPpb/Wh2mj3L2nlxoa+uI5U4PYwhjnd6XLJ9kmGKlIVopZW ZQGWgkvH5VDNUZOKISehGD5029bA/P3X5ozQxFPanePyzTKHTT06mIUS3ukCxfcy Oit+PADHBhS9w/QIZivr4wqzodY6UJ5DgxDCOQYUakmsXMqWPx1SS3YRZryj8Tz/ DaaIqbPOMVsWK4c88BrbTUJ9lBob2kdDwd4psEFPxHwc1w9ReRJCDXid0FHj4iaz yjOcNRiDiEMD9CUptl3EZdyW4ILUPw2YwT+sqAIjbPBRJS/JHdwjnJ8E0kRuzHIj xgF7PWnDeDH6T5JYi5qcdlyrvepCEdSCK6cIUEhMri0m8pJ/h7T2Im3tbUjJQbah bbTNTlxds3js6RkoSC+Ia7EYm1gLQzxLjjsWkOTl/r0iW8hjAgoah+BJyaYFiiY1 hXnM3azNwrk7xt9c/5wCSm6lL7JPaRkBHxhI456IgcD18pqzqxAQ1AKkA7V2QQsy s8PmF+HraIDjNQwTAgMBAAGjggGFMIIBgTASBgNVHRMBAf8ECDAGAQH/AgEAMB8G A1UdIwQYMBaAFHEVZ8jIyb11XXLQOBhqnfNxJFQLMG8GCCsGAQUFBwEBBGMwYTA8 BggrBgEFBQcwAoYwaHR0cDovL3JlcG8uaGFyaWNhLmdyL2NlcnRzL0hhcmljYVJv b3RDQTIwMTUuY3J0MCEGCCsGAQUFBzABhhVodHRwOi8vb2NzcC5oYXJpY2EuZ3Iw QwYDVR0gBDwwOjA4BgRVHSAAMDAwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuaGFy aWNhLmdyL2RvY3VtZW50cy9DUFMwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF BwMEMEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly9jcmx2MS5oYXJpY2EuZ3IvSGFy aWNhUm9vdENBMjAxNS9jcmx2MS5kZXIuY3JsMB0GA1UdDgQWBBRo3vC9e3o8ffDS j7LxZS8/PiEU8DAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAAD6 wgZr9tD+KCSWMtPPN5IeQXo319qDekNzUWyEoYMcgfkSSGyBqDaPu80LjFFJvWBm XyBzis5tbuv5ynVhwval65yK+QEZYLVOiKIUQ1NPglux9a2VD+s5hUL3l7WEHTFY qIuNNAM/gV1PPOFXVErgEY+PS3u6Q2Pjp39kFebzuJiHGASFw1ajDdaihLhkJr2H bxXVyWjQfrqWJ0K6djKLmM/HHF4tYeVmfCjz1fn1EvUGrNKw+DP5VIaDOQlFm2Cz JpjBkaLsVlsoqNDgGeH3QkZpyC2nuhQCK7+28QIS2uy3Uk4veVnST0i0jkhogNvV 5QM8wWwLrFrcX2JZQ3Jzg4pLL0FRoR4NIBMQvIGoccWHHWdUrI3d7cuZAd8x0XyR 2+Nus2jKavInJQHcPDU3Az4P8T9fyw3v5LSoi0mXwSRg2xsFe+DIJhRjt3f/AGX3 yMiKdqsGtM6ox1myLMwh9Xy0bK/G4ldnzUFmKmw/04j6dyQGBsCcEGt1rcyihzFR Q4x/pERC+BPsi9cZq2xDixn3sI//UIwYxgEjdx9fgYTpHqiQ6D7zLqp7k/LigNhY 0f47uPkqOW9g4vEUSwuG1rdT/u21sFKK9yNCeTh5UshnxfOCaxQolvXJsYPsNX+U 4IA+FR78WF5OM79Di3P5XviNqP4MosIWEYMSQJrG -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIZDCCBkygAwIBAgIIAaS3Z8WljY4wDQYJKoZIhvcNAQELBQAwgawxCzAJBgNV BAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQg d3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcx GzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEnMCUGA1UEAxMeR2xvYmFsIENo YW1iZXJzaWduIFJvb3QgLSAyMDA4MB4XDTE4MDcwMzEyMDExOFoXDTI1MDUyMDEy MDExOFowgacxCzAJBgNVBAYTAlBUMUIwQAYDVQQKDDlNVUxUSUNFUlQgLSBTZXJ2 acOnb3MgZGUgQ2VydGlmaWNhw6fDo28gRWxlY3Ryw7NuaWNhIFMuQS4xIDAeBgNV BAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTIwMAYDVQQDDClNVUxUSUNFUlQg U1NMIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IDAwMTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAOTX1Zh09z52UHsBb4itNN1nHE4jmbvw4QxQP6JzPBE2 HYL0N3RDqIUc7jEiOgTMN90w2Z+2p40BUrpWS0+sIRcZl14McSrzIUjLAqHu6n6Z yDfRzAJtlhkoKXprimqVXI0zQkFRBGrO9SfPOqnciBytMv6CyRV19vwIjyS21+tv zhId401J5ab/weycKRi0V2ki4V1vPOIkW2ygqXSAz8XwLObvhTdyETHZCFEpge7v czc2HCTLQ90iJcTEy0DYmQU5j05KuYsHp7g0tc9UH0X+I/LEQqqSv9k4B8RYTgzP 5QU7aG/85Lu8Jbb2Rce+Rf2uuKds2XVmqhKb/k4OQ057unOy9EKVRsqA012ofyEU IJSixdSaF/Bz8qtCxX6Qeyvjjk5a2k93xdr/DoDJdRv60YWwbkNVCk9gj6CttbF8 m2YHuVaOxCjo79/pzTnsgBZf2/C0thKdctuzvkXy75Fa1Oa20BXDDVSHQGg4iuex cyEr98nraAGm1sFkzcaRprtwNCjyrYNdlehLehamzZOU9+y+0v4qZGfBLpRz8Ac0 BJf7NdfUIUiZ8GhwJ3Ml9mhdG+ND0P+LhtAiI9m3MnAkNoAHS1VAQGgshp4TAew3 vvuSKvZ9Eb7ct9vz5c5YPZ6Y70bE14wlqpu4ZlDbb+KaMZa2CNHAMuCFmuCjW9Cb AgMBAAGjggKLMIIChzASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSwAjlS Ck9zmsjZgUU2XRGdXyM5lzCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuT BjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2Vl IGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRkcmVzcykx EjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJtYSBTLkEu MScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp 1X0jzjB9BggrBgEFBQcBAQRxMG8wRQYIKwYBBQUHMAKGOWh0dHA6Ly93d3cuY2Ft ZXJmaXJtYS5jb20vY2VydHMvcm9vdF9jaGFtYmVyc2lnbi0yMDA4LmNydDAmBggr BgEFBQcwAYYaaHR0cDovL29jc3AuY2FtZXJmaXJtYS5jb20wDgYDVR0PAQH/BAQD AgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBABgNVHSAEOTA3MDUG BmeBDAECAjArMCkGCCsGAQUFBwIBFh1odHRwczovL3BvbGljeS5jYW1lcmZpcm1h LmNvbTB+BgNVHR8EdzB1MDigNqA0hjJodHRwOi8vY3JsLmNhbWVyZmlybWEuY29t L2NoYW1iZXJzaWducm9vdC0yMDA4LmNybDA5oDegNYYzaHR0cDovL2NybDEuY2Ft ZXJmaXJtYS5jb20vY2hhbWJlcnNpZ25yb290LTIwMDguY3JsMA0GCSqGSIb3DQEB CwUAA4ICAQC0NGt2BqbMpJ9r3xUvSdsbXOcLrhfLP0yx72gGKW17gJ64fpr+tglf hP476JMyvvmeU0gGG7543NdYO24dF7YGjH+GeRWidvmA0Ri4GIg6vi58ISeRJ+US aY+Po0yFRmaboZGi/Xtzr+g6QSMW+AC4qHNYJU/Yal2C3hT2xAyYbr8A/ty4ZKUD OCEDZ3N1MN7vrkgnBzTG5Z8XxHbcVLZ8Fpr6V8SBZeGCod1wq2WT48/vE5FxLrL7 vVejQFmw3QkM0YcfLWEf3l380o+z4AyKoiSUGoPiwxVH6OKBAhxmye/6xeQ+uXPw OxUKcDSvuzGpdK9GA/I6kYEaYbMkZwi2H97BExwd1hsWoYpxilcGEXXQhmZ6pnjq C6jMRMDPrPBjcsB2XJr+Cz2EUooG6RuNjQTaceiHneFQrhykR21hw0TEobzqfpqN 6WZf2sLHhcZ42uGwVyoGgC9EtHI/hspQEbtGQ+jXwnEzfzfu25XQ6rfwQxV1HF7I yl1pypk9b0tsttFDzdDrrpAOsG9YF0i09fQIrTf42E1H2JQheq2L1qnMszNUN3qw PObfqN3k0ZrImpDL5aBPpb0kgNZxr0D4bCi7kSWwlNnjWM+i8kdndg9W2BkzFV/A wKXoJijDteXrLxkLkWdN2k+W4/Jsvs/M4LmaBEruqTeUMa9FHlqJKA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHGjCCBQKgAwIBAgIQaH23FxdE2iNbP2Jac5P4pTANBgkqhkiG9w0BAQsFADA4 MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 ZW5wZS5jb20wHhcNMTgwNzA2MTIzNjQxWhcNMjgwNzA2MTIzNjQxWjCBgTELMAkG A1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMTgwNgYDVQQLDC9CWiBaaXVy dGFnaXJpIHB1Ymxpa29hIC0gQ2VydGlmaWNhZG8gcHVibGljbyBFVjEiMCAGA1UE AwwZQ0EgZGUgQ2VydGlmaWNhZG9zIFNTTCBFVjCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAN1INsruuFEV4Z9tcfhNC9neg6vTQYhJPNFJQmKGJVcELjn3 Scf8kP0jJJOWlDKxYiP1dXjzV0FpK2colXDaV7gHXD912VoPVLmbRyK3UyV5YYTO TGd84ErKtIceYLa7Hv38zsZnIkL+rfS98QoivMcZhpjRoLY3IUZ9U7j+DX/MkkJ5 u6cXRe1vB8x9FwdWSwTkkLK4+lOhFOW0o5LDnt99Hs8ddi48KEflIbS7qYZty/Wy SH6pvoi2ZqEAFL4eMIos4TMfV5Pdrd13HAB45Il/kdva0dq6GHfpy3absBZhsxVb mvdAc1f66Ytr/qoLKSwBxRM/cCpQurnbS74HVgA2xBPEHM75J/YBa5uMgI/yxTzo EiaGhExhTMUGG+9od8oqhXzDR1ecyxXqndVzf4RJB+zgd4LWnVXM3DJC0WBgmFES Ucn0fqoyb09RPN5vFtjY/HeAuzm39p1RDclejAWWnQaDAHJrKUsk62zWKpJjuR3m /WhLo9upz+oWO8hAofLIdxH7BOFPL+OOOsWJ8qqQPZpIZQZkwV02WBaxYufwMjgf t4anyPrfRgujyIxFmUJxxTl6faL5XngYkZK1f4Ns2hOfn1qKZEX2C9UlCpBrSVQi QMkM0Q3fnYOa7TBDB/f9yroxmrLmXUuG3VOCZ3rtN70DvcL7KbwiNlX0ld1RAgMB AAGjggHUMIIB0DCBxwYDVR0RBIG/MIG8hhVodHRwOi8vd3d3Lml6ZW5wZS5jb22B D2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBD SUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgx QzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAw MTAxMCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwHQYDVR0OBBYEFMbt/nf7UVZN/KvV47EME6O/VOObMB8GA1UdIwQYMBaA FB0cZQ6o8iV7tJHP5LGx5r1VdGwFMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsG AQUFBwIBFhlodHRwOi8vd3d3Lml6ZW5wZS5jb20vY3BzMDIGCCsGAQUFBwEBBCYw JDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AuaXplbnBlLmNvbTAzBgNVHR8ELDAq MCigJqAkhiJodHRwOi8vY3JsLml6ZW5wZS5jb20vY2dpLWJpbi9hcmwyMA0GCSqG SIb3DQEBCwUAA4ICAQBYRlfC3xiMdbPZfP7j+5iHtfH1sCFGWfUF8PdWR5CGQHXq 9gybOYNDYBg8fQNIl3wKMZCI7WoXn+8e3eUUzKblhzU+009CNc2bPHIW4nCn8nak JAcy3ZvDFO9G9K00aiu/aTgLDXnvR71crRx1vTOu30K2Lq9sJNzc8DeJWKmXY4Vu J6C5AgwRsmtRlIBhudOyKTeXU72dRDEFejt8bGOt3gIuSEgrlPGEIP1LRnVVyAnR RWfMOvDjwS5DQQs1j9/YIKS/w9pGB40QsCzUBsHd3N6VCtTi59ZDXky0DrA1c1ae QtyXc90PfqYTwwEwYnQHsR6U0gk8SUB6xSn1nwUuWmHriJtmQGphGw4ax76sEJXN k7XUJeclyKFCUK8gX6fYMb/l0hu2O93sEyfGJF9uIcqvduqEjRWQY36F/xO4r/ZH ndVrI4vMlYN0Xiz/tPS61b3kkrWUVsknKfic8cuBiqGgop1ni0RNylpVk95UsROm 3Cfdcf1fdwVA6poiiYQiINhWb6mF0P7+DcfccC3llMYvxsfrx+11jt8YCQYI8FF6 5FxPCt+YEBO2hnOnPMK3cA8Yvu5ol1fkE/5tcpcjPeRrvuPy/l+at2pj8hv8f4FW MX6Gj8zt8+AoAprvXeQRaiEO4FL5alTv1Rqkv7i0HCGIpc+Ct2ApdcBtC4uSTA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF/TCCA+WgAwIBAgIRAOu6PYua4W17NhIwXdIU9iswDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MDcwOTAwMDAwMFoXDTI4MDcwODIzNTk1OVowcjELMAkGA1UEBhMCREUxDzANBgNV BAgTBkhlc3NlbjEQMA4GA1UEBxMHR2llc3NlbjEWMBQGA1UEChMNQ2VydENlbnRl ciBBRzEoMCYGA1UEAxMfQ2VydENlbnRlciBFbnRlcnByaXNlIFJTQSBPViBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdxKIenpwImwr3dZ4p0zDSs tGBJ0s0js8Sx7XnUvCji9L9n6hM10hd/pNu12q/PPrqk50aFiJ93AW4zwQDGGtpc AyDJwBtCor3rOaVyWLnv0CARqKKmrPitp4Of1HhMqcG/yuR6kU0pbKQKQVSQ1cDk N9IxKadMFjcxUw6kvPDQBdOMHAMlLFeXC5SOMEmanPZrWlAMSLr73F+ogtNREGQM iPK3XmTsv58C3Be8iCWRbGW6Rp54O+zogiw3VwLHYZQDTiHdgzMw9OIW2rOwYUp9 nxZHjdFR7ebX+KE7sxXiosk3MnV0vr/nb0MhkgSikwvhbRoPOTWO7l954HXYo/8C AwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0G A1UdDgQWBBRO/IF8baPlGobqqDhmbpwy7M8NlDAOBgNVHQ8BAf8EBAMCAYYwEgYD VR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw IgYDVR0gBBswGTANBgsrBgEEAbIxAQICPjAIBgZngQwBAgIwUAYDVR0fBEkwRzBF oEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRp ZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcw AoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0 Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0G CSqGSIb3DQEBDAUAA4ICAQBxe5XWjfNN2hULvD6W2OBfvrgQIEVFMzQ36kZcxxvM f7u+eEn89JhraHwh9YTEKypptWnR3e7NfP0ZrrQF5nfrqmqWdA7fBczj7rkJBs5U aTxBlnZasUJqJj4p3il4ytcbebM6XE6zM/+NeNQ3R6jHaR6cJ9EMbUphaCPYCdEY VCxJZgvfLfQo4/2sCKVzGaZeT85F8/CIvEsqD7PlAvEkK1pPUMveKzOvVKSFlW54 AH1SrLUq8yEKp04JzQ1bW9t88EM7Ll2PQKFJs+umxmCnurESpjl/dpJg4XrtJQqR jLasfuSxaXgPsYN/aNPNNJSluwxBdo+ql/tHB62+ApvuY4dHEaBQGY074PLo8CuR +/2xbHGzXgm6ZMaO/OwMHJiGrgf8fYE0FNmUrU81W9ABoveBgAFpPeJgqvGs6M/c YnSOO7g9QXWraHhM2H73o89MxijkpEPM9q1vTk3jzaGLk6ISneuuh0d24IyAprKi 20S5MGnzZtSvb4yI6lMfji3dZaGRzOWvhKYtUjPVX0Vk2phHmsVfdfutaXzCwHhF jYeu4Ej5IhHmzhYAecvIN77rzDUdROG5TsOQogwlchgbgC/1tN6RNNXOmxY1a2AN gsMnSR/56NbfXPIxVEpoEfrYQIDLBTIpGhkgWAMEi1DnzH2YLw8GB6cCe4dIioxf cA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkDCCAxagAwIBAgIQL9WP4x+8PVVyfGhYjrcrezAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgwNzA5 MDAwMDAwWhcNMjgwNzA4MjM1OTU5WjByMQswCQYDVQQGEwJERTEPMA0GA1UECBMG SGVzc2VuMRAwDgYDVQQHEwdHaWVzc2VuMRYwFAYDVQQKEw1DZXJ0Q2VudGVyIEFH MSgwJgYDVQQDEx9DZXJ0Q2VudGVyIEVudGVycHJpc2UgRUNDIERWIENBMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAEFla5R1oeT9C4PJt5YyFkjYYP9uBxBKqaZcqH /QqxSvOFd5VfRrRkgr1aYJX3fdRDPLSqHCzUSMwVpAKC9QixcaOCAXUwggFxMB8G A1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBQFB4MrGHtx lpwlCXC1g80TVxlH0zAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsr BgEEAbIxAQICPjAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2Ny bC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3Jp dHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51 c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUF BzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2gAMGUC MQC9GhsYrhaF1JVEq4gPwERT6ECmUS1xsS0Bg6Bwo4nEjcFWLx4BstBi9t5orojA eOgCMFSRlRXzyqJHXut6F0zATqxHrM17JvieLU+qSm0tpJ36SEIXElHB80MQDIs0 rHvsLA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID6TCCA3CgAwIBAgIRAMpnPizyr+w2NfxlHraUhNQwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MDcw OTAwMDAwMFoXDTI4MDcwODIzNTk1OVowgbIxCzAJBgNVBAYTAkRFMQ8wDQYDVQQI EwZIZXNzZW4xEDAOBgNVBAcTB0dpZXNzZW4xFjAUBgNVBAoTDUNlcnRDZW50ZXIg QUcxPjA8BgNVBAsTNUNvbnRyb2xsZWQgYnkgQ09NT0RPIENBIGV4Y2x1c2l2ZWx5 IGZvciBDZXJ0Q2VudGVyIEFHMSgwJgYDVQQDEx9DZXJ0Q2VudGVyIEVudGVycHJp c2UgRUNDIEVWIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEO3tvqwqs5vmJ 1xbnHhKDuek7V1xuRupZkparH9sYuS0tJqx5LeI8Ib/VLTuu+jy12fyXsxO2RgGK otk61wzd1aOCAY0wggGJMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2Oa MB0GA1UdDgQWBBTPBif3zAgPmGJIxedA9beT+DvQATAOBgNVHQ8BAf8EBAMCAYYw EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwOgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYBBQUHAgEWGWh0dHBzOi8vY3Bz LnVzZXJ0cnVzdC5jb20wUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2Vy dHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3Js MHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1 c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlo dHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2cAMGQCMA2nSJGm LYKaByydKTEvFTiEpQM50zh4EOx7Xot9iQpTStEZrZ8af5vwZGb9yeVyZgIwXU4a /QNZ/LHBkulYzOOwneK3miazSfg/xqA+KNXypHwXhP3hmshQolBUTO5YxK7Y -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF/DCCA+SgAwIBAgIQZxGIu5TD/7pzBUDRxUUqDDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgw NzA5MDAwMDAwWhcNMjgwNzA4MjM1OTU5WjByMQswCQYDVQQGEwJERTEPMA0GA1UE CBMGSGVzc2VuMRAwDgYDVQQHEwdHaWVzc2VuMRYwFAYDVQQKEw1DZXJ0Q2VudGVy IEFHMSgwJgYDVQQDEx9DZXJ0Q2VudGVyIEVudGVycHJpc2UgUlNBIERWIENBMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAigxDNOEbVyOn2nyD9uu0FUbx 99k6oMF20pBRnVD++qtJTx/6zalqqbCR0yrCUPEdEnYULJ3ukDOrEel4EW7mLgLC GAfLcG9/ffwOwdz8LD74WSKwiFE5T8m3jtsPM1XoRKee9Ay14Asvk+sJCqaFODVv glPRHT+Qnh0uunu0negtUstEQo4sAgp2I/qiG152J0kCEjHtnZ1RtKacC/BJlHMb igiIzTF8RjLGTHCxD1DwEj0ahzfasSzq44UkLLQWvPYN+mTWekRWFWelyq5sNkxw ssb5eO5iAWRC0U2ZQUxrWuJEuUyGaO1j3GNlZJIeMhcTj4+qQ7v1oPOfQYC1cQID AQABo4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYD VR0OBBYEFBEL8qqKfDptm/156w7Iw17ciOXPMA4GA1UdDwEB/wQEAwIBhjASBgNV HRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAi BgNVHSAEGzAZMA0GCysGAQQBsjEBAgI+MAgGBmeBDAECATBQBgNVHR8ESTBHMEWg Q6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlm aWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAC hjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RD QS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJ KoZIhvcNAQEMBQADggIBAFAN3pCaUsOcbpBp3bOY319JDc35duEEKJJ+M5e4oWdC jHLFdDxcPwcROUFEtjYwV2KGANhFwiWQ9hKbMi2jdCOHM5zxeTsybr+JRSZ0W1+f iootRWeE+wbGwCBCfy+XupqsQdUHzbgQKGSo67WgCLK77qwAfvvWr918WYH2BUgq yo90PKwY1yYeA2p8AlsmbGVrHFOVReDuCU1FVKAL/X11fb+zwfFq5BkZrSeCz5hp U8mlXU2OSdg9znuYxCJrhqx/FUYLiOk60UFGvyjT+u5C6LaPayRLkHErwuibTxxI JxSIsBN2t7J1h/ieZj06JPQd85KE0TCwk/bRaJR5++pCChr8Akqr3BzidjmNVIFD 0tifoZN6R8krLFjrmkbV2FyERC9BkYJ2aub8alVZvzTRw28zF9R2P74muKNU40aF ze01/ucVTkbFXS+Om12WxQpgdhJF5wytucer94ql4A/CIsyPLBVgRhms7sI/p3zS ttHS7qDWCjXws+d1yfMC4e0urBQ9QxXyWry4dWaOmdN7XR7DGVtxtrjr5iVJseXL EHlrnV6AuHzuliDUUZfsDgmhMrgnE6fSBbu9FRjm3M8dHwt+wipOJOoBa7gvnuKi nxWEl8vpexf9yq/DPrjiHcupNeAq7NoTqoFvLF7qRzEMMdV2RrDw+yVV5wpVSH2x -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkDCCAxegAwIBAgIRAPEoorqEPeql1Nv2H3T00W0wCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MDcw OTAwMDAwMFoXDTI4MDcwODIzNTk1OVowcjELMAkGA1UEBhMCREUxDzANBgNVBAgT Bkhlc3NlbjEQMA4GA1UEBxMHR2llc3NlbjEWMBQGA1UEChMNQ2VydENlbnRlciBB RzEoMCYGA1UEAxMfQ2VydENlbnRlciBFbnRlcnByaXNlIEVDQyBPViBDQTBZMBMG ByqGSM49AgEGCCqGSM49AwEHA0IABPRHe54fgBwEBJFs//MkH/dIP85pc6A3EGvT 0PgNNtmhVUtDN4/WvU6/JmS2JRbovOM007gQA3zNCmFM4Pka/LajggF1MIIBcTAf BgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQUUqPmqoyM j1iPV6rAt8liZO1hCvswDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYL KwYBBAGyMQECAj4wCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9j cmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9y aXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQu dXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEF BQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNnADBk AjBcAYXHETH6+G81Fnwl94RG9M5m0QBfR6IIl5osPhaD72LMUBKwRCw1BTI0NnId JuMCMDvkimAItow1CAh5AF4CXZUIA7BD8JpCR1fT4dAHAHscR9OwlFfVkRRGT03v ZFzevQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGVTCCBD2gAwIBAgIQNDS08r//1aRL0egoOt5KqTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgw NzA5MDAwMDAwWhcNMjgwNzA4MjM1OTU5WjCBsjELMAkGA1UEBhMCREUxDzANBgNV BAgTBkhlc3NlbjEQMA4GA1UEBxMHR2llc3NlbjEWMBQGA1UEChMNQ2VydENlbnRl ciBBRzE+MDwGA1UECxM1Q29udHJvbGxlZCBieSBDT01PRE8gQ0EgZXhjbHVzaXZl bHkgZm9yIENlcnRDZW50ZXIgQUcxKDAmBgNVBAMTH0NlcnRDZW50ZXIgRW50ZXJw cmlzZSBSU0EgRVYgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCX EofkFhTXr8nq6xdBkQ0iOoMH2pVgUwC7OcLr4A5s8XCgEug9a5KxCLkSfzpvrMKK yD0vxv4NV4y82f3HCUsGlz3Q7VBCQAF+OaI5Vb0QNp3a7dzDkODDFzuULVAHWi3q IvwnCE5Iv5pwuxpLmQBAP4KjLYZuSxQDXSy6WkmnL3+ogDfdPy2iQSjScVzgRiCf NDGEtnYr6Dy8lf13C5qfVRRXq2WsAeplUZaTbRp0khE4M5IR90mf3KkuiRt+vV/T GtiyqyOzCwUSqs0AoKKx2QB2XZaVNdmWYCELjPd5pFrz3PjWBS+MqC0HB3quPbzw VlThFiWy/M/49W3QkyztAgMBAAGjggGNMIIBiTAfBgNVHSMEGDAWgBRTeb9aqitK z1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUevI4uxLmYzZAbyK+q9uy3L8291MwDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsGAQUFBwIB FhlodHRwczovL2Nwcy51c2VydHJ1c3QuY29tMFAGA1UdHwRJMEcwRaBDoEGGP2h0 dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6 Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAl BggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0B AQwFAAOCAgEAdZE/AEpY35sc5dkSlI49p6aNNH1XbsF8YnqiUkw5FWER/eoBwc7L FMaVLMm4W2bqy/G+dNxKczYMWlPmzhg94sAJCxHkxXvQY6Su9io+Po5RyThIFV82 CH8cZdIgT7Un8b95OezaVGYcFNrBAkUQrMDWvG2/IbpphALq45R8UwOVKzATBh7m 6k8tCXNfuOv/um6BwplH/GC8jYpkXmFOnbZjvmL1dgux1H5vQMCvok/c1+LI9Yec qngOo8/QNV6kR8Gcf3wJwAluErxXFuiIH3y0hqvumTHolqAiSOe7/iv/gfcU1/AF l3ZMYbpZUAbvGjkMu8HlTHw9ND/Yf1ooaWdjZ3SykscKbUnOK9ddReKk5GY7S/04 JKWVkMfDJUzRso4GMTdf0wjDZCjZHp0cgISReYS00+uatCJU5FHpQU6SW1u8sJ/s GiP+nmnqnnWwhvZ7roZiloudVl9hKANP8Ll0ze2KupJlI8WCr479uq2NH2iGu/3j HT2JWhKKVtwiSrVbtZO+gkYa1g/RBxBDaRdunrHkVm0XHQsgj+h4gw6Xj1OpCZMJ PC8KE5CVIdpb20rLnFB4PWFbl58O/8na+t6vkgzNXVfQb1lk4CEdlgjDpRknB2MH IsK3/7JSl/3pWBUrp41WhK4g/uN22tn9mukWMWvWK4wuAgQ7D927tUI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwjCCA0igAwIBAgIQZVQgp61GpFI5YQ4bRYdLwTAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgwNzEz MDAwMDAwWhcNMjgwNzEyMjM1OTU5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgT AkNPMQ8wDQYDVQQHEwZEZW52ZXIxGDAWBgNVBAoTD1RydXN0T2NlYW4gTHRkLjEz MDEGA1UECxMqRUNDIERvbWFpbiBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIgLSAy MDE4MScwJQYDVQQDEx5UcnVzdE9jZWFuIFNTTCBDQSAtIEVDQyAtIDIwMTgwWTAT BgcqhkjOPQIBBggqhkjOPQMBBwNCAARF0YSP/w2jEH3ADahYTXzbGIABuPVRGLZG nZ/WuFWUmxsFvu9iTgnNRO5Tq9S/fIzbWSFpKghb7icZguEpH9TGo4IBdTCCAXEw HwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFDiF49YK amxIk2wf+YG2R9vIJJ9lMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/ AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0G CysGAQQBsjEBAgI/MAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8v Y3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhv cml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0 LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYIKwYB BQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaAAw ZQIxAMp8AR2DOFD1xNpOzP56gp+4bGHPA+gcFsvBn2dZxFCfcMVk3lRT3nrRT5iI iL5R2wIwLJsZq6wYKdQB0fO+umtqidZpX8qtREvAJssLg2aW7B0Gs52B3xhW2Dzy rVLsjomt -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGLzCCBBegAwIBAgIRAJBuE8344SrHVZEVqVicPc0wDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MDcxMzAwMDAwMFoXDTI4MDcxMjIzNTk1OVowgaMxCzAJBgNVBAYTAlVTMQswCQYD VQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRgwFgYDVQQKEw9UcnVzdE9jZWFuIEx0 ZC4xMzAxBgNVBAsTKlJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVy IC0gMjAxODEnMCUGA1UEAxMeVHJ1c3RPY2VhbiBTU0wgQ0EgLSBSU0EgLSAyMDE4 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAidnSmDX9ViPaK+aTornY FGuPKFRca4ThtXSCPkJ9gLnyVVCdjdfa7P6azfGv07r8YprWtQZt73A/MqFdT0op BawYVvD4tnVWEMtsjGAU/DXa+qrvnfWm4cNl2FMXV63IoMbHOsAsV9753oLnCnhm EdeD+BqtqucZxoovKA7kv7e9ir8kKv1alxkc5LI5GrjmhOSVXZPa4c26YH5H0ukz dBxDEqkqfFiVfJGqStmyYMyFg0jbgWRrPr8KmogSmvsyIFpEZEAAhP8CDDhNY8oQ Ml8AXig2qW7Kor1yDNc0oDTbzmYRZm7u9pqxaPT+mj2rnQu2bpn/OgSj3f5WUNIp fQIDAQABo4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZssw HQYDVR0OBBYEFCdzNv0y4t66f0o0cMoDQe6gVUo+MA4GA1UdDwEB/wQEAwIBhjAS BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD AjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgI/MAgGBmeBDAECATBQBgNVHR8ESTBH MEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2Vy dGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUF BzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1 c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w DQYJKoZIhvcNAQEMBQADggIBAHBxOFnbGnH0BBoM2neWiPTjxSrDaxQasUsJaWRS /6feXQjyR9uz9sYWh5pIX0AYlNmBGBhEFtRdOaPadjNlR8eFMnehqKK9rZUPr3mX tKXCdeWoycmTqnrZ03RrXIuDBs+RIsMc6dvO+1CIaLGOGxmr2+ibyAXWW7KObtTj ONRt7tZkmwakXxA+2Z6ZFVZxnlb1JyNn6/gYd3Hj8GnfS3c987gWeoc53pa7adEf 1MbEMg5fRudDbqvoVhBbc5UGbD0DmaaFo+o1K8tmqkX0Ythzp/tvvcXABvvSzwAq Pi1v8nS7XIxl7PVzc8e7j0/MTUFzgs5H/y5LrNCbiYlT+t4XWWgQbp4Qffg7QD1M 0baDlssNGbpdPgveeMEIG9FTRvXMamvnt71Z9PzLdMkkaRMO4rnKkocblb65oaQQ gPO+FnT/00lRcOR7/GdPTmuRxc550hf6F2kaOh/LS68CCLoSiuwnrX58/Jln7nb8 it9YX8jVJ4kB7cBZsT4JJkMXg18oKzszDxVEr1qvECNoun2bXB29pDkPvUXrapQt hT1i3CIQ+dmRpPgatlP3HJqKWLJ76OHp/d5+zng+XuGgrFEJ1JpCdH5Pv4VrhyyZ oMcORjMQKebHa2Os+9n9OAlZKfQxgLAjloHQsRVjVK77zP7Kg2GASbTEIkgAZ5LW RLLH -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICuzCCAmGgAwIBAgITBt5lU/RxKhgxLf2itIRtGzb3bjAKBggqhkjOPQQDAjA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g Um9vdCBDQSAzMB4XDTE4MDcxNjIyMDYyN1oXDTI4MDcxNjIyMDYyN1owRjELMAkG A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENBIDNC MQ8wDQYDVQQDEwZBbWF6b24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT54+5s DVFTJ1ViZmj4Q6YZNDtTW9XnMo7GuR23TEgWcUWnqchC1tJ2vUEMJU9SJH3yWWeN p8rxiiEaiURj27/vo4IBOTCCATUwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8B Af8EBAMCAYYwHQYDVR0OBBYEFK5cgP9Cl8nDoJtlCwTOnnF/Ps5aMB8GA1UdIwQY MBaAFKu229cGnjesMIYHkXDHnMQZsXjAMHsGCCsGAQUFBwEBBG8wbTAvBggrBgEF BQcwAYYjaHR0cDovL29jc3Aucm9vdGNhMy5hbWF6b250cnVzdC5jb20wOgYIKwYB BQUHMAKGLmh0dHA6Ly9jcnQucm9vdGNhMy5hbWF6b250cnVzdC5jb20vcm9vdGNh My5jZXIwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC5yb290Y2EzLmFtYXpv bnRydXN0LmNvbS9yb290Y2EzLmNybDARBgNVHSAECjAIMAYGBFUdIAAwCgYIKoZI zj0EAwIDSAAwRQIhALhzrminJQeFNEOGC9JLWzlynT+3uBd6flr+oC+GiB97AiAv 2QsQjxOisNt7+i3DWrPWZ5qKcadzhUIpap5YnGmRcg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE4zCCA8ugAwIBAgIQCZ3/J88vXtVVP0ejU2fCZTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE4MDcxODEyMjgyNVoXDTI4MDcxODEyMjgyNVowgaEx CzAJBgNVBAYTAkdCMRswGQYDVQQKExJUUlVTVENVQkVTIExJTUlURUQxFzAVBggr BgEEAYQHARMJMjIzMDEzNzAxMSMwIQYJKwYBBAGDmCoBExQ5ODQ1MDA1MDVGRTgw Q0QwTkU1ODEbMBkGA1UECxMSd3d3LnRydXN0Y3ViZXMuY29tMRowGAYDVQQDExFU cnVzdEN1YmVzIElDQSBHMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AJwT8sRVYG+nfQu0L+PyeFR5hYJP28CLNBQzVyrPPzHnKRtiNAxRjf+Ejs8cAviS 74gCMjpH2svXsxcF9L1DOO8iMfP7LgsfXUpfxig6UQZsCLx0sW2xvSCqny5WO76L nZQ3vLeS89B68InDkMffxw3M1b7EUwE1/ZPn7pk+IVY6bSgGeAlszRSkXwqCG/0/ k2H2i2Gc89VmXEU5hE/HxkiEIVzQ1RFD4WGtExrYuNSeu38uQ4yjBHI2opGcCOE1 Jj/hQ5cmPLo+g2xqi6r0wLP2UZuB9CC1B3uIDrTMTnw4abWVN0dnTVmhNg/MZOuF qmjAMwmAEEXTVJbIPNb8A9MCAwEAAaOCAUkwggFFMB0GA1UdDgQWBBRgiIt5mXuz s2oO+9fvHVzSWwwymTAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAO BgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIG A1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhho dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDov L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENB LmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93 d3cuZGlnaWNlcnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAY0JcIPKhW5ag to8ztFVeKFkuZE1Ap7c+rNL0jEB7LLOU9LO5L8kBOHCgWdhhs4j3Q9cY4KWDpg6M 0Cqt63+KfOEImWUtJrwE13ErBxpP4tf/QPRKq+LLW5TLN19G5Ccj/wd9pLQge95O W5YFlT+wnwP7/8fCvkUr+K9WStDetNQomDJCFdgZ/0lMNff54KDOHsWe8REv0CSt zT7e69f7OfuJCGFb0MkRPnaXOsZ9AiY9cf3yBodqh5YwmktHjRinGNM6MP/9+GI0 Ib7t9hhNbPNISGF1bW+LoJgu7kr+bckOruzkzqNtngjcZJZMsJOnIviRO59qYlHz nuImxzQJdQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpTCCA42gAwIBAgIJIrmxTch2GE4MMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTgwNzMx MDU0NjEyWhcNMjgwNzMxMDU0NjEyWjBbMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjElMCMGA1UEAxMcU0VDT00gUGFz c3BvcnQgZm9yIFdlYiBNSCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAJIsszOU98kNAabsm7SzAmC90Q1KrbaVVR2WDR51sfC0rNU7xlUgqdJVZH9x 08j/ofCastt8/5zPsy73ysZz/L67nEAZXS0W0Ee60vvmPzsfM1qSGgygCr8qZDs9 BxsPcSCA4mMUtmrhXhX0fDlkwqCHUg/3qgImW18+9r6FclGky0rw00/OhiLyPHOz 9ezErDaRCOc/tajvsgtdFg/np+AguMKzKGlfQ7oTg4ETShBPcM6m1KegCpfQ4UdL T5/c6S9PlvZuAPXTmk7SwpsfuCJvVjTLty/YzXP20jGgjMHuuSeuqMzHy/AdwCXp C/sKWBvN7ygELzJaFpUwokECXAkCAwEAAaOCAWgwggFkMB0GA1UdDgQWBBQzlf2x cvHmUDItWVL7p1rxBQHJCjAfBgNVHSMEGDAWgBQKhal3ZQWYfECB+A+XLDjxCuw8 zzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjBJBgNVHR8EQjBA MD6gPKA6hjhodHRwOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290 Mi9TQ1Jvb3QyQ1JMLmNybDBSBgNVHSAESzBJMEcGCiqDCIybG2SHBQQwOTA3Bggr BgEFBQcCARYraHR0cHM6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJv b3QyLzBABggrBgEFBQcBAQQ0MDIwMAYIKwYBBQUHMAGGJGh0dHA6Ly9zY3Jvb3Rj YTIub2NzcC5zZWNvbXRydXN0Lm5ldDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB BQUHAwIwDQYJKoZIhvcNAQELBQADggEBAL+dAKKSk/1VSLHXMOOujq/OeyaC5Fod pnszydO+GJ3rxfzAKcUuNo9aOZRYf6kxEDnlnPtkpdvT66CM8On73uj/5HQw9Cwh rZUKjbn3bgf9qIHY7mijTUBDK2FawhdYX4QWI3wryYKGCw0PmMtpQ6w8P3dexnRn 3pkV+1QgE87yfEqbzLzfQIrl4bDAOVeKyuUgruffSHqgEyMFHUCA+iTw16A4O9dp QUXSq4B5It9NlEJ764VoRovD6ujmyyfNlSG5YPpI1TFEbSZMwIOE3diZik7DWaUP HUYpj+c/7LggHA5pK915Yw4td48n3FHAunCqlwTWc9aRol1FXGBqN/8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpzCCBEygAwIBAgINALfzPrd462McvnyACjAKBggqhkjOPQQDAjBxMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MR4wHAYDVQQDDBVlLVN6aWdubyBS b290IENBIDIwMTcwHhcNMTgwNzMxMDkwMDAwWhcNNDIwODIyMDkwMDAwWjB6MQsw CQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2Vj IEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MScwJQYDVQQDDB5lLVN6aWdu byBRdWFsaWZpZWQgVExTIENBIDIwMTgwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC AASgco960wV76MEdWtug1L/YHhkrZqorU/aHRUrHy/bW+MwlYCE+SiUk3KK6r/V/ YAwMz+zqGOLeq1iB9osx34aso4ICvjCCArowDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAQYwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0 dHA6Ly9jcC5lLXN6aWduby5odS9hY3BzMB0GA1UdDgQWBBTZjRi4rCO2O4wXyetu uRcAaQ2gjDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDCBtgYDVR0f BIGuMIGrMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1jcmwxLmUtc3ppZ25vLmh1 L3Jvb3RjYTIwMTcuY3JsMDegNaAzhjFodHRwOi8vcm9vdGNhMjAxNy1jcmwyLmUt c3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3JsMDegNaAzhjFodHRwOi8vcm9vdGNhMjAx Ny1jcmwzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3JsMIIBXwYIKwYBBQUHAQEE ggFRMIIBTTAvBggrBgEFBQcwAYYjaHR0cDovL3Jvb3RjYTIwMTctb2NzcDEuZS1z emlnbm8uaHUwLwYIKwYBBQUHMAGGI2h0dHA6Ly9yb290Y2EyMDE3LW9jc3AyLmUt c3ppZ25vLmh1MC8GCCsGAQUFBzABhiNodHRwOi8vcm9vdGNhMjAxNy1vY3NwMy5l LXN6aWduby5odTA8BggrBgEFBQcwAoYwaHR0cDovL3Jvb3RjYTIwMTctY2ExLmUt c3ppZ25vLmh1L3Jvb3RjYTIwMTcuY3J0MDwGCCsGAQUFBzAChjBodHRwOi8vcm9v dGNhMjAxNy1jYTIuZS1zemlnbm8uaHUvcm9vdGNhMjAxNy5jcnQwPAYIKwYBBQUH MAKGMGh0dHA6Ly9yb290Y2EyMDE3LWNhMy5lLXN6aWduby5odS9yb290Y2EyMDE3 LmNydDAKBggqhkjOPQQDAgNJADBGAiEAj8YMiPO+G04YDF/K4z0t6b+lZDH9kgBw JF5TWvQZoagCIQCy1mnuRaH3DnZw7SjejdGQKCIRuWB6o0gC8aPza8yhsg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGRDCCBSygAwIBAgINALhu3yfY9pZ8ZHBjCjANBgkqhkiG9w0BAQsFADCBgjEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMScwJQYDVQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkx HzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMTgwNzMxMDkwMDAw WhcNMjkxMjI5MDkwMDAwWjB6MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBl c3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0 NDk3MScwJQYDVQQDDB5RdWFsaWZpZWQgZS1Temlnbm8gVExTIENBIDIwMTgwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCUqWys07LtoLYGPI2CaftcqV04 RnOKO/0VvI3xTidTpedvmwhk827c/Gks68y6ncC9chZGmvgN6G9lnD663kovauXC Y69+xHfTskdt5xUQDyKKBjIztZNwdWKM9sJZE6UDgrIjHrLJ11FQs1dK9XhrtHIQ O+XSOat8DYcXwAgpTqkpTe3RUDVQT7z+PleqJRe8tr6YCYuOiq4ZN2PTpd3LxB/B 25LZkYfB1aK7aHv/aXbo6mxR6+wr052a608IRnfHfY5lPV0GEDfCHtoY7Nk7nkb7 d8LKyBcFqAJ18EKjYDJHYhn9lVa/huF1ZwoQomwi+3XeHySmUjzbO1HVW9VPAgMB AAGjggK+MIICujAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA7BgNV HSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL2NwLmUtc3ppZ25v Lmh1L2FjcHMwHQYDVR0OBBYEFH2ETsLUa+rB1yKMaMPpoPTsmIocMB8GA1UdIwQY MBaAFMsPxt9CQ8w9y7VII6EaeqYquzRoMIG2BgNVHR8Ega4wgaswN6A1oDOGMWh0 dHA6Ly9yb290Y2EyMDA5LWNybDEuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcmww N6A1oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNybDIuZS1zemlnbm8uaHUvcm9vdGNh MjAwOS5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNybDMuZS1zemlnbm8u aHUvcm9vdGNhMjAwOS5jcmwwggFfBggrBgEFBQcBAQSCAVEwggFNMC8GCCsGAQUF BzABhiNodHRwOi8vcm9vdGNhMjAwOS1vY3NwMS5lLXN6aWduby5odTAvBggrBgEF BQcwAYYjaHR0cDovL3Jvb3RjYTIwMDktb2NzcDIuZS1zemlnbm8uaHUwLwYIKwYB BQUHMAGGI2h0dHA6Ly9yb290Y2EyMDA5LW9jc3AzLmUtc3ppZ25vLmh1MDwGCCsG AQUFBzAChjBodHRwOi8vcm9vdGNhMjAwOS1jYTEuZS1zemlnbm8uaHUvcm9vdGNh MjAwOS5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2EyMDA5LWNhMi5lLXN6 aWduby5odS9yb290Y2EyMDA5LmNydDA8BggrBgEFBQcwAoYwaHR0cDovL3Jvb3Rj YTIwMDktY2EzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3J0MA0GCSqGSIb3DQEB CwUAA4IBAQB/UW04hmlTDGlMwETB/pdfSi6eFSvWtDxBd5LsS+5cR17yT9u5Iqxg 37Ov5SWS2gaJP+JQ2Llgpz3YbYnJYexiFTsWhPEmUQR3YoQfIJ6tYmmMK1EE2bJE fWmXMJDps3h4o2IAKsIsV5NjjTYdVtg6tAoxdKUEMJj7y1K4Z/DoMONz/Xd1Lmf1 clzWuce4vzA+5VxdpWJsupDUfOS0uuvUjoZxrYXMIiSarYzn51XU0kM+kf/+cNu1 E0NKnqshwv10EWG5IKFRsq0LYWjogihvzFlAmXftt3G12gXFAwndw2Hed8HXBfUj 8WjjEBCliiD/N9P40C9JEZovvAkkL07h -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGYjCCBEqgAwIBAgINAe5fFX7QOMo4XX885zANBgkqhkiG9w0BAQwFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFs U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODA4MTUwMDAwMDBaFw0zNDEy MTAwMDAwMDBaMGQxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52 LXNhMTowOAYDVQQDEzFHbG9iYWxTaWduIFBhcnRuZXJzIFRpbWVzdGFtcGluZyBD QSAtIFNIQTM4NCAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA nRPORkMYMKQxrfuvQUxlS1fpIZmTBTleITuxN1AjGldNqNC4+oYMPlLvyedsdSYE rJRW65BBg5hS6nUxbMg2RppbsjVoKgLQBB7glZB6ap9dA/MvQou3QuivzsWSE2ob UZ8mMPtJCQIQ21KAf5CpDXJjzmpCndmN3aqF8w6cBdcoCbS2ImZ27L/q3Ute7Qo2 QN8H+H75tvWTDdduvvfh4EErNh80ne5aCak9iePrweyruIg6pnzztSJondLFG+rg 7vfqeSwfqU75CBfKJuCCfg06LJupR3YT64ReldjuZsTBWoX0dVI+WRIr/3+j3ILn WsBJmh6Z5k+yAvlUMvnTjgJixhnScF0Kr1UlqlAOICq3iww3ftF81WKEeuo9j53G kgujK4hfAjB3CvDO5aLnBj9GWrk34xcivHCkggkLF8NWGhVSYg7t4Zs+I8q5l1VU Xk24uI5tUi/IzmDOteKxMQ9J4c2xdBgpcf3pR4MtDdIsUNoZlhaziVOwg6u0MlQQ dkClKiByV3y5waeR/kk6SpftEfStF1EFziEOyldrcckGMOzVDszOmz8UeECS67Ex JLuo018y7cajwBxxlR/PqCBgBjniDgvdjTrWfODmKob7hB4chV/oLM15z8Bsuz/k cZUSz9wnRpEoU16cI064Cv7ZaGi5AhcQlh/6leJIJfkCAwEAAaOCASkwggElMA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQjBGRa Jiu4UrUuU+/pWqqE2VGNfDAfBgNVHSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdT oDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwMi5nbG9i YWxzaWduLmNvbS9yb290cjYwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n bG9iYWxzaWduLmNvbS9yb290LXI2LmNybDBHBgNVHSAEQDA+MDwGBFUdIAAwNDAy BggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9y eS8wDQYJKoZIhvcNAQEMBQADggIBAAELAF7YtduG385+UdZ/iGvxOUMzVJg1D6Is jJxYC1vV3PBfuiMM/M+HE/vBCnRUZgtl5u6cG4O1tDFsEfG2Mgwrypn+9KTqsEPQ Hqq3rBH2I0WCsvzQ3T+fZ1ugrQXpc/pW6IFvJHo+dXYNUGxNCPKUth+1+i0VNB33 CNTxwAQ/UvsRlAeC78hN3MHFUz4iI/VCNFany+jTvLIZhLRcy3HPLrITqX8rzZHS xHUATXNcdHbWZfDBxi5qAD32r/lIYMH1Tmg6YtT7CWqd003guT2stbB0Dx6+ctqD eDyeCmihL0B5wzf6Wy/HXPzbd8eGiuHuF9h8XKO8j8eB5Mck9fppE1U/i+XNvDcH wfN3RdEhuFKZcfUIQTNvmid+SyJ+Z/YX1PF1EIIgD7/zPe9vlIlzIL0a3nIaR0N0 ISsZtrRlH2HM0/791zivlORcV1027QLK+LA0aU/FtP7C1J9wcfBr4F9cT8NH8O5B RwvCrQl8WhPDMegdlU8WbCn8FnWRvIhBQ9ciUk5MYGAU7QgP+FMBWFacNBn6velK 7cmQg7ADPU2pVaUQCfPRyiMTUW9LNUkXP9+d95gGZR/7M9oS2Px9vEla/DhrnfOP 9WKZX/Wi2f8zrwy7sGR9bO0ZLbHV1BM79uIYpM5v7lbTdDiiGIdl+DuZlYXxZRn1 ZnFC8qPK -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFsjCCA5qgAwIBAgINAe5fFZoAV4HO31tqWTANBgkqhkiG9w0BAQwFADBXMQsw CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEtMCsGA1UEAxMk R2xvYmFsU2lnbiBDQSBmb3IgQUFUTCAtIFNIQTM4NCAtIEc0MB4XDTE4MDgxNTAw MDAwMFoXDTM0MTIxMDAwMDAwMFowVjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEds b2JhbFNpZ24gbnYtc2ExLDAqBgNVBAMTI0dsb2JhbFNpZ24gUGFydG5lcnMgVFNB IENBIGZvciBBQVRMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvlHr iXRbo0LWNFAjiugjNyrlj/8F6/GFAIlmEBEKhNjUZ5vNkaJAExkRQnXRTFHpg8AT 19qmo0r8OYInLEyZhJ4qw2q18vz9BaPzzzaApnGIWn8jWN5ZoYhoNcOoLv/bRh2p d3hRix7xJ8FaQylGThhLEJ7wk8BKCc6uBLm3yz3RnNEE/CRhJxDGS54Kr0jugZJg qBVa/URiGEJauVcCI68XQec+XLNijKHlLmsyV0lcqP7BrF6VjQETUZv8/ShFqnKp 1Vf2qh8TrIKl4R8yIZU+UxhOQ5p+MzVcsQrMuFkt5XIpvYUBg1Jn1awgVB9PKqUR lx5mKyIOAU2CS7Vn+wIDAQABo4IBfDCCAXgwDgYDVR0PAQH/BAQDAgGGMBIGA1Ud EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJhLGDath1jpHbl5kJrVYL212cQsMB8G A1UdIwQYMBaAFInvdXF6X0cblyPckErL/8AmNgjVMIGIBggrBgEFBQcBAQR8MHow NgYIKwYBBQUHMAGGKmh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29tL2NhL2dzYWF0 bHNoYTJnNDBABggrBgEFBQcwAoY0aHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNv bS9jYWNlcnQvZ3NhYXRsc2hhMmc0LmNydDA+BgNVHR8ENzA1MDOgMaAvhi1odHRw Oi8vY3JsLmdsb2JhbHNpZ24uY29tL2NhL2dzYWF0bHNoYTJnNC5jcmwwRwYDVR0g BEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNp Z24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBDAUAA4ICAQAy8aLPppq7r8YC 3EaY/dtgz5u+PTWHzgSKUwsuMHsR6dHOqlbPTE/7HRzEgCx54r565Wod+YNLZF+U EA0/IEuKBZOCpSG55m+AVmDKlwRiBRKMef1SWgH3ab0c07fSGsQCgrMoPbb6aeAR MAmknIZZuYD8vhsYSPaoIFxhzqVAf5/xMIgUtJJuUWbaoimVWzZ7ZzromAJZQHll WywWwd7jxP9Xn8t0C88xfywZtD3kqIlwkjW0PdVgv/cl/ctBV8yS2ERuWNYonwBH fqxmRKEEfzTns9LivbZ3MtKHL+XyQbbT/FZ8yt72cwOdXhWi3ZqLSSv0cgiPabpa 04cdRY0ZafM2EVFOEQ50jZcadCeVYXBrSUb0ysNM80/IUJubpoHgxDJwGnYw4ELD vxyTJ64ggMeM/TFF611/tZlu9IYuR8Y+2hHYIyeuGOqdY51cw2AF6HafPPzxQ2ma MtFZ83dONYSgshxUmajg0WgP/wKTgPmbfqOgf0h6A5gvnroBkZNdmn74S+bMN710 +wC7PgzILlPjkdtM8MlmH3kfisrN18crnej4E8cvUyq2T168hrZmsLti2s0+krC8 YweAUSnFfjjy0jEpydDJkGFZ3lp4+AiCvMYhJcum5HElbWA9GgbNYOxJLZN28qtR 0hiOIuuXRkrf6btJCBiHJABGxWXLyQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEujCCA6KgAwIBAgIQEB1CIlXh/kGGZmDEgBd2ETANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE4MDgyMjA3 MDk1MloXDTI3MDUwMjA3MDk1MlowXTELMAkGA1UEBhMCVVkxFDASBgNVBAoMC0Fi aXRhYiBTLkEuMRIwEAYDVQQLDAlJRGRpZ2l0YWwxJDAiBgNVBAMMG0FiaXRhYiBT U0wgRG9tYWluIFZhbGlkYXRlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMPvaTRvcO1CAI0wFpjXVwe4nox1aeI0jU6KIzA/nHeqAdYPxB6ta+F0On1y taiptSMvPMXXOqC8bfvW1tOvJ5jsQ0xRr95vzCXopMzvxbXsaK309BOM65FEPH92 f7SxNXItf+/RFy2CJCPPVeYLtf/Vuq0VA4yAWaX0ppjI6iJ7M0Ohfp5jJDASkdgJ cQAAwBO5DNQpFsgAum58CFnqjneo4LYKdcRmX5vtqcYFvIjx1DOGjvgGpUqO3s7K p93N3jKgKQx/qQbTrcoXpuG5b6+3tHzGQc/CadmJI7i3jPgA7uKzyLT5wR3/A61O 8umCGY/lqfYDfDaqz58p+PZQXDMCAwEAAaOCAU0wggFJMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFG9AQhsv6QZraCJLC1KBNEodjrN2MB8GA1UdIwQYMBaA FFSZ3Zv/6KcOoxmdW75CV98w/I8yMA4GA1UdDwEB/wQEAwIBBjA4BgNVHR8EMTAv MC2gK6AphidodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9nc2Nhc2hhMi5jcmww bgYIKwYBBQUHAQEEYjBgMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1j ZXJ0dW0uY29tMDQGCCsGAQUFBzAChihodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0u cGwvZ3NjYXNoYTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIB FhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAIiV b6WfzIFb8MHGajFP1cSxSZVqcA9t2pgKxGUgRolu8vfanxOLsSJPKSfM+cIzSLv/ GS3KDUVxjURP3tUQGpx5WbUIboN08F8VYw/6cmmjxmuZyKihYAv83LwGCS9CDfZ4 mC4+PnoY8sYrUjxn1vZRSSZRrUO+2s33BGuLiYiXnULWeM3J8OCEOVNjvPy3yJbr ARp2lKHshD/T0RqlHAh904RF4+V8wF23igJEGL9rxviOIqQbSaaibmU026Ie9CHK fEakGKhu2VaL/ezUTI2eJYtuz+ZtIQY+wqISkGfcJ5mdXSR/9omIK89eo+vqPWqT awustbKQ2UaxlYhsG1I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEwTCCA6mgAwIBAgIRAPDVlBXG3stPiI8oN+YGgQ8wDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xODA4MjIw NzEwNTlaFw0yNzA1MDIwNzEwNTlaMGMxCzAJBgNVBAYTAlVZMRQwEgYDVQQKDAtB Yml0YWIgUy5BLjESMBAGA1UECwwJSURkaWdpdGFsMSowKAYDVQQDDCFBYml0YWIg U1NMIE9yZ2FuaXphdGlvbiBWYWxpZGF0ZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDRHpKZ1x9MN92GPEzBHOreEaFKQ970cb0DwzwZ9BIFvL39UnNp CA88BKRI7xUsOso3IiNrikyYvXOdW8VOlYn4nR819ocdmFlDi4fsTUXhPy957jb7 m5HK+AQI5V0G+VQE3Z1KbuUJD5NCpAsWB9917LIQ5+n296wZrGxvKDaJZftxNgBM UYlAWNnc88R/jFNVcKY3y4VJCEzLMx68K9p1fbV4mpCafXvEgzWzQlpW3/xkBicg DwoFoL/fkUq89q3kLfJy9IoJJdfD7DtZ+NTe/sOLU64xpyqIkmH/F7zBuGQZ76TQ rpCI0EWUOKzAk4RJINBE6xjLhdYS/XKTTiYZAgMBAAGjggFNMIIBSTASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBSGC3U4ncuDuHEGDR9d6I7U6J6QZjAfBgNV HSMEGDAWgBRUmd2b/+inDqMZnVu+QlffMPyPMjAOBgNVHQ8BAf8EBAMCAQYwOAYD VR0fBDEwLzAtoCugKYYnaHR0cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwvZ3NjYXNo YTIuY3JsMG4GCCsGAQUFBwEBBGIwYDAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNh Lm9jc3AtY2VydHVtLmNvbTA0BggrBgEFBQcwAoYoaHR0cDovL3JlcG9zaXRvcnku Y2VydHVtLnBsL2dzY2FzaGEyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggr BgEFBQcCARYYaHR0cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBCwUA A4IBAQAiBThwLiKG2RvYPpph0ftYNFf7SaoVQJKWTmYGP7NkGpevtWQS9QkYKPtd HAm9cPzKA/Las/WrwXin3zXzUUGuPttSSxCI4D9sRTX2RHAUSRBLrFXV/BCjtjlS ehODXP2CXJsQtQ6SNvDaz4w8iSnrKhJyLgCIW/Q/u6dfkktQxEq+FJ4fWRC+Z8DY 1llk6g6FWBMuLVclLnUzQ0BplhJKUBLA7pd86VsJZStGWcRtW9iaMwsn4QnnLZ0B h2wLKEzze5KwoLPuY2tm0SHWubPO11HJhoMJ6k+QgJG1XObTBLofuJC1/NpHy72z xrAnpFWbSDnEYkhrXDMGxTSDdkAv -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIQY+mzeg/qciMUhLZ+7Uup4zANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE4MDgyMjA3 MTIyNVoXDTI3MDUwMjA3MTIyNVowYDELMAkGA1UEBhMCVVkxFDASBgNVBAoMC0Fi aXRhYiBTLkEuMRIwEAYDVQQLDAlJRGRpZ2l0YWwxJzAlBgNVBAMMHkFiaXRhYiBT U0wgRXh0ZW5kZWQgVmFsaWRhdGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAJ7LhlpxF66KMydnGdMzf+5JKuPwBiVzliKPg0zb0DUz/gokUVuLsbV7 wMqXn24X0k/ChTbTM0R4R0Qlsnbb8amWu3M/USA7bK1sng8i7BBkQbp1lrbWoF+e rNCdCsD2Kfo7eD+kLlrHrL6lHG2CtM5tpJOMH6UNS/Qp2R4XfV1v/OIDlErWEE4t eS3rPsNyK/AfCCwBRmL2paLfuauN3l/XFrJ1rRJEejAochTxG+mX0C8NemuJtBrx mCRUFu96A1hUgt3YUWVVJjN9Qh8jAZjWNVwqMgKjcZxKaGwC7FW/Kn/Jph9VESU/ RSiR/6zZPWuPEENIqrcCSk39yG9rJiMCAwEAAaOCAU0wggFJMBIGA1UdEwEB/wQI MAYBAf8CAQAwHQYDVR0OBBYEFIQcE3cNNuj3bDovlgysxnc9Rqr1MB8GA1UdIwQY MBaAFFSZ3Zv/6KcOoxmdW75CV98w/I8yMA4GA1UdDwEB/wQEAwIBBjA4BgNVHR8E MTAvMC2gK6AphidodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9nc2Nhc2hhMi5j cmwwbgYIKwYBBQUHAQEEYjBgMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2Nz cC1jZXJ0dW0uY29tMDQGCCsGAQUFBzAChihodHRwOi8vcmVwb3NpdG9yeS5jZXJ0 dW0ucGwvZ3NjYXNoYTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUF BwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEB ADOPoWjWG45dMNUmyTBKo1418MvWWrD8saQlvsm8a157bmM7QRr6sjMzj28Y8aZK QhV2m1Hb/izXHACMX0DrnQv1eOFwvqkIcQvzC61JnUnGCsaFTnhnXA3YbYjsxOFV msfYPU5m+LybFZ7GPjnImwttUXiH9uPU8b8rij/6/6Sc1wM5636pPBTmBlmsZejD dIqlq0TL71elOpYbMHqPGDKvQe+o8KzFnY6Z1psv+2fkbiQJxYycSomlkIgyW9Zh SLBMeGtHlijSgsRS2/96GrZFVcN+e4bLGvzF50Mqp1Xy6i5xT1GnQgrWKiJQFFqB 4G6Ru3+xjtUSTyxlj5ZfIWE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE4TCCA8mgAwIBAgIRANjwLnAC4vU/pTnqJTomTTowDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xODA4MjIw NzE0NDlaFw0yNzA1MDIwNzE0NDlaMIGCMQswCQYDVQQGEwJDTjE2MDQGA1UECgwt U3V6aG91IFFpZHVvIEluZm9ybWF0aW9uIFRlY2hub2xvZ3kgQ28uLCBMdGQuMR0w GwYDVQQLDBREb21haW4gVmFsaWRhdGVkIFNTTDEcMBoGA1UEAwwTUUlEVU9DQSAy MDE4IERWIFNTTDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALBdxP6T UFfTpcvNj4oFAq4dF9rd/oduB+9HCmCyc9VjhtcGyWFddp9E7IwYmz+UzEWPk6lX EnWr5QHuDN9lSv9N6esgbCJaNrw9hWaUEi55KEvYN3yon+2wl0g4LP/69oJnM+5B sYHhGN51W2OjDKLKxVPug2uORlKvWARLNCm7nil4P5A283yeC/6jkmMUqu860wSI 5LU0YfOl7/ttI1/3VJNDVo/3gWkbKIC+ans/5TuKlcxxDEVA1kdAWGLSBaOKX/Zx COmCApL2HqnyZW6a4AfhF7FD8RL35dp7ZHNut4CqsO3Henz+U8lImrSGFRHXtuXH GusZQAUUrPkyix8CAwEAAaOCAU0wggFJMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD VR0OBBYEFCCjCDKu14YS+PPGPxPHaW3QiHHdMB8GA1UdIwQYMBaAFFSZ3Zv/6KcO oxmdW75CV98w/I8yMA4GA1UdDwEB/wQEAwIBBjA4BgNVHR8EMTAvMC2gK6Aphido dHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9nc2Nhc2hhMi5jcmwwbgYIKwYBBQUH AQEEYjBgMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0uY29t MDQGCCsGAQUFBzAChihodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvZ3NjYXNo YTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRwOi8v d3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAB24//HgOg1NOxFU VoxnGgoV6Hglt0uCqBhlbV0XdF55UhhGnM08MJrosBTVovtBizvf98EoM2O5hMf5 tdAa+w2GwPgpTSEU1frpW0IMxjQH7MDzpxOzO8LbCI73rS6duUKXASLE6iraHLe5 TFP9Yj+mohgmfNnR5lj0U2yxXXL828J9+yft3Z5GkxIjkgg78dYnZ5BHeu139Iew g8y2P74f8fNIZ7X+CdnZ4idzyewTHAwmZaAeSE3dAaqCk1GFmMrXjzzFxREMwCH/ r1dguJCNZZyyQyvGBWGBAue10zqu48hbaG2j9YesAO4NfYTKtu4bp/Qto0zD2HKw //ey/1g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqTCCA5GgAwIBAgIJIrmxUe1MoejaMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTgwODIy MDcxNTIxWhcNMjgwODIyMDcxNTIxWjBpMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEzMDEGA1UEAxMqRUlOUy9QS0kg UHVibGljIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFY0MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAtwiU6mdmwMgBSjTPa4DqspEnnSWMk7Z6Iel7vX9Y Y4X6xMhO8WvK4EJ7dM3Gm06sbVCpfk9qVub7Wgl/oD/ABEDdbV3ehJTYYjiSImgx yQh4f53cYf2sHgGrf/Gj7O6G6Hndj97KmXVXtzBkJ+WH/wvDx+yy6WVtdINzKUM+ QEzJywzS1XCG28s80MnUvLlVDdfFpkH338zCG0A481gUHbKXZ6sRZHdUGz6YbEPv xbdpClwF3QXSdh3Yrn4v8MmgJtT+mWsYugbynnIn3Ohc74AS3WZ39R/LPdnqHKJM T1n6EEz7ZOMa+SOHhPprAasDDkOrKjtd2dHQ2WSZI2BufwIDAQABo4IBXjCCAVow HQYDVR0OBBYEFApC5rY0uS27/uC5lO0WaoIdPAwsMB8GA1UdIwQYMBaAFAqFqXdl BZh8QIH4D5csOPEK7DzPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQD AgEGMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1 c3QubmV0L1NDLVJvb3QyL1NDUm9vdDJDUkwuY3JsMFIGA1UdIARLMEkwRwYKKoMI jJsbZIcFBDA5MDcGCCsGAQUFBwIBFitodHRwczovL3JlcG9zaXRvcnkuc2Vjb210 cnVzdC5uZXQvU0MtUm9vdDIvMEAGCCsGAQUFBwEBBDQwMjAwBggrBgEFBQcwAYYk aHR0cDovL3Njcm9vdGNhMi5vY3NwLnNlY29tdHJ1c3QubmV0MBMGA1UdJQQMMAoG CCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4IBAQAEjMcjf1u191u4rO5rr/3KHLob OsHpfVzO0ALIqV/sX+KsS4/8ZyUqq0pVmTpnj5Pqcz4ffYD52o0WrPx5+THrilH8 TTeAitQx0uykr3QoUNmvXlz1ofCO3RckarY2MshWp5uzvR5oeIR7SPlHwRS+DDwt EmU1ldSQDPU+Ov0oxDeImiBV2yhnYIPLe1cipYV7aQsPiGaK5W0JoZ9+Xoi9aT3N YCCESN6KimTchBrJoX2O1QxXVonHXbYIbJEt+Yae5glvdjxAKH9lsgqNkvDwKy2S 82PfEtv/CSR4a84Nou2SmhrNcdQ/1H2893tObrj9LDPSy1lVvcC1v2gatdmZ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkDCCA3igAwIBAgIJIrmxUmQ7WLARMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTgwODIy MDcyMzU4WhcNMjgwODIyMDcyMzU4WjBQMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEaMBgGA1UEAxMRQ3Jvc3NUcnVz dCBPViBDQTUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLj3JGKsEc IyXJOjS5vsxijuumvhBvV8OVI11PWkfIbE1RStIT3IF1ZGJvuvyzgjPe2wJoPYy+ NlBAjdOnGDNl3pSJDrmIn1H/TqF/Zl3bYBt52/uDgHyCFqHzuZ+gJeRZHuJu8+R3 LcFjy/daPVf/BJgJN8F1di3EcP9+BVpqY9t+HfblLtpRUotjrSrJ3CaYreoGeRuB zYSWMS0MO/L7k6X0whOGOpkp8VuoGpZEB9tmAMoBEP8q7fcJUj5hsqw3IqT6NBmB JMp63lvJlc7h5NS6Fpc7eNHh7Z46RUOYmptb482Z3uknsM8wI2EMM6hyXzzBMvyv +/xJ7l+UQ26pAgMBAAGjggFeMIIBWjAdBgNVHQ4EFgQUJLe0QdQyT8QZ/15iZDte aSdhF9wwHwYDVR0jBBgwFoAUCoWpd2UFmHxAgfgPlyw48QrsPM8wEgYDVR0TAQH/ BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwSQYDVR0fBEIwQDA+oDygOoY4aHR0 cDovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0MtUm9vdDIvU0NSb290MkNS TC5jcmwwUgYDVR0gBEswSTBHBgoqgwiMmxtkhwUEMDkwNwYIKwYBBQUHAgEWK2h0 dHBzOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290Mi8wQAYIKwYB BQUHAQEENDAyMDAGCCsGAQUFBzABhiRodHRwOi8vc2Nyb290Y2EyLm9jc3Auc2Vj b210cnVzdC5uZXQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQAD ggEBAE7HMS+njC2n8MTA3yWz/UE45GSVE6s9Wbdcse9Ksp64bCUYISTcryUgK4nI 8UXwHKAU1QtvTI57/f83L4KkkkM0ag2PKJDiM/v9BwYwaRf1AnLLMUcwUpdnszk9 lMfXSRZEeOg4/ZDOjLESbACa5fpdbQ/D6XOVwyCcY5w+3sBw0ajzjom8jLJglluI eqxkHgkeWuLAYKV71xKwQ401XnmJrEutby46DgD6Q1nXtsdSyjmUq2wpCe63bACl iA3HpoHm36ClGklNM5Ydw245VUtu0jRnfQGsTukx2claA9I6uRT+uvm0trjyGWMm FLyxMOGHsLklZeTTCwSXiygKujQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkDCCA3igAwIBAgIJIrmxUyPlrv3NMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTgwODIy MDczMjI0WhcNMjgwODIyMDczMjI0WjBQMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEaMBgGA1UEAxMRQ3Jvc3NUcnVz dCBEViBDQTUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCnTNi5Kgrt FL8qBuEmpL2gvLFY7f9MEgjzClvic/45ebM+DxZ2CMuqtMtImgf8XPIpLaFFbozx 3VgqH41cmGHbpAoDRKpwfF1f53peHYhRxpOVgcnsiVCPZJPBPCUM9St+cuEjfo0d YGbr3aG5urdT2zeKIFyxKbggdkU0LVRHwvLFsIpXCn/YK/8Rmx87yW9VB80OXkzf IQoZop83+aebq1VwzjNCN3u4bWSFLYDyJGqE40WlZ53NZh+TwBsa6gld9YXPGQfx k8x38zkFXberlMQOYhX9KyuTOMdlFkbx6LfIUqVKJavpcr54+XPzVyeroNPpKxtZ mEqUYiFjAqUVAgMBAAGjggFeMIIBWjAdBgNVHQ4EFgQUT4twz6lAHJbllF13rNZv TS2b8ncwHwYDVR0jBBgwFoAUCoWpd2UFmHxAgfgPlyw48QrsPM8wEgYDVR0TAQH/ BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwSQYDVR0fBEIwQDA+oDygOoY4aHR0 cDovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0MtUm9vdDIvU0NSb290MkNS TC5jcmwwUgYDVR0gBEswSTBHBgoqgwiMmxtkhwUEMDkwNwYIKwYBBQUHAgEWK2h0 dHBzOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290Mi8wQAYIKwYB BQUHAQEENDAyMDAGCCsGAQUFBzABhiRodHRwOi8vc2Nyb290Y2EyLm9jc3Auc2Vj b210cnVzdC5uZXQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQAD ggEBABEDSrrhhR+Js5q45yih2Ne4cMLZmrH0AZwU3eM+7HZplzi1EhppgvcYk/2k LM9haQGWnAZ5wiixLqKu7WlWrHgblZbXyCxALmMBK1rqeP0omxXExqKVqWNHU8KZ t3jahH1wDYSzfetM7guWR+PAPpb9oQCtAx8DVyI/3Ocswvti/uWb517Bdo6Nd0+9 mf0LiphNKcSzSFX0s1Cb47cJROYHGBe2J6NUSWR7wE0asPtKsznGyNO+NJCUR+0h OLN2cA2KJwPhZjYJt8UkucAF/EE7qC0Fc8B9Q/gttQ52en5BZxdkDrHCi4qnsSvi gueQme/RzYkEaQlNT1WCZ9AIgVE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpzCCA4+gAwIBAgIJIrmxVPM8Xl4AMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTgwODIy MDc0MTAyWhcNMjgwODIyMDc0MTAyWjBnMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjExMC8GA1UEAxMoRnVqaVNTTCBQ dWJsaWMgVmFsaWRhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMdXCsp4TeyYoKJfu/CkiULI5mWRf1hdjOXjHVcTuaZf RijjVh72ipGt5PfZOIz6oLmMnijHinoM6KtCSa35yAQ8uRoqlx9qmLAM/5UIdJl4 ScGbGL21Rete0sJvBI55NgDalpPzcuVwA8DU6VDmxrlshiF2EHEWkPa9n5BeOelU LKo1T4d0EjcpPCiNHYJeTcy4Lxbkr5jgPWsWoRSx+SuPZt3gchneEdENke3LciD4 jk9lJAkn1S8lWSOK2GLDui2ml53bGZEuOIJ7iQvmByEx0gIUiIrywgI7OXWu1MJA oLViTvRL0PCzwkpnbnmPKKybzBM10Vp7aqU3Ev4iL/ECAwEAAaOCAV4wggFaMB0G A1UdDgQWBBS869kR4FFkb//wdE8NWqtKTy14JzAfBgNVHSMEGDAWgBQKhal3ZQWY fECB+A+XLDjxCuw8zzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIB BjBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0 Lm5ldC9TQy1Sb290Mi9TQ1Jvb3QyQ1JMLmNybDBSBgNVHSAESzBJMEcGCiqDCIyb G2SHBQQwOTA3BggrBgEFBQcCARYraHR0cHM6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1 c3QubmV0L1NDLVJvb3QyLzBABggrBgEFBQcBAQQ0MDIwMAYIKwYBBQUHMAGGJGh0 dHA6Ly9zY3Jvb3RjYTIub2NzcC5zZWNvbXRydXN0Lm5ldDATBgNVHSUEDDAKBggr BgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAQEAMDv5Rwc6XDgWZQdSdApBquE78dVP oysu8zN9XodyC+//9yMXx+SBTWxsTJNgnKT9FrwZQZRo5CTWsYF8WicsGjAyf8Fy GSaRzc2rKjfICygyOPMTLLUHec+lLgkPr9gv68Qbsyth1WjVrDrj77jGIaE362wb Df9g8bO5omU3ZmkxmcADzarwL8M3Z0XynpNakwKGFr7UVT6fxBN3dyhuBO8Lai6D g3tiJAlFIpfXXD4cArZo6ZlXJ26B4H7vk5GmyR6poDy/CRvC7VIz3xp6o2348W1j 32S9pEuZhtxtMvPjnsHIWPNdz8pHv21x7bYwDnocwN2uk3QrrljxTQ9evg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjDCCBHSgAwIBAgIPAWWE40o42elj6+7SF0eEMA0GCSqGSIb3DQEBCwUAMDcx FDASBgNVBAoMC1RlbGlhU29uZXJhMR8wHQYDVQQDDBZUZWxpYVNvbmVyYSBSb290 IENBIHYxMB4XDTE4MDgyOTA4NTE0MFoXDTMyMTAxODEyMDA1MFowUTELMAkGA1UE BhMCRkkxGjAYBgNVBAoMEVRlbGlhIEZpbmxhbmQgT3lqMSYwJAYDVQQDDB1UZWxp YSBEb21haW4gVmFsaWRhdGlvbiBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBALvfr7q8p3BUGG99Z8QPKK3BeRtR3bvEvTd2NpJMKB5iDbhWTiyQ PqakD/UksKICujpvG1A4rCDX3q4wBxPD29OOaZSEufzsQMI9M3lcjTsIOinX+N05 8/M6pPdocCGBz+/6pGHw9VWk381hFKNfdqcTJj0138udZwt1coxrVBZ2MJe1tnJR vak8aPUANEJBmzDXXeJEGuAyDrecnh2uZqn+yM7yKJnzkxj/AmnyMMPnnbTBfdjZ gfy04yLsBxZdQNf/t7+sni+FRPKgpgcdRG7Vz4W3LHEnbwvDSGuwi9XD5BIA1nLE B0x9fEhmJnCtVsN00FEYpr/2YZaEpBPnJLEKYFLASke0qV8kLT4y8c6YQZ90U6GG g0VS6X3TN/qpiai/VNnzIugT1hnHC+4GyeqPJhjpEbjOOPY9j7FjOI/P3JLi9Xvn 9HveZKf3Cx6R17mR8HXdFT7he6yJbiunOq60YXcf8aVyKIejWGysMuvyUg9mF0Rk ma9vuOg/q9eFWBseeGV490HP0l//Q7+O530BjAmQm4JzI39i0Kas3oWiei1JoVa1 NCrpWEGypXjeWmkVvTSS2hRSiCc09imY4xH8KJm77RfLte8yvYVnkTbAWDB2s1da z2wgh+D8t0ZVzgU0m7L4o6+mktuA1jM6GcUFqP1i7+7OQUCYJZGJ9AZTAgMBAAGj ggF5MIIBdTAfBgNVHSMEGDAWgBTwj1k4ALP1j5qWDNXr+nuqF+gTEjAdBgNVHQ4E FgQU7T10nCxTu3GTe0sR9riR4oL5ktswDgYDVR0PAQH/BAQDAgEGMD8GA1UdIAQ4 MDYwNAYGZ4EMAQIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vY3BzLnRydXN0LnRl bGlhLmNvbS8wEgYDVR0TAQH/BAgwBgEB/wIBADBHBgNVHR8EQDA+MDygOqA4hjZo dHRwOi8vaHR0cGNybC50cnVzdC50ZWxpYS5jb20vdGVsaWFzb25lcmFyb290Y2F2 MS5jcmwwgYQGCCsGAQUFBwEBBHgwdjAnBggrBgEFBQcwAYYbaHR0cDovL29jc3Au dHJ1c3QudGVsaWEuY29tMEsGCCsGAQUFBzAChj9odHRwOi8vcmVwb3NpdG9yeS50 cnVzdC50ZWxpYXNvbmVyYS5jb20vdGVsaWFzb25lcmFyb290Y2F2MS5jZXIwDQYJ KoZIhvcNAQELBQADggIBAEX7NaPbTTbHchQrIU7orj0t9IzTHCNwQW7TtYSwyLVA fI98pVfB3JBjnskfLvDzVYY5gWfaFqX8PjR4Dt80pHQmOpX+VvcC8ZNkcEvN/TDt NXaMAtyHoGq2JLMakXf6NarTHD6Gvb0e9rP1pT5Wa4IsdMwmLct12fk2MVach/xT /mRoB2375f1dzSiwm7iEIPY6ebqr1LhdEj7sywJXCJ/a+hideRgdgQo+OMiG8PAU hfkDdigpJUXY1yDtTuI8jF2+gYSIxEj6Lh+9R3sfAHj5a5FL1afvBKEnVU2aaDIE PxIhnLYHfmS/n1CzeWPzvLbmkZJ9afyL0dWgxsAOSRQzgVqrHwYgYWPmEiFa5mRO BalPxdzC0O+Gfz0dyFu4pgYPe8QXxZTIAvL2hFvda2FAT4lqMRNJRwXH5BbuET20 xPMHHeaAxJW//xiJEdwFAb/vSTYP3tudXpOp69X0f7A+wM83eUM+30mjXEkjWXnD ULcx0AjCwN8LwYkclLwFEFhhUkDeAd/UmjmzwQj9AneM4Dz8t8I/RbK4k5FnJG9a BGTdIQ8Yr7xpPsdYCEbH89C4Zh49NPCEqGG/snLQLWrjCq6oLEDbTNzRriMyqdrt v80G4TJoIXmTE4viSpUeTL2tqQ/5SXkoMCXUMXAZHi2jrGQKDmespX6H9VqFm+3K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDazCCAvGgAwIBAgIRAPFz8qqTtlllRGvVydIjmTYwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MDkw NjAwMDAwMFoXDTI4MDkwNTIzNTk1OVowTDELMAkGA1UEBhMCTFYxDTALBgNVBAcT BFJpZ2ExETAPBgNVBAoTCEdvR2V0U1NMMRswGQYDVQQDExJHb0dldFNTTCBFQ0Mg T1YgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQoZ0E6ymikCMsUKaEP0slW tSi0dcOyKHXxkPCL7tIbbgttSxtZNYoA37jechi1HAWmEgkpSUu5g6uIJkkDdTpz o4IBdTCCAXEwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0O BBYEFPtauVO1mWA3ImgLSrJjByl6TIB7MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNV HSAEGzAZMA0GCysGAQQBsjEBAgJAMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQWRkVHJ1c3RDQS5j cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZI zj0EAwMDaAAwZQIxAPwptS9tfb0Rc7E80SetAP1fpYHCLw7F9Qm4eJ9S/5lkfV3y 0W7mPkM+EeWUDxzDOQIwDyffARsOZHcy+u4QxMFD+j94kXJTirpNv1gZsTASiUT6 2Bx91D6r91i1F1Ss5YjN -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0TCCA7mgAwIBAgIRAKQ8p33uR6RZrThpO0jdIAwwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MDkwNjAwMDAwMFoXDTI4MDkwNTIzNTk1OVowUDELMAkGA1UEBhMCTFYxDTALBgNV BAcTBFJpZ2ExETAPBgNVBAoTCEdvR2V0U1NMMR8wHQYDVQQDExZHb0dldFNTTCBS U0EgQ2xpZW50IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsG8P tYc9Dg46Uo2UsmG00Wjdu1QINaepaG8MmhV1d5L95DqcKN2V+bfl+is+SMB3L0KD OvHKezuJHJl+H9zvRaM4F2i2QbCzz+LN1D0dqErCD/Ho+CZ6udO4zykVa2eBnF1O V2Y+5hjZG2zqUWgSUHZk9FwoKDuIb9CNehwiINLqDf8fEVulGGAtIAwm+HqecKl3 1/JcdMPq3lVBZysP/K3vgZjNi0hc2ihV+2jHlsUrLKeD6d9jUJe5C/5KS+MIaKfq R+v0UvU9xcyrTPbdRlwUhSswqO/i/kL9UwLFaIDOBASR2FLOA8VMvbloJ/LepEnz D2tpZOga+QkHyJUuAwIDAQABo4IBazCCAWcwHwYDVR0jBBgwFoAUU3m/WqorSs9U gOHYm8Cd8rIDZsswHQYDVR0OBBYEFFkRFJxha0/M3Dkl28kWcd+hcdsiMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUF BwMCBggrBgEFBQcDBDAYBgNVHSAEETAPMA0GCysGAQQBsjEBAgJAMFAGA1UdHwRJ MEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FD ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYB BQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRU cnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNv bTANBgkqhkiG9w0BAQwFAAOCAgEADDAa9SA7cRB6VcF156D+I8/YYaVCQAvWe6ni s78jGssFvQ9ib2XCp2yyXen55Ja3OvSlh+ALmcUGu2FO6WnW3mlPaIHQqrKJacSZ Y5uqGkgeci2RA1BL2WsdrlMNyoE3CgMEwcsypvQQKVjOs/F1+3vv0XbtExJT03ts g4RUqLfvhwwZJ0ohB4bDtcpOsVb/96Ipax9MdttpNvosu1Zn4uw+e6NRvhXTizHu QMFTxL1CQWPLb8rgemw1aqzG7LFRKlqdvW8Guo+Q7wy9EN9qlUyTYKxJkpksoRLX MP1bJu99vzbu08dXQBbuCDMjm883pqULpSLFIgy8Cd52mpoUKj1UqyrfT5wgd3+k lyR+sTdYQ4dOCzfA3zaz49SllfjubJMQZ0uG41dIJ7U+zIVm/cHTm5M/Wx0wUJQt y/yjpw67lI6x2l+pFWA499tRS2Rx2kqd2+PJ5FW/9waDJ3IeMUb67AH3d1w0L4WG Kh1mxit34TDeRB+5POf36J7UtkXv3zmLLXfIONAiw9WJj8wYyE7prlv5txDNupsA sqVKq2ZOahYf2P929kr2is2m14l/54gXzfm+LS7YXwv6imXF/B0GW8+CTPDnT8VO 4ouP4SSz9WdowDJEpfc2/OPzBIw2jbJgr+3fATbHDhxBZi4L18Z/FGmWLDjns429 iPLWJ0Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF1zCCA7+gAwIBAgIRAJOLsI5imHtPdfmMtqUEXJYwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MDkwNjAwMDAwMFoXDTI4MDkwNTIzNTk1OVowTDELMAkGA1UEBhMCTFYxDTALBgNV BAcTBFJpZ2ExETAPBgNVBAoTCEdvR2V0U1NMMRswGQYDVQQDExJHb0dldFNTTCBS U0EgRFYgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfwF4hD6E1 kLglXs1n2fH5vMQukCGyyD4LqLsc3pSzeh8we7njU4TB85BH5YXqcfwiH1Sf78aB hk1FgXoAZ3EQrF49We8mnTtTPFRnMwEHLJRpY9I/+peKeAZNL0MJG5zM+9gmcSpI OTI6p7MPela72g0pBQjwcExYLqFFVsnroEPTRRlmfTBTRi9r7rYcXwIct2VUCRmj jR1GX13op370YjYwgGv/TeYqUWkNiEjWNskFDEfxSc0YfoBwwKdPNfp6t/5+RsFn lgQKstmFLQbbENsdUEpzWEvZUpDC4qPvRrxEKcF0uLoZhEnxhskwXSTC64BNtc+l VEk7/g/be8svAgMBAAGjggF1MIIBcTAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dib wJ3ysgNmyzAdBgNVHQ4EFgQU+ftQxItnu2dk/oMhpqnOP1WEk5kwDgYDVR0PAQH/ BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAkAwCAYGZ4EMAQIBMFAG A1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1 c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgw PwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RS U0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRy dXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAXXRDKHiA5DOhNKsztwayc8qtlK4q Vt2XNdlzXn4RyZIsC9+SBi0Xd4vGDhFx6XX4N/fnxlUjdzNN/BYY1gS1xK66Uy3p rw9qI8X12J4er9lNNhrsvOcjB8CT8FyvFu94j3Bs427uxcSukhYbERBAIN7MpWKl VWxT3q8GIqiEYVKa/tfWAvnOMDDSKgRwMUtggr/IE77hekQm20p7e1BuJODf1Q7c FPt7T74m3chg+qu0xheLI6HsUFuOxc7R5SQlkFvaVY5tmswfWpY+rwhyJW+FWNbT uNXkxR4v5KOQPWrY100/QN68/j17paKuSXNcsr56snuB/Dx+MACLBdsF35HxPadx 78vkfQ37WcVmKZtHrHJQ/QUyjxdG8fezMsh0f+puUln/O+NlsFtipve8qYa9h/K5 yD0oZN93ChWve78XrV4vCpjO75Nk5B8O9CWQqGTHbhkgvjyb9v/B+sYJqB22/NLl R4RPvbmqDJGeEI+4u6NJ5YiLIVVsX+dyfFP8zUbSsj6J34RyCYKBbQ4L+r7k8Srs LY51WUFP292wkFDPSDmV7XsUNTDOZoQcBh2Fycf7xFfxeA+6ERx2d8MpPPND7yS2 1dkf+SY5SdpSbAKtYmbqb9q8cZUDEImNWJFUVHBLDOrnYhGwJudE3OBXRTxNhMDm IXnjEeWrFvAZQhk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDazCCAvCgAwIBAgIQcmppRZS5Qa5X164QDHTuOzAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgwOTA2 MDAwMDAwWhcNMjgwOTA1MjM1OTU5WjBMMQswCQYDVQQGEwJMVjENMAsGA1UEBxME UmlnYTERMA8GA1UEChMIR29HZXRTU0wxGzAZBgNVBAMTEkdvR2V0U1NMIEVDQyBE ViBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHdWp+7zKP8h6sI6zFfJ3ZXU 4Vp7xbi6x8ehUEMIqWpYHr+7aOVqA0N6usZL1FaOJpAcOC2vUSfEqsPx7b3BTlCj ggF1MIIBcTAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4E FgQUTQpD/NcHYzUaKXchSG6iOPpiOOMwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1Ud IAQbMBkwDQYLKwYBBAGyMQECAkAwCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGG P2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0 aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0 dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNy dDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjO PQQDAwNpADBmAjEA3rJX98bpCOopk+BfYDhTOxT9DIo3wYlrTEF1WfVQKvn8Byu+ A+p02M7FjOxkJIVTAjEAs8jJKKwYQn1IogusMfbyAr82RigZR4yFLUKCQB2i/NmW 5AjZovG+21WMmnCvcLCi -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGKzCCBBOgAwIBAgIRAKVuHozHz5MnF4qZxEffvXUwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MDkwNjAwMDAwMFoXDTI4MDkwNTIzNTk1OVowgYcxCzAJBgNVBAYTAkxWMQ0wCwYD VQQHEwRSaWdhMREwDwYDVQQKEwhHb0dldFNTTDE5MDcGA1UECxMwQ29udHJvbGxl ZCBieSBDT01PRE8gQ0EgZXhjbHVzaXZlbHkgZm9yIEdvR2V0U1NMMRswGQYDVQQD ExJHb0dldFNTTCBSU0EgRVYgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDLjrZgHYrWJlRBo1IhlTDlkP5BiVses7WQsH15KmhxUQumCpBx5wjT4mYJ UI793Yz3Jya/vy3LU4TWH8hQiiuz1ycBp+o6ks1d448xiltYXAZNQ4ahXurG66mK qgOjhaVhMKa8pU7Ns0UZU1kuUmQq1oyoUTAALOaWLgXfM4w4z+HpPcamHxC/7WBz CSf1W6d3FVilaxHfXBzCpgP9v31v1hOqMhkEP7qW+M4x/uKpwwpp3GhjePy3O1Lw pnPiMXbxuH5Qwz1F5yBlxHmPRCEq2x6mjwBajGBswpUgsjmf/x5bd105xDhVd3Dr T0+tCmhzXS4hsilBHPje3LAptf1vAgMBAAGjggGNMIIBiTAfBgNVHSMEGDAWgBRT eb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUzwc6XeGU5VUSI2PffRZBPOd6 ap0wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYw FAYIKwYBBQUHAwEGCCsGAQUFBwMCMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsG AQUFBwIBFhlodHRwczovL2Nwcy51c2VydHJ1c3QuY29tMFAGA1UdHwRJMEcwRaBD oEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZp Y2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKG M2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENB LmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkq hkiG9w0BAQwFAAOCAgEAa3TW0iAyOQ+zb1bSpiOdDFv6+wdrHJed8UyCJUlNMP3h UetEM0WpnVSii9krwWwgAN9vddJRcZ2HTHijVoThIi+di68IPMRitwNl0iUbCZnC Af9AuJPlbhRT1yMHCHSWDCvoaetmuiBs0RZBGj9eIRMAD3RpFJN+tCp+fNNe1Gyz 96GlJh4ZZYOJW38qLOv+/qxXax9RZ1aJASTON4EDuvB24QFTpuxrDlAnutXUtkn7 QhD3fk5WZJKl/7FGnzbBsF0xhfwFrTLsNjI/AC879rqyciRxzztkyPEoXHtOUOKr Q3rlXsfHJwDZgBp8QiC5v3BoCSYDaHL8bnPLgZAf6ubNUjPhLv972v7nXkiXJ3Db r2jM3e36eOStV6RZGWC2lb8ujC15GvfgL18VwtoIp3IFMLIYomUMpQUU0+W9K/RV +M7hdzoy/s9GOtNmrZnuBTtj8UMeYnI2FD3QDPB/mKBGpeXLk/K1Tb+PidoYR4yj y61vJ0nSRbzquiDZ1/bmlXQmVcQp4vpcKipyAcyOh312Qs8fMgwHXZT9zHTLRwJf yeJ+YsUXCb07um9X//pPJZYDMXBw7IKudAzrIOmlukxnYYn29Z3T4hiNQhWUQuKd gZtmbMMGTqn1IGUk/5hmkABb703KTpR9Nx/kDpvWPN8OQAeZbrZ6+HCOFnI88kw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwDCCA0WgAwIBAgIRAIseFn/UY7OGr4IqVwzWsh0wCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MDkw NjAwMDAwMFoXDTI4MDkwNTIzNTk1OVowgYcxCzAJBgNVBAYTAkxWMQ0wCwYDVQQH EwRSaWdhMREwDwYDVQQKEwhHb0dldFNTTDE5MDcGA1UECxMwQ29udHJvbGxlZCBi eSBDT01PRE8gQ0EgZXhjbHVzaXZlbHkgZm9yIEdvR2V0U1NMMRswGQYDVQQDExJH b0dldFNTTCBFQ0MgRVYgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARny4ro N/2YypIH2TrNN562UPfcX4nmTXy2GCmUwecM2JrR4fxHmuXC351TrnCIPr9t6nrI djXWj3GFsSSwodc2o4IBjTCCAYkwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzg NcZjY5owHQYDVR0OBBYEFO50mYDkBTKo2xVdE7B3OIz9cqUHMA4GA1UdDwEB/wQE AwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr BgEFBQcDAjA6BgNVHSAEMzAxMC8GBFUdIAAwJzAlBggrBgEFBQcCARYZaHR0cHM6 Ly9jcHMudXNlcnRydXN0LmNvbTBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0 eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVz ZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUH MAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaQAwZgIx ANWiKZ2TjeTFIlr+nAeb9Sq9lkCUU3yfPwbpnp2L28oKWf83Uz0MI3xBV4LoO+fq vAIxAP9tDaUS1cueIaL11e+u2qFZGrFrW4zD7w8+63+hgzBQzAGYbctu2Aj/SXFH eiqO5g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF1jCCA76gAwIBAgIQcafv2JIF1zoexDKAxF21ijANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgw OTA2MDAwMDAwWhcNMjgwOTA1MjM1OTU5WjBMMQswCQYDVQQGEwJMVjENMAsGA1UE BxMEUmlnYTERMA8GA1UEChMIR29HZXRTU0wxGzAZBgNVBAMTEkdvR2V0U1NMIFJT QSBPViBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKqRXfMokJtx bIC/GqpsPEFDd0QyBAzPPq/UyG2ZIZfiPSrMu/Fe7RYtdzFtVqPjUX/FG/lsx9Sy LOPamas2oX1elfwBsMnCFx5GqAkKIlFdbEb2lHx+wOgiZYgBygDjVw/CKP96vBtW eqfehKx4thmVQhTQXBrULTrZ61hLhBDel9gf85ND+1vmnVoBGHOyF90NDYack8Dl r80vjmZv6N8anddTc1v0whzuVOdsscs5NysgrCDdlMSNQvQ+ZyrfkKZji67d/A2L pc9UvF/1c19YW3WMMWsU42n/1azDMS3EmRImYYOgk/njal/UpcC5z4zCmutPMYMy p0V8HjyNRUUCAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvA nfKyA2bLMB0GA1UdDgQWBBQs5Po8O9mx8eIE1x8721u0/GkY5TAOBgNVHQ8BAf8E BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICQDAIBgZngQwBAgIwUAYD VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/ BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT QUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1 c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAXSyvITDnap0oOEk6ZtKuVvUbixS7l ajeDX1XixGBgTD2T1LIhCrOd6JfQfbBnpMr1nZE1kFiA5GID8qVGYRh1bEbrEKjJ SwaKfT3g6RFFoppp7K5fX+uJHBPGFlq1UkugRo7dGTYFwukJ9a2PcCn9CmhMQMhB uJiD78yTFGiBBw26rfCEqR+6pxgfQINiOQaPBfDhbDTsmPoseXHenJsppbH0g7ci GpXhBElxpv59doUV0+HeeOkI0d2cJMFmowUZXJP32iCZ1WJlfV/cNRRyf6cbHPKX mITI/DaNP+8ORyj7fJQvG/xlHFMlhz2M+DLBvbf/ClUjpORISSbhjjyPNYabHNyk 40a0FhflgzEgRXXWbYSRRT2bV16H5ZOglt5mF3ptFVkpC2s7ay5H/Sgbfw4580V1 DGe5CbdOhad8RjUPPgHZuDG55LHMEKk0vueePZbbm6zFhELtWX/FipsyUsMKtlYC hwmOhZxK7og2Rq3XKqtFWNphKoOvToBPJm30kSWnlkMU2UEy7xJHsqZWtFp0VHul kw2l7EpO7GNiM5eT6lytfEWda2fhdKJfuJfDvBcg1DnVfPi0wy3on8paRgp02mNO sftG8y3NT6VFE6AHFnBlL7Q/y5YH9+fJNnYj2MDBRmO+CQVFRzHjD2nR+9nuicwE VXf2yyOIoOuhWA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGQTCCBSmgAwIBAgINAL2sPTWYT0LlVg4iCjANBgkqhkiG9w0BAQsFADCBgjEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMScwJQYDVQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkx HzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMTgwOTA2MDkwMDAw WhcNMjkxMjI5MDkwMDAwWjB3MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBl c3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0 NDk3MSQwIgYDVQQDDBtDbGFzczMgS0VUIGUtU3ppZ25vIENBIDIwMTgwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDf5RYfEdhtBU6Mi79PDqO+WHWh8UpG nCh0V2L+LJXzZsRuxHPpAocEn7x+36oreSm5eeerKVIn3TKUBTW0B/GcpL70ysat QSle7+nZdsT39Ify2Hyet9NxeWXTp7UU/mrxjQGl5ty5/XL4CQ5XHBc3yvXi49lI QyNc9Yu525/uyjcUb3ClNNwU5z7+kjqIMFuyczz8ivMyGz0XOyaAl9yCIj72uepN RsPmhB7SYrSMErUc1y4RIfyqNvuQJ8N2RpxWDT8Jiau+SUatnHpDGcjlSBQX2De2 jhqdAuJYgh8kM24pmLVQeThrobnekzPJAevShBB/C+oTd2sUQmCQjsszAgMBAAGj ggK+MIICujAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA7BgNVHSAE NDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL2NwLmUtc3ppZ25vLmh1 L2FjcHMwHQYDVR0OBBYEFJZK+MZgjhbAnXOsIIWAGZ3XwBhtMB8GA1UdIwQYMBaA FMsPxt9CQ8w9y7VII6EaeqYquzRoMIG2BgNVHR8Ega4wgaswN6A1oDOGMWh0dHA6 Ly9yb290Y2EyMDA5LWNybDEuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcmwwN6A1 oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNybDIuZS1zemlnbm8uaHUvcm9vdGNhMjAw OS5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNybDMuZS1zemlnbm8uaHUv cm9vdGNhMjAwOS5jcmwwggFfBggrBgEFBQcBAQSCAVEwggFNMC8GCCsGAQUFBzAB hiNodHRwOi8vcm9vdGNhMjAwOS1vY3NwMS5lLXN6aWduby5odTAvBggrBgEFBQcw AYYjaHR0cDovL3Jvb3RjYTIwMDktb2NzcDIuZS1zemlnbm8uaHUwLwYIKwYBBQUH MAGGI2h0dHA6Ly9yb290Y2EyMDA5LW9jc3AzLmUtc3ppZ25vLmh1MDwGCCsGAQUF BzAChjBodHRwOi8vcm9vdGNhMjAwOS1jYTEuZS1zemlnbm8uaHUvcm9vdGNhMjAw OS5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2EyMDA5LWNhMi5lLXN6aWdu by5odS9yb290Y2EyMDA5LmNydDA8BggrBgEFBQcwAoYwaHR0cDovL3Jvb3RjYTIw MDktY2EzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3J0MA0GCSqGSIb3DQEBCwUA A4IBAQAX8821EX6razm9TJske3qrTI4IWvRGAfQcq8TAd+Ew9Hj+feoWdaDPP+Lz Hd/9SJIUHuz+vpwnnVHcqFLsAIHHaLk6JO2xyS1qiFiDhk0QmX4kd/U6ccEftXWG rfYwO6FudOEnuaMc9+qiXqsStQUiIdqo+GdrTN6ydwzZn7mRS/0i5oX3wSqyGhRx DxpnjCWDjHreFJtOzQxpCga4I9WAsQ29LUo4goDSXsrC2ZgSHSxT/3nDXXLuZbAB I69bFQw9Tkpt+OhJVNRG6GPrRVuFSlAczXCxUcIRkqJ1zPKuQgpH9z5OrUzuoFiG AGWprNbrzcLASC1DvNMEa9vQIxD4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGRDCCBSygAwIBAgINALw9mlbUQaK7WYdiCjANBgkqhkiG9w0BAQsFADCBgjEL MAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNyb3Nl YyBMdGQuMScwJQYDVQQDDB5NaWNyb3NlYyBlLVN6aWdubyBSb290IENBIDIwMDkx HzAdBgkqhkiG9w0BCQEWEGluZm9AZS1zemlnbm8uaHUwHhcNMTgwOTA2MDkwMDAw WhcNMjkxMjI5MDkwMDAwWjB6MQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBl c3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0 NDk3MScwJQYDVQQDDB5RdWFsaWZpZWQgS0VUIGUtU3ppZ25vIENBIDIwMTgwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDsUi6HKiAGkFC2BAL+zB/EG/eV ynCr2PQVxlFotCZtIMXUbFhyHPzvPrrPdsBRkxx2F4RLJP38bKvUigQ5IHQfKwOR JfswAkJSak337+nl1jpo8wweVaoW8QK8y5zHULnxh/AyfFaa6iJGlsuzdKpD3THD d8l4zkJ94jzy5LnN/vib+aVYAJlRUBIGu/GtUfPF3fKC2hErGqL12kqeyNTP1krB SB+NFbYc4N14B2gyjvaHlwJJCpEyE5tWJ84dgzbP15s4qjkIFollOx6eJLtGuONk WKBlDCm6qF4SU0g9X6GlTH9RLQRz/cTVfEysl+fW2MPYtGbSOM1ufI/HnEnzAgMB AAGjggK+MIICujAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA7BgNV HSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL2NwLmUtc3ppZ25v Lmh1L2FjcHMwHQYDVR0OBBYEFFVGDPnTmaPUbAbL/XjeR+d7Ph6VMB8GA1UdIwQY MBaAFMsPxt9CQ8w9y7VII6EaeqYquzRoMIG2BgNVHR8Ega4wgaswN6A1oDOGMWh0 dHA6Ly9yb290Y2EyMDA5LWNybDEuZS1zemlnbm8uaHUvcm9vdGNhMjAwOS5jcmww N6A1oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNybDIuZS1zemlnbm8uaHUvcm9vdGNh MjAwOS5jcmwwN6A1oDOGMWh0dHA6Ly9yb290Y2EyMDA5LWNybDMuZS1zemlnbm8u aHUvcm9vdGNhMjAwOS5jcmwwggFfBggrBgEFBQcBAQSCAVEwggFNMC8GCCsGAQUF BzABhiNodHRwOi8vcm9vdGNhMjAwOS1vY3NwMS5lLXN6aWduby5odTAvBggrBgEF BQcwAYYjaHR0cDovL3Jvb3RjYTIwMDktb2NzcDIuZS1zemlnbm8uaHUwLwYIKwYB BQUHMAGGI2h0dHA6Ly9yb290Y2EyMDA5LW9jc3AzLmUtc3ppZ25vLmh1MDwGCCsG AQUFBzAChjBodHRwOi8vcm9vdGNhMjAwOS1jYTEuZS1zemlnbm8uaHUvcm9vdGNh MjAwOS5jcnQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yb290Y2EyMDA5LWNhMi5lLXN6 aWduby5odS9yb290Y2EyMDA5LmNydDA8BggrBgEFBQcwAoYwaHR0cDovL3Jvb3Rj YTIwMDktY2EzLmUtc3ppZ25vLmh1L3Jvb3RjYTIwMDkuY3J0MA0GCSqGSIb3DQEB CwUAA4IBAQCsMKXj8a1+9g+Asjhq0ydrm8FojCmIpqV6lK8zOIOxp1TVel/Tz7qq EWq/GeQw1BTR1Pj2x03E6GclUvA4LcNHRd5RUnUQpgMUke47laGmJQD9UYj5KOXi cIBijhFgMr3EjL6KMhxbw8y7hNXGIwwMkHIhwtOV8aZqvAtIWTLYZewlDV3G+0Xt xlf7xB7REWHSRbPmNuJ35jtNnmroRejNkBjk2vzg4qK7nrcvX1Hq/eC/YdomxQMw V+hvP7lx0ax4dOHT7NhDJShZlz6EIRcvHoIKk9IyYcI4CJWFGbPVinQzeI7eEH9C VpvGgK/EUShve9Cqk2nE3hvpBZ2Fml6O -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIETjCCAzagAwIBAgINAe5fFp3/lzUrZGXWajANBgkqhkiG9w0BAQsFADBXMQsw CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UECxMH Um9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTE4MDkxOTAw MDAwMFoXDTI4MDEyODEyMDAwMFowTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBSb290 IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNp Z24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMJXaQeQZ4Ihb1wIO2 hMoonv0FdhHFrYhy/EYCQ8eyip0EXyTLLkvhYIJG4VKrDIFHcGzdZNHr9SyjD4I9 DCuul9e2FIYQebs7E4B3jAjhSdJqYi8fXvqWaN+JJ5U4nwbXPsnLJlkNc96wyOkm DoMVxu9bi9IEYMpJpij2aTv2y8gokeWdimFXN6x0FNx04Druci8unPvQu7/1PQDh BjPogiuuU6Y6FnOM3UEOIDrAtKeh6bJPkC4yYOlXy7kEkmho5TgmYHWyn3f/kRTv riBJ/K1AFUjRAjFhGV64l++td7dkmnq/X8ET75ti+w1s4FRpFqkD2m7pg5NxdsZp hYIXAgMBAAGjggEiMIIBHjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUj/BLf6guRSSuTVD6Y5qL3uLdG7wwHwYDVR0jBBgwFoAUYHtm GkUNl8qJUC99BM00qP/8/UswPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFo dHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjEwMwYDVR0fBCwwKjAooCag JIYiaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LmNybDBHBgNVHSAEQDA+ MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5j b20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBACNw6c/ivvVZrpRCb8RD M6rNPzq5ZBfyYgZLSPFAiAYXof6r0V88xjPy847dHx0+zBpgmYILrMf8fpqHKqV9 D6ZX7qw7aoXW3r1AY/itpsiIsBL89kHfDwmXHjjqU5++BfQ+6tOfUBJ2vgmLwgtI fR4uUfaNU9OrH0Abio7tfftPeVZwXwzTjhuzp3ANNyuXlava4BJrHEDOxcd+7cJi WOx37XMiwor1hkOIreoTbv3Y/kIvuX1erRjvlJDKPSerJpSZdcfL03v3ykzTr1Eh kluEfSufFT90y1HonoMOFm8b50bOI7355KKL0jlrqnkckSziYSQtjipIcJDEHsXo 4HA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuDCCA6CgAwIBAgIJIrmxV1B1SHAJMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTgxMDA0 MDUyODA5WhcNMjgxMDA0MDUyODA5WjCBjDELMAkGA1UEBhMCSlAxJTAjBgNVBAoT HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNFQ09NIFBh c3Nwb3J0IGZvciBNZW1iZXIgMi4wIFBVQjEqMCgGA1UEAxMhU0VDT00gUGFzc3Bv cnQgZm9yIE1lbWJlciBQVUIgQ0E0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAx7lxTQux3E4gt1XVR/Woo8lPgGhYd7BkIxWxZvkDZXlfwW5q3GzQX+VP ra9TsIPJPzPZ6KnUbzvtvz95wu85GQD5MNlckDOINhea9bbAkvp8Wfy0RKe86TkM fn1BSa/bS1YG6KXGYX7YGKmJkhdnDgNAWEBBdlH09m9K7bizfxwIzIZu6UBqGFnb Z/WNRcS7cQVqnpGAdDnA+2AYPoXrLlvgVR+5TrwW67cOTdfYbVX4B1JaLEp9GwoL +0+YgaQVXmBT/QAPTaIKx9eVY3eAghweNOouUrIIj6ZVuBlhlDXDVasg3s3jYKu0 RJ7AabTrjCO7Oti/lPRSnWG2AfRT6wIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFEiM ZXbSHqv1/zgktsQ22QqfoLyuMB8GA1UdIwQYMBaAFAqFqXdlBZh8QIH4D5csOPEK 7DzPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC MEAwPqA8oDqGOGh0dHA6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJv b3QyL1NDUm9vdDJDUkwuY3JsMFIGA1UdIARLMEkwRwYKKoMIjJsbZIcFBDA5MDcG CCsGAQUFBwIBFitodHRwczovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0Mt Um9vdDIvMEAGCCsGAQUFBwEBBDQwMjAwBggrBgEFBQcwAYYkaHR0cDovL3Njcm9v dGNhMi5vY3NwLnNlY29tdHJ1c3QubmV0MA0GCSqGSIb3DQEBCwUAA4IBAQDKRUJp b99cV+ciYAurlQGywutTks67EBsA+LyGDL8I0EhaXG26+oBTgjS5OnldA8BIdkJ3 krQmEQRDcOUD0Fn6ItFZdHC/lKDBRy32jwaAfieb+t7M+B2jnZP8pMWvamCGqjS8 V7kz08jJwJUmEnuz3AAIiFgShV5Nk3qw+f7rGhGpxnz5cjxRHh20ftFxkhRVbDox jZTI+8RIXuif/Z1CzvyNq89R1N4f9mkW48IekCDbsyOjOU8GsC4FNKRc4BNH3HD5 Aef9x4+JJfMA+WLwQ+Lpzy77K+lpXv4XuuznqJwLIFCCdm28lK6hi1lFwY7T/vmU SN1IEB+nlCfBLp43 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEoTCCA4mgAwIBAgIQQAEz8BQAAAAAAAAMz6481zANBgkqhkiG9w0BAQUFADBf MQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290 IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw HhcNMTgxMDEyMDMwMzU3WhcNMjgxMDEyMTU1OTU5WjBXMQswCQYDVQQGEwJUVzEX MBUGA1UEChMOVEFJV0FOLUNBIEluYy4xEDAOBgNVBAsTB1VzZXIgQ0ExHTAbBgNV BAMTFFRXQ0EgSW5mb1NlYyBVc2VyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAoTC7HNPpQs9j0mmLXC9ZWoXCSP5IbAcufJi8VhjVKDQqK0IZRMxe rISJ8JKT02epWCkj7Z6xYYlOr8tCtVpkmKLe+hqcQt0xqd4TdA5TRwA6Tn+ERlc9 QFaCFX1bkym7CKzyiKXksoaQQHTUv3CwZ8tSD9NWZnw+38T6qnAV/tzxLwr1/Z3C 1WKf3ZsYQYtz3ZpQMwgSDtEJ/Da62ddblavsw+8amTxSkOBwUBSIFoCsGmJcF4Da RARG22yqFlrALQ9T0IIECe9dSM9//adZTjQZ58Uf6LVHjgPc1uaHttAZ0qULzZ+a lq5jaQVmCk/y4b8Iff0nlDt1WCsiUJnQUwIDAQABo4IBXzCCAVswHwYDVR0jBBgw FoAUajhbJo3ei1ryT3pUgxkY4wg1prowHQYDVR0OBBYEFEZvFob0oFsRQb6TauwG UM6KVUZZMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYB BQUHAwQwgZEGA1UdIASBiTCBhjCBgwYLKwYBBAGCvyUBARcwdDAkBggrBgEFBQcC ARYYaHR0cHM6Ly93d3cudHdjYS5jb20udHcvMEwGCCsGAQUFBwICMEAaPlRoaXMg Y2VydGlmaWNhdGUgaXMgZm9yIHRoZSBzb2xlIHVzZSBvZiBUV0NBIGFuZCBpdHMg Y3VzdG9tZXJzMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9Sb290Q0EudHdjYS5j b20udHcvVFdDQVJDQS9yZXZva2VfMjA0OC5jcmwwEgYDVR0TAQH/BAgwBgEB/wIB ADANBgkqhkiG9w0BAQUFAAOCAQEAJZ5cNW3mp1Q56L6VYc3lq8eVtaHqVd66I9rL /MMs467YMp8oD+rpced+HUQG0rHTag5UlskJH4QugI9+VgbToero4lwXwCZND+8Q ol/JDWiIHH43jKT2z3z8GM6z7ohIOZQ01wIcC766uV0ss9ICJKygq4qjxS2q+wSf up0au2GzCuJcYE1zh7rgDin6gGR5+eyu/IrkcHOA8jPsKJfLF6rIQgDRR6G9hem7 RM7lkoIbwVcfITR6q4zM0GGVxQZlX1E5Z4uqJyrtsiJYyayOP2mWdUSqAE/FLcmr bqm82vldx50F/AAqrklUoBALhTch7v9aIAnOtP9U5WAPXphIxA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2jCCA8KgAwIBAgIQQAEz8BQAAAAAAAAMxwJBrzANBgkqhkiG9w0BAQsFADBR MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 IENBMRwwGgYDVQQDExNUV0NBIEdsb2JhbCBSb290IENBMB4XDTE4MTAxMjA4NDUy N1oXDTI4MTAxMjE1NTk1OVowVzELMAkGA1UEBhMCVFcxFzAVBgNVBAoTDlRBSVdB Ti1DQSBJbmMuMRAwDgYDVQQLEwdVc2VyIENBMR0wGwYDVQQDExRUV0NBIEluZm9T ZWMgVXNlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIbK36k6 o+kGn/2Eq7F1f83dajinMMOC71bJxZemN5j6m4+B2jnx8bp4jrEi3COoPCYfz5qV Ye5tYRPrGT5EZM3M1YZyiXkV9vMS4Qgf+fEwbUcyoUeuFcXaM39aiF1lz+sjZI78 9/sPpZGmVOV4lEBUGeYdTlgSFR8SsGs9ilBuzT/NMZIX7oqu9er49+RgWsU9pijW VSTutrVrsvj/6jCvsPDVTiJuHrY9z1kN1gEjERjALeIx5q29euDh3Iay0KV+2BBS +wzbXYDND4YJEaQww6aYd4fA2VvZnPsLkN1Uo3113xHMM+yk432a5Wm0p4Jk9LMb cWTRo9nJa9HD+hcCAwEAAaOCAaYwggGiMB8GA1UdIwQYMBaAFEjbzd6O6UlyWojo sdg9B7O5a2ZQMB0GA1UdDgQWBBQafOXnah9hjkuqtvz79pCF7oQJ/jAOBgNVHQ8B Af8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMIHRBgNVHSAE gckwgcYwgcMGCysGAQQBgr8lAQEXMIGzMCQGCCsGAQUFBwIBFhhodHRwczovL3d3 dy50d2NhLmNvbS50dy8wgYoGCCsGAQUFBwICMH4efABUAGgAaQBzACAAYwBlAHIA dABpAGYAaQBjAGEAdABlACAAaQBzACAAZgBvAHIAIAB0AGgAZQAgAHMAbwBsAGUA IAB1AHMAZQAgAG8AZgAgAFQAVwBDAEEAIABhAG4AZAAgAGkAdABzACAAYwB1AHMA dABvAG0AZQByAHMwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL1Jvb3RDQS50d2Nh LmNvbS50dy9UV0NBUkNBL2dsb2JhbF9yZXZva2VfNDA5Ni5jcmwwEgYDVR0TAQH/ BAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAgEACjEGw0ouKFFxoQrsKBEdofjE VK+gTlIbGJ64SVOoUd78nliwVjq4CQ2sF9YcHTe4dNkSyxtfTXBx+Mz4Jo0Gz3lU tVc3aLZJTQXdl9kQgexnSvkij2/q4Qj12ztBAfxcZuzinK7ciVKUX9YTjf5CQ8oK LgXDhzGM88TZ3uroekYVVlHFbfe7Fb3hC1en7Bz9+DAtKUtn+ggDOQpxjJ9A7UtN 88jLRlBQGkuHMc2gRB/d3royE/lTC2DR8BFkElSRWN1QaQqoC+0uMGpoBi4iSfrf 2V91pcCus6P+g9XL96tBpYRC750lOvVrSM67QbLN8NeeYrrMVp+6Tpx3slvIYqg/ IUBGtjKsZ2LofIuCIPSDVukDFjWD/ADMACZbvJT3PHjMdGLl3g+R5+D1yEd+4Z+Y Xx/UWJQkMGP3fqogcvXeCK11/i7Eordx+70OoRm35OXqir+eD+axh1q6tdFW2rMA 4l9ucplQhBnUASdd5QY7+8XgdLSpLd2gETufG1Gs0Pi8trra5h0rEs07utgGJVlI T5ktsal5UnmHMWl/dxHKrKwWs0VAgXodk1zHUdDIO6CZnnDYYeVMBWdlilI+e1m9 UacPYkJ0cRdPggporXDLhqR4IyxqA4ctiiVYUnEG8iIv6qLejLdiFPWjd24TKJPq i7xmF+pwri1jiK+Giuk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkjCCBHqgAwIBAgIRANYl7igApQggZMPzvraNfoIwDQYJKoZIhvcNAQELBQAw KDELMAkGA1UEBhMCQkUxGTAXBgNVBAMTEEJlbGdpdW0gUm9vdCBDQTQwHhcNMTgx MDIzMTAwMDAwWhcNMzAwNjIzMTAwMDAwWjBmMQswCQYDVQQGEwJCRTERMA8GA1UE BxMIQnJ1c3NlbHMxHDAaBgNVBAoTE0NlcnRpcG9zdCBOLlYuL1MuQS4xFTATBgNV BAMTDEZvcmVpZ25lciBDQTEPMA0GA1UEBRMGMjAxOTA1MIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEA2fPBp+iJQOYudXVNrC62hpj3X+1V9yJdXLPeJi4k IlPGiEUP4IHqxm4mCskF3IO0fCne3/19QczP3QJTF0LJXDF42YnKgi+4Y9vfhGwX PZBCH6Gg0xYwyXBp1bxgvzQKzelNHc7p27vQc3RIqbu++T/JKAeZijjpCegs4Ifj sTCBgvm3lRmRciN7to+bio5UhmbsXDx1k4W1x17zuFsZJtcUR2Ve/nar+hbkHMQl uATpRUsrxQR7EbWCBtFHt+oeARKoKnizZZTmnd8eRXi21PuHjBMehr8hWsOPVxjj T29PL4nFEyZ8QGl2/4GO1R0LyU/s2xK3PnbInlFDY414ga8RlT1BOC7iqDp5dapH Ox9+KP0ZgwoUVOGIl4EGKQpuYUq/BH9U6SeNLhI14iYQCEC0dfu8Dq0WfcFu0dbe 6cxxUv8EGBXLSJCp9n2Zo1g0YbE7Ez88LVK/e/0HvjQhPa0c8d3WfksT7ab5dSvM wi7T2ihUkcKemdE6situIJd6csEtleeZ0SJbJpFaGFD5rAiwy8LrXUtn+izAFIhP qAnlOaDUQbz0BPRaMz4MfqawRUZU5uYHiYfKt6jtDptykZUb42Ci4DEp93AzlgOX CyoZFakFyfRtlPdz4fqGSBUFS9aFkw30QhAF2OxMrpLWHP/dzEyqEyfjojtpSkCc ktcCAwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/ AgEAMHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVp ZC5iZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8v b2NzcC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD 2XrZW+dJMEMGA1UdIAQ8MDowOAYGYDgMAQEHMC4wLAYIKwYBBQUHAgEWIGh0dHA6 Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0 dHA6Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSe OtUBLLA61M9RpktzXtOdwjuKbjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH AwQwDQYJKoZIhvcNAQELBQADggIBABFmAdzLv7s5UMZsdebVbXazXJn1mzNwEhqR QwgV03S0+XXGztchUP2uILl4/WvPx2LAcPBgL20PS2u1B2KGVoHxYKJ61MlItjsM MmIhQUKApE7QPlkrWjlJi5RIIXe7XcP7bYTLPeezHNql4bC0ke6D+kS2nJachxe4 f2c+BFGcXF3KuEeK3n4wHVBk68w6q12044ijFVIKjvhQOudRK37YbIl0sKQmD4FJ EcTQ9lRHlDDsM5NbMzzL+WER0qQiEiUSs1nLgdQcx6ZO+yH8OB6xLnV6hkkjy8Vf /yjlK0EeV67yx75aPFaIuPnWifUGggILyOyy/KQsAtshmCx1Rx27u1R/Ta0E/PKK EKDb1EpYb7Or7yuvrQJEfhzryAX15M3W327k8iJzqcVX8dTDpkUM9QAhcjaCOUpV xTE61CVHDUHsTrZALX8dx8+hpCnk509ZnFdIHfdhwQiRWCc/1WliXSDv26gOLtEu Jeq+AavpFhjlcOnLFMXjgALGHyJa53T56DdrfmjdFSXdLcjBMi0KWlfos2qI5Cpy R3xwxdTPu8sUuqfKo8HpylDJilDaval7fSp3N0D0iYXhF7Ls1dJUDd9UBwL27hhN 9mW9Wv8cVcmfvkF39sVUrL5VM4xcNztc/R3MIuu9/eLQbPf6KJCIXlMVW7LKMviX G7E+c5Gw -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQGJPKaZFqxMMdswzp8It6ZDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTA5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA3fC2VOtrF/FcFfmqq19XgtT2LInX98vEKuDpmUg4iMOX NxEi9fnIu4KV4LQRZ/Mh9tzq+xJCb0bDDwHP01/UJZc6DqfpMy/FiClHLFH0fMkJ fbJI9GpzZQIdQutBWyWxw+DlXG/oTPkDUQdja4QyU5Q7oyKw6/VnVSRGXH5Qv0cJ WLbx4AD4NRdzDLGHJJhxb1Zgs8DTFFl9PqS5oMVgR0ACc8SWk4jVtxerMrL7UXc3 TP4qm+uZX30GQbQKKwlGNPYUO98C8OLwsbzWVK/cMav/omyQpolVLhdzDj6dE6Xf zDzVaiFtm5HaN7aupqsrv7NoGooPzNS+Us/3Sj28VVdCd9HXhwUjzt9Tu+37SLVq SKoWIP2qNYyCnMx008zS04Ru/Vve1Mt2Pd1JDTMvuBaM/NQsoXe/1AS0jxOH7O6w e6OICYM+tdyNEZl67pgrdKU5OLD1uFk0xDB2usYAA4L1jZwURcCLKOniB5cLErZc OiG2m4uw16ohn+5E+zVqNSBA5b0PnTfmfr+217QookQ/iAM/cIcBKii/0tbQdfBh 7uemr0EHEEOGVDAnFqMLZeC28tY632UHudrtTAymD6yrIasI75eJiSJNdK0MuQ4b CLj9eXXodaV64TiDZYCCki9QWJJWj5e1lH4V339PSBaUQ6JqszZqTPLfQYJ7O8EC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQ0hQbY dh/8qohNB4LZjf36lQPFajAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAIcOIyfvE7dC0TQdckVseT1PG40uHRY4baq28m+8 xKwiLp9MIJrRATA8SupF6oYJHiz/jHFK84NJWo9SKxo5bx80S4LVP8oVouoduaZL s2YKk3XuVu5I39WMLOO90RBaLTuyT2wd9korL/ShxJwaTleG0KDbL18j9RmR9dya EzcRgKJQ5x0r7R+/6eQ8iOj8rjBmowtIHNrIhRzvbtFaAGfkswq6FkesopDaO9JM v5frH65+WOjDt2Algg1amjvzeX6ApU7HOdmct81z/Ypdpq1IxpnnkRO6BqaTQ4tb kdM/DCi1yloakAGrGYSHdTDB2yms4oZETq9NPps162lwE80jWAi5CodgGHw0XIIS RYdp8qI5Qhw3+toXpZU0X3MCcLuyMCASU/iX13KiHUYPxOPNxFPV7cRceNJTfWc+ e4/ZnEYjqie2TAOB6rq/fLCOn2uKkl3a6BAijS98dYYgS9wxNL4qp12q0mI/4yb7 HkIDwkbCLEy0rNEuNLwgHfKVGIfIbTOtnQkUXYJyztJb1Aqus9uJ+rfr+WIEzLMl NJezwUzCI3q8zpt25HjlU/2rYarF/TaKRj9UE8tr6ArixkDJQzrB7pizJRzqAueU 4lRyBL2ps+5NKeA+3LxFxsYkIvA2Ajl6NyFGN6pRN/xtgZ99kwhmXAPGedrRmkLT M+OJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQKhF3ZYyIMoPt1IWsUPW4ETANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTE1MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEApYemoCjdecP/qB3fgpglAsghpIJqOaMcRI6hpVgrLM+j SQvsoAPBy637byFDNTmA4AmnTOIVcIfW4QujfAUrhppOsWI8CowVLTxUR8803e/A NoL5cAbahnB5AYdzOtE3cFbLLT+DEIdsxqkjiXhkR6MQLqxKMPTaw4KiNQvs/lvI RvydfZAreH+1awfzWMz9MJEufAJ2QeUz7KZRcE2P16upJXOAQnaP8+/xBaOdSH3B 3Z72+4gm0cNbjBZiH9Rsdsy0USIeEkNb0PQdvVy1z+TEE1YrgbxmOdPa+638bveG z8IKlj6iyhkdAIM/RTQgd9ZtGU0ig562FMu1VsXkZy9JGiLfraWE68g9xgtRlxxE 7xaD0VwRri9RzEgbBLiiiVphk2jqsA4eI/xLTUKqTa2jdT+6zrjoh9DcsWNlU0Ms UfIM6rW0ivV/djYVmUoPiKZArfEw3bTJSs6scF4gACSkY1PcFBSZJqcHKDOeXiOR AWuU0YhifI1R4X8yfJ+ZbBM6fCDKoyb8jhiGzxnjf5QBkwZ22k0yJWRYz40DQJig Dd7hQ6M4TOunusJUP4l0hjicIISiYN8aubIzmeWoN3hlvz3W6/DS7NfpZF+zWfOw OL+6MVc0MILOx3KlzcjTqUv00cmDc+C3E1wbS1fMGYleOY1ElywqLU6qMujDtekC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTA7B/H YDQlHqWcAuNv9pQnatWT4jAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBACvDsQVrBE4lE1XoUNRgfo7I+362LiQMCVhq/pDD CbnPjqgXlIL24ZziPQ7y7qmAhhsFTMluJWRFVy+GreyuUMPhFJA++iAA8D5PMFD5 QEsrfFIGR9ShtGdbQQcwBxK4E6Rhr7kCktcSAoe+p6VcinSiigAv0VrVHULjYOpv UdXIxdMHHt0HiT47dCwMRUym0sRzu6uP4e2HuVjq1GtttpJzhOtMDwdHZyRrxusA Lnlkog2g9F4fEjn5dG839HM/QrUBIqDdH8gh75IPlleHrQuiAG2fu+DLVu5JHoeW eh+ZQjQuWuRSNIPScILTMkSkoV8dsWYoLE2QHjpTTJ9k9eoaqACFq9ecedbnBuqj dUbfO2G8Hgf0BLDJqobeiveKjS8NlHG90VCOxsLTKnP5MHOxogkaNlNaK2WvIRIc FkCfa3+2VCfJOFCfEM+vGepOqKLj0rRYOm4G7u4iVagN7jZi8hwPMWwLrBUrNIsL 7AkDYmpsi6ah4cl/TeDupwLm+RqN5C+E1Y/7+UW+JxpIgVK1Ih6jaORJOpRX6FNj l6LRLUkXZw236fbGTQESK8McQN1righET8YUYZopb7aD+Ec8egICjTRsjNqz77qW /7zWRjjt/x1zghvgNBOmXZTLlfQ+bIJNTXw/76JQW05/KBkJ7fX/5BI33MDUgeLP hwgE -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQD8te2hkL4ndXDrzFdHnbpTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTEyMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAlSc1S3/zP2YANMeaAYssxvV0Om3C0VenXc6XNQPBul/h BDzuxgjGkwteon6+W6PIDDBc/mGpMir/dzvTt8yaJUdXCINk5pyAjmSoDEScCWvR 8HiAN/7GOVZWkxkPL6+b5fRRseSXTCxNzMUTmp4ZEV4PtnnBokbDxuhKTHgdW8sF hc8z0HBR/SjnwNGmIm60hJspOetiI3knW6dQn3RD0rETxQi1fIJlhsPADx82ALHP qqebsaqQUwukHIF+CUZ/RkTad1ZMeg08v3zNApp8Y5gDq5ISmMX7UO877ttBg05r 3IaoFo20b5pjIXMQBekGTF5yP5SsJv/dS/0yPiB9q528Qihkz29EPDrq+Ks5+nSR dvgic697HVHkdKqUG7VWyWi7U5XGUID6XRfMPsWDQYI8CWnfPoszovWn4nlE1xVg kyVV/PpsmKD6g3vAngEGSGsMLpE1zRR7bo3DLXaQMkC0mcPP9t7udpaS38N/lA/l hkd/LUWL82xuEDLr0vn2iBTiu07eUeZdobO8NApk4BKv1CI1JU1iJhdzWiQbigqZ K0TflXF1/Cu0gVxoADPwNxhxvTELlL5w78WAsol3+keARKhYll+kvKVpK9Xy2cWj lp/eIegVM3BJarBEsPtyjjMrq0LxT4QUxno0kaqV07DXZ8qqnFfZfxolziEDgEsC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRP+O1M clLc6fXWnjrwrbDJOYY6qDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAGlaHa4Sh1ttEOziiebvsdM85A+QJXVb7yWzsPfd 0BH/Xeac1oAT8fgD01SvxSANaz2nbaonRnfSn4Gvz9f5hpzhWtwV++RS/HyuJmVh Rbcc2eOsV9kivaz8eP97faaJnBKGNwh1WfGTwTuh/2+4CFpioP6CfPsw0Cy9peVE OLvDJBrmHLylPHquub/r88dG6ow0bWOy6IteGN5m/+sdQYFNOxkBc7ZUE9t+7NbM V2yuvIQbNMISHDo9m5XOjzPGnboWDKkfd3VS4iPG+ASZxDqsY0aMWQVYfhnyBZg+ wiUSv2ATp3AUq2RsDms7L7ojZLUhe9MTRjwCL7cNySFlxXcpDDENjpilrPwSJ2Dl qiBnYNuBI6l51piWYV5Ay6juSStjQYdociswC6ps9Xww8qOmQC3hBH5aOUgWC3xh fEm5CnhPvMio6h9EZ3dlrvVRWQpSRBnE0NNEwwY20iWxlvgTO9jUnm6Dp3hFUJL8 BDKq2DvSSK07aqic6VmkwZ0SxLrOHpyU03VpStaxhRNXku6Ww/2PCIP8Creh2RIn F3v23EytzGAE/i8Lw/pgAignyT5NwMsY1NrHoSp71ZN0tS8klZz9McC3theS652C jAf0cjtjif51MtEqJLUJV83MaMGTKdoExsYQx8n9mVrv4NNqRTb2JTvcY8/EArvB 5heh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQBrMqbIQW2Dce8MU65aOOfzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTE0MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA8/hZmjLkmTXtCc67RGNMUDkwQ9r9YNj40IdUZL0yJWMc KT1RRGetEKRDBE/dYSCTyktnG4U6NRXezsDPbM6EAETf+uV8vWj9DzQapdtzwKZz ZHuNztgEkX/1ezb6QNikl0UG4HVXajNsQFTwbCVOVAVe2aHluD7HgXn2aZaRQZcR qfMVjsivgv7W4ByehDtZlcoaMiFbRvzD6P8qNZqmwopPTFQ7HrM8TpNLkRXYff+Y h7JqOHm9541iziRI4GH3PbP01MQPd29Zze0PRyG+xNynTN5WBZmKrJ11PRvyrEXx IMHmiMsUme2GpQgGeDcFXPsVigWvuBnXzprAv/LdlqfFCqlkARCUwsX5mPxUvIlE bUMp+YJx5/TrSJseHN9NWgQOV1xyIKKH5Ppuhr7Frl54nQKdb9EWBWZzRwBo6nnj pBuO3oHgJicbOIflReBukwmDM+33cBOx9mmrSVsVxAHBQV43AkavSSpHWauv703h wAReN71n++e6bsfRnYXEOwMi8X8PceKBG5eTOOdNlSn2LLycXwz7ckO1UGbeoQ1Q O5w+idY4M46wXxMy9tUO45rdZZueI1nlWwjAd+WqyqeIgjfImWUKJWtc7xj8Ua7D M9xer2+XuA/9y8tMo4uYuUsJ0r4ISXjergTa+Rwcm4BRAHWG/C4jDF6lSrFZeRcC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRt0Gyb ocuFubKq0BoiLopa858jZjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAAu3r7e+ZbDBkeNWly51A/KodrdbryW4JmbRmHbp slaEirWWiHYnqjwZhzZegOYJe2ZNa2OyvHNoetXJLhRjJ0bjxk168m8rOKfPsmEX vlDXUY0dgSSCrgmXqLWfuXeC1pxgx6DFSA6cJDZYbKiKKq8u04mpIIKHWC0M+EnX QVE4bHitOKMxhfZ0n47SKCruJLRbBA2KS9cy/1DaXZQUfv6xogTSyJ3IImZT7soj CpDGU/D7GMT+XdntQ7+hxCufw2oRwdHXEDeNZiDyg1/WEyremeGNciT6aRORbjNF +rSXg2YY020z4f3XzUkTY0Gk7NYw86UEu9CcuD06IUIsRsswwE62b5eY+zclo8VG 2h7aEhXyDT0gCwfXeKomKuQoCKpWoEYPIlEGctzcFhBNc4Xt+9r9alVGx8aXkMQw an3HdNW1SkRJ8bGG3btcH8VsJD55cNlujDv3yfxAKtBEaWHy8IK2T6GTS/YtJ+ts yRsDvC+67zxktXck+4K3itYi6ger4UfStlUl2GggEkPWwatVFYN4nq/Rp2AGllKu AyktU/p6OfbBirKkF10dIgvtuSwmSxnEFhmRIFuHoVs/kK3iZ/KLHTeDZbF1CipP iryLMhmY66+BwwwJWaTCBkj88SotzMNVdSkLtHT515GP3bZW/Y9nKZgQoGYGTahG 9q7R -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQbTRg24cLDcki3ht67GWHWDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTE3MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAwDw2+hl9JF8cJ8DxzDARgpBCYsplEKYwWorVZUNrg+he vkwe5/vsUeTw9533Bl5vg0vJiPJQi7QJ4tmvuCCIOrPnKHgRPmL+LEoPEeTLCWy/ kS6x8QVNWPAHFkmjgR2lOCRjZdI/YjMcGf4WmMPO2wzRBFqHxWvvNeBvhEfC5hm3 /ZpiN2Zd48h9SADzlyXX45hXxKfvki4imoKsqbQy7MZ1unSjwYhshWqK8Be5AbXK JPpsQXjQpZSZLMxVq8JvFf38adjjZ3GxRshJyAcAtChSyLhQjiFk7V8426lNuiPl erv2unadnRIxYR0pQIQYOMu9OFiAxno55xMDP1R96J53OqdEe/vo2NLLA7HWA6yH ulnsDivXGg91M7QUdaiN19qKdU3io7ZvxjNRsWpxg3s2hXfUq2UYGt8fO6wremzy Hvk4neqF81fHikWG/yv7N5N//hEq84ATpWnqVlAtMrEPfX7cXNCD3oTPOnKi+Ain VqBTNtgAP9g1D9WghFA8n07ENFzZI67N2goz1rCjYyZxwkrQufiY63vmxY1D3FPS tvK7BucmJJsJKsJR2/s0i+gcc2xvzt7pR3b5bZ7vWJCLM1dxdE6zqzkozoAd5jHA qZLg2CN2+my2qGkX1ckFyXfjVM53BDVskohNJdXF2vM6I930I3hFyEz2O4KmH5UC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTipg68 Qco3aoKAKYTEDwRs5BnphTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAHl2jPobJ+Z2BPDw1MZeA520Yca8ef13DsU/PQvt VKrzfwH5QE/DRni6QO4d930G3OwYCxI+pTf0R0pxt62WpT+CQ4QaDiWjTa0vV9yQ c0uc0GEvlqdkgszYWkjaa94xbGGiJEYQL7yPwFEhwHAU6TTdDej4feHBhsMeQF++ uiQLYOTRZeJ83FgD96NhAfKnCc3zR3KE04DHasyHt3VrSxWNwDg/BlVV9zhwWPMp +8CyDEhvYyBWkFu5DUbaXGNnQ8kQLHXysrbH4UnxKsbd0cGaph/P8zoeJIpeHOIj vDfwOJVcTwZIdNjawFB5NN4J7NBYtvJdKuujy2+P9rVPR/9sNZ30nclqwmbfWOOn Z8e70KINKQUxuiT8du+qFB3GHlH4w03xMNrxIypURzZ6G+DEwWwqxR8a9Q79Hrnp N8rUAHP33I3+CeLSQIrCYEHmfC3WtDuyUyUJahzILOs8eQV3OzxUEjX315fwOn60 0tK4cFrwZP+RyAE/e1uobkChEIV6sV3wNcepqrJaBCVHWRpNkTXcmHaGJznu79K9 iOu/1vjrNIk7FCUJgvd2sIF4PW82k9GZCo4u5+6HzINY57oHxylgu4dTlq+VgJ/j juhA4787uXpo2tetIrqWHB8dF/wyB3lCC/5gVZ3ATEc3+Si4Pm7FctDVOvVesDmG AJrr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQMFV+iSrFJamoR0XTMU+m7DANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE5MDMwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCSUTiPsvN5ATVbyVMKZ5PLswCx3PrL1yunE1U7y1EE 7OryV+T7idKZS7Es3Tero6pbkzP7TrJdvSbzQYmSDVj/HmiVFtz1ETHA9uIp8F2t /eg/mbTX8bZ0WnDvE7p+wFDpRftyHF+Wa9mTy86R/jHXlrgez3A/2xoIWw/3IPZ/ /oUCYQL7Ztskf9ST0AjgpfcYRmtMzZlE1Oj4MBKnF4jtpb4Zs33gsG2XfdkaEi4B qH8FbiRnpw+G3c1ydegzytQLQbXFpFUsNdiO6UxsFFK9MgAs7emtFneGxiX7bE7v FWcNHH9rDBVHyvLtboQKoa6OP6B50qZtiGQPppGh1kVzZQJgWwb2uouDvtqRQ5dT 0R/Q1yIRDG9n+YrKNptNf0MJkkgeAD7ODkmKTBsvvERYsp1/YLQbwm9Js4hv0tiW XOhFsCW5QPnW7w4V+xa1oJojYk7ay1H8wugijf2oZjAukEQw3CF4EPEGZcA7waNc gs170ewsSuK5qIP6HBoMXJbAplJ8kw8O7WBAuNq+bN4wBBeJWvWnYRNLc9iI/zrf VLpYvLbCmnss09hJLg88eQ30z0v01pYqycXvw+7fZLHUs9MbMBoR6OVFSE42BHaz K0x1iI4Oz0xQywKNtSj+uY+LCOFtboWncuqJvq3JU9oYEk/aubsxNosdhxG8KfMs SQIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFFsN HS1pnLyVPrxrGCW8p2/3X5BoMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAbxnUPA2jHEw72MIgDgp1U3uw4pOBzyOr8Ydy qAAZ8WgtDKGBB46bKQBoAC66nPxz7QYl/EbnqOGo0J0k4t28GsFahVqO3crZjBiV Ne395tMnb9MrOQpsD7S48DMsSyR2n/JrVGSTn18KbqHwEhgNfHiRS+0pgQmX0k7N nXU/2IABrGcdUE9hzbnhFhEfE1/F5e5BpnYaJzHvoFfDVf4vA7w+Sn7LaGKXa+4n VwobBWq2JDlHhakGkLmZMeR8wXdfcgY5D6Uxp6DXsrTfyXqPqkC9wq+CGjV7dHWw DWxTOmEq4t2Ty3iL38j3I83Ocs6Qg69aRkg9WGX19X1jKAppFnuReELyUhbNrSMS WkDGP5F3bfYAFhyendgtf2d4MwhwSqhQy6vEuOu9cYoTMMHTFMdGLcSD7kwEcOwN ikHyACTlu0wnxaCt6BRKEgpb0L9l0zuwL85h3NuRSloExoJmeXHy5zVX6F+T4wZv zTL/hWi0okkfcMJDCwl5saeD6IdvDfJtqWvhpF+d42FGjrmKfWkxYbSNQH+KimfH RyVjqAuwFtDyN3OcX2FobImvqv+EXWch2fyRpTBgBetuMgIk+4xi64i4VzeTCdTW IvZf8waW0jheBzzuxCeijitX23vu2d2ULwfvjRnCb2xR/be4scP9B2nkOaUbh3Ze TKnCdKY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQJO0XoYvkxi1mz4Kv50zNqTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTEzMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAtT5nMTXDSpqHncYdefl/AJKcZuhRe8WQd17bwrrsr0B9 tNbUzRIZfkIyRxwhKZOFg0m21uIa/3B/+Tt/qEC9dSzz79K/Fkbkiw/++zxGLBUW QeD/nC262ytf6bYsLWJokcjY0kAevABrSMXZJOgph5Yl4u3mk0P/6Eld1/gJvvSP xRiSAZIx+ZPHI8FAXQnDKZTzARQP+OpXfLDmNYckJH736HGlXN/NHRRWmony9DCN mzn/uspstOlc+teJu2HgeCo2dqWqJvFFz4efQ73Z+Esp+TWuKd8mg0YZUMOrvCll yJshEgS5CnKHh3/Juj99VLzu0Jupxz5rNH/wZdLb1/WDcsC+C4esvsDyrUjYKMAZ ia3cVuOyMbWM4PIB9P7ANTsnWOMaDKJ8v8wuw7QvFGs4mnGLOXqZ78bxD4DixI0q CspOdn2YJeNsvZ5fzosYaWhP6YBbJDRDPJMXIVMzC4v/7LDn4GqxPJAyTHRrl7Rh yqG9uk5s8hLkZ77i+pNXbXoVr++rpAM/z1+U5JEFv5xmA5HXHqYTprNfLbuWXEnS CE67GSY8UEvaEYGgDvljwYTln9dpUV1OfcPXZE++O/ZzKTxCCjMJbdmoC3ASrw5c ChwGaiNTVKMCzAeho2qqQMn32DN64+DGYmy6lz1RZ+q5Ttpwz3YveDlB9x6wIM0C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSXAjSI 2gPgAv2J7m9MfOLlpJA4WTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAIQOFOOsCUKBhA++joQkz5oSMK/BcJAJCiu8AVsU G3FkApsNk38IyIKl+dEjaMUCs0PUeUvKgpbiXRsNhHxk1xNYhLWuqNBBTOyFqX8P 0Tw5aAeiOwk9fWtmJhCqXIq8jp+/p4cC55GC+sRK+dVCRE2DkZD89uvcN/byLZgr /4s47N0BJ0D99H+pzKLFdWftxleGOXtqvb9nV9zHt+Jn8PVs5tigM97/VIVsGQsC vZKCHYrBQBFaV7N8LPZLwkL+7437tTZ88IuxMO/lId+Sb49wllEwt0oVC2/NOZ0F eV9LrgX2dOrMNmftrn2C36MGSi1lTPhWp4sPdMxBe/hTKKQPW7AsIDyduf+bWII5 ++i3aXVRsZ5L7yi2vNedIU2Uz6FJqf4iPuTCFIub4T/92F+OWkS9660AV9ha4Brt r5pCNy2hLF1Lo/vVMl4yKSXO/WehEEnpPmElkej8TaL+7xATGKhqXxPQLtThgxkQ +6jZa63IpToED+vGRC6gfPPyAEpyl7pCkc17cDsCxBqWEnGr0Bdvmy6JU/htJY/l fQ17QZJmZunh8PM+P0BFkJ/z70e03nobwRSPgGnxUUzzEbgAt1Wd6jqjRZ7Eoel1 +vRp4letb/m9ELk8C8+Fnqf1VtLvFngF2ml26cXh1D6osbztMvxk7f2VNLPSnCSu 2UGB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQRMOXlL1r+TYckTtdC8ZkszANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTIwMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAvux5vXrTfmXNGoWvMBVnKI8KDwBj2nT8/XR1j2d9zX9G eS8qJmUJ6WM8dW7og1tTcaV/IIkWPikp5voiz1o6+LKmh3GRXsT/gbLpkOvH349k o9OKt5qdpf94RvT9Hb5xF033wjd5xy4Ura2vmr3X2UUhW58FqpQO0oROIO3MAnVP w/xB+mJF+VqwYaL2M6sOcH50VpdqBE4NC6mXPO1AVOb1DSgn7+bwudzSVOBFyMfl YHMfnUrA3E4ItTfvCJtbjizaDZdCHVm70OJVASkRYsk3/NZrr7OSHfchLzoTh6Vi DMDJ55fLc2eeEVSjKMJG48o1QI2Iw688LjDpX1mf0Xl9+VPBaag1Jq6BvYMlOZTu xNX1TaM2kdD4PHsyAF2tuuc8U42udt8prMhp97Qmv6TfYAfGAoODatdOEL69mSTH 6kvrMZIzpdr62Ryr6HyIvjemls0wauEYRQmqJrWwyH42s6FzHnx8fYDE2AI8Fnfz THxUxUue3GRUFJ1QmpLj3FjVWlyEw74O9h8IlsS0aZtiFiUMt/W8phRpOlnMJbN2 YOXs/hJwaRdBDnBNK2IHHeP5WVGoX9GTd+lHa5+7b+Wg/7pN/xVi9Tp+mAekYKji tub8zYBwIlMHJMxmlTnowOL1650NR66VxfcXjFyYFqcEW1j5dE/DAGJkwp3flvEC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSZfL5a 6ocB/87+BInrRcFM/jpeozAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAINyjiYiinHdwnpJNVJT0EW7jKGpGG6DnNfL7ct4 3t2UHvV0LTWkt0DgTCk1JAGO5FR9Z6xaci7GM52zdKzpYdk07rucwrowA7rvkygy KTLizL+F2usWrrkLkpvMKWOpBorkleNEEDoEn83QsS/ybRyXb3iKYzeQfkDPAIWO fN0AlHZoDE/+3sRambnxo8e+6i+mAdPXOIQ8XS7z0Wa0gsZ4O9uuorgviDnCWFIw 1gd8dh0U1zqSfo/lJHxjdihePXwlFcKQ7lGJj0rcjSZ4V19J/WnXxfik4gwX6DYh bezb2ottikDsdwqcrrjyhKMponbkvneHtfNVJh55nMXEXxI4gcEgdhvgwxkGVTvw 5OrAlBlsxL+8rLrmDzkXwd8aA8YfUxcBNjQ01J+uK4Vhs270ztOfbQ0mmWFMzqb8 ZFmscK9iT8K4MWvQ/mSThh0xjC9jwYZczEUCHRu21hl+iPC06kI6jmW1xh66ya1p uSsBfWGArEf/0Y6vPeF2PYgUsWqPCCN6XJ8pYV88XivVVR8AYokeOtthKW7vV4XE 9gJp4xV3hx7wzL201HPPjT5WQeZJC3Jr08+/zg32Qf2zrV+VWKhipgu2ksiPMK9v 3l8QhsH1lUVYUoxtiZ2lCQy+lz+ZFoY1NxxCrUZYLfjBHOEa1gRgKq9cuwNgMa2y FsHp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQGWcTiz5eAiHBeD3nkDt07TANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE5MDEwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDDznwn2cEpteFkMpxZZzYqwDHAOkkIjrAgR8SniEh7 RurvmPA4juhsYiU2lcOuVlIUIdo9nlf1600IKdnouSopYp0/YNKhjhTWSxMgTlSx 2IEGwOKwWUF/+pqWShcnD2ffpNGmVtVOcNXe2BRNMxCd3vL7201iIN6PEpHk+WJA 5f2x0hmUbIQ1l9X7yxgtsOkJKMkOzSYrpXohPtD8VE3fNBoat+bEfks/F9vGBYO0 QbSsRQFefSP9rotCkMZVnAGRTj1qShnYZ0y8OQ3dEjtLV/qkXll4D3Huqlc6+tRG nIN/qLZThvmQg5SjvOafnF7MTNwPfqd1CaTshwfO9CyLPE1JOubJBGfsmNgZlAG4 VT2+zRASo5oX9pORUs4FFuLdQ3L9zxkU86VHFlaJIc2XrKAUdjsMN1rn2e4WL4VZ VkhSkyvyJ399Laq50hqSPyEQDzfdDWQCpMVp5SBQGhL2y24dixHUJqJq+/qzQW+H a79rV4SW4P+ZuXEKj7RPjY4skR3M3Nb/XWzXpgOUjrOuJANh2NrgGE9mf8ja5q+p EYQeAe4fvSDIXT3M2uqHOjNsIL0rv/wkHdU2Gwmc/hfO2btOlog2SJSh8Zll6NuQ s4pljoiDtCUiLbfkxuUahB0WetFZJU1N+KLHZV7pxGkx7BtxYolps1hs9EHYPYB9 uwIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFKd7 eEnyWdCYiDQeOfFK6VLzGsA2MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAX1UrUjKbk+uMNSY5wQXeMn/f8B4odA22CB3t 2/3sGyE6moWzCmGrMOX2qjnjWGNmcTJEeiloZKA+X6xPb3qZly/hoeI287JxiaBx KCtlH7fQj96vk986PPsX5CbuOmnaD/bQNc+jUSgcoRyimgy4NlI17YkTd+9/Ai9s 1Ifp9FbUeuZpVTZA0N2n/GoeQgkaOUxKlz1ilcu8zMPO9GfEVENUZMXx0nJgk90R 7m5PJiSB5Zyf+osbUfsONBdYMuPLamC13NXAm++2JWaRZjeqEf6bmBorpdfU/2ZI 3aSJyMK2nGGpOmvZ/J0je3JxBGxHUEmAmFYXXJOhevSjG8MMyNj6wliVxutIXisx zeVtOoHaV0VdprFh/LSGjtG5FHRlev83998mQdvfSG9NsyLaf2QDkQcXxZbbmKhe 0DUM9+PGp7ghaUy1+uZSVuzN1PXSBUJtXRnHyWwVPMfduJDPz+CIsgUrwUG6SMF/ lVgVSQoDzyrYKwZwi32eJRJmDmxZ10B1BSfHhPH4tdha40u0jWp+N/2XZYPwquLH aSmeeNgt32kPgvGss2H/HKvXY5BdiK8W3OscdoFHasCcIJRv3wAUu6huhgwLZskz Icvbl2U4iYg4Izemuaax0bEde5kT5ajB6axeWsHjjpDGqZpnFMBUelGGGrq5Xi+6 JBaeITE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQJczt0Zmi9LYx4U11/B43KjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE5MDQwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCtIdV8jxBo3Hb652wSyxzsZxVwhNLw9jHb1gTowtgW ntrdWO5qA8NJIxxNB0evA3slEShTmW9nJpW+7eC5K05oAxvblXY/QWIjJ3ocpbZ+ QV5aXlnVkAVpTj0vdIq2VINjnD6yM/q7Tb+kefUDUK8kHtdlv02An72yC8/5XF7Z bspS+lsV++s7Jf9qrQEF0zM8vMK8ocek2iykjwaPTFop8ok1d2CyQdhfxAV6YjLK /nS2NM6rqrhN0cZfQ87+K3QG97qHTlUg9a+N1xw0+mqBv0rXN0HbBNq/ZeC2ZvoY CnUERJUI5iM+MqB+FtdMzv4vHykyjGebuRHgct0ycsXNvHw8kWevacx67ezx4ec1 Go/RjJ+FVWROnz0UMUYDGJK4WB0HgUAiaeZzeJX/k62UIZuAog+sbCh1XTN9WGaZ IRWpBmu97yBorqupI28HuNr4Vk/XOYnwPd6rWDIcyAxlomvVoVNxELA8ise6ncTO L90JBSlJESQUzEbPA/iQ0LWmuFKQWSzXLjbZ0UfqcxHw+vnvHCKyQhoDyWSzibQI +tSw+EkuODEayniwJpTxkps43llyUv/M+S1/nTPsoRwZBjt7oCSBJGSJp1G9u9/8 TpfJBIqCl8/C+UDi6j8PMZqNySfO0J2WS5Udn9Igfj2iPYAqecA3NKxoaAcqUKyW AQIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFIjh Ai6b9wdmYXaBx4r52x5sicIkMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEANegA+IoU76HInumkqmodyCFciYcQ/eOwjOzH Iv+kd589DY45gUL/LO80R7I+GM5E5Mbb/3XeTMo18ldQsGLXi9xjldF7bFsCeqEg TFs+PHad18w6w8xiOh4aoVJoTq1e0dudaRpMX0npKIHwjPdqudgU02KeFnE0CkJi k3IGMFUiCIM9CmhR17dxinG1uZr4HLmUcq8cHvH1QOWrItmUYOgH2g8SgCpvswmF bluTdTb6iTOW8r9sAWdUo29vRFMpou+3ehWAmkbOyo5VNHPSdn4v1Jdn3IaKuxXh vx8UClVu4xzzsbmQS1kR9mZ1DXMOuSKDsHCtlZb7KVM64n2r6slv2kCIbTOX5/s/ Qk3FLz0CNnFj+o7kihFH9e1+jfJnTm6kSGbqMrgm4W8TMgRpmCeszwyflxnVhRsw FKHoWJkS/wPHd28WtUvLqKZLJkVqQD+3iL8CWG3FZ07/HBSBN8S99VY7H5mrfleB cZmp80rW9bozN0AwGiN39ELmdzLRk+BOLGNsPGhdFCusgR1k362YDu08Wn/zjkZ1 N1wSP/TxClwV5zxrBA4W+8C83mMXkcQvDKo9xL2l/uJYjHt4ijwFd/XCfM+DqDC6 I0u1i/yrse3zG1Yqu9ovFnAKE7+uESFsPN6InSYiBuCuPoabTJ3Gi7geq1QJWAkW 9Li+0ok= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQaYeK5jbXVlnncPGg0VhjKzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTA0MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA1weB5LSXPQMrWAfMMqrV7kf/QEQlYCYdH4WuFt/aW7Af l00d2VjrwUFwORCl2q/dcsZlX1A9HXupywri+s72J1uJehebh3E5/d1AKKU6We+V qh3EmEECXp78L0R1yXYLAUTapKu8AU+v+eqOUsSH8U08aClr46YVCZPNrIYPp/nO ns/MY2gU5eYKGv9jWohLjABXDQ1DNXzozUoHFZpwQDwBIYmwvhsCMD230j0D4Vlm Fy9rYW1oNrbA88T/zhcwARwwCJ+IBTMQvA1/dp5N1t7iiR/zWEVwPyfR31JVBxfP CizaoRlYieSiZ6k9WxtaYN8vLpotG2e4Ian+vS2GEE0h9dwbr9Zu/f2ZTTI+FnpB wRyTdYdmBfzVAyzoTO9p3a1tvS6cnyJkFLwtwjpvZjY/2eJFhmXhQItEqZsMIAeO HibrozCxGkNeW4axAtzYY6eNz67szpL2x9D/FajSKohUOp9o0R3NbBwzBTwN+Axd iPxNQktggeOZhfUX6Hr2R1bAiUJUYWRZ55C5IiRI1e043Mp4jCwP0lN/+GtFof1l 7eZQyn1ynt/SGi0Zzhtotpn2qEVlxfOvvYk+zgFWzdapdIoxradiUaSif+thxwkF Ee8UZz+obvtIDsPql+9Be7A3pEWu98l9srPp3qTSg8PA3CYZBuV7o1zytrdKn9cC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBS3kDuh bsTb+riqeE5UVkhBpT424DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAAYOAp/et/SrXlulHq75lUocDXfspxLSUMtfrEJ3 RiisyduoKu9Q9BQ9SWGjId7CyoPusfCAttuNEDo3r+Wv5G94yfiNfXo6g+DBi/w0 uGYCRXGR6UVrn4Vr5A29Sy6TLpSYCUPANpU7P+KWo+8ohX2ToztxQFVCCd66QP/D syGHxpgtps7KkaEqZAwwxVRhFYDe+ihccou6hOM7suMviZJ6la+vpEcQV7iMV12M zZkMZA/jckEzvS8MYOhrmaSirXKRx2pE4KhcswtpBoSUx+pzIHjalF9uT5Z+pdDL qMizwNTzFb4NxHARcg8wnSCgkJ49C0yZ6owmc9o/OQ7U6R2Nj0mcgKZdpA7v3wne GGwArG4Z0475L7y+LwyrhT1ylZhgAOFimyhzIGM27gBSRd3UklC7hmm2D3wBfMVr gLtFJM0lQkHxz/aYmwLx6Ji+juw3qN68HCV4X6gATPEgMFHB9OTNwu5ii4vYURfE fJjTiJF6o027ZlkNS+yh+8R0U7shluvdXkW8v8TUk/uA80SULkSW6E5LtAqq8gFD zhSrBXLPIFom+P4yulyi1upvwLxH6yI9vFhPs+GygbHm0yLCPKJflj7EdVPJODHp vJnVM2Fu3pigKhnzQ+EKK2HCKBD6hLpHDEf4DO1dA4UoGzbjcbQ3iSK4CdloCBH2 wxJQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQOcg/S7sBm/AxI3FQxYtk2zANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTAyMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAsBx4dWk9Ku0al9kIATPOsBZ3My/P2w4Uqlww8JRzwKin nMyQGBswj2wMu/G6Bun98aXpW9CQnKZLsS76pJ55qsJX0sWvdYScS1dC9KsEdonj VmWGFKWY5/VABcSY3mQ30cFKK5OfbdmA2e1FXVi/lMmJqN9rf/VZT4H7iGA0YSwv qqJNjFIRM9z3+oMHdMaKVHngRED6ZPopgWCYHy/SDAqSAVZotSlSt41CjBdedni1 4I7Slm1kq0Ha5raeeSdLWmKUlTU1zSyAgzlu7DDvJwLXtOKn8pxqzp7HseWlykSn 2Of9ixnb0nLfDdH9gBJ+nbbjtM8t/ToPTkWMpsWeYcJOrG+RtuQAboTtfcFCr79L 1lW82u1LI6ohSxXazF0/AHL0IuK8ovHfBcLrdbzl5EqT4ofz/hAKecrbnZEdJXXY zb3nXKlBSIHMwsLw3509R089XSns+YAREkHLLfpQvztTbqkdXtEVT9NNAepFpDTE T216L+vVUCXWbptegUuV0MqJQBymSE40H0J22crmcsyF5poHU7YSH+Rhh7oRzsPB 1hyJIslpAeA2v2/VlCKtuP7nIuDRnMEKiXFMApgFioisOiWkxJCr9guAsBsdhZDJ n5aqwfQiURQ2XiDkPKMQ1TV2Uv1p1fCWL2GcjY0EG5dEydTy2XebBr2Q9S0ZZZUC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQA05Fn b+XvSz+FBK6P/ovQ5tkSkTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAJWAxdP6Zr75Y1O+h4CdjZHpvVOo2MRf6BiFeHBS pcyzUeXepr1ziNYVCZgnfj+4BOQF8tCUagCRs5d0MpJr+aF2wHDRHnVDWim/u0m8 8TjZL3Ya7yiGPa2zBZjT2EYJ7eL+317r5ZOz+0gqI4i6IKlwreHXHVUw+d5RFvjo n4pJ0EyDqNKKTsZ7XsT4bxG93x+WGuVxeEscDQMIyp8yNVufW6/5FyOEz6l5sPv/ QSL2oo+8ZV9K6tteo0aQL9sZXWmHQX0Xw+KUMoUu5sQ7QlP0iVop5NI9wy+7SBPw jKtpJF5lnsjdxm7vfVahhXnWiKrSNt9wuuGlaf9mLW7lR1BNmmpiB+n8wcmVgQUI Kh5fgoz6keDXYcoGymt8FyNHQXXtO2NxdjjyNe05nY/j8yiWqUUmlGHjnCHCuB9f rxKU80rj23Jfi9yC3fUXSNxR6s7iEWYSE+icr3eaYeXAHUO4W4oqGeMD0PWpgNhN CiW8bW+a/Vd7Pyy008Y7ugCHtfciCIsz+tUMvAzg6tvVJohEN25d/2qyyjnLy9FU ICxP2qJM69U+ezgr4ITLdq587NXIt3ivqQ+mYDrC39HBGQMBA5s+omBOW2213ymZ qUyGHRb+i99Pl18kYzBLLkmh1d2w3frPveDG3DfOHv8ijCdH6EWNGAP7aFgoEuzp uFsc -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQXpNR6VMXgxMYXZ/1yr4VbjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTE5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAkJO8c7zx86dz4oxpHyDfitHzXZZ/1YfljfRul58tSu5s EeQZuyG9azy6/uR6jYUc1GyG7cqI+ZKasiSlgUOkZW6rnaOkR+g316Iu4jXBMYUW EphcdR4qM/dPrOOL4ax0zzQGliZXqbsrjUthYn07I++kd1u2s/EldB48ih2SZd1z wR5YwN3+J23E5ywZVo8Kflo5ki1JBrs0Uwm74XqO2tA+6A1fbCiyZ9ipy/zl4Wqd PXeScO26QovATtoeIf7bnl79rFJqwr0k4M3SCldS0nv8xQAnZV9ZwY3lAb2+q1Ai kMhnVHfIBC1DdFRjLIdFPH7KfHoWcpJTzrkrhOxIefE8tMM4TlMhAvMuaOh6c6Xc q7To3YDhig2r0s0XljaZ4h8Om4/okDeZb3uu3gzRDAJSTX/SNmKRQgP9DdwnwetN wprdPzVu46PIAfuyZ17RK8XiUfm5BZ8CXzhEF9nPo/pyg6Z34fMXTmg9fmkjFbzQ ghGu3MwhbCdeT1F/U8cqNxktYgz0qJXjqR+YSIDmLIsln63ozxreR3aMY5URsSuG AYT+wG3QCN5PyzyBT+kgSGyp7SoJFoV6xwUnV1GoIliqI3Cn9KaxihhGt/Zw3CrF 7L7P+1bNrZOOF0SlTsrh9h17R1dhUUFrPAFnR7kEV0F1/MFv9VElYHIViJSLoWcC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRzqsPm IftWLOUiSuS9t5PyS/b4AjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAERqPKSdDIz4iioIUwkGJv6RUw/Ce3wc+syWPL5Q +L7zSX1OQ9P80kwoeiGwGR2uefTOruNY+ZuNPWO7GnVtvYuEGlKGhyOSwmiU6BXe KpZ+kt9J14b89Fnf5lT2+7yl422q3VDEUdeiNxftfhlAh/5A4ggEfq1JG7ymIcSn HrKceerEPNfuoS1nXquwZtDzqIAg1VZbfW8lLeCEBJSpGbT61HyC22ky6vrWcNpg g3dGdv8RSYpOo/VpvwBIo+3XbU+ijmEb8sEQw0IBae/xsVcMb8CJPPYYjGhCjzww fF5gwfFLyQ4EeNr1J1msxuLKWnU/szRxHHyyERgYE+rr5YT8k6BFiLdHOh9IecFO jK/LVUW319/bg1ozm/E/y802R5IjODriX/Dddp447gpO0DSo/Q2xaVXosAn0V/SM s+v3sutrjY289wTQZlR5IqM1quR6YRY201j7LPB9t3QcUnNF9PT0r+numM6qRPJ/ /8LMXTK7vX0oMMOGbM3B6BNkB60OJbydGwYggIhzaQyPAwLOeXk7Xp+Is05likSt HvT+KI6LdV7GJq98k9MLk4XU3AlawXKauUc1Y+FqoxwOiegMamo1xvroWn75kEPm mZGdCyPNhgn+xuPiNTodlHIOZolgPzU0IWmRa8EZzuCcqtALmeIfHL56/PSyX0oJ 9qju -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQL/WkNaKtHylzOl3jzIVYQjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTE2MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA05tK0UzYl7PxbXiLGsl/gOjpqFyeYHGGPjWtEeTF1cVe U4BU5fCJlShjjEriRULTTjiEhZ4r8czO1wJVfoECFjPrcPMWCshiSq0jIapyqeAp XZpmvri74mhTKh2p6vqs/sZpRxcr6WkRz1YnWnc6p+bp73dktQbxCI08KliSzwOH QACWe54oKzofHihGeBsIaxxxrjppRjXPni1MuOsi+KJaRLgauAk+HtNtL6ATdgFw cv8gmT3tcp7lY7ZAj71d7pmEOeAKIIbJC+A9G3/gerwZSEBizGbtxPuWcu2foZ0O l1H+n7kDr7JWpCURqZx42tC6ogzpw3o/x3lRnlku+1ogeXAfwn7Z/rP3IF5U/Z3M D1ah1K5SoENif24TNVBg5jkWzOYFruQMhAnWHDS2L4TOqzlHwkUY4N4waDtlxIg7 +f+OiKolc6AyNYr+IYfibvP9n+HvNJwbynpcg5845WXpooUolmTsA4Fh/GdVLPdw FBi5jLCTAwbQnR+7lo7je+/k5EYFa7/XVHNBflgDiCGYj2Kh0LrUbZH/bRJd7kKD YrhpWI+iKPRfriOIGZha5hQ6S4U/e6vZMYiZd7GCijbB4EQkHsBa2ezUGt3tuepO 9z9PSWwEkMCmsBohXS0qTb3enS/gbh042rZZe/XNVCugHybJTR4zcqc216WfIaMC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQDaGnp dRXfUFTXwbJHjMRisywV1TAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBACc9D9zDlaWyFQYBFh12ruAFuQL7PRWg511bbXl/ BnANk93zeaGIG/TaKgNa67s3K7Sb4Avu+ghpqe8neOfg2FLl4wxk3QT+L1JfZsiY PK5RuFmEJs1RT/RmxIsfzhO4y71HJ6vqO/iTT01R9CVDC6aVNJiXo6kSHhRQCcyp 4uX6twQVB7G0/3Oh76K85Un6qO2R18bx437lPjYtOP03XHL888kIWFfzO84elPAH V5gBd7xzcz+BuVctcNCSOxBi2neKBHfWEy3+ByhuA58UhsA0kgUeddWa8wGCI8ZN EfS3ATB5yLmyAER+Y1b1S8xtUACikscx3g/JHmx0oJ6NsYYbKXs2/FVeJP2oYDE8 k06nOIckxaabfo7MaKZS5NKixpAHUlIzR9niQ+n4SnvwWj1N9CUxrjjDpYAsb8hI eZSY1lseTXyKpWkNK86eu59z+BTPITN6r5Z8RvZpOhygLfwJAITVv575VNDUaleq xNNPyzLVB6A4yPfbBi1I+U/WFBONFiZR89jIlfpL/Wlfo36ynqQWdCGRFMyjQb/X B3HzCxkjExpmTEBc4r8E5Wp+qsbtYJZVs1myC0W6pYUmLatLtbURHuPGL/G2J9pA Klby1SBwd0qGdFz7kTVXD7XjmTvx6V7fCqNl5FTl1cxpa6RPSwyr8RcgIfbBa+yP RBgx -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQVouINCv+bckpNdATkJcGYDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTE4MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA5aprU/hoXjei1pgCKIyTaY/CJW19SAAw9XziFpS8ZGZj aZw4968lDfwyjptKOWGLD6WsYoNI5wislUyBSXRe9S236zXbS9wkB7zv4fKhAMwK 1j2UKGqHNjvMSEXSqxid1+e4p3c9XTjfrWqSIXZIf8tGk1PQ+Zjrf6bUhyC4R+mQ 1hS3CBlI7Tpi6A8ZxWBSok6J7azQ5yqlCbcSQ1glv/8s52NkqqVojwTKynmcL4lA gSqf7YahUmjRgj5FDy8QW8v0qhe81qgjEM6Ot1T624e/LApQKqRPAAY5oU7h2kIl 1C1ZmQMFDXISGUcwE0FcVcFztRFEOnHMv/gCEBoReD+iZYwcwLnyPbhZYKIurEpT scTyhjuQrYoS6CYydfBmuyyM9w/HLz0b8ynDKP4B2hyjDK8p9D/IeeN5iMIDw9Ms QyLOpruuxsEWSRaowuj4g8Sjy6ddBtrM7VbQUdYu2G/ezd/Drsk8TIFHn6Tp/wb5 qwx/FyFxPjiYPwDzyET6juhgugffbuN0qP7BBRJbMt811dUpekbMxTkBpcNcozlF ZRIk6Heb+w+jMbxnIT4700Q8/fMJCs/cL7EL3m+GSA3T54hilCUrBAK+kwjeLOUZ 3bnTE5wiBcEOH66yf+SAdUUqGjFQablWgRg/nR54nwCiCXIVerMPIkrsOjIhuF0C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTCxlG7 DPhSqt3WcPyhq2SvEx/+YDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAJR2pERlOlVjvHdlDGYK3ZQginsLt5PwpZcWtUuM bRL/3zMpF/SRRiEckS15gVlxhrnTGWaPoDkrNwcC7Ty3UV/8Z4JbTvFWXZVvlM9T y8Yo3vBzG8ZVSZ9wXfNMEhMldQhcF1drlVT4p7m5ZmsG+R0kjL10o+A4JuD3jLiv zbfxfKAUENwv3iSemlsW3PG6GayuWJZDklj2hCK/c3VJ8HzKtTdv+BbGN6bFPjSM 4n5V6AtQrgwWud6KJVtamjD5KVUGOqYzaIunpypt93J81mCqBy09WzD2+nDC49bm JChar4lgepdcCtliqmbFL82B6HeCxTSMpY650Xk4BLtqmJHg3rVv6h5UDaxJ/OGH 70Mta57vhSGvyqmpZO73vNXyXQwaePZW5af4YZHQTBduF5DuYUNz/X9dGN6jEXfS kQzYLUHOyECKvNPHJSuNuYX4jZt9g61BlskpsnQW8AkOrQKMN1tdWpwNq2MWxX6D di5g7g0duamXzomhGiXeXtZIa07El4Yv+0vbX9oTQGap9X+TyPZh1gm41XR3cxQh mGr3TqXpqTzvca6bboC6e8YyJk2pYAPlweNhy4fxM8xoJJDhsSWCb8YDXVsZadsX jsANBCHyzzJ+1NYNU0RIltF/Qx6Khtp9arYdaq7KYHhF8B0RhDKJt2EIjnVu9b3z sezk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQVXNoYFyEALaDXG7nB2AoQjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTAxMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA9SHoRMg+Dhd0w63ithVC8CVZZMTkHYryM+I7nqh/q9FZ zvc0tQtLwT0DelDJxzTm1zTu9wS1AGStgCShUoBuZRv6uB7KzZAld9135bs4+6vQ w56ToKVSA+v0+b1C7lzcVx+9gQa0nAjfzRERm2/LrN8fVX6RKglNnHRZbmY+Zm/9 7J9AJR88jT76/KE6laWLiKSyc+4uF7FOSspyd5jDXkSfI7iXdxY8/J+8ti9MaxA6 PqT6kOOsvXIGxa33W6HOKCQvvHJ86l7pig49modXaM/odktYNAVRlOJzKVqWYDzQ S0kx6iL9vE5kgoQ9q98YA747pyGkSOQMjS8Es/sA/WZCPloipJbsFmiLAFP9Fwic XNymNCAOgDjHTfLnCsW7xDN51InxMWnjpkJK90RHvTGXwztJZ25+dWiavi8RmqtK VRIYyXDpOoDnwMHsErv+UFxyXZyXR99+WAXTqnnRlGg3hAIPSRI9cqYWJ/sRBXHm Uo68tjnHHOxCEBhS/3uPSKao46ghZcwzSeHCZOxfIXn6w1H6FOOCtqhcJUImvkRr Y3moluXM1y248TPdh2ZIens2lFMTrPX2vULu8wfB9vlMfT3/4iTX8TtwVqeoan++ uR4HNdMKbz0uH1WiN4hPjiP0xT6WIFifHl4dj/L6KZkSh2Uq05ZAmp3drU1sU4sC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQqDIiS u+3AuX9uuuWBQfvKy+XFuzAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBACSsmmR6IXJdUbHjTfO5uCmfyuCz4xOdijYx/c/t +rwAWy4c9wew3SPUQEdQcAWM1IOGYJ8IEhNvi6pajAntkQ0uYOIhFn31kMInLxUM aI0hmzspV+d0Ethm/MezKqusepGjHWaM8qU7xgQAmaUc3n8gos548xYhkdc6613i Bi4fx8M5hHvBhPlbNFR2IbKJH2k2nz9MekYyIHgq8u6dkNY64IUA255mGT3ax/By 1XiyIBrONTZuR009mhkajZZYUA0/Dgm09tu5xcg0P8IVFyeCO1TwjToqsPPVXU/r skUF4UPD/IEcSVIVIEVTP1al/n1oCJk+xJiO8NHHALxJYi8lmhAJM+OGQZYCmskW EdLL0Fxp3wLouawmPvw3M0cysMR+WXn6OeUpQZZaAIJxeGbqvadV6MTpTVxxeXmk 6XduNpZXy524fS/5KtfINzwIMZ7nDTPLQPE6ZyQtZYg1xHHcsayGHCoDM3gUYMV6 VGPMnaaLhq4H8oE8w0KDPzBOmG/7IBOzTnSTHU/sVY9WgZ9CxaoEqI8oXRpFv5vy W+S69am8/KmuRXK7HpeiuiZlSM6BK3buqaTuhbylSI8sRbocwYAi4Iwgf4ID8178 VpJoNN6KghIv8jXs1ONOqBVW8QCtggcTUGy9JIXkb9cBzpz6c2WIhnAiHbvZ41v1 sVo8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQKf9zE4rgqqCFJYJw4aJQfjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTA4MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAhnaxumJ578Za1ADuvrTXdUpQHILtdkopzTkQs5Yq5YXt 2BJCs7I5oZOIE2EN9KmTDgnjIG/54XZAke57i0WKFdK3Iw/8njsgmIxoZzPg3FMj tB0bYyE9UptQn0V4i7i40tJ3EczVH4zAXPXymxM1EDGg/h82Q5zGxLhQPUQsTujt DplqwousVOWox7UQuHPBzP0UAuL8GRyHeBjA5VOcWvZ2qNmqfzqnaAkrnNPwqJ5f c9Q9wiwy6xKnXjdv4/X8zNK1fTQdjX/GTge5mSJxm1SnBtkOrSdM2mdOrl0v44b3 CgKzX/23UkK/Do2Q+whyutCnJNddXxl+WSIMVbXU0Gqk0FPKVlGMxMfmJ96H2ON0 HqnCNd7Qed2OqfV5jGhgZ7v3M9SFMZSwxACOGMS40ywwYSCkPNc1WnvVSAmOQxWI pCMXR3NViZ698CkLqI0eTVbVYFZltMyueam5RKI1u63msDGulESZtRakk+fIIL8P T7KHFJH/0HJ74jEF5XRaN+WwPJwsbDmIZJLSQALci09Jt54emL/l6ZN5iXoi+BAD Dwa0ofCEe7S3WgOWkMftpLSl+tPL6+FN+JDT2f3yUQV+MTweDCu7JlLUcD/Yt5Ci AiRgRoKNX5nGO2DAm4RQCKC/QNk3oGLrkqEwA0ZcZOmKcxEpEuloySsoa3gVIiMC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSc5WFC cMjV2lxUJO5JDGXPeS1a4TAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAJCq8eVHmA1uM9T7aTWzIAScRwqrGy5Upbq6IxEN XYDUQgEA+tcfJKpHvfPY1+3IFlQ6T3ZUin9YC9HjRyWcX7mln9zqdq90RYn4JSum GJ9k4so3Qu0sFb9hNPnTdsPO6ZAxD3X1Gxno5qMADSY+FMez3picEsqIvuoNGsVE uOHZ/bZ7KpW4Fd6jF/OxgkUu+x//m6EPYE4C9hA1gFB5KL7l+u4JdrLiiA48vEZk N0nIZMHSGNGcy/XehrjQqhUBiSyixd8AsM/vZv5NJjPMGv3nBjKKq0M5Dn960HpX XoeURkkxdSKdr8gj/O/inLxzlWeEXTExLqpAdIjntR+vcHR8Vb7iRWFIU6IIicmp pY4d24aafxuGrE5De5Zf77x+jZ8o94Q/Tqy2UsEOQ7cfJmI9f+4Edqreij13kxJA FBHQEDZseF/9KqaIXfvDd2TtMvrd/Zh0wTH7roITvhbAQ4lduxEqU1RNpkqIIx+b YCkQIZw6ruaL6tXCYqfK2rtsZjGviJQ7DbdALGPKay71nwTUMpb3P34gu+v8dsMO lSNMIjnHSjCb2jUd50UHoIiaBJp8DJA/UFwwjPI7f2bfRatAsmLNnnznQGvZRXwR u2yUtqEhrTH0lb0oLIcambmqa132Ke+Dib2+oiRadIWfJG0+Mq9MW0BAraqZJMbz 4fr2 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQXNMI0GJKJqwlT6JiQeVAPjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTA1MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAkryfXqmcvK/8jNYqdn+/k6/UJn6htjNdVuccORh+NAIi uiXLgA/BD/3Tpc5y/HJVwQYlrlrjx83WJhdaaAERGGmRs/PowJWYQK/gOY+5KrjX SjmkuXkRv269QjFqignNe5nl40y2jk86MgaoIVVcaOkBQOvPmhnU4At0O64SHW7t 6D44/7oULeBwCLpKDofS8G/TVmnUGSYZUeUiG0ejmwRUbBRn4ZTjDroPQau+CDkp 2txreS1POFdWBjYLvgr5hnjRRVpqNw/2RKBgGe7vnOiginzwkI6YATMWMm8WDhfG wIhkjHeagyfsdilh63KQ+nlUtQawcM4jBlY+ybAiTRuA4HAaQpyOB91OEOUaVDnP WA3TQdVczaukqFLUl20V0Ge9rWgab1Pl6wSCap++8nIi61r/1ihPTKLUtinIPetq iFVq89wLT0QSNvQMKbYFZm7M7Dq8aJKw1/i9LmVRfo+eEVoR2A1DtpK1ZjhFVYmU stPMoqU+5debfNpHGaMP4WF+ToElKNY+RwhpfaNdsBetGzgmqvMvCVFywMyl2TEJ 6WzUI7CL5qYTTBWg56kJiYaOwpJPbHDaOzvu5FpeEli98MaFzJleekwUuljs49eS /npjLUTJgDvPKUWWnqJXwvFLaDB9L9una7RDoLsY6aSJr0dzoc/gb+BbxXp9uO0C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSgZmb0 +YCuc1eyHYUItB6MMr7+KzAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAAKBLXFJ3CgVGA7oUXZwwTjlAzr5C2om6l6L/agh Vh9vCnWIJ7CJDcbhEGhGfbggZ2dKK9xGanTJHpAmiFssfJra4iKwohrXq48ApFjW OP4/LUWHAXJFABT4nbqSwpn+kNRmAJlUAO0pEx1zB44jv+UWq+7L2wFkVW+3FobP MYzFd1g/AaC2MDx/DQlXVz4rA2sDJ8V1vP8pS27IK4sin5m3UyObmySSVaqoRB+w 7vhfpp2+bNKCy5JkmEL9//TlM7/R+1Im0nfI8aUVjiV06bEt4yH6wTQs8sMtgqEe wr28fZHmtQa1GSvwO5VvNqVGth96dLR5qpT23tjG136ycD2+gzzYFNKo7tV32nV9 Eypslwt2G0CWQ+ZC6kSxXq3ZnB6cOTbNA9ad63uQJ9BDrG8f0VdurynKQfp5xbnN 3jSoAddjM7P5+GAUlydOUgQXOu+FPYRHnIRzEGcOgG8ywBHaVQVck4idumaotFCV ktGwsc+8CrSK79FtDcEDitohQP7rmfu9WK8Zn67LgJ6fZkG9ifiltI3gnIcCUhgY 2VqFA/tQk/xEH3YV5kZDa7j1H7nLwdDQrDpfS97K5FeFoai75y++JimOBzpSbXoD p1hvQXEotIh7jfiWogsvQdmMcSezSYBWYZqsdS6eYgKCjULujRPLbBPCM+AwLEA/ TgX4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQZc4W2t+DWVcveeiLPgwZAzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDE5MDIwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDjhfNTJVsyLcKTMXSV9F5fDG7chOB8Ibb6guoeBOEo 5JKvjShJDQ9XkoU94sPLhi+IMdfbUjm5F8+X3pt5MGuau6Oc6bcdAOOktV6bWPkE vOgSBSP3YVTWN+L3UQaVcKlgLy/G1jNsrHHpx+iOdjCqUQtS2/Ml3HyHvTrKceMb 1zgYflMRx7SayhK6B6E3cap8JQCgnF6YOQHw1kVJimEXOqkh0++Gy53cmZRMEhkG itNqz7UKfbTbrTcWT8tapkEzSWrbrjsxD849cQCPj5+im25qFH/LYGrK8e9zWK2c MCmy480t0qzAUO7NETmDMrS3R2O27lb39NIwlmZyHk1VIiIPwtdfhE2ZEn0G+dp8 uTaqR/aX7FD7xTa3Pm0LBlsAPtvVzC7ATqNFc79l8z5ALn2kBoc1bD2vkDDF8xX6 00GxMtRNQ13jXvrMynwtiIKrt1e9Vxg+ao2qzhDAF9shdnPy6+iRGI+qcu70d8L6 lfjokQkqBA1uYPKz6OJRo42CGVKU+3jgzYRWppyE5R9MY5vGyuqFU2m6ij9UO/vW Y8MDusLlglW4htiYnmYz/bgRi2CwCgsQSWU4+uzYh8fGEjQSqj0cEDKfv2S0WumX bLgGxU01oXsPmv+AqU5FgBrETz4In+Oij9E5VAU6XtdeNKLtB5Org1ZukNDTrzAt gQIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFNJQ VFIK4y8onDwANny9/LcEbDimMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAMP/5nyHW5/q6GtHEy3cISdmh9+3Nnri079w3 9jetdlRC0FF/X40BcnSPpPxx7338qrPm8+Cv6S1xVFqldkpxaY4Jb5k6dBkwhz2J 5RTxnKLs5+PdC15yrNtQZuu2iDz9llB2jpknjHj8koihQZQO7Y58kHXtXQAhU9vB PPDg45EYuCNestXwJmmt6NEqxtNduwhLJCoKZGeFuj90xNlkZBK//+DcjE/HEC8T IJ/yLSAI26xsrsVXUsApjVz+0ShE+ewEpz+UWwE2CYLYsHIg1KyN5wlpxUvXK7Ez +kaeuj73VMlan2qKl+CbuMVmmsi8U3thIRHFOUu4cVflDo7WO7gH2qlHGE7UAaDt 8Or3z5O74srBPmXYfZWNkRwtOQTtDubbxhTT6kzkUeBfIuDOc8ZsZfOkyUN9mLZl C9Sv4XoDdXtAjShZmdeXrazdwY/rgCG8dC0nRSDl3jGjQQZRYxYIHHTgpu2ZAAiJ xbL9gW2fKyhKc1XmLz2uoiePuonmg/3jhz5IoYrB4sQQoOM+/zjUhN+gjIyf9B5U NhuYho3Wdn1fY0TJqgzA1DGIvQ2tWGOP6L49A41JcATdbUEnVUYnn90RBypUufpb +xAeSGjHGiuPnCN8RB3IJtc0qoc5V+Dzu7jHHx4dph/ETwvWGY5l+pz64rgb5fEv oLZJ4d4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQU7a2cccpSRJ0GhYwprYbujANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTA2MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAoAe2NyLzCgFoKWtYXEScR+/tIDHfLKn/kmcjuc/544lr SbhQ3lNbDWDi2ZKHhQnsbEib2b5wrxeB9CXZQ4Hd3DeMxkXnsdlvbAdAtwsKoqlb ozgw55e4tlz2/ueyJ/QBNo+iQKR2GYHOxTfHOzvbglDLUkDOnrkyYZFsL0UHg/tw V0ZnrsQYeDDoKTbdRXE6xosLUVEc+Z80vrhXtqlDoV25yH02zoNQJeyvtnwBXESA MzQTteEsHdTPxjBarHL/8ESmW94tqWXD6axDUmECeKsonsyy6ME8PRrxSdji2dtK JB3Nvcj8yh5Q8srZxT/ul0iZAmPEG9sV8VSXPHLJwxDBLa/u7BfB8yP4FtKYz17z QXtnsj8j02BAykU5YgjgAbeOUT6lcqbtUxMS/mBS+Xx76MBo/8KogW+XXUb/Kx6b fR8U+Wxyb4+1gu9gQWFQgMfU0efBO/8n/CeHqTExWeCz3AWWg0CINl86NloRqBi1 D/UtfmgJzx3PE7KM88HNDrrzimkuVrgUGk2L4jld1CK45ZiOcriiITHVKn5dsham e8W8BMfXwi64kbnKjx3ZZfC54YbsLqJ080X1Ojydjvf7VvtpQXBsDp2DBNgC08T2 dBtlPDQRBir6JmYKAOauCBOmFa/yY+3C29l+A7Tjyn0ZLbc5z1Z/RVIA12Da4b8C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRClzrh 1BAwDr/YRRyTHqgM1sYsZjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAFA5G8WfcvCWO7cTxsoa6ZUqqmgEJA0+yG1AQqU9 wGDJGBuL7QtKrNxbXkB0sm7wb462XTM+ODBqOgAo7dZExeQzpsxX0ZRr6SEGbmlU ULGJNA5rLrF+lhaHBelvo8uvYAVdmFvlBKXLYesgUEyO0BPEVCVkCsj4Cj78kBVh TsqCn9l7FDsYWqhITk6iW9dn/+VwJAhgWsK5OuMsaIYFRJITLEf0yM2XQbXx+Wxc 1VQuKNZzdRArmmsmopNGgAYWTKjldRbPfF583T4bYmfOP29vXrixc9K8EyoQo3gL e8YVpRLS+b9HBDdLRED5TNZLfh4PpuZS3m8G9Fsy2ZWCFyzR8TmT9xePT9K5dqsz fW/zW3QC9J2dIn7P2lqCycgiKXG+Joa8/+ykdPRM5BdMJEb1IPV6fMfOrHZfYABO I+LEpfaJoOwZ635xa8yl7CuCRhwJ56naoqOLwdGEcLzVEIBgfCqM5uoakByOHQ9A 4oOgVPqJNJ+TFPJS+JagbQp4Vn5cVC5iWEDHhbJtBxiLVPAVzjP1ORPcB6fpQuHz Bbv7JAzdWu1YQMzv0JSU2fhdIMQkYzvvwprBsfdpyfy0FKXvV/m9PwWk2u7hmdR8 s9JZBT46Ce8vTbvGQ+TQJGuYj8ZAF1EP00eSPLrvwcdInMXttvlJcghOiHGmukRe fhSV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQI3YVrWANBzUmxRgckHPmEzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTA3MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA1ZU+dyFkeqfwA5SXIlYAGA3IIf2QydMcBpTV/tC1dzSn kW4nQeM+4tvK0XCH2+etlcV7/vZpuwvT7GAX2265X8pvYbJSWidLX8x0JydOmpDV JdINIMYLlsedIalaJY9tDWf8g65tRU9tzDhCQkaIHzAXIDVI/shjC13LZBCIH1N9 Lgt2USI1O605PuPG9KBwxk2yMwLJlDXJDuNdI+lXIoXlDIRsjN5fj7AwQF2QpkI+ E7mS8eljz06JoYRhy78bhG+FDtFJQIUt8PCq3cAYRFvYn79uFM6AXiPQQv2mT5T5 dJU2Ar3O8Z6xCYPn01/vRV48aVr3S5BSi7IeCABLVsrRLnsI75Ab2f+xE5SLRLZa nSdyT/8KfO/ShGV9SfZ9Btv+W5nll4B10mENynotXtF2/SqvkmwVNwOx1G6eb5R9 VrOPZgkDPRhw3plhMoXhYvnSarMlfV+fIl9SgE8SeVmovb5NgRwKSs4EAPZOF0zN FTXdIi86v145KQH0yn3aWK5BIBp1NR646+J71fH/kw5853T/WxdkZA56xUI0xTUd v9wvLIZ/wHX0nCiT9cXYAbXCY0MLVM8QLusHUJDJg9qgEQNPFfv/f6hjNBNSJj6F xAAgNyUBgGdUyZLcpnwQQkOxFHnyOfUZdE/mvqasgcPUnoV5zpzRQ6Jc2ycajGMC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBR2dOVo wS8KmZd3OtYxsHo8HLBa/zAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAIbOjonhH8ddD7Iw9Qei2DYkDCqhw0erRfyljTG0 L+OpIik/Zl/e55e5ld5gZ/fDPaDH3/4XdDOvGOYzIHIFKFrZDnIYmpPECYdoo6Ly 8GcuhxjFlN+Ed2AjEgUBxKDQTneEoOAl5YCu5n2Bqq/dAtLDiu1IoruANc3xqzDz BWdZrBVQ7wEt2X9ZtkG12NWYOO8SrxmETkBIiHqmiZfgnulWiEBKHgVFhHGihrgk XXy1xHRIGr5FQ5Pl4LYbTNFiRjGy/zSwJ5f3kjycd9689SMPzQefOlGFFelg5t+s T1u4Pw0+/tUG+PcOF4Wp3PBViO2dQW0kr8cSRG/k6ZODgMwtebG0PxNA+HNhqnsI 8+6jDQfd49lb2Z7YxftxaKzMUP4VfCn98XgO7XVNseR6EytL5mm4z5/KpqrhuggW /CLGrNKXBzNfXI8u7Zv9A+w7k7IYg/Q41H9G/bjiY78la9ePjV9pQwlPAyUHAfIZ SkK/ddDfj4Pzm6w9CWnpsvEUvp6kDvYbtgRldw2p/Rgr8WhOPnbUj02orZwky8eh OQ1ZWOVqp7SYwu0FyPbgRC4AOC19/ZKmzJA7iXrlBsyDupOD6NttX8YMzs01tpVL 2PZiRdY7ULXZET6fTaJgzO/yGbDjeTR8gFY+eIwV0IoyuGvZAyLtB0PwzOzNTE1z mEeT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQRnFESGZDsblTmnu3Dy4UQzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTExMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAy9J6OSzGqXfY4a4c4c6YUXudC9XjEIwCKXOgODikoU9s O3I32tUosrTJsOQHLlCHaGl4rD1X2lMKeSAP3YhtJPl7zCq0ZBi31Hr5Wgiiegls 7vQAMLXs2d+tLEdbU1HuWjx72YwxqJ297+jS3hk5yge0Ux4TxYv/5RnGgBkDrxRe p5fReWBv5z5YQIxWUFbCiMFBzuMeyzarot//ZstY3i1ILrxOHHmPn5Bm450O/qbs o2DM8Rwd8CpZTkPL9RYSqQ1gDnvm3cmCt1q4y4q8dg7e9URxzmosn8shKskbBNCi 1eGilR67/oFYRzDsPfNy4BdyBYPQonElM1xCAvUfhHEXBHxBHkuNulkpd01hqie1 Nv3DJesIH/M6okqxtwYkK0+5yt/IS2Sw5NUSr8+66PkEFvZhzaWubXRB1yCZxpHg b9zjTyI0+8cD82QX/y9m0EThmmvuW9hXZDmW5JfHcHGAjTH7QA2/qtQQyWwFFEN+ rpjQqh051hSjqDCcSp7hsF8os7v4MbUSGSwuo7cdKWTfT35RiRjEOZIScRM/IJid B4sQolOoGt+tnY39GVOpodIInTslspY0ctbsSxbPxbSbqG/uMKhpXob+zo9YhCUQ 8SPc2037z12VXLMkm3Gh+cu92qoTcESjR3ANhlti5PtmxGRRJ/c7ayGu7fBiG/MC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSohnKR 7k/md8fBjIZYlT/GyViNRjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAJW+fAezZh2botN24JOKclQi7B4+rE+h+IAmePC6 1jj6KY3e4QP4H4gp84t2HUwgfFGJoIBO9mc2jaxTtoB9N+PhdLGMyvxdlAsdAWrT fHyHqqbnzlxvZE3las+NuVpibvO8+gQailyhfzD8MpuVExY7Hiva/n6+F9Btpil6 TX3nGNTWvGseLXyrXSJhj7vr44g+AsjA75xP6sUT/JYmgGnSNp/7u4LGqUUvq7Yi 6sGgz5Zsl3GR/CQUuvi7sKm+VVLBUpBUhkXiQe02EZsEwXXxQc8dz5NKay1pFjZk I+PqsZBNMnAWoUaMxLj67GC71fpTU2dBUw5L+RBGLYlNscIoSPqEe4gfUjwfvSPl OdVMPqzYUWRhBCu0c0AokYircPy+LvB0UElW7XMB6gVerPd032ip4bRE0k2riCZO CH3J8IbHoqdU91Z6oXBCqAcnEMIqjudXxSpw9TaLFfhMD5GD8BC2tgrBCv58N+Ui m8pKNO8ZExTZsvkc81RTKSwrciQIq7uAwIS/NNpwUIP+kyCe/ql5iq7yK5vJ1r+s RqJjcKmEpVZ+IcHWoOhAErLIJ0BQzGraX99rPHA1OqRWdQG5iBsucyj3stPqin/z XyCS6NV4pURO5OdkdvqtrJ4lM5vAjNBnj7zdELBqxeKAkCRsLEusJ9WepFOXYMu6 yjpy -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQNQy52niTwlxQD80GxG0ZQzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTEwMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAz3OfOo6qKs4qbsIPV9k4K3CoaPN/yrYOBbatMXsCuQJr yrDWWPl2zZCc7b+JE1fto3vN+8t02uyu4DodwjBogwsJ8iHgQJPD5DGjMvtcfYHS ku53f5eQC3hq2ae86Hn8IDSOh3C5m3TnUzqbf7jHGDG559bvpXgV1FGe4CL+yXVo ceVjJuiJEQl4eG6Ri3dGZ2l8GczpiZiVbJW1xqNM2MT9OgpPT/AdykJxwj0TVRI6 +h3dC6eKW+7T4VgnrXEYg/q42P+kJQ7P4hmog4Ripq3yarxPUBk8ix17u9QCV75F +bNEFtFgyvWBwca9PBTyNsPvoTUCg+fGsgwLdzA66jTxsam7UWgs4SGcRDXvQe6N VkXx4oymeKsJkkqbw3jqizqLvW+SmQQ0ZBlC7/ro1Le3ibmd9GMelckr1G6/YTor Gn0tguYm6CNh8ou5aed2edXz5hy56pbjwHoUZcTh359wbShqKEMuKqDmeY2fe/Dr jm48wEyX+GGJcPPIvfQdUIsnAvH3AGcclV2k6dSC0DtAa36zWFrGPogrM/8KFlpu vjPmukTWJCdN+O3DjH4NXL59zrpWEijyKYA/jDfCY5tVVPwZez2xjD5DWFhRLP50 EBlWDX7uoY+RHI8ZWiaiIaXvRV2HYIxsQhhSragr//RNf88k2lKeIMQDD0V7LAkC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTENYn6 8l5fFWTA1ZWv3adyIryblzAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAB87wMyYRfPDKBpSIkkD2M5F9rwBS5tc+glgacpd 2VUiAs5ocNM76bH/Qeloa25xIzzA1tOJ7qOrZku+iyb2tB2JkDBL+Gntvn3Uq8P2 e/n2qfRXSRrsEMUO/fHZ7+xTIHD5OopXpQateadqy2tH2NtPAwJDHHEc5E2ut98h bOb5WOE05AjPv12OZIRVikmoQwG9ObIl6wd21jiiSbaaMudZEa4eig8dvn5t4RTL 3HGCctFq+7eqBU/GvaQPRnnfjJlgWyBtSHz+nfg6+v3Ib96neWjD3fr87r1QXH1b clYFgVTFV05/q5mBdiOGaxnKAVMhl6Vyxr0vP3RzLzrvy38mZJ5jOMXgK3Taqv5V 4EkKC8xmdIm997JidaNcRBFdZCfN2TRc43EdxYlmtqwqIv821LIRxL3a3EkScWMf XsLubh56DRhLra4KssfSav4BkZA2JIW5XkEAi4LcsRPiwR/QjD0/n248IO5+PXKK NIFfk+WX5GKUhZOEflBr3OkMCxVYnwaGujho+6rnwmHser86eU9GPZLpfhXyRrUL C04neWokRMVtg7h9xy4au5k5wuqHs+ZIxGEewBQ5laTBb+DEeVChe4tBUq3UVgT7 rToeN1/yAkOzfOHYQUHaaW3phaGgFBqzoVHNCZXsbblKCE+gIOKX32mEovhWW1ZU G7fP -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQPuDnSHhHTTqZoeTzshVQvjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xODEw MjMxMDAwMDBaFw0zMDA2MjMxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAxOTAzMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAuKEWWwBCN7fXRQsNfbJSP/vsviLS6ICHvdMDHWefm9pR wyJ/2mDqnUpQniFL0cskaeuC3UYeyana5VSWLWqrnWUxWZuDu2RtC9M/S8KSyPaT pN0XWL+OSCSajOe/YECj7w0PecorDkrpERlVxsCvL95G4Hk86nwCfdu/GY+PwDkR u7XiGRop924mN/rWe7kCDArofTnlU6UrPw7Hpwe8t3Y9AUTwZI+N5mJfYDlCpiLt DsV+H0h+vdRxLFoNH3rjqaXPIhwNVjY/k0crcpGr8BepA3KrpeMyr11apmB4VT3w CTFCOalXjr7KBJ04XHa1uOyjbKguRsz0NB4kQc67qn6CxrOOTD3KQn2Z/+r7IDel e4/fnYn/UUbJAhxKYcBzfms8tb3KZkhjLDJeJdaGavYrhlpEAvn16Xa7XdrkkXbe byBRdCo8btKXdJztk6N46jY7xkpQBRHHQ0FsXyk8Omd3ERw8zG8e/b5uBLg5P4nm SCeCTdvvqMj8ROkjnp2usnE5p6sIinjeRMY8wDPDlpIOiewkISkzURXRQuH7tbZN 6vwOJq1sos7Te83KKpOuJ9GW1hAhSB+zc9MwCpFGE7ko2UnYLsz5RNwScoPHQBS9 KYKDRUn4dsQXlcy/Ebs19aJJQ8AIgFUIj+Mpn6z94K2d4dop8Oz8VFZl3sEeQKMC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBR38Rda yse7/5jR/MLrYLrwH62sVTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAEvnIGD10thT/1Nz0WCrxPfJKsu7btqGbSmUSubU oWY30vQPZNLiyQIytXu+2KSoxfaMV9JRh0UAaf9d7wcc2nt2/Nj040yShfwqDHKP kZr69zQ4M9H4zBNvdk8l8j9CLYDtL/qOJbfSSFhLfBKWLE2+pW1o1+fkwp4+BEyO 9DZYDl51PxqeMdcOVJ6tcekJYk+efI652aaY8Rm4yLFgz0HTbSMviOwU8XQ36qIx 4NTkMqYMxxbUKi0zuET2AzzTJBnCTSlDR5osFptF5XP6AKZi6oQB/pNPUzoU3iZK /dsm4jBNE+49iwQznSImCt3JLcGUDUiBmHKSpruVqL7IMeXrKcggR7AP2QomnmXM EBw8CHlRhw0SQFAhdbw9H5Bx7qG/LPu91/cdUMpm4cdqfXHlg4exsRa766oOJmaq /DklDGm113ckC4GutTPsNjLVNxB6+yB4gy2G25LxcRtKcatidOXTvHAqeSkH39T0 O74FEglw6UKO1ZHKGB8ubfi/XIXqaTlaA97np3N1dk0lGosd6+YotQWYTQJiPzUg tpVUg4wf5qqzv5nDYeEphASv2HzokUuTog6IwuPn7qCiRIMWtU5OUxng/RC3o0o5 zpyF9MB72GwcGutC+uJcX5WEjOU+RNo1HeWxGkKBcCGfP5dnBQc4CQi8syDm5x2A Oltg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFUzCCAzugAwIBAgINAfD3nV54J/tAqRKzEDANBgkqhkiG9w0BAQsFADBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTgxMTAxMDAwMDQyWhcNMjgxMTAxMDAw MDQyWjBCMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp Y2VzIExMQzEPMA0GA1UEAxMGR1RTIFkxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAv72WKaCDZTTnN6KC5yhiaDZLawHdgu2zIhpeHogZBdpibue99PU8 V26a17//FpbCHzCLBxq8IDnAcIGBtOkGJ+QfHcUow/iFccLDQrhN4YlHl4hhEAae jqXKBy3U+NN2De/rfdDB/QX+38MZnfrxcLudTgS8ItVbmA9kC/8wnGGrMbLvC7Kh Jk6aPspN8hXzmjfEHnz3Y9O64eu9QBou47trCZspr6bXqW/XZV/b/KiOlsprLR4p obkd4gOkrLSNMTsRcrTHh/4SCPYLR6QVoIZ1K2cmLhJHuxYTOy7ziG0sQmvku/Sh +GeU2Pakm3wSPubxQFDofYs8AQ2dZYfwYQIDAQABo4IBQTCCAT0wDgYDVR0PAQH/ BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8E CDAGAQH/AgEAMB0GA1UdDgQWBBSGIhBdhWAl8joefQqvYSqzFRoKdzAfBgNVHSME GDAWgBTkrysmcRorSCeFL1JmLO/wiRNxPjBjBggrBgEFBQcBAQRXMFUwJgYIKwYB BQUHMAGGGmh0dHA6Ly9vY3NwLnBraS5nb29nL2d0c3IxMCsGCCsGAQUFBzAChh9o dHRwOi8vcGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3J0MDQGA1UdHwQtMCswKaAnoCWG I2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMB0GA1UdIAQWMBQw CAYGZ4EMAQIBMAgGBmeBDAECAjANBgkqhkiG9w0BAQsFAAOCAgEAGwepaWYDaga8 oDkqj6wNomRJ5RlcSkoHOZ/UJelqY0ZpRhKI5b6ww+eKuV+N98EF1yw6eUzx4W08 RaTQiT81ZlJih+ic85efKgSeis4vIxYZqUKvfDrb98h8IgLFydJ1ZRpeZPld62zg urd76TlpZh1CxIdVch7WSDDrYwcjmO5OgD46lXVem34ABfpPpLpxQhAtkfoUR1gK ZtR3PSF21/R4fG8AjIRUiWZXWgaHXAunJuXwkf2ckAQs7mz7scL14g/6+q8+pnhx ntuinZcLxxDuuoRl8nFsUp6ga8YHbqNYGTsD0ZZi2CIaXRcc/iEEusSIuyDmr70z nc2ce2Pr35RWb49s7dXASXNFfaOE2VSv3q9Bqspg8hdLSP6UjvvAdVxDjgrwKajC yugxbt2W1mekIciOfupvgL5GOOblsRz6KYr/PaN08Mxsgl6eHhSRQ6ZJNDbCATr8 3IctSxiARHmXZ/Og0uMVX3cKMtJUBBFKeXo2ksWC6MAl/WN0sXqLb7U94r8uCSVL ie5nv24J3Rog0Doj7LLPnwMWZZcVi5zOUiXAhucASd27iX5Iq0eBoVVIJzoQEXti t/na1oW2LoE2xIabf+n2f8eMA/A6iWGxbUm7Uhe22gn2bFgJBRWg+oBKIodHVeth ZmdKC4kdqYN6aknIFoKS5dpxhOcA820= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFUzCCAzugAwIBAgINAfCcWw6iKTfPnuRBbDANBgkqhkiG9w0BAQsFADBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTgxMTAxMDAwMDQyWhcNMjgxMTAxMDAw MDQyWjBCMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp Y2VzIExMQzEPMA0GA1UEAxMGR1RTIFkyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAqB9XbHMq4soQmRpOVF9CsnIPC2uZ3ITR0QRReBLhOY3sWwjeBctq qMcocN0zg+30c4+UVAcOdAxHjEpVakbrtcqfF71wrhau8o6sn+y8MrdYAtrGrYzn s26KETX8NIzxJy/v31wJOQnW/WZEizes4JfO/1Mo3qWAiaoctsiHmL5PG8xQkdOh PNdHu6KcgO0IsJ9BCCufd9TpJMb0EnO1WK3WZLQdgmVny5FkEqp0Fz5TgQKekHya jnbujf1T09AGzTQgO0Btz15WL9pkMADMWKwYtbEurJaHrAgejMHWC7KjaqH3XlVm FMJs3rDDIQxyTRLBPqRLaiUkzxvBBnmrlwIDAQABo4IBQTCCAT0wDgYDVR0PAQH/ BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8E CDAGAQH/AgEAMB0GA1UdDgQWBBRtZaLX81CPCXhlsWKivjztu0Y6NTAfBgNVHSME GDAWgBS7/8qOI59Pmcrb4mimpRUnFx7ZDjBjBggrBgEFBQcBAQRXMFUwJgYIKwYB BQUHMAGGGmh0dHA6Ly9vY3NwLnBraS5nb29nL2d0c3IyMCsGCCsGAQUFBzAChh9o dHRwOi8vcGtpLmdvb2cvZ3RzcjIvZ3RzcjIuY3J0MDQGA1UdHwQtMCswKaAnoCWG I2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjIvZ3RzcjIuY3JsMB0GA1UdIAQWMBQw CAYGZ4EMAQIBMAgGBmeBDAECAjANBgkqhkiG9w0BAQsFAAOCAgEAEGHBHI52AjPZ aGwhI2S1aqD+BN3e4kK5ygYdX4esk2Fyt3C96VbWGuMaP5nbb8oc+6XlKBfyO2ia 5Y2xpZKiJ1nbzDvFtxVNY72VDpEEdANBeObNovqFxnZg7G4n7rS9rF4UBcB3Ir+i Ji3G1pEiv1jJHUlAPtEPsNOODyKpm3qhw3zbYEfr8+mtCp9jzcTcB5NqLEUffY9g hiKJpQ4euRFUZBxlfdcNj1kvyQLaHAz2ygwdrd9OxMHeyup6fkXrleZnfCfU5YJj VxeL7kdO5AeyzVuABkrMBtwiYhxYBbDVT3Ar3emz2SPMV01TC8mXENyCCKeZjykI oZsjBkN71c30nHoLleflEznRyWvK6BpOkqpekg0I8PDuKg3GKAbvQ0SQdbDYwHHc 12kE6fOwDxHn2ggO+7efLO0IeGva4ZpWx6T8XNFNFJ/2akwOI8St4zlNEmZr63DQ 2VP5pQ9c4fTXi6s9k2U86yHmTqFk5UOGHp3W8VK491nZwMq4umbApZ/Khlo1W5kJ cx5O98FfnNGzJp8kdTCdGTQmCPsU+UEzjosNw6NJFhUjZlsI3rQwe6W+VwE09M6J bzQwa8yMvvdoy+bUnEC00MFnrj8ErJwcjuLnFTJuZVfUlZw+nrbuSjajR3XrH6/F xIDK4meJyr4o6ngs/nUaeRfeG9XSx5o= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICzTCCAnSgAwIBAgINAfCcV4rg6fwYVYZ8ZDAKBggqhkjOPQQDAjBQMSQwIgYD VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTgxMTAxMDAwMDQyWhcNMjgx MTAxMDAwMDQyWjBFMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0 IFNlcnZpY2VzIExMQzESMBAGA1UEAxMJR0lBRzQgRUNDMFkwEwYHKoZIzj0CAQYI KoZIzj0DAQcDQgAEWgDxDsTP7Od9rB8TPUltMacYCHYINthcDjlPu3wP0Csmy6Dr it3ghqaTqFecqcgks5RwcKQkT9rbY3e8lHuuA6OCATwwggE4MA4GA1UdDwEB/wQE AwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgw BgEB/wIBADAdBgNVHQ4EFgQUgIz8FgrI85nOXJO/Y+NKlsucmbQwHwYDVR0jBBgw FoAUVLB7rUW44kB/+wpu+74zyTyjhNUwYAYIKwYBBQUHAQEEVDBSMCUGCCsGAQUF BzABhhlodHRwOi8vb2NzcC5wa2kuZ29vZy9nc3I0MCkGCCsGAQUFBzAChh1odHRw Oi8vcGtpLmdvb2cvZ3NyNC9nc3I0LmNydDAyBgNVHR8EKzApMCegJaAjhiFodHRw Oi8vY3JsLnBraS5nb29nL2dzcjQvZ3NyNC5jcmwwHQYDVR0gBBYwFDAIBgZngQwB AgEwCAYGZ4EMAQICMAoGCCqGSM49BAMCA0cAMEQCIHefcgvUaglzgnTWmDYl1CWe X3GXf0bC9zKDpXDXQSv+AiB4uN8G0OaMfc6LQXcg3EBGX/3ER7kj6WdPct/JGbt3 gw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDyTCCA0+gAwIBAgIRAID1YG06FisUOtwS++jCBm8wCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MTEw MjAwMDAwMFoXDTMwMTIzMTIzNTk1OVowgZExCzAJBgNVBAYTAkdCMRswGQYDVQQI ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoT D1NlY3RpZ28gTGltaXRlZDE5MDcGA1UEAxMwU2VjdGlnbyBFQ0MgRXh0ZW5kZWQg VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEAyJ5Ca9JyXq8bO+krLVWysbtm7fdMSJ54uFD23t0x6JAC4IjxevfQJzW z4T6yY+FybTBqtOa++ijJFnkB5wKy6OCAY0wggGJMB8GA1UdIwQYMBaAFDrhCYbU zxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBTvwSqVDDLa+3Mw3IoT2BVL9xPo+DAO BgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwOgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYBBQUH AgEWGWh0dHBzOi8vY3BzLnVzZXJ0cnVzdC5jb20wUAYDVR0fBEkwRzBFoEOgQYY/ aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRp b25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0 cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0 MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49 BAMDA2gAMGUCMQCjHztBDL90GCRXHlGqm0H7kzP04hd0MxwakKjWzOmstXNFLONj RFa0JqI/iKUJMFcCMCbLgyzcFW7DihtY5XE0XCLCw+git0NjxiFB6FaOFIlyDdqT j+Th+DJ92JLvICVD/g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrjCCAzOgAwIBAgIQNb50Y4yz6d4oBXC3l4CzZzAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgxMTAy MDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBlTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMP U2VjdGlnbyBMaW1pdGVkMT0wOwYDVQQDEzRTZWN0aWdvIEVDQyBPcmdhbml6YXRp b24gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMFkwEwYHKoZIzj0CAQYIKoZI zj0DAQcDQgAEnI5cCmFvoVij0NXO+vxE+f+6Bh57FhpyH0LTCrJmzfsPSXIhTSex r92HOlz+aHqoGE0vSe/CSwLFoWcZ8W1jOaOCAW4wggFqMB8GA1UdIwQYMBaAFDrh CYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBRNSu/ERrMSrU9OmrFZ4lGrCBB4 CDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAU BggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgGBmeBDAEC AjBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEE ajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRy dXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVz ZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaQAwZgIxAOk//uo7i/MoeKdcyeqvjOXs BJFGLI+1i0d+Tty7zEnn2w4DNS21TK8wmY3Kjm3EmQIxAPI1qHM/I+OS+hx0OZhG fDoNifTe/GxgWZ1gOYQKzn6lwP0yGKlrP+7vrVC8IczJ4A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGNDCCBBygAwIBAgIQKE45wUs4bYiccpnljNBaVzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBkTELMAkGA1UEBhMCR0IxGzAZBgNV BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE ChMPU2VjdGlnbyBMaW1pdGVkMTkwNwYDVQQDEzBTZWN0aWdvIFJTQSBFeHRlbmRl ZCBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQCaoslYBiqFev0Yc4TXPa0s9oliMcn9VaENfTUK4GVT7niB QXxC6Mt8kTtvyr5lU92hDQDh2WDPQsZ7oibh75t2kowT3z1S+Sy1GsUDM4NbdOde orcmzFm/b4bwD4G/G+pB4EX1HSfjN9eT0Hje+AGvCrd2MmnxJ+Yymv9BH9OB65jK rUO9Na4iHr48XWBDFvzsPCJ11Uioof6dRBVp+Lauj88Z7k2X8d606HeXn43h6acp LLURWyqXM0CrzedVWBzuXKuBEaqD6w/1VpLJvSU+wl3ScvXSLFp82DSRJVJONXWl dp9gjJioPGRByeZw11k3galbbF5gFK9xSnbDx29LAgMBAAGjggGNMIIBiTAfBgNV HSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQULGn/gMmHkK40 4bTnTJOFmUDpp7IwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDoGA1UdIAQzMDEwLwYEVR0g ADAnMCUGCCsGAQUFBwIBFhlodHRwczovL2Nwcy51c2VydHJ1c3QuY29tMFAGA1Ud HwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RS U0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYI KwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FB ZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0 LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAQ4AzPxVypLyy3IjUUmVl7FaxrHsXQq2z Zt2gKnHQShuA+5xpRPNndjvhHk4D08PZXUe6Im7E5knqxtyl5aYdldb+HI/7f+zd W/1ub2N4Vq4ZYUjcZ1ECOFK7Z2zoNicDmU+Fe/TreXPuPsDicTG/tMcWEVM558OQ TJkB2LK3ZhGukWM/RTMRcRdXaXOX8Lh0ylzRO1O0ObXytvOFpkkkD92HGsfS06i7 NLDPJEeZXqzHE5Tqj7VSAj+2luwfaXaPLD8lQEVci8xmsPGOn0mXE1ZzsChEPhVq FYQUsbiRJRhidKauhd+G2CkRTcR5fpsuz+iStB9s5Fks9lKoXnn0hv78VYjvR78C Cvj5FW/ounHjWTWMb3il9S5ngbFGcelB1l/MQkR63+1ybdi2OpjNWJCftxOWUpkC xaRdnOnSj7GQY0NLn8Gtq9FcSZydtkVgXpouSFZkXNS/MYwbcCCcRKBbrk8ss0SI Xg1gTURjh9VP1OHm0OktYcUw9e90wHIDn7h0qA+bWOsZquSRzT4s2crF3ZSA3tuV /UJ33mjdVO8wBD8aI5y10QreSPJvZHHNDyCmoyjXvNhR+u3arXUoHWxO+MZBeXbi iF7Nwn/IEmQvWBW8l6D26CXIavcY1kAJcfyzHkrPbLo+fAOa/KFl3lIU+0biEVNk Q9zXE6hC6X4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqDCCAy6gAwIBAgIRAPNkTmtuAFAjfglGvXvh9R0wCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MTEw MjAwMDAwMFoXDTMwMTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAkdCMRswGQYDVQQI ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoT D1NlY3RpZ28gTGltaXRlZDE3MDUGA1UEAxMuU2VjdGlnbyBFQ0MgRG9tYWluIFZh bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEH A0IABHkYk8qfbZ5sVwAjBTcLXw9YWsTef1Wj6R7W2SUKiKAgSh16TwUwimNJE4xk IQeV/To14UrOkPAY9z2vaKb71EijggFuMIIBajAfBgNVHSMEGDAWgBQ64QmG1M8Z wpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQU9oUKOxGG4QR9DqoLLNLuzGR7e64wDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMBsGA1UdIAQUMBIwBgYEVR0gADAIBgZngQwBAgEwUAYD VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/ BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVD Q0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1 c3QuY29tMAoGCCqGSM49BAMDA2gAMGUCMEvnx3FcsVwJbZpCYF9z6fDWJtS1UVRs cS0chWBNKPFNpvDKdrdKRe+oAkr2jU+ubgIxAODheSr2XhcA7oz9HmedGdMhlrd9 4ToKFbZl+/OnFFzqnvOhcjHvClECEQcKmc8fmA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGGTCCBAGgAwIBAgIQE31TnKp8MamkM3AZaIR6jTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBlTELMAkGA1UEBhMCR0IxGzAZBgNV BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE ChMPU2VjdGlnbyBMaW1pdGVkMT0wOwYDVQQDEzRTZWN0aWdvIFJTQSBPcmdhbml6 YXRpb24gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAnJMCRkVKUkiS/FeN+S3qU76zLNXYqKXsW2kDwB0Q 9lkz3v4HSKjojHpnSvH1jcM3ZtAykffEnQRgxLVK4oOLp64m1F06XvjRFnG7ir1x on3IzqJgJLBSoDpFUd54k2xiYPHkVpy3O/c8Vdjf1XoxfDV/ElFw4Sy+BKzL+k/h fGVqwECn2XylY4QZ4ffK76q06Fha2ZnjJt+OErK43DOyNtoUHZZYQkBuCyKFHFEi rsTIBkVtkuZntxkj5Ng2a4XQf8dS48+wdQHgibSov4o2TqPgbOuEQc6lL0giE5dQ YkUeCaXMn2xXcEAG2yDoG9bzk4unMp63RBUJ16/9fAEc2wIDAQABo4IBbjCCAWow HwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFBfZ1iUn Z/kxwklD2TA2RIxsqU/rMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/ AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYG BFUdIAAwCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl cnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy bDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZ aHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAThNA lsnD5m5bwOO69Bfhrgkfyb/LDCUW8nNTs3Yat6tIBtbNAHwgRUNFbBZaGxNh10m6 pAKkrOjOzi3JKnSj3N6uq9BoNviRrzwB93fVC8+Xq+uH5xWo+jBaYXEgscBDxLmP bYox6xU2JPti1Qucj+lmveZhUZeTth2HvbC1bP6mESkGYTQxMD0gJ3NR0N6Fg9N3 OSBGltqnxloWJ4Wyz04PToxcvr44APhL+XJ71PJ616IphdAEutNCLFGIUi7RPSRn R+xVzBv0yjTqJsHe3cQhifa6ezIejpZehEU4z4CqN2mLYBd0FUiRnG3wTqN3yhsc SPr5z0noX0+FCuKPkBurcEya67emP7SsXaRfz+bYipaQ908mgWB2XQ8kd5GzKjGf FlqyXYwcKapInI5v03hAcNt37N3j0VcFcC3mSZiIBYRiBXBWdoY5TtMibx3+bfEO s2LEPMvAhblhHrrhFYBZlAyuBbuMf1a+HNJav5fyakywxnB2sJCNwQs2uRHY1ihc 6k/+JLcYCpsM0MF8XPtpvcyiTcaQvKZN8rG61ppnW5YCUtCC+cQKXA0o4D/I+pWV idWkvklsQLI+qGu41SWyxP7x09fn1txDAXYw+zuLXfdKiXyaNb78yvBXAfCNP6CH MntHWpdLgtJmwsQt6j8k9Kf5qLnjatkYYaA7jBU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb +ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH 7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38 sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq 6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K 00u/I5sUKUErmgQfky3xxzlIPK1aEn8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpjCCAyugAwIBAgIRAIgQfK/2XAW2FTReKHGJpvEwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MTEw MjAwMDAwMFoXDTMwMTIzMTIzNTk1OVowgZYxCzAJBgNVBAYTAkdCMRswGQYDVQQI ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoT D1NlY3RpZ28gTGltaXRlZDE+MDwGA1UEAxM1U2VjdGlnbyBFQ0MgQ2xpZW50IEF1 dGhlbnRpY2F0aW9uIGFuZCBTZWN1cmUgRW1haWwgQ0EwWTATBgcqhkjOPQIBBggq hkjOPQMBBwNCAAS7oMoslfoAYkh/ZNv4XR1GejWc2JKwUrmIaBMiPD1yaAkCLrR3 NL7tUSbCGq2ySZMTMRIoVyiXNiHpB86xs3iWo4IBZDCCAWAwHwYDVR0jBBgwFoAU OuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFLxzFsPwbS/aSglRBH6rjPXJ hyaMMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQW MBQGCCsGAQUFBwMCBggrBgEFBQcDBDARBgNVHSAECjAIMAYGBFUdIAAwUAYDVR0f BEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVD Q0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/Bggr BgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0Fk ZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3Qu Y29tMAoGCCqGSM49BAMDA2kAMGYCMQDCD3nmeVCBqnqeExkwqKW4z43e5qarQnbF pqmcp/bsEbCSC9wBFMte4D1QhXKu6bYCMQCPnVdna/0sC6MMckqCloxhPYsIUlmM kmcdlxJqkRkatp1mQG03aiQ3jfZkkzKJ8Mc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGEDCCA/igAwIBAgIQTZQsENQ74JQJxYEtOisGTzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBljELMAkGA1UEBhMCR0IxGzAZBgNV BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE ChMPU2VjdGlnbyBMaW1pdGVkMT4wPAYDVQQDEzVTZWN0aWdvIFJTQSBDbGllbnQg QXV0aGVudGljYXRpb24gYW5kIFNlY3VyZSBFbWFpbCBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMo87ZQKQf/e+Ua56NY75tqSvysQTqoavIK9viYc KSoq0s2cUIE/bZQu85eoZ9X140qOTKl1HyLTJbazGl6nBEibivHbSuejQkq6uIgy miqvTcTlxZql19szfBxxo0Nm9l79L9S+TZNTEDygNfcXlkHKRhBhVFHdJDfqB6Mf i/Wlda43zYgo92yZOpCWjj2mz4tudN55/yE1+XvFnz5xsOFbme/SoY9WAa39uJOR HtbC0x7C7aYivToxuIkEQXaumf05Vcf4RgHs+Yd+mwSTManRy6XcCFJE6k/LHt3n dD3sA3If/JBz6OX2ZebtQdHnKav7Azf+bAhudg7PkFOTuRMCAwEAAaOCAWQwggFg MB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBQJwPL8 C9qU21/+K9+omULPyeCtADAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwEQYDVR0gBAowCDAG BgRVHSAAMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNv bS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEF BQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9V U0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29j c3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAQUR1AKs5whX13o6V bTJxaIwA3RfXehwQOJDI47G9FzGR87bjgrShfsbMIYdhqpFuSUKzPM1ZVPgNlT+9 istp5UQNRsJiD4KLu+E2f102qxxvM3TEoGg65FWM89YN5yFTvSB5PelcLGnCLwRf CX6iLPvGlh9j30lKzcT+mLO1NLGWMeK1w+vnKhav2VuQVHwpTf64ZNnXUF8p+5JJ pGtkUG/XfdJ5jR3YCq8H0OPZkNoVkDQ5CSSF8Co2AOlVEf32VBXglIrHQ3v9AAS0 yPo4Xl1FdXqGFe5TcDQSqXh3TbjugGnG+d9yZX3lB8bwc/Tn2FlIl7tPbDAL4jNd UNA7jGee+tAnTtlZ6bFz+CsWmCIb6j6lDFqkXVsp+3KyLTZGXq6F2nnBtN4t5jO3 ZIj2gpIKHAYNBAWLG2Q2fG7Bt2tPC8BLC9WIM90gbMhAmtMGquITn/2fORdsNmaV 3z/sPKuIn8DvdEhmWVfh0fyYeqxGlTw0RfwhBlakdYYrkDmdWC+XszE19GUi8K8p lBNKcIvyg2omAdebrMIHiAHAOiczxX/aS5ABRVrNUDcjfvp4hYbDOO6qHcfzy/uY 0fO5ssebmHQREJJA3PpSgdVnLernF6pthJrGkNDPeUI05svqw1o5A2HcNzLOpklh NwZ+4uWYLcAi14ACHuVvJsmzNic= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuzCCA6OgAwIBAgIQFMfOWTeODs3ocezWp4xhNTANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE4MTEwNjAwMDAwMFoXDTMw MTIzMTIzNTk1OVowgYgxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1h bmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGlt aXRlZDEwMC4GA1UEAxMnU2VjdGlnbyBSU0EgUHJvIFNlcmllcyBTZWN1cmUgU2Vy dmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwx4YXoLwl2b4 QhWnXxnYvFcjCGAewDI2iT39FXYvSaiK+1A05EBmxXGRttOnl8OLjB29ImQjWhMn P86Mh8sV/CfxBUnnpDJC40h4eqHEpX9otWLjLTNsKUXD4V94d52Wyjv53Dwv3U/W eNt4xgNbgPJkASioGUaO5t6sAUwWMYWA4an9AKupg3byc5SEOWH/B4qm4AAo5xGc zo4fJECPYvgIt9EKDWUp3tXKCKsxqxC2h4raKokTtrAnKCaCwaqyZJzLu9ZXLOjy HcQoXwrMMyOO9W5DH2aos6NJEjw5DMhy/I0TttHqFlKwXVdl5L4wMVZSpp/u0yCK QP+GS4LV0wIDAQABo4IBKzCCAScwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Kl f9AwpLQwHQYDVR0OBBYEFIHFuh2zAn3Bv1bxaAzoB4aceoDGMA4GA1UdDwEB/wQE AwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMCkGA1UdJQQiMCAGCCsGAQUFBwMBBggr BgEFBQcDAgYKYIZIAYb4TQECAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQIB MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNl cnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcw AYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAj 8Y6ulwmqXyi3huINyFS5P16QGyauAJpQ0QRS7LE0rF6gk+qdKruOUUnztdAepg3S TxzyCZP4ewki4asVk4ZxXW/XQ4mQbvc5bGk60yAp8Dumx+l4X4awcUl0pN/L37mt QGpe5MAC0AmW3i+H+UXQtdtypfCOfgyC0a8j6b1NWFgsTQK1l/yEZcuAT2BDJcl2 ehye7+u3UqfM15JueAcUByFBASokKYYbDVOuP10HDEfJB0OXx8ZQjMybB+wtPMTf hYUHNLNxezftAZk/INrtwLrU7OXAOR5tM5MHMroducCK+2VFK4mB+TTzFokdHQnf jv8WxygOnqiipIqhVvwB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIElDCCA3ygAwIBAgIQCmioyQeveH9jehvnbDs55jANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xODExMjAxMjM5MzFaFw0yODExMjAxMjM5MzFaMGcxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xJjAkBgNVBAMTHURpZ2lDZXJ0IFNlY3VyZSBTaXRlIEtvcmVhIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLLsm9xltothSSjvNqxV3qBScyfD BGLgEKpr0AQpmybWvSpe3Cx9iZCmfKwxzTBF9h32i/GRjzUNFBazv2m98eO7hlkn YJg9UcTJj4yXurXt0L2835uIx3UKHe7rXhefTbo3aHu5z/A29MovRqX62jV8wszo sA6KOV3gXLnKmfxVM6eA4jVl9qYNIsyOY2jFiXvnqqbRHciAs8gD/FuB6U/Tm4qN E3E7xvchN7OUWg2XplLsRZ7suQODmPT+qz7u/hJF99MwSVbC5CzH4NFwMlMSIQGP OViY/NMYn84kTPcbRwO/T1vGQet+hIXPpukBHSiBx0vXeNhhCYrBKUamDwIDAQAB o4IBQDCCATwwHQYDVR0OBBYEFKISuti6MOlEvbzkuf8JxZMuQZ7aMB8GA1UdIwQY MBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0Bggr BgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNv bTBCBgNVHR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGln aUNlcnRHbG9iYWxSb290RzIuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsG AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEB CwUAA4IBAQCn0tlfwJL5C+7nstYLdUcFXlaea8G7225DSWQfQh7H7DljMbh/cavB 7Wv8dn6JmEhTiBHNgzmqVWiL92RJ1MVWlva6+NCmPx4cM20mkvKP6LxxxpWc4BUW iBP1pZFH754b+46p2UC8V24tSAHOgaHs8yhy+PwwCu5qj/qEOBYG1vV5vOmb0Oq5 Ht2hjDkNZrra0ykHhJLQN4r9ILcmc0UXBDlTlYc/ooNs/GhHMg1deyQgIpPZVpeb Mr2udigGJfBQPYEIu+CErDBtPgfUlyH6zlyZJGdVDqvKJJCE6GtUVx6z5FLIOiZi y6s6uTDUy/jEkKwtNPbDgq+CfIcprc1P -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEnTCCA4WgAwIBAgIQCuPG8785fx4dEpgiz73xhjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xODExMjAxMjM5MzZaFw0yODExMjAxMjM5MzZaMHAxCzAJBgNVBAYTAkpQ MRwwGgYDVQQKExNEaWdpQ2VydCBKYXBhbiBHLksuMRswGQYDVQQLExJ3d3cuZGln aWNlcnQuY28uanAxJjAkBgNVBAMTHURpZ2lDZXJ0IFNlY3VyZSBTaXRlIEphcGFu IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA04jr0TNk5SzwmRgQ +IxSqwTbRIC1d5O6rOintlLr8fCzyaGUbR6tanIIreGztCfwQQZSWDEACnJnE8lH zG8HPtzow7AQe3XHbQvXUGGMtnmuReRGhjwwse8DutKOCnuNFrfFkojl2K5+abV7 bTDSI9+mCREpvDUmGsfXOhrwQr2RVx6BZ4MtuvOBng1/5CcNaIJ9fZk71s6oJQiw 04Ogfa5w7kg78WQf+mqH9873jplhNrZoPzEb+ZqZzms75fYAKPHN2FWtfRj7tu0y bw5ORJOWY20G4ao/OTVrf3z0Di25dsUKqHtbgmJ++jnqM5k6b2tGk1TbDuYhXzdJ T2zMGQIDAQABo4IBQDCCATwwHQYDVR0OBBYEFMewKcGEykLLxtorblP5vAv7cx2Q MB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIB hjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB /wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp Z2ljZXJ0LmNvbTBCBgNVHR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2Vy dC5jb20vRGlnaUNlcnRHbG9iYWxSb290RzIuY3JsMD0GA1UdIAQ2MDQwMgYEVR0g ADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA0G CSqGSIb3DQEBCwUAA4IBAQA96QGXTvT8oVPzjja7SQmgbruu71LoPC+mF/d89FMf Er05HRt3DsvIhaeWMON7DFs0w1huL6O2881xe5EqF95EsOyK/pEFiaxESsUbdfqk 0b4vt0c9oWp/LiZx//kyKMUBL7aejwBo91YtxbsADH/hE/65EG6Q7rXGRwd7dZ/q n1EznnqUCk+rB8SegCSABrZNxBPlVJFMLw4uvBf79KF8rVRrG7N2+KzuzNzTSpu8 /f25j6f0kpaaz9Tnq99S8SfLEr+FMTMrEH+ZjdiwP0eKeitX4lS9n2WhKyEsD7t+ zC8YzcPk7ec2aDWdhwSwyE7hA2RWW3sAmu76/VbLm61m -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEiDCCA3CgAwIBAgIQB+xL3s3F6FxYGFofF6T+oTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xODExMjAxMjM5NDFaFw0yODExMjAxMjM5NDFaMFsxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xGjAYBgNVBAMTEVRoYXd0ZSBQYXJ0bmVyIENBMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAyi5Il14p1jX7Gbay4U7qxzC1dqj55EmoP5wZGV/O7ica IFKZpTa0wNFjd1TCAzbHpvnkWNJqTVQlj43vlRAGuiVjhYd33VeWzIyREkHhxr+L LkKjIVd4xUEzO987o8nqAe2j16Yfuqn4KOQzIr9S1P5QpGJRTVH1VgzJcFObMMZt 0QPRt2rKrF1ART3f/Q/SRdJzZtJguJt9E+k0F64JJQb/o74vhLVLRygip0vHZIjq rVOUOcXFwH10o/R9ANUMO/cqxW+oi6dHMBBwWAJ+YRXiCUNo1KisFVLoTZEasqf3 AZfPd61tmR5DgfIFQ4VC2JqjXQDs0/BoATDdklN98QIDAQABo4IBQDCCATwwHQYD VR0OBBYEFG0vBxfZWDscb/qKDRRXSBFDZJr3MB8GA1UdIwQYMBaAFE4iVCAYlebj buYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYw JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBCBgNVHR8EOzA5 MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxS b290RzIuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRw czovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQBzojCB Wg9A4GeVXZg9/nP87nj/d8rIsWXK7Uma4vgnarTFifF/uZVV8q5ITm8FqYYt4kve MG3XK95CGPJKNQVLkljg4YMJMAc4z3UW7w7UYULDsi4336BKVWHq3dNCzh0Jhb3Z swieEzu8esTIAWtyy+Wj3v2SluMeonVKe7mlyJYK3JOFHN63Wi4e0wuanS/kw/e6 gfl3FP2E2Gz4S69Dw32CcIA3Vc828Bui5tiExXhtnT1Z0TR9rCftud5TRO4SSqGk TXgRrGE8cref2xv6vLJszq7HyS/tD5pxsdP4sktkiGlw88Y83qrKm5L+QywhkJi1 4HRViMWBwjy/Zjhe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnTCCAoWgAwIBAgINAe5fIj49NVuZK8gqtDANBgkqhkiG9w0BAQwFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFs U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODExMjEwMDAwMDBaFw0yOTAz MTgxMDAwMDBaMFAxJDAiBgNVBAsTG0dsb2JhbFNpZ24gRUNDIFJvb3QgQ0EgLSBS NTETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjB2MBAG ByqGSM49AgEGBSuBBAAiA2IABEdFDpb7fV2/6TnRIfifC7bVex6SOkhZHPBiMS3A eij+Gqdcs7bMl+dF1Fj60XdtQ6LAh2U0Ch963es8M6HFnU2kb0GVOH/JHoTr0Z5J koeUhww6hUpmn51Zk02XYQaGSqOCASYwggEiMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQ95ilIm+oHyiFESibebt7Sg9CfWTAfBgNV HSMEGDAWgBSP8Et/qC5FJK5NUPpjmove4t0bvDA+BggrBgEFBQcBAQQyMDAwLgYI KwYBBQUHMAGGImh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjMwNgYD VR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIz LmNybDBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93 d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQEMBQADggEB AEr6e27WML3zFYJfjApU2aS3C2iAenE5n694Vu0v9wh33RkXK6ccDsLgj0qI2CaH VWCyIh7MHyS7vcK2yxJUnh84wQAV46tLByHG32btb2XGxOxt8C08/G2iZqL7Hmvo DKfxQ/yAxueM0odidxshAL33bzHj6zgj3PMkguCuXsZSIr5Y0r63qHIYmP8jXG0o +S4qbyhM8G7eMb35iG+qrrpklUuOAez4RI6w6abSZSxaxxuwv9T/32jKbR0bEq5D pTtZAAKsZdPVb9tztaxp7y2GEOS2sbhI+VoOBiONdBoRyszsK3bUu18qDpvkiHkM MEaA47hRsmFqL16t4Ui72Ec= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAomgAwIBAgINAe5fIpVCSQX5AZGo3DAKBggqhkjOPQQDAzBQMSQwIgYD VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjUxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTgxMTIxMDAwMDAwWhcNMjgx MTIxMDAwMDAwWjBQMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBu di1zYTEmMCQGA1UEAxMdR2xvYmFsU2lnbiBFQ0MgT1YgU1NMIENBIDIwMTgwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAATDoRGNZSPhluG7q6bQA11PTe0ZD/xx44QlFam1 BM4eLeN+wfgwalsbkjzARCM9si/fnQeKNtKAlgNmNOHTmV3VfwGbocj6+22HVWZu VeX/VeIGoWh1u7Lja/NDE7RsXaCjggEpMIIBJTAOBgNVHQ8BAf8EBAMCAYYwEgYD VR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUWHuOdSr+YYCqkEABrtboB0ZuP0gw HwYDVR0jBBgwFoAUPeYpSJvqB8ohREom3m7e0oPQn1kwPgYIKwYBBQUHAQEEMjAw MC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHI1 MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9v dC1yNS5jcmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBz Oi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMAoGCCqGSM49BAMDA2cA MGQCMC4lzZGQw5mpNZBmztq8huxKf9/tRUJ5yLI4q6YU+i2fjF2FRBNA64EBmljA 7dkSOwIwL9qYB0APhsLmV0LhknrzHZVvtqzg7NQaIV18BEIDZQgK3gjxYzADjHSH 5uk4mCdW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAomgAwIBAgINAe5fIqUvfWwWGu1LsjAKBggqhkjOPQQDAzBQMSQwIgYD VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjUxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTgxMTIxMDAwMDAwWhcNMjgx MTIxMDAwMDAwWjBQMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBu di1zYTEmMCQGA1UEAxMdR2xvYmFsU2lnbiBFQ0MgRVYgU1NMIENBIDIwMTgwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAAT6IB5AMcL86n43ZgyKS4VW3d6/Gjj4h8/KFiLr npBSpOj66qbLgW0I/+VUDHu+V86I3D5Rsovv3RA3viu2sQN5CnkbZJ7Q0rCVZd1V FoR9hPRn602aCA5no9ofW5p+HwajggEpMIIBJTAOBgNVHQ8BAf8EBAMCAYYwEgYD VR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU2+/d/JdC11UoDeL3MHh071KLbd0w HwYDVR0jBBgwFoAUPeYpSJvqB8ohREom3m7e0oPQn1kwPgYIKwYBBQUHAQEEMjAw MC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHI1 MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9v dC1yNS5jcmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBz Oi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMAoGCCqGSM49BAMDA2cA MGQCME3jMkzOyNRNWTFXoeqLIZ9ZidYq+sHm+qxb6PvS8xMnqJ+o9saZrIIz45xU pfHcAgIwdgiRo9SYGrVNDOfHdJLtCAy2XiKDPwHpQ6Jc7MJEpwl7fnkjsZLgTtTG QgXZtk+o -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIETjCCAzagAwIBAgINAe5fIh38YjvUMzqFVzANBgkqhkiG9w0BAQsFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFs U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODExMjEwMDAwMDBaFw0yODEx MjEwMDAwMDBaMFAxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52 LXNhMSYwJAYDVQQDEx1HbG9iYWxTaWduIFJTQSBPViBTU0wgQ0EgMjAxODCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdaydUMGCEAI9WXD+uu3Vxoa2uP UGATeoHLl+6OimGUSyZ59gSnKvuk2la77qCk8HuKf1UfR5NhDW5xUTolJAgvjOH3 idaSz6+zpz8w7bXfIa7+9UQX/dhj2S/TgVprX9NHsKzyqzskeU8fxy7quRU6fBhM abO1IFkJXinDY+YuRluqlJBJDrnw9UqhCS98NE3QvADFBlV5Bs6i0BDxSEPouVq1 lVW9MdIbPYa+oewNEtssmSStR8JvA+Z6cLVwzM0nLKWMjsIYPJLJLnNvBhBWk0Cq o8VS++XFBdZpaFwGue5RieGKDkFNm5KQConpFmvv73W+eka440eKHRwup08CAwEA AaOCASkwggElMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G A1UdDgQWBBT473/yzXhnqN5vjySNiPGHAwKz6zAfBgNVHSMEGDAWgBSP8Et/qC5F JK5NUPpjmove4t0bvDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6 Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjMwNgYDVR0fBC8wLTAroCmgJ4Yl aHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBHBgNVHSAEQDA+ MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5j b20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAJmQyC1fQorUC2bbmANz EdSIhlIoU4r7rd/9c446ZwTbw1MUcBQJfMPg+NccmBqixD7b6QDjynCy8SIwIVbb 0615XoFYC20UgDX1b10d65pHBf9ZjQCxQNqQmJYaumxtf4z1s4DfjGRzNpZ5eWl0 6r/4ngGPoJVpjemEuunl1Ig423g7mNA2eymw0lIYkN5SQwCuaifIFJ6GlazhgDEw fpolu4usBCOmmQDo8dIm7A9+O4orkjgTHY+GzYZSR+Y0fFukAj6KYXwidlNalFMz hriSqHKvoflShx8xpfywgVcvzfTO3PYkz6fiNJBonf6q8amaEsybwMbDqKWwIX7e SPY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT 7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o 6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ 8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi 0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF 6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er 3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA rBPuUBQemMc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGazCCBFOgAwIBAgIPAWdfgr4AF96JVak3brH5MA0GCSqGSIb3DQEBCwUAMDcx FDASBgNVBAoMC1RlbGlhU29uZXJhMR8wHQYDVQQDDBZUZWxpYVNvbmVyYSBSb290 IENBIHYxMB4XDTE4MTEyOTEyNDAxM1oXDTMyMTAxODEyMDA1MFowRDELMAkGA1UE BhMCRkkxGjAYBgNVBAoMEVRlbGlhIEZpbmxhbmQgT3lqMRkwFwYDVQQDDBBUZWxp YSBSb290IENBIHYyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAstA/ B7zie9Brmfjid2nnzp2kA7yCbaH+gWUfTCesjgC6FnvrMGoAwLN0aH6yr8fVYrN6 P1DKjDZEJGPSNukMhfZDdtVMoWByZ+IoM6XLMbg6IiM0uH29ViJAner0ewOtaPyy gU+Y0HTqjeV9zWPDo/beksJYGeCWu8XEqT2ldJb+r/mJqr2VF1TYeETxDHcVkuCY Qqek1qogks3BoLOWsjqEQo191ZXk1tvpYsRYs3nFjNM1M4OfdaFSJ2E48Vk9jlDg vXk852yW/l7ZAmW0jlzQETTfXb9Sp4EAw3+ZRZkV1RfIClPsY/OZfcxpEobCF/AB nr+EvNFSyxuSZs6kU+Whv8TbCdbmiVYryON83uP/ieU1bijobAsjUaklBetI+N2x yvpsCFHvtxhsRMom4XPGiQaB5YqssOIpxrkks2tEEfSlQ8JMQ+VwNoy2M1d6lS6C oPRcELNhg/YCBYYufC1s3ANGbjWT1XqVL94g2Ft+lJAEarpZPQQFdZ03og4uPevB pFKD/tBr1GaO3MbpEk4dKleqELx8XoJ9pqbJ8i259RcnrdEOiVQrlfrArR2YFHgz QoYKqXO1+3QNtxswGcRaDhwnt9oY0P+KyAW68aocoje35kikRiyU6qh2YkeLEFMH SFds4pJNtq4Fy9zBSl6PrD0ZTsLtYHUr28HKQtUCAwEAAaOCAWUwggFhMB8GA1Ud IwQYMBaAFPCPWTgAs/WPmpYM1ev6e6oX6BMSMB0GA1UdDgQWBBRyrOQzeapFh/b9 rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwPAYDVR0gBDUwMzAxBgRVHSAAMCkw JwYIKwYBBQUHAgEWG2h0dHBzOi8vY3BzLnRydXN0LnRlbGlhLmNvbTAPBgNVHRMB Af8EBTADAQH/MEcGA1UdHwRAMD4wPKA6oDiGNmh0dHA6Ly9odHRwY3JsLnRydXN0 LnRlbGlhLmNvbS90ZWxpYXNvbmVyYXJvb3RjYXYxLmNybDB3BggrBgEFBQcBAQRr MGkwPgYIKwYBBQUHMAKGMmh0dHA6Ly9jcHMudHJ1c3QudGVsaWEuY29tL3RlbGlh c29uZXJhcm9vdGNhdjEuY2VyMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC50cnVz dC50ZWxpYS5jb20wDQYJKoZIhvcNAQELBQADggIBAIesRw+pLLljhtNfr+wtck0h 9fJOPzxsDF0YuKvB5uzIFZv0p0J4d5kQhifNLAVG9cOjwVHaVkY72+Cqwv9j1wZi /DnWEFJ9EzQPUtF5Ob6Iur1CP0TlF6SFnM+ZMfEFQrXhS8ni2WC83Y2DjOTFpNKq 9HklT5U+0rLmgfiwSzaMtyCYpU09CSvxraZt/wmL/ov2IHW4gtravMyxi6Dnc4LC 1Qjndx09lgOuWBj3pD2fuFcN5DVVOxJE7Hl068CPxv3Q0kp5U4AQsTDk17LhLGUL VfP6zRThdzCWNKxvnzbjx7JKiutxOKLqAw/fCBBJP89kIv8EbMPc0gjXS8Y1nt1g xJo0xJeP8FpuTodW+1SABniEHYNy0T9C1BTsUdJa18ukOoR3l9uevvIUr652JSh/ LLPbb7l1mlXhQw9qVjnqqBhjKpkzvctcQnoeadxdMKrakbQovWKmg5QLGyjORjbh aYmMv+hUcZp1ccbBxXlnpkgSME+vyMzicbyZFnaYOwZAIXDle9VW3oHZrBcXrSx9 GrfB0I6Bru0elSbKSLLzaMJkf8+glt1mK5w0IaIWPnOrrxwkU2NIplhA+m+wACyA DksNn9GptR6KJsSoKwwwT5I5wuNeay96HMf9I6EAFIUl42l4lWK6NSfZ/LgSDaFl BIcaW5MU53XS4ddc3md2 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGnzCCBIegAwIBAgIPAWdfrHKZTHS/GmftwbOtMA0GCSqGSIb3DQEBCwUAMEQx CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMzMwMzJaFw00MzExMjkxMTU1 NTRaMFMxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEo MCYGA1UEAwwfVGVsaWEgRXh0ZW5kZWQgVmFsaWRhdGlvbiBDQSB2MzCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBAM5UUDh1YvHRzHKqO7BwDh1V4Wc3pCgR FnM02WJkGzi5HGzWEbQ3hK0Z7RDvVusdxiIG+C5pVaiI1sjgkFf58l90NPqh5KtS pQi2flDTZkdnDREvuibNu/kKowkuQ67F4eDiLSyo8qbyBWtKiov17RECFVFQH3eI hd8jn2CIgUaaIh23c4lzZcD2nItu7tRJpdAD5FAzFTr+WLKNovsbkwAsnX7v+KLk TBTQLlqUmJJ/VlRWMfYDRByGh/dQK2/YqCmdfKoGdibWruMH6rx78rUBjmwjOz1H 4R5xxec98gLDJpd1BDC0esqqdw+A/Ui31szxwjG3WYKC2Ph7cJvUIjzx7DEMhQts t8M0S+QP7J/WgGVXQfmDNI6zW3Veh8MA+uTI9ET2OyEKqX12jfFYwmD/w//SKeO9 4dMtwI9U6WHJIi6YdsLZcRjFeQ7WkF4wg0ilt+zZhzu9WXm9NARZ3DDOh0wA/qoW p+z9GLyagonZpg9ZG5nKOrGXra/t6GDLZaa0LWOxfZvYP62M3BdG7MLW17DwloL6 mH0zwFMPNWwxQdvEOf8ZJqY4j+hA+LTPkM7lHNmFyhfbAYWrUrnQknU+WaUEDMfe 4vDmG3kvNf4AsQ5z6qFMiBgZKrf9dWYRT7He/ZWPDXOQvQZPMnCPxDxTCDRyQhLV tmvSWSH8WEH1AgMBAAGjggF9MIIBeTAfBgNVHSMEGDAWgBRyrOQzeapFh/b9rB2e 1scvhtgkOTAdBgNVHQ4EFgQU+zZwO10f8H2yIInA6S632ehYqDUwDgYDVR0PAQH/ BAQDAgEGMD4GA1UdIAQ3MDUwMwYFZ4EMAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6 Ly9jcHMudHJ1c3QudGVsaWEuY29tLzASBgNVHRMBAf8ECDAGAQH/AgEAMEEGA1Ud HwQ6MDgwNqA0oDKGMGh0dHA6Ly9odHRwY3JsLnRydXN0LnRlbGlhLmNvbS90ZWxp YXJvb3RjYXYyLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwcQYI KwYBBQUHAQEEZTBjMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC50cnVzdC50ZWxp YS5jb20wOAYIKwYBBQUHMAKGLGh0dHA6Ly9jcHMudHJ1c3QudGVsaWEuY29tL3Rl bGlhcm9vdGNhdjIuY2VyMA0GCSqGSIb3DQEBCwUAA4ICAQA1uu3Sm3+UxXKdFqYB UQu/CGveKYVORHgbQ1czZ+UfZgvmUw4w8EP/OFHo6OR0pMqFiZEOBiFqNDksucOh R/fzqbf3JWgyQkPgImYdECK/j84HZCGySD7vQIbUqRaIGp8G8V9Wa80HVyntcWKz RCuLYLQ/liNDuNLc2ijwmsm5kZ+xiPvmiY0G8wBzgRSvgaZOj1IMxOSRsQARm5Hk QAdIgExmc3fsaQhCeXtZpcs1AwVB99Qx010IcK3mv8Zdy9OzR0QkPU2j8uK7Zj23 cuYcp5uBsnOAUQB+ASV4pf06IJ6NbYC7AbqLs1kDpi7AqKk4lVftftlcX5rAo8/j 4CI81DJRjjbiKWJIfpACSIHWObfPPw3jyJnDsZWKRbdOc8XMO9kqepu2GnKs8pmE mPjLadlbTt14ClYGCQpitYo6fgiBtWSeUjcXXLo3u5IcWFpMPvc56zp51Cq/E7K6 UmAJ7rxcEpH3PvA2auToJl61ud/BaW8fJgxakM0x1KLdsYPAXe0ZVeniCTENJEFC x5UponfhpxxY4aMOWznysVXGaoIsY5II539pkAayycy2bPiN1Sg8h5GwwldDnRfP FbD1hdK+na9x7ZHc3rTmO94OYDkkEoAk/bYJ/FOE0z4YfENS0RHdXBMWsRRVzME/ 1XugcrXQSUhnmRXQhk8RYgSFbA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkzCCBHugAwIBAgIPAWdf548Q80klfxazcx96MA0GCSqGSIb3DQEBCwUAMEQx CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxNDM2MDVaFw00MzExMjkxMTU1 NTRaMEYxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEb MBkGA1UEAwwSVGVsaWEgU2VydmVyIENBIHYzMIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEAvEOTCprOPJB1r/BikJEOi0F6J+/W2ZfRGzuBT0TYZpJ4DXbi /Y6W6KzcuUqQY4vH+h4rcF1aRSY+TBJs7GUoETp8YaWl+oLtceR7nW2M6AN0BSFc Uf3oz1iYT/RIoT+H6uW1JcS+zNUJeDhFbDV4yqDXmdOOmoG0LLWjhP1O8jPAIv3K trTnjBRSZ5bDY+z6hExAKNdIeaEd298LMbTSUaDXjvGKDmuVBj4DrwYmZDwWYIC6 OtOnomYo4HKVcyEevPeH5OprriOR2wr88STfJE0lQuwwKRpea8kbrQ7RT263w5Dn MZ1w6IK0+XYc+ME0EwgNnLjIvM7mMCufMXqpg3/imbf6XIyxwbsdbZ+UzTe5LUR+ a6y62mpLbIQ7ZPYGLchNOHVEbLSRkryNOaM7VOvYProEeOux8SkJLv38+awkHqJx uir3XkXOd80rmpgYV9EiSOe8UE9GldeenwT04lKaQoz1vBTAGXLuGbiG5M2BDkkM kwY0WBDQI8ihwLS8hHVmaFD2M1yPYOXlMRydVRHu9IQMXUzYfd+ezzqXotd0P5+X yYAcCFC4K0mcEEb39QRTAyb4+WCPXVVdluA7tnnGI+mfR4GRyi0FzuhlMxcwA31e iQ31Nx4jAhkY/0EBvdmH56cBnVar+46dK0uy84UNGg78SYrWdS57XSI64QcCAwEA AaOCAX4wggF6MB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1Ud DgQWBBRGZo0OByMWsOpPBeuWWt6l7sl+pDAOBgNVHQ8BAf8EBAMCAQYwPwYDVR0g BDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9jcHMudHJ1c3Qu dGVsaWEuY29tLzASBgNVHRMBAf8ECDAGAQH/AgEAMEEGA1UdHwQ6MDgwNqA0oDKG MGh0dHA6Ly9odHRwY3JsLnRydXN0LnRlbGlhLmNvbS90ZWxpYXJvb3RjYXYyLmNy bDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwcQYIKwYBBQUHAQEEZTBj MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC50cnVzdC50ZWxpYS5jb20wOAYIKwYB BQUHMAKGLGh0dHA6Ly9jcHMudHJ1c3QudGVsaWEuY29tL3RlbGlhcm9vdGNhdjIu Y2VyMA0GCSqGSIb3DQEBCwUAA4ICAQBEN/KA28R/Jzyds4FExxG9wrVdqrYoBbXW gZDXRt9y3lzXg6Y+Eos2yi7wqRLgzefpy5lGdWK2hejI/M618OWxfl8jE6LTneD2 1gkCAkZzVC7tPUWl3UiaaN5x95VOgEnkHirenbwxDl8vAZiIxH//AUQcLgizq4fa piAUsGIWO98v5+kolIsrbSpumAp0wYGg2tsE61vc6ijeZ7cU62RRbclQmMriHnT8 zLIdNxnQ/IqjG4AjCqa12bulYxwAfGOnLgTyTT3m40uLTlAD+yYAOfbDn1raWZIK IaTGpd36A9cIX5TcEDaEQqjAXZpb4AHjiifPAI2iR7I5iUNtt174NF6cBgEajs2u YrVBcMFfraLDQYfJjIw5jszQcwFbxVk6J5RsPzIgAY0BqBIDkuITyNZhe70x4cuQ mNxQp7MAU4f0kp1RhX2wzYu7BDy9z4qWbpCop4UNtlChcKvsqNybtrtWy1zGwosl DoQTHpWBH8Afy/Ql9/9C7+Z23wfwA3LX4BWtyT46NDD+XmIcyFgF7tzgcSSclGzP geCvWmSyIGBdNclb1GODzF8uZEoba7ooOxRrZktEcwTMc7rOdcBjqyi1aDf0cmFK QcypAX65ek2lVAQ+6H+U8dCGlfjSV43fEg8IYr+S5KNWTzmHV3xaLpxwNWpLuYJa fM15Si+DPA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGnjCCBIagAwIBAgIPAWdf/efkGBHizXawzbUKMA0GCSqGSIb3DQEBCwUAMEQx CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxNDU5MjJaFw00MzExMjkxMTU1 NTRaMFExCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEm MCQGA1UEAwwdVGVsaWEgRG9tYWluIFZhbGlkYXRpb24gQ0EgdjMwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnvURYG8OHvDXCxELPSflA0dIqNba5jPJ5 T61JEOvez6QbaeDBn5CyveVO22vkPDBGzsmzshSXcIBAisFt3A0Oce+kWUikjxLU SpcYChdha0ryU5u19bkl9lGp2sK3h6l0e7OEE3uMledUZBNUM8rAcJzgPQNWgX8C hXnf4BCPXNytedAG0Dc26EjxnLz3FeIw8oY1sRkg5vsXTpLZWv2+GRDRmJ5+5qo/ 0EkaUzok5Ngwtt40sJn2XmloZ5xFHxC2QDXUw8iJwyZhR/0yzgLtTMikigSzQKVJ u15DJnbOhaXg9M8r64TZ7JmNs6NZq92f3k3DhbckWoNmiZCAnnyEiEsLOjYCNcWs lIXtW7qSN52PKHZI632ko3fqUKSPGgC58UNxUcgosW5xqEof0+FjdBSf5Ohggp6k 5CspDkUVyFY/T1xhs1l0O4vjx7xaB22n8DhFsZlTqBn9rZZN7Jf/8gBAjPhSSe7w xGoBxKHJF/hDwguuQ1eXB8W6WInc38wdzYQnOvdBMrTg1GV/hS1nGyIuquVT9P51 xrC1kri5a9jlm4N+ZSinSOzJeVF0oJDiXH2R+VWP9ivnJw4+HwquosoG6a4yMw+R owVGF2ay72YJEWu2403xobV5vJg45AbgOKIqnh56bAJTjTZk55GTpMU8DgLNzbg1 krhwZTfhCwIDAQABo4IBfjCCAXowHwYDVR0jBBgwFoAUcqzkM3mqRYf2/awdntbH L4bYJDkwHQYDVR0OBBYEFFvx7imNMbI7OuAXy6QH6T+CQh+jMA4GA1UdDwEB/wQE AwIBBjA/BgNVHSAEODA2MDQGBmeBDAECATAqMCgGCCsGAQUFBwIBFhxodHRwczov L2Nwcy50cnVzdC50ZWxpYS5jb20vMBIGA1UdEwEB/wQIMAYBAf8CAQAwQQYDVR0f BDowODA2oDSgMoYwaHR0cDovL2h0dHBjcmwudHJ1c3QudGVsaWEuY29tL3RlbGlh cm9vdGNhdjIuY3JsMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATBxBggr BgEFBQcBAQRlMGMwJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3NwLnRydXN0LnRlbGlh LmNvbTA4BggrBgEFBQcwAoYsaHR0cDovL2Nwcy50cnVzdC50ZWxpYS5jb20vdGVs aWFyb290Y2F2Mi5jZXIwDQYJKoZIhvcNAQELBQADggIBAFWj2sdjtFsGSuApNj8O Cm7RhHmDpHT/kttmdh39z1Cl5/yhnFg21f5+mbLHhPLsHSEFcnOLZZhsCrvTVG6n xclRneWgXMChLXJPfMTQ+7rsFxL9JtBYnfnak2nmZI+SupX3wSvvhDdhHvRfw0xY RpWUQfLApnXqqR0ffGf713uSLwPfHV4F0rTXnJBBGSEIMtavk/aK6Bxwo0foAux2 MMPqAZhVLckZTHwWNK0SgPA8c9o50eB45u2wB/ksBgRUckj0n0MZqeFrsBk2ztYg fNrFtQuMmNN4NXwf/1jWY6KJVOSyGy2EfLfmClIeS8zMncRcRjFMpnit+HRKoWhs MxKewJtwsnmrRlZu/x8WjmzMscgWA6zyDB43uWh6bBG1jpZSwohU4mlgxoVPYxhu bq5siJ/GpA+v59LvazGSkdUQmr/TnASa1HV3iVEy60TjNWUQVo4p6dGUZb2gyrL7 93PtLUJ7r4HbV92EG0HlmYakXc4ePLmJwEhH+NdTw9wPYh2NjHdQ2jQtGEs8c+5J 1WYZ/NUFygOJqegcRO2APN2+QBnE4KzUhXWWTObIRnY0wgreJ8ghGYNhHwr0Mo8i gWR3D/K7Hn/XKqrPVzlmxnZZfs6riqF+7o+HCG254DPJc5LgcN6w6RcsF4lL5pr1 gr6Cmg2/Tn6odHWrYEV1+wNC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDzzCCA1WgAwIBAgIRAMNKCkcZ4RnVPgmMFLxDiqgwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MTIw MzAwMDAwMFoXDTI4MTIwMjIzNTk1OVowgZkxCzAJBgNVBAYTAkZSMRAwDgYDVQQI EwdIZXJhdWx0MRQwEgYDVQQHEwtNb250cGVsbGllcjEOMAwGA1UEChMFWml3aXQx NDAyBgNVBAsTK0NvbnRyb2xsZWQgYnkgU2VjdGlnbyBleGNsdXNpdmVseSBmb3Ig Wml3aXQxHDAaBgNVBAMTE1RydXN0U2lnbiBFQ0MgRVYgQ0EwWTATBgcqhkjOPQIB BggqhkjOPQMBBwNCAAQYjGxoWlWfv/DZQuxH4zF+wVndGCJB7+2/iotumeTMnEEc nrIIAC0teZ7A0DZUpQlplI7asrWZDytiVlbOFv1co4IBizCCAYcwHwYDVR0jBBgw FoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFACKZAFfz/N/PPdzWZd7 oxcLJEtAMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4BgNVHSAEMTAvMC0GBFUdIAAwJTAj BggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwUAYDVR0fBEkwRzBF oEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRp ZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcw AoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0 Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoG CCqGSM49BAMDA2gAMGUCMA1iSMXnqRBEpfrRjHnoxYqQ7U5ovjk1b0al3iYjbH+Q CkvhkSAIaLHbb9JXmTUQ0wIxAMPMn+GoOYm5jDt8kwwPd9gNi5RJqQTZHg1idFaF n/4GHEXW0HvOBdL8xcb2mv8hJg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDgTCCAwegAwIBAgIQB2hvp2UyWRwhZ7FbEaiLyjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgxMjAz MDAwMDAwWhcNMjgxMjAyMjM1OTU5WjBjMQswCQYDVQQGEwJGUjEQMA4GA1UECBMH SGVyYXVsdDEUMBIGA1UEBxMLTW9udHBlbGxpZXIxDjAMBgNVBAoTBVppd2l0MRww GgYDVQQDExNUcnVzdFNpZ24gRUNDIERWIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAE9JcCjfYQKbthTBDaQRL6Acr122L+Tlbx8K3Ee4yZ4CmZHzoih6zJSzQn AitJPyriQdJDLfVVhH4HPXpFqUMZPKOCAXUwggFxMB8GA1UdIwQYMBaAFDrhCYbU zxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBT4dAO5kSQ5pZhncBB5qy+HL1qbKTAO BgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICQTAIBgZn gQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29t L1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUF BwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VT RVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2Nz cC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2gAMGUCMQChEH8mmeb/Z5SQV3Fx KobD+ziZYW57HNR96wIvVnFY8+ODtLOmqW4KEskra2DCPJwCMGQuyQCUrlxJ0Rgj 56TNlSLDYGPFUh437T9Kqa0gpXzpbqo9YBpyf/hj6Up/6bWqlA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF7jCCA9agAwIBAgIRAIM/ucF5gZOSbLyOUjsgzvUwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MTIwMzAwMDAwMFoXDTI4MTIwMjIzNTk1OVowYzELMAkGA1UEBhMCRlIxEDAOBgNV BAgTB0hlcmF1bHQxFDASBgNVBAcTC01vbnRwZWxsaWVyMQ4wDAYDVQQKEwVaaXdp dDEcMBoGA1UEAxMTVHJ1c3RTaWduIFJTQSBPViBDQTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAJoZs/YLisLeLL9AmpqEWbYIxcVuwW5uSmchgsfXNhlp cUPxuW967DaLtg+8AGZv+/S8tp09o7t+QehX+ws7Q1oGkYeze1JuqXCeZX1RJ+DW NMB5T/hKSaHUHQ/r4oxRJoRXUz8wsFaxMffnDGxmnJzX9BuLJzckgE5I6vofxJf7 5EFu637+65rzABT69cV6kFmX48sCJng5a/9gwOTaKtHyQna1zg/v9Pi+OIe3mVSH 3iRoWo8oay+ONyCvXc15FIVxCpcCGvlBOaYELV2jZEOb44KdYsfHOUGnO0AEK7Kd 5taoM6mRvJjLy9mZ/Frs9SjfggTHjRtwU3DHCTFzX4MCAwEAAaOCAXUwggFxMB8G A1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBQUvlIZLLPy aVKA9gwDG4C9pVCfHDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsr BgEEAbIxAQICQTAIBgZngQwBAgIwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2Ny bC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3Jp dHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51 c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUF BzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4IC AQAl/L/1El4lDetC403waWKNK1/GV+VHMExnaBxqFYSTDYQjtvECqws5p0R8dJRL BL++apTYH1xkRh1f7m3/cSIMepXx76kB6XTaZYc1RI/2fJ0VEfHP/MSlYhAiZyLr /S6IMf1kn1HVhXox60cLaEb63zhMkpuF9UJMRbl1Xn8jWhavViSVjJ5YoK4o/rvd 9/CszLTVMmtKMsNohAgyZNzca887Wa+ObEesW8gC0ruPpLHIczURCQsRXfBL54Ny cZ/WVkQbp9fzQ66QwP+vEgfhI8IG3eFALFOsMDQsV9Io27LNl6Jgs4HHsBsqVEeo ZMgUkxKddQr5/I/0PeRY7ZDz7XgWMDd8c+yJWDrtcAEohDKi4SX0BjHyPLZc47DI qLSZ3jnpNC4s1OD/fqLoiTa5FsOxVXONr1PYPI4dT1J+lOWfpY2+VgS/EGIRQlNQ wpLMpuCKiuesea6J+156yRfHt8tIcNXMFEvZ47I/uN0idRfaJ6NA542cWnG6FKOX tH8QHu0cKAZQhIk/7fNOxzLAMIr8dceUuJrLsd7kAofU3q67SUGku33Z3ld1M1tb YdVfVu7jU09Vm0v1k7+RF7Ke0tyb9rXweWxRKJA8TfghmAbKJNGB9dxLo0UxWIOK 2p7I3Ne//dQ3HXB7A/nSiyoWY8yI2/obbPRERUaLy/N89g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF/jCCA+agAwIBAgIQDn3fcKv1/W5CwIKpDut6DTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx MjAzMDAwMDAwWhcNMjgxMjAyMjM1OTU5WjB0MQswCQYDVQQGEwJVUzELMAkGA1UE CBMCVFgxEDAOBgNVBAcTB0hvdXN0b24xFTATBgNVBAoTDGNQYW5lbCwgSW5jLjEv MC0GA1UEAxMmY1BhbmVsLCBJbmMuIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IDIw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQHA4QC1VFekcI9Wv60lK3 TojsG20qBpM+lpq4+X9Qi5MviY90ktPjdZSRzaXbOL1lS97bI7E/TruVBzfc7DrU iJcFpW4EwGLUbUZTlqpYjjfmLO/lP3bQw50BctTT8jAnb6sy929Xf9uphuqkY0u1 OYiFYAgFuHnfmykHYvzk79iAZTpRPbxIrjhai5rOQH2buquOsRy6L7PS9q5GwFlu oY4D4c73LFxR7NnMfYrmRp21FI1UsJgxmAsCzLpI/JybbECmc8p1pYp9l+lfVZyV iteIAdEkwBmPzZSNOe+6UjcjvyHW0mHcdiFcBxCKXluA/PMFIjFMh9O5Xc6C51rh AgMBAAGjggF1MIIBcTAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAd BgNVHQ4EFgQUSTyrvgKxgBGMhOKeFCHgp6tR370wDgYDVR0PAQH/BAQDAgGGMBIG A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAjQwCAYGZ4EMAQIBMFAGA1UdHwRJMEcw RaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0 aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUH MAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVz dENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAN BgkqhkiG9w0BAQwFAAOCAgEAGoz5psnH3opfu0O5yAhU7Xj5h6FMKAukU42lecg/ z00dU1U10X9Pro52BUBU1L0rd9xYVV8FtvmXmKbKrqqEXWe41kurSQLUSQXP+Wcv 86+6M3PkboyRHDAtL7nGpZni3C/pq4jG5TsKxGHaDmftkoiyZfHuRW8dQTO+53tP jBSkfk8UW+vTgKxqn2UU6Ty/J9+HQQ4JS2ZvhIGx2M/StCiSkkB0U6sKX9jML8zm zgUNmuR/xWf9zphhSGiEjYiq1zuRfSg4DiJFHqM8/zo1FdOQRMwk0maCEQfQS7fN sL6E96/I6WgVr2MF17BB8H2ZR4FbyWv6X33968jFrV/abhStAwvqA1vM2nRApupO 1Auug1EVtPvy1jP2307ZGokB2cQxjBLDh/ucnFZyrHFgczsUJ4KtrUvhLDEh97TR mZvPjdMH8cfc9BE4HUuvXC3kVw/vS/btEwEfnDK0zYABgcSesdUms5aaAxtkOUrv lcwDShCsquWr92Mg0q42LxpvNNVmwSSb/4po+fGnJ5jCYIVJq/78zRY9+ADWfoGx P+5H5HU3SDX4T68tKKqbnCEfWUuZ6KspiV9JRQkh5D9wkOUara9QvG960kLwfbyt iJTPQ793S++94c7Z18n32ujHB4xGaOmo72SsJdbAzRiULEWWB7Jg9cGPYR5GStpr r+M= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDgjCCAwigAwIBAgIRAPynkt6UMaw+405OnaJwREowCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MTIw MzAwMDAwMFoXDTI4MTIwMjIzNTk1OVowYzELMAkGA1UEBhMCRlIxEDAOBgNVBAgT B0hlcmF1bHQxFDASBgNVBAcTC01vbnRwZWxsaWVyMQ4wDAYDVQQKEwVaaXdpdDEc MBoGA1UEAxMTVHJ1c3RTaWduIEVDQyBPViBDQTBZMBMGByqGSM49AgEGCCqGSM49 AwEHA0IABGfMo3xOFetB2VnR7jSz6Y+moOE8R6QJLMvkjx2x+xWY51RFUKD4yL+Z 9+uEpie3d/LGAW8ADyUqAxxd9hYG9HujggF1MIIBcTAfBgNVHSMEGDAWgBQ64QmG 1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQUc9ZfQt8gN7J7xFPs33wNXG1ePlIw DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAkEwCAYG Z4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNv bS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEF BQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9V U0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29j c3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNoADBlAjAq4SJ2bQk/ogeIOulz dSEuEu6/YKJOPT3OPW2vncVLQ0MIbNpbTMvU8yQr3ZYG4EsCMQCxSM6y6MZ8qXSV dsO5AUK3+ZWz+X+ZWs3syxz1dxV/foP0c71f1qSVsAm9RSBqzPQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGOzCCBCOgAwIBAgIRANiAvRUTZg1auEbI7+YHZigwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4 MTIwMzAwMDAwMFoXDTI4MTIwMjIzNTk1OVowgZkxCzAJBgNVBAYTAkZSMRAwDgYD VQQIEwdIZXJhdWx0MRQwEgYDVQQHEwtNb250cGVsbGllcjEOMAwGA1UEChMFWml3 aXQxNDAyBgNVBAsTK0NvbnRyb2xsZWQgYnkgU2VjdGlnbyBleGNsdXNpdmVseSBm b3IgWml3aXQxHDAaBgNVBAMTE1RydXN0U2lnbiBSU0EgRVYgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCX0uTvGIMCGbPxykRA7R9wbUJBVXk0H5lv oiDff+6Q3XjpoYAfzgW78aT77mDqOQqvhT9TziQ+L4qqkbwMdfzmCWadkUUeR6ug QQznbY1HBzWYsHYqabwZ4j5PrKaAwFh3W9JgWhXtEclkwJKRRG3eWJqJoae4hnKG cSMWqsfhIzyaz7qRw0R63XC4K0Yv5gh2PibI9DFoUeBjJJ500guI3a8qt4l10ZFx 1vDKUvK4Vd/pGgjSsWhFa8nAAogHHTCP1lvVNxIFjpOT8LbeT/XMQ2+qJFLKA4jx MG49bJaXALVDJ7NjBoZypXKSNtG7Fvn265RxBQ12ftDVdJdTGfQHAgMBAAGjggGL MIIBhzAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQU qyfeB13oAV6MVtAwo7dL3cUYSJ4wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQI MAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQx MC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQ UzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEE ajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRy dXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVz ZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAHgFOR30at+yVaRAMiQyir/L yNL4jkPoiPr7MEbh7PaeRm+9ykfJr0KgFHadEcNxa4iCV1+FpJARTWhiqId7vpZ0 Vo4o5r8JuRo6q9wHXoTsSohIWB/oeIlSWS8TjjAC23OtJ2I+ZKD+CEfiv2+984FP LMnVr8+CEiAkK3yXIwjPVO6B6/GgLUW20OsCXKWTA97WdLhE5T9fmbnfoENmyG1t p0DWy7FyRrrI6kfqENGOP+bfZvo3iFw/XuqElznbrz9E3geaaqYntVb1N8NYgz6t pxWraoLUtTnxuO4tyoo86Q+MBC3lQxINZGEW0dw8T8VzUcC5tRuZHkG1/hj67IPi z89fGO+3D6zHJtY8kxQAbjX5dWxFFwWBqj6F+5cd/0GH0P1OqFnXMTFMRBvC/mHm JjZ2aqq9W+NdaDW2McrDN53jEKQCGlAg7sZmnxmyl/keXQNTc+NkfQXTEXTEtm+H 7V2nnJPUsfxCq/AahEvFmrmF1St5DSUOzsjg8LGBAB+DBMHenJFAz4Kz7p9HDcnd 4DEraZSm5g7UJ3j3FIhNlKODLVYoaKwYZzHCEhDUdN5YjkdLrNiyJxutc4NPB+XC 3RU9hcFCS9O1B4h5WXdm6iClGOHfYNXIJ/lM375uSdDsHTsaCGX3j/HjfHlGqo7L UqqphWxLwYCBEKNZ/dfx -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF7TCCA9WgAwIBAgIQVCdbLL+QkRoRwfXX5XPuczANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx MjAzMDAwMDAwWhcNMjgxMjAyMjM1OTU5WjBjMQswCQYDVQQGEwJGUjEQMA4GA1UE CBMHSGVyYXVsdDEUMBIGA1UEBxMLTW9udHBlbGxpZXIxDjAMBgNVBAoTBVppd2l0 MRwwGgYDVQQDExNUcnVzdFNpZ24gUlNBIERWIENBMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA1flZMTYv2I3K5APXG2qo5QiccqhmjX2H4V0+7WW86ROo w3RT+HR5GpTBu3GEHoh452yLSAJ05Zh0li5O3WZ1dd3HoY3GgS8covM7BQaCmMZH Yv2Zq6LJiScFSYwpQ6XSKi7++5L6EhDddZQlwiBW06YVmWnv3YIhBzFW/3a+YWF7 ZbLIoODFqd3TYvPey3TpUeenoOIL47gyPYKGXwTk7iQxDGJqqGrauic+meoZx9XV 7x2QV+lmARDQcNTBfJcosNICadhKJnPdhyfwoZOMQL6SiTWJj9/rR7X+1cywxyFX rDrSNQaldVYegrFCk0+pOK3AChJQrAQz5lqsgBojkQIDAQABo4IBdTCCAXEwHwYD VR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFFuGxTiFJTOM NepF2vVPeVx16r6HMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEA MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysG AQQBsjEBAgJBMAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0 eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVz ZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUH MAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIB ADQFa4jTDpXStSJnRiJq5BFGMqDPiOILjRHqKdAJXqHAgwDN2ZWd7o2R3cUnuZl6 caAsrdrwNkW44p/bUAdMoFtbwsrdpHpRv1R5BZc1fvaxG9dlw6XGLKeFD4QiRIP7 oFTk+wIVaAF4rN5x0mSZ8lBBlR4SHDjoEN4urDJ0aB1IXiQ12fu1jW0DQGmAn+r1 qVB3QMUncOT2ZNwQNJKNDKfYFKvmxADAEdeakEfPBeDReXNN+cjlalJy97nH2dZ8 EfWaLNMG1zU4gnrUqSl0FupFScBFXvHjdqPI3La8EGSw++r60/IQQJIPzI2gdVav iE42Z7cVCashCF9+BT8nkPj/aQ9FoWyCXgMucjFbt5KDlk/wPxxl3dpO7tpcGKba sXaEGOrgjmfE2/PIzeZRVUiPFQ4S1d4liJYPoQhMiDzNel21FgHkXmGwYSdJItTG nlOXo9R8Crkvz+Dzk5IJC2L4PRVdmaRcCsx+xzquNW8bCI5uQoGjKU8TMk3Zbmih TsbdxzK8A/2WXtUD3HMQPeubt8tKC0e2xZSxcU6g5SeKazNpD/Wp7v+x6q6gRv6q V5jTW3OGiT1RaEteU+6jJisCRcNt31M9ckru7wFnSk4WsqUiE1pu2WDXQnGSR588 R8k4YX2h+ggRjoXef6H76fMlrxrDWb31PgINZy9yiDIi -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqTCCAy+gAwIBAgIQTYpKHavxJtrHJvxmP6tyqTAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgxMjAz MDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBkTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMP U2VjdGlnbyBMaW1pdGVkMTkwNwYDVQQDEzBTZWN0aWdvIEVDQyBEb21haW4gVmFs aWRhdGlvbiBTZWN1cmUgU2VydmVyIENBIDIwWTATBgcqhkjOPQIBBggqhkjOPQMB BwNCAAQ8ZzvNH7DvLmHmPWKbPHfPxlphsNpA3vw7hhhTyE4zf3znIifMOTSQWdig Y4EfVtzleTpjsGhoS0XHyYFJtvRUo4IBbjCCAWowHwYDVR0jBBgwFoAUOuEJhtTP GcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFIi1LMsLfHTV41CcbEJFUnZzsGWjMA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQIBMFAG A1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1 c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgw PwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RF Q0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRy dXN0LmNvbTAKBggqhkjOPQQDAwNoADBlAjAYu0YXnOI1w+A8U05QFhaSVJ3feHRP LTQ7vnSRH5LcutgLJRL1LK3D/e3EEGmJ3TgCMQDPEZm0gs7pmtwGUHW6+6h7GqHj U8P0sguy+fdkZVa/b7ar2BvYbsh9LpzF0jCp6tk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEbDCCA1SgAwIBAgIQDU5Vu7rfp4wUOY2Uq+0vvDANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE4 MTIxMjEyMDAwMFoXDTI1MDUwNzEyMDAwMFowTjELMAkGA1UEBhMCVVMxEzARBgNV BAoTCkFwcGxlIEluYy4xKjAoBgNVBAMTIUFwcGxlIFB1YmxpYyBDbGllbnQgUlNB IENBIDIgLSBHMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKUnQDUn 8HIHgWNSwhuZgu4Dk7kwZDDYbwVE7A9+/yBzfTDHlDhNtxtg2alHMrkOh4GRIsWd Rxg+CrltQgwT3kKZORofrpTOjNv1iR4Z+3i3sx1HOywblMbib+d+yKoDBr8brFAe u3/hWFemcqAwa93sqQ79VLHAwh0whuD6WMhQ2IW18s/vuK0d+LKho8qjp8AiMDCw 1SVVydGYPPokKI30scKMhECqfF71wcYg3WDvzYrVVWUpgF0RJyaPI1YLcgWghvlL ToawrlBEb6PLXtLRQIvRVbOUVvmkEsVd9Heeywk9WCYXiCpo8RQ8qrOJaQDwxFao 07OeDGz9883b6W8CAwEAAaOCATgwggE0MB0GA1UdDgQWBBQBnHZJxe4ad6SKU6DM A6onvixIxzAfBgNVHSMEGDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DAOBgNVHQ8B Af8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB /wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v b2NzcC5kaWdpY2VydC5jb20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMu ZGlnaWNlcnQuY29tL09tbmlyb290MjAyNS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAA MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJ KoZIhvcNAQELBQADggEBAJu5OWUDDbq8MDOKfbAY4vqQHWj41UwexIQilFMHibJy Kk4/9rx9B6K390O93Dxo0gSgecG9rG643F7/NHBAn8cCPcWWIylZaaweM0pYd2aF Va5tdmd5nDbspkdyqSqAkH+edZB52JKR9th8VbTwhNx183yxb9l7u/WXoYXdwcqc p2FfCX2Wzl1MknbgMuqHOx6M2PfWfZVzhaHgozWRnCPau6EMH1v1+NMHYgsssSHn A3uWSUabv7Un/xjmiGgwCh3i0EYBbE6UCy1G9XwHoXhV0zhW0XgTwElnEY/2W+f/ DqHVOGvV3nYXTOq083lrS9KOp3aJNDhC83O2wsdC8vA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID0zCCArugAwIBAgIQCkjVfGX7Dmz3BKNkXxQY5DANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE4 MTIxMjEyMDAwMFoXDTI1MDUwNzEyMDAwMFowYjEcMBoGA1UEAwwTQXBwbGUgSVNU IENBIDggLSBHMTEgMB4GA1UECwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEzAR BgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZI zj0DAQcDQgAELVSOaLAQE+/0LdvYCbJD6J1lmW40uNSXyY7J1qgiNzLIcWDusPHy xWT2ukdf/OYHeDIt9sqAIMn9cPhykyGIRaOCAVYwggFSMB0GA1UdDgQWBBTDxKRY BWPXgwa6lo3cso8y9ru3QTAfBgNVHSMEGDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN 8DAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAB hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0 cDovL2NybDMuZGlnaWNlcnQuY29tL09tbmlyb290MjAyNS5jcmwwWwYDVR0gBFQw UjAMBgoqhkiG92NkBQsEMAgGBmeBDAECAjA4BgpghkgBhv1sAAIEMCowKAYIKwYB BQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQEL BQADggEBAF5Pz2WYaWVNfiw+bosevsIQxOc1oWPiYaOn1cgmAtLt9gYa3ur00j38 9zI3pFcJCb3SopEDbHQpkJ5UFo+g3a0ygo3dAJdLqLBluOw1csi7PzYIWv2A7wgV B5P3uMOVigMLtfAcvkx4tf/ujaJR7Eg6QL/W2rTOxO2WdSApLlQ48SVuf81NXs7x /kbfnOFsZp8ZlufRYaFZEiRKkeGg9GmRTK0h9VBmKXSYMGGoPaGCtTO5GvV3r5w1 zH4decUEkiWrqNCPic6S9Pc9IOQGmR7GDs32igCL3iy7b0jksrlctNtL4LVjrzB4 2xC8K8hG2P7VuXXojnw91yKtH+e9Rec= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEnjCCA4agAwIBAgIQBVLH7/7sKSup8Th7B6+SnzANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE4 MTIxMjEyMDAwMFoXDTI1MDUwNzEyMDAwMFowYjEcMBoGA1UEAxMTQXBwbGUgSVNU IENBIDIgLSBHMTEgMB4GA1UECxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEzAR BgNVBAoTCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA0JOhHUdDIBayC2vrw9W06MeYzfPev+hN6eM2gAf8RRtq fEWGrlbTpAl/YQ1rXX5Sa320yDnE9Gc694POGW+GL35FfkccZ1LKlQVd4jZRhcDU Z4A1bxXdPv0d0v2PNFDY7HYqvuPT2uT9yOsoApYRlxdhHOnEWTtC3DLRCR3aptFD hv9esryMz2bbAYsCrpRI8ziP/eoyqAjshpdRlCQ+SUmWU+h5oUCB6QW7k5VR/OP9 fBFL954IsxVJFQf50Tegm0sy9rXE3GrR/Art9uDFKaCoi3H+DZK8/lRwGAptx+0M +8ktBsOMhfzLhlzWNo4Siwl/+xkaONXwlDB6D6aM8wIDAQABo4IBVjCCAVIwHQYD VR0OBBYEFNh6lER8kHCQFp7dF5wBRAOG1iopMB8GA1UdIwQYMBaAFOWdWTCCR1jM rPoIVDaGezq1BE3wMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYw JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTA6BgNVHR8EMzAx MC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vT21uaXJvb3QyMDI1LmNy bDBbBgNVHSAEVDBSMAwGCiqGSIb3Y2QFCwQwCAYGZ4EMAQICMDgGCmCGSAGG/WwA AgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAN BgkqhkiG9w0BAQsFAAOCAQEAWgDobaZ4Dq8zSOdyWvCa+Tad60OIwE9qkz2o33KF CcAM/CvxXrcXTTYo9VJHninE+G9SguIdukkDDAOHMT8WvsqomydMXknQJVbREOAX KUKgS5q0/9ou9N1FjJvkhPGFzAbuLnSJtLomfJPxHW4h3l6bdliQodVQXd3xUbXR qTKNUbF9bIh4601+KhyZL0u0B/eTppf/1O5S+qFAyRADr1lvfIeNHZv11iyf4u7e uLBsXjyT3vPwxrihpAwB5pu/DhJWh4iv70Q7pcvAaRRfiJgMj3A0fFgvqvGbW9jm t04+Cr/PjpWeMFt3KKj3DRh4jJKjJUGt+JxdGGJ4tCGyCw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDvzCCAqegAwIBAgIQBa7K06LSRtWH7JORcR0RFDANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE4 MTIxMjEyMDAwMFoXDTI1MDUwNzEyMDAwMFowTjELMAkGA1UEBhMCVVMxEzARBgNV BAoTCkFwcGxlIEluYy4xKjAoBgNVBAMTIUFwcGxlIFB1YmxpYyBTZXJ2ZXIgRUND IENBIDIgLSBHMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPVJMs3lGFIILq+f mImVAttsUiwFPXhyhxN/buSsMdbYg4ESogBaFlzg21sTLKBzwscwmnrv5i5NihD/ genZ3VSjggFWMIIBUjAdBgNVHQ4EFgQUtWRvvBefyVBl2PU/hOmVCXp8X2YwHwYD VR0jBBgwFoAU5Z1ZMIJHWMys+ghUNoZ7OrUETfAwDgYDVR0PAQH/BAQDAgGGMB0G A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA MDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl cnQuY29tMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv bS9PbW5pcm9vdDIwMjUuY3JsMFsGA1UdIARUMFIwDAYKKoZIhvdjZAULBDAIBgZn gQwBAgIwOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k aWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQBAoMZIDy0cZEb0qb38 qExEaFOiRf6GT/oNn5BKXWEmCJeWCOcNHWiPtQPcBm37QFf3GwUw8xrd86jl8lps epaotPubM4F/H1vNd/RmZxRHy54YPMjocy/pB8f7AkpxfIsRgXK+nB88f0PSPtHN FhDw5CjSdhd75UI6JMh5tCxEfjDTTnXCIYnRg+Oj95vPpIyaENg2CEMvUO3AVjc6 w1OySORrzxavJ1sZ/mjGLnAxz4iWyCrCeXIF7r8LUWBg5b7Wvul+6KyXWPAdzZTK cwktLIehiCGYyM1A6QQryu6bEXD79+1AZZ7Hu9BJTuaMraeIN0hrh/6qu9BQH2Xf Iuz8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEijCCA3KgAwIBAgIQC3ma73ud7StBi40+qjqPfDANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE4 MTIxMjEyMDAwMFoXDTI1MDUwNzEyMDAwMFowTjELMAkGA1UEBhMCVVMxEzARBgNV BAoTCkFwcGxlIEluYy4xKjAoBgNVBAMTIUFwcGxlIFB1YmxpYyBTZXJ2ZXIgUlNB IENBIDIgLSBHMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKl55u4y YQpkUgCD2lxvHawFepaeczR5K5PxO1+QA0CPug6amfkhDf4rnYg/eL6ISOo7FPbd IVvUpleQi+RHT51SfslZbU+bQAPshDCLdLuHo9Qhmw1lF/K003vYR5Regxvw6iuC NmVT2IGh8RMcZBFShkO8aZfMO4wFE8YcKDOli8gFZSXZohh/1DYoE6N6rkIvwlYT kEbLvhNi1kjlLZvF5fpd3P+YxSazekOQkK5hCFh1HP/AgKfAaTDI/nG+GU/vor1c L1+AgvKMXqyPNEzZT+DTTNaw+IkjGrF1v2R8RX1u4B3rkh7KxzppVULNOTqfQEuk 9jRnSNr6E/mNaGkCAwEAAaOCAVYwggFSMB0GA1UdDgQWBBSQYfOj1wbO9Re2Vw7Z jKeVSxYyiTAfBgNVHSMEGDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DAOBgNVHQ8B Af8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB /wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v b2NzcC5kaWdpY2VydC5jb20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMu ZGlnaWNlcnQuY29tL09tbmlyb290MjAyNS5jcmwwWwYDVR0gBFQwUjAMBgoqhkiG 92NkBQsEMAgGBmeBDAECAjA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0 dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEBAFME 3z7FkMJ7mCDw0wInQ02Nx0s05f5PddIXqvd6J3XQNRyUFkPVuL6jHL0SE81BRzYG WGpcmdjHAgZckekU4CywJo8HgJMjvb+viUECcuQtFmcG1q38/AcvCdf/cPpRMHws HKF3/Y2cE/Yc/2ynKC/DycXBtWKXi7JmEtGtrb7KC/5G2xDlsbCLMD0QNs8uDG1s XcKPAwb6u6uStOX5KGHqkbqox/zo5874lSy+Nqc9IRXhS2CDlgFDLZ4kjIEXws/a GGlNWLf/ctIvWbLDxHuK/fVyGpVniEpPCuPX2VTTVnDCg6CCpdclIfvQRj0bNrcs rZQfG6zUAF0a6uYMYSo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGUTCCBDmgAwIBAgIIfbaLomhQVzcwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xODEyMTQxMDEzMjNaFw0zMDEy MzEwNDAyMDBaMIGSMQswCQYDVQQGEwJFUzEeMBwGA1UEChMVRmlybWFwcm9mZXNp b25hbCBTLkEuMSIwIAYDVQQLExlDZXJ0aWZpY2Fkb3MgQ3VhbGlmaWNhZG9zMRIw EAYDVQQFEwlBNjI2MzQwNjgxKzApBgNVBAMTIkFDIEZpcm1hcHJvZmVzaW9uYWwg LSBDVUFMSUZJQ0FET1MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6 cIlUCaCe12gMnFsVFePe9Z52zvebP/J30UrhNH0H4vny6VS7oVOd+aMQvvqW9JmT rYIA1i72jp8TnWNHq0RNlQMzjd+uQkeVSIOrohSHMejah0yx+yUusoWDSXOdhKV+ CCjN+nvcCDUxJW+jmiN/UVZkHzQRK3M0cbQRGRNADeKPsrUrB0028OhBgyPOxM6S x3BIxXz8r2mXXtlFkkgtVYOtU8zyT4OM+c6mPEmnWL+uHpuL4MlzvZ/1RrO+ynyu a54hGkh4iijt1a3PecgdY7269FfhlsIWMSnXvKOeY6u6+F+CkkxwqiRO4xvCEVXY 1ObIHPgXON3VYWIzLxvlAgMBAAGjggHpMIIB5TB0BggrBgEFBQcBAQRoMGYwNgYI KwYBBQUHMAKGKmh0dHA6Ly9jcmwuZmlybWFwcm9mZXNpb25hbC5jb20vY2Fyb290 LmNydDAsBggrBgEFBQcwAYYgaHR0cDovL29jc3AuZmlybWFwcm9mZXNpb25hbC5j b20wHQYDVR0OBBYEFIxxzJMHb9HVhmh9gjpB2UwC+JZdMBIGA1UdEwEB/wQIMAYB Af8CAQAwHwYDVR0jBBgwFoAUZc3rqzUeAD5+1XTAHLRzRw4aZC8wgcsGA1UdIASB wzCBwDCBvQYEVR0gADCBtDCBgAYIKwYBBQUHAgIwdAxyQ2VydGlmaWNhZG8gZGUg QXV0b3JpZGFkIGRlIENlcnRpZmljYWNpw7NuLiBDb25zdWx0ZSBsYXMgY29uZGlj aW9uZXMgZGUgdXNvIGVuIGh0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5jb20v Y3BzMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZpcm1hcHJvZmVzaW9uYWwuY29t L2NwczA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3JsLmZpcm1hcHJvZmVzaW9u YWwuY29tL2Zwcm9vdC5jcmwwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUA A4ICAQA7REamLqwdXePyP5WI5kYGEKgtKRZCQGMKKdC0QLwhXIQLp06lgbEmd5kr insUqpp4F+mJS7vueWHx1T9ZI0tO0Te7hQz0SGGMRtFvj/JwrcSyZ1FYZVOOJIkl JBFpTCXXOMJqXD0YEITANx+Red3F5y4tcTgpWL2t4n7dNiVVwLRGs0MR2lS2a9kM Jw6ZE4c+CMXDR4Af9x3Qy8PyQtp772MP79LFUD++qJD7NpSVHGiCsgqJHP28+frO lBcNunrsCfJcQRGr1lFeB6tk2vj0y6cI2ZEAGrJw6tPRqKMS2jjf2zqefP8Ljnsn tJnDyjRNlJVp7YVLEhpJVeKKbGTJvUxmHs3mqgdqI374ODyiYLhkhDZp2oxk4bZ/ XGm6rsW4LCRtZet5lV7a7WjW4pa+gMttgFVOweS6GkZa5CQokoUE4atKUyBDI74K 2BzgKb2UNm6wMqc4g+PsXqoLKu6BpVD5Lp+cup2Ib0lLq3JIX3cvGNRq8EU3Ncv9 Yu9MGy0kTMnJMfPTPECIFqVxU0rQn4/tEY3YYJjpIyKow6UjCmWhnRfZMBsEHoD8 ukReqwacoJW7SbW/b80Vc5QZRLiz7hbQ4hSJ6pu0DNPEC3I5Gn/udfesHQg1aIHa cilXjuJlhE94KpdxPkBi8CHTM39rlRUkkSPxquBlcDUDUnx7Yg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG5zCCBM+gAwIBAgIIYoDwKcQG3rgwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTgxMjE3MTk0NDA0WhcNMzMxMjEzMTk0 NDA0WjB+MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv dXN0b24xETAPBgNVBAoMCFNTTCBDb3JwMTowOAYDVQQDDDFTU0wuY29tIENsaWVu dCBDZXJ0aWZpY2F0ZSBJbnRlcm1lZGlhdGUgQ0EgUlNBIFIxMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAvvRuokjLk4U1eUEn1IpnXJH1Law2PnAh6L3+ TjiSN2pjFdBar7P/qv2xO7Zi35pJcNles4YK76OfUVejRjUCC7jAl/ZoSXSupTuE fQYKB8GMm0os8o8BsE+X3m17ehhgLcZU56mGWWMBbCQVz98GGJFtp+PL9a8IQCwm XW2/5ljVVUGff8V8wS4du+LSXcRyGWZt/i44F23wjBsm4FBepBg7v6CvoKjVHnDZ YLhGTqYcqM9lI8qHN8BqMcz3RgpHGcQZlSaYjF9kv9KrpoNRbqflooujXn+X6kpb dPf5sE2mwzj0Jqnp4rhTU9TaAzUbqkUbe20+EA/IBPvxeHZbhAIOacuMxTk/cJsW e75e/br0PjRxEZCOlaJEfWHMjHWMK2/JlWgrU+3sv71iDKWJtApEs658EY+Qo+Gi IdVc6AaaQjL5rW5Rc8oddQ9Ia1+OGxroEqNOg8BRSShvKnoyyqJCnd1W32AyZUg8 vdFDHRkZi9uUjjXxKXTqwBz6MuMlHFyZ/nu/ALLhp9RUjrJ5+WbntHq/lpZCfRnG Fyodp1KP9vxLjT/mlTcDzM67FWazkBujpeePl9XiMp+wUc7Acd9kTGvcGrdTdeid +ArIlKPHlSRsyj8R/RJOTr8EqA4lLZ0AP/65h9VOs/qdMOepVl3hnUCBiS11e6BQ cNrtgpcCAwEAAaOCAWkwggFlMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgw FoAU3QQJB6L1en1SUxKSle44gCUNplkwgYMGCCsGAQUFBwEBBHcwdTBRBggrBgEF BQcwAoZFaHR0cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29tUm9vdENl cnRpZmljYXRpb25BdXRob3JpdHlSU0EuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8v b2NzcHMuc3NsLmNvbTARBgNVHSAECjAIMAYGBFUdIAAwKQYDVR0lBCIwIAYIKwYB BQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMMDsGA1UdHwQ0MDIwMKAuoCyGKmh0 dHA6Ly9jcmxzLnNzbC5jb20vc3NsLmNvbS1yc2EtUm9vdENBLmNybDAdBgNVHQ4E FgQUvHYtg0mFmNNBolbW25dDeZCuKhcwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 DQEBCwUAA4ICAQDBnwHRIKOQpr3YqagExDDRVUpNIf8h/Gz2nhZ7VAcjQda8fOZE eYsmimuxY2meiGRWLMONISySOPtTvtlVBerAdGQY2vqgx6ZAYd9KW4eX7Ggsirny ve3ea/wZmFf+jI4fAm2rN2O+wvrLxHPHa0qrhJBL/6ADq43eJ/+Er9/MupLSIyIo zf/x88W5qQ72SB3k35oY4rsfVSmvK9IFBzaXRCaI8LlTiTKGn1dYd/R27P/OwfXe GAN0sdEL+ZNHUsUWqSrUZwlIcLJI+TDX5X7d1emV6c6fzkmMM5xdohF6uMWZN1Zi spNixlAhIyhYEAgLJuSRztT4LMTxdrLK483KiX8fuUeHozuCvQB03wjV26wbZnvg O40lLLI9duFNpUJuUIMwW5/As5FoeZaFAaMt/6IWRsTEAp5sbS8oshU++X+vDlG+ pA64XUiYKrAurgbvUtWPYOMhV/21nz78lTOxFxMPk2ODdnOTZWKUi9qkM7edtUHJ ANUHrYM5LVgLjte/GGbMvguNUDnZqRSoohOzFoIM7X6iU5xWTtMx4xBVXnkI3wqR N96Dz6qyxQ1F9IXxPI/U9KKPMvAvAWcXTEYXTVXCHbWk3899G1zFWajbIPbf4eNj Edgno3CjHbD6NhZXEfsKq8LO0RMnUvSE+gK8ZNgxI3X2B4gPOEO5/skC7Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGzDCCBLSgAwIBAgIICeb35dyKEL4wDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTkwMTE2MjExMjQ4WhcNMjkwMTEzMjEx MjQ4WjBjMQswCQYDVQQGEwJTQzEgMB4GA1UECgwXSW50ZXJDbG91ZCBWZW50dXJl cyBJbmMxMjAwBgNVBAMMKUludGVyQ2xvdWQgVmVudHVyZXMgQ0EgZm9yIENsaWVu dENlcnQgUlNBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxoR5uQZ4 tKdfDy/dOjBq4DEylB5r9Mpb4yC0JrBnOdS1WlK2s72Ts6C9cYQUDPy6t8huqTl8 DSgWf3xAYviO8/o7eh05Yjy2t4w0v0ubYbBdMgm6zHFw/4q+wVKWiIAg0E+LXj7x 8QbtFDB0351XvwmVfaJ4HaS3Afr5zFIwnsH4bw3CnLwIug8brXL+oqzr8mAZTLwv FCgPOj2F8rcjkpyRWsNMN4qKFHUZ5JWFQp7SAGy69cl8W+LGkEUEyQ9S/DXEEq/R 689Bxw2r8p7I1YyGjvCxkYZbVe0bxYdsVROahrQknF/vm3SwFA3gQq+1oXBxNMuM 1OMj6r7RgJs0TxiJRmnJ40mFCgYrB5VWQ0Rz/Yj/AG1O2TJAGn9lb+UOfA4yms27 /hqbkE/Qo8og1ZT1/E3lIdP94/swofyKU6zycUeMz64Jm66Rn6o0fyRwraMw8yZc abz0SQVrZofIoO3Sk6kDqXFmPYyLxiDaCM/nO4GbTGWwvjD7pqIi5CnAXk2bWHJI TTfeukwnQ0J8AQmH3bnYoDJTOKVOcCAe1UmQdZqc8PSNfJQWVk1sTzEnlY8gtrnT z3Hrmj4g1kZjHZ7slI5xOf2nY0UnfgiivmU8a3X63opiI5FGG8N7YWFTWQCt62E9 IRzxAUVfkkpgMdxyS10RabH30pVN2uf0YTMCAwEAAaOCAWkwggFlMBIGA1UdEwEB /wQIMAYBAf8CAQEwHwYDVR0jBBgwFoAU3QQJB6L1en1SUxKSle44gCUNplkwgYMG CCsGAQUFBwEBBHcwdTBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5zc2wuY29tL3Jl cG9zaXRvcnkvU1NMY29tUm9vdENlcnRpZmljYXRpb25BdXRob3JpdHlSU0EuY3J0 MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTARBgNVHSAECjAIMAYG BFUdIAAwKQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMM MDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmxzLnNzbC5jb20vc3NsLmNvbS1y c2EtUm9vdENBLmNybDAdBgNVHQ4EFgQUeKHXWTipSGyK4VRsl4ANmGKooHYwDgYD VR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQCU0+/uzuxoM40qaAOvZ8xf VDucjxF6igRRCwRYrtqDQAN29c2Ps1/XCyFAmTeR03Y0zW/2FxI9SlYrZyP2dvmT e7tM6HFHwX/+W2crGBe0v+g8UsIEiHaInjOZrfhhsm/+oWe8UKboeHu8dEKsoflE bgZE7mD/KRHjODxUM6RTMAy9JE4wq0AjBj4G2ltqvJIp/NBohjo4Z9zHeAfc7Ajp lAeeIHEKcWRTIorJEhTOaxrD9KMf2gxBC166mHmh5znTLxQB64993c3OkrqS3fUy XM6h4js6C80QxUgw0qz9uMmcgTiOvoqT470+Fd/UG0Ng8xEE4SAVXVpy1UsWStW2 KRdm2K0QWwL70OryRxpTHtbBesrokpiON8aoMrj44bbiqKD0l+ZznH2Tg7p9rMuL F5yTDK7ot6T6Ow6QKUAKoxGw03MYk0LBkIvGost3faW8yjEvwZCDaOzJb1eURRUs 64fMGNoY7gDmb/fMff+9ImfmSYQRouBVyJ/Z8qcaxQrhu6d6oRixexKGzp6lngXU FZVhXy5Fukun4T22jyYTk/TgBJDI4jSNvhg3G7A1hpz2txTWoVO94TQooosla744 pVnMRZLLNkFjdbga8iG4FoNZy55uOw271WlNAnJxE/isaYprq9n7QdJlICjFQHEP sr7jdZaEEW4zGsWLuNM0+Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGiTCCBHGgAwIBAgIQIyygpSElAUZRSSMeuADPTTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw MTI5MDAwMDAwWhcNMjkwMTI4MjM1OTU5WjCB6DELMAkGA1UEBhMCVVMxCzAJBgNV BAgTAkNPMQ8wDQYDVQQHEwZEZW52ZXIxGDAWBgNVBAoTD1RydXN0T2NlYW4gTHRk LjE+MDwGA1UECxM1Q29udHJvbGxlZCBieSBTZWN0aWdvIGV4Y2x1c2l2ZWx5IGZv ciBUcnVzdE9jZWFuIEx0ZC4xNTAzBgNVBAsTLFJTQSBFeHRlbmRlZCBWYWxpZGF0 aW9uIFNlY3VyZSBTZXJ2ZXIgLSAyMDE5MSowKAYDVQQDEyFUcnVzdE9jZWFuIEVW IFNTTCBDQSAtIFJTQSAtIDIwMTkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCBPGHDVaj9n97ovPqbVzeCUylcoQdDR9C8BqtC5VdcVmEh+vbmRrSeaha7 Ba3Mg9wBUY3IcAOFmgiEVJhoOi8dq4dRzRPQN3FtdW8la7BmWwnZrnmcO0C+1E7u uJjatDpK/rDajDkW3ebShtkgq1UMnBNRZJmXNbx9UWshV1Ery/Ydwf2jExFZ6EIH sMNP4zdidwJbTobK8dD5FfPA1FPIfj3UOcUI6/N7YvsdVg1vid1nPJ35XjHNyXaI 5D78azWI9uogdM85oVqg8Sa0Swk8R5r87msxqFUS9Q7sicgQszTtYAxsB6FZYDI6 IYTPUcB2o92LPvpvmV/KA/H0DlQhAgMBAAGjggGLMIIBhzAfBgNVHSMEGDAWgBRT eb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUElZ7UGXhJtE+Xpc1P110BfDW kVIwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYw FAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsG AQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5j cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI hvcNAQEMBQADggIBABMmLiUVC/3pbe/rcx6twt13vVykTv4Y1wNLn6C99mgiP6ni ZDr+RWj0QvVGrqVu9Ib9uBLB5iAF0Qyua9lbeX5/lfoD7rfcCUJX9IFNhFp9nESy QPwc4dAnqY1sMXYN6To5L6Gf8HFPtNsuITW9JYV4vmB/ZOPUAfiaIGEm2M/Z6WI+ G4lpELlH6vmZXqdDbQLd1Ci6g3WAVMgUqVx/7BG93X5s2ZyqgBFnHlT22r6co7vb QgcSvsBXl6H5wFU2EQkXoO8GC0fRvYlO1D+2wRxdZA6oOIsZ7RwoGqwksLTFBZno HNwDsSk97bLOBnbnjHm9Fh9bfzD0Yn4T+c9U5sXA9gsgfYQH+blIITguM3z6eD1h Qcujo2yKI59cJIvLswxGEGAk244ZxyRgDRs8mWZYP/NGhbeDsQE76luzRsk/0TLJ 4yxDvp+mAIuzwljLmRdgy50/GUeSZ2kge7SJ0lU+am9E2rT0JDQ0borHvFEZD5ZC SfplI27V9NH+dKGqPL5s/Kf44Q9Tntuhv9VaCKmD0ISP0+QGtIx5vYx8DmiATUGq /kgkUjaJm2lZMZklCaQibNLEKVUcpFD4n0Obwd4l8pTK71T6AhbouHloffp4YpVh V4xmhknXY3f7tVjJZcRYVdF5DLXNy8z/4Bk8Z8NCEBzCDvgLlqsbanU5fHQc -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEHTCCA6SgAwIBAgIRAIyKF6j474AWe01PLn9A6I8wCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDEy OTAwMDAwMFoXDTI5MDEyODIzNTk1OVowgegxCzAJBgNVBAYTAlVTMQswCQYDVQQI EwJDTzEPMA0GA1UEBxMGRGVudmVyMRgwFgYDVQQKEw9UcnVzdE9jZWFuIEx0ZC4x PjA8BgNVBAsTNUNvbnRyb2xsZWQgYnkgU2VjdGlnbyBleGNsdXNpdmVseSBmb3Ig VHJ1c3RPY2VhbiBMdGQuMTUwMwYDVQQLEyxFQ0MgRXh0ZW5kZWQgVmFsaWRhdGlv biBTZWN1cmUgU2VydmVyIC0gMjAxOTEqMCgGA1UEAxMhVHJ1c3RPY2VhbiBFViBT U0wgQ0EgLSBFQ0MgLSAyMDE5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/l9w GSFVAUkSfYoRYZM5ozTekzO0vj0CK3bhjLfKXzVoFyQS7kP73zs9OtUtT42V1DKD GkiFtTN9hyP7d0/M+KOCAYswggGHMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc 4DXGY2OaMB0GA1UdDgQWBBRL6Hej0fZqReZ423DkvLaJwR2KSTAOBgNVHQ8BAf8E BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEWF2h0dHBz Oi8vc2VjdGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwu dXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5 LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNl cnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcw AYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNnADBkAjBu b4EAfkbNWYQ/KUv/uy8PaI4/sXVrDkyQPIybtawwfEq1sULyfYI9IHCMx95iFyIC MDYLclo35A0UXSQtIcBctq9MKuGQ/OLnkTj1Wif3Vf4lizQ+sZiglwNQdeAKPUN/ /Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkDCCA3igAwIBAgITBvHsAOWOmt03LIcdJYQ/2rhS2TANBgkqhkiG9w0BAQsF ADBIMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRp b24xFzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTE5MDEyOTEyNTk1OVoXDTI5 MDEyOTEyNTk1OVowgYIxODA2BgNVBAMTL1NlY3VyZVRydXN0IE9yZ2FuaXphdGlv biBWYWxpZGF0aW9uIENBLCBMZXZlbCAxMRQwEgYDVQQKEwtTZWN1cmVUcnVzdDEQ MA4GA1UEBxMHQ2hpY2FnbzERMA8GA1UECBMISWxsaW5vaXMxCzAJBgNVBAYTAlVT MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4QVBCdYToXFIfzd1SQfi TEgg1bwHXM2cE2VsyxwWK8NEFH8zMYdKy2hYOAjbfpm0xE6q4TQzS8KL2vAtCNyY VrwX7d3IvKR25H5s1LUDeQXSl1JBBZCtgJf2caJcwaYa6n2pZ0EKt3wBB+QteSFn 57ENB37T13y7Nn8gCt9ZZaPYqRWxHcPaIWO3CVzQZ3tXjCLqzJMCV2KqhK85DZk3 wo33Zb6cyYDkerDbWyric+10dJ/wdgE49dkfyZxVxEGpHg1SCSJdHjGb4z85Zx/u eBpxBS6g3dfrkDjjT3MUxyNS4EaRTZp7o/2EqVCYDWJDM1HcOZL64kyWyi0d9jqA 7wIDAQABo4IBNjCCATIwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMB0GA1UdDgQWBBR/QuNI bljpLrlhyGp3tPcDuM1qWjAfBgNVHSMEGDAWgBRCMrYW+gT9/l1LesP990xAHVpD rzBBBgNVHSAEOjA4MDYGBFUdIAAwLjAsBggrBgEFBQcCARYgaHR0cHM6Ly9jZXJ0 cy5zZWN1cmV0cnVzdC5jb20vQ0EwMgYDVR0fBCswKTAnoCWgI4YhaHR0cDovL2Ny bC50cnVzdHdhdmUuY29tL1NUQ0EuY3JsMDYGCCsGAQUFBwEBBCowKDAmBggrBgEF BQcwAYYaaHR0cDovL29jc3AudHJ1c3R3YXZlLmNvbS8wDQYJKoZIhvcNAQELBQAD ggEBAIwGM/ejz4Hbjf7Vc11gS8jzf+BwtZq9N4t1Nibj4rIDsW2G2jDE0S7fCN2m Mhq76xkfnwfXhBbXDEKz6rj/M0G2u1kHw4Y8ZtKSzYEyRtgpeBFm4qU6voCSREpD FJXsL+Go2/YLRSE6xkWVSocklxppx4hi5o/RVdMMQept6ooOSFzBpH5XZYUoblKi 99Yj0FUe8egIa9qSts42TObTpH1YVRMDnH3k2MNX3rcgPf9v/QO9Cf8W6RQ2+X3R CaYMPdL5OIKh4RGYjxXe3LpgiTKBWik/ZWTFL5sZSjetrJFl50NONzTc8E+BJtrx VCHAI2OcWyloxrYd4zMipw0YjDw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEfzCCA2egAwIBAgITBvHsAOgLG6+YcKfEtsvkAaMtaDANBgkqhkiG9w0BAQsF ADBIMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRp b24xFzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTE5MDEyOTEyNTk1OVoXDTI5 MDEyOTEyNTk1OVowfDEyMDAGA1UEAxMpU2VjdXJlVHJ1c3QgRG9tYWluIFZhbGlk YXRpb24gQ0EsIExldmVsIDExFDASBgNVBAoTC1NlY3VyZVRydXN0MRAwDgYDVQQH EwdDaGljYWdvMREwDwYDVQQIEwhJbGxpbm9pczELMAkGA1UEBhMCVVMwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjRHBw8iIivBBrfE6HqexQK0oMt2Y/ x8jO3fN96KEazZwEoGidwloRBk2Q7VfVvZ0ZDk+qwJZGLZJLS1ntGaZLH4/Iel+r Pnp36IVF7J5MNDB+K81a/y9svEMfDu0p3FdlBUyhHvizZ/zFNP3tolmQfZ7T0mGL 7lutlNAzFYoVTUlVeF5cSC8Yca906TEKyizYXuXcY8Diee+t+fQRHmSI5Hk5kyXD YFWcf2tXEfdkuFlDjJ7HPdFyfJzrNjD+cbqt8R5rZKnK1GNVP1dXm0cIYS+BMlMa CC1yF18oygbnOZLw5fDv9bxs4MOgF8E/Iypw0hLQHVkuD8wAvxVgPsqvAgMBAAGj ggEsMIIBKDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNV HSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUYt6tehfefLfDfCMXo7Em5UbXOvQw HwYDVR0jBBgwFoAUQjK2FvoE/f5dS3rD/fdMQB1aQ68wQQYDVR0gBDowODA2BgRV HSAAMC4wLAYIKwYBBQUHAgEWIGh0dHBzOi8vY2VydHMuc2VjdXJldHJ1c3QuY29t L0NBMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9jcmwudHJ1c3R3YXZlLmNvbS9T VENBLmNybDA2BggrBgEFBQcBAQQqMCgwJgYIKwYBBQUHMAGGGmh0dHA6Ly9vY3Nw LnRydXN0d2F2ZS5jb20vMA0GCSqGSIb3DQEBCwUAA4IBAQAHXPYhl+++o//di2Qm aWGmC1ijxbGbKA4jOSDRvQfxlWOVkqPF11Dpxz+V8Rxw7QFFVoJ5mHpfoXtQOijV tsCFknxTKgzQeArNkZrkXBNpYOJAcuc5v0eX0OllBWgVdIvZRl2TM5L/u1WFrlPr qwWdEYTkinQwgAHXVV/7WZi6c4StcqNnlw93mlvN6Vspzaf/mWtcYp+aqT9vrqHt yNR1k8Ri5eIRPIU0B8woiXTj3bifLg6/O217SY5cWwQKCMFsa6nGWoRVCJ0JJXa0 Z+m3mPQD2OcW5YMrynhL2VWohyfZAjB8l/NZaeRT7M+vki56fxbx3Bk2lqy8Z1Zz Wd5m -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEizCCA3OgAwIBAgITBvHsAOMeRtNBsrJjPOSA2RX4HTANBgkqhkiG9w0BAQsF ADBIMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRp b24xFzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTE5MDEyOTEyNTk1OVoXDTI5 MDEyOTEyNTk1OVowfjE0MDIGA1UEAxMrU2VjdXJlVHJ1c3QgRXh0ZW5kZWQgVmFs aWRhdGlvbiBDQSwgTGV2ZWwgMTEUMBIGA1UEChMLU2VjdXJlVHJ1c3QxEDAOBgNV BAcTB0NoaWNhZ28xETAPBgNVBAgTCElsbGlub2lzMQswCQYDVQQGEwJVUzCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANS6vRtFpCJBJ7zJODH07Y3k54Qn VIBhnQmmWoqFqzCVMX97GAyAfzjcQrhl/TNiJiRCrVQWPI4n0R8eUd91Ab1Qzfsr np+0NRbagVDa6+nF0KcNxbSZ6/iZQ7Ac3HyhCvJS2rH2CVYlzqdsrxDXcZk69jOO dPV8+w+7eNIn34BKpB/ZF7iXApDoAKG81kg1VtpGOxJhxTsKLuJmURT4pQjtZqF+ F6rN64j5T2DOK0gOA4G7BLoTdOQuXkPS38LXKgZ43lKqEenjmiOaMF/XuLYzaHrW GYgCM2wJsykgdB9hCsTTEwsHRZzt2q9mLBDvYYWVhql1/kR4K/RN4JdESEECAwEA AaOCATYwggEyMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB0G A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAdBgNVHQ4EFgQUA6uAxlUKKpWh 4Nf+GubAynjMsJYwHwYDVR0jBBgwFoAUQjK2FvoE/f5dS3rD/fdMQB1aQ68wQQYD VR0gBDowODA2BgRVHSAAMC4wLAYIKwYBBQUHAgEWIGh0dHBzOi8vY2VydHMuc2Vj dXJldHJ1c3QuY29tL0NBMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9jcmwudHJ1 c3R3YXZlLmNvbS9TVENBLmNybDA2BggrBgEFBQcBAQQqMCgwJgYIKwYBBQUHMAGG Gmh0dHA6Ly9vY3NwLnRydXN0d2F2ZS5jb20vMA0GCSqGSIb3DQEBCwUAA4IBAQB1 fzAmGGmtbJyIvOfjq2McCpUoYkXAq6JTN51+nb9NDAihhDoTKMde+801bC1/l54h xPPm4HImM6GK6LFckDew/FGwbdRbEznUOJ7uVL5ploNBIjte23kTBUZa9fx3+aXK hUTAipSyPtNjnOwVVBVXzrMynfMhdsyRRe7gLXNFYCXIxtks3IkIpuYnc86NAuV9 nBLFlZzgmbAsW+tMc5QsNvQJ9pQ539K8cqZaM+HFCScreDERxmNtHHbMw+hCa2yL Oj4ntekgWLO8KQbE0lPUNLIM17QK8aktJavj+GezBztKMmJJwhVYQy9nxS388ApX xcZsEgIzOCeH0SOWg4FA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE9TCCA92gAwIBAgIRAJBz12dMnLp7vhBwZZPdcjMwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xOTAyMDcw OTE0MDhaFw0yNzA1MjEwOTE0MDhaMHgxCzAJBgNVBAYTAkNOMTowOAYDVQQKDDFT aGFuZ2hhaSBQaW5nIEFuIENyZWRpdCBSZWZlcmVuY2UgQ29tcGFueSBMaW1pdGVk MS0wKwYDVQQDDCRTaHVpZGkgV2VidHJ1c3QgU1NMIERvbWFpbiBWYWxpZGF0ZWQw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4YexzKrFMgRgVCAruOrGe FjnWGNX6DDP3tbsEHUJLEgtB4Vz12kNVyVLXFpNC++MCjnVOv3lemoZ9KgDPYbFL gyB1d5nDRTvqsem4kWnCejc/RABCAV/kM/kLM1yzmislxwo4UtNeSecohqVlVBfF ac+CThX4LVqRRDPpma+3QdCXOFthqZ+ZSCCEJAHUx59maxhQNLALSJUxYHNLk6se EiwIu2esmw1iSf1PeRp5llQcc1e7QzGkyR+fS7tXeM0G0k9PepN/ch1HWZpZjlHF LwFhNMRYwrr5vByWOy1scwYtCdijIhAshFmApWlelqS4G1NTTiwrRwcR/Sns8xbB AgMBAAGjggFsMIIBaDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQsbNED yG0a2Lhlw2y9Zu+SIZ9t2DAfBgNVHSMEGDAWgBRUmd2b/+inDqMZnVu+QlffMPyP MjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly9zdWJjYS5jcmwuY2VydHVtLnBsL2dz Y2FzaGEyLmNybDBuBggrBgEFBQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9z dWJjYS5vY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0 b3J5LmNlcnR1bS5wbC9nc2Nhc2hhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYw JAYIKwYBBQUHAgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0B AQsFAAOCAQEAxym3Gby0vLg4tG+l5BS8P+cssXo3WlzCUt3MdX5Go01ZZUxQuKcH p9val6R3dqw2km5RQdYPNJQ60uNFSXQON5wGBPZklfH2jodWx2idtNKa1JE6Tvge evd/l6ROvOdLslNz5K3zrz/JZcP0Io091jMZTzZmOUuGU1xxmAht1Eu2TIx4Jm4G /9r8ELfvwS2xk5+c49So9eMpVI3pSRtKsaz6ZrHn+rYPL/a8byrVfILrFkb6Eb+g EOb9mXaA7PFzFTh7DtdWUb5AwZL62k2kcvSCi03nzkxe62A0WZ5y0BuT6xlRvalJ 4bocr2ivrYkB+Ky8pM74qmIEUGm5zhmwQw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE+zCCA+OgAwIBAgIRALN4DITbDQQbHNZqQMuNlXMwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xOTAyMDcw OTE3MzRaFw0yNzA1MjEwOTE3MzRaMH4xCzAJBgNVBAYTAkNOMTowOAYDVQQKDDFT aGFuZ2hhaSBQaW5nIEFuIENyZWRpdCBSZWZlcmVuY2UgQ29tcGFueSBMaW1pdGVk MTMwMQYDVQQDDCpTaHVpZGkgV2VidHJ1c3QgU1NMIE9yZ2FuaXphdGlvbiBWYWxp ZGF0ZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdHx//2UKRJSt+ /zvSdx6wCFCGwsYKVjQQP30JLlqdwDNZvHBlSq46dNT9SlpH7eZVfjJRf7hgEE5P x9lnOM/ESMhp6oA7JHGwygD4NmYiOqmHFA35AQE82hrVbFjVDZhqMmmi1eVNJOLX PX+qWIdmS0Ciq1JYsHSp+mRwXdb1PwlXjPyp6MOKab7qaxQRDVgSakhlItA/MSGL w9kwmtTiRLHsTUwWyiTTw8FddPoPVumrgMvxxe/b+1rMklzbFVCI33ZC2/+A2/Pz e7TnfaF14oLBg8jGZ9y0tBUk0Hjwi/EvVfGM7z6h8DpKKBirKrbyb912kPu4TJz2 4WuKJeI9AgMBAAGjggFsMIIBaDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW BBToRhDHcp4/KfHOdHrCVZZvICWoQjAfBgNVHSMEGDAWgBRUmd2b/+inDqMZnVu+ QlffMPyPMjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMCMDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly9zdWJjYS5jcmwuY2VydHVt LnBsL2dzY2FzaGEyLmNybDBuBggrBgEFBQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0 dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9y ZXBvc2l0b3J5LmNlcnR1bS5wbC9nc2Nhc2hhMi5jZXIwOQYDVR0gBDIwMDAuBgRV HSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkq hkiG9w0BAQsFAAOCAQEAb5gMOfFTwoQUuEboZC3yP3LIXiY3xoV9sm3eywZ0o82B CCFWwo+7BFayN81CZ9tUJCJ/D6zVyuaRiuRc86TBREnP51JA4DQtk7sHzzFb8iKJ NmC2xRg9g8+nZxY64i64sMyrU9mONsFoKLFYrgHU3WMejcD/YUTGz/Lp/G/nR2yw YKYYT/1+7E7T1dZPnsmNo2zfmsGA1R2mVUE1KlxnGc04eyU8kfbVAu9qKVpAx+ir h9Q1BKWUZx+fynprRC6LnuSQYWhdcbF//QSNaNZnnp9GhEmSHCqxmBlre7tpCYae zkt3EVSu4+FtUZt3xueJkD8zorgd3187CrwPWzx9TA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE9zCCA9+gAwIBAgIRAKUdNES83rHzMkAAG9WNITgwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xOTAyMDcw OTE4NDdaFw0yNzA1MjEwOTE4NDdaMHoxCzAJBgNVBAYTAkNOMTowOAYDVQQKDDFT aGFuZ2hhaSBQaW5nIEFuIENyZWRpdCBSZWZlcmVuY2UgQ29tcGFueSBMaW1pdGVk MS8wLQYDVQQDDCZTaHVpZGkgV2VidHJ1c3QgU1NMIEV4dGVuZGVkIFZhbGlkYXRl ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPEi9Buyt66nevUyqHKI JYwFWRicYo9pRsTqM7BsSXmrglxwUF8VppXJZ4Ha13+CFABi72Z8kF7hzLO46nvN BTGh9Lfkrw0D/d5nnMEpSNwl0qLcEDvo5XY/OeoTRh6KEaWaFTcSkpEoDfqEzjJb uxMRL0VrRJ/bsXT2fdFxI8BSLaqfT/4+n93LZOZr3HBt8gFx3I2MRhwxmSvvEm59 8RNUzz+19DHBFxtZs/28hhwEMMizsfC9ObWdOp15youq5i0TUs/G8ce6TdWjut3I mMVAqXiRwztdftgrhWAJhHXKBnD+BvLJRLX8vaw3WR/3RunDtk5N+15dpZYV2gYZ haUCAwEAAaOCAWwwggFoMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFNW+ hHZJRS+v+A8yjM6v14JCrARbMB8GA1UdIwQYMBaAFFSZ3Zv/6KcOoxmdW75CV98w /I8yMA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwv Z3NjYXNoYTIuY3JsMG4GCCsGAQUFBwEBBGIwYDAoBggrBgEFBQcwAYYcaHR0cDov L3N1YmNhLm9jc3AtY2VydHVtLmNvbTA0BggrBgEFBQcwAoYoaHR0cDovL3JlcG9z aXRvcnkuY2VydHVtLnBsL2dzY2FzaGEyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAw JjAkBggrBgEFBQcCARYYaHR0cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3 DQEBCwUAA4IBAQBIvW5JPAIUDNlN4R7nsamAJBewnUZSOV/uNC8WBZ/VJDl+U6s0 FNcpJC5bYPAnNnIrbMFNFKtgk/g1hdD8i5ajgm8HeAKGFpAe6WWDkWuguWuQot9b Co5MpFx785yQGyswUTBX3F6q7UXq3rb/Gr/k9bzVM8C1zV161Ly/2JpGNZq25JIL tdxar/gvOjibJh0Nph9po/wHLso9JofXat57+WOjnnxgOwN8arnED+l6T+h84FVl R9BQk36Jw5DXYgtVMLUJvlsR/6f8VjiWb+T7OQi9wSPXjSV1HcmKL3HEo1UzC4Dn /ZJdAIojNpsv3V4shBorn3Ng07/Q7sTdDprj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG6zCCBNOgAwIBAgIIYIJC1GAilOkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTkwMjE0MTc1MzQwWhcNMjkwMjExMTc1 MzQwWjCBgTELMAkGA1UEBhMCU0MxDjAMBgNVBAgMBU1haMOpMREwDwYDVQQHDAhW aWN0b3JpYTEgMB4GA1UECgwXSW50ZXJDbG91ZCBWZW50dXJlcyBJbmMxLTArBgNV BAMMJEludGVyQ2xvdWQgQ2xpZW50IENlcnRpZmljYXRlIENBIFJTQTCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBANpmdN/JP9mh8dvaHtvuxFKRT5UOrUXB 54TcSIqvhlMIm+JPXJygFjmSp3y+jX9MS5r5y9PtBf91HuttrAS++LMslPPJWyHP vZxhlO4uf2c7T/AD/5iaDwd3ik9koWUlctC7J8StZJmUA0eWu15dL9bCxkLDERNJ 1DjXyai3rf88jM8PKUgMP0Dn22p3QvcO07fnkMUvJK6ACaz1JN5C1gflcbtteItV 6xsyeVMx1nqI4zm89nGiJt9jk7ZUZU6VwtAcPO+iG7XQJDIRXY/NGKFA2Rplr8xR 1BxVTTKkuAKVNAFC6ER5Bf0whODRnl/ZFyAA1Cgzj1ShYJkUT19jv0h0B2WswJ5s H7w2/s3QbpDLVHSWVrbHvIf5F89KgBgt8I0HTZH0E6lLsSTWV0OohYplkpiTYFAs lzD54ZGvrlSyfy0uhaERMfR6bLBzQuzO4JPIHwvqanXF92kdeLqb8gIqYzriC+l2 KKPk33+HqiExHOpX+ELh334tt0vFklUYOYhtQdj/t0Yz5Uu4ca+kVJrzSNHZvy3U viIwNjLMafmvBVoLGcGtO1qAKVm0PmHnIQezUkiIbvhMAsHTgJd5VY0j/KsJQIXe 9zG5PKkLZH50btmaBaWLbvPtHdMR1xdSefHUjIg54kcRdN9Fwb5kWa7LB9V5V7+a +FXiHMTRnHMLAgMBAAGjggFpMIIBZTASBgNVHRMBAf8ECDAGAQH/AgEBMB8GA1Ud IwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMIGDBggrBgEFBQcBAQR3MHUwUQYI KwYBBQUHMAKGRWh0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTGNvbVJv b3RDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5UlNBLmNydDAgBggrBgEFBQcwAYYUaHR0 cDovL29jc3BzLnNzbC5jb20wEQYDVR0gBAowCDAGBgRVHSAAMCkGA1UdJQQiMCAG CCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDDDA7BgNVHR8ENDAyMDCgLqAs hipodHRwOi8vY3Jscy5zc2wuY29tL3NzbC5jb20tcnNhLVJvb3RDQS5jcmwwHQYD VR0OBBYEFIIuZPJH09er0spFewhmjPoLx+lCMA4GA1UdDwEB/wQEAwIBhjANBgkq hkiG9w0BAQsFAAOCAgEAfbuLb/9do4ADeUheEc9Oq6SeYqsCfQuaVZbl74E7XjnZ vgvC5EP2mFE+UI4WdCcIs1MXLg9US7RM8R+7X7Q2aAOCZbytha5wbGsX/XlJohjI dfHfJjmu2rU7X5Lr8K6nO1xNoH86cEztTW/o9IizBQqilMEbJCJXV+NJmjNMazy4 T/X7R9dsnEP27lWz3DyXFmuuyoYJMFyOUlggvlkv0fxObo+tPZf7T+kJEvIArY4L hJBlSaEhFxco0j44lD1MfPIWP5Lb0qE6jgkdAyEGsA/9DiMpmJrBOuCBGmc/LFU6 8kDCQJi79OhogHHB5ddBly+ld9kwMmByAQOVcphEaDbgSJviPoolhGmzjzpLreTi opCBKZHQ/hbpqHOw5yL93Dn9FELdGSEBylng9I3H4uHsCYignlGfRNtjgSuu6fxj 5eqmsTGsrExuPLs+lpytJpZkzn+H3Xc/YhMswnxskmm9U4CtknNbS3zs2nuzAnUZ GHD++aujR1hsejpkyXj1P7i289gVF+u83iRFZ6Zwc3kA9638NHEhzgz2vQikDxYk swZVTQBOxCj1w+KGJP9DacAeR88WLiwjoiKN4QyCjYpJoFBPz//HJu4fpmwxrmz4 xBdfU/BnNaoEtFKg1q9HfjEL1XjquclMQWMo6yAVTF2ZRHhh4dfrWCGSFw/DZeg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFCTCCAvGgAwIBAgIIPyxgjFz5YyEwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTkwMjE0MTgwNzA4WhcNMjcwMjEyMTgw NzA4WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEG BSuBBAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllir LZXI7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/ qCPgCemB+vNH06OCATswggE3MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU 3QQJB6L1en1SUxKSle44gCUNplkwgYMGCCsGAQUFBwEBBHcwdTBRBggrBgEFBQcw AoZFaHR0cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29tUm9vdENlcnRp ZmljYXRpb25BdXRob3JpdHlSU0EuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2Nz cHMuc3NsLmNvbTARBgNVHSAECjAIMAYGBFUdIAAwOwYDVR0fBDQwMjAwoC6gLIYq aHR0cDovL2NybHMuc3NsLmNvbS9zc2wuY29tLXJzYS1Sb290Q0EuY3JsMB0GA1Ud DgQWBBSC0YVzMOc1BNOOApL75aTRxCHozTAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI hvcNAQELBQADggIBAPC4p7e2/AfR2M/1S1dX6tXCKBNJmezj60laF+VZgx6mWPUE IfVy5TPHGIjEQHucWLUrgvKpWhIqRqxAXAIYfLetsWMNHpZcbgvyMSc5ZnZgGJFp EMuaCGPpmTYNvg0KE+Sp3mExmC4jqeebN2kFQnaF99rGxCKGwXy7s9wvpVM0jHqU YU75uN2Wlr0SF/cdPk/RnQDSQf97KXlIqXVCUnwu9oobgOl8ULITcDLYqtvbXrQb 1lFrkjYQ6jIU7wNi2URiMPuwJ9MhKWS6Bt2CMUisnIVp2PZ5LkX1lBQdmNWmBg6w bgg3Ya2g8hPIwwyq850O7u9qrhAsjYkFJJVxlb0Mzvz675nLzzGzdklLY0GADaDL K5yuVoMcuijaUnKNQHnwTXrDiMZOgtTa7+UNmBjA5VAwwN24wl5UgYw8plgnCIQy V4ltHNI0EyKX5NyOHtfT2MLelI4rqBsleMIF065b1A7IQb/sgrSpq0dlCRMa8YGG mafxhWKTFABz0ES2MrXm3falKY/fp48TKNTnYU6QIMO6evNNXbxtM2gGVN+a9zIh Ghfxg5Adv4gju/886VksL+4YrGZvTHB+EtHCD/jvKOslGAitujP0yQ3bCSgZbkyQ S2eC1h8SyRIbOcb+8WsL0vXJkpz0eK3FVsEGdd3ECjAFazn5T00wP02aJxfa -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFTCCAv2gAwIBAgIIf6MrKLHJq2wwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE5MDIxNDE4MDg1OFoXDTI3 MDIxMjE4MDg1OFowfzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYD VQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAyBgNVBAMM K1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAASqEkeQmBv778NAB4MgTvEwgqIG0fKShmHy9iFo ygDEx+pDAFSG3P0f3wC4QWJc3HAWMt4fmdTMxQfICB9hFgdRPX1cB1PjNTiM382f 2S4NSrYZLlpwWgbtvvChsMrQCSmjggE9MIIBOTAPBgNVHRMBAf8EBTADAQH/MB8G A1UdIwQYMBaAFPlgu9Tj1TT2uPUGgCWnc9tGaaieMHwGCCsGAQUFBwEBBHAwbjBK BggrBgEFBQcwAoY+aHR0cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29t LVJvb3RDQS1FVi1SU0EtNDA5Ni1SMi5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6Ly9v Y3Nwcy5zc2wuY29tMBEGA1UdIAQKMAgwBgYEVR0gADBFBgNVHR8EPjA8MDqgOKA2 hjRodHRwOi8vY3Jscy5zc2wuY29tL1NTTGNvbS1Sb290Q0EtRVYtUlNBLTQwOTYt UjIuY3JsMB0GA1UdDgQWBBRbyl7l3tKBqs2oLWRRttlym5fmTzAOBgNVHQ8BAf8E BAMCAYYwDQYJKoZIhvcNAQELBQADggIBAEtbzx2YtVSveXwjAgO1JRrPoxRpnjOU sxDIcy9Jcc9NeVv8poNXSmxb9M2giWJ1llgCJiLn7SIs+4FmE00bYIB3K/OnOPz4 KjZQUVE1dP8Meds7rfRZiQxqDWMoIDGK1XI6Ug1gQx4Q82KxG0AVZW8m3AeD96OY Wj9VXYAb5zdwqw/28xaSYgsoqUSETjFNCLePGy+Is14Am3MF5kRp0/8TktUmoLta dY+F9MF9kG6e0IzjwxsUpJzBmQw+zLZUJW/dCs23dH4l+mMTu9udrewqHbJccXd4 JpPSL4W+WcF9s9ymT8HJgQ+yNR7wlPiDJvksRZ0AAQYlcrViaaRnY7AfhmrS1Qp/ VULhXQFxxOmQdAAcqSvXSACS8/gsYqKuETokm5Ws4FHOFyEtt0pDfIkbrD7opvaU ksX4JPJDkjnyks9/EfiLcdZ88/MgZJw7xK5CaSsntORqWShQFaqKukdhWu3AdGG5 Jp0NbZ+J3ws1ft8WMDc3zBXMKG8S9i8Oh77nr6KcvJhJ/EtBBdkhJ1qJ/bVxLAnn jTMzwd8YqO1+UEmZFwtNLzCljpZ6tTWn1qY6ijn/CshHmL5HqnWzO8sFno4vgKpM JbBok9Ol99KWY+eFSVm/IDkCJOIyOVOt0t/xrfYG74VO4RL2hfK0qbO6KhW+GaoC l2Lxp74DbA3f -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDyTCCArGgAwIBAgIQC1v2W2un+9CLKQ2QRTfe4DANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTAyMTUxMjQ1MjRaFw0yOTAyMTUxMjQ1MjRaMGcxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xJjAkBgNVBAMTHURpZ2lDZXJ0IFNlY3VyZSBTaXRlIEVDQyBDQS0xMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAE5rt14WuvLvHn+zZK+KRSigbJRYTGRHg8A8Qk iFTl8S6JM3rPXQ45S7mZwHGqWnvKEM4w4PEPg9x0e8kZGb3fGqOCAUAwggE8MB0G A1UdDgQWBBTbNURdK+tTr54L9XE9o5lzrvtcUzAfBgNVHSMEGDAWgBQD3lA1VtFM u2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAm MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0fBDsw OTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFs Um9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0 cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAq/3I H6J/UvB/6Q9OECLSeul5xkW0PvhDzYJhcRJOZeWYWU575/+8ZnDJ/JhYx4wbEZ+P VCDLiVhiKU3//F8W7ZdsVLqhdVVrOoZJv+JZar3RZ1rgwhavgHB6Sq142nTSzG5J 3O7+i2NZj4MJVM5uKPDUx659T2m2CsjzzXhFRnacQrN1QFh7+EUKXmxB1oFMcC8k 4BSi4ZYvsAAvb8Xh0g4fHEq8fbAwffNSfEvY3JEbAjeRVA31J1ifBMwliRzPHGLf eyiYwvPQIUJ9ODieH5vDzLq9XvtdmFzBPXlFnHKI9LphN6sUVXdf4B+dao9drFZE ifuXbKlQ/2TRZPFeBg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFRzCCBC+gAwIBAgINAfJAQkDO/SLb6Wxx/DANBgkqhkiG9w0BAQwFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFs U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xOTAyMjAwMDAwMDBaFw0yOTAz MTgxMDAwMDBaMEwxIDAeBgNVBAsTF0dsb2JhbFNpZ24gUm9vdCBDQSAtIFI2MRMw EQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlQfoc8pm+ewUyns89w0I8bRFCyyCtEjG 61s8roO4QZIzFKRvf+kqzMawiGvFtonRxrL/FM5RFCHsSt0bWsbWh+5NOhUG7WRm C5KAykTec5RO86eJf094YwjIElBtQmYvTbl5KE1SGooagLcZgQ5+xIq8ZEwhHENo 1z08isWyZtWQmrcxBsW+4m0yBqYe+bnrqqO4v76CY1DQ8BiJ3+QPefXqoh8q0nAu e+e8k7ttU+JIfIwQBzj/ZrJ3YX7g6ow8qrSk9vOVShIHbf2MsonP0KBhd8hYdLDU Izr3XTrKotudCd5dRC2Q8YHNV5L6frxQBGM032uTGL5rNrI55KwkNrfw77YcE1eT tt6y+OKFt3OiuDWqRfLgnTahb1SK8XJWbi6IxVFCRBWU7qPFOJabTk5aC0fzBjZJ dzC8cTflpuwhCHX85mEWP3fV2ZGXhAps1AJNdMAU7f05+4PyXhShBLAL6f7uj+Fu C7IIs2FmCWqxBjplllnA8DX9ydoojRoRh3CBCqiadR2eOoYFAJ7bgNYl+dwFnidZ THY5W+r5paHYgw/R/98wEfmFzzNI9cptZBQselhP00sIScWVZBpjDnk99bOMylit nEJFeW4OhxlcVLFltr+Mm9wT6Q1vuC7cZ27JixG1hBSKABlwg3mRl5HUGie/Nx4y B9gUYzwoTK8CAwEAAaOCASYwggEiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAW gBSP8Et/qC5FJK5NUPpjmove4t0bvDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUH MAGGImh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjMwNgYDVR0fBC8w LTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBH BgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQEMBQADggEBAEmsXsWD 81rLYSpNl0oVKZ/kFJCqCfnEep81GIoKMxVtcociTkE/bQqeGK7b4l/8ldEsmBQ7 jsHwNll5842Bz3T2GKTk4WjP739lWULpylU5vNPFJu5xOPrXIQMPt07ZW2BqQ7R9 CdBgYd2q7QBeTjIe4LJsnjyywruY05B2ammtGtyoidpYT9LCizJKzlT7OOk7Bwt1 ChHbC3wlJ/GsJs8RU+bcxuJhNTL0zt2D4xk668Joo3IAyCQ8TrhTPLEXq+Y1LPnT QinmX2ADrEJhprFXajNC3zUxhso+NyvaxNok9U4S8ra5t0fquyCtYRa3oDPjLYmn vLM8AX8jGoAJNOk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHVjCCBT6gAwIBAgIIOoGeCD+9uPUwDQYJKoZIhvcNAQELBQAwgaYxCzAJBgNV BAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFjYWRl bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAw PgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRp b25zIFJvb3RDQSAyMDE1MB4XDTE5MDIyMDEwMjIwOFoXDTM0MDIxNjEwMjIwOFow gZcxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHDAZBdGhlbnMxRDBCBgNVBAoMO0hlbGxl bmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0 aG9yaXR5MTEwLwYDVQQDDChIQVJJQ0EgUXVhbGlmaWVkIExlZ2FsIEVudGl0aWVz IFN1YkNBIFIyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAi1509ou7 uBA+oO7qM9HWxzUC8x5cw/Uh/PIuqgBNoXgd3K3h8vNq8qIn+0T5kj/aR00vtUju JyhuS8ZakjG2DsXDUoD6PNOjTaxLWt7pDXgfM0lcgfOh2FX1HnP1jkSEUKfnODx8 0SEtY6JN7vUj4dq/e2In5YdhBfEkXI8xEtV08Q9H/VK4ETtDUFsfpf7KJDea5/N0 XL0+t33nbabIoCEPAo1ffJTRyBGZbybc00IdAu6yCAdxKo7ujexnb6oMY+ZP+ODL Lf9Vz7yzUVWPsYVSbzyuPzu0r/7KmfxAfnsYRkZWHZsjfXHk1uqTQZzYkNkFGgi3 IS9EIXcXyCMl7OAMSQQ+ipWa/ale1xMjQWKLakkGxjvYHVYBQEaxPvgXdZq1ebjk FRxDTPvQVTndp5B/4aRDIOsHed7Zed/4QrXmAXiNOzFOCcdKyPyoaxHKdxogRvBu d9jNBidVDMTz3O/9+J0PPoOcPmkI5TRHobG02qgxJlMIHhtlrtaa+k3hhwv+O1RY 1bgg8SzKeDb8M6hsgP/jmYf0vRA/2gqLfrtzII49IJ2py2ZcHNj5ozYNE4OtBLcA VdeOsNZKya20UjvLdDJqLMS8cK0WjXVrKCRA2ckX1EUgMA+PMjIPiEvh3RgicoZB qQM4JPeZrn8IZUANklLOLcZflFMdWJ83R2MCAwEAAaOCAZMwggGPMBIGA1UdEwEB /wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUcRVnyMjJvXVdctA4GGqd83EkVAswbwYI KwYBBQUHAQEEYzBhMDwGCCsGAQUFBzAChjBodHRwOi8vcmVwby5oYXJpY2EuZ3Iv Y2VydHMvSGFyaWNhUm9vdENBMjAxNS5jcnQwIQYIKwYBBQUHMAGGFWh0dHA6Ly9v Y3NwLmhhcmljYS5ncjBFBgNVHSAEPjA8MDoGBFUdIAAwMjAwBggrBgEFBQcCARYk aHR0cHM6Ly9yZXBvLmhhcmljYS5nci9kb2N1bWVudHMvQ1BTMCkGA1UdJQQiMCAG CCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDDDBGBgNVHR8EPzA9MDugOaA3 hjVodHRwOi8vY3JsdjEuaGFyaWNhLmdyL0hhcmljYVJvb3RDQTIwMTUvY3JsdjEu ZGVyLmNybDAdBgNVHQ4EFgQUtQU9+hgqHcCDxXevoYHgKwyLRl0wDgYDVR0PAQH/ BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQAmirOSsOWRu7hxWgVtQ9w2oFtRptVB fUcobi4d01doFHSAmB1tdhkHZFPxivWgSCHfZiwa0dcROXLIAv+rN9mQ68Y27Y8j eTntNgHbxIB6IIRznTz4ywc06BtjNI6sJHKNutq6vd66g2rTwjpiTLUDYuykeava SjdmG9ie1fJTKfxeUHZmIofZzT0h5x3Gvys80fM6WG/jazj4cROLkFC7XcVZEL76 4VxQc3HP3biD1MJ0j6PgNyHNJGGvpmck8d9I2nSlLxajx57LxbFXPgICgTxAqu1g J/F9vgzUKFh/thdWu6kFIrp5zkJbqIetDDTMijVpEcy+o41USsJxNhANpmkNkGsC FBTkugs72CEdJb1svJU8rdmZsnq7p8FJP92WAcM7qRx3pd4xIB0rVWpeNcDZ907Y 3h0TdvPDDhUaYhxF9t30u4or3NOsi3lniR3CLjVCTA4u0e8bzrT16YX4ev4imiK9 Ts+hq5/YKIne5hP+omyw/3u6AmyJJkMcblCOzzW0XtGpoxXNzSfeZU5h+1LXxt5i WxjeBjOe6/ixjlAnQBFvuNl2p+PcZuyLhV5ZWYDw/8nbWnf8IdZ3PG+BwTmtjwwU 8mEMGBaGmQPT5txq2kKbysNbY5Ep/ql+69G+i/RzxNN5/YIHbdORZ/aBrblfsZYC 6gfIJ9UItipnng== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHWDCCBUCgAwIBAgIIElYS6jdtgCIwDQYJKoZIhvcNAQELBQAwgaYxCzAJBgNV BAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFjYWRl bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAw PgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRp b25zIFJvb3RDQSAyMDE1MB4XDTE5MDIyMDEwMjcwOVoXDTM0MDIxNjEwMjcwOVow gZkxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHDAZBdGhlbnMxRDBCBgNVBAoMO0hlbGxl bmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0 aG9yaXR5MTMwMQYDVQQDDCpIQVJJQ0EgUXVhbGlmaWVkIE5hdHVyYWwgRW50aXRp ZXMgU3ViQ0EgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCcOtue Kes+i7jws4yVUoQUt6RTZ+J7kDS/wHiHbhdKpGcthEoWRoFkl9Q7bIrU7IYhKh/p YhwDkPHmOzEMuY/fK1w3bA7pE9Q1ShhYOu/jRO6b+MRPhmt5XYIQ9EOPwmcbe4X4 vsa/IRY09SiV4sSa49a9ROQy90poPg4pzTWcOGW/btNp1fKx8liy2opbOx2qpGGj Eg1CrRfGawpZFCbY1vOvjN66IYP2D4kA/BY/npd1WIqMZRAyHwuNz3s5weWYuKuA r2D1VtpmhUL9oZfChKdZL6Libmz27H3GcrfPcaQmh1B8O3wVWc6qV6raoZ6NIpxb 2QKyb4TNVgx93BwpSyIc0K0dRvwnkBV2oIOOQo0FV6Of9NoRNok6Fhktm3uU0h4A d4xlpKvBO4wgjyeG3Yg5amPxyTSaeAcdIj8EFW+vUGYjgkCK32TTFkYZjOwPWQ0n DtgLCUJ9pYDyNNtaq58m7YD+8WJiKz9MG/STPsyuCB+fRoWyLjLAukl339TTtH/T PljZs5FfGQwpDz2A+gpGzHl+VcIfS7VWYg4vVCqrUZWNkfnBB7B4wDDrQ8vbEaz7 eIDzuPhvWiaQqXla1BudT17HW0o1edA9i6mk9CRY0t4XeWIbI07ToI8uh26WYUNE 8ugc9d277vSvostxRLvKX4Fr6jl1D2EoWtuUnwIDAQABo4IBkzCCAY8wEgYDVR0T AQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRxFWfIyMm9dV1y0DgYap3zcSRUCzBv BggrBgEFBQcBAQRjMGEwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yZXBvLmhhcmljYS5n ci9jZXJ0cy9IYXJpY2FSb290Q0EyMDE1LmNydDAhBggrBgEFBQcwAYYVaHR0cDov L29jc3AuaGFyaWNhLmdyMEUGA1UdIAQ+MDwwOgYEVR0gADAyMDAGCCsGAQUFBwIB FiRodHRwczovL3JlcG8uaGFyaWNhLmdyL2RvY3VtZW50cy9DUFMwKQYDVR0lBCIw IAYIKwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMMEYGA1UdHwQ/MD0wO6A5 oDeGNWh0dHA6Ly9jcmx2MS5oYXJpY2EuZ3IvSGFyaWNhUm9vdENBMjAxNS9jcmx2 MS5kZXIuY3JsMB0GA1UdDgQWBBTFKHCr1nDYpJHbVIwsmHc1SQ3Z8zAOBgNVHQ8B Af8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAL+Gt008e8vIvO9Z++8p0/409S+q J4GHlVjZo4aF6iUJhnPv5OHBbIHXexbSadzkFNYesGR7neK1WPwXaC8FSu8DfyN7 U7GnkEWQZEft9c+zpO4ppwzd8vLKKLHCTAb0SoZgwz8WQVNyBkx42rnuQujQx6qE X8RNCBzaHzsvtAlQFEUN4hu2G3zXvFROLRSOWF6iaJeXkiuZzY2NNPJ6lHBapiMu xqnhP3Eq+64/mdzaNTqL7rvgxmVYu68ZKtwIagoaA7E48BR0VD6AagMwZ29nTqdn +HZdkdUd2VctP/ieGCG+Inrd5L9XrqBBmbivnk2IoGr3CU7EDKcOb24zbDfGWnHT H3B8dOaDw4DDUwVjirvXaFh8dikeuSrTZmMcjZQgt6y6wpQkmb+6vRt1MLnfrfZ7 rGH4aescPo+4QuKCOgkzDVFuedbvCQG1cy5AsvHGhJulkClX9ZEvW8TfgKMLJzaZ 7s/HQDjaj34LGdZ5kad1I+jO/zMPvUGUlIoS5jxtYRZHyJv0D0v9zY5KG/bHr2ec 4r/fj6Guo102ODZb21FweFxTG9H6vnQGH4i0EzuI2Vxkjj+htY71V8xXZxmfRq7z +FH++wBgX3mTKC3lelh13LdbRRlFMQuKM3Z2d5bwYIbqFI67j3h78c6UcGUq02Sw eRTrMlMs3u73/w1A -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGLzCCBBegAwIBAgIQPBBPCb2cXuUyH0TF6Z2zBDANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwMjI3 MDAwMDAwWhcNMjkwMjI2MjM1OTU5WjCBsDELMAkGA1UEBhMCQ04xEjAQBgNVBAgT CUd1YW5nZG9uZzERMA8GA1UEBxMIU2hlbnpoZW4xGjAYBgNVBAoTEVdvVHJ1cyBD QSBMaW1pdGVkMUAwPgYDVQQLEzdDb250cm9sbGVkIGJ5IFNlY3RpZ28gZXhjbHVz aXZlbHkgZm9yIFdvVHJ1cyBDQSBMaW1pdGVkMRwwGgYDVQQDExNXb1RydXMgRFYg U2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvSg9yNme TnzMON+GPL+s9Rqv7NcqgCFWNhNdGWB71CNy64AiFiBWYrhg1Xzi/bK35kWH0V4F ZWmGEEmDc/yGsmOrWbPsSU5iZPjGnJEu35WutT7WaGkIaatoZlcpv5J5I+nPqkKq bVMXvUtEig1srIons0shw71oNzyo8Xda2f0Jk/EJbJ1e0irSxrmZEBjWJjpTL+Fp IHTgfU8nr/q7AyEBrEYIqBu20g/A69lGVJ8qi8B9sWAT/ac2SfabAkU82UsZWbPU 74xuBb7kDGCGv7Z1PfNHSskxWtx5Subb30YSjqJDVsdOy9UQEKjTVIBLjxozmbbg 2CuQaH8dTHRisQIDAQABo4IBbDCCAWgwHwYDVR0jBBgwFoAUu69+Aj36pvE8hI6t 7jiY7NkyMtQwHQYDVR0OBBYEFA1JyQ8+sd8yA7WS2yWlbXTsWSLLMA4GA1UdDwEB /wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgIWMAgGBmeBDAECATBM BgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9S U0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOwYI KwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET1JTQUFkZFRy dXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20w DQYJKoZIhvcNAQEMBQADggIBAIidyLAuqn9Clxw5OepC+VqX6+yr/Zu24U4PyHXv HPYyxFlYaiVNHv5k2T5xQoNE25ERSWKsGzlkBCRttWnNT+Mhh9+NFUX3kBV2nXVs pA46YqSt6UrzNHwkYs7qM3+5Qx6x3b99UCr+6UjuF1iofagrt47uKUUrApgzRuCF szoLNjbeZ7MUrhecHQ9p2N01emFLRxz/CGeJnH+xG3qHwLSPRUL5gSoNLnVs/uFP 2FEOFElfRF6BZzKo6LzTdYxEaHMVE0sjF3pSxp04WsPZKq/zQ8gqmQKgfm9Qw1Oz Harl8nxbx89HePhwe3tpiNhdFBaMZZSFATPzzeI+NAwQQMelsz737ka583vTpQCG 2754nVq3yPC4BWdpyvNLBks1Tn+O10S+H+Er6i1xw6TE1+kJgP2f0H0KFCOa7cwJ jltuMeEmDm6axVxd2wEi5iYn7c/DkZK09wM+My/WLmSPjrbnSVPrlr5wivjv5jxg CmPbtlCQ7EdNgLXOOMIEhyMf3x/otrVXn3VETnKsHchZrBEqV9sUdj7y2Zb1J3te m/hvm8kZyzp2URWCtjhRRR6oQo56DIaGc4xaJwLqDOJmBBxn/BOUGCla5NviA2i5 RNYx9wRewX5TaaClyjU5+5Rg1G8YiEGcOadfLr5ljpbUfnHvFy7nw8c6CMK/zf9q I/r9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIGDCCBgCgAwIBAgIQQAFpNPSsHJapFG+s8a6JfDANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTkwMjI4MTYzNDAxWhcNMjYx MDEzMDgxNjQ5WjBLMQswCQYDVQQGEwJVUzENMAsGA1UEChMEU0FJQzEtMCsGA1UE AxMkVHJ1c3RJRCBTQUlDIFB1YmxpYyBFbWFpbCBJc3N1aW5nIENBMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAt/6NG4BjDiPol4DapVRTq1CkoYStznIE /zzitTppuvi+N4Offzm0xHsltq9VmC0m3HVFv+Iy+wxo5xWowEDdqeoBVEw7JwZI CjTWb1NQ8ZHtjfvLSrRGtpUrScf67QmPsYuYLb+FFj+IjiKLFvxKMCXLq48wJLbR wzdZOLic0WIK/PwTZV3NOLD0t0Yku6MWSXf2kMrzp/4dbmyBRKqcNsSOdF85Dj1r OT+tJ55xd9Jo34lXAJUMMT+mN12aD3AJ8OSZQKSTd5u4l8IjoQQ1doVhK1gzycS+ KmOXJqJ1FB1qBR2JZg21/znxzkergfrzno890ll3amLDqzKHlt2dBVYK9goEDGVv CvcfaUJLE0yE7B52XoBPdc9EF0ukn1ZTXvw2eFVKmGlabibVqYyGiz4DOEn9GYaQ JKNM3tiWQHyXb0iL/LljkRzObmGW6mVmcu5F/6lLVJlRM5cuVKGJP1PZx0DvGgMt 9rmpr+ceaVeB7O/V4zKlpPT3EMtlmEWnnC65c9aLJjYRkFjP6gqwGmWwFeD8zyia C2CSVCfkMXTukR9QXKasAl5SD/4X3rS+f1L8RHEQ1h0djgePAr0S66IUhRjsBNtc LtNo8KMcWGxrlGz1FDc9yPu1qm2DPZ9nQnPq/ljhxsI/WRfdukfH5dJLuyWLMIkL pqtsvWjspLkCAwEAAaOCAvcwggLzMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0P AQH/BAQDAgGGMIGJBggrBgEFBQcBAQR9MHswMAYIKwYBBQUHMAGGJGh0dHA6Ly9j b21tZXJjaWFsLm9jc3AuaWRlbnRydXN0LmNvbTBHBggrBgEFBQcwAoY7aHR0cDov L3ZhbGlkYXRpb24uaWRlbnRydXN0LmNvbS9yb290cy9jb21tZXJjaWFscm9vdGNh MS5wN2MwHwYDVR0jBBgwFoAU7UQZwNPwBovupHu+QucmVMiONnYwggGUBgNVHSAE ggGLMIIBhzANBgtghkgBhvkvAAYBATANBgtghkgBhvkvAAYMATANBgtghkgBhvkv AAYKAjANBgtghkgBhvkvAAYKZDANBgtghkgBhvkvAAYCATANBgtghkgBhvkvAAYM AjANBgtghkgBhvkvAAYLATCCARoGC2CGSAGG+S8ABgsCMIIBCTBKBggrBgEFBQcC ARY+aHR0cHM6Ly9zZWN1cmUuaWRlbnRydXN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9s aWN5L3RzL2luZGV4Lmh0bWwwgboGCCsGAQUFBwICMIGtDIGqVGhpcyBUcnVzdElE IENlcnRpZmljYXRlIGhhcyBiZWVuIGlzc3VlZCBpbiBhY2NvcmRhbmNlIHdpdGgg SWRlblRydXN0J3MgVHJ1c3RJRCBDZXJ0aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQg aHR0cHM6Ly9zZWN1cmUuaWRlbnRydXN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5 L3RzL2luZGV4Lmh0bWwwSgYDVR0fBEMwQTA/oD2gO4Y5aHR0cDovL3ZhbGlkYXRp b24uaWRlbnRydXN0LmNvbS9jcmwvY29tbWVyY2lhbHJvb3RjYTEuY3JsMB0GA1Ud DgQWBBTKkXQjS6MtAipCj7Xo6ehDUPJvTDAdBgNVHSUEFjAUBggrBgEFBQcDAgYI KwYBBQUHAwQwDQYJKoZIhvcNAQELBQADggIBADz8N+h06HUlcT0Eb7TthF+nc9vG xe6xfTn8rUuLFf+wPcG8fcJ9oxJJrxZSjSvS/nvQ1t39Xq3Om7wDCj4c3cnp7pZk EJ95UaiuEy+ew7aBPznWU1eDgSnyhu2CGrgwJWZFkicXiPj0qs3CY+Ys1ciN6Y7l C4RvMF308iLQfXxdHNGx/5N8RKAI2xkdSaQSlFTjVRoErS1Ag8tyJ1hECG4rlEUr RAtRaBYGvzlAumgOP/lqYZoPAVbrX6K1juIOzNTPo/AwuD8Qzuy4boXOg9FEUUie dwiRHTKadxtikrBFoMi0Ta4j7M6MqhXG/5EdC4v7yc5qBfF/Cw/QLg+B4p+TJWbg dlGWs1TyeAe2RjQj/4dRNdgSQ0yS/mIFrlnGSBCzIvgTOQNkF9pgylc2SHL/P9MX Gvk+R8tKJ0tdCSKcTIMBHI0nDX0quUnkPGix4Xd7HPKjXR3IFp1v69hcZ0FoVa7o mrfm5eUK6sWtG0hyaVjeFBr+zDfXsRHOUa8jC1VihSd9ccx1a9PXxbtKseg+YA7U +WtZ0QErVCdvlKahPpGJpurfuiol2GLabW3hbHcKS8Icz0FyhqjAqWS7OThrTO0p IZIRGI5KGUGgRPA+cAD4K5YyADkNA1fNUDU7NLLRC2/EhO1wjR6RVBCjuVa2YNzS 3ba1jZFxolwzy1PQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID6TCCA2+gAwIBAgIQffy9nCl1ZOODwKYEKfi+vDAKBggqhkjOPQQDAzCBqjEL MAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3Jp dHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0 aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE5MDMwNjExMDE0NloXDTM0MDMw MjExMDE0NlowgZsxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHDAZBdGhlbnMxRDBCBgNV BAoMO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMg Q2VydC4gQXV0aG9yaXR5MTUwMwYDVQQDDCxIQVJJQ0EgUXVhbGlmaWVkIExlZ2Fs IEVudGl0aWVzIEVDQyBTdWJDQSBSMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABMwP WZFzDI+pZUc9FKUelQN54FLne9P/KD2Uiw93zTv7W/dpRixflicRW3/79jYqq7hZ DvyOcMUMFEpcSuyro3Wsn4s8ZH/BqR0ux4FBsyd8KBRiQkdvIN8c5DfDoWNm4aOC AWUwggFhMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUtCILgpkkAQ6c u+QO/b/7lyCTmSowcgYIKwYBBQUHAQEEZjBkMD8GCCsGAQUFBzAChjNodHRwOi8v cmVwby5oYXJpY2EuZ3IvY2VydHMvSGFyaWNhRUNDUm9vdENBMjAxNS5jcnQwIQYI KwYBBQUHMAGGFWh0dHA6Ly9vY3NwLmhhcmljYS5ncjARBgNVHSAECjAIMAYGBFUd IAAwKQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMMEkG A1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmx2MS5oYXJpY2EuZ3IvSGFyaWNhRUND Um9vdENBMjAxNS9jcmx2MS5kZXIuY3JsMB0GA1UdDgQWBBTIhm/oD9Z5DgQJ/adR ZhHVQ0P4WzAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwcinRdZrB S+JSoSy9xLzvv8hUpaaYmhB7OaF6IF6kc54ASQEdRBdSitLjEarqNyJeAjEAvHou rv4tkBCKpYeybSsPmpmGC8Gv7pi6P1IFM5XfXsyAy4T+Mm5y/3xHkhr257mn -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID7DCCA3GgAwIBAgIQK7nQzpC6ImIMsA42dCKAUDAKBggqhkjOPQQDAzCBqjEL MAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3Jp dHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0 aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE5MDMwNjExMDQzMFoXDTM0MDMw MjExMDQzMFowgZ0xCzAJBgNVBAYTAkdSMQ8wDQYDVQQHDAZBdGhlbnMxRDBCBgNV BAoMO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMg Q2VydC4gQXV0aG9yaXR5MTcwNQYDVQQDDC5IQVJJQ0EgUXVhbGlmaWVkIE5hdHVy YWwgRW50aXRpZXMgRUNDIFN1YkNBIFIyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE Fg//sm58S6EeZKRKk2HY2ACeqXAMWMTAaWK3ZGygLEI2f5Cd3bc2DctwNw4zZvfp ulXI5pr5vYXZmG8Trnh1Zv0FVtQej7FLpa8ejwwUtD+pcz+tGpYFQOF6Cg4tzisQ o4IBZTCCAWEwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBS0IguCmSQB Dpy75A79v/uXIJOZKjByBggrBgEFBQcBAQRmMGQwPwYIKwYBBQUHMAKGM2h0dHA6 Ly9yZXBvLmhhcmljYS5nci9jZXJ0cy9IYXJpY2FFQ0NSb290Q0EyMDE1LmNydDAh BggrBgEFBQcwAYYVaHR0cDovL29jc3AuaGFyaWNhLmdyMBEGA1UdIAQKMAgwBgYE VR0gADApBgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwww SQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2NybHYxLmhhcmljYS5nci9IYXJpY2FF Q0NSb290Q0EyMDE1L2NybHYxLmRlci5jcmwwHQYDVR0OBBYEFNeVKvrc6zs38YU4 q5uBt/tfj7q0MA4GA1UdDwEB/wQEAwIBhjAKBggqhkjOPQQDAwNpADBmAjEApd2p 9F0r/2KX4UA1NKsKkviSAPiFKk92BHZFCfPdrkvbnJzrCeHR+wTxe+/7qf7TAjEA 1O4X/Fm2qOMUfvdp0xkTtvDDsgA4J7dsF1GKZvZQuzAUsQsTBu6M02///Z5z1bp7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID/TCCA4SgAwIBAgIQba5AQvxu0MMb6pEaAGgJIjAKBggqhkjOPQQDAzCBqjEL MAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3Jp dHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0 aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE5MDMwNjExMDgzMloXDTM0MDMw MjExMDgzMlowgYkxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHDAZBdGhlbnMxRDBCBgNV BAoMO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMg Q2VydC4gQXV0aG9yaXR5MSMwIQYDVQQDDBpIQVJJQ0EgUy9NSU1FIEVDQyBTdWJD QSBSMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABLBx+MJqIwD14tLulD8/VDDqqGaj IkAKPuFLqb0gcC2dvsWS7HKZejzS98uH8lu7wEMpjatJntCH6iEVJ3/2VgOPT3MB kn/qOb7qsW7Da0QELTyQqpM18AwAQph5KLMwIaOCAYwwggGIMBIGA1UdEwEB/wQI MAYBAf8CAQAwHwYDVR0jBBgwFoAUtCILgpkkAQ6cu+QO/b/7lyCTmSowcgYIKwYB BQUHAQEEZjBkMD8GCCsGAQUFBzAChjNodHRwOi8vcmVwby5oYXJpY2EuZ3IvY2Vy dHMvSGFyaWNhRUNDUm9vdENBMjAxNS5jcnQwIQYIKwYBBQUHMAGGFWh0dHA6Ly9v Y3NwLmhhcmljYS5ncjBEBgNVHSAEPTA7MDkGBFUdIAAwMTAvBggrBgEFBQcCARYj aHR0cDovL3JlcG8uaGFyaWNhLmdyL2RvY3VtZW50cy9DUFMwHQYDVR0lBBYwFAYI KwYBBQUHAwIGCCsGAQUFBwMEMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmx2 MS5oYXJpY2EuZ3IvSGFyaWNhRUNDUm9vdENBMjAxNS9jcmx2MS5kZXIuY3JsMB0G A1UdDgQWBBSYzLMwlmjm+zljcWk7uCM6Tug1XTAOBgNVHQ8BAf8EBAMCAYYwCgYI KoZIzj0EAwMDZwAwZAIwMkZb1PKLOqHPqCxtkR8mTIyJRN1LX/48LTJlv3O3eaZy tq5VQH/uzOMbhOS3Yth+AjBtwUe7Pd52vwLjUtQZlb0ikFOO2Tb82WJd1i0uzE8b hD6zRB0Bi5ilRr961t5cLdk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxzCCA06gAwIBAgIQIgh8gcCEH5SGiQ21GCMGIDAKBggqhkjOPQQDAzCBqjEL MAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3Jp dHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0 aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE5MDMwNjExMTE0OFoXDTM0MDMw MjExMTE0OFowgYYxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHDAZBdGhlbnMxRDBCBgNV BAoMO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMg Q2VydC4gQXV0aG9yaXR5MSAwHgYDVQQDDBdIQVJJQ0EgU1NMIEVDQyBTdWJDQSBS MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABMG3VHSteQ2W8HiK+0VX3Bg2PVOaPc6q yl1H/MVnPC4ywcUe8nkv36Ks5Krw2jxAuphbTq9PB/KZzYDb81VC+VsbaD7j7GQP edXzObTsNZNRZCJaxQP5nPNL2fFTy/NW16OCAVkwggFVMBIGA1UdEwEB/wQIMAYB Af8CAQAwHwYDVR0jBBgwFoAUtCILgpkkAQ6cu+QO/b/7lyCTmSowcgYIKwYBBQUH AQEEZjBkMD8GCCsGAQUFBzAChjNodHRwOi8vcmVwby5oYXJpY2EuZ3IvY2VydHMv SGFyaWNhRUNDUm9vdENBMjAxNS5jcnQwIQYIKwYBBQUHMAGGFWh0dHA6Ly9vY3Nw LmhhcmljYS5ncjARBgNVHSAECjAIMAYGBFUdIAAwHQYDVR0lBBYwFAYIKwYBBQUH AwIGCCsGAQUFBwMBMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmx2MS5oYXJp Y2EuZ3IvSGFyaWNhRUNDUm9vdENBMjAxNS9jcmx2MS5kZXIuY3JsMB0GA1UdDgQW BBTi/nXgKf1vaUmjmlE+bM+FC+33qTAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0E AwMDZwAwZAIwZzLgz0pL0lLRIHaTlUIbGoRKJaQ8iAWMODPmLrCutMSQIj8pztbU fGlgOKW+vRBhAjAW/uTIjrv4UpBRSSdkEjMGdKgsI37RTZhJB74mcHwooxCZejZP oPZMA6waf3sgvwE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnDCCAyGgAwIBAgIQYlOBhXWzkj7ltEnfyvmmKjAKBggqhkjOPQQDAzB8MQsw CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAW BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzAeFw0xOTAzMDcxOTI4NDZaFw0yOTAz MDQxOTI4NDZaMIGEMQswCQYDVQQGEwJTQzEOMAwGA1UECAwFTWFow6kxETAPBgNV BAcMCFZpY3RvcmlhMSAwHgYDVQQKDBdJbnRlckNsb3VkIFZlbnR1cmVzIEluYzEw MC4GA1UEAwwnSW50ZXJDbG91ZCBDbGllbnQgQ2VydGlmaWNhdGUgQ0EgRUNDIFIz MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAErlQZYgv0U/8lMXg1NoYKHm2j7T/CkFg6 iqlp6yVzm94TCoFom9fAgBcEKXv5Vdag8VbZO9ul1TWxFIC6ZN79ewheh9m5oPIE gtPjENxmVs7ga+yrlMCARprQkX1UpBK/o4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB /wIBATAfBgNVHSMEGDAWgBSC0YVzMOc1BNOOApL75aTRxCHozTB4BggrBgEFBQcB AQRsMGowRgYIKwYBBQUHMAKGOmh0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5 L1NTTGNvbS1Sb290Q0EtRUNDLTM4NC1SMS5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6 Ly9vY3Nwcy5zc2wuY29tMBEGA1UdIAQKMAgwBgYEVR0gADApBgNVHSUEIjAgBggr BgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwwOwYDVR0fBDQwMjAwoC6gLIYq aHR0cDovL2NybHMuc3NsLmNvbS9zc2wuY29tLWVjYy1Sb290Q0EuY3JsMB0GA1Ud DgQWBBQhbQw9QT3QUZSPU+OAL1h7jISWRzAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZI zj0EAwMDaQAwZgIxAJ6Y9Emo6GxDO1g99eB5pIIO8QkCKROOJrQc7X4krd+/NOSc gtdnWhZPJpyEV+lGbwIxALwYtAsTf6bWAg3NDRLCyWMobW1UsZ1IcgPOqcY6kAro rrfCxspa1VYQHgS5FFp2OA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjDCCAxKgAwIBAgIQcetBW+6jOSy8e7tQnpyhZjAKBggqhkjOPQQDAzB8MQsw CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAW BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzAeFw0xOTAzMDcxOTMwMzdaFw0yOTAz MDQxOTMwMzdaMIGBMQswCQYDVQQGEwJTQzEOMAwGA1UECAwFTWFow6kxETAPBgNV BAcMCFZpY3RvcmlhMSAwHgYDVQQKDBdJbnRlckNsb3VkIFZlbnR1cmVzIEluYzEt MCsGA1UEAwwkSW50ZXJDbG91ZCBTU0wgQ2VydGlmaWNhdGUgQ0EgRUNDIFIyMHYw EAYHKoZIzj0CAQYFK4EEACIDYgAEZvf9klX/Oeqlb5IFPGzWBWfNfRHiXWlX8unY HZKiGx/X7tGQe4vsQw5vQLrX3C2HssvOOXbvabWue4quF6MN/wrMyu75KolhLU47 F1wg9+HHNqROEqO2g7Vdum1xN2LOo4IBUTCCAU0wEgYDVR0TAQH/BAgwBgEB/wIB ATAfBgNVHSMEGDAWgBSC0YVzMOc1BNOOApL75aTRxCHozTB4BggrBgEFBQcBAQRs MGowRgYIKwYBBQUHMAKGOmh0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NT TGNvbS1Sb290Q0EtRUNDLTM4NC1SMS5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6Ly9v Y3Nwcy5zc2wuY29tMBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAUBggrBgEF BQcDAgYIKwYBBQUHAwEwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybHMuc3Ns LmNvbS9zc2wuY29tLWVjYy1Sb290Q0EuY3JsMB0GA1UdDgQWBBRhP7oNOe9LgqOS Q8PEIWSa/v4PvTAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwakjo LqEHHWv9J1C2Qlku12DgD1hzocn0Hxnr+FotB1w3K/20v5ZVrsjBL3qs374MAjEA 9E2lHTxabo0uvFbO1iKfbsgd8OdqOG3FJLSePmMPfRFXudJi39J2hB3JPe3gFwYG -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkzCCAxqgAwIBAgIQJ6uF/gMxCfH9tQMtV30gODAKBggqhkjOPQQDAzB8MQsw CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAW BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzAeFw0xOTAzMDcxOTM0MDRaFw0zNDAz MDMxOTM0MDRaMH4xCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UE BwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxOjA4BgNVBAMMMVNTTC5jb20g Q2xpZW50IENlcnRpZmljYXRlIEludGVybWVkaWF0ZSBDQSBFQ0MgUjIwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAASef3xFPNLLdSgcAUk1vIep1NKM7aEZo8N5C2Efwn8+ m5wcI39ei9+9+6mMNqoElAVZojJZ519XV9rrwSesZNrgtVVNFMpPmIBPfk5ACQwi OugouQ7UkRAThBQjfo0vgGyjggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB8G A1UdIwQYMBaAFILRhXMw5zUE044CkvvlpNHEIejNMHgGCCsGAQUFBwEBBGwwajBG BggrBgEFBQcwAoY6aHR0cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29t LVJvb3RDQS1FQ0MtMzg0LVIxLmNydDAgBggrBgEFBQcwAYYUaHR0cDovL29jc3Bz LnNzbC5jb20wEQYDVR0gBAowCDAGBgRVHSAAMCkGA1UdJQQiMCAGCCsGAQUFBwMC BggrBgEFBQcDBAYKKwYBBAGCNwoDDDA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8v Y3Jscy5zc2wuY29tL3NzbC5jb20tZWNjLVJvb3RDQS5jcmwwHQYDVR0OBBYEFHco NRRSZVUP2CFnn6aiSjWRgSVUMA4GA1UdDwEB/wQEAwIBhjAKBggqhkjOPQQDAwNn ADBkAjBP+Mnn2uq5z3DmuZFIewdGXDNHQnFdbDc0C1mFtd+HMgaq/HhTjWmbVOyL 7+hL6PoCMGmfO1R5xV9sCpAU8JZekqD/2UwDW8QE5LYnF0/FnVzHKm21Q2TNM5FE dXjc6hcemQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhTCCAwqgAwIBAgIQPH075n+j7W0w69DwtN+DnDAKBggqhkjOPQQDAzB/MQsw CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAW BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNvbSBFViBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzAeFw0xOTAzMDcxOTM5MzVaFw0z NDAzMDMxOTM5MzVaMHIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G A1UEBwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxLjAsBgNVBAMMJVNTTC5j b20gRVYgU1NMIEludGVybWVkaWF0ZSBDQSBFQ0MgUjIwdjAQBgcqhkjOPQIBBgUr gQQAIgNiAAT1t4leMOvsxnX7aOOmLIoNVAm6ml1dgCWh1gA0A1jMIeOm3cI6vRUs j1mNq+Fi+gFmG4N/fJm8jGgakxhO7+rkDUE1fFF74YMMBmZ0ku1AeRTXgnLmSWCD C3nmK1X8MI+jggFWMIIBUjASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaA FFvKXuXe0oGqzagtZFG22XKbl+ZPMHsGCCsGAQUFBwEBBG8wbTBJBggrBgEFBQcw AoY9aHR0cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29tLVJvb3RDQS1F Vi1FQ0MtMzg0LVIxLmNydDAgBggrBgEFBQcwAYYUaHR0cDovL29jc3BzLnNzbC5j b20wEQYDVR0gBAowCDAGBgRVHSAAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Jscy5zc2wuY29tL3NzbC5j b20tRVZlY2MtUm9vdENBLmNybDAdBgNVHQ4EFgQUhO74eT4IZHZIZDn1sb+LAl4L vCcwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCx1zLVSyEBp5fv Db5CaW0hZG1M8rXEn0o8bVvThDQ3oGhDQqn30letMq7wqm8Wlw0CMQCC9kSf1oa0 nvHk8EwWQqToAbE4Em09b9qsReLgy0Bz6OldYKedC1Ocuy5/nktf4aI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDejCCAv+gAwIBAgIQHNcSEt4VENkSgtozEEoQLzAKBggqhkjOPQQDAzB8MQsw CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAW BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzAeFw0xOTAzMDcxOTQyNDJaFw0zNDAz MDMxOTQyNDJaMG8xCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UE BwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxKzApBgNVBAMMIlNTTC5jb20g U1NMIEludGVybWVkaWF0ZSBDQSBFQ0MgUjIwdjAQBgcqhkjOPQIBBgUrgQQAIgNi AASEOWn30uEYKDLFu4sCjFQ1VupFaeMtQjqVWyWSA7+KFljnsVaFQ2hgs4cQk1f/ RQ2INSwdVCYU0i5qsbom20rigUhDh9dM/r6bEZ75eFE899kSCI14xqThYVLPdLEl +dyjggFRMIIBTTASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFILRhXMw 5zUE044CkvvlpNHEIejNMHgGCCsGAQUFBwEBBGwwajBGBggrBgEFBQcwAoY6aHR0 cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29tLVJvb3RDQS1FQ0MtMzg0 LVIxLmNydDAgBggrBgEFBQcwAYYUaHR0cDovL29jc3BzLnNzbC5jb20wEQYDVR0g BAowCDAGBgRVHSAAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATA7BgNV HR8ENDAyMDCgLqAshipodHRwOi8vY3Jscy5zc2wuY29tL3NzbC5jb20tZWNjLVJv b3RDQS5jcmwwHQYDVR0OBBYEFA10Zgpen+Is7NXCXSUEf3Uyuv99MA4GA1UdDwEB /wQEAwIBhjAKBggqhkjOPQQDAwNpADBmAjEAxYt6Ylk/N8Fch/3fgKYKwI5A011Q MKW0h3F9JW/NX/F7oYtWrxljheH8n2BrkDybAjEAlCxkLE0vQTYcFzrR24oogyw6 VkgTm92+jiqJTO5SSA9QUa092S5cTKiHkH2cOM6m -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgTCCBGmgAwIBAgIQOXJEOvkit1HX02wQ3TE1lTANBgkqhkiG9w0BAQwFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDMxMjAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5 MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBO ZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgBJlFzYOw9sI s9CsVw127c0n00ytUINh4qogTQktZAnczomfzD2p7PbPwdzx07HWezcoEStH2jnG vDoZtF+mvX2do2NCtnbyqTsrkfjib9DsFiCQCT7i6HTJGLSR1GJk23+jBvGIGGqQ Ijy8/hPwhxR79uQfjtTkUcYRZ0YIUcuGFFQ/vDP+fmyc/xadGL1RjjWmp2bIcmfb IWax1Jt4A8BQOujM8Ny8nkz+rwWWNR9XWrf/zvk9tyy29lTdyOcSOk2uTIq3XJq0 tyA9yn8iNK5+O2hmAUTnAU5GU5szYPeUvlM3kHND8zLDU+/bqv50TmnHa4xgk97E xwzf4TKuzJM7UXiVZ4vuPVb+DNBpDxsP8yUmazNt925H+nND5X4OpWaxKXwyhGNV icQNwZNUMBkTrNN9N6frXTpsNVzbQdcS2qlJC9/YgIoJk2KOtWbPJYjNhLixP6Q5 D9kCnusSTJV882sFqV4Wg8y4Z+LoE53MW4LTTLPtW//e5XOsIzstAL81VXQJSdhJ WBp/kjbmUZIO8yZ9HE0XvMnsQybQv0FfQKlERPSZ51eHnlAfV1SoPv10Yy+xUGUJ 5lhCLkMaTLTwJUdZ+gQek9QmRkpQgbLevni3/GcV4clXhB4PY9bpYrrWX1Uu6lzG KAgEJTm4Diup8kyXHAc/DVL17e8vgg8CAwEAAaOB8jCB7zAfBgNVHSMEGDAWgBSg EQojPpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rID ZsswDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAG BgRVHSAAMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29t L0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggr BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUA A4IBAQAYh1HcdCE9nIrgJ7cz0C7M7PDmy14R3iJvm3WOnnL+5Nb+qh+cli3vA0p+ rvSNb3I8QzvAP+u431yqqcau8vzY7qN7Q/aGNnwU4M309z/+3ri0ivCRlv79Q2R+ /czSAaF9ffgZGclCKxO/WIu6pKJmBHaIkU4MiRTOok3JMrO66BQavHHxW/BBC5gA CiIDEOUMsfnNkjcZ7Tvx5Dq2+UUTJnWvu6rvP3t3O9LEApE9GQDTF1w52z97GA1F zZOFli9d31kWTz9RvdVFGD/tSo7oBmF0Ixa1DVBzJ0RHfxBdiSprhTEUxOipakyA vGp4z7h/jnZymQyd/teRCBaho1+V -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID0zCCArugAwIBAgIQVmcdBOpPmUxvEIFHWdJ1lDANBgkqhkiG9w0BAQwFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDMxMjAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5 MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBO ZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEGqxUWqn5aCPnetUkb1PGWthL q8bVttHmc3Gu3ZzWDGH926CJA7gFFOxXzu5dP+Ihs8731Ip54KODfi2X0GHE8Znc JZFjq38wo7Rw4sehM5zzvy5cU7Ffs30yf4o043l5o4HyMIHvMB8GA1UdIwQYMBaA FKARCiM+lvEH7OKvKe+CpX/QMKS0MB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1 xmNjmjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zARBgNVHSAECjAI MAYGBFUdIAAwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5j b20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQG CCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEM BQADggEBABns652JLCALBIAdGN5CmXKZFjK9Dpx1WywV4ilAbe7/ctvbq5AfjJXy ij0IckKJUAfiORVsAYfZFhr1wHUrxeZWEQff2Ji8fJ8ZOd+LygBkc7xGEJuTI42+ FsMuCIKchjN0djsoTI0DQoWz4rIjQtUfenVqGtF8qmchxDM6OW1TyaLtYiKou+JV bJlsQ2uRl9EMC5MCHdK8aXdJ5htN978UeAOwproLtOGFfy/cQjutdAFI3tZs4RmY CV4Ks2dH/hzg1cEo70qLRDEmBDeNiXQ2Lu+lIg+DdEmSx/cQwgwp+7e9un/jX9Wf 8qn0dNW44bOwgeThpWOjzOoEeJBuv/c= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHDTCCBPWgAwIBAgIQQNuabltugn1IBLpOCqC9DzANBgkqhkiG9w0BAQsFADCB pjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVu aWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRo b3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJ bnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTkwMzE0MTMyNjUzWhcNMzQwMzEw MTMyNjUzWjCBhjELMAkGA1UEBhMCR1IxDzANBgNVBAcMBkF0aGVuczFEMEIGA1UE Cgw7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD ZXJ0LiBBdXRob3JpdHkxIDAeBgNVBAMMF0hBUklDQSBTU0wgUlNBIFN1YkNBIFIz MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAiNlhfmU+e8wXjAFYqW7t MYNrrX809EIbHl3XF52YmKRnTjK41nvNHeQQfXFMzNayHpmusY0Ntph39i+P/HMC WGd8Shznp+gGqyejxTceEkG4KLkDsUUOyywh4V4QFW7aObwwesv7BDo+rJG5xBK/ SrTtO1XbIUD3EompU9tST0qqZe68QmhyozTNp09K1vhBdfGXbnSayuVXMCWPVDD3 flmnk2c9u01NWQXNpCPlmoUfWNFLVh5byoNA+VvydShI9lioCS/jivQldvpO1tFS P2k0owp7XLfpiySk3JRGm4dLBZ292U+RDhy+bAYxTDerHYzcb9XVFhTzfq2FhAZJ LlSQTmP2voX3Ac974VOKIk2INSIMdJC7NXS/rXzle4Vkvg7VsLIom34ZX0rIlQqc tcjsBt4yXzrNxZ3NtAVK/9+AJC5QEGOjf5nJKRXSZYqY4q+Tiv1kR20Y7lv5ufg0 3n2CivIsXd3lkkDg/XQjhIllqrMDcZBQRaVAEbkGnVWGEWaH6OYy6C+g6t9uOe5B BHpPM8MMIVRUiuncUvQpiPeYEJ007gijp0UbVY0MLE9V0uSaNo11W3mn9KxNqA+w /6de2mmnHz+hoxpSwnVliC9Y1EcDXA4ziC5dgVd/gByQEpiI13PCJBx1BL3hUpGv aJE0VHF+V/aRTQ26/T9bHykCAwEAAaOCAVMwggFPMBIGA1UdEwEB/wQIMAYBAf8C AQAwHwYDVR0jBBgwFoAUcRVnyMjJvXVdctA4GGqd83EkVAswbwYIKwYBBQUHAQEE YzBhMDwGCCsGAQUFBzAChjBodHRwOi8vcmVwby5oYXJpY2EuZ3IvY2VydHMvSGFy aWNhUm9vdENBMjAxNS5jcnQwIQYIKwYBBQUHMAGGFWh0dHA6Ly9vY3NwLmhhcmlj YS5ncjARBgNVHSAECjAIMAYGBFUdIAAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG AQUFBwMBMEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly9jcmx2MS5oYXJpY2EuZ3Iv SGFyaWNhUm9vdENBMjAxNS9jcmx2MS5kZXIuY3JsMB0GA1UdDgQWBBQ9aYUZUX+V z1FeOJLIw4DSH+IgWDAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIB AIdmkaM3cucTuq+LBKsi797TuqKXICXkVDvTqT7r6QtdcHT6BQbEHKrULV9z/Xeh E/awmcbakoJ5p7pN3iToCN/+IbRfWjL2JrliAMOZoEQOIQcO9RQ1//dW4tB2IK5X 1tR23KjnF7CgeoiThAT8GfZi9cQnfIneL5DZW6J0psSIPS3yqThzEWNvoybQFr7a wHrqFPjjPUo7U6aqGfzKy+3SQrDO0hQ4Ia2CrFf5AcJNXLFeFfZaZF0igcBZtfHD 2Om2No34t8O/ygs1bMMUQvzEVPwFgWeN6+Vt5o9pZ8pnAmeIdQoWmLTWSlTJ16vA wDGVprvwnTfv5HmOJ9LCnuqwvcWYY9vBeoeuQeUXBTHXLlETNNNHKMVf2WrnE+WE P9d00rb6D3q+ELqV/XoK5Sf87vD5rlDztZJ0a9JrFQPQeNeIiVeYVgmzL6jgGRMw NWaoNmSLOZyNBUQrtmhAt9fOr4UvU9UGjlEF4n2AMYkiOer6F6nUpY6Zq2eNzm3m r2og47z45XYCY6TEnjtNHInizr1NtgECMqrEOdgu1mcnA8TRkmR3U/C/XWzBNWJV xAm2648LewDDCUJUOXgeLgObaxwbv3koQf2oU+bGs9Pt9vig/B5RulWfGx6ow/SZ 3KUDnZzbCdLzg/83frHflBXYWj09nAp6IdKGcaG9E5Nj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHKjCCBRKgAwIBAgIQJ2tclvFbijeMbnnDqQHr7jANBgkqhkiG9w0BAQsFADCB pjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVu aWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRo b3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJ bnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTkwMzE0MTM0NjUxWhcNMzQwMzEw MTM0NjUxWjCBlzELMAkGA1UEBhMCR1IxDzANBgNVBAcMBkF0aGVuczFEMEIGA1UE Cgw7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD ZXJ0LiBBdXRob3JpdHkxMTAvBgNVBAMMKEhBUklDQSBRdWFsaWZpZWQgTGVnYWwg RW50aXRpZXMgU3ViQ0EgUjMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQC3xHnml3k2XafPrjLX5Dscb/Q0g8RpDakdkbA8jc9+qfVRHsEjuAdXJYOkl3sF BQXMrH6B/p5jprz1qqcblAK1AHJRTdW9r4cuf0zzZFTP0UKG9ffUgkUQyfQumsMy tCVavF71TGKx0Af+e58lFU+Ym8Ko8NRT2FzkOzeL4g72hbvBHksSUQrKzg710atI psXjQihNPtCpKdcmKzQcWGLEDu5Z+53RyLci5apmt1cUUSPiCWP8cjpJzt6gdUyB bW1e4yee88vfzno+7Iir5wBF/q+Z97COiQAJMUllkPlOhiqRXSW0CwhdbasSxBaF 0pL0BPOZzbU3oEQplqD5fdHgkttfLQj5qq/kgErndsWOgZqqdckR2YFvALFMqpqy RvR1sX/4UNb9y2h8Eh1xwp8F/OudI+/zX7QDp+rHh2OjqkL4NWPJb3OCFDZ4EXFR xerEdZIxI4lOGLHneBUEYv7w168Vat3qug7CPghxGSGZGV4RD6m9xQNNgKFoELIa StUexQGaaAzTEe/Sd5zQ6pHhQQl83h512CKZApZOcHUnkIUif3/CvaUWO6K9Lt23 Nl3D3FF1FpffhMebzcKBPiXornmU/XKDXzZFqhau4xyVYrMtjRBXwkw9yGof+py/ p+qSsY45MekdrlZxKuSFUYcXXNs6iEhRjvw/3seoSc8CxwIDAQABo4IBXzCCAVsw EgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRxFWfIyMm9dV1y0DgYap3z cSRUCzBvBggrBgEFBQcBAQRjMGEwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yZXBvLmhh cmljYS5nci9jZXJ0cy9IYXJpY2FSb290Q0EyMDE1LmNydDAhBggrBgEFBQcwAYYV aHR0cDovL29jc3AuaGFyaWNhLmdyMBEGA1UdIAQKMAgwBgYEVR0gADApBgNVHSUE IjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwwRgYDVR0fBD8wPTA7 oDmgN4Y1aHR0cDovL2NybHYxLmhhcmljYS5nci9IYXJpY2FSb290Q0EyMDE1L2Ny bHYxLmRlci5jcmwwHQYDVR0OBBYEFPXcw7QFx/jnYMAAdfAKmotsDKHJMA4GA1Ud DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAAb5bIgaB78Rr8EI2NE4uZrzn eE/4F9q3MU6pcJQI0GVkm8+JZlFIYCwBKajTI91+mHiyY4JekCRNQUu1pMb2NieS QArIttnFzU1ji5p2kjTPlt8dEz/X0TwizHNN4CXjAzGOyTmsb2fz6t80ZVxVJeup HFiw4DC9Z+xVazKDlMbv3A1lKwZOi9sjHTGSuKdTWsMd5rfVmBAOADW5y8fEjHwS aVh0K/cfMpVtqS8T80GazCRgkyV6FsrjBpy6ELhvNUc0nBJ/Y93c5E+7CsXl+NwC K/rESoTfA9JgTKzQ54qZeU/LoEBV2xrVX/wKlv6fPfGZl3W+EhlysYkpHkVJmw7Q gJIsml6nJePfScPdAYsdcIHJp2taYHivUPOiTubqUvAFUN1PJgT0hdcRUYK+fzAi UlhLJnPgh5eTzZr6+aiHM8owzKp0refhpmZUVArFLZKmlP7/sGyyNh2KAQ3vL1e3 buQBtvfDsscXtHE+UX209Aps44QM6B+EyD9UHlovW/4l85I2UGdgtY+sHPP+f9l0 F2XVoB12t0fx7QIDtllMT22pAH8QGoXm2maUBGqNBluiG4uemh0RiUce2x9Mw7c3 4695TcL0/rkNVJ6x2mo51OqJcNCincx+8cZFojU7bD8pClma/B60yeJ1TqTmsdhj 9RvodwtkOyZEMClE+1A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHLDCCBRSgAwIBAgIQf86qjaECbfp3FNE/3hX4+jANBgkqhkiG9w0BAQsFADCB pjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVu aWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRo b3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJ bnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTkwMzE0MTM1MTE1WhcNMzQwMzEw MTM1MTE1WjCBmTELMAkGA1UEBhMCR1IxDzANBgNVBAcMBkF0aGVuczFEMEIGA1UE Cgw7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD ZXJ0LiBBdXRob3JpdHkxMzAxBgNVBAMMKkhBUklDQSBRdWFsaWZpZWQgTmF0dXJh bCBFbnRpdGllcyBTdWJDQSBSMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBAIILSyhk5t2dqyZHZTRQPHXmyaoUsDaiVfqqWzc7uT0DPT6kVPQ4uryaBQpN UhyD3sJWqK5GBVwFbzXamm2TjufYWTukGDAKtR+0jlJnOmD//0nfSc8M5fYg7WQ9 UNeeau4BjgS6m604zevqD2DCky8Wohx++hW9WR8OuOV9oF9KieUAGJXNjrxMarc5 F61Ic/zg6xWBfsJfyx4YzzjU/y/xV6nuljWFxUuyZ41xo/eKgyF5c8aXPDA3iHnP 0oE6EB8W80u+kx15a7Xu7Mp+Tdsc8TEYUKZifsLogBd+TUY20Ou2KUgqIDLLrC7E 4f6O4y3kxAR6FNZH6RZhjr8QS0WWoVq+41rR6XoHFljmZoG7Yxmf0UHJM4Ibl2qZ SSQSVr7lcf/yoxDan2YHz2bTtCNtkO5IThb2aug2UNVYC1mtZitL+gv58VCCNQzk HhwJSWCLk7W/3pF7ewDIKaWgMUn8VgFQ5FdkwAaLXGTp5LB6AqMgs/WSTITi4znf rRd1WaRrnDFGKNQIZcLbZw0VR2gxkE2d9NrM+Cg5lMfT5CFeLdlnbWNcgKJ4ZFWT +SV3SDdfHIfHp2RCr5UlwVe1PXy0VOm1FUZYUH/ZtZ3i8sumT/bg/75rSSV/s2xS HnCZccrI4rFRHBxqS5vR7WddXy1AxSCm3FYXPlvfEi8hAm3jAgMBAAGjggFfMIIB WzASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFHEVZ8jIyb11XXLQOBhq nfNxJFQLMG8GCCsGAQUFBwEBBGMwYTA8BggrBgEFBQcwAoYwaHR0cDovL3JlcG8u aGFyaWNhLmdyL2NlcnRzL0hhcmljYVJvb3RDQTIwMTUuY3J0MCEGCCsGAQUFBzAB hhVodHRwOi8vb2NzcC5oYXJpY2EuZ3IwEQYDVR0gBAowCDAGBgRVHSAAMCkGA1Ud JQQiMCAGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDDDBGBgNVHR8EPzA9 MDugOaA3hjVodHRwOi8vY3JsdjEuaGFyaWNhLmdyL0hhcmljYVJvb3RDQTIwMTUv Y3JsdjEuZGVyLmNybDAdBgNVHQ4EFgQUDdDvrDVq/UnU3xC/ZfhZmH5lnqgwDgYD VR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQAtgHRMU+hBTyZNI4X1cn/R hRi7iTZeplU/mixtbiJf9LPOBe46pl0NeUhXUpGNdDHquLdYGHE91DpdWfS6wA1X L+qIYYlW+ROdRETZq2qc2bKk+CHpzSzb1piqPdoNGO1jo/ONi2i2UCCRClbc6umZ dqAqMfgPQb46I1iS8S1UzYxW1c02GWZuPbOC+0sl6LiKBWlhMW59wN+QTx6YFMnt 1CQ0Q6aEWaenxlDGOK+rJJkqvdVCLi8e0sOM+jbsynTu7lFXKTRiWyPauOZieoHz YY0lmL2x6f7WAe8MTZ/ltTcXWtZWaiSQid0aPlq+bR1q55Mz1vV3UyJ9D1xbcb4a EQgE3VnOZnfAv2hBdBqJjJr7MBgyGa1j/X+OqMgkf+TCnFa1n2D3Y0zMZnCfyxfu PGTPjuIzjbOUqKXsTLjTxzZbvpDjbeUBOngWftLeqbtY1wuntbehGKKCeU7yTC4L P4dLQ4ppZPoUXNtqVp0NEC/ntwh3DxrUdlJHou4vjQKFc0gsNJ4BryazK4x66qNh sxDab6YxogddwTyJAujNf3FTY0AewY18aGZTokKMgw47WVTT1h9KrM5oMtmTPr56 DUHYAzgxLyZ/I2YBNp17yFcjxwEbTYWZ1xg+a952nSPbJoDHCYr+cmi9orfDAuhv PfrsnwC+DLuvnR3RIwfHVQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHQzCCBSugAwIBAgIQQlgke6pLBzMD51YBu8IQHzANBgkqhkiG9w0BAQsFADCB pjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVu aWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRo b3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJ bnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTkwMzE0MTQwMTI4WhcNMzQwMzEw MTQwMTI4WjCBiTELMAkGA1UEBhMCR1IxDzANBgNVBAcMBkF0aGVuczFEMEIGA1UE Cgw7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD ZXJ0LiBBdXRob3JpdHkxIzAhBgNVBAMMGkhBUklDQSBTL01JTUUgUlNBIFN1YkNB IFIzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAm4ST/yTO/5kqsfvL BiDTZnolmnYFHPnZA9677nuXKgXVqNxCQNvYIaXTzyVaHtyFnan1uhcnxSPNVRF5 enwvwGx9AOp+tshQkSINCS/WjI8px+QKRoMx3bt9gOFAMC8pUuh1CXvqJ1pJ4rFD xsNu3z40Z+vKfPuyCP2JzUYFmj3QTLNwFS/JOYeVUaz8l7sJH9qbR2tNTmlajL8a WRirZxDkPnGVHUbOq/qQiHPtM5jvsep0KTSomBb/PNQ1ozaq6V/jmXzl9yRJPonT eTnj41C8b3qGtpF2qq5ICTMXnAMT5Y0oykGd4i1hotmCYpXOPM9Jo+UO3VNfqleY mIVGkJf3XbNS57ge0Lll0RJ0C77KJwz9D5shr7MpkR5V7WlVfvzDx4FOd17bqwZc h93beLcHC6YGN3CcCd70tAVay1Ec3wRusR3Ie83SL2TRsx9w3E5MmxOyvG6uMOth Yi1PJKW2F7+aLj2kjbscJaWv3EkVJfXd1/BKYqtXugM//yqEA/S7KPdcMYs1Yekn Zijv6tvxLi2rNb+6aNNDaiDEsTxFS8Rm1eSPRyGNVK6vuRNTzPK825nDhimxyw9A Y+i4C9Pp7/QpnXfxC86gGlnPtruXAOQzpFyy0I4lbdvVNN6NTLDwrB0K4zwzj6Cp ABdyIKTiNtbD1z78ltpKJtx0DxcCAwEAAaOCAYYwggGCMBIGA1UdEwEB/wQIMAYB Af8CAQAwHwYDVR0jBBgwFoAUcRVnyMjJvXVdctA4GGqd83EkVAswbwYIKwYBBQUH AQEEYzBhMDwGCCsGAQUFBzAChjBodHRwOi8vcmVwby5oYXJpY2EuZ3IvY2VydHMv SGFyaWNhUm9vdENBMjAxNS5jcnQwIQYIKwYBBQUHMAGGFWh0dHA6Ly9vY3NwLmhh cmljYS5ncjBEBgNVHSAEPTA7MDkGBFUdIAAwMTAvBggrBgEFBQcCARYjaHR0cDov L3JlcG8uaGFyaWNhLmdyL2RvY3VtZW50cy9DUFMwHQYDVR0lBBYwFAYIKwYBBQUH AwIGCCsGAQUFBwMEMEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly9jcmx2MS5oYXJp Y2EuZ3IvSGFyaWNhUm9vdENBMjAxNS9jcmx2MS5kZXIuY3JsMB0GA1UdDgQWBBQx eqJ3TmpVqMS6iq1NGZwaiA1bMTAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL BQADggIBAFoyF1VqFJ4dVXk/5cFXr3PmFRI6ICIcvh9RP/+c7tlzqB0y+52kADfN elT9d9uaHYwnt0JmEAkrY+5Hf0t3An2zDk8eMyxg6EXgnsUrBoMTTOXXVVBk71fP CQWt8duQ5CKbrSPaRAKeSUeF5IL1+ow4EabTUKIEeVkhf7iL7F8cqusFjQupRQDn W2a5Jjo2E9nTTY1hC0I1v6PB805YNe9JbFtCgpH7qtMJ6Xy19bl0sJr7kec04ciB mhsn8eVCz68clmkBLQzIYLNUd+4xS602t4SEEBXhioBlZBygD/nkMSZ475w549Cg vnvmGNXaddEwwtC/GncEH7jwuQTQ+HgPtpXCSVAcDcdcQxqpjwGV1NjfAVD26vsm ULep1ce1fvLAesb/3BEebOKgsC2riifrbF6eSNGY1Z1k6TwT5FijX4U7in46Os9/ S5OWkZMjBNJXR46d5I9mGXGX6VIDjQ0hiDxm8NCd5L0TcwuLLPqbITPkVYz2SiYh qeT9Q/w1U+RsSwaz9nu3DNJjOqmWEUqpN9rMskRa7Q+C6hzEqNbrjpdsNh5Y7azf mSuMrOY9VM9LVA/0hK8P+XsMCD5hWwy7HbcFOWEirTO84TttOn9fRZZO6I/sg1bx C6CVt31cmgwDLJCjtVAARyMbfyqWDH6TMm6IeqBQ/lYLeSW4yBoS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpzCCA4+gAwIBAgIQYrTD66U5GBd/EnqDe1dPljANBgkqhkiG9w0BAQsFADBE MQswCQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxHzAdBgNVBAMMFkFm ZmlybVRydXN0IENvbW1lcmNpYWwwHhcNMTkwMzIxMjAyMTM3WhcNMzAxMjAyMDQw MDAwWjCBgjELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYD VQQLEyJTZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTAwLgYDVQQD EydBZmZpcm1UcnVzdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBEVjEwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZLT2Didbswle+ODgIPHb/DXnMZDfd pOotUIbYHMhW1HiAh7GkD1MgrTI1AzP6lj6DMTxiVUi4N8OK9EI4XZdMi3sWq5Op kBoV49lmnuSF/Li5dnyas2ItuBFmzqiEkxj43Fas627qIWPwX4MHyDN814K54pmU /ohAglEH665b+1ArDz1vxEEpFER6I8L/fTXYBGs/wCJIV5XnBKXjkOl96LR/RDVq k+kV6c9E4/Ths4IVYeLizFuke7fNoiZyvWQ+H/tUIZWGoyqZ2ZCIXpPKNI6kt5oF LJXfHcu7lDQM5UxjVlzVDbJFeTD5LHHD7UwlRECJY8GC39dQ1wk1JOKFAgMBAAGj ggFUMIIBUDA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3Nw LmFmZmlybXRydXN0LmNvbTAdBgNVHQ4EFgQUM996PgJ5luu2DMBj+nW/kiLNkfow EgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSdk8ZTi17Krz+fHg/lmZW8 JPaUjzBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93 d3cuYWZmaXJtdHJ1c3QuY29tL3JlcG9zaXRvcnkwSQYDVR0fBEIwQDA+oDygOoY4 aHR0cDovL2NybC5hZmZpcm10cnVzdC5jb20vY3JsL0FmZmlybVRydXN0Q29tbWVy Y2lhbC5jcmwwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr BgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAkXyr+SWj5byHGkFMF1D3gLvqjvrU 3U89UbUdSYv6G9WHD78PLWgb3GgJW/BFmDWtcRagIY/WgxnUPHb5gyq7/vdNYnVX L6J175VB03ub4pcz//DSn/9gWiFAWIKee7H+j5GBvTw5X9xR1qfQc84bcYTVA+ox aRpSe1Gcl9QHjXmThXDTyg8FvNK7ewjQ1quE8aeLuU9Coq2Wn/wHLg8YmsHf2/Hm Fo2b8Lus/aw4UImSFhwAO1KqaNKiLNkYQRCGOHrmPvZpx3XstTXCuo02iaB+u2bM PXYBpSAzqDc2jyfie+p3i2weJIUpbjLPlVPr6BVAAch/mrhjXcfdIzs8Yw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpzCCA4+gAwIBAgIQU/amEQkuUo7ZY/GRSVMiBDANBgkqhkiG9w0BAQsFADBE MQswCQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxHzAdBgNVBAMMFkFm ZmlybVRydXN0IENvbW1lcmNpYWwwHhcNMTkwMzIxMjAyNTMyWhcNMzAxMjAyMDQw MDAwWjCBgjELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYD VQQLEyJTZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTAwLgYDVQQD EydBZmZpcm1UcnVzdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBPVjEwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCvco7Deeb/p8vGva+AiXD+Y+Cu0Hi A4apJ4GQNNbLSFkQ9PdoNvjFlCPH9gIVJfc28Jrt871d4IPhrxowey3qa+HPHMmN oiwAcjXxissCBq7NrZgkSXRMhia6Fu3NvFgFqZNl7zb1GTpCSilYiHIE/W/tHtbc ln1bnLIk7AMy2ZS2EgsmJyU7yVbmEo8Y20f3A3WDIcZVzjOQGJb8dYxhcBs1MWwD eohavBhMCFi2IDXfBZjbD2B6Biq7+jZJtPo06yyDsC2feL5/el7z1D6gTUcoCBlT 5Y6zPnsBB90V1vVHVTeopdnhP4uccqVln40IgAAKsa35cQstxqZhLNhJAgMBAAGj ggFUMIIBUDA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3Nw LmFmZmlybXRydXN0LmNvbTAdBgNVHQ4EFgQU/mDDDaSinSFPenhMYsXbFPw5eMQw EgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSdk8ZTi17Krz+fHg/lmZW8 JPaUjzBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93 d3cuYWZmaXJtdHJ1c3QuY29tL3JlcG9zaXRvcnkwSQYDVR0fBEIwQDA+oDygOoY4 aHR0cDovL2NybC5hZmZpcm10cnVzdC5jb20vY3JsL0FmZmlybVRydXN0Q29tbWVy Y2lhbC5jcmwwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr BgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAOk54qHPMeJwOtPt/KP0vGZ1Kx/G7 zkfvY9fRw+1ATGeLyuBvDPFDGC7ZHXegy9cH5txHJpzYt2Ns5l90TwqKSLDcgWHt fegtWnzYROHl7w3llLrMSy+MjhjUlH7hTTRrk6Vd0Hrcrz4oB9ebHmG/UFFWoD4h sg7KAgqTjtlS1Vs3ZWCnUaLAhOcf6J56IRo1AGTfOh/D8zodg5QHthZi+Ucl4kwD 8zzUdXdzcYktuVws/5ZNp1Nv2FvSmmNKnpWFfkJ1OTVGMKnrwU/F8KsE7thIUfz1 x/BL/kNRp7PMiXRKi4N7KEiiQPled9EM3FeF7O0q2fbn5S4Z5yduCEYrqg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqDCCA5CgAwIBAgIQFylVHtaOf7Ht9XMA811/1TANBgkqhkiG9w0BAQsFADBE MQswCQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxHzAdBgNVBAMMFkFm ZmlybVRydXN0IENvbW1lcmNpYWwwHhcNMTkwMzIxMjAyNzU0WhcNMzAxMjAyMDQw MDAwWjCBgzELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYD VQQLEyJTZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTEwLwYDVQQD EyhBZmZpcm1UcnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0gRVYxMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuPBMIa9VuXJGAw0MHvieGciPFA11 b9T49YJ7T+zVpoMMQO+ueUKVHb2l26oeCiwIhXMQ5LquOVcx+rofouzcKXY3wKDZ zHIOnAkU+23Ucn/3dRH7aHJULsBufZq+NvwgYSgJJEDKfqvIV/c5HiRyZ2H+nAI5 10Q2xC0UxgSBsufccQ+Fwkg6BAGDlTXrvi8wi75UaGue6jv/qcKLybeVUrgqKE64 d9oa9PG5/g89QwSdsIQEdVSFzFvFpOG9YhJbJ177Zg6DGCxU0lWwFrVpyH/2vnXl jhMQScn8UxzCJdDg3EDqjgaV0JH2yoLug+QVYgURPu5BEb5ut9vAdP7cLwIDAQAB o4IBVDCCAVAwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vb2Nz cC5hZmZpcm10cnVzdC5jb20wHQYDVR0OBBYEFNvvZTcL5UfLNdGQHwPBvIjHp+qA MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUnZPGU4teyq8/nx4P5ZmV vCT2lI8wRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v d3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MEkGA1UdHwRCMEAwPqA8oDqG OGh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1UcnVzdENvbW1l cmNpYWwuY3JsMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAATH11fMrINGmQGQqQW0ATteVnUG LrmRSN2OlmRm+dkUwKXhcQQEfYYlEggPqgvxSUpw13fXSOqVHqAcj3BIqF957kh+ m3DmC0RX9KaEKD165pf77P5nZcRmZpBl9cctvzIxN19uzcminchusYwLyeWhBtTZ xpER9LbrfMNaQ7GnrgalMx54QvdjOhw/GJs9/SqEzYmPshL+DzgZX/oAzY63rQIh rBblf6/2talZqci96oFzNst8rGfPy/xQ7lgkki1hwIYbORMfloBhP+vAZJo0mxdM ipu3Z0ToK+KU2iqnBxXVr2/kod+CpkHnjUHa1wnQuSaefng3XwZ/vqtSL9c= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqDCCA5CgAwIBAgIQNCSh7Pjwo1/nRrcBHEPoRDANBgkqhkiG9w0BAQsFADBE MQswCQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxHzAdBgNVBAMMFkFm ZmlybVRydXN0IE5ldHdvcmtpbmcwHhcNMTkwMzIxMjAzODU5WhcNMzAxMjAyMDQw MDAwWjCBgzELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYD VQQLEyJTZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTEwLwYDVQQD EyhBZmZpcm1UcnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0gRVYzMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmHDl/3xr1qiHoe0Rzb3AGLw56e9J l2a3X59+PAfI5wGBHuK9Dl7XsyoH65X6QIC/rXyVpuNgKbbwIGHB+rCSplyHzGyC WeM3LXa2q1US7VteeFDS959nxJVRFfwATR9xAK6YTUWQ/yWdw0dZSm0lQNmEMBwS qi0ufWokiWXZUzWHOu7A6driCohu9sFDwe1INJUPH6uIlovmzGvG3UYbUSymJcjs Ka0fXXX9zukco8exlOIKWRJSNLxKtSSPDVASrGLQ1xi3qkiLTKci3+jKMNDFf1vw foZN99HhUcWKXfr2KlWfANdjTMlsTKCfuhfWl1OBVNHGRrACAQCXI/ji0wIDAQAB o4IBVDCCAVAwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vb2Nz cC5hZmZpcm10cnVzdC5jb20wHQYDVR0OBBYEFHkesckXxx6ssccU18Pof7y5UJsV MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUBx/S55zawm6iQLSwelAQ UHTEyL0wRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v d3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MEkGA1UdHwRCMEAwPqA8oDqG OGh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1UcnVzdE5ldHdv cmtpbmcuY3JsMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAAhmE4I56hNpnWXQ2Si8a/TgQUZr X5Jlv1LDvl3rkDyfEIHNZ8dth17SakJYJBWHExph/iIYjCJ9YmeyhghV5rPqT+wF 4yyE2ngenIusfnWT2bTpT9u2VZbCNeACE5XnN2UHSA0J9idPjfLuthViWEvSZZUh DJ53bX+exO366nDY4AI7owIyhz8hdsWyhZ/0ST+eD+kbgd8osd+GdxzRmyKcfl84 D1K1uff01T9w2dyUaZglQsFljkaO6xmeXZJsPnhwCp/HlMHWzhAneUQ7I9FZSOW+ WiYbt4RitmBpysadBReikWM4knECzJQ/fMT9vC0k9BLlqUYRwCH9vr0UnZo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFojCCA4qgAwIBAgIQU3HI6weE/VEI5dTz4yPsRjANBgkqhkiG9w0BAQsFADBB MQswCQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxHDAaBgNVBAMME0Fm ZmlybVRydXN0IFByZW1pdW0wHhcNMTkwMzIxMjA0NjM1WhcNMzAxMjAyMDQwMDAw WjCBgzELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYDVQQL EyJTZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTEwLwYDVQQDEyhB ZmZpcm1UcnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0gRVYyMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvDDZHfxkB1nAGFKdw0VCgV+B/eBtW1o+ bXzwRcpeFh5saDI+tv1RAMrYFq+AJkXCCJopgMF2Wqfv5myE3JMgxEHuuKUpJz7H FprrFckVOGCtJKH8Iy9AWPjBwt8lKmxGJF7EZst+QoVt4hMe0qhL0WEKbATFPe41 DcM7UsyQv6Bvpn424uePy3/1ATIsVL3YmvAbUNR0aqVxYAJzTefvyIet/761bKGc NyqdOVWFFeTDtr8iL1TBXToAgl0GJ39bFQZsP19VcCpfk9Zj3YHTPRPq5wZOZuUN F7jiBUEi6DaVOi3Wy4vdySHtWPeBHRYif1I6fcUfdCNORMc4ee6KewIDAQABo4IB UTCCAU0wNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5h ZmZpcm10cnVzdC5jb20wHQYDVR0OBBYEFHN8mjhoPFF8QQj+oR8qHrRh2808MBIG A1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUncBnpgwi2Sb1RaumZVIRJ9hF rGMwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3 LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MEYGA1UdHwQ/MD0wO6A5oDeGNWh0 dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1UcnVzdFByZW1pdW0u Y3JsMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwDQYJKoZIhvcNAQELBQADggIBABi64UEwl3l0yIiuSACyVQQIBI60BUmhseac 4BzCAsJrR5tE/2U9QAa2y6JpR1nqm76DJvw1QQgvFcNe+fkwpvoViCaSTbZkGGwD mQe2xRSYJcDSMQUc/GgzLcX2c1CrexQXE1vwV/q33af1en5s1GzLl915aNS/k1ch G7EMruJ/D4cuH9j4j2i+b+llmVBzavBwelN5rc693o+Ot9id/1sTWNugwAu3uXGb VlhETMnjXGIciegOLdWYhWBln0izYlt9IwlDEpjMVaZ0HZlj2JBGaSe4PfEFpJPO beuPcQpLQGw2XpW2ZMG5JcRYaoKWjixXAGktRA3H9nvVW92jvzx/RX484w2ZM5Rt E+I1ikAuQLAyWG7clht387e2RuC3NZTtefSyjE3L9gQDOPC+Z9ycwr0WJHRsxFvh FJQi3JnxgFZf5mc5n2mh3qAgALTNOUHuDiHrerjTOWbpF/1/NJmo/c/YZ63vZIhc EaER4HuhbBqlpf6z3WOIQdZm1ChwXYHrEcLDgfwm9cXoaVK2HZapkMwQbPffPlT1 E+AxRFB4YmT1y2WzdaHfhFA9nH6ByUdL5+FfrDoIIUO2e8OLOAcrJsf5+unhAhc0 v7N48JWdmpstjkXCaCIaidrZLJxS+pikNgHB1dXF/TxokLTiPB9jcYKdGaYs3XHb YKLdwubu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXDCCAuKgAwIBAgIQAgKlhME0Bk3J8y0gfqNymDAKBggqhkjOPQQDAzBFMQsw CQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxIDAeBgNVBAMMF0FmZmly bVRydXN0IFByZW1pdW0gRUNDMB4XDTE5MDMyMTIwNTUwN1oXDTMwMTIwMjA0MDAw MFowgYUxCzAJBgNVBAYTAkNBMRQwEgYDVQQKEwtBZmZpcm1UcnVzdDErMCkGA1UE CxMiU2VlIHd3dy5hZmZpcm10cnVzdC5jb20vcmVwb3NpdG9yeTEzMDEGA1UEAxMq QWZmaXJtVHJ1c3QgRXh0ZW5kZWQgVmFsaWRhdGlvbiBDQSAtIEVWRUMxMHYwEAYH KoZIzj0CAQYFK4EEACIDYgAEu9f5NkumdaVlmaNaxpDB+rBk/S6lhqcUU1zTLcRz 4G0dr4290hezjrvZJxGJ/X15aexpdD2V9cwaPD/yuEJcaaz+rg/qDoqQF3+AFqVc 41jw1E0S59+57XVKLtXI7Xh6o4IBVDCCAVAwNwYIKwYBBQUHAQEEKzApMCcGCCsG AQUFBzABhhtodHRwOi8vb2NzcC5hZmZpcm10cnVzdC5jb20wHQYDVR0OBBYEFMaQ jAKD113jvjucLtVlfSoQYO7lMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgw FoAUmq8pesARNTUmUTAAw2r+QNWu1jwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYI KwYBBQUHAgEWJmh0dHBzOi8vd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5 MEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2Ny bC9BZmZpcm1UcnVzdFByZW1pdW1FQ0MuY3JsMA4GA1UdDwEB/wQEAwIBhjAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwCgYIKoZIzj0EAwMDaAAwZQIwHJ5g a6sHvQ51DGr0bWq34awuwlWbybC2grHoNp5uYapcXr/qTJusb/6n+dczqFdaAjEA 7VQY06fE9ifMnTgT9824jc3+H6kfhMk4PoIj9ouWdYfc1DyTBS/low9Hb8liQyFr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFKTCCAxGgAwIBAgIJG+Dcaj5/IgR1MA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV BAYTAk5PMR0wGwYDVQQKDBRCdXlwYXNzIEFTLTk4MzE2MzMyNzEgMB4GA1UEAwwX QnV5cGFzcyBDbGFzcyAzIFJvb3QgQ0EwHhcNMTkwMzI1MTIxMjE2WhcNMzAxMDI2 MDgxNjE3WjBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwUQnV5cGFzcyBBUy05ODMx NjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAyMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvU4V2hRFFe4K7BMEmm4IoMTwS7NyDQB4JEar dV1qBsKHIIQJDm9hbCakcLIWXVv6vYrJZ1AEF0b6awBwhhlqXlyNnOtNa9uR+IAP 86d4yOGpgHSlNAhdtOOk9Qw6MUzzBo1lyoYmoL0f5n02SMrlMcArSg458o08eDUx 4iZs4dXDR9Hjxac2s+mdAO35Js8VK/D50AIMDJvHVeCMw+rumZkNZuRqM7PjIK+u BmbqO8A95PeqQEWHvM5nchlV1+ZGNVqHHSJenlMnVKytGv+4KJp7U741H/9cMbd2 X2PXsewWWFhGXoS8R9VXQ5xb3hF6324FQXvcA1mXRv6DAJedXQIDAQABo4IBCzCC AQcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRHuM3/5W/u+LLsL04O+SWw jjxrwzAdBgNVHQ4EFgQUIjAu0vv2S8rAuDvSBMTpcuaXmwwwDgYDVR0PAQH/BAQD AgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjARBgNVHSAECjAIMAYG BFUdIAAwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybC5idXlwYXNzLm5vL2Ny bC9CUENsYXNzM1Jvb3RDQS5jcmwwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzAB hhdodHRwOi8vb2NzcC5idXlwYXNzLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAo42Y fp96nUiZbZsqvYBID3Sqtx3jJfU8gNHFeXgkS0pxYHHYUwsVSVRjw+BGVEGUswpF MaYMCZD37ZL0JpvvXWrCDaMb/GqDJAQHLLTyVKPGGGIWCZH/FrhnNvcpt2XXA8lU Ujzp5nZPuqvenzQ/aXHI4sH5sN/QjyKVMSa/6RbWBeQmvIdgyM+0jIR5/r6UGiKM ar55trZgnlIbvQJ/w8QTmI/NwvA5CtRaOslQBxeKoAR0BuA/lRWnocXa/BM5uO6P ULL7ct/uI1bS+YThHXHmFybI6kDf+RhRzWY9165ZP96PBph6smQkxPDAz2b8v+mh LThH+5hkqnoetYfK2MdBYinceGPP3gZ+uBSDDI2o6vdVvdg7G96GP1OEtgTEqZa3 glVafckpn/8F5CisypdQuZ5zyy/6SXZCKkPcikR87ysSKnjtteXbxMWVtwkeBALT K7DbJA+5aOCYRNj6CJGULQKiGlC01/ipORKewf5J3yus81lLHzBmgQMA5l9RL8rV 6dI246mPpQ+8WDLsDrK3ydSDv5izgdVHzhL0tT2u4vwSq2WUqCgi4xLIA1N/fA2H xEW7zh0X/3YVz++g/6bd7iqRD9nRRZxACekRbza7AqU5xN1UjvVtCJQ9VC74K9KP pBoLWE2Bz5ksL9VUc4kS+WGORvZrSE1EpBq6cHc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFKTCCAxGgAwIBAgIJG3gcbV40zh93MA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV BAYTAk5PMR0wGwYDVQQKDBRCdXlwYXNzIEFTLTk4MzE2MzMyNzEgMB4GA1UEAwwX QnV5cGFzcyBDbGFzcyAyIFJvb3QgQ0EwHhcNMTkwMzI1MTIxNzEwWhcNMzAxMDI2 MDkxNjE3WjBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwUQnV5cGFzcyBBUy05ODMx NjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAyMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnKtnxpZLDQ+R0uzKzDMr83L8Dn+5ToSpD31z qiYMykj7I2geNQ7javKsBOzhgeVr7GP4yJ5bK/P0dhoKesYvQITihfwztbMP6DyH q1QJLQBqQnF0Lk8GhxSSNAZnlkCgX3aazoL32p9BeEfHuUE/8BlPywJY/RyE5/39 w3EKmWylhUkeRCMo3dUZr4khJq8JwGp/feKFs9n5FouM5PGhpFpZO+WQXEeqxpnc CxbvWpInBoTnmX3+ofjm+fmY+sdAnyHkuOBBw3koGbFQygDaJP9VItOGByCX4iSV ty/2uzppowIkf7Mpu5v5HJGKObLMP1gGv5lNqjAe8mz0bn25kwIDAQABo4IBCzCC AQcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTJgHfgYpKC9Uac87r3TMPe uKOtOTAdBgNVHQ4EFgQUkq1libIAD8tRDcEj7JROj8EEP3cwDgYDVR0PAQH/BAQD AgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjARBgNVHSAECjAIMAYG BFUdIAAwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybC5idXlwYXNzLm5vL2Ny bC9CUENsYXNzMlJvb3RDQS5jcmwwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzAB hhdodHRwOi8vb2NzcC5idXlwYXNzLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEApNka 48a+qhJXXS9R24p34CWnirlyxPMhxFfQyvPFXnwBQGHvrm7H5KY3/9/etShFXdY/ N05Aq6UnE8my8jR4iHMm2e9iEf4v+O2E2JGH/5/H8wup160GBAsp4zAmJIT8KEgh YAA1j+NaClVryZfEaaDfAdF6LbU3cW0ZgooILPMeeCEXso23KsdCD1Q+SMvD6nQJ 86iTvzWPY2GFJyEmvG/N2f29nBaHxWwZBwCfWB4Hqsw9wdKfY5M9SE/AGSLZ7LRM BmkkF9nqkWxxISadx12nbxn0LsU2k8Xyt830DqhHGSoYHEC/iGxbU4Bub8NC0uw/ QNBj5Gd5cXLFhRUWLLBTq4p6P6kLc7JudpM4FNQ+stWK/eDZylbDLN3iCBRnHH4p qg6HAlWuieiAKVsidBMxPUyDLJ/8Dt+aW8Z3vCNcYC2n7wqrLZz5e4FG+Wn9teFW Rt5pO6ZUZAkDS59ZVojbbjOdQzNw3QHtZl0IMHeNYXJlPIUlHi4hGL3maGZ9sBF+ AMfMLDu56+J2DewIuTXPzCeJeSTam/ybNt5FxTznxCSCIDqwmZMy3AQEz9nGSbE8 zfwB5VT2ijLB0PpPX4YbLf33Vodf0NAkBUv6N5It30XiTUPhdk+caBYPoljz/J9U 15T5+EGHs8ccHQWyYQ6gqYk8o4JgP4rSJqO1sMI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQCLT17zQGjf1LFRbkw1rAHTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDMyNTEyNDUzMVoXDTI5MDMyNTEyNDUzMVowajEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEpMCcGA1UEAxMgRGlnaUNlcnQgU2VjdXJlIFNpdGUgS29y ZWEgRVYgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0l9xY4fSU 3afHAuWko+LhYrN4nuDyhJPpZ8Ua1E9QE06lYqTR/yA+H7k51egdMR6MYUcizEVt QzqbEiP5UHJGYadtD7Y/yhJ+N6cpQJ3BuYyBnE9HahTyQ6ZY6ZDJxheloLm9jARS AvXUWZ+OLss9xLL/UFd6ssPzMmQ9xdBJmnew2RgusyXNV10qvW5+uwwSxMMcaazS HLGffOCLEmPoha/rFpKrsV+SbXQPxN5KFAaAQ35T1QIbY64fg1NtguftfqVC7/rO pPw4zU5ZCbr7M9fgaggDkPrBk0GVM9xDfkFOVCi6SHjrOwi1XEmw4k5YUi65CLC2 lWXYWN6BNLPhAgMBAAGjggFXMIIBUzAdBgNVHQ4EFgQURdgmlvaR/XCtuftoNEAz +lF/46cwHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDgYDVR0PAQH/ BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8E CDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29j c3AuZGlnaWNlcnQuY29tMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwzLmRp Z2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwSwYD VR0gBEQwQjA3BglghkgBhv1sAgEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu ZGlnaWNlcnQuY29tL0NQUzAHBgVngQwBATANBgkqhkiG9w0BAQsFAAOCAQEAPgw2 w6ZCAn5rRWZ638fA4tBJRGiZOON0B40mLeXVpF6Uo3PO8zvcTgP8vcXYETxsstnr Dp9Ssn7aSCBpfiJ0gF0NYbdxKP8TCiTGx1MKoazbvgvmfahXuknx6yypQOyuZRvY t2NKnBAWdi0OsJuGfIMkS6bS0u1bc/r1R2N1AurXGOq+RNEdxZVu6l+lYjwF9abr zm/yoVwtU/uk5mt5Hdx4vHTdSj8DZpUa7DV59x8U6rqXIfZDy62TFG3b8EN25752 vT/Xb/rjYqYI6H/kZY8HICb+qQFiOJG/Hy+ZoljyGEAwR1OhmBjseM/CKBR6tkpc CorDzmAUPphVeBmnAw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQDWGMrbYaqU9oEYIzz9SkXTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTAzMjUxMjQ2NDVaFw0yOTAzMjUxMjQ2NDVaMGsxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xKjAoBgNVBAMTIURpZ2lDZXJ0IFNlY3VyZSBTaXRlIEtvcmVhIEVDQyBDQTBZ MBMGByqGSM49AgEGCCqGSM49AwEHA0IABF43Dg9MDmLVpFLAck1R1v2sYHpZbFwV 3m1ABBJx33nLdZd/IzHNT+GYkkIndvLAj3b/Xh04d0w4UZ8n2lAdNQSjggFZMIIB VTAdBgNVHQ4EFgQU8fSWo5rehOCxWDc1idnynf+lLZswHwYDVR0jBBgwFoAUA95Q NVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEB BCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEIGA1Ud HwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEds b2JhbFJvb3RDQS5jcmwwVgYDVR0gBE8wTTA3BglghkgBhv1sAQEwKjAoBggrBgEF BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwCAYG Z4EMAQIDMA0GCSqGSIb3DQEBCwUAA4IBAQDcmthudDWFvbXRrLcocxBzSFossXwA s9h7+lF10+DDPiVVlOf01K4AJkjlua9ZhwPgy8mECeqWDEB8cRbjhW3oyN6W8d2r l+kqcGiEa5jah8iLGkHY304z+xibVEK7NYgFeqZzduuAooHQPfH4nGeCVXMaGGOb UY/WZKhnfNH8hHeofY4dPeiGGJRCAffz4GRZSxcwW0RLxxmxQqrWqgBlPnJbN2+j yB6acN07vjPrTrTYEv5Tx0RrWISyiqdveCZIMv7046q55DVCARO3uo97C8apzrwo QKH1/rSLkYBs5xTMLaQAXYIjwpFS1JeLojTUz0sXWi0FyEAZls5vocLR -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID8jCCAtqgAwIBAgIQAtyF17jzCZRQia49J52UPTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDMyNTEyNDY1NVoXDTI5MDMyNTEyNDY1NVowbjEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEtMCsGA1UEAxMkRGlnaUNlcnQgU2VjdXJlIFNpdGUgS29y ZWEgRVYgRUNDIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErNrfvbWaoOdV uYDCU+IIWfHag+ezD9W9xN//gaajDv2IgcikKUwk5COncaqVTvja3WPZ7m2RyUB1 DscawEcPX6OCAVcwggFTMB0GA1UdDgQWBBRVmi8UPp6fpoTP51p8WG1aBEK2fjAf BgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp Y2VydC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDMuZGlnaWNlcnQu Y29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDBLBgNVHSAERDBC MDcGCWCGSAGG/WwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy dC5jb20vQ1BTMAcGBWeBDAEBMA0GCSqGSIb3DQEBCwUAA4IBAQBOb9ku3v3X+KUw Z+BRTsGvw/l8erKjEcATPTqeu0leXz+sOq0Fl5f2Stq36yVOuNAVgnYPJgOK7Txj 76Z213RdKzl7zGFDI58s0sDzDyy/+coYImChb3r2p2p6F0iFQ5QJmtUjbXp3amTD fGoJsHRdsW7D/BHzn6k/wnYLUsPgVvD0bHBNc4tLlt77lK1OqHN3lGzbM2UC6+G0 ZBXyFzCGIrLK9BnTS4P8W1RM//6we+O5MWR9+WetzrywqglT39FUFXg5gSvtAj6i ebt9e+A9D6/g5gxJZmb1J89MdSK1/aUFBwL+WginEEidBHKZCD1lnIBaOQUmaMmn w4MYa1gY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG9jCCBN6gAwIBAgIQEwgRH7aT5ho8d3Ge2qnLgDANBgkqhkiG9w0BAQsFADB8 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTAzMjYxNzE0NTRaFw0y OTAzMjMxNzE0NTRaMIGEMQswCQYDVQQGEwJTQzEOMAwGA1UECAwFTWFow6kxETAP BgNVBAcMCFZpY3RvcmlhMSAwHgYDVQQKDBdJbnRlckNsb3VkIFZlbnR1cmVzIElu YzEwMC4GA1UEAwwnSW50ZXJDbG91ZCBDbGllbnQgQ2VydGlmaWNhdGUgQ0EgUlNB IFIzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsTin2eZcqn09L9he xcA58zeRb2T3XHIBT1BCNeKWPW8HHJhkJnPCW//QtxJrBeXiXwF3OMrUMbll1wb+ 0YRfVSiZHKCfWmwaZrGxMiYSetzu38rLx8HPYp8UOXNO8qXxmysVAV7h44A7bTb9 Gy3A/IR0/OOquDkyTCSWRIjCD2rf1nKq9VjN1ZSnA6iMingczj34ABCYFv5KqMev I5bv4T/K5E49BncyyYqi4LxbCh2MhF3Py9x/BRwt4ynr8YbWjdXI4eM3D1pWwbZN 85gUa08ufdLOhM4pHnt4ssvABRQ4NWEY8h95YHvO0MCtARtTXfEZ8Qc7URTjHw6Q 5fT6WXpUz0FLoA1Iytlnt+daYV3WkTTlxmobv+6DmcYjDk1iUIqUBlvzgo+V88Il /ESnnubwc9UI11SOkypOLMsny2Na9cP6UP0zy4TQgwWTvLtuRMitaV0kpe2ii0DI yGny3e0hiP41yX3zVdJBI+lCJ7SpcYFR53hzF+8fdFfh01lLX+ewc/dP/BRs3P3Z nzcMuwT7nwBnwpaSAM0eWuY3326EkOVquO/HKo+oGwjB3ajANc3PI5NV/2CfzwKh p66o22LDNXut1pxbrtVllwGT/Rh9IrGEBc51Zg7+DRcrS6hQu2TF/XyB+raLtphd asBmgkLnEpYo92XjRSB+JXeGOcUCAwEAAaOCAWkwggFlMBIGA1UdEwEB/wQIMAYB Af8CAQEwHwYDVR0jBBgwFoAU3QQJB6L1en1SUxKSle44gCUNplkwgYMGCCsGAQUF BwEBBHcwdTBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5zc2wuY29tL3JlcG9zaXRv cnkvU1NMY29tUm9vdENlcnRpZmljYXRpb25BdXRob3JpdHlSU0EuY3J0MCAGCCsG AQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTARBgNVHSAECjAIMAYGBFUdIAAw KQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMMDsGA1Ud HwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmxzLnNzbC5jb20vc3NsLmNvbS1yc2EtUm9v dENBLmNybDAdBgNVHQ4EFgQUuM3OdrhlfljRRmOspL+WTby4xEkwDgYDVR0PAQH/ BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDt6eM7at/SOGuGt2bI/2OIXFKH+riB DOi902O0AYDBndfQDyD35Eusgi/DE6PCivS0D0+bOyzeX+3Zl2vhNL+cIRGb6wa4 5LDgqOyKjV8WcwlEtxXDXw1YBJgjeG+qN4e+Ox5RZHjBaJQz6dV92mQUthvZvy/C fxo6jH0RHdHHj/KbJxQzG163y16iA/UxqZCbvg7mRTKg5eNErmKSx10vtDZfuWDw YNjdWOnoGbgGYGXmlwnFirNDESgHfkgutvVIfBUeYykgmp8fC0vP0f0wXrCiQHoX wsb+fg6ipsziQ8CC+8mvASe7nyVULN5WAhynm9LhKEkRoXVfM+GUQfVRUYMtntxp xPh4abpyge4aNgdGR8pP6nnDyxTIjx6x3KfOGpYnQaGq+rqfTxDkeBAltXADKT2r E75ziCgYkJO10pVtwnLAqvcpdbWDqbURWJu++dA4zjAEI9SLjd24ZSDLuIzxzZpU PsjZ2minNxT3KCDVFowZSSjG5jqzqUXOXmg7UhXltvxdnCgiFcVAuFKDyXv8EOVe Sb0y0/gFt1zH18YgUQxs1blk3PX3L7oP92iFZc9Ht2lv/jvIIgA5q4XLXK0GUlMs fmE5kb/bPfti3USxOzGngI59iVRWGDjvL8zpGMJ6fTinVdQxoQ019TG/5L/MZMoo /g+Gm1gWiXqvJw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG8zCCBNugAwIBAgIQRtNp7fstuGGz2s6j3yzzMjANBgkqhkiG9w0BAQsFADCB gjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9u MRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNzA1BgNVBAMMLlNTTC5jb20gRVYg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EgUjIwHhcNMTkwMzI2MTcy MjA2WhcNMjkwMzIzMTcyMjA2WjCBhDELMAkGA1UEBhMCU0MxDjAMBgNVBAgMBU1h aMOpMREwDwYDVQQHDAhWaWN0b3JpYTEgMB4GA1UECgwXSW50ZXJDbG91ZCBWZW50 dXJlcyBJbmMxMDAuBgNVBAMMJ0ludGVyQ2xvdWQgRVYgU1NMIENlcnRpZmljYXRl IENBIFJTQSBSMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJwX9ks6 3x3i1XuhsL1S2jcWm+DvmL+LtiBfab8Gh/eNXXU3xYMVI57Nj2R8xsQFMFHDMks1 +DPr0C/23Wwbep4TxgP2ZQ4jgS3YdskibZgsFknFZ/7w5ZFoPZ6wCiKvgqeO8vK1 ZP9RxqW8Uz+VjiRil86y39grOOjBdl3ZMLCeh0qcNHcYZ5xj7rLejsCSDqqsVf7o 0yZ0StdZx8LMo5xf5ItppVSX4hxI2+4AZvyOIg7w/hkhG4GlHa46MVXRiZVrTzrr ck92/PST2Mgx8RHa7O/RlIxbCIQo+8pmp0Vg79ElNRZA1S67XYh8PI5eA6nREi92 53P8zjjZH1H8B9JO6hcXNr8l0XaXmlcrTTnAKS+XVk+rHybZxX7E1WAio82feJYb 5ByDbI4n8Cazb0K6XA7VaNk/TNtLumFrl0rzGV/8C/ert0reovJUhYR6xqGthbIv XpbUIHapWWgrGQM6gzaUuo5eu+AQeapArowDKsnbA/rgYvvWqeZC+/oe50WehKx6 myfDpsoS23F7zk84illtwg7pzy5z9HDwSpjl+XA+lUy2vWB6l/+P77IhkdrG63tb qRCgNvEZyzLi4VcOMp2HYJrNnNPB2uqNd5fxdDgOZhD9ZZRLT4TgvFDnFvZc9mTt uCEJ+KuKy8Lgq9A/MQH59xgndFT26olgDak1AgMBAAGjggFfMIIBWzASBgNVHRMB Af8ECDAGAQH/AgEBMB8GA1UdIwQYMBaAFPlgu9Tj1TT2uPUGgCWnc9tGaaieMHwG CCsGAQUFBwEBBHAwbjBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5zc2wuY29tL3Jl cG9zaXRvcnkvU1NMY29tLVJvb3RDQS1FVi1SU0EtNDA5Ni1SMi5jcnQwIAYIKwYB BQUHMAGGFGh0dHA6Ly9vY3Nwcy5zc2wuY29tMBEGA1UdIAQKMAgwBgYEVR0gADAd BgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwRQYDVR0fBD4wPDA6oDigNoY0 aHR0cDovL2NybHMuc3NsLmNvbS9TU0xjb20tUm9vdENBLUVWLVJTQS00MDk2LVIy LmNybDAdBgNVHQ4EFgQUfYC0rAPVDQ5CW7hjOW4X8g92jSUwDgYDVR0PAQH/BAQD AgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBpnQplL4g3M/3QIFJsOegvufL4nzUAgztH Fq7ryPKovWpVCL+UYkl8Kdn7KvwlxgvmuRi682CVxz97yqqbhcy/jC/knP7ALz8B sgCJjoBqFPWUgmYRGXXU49k22DM1k7bYjy+b6PG70gs0a8r8fsqk0ayFUCmgeFI8 FW83mfv+xDfb3Nms5DYJbaILEo+QvQwa0juvHiWJo4YedfwDVi1kZiSziv4kpzuW U5cdVO8/M5gdPs23aBo4r2Dc8NrGgQB2Lm3wNXUB9ZRfj7ACqxbKZvgps2NxLVSY +wDf6BLmwL9aQGhUeOUBiC10HU1wqvpXb/hf4DXmHnaNm3jDGKUMmb+J6FVjc112 oMYUqJyNo1BzZLtaYxjQH31gUMez/hgVdBo9KhQGRLIcvN7XKwkXhW1O+NaL3Ugt 6TR3HMkuN/yE1z0sNb3KaKb5jFGvgJr50wDdcNSKgp2G7Gzwp4JGl4qZ4lY5Seor ZdESev8LZR/mm9xaB+/OQrn5QBkANj6nGyUEKFDQIhRZG0UiHtLVoTRgSL+0+UR+ xJYrMA96IvY81tJV/twPGeiSnhtCUNoVInQmM/4z4SQ7R/CpKn0kyu9zX6AQhvHq vqvP/oAlaP8WjhHKryslOQuRtrvWLeOlj4e1vK90gj/efgPDcnxkBEia3Y6wE07z 4gozrT30aw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG5zCCBM+gAwIBAgIQOXQnZqWVgle5u3wWTzhUJjANBgkqhkiG9w0BAQsFADB8 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTAzMjYxNzI1NTVaFw0y OTAzMjMxNzI1NTVaMIGBMQswCQYDVQQGEwJTQzEOMAwGA1UECAwFTWFow6kxETAP BgNVBAcMCFZpY3RvcmlhMSAwHgYDVQQKDBdJbnRlckNsb3VkIFZlbnR1cmVzIElu YzEtMCsGA1UEAwwkSW50ZXJDbG91ZCBTU0wgQ2VydGlmaWNhdGUgQ0EgUlNBIFIy MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAl2AAGuJKNScL4pBdPVPS Co/npDIJwPMuPh8lsu0OPndyN9oLNfYeph+p9m9hREKDS+gKj/u0fJda6Is+KpAW 5pfeOmt7AlbC3YYZXFsYsFfrR2G/Md51k6/2T8CtM3ek/gc/noZvYSwQf1gq5t+M C03UNFGZVW0bahWmPv5SwHa9ToDaptB7j2Zoa8KjFyzkLqmcRGXWasxZuPQwy7hO hYHVbTx31ouhMViJt+MNpG5uMzcmzXRdPrRwApf0zL1hMkHMn7NM3KNcp1Sk7jIP MOqz5a79PIXwr6+4WQV73afvG15smTGFk+TyRSkJKDsQtTMBLCmwRWTVdeWSu4Lm 8dwyWRg2mrPRcigoIBf1E2wv2zSiEuhfJqHV0DVtd2eIyTzP6itl6FlEW4AjZo0p 9AHDPjezghACHJV4K71RbLV+aumCd1hLMZNZL/CAZLpALk+iGBVvTmyaqQmSBwV3 4XMMMXPnOuz8/bevNQjAgvCBlBlNdSm6rt6CQkmwN19JeWlsxI0+65z5AiReJMZw YFausP1W/Cjnjat5euf/MOMhDAalIP2LEVqEPyQkrIQFM4R7i+TfwSkUBaqh96R7 XMSy+qbBScSfm2bNxep/4cQja198O3Ggz/QtUMQ7a6a4pKS3QjdmJcyBtKCO6lM+ b2/XoxN+lfRyALXOuZfdI3UCAwEAAaOCAV0wggFZMBIGA1UdEwEB/wQIMAYBAf8C AQEwHwYDVR0jBBgwFoAU3QQJB6L1en1SUxKSle44gCUNplkwgYMGCCsGAQUFBwEB BHcwdTBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkv U1NMY29tUm9vdENlcnRpZmljYXRpb25BdXRob3JpdHlSU0EuY3J0MCAGCCsGAQUF BzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTARBgNVHSAECjAIMAYGBFUdIAAwHQYD VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMDsGA1UdHwQ0MDIwMKAuoCyGKmh0 dHA6Ly9jcmxzLnNzbC5jb20vc3NsLmNvbS1yc2EtUm9vdENBLmNybDAdBgNVHQ4E FgQUBi+mUBS0mhHndHWKhO/NgUMTjh4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 DQEBCwUAA4ICAQCqrRL0AfHQa1Hf44N6YJ8iX3xC1rAUhinie9QL2OWxDodWy1BE EU+08SMqKcBqeZi4pha5AlkWCa+wlZsIUNjiSmh5B3Z9tWOzWeISlNRoJyjkZRwI bGTE/h082bnQGuB7iW8Jw6XA+jn3SIbNDVOK8LR37X6PjEMGO1RshAViNXjfNAGe /dYHGM0c+59f8jSGhqjdbSoK26WJjZs5m0/sOwVmZm4DUdifZhmarQ5LBn/IK+HG AKdqv7qmkvDsQrJHlk+1UX8VyMybkXhZWG5Qrjmsg7NSAQcwN729dHYy9KRMnO6W WHIw0UrSabRXbo6n5tpTuGHveMYk+6Sk1B0U57HECrbMvFPUnNH3E7BByjIpC1eK xZNdUqtORz250H6iVrflHPOFozKTsvKSmYCudauNXhrIcYonIvEFSEugxYGKB1df DtIrkg2u4/pbOi9k5CHAFlh7xSR2dKuZtgaXYzFFFy+3fwlEPJrxuM9szDosQjHL Q048LQjsozim5oWea3A8g9frDGs4lVjxgeOQdcA6v09nLi6Ze91B/QgdZXlQp+Xm S6uaXcVAUxYCa9T6jZGDrKwxAxbwCFa5pzVNgoOwdWan1FD1nS2Se0C9urYuydcL K7JyCRGR7qBI6ZKSoQkS65ZuqMsrXAt/kPie+4DIlYiNqBJZJjj0EOcSqw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG+DCCBOCgAwIBAgIQOPGlF04hyCbJUte/nd8v8jANBgkqhkiG9w0BAQsFADB8 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTAzMjYxNzI4NTVaFw0z NDAzMjIxNzI4NTVaMIGJMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO BgNVBAcMB0hvdXN0b24xETAPBgNVBAoMCFNTTCBDb3JwMUUwQwYDVQQDDDxTU0wu Y29tIENsaWVudCBDZXJ0aWZpY2F0ZSBFbnRlcnByaXNlIEludGVybWVkaWF0ZSBD QSBSU0EgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCf2C1jWf9G xmJ8y+JvLXfi4sGjqnsGJb9OQn6If0WuoLZFYw97rKz7YpbTlC6q9frJjLgNH5C3 mEb5innmaIKGWiv6Jxnl4ru8V5HkqulIhdH9V59OAAklc9E3OXZ1HSoZ9N2Hy2h+ 17bV2Z9jbw2nkmv0EXtxRtlgtqneWxL3uIyEFGE1h2FtM+CGZM/w/+ZQJT+pW9B1 nU+mMZuvJpL7ZWw3RqafoGgg3Ga7ITNWM64pvw3HKxr7zDWYaY+8MmvULla/3JYq fEgi48UGJi4CeMI0iFkpdTPmpRrUBsnSNsnVEwSXRuutofbvwfrUn8LCIV8eBx7Z 6Z2J1y7wT6W335qFRZXH6sf7l5Cww9OuhCQ5T9kkRCnEspPFNZb6T0YGJw0RKHYb +sJevSMdzY+C03yqwvWJMXpzRtII/9CING9NtViFum86s29r/JvgDE+jTzYZNnVb DtvNuNKm9lb+jMMAOJ/w1/SgyBcAO6cSFPOoMw3kwoG9V74nqe/vXvADrX/tZmog xtbR+b7nOiKRbp9TgbPAplQSv+LWXARL0Y7v0nz4C2bHZ9+OynGxhwIPutSAAvR0 l1ar1vB1yTdVGrO8Chh4hwEryIwEBxHgzXkUnAMat063mTqlvTFAubF8nZrNo8Bp Zk3TVC49G9yosblzJyZkXhpUB14CX+6iBQIDAQABo4IBZjCCAWIwDwYDVR0TAQH/ BAUwAwEB/zAfBgNVHSMEGDAWgBTdBAkHovV6fVJTEpKV7jiAJQ2mWTCBgwYIKwYB BQUHAQEEdzB1MFEGCCsGAQUFBzAChkVodHRwOi8vd3d3LnNzbC5jb20vcmVwb3Np dG9yeS9TU0xjb21Sb290Q2VydGlmaWNhdGlvbkF1dGhvcml0eVJTQS5jcnQwIAYI KwYBBQUHMAGGFGh0dHA6Ly9vY3Nwcy5zc2wuY29tMBEGA1UdIAQKMAgwBgYEVR0g ADApBgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwwOwYD VR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybHMuc3NsLmNvbS9zc2wuY29tLXJzYS1S b290Q0EuY3JsMB0GA1UdDgQWBBQXtg8ECVIq8CZv82JwIhDdtSvxsjAOBgNVHQ8B Af8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAM12+GA0GffuCNeElQbrj6Rb21a/ WnekHXj8p6CtzI8204J/mq9GhsoKchQTUIo9irokJf2Bs5Qlu6BkoDCSYLBaEDuj BbDwDa6ZomeDqUF9DohALCfqHxcuiu84yMM483zk/FAWjKQBVN/UCe6dgGOB5YJl E/GNxnX2OW66RoFzyXXt9t3VRJcsUEN1nWzlbTSswRVjibTwMbmRbsJaSIy8Drbd 7Wil3rvu+Z85qNBzqmJ8gr8jMes/QbQzJBf0SfIK407JT64aPQSkMFGUC7gtGPDa rhndPSotZGLDbH4FyRjIUiKGMHcBdZ0uXrNLjGSx29G0kL6NURvanUaQtzlL9u7e a+AXbte2m148S/2+aynCvra5s777NEj0UtE6SPGqz+DSlpsrqAqiQfSW/UL+g1w0 oIoSYi3NyAFpp81hGDnQE7nk0Yu8vlIju3QTUm4lbstd7cv8h2yyRg0oIflZdhZ4 E0j4/EhsNvNAnGn/1ANtFqUZGmSGMX2M1CG7jRjagJL4eJtOFq101KM5bN4PzKWE cDVmWq6/9yJCUhl2H5xemGthdMuzLrN0pr67wjusQP8Gvpyonk+1fLLS6cE8Hyf/ BIravyDZtkzUFVY9r5okqW46O3S6JhC379YcEXWQdychyP5zyFAOM2HhlgKX2gvt 9TuCYtYbdrNv1n9G -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG6DCCBNCgAwIBAgIQcutu88UZpyQI0VqiTeto8DANBgkqhkiG9w0BAQsFADCB gjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9u MRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNzA1BgNVBAMMLlNTTC5jb20gRVYg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EgUjIwHhcNMTkwMzI2MTcz NjAxWhcNMzQwMzIyMTczNjAxWjB9MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4 YXMxEDAOBgNVBAcMB0hvdXN0b24xETAPBgNVBAoMCFNTTCBDb3JwMTkwNwYDVQQD DDBTU0wuY29tIEVWIFNTTCBFbnRlcnByaXNlIEludGVybWVkaWF0ZSBDQSBSU0Eg UjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCl0OPcu8wMH/C11EdB QG0ve5Pqy4uN2KGyqiaqvKJjX8Rv6uRZoLuIm0w2qXcH4zwRpnC/QhJGs519x/XL XwZ7nfcginBRFXdq8gPVab0dUXzmQoP4rfu6H4iz4L4Fb8KHnmzrSHf0KQcS2b2j UCNj12J4WhIzpIspcQFkWgTfQXNp8J/OKElqo8RM3zi1ggRCc/ehAGOiRnKJeHiC fWwsZAIa4Zz9vl4s87ktXNfcqopJFshGsN0PrLgaIdK0ZWtvl1WSA8BxJ0Bba2FV 77nXZz3MtlVPvJUMaTkMamgSTQPv6Pwsod//4RzBaFIcLYEdAgfGRhMSK2jqj5Wj NtzUANZhS4qBFSv2g+7VfMAv+6oHocm38fdf9gTjCW5ki7O1fexgtiyUWSE3T6py 5fsZY3ORCYlA7Xz3B3/Mk3j8TIxXzHydoS+rW7tj3mOzqzF/L6hnNSqfdfGXxbQh 2kn6vMVXEzEaqsLqjcy7Iufs26X5GHw0GLsets2SRPLBWg0dr7kqPrMa4I+l5rI0 YJLGHPzDPZ5qMSS0eF6Adwgcxy9frCNR76wWfKXf2p+z9WSfZaZq2sxoW01drinD 0BVqKsCM2SFXERYieWWd9LXlsmlIgzFNg0YzIiSFktjXQuaz9//1D53iXlDi1jjv 1VDY17JACgzcj9gLXOlK0aN7TwIDAQABo4IBXDCCAVgwDwYDVR0TAQH/BAUwAwEB /zAfBgNVHSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjB8BggrBgEFBQcBAQRw MG4wSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NT TGNvbS1Sb290Q0EtRVYtUlNBLTQwOTYtUjIuY3J0MCAGCCsGAQUFBzABhhRodHRw Oi8vb2NzcHMuc3NsLmNvbTARBgNVHSAECjAIMAYGBFUdIAAwHQYDVR0lBBYwFAYI KwYBBQUHAwIGCCsGAQUFBwMBMEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmxz LnNzbC5jb20vU1NMY29tLVJvb3RDQS1FVi1SU0EtNDA5Ni1SMi5jcmwwHQYDVR0O BBYEFKjLRoac0KHKwZRDlDAKcgP0EcruMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG 9w0BAQsFAAOCAgEAW1b+mzu8pjzEoPEMRdTa0dCYHM9xTvJEDXEkprbInhXRULVT HLRo7Y6RdZ+1M+aP29KyXagmxo0i0051vKHNE/RVZHeoZR4YkN+tRvDUR8DoSZbX fhrqdKjrTtNl4/EjrGmnoU6TeBtVEx2dxXiUMHf7zjHYFqnzEbkGX8Y/M+ocnCSF 9m9Sc1QumpDo9Nfqg8c5H69RR89CrIo5IPp7DTF0ynqMfnt0AXfZ+zEyyu2xL5qr kWujcrIb3m9x/g3sMu8RModmBq/Q+p4sc8sw22r7QVcGkpi97heS2RHBeo6k5dFl F3j1/YOOvsLOPs1cvV6qjNhao0b7D84V04TF8brm4N4T63PJzTn5V8sdxehAIgk9 /XwSmcwWP2SGOt/b/UhRaWKKUoQjXIPZmyHjaGbzI8qWdOAGjKTqsAjQaxxjiQfx hIt4cGo7JRq2Qf1RUvLJBH+pcJPPAROg5lyYlTWUMOHJKu7j7lN+NHdaKoJqaAK6 9hjdOe5du84nPjQUh2eZejyP0vpWzZUgDLTMBP/H0/Zvo6YSul6q0hEh//M+kmGg 7Sy7hh7gLaJdA4NRjyIW3dwYLGCwJwIq3s3PNiBt+2Gqgd/FgcJqzZs+NZ4o18fp jQDzplshWKrRsFFybc6cfUuMlQNfv9/sZnxMQ/+UiHvzui0blorRuqcl2qM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG3DCCBMSgAwIBAgIQekYJPiN8u6jQIc4ccKrwDDANBgkqhkiG9w0BAQsFADB8 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTAzMjYxNzM4MTNaFw0z NDAzMjIxNzM4MTNaMHoxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G A1UEBwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxNjA0BgNVBAMMLVNTTC5j b20gU1NMIEVudGVycHJpc2UgSW50ZXJtZWRpYXRlIENBIFJTQSBSMTCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBAINSlaA4gvtnAWSxT5bXGvlOCmJmS0E2 RlRky8QPENT0ZyXGUsnluHz5MoIOvQ0JOQN/KuRvOsjhDQ80Ljdv4wETn3CXpWHn i+URsf1wBFwfdqQOMkXPk+maMnfiyjPinzVNVlbbiLyi3lPsbePCW+8R+Zje5qqH y4DEI0IzuuD6EUoBTAtiEyEfh0xP5M2yeUl+g1BlmvO6PUqB+TDkn9KCc95OK3pI m7spAsUlxhK0P2MZiB6s74QNCWB4IuzDMY/8/lMnMbtkZUYneBRKj6Jt3zipQ6LE d982dwOttO6MQg3m+A+Zs9fZTBj0eojn1OAUA0bxzBqu9pVsGxgrQ5HHTosGOuW7 1sFLq9ChO7lv/bZxTAzO4G5ym3/t74j/OdPgbRKc5W6CxhsoqMuy6g8LBzf6svP7 3h5l8EZ4zwZ1v8xFy7iTe7+3FQZBG15l6GL7d/BBMOC9Nxo+IU4hEe6N6rcee9kw LwcpT7aB3d9SqSw59wL1Wa+k+l1uSX2QkfBLBVg0uSF5Hi+NyvKrvpNvSF7IEUQ2 ii818dArblAmI+C6x1hV37ev3HJhpj6hzbdc3JAEZysezYCLjL6XmmAfPHShRU6N Ug83906voZMgqBiJcpoW/vv9FI42Y35TIbESPvKk2w3Aznt5PhooqYOHslzIDASE PoPdiAhNEhRZAgMBAAGjggFaMIIBVjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQY MBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMIGDBggrBgEFBQcBAQR3MHUwUQYIKwYB BQUHMAKGRWh0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTGNvbVJvb3RD ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5UlNBLmNydDAgBggrBgEFBQcwAYYUaHR0cDov L29jc3BzLnNzbC5jb20wEQYDVR0gBAowCDAGBgRVHSAAMB0GA1UdJQQWMBQGCCsG AQUFBwMCBggrBgEFBQcDATA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3Jscy5z c2wuY29tL3NzbC5jb20tcnNhLVJvb3RDQS5jcmwwHQYDVR0OBBYEFNA96qKYB11E hc8D+8q/NAqfEMRoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEA JOmE8VLUTIykvmLBD67jxXzMjHEw9YZSbg4HEjBentc6mNxJ+I7BAHJqx+pbIXbr 3Ik/yTIZyyRFfdBB5Txf7Fdf/3emA0/Cchu9mVy8rcMrf78zNS1RnTuztnyw1G0C zT2n3YgJRBKfTmrhIWekF1nsZ6Vj/XvJaDSwQr1UQwp+5JcWZt0IgUr2idntxp9P pv/rpwEHot+xs2RufVbfZCjlknBr/i1m+WgOKLe5TZBf6yjNBb/gOo1u2HOLnQw/ 54iTPHvjBck0eRnwTUCcBEIC4+kjUPbjUUtxU20WowsUqlOb4rEzjuevTMXCZdxe GsxvKvfEdlxUHOA/lcGEf/2uoov8uV4v6aFT9n/ZFJwoIzjB7R/tn/uHoATpin4b gds1Ffo12dl/PoaCBS5OgWAnJ3+cyBOdJ2/XPFb5kNWTfuBMjsNeNvWqWLJfbYP9 GlTruPqC+Uh/tTETkHSxUPpywSnbNer1M6eL9CQVIYZ+g6nESXFvOpaWfdAa/MlZ CB5yejdUfxihUkHf5/bbho8hQ8KS6CKJ0rB7VoQyGktTFf5N5jogSox37MSYoR5d 9HKwvZmHPgBYLwGD5F/EUQhiMEHI9FLwvgeKt2yoaGFKxWilOm1g5NWNOSaoI+bF yHnQZqUZ5+CL0njjIjweuPfE3EgZQr0k9tL8fkkgDFQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG7zCCBNegAwIBAgIQB5/ciUBIivHZb9J0CmRVZjANBgkqhkiG9w0BAQsFADB8 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTAzMjYxNzQxMDZaFw0z NDAzMjIxNzQxMDZaMH4xCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G A1UEBwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxOjA4BgNVBAMMMVNTTC5j b20gQ2xpZW50IENlcnRpZmljYXRlIEludGVybWVkaWF0ZSBDQSBSU0EgUjIwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDmQ+3UxwVE9dAx75DUrLZwgASW LLr/ID8bbGCfpcrSHIRsrR4ut5n49JGViu5DYE6addkpajbiMA2Jaw1Ap4RncDjZ +0fzSWbqGKEE+vNPVLoKy7OVIrxf/9HzGUT6YaELSNrGTR0cYNcR+W5bE3JTxTMQ iLMAwBbMXH4qKXQUT+oyIXD11CIMUtM8ECoo2o7qdpw1zaZWwVvhXy9mkAaRgrkw 2NpddZUVbJKF/spsJa3lNVdSi3wcJpDDQAl6jxtBF/3ctkY1OjBQz32yRlArFyms Pc+we9ffHAgvfqbHVfXvgWG8urVith8/6MjmojHMCKqFoJueLbtTPoN8QhvVh49u oRYYAUUH0HOAYCOzGBGrdJvMIYZqQsX90XlU7Qxp1En7vMkQswkQTvGmBPWrK/Ew SAJc15BZm+i8QBxPqVKFORfLETLEC4ZrwomtW/oPxBP8zXPvQ0K1dQzAkw+JXxKv /KiwDryFFhU5xMMB3yKxO5NRYXlnqW9nwfhdBTJScthzAtGO9KZQ2GPmq0NMVMuX e1XdCOmnPxOptKkMldBItkaYgrkTzqP1nzIAhVfU4sNnHIxKPftwrZ9VMSc5Wkz8 8bOtAJyz3KQRY0qcAtR4LaeRkiZaEmprQA8EOpdJxtv03pBZtaUnnTY6DsEwGQ0+ P2mmB5IHB74SknyNswIDAQABo4IBaTCCAWUwEgYDVR0TAQH/BAgwBgEB/wIBADAf BgNVHSMEGDAWgBTdBAkHovV6fVJTEpKV7jiAJQ2mWTCBgwYIKwYBBQUHAQEEdzB1 MFEGCCsGAQUFBzAChkVodHRwOi8vd3d3LnNzbC5jb20vcmVwb3NpdG9yeS9TU0xj b21Sb290Q2VydGlmaWNhdGlvbkF1dGhvcml0eVJTQS5jcnQwIAYIKwYBBQUHMAGG FGh0dHA6Ly9vY3Nwcy5zc2wuY29tMBEGA1UdIAQKMAgwBgYEVR0gADApBgNVHSUE IjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwwOwYDVR0fBDQwMjAw oC6gLIYqaHR0cDovL2NybHMuc3NsLmNvbS9zc2wuY29tLXJzYS1Sb290Q0EuY3Js MB0GA1UdDgQWBBRmj6a8t5Msnfm6SeVP3OqQUBFqnTAOBgNVHQ8BAf8EBAMCAYYw DQYJKoZIhvcNAQELBQADggIBAMJr11ncGIPKbaZxuuU2P1TGyXF+gy+xH2TBNWNl iJVL613nH1J7L2WcJQzqXYl77rKTzGeQexnKeYZ13MFwuE80vISif/gwK569WLoy CvNVvGEZ2bZ+JL5K49mVhrv1gqO+MgMvc8iEENl1xoWRpJGD4EClk8t4u7NUCgBv hYORiyzHCZcILHcEMvfEwmmFshMN6TqcAJdRjFT0Ru0hJcs5d7EFdM9dCa5ckXWr KK49cSNq4qOaxqpG99EfDw6U2c70YcJ1/IhC1wL6z8qlGvhYQ0vJvqGJqW/DdeuW cMmrB+qZL9WbORQ1nvlNggB6smEk0pXXYBr8HYjxT67XwtBBmkBXFpa7G6y4P0BO 3kxWGBfvRBJHfyaiwREgVWa36V/WjXtPmV8VHcv04Rqgk64E4OlSUxgi9k9VC6ki vTXJN+Gg2uJJBQdf+ptVhJqkkrtB0gABF+kQP0xsagKkrS3NVrVKo6peWMx0h7l5 2bGqT8ucu4Qe200KQi2xp/r8jpP60EE9U4M8D1grH3Kh9OxVOL4wykdoC/yGJNLK Il0BfsCVWB/GeSq5hxe/84K51OEJqpjDnOMrkRevfVzqGBFFAeg7Kg7uSysVR05w R+ltp3ytaIbjGJtKad8raIbM1qiNFErG7YB7v4baI3BP1s/rTDtPLototahwHP7I qOHO -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG4DCCBMigAwIBAgIQA6P00GAwUqM3zjgKiDAxjDANBgkqhkiG9w0BAQsFADCB gjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9u MRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNzA1BgNVBAMMLlNTTC5jb20gRVYg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EgUjIwHhcNMTkwMzI2MTc0 NjUzWhcNMzQwMzIyMTc0NjUzWjByMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4 YXMxEDAOBgNVBAcMB0hvdXN0b24xETAPBgNVBAoMCFNTTCBDb3JwMS4wLAYDVQQD DCVTU0wuY29tIEVWIFNTTCBJbnRlcm1lZGlhdGUgQ0EgUlNBIFIzMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkby+CNUTyO0wakMc6VeJxQLGcTtfwJG6 W9MYhMBWW22YUMtfCL7at/ey89eCc0cNy9uekJqitJe78Ion5qHBLfSpahYWttzr LflXkdlPz6xsZuw7F/tp6oYrcUpRIX92ci0EhORtb5xoX7rwzrBnG2Jv7fPn8JGj wmvYPS0meVkuKGtdR/s3dkl0tDraq2xti8cN7W9VawzLDL9yNyEw2GWAp3M5Uqex Yjh9HY5w/4bgk7K0KSw+2njaXCEa2MugM6txHDKjocVFBe7G8JPMKkCcbbrgZo/q ygTnIY8q7B1XQG2wrdsu4LTo9ijIYmoZHBAKN/XCdPecQYF9cHrv6NjVUcMrNmHT B43NrIvrXmm3lZJU4PZNUhb7YrDtpN+rV6zSaKAu/EArGDzYv8iHKT2E+wjhwqOC WnXv1qSa//xvN6RSoDMpj7q7iTxfdrQqRFsr70hyPrUmnoJLrBBg1+IqFTkaNtuk misP4Bd0zeqkEuxYCmhKcCTM2iS9RMCIot5HI5qeAcVs63WzM+ax0zbHK1F9AIOG gwrVRrdwXRSXO4TlvamsL6klJMnjSCs7E1l8xeE403nZPp4RGr5ZQFrhfdG9nL7w 66osGX+dGHGZkFjASS3Bw0RCiz4oCJxFGE+FAD7pJaV8GP6XTkaZp9n1ooYzCC48 vq0OtfRS62MCAwEAAaOCAV8wggFbMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0j BBgwFoAU+WC71OPVNPa49QaAJadz20ZpqJ4wfAYIKwYBBQUHAQEEcDBuMEoGCCsG AQUFBzAChj5odHRwOi8vd3d3LnNzbC5jb20vcmVwb3NpdG9yeS9TU0xjb20tUm9v dENBLUVWLVJTQS00MDk2LVIyLmNydDAgBggrBgEFBQcwAYYUaHR0cDovL29jc3Bz LnNzbC5jb20wEQYDVR0gBAowCDAGBgRVHSAAMB0GA1UdJQQWMBQGCCsGAQUFBwMC BggrBgEFBQcDATBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3Jscy5zc2wuY29t L1NTTGNvbS1Sb290Q0EtRVYtUlNBLTQwOTYtUjIuY3JsMB0GA1UdDgQWBBS/wVqH /yj6QT39t0/kHa+gYVgpvTAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD ggIBAAoTAGRea1Lg+Rlvnhj6lHbvhn9mjUlXZuI1b4d4jDDk5X29gNKhW7Rg97Qt oBoJaLb9gZkJ2MkUbCE1x2jIghjLmmFvaIq+nAZEMtWWEi0ycqQm8rVUHioZ2Mfn 2SoFtQeY+5MFLO9l8IeDaNZ+LV3su8YTsh/453vExhiNhPVEqLyGlkkW0B2gNW8z bsRy6L5QW0cZ4gZrY86MvHB0Gl299mTJ4jcgic+Oalbz9SZJ+EiW/aUDSpZ2zawi ackPWmAbk0y0gouOymrwOJZTuq+AJEJ6M+WSVdknwE7YwDpVMszHXS38BS1A5N1i rzW3BcARHbtCb00vEy2mzW5JPM2LjkzfgJ0lBiyDCE3ZeBeUtKmcdFUFrHwHl3gV aRipD+xMa1hGOTh33eMzwWoRxvk6o7y73Sy6XBfycN+8LhXUZT0X8STmWtBtLSMp blWMjuuFyUVQvIj05N7hORY/LhdQhEx8kVwS5RkLVSpRnohdk+nI69yIA7EwZKlw kKEsDqlVOeDYWVWQANDC55kJ7nOyJbqtGJqImwWXdQcf37fi80cf+mKOYs5vNmkx D9bwFWsKnP71x0liSlv8z79vRAo8FJwTgXRNO1c0ACf0rXEJy3GRAXRWiTvuGahR JVM3Jnn0G6o3+vTfwa7CKR/9Jc4t25iRU3xmSgiusg4u8i5x -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCBEigAwIBAgIJPZ+eG7IbOqovMA0GCSqGSIb3DQEBCwUAMDwxHjAcBgNV BAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UE BhMCREUwHhcNMTkwMzI4MTEyNDExWhcNMjkwMzI1MTEyNDExWjBGMSgwJgYDVQQD DB9BdG9zIFRydXN0ZWRSb290IFNlcnZlci1DQSAyMDE5MQ0wCwYDVQQKDARBdG9z MQswCQYDVQQGEwJERTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKYv WizVegVZyhz5Ah4q5hHgpIvfTt1Kq5uydMxplt9n4x5NQmY6L+cSuEoOmkLIKSzI or0mLfa3Fpaqjcm7ZCe+3HmEw8q4S9VHMDKhgpfeYVcR446C0vpgM+4dWBwDkVzJ sxMBmpbco3pqhoJtSZZJ9X+71RNtOiz5TMJ1c957vJCIEYwXakL7USnIcsyfoGpP C5vNtCpZzbwI89Katke1r90uBxmnVTckgHmHoheolFFQGqVbGNQV7mhOoS6auKv0 7d2qA+5CQHaEYUfa0t6qDqPPNx+3P+o1X5oZyKE6agRUQRevS4L8+UT/MF3O8ZoH rDxXUgmR5IeGY9wbz3ECAwEAAaOCAlkwggJVMBIGA1UdEwEB/wQIMAYBAf8CAQAw HwYDVR0jBBgwFoAUp6UGsSymCWDu0ZfpcK68Oxls2yEwdgYIKwYBBQUHAQEEajBo MEAGCCsGAQUFBzAChjRodHRwOi8vcGtpLmF0b3MubmV0L0Rvd25sb2FkL0F0b3NU cnVzdGVkUm9vdDIwMTEuY2VyMCQGCCsGAQUFBzABhhhodHRwOi8vcGtpLW9jc3Au YXRvcy5uZXQwRAYDVR0gBD0wOzA5BgsrBgEEAbAtBQEBATAqMCgGCCsGAQUFBwIB FhxodHRwOi8vcGtpLmF0b3MubmV0L0Rvd25sb2FkMB0GA1UdJQQWMBQGCCsGAQUF BwMCBggrBgEFBQcDATCCARAGA1UdHwSCAQcwggEDMIHAoHygeoZ4bGRhcDovL3Br aS1sZGFwLmF0b3MubmV0L2NuPUF0b3MlMjBUcnVzdGVkUm9vdCUyMDIwMTEsb3U9 Q0Esb3U9QXRvcyUyMFRDLG89QXRvcyxkYz1hdG9zLGRjPW5ldD9jZXJ0aWZpY2F0 ZVJldm9jYXRpb25MaXN0okCkPjA8MR4wHAYDVQQDDBVBdG9zIFRydXN0ZWRSb290 IDIwMTExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMD6gPKA6hjhodHRwOi8v cGtpLWNybC5hdG9zLm5ldC9jcmwvQXRvc19UcnVzdGVkUm9vdF9DQV8yMDExLmNy bDAdBgNVHQ4EFgQU+2PNFiFqc99azvQrqf2qJv6rSaMwDgYDVR0PAQH/BAQDAgEG MA0GCSqGSIb3DQEBCwUAA4IBAQB0oStqRU0DSDKF79wtjcEZK6jchvZLhyVYX8i0 8oUeDHGqGn8v2GMLnK97aeVNx1/7RcZbgay57WJ8SpuPHWRRiDL3Ec71HIGsc+N5 VPkScYlkxHVamBWkicxrJ7oTgZkH6uDMNjXTXXzRgKS4luy2FYJMH18Yb5XdEJ3S QRU91Lq40p9Px4DcTkSccffJd3ZLWfbNpRF4PKIIo6VK9N023RThjVqe8BHpv+UC lfe5MOjZlfCmJAFl372i0ElNb9qf51ZVKakP29Va/zx45iUMDwKxjFVlZKS84ciC t9EwI6Fld/+formkXgesy8SlRSBTSZ9ljytlnL4EjXS9N9Wg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3TCCBMWgAwIBAgIQBxLie1GKhe7lMdhK2rbD/jANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwNDAxMTI1NjM3WhcNMjkwNDAxMTI1NjM3WjCBqzELMAkGA1UE BhMCVVMxKzApBgNVBAoTIkhld2xldHQgUGFja2FyZCBFbnRlcnByaXNlIENvbXBh bnkxNTAzBgNVBAsTLENsYXNzIDIgTWFuYWdlZCBQS0kgSW5kaXZpZHVhbCBTdWJz Y3JpYmVyIENBMTgwNgYDVQQDEy9IZXdsZXR0IFBhY2thcmQgRW50ZXJwcmlzZSBD b2xsYWJvcmF0aW9uIENBIEcyMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAKaiBWd16x714O2CIYxPoA36aOfV9+HMAOCKLPnpBOEIzYxIL/GIljicAbyA qBvN6znNVPJ5W9lRY22CeKTnr3sMAlyhLToUPqfszZ50gwaIIC3OQEDVJmu3HAzc QITF0gwdWsyqFKKQ1i80hrmiHRxd1TDGjSDYwopUx7Gb9MqvvPFEFFAS41FFaWja 2xjDe1rXGrHFkd2DycewpO9mndr0mpCNfDWAEPBiT3vztvAso4SaiT2V0IG6Y+sd AjSkGk0QfACD9Vlfm24pm7ameu5Q+0cnkYGF8H6gf3z18DWnO5W36UtusFf6hN10 WwFs1cZQrFXf+XNFIn/+OAOJVQ0CAwEAAaOCAkAwggI8MB0GA1UdDgQWBBQUmVKS CWHQ0ZQzESg+fK1zvcxOcTAfBgNVHSMEGDAWgBTOw0q5mVXyuNtgv6l+vVa1lzan 1jAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwME MBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAB hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgYEGA1UdHwR6MHgwOqA4oDaGNGh0 dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5j cmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy ZWRJRFJvb3RHMi5jcmwwgdMGA1UdIASByzCByDCBxQYJYIZIAYb9bAUCMIG3MCgG CCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEF BQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMg YWNjZXB0YW5jZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRl ZCBhdCBodHRwczovL3d3dy5kaWdpY2VydC5jb20vcnBhLXVhMCcGA1UdEQQgMB6k HDAaMRgwFgYDVQQDEw9EaWdpQ2VydFBLSS0zLTEwDQYJKoZIhvcNAQELBQADggEB AF9Z3q65dQV2bBTGZWt4bI31GyE0tSSar+VagEYAY3Ypw6rkYGrhmZe3QsKntpk5 rKa4tIPWZGCPbkXHNgcaetlSARVT40JkRYnU4vGwxj83cJn7kEddVDwL5WQk+g+9 6Flk7rHyJGnQOkwSVSBglxFpzGahMkq/bS2/jRo8FXvSNUPDQKz0nKlFjP/DDPlv rHzKKnj9tRZeieC1PTxxqzighHOGhzEv3F1WVPXOQVQofBLt1XLZ/uUHCtwl8V1n d+bYnmJmYy2Hp8MyQ/4Rm3RRzjULd1pfe1ZGQCL4ieGr/iGW7v3A2uoYFSmOXPd1 +fP89StbnOp/C7aXunRvZsg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHVTCCBT2gAwIBAgIUe3SFufBRSlUh5S05Ghqu25Ntj4wwDQYJKoZIhvcNAQEL BQAwajELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRl bjE7MDkGA1UEAwwyU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFNl cnZpY2VzIENBIC0gRzMwHhcNMTkwNDE2MDg0MDE2WhcNMjgxMTEyMDAwMDAwWjBx MQswCQYDVQQGEwJOTDERMA8GA1UECgwIS1BOIEIuVi4xFzAVBgNVBGEMDk5UUk5M LTI3MTI0NzAxMTYwNAYDVQQDDC1LUE4gQlYgUEtJb3ZlcmhlaWQgT3JnYW5pc2F0 aWUgU2VydmVyIENBIC0gRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQDNZfwvQT6bhd9JwjU5SOrZd0Fe3Fmcftf2KIGrbBgIjJZKkiRximQqWZtfwyzh by/Pyli8HAQVsXNPKHPqrJ/iv1YtTlDntuRk+w8IaZzWo0Rf4IO5VmrnjFUGkmvS QcTyCN1LdNBoHI185aa3Br7lGUltBv86Q+nlymHJmMKjC0y6C0+Xpt7SuWr0nO15 wqiBZdUlFF05XcxXbTOG9UouVhlSKU9ujnkfNSKw7N3x4gqJNQ9C0W5O2zVO2jWy BaK20vnbN955FQM84O2prhMFQrCi3e6lVvtTamxlnzVOiVUpH+59Rh0PeOw8OwCn k8GLXwkvIrxPgi3MFIpVy30q52eGHwzEkvExTHkuTm4pUSKI3N8zypfKBkfPUCnF k6PluFkQZYvZSVWMNbLst6DOuStKSgsWtH3lQGz3qNgyLgtWjFBS6S7+lgb06On9 SadJ7MgLTyvaPXGOieDwEq3BhjTnioNswPjIJCKjGad6EtnFaK+kG0wzE2v+gger 4shh72Vj7GM4305UPBCEIlvmafyCHSD8r2lMBX1bqnbp2aw9ocdDbkCTzJ+N2Dkm KkAp87NFRsFXgfnqgOjG50owXLNaEsXhOwI3lBOCCz8FG7u0jD44k67lU8n3LvKh BenixXYylak9vulc1q13uICa04NbMKegL0uW7Wb2anw1+QIDAQABo4IB6jCCAeYw gZkGCCsGAQUFBwEBBIGMMIGJMEYGCCsGAQUFBzAChjpodHRwOi8vY2VydC5wa2lv dmVyaGVpZC5ubC9Eb21PcmdhbmlzYXRpZVNlcnZpY2VzQ0EtRzMuY2VyMD8GCCsG AQUFBzABhjNodHRwOi8vZG9tb3JnYW5pc2F0aWVzZXJ2aWNlc29jc3AtZzMucGtp b3ZlcmhlaWQubmwwHQYDVR0OBBYEFMOapntedCuCtsZy/XROhdKXzf0YMBIGA1Ud EwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUQ+tNANOVk86mfEANbRG+OdEyruIw JQYIKwYBBQUHAQMEGTAXMBUGCCsGAQUFBwsCMAkGBwQAi+xJAQIwQQYDVR0gBDow ODA2BgpghBABh2sBAgUGMCgwJgYIKwYBBQUHAgEWGmh0dHBzOi8vY3BzLnBraW92 ZXJoZWlkLm5sMFEGA1UdHwRKMEgwRqBEoEKGQGh0dHA6Ly9jcmwucGtpb3Zlcmhl aWQubmwvRG9tT3JnYW5pc2F0aWVTZXJ2aWNlc0xhdGVzdENSTC1HMy5jcmwwDgYD VR0PAQH/BAQDAgEGMCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDCQYIKwYB BQUHAwEwDQYJKoZIhvcNAQELBQADggIBALuwQ/7/bwHCXqLJS1ZACMmTm2GpkvQm plXC3HHpRV8DTQ4u/jMhtkSLzLsf6AcLGKTGQLrYv2lGBglFxtlZWTGOirTmWFyR OUbSSzkbSd5H8jvt/zswWffiSPRdMMncrc+yMMjD44lDfIytwZXrKYroI4ftYt5j aJ8wwMTOJTk9apzFajhIgGtMybXfmgVJDr9xPP53aMOjhHmlqlQ4yNdZTlNOO9LK KRxw+injitKp6jqoVSCL0TBvrbKu4pw0TqtK9NfaMwWGt55lZV8ZSWZaqNX97Umm xHqlqjvX7z0gE7s6wzvcgYyoR1Qo+2A60tLm4A1mr2mB9+aTnupdaGsBzCdkqKIR JcnEEeb+cffgKt0upfAAnqXAwkxTiG0NMjJp3RBkBFItOByy8ARduxiH6w7ZFHhs B8W1kL9/26hbYY1RTyAe86hfb6NuibTg16blnqNF/xCjVqCiTGXop1CQLBDlx4Hp wIrKEDvIGGBZRIzPqDI9I2KMlJEywa7k8Rm+HaILymBz5jU9NUD2CIBCCp94RqBr 4XFcJnXvSIjfS0+2tIzljXImImIxxZkYLNiWElB6ytiHi0fKBvQ+cgDAOmbfLvhE Nankk8qgo22on1buVddUW7vYjA0qiXIQYr0N5mrJqbLGdrSCVceMgVOVSI/b1a31 cVXLiGvOxK8W -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFLjCCBBagAwIBAgIQbmFmmHK8nDAAAAAAUdOTHjANBgkqhkiG9w0BAQsFADCB vjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsT H1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAy MDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAG A1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw HhcNMTkwNDE2MTUzNTUyWhcNMzAxMTE2MTYwNTUyWjCBtzELMAkGA1UEBhMCVVMx FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVz dC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDE1IEVudHJ1c3QsIElu Yy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTErMCkGA1UEAxMiRW50cnVzdCBD bGFzcyAxIENsaWVudCBDQSAtIFNIQTI1NjCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBANg5rV49ZcGTl2ll7xEbTkj+0DCPk7PNkUHNnrag3mMHLSC16pML EK2QemIymtQUJwZix8Z93FsSibagk+2T/eWFcXNDF4z+Ynz/cQ/3+fY5WHf+0jyM UFI19fr7FemmOLU8z4mjrt1R1Rmw+9LIt1nVLyYd+uwjDlNqNJl4vTMFtXwcDByv fTSoKcKa+EIck9mmfqLP4RhkC1GJrHuQ37Iau/XnpV8hQtRSK7zNAIQJPk9zShT5 nJCsMpN9I5BTBJUp3k0e4GpzkzHk9ThKlaJsibDMyboFWjM7kreL4SRUrf110TD3 D0/TxMd/V+/DTZFnk05C9RoavTtlngErUDcCAwEAAaOCASswggEnMA4GA1UdDwEB /wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMC BggrBgEFBQcDBDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0 cDovL3d3dy5lbnRydXN0Lm5ldC9ycGEwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUF BzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAwBgNVHR8EKTAnMCWgI6Ahhh9o dHRwOi8vY3JsLmVudHJ1c3QubmV0L2cyY2EuY3JsMB0GA1UdDgQWBBTiSbnsJd63 DN7lUBhbSMwMjhXypjAfBgNVHSMEGDAWgBRqciZ60B7vfec7aVHUbI2fkBJmqzAN BgkqhkiG9w0BAQsFAAOCAQEAVbmgsDea/OXEKYXMlHvkV6mmMlJlRKk1hv2vfFCX V+OL5AoM3Q//gp+KOsG0bp+wJNJHQkd6nxQNe/+UDkPAyzskeV9+2LcW8tuJUyyi noTZXN42qTPF0EBWiaizKtzF1xWIVpRZOFB8F2C3A0e18gN4WLmi+h1Pdofrhkgx HAXlfp165OBUYBHxr4pR33fvKMwY0lSjhei9fn7iTZGhVmLyeEIuuJ5Zlw7JOivX +j+BU/IVwNgp+rUBgKgs/Lem5+5Y7WsQjCddCxPqJomQ31l7+D65L4FpzamRM0MP hNPR8BHOw41ff3xqlIS0dgCpI2BP+/K5cpmD7zn+25qUmA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFJzCCBA+gAwIBAgIRALPSJ9szCF4XAAAAAFHTkx8wDQYJKoZIhvcNAQELBQAw gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg MjAwOSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MB4XDTE5MDQxNjE1NDU0M1oXDTMwMTExNjE2MTU0M1owgbkxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxOCBFbnRydXN0LCBJ bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxLTArBgNVBAMTJEVudHJ1c3Qg Q2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gVk1DMTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAOrOE7nPsgxnWadbz0f0D+btzyoxflXpbrILq358XJUn6MRq k1m9BmK35G7bf0myFreyx60Rxcj+SvNRsraMd6FUzDuOccfK3PzbUktMKPxMBFh7 R4/ZSNBMTko2fn7jhRPdFW9k0N+sSKtHwhu0xw8qzGg8oFRJgJgpxZv1zzrny43E IuRiozQgg2J3ZzY4ova0s/BM/SLqdsGo+Jc68S7jsI6K7zKvw0FB3T6SWYxrBc1p GsYvlmbCrDs3AP0Jcuske1GlLzFUpUkrvx4na9i4t7XhxVcwz3AuMRbU4nHDIc0w tLG9Fm24xB31kSqybtpxEGC/oNybhCWjQDqYW58CAwEAAaOCASEwggEdMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMBMGA1UdJQQMMAoGCCsGAQUF BwMfMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3 LmVudHJ1c3QubmV0L3JwYTAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0 dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDAGA1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9j cmwuZW50cnVzdC5uZXQvZzJjYS5jcmwwHQYDVR0OBBYEFIu2OXbQNJCmP2LhZOo+ vPR8RqFzMB8GA1UdIwQYMBaAFGpyJnrQHu995ztpUdRsjZ+QEmarMA0GCSqGSIb3 DQEBCwUAA4IBAQBphKvXT6JDtmuQAhgH8nZ5Xo9LlymnCw5fiGpQJ13rsr2A2Jnl 1Z8poTwskM71kIImRctlYs2Q52Sgvd0egxvcPELQSL7BMGPU42BijWCEvnD8GZvU /1x5pOg0F2SiEQ5ycmC9ADr2EskcbqMh2QMOOlNV4JfFjtUY1JCTviOWJ7O29wsE aVMiY6EdrsN1hjqmwaxfzTVikM5m+jgUKWqK3U+56outMWziOfxcpo+Ur67hTglc fTUKIRMTGhDMVFbwW5O2jINlBjGt5yAbhI/LnRwPvB99LFkISKX50c2NDEkOzEPp mDaPrsUl15evEah6amsBfpQiWRbKpDLKs1kF -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHZzCCBU+gAwIBAgIUdMrZyGVrP13Igm3fEdGqSGNOtzcwDQYJKoZIhvcNAQEL BQAwajELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRl bjE7MDkGA1UEAwwyU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFNl cnZpY2VzIENBIC0gRzMwHhcNMTkwNDE3MDgwNzQzWhcNMjgxMTEyMDAwMDAwWjCB gjELMAkGA1UEBhMCTkwxIDAeBgNVBAoMF1F1b1ZhZGlzIFRydXN0bGluayBCLlYu MRcwFQYDVQRhDA5OVFJOTC0zMDIzNzQ1OTE4MDYGA1UEAwwvUXVvVmFkaXMgUEtJ b3ZlcmhlaWQgT3JnYW5pc2F0aWUgU2VydmVyIENBIC0gRzMwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQCif59yx1tCrQUccIYzyvfDNVoASBFIeaftj+3n Gru7Uxv88hTN57qqNogGzIvQ7gX/nm450qQ1FK6yS41AZbXJeW/xwpxwvurF4Pat K02OEyGC4Gema4maPwXKKVr56KOBxO+fxDw1UzkxL5e3cYj9Qju1R4rj58I4/pyG sz087iBPiNPVBpR4edVj5M+NQZ4i2+242uyTyaZOwRftR58I/qKGBdhFb9J0RH8c T9ucRAsgzD+LK5h0dJ8F7j0z95lgh3addM0mjAMqlDyU3JfRJ7BblD3p9PulX/Pw wB/idRUpMKEc2ZV0J5kICLu/5UiS6nQJzrXkEGpXrLH5iwf3uPK0X/XFCW4Cs1vx HJ1zonw/rmVDRVYap0lK4Bw5vIbMYPfNATu02198knQpFV+PoUvQnx3gNCAADzM/ LLryDrb5x1wIV9wx7nPktCnRu0MnhtafwwEyTioyP+v/5QryJDaiQR2FdR6eHXEy 6mCoDDUKHoYfzkWpYRd0iQwrDNbx0mF/+mU4rvtqwJusv6IYFMftN8OVR6Ju7oVX FMa53fmcnBxiWtPN3FZQBWhctYKVtv31PQDRD/qa5TkkkvAAflc51VqsaJAq2hJQ UZw6vQVNyO3i41+63ZbOSNykBJEONkBfqBuxMFBDqCYS7f2v5bzgsGxt+XZLTlg+ wzoV3QIDAQABo4IB6jCCAeYwgZkGCCsGAQUFBwEBBIGMMIGJMEYGCCsGAQUFBzAC hjpodHRwOi8vY2VydC5wa2lvdmVyaGVpZC5ubC9Eb21PcmdhbmlzYXRpZVNlcnZp Y2VzQ0EtRzMuY2VyMD8GCCsGAQUFBzABhjNodHRwOi8vZG9tb3JnYW5pc2F0aWVz ZXJ2aWNlc29jc3AtZzMucGtpb3ZlcmhlaWQubmwwHQYDVR0OBBYEFLfp0On/Zw7Z nAwHLpfUfkt5ePQgMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUQ+tN ANOVk86mfEANbRG+OdEyruIwJQYIKwYBBQUHAQMEGTAXMBUGCCsGAQUFBwsCMAkG BwQAi+xJAQIwQQYDVR0gBDowODA2BgpghBABh2sBAgUGMCgwJgYIKwYBBQUHAgEW Gmh0dHBzOi8vY3BzLnBraW92ZXJoZWlkLm5sMFEGA1UdHwRKMEgwRqBEoEKGQGh0 dHA6Ly9jcmwucGtpb3ZlcmhlaWQubmwvRG9tT3JnYW5pc2F0aWVTZXJ2aWNlc0xh dGVzdENSTC1HMy5jcmwwDgYDVR0PAQH/BAQDAgEGMCcGA1UdJQQgMB4GCCsGAQUF BwMCBggrBgEFBQcDCQYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggIBAG15Bl65 SEHVk3Y6/Yy4hTpcUkBaIr42+cGNuhmXsdT1pjNpcMwQO/VwCnnMP/WGlXKpc6v+ ODH5cbxDXjc9lceZg04kYjq1bWdsz9SyGPWrtlOUtA/F+uA7nBRywgRNv0SZeQKk gDF66SocHTIzVz+qBxFwjjkIx2JMBiHQI+F+ttnohidsrOM52vwjkWw6M1yAcero Ke8XpKrmu2MUjwfU0jpM6oueToA9keNCya4dKOZuRpKArImqAKJ/VPaSKgjvDHV8 5dUmFjLjQ/vt7JEUxju8bnSsXqjLljIo1ieZNvynj4syu7tui9V//CkBhi0Pb3xs RVJ22fOy7rubq1EDG+vyRwilsfIkiWepgbfrH5r8WAahaXXfLPPF7H8oGnPBLixu LpDXqXmGNuRMSat1aB8XpxaemVD5N6JGyFUB++ixhw/zDGSEzC8ZmcSUQBfdEehs 8oZs0/pZm716whoSOs8DIG2JTEnxv+ATSbhOFS37mXK5gMBIPqkeHx6eRx2yesCX dY6dfhWiKddMdbA9ubeMhEQLAIwxQarJJ/8C9J3pFmqdK8laGZ69V0aFTf7uAtvK LuSTRdw9ZyiWb+7Fh48r6e6MZMLUNNAXDtEfvLm4rDNjP+zfgsLb7kDUtKhx+F9v XBdHmxsrwN8L8sCqpWv8rZDtb0Rm5t5MSt+P -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHZjCCBU6gAwIBAgIUVVo/86zdtyOCeYoMPDTgJPNILkgwDQYJKoZIhvcNAQEL BQAwajELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRl bjE7MDkGA1UEAwwyU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFNl cnZpY2VzIENBIC0gRzMwHhcNMTkwNDE3MDgyNDAwWhcNMjgxMTEyMDAwMDAwWjCB gTELMAkGA1UEBhMCTkwxGTAXBgNVBAoMEERpZ2lkZW50aXR5IEIuVi4xFzAVBgNV BGEMDk5UUk5MLTI3MzIyNjMxMT4wPAYDVQQDDDVEaWdpZGVudGl0eSBCViBQS0lv dmVyaGVpZCBPcmdhbmlzYXRpZSBTZXJ2ZXIgQ0EgLSBHMzCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBAL+smIBJEbwtr7PT83fssJvDlLaYAOYxrIqTL1le DVliLiIJFCfFWwC1V5UiGFHckvIFir7bH7zcb8fmfRozrZriAoqWXns2NbNyBLol Vml4R59aI5ojkPFwI/rrQiwuyRlfx8TRJnUsLCyyT6IZgfjCNjbdzLy6WyQdsnle iLNu+LiMFxOa9yVELXK5uPx5yThzUfDN4yCadY+s0c76x+I9yp/aiIHoy585l3IG 5DsRbwEL6LotGUR8fYR3ibu0Cw1nRp+FaCekeuRX/WYkQG8kAtP9z8600km8lT9o +i6rER0FffhXUxB7VkufhO1oj2HXPW11pubU9mWjCaQa4UTHTElv2fdUu4vPnpQB EYlxbV8c20oruytBqlOpu8n4muuC+LQO/La4Jg7l/rukk5Z0e50FhX+9QNQD46m2 QSRiEEWyYAejdCZSfmEBpi6zJMH10luhiLBd7yOu1x3bkpqvAHCfwrAaawBV5LrL /ul20zRmxwbMMw+146iNw1iEgr3u1CcGGDbovTbM2gXUnadRfQeWmQixXEdFMhcN vOYmSlSkE+4DJKLkHj5DwUsATiECflOyTQlQVCo3KCiQUQ01DWo296ic2vnk58ot /jx1vFVvNskBGjezjo2c+q0YzGkO2qip+HF3Kare8DFKtPEiNqdjKEPOc2oVl3CD /Is5AgMBAAGjggHqMIIB5jCBmQYIKwYBBQUHAQEEgYwwgYkwRgYIKwYBBQUHMAKG Omh0dHA6Ly9jZXJ0LnBraW92ZXJoZWlkLm5sL0RvbU9yZ2FuaXNhdGllU2Vydmlj ZXNDQS1HMy5jZXIwPwYIKwYBBQUHMAGGM2h0dHA6Ly9kb21vcmdhbmlzYXRpZXNl cnZpY2Vzb2NzcC1nMy5wa2lvdmVyaGVpZC5ubDAdBgNVHQ4EFgQUFNpISXBRtDQS eOaKwBV72Br3H+owEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRD600A 05WTzqZ8QA1tEb450TKu4jAlBggrBgEFBQcBAwQZMBcwFQYIKwYBBQUHCwIwCQYH BACL7EkBAjBBBgNVHSAEOjA4MDYGCmCEEAGHawECBQYwKDAmBggrBgEFBQcCARYa aHR0cHM6Ly9jcHMucGtpb3ZlcmhlaWQubmwwUQYDVR0fBEowSDBGoESgQoZAaHR0 cDovL2NybC5wa2lvdmVyaGVpZC5ubC9Eb21PcmdhbmlzYXRpZVNlcnZpY2VzTGF0 ZXN0Q1JMLUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwJwYDVR0lBCAwHgYIKwYBBQUH AwIGCCsGAQUFBwMJBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAgEAnR7uLrmc EtVWGnKUmae2MaJP74/HFSdk1Xlh3srLCUJOrvdsR0xRR96mgITrUUMRz3Dg3+z+ +HD18qCGsIfhhYVcV/b+RtuAvioO5dBGTugQm17Cj4dZr9h91/+JJfxk/h7TTG5t nmk2D0YWFMd2VL26Q9cZOe+kX/chrpkoA6g9nEPlJ06ZmqxhkJee6b/Oi5FIzIff BSb1rJi+9Kr0HoeDFqIVPDnqNhlezSAFnaf05mRokaAbgw8fXNw4J4l9s05fXpLs 1/F6PWFyzr0mlSWlnh7El+fl7PUo1DPdJ1Dg2DryxE0a6JLgmJJbEcMdNwvpugOP ZZazKX+CHs4uNmHmfT+G26bfijg4AwARd6fMHIaccEqoyssMvJfOGYNzgk3UXTKL MsGO1hz4G19UBox2tDg7cy+9O1kqekY3pwfBkYXXXmcZhKqAR0O633IgspcGj/yW EkdLXsGNA2Q93gDehPAvIUDJsyd+CR+MxsF0VBtPKLFvOQd1NhYidVe20gHrFQOL GeBeq1SzkIFgVbEHda3bRosgezxPA4TniR8GI5fQG1Gfyj/nPFNW7+6uFqHMwQol xeeDbOTbbZUZfco/ztC4nC18MeNRemMnUyLdWXDcRtFEAI0eYpSzgxFRRaLEwjEe 2Dm+mylLYugMreMmQq5rDfIxHSTqlD5Gt4g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHVDCCBTygAwIBAgIUTCAvTLEaU7ToLOG4iPY+q8IbmI8wDQYJKoZIhvcNAQEL BQAwaTELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRl bjE6MDgGA1UEAwwxU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFBl cnNvb24gQ0EgLSBHMzAeFw0xOTA0MTcwODQyMDRaFw0yODExMTIwMDAwMDBaMIGC MQswCQYDVQQGEwJOTDEZMBcGA1UECgwQRGlnaWRlbnRpdHkgQi5WLjEXMBUGA1UE YQwOTlRSTkwtMjczMjI2MzExPzA9BgNVBAMMNkRpZ2lkZW50aXR5IEJWIFBLSW92 ZXJoZWlkIE9yZ2FuaXNhdGllIFBlcnNvb24gQ0EgLSBHMzCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBAL/MtUDP+XQNHP9/3GDw2B0iFojRaaEHGHi1bpyX i5dsElWMEBZ6XJKY93YaRcslKlEpeQJ4pPo78Zl+rY8Spp2Ox5bXewrLa/85Wmda HnrfG1hxCkyR0LM03Ayo3xo0eVu6TZp1cQLnUXb4rH+8qfzdz52EhbUUJdI7lEoV O4xLC3ydmzFtRmAsSb37xT/vTR3vs7IFlRxFBFwjQTtc1D6PBTijf8mv8aGqtMrj WqU7thdh1e19kxXFlsl9VkWVpGmfDdGsr35huXPPMS2rrGKWdtIgKDmintYcVPyG wsr9OL2Xxk4w5rFrE+YooOj2rqmwl5pT+InAjbZuuCpd6zxg/XqI1n+GFXtQvPP9 CAs/CaeghW+BQeXiMTnzOByUFsbk2Rpr8emw47fAsufxqisXE2bQnpVv+oEvUhZi 2eQPA6rTizcdINICZpC8i+mWmvhnKB8uhcSIhB1tbB3jKPYW3z+QCV1trNAMIRO8 MiHyWjkyDRnS5O6GyuLU1wOjhCklqDyI4pXW1Mpf+rbFaQieIfcvoBZNOCD3aQJj g+/cOHLS/tbfUEu9nlwag1gUmG6fQNJvj6FMcWU1KkcC8EgfGRHYZTeFhx1Qp/bN Ncw9t91XPVDaqWdi13ohrPg/7qlSpMu61veUFUsWiymb8Qse4drr0bfx8RH/dpFu Z/n/AgMBAAGjggHYMIIB1DBVBggrBgEFBQcBAQRJMEcwRQYIKwYBBQUHMAKGOWh0 dHA6Ly9jZXJ0LnBraW92ZXJoZWlkLm5sL0RvbU9yZ2FuaXNhdGllUGVyc29vbkNB LUczLmNlcjAdBgNVHQ4EFgQUZG1d46hMpTbuJjYv9VdUT7hSff8wEgYDVR0TAQH/ BAgwBgEB/wIBADAfBgNVHSMEGDAWgBTurG1A6tUEaocsVXv1Py3a7tus4jAlBggr BgEFBQcBAwQZMBcwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjBdBgNVHSAEVjBUMAwG CmCEEAGHawECBQEwNgYKYIQQAYdrAQIFAjAoMCYGCCsGAQUFBwIBFhpodHRwczov L2Nwcy5wa2lvdmVyaGVpZC5ubDAMBgpghBABh2sBAgUDMFAGA1UdHwRJMEcwRaBD oEGGP2h0dHA6Ly9jcmwucGtpb3ZlcmhlaWQubmwvRG9tT3JnYW5pc2F0aWVQZXJz b29uTGF0ZXN0Q1JMLUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwPwYDVR0lBDgwNgYI KwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMBgorBgEEAYI3CgMEBggrBgEF BQcDCTANBgkqhkiG9w0BAQsFAAOCAgEAPihRUdJik1NSvghFQT3PWGumPGO+/Yjd gQ+AkdZgDd/PB/NuJD6K0tNIJ+siKf1RuFnniZIx9hM6W7YrbamCi/MRLh5Ikpig 00wm3M0l9WwCr9UFeIv1wi1kR7HEEg7h7ltkZnH0ueigBse5QhVxUhQLZHd6WsUJ oHE1MPxCkX59VKsagx0yRwOWhV83OJfZHCrx9rnMO74mdfpwfjZ96CzJIyjWlumd +HUMxI+FsceM1f6SZ3XYLEfmNu3SM6zMF2bsSYsnH7X3o1L8gdyRHYZa3vJ6/EzV Et4fHO7K+qZhtX+O8/n0bV18QtjZchLhiCKiGK2NjHGSL55dLLzFlNM7OnViw7v5 +9hCORZBCeKwVsuJxYIMM1hXARyiSJmrJWlzYBQ3/e1Z52Ev2QzI0YeTlTgqzK8Y ydGPmOufdIDZhdM76hw2xo+4qeNirh47O1Op4Lt/wfJxkf00Czu+xWluFnYfpuoL ldHRYYRFFb3JYkerG+wDzcVyd/582OYUTo86O0XqzRYkrcL3jqYgMDCk/ynHePiq PToBvYEjFt68rGNFTvhNdFeQk3D0fyQqulW6ANLwyvpmN3ghfjjCKZIPYUv4nOKi FPj+UNisBIvRvgzfcc8thGKZVdMtrQNGNtdCXeT50p89Q97SrslO6SigoL11oXRG Uh4MClcBULE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHIjCCBQqgAwIBAgIUd5bVXiltAcz1DO2zcHsN2EJpVTUwDQYJKoZIhvcNAQEL BQAwXDELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRl bjEtMCsGA1UEAwwkU3RhYXQgZGVyIE5lZGVybGFuZGVuIEJ1cmdlciBDQSAtIEcz MB4XDTE5MDQxNzA5NDY0M1oXDTI4MTExMjAwMDAwMFowdjELMAkGA1UEBhMCTkwx GzAZBgNVBAoMEkNsZXZlcmJhc2UgSUQgQi5WLjEXMBUGA1UEYQwOTlRSTkwtNjc0 MTk5MjUxMTAvBgNVBAMMKENsZXZlcmJhc2UgSUQgUEtJb3ZlcmhlaWQgQnVyZ2Vy IENBIC0gRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC1eMhxwuN0 wuOHZ4BKXo/1Jar/1cepiIFcOYt1Gs5s5KLyUDnM+dYABhUz0WIf7vauVvPcjxs8 Nd++Zimfg7siGwu+1bImvRYGpIs2iFtGomnQK2n/mN3Wiuzwbc9KqVOBvkQPC7X/ TaNrKzmIJetBsbQtmILsCgv91vObjRoQZlKul250jZiAaWAuycC4FcPYDd0tTk1y Ux0q/1+uR1fNBVMRa9TeR+uovy2XHZmrxND0M1w4KZ2EoaTT/XP6bNxK9K3907LP ytkdUQ8zCyOV6/mJYLyoytLPTT4lUqtpY/ij7yvEN0DtQmeukmVSuwnaVLYPHETD KlpzbfZXy+Y1PT1xzz99Yi0LiX49uUZj+G3t9SrocL3NJIca2KoYxLM7JQOaqEkZ eTWwD3ieHMp6OvEkj4w+7qUN0hTZ7zzkW6mSdO8gKRmSOfCvyC+0N3vGQcSgrgS8 rOB+FuoLgqMWmrswZhxCxi3f+Vjt7u5kcjb/RTkpJf4RkBKMVeEB52EaBZcpUOhn IkeO8XZh+sywZV2bWsc3mpuXAnk7fkg+UQLzXjLycQIpRWvj/M0PYMxenBWf7NAY CMsFkBsoz9QVguxAjFHONpue0Z9y+/8/Phtnb9w8XB9mEiemeS5wqorCViKfV999 I3AgVZHxenrebsFs6cmZPEuSvEWfIhkytwIDAQABo4IBwDCCAbwwSQYIKwYBBQUH AQEEPTA7MDkGCCsGAQUFBzAChi1odHRwOi8vY2VydC5wa2lvdmVyaGVpZC5ubC9E b21CdXJnZXJDQS1HMy5jZXIwHQYDVR0OBBYEFPGOaY4+TmFUGs7WkpTSgoV9+rlA MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU/2h1Qn36b8dakzifNUTQ qi0AsokwJQYIKwYBBQUHAQMEGTAXMBUGCCsGAQUFBwsCMAkGBwQAi+xJAQIwXQYD VR0gBFYwVDAMBgpghBABh2sBAgMBMAwGCmCEEAGHawECAwIwNgYKYIQQAYdrAQID AzAoMCYGCCsGAQUFBwIBFhpodHRwczovL2Nwcy5wa2lvdmVyaGVpZC5ubDBEBgNV HR8EPTA7MDmgN6A1hjNodHRwOi8vY3JsLnBraW92ZXJoZWlkLm5sL0RvbUJ1cmdl ckxhdGVzdENSTC1HMy5jcmwwDgYDVR0PAQH/BAQDAgEGMD8GA1UdJQQ4MDYGCCsG AQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDDAYKKwYBBAGCNwoDBAYIKwYBBQUH AwkwDQYJKoZIhvcNAQELBQADggIBAAft+b1uQd1yGQPJrrWR4zbjoxlepwFVmHW4 4QAjdxQgCBnByobANcqfHszNA15tEduznUXkHlgUUV9hT2LUkz/ozsuaJB4x9635 pjq0d2hlE7PwU0JW8EFqsc7nqdQXIJ2SYqRSzxbJ851XwSwX+wG+/od6uVxdW1pa qk+WX6xKQzpM2bQpR6WudxBBOb0AO257mVB52+on/rIGS06GqwGEg6ltQW57t8fk MG6eG5RpRKTd4ild0Y1fnYcqg8ORLKUNVDZk8A0Jt2NmqFeB+02wXFxNnaRaXHMz b5J+LrVxJ/p/x+2lFmPdNaxK9cnpZfDlBToYlpojej1KXmR/d6ghW1OFJHLhTW4h guSOiAGOM4AeQEMVOhVJdqPyw2FLLqB2YCaffObG5WCG3xcgHxj+7Aibii3AMyVT hP08Ssqm4hlG+Z2MD731wNaIV/7d0hLqq6zX7SgsrR1QWc5vz2LFX8qP9tPDaotq ugj6r5WPChUHoCHcu6vK8eiC+ZTOmWhXJT1YsBYEH1/7OMhb3azuprdqQpLkuTxM zqN2xQc8dUnSjjnfTVF4h/+w0Mz3ALhnOUUawLeS39OMmcI7dsjEDT4VsRoRqUmf T4ghnrWHIXhSJv7CKTf6GwAOj23yY3fjhstx+pHyy54p4dq3hLUPPKH5dzv2u4w7 fH+M9yjW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIEjCCBfqgAwIBAgIQQAFqLJVqNXYKqgYC2wj8GzANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTkwNDE3MTgzNTUwWhcNMjcw NDE3MTgzNTUwWjBIMQswCQYDVQQGEwJVUzETMBEGA1UEChMKSElEIEdsb2JhbDEk MCIGA1UEAxMbVHJ1c3RJRCBISUQgRW50ZXJwcmlzZSBDQSAxMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAoEyKBz3/fM/JAX9I1QNhOtPQkzBdiQr/12dX vupJ+j7J2UfdfpiPVu9u0w//clPwSBtLAgNqevtXrgS9LXPFBIY0QZLiyY7B4q/v 9h0SeE4N5hggOO9a0PsV3kHAlBdPWmO9McVEq8PGIU7fXTKDCsMGK0RYAHVYQtox u2PY33UM55IQJYq6EQeqXZVucVg9MhAGZnoXiBYZDw4ttIX3q4GTGkA0mrY5JDfE K1hdj2AFrne6MO/dGRyc48zJvDBC/l4Aaj4ltBS1+XDT6kF2C9GesZXVdLJvQEHo jlVKyJ5/cmkeDZrmzsHd4dxAkZxRpio82GxMRUTf54VsPuReBJfE0rakweNV1Ouo ULlZ4EhrAUKeN8uQEPoCkTifDedrVbu3Bh0tAQufdqGw7agvp/ycIWnOzNMtWhC2 vd/OEPDnbfTBrrLQNcbVQnDCwnRWNoMOSCGWjAej6RPhCyJ77N0X+4FXP8Xbq7ap op70bf/JzcdF5zJFyGIJH1DaK6o7jrmhf7PE15Hl7mapxWTARVO0449XiJMvUqVs 2GuWm6+U5jHHZE7/0Q/U1c6c0GeHLZrpesugZFQSLQ1RCukym/GwDxWHdemgKE6Q url4/CZEjePXbc7MsaVu7/pKyOrL16qnKIu5EArWZa2Z37Bvfba2k6nrLjN7NkR5 5IOFzbECAwEAAaOCAvQwggLwMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/ BAQDAgGGMIGKBggrBgEFBQcBAQR+MHwwMQYIKwYBBQUHMAGGJWh0dHA6Ly90cnVz dGlkY2Fhcy5vY3NwLmlkZW50cnVzdC5jb20wRwYIKwYBBQUHMAKGO2h0dHA6Ly92 YWxpZGF0aW9uLmlkZW50cnVzdC5jb20vcm9vdHMvY29tbWVyY2lhbHJvb3RjYTEu cDdjMB8GA1UdIwQYMBaAFO1EGcDT8AaL7qR7vkLnJlTIjjZ2MIIBWAYDVR0gBIIB TzCCAUswDQYLYIZIAYb5LwAGCgIwDQYLYIZIAYb5LwAGCmQwDQYLYIZIAYb5LwAG CwEwggEaBgtghkgBhvkvAAYLAjCCAQkwSgYIKwYBBQUHAgEWPmh0dHBzOi8vc2Vj dXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRleC5o dG1sMIG6BggrBgEFBQcCAjCBrQyBqlRoaXMgVHJ1c3RJRCBDZXJ0aWZpY2F0ZSBo YXMgYmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIElkZW5UcnVzdCdzIFRy dXN0SUQgQ2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vc2VjdXJl LmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRleC5odG1s MEoGA1UdHwRDMEEwP6A9oDuGOWh0dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVzdC5j b20vY3JsL2NvbW1lcmNpYWxyb290Y2ExLmNybDAdBgNVHQ4EFgQUKCJY7wV5HKmj 63uoQ3BQn9AXq4MwVQYDVR0lBE4wTAYKKwYBBAGCNwoDBAYKKwYBBAGCNwoDDAYK KwYBBAGCNxQCAgYIKwYBBQUHAwIGCCsGAQUFBwMEBghghkgBZQMGCAYIYIZIAWUD CAcwDQYJKoZIhvcNAQELBQADggIBAEKl3MRGwB6NB9GlpzBmT9EP8ekOKWkhVLGA 8Tqwk/zOaFQbbht9Ss6IXivM9Dc7/86RIAmZkSM1fQra/cqYnccipeCkl6NK2Csq 8lbQcXK3FdyLOqRlXEf9Ku1Ge7UonDp3fVOgM/4tc3ROtlv+VJ+b3MmztqmZcXXv bLn5u3Kp9dF0h2+e9946aH3zZzCs9OH9TynVYpKOYydQ0ZxCSipbSVKB2Ol3Bm1h th/amLwk9Ecx4ZD+eJpiXsqRo/bSncETssu9OU48Ol/Ot7uUGPlsPM9A/9AMeceo QnOBxEmlQlrExaQ6+mgmkPDdSI952T2azDyjDf9NrqYJoTvtWwJIAL0hrJcCiYtr +Ep/koXntyNe7c/D6IZLQacgXMToO6svWAprVFZZz88JPXe3zNjZphuTUMQq2/tj 73rZnUIyhNDmElZD+lD8kmesDhTuIe5BPYALvAm6MjTU8SUlFm/HgVrkOTwS9hhM AOxnM341ontR+Lx4h/u60Fxbsm7Y5QC6Nnz+nTjw84zH4o/3jd06E4nuTHOWQiJL NUXjnhtfchXCjVtSYs1kKgXjnXnWDCbmeZ+fS2kSbHX6JEt0dGLD5RTjWArvwsqH gxIadfw/UNdXqCzJTHaDSrGdZAQzbGB5dHtBl911GamQy5ynyfBRLPO98gtUOsZ1 hWmgZv15 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHNjCCBR6gAwIBAgIUJO8e7W/0SPlK0tGWvdPRZNzK+JswDQYJKoZIhvcNAQEL BQAwaTELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRl bjE6MDgGA1UEAwwxU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFBl cnNvb24gQ0EgLSBHMzAeFw0xOTA0MTgwODE1MTRaFw0yODExMTIwMDAwMDBaMGUx CzAJBgNVBAYTAk5MMQ0wCwYDVQQKDARDSUJHMRcwFQYDVQRhDA5OVFJOTC01MDAw MDUzNTEuMCwGA1UEAwwlVVpJLXJlZ2lzdGVyIE1lZGV3ZXJrZXIgb3AgbmFhbSBD QSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANEmRf9a6VvvUfEd Qycq0IJzCoixl2o/BK5t4BsQfe/Gk3EMUFPoTI6MStZ0JtdE/D/90GMkX6BduLC5 +eHGuYhCPQE06vKLtxjwRg/n9s24nTRwgE0bcsyDaIQvK0CC8Mm+CY6uQXAIFr1S /Djm+RCl5AxJdUKOQyfCYO6mTtxRR+3/7rllCBCr1HehIASROlFE+C8SSSJd/tBI no6oRfS48KuekzIWy9uuUD7VyE/xLmOG40dEZLDi7jFE06VYny1MYxGzlpnllgYJ CvqpUpEJLZi+Zj+4PfiXLIBCkyOJXX310N9Db+Zy5knYQyD/6X5U3poxuudHeHbB QJQUW1IzwnjBTKWfAO2TdXhmGAse4Cjmqw5HJBmflh0k6kJ96j+FurnFCyXLfEDL vDSaghtOBQeDG3yrW1mgu2Ts7aFmDUZ2SesdhdJ3HYGlKXiSbLl3Q/qBji6TXa84 disSpnnLQBWJ8URqcD6P6oQfav8wmKxnmxObGQYVP/OPlpowoBJ0hw5e45nT4B2J KY+4ObW2Iu673MToOi/2jftxSixKf2ALOGLS/DWtcove9eMztdsDl1G0cNSm2JO0 ui+HmDp1BFgY2EdIHlJBdhATMiXLSz61RBVd4M0J8dovRXi8qvt3LyQ2F9UkaOhc kSFNAz9KvsC9LSTDAVFitjUPmXyfAgMBAAGjggHYMIIB1DBVBggrBgEFBQcBAQRJ MEcwRQYIKwYBBQUHMAKGOWh0dHA6Ly9jZXJ0LnBraW92ZXJoZWlkLm5sL0RvbU9y Z2FuaXNhdGllUGVyc29vbkNBLUczLmNlcjAdBgNVHQ4EFgQUoNJNB+c0pkpaSwmr 1Fgb7UkbgdQwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBTurG1A6tUE aocsVXv1Py3a7tus4jAlBggrBgEFBQcBAwQZMBcwFQYIKwYBBQUHCwIwCQYHBACL 7EkBAjBdBgNVHSAEVjBUMAwGCmCEEAGHawECBQEwNgYKYIQQAYdrAQIFAjAoMCYG CCsGAQUFBwIBFhpodHRwczovL2Nwcy5wa2lvdmVyaGVpZC5ubDAMBgpghBABh2sB AgUDMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwucGtpb3ZlcmhlaWQubmwv RG9tT3JnYW5pc2F0aWVQZXJzb29uTGF0ZXN0Q1JMLUczLmNybDAOBgNVHQ8BAf8E BAMCAQYwPwYDVR0lBDgwNgYIKwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMM BgorBgEEAYI3CgMEBggrBgEFBQcDCTANBgkqhkiG9w0BAQsFAAOCAgEACzsRK/Ux cqxyVFA/k3i9N9bssx9O+1ocQmRzZqBKftPXK20d21ceWArgFtM2I5cn0tiouU3V OVRFrQSIPvcyKdA9nENXKis3ZzUSvJNzTzgulqbT1Bs2sd3Ilfuv5nIERG0kn3ca RoZdMgS6fM9ewngFsnrCgCTeppnbNgNP88kBo7orRrtz12fbfy7Wz3ZyY52Z4A99 FFJoung4iYWU4LflMHXKHLnLZaz3s7RXAARH1qH7Pl+DPYAaYzbtOs8jtQd4fw9l 3l+YrI1UlAYR/gFG4+mPM9C+Ehg1kYYwcLiM9wgsafUzBifqkBO+4ArtWla+QWcB koK35JKWGuNi9io792CCGfwerjPLDhePK4wi2OaDqsi/SbRDqwwyBGrAbr4XWBY2 0B1ftfXZONGoNk3+BcxEto/DepG5XHnaKMPMsp2I+654rPa6xeHK8RBaH5vlgYqL h72LPte1yd5zdTgvJgli+El0YK7A6o3HHB7tt++ZeuF7k/eRXumOs4AKHrnkwBci ojyL/Nhr4oaW9QFWBveqKPrRhugH2AhTEvEbjzYVEpo6JmIO6AZZ5xI5z/q6DLx4 Cb5954sbjfc8GetO2+dppRa8hlhFLchO/AOdOb2FyWcbDZ73vrbT6SOF/CTLa2m8 /DIr5TNOSqSBJu69R+13rvJiQCzk+pzoWBk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHMDCCBRigAwIBAgIUYbb9nTP+qnDwLif7mLdvgoK6QSgwDQYJKoZIhvcNAQEL BQAwaTELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRl bjE6MDgGA1UEAwwxU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFBl cnNvb24gQ0EgLSBHMzAeFw0xOTA0MTgwODMzNTNaFw0yODExMTIwMDAwMDBaMF8x CzAJBgNVBAYTAk5MMQ0wCwYDVQQKDARDSUJHMRcwFQYDVQRhDA5OVFJOTC01MDAw MDUzNTEoMCYGA1UEAwwfVVpJLXJlZ2lzdGVyIFpvcmd2ZXJsZW5lciBDQSBHMzCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANOTYjTlxWK4W34n65zmWrFl i9i13cE1lXd7oLUQhydE7Y+zZOe2KfXPMq4pGJfa0/EELppt4Flny7GBTnc/N+E5 zcHV8Rawhi8qmoHSm+LY3J6cJzKWGYKnezV8CIOD3x7DxNBV3BxkyegXF+gwgdAk FeAO/1ddVTXq0BjWQvEOkfJuQ3Vo7bsG5+YmyBBjXroHN2xLGWtdWZJIjem7OvC6 kYMJkdtz/AsfLFFqC4KoKYysSZ1VD3IxSjulc878vDpAuQZRLBTUyQL+blMggFDw WZp6MUsHFUaNeWWW0pNfS9VTfmBYdSUxEwRCewUm0EFBrKUxnSORkD18q5MhdVt7 tB33zvw/SlQYpF8QZp/TR4uXc4EobYiRz912URkTmcD1v7cETFOHiSQyGrh9BU3r agEdzBh6CGQarLcLFhA9XOSxkN2xF8R9jBPdxIHDJBMv941XqK6wfrKn73WNAfSH o7pniPn242lmivqelTBiSCicr68jYkHmTpSYWPoXCW6LMHM+cJKwSv86uzuFuIMj SkeVuyiiNB4nlvKW3EqgE1gxolOxQE8aglzpENXYgGSnyl4kSp80kpiiUakDH0dY LnbhMGL8vhr07ze9mU1H7vgpumBP/j+0idWURA9BpVNfuDZ1AenirsOuiYHcxfGp OZ/XnWndAi7YkQuN4tR/AgMBAAGjggHYMIIB1DBVBggrBgEFBQcBAQRJMEcwRQYI KwYBBQUHMAKGOWh0dHA6Ly9jZXJ0LnBraW92ZXJoZWlkLm5sL0RvbU9yZ2FuaXNh dGllUGVyc29vbkNBLUczLmNlcjAdBgNVHQ4EFgQUxPx31QhImBKHt/ZRE8XLrvs1 g0owEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBTurG1A6tUEaocsVXv1 Py3a7tus4jAlBggrBgEFBQcBAwQZMBcwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjBd BgNVHSAEVjBUMAwGCmCEEAGHawECBQEwNgYKYIQQAYdrAQIFAjAoMCYGCCsGAQUF BwIBFhpodHRwczovL2Nwcy5wa2lvdmVyaGVpZC5ubDAMBgpghBABh2sBAgUDMFAG A1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwucGtpb3ZlcmhlaWQubmwvRG9tT3Jn YW5pc2F0aWVQZXJzb29uTGF0ZXN0Q1JMLUczLmNybDAOBgNVHQ8BAf8EBAMCAQYw PwYDVR0lBDgwNgYIKwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMBgorBgEE AYI3CgMEBggrBgEFBQcDCTANBgkqhkiG9w0BAQsFAAOCAgEArJGT+jDqhDCBTp82 1oDcEc8PNptFJ/XzSfShTX51jVC5x8+W4I6h9tDnIYNoZOIoY0hOmnJnCvgJ9RCo vp+jDxJ5DGzOD4eXw1OUHiIVPKFlsm0aNN3maXi3RaAWCQ7ajF/X3PQAV50BHAXH deJYeYJNPcVWdec2hY0QPn6x6IYaGbu0MrhVtsnpFuk9FaOs/gRWW65dpMRqrw0e XmggE5hdueY7IqbrE5j+RP8YrdoUQO8J5DdgD8vvICz6k96x6Z0Mja+X+2z2kkdp +zcwesnKExOxqBwrNO3N5CY7QCM0XZ26PXGmhUqtMUfA1qnWEOXSRzsa2SOMwfS4 vgJxyuVZgxhpJPaofLLkfiSTSw46fVYwPEljGuAHo1gYjaMsy19V0lcCOCiD9yRq 5k/ZU/X8PY407Zv5vT0/7ODSmULeyzW9MROF2IVI2XpDNuPx/95DypgHjjAp1834 p89ONzwjNJdrR73WdR/SfKQLfXjRtfJMyEniEc7ackPyy1EdeXvPhAq6sBte6pGd UrRJbPSSDEtlsYVh53CQQinxZPMKHYNKYjQpY1Tfg875Izsy0KOZAcaA/28uRa7f 3lrUJt+NI/Hmk1gMBIKoXS8rLzplvVxt1KfwJUPCu+wZzACTSN2aMo1k/GnEzq8O j812qDDKUNYZ1rLWPc9355Ar6mI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHdDCCBVygAwIBAgIUJMtQVVRw63mVx6l1jYxCvSQq8NgwDQYJKoZIhvcNAQEL BQAwajELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRl bjE7MDkGA1UEAwwyU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFNl cnZpY2VzIENBIC0gRzMwHhcNMTkwNDE4MDkxMjU4WhcNMjgxMTEyMDAwMDAwWjBq MQswCQYDVQQGEwJOTDENMAsGA1UECgwEQ0lCRzEXMBUGA1UEYQwOTlRSTkwtNTAw MDA1MzUxMzAxBgNVBAMMKlVaSS1yZWdpc3RlciBNZWRld2Vya2VyIG5pZXQgb3Ag bmFhbSBDQSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO2QTjta 47kdkgQdFCE75qNEPJDvB1xQ+PP9v7Hez8VmrOUW+r3Sjp1K4z9c0k4KTUNRZpeW o+Jkqrg8P5OzQ1V6a1vqIZEdCcERI+nR9/0ZRqpc6ZVUHQGZ1pm8wxTj2hbfbIEk bHfDaaXrlE8UWbMYqlD7/shhiiUhm03yEPI5VFhZXk1W8dT11fagYBJLWr5A0jXS AQ9OOBuGY+bv6hWpoON61ANgwoTDzN7a5/mYvYZ+ICV/iGaOXJAoDplaYW2ycrTL S/HlCIPHfqtqTbkPrqdY4/PN1RNYr/+JcoFVHkk75JrcIRZ1Afyyk8l9JX+DpIIb LS7LQVzFlzwQ3A94wJ8Q3hrfnEWQ32rvzE2+8aTBf+8adsTnnIUFWy2cHi/b1vUK 7E2P06KHcbkRmD837qwRkBDDCMQHO0ochfpxfen5eRFRT6JNmxskClk9A+JguJeY GxyNM+kRCqN2YLGbIoUmaVC3U/L14bkHzZtgNwRN4trB9yGkI1VfzBEpqxQyr9/F 7uu9T1iFjhP1KWSKaTDUU5BafeCVbWaq/95/BubTGsQi2XNyoAPIE+0EhmgLpNdL lCfbI0F0Hj5JchrzEoYJxk9ohi0ZuNDm5xmOR6OZpPM8iwf+M17VeP9lFb/7Tkw8 O1e4UcYfjF/RuXUOPDh5GNH24iTSnjfjC3WhAgMBAAGjggIQMIICDDCBmQYIKwYB BQUHAQEEgYwwgYkwRgYIKwYBBQUHMAKGOmh0dHA6Ly9jZXJ0LnBraW92ZXJoZWlk Lm5sL0RvbU9yZ2FuaXNhdGllU2VydmljZXNDQS1HMy5jZXIwPwYIKwYBBQUHMAGG M2h0dHA6Ly9kb21vcmdhbmlzYXRpZXNlcnZpY2Vzb2NzcC1nMy5wa2lvdmVyaGVp ZC5ubDAdBgNVHQ4EFgQUQ+41v2d0P5/MZRXi2cVXJdhBiNIwEgYDVR0TAQH/BAgw BgEB/wIBADAfBgNVHSMEGDAWgBRD600A05WTzqZ8QA1tEb450TKu4jAlBggrBgEF BQcBAwQZMBcwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjBPBgNVHSAESDBGMDYGCmCE EAGHawECBQQwKDAmBggrBgEFBQcCARYaaHR0cHM6Ly9jcHMucGtpb3ZlcmhlaWQu bmwwDAYKYIQQAYdrAQIFBTBRBgNVHR8ESjBIMEagRKBChkBodHRwOi8vY3JsLnBr aW92ZXJoZWlkLm5sL0RvbU9yZ2FuaXNhdGllU2VydmljZXNMYXRlc3RDUkwtRzMu Y3JsMA4GA1UdDwEB/wQEAwIBBjA/BgNVHSUEODA2BggrBgEFBQcDAgYIKwYBBQUH AwQGCisGAQQBgjcKAwwGCisGAQQBgjcKAwQGCCsGAQUFBwMJMA0GCSqGSIb3DQEB CwUAA4ICAQBvtfYjrP0TJTbTHtDVeKfVUxJpWGL1OsqjWgyU/n0Afi51vTMUR5kF QXFMOTMOsns9vGMelQXOUM0aG95ubaESaATdLFnAfMfAt2lyxX54d7iNyIqlgVK/ N1StPt9jEELbkwCgcyDdYqw0dDfRoHWeZXyZ8J+676CR7SFOMUghh4z5hzkPGiJq lK1TGEu+g9rIVldlMSzHYk7f8qYFsNG0o58uBoQpAfXAKm/aHRmGXB/35g6Ak+Tb KLtj+U31qzLb4sOnQ14kHJbldU7xiCw1+e5LiIAc9HyqGy7sBl4XYtgdFZqHBclx YZhAbe6tzZD/r2mRh2OdFYrVKQ2FGWgSmGIML1Q4XnhgdZCXBen7bCIdR2ncRWnp KDLQJvDwmoDzu0gCU1Rq5LLENX6RzT7FR64APaO9BSsBt+95zAhnTsPE7qSYL3Hv cAHjiMOmZzL4zHbgx/v5cvXlQoRQnpEMCRmy9KDV2ued0TJ4851v0MsRgmMi8Jtx 3L6kofhG2tq8+eXVGRRDXxDSzd//fZQHfzy6VpQC/zv01S9sobjXRYejDQFrkbfq umRKzeCBiWZqnrYuXBdd0g+7SlDpq1GzqFqvpS7yXzy9O8+RPY/LWi9x4w1rxl2u 6Nc9U3EvmE86vuR9CKq7iJw1gJlN8LKArk2YaPr9j0+uJYfORf37PA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGJTCCBA2gAwIBAgIQWv173AAGcMbgDjGP9VFEgjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NDI0MDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBgDELMAkGA1UEBhMCR0IxGzAZBgNV BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE ChMPU2VjdGlnbyBMaW1pdGVkMSgwJgYDVQQDEx9TZWN0aWdvIFJTQSBEb2N1bWVu dCBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj51+ TjRZu+DrIrTE/lMeFUqx/Xur6S+EIkUXptdm9bZNjlYai5e9yfbHhG6fyEijlT5e jCJ3eNGb/XHrq8CdtXR7xpzFtPptVC8/4vuNgZowMHNpcLQKEMHNNBAqQ5Df7K5X 9VjpJCBeIGvtfZ6mL7oq0wQc7plhl8rZi4HFzOrPCKM1svKIWcrJE89mJr4ZxvNL BOJ7emiyyaqcGX23U4fzqQkMwpKDr4ad32DT2+nvm0k7utjFCa7Qj5XGxlpnyAbX YPcksl/2speB/PPIlt9+5sI2fEcTm0z/19rmO0sOSt4yJv6yY/HA97X+An8d08cR 0GHzFSa/icB/EviTEQIDAQABo4IBjzCCAYswHwYDVR0jBBgwFoAUU3m/WqorSs9U gOHYm8Cd8rIDZsswHQYDVR0OBBYEFMxrzya9+kwtT+sMXyju49mHA+4KMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMEgGA1UdJQRBMD8GCCsGAQUF BwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3CgMMBgkq hkiG9y8BAQUwEQYDVR0gBAowCDAGBgRVHSAAMFAGA1UdHwRJMEcwRaBDoEGGP2h0 dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6 Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAl BggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0B AQwFAAOCAgEAP8IBFyNqtKm/M0rsGCxVvCM7q78CGaZ2F8K9PJJFhYLvksy/9hsF 3D3KBdjwFEvVyZiZxxByaByRb5XkpmAnbBEfkIV9TLyhoAeykoRoVqGjbTXxrz+q qmSUUw506OjaL25IDshoy7s+gY4/NMALSNj5NTYJvX6EqEh6EYETPxmeG9xvhIM5 VO7+6eD7IpSju4sDUGyb+7veAeVOUZQw7nAIeQDm4l9MDeUXJb46hWPg0zlCyAqL dMz362ADqbC27p6ck9Xfdv5CcufoQ3ZftDQrKemTSBFdl5/yNK5tI2DQFqwI8ajd ckzgsJzEqHCzoo0Rtp2wLtknY9OuDrBPOJFFZgFDg+vMrNeLN8i3yBCaJXDssdwJ Eh4OVad6JCnTcQGsD2pibiQX6HHQtOSUcNgZ4vSugHjqre5jVyNk7w3b0p1pDtYS iWWhfwuIRhtpJa6/UJCXP7lWhuXpD5VgPnSxmiaJHKcQNI5GF9KoDfAeN3aJEHgi aEtECAOiIRVRlgOpkGxD3wpDat95l0VVu7cZG5VWDcCkja8DXjZ+jmNJSeUZmLp0 80nnOpSsH5SKbMXcc9qAWaNNlbOp9KakN9G8KjmRmpHVJrharDLuuVlNEHnNOTkw Q4rf6cuhVzsdT3mgxCRrio6sqwW+jX8JiI8c8Ejz7bWrvptX5NVJ6LM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvzCCA6egAwIBAgIQDq4EhhYgr+B6uMqiqIQTXjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA1MDcxMjI4NDZaFw0yOTA1MDcxMjI4NDZaMGIxCzAJBgNVBAYTAk5M MRMwEQYDVQQKEwpTdXByZW1lU1NMMRswGQYDVQQLExJ3d3cuc3VwcmVtZXNzbC5j b20xITAfBgNVBAMTGEdlb1RydXN0IFN1cHJlbWVTU0wgMSBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAMyU0ZIguVyV7JnNRyG+sqrwhe4EQfhzmPgh pNlnb2Wk67tdfPblp6YGBIht/rM8K3d9k9dJCWlDrEmWPNvi2C0R2C3Z6BFhtQ8o P/dmhDu4fW5qUXeHBpGxl3ySmxC9ir/bcE8R2nVlkIZDKmeL4Nf9dsIUmHAbRUf8 DkDqvTzbemEEhWFKX7qdGxp6mEEEodFDn9IQoBqTt4x0wD/LXd9NkVpal018rUWx AA8JdhIKTcXi8AmX5xbwIudJpMkcXv6RYN0TmSeB9w9EKmYU95K54UKi7h3ayQGo y1oQF58sNkSE8Eza9it5PU7wZBuKMNdpTSmSPL4I0zbD90owCaUCAwEAAaOCAXAw ggFsMB0GA1UdDgQWBBTxL7V3HPSA65eF9GgQ6MSnnkeyVTAfBgNVHSMEGDAWgBQD 3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUH AQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYD VR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 R2xvYmFsUm9vdENBLmNybDBtBgNVHSAEZjBkMDcGCWCGSAGG/WwBATAqMCgGCCsG AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAsGCWCGSAGG/WwB AjAIBgZngQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzANBgkqhkiG9w0BAQsFAAOC AQEAGAEOvzJ/m576RHn+moWtxuNvJwDz5RS4WcjLbBlz9vKhVD3sCEyR4AvdMo4U tEUbwDPuqxxjItE+yq96rScNTTRxzrH2rn0EGsQO830bO/OKExyabXqZg4OovlX9 ZJ5rA6juZ9hz/9XZklhxXVZzClcY9MRf2xrSZsV4cfGFE5V6x/mHtnF7lrxfjmLp 3DdDmj24XLZxefp9dufoAxgM1b7PIeBB1qITnAjIvhiPVWJVktjc6fk+j4T0qDbe HMWT2NvORdQjJUwEj5zKwaubilKgHYf0vXhRwCseKr5Fs5YuFaagyf0eZr6vpcOq pypkRF+GZD7aVBj7oI/q6bO69Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtDCCA5ygAwIBAgIQDz+C15Nfgv4UjN75z4+5UTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDUwNzEyMjkxOVoXDTI5MDUwNzEyMjkxOVowZTEL MAkGA1UEBhMCTkwxEzARBgNVBAoTClN1cHJlbWVTU0wxGzAZBgNVBAsTEnd3dy5z dXByZW1lc3NsLmNvbTEkMCIGA1UEAxMbR2VvVHJ1c3QgU3VwcmVtZVNTTCBFViAx IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3AaofIIPmTqsLbpN eOVz6+kV35EIliPib9K3HlMDELx/B9QTw4xnJBiey5J6berhTfP+2ekl6BGHAvf+ Kr6E119aNAtZTZ66EjNhZGvo1rij9nezhLpdma9e98t2nmwIlR5DRRn8mPZCPS5C a4Tu0O653ztyA4CrGIGOy/PTYdf2OPed/eiZRiucvp+e7tuFNsIJVxQJIqtN385j OcOvp6nq/Au/ByeHPIA859e/SyWxuaOaFHxKvHyoFMkyECFpc0676G4UEYUd9wCq xkpTfvg7kIIKJUsStPJRhdD0Lm97Qjpr37TU8U2UBSc/j2ir5JI2Gbyjj9NdYPbX xrD62wIDAQABo4IBVzCCAVMwHQYDVR0OBBYEFC1z6GjzAB9yD5c2wEAaUpHh91VG MB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9jZCvDMA4GA1UdDwEB/wQEAwIB hjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB /wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp Z2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsMy5kaWdpY2Vy dC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMEsGA1UdIARE MEIwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2lj ZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwDQYJKoZIhvcNAQELBQADggEBAHQCpooZfTUM tm92hD7/X7XiQeV1NbDL7oCJXHdpECoBnGk63Sa4SSg6U5y+Iq9LC84J9rz8/QnN TgmP5WU/G+E6qhOLkhq7Z4w4h8q0qNyl01fPTyYaXZahDH0Vik5okzrBiRwzJEd4 Umr8nID4e0JzGCE1/XJShQU3op0hDpPEpZdQnOxMJRCFChi3UypPqjIjM0fjHxK4 A6LJ5QWS5rAtQJq4nLPIKCNDAVx+HGZeZQVuLt7Lby1WAf1M6d3t/HRFR2Dv34td dwKgvv33mEqTm0XuiXcuRQn724MLH7a+lr1FuclIh3nFSfc43EpFbrtUK7XELDAk 6ZcIy2P3yG8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID+DCCAuCgAwIBAgIQA88eZXjGXrL3zaF3t/3DZTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA1MDcxMjI5MjlaFw0yOTA1MDcxMjI5MjlaMGYxCzAJBgNVBAYTAk5M MRMwEQYDVQQKEwpTdXByZW1lU1NMMRswGQYDVQQLExJ3d3cuc3VwcmVtZXNzbC5j b20xJTAjBgNVBAMTHEdlb1RydXN0IFN1cHJlbWVTU0wgMSBFQ0MgQ0EwWTATBgcq hkjOPQIBBggqhkjOPQMBBwNCAAQtt5UJijO4BHsBI0D0YZisWv/zL6mtZ7bFDHav HWECnEBly0fYlJhwFwScbR8EgMCDXH22KI5O6jq8wCpP3VR9o4IBcDCCAWwwHQYD VR0OBBYEFMm3Q54z67acrowgVgjQKHy0vamhMB8GA1UdIwQYMBaAFAPeUDVW0Uy7 ZvCj4hsbw5eyPdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYw JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBCBgNVHR8EOzA5 MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxS b290Q0EuY3JsMG0GA1UdIARmMGQwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEW HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCwYJYIZIAYb9bAECMAgGBmeB DAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMA0GCSqGSIb3DQEBCwUAA4IBAQDJN676 Tgdp7RJJsK6W4pp+EU2V9LYx7AOL+YWlQozsHJtNWFwaHZESXz4ONIFRS3Zn/OyR tv0d23eXn+8IVuWTvOo/FR21Ua1qq8/g9dRP67CiTEZDIpA6VK7vfUqVmknYuu0L dUbnXKWCjeoQaKpkc5E779m45hcviwXEsqOBdWIgt1sqA2fbUbJJsg1XsOLS8SqH unkfclzHlRizZ7CDLM6hoDS0cisBHlHydaeSUU0vz9lxpGyYmy1jKMJ+UjiChOXA R1xHduaZzku4MpNJx6Gi1HkrSJ6/r1JsSlkkogRL+CGBICYoFUmLZsapIcNfYGqb Wwcd1f7oZkB6+2kS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID7TCCAtWgAwIBAgIQCvJ9uaYFXvn1SRvcPvki1jANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDUwNzEyMjkzN1oXDTI5MDUwNzEyMjkzN1owaTEL MAkGA1UEBhMCTkwxEzARBgNVBAoTClN1cHJlbWVTU0wxGzAZBgNVBAsTEnd3dy5z dXByZW1lc3NsLmNvbTEoMCYGA1UEAxMfR2VvVHJ1c3QgU3VwcmVtZVNTTCBFViAx IEVDQyBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGB+fE2dRGT8EZXrgam7 yoixdqJPmDM6doueDLOkVuFnxAA2SyfW9LYuvQ0A3DQm8ynr7imuS4NBzSGOpYPz 4KOjggFXMIIBUzAdBgNVHQ4EFgQUq9SIVzuXBMIcz3dHg9sJK72DPYYwHwYDVR0j BBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDgYDVR0PAQH/BAQDAgGGMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDQG CCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu Y29tMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E aWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwSwYDVR0gBEQwQjA3Bglg hkgBhv1sAgEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t L0NQUzAHBgVngQwBATANBgkqhkiG9w0BAQsFAAOCAQEATuwqW2pXN+kFyR40FIOU 8M3qc9bSmZu7t3T4cqkP3pAv7VmWg34n7PYTa2oBSMcSiCdoNpkKSsfE/v4oXkn1 dHOzJFiu8OtKlazI18nGg3CynRxBOxD8Z2tX8Nxf6dVWhvqOKRrJcawPXwxG3CNK QdeyRTUtTqf4K2My7w/SftUf5VrHfxAgHzLlwe1wBRt9jttOhfqvI/c9kqoce7P5 tFTjj22/Y5XaPW/Uz/ysUIAKsCJuakG7+7VyBuHq3pG4ZpNAzAUSPRXYqejd2NPX 8sXsJtoh0DXtCGavqWkkdIcaMhI5dK2mjCiGUdR79f3RRNh5f51MqXU2N++GxAyX uw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFZTCCBE2gAwIBAgIJbV2+lpv37LNTMA0GCSqGSIb3DQEBCwUAMDwxHjAcBgNV BAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UE BhMCREUwHhcNMTkwNTA4MDkxMzE2WhcNMjkwNTA1MDkxMzE2WjBLMS0wKwYDVQQD DCRBdG9zIFRydXN0ZWRSb290IE1haWxnYXRld2F5IENBIDIwMTkxDTALBgNVBAoM BEF0b3MxCzAJBgNVBAYTAkRFMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAh63RpvKi3N3jX7Bh2WeknfUt8fwr3KnzMiEr0eVSg+Mveyj0mk7InFnh9GMm qZDhP+01mRIw59XDmZnDaDS0MTaIGHtJJ4JoWFihOwAaiDucyrXHm+u3ufSxWw1t Sm8TOMAFphUmkK8WLEbdE7UxoMsgW3G9qJgdE3ctzm/4Mn9QngynwI+FwX9mUa1F v5LJTV48g1jD2FEZw9+wYn4IKu2prrC/3lFpej0+pc1dUUnod17+bzD8s2+fEmlC WFVkcGxwSbQiG9trT8RysxzRRGLzA4SbLWJS14R/enkTztB2PoLV6QvrKSYLrjNc gKFYsbfbjDrgZNi/YVL6BZISbwIDAQABo4ICWTCCAlUwEgYDVR0TAQH/BAgwBgEB /wIBADAfBgNVHSMEGDAWgBSnpQaxLKYJYO7Rl+lwrrw7GWzbITB2BggrBgEFBQcB AQRqMGgwQAYIKwYBBQUHMAKGNGh0dHA6Ly9wa2kuYXRvcy5uZXQvRG93bmxvYWQv QXRvc1RydXN0ZWRSb290MjAxMS5jZXIwJAYIKwYBBQUHMAGGGGh0dHA6Ly9wa2kt b2NzcC5hdG9zLm5ldDBEBgNVHSAEPTA7MDkGCysGAQQBsC0FAQEBMCowKAYIKwYB BQUHAgEWHGh0dHA6Ly9wa2kuYXRvcy5uZXQvRG93bmxvYWQwHQYDVR0lBBYwFAYI KwYBBQUHAwIGCCsGAQUFBwMEMIIBEAYDVR0fBIIBBzCCAQMwgcCgfKB6hnhsZGFw Oi8vcGtpLWxkYXAuYXRvcy5uZXQvY249QXRvcyUyMFRydXN0ZWRSb290JTIwMjAx MSxvdT1DQSxvdT1BdG9zJTIwVEMsbz1BdG9zLGRjPWF0b3MsZGM9bmV0P2NlcnRp ZmljYXRlUmV2b2NhdGlvbkxpc3SiQKQ+MDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3Rl ZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMCREUwPqA8oDqGOGh0 dHA6Ly9wa2ktY3JsLmF0b3MubmV0L2NybC9BdG9zX1RydXN0ZWRSb290X0NBXzIw MTEuY3JsMB0GA1UdDgQWBBTM4mc4rdlU1jc3JhvGt087SNaZXDAOBgNVHQ8BAf8E BAMCAQYwDQYJKoZIhvcNAQELBQADggEBAD/I1QDV2wurHe92UyIhI7HQ68qd3ZfR xphtVybVTLTzT4zHOJRzeV60nUUAZdWvlGNlJkGRrhTttHStGVEQ1kwR2ahmCSQc KWL6WkinAqiwTbm0+I2ejmLe7R2uQNMxhv23579dcV0GAWwpDovpP2olhNpFhDbc ke2hvCfEPFqDzmTl+fIZgLOleJgWCNPwRI8YZ9UzFRdvj5YZnjC77E03mVHxGNsO J/CkWEci9jeIOhhmqlfdSRHwReLwk01rVKmZu14gUCX2yWrP7uAOBEvG9pbVezW6 8XgG7JvBVfQLKofUaNXSTfiSelFwbhCrmJDHEGdSdbfzc+6ye6ngOWI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFezCCBGOgAwIBAgIJEq8M0hh9sUDEMA0GCSqGSIb3DQEBCwUAMDwxHjAcBgNV BAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UE BhMCREUwHhcNMTkwNTA4MDkyMzM5WhcNMjkwNTA1MDkyMzM5WjBhMUMwQQYDVQQD DDpBdG9zIFRydXN0ZWRSb290IENsaWVudC1DQSBmb3IgZXF1ZW5zV29ybGRsaW5l UGFydG5lciAyMDE5MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALTUkWEF7nfCRLNM0ARzu/zc3eah6qU0 Zo8Ri8rAyDVbckgRQqsB6EQ8PXap8Nt7pCsp/cjOo6oaVWVHjWm3SnoHHna3UBJX zrIWMQxZ6C70Jg9RuH0volKiByZVC2xZGNojx2/y6uLG40s3AsGIZv0xL8XbvxZ9 BjULQLm7I1A/okQ5WklwhjKSt+PgzikXAJ7jDmW2Adf9OKJOPIkhnf2//uxJngsI 5T8aH1MqkmLvyUTDG1abOLu3BxnqzmGZb1G7YV0SsfNLB7bx+diWgYQQhw34/aOG BP/b7Acg88DFcaYCwT3gKReXdUp89oybFlYK9J4ZQb3toUXZSYHbyAUCAwEAAaOC AlkwggJVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUp6UGsSymCWDu 0ZfpcK68Oxls2yEwdgYIKwYBBQUHAQEEajBoMEAGCCsGAQUFBzAChjRodHRwOi8v cGtpLmF0b3MubmV0L0Rvd25sb2FkL0F0b3NUcnVzdGVkUm9vdDIwMTEuY2VyMCQG CCsGAQUFBzABhhhodHRwOi8vcGtpLW9jc3AuYXRvcy5uZXQwRAYDVR0gBD0wOzA5 BgsrBgEEAbAtBQEBATAqMCgGCCsGAQUFBwIBFhxodHRwOi8vcGtpLmF0b3MubmV0 L0Rvd25sb2FkMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDCCARAGA1Ud HwSCAQcwggEDMIHAoHygeoZ4bGRhcDovL3BraS1sZGFwLmF0b3MubmV0L2NuPUF0 b3MlMjBUcnVzdGVkUm9vdCUyMDIwMTEsb3U9Q0Esb3U9QXRvcyUyMFRDLG89QXRv cyxkYz1hdG9zLGRjPW5ldD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0okCkPjA8 MR4wHAYDVQQDDBVBdG9zIFRydXN0ZWRSb290IDIwMTExDTALBgNVBAoMBEF0b3Mx CzAJBgNVBAYTAkRFMD6gPKA6hjhodHRwOi8vcGtpLWNybC5hdG9zLm5ldC9jcmwv QXRvc19UcnVzdGVkUm9vdF9DQV8yMDExLmNybDAdBgNVHQ4EFgQUy0VDuZaMYGm+ HQAzPQ5uWyk4Ls4wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQAw PpzZw391HM65BX96L10//ZnFkwCb2VN6sUpnVUmgXpclKrY+zDkeL3/rN4H8L1Jz oR1vdQsdXMnfQZ+uH5QOmOlWc2znpP5QGcZaUcwz7VQZ7x4gIcvolxjOofVuFRNR hLC3+AbrMOg6Ouaqc2MtbIxeeyivqE3vdF1OREZemG7y86kzZ6lpanaNFrLU34Yz /+vJA4ESRZhUaaXCLoMG3SqUvJvK6+BtmOtnUnZYceu8pUAIY1fRZCs4cE9WIsTA bXyQ3ttVI8lFwxQAIue70qrqlktWa1GDaY7+jeDH1R2yaUAdNviKzSDqi6tGLmTd qg/wlaEdGZ691b+8ZoTH -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWzCCBEOgAwIBAgIQfGrcmTRUBXFrq03rqZKwpjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NTE0MDAwMDAwWhcNMjkwNTEzMjM1OTU5WjCBujELMAkGA1UEBhMCVVMxEDAOBgNV BAgTB0FyaXpvbmExEDAOBgNVBAcTB1Bob2VuaXgxIzAhBgNVBAoTGlNTTHMuY29t IChOYW1lY2hlYXAsIEluYy4pMTcwNQYDVQQLEy5Db250cm9sbGVkIGJ5IFNlY3Rp Z28gZXhjbHVzaXZlbHkgZm9yIFNTTHMuY29tMSkwJwYDVQQDEyBTU0xzLmNvbSBS U0EgRVYgU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAJibUY5PjHm4reOu2/cghfMj9UCyNclteWaeLPsPqzbwR8DBTfcGmg1R /v+Id0zDYNUpRJzzQWqSI7hlm/qXF7oo4jFLuFyzYw4McFgFHxIvt7W5/W2P9fim +8IE8bs4l84Y2dikj/mFuA2fPr1G0jrW7wxJJ8DdxUnb24j49joSP5sFH9f336oM b5p5Ua45Q1sQ0wEMnDWQUcv4D4/GKCYozjb37gK+IDfVyuaz82iYutej2za6WOaQ X2qqqb2+0K4G3K6nbji4oxJOni9VHhchxkacpV5jbTGMu/t1uKrforlfPgDcn97Z iNYj2A3iatS51lhelu19QOQVw5uQxGsCAwEAAaOCAYswggGHMB8GA1UdIwQYMBaA FFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBT+IhedWWJjx32y4Hu3bJtA cB3avzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYI KwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBD oEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZp Y2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKG M2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENB LmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkq hkiG9w0BAQwFAAOCAgEACquVVtH8DYadSfz0NHvhyOxo2kCpH0njmjrDcGUXTLJa B1yBvLrJG6HIBAqObgEwm/iYIsWUqQ0+tWNIG810cEcSL/bQn4xyoEwvbI7+v/e0 RZsM/WZxdyzpxU4/+ZAivbyAYJcI62Bb5J800BcNFUCHO+icwsFKL+QTxsXLBwdi 0XPqOudcQ8U31+kguCoZAlHQalujVTzOjkZS4yYYG5BZkeRCzOXaLR+8qWm6FigU 2CboVx84MGQZJgRS4SE2FUo7HdCMxIekR3qNsfq0ZSvZ5OCGBHsvv4bvD+LUnUKf DW/Wr3DLjW3qFWDFmNSkyh9VNGAayn5apORSaHN9EzObNqFVaadKWelZ7FvQ8l3c N9O9O7++neiI1H5ZGXBDOXS3UISyESl6i7whKG7aFPMTtae/Kg++vPWrZQL/QyeR 2dYTYYyv4lCndiQ8GzqYaNbVM7Fo9ryet9VV00KnXPTZl1RLVB5ShCJwPvyqasuP XSy2vkccznj18SzWoZZ3Pyb3Q1T2v5BpMLUVIiKCslC8jbTM9ksGyrB3yuyUGrHH dFumZ9rG6XVriXuNQ0XqZYhEj1aJGNUcuZVP/NPWC4NighIW4kpIi0oUyCBQJsxH VAdB0vs6KSqQi4pouaNJboKQduNpRnWWVo5aMRLg389gImoCyki+D4ERklaaB6Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDsDCCAzWgAwIBAgIRAMuIwpyXg2f0Wl/9CVl1toEwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDUx NDAwMDAwMFoXDTI5MDUxMzIzNTk1OVowgY8xCzAJBgNVBAYTAk1BMRIwEAYDVQQI EwlNYXJyYWtlY2gxEjAQBgNVBAcTCU1hcnJha2VjaDEfMB0GA1UEChMWR2VuaW91 cyBDb21tdW5pY2F0aW9uczE3MDUGA1UEAxMuR0VOSU9VUyBFQ0MgRG9tYWluIFZh bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEH A0IABEKn1KzqFEYHIcPCMr7tcFF/FHKVCX2XuT2UTe4uXIdZ6WTxm6550AfLXobM MuozK7PKOVO6zG5FWbfQrIlRUWejggF1MIIBcTAfBgNVHSMEGDAWgBQ64QmG1M8Z wpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQUCiofYImrVycfM/5F86UZ7Rie9hUwDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAkMwCAYGZ4EM AQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V U0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcB AQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VS VHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3Au dXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNpADBmAjEA1Y+Ubw1tOZbnBDp2FxoN blqg5ydztwKNgi88cWLy1eBOjPcK2o8URIRUeeWs+evQAjEA+ZbqqNYu8MlKeYNb NRSSa2+lAXt9w1v1xWx2O9jylDtMIQkzOkSZMzhx8zSg0UNC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtTCCAzugAwIBAgIRAK3ArXFhq4k9s+bgVOsWnckwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDUx NDAwMDAwMFoXDTI5MDUxMzIzNTk1OVowgZUxCzAJBgNVBAYTAklOMRIwEAYDVQQI EwlLYXJuYXRha2ExEjAQBgNVBAcTCUJlbmdhbHVydTElMCMGA1UEChMcZU11ZGhy YSBUZWNobm9sb2dpZXMgTGltaXRlZDE3MDUGA1UEAxMuZU11ZGhyYSBFQ0MgRG9t YWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABIND0n0KjXwPz23GWU8r10+PCOkMWy68+tWWBIXJ+ZgJEt9rNvUe 9R7ta/9bmar3fBBBQ8bDJv1oY2PD8Tx0PgijggF1MIIBcTAfBgNVHSMEGDAWgBQ6 4QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQURKlJvyGIsOOTtIA6GYFFlUf4 umQwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYw FAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAkQw CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv bS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov L29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNoADBlAjABeiGZ0Am/0f14 COHktALxJMSYCb+K8i7B4y9C6wmaYFJi8zWhj0AzkgN48/0CMxgCMQDGpOo6fUPX WEnrmCuYIfHRSFXCTulRFJFseqHB1SxBfnKnyLasYNOoPKXy1t79oDM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF+TCCA+GgAwIBAgIQOly1wtzRaBq2ZZIu681rNjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NTE0MDAwMDAwWhcNMjkwNTEzMjM1OTU5WjBvMQswCQYDVQQGEwJVUzEQMA4GA1UE CBMHQXJpem9uYTEQMA4GA1UEBxMHUGhvZW5peDERMA8GA1UEChMIU1NMcy5jb20x KTAnBgNVBAMTIFNTTHMuY29tIFJTQSBPViBTZWN1cmUgU2VydmVyIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwjmmbw2lC35tLRmhMOVA6T21n7OS 96DHc18Hr7sIeOOnYslkil4wX/+0e0ExyAGmpINuyc9NKxvb6iMGBSpGfmwBWtH/ ZCokuOJpxsj3hU4rdrTzOskm2DX3b5pvW+/vaKDzGqP887xmIT4W/FPRY29zI+eR hkFly+SG/LqgGHS18dGhu2T8UmC+NPRBl0ecjkLnxWmTJ1YPQaj3OXRJVAZaRkb8 SUWJTufKvnTncGKElW/emiRFDo2KWT7Ek55ZlQwpiEeio8Lgr2rv53zTVIFAUHUR 8FfLVqUJPRv+aPyFvn9pux+eIqCyiLPO7Z1q8Z0ov7wNfJmbauLjcsR5GwIDAQAB o4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0O BBYEFJqa52DKwxsxIfeDdk5BMrdPNj1mMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNV HSAEGzAZMA0GCysGAQQBsjEBAgJCMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5j cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI hvcNAQEMBQADggIBAFdhc6XE60bJGk442p5AoqSB55ShLnxNFm86AyGO4TBW/ZHy vBEuXTT/hXbWzstCtJQcR1w8E5pR+AibG3DWuYcfqsyzvYCU9XD2f9n94qKZZNIS Gf/jitYYdTDcvq0PNzHBMqZWdn0yIxcKnfONBHodOUZ2SvkX+D/cWcfViqjAXHqZ CTO6oyitvJOZUsr879f6JMRh3xIHZbCSh8W2uaUMCGkXH4zIXLEp8OQj4YGUAQDb O4P9h7mhgw18NKUTJvKgPXi7WqtJA9jFzaM5LTEhTfnrwdccp1MU2uNADoKPE0Ma ZxVyK9Zv9QoFTNjF5sr+3bOlA8kM548n1QOvSFfC0X4v5EHteONqa3XAYqSJ+LAc poIwa46/w8B23OjkDwI32EAen9FzqZUlvANkMjH82IJ0dGcQ/zM9MKPRp2LGgoeE tWW4XulPnaVG9NRCK6lu7VRocPNaQV+Vp9Dc+Wg8OcmxHK9ElSi4DpkKTZRcwOsF ZsiasRVXc0afh1bCFykO02svmmjuYURiwc4jyNKahbQo7JUJyd5upf9rdUDunTt4 8o1l5RLsaJJY1WS8+/YoV2bBcJId3i+RePjiQqPkfrWOiq4noZwyLcSm9pJgF6Jk NtUJXxms1/Zz6lKUp/ku1ZL0EBjGA+245X7GRnNjn6AP30P1gyJeX8AmbwRx -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHjCCBAagAwIBAgIRAIz5UOB4ZW1aeHa8vGDi7w0wDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDUxNDAwMDAwMFoXDTI5MDUxMzIzNTk1OVowgZwxCzAJBgNVBAYTAklOMRIwEAYD VQQIEwlLYXJuYXRha2ExEjAQBgNVBAcTCUJlbmdhbHVydTElMCMGA1UEChMcZU11 ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDE+MDwGA1UEAxM1ZU11ZGhyYSBSU0Eg Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBTZWN1cmUgRW1haWwgQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDEsmiyBNG2Snww7+vZtJQw33IjJwSK uPTKnH0W7SI6L7rxFxOxsFom2gcLmMc7hKLvCCpjc8uBf676WdRQPYaLVfKamAeZ OAKdTXevqpbtuAxTe3dNvknus1sOB5wcGw0ljQ4JUGvMLwdvDMHy1DPcO/jKGGzW +ojqKpnNyclFWk6fUO4clG7L4AC68XrpKc/ROOawrBIebHjjVjPtkX0OdnBXM8ZY GdH0sEt7SeTBNuy2oUXDEehdjByWG6mmZUWYFCM7SX6Btrrj2/wKV7+hN+dU/vMz pcgBSqXrGdcupE8O8NxpYOXiTe9oYUeCQDybNwlGcLfxSU1LQQazTtP7AgMBAAGj ggFrMIIBZzAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4E FgQUKw+7S/xr9vxO3/HrHc0q/sx0X8owDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBgGA1Ud IAQRMA8wDQYLKwYBBAGyMQECAkQwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2Ny bC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3Jp dHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51 c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUF BzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4IC AQA3t7uHrFTk7CWXr9ADDOw9ac+Jy7sDEBoDTJuTZXVjRAS7orDgY0mECPfUtS6z GOGF1+qc7MPjecpEQvNRl4qX9+gdcAhZ6YFSDUf00d8vNpg6UB0a8IJsyWGrLfkR zdwlOdVZCFDZ9RRohkAmsPntcKKfovGEJwrazUy/bJ0WR/ghKrLoqWXwVGqmNbIA J+YMO2wnfaw+h0tJnuBaAFin/z5e2BGOV3rw7x+TzkKmzW2/cZ8uRQDagadeTSxK wpI9c/ny7QzctE7G6J43bNNmM3FlC1N3pRcNVq7W8yf6dCjZy8xCVSDD7eM1JT27 m+YV92o+mPLDopXMHLD2/uNI7ftjnfIT7S8Ql8S94Op+/69JjgQekzPOcMcPp0mX hWA0DoT6QVccGYTjt8ElqJDdW6PaMfnet+oJpQgKgfeW1VctxiIZYXTw2J4j3zQJ mJ85KxYqT5vklP7LJz0vAkH1T9TzB9O8t/YXI6cSWZ1ODiMIMZ7MfhRgl8+kR8UJ XVGEFJmNGPhJMk77lwA+U/2MSRBkreeLRcnqkHST8YPQSihkLHsiizYHIJin8u95 ZBS4TaPArwtV6MK0rIVCEjA3VwgOpL0TGlXX8W35lw0pILqVXD9LOBdracWjFbHY 8aUJmvNc3nJEw+EiPTdHAJgJrLeAP6JeNQcjE/LC7MuqXw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID7jCCA3WgAwIBAgIQKIBjf65//GUfCnWVUULbLTAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwNTE0 MDAwMDAwWhcNMjkwNTEzMjM1OTU5WjCBujELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEDAOBgNVBAcTB1Bob2VuaXgxIzAhBgNVBAoTGlNTTHMuY29tIChO YW1lY2hlYXAsIEluYy4pMTcwNQYDVQQLEy5Db250cm9sbGVkIGJ5IFNlY3RpZ28g ZXhjbHVzaXZlbHkgZm9yIFNTTHMuY29tMSkwJwYDVQQDEyBTU0xzLmNvbSBFQ0Mg RVYgU2VjdXJlIFNlcnZlciBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBZP PtSFX6jmkcabG3nr44Wz58ABrDNANKgkao3OXoO1XKt9rz772vdZ53u7V5OCrRsy mnuSrqEiC2SiB7/X7PejggGLMIIBhzAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl2 3OA1xmNjmjAdBgNVHQ4EFgQUcCe+tvjCSE/vDei0nzqpKAL0uWwwDgYDVR0PAQH/ BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRw czovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0 eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVz ZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUH MAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDZwAwZAIw ENqPaOnFzbb0v0K3bspErkkGKCwSZS0rq2atMKweF/fK3UFyB/Q/zqIOa7utCjWO AjA94cGDlw3d2qBx0oPuwLWQYzXOTHXt8kPv+M9wO7IOD72Ad1YgA6QYr6N7fsud MNo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjTCCAxSgAwIBAgIRAPBC9pWUwz2C8aEhZefD3gkwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDUx NDAwMDAwMFoXDTI5MDUxMzIzNTk1OVowbzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEDAOBgNVBAcTB1Bob2VuaXgxETAPBgNVBAoTCFNTTHMuY29tMSkw JwYDVQQDEyBTU0xzLmNvbSBFQ0MgT1YgU2VjdXJlIFNlcnZlciBDQTBZMBMGByqG SM49AgEGCCqGSM49AwEHA0IABNABUIPdtvWoTGHsYeKUfVhnXL5eaXW8bDSuL6c3 7O5ZqqRKEjUA5UQSnxP6Uffd+7gfspUpiYgdQeuN752D9UWjggF1MIIBcTAfBgNV HSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQU1i/V8G9z2NUf 3JD5koUIDRpBDbUwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYB BAGyMQECAkIwCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwu dXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5 LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNl cnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcw AYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNnADBkAjBI hTCIsf/U/GItWmwhHj+vEiy3vCW5BDnsziw8a2uvTb6nofHIHU5RY7i/KRvT3d8C MGgv1umC0k23Vo6dmUfgWVWJMhZHxrBw+gNxDc/e8SzPaXTABXYrPgkgNtJjt3kD mw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGgjCCBGqgAwIBAgIQRg+obTrrnzwP9vfsJyy4CzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NTE0MDAwMDAwWhcNMjkwNTEzMjM1OTU5WjCB4TELMAkGA1UEBhMCSU4xEjAQBgNV BAgTCUthcm5hdGFrYTESMBAGA1UEBxMJQmVuZ2FsdXJ1MSUwIwYDVQQKExxlTXVk aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMUgwRgYDVQQLEz9Db250cm9sbGVkIGJ5 IFNlY3RpZ28gZXhjbHVzaXZlbHkgZm9yIGVNdWRocmEgVGVjaG5vbG9naWVzIEx0 ZC4xOTA3BgNVBAMTMGVNdWRocmEgUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2Vj dXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0y SmZmqlCEDCu6mRA7oMQDLjld+rfr64b2HfFFvzHzGzsUWs0fJBQvnpPt9Ia/INPk 9EzW4I+/y3KicJl3b38yhmJlQA0o0ZhfRCHPl0GOjmUQnhkAxPLS6/XLUc1I8uKJ 5P5SWttDTn5z8Xgxm0BCsh+RJyhwyDkrG4ebe7X+FM88elnqQotr2fRw2Qef3QLL a3z5h5pvEPNAWkSZ9TnKr4N1hBPyfCMtlT158e3FViWSTuwaAKR9dcVfzJvx5MpI SuL46utA1N2IwR9guxb9NmA/WB1WHjEqH0gWfwDv00JaBeIwdXpp3g3pJq0dWTUu OII9FAldrAwFkYKWXbECAwEAAaOCAYswggGHMB8GA1UdIwQYMBaAFFN5v1qqK0rP VIDh2JvAnfKyA2bLMB0GA1UdDgQWBBRfte7ROKAfMw+xwWpUW4j3vsYRTzAOBgNV HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEW F2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6 Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0 aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9j cnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggr BgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwF AAOCAgEAfxV9Agv0mnC0zmnxceMNXNXNA7TcVEs05D2HPGJKpdjJ0aYQPS/F7qqt b2y8m2BfsfvSM42vYgslVF7tLu4BAwJDkIte7z111p6GqZzaiqEByFMMw+YWyJ1P RJEQdWX0yo/bcUF7hb+LVAsqtXs0XLyX1gGOXi2IdQp4qLIgjmMdsUEctPVlwjNZ 8o8vg1iSzkF/CIDjvgQtRIylyTCxXubYwzpt0JXhfq5PdPpdPF6DnVh7K1t5SwZC hCd/Eno7IG+X2zLn/NtxG66B1JiKzO4Se+slwwF6zZwkh9TMjsSY/i8gRROGoGUr V48qpg9OuXLuvg4bgimhn6mc+wNHtXeMiKNN5k6EBJKf+soHndqmVc4c0K4ZSscn 0rGUvr7vHXn4RsZB0+NMKG73KhzbVZGcv9kVp/WBQEHSjW9NmHWRfgECBQcXk8p3 Rji65Fn9UXv0rAcEIg5dxdMbRgvldpRyJ1I03+fL4XXrPAcJo0ovyC2g1QA3amSx +DL8i5Sc9rtFL+l4bsx5u0biEZa8IBcsghRcbN8EuMPoUEdoy0kGNnrDTKX1orfW aZ8q1FWBOMgXARB1bCfSM0PtZWAg0vONB4YxB2DqJ7b+gtyjb41Vl45PPqIsuv9Y HPLMt8/11wCzaj/GR/1jluePMpkrIi9Gy1VX/g1qbKNyL6LVl6U= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGITCCBAmgAwIBAgIRAMhZ0MPThi9M/t4T5ZkofcEwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDUxNDAwMDAwMFoXDTI5MDUxMzIzNTk1OVowgZUxCzAJBgNVBAYTAklOMRIwEAYD VQQIEwlLYXJuYXRha2ExEjAQBgNVBAcTCUJlbmdhbHVydTElMCMGA1UEChMcZU11 ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDE3MDUGA1UEAxMuZU11ZGhyYSBSU0Eg RG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAJ5Q3+baibM43SsvMwraU0BPANsORz3RtLNSw4hG FQUgrrPYhmYVwmVmfCIodJLuvhS8tKinwXFF+J5ppNbXCMloKgfdpCGKdg1lZuu/ wAbfzlWwfYLfFThN91NyXNsvVWh2PVIpMSpFO2zxUdrMkdT4PMCuAB6Ro6Lr/h4W SSL7dz6OcnCKcNAEIIzZfOCkPMdlgJt8xldvKfbK90JEH75wgvIMuCreBYBkbr+k hOVSfUoEhBuWI15jQFbgMmE/6ydsTjo/s5CkwnXaiQJiLZRE+2oduyqefvc/liNr AobmCX6YsR3bgi5w84548rMDNMxAaxXdcrZaP4Mgx3k8iskCAwEAAaOCAXUwggFx MB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTqFxwA Ef4yQ6LAUzqjA4rKsAQSiTAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTAN BgsrBgEEAbIxAQICRDAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDov L2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRo b3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2Ny dC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsG AQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUA A4ICAQByPjPgwX/+uJPwlZgOiRqIoGUgwhP2hS+PmMBYGRXZfJo7Wxl91c9WBtJS 1a0GT4rYZX1n6LPE6Tr1H7KnNvgoCMy6UX/Wd8RLbGbQ6mo/3XVjD5K5t0ISgxIR GKHoxrIWX5dcTl3RkWcacQL4tMfQMDe8BqENR4ILmn6t41FXg3VR3+gUW8n7HAPL K2LRVDkApzOA0YPjzuWFoMSU75sHHUeivjcxjjgMI9RYx5NByEudiZB6hOfxPE2W ea1OpEno6fEmpsmIKotEpR+oE3FisBk/8QxMCf2m5GWD/pQ211JSQP4JdH0M70Ly k+vWhqS/HRnvhNGmwq6ixW+k12VKPkymRI/DbpJkt7JpXEDdmZR8NxIpfE7MXvLH hclk5bu9wbtCNwv/Uq6QisS1JPJTGR2yPIA6cDdNCI34wrVVIzcE4oSU0AOhuc98 RFkFk6OUnRZS2yOScFu4Wp7MH718R6o+DbRq90pGZRAldFRnZ9holWweXv96IClR xwpp3gfSRMrMDsmx+LMJtJkZuQa0iMI7Gt/fXPC/ESCCgahsdv0P9kwz21rzGkn3 47YuytCXW+R0gq2secYCxQV1yej2G80Nr4+55tg/YNLyQw53Pxchkg3j4uX4O+6h tMay3VHE11WT0helc0vwdEwj21QYyzojzj66nn2u1h5pqgegRw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGJjCCBA6gAwIBAgIQdP5LjXnvPRqOhThLV2tzqjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NTE0MDAwMDAwWhcNMjkwNTEzMjM1OTU5WjCBmzELMAkGA1UEBhMCSU4xEjAQBgNV BAgTCUthcm5hdGFrYTESMBAGA1UEBxMJQmVuZ2FsdXJ1MSUwIwYDVQQKExxlTXVk aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMT0wOwYDVQQDEzRlTXVkaHJhIFJTQSBP cmdhbml6YXRpb24gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAozwI5ZvXh7jtCPeVITk8cetIU969ZG7R SkEjpV7wvo9Sb5Yl0H7iYqNsUBepgj6SexoH6OdOaG6OPF5/lOvPZRvQFQAJt4S1 D9iUFA1ByTjGTTA0r2fH4ANgLkFwjp4PTcNMUdE74Wv21Pi6bjv74vAhYKIDqCmt d/vuZf4Q9N0lEjRGEqU0/dvvXJhb/cONAKoiqZj1K6+SYm5drSVnoMPsbuN+ajS5 Zoks8pFf+q1CeCRybcf8fyrAiecjR8Yyuh7uPPjfV4vJmtog4HHIKjtiXp4yrcrr tvHWL1rlSi6NKlc1Do8+Qdfb6o3aknWINouDKPZYwvLxiou/L6eH9wIDAQABo4IB dTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYE FDI/V/IFSwlukRHDgdjlyK8NorUrMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8E CDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAE GzAZMA0GCysGAQQBsjEBAgJEMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BBhj9o dHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlv bkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRw Oi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQw JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcN AQEMBQADggIBAGdFrqpDqCnK+7W9bEDZczvr4Q9iV9ow46FYAA47oaBAPKIHyPA4 bQ5T1zeqNdEYaHQLTea80q1i06s2I4/fL0SjqveaU2xRvqusNvrrZPnEDLFAykUI jWqP50PuyxtZ6VrfIze76VhyubSkUVV3rcLAKzLddb6Ubo8Xk/oRcCJ70S0PlOoG O5e+Vxi8goCQ989XrvuDZ93PKAknwkmkjKh2996DA8dETbYqqGJ14536h19hr0H8 XaMVU+k0O8QM+W/hdUPcS9ydVFRdElzAsspCPZ0ga5I4vPX5ezr/J4evhFbslaAA 0T6Kuby1yoNAz6YyxnSreS8mjWAGyksDTAhoVO9rXtEVP7NdPYbsP7m8+ck3XFX0 uZQJviyjpW79EPzUluldCHStl1/rDst9guDdaFFdx90JDEUttVMkNiOFIXst3wCh 2NF57GsaTULblfNCvwODaio+HFofXUEIn+YO26kiWA83Tf7r9Ic/ld5wd1iNOMul p22li5jjaM+f8oq8O1rfVNY2zlPrnELf2MIzws3+M+EC5hzIyTuqPQLnVYufqiHn 1EVX8UR2kmzuDDlkB/DoimBBSgeQWHMHhLEEVgXygLSmYKoNQu9urohxBup/szf4 llerzaQlH2dtqftG0LcsGaxTHCtCK18wRSHHg6goJQ8/sNf64fu3ulWD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGITCCBAmgAwIBAgIRAKmACTC3v27Hsi7W7gwvye0wDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDUxNDAwMDAwMFoXDTI5MDUxMzIzNTk1OVowgZUxCzAJBgNVBAYTAk1BMRIwEAYD VQQIEwlNYXJyYWtlY2gxEjAQBgNVBAcTCU1hcnJha2VjaDEfMB0GA1UEChMWR2Vu aW91cyBDb21tdW5pY2F0aW9uczE9MDsGA1UEAxM0R0VOSU9VUyBSU0EgT3JnYW5p emF0aW9uIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMewZg78IGm7S7/LWbMLjHvpC+yXdfqytljtxTad gxCCsyNvlL6sM/m1vGUer/1EUgdOUoFAQMkaKtSqzjE7sVMGPprUsk4vkkO04evf IS0k19uUTVOZcnsik2UVAgAmfWpdIk9cL285okCUsmyVPbtaJtBA0VU70hBunfwR HCn+yBzcd5zQBuZVRETsBjvs1A1zQ00CZplh+p7BlA6ghGhE1w0WbQDVfYuPnfGh +6+qkMhZApJVb63MopGfqz5DaUiuZ4CismUH2V7bPPfxrVdnyWYZ49/R1qh7AdR+ rErXzXEn/IEYCeXSl7CCmH0ndg5gb4IrdeVYkE+Id8pyoXcCAwEAAaOCAXUwggFx MB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBT2N1IE J08rxBTHCv7+f2ImdiDjJDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTAN BgsrBgEEAbIxAQICQzAIBgZngQwBAgIwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDov L2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRo b3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2Ny dC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsG AQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUA A4ICAQBwLjbs92ghbaaoHxs8sa2TGxUUwbs3773zsoH9gQh5iavC4ErWw6nJ9Xi8 OgpCxLkzwinXsibLfrjPNZ6bX0D+2lOvAz9APrNZRy+gaynxBxCj3rB9xqqtr5tD i8BlHpS6G8aBA8AH5l1aEfhbu+uJNpI5HvzPk14wdiCF6QV1Pjv3oSK47+5br2Zk LeMN5P/VBWB6eEUkHEmRDRRTjfO1cmMQiSPS0t+dfJynezWnsbw9roFuLRSOcl+H d0cv7V53ivk/yhiSHAsK9YQLTNcVYDzjEeCKf9vEQ6TzAS8JNbgqlOzxYgf8jFzC pbHxwluio7dfXf8XMkIWV2d+jq1RamqyG380irimKFkTPdUwZAQNBk9yW9OLQYjE vuHVTuIfLtTeOZpZp3Ak2rbZ7LvCJDQc9ydFznOAaElCkODGhI3zeTWBzFPfTFD2 hjdH4DU7oAalKzuxnnS3CWN1ji1ffikossHss9s+q6TN6Jpc+Z7rKUtSpG/PW9Um AJtpwQeqP8IReeUJsgYW6Mo48dDLeHMAn4QeQcHtZM7FzPJlr01zm6pxCN+9uydd fia9KG3z6PC7FqKKjiG+TTuJePvrz3gJrcxM4x4nKN0TIdqUeBpm9eryO1s7Ay7k 1qCizfLztXU5Nx80TtHDr0FWWPqXU7qOV2bU+DKPI/aa9+Ct3w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFTCCA5ygAwIBAgIQc7eBuodoQq4ZLBCoebdtOzAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwNTE0 MDAwMDAwWhcNMjkwNTEzMjM1OTU5WjCB4TELMAkGA1UEBhMCSU4xEjAQBgNVBAgT CUthcm5hdGFrYTESMBAGA1UEBxMJQmVuZ2FsdXJ1MSUwIwYDVQQKExxlTXVkaHJh IFRlY2hub2xvZ2llcyBMaW1pdGVkMUgwRgYDVQQLEz9Db250cm9sbGVkIGJ5IFNl Y3RpZ28gZXhjbHVzaXZlbHkgZm9yIGVNdWRocmEgVGVjaG5vbG9naWVzIEx0ZC4x OTA3BgNVBAMTMGVNdWRocmEgRUNDIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJl IFNlcnZlciBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABMnEGRJJ5H0EtRZo K4Z11VnnVUkp5fWhA2KTTP4uartBlUhexc4CQBtuQuzmzC3AaKYdneEFyNEfKoV2 1RC0PLSjggGLMIIBhzAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAd BgNVHQ4EFgQUZ8OvqmQ3XSmUlZ9sr/r/Fbgt4hUwDgYDVR0PAQH/BAQDAgGGMBIG A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3Rp Z28uY29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVz dC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYI KwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5j b20vVVNFUlRydXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6 Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDZwAwZAIwSBDMIR5EixwE ldTPg/2tVWHfnHgbWbuUdNkwe9M48rmCTikcF1cZZwSTVVddEPxSAjB6Mcw+YUfr 8ovpmo7gheUEqeTRxStFzM2eEc1xTdjJtpUzu+5jAchK05SNGPWP990= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGGzCCBAOgAwIBAgIRAOYHB6hw5U5b67oi5v8ZeUUwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDUxNDAwMDAwMFoXDTI5MDUxMzIzNTk1OVowgY8xCzAJBgNVBAYTAk1BMRIwEAYD VQQIEwlNYXJyYWtlY2gxEjAQBgNVBAcTCU1hcnJha2VjaDEfMB0GA1UEChMWR2Vu aW91cyBDb21tdW5pY2F0aW9uczE3MDUGA1UEAxMuR0VOSU9VUyBSU0EgRG9tYWlu IFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAJjZ6C5IvizOoKSf/r/vny0F/OLL0trYx+StVh6EoLfRw3Gp 3n8kTDnc1lBXhNVoSLOnsEk2+rII4GDV81r1dglG+6nHvnAflV2n9Xm0GIIrXK/x j1kbviEm0fXyF9MI4v+UGND3zjocZ4oiMHo7phiL1lkOZ+uKnQHNq6GrKxJkKFFs LCY6VStfcQwWA0IGiKfmGNtbbVjp9ar8sJS2Cr3Ns0NmRUFJEwjAXUy61YU9q6k9 TDCNgLaMttfn3MQt8Axjgt/5+2FwH4mlTst3fzLloOmACjzZLyH8589nb6hzC9+F aZzJ5uyLlaDa59calgSW1ESXW/PwBMt953yDHAECAwEAAaOCAXUwggFxMB8GA1Ud IwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTGLIQsbLlWLNtG lCBKqz//TZU/zzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAd BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEE AbIxAQICQzAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51 c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHku Y3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2Vy dHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzAB hhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBz AokQeJrfaKuwqDW1sIE1D7NiHSKCi3d/z4BmFkp7HaI/BhJleQARfT+R8/K4KJ0K KI14DvPsplBC2beAJZh+iu5UVHkycSDDez3wRXNlY8TvC2Xwqd1ITi3x2lw/qoiB /6Ky1uXCOe6xmMXOFEN9b8Re6Bx8FNa3gZSO3UWpqMAl7vqpzG6qri/Bfn6TsoT3 kHs8duNz7LjxA4bD6YfxHSzyqUtUHc/XhR3qkCdzwuwNrMI0kqIdOu2eStMS0vpw SBuOjD3CCbnixMOqNIGKpULsyWU5g0rFo5fXyRxxeQ9kQWyoYmce1r18bcd3hDzA kR4eTM9WD3qQA5LAb7QJBb2q1rk3nwJP+hjhiBH79hOq7kzW9aAY0hO6RFc396eO YkyycPMp4o0XzgTGAhPULUfiSfii0+STx16UNVZTrW0bAhhMDZ/xBweqdXHUPgT4 4NODSxscYQrfsYfVeP24vlJz3NLTqEtZxYFVZVZ0KC/haRWe9HfuGf1a6iWJvTyD F+lsvsuwXVdE5ami2JYXmJ5GrBylXUDR1GA1XLfX7/17bazBN0chfjmtxw1EVs0T hCVQUCtEUJ0i505tQZDI4Fs6qg5YruhryXhxikrmkrqoVFJ9/o+7AtswBlF6kTXj bY5oA7WUYU2KE0201GADsEQRdByZpw9d2BrUf1qinw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtjCCAzugAwIBAgIRAPuIGDnQA+BV/SKHCuqBSS0wCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDUx NDAwMDAwMFoXDTI5MDUxMzIzNTk1OVowgZUxCzAJBgNVBAYTAk1BMRIwEAYDVQQI EwlNYXJyYWtlY2gxEjAQBgNVBAcTCU1hcnJha2VjaDEfMB0GA1UEChMWR2VuaW91 cyBDb21tdW5pY2F0aW9uczE9MDsGA1UEAxM0R0VOSU9VUyBFQ0MgT3JnYW5pemF0 aW9uIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABMlpgvJccswExPp7T4yxYnrABWSzhDMp+cN/TPhVyepOiVPtSFzv xQBkkC98i1LwhK9NI4AlYeflJft8FwYp07mjggF1MIIBcTAfBgNVHSMEGDAWgBQ6 4QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQUtlex3NhwQFAgiuBxUc6Z8/dm uewwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYw FAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAkMw CAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv bS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov L29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNpADBmAjEAvXqlnMtBRehp TKLJh7CMkwRUIYQa7Xbk4EmcwEbQ+b6jQFiQlZ5iAXtLTXmZKxdRAjEAu3pWR6fL I/+Sbi7IljvzS3LCIkWna7HdfJML5V+RrebSLmNdckpRbvR/bgqTdIbh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF+TCCA+GgAwIBAgIQWzEQA7DgZglnbSWDE/U7GTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NTE0MDAwMDAwWhcNMjkwNTEzMjM1OTU5WjBvMQswCQYDVQQGEwJVUzEQMA4GA1UE CBMHQXJpem9uYTEQMA4GA1UEBxMHUGhvZW5peDERMA8GA1UEChMIU1NMcy5jb20x KTAnBgNVBAMTIFNTTHMuY29tIFJTQSBEViBTZWN1cmUgU2VydmVyIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkSF+WlVtLRrE7jj8BUgZbPv6wSec te0alHaKXWHrWq2z1xJbeN/+b0sqy2MLZiRdF9XWfANHSULAe0mGfbb1WQR1wgoU bRKJXEWiFqeNd3kmWqS/r72/z9maOh7hc6B53Nw09I2FDuXpzqVWtyZRmviCDPlT RJAMcoO8Es6Vd4XsnWTDQFjWFhIslPQ1DIvkgs55xVc1giO+tUsPNsoSz+ZD4Xtz TPh+ajgVX66xH1hyd4f24VvKoUocA8rpsx04Ju3y+HurjFFuUjesz5HCpW7+JJFF p/IUBi/99gF++7lt8pqvSpearw0SKJD9g6CZ24M4TLti1yows6/SVjx4LwIDAQAB o4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0O BBYEFK8mzOFowxVer/9SPBYqEPfLVa+kMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNV HSAEGzAZMA0GCysGAQQBsjEBAgJCMAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5j cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI hvcNAQEMBQADggIBAAksnMBFmGGMcfCTH8NxwwU1p1uv3sg4RZhqsHSXoJspLAOY h+P0jSVbDF9vLe0Wrh9DulpfecJ4xzzNSglCADf+mNZ3TSvR4/b+914udNgtrSH0 7jUbgEKOhNafx+PgWluZ98MfX+o2IBrFqbxMmyID6X5IiSynaAHfsj99zkHYtVBp DhES1g4CyUcTZixNIhs7hxPyJMpI97EFwVM2La8zQqpyzexJsy/gChQJGK0scr8X wDxZP2C73cpN4aLrZFDpY2GQCu8GGWhRsc6w7qoGrevbAaUsJu3Fr5PZH4B3FrGZ 4MN27W6SWDcE1speK/Bd1gpe0xtguXNiUca4PmNqU2FrWLGRtYn71Kwo4oEG+qYE NgVcTeeu0kHV0RuJj64b4zFTGRSxILUsTMmuY+kLjl/Vf5EunryP0lXULipUss7A j7Sbua68kDNOAO7Rqd6+fJzLb2vHR0pMymB06kp5cQlaeMMBmW/1DegDKuG59AOz 43ak7KjQhVXhpvtf+NTwOxSY188T/lNr/u6sLbH6F/H/r+29ovxjnAyQnbQpBX9+ DhqYb1XpF7ZUB5ABp4vrlU8Ln6WLFLBnqKTq+ldedCvPsbAkGkGhEkd9hEmOE3qG O8Pm/A+MNAR8FQoL0IlL7Xih9R4JlvKv1lzW1KIliUvtUM7hELsUiULzRG7E -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDujCCA0CgAwIBAgIQCAo74kqt6NzbaBGi+KaqoTAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwNTE0 MDAwMDAwWhcNMjkwNTEzMjM1OTU5WjCBmzELMAkGA1UEBhMCSU4xEjAQBgNVBAgT CUthcm5hdGFrYTESMBAGA1UEBxMJQmVuZ2FsdXJ1MSUwIwYDVQQKExxlTXVkaHJh IFRlY2hub2xvZ2llcyBMaW1pdGVkMT0wOwYDVQQDEzRlTXVkaHJhIEVDQyBPcmdh bml6YXRpb24gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMFkwEwYHKoZIzj0C AQYIKoZIzj0DAQcDQgAEMLtSZLCWoiDKYPu2P8R3STfg4UnZ7vXHr3LnhOQ06Q/h UGteTs2KL3fqUmtt376Mxz+TiSO6g3/8JZ4MRpjA+6OCAXUwggFxMB8GA1UdIwQY MBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBRr/uyjxSPPY0bNHZOp 7rjcVSc7bDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIx AQICRDAIBgZngQwBAgIwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2Vy dHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3Js MHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1 c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlo dHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2gAMGUCMQCQSs62 GiWqChUtLtHozN7ZXgsYStzsOvBuhDxpFzdDAsuQJzXkDvjkSc4O9RV4yZ8CMDy1 2ONYXNfqE1B2sbVa61vvAT+z0/COSG0mPpJ8FslfUsj3UdQDbeK+4aTOXIaxpg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjzCCAxSgAwIBAgIRAIQ4lT4lti2S//qNhbDsxvIwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDUx NDAwMDAwMFoXDTI5MDUxMzIzNTk1OVowbzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEDAOBgNVBAcTB1Bob2VuaXgxETAPBgNVBAoTCFNTTHMuY29tMSkw JwYDVQQDEyBTU0xzLmNvbSBFQ0MgRFYgU2VjdXJlIFNlcnZlciBDQTBZMBMGByqG SM49AgEGCCqGSM49AwEHA0IABBwm2tZSQMkM+4J9nfhs7FLPHdDz+Vg3FtyD+B68 qSaQeAH0r1lSSV+IWM2XPY8PtkxFL4M/t+gPnaN+rQv5znCjggF1MIIBcTAfBgNV HSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQU8NqW/s4CW+76 eUfgX3P+2EvWqzEwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYB BAGyMQECAkIwCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwu dXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5 LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNl cnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcw AYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNpADBmAjEA kWzoJoHBbGC5Fy1kJ3Udaz+elBS+vzqg9ThyXM6vglE/OX5VlIOtpftnz2SxGYzB AjEAwUsZAV1/uCzNKWlzOZUrh+r7B0sS2qGPSnYbKY6Djy0eCu3uc9Fwo6UsauhS mNQV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEDTCCA5OgAwIBAgIQYRVw1+ci1szB4xBy7K5f0zAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwNTE0 MDAwMDAwWhcNMjkwNTEzMjM1OTU5WjCB2DELMAkGA1UEBhMCTUExEjAQBgNVBAgT CU1hcnJha2VjaDESMBAGA1UEBxMJTWFycmFrZWNoMR8wHQYDVQQKExZHZW5pb3Vz IENvbW11bmljYXRpb25zMUUwQwYDVQQLEzxDb250cm9sbGVkIGJ5IFNlY3RpZ28g ZXhjbHVzaXZlbHkgZm9yIEdlbmlvdXMgQ29tbXVuaWNhdGlvbnMxOTA3BgNVBAMT MEdFTklPVVMgRUNDIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBD QTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJuQbMcVOFUySZLwVH2RVHhMyaji duf01i2lPnRSRo8EeB3PA/iTCxNrAbSSV3vM2q+E8mg23lnZvfQgQxWlZdijggGL MIIBhzAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQU 8ykCoFiwfZtOc6vyQAYJ8MV2B0IwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQI MAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQx MC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQ UzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEE ajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRy dXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVz ZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaAAwZQIxAMbfoPENSVeJasuRzqRCN8eo ARUgP60iUWJpoAdCPVn0iV6jKOXiJdN6/FfIBudPygIwdz4Ct19E6OR2iIng+YIL fhEgPJMjpNV8nMYCS8qWUXenHrFZqbOyqMLvLEDufXnr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGeTCCBGGgAwIBAgIQGysB1r5py5MpaFWHaudIuTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NTE0MDAwMDAwWhcNMjkwNTEzMjM1OTU5WjCB2DELMAkGA1UEBhMCTUExEjAQBgNV BAgTCU1hcnJha2VjaDESMBAGA1UEBxMJTWFycmFrZWNoMR8wHQYDVQQKExZHZW5p b3VzIENvbW11bmljYXRpb25zMUUwQwYDVQQLEzxDb250cm9sbGVkIGJ5IFNlY3Rp Z28gZXhjbHVzaXZlbHkgZm9yIEdlbmlvdXMgQ29tbXVuaWNhdGlvbnMxOTA3BgNV BAMTMEdFTklPVVMgUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZl ciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJPhsQNus1z8pzKH QQchsctyMcS0gPykwXR7a4Y97u8Tl0j4FjzIJJOJgBTtnblcQ2H+X9/xk6QsByHS s5eXNbvG6ktqt5/zKkCh67H2DPxqprBuz50LdpDt7kgXd8/23pOCRFuUmy5Cdk/r OKVMb3PM/qNzucEtk2BQZ+a7Xi0iSxaXfYtBEKBEPCAwqkv4z+HGPYD+U75AZxQ+ en9g1UW7b258DsY1oXR1Xct4bW380EUrG/59fpkGwamd/YLEctsEW0Yb7QQ/Oa2w VYvR/Ufp0GqL909j4cD918UFm1Uqrzx0lqmnRJdHEojEwWdfgEd60RTbt8yGC7sq pZw5T1ECAwEAAaOCAYswggGHMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKy A2bLMB0GA1UdDgQWBBS6L20V6WSrFXhsfGMgz6i1xn/b/TAOBgNVHQ8BAf8EBAMC AYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB BQUHAwIwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8v c2VjdGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl cnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy bDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZ aHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEARnA6 0lEzu1CzC75sciuUb07huIup2MH9utg8+AtrDDlam8RFqdI4QXJxMIYr4WNZluKY EScZ3edXfdktLyxt1Jn+RXZx5d/n01TzimiqIczwV4Yh+mP5Q6p7217UXf1txZ+t b4fcY0kU+O6waiytesh56INrmv/zGlT4r/rGIfct+sTUt/naBwvyY8WLg32RGnTI l1+dypktHH8Ru6fxWGrzqoJ1s28AqLiDGfY8jlTnoGGP50oaRKVxjpyIWgLLDkYL 0qL9CRyQYQFZZqheUm64RwERlQVY99AbhGLXnYAL62aqWUAvz9U/rqxchuT27pu7 FTmPX3rEjamSrSa3OvH7wssHUSm//gi/teSjfaMudd/xWOrPXqYUa26DcBUY8WYS NpFO/3FQlEdsa22x91JC122w5YoOOTYX3Mq07ECm8CnQWN5UbFChq7rekDhiFUhc 5A88KOggH/SSljMMleEgwuxPa1SohKn8BN4OBkIHVjCzDfn0vZ/J6nhf3oV3ZfDU PeIPlWDAS9STeFa04QbySSORBtcNPNoAf0WMVUeCgL64GVOvjqyVUtqYHAEquhlP 3wxlRlYaKtqrKkdHRmztipq8wI8qXMQc9xeZweqkDdF6JbfnoRDLN46cVhSqRpV4 TkjKPAip9O/6B5MzvqkX4pdiJRZ8csg47HA27gQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID8jCCA3mgAwIBAgIRAKU5F5+erP55mwM4vMCN0BcwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDUx NTAwMDAwMFoXDTI5MDUxNDIzNTk1OVowgb0xCzAJBgNVBAYTAkpQMQ4wDAYDVQQI EwVUb2t5bzETMBEGA1UEBxMKU2hpYnV5YS1rdTEUMBIGA1UEChMLTmlqaW1vIEsu Sy4xOjA4BgNVBAsTMUNvbnRyb2xsZWQgYnkgU2VjdGlnbyBleGNsdXNpdmVseSBm b3IgTmlqaW1vIEsuSy4xNzA1BgNVBAMTLkZ1amlTU0wgRUNDIEV4dGVuZGVkIFZh bGlkYXRpb24gU2VjdXJlIFNpdGUgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC AATdax7xXNc7pEJ8AHpy9CjyHI922ZKU4CjaweRR/CERsCawni5Epsm90nwvpUVe ObQgl0klGZ+t5e6NlLBNDocbo4IBizCCAYcwHwYDVR0jBBgwFoAUOuEJhtTPGcKW dnRJdtzgNcZjY5owHQYDVR0OBBYEFDPvSikW3VMnUVHdDhFP8xLjEefqMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjA4BgNVHSAEMTAvMC0GBFUdIAAwJTAjBggrBgEFBQcCARYX aHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDov L2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRo b3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2Ny dC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsG AQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2cA MGQCMCmt2SfVntwP0c0iH8UCZm+6SFoaeKknv+ibXG0onw2E33FhFnjKg69wDlqh iOgi5gIwZI1tbO0u5tk6UQ2jaBYx6Qg4uSl424ClDziMtQ/0uaQdq5+Wj3rZeijN aYaNtj3L -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGATCCA+mgAwIBAgIQQ1Y2Hui1hl/YHBDQI9jXBjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NTE1MDAwMDAwWhcNMjkwNTE0MjM1OTU5WjB3MQswCQYDVQQGEwJKUDEOMAwGA1UE CBMFVG9reW8xEzARBgNVBAcTClNoaWJ1eWEta3UxFDASBgNVBAoTC05pamltbyBL LksuMS0wKwYDVQQDEyRGdWppU1NMIFNIQTIgQnVzaW5lc3MgU2VjdXJlIFNpdGUg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5GZdVPaJBmLwQmzIL kJBKaf+ELa+bw3n2MFmBjWfAu/Byi2+YFSdSTRCw5s7aT9cxkCo0olYzBqQ8el2y qCkSs3UL83l2CM3j4sZdkzXKVxMSt/QD+zp7wHvKwAwuas8lYFaIvsMnDkgOfdzz DnIJUqy4CzISkBGWW3H/9tpk+mPDuN3ms7L9E41bcj1D+PjEzjYdx+Nuu6cZ1ql8 dzYhZbDKaSPiukRYfOAssWoH/5iH+J8E/Wq2cxylDkzN9Sq9p38FhjwSqHqh68mw WI3W8as29LfPdw71MSKE3Brb5rHRFw6cGdasdfdjHXch+nOn8Dh8gOh+71aR84sH Jy4dAgMBAAGjggF1MIIBcTAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNm yzAdBgNVHQ4EFgQUatIg7ZOCCXFZePYMohe32a2IQsUwDgYDVR0PAQH/BAQDAgGG MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF BwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAkUwCAYGZ4EMAQICMFAGA1UdHwRJ MEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FD ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYB BQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRU cnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNv bTANBgkqhkiG9w0BAQwFAAOCAgEAYEcvy3r2pdzsbBV4t2JCKYA88IU4FBd6C4+m J7Aoiij8roq/U/pneFFHU4YMca9JMpXJA364EquizZiu9cZrXNsWg8fe3PaqJ79h ONE1xlm9WgPxcU7HljnskmS4eWbkwTCMwVnYLIYNpnCurKkjcPq3jtOVBzwM4erb ihunZwq5yzkuB1lq8PrkfITpVPsuH77OR/upWQXH1xja8B/l/O81uGFv7otZFuNg zjvpe7D73Ld8ZogvKnJIaLDSlCq40gGg4vxq1MxI1LvR2NTFczyM8PGM0jezzSDp t9wMs7PqIpwyXRfwN6WRaq4hGJ1zHQoiS81+Ev4lqGaGGTOLyRck0vNqCuA388bL d9duZjFN3AIO2bcWT/uOrMxqOaCcSZxU+MDZ6WR5RsOluWFmrqq67GgrMMjM/G/Y DYPB0Sy1ZzxTC/lmiCVnNoSaGvvdLkpjdap69PEg1mTWNfDj45cACp6LUvOtg21/ M/2nD0f86Yx774cJMFLWPAmZNn2FYQen4ObjNjjIOZKH3h9cgngo4zjjEy3WEp8u 8zWJ/oJXxO59ItE8/HS8SRNIQMfWqVWKOlj0DqBA2UQj0S6oA1dcb26bdePmHhuM Ah83vqIulSmKxf4WcML8vVb5D6TJ+M3V1487mzRX5duH9ibi1/8dLZNp0yNdHCzj R3M45NM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDlTCCAxugAwIBAgIRAM6v1roElFdoBhudWGtNQOwwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDUx NTAwMDAwMFoXDTI5MDUxNDIzNTk1OVowdjELMAkGA1UEBhMCSlAxDjAMBgNVBAgT BVRva3lvMRMwEQYDVQQHEwpTaGlidXlhLWt1MRQwEgYDVQQKEwtOaWppbW8gSy5L LjEsMCoGA1UEAxMjRnVqaVNTTCBFQ0MgQnVzaW5lc3MgU2VjdXJlIFNpdGUgQ0Ew WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASCmnDOA/tAbxvjWlg/RvpT1Rn+Jq2N F+pmNsaZQ/dCuCm4MLpJ7JkOwGgtM4JPjDPxxOjCZLyCHRDB6Q+yIVZfo4IBdTCC AXEwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFEmD W5ahM4vGvN++5U5jZ6M6T5igMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAG AQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZ MA0GCysGAQQBsjEBAgJFMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BBhj9odHRw Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1 dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8v Y3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYI KwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMD aAAwZQIwF1FaGTAqj6WSUNbknVT97ouNkVH3Sw6thEX6peEBAYVxlAa/VaSSRIR/ 7BX/lXy2AjEA2VLy9cCrER1UTfucPlUDL1D8SlGHICYdpm3ESXuJn9JbMgCcbGmp iM+/J4RZ59EA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaDCCBFCgAwIBAgIQdR4+54VB4tfq7ONxbGDjnjANBgkqhkiG9w0BAQsFADBj MQswCQYDVQQGEwJCRTEVMBMGA1UECxMMVHJ1c3RlZCBSb290MRkwFwYDVQQKExBH bG9iYWxTaWduIG52LXNhMSIwIAYDVQQDExlUcnVzdGVkIFJvb3QgQ0EgU0hBMjU2 IEcyMB4XDTE5MDUxNTAwMDAwMFoXDTI2MDUxNTAwMDAwMFowgbwxCzAJBgNVBAYT AkJSMTEwLwYDVQQKEyhSZWRlIE5hY2lvbmFsIGRlIEVuc2lubyBlIFBlc3F1aXNh IC0gUk5QMSQwIgYDVQQLExtHZXJlbmNpYSBkZSBTZXJ2aWNvcyAoR1NlcikxFzAV BgNVBAcTDlJpbyBkZSBKYW5laXJvMRcwFQYDVQQIEw5SaW8gZGUgSmFuZWlybzEi MCAGA1UEAxMZUk5QIElDUEVkdSBPViBTU0wgQ0EgMjAxOTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKXy0aVSFMG4AXgSL5oDnUPqls7zPa1Fuik4KqTf STaz1Q7ucOLl++mgy+a0QsNCgunY3fXTwWmKMZABj4+K5OCzyNIuaAZdG7VN4+eu IWrHS6MDycpR31R/oz7Rle0bxv7mvEUBXoP/UIicYuM3jerIVCg6MsfvA9Zf96wW +Ay5wEmmGwhmNLSTULwKFLYzrxNoirAfgSFqOveSE4tjrpFuIuZYj/E587tpT14s PklK8iuQmbfe32JdsZ9kUKgAOjTnaFH3S1xaKAYsHHlOAlcond2TDneTAdU1B6fv fKHc8lWcGL1luzagXy8otoMTjLLAIMusMeGLKchPwUvHyrcCAwEAAaOCAbwwggG4 MA4GA1UdDwEB/wQEAwIBhjAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG CCsGAQUFBwMJMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFKswxwcoS8t6 jlv+YWn31HqyhZtIMB8GA1UdIwQYMBaAFMhjmwhpVMKYyNnN4zO3UF74yQGbMIGN BggrBgEFBQcBAQSBgDB+MDcGCCsGAQUFBzABhitodHRwOi8vb2NzcDIuZ2xvYmFs c2lnbi5jb20vdHJ1c3Ryb290c2hhMmcyMEMGCCsGAQUFBzAChjdodHRwOi8vc2Vj dXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC90cnVzdHJvb3RzaGEyZzIuY3J0MEEG A1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vZ3MvdHJ1 c3Ryb290c2hhMmcyLmNybDBWBgNVHSAETzBNMEEGCSsGAQQBoDIBFDA0MDIGCCsG AQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAI BgZngQwBAgIwDQYJKoZIhvcNAQELBQADggEBALoshiuq7NiX6GqigqN8pLfvz/ft 29m6mEpkxzYZlyPIcsK5Vek4VNrucAhhttPl3HF85pNMDWICjpev4DwlQSs6q+H7 fJG8we0PPIJyhVtYMTFbSZz8G7NQcuCeSeLlOjEkAWWLR0F/lhOTktURLoA3q6// lkkwEjOoQekpqI3RmmIMinWinIryzFim9P91ACY6O1oBi+kknw9V9vXHFyjnir6K 729SJNjPshaIQ9OU8oTV7d88cXX5mPUDq6bac8Lql5jx+z7t2k/89x7E9IO9IpQY iSJjL2nmcKMip1/pHy1UOgI5UDQkouw8VCpi/TwwxybTPJIFOWPHt7GdN7o= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF/zCCA+egAwIBAgIQCqWJe6uP9goE9nLhzV6r4DANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NTE1MDAwMDAwWhcNMjkwNTE0MjM1OTU5WjB1MQswCQYDVQQGEwJKUDEOMAwGA1UE CBMFVG9reW8xEzARBgNVBAcTClNoaWJ1eWEta3UxFDASBgNVBAoTC05pamltbyBL LksuMSswKQYDVQQDEyJGdWppU1NMIFNIQTIgRG9tYWluIFNlY3VyZSBTaXRlIENB MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuVQzLtT3QQenCP1eqeK5 H7VX6xX5sGGQI3ZG7J3q1zPV8NJHUfsfTiZHC2LRGiTGQ5G5dvHo287z7iCX7U1o ohC0JiAeTAC0FRWUVcprY6ElkOcfX+KYO60BOABXWMFBN4cVCYq/U6VT6Zbwi60b MCcYtO7SL6AgyjBH1U5VyKA9GhCb/rmoxv86UgO+c72E1tCPqBa+Kb+XJKIjWTvi y+kuN+o8imkTT0B/cO2mNDLbXewsbIfF2idJ6N5LVIbceeKoC4MIauCUOPPYm/3Y tPayYxMFRkNkZRgpBOMibb+e3X97GuSCt6Y5DGsF6suai2L9NgOQCiVj6zt2Xqj4 dwIDAQABo4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZssw HQYDVR0OBBYEFOYiQE+kUKl6LZM5Ua+ynXM288GwMA4GA1UdDwEB/wQEAwIBhjAS BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD AjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgJFMAgGBmeBDAECATBQBgNVHR8ESTBH MEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2Vy dGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUF BzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1 c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w DQYJKoZIhvcNAQEMBQADggIBAH7zVueZ1KdPuTOLaoHEFpFcjguA3OtB17UpSJ7e jQfbTshawJVUNNAOLgFVjmvjps9X5gxYof40KboVt4pC+FFaAXMUJez0tcQAjMs9 VCPSmSjJiPtCFHTI/bE5pZDbJmDU7pnadn3PKvtQJXQokw8x68hjoJUX44BFXwLk Du+VCRln3ScPBDZcZ5FgZJ8ZUnSsxKLd5LCgwfrM85GrcJ7JCe4c3vr9FqFxI5W0 HFr37UlMzu8ydDXGgwr9QpKE9inQ9BXlcrMdSyW0vyXdOfN0COHEFZN4A+lidfcZ Wj4VHbUVapT6CPHcDLZGwLHFE08RcgZ0Io7Az2DbrBtdqi1N+eFWXRiqxjnxwrzU uBN0XzBg1vhE/pgOQ5nYnxC49II6h6Vi4/NZFnpQP4Yd1osyAaQ5VgHCt8epBKd9 BGDiAbfjLyokC7IMLUdeiOp+icjMEhjA4TuXP45Cg1RKd+47bNdFwa4mRtT8VAQC c7HYoUiDxtRV6EN927lo3kYcJzm0+J0OCxNIPe/x1qWkfwR4y2f+U61BGpeJi/75 ei5NG3QpGzLTYOG7cNxw7ox5boPV0UVONFYkTSqjb09W/xU2pYT1UAEcKEMC3KZk YtSc5tWkjyr+3uBglBvzE5yJ7sC9t5XCOrww6HuH0EBvAjEjkTrMB+08p+IfnwMT zxT/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCTCCA/GgAwIBAgIQMszoFbZBZn8ZU14z48d3EDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NTE1MDAwMDAwWhcNMjkwNTE0MjM1OTU5WjCBiDELMAkGA1UEBhMCSlAxDjAMBgNV BAgTBVRva3lvMRMwEQYDVQQHEwpTaGlidXlhLWt1MRQwEgYDVQQKEwtOaWppbW8g Sy5LLjE+MDwGA1UEAxM1RnVqaVNTTCBSU0EgQ2xpZW50IEF1dGhlbnRpY2F0aW9u IGFuZCBTZWN1cmUgRW1haWwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCO6xMIpQRMk7n0vuGh+5gFjvfcc8ZfjBcAHrnhszDCIIA7OZ9c6Tar8ZCr r7Ubk/zd1R0M7KNxSd15QplSP6x/CP/FPkJrXmeowpfyS4tg7FrjCyEEj5voaWH3 2k4/ggDJ3O31KNYr0KQiOLsKoG0oDMVGbYwbK7DGGN4TnOK11ci/LNbsxg057YZ7 vz6sSrmsMtuKkgUCwM0eDT7+7g0g9/iuFJrLTwcw+0Fphv4ucpxQKRlthaUD9oiK xmgQZ4IW83EK+xKi4V3ng86VMvbrlleKBmXO1xz2HCEsnlKleAALQZ90Z/aCCPhq 69wonfLpUMVcVY6QOLB27RriD/XlAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRT eb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUj1oRO7CxZmG222LF5F3o8EGZ haswDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYw FAYIKwYBBQUHAwIGCCsGAQUFBwMEMBgGA1UdIAQRMA8wDQYLKwYBBAGyMQECAkUw UAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJU cnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGow aDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2Vy dHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBM+ibRuxYRElYP1vcsPaHJK0FA i5g8Q1uv9ClnSAjK6HzMZH2qQlidLIrR/MyFLlqwkeV60CVd27dvQik4ELmmvf89 E57P/y4467TfI7Kzpe7Hg9ghZiV4qYChH4xILGOIS7Slu+LX0rjlhu8l31lb/LsL wirfSsy0A8Wz1ZaQquVMzeRR2GpO9Kt+UUpPiKqpLxtgl2QPgOLlmWQ95W0PpdQL 62XQMl0ViISDgaRp8jyDqjMb3/RSZbpBYUV7uacuDtNGIealqE8C/uG1Qb3z5/Mu EPCyHdLhDB/pCSX8l/30C/Liv+TCHb8bQrkk109uP6hP/e4ugTr91G3oPOAJqoGz 3dWWQfOjTAGYCY62Q3Hrx5AAQ86HwXNZ4F6lGWmTIF48TFE07To/Y+cz960s0NrN LjPV4de6bZz5VpM4OOYfaEubcq8XVm5UoBmscrzsnKlIKm5DrqW2MmQQiJVC+uSi DPPzQN+xiXzQdQyu58KaznnDhZ08fZMaNFv6jtWt3HB+eVBrgBE8Ou/mJHIthmUN HlEIVWSeM/oDZCptGn6VM1skHLqDD96UIvlKFIktwJMNxYC4qdzGCDT5/vCnn4bx 7h40gDzWZix6fq7OpRzbjzY0m+tafAF8tyl7n9KI7M01wGquXVgFXyOosOOqiHnB u3QatcH2DryuND1qmw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkjCCAxmgAwIBAgIRAPDq184Xoxf/lmrpG+5K274wCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDUx NTAwMDAwMFoXDTI5MDUxNDIzNTk1OVowdDELMAkGA1UEBhMCSlAxDjAMBgNVBAgT BVRva3lvMRMwEQYDVQQHEwpTaGlidXlhLWt1MRQwEgYDVQQKEwtOaWppbW8gSy5L LjEqMCgGA1UEAxMhRnVqaVNTTCBFQ0MgRG9tYWluIFNlY3VyZSBTaXRlIENBMFkw EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBHCK9noHaZ50RXhISD0Oyw3FuY+OY9cM 2C2yir/Bh/kmPYPA2qNurA5kYooHFflnxeoGpKrnoDB8LWRG76txeaOCAXUwggFx MB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBQgLLH1 c/2S/Cd3zXlXeNNEiZRedDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTAN BgsrBgEEAbIxAQICRTAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDov L2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRo b3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2Ny dC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsG AQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2cA MGQCMCCQ0Rxpg5g4tVxZXcfDNkmvplAOybPWNipnju16Z24THGFeB96itKIbFxM/ 8dxNywIwfvtaRlCpZKyjY9CoP05ojtprukElfgQ/GATw782+5ThmNFDt/K2IWtiy K24bi4cV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGXzCCBEegAwIBAgIQcgahe04phWx47sHkChlOAzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NTE1MDAwMDAwWhcNMjkwNTE0MjM1OTU5WjCBvjELMAkGA1UEBhMCSlAxDjAMBgNV BAgTBVRva3lvMRMwEQYDVQQHEwpTaGlidXlhLWt1MRQwEgYDVQQKEwtOaWppbW8g Sy5LLjE6MDgGA1UECxMxQ29udHJvbGxlZCBieSBTZWN0aWdvIGV4Y2x1c2l2ZWx5 IGZvciBOaWppbW8gSy5LLjE4MDYGA1UEAxMvRnVqaVNTTCBTSEEyIEV4dGVuZGVk IFZhbGlkYXRpb24gU2VjdXJlIFNpdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCRuGAl2r7Ywgq/W8FSsyq4QtH8XdnPvBvk7UdZ/D34eF/llnTb mqJI89KqhI8tUNBg+iw7fErnHoU1Tya//85h/BhlfwjGjO72U8dTYjPJ4Y45GmPB wxdF3C8J1yUqJVGwMn7FgGn+mvuSliUneOaHqlvKw7MTKh1FO/YKYwo/hf8jiFcu UebC1lVwQqCt4ovAGQ40kqT/xrEAH/BPkj+FJfFoTULu4yI/55tZzMdoUgllBMkw CO3ZDS4NO6Iqu7kr+w0Z2lLGoM6rlqDS+SRmJjfdDbeSVUTd90qDLEcT8MkmRr05 BQo26gXZ91iDDwl6HRSjff8cuoPP3CU31GVPAgMBAAGjggGLMIIBhzAfBgNVHSME GDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUuWMIGYeiC0YxOf5f +ATPyh8aE34wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYEVR0gADAl MCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBH MEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2Vy dGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUF BzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1 c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w DQYJKoZIhvcNAQEMBQADggIBADnS+9BkrgKK5zNCQ0a2L+oYmKCOb2ija0oXJrkR XHDxp8zHmQKuztLQjV2RFkLlxqBfohTk3oJI0JcI/6ivtLAyaiv1bVFj4Ns0e2Xu e5nn1oHHXKFEgbEV27VxCtbvbPohMISrIm8TCYCjMBdLsthSsjd+0cm4yN0CFqoA eEmwyzmDz0HKoJGsQ2VBpAfhkNWI6YGhojYe7ZNfe7ZAmWBR1Wt91MR8R6XInXCo GXORSwzAZ9XWJhxSK3SEPzhECYYopBlGjNKvrYI23jHhb3QGKzslCYejyY//ZVyW kvmW+/Nnr3jVP9llmAB4sgpxT0iVthNN1DD5JeAyWhah7GO2fK/wXrGPmwDO7zL7 fluvzSJ5z7vmOhmf0PkxpS03MUCY1nbv78pIhvMpv5PCoIiAQxipE7QW/mf+d2E+ mvQ1+lPPj/jSc/vtjcl8kPNidcBSoj1d+0FlXFaTBp/6s8MZF+y+ja3QaGRe0HNr zPR0wllMgYc4si3T5b2UKhuRscLUPfS6x+9i7skktsl17kHbutjrnEeQO6aT2wGn qFtdp6AUPT70lNAgZlHwZpoFo27btlG1pZhpsgyyb/4KCDbtaxRnEgzxDE2YkS0S LCrIPTiiUq1W5VVP3sNpWyxMEVLLdin3K/t0SsZPBLTS+ge/Oy9UnSjmE8TtJFTG PBLF -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFezCCBGOgAwIBAgIQdR4/Pels1yiyZmLFUjJYezANBgkqhkiG9w0BAQwFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xOTA1MTUwMDAwMDBaFw0y ODA1MTUwMDAwMDBaMFExCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMScwJQYDVQQDEx5HbG9iYWxTaWduIFJTQSBFViBRV0FDIENBIDIwMTkw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDERtVIA51JWfdcIKACzqJc FKtZ9l3yKtnILRI7rpVa6HkWsAfQlzrFMA+O7bCeiXN4WVN0Lm25VbKbsDtD/yuw 4CNEWOljgas3QPIl8HqM7U2PVO6eal9gaaWL0ZBKzOi6yX3TWMerwah8AAfczXAb frz4RJ9RNniC3NlbeYfkiPh7HQ6Tdm1ouhUzFdO2hoOgOrsg9VVxCkJOSutm3pHC US+pSQcbz8Y+TluTAgSPY08qvPHJzfNfaD13LUXPmta8z74SGnd5b4yYd+1nNv1Q QPTiyyVvv6sKnUJc+RgchszudFW7BKifHDUDzgb2JWZm6rjPvWCfNXCdcTYp6dFM 4qdx1DnooL/w7lPZ1o6/r03qNMdEoL8qRcw0NqnJwPu1fVwtNpCIvzlLMLhZiCFb mfK86fiBoVAQckYOJ2uj+Lk48FGU0dzjjaqK3011Q6xczxt7eNarZ+DMDENcgO8N ggu8mffq+GPxT7ycMSNcmvWhOPOy1hg3c/zYG6+cVdkVZvkWcFjGsozfmycNFLWn rSS0ikDrKeucA4MWhptIiha92dEaut4NlcyqxZjs7WQYq3+iNmf+WuMYGq/PMCY2 bX4CSV2v39AjEtgy/PYhXOKreFQT1qsSQtvR975D9BVqMTC3dBpe9YgXnb3EL90X gz5BrJpMimF3hZKxXk88/QIDAQABo4IBUjCCAU4wDgYDVR0PAQH/BAQDAgEGMCcG A1UdJQQgMB4GCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwkwEgYDVR0TAQH/ BAgwBgEB/wIBADAdBgNVHQ4EFgQUUo+qWrOrcu7dyfmRocm5BhLSBN0wHwYDVR0j BBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7wwPgYIKwYBBQUHAQEEMjAwMC4GCCsG AQUFBzABhiJodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHIzMDYGA1Ud HwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5j cmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3 Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBDAUAA4IBAQCq RGVh8nPOW7WlILMsE7ZtvimOJRpEZ0kd/Xz2AuV/nj+rLIPi74iaqDbqguhHOey9 lINqPcwKvRnCvDu55d9SHcQce4/Th6CdBWW6Gdia6EqmbclWKXvPldWwNNEmFGbU yGvbegtnN7oYP48Z9TUgxVmGq2BRTz9PqqxZ9HYHTg755QiiCQo/llMfMHedcGrh qDIMvz0zy1L75MGHjcLX0801YLWUN6A2hWERL+MxBlzgk4el9hi5JTJZe6MEepx5 Y+8uTIO2QbRc7F7PQEU05/lAPVPZOzjRt632xNMaNCx8Fx7/PZWrCbAlcbHQMNEs Z1SvsHdUqryEOgyXBpms -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8TCCBNmgAwIBAgIQDp+h1MRZs9AaHaJ2K4NQnDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMTkwNTE3MTIxNzM1WhcNMjkwNTE3MTIxNzM1WjCBhDELMAkGA1UE BhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEzMDEGA1UECxMqRGlnaUNlcnQg T3JnYW5pemF0aW9uYWwgRS1NYWlsIENlcnRpZmljYXRlMSkwJwYDVQQDEyBEaWdp Q2VydCBTSEEyIEFzc3VyZWQgSUQgQ0EgLSBHMTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAJi7H/6cAevzLfCNBKHGw3j4zhT25y1PQQPkme0pTCZExYu0 Ar++Xfo52bYR8g56WtwEPyh2bz29tmncGaoThBIs3cT4oj4+O4pz1c2v2DriqJea Oe3qFRMReum2oyA4HzyKGfQ5/4ux1U/ZTSSpmXrw5u7wEgVw0cybimTY80OPgXIF PXTS0Dz8LuSR7j+OkWHcokDZKClVt0rfvtIsGMA4AFkTi4i450tRGWOoH8KmqmQH rSuVkWgVBm5hyQ7Y9ty6sLZt6StEoGXq4JBWPpHhPF0wHuI/1gG1NyrwRdR2ck7y fPaPkuSh3kHgm/PAMry36LLC8dEepsE6+P/J7GkCAwEAAaOCAnswggJ3MB0GA1Ud DgQWBBSxFa2XXc2rHzitNLW/JxqloS0wozAfBgNVHSMEGDAWgBRF66Kv9JLLgjEt UYunpyGd823IDzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwQw EgYDVR0TAQH/BAgwBgEB/wIBADB6BggrBgEFBQcBAQRuMGwwJQYIKwYBBQUHMAGG GWh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbS8wQwYIKwYBBQUHMAKGN2h0dHA6Ly9j YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQw gYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdp Q2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2lj ZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwgdMGA1UdIASByzCB yDCBxQYJYIZIAYb9bAUDMIG3MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdp Y2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMgQ2Vy dGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUgUmVseWluZyBQ YXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5kaWdpY2VydC5j b20vcnBhLXVhMCYGA1UdEQQfMB2kGzAZMRcwFQYDVQQDEw5DM0NvbW0xLTIwNDgt ODANBgkqhkiG9w0BAQsFAAOCAQEAmFolJIDFG2tegigHneOhzY0stJUnKrQZ3koZ WLXB4i43wip4d2tHnlKeqeVv9dAB/DlW7IoYil0R/whIUz2frEmELnQtjf4ejdC5 vVMtScnC9GquGP8gU4RcLRGczeYgLtM4M20rEzBqIU7wOot97xfnDexyLOPAk9tK OCL0W2M0/AUGTQ5yavmtrd0Bm0UsMlVHA2dTC57qbu/yEmU125oZwPagjgjg5hJI Ja/bvuFjM120o0Te9cBAi0HWJ733sg3OWUamv5jOneuNnAFIHpkxX+TYmiL2BrbR VgVIZIhEFUDX1KTbS+/STWgpKISOgQJRDFzbxI/s8gnp8vGw2w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGBDCCBOygAwIBAgIOSUEs5ABcxl+EFyHWQKEwDQYJKoZIhvcNAQELBQAwgacx CzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEVMBMGA1UECgwMTmV0TG9j ayBLZnQuMTcwNQYDVQQLDC5UYW7DunPDrXR2w6FueWtpYWTDs2sgKENlcnRpZmlj YXRpb24gU2VydmljZXMpMTUwMwYDVQQDDCxOZXRMb2NrIEFyYW55IChDbGFzcyBH b2xkKSBGxZF0YW7DunPDrXR2w6FueTAeFw0xOTA1MjcyMTExNDVaFw0yODA5MTYy MTExNDVaME0xCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEVMBMGA1UE CgwMTkVUTE9DSyBMdGQuMRQwEgYDVQQDDAtNS0IgU3ViQ0EgNTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALcBXbJEUXFl1/F6rPW0Sfulxyb2PUGGocIc PIWVCyud045B/zDO5KDyP317KRfetMsPDUWDCLmKXCFcVD6KXzmlLDNkyfaqESNz 8CCiTR+gvAKPqyZ0qUAH6qO4NPDF2NzEh778Y/Dg+5mkYY3aY2KSOG7EnUkba6Ga pNzHO3C10C7R7hZrZbgZ9YPJkQveAysFFoWs5bNRgKevn4J7x2+uQjylGVEw6xTM SiuPHfaz5DMAu8bDk131rg5ATfCmvBx+uAaOQWnz41Hz56JJf1d1Q3mTYi2+12bY 2aOvOLonR7pES3jfPEszle7Bypjkq/ySUR0iJmq1m/aEVJfyWAkCAwEAAaOCAoUw ggKBMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaA FMz6Z5PwtrjQpcAe81P9jFPfg9eWMB0GA1UdDgQWBBTe7bJVc1AbOmR2hxt3VRLe wSrwcDCCAT4GCCsGAQUFBwEBBIIBMDCCASwwLAYIKwYBBQUHMAGGIGh0dHA6Ly9v Y3NwMS5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRwOi8vb2Nz cDIubmV0bG9jay5odS9nb2xkLmNnaTAsBggrBgEFBQcwAYYgaHR0cDovL29jc3Az Lm5ldGxvY2suaHUvZ29sZC5jZ2kwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWExLm5l dGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0dHA6Ly9h aWEyLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0 dHA6Ly9haWEzLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwgZ4GA1UdHwSB ljCBkzAvoC2gK4YpaHR0cDovL2NybDEubmV0bG9jay5odS9pbmRleC5jZ2k/Y3Js PWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwyLm5ldGxvY2suaHUvaW5kZXguY2dpP2Ny bD1nb2xkMC+gLaArhilodHRwOi8vY3JsMy5uZXRsb2NrLmh1L2luZGV4LmNnaT9j cmw9Z29sZDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDov L3d3dy5uZXRsb2NrLmh1L2RvY3MwDQYJKoZIhvcNAQELBQADggEBADLCzBdvqlNb q0EY096S6IFFYcSOdS4mMnozpU7pToK9kC5UBTqgVJ+BGvczUrR6dPsQfk5tD0C1 y1ZmStdTix3ivzjpxiTdiF6atfYaSkg4dadaKxaS/YTw+19AfkadTOCxuxv5RViu OJdnSgww48zQwcwPVeBtocBsdKavfoPc+NhUYwmSsl/aMWZdblJorHI48AGZwePf wrlwp//0U8mTfLdrvP3yt+Jk711qWNmxiBwZSmPzVHJrohPSK3SRXsqafITkPgO7 ScHCv71AWAwg/+gEBoZVe1oL/aiSwPpf+F5hQ+ZaJ1CcGkP67i0g+rkL63dAbK4C vqsz2t/c9jg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF+TCCBOGgAwIBAgIQBQLgLidYQLf5ffP9kBAAoTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwNTI5MTIyNzI4WhcNMjkwNTI5MTIyNzI4WjBrMQswCQYDVQQG EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQzBBBgNVBAMTOkRpZ2lDZXJ0 IFBLSSBQbGF0Zm9ybSBDbGFzcyAzIFNoYXJlZCBTTUlNRSBPcmdhbml6YXRpb24g Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQkBECVnBOF7pzAfLg DpTHWk3+wHknb1xumm/2ELQDJPLbE2r3S/6e4zvG6FZvbZAoHnqeyPZjaPiUGkfn 321OjgXvSLQjvW4nvzRSZqfnwJYR0nVpjyGIMp8btxQr4uSlxnaQvEixu+Rb/Xlk twfqpp1jT1Z8Ocbj7RbUJNVAuVUqX8q7J8zb74wQOiAzajgRpcw7un5MjMsG68AS 7xCxD6v74Tx7Nl3FJhftLwhizhXsHm1vEf8DEVmfK6CBMoGHeQk9+OtKFU/ZpJ0p wZv8egqJ1xHI8z8hb888gA3GO8rQgBODQ4zzt8N5NPlG7aPiox5QZfN5VX6mX2Cg MmQ/AgMBAAGjggKdMIICmTAdBgNVHQ4EFgQUBjF2UHQQopewmD/2j3J00ov98WUw HwYDVR0jBBgwFoAUzsNKuZlV8rjbYL+pfr1WtZc2p9YwDgYDVR0PAQH/BAQDAgGG MCoGA1UdJQQjMCEGCCsGAQUFBwMEBgorBgEEAYI3CgMMBgkqhkiG9y8BAQUwEgYD VR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0 dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDov L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNybDA6 oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElE Um9vdEcyLmNybDCCASIGA1UdIASCARkwggEVMIIBEQYJYIZIAYb9bAUDMIIBAjAo BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCB1QYIKwYB BQUHAgIwgcgMgcVBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0 ZXMgYWNjZXB0YW5jZSBvZiB0aGUgRGlnaUNlcnQgQ1AvQ1BTIGFuZCBSZWx5aW5n IFBhcnR5IEFncmVlbWVudCB3aGljaCBsaW1pdCBsaWFiaWxpdHkgYW5kIGFyZSBp bmNvcnBvcmF0ZWQgaGVyZWluIGJ5IHJlZmVyZW5jZS4gaHR0cHM6Ly93d3cuZGln aWNlcnQuY29tL3JwYS11YTAnBgNVHREEIDAepBwwGjEYMBYGA1UEAxMPRGlnaUNl cnRQS0ktMy00MA0GCSqGSIb3DQEBCwUAA4IBAQAf99w9uHX9H7GkLtcqtkb1RNUn ReGdLi1ROLtjOt7M7vUWGNGPEQm2hjta+y+L1opJCJIOew7DYKMfpo1c2su+XEtC XjXPjGW+2jCv9K3dSoz1P5D2Qdx/ZiQ2Tu/GXVuCTSLvQPeSvn3+3APFjC1p+mXb AOocbqMH+zHft1uG2NJHw8OnRxE/bZ3wJ6TH7k56aKvw8h7EgIW9elHP36uAjOmx k0/XjwqpdxSbIrgj7Lv49Lv4hBaLw6anHKV7ObqWVyC65jTDm1n1EKi+kEBQDUm2 sW4km0fuxFPLs0k1JrET0pI06UfxwnPcwJCVaFI0+gqeNhnvvQwpz/Wvc3AS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHzCCBQegAwIBAgIQA7gNA3OmuuKEHbLRsCd0qzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwNjA0MTIzNjIwWhcNMjkwNjA0MTIzNjIwWjBvMQswCQYDVQQG EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xRzBFBgNVBAMTPkRpZ2lDZXJ0 IFBLSSBQbGF0Zm9ybSBDMiBTaGFyZWQgU01JTUUgSW5kaXZpZHVhbCBTdWJzY3Jp YmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApmsvCMgojDJd 5YC6OgUq3SwSr8dFNSmUf/D870v67GQwUCS7lYJjk2gcVKzaqPVrXoyPZnuR4oWx yhPQbcnXMgvH/vHDkDl94To7NEma9j/XlwEfEln9Kf0P9TZGEaK44z6OM9EaLxJ1 /3JdKH+wp8tH1uubTAbf3sWsUE7KOhGtYkRfVPG3+mbBZHr7DbdVikmPV/0L1lIX 6GW+H7KGvCVGZCTM29dsEv3C51oWjuRu3KmfhNiqobqpTwq5VBhTVbmj3BrLmUct l9QcjIAOFSCMDTRtEZT2vikqqYsTukSu5Fk5beQRoYLSsOzJ7g3C7TNgXEsmjyBK mZ2qZ+an+wIDAQABo4ICvzCCArswHQYDVR0OBBYEFNy3HyAxdEuUGnatg4Kt+Maj 8ERfMB8GA1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWXNqfWMA4GA1UdDwEB/wQE AwIBhjBMBgNVHSUERTBDBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwQG CisGAQQBgjcUAgIGCisGAQQBgjcKAwwGCSqGSIb3LwEBBTASBgNVHRMBAf8ECDAG AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au ZGlnaWNlcnQuY29tMIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdp Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMDqgOKA2hjRodHRw Oi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3Js MIIBIgYDVR0gBIIBGTCCARUwggERBglghkgBhv1sBQIwggECMCgGCCsGAQUFBwIB FhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIHVBggrBgEFBQcCAjCByAyB xUFueSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRh bmNlIG9mIHRoZSBEaWdpQ2VydCBDUC9DUFMgYW5kIFJlbHlpbmcgUGFydHkgQWdy ZWVtZW50IHdoaWNoIGxpbWl0IGxpYWJpbGl0eSBhbmQgYXJlIGluY29ycG9yYXRl ZCBoZXJlaW4gYnkgcmVmZXJlbmNlLiBodHRwczovL3d3dy5kaWdpY2VydC5jb20v cnBhLXVhMCcGA1UdEQQgMB6kHDAaMRgwFgYDVQQDEw9EaWdpQ2VydFBLSS0zLTIw DQYJKoZIhvcNAQELBQADggEBABU3M2Y7bTJ04TzMUMnnrmf1XkBwjTasQs3uuODt fcVxNFrd6gcdVUVP0HS+JD7QFr4PbDB4ULS76fckp2uLhefn3xUHh1G19dsga35o AE3Shz9p6D3slQl53LpUqrBfxf/OeHQVvWdY3zLb8af6m0zzn/XeXdZsbfpieLA3 73dMJd1NsFQiTFG0l47PGpR3lOnpmrSMF4qLObJ9nEHCKTLZv8ko2L4YeBtQzFK0 HaSWUwaL7l4fMgN1K6vGYJgXeps3puOdCwePH2uk0MkVGSX69uinvBDqwRCi6L4v okwjEG0LEfuExLCZSQT3ppMKqXHyOFdxlWEI6utxAgtn7QE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEAjCCA4egAwIBAgIRAOpIk61orHAPef2Hvc1iyL0wCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDYw NzAwMDAwMFoXDTI5MDYwNjIzNTk1OVowgcsxCzAJBgNVBAYTAkNOMRAwDgYDVQQI EwdTaWNodWFuMRAwDgYDVQQHEwdDaGVuZ2R1MScwJQYDVQQKDB7miJDpg73mlbDo r4Hnp5HmioDmnInpmZDlhazlj7gxNjA0BgNVBAsTLUNvbnRyb2xsZWQgYnkgU2Vj dGlnbyBleGNsdXNpdmVseSBmb3IgQml0Q2VydDE3MDUGA1UEAxMuQml0Q2VydCBF Q0MgRXh0ZW5kZWQgVmFsaWRhdGlvbiBTZWN1cmUgU2l0ZSBDQTBZMBMGByqGSM49 AgEGCCqGSM49AwEHA0IABKedESfG0lalS2WFqpIkG6B/bj1mVcd1Uz6bAPL6WlOg XHePqEJPZv8cLLCmz4+rWDrKUODh+1f5DjQHKr5djDejggGLMIIBhzAfBgNVHSME GDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQU1ck/T2D/TUUBJW+w MMAbC2TZ7fEwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYEVR0gADAl MCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBH MEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2Vy dGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUF BzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQWRkVHJ1 c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w CgYIKoZIzj0EAwMDaQAwZgIxAKMZCjYp22VIGOgX/r4fE5BWkXGbL/CKoORIF2+/ sK9Mti84fcKOiOfpTCYWUJ7P5QIxAM5hatqf4w5F0YBcDClnhVab7KGjk/XDiobp e/y6bZe33FmFTZIqW8lyz2Sf94lBvQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjzCCAxWgAwIBAgIQYCaE3KLvXvXpBrvuaFjAVjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwNjA3 MDAwMDAwWhcNMjkwNjA2MjM1OTU5WjBxMQswCQYDVQQGEwJDTjEQMA4GA1UECBMH U2ljaHVhbjEQMA4GA1UEBxMHQ2hlbmdkdTEQMA4GA1UEChMHQml0Q2VydDEsMCoG A1UEAxMjQml0Q2VydCBFQ0MgQnVzaW5lc3MgU2VjdXJlIFNpdGUgQ0EwWTATBgcq hkjOPQIBBggqhkjOPQMBBwNCAAQVcZpDdpMoNpqcCecn5OajxwMJvYaPbi8rVrpw wE51MXFG1ius11Sljp2Wmo3NU/FZCjrMU7H24HdkQF1IIpLyo4IBdTCCAXEwHwYD VR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFI0Xfdtmrnge EFVICnyIJIght52gMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEA MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysG AQQBsjEBAgJGMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0 eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVz ZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUH MAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaAAwZQIw DAg1WfHGopjBoIVFsWht8Rjtru813wxFp6n4HmaTijzo5G0s+NhOijho70U9xlEs AjEAm9lW5qzmg9oegFE/vNyTNHR6/0XqqaVS/vH4ZNEpnoQJNf2jIcGLM/obN12m VOKr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF+TCCA+GgAwIBAgIQR/MRXCxMd87EIlwE8gPGmDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NjA3MDAwMDAwWhcNMjkwNjA2MjM1OTU5WjBvMQswCQYDVQQGEwJDTjEQMA4GA1UE CBMHU2ljaHVhbjEQMA4GA1UEBxMHQ2hlbmdkdTEQMA4GA1UEChMHQml0Q2VydDEq MCgGA1UEAxMhQml0Q2VydCBSU0EgRG9tYWluIFNlY3VyZSBTaXRlIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtfgx4yEcy8y6ALS6kL5hFXNeh/Hn Is4Mbm0pyAgobTFZ38fSewyUe9D5IWnprySLkISAER5Yg/6K3XNgBRhsYBanh+J+ eQBFhmfBxPQ1U9MTK6XkhJfk+5VU4jR63zto0Du6mpiacrsjIdR/TlUicdRamITI BIjiAMAzXP6vQMvSJct++ON7LXmc1EV4Hy7gWXKmtcpgyabIZ93AXp+qxNoekw7e KYIkzAMLUE2W//1I2xzr99MZUpD6uJO8Yc1DCebQYjMJgq/9a9QEf0kQmWqU4Yc9 D8d/6vagsIERlVWJEWmlHlqXmXGiAJntIpkdmW3BREU5735/LbedJECtIwIDAQAB o4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0O BBYEFEU+vFx4YU3+ZPWWrInkE/GhdTdzMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNV HSAEGzAZMA0GCysGAQQBsjEBAgJGMAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5j cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI hvcNAQEMBQADggIBAFNW7wVmdBf7ziKMnYhEA+ak6nJCMRUEpS4+hy9qDBU7zKzM VjGJZZRyJQplssncT6BpVAqfeOV3BD1GEVuu94Qmukk/JKVeChnS9nlRO1XKDa8m lUh19q5irebvgQSgNLbpgWdlc3+osBAuhZe2OiUzLcpuYN0NZvOeYJtpMYst8ils k78glaKJRq/jRxpsgoFkChAq/G8oqYgzDFYhkIII4XYO9s0Sw/tU99kVgAx3uU2q 7DfAoE2xtS/lH8+i20sHmNi9ArFfgLPk4M827BQ+N1YHBy39gphpoLgYGqGJleTx 7crBElsDgQ1tczCtkz6IdvApQxkPtWeb5nMtFdFuBoBuZAHUg8pleN4XojQFpfRO FxWaox/Gmn8AOnHE6Mzg4j8P541AbLS48VoYkHLYb4E6Nik2vIPaG35GWC8565TC wBvOmEFiw/IFRfaAwI8jpMkmiiCgvm/vGtK4I9Nj0KrIU4+0n1OHK3oZFr3PXIYj dW7VeGN4/BswbSrQBgZIE1Um5PQrrbxSsZAr5ZDNjPXIIVTud6L8SLCxtPKVk9Ly Bsk+Elki2oIijxo8FQx6Rao2hRL58YFw9SHBB+wAxgkTwzRI4PrAeAR9IbRADmkf ZeUs+KS3hM9uUDdNrY2mpXiAHHSN0dqEkFivlVDubxvSBsv129GkrwOrzTzM -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF/DCCA+SgAwIBAgIRANEnjaFHQ6zb6K9cZ5Nsj9cwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDYwNzAwMDAwMFoXDTI5MDYwNjIzNTk1OVowcTELMAkGA1UEBhMCQ04xEDAOBgNV BAgTB1NpY2h1YW4xEDAOBgNVBAcTB0NoZW5nZHUxEDAOBgNVBAoTB0JpdENlcnQx LDAqBgNVBAMTI0JpdENlcnQgUlNBIEJ1c2luZXNzIFNlY3VyZSBTaXRlIENBMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0LwaFwg4a/gg/CnqYXJ8zMQC oZyYR1W2vowofV2hkjP7ye9+LOxoNUJMPtAe86ieFaFvwOvncNNQ5O1cBqpd80BL Xo6KeeCUsxuwFGqt2lniWjlMEIf/5+YKg0Jc9cOk4pbcQ5jXjibxo5dafaLHhbPq Y8MbQcok/nw0al2Oh8ANOLfnhN0nh6kcieHb67CfnJ8OZ/gCtT2PKJs0Be4aOVN6 YZmjzxbQ/GdvJfHMaa/nX8w855DAnFN7Zio/za5CCo5xCeuoK9IuNmtv/WYgWxUi nChGHFTc6OnDspZXVmM2T3pWxAkMcL5/1a81gg7uQsrY2HJt7IqfrCgcI4s9lQID AQABo4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYD VR0OBBYEFLbYuV62++gTnv+JhUTyPgEHouVCMA4GA1UdDwEB/wQEAwIBhjASBgNV HRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAi BgNVHSAEGzAZMA0GCysGAQQBsjEBAgJGMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWg Q6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlm aWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAC hjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RD QS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJ KoZIhvcNAQEMBQADggIBADFoqJOunOEFTgpwawxzkkBiQVw5TkWrYjwhh1jxu5lq GRWw5D2xnVQjsRhR824csP5n7v7G6UyMuQ5TsrSiYs7KBCmF5IVugglMJgdllRg+ Xd6FIouzAkAOan+g+b2Wjf1IwdRTysVNZdP8uBG9ItVoNsZudm7uRLExJA137vwz MtObbRLSz4ZGbDvFNb6V9bEtEsb+bGXe9sEqkIa49T0pcnTRVF6j1/hu8lK76Br1 A3iuTh9edFOdvEFxBiChmg2rrW0D9ZkzynG+ZyRYAoSl3RKSLVgVvUgzbgFoz95O pW8Rspg1iaiVFeR+cd0n5aEB5yXZgFNCLF2FdtRGHovt2Mrfy6AKeqc16iSfzY/z 5CAvrv7wNeVDHXbm+DvEJsrTkLTp9BdPMzZSlkxpP8IQMPr2QlTXqanDNcHtChdW FO/Bak+C1Yx4JILq/4Adt+Os4eAXWwVK4ni6PQKtFnxs/aypzEBzyxhbOANMEQwo hg1Bfr30oox6xf6V4iARudIhzgMCyC6WOvhOka0upNWw0hlQWNTnV0GehjdvJA6x PDS03UogK3ZQTWvTUw/uxTuO3KLL2T/i9LqPeKmAtOxbWYsno6z3fB1ym0+3Ygs1 oLAvMO6su4rbwcxsaaoYrSZTIze4fIb4OsKFx0EIcU6+JExrRLHCj9NoUaPaq6x8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGbTCCBFWgAwIBAgIRAL0Vx/BRSgtL42nPtEwKrC0wDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDYwNzAwMDAwMFoXDTI5MDYwNjIzNTk1OVowgcsxCzAJBgNVBAYTAkNOMRAwDgYD VQQIEwdTaWNodWFuMRAwDgYDVQQHEwdDaGVuZ2R1MScwJQYDVQQKDB7miJDpg73m lbDor4Hnp5HmioDmnInpmZDlhazlj7gxNjA0BgNVBAsTLUNvbnRyb2xsZWQgYnkg U2VjdGlnbyBleGNsdXNpdmVseSBmb3IgQml0Q2VydDE3MDUGA1UEAxMuQml0Q2Vy dCBSU0EgRXh0ZW5kZWQgVmFsaWRhdGlvbiBTZWN1cmUgU2l0ZSBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBANt0sOukla6L0cMyqo73Lqqnb4XdWxBu THls9Kb6cwKFkfQc6HdFw6I2XQ77J2op0Fkd7ZDnO1K2doZT9Nlh8GrWw8zlnWLT wvO1nPHJBvNXljwPOZHAYexApcu2zqIYBO0+A7VltpZ1ZUVrinWV1AF4vK75QZ0p Xg4ol++4b2WUahF+3xZGXl1DXDAGI1HXrEaeR6wub8ykPmMDHVOn0TVOeiKiI/Xq jnSL7C8Pe8oYxgtkvB2JirpX5Spk/WkOQGBg4akacI6s48nT7Umjs4A2WYXbWfJ7 nnKfkc0c23krOv03W3DVb837q9iXVbwGqld/YlV9ihVYnGlE4MzD+e8CAwEAAaOC AYswggGHMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQW BBSHRjeuKMGSJn6TwsutzAqNi8xB8DAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/ BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwOAYDVR0g BDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20v Q1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V U0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcB AQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VS VHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3Au dXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAV/XmKlkXgMyV36a9v8sN KpuK/oI/JV5WcpzWZ+F5WzAPBKePpw3VwN657wWPqWQBgmzJheocoTYw8IFJerZw yNyMCp56wfEbqXsG/XnFtXriVhPWZy+K7vAK3jtc/XZnPlGJiM9fhFJkoQ61hGE3 /yHVynIlbCYjLzSGW6BusMdT0BwpBM/5l34SFik3Cw8TVE+4UZmkKQWRYJ+P5uPH fnslyn9LSbYD5BURBDV5l2HiIU0FSDVa6tmCNTodbb3UdQLmI/shZmqZCYBHbgY5 Dynnsb9K5eC1fPMk82jxl7ARDjGB0dghpFxBKywzADAQAWwRj0revBdVmzlNdMHL JWsrCEixmqKQMakaY4KuYH7G6xInX9S7dDLcjdDoSvNHz7cc/wksDw93oFQeg6w7 aIm1TvB/fP9/STtqZlZePGhrSHFLh00zWPGVmLHDXfFCyTAJObXygdOiZhNRQWVR fR7zvoC3WW5WvaV0hAPEkKqIXubp6wdjuX8mbg3nj9Hc8Zs7OlVjL+WRcfjh2JoF we1ds4L1W57Zo4SjTg5ztRsJr6RHTymLjVce7R48niWinoerOFAho2uhLPZyGrai Ar63JmRtqpIPksXpEkCN4Uw3FmDhElxbOv8V0txOLv/55lUkgbH+L2RHx+5OY+8n IaHxnaUds9ylSrXKeU8mDs4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjDCCAxOgAwIBAgIQdL/Q1Wcmd0a3xAfXXsaVVDAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwNjA3 MDAwMDAwWhcNMjkwNjA2MjM1OTU5WjBvMQswCQYDVQQGEwJDTjEQMA4GA1UECBMH U2ljaHVhbjEQMA4GA1UEBxMHQ2hlbmdkdTEQMA4GA1UEChMHQml0Q2VydDEqMCgG A1UEAxMhQml0Q2VydCBFQ0MgRG9tYWluIFNlY3VyZSBTaXRlIENBMFkwEwYHKoZI zj0CAQYIKoZIzj0DAQcDQgAEzK2z6gVEhgl+VHFko8+i18F0L/qMHrbMMr5LdTh4 y8mPZPLUZ/njLgCj6NLhY2upbLT7ga3rypl4vwXbY0nlPqOCAXUwggFxMB8GA1Ud IwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBTK7DxP4yI8LU6V ApowMlVcaPWbKzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAd BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEE AbIxAQICRjAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51 c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHku Y3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2Vy dHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzAB hhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2cAMGQCME+J 5TYDyjvmfCghX1ibMK2/2CZt5/mzyHAYZfBLzE20sNnrY/RwoS4JttTkPriwaAIw R1DTS3xOiIXa2WBusVDqfLn4siLjfEOOF7bbjexa5SExk8Qhyi9bZpYicDAVangI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF6DCCA9CgAwIBAgIQGJyrYyrMApEs9N5xV5SnRzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NjA3MDAwMDAwWhcNMjkwNjA2MjM1OTU5WjBoMQswCQYDVQQGEwJDTjEQMA4GA1UE CBMHU2ljaHVhbjEQMA4GA1UEBxMHQ2hlbmdkdTEQMA4GA1UEChMHQml0Q2VydDEj MCEGA1UEAxMaQml0Q2VydCBTSEEyIEFzc3VyZWQgSUQgQ0EwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQC0I7JtgKAziXn/Zcpr0huZLxozVqc8KuLRcEcd 1nHUd2A26jekCyvMWGGmyxmi0y7RDQF0Pdrq8lRk7cmsIn0mA5zNC1A/3t3EPjna eXtbCCOMo7SoaVbia3THy2zR/dAkeJa4NONB6CrPjIOhfKNXL1RUQ64W+6LGvH+J NFZU4aZ2cmfZ3tfbsHhLcTY+9HcnVFsnIHZtV67/eeo1ReJP6JE7lYYgHPiW2xWU Yi5Gw82mBOkZy/LTOuHXwDxCCEkWOuxvRkZK49adojWTesMh/OPfOPYQ8Mhd88JJ noeSf2lGI2ZsraBIhTcrN5NXCUfFlMBp3SubV3L2IN9IRqp5AgMBAAGjggFrMIIB ZzAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUWQV1 uJ2qfivB2k4F/z/Q+COqY3YwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBgGA1UdIAQRMA8w DQYLKwYBBAGyMQECAkYwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2Vy dHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3Js MHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1 c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlo dHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBJHuCm Yxy8ZOHCk1WGfb9LVQw0iQ1jH0PuYY+QRwbTNb7d1cwepjjweBLszCA7vfXTkord 7xG7Vox91wBdSFNOZryra+chBo9fzJ4XbsqerBZZMAKnB6LzJ6gl4izudSA12Rag 331LMTVYt1BAXaePW/qUByGUDzjBLdxZKwfrPjhHlOj7blFox/zPWXHtQOi36AEm RUF2aaPmBdX7CwfQnkP90AIgAKAl50IP0ktBes6fafdGqs6KEGzVP9kN69C2ZO4D 4EU+ss6ob8we1AoFOABUf88ioQPVIzEPOVFwsRPKFni3XAbczN7Xza82lHUeoukb eTEtq6u8wTWGNda+xt2CddkbLBmj388ncRjpDCUE04o0He1MXXzWTaGYuMqvQ6ic kRIjhy4cCwljgbo49n97aq/nrq7/85xf675GbNPysdGWCYMCpYl99+VBR2cZX0w8 gAYimN1m0ur8YlTVKCbffK4yQnbQMt3+sy/RtBcONwRgryGK7gIVR6ZMP6Qtv3vq 4Y6pHKVV/Y1uC7m3R/XBXk4nSKaOZt6ar7O9tF0xetA9dms9//qyNJDu5IyVyxi/ Nw+biuiv/ghSaUKFSi3ntsqBocfuRIolrymLbNgUEuFyPOwlm34JMJCfhj8BBevX m6xwBSgunIlw9L15u4sMTvrRYat4fmKBqWpgww== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCTCCA/GgAwIBAgIQTmXWVteLFxnxgmt3QBAbdzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NjEwMDAwMDAwWhcNMjkwNjA5MjM1OTU5WjB/MQswCQYDVQQGEwJTRzESMBAGA1UE CBMJU2luZ2Fwb3JlMRIwEAYDVQQHEwlTaW5nYXBvcmUxGzAZBgNVBAoTEk9uZSBT aWduIFB0ZS4gTHRkLjErMCkGA1UEAxMiT25lU2lnblNTTCBSU0EgRFYgU2VjdXJl IFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANcYlGvF 8gmKpfzbkxPePQHedEZGDD9NHFx+fp5UxRs712j3sR4DQl4I7V978Tu8dGGmVE2p yFk5j0946qsP22fftjwgYUhXQXvRtqqLc6IdqsnJEdaOKKAw9+mna5aUyqehoLmX UXbEs8WzhVHWm6VgWuwpLnwAI1AH/TxLcl+Ge47XDKv2dpd8uHkKikvlwN4/2KzP mroq/hbbUu2sEeApyhaLDd4aYDQZDzmWmNg1SXN+G0wcl3CBh2qARC7V55jMzy6G UTHTgu9Tu5L3cuoMB83EcpO+Ie4s4QIfKMYch+4SoJpHwtWDKE5R0XzXHs0VE+Zh doX287rxev8jXrUCAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh 2JvAnfKyA2bLMB0GA1UdDgQWBBTZ2/swDqfXirFbcGBz/O1+g5UCUjAOBgNVHQ8B Af8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICRzAIBgZngQwBAgEw UAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJU cnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGow aDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2Vy dHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBNu4WihYSXiTPgUjwaVNWDujZ6 EFSYCYvPDLZKw1cNVfoDITMFOy+r5TTGxHkzAwxY9Kg/Xs0zpBCWZHms7ukZRPM0 ctWkAr2TOumA1Vf/3X9N2ydU4ZWLXeudsRS8k4T2eZ7v53aRGUQSlPeD/ErCKCbk ywl6jISh1fvwdxiQmX0fody9photk6G6jcrcblxQIU9LJG1ksK4d+wBPZwR31t1z gszdqEH98LM2K7Rx2ULBeGZGA4D+iRgz/eHExpF5AVMOisiTn65JRtKGLN8XYERB wk9Xirmeuzy1Hb0julx5Fj0jyydCcRlm8Tu6YKEm5HspMY1tYnmyfqQm7xCdbumb 2x4x/f6ceq9rTpBeubRApsnUtYHBttQ0feIFlK7d0MNO+f84EQDTji9Gw7Lqpko0 vIyHo11NR9C3QnoZpnTnlE4vdRQd7MtcgX3/y5XbQ7sUAEzjxwkrFd4AiJNs28FI oWFU/Yp/pD2ww4uIdWipMbp4cvxqBrW1fRQKYsuF6R76KhDHBTpolO5bGTXY4iSM 7Q6WWWGOn+iVmMLg7UCm2sf48n8rOo0KemrlfvAs2mKPSjD0YBJUpPUh60o5idWI CdvAUmnWSs12NSSUJReiMG3zQes11hQGg7SIvJlyBk5+LOPAEhPMuAqYl3o58rEO Nd89rmzgEYorEU2nNA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIRANYHrK4VPXl6KqkLIf8AmDUwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDYxMDAwMDAwMFoXDTI5MDYwOTIzNTk1OVowgZIxCzAJBgNVBAYTAlNHMRIwEAYD VQQIEwlTaW5nYXBvcmUxEjAQBgNVBAcTCVNpbmdhcG9yZTEbMBkGA1UEChMST25l IFNpZ24gUHRlLiBMdGQuMT4wPAYDVQQDEzVPbmVTaWduIFJTQSBDbGllbnQgQXV0 aGVudGljYXRpb24gYW5kIFNlY3VyZSBFbWFpbCBDQTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAJW5P9BcuzSOIQuwHFGlPioJFlUviXlY99IhZ6iNGjth ZSxrgwbSFk8f2Wxoxm2jIdZllVan8G4b7GXDcc/ZfCklB9TnDe7o1FYd8p1rMc7f BkYhuv93iNjNTIVkP3+Fyn8tGsYEkFW3K1fW6OftD5TOII/QXV9jz7zpOYuJKxck JT8isQaY1RuWD26urYi27bfB9EUcNIwo73UIqHyPAG3Ks6kuyv6fl/wlaqACPUOk y7w3qKRPG0IHnUR5/tSPbSoALhIzKbAkN3UpFfly/Kid88cqfiXc88CGUvD5s/bc il1O+EqLWmUb0wIlORF502EebYhgcjsU2CPlq/2AhfkCAwEAAaOCAWswggFnMB8G A1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBQ8KhGVlQJ5 NunCXOOKzbu8nioi+TAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwGAYDVR0gBBEwDzANBgsr BgEEAbIxAQICRzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVz dC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYI KwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5j b20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6 Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBACg27qQ1eUaq JfY/zOf4R6Dx1tpiWJkdLsPHaBptXefXYthiSHaNPtZKM/7xBPy9pYORVqu5uwXa OvESN9U8tWYPOouphepX9+CX0edQZZI9Na4LPs0MpAbfiOiSCK5mqSHRNvN5iasa QoFB4o7BUJFEX0fkdgSiqxsSANuSANaYQGwlC1Nc2XjOf9/+n+9Y9MR9z3asVEEo VIu3y10YmqjBAG9AQZO1obSSvVkFJf2gmwfAmX1DmyoWAN33SRnOf5cRDiqPITAf Kh9FZHMw3+SF9OzErYroVXqbbm2HXuAgVm+ZKsu1Ov9oHJZ5LlCW3Dv/CexxYFj3 LPU+E9hGtVDY5tZf3Jj7VkuYw5Y4crXAvweQ27+wjeTQWaixYFtuID9PKJpVPbQ/ ofsHZTLCfdayykIaHiKSJ4cjPTYoTc4x9p4/4voOx8KZNb2IlJHlzQMIbfr3snBv oMdx03NWF5qjrOYwY3e2gRfm1bKm7rIW+/u93F3Ud2ukESTTQv7HBGAxnjuDQE1C mMFS/wPipf0LVpAnRkZE+/W8w/OUSB5pMHDYDehtj8ZPHvlmSpGLQaaPdRgk96uF /0y8smv/rFR1Xy8DdDxZJlcRBXikVpEIiPr2Jx0nT3hxqMOP4yyVto3z9Seda96H MvzMmNTSBBnoxO7l6hu9F5rPeh8CsWg2 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnTCCAyOgAwIBAgIQRB/KBH9VgbnLpOJqZoTyozAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwNjEw MDAwMDAwWhcNMjkwNjA5MjM1OTU5WjB/MQswCQYDVQQGEwJTRzESMBAGA1UECBMJ U2luZ2Fwb3JlMRIwEAYDVQQHEwlTaW5nYXBvcmUxGzAZBgNVBAoTEk9uZSBTaWdu IFB0ZS4gTHRkLjErMCkGA1UEAxMiT25lU2lnblNTTCBFQ0MgRFYgU2VjdXJlIFNl cnZlciBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF806+/XDCxx1OhI4IDN SBiEUL3WJEnRKD9puaABAO+lkn62PWKTWRyQh/DMyV/jquIh4NBxXXB1mYEwKUbL JX2jggF1MIIBcTAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNV HQ4EFgQUe/Z7cKzVTTZ2CT3yiDHq7pNvJDYwDgYDVR0PAQH/BAQDAgGGMBIGA1Ud EwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIG A1UdIAQbMBkwDQYLKwYBBAGyMQECAkcwCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBD oEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZp Y2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKG M2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENB LmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggq hkjOPQQDAwNoADBlAjEA44r6o6Z0fk9LkBM/rWHJHRnnAUp9Xk9SOV2f6UhmKgeD j7Z2L7Yo5uXkNXbSSlPMAjBNuD1eZPsa01x5O1s95Ah1n1cqQWEx2RlOQjPAusSl hqLPAfRaBwH+DT3+WIe4CFo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnDCCAyOgAwIBAgIQYzZ5NUTvDA50idDA9enfsjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwNjEw MDAwMDAwWhcNMjkwNjA5MjM1OTU5WjB/MQswCQYDVQQGEwJTRzESMBAGA1UECBMJ U2luZ2Fwb3JlMRIwEAYDVQQHEwlTaW5nYXBvcmUxGzAZBgNVBAoTEk9uZSBTaWdu IFB0ZS4gTHRkLjErMCkGA1UEAxMiT25lU2lnblNTTCBFQ0MgT1YgU2VjdXJlIFNl cnZlciBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABMCLKH/oZ9jYxeRxy2Qa XmAS5xOONO9Ai3YZq7nDdaYRPvgSnluO2YiZJLNfWjW2zQHMcesa1n86TRAH2osd FQmjggF1MIIBcTAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNV HQ4EFgQUzbnM1P7AYzxO6CKim9pC9TX5FOMwDgYDVR0PAQH/BAQDAgGGMBIGA1Ud EwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIG A1UdIAQbMBkwDQYLKwYBBAGyMQECAkcwCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBD oEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZp Y2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKG M2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENB LmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggq hkjOPQQDAwNnADBkAjBOwLFrlbXq0KZKtu8RYOX78QVYJQRxxf8fFHl6rQaIjgj/ EVwKteSri+f7LOUoEBsCMCuoR9jhJV1p7u+ZJA4DzbZ5lD/iggQFV0d+higVRuAA CYhHWFgfkB2wDTlyotARvA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGYzCCBEugAwIBAgIQfIlUE7QV1z23hAUnk4IoTDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NjEwMDAwMDAwWhcNMjkwNjA5MjM1OTU5WjCBwjELMAkGA1UEBhMCU0cxEjAQBgNV BAgTCVNpbmdhcG9yZTESMBAGA1UEBxMJU2luZ2Fwb3JlMRswGQYDVQQKExJPbmUg U2lnbiBQdGUuIEx0ZC4xQTA/BgNVBAsTOENvbnRyb2xsZWQgYnkgU2VjdGlnbyBl eGNsdXNpdmVseSBmb3IgT25lIFNpZ24gUHRlLiBMdGQuMSswKQYDVQQDEyJPbmVT aWduU1NMIFJTQSBFViBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAvhKNlELkq0uYGXo5lDhn9Djmz3n0GZ/wVYomfc5PzNk3 A2Fl7KTnHQJPgpJl3aOhid/9GhYdMLo9PfhouFIoLYSG+8i0diAdyL5YjKuD9++W QWEJvVOPbRGj708kFbWfy2+nfiVQ2G/5sxcMhlPuXZicLNHCpYn3vDfzAxxQZAtU LnlRGuiHlD7ooV62ZHi84Ysy98brq3a/rF7HAMYq8uGDseg0+1O/sxmonlsOtH9Q lA7t6j9XF06uHomZUufLoYxMnEYw8388efwyZghr7KaEwlCsQMLmYhH0J+DQF21v XdlPje/vXDgZDUn+xCqxv4wFX0MQ7Gv/fnMPvpbvFwIDAQABo4IBizCCAYcwHwYD VR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFGwtg2HsMHRg C1l4SzLYRAwmVjm4MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEA MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4BgNVHSAEMTAvMC0GBFUd IAAwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwUAYDVR0f BEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT QUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/Bggr BgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFk ZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3Qu Y29tMA0GCSqGSIb3DQEBDAUAA4ICAQBfWWEEQ8R+AZKKCNrF/p9kGX/pBEU24QUx yKHx6jrJK4yaVAF1Q01uq3/QYpfV86yucqq4dQ+9+/iRI5yCogtcuEtorshTcC9a Ya7jwaxWWjZzdwrS+8zxhYI05k0AiASDFlXP+RJaF3tX7s+d7gEjnmi5nQL72YbN mMZ9goFVDTTUEduM5tmKEjx2LiNneUKGx8bkkJnVeNiEr++AzSZAoCwBv/J0O7NA oQpmjRQhHWjRtxcz1zAf6DQsKr65hfsLpuDEiPKm/UpGTu83VmqZYjBr/tr6eNUo SanyBQFQTbQSpMv/WoNteZ5k5ovKUwckVAQoXcC68tZ/GQDplu7iRK3M8Bzm7E+S Cp3uqf2Q+uw6EsSfkVjLxZh5PQJVnUJ+MbPXA9adg9xCoEiEwMvvl/9McTZJ82Xl b320mQppNVxRouu3pPB5pMIb9x3W+W2GxUt63poaJRT4Jzo9MhwtA8Ccafkzpp9i yVz7fvHGSTA+/o0elks/Dxhw0T1iXsF3P3yMIJg+dUOZ2+9etEbKxipMrfM2vRFs IH3DoNIL9AoDsgVKjbTWpxWbeQHz+q31psF2DfvJ9c7ryPYLjjvrf/mYohDciJvZ bw+GdKhmDo6JqtSDHIWp/uT3c0Q14TTCA5Qbw2P3h/Th9TXKA/ZRa52sAJmgnFfe 6c0bqXjsvg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID+DCCA36gAwIBAgIRAMY69krIIEy3g9QM90onyCswCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDYx MDAwMDAwMFoXDTI5MDYwOTIzNTk1OVowgcIxCzAJBgNVBAYTAlNHMRIwEAYDVQQI EwlTaW5nYXBvcmUxEjAQBgNVBAcTCVNpbmdhcG9yZTEbMBkGA1UEChMST25lIFNp Z24gUHRlLiBMdGQuMUEwPwYDVQQLEzhDb250cm9sbGVkIGJ5IFNlY3RpZ28gZXhj bHVzaXZlbHkgZm9yIE9uZSBTaWduIFB0ZS4gTHRkLjErMCkGA1UEAxMiT25lU2ln blNTTCBFQ0MgRVYgU2VjdXJlIFNlcnZlciBDQTBZMBMGByqGSM49AgEGCCqGSM49 AwEHA0IABFbx24iujAMGtIKjy/Me7PKK0m+iytEwU0W3QXMjVs3JQ07P9TjkKl+G dj/s2D5RnLvTkASnp3o11DRIHfzE7VijggGLMIIBhzAfBgNVHSMEGDAWgBQ64QmG 1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQU575pjHsGxyO2vgtW+rM2RInN6AQw DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUF BwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9o dHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlv bkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRw Oi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQWRkVHJ1c3RDQS5jcnQw JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0E AwMDaAAwZQIxAKkVCKRWtGfp5J4nXQQpKM/3KduAcTHZSVANOFGnX7qXS1gcrUYB 3prbGOU1NkTB/QIwBNg7rp/l1wrA6ey6cylHCVTWNJ8nSlIitafOfVbAuXVvW1P9 /A+HpB3vZvl90+Hj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCTCCA/GgAwIBAgIQWapRhJsNopDxPcmcnDyxdTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NjEwMDAwMDAwWhcNMjkwNjA5MjM1OTU5WjB/MQswCQYDVQQGEwJTRzESMBAGA1UE CBMJU2luZ2Fwb3JlMRIwEAYDVQQHEwlTaW5nYXBvcmUxGzAZBgNVBAoTEk9uZSBT aWduIFB0ZS4gTHRkLjErMCkGA1UEAxMiT25lU2lnblNTTCBSU0EgT1YgU2VjdXJl IFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCqUy0m mVb/GJOLCKt21hOVG6w6Pl/lXKAVG8eJ2XxvPKg1ExtxMpxZrEOTPpnqrJ5rfXwA ejYqHw5bhIXb9EVD8Wg2Rft/i2iAx8CHIiV6YSpinnlx4vW+zCLNHIxYRMUxrS9A UDqE+tZuEH5ymXLnO4fJpyf7jleBODgHZkRG8jOhfSmSPrbxX/x9lLjQatGzTD1d MoqofS4jpgxXoZe3Fjoak1igo485zu3wUg+98xcn81JqR9QFU9Jy/2vm2WYAPKNj 9A4p6dBF5XlkUJKPurden1T/kAmr4IOpJ9JfRQiZ6nMME0RSREdEWZO3Ox5/HE9T i17EFJp3+psal1kCAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh 2JvAnfKyA2bLMB0GA1UdDgQWBBRUACDlSFFUEyfuGI1wviuQV9pycTAOBgNVHQ8B Af8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICRzAIBgZngQwBAgIw UAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJU cnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGow aDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2Vy dHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAQDdqQog8/ApA2RcwXepFGjoS7 Prg+yeIWFaviL46oroTQ29J7idbSidfvafaadqTmaLiJeq+hHxLgWk1XPoDAnSLq 1IanfzX54fWDiTbjivlxGuXhEWG4uQwxUHMKCwSbxfsBYGDXKOMy5KoUFAHcj6Uo bVNUTkFpGeOlxh7FcUx2v19LKHZtOzuLR1mzZoW49daapczg06zCMFwWbJXJL1qG tZDYaNEHaChtuLnm1JEyDKVux7TCGWV9w1kmKbjNr5gTSj4skHOQ/l11weMklTeW q7Mvfl/kq9/K/Zxtrf4MnvyoXkJE8SjaPXw2fC6Qe/FHxwER5CHhqKUV6jJFyr97 Cf9tJ6FZb9QF/2AlI9vGK34d55tOTAGfc6GIGJ9MV8gcWrG+Sb8g3JRqWZqJ5w2m b0N/PFeFMwXIwmPwwCmW6DhSVpiMcVEYKc+Cm1KNubfBTEGpAMRD6Zw11UqnmJLu VHLrhbLPLPj3BTTmgKSYlB8gqAHMLRdp+Mr3Nks6h2O1YgFVBUnbrcvsGlBd39i0 +1Imj7n3kAwDGtPhv7RIRcsWqQrQypsYhHK0ojvCzqgiiXXDzR0lVko24+vJGnUC 7nAOX9DcmT35nSIki5ymQXwi7odtGuu5DHa91ryOKp8qM9A5FyuC6sK/HJtqxC36 d//1naGE/rfgl5DWcA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8zCCA9ugAwIBAgIQacBXDW4hRjGa0eWDTgSdzDANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE5MDYxMjA4 MTAwN1oXDTI3MDUyMTA4MTAwN1owdzELMAkGA1UEBhMCQ04xMTAvBgNVBAoMKEtp bmduZXQgSW5mb3JtYXRpb24gVGVjaG5vbG9neSBDby4sIEx0ZC4xFDASBgNVBAsM C0tpbmduZXR0ZWNoMR8wHQYDVQQDDBZPS0NFUlQgUjQgRFYgU1NMIENBIEcyMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu9JK8vwFAT3g1JubBXTXIcO3 FfD209QVmBsAZo1m1S9XAT34fvRa/vUHdfoeHio+bZmHKs8bFlcKSPB4x3LqIVWO IskAnJewGe4mxOCjL+sIWh3X6TVRTgY/XdekbDNKJ5q1UdSaxt3WmcFMSmBaZcvq 00/2CBZVRx/AQZm56dGtmmP8cliJHgkM4m9JGfaMpgHhnnDvjEQnYoH2Ku7J0NUU 4ut0Oty8hJTclLX1eItoltmKx3kHNgr6SuG4uadUnXITlWAErvFyh16MyPUIY0CM jRnGbmN3iVKwZmnTJy6aj0m8xIj/LJAwLaH/WotUnWsz5qmYIEF9KSxVNtjd5QID AQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUut7yQf4d M1qCR5XtKBoYVvpvtNIwHwYDVR0jBBgwFoAUVJndm//opw6jGZ1bvkJX3zD8jzIw DgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4 BgNVHR8EMTAvMC2gK6AphidodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9nc2Nh c2hhMi5jcmwwbgYIKwYBBQUHAQEEYjBgMCgGCCsGAQUFBzABhhxodHRwOi8vc3Vi Y2Eub2NzcC1jZXJ0dW0uY29tMDQGCCsGAQUFBzAChihodHRwOi8vcmVwb3NpdG9y eS5jZXJ0dW0ucGwvZ3NjYXNoYTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQG CCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQEL BQADggEBACyLFhxwH6ygdyWEeRxSHolkOF3/UTBfab5t0vbQ0iCCerR73Zq0TJwx sA6LApBDPp8TEfevV0HSIVzVPnDihwMCJpY6Y0uwWxycByhWgx3IkgNBzDBM1IA0 Ulfinh36U7mQCeHKy3B7/RAqlnB6lYa/YFIaxQ8QCUg4WRy/De06yxndblbLiEYe O1F2KYo2cpVXQsAnm1ZXocm+m7+DDd2WtSNP5EKqwqQ5E1NPQhe6OJC5B7wcT6b2 w9ydywvxIziCm7+JHZEHuctzAVuURjw9HR8F+3YpVpXPqJ2w1x95cv/rD5cHHCOx WkrtRrKz1lX8hTiUIaFXWgQpbuyQjQ4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8zCCA9ugAwIBAgIQExCcvNQp6uiB8J4hXy3tODANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE5MDYxMjA4 MTIwOVoXDTI3MDUyMTA4MTIwOVowdzELMAkGA1UEBhMCQ04xMTAvBgNVBAoMKEtp bmduZXQgSW5mb3JtYXRpb24gVGVjaG5vbG9neSBDby4sIEx0ZC4xFDASBgNVBAsM C0tpbmduZXR0ZWNoMR8wHQYDVQQDDBZPS0NFUlQgUjQgRVYgU1NMIENBIEcyMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAogiPK5lB9HtHQ1bRZySHal0Z 3Jupl2OA3JhLnnrprEspoG5mF4dtaxdnU9I1zLCZgVZwCzkVQEp96klBgz7L0Y4T Y9rGBDpSnTila3k4C7P/tu7Id1ZMrU8S/BbFOCD1GEd6uZkNEJNfKqu5bX2P4WgZ fxaK6/EVzo//sBLWyZhS0NeP2bVSNPFht4ttg88B0k6vsoje0oU7JcKco8zZdfl5 ofo70NNXw8vPluSe6IjyZgQSLhg0j5OySnO0vypl3s6ahviWyU6emmyrXm5PX7JR /EczIxhCu7/kfFBpQlu4rGEt/C0jd7QwlCBpZQCgclgQ0yTAUTu4wIP603qgOwID AQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUNDo5si9z Mg0jLHpv+oD7Ap9EfTowHwYDVR0jBBgwFoAUVJndm//opw6jGZ1bvkJX3zD8jzIw DgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4 BgNVHR8EMTAvMC2gK6AphidodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9nc2Nh c2hhMi5jcmwwbgYIKwYBBQUHAQEEYjBgMCgGCCsGAQUFBzABhhxodHRwOi8vc3Vi Y2Eub2NzcC1jZXJ0dW0uY29tMDQGCCsGAQUFBzAChihodHRwOi8vcmVwb3NpdG9y eS5jZXJ0dW0ucGwvZ3NjYXNoYTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQG CCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQEL BQADggEBAMTxakL3WBnjhNd0O4FyI42h0pPjouN6/eUVzBYdqUTDH+EhLDkBmH0g Lb/SawcPsA1tdWgDMLHdw0XtLhgs1PF66y5gF53QAqxMHNdD5d5jrR7hwk29s1a2 y15JEkMUjgOoXKRgYwVTlFecx8tBDrcgrGAdwX5Gxkn/Mc/y5Dw5Y7O8LC7JIFyY xyibmW2PgkuHHvB0kk95XMkq+dufwR6Pp73KP6vjEvzbdXyPbs/5mM1dgcGUhQPK rhlg/eVPO7PL5Z+ZVjIaRZU2YC0TQSSsgyESnMXRwidw6tNPKGUurQbRc2D9Qq9M JRp2JmYPabWLkUxvJGxhD6MKKscOOJw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE9DCCA9ygAwIBAgIRAOxODrarKieKZs87DWGanYIwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xOTA2MTIw ODEyNTFaFw0yNzA1MjEwODEyNTFaMHcxCzAJBgNVBAYTAkNOMTEwLwYDVQQKDChL aW5nbmV0IEluZm9ybWF0aW9uIFRlY2hub2xvZ3kgQ28uLCBMdGQuMRQwEgYDVQQL DAtLaW5nbmV0dGVjaDEfMB0GA1UEAwwWT0tDRVJUIFI0IE9WIFNTTCBDQSBHMjCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOcmEzMfF3hka1d27dSMcqko hhzMJRzT0Vgef5vvMcmgA5DBBTYvDhcCNZlK9Io1ReYsvp/Kd+ALrgCXWa2o76NJ pALpPTOcDHaYk6eKLCBWfKwlRU3M9XsquyLqHAdvmmOUUchRvKdAgCmsxSQLVq9i ScwaoNh+/tmMYHJysPmmJq4Ld/Xgneeb9m+yQAIx3vUa6v+AyqDQE8JJfkHyaBMG DLVJUim9J3oj/U5Ub40A9qziM9s7mjG8rMBNSVAXwB75A30TZKjovAXqZTppTW56 ZI4DKyOz4bKJ5az3LD/nZi9lfkIE/zY2trN4ovk69VHrkvqfLP6NR1GcBp/4f3UC AwEAAaOCAWwwggFoMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFIUyGP93 msmRgNgbkRe6FEACMWpCMB8GA1UdIwQYMBaAFFSZ3Zv/6KcOoxmdW75CV98w/I8y MA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw OAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwvZ3Nj YXNoYTIuY3JsMG4GCCsGAQUFBwEBBGIwYDAoBggrBgEFBQcwAYYcaHR0cDovL3N1 YmNhLm9jc3AtY2VydHVtLmNvbTA0BggrBgEFBQcwAoYoaHR0cDovL3JlcG9zaXRv cnkuY2VydHVtLnBsL2dzY2FzaGEyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAk BggrBgEFBQcCARYYaHR0cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEB CwUAA4IBAQBmeKFhY8giBe6Vq+hl2bw+5Okv5p1mdpKHnvKrZwCqpfAQpxdo1wnd PCri8C6weusrPZEQWVatamiie/HghzcYlEzMGh4dWb3J28uSWeXFL2yRW7qRgKtT 7JP6ZDB6hYcwCWMevaMxRPanP9yxV2a3Z75HarDemTBGhK7u4gvSpaKK16XAvYCM 5tArdy0jMF+AlrHPQwCikdozqoYhhlaXsjjEtTbYRpHUAmcQEzbrd+j3BTtkixgp LO8aSAPgwUTqmPufx6+h1dgjkoAH8ddAOZiYeoFTUKZUVtbAhOzVa+ejMFa5Az14 Sb9LjsnZUGkGzS64rlbE15mihoYGHWb3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9jCCA96gAwIBAgIQFPAkFSJhqpbMfp4uhCXglTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NjEzMDAwMDAwWhcNMjkwNjEyMjM1OTU5WjB3MQswCQYDVQQGEwJJTTEUMBIGA1UE CBMLSXNsZSBvZiBNYW4xEDAOBgNVBAcTB0RvdWdsYXMxGjAYBgNVBAoTEVRCUyBJ TlRFUk5FVCBMdGQuMSQwIgYDVQQDExtUQlMgWDUwOSBDQSBQZXJzb25hIDMgKFJT QSkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDjFjcmfhptTJKaBUKW lTWc0zRWUbPWd/h00y3XzpqTx8rf38AKSonIKAQ1ePC9qMzLZGJdJb245P5GiFmi ogjXWfieLTKq72Ohd7qfDvtvAVTo5HbNA3hE+0psrQKMCAqOphde1OszzdPZo0Tf fht0mo5lUDNnU3xkcnF/KXKWWrcqsCjcqOmw51hdDWTL+JUDXyLzbv07UhXlNn3e bB6xNXp1lMwWMiPekGI+yY6JApiWWc/j1k6IcOs08prmOkokLEZL+KA0xzexWSwV Nt2USLjt3zLOMn5YY0crhRTR8IZNQyaeyD+9PIc0KlNP5OL2TMQGC3SgqZFN6NkP feiHAgMBAAGjggFqMIIBZjAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNm yzAdBgNVHQ4EFgQUCvCYnPwjUIRazgoGYsd0mFlnapIwDgYDVR0PAQH/BAQDAgGG MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF BwMEMBcGA1UdIAQQMA4wDAYKKwYBBAHlNwIGATBQBgNVHR8ESTBHMEWgQ6BBhj9o dHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlv bkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRw Oi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQw JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcN AQEMBQADggIBADoiun7R++b1XOSHDCq+csIwDTfJJCT6J0DJFeWCKX8CjjL0MmaY A6a+PsJeShc8lbw30jN1Lm9wn4w4hOIM7yvs8enfzVJLKC9UbHp3BBJlkhERsOTw DtZ72kaZxwj2J3afHVh0UAlV5qpy411kw/3prw94QqQ4uxvkplWTQ2FG+FwUPe91 x+cwhumO3Dhmt3fpjbOQV2Sm6jo+6MmPi/idGKIOpvhGts0dByctb9BVG7uKEryP N+RefvbuDhuNhrofV0VIbQNtrWZPCM+H86TlCc0Jw88A1991VsCxJpBMUA1j5GPd IrG7QTrb7SyeiIjSbxl06ObnG5JBk/mTKvSA9OjgO5Ui4MDH2htXIj46gjR5ND5Z qC116+4CiHYG6EEhTnEuiF4z6/IGWw+rJnBDEZvDhY99A8If4bV5NzVfx2ndkgmj lqs/HGz148yN0qsO57cFR/JMAmX34IiCV/EWODhDgKwau0xje3yvcZuNj+AzETks wnn4UF4Ef830a0iK7cr38ygQw0Kh5SshoXxmsuYrk9eexGzFUGLY4xVmQBlTSt8a dJugRjRe3gZ6tbyC641AWOTPYIG494OHZJmMs6FSt+xAF1LFNjcDV3cgrwUMPewK GxtdtoTLdRJeRoG3zBKL716dKloBz1feGW8iuc5ubvZf43VCWqGv376e -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDijCCAxCgAwIBAgIQMgZCPebGLJaMjsGc924E4zAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwNjEz MDAwMDAwWhcNMjkwNjEyMjM1OTU5WjB3MQswCQYDVQQGEwJJTTEUMBIGA1UECBML SXNsZSBvZiBNYW4xEDAOBgNVBAcTB0RvdWdsYXMxGjAYBgNVBAoTEVRCUyBJTlRF Uk5FVCBMdGQuMSQwIgYDVQQDExtUQlMgWDUwOSBDQSBQZXJzb25hIDMgKEVDQykw WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARXciwprCDGn3G53tefvMM/a5x0CNr2 DPQZNSm4Bgzai5QJJDLiuja++u0zKQbFBhcnijYol0ayyvCHhyaP7Fygo4IBajCC AWYwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFLiY Sa4L6oKbCdmffuRRrvzzlvGrMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAG AQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAXBgNVHSAEEDAO MAwGCisGAQQB5TcCBgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2Vy dHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3Js MHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1 c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlo dHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2gAMGUCMQC4a4Ij DmxB0h75ms1HsgFDPvDcMsH5k6wY3edCfsrVGMzdl8ewF8HhcrOBsUaXiP8CMBBE WdKbwSAwtCHeW0B2LMNetdBVX/i3ExYWWCGHR6nrb4bkMiMGZgWXqvqr+WReRw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkDCCA3igAwIBAgIQCuSPIwEwZEGSWeHCmumNGDANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDYxOTAwMDAwMFoXDTI4 MTIwNjIzNTk1OVowZDErMCkGA1UEAxMiQXBwbGUgUHVibGljIFNlcnZlciBSU0Eg Q0EgMTIgLSBHMTETMBEGA1UEChMKQXBwbGUgSW5jLjETMBEGA1UECBMKQ2FsaWZv cm5pYTELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQC9vhI3XrifeRWYC+x6U5sPCaYAPncBLBBsyQdt7ztiyROEG6fEKZG1tToZMES3 jtgqV+7RcBV9xX2jVeU+EwAnHkIpwoDWcte0gLfALL3hkVcwXJoJaojVF8mMHlJt QYTr3FYkZ6FqALt/LFUxeis3/Zgtug7EoqBsZeF5g79lSZtZqcNLm+3NuvZUdAHB GIzD++wVlOhy9IxahD/Z7eIkpuJTedYVpLmnX/fHq92gYoNHezlNN8vdILlsPV4k IdrwTKso7II25Kha0/l3hx2xEBtUIQLMGxKF+fD9AjcYhSMqhTM5/2tyud4QJxIy 409Dj4OhNooHAxurBDHwV8ZlAgMBAAGjggElMIIBITAfBgNVHSMEGDAWgBSgEQoj PpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUHlwXkQVXAvx3XONwQ+xr/d3S2Gkw DgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAh BgNVHSAEGjAYMAwGCiqGSIb3Y2QFCwQwCAYGZ4EMAQICMBIGA1UdEwEB/wQIMAYB Af8CAQAwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsG AQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQAD ggEBAGa7XPTd+1lgnT/dDf2agLAIIXpbTn6XtEGMq9jovXbK076zHlQSWapd6Zd/ p/uWydwuTbd+cobkUTFZhKGMkY0e8gXgI2s09kQ0EfotFUOdQ7qf1U+UM7JIEZmD gsTn9vBLNwbtwH9t6cvYxH//VhWyL07pPkfTFBVqvAprGZ9MgraZD2S9qYu9usfS vuH4lr4b3NuZ7mh3zOs4aD3Omgx30DU8DV82LikGN4/MF+uDOGgHtPv0ozlvPrFc 8bsE+lTnjP199w5X+kPtpzrkjYPNrGxTg4nhugo6y+GPOCl00S+T/794oTq/HFlj 6IoOvOR7UaKo39qnYwA6Fs0F0to= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHjCCBAagAwIBAgIQTkGDlLJAp8yo52qunYSXkzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NjE5MDAwMDAwWhcNMzAxMjA0MjM1OTU5WjBkMSswKQYDVQQDEyJBcHBsZSBQdWJs aWMgQ2xpZW50IFJTQSBDQSAxMSAtIEcxMRMwEQYDVQQKEwpBcHBsZSBJbmMuMRMw EQYDVQQIEwpDYWxpZm9ybmlhMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBANXQleBp2ymgmzpKNQxChEbgw8KXA1YbskpjRfjnXb7d bgEKqqrmlsTk/Vat2lmr+wPGJto+w/uNkiXHXyy/MjoAxc+M4Ad39cQcEmdTyp4Q cyHkqqkNSHg6bhExrCi6gQM4881sWc0Pw7B+4ZMWw43/x+d3005vtMXy5pwoJDDf 3Dx39nVfwnPwt1QyTwpiu+aWNGJdiDAC9btsO9j7/SKsqb8PMCNPNpE38UibH5jI SkH4hJAwIhZxE9iA/+iGzvSgHCG5UBotniscZfZTVV4+AB0745hict1QqNZDWZkc VCosDohqfRbgvVPkCWI1am4rDvohKlSk0PmTU4dW1TkCAwEAAaOCAaUwggGhMB8G A1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBRf9paPjrWI HXPcIHt4Mdxftrc9GDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH AwIGCCsGAQUFBwMEMIGSBgNVHSAEgYowgYcwDQYLKoZIhvdjZAULBQEwDQYLKoZI hvdjZAULBQIwDQYLKoZIhvdjZAULBQMwDQYLKoZIhvdjZAULBQQwDQYLKoZIhvdj ZAULBQUwDQYLKoZIhvdjZAULBQYwDQYLKoZIhvdjZAULBQcwDQYLKoZIhvdjZAUL BQgwDQYLKoZIhvdjZAULBQkwEgYDVR0TAQH/BAgwBgEB/wIBADBQBgNVHR8ESTBH MEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2Vy dGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwNQYIKwYBBQUHAQEEKTAnMCUGCCsGAQUF BzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4IC AQBrLVtXy+yZ1ezqBAm5pzrTPwSJqjRz9/rIE7nE6gdWyS7hw4jtCjN50y8KnHyh sDbKTb1/4Q03PJX6Q4D3SSR4q6674hsb6bMtzufBULC+2Y5+R3WTj6oTxlinJpUt MKcTyNeQG3/1XuZJKq81GHrNvAb22O+QSZ4PKjThHCTZI3g1ZjvkOnBdQ/++3I0/ /IKtv1O00PkD1PXLcca7YPUMTnGl7NvMsS+v2SyFlQFgFPNk/7dSHsFbQ5aojaKS upqddkv79uRKrMDjB27Fj0KS4K96BNEncuyEGRfYvpjCKbjNaew6A/w9Udm+mV5P h+FMMRS7pJ+CDcZW1iJTZ/q4VVLV/h1J5JFjrw1myfLFMa+gwONvKXBMIAwKmhrs VTbGI+EvbGUig5YZtAXJrB8v9iQUX5qURHEZHKV7tIqRsMaUKTNXbIMFRdAmbkYO j3bBnrKBkZlyJ9CoCG9ms+F8dcgCWcANOUPwRCLZwlbPebxBID5CjMh5HPJQoQRl clZwB9XFiaMMDDXprhp9Pmekr5i7KySKmynTggYeubuMwqA2y9K+vu9pSOs1F/60 d0OZ8zzsUaeNQ9RZM8wOcpIr9ZK5vAyesbiQMY42ZHQyXGvBXSqUrzmUf1srCoR/ eEoQmCb6b7pQeYVdf0Z9zA7AkfbjnWEbF6Q1k2wlA0HIwA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFrDCCA5SgAwIBAgIQXfq7lXfPq2cfx93+0c8gWzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NjE5MDAwMDAwWhcNMzAxMjA0MjM1OTU5WjBkMSswKQYDVQQDEyJBcHBsZSBQdWJs aWMgU2VydmVyIFJTQSBDQSAxMSAtIEcxMRMwEQYDVQQKEwpBcHBsZSBJbmMuMRMw EQYDVQQIEwpDYWxpZm9ybmlhMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAPiPPrsGoduNR8nbfQ0MXTV/7CPf3ys1hKdt74O7ykg8 SV3Yd8a+SnXPeHPlNxlupRGtZOoHSCTUY0AxF1Z19i466OI/clzBzO/rLmd9WI6s zgG3tzCvnVIDwT+ChVp99lmHxkmSkoTiU+U5UO7QF8wOQR/OaShX26295YUwP52W uVnhKkzTLvAdMjvZv7OtbcKh6LQwnnOwVbiM5K1o9gelleEwvra8+HXQZGkdzO7/ pv+26ZRLQNlevVAMJMxgo8/zwP7vgTU+hPKVkLZQOFCWLGquaesFf8GGIVlIn6AF hscYhu47HJIcl51WtrbGoWvQ/IqkX87BFBxy3SXWOpUCAwEAAaOCATMwggEvMB8G A1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBRQArgTLBWD 0UHDEYqLQjsBI0OpVjAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMCEGA1UdIAQaMBgwDAYKKoZIhvdjZAULBDAIBgZngQwBAgIw EgYDVR0TAQH/BAgwBgEB/wIBADBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0 eS5jcmwwNQYIKwYBBQUHAQEEKTAnMCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51 c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAnd7qlXd+K82A2HSfIHt3P BzcS+q1OPkj+f/9Ft3nYg4NYlx2h2r8zax6l1A/osslr8g+B+MXCfclPmOhN69GK Pk/1YrergoBtI5iJKJBcDkUKZ++0aG0yNimNZuLfRn24nfVtjkI+hNdP36Cz0HAM FFuySnF2UQKljvUs8GJ5DwxefrNy3a6zNWyiWMx44fHfncWnQQ1lSvsfPVFvlqX3 vXJ79GmxZIsJWoFy5adUER2eYo7hXVlHjjD/DqrqYxwLROPh7TEbld10ashDDJ/5 6HClJNVME3S8A3FWyk1nvqwuLZnHxaBnvi2mhy8UeX8nA1CcvTB4gHr0wVP2Xbuc NkYUOZgB2TaYBlRfF7QGgYlxtLjq0Oqv5RRI6A3ZVDkYtmSxOrCc6Ymwwf3B1tdn vKj8dv82zfUGUy0sshcSU3Vb0pwE5mNt+9QT0S5fCix0dco2SanGDTgJTkR/yRFR cq0V6ip8wcr7pCwg8IwF16W0UzfyA3c1Tnkcc2rIYJ8UodBgRLgCUsaqk9KyehAm CiBSTYraMMSOZgVhXnWYmxVPBG9wCpt27xiM+VCmI1CqNOEcWXvFY8edfG4RbBhj 5dXwWbO9rOaD7aog62ItxjM3a8DuKgeP82IXvj5f2/ZVUGU/HzQsa8NjiPjZ26Ho 46TkVtBBCemE2Gq3DbkcFg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQcmYYdTrWySLFbJ3h84R4sDANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDYxOTAwMDAwMFoXDTI4 MTIwNjIzNTk1OVowZDErMCkGA1UEAxMiQXBwbGUgUHVibGljIFNlcnZlciBFQ0Mg Q0EgMTIgLSBHMTETMBEGA1UEChMKQXBwbGUgSW5jLjETMBEGA1UECBMKQ2FsaWZv cm5pYTELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASXeXEn 8c9E2Yz/wRm1h1nu0bXLeJE5jE1KoRg9EMpqvAp/dJXkt55PMshirJY11V2e8n6F Eob4GkhYnzFGbrAwo4IBJTCCASEwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Kl f9AwpLQwHQYDVR0OBBYEFF/jLoqUl97TXOG31LyYjjEpyZA6MA4GA1UdDwEB/wQE AwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIQYDVR0gBBowGDAM BgoqhkiG92NkBQsEMAgGBmeBDAECAjASBgNVHRMBAf8ECDAGAQH/AgEAMEMGA1Ud HwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmlj YXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0 cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQCj3G3o0UlY 2Mhej3oddvVnuieM19jahBV0OBTA4WPEqWyycEubm8+s9zWzALPqYdnQU3/DWCS0 PUlxsE16N7VV4C9kYkdDIfyZzWzPoEuuCN4s5oDUQ0UmXzJPvfuJX87HZxLiBtzk HQHowsXqhkFmfSIadhOW61Q/xDia/LWNPIkncB7Xs8+TTCMhf8oorfM4P9hqSLzb Pq4nJ+1kWaNEPCIPC3zczBl9joB8WDXB6fuWyadAJI0lVqB/jADhQYu/qJGo5tsQ +6qvg7X6ZGXQp4O6g+mLcQ2BKReqzZtQUIGpXCFYNHdi8A89c8QqPKeazcrBrqH9 z6X8AMunwFlY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDOTCCAr+gAwIBAgIRAJjBcnaqg2kI3NxbTvi9QXQwCgYIKoZIzj0EAwMwgYUx CzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNV BAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYDVQQD EyJDT01PRE8gRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDYxOTAw MDAwMFoXDTMwMTIwNDIzNTk1OVowZDErMCkGA1UEAxMiQXBwbGUgUHVibGljIFNl cnZlciBFQ0MgQ0EgMTEgLSBHMTETMBEGA1UEChMKQXBwbGUgSW5jLjETMBEGA1UE CBMKQ2FsaWZvcm5pYTELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMB BwNCAAQMOys00wbS//d8upMzBGqcAE0yvE7lx9Xi3Jy46buB1jfqZM77BniCdgV7 BebQfCtf2RfbSHjOfnCpkmuw2dhNo4IBLjCCASowHwYDVR0jBBgwFoAUdXGnGUgZ vJ2d6kFH35TESHeZ03kwHQYDVR0OBBYEFIW1lNhxgs7OVoCzrzWYq3ZLbawpMA4G A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIQYD VR0gBBowGDAMBgoqhkiG92NkBQsEMAgGBmeBDAECAjASBgNVHRMBAf8ECDAGAQH/ AgEAMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NP TU9ET0VDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMDQGCCsGAQUFBwEBBCgw JjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMAoGCCqGSM49 BAMDA2gAMGUCMD4Ri/A8513J9YSUzSCjyNtqqfvZbOqOAOevCqaiLWFiQ73penOt d/5zmgZTyJbItgIxALCSbL7oEpk1DzLHiJ72sDnHiQWdeRSCI1H6gycotKQL3x8Q pNEd45fb6rj1ghL0GA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFUTCCBDmgAwIBAgIQdR4/VknnTLv2nQAmtnyqjDANBgkqhkiG9w0BAQwFADBX MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTE5MDYx OTAwMDAwMFoXDTI4MDEyODEyMDAwMFowTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBS b290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCVB+hzymb57BTK ezz3DQjxtEULLIK0SMbrWzyug7hBkjMUpG9/6SrMxrCIa8W2idHGsv8UzlEUIexK 3RtaxtaH7k06FQbtZGYLkoDKRN5zlE7zp4l/T3hjCMgSUG1CZi9NuXkoTVIaihqA txmBDn7EirxkTCEcQ2jXPTyKxbJm1ZCatzEGxb7ibTIGph75ueuqo7i/voJjUNDw GInf5A959eqiHyrScC5757yTu21T4kh8jBAHOP9msndhfuDqjDyqtKT285VKEgdt /Yyyic/QoGF3yFh0sNQjOvddOsqi250J3l1ELZDxgc1Xkvp+vFAEYzTfa5MYvms2 sjnkrCQ2t/DvthwTV5O23rL44oW3c6K4NapF8uCdNqFvVIrxclZuLojFUUJEFZTu o8U4lptOTloLR/MGNkl3MLxxN+Wm7CEIdfzmYRY/d9XZkZeECmzUAk10wBTt/Tn7 g/JeFKEEsAvp/u6P4W4LsgizYWYJarEGOmWWWcDwNf3J2iiNGhGHcIEKqJp1HZ46 hgUAntuA1iX53AWeJ1lMdjlb6vmlodiDD9H/3zAR+YXPM0j1ym1kFCx6WE/TSwhJ xZVkGmMOeT31s4zKWK2cQkV5bg6HGVxUsWW2v4yb3BPpDW+4LtxnbsmLEbWEFIoA GXCDeZGXkdQaJ783HjIH2BRjPChMrwIDAQABo4IBIjCCAR4wDgYDVR0PAQH/BAQD AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFK5sBaOTE+Ki5+LXHNbH8H/I Z1OgMB8GA1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMD0GCCsGAQUFBwEB BDEwLzAtBggrBgEFBQcwAYYhaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9v dHIxMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20v cm9vdC5jcmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBz Oi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBDAUA A4IBAQDHrE3fEsZgYRw59I03e5wt03B45il4hAHmquLc33pbkGZn6r3GgoKVzvwC aBgtl6Jp93gZD8G5UjAFLj840jWDhOP7KSX6Q7rGjOsWNFFDJJLDUKQeJpB1PTRu HqVI15zxiCl/VCP7mbTW7X/pILaFOPO+T0Qj+TUOU37WOjk6wdeyyOFiDhKSwH2Y VE4YlAo0R10Jo3uNnSCFBgPw7gy1xt1+ajCbnzZYpQNXFy/0Lp9h3JOClE7TGvli FUazCjxvhHm5YWqulA51wFT2K9LRiiEWw3UJAgTTmxASitVHHLb3erkETk6SCwGv OG1eD0qLwuSeARZmhw3xFOCvMHeQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFAzCCA+ugAwIBAgIRAMt5UT/fWkG366O1ASxmV2IwDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0xOTA2MTkwMDAwMDBaFw0y ODEyMDYyMzU5NTlaMGQxKzApBgNVBAMTIkFwcGxlIFB1YmxpYyBDbGllbnQgUlNB IENBIDEyIC0gRzExEzARBgNVBAoTCkFwcGxlIEluYy4xEzARBgNVBAgTCkNhbGlm b3JuaWExCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAm39I57iRs4aa5rTkT8v25aMpY3wlYJoEQ+S2f/FWHuTVAGD3cZVQinVLEPno c8b3P+hfrFzx0jDl6HCy7Qa0a6epruXfORXQD0/Q2Y0MdGYaIwJqN2ClPsa9qICt J6RKFFjnS9iMzDoq80fJ0sCnY8HFBlTJ1+BJCsL2FH7kqIDVPuRGodcE8qv/eIR+ USwHEY0ih6vWWHs1/+wXF35wdwDa/mDosthxr9y3nK/28BnHL+B/KHVk8dRrim1c 5ioO/g8st6y9fz3Hgep+sEpMh51NkUFXwoVlsu3aZOlj90MvynPq+XZD+bfuc6SJ wBH8Rk1MxQBl5aPMrkHInUP12wIDAQABo4IBlzCCAZMwHwYDVR0jBBgwFoAUoBEK Iz6W8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFMoG8JISPXsAWukoR6glG/DQgELM MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw gZIGA1UdIASBijCBhzANBgsqhkiG92NkBQsFATANBgsqhkiG92NkBQsFAjANBgsq hkiG92NkBQsFAzANBgsqhkiG92NkBQsFBDANBgsqhkiG92NkBQsFBTANBgsqhkiG 92NkBQsFBjANBgsqhkiG92NkBQsFBzANBgsqhkiG92NkBQsFCDANBgsqhkiG92Nk BQsFCTASBgNVHRMBAf8ECDAGAQH/AgEAMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6 Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQG CCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2Eu Y29tMA0GCSqGSIb3DQEBCwUAA4IBAQBVuyW5n/2AUXteIehTcfA/AENKMJwZpvfi tTwIOPin2iyywoxY/eulT7lEp8eJo3pqsLN8daxqOjdC+c/swMKN6/dcPVKtUfgh t3xgKzfuzOwlQ3AVJAtCta5shCo5Sg4zxKdguQ5oaUvy6JgNrQzLAo4+p03YfNpJ dD7ienJQ1gfMP1gXVimRNAA7QhRqZhCwLVdisu3e9A7kRYafrjK4P5/t/GzMu1Ym EoMDgZzj1yhmewNvqOqformfj9+Ly+Tw+KmbWCy/ty6Z6bDwdxYcoGwgCC5vv10H nwusiqf7tIbbvSrwkPldhZZ8xEDfILwOLUHxdznoK0mZe0lC+arK -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpzCCAo+gAwIBAgIQdR4/U+MYWTPpXwjs7q0ClzANBgkqhkiG9w0BAQwFADBX MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTE5MDYx OTAwMDAwMFoXDTI4MDEyODEyMDAwMFowUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBF Q0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpH bG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8L ttV7HpI6SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWd TaRvQZU4f8kehOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo4IBIjCCAR4wDgYDVR0P AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFD3mKUib6gfKIURK Jt5u3tKD0J9ZMB8GA1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMD0GCCsG AQUFBwEBBDEwLzAtBggrBgEFBQcwAYYhaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5j b20vcm9vdHIxMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2ln bi5jb20vcm9vdC5jcmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEW Jmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3 DQEBDAUAA4IBAQBQ11FVSLT8GKzvaFvpSX0w+HxmfvrzTyL4O3FkaxnrNVtzxu/M VkQBDYlswOnpMjaphFtnWBvNWrPRA60hNYGyGuNYe5dGDoky/9mPlnWXCNydRQJ3 7Nph4umG4yvqrxhnrsjW6NKca9ccoAw0rJEUDd1cYSakNgtPSf+tD/9bkN7E5fsu QWUkqgT+sB7Mlx1rxBULK6rPidx2fbgKwTzNXfTTGc8JuEX+YN3jG2dkMhaOdk7y CsAqHmzJ/BIXWwWrGgLozflb7j9n8CSOqwO3ISlr5Ztjqx2YJ4LWb25rHp/pATLl iBujmo+JS32LF0qcFLpp2+dCHc1T9qcvjmZy -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFHjCCBAagAwIBAgIRAIZmsCrBy1RAAAAAAFHTWJwwDQYJKoZIhvcNAQELBQAw gbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkwNwYDVQQL EzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVu dHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xOTA2MTkxNjUy MDhaFw0yNjExMTkxNzIyMDhaMIGxMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRW50 cnVzdCwgSW5jLjE5MDcGA1UECxMwd3d3LmVudHJ1c3QubmV0L3JwYSBpcyBpbmNv cnBvcmF0ZWQgYnkgcmVmZXJlbmNlMR8wHQYDVQQLExYoYykgMjAwOSBFbnRydXN0 LCBJbmMuMS4wLAYDVQQDEyVFbnRydXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gTDFFMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtlsEVHfdDiRm 3Cqh24DMXcdf/VIWWNpflAapuLa5YwxHIILsx5VOi7h3Umo9tYep1uHMdOWmyMDU Vk+NLtYIPgxMQz7wQZNeRu8559llKgx2UCe9Ww0zMwfg96KpnOERM61m/NIseqqj cxa+k4V1D9c3jPojt2T440xu7bMFveI223zedkTagnJ2tm7/lKHQhvcQzUpai7B1 jGZSgE5ITEmDpkDXd4ETTV5yfkhGIqoP4j5llDjhcnH+SnEJujV/VYk9gdW4KAEQ dzZaEIXSvWCEK0lhlAzeTEBqKsR5YIQkgjJpSphL4lYQugNFUSDTz9qOVBtFtnq6 l5pa2MbRXwIDAQABo4IBLjCCASowDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUF BwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5uZXQwMwYD VR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbnRydXN0Lm5ldC9yb290Y2ExLmNy bDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL3d3dy5l bnRydXN0Lm5ldC9ycGEwHQYDVR0OBBYEFFtBirLEQ8G9v8hUQVWd4Jat/7mhMB8G A1UdIwQYMBaAFGiQ5GekplOAx4ZmpPH3S0P7hL1tMA0GCSqGSIb3DQEBCwUAA4IB AQAPUNBX97sqIXZl/zLu53iv7a0HK7prvD0cVaZM0yRfVptvARgjIZZzTtv32v6X wSr4fDeRmpLaTWtipBGSqh3fNkTSVT8GGBq6+h1lrPEYv6jnStDf7VLQxVliKt2w h34JjgRUx9rdia30tk/EpPavkxxPks8vjoLN3f4dbkIY/sfljyZbseqVLx9kl/we OvqL6jZgaQOapFQLZJze7VwLiPVuUnW8ddK3JIE1a5YCZs0irIW5+96ttznIgPK2 aUOmHQp/zasi7SFl49HrKGKWtZuyDB9U56e01H6PDTpSSSTPyLsSVg3JALHBPDzS bBraAU3wuAyc3BQ4OIOmwwnT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFjCCA/6gAwIBAgIQCH4Y+4+qkn7odgoNiYL1EjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA2MjAxMjIxMzVaFw0yOTA2MjAxMjIxMzVaMFsxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xGjAYBgNVBAMTEVNlY3VyZSBTaXRlIENBIEcyMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAx7s903fR6SgpA08UdhKEUIZHa2Ig7KPNkTtwMS1+08YS 5QSEDM4DQxy48jP8dZkyyU9J/0WCm8Nlv5ga7HOAxhdJcv+CPP4oadx8EbdrmjAH rGOv64oHvt7Ina7uzLd3krqxd0doeuxRpTHvFAyjaUhxjSfZx0wh1f6W7prPm7V5 0VcTudj4rI+xtHXUcFAuFz4bcapTcru5aaZ1v6F2usMCMVM+xJxEZcsUM4uTxdIf W5FUTI0dbP8NyZkr/WVzL59aGwBE4ZU0JKBlgEmtkFpLPR7JCzYunafu7nMk5YY2 6WDOmezpWDjzDxJ8xakizykWYT5gdJYE3ULlUe31WQIDAQABo4IBzjCCAcowHQYD VR0OBBYEFMQRfohAhsJBv2XzGuG0U0Cjq+x9MB8GA1UdIwQYMBaAFAPeUDVW0Uy7 ZvCj4hsbw5eyPdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAxBggrBgEFBQcBAQQlMCMwIQYI KwYBBQUHMAGGFWh0dHA6Ly9vY3NwLmRjb2NzcC5jbjBEBgNVHR8EPTA7MDmgN6A1 hjNodHRwOi8vY3JsLmRpZ2ljZXJ0LWNuLmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD QS5jcmwwgc4GA1UdIASBxjCBwzCBwAYEVR0gADCBtzAoBggrBgEFBQcCARYcaHR0 cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBigYIKwYBBQUHAgIwfgx8QW55IHVz ZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2Yg dGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93 d3cuZGlnaWNlcnQuY29tL3JwYS11YTANBgkqhkiG9w0BAQsFAAOCAQEAE+8lW5Yw IuiRsHn4gYRRVbLmIypWwYH74lIXnQiALeUsUkWfW7KA0ARF1el3YaTAg8/r6zyX eZTdlhndxKOKvO5N+rnHWJB6a3fJURn6e0I+rDzKV1Zacv2Vx/ZHLZmza/bp4Azi BrDOiPlW/Ktj6ALQzAgq70Oytk9htLupBWPuplJDdyhGqb9RfQvWc1Fa1HwXdBQi oJPibfMaYkHMY3pTbOv2rzMKEoZwHDHqyC73RI9JgqqiXHw0rIL8A1uL3IrymXEr mycTqbSozQwiiEfb+cxzY82YaNzaLpJyIst0T2QmdDDngmyd2LEmm4NKeXRrcFRh XDDFfpIn93B7JA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGjCCBAKgAwIBAgIQB9V/HxVbveTPhDeOF/eblDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA2MjAxMjIxNTZaFw0yOTA2MjAxMjIxNTZaMF8xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xHjAcBgNVBAMTFVNlY3VyZSBTaXRlIFBybyBDQSBHMjCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAJ/5VnZVJh4MqHMX9J60c7O4Gm16uxwK8OKj+o0p hxSIgI++7rY1y6DOs3TCS7ZQMtsNHaHFcwywzhj/2ElWkW7rS9DTmI7TiyFdhejT WF8VIihNem1sv3faxeRbGpV7KDU+yjJ8FmYSD/6nPF5Juq0ei25yhzxNEsNS0/h5 BqwZGskmMSTworFkr6k8eSNvKXUw1mdpxcUAfIMn4YgyG+HKmgGJPWk4Y0Vchjv3 RFvzsdktrNJOl2l86LQC/bhmL0petbpnDtSJADfb8xp0UThqMC1UhyJn7seERANw 2Ss5c/wYrsr/xllMLnJLFQnQaz50r+Vie6S8gduxI4KusbsCAwEAAaOCAc4wggHK MB0GA1UdDgQWBBRFQeOTVHC46aW3lrwmsVh1Qpc+8zAfBgNVHSMEGDAWgBQD3lA1 VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wMQYIKwYBBQUHAQEEJTAj MCEGCCsGAQUFBzABhhVodHRwOi8vb2NzcC5kY29jc3AuY24wRAYDVR0fBD0wOzA5 oDegNYYzaHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vRGlnaUNlcnRHbG9iYWxS b290Q0EuY3JsMIHOBgNVHSAEgcYwgcMwgcAGBFUdIAAwgbcwKAYIKwYBBQUHAgEW HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFu eSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNl IG9mIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBz Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwDQYJKoZIhvcNAQELBQADggEBAN53 jp3wazRfQxcoek8gVcZveTm4irJBTfYjwtGwg+vXc4O1KDpokoEWW1Kr/AzwdR7J uAu0mHyK44+cla8frJld8TMPnMcpo5b+rWdoWgoYaxo50TXKU2o4CvqQaKQENb2P S9XrToukrGvQWMq+syA5VBD3QHKkeeLTxC9jdrWHD8dsz/sibc/UbdDDeEYQrP3j CPOtH+PWhaaNYzpWDFMyA6r+R6uaI2+K8P/9r4Z7x38zsv8NRA0kSEx1tFMTszOC uad+dOaQLuHlK9yVNmEBc8osrqIF+nz9axXsS2VLfTac6SgkHFyHCVaSnBpdFfdN aR0B7R5Snw4QzFKtU4c= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEujCCA6KgAwIBAgIQBahUCVpSbEJ4x1tHRh4J0zANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDYyMDEyMjE1OVoXDTI5MDYyMDEyMjE1OVowbzEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEuMCwGA1UEAxMlU2VjdXJlIFNpdGUgRXh0ZW5kZWQgVmFs aWRhdGlvbiBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALfi 6MdegU/YaWxmXJ9mYcvY5hbiqRZ221Nq+paGg9wQLnVzw7tpbisbCKQ5s4tnhdh2 8JlqrgqB9gneUqmITQI2mzeFyH02cjmKDjBxj8Misg0ld0GVV8cNVGPKaJ2/APCm HqSfbTwybDWmf3Zq65ZYGTJVHbBeu7X8foqA19D2Jm9CO0CstO8fz92pmebbtRxH 8L/5wLvHIra+0xXJ+znyT2Tom2hNsYv4PkZYTYAbwx1hOZnaFXPP48X02zE3oVJA H+Q458SPmzH62ybCoh86knzcTJlI/62ZRWfkFe4W+Vp5BunaqZC65RuRDgTViScH IDqFwVgscAiPF/DA2AUCAwEAAaOCAVMwggFPMB0GA1UdDgQWBBSpO7p6WJVINf7W B50riyX+auHboDAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAOBgNV HQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1Ud EwEB/wQFMAMBAf8wMQYIKwYBBQUHAQEEJTAjMCEGCCsGAQUFBzABhhVodHRwOi8v b2NzcC5kY29jc3AuY24wTQYDVR0fBEYwRDBCoECgPoY8aHR0cDovL2NybC5kaWdp Y2VydC1jbi5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMEsG A1UdIAREMEIwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 LmRpZ2ljZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwDQYJKoZIhvcNAQELBQADggEBAHBP Iu2CItLIdTCbcrRNcu/cMGQL0aSomsFpDuf7urBxdi0QNwwaYRA4X4gLOP/3+W3D ERoh6sGbizx+4Cdfxb2jtvS87eNOG8paP2bFfzek6W9iUcNQLU2m0GQw0XhMobKC zLRTQdH1upW5iLlaZVPGqqQwWXeruHBJBZjGpk/7W8S7t3P9CNMUM+lxwIxOhUtX 5ZQOEYcLQge7ZKG0jkv06+XMhog2BlHbg1ntaSTOGkf4iYoLG7yk9i/Jxl9I1487 3ZmXwZOEotZt0Fbrx5/XQOo20H0dHYhoA+3MdadzBB5d+5oce5cMSz+aQX+S/J6i F4Uy4hvWLWGuTMm9sUs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvjCCA6agAwIBAgIQB3BLtxcv3UeoIkLdQ1DlYTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDYyMDEyMjIwM1oXDTI5MDYyMDEyMjIwM1owczEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEyMDAGA1UEAxMpU2VjdXJlIFNpdGUgUHJvIEV4dGVuZGVk IFZhbGlkYXRpb24gQ0EgRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCjVtaFuJxO2puJ4igP/DfH2KIMWR1FjTz5JBxX19aq078bo6cry5oRDgkhCDor QXoXMKs2v7es+1IkpmklsfK+8sP/LDXa+5UCuMthgjtze3gQ3+jP3OxtGyby9ETN q3vBKkyzDZuc6LW0KGI4SuPAmPfDT8xAz3pEeK/d+uAusgB0yuga4Xa6MjfERsnY 8tSjNhYUbfsyTwmZrWG6l6y2w2+sts7/2kuqUAJ36oMPU9tMnxKGiik7GMiLOLKI KelNOfrBr5fNkp0F/AdeYYGMGXI8PZ2vwrjGsKevEVDFy7j+7d9aG4M7gyIekAb8 dosAZH7q/pfwWB1MWMBpFDpbAgMBAAGjggFTMIIBTzAdBgNVHQ4EFgQUsZUUqNW6 dIhxzZaLFzWI3/DBXfMwHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8Mw DgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAP BgNVHRMBAf8EBTADAQH/MDEGCCsGAQUFBwEBBCUwIzAhBggrBgEFBQcwAYYVaHR0 cDovL29jc3AuZGNvY3NwLmNuME0GA1UdHwRGMEQwQqBAoD6GPGh0dHA6Ly9jcmwu ZGlnaWNlcnQtY24uY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNy bDBLBgNVHSAERDBCMDcGCWCGSAGG/WwCATAqMCgGCCsGAQUFBwIBFhxodHRwczov L3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMA0GCSqGSIb3DQEBCwUAA4IB AQB+euHcvpJFk5LXYpVHr2c4aKwPUTCoQZadA9BZ0uELT41zfTGKoLBmf1tLeNlF Etyhp9B+l/NoIhJ9ALfaniGjw+V9N76ix+i74esrIjTuMTqCuWQDvl18IUHWC/dK 5yv2EEjSYgySdprzb87Jm9ePLGq22VvHo6Hc33Mzedsahmuh0/wjjKkaXpn6gO3N TrixcDWBbMKE3+i8+QWRC95AIDkg5sW1vnof0d8io6TXezkx5L0DY3571VJ+WUbu 267V8j0szr5evh0AtvoaOML8nRY018gA2CTaX19ppC9RtAeacoh4Ad3Gh8B57+AH j30OcGp0TZ8qrRjnMGegV5Sb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID2jCCAsKgAwIBAgIQDPXy0UPwx4Kzm1dhOBV4PjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA2MjAxMjI0NDJaFw0yOTA2MjAxMjI0NDJaMGMxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIjAgBgNVBAMTGVNlY3VyZSBTaXRlIFBybyBFQ0MgQ0EgRzIwWTATBgcqhkjO PQIBBggqhkjOPQMBBwNCAAQ5oekkW5+KzW4+SaPO1J6FjKyGB9Y6x0xa0yq+KqiG iMg6WjuCtnhNzzbbOluDZfv/7PBF0Z4Py7nelDgJmjYco4IBVTCCAVEwHQYDVR0O BBYEFIbdzFj/9thyV3eQ7FDvwh5yBIq1MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj 4hsbw5eyPdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAxBggrBgEFBQcBAQQlMCMwIQYIKwYB BQUHMAGGFWh0dHA6Ly9vY3NwLmRjb2NzcC5jbjBEBgNVHR8EPTA7MDmgN6A1hjNo dHRwOi8vY3JsLmRpZ2ljZXJ0LWNuLmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5j cmwwVgYDVR0gBE8wTTA3BglghkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6 Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgEwCAYGZ4EMAQICMA0GCSqG SIb3DQEBCwUAA4IBAQBWG8UTMnwHSYmqhr4W/r4roBSZzoVQT0yk/2+FKOD6fXHp Q7c6BM8ndOby2bgU1MwJzZNBpD0s9frxOXhTp/EsqPYUeRvH9xwg4nu/mPFIBbRK bsRtJXOWuMalmXBbZuJNsCXFiT33Io6JdwijJi7c08lh3Qj3HqlIIdM9YsWnqJP2 PPVrNPUtiQvRcN94SKRd8r4s+12CHL49wVoXgHhvrgAoFVo0dJ3oeIMvR9y3h9L4 4nUVRV7TbD2BDiTfytsWFzD/MaDXbU32pbkMsHXXxeJ/Khte74idRDUSEY96Abjm T27g0531T6FxZu4BZN4xLMR2rCeaUwDvp1EuuGDE -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgIQDhLlFAPolZxuQjDi7Zw+EjANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDYyMDEyMjQ0N1oXDTI5MDYyMDEyMjQ0N1owdzEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTE2MDQGA1UEAxMtU2VjdXJlIFNpdGUgUHJvIEV4dGVuZGVk IFZhbGlkYXRpb24gRUNDIENBIEcyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE tZDt0Z7XYoJHWefhTBA7+bBk/xPnwsKMvVS3p+9U9c2foMBgeGufiNVeIQRigRXQ m4jQ6fsIN69f71A7DaMt2qOCAVMwggFPMB0GA1UdDgQWBBRdyFqr4GMPcCpf+fTn CM2170BZrTAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAOBgNVHQ8B Af8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB /wQFMAMBAf8wMQYIKwYBBQUHAQEEJTAjMCEGCCsGAQUFBzABhhVodHRwOi8vb2Nz cC5kY29jc3AuY24wTQYDVR0fBEYwRDBCoECgPoY8aHR0cDovL2NybC5kaWdpY2Vy dC1jbi5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMEsGA1Ud IAREMEIwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRp Z2ljZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwDQYJKoZIhvcNAQELBQADggEBABlLd+O/ ruAPDH+oLLxi3xpo/KDDTmSLi4XBNr0F3zsBfP3a5M6E+5Svu9COM7GYYak2qQnt Aiml/ES74IFNrX6cPSZ6GARq0gETTx+6E468hyLWPZcpG64K+lBm0gH4oMmNTEgf v5aZJcAfoocJn+4bvMsLD9irIm5wJkT1VJ1CKGq0C1sJV0vf1sLuQHC40X+GcIKr Y/4LtAAIL4k/tHQ+EM1DZVx9soPeFptq3FR/i8/50dnbDV2a/8kyljLM+zE8vVQh u4ODf/FenpoY2rd4JSDD4C2iHx3kS3UanC0CBP+/Amg3SpY7AmSur714lgxucINf wbRNt6I80i/gN+Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGjCCBAKgAwIBAgIQC1D+aUyDyVziJBXGCVz+QDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA2MjAxMjI3MzRaFw0yOTA2MjAxMjI3MzRaMF8xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xHjAcBgNVBAMTFURpZ2lDZXJ0IENOIFJTQSBDQSBHMTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBALv4mF6rORUUXZuwg/FR9YFOM5tZj3RE5JTMFWrD darbvnxdgu5BHqmPyt/Q7xNS7wOyHRJ4eRpYh0hJPRbtVQI/0VggjVpXLdNhxpVd /RhQ44rej5/YVSUkgSPagM5zppdCo6lSBIa3pznzXTVsHgE6umt6RzaxCQs0RrU1 StqME9YlRHO2cY0skyA5eYYbxrlr5xJZ4m1j89r3OyHYM0Mc4y0bio7gUhWPZl17 BvDuGbk9DXDxowd+5vnpKpN051Ltm84N6BECzeE/vbHOLGVU6cY01V750zDJ7STp dNz8FrV0CMP6K9rfBGRVYYEy6+rMSOvLthP+RqId3b/IbnkCAwEAAaOCAc4wggHK MB0GA1UdDgQWBBTvRQt4FZGlttFzpJJvY1pZ018+nTAfBgNVHSMEGDAWgBQD3lA1 VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wMQYIKwYBBQUHAQEEJTAj MCEGCCsGAQUFBzABhhVodHRwOi8vb2NzcC5kY29jc3AuY24wRAYDVR0fBD0wOzA5 oDegNYYzaHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vRGlnaUNlcnRHbG9iYWxS b290Q0EuY3JsMIHOBgNVHSAEgcYwgcMwgcAGBFUdIAAwgbcwKAYIKwYBBQUHAgEW HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFu eSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNl IG9mIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBz Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwDQYJKoZIhvcNAQELBQADggEBAL9c 8lmaFkBmO0ch6w5mi1RKS7c7U3pq3wWOXzUFKKJZCnyJYHcMUIyNCDg71clCFz4F t/yYLoXkzqNULAaEUtZ5ikf4I8hJHv60kg25GLCsfm2O1isbE0Wxpeb4qf7OGPKK MLCmmcdbZkuO+Ax38jo8/BO4TnVoeb+bYKgTuvev6wGCTezIDNGB5+/pD2NXwpkq cgX4ofIK4CdKlD1Hi5nwJbKYOLRpNrXp83n5oacxlezxp4ikt64EhDsG1mWaQD0t qCcBpGHbb8GSyBs2KohCp/lcysTVLZtUZkZGtIBd+Nli3jVPpuZjlGi51P30TReJ rgH4+ePTzmDxnYSkUhI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIErTCCA5WgAwIBAgIQB+NyoS4T59KdlHEzrr+dwjANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDYyMDEyMjc0NFoXDTI5MDYyMDEyMjc0NFowYjEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgQ04gUlNBIEVWIENBIEcx MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzujxiw/ym9or9BoGS7wW AnweJdMvuOqWTZD9oVyefbvxRZgpdMbCLQFzdk9PxjAFxq5b4FT5o6Rt3hHER/5r 1ibLoeE8t2NX8tExtDBgX/FbevvU6swM/ixQbKOopjHcDxGV0pWJF93GAOr4z+1y p4D2D8U0hXX9Ajxi8qEWfLqoFUm+Xm8u9amLtD4PCgbHbLzg5OGhxjacFLD02Ibn erL6PQFnweQmsvF9e9KSaqV9xv6A15mW5ZXi+PkBJQBCWfYJCnpGIy26sVj1DhIN MP+PjrpgsxHKscZj+t5pEP5zCPCylxfXiih2oBMAunF5lnfPec1SK8s/lTrTti+o PwIDAQABo4IBUzCCAU8wHQYDVR0OBBYEFI+fSb/ovSTmoiXbaQb7d6CINsyGMB8G A1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9jZCvDMA4GA1UdDwEB/wQEAwIBhjAd BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAx BggrBgEFBQcBAQQlMCMwIQYIKwYBBQUHMAGGFWh0dHA6Ly9vY3NwLmRjb2NzcC5j bjBNBgNVHR8ERjBEMEKgQKA+hjxodHRwOi8vY3JsLmRpZ2ljZXJ0LWNuLmNvbS9E aWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwSwYDVR0gBEQwQjA3Bglg hkgBhv1sAgEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t L0NQUzAHBgVngQwBATANBgkqhkiG9w0BAQsFAAOCAQEAD9Wk8/gLXvgo//h0LXrX Qn8suHSyXJDeHfrqorbDInqaTOp4A7W29MwCatA8ETSXXE8z0rcFJOeRMe2i013W lMvYJVks61giDWx2Z//4rlQusygv7ZH7JbidLdCrKNW3YUQDqDxSOs+43i6MtkH/ NDK9jVr73UbHO8BjuDbjFYZ0eJeGVNfCedOaJhfWmF5wpBuY3983BPZFvl7TKPRe bW6H50KQ1be+jONHnf21mHtZGdBglgxonb1opxABBj9ynW0AQLSEpB/ss5XXkvid xfucc1sLRCb8TiUpUIA5qvDz2HROPOScfPqDKcO4+PGNI+Z7n2dGtsLsAH0MEUIg ZQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGjCCBAKgAwIBAgIQCgRw0Ja8ihLIkKbfgm7sSzANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA2MjAxMjI3NThaFw0yOTA2MjAxMjI3NThaMF8xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xHjAcBgNVBAMTFUdlb1RydXN0IENOIFJTQSBDQSBHMTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBALFJ+j1KeZVG4jzgQob23lQ8PJUNhY31ufZihuUx hYc6HSU4Lw0fxfA43a9DpJl74M3E6F1ZRBOfJ+dWnaiyYD0PxRIQd4wJisti4Uad vz61IYY/oQ/Elxk/X7GFDquYuxCSyBdHtTVMXCxFSvQ2C/7jWZFDfGGKKNoQSiJy wDe8iiHbUOakLMmXmOTZyWJnFdR/TH5YNTiMKCNUPHAleG4IigGxDyL/gbwrdDNi bDA4lUNhD0xNvPjQ8BNKqm5HWDvirUuHdC+4hpi0GJO34O3iiRV16YmWTuVFNboU LDZ0+PQtctJnatpuZKPGyKX6jCpPvzzPw/EhNDlpEdrYHZMCAwEAAaOCAc4wggHK MB0GA1UdDgQWBBSRn14xFa4Qn61gwffBzKpINC8MJjAfBgNVHSMEGDAWgBQD3lA1 VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wMQYIKwYBBQUHAQEEJTAj MCEGCCsGAQUFBzABhhVodHRwOi8vb2NzcC5kY29jc3AuY24wRAYDVR0fBD0wOzA5 oDegNYYzaHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vRGlnaUNlcnRHbG9iYWxS b290Q0EuY3JsMIHOBgNVHSAEgcYwgcMwgcAGBFUdIAAwgbcwKAYIKwYBBQUHAgEW HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFu eSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNl IG9mIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBz Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwDQYJKoZIhvcNAQELBQADggEBABfg eXrxIrtlixBv+KMDeqKxtNJbZiLDzJBkGCd4HI63X5eS6BElJBn6mI9eYVrr7qOL Tp7WiO02Sf1Yrpaz/ePSjZ684o89UAGpxOfbgVSMvo/a07n/220jUWLxzaJhQNLu lACXwwWsxYf8twP8glkoIHnUUNTlhsyyl1ZzvVC4bDpI4hC6QkJGync1MNqYSMj8 tZbhQNw3HdSmcTO0Nc/J/pK2VZc6fFbKBgspmzdHc6jMKG2t4lisXEysS3wPcg0a Nfr1Odl5+myh3MnMK08f6pTXvduLz+QZiIh8IYL+Z6QWgTZ9e2jnV8juumX1I8Ge 7cZdtNnTCB8hFfwGLUA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIQB57DjKLa0ApYKfjg++qjvjANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDYyMDEyMjgwMloXDTI5MDYyMDEyMjgwMlowXzEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEeMBwGA1UEAxMVR2VvVHJ1c3QgRVYgQ04gUlNBIEcxMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx3SoM+KgtMsQUZpTYGVvR0WM l2YNIQeixGsoss05Yoa0b31gFfQHoNeccyIc4t9iw2VcXQizlwOOs/jwyG2X5UJN TxQAQiAKWLMzE8kAeEcnhyz5BAl7aMwnyHpS7iMQ1FbischX9CodNVM6UoBOSeRl mw7CfAUK0v+ggG+pQaClUYhzS4dvKhjQqChYtG8VW6ebEIEOJV2Qk2p90wFuZf/e DKEyR7vNrlq8ft/NZm2wlsmKHG/4cFN/O92VwpSPhoAZCIDe+VbT39QJoq3xK3+K NUnz8FrxWB5/Tko2YMyOKfhgfCJ7aqgqq/Tl7Xqktrk69UUQ/j/iodgupKDQ4wID AQABo4IBUzCCAU8wHQYDVR0OBBYEFO/FYo2VG1pKphtQhAgaWDjzaKFgMB8GA1Ud IwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9jZCvDMA4GA1UdDwEB/wQEAwIBhjAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAxBggr BgEFBQcBAQQlMCMwIQYIKwYBBQUHMAGGFWh0dHA6Ly9vY3NwLmRjb2NzcC5jbjBN BgNVHR8ERjBEMEKgQKA+hjxodHRwOi8vY3JsLmRpZ2ljZXJ0LWNuLmNvbS9EaWdp Q2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwSwYDVR0gBEQwQjA3BglghkgB hv1sAgEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ UzAHBgVngQwBATANBgkqhkiG9w0BAQsFAAOCAQEApSBmV5Ps1+C/vGSHxbHprhNw A+1KTV+OSl+jknV39V3fGhAx8IcdDXwsbyhvmUjOHY8GcqD8SCUk72LoBgj3idyQ hTgUVL3igaP303F/J+hIrZIgTiJp5TrBi6NXq0YNww7LnA9qOBJFFB2AgCFCfkUw naQumPV82iTDP31BMNi9yZvWeGrlBFBcAx9GJ2TS7hxrCdhO6Nf94uBx0nOjzXjc RfrYXR/ATawEyh/xPCDZ+lBNFIcI64OFRbnMNKByl2YuJmHJ/4dO5m9+4VB8p5ta zOQAMrcqnE3KD3bFqYkJyPeH04YHEgiaJqoXmg6ml+kGxWhSotuKUtgbibIKdQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGDCCBACgAwIBAgIQDzfM84E9heVerQl8ZHkjTTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA2MjAxMjI4MDZaFw0yOTA2MjAxMjI4MDZaMF0xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xHDAaBgNVBAMTE1RoYXd0ZSBDTiBSU0EgQ0EgRzEwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQCzgci89PrLo0hbutmkcXbgRF8G7sREiMqZ2DbuSY7v B3XxEh0+rYoL97eG49JQy+OMtcneZaV+11TfGH/WAMjZK/jMg2kZCw0VThxE86dq Ph41dp7PM5BT+ImF/iDFYrLZR3lu46bxTnVVlpJ7C91Q9+ZQb9D+J0LGnUnFY9t9 b75+wC+rz4r41rUKkJMZrY6jBDIagPKsMNXyWz251bPrbyDXnRD/7re5sWGwzuTf a2n+t6AUQCtASoQn5bOHobmHho+/J3Q8wlBNtbGrz2DdmZIwNXyX0uEkAWBBwii/ fJF1MjI5dPHBNSUkso/3RW6dzXsSkYmfgrUua8CJh/YrAgMBAAGjggHOMIIByjAd BgNVHQ4EFgQUd921A1Hu2AvElJsl9tbymKAj6vowHwYDVR0jBBgwFoAUA95QNVbR TLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MDEGCCsGAQUFBwEBBCUwIzAh BggrBgEFBQcwAYYVaHR0cDovL29jc3AuZGNvY3NwLmNuMEQGA1UdHwQ9MDswOaA3 oDWGM2h0dHA6Ly9jcmwuZGlnaWNlcnQtY24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9v dENBLmNybDCBzgYDVR0gBIHGMIHDMIHABgRVHSAAMIG3MCgGCCsGAQUFBwIBFhxo dHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkg dXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBv ZiB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczov L3d3dy5kaWdpY2VydC5jb20vcnBhLXVhMA0GCSqGSIb3DQEBCwUAA4IBAQDUAdjb +rRkzI79bUzsLBfeYnY0s9m++3QwlAE1/HzNT3i/odV7/UMglF6oHRWT3bPHr9LP /RjxXdJy3VEi1xqVusLqCyLvWSp3hBrrlfLH2LKxiq1AM6a5AxtktLS34yFACGbV CsVfilJth8bXWwvVJ8jV1MQsxjvMgjr0XKGYykUOIP5sHQnaJ2biBP9tq+Vfr7e+ mr9J8vlubppZQPaIqiMN87v30T1b37eXuoNbmTFph+rj4aaN+Yz28iCqmGqs4qHU cICRmH09esI+SD0Y+Or4gxM2aGDmh79aeLuxYYIsJRWox3EM09V2rRk7KrjW9wrR BEBEtYxDXhI3Zy7+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqzCCA5OgAwIBAgIQAiNKBjFb5COpdzQhXd/JPjANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDYyMDEyMjgxNloXDTI5MDYyMDEyMjgxNlowYDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEfMB0GA1UEAxMWVGhhd3RlIENOIFJTQSBFViBDQSBHMTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANMD5Iie6O9Ifldi4gUVFuk1 E0DuIg6kcySD5KXF21rCUp74e93QBFIjpB6620n+HZPJ28oP1BfSOhasTLpjR5pQ zNHiRZJHj4y85iMaVKs2yPN9ZQ2dnn4/jg0TQwwSmpEqa0Nx97YqxMJAdNDVCyvf kref4toGeVIkdwg/c66beG1RM0IMHuNhbNkWs2vCB3OkHFWFJEuf7BePWWAn7ASm 1LviYLC2uPUESXASXnpjtN/iRpoOpPJ9v3wHhwJlT+8d7QMGQCCe8TZR2E42faX3 z8Hd10Q7lEV/lHqMFVhawgdnYIGHw5xJdWOUWvsB9NYkQ4qNwmIdioSKI9VJTccC AwEAAaOCAVMwggFPMB0GA1UdDgQWBBQx8x3+kyDcMotj3+3i+sWjed94uDAfBgNV HSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAOBgNVHQ8BAf8EBAMCAYYwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wMQYI KwYBBQUHAQEEJTAjMCEGCCsGAQUFBzABhhVodHRwOi8vb2NzcC5kY29jc3AuY24w TQYDVR0fBEYwRDBCoECgPoY8aHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vRGln aUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMEsGA1UdIAREMEIwNwYJYIZI AYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9D UFMwBwYFZ4EMAQEwDQYJKoZIhvcNAQELBQADggEBAJ1+lMkRXnwKXLtc/GcexDtL PXD1nYAKciTk16su9+Aif+zEC7Wje+zZ6TifDMAhgOreuFFTA6AmS9KH5BIwcMZE 0rU+z5rVstVs6iRvB39/y4lFXSfFz0M8gwN85+BxNGKX8Bh+0VydDtOuWcKUXdEF ApLMSfvQT/D5QcQT5tqjvGQEQ66MRu1bwL5G3c0NePSyzq6P3A3JAiF3Ra0CtXu1 iwVW28EgbKEfxIgToT4bXuJ1JCRPljlNx1ghD/wHIvrJNQ0nlJ01QfGLgpiNzih8 WEYsicyR6MtZhxmlNLdsGxWKu/Q2m+CZSLUKScysFVjUnmjWThXbPGtOKjmo7IU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIQD6mSTOo/FQoxQHBMUXxnszANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDYyMDEyMjgxOVoXDTI5MDYyMDEyMjgxOVowXTEL MAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIElu Yy4xJzAlBgNVBAMTHlRydXN0QXNpYSBFQ0MgRVYgVExTIFBybyBDQSBHMjBZMBMG ByqGSM49AgEGCCqGSM49AwEHA0IABGPg7/Z2mPo/Dl5FOkJGSfYQM7h5RLPmA2xe TyEfQ9rsZYckDXU4FGWIfouhvDSkTLuPRvxj69gG53DoUT1xKwGjggFTMIIBTzAd BgNVHQ4EFgQUby0NYcws4YBlcDCOCD/4iK4qj/wwHwYDVR0jBBgwFoAUsT7DaQP4 v0cB1JgmGggC72NkK8MwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MDEGCCsGAQUFBwEBBCUwIzAh BggrBgEFBQcwAYYVaHR0cDovL29jc3AuZGNvY3NwLmNuME0GA1UdHwRGMEQwQqBA oD6GPGh0dHA6Ly9jcmwuZGlnaWNlcnQtY24uY29tL0RpZ2lDZXJ0SGlnaEFzc3Vy YW5jZUVWUm9vdENBLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG/WwCATAqMCgGCCsG AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMA0G CSqGSIb3DQEBCwUAA4IBAQCDJXNyw3Q/vvrAKVVFL8d3BIux7pY2AQuN7Cq20DGK sQ6bdZQ2x0oXcxlluwgvSWJlLbmsxiq7UOhxqjTHuUoVIBPJwRZPq0vLvKFyUlfe dHnxa9H48Vk/01Y8x85BtkLy7vLqAvRa2JPr0kNlTaSdnqhlu/ZlxGRnUGVeCj1d EzHP2YetcOOpklaCURolkx94HlCgzY3F78QnQqXULuXgwyEePD3ujEy+gNqjmKzk GxYJHHvJn6YeyxERarGC7dikI2KQTo5f2LZrMgqAvyILqbMj1PsHugJQB8lG+PEE ONe8ouVDQXlO9ZoXa6ZgKzwfAbiVc0Vk9tNA/V+kQKcd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4TCCAsmgAwIBAgIQArxeKxjrTx0R8U/latSHaTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA2MjAxMjI4MjJaFw0yOTA2MjAxMjI4MjJaMF0xCzAJBgNVBAYTAkNO MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMScwJQYDVQQD Ex5UcnVzdEFzaWEgRUNDIE9WIFRMUyBQcm8gQ0EgRzIwWTATBgcqhkjOPQIBBggq hkjOPQMBBwNCAAR6iMBXCZLP/2ZD27izsSQvs8pj1oYxFapXxHdhOfQ/S60lZ0Ao c9mPPkMo8rumEAcyFV8drD9OABIC3aDNjB0Oo4IBYjCCAV4wHQYDVR0OBBYEFBSo R/Qt4BHV4uumaXHhQNA+zbWLMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5ey PdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwDwYDVR0TAQH/BAUwAwEB/zAxBggrBgEFBQcBAQQlMCMwIQYIKwYBBQUHMAGG FWh0dHA6Ly9vY3NwLmRjb2NzcC5jbjBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8v Y3JsLmRpZ2ljZXJ0LWNuLmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwYwYD VR0gBFwwWjA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu ZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sAQIwCAYGZ4EMAQIBMAgGBmeBDAEC AjANBgkqhkiG9w0BAQsFAAOCAQEAHWjCgWLijPxcWNwXS33xLQj8CcTcjcwlzbUq UMfivsDJT+KyIEeaRUQKIT2ZQfwS09GDOm8BvlJLyOhcJ3AST4lFKTiNh4XiD7df LwSAI5DqFNkRj7v6lOb+lD5WQop59bMu+L+3kjl6c2unsuCzlQNPnT222rxJkhDA 0q342jq4/wl3tQRj551CYxQOXXRiG307FQUNuP39LWx+tkLMRoAGWAcRvCKwBx3Z ccq8ANsliCrXNR5ntZxLvcaob7lSq3y8pQ3EgGSUmSh8zCDPgOPBHcFNVONkTG8g N3kp58QK2k6cVAIKujEj84bWs+zgMfb1I1Wb739tPVDo/TNZRg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpDCCA4ygAwIBAgIQB9jigpEp1PkiYfXiuRtdOTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MDYyMDEyMjgyNVoXDTI5MDYyMDEyMjgyNVowWTEL MAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIElu Yy4xIzAhBgNVBAMTGlRydXN0QXNpYSBFViBUTFMgUHJvIENBIEcyMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA15dnkGxf4PwDxrIdAl4GmOY3xP9Fj13d DMGS76H2OvxqoSsic4mpOIUrfmS5uzsjFRcM48ktD3Efc+6337AKYOa0nLn4yMUx dpTOgMFzzcf4XMAO2OAuhihW/O52OwD2VeJTAClI4wXoLOAVkEBd8i59UUn3cNwk y3oGL8NlfVA9oR4+m5bTo4LuqQxZC+FFt16SCvmzMmjDyShtbeiu5giPtHUvOG8W XxL9ndj6aDba2w6bec043wvGOj0Drf/XMbVNbTpfGiHNiFd8vd+jLKzw6PmriIAq Eu7NwALO6Pl+Sc+Q0UCa0hzGOTQUrvltxKNI95UiYZfoL0tkjUTwhwIDAQABo4IB UzCCAU8wHQYDVR0OBBYEFGebMX+NrCFQfdIgwzjhhb8uqdm8MB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAU BggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAxBggrBgEFBQcB AQQlMCMwIQYIKwYBBQUHMAGGFWh0dHA6Ly9vY3NwLmRjb2NzcC5jbjBNBgNVHR8E RjBEMEKgQKA+hjxodHRwOi8vY3JsLmRpZ2ljZXJ0LWNuLmNvbS9EaWdpQ2VydEhp Z2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwSwYDVR0gBEQwQjA3BglghkgBhv1sAgEw KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAHBgVn gQwBATANBgkqhkiG9w0BAQsFAAOCAQEAVaA3ZsgU83K5uAJ/tEQC76OD6uIYiUCA dIXyu4m1YOEsB2JAPYL5pswH4MeVV2l9mtnh+9/y+z4tkv10wlMwPuTYQXwSrJyM dZy+A3hpdzUS0oWjgeLLmV6hq8k7FigJIJyelwM+1CUrelewKLWwcPKn9HIRoW/M HhIIN6vgfqvd3JhacVDAvaZyzheDKh+xn6AJrJol6PYXsUDrEyxmaxLXwpvMygS4 FgU9Fu1+AHxGmflCg72kRfrHkn4Y8GE4CfqC/hnhTvKOzdyFvaesgivPRD+du/1s RgvgAEI6J/SiizVGQbyy1sSmI93gwMzQANxH969/2TZecw8SjfYr7Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFDCCA/ygAwIBAgIQAfbmZXRWPiCVTeVM4Te6WzANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA2MjAxMjI4MjdaFw0yOTA2MjAxMjI4MjdaMFkxCzAJBgNVBAYTAkNO MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSMwIQYDVQQD ExpUcnVzdEFzaWEgT1YgVExTIFBybyBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBANi3V94eezo83efo/Dt5k4znCiM/hKssy0J3Ws4d3F8hM4z5 OhtIY8YBlKfl1gqmBmqOgd3HwyCmXbx2Reud3nT++GVp9T5diT6AKSnKTwpTBjip cJ6GRsCy4dqs2DOx6zBI4Dj2LlYhShW1pH8VzDmmtSfUEF5lOTV7iJ8PPiBws37T lPw7Bb36llnwtXGlYr5zVxrYI3WatYLJHXywPtixs4EgtG7a/OpsDWtGqmkDf3us e13BtwoBorvFtUdCPaPHGgiRX3seDm2KauZcH/ejITrl+8jEEghd01o3kPgiMud/ wpGSqb+dGsRyX20h0+/jgFNPSCv/eqW3V1Nqo5UCAwEAAaOCAc4wggHKMB0GA1Ud DgQWBBRPhfybWdPGU5ePvB6D8x6CJRS8eTAfBgNVHSMEGDAWgBQD3lA1VtFMu2bw o+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wMQYIKwYBBQUHAQEEJTAjMCEGCCsG AQUFBzABhhVodHRwOi8vb2NzcC5kY29jc3AuY24wRAYDVR0fBD0wOzA5oDegNYYz aHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0Eu Y3JsMIHOBgNVHSAEgcYwgcMwgcAGBFUdIAAwgbcwKAYIKwYBBQUHAgEWHGh0dHBz Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFueSB1c2Ug b2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNlIG9mIHRo ZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBzOi8vd3d3 LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwDQYJKoZIhvcNAQELBQADggEBALTfGthgCvXQ a29I2oKevgfQx5y/R1Mbd/39etZMR+PtNaFOf5tfkTbqpNBbXhPIgGfXplXuPPn0 s44KesbD3t2W7K9MAvaYGG7MYyFTaZ99wwU1cqkw1lIw9UZCRJlAXQBsuKl0H4/H Uxc5ZbIocBsqmLcFTpbmbDB7kDZ7v41faH6YgVFAWgUdGarBLBC9cNJGuxH0k3Ol q0vsT7tcj0M16Ak2q9wQH6vB3MzrgBBh9TBHzn3PXaaeyRlebKgHFfFMVs44dTE5 355KWwcAfP4/SCN+LjeJvzHzQfMMoMfAwA+UJTZHRV6ab/62B8chGbB0Z7TU/8gX J6purZLIU0Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9zCCA9+gAwIBAgIRAMF+meA4drMEPrcTO+wgQmcwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDYyNjAwMDAwMFoXDTI5MDYyNTIzNTk1OVowbDELMAkGA1UEBhMCR0IxGDAWBgNV BAgTD0J1Y2tpbmdoYW1zaGlyZTEWMBQGA1UEBxMNTWlsdG9uIEtleW5lczERMA8G A1UEChMISVRTTyBMVEQxGDAWBgNVBAMTD0lUU08gTHRkIFJTQSBEVjCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMpzrjU6wQQIkYxsubPWgx6f3wOK2Y6O OT+U+48TlqNVImVmF0YYlQ7UKbZKe4nZUTg6TUtw4wobtKmAgQrV8ryFfyyzhh83 avHhngN5On8Nlp0aT42mc1IlADXo7qianYBuAcbsEpm7eioRPhFB7bta6AG2ueqI i+D5vfCXZ2cDcR2m0V/vyNQa2p11zZVxPe5SPNfUwImCQzpqlTO0hoF1yVu+P8fB scnqYORB4n3pXXLP85//Ejt3D2H/IP4PdStw6XjGx3qHTlo1IMqQQR1BunmExIzN +tp6y9/C3HJieSzxFmp5a8KKS7pTmeB5Vu5AjrjS3QDOgbUJA4Ch0X8CAwEAAaOC AXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQW BBTq3ziiyuwx5N4jqdO49rfhGumpQDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/ BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0g BBswGTANBgsrBgEEAbIxAQICSDAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/ aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRp b25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0 cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0 MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3 DQEBDAUAA4ICAQBqM/f3zjfJmFfZ9TnBQYzZx3Ck+DhAy3RrLzrqfgkPVmQdQE6P T7Pi/z3vEKQxw9DhvqTI+ZMBbrZbF2dYkzMLS7h7GksLJAsAmFDOxdN4TDZKh/vM T5Ot69u6emSfzaGrYXpvIBK2Fu/f4diFcFCWx1hPXp4yqPTFNPPKOROlAJqedJay 6erfW1Y37XzHjvvVkF6bp6SpYnb37qT4/A85SwHeGgznhH7EATCKMiaFz6KEvzq4 nTN1XbfAgcGmYOPfKqkH5Iw9UX8fh7sKsZZAwfuoYx7A8F1UERv4v110prGtY9NC N4sli36hjd9zAeF4BDy5pymozYA9APcIU22oaNS6V3m7s75t+oT5I2q83uj2gCxL tty6Uh6larWteNoRA5I0EN6Ws70ny4bPHQB6r77BDmbixxn8WvEpTnZ38awPKhg8 e9vt17ph/2cpQ2MIOSdpjIyCyohy64VENcMnsFrq8/bnCDYKs4WLER4MoI0pNgXK XQCSRCvez7EiC3T8c7W1JYqvA3bSA1mTLMvFOarTFw1jVtbdhbt/bWcxa/thsolf edy3Ob7zgI97V8rrAJiQyCEhXb0+e/JbH28cCDUGUncuzQz8C/KmLU88bnE3vLAO 8SFRoF82MfkWF+0TvHNJerej1SvgxFBuReUa94yp1ZfP3DlaOi/HyZiShw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHZDCCBUygAwIBAgIUKkEld3SgrCNJd/46d7nmfnn1fU0wDQYJKoZIhvcNAQEL BQAwaTELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRl bjE6MDgGA1UEAwwxU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFBl cnNvb24gQ0EgLSBHMzAeFw0xOTA2MjcwODQ5MDZaFw0yODExMTIwMDAwMDBaMIGS MQswCQYDVQQGEwJOTDEgMB4GA1UECgwXTWluaXN0ZXJpZSB2YW4gRGVmZW5zaWUx FzAVBgNVBGEMDk5UUk5MLTI3MzcwOTg1MUgwRgYDVQQDDD9NaW5pc3RlcmllIHZh biBEZWZlbnNpZSBQS0lvdmVyaGVpZCBPcmdhbmlzYXRpZSBQZXJzb29uIENBIC0g RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDI4VPNwCeJdEeTJCaG S/4xz51pbs/e4cBCwY40B/+QzdMz4vHLb4Rcw4Bx9ajmf22yA6YI7fBmGgKfgNfD XJx2YXcuX9RW4sigkJuml66khWJkT3z8cMKkLoVToXLGoepr8U5HutbpYmftOBjG oX+vEsTq/3SqbujcIqomh6rhjpQOpZYjV3aBSUSpJYQUI7ncavDH+gKKl45OcdNw SW+h39bHfug4znwKL+Wb4Gnw3543uqGEeZAeuyAq2Pl9YW42lqEupo7hFeOOhBiG pOSoACT9mZjgb6TWwIbKRGcd328KRiW/qTTHHHWFWDszfLeEmEV6ub3ibBjT5Gve GbMRjY5t3WQeAity4TDGxQKYLFxBvHhJiWryuaiUdx2ZGMEq2iTTWef6c+8I37C2 oo8gq7r+giKnWnfmpDJsCPaqPgtYwq5yJiTjk65+wsGT09Ezoj/1ODB6bhmg83LW f5r1PAtjVRUfK89Gy0tIAIi8ektywyD+TGh10kVyFNxsYzio3V89u5qlOgwJrNo5 utv88YBFzVBRaj3iHLGIgRzqB0IpxOq9Fa55RH10X1cA65WGcnext7pUkSPKNuna GnlEu2nNfnZMjWenS8sl6x0isEZl/xSO16JBC/Ah7TMTsmD4RjlmWc/PSQzt1vGE VW1GNVXimZ7vA5Va3GHwZ5eBlQIDAQABo4IB2DCCAdQwVQYIKwYBBQUHAQEESTBH MEUGCCsGAQUFBzAChjlodHRwOi8vY2VydC5wa2lvdmVyaGVpZC5ubC9Eb21Pcmdh bmlzYXRpZVBlcnNvb25DQS1HMy5jZXIwHQYDVR0OBBYEFCO7+d+AiROjdyfpxmlD M41JB8JqMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU7qxtQOrVBGqH LFV79T8t2u7brOIwJQYIKwYBBQUHAQMEGTAXMBUGCCsGAQUFBwsCMAkGBwQAi+xJ AQIwXQYDVR0gBFYwVDAMBgpghBABh2sBAgUBMDYGCmCEEAGHawECBQIwKDAmBggr BgEFBQcCARYaaHR0cHM6Ly9jcHMucGtpb3ZlcmhlaWQubmwwDAYKYIQQAYdrAQIF AzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnBraW92ZXJoZWlkLm5sL0Rv bU9yZ2FuaXNhdGllUGVyc29vbkxhdGVzdENSTC1HMy5jcmwwDgYDVR0PAQH/BAQD AgEGMD8GA1UdJQQ4MDYGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDDAYK KwYBBAGCNwoDBAYIKwYBBQUHAwkwDQYJKoZIhvcNAQELBQADggIBAIWaXw5qH3+k jOciAYr4onkeu67O8GVWS8wWxJYozsfjDgTqOqRyHejMjUj+CeMepsL2XKXrpWT9 NAIteTZpWbpwRENQQ8yVnAdiQhP03wR7j5WoQ83PQQ2v5dK0uESlMwDidELELGEL zNSsfbWaXXd2dE2XjS6Nzq/WB8+2U2AHhfZ13lPzbuSmOjCWF22QFJruMNwCuRA+ JnfCTRZpmjL8x5eFn9SiZvN1lDsCh06AL4wSrTj+RsJ73fPjqgWn3hVV8OCmWfjU WBaFb8OIWByitiJpjVQ5WTRW0xaWcNPNGXMCGPcgp50I591jrcQ/XAI6RmXzTMWp 7nq4u4Ro6umTd5lPoBtzT0QKgwQXK+0e/J/bDMhQuVrztvSannr/rqep9cTv61KJ kwHx0rnuZAwIot+Vz/b7OYrnN0EO/EF2MQNpRIp+81uNIx6hjmGX8QbvT9m/1JRw mBV1lFd/JKkEe3eN0jUsvUG6moimrE46UendVvSXAlG0jMmw4CKGkFoeb7ZuOdzd i/4xSrlRUH4lqWaBUlKE3ofJJRpK3lZDj4DCGUiGv3gSFAt+c9mzIcJ8k9HQy7ak E+/kOcMjdRgDESXvhLF2EU8vHOsqp0zt0Bk0d2flaxKJm61y8W0rNnknloveFC4Q 2WimmV7I1bTwzvT4/gMzr/LPT4W7fHED -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvjCCBKagAwIBAgIQB4HsLXbbEi4NQUs+Gec5ezANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwNzAyMTIyNDQxWhcNMjkwNzAyMTIyNDQxWjCBizELMAkGA1UE BhMCVVMxGjAYBgNVBAoTEUFsY29uIFZpc2lvbiwgTExDMT8wPQYDVQQLEzZDbGFz cyAyIERpZ2lDZXJ0IFBLSSBQbGF0Zm9ybSBJbmRpdmlkdWFsIFN1YnNjcmliZXIg Q0ExHzAdBgNVBAMTFkFsY29uIFB1YmxpYyBPbmxpbmUgQ0EwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDSUCOvBD0XCHhBlCZIwMVfq1wh2cjYAJrsm5Xj SWe4Rrbns+MsMXWRCiO65CxGNEQu1mZp/OnQCrbWWW1JrjZsjjG+U/TjzJdpFp9U 0iOmDtx+EFuSLZtMyIJmfU9ORrQQx20EFpngZuIm7dFmtqsdEgzrb1IaWyrf+jgD +Iu16oWADaQ2gXKZ38Fjzslm0X76WsSF+xz8FDrnYA2RZH8EXUGkpB53u7FgIEfX 2t/l0i+TDBSRIWIXCuFWU3fEvrMnJX1SvTwp3yfwMVXJF0lKb5qBuPWbxNFSsr9J /PuXLxBeg6MwO5acAKRaOxZSNdjwDsPFXVn7ldIqQrf73PLXAgMBAAGjggJBMIIC PTAdBgNVHQ4EFgQU35Wbp20Ejucn0jfu9cX5uSP6fkEwHwYDVR0jBBgwFoAUzsNK uZlV8rjbYL+pfr1WtZc2p9YwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsG AQUFBwMCBggrBgEFBQcDBDASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEB BCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMIGBBgNV HR8EejB4MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRB c3N1cmVkSURSb290RzIuY3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5j b20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMIHTBgNVHSAEgcswgcgwgcUG CWCGSAGG/WwFAjCBtzAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu Y29tL0NQUzCBigYIKwYBBQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRpZmlj YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkg QWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL3Jw YS11YTAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQRGlnaUNlcnRQS0ktMy0yMDAN BgkqhkiG9w0BAQsFAAOCAQEABZJb8bt5xXfuuegUSHSpMBAl4wWKqUXGQf9F5VcB jCRIGzGUs+1u7U0Vr0xf23PwkkPzJHaP23Znh1diQYUfr1vHBlj/MvsM384VwLkC j9YwV6K7qMixTInJO13ouLnSE8W/UPJwoRF7ghH1H8fyepZX6G81UpuziU1Gi6wi hbzIE+qxl2sXbMYwjF/Duc/YQLSaklUovHkbvqItl3n0RC0vFItvXRYQucuAOz2Y kVptb06xu7UzjRsn6KRejB5d0ykxVZtt7FkzLvEiqefggTK0ri/KCsM8U08UDksJ X033C0MVzLmaggBRIeiW3vficc9RydAm2NLDqoenqYTIpQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFujCCBKKgAwIBAgIQDExu/tFklO8JaPo2ZOG7QDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwNzAyMTIyNTEyWhcNMjkwNzAyMTIyNTEyWjCBhzELMAkGA1UE BhMCVVMxFDASBgNVBAoTC1NvbGVuaXMgTExDMT8wPQYDVQQLEzZDbGFzcyAyIERp Z2lDZXJ0IFBLSSBQbGF0Zm9ybSBJbmRpdmlkdWFsIFN1YnNjcmliZXIgQ0ExITAf BgNVBAMTGFNvbGVuaXMgUHVibGljIE9ubGluZSBDQTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBALuKuaDt6F3yEK2Dcy4SoRgPjd01PlOLLAanwe92CC6I vYF9dQ7LxyFJVEo9vpn///EoMLxjkoSqAQARscjkqArZOpldemuupr8sqLuHrnIL mk7vCJ176q+j4k+LiE6umIpknG2xE52pbCoeGtq05euKf18NDKtd+ZBpUJ2jxrK1 9hkfX3pSW64h/LSDtwEFCdWy2/9zVh1jPGUlvRZCUeSuIQCEp6hPPJbly6mpZ3rB wZhgYFs50Yap9JjkC8O6L78LRizESDpuWmUxaKkxp+OyFtRFIne++uwxCQym6vt+ YTKwHmZ2HqTE/HZfnzsgMs6E5d4oIhqddkGYpDkkkvkCAwEAAaOCAkEwggI9MB0G A1UdDgQWBBRaUFvYvCRnkHjt39OKm6Ji6VRKXzAfBgNVHSMEGDAWgBTOw0q5mVXy uNtgv6l+vVa1lzan1jAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH AwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAm MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgYEGA1UdHwR6 MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy ZWRJRFJvb3RHMi5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9E aWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwgdMGA1UdIASByzCByDCBxQYJYIZI AYb9bAUCMIG3MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v Q1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUg Y29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBBZ3Jl ZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5kaWdpY2VydC5jb20vcnBhLXVh MCgGA1UdEQQhMB+kHTAbMRkwFwYDVQQDExBEaWdpQ2VydFBLSS0zLTE4MA0GCSqG SIb3DQEBCwUAA4IBAQB7z7ZGCwRh9qMI34hlQ+1Hi5epRSHDjHMqjmX/2hW71hDc M1L5VB+MqHdXBEjbJc+ZrwRP2okhLsQS1VFS+FrSwMVlwX7AD0cOeYyuWO+iOzCB yMyJu8UBNw66kX37Lx7grj8S9mULBnrpzOysDcQXXuPAyI/gb7ilHNtnvYsDwhEx Q217sBJfwyb7MNBOj7azcX0bNWA/KQkZg2UBGqk3cOWIM6/oIQOfybSe0d/HFvLu bEUxWEZO1lGrKR638cUHEAqL0MsuuT4zRq7Mxitp9vZwBIh00UNUA0BgAHeQoJ7o NkK1cYO2+Zjt1+w/bIeH+G9G3YX92lHTNKHgmC0k -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFyjCCBLKgAwIBAgIQCEQc0xzwgpwY59okSfd8PDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwNzAyMTIyNTE4WhcNMjkwNzAyMTIyNTE4WjCBlzELMAkGA1UE BhMCU0ExHjAcBgNVBAoTFVNhdWRpIFRlbGVjb20gQ29tcGFueTE/MD0GA1UECxM2 Q2xhc3MgMiBEaWdpQ2VydCBQS0kgUGxhdGZvcm0gSW5kaXZpZHVhbCBTdWJzY3Jp YmVyIENBMScwJQYDVQQDEx5TYXVkaSBUZWxlY29tIENvbXBhbnkgRW1haWwgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmXsAM/5L440vxJ+DYKygJ adh3LD+/TDDY7W352s4q9fv2bDiapPHS5poZe/Js7Y5APkGctCGppRreZCRLZgZv 9C0FjYzz17dptez05dl0Mrc/gTfWkTzGMzqzu7RAbQt4CZ7OKRVxTfZrtoRm1P0u TejHnaB5vUdGkyqblmyIucxoveGN9TSal4cf8miTQkz0ajgHENsFdKLjtPUM65VD kvJCny1zQenxwp3DilCCIcBzRhBhcWpUXQlZzzQYI/Vcv3q2iJzsrraMC6bsE7/W Z7bMMNkQKDb6GFTjL2t5YXG9FeKukVM1rMV80qdICErmnbeMzWn9hIa4ctGSTGKF AgMBAAGjggJBMIICPTAdBgNVHQ4EFgQUxJhIhTrZYQhfVLGYNcp+30OkpfEwHwYD VR0jBBgwFoAUzsNKuZlV8rjbYL+pfr1WtZc2p9YwDgYDVR0PAQH/BAQDAgGGMB0G A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDASBgNVHRMBAf8ECDAGAQH/AgEA MDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl cnQuY29tMIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5j b20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMDqgOKA2hjRodHRwOi8vY3Js NC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMIHTBgNV HSAEgcswgcgwgcUGCWCGSAGG/WwFAjCBtzAoBggrBgEFBQcCARYcaHR0cHM6Ly93 d3cuZGlnaWNlcnQuY29tL0NQUzCBigYIKwYBBQUHAgIwfgx8QW55IHVzZSBvZiB0 aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFJl bHlpbmcgUGFydHkgQWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93d3cuZGln aWNlcnQuY29tL3JwYS11YTAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQRGlnaUNl cnRQS0ktMy0xNzANBgkqhkiG9w0BAQsFAAOCAQEAIBR3CphZ+shUnnj/eZtqW2uu qiClAsmgnPA8fS1aXqkHe2fA0pXof87HXE1sQf4HoofNJO/7RRbfiLGa5HjERSa2 8JGRgPfAoyD29DyDbV1uUvOpUB3c1TLBZQ0OP3wyysThQaMTshtis22NuTaKwpB/ fCFdsuFt97+6jSKb1Zsoa5hYU9Cz/LU6LW6PncYkVrfl2iZNOmjRSeBfMB+qsAu9 zyJ1YYYQa7988vS4oAsbLIWnWXck3a8ChGZs1alsAv9iTh6qRloSXl2JWsmT8lxq PJx4kWHEk/qiJxVn0X8EpZPmneQ/FldsRvSQzh4rnTtt2PuqXS75NrmMTd0/pw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFBjCCA+6gAwIBAgIQIrmxXEoSYXSKUE0XIUepzDANBgkqhkiG9w0BAQsFADBd MQswCQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4s TFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4X DTE5MDcxMTA0MzUwNFoXDTI5MDUyOTA1MDAzOVowbzELMAkGA1UEBhMCSlAxKjAo BgNVBAoTIUphcGFuIFJlZ2lzdHJ5IFNlcnZpY2VzIENvLiwgTHRkLjE0MDIGA1UE AxMrSlBSUyBPcmdhbml6YXRpb24gVmFsaWRhdGlvbiBBdXRob3JpdHkgLSBHMzCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALoBFHBZu+3cHAAWGCbPpfLm 5KadFEuMwgzniL7x7G/2fkag/NJDCz5Vk4wde1ICk+KBu8EBqFlncaFweLHefHCo X9fphQUR//Zsg/XtIZaCt4lp/Cn336b8sCw/IjTmIrDmiWluRw55sES3jTbEbbht IzwIIUOMLtkpdJE7bO/7t500Bg3TZZ4X4WIpEdpkglSxBZ3VGa3qFKtquZ7jwM8U /eNwrerAHaKwvBfgdRmTZP0N68Ak2LiG/95dcAdY2LoGUImB/I6zfh90NZ3IJWuZ YauzKMNlZrFIKO1Lfz7qh37NHlSvKMa2ve0cUuHS+pziTVrqVyc7BQjI1POy3+8C AwEAAaOCAa4wggGqMB0GA1UdDgQWBBShEBXYG/6eTppOHfK2X0ETgh1BUzAfBgNV HSMEGDAWgBQKhal3ZQWYfECB+A+XLDjxCuw8zzASBgNVHRMBAf8ECDAGAQH/AgEA MA4GA1UdDwEB/wQEAwIBBjBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vcmVwb3Np dG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290Mi9TQ1Jvb3QyQ1JMLmNybDBSBgNV HSAESzBJMEcGCiqDCIybG2SHBQQwOTA3BggrBgEFBQcCARYraHR0cHM6Ly9yZXBv c2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJvb3QyLzCBhQYIKwYBBQUHAQEEeTB3 MDAGCCsGAQUFBzABhiRodHRwOi8vc2Nyb290Y2EyLm9jc3Auc2Vjb210cnVzdC5u ZXQwQwYIKwYBBQUHMAKGN2h0dHA6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0 L1NDLVJvb3QyL1NDUm9vdDJjYS5jZXIwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMJMA0GCSqGSIb3DQEBCwUAA4IBAQDL7q6WCUUM1bh3HcRj2uMuko1t151J +L9RfGGvpRstb+YG3vEA1OQps3r4hHq7y46hkl13mpOspP40gZ4G0NtMnyP5a/8t /x2KMAgG7yG2gIOygW2Y/znxFvXeGiB0uquEAiD+Ph9F7FInMMQfJn/WV37fCnP/ ksgapgTgHxp7piRhBHB21N+gAdX9uD8REtfotzhdO3F+6jL2coowQXTRpiEs2lJr O92ijJGnMETaSP2Pst6VhJe7mTXdMCle/1A08phy6gO4Z4Gh80CYYemyyhy+16CN 8HYTAzI6ksWO7A5Rf2S/zNqVVMhCMLQaKvJncC3CDyF5QEEfm07fjONs -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5DCCA8ygAwIBAgIRANs66Z/PZAfY2u75jMd/jBMwDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0xOTA3MTYw OTUwNTJaFw0yNzA1MjEwOTUwNTJaMGcxCzAJBgNVBAYTAkNOMT8wPQYDVQQKDDZT aGVuemhlbiBEaWdpdGFsIENlcnRpZmljYXRlIEF1dGhvcml0eSBDZW50ZXIgQ28u LCBMdGQxFzAVBgNVBAMMDlNaQ0EgRFYgU1NMIENBMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAuqv0ecv+COJ6TzZ5AdqGadw5MSRnRk0s8Y4t4357Dnoy jOL/6gkcvP/fn/m1gb/aHSL2qnR753PFHLkpiRmupUPReNwyx9rK2ICTC+YUDZlp dX957377nmfAGgUOvuPeJ4Y30ylopjngk7lZrEB3GB/rnVhRO5Q4eqoxDtkMsnQr UNcGl26dry2TSptvei4irIi8dSzt/C0e+V8ezfx+o5X7WhHF84YuQLKaeFmV/gzd pf1y4oR1GQNCWiFtuFTgwx6qMMv0A9AaY43R90s89MGutTWIwrJfF0lHESzkqUDs 2OS4mt0W78SjiCUz9NBq7v6c8NnjXRdit7agREzFdQIDAQABo4IBbDCCAWgwEgYD VR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUdrOwy/VOkSG2lVd7gw/8FbIKHDAw HwYDVR0jBBgwFoAUVJndm//opw6jGZ1bvkJX3zD8jzIwDgYDVR0PAQH/BAQDAgEG MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4BgNVHR8EMTAvMC2gK6Ap hidodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9nc2Nhc2hhMi5jcmwwbgYIKwYB BQUHAQEEYjBgMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0u Y29tMDQGCCsGAQUFBzAChihodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvZ3Nj YXNoYTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBALf+JxGUAsZb 6hx1YR1ddqd8cGvtjptESJjZv6uezImzc0EqIzssfAGbpi0R3oCeodDO1du+/xd6 xbfdUqqOg6yEY3Gu0r9NtSG+ZT9oGRDMhQSCtdnBkI5v8l08OUF+8tORLEnr632H 8/Fzk7TENwERzZl53pkn5IvyenKJR+2OO+ABmppyPgeivnUebXZSaWcePR+fVNaw ogXIgKm5A64DjU3wYZRRsU6wDjkV7bwEfEbCdPn6osS9ugD7AUTagBkI3AqcLfuE CxDf/V5hUymQ9RXnkq1MrxDUL9CWWoVcJ6utoUr1J0hB/lrJcX3DiTZOf+GqqHSQ hGY4s4hr9tI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE4zCCA8ugAwIBAgIQIDaUPL6gi2kqKW1mJEBkojANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE5MDcxNjA5 NTIzMFoXDTI3MDUyMTA5NTIzMFowZzELMAkGA1UEBhMCQ04xPzA9BgNVBAoMNlNo ZW56aGVuIERpZ2l0YWwgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IENlbnRlciBDby4s IEx0ZDEXMBUGA1UEAwwOU1pDQSBPViBTU0wgQ0EwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDPTuxeyLsB5kuuWtudMsATk4FhEgG9U6ft2ocVM9OdQMld FbRm9CmxRxiGY+UG7VvSmBN3vzL/xtTX1JUe1Sy5+D0TcCBdGBZy87L8hDK3YCDb 7ntQ22ZSh5jmw75GiM/ajadxWRQvhhgZfQcdQIa86FYrPwEc3WfM+zpfaclq4rZA EAnt31sSBR61kvPHqQ/qADLdvsrYSFBj4kVR62p91pP9Pr1e2PNvcwkKsuLaRn75 9Dc7DJwky7L/G6WyZ3TFv5CqFNMHPqRbnG5fMwuoCqunHsaSyVFzbcLCbpvLxKdN Vs0mIlEu4V/GjnMFIFhCZAs9pLiBQIOcuJEcFPQXAgMBAAGjggFsMIIBaDASBgNV HRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQsxhCn9BTshBk/slPsmMs8yfdXZDAf BgNVHSMEGDAWgBRUmd2b/+inDqMZnVu+QlffMPyPMjAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdHwQxMC8wLaAroCmG J2h0dHA6Ly9zdWJjYS5jcmwuY2VydHVtLnBsL2dzY2FzaGEyLmNybDBuBggrBgEF BQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5j b20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9nc2Nh c2hhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6 Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAFxHL1t1rDDwD 2FFgy5kTWRYD/tVaRrDxgeNtiYcIIUwfZ+h+/UwXeystEH5v6BPr9yJanXPtPIor DgrW+l9r6ZAFTqjAa2mFGMktBzeGk7P7Yz9Z5v0LNbOm3JVO8Z9fsVsAM1M9E3V0 y8FvuPmvB9FW8ajXXEnRT7vkLs/mvi3kR89VJdtbzsdmodUK9GC9gzoy7WzUeUIn XZ+caJoEuGBXZcuqf4SA0dhiffDgP9Rs9xBq9Dt5u75zPuNXMv2A3CxA5VTZ1jFt DL5VgS41Uh3hFbckOhnXG0O7256eTR2Y6FLOB/k5UyUt7u58htIthSBmyI9tKR00 O2AXQndmLQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE4zCCA8ugAwIBAgIQTg1Z4ToaCOsNronpG2dQ2jANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTE5MDcxNjA5 NTMxNFoXDTI3MDUyMTA5NTMxNFowZzELMAkGA1UEBhMCQ04xPzA9BgNVBAoMNlNo ZW56aGVuIERpZ2l0YWwgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IENlbnRlciBDby4s IEx0ZDEXMBUGA1UEAwwOU1pDQSBFViBTU0wgQ0EwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDMy9OpY4P/7zkTlnQMdIQ3BA46BQQUQUnrhQLaTutJzfW8 8dqWSAZ4McLOAskQBaYGUN/fXc76oHsUR7bZXdF2lxq+13C8kgQXCs1sabReEbpM vuc6/5YR9O9xzyE8jZ/O85tcy8ZVDyh59oJ4Ep6P8jI6hKgSdOGfGtFV2um9awgE kjUsgdv8X08P040gWtE6HKU1S+7kgnONdplmIZdkGEr8Y6LalJqtEHIbeCw69iua x85yxfz/K3h03wAfmGskYSG7rkOFyoQn5tgLiG6eo2OG2iW97tVKmQZrtCfOGiIG E85YOxSXzIRh5eyNbRB14hGSBrAo5Sh2OkuW7HeFAgMBAAGjggFsMIIBaDASBgNV HRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSz/tvkSZXQoQD7hWndntIMlDewyjAf BgNVHSMEGDAWgBRUmd2b/+inDqMZnVu+QlffMPyPMjAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdHwQxMC8wLaAroCmG J2h0dHA6Ly9zdWJjYS5jcmwuY2VydHVtLnBsL2dzY2FzaGEyLmNybDBuBggrBgEF BQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5j b20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9nc2Nh c2hhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6 Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAdGQGgh8Ar89p cGr8XkoqawS/Z2HY6DvkO0OX8r6b/gnVNIYDGx/Fo+T/pxQNC39BfLzLU4SO5LLb 6nSv/gDc87b6z/ZE5RgifCO8LZ4nyKUBIAl4LDV7ufxNMJctmclcU0Glw9oaP8Ul dANh/00WlE7x6XMKXYh0sA5/J27DbYXv6gZL16tMu2l/i+DZ5nlJ/ZywyD8uq2wt Kb515nHKfnj/qBfLLkc7zIfkQ9QGbCHnIwzkRSN80xSYi/AnkN2znn3SygEnqfer CTiIUpoCLcgsCkYYM4PhOKDr7httEx7cqswp0MMHKxjUBcL0dgbIhyvHN+huLjUx xybOLcOYHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3jCCAsagAwIBAgIQDR78aP6XDkXNe5w102dnIjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xOTA3MjMxMjU2MjBaFw0yOTA3MjMxMjU2MjBaMG0xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xLDAqBgNVBAMTI0VuY3J5cHRpb24gRXZlcnl3aGVyZSBFQ0MgRFYgVExTIENB MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkIijFPTilcgNvSmM409/5dss/YFs lTVxgl1Q+sFLNTHojm2+wLzKqXfX7OyxQTHg5SBBDo2+l4Pd6hdU+NZusaOCAU8w ggFLMB0GA1UdDgQWBBTV3oXeSkaGzWFcz6oo9CWnfCnhpTAfBgNVHSMEGDAWgBQD 3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUH AQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYD VR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 R2xvYmFsUm9vdENBLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG/WwBAjAqMCgGCCsG AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAgGBmeBDAECATAN BgkqhkiG9w0BAQsFAAOCAQEAyHON5AldUWErtS01Zd9+kpUviNA83cMP3BGO816c SrhWxqZuM6yd+g7m1n0e0IcVi+ozEjeMoZcvWQKJsHLZ6b/l4z03yi2nd1oPzroq 2vmtwqR/3ckzd3Be87pg9t2ozXRUKgCq7Y//M/13O0VSH9Agag76sJd0ZnDSNDfF ODaT0PLptAI4SwdSYl3vNLVviM5FvzCXD0qbQqQhl/roiRWUPSowQhOosz61/Itk 7dh/UZzqwaFTXPH079kFKQzeTKukimY01KKPlg/w2w5Fstcbfidp82N3D7vIjJYS 1U86mCqPWZd1J35qbJPhbo7/+IqzK85lpcSAorkUfR3AWQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE+DCCA+CgAwIBAgIRAJxs9pVwDGAAAAAAAFHTk6YwDQYJKoZIhvcNAQELBQAw gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg MjAwOSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MB4XDTE5MDcyNjE4MzE0NVoXDTMwMTEyNjE5MDE0NVowgYAxMDAuBgNVBAMMJ0Vu dHJ1c3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBRVFNQMTEYMBYGA1UEYQwP VkFURVMtQjgxMTg4MDQ3MSUwIwYDVQQKDBxFbnRydXN0IERhdGFjYXJkIEV1cm9w ZSBTLkwuMQswCQYDVQQGEwJFUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBANzuQL7uN0KUXjcfIOAhX+kmgFVcPgBSjqzmrEp523IM1KICgVTQsJQyDvdM t0qAgAqvUhy6Q45JhRISFu8YUyueXfMXoabf92LKHLfChYEy4Ixgei1I6VCpMv12 udvpEDPtx3eLQJrWrnWVLtl40sGcBTmI37AmTw+z3oiudEUIALI0SbTLIcQv3YPp pb74mox2rFfzGhz+mzAKxE9dWznp/L8QeX1bQtbid5oImDwhFlnvS5KAvrxyEX5l Wl8x57BT4fSYhV5iP1/FY9y7Y0BemU/xZ5niTJhibQveJx9uNBnea7j4WQsAmaVB DO1hFe7g9KJWZ94p5dvW+iOytKUCAwEAAaOCASswggEnMA4GA1UdDwEB/wQEAwIB hjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL3d3 dy5lbnRydXN0Lm5ldC9ycGEwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdo dHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8v Y3JsLmVudHJ1c3QubmV0L2cyY2EuY3JsMB0GA1UdDgQWBBQcrT+c1y0iGaGcS+na 8Soz9/u6DTAfBgNVHSMEGDAWgBRqciZ60B7vfec7aVHUbI2fkBJmqzANBgkqhkiG 9w0BAQsFAAOCAQEAJhhuoOOrp7VZX+7gzDsbRLV7sbkiDZTkfBg23+trxG/lj93N sjQkpRRoUCH5HsmeaqhzfZWAv47ez53VrT/HzqECST4Yae2HDFysNaXGkBnV2HhC bjWEDxMB9HWlR1FM0K0l1wtY724NU+BqsDQL92JXxRlIGYQFvUjSyddUEcKFyNWi ah7BakLELC/P/V8C927byrCARGEOkeMYoA6YnMDWpQX12eRJCMuXzrSRzl7THoRp tTZGX2RaPIpqjnCfEzU8xJcFaaCfkXruhdfAv5ew6aECJ0liFkEgGW1ixPIjibwn 6A/BaOe0xsAudqAjLTQh/9xQnaAdrK6bxqxGRQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGBjCCA+6gAwIBAgIRAN/taPn0qYs3uaR/m7ZGGIEwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDczMDAwMDAwMFoXDTI5MDcyOTIzNTk1OVowezELMAkGA1UEBhMCSVQxDTALBgNV BAgTBFJvbWExEDAOBgNVBAcTB1BvbWV6aWExJTAjBgNVBAoTHFRJIFRydXN0IFRl Y2hub2xvZ2llcyBTLlIuTC4xJDAiBgNVBAMTG1RJIFRydXN0IFRlY2hub2xvZ2ll cyBPViBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM/P5VGAQQhE suVfPA7oCgVSFNi4kIytdOOxb4hqGoBtTxexnHwyT0bGwxOSuvsKhfmhSxAn0plO nCzUoQW3AOddLODQt8IbSdKGMSniTiG522TZUoyFDeEfPn2ASeivHMlhCg7a1qEr LBSeriiuZpfEADqSZBW6EOg54KprewjMjabY+SWqH+WObgYa5K+9tuEjfjYqf1Zt BKXxys84GprQn0zl93PAVEZ3Yo1OF4zuF5QzSuD6l933gGebq0EX/JWmikUcQwsf 0RnlkwH+4Yq3m4uzV0BXulqEDMQuURINVDK9/0GsijMjO8j53cHEgIOgOx11SsUh 0ppkQpRXo6cCAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvA nfKyA2bLMB0GA1UdDgQWBBRj5T/4zyexMRkqK1zN/y5x+yk43zAOBgNVHQ8BAf8E BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICSTAIBgZngQwBAgIwUAYD VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/ BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT QUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1 c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBHwDEaXKg/u+srk31kfi1GJOYs3fQD QTT1FIj0IQ02M9zbmNipVMhamFYfH0RoD5/v4tc0Eyg81zMbmWpgn5R+ixXpAvjL WYzzSeE/pAlf1BuVNPXjnNNCf6tl6Ik6MsW5jGrJ7ivyUbiBQqWce0+gJfnzgEUT 1j4APOwuolLtqEKzqz099vqwuhJA5JYQEtSPaBEoRSlNS6kSraar9BaL6oSqhPrV mQSIx962dqJCxbm8Bk5tN9NzH93np4YJuIuGE2mx7K44lqdXYERWdm8EpFzo9Nak cq5MsVs1yiLdRdaZAiMSOvxpOECxxcuh/Pno0VYG2GRpQcgm3Fwi30O2OzLJ7eOI cQBItHxOo3JCu1cNfy8X36SFP8prZPXTqHSRI09Z9nMDzB0KF2iTHsG+doTUvCIj rTcwLehnYCeivpFiHvWmCiue451NeWf43PFH8mWwSdvhSJI6KMsO2AmoiqQh3VBv WNIrGWIrzvBNCWrDp8DBY7wq8CgNU56mKCjT0Es17AA7mlcc0qL7zaib0DMJodiD rarDI5LTPf8ifIU+kkWKEAuSxiBnnXvRmdw/X9G7KuHJ/43G3Lpu55srP6jsKA2m 0fRZDZkytVB5a2yijWm76QDk1+ZP8n1rYVKqivlYZM6vwVVVp3E67vB42PeiNwnh n6nkJcD6enyN6Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGADCCA+igAwIBAgIRAPbOoBhRRn9q0a7gMWh80OQwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDczMDAwMDAwMFoXDTI5MDcyOTIzNTk1OVowfzELMAkGA1UEBhMCSVQxDTALBgNV BAgTBFJvbWExEDAOBgNVBAcTB1BvbWV6aWExJTAjBgNVBAoTHFRJIFRydXN0IFRl Y2hub2xvZ2llcyBTLlIuTC4xKDAmBgNVBAMTH1RJIFRydXN0IFRlY2hub2xvZ2ll cyBDbGllbnQgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCKylM2 NjH1L1H5KKRNLsR9I/JOFKK8zz7FoNojewte3Jbi2DmzXHDKWeac76AqmUoIO2x1 yAK77jmdVH7WL/g/EqkX2bwwKNc/CqEsEBV69xAYBn9DtiKccCkfW9LlhPbgEt6K /9P07XILsJfbQR7LzE+TEzuPj44QIic+ogn55WoXXvAZ4iAMeno+U2koaVxPyi79 BBr8YMgRUq16i4tE+pNAu2gm2ueEq+LO92C7IEGXvzNC8keZnwCwrkp56DFFPAL7 t2fNrnBXBY2MA4rNvug+N0EjFjCk824HWu3XyVOGRGulaav6LIFTMmljEMbrpc18 zcSOTBBzqjEsiqKPAgMBAAGjggFrMIIBZzAfBgNVHSMEGDAWgBRTeb9aqitKz1SA 4dibwJ3ysgNmyzAdBgNVHQ4EFgQURnJ0x3lPfQtVjILfZDlOa1I3ce8wDgYDVR0P AQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUH AwIGCCsGAQUFBwMEMBgGA1UdIAQRMA8wDQYLKwYBBAGyMQECAkkwUAYDVR0fBEkw RzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNl cnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEF BQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRy dXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29t MA0GCSqGSIb3DQEBDAUAA4ICAQByyNVZbNyFWDGhjaFOVUdJj0FhGGQmFI47tRWi pzuH/Xcx9I9zv73FklJtQXJ2OerE3DkephxxUxHt6T0I+h+cnHehD2abMT8qII9T 20b2mVAiR1r1GSUwBuOlISGWbCjo6obFZ2a/38UmD3tVm8yLa6CJZBM99LXSb6sU UUrWbpOkRVExs4x0J/4pX3GNAHDS7n7FXjX+qAvaiAIgokr3DnWTfMI/PPzWEIQ2 skIUSy0Wjuz3ia3fh6HZGoObjwXQwfT9rHmPQ6S/9CmCeOibT2RYx1HRHUFLS4kD kTDuRdnWd/36MoCiNJ0aZkjs8f25E3fP4AzQ7oY7csumdRWWK7g+aKLQdQHEZLA3 8CbTJlgQNylLtxV71saNu0A66/+F1JQWQeFgGoLqDHjdebvtx4xG5W3o9kFZki8N /n2FFuTfHjqYugCkKUzPJwpArW9AgLM/8R74y7CeQVrmZnMD9FRuDkb0VTtjL1Mu DGD9V7vBAEZ3+yOrWh0zwkpLzdM91zVps99+fj9+jdCtSC47JEnOOHsCWNCoHk6D qnUbLYE19FnltSyguXBYDy+IypErebIffHYTic1bcyS45S6tY17h15Npz3TWQIY1 Fn8qyR7M3ScltpoexG4sIiLYLMFDWU/jR3vzG5+2uE7DLHz0C84zxzaKtO+gnYt0 Ud/6Pg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGbjCCBFagAwIBAgIQIK89Sa6AQyfcsl+9j9wM3DANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkw NzMwMDAwMDAwWhcNMjkwNzI5MjM1OTU5WjCBzTELMAkGA1UEBhMCSVQxDTALBgNV BAgTBFJvbWExEDAOBgNVBAcTB1BvbWV6aWExMTAvBgNVBAoTKFRlbGVjb20gSXRh bGlhIFRydXN0IFRlY2hub2xvZ2llcyBTLlIuTC4xRDBCBgNVBAsTO0NvbnRyb2xs ZWQgYnkgU2VjdGlnbyBleGNsdXNpdmVseSBmb3IgVEkgVHJ1c3QgVGVjaG5vbG9n aWVzMSQwIgYDVQQDExtUSSBUcnVzdCBUZWNobm9sb2dpZXMgRVYgQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc9GUNkbWTns4Zyf6ngSEbcOlG6IK7 7W0DU3j1Z+Zz37BBBpvs8lbGnjzSEUcPBNCT3wDbqjJQllGQchOe1req1TwVpP4m tFJ9DbrnONXTORz48XyBHIe/Y+Vb5oP2Ea8rozwcxsbmG7gMPb649Z8N/Ptswomw axOwDtVYPQyIe810t33rhif39npAZdl48bM2EutkD4K6X9XokXELUXuMn3gD2V/6 OOoehJ27CV6rL736xJmbBKHjXbhqr/yk27qaC4m8XGFp8GCtzFo+d/mxuGavKq4x e5ISbKBYAdR2G5Gpr+kuw2WGSTcaBDn3uyeHKPI0goaQoCMECyqTGZeVAgMBAAGj ggGLMIIBhzAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4E FgQUqIvDFcbat7O3PMH5JoaizPZ3Vi4wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1Ud IAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29t L0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20v VVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUH AQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3Nw LnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAHJ3tjJyMAJR/xNlNFP6 9bOcxT+cfBRyfFiTtwYoftsyLR+yqQG9RQnh6bt62JS9Jf1qZrDHeGZPBTuwdtp/ 2VWhblqWKsfGPgGoopkBSaLu1jeRbplc3qjqEGakzPVQ5RIAQqwzn0JVtzEzeLLo 4I7aFnKkBI2tVV1yIn683adAb26HR2Pt2kVZg8tjvUbh+VtQtTaytM6RrFa0+k9G 639zNj/lRy+F5iQx/BIKMKlXnOtLwORYrpVmX0jjNLc32D/FTuPfw/cBNWY4Tu5M eRgu4j7QIjCIZoNDCmB6blqL3M5ZO4dOlA9zySIJlfKCOPKsGEMf3Tt2uSaOZHGn 93rZn7sYyACuijWw/M7OPj7SlUutBDslwqMnLDjWp8K3hpNnxXkOsT3WgZYiIUb8 5jYXUputfwy3LWR5x7SiNg6RbNJAb4mQtXs2DMoK8FFjCp0G39jWH8/uZwtbaxLc QHJEPi8KdMEAJ7wWEtzjek3a0WXE9j/5uYVWBdLVL1afxjyB5M7cWyJur/MFYSuM SmFYenRKujOnhG3pM1g7ZasMyVNwg8SKwsleUOV29VsyP0x29rA7IK7XbJXWz4gt e2EsBcWAlpo55b3GoJaDbgB8OtpZTGt49SSDb15JROlTuEhlwIkOtOuQkKSEpg4e ZEwaYSjGTFZTc7tzBu+utl8i -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGBjCCA+6gAwIBAgIRALMcXS7T8KrJaCn0VoiLO44wDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MDczMDAwMDAwMFoXDTI5MDcyOTIzNTk1OVowezELMAkGA1UEBhMCSVQxDTALBgNV BAgTBFJvbWExEDAOBgNVBAcTB1BvbWV6aWExJTAjBgNVBAoTHFRJIFRydXN0IFRl Y2hub2xvZ2llcyBTLlIuTC4xJDAiBgNVBAMTG1RJIFRydXN0IFRlY2hub2xvZ2ll cyBEViBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKRYvlj4gqxr SMQPfD5tXRBiK9tifjCoeFZ6BnPwT+G6XthhxODxX1ZVrqXjREjtef6uQc1K9ao/ gXJ5jA4soV72lRLvxyVZ9uHcw83WZft+6oqpQaSOdo8Bvag3HEegoSb3zElSmPhv NArENCdK6uiHmXvOW6uzPPdXG4uMeqyTdZVlR1u27UVJ5xB2Um6ryNfHqAA4eN22 djopHRIeVAu5sQoeAurLTBOfq4QEpecDm0xa+ySe642X+HVNzQGye7diI0sD/ngf Ir9x7h1HxyqxC24rXT4XZlK+ZA/d5bpuvoMQMDEV4CKo6T9J7oo+Oq3u+HFwBo94 BClLlXBc9aMCAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvA nfKyA2bLMB0GA1UdDgQWBBTWUeJ5s8ZXr95WY+CywoVtRjQVpjAOBgNVHQ8BAf8E BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICSTAIBgZngQwBAgEwUAYD VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/ BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT QUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1 c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQA0MXhgkf6J+NnG0SAwIkNrC0zv27vT IwtAkVcp3TaIIdnIT11XJ1mVmt7MwidqMC7cYXqe81zlIlVB65+NwZWuhEiM+1ce vu8MFA6xcaFHFTTFYFIsBGHw7Fgbo54rP5cIHKehyCcCxvFFdQ2tvbMVjGWMubZO 5sD0rAWb1gGkVQ8uNgwR2RJrrfllPDqbNz/PNyxAAJWtY7dpTd1duEvA8u+uJ2wk 0DHKtPX8MvmojNwL89KZMUbXE+Ecg4Dc120SWjk6tcExkkceRP91MQv9oSABGw03 mSO2F02LguHJbfrS3kP1Twx68B33SIzR7OUcP93aAU+eKjCiY+jMqfr/knaqmaY1 U5AEANMHIFLoM7SOYvQhBa0sqNAxiwIZPT2lGxN8/znPAf9wEk7zHOpsJ2Qd+Tb1 Or6F+Y0Q2SsVGCxEB+HiFG9Az/rBk0sZhMuCyvd81XYPO7aTJjf/ppwtiBxdlTJK +/hjAlzEHGZzeVDbAJ2/K1XJgxsqYpfET8qfyOrDjbCfiz4zuIy49aJuU0M8NMcQ +qBBcLfHP9K+wpAJ88ERGlFx0uPip8Trd4L2asW2K+We0S3epfCC9/zmMfi4uVQ+ HiODkiJQstTt0nS88Vuq0uYIynnu52G3ueKVtNkCb45AxT8MO2UIH8Dm5cvHV84G BTbqpLm41FxfJQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvTCCBKWgAwIBAgIQClC8/rpytrSp14MSu9+E2DANBgkqhkiG9w0BAQwFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwODA1MTIzMzQ3WhcNMjkwODA1MTIzMzQ3WjCBijELMAkGA1UE BhMCSUwxFDASBgNVBAoTC0lUc01pbmUgTFREMT8wPQYDVQQLEzZDbGFzcyAyIERp Z2lDZXJ0IFBLSSBQbGF0Zm9ybSBJbmRpdmlkdWFsIFN1YnNjcmliZXIgQ0ExJDAi BgNVBAMTG0lUc01pbmUgRG9jdW1lbnQgU2lnbmluZyBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBANhCW8bztQiJLYpG8lLlcLXN0QjHEXTBFu0rCku7 aIMcGifoXeP1aM318hG5RxfN8l3nrDRf/mF/LpD+DiPPZ328KAbwprBdmZXcucZ+ 1cUuBTdC7cfGRYcaUEaKszWOfggi7nwfQB4ZDbQNatUCc/WY53pP1iiSn8WG0O9o hjaP4v5xd+OvKENi/RwRA21NXaZrArtKIxUij6Ye/U5yXq4N5U6mGO2UTKmR4zzY HGO/kOAbAw/ikuA9fqqjt2BRTUwpL0kXAKcyStfihtV10/UQSkBfNhlGdGez32Q2 hFtxSWWbDwtaOq34Ei3iTzT9GHPy3QBdrMN8pymgaOwXpd0CAwEAAaOCAkEwggI9 MB0GA1UdDgQWBBSeisNMzCQGVOU9/b826k0BVILoWDAfBgNVHSMEGDAWgBTOw0q5 mVXyuNtgv6l+vVa1lzan1jAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYB BQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEE KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgYEGA1Ud HwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz c3VyZWRJRFJvb3RHMi5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwgdMGA1UdIASByzCByDCBxQYJ YIZIAYb9bAUCMIG3MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j b20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNh dGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBB Z3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5kaWdpY2VydC5jb20vcnBh LXVhMCgGA1UdEQQhMB+kHTAbMRkwFwYDVQQDExBEaWdpQ2VydFBLSS0zLTMxMA0G CSqGSIb3DQEBDAUAA4IBAQC6Mgy6pQJyFT6FABhc6zBCV27hkRDzaX1e4BZzsjIN W1WXL72pGh6VLuyXS1YV236A0k6+Z1HDcebhAgVGbudpGyv0gts4JzPuaquvJNls 7IieJIyjp/Tx0d/lMbEKbs0VxAvWkaiTeVqsX2g1stcOgc5nFyGkT07RqBe789ST bOOq8KYBDMv9DDb+WveQJ5gj4hX/E4sANbIGe7One/UM32aZqD/1iiEpqs1+NgrG 4B9mVNsglVXKRfrQJonq4awsfpXu9D+8uYJMH9opCRZVMWaTheSSUqUvLySsX733 PKUXIeBSCxMhy8UOsFxLzQPHIW+msUgG1iUHV087C1ZF -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGyzCCBLOgAwIBAgIUcsmHQXZHIx0hpaHhMjTIDzP8NaUwDQYJKoZIhvcNAQEL BQAwVDELMAkGA1UEBhMCQk0xGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxKjAo BgNVBAMMIVF1b1ZhZGlzIEVudGVycHJpc2UgVHJ1c3QgQ0EgMyBHMzAeFw0xOTA4 MDYxOTMzMjlaFw0zMTA2MDYxNDQzNTlaMGQxLDAqBgNVBAMMI0JUIENsYXNzIDIg RGlnaUNlcnQgUEtJIFBsYXRmb3JtIENBMScwJQYDVQQKDB5Ccml0aXNoIFRlbGVj b21tdW5pY2F0aW9ucyBwbGMxCzAJBgNVBAYTAkdCMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA2GpGW8pDGBA9V5T8IupMxwE4inSXJERuiiGstka3Tx4v XYotysM+irPC1xnnKNj17uUJRYD95CMnJN59DsYhL30jFeH1cvNLQDidopVqFRkC PQDSPYY9Gd3ua2ecJ49GJ7XZfXIsXYNqh0DMOA9WesYCTobHZMtOXnfl5U60g2FA 5fSbAbS3lgdvA2hR+g09xUTMJp9FzIF4oAgF4HQ+fVFBWPRkKq2A1LMjB+33kmH1 VLCpnOk8cl0TyLMA8THjOx7sTkbogKh+Ml7F/oax2PxKrP/elLSOoCgX0c2Ov8H2 N0YJyUiJC20CO73GHUKPPHx5OI75oZYohP/7zXQ656Vr522v3FF4iIhiJTHvh4Ra YK/4h5hgPN3rqU/Z25QNWDUC85Vm+gbPi7u2re5BARu4keD4wfk87byZI670bi9k ndLJvJkeRG86Ygiko/iblPSi1zMb4+MmpbxlzC3iVfNwU79D66EaOouGIiPUaWn0 ZWKK5Dl/GtkcOotjAXxqbZI6EqyfhRLPGpditYZAA4YPoofBtipm5bK7pmzG/f4+ F827l6mAAFSwM5EyrCZKoaHDA33polzY9YkqPJr+/SsXRuHyrYtqTkiLGDt5swH6 8dXH0zrQFE/HBc/j0Qj6Cz2ZoNkG6O0c9cnCXjOakorFuAAGGUtUX0KfLRQLUs0C AwEAAaOCAYMwggF/MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU8BZgIpg1 iS+G/M3ZhxwNY1VtOkcwOgYIKwYBBQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRw Oi8vb2NzcC5xdW92YWRpc2dsb2JhbC5jb20wJwYDVR0RBCAwHqQcMBoxGDAWBgNV BAMMD01QS0ktNDA5Ni0xLTI1NDBPBgNVHSAESDBGMEQGCSsGAQQBvlgAAzA3MDUG CCsGAQUFBwIBFilodHRwczovL3d3dy5xdW92YWRpc2dsb2JhbC5jb20vcmVwb3Np dG9yeTAnBgNVHSUEIDAeBggrBgEFBQcDAgYIKwYBBQUHAwQGCCsGAQUFBwMIMD0G A1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwucXVvdmFkaXNnbG9iYWwuY29tL3F2 ZW50Y2EzZzMuY3JsMB0GA1UdDgQWBBTUqHQyW9PB/VLtWvdNQO4FfSVmZTAOBgNV HQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAC+FFOiiklphYtWWcSXsmcW7 x7Cmc1bSKJln3cnMdfhDp71tPJxZmlKmwodadlTZf0x01BOWRttr6bA5K088dpJe K8RRTX/RzJk8XTejpIFiBdEmCDxVO8gQ8M0PJ1sFlvqNefo2ZGOtV1SbWAHCXAYK s1ryzJ0vOb056gwCF9qAVm4Xo42LDiPlshtAMZ54cOtKJ82Ac1A++6Fr/2T2S/0v Ml9uKLpsUHHlTH5GWM0ORN9c+Lek6d6t1WcnP1SCD8snX3VahakEjEsEhE4dz3Wm ntWWr8Q42NpdTrQZbRbiAUwmw90j2DZ84WoormyQ1fVskDJCC7ppfZpP/F0Vj46F XSyVGuiLDCg77xy35B1JMFtwPjQ52EYDi6X4s4POQe3Aga6qHMTmLjV2S+CrrkMT btsOcYZa/SCE4D41FfKxh8DMKRgT/+72bmpyW7nbUEDhvxMBqz5WMtf/5IzWVGaJ aPiSydgygzOVuJzh3UPFoGQ10xpt9m7RywyATVAUw852Vlrq72sAu8P9sowntjhn r4zQkcELQL2yh2+ufPUuCudMCnIGV8KAwmKzVFSjUAElbVDfNfGHcNFbj2P51lRN HobmYzJ3+812YLTlZDdLZTY525Ifu6p8pAfVUUC3ikIqEkq7cyN8V78JBxdjD8Wq mdj8G9sjoeeF4EEEoNoL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGaDCCBFCgAwIBAgIQFu99tiLhTZqnh+g/m3eLNTANBgkqhkiG9w0BAQsFADBk MSwwKgYDVQQDDCNCVCBDbGFzcyAyIERpZ2lDZXJ0IFBLSSBQbGF0Zm9ybSBDQTEn MCUGA1UECgweQnJpdGlzaCBUZWxlY29tbXVuaWNhdGlvbnMgcGxjMQswCQYDVQQG EwJHQjAeFw0xOTA4MDgwMDAwMDBaFw0yOTA4MDcyMzU5NTlaMIGkMQswCQYDVQQG EwJQVDEsMCoGA1UEChMjRGlnaXRhbFNpZ24gLSBDZXJ0aWZpY2Fkb3JhIERpZ2l0 YWwxPzA9BgNVBAsTNkNsYXNzIDIgRGlnaUNlcnQgUEtJIFBsYXRmb3JtIEluZGl2 aWR1YWwgU3Vic2NyaWJlciBDQTEmMCQGA1UEAxMdRGlnaXRhbFNpZ24gUXVhbGlm aWVkIENBIC0gRzQwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDkqehv trINU5kMuOB0eRNyzgxd/f3COAwEyJbqsUKg4UeTjFtWR/S22GU1g9x2YkeDQr3i FSuyqRElznsA0fMBKajILKh3vHdtZ4qp2oyJ4yuikUpO7BNn58c1IqScWPY3HTZI VUkqrGWbfk5XHPn2siKoqVYmvRTFVig6EXRRExlnm8/JY04ReyumnUz07VDi5v0n iTvIokClNGQXOBiqOja8kEj+uep9uRVCOHb9CnSRcvQmPJ3MP7oN5kbiCoaNPOqx NjldFrcV6lH/6foMPNQC+p+p3RBbJ9P78yMvusdEO04rHv/nkKGH+6eMjaZKZF1k Lzbkna4dMLG+h8CG6vTy/HsJJrEHFPm7PaBAaxEnj7We/n/peIPWGo03656/sKZy MyaVQjG5aWB+EixOECpCiT0h2nkfloa4CQuSYb9fEzatH2NIwjpXbEiAtuSpkock gFEvEOjDFChJpBgf0n9yNhjrKocYa8T8rTzj0HLvZJ9WbHTbmyViNkUMX+0CAwEA AaOCAVMwggFPMBIGA1UdEwEB/wQIMAYBAf8CAQAwQwYDVR0gBDwwOjA4BgkrBgEE Ab5YAAMwKzApBggrBgEFBQcCARYdaHR0cHM6Ly93d3cudHJ1c3R3aXNlLmNvbS9j cHMwUQYDVR0fBEowSDBGoESgQoZAaHR0cDovL29uc2l0ZWNybC50cnVzdHdpc2Uu Y29tL0JUQ2xhc3MyRGlnaUNlcnRQS0lQbGF0Zm9ybUNBLmNybDAnBgNVHSUEIDAe BggrBgEFBQcDAgYIKwYBBQUHAwQGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIBBjAo BgNVHREEITAfpB0wGzEZMBcGA1UEAxMQQlRQdWJSUzMwNzJ2RjYyMTAdBgNVHQ4E FgQU1t8PehwdXyxSL9ixvtjpeR8E+X4wHwYDVR0jBBgwFoAU1Kh0MlvTwf1S7Vr3 TUDuBX0lZmUwDQYJKoZIhvcNAQELBQADggIBAD+c6pCBku90dgZLUZK6EQdDgxqF rJHnKoIhpVbwRhe68AyUvZHN6HWsvJTJnZEBBYyEKEVlEsJ65YgWF5Wmk1DvmvYx m6xrkvyHv6QQYlbx4CZCXlwcLAcbxUTi+PKLwOwj+jXii/S0UrTC9qHS9E97eQ/V oOOLcdX4PhwzIKI+mv6fa1v+bdVfVvdsvEhVBQf7E0dwZBZKwIlKvjE3tOibbW1t 9vUYcd/37iNa3bb9sczWsp5pdp7Mr3483gNOArTb77HknUvpLUTTIfiSRfJR/05k SdYZxfjbbcLINwGbxq7mw7Rcc4ng8wSbB2MFAQfXi2wK2HeD8UYafhWo5d7kbSpl 4ICPeO593dOc9Vw1vax1JoOkNsr9iSWryk8O7TujAqi1viMF3j6sZL4HArRnQff3 Df/XOaTvLaVcANn+e1e+ikiUxNKGJtySTZ6fIDZk9kXAr1umXZ00Js784L2wizTx FJvc5IWWi+NG+MmDnD3QZc6rRyGsAnuhV5EqXxwenyB5lJ1/Gf6hvxnYuwqpEYN3 L5/Lpue8+S0omLibtwEdzUvyrtl0Sq44m+KJZ30wbqxzq9F3PhW+iPdeY6EhpeIB jyap+tLO59nia73U2gi4yusJZ0lKTxfUd93HtShthxkfIryzcU7upa6c/IEXju/g /HrGQwThYjf6S/I6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhTCCAwugAwIBAgIQPLTWlkfKJt1jQIE1gZUBPzAKBggqhkjOPQQDAzB/MQsw CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAW BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNvbSBFViBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzAeFw0xOTA4MjIxNzUwNTlaFw0y OTA4MTkxNzUwNTlaMHMxCzAJBgNVBAYTAlNDMQ4wDAYDVQQIDAVNYWjDqTERMA8G A1UEBwwIVmljdG9yaWExGjAYBgNVBAoMEVNTTCBYIFkgJiBaIENvcnAuMSUwIwYD VQQDDBxTU0wgWCBZICYgWiBFViBUTFMgQ0EgRUNDIFIxMHYwEAYHKoZIzj0CAQYF K4EEACIDYgAEln291HoOA4SpNadE7bspL7HQE9Nj7yw0k0ZHx5SAbfPzAmk/Cwrc kTK7pw7W4sWwRLzWhSqrYHi6CHv081Gv4f0Nv9AF7oSuK/QZ4Gv6QfVxDU29wYeE MMNzdx8Iviejo4IBVjCCAVIwEgYDVR0TAQH/BAgwBgEB/wIBATAfBgNVHSMEGDAW gBRbyl7l3tKBqs2oLWRRttlym5fmTzB7BggrBgEFBQcBAQRvMG0wSQYIKwYBBQUH MAKGPWh0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTGNvbS1Sb290Q0Et RVYtRUNDLTM4NC1SMS5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3Nwcy5zc2wu Y29tMBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYB BQUHAwEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybHMuc3NsLmNvbS9zc2wu Y29tLUVWZWNjLVJvb3RDQS5jcmwwHQYDVR0OBBYEFHpgi6RpBncesspO95MbmWmR 18WEMA4GA1UdDwEB/wQEAwIBhjAKBggqhkjOPQQDAwNoADBlAjBOWe3TcXmp5N+h tYYEohAc1Giy2j2LgxpmuHmLkiID2D0gSM82PCSsT6+HCS5N29gCMQDj541NUp0A //4GeZyu8sj/hlB5PlJQhBud/a+76Z3k2W4no+46o/DVmk2970Wek74= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG4TCCBMmgAwIBAgIQKHpJphmDZxRIPBZGR/82CDANBgkqhkiG9w0BAQsFADCB gjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9u MRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNzA1BgNVBAMMLlNTTC5jb20gRVYg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EgUjIwHhcNMTkwODIyMTc1 MjU1WhcNMjkwODE5MTc1MjU1WjBzMQswCQYDVQQGEwJTQzEOMAwGA1UECAwFTWFo w6kxETAPBgNVBAcMCFZpY3RvcmlhMRowGAYDVQQKDBFTU0wgWCBZICYgWiBDb3Jw LjElMCMGA1UEAwwcU1NMIFggWSAmIFogRVYgVExTIENBIFJTQSBSMTCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJO/DIsVtcF9GCdqiuM44ihD85A98/hv JtV9yd5S+jxlj5OJIZq/nId5CgB3vr94WrWLXDn9sn8rpW4vldMbQogIVHQKyEJ3 VRIfRZYA9EKiHuzKWsuxr7Apg0nNDL3aV9JXCjz5diev2ulnyHv4BJNPKLx7tmhu UeZ4iypHJyzqLkN4eQnkS3cGm2fpS8zPCr3wwkH4a7YMpb6rMMdcFZrMBYUpGwcY JrrKl7Xm7x0mbE8n/j964GhqgOVNi/ohuH9k7FL9978sNTQDfjHhpyyx74bQPZN6 1vdVYPrZAIDWnJTACTeboxgcte5xHYN0CPaqSZgFaDEGgSY41GzcKkWsIvRCJPh4 By8vkFvEHygWS8K6fwJFY1t/rNRyRXcCWhAeLiWFi1kkZKBsWTtR6u4CkQkEh4O+ q8psfXBbDyWoAFquiBRiD6YLDRGQfE8cIag6OS8xYZjI8j1zTThIDQ0GLmNf5sZi NIHhbik0DO+adkK5mLjNFMOMxuH8lyUjVkdVCsk42+3sa++qHVOPYeQAL5myLrj3 UG1vfRe7TxP6fW7T1FUVMVCEK0SxFa/EtrskFrRY8hiJfgALfPJCYjKFk6rdivkJ 1UhnD+ns9uIpGHX8S3oaw5d7lg6HFaEWGdHJvZE0bq9JBLK0elf/q7486jWzzt1O 757LW0BNsbOPAgMBAAGjggFfMIIBWzASBgNVHRMBAf8ECDAGAQH/AgEBMB8GA1Ud IwQYMBaAFPlgu9Tj1TT2uPUGgCWnc9tGaaieMHwGCCsGAQUFBwEBBHAwbjBKBggr BgEFBQcwAoY+aHR0cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29tLVJv b3RDQS1FVi1SU0EtNDA5Ni1SMi5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3Nw cy5zc2wuY29tMBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAUBggrBgEFBQcD AgYIKwYBBQUHAwEwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL2NybHMuc3NsLmNv bS9TU0xjb20tUm9vdENBLUVWLVJTQS00MDk2LVIyLmNybDAdBgNVHQ4EFgQUey9x PfXRNOTvG8F0Kc9I8TTyc9kwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUA A4ICAQAt5fcYgRgPo+cqxBohstEip+nznvhl+lqMztRjiUksotxBF7+lXLBceEmD U/G1iXouSGwQPzD7h4CHvjZfRmckHidZXl9PMq8oiHUnL0VnlXc27HseCIPv7AQz Bjmp/8OALteBmXWGXbQrdZqf0WQOjWRGi9isGurCpycYgzu0NAXcxsGCqLhsENvb C14xQyPBiiWepTWTWOaGBPu2djXx4vt0DNztO+pFLdzAxS7Aa3icY8B1g4aIzijn jgHLGrq/C25mi9SsTYU6/7PjFnfUeAwMDKUUNjTuOfeZoMy0OtOCIPdXJezCcSvJ s8BrP6CQC1+bTHPF/LU1Adi185355nHH8cGeYqFc3AedwPl4vJfibgyZ3+pm+Inh KdWvtbJIvNqthMMMsr+MJXGeL8M00/XUuxiMh+d4UKcDvB8K6OeDwK0w+4MOQ3kz DjYg2H9J9xdixORs5gk3Mfh3uoVpa/M0M4fGCoygpQpgQ7Oc3U10N0LDfZ57b7zH BXFruguw53kxjuwcb9WhrG94F/df90VhKAJFIwP2oMI0IbHomeJToSIb/j5FS3fx 0evj8mzauSSkHg3x3GANp1BrUfE+5oLRR8Yn9qKeUqZQiDofKRLvn92RlC9S3a53 FRxwWvzqidy7bVSjMa+E20fdJ+UQnmfYeqArlJx8iQtHM1T+fQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG1zCCBL+gAwIBAgIQWvZzZUDx/Gn4HYHpZWV2mzANBgkqhkiG9w0BAQsFADB8 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTA4MjIxNzU0MzhaFw0y OTA4MTkxNzU0MzhaMHIxCzAJBgNVBAYTAlNDMQ4wDAYDVQQIDAVNYWjDqTERMA8G A1UEBwwIVmljdG9yaWExGjAYBgNVBAoMEVNTTCBYIFkgJiBaIENvcnAuMSQwIgYD VQQDDBtTU0wgWCBZICYgWiBTTUlNRSBDQSBSU0EgUjEwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDHEjtBZz9/b0R1dxsHgmL/HsaGgbVoc/m1CuuCxJkP No+fDDrsB8h692u1KIYlj3b0yiknaiHDUV4QPFkSzkvb4tuSu3TOzN0XyNG3LEus qn8mLNtEskIOKKiLCh1p69M6ilUWnXAgH+gvaOt2qn2dqmNxvgGdF7cizpfUnvqo Ib6WIC6tKi356h7tFoCDKPvR455ac+D+3sLSkWZJ3Ix4LYkCDhdo2xjI60hFkFRl O6Ov0C1GeYvj9DkgsbCQRM11pZj5uD8Kd4BxkQIluqmIkvPR3Bl6v+5tDY20c5Yc 1jkHNHF4SV0bC3JvpTQ23OSSxM55UBeO1bPTA0p4arMsB0I9eTD7tTUilu1nDSCA Fgy9oCuvmTTmFgdHMfm4WZZHxfXaM5fHQV8Lo5SO28I0y91zernWrQ1qS3hS1mbD LYGaPQ9Leu3lPB9bt2/AtwJGDb9NBeE67H699th1InKTgQDT7eiuLfQmKWrJh+yH lZ0L647l/974vrAYLGiwmB8d/hZMjqs4FtnNdiUImiSBXnoAqlc4CXCojCBY95v4 fD7LU3Zs2/BVpuVrDUK93xZTqmXt//yAxmZB2+y6j/ZQZuRRFP4z8YzSE11MwnVf ayrRdtiSdjuR59gY212k2h46gWh8Ira6lxSBAPPm8EyIUMXV0uizc4gi7RdLAvu8 7wIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBATAfBgNVHSMEGDAWgBTd BAkHovV6fVJTEpKV7jiAJQ2mWTCBgwYIKwYBBQUHAQEEdzB1MFEGCCsGAQUFBzAC hkVodHRwOi8vd3d3LnNzbC5jb20vcmVwb3NpdG9yeS9TU0xjb21Sb290Q2VydGlm aWNhdGlvbkF1dGhvcml0eVJTQS5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3Nw cy5zc2wuY29tMBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAUBggrBgEFBQcD AgYIKwYBBQUHAwQwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybHMuc3NsLmNv bS9zc2wuY29tLXJzYS1Sb290Q0EuY3JsMB0GA1UdDgQWBBT4gS7fm9A0gT8lGwsb oYybKmFj9jAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAG9vdR+R 5kgg8+afbU5n56WuUmT7CsOSn5FvhKdNy9XVVoUQWBbyp8oep9kGZ45Ch5I3HSqb XluDSkT1BbtRb2JO/mQUdLq1j/ZDYDUjNYy/uD6GYuenXDx4n63M23NKOEOJt7GA lvbSkRkOoEUbzpkUORReKdWCSy2SVnag4SOBFmCN9g24RarydS/1sTNFWR9gK6vL 1ZIyIPd+QJl9VMwKhyme0DLWJ8wkS/bWpt8g7P7U8YHriswbJbZAgdFtLa7bIKVc yWHi7BWfys+Hq0kd0Z4jyU2yhCe3JFjKBbb+RUiAhg59S6uIKEtmuQnYtdvEArvu uqr2sUoXFx7c6GLAtnLnL60QOHdOUodDY2DLq8pU1+8OTgKZmVUeu4DwwDxLttsJ /w/mTVzDT30wv6JOTABBPlTHv71QnDEesYWUDU+wyStODvl6Cgvd6KwTfpuPv/eO 9qtehyInvix8W7jSmG1n5rFbQmQZOi1NJo58mYAYMr3nsY4Xw/bv6UYcgrXl0II3 YbzZN4s004mYZG45zjMalcLT4ryTA8+VsCtkIOEquEXQVod4NEJkHO6jQ2X3P6xH XfTR1PDRN29FP4/Mho1kQn/6/OWNj3Mvh6xLZBzqXqF0gwoiM7Ix4l3HVqKKfm2M QIkZme3WbNafh5/ZcwOevvGN3oTdnCciesG6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDezCCAwCgAwIBAgIQPcAH56XNTxuCv3DL7xgR4jAKBggqhkjOPQQDAzB8MQsw CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAW BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzAeFw0xOTA4MjIxNzU2MTBaFw0yOTA4 MTkxNzU2MTBaMHAxCzAJBgNVBAYTAlNDMQ4wDAYDVQQIDAVNYWjDqTERMA8GA1UE BwwIVmljdG9yaWExGjAYBgNVBAoMEVNTTCBYIFkgJiBaIENvcnAuMSIwIAYDVQQD DBlTU0wgWCBZICYgWiBUTFMgQ0EgRUNDIFIxMHYwEAYHKoZIzj0CAQYFK4EEACID YgAEUFkKxdALH5VvVS7iWZv79rLQIAZDvkyNfMXeBiE+csb+/0vARptrSnEklTXa bWtzFRRn0FsOeZJBqEwyQZWeH7eSx5wKMv6yOsFWr3RTRylIvmt4lnHbop7Hf7Lc KyKyo4IBUTCCAU0wEgYDVR0TAQH/BAgwBgEB/wIBATAfBgNVHSMEGDAWgBSC0YVz MOc1BNOOApL75aTRxCHozTB4BggrBgEFBQcBAQRsMGowRgYIKwYBBQUHMAKGOmh0 dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTGNvbS1Sb290Q0EtRUNDLTM4 NC1SMS5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3Nwcy5zc2wuY29tMBEGA1Ud IAQKMAgwBgYEVR0gADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwOwYD VR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybHMuc3NsLmNvbS9zc2wuY29tLWVjYy1S b290Q0EuY3JsMB0GA1UdDgQWBBS/IgFt4rawvc5eluZy/iYAjxIx+zAOBgNVHQ8B Af8EBAMCAYYwCgYIKoZIzj0EAwMDaQAwZgIxAPhhEfH4DgzsgfO7+w1ooiVALU2y ALpG7Rtd2hteufplV4hs7H/yfmj2kZXBzPpIwAIxAMGzBpqNkZbOVqz8izwA6WfJ 0ppdv+mBa9cNkeWfCV3QntT1kw+F7Hfc6KZoqWSSBg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG1TCCBL2gAwIBAgIQKeKCeAGZ2nV6Gzfgc0Z7NTANBgkqhkiG9w0BAQsFADB8 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTA4MjIxNzU4MDJaFw0y OTA4MTkxNzU4MDJaMHAxCzAJBgNVBAYTAlNDMQ4wDAYDVQQIDAVNYWjDqTERMA8G A1UEBwwIVmljdG9yaWExGjAYBgNVBAoMEVNTTCBYIFkgJiBaIENvcnAuMSIwIAYD VQQDDBlTU0wgWCBZICYgWiBUTFMgQ0EgUlNBIFIxMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAp73icH11v+Ryv9IRAEo15dXST0shw8wEg/Fps4aZjdUC zKt0o95Tl98CXM9ShazXawrIXwPbqTKXbmza/7xIVALzhtpla2ssG7ardEFAYRgd ozXh24pLnFXF8t9IQd65dVMfu+B4irpb2dxvXnzV3RdJyKtsr9Z9WKLxtuVFO2OQ c5H0o3VDaBihsq5SEXOAyztX7p65wn87E/IoGVHT2LRz3LuFKgTqIjrY3dB2o5rq lbK3nhsmeg8iU7nUR4c51PFJ07To+ki7bKJu+gtkFAiOf2Bqp0rIUQ8BixNFNL/6 huuBAnEO2Rovo535g15SQakpWcIjMy3f+RAOuhZ19TC1LtWcLby0YLli3Q52/1do jDoAorRSsqkdwkRyMUd2Xci1QgilJnp211ognXcQKio8MQcWyEj+UWeETjrPpiJZ pflGewf2gceQOxLxRaJPQJYdE8vq8WyjCwE8WCE3Y3OcmQrR14rMP+VE4wvRprFX L3zsplDsrrFME4F78mEK/kLN3E94Sbf6OyQ/jz0N2g0o+twQH+ZWc2zBF3D1D2gj mGHgMsVnnw3dwylJKHKLofhAbLgu5t4PlG26gX/UqzHMjI0qTwZr+4ryO8E9/JPY bnBdRXQDujuGdoIa1cYiqdtWIe27Stt+atq3HrP1n35gq7J3il/5AKIt1AlsO00C AwEAAaOCAV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQEwHwYDVR0jBBgwFoAU3QQJ B6L1en1SUxKSle44gCUNplkwgYMGCCsGAQUFBwEBBHcwdTBRBggrBgEFBQcwAoZF aHR0cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29tUm9vdENlcnRpZmlj YXRpb25BdXRob3JpdHlSU0EuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMu c3NsLmNvbTARBgNVHSAECjAIMAYGBFUdIAAwHQYDVR0lBBYwFAYIKwYBBQUHAwIG CCsGAQUFBwMBMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmxzLnNzbC5jb20v c3NsLmNvbS1yc2EtUm9vdENBLmNybDAdBgNVHQ4EFgQUlVK3WHS6D4gXrL1fuCEZ a7LyQh8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDzp8APpwaF Zl/4309HDyUrY0vmzoW5TC/OrR5Xz4pchQxYKT4GQQFrSTN1uR+4ffwei1GC3MPn J3b8UUercrSGB6cZtNH92dhV6GBEBXVWUGKhFISZ9DkCVs/+0NtvsFJWNWeoWlWw 4QtWH1Ii2Pkizqbn8VAFCMHB5EPTShu8Ob61F606HGHmY51GLGiH1bVyGDEiXu69 Bm4wG0Q4Heq30IJVHqGP19BLSMgml298t89tnm+CjxWoLacmGn4EvQG/owL/HQOR l+q4WRPj3zkq1Wke0LZbbMV6rrn0uX5Q3IndWsWYJRl8ElKq12+QRlp5MYXQU8wm t6/w9WBxe9biseEGBzeCVSLtHO/WN3axz8gQi79x/Ybo+FPnp/mA6+LTInnf0Xee CUYP1l20dyIWuOlFx4hjW4P0XK7Ae6rQ/2zWIu2mCFuEfFWi2Dm9fUP5e8YWv3ay 7GTXe2sqkNETOg4aMJl3muuOSUdIeiJChVjH3x40SJYUyX2uixJNjE6Y/Ro9gQUq 61tZQ3dzG/op4UCfiQITyBBSDFrCmT7c1K3jsH/7jBSZ+joqsdM6Qc9QK6i6HUU4 9iFR+hK5U9SnSlIe1l+39HZqV7pM0VLzlfdEsu738u5v7pFl2MZMx2jPQrHYsXVU avqNcLyWUx9JTwTcDZYs+VFW4pkqO2r/UQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDmDCCAx2gAwIBAgIQdryJRFXKoqnDjF2wM0LKdDAKBggqhkjOPQQDAzBzMQsw CQYDVQQGEwJTQzEOMAwGA1UECAwFTWFow6kxETAPBgNVBAcMCFZpY3RvcmlhMRow GAYDVQQKDBFTU0wgWCBZICYgWiBDb3JwLjElMCMGA1UEAwwcU1NMIFggWSAmIFog RVYgVExTIENBIEVDQyBSMTAeFw0xOTA4MjMxNjQ1MDRaFw0yOTA4MTkxNzUwNTla MHUxCzAJBgNVBAYTAk1VMRgwFgYDVQQIDA9QbGFpbmVzIFdpbGhlbXMxDjAMBgNV BAcMBUViZW5lMRYwFAYDVQQKDA1Eb2RvIFNpZ24gTHRkMSQwIgYDVQQDDBtEb2Rv IFNpZ24gRVYgVExTIElDQSBFQ0MgUjEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT0 WtwCjq1z47UMJY2mOmm5L2sFmFoiWdmTNciVi2Mp1P20CHaBFXRscpg6GqldT/Bi +elmrtg9UArxAMHG21sYWexJV5Eb63CMgM5Sn0Bls/V6ojCe7ERYGBZQB59wSRyj ggFyMIIBbjASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFHpgi6RpBnce sspO95MbmWmR18WEMIGFBggrBgEFBQcBAQR5MHcwUwYIKwYBBQUHMAKGR2h0dHA6 Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTFhZWi1JbnRlcm1lZGlhdGUtRVYt U1NMLUVDQy0zODQtUjEuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3Ns LmNvbTARBgNVHSAECjAIMAYGBFUdIAAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG AQUFBwMBME4GA1UdHwRHMEUwQ6BBoD+GPWh0dHA6Ly9jcmxzLnNzbC5jb20vU1NM WFlaLUludGVybWVkaWF0ZS1FVi1TU0wtRUNDLTM4NC1SMS5jcmwwHQYDVR0OBBYE FCE5ZcQExVijGfhoNr/YJ+EY4GIwMA4GA1UdDwEB/wQEAwIBhjAKBggqhkjOPQQD AwNpADBmAjEA5aZhDA7hDMbRZBtXLJeaGMWpG96AXEH44OQM7MtwWXnj/4xQNtj+ KMiJH50gd7rvAjEAyt6rOLT0lPlUX0EnbEIe3/60DyDFqO3fBmgDlf64kZlYamJP 1CfNbFO7uJdTf3pi -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG6DCCBNCgAwIBAgIQPlQaAYTNj91pdis2KgzX+jANBgkqhkiG9w0BAQsFADBz MQswCQYDVQQGEwJTQzEOMAwGA1UECAwFTWFow6kxETAPBgNVBAcMCFZpY3Rvcmlh MRowGAYDVQQKDBFTU0wgWCBZICYgWiBDb3JwLjElMCMGA1UEAwwcU1NMIFggWSAm IFogRVYgVExTIENBIFJTQSBSMTAeFw0xOTA4MjMxNjQ4MzBaFw0yOTA4MTkxNzUy NTVaMHUxCzAJBgNVBAYTAk1VMRgwFgYDVQQIDA9QbGFpbmVzIFdpbGhlbXMxDjAM BgNVBAcMBUViZW5lMRYwFAYDVQQKDA1Eb2RvIFNpZ24gTHRkMSQwIgYDVQQDDBtE b2RvIFNpZ24gRVYgVExTIElDQSBSU0EgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCGI5ReQgKxf+3/jAAU9Z8+NF7BUjYm9NsFSgHaULZSluKm5SCN 2bmfBkp3rGNCx0s2ndUNQGnb3UxPMjHPTcpGt9dVxflREuI/QURHozJl6yz9b2B+ xuAVNYZGuNOnWCK3I7YZqr2awZ3DaqaFt6oGNwkOsSBaG0tIhDBp05OJCwIBTYyn GTp8hgyAWkfpEuZRpKXCuuOtb1p1hJTkGZQiRmQ747Nns9Nmu72CwP4zA4d0P0dE 2NwAD4XPaFl00LVy8M5LxMHJfhlH76WM+dX7pxrJXOef95Wy26y+eAky/FbR1cWy j4erobCa5EN2HF29HCbPm7URlxYdMPu6fS6nmyib8lRmyShJ4HuwhBVQ8vIFFunw dnk48vyriMClOU0KxyUj6oD1VH/Mo4n/O/KCSAwQFas58s6ruXLKUD/IS3f0FwER wl5318/cVuv7Sgjw8iARY/NE0mRTemxtozHwgqjKBKCNuQB0ETvC93yhF6WQ1+vp +w1yOj60ldEVRI11jp04vlnP04OGxIKOAooF0DrjpfLp7kjSP6Bx/ZSgQBy8SnDb c7oQpn5xNprA0AcNs6P/VBVZbC+NoVTf/xG96oC0dHQpyivsUcfpXsGL/Xr0dm0t djbuhEKs424JyprBRJqusX1KqrpM7e/y6ACE4xMvT7NVJfhzQzcngzUU9wIDAQAB o4IBdDCCAXAwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBR7L3E99dE0 5O8bwXQpz0jxNPJz2TCBhgYIKwYBBQUHAQEEejB4MFQGCCsGAQUFBzAChkhodHRw Oi8vd3d3LnNzbC5jb20vcmVwb3NpdG9yeS9TU0xYWVotSW50ZXJtZWRpYXRlLUVW LVNTTC1SU0EtNDA5Ni1SMS5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3Nwcy5z c2wuY29tMBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAUBggrBgEFBQcDAgYI KwYBBQUHAwEwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL2NybHMuc3NsLmNvbS9T U0xYWVotSW50ZXJtZWRpYXRlLUVWLVNTTC1SU0EtNDA5Ni1SMS5jcmwwHQYDVR0O BBYEFB+6L7iQRzAZd3c4kYBHq/NanD9UMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG 9w0BAQsFAAOCAgEAQ5HhQExzB+hd1bIDh2/wHXkc3C3F2VT/GeX5/bUB28k5fQDx VWO5bhi+P339Jowd/76zBxjD2sw5RPw7UepBAsZ1/Dt9Srbrrla0/HNoueDZgnoR Eh7MolpVc+PGFBzV0OkRXLw4BK1/Xlj3H674DJ7/Zp6csbsthdvHqx5KDcAEA8OC RV3pQwu/veQ2Hu/me5/sxPIH87181wdXZ9obkzeySjloqIBPFoHvtr+zYVZUptqh QJgYBCMP/RVEKWmMUpEnrt21YzgA6qotRequtnLtG7WIZoaf8T2/V/UqDOzo94nE y89vw5TxaJ/sQCIOPA6NFzHrJ9dCPflqOPnbQiBTNv4e1SGm9R8dBNwboKVJgT22 7t40Ygl4o9yRQbQxaHeTbhwmOse0WoSD77tppwIySdVrDl3Q81sliX173UYRgI0B kltywboe2eR0kLI2bdNHtUYqHlgNM6pV9Tye8FOFjkLpi6LeAeLCUr0eufrbBjAB E1GKWn0cM77+BpjWADA5LWE+DzTElDiW0EL994lvOkB/qHEZ+yD0AVETjWh+BRi+ v8t0TcisjXHLrLD50HgRbQyBIpHwXqwSEYPaq6wAPtKkNgieQjA6iK9MHI86TAei YUUM6vs1ucyGTxPcoNPJQfCQpEUqepRC0ESMpu+1+om1xkzUe0b9O+VdY/w= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG5DCCBMygAwIBAgIQNnfTOwg6tAYHZn3EGE7+TDANBgkqhkiG9w0BAQsFADBy MQswCQYDVQQGEwJTQzEOMAwGA1UECAwFTWFow6kxETAPBgNVBAcMCFZpY3Rvcmlh MRowGAYDVQQKDBFTU0wgWCBZICYgWiBDb3JwLjEkMCIGA1UEAwwbU1NMIFggWSAm IFogU01JTUUgQ0EgUlNBIFIxMB4XDTE5MDgyMzE2NTE0NloXDTI5MDgxOTE3NTQz OFowdDELMAkGA1UEBhMCTVUxGDAWBgNVBAgMD1BsYWluZXMgV2lsaGVtczEOMAwG A1UEBwwFRWJlbmUxFjAUBgNVBAoMDURvZG8gU2lnbiBMdGQxIzAhBgNVBAMMGkRv ZG8gU2lnbiBTTUlNRSBJQ0EgUlNBIFIxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAnAY9K76OpTgu/wjxhGuLHx39MLlxvOeqq534Q7loMTMlMGDj7Os9 j7tHcB2dUx1fnfzNW2IsJ0/zis0qPDQdjE6zpyYMuMdJJc8LWFGHvLw4Nok+aK+q TYFVlPEBVZ3PfQ4kVU29fC/q6uci0sqrZczpdlynNmMuQMhMJjmiq/rdEO4R10zj M+/jDI/ihbv1kycFIGMD7Op8kmTkPj9yvkrzQW/7/dGLvyn/k+g6ay/qotfoCihj GNfowJ4y7QUyEI9n+/7mMQ4ZHE+ysC6B1f78ZG5TnK3tNR77HQfY8vP+geuD/re2 JcQcbkhCLrrxxO2XOYFO1NsvJ1ezkc5VXMipk9PmYJ/IW+MTqVM7lD3U66+jJKVO M2K5YxePIlP3zAr8R6cF6hcorvHhR2askupiwZm/nP5Bsr2f08UqMRHJ2kUBo66p FhXu27taTt4j5nSgVdYXS6lrtPwiqxELCVVesCkTIQcrgJGDXjF616UG41F4k0yE 9Gxw46Hjqgck1XLRJRe/TfXDQmE7xwkPMc2s58cHPx9nFAKx4qrd2b/S/QGVJDtS iOGXmpt/4zuox9zV0GVtKG5/oIbexCWReRUgA1rEfKz0REQdkBs794+mDRVpNsO5 MrGaRDiKMQWd5OcTAuKR6mtLS71jxOEidg3TLbQe7PEMi1o7UlfO64kCAwEAAaOC AXIwggFuMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU+IEu35vQNIE/ JRsLG6GMmyphY/YwgYUGCCsGAQUFBwEBBHkwdzBTBggrBgEFBQcwAoZHaHR0cDov L3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMWFlaLUludGVybWVkaWF0ZS1TTUlN RS1SU0EtNDA5Ni1SMS5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3Nwcy5zc2wu Y29tMBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYB BQUHAwQwTgYDVR0fBEcwRTBDoEGgP4Y9aHR0cDovL2NybHMuc3NsLmNvbS9TU0xY WVotSW50ZXJtZWRpYXRlLVNNSU1FLVJTQS00MDk2LVIxLmNybDAdBgNVHQ4EFgQU +KRqKcUSlYfK1U6J/EcaIfN5i2owDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB CwUAA4ICAQABCusqNrQgaqhCqgrwaMpgl92zMckr6mhI5xiX2UAY8RSEteMVZYuU w9E3sSd3xU5MmSMNL+ijgFVbzfFzVWGmjRfnflHsbUOBQ8o0PBs3sdtDJ0X2lAhB vv/pJSQX9fj+BwW7WpSyEetcNShZxjBp2tRai30EeDtzEopPZyKJ8elDVlL/Bf/z +2UTgD9Rpbs8dNMiYj8HUpyzFeDMyf/ehKB4ZuzC+EsQoEnOy7BvJsOdBVNgHOdp VXXKZtnzJgQybRtcCEQTyqaoIDRCLKwqus5lcvWsIqxuQCUit1aVSqHLyIFsXxLa IyI6OfzgiD98Yh21iqVMgUFstO2p37QptCkfbyEE+VTLq+F5iNuW4msubmG+wID1 Srg9ORToMMmJodcw1NJz4lFkjUy5xFpBMgPbXgHyKwGnIYgDoJdzI6x0ycddO2xE yDqZcVUxWByDBrxCWBxwH9HwXOYmeD/eZKfeIwye+p38Qux0LJNRiXPYZYmU/e18 FzcJsLyUpIrLHCkVk9axWa97+Q7GOcHeLgbdwThC+EY/lHhdl7c23Ut79AaLrbbf 2HAzMyNmYwJGokJUihbcASXJq+aOFY3ioA6OZIr48razeczRfgZZn++J+CAKTCx2 y2CXMa7n83/8JgGo9BZdT9ATAQ5YsE1NHNklDYEn4Oiku80V014X/w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDijCCAxGgAwIBAgIQHqBhcachemjDo9LjK5YybjAKBggqhkjOPQQDAzBwMQsw CQYDVQQGEwJTQzEOMAwGA1UECAwFTWFow6kxETAPBgNVBAcMCFZpY3RvcmlhMRow GAYDVQQKDBFTU0wgWCBZICYgWiBDb3JwLjEiMCAGA1UEAwwZU1NMIFggWSAmIFog VExTIENBIEVDQyBSMTAeFw0xOTA4MjMxNjUzNDhaFw0yOTA4MTkxNzU2MTBaMHIx CzAJBgNVBAYTAk1VMRgwFgYDVQQIDA9QbGFpbmVzIFdpbGhlbXMxDjAMBgNVBAcM BUViZW5lMRYwFAYDVQQKDA1Eb2RvIFNpZ24gTHRkMSEwHwYDVQQDDBhEb2RvIFNp Z24gVExTIElDQSBFQ0MgUjEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATQlO+0Gm7H epsjUfCZUUAcKnqjQlkRCbBLRkHrsYEQCVoKcGPow6oMVxxacjv3a3QbfmMwOv6y NSPYzrdYT8xVVX10eqSgoifOF+Dc35eXCERfPeiFyI62fe/ohRdnG5KjggFsMIIB aDASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFL8iAW3itrC9zl6W5nL+ JgCPEjH7MIGCBggrBgEFBQcBAQR2MHQwUAYIKwYBBQUHMAKGRGh0dHA6Ly93d3cu c3NsLmNvbS9yZXBvc2l0b3J5L1NTTFhZWi1JbnRlcm1lZGlhdGUtU1NMLUVDQy0z ODQtUjEuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTARBgNV HSAECjAIMAYGBFUdIAAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMEsG A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmxzLnNzbC5jb20vU1NMWFlaLUludGVy bWVkaWF0ZS1TU0wtRUNDLTM4NC1SMS5jcmwwHQYDVR0OBBYEFC9xQzyNSj5okcfK rSxHcI72jtAHMA4GA1UdDwEB/wQEAwIBhjAKBggqhkjOPQQDAwNnADBkAjBhKtmQ 55sO+b2BlhtKpg4UEtKOC5u/AXIjaWml0X1x21RX1C7SbKy/8T2nhBOdYTgCMBAM j9NCW6aEPI6ohyXgyg7Tij2bXyPEzyO4bRYBigYfvvMfa5G7TKcpUJ7rnUEnkw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG3DCCBMSgAwIBAgIQENxpdkmEj5PYSRkDGI+BezANBgkqhkiG9w0BAQsFADBw MQswCQYDVQQGEwJTQzEOMAwGA1UECAwFTWFow6kxETAPBgNVBAcMCFZpY3Rvcmlh MRowGAYDVQQKDBFTU0wgWCBZICYgWiBDb3JwLjEiMCAGA1UEAwwZU1NMIFggWSAm IFogVExTIENBIFJTQSBSMTAeFw0xOTA4MjMxNjU2MzFaFw0yOTA4MTkxNzU4MDJa MHIxCzAJBgNVBAYTAk1VMRgwFgYDVQQIDA9QbGFpbmVzIFdpbGhlbXMxDjAMBgNV BAcMBUViZW5lMRYwFAYDVQQKDA1Eb2RvIFNpZ24gTHRkMSEwHwYDVQQDDBhEb2Rv IFNpZ24gVExTIElDQSBSU0EgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQCJTB1raY2E4uFRGRjv8+jrLV3iuMxWoskHnn/MeZW+pdX0nuDgObYUgLiH 3okw2zRl6V8aDdUsTmMYEvHcsxNgPaHVZTTuNSuzPndFLO1DPlLn41ZI4/wcFf47 mPGaHKvQTYKArP2eWbEsTO/4SW/neVF1FsVrHLH3sgWBs23DT3UccheIdGm/XPG9 gahsi751qquuntKhDqOgMu+OYbODi8MFqzRuXvvn081HQSJzbtxQ72JHwzeWvKtI 8qpDezwWJAHnmQPVY4HO3IMXpW6S+PcDUlH5YNJaxZqKLoCQAKQpp14cQRzgz064 DK2hjwKjoQA+luPD3IH8IuGDL4nU+eAGopySZPR81YbAm7qCsjmf7+T9F4dafmG0 AQmFbRS+fJgXPJsMfMQRiD1bKGiwoY+0hC3htfFlldO0fTz+q+1aTlb7IfCC0fXT bZyxqPbj1V8lyyPH4OQunKglJ4qetjHoFqghIbfMnTNguGb1uH5eEua4gs4TjOdi PM5qzQSlkCE/DDJtFcKs6DEVGPDMf921CfJtT0CvMQK1UnzxiLvSwPwhaObqomwE A5fHz/U1RsVu8MMtFP1baAzxX+SqbqsQNuI5QLz+C9z2800+qlqONfPZKi6aaR8L HrXSiBPpzZJB3c/9DmA7mkwNTItKepfeiX1NIP5d6SFXdGfmHQIDAQABo4IBbjCC AWowEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSVUrdYdLoPiBesvV+4 IRlrsvJCHzCBgwYIKwYBBQUHAQEEdzB1MFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 LnNzbC5jb20vcmVwb3NpdG9yeS9TU0xYWVotSW50ZXJtZWRpYXRlLVNTTC1SU0Et NDA5Ni1SMS5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3Nwcy5zc2wuY29tMBEG A1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEw TAYDVR0fBEUwQzBBoD+gPYY7aHR0cDovL2NybHMuc3NsLmNvbS9TU0xYWVotSW50 ZXJtZWRpYXRlLVNTTC1SU0EtNDA5Ni1SMS5jcmwwHQYDVR0OBBYEFPpzVVzum19m UXtHEqUiJlCeFv7vMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEA mKD5+iBvviSgA+AACz+9qcY7elrEXq4msuAp2emcDm9GXvnOajj6jZ6EI7c+nnXt kL7SDHBpwgz/q5MZT6rTg0juXfBgP+dgUvSy5x8hbruDPTsIa7Slb7Ph9hFie9Fx fGpdO/q4tco3jDIAEl7/WKtWIkhGvW6J/9weQPdNtfXYPQ05/k0oOu4pNywfPFao +fUutj4HZbvAewGoTxSL4pSL52x8ahq41LBCgoRjuJppVo6fBGDwVGu+ZCFTfu3q Uv2f2KHsXIJUbU9e9DGcHRDPP4Bb/b4buTwVpo6E1S1p59V1MzeZt3n+RbdRNTmm 5QDhPxtgqIaiignWmub7gG4heAwMCyxPMt8sLdxp4Yoj5YKhDm26zRgmouG0PTv5 eakByC6+qGhi6ysGwRO5xBO/ROWQsGaHBagyKzsNRbclKQUXAR/Wi5OHbJOAZzP6 Xpo1CKOBRBPwU+72P7N5KmGA53T4TfGgw8Dxch7PYndu6wmA23syKt+YgL3hv6LI uiB+DTPMOfAkhPHRfW+YUTxSfLancutHXlD8H18OIMncqaJ0iL7+TihntX0YJz6/ VRI6uRwGgawfQmeO9Yoi0/mE8FjaA+NF5/lOksBPjtwX76b7G1zyu6j1XfI6kt8n OVWivmRvu2HCAhYl6vLEn8ykekrKl2SFCVnAZnONH4Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGpTCCBI2gAwIBAgIPAW0aTZSVG6MpSgwm0GJQMA0GCSqGSIb3DQEBCwUAMEQx CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xOTA5MTAwODMwNDFaFw00MzExMjkxMTU1 NTRaMFAxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEl MCMGA1UEAwwcVGVsaWEgRG9jdW1lbnQgU2lnbmluZyBDQSB2MzCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAM44Pcw/C+8y524K1KID6MyFIGZXSiDGg9HJ PeVusVlIBkxiQHb5DlL+oly8J5jLehYawMR9GXREXh6NY+et8ak5E04BRku3t66Y v5ato7CLdPfKuHfpK1cu5ZHjETt8K9Dq4bpYIq4597MBpO+EuVSmuDM/VdFz3WTw xuqyJ/mwQZvtZRGQJClLsf9oZTygFEsZ9rXAsQZGJm8K5jQRtIfGmobXP0V/Arud lkKJvW9+QjQmZC7tuHlBOPCRJeP3j1EVda0omlKEAR+D08muv/5AD3Jr+oZ6BMH0 FeOy0oEhEX8YigTEXM/Fx/NHc8C8OqIBDJYEN9Oo+Oe/sHCsU+NdGYETkeqtB3GH OlXSCIvdyzKuHeTNnWt7rfANiiJc3kBvfy8jJsEl4fKs2mGznBtWUmVXMt0w6NI2 Hyj1VBiC080pKr+7s45tgVtys/W4ZgSTVKUO7C632AJ0w8XqQM7YJx2/CRDWnv07 IjfkpcKL3U1BWKxt5u2MemzZBj8b7tYBOKu18JBDtOW2mB9meJCDi0AJyexkz1/I 8rgQnjrmoU403+s/TklHWgcsuGSBM7Z6bA/CQSGAKrd41sqXrFOaUTY42D73FWlV maNaAViGL5LyuZ2wa1gsZdUAQ95VmF6sNYbUpDTghq83xInp7giTy4CakuBfUVQR opOdRspxAgMBAAGjggGGMIIBgjAfBgNVHSMEGDAWgBRyrOQzeapFh/b9rB2e1scv htgkOTAdBgNVHQ4EFgQUNhcQjp6GnyZ/1XVC+tN7wpBZ3lQwDgYDVR0PAQH/BAQD AgEGMEQGA1UdIAQ9MDswOQYMKwYBBAGCDwIDAQEUMCkwJwYIKwYBBQUHAgEWG2h0 dHBzOi8vY3BzLnRydXN0LnRlbGlhLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMEEG A1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9odHRwY3JsLnRydXN0LnRlbGlhLmNvbS90 ZWxpYXJvb3RjYXYyLmNybDAgBgNVHSUEGTAXBgkqhkiG9y8BAQUGCisGAQQBgjcK AwwwcQYIKwYBBQUHAQEEZTBjMDgGCCsGAQUFBzAChixodHRwOi8vY3BzLnRydXN0 LnRlbGlhLmNvbS90ZWxpYXJvb3RjYXYyLmNlcjAnBggrBgEFBQcwAYYbaHR0cDov L29jc3AudHJ1c3QudGVsaWEuY29tMA0GCSqGSIb3DQEBCwUAA4ICAQArKLVX3/8M Ih+MSkuKrMchHvg4wpex2jSuZnRtO0H/xEQqMm6BJQgkW/6rNx/Z2+Pt2JHGXnjS yE7kcyj7051ZQCGzm3P4GaIJekBkyZCUQOqTdx8lmcGix7guXQ7bnaeLSyI/+cCG kKv2E6n1r6QN22GcGzUJDQPNK9As2wwwB2RReOofYmclw/OaCp6QY9Qb5BLWfbhm gixCm41+RpZcq82ECYpO5P4g212AP5q8eS6TrDtLHAPi5LE42m0pUXF1hWoxt5lQ DXb7luToFBh6V6eEvbG07Tse7gcX/1SeHpUyRfu0hD0kMLcUPJQQfssy0MN3/c0C ZdkpknU3TIfNdRReuz3G16AV/h4vkP3UVGz2b1qwh7x3u7eP5/rJAjv6IH4DKEIP QbPZmK0xsvVGa7QJRfDPaF2vpK8NqImGlmul+i150Za8vWUZO3hbMqzjnjCkFKqa LbHTm3Qcxi5OjZYfOyRKCsORqoUOVqxSUMho/5IGVu2KaRea9TBDamNGJTod2fbH UspE/eXKu+UGHKQZt/itRinHLZt+2QRxFIw9H0L1irO349/t0JMHyiDFWqVzENRV 7AbMq3yMZgSYO5dKCqwv+QIjSBjUpVpWhgs0mq2gcd79hTZ+9Ua+7QwcyRAW5unV 2TdDodkBldkQwuPkhMM9SF6y0ZsVvHqdHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDcjCCAvigAwIBAgIRAOfd9mwFGtjasIJizHRQhlswCgYIKoZIzj0EAwMwgYUx CzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNV BAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYDVQQD EyJDT01PRE8gRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDkyMzAw MDAwMFoXDTI5MDkyMjIzNTk1OVowXzELMAkGA1UEBhMCU0cxEjAQBgNVBAcTCVNp bmdhcG9yZTEPMA0GA1UEChMGV2ViTklDMSswKQYDVQQDEyJXZWJOSUMgRUNDIEJ1 c2luZXNzIFNlY3VyZSBTaXRlIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE SwgzCUUkIkVw4H4giDhCokjj8mjYb/KPvEaHZhf2T8B+GNbfnYzbqXTQYpU7ptq+ 3KDOsuVP3Mx0BpwMD3I5JaOCAWwwggFoMB8GA1UdIwQYMBaAFHVxpxlIGbydnepB R9+UxEh3mdN5MB0GA1UdDgQWBBR4fKgayZipkmHEn21OXXhPsO2bYTAOBgNVHQ8B Af8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICSjAIBgZngQwBAgIw TAYDVR0fBEUwQzBBoD+gPYY7aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RP RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsG CCsGAQUFBzAChi9odHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9FQ0NBZGRU cnVzdENBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29t MAoGCCqGSM49BAMDA2gAMGUCMExm7Wsd8zytcqlXtWwl2g2guSPFVc4rqNNUx6S7 waBhMZYX33rUTzdY2vloM/xuQQIxALGtE4aNbeRoyOX96W7PIAOMhS6i8bVJvfvU HqSJ8y8+em2eRoxZFO0Wh/RJz8cVzw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGazCCBFOgAwIBAgIRAKhuXfOU7lgWChRYNgaGGN0wDQYJKoZIhvcNAQEMBQAw gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDky MzAwMDAwMFoXDTI5MDkyMjIzNTk1OVowgdUxCzAJBgNVBAYTAlNHMRIwEAYDVQQH EwlTaW5nYXBvcmUxQzBBBgNVBAoTOldlYk5JQyAoV2ViIENvbW1lcmNlIENvbW11 bmljYXRpb25zIChTaW5nYXBvcmUpIFB0ZS4gTHRkLikxNTAzBgNVBAsTLENvbnRy b2xsZWQgYnkgU2VjdGlnbyBleGNsdXNpdmVseSBmb3IgV2ViTklDMTYwNAYDVQQD Ey1XZWJOSUMgUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNpdGUgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCBMZ2lvxfBjrkQW6Q2aLZc uHmkfHuDZNRgQMp0G2bSa/grhEv9pH0cB2IU9tfU8piHTa+ClyBL+vRGkauWJbLg ZVs4gsx9AtBWVf/7kjlE4jUzfN+XxxsDFq6JPN/LBSkyHKiPclftX7kDhyy9+u8c TbxSt+YN2sNtVnznjTkBREnn9gk9lHSuGSUOM7wEnk6AbC4XieFeKGQKaA4Ldj9y CKZc/nnO9F6C9ki5aYNY1ECwMiThbIaNp8OM72QfulpHNrJdNS7TKByoxzzUGLQK 4Ps6v3It4ZoZ4QTSCErOxj6GFGBuEMfNH2b+3QgeGV9CK1lIO3rojWZSbuZxrzbd AgMBAAGjggGCMIIBfjAfBgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs2TIy1DAd BgNVHQ4EFgQUPMFMp1pckwhuT7xx3NsvgNw6bfQwDgYDVR0PAQH/BAQDAgGGMBIG A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3Rp Z28uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2Nh LmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEF BQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NP TU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5j b21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBADt2L6XMH5/jUT3mYy9u3fMs iiIV1H09knFKKjX2QaQTD6HBaDRtom2hxb6m3QJJeN6F8WQJ7E8hsNnLEg4dssVe ESoLOISK4ndQNvmt0uHkUCHWljOUkoeE6YTQsL2ESCsqi2/8MgFQrwem73Vg0KxK Gl+KLRhqUS/5AMMj95sVQ9+RAEkBIqviTTh9SO2pcYuDMSsrok+k6uUBgxeoidgj uY9QrwX/U1HYL0GwLY2BpyOs/WokS8kDWAmGnt68HPs3feGE/jfiWtHxSxYOo7YK PdaY1ZkLr1qwvRo1F0oocGdofYtMMFt0cf7v9O3CH+VOlDFMWneV/MSlkg6plQEW 6WcLJ2B+WMsD6u6glz9mdqLzAXj7iQeqwSzdWLFhizfuTUo9r/0FTacU8rXJwh3t ouzEMEOpIoXktoSf0xZxdOT6/Buadf5XxFww7UF96oAdx9anzWj3plewa4Sx03Kv VysE/BfEXH7ruMDy7VQmK+vrjG9cPwXr4hzAEugmsUHYTcLpqN2NuUexKVtTLCPT WAvF3B/7js/G43m9fWOx0+YBUQLe362QDPMVMVKkqyQ0RZeu/LKK2xL3cs/BKuZV 6Q/ZHUzAiVqY25JrILk15N7JXL9rtQXJ8y4VN3v1LwSiuL51Qs98j7Xht3UMBQq+ iggOw3Yj1hY29J4L6zIL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDcDCCAvagAwIBAgIRAIjvLsnJlRQjR3kPY0twPDowCgYIKoZIzj0EAwMwgYUx CzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNV BAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYDVQQD EyJDT01PRE8gRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDkyMzAw MDAwMFoXDTI5MDkyMjIzNTk1OVowXTELMAkGA1UEBhMCU0cxEjAQBgNVBAcTCVNp bmdhcG9yZTEPMA0GA1UEChMGV2ViTklDMSkwJwYDVQQDEyBXZWJOSUMgRUNDIERv bWFpbiBTZWN1cmUgU2l0ZSBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIqm HsRVKTsFQPaSIqKqLOoC6Em6oGK2PTxCnK/f6B1S1xjlHaoMoCj+jmHptG1AiS8S E2RLsLkJTdJAIAbz6W2jggFsMIIBaDAfBgNVHSMEGDAWgBR1cacZSBm8nZ3qQUff lMRId5nTeTAdBgNVHQ4EFgQUtv/4f7o8j7wfhNJgPnpBfFnDB4kwDgYDVR0PAQH/ BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAkowCAYGZ4EMAQIBMEwG A1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET0VD Q0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA7Bggr BgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPRUNDQWRkVHJ1 c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAK BggqhkjOPQQDAwNoADBlAjEAxcFDeNb27HrIGb51OBYozmngJQ/qqaVEl5DFpWHN SCCaW5XnxAaLLKtMHl5wP1DsAjBkb+BEvhNjXW+I1HyGivkb08CaLWoteL8v74zt zk0DQL+SPzCh09YD8c0MaK4WXBY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3TCCA8WgAwIBAgIQe8CDweXQVGTPZFkOmc61wTANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwOTIz MDAwMDAwWhcNMjkwOTIyMjM1OTU5WjBfMQswCQYDVQQGEwJTRzESMBAGA1UEBxMJ U2luZ2Fwb3JlMQ8wDQYDVQQKEwZXZWJOSUMxKzApBgNVBAMTIldlYk5JQyBSU0Eg QnVzaW5lc3MgU2VjdXJlIFNpdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDS7qdc0xqeMBMWZveI7imMMdvQArd7+PNNHdLFaoDkT4ShQCXxQKGM q+TWG0LOpH/+asT+dKKLwSHb7ra/XbfSfg4UbESgq4pUfhznl03SmEyprDRRW33j uP1DIIzPxUXAsxcqRP0tl8s7UxIiq3ibYUkz3d2YT1HmcklcVQeh5QQdVUp0uxOS wB6k3lwRj42e09wDXLZQea+9tBgfo/rjrSrCFuFj2lv4g8+rZlzlA5UZNG44sRwG cjt3JEw88P75jJ4B5/THbHQooaveOnGUsujQDQIiqUwqHXdcQfk6RpyqZyE2VbyC IuX4efHx7GEIPkw2e1tTkz0/4iUt1FddAgMBAAGjggFsMIIBaDAfBgNVHSMEGDAW gBS7r34CPfqm8TyEjq3uOJjs2TIy1DAdBgNVHQ4EFgQUSYKybJvpj1NJFcTe6xHt Ca8Rz2QwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0l BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQEC AkowCAYGZ4EMAQICMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29tb2Rv Y2EuY29tL0NPTU9ET1JTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsG AQUFBwEBBGUwYzA7BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5jb20v Q09NT0RPUlNBQWRkVHJ1c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw LmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAL+lYWlucfi0D5yUnmr04 eKjG5JuQtG/pPlj22fPfjP3VJMgL04JgvpjXMME7wF75aCMTAGQAuNbhrdOPLCO5 HUUQF9vPUTv5gYarO1JSnTg6rpzaBABQN5j61++PbbB9wZmYptgKSST9XYpRw1SO 93JPn8ZwhPNWthaPGvi20a6fl70HPq6GMGaZYWZBGxGfszwGZtA9H6y+vyUyrdgv Ltaa2yeO7f1vv3XHI6iT657LWB06MQHTmG57n0Ikj552H+0mtgHVKMlknz07yIMl E8eWtd78oS7GAOioph+rl33hYISAVNEJksRjMQsDQZZ00PRhKb5V6odfHmct+K3O Mo6W64Fd791g88aPyvnzfyvg7CXJ+G3y25vs5sUOfGuVpH2sZtGTVWkYahQGiWgW V8PyGr3WNcVKqGy+b7p93V5lI4eOrmZZr0GxnYUqeLhWr9l00p5HhV0f3AwrWekX S72ifC8C3038dnR5FPHtbIf9V1LOcZvoQqXeirQ/DLpJut0oqq6gzPcBMi6Du3en SGZsFWriy0ojOkjNanx/YGQznIyy5TKiv2woyc9nYodT3XLGh61hcBwnvBMAGOgB dosdCK+hrWaATGG/FSUPR8mPSl0q9h1Jji5MW78Hx6hBEAWE+qetPWaPqDEWL/rP ONAmbF3hifrDFvxPGS/68Tg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID/jCCA4SgAwIBAgIQL/Iwi2myrWzCwkckT1fSmjAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwOTIzMDAw MDAwWhcNMjkwOTIyMjM1OTU5WjCB1TELMAkGA1UEBhMCU0cxEjAQBgNVBAcTCVNp bmdhcG9yZTFDMEEGA1UEChM6V2ViTklDIChXZWIgQ29tbWVyY2UgQ29tbXVuaWNh dGlvbnMgKFNpbmdhcG9yZSkgUHRlLiBMdGQuKTE1MDMGA1UECxMsQ29udHJvbGxl ZCBieSBTZWN0aWdvIGV4Y2x1c2l2ZWx5IGZvciBXZWJOSUMxNjA0BgNVBAMTLVdl Yk5JQyBFQ0MgRXh0ZW5kZWQgVmFsaWRhdGlvbiBTZWN1cmUgU2l0ZSBDQTBZMBMG ByqGSM49AgEGCCqGSM49AwEHA0IABJGOVMVenSkUdt7ch0h4OHAIqwC74ktgF/ho fPeBZftSC71HS2sC/mjTBsvBpn+oGW+o2EJ//RGskBtnz5u0he+jggGCMIIBfjAf BgNVHSMEGDAWgBR1cacZSBm8nZ3qQUfflMRId5nTeTAdBgNVHQ4EFgQUic6uOH4y RmMRrYSu5BpegCtY5l8wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYE VR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzBMBgNV HR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9FQ0ND ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOwYIKwYB BQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET0VDQ0FkZFRydXN0 Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wCgYI KoZIzj0EAwMDaAAwZQIxAIq2HCnhuBf6lKSiTJEQpH3dNTgXHlc+RNO8pTe0OzLe UBfP8d9LG6Ia/VYWHn2hxwIwV+9Dpkl1txkgo1iHUD2w0/gHo/efbJuMA87LcbEP 1rINu18vpx0AebuvgQsYRdQS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3DCCA8SgAwIBAgIRAIPowM/8RHJ58/JqUUDj/MswDQYJKoZIhvcNAQEMBQAw gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MDky MzAwMDAwMFoXDTI5MDkyMjIzNTk1OVowXTELMAkGA1UEBhMCU0cxEjAQBgNVBAcT CVNpbmdhcG9yZTEPMA0GA1UEChMGV2ViTklDMSkwJwYDVQQDEyBXZWJOSUMgUlNB IERvbWFpbiBTZWN1cmUgU2l0ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALmpHGa4NzTB/tBpTHovbIhi1DVUQZaC7RXrBtW5msz8gCi4YPpPPhkP WGvBPP+JRdNn85PDY3PzSCKfg+hTaQmMts8O1PE9/e0D8DHIK5TKrIRFDcDAqXAP Z0iZNVe2Pgc2DX7gWD+JMRGNBbsNszVfImcIXqFTuh75UeSdVWAlZcheLRMpJukJ SvPIRz+3MidswGNGGVodPHHVNyaojLyPPBKr+odcOFpYTV31D+Q9qlGoOC6DfYDD NTC6fQFhbzHEVc4OXk3P/Vs6JA8qf87Pg4q6BabK+jejyIXqAjTt0ySKZF1Fx0/v lTBCqWgdVFb/0nLzpPeyYapobixQoM8CAwEAAaOCAWwwggFoMB8GA1UdIwQYMBaA FLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBSUDEktfh0+D4td6c3EF5pF HSi7NTAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQIC SjAIBgZngQwBAgEwTAYDVR0fBEUwQzBBoD+gPYY7aHR0cDovL2NybC5jb21vZG9j YS5jb20vQ09NT0RPUlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYB BQUHAQEEZTBjMDsGCCsGAQUFBzAChi9odHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9D T01PRE9SU0FBZGRUcnVzdENBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au Y29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQB1Q3JA4GuS9XziGgBVRg+q dBRyK2hYfhvh49eoiYas1VgKHAKsuWPkpHkRgMgAeQ8PLRZEvMdABnVkb5YFevNw 6pz/U0IkOWhjmwkMU9Oj4+sjEECAEy3iX2tarQIcatrzWJjEk7Y6nb+mZivECxaR LcXGmNHgmujDRYvlYj1Z5QJSJju+UMnFg5EIZyWy623fRUOp/f7Y31kfDAEl0drd 942fyI+dquFTqC8vLi/XBmUlWZ0tG59pIopUA/Z9175oNX4/khG4N0/dNEGZTuEV 7VugcnGDYzjAPYgLw2a1XhSbTVfc+oqsFHlYJAl3iZ3Cw51GCcnpdqRm3rKSL7PD TR/kVEEVRXhBbdguBxbVtcyY8YZsIwiodtTRdZ4X15wtve+N4czzqxKrdedsFAyG rWu8cd7mpy5sSq9VLiRP4BuZD7pXICX1gaLqCfRf+Y1kHu3AII6T2KVkH6YYSHSm znqkfO76KEc/4CJTAF/pzZx1rwdJ/f41fPX6Sc1X/zI6lTJ76nIO2ngqGgR8WPGc EZhCgPFX2aV2A5cpKVgS4GFcGhHTQKOZMkF2kGD01+kTl6ZorDyQtYCT+2h2g+5Y tTlVTmoYbOvDouUKO4kun2Wg8sjC7xZGnWx/h8BvGFZccspnWPmjO1QEZur4J3eB wRQc9e0RYX3TBFBJurFDqg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFxTCCA62gAwIBAgIQetNp5Giwe1YACpLSeenFUTANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwOTIz MDAwMDAwWhcNMjkwOTIyMjM1OTU5WjBRMQswCQYDVQQGEwJTRzESMBAGA1UEBxMJ U2luZ2Fwb3JlMQ8wDQYDVQQKEwZXZWJOSUMxHTAbBgNVBAMTFFdlYk5JQyBBc3N1 cmVkIElEIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhNnL3Gju eEvgrB0ECDR+93uHyP58vcrPxEqklsl92S7dHTJCxjIrQuVb8EVfc+oZvuSOcAHH jPTcJMIHRWL4+NuY2D/TZIJWF97lilOO5q0+xqv8uah1br3g1ZygYYIRlBplwdeR 6EKiZ1sph3c44kCzXFth8gOiiq/mAozuFyyIuvbNBOiedm1f2J54CuVra5wCQ1NT gKFpSbwuTU68WGzP1WoBX0rbAESaxQwupOM9fD0glCYZ6gw0aw4T4E8eovWwNX7u klJU4v9kOI7Y5jn2DJ0a3LQziJ817mM6fm5oOZxapd+T0qhCnQUaY0i6vJlJK2iT Xea4FS/fOT5kmwIDAQABo4IBYjCCAV4wHwYDVR0jBBgwFoAUu69+Aj36pvE8hI6t 7jiY7NkyMtQwHQYDVR0OBBYEFEedTRnEL7751fkpCf0WsvxXeKXyMA4GA1UdDwEB /wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMC BggrBgEFBQcDBDAYBgNVHSAEETAPMA0GCysGAQQBsjEBAgJKMEwGA1UdHwRFMEMw QaA/oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JTQUNlcnRpZmlj YXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA7BggrBgEFBQcwAoYv aHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQWRkVHJ1c3RDQS5jcnQw JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0B AQwFAAOCAgEAGLq9syLRmGltU6GPeWbfSgU8yIquNHgIRSQwSYwgwS7bG5C9xiLt Uzp/T5XFQqNNwm5dLpGfo95tG4qk82KWibd+fbgHJyu6oMVs7gYzjWpW1foiIbZC 5GaS/PVctNyk0RAxsOx6blz+f6pdQnKDmixNWE5l4jRzCxdLFSbCzK7/nKhvgR1+ JFIAMaSci0bHrUolqnLar8z5aWvqeoyoeGxhXJ2/5nfMRQWNS+RI74PDw91ekRQz 7gb5iQ/FQltJRYVcRJbex/zMSg+HyF5XrnIENVQXXVPpID/BzkFd6gbIGMVXT/yx 5vmoLqEVa0qj5BEe9eI/KbRaEv0f3dbaCAeINteq96KDjxJX9sBPBBtYMXZZW4Fx HVZHRQHjOkNUvoa3123/t9R21hq8UVAtyLoJoJzguQVwmqtkQqN9N/IzyG+2cTb1 DLlFdLIM6U61JKJK7b+aCeinNyNqHmrDQB1Xb+JBbytTLWOTM2uS5pdCkXcnDhUL vc24uAKwzxTE0Kx17Rx1z6NmfWMO96L6Qs4Pjm9aDFV8e/LwRsQN4BphPjeMLAk5 zXlBnvX0okIPIENuxiYDyapH43U4xsgDublndmWhgQXNGX+IJbyFzJDyDZIEpO0H 2JMzoA6Shmgsh9hrSvlLK9iMIsmiavIZhmDgSIDVwMHVHH7wk7fyHDw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvjCCBKagAwIBAgIQAkpFkjTIh3XYqhmyjtBMVDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwOTIzMTIyMjI1WhcNMjkwOTIzMTIyMjI1WjCBizELMAkGA1UE BhMCVVMxGjAYBgNVBAoTEUZlZEV4IENvcnBvcmF0aW9uMT8wPQYDVQQLEzZDbGFz cyAyIERpZ2lDZXJ0IFBLSSBQbGF0Zm9ybSBJbmRpdmlkdWFsIFN1YnNjcmliZXIg Q0ExHzAdBgNVBAMTFkZlZEV4IFB1YmxpYyBPbmxpbmUgQ0EwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQC/Mv8Ve/0st75deBgVMifjz1O1Bv8hyx4LjYav Wi/2u0xKBzo9qRHy5rOhb9vFXKkS2EuqBuErr9HuN0TJ6Z0K15MZg6RQU86aBWOk SljVflFfkzuJGbz2ezIBvIasmZ/d71gLHdowuoi4htlqs+Ie/PynEQatP+LaV5WA QK0HMUPEpBkdzxrm+g+lQZCNS8rSPTPhzCQHjBoMlfKWFgsgFZLQ6N/fS2YJvDzq n6zjiYHT/nTeO+7rpeXfYnjghopzqJg/0CTiGR/qmDWQJGLm93Ysumz3ZgXOzXUn OEAikYoTYvlIstauzOYBlgThUhNfzwwxJzayk67PxDvLzPXHAgMBAAGjggJBMIIC PTAdBgNVHQ4EFgQUn72Xk7IYiNgHihALbNm0CvYsUB8wHwYDVR0jBBgwFoAUzsNK uZlV8rjbYL+pfr1WtZc2p9YwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsG AQUFBwMCBggrBgEFBQcDBDASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEB BCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMIGBBgNV HR8EejB4MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRB c3N1cmVkSURSb290RzIuY3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5j b20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMIHTBgNVHSAEgcswgcgwgcUG CWCGSAGG/WwFAjCBtzAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu Y29tL0NQUzCBigYIKwYBBQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRpZmlj YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkg QWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL3Jw YS11YTAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQRGlnaUNlcnRQS0ktMy00NDAN BgkqhkiG9w0BAQsFAAOCAQEAopE4NGFAqlqMJqMy7IY3rRgphR60KMixmGKf/Tzh JJYaIuZKowHfhq+GCa+PeIxbJG9JMsHWvZYWGTzlb8keOIc33tctRuZsgIfGS20W 1LcnMFJJdbKwiTYml1UaASEc8WX9q0LWdDLPThlydApCyX/o8A5lt+pw+RGDA1Lr niIKO3JOeheQIxG2al7qMUaz8+BCzq9QkbEAzIu3xhFhv68OHortR02NilP7gscl i479Vo3i7JGRcMI6HWB+OeZu1/XnpYFHeuu/JPKprpO8h1vptzB46qsT6SgNu25W T7VLR++j+3QIF2iF4Kh/herxh4KnFiwLO5UTCZRual+WGA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzDCCBLSgAwIBAgIQDupGQ4unmskENRwmlEWcUTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwOTIzMTIyNDE4WhcNMjkwOTIzMTIyNDE4WjCBmTELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMT8wPQYDVQQLEzZD bGFzcyAyIERpZ2lDZXJ0IFBLSSBQbGF0Zm9ybSBJbmRpdmlkdWFsIFN1YnNjcmli ZXIgQ0ExKjAoBgNVBAMTIVN5bWFudGVjIENsYXNzIDIgRW1wbG95ZWUgQ0EgLSBH NDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMxx3whpFdnm9mAQ4Fsr bcbpcE9A4mhoOxab+ixvyo6+yHsq3qq05yrdFO77EGxckZo2uOLrt7gdw0V13azw rNcrJNBTFbVqXzWCjAdpZa2sa2Ed9b3kWR1RtmW0Wvsi4GcIjhbokfDx2/UsdHwc b8Qxw90gTMxwp4bDqwgjlEfigbq/Ocr/+DT4gjfGwhLrezfAOEn2by0KlUy7KGTO B/YW8ibqfrsvJGqlxZ+iHt7rHLcQIFichnzQwgAhcci1MH7sv3m1xeYovIGIUw1c /zErqemBKcvbwSUVa2CFDU04aKKGKPqmM0S8s6QpzJGG+u6Ky2c0Gyryfu0dRKtu s2UCAwEAAaOCAkEwggI9MB0GA1UdDgQWBBRpdZ9OVkK5DOOslAfX3SBDP/uozTAf BgNVHSMEGDAWgBTOw0q5mVXyuNtgv6l+vVa1lzan1jAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYBAf8C AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp Y2VydC5jb20wgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0 LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwOqA4oDaGNGh0dHA6Ly9j cmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwgdMG A1UdIASByzCByDCBxQYJYIZIAYb9bAUCMIG3MCgGCCsGAQUFBwIBFhxodHRwczov L3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9m IHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUg UmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5k aWdpY2VydC5jb20vcnBhLXVhMCgGA1UdEQQhMB+kHTAbMRkwFwYDVQQDExBEaWdp Q2VydFBLSS0zLTUzMA0GCSqGSIb3DQEBCwUAA4IBAQCasgCZfEwQcB/KbGF61k1h ThX6cjQBbBFAOvywuS4EJejVmecZV0nCYgmkxDXE617u/QM9qvF8GGU9XsVaqNiS pFruHqlVDnE14Dl3VIyrQbzX1x6L2pup8M/yInZyIAaKIn4ngtkQ6N98u3uPGh9K 5Lg1q0GbkFJUDWpZBhnySwC7YzB751nbXPIN5xZhZXpCWgVFLVbwzPyNKFhgSKH+ sdqJEzclGLx+5f8GlR4M1mOMGK7N5nuj6EMW4sQ9NBI1rzMqAtDHY8pdscDcM23B IHNnnPhEVaashis+HE2k/hZt2DbwhC2VT1yduqEYxUiqFv3uqyqVoT0qC40jUjbZ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCBMigAwIBAgIQBUPpDSCWP5x9VLwJlUnkqjANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwOTIzMTIyNDIyWhcNMjkwOTIzMTIyNDIyWjCBrTELMAkGA1UE BhMCVVMxNDAyBgNVBAoTK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMg Q29ycG9yYXRpb24xPzA9BgNVBAsTNkNsYXNzIDIgRGlnaUNlcnQgUEtJIFBsYXRm b3JtIEluZGl2aWR1YWwgU3Vic2NyaWJlciBDQTEnMCUGA1UEAxMeSUJNIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5IEc0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAzVgxf4qQBwBfrSwwIxhP0ktWHX/SHveA7p/oxPd2N4IJBvCbfsMXfrfS ViQt1UQLaVjgqG8QlJnJBnMsLsFVTTcpT/1kkDmi2aZQfoDQ9nn8w2l9G+pshy/x 9o1x+T4xT8xBrv6C3+gzcsPxUHcQMWggH5lu83bOiJN+w+5J3gvxRB2pbIBKDlJv 0prHnxuifRxUU+fxLPtBFcuUZscd/yIURY7vl12kct9zk82CMtKJe6G3xwmU3+ap m2QQ2v5Abh0JvKsHzT8KKbdjV+PAOlboGw2gO3QcN8af2NLReaxHWZcu2Pj4/S8z ZfCLFSrkPMJwPDGyus+KhckedxaReQIDAQABo4ICQTCCAj0wHQYDVR0OBBYEFOcG 7LN0cIZsMSRNpk331DJtYCaFMB8GA1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWX NqfWMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH AwQwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUH MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTCBgQYDVR0fBHoweDA6oDigNoY0 aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcy LmNybDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNz dXJlZElEUm9vdEcyLmNybDCB0wYDVR0gBIHLMIHIMIHFBglghkgBhv1sBQIwgbcw KAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsG AQUFBwICMH4MfEFueSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRl cyBhY2NlcHRhbmNlIG9mIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2Nh dGVkIGF0IGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwKAYDVR0RBCEw H6QdMBsxGTAXBgNVBAMTEERpZ2lDZXJ0UEtJLTMtNDgwDQYJKoZIhvcNAQELBQAD ggEBAJQkB9tihpEuaP+KP49Zl4LZ4sAEfM3T153RZQ2ebyFYyOL2cG6Vz6oT4Bkj dZ62zilQXS3Q3nO9FAaWoKFcBKUuO3UPzx/tdrw1ENLHLeadDl85kxBGhfL1lqLy EJ83qCb8CPcRRzd1xb3uEJmTMVRm1V0PurTBu5U6NMOOtW/dk64zrkNELAH/jvAS FwCGIZC+DNi96hCqYDg+8QchO9HkvoDHpcxbI7EqI+vk5LacMFCKqvd1YGaA5MjG hy6ntl6OBYKUiMaThiRnJZhHmkK9/52NYyfE4NpHZjhzqt17QTcc/Upp6l3s1tr5 D+4Lno/6dbNVim/aXfj0WCUjajs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFVDCCBDygAwIBAgIQA0dFPOGoknDYQ/5vMDnqUDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xOTA5MjMxMjI1MTNaFw0zNDA5MjMxMjI1MTNaMGYxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xJTAjBgNVBAMTHERpZ2lDZXJ0IEdsb2JhbCBDbGllbnQgQ0EgRzIwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDt6T+fxRJiR2DwV9BtBw5ZkASfiHjN gWDhJTmO79QQMvXZvy5+Q5NWIo7s0ELdBr7RoVCBhSZinHRixX4Q/oNFw+GClP0w 8G02kLbJ+q7afCrvvjlcXDCuvGaSNXM4Hd+7NRtSJAH1s95aeGWqnVS/7qHIOtnZ PBlZ40fYc1HdKPgfBvukY8V4atKczYe9dtQuCf4nXgtabW46CexjgxWikvXbXKX4 i778EAji47pWuj5822mXO6oIo/7TvnjHQPE02RoAXHSFWFDueHYsKDQzeSA1pvOy OPSIczipGzyfDCE/Yr5TAP1JSuPP3kHyAv1QgHEwvAHweDijUcW64L7hAgMBAAGj ggIBMIIB/TAdBgNVHQ4EFgQU2QoTWN1g6RtSyIte7UETGHYeaJQwHwYDVR0jBBgw FoAUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMEwGA1UdJQRF MEMGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDBAYKKwYBBAGCNxQCAgYK KwYBBAGCNwoDDAYJKoZIhvcvAQEFMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYB BQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20w QgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lD ZXJ0R2xvYmFsUm9vdEcyLmNybDCBzgYDVR0gBIHGMIHDMIHABgRVHSAAMIG3MCgG CCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEF BQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMg YWNjZXB0YW5jZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRl ZCBhdCBodHRwczovL3d3dy5kaWdpY2VydC5jb20vcnBhLXVhMA0GCSqGSIb3DQEB CwUAA4IBAQBammrjws2hExFUcT15azzFf1b7lL72zLXu+Zw/CYiTrluLEQa39VNq 1hCAlDJ0anfy4CSDwkkzDFxHV40o1L/qxZ9Gh9+NOiUt1HvZlLRruJRLLkNdqZp4 6WyLPPi4jOI1qEdQO6gH9yesIuAEP+95XIyMVUPB0X+Lk1mriy5jc9CXPjKl8zvX OfNj4l7G5bA+1VVNA1YH++ERkJ8sf4EcOe5BMJOdNYZgsuOONG+IMn6VbpDbU1rr KxgkBUT+5DrWvq+ITL+lv415hDksee1BmvhBHzrfqemv1/lo2cC3hnYGXaDbpeZy EAd8aJueE14fBzplc8lPVAzqfDixgILP -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEBDCCA4ugAwIBAgIQBQoq0cg5XPL3GFYHHjIjzDAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xOTA5MjMxMjI1MjdaFw0zNDA5MjMxMjI1MjdaMGYxCzAJBgNVBAYTAlVTMRUw EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x JTAjBgNVBAMTHERpZ2lDZXJ0IEdsb2JhbCBDbGllbnQgQ0EgRzMwdjAQBgcqhkjO PQIBBgUrgQQAIgNiAAQqB2CHin7dL0qO7Tz9PLe9oCtqFBz3RkzOSFpwzipQLZqF X8IiQGogBfaaoPPi9mWChGMKv++Qenrq6J/zAatNAocnI8AXVxTkDe9kgKwomU3Q Rd3Gj8ysYp4HUi7zxU6jggIBMIIB/TAdBgNVHQ4EFgQUSRCU+VF02fQWF3ieb9kV MLcek4gwHwYDVR0jBBgwFoAUs9tIpPmhxdiuNkHMEWNpYim8S8YwDgYDVR0PAQH/ BAQDAgGGMEwGA1UdJQRFMEMGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoD BAYKKwYBBAGCNxQCAgYKKwYBBAGCNwoDDAYJKoZIhvcvAQEFMBIGA1UdEwEB/wQI MAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5kaWdpY2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGln aWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEczLmNybDCBzgYDVR0gBIHGMIHD MIHABgRVHSAAMIG3MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j b20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNh dGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBB Z3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5kaWdpY2VydC5jb20vcnBh LXVhMAoGCCqGSM49BAMDA2cAMGQCMFvUgkhHjggl0tGE90Q+eA9AIRnfwJPA6pGj L11jr0/HRiTa5alVNZoO0epKtGKmBAIwS13OF7TV3qPChVKUITidKPx9NYzfsVJB X9PAzhh38bwxZHJdLraOWW0oKR9SoaWj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFXzCCBEegAwIBAgIQD/rh8xorQzw9muFtZDtYizANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkwOTIzMTIyNTMyWhcNMzQwOTIzMTIyNTMyWjBqMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSkwJwYDVQQDEyBEaWdpQ2VydCBBc3N1cmVkIElEIENsaWVudCBDQSBH MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOqxRa06rLwKBvrDb/qQ 8RtXfeKA9o0A42oZbLF4GYr4Xdt9JE8r3PJRIOUZD1U3mEln4S/aZoS54Q+5Ecs3 q2GGT/Z82VeAPLeGvJoT0LS5t/zXeUcbMuDFWgyj33kiesnuusnOWvpISoxN+oBH 4oo0+oUiHI65mMjMAlb93x6sabh9kKvHQvHC4x2u7wYv5+NXjnbOhJS/1NjGq+ug LMXeldFMz0O5qFIDpn3aQGU0htyJQ2SZyxEqlUrgunsrYj9wgfW7XuhAi2j0y5d9 oMT0SuVeKFFnQhTEk5B3fq+OBOW0AU2JdW1r929UtRbAr8RpLt05WI2G2RNVVlHY aU0CAwEAAaOCAgQwggIAMB0GA1UdDgQWBBSlYiBQ3LtbV5etI4814lRsqX75TjAf BgNVHSMEGDAWgBTOw0q5mVXyuNtgv6l+vVa1lzan1jAOBgNVHQ8BAf8EBAMCAYYw TAYDVR0lBEUwQwYIKwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMEBgorBgEE AYI3FAICBgorBgEEAYI3CgMMBgkqhkiG9y8BAQUwEgYDVR0TAQH/BAgwBgEB/wIB ADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2lj ZXJ0LmNvbTBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5j b20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMIHOBgNVHSAEgcYwgcMwgcAG BFUdIAAwgbcwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9D UFMwgYoGCCsGAQUFBwICMH4MfEFueSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBj b25zdGl0dXRlcyBhY2NlcHRhbmNlIG9mIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVl bWVudCBsb2NhdGVkIGF0IGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEw DQYJKoZIhvcNAQELBQADggEBAHZrbCQCo3MAIqR0kekGYrC70EAGRDRq11COufNE Xhcpv3YH6BMhUoVinPPNgfo5HPrZAFrLK/KPXYdJdgkASGsINabAfY2ljUaJwKlp IewwjS6KuGEn59MgidaAUPh6lbetIoRsLhCqCzAnX1aL99fjCMf4NMWLUC8Tqotn nrKNuw4JSjx4fcQs+U5T1bbgnyDx+8ybONuIEDvinHdKDu2VjoECzez2y/1IVTPl h57zBfjHJQFqLWzHdou8M+ucdJtr2swXII6s3nkq4pfEn7KnbzMS9quFSuyOGILc g/3qVwaHNLM5R+8nB5gPI5+u5Uh56w1i+9Ds1pjYAiTHdeU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEETCCA5agAwIBAgIQDOwH7GElSJtbxN0K7NXWITAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg RzMwHhcNMTkwOTIzMTIyNTM3WhcNMzQwOTIzMTIyNTM3WjBqMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSkwJwYDVQQDEyBEaWdpQ2VydCBBc3N1cmVkIElEIENsaWVudCBDQSBHMzB2 MBAGByqGSM49AgEGBSuBBAAiA2IABFnQ3NFrfbELIPn74kx/x6S1TgZN7WkaAmag 88BtHnXpaHSb1Z27g/Dqf49BQHFdrwLdCBd2KW/YhVaEYWa90OW5Ua7jdCLRHfD1 lISPFruSym40fb7GbFgKdRM3tkVA0KOCAgQwggIAMB0GA1UdDgQWBBQJUzoRW+50 mlqVaEsjGd7pjYnFJzAfBgNVHSMEGDAWgBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAO BgNVHQ8BAf8EBAMCAYYwTAYDVR0lBEUwQwYIKwYBBQUHAwIGCCsGAQUFBwMEBgor BgEEAYI3CgMEBgorBgEEAYI3FAICBgorBgEEAYI3CgMMBgkqhkiG9y8BAQUwEgYD VR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0 dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8v Y3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzMuY3JsMIHO BgNVHSAEgcYwgcMwgcAGBFUdIAAwgbcwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFueSB1c2Ugb2YgdGhp cyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNlIG9mIHRoZSBSZWx5 aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBzOi8vd3d3LmRpZ2lj ZXJ0LmNvbS9ycGEtdWEwCgYIKoZIzj0EAwMDaQAwZgIxAK+rHstpAe3q1HqKFtco B0n+J5fk4nF6R0zA0UaWm7i/Zk2VQMUXRetAgCp6e7q1UAIxAIliXLJpauVTwmA2 y2TVhRljFGU3ZRP8owIfNVwc/hBcdtVqtUtBFgAl8cGZi22pHg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE7jCCA9agAwIBAgIJIrmxYwzstDwuMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTkwOTI3 MDE1NDIzWhcNMjkwNTI5MDUwMDM5WjBeMQswCQYDVQQGEwJKUDEjMCEGA1UEChMa Q3liZXJ0cnVzdCBKYXBhbiBDby4sIEx0ZC4xKjAoBgNVBAMTIUN5YmVydHJ1c3Qg SmFwYW4gU3VyZVNlcnZlciBDQSBHNDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAMtunFmosT8IxBkVFP+OnkGkcVmbui+hdVBlGZhniniVluAhigm2WUxx p4X5V3B/QKJLZmeAswmzxGKXaDCzcomYxXTygNXcTLI+IMyRisEO7V1NXFHUjSEl KaY1LzCA9/emldnmRjX6B9Zt5xXK5q12WOIWkJECEwwKku77tvtKZPRKaCNCGsZ5 Hja7PBs07jLoE0rMuZLQZNQEB0W63attKGCGzEk50lDj+wQ0UlUbQk3zAEsvdE6X o1qZy9l783Va40vSx3VqhGYb4jWQrg2CrAtJcKQNSJ0m9yxJVVQDwpQQwGxHO5Em Qv1LGJExASegOXzhzqCr5yiwECfSrOsCAwEAAaOCAa4wggGqMB0GA1UdDgQWBBRi p9La3oW2kvGFvPbolZ11oPpOHzAfBgNVHSMEGDAWgBQKhal3ZQWYfECB+A+XLDjx Cuw8zzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjBJBgNVHR8E QjBAMD6gPKA6hjhodHRwOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1S b290Mi9TQ1Jvb3QyQ1JMLmNybDBSBgNVHSAESzBJMEcGCiqDCIybG2SHBQQwOTA3 BggrBgEFBQcCARYraHR0cHM6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0L1ND LVJvb3QyLzCBhQYIKwYBBQUHAQEEeTB3MDAGCCsGAQUFBzABhiRodHRwOi8vc2Ny b290Y2EyLm9jc3Auc2Vjb210cnVzdC5uZXQwQwYIKwYBBQUHMAKGN2h0dHA6Ly9y ZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJvb3QyL1NDUm9vdDJjYS5jZXIw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IB AQDFUXkuQAZKY5Pb/JvgufizJ8uZKpN++fiI8kOTgkrSriNYNjO9iEdTwVV3sW3P abr3lAdCGrJ+wgArLLUnBZ7VGM//UlDhTRe4A19c0TmV1udTSbxabwQJbN1zIGbG 3KQsumg9/70PaIkawnihx9/TxGCrJkAH5W+9pkX7OWefsahylwiPkKRkJRv2em/v rMRyb3LxRU5t84k1xQqCnMxTEWOAiWoOtatExZ38a8kn8kqiE1NEvtPOzSrVjSvD 7pH56AlvO7hzGzng60kyWnAz6O5rQ0tsFIgW9xloWTQQVcfEtzvjc8ptuP9onkbA jMRDJaqLXrIVtB7GMek7S6AO -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8TCCA9mgAwIBAgIJIrmxZIi85pX8MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTkwOTI3 MDIwNDIwWhcNMjkwNTI5MDUwMDM5WjBhMQswCQYDVQQGEwJKUDEjMCEGA1UEChMa Q3liZXJ0cnVzdCBKYXBhbiBDby4sIEx0ZC4xLTArBgNVBAMTJEN5YmVydHJ1c3Qg SmFwYW4gU3VyZVNlcnZlciBFViBDQSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBANiYyzYgvqFeBvvMTpr9WNeiuq78UMqr9XVjnuCz9DX1Q3Saa434 tn4LXE8z0xxFDioD0pNvPkQQbDVc4RyqBcdHM3NR0UlkR42d8RtrZmCO1s93cshb LAO6GH2mJhA65UjYNEs3G/meG/EM76fxhPn52cvWN0d4ISP+60sT0IqIjw+84MOQ 4Ked9xveiIsI8QTOiAOXORoSstvOuzT+a3CcmtHJHWdBz2eUPUXLqq1e+UdDiyOW fPsrjW14QRstE6Ix1oUO3kbIq8nSG6O2hHVHHSIH8YLziHsca6kr8GICsLpNEm9l jDrgVk3TcIx/hwZboIs+LCicdnrYGQN1w0cCAwEAAaOCAa4wggGqMB0GA1UdDgQW BBSCbHVdU/VFabwlLaRMieayt0GHozAfBgNVHSMEGDAWgBQKhal3ZQWYfECB+A+X LDjxCuw8zzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjBJBgNV HR8EQjBAMD6gPKA6hjhodHRwOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9T Qy1Sb290Mi9TQ1Jvb3QyQ1JMLmNybDBSBgNVHSAESzBJMEcGCiqDCIybG2SFUQEw OTA3BggrBgEFBQcCARYraHR0cHM6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0 L1NDLVJvb3QyLzCBhQYIKwYBBQUHAQEEeTB3MDAGCCsGAQUFBzABhiRodHRwOi8v c2Nyb290Y2EyLm9jc3Auc2Vjb210cnVzdC5uZXQwQwYIKwYBBQUHMAKGN2h0dHA6 Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJvb3QyL1NDUm9vdDJjYS5j ZXIwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUA A4IBAQCewKVTadoA0v+ZQuCBrFC+7KwIirXey6k2WGLu38uW9vpET/1XTtF+PbN3 HBnuUidqfu92vHaBnLv1dt6VAJsQPxcrBju9jNMFvDk34pEYXk3dGfi3Yg2YF4j8 cCYsRGq2JKNjuq05GViO//RbV6jgaiUhJ9ekyzj5jQpmggo5W74FVyqo3p15GUdC J4RHVMAn8LtNIoqd6fFZizrletoHDWbpx32A17u0Nu6rKUJGxcPKxOQnomvXyEt3 A2bXBaKZFgEz8eWXNcub5IXhhgCd+hSOqzeitkEAGlhtMKKdnoqwVon+83JI7t0w qTRHfLanusz41LYNnI1YnYO5iAEq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE7DCCA9SgAwIBAgIJIrmxZVyOaZFbMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTkwOTI3 MDIxNDA5WhcNMjkwNTI5MDUwMDM5WjBcMQswCQYDVQQGEwJKUDEjMCEGA1UEChMa Q3liZXJ0cnVzdCBKYXBhbiBDby4sIEx0ZC4xKDAmBgNVBAMTH0N5YmVydHJ1c3Qg SmFwYW4gU3VyZU1haWwgQ0EgRzQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDEm/hTq7JKziKCyicxmRpgcORiXZaGAoAsVBJNWsp8Bv/m4It/+cZqPtkr WrfGRwWL0CnF2kV2ZlMzYxp+UxAxaAFnVlUqdaqnAXTZZq/DvWhJsWx/nS8Xzfqk 9YbvMA7SEThBO/BNanHv8OBVO2a0yeeEsgFi4GLL7fKXiGZjRsN43bhnXC2rKHMA 4msS28Mtq9VjGY4g7i7hNjUD687F+Op1Lsur+Mrd8ZCcbjeVqFH7V7JG8LHNxMyc SjkgqwFjWq+4GSF3TvigYY/ESWNJU8dE4H35fOflq9sP6cxn2/dxaNB7s+gAgyd3 mvtuYxdqhZ7jRunMK/EUv7dnDRg/AgMBAAGjggGuMIIBqjAdBgNVHQ4EFgQU/Mba /set1VrOSN7P/egoxaO6jxEwHwYDVR0jBBgwFoAUCoWpd2UFmHxAgfgPlyw48Qrs PM8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwSQYDVR0fBEIw QDA+oDygOoY4aHR0cDovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0MtUm9v dDIvU0NSb290MkNSTC5jcmwwUgYDVR0gBEswSTBHBgoqgwiMmxtkhwUEMDkwNwYI KwYBBQUHAgEWK2h0dHBzOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1S b290Mi8wgYUGCCsGAQUFBwEBBHkwdzAwBggrBgEFBQcwAYYkaHR0cDovL3Njcm9v dGNhMi5vY3NwLnNlY29tdHJ1c3QubmV0MEMGCCsGAQUFBzAChjdodHRwOi8vcmVw b3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290Mi9TQ1Jvb3QyY2EuY2VyMB0G A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQsFAAOCAQEA OIOKWjUNrNgVaVrpN6xaQlT4bD01tQwQ6mU76mR9y7zMoev6E7l99gGjdtikGQle 27ExcAJpGrvElf3QEwCNDYtYl6WEx1xY+sYHJT6NX3M+uI/RWKT+iu2Qs8bSpYZx k9Z5OerHFNiSgcgB5tJnuu8x1ppfErnUcGqKOpbbeyVk5W68LCEJeEc4Pzwc659+ G+PmJmPfHljH4DdDBvySJFgCA7c/eOAtcgKbvMdjXY9BJZh/TaUKIWPNgiU+jZFh s81RITedHQsZTZE/k84avQHqfXvD4tYu3J1cJqiXbhU4Q+UUgqckXVX5Q+oTkvdI Vx9dMFTT3+ABGMfr7WgjyA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG3DCCBMSgAwIBAgIQQNs3BJZDXn31Fo709X782jANBgkqhkiG9w0BAQsFADB9 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x ETAPBgNVBAoMCFNTTCBDb3JwMTkwNwYDVQQDDDBTU0wuY29tIEVWIFNTTCBFbnRl cnByaXNlIEludGVybWVkaWF0ZSBDQSBSU0EgUjIwHhcNMTkxMDAxMTU1NTU1WhcN MjkwOTI4MTU1NTU1WjBNMQswCQYDVQQGEwJOWjEXMBUGA1UECgwOU2FmZVRvT3Bl biBMdGQxJTAjBgNVBAMMHFNhZmVUb09wZW4gRVYgVExTIElDQSBSU0EgUjEwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC8Jv4YEz+OPhuZVHk9YAI5JbIs xYVueZfQlgjL/u/Op5L3Ubn5hnsk/qnIwUDAzDyh0UPo2yvL1oZjKFQ9zVW08drb hDxlgJ/DsbP3xCIFolYVk2lLeHZDJJbldUBIYDBAFLtA55NLAv+TEmxMRf38MDFE k4L4Tz8DXWCgMll/4/uiapensGXqW3vh7T+mk5ps8ywTBTmumyAffxNpgEpxOEtw TBowKXofmcyKE97YF4SLUJXMpUe4Bsoc75v9+YnOyetajegnX/eM0K08kHDmks+p bBNz9qvT+oTCCG3B5LGB6EJKXbUs8/PlJc38Eqeb8SkO0bDp9QGtSvpMRuCXFYzQ EfuF5CnxzeGbZtu8M9HJdooCCZMd0EBxAVl4AondgtmhhEewg3+lDhO1YSdG8p0j vgFlcDhITRs11509QSSzWDQss4C6D4hrtvkbGi/76hQV79Io+FNWHw+6vC4tDSA0 dYaoOUPN21Fq8roG7nAacm0fuedYpbUsUKUZkeuewNY9MYEq3fcAb31bj+8daZBY bxqOQP+AHVOQV1FzEkryyK6EMvQk8susm7SR9opEKly9dWg05naMhxgsegaxJgX9 NSJpOELoyvepio+0bD0RXijcwg/k1ke+tekTK3cKZ4iZgFJGDC6iVXeGy6uV41I0 HrO911F4kJQOBhCvbQIDAQABo4IBhjCCAYIwEgYDVR0TAQH/BAgwBgEB/wIBADAf BgNVHSMEGDAWgBSoy0aGnNChysGUQ5QwCnID9BHK7jCBkAYIKwYBBQUHAQEEgYMw gYAwXAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NT TC5jb20tRW50ZXJwcmlzZS1JbnRlcm1lZGlhdGUtRVYtUlNBLTQwOTYtUjIuY3J0 MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTARBgNVHSAECjAIMAYG BFUdIAAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMFcGA1UdHwRQME4w TKBKoEiGRmh0dHA6Ly9jcmxzLnNzbC5jb20vU1NMLmNvbS1FbnRlcnByaXNlLUlu dGVybWVkaWF0ZS1FVi1SU0EtNDA5Ni1SMi5jcmwwHQYDVR0OBBYEFKKZQd1e4YU4 uJ3DGdZiH51DXDMgMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEA XLJgPm6c4x0Jus4JZH6h4PplC1m2Xq7Gfl9Knhszu2N6VDpAMCuGv1QYafLNSSoM Ac3EvYAuLZ/QAthlOxkH3FVUe0sk+DVBTzCiVJKOundLgwcZTx+z1lXzauF60b8v wtTDcm8Ssb+e+NfZeE+uHb0gijqrvzWJ5gpOTIJ+0GJO4RbkZWHIx3ltvtby5d5l y/tJp50IKawzh9g9hwc3OtOr25PN+O+22PvawBtkrHQQVBlVdK5P8z8vdF0ddt1a crSi3wTck18AKEFXlXrMAil+qVC4+2c4woI7ngjzEcmE5Sg9nqyADKtdDxKaN+Du B/KZmR+/C2XcXdy07KHc3As2bZh2WEXGnCX9AXrkXQ35pUf2KsUmIJBz29HrJadq 838O44eWi/IDd2lCT5x8ym4D/8N5hTfBp+/uCIfqQ2du51aLgN3rHeGqmLvIfyYa 1xtGicaN+lzEQMGRX2DuklBTWcjkTNpDnsXQmU69YFRV95XqMqOPljBU/OTxv1+H am5jb9GUjd/Y/kkKnZ2JuJFcEl8rpotM2ZL+2ZthePSaxFIqnVwGj7+8kr/VOe74 mfomSRqdg2j9bil9ctur0DxhO3K+Mp8o2kEQ6giDvqj5wb5Wlor5pErujTGTdLo/ crhAizuWkxKffAeP9gnjFgSXTQmIDqpUcDUf5p/Sm3A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG2DCCBMCgAwIBAgIQcE1xYPQf5ocV1JCN5O4WOTANBgkqhkiG9w0BAQsFADB6 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x ETAPBgNVBAoMCFNTTCBDb3JwMTYwNAYDVQQDDC1TU0wuY29tIFNTTCBFbnRlcnBy aXNlIEludGVybWVkaWF0ZSBDQSBSU0EgUjEwHhcNMTkxMDAxMTU1OTQ5WhcNMjkw OTI4MTU1OTQ5WjBKMQswCQYDVQQGEwJOWjEXMBUGA1UECgwOU2FmZVRvT3BlbiBM dGQxIjAgBgNVBAMMGVNhZmVUb09wZW4gVExTIElDQSBSU0EgUjEwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCD6CgGNfi4CIAcv/j7GGYbKpalqoxYbRJY iTb+87pgwVWJI59Z/AplsIXXThJfKN1Mx17RDbMesnwAuqFBJDGWpgA4Vh490lgR TX02GAZyI/7L5elnMYGYxGPKxNvnMA1H4jHZIY8aSZyrP36EZ3lWbe+fPXjaQ2/h aX9fGvYjR+3TZJIsutwCf5O0TRtKqG/C6bPuj+NMbqzbGovdEriZEX8GrJt5YTtF 34op2sRtpzb5/XtXEujc9FrbdXwbNTj+nP8a7WTqVVctQleFzEbVJ4SUM6r7HdHS SucP9G+IwNB/g2+x7vkg6UnbEk4fhdEdbfiSSW48I7HUazZS0oHQ8iOcc5nYWRNh Jv7I5FuNVe28ODN+0VjLycwWUNZmL/1esdlr59LnJJNes6jknxYSzmDldc2RwFmZ ZTyfPga5VOvYBUXBmwW+4y1r1TrAXG4V8KnYClTZmOv3eBo6lEjBM2U4QcDREy39 NSTFc4l/nol3t3G6WuYlQoqmnnfmh0ULjNHHC20TYnz+c/uSSxzl2bIgi2s0qXm0 sfhbMkD/h+PR/cObF38VFZpLA53SrOmYgOK80y9dyZhZBD7P+wRjaqO98W6Ys0Ud kA9H1MvL+Vz51Ajyd8FYWn+tr7D2+jn9DdEd/7Xb+OYzKjPBj4mE37BsP/gr4TNa jD787jW+3wIDAQABo4IBiDCCAYQwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSME GDAWgBTQPeqimAddRIXPA/vKvzQKnxDEaDCBkQYIKwYBBQUHAQEEgYQwgYEwXQYI KwYBBQUHMAKGUWh0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTC5jb20t RW50ZXJwcmlzZS1JbnRlcm1lZGlhdGUtU1NMLVJTQS00MDk2LVIxLmNydDAgBggr BgEFBQcwAYYUaHR0cDovL29jc3BzLnNzbC5jb20wEQYDVR0gBAowCDAGBgRVHSAA MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATBYBgNVHR8EUTBPME2gS6BJ hkdodHRwOi8vY3Jscy5zc2wuY29tL1NTTC5jb20tRW50ZXJwcmlzZS1JbnRlcm1l ZGlhdGUtU1NMLVJTQS00MDk2LVIxLmNybDAdBgNVHQ4EFgQUkvs7fmjTOsMAdjhm DIpcvJXS/VcwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBl9IdA AWG6kViz2iTYMGUtsGv057hpqhjJOpyKPhiFBRVnh0S60L5U1z3230NkSx9yFO92 896KgYLHZrE7WeZ1nTWbYN5THPqg4ukAQD1D6pvJfkfumfHvip9SQwB1NuBXxLQS 18+/0V8NimAAhWNU6F3ZLJ4GkGqWdl2/Lciy1GikMBaIavsYpr44Px0tiyibPxLN Hmu9ODyyLEqRBKv3h98W2syrVeLKMX3g2yR0wFtdr+8FtXy79M6pL95AHqcRcAT6 fRCyKAmIFAvOxX/eF8Al4/ZArgq2CNJXt6S4ByQZuMKEA/0iuk+scP7IOXj8LeVf GkQauKHpO2YfSWqnEuTXsxFachT/bd90Sp1INW1KiV2tDHNe+wnEGcJQUyH3fGF+ w6Y7tOtUZcr4NV2u9p3Ifq4YXWoMbDiZanvmIlRMzIz8GG01H+44zw+s3qXudxmQ XPU9XTc0kN/duFP6LKwbqQqKW1fZ8ALW3nhDlpnjgqdmy2Mmphw5D1JP5N7jRQOk kYNBxmQEAwhBtgCXnzblIvXfaqRinYydog6+t+zmoSxHGO9VJKvvV88i6Z1FU44J kaRovsCbo4g5a16j5muSV+t7nCPmqVELGumyaRPUTJZqGorzDbNHNiANTaG3e+gw aOmGp1RdIT/spf9DlqTMEHbYrcaJqFuFe/0lGQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG/TCCBOWgAwIBAgIQKO74lnD+yX328C2++3jr9DANBgkqhkiG9w0BAQsFADCB iTELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9u MREwDwYDVQQKDAhTU0wgQ29ycDFFMEMGA1UEAww8U1NMLmNvbSBDbGllbnQgQ2Vy dGlmaWNhdGUgRW50ZXJwcmlzZSBJbnRlcm1lZGlhdGUgQ0EgUlNBIFIxMB4XDTE5 MTAwMTE2MDMxMloXDTI5MDkyODE2MDMxMlowUTELMAkGA1UEBhMCTloxFzAVBgNV BAoMDlNhZmVUb09wZW4gTHRkMSkwJwYDVQQDDCBTYWZlVG9PcGVuIENsaWVudENl cnQgSUNBIFJTQSBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUC XLaULVYuLsIHgywpaVDUn1LU1ExEZ0L1ywicgOweoIkboeHdyReXsROdUfZ7ev5A npkY9SxG2WJYuzvW97Tn9M/Ft3ZxZm3PV5/uI+AdB5sWA0U0b4du1jCa18ukRGSi aEUMynOq5oVqXn+oCa4LUNFDZ4L0rdMB+fHrGw7H9KuseN8Bya37HOmMp3wHXSzW QRm0mc5v1AU2xSLSuQjb+bZEz/ziCSew30sCVGMroJy2roD4HV9mDI2GSyc45H8g nw7b8HHyWGoZGav9AZZG10iyFusY97ZJ7JEkmqrMrwZ7Kt8ck8mttQ8ovBVYoXeG dX4YQMW/RFp+xTfgngjBZkxb17A1ch6yMpbxt+Ijto0prfovdAz9Xhs+cFeffxtW TSGKKNxNsAon9V++d3ZTBYk0BJyJteCRxGRl+/oVkjJ+gAIcbVzqdGXMbK0KDygf acDYQmgC8RTq2OfJwlplPCTYeHgKkO+HRm7Xqg1BmLXwCT27gjKlfM94qW4Xm6zc WVyqjaqpnYgOkHe8C8gFtZdcRrdxvZLvK7cdB5DaSMj8gbNsdzdrTAXnHrwaFoFE fW3Q7BPzc619tK9aT7y9b1OnKcNlU95jnoClCs3wkAVE8KHvm66oo4MfaMOYbwdV 43eZC7PZdK43r3qj/iNjEqmUwelnjYceqQnuHcG3AgMBAAGjggGWMIIBkjASBgNV HRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFBe2DwQJUirwJm/zYnAiEN21K/Gy MIGYBggrBgEFBQcBAQSBizCBiDBkBggrBgEFBQcwAoZYaHR0cDovL3d3dy5zc2wu Y29tL3JlcG9zaXRvcnkvU1NMLmNvbS1FbnRlcnByaXNlLUludGVybWVkaWF0ZS1j bGllbnRDZXJ0LVJTQS00MDk2LVIxLmNydDAgBggrBgEFBQcwAYYUaHR0cDovL29j c3BzLnNzbC5jb20wEQYDVR0gBAowCDAGBgRVHSAAMB0GA1UdJQQWMBQGCCsGAQUF BwMCBggrBgEFBQcDBDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3Jscy5zc2wu Y29tL1NTTC5jb20tRW50ZXJwcmlzZS1JbnRlcm1lZGlhdGUtY2xpZW50Q2VydC1S U0EtNDA5Ni1SMS5jcmwwHQYDVR0OBBYEFIU1y+hKK8Rf6933kdspxgtie72VMA4G A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAHf0ib+DzS16ieUa4571s 977D3EC3WCjED7ctPfr7SueY8Pw9oB0N/Y7jsnh6aTOVVfdhczRzYvEeGsrqjt66 1yuVlONOzQNMU0LSTGV8cBQDQSIhj44t8e9SX7MeDVEcfFvpKyO3EzMegcM/YnVZ 9AEJ5v09OljTLSP6W6qVKhOtLGy++X57+9BEFyFV8PuPwcmDhGmZvCcWmtyoUPRS 9fdVqitciiLpi1Ma7CficZzp6jhJry1QqwGBxJ17U3O9kveAnzeAlDLj+gfBOYyi H4qj4LIif2rXn822thn8o0ND/jjL3R7lbdHZ1Ti1O6FN40Fu94U+V3hUYIEuOCaG YszA0xESf2NqY3A3B355Nw1x5JpTbxXLH8Giq2e6PwpL34rYVGdSrirTE8i9DF1s k0D6BaWHn7J5MFRzi6ZxmvbUQA5i7I/CQ0G9ypF0VZ9fsSItzVa+KtUZRxx82kwX 8Ghj2fcQG6bB9+OOQnsr2Hqa1v/hMNeVNxdOtf1SZR38csEXXeZ5G6Hd3rtXLJs2 GIK/tJqB0Ia8bVcDdsrWClv6fKLyX/vkV869sxFXMweR8OE791joo5esHK5ROZLN 7bFk00t9QjIrSKCGi1L6rRfmTaZxq6xhwL7/aKuglCW1hFvGy1DI8uMXAgH1K7dL XOaKb/60iOj/vADI/q2Sn4M= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG1TCCBL2gAwIBAgIUMw40/E7Jm8RtKO337qLy4Xh7WAAwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xOTEwMDcxODMxMTBaFw0y OTEwMDQxODMxMTBaMGExCzAJBgNVBAYTAlVTMTAwLgYDVQQKDCdIeWRyYW50SUQg KEF2YWxhbmNoZSBDbG91ZCBDb3Jwb3JhdGlvbikxIDAeBgNVBAMMF0h5ZHJhbnRJ RCBDbGllbnQgSUNBIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA oPnnyh2HHcBnusXKkXZLihCGmzNGJWpqH0GFbktSU6AJdngnMSVFV7+mA4wmYGVf Hg+HvMi9z9u32Rr9YKzRBk2eg56nfjj+8CvTTId6A2casQdrEvOzzwfKXCD18VJd I0hjaSwnZSHylKoq4SQVnePBM2E+rCFo72CbzV5q+IXegfzD7O+J/bXtJs4YzvtA rbDwUla5UGV2xaIzSWgRY7UcTdpQjtCtpgmTQbpcoYjWa8hVkmuYDJh/Dg92v+u1 CR0xy+Fo3SKdVttNWHUP0BkIraHuTWecnGIWcKisDvjQx3wvCIIRC3hHVDAG1ATi NAgq83qGuk2xNat63hSamYW0H0zT3SBwzmblRFg57VXfczevaSbK/KGzTf3dj0BB NhTti1Jwkeon1otDFHPY86YAJaHpAtayWEKCmkUAF3Ya9Ryu2Zjr+1N2Gz13nbCr gwaAzzIbD9ZTN7VQJoN1EmO6/XCe/Ho7tmR25buByosTBUAvGlko/xdIGzaa4EdF 15au0FLRZpKOLpXZmPTFOaEwKGiKh91QxdmfWNByi83izlovw8QHQM0Gej2BqUXU 10HlRp0ppbpV0px9uetBdZHN7ce7qlRgnqMqli32KAa0wdFipeCemn27/PWOQpgj qqHdzuISwUPaykVGsTY/7oGEKetOe2UnvDo9Wq78IncCAwEAAaOCAZwwggGYMBIG A1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUxhfQvKjqAkPyGwaZXSuQILnX nOQwdAYIKwYBBQUHAQEEaDBmMDgGCCsGAQUFBzAChixodHRwOi8vdHJ1c3QucXVv dmFkaXNnbG9iYWwuY29tL3F2cmNhM2czLmNydDAqBggrBgEFBQcwAYYeaHR0cDov L29jc3AucXVvdmFkaXNnbG9iYWwuY29tMFQGA1UdIARNMEswSQYMKwYBBAG+WAAD hwQAMDkwNwYIKwYBBQUHAgEWK2h0dHA6Ly93d3cuaHlkcmFudGlkLmNvbS9zdXBw b3J0L3JlcG9zaXRvcnkwKQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUFBwMEBgor BgEEAYI3CgMMMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmwucXVvdmFkaXNn bG9iYWwuY29tL3F2cmNhM2czLmNybDAdBgNVHQ4EFgQUJ3GSDxfyCZeYbh1rzLJZ TzHQhE0wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQBW+GFb4bCU glQVizlIgbsYY/ce0SLNglPhdb+SofpUENHIZwtki8qx5KSseefbyq9SCRr/MKQ5 1bDiwtWSNzDR1eZ5dmESic4WwtRbe1FGmibiV/XEXYvNfr0Qudog5oJ1aC2KilyV ihBi6tpGZM+6NqWXugGD+YOYTdDahowZjb6SzZ4YW0unai9O8j3QjRlw7LY//+0F ayhFJZozWSBCwXu+yxvLSZY/67KJ+MRWOyzOR1lUTok8wH8nOxud8rqPVrjfkAQr OydGy5/KdWELDQgQ/iMOIZtdPUzCrRhJZeqXDwa6RyjnTjB29LFkmoRiw5+PgqYz OrHroTYA14boyRiBB0z52HSXLiv8FFOq/hR5vz9XuEChTs2WDquCnch2JcU7LlEe 9erffxv/C2eT7rrf/ZQlpy7BWKvcJm9padyk7g/NgCgDGHVT/yqtCFxHYYaFpXZU 72TailcQakOZjd/7BBp41KXR4m6xyK9ZTcrbkFQJmvAJfYlcQg4OLr8EalS57uFe Cpkdi2qoELMSRwKKuxL9iT8Atnx1woBGDQSWnPkijO9t8M10gqWzs5QvQ8y66ri2 VXzMCOQ+5Eu56VaPZXi+ggTQu8L/XmUB0ArsdDvF/dZWPYj1BK0QUBfQOsDYn7N6 hv13OKvEOolJtG0oZ4XP7NrF9Lpbq33F/Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGsjCCBJqgAwIBAgIUYb6CkufoyzrfmOLKevNBVCmN0GgwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xOTEwMDcxODQyMTBaFw0y OTEwMDQxODQyMTBaMEkxCzAJBgNVBAYTAkJNMRkwFwYDVQQKDBBRdW9WYWRpcyBM aW1pdGVkMR8wHQYDVQQDDBZRdW9WYWRpcyBJc3N1aW5nIENBIEc1MIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArpE0+roCCjyHjR1iaa4zGTNN8KrCteDo cRNuAluIKrTnQuKSqtykU7/H3COSW701Y20nuGsJhctHgzNu8k4bTwesDLv2XIxw qfpQQAexpi8vZb9SmHEXjHMGjgDq7/hv8Yp6qOwmv3FzBMkCmANgf1poB+cMCyz9 hatvYZ/va32QvyMP5JVcT5+H2aaezEREak+UdOq/q06O+xNMGOlbkLJOurpLdzeF tyUgceOP4zTsXKZtvgdFOM9w1J6Nikx7l6eNcn8ZNbCLgPdqyWKC8st5ULHKGv+a pGqqg8mXmGvuqjnNSvClVJOlA7dl+gY/dKxm7ucAD01SUEzZQonG6NC7HzSEn4Ks LN7zQV7QwVllzc9KRT0SFhAOZ153lFg2QEzHuJnuaGTf4EMGrbr2oppy9WKunsOf mseQMmitYB63M/Gq+Rbi+LWJeCMtw6KYFZoowu+Tp0/GMpCe4kLv5udh4jBYGDan dorDl+sEW8wSXL21Gjnyw7FnaaCY1HitiUKJkBKrOrJKVDPsCx75bD8pTQGTAjcX Z3ErR4zK+gx1mTN6ZIKgXpJKFiP+BsdBmq5n6BkfQ0x2G4KhdOe3QGYfPLDL//kt Uhs+LFaaACII0mIzgDbgebtLKjhaJ4j3yE2LdyhwRiekEobmIZf6MNHeSlqbHLVA l0dRQhiHr80CAwEAAaOCAZEwggGNMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0j BBgwFoAUo5fW816iEOGrRZ88F2Q87gFwnMwwdAYIKwYBBQUHAQEEaDBmMDgGCCsG AQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMWcz LmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVvdmFkaXNnbG9iYWwuY29t MEkGA1UdIARCMEAwPgYEVR0gADA2MDQGCCsGAQUFBwIBFihodHRwOi8vd3d3LnF1 b3ZhZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5MCkGA1UdJQQiMCAGCCsGAQUFBwMC BggrBgEFBQcDBAYKKwYBBAGCNwoDDDA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8v Y3JsLnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTFnMy5jcmwwHQYDVR0OBBYEFDdC HU5iaqadD/m1LNdzQsT7pj0tMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEABi0xKQp/AIwS/Tjk7LlayzTIGT3e+7BoNmwYqiIFkGf2FlRWKm/UP20O pod0tvgBepCO/TF4QTyooPTXRl3QlN1TKFZohUz3IADIIg5dXXWC9hCoG6gNEKb6 EXBnx9Fdork3bj8rWupIi7RdWUZM8PZN10UUNBchUDgBWkmrRXUH8jzrLyONqKY3 SLKJv3lj6SsLdiZ/Z8MkvZRR87rCTngiDK+HJrWmbh3qWE84m7BevycpBypZoA// 5LurQKZB7YxmOVcAWENrayo8zV4+SbpPjo77c3Usueh7ZkO8m7sa92VV7P28tGZS ABsd+S/QYO359CdvsZb/xxH9WSa254fPSv2xRFBIayasb9TV/5AEXa4xVi7jfDWv XWW/E/rW/5eadlTKng+X9VS9v6tpJyRzcd4QjUE/URmuI6Kc2oJP0I2W2VOfUfem 9hgRKIVh/GmNrUvn8nZnd4rAbz5QJVTnx6Oa/vBprN08gTJjPDcYxSx7cznnVQ9f hd5+4w+iRjsqNBjxUph+LICb0bfFkJncio1B7QAjjUOXucZgRCV4Usk1Yfe1Wy5/ 3t/1L2KiaGdlg+7fVq5lQ4Gfw6f9lFbW+Ag9u5egLNZo0Hzjltg7RmDJ5J2Qd6Qv UEE0o9OXtqt/hLLO/aGouvV5WAyojiuiOGNKXQBaKF+AA/fdX5U= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwzCCBKugAwIBAgIUEn+LMgYmKMDKP41Evvny+l2xRAwwDQYJKoZIhvcNAQEL BQAwVDELMAkGA1UEBhMCQk0xGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxKjAo BgNVBAMMIVF1b1ZhZGlzIEVudGVycHJpc2UgVHJ1c3QgQ0EgMSBHMzAeFw0xOTEw MDcyMDM3NTRaFw0yOTEwMDYyMDM3NTRaMIGBMQswCQYDVQQGEwJOTDEXMBUGA1UE YQwOTlRSTkwtMzAyMzc0NTkxIDAeBgNVBAoMF1F1b1ZhZGlzIFRydXN0bGluayBC LlYuMTcwNQYDVQQDDC5RdW9WYWRpcyBFVSBJc3N1aW5nIENlcnRpZmljYXRpb24g QXV0aG9yaXR5IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAru4h XCjP1D4tYgpQHnWXZNrXRDcey6U5NqdpJcEUb8NVF+EkF76NQt/y6A6pp1uoRw5N MQ8eJfrdJ/t9GKGe6PfQQnxwObARoOAJq1elfquM7bfeIkCgV2DA09hCEufT/9UJ V8pQhmOZEpuuoBmfFQoseoVkZd502xNK5T5R7iGAJIrnXs63rTCJj8rGOg0HC73H WKALgC8oApsysNKWBFxahgS8UYdLLYWascCxwCnRfq10BXRqZefQd4udihJTcKqC BBO2r1OPFl6J0lMN1pcURwqwZSeNlmJ9wt+sl/AdDHgNEzdW4sbnxvQv4QREvq+1 I/3I6aK7nDHW4D5ADWdo/+733k6RM3CIye4UekJMihC9wEgamkoVtUBd38s+jsWB DL18OWVZ61If8fZu5dHeQgYizR2qjatHQrhaN1xICu2JZ8fabO4AlD2egJcDkfHA +/u4fCfcfGz1yV+k9cqOArK84/D2iLs/qsoHlFLKv576If+Aq6bhNi7Sjq94o9z9 6TVgprA7s+/vHHmlX/jCl9Lf+VFsquwZ9j4t9HsLV1pBaaoDbkcMWogskFXhD4ir QXN3947IVsuxAjDnc3Nohy/Qn3IzaOI6Ve7iQXfgWvjSi2GbsOQVUBDcOUnDOVFv WusypPB0DrTx53iRVX8YOl2TTCNKMAJ3MWIiUGkCAwEAAaOCAV0wggFZMBIGA1Ud EwEB/wQIMAYBAf8CAQEwHwYDVR0jBBgwFoAUbCa9YFUpKU5mMgeg/2OLg1pLNMYw dgYIKwYBBQUHAQEEajBoMDoGCCsGAQUFBzAChi5odHRwOi8vdHJ1c3QucXVvdmFk aXNnbG9iYWwuY29tL3F2ZW50Y2ExZzMuY3J0MCoGCCsGAQUFBzABhh5odHRwOi8v b2NzcC5xdW92YWRpc2dsb2JhbC5jb20wEQYDVR0gBAowCDAGBgRVHSAAMCkGA1Ud JQQiMCAGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDDDA9BgNVHR8ENjA0 MDKgMKAuhixodHRwOi8vY3JsLnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdmVudGNhMWcz LmNybDAdBgNVHQ4EFgQU8uDtLAOcY2w4ZSrH5F9KOktnjYgwDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBCwUAA4ICAQCJTt+cVr9QccgOQzy/Q4JiGT4FXrFzmeBv uoVZGrjljCJYeQPsjqKIYfwB4LtdSB/oIbpiDEDEcP3QqzflRz03D63tJRAyGT9M i+YEI9f4YTY+WJMpZIyPyhdlWx4VgRJD7bkF6ctD0HCQuss25DFAnYtWzvsg3qFO txxPT652UZ+E4OI9uGJtbQRa8fVaB+wZjpt/6Squtokntpbv0oQXQwG1TUzo2szE 3hItaM45SiEdwmjFgInlmTkSuiXDEyr2XT4tEM8MqlKAo/jtacGnzp71dXPMUdj4 DGlCNxQvLG7eSeStTmDYicAaTa2tsi1HzKCu2ZG1r8uvvkOPso/LgT5FSvVU2h4G lPnDze0iE9pPXov2p64H1xQiH6WMJZ9rEQKd1i39tWJdsZ+/ZW5Ejhm1rqJMvmPR Cs2l/NEM6/B/kEet/QJlgrHE845WL/N4ejSGrjcFh9CRisd9nrODoGSfAqpajCgJ oFMYq/1vtR5EbepQUjdOZcF4vkcwiO/xnqJxVEge+MKF5r5shtgodU0bFVvAgCYV d3MjkFpnCxbyCmcgYcCIhfy+IXLT115ZfYtN8xuAJZ+1ak1wGlQ2bUnz/VVfptOl hFApe1oMGkSzsDwHWjNl2+CTxjL0ieXR+P6Nbn3JkcMNXu3IPBFkT/VMh8XXxbmw yuu0SGQTZA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHiTCCBXGgAwIBAgILYK6GLFegRUxeXWIwDQYJKoZIhvcNAQELBQAwgawxCzAJ BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3Mg YXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMy ODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEnMCUGA1UEAxMeR2xvYmFs IENoYW1iZXJzaWduIFJvb3QgLSAyMDA4MB4XDTE5MTAxNzE0NDQxNloXDTM4MDUz MDE0NDQxNlowgaoxCzAJBgNVBAYTAkFEMR4wHAYDVQQKDBVNLkkuIEdvdmVybiBk J0FuZG9ycmExEzARBgNVBAUTCkQtMDU5ODg4LU4xGTAXBgNVBAcMEEFuZG9ycmEg bGEgVmVsbGExSzBJBgNVBAMMQkVudGl0YXQgZGUgQ2VydGlmaWNhY2nDsyBkZSBs J0FkbWluaXN0cmFjacOzIFDDumJsaWNhIEFuZG9ycmFuYS0xOTCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAM0sDzyDqobny8Y1c0FUJyDsRL+MMRJZoTaR dUBWgNEmDVAfICQqWy4BYSe3rNGoAiMJNCPLA8EYo3XIUmfAQ/hBkxmVbcp/kkZ2 q58I4EC7f7L7sYAdhdmDrvcWhQe+ZvQXyCXKBnKiiFnkDyLwkp+W6MqcxC9YOFxz jslUD6R2ju7Vv/9jq2wikRWA1/bPxQsuzsLJcyDUHOCMRv15MOugNYq4IjXHc7i/ kU6wobOOKm8UD6Sls4O9p//Pul4ueMnXMqcEU1kyU5iT3kotrerBa5FnoYdmaTHg Y2kzwTpHemVBYDfQT/LXtED8mJG95SLRymIEEclGdqW8Docj54Vr80VwWcL7ySvP i5tBAEqpAKn/YAIyAwuHVTVDc/UiW78yat3BKbeUcx6Bf8JHqvR1k3ERzgU/g1c1 ICJWqXnX81elGPS/nB6uYnYE3q5G71P/crlrE4JdfbVTcZwaN06DYq+SEyjU24Qi phGt4RwIvn6YyXnyrjtFdwPaBkvcKM/wdPweCt7KDXNMQXZxP8AHZHBymtF83QrC jCpCPiwBoesCixXP9XU0GfiSF7ERMXqb05xrd8Z8RdTGkxqTa6cB8aI0wyNpYkkL Pdq0miD2F/II9Fijt6Ly23ZvMvEgnEhGp2AUTx271UF71BnQIVE4WsJIEhsyOFhQ REFxHh7JAgMBAAGjggGqMIIBpjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW BBTAwXRNxsXBB3sDFFhdWEDJeDO4ajAfBgNVHSMEGDAWgBS5CcqcHtvTbDprru1U 8VuTBjUuXjBVBggrBgEFBQcBAQRJMEcwRQYIKwYBBQUHMAKGOWh0dHA6Ly93d3cu Y2FtZXJmaXJtYS5jb20vY2VydHMvcm9vdF9jaGFtYmVyc2lnbi0yMDA4LmNydDAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMEoG A1UdIARDMEEwNQYGZ4EMAQICMCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vcG9saWN5 LmNhbWVyZmlybWEuY29tMAgGBmeBDAECAzB+BgNVHR8EdzB1MDigNqA0hjJodHRw Oi8vY3JsLmNhbWVyZmlybWEuY29tL2NoYW1iZXJzaWducm9vdC0yMDA4LmNybDA5 oDegNYYzaHR0cDovL2NybDEuY2FtZXJmaXJtYS5jb20vY2hhbWJlcnNpZ25yb290 LTIwMDguY3JsMA0GCSqGSIb3DQEBCwUAA4ICAQCVu/0Dsxhev5ia+yEOYHkm9acE CsTG/706jqsuXA0NW83tp/9MA5XlnmegDhQaHpeJFclE+hVd2VJspwWi0tT93rVD QT+LwYEgYZsC+fNsr+8f0Qgt+OLgOZEB3I2fqKhrmea7kwduRsg01qTZ14MFX/+Q jKYcXhyEwB6vpC7e9mvLOdF5ng4LxB96KdL99Is53mcx4XkG7HNL6wIbOOkI9Gs9 SZX8ySNMRdPMUeWj0W+YEernESmutSiR2SHci5MEmFlFc8GOK3bgGdAdVKsU+qX0 wWhtfZnHCyXwgcHPPR27CEMDL94HRSmYE7wZWOBvkvpdluZ668/ADqb5tdH9K9bx XR18zq8G21+RnEvuqlB1JeqryKaCw/GW/iGQBfSpHPvnWSX0JPUvHz7ndHLIPQHT WqcegOYLumiy7QzkckANkl+FTQW3/V+CVIa8Oawujt0W2M2fIPCigWRl3PlGrlmj KVlBcASETSETlSRxJxH95bXbkw70XoeK92K5Oz92ipkTpidFyYaS/TCMc+gp7sZG vsQmwGotqAQx/vTd+ipQEbklWgLdWfsegY9J8ePu1uI8nWc+eMB56eEHMUnPpK8j W/rk9jtaPhgmMSAfG403OB4umETT5yht99rxd0YoyKgEJ3mjCB3yx4WWGr/73e1I NNCbXlAfZAt1Spu36w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQblezuJGJgnx6ojSIEJkjhDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDExMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAvEYh5NbXwXHEPqEz50uto6ysN+wBc94JkHpSUJmTOOiV ahDk7sFIEiNjPb3ltr9B1+SQ+GwUBcqhbTp4re39BPTzWbV30UAZjJXNOUEqMajZ a1xAuudeK9QXeaLb0jVMrRCz8tIIIsjbw0f8z+5yjIW5tMkjsCba6c4zU1J1rZ+z gVB+mB4NX5QO+ihInbxUTjXTyuE34n0NAujiAMtrdhHoWr4OIILl5z7ab0nK6K4Q OyKzIiP+XZicM/H7Oh8LZUAbluuW7GsRDlhFs+QjEWrVPhs5je4hpmt5L+QimgGP 2YaAD9EdIRK+56Q9kSALwsdgVoIaRA2oMg8xbeQdC0zdiEKfwrNQfn6P519LuCsE VxHGHV/IzHaqOVrU8VAxuYd76Gs6UHt4OwNJy761/KhylSOiE3kqF5O987mge0J9 GQFOOH/3F0QZ44v4zgoB+1XlAPe2Fg0WXNVtUQ6dDlubcc9wvsdn7o5WaZuJ2fJ0 mS97ZjakFOqIXDu5AP8KpDqnViQ8M/kGDBhec/lX5pZX6FQsljzXD+UQmTHmBBK/ ZTIFyPm13XS/ZbjiSV+sWeaSSrN9n/6sIu6/fXwa6r+C0Ar/2Jond6d40O3jeZXv JgK+RoAocL+PWdlgOUBnCJwR35EHExShS2atEDMvYn1BYhU+z4QpdUSOFRgaxNkC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRxQYuC wdk+IIzf7KsErgvk8eXg+TAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAG/AYjSYm9bbE2e3pkbtPwuZm7Te2eIgGEqQn8dg AKXer+R7hOXZaQSCOA0c7WWQw17Jq6mwGDT4x8juON0hlCBcawHXtirZEENynhhC vng7qg/E1KppdDhZRPIw4AHHpkH6dqnb3Qr/xu7gTE+Ycc2DTtOvY4pkbFt8RYIz q9aQLWVgU0iwDyiak62Q+vB5E+NutOX1khXx1sfuqeDynOuSvqt5NOBBEqvtVqKE dsekaEi+yR+mFhyuIEBNnn8Oyh4ElUstpNn/n3+DeED0IkRttcKln+r8Mm/KbSMp CH1M/xsLam87POciSr6y//sKIoiezJy+0OGOzgszKQl94c+yrAKhaIkXvoMZ7lRZ 7i+kV0KThHGPGm29Y+gUmIFQrMn8OmL5L+pqmUnWBaaEYTVoP1qRs+/u+JCUckdS PLIUHqMM/FApGzxlyqZ59zNy1DsRF/WBLSpLreDLkiWV9ic2UF4U6WUBzFHWunY/ DsJpzS+PnD9BUufgnLF1GodEbUo2YSW7NDd9Di3Xhu0a79hOT9TsnTYcqNRPG92/ YpVlrYKvBnhIxHbs34HUqLW9pZ8ax0ZQ2yV+C43W7VTtpooOj1lt98FgPwZTy3eV FPXzTISgl7VdfbNEZbwknsPJ9C+dSrQRg2VT4uZhOBYSAgw0k9leNupulEO6qN1d Bs+l -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQD6Eyl+qtc60bqAddkWjZ/DANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDA3MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAh7EvsAjhCUny6T4B7/6W+E8y+HU382gD+AUokCgGsneW h7MdAyk1qE6C42XePnp9XobAJtqVlnCw3KFLEjvAv4MocZL31OUY5CvWzW2V5Z99 b2ancDEgAD5U6s66JaYfw35nwomYrjCJyKnhNzsE2X3R2VJTT6KzEjbvMAvWPDEY YX22vRZiCwWkeYT+XIZg+jTVtwYDMw7ClPKeUxQnfmruNk1IEtofI1HDfBiqNqft 1byF6urdAKvGf0sqGGSn4vOJRxCIARwkgx0Al+QH4JxntEc7UTQMWxH/66a0yYFS iKj5fckfL795N9PG8vyL+oD4ezu4K3MBkdO7+VBIB8CU1VRs1mA2sFXVMdwvewlV HqQilAgxrv52ZR3xKbJIAg7RSUkYOQugA3U3d/+mz6GbhrkjUa//Fb5CRHBt3sNH pWbULfAx8BlSGnWK/w+wS0KjG8feNIY7yYp7+OBA7wqcqRBHXCYlY3PTKZs6ZTSV VpMuwuYvclvqhrE66kGTbtziUgV1JatXxgIvd2Ee2Coy2XLXDBLKQPOpWRezPD5A CE3bZ2mFfYiFAWHkXiGgL1feXw3Vwnx+1eZgHQE4GY665GPDX/MaVKUhrDBvjjZB iXtan3wBfz0JgI+V5GvVBPvclYfnmrV7Ld1FiApeVQcma8ghHVwrSmAVdEcAGK8C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBQ1Wnoy AF1mQL5vTQ545UNVYplRLTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAGZx4vuq4nhIU9O6eDzwWYLOEU67bjShEB3WVFIQ +C7rGk1gBct042rbGZ5igw+Km8M3ij7evRyc6u8FAR2O8Lje+FejYdS6RzspzFfi kQSqAtzkOVzqaX8Qj81vv9EvxF9VN3pKraAWsEEwFvi2+O7jqJkPBdWQmXs5Jchd 7PnXuJVsL8O+THD9Dl+NytyUSYIME9/22+s1gEG0efwtw8DoH31g6CiTDrb3z7tq DoJX429HOkDj8NuCflqaKL1akYRz0HPuvK6vgLINvehSY6N26ErRTcLcmYxVpRVg eqE+LpxTVnRf4o7f5+UfmLf0ouA53+gU0To8nWzNb/GALZPsJ6jNtGod154CRZj6 v+ph4HEu69Q5rKOEWNBonilKUT+SosaS3QL3Na1Zt46sOdhnANMdjbH7KrBHofsa PBaKSH146JIIdUM27YugJJkFN48WvanYilliGvPOe2Jslx9P4XOCc6RXSU8zcq6U EBUy0wvD5jWsl/n7QnqINC7LDGI2XobO3iVrv9nwAMevthVgEAu31Ae5tDXvbzVt 6jBoYjAHcuYtzuuPQsp8MSQAgQ6ZDEFTuDzfUlf0wuxhaTkz9Y8mgmsrfoU6itoo 33ZnnLkmwmhUjUGgrH/1OR6+XBw781r/desUYMZhy2uotOKhiSQ5O7gkxn0yQKnI 9ex7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQCMLP5JBkZYrJvB8W15UqQzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDEzMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAnu2WNqPvv8ewWInjsa42GszGnYbslxCX1Oo1y/RVF30a HYU2urebqaGCl2hJhuS9QEUR6/1zDa5efNZdyuxPNhXACMdN1eoIEbOLqoygEAiq 2sEHmPeY5xHuxy/MKdiqTLvwXE1qUnhJOCO5os3Hnxpge/sMVb4dDZFcZAopdDak 8SSFSbSgV4lar5bXEjY6jhxztSB21Z9hmwuP+ZzDBLxciWcr3ZLHSFmLbwRT6SUe NEJwnZ7il69uNTeQHZrdPPfnwcgr8PBv0SmRLiBaLYSyF0Y3IeI+Pfb0NYBlWbaC 0jHcSTi4FMKcPdS458lh/tQceDMe2GW2y/3SgnqjYZzYvoOyV7P0puu2mj/GstDK oFt+Fz4/mIOR7eufOU2Fsv7TPIWGYxy63i2ZJJ9psOopqu7Y2Df+mBYZBEl86QiB s6Exj9tO4GYwwLe9/SYbxsZfVgieZJod2ffI8WwIgiKe0CatAmhee/+xuD/rY+ky pLLBGjuaiIV1ctW+3/u5PFi0fIor5EdiawOSVSzvzhF4GlimY2eCD/c6H+Q9GKbl kSK5F+w8kI414sMuZLLb7X9lyvw8/9Or9ZZ+DGe1roZu5w52N5sI+g4Woz8f/TnR 4yqVv65k7ALDe9v8h7IyPM+qx0itgOM1DqImIS8mk40annsxZUHcrGMIUZC4UKEC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRtB5dt 0m18QpF+Z1epVMBhqgNCSzAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAGOjADqtGz9cxCBX6XjkRn4F8VSn9dSc3/ciegEZ TN8NUyHhwDgHwErrB6i0rxhFNZPwvWF8TbtogCn5TigYNUO5pHB/8DsYJhZetw1l PT5bTlMfp1bF3EZNJqCnc+BknE+ZZ6y3dGwjDhHvfMesArNjtkZBCVLYjxlWzk2R BJTfB8cB4zYa/3I1s5TzQ55mRhBnxM9MyC6cmEGGcLJ4/vC8Ku1Tvu/VDHPsVT1f A76gpfU4tKhyLZPDclzocbx44eGrPweuV0sgWXrZda1SlVHwAuvCMu3cC7cROf5r 2qTNTQXwqtaUOdfzKOcg9LVDmrC0W43zRnI/3wIl5nFGlYH8CDN6+VbM39Jh48qM HacgkCcPM/qN1c3u+1zFX53ibqZk+CWPcjloLs7PmTED99CBbJsN9oOpQ0Qq95xr hMUUmlvcVn849bkJHuFQSQBYr88MjBcLMjhu4loGmNJfRiwLOsrUeOctUczphHeG jwuBeXUVW2UbSmYPiq0Pts6VdMUMO/voz014s1Pwkfh2E6kfexHkJdbSVlcv1i7P gEAW02+jc1m2JWMcDlNnzXJ1IUHxmvJHvVqfq6TnDYcsXPNXU60FmNF2ZtbaP1Pa CtAsfIe8lT4NKP8068ES105Tm+eDxdvU123fntTXWAihY7nX6smiQWqR2Y+3fzVI hdan -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQAquMn2kjUdDPANMA7ekYPDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDA4MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAngj2Zr0BpWtATeuoH79QbbOF7lOopDnRs8WU4FIUe3yK Z+iqvCCzxz6SMP4gxWIddrxm5VeQKSFP+rfwY7b8LlbFCNvZ4GbE2tBamfWZ1Q// h7T0xCm2z99AwGf8ni+1r2JbkV15d8KYM8FR+Sc4uR4LKJxFYZBHevCyNd/lBcHM uPzu9sAhWk8psXosZ9T/wgOrJ3fxFchHDthPbMSD+Cu59yEqsIpL7AW7y7I8Tk00 xD0urirZadsVnni1gF9HF+qwbJevVXGNkAh8WyNqMYGE9v52cjgo8eI93cZPkpxv xN0xskfrVdHFunQ5PXFQ0oEQwQxJyQzvJQy9OTUcYK02Q8MpvcJ6KZORyFwrFCzR zPUcNIh5uGkI+POlTmxmnjTZ2Hc4dWPSzjVjJKdyOQKz7bT1Euw2M7JfsfIX1wAB D0nkrtA5/wTKgGMc5OPvlyEfH6CKw/a+hC9SmTz/EDmMMfaXbNlR6KzshHK5mcIJ HAcSP/a48LYXthx3I1hSEnA+fxBvqfwhuss7ZgULd1dqF+TOlthdfERn3TsWartM ILhi07FqPQZojeic7ACNcBDOTO6IFS3Et7Q0DISucUG1MMhYnuIoUx9c4WLYV4s3 baaOZ4nfpSHNmKyeej+as31lI44xOwims+ArE5VtS3LX5bBUYGpSElDbjHHNzMsC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSFy2OP WO51gHEsoqztVoLeLsolizAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAJaMA/WqFANuglRv6W6rDbgTPTIVaTNJeUgEMyjm oo/9YNlLOvT+ISJqkak97tNyaIsSXxoiqf9rvTG1eGrp1A6qGv9ZpuVMq1ykyVBN xORPwcp1VD208MeLZ7OWxaPM5n3YWgNNeMG/xAoX+7O/MNAnEnpzI+WdHGHYZDMK wymX8lNrN6vL9CICMUtM4tNaUYxBrh9iPZEEDd8kIv2tM8QVWeBqvHMKtpyfgvfv Lh9kULs0+Luch6FhhnGMvGLa9Mly2JjW9QMvtF0td8KKvpYHni4u6FMmTKNnCPau OmxupwFacbwYf4VB4aLVzyn5izylg488wbLgOCPz5GX+xI+UkTFVp1aFMGUayhGI ouWQd4rUXmiB5HB2n/JvHVGkRNA82tDXSB246ZpCjS1VjaPw4gfiksO1WxOUx6CI Z3YH/IZQG3aHhmlmywWVYmBN913ZhM6xAUl0Bn0k2xKKAMjwyfk6mUCKiySMHcl+ mf/GbOo+U3uwLnGafFyM3OIpG4Lbw3+qB88Xg8MM5V0f02PAcJ0qsh9btWYedPVl X2V8jBQsi3GC8UOJB3ZY9nH7tqP/VjTzBKh9XgoSdfZ2v4dvMwfwD+hzqQPsJM4z P44Sgdf+Rb3/k4DKV9G7kYX3uJUmJk375RnVG8B7GH7ZuPHCQHor0twn0NTmwCgm EE04 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQQNvpY13xDyhGNvCOmHmbtjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDA5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA5iO3TbMw4Ix49zrHquYAbYCgl8vxbgWMaYZxjCsnFMC5 f2idLqhfvcIOoaMGz0NFZv4+CM0aNy1yItjK73lnmT4QfhRLdFTcJZhhU7HpIWiz rc7SDH67zYTVpT5EgS8HwDMeZE6q4QGTDz/IuGrsNg316zrQRR9iQOKPmiCISkg/ VjlD+NTOtUVIHN+750EyeHcFKHff3Vn+S2aBh5tqb00ZIsSVi7FhEezzlBHfZUwt BmfKgfMkB1M76HAom0+jHV6WBFvUSTbXinkx2KpFON+896QeXX384mw6nXUZyLnt ZUbi2crEoaXQpk27cT1NiDX+XUuYZWxkbiix8WQL2ihSRX2PS5uwn4sw+atd+afL gFHCUsdOR40czchHVunGLnohDX0MheZw1Pz0a/MM8RL31p/VqebVJOXu2qU/Z+AW hWxywYbQNVfNzjtXbaeRdlbv1v03Ar84y6ogM43BiHmZpTUhS9DMmgPHkApPgjbe vyKB7ar851W5CChm4CZMM06F56i99c5S+PmvFE9i6RHXApP+f8Cg1XH1pTOivpTS UbEZ6NvZ71q5yaeSjV6eTCpyLi2pG9LY8xpTXuZi0tPtlwTICvRy6KgglBevpZD1 aCCN0u6RDrhOE//jGhoIzJV3MCRwp9rol3VgwNvULNw08z3tYLFZw0o8UKuAz1kC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRS8NUc eS4mTIXEEHsLfI4oew/PHzAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAIVgniFibv6RG1CeyTY+ZYMnDyKm04tNhiGOKVfq lyg7YN67trsdt9ZV13fY4gK/zyjrXo2n3ARgRF4XpAfTtBChy519/3kEhLpFjJq9 ZNyzG1KlXA67Xt7G80GvhD2xO9FbSZsrdMbmG0dfxzibhx2Crn+R3szhl8q2OeDU vp82kWIQc06xsBzhc5tHvzVxzPURtgaU4imvZvK2uuF8RB6obb3KitmBaQhqSXez UiNkGbUwH2p7MGSPpXKukk2ufhA7Sk0ufzlBFRHGFJ55k0/WL5Q+nlFeMf7wdNU/ tiG6l636hDvVkoLu8FHWnKcdzI10n+D5P1bFdBwpNQ0vi/d0C3rftXgu0OtxSTC0 5qbG9u9iu/gFi8HlOY+rUjjILMylpaWBhPWxKN7nQM/ckH9icF4IIGFKl76Z6ajr d9hFhSB4jzdohJSj9tD5CMcQt4d7vd1c0v4JDbjL8uwNPFLK3jHOPeHpW4TrxW+y D+6QBiCJgGGo5OP5vVV0cexSUy7feeQ7MOlet9iEbc/eoRle9aniHy0/IA0YwyF0 Vjoh81rfrShX9XOWnIVAv5bxoLN/5VlfW5NpuLWemAQErEgEPTlf/X+Bhf/kaFEa oEMz9TEM41EVZtOP9+A1DfrXlZunLBcKhC0WK4egKh6N91rPl0XsNU6kG6LQ5at2 s1tv -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQDTJp30WNYJ2r5PdCEREYujANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDE0MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAnNaSeRcqntpXA79CJjI718O+OHG45zJLtXVoZ36epC51 H9JnWCUM8UJ3W1wjl1B+Q94cKaI8gMIe7Z2p2Mdjk849YGKGw6g7PUMbRUmOD1eG 8VIPscjOmmth+8Uj1X+/LzMMDiKXDpubmealiTyNWt+u4FZ7e8GXXzM0xjg9l49Y K9YyG8NqXleIOdZAzfFMimC4LAyMpU9b3V5j/O6xL2hHVWVkOogyzX2JClhFOu03 xC/Vaazay+xX4g9jyeem2r9W3jDWRPZwWZLyB2jR3i/KufxhVGfton7RBDAk9Hpf OKXpeOrw3VxD8DNU3VgYVrZ/1YJqsFQL+JL9+ZsjMu5SuY5MNBFSG3Je5EFt9jHA JNLw75/okeY3PLNEkSipbE/r6hnYr0qvA7v+m+/g1dgTOcN7qPn+5gYLxj7hvzEo RfUU42L3xx8m0eiccf2wBvHdT2nLzqFYuL6ngrIdJLOcPoqfHCbMYqXeHuNrWMU+ P9OAkAvrxemVbr5UAUCE9K8RLj7/XPaHeJn4lVGMaGLXv0ExEfYjNGjF8p9dQqJI YVaopsv2i17i3WBQhNrkvDibJNCJba1lQPRCUJs6Z1uBlklTTCdjKOXvMlcfpwMa /2kbLN8GE5UDr8751eF4YHyliNFK4XBr3bYqXYlvvGz5pYhj/oO4t0C0XCvGv68C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSYpzkm 25WmeGuTmu+d442JXAvvyTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAGJkY8rLeldY4MF+HGlRGdvzyP29sTglS58uDZwc ulLL6ptpHafwWqeoSGF+D+1w1G2JPH0Il/b4aXj/N8s9FycQ4GT+jbacRYZGN/Pp KDuM1DWVOdV3j2isQxBLj3F7dl7J/uM+TX/xlI4nhnBvs14oQBrEvqpMo7qQNfYq tPUvEBqhaWEvzak86ePHMDEHt88fZ+I9eA15wOUwofasgs2lFBDjqPvr2wboEh/w 4luRV5hAaVYohY+FrsHINuk2zLuR/i/63CNkQ2+GN/UuZlLzGydHaFm7Fiyy6Zsv TOXatdYsA+gHcyBdAp7J2XEGm1vsbNJAMlPaKYvWXkV4K3NVWaAdDCj+9P9ibLsa oE13UgNlV2hzqA9w2ANKmM4njlgjM3kwW6lLjB4mB+TLu1Yo5qEeaXARHM/jpNAO O/dZ6PH7kgDls/l4fX6WPKzpyiMaxNdSybprLIdKrBC5r8vC79OKrfXXyeKZqTjT D6s5sDR8gYLJwIkpYxGkE1msDU54P3Y8QOQpMFJtGoZEPvr8Sgo2peFj8TaLKUDV QQx2GNqtGAAqxLJldGoFxb7rCSrvaV4/tFtLmnNMymIO/MG7LvN8QUCs7sAWxiHF jTifgCsAw0gQEeG7SJLVBtvkcGV9hcm8vXRh6mQiw/wVOzECYDiFupJDE15pMmEE Dkl3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQTayWnuF3dpvHngbHBJFLcDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDIwMDQwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCfeRFwGKzmuKMYll1R02Y+hYTpFtPQGnBBaeRIvuFR QaXomsKOQafjjigc6L9zOf+8tTf0/XYNbluqF5wcCnNQROmBuIR8o/p769i1RwEP htxfy2ETO43Ln5HfCw2WiNmiYIFrt1nPtL+p50m5GH6NC79Y/0bMhaHf7BHexKgx IQ9zhA8E6NSJ6Pozvra2OV/B8zxVu9CWJy0D7pnx5p2qk6sGxz+3WEageafGLypU +8kTlCn/C3LSmRs1j2mcnuzML6rH5FAgmV1EDCyd+iRqthuzqtl1tviq68Um4Daf 8VyzNZjfX+yan8hG9iKzRdkV37EGDDtyUAaCaB2S89sglHWDOXdqFrRfTP0oWHKX 9Rn969M+smmc4UIGJX0+Gck+Gnxr3TyZ31bV2VdgnFN3JUsM+FmXQTbVPJawUQ6t dFB8pE292oI+3YtFYIcv173fFn4LSC59QGYlgJl4QCGblmJ7VqLrnwbbWmmrnC4H qAhb+l1SJGuO2YS2KjUz7j0t+yka19FrKnO/X0RZ4EF+5Mka2PuWjvqwfODJs1PV V12rKyOWoLBa0TBDXiSsUewb0Nbl2szJNQXYxb7G/Rt96TkS8OaNHmCsw2n6NiyN b8IWZTyuyA/KgA+WxDowGN4VOAPhUkglx4Z5NTceb9Po2y64jhXSWkvXnaTuGFw7 FQIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFDhC 6X52oVhdImqnv94exS4qUE1NMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAcmSL/0AIT2i5OWzaIv7t5QKeoqhVIQN69VzU 6XbbiWPeT0ntuqk5Rk61akuCtphumJyvhwkpz/1+zplnE4gewU7GE5rljtPnTYB8 RL3aXFqgcmghi1mTXrfTuN0Z9rywhMo62CWJe7n+fCLIXxsu4B4vERB+W5AlkfwX KVx0QHvgSdQC2xlB9XM4NURDmyBViySG8GwiY0skEUZ1NppiFldH0soKuVJI/pqI Uk5OD+cAUpSkIiqm+qCWO/gYbnxnesQAsKaYSLWbJ+f8Sr2EtPFalDx1emdRLTnk pb2BPrf8n166LqMJf02R7w4kqRjQiSxtpB0jkiGuVlxRG0qlMgKWvsTxklB3yu4Q Oq5HbG9QaZ7vjVC8SfTZfg1LG16L33q95fNfiPcgMQ+qDvUqQ5QV+mFcigOEi9ly 0l0EQnZjHN4nfQlDX0towPJOpButAPd/e34UT5Kkqvf9O0+98bddzNxZgwSaYoxt 8sYvNWNjbE/Yp2HvtzFdnSMBrdq7CyDyoFkILBM+uXQIrp8xVUUaGMmvGtuQMryu iZYVGkwqK7QyVxTX1AZGqMMtUcZkZ1ZpFaBCM5+5A3yaPWDuR+rb0Y4AkhKjzyV0 ZDUdM5X6iT9HokjhY8zLAJf1tsNZehkcCC7UipB/RFzGWDI+LbHYaXVmpftEdO9v 4ZmcCHw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQFVmnUEV0Xu5GJAQ9WVVDmjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDE4MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAqSAe63H3azguY6ZBFb/9IbvSVTyisuTckXTSXXZXMy3u 6qIVGaxlusc6BnJ137SR1K04pWx/vuOOtwXx0g4t0OlQOopC/PTeRcg11WKIjedd lipIuCOz2QD53uN1ADOvxKPz7EnZIJun2tqwZ69myS9Du2ov4lQUfCb6C1ZwCbgH FShPBcT4pTEK7SscSRYNiyZou+mqAFdm4sD+RUbYR852xUBED/IMX0M0549oKkq5 7KMwLqDWhp3HUSs2/+l2epYHpQ4Nh67HtjC9ntbxD6uFNZTnMGEIY0PzpAN32CJE okqOwpeEeXFz4y1X7P3LDaLkGuYTMfKBfVnOOaW3NcvfxZWFKL3RoW8n5BcDuXuH G0FWcrZEM10KbAsrE7gH1KiewD6jaynDFIrsvNtdevwFf9jaSbVaTvzMYp513rZY c85J61pUv+0gtV5+UE+LtyPB7rY9rm40tOuTSIlmypZhA+x+3lQzfMN8ZQMgJ3sa rY+oFAx8S5S2eaQh2P86jW8niCQG0EhnYPlNkELkbZH3keoWKGQiZ64h7NwhKHW9 ZgshA0sb83kSyjzQjevemVDbNWsP6GFv13UCb67u4N2NAroOCqPm634XNYp7QZyY 5MCiTiuQlNjav0jXrDIDu8u939SYM+qmv8m4bBeoSChR+Ec6OCph+AyCclGoM2MC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSg/RGn yV7XY6MXqWUaiQFHZYucwDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAHQwGFR912OIEMoBoNjhOilGZCQ7LRL3jScMCzlS 1h30NI2kE8+42Dy0QiRzJqtfjYZfSS4maG/6ALK74L51vvDEw50vvN+0o/NIu9qy 2tYKo184WrvyH0iHhlkjiMbWFP38MbK9J9OFCKKTpMiNtDEQ1CTHaIdyLoQfKgtD Vm7E7hrdylSqH53+5TMiRcWF/EJZRPwUGXE2Riwr9MceFfpW8Y1qBuQA2Bt4FZ/j BwDgy+okOt0xaldEcxRGnYSJp56E03LPDof96xBtxy1rb5OauRQ/u6OEjgVx2mTT BHjwso33DGKm2DE5u7rO4uqCdPbJ34msYai/tILq1LTn5Fac+cq9NLfTwwpu9qfI raUbkCwEYXm/fA1Eyh/iVdXfg1LK5uJVuZuLPJBxQUzfGVqOdwdaNKXn8wQpedXs fAM89PwhxsdNqBB16xmNLtVj+vdvSR9yCJdSgjGALzVfURmyPq0BMDIWuSGGkkoE hIHNdPn3d2lmsWw1B4VlAyTaPkYFYxZfz9Ry+Q8XJFTdQktunum+5SZYOulpQ7s/ 8LQTkO4MHTcOc1d6EYFLMcwIhBHVwsK3siwBK6aM9zX5+uLwNn0QXVUXuQz8zBKu kLL6/4FyV3WvUHITIfInEsJxNrp3z95qKaN6kejdAcvM0mfW1ToSactvSAxsoBR7 Crjd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQD7y/F2GqKvb12iErWsqIHjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDE5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAhrne4/M64UPo5tEfGBkx0JN7atJuHGzOP5RWwVYVBLPB HQGM5AaWjji6pj6+djBR0P6jdYBaj1Ld7UpHN39S/LCQinxwaQtdIjN9eFkil23A jc005GlkuTZRZ25BFonhyeEfPlminzriUfiNu/TqsCHHJtUZmQ2XBAdebXov2I64 cYIae8RfGdRxkAYWSlbUzh/pWGKbYdX23TP7BdwBPlYBSuB8OpUN6ZVNVl4CISGe 8gPb/EnvcVyJYOEgtIvrmq+gEQUXCG8t0zo89QT56IRdF+JnuKEIOjD6l96pj0/2 pJHdwTATbDxm8G9tZcSCdIG4EMFeIAIgg2EkyWbEb8pDA8yYfg7XFsxaL6lWRA/5 9EDIbkFm6WQkMNC0ThdK3L7icI8NFdtZ7AblGfqntVrSgh+dtCVJuKFoiN8yhfh6 Zurcfty3UnHKGVT5m663CUhiCGMUUY8/8D83UKqNc9vTWSe7m5GHPaAmptZCDJV8 S7PA68ENtSY761ksZd7Qg2iD/LEZfcIcNQu29k9ANattAV33tkDhx3RaVz16SGFU 5xEEFhXmBhemktEUG+klE9//VMEnljPBS0N5l15oWNHY7vTKI+7EqceiaAbzL+J7 esQcaqnYGGV9vXjKp1wA4rl4AG/rviGG4fvQ2SF1QY3J/YKv6v1npT+L8fjtNPMC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSCQeYN v8ryW955JjfiuVVQqqJ7+jAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBADujU7pC8gBhNKNz0gZOuLfaQIms3aJUXfH0qzBz Oxsy6yT8ClO41c09FNqtZZHyj18YeMLbbdfmDgpq/q3/6GQBeA0XMd9oteI6ldj2 NbG1fmbwY3ytEBnkJo/b4ziJabrD4H8dlXZNKf9vRSbDt32bZG6Ff9GjEdgq4kLp Hnicfp8sEA6QPSCaA8KG7Xj3TYM1k0cdUcq9fr9d9PJsbEvDmwGqymLLb9uqX+FC bTh/oRZYLbw1W7JrrFZyGsGjOsfKtU7BFx0/YlKsK9qQRgHyC28Us3E6NNvpgzjq pFMBi5wplQa0GoF5BA2zJEtamwpjCAbPM4SllVL1lI+0y0BWKArcSdWMHUEohnzs 49DckXqLb3+7ozw8ylt+FY2wQQb4t0CIXrM3GLMaRqzohQPlio9P54A+SCDlh6/d Dm4ACBpT+xATCcmfyn2LtH+RKQzZ3jS4PfWvrBw8T/3KGITmj3NsJN66oo8pxi2S 9/hOxvrwwQjmarTtqWoFI5fk1lPCTm+SgIfh7PYzTjbo/xqlgbGZ3zQS6q19fWl5 xuSmfJczVDN+mAQjxbesSU4FjRkZfZ9iUSXe7XzmxQ1Pxy4ZCFfoyKOWpaboMlHp Nin6/pymNJKMRFfaZla473G59kviRrC/8kkBwvILED4+RnIDMIN8M6ZFVJy8z53U mx1L -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQf8LTW9Y6JGCDHTNtrx1OzjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDAxMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAnA2MflXHv3y6HobfK45jLcEh9tMcKuERrSZ/t9jEJeyY TLfQrLuJ/lX9fn8qk7XfrKtycvIlXKNXwQE5Li7mdp7hnx9/NcB8exhx08/+plZ7 cGoYpAu0rVhjSuwAsaUj4pJ6QwBJUC7m5drKj28SVzFvtWwk4RJoZNtvGmoKtjOm I2igK5uJHaPN/KXOFmg2jjrORh9MsQKki/94p1ZPygLQrl198prpAQM2+zNBGDKD tfiSAzcUPWk5ivEv40hKt5bNNHXh5o9RRA3p7oU01GyeQtwsNgZsUtx3D1StBKX7 WJk4OXckL4gHvQ+OQvvxONNf4EetkMDR0P22OcRjNZqIEeQ0x8b/983EwkBHhsX8 W7KjuoXU7n3QwOZWZJB7ehmpRIYSKCDHAyw3xhbcVJnp1jOImpFzi9q2mPmyNccs NcXBkV4W9b90wwy7ud0uERTXutCdXqFgdEY0TkHu7edh6cHsSkQ2CsLR/odDjM5j JmpS+s29yl0JucA1i2sKKdR6IzyrrPYp+W1CBTN+vbgJTDmFJ5JfZH62qjPZAtaP oUcv5y8oA91rMQYsnnMiHQaexDXnlUivbk7rfdK5dXaKC+O/IknzyQ4Eyrl2zA2c NG+hGcYbmCKzfGFyJHrFzag1O+efrC/F2khAO4ztJM7488faUHhqCcluK2rhfNsC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTUDPuj Pr6nVh5j+iuuTkr+cMmR+zAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBABVfH3hBQB5nOFvSU9H0PtnMNNc2+FclTgZv/I5W 2qb2Eu7n2jXkH4KJXTjUMDoDzkrl9S3OKBZedcteM42z+OtXlSSKERI61dL3taHP f8fSK5knc8eS6zyX19FpqyJjnHDGO1LhJsfe693OL2yMzn3Fg0IcdNWS69ecHiCP 6j24lKe8lU58IUaseShf70JFw2FAR23TQA/3HbdTIHJbGKn71sbROTj22LZxOII4 2fDRWj8Oof8QsCgTAFKy6w3FQeWXO/9zyFPkYybydLkS6tpgDgBfHxNUdtX19nHO CwOF9xDVsLFlQXdQNGWvn/JQ0jnRPcb/2jTnsm0Es7nyQlIhh5/Dj+RLtNL8tjij FoYAnAwY55fL/j5MMa3WpDgnFl6ZVDh7ipJuZGZWs6wjTG5kaB0Lq5VmAs4OED+b 1CvewKPR6vRq9+YiPlRcFUrKcJag5ZPEw90dzgFcGpjIYt8pWsxryhqx8i+ZbIlC AJQFFRjScfHiLX5aLObTUijfHyllrDnRGb3J9RQNKa4/5XK1QyjY69a1P2ivcE9L cL82ZKkOhX69wnCMzPOLC29o6TcLHTOpq/LGjzeCvlVV6sCzF5LK/8SDDiWw4pCQ 3yH9STwghrzEiK8Jwf1iWdPvJriMh4ctCoI3ZXSm6xceU1NCEF/rS1I6vjBeQWj5 srFw -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQVYW8Ke2CeVscfic7L/x5kjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDIwMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAnOTE81JUOF5/+HTxL1cYrYZYVE9v30AxC0MxahLq4Rym 4CqkbNVceVGoYD9zPG2+QW8jdVp3hL1t+0vqt6uXQb37wKicvahX8WtoLrVChS6c rwiaNf8mKjoaKK2JnMOK1iqqosX31JB1wAlBmIEDlFckc+vhq2Xf2jcgEAFLR7WP J/PjDR22az7vWk7RHl28vydO5ds6ZLVY2yOS66oCq/nuczZoN+94btNRCkpAOIzp URNPXIn57kiRJ6KAcTIKZn8yDysZvi7+tWOUi0uSI5d5HPAapQWfJ/wJGwlL3glE +VTI+g5tmbv3dzG00VoUvTVRLEhEUWCEjGkB7awWL99OaoqI4uF12J/+mjBOx6xA gBpkHN7wCDNQHxklG3NrRUFmh4qoCh1tzMyVqmiWNByGzHoUXiixl+IGM9fPQiXX y0v9suq8Z7D/7beGv7dRU20Rtqz9xf+N46h5CoV9LL7S0mmqMOt7AKjMDUjnOa4z RneKAGoErsIK1Fvf3JCSrn7uLheQkXaiZnI23haUH2Vr8njFwA1IVi6bMYpjHPXw VlcvhO/Cmp0nDiGd/VjDQdTb+/Ep2GVwloOQ3u5zHiwiotR2BWhomDU62FXyBxy9 OAxFYSsoSIuJsuJyXDZSGV13HKbFDQ4zyKmA4QMcuqzPVPzCpu2FPb81BuDfDyUC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRmCgLS A6DvOsJOkww/Tv+Gahv9WjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAB3E3SDn+90c9Dn6dznHqIZx1Sp5A9SJbQRj/Ygm KsJ/giiVcm7zI8nkztAtCINRVcAPMlUG5XMWb2vs6d9zBjFDPSCtr1rodWMRRjD1 mUg8oPM6ZcL37d8cR2+pM8+A9cOheYv0SEY1dWRwihUq9tkv3EyOQuGHOjQxv7oC V6qqmAA6lekevRTXZpoVaAVHc3wHSOdUyK0lt5T1b71B+MUx9RlZszZsjPMTZWsX 78i00n506hWJjDhAiFs9vOozyL0GMWR+scr8uoH3BzI0RrtuZQ4QEkyZ7PfT8iJJ TkfM5DceaHJS9RaWeLH5IrwYwM06IFsU20nHNmewvj2u0UmlS7VHgBs33LOpcap7 r87JetHggGmVyBi/V0kLDdW4lF7jsLv7AbPC/hC7hh6Yt2IBG1xgrVc7WrwJrBXF 7Rvp70P7B8p1MNcjRH4YlxV1lJpUQKQ/9lL239UDxTavgLn0Juk3jCVbW6iZhYEU K582CgVwj/iPKsXu3wEXUE8jpXlYnj68yXkF3PxfDxC3OxabDXTrLQd4yZYBAa+0 pFRR5YH5GruFNpu2RenhTHgZckpgeIE51lE9CijWxT6+d3rbcHoQqXI+zzbiIbV+ 2T2GTIgnDFYDtgXEoaASYfp89iABQicGk5oAFj9kgQLbKnh5m1XGJxXTwH2I2gfz e+Jw -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQA4psWB1Y2esAy85Gc0D29TANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDIwMDUwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDERJyMVwH1LpItJji286j6WabNc0GUvVju56Leveb6 zm6zQTPu/+Wt6urADaErxSlqxxedUg+U6mNUAxrlnp4pdJAATOYLptuMtuY8ArIy gwyaN4+Mckxe+cK8ujwbG/7Jw1PkFitWN8TN1bdwTdj9o6G56AtyIlIX5/jfsHTW zaaX1MzOkUWoMC9oecQjELA3NonbbducLlvgC9MnNSThr7v89+EJr4GLrtl02gEP lz+NQYKTkTgtTKizuxFSKhAgPMomnuuhQ9f0ip5jw4rBfbYHbxXDARiEtnkpZ3+r 55WzuYCeLuIhSET8J/k7vTmj5Uq9KTCdpL8hRXqTMsR9kEPUOQ4qyrHJrBOgtjXv I4NdwXFv4OgApPTcED/LZhaRqm49VG8rfmE0GoVjiSbvANpWZvx19z/7sBT4QSmg zCAZOKbBfpUhRUjGqoZMs7xATl6ToY7vhq/CGdoC00ra8JtGCDw64LNFxlmfjZgS CZ5Q9b3uVeVsz6GPJMmAoOS9zCAXL51GhKz25Vh7r6B3tbVWruD6JQ5dQAPzGPzN RxP9aTvNDqptUZVGemTweCoKXc4HXDkiOzev71lq+kDbqCoUmTyE4geYZp2Cjbk0 1rEfjMVKZm7xVB5PGNMZfryVQpyuwtzyxLxNK4VfBNxybqBixJ81IzDtNAmzazaf vwIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFAFD MVI7U2mc3ROLnjttYjlSJO3TMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAeHijIfGttEQjIv65TiaY1prtav5c/Xop96kn c9tlQ2JtRuGrTGdJyN8fNOYmHMV8QNpNlA+h8OWuREIzvHrRIpaA++pUEMWwy0rz FRMO4WzRmc82/JF2twRGXVZGTmdx3lvbgM9OI+ydrYF08O0imsHrxQhogRlX0Xg6 VnNAAgsXOvXIrv0i3S5ZOvdzRsZmkKcRuZvhs1CqZfnGXCQcDjCLLyE/m+0+2pGM 8HiRt78Z9fzeNwmXuuMnVMsNYVnenRIsVa9dHMqCWHoVHb+IuJpMSwzcp2WwYqap 4zf1k1afZEli+lI+oJ43+JpTATPI4O2YHx51gIs0v5CDp7ry+bkZEUvktqh3l30o 1xeYvDkymBBgtII0xVUblDpnRgLHjITFLFku2Ql78QipkP6CzP9rz60LR6htD8OE aYxnAbawpbku4o3W5/xOozYuWgAcoCVCliiXYWNrLxJyupebr9jsLwIEWdPX46BQ ov3IiBT8oim7bGOiyK4axHbnzPTdoxi2FDnRyZdRMZjkGnT5A9rxbSiawLDsxGZV LhnJ5IOxXkUhdImyupQV4llKtaNrHkv3HJC6n8sE32b5/HL5xP+qaODQuVh2CBZD 6aGozBTRWcif0e+5olknVGV/Wm1uWjCbiG8jTSbL7QE7vKPA3yisKHyxDa/moJZi DZVf6Z4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQTyw9k2ZXM2Ojr6w//2Gw9jANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDIwMDIwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDJmvDca3GrBeozT6sddrqF9Aby3swCruVt8xAogcNq QB7zj21SMv7XgsXBZx6z8oGBCP/Mw8Kw6Jg1ex3wFJnx24Uf29EJqWGQXSbriYDk 8UuF15EqfCbUKUp2qhp37ia/o8xBvGIk6fuS0lPtkbHW0HdMGymc7Yrzu9xfjPS/ hUSNzHRGNl2bwGErytlTuJL/k2vU8/3HKEHWrdOHxemQZRY6P+/bUoI5x8nNGZy8 gqy35LBgTVw28JPgLQVyUwWAyFuXVeZugsvIn6En1k40lG8oAGOkYWfRw8q99M+8 OdmbpOoFR96ir834obsoV2D3p7ipPytcV92Otmz3veiob8HRGd/TQe9VMxYQTtqd C7QXFwO02vjXTDHC9Z0MTThIxaFPpkmiDeLvL/NY8Xck2opU1g3l+hPdHNjD89d5 jNKCNBAV8O/Ccp3c2oWxbDjmugf/mGwfD4Ijjuf0cD/DRjmohKAO6ad8jvIHPrGK U3bvSpU0sRDUvwyKeD7zoFbu0AfOKkVQIGD3yLBf0CJXaCin/1z/KCOoj8xUX/aV rU031M2LI2+iIVk38JJxb9IdykwRWfsMzvDofNo///isemVVahHakh6AdX/PqzSW YMkZnDTlengaja3g47GsyFWpiilqhwNovGZ8m775/R2n8wfH8Wf5JBrNgqQxpaxG NwIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFGq+ OSADnE7G+mzaHju3dGvyQ/k/MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAEp0ISHoqT2aDC7M24+gFJ53BxeXVxe3Llr2a cjrHvs83dfjOgv3pSSlSXLmjaADH//cOjaDCgM4zX8/evdWpiti6UdZBDoRfvw8o ZN6kjtTCv8wKdNgn7W3O2By4UpZURlv0dGWjuNa0d038JpWLz+n5iIh5Pzcji7+8 ahgthJGDE7HWpdjQd1gt46Amw5fVMURTfpF75Vyqjq9SOVRKMB9O3eLwtZHK1QrP S9UMCcCEST3jznjN5+C25kvBKEexVe+zmT0vfT7BdiMv6zF5DC0gLehFJQKbToQI 3uoCaVgt6FhRze8QSGQaWe1KZvG99eRQ3ZzMqkNCy2a7KvAhbIRuDRPCIcinHuKF rmN6U0hwo4/dwlo533QqrziZF4ywX1Xe0QzBWwGOf21OsCmFge2pzuusExna1Tzk 9iVy0espWmNso+M3uskL2iy2P37dQsgg/ZhOlokvkU4isNmozHF+MBlZaf6fCG8n ++McHWCAb6fc3z4r7JkZxa0uindBG59nN/q6XlYY7UHpPNL1XImfxuOFN58m+nUL 3IPN6wlaQ1hffvtfBn0/5HIEGX1sGz0SSV7zAu8a7Vre9O95znIncc5am/bSSasg TzZNvaodgIst0UCTRq6nLnkRd0J17RWuBR9h6sIYCNMC7Xv/th6y/SOfyD49r2jD Km0J3I4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQSapGBqhuAUr7IVmKDs1iSjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDIwMDEwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDsKpbx0OXArCGwWAT7ObWJKTYtjoT047T8E/o+Em3l CojOI/tw1gYY28V3KRwwDNJ9BREYnP574VLmyfuCY5WQpWdWgdwLj8IPtjO48V/W YIX9ATNv0NVZZ0FSfaUmYV6HeAo1zuW/K9W89bnmvp/0HJhLFo2xHNzCwqmuREv1 +HI//Q8IJ5xWhUD7tsv6meN/dVNhsoc4m4YXDw1Kbf+cBPc95cigeNLRBqVxB7Cs t6Ko9FiLZa1u6T9iWMfVqw9WVV3cxB7umYfXiIBovcZGLyn7mbzEaeokBIDIn0+k 6S7GvE3vp64CMiUWQzGNkwBb7oTMpCaMS4vKJiIDZZBKohCK95FBm226VlilkVFg EZjYRvpbkalh/uzTe+5Nhi7MpeKYStD64/3MIci9w/CxxXJhZgase5Vp/6sHJWbL XQvH3gyGzPfPbHPAT20SEKnbq65nXOuPU//r9FGy9RJrVzXmB9nsgKL3C7QSR15e TZjSrXFFIs50KQSPVbZLFpmqbwexniffH1l9rl5vOhk3YNGnX2bUWHccopMppVg7 gCNfqeAs1vmWlXZ5CVN37mYDbw9fjnTufhT5xEraH4GGypqbdhWHB4cAqfig/9SX LOm65eWTPH97NpVoxj3x0zBIFRK+YZOjYigzNQEDjlYBgh1cov8TDffh+/GPMT1T lwIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFEX2 ip8uICsFKu3RqziKeEt4cIqwMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAIhTF4xT0mdWw+L0+CSQM3YQ+JRih3mmMFQFm CBR4xnzK0Ukj2bsYVHJeZ7oJEAdJ5DNbZFHGkB5IOzMFGHH/wWg1WFKbYb3n3lYD GxEtizvZunHKSx1rHfTOCWYW/5X7e7ZxYuYKwmLg1PsUBcvqFwB7Z3O/HjXf3RyX vB5NifEDskAxSJ0VVl8OXMMAXVpAffJmMY02sbLkGt8OYA+NNEaQPvGz3iJFqQNd hOo7sHCEIArnShKILn3c174O+80fpHr3AT/tZmKQ+/dP+UzCUKqLnWu7Ip/6LpQK UWK2zvkSNRvIbzFTzD3tiBa/DZ+Q397+MTJMA6v/VAFuFrtGq+rOOb3vZAc2hPcB REvvEpRr8LPZJ5bN7uWD7skGWuMj6l1/IC8E9eqaMeZiX6zndORm6QJ+VcL7q0ac UK/VLjscMOXit00YxOkDhLTcLpMUjlr54cvIXL7OYSPJl8RjHjzLgW9n3lXRCICc 60ZP3srqc5t9MlTQ71QMAQ8APNIvTCWxdu9nHxI970zqJYxsq3SIykm68VrLPDlH Ylv7TVdNuoqhTpzpixTs+EKZjMyGWOu/S8+uhX9Vv0A/OryZPUtFbeTMnSkt7LDM w1I0OGL5EeiZ7KcLPuY35z63S5CgeuliUDxZTOS4Od+khdLz177/b7gbEZGb7/n+ IbCH8Nk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQBNxfEbr9KweAM31yzbNYPDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDEyMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAvfqZM8YQb5H/XFzXHBf+GyzKhr+QaByd2a+GA6SIxwim uHawysbScnX4EHinVo1fNcKfSL9RgMcEyYMhPW4jkAQ8N3wHpCNoz7g60dKSBC0B kWbHltg4yLvlLskaBu7YCDJJ9NnHfgI1UpvWSKZm+aSClz5Jv27DDcmAxQ+noxyJ m0BgdksABqc4Aupu1XVxnSm7rhbWe3zZE82aM7FCDvgf6SO6Y0LlEFbd5I8D+xNt +xtq8UHOSXS4hMZWm0ZV2x5sBJ614h7BTKMoJkdUSbti6+KKrrVRXYs0XudSvueV 6k0k7kwUQgjBc8mFnMy9BYEahw6xx1rKIZ9boNg7MGE0LSFeD0NOaP5PqbYMZqtE Jmi98qG79ywZHbycydYIzM9p2x86XwANyW1Nk+2dTM+vpnHRCmUZDWYCKmP2AAQs Xo+h8+y7dXgmRAnbH6SHPnPZmmmF2p5ipaY+GQyH4hluUwEMqH+WxrTV58DTTQFN kJeG7zktGdJrQ04tKmyNufBjg8TDBcUoKAW2CZvUGwRdnHjBEXBNIkMQTwFVSTrK EHeu2TYFOnXYiJps3Sxj/GnlWYTBFXNCj7CVOoHeLTin+8wzVwpvlK12A4miH2aR FpkIYzf08MJ1OgKPeiZENMMaFKdAqe4OBxAahSPz+yj8XDL3nNhY+zO+hp+OtPUC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBR0RhOh SExS2HAfOb0qnc3rnfp4oTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBADStDMTLbNe6nZ+sQmEdStFCvk0hH4aviyX+r8DF T0XZ0KvQ/e1Y7yWI7GlmjJuxvqbHFN1boRuoP3O/UTdzsucrOstcwHfxJDk0Yrs+ feDZ/rGym+LJNOxliInIrqR/9K1Jd9/kWpGT6hsyBMhUPU0SbY+glhn3rNb5717w yhQdKSxGvlQo9dNAWCP/6eJ5lzgYfxZtQCcOji15VmOag6KA4rzXr/oOwAc5kT+S aSsRF72896C+/UVCkvkp5r5vKl4zGOBnoEWyCj58BCr9zsMgnRYSewuYj4npzSFW B1EumMG1bAHJXZmTsSYrLh/L9zZvvalPDXyDSKDBbFNeYOnvGoJdkcMxGyWEsuMt CsnlPww9BnScpMPLRbq812oRnKM/MM7VBJFjUxLVio5W8lVnhJe2C/kgAYId1/qd I3gplUttVgF/JibdPU3DmZjJYRHEBg+1z0Qn7l1BldhMSpZMFFdXrGeIr/9BgHLX F+4VjxAqTyaxpko+KvDmx05bI2pDQSbVR6j9vPukYAj2o5jj5onGSBqGDukpUeAy 33rHK8HnlFgxUKvqXxWwOjoNZwJXww1m5UD7nUY6dDlu3vp7otdyWPsfGVwPWvI0 lbKo9LwRSFPGRrLjubIrzR2ga5vjdPY2h37KnLNrMtd/SQ7W4/tFrMMKiT1PFQwO DZrG -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQO0v1MnBxAUB5EZBZJghh2zANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDAzMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAoxv98lDiLMT+BOwocOkzM2h3nAoQujQsOzozFfQsldO6 WQhW+9uDl5/QSNx1ya6pZwvZc7bZUa3LQIe46LhwyE70cpP/7mQi4Oy92GdMPz3O qu5tg3WZEX+H4De+n9eAOi9wDl0i13xIx9SSOjHpm8tKnZlOCYUbdG9XOxkfUfWn BqXbAdZVkFzOaD97TWIUdGyrD50v6coOO6ebpJiiON+n7IitB4AWGMDEV0dUOmWn tZhkeeiIa+zJTwSryskm3Bsp8HJH24i/pu0vwwTa7tc45yA5pKQyuRi96IlhwIoF MZsDFYpoFz2t5tzoxxCdI2aOHAJkSR+kLFetITK+g6P0BZm1IKCXrbacHP3s/3bG cGUDJ1K9+N+fFjGuRMpRIOm7NqrYJfliOfC5m5IDjYkQcSEbm0mkr0Ry6jalFIm6 SajCiihYFTDsHG47E2Q+GTI+63xuwx10x52jnbv2c5lkQ8INJXyn6245HjIFC8jk njKK56rrniMxwdFygRRwc09fkMYU6YhfedZUaRGQzY3K3wjv33X2HDqC8LsU4DPj i7lHaytZkAvjWhNndMHKBIIEis77kL9UhXJ3ml/5RKydZ3ZcvajHOc1SDnvaXWM8 RXKfPUKiJ1FofXDbF15WgiY+OfRL0swlsTtRTV1i89+DRKwzTG540MmFgsg2JicC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTpZZRw L9LzpAv4TNi/tXymU7VXNDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBABB8UzWDgfykwZoWKqKLAI9GXTOnBw/71Q+LU9zR bYS6W6THgxcFUUariBLfrLgzwB3PUAcAA1TjpEK+3M183s3u34QVQIlf8CnTLLgm 4EY/5fGm5dkCEvBUVkG9FX8M+Iv3L3xlnlkQXMqpjw/860AXUixoRlywrpDOhN0p BIS5en8UT8Fav7eJuJl/RmWU+X7A3PY955GilsykkiG7PVpneNSZTXY/VZ6cwHYd LYlF/FnyuU+VrSm4dxWZsgv4oHqtik3UDVAtyGZCSiTSNQUmiR7la3Qtc0AYl/Nb QtNEAF0qaV95t+4wIPEX5R6Pc04qGRnUslG9L7eXWxtnt1jojJ4UAR+NeXE1zjD5 nzXa6r720VKjaS7+hm7QijxxaeGyFY7VbuK2dNVv6Wtmf7Og9EPXYxg6eCpBbNEg kzkl8J8zYYenRIkMFCDYYd2UCUKft+cC7xVSoIc7SL/UqDdx3ZOX6oPjLRP+OkfT JAnUKxuy4zzWb/qvx6jS8NDn+7+UsZauT/8SFZn6W+1bJrc7vls8QKBeKBGkvTMG u3tvgL9ToPzJU51cHCKbPERFKrY8ZmGc1On8nJcVq0YDEZI3zz3i7coxPvNkzvVI +EyodEvNoKKMuOvePLCTa2PiZlRTpDmV6P6mYa8Z2WdMp6aK1PKk75t2MxXWR8V1 Ww51 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQVkcXXZpFYn8HcvaHL58MsTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDE3MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAsnmjVjRhHwS0rAkzjNYMBbHrzRy2ciwIho/S+n2I6rOD tlbnvvD5sFEf01QRq32yeV0kQddT7OBM55GxwOUrcEIyRvBof7ajcIXooQliadv7 99cGmuE7KMHhd/SoEr/Ps5g8Y5JnlmFK88PeX4j5a4aS10z1UCj+I/qFjnrfCyY8 MniWlTadrSMH+TAxtRW9lAgIrraFq6gTE8K/07biioMMWeOVtLn8AsXvgBuiP7T9 AiwhwYxQbduCzgFjFfYHMiyqAGaCMjGNzsBtrRGfEKWubEcrwEcDHnYkxQsznHRT kyx5Vyms6uYQG2S9eWWNhAzJpQGqgYiL2fzse+UOiJ27re9Ee68AcnmD1c66b5+e Ovc86fZTGNXlWzZQhg0POcWL+PXuga47+OK/n3TCSfmxqv+fuI2cFNy1CLlvOG/Z LJ6HX5iAGeKRU+DXAF8I3mPAfJgqt9hfeL0Cr+1XGgtYDLdBkq/31pVchvJRaR+Y 8s78FHm37z3NzGXh9XEt/PkpOlvvNC7N5Kmzfq2XZKIKvVdaand4X0gyPpSd6be0 jftxJiyzP3WC1EC/Nb9FbgJDxQbohD+uThNJ6eW3VElyasTV7h1y35oKRrS/KkVs T8loaSJq98+5oL3ng4XQt+qt9yqHAG6kUm4/gkFVGLBUTvZEbgkXAuTRMb7IXf8C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSiIVMe XiNO0nvLOxW9uLIl7yABhjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBACNYRJpLnQ2DFIA/GWDEawooMTHcSqRHOl3rYXFX 1owVNN9xX6GDJEezpZU8bCdC+sAsp/Gcvxpu+8+a+qcquZypYFKkA/CadVkijxdk I8nxzjTc6hxwN17WFqFLHyONEEK9CLlXTrheychORB31BIQ3oPP0a6nX5QZAWoj8 /Eq74QzVy95zB1+9kk/YxubjPWCNthgK3q2RAMmdxxk0cFIjt7jr6OhpP6E7KjrP g/MaILCz1EihkZEtv66uc9XlDj8WQuj7yu3+Ax3de5QP6vEeYsW7euDQnc3Xuogy dONB2LGZ1PndV+NNgLLucV06vG9kDYhezdz7IF+psP1NvqbUI/8V3s5NqJfdiu/L aBYydO2ljvcxfsQseKAL4A368uIWzfqATwDnd0A5tkbl8Qe6sfqXgZTEhZwBvkDa uon7RqEgVRvC+lsjyC9V9Vh5EZUSAqtHQnoa2SenwmJv9hPrM6E6ixWFXd+UVLkJ S0DqHKUBpPocLq3ymbxr1rP/L8MGYyK8D3EC7jqci4fTNwca8PRMbTJJiVz9CfBC 657LYog6jgnoUgiHJNYWqh/huEgNd8YNVmHyErAna8f17AHmHOo8cgJZ4P9gvy9x 2c1go0BuiOjCQGkaq9SwcMnX91J2WpUOpvN1zrFEtQw5V4wvHpJki2vdHJCzUI24 FO72 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQL8kr2nlQ7yyWnpNoRb5pRDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDE1MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAtMLnQN15eoN2dmFfj7InfsmfQCsiHFEa/Cs5+oRhtKnp RhMomVJG8ObLCbbyWexJ+4Y2lqRh64YkI3J31/HAatncMWPN9cveCanZg+WElcWc E5FJM8Lf8UkHvPq6ElmXBANUZin5GfQOqYVXIBN5QLcAgg83sdWfCZMSQKs3QMFw a0YQtFV9aGqEf6FSELjNxC+iXR72sGpPhHySzHh2B3vZo+YqCQ3Q0CCn2X3Iyf+z e2DfaiN3tHU7z/oCWK3Sdx45SKv75nar25VgmhQXIBPjhuPffRn0LwaLN74orK1d d+TpJQD+4nH8dzCLoQTedfUhKn418TXT8gas/mWhWNdJp90WBKuRevfzTLSWeAL0 gpRtNm2vnsqLCf/T07yELrdwhMsY6CdyJTcH0PkOhJGMH4BraiSjqxsPMC0BnliK m3hkKK06egFN/8P40S9M+056mW59sNt9kBgfFLuXTRNRb/Vu7HMyuEW7cMRkhbnt SzxGvD1WfJeXLM93t8FgsQ9J7krzM4jyjqcMXiKQvXW+IeCoBZ8wtCkRYJsRpHzZ 9tNPKAOKP6X8k2sjszX7tTO7HHcBwrELFAXnqVcY5iIuDT+GiUK8J3X0RuDDzNWr BpodWrfQP4Qp7smwcs8tMOQf5qJNi8gH5Yx9QE7QfA/+GqAMKNYHNhPKBckuylcC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBS8s51h iOkfzYmKcyvJw5HLc70a2TAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAHfHEQleFJCgeM1f0Iu9AYdpfXkLDOakpesF05SA o/uUOsV1EYyOntp+pohA6axETKKtNfY5qmTq8D0clWHJajE9GZa21DjT0BajuUcY 600KtgsXnaD7ypkoyfX4RlYHUf2/7TRkGXgXDeE9gSYiJF89ECL3YViG/ORV5E5l leBHQBint9NMo5PO43uyNbr7EysW3I7JUVYaNHXo/BrN3ZKFAgM5JmDeN+Yn1YWn zuyb4io2uFLnLaJqsz0wcoQ6Tt1HiIAc0scZt4P2faMvSb7Y6THfEW5XnTm2QKv1 KQCnOlYn6okvGxwQCq8xCJbOEFkCMI8u0gYub00ReJSUxY7t3IYOUu+KQquKAlJd 9ZasD+VYP8XW+WTVSrtQvmCT1JUlKsu+XpYZDvuGG1i/2HPq2xEOFBAjeZdF5pE/ 2lMkpBQdo/+lQopCxZ7gxISEsQtXukAfkwXMhmCF7+we0c2Rmsr/oCBxhPiU+grl SQVxB7BSF6yYmia18nDw4y9qwEbur9LJZEX3RsFLiWGLAK4gh0hP4MjZQZZcuMYn CsHmYPTKYmOfOGFPJc5ctf7TBREbq7C0oyf8kHUXFyTvoJmwWSoZGRNjiP1zu0N2 ElT1xR5cyhXEAayKuGTwIEkKcbUu15ODlNE02EgchIapdtodyo6e5p/PpV/k/L/T t8zW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQH0YSYclzBNuITt7E0tIY4DANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDEwMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAqp/48dWzNMU493jLFOL2Tsh2wfCuKngRtxaXb0ekoZz+ RRoXAMMtrsWQEy9e3UBmFfOJFZFbEWxJClABov01Bp1cAvQw+Dd9Wi8/ReOFKRJr ZyzKMjde+Atq+q8YRbqWwB8MQNCfWg+bEFSrbBgoambnTnPeIJbs7wWEY1au8gnD YzltFDrqvWd4kSrAUIV45tFCJJRythtJkUQPjiuCbEKhN+g3vJxh4LLuI7poczjb 80COmWgtNutpGU2vIvh4jXPJmyyndb1IF2FD3VvhFHzNZ/z9DpkFotS9AyKSRO6h a9apDrZQfsByLarN6gioL67Mx+8whr6uOmb/0nQVo9iAUqb/dwgZwpPE4Mcqb0sY FzY04zafUc9bYx6qhk4iY5n3AycA+LIQjQi7MhHuUPLtwX5gns4WMFmTPgiE1Ty5 BjBEP+vLnxIUxBrzUbBie/uZKIBcBzHPu7DDwhaDc06njyiKUwbBUghcJs69Xqsb hIY4UZKiJSbW9T2DV8rxafpVa327EZjXTNSLfVbDxKEBRj9+AfWqakITx0V916Jh 1BggIlNsQjtrUiLxYVw4vKmJCdATfjJBMjkYH6j9O8tIFDQ5VNOP0fAJj65UMArZ l4E6fpnpHmrlKt8LLBrMN3FwfzLTv5aIh3ai+OgqgntAtm9ECmEqTSP3zB9Yz6EC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBT7bJzM dqnSt2ci9gcsGjW67+wNqTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAAf3PGc2w/9JBRPqGU9C7lF9mKu7bckmUDJvac0Q jLxKOmz7AN9x2+AXFtCMNyLxP2epTZgp42Tg+uArsi9oKKFmplI8AET4V1PVPwDy O3NqmCsQiMquhbWC0JmzIyRoAzHzTVAVedyYLrn6zgGXoevfGAJsZJCIQf3H9pAe G3QIE2K+ndrW4BtphEiGc9bD5d5+5/AduFZ4EXCQ8xICV5dcz9TdQksLNgqCjsBx 2PDjzg83XceR3e+slywIVq7gg2RYipeO1swCRjxdvNfgHZlRotIxEGDuZmnFVHaE k9SsaHIT8gmOkxuUmCFsLDITGokswk5BhVT2WCW5tER5cqZiV6dYtBZgE12X7lPX g4FlgKT5IfgwPVw1LHz6tf3415fzHcjclzAAAXYyEMePBba4WKwlKmefXixHDbHt gxuHg29s3rAeUIxcoY6kCBn9AUUD8hlvdZOTPVC/UWPpZukyXVBa7h/KeMPJ35lq LPA+GnIc7UKSeuL4ueOd20rcqspVe4JQgVH/DgOuSjzxpjFB3k5Y1NV7Cy7E6waF HxfV9f1EnzEMqbltvAS2MeuXLFzFMbew4b1hNYAamCOFZMAI4XnO6F3GYrrmwF6c RtXTjllTER5B0EmwjTokGYLT5ck/n48zOz4rUBTZwbh7nbmYrY8yACyT4ZD3irBX 37SA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQSxRd48Csa3X6EsG7rl1AnzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDAyMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA2L+b++I276+PWekm7e4hYqv6YiN3CgHjXfHmQckhMhEs iRVEIk6Af4MnTegnmY9HNuXB1hQNzK7SMxrlAezWv1O8ovQUOqTI3DujTQidoyP+ ro27ryke0YybM03pM7aTMWQL7r6fJo4sASxvD27AtSYosj1O5hCA82txKJ7H7KOE xcHA1D75BsxfI2mksrcnrN2A4gICp3XaphStQ55Ns3fVevqUfj9HvaZ5SXJmb8CB Av3JScBeFVPQpGbqusBL+Sky2z6wudCvH//dQBEP831mpM1H9DjwWnnRBYZRN9L1 PhxxDhwR4+BSWYMIzZNJDhMq2P/ng21OCTD9guWLKIu+QPBXehxWICPmFun77UVI 7JbdNWlE0/cXR//kucIx+8YMXwIzIR9RI4Y1Cfl2rQDKNVAtCXQp7PZUWgJ48iB4 v6tMpgjhLlrHtRi5ot1cv5JGOidax+/wQkr15MspOujyD15FxePt1d0X0lf3+KTv L3fblSO2cLI7L1dsR1Db/+TBWRD+04WJ5ZjbyTeJJvuYsC36rp2U2btKrZw/y0hb RfIB1j2o9IuQQXRG9bk19PKF8/hJUQ4IT6iUmCcm0Idq8zrcw7C95QF+JKfhUqEe oVVrgJ5EKUXwb0kU7Z69lzfrAeJjNAFLWvsiDQO/Ssu1CPT76j6J43j4Nvu+2PcC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSSrEa8 5+nQJH6gwvokutB/Grm4CTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAD2heT6NKvXdOhUdGOdX6PXmg06G8/spqMVbmav8 hdlCfqgbXB29Z052tLz9UC/Vxmw8pjkeNcjy/wZDq8THtp0Mgy/+JR9RKttcg+p0 EHugKF1gxgV5uognN2Y5zv8cgzaYUFj75ktuscXhTcpKbTBYyEk6YdiCO7/IzF+E yTLL5jNvZE15XDDBXNaIY9i2SezC2LrgsMJV8eX7wNG4wL/DeeMKk8SD0Cw04rKF MGRWghZs930YTsBbhOwVXsQl/pHp+dRPQH1YtzhcRy++FV8+13s0ELpE/y/o35Xo NWO3SANnrb8bslaIBVbJFVeRW/C5OljBL7uU/B4yGyyMf0FcqFGi91mhYf1bFxaw FJZgIcfRXDqnzkRBsx/4/CixxqGFfrtEuZ3HTp6KJVlT2RRPd2yW3rKh1CbDK6P1 2R4FIzfLJyArDsmgp75TxZsWYLfpJvOi29xZQIBosFFu7jNNGPCsYHmebzqDLgxo iFSrtARK2FdTQ2Q7e+nR5e5MqsqfxMkjdOmbTSg2L7XUeBEYTvJ/5yYJW44fB+QD 1wCS9jxSq0JVEAt1/9rO4diVkTjH3Y0yTYjl5TOflxhfkREw950BmEDpZYBvca+N Km8055v86gvwvXwBTNHFwQ7KsjBxycpfjJoEUpIZD9u4nvgy00o8AIS4ECiyNQom 3G96 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQRZKy3MWMDZhiQnFQEqIStjANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDE2MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAqI2a5sJp78m68O22fOyHr9o6VF9yA8E07bcbEb8re9cO mMT6+pUss4DcMOyJLws1o2gjrYUsG3gDUB9rPlVe1+kCCR5h4Kr/MGq1jkGD7NLc G0paBKyiStes1JMrqFsD/KoJEj0hdc7VsjZDf+x0F4Fs8qfPw0V+m3jorcXBSaKV 5vokRUjmvxGVfwd2M79MQdhjO2J3uu5aVfoAkaEvfMaUGxerfZoZsAa/nFa5UtWT kCS8x4y0hxdDwg4PV5ogSPqqj0eqpJ6x1SFEAVS+OEZk9KnZgC6TBYmKDyIfOnud xTLl5NOw8sAEISb1oCV1okAdeTFMgdDU9k/P/A5Nbc2uyG/vZX5fJ5chyyhlNV5m pCa23JTEswC8fjeG1wXwq4PUjPhgL6k/8Di3uHCCIMxl75yi/bga2Ez1kbpAoEfg wS1NXEwMVE8S/DRRF472cCFvurxVv4ikrxVaU7RlYW/IhzQ5crSDMnj4lCpdA/sM e/9inOsyMGGJzqX8d147swxLXyieE5LGHbww3C18qmgkN//eB8j+dfDEDJHv9a1H Fni8DKijtu9Tw73uvTKobi2j4SAKEqpnhP2V0ruLmr7AQ/D85BKloNJJVgJTvidR QNL+UXMlpELXkibYUsCyjV02KhonRJC4i5m0iVykfbX1AXA4BfED8RoazZRmDpcC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSAipgI rGZ7mwgmjSHxmGXJeTNshDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAI64K2LwYEH1sIyzMj1cJoVzLIDdyX52orgFNg6L kcpdH7/QtMFHCs+5+r2GCXVg93dxM5ieegl0lGkZxRMJhRoYtdr2JBLTwUFCzQQh iugXi/4FJPh5JuP2ZWFXslpAZIaxgTPiGMuJYa8L+X5gc9S3Un4C/iZyfAYAyEM0 xCi/nRHOrFzpvoWHIFX7IoYhVax9VYIBwKVejcggEtB8KN4W2tkRggPaUN9SuV6V Ea2aXhVGARHvu9lvLyqbFOIoT58vxIZ5GTb8uQ6JM32dzCT5foIReOyEOGA2uaUw SHDAthrMeUR30h73Bgu+czNwXX0WYoXPjdSaMQT9iL73U2ZA/NMjkPjodijosKya aIzN+/15NlO9QKxNfuq25Uvc+Gaih6vd1mUO47NMj8K1xGDErArOS8w9tJmsMAkA D+maK1OmzBqUxOOIewj/PxGwOb3aJwu4IlRbUQSIdVLX1vCDaJReNz9N/qpWKb/s WRZ4INBFWWDbqQN2eqWkKYzTkLI4Fx1Ooi8KtO1TWi5WNd1lX7Y6UcXpS1qvml+s Q2QPb6B/KgaGkjJrFeBJ4G6/XyQzItPkFsOBmtWjHwXKOfCLO4niJaGFLl5RqvBK tDxx//6eoGI10wm+6+6UKuFxQTmnzMKH+gG9mVK2RS2bGPRN0hlkHVTiCqXdXinZ ELlW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGkTCCBHmgAwIBAgIQIR/jjdv219LQnnnED8fVqTANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjEVMBMGA1UE AxMMRm9yZWlnbmVyIENBMQ8wDQYDVQQFEwYyMDIwMDMwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDWamcEdahf8i/06MD097uSUe2TIvU4of0tCKXGtDpF EKqQetvc+ZcXiEhvzMSWobr/oIfTTGYUVe1Napmah6UdoBSvHF0P7qiZd8PnWkpk 91bFYFvBevKn0Mv3HKSoTfAFqdhe/vHxNQl8EjTpzbTwP0GM8Bjz755ShpRGOm82 n9hahGnG0hTnaxB4Phm9B+PUlqD2JpZz1IPVhqe4lWDGsLInX1z3dyoYm9bzipxf hl8M8f+JuFLSSc8RPLSSJs2taDfhCndTT5GjVJfiVMWUsPpgcWCQz4FMT2RlbRVa hmFdCQ+8SQOz3VrQAlOq9gzUYqrngcceO1VQX6/WUUqtlNOID8/KFZtugEgSmhjE tb6E/RSiRh1OvI8tTh+jcG3RpHuqmBAupgXtfTw9RZJy++5Qiskk4aHrqHmcMAZK inlP5eIyoR1KKk7hHYltvFwKJTdQZ8ap1P941TKe4yczxpZMy1M75Y5PJFKproxo 1+GLjzRZOIB3iSF/whGep230VvrHGLr7Q8g8EfIXB3MLZzF7hlpGaKKVdTw7305H KKreeyxV5YcccIIvNhCSwsSrIncsoctgXJ6rrNay83dL6Y9SnQ4/a94UobmJ0pum uQVaGGOffSpVdL270T7gsf9ae63LXN23RMxPEMQ9ZAoKMgfl06CsfAfyO2/+0wWk 5QIDAQABo4IBdzCCAXMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwcAYIKwYBBQUHAQEEZDBiMDYGCCsGAQUFBzAChipodHRwOi8vY2VydHMuZWlk LmJlbGdpdW0uYmUvYmVsZ2l1bXJzNC5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9v Y3NwLmVpZC5iZWxnaXVtLmJlLzIwHwYDVR0jBBgwFoAUZ+jxTk+ztfMHbwicDIPZ etlb50kwQwYDVR0gBDwwOjA4BgZgOAwBAQcwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuZWlkLmJlbGdpdW0uYmUwNwYDVR0fBDAwLjAsoCqgKIYmaHR0 cDovL2NybC5laWQuYmVsZ2l1bS5iZS9iZWxnaXVtNC5jcmwwHQYDVR0OBBYEFNpm QDV/3OTi2bD3EiyMJG312UlAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEAgLa4rMRIrEg7qzmdG17fr+Kka+Ozy1o16jiA Z+d7S1vkJa5tNCpOTbxeLzbn6mdIVzcpUdnk17Wp0TIwGQL6N0YasXqPZKLTaIpb KBHiitLiqJutaFk0N3ZAa1nShmf5R4mCb/U75043KRxBParEUELi1YssVsDzQxRu U5olY09jDN0p7VGHdLWB6+FDmE6XSx8eq6yZSbWZMJOs0ozsSpe15ASmHev5RDoU nPiyT7BaMQRfU39u1FgFlUp3+wZdwS0tZNQYz45A6Qwy+1cJ7XLMS75jEyepW2HJ 6d2SMB53ieDsGPRXgXgCbjEMzaP/nypyGX4nJgPOIWiFH9CTtrr/CnU1j5vE2xHd vZPu2RROfKYrgk8BCxI2NEbAYR9lg6kjw1vXfHGtyH9xL8z/vwd+FxxXPfyr4Cd5 PsBL4BFBNhMfx/MMa4XkIwxZ8x9ae5bybqBiIvgHpvUb/2m/whSHaeEAR1364hAB RuZCkUU8xTGErO385xu/mejsqttUHpQBFEpS0EpIJOz7/W3F/amhyMBGRu6b3bHP wX2Izg+OZF2U6h2x+9fX/CHBQtif3GdpZvakYM68BvD1XQlsssCfWFV50ttUQjIY t5j5dBFgtD623NMKqtx70zBNn9naWjNXFiNSmBkZqz+RKmcBlItsxJfwkbcyL5o1 8Q2kKYI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQOFn8fExkdfLOyHp7iL//wzANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDA1MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA6gSk5wUdUrIfPBvLNQbxvQ7zVp1REUj87KQqlhZoG4oM iQLRAKTEKQV40WLEq1M7vsnq7QQusgrKYFvvXQ2fBc3yOTay+iZe5/JayZE8BpB6 MKLdLPftl1YuPJk/4ACxg5FzEcHCy8juitkSM81XBOjEMs3Kzl14sXOsBUAz8iCu bF1uRiQZ4CB7OsE9vknXl9025CuObFUreFcQb9K5iCzAJKfUWGc3p8UrL21GMzs/ XuE/yCdcoi0xctBAzobyFzHFzBhTpoTD+z7FrmBaym0tIz3i0/T0RLMNRAl+LIvH LaBThTg5uv62TYnHV/ks3uXU9aUWqqVTF+qsmQsnK3gL/7kBud7MMdOzaJSffKks 7gvfPGp+SA7Lahf0AT1HDJV9Ue2ChI8oQGHLP+NCy99YKY2o6rhmBw1qySFCWhip NJZTMnmHD4M0I47yORznZKBISaN+fAIxBa9EjVrfuonFfzXJP3L49KoRTee7QKXH VbEYrRsEx13sWi9Uk6VHQzUcha0jy+9ju2bj15QMCEha2FKLipgvRW7A9KVKj2yy rkr88+DTCNxBVVlCXAWFniEcmiNuOdT+wK87uv1sr3DBzeME76q48mDoqdL35Ijq dKJSLM4C6119FNNEuqUpj4Z/XsCrSiv7OPF/LTWxUPs2InubhHwO6a4N8VnWF6cC AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBSzD9I1 5V5Huk+NEFqUTr8+eXrD5DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAG8/fVD3zJ0t/5SaAzyQixQgsfyQzKAWNHO4G7rT 1tHQuTbCOotyMcmq/donUmdEXVw8U91Q0lxD3YF5GGsHlhIULAEVJpJ81OeLwoxY ctj7oqnpIraIKypoxFnZTStJ3HEviskRjyAtqkyebZm7A0dMmzhtm749uiFTSxcn 7XP8Fna1kKl81llpd2DF+1k7e9ZJD0sSNR+z/czzvR7z0BKW8t+nkghGbHTPjinF GbySCA//Ybtwp5EmKJlzOCSejYoRMrqtNDjoWW4bmAI2WfdRD0pdMXHQ78t/w5Ul wMx/mnOiRg6AKbodle4XnfAmA4m7Lg78qlu+zB1FaUC9QCC9xp58qgRIm+KuLmcb 6bas8ponYDNe2hi/2VI0xW9iW7Zoj2Ben0OEldE0xzJlqiGEShZ+t+zoLAX7D15G bjIzhYCt50CKCkYKosUtflIyLfshaEew2MJKJLWXHil/DEjiWpkxymftpR4a5mrL 7Xn6V3RfjGqAzbry2XNDN3b81npYRdqWYh05FfmvlNmoJJ6wjJ0Pkt7oR6vYCibZ xszpqPKYuT0DKuf+VJl2Jfj1tvhU+ubNNn0aGxo4sVR5tKErNZppsqGZavGzciuF 6rF85bX050f5mZ0AmmfSZoCBOv42EP95Xi/48QeLhaEznmUi74XMJzZ0+YsV5wVc Jrn2 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQBK8o4Zq4H/CKw20VnxW4GDANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDA2MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAkyTbjPYRRCHuil8UF9K8DtESH3xrjKQl6hzR4D3xRh1R wgOflJgNCPWV/icq2Iuo6c8GML6fnzRsq8qjWwGrrV0qkKGLL8cwoDap3msmeWxH Q8C3SIY/Vwha3sNqd33xi4ZxG/l2xqq/Afs++TnvxCfyKtKpQrUbujtGsGUzjcu8 obykXP2e54TSIWm5OOGnd5AKhD1+0wN1GReNGuY+BxAh/Co66Z1u0m7PXMU2/iMN B17HZLV5ktbLOPGiXEef+J8hlKwk6HwlY9ZXK23sx4+OFVwwEu6LLkreA2TZ/J+K 8yABk8KeUMhQJYGLiKkz6gTrt0HrifyL+9ZVfo+tmvZj1mlKMSUkcbuGLyGmTJ7H Coj44clonIJ9aGTWXGozQy5h3gjSprk3Wraag58hgi6s6t7PrLezywmqCs76jXAA NZqkiP6a0SfsaqpzbkRiY16P/qh1zyeSAd/SgmmLTh+Kpy8jxT37z2ZYoLGmbLpd 7pd6P9zpUrTqaB8DzaOxv8NV8DJJkcZqoSG2htihbBRcPxHLCCWs8NBYHKgveXV8 GqW/K9oG0CghEM0PmKp0wjgY63H+JRXoLmQcLQywGTllvroDx5AhvBgfvy92tzPo wbW/RNkprKRb9UzBxSVvfZVknRZfk7jTZ+31NQ6PMqCRpPSg/qbWs5OIrdFqlF8C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBTYhHVY ZJhASNQI1im99V6FtTjF4jAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBAC2M1seWUZg44WHe3rBGhVEYRpSqNfkV8cnKRPrF HmAUhGPcyoYGmFWEiBwDSxZ7E2TJKh6rwZLosh+kEarFKVpQFyXNi9XgEyPtPenI K4ewwfWjbkN+ZbxncA6PXv9u5Cqmaqt7paxxyuRIxAjYJhc6r/JZ7V7zkuFqNrI8 rzJxMHc+I8ipl/W6ey+my+AYtOB+LIE9pEfScQw6IlkYqaqN/cMagjv93kYzMirt +S5le4q5o4UvFVzIYrKLuNL+4bTMeNOo4ppqdcAmCu8Y5bciKzQ07sqZz0pEVGDz tiQ0MJ3TTU1WxatWU1QYNV3PQT9VP7UhKkViHdKrRco9F1NfhMLIdnzmUIH8Im89 IOgEwKMD0aaMNdcGrDKRJwjjn89bjLIZ8DN7JL6saHsZO4JL/6fIrJJquhgVu4P4 2EjJ64S4TrnaqvxQX78r9wxJ5IovrGpjgQRCZXeQu03h0MIvec2PjGJXHoktpYqR FgLCaHJQ6K1q22A7+IBND4nLgpAi1TvpCHu+RYi0w0ek9Az6ScOgOoPpgo8eJxrS IsMSn7qRtoG9k3hvOkl9kv27TPefuYztF06OajIdLsmctv3vCbFuxCQK3bH/t//C LzjONUs0ugg8+UZi/mYsNrNE05uYal83u0roT0bvrFOmoOJtalKs/gIkViOK7NVq jJiC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGjzCCBHegAwIBAgIQCnTiezqAGRfQr/kDt+bc/zANBgkqhkiG9w0BAQsFADAo MQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1bSBSb290IENBNDAeFw0xOTEw MjIxMDAwMDBaFw0zMTA2MjIxMDAwMDBaMGQxCzAJBgNVBAYTAkJFMREwDwYDVQQH EwhCcnVzc2VsczEcMBoGA1UEChMTQ2VydGlwb3N0IE4uVi4vUy5BLjETMBEGA1UE AxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAyMDA0MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAv5/PEMGeP3KmX9rGKACSvf+7qAHh2w/+Kq/SZZIDR+Y2 gHWvVu5mIvH4hQ3hhhXbK7Lk0sQzR4XYg6nwRxeO7FEshSm0u7a5/1j+PtI7Hzpx 1I+CG8kKj0mEV8m1UbMPpL0aZ4vDXwOl7kpobBxIjeW9z1s/oFycrFyfUNgxp5S2 ZMDcHnXx46scjdZOtOamYGiHcm7Fi2iRTI0J+gyL/EHgnpl+jNjyhUbdiZpyr7II 3Tf5s9gJXyLplMEj/CRckM6Bd7OHOJt/j054D4BUjJwhR+BjW0RzGoreb6VZt5Ik /aNaS/AAlMCiiUhP8WhUZuLWjjSwTAVtf0oWttjOw1t4se4fGsT2hBtd753S3PQi UoqFAQC5RHYwGNinZGzrX2fI+dJ4zfa2ceA15EiaY2fFs3LRC1J4she52i5Z6lOz AeKEbHYreOMOOgvaUURsEootQJUyJxoQHw816bVtQEEycUHTiKZ8dlAFGiLFI+Wt mh8MTGonUb8BQO8QWcKhKghFlyknMGMleeTjmlHk3qYoBLF86unB6b7aHxppXxHh Iz1zjFvnWWnAyr6F0cYmTGQ6NOUbUBozXifmGIgt9MRh2KM/GpCuegJWnoGdHb4B J8rv4EjVwqnxlFzcsPC+AkCD3935ls+gbEhWt7rQTGKtnqjtLKiauVCH/rMF5S0C AwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEA MHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVpZC5i ZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz cC5laWQuYmVsZ2l1bS5iZS8yMB8GA1UdIwQYMBaAFGfo8U5Ps7XzB28InAyD2XrZ W+dJMEMGA1UdIAQ8MDowOAYGYDgMAQECMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly9y ZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6 Ly9jcmwuZWlkLmJlbGdpdW0uYmUvYmVsZ2l1bTQuY3JsMB0GA1UdDgQWBBRkU0hv z68XTbske0wvyEa8I39XFjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw DQYJKoZIhvcNAQELBQADggIBACgvtg+QeHUz6LKbzKda0Z9Y8Nh759W6I6uL98Da OWzThhT4s7TiFUXoAT8scvDKFUJnCCYiVN4xbgByvs/aegA+1KTZe9regm53158C Oa7ML/oG2vUXoKNzgt6zZ7qktMA/ydxtEQpXf7LXzR6cXiiZWC+a6cqrd6QZeUyW RF6Y1zDN+Sv8DDNCdr9HwjJ6wbEjpTYZwl/owGCBNygtdoOQm3U3avKGKaHs+pZN DFyaTMHmjXBXTQIuu7wRvvl+pad+173pPtuTshQ7tk71NawNX9ynvTkmjjKrt2HC /oSK92EHhgz0o8P8gb17qxwZ6cc5Pu3yHcPwGSo9WwU9qF5jttbXMvjxvSpzjzWt NVqroGwG8MhIZYaVU+ginVv3m3aUkCONtds8uUlNh8D24THkYHydPqAfFO+I0I+n nWls7qNgSwzfhqS/ELVFg03P2fiHtp46mTh/BNp5w1PdZMWX2laZRLETYWkpYWxe qWDKnkm60JA4dmimRJbl4p+GN9VAOX3tmWxaoBzfByv0K5e4CDhaG7W8n+ARLAFx U6gdNXNLT959JXXluuODayOJaO9wWRN0wKxmYlxaphNeDCtjyRg63Wka5SPmnww1 aoN1r7DokElwmWUxrI8bTGgB/R14BDhsi3YoUmzg6JwhJNENvLA8o4lkSp8TOSvp H9as -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIQBQsM8L3hav3F7JEA4fX7dDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkxMDMxMTI1MjE1WhcNMjkxMDMxMTI1MjE1WjCBnDELMAkGA1UE BhMCVVMxLDAqBgNVBAoTI0NvbW1vbiBTZWN1cml0aXphdGlvbiBTb2x1dGlvbnMg TExDMT8wPQYDVQQLEzZDbGFzcyAyIERpZ2lDZXJ0IFBLSSBQbGF0Zm9ybSBJbmRp dmlkdWFsIFN1YnNjcmliZXIgQ0ExHjAcBgNVBAMTFUNTUyBQdWJsaWMgSXNzdWlu ZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKqd4dacLbt3BzeL 1Uof0UrwVBTiAxHB/G8ixOnRnlmui+AU4euoHzJsnAicWeBjmLdgSeqhkmNybUeM 8+VkoKXVHzagwGwLwLIsnnLsuXRPB9tUi9yQiOSFdbUh0dA5P1UVtKQfNCmaCjbs lKttpcoLopu6YKUFzEJGAawR8c2JZ28vWj07Xzgdf+9Y0UbUVEQQT1O4BcxdSoPm oewvwbJb+cZqnPYKfgrvLfWwyErp9UFf15vo70n1gr6nfxz7yyIrUSzkhdL3nVlN 5yKWf7NClZIm7d1o/9rtyeja5reSGh2IVmsazpeAxXk0K7RQhe5UcH2HYpM2sw0/ 71DxDiUCAwEAAaOCAkIwggI+MB0GA1UdDgQWBBSMpMZnsDKtR2cX3hZ1ZJF3ByQv 1TAfBgNVHSMEGDAWgBTOw0q5mVXyuNtgv6l+vVa1lzan1jAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYB Af8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k aWdpY2VydC5jb20wgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2lj ZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwOqA4oDaGNGh0dHA6 Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmww gdQGA1UdIASBzDCByTCBxgYKYIZIAQGG/WwFAjCBtzAoBggrBgEFBQcCARYcaHR0 cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBigYIKwYBBQUHAgIwfgx8QW55IHVz ZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2Yg dGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93 d3cuZGlnaWNlcnQuY29tL3JwYS11YTAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQ RGlnaUNlcnRQS0ktMy04NTANBgkqhkiG9w0BAQsFAAOCAQEAp/vmseuNBvPhWnhx 7RtuvcmydhcNJayBeRzDW4WnH8WI0tWJ80bAyllNVrQ8PycX0hBHy7SVBrRECwr6 ehoOGUWVxIqR+RNzlgDKFq75n/RTwvJgbT7oXV+L9KzdVj9GDYLQ9eVhP0VYI2Sk DgY286eXulCptTNL7XiVqAAsnnIZFGeNsyQaGo6m0u42oV+CJxT46CssD5/0iJoH 4jTLWrweNi/FOwGOKHPJuKMS63I/TsUAMeucuEYRB2r77gzk30seSDvyCCiMvVup YL9RlqNKw8JLUzublOzIir1nN05p2DUMJXIZQ+cyAI8QKx9fL2EWxjFdzLxuszsb +g8+3Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIH5jCCBc6gAwIBAgIQAM6m80pTVeoL0yP3WDrKGDANBgkqhkiG9w0BAQsFADBJ MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQDExpT d2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjAeFw0xOTExMTIwOTMxMzVaFw0zNDEx MTIwOTMxMzVaMHgxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcx MjAwBgNVBAMTKVN3aXNzU2lnbiBBZHZhbmNlZCBQbGF0aW51bSBDQSAyMDE5IC0g RzIyMR4wHAYDVQRhExVOVFJDSC1DSEUtMTA5LjM1Ny4wMTIwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQDKF9pp9NAgsc68LWfMMofsa7jXyUXg1MsfQYUt ogSPPM1nZi1bE3f3y7NYzpndmwAt4pcCcqsu2pzGMZHm9SQWJBoxG9bOfl3r8y5V kNu4zXUZOm+6vewk5YXdLMd/GFwouIe/y7IlYNoseRIP+FL036PEVQxN8DLqZIiK LmIsOFoUI2w5MMcrsSaDOsoMeqTVjRxLIA3mhc/mDK4eT/qJVSAjpk4OOVDqv9fd T0kriRQg92S1oNvjgUrVu1W7iS4l2ymNLmfm/y0PuyIJr2f7SnTOgBsZMg80vSg5 f1hHTv4ougOebZ+9mhzIes6iQ7H2Kj5ffYDjPjR95Fg6GmqJXKTfcIEilROms4Xi kzxU+EEnyF8KLVhkEm+qbYttTIlbClbQp0FI5zRc8M63qTEHTOPCdqul+RJhqvMt ZLVNY0TyJPBkRJm7d4jYDezUKpL0Qiqt7r6E/OokANPA8hDinFijIIhY/9PEBVpI busu5m6RAo3xrM26VkprKwrPqaX0AHvqCJsa/XwaejNLrfKDe6jtICCB/Uuq3O6A oKer3593143xNpqobbwCnSS/OYJPJbgVdjeL9Sdck33hoTFUpmNz2IAm6YbJsJ5K Cj+ttZpIGqPlcutwA4XqW+zjlOSHmUcdrKnCtCwC/1c7mTsffxEIw57tYFTEU7VO L0nZYwIDAQABo4ICmTCCApUwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFDKlfjHYQtu6LLL+5mkJnbfakNIQMB8GA1UdIwQYMBaA FFCvzAeHFUdvOMW0ZdHelarp35zMMIH/BgNVHR8EgfcwgfQwR6BFoEOGQWh0dHA6 Ly9jcmwuc3dpc3NzaWduLm5ldC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURF OTVBQUU5REY5Q0NDMIGooIGloIGihoGfbGRhcDovL2RpcmVjdG9yeS5zd2lzc3Np Z24ubmV0L0NOPTUwQUZDQzA3ODcxNTQ3NkYzOEM1QjQ2NUQxREU5NUFBRTlERjlD Q0MlMkNPPVN3aXNzU2lnbiUyQ0M9Q0g/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlz dD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MGQGA1UdIARd MFswWQYKYIV0AVkBAQEBCjBLMEkGCCsGAQUFBwIBFj1odHRwOi8vcmVwb3NpdG9y eS5zd2lzc3NpZ24uY29tL1N3aXNzU2lnbi1QbGF0aW51bS1DUC1DUFMucGRmMIHG BggrBgEFBQcBAQSBuTCBtjBkBggrBgEFBQcwAoZYaHR0cDovL3N3aXNzc2lnbi5u ZXQvY2dpLWJpbi9hdXRob3JpdHkvZG93bmxvYWQvNTBBRkNDMDc4NzE1NDc2RjM4 QzVCNDY1RDFERTk1QUFFOURGOUNDQzBOBggrBgEFBQcwAYZCaHR0cDovL29jc3Au c3dpc3NzaWduLm5ldC81MEFGQ0MwNzg3MTU0NzZGMzhDNUI0NjVEMURFOTVBQUU5 REY5Q0NDMA0GCSqGSIb3DQEBCwUAA4ICAQBAoZC6vwyjeHq6F/b+r8csNmOXuzQL pYz2DU+/uHQ1HuBxateeGWZoTpznruX91ksJqgjjmrx9tc6Bbqp3tV3j2cyjOO27 Uhq0RaNku82AdS35pplzliSWtl/gwDCqVQ8FBWD9h5qDnDZHrU4jyoV91ZRgJ249 sTQ4b3opF6bOBa40MNWSnS26oWFth5QfrepRxDF+nXOrqxDdmXEO8Uese++Bg6WF gNzgrCXYPZ008Rv9rTYdbTcPn4pL/2HzOiPJay4Hr4SJr0krC9MrIVARGDGSuxQm zEc1SwZ6MzFeHR6qOWTE7sKM/TmrblgNeUuZdRxIlynO4KSFLOkqMM17Jpb1Tf/q glhRDc/8TWYJPhRJuepu4n6HCV9ovtB4FRgiJZ6H1iR/rNZEQstQuSur7o5VmSXK v4IDmRXTJSm1XndxyIkW3kIng7T431e62ws6X9ijeo3gVvUz79TMaA1qomwyy71a w0j6VHIh/u3v2O4BGkdLMH0UqQbXtCdQ23RkQrRTc866CbcHM58yBgHzktJZ1sla evwZrM3J4pDTzn9hE15x6E8ETNzmYVk7jceoo0mc81gJBSLxM7lFukQM9yQ5eD5P 9OqSYod+HJM1nwUBIGewoYN8nsjcgltBP8WojvGSl9HCOM1+LzbBGhcbQAa1DCHh OaJ221j2KtEASA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDPzCCAsWgAwIBAgIQDTFNGf3m/wBjpIYrjTLF2DAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xOTExMTIxMjA5NTdaFw0yOTExMTIxMjA5NTdaMHAxCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv bTEtMCsGA1UEAxMkRGlnaUNlcnQgRXh0ZW5kZWQgVmFsaWRhdGlvbiBDQS0zIEcz MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEilq1Ybn+90fYdtUNMIqE+btMHKAc 1mVMUpatXMEa8hhmsry7fz35IerYYI4+y1sdADNPMgOeW1vT7DGIGfjszKOCAU4w ggFKMB0GA1UdDgQWBBSu6u3GrJIrcgFQ3xwjxkT5qbGg8TAfBgNVHSMEGDAWgBSz 20ik+aHF2K42QcwRY2liKbxLxjAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUH AQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYD VR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 R2xvYmFsUm9vdEczLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG/WwCATAqMCgGCCsG AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMAoG CCqGSM49BAMDA2gAMGUCMQDCCJ+1Yo7tQTSqpdEh7R/aiWc19Y2eSkicX7B0wqUd R61ECydw54o44QPCXOQeQ/sCME3zAaszP0umatUgsZ+uk5CdnnGeqTtuTSYc3lKM n9XxQE5QkyBKTueGGLZxxvZBTw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEnjCCA4agAwIBAgIQCAw6MQadDVbsfa+CftTtFDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xOTExMTIxMjEwMTVaFw0yOTExMTIxMjEwMTVaMGMxCzAJBgNVBAYTAlVT MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0 LmNvbTEgMB4GA1UEAxMXRGlnaUNlcnQgR2xvYmFsIENBLTMgRzIwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTiZbCGjKzGNH+yQB5DC21ZsPJ+DGLTAaE QEAAg290a5XE+6pQBLOdMMscEBTRoJp29tX6ca5D9nYyN6ZXOlo2BMFUvw2sUTPd x3RHPYvFte3dgiL1JUsf6Dp3XbethACtKohyu8hA6izu2XBNAx3Hft8YJ44ATRFT jXnxfv6hOmpMOKZw32ZFcc7lF9CfbDx578g4K6zEJimkJ2psHiku/Ea4dMnAHQDQ KgULoW/x6McmCDC9U02cJO9vaYRcilErDdR8pxwJFysoXhx0xFW2ysnT4gpZNhO7 I+gHvU8dE58kT4GpcChdATTEIrOfRleBcZ8YoTqANtNSSbOB8WWTAgMBAAGjggFO MIIBSjAdBgNVHQ4EFgQUm2b1dH/LXQ6vGq5QagErxYSmVMYwHwYDVR0jBBgwFoAU TiJUIBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUF BwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEIG A1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy dEdsb2JhbFJvb3RHMi5jcmwwSwYDVR0gBEQwQjA3BglghkgBhv1sAgEwKjAoBggr BgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAHBgVngQwBATAN BgkqhkiG9w0BAQsFAAOCAQEAb1fvuWDSJohDY8tqQtNK6H987rkNnvMBBuzjh6oc Lsxbg9Y5Lz8EHogBHctlATEQk5q2D4NkahK/6tv3YiM6EJgEgAz35pVU2xEPMkhM PHqesa75knjyjYNi0CrWxxoBVMOlWYO6EvtrATjAd25SIcg55kuB/i5InNRh89H2 yBiBD1zkEGWBy8+iQ6hF5RboH5bw+BlCkxxnGALfBOqOLLITcO6h4gPuoWnZBnKl clF/tfI9e5dfSjMABqg7EXee0ytQgnzqUrHgwTWbUqfFipw+O7RVhSH1F+R62VfL kWHWBEh35MaC993nOCL/DyjcIHSnibtY14neAJ7ecv0tpw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEyDCCA7CgAwIBAgIQCBFAVkurzpTL7gkKKGj0nTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTE5MTExMjEyMTAyOFoXDTI5MTExMjEyMTAyOFoweTEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMTYwNAYDVQQDEy1EaWdpQ2VydCBTSEEyIEV4dGVuZGVk IFZhbGlkYXRpb24gU2VydmVyIENBLTMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCs6JQle1NsmGguPJ2r5gMXbK5yFkgIgkSYxPo9vgJiHI91zcbYVkrt XLat4sxnIhhGEFLHjhTLAcfDFfXTu5l6JlqOVPG06jCgVdt11tJCTjeBN4Oea/Dn zjU8lWzy3gR2BPsce5Kr44hyJSd6TTgRJ4zAnV8051DDT7wDEYfC/BNZQ1zxyjPb P+pqDN4LLuDRc/jD5qOopLcMS9c4SU1O97fa6azCbpeR8mQZdBs/33a1X/QZrtUX F4ykaL0LrMVtqR+gtPDDODyxFuPKqBVjWQhTN6Ww0Gbguxc9m6Qyffsis0WRMTNq IkgEjVNdGG4BjZuu8VJMEY9nm55l6wbLAgMBAAGjggFXMIIBUzAdBgNVHQ4EFgQU z4XxvDgYeDpVM/RWysBprXduu5MwHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC 72NkK8MwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEF BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEsGA1UdHwREMEIwQKA+oDyG Omh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VF VlJvb3RDQS5jcmwwSwYDVR0gBEQwQjA3BglghkgBhv1sAgEwKjAoBggrBgEFBQcC ARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAHBgVngQwBATANBgkqhkiG 9w0BAQsFAAOCAQEAwhggyoNeVzDHTEjIOaC8C12fqUT1gSjttDNgvZMf6OpYNG7l E6Uc7NJ3wheIIbjHcwKk2M8WOfaRFf2aYtRwBxdWmBN1Fasn/K+QXYqqVdgE89Xb gkASgCT8rhXbTtMcpRDmKd2/2eFC/rkA8Pc0tZ5A7E49EQ0/7J02WHx2ZpqHmYhJ k8bQpg/De8lx69EW/7qsNLnBgtP419cKUBajRpxIVW5a35zf+zCxfBH2+vT1HqKF sT7xaGiiu7eAuyrVQMc6TMj6i2VOco/HypOkSs+6i7FVvC4FxTJjNA2zh+z3oL3/ lj8HPrJLpq6OUOdPU51ysAxxeWA0az3Zn+aH+w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC+DCCAn+gAwIBAgIQdai61XOlIHXSkEohAa7VYDAKBggqhkjOPQQDAzBQMSQw IgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjUxEzARBgNVBAoTCkds b2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTkxMTIwMDAwMDAwWhcN MzgwMTE5MDAwMDAwWjBGMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2ln biBudi1zYTEcMBoGA1UEAxMTR2xvYmFsU2lnbiBSb290IEU0NjB2MBAGByqGSM49 AgEGBSuBBAAiA2IABJwOsc+36J5Sd3U0+qVGp60yGTK0B6knypS7DNIKEMfaibCX DHATCQGO2OpH6r6ygCvN/CgN26y8pIY37XAIAHXqkwt7LlKcI2gjBkPski9ThNv7 RxQH6F+UZ13JeoE8IKOCASYwggEiMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAfBgNVHSMEGDAW gBQ95ilIm+oHyiFESibebt7Sg9CfWTA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUH MAGGImh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjUwNgYDVR0fBC8w LTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXI1LmNybDBH BgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wCgYIKoZIzj0EAwMDZwAwZAIwdcO2G9mq 2xNIKGBzXe9VuAQRDjgxz+n/YyUHZsLrTXi3eljceYiw7PSPzqk+Q3m1AjAv/kua GEx9TzT1Y58y0bahUa1yexla9zlt47OuPWuSUMVZ3XSxpHdSBDH1wrZUdNg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQdai62k/fRIL6M8Tw85T4SzANBgkqhkiG9w0BAQwFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xOTExMjAwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3QgRTQ2MHYwEAYHKoZIzj0C AQYFK4EEACIDYgAEnA6xz7fonlJ3dTT6pUanrTIZMrQHqSfKlLsM0goQx9qJsJcM cBMJAY7Y6kfqvrKAK838KA3brLykhjftcAgAdeqTC3suUpwjaCMGQ+ySL1OE2/tH FAfoX5RnXcl6gTwgo4IBJjCCASIwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFDEKkI+2xp3SREuAtaLmH7ESTxuVMB8GA1UdIwQYMBaA FI/wS3+oLkUkrk1Q+mOai97i3Ru8MD4GCCsGAQUFBwEBBDIwMDAuBggrBgEFBQcw AYYiaHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3Jvb3RyMzA2BgNVHR8ELzAt MCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jvb3QtcjMuY3JsMEcG A1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9i YWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQwFAAOCAQEALXK19TDy ISTVZWVAZjviCiw4i6EN1bNTWOdahPRh8fQjOzEkqVn21I4MY9UddgqxQZ6KBnkd RU/HvNqHjGDJSJ78j5Sp9EKJkbGqJ08ZxI5udFriM3Nx8JwOF2froazeE4cU9P7T kyOrarBxbAg+yrF6Hnx++ZBh21Xbwc5qumYfhe1CM2O+mow++3tckL5j+Bcx9z9U 7O8Oi/KT7kLS+Rv0buYrJ5os95NvZawiS+zssgBZbRfKzJA8MT3BI/o2+Wzr4Z9n Z92uJFFHzi8XCsUL/3c+XQdCwWbTwvzI6LQbKRtxuab/6G8FdFpT0wGeOL4UbAxF sNSxECO1uDy3Bw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnTCCAoWgAwIBAgIQdai60w2Y1LKLm37oUtJIqTANBgkqhkiG9w0BAQwFADBX MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTE5MTEy MDAwMDAwMFoXDTI4MDEyODAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoT EEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYw djAQBgcqhkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qU uwzSChDH2omwlwxwEwkBjtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNo IwZD7JIvU4Tb+0cUB+hflGddyXqBPCCjggEiMIIBHjAOBgNVHQ8BAf8EBAMCAYYw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUMQqQj7bGndJES4C1ouYfsRJPG5Uw HwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswPQYIKwYBBQUHAQEEMTAv MC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjEw MwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290 LmNybDBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93 d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQEMBQADggEB AMUa3r9xUlvWlZge0FPK39GCTIy6IdffTGlyEBinrM+G6EXSNDGdlimXJOaTas0Y 1ofMcL0YYc8mji0iMmFvFzeohothhUUhONoDKbRwWi1uajLEYCsBcvUDNmB7nKhY fANARzhocnZE3IUzUkvPB29HXokNvac3yD8UrB9U+2ImMK0E0ZbLewWj5T6S5MvG c4+k6T1ZDccHzxnmYCUXVXfsfAT11HgegXpwLvG+0Wg5tX/JKvI45mmSq6ZF7DTu sqcpmMxCNqXx2g2CtwA6KjirD6uJWlqSKpnPtiLQhAvCm/AAKZFWD0xUjuVhM2Vm W6oPV/EM0svKrLcMOtXu3AY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGRDCCBCygAwIBAgIQdai62b4c2Z/P4Yu08NRPGTANBgkqhkiG9w0BAQwFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xOTExMjAwMDAwMDBaFw0z NDEyMTAwMDAwMDBaMEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEArKx0MuizZeW67UMmHaaJDUW6KYiypB1j3dPB LAlXiTmhVelnNHcMbuRVHVIl0hNrXuEdqbd9iTJfDZ6fLHpjYEAfprC2eI+ZVJYI WK7kBrxiBQIWv6+oIwO2lA+8bmzCy9Wmuwzp9sEC+yHeZt0Xq3RC7/B0LyX06mtV W5Dbnd9ehwpA+60Za/v3ymCI3trBj9au1X/UPIPu1xZMg0UzayfQhtAcLWvzq33x han1KNKt7/OESxyH/BOjOnKiWhEr1idxJ+2BLW1mgZKHtBtYesw/CvpGT014XPgr SOMEhMtd9rRqs2X8Qp5RJiMgyz0U+YHtZRYATxpkl2YIz4x74yvAnfkU8hvxVmoW vyyFhc14OJrrQmoCNBiDF06UVvi2grXzlt09875/IHc+exkjayzUcnNDV33g+Ndp Txc2BPnAkGA3Rd7mDNh0ja6com10XUK+BvXZZG4CEKyJsEw7B01AfiTFipiCeY6k p4IgjSP6J3HJ38ZBdKBN9pEW3EaMXyljMVlxDNhvwrYyffvmXVOmfhX8u3V8Xez4 9hcc7MdrGcvze/ArB6XZbHlUdmydHKZuDul5DKgjaqPfGzAxn7FUe/5qy2aq3GXQ op5Kmgcha4GP28RZ+t4iwASc46pbNpPoPb16oZ0LdrELx539z5ioBsL4KqOhg6C3 JXKlAuMCAwEAAaOCASYwggEiMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBQDXKtzgYeozLCm1ZTiNpZJ/wWZLDAfBgNVHSMEGDAWgBSu bAWjkxPioufi1xzWx/B/yGdToDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGG Imh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjYwNgYDVR0fBC8wLTAr oCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXI2LmNybDBHBgNV HSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFs c2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQEMBQADggIBAI15/CxkZDtS B0D7B4iARQRQ6d6OMGN/CB3V8gSshpq5rMxYMKVPP8AJKnEZ8HqhHqPAf4nkQcuE i5r2ICC+fT3DrPlYroLw63H/ybaIiZr5aOEPcUWwbs19W0HarQVtaNlQm/qPXsBv /dPdI6jhcVWF+TkhvhSbBoaqv4HBxpoY5jgozanf1qjRtjyViPdDHnCaeI96fMfs sNt3wIsrjHX0yIR8bvnwCYvEkIZrq1+fRpMCNfIyg0hXqrPCiDaCtUK7KFqC4SLn Ky3zPIzC1cMC/b/ZfVpShS/b8HFpK3nn4twHs5cpfWMoPUNFsvf1CYCLiIIB64db 1cYKPfweYFZ9Tt9viwlsd7nqZHLatA6ruDb9a3uzkDFyxS9qiRCx43+vI86DEkF9 w5fM4E+VTo359zYeEHmy02lenXOo6UlkEuLiQti1/OS4bSexYAilA9oK86iPzFI4 xlhsfWwGxdHY4CXc9uCaKPTCv8NN12zmYd6bQefBrQtsqZI1Wyh33sZOac9ICPxl KnnfKGHYbm3UNwZxN2fq+4E9e8CVbKC5RQlKS/r44c248gXB0LGzYiB33djbJXwt ctg/lprhnMQjbs+ERRX7Rtg+QsJD/9//tifsaQpj/YE7pIkoO8S7DviKDPFWNCAh l0GGkqW4xBLGp7v7dmDqT2b5vlNnqjVB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFSzCCBDOgAwIBAgIQdai61oMhNQtbC6w04c44nzANBgkqhkiG9w0BAQwFADBX MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTE5MTEy MDAwMDAwMFoXDTI4MDEyODAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoT EEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokN RbopiLKkHWPd08EsCVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNg QB+msLZ4j5lUlghYruQGvGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3Rer dELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNr J9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6 zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNr LNRyc0NXfeD412lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsH TUB+JMWKmIJ5jqSngiCNI/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++Zd U6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGf sVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3P mKgGwvgqo6GDoLclcqUC4wIDAQABo4IBIjCCAR4wDgYDVR0PAQH/BAQDAgGGMA8G A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFANcq3OBh6jMsKbVlOI2lkn/BZksMB8G A1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMD0GCCsGAQUFBwEBBDEwLzAt BggrBgEFBQcwAYYhaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIxMDMG A1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC5j cmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3 Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBDAUAA4IBAQCZ W2NlJdAwd4jzvspgWN18R5MjvsAnYX6iOzqWXMSFh/fwst/J0GEjZgE3vA1HEHJs R5b+M6yo27J3vhUl/kUnFJvfwBT0GadngKXUV8AgllpOyaVZrBI1uLW3/Ll7/G56 4meSrMUHzR9ecHYRqMu9REt6x7rCFyVaLraxuNKFisu9FMTh3f/RQHJAT26pviBX mWW4R/nl8MERkyhbXcW+IvqcIIkcM5wlCe68xllqXBn5mJbwIso6lTJmLGrIj0KI DuSOCd9xwg+aupwM7cR2lV1Bosu/G4AqG9K64v98V29Tdc+Xl3Q8dgzbZsc6WjCr QY9qNfNSmbTJqUEw7lXm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFRDCCBCygAwIBAgIQdai62Hj4rzBfct0cEUDfOjANBgkqhkiG9w0BAQwFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xOTExMjAwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEArKx0MuizZeW67UMmHaaJDUW6KYiypB1j3dPB LAlXiTmhVelnNHcMbuRVHVIl0hNrXuEdqbd9iTJfDZ6fLHpjYEAfprC2eI+ZVJYI WK7kBrxiBQIWv6+oIwO2lA+8bmzCy9Wmuwzp9sEC+yHeZt0Xq3RC7/B0LyX06mtV W5Dbnd9ehwpA+60Za/v3ymCI3trBj9au1X/UPIPu1xZMg0UzayfQhtAcLWvzq33x han1KNKt7/OESxyH/BOjOnKiWhEr1idxJ+2BLW1mgZKHtBtYesw/CvpGT014XPgr SOMEhMtd9rRqs2X8Qp5RJiMgyz0U+YHtZRYATxpkl2YIz4x74yvAnfkU8hvxVmoW vyyFhc14OJrrQmoCNBiDF06UVvi2grXzlt09875/IHc+exkjayzUcnNDV33g+Ndp Txc2BPnAkGA3Rd7mDNh0ja6com10XUK+BvXZZG4CEKyJsEw7B01AfiTFipiCeY6k p4IgjSP6J3HJ38ZBdKBN9pEW3EaMXyljMVlxDNhvwrYyffvmXVOmfhX8u3V8Xez4 9hcc7MdrGcvze/ArB6XZbHlUdmydHKZuDul5DKgjaqPfGzAxn7FUe/5qy2aq3GXQ op5Kmgcha4GP28RZ+t4iwASc46pbNpPoPb16oZ0LdrELx539z5ioBsL4KqOhg6C3 JXKlAuMCAwEAAaOCASYwggEiMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBQDXKtzgYeozLCm1ZTiNpZJ/wWZLDAfBgNVHSMEGDAWgBSP 8Et/qC5FJK5NUPpjmove4t0bvDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGG Imh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjMwNgYDVR0fBC8wLTAr oCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBHBgNV HSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFs c2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQEMBQADggEBAGBD9cJLVP2v gPSlomstHU38guKTe4ELEFOnM9OnuzK2HlzmgVSPdf4Go7r8FZt4+d8lVs7JPt2z THYK/cA1f/DYT56clWZO972GbvjOwmHop4LqAe902mRBxEo966EFsaBqwk8zzexW nPZ29CXHc3doU0wXhIPzch5d18Mp4y1RRjybOODc89QJSBataMU9rIHNTF6rePxw gL4/k/zrGiCRCRJ+iblTL/WIhm0ENfNJMTxlbMHxPYH4aiHarVBXpXPkiZ/85knD XNcnTUTZKEtY6xJExiC+5IHDjdnWz/V2d8MkQx+o7TPbwgF/SVcYcp0GPJG6RkLD rkNz7Wn9gck= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHljCCBX6gAwIBAgILMbMURP3WwqePCpwwDQYJKoZIhvcNAQELBQAwgaUxCzAJ BgNVBAYTAkVTMUMwQQYDVQQHDDpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3Mg YXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRswGQYDVQQKDBJBQyBDYW1l cmZpcm1hIFMuQS4xEjAQBgNVBAUTCUE4Mjc0MzI4NzEgMB4GA1UEAwwXR0xPQkFM IENPUlBPUkFURSBTRVJWRVIwHhcNMTkxMTIyMTA1NTAwWhcNMzExMTE0MTA1NTAw WjCBlzELMAkGA1UEBhMCSVQxGDAWBgNVBAoMD0luZm9DZXJ0IFMucC5BLjEjMCEG A1UECwwaV1NBIFRydXN0IFNlcnZpY2UgUHJvdmlkZXIxFDASBgNVBAUTCzA3OTQ1 MjExMDA2MTMwMQYDVQQDDCpJbmZvQ2VydCBPcmdhbml6YXRpb24gVmFsaWRhdGlv biAyMDE5IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCioWue YMmC+ffZgLNI6krCAcDHDrQe7y3WE5ITq6cy+iC5eebwWVzZwKsMOi0UQSIwZPUT /fcIr1LpbJfwSSc9LcEBbCw2va9kd/nUWIKz0flJZ5bjXksZmMj1nUsm28Bxly3U jkQpGMi16KEyCndLrFcu4VY4vyG55oHUwm0S9yZsZg/KcNUnjvlykxZxKDqQPjLj xA8Uahao+4Pb1XxzhM8HMOxcEWSVHfiISvsIEUdw/uW2MrOM1czlTIBB9DvicZ3e Gcb+VrJ68vQtZva8mECdbhrOy5p9xI+PeyCYy6C7CQnKJZ2MEbS0VsYc/RFc82sK 4349WhAcTCJdUt6MMp8+EM5Rep7U+hzEdpWy3AbmVwxWVC3qf7Xw3DfUIcQ+aJbh zdYHd5WCpfScoaMf0NShepYPWvFzX3Tb2KLtcempd39iUObFb6PkkRIxztB94DT6 tvcxas3qD7O/0b4vKPDsm3TaosISyI267d8Ei/2O1W6SM2fc+ri+Jox8fmOopzPY 8Mge1QuP0pDcZsfsIk693Y2QQjYoBVAHdx0wQpEc+a0x70YPlL8r/8T/Dh5ul3h7 QVGuMA7S6qUmDYS5CpQ/oRL9hIQPDHGXR/I+uxIf9b9VW8ljl1zWI9s5WauMFPD+ gTOGrO17rW413dl8hQ8NhMyf+XCrLgTFN5vDGwIDAQABo4IB0TCCAc0wEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUiDK/CftCOfRyQyBouM+sipJ4XQwwHwYD VR0jBBgwFoAUWxvuA3ui2+dGwMJUq6FQKV/xVtcwfwYIKwYBBQUHAQEEczBxMEcG CCsGAQUFBzAChjtodHRwOi8vd3d3LmNhbWVyZmlybWEuY29tL2NlcnRzL0dMT0JB TF9DT1JQT1JBVEVfU0VSVkVSLmNydDAmBggrBgEFBQcwAYYaaHR0cDovL29jc3Au Y2FtZXJmaXJtYS5jb20wDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUF BwMCBggrBgEFBQcDATBABgNVHSAEOTA3MDUGBmeBDAECAjArMCkGCCsGAQUFBwIB Fh1odHRwczovL3BvbGljeS5jYW1lcmZpcm1hLmNvbTCBhAYDVR0fBH0wezA7oDmg N4Y1aHR0cDovL2NybC5jYW1lcmZpcm1hLmNvbS9HTE9CQUxfQ09SUE9SQVRFX1NF UlZFUi5jcmwwPKA6oDiGNmh0dHA6Ly9jcmwxLmNhbWVyZmlybWEuY29tL0dMT0JB TF9DT1JQT1JBVEVfU0VSVkVSLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAqUqvjxL9 oJD7cp8EacdYPoX2K7HydNdqqGlF63NrciMoacRW+21UlhJKNFjw0kN7mt3j2yG6 aWxilEwRxGf4kDtVboL5p6AbLuSXhZwxWwGXNO6R0Sh4SR/3KXQz4mLlP4bn+fiX aXgH3t1MEMph/yaLnA1EXZTNmbknhJMblxwiJ6nNpTyWQGLWg9Yv7i8G9dc2WZb6 p8f7j5S9RhbRqH58xZkdC7qHgzzy9yz91aDC+O7TTrTG8AtOVHTGpOe0XrxXReyz crGaQ4zS7RrzKtFDb0JAEZuuNH57PZlvbdOMGc9vMEI4XB7Oq19p29FDy+LOafvU VQZNgTyE20URKwwLbOl+P/8z13vQus6r/cmbB4TFPQOHI6I8pd7CBFr3S8MJ/NvJ IUIPAqalmU80Sq3+n+oBUwTMfrH79uzaNG3DHNPvAnIrZJdqAv/x5xUSBolJ1F76 0antfyn4EQcObrk3bOX8EB/RQ0pLmxPDlHNnBsatbOWOCYO/Qy+pLp4PfJ4oIkVE GSMuqF8nbJNCvoAwfiXzNlqJ9HuTbm06czecflj5gVnT21jUUxGbT0SV3RhCtXGG u83rBIgCzVhqkV9MsHSPMcKwKMYvXjOr3MuPiIiF2L4eX+veAG8Y2rRRI0wTyvmm 1y7qaOpSZPW5y44UfOu7RaJrafSYqUxuDQI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHojCCBYqgAwIBAgILcvJ358Jb7tncxn4wDQYJKoZIhvcNAQELBQAwgaUxCzAJ BgNVBAYTAkVTMUMwQQYDVQQHDDpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3Mg YXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRswGQYDVQQKDBJBQyBDYW1l cmZpcm1hIFMuQS4xEjAQBgNVBAUTCUE4Mjc0MzI4NzEgMB4GA1UEAwwXR0xPQkFM IENPUlBPUkFURSBTRVJWRVIwHhcNMTkxMTIyMTEwMDA5WhcNMzExMTE0MTEwMDA5 WjCBozELMAkGA1UEBhMCSVQxHzAdBgNVBAoMFkludGVzYSBTYW5wYW9sbyBTLnAu QS4xIzAhBgNVBAsMGldTQSBUcnVzdCBTZXJ2aWNlIFByb3ZpZGVyMRQwEgYDVQQF EwsxMDgxMDcwMDE1MjE4MDYGA1UEAwwvSW50ZXNhIFNhbnBhb2xvIE9yZ2FuaXph dGlvbiBWYWxpZGF0aW9uIDIwMTkgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQCvzUTRyQWIqeGsAN7dZNGRONRvCHJ95vgjKFSCwUvv1MvWf8axM19g HJ7B4ciULgH+W3xtWoK2UjmtYsyzJ7GYDNiZGLuwCakdxFxApy9ebzvUDBTjOu0t UsuuUEXX8Lg8dhDadk8on63cVOlyNSYHDxGp4cnEl4/I+LmFUxBj0sjTjTr+pXwD PNLiwx48N/+OF3dF+MWhdJz3Q8HZfz3sL1zL5VY7Hkgbv5QgFzTKVsfHlzcnyFhX t4/7nOuoZEmTHgKn+hyz8NnX3J7Knn1k3Dg3VaYNXePYMsZ6FiT/R6UAsULU9PnE obkkI9LeDLU5x+2BHCTLTl+MN19pOSmBUAI1VeU3TEF4N6NPPOPy/7oiI1M93DYZ J7raHva8UMa+dlPj9hU1dq7aFMiUE0lEr1jhFyiBFzENkyJW0EMs+LgeXrKh0oFh eN34Dq5R3oErmdqPn7e6k6PpXn2lowUj52E8eqa5dJsyNm4fgGZr+Aqxw3QARBBI qjPJEEpIASLaNdBC+Y2Kk04RT3sxGju3zcDN3+HTxHCKvipGWguezJjBPT5cVT7w rmVkfh1b3+JMJHJqiXs14S3gOBqNkGdcTlw/Z3feRAFJT5Kp74eRsDVVBKcK9l36 q4wX6YscOaQhkqyDsAEsx+70gHaRWNUeQWVZc0qjqOj6KYWI91zU/wIDAQABo4IB 0TCCAc0wEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUy9kwnXBUNui+KELg 0MYO+2EoN5AwHwYDVR0jBBgwFoAUWxvuA3ui2+dGwMJUq6FQKV/xVtcwfwYIKwYB BQUHAQEEczBxMEcGCCsGAQUFBzAChjtodHRwOi8vd3d3LmNhbWVyZmlybWEuY29t L2NlcnRzL0dMT0JBTF9DT1JQT1JBVEVfU0VSVkVSLmNydDAmBggrBgEFBQcwAYYa aHR0cDovL29jc3AuY2FtZXJmaXJtYS5jb20wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATBABgNVHSAEOTA3MDUGBmeBDAECAjAr MCkGCCsGAQUFBwIBFh1odHRwczovL3BvbGljeS5jYW1lcmZpcm1hLmNvbTCBhAYD VR0fBH0wezA7oDmgN4Y1aHR0cDovL2NybC5jYW1lcmZpcm1hLmNvbS9HTE9CQUxf Q09SUE9SQVRFX1NFUlZFUi5jcmwwPKA6oDiGNmh0dHA6Ly9jcmwxLmNhbWVyZmly bWEuY29tL0dMT0JBTF9DT1JQT1JBVEVfU0VSVkVSLmNybDANBgkqhkiG9w0BAQsF AAOCAgEAr91vlqdxI0dR3kookln/T7KjNZq3l/Eu21rXJxrJbkVPfowHfq8hp4mw 9FfxZvikt1kFuVOAJ82qsP/GvMcnbTnE/92Vrg/ti8dxVin5dgZsUQyjJdbBs7GP GfCV+3/gRY3kLL9DFVkOT3Tdwdxg+36LUBNYCfetIWjm3Mqwe6NlIjJsyoQqo9f0 3iVU0Rw4gO8tFoI9qWye2RsejEYz7BQ6+ULklVojSi9Q7Y7dIFWp0lkQrFl48bOq 1h/QCmRmK/UjT/ux58q8kaUQtV7bKu6nzK2U97XQCmVLHej8OkwpCc+lrekYHtw6 yD0qjZ+cpRkzzdDSvCk+d1awcb7mKxnHEQjJ85rRY7rn60b+UKF1SvGiILtaPmVm LBntDzBZT+aDl855TQowp4osnIfAOmSih3AVZVYEZgphmdyDo5+AUJfvNlglvyW2 11yZwltIhoLRH68YeUK7JZZkFIIlQFXvQOfqVkC8Cqw2L1T8MJU0Cq5fZ/V3SAKG QQgwpCQGjOth2c1GbP3kOKKEdlbY+9U3q7CiHzTzw0+L1CL7G9k18B3D8L3pU/F3 jGViEQhkXmlRHhW0QEjqI56+auU80oC5BEHoVp5nEZ2ZsdDkIpCf/7+3xoeTfVKl 1tnv6n8IDCfKE7DC8o9+JFTE1l7n3f8OwHCf5L2Ssl3SIirLcRA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCBMigAwIBAgIQAw9hzRKvkOlHxrdzZwNVHTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkxMTI2MTIyNjA3WhcNMjkxMTI2MTIyNjA3WjCBoDELMAkGA1UE BhMCVVMxEjAQBgNVBAoTCUF2YXlhIEluYzERMA8GA1UECxMIQXZheWEgSVQxPzA9 BgNVBAsTNkNsYXNzIDIgRGlnaUNlcnQgUEtJIFBsYXRmb3JtIEluZGl2aWR1YWwg U3Vic2NyaWJlciBDQTEpMCcGA1UEAxMgQXZheWEgQ2xpZW50IFNlcnZpY2VzIFVz ZXJzIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFIeROjE4l deg/rDbLUlhaKImSL/D1+3I20CuWp7Oln6orDy+K57Yw0J0L0SsawTbxkf4HK+Fe dl/WGKBhjBD8AxmGsGwvTxuaIP9tAFQSo4GCsBdqorSejlg6zYfQHs2wYlRIh8rI hHNG4On7IWIU5vQGmpuuoczUdUAbvOcHEmRQmGnJwDjwpkBgNsqtLh5/zun6lK60 ar1IQpjlO4YIwoQ+FpUsiJUBqZtHtV6HhsMzZLdOcki/g32XTaOerJPBXj3WoYdw +yAYQX1l5bLCtRzaSQGAKdM73fxBTDHBvV0PblLlhSnhIeLU7m5key1U7+rkiB2X SK7j6HOXNNlZAgMBAAGjggJOMIICSjAdBgNVHQ4EFgQUoyUy6xqzDKRfpTaDO8SW zQiO73wwHwYDVR0jBBgwFoAUzsNKuZlV8rjbYL+pfr1WtZc2p9YwDgYDVR0PAQH/ BAQDAgGGMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNxQC AjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcw AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMIGBBgNVHR8EejB4MDqgOKA2hjRo dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIu Y3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1 cmVkSURSb290RzIuY3JsMIHTBgNVHSAEgcswgcgwgcUGCWCGSAGG/WwFAjCBtzAo BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBigYIKwYB BQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVz IGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50IGxvY2F0 ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL3JwYS11YTApBgNVHREEIjAg pB4wHDEaMBgGA1UEAxMRRGlnaUNlcnRQS0ktMy0xMDMwDQYJKoZIhvcNAQELBQAD ggEBAHS8g151vb8l08bScOcp7MPlu/XB/8KPZtDH6leonJBB5YbUWHOGiaZyfiqU FJLhxQgAZ9fJf8EPn9THmnrAMiNG6leF8Dt/BFOvJddktnV8S1ycl9nIHOMgGrne 6kdVqN3ymmOb9DzUpu3+ez0G01L6mcdRpG6Z3rEKlYHrOrXCvdkFAoTElw8FNKIk RQ01dAltZOq68DFJ9JceVrzrEaz4zyx3PLOScTEBecCQTBKsl9T+s1haO6DoAkKR LFAD4x3oOKiAoiyoxtVtoFqoTYNphm2fRMTJAJaF5RXdkNrtpUlUGmDDMdakKaTF 71cDYqqYHdirbqjo+KOV4ay40tY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvjCCBKagAwIBAgIQDw5QP3lfdboN2xS9OtW/DDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkxMTI2MTIyNjQ5WhcNMjkxMTI2MTIyNjQ5WjCBijELMAkGA1UE BhMCR0IxHDAaBgNVBAoTE0thaW5vcyBTb2Z0d2FyZSBMdGQxPzA9BgNVBAsTNkNs YXNzIDIgRGlnaUNlcnQgUEtJIFBsYXRmb3JtIEluZGl2aWR1YWwgU3Vic2NyaWJl ciBDQTEcMBoGA1UEAxMTS0FJTk9TLVBVQkxJQy1UUlVTVDCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMxq/552okNn5iinzn4yJ5LurzKku7w8A/bTEAHN qH3xL9najSF+O4ZThTDgZLxjSP9Mmn9pMp06LlxeSLrvYhuRpNkZ9p3VAAA9Mg8w JOrjIeKHb2aVwteQUEQ0EaMTcmcNt7KwhaJL0CwHF/2tkM9FACg28YnCBcydWovm 3oZ2woWvgQl6yJVLPK32jJV0FRGzs1az7O8aXdQCSBT/vzDu9DI3XQL527NIYP9j DTHu6GxHiTvWqbN9utZRgSxdKZ2PtXJkWzcjJJRn9HJV398H2tGb6iRXvIh9I+v7 qmYA0kL/hXfd+qwkS8/1JCOoq7Jupb2TgFLjfVzTdb+EYUcCAwEAAaOCAkIwggI+ MB0GA1UdDgQWBBT7iu/JNiJ2M2G3yknEjY1+BeXDUjAfBgNVHSMEGDAWgBTOw0q5 mVXyuNtgv6l+vVa1lzan1jAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYB BQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEE KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgYEGA1Ud HwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz c3VyZWRJRFJvb3RHMi5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwgdMGA1UdIASByzCByDCBxQYJ YIZIAYb9bAUCMIG3MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j b20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNh dGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBB Z3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5kaWdpY2VydC5jb20vcnBh LXVhMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFEaWdpQ2VydFBLSS0zLTEwNDAN BgkqhkiG9w0BAQsFAAOCAQEAyWzWv8V99yqsxSkfXNiZiHLV1XY1biMKXST3X0ds Knr58dBf94O89vMj9/LQHxg0ryr5RYyMeSUvMfjeyXe+enw3OjmMqb4NaI54dqpM F0/+SGN9EPkPJ4ccKsBfi9twlse2Kde3W4bvqHtO67X//HuUeKte/hSC4EXpmf2l ohdzlAmMTbp8+PJLEBft2XbGhkvTHP+Re9a8C3qQss6kEVThD3Xah1S/oPF0HazC HKx+HTJUTNxQpsyzAQfblZUDLr3frSCjUm9WjGtFTFwIupeadPZVf+MA4e5Mbyoz fq/F14/uxXkIAgrFkMslkIDEGiBYNkopnxrICvLcbnMcoQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzzCCBLegAwIBAgIQCWinmmAsofddL9nmj2a4OzANBgkqhkiG9w0BAQwFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTkxMTI2MTI1MjI5WhcNMjkxMTI2MTI1MjI5WjCBmzELMAkGA1UE BhMCREUxHzAdBgNVBAoTFk9TUkFNIENvbnRpbmVudGFsIEdtYkgxPzA9BgNVBAsT NkNsYXNzIDIgRGlnaUNlcnQgUEtJIFBsYXRmb3JtIEluZGl2aWR1YWwgU3Vic2Ny aWJlciBDQTEqMCgGA1UEAxMhT1NSQU0gQ29udGluZW50YWwgU2VjdXJlIEVtYWls IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0IKfCJ8DffzzcFoW +AotbKqITr7LjLlqHGPHCMrC+RIFGySREWgNc0KCqUcleoAh1xO/ndFqMfPn6sQh YSLPX567rjNv2xSp+6K9nKi76wU0qZeMXVMKyu5mXjsQNjpkOrcr2a9uWsjtQRmk x6h2v9qhBY2QhfPJ/o7yzrujkvc2nnCp0qNba/i3gk+S4zYKt0c4LC37X+shKQwG eWa8ZwKhY3WMwQaDxX7MQA8HValOoUfE4tRmiLpkQz9OWHnjKEBXweFAMhsr+ttA okDg/X3ZJ73SmhLNdTqUPcmYx74uG08znNLLCNz2xeS5JTOvxo1+gJea4Abw3tPZ +8ufuQIDAQABo4ICQjCCAj4wHQYDVR0OBBYEFKgSIGeea1P1+tuyeqtfvBbCIy2c MB8GA1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWXNqfWMA4GA1UdDwEB/wQEAwIB hjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwEgYDVR0TAQH/BAgwBgEB /wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp Z2ljZXJ0LmNvbTCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNl cnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNybDA6oDigNoY0aHR0cDov L2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNybDCB 0wYDVR0gBIHLMIHIMIHFBglfhkgBhv1sBQIwgbcwKAYIKwYBBQUHAgEWHGh0dHBz Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFueSB1c2Ug b2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNlIG9mIHRo ZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBzOi8vd3d3 LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwKQYDVR0RBCIwIKQeMBwxGjAYBgNVBAMTEURp Z2lDZXJ0UEtJLTMtMTA1MA0GCSqGSIb3DQEBDAUAA4IBAQC7xg/pfSY4Gd4PH1S3 e+XVTjXZdhnSXo0mmB/Z5sMp83QLx/Xo9eJ+gK84gOxYfI3lss5k0r/fLklhZ0tD tbRmold4YlN+OcTHWspVMNRY9a5nmOVadWaiD6vcH2CdH7V/iI3S2PSbl29U7e8f D/aa6P+8CC8MxLJVHrbH55itEEqp1JgN5aKPyOMqxIQjUr+53r3qU621JwCALd6Y pKESNbV6bm3MZ0JaoVxTioOZS6xX5hbCNhP9DRqzmd9rHS40ASy8MCIcs1/Z1wUh +QtM87l9/Ej6/y+nItLSA6hIpc2YhcKu41lahijWaGViMAeKjXVH1YUrRMJxu/1v HlGx -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHODCCBSCgAwIBAgIUUf1UroiXyi5xvfKGVabVFa//FcMwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xOTExMjcxMzA5NThaFw0y OTExMjQxMzA5NThaMH8xCzAJBgNVBAYTAkNIMSYwJAYDVQQKDB1RdW9WYWRpcyBU cnVzdGxpbmsgU2Nod2VpeiBBRzEeMBwGA1UEYQwVTlRSQ0gtQ0hFLTExMi4yMTAu MzQ5MSgwJgYDVQQDDB9RdW9WYWRpcyBTd2lzcyBSZWd1bGF0ZWQgQ0EgRzJ4MIIC IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1gkLU4uhYaBadBKWR5tY6eUI TBdIe1nbkJOxO18eyZJE0jnczAg2//Ut4JydaKi9FTwI8wq2mKLX/htSx4p0AgRp SrEXU2RcWNbxq9Cfu0cOUR9f8KCVPvEcRv7+4BFgFsqFvJ/Tw5DNkRzm+SRO/H98 1yCfEZC16n5I7kdaFuQcY3dBWnrsIRt1bHwCzsYzgO3lSP/DDLgi2pHjgNm8fJ4q Yzj0TYotzotAsAqlnSDSnNL9JppewHy/D/8JnU4OIvNXIr+gW08y6SFPgvI7lCd3 ErA46e/GJ06j1lXd/mYZJN3fWuxpBtI409DVQvT0NFXZvcwdwciZ+c6z6dWmYvIg culwWDaCa79HuJvfRHUtFyJr2DdPFo0rKKGQYx8GiUp+PmYDu6AnvwCxuhd9G4Tt YIDZUv0rEo+EUC+JN3idd2ZZtMVQ6paKIPpKkwdhNkGkKEm+cny3b0Ht52ZwIlPb Y7wC7DXhDn0dCA08tqCdBcvom6v6pYmwqDnhwAkpKQZkiPbwUP6w1M0onqvZbiOu 0gNSLGIRKHu1XT+aQpA1PYA5tjZ5oWLFVU5lr/1kF08zLio0Q6q3jDpfNokpvf/5 Bdow3e9hfvf81dX+Efd4qArGJBG0um3StdCM6W+zF2GwnstuMC8onEpb6dh9dad5 6sc54Hx+7OSaM0b0th8CAwEAAaOCAeEwggHdMBIGA1UdEwEB/wQIMAYBAf8CAQAw HwYDVR0jBBgwFoAUo5fW816iEOGrRZ88F2Q87gFwnMwwdAYIKwYBBQUHAQEEaDBm MDgGCCsGAQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29tL3F2 cmNhMWczLmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVvdmFkaXNnbG9i YWwuY29tMIGYBgNVHSAEgZAwgY0wbwYKKwYBBAG+WAGCLDBhMDoGCCsGAQUFBwIB Fi5odHRwczovL3d3dy5xdW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeS5hc3B4 MCMGCCsGAQUFBwICMBcMFXJlZ3VsYXRlZCBjZXJ0aWZpY2F0ZTAMBgorBgEEAb5Y AYMQMAwGCisGAQQBvlgBgxowKQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUFBwME BgorBgEEAYI3CgMMMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmwucXVvdmFk aXNnbG9iYWwuY29tL3F2cmNhMWczLmNybDAdBgNVHQ4EFgQUQnGpos/WTsHNLV4D ejE6wo1aeTUwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQCBVVdb XHCElr0X1ekUb1XCV1LWMnhwE3HmjCoRgiYAjCY0DGBorkRZHaRPl3x7UQ37mMST uFsgq0WstL3j7Dp8RhmLE0Z5b64aI+C9x1MnENo/dYEXUcdfQsoZQfPZXS57JER3 Yiu+RPsj/uAsG01o5sSg1rqdhlprl7/B3HJwHBtFzVuljbGZeULtssk8emCdrY8N enAvIJmxXkj9gLzVCo8uQ9/fd8n+3d95z8Jm6/7tGBwEzoz3/0BaJ0NBeqXLkDmQ MAXBd2VQV2sj5lX2iU17A3KUVn/VAGmTSIC5+zdezlX+ctIOpknN2/tZHSNSo2oK yqkzyf6y8jDT2i4FJ9tkvz5S7VC2fnXAwBw+09sRbIiPs1a/C79IX9vOCx1A+2MO 7RdtSSdwHADJ08Y6uHKLJTXBTdvp8fO+j06jkSe2UXS6SvwMe80ZaZ0KUaLHpX9F cvoWiBV/Co1hHWk+uL7bvUQkQorGU1mMhX6H9Hl0LGBgEvhEmA/xZbC2zGOkczIn mYFggfPWZTaQq03wRgjHdSeOynAmJmiVV77Wemy07mWO5lNfoVrYqjU8jf54tTNm ayEo9vA3Tw1bxMgDYFs3rL6qDusK2XwY4GXX/pTZ4ytMEyGy3hKBYNBG0HTvDDx/ srzV3vtDzxuHfbAF+9Zw5wYxjuHjCVJ4SoEF6g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIH8zCCBdugAwIBAgIQNIFgxR9e28td34nKtFczkjANBgkqhkiG9w0BAQsFADA7 MQswCQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xGTAXBgNVBAsMEEFDIFJB SVogRk5NVC1SQ00wHhcNMTkxMTI4MDg0ODA5WhcNMjkxMTI4MDg0ODA5WjBnMQsw CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxGzAZBgNVBAMMEkFDIFNlY3RvciBQw7pi bGljbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIiXtTkI+RwQtLvj xKUjJI6Gnfhgr+3HPWQQjB36laMkldEfQGsVxg6pZdQfW9YQqNEW5OqJ/XxMkExF Vt6y9/GJOJfTOPFyys7tObuPMw6wk0Yy+UKZg56Ea/dxJC1Dyb6pI/k4+tBvyAFM XzwbvWfT0PjZSTnvf51d1K2+IEDjQ8LMFOnHQWUBGaOub8lemZnMeGROBYXEWArm jy3wEjVwNxWvaTfYxRw9SbHqfgOHoLkALkMshNM62CGQnHldGBH9w8r4vspF0/XH b3nvq2GWkBhq5fxwu0OzgaBpSiBL4Mc6xDJaoelPxB/ma3icD+aANiBr92z3zCli TUxe4c33L8qPmnV2GKctADAR3YEcOOPCJXjn5QOdNDQmjPBLCbi8GL5u5eJ4NZXU iF50LNyooA9z45BtL5xY2es+ZCOIsYr8L9X5klTvrAP5lKLleoRrYbUnfLq1LVkp GaOO2wzMyoOtp9YEJeaA8punnPI5jSK5n3JIsVesfY0fvq0Dia4V3NLv9jPnOmat buV1CadT+wuKG0ZVyoM05zzE5G4B+DH4VWfZy0r6WziOc4XfQcTifMk9hcZEWPJQ 5WxlGiUuWEfOvVizrYIzjJd3nXRSN76+xcHVly6sdy9I17DMODMLLhqn8vR1LJaw XM7vNbmNhs5Gcex2heeOh6yBpNohAgMBAAGjggLFMIICwTAOBgNVHQ8BAf8EBAMC AQYwEgYDVR0TAQH/BAgwBgEB/wIBADCBlQYIKwYBBQUHAQEEgYgwgYUwSQYIKwYB BQUHMAGGPWh0dHA6Ly9vY3NwZm5tdHJjbWNhLmNlcnQuZm5tdC5lcy9vY3NwZm5t dHJjbWNhL09jc3BSZXNwb25kZXIwOAYIKwYBBQUHMAKGLGh0dHA6Ly93d3cuY2Vy dC5mbm10LmVzL2NlcnRzL0FDUkFJWkZOTVQuY3J0MB0GA1UdDgQWBBTnBO5wkRGS RPkOko9WQx4HHb8EnDAfBgNVHSMEGDAWgBT3fcX9xOiaG3dkp/UdoMy/h2CabTCB 6wYDVR0gBIHjMIHgMIHdBgRVHSAAMIHUMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 LmNlcnQuZm5tdC5lcy9kcGNzLzCBpgYIKwYBBQUHAgIwgZkMgZZTdWpldG8gYSBs YXMgY29uZGljaW9uZXMgZGUgdXNvIGV4cHVlc3RhcyBlbiBsYSBEZWNsYXJhY2nD s24gZGUgUHLDoWN0aWNhcyBkZSBDZXJ0aWZpY2FjacOzbiBkZSBsYSBGTk1ULVJD TSAoIEMvIEpvcmdlIEp1YW4sIDEwNi0yODAwOS1NYWRyaWQtRXNwYcOxYSkwgdQG A1UdHwSBzDCByTCBxqCBw6CBwIaBkGxkYXA6Ly9sZGFwZm5tdC5jZXJ0LmZubXQu ZXMvQ049Q1JMLE9VPUFDJTIwUkFJWiUyMEZOTVQtUkNNLE89Rk5NVC1SQ00sQz1F Uz9hdXRob3JpdHlSZXZvY2F0aW9uTGlzdDtiaW5hcnk/YmFzZT9vYmplY3RjbGFz cz1jUkxEaXN0cmlidXRpb25Qb2ludIYraHR0cDovL3d3dy5jZXJ0LmZubXQuZXMv Y3Jscy9BUkxGTk1UUkNNLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAoiOeh9gNG+m2 D5sGhF42Yikr03aD2jNwMEzfOy8j3GY9/zIYu749MeNwAq9KVx/NnxNiHHUUOqJz uChPM/wMNaS6GeTYerDsU90C0fsbPmAOIfWQ1RdZWM5DVlOK7IhtRN1pDm0SCIiC vWt4UtFRnu04Vef1p5Wdi71JisT/5TwtALk/bsMP56KaZP6NHgvh/CaXu30UxSSa oJ+HPHyDLE2MRpKF8YyfGNEtqslSYZLsicGEdvqegDWxnJ8lR0dOMV6T2Aldct0o cAxK+fRUpNx3Dzw9u7zQXwQqR5C7pjpv2Zfz+aSG1Wuc/c+XyJRsZXBurxMwE4tf rKSvAWSBEOM9CaHwMVbhuPyDZqbyi2AdLGkpv6TL3QX0eBcsqZrGP79UYNdi3iYo e8B5btv8qTXnXc4AFYUOgpGFffOBbX6CwkN7tdVng0qy3lfELEB3NYdCJl1omVsT i6UbZW4l7wa04JNK3PX3Rm5KgRYy4mxkH3wDAFzMV2021avyPf4SSkwAmQfYtpUO QQGcyoSS4Jp2CGTa3+UIgPyOsyPyu98QrAnqt1jI1T50xJMgy4lYQDOiL9UmzOYZ G/0raweJ2iSvCkMHTlknvisXo8cXg7+J1bC0+hBEoNq+dtWyT+r7PTOGChpQzOHP byc75wBp7Iq75dVxe4asXI8YdytrFxI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIATCCBemgAwIBAgIQLO0aXgKAW7xd34o67KqYWjANBgkqhkiG9w0BAQsFADA7 MQswCQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xGTAXBgNVBAsMEEFDIFJB SVogRk5NVC1SQ00wHhcNMTkxMTI4MDg1MDAyWhcNMjkxMTI4MDg1MDAyWjB1MQsw CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxKTAnBgNVBAMMIEFDIFVuaWRhZGVzIGRl IFNlbGxhZG8gZGUgVGllbXBvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC AgEAyEa0GCFLd4/kGN0f8LgsXBGWyCEmOsrmTQbKO9PvNHF6Q1lg0Hc/zuzQxSC3 gf7IIGVbbgDSojOPcqnKv5JOT4ARax/qUhjSqCgKeTKbCKLW38kQQtPw9N1IYGwM NhQYal3ENuj7kGO1edaXisJATXj+R6aI4e2h6zghcMnDnvFCv++9dx//y+0BbYi5 o/PFeTZCHZ4aWtC428s5b8f3fI7CduVqO2BHYI+E4ok2y/15YM5oYNmVQ9g0eLhn a60m8t2GRAEyHBmthz9juvWN51GbiJXnTiCgd1tYUqEau4WQV4f9mucgEp7MITCM 0ffMzAjfqKO/JuSfGZDZfPLPxLQMKlv8lS9GOWFp3Zy/Vcfo86PETK776zRkVYti kWm4pp41V4oghUOvkHXAyxsKkg9Vdtq8wE+sM0xvS+HdbjGHttpdixu6M4hrAbRg ZygFYVAfLixl3qhJ1W0w1xxy4AOLBAdaAMA/fYh8OO11k8aibjeKB9xcmuEK7yrk 57iz+WmwuiGIlmjg5EqBz6fwDi5lwx5ZeYkjlg0k1Cni2G0PmUWE+XUyk9tW6Yab U8Y0/BDEQbvl6jeVy1jX9AMrAN4m5Cqdko/iFEuH+St4SkJzpf602UYhj/2KJSPF CGJwhNSd2RMQIAxo6CZ/4bUXjXNbRnZmv5UzSA4iPjsczqMCAwEAAaOCAsUwggLB MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMIGVBggrBgEFBQcB AQSBiDCBhTBJBggrBgEFBQcwAYY9aHR0cDovL29jc3Bmbm10cmNtY2EuY2VydC5m bm10LmVzL29jc3Bmbm10cmNtY2EvT2NzcFJlc3BvbmRlcjA4BggrBgEFBQcwAoYs aHR0cDovL3d3dy5jZXJ0LmZubXQuZXMvY2VydHMvQUNSQUlaRk5NVC5jcnQwHQYD VR0OBBYEFEC5VQSoT39gkO0RlSXDJfpa9IXVMB8GA1UdIwQYMBaAFPd9xf3E6Job d2Sn9R2gzL+HYJptMIHrBgNVHSAEgeMwgeAwgd0GBFUdIAAwgdQwKQYIKwYBBQUH AgEWHWh0dHA6Ly93d3cuY2VydC5mbm10LmVzL2RwY3MvMIGmBggrBgEFBQcCAjCB mQyBllN1amV0byBhIGxhcyBjb25kaWNpb25lcyBkZSB1c28gZXhwdWVzdGFzIGVu IGxhIERlY2xhcmFjacOzbiBkZSBQcsOhY3RpY2FzIGRlIENlcnRpZmljYWNpw7Nu IGRlIGxhIEZOTVQtUkNNICggQy8gSm9yZ2UgSnVhbiwgMTA2LTI4MDA5LU1hZHJp ZC1Fc3Bhw7FhKTCB1AYDVR0fBIHMMIHJMIHGoIHDoIHAhoGQbGRhcDovL2xkYXBm bm10LmNlcnQuZm5tdC5lcy9DTj1DUkwsT1U9QUMlMjBSQUlaJTIwRk5NVC1SQ00s Tz1GTk1ULVJDTSxDPUVTP2F1dGhvcml0eVJldm9jYXRpb25MaXN0O2JpbmFyeT9i YXNlP29iamVjdGNsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50hitodHRwOi8vd3d3 LmNlcnQuZm5tdC5lcy9jcmxzL0FSTEZOTVRSQ00uY3JsMA0GCSqGSIb3DQEBCwUA A4ICAQBNFM9IPXNDhmKVlxo4vK6CdL45Gt0+nROnf1KnW83CESo+KiylEo1quLaG 1oe44jWspRJbN1ZEJQJbNS5ibsuRJthF8RN4Bsy1TSNrXETXddKMtqhbihaMrmaW 0Ptn1YO+oIAAgfLuHopSiJj2N2rqq34LerBz/BLB0dhTLy1eK9TRRJlc4vIJsGck aHzC1D9fdh7+1amkVmG8GvNLMxvINKPmIG6dFwXO9xzeAvzhIfDCfDjjysdicMOn 7n10GPrloQwaILFlCqxXVdFIglSv4/o1qp6wFGv4zPuE50ko6dylPdoBdRxmGdk5 oaBT7ZuFBgUyPMhuWaH5G3M/5wXI6LGVGHNmbxtieBv5HJ8XB0ciIBb+6LSSR/Fr sQVnqU0QCNIKJYhqW1ghc3wnDazD74KCeqOfskeINwWZnUocQOpjOAVkPIyOFnvY up9KsNfHdK75Oi4LGESKqmRfAUQ7U0fl5k7A5wJi2z5kvrHQmkSmYtqBlRBu5zX+ 15jw3Kgar3r4A8F7zt337CEsxYGo7Kxd2mZelD9cQ1q7WgCb6Aj+1KCbQYL77ezT MYRggfUtsq5YYaxNYilOF/4Rn0+heh55ulc8RbAw+Rl0wkeah4BQ+vSBUBmGoJPh C7Z8GRfFCy/2m3ZbozAqHmwkiYktWbmH1TlM+7UEsIfXWCmwfg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGBDCCA+ygAwIBAgIQCNO7HB1sjEGMTCY4N8GhfjANBgkqhkiG9w0BAQsFADB8 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTEyMDUxNzQxMTFaFw0y OTEyMDIxNzQxMTFaMHExCzAJBgNVBAYTAlNDMQ4wDAYDVQQIDAVNYWjDqTERMA8G A1UEBwwIVmljdG9yaWExJjAkBgNVBAoMHVB1YmxpYyBLZXkgSW5mcmFzdHJ1Y3R1 cmUgTHRkMRcwFQYDVQQDDA5UTFMgUlNBIElDQSBSMTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAIeJs7WMogRnuPRWu1ElJi9so9wpQL+qJlt1UHVp+m2O P4Kd0dN8ez4vCu13vTSHD6+W35CItDVTmTSTRBEBbZU6/FUvJ7sHqEJdg9TO2UV7 S6rQLojf3KSJC34XLh7YtuOKWXskws2C06F5nCWYCxd4gatbdQgnhz1qaLb9sa2d ng0Q3bK5xDHq9mBR+VCzXud5VzAXoEWQ25DKrzypXIcqtHqzesvF9NHd1peQReBl u0Rmc7L+kepl3djwFzr0kVsoonqK87O/X9hPqpmBhY69diMtq+LpNyuG8lSLizxG eNshcZkdkMLJrz4oL3OG7y4m3sG8NbQmhib0e98XLV8CAwEAAaOCAYswggGHMBIG A1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU3QQJB6L1en1SUxKSle44gCUN plkwgYMGCCsGAQUFBwEBBHcwdTBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5zc2wu Y29tL3JlcG9zaXRvcnkvU1NMY29tUm9vdENlcnRpZmljYXRpb25BdXRob3JpdHlS U0EuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTA/BgNVHSAE ODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cuc3NsLmNvbS9y ZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATA7BgNVHR8E NDAyMDCgLqAshipodHRwOi8vY3Jscy5zc2wuY29tL3NzbC5jb20tcnNhLVJvb3RD QS5jcmwwHQYDVR0OBBYEFPSuWo6U5h2QB7V7IQYUnr1d41o8MA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEANySLZKzXHW0Qgt/drZlLzHo6XVbRRoWE yaE0FhFQqu8sHlybQxnvrjhn1sZykNxsmHvzktUxBRHD/S29mTfLXeV9JMfJcnGq JMm1UxbgN+J3pnPVfYYI6jugLH9y92uhldImpn+GN0zPAyzEDR0FkiH7EluRLHZd mj5HwtRYYqBEWOQNvGvZNWYlt99vGgYz9g1Uy1IodCkg1DyLCm7nFKG/Vxsqscaf tlJ/ZYEtos612ddrtEIc292lWpLsnWekDtp+50k2BtsBMRNFzkIB/VSd/pidUbzw /az2rxdwLaIjZ9yBBUOMckOO3z7qbKyqRbqsXdPdDS3xRBtV/pY8RE8IMxe1v9V/ U4vUnD7yjDxK+b1dAdmmnX95cS+IVS5iPOfqImUGIALgIiFH8LgrBw/U5v51b4hn SPSsPXNadtgMizB/Uxgw+gp5/ddp5Xpm3pm1eI/cbBqgpaJo/2S5A+EMbRJqkkaa a5frQKI8YQUXH72CxedzFUZM8mzNxzo/c7h0lU/CdjLHWOvbiSzso1ygyueO9kuy SCZb83eVbE7pMsepBi+gi7XNTgFcovr01uBge7j+YtsLeP0zwqmQsQHzgR/y01Fb 27prtVKjn7UTkI3D05Py811gaoC0/b3A77uNtn/mVhBIPekQxYaI7Q0I7ympa8Ux P1zufJy0lxs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGBzCCA++gAwIBAgIQfQUIIK66EoIui/OPGAP+dzANBgkqhkiG9w0BAQsFADB8 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTEyMDUxNzQ3MDRaFw0y OTEyMDIxNzQ3MDRaMHQxCzAJBgNVBAYTAlNDMQ4wDAYDVQQIDAVNYWjDqTERMA8G A1UEBwwIVmljdG9yaWExJjAkBgNVBAoMHVB1YmxpYyBLZXkgSW5mcmFzdHJ1Y3R1 cmUgTHRkMRowGAYDVQQDDBFTL01JTUUgUlNBIElDQSBSMTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAJok5Rn2YmZrbHu0VTsbqoabC8vLbdvEDzjjJZEJ D6FrjcYVMRfp1N69N8aCIwHxukyscz2zWd3y5UWzAz8dAH/w/gIvBoW1LC3rsKdP bZCmW6Sy0Nv35ao+5kfXtBDvLtLvXW3ll0vMJo9bjSa5FrId9YE+VG1m3tRiH69y eDiQM/MfIgyY81BQ1em+vogww+6N00ZEBWs5WH5cPdFycsReoG1GWZdagb0FfE2j zYRVhNFaXwj0iS7Bk7rXTL0hhcO/hU+t7lWP2xRa7d5i6bVd/SwtzlIx1i8y1SQU sxMyck+bJtZUt1pba2AHgITOdXdeNC9NOMH1draJvrAeZhkCAwEAAaOCAYswggGH MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU3QQJB6L1en1SUxKSle44 gCUNplkwgYMGCCsGAQUFBwEBBHcwdTBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5z c2wuY29tL3JlcG9zaXRvcnkvU1NMY29tUm9vdENlcnRpZmljYXRpb25BdXRob3Jp dHlSU0EuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTA/BgNV HSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cuc3NsLmNv bS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDA7BgNV HR8ENDAyMDCgLqAshipodHRwOi8vY3Jscy5zc2wuY29tL3NzbC5jb20tcnNhLVJv b3RDQS5jcmwwHQYDVR0OBBYEFJNoxdD0YIa8YPYbS5OfB9SN9JmbMA4GA1UdDwEB /wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjQtJpGnMr1MaGm4vBMO/GXOpgD/D Hz2KJAkYuhiqJfUnbV5DPOdpAMYEWQNcYO+Q0cNuCNfDor9f+9GK+15aCJuK7N9A bfFbFRJnrQRBGIKJRkM4XDcChFW5l7UUqswYwl4ybVsLNcorRd1uqQ5nCMSHo2Hq bbrTqqKVrWE38HTsByE1UYHf5csrJ5epHdcnQy9UyTf0/fxKCGhBbMgdA0hXzN/I F3pCgnO2XEjk3b4eICoAPkB5BQHRVuDVFuNo7cZJHIo5HSrid9US90KEwGMc5VEl gU1w/ACyE2gzjVM/egJbFrxJ+pCoNUaorGF27X/QpJCD8EiyESs8KcAW6YLb1ClW e0ESJo+NkVjoEvahWgqhZg6m8EFag3mxc9tipSNaVzm6cAaER5dXNvUaQc7KaShv XzJeNNSzy7VKxoycMHZrL7F+/mRU1DkIlCtlCF0QKBovUMJ86pZv5RHBy6UBMqEV KNcAAjQyr12jl7gRLupek63LUSSWyohk1Itac3fB3yiaLVa766oms0WvuMtsGNZf gjN40mX/I+RVncPyQEWMkF92qFi8Jx9cp2IP368gOFxyaQeEKqCsVonsoSQg0p6H XNw68ZxQcVOHyH9OnKBqProAR+ssJkKfR2tbkaMvGmnw6YoWrkOprcPENLDix0hw cz4ds6Yt8PytLnY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGEDCCA/igAwIBAgIQXkXCVpudK72cE8vm41R9ATANBgkqhkiG9w0BAQsFADCB gjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9u MRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNzA1BgNVBAMMLlNTTC5jb20gRVYg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EgUjIwHhcNMTkxMjA1MTc1 MDQ4WhcNMjkxMjAyMTc1MDQ4WjB0MQswCQYDVQQGEwJTQzEOMAwGA1UECAwFTWFo w6kxETAPBgNVBAcMCFZpY3RvcmlhMSYwJAYDVQQKDB1QdWJsaWMgS2V5IEluZnJh c3RydWN0dXJlIEx0ZDEaMBgGA1UEAwwRRVYgVExTIFJTQSBJQ0EgUjEwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCLjF5efmMUn7kuyKaKLSgI8FWGj7JD jEHuTfe6X/HhPz7nssX/Ug4pb37olMpmDZK2uDwvt6b8I7p1yHZRu4dh4SJTYsoa 6O+73y+Ts55KaDnQjN4p+4NhK+mNDj6BAJu1/0dvsMnQHnOKVqiYDEv0rKsv6tzm d6OO7DtxTXFxteoddFe7RNQP8XU05iXzYh9+AyuVwK3w8lj7Bk1lkwNl28j+umju bOA63Iepg6U+kZ/ngY77CTQtBB6GAANQzGFWZSZv3UNzw4npOxd+ogGyAiwBoDhl BADnCjisJAD2dG4k0eGL74Px/xT40ygr1mOp2gLR3qvfYQM5AMzWVUt9AgMBAAGj ggGNMIIBiTASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFPlgu9Tj1TT2 uPUGgCWnc9tGaaieMHwGCCsGAQUFBwEBBHAwbjBKBggrBgEFBQcwAoY+aHR0cDov L3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29tLVJvb3RDQS1FVi1SU0EtNDA5 Ni1SMi5jcnQwIAYIKwYBBQUHMAGGFGh0dHA6Ly9vY3Nwcy5zc2wuY29tMD8GA1Ud IAQ4MDYwNAYEVR0gADAsMCoGCCsGAQUFBwIBFh5odHRwczovL3d3dy5zc2wuY29t L3JlcG9zaXRvcnkwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMEUGA1Ud HwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmxzLnNzbC5jb20vU1NMY29tLVJvb3RDQS1F Vi1SU0EtNDA5Ni1SMi5jcmwwHQYDVR0OBBYEFAE9DdBxG2Z47mWNMabUkoNAtxKe MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAKZ6CPOBJ5aQS2vZ2 KQiZ4poCbqh/NnuOqqdElNqRyrdTiOJ2/lXWCyxhYYMkNIfp25X8k9VSwg7JJfqK 0bpKVKSqOT3beMaaPn353uREqf+G8xQa4v4zuT0ufsh6kTBjZH7IILNcvWWs5OZz mP0ql33ySRHSBRa8KCDpOvNEWuQPPDjdiTp8jaEQ5An3l7dj9oc4HFarwcAKWJLE LHpl6IiTc5TxD7sUz6J9thNITGwWQBO0wUlQOZXxOYAUbU7FAPyDLk6l3ssmJxEK Ptr5bi4ddolXtMDtjaZuSvXvwlRo/BX23PkWCpv+BdJ6+mG+v+03+eFwR++f1zFQ yTOqV5NGb+R4W+cjQQYzvY/qBKcPzvjGxvNmf4K7qdcASMMu4O6SJgNukKtn4Tv1 zJUvIf+OHRZyEEXrlNmKOvz8PorXjAxwiqJXGF/GMsGsHEFlUG+/qCHiuJM4f7ig ale3yWADlYTzjXKXXmWUvRA2RnbX6fZFFvFANXgu3XcmFlHSgfyrT335RfcWP6p2 5uyuyDGUaFIb8i3OduFOQB7XdD79OnV/KLdHTXdNtvuxn4+ot4EpS98jN6v61kcb btkPo9nA/tmuF+x2gHKaUJMnuh13AE+EKKMJvpMHrs2hGhIyoR7SSpX7RGPj6f2v 0yEwgtlGE+H/4tT6VQihtx2OhKg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqDCCAy+gAwIBAgIQT9L6yA/FobXp6H4lKG9bgTAKBggqhkjOPQQDAzB8MQsw CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAW BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzAeFw0xOTEyMDUxNzUyNDNaFw0yOTEy MDIxNzUyNDNaMHExCzAJBgNVBAYTAlNDMQ4wDAYDVQQIDAVNYWjDqTERMA8GA1UE BwwIVmljdG9yaWExJjAkBgNVBAoMHVB1YmxpYyBLZXkgSW5mcmFzdHJ1Y3R1cmUg THRkMRcwFQYDVQQDDA5UTFMgRUNDIElDQSBSMTB2MBAGByqGSM49AgEGBSuBBAAi A2IABIcDHLjPPRAljxCUUkxJDc5iKWoaDbcp692vUqhdHDF6fdaU/BzyvVgV/GZB sQDIAI/fzsVtD79pi3RAqqiZHJQNIbjLJAva+7q58ewJsmXx6aJbM9Ibu+1SAqjo T6HNmKOCAX8wggF7MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUgtGF czDnNQTTjgKS++Wk0cQh6M0weAYIKwYBBQUHAQEEbDBqMEYGCCsGAQUFBzAChjpo dHRwOi8vd3d3LnNzbC5jb20vcmVwb3NpdG9yeS9TU0xjb20tUm9vdENBLUVDQy0z ODQtUjEuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTA/BgNV HSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cuc3NsLmNv bS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATA7BgNV HR8ENDAyMDCgLqAshipodHRwOi8vY3Jscy5zc2wuY29tL3NzbC5jb20tZWNjLVJv b3RDQS5jcmwwHQYDVR0OBBYEFNynJba37KVQ8jP2Z9XMo7dX3xhGMA4GA1UdDwEB /wQEAwIBhjAKBggqhkjOPQQDAwNnADBkAjBa7dpJkw1g2KbZvCLhRJZzrzJNm1Oh kIyTiGClTA2VMDAmqs+aVlqAOJ4EwAByc+sCMHaCizB/MsoyGjuBK8gvySoZqI/c IWvZLqC2/J2geFCTklrtYlvjD4RnlEhHN4JAQw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrTCCAzKgAwIBAgIQCpW3UYwc8/NSAWzkfr9aPDAKBggqhkjOPQQDAzB8MQsw CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAW BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzAeFw0xOTEyMDUxNzU1NTFaFw0yOTEy MDIxNzU1NTFaMHQxCzAJBgNVBAYTAlNDMQ4wDAYDVQQIDAVNYWjDqTERMA8GA1UE BwwIVmljdG9yaWExJjAkBgNVBAoMHVB1YmxpYyBLZXkgSW5mcmFzdHJ1Y3R1cmUg THRkMRowGAYDVQQDDBFTL01JTUUgRUNDIElDQSBSMTB2MBAGByqGSM49AgEGBSuB BAAiA2IABOI2esZ3NlAATKU19rYs2kCRg2k/F239UEpFTlx19Gm4CA5ZzGk1cOQz q+b+BLHAIf9htnaPulI/1T3OCoXhFZe/gMbMXPg4NJ2a9kAv80vnKpyTDzLqwXNM vy76+bPcLqOCAX8wggF7MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU gtGFczDnNQTTjgKS++Wk0cQh6M0weAYIKwYBBQUHAQEEbDBqMEYGCCsGAQUFBzAC hjpodHRwOi8vd3d3LnNzbC5jb20vcmVwb3NpdG9yeS9TU0xjb20tUm9vdENBLUVD Qy0zODQtUjEuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTA/ BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cuc3Ns LmNvbS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDA7 BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3Jscy5zc2wuY29tL3NzbC5jb20tZWNj LVJvb3RDQS5jcmwwHQYDVR0OBBYEFHkMwls5jakutov+4+7Nc8eQLNSCMA4GA1Ud DwEB/wQEAwIBhjAKBggqhkjOPQQDAwNpADBmAjEA3Y2PpoE8yG9drpwil9unEXYl 6AE2Ye7gBVp/H65O6zoNXvj9AV92mBeF5Ls+qQAkAjEAxuK+2VBWH/eVgpNcS0tR NXh9lwjlNgjs09wE6GBW88JcTlEg6/AnNFuUHGmDSZdl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDszCCAzqgAwIBAgIQDTVetRXgI5CCmvFrSBGi+zAKBggqhkjOPQQDAzB/MQsw CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAW BgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNvbSBFViBSb290 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzAeFw0xOTEyMDUxNzU5MDBaFw0y OTEyMDIxNzU5MDBaMHQxCzAJBgNVBAYTAlNDMQ4wDAYDVQQIDAVNYWjDqTERMA8G A1UEBwwIVmljdG9yaWExJjAkBgNVBAoMHVB1YmxpYyBLZXkgSW5mcmFzdHJ1Y3R1 cmUgTHRkMRowGAYDVQQDDBFFViBUTFMgRUNDIElDQSBSMTB2MBAGByqGSM49AgEG BSuBBAAiA2IABBJ8yzo3vPihqmhMHao1XJQ+n4HaSKjqejVF7mczZNY6NtbbY1R5 NOTcKspp36i0I17y70mqBSrGr5P90evkTlBDMRuBGmtqLAvE2caC7mp4nsSYtnG8 JhErVe4iWyP1IKOCAYQwggGAMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgw FoAUW8pe5d7SgarNqC1kUbbZcpuX5k8wewYIKwYBBQUHAQEEbzBtMEkGCCsGAQUF BzAChj1odHRwOi8vd3d3LnNzbC5jb20vcmVwb3NpdG9yeS9TU0xjb20tUm9vdENB LUVWLUVDQy0zODQtUjEuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3Ns LmNvbTA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cHM6Ly93 d3cuc3NsLmNvbS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Jscy5zc2wuY29tL3NzbC5j b20tRVZlY2MtUm9vdENBLmNybDAdBgNVHQ4EFgQUrzTS2j3OAubJHUMavJhbJ4DS 2vgwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMFFTufheGNEGHpN8 mWf0HZzqHDJkgszY13UJZysdkacFd58CMJ7Et3TXVTf2UAwvNgIwMX7FkvuN6Vot BdcOUkFUL726ethqcoT0/U3Yyryev2xhEEA/wjy/79IoVDhAvQeC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGvTCCBKWgAwIBAgIQQAFu+vSEq6LjsbaVYwMsczANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTkxMjEyMTYzMjM5WhcNMjkx MjEyMTYzMjM5WjBZMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MRcw FQYDVQQLEw5UcnVzdElEIFNlcnZlcjEdMBsGA1UEAxMUVHJ1c3RJRCBTZXJ2ZXIg Q0EgTzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7g55cFrCoIeDK 1sq2+V5Am2l1vbqjhalYhRH6x0BhmP6XLx0jhqwcVm7HfhQ6pJQEVxo8kB0Qp9Ry mSOvvVNCtW2UnmPxuoNxGFlZvjNaYf/jhMzUMGGQZ0ZXb2hKe5NMYDHwuVvnSHnT MvSYAzu9rPOruXOlfURxYIu+3o3huWivZyBP+Ze+xMqmbRmYgnAcXSoOVI3UhwKF /r5+o+CFOBvSkgB1ov8vLhE0rLQkHCXdk/qCmxFbwhYO+SsBrGKUfXOK8ze7AXLD n6e01EyvUscRZu8NlFParxMWW7STjwZ+kh+QFB2HLj8o2V8irmubZMBsVkKWyG+W HoEuL7m/AgMBAAGjggKOMIICijASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB /wQEAwIBhjCBiQYIKwYBBQUHAQEEfTB7MDAGCCsGAQUFBzABhiRodHRwOi8vY29t bWVyY2lhbC5vY3NwLmlkZW50cnVzdC5jb20wRwYIKwYBBQUHMAKGO2h0dHA6Ly92 YWxpZGF0aW9uLmlkZW50cnVzdC5jb20vcm9vdHMvY29tbWVyY2lhbHJvb3RjYTEu cDdjMB8GA1UdIwQYMBaAFO1EGcDT8AaL7qR7vkLnJlTIjjZ2MIIBKwYDVR0gBIIB IjCCAR4wggEaBgRVHSAAMIIBEDBKBggrBgEFBQcCARY+aHR0cHM6Ly9zZWN1cmUu aWRlbnRydXN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L3RzL2luZGV4Lmh0bWww gcEGCCsGAQUFBwICMIG0DIGxVGhpcyBUcnVzdElEIFNlcnZlciBDZXJ0aWZpY2F0 ZSBoYXMgYmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIElkZW5UcnVzdCdz IFRydXN0SUQgQ2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vc2Vj dXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRleC5o dG1sMEoGA1UdHwRDMEEwP6A9oDuGOWh0dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVz dC5jb20vY3JsL2NvbW1lcmNpYWxyb290Y2ExLmNybDAdBgNVHQ4EFgQUThcZFloO TNxO9HLs5DoBwRmU/TUwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0G CSqGSIb3DQEBCwUAA4ICAQCbLpB+BNTA1WvOU48YNwB9OzfX5UIqLOtw+3FoFuvs MY0b5V4u8+lDj9n8hQW67qtbcb1eN+ZTD9hqkG39BnfkjnJeAdagfDBl08Utfmhq gZpH0SI/6ug18pVTPU4MBAWHgyILWXsuSydFrt/Sw6pq+G53ACWWs8zYMvmfZB9y 4ABsr1k0YtM2wwist+XlxRQqH+NOqc9sUPeTfPmITxyvotAXR6sHrjEj12sQIE65 /IfFFvsYFlfmHpy9bX5Y3hQ05sscd35ONefXYzNDxe0spVpwbKmRc20Nd/TtjtDO yINrxW1e92karKJUf2cO4GowOElP6c5MRSXzmmIDnahoJ/CSXcf5c5lv/YhdJU7M b8ZYTBJqeaZYQemukOLyn8bXMlZdx4lSdQotO7wwnmXNxDaLt3AsoynM93yti0pJ NuhNdFwG/ml5gDVcK6Vfq/f2mOcNf3YCkl7vJuLvvR+Qc1/+cpSpmnGxMC8qPp1m cg9cX8n5eTzA6ypwRli4S+V+fJsi00SYpQGY72UEFwN/MmSJTL8vQevba2IHC8eR Qj37A6623FIQRfV4CnPupuZ8i/ErZMgUM423EeuAg68TEgP+w22IijHD9ZLXlm7O LfwZqbN9zHTd8TIoBYNBEzCv94oduRyUa0//S1mfW1QH9sHDoA0CNud3OBtTdpwL iQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGvTCCBKWgAwIBAgIQQAFu+vTv3OApPm6UEHkE2zANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTkxMjEyMTYzMzA2WhcNMjkx MjEyMTYzMzA2WjBZMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MRcw FQYDVQQLEw5UcnVzdElEIFNlcnZlcjEdMBsGA1UEAxMUVHJ1c3RJRCBTZXJ2ZXIg Q0EgRTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCw2noNf5d9aI48 9lAsvHo3VBSkbc9PMkna5BPiT0+ohCr6wOm+qEt1Lni5TwYnlthG4uPplcmjUkPJ L9Ct9E9bd9XjWqHThf6CNo4VVYo0OqTqQoGJL3cuPyLKI5YRxiQDz4WPrn5I1KIR 7hJtOg6q1n4diNYmIk2j3lGAw1fhdAypgz649D3r8ri16IYh7k29VabMAZF5FaVd MKdUQLIWtDi4xoU20BNWa6IWhYi7UZIeC9qywH0vAvZIGHaZAbN5pQQB4DPKDTLX 3Fec/y7HSl4a42r1QD49pDbjq6AP4LIZbjJPwN20e5miS96THTtlXfreA3sdcSaM 5ct7ykb5AgMBAAGjggKOMIICijASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB /wQEAwIBhjCBiQYIKwYBBQUHAQEEfTB7MDAGCCsGAQUFBzABhiRodHRwOi8vY29t bWVyY2lhbC5vY3NwLmlkZW50cnVzdC5jb20wRwYIKwYBBQUHMAKGO2h0dHA6Ly92 YWxpZGF0aW9uLmlkZW50cnVzdC5jb20vcm9vdHMvY29tbWVyY2lhbHJvb3RjYTEu cDdjMB8GA1UdIwQYMBaAFO1EGcDT8AaL7qR7vkLnJlTIjjZ2MIIBKwYDVR0gBIIB IjCCAR4wggEaBgRVHSAAMIIBEDBKBggrBgEFBQcCARY+aHR0cHM6Ly9zZWN1cmUu aWRlbnRydXN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L3RzL2luZGV4Lmh0bWww gcEGCCsGAQUFBwICMIG0DIGxVGhpcyBUcnVzdElEIFNlcnZlciBDZXJ0aWZpY2F0 ZSBoYXMgYmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIElkZW5UcnVzdCdz IFRydXN0SUQgQ2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vc2Vj dXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRleC5o dG1sMEoGA1UdHwRDMEEwP6A9oDuGOWh0dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVz dC5jb20vY3JsL2NvbW1lcmNpYWxyb290Y2ExLmNybDAdBgNVHQ4EFgQUw1Vj5cKI jTEdZOP0abicXFDZOI8wHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0G CSqGSIb3DQEBCwUAA4ICAQCb1autJtX9K/9MgtPlxzEfe8yRRiGE+UY6Jqwvtvxk RR9ov7jRBlO/9S/rjuXZvcF/NtGDtVoLlIEU7otk8mE8D1712oWnczgu161L1eCZ AC/GNA5sZy1hmz2y5qpmTUB0qONN4hHJWITU20h3g5fEyaDfralsjeq0f1NRZ5uh mKehxp657heq9o7QRMw7dYkED0rS9ECIllKiG3jWdPeLTftVZ6fBTp9SN3SeXlgO 4CzsUQFuaPrw2WwLNtzqjmvbXs6WDLWotilqbT93r/PfoIlx1zyd+tPchVkpIZug zxMT3zVEuKHW7dVU9q/izK9SvY12KoXA4eYcN9M7Y5E0P34sjKr17rcF9lDPNoNk b1l4XSIFWfVI/D2HwmChODtcUakRTW5kzzjr9Ra4SfbA/Cc2d5fM//mXk/lE+3rp dNCXC7WgfQNrmQzo8FNJIMsxh/L2nbYTeAX7dxsZGzWil9fYKhSwwJbHFsfx2i1M dY68DusAaTHFJCQLgqiQk4XF7YvAnLHUDUcBJ5Y1wb3bca21nk9QINqfe9eHnhKW uRYdG3705yinnF3Y6vIuie+C0RjMYeqz80265qEIFjlfiow+1JReIZcX1zkVCw33 t1gANR4bEEB5p9QZzxWRnHbAubjKIFWNjaMrPWouCuVtRxWDdYE8OiJE98aMdUys yg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG1jCCBL6gAwIBAgIQQAFu+wogXPrr4Y9x1zq7eDANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTkxMjEyMTY1NjE1WhcNMjkx MjEyMTY1NjE1WjByMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MS4w LAYDVQQLEyVIeWRyYW50SUQgVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlMR8w HQYDVQQDExZIeWRyYW50SUQgU2VydmVyIENBIE8xMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA6huZbDVWMGj7XbFZQWl+uhh0SIeWhO8rl79MV4+7ZSj2 Lxos5e8za0H1JVVzTNPaup2Go438C5zeaqaGtyUshV8D0xwUiWyamspTao7PjjuC h81+tp9z76rp1irjNMh5o/zeJ0h3Kag5zQG9sfI7J7ihLnTFbArjNZIRaZnszOnu Ga18jh/9epnGmEYL5BV119LNVo5luWshvG/kifk9mHjtkA8LzVdsOkvCrmHBpzpD o4qyPk2lDypq04IU48JUqhFrG4kvlPz+VO7sse0uxYXj81FdNb2qoJnvAjqV+Zj4 Nii8PIcuNGqghDjzrs2PW/gEhkaWDikhhSY7DjOLiQIDAQABo4ICjjCCAoowEgYD VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwgYkGCCsGAQUFBwEBBH0w ezAwBggrBgEFBQcwAYYkaHR0cDovL2NvbW1lcmNpYWwub2NzcC5pZGVudHJ1c3Qu Y29tMEcGCCsGAQUFBzAChjtodHRwOi8vdmFsaWRhdGlvbi5pZGVudHJ1c3QuY29t L3Jvb3RzL2NvbW1lcmNpYWxyb290Y2ExLnA3YzAfBgNVHSMEGDAWgBTtRBnA0/AG i+6ke75C5yZUyI42djCCASsGA1UdIASCASIwggEeMIIBGgYEVR0gADCCARAwSgYI KwYBBQUHAgEWPmh0dHBzOi8vc2VjdXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNh dGVzL3BvbGljeS90cy9pbmRleC5odG1sMIHBBggrBgEFBQcCAjCBtAyBsVRoaXMg VHJ1c3RJRCBTZXJ2ZXIgQ2VydGlmaWNhdGUgaGFzIGJlZW4gaXNzdWVkIGluIGFj Y29yZGFuY2Ugd2l0aCBJZGVuVHJ1c3QncyBUcnVzdElEIENlcnRpZmljYXRlIFBv bGljeSBmb3VuZCBhdCBodHRwczovL3NlY3VyZS5pZGVudHJ1c3QuY29tL2NlcnRp ZmljYXRlcy9wb2xpY3kvdHMvaW5kZXguaHRtbDBKBgNVHR8EQzBBMD+gPaA7hjlo dHRwOi8vdmFsaWRhdGlvbi5pZGVudHJ1c3QuY29tL2NybC9jb21tZXJjaWFscm9v dGNhMS5jcmwwHQYDVR0OBBYEFIm4m7ae7fuwxr0N7GdOPKOSnS35MB0GA1UdJQQW MBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAgEAdMrY9RYw NyVgzeOqqcbdIxy5gHRQFbh3RTuIi0fsnbEh3v7BN+I3zmXJq71gyLOzG9wvqCul XtLQNAZnrlSacXichYDV5zdcnbBrFH/CXt47oW4L+9yD5LPMKaSU5DP9DEu88ws+ QAjzL6/q+hP+CLQh0/vr62HoEGS1+NyLfnJIN0RVcVDxBAwVqNF8MU5An98ZmHj4 XaSPA6s2s+3794ULe6r2TzVXiLtun0JJ0kBZL3Mx0plhONvhq7jCsa6bYCF71DNs 7VhrNUh+BZNdQvLqAdfQJtFY5EiWpExhiPC/ZdtVYN5RfrOMCWgBbjnl5e2n5WYa 7LM4HR+z7U+6JCBqaRjlbaNNLed/qg+OMdpBJe16qJJT9E5Uzdc4PsUbL2a+9IUb uxx8nmrbQswe8p4yvcy9RLje07a4Y09otZ/Aai3Gijup67jTCez1hd7VYIAuznqP os6SLponh2vVcHu9vQoT18OCL9janJ2Ilh3lJHUxv1kHD9IxZNpn0j/QPzGFv2Ez UXZVAECEQLS80qWh6zCXhXl6dVAeM84sSysIiY4Kv8oaXEF5Atyg0LcUuB6Iwgg3 K/QUY3QusnjrDcgGRyoWn0Zt53meMCi3C0hoQ+FrQ3zF4/7wtxKnGGBH5hKBU23M 2XrKEZL5RmGZidpWP6ZBbvEs2MqSD7zcFvY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDmTCCAyCgAwIBAgIRAINZ/Bf3bmH+SkpsTtPScaIwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MTIx OTAwMDAwMFoXDTI5MTIxODIzNTk1OVowXjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT DkRORW5jcnlwdCwgSW5jMTYwNAYDVQQDDC1ETkVuY3J5cHQgRUNDIERWIFNTTC9U TFMgIFtSdW4gYnkgdGhlIElzc3Vlcl0wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARs 2uAfos6NKHRUNtdx2q1XNWB7hbzYR+i2044/4bFqpGuGteWmF2YtVrL9iry06uaf 0ka0S0lcwcyX+1rWizrtgtaG1+IgKwjaHmfCAFpMDhpRAP0WHugGAY3ugzs97pyj ggF1MIIBcTAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4E FgQUFSbBBMIFB3ijpKfInb+reCnBYdkwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1Ud IAQbMBkwDQYLKwYBBAGyMQECAkwwCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGG P2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0 aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0 dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNy dDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjO PQQDAwNnADBkAjAatPO5rS+fADHuQkmSbBv205oJSbRORz0mqf425Dx/ZNekhR4K 3eYGpHTb+pwQuwsCME4tejkxzlmeaC9uiOIBzDwyr8Q9/93szcwu4wV3Hw+cb95K SbKt77NS6V7EbzmtWA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG/zCCBOegAwIBAgIQWglratfwwcS48AB7AxQa2TANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkx MjE5MDAwMDAwWhcNMjkxMjE4MjM1OTU5WjBfMQswCQYDVQQGEwJVUzEXMBUGA1UE ChMORE5FbmNyeXB0LCBJbmMxNzA1BgNVBAMMLkRORW5jcnlwdCBTSEEyIEVWIFNT TC9UTFMgIFtSdW4gYnkgdGhlIElzc3Vlcl0wggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCPKs3bMDhvPFceCFvWNSQ2I3vgmqrpwyCGik8fgO91kilFj5pu hKWpKLBI5bUejVZGVOGbcYjAC9Nqnfo7S+Thfv4HAKSaaMRjB42MgY1UDaOCfr6+ MdrOo0CClvJmGVSBeR1jhKj6ctn8QNAI6TvAgt/OvFqCnG1az8WH837shaLG3abh qaOKVjHy9uAnpK8XczF6hVz7LiIDPOmLwLhuTQ2TwBB4hR0VGcvJYcmnccgQFMBV JqFAKVQDGcAV4MDhVqzaTuwB+d8K4ti8ydfAxWGLXF3Y418ucg9W9q2w/jMzeN8b lhcdsIzSwN8JKtRzdZCti0PjKGxA8SMnWrrUZ21ka0Uk6AC2guCpjupTLCX+TR4c 5E9n1GUgnf/71geG4jYWnGRp96zLd7dInbz2o/ZTtI+9aWwoe+6eR1f5rpMWjET4 WVFcg/Ag65+0+Z0R8KMxSqha7XA8/e7TLwo7BC8UffK2GADVb4MmHNX08AdTjIrK Hmm5/zREdfi5WZjj4AKra/M0ZnRrCBo/OIQvi4/Vk0Cs4B2urxK9Z8GnriQyjQbi AFiKnNftrwpIwzvbD/SkbYy5vSl2sbFQ6ruP0P5mi/5Odp+SfpAv+x3tWpuuinsQ WB/lrSSYyVxr03ZZ08/ULQjuT8NfDYvDciDKL2qLGxqRi32/ix6qiAFQYwIDAQAB o4IBizCCAYcwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0O BBYEFA12Jokk/NTTkxBuLvR30EpzmKPWMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4BgNV HSAEMTAvMC0GBFUdIAAwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNv bS9DUFMwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29t L1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUF BwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VT RVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2Nz cC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBiIYfk3K2eJPqq3PCS z+mIt7kAcvs+LyFdaE73Egc+VoIKz/6gjl95/V6zHn54a5AMKZSSU+1yygeVEHDf M3uoDbzNZyZMgDgWUBSGU4iYp+MlJgmqpEshKAEW1/YrzUvFaP7a9zwcT5H+4zNe dRAxHppc3VUESTzCYCrP4l1+M3MgxuJxWy+JXYtwcoxk43v2lxLD+9uQL/Q0quYm FXd/v2bfZZX3Qs5hstg+GYfWxcPll2DO9KWvbpgtj5e89do6RVwfwKSS2SH9zG1P uLs2vOvfMkpusFM3GfqlTisANPJ5Vf+xZcl9+NmJQZhRZcxOmlTlxJEVHl2ZGZUV mRIYPwMlFtgBpQ9zcn2oaU+6CJO3Yc2xan1rfy7oQn8oLB+rWZiorYGlykLJvo9Z LO6YyVGk1o8VqlsQnhv3SAH1suFsgKhNOHLYsYMb6k5EwPkPc3Q2Isis3KRaawnk v4eZJg0j2ybRK9lJ9sVswZMMnA/BIDRt0mqybBPJz1feH+3WMreUcdTPNKGFqvsK fJSBKYau2dK08iBm8sS3+WNs7H5fux8qlPeEQlC2NTOeb+EVc/HzsKp42sgxZNHs Yb4pbW45GxFtsVwxKVlvT9wwmrgkufn8MWBdVmNyTjiDF5BHkoqz+HLE+h5Dm5ic EuaN+DVMBCmTZ/0hNUhJpz1U6A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG6jCCBNKgAwIBAgIRAOiXg0mXjM9DJmX7ghLddUMwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5 MTIxOTAwMDAwMFoXDTI5MTIxODIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDkRORW5jcnlwdCwgSW5jMTcwNQYDVQQDDC5ETkVuY3J5cHQgU0hBMiBEViBT U0wvVExTICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEA2sBUIktXYjvvjMSfViCinvEl2PhI3w89SRjNtNh/YAtDxZUO 5yoBxmpMhsk++L+wY85BGtxhoMcSXyNKFZTGXASPBVMCz/VieM/xBiFF4i63hG3w tywPJ3NXmaMBGD9Bf6UGOgJ7nnGC93bpElsegBS52cooKmf3uphJttlZzWb7kRKD fM7/EtJRYNflyyUOheEVFSEqbEOyClkJ3YWuWnpUGNKJjOXtP6tGFCd5f8tl/3G9 VuEEMVyDawyhVv7Jt+PRhQxQyx4n65cAWITy6rf7RkYlA/zCC1KuNrhvlQ6Ap9cn uRsQcnqTTwxNe+tGqQUIslamz1ruCK75RuQywqNEwl+6o+eOeSLyFnGcqgq3odgc NqHVdy/SUak+u5LcxOm2+fUxOe+OHt/TcQlURC1ia1ai6mQzbnOQfrOClkfcx0SE yxCnZVwpq5avc2s9UIP7Tlr/bVYAH+8YOYJDpu6jpeLqwsmlZuRfUyj8ieSyJddN r4nz9PvCBOGaK6c6uMmb/m8tYiOLeJ+8FNMOvzPKFKw8U2TIkoqzaf4NFN+aX1fc m4EEg4wIlmaS0ErAdbIA1Tlxi0+1WzqPXFZFNB7dGPfpeD++SC/usi6ricah2sGn p+qJi5N9bGUDL2eZpcc9GEoFFWtS9VdHxJND8kozYmoItlwLklvTC5U07nECAwEA AaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1Ud DgQWBBQ9MRS9SSdax4UdNSYmZy7a/tjwGTAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYD VR0gBBswGTANBgsrBgEEAbIxAQICTDAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOg QYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmlj YXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYz aHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0Eu Y3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqG SIb3DQEBDAUAA4ICAQBQn/JoBj+Z9hMgpx2t1ParSyWXrgtwa1bMHG5/VXWY9pdt X0h8tp2eFu1irdfy+Y2nBXkTAe0EZCuHtvXcqEUQodm2z94A3j8Hpdg3Ht9LgdTf RgqOYXkyqJpBlpjHMVW7A2mCGBAVNKDF+XZbkBf/4kdykulxAvgt75wqwvBVhk6t FliJXcJ+7tD/y1lTqocvWO1FRi0qjRtqgUNWFkDxTx0hYEBcwvO/6nQux0Nptxa8 xIr8bhkgQSckVR1NXK9n7/bZd5gOVJdjlxCB6ieWabVmP14+uYGrAe3aoMTlZ2dP HUH7i9GqD/UboNvyjcgh8sLnD4lV1kivFfT+9Ef92FBV9fTu49mN/AmVR4lOjEa+ yNegwVdR2abyiT63xGlyw5zw7FwjB8TWft2yS2lTAScoUc7TV9z0Q0IylxzsYx1s YYSHevXoJYbh32ph0rTP1lm44GIjcDnEJY/SfVfufTt/Xr72wlokNRBaL/cTvWAf jgKqmj1DE7TsdfPPFJvSxLoEBapGlsy0RgTocd1i1U6FxcFbuISp4SGDE/QHTKgc uvMn4JXQHv3s+zDxMuTgSsYUfxK381OcSETXJ+aA+4T7UnKuyx14tzP4vuShXKhX WZ2rsHUCZN4AjMWKUPj7/7R7MKXyibqH3YpQ0jULJlNw5D0VlJ8qtys/PkqbOw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG6TCCBNGgAwIBAgIQBaj31bYBy7OAbYTPMvI4djANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTkx MjE5MDAwMDAwWhcNMjkxMjE4MjM1OTU5WjBfMQswCQYDVQQGEwJVUzEXMBUGA1UE ChMORE5FbmNyeXB0LCBJbmMxNzA1BgNVBAMMLkRORW5jcnlwdCBTSEEyIE9WIFNT TC9UTFMgIFtSdW4gYnkgdGhlIElzc3Vlcl0wggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDZdzyUNoUv0Z3TldjhqbKmImZDEUt1ne4SEByZuL7Oy1KHYDnw F14Iwc/KAFG/lx2VLkxGgA/yQrZugVDjj4zrsW8z/ujJa5eBfp7cVjNsxXyJ/g2G 5yIYD+3YWEsy9UyrAjFXwrUrNC/wKk312UWSu7uK1qFygqFLYwg4fWOQH41lymUM 1Xozt+MGkEcVa0W+q3Fr9bDvrjCq7Qfba/JX9yednq5JoD48qqJ745z6EmvfE+0I F8nGnedC6+yVKp0g6kugieOippjfKTvlZS+lbnnv1l96uafIryCSZ4mAu3IsN1o5 VNJhXO5doPff0J7YdfxTHoMd67FlXoyrDqFAlVJR2Ej1mV+0AFv2D1Xe1ykxN8GG OXKbIYK2xzkMgV2M9FKwCQ+aOevD0167EDfCQFatqnJsrvyc/1LPzdYNwzVAI7bL RowodubvyeGXjQM+orAmvhnz5umpuddkqXgygPJ/WiJuX9PWQUHIZly0QrMD2Who TiES61gVihbGsFp+ohuJJ2dhSI5QrgotM933JvWFcr1y3qrgTcIDdGM9sfwM+wCX kugsDSYWMINUU/KtkdC5i217ig7EtcZoYZEXYVkQKMBX59fpvjSc3RbwbXqvqNDA d7KIwHbvSn0gXsdJtjd1e1Pqv/NLE02IDRcixJcHzZBbRV9gayUgpiSneQIDAQAB o4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0O BBYEFDo7IYZIhe9id2WHxEslawlZx31GMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNV HSAEGzAZMA0GCysGAQQBsjEBAgJMMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5j cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI hvcNAQEMBQADggIBABsCBsjKmkOSSGwuHOj+AQ4pImFIarYB3oJxknS+ry1jytnD zxQkQusmCYqnTfqUBk3lwn713tsU3wSaZQgJB0WZYISDObDsazCFdFOMsu/mJsYF TBuppkE6SRdqwNl5wHdanBvgLLTlQxYkxc8TMNtTlzAidt5G1AhSfv68y+rxFds5 bMU/iSVlte2NKQHF0a8UGVOLuVkTeageFYpqvIC7ZYCiHgVBNcYCbe+1kuiF4ktQ pWTS3ReypN6aa5B+f+th9a+NYv2VYFPsL42t08wFByrOOoaI7JC9NJTMv8YC9xV2 x5f99wY7SIwk+S/lSfn0r8hpGEOoumogsuF5ZKPKntXjIb3eC3fjaR5iMgi3E8/o TwU0PUtCWRgfwuVtjKA05KAI0FP+wTNs35On7K6xlN6qIefLQ9bUE/kZEvq1G8dM GxCZUZcAeFvZpeEBWDjz4mvFBbiS3wXdV5da9int054T6xrumnNS45cwAkXoouSc eLuolHbcRdGi6U5zfGib0Z6m0m+5OeN4O4PnUWdy0JvUT6U98UMyGLSJjSMOKry5 kA5YzC/udSyCUZtsM4tQlJNjfNY1PRhsZyyNAFy1kC/gLxEjTFUoWWjucF2gcEch yHgGZRXdynlc06+Oq9vAdy92gCuyFqqjZbEkNu1gV2GmLmpx6KLbXSpikuVQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDmjCCAyCgAwIBAgIRAN6DPC0lGDfq+m3lBnViLOcwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MTIx OTAwMDAwMFoXDTI5MTIxODIzNTk1OVowXjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT DkRORW5jcnlwdCwgSW5jMTYwNAYDVQQDDC1ETkVuY3J5cHQgRUNDIE9WIFNTTC9U TFMgIFtSdW4gYnkgdGhlIElzc3Vlcl0wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATi Cjh0/9DbcQIQ9VdPDWfA3BfBxL2vNaEkmHePbVo1aq/T75a2LdHErlWBsG82JzaT sgbxJBXgSpIf23wKznphQ1jca3tdlRD/mwURjx3r4I2OzdiuTPF3yfjHgBxjt52j ggF1MIIBcTAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4E FgQUvT2LqioMAfyTGitAkxBkSiczSDMwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1Ud IAQbMBkwDQYLKwYBBAGyMQECAkwwCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGG P2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0 aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0 dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNy dDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjO PQQDAwNoADBlAjAa8UP6mOOLh6nRVbqfiMGGgA+O8RmB4PGYDM9X4hKJvQ7rMsDr wAoJzAqwrayPVY4CMQDCXrwgqM2a32Z/nZu7/iuQVZC+2VSBXVZ/cLJkGyUpWsW5 HOtCKFR3GZI972q1jGA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDsTCCAzagAwIBAgIRANutns8AqNuP6X8HIetgX50wCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5MTIx OTAwMDAwMFoXDTI5MTIxODIzNTk1OVowXjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT DkRORW5jcnlwdCwgSW5jMTYwNAYDVQQDDC1ETkVuY3J5cHQgRUNDIEVWIFNTTC9U TFMgIFtSdW4gYnkgdGhlIElzc3Vlcl0wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQS EdBLmqSfV+63O/id/XpCf4F1n6G7FbczHOqEvfURL6EMX33O1uu6ny2zsvWeJ6Qu VyO5TskrqJ8XGC4syJiEusLWypx2lkBoH0CkrrrEclyNETv7rkKg36+cxCzX3T6j ggGLMIIBhzAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4E FgQU7GZi/KvBwabkRp5P+FpENrzO6O4wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1Ud IAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29t L0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20v VVNFUlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUH AQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3Nw LnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaQAwZgIxAIartq+m4GuWu53BTIuw QChV3Dh2jfnEYdsCDvkZ4VuqXevXcLx9mVnwgTyr2w5xdAIxANsrmNaahRluOZyi yZ5b3dZbrGS+ysR9IhDzR/R13AHpKdUDWQ9H9+0/enzPJLDNww== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2zCCA8OgAwIBAgIRAKoXOjiYUiY5IzVvGi/nX/8wDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDEwODAwMDAwMFoXDTMwMDEwNzIzNTk1OVowUDELMAkGA1UEBhMCVFcxHDAaBgNV BAoTE0dsb2JhbCBEaWdpdGFsIEluYy4xIzAhBgNVBAMTGkdsb2JhbCBUcnVzdCBD QSAtIERWIChSU0EpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr6oH NQMYZgyxCSQOZOF6OjMBaKIXnyWOG9W2SA6tHENZU5sYLYpTntLQugBxHI1soJQk fv14T7EF9Xnl68yOSbftT2+5281xgxwqWUzlprEmHgEOUXYZK5lbIGaZCkHy2W5a viBcNtbnF2Qak6SgLrdO8OECGDx7aTg41S7EaGAZvy2pAPEMkU7WfAWzk2HgNhMC +Uq0U4NVE6YUqvdCvRzmKQ+2IpVEH6kHiYNvZCKwfqewNXFBZhWaKLalw53eBqo+ 5AyFDEkRNdrxJJ7QHleXtCdmPWCK6aR8Q7Jpv2kzvs0c7EtWZabDfSiPhJKYDSUm a9rFgKvPPAFhq8scTQIDAQABo4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9U gOHYm8Cd8rIDZsswHQYDVR0OBBYEFN0D9jfnwuE7auPfVTgrIN275Z4RMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgJLMAgGBmeBDAEC ATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEE ajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRy dXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVz ZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAH2PiEeWGUCgsnxVURUH8Acz GZwkT1JgbHrHdWtT0lyk8ARiNDGAofufKe6vjwMffGwU7bCALZwHal5Xu3hekjXm 570TtGd1HcXXYLs+lOfgrYOReyECZ2ebcUu4TQzn3A3F1msZgTTPBt39atPvsxHN RXvfgr44+8jyCovLNcj8Z99s/awVXGA3UhXSnAbcmpOBzwh7KMUMbqe1QUHCeEHf fitHXV44wTn7cvJ2v1Ojk1J8K9CPnud1ZX0WoI7ROC7XyikZcSFXL3bweSaWE3s0 5Hj5ilQR28yEJxAPAqRDoz6pevewCfwo4IZlDcrZ7r8kEHfo1p+XRjkmdUyMOBXC 3OPZHmwJVSg/x7lO2dZgpd1GvzC3UbK2HJZZacYp55cHMlCzQPVUqNMo53CNbXio F4OXvqIIR3RvBUEwYWiRtBmOJxt2yIP5QhvKhjifkc7Ojv6GDUjaWTbk4vllS61Q kiUD8vwJmrMnndLp7R+3NuQVkSHMxrS1ZyuA0rJH+CdyH81HYwUF2ukoLiY1V3hT manh/mjxcDlZ2D4frue4Mpj9awJ7UtJke+oaNUpmQEsuHi9BB2oq101kwIY2TcLt gAAezwzFx9up6c23V/QxS3/aLR6QacHVEnXzwNWGFN+k7FGzmGqpwOtNDdT2NCn1 BCgVeKDqhdnH1miTAVMM -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4TCCA8mgAwIBAgIQHQgpVDhMv3SvabmRFpvwLTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MTA4MDAwMDAwWhcNMzAwMTA3MjM1OTU5WjBcMQswCQYDVQQGEwJDTjEaMBgGA1UE ChMRV29UcnVzIENBIExpbWl0ZWQxMTAvBgNVBAMMKFdvVHJ1cyBPViBTZXJ2ZXIg Q0EgIFtSdW4gYnkgdGhlIElzc3Vlcl0wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCARFLq6kqQRZ4SdFMPdd3XJTcOdVVT5bvZZx0VVDrkw3TmSAloQVFf RhqDOSXg4CsIaa64qFSrC3a5sc8LgRhx7AUdvoUdfvdxIY1uoyxRWpoWO8oTUkSn EXjEPf+zrcU5cWTOi32xWL9vklYds7iOQwgsKAHDzt4an8MLGvcLxAHciyiKcDEh HZOGUHO5bKaCq+kP2rJCfVSlNvdyl1B8q+aGWXoi0gXGVL7WX4pcWj+DGuITbLB2 MzMytse4MjLJ84zaXh0UD4STlyD8tu/fakdxIwQ7K3/pP3RoGj1R9CvMWXUU+fZm KNLW5565hd9Bh3Wkz8b4ApgMD9o3RUjTAgMBAAGjggFwMIIBbDAfBgNVHSMEGDAW gBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUDUmPFTN7wE+2+zo4Cfw0 Fdpg3RQwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0l BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQEC AhYwCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBx BggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RSU0FBQUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9v Y3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAA5G7XA+fNKyj7Fy uotoII38/32eZ4UrC1vGFPEtDyd0yzOrr7SvQUoO2GLxFzIQ0SsgMNXJ4UAhMkTD yz1OA0tx0g0GjOQXBGA/yfRR7SgitRJAdbqkPfppMn+dtKXCHHx35ohTL0PklRdb mXacvR7rXUIiJMdsvZZqYwc+DpGJ+Zv0sRJZEL7pm1oZv6EV+UzjAlOnLe6yrnyD c99Kk1H/RFPUzduUWjiVR2aMDT1oMiwYeB2Zq60Sb201jqZPNQj5E+TkDD5BPFVc kLeRi3LyXBUuBvXPsdLtBNlr+LExtCDd66kjeUe2/YbTHF4ai5PZPraQxgbOJJyc gizGl/JOgrIQPUOLSQvXlxpKEqS+0z6KqV52bco2PNrC0f8ILKuw0nsfhgcGy46d Su8fmU9+FT6e61i2nteKvt8qkkSkAJKQxRUWYduN24mG/OOIkoeOPdYHi+qEfbyI qxiiqcH9cZgLK9AVuJoKtt7vg21OyrWi7S5T/WbTfTz9XL7QGe8ZODZZx6d50uo/ lDOmXm3p/kdGApvUF1UrL+og22jBLi0Ns6xzCfzrI3SpC9abvU8E9EnxQABuu/gM /B63dbaZzSsMVFxeECD9nMWv7IH+/rqyGmjqEJzgKdPGvXhqpebQ1HhWrV+j+ipc jplXB1j3GCozDFsninXG102N6wC8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDvzCCA0SgAwIBAgIQEMFptNNjqsvo/WT77yeWyTAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMTA4 MDAwMDAwWhcNMzAwMTA3MjM1OTU5WjBtMQswCQYDVQQGEwJBRTEdMBsGA1UEChMU RGlnaXRhbCBUcnVzdCBMLkwuQy4xPzA9BgNVBAMMNkRpZ2l0YWxUcnVzdCBIaWdo IEFzc3VyYW5jZSBDQSBHMyAgW1J1biBieSB0aGUgSXNzdWVyXTB2MBAGByqGSM49 AgEGBSuBBAAiA2IABFzW2EymJUYBT/cXLOHO2GzzAAGKBVIIEKv+iBt/i4Yv8JUW oXbclI6VS60Z/zV5bpGTBAN50ury2MvohHEpJdSJcdoGRABGNeN1X/WaHbhHLm34 5Yd/UWZB57i4BBcxcqOCAYswggGHMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc 4DXGY2OaMB0GA1UdDgQWBBSSTufGXknGbh/yzqisvlcUhTEDXTAOBgNVHQ8BAf8E BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEWF2h0dHBz Oi8vc2VjdGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwu dXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5 LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNl cnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcw AYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNpADBmAjEA mmKVm6UOpjalsYEwz/RY2IPr9zZRUNz9UZSd1KKxvXWdoCfG7BkO9WyBLHWb9upw AjEAgIEzJxp1Mgpahw2AA95buYzft7Dw6ufo8HDwJxOwuP2uNqNLmv+gaEGCjuHq GViN -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2jCCA8KgAwIBAgIQLKRb2KpPITfMCmRjPhvo6jANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MTA4MDAwMDAwWhcNMzAwMTA3MjM1OTU5WjBQMQswCQYDVQQGEwJUVzEcMBoGA1UE ChMTR2xvYmFsIERpZ2l0YWwgSW5jLjEjMCEGA1UEAxMaR2xvYmFsIFRydXN0IENB IC0gT1YgKFJTQSkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIgNCL tpncmv1QLoqVktAmQ5m9oMU71G0DB2QfjybMPnjTblC90usF6Bedb7XtsJcPU8nr c1gOfrgbfnSLSogscdR9fi40T2/yLhM7HbigmVxnJubaCTjwhgUroalRbknGfD9w +4Cm6U9ExLWUxbrpdFj+EbVW6LePw9T+yGzXtqCEPtNSEo901g2q4RyuLToRl8R/ c0Upcz3BTw7HMA0zN8K25y3QRxrN/SHBQqSMMhZkYq41AOPQ0WY8s/ZZNwOkyypO 5dv8UVqw0JJcz4BVLIW1O+WnY7iDbRxrw7dLZrZNYDd/dY4tvMvzGxRwu1bnT2eo J4As9xwos7KPHsexAgMBAAGjggF1MIIBcTAfBgNVHSMEGDAWgBRTeb9aqitKz1SA 4dibwJ3ysgNmyzAdBgNVHQ4EFgQUI9y3gbEnEdnyB/CCeu2bunnmfjgwDgYDVR0P AQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAkswCAYGZ4EMAQIC MFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VS VHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRq MGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1 c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNl cnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAbEo5Nw5PYXtkRMIl92pcoMuv c8jKPunmMDiltl4ZooJw3NSyEB5wHVJerOQIxaMPJkML2P81Y/G+788PWZ/P/oA2 Of+POzHe11Iz8QCSRzPY+HvPYctI6p/Cf3K2AbVMWJiMzn/mGsomRhoffIt1CP0f 28AYYmmX/vltmHz5aC1kV3BoAlbdRKmyyeNTSTvBF9oL9g0o4m8cwGsWHdvDZR3E Wd+kpEGs0oT6ErwgGKgp3MrQMfucy6EzkYEwMRm/obOuROuuyXvarfxO1v/ba/OC zpoHxT/oC/AhzkMmnF1HAp1roWhpp0q1jlnL3q8qgE8zwg0OW0sEFTJpSWgd1r5H 5lNaJIRd9tijxufJWT5zlTq+lfBvKUc9bQokt7rOw/vtCr8dQd9ic2FKF/4S5gR0 nH1HYiCmC5FfWHjhFdSnLXmsfhVFwOhRrRYFN6bH6RspcwTNCohdMOFTtgwyerjW nUvmBnepvTCBXUqrhDuZa/+CQCG6CMDLCE5NQQclY19P1OLD/J4CxUo4+Nw4qXi3 n/vOOnnuO59ZQxh2fXr8WhfkTyrf1dHm/i2xyoCGi0Ph29mBd5HpYWAAOdZ/0bDR 3k31Kzs3MY9EODZsM9Zg3fkstL/zZ5Rk4JQynR+h0dPzwwZB4Rp7SnVLZnSv+Cs7 APEle2tLXqk33eL8SLQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF+DCCA+CgAwIBAgIRAOJ5tkZZMaCL5kOD6VvpLSUwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDEwODAwMDAwMFoXDTMwMDEwNzIzNTk1OVowXDELMAkGA1UEBhMCQ04xGjAYBgNV BAoTEVdvVHJ1cyBDQSBMaW1pdGVkMTEwLwYDVQQDDChXb1RydXMgRVYgU2VydmVy IENBICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAqFxCoYt6Ll1p6zbrR0TNp06jb3bNRbVty6PxvZ8J2j0HEylCcZcW WW0BZrwelLPoNnvUDAZ20/2P1uLWvp3Wtak+njw4LM6lyA5wZRft7Zmudb/cQLCO 2nZBbVBqITnkPA8qKCrxFbegsPUppVD7CeaYSyMXxcpDSbTBGg3EVT76fW2qi3Z0 dewsWYBrgrmzoWAPzwaV2uKdY+JLA1QVatXExT2ZKWEZKvX5Gb74bB4WOJraH5Ds Aw99bNQ7wvKbpJAgpNvWkfAQcjiI0TD3DM07RTVmMDOtv02HhcdndY5hGIQjctFs 6d5XABwDB/i8wRrZOGaN5I16yh/AzDIdwQIDAQABo4IBhjCCAYIwHwYDVR0jBBgw FoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFMTyUvmZmtga2s+TRoPm MgvfA1gbMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4BgNVHSAEMTAvMC0GBFUdIAAwJTAj BggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwUAYDVR0fBEkwRzBF oEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRp ZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA6BggrBgEFBQcw AoYuaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFBQUNBLmNy dDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG 9w0BAQwFAAOCAgEAOaN8eJFZnVqo8b3j8Wb+q+4QN+NX/+X48UVMS+P3j98qCXaY Z3dTRztiQhNGEUoF5gU+qaJ2s0hXYtwqDr5/+sPISRvdMsNt3JsbJbMZrVZ25Qj1 +t2lqt+DVjjxjyOwqqqNAaFYBFqbQ06oLknVCGhzgw3bhxoo8UKqOhTBsqEqTSje lCaJOCVj/wtaqZbhpw6SBI0J+3jAzfJIz8HqXrApFrBs93IZQNqMQCV+hurQJ8CR IuZajL8ITi2I76hhzJ5Pz9jxVjfPM6fEjMRil0qFK9KiI8MglySZlwo85hUaUcfh Q5f4box9u6+2fOzGsGwksUJ3+++hy4bbT5H8hKjuWHZOlP3M1sLQ3VVX7wXHKKa1 n21qDq/1CzTfUmz7q3qOhdOWPFHhnDuRdKmAD9HVYdQ5ZkYdtW6cwt+f1+pc7cCw 00Iu3zoQt5rFvWn1xV6KcFhpikvrtjwkWarzanuYxhoWsEzhhv7pETogoXiRyNib VDnmPMH9oMCtkR+H6Mw+607kf4QE5yGbXuk9jjscpugkb8dei+j5ZZ/VCGA1I5qp RO4qULckExygAjyuepCyUKW6Ch24WZgCf9QNcTi3iRHDi0jrB4v57bJ8O55xEYu7 Zy9c/lezjJujwkUlyDv1zSxkjt4DhA8XX4cNU2nhS+Gm7MmSLD3sPaNWwEs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQDZz+3TN6EBnfuv7W+kvaJzAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMTA4 MDAwMDAwWhcNMzAwMTA3MjM1OTU5WjBQMQswCQYDVQQGEwJUVzEcMBoGA1UEChMT R2xvYmFsIERpZ2l0YWwgSW5jLjEjMCEGA1UEAxMaR2xvYmFsIFRydXN0IENBIC0g RVYgKEVDQykwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATEkgxztTgk0WRHpkZE 3pkSHQmSjIaQw/3a63FcWAZGdPI7iGzjk3BZu4bzwX8gNibRVGArkv58YBnsVFsD HE/Ho4IBizCCAYcwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYD VR0OBBYEFDNJtb2TE1HdIurZtOZNzGsvXOJfMA4GA1UdDwEB/wQEAwIBhjASBgNV HRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4 BgNVHSAEMTAvMC0GBFUdIAAwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdv LmNvbS9DUFMwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3Qu Y29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsG AQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29t L1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8v b2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2gAMGUCMQCSdbVtIZdj/6tR jOIm3EstsiEnXyQmNTniRgmx6h961LWUwjv7m3lcVY0cVowMZGMCMD07R37yHspi k5cevdONRzj7LJjPr4hMM/cwYZXESXahUSoraOGJj1UxNdwlPBf0rw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzjCCA7agAwIBAgIQOX5cl88TYGdArdjSOSKrWDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MTA4MDAwMDAwWhcNMzAwMTA3MjM1OTU5WjBOMQswCQYDVQQGEwJUVzEcMBoGA1UE ChMTR2xvYmFsIERpZ2l0YWwgSW5jLjEhMB8GA1UEAxMYR2xvYmFsIFRydXN0IENB IC0gQ2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhRIS3MeI CEJEwvgPfrAt2Z4woMYoPjIrPQvMfIeWmdbyFnRmN3UhX0PS/Q7VjQrTsP6vzAMH YBeNsqhLlPXiTRuvF5TmhOgfLmH2ZBnMsoaiEw9JtA5Bia6kQK6kC4F45ZDuU/yb kWzb/fSpy3Jp34DNfqBPhmhl+BTBuOF7lRY3nDva5nezflwRiYWYSlaiaVOmGuCK tq8kQa+l04Mvfr6ds5XoSp0rkg3HRs8Q5ZlRcPG1GR/09xOUSCZ/itu4ir+TLIzY UTvJ59C82AJ6Kh1IffCemAgVGLeAQ2+he3dJDb68vR/4duP1K+4XMh3VuZMNzOb/ n25SCTPmHVaoAQIDAQABo4IBazCCAWcwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHY m8Cd8rIDZsswHQYDVR0OBBYEFD8V7RWydRKA2sXKvTL4W4x4uHxqMA4GA1UdDwEB /wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMC BggrBgEFBQcDBDAYBgNVHSAEETAPMA0GCysGAQQBsjEBAgJLMFAGA1UdHwRJMEcw RaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0 aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUH MAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVz dENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAN BgkqhkiG9w0BAQwFAAOCAgEACOOuPNYw/ONEp9NEJbAbhKLw2yM85Up41S4QCKSJ ldh1K0A6Ma+/RtCIhDrw3AnsGsPDtIcSjcxUWgB/Iv8DUd7BFNTyUVEs8lIyWrrl 89vBaEqV58qrCamr7SJk7yAS4lyMKm8QU+/qJtTEWaBllPCyh6SGDazBtRbS9Ziw z0Z9G04IK5xYItkZ5LbsRROMJgMiD4V2wmaqgw51HDCQKGsAiuuATzvUTmGfLRDr /JPiduBHA1IFwYx3L2pniQI3bTgrTb/M/EVlJgvYaJG/Uq2xxNfMQAG3KoTeD3g1 6ICtrAWL5uvDsxciLvq/rKvFoM62Wwk7/mE6NE/R1HP+L3RXwEBuwtnp51+2E3Rk fHhOCf7kyvzamWrnjwZHmL6dN2VFlgnuzcR2C9o3zMpxjnbvwiLvrFj/ll9IlfL1 /02mmlejTr9I5OXBBsu3I059KXxB85x4qn890B+FSDmJPrtR1bJ70nGKmGXKCyNm qi8Ct2p9sGMVYH5oiiwJrW19cklKFVLuR9KspRm/WwQLPusqp/GwaC4ViwDtfZTf EhgAMb08zcEdwjeqzwzogEiPBbyRWGGZNMVfc0AKUaAsDXeKgNvYDlZDdoim2zyq gIWfFoziWu/QY6ehY5Rkx2YPN3n8G/jy3MF5H6cmoQgmJ0lrRFeHS8Dr1z2OP2S+ z68= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDlzCCAx2gAwIBAgIQfSwM8UyX1Ildwpvq0G3ByzAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMTA4 MDAwMDAwWhcNMzAwMTA3MjM1OTU5WjBmMQswCQYDVQQGEwJBRTEdMBsGA1UEChMU RGlnaXRhbCBUcnVzdCBMLkwuQy4xODA2BgNVBAMML0RpZ2l0YWxUcnVzdCBBc3N1 cmVkIENBIEczICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMHYwEAYHKoZIzj0CAQYFK4EE ACIDYgAEyoFvEC4e9QtFEQFPxw6SbN475Y1vO9YRCumJ7aeoE2XKnK9PfIHhi4qt 0KO+76Tg1sOE3QGWA+KOEXrz84RnOmhyWUG4oedCxuyLrk5K/ZLg8KPhmzpFumKE N/QLiPdvo4IBazCCAWcwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5ow HQYDVR0OBBYEFBogJWwzkpn9Fe6LANo0cw8zJ6ESMA4GA1UdDwEB/wQEAwIBhjAS BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDAYBgNVHSAEETAPMA0GCysGAQQBsjEBAgJNMFAGA1UdHwRJMEcwRaBDoEGGP2h0 dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6 Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAl BggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQD AwNoADBlAjAa9OvKn0T7pwpsAYDTOZqY6MeqjkbZXC2Cvxho1sEx1hk5KaEFT3iA TKRHTYkEybgCMQDZKsEXjBl4HyAzv6c/QGIDpoIircxxHbcjYFZL4WjjZN6tgPX+ mL/rDXWCkTMgjgA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG5jCCBM6gAwIBAgIQD7vzxof2pKmV4hEWmOefkjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MTA4MDAwMDAwWhcNMzAwMTA3MjM1OTU5WjBmMQswCQYDVQQGEwJBRTEdMBsGA1UE ChMURGlnaXRhbCBUcnVzdCBMLkwuQy4xODA2BgNVBAMML0RpZ2l0YWxUcnVzdCBB c3N1cmVkIENBIEc0ICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAxTUra2nGJcCFOPYx9NVeaNqIYfex7ScCOmnXa1go KyI1G3n+HKh63Eycl1Nch6EZ2JoqXtSvBc4lCohnd/funAmKzTbIzcrD87rOoT1l eb+ADC2kZatInnOXdwQs+k5DgjWhjiDLLOLnLnxzCumjcpbdu0AjO4BuO7voGTRl xdOKJ6n7j9lxr98AQS2171rHBch/FfGoKMlVeHGIn3UZOrcoPACcF3SXm7H+sA9i GFsWn+keUCr0da+vsjX/dnf2dyvR8+AmjfFiHACL0XzF2GcBCPfARgDzpqlP6QQS /5xMfRyyyqT2sLmhTfDlHr2mjgcqepX8ayggVeaBYC8DCEXvSVF6oAUgnoOE+8Pg oS9zzZXFkih80UIAHgG199HMeBCjSVmU3VYsniLSElRtkpdAuTI4qZ/cmRill0KA mimH6A4O6Pa65a1Xe1vio1fwrODvOa0enpV84Bs5RSuLFeefS9X/K2RBT8j7x+lR gdpUWeCIaEEduUnc6+yeiCpCnvWTpKxb7/hYLt6zWRy5VVl94SZQXn3K1oAUTwWa L6GcmebHXiPuTw3oBkkHcLY6fjaMVyQV338EhqMTR2utOMOwgWskDXldzpiWeS+a LUPeNeSUNDSCmxH9TJRYX6sJuoK1vSa+Fz/+doHgkTzkUV5YGDdeCaTnMs6AtOw3 5f0CAwEAAaOCAWswggFnMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bL MB0GA1UdDgQWBBT2immucNhZ7T0tOUSfq7cAGcuPGDAOBgNVHQ8BAf8EBAMCAYYw EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH AwQwGAYDVR0gBBEwDzANBgsrBgEEAbIxAQICTTBQBgNVHR8ESTBHMEWgQ6BBhj9o dHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlv bkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRw Oi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQw JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcN AQEMBQADggIBAGejRbEqIJv8jjFtBYucMqARa4aoqhSSXdPhfZRkBPxgYqloR9JD R0eWxeGkvJiT4MQUeRUQ4vjQfOUK/81vWPY/YbPWXhnVpfwQQ8ces0aGo8kaDbnv k5xCS8xyCfu+VurRfwIP3I57YXxXcGbYkoFJO5RqohszqIjxpaYNS/cGVTCfD7C0 PLHHbpunjnvAm245TyFtqHjMvFtcICp7WlO2aay7cKEaAO6WYu1zReyYJe1wmDhZ R3G6dlNLEbKPu1S7cgHwG1mnCJsVtyBR8xHFhOh3bCTzqt+Vdx+Vflq6QuwZpJjj uB8tnM6vKoV+XlqHuffnxEifOtquP6MgB8oyqDqd+cSIKw1597ykoQQbEydJHoAs rG/fWoIvvc0OLRFIrC04P+eSFzXwOJmae5uShnWOYvMmR+yJUgZPQd5dD3cCxUOM LVLP4vCkkkjZs1PlDrS4ULcfL42FUWHBVQYOIhmySXNOI+XL/DVMmra3rN/n+SRW +jp6dw2aNgkpJKArrjrUwxNaKTeCak/yv266sMAgGgCIxiV59uN8sNl21K+YKpYa yzq3oFuvlVCi8ZIBF+uzG2uo87HYRq5QP7Q2NGX0M6o/UQsSug7IzGT+9/BABD20 IUAFf4nbbiCaqsp5uMgBOrLgUZTiZyOI5GZDxnklTFa0aes9/Y5ExHKS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHDjCCBPagAwIBAgIRAPdjgozTITow9O94rrPEV2owDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDEwODAwMDAwMFoXDTMwMDEwNzIzNTk1OVowbTELMAkGA1UEBhMCQUUxHTAbBgNV BAoTFERpZ2l0YWwgVHJ1c3QgTC5MLkMuMT8wPQYDVQQDDDZEaWdpdGFsVHJ1c3Qg SGlnaCBBc3N1cmFuY2UgQ0EgRzQgIFtSdW4gYnkgdGhlIElzc3Vlcl0wggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIHNShluX4pbdAt/kRedTMAPLz0u9k BtXHw7UTpew/l5nxLtsrE5zs4QcJT3TGMNstHMiW8x4EwG33Bl2unchFtKCWkgEZ iX1qkBgkohj9vaf1ZoUQ/iOtez/Pe/P0NfetqC1ChvtXT/zfFbhszPUqoyiYPfX6 rCI/kT/6uZAgAESWu/eWzr//wPz3v78HS1yeG+QEIqtU44TxP4N5rlNT0X1SKPSu jcsKOWhqc3d9uKfFIRrN4OtxdO5Feu3mpjJ22LWRcS9oJYEMuf08J7O2gSkigCDD 2RLoyyG7lbquNEhruThiSnofeQBqoABu9L+TqNvkwg7KdYLtk7FaRbE8o72csRWE yO8fkmElFPHkd3B7jJ/DcXNAO4cdJEWDVtmNtZQJ1YVFaxtAt6w7NcxaFZmGWnmE 8pMAE2m0dlnvWqdQmuukUlim7RsYm/Mx0V+NGFQjHMZf4VYFw57NpAusbJxPFfVQ s6ZijWt3j2NMEBk/WfDLidq0HH5B6vfUfTH9b+6a3CYMNzQLMsT46qH6DnR+n/sX H9yK3stjFaihlHjiAvD5BIOUQwPYeBbyBnPF8rDypKbbBBEWmxouvWQYtsGxmjFB /Ess3oQ9EyZgBBtwuR0qWS/Vec7IyGsFTIuU0tkBA6YnJXULLnnqkBw9B32Tgcrq DYbF3bcHhKsMIQIDAQABo4IBizCCAYcwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHY m8Cd8rIDZsswHQYDVR0OBBYEFNN5DlFuCkPe3W/DtKC1vedovsjGMA4GA1UdDwEB /wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjA4BgNVHSAEMTAvMC0GBFUdIAAwJTAjBggrBgEFBQcCARYXaHR0 cHM6Ly9zZWN0aWdvLmNvbS9DUFMwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2Ny bC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3Jp dHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51 c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUF BzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4IC AQAhgxz+gKwNY/BD5FTUSviD/+LgMviUewBNfYk122eIR52A1qGg7d8qMAxIKHTF twQddh93Ejm1Swd2GjfFC+768aQR3ZVSVt+O08gn8ny+Oq4ZGrWUBC+Ofuz53XKC eit+SARz1m80OFpYqgLlVtmn9GY6mLg+7Y2Dmb62jMv+eLbhJfIXvbA4GHYQhG0R l7GLcbog4dtdjDbIHGjIhBRmVYAHUMB6xl/QKVAfYGxt1NFrnL7yrsCpT235BqsN MuU8ux9Iqtt2Hi2XG99tfImhENIWwkliHb33uUH94qI8Dqn8LE5TsMR4M4mdirmx gS/cTSTpphVvH5OaMSbfiClURtN8bYLsLzheTs0jIYB+veGvXIaCFilC/FTnKKaV nuWFD0uIL08WW0U0mJ3F01YnH3tjJz83tZUGm17OpR1PZRnEWPvg79pMoaIPKrA+ 3l2716QIgMNUsLqldo1j5TFNSmYFVjhmAO7u9aEQzLrehRg7T7VMZlkpLpNylLhI 5qoo3vmyqR+4bN6czcKW8jeOIqScoLAwm1m43Nq3Ce6dpbZMvko3lsUshK+3fMGe DLFCHj6ZncIvRD+NQIzRqVRMwPV2rx8ih/VwCvCgWHI1Fqr8qoTgB38BXS4HzQY1 h1+196UZHM7iFcyoh4cxs1mIJFQHu1lp5POxgVuGV3YVxQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG8DCCBNigAwIBAgIRAI78pzR7Ou0QC8BJljBJzPQwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDEwODAwMDAwMFoXDTMwMDEwNzIzNTk1OVowZTELMAkGA1UEBhMCQUUxHTAbBgNV BAoTFERpZ2l0YWwgVHJ1c3QgTC5MLkMuMTcwNQYDVQQDDC5EaWdpdGFsVHJ1c3Qg U2VjdXJlIENBIEc0ICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAmzC4Y2Bmbm51NctZcYd3Z00oUW+VrBdvAkIKoUDy KvkFnGED7P+Pctgk+usIp3Yd+WMdF17KGwOvs/Z8lPls4lxkz1iKfaGFvnEZA+aN PsPMxNaGZL81aKK5eGs64afrtkuKQthcDwmRaNavODIAECHCfXO0Mv39J59etlNw gdbgPJpy7ZM7DmHbjxIxrXh1n6oqoJ/dw3JT9jQ66ZT6QUCfA6DRRhTU1Kg7QdEY neVOvH3N7Itw9lrosTsDLDMBTKeZB1MvSqb6SVTaz/sYAeLcsNWq9gemBrJEv5Rh BYdnOFjlu3MHwFahvEDj9T8XGqWLBhwAivyfgrTGcbE0AdHJCvKDjwFDxzYxlLdi qYKoL0+LZavOgHGGDSkYyKHTysWiVn4k1smgSHogiyS9u0twnfrpjHtyKrC9cL2/ mRxgS9l/WXIH1KdC+vbkWlya5pizAn8yqIN6hiUmPg69pb5w3YemHIXgQkQmGVHu I64WB0gGy7c2rR19de37skS1PY/YkqAA7RPwP1ZgDwn6p3U6F6+1YSyG3R0AHNGb QddMZbtBP42gl5AMAVlyY2A7u5Z9PK9JHThNWPfFszCWBy8SvkctW/xtsUSFRKg6 GGDsgK2/s/lVVWx4qs77oIOOHN9rd1jPe4qgOYCk1w10ZliO9hy/9xsep3rNcmIX 2yMCAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bL MB0GA1UdDgQWBBQbfnu16d6gxZRFUYmNQ071SE61uTAOBgNVHQ8BAf8EBAMCAYYw EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICTTAIBgZngQwBAgIwUAYDVR0fBEkw RzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNl cnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEF BQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRy dXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29t MA0GCSqGSIb3DQEBDAUAA4ICAQB5zEyZWjq5oi6BGaT4ipV9VI5WPW+hhRv6+ZBf MoXpZyXhmGTkd3+ItRPmo1zyvxl7XXRECJVABGpYC/dMEgt7y6YqmJnhMLQrjZ3F GLz/6wN18cKp83e9qvvpLZy9RTNAVIl+PI9WtJRrVf6NyGb/HXd+atrFA81So++U 2Q//Cp0MyxOMrd/16ZeVFrIZX0tEn/pNqbPB5HQRCPPJV85G7+cmENEMJcPCbivu rFYwgG3RbsLZ27u1SevPugr7bFEVCA/Ysmdm/XgUwm3QmJHsa/CRPtINSn6NJ0xT ZbrRIFUCSY/IVpXBPIdR9ClQ/V+xOW0h8BoOzIxsE4+S6ye5EpeWfUyBzyWtenN8 0TYWd9ruw/WEbCR5AGpSKEouubbBkJxK/GMO+ZG5GSwG1Q5POnEuYUqvW0qhw1PL 46sE++8mqyvXeTLUJVmtr/Aa0aOxGpo1b3LvYZE9FBCDT0r+x5+6PeNN/BoXcmj+ HY3zqbMhHKjz7kKfyUyW8ZBWbSCX3rb+YZULdXrBTTmFFwBNNnB8UE1FWkkUZwX6 2xsPwMpe6a67ZUszTFVgbRqQBA/mD7a57o1sYG1Zx+G0c93MG3IjMB7EAy8vb9JN QbvJ4THP8OFWN7k/FJl8qrVHcwXlowOBBccvxmdeDjMd78lxWw34JCvNWWTnsywe IsvufQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG6TCCBNGgAwIBAgIRAPKgIzEqgw+8k5VSK7gNTW4wDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDEwODAwMDAwMFoXDTMwMDEwNzIzNTk1OVowXjELMAkGA1UEBhMCQUUxHTAbBgNV BAoTFERpZ2l0YWwgVHJ1c3QgTC5MLkMuMTAwLgYDVQQDDCdEaWdpdGFsVHJ1c3Qg Q0EgRzQgIFtSdW4gYnkgdGhlIElzc3Vlcl0wggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCkUOHDJE3JR2hNtQoQSXVUjbINjoOzQrH01ANGaQPi9yxaibBS 60xltVH9YrFPZqjqgx2sexel1RGiJAMreMzlfwY4nbYpjAbkWFhw13f7X2Tu9Bwy ED/ezhoTYeGqtU4EkzpqPiFSj7H2Q5mmzx1+q/SAAef60k+C0TwR5NQMF7rPo6Ob PdQt7frVpr5gQ11WotOz9isNB0CyNzOyn9Km8osGiq9Z/RX3/YwGarvkiw3eJ96Q CNScw+sN8tsiO8OOYCkDWliKh5aekGzLqzYjistRlGcnfUu+Pe47v3Z5kh74d6yy ibo+4Ynmly/dHRfaYAYATdTTqM0/Q5byKnVPnYIuRVNiUsDR6tp5mZAehjBR8rqk I2O2kLw0Ehe5NdDltqfATtGAGviVSD7aRznSWJlWXXLQMteIj2zseEH6MCH+8l24 IgINZXrwRF1+60A5pXWlRaegiUoMQHHFfzKg98+L0KixX5aghMqN95Y5+2r3hC5z xZVHBIZlT5o7ujf1hTI546Zn+SmeFxb/3ByJtq/EjQ8vrjyy4XQbXDZ+PgQU3DJ9 0gcC6mxk8DKaiikMizwmWLZGsfymKqiubF/3x/5sWFQl4dJZbLMuM8cdRQ3xOZyG PQphRsGK70bTsTVFvbKLQB5Q/K/Y+CKNMIehs5oMfqoCvTbvKrcWs8uVFQIDAQAB o4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0O BBYEFPuezvRC033VvHroIvctZJ+x9f67MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNV HSAEGzAZMA0GCysGAQQBsjEBAgJNMAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5j cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI hvcNAQEMBQADggIBAFCBcJe+NiVfoeCXxzQD39lZueO9Zx031mujeA+NuJY4aRKM NpOxVMn28yVKRpa/ojO4jeMRJEu8JYLvXqRGXglZhsJOpb5pmz/gZeqnWpZGgiUg ZvZzTY541zkf2NKUQzFadZq0DNd+0G8YIueSU8Hs+K4tZBoUgHK+ih6Nw7/N4Sew BXBOaWIVVTnX4Jrv1L4r4qD9weausS6v6eRm/lteihSZ97S+hl1stSR8GlFHaQCK QquOZxrHLbIp+RYAFbBTuh0DvlEHyUW/hZG61fRcR0ch5ogDvpHRCQl/fJoh20Tq 52Rl1yafWrGMcOPw/0DvAeiuEs9qmDn684xngLtltNMy8IKfLpeBR9tJfirSmVHz 8uzzblDotpajfvwHLFksMyhSaPBl/JsqzIm23g/28aj6aXTDytgetw+ztxMyaSYy cfDfQqLwxXTXR8bEXQ6Yyugm3OfNrLzXXIfk+wr+BC//oNsj+M4kX2XjrY0Dm9UJ +LEFBbvwEESzuVhtj45uXjpU5cjoa/s7BimwjlDsfPwSvtwmfySc7vJIMF438Ty7 KZzk6egr4mcYrRd8noIEcsvynWdqBUpOAY54FF7TNS+xv4OmQFVzWrB1ENIw02zp /r2Z9xo66+AJ+z9Lm97SuUXL6QsfWLM0NJnMmmp22TpV5bRr0oxpc+/Zh3Iu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnzCCAyagAwIBAgIQDgv8b44L7KxhYOJ7kf//yDAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMTA4 MDAwMDAwWhcNMzAwMTA3MjM1OTU5WjBlMQswCQYDVQQGEwJBRTEdMBsGA1UEChMU RGlnaXRhbCBUcnVzdCBMLkwuQy4xNzA1BgNVBAMMLkRpZ2l0YWxUcnVzdCBTZWN1 cmUgQ0EgRzMgIFtSdW4gYnkgdGhlIElzc3Vlcl0wdjAQBgcqhkjOPQIBBgUrgQQA IgNiAAQT+b3P1XVw7E/Nu7ZDqgzIRmZUabwcSjSuh4IgLPsNlFjZGfVrl+iS565b 85fQz9g18JOBPmyKeXBJlXpzzV/9N+DDsEymmcBmiANtwE/Amp35b3ZHfA0YkLBj 0XSmym6jggF1MIIBcTAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAd BgNVHQ4EFgQUH79TBvFNMYaAY5Ug8EXBNZdlqEYwDgYDVR0PAQH/BAQDAgGGMBIG A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAk0wCAYGZ4EMAQICMFAGA1UdHwRJMEcw RaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0 aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUH MAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVz dENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAK BggqhkjOPQQDAwNnADBkAjAVzoTHg15j0TWe7Fw1LUyhZNgKD3SAsIJ9Z0SpT6JI UMV2x4E0l2pwnTNWRtQvPScCMBqm4oSrm83Gaejw7BYDgE1UFPTxf75/42Yd2qfQ dzZEKK+8z66O9skt5Pg9HFL/mA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDmTCCAx+gAwIBAgIQZEDSLrJJtouzuTzOroSH4jAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMTA4 MDAwMDAwWhcNMzAwMTA3MjM1OTU5WjBeMQswCQYDVQQGEwJBRTEdMBsGA1UEChMU RGlnaXRhbCBUcnVzdCBMLkwuQy4xMDAuBgNVBAMMJ0RpZ2l0YWxUcnVzdCBDQSBH MyAgW1J1biBieSB0aGUgSXNzdWVyXTB2MBAGByqGSM49AgEGBSuBBAAiA2IABA5y eLjmrWm2wRV9+p/CUqQfBSLBWi48LiXsFDGxq71FLIcbvMXeBycXDKorztI7yg3c 5RBBvEo5P3PVILG0XPypQu359PB8bNKmasepI/oOq20zu6skRwZy4jWpJhsGqqOC AXUwggFxMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQW BBS6CSpEmLf4cQjfD4NGaJ9TGtJ63zAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/ BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0g BBswGTANBgsrBgEEAbIxAQICTTAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/ aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRp b25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0 cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0 MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49 BAMDA2gAMGUCMQCKKRHjbLzHkwrCd6bPJFcEOkay9+uxyisUqOWcqG9B9nCCJ+s3 pOvVOzfumTnGAloCMF7lyVnJ4fzTav7EBKXjnesx544909Rphlms04PxwhvDkjoe EsPQB2UIF5P8ZFnLlg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDbzCCAvWgAwIBAgIRAKyCLFg9TYMzfw1zYD7UXxIwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDEw ODAwMDAwMFoXDTMwMDEwNzIzNTk1OVowUDELMAkGA1UEBhMCVFcxHDAaBgNVBAoT E0dsb2JhbCBEaWdpdGFsIEluYy4xIzAhBgNVBAMTGkdsb2JhbCBUcnVzdCBDQSAt IE9WIChFQ0MpMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXFGrZoovfAvwItBK cpYqR5Oj4qlX6OVhYO9TxH9nn4360UoR2stVIT5KTnBLWdfCJHs6F8XqUw/o0Ejx 0HmBu6OCAXUwggFxMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0G A1UdDgQWBBQuYtJcsnUL6FsQscCo9/QRAhlJ+TAOBgNVHQ8BAf8EBAMCAYYwEgYD VR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw IgYDVR0gBBswGTANBgsrBgEEAbIxAQICSzAIBgZngQwBAgIwUAYDVR0fBEkwRzBF oEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRp ZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcw AoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0 Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoG CCqGSM49BAMDA2gAMGUCMQDNsA5yNTqtqjd1lmfq3eIdzCBSZ9trRyQs2zph0fbV Km32HeTciVs+jKmAtYcmcD4CMFTQZbFoxwotQtdugK5brq43xYUeM3BJoEGow2Xj IZi+LYPfxjkjEi95E3P1392Qpw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8DCCA9igAwIBAgIQNrzFqmr2AWd5v85Zh9XfTzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MTA4MDAwMDAwWhcNMzAwMTA3MjM1OTU5WjBQMQswCQYDVQQGEwJUVzEcMBoGA1UE ChMTR2xvYmFsIERpZ2l0YWwgSW5jLjEjMCEGA1UEAxMaR2xvYmFsIFRydXN0IENB IC0gRVYgKFJTQSkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCe0pSY uR4RXNpg/ejgvR8aZJvIEke5S3YHluwq71IUDZH8H25Yvkf5qO2smnV95lsNdfLt ggvtgBjs7s7547WCyswZ5zb07yJs+dagYROeD1zHpuhfrXn9KPSpVRf4yGsNm6NK k7QqKcRdjflShRJVMrq2GTl4HL5N46u4lzTu2FDjLjlfZTDavLbMsBshRBiGwpa7 FvCF8PR4I3aV+b20F7EAKWboMfpb84kooI6mz2qt8sfiQwikzQ/MY4YjUNGF6Ufo pNGyLWFIhbhKncmupPoV7O5TImYCHGp2Ez49LFXfeFKb5H01id4wPNOyFI6/QNu/ EzqUuaeENluayPb1AgMBAAGjggGLMIIBhzAfBgNVHSMEGDAWgBRTeb9aqitKz1SA 4dibwJ3ysgNmyzAdBgNVHQ4EFgQUQxupjGGnhGh87fufibIzmPvwRMMwDgYDVR0P AQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdo dHRwczovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8v Y3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhv cml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0 LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYB BQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQAD ggIBAA5oMizJ0TvRwzOxjSyG30VNNGLAcJqYmjtetfU7E7jzNbo09oE0JdbuDrRZ jb8XgdF2LrRCferd2tr60gvSe1zfD40Ddlbzr3PZ2hRxJBmRlcuqtoGm1N3TPvuK 9GB1fO5Xh9lcaYkwNTkky6JL82vXO9udf5cE4vtC0gAjtqzTiR/iurYya3Defel7 5bRyyGyuh1ms1RZqr1yMsl0w/zL6ZZILv3+k3vjZSOcfU0+zTE/NeURZou0RCxTE 9XgMFB2qjCFTa0pff9BK1u/cAOUaevB+ZdlFwFI2HBvr9kfA7x63nb1rG84Q0t84 qaJXbZgLu9lED8XHgfM+ZtSk2o7IdBtmrlqX4vJaTtT/FnTKWXfN/FO2yWAkPzff Uh7vreR5VO9SVsCeZItv2iSuta9emxF1s7/lyMADG+O7aRboRg2r989pjZ9U1lLh B0BNEpDCqK62sapbJIdz9ffSaF5zknpd08N4ME9keXqNtq5kOEnJB8fJrKJLFo4y 74EEHrustGLnAD55/JWlUjgecmC724AfjCYYl4bgE3n7ErAshalAGz53CpBhjG5K jxSrY6Bc1RlpBfx7o/TzLsZwPlpRjTFQdGJPR4EP4zsT8SIhchTm7H5sY/RxIb37 RazWpQCviXe2+UP1gUFUHFDWndzDONa1tUfUYnvs7Evrabno -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDbzCCAvWgAwIBAgIRALNpJnuYv3Kkcbzhb4iK0fQwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDEw ODAwMDAwMFoXDTMwMDEwNzIzNTk1OVowUDELMAkGA1UEBhMCVFcxHDAaBgNVBAoT E0dsb2JhbCBEaWdpdGFsIEluYy4xIzAhBgNVBAMTGkdsb2JhbCBUcnVzdCBDQSAt IERWIChFQ0MpMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEG4yDqklp3H5Shy3t Vk3AUcGMSAGeUlPL0fztxdqZjJLVaeGBu7Jjc+/fq2ptNlWRNdGym72xkw50wk/b guD0JqOCAXUwggFxMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0G A1UdDgQWBBTsnHbwn9fzIGKbKyhXN+dxqHjBfDAOBgNVHQ8BAf8EBAMCAYYwEgYD VR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw IgYDVR0gBBswGTANBgsrBgEEAbIxAQICSzAIBgZngQwBAgEwUAYDVR0fBEkwRzBF oEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRp ZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcw AoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0 Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoG CCqGSM49BAMDA2gAMGUCMQCR7l6vmfMW8QLgKSydVJSJDbzF2s8f1nNbh4bb9zJe 6x7Ly+KKpI5PKWlKpIeUwPUCMFLAeu/HsQANDEEwqOf2yONlo/tqV9kh887Iogzq H5Lm+xzC7i6IiKmhRVUjPZeO/A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4jCCA8qgAwIBAgIRANVuJGyU7WOrsUbvwZa2T7AwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDEwODAwMDAwMFoXDTMwMDEwNzIzNTk1OVowXDELMAkGA1UEBhMCQ04xGjAYBgNV BAoTEVdvVHJ1cyBDQSBMaW1pdGVkMTEwLwYDVQQDDChXb1RydXMgRFYgU2VydmVy IENBICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEA7IE0rmVTVdRdNOzK1jsR/VppyukZ/XbQgakJHOhg6XGDsiHe/l5B 3PxyXw18jEdN+7YxP0qsGz+HlQbsQh6XlwIyjpz/2gFMiqa7y1v+dHOgj6xNOF5a oaPm/Qhb0N+JYQidgaC+1Zp6W+YeC736rzCMr9vL1Usa3QLzRoQEo0DzbG4sPeP1 US0Ia/i8o6szArH+DAcvrzCZ2kkpTScQ9QfOsvkMBP1W2otICdKUyZHaBc+ztTAd ovSlOR+GPf29dYfGQkZAp0tffIRw/na3WB86WGZPpNFfo2QxxsHYoL3oSWKfSWTY FgW22J8eA03TFHYowm/NqYuJ7GW553HppQIDAQABo4IBcDCCAWwwHwYDVR0jBBgw FoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFJmbLfaL8KPbidSe++V0 L2jSkE/kMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEB AgIWMAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0 cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmww cQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVzZXJ0cnVz dC5jb20vVVNFUlRydXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8v b2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQB5t8v3uYzHa4EL 0rOb9g/YAmptUbILcBMKk1x188ucsGVPaG1DG9bpVamxbmCtFA1MlrA7iUC8SGop KBnuWFsNKiC7jCbRoahT1/FSwFsSuDlDmOjr1MqDXE+or08UkXsJB57XxXxdVOPl DcZHII4qHi1XKK4iurMqb+kbdpAWadyfidRRCGPopYCVYLLYhRJgpFGtfr6Gk8N0 j81jq/7QbN0dRSDzMNdadKTc7c3+i9fIrXj79lV5Wvva+OL7nh8MxQhG1Ekek7Rv en++jSZvaEhCrMsSedFTA/aIy7oJg85tfglF2ybK61HsobjYzdDNICKJlIm4chlA XIDDqw2mw0Kz2snrkp9dpvMBqahF/Uy1kHzPcrq1/w5OqZWAuDKxZ68PuZ/ME2hI YbIDG9dWT6Y7eqtjQ2TmAQbOqdAG2LeikPMl2DMrPEa4lcKJzsFbHfHAW3hVgPSQ hRfS4TtbNnxijbsp8GguMHxP2R7dpAAYybwfZdXP7WYAnwEr1mzIf0Y3J0m7GDyX JhaflN3G2wIm2HzRd39NvnDRmFEraqui/YYO9ym0pwq1d0S+bGG6876QCto0u3Cg ItFh3Za2ZeIY+g5mWrejSaDs9LT7eu44iCyebfgekdMRqFeCuGAsJdsun3LOHHJo tCVPRjyFg9NDeJeMa4Z8QuXAXLd9cw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG6zCCBNOgAwIBAgIQeSmaexvS3f0QpnfHL1JU9TANBgkqhkiG9w0BAQwFADBS MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UE AxMfR2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IFI0NTAeFw0yMDAxMjAwMDAw MDBaFw0yNzAxMjAwMDAwMDBaMGIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMTgwNgYDVQQDEy9HbG9iYWxTaWduIENvcnBvcmF0ZSBJVCBB dGxhcyBSNDUgU01JTUUgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC AgoCggIBALmLoYT/vTd8M9b57KT3WrbFnqNQBWS3nXQH0dWsXx9g9vXycWHQncs3 zvw1wf0NrhHeZgkwL4b1sjNWJBNxo/DYz6LdgLWZR1h6cFqfl4YZPN7iqelISBRO MfFg4JlQgSIFpEz4Ab1ptdAcnNYDVOgMtqvuBO30uGZwJQa+ObwgJGO/ihUrhfCC FB55gz3PgGnEUP2boSEwjqzFUxzClL9etbbDUIa3tlpO4T8evAEcQ3KfG5bdbyDR yqlwEvRZapRwmvQeD4kd/zAxFRHwwP8w9pys600/MXk2YJzB7/WiYidRXukwDA2b BgeT2YklWhcfyhoB3B9w4VWn2PJ2YtE+3PqR1lp9Q+9I2GCAFZX4vOl2qSAUIi5p iI9zU/RleNl+EV9lxCIWR0qcWDw3kM/kGusHfs6r6BBQIon14lsTIPi0t2Q98EUV gEALMkzdWvR1w6v9ub66qMLgAUe+mWweyd6gN9/sTBy9uKNJtxkZXxEWf4eoHjSG YFgWiPYXA3h6HLJEqDzndgX6oUECCK0X2PqoevYqDdrYc/Y7ke1TkpHG43mQKRcx gywV0z7XOPsGnXzlZiKanzB+QftBzg1FgtTEEofYNcT9bbTQ1xiUCT69ooEq9ndJ MuXkXhiJyXXUZPAOjT4pYu+6oBq9bBX5rq3nECQqTvXs0Lj46cdTAgMBAAGjggGr MIIBpzAOBgNVHQ8BAf8EBAMCAYYwKQYDVR0lBCIwIAYIKwYBBQUHAwQGCSsGAQQB gjcVBQYJKwYBBAGCNxUGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFGJ9 uWbj1bWXMpYxQ3KGjEPSeJ72MB8GA1UdIwQYMBaAFKCTFShu7o8IsjXGnmJ5dKex Dit7MIGJBggrBgEFBQcBAQR9MHswMwYIKwYBBQUHMAGGJ2h0dHA6Ly9vY3NwLmds b2JhbHNpZ24uY29tL3NtaW1lcm9vdHI0NTBEBggrBgEFBQcwAoY4aHR0cDovL3Nl Y3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQvcjNzbXI0NWNyb3NzMjAyMC5jcnQw OwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9zbWlt ZXJvb3RyNDUuY3JsME0GA1UdIARGMEQwQgYKKwYBBAGgMgoDAjA0MDIGCCsGAQUF BwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkq hkiG9w0BAQwFAAOCAgEA2h3dySyXP4DIgt1ahFv5+hSG9COBnCaa8wLBQP7Qj6Ou RrMkCtcLFH1j8MZNO/kp49nYPQKcLlQFmtmXVDyr35Pox8hOwpw46EGS80ZHPS+g 50Aas2KomwwKy/gqT5hZEbetzJN4+gsM5NOOD7yb2B/dv6LChBXQnIU0h62JqbPp Ze9HZXiIcqHWtTWJXojBVYGUKk9NYPLHaiM/4uDqAScS3gIcxxb6/qhVXBacdiF2 ljuwDlzOxq41CyOnmedclj5O6uBZIaJ68yYre4UqZyqi/qWnFyJVne89r+pfNy7f tXYwYKX79ENbc6kb6WG67knv+DSwidSu9Gj6RNLFso9V/SXdrviNNnriHg15faC/ ZVkCEMKg6fhZTYKTbSuego7Ls+Ykl1i43mrwlMvQDJc3+xb14vGmEQJG36vPSFoK 86z22xb71nnXlWD03/Z/o+F5XketBAUoLJ/J9IWCdG1/+OaE5aLTiWmhkj7KR7Q1 SUOPJAbbvOFYb2b7Bc0njQb/vTJ8hlUERkobTOm5gslJEWAuFtsjxlJPEppvbYq+ ip32s+vyPKvVmeLk/2cy1NAxxGzU8U4kch9xzA6vo3UCUQy2T34bDQErxyG2Yt0S MFypCRlWKvREcPOVSRCzHsfpJ58ow5eZCOs9dw+5g7OQt48zvoK6hHSJqSOPIAQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFlTCCBH2gAwIBAgIQdlP+LqCXJIG0he/zt/QyYDANBgkqhkiG9w0BAQwFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDAxMjIwMDAwMDBaFw0y NjAxMjIwMDAwMDBaMFQxCzAJBgNVBAYTAlVTMRwwGgYDVQQKExNHTU8gR2xvYmFs U2lnbiBJbmMuMScwJQYDVQQDEx5OQUVTQiBJc3N1aW5nIENBIC0gU0hBMzg0IC0g RzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzKjsiyxlOQbhX8Rp1 0DaoIh+cIovFWFL46xFDa0tEeKoVizZbbZAswCyBtrPXfeebCn024Lmr2iRlP5my oejf8kJrGt+XICavL/fePZyPWZFw2O8dgwbb8WGiHmBIEu4Axe4zgvtrUOFGCy5P r+Tg7f0f3bKRJKx+Bp0/M83zzl4xiZWGPnoTxhEgj8DKjS9ONeCIdk/Z27m6smC2 0hSLOG6ES23MopbUbvA0YkiiEzyzy44VtienyJyxHnrQPi7keyla9t3SuYBy+zV0 u1gkXdvm2eDVZToavma2l25okALOkGHzvDeVL06Nb6PlystzFeHHDmUlvjpC0jbu Qn2M8ymRffETlhjknl16mvFDZAR0DzXim5MC4HnhuIZrvxg5N++WriFhaMK+AN2p 2ipaNrIUDiO6d+FI3Vn9/ct5ZW7DVfxONB4k0kNWmIorHdckbhvto5RqTOl/wvXU KQ7PNLaqsOxSv9k1V0aEapUdYfqFQ/l2FlTjvyKg6+xsBjBx0eh+bG3HWUKOm0/T YipK57sjeJTk0CQavFwDwMjMmtYkAV6d+uJmae0TwIQQqZuYsMvORQHrouJws52q rJGaq04hAGoSgaQt3HNaOaQV6ApTyQY/Ns0vTw0VzSKIBr7U3kNredbbsuI6s6SC Xw4B6Rp3eFroVqM/r530W+Ua2wIDAQABo4IBaTCCAWUwDgYDVR0PAQH/BAQDAgGG MD4GA1UdJQQ3MDUGCCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUHAwkGCisGAQQB gjcKAwQGCSqGSIb3LwEBBTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRS wK4pojmXF8u9PslJVeRBDj5l4TAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpjmove 4t0bvDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwMi5n bG9iYWxzaWduLmNvbS9yb290cjMwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2Ny bC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBHBgNVHSAEQDA+MDwGBFUdIAAw NDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3Np dG9yeS8wDQYJKoZIhvcNAQEMBQADggEBAISTcJYEYPJUY1NfYznp/okWeAajZj7a pwvTsG8O2ZpigK5k64780XztL8S8BLq48Sq1mNiI2yFSVtdHbybzq8cySIeYprS7 caeHecHI17ZJZyy0SUbp3m3YDouiUdYWzDmzydk1W7LZhKnU2SF4TxqjrHXHfMMD OEmi5jB0OTUvwT/mKsFH2wk8gr/blGieHwLVZbl+8GaXu9dyDxUvGJzPmZxNypr+ 1E2ZsTeVE0pXxFBtrt7PKV/b6CTwXwinpl6M+oFM/txpEQbtJmxyuF1l8xAqiIb5 jLvH7MlP9ERIP5T27e8iluZ4ZOnD1aDmCxLGGd8iOCMrRMJv2hhuxwY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgDCCBGigAwIBAgIQBG6lDwhK7cZI+mGDCmb06DANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwMTI3MTI0ODUzWhcNMzAwMTI3MTI0ODUzWjBNMQswCQYDVQQG EwJVUzEaMBgGA1UEChMRU1JJIEludGVybmF0aW9uYWwxIjAgBgNVBAMTGVNSSSBJ bnRlcm5hdGlvbmFsIENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQC5eRKUjMENdDOH3OfxucwLgQrmy+ZT2SMGcxj9GcyT436M8CcZZFmzrUEE 872qkTM+4hT/4tYB7OrpT9B+04ED/f2eRQHW28BDPW35bZDilpUjFvXXxRseZb+1 pq8GdkK4bXY5TjB/mLpcfz06he8w2rs0oGrD+TmuBP1CnfINaUNEaPr4dKtvvPea jhoYmyRwwjNIfNO4VNSyb0cVQdF1+t1GSRsM/mwF16HKh/5n8m7lYD7YL3IMKm4/ 6pGwinIrWXk9cMSaxpej86Hb9Zz2FJrSBDrBEqBC4jyUZ7tN30xRX2oIryCywCxZ i94QiDGN90otj5yu5g6qkC3FNU+1AgMBAAGjggJCMIICPjAdBgNVHQ4EFgQUJ1Yq DgZgzUHL6n9tNFEGmttVs8AwHwYDVR0jBBgwFoAUzsNKuZlV8rjbYL+pfr1WtZc2 p9YwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcw AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMIGBBgNVHR8EejB4MDqgOKA2hjRo dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIu Y3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1 cmVkSURSb290RzIuY3JsMIHTBgNVHSAEgcswgcgwgcUGCWCGSAGG/WwFAjCBtzAo BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBigYIKwYB BQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVz IGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50IGxvY2F0 ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL3JwYS11YTApBgNVHREEIjAg pB4wHDEaMBgGA1UEAxMRRGlnaUNlcnRQS0ktMy0xMzUwDQYJKoZIhvcNAQELBQAD ggEBACB4IF51FveALn8/7u+hRiI+T0coDoFFiCdtFYF+kqI8KzIY39UmQ3yScayc 5B4o2xkr0Yk/CEj2xS03B3DG4SLRVZNHt7XNBjcj9VfB0pkybizxsx/be7gM0rMk zu0sr2Zko/HBldGs5iGsVFb0KaB87f4qQ4qScPuDcCRpYX0XpOMBgMLRXhpylXgT 7k9hsmmdY1AHGEjZxQWaYKNN1T1XJdTrHngTnN7KysWZc7VkvEYb40fdFBKHJcoX bUVTBB0k5+V19+U+Ny7maV+Lv0wVi0/ajBRgTWy/kkIaFlFy9C8G/AbVmgWdyp+h SWKIeLLiAH4OrXYVhoZbArH1V9w= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGtDCCBJygAwIBAgIUHN/ZC09ycZhg4wHHbDaMYdkfEngwDQYJKoZIhvcNAQEL BQAwVDELMAkGA1UEBhMCQk0xGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxKjAo BgNVBAMMIVF1b1ZhZGlzIEVudGVycHJpc2UgVHJ1c3QgQ0EgMSBHMzAeFw0yMDAx MjgxOTAzMzNaFw0zMDAxMjcxOTAzMzNaMHMxCzAJBgNVBAYTAkJFMRkwFwYDVQRh DBBOVFJCRS0wNTM3Njk4MzE4MSAwHgYDVQQKDBdRdW9WYWRpcyBUcnVzdGxpbmsg QlZCQTEnMCUGA1UEAwweUXVvVmFkaXMgQmVsZ2l1bSBJc3N1aW5nIENBIEcyMIIC IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmLsm3G2sWV/LTr0gC5iOXSSL DXGEdSFvK7dsEU4wgvy3kv2sL1bpx4g9UjmoQuUiLVfvuIWOSmcunFA9CoTf+vK4 uTxqvYjOVdd6dAjUx4D+xgGGdQdONKFNv+V6PPZ7KziNO/QfJWZhw31sRv/3vybb ZdVFcaEoGhisYw6GpJ+nQfzyTuvwnjyFdNsS5qA4YgNXrmHcH91PMrM3pesCa0iA hB24snUAJjyggJWXLR3rUm7QXgOulkfQtFEPwvq66kmVt6To45h8CvmCcwqDLPp/ H1N2oMuTfEnxqDFwUP4pRHcCzUt9CWNdk8wUyyUWnWd5/YMFI2rMK5tdycfuwzxv LJn4LOUEqn0hvxtV4w1Q15MV7ipM1AiPpaWXE1WU7BNFcKO2aPWygQnkJOEKW7fg Aq0QG0FdqqGb12v1c06EQvRi5D5SJQNq15A5cpqy8XdaeXkANP/IlAMI1cnsPMBS IySuQ00zQVqHiIv+q3kls3oz7PV1aglrZ3pJXp9BZGPdcZjhJh5JkVaF8zQ6qrLP a+YO8/ud2Bklt6I0E4EY/637VhcPYTlfxmvZIPfHjM8HWdjBg2c/i+sd5CsIfeeU OWlUZV3jZbtgQijhe3meejHpbYzggZKM0jUU8/p6vsvzBKRhqj2bgABByUcFaLHH LTBX3BKrSpS+hjgan7kCAwEAAaOCAV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAw HwYDVR0jBBgwFoAUbCa9YFUpKU5mMgeg/2OLg1pLNMYwdgYIKwYBBQUHAQEEajBo MDoGCCsGAQUFBzAChi5odHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29tL3F2 ZW50Y2ExZzMuY3J0MCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5xdW92YWRpc2ds b2JhbC5jb20wEQYDVR0gBAowCDAGBgRVHSAAMCkGA1UdJQQiMCAGCCsGAQUFBwMC BggrBgEFBQcDBAYKKwYBBAGCNwoDDDA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8v Y3JsLnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdmVudGNhMWczLmNybDAdBgNVHQ4EFgQU h8m8MZcSenO7fsA9RVG0ASWVUaswDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB CwUAA4ICAQDHIQoeUvLVsFvHnBcPOctpcR7L6CHNblDN2FuSuc+f0FNOPA6V42r1 kKAI8gz+h27FL46tHmQ42FCWLdhvLBnRA/MKr/8dRx2AMcsDrj4XdEeWNQkWTaxl Eb9kSPXWOSRoHZjJW+lyxE9BcMLhZ69mBIL2jmLwhf1OPOolp1T8M4chAgfDMmNm RRIJZdUli7N6xY6eE7mAGNoFKkbryrHwpU8KEcJz4/4h6AC5jBmWuOGHiqeBF2x1 cwBoGnjpHO55tK1Wz2BK+z3yb85YPGseSSq0t28vRCfxOyyucizBff+e2YqgDL1g 4FVthrMPa0FjfjbanPfD+azwCJHRSTKrxMeNEF87rt7BnR6myI6sQ43yjvWAeScY 8aekoJuxapoN1un+1EIjWQjKVy4GWP2pb2pZtdYaaje+V6uQaLc0Y/gO/L2/KyPj EXgXoEKCImGvDczkR7koSMflqwjzPUL2Yg9jsFqpGRdQs3aHomnTSikpnXchYaR1 43pAl1ILFFN/UZM8Br9jaeR3ZkV+PsEPrvV8OEkjPMSG9eJSTjGkz0Aj4bAyIBRu iKDRBV5dKJhMPIKke6Vo3+buovXMT6qY/MV3MrSASvDDWWsUHENSpihCZlPg+jeV T5SU8jeTuDpHQQpE4yU8VVK84KnQBtxutSuhm0flD6X1EjmIjKnOPQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDgjCCAwegAwIBAgIRAO9kCADxUMyMns2lqg7MekswCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDEy OTAwMDAwMFoXDTMwMDEyODIzNTk1OVowYjELMAkGA1UEBhMCVVMxGzAZBgNVBAoT ElRydXN0T2NlYW4gTGltaXRlZDE2MDQGA1UEAxMtVHJ1c3RPY2VhbiBPcmdhbml6 YXRpb24gVmFsaWRhdGlvbiBQcm8gU1NMIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEbag3C3VGu3FZIxFneS4m6LSlKA/wIEcL97sX2vlNViD7wx+ISWpBPkz3 r7hqKFS+aofuB+wkpE1h+5BAZti5i6OCAXUwggFxMB8GA1UdIwQYMBaAFDrhCYbU zxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBT7uGqkdDdtH64tyTLP3lkbeFJiOjAO BgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICPzAIBgZn gQwBAgIwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29t L1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUF BwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VT RVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2Nz cC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2kAMGYCMQCe7xYIGkTd8VPfBXHt nFSrQTsCJGhxaWx2TvAcihPSHzCKypEjOVsvuKGj9tDC1EoCMQCNlL56ITy+ytza qlUdjrE0OS/QOVucZROkJrjsteR8eWqXd5ozVuaNwk0tlMSh/3E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5TCCA82gAwIBAgIRALcp4lNC8JQrJz7078ThsNowDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDEyOTAwMDAwMFoXDTMwMDEyODIzNTk1OVowZDELMAkGA1UEBhMCVVMxGzAZBgNV BAoTElRydXN0T2NlYW4gTGltaXRlZDE4MDYGA1UEAxMvVHJ1c3RPY2VhbiBPcmdh bml6YXRpb24gQ2xpZW50IENlcnRpZmljYXRpb24gQ0EwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQCC2q6/4h3BE+nPe56TEn22EiCz46b2AjFuY4z7qVAf 1rFCWXRg85uWAgJhrqlEtHCfsgrroIcIl7NJEaja2Uiv6YE7FUqmF2mosz/NJC0J 8vF+x3rgEbVCB2HixJUCNm7QgQb06kP4vTYeNmwJ+HOtxM3IO5BwHRRpNwra26MC naUo65yUSjVkdbIeJMLbdQS/5cn1mjMkuM4/YhYGwG9WLDqiUYom5/ywVluICsK9 kDoEbSPCCCKq/I5ppoKd0fqsLKCHnjCyzNAr1ChtEKwuBMkLN1YMFF9sJZynp/lr uZnmLRwIHuV/7VTdSSggD70Izt0z6juVerC1ClskQIOLAgMBAAGjggFrMIIBZzAf BgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQU2IqBMe+y +r+xMf0GokRcRlSeLHYwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBgGA1UdIAQRMA8wDQYL KwYBBAGyMQECAj8wUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1 c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYG CCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3Qu Y29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRw Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBQ4Sczbviy +S2cQnotegi65gnTbjmaSTsZg7C/Uuf7tJmVOdmOsL0DL1diJ6/2fVKGzoeqOqOb 1roXQWr3FmSNZyPXK/XnyNf6vUNmXt1EgGIvbCp/kDZlxaqia+eI0VlDA0eXuK0a lP4pEkLbeRLySrHu8YWMgmlksJAy5d24lmxHSp5FmF89YqTqX0y1GKEiI3dHb7QR vyphwt6LLq3o1X5i1vkLyks/QfMS6r+NCzYeN9ETRiypQIRqvuMQqCc1FRna3BY9 L8XivJ6guAlBJiPr7dzm4mwpobrO0C/Tmu9OjL/jDD7edHR16eiJ6O0vwR/DEKHc 0VvaNqLEx7szuxJRhqD02QmlXPsKca/TOE7RyfW21+fEFXij7G2YfBILmqwokk4Y RTWNEJogN1sOV4JZYRSbUIdSPAFVNk9N5s/buzShoaZa+HaMFpk2ZToRxTSxGlmp ZiIxn9Lsmkwe3IaHauupXrIuK1dmEd+rEpiDS7Cu+3MVjgJVJy0De+G6KPQYkK7b VcrhZbEgGIjkfBrQwOCK1B+mY77K2f8Yv7r7ZH3yZvT7WtYd1emUnDkxkmSUwzzO RyMOqgXCfyjSXnpd5klIebO+9WRsYgD0UzOrDKHqWYp7TR1zxOtUixu/ndzhq3qU Kp0Hlq+btDzsLB5HaUr0iEADIoFortfBuw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzjCCA7agAwIBAgIQVGFdl5j7DGyBksFR1YNATDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MTI5MDAwMDAwWhcNMzAwMTI4MjM1OTU5WjBEMQswCQYDVQQGEwJVUzEbMBkGA1UE ChMSVHJ1c3RPY2VhbiBMaW1pdGVkMRgwFgYDVQQDEw9DcmF6eVNTTCBSU0EgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChW6aqHblaacSQUKJXIDU3 4Lh7opPq9GBkU4MonOoDZdPJXAYAYB1MeOhvVXJs8776QFVPaHkMcKCHwrx+OH+I 59HNIVxNBtCnljfaEhFtrL2I2LHkPtjmAFs2EmboWMj8VDCI5X5Ff07fihfDRnOr Fmr8Zta64StgOfOjpLnAdb7Oq7XBy5OjhzGAR2s1tpbaTk6AOJXYqaK/KPx3mfSI vLuIPn9ipHU5DHFOlErc0W0Z4axLXYdk+dFKF6G/UTXFvN32KuhV7kXW4F3MKGqo 315pahSEcVjKd3alJAYrIU2icRuWR0ISU6yR8RxpzHSYIVxG4Pd3xxv8KY+5LEGr AgMBAAGjggF1MIIBcTAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAd BgNVHQ4EFgQUusN971engNMgVpf3BA34pTz1ickwDgYDVR0PAQH/BAQDAgGGMBIG A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAj8wCAYGZ4EMAQIBMFAGA1UdHwRJMEcw RaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0 aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUH MAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVz dENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAN BgkqhkiG9w0BAQwFAAOCAgEAElXkLKGZDlmmgCFlTZsJtbia/FOGo7AbmSoxwp54 k34jyjmF/k7R+FZuTz7o5iasNYfGhJ/eKsXTUh9RZND0c62++Mw8iLFI5KuqWiZI fGZWCADpMUKbsoQaSN1Oafrkc6OuyJJVtojezzv8Ah5/ubzmUCYXp45r/8Z0+5lO SrKkkKC5/+fhbi1ZPKlGqtY2Y6AEeHhTAss43fmDsVWVv2wnAIuZg4rm0Bk2iHL1 UaS05FWXHu7CJQ8Yz4KVnxrBrJ/Y46nkA8ijUDcWXL5ScUANYiBmkasmkbb0BEEu cJih79ofggHedBtIygbCYWin2NxJf1FaVnaX5X84C8tDzelkPCx7H7tw4v8ven7h LrkWwVOq7HENZDiuOVN7t3fOqrlFruwKCQnk5XXb9MJQ4TxJ4X/YiJPBaxa+dSIY Dh1zCSAVPs+rr2RE2dCSK3VZnpNloR0fkZSQ0KHwTYBJf41EwwlnJTzwV+D0VFEz 5xU3m2fbkBwJb+purTG1jPQvE1V1KvamAXwj9mt3ybm84bPOUEw0iMg+zmn2H0NT 6In60aT3E6Iy1UH0x0C1IYe4FvKLyR/FKz12kZbZntdZhj+wCC0bofhO5WXFtZPJ y8Gvo0i3EH99vrDzdwQyJyi9v1MGpaHNkDLYNdJKpCDVbFOrDNs1NNghZz5p8ZT4 DO8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQWAE9mhEYoCYAhMiVAzSf2zANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MTI5MDAwMDAwWhcNMzAwMTI4MjM1OTU5WjBUMQswCQYDVQQGEwJVUzEbMBkGA1UE ChMSVHJ1c3RPY2VhbiBMaW1pdGVkMSgwJgYDVQQDEx9UcnVzdE9jZWFuIEVuY3J5 cHRpb24zNjUgU1NMIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA 8M/70kllIlWZl7Y6EkDO8ohq0wnnlYqh9YhKSmcFnEFMORW8MYYCPdMQW6BiNgbj NBb2txv1gI3RYx4/vMbGXVw2eDahZeCPXiZFvdAKTTCdUtenG/tJHYCLHoPqS/KD RgTrcvwMk7tCr8wmb3/Eha0fDgt3uMb6DAQyp8PHy04mXy8P4e3A39t9G+YKfpAa nqRHJ19buK6mI2I5AYv8HbSylfXOBHGqbq1Yo3P1MVX1e4AoTulb8wQxrjA9nSf4 GmboMKSg0LGUn4RWL69Wx4NOxfz3vPhA1JRZaTlqw+xi2y0ulYPf8t3jF7uzhv5V 0x1+tlQK4ryT28uE5BBaeQIDAQABo4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/Wqor Ss9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFDYOoj4y64YfqpcUPYDaRuLEIklHMA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgI/MAgGBmeB DAECATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20v VVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUH AQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3Nw LnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBACAiONLPcKqPlGuMLfIN 5zx4rVfp/ylVR1xmCOYt0wxA0D+aAL5p4Sin5XDi9PnHOiKQeQmjwPig+MV2lJXq DKKR64r6LdG0f7elrrGcO0bjo+VyphdPqdxZc/Pki7IJC/CjRhwaO7yKyyLWEYDs rZRzjUl3qQ3VQvEq5Hp4BM218P4y3dmdf/XhKR09Q55FV1HIbP+nx9zwdaH144xN YHVkHn9+Ni6oSr3kpIEmC0SO1xoZI/vApD/ymZ1IRCqzxXgxMk68JMsFM+YuoCea NL6+flLdyM9Y40M/X5joe275AKb1BAoaUFea+2omf39T0F8FovYstezbIS33gSTi ch66LU+Olr2oyTCiQNERWio1oJFUwKbVoDsN9xF2ZCg+qTEi6jNoztIVcVg9q32G 0Np7VbFoxFEhoS5ZF3HTtNvWR0E74nsYZYtGnT05hTn5yR6DEzbVD+mEcanIWxPU qSEAH/ZnPebjHlSt595FB8YxSF971eJgyWoVtErkxpnF18aLc9B2BfPiIGrRA5sH lvX7rl5bprruF+u1AuhvkTOCXl9zJErotr0f7Hi305U0yr1I4jXPBWNr4ZapSLbm kq7KjVa0gGx8516IVdUwQq+xPnPH6FcoFeFoqcsX4EZ/9VUjohiWUCap9MfQ0cYq APTjHw8xAdafvrvfGIHKKS3R -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF6DCCA9CgAwIBAgIQBw1L/czFd0GTl4v2bxUqqzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MTI5MDAwMDAwWhcNMzAwMTI4MjM1OTU5WjBeMQswCQYDVQQGEwJVUzEbMBkGA1UE ChMSVHJ1c3RPY2VhbiBMaW1pdGVkMTIwMAYDVQQDEylUcnVzdE9jZWFuIE9yZ2Fu aXphdGlvbiBWYWxpZGF0aW9uIFNTTCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAII1rRFRR4lrRuxz51ibnGoeutWQLLXQQQh0Bb/LOO+JguZbZ3JY MP21tdGBFitmtw1lse6n/NG9+oUTOyBVpY0dLKEnI9djXejm5BnFOSvaNwlzXBWn iNLByEWCasvD4flXfA3moLNe7u6bVqaBXhYdPpc+NIXWG7z2vZk6KGDmb58apNvY 61AaShGOxp7HOKE34KI+qrsDMA4ZMImKotxeij6Wvc6kImyG7G1IFAnBZJJO7M4Z fTXWpwiNxnAmF8bvxdbBKxWL+dgl1+F4oKOw9GMW/rby/Z/bH/9ggXnJqMJH93RC 89ONZSGCUThJI41G+WPJd+NEUycDZFcSfGcCAwEAAaOCAXUwggFxMB8GA1UdIwQY MBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTDV6YJmAibJ2S7t7E9 +aG3BMtiBzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIx AQICPzAIBgZngQwBAgIwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2Vy dHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3Js MHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1 c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlo dHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBl7b5y LeFlE3k3C+IWKOosclifAzQh/gv0Scd+h1jQpOWWbQA6lgMlBvQJZlhyetDbWgeY 5lxqQews+ANz2mPnBcoiHibBhYrVfT/IS3XrZ2xFqY1bAzm3SQ6JJxd2i/lUu3cz kSBJ8WDfGHNsVMIMgnWph+4HMRYoD2FeCry7MHeTKEw/8c1F7lO5XQm4/m16XSJB 786njnAKUYQm/4QnbDX5s+CyEEB9fJ8enBEKaW/snioDIhKZWn76HDEhhXD0WQdH zBetJpYZAzKXOquxo2bl8kZDXYUtdtp17GUPThDEIj7FkYYlhnrnaiWIZ8c8Jhlh InH0qjBfW+r3SGhJg/lOzWRNWH38KXJi60YwKU/sHoCLMbVwF838so1PSWLuobuR X1fSLuz/NMBJsWjU3qVPXSRakelGEgn6Kr8kxVCmfqjLCoa5m13SMc/14RE3xblZ K7OskzdFWi/17ZFixShFix443uRV4EucNZSzbkUZvBr/ca9vIUg+37tkhDPbYCmU fooN3XpEv0uQhzS7BAV/f26JIX+QVL8IqNSKi573cT1fpaKTvZvSo6RIGlPf2KS0 dA9KLgiTM+7azslAAX5i9FfVnWmuMsfWHlSn8XCyQXqnrP+o1Lzba3Sj2Qt/FN8l 1i09K9sZ2x2g1pJZyD4M/RHFUdlL2HghvummDw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDYjCCAumgAwIBAgIRAMPUKMN4jsXBS0QHU7GpitYwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDEy OTAwMDAwMFoXDTMwMDEyODIzNTk1OVowRDELMAkGA1UEBhMCVVMxGzAZBgNVBAoT ElRydXN0T2NlYW4gTGltaXRlZDEYMBYGA1UEAxMPQ3JhenlTU0wgRUNDIENBMFkw EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7rbVFW3RhTnDGmzrrjT4Sn+KBZACr0UT +jGII6ube6Ss3KmBv79QNXoe+aFG6ppeeeBd1srJ8hyKJRSSVry1TqOCAXUwggFx MB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBQzk4Zz YNPn/S14gk4rAPAZduGgNzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTAN BgsrBgEEAbIxAQICPzAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDov L2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRo b3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2Ny dC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsG AQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2cA MGQCMFX96n1UmUFvakg4PC9ZpE0PdOXggtpVfbWiV0bLuSDy2+sblJkxaQoGEsC4 UiCzDAIwY/v8pWtuO2AG6PGY3G1WdtFw+91CqMU6FuNBXM/NqEKrJDZxveTf5yli M4wb3Yxm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdjCCAvygAwIBAgIQJGSVSBLLB3o3k9sPvSI4mzAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMTI5 MDAwMDAwWhcNMzAwMTI4MjM1OTU5WjBYMQswCQYDVQQGEwJVUzEbMBkGA1UEChMS VHJ1c3RPY2VhbiBMaW1pdGVkMSwwKgYDVQQDEyNUcnVzdE9jZWFuIEVuY3J5cHRp b24zNjUgUHJvIFNTTCBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI5NMoh+ VS4FSC2Rsa1fRwqmBmp2QUgl0DPBUS6jmag1BBa7f9wmPGy4si2GPVfoMz0m+lnS PkmEEq3FBOvyvrijggF1MIIBcTAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1 xmNjmjAdBgNVHQ4EFgQUDHjMvC/J5+3pyZPimmekbDiBBNcwDgYDVR0PAQH/BAQD AgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAj8wCAYGZ4EMAQIBMFAGA1Ud HwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RF Q0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYI KwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NB ZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0 LmNvbTAKBggqhkjOPQQDAwNoADBlAjEAvnvLZ7hjnfCa2Srvy1HJbnBgXIIiGgTt mkZhWTGVgTZn71gP/GIzPiqHS6sG7axkAjAwkjEP40PKftR/OBbGBKJGVeVsrBQs kI7B7gS5/SCkJjou+bHS7cvQkk56GvfQdBA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG1TCCBL2gAwIBAgIQbFWr29AHksedBwzYEZ7WvzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MTMwMDAwMDAwWhcNMzAwMTI5MjM1OTU5WjBLMQswCQYDVQQGEwJBVDEQMA4GA1UE ChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NTTCBSU0EgRG9tYWluIFNlY3VyZSBT aXRlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAhmlzfqO1Mdgj 4W3dpBPTVBX1AuvcAyG1fl0dUnw/MeueCWzRWTheZ35LVo91kLI3DDVaZKW+TBAs JBjEbYmMwcWSTWYCg5334SF0+ctDAsFxsX+rTDh9kSrG/4mp6OShubLaEIUJiZo4 t873TuSd0Wj5DWt3DtpAG8T35l/v+xrN8ub8PSSoX5Vkgw+jWf4KQtNvUFLDq8mF WhUnPL6jHAADXpvs4lTNYwOtx9yQtbpxwSt7QJY1+ICrmRJB6BuKRt/jfDJF9Jsc RQVlHIxQdKAJl7oaVnXgDkqtk2qddd3kCDXd74gv813G91z7CjsGyJ93oJIlNS3U gFbD6V54JMgZ3rSmotYbz98oZxX7MKbtCm1aJ/q+hTv2YK1yMxrnfcieKmOYBbFD hnW5O6RMA703dBK92j6XRN2EttLkQuujZgy+jXRKtaWMIlkNkWJmOiHmErQngHvt iNkIcjJumq1ddFX4iaTI40a6zgvIBtxFeDs2RfcaH73er7ctNUUqgQT5rFgJhMmF x76rQgB5OZUkodb5k2ex7P+Gu4J86bS15094UuYcV09hVeknmTh5Ex9CBKipLS2W 2wKBakf+aVYnNCU6S0nASqt2xrZpGC1v7v6DhuepyyJtn3qSV2PoBiU5Sql+aARp wUibQMGm44gjyNDqDlVp+ShLQlUH9x8CAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaA FFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTI2XhootkZaNU9ct5fCj7c tYaGpjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQIC TjAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1 c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYG CCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3Qu Y29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRw Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAVDwoIzQDV ercT0eYqZjBNJ8VNWwVFlQOtZERqn5iWnEVaLZZdzxlbvz2Fx0ExUNuUEgYkIVM4 YocKkCQ7hO5noicoq/DrEYH5IuNcuW1I8JJZ9DLuB1fYvIHlZ2JG46iNbVKA3ygA Ez86RvDQlt2C494qqPVItRjrz9YlJEGT0DrttyApq0YLFDzf+Z1pkMhh7c+7fXeJ qmIhfJpduKc8HEQkYQQShen426S3H0JrIAbKcBCiyYFuOhfyvuwVCFDfFvrjADjd 4jX1uQXd161IyFRbm89s2Oj5oU1wDYz5sx+hoCuh6lSs+/uPuWomIq3y1GDFNafW +LsHBU16lQo5Q2yh25laQsKRgyPmMpHJ98edm6y2sHUabASmRHxvGiuwwE25aDU0 2SAeepyImJ2CzB80YG7WxlynHqNhpE7xfC7PzQlLgmfEHdU+tHFeQazRQnrFkW2W kqRGIq7cKRnyypvjPMkjeiV9lRdAM9fSJvsB3svUuu1coIG1xxI1yegoGM4r5QP4 RGIVvYaiI76C0djoSbQ/dkIUUXQuB8AL5jyH34g3BZaaXyvpmnV4ilppMXVAnAYG ON51WhJ6W0xNdNJwzYASZYH+tmCWI+N60Gv2NNMGHwMZ7e9bXgzUCZH5FaBFDGR5 S9VWqHB73Q+OyIVvIbKYcSc2w/aSuFKGSA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG1zCCBL+gAwIBAgIQB1YA00tK0LoAYM/wc0eNjDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MTMwMDAwMDAwWhcNMzAwMTI5MjM1OTU5WjBNMQswCQYDVQQGEwJBVDEQMA4GA1UE ChMHWmVyb1NTTDEsMCoGA1UEAxMjWmVyb1NTTCBSU0EgQnVzaW5lc3MgU2VjdXJl IFNpdGUgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCWNEBLoW0h Vdjte1dL5NiPbPPNpQasf1VzX2N61yh1/rJaL/WEc3+0hQoVCQdwQZSIoN9RnCQd LbuHmpyRFr+CbSrF/VH+YrkhV3wvDh04Ov0HCdj/RcOLY4UGRF0HM5SrMnPXaw7z D4NGN6tPonlwUA2rVLd9Ha5IPgvQQBMlKjZw7b08uUebhxuXG2DQcAlKcIwatJlt RT5vkUPxPjBepe++GHpg4HyytApieRN8qsgWwa8RyTfLSezLx+tX4qK/B2QB4x9G UQsGGKyqTj/Vy5oQo39JVMMqPT21xBVfpdIkv27R32Tu2Lb9QJoIaXg2DwHyaEOi A+j+YbbMGCSI3gzNvCZuMGxbk7ne7SzSDCGhBC4JeZhYmdBDKCfVMQLx9gAA+uy7 wOdpJfh+ALgsU4LMtgIdM+OiZTqo7w+jSYu9Jg/J49DPclQCzqCm9eaNrfUptBsv Ar6rCtk94dYzuHh/ig0UGj5+s5niDlsQdPFuSnufB8eueSrRTrLPt8OQ5LCAzdlw C50pXmfxvUjiMva6n/grGrd/9ZzBhqg/sdqSlW/YY+176L0n/9ETql4zS4r8r7Ub sNU4jMmwHHB0wHaZSPMT+soPY4J0DWNbCotYyCpf63+JqX6gAxIE2TojYhZ4kfCV jR0emLTs0I0W/pnuXIQV9XymDUvLCtEa9QIDAQABo4IBdTCCAXEwHwYDVR0jBBgw FoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFK9VXvzalyhTvfw0JGGe efu8g3zTMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEB AgJOMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0 cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmww dgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVz dC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0 dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBADo9leXl JLa+wW9HIxU1WVraEGaLISYIyhWosUaxDbKc8MP5UQoQM01MrRiMf3zn46J4AQqt Qn6TrH1hoBKOSF2DmaehlzhpUxHuVntyr/Ga7HtudFKFnvnO5c3FZVsjlycu9i/T gzuKZEhacn7GBnNJlSr8AdoXL1Xk1CcjlO+RDH1HPy+OcFg5kSMuC03j0bDfYHkc GMsMze4cY6BUJdbI6zHQFlMACx3sCeOYyvTCTMInpM0pIavRGOk36MsTgkdHRrsw DyBeRQMWUaLexiuaEK8lrXSFiOp0Rr0fLOOyfiy4XDtyicFL3dbYwtjjdeuWCVsu d1wP6HZFzNZ5E0ZhMQNLyo9xGvByOPRvfnOsSLHDJJrfHS2gEcVmZOOAyFzX3QEO MWA92C/DSwdKA/xYMq1Dlyhkh4MIPkwIWrVVx1a2g5CX7q7r207YxPqI3EI0Xb5G wxPb7S6r4/1KdcyM+yApf+lINtx3Dv1qSgrOzfAYGrBMrkbQCQWliTZPpgKijskI RomgeX6Xxm2RN1ifRNeCdhaR/kGT9d9xTFmp8nSIO4tfY/NdlSsBYSw9R0+DoD3F 3Q53KDRIgZwe4XBgJ48AdXwOm4cCIv94tXkNpcyb/I+18hEAne3nPCCcQCsPbSCh GodI+HGUp6NRYGZrD2yq8r+FhD4BLK79CumB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG6DCCBNCgAwIBAgIRAP4S3e34ur2sFTfWXr8OPYgwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDEzMDAwMDAwMFoXDTMwMDEyOTIzNTk1OVowRzELMAkGA1UEBhMCQVQxEDAOBgNV BAoTB1plcm9TU0wxJjAkBgNVBAMTHVplcm9TU0wgUlNBIEVWIFNlY3VyZSBTaXRl IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAj9Xc6J1FDp+kBN/j gVUSn3PFDEfUO5w9a6YGBiSxpS+1MGFTEuP1fzC5bQPitw/+vBZkMIetQdLMygIr NSrdSSJiTwnd/Kx+iL3xSbzFehlHmn2jSlINMY7d/fUvF2CymKfP4G6A7+kxtGTt fdBM5gjUm43Lnbd+T4WUGC3Gc0zht/Fh/vYZOe5o+z9260cwgIxWdlgsyNO2NdRi R9Urh7J8W/md7EuB0zxC2L3cpr4o4Isq7VtJm5yrPKDzzED0jS4/2OOurXwlF0Yy fuenkCSz8RlczR8KEw9eqNZdLEO4g5A1l/qDoM9j0AY7WXX8j3j8LuagKyqlixno tp08BwS1PdEpCnkkuXk8q0yHtbevsmTCYnZcDtqpHxY16Zo8vzmE1PnA5ons1R2F oOYzyObxhQZ4gbtoNf5tGJ5RtO4MkONN1D7G6CdK+sWSER1qzFwfhIg6mS9RqQpx +VQnBLLdLo3siPmPb+oCuDE16YgpSqZjJWHmUiO6txhq/8G9OATffMgDVuHEH824 MJk50aYMqdctrAOcQsJxvX7Rk/B8IpUrsbF37ehTM5gv0pf5/0noSiPNUIhmi6UV B/SPNuUJV25dP4qb4rs1h72JSYTeqD2LxxQumU2TXmTDoMG5rlaCsUqTKPLUx2VS TCLZed8yw5z9nX4Hy+yKntrAuVkCAwEAAaOCAYswggGHMB8GA1UdIwQYMBaAFFN5 v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTov2yT2Blo3TA4urSRtMfS8X7H gzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAU BggrBgEFBQcDAQYIKwYBBQUHAwIwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYB BQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGG P2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0 aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0 dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNy dDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG 9w0BAQwFAAOCAgEAKa20C8B403IwSNG78JX5Qjsgc5QCy3qB1V07MZaD2m828j22 DmFpn2KSdQiXnWNe/UNuCwFa+fbZnLn6Ev4PIb8N+NUkmR+MhTrmf1zJnUvzHAnC 4O1HcLgZFuHBahXIKP3Fsvc08JsAmu8WHB0gBjzbIVVAKxiVZsn9ZFupKrlLmYTm x6DKGc4gUqIvf3jqI7+6ZzWaLZedEHQ/vEQZ/ao3fwI/0PEDvwFk6Hk1fSKzT2IF ypdztzQPUJD+LrnVANsBR9n2Mcdk80o2OinGtV7BE74bBwFF050Y2QU9Ifr6UPl/ e39CSwLFUMFnh+KHxSrOXVRq7XcEULMCJsddC7I5Bdln6a+/8IGhuVn8gYcQjLGa q40betervr0SXBXxNgfLY3fPBt1Yma3UDkwu8kN8egnkvIE5hUKJ0sC1+zX6RFzE czRGqQQVUZvwZWg+mYWy2UGcucjbqE23W5UhA5SejxRvJ2Gfn8l/CW1vVj+qhZ4k Ph5HBXVMA+UG7rFD8tIlaAoGEwpTAcs8s9kTRkFsZSOiqQZ3zHAidX64uoLED/XX 7o4tr6LMWgUL0PnLgqAgmbRXE0eZ/lHXymmaYErcxgYi78td6RdZEl7E8/35SmY6 8kycjoCyp7FcWe2IlBM9FVwnH2HJ+HQ072lnN4PpTi7gUcaMyWUPilFaTTs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhTCCAwygAwIBAgIQI7dt48G7KxpRlh4I6rdk6DAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMTMw MDAwMDAwWhcNMzAwMTI5MjM1OTU5WjBLMQswCQYDVQQGEwJBVDEQMA4GA1UEChMH WmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NTTCBFQ0MgRG9tYWluIFNlY3VyZSBTaXRl IENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENkFhFytTJe2qypTk1tpIV+9QuoRk gte7BRvWHwYk9qUznYzn8QtVaGOCMBBfjWXsqqivl8q1hs4wAYl03uNOXgFu7iZ7 zFP6I6T3RB0+TR5fZqathfby47yOCZiAJI4go4IBdTCCAXEwHwYDVR0jBBgwFoAU OuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFA9r5kvOOUeu9n6QHnnwMJGS yF+jMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQW MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgJO MAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVz dC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYI KwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5j b20vVVNFUlRydXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6 Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDZwAwZAIwJHBUDwHJQN3I VNltVMrICMqYQ3TYP/TXqV9t8mG5cAomG2MwqIsxnL937Gewf6WIAjAlrauksO6N UuDdDXyd330druJcZJx0+H5j5cFOYBaGsKdeGW7sCMaR2PsDFKGllas= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDiDCCAw6gAwIBAgIQMH4Ub8vZMwFxECZP9TIeFjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMTMw MDAwMDAwWhcNMzAwMTI5MjM1OTU5WjBNMQswCQYDVQQGEwJBVDEQMA4GA1UEChMH WmVyb1NTTDEsMCoGA1UEAxMjWmVyb1NTTCBFQ0MgQnVzaW5lc3MgU2VjdXJlIFNp dGUgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATeUQs3vD8M4pK4SZde/LhAtIuA 5HFyUKgw4MnhuSA/DxSX3yBN+llcPLQglpe33jf+iXMclxM8wPGYvdbu0+s1Ouct 7PTxCA40nC9/cXKZkiKJOMeDOH9YiqF/JuFJ60mjggF1MIIBcTAfBgNVHSMEGDAW gBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQUSM22PoVW55obm3wgEryT ErJPBUowDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0l BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQEC Ak4wCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2 BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0 cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNoADBlAjEAzZDsD2qb dqzbBvL7Uk9xVHJxElsnNWGwpog/RVQM6TLxRp11vaWsapzdT4Kb3l5EAjAJvEI8 X0HTatQ1vI/krwCd5B6ujVUkB4tF3O3BUsTu5QuRiJ94bhC67uMqjco23mo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDmTCCAx+gAwIBAgIRAJYwaDTXq4V3OQgle50Y11kwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDEz MDAwMDAwMFoXDTMwMDEyOTIzNTk1OVowRzELMAkGA1UEBhMCQVQxEDAOBgNVBAoT B1plcm9TU0wxJjAkBgNVBAMTHVplcm9TU0wgRUNDIEVWIFNlY3VyZSBTaXRlIENB MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm9DZyPnlQJGjqhivZY8Y+skpPNRacTuO bsP9z0frAqEDcJhqJ190yLzDMf8NGZGfu8SsJdUDXg/J3iJ0NdhGnITABj04DN+k JZxrAM4mnUBw4i8EGwETp8tNv/JLdySZo4IBizCCAYcwHwYDVR0jBBgwFoAUOuEJ htTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFDvjtdnD8al22mzMv77c+qs1GnJY MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjA4BgNVHSAEMTAvMC0GBFUdIAAwJTAjBggrBgEF BQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwUAYDVR0fBEkwRzBFoEOgQYY/ aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRp b25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0 cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0 MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49 BAMDA2gAMGUCMCVFz2ZgF1pzEwi8Pv24OcGXzzI6kkcVoTcbEY8OKO0mhgYd4xWa e8YZaQaYwaIYKwIxAKYx1ReoZ0+ChsvoFFqJwqSit6JBL7jhV7sN3jF932Cg9mrl Nimp6l92VjCtWCTHcA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAm2gAwIBAgINAf6lgMJYpzHLw7OeqzAKBggqhkjOPQQDAzBHMQswCQYD VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG A1UEAxMLR1RTIFJvb3QgUjMwHhcNMjAwMTMwMDAwMDQyWhcNMzAwMTMwMDAwMDQy WjBCMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz IExMQzEPMA0GA1UEAxMGR1RTIFkzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE 8rfkbjTwx1dixmkxk3b8dhsNCYRCnpKv6jT9gnu5BtJlK3kG/l57HRM9E1/GwErn pBxDBnkLeee+Qb3VxGWHs6OCAUEwggE9MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HQ4EFgQUqmPVghc9NFM8RUBMjCXah7zRnh4wHwYDVR0jBBgwFoAUwfEmuqAtroWB z9PxKhK9uApn/bwwYwYIKwYBBQUHAQEEVzBVMCYGCCsGAQUFBzABhhpodHRwOi8v b2NzcC5wa2kuZ29vZy9ndHNyMzArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29n L2d0c3IzL2d0c3IzLmNydDA0BgNVHR8ELTArMCmgJ6AlhiNodHRwOi8vY3JsLnBr aS5nb29nL2d0c3IzL2d0c3IzLmNybDAdBgNVHSAEFjAUMAgGBmeBDAECATAIBgZn gQwBAgIwCgYIKoZIzj0EAwMDaAAwZQIwU7aBuHn0ga9DpI+pVPx0hwo1NWeNsjfF 8MOu9Hl/pR4Quyri//In9uZfC7Q0DNztAjEA4NOsow/XOOUPqK40g8LFYMdVq6cZ dZd4327Q9Qu24pmWG7ucs8wTKkrtPKu966DP -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC6DCCAm2gAwIBAgINAf6lgUR+O/07uBwkmDAKBggqhkjOPQQDAzBHMQswCQYD VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG A1UEAxMLR1RTIFJvb3QgUjQwHhcNMjAwMTMwMDAwMDQyWhcNMzAwMTMwMDAwMDQy WjBCMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz IExMQzEPMA0GA1UEAxMGR1RTIFk0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE qPJbOoggUvyliF5Us9hq047KDrKP9uViYwR13jjZCM4rgkOdciVuN0w8zuxzFnQW aY0r085HwQKAr8rGsbJYdqOCAUEwggE9MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HQ4EFgQUtKeZiviRSayOWLmzXk/McJjNImcwHwYDVR0jBBgwFoAUgEzW63T/STaj 1dj8tT7FavCUHYwwYwYIKwYBBQUHAQEEVzBVMCYGCCsGAQUFBzABhhpodHRwOi8v b2NzcC5wa2kuZ29vZy9ndHNyNDArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29n L2d0c3I0L2d0c3I0LmNydDA0BgNVHR8ELTArMCmgJ6AlhiNodHRwOi8vY3JsLnBr aS5nb29nL2d0c3I0L2d0c3I0LmNybDAdBgNVHSAEFjAUMAgGBmeBDAECATAIBgZn gQwBAgIwCgYIKoZIzj0EAwMDaQAwZgIxAOhvO8qdXxFs2wSJAm77pG35iMG5jRNG MK0GjO9MtzB2JLeHTAEub7vCDoytztbfLQIxAOmhOSYnPWPr9Zjs9I7yLckfXtEa XraMLPrXQeXfVmKJMMbZlihKfi17khRqOAWHRw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIRAMPgD58ALsVZugLEpfJgDF4wDQYJKoZIhvcNAQELBQAw gYMxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJzAl BgNVBAMTHkNlcnR1bSBHbG9iYWwgU2VydmljZXMgQ0EgU0hBMjAeFw0yMDAxMzAx MjIzMTRaFw0yNzA1MjAxMjIzMTRaMEgxCzAJBgNVBAYTAlVTMRswGQYDVQQKDBJS b290IE5ldHdvcmtzLCBMTEMxHDAaBgNVBAMME1Jvb3QgR2xvYmFsIENBIC0gRzIw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbkYqr0vNYKfrb4HxEOVZ2 8K/ect1UFZJqUfvJe1gBWj0iTNkrlK5ZWpRlbEYdLxEIugwN1ElB7yX/i9p1RZ02 vbl9xeJE3W+fihNhgF5netuF61IMDkzHBAkNU6IoTOgtaWAYOVSP2eMTKXCrUX/r 8aX7/k3JZo6Q2flXUEnYcntMfAkXEsFYTD8BF+3LUuF+x2lckP2dAysr6FbTTCH7 nmXzw0obMOtVuYdjfFnW/j3kAk1IDK2tM59wfuxHBvBamKMfNIfB246DlZwCyjov rvrZv6wo4KGqjgwjcADR2jd6ieDEAGkpUkQ3GKKLv8l9HTkX+2DlGELIIn2PEK0J AgMBAAGjggFsMIIBaDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSxwEZx 76iODUHKX5uVKgLuLGIRSzAfBgNVHSMEGDAWgBRUmd2b/+inDqMZnVu+QlffMPyP MjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly9zdWJjYS5jcmwuY2VydHVtLnBsL2dz Y2FzaGEyLmNybDBuBggrBgEFBQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9z dWJjYS5vY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0 b3J5LmNlcnR1bS5wbC9nc2Nhc2hhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYw JAYIKwYBBQUHAgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0B AQsFAAOCAQEArPzcDkmtVrPvJyOPoFtW+YTfr6kvUd6V19OGHCBXajT08ejepxHC pFJ1riE4nWjYgVb0XMzmjj03wBXPWSPEf6PaAPKJACkUzkU8DBqkDImiPRJ0PEI3 0n4v+EePESwf6p3C1Oip8aPtwpDktjpEyBOzv9WHEvadtKQvuR6imd1SQuMnHRxr KpDf0OB33oSiJCjr2Fnf8oZ7BMG0J9Xd2UNc6ewaqZKgFj3qJgQf/MIzQaTOVxhv ZoFnOzqwVvjnKPXWGV3lPZ8ipZgWnaffKmGvqHVOWAJPTs1+RkOWD1bwaqFu88Zr AaJrGIy9xXc/OP8fOpZXHN28p+y5fj0p0g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdjCCBF6gAwIBAgIQD8F7JOWbM97N/zvWMOqKwzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwMjA1MTIyNTQwWhcNMzAwMjA1MTIyNTQwWjBDMQswCQYDVQQG EwJVUzESMBAGA1UEChMJQWRvYmUgSW5jMSAwHgYDVQQDExdBZG9iZSBQdWJsaWMg SXNzdWluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJqcd62M maCIFhpshqSZu25dTVsthyLGlMwgo91z+Om+QUTayHBq955tupzHErqGZ23Rhu0f DiUnbJbREKaXL5/Ww9j/GQ1p6tUQ0NJm9RX+AhY2K6vXIDSpKBXNVOpCPQxUaUI0 SkwO20isSHbbstXXf4u+smZ6oAgW8aYSSrHKq6o6on0+wu2NHzIyaG7Q68cCbRHc aSgmmzChWdBW8iU/vunpvY8aGi3yUnbjyfT+I+ZZvWhVlos0tQi0PqS9cEWcQEOC FnXoepbeC7P+sD7BHDHZpw9N6/isao5zwbU+yuaXvNHIDSvYw7dfXS4ZzuvIBLG2 WpoWG/B8Lhq+eLsCAwEAAaOCAkIwggI+MB0GA1UdDgQWBBR7KELkLEG2RDl10VBd BHQRluHmrzAfBgNVHSMEGDAWgBTOw0q5mVXyuNtgv6l+vVa1lzan1jAOBgNVHQ8B Af8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB /wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v b2NzcC5kaWdpY2VydC5jb20wgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwz LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwOqA4oDaG NGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RH Mi5jcmwwgdMGA1UdIASByzCByDCBxQYJYIZIAYb9bAUCMIG3MCgGCCsGAQUFBwIB FhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxB bnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5j ZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRw czovL3d3dy5kaWdpY2VydC5jb20vcnBhLXVhMCkGA1UdEQQiMCCkHjAcMRowGAYD VQQDExFEaWdpQ2VydFBLSS0zLTEzOTANBgkqhkiG9w0BAQsFAAOCAQEAe2XCuNtw /7JdKTxxhQZZSDlAw+m4/Go9YEnHMgrXUSpiCxZghqRH7uLQWT+saKQAp9qcBKO8 yo2gZ31kCjCOiMNsJYQYPR9HeU9UzYz3/X8XXDbJI78TpQOLhYpJOTuGS3aeRiLu Z9XPsUd4M5PSMfY9bmJ516isqGEe+iPpShN5fOa9l9H/2+6xV/X/38okGtABidTe W4lqSSy+ZlnQd+SwGMYSoiH68hvJ79CWnF2pVgvmA4MFrABQUw24q3X2r9Vfi3ch wp/ENsmUhyWV1sEqVDZXs58zcR3g4A8Xi+w8JhnXUV40/f12/yOrXK5r0JSPhoF4 6HIrpwB5M6IpzQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFhjCCBG6gAwIBAgIQA3dkg5X+rkBw0ajVnPFjMTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwMjA1MTIyNjQyWhcNMzAwMjA1MTIyNjQyWjBTMQswCQYDVQQG EwJTRTEhMB8GA1UEChMYVm9sdm8gQ2FyIENvcnBvcmF0aW9uIEFCMSEwHwYDVQQD ExhWb2x2byBDYXIgQ29ycG9yYXRpb24gQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCtVuM8Lgh1f7qdFwmCSq2G22c5AE4GBJh4QtrT/nXdrZBDQyvz DJEC7AOde82mxjnxRoxkyE1LCwlyxgFUWTTMHdsNwtBlG9LN+cdaTe/+ssGpV6wS W+viFRrFfGVCgbqqy0dxkU9nV5gnkWG72Mt09D/3SOwhF4xZlFRoUtjaSwVV2vJH QV025eWUlIa0hGqGZKgMXtrNh4UfmBhH7Y60GKCXmdd2KU3JZkREgEo0WcK5Rt+d gb592ufCwLbVB+n4W4eMDARHsABbphLGpNiXTqaxhMaQ2Ar+dTHRccYoUjZPgppb 9Juzola+W1jEVPcmmP/1uiQHGtp3h3lTrZkVAgMBAAGjggJCMIICPjAdBgNVHQ4E FgQUjjH+02KNSjhOePkn6pvMSC6OAG4wHwYDVR0jBBgwFoAUzsNKuZlV8rjbYL+p fr1WtZc2p9YwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr BgEFBQcDBDASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggr BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMIGBBgNVHR8EejB4MDqg OKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS b290RzIuY3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNl cnRBc3N1cmVkSURSb290RzIuY3JsMIHTBgNVHSAEgcswgcgwgcUGCWCGSAGG/WwF AjCBtzAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCB igYIKwYBBQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50 IGxvY2F0ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL3JwYS11YTApBgNV HREEIjAgpB4wHDEaMBgGA1UEAxMRRGlnaUNlcnRQS0ktMy0xMzcwDQYJKoZIhvcN AQELBQADggEBAD00Yy36gcGMioD+g2WpfrBu3YIuEMRf1BPvHCE5Yyq9rkZU4YoL kmha3IKwTHWT0/1ZTiotCpchJ+cUaurwcMt90kOogW7azp6T2+BJZVYTmmxwZAoo pV9aBGse59qhmyaWJtUl7rNk+fguB3gTGew7HK37otwjoGjuJX9P1NsNhblc/Bdy SjbENIKfjFbu574t+bvO5H897rXuytZM7WhfnMFaPzR/HR/Tt9ivZCFkzh2LM9tK tR/bUlK2WdTtd+YeuyS62ws1HwvNunZWF/wQxuU0bGLCw6xLcQp6bZ1w+yQIDm3e 5BvdQ13QQDRwSaAkfuSzFwijZEUMM7Jnpfk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGNzCCBR+gAwIBAgIOSUEs5ABoqa4TNDQoI7MwDQYJKoZIhvcNAQELBQAwgacx CzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEVMBMGA1UECgwMTmV0TG9j ayBLZnQuMTcwNQYDVQQLDC5UYW7DunPDrXR2w6FueWtpYWTDs2sgKENlcnRpZmlj YXRpb24gU2VydmljZXMpMTUwMwYDVQQDDCxOZXRMb2NrIEFyYW55IChDbGFzcyBH b2xkKSBGxZF0YW7DunPDrXR2w6FueTAeFw0yMDAyMTAxNjMyMjZaFw0yODExMTQx NjMyMjZaMGExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEVMBMGA1UE CgwMTkVUTE9DSyBMdGQuMSgwJgYDVQQDDB9ORVRMT0NLIFRydXN0IFF1YWxpZmll ZCBFViBDQSAzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6/uyvAd0 Yuw+PoYO/2EqxdSEdXnmPGc7w4q14+Mhew/ASTmeeN1f5z5zjCHKyQpEtcEmdYx9 +wTFW66XW+GSVdgM1mhGl84ihGh44XzDPHXDoG3TaydQzNw1JejfgoIzMfGEI5Qa hSGkhnePRt8Leku07kiNXzSkibTuyUemh16wG8jpHjO0FNJHqq/u8zS6djVAG6IM Chwwf7c+b8eOrsgZUvYecQacFLqeps2OGfbOO95sUOb5E+nHmyaxhCmGApPGJCiw K/yZk1hcf8z784EjHPC3HwFDA0FjY9Zr2OVe4+ps3k4wDB12nqyuSLY0qPEyWEyw piOivkGrEtjmGwIDAWdPo4ICpDCCAqAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B Af8EBAMCAQYwHwYDVR0jBBgwFoAUzPpnk/C2uNClwB7zU/2MU9+D15YwHQYDVR0O BBYEFLDcla6YCMiPFzbgi7zkSbOPSzpXMIIBPgYIKwYBBQUHAQEEggEwMIIBLDAs BggrBgEFBQcwAYYgaHR0cDovL29jc3AxLm5ldGxvY2suaHUvZ29sZC5jZ2kwLAYI KwYBBQUHMAGGIGh0dHA6Ly9vY3NwMi5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsG AQUFBzABhiBodHRwOi8vb2NzcDMubmV0bG9jay5odS9nb2xkLmNnaTA0BggrBgEF BQcwAoYoaHR0cDovL2FpYTEubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0 BggrBgEFBQcwAoYoaHR0cDovL2FpYTIubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9 Z29sZDA0BggrBgEFBQcwAoYoaHR0cDovL2FpYTMubmV0bG9jay5odS9pbmRleC5j Z2k/Y2E9Z29sZDCBngYDVR0fBIGWMIGTMC+gLaArhilodHRwOi8vY3JsMS5uZXRs b2NrLmh1L2luZGV4LmNnaT9jcmw9Z29sZDAvoC2gK4YpaHR0cDovL2NybDIubmV0 bG9jay5odS9pbmRleC5jZ2k/Y3JsPWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwzLm5l dGxvY2suaHUvaW5kZXguY2dpP2NybD1nb2xkMDsGA1UdIAQ0MDIwMAYEVR0gADAo MCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3Lm5ldGxvY2suaHUvZG9jczAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAKNUbRRH bw1HtuynqiWW19XB3Kct6OnRhqIE+EjhK3cxP4LRp6ORAURzKmYhazRYSreixjTX OHXtJdA1/sGOma5GyVfBACBGo2YYO4cq24XKZxhiCXhcMsKKga3g34Nh8q9HEvQu eAcKAsmw+l7o5nTMTHDA1rNhcEXyC2J88Xklu+mNSxrfm+wMkuuET28QQL+yF2Uc Sl3y3qE2wNuzwwN1Mi3cY6ACVMPy18E9xTZfnH6jvdKUgi2djk+tAXU7FfC4XFXi WHLG0PE3c6TybpEpUoZBPUqg7Z3sUxaUOOLgAbR8fXWZ7HDUq7K4ksz0u46rk87q aNQXbv2uB8mA1+0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGLTCCBRWgAwIBAgIOSUEs5ABpEcvCPMeYjPgwDQYJKoZIhvcNAQELBQAwgacx CzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEVMBMGA1UECgwMTmV0TG9j ayBLZnQuMTcwNQYDVQQLDC5UYW7DunPDrXR2w6FueWtpYWTDs2sgKENlcnRpZmlj YXRpb24gU2VydmljZXMpMTUwMwYDVQQDDCxOZXRMb2NrIEFyYW55IChDbGFzcyBH b2xkKSBGxZF0YW7DunPDrXR2w6FueTAeFw0yMDAyMTAxNjQzMTBaFw0yODExMTQx NjQzMTBaMFcxCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEVMBMGA1UE CgwMTkVUTE9DSyBMdGQuMR4wHAYDVQQDDBVORVRMT0NLIFRydXN0IEVWIENBIDMw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDlmVAR2SYwaYcXcU8XBr7Y KABcKYYngUBnBHYNCeQu5Eb65YyEdX2r2Jpb+E/xcWMFvOb5HW24smL3FM+Oc8gp nNXw4S6Ifs25TPEFuaDV4wZC0UZdraCX1XSFmgA2gvT44NgMow8EEiWmF+RPTcAh c2Gj1qgCKWNiiS75lnBwQHTPPX9DYPOWjiu/+/Ln8vX7mIAd1+/Rx2V2HU0TRT/b wnCt7h90CaPjPe2OYIWwh+1wOgu38EK/ea+YTlbWeXSuRFVv4T57iewgC0H2Y2Ro bFAcuXLnGSm6J/XfFphGPW4h3vD9d7CHO/OP6CuK/MmqxcSTHeZz3eR5u1CQsGwz AgMB+eujggKkMIICoDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAf BgNVHSMEGDAWgBTM+meT8La40KXAHvNT/YxT34PXljAdBgNVHQ4EFgQUaQLXT+xW P9AMG+uKHWs5kbjAD1IwggE+BggrBgEFBQcBAQSCATAwggEsMCwGCCsGAQUFBzAB hiBodHRwOi8vb2NzcDEubmV0bG9jay5odS9nb2xkLmNnaTAsBggrBgEFBQcwAYYg aHR0cDovL29jc3AyLm5ldGxvY2suaHUvZ29sZC5jZ2kwLAYIKwYBBQUHMAGGIGh0 dHA6Ly9vY3NwMy5uZXRsb2NrLmh1L2dvbGQuY2dpMDQGCCsGAQUFBzAChihodHRw Oi8vYWlhMS5uZXRsb2NrLmh1L2luZGV4LmNnaT9jYT1nb2xkMDQGCCsGAQUFBzAC hihodHRwOi8vYWlhMi5uZXRsb2NrLmh1L2luZGV4LmNnaT9jYT1nb2xkMDQGCCsG AQUFBzAChihodHRwOi8vYWlhMy5uZXRsb2NrLmh1L2luZGV4LmNnaT9jYT1nb2xk MIGeBgNVHR8EgZYwgZMwL6AtoCuGKWh0dHA6Ly9jcmwxLm5ldGxvY2suaHUvaW5k ZXguY2dpP2NybD1nb2xkMC+gLaArhilodHRwOi8vY3JsMi5uZXRsb2NrLmh1L2lu ZGV4LmNnaT9jcmw9Z29sZDAvoC2gK4YpaHR0cDovL2NybDMubmV0bG9jay5odS9p bmRleC5jZ2k/Y3JsPWdvbGQwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUH AgEWGmh0dHA6Ly93d3cubmV0bG9jay5odS9kb2NzMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAuMMpNc9hJBq1KN5/VrLz P+cUfReJD+wFXsY1HT+FloF3xkaoif5DPsarWg6o0e+RQRqSE66NkVIxUlESsf65 rf7OTNhWnEIE0v15nISu58k2hWQRZW0SP2kvx10q30Fmb3vHNXCehrxmTmslsWQ9 6rZetkT0Ut4FA2JIfUC/4KcEjFQomF4xYD2QI/EKxTsIksCVaCSLDwhj2xo+G9R9 O9glDujZMkhnjFCZ6/4qf5s5klgbt1wVOxXNNxmE7SI5nKhv01npck6ndU65fVxX 9iyMVYA7Ju0KO04GwgrrHLJ2YBjE6CwiVUou/yyMuS5BOkqCkque/QoflubvBWGL eg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGlzCCBH+gAwIBAgIQQAFwOzq6gYzJPK6eDrjUEjANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMjAwMjEyMjEwNzQ5WhcNMzAw MjEyMjEwNzQ5WjA6MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MRcw FQYDVQQDEw5UcnVzdElEIENBIEExMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALurFDtNUgw/fTzPkHWZDcSsSTbdDYEBPmbeosWjT9CSko03fkhuS8Ks QVo5zoCP93ZcILUjXje+wIErPqwOGyuBie+XFGWQDVF0SsP3rfKX/UJ+oqoAetzn R8QTf9eSmzNx0fj8oh10KFFSHrwilvJ55Vp52Wm09RXozoUUSlVIORwAhjk35wjj ja5cZYPptVY4J6NbjajbizP45A9c+qYTWfxvSH2RiNKaR1+QAP21YlnHl9uPFZnn zYUkdeAA2SbZQAFjotrp9N26qwTxwPZw8l8SPK4Fi31D+aw8vI8doRCLYPefjkRe cH5BlKu/OxwY7KRPOgnGnbi5GvwZNlcCAwEAAaOCAocwggKDMBIGA1UdEwEB/wQI MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMIGJBggrBgEFBQcBAQR9MHswMAYIKwYB BQUHMAGGJGh0dHA6Ly9jb21tZXJjaWFsLm9jc3AuaWRlbnRydXN0LmNvbTBHBggr BgEFBQcwAoY7aHR0cDovL3ZhbGlkYXRpb24uaWRlbnRydXN0LmNvbS9yb290cy9j b21tZXJjaWFscm9vdGNhMS5wN2MwHwYDVR0jBBgwFoAU7UQZwNPwBovupHu+Qucm VMiONnYwggEkBgNVHSAEggEbMIIBFzCCARMGBFUdIAAwggEJMEoGCCsGAQUFBwIB Fj5odHRwczovL3NlY3VyZS5pZGVudHJ1c3QuY29tL2NlcnRpZmljYXRlcy9wb2xp Y3kvdHMvaW5kZXguaHRtbDCBugYIKwYBBQUHAgIwga0MgapUaGlzIFRydXN0SUQg Q2VydGlmaWNhdGUgaGFzIGJlZW4gaXNzdWVkIGluIGFjY29yZGFuY2Ugd2l0aCBJ ZGVuVHJ1c3QncyBUcnVzdElEIENlcnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBo dHRwczovL3NlY3VyZS5pZGVudHJ1c3QuY29tL2NlcnRpZmljYXRlcy9wb2xpY3kv dHMvaW5kZXguaHRtbDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vdmFsaWRhdGlv bi5pZGVudHJ1c3QuY29tL2NybC9jb21tZXJjaWFscm9vdGNhMS5jcmwwHQYDVR0O BBYEFC233htZfiqYLs3h1BvjxRASXukUMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr BgEFBQcDBDANBgkqhkiG9w0BAQsFAAOCAgEAf+wSnMoC1+jZeGtN3Ax7e0y3T8Qs xbwxdm5FWAhU0V+O1H3qJhdYATxQ3ntx/yD5S0Zrkz6DbdKo3aX0M5g1jfeY1Fy3 Sz0U6DccmqAebNIToXFeh9PLtxRwAgYn+eYtA0w81Umgb9AGfYdV3rhseBYodVZt 18c9uBgaqlbnbz0S8jCe7uobwakyCied7grN3ckC2U/Q156fpCb/Mu2UgGPkFayP 3crE/Gr7Z/He5O2szQZH520avtHvPEKAZ3pervn6cG3eTS0R8sF3h/qYW81Cwmvm yz0TKiWltpW4b0lqzB0Q8t/3fB74JywgRStrOEqZ7OGAjeMVXG6pRls4KJRwilB9 /b6XLA6NcpmRayfEEeooSJ/BZieaCsAJ53fxugA1xQvW7nW/fud9qYUgFzma63nC EJ/r7T9+ujwvmgpQD7CCAyQ7KLUuc+F9iVBbDSLhIFxqoYihO0rmW6xRvbHXC6a0 pSTe07EQ3NFtm/Z6sA/q4/+TDdAvnisIWvvMnb9Pqs08sTz/dCkYGnoBqMAuHVLG ck5Np+GdzLgB1+ZwGS/1Yf0sg4/2o6K1eOMqmQc0NwoSoV231EsHtsTJsoANmeQ0 cDESZ6fwbHIs2HTZNllyTE5x/sFSzfLCxMBLUEeHky6BZkL6ytgDAUvZFubAZDMy Dbf2W23GdxfngDA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDeTCCAv+gAwIBAgIRAOuOgRlxKfSvZO+BSi9QzukwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDIx ODAwMDAwMFoXDTMzMDUwMTIzNTk1OVowRDELMAkGA1UEBhMCTkwxGTAXBgNVBAoT EEdFQU5UIFZlcmVuaWdpbmcxGjAYBgNVBAMTEUdFQU5UIE9WIEVDQyBDQSA0MFkw EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXYkvGrfrMs2IwdI5+IwpEwPh+igW/BOW etmOwP/ZIXC8fNeC3/ZYPAAMyRpFS0v3/c55FDTE2xbOUZ5zeVZYQqOCAYswggGH MB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBTttKAz ahsIkba9+kGSvZqrq2P0UzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwOAYDVR0gBDEwLzAt BgRVHSAAMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMFAG A1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1 c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgw PwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RF Q0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRy dXN0LmNvbTAKBggqhkjOPQQDAwNoADBlAjAfs9nsM0qaJGVu6DpWVy4qojiOpwV1 h/MWZ5GJxy6CKv3+RMB3STkaFh0+Hifbk24CMQDRf/ujXAQ1b4nFpZGaSIKldygc dCDAxbAd9tlxcN/+J534CJDblzd/40REzGWwS5k= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG5jCCBM6gAwIBAgIQMQJw1DW+mySa+FbQ4eKFSTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MjE4MDAwMDAwWhcNMzMwNTAxMjM1OTU5WjBGMQswCQYDVQQGEwJOTDEZMBcGA1UE ChMQR0VBTlQgVmVyZW5pZ2luZzEcMBoGA1UEAxMTR0VBTlQgUGVyc29uYWwgQ0Eg NDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALNK4iJeJ1vpBFsUBDUy IBSutNIxQMbNUMAeoUTKr55KYX8tkN5imzNqLaRCypYBPP9wED2AaO6e8njkbjzJ wLgPqDBkW9sG3kmi3GW6cF4Hwr5ysZqve/5EJDhV+9OhfTu/4dMnoR4Q41HcjMk9 MzLOADAQ0awBZ/29r0d49AUmIKELNeqEqmnTN6fndL7x/2K0TLToZLxqS7sy/Jvi 0wEFr0CfdjcAsioh7KaD+Jizyb1aRKQzJ6Q20VEHX7UqWc1SkzTkbz6xj0S5ydBB FQh0fNiy+qM/deVpK4HgmPSJrrpQZ+LlbHfWabmwoDPxF71QZVYiqrrAoUrGRJ+4 7iLBiIg8miIYS7Hd2ppvAUt24CugMXUjETjQ+oYh09fNi5n/AvoER8UBvTHLxt+b lL0bvL+2z2YiUWk+2Qtn+dD+JU5Z2y71qV7+cr+4YXjvGzF5bYsi8HiwflTb4Php 3y+k1twKtchdcq2QGc0eDG6Y01nRHUiyr8/PtMAsLHEPNZ2wzsA7fb8mftHiV20Z FmYqknJ8AIOfwdTVA+E62JayOJ+sxadqcmFDorsz/mrPwGZ8+txr4xSuvVjg0dlv 0yuA+1YpBDIYNfL4bkX+IcZ1mTstL4Xw0f4N2iW3bBmnPnYmoYxMM8gflCiTgss7 3nBvG2f7v1PD7BDGYNO4iD4vAgMBAAGjggGLMIIBhzAfBgNVHSMEGDAWgBRTeb9a qitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUaQChxyFY+ODFGyCwCt2nUb8T2eQw DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI KwYBBQUHAwIGCCsGAQUFBwMEMDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUF BwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9o dHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlv bkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRw Oi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQw JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcN AQEMBQADggIBAAoFTnsNjx8TOQD9b+xixsPt7Req4wHMeNw/R5dddEPgQAQAYJZK z5BEv1cjGbH7nbPH3AxrxhN6OVH40p6OLIo9MXSrrfMzGs7/P+FTCjwgNxFEtLQ1 KC9NboA3asJcl7mIs3l8h9iAgEH1zLUvq2s+5n++NQmbzudDsTFDMapY3kX1TwyU CTRzmItqcbsYIyg2MeIXWfRtqPqC5R4bufmpzA5BPINLX340Sp/CNQ9QZqw3Vkfy HWwTo+vO9Gm2L6srNamJT6Lb+TeXZvl8UPL5a72O/pH0GgGHjt6z9QzPARnaRKsh VWviNK6ST4WmZHllu3CJg0BXqx1vWyswawgvNeWt1qxITacYe9mSWTbNR2CftvTU werruDSY2jMaZPoNqbjUpuG/blYwWzzvVerBUhviAahPXJF/9V48ybWPBq6qKOEo kW+s3B4ad5sY96KlovEijaIQDip1HO0SD+rLNYaiBcr9MV2aK+DfbZ8w9BaNCQyF EYwzxIKOVk3bYvzHRk5ihUDascmbk/bkiNl74c/KfuKQmJImaqWoWZR6jBcXcPV0 WUIKz/nILTpFhGojZEQW77by3aezAi9jrEIUBHRG1LwzPbJc2V3SOzYyaJFQatzu KZbN1Q9s9y/2x1QXtKwREY8jNgvx0iIfOK35gKgYJJcyDql4XfuEc2nV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG6jCCBNKgAwIBAgIQN9uaOAbXCsc+ONHf725RKjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MjE4MDAwMDAwWhcNMzMwNTAxMjM1OTU5WjBKMQswCQYDVQQGEwJOTDEZMBcGA1UE ChMQR0VBTlQgVmVyZW5pZ2luZzEgMB4GA1UEAxMXR0VBTlQgZVNjaWVuY2UgU1NM IENBIDQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCUtBhby5HZ4dxN stR0OaxF/QrC0FENJm59Na5LZzPwXqwTdaq1NJUZwMIrHTXavExQpGqzdqwIKNS0 liyLkTT54vTs5VPh5SYRFtVAX9NLkY+fUIu2icOEGfwlPR6VlYp+kiR2Vj4OwYhy aM0tj66uaTCaAj3Rz99dN1s64Z1jw/wjckCLat/MGHL4crKuQErYyPfoK1s39BR/ gXis0E2anvfmuyAZ3YDOsAyGKpPhEj3Dxuiz5+qpqJIePs3Vgylyx/ZIoJEH/jAq v7GbdVTsSfqyMlnyceF0pyGQ6Yzp1DkLw4Dg26zoOSckLYeICtRziSwzrMu3YLYW VB6h1r0Nw/hnuXMYt6WgLYekfxuwapwbntbw5gAJpK63geBp3Hj7bWnrPb8aLjBz eutA2St+Y6YodQ8PjbhUpaWVMGzz+c2YJK/xbxTAjWUPOdd8cNrM7ilaOrvbSaLz e7aPBFWZMpg1kOva5J91qSdOmS45DHyyfT4Xk2X/3HhFRLkKA/cdJaEYE1I/p0P5 A2qFlMdr+QDx7Uar5Zvsbvrm0gn+MER1uq3xugoweC3iegHwQQh4YupAEamo1vPy n04r3WPn86rLjpe0OLFvlM8CQtvTWV6wOXy3HTnIh8gFGxe/0Wu3XYBtPcJXlBMO aV7NDi69LE9ZiYNF+wBZ6iUgVw3ZRQIDAQABo4IBizCCAYcwHwYDVR0jBBgwFoAU U3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFJoriiLWjQzAKqVvZDM/lmBn FR2yMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQW MBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4BgNVHSAEMTAvMC0GBFUdIAAwJTAjBggr BgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwUAYDVR0fBEkwRzBFoEOg QYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmlj YXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYz aHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0Eu Y3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqG SIb3DQEBDAUAA4ICAQAmpZcT3x9evRVo7pAAsdyTx3mmtbOGWIAQFQRiW4po1Jx9 9szSmymPrzDq0s1Lh7EL+sworQnNKEApLYpcFZ/ZeyjWPt+7D/SKGdjhFE9owf71 hNiwWBWzMHZWE/1lYpISw2gbclDk6Mp1GkDQhRVXQL5O6uXeouxNiKpAXZj8QFx7 Sk1kkuXewca4dFRTs9Oadec8ARnR+YzxhTE0p3m2rBkWL3zpNCtl+7zpPJm58eCc 8Oxt7ib/XwoZKE/tKKZ6rcA+kBL6X6xeim+DwVqToJW24yiqVAI2JYQw1741fqm8 lklFlkAoOTJTprMd3jIK2DKYvAXkZiAeY8eD85AVCJgC+DpD/0Oc3OpsP5kljGzF 2rUYGLutL1a9Uxd2YCGkqnAym2f2LsBo5u2+Znk5YzfD5xPSWBrs9K5UtE2G+5B0 iygvf+yl/+hcv4aN3zetNXbfsSArAR0ecdNkNtehXeVaFE7rIZUXFahzHn2cSOLO n4vjBWKRHJc4lvlqhfz1jaPrcxS0BxaJq0VNrX3skPeajbVSsPAjXXVDh9I5qjdG yMvAe5TUyUf752JKBN56Zi5mvz5ufbvULGcV4Frnwl2c2ySICF7KGIB+KGhGbgbf tN6PKXHwC3gvRw9yzFSq6Rdwh7U+3AkmDel0rhdZnMTx2JryjQF/AeBKwkfrUQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG5TCCBM2gAwIBAgIRANpDvROb0li7TdYcrMTz2+AwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDIxODAwMDAwMFoXDTMzMDUwMTIzNTk1OVowRDELMAkGA1UEBhMCTkwxGTAXBgNV BAoTEEdFQU5UIFZlcmVuaWdpbmcxGjAYBgNVBAMTEUdFQU5UIE9WIFJTQSBDQSA0 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApYhi1aEiPsg9ZKRMAw9Q r8Mthsr6R20VSfFeh7TgwtLQi6RSRLOh4or4EMG/1th8lijv7xnBMVZkTysFiPmT PiLOfvz+QwO1NwjvgY+Jrs7fSoVA/TQkXzcxu4Tl3WHi+qJmKLJVu/JOuHud6mOp LWkIbhODSzOxANJ24IGPx9h4OXDyy6/342eE6UPXCtJ8AzeumTG6Dfv5KVx24lCF TGUzHUB+j+g0lSKg/Sf1OzgCajJV9enmZ/84ydh48wPp6vbWf1H0O3Rd3LhpMSVn TqFTLKZSbQeLcx/l9DOKZfBCC9ghWxsgTqW9gQ7v3T3aIfSaVC9rnwVxO0VjmDdP FNbdoxnh0zYwf45nV1QQgpRwZJ93yWedhp4ch1a6Ajwqs+wv4mZzmBSjovtV0mKw d+CQbSToalEUP4QeJq4Udz5WNmNMI4OYP6cgrnlJ50aa0DZPlJqrKQPGL69KQQz1 2WgxvhCuVU70y6ZWAPopBa1ykbsttpLxADZre5cH573lIuLHdjx7NjpYIXRx2+QJ URnX2qx37eZIxYXz8ggM+wXH6RDbU3V2o5DP67hXPHSAbA+p0orjAocpk2osxHKo NSE3LCjNx8WVdxnXvuQ28tKdaK69knfm3bB7xpdfsNNTPH9ElcjscWZxpeZ5Iij8 lyrCG1z0vSWtSBsgSnUyG/sCAwEAAaOCAYswggGHMB8GA1UdIwQYMBaAFFN5v1qq K0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBRvHTVJEGwy+lmgnryK6B+VvnF6DDAO BgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUH AgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0 dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6 Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAl BggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0B AQwFAAOCAgEAUtlC3e0xj/1BMfPhdQhUXeLjb0xp8UE28kzWE5xDzGKbfGgnrT2R lw5gLIx+/cNVrad//+MrpTppMlxq59AsXYZW3xRasrvkjGfNR3vt/1RAl8iI31lG hIg6dfIX5N4esLkrQeN8HiyHKH6khm4966IkVVtnxz5CgUPqEYn4eQ+4eeESrWBh AqXaiv7HRvpsdwLYekAhnrlGpioZ/CJIT2PTTxf+GHM6cuUnNqdUzfvrQgA8kt1/ ASXx2od/M+c8nlJqrGz29lrJveJOSEMX0c/ts02WhsfMhkYa6XujUZLmvR1Eq08r 48/EZ4l+t5L4wt0DV8VaPbsEBF1EOFpz/YS2H6mSwcFaNJbnYqqJHIvm3PLJHkFm EoLXRVrQXdCT+3wgBfgU6heCV5CYBz/YkrdWES7tiiT8sVUDqXmVlTsbiRNiyLs2 bmEWWFUl76jViIJog5fongEqN3jLIGTG/mXrJT1UyymIcobnIGrbwwRVz/mpFQo0 vBYIi1k2ThVh0Dx88BbF9YiP84dd8Fkn5wbE6FxXYJ287qfRTgmhePecPc73Yrzt apdRcsKVGkOpaTIJP/l+lAHRLZxk/dUtyN95G++bOSQqnOCpVPabUGl2E/OEyFrp Ipwgu2L/WJclvd6g+ZA/iWkLSMcpnFb+uX6QBqvD6+RNxul1FaB5iHY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDiDCCAw6gAwIBAgIRAPFVZjGnycu/NlCaWpIPalkwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDIx ODAwMDAwMFoXDTMzMDUwMTIzNTk1OVowUzELMAkGA1UEBhMCTkwxGTAXBgNVBAoT EEdFQU5UIFZlcmVuaWdpbmcxKTAnBgNVBAMTIEdFQU5UIGVTY2llbmNlIFBlcnNv bmFsIEVDQyBDQSA0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3Oad56Xl15SY nK3MmKcZUEu17k4jApQvPwTnGUqFxMbgDvAtxJtWqbKk8qvCOcZ/oCyrHkloS6Nf AiTDTV5bZ6OCAYswggGHMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2Oa MB0GA1UdDgQWBBTt5lFk6mex24xLv7WAJ5g/2CMeZTAOBgNVHQ8BAf8EBAMCAYYw EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH AwQwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2Vj dGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2 BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0 cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNoADBlAjA8KoDpeqid slDXmfwHD7kr0XTY8rOdQBWMzT5uU7nPROEYLK00Dc9w/J4M8CGaLX8CMQDoaX4P os4y0yfmvRAPaFZxyJi1ZHaZh+G0dX7ggOEyMHmT0P57T6TjdfcBr1G/J/M= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDeDCCAv6gAwIBAgIQCtLIkeyu89lwFWPsFKwUJDAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMjE4 MDAwMDAwWhcNMzMwNTAxMjM1OTU5WjBEMQswCQYDVQQGEwJOTDEZMBcGA1UEChMQ R0VBTlQgVmVyZW5pZ2luZzEaMBgGA1UEAxMRR0VBTlQgRVYgRUNDIENBIDQwWTAT BgcqhkjOPQIBBggqhkjOPQMBBwNCAASIz58YxU6CmakIJXWXxv9WntB33X8riZAA 3Q+34HkXxg+3QALt3WNZfL2vLg5PR9+MmsWh74Af3rh5ar4Dr1fJo4IBizCCAYcw HwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFJFVkhfA cvrHAv4gYdMYh1Ib5znjMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/ AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4BgNVHSAEMTAvMC0G BFUdIAAwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwUAYD VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/ BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVD Q0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1 c3QuY29tMAoGCCqGSM49BAMDA2gAMGUCMFjk8QWPWP2ZiBtppqumXYpc5cjTjE9Z hEuCl85m7FFv64DiFpN20kHID/nrkwNNVwIxALa1+3QL5kM8o3VFXtiBOy51mg0Q wA1Inu3wBZYNCJfJZhJMNUtlolJgEElAycJcoA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfjCCAwSgAwIBAgIQdpAhff5d1sLEUCfF3NFaJjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMjE4 MDAwMDAwWhcNMzMwNTAxMjM1OTU5WjBKMQswCQYDVQQGEwJOTDEZMBcGA1UEChMQ R0VBTlQgVmVyZW5pZ2luZzEgMB4GA1UEAxMXR0VBTlQgUGVyc29uYWwgRUNDIENB IDQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQYZ2cR4O5tfdskg2NNo346Noyo enQjWhWQElTQQ+brmMxr5leW1AfpAJ9bsaUadsCJJnA5ycFITYjXfl/XvfPko4IB izCCAYcwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYE FKgtbYEyZI3msk+s/hHyZZmFE6luMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8E CDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDA4BgNVHSAE MTAvMC0GBFUdIAAwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9D UFMwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VT RVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEB BGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJU cnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51 c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2gAMGUCMQCCX6P32oo7RiAIk1DIekZM nFGZwY+xJoZ5HyChGc1Ncuupnh7Ezukr1EnL+MyAhNcCMD6DlSMWE5I++OBvznnX 1npjvntLcKogArAPjLglGGeymFt4U6pdy7/C0/miHCPuDA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDgjCCAwmgAwIBAgIRAKZyxVx1Z7iXm9Gpc3bygYswCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDIx ODAwMDAwMFoXDTMzMDUwMTIzNTk1OVowTjELMAkGA1UEBhMCTkwxGTAXBgNVBAoT EEdFQU5UIFZlcmVuaWdpbmcxJDAiBgNVBAMTG0dFQU5UIGVTY2llbmNlIFNTTCBF Q0MgQ0EgNDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIluIR/57Gi+A/PBU/HJ Du+ib62ojbmgrFplMIet9FpKgUwqGkcPXoLXPsQqLGA7YjUgDDa7DVdchYDP7UPr bCWjggGLMIIBhzAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNV HQ4EFgQU5uJP1y+hutmLqFhNiCUY45Ku4HEwDgYDVR0PAQH/BAQDAgGGMBIGA1Ud EwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgG A1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28u Y29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5j b20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYB BQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20v VVNFUlRydXN0RUNDQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9v Y3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDZwAwZAIwOT7r0xcx8SFLchKn /QsiSWlCYaWoEOsaIK+dNrekDE1IvWGWzgAynhka7g08CiULAjBA518/JC2WTcmC lOsIDSQpVv/vs0CVFDGFdL27Dy9z3uBLs9blu8Du5L6IM6mggG4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG8DCCBNigAwIBAgIRAKoycu7aGxmmN/byVir07vEwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDIxODAwMDAwMFoXDTMzMDUwMTIzNTk1OVowTzELMAkGA1UEBhMCTkwxGTAXBgNV BAoTEEdFQU5UIFZlcmVuaWdpbmcxJTAjBgNVBAMTHEdFQU5UIGVTY2llbmNlIFBl cnNvbmFsIENBIDQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCVokk9 uR1UAJRcNg1NTatsuxEwya7FpTRm5wcbSJqSLeUd5gjI2zHzwjaevHwCjN716blp iyvEVr96aGw2y+FrVo/0yr0+/XoK8WdkB64j3KmOdUttTTXERY1T1vXxvkZhchHl JvD/VVDIt/V/xg2iDpAa2N3SW0SNSyuAGqtVaCTM4eOEgVT1Nyg5VtQJVLujMrvv cW6+1W1rLR2O05FxQtINVnrblTKWotAitEv8yMe9qQr1Fz4sdyVj2cBwEk/zQLok JRCSw981Hoh5kwt4AVMSxjfeSRjx0Wt0C6ioRJ8WAfSWGNDZwnUWZ4nJrW2UWtdJ Z59t2VByBR3e8MlVTVE4pirg3R5lCCIzPhNLQm25Rap/a4m3+e9A+Jnjgfi3XzSB fd+gcMh1xBXK+YOOfbnZW4H8T1Ty9I/HKsUp/isLV8TJsFOLZCyuV14qVfi8jmRU 0wYIK4vQRj2M7VxCyH4MPn6lgnyecIieL0b4gFNWhE2waH2gfigvpQWH6bQuSWIh l0PaRDWFavo1SNTFKdAVQDK7w3Iw3XzOhQnjHgU/idvqd5eaqa2G4VN1vV1pNirC LXJccKK49zDSS1IFMX9iQC4YFxc/BbWRndI3smg05dcYn7Di73B0EzFFO6dyg0WD r2N9G/8fgjv89biSARMNzjtg2XR2cLxdT8PAYwIDAQABo4IBizCCAYcwHwYDVR0j BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFLYvVVqwyWAZ788J WtHxE51sjMkEMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDA4BgNVHSAEMTAvMC0GBFUdIAAw JTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwUAYDVR0fBEkw RzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNl cnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEF BQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRy dXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29t MA0GCSqGSIb3DQEBDAUAA4ICAQB7IGXk1vGM4J73d8UD3f71UqLxom42Icu/IP0V nrIRzbAmz+C++7Bir4mqkKWt89dd9ZlIK8Ez5Y97tDEEd2eICo6dTvy5JOxiYsWK iubpyqmW/K0xjUqutANMxxGXQOJn13RnI9OHSxNXng5OoM66O5Eq08vXdcQbXF3i qPf95g94OJVoyFwlmYiIMuV6cOCVNShbGKvFPpNB4p+7vr2FJ7ZeHEmiZKMXO8ex 3Uq5j1riVT/4tCemFz7dSpaCkHJ0xj5Ayknj14+t/lwF7IcOdP9/15uDp8HkgNh9 xXkFqF3wtLkidVvmmbvDmOQiLJL6Hj6MxwEwI7Cf4ZN/UH0eIra7tEgMP+mkdNtR K3tB4lQNLquWBr25PbzMiK5LfXPGL+odDAb/7mE1ClQtg28gohf+Ms9hQ4y2rZSG sYUgh+U++Yn+HlYKI26tl7qB6lFcQb6Prc1SELAEFob8yMFkZ3UnXXLRUkLeM50K WV9s5wu4Rn6Rzp722wdTQoBeaSxZ5bjmT3QerGV2GaRmuYjLxdYGZ5Co07DI+qEJ Tj4mbpHx/OiqD7tR9i3rHpPyTjpD6MhJ3U4EjZfd6UMWGMz3Zcw0tvJe1cLpNRX8 yjTdSxF1/H7ni7/IHkK4trIBuc58YPbZXAfYTcPugPwQE6N7RcfQHA4McFX91SZa DskXUg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG5DCCBMygAwIBAgIQBHuLbQmxZWdCqKfBhpyfqjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MjE4MDAwMDAwWhcNMzMwNTAxMjM1OTU5WjBEMQswCQYDVQQGEwJOTDEZMBcGA1UE ChMQR0VBTlQgVmVyZW5pZ2luZzEaMBgGA1UEAxMRR0VBTlQgRVYgUlNBIENBIDQw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCfQj5WwXIGcoT7zvITdpnR 8P7auxwyAmBFjTtOksiLjlXP62wum102dz70U1cvdWnrK3e32SyVHIvVVJRIeUIl q9cRj38gd/4t/e2etn+tpHUtL9wK5AIXs9tpIjEnw4UlcpLsVpLEiyc1Sc2XtwbC or7MMrOB4qVucNPF+GQHWi/Vnss5zLVzXlfuJ7A5Efx1lSeWvMkNDdHxxuv62yYs j+FEiY1IXjV1WyWxTlseJcazDUciw7LMK30Tp9smdONuPX6rwEVSTUiC3QzbwNaP 4C1Um2yAEbdve4Ru/qURloHud5LkBaJTm2+MDJz+yHZf4g7lvKpbcKrf59Jg8h02 sRipT6GA3cjpgB5RU5bnXFkn4kpT2+/P25HQFeg0lyKw8dFm864sn8a37GrWviOC TOCWtrrSxtvLvCy9axxgc9btrA596rMKrw2tpp42KPPRXHjaVqfLf6Wj2SCynFWx +insGBIikpbxxOdrt4qGEDgVdSOCN9f3b6CgyTs7PD5KlUiei05Cg7sbX/Zi9DE0 8782f4SGsZtyn4G/rMIqxyZ8SfyQZV17c+zNkttdy93iQv+IlNJGalCM56Mmkv5n gRtWJXzk0stw30tVWdRSGlRVxxScfcwEF1GcfVjuyosTSnEju61Qi9N5WvhqitIX J/wLzkppJc77xbQX+5tinwIDAQABo4IBizCCAYcwHwYDVR0jBBgwFoAUU3m/Wqor Ss9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFLYgDq6jy+lVAwYTZtSsvieQVGDzMA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjA4BgNVHSAEMTAvMC0GBFUdIAAwJTAjBggrBgEFBQcC ARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwUAYDVR0fBEkwRzBFoEOgQYY/aHR0 cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25B dXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDov L2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUG CCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEB DAUAA4ICAQAmUg8HhUdEzgbJQrk3G7JLuFyKJHWQ74FRHMFCorKd+h9TXoxSBOAo PZU5iIKv/mPXyhT+sh75NvlXr/N+d52Tx2HIY3IYWx82I0uaa0/tPKImL6ByJuqu mcvb2c4MqCfTGAi8kILbQt3WHK/idEiG2APMlq1YNoR3aBh7tc1rloxmQ5joEmrj wSoNA60AV2w9zEmi4KTYVZzsTjRgK8vh8WGQ4un3ZQhRYIVTdiI1J63kohIcpFTe fJyz9ip3C1Rjr5kink4bGlcxpRb1WjEs3OWhzCJSo7/ZZIIZu0pRsDKltkpNmoUQ 5/4aIAEG9a9azLTKxTktcKOEJCOzdVIhNC/b6jrCFD7vR9v/dTI8zX9Ol1cK2nms k/uD5CZcvMZ6Rh/D7AS7B8dWODbN3nQPzucgdION4KHvJJe1G2SxDe+5MQO4CbwI WI5U+OnxKTP3vlJv2CxvP/+4Drf3hkp7YvVSZnmc9KlOeDvdC3Om9jNSw3njrEde foNq1eeeV89hCWKKdn05kpyitOiy7pTJJuDgVs64YGaSdQZG0E4m1bMSo13cQxYg J6EY3nagUJyiLzdMNuhbKlj2oXxjGLgUXYJJgSnnjqK7ldTbJDXK/qVX0gQSOr1b 72T77sRtDcLsmkh7hYi6a+QwKARgmMLZjDirRS6ovWtH60yG2rkxBw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3DCCBMSgAwIBAgIRALsCK/mrS/IL9O0gFtqEn74wDQYJKoZIhvcNAQELBQAw fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0yMDAyMjEwOTE1NTBa Fw0yNTAyMjEwOTE1NTBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVz dDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsG xUypK8FnFyIdK+35KYmToni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8j rg4aA3++1NDtLnurRiNb/yzmVHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJU KlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3H LYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa 8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg 7Mc/R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViS ukqSKwxW/YDrCPBeKW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQ F2smuvt6L78RHBgOLXMDj6DlNaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORI skfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrv jUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUC AwEAAaOCAZQwggGQMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFIHEjMz1 5DD/pQwIX4wVZyF0Ad/fMB8GA1UdIwQYMBaAFAh2zcsH/yT2xc3tu5C84oQ3RnX3 MA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw YgYDVR0fBFswWTAroCmgJ4YlaHR0cDovL2NlcnR1bS5jcmwuc2hlY2EuY29tL2N0 bmNhLmNybDAqoCigJoYkaHR0cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwvY3RuY2Eu Y3JsMGsGCCsGAQUFBwEBBF8wXTAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9j c3AtY2VydHVtLmNvbTAxBggrBgEFBQcwAoYlaHR0cDovL3JlcG9zaXRvcnkuY2Vy dHVtLnBsL2N0bmNhLmNlcjA6BgNVHSAEMzAxMC8GBFUdIAAwJzAlBggrBgEFBQcC ARYZaHR0cHM6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEA fX+K2i5wcz2rPgZCHNYphv6XnpINfGC1bscZffzmBwq3nF5BZGwVbJQWTunvsC/E 2HSZpjYBjqo1PWUYa0aHu1RVtRBimhLGq9ZtTc0sUIROGp+l4qnmVUVjudEdfQyT r+K9jLHr0DkAJBL9oVm4vZrA+W8/OF9UqeW/eiayX8/oooxFCWmlhj4fgeQKL//y wp2HRZkKSPWHLv1CChLC2me3yqySYIWiFZQzsO/eYO/xDGQOSyOh3sIXCoqHmsFk aMn5NVe4A+4r41A8lXd3dMlbf+vAhBd6YE7fcbExyz2nKxkFNtlnt1W8rLz6GK+h 4uDPocrh1HrVpMZVPb4iSg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFLDCCBBSgAwIBAgIQB5JfJHDgvxS7XDqvLrTBaTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDIyMTEyMzAxMVoXDTMxMTEwOTIzNTk1OVowTDEL MAkGA1UEBhMCVVMxGjAYBgNVBAoTEUNyb3dkU3RyaWtlLCBJbmMuMSEwHwYDVQQD ExhDcm93ZFN0cmlrZSBHbG9iYWwgRVYgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDyY6CgLu4Z2dZJ6UFO0pIYoaIR2rBJ5IZWvpA60zGZqA12xDLs Sj4qC2QrvOOlCCmrek7dFdSan6CisCOVoxMRmULbaT/uW6qG0sqO1Z3zoW/7+yIw cOgqEmM5MRiPYw9rF4TZvsCVN+CA7yTxnpVahB79ZEq3mdHnRNpv2Q/oDVR8bcgc FFPIltFannIxt6G6ZKbuPUe4xD1/RPzFi5cTIC3/oIB2rNQPNU15wUQXTO5KMsdv NiIjWICBlSQeCbtYzOKC1M5cRR11TgtqUFxLkTL56fUXPd2ZwAJyrge/YCnuzkyO sgmfGdGId2pCR4Cxbh6FhjKvYk5qagejGNuVAgMBAAGjggHoMIIB5DAdBgNVHQ4E FgQU+jfnyb6nUW83iHdpLrOzArRnrLEwHwYDVR0jBBgwFoAUsT7DaQP4v0cB1Jgm GggC72NkK8MwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr BgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMH8GCCsGAQUFBwEBBHMwcTAkBggr BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEkGCCsGAQUFBzAChj1o dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNl RVZSb290Q0EuY3J0MIGPBgNVHR8EgYcwgYQwQKA+oDyGOmh0dHA6Ly9jcmwzLmRp Z2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwQKA+ oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFu Y2VFVlJvb3RDQS5jcmwwTAYDVR0gBEUwQzA4BgpghkgBhv1sAAIEMCowKAYIKwYB BQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwDQYJ KoZIhvcNAQELBQADggEBAI50mJcLH2XeRZ3FAyer1ANpP0EcJFvCBgdTPwR7HU5k RVc+Ra5eLUGhi+xE05Yoa+xB8M+JBP0YJNbpGhh3ARnypL23OkDyURFh3c7u4U+D m9n7oUcPCr1ktai5lKNcbt+ohL2sPZ7rBlq5P3l6smut44Y3Ds0izRXjIm7A48j0 QZmHWDvuRfqE8ursaoo/Q4IzZ0F0JSeo100yi+h+4ojq7sRTW+eAHYq2ce6JmN6C zT8XMb15uqYPWmo3uaWCR4TUYrApTCPlXIoUJlPE+DDjgHSo5yf2Kur2CEkqujtJ WOwOa+tjsJq/tn272HNWX4pBEuFjvXIjxqJ6JAKbmRk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5TCCA82gAwIBAgIQD38DVGa3gW6iDl6C+WqgGzANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0yMDAyMjExMjMwNDFaFw0zMDAyMjExMjMwNDFaMFoxCzAJBgNVBAYTAk5M MRwwGgYDVQQKExNUcnVzdCBQcm92aWRlciBCLlYuMS0wKwYDVQQDEyRUcnVzdCBQ cm92aWRlciBCLlYuIFRMUyBSU0EgRVYgQ0EgRzIwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDXpD3oKXtheObTAQUn6vsu06w9kFI82Yhp8rQ9jMi/ca3y 732TP1IB8+O/33QrnSTI8TZisZhU0uuUgtp7P9fMtWHggpincRVojrsFoBLiFYJJ HoaUi9GIJXp/5tc/Be41RMyjFHdQh3kRybrgE07lbKEI9r3aQzHKQ8JeR/UCWJJ+ Y8bm3S6BdxkXNOvUG1y9CrNO0z4j4Hj5NyTPfP4Y1GrH07Mr4v5xDIXKlkUmKArj Xg/dF1AlN2/xCFBXWu4beAJdijc+oayBqBEPsEWXqvIFdXTZF8To4ti4JdYzBanv 62SCBchQTmNoMfMBj3iIxkQimu2fEAwYYZKGfguvAgMBAAGjggGeMIIBmjAdBgNV HQ4EFgQUUlMS8cr0dJRxavWQz65Bnt5E8TEwHwYDVR0jBBgwFoAUTiJUIBiV5uNu 5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAk BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIw N6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJv b3RHMi5jcmwwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy dEdsb2JhbFJvb3RHMi5jcmwwYgYDVR0gBFswWTA3BglghkgBhv1sAgEwKjAoBggr BgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1s AQEwCAYGZ4EMAQICMAcGBWeBDAEBMA0GCSqGSIb3DQEBCwUAA4IBAQCZ02A93DwB TWrsqBYbnAViXVBFVPJLj+KShLHiucI5zWbLJfWJNlKj9b++aOmIM3aKKbIPvMrI sJRBWoN/epPWL+Axpp5Ka7GK70HzOQfz+g82TXNAuH86Mhi01LqgHv+uMGHEZn1H YUkcxEvjSiCsUgzVKMrDaScytDGUip9jIRcjV7u1wz9+2zhX0WuEuG5bgTUyFICX DzkXoJCD5xpp8GtmE44KXugRjdzIaiFE8Afr/+4+EGPcK5ccT0o2qAJJ5molgNsB Q4r29hdh5XxuF3T3p0tnxD1BVcb8nf5TaqRCh5P2wSxWa+xun09bPQXh5MBiiX8m /KtGtJyc6oBm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG9jCCBN6gAwIBAgIQcosJSKjKkO5firQBCPribjANBgkqhkiG9w0BAQsFADCB pjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVu aWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRo b3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJ bnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMjAwMjI3MTIwOTU2WhcNMzUwMjIz MTIwOTU2WjB8MQswCQYDVQQGEwJHUjEPMA0GA1UEBwwGQXRoZW5zMTcwNQYDVQQK DC5IZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENB MSMwIQYDVQQDDBpIQVJJQ0EgRVYgVExTIFJTQSBTdWJDQSBSMTCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAJByih+OKxQJ9CuSTiqX4O9ztuaBH/lqhYNU LXfLIBCA6NzHXNFEas3DJ08tdc/6/XVXO0Jhu23or0MarLHfUOqn8k2tnhG9zlSy tt8dJgGPyZ52bQgXHem2JfDt7pDGhyTkjh/17qIOO/bnAzPSzP5Ynfd6FhSnBQF6 4sY90uLBKMRfOBu1Sfpmp9BfMg+R+bq3z+fxFjuJI/G2/Q3nqFiL3TptPyxhpPJQ Q6+lTjLYjCXHXedZWBcawqsiTJf6TwlV3HR1DmLSyVn5sD/WfNQr/Vav/9uKQnUU BBYd0NJ0W1WEolD6+ICGTWZ56ddcLWe1BXZfsz5CfvrR72MDCSObyG/1OB1TWi/M 8NEcPCHjcqwrFY1ZAQ9fM9rvK6VjkI6b0m/HUlIM8BvjVlLsrqs6ArESl3t2sYS8 iXMGGYQCKWBV3wLO/1fjJm0sxkZ1lANT4DIOXmkb3ZRDSl01zgDcijopSWyruweI Bi/n9iNF1reum5kKnerXxe6aJAOHea7a4UVlQ/nIo23IO2x4Vr2Qp4Jox2RIjRM3 klc/nMe79qkbxIYiXeCKqrke9KcFHOewEwAiv5wQphImM7JOiU50hV73vJqu7xlw u4/oXgCeKWABJj8dXBILBbK90OIQsDTkk9hwHWAr4m14Vfzg2LXmpEiX8OJ7Naed HqTv5rTxAgMBAAGjggFHMIIBQzASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQY MBaAFHEVZ8jIyb11XXLQOBhqnfNxJFQLMG8GCCsGAQUFBwEBBGMwYTA8BggrBgEF BQcwAoYwaHR0cDovL3JlcG8uaGFyaWNhLmdyL2NlcnRzL0hhcmljYVJvb3RDQTIw MTUuY3J0MCEGCCsGAQUFBzABhhVodHRwOi8vb2NzcC5oYXJpY2EuZ3IwEQYDVR0g BAowCDAGBgRVHSAAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATA6BgNV HR8EMzAxMC+gLaArhilodHRwOi8vY3JsLmhhcmljYS5nci9IYXJpY2FSb290Q0Ey MDE1LmNybDAdBgNVHQ4EFgQUDGqt6XtOhSb1+WZdFUymYtQ6Fc0wDgYDVR0PAQH/ BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQB0XFon6y9ebx/ZW+CQkwRiVN0a+FF7 gCjnQ5RkAqF3ZVasBt+OL0kC6AaLWKtqIdV59mE2Hn4eimgIDmtFRzu0YnfF5dFg 1rK3n/VsSffVKq6Qme6pnruNBm/mFL2jc08ZN9I46DiP7LNT+Q7eHhcdwFvOlZbj 4blcQq1i5ljgE83QejG13X1jnbsVV9JTTtbEwnkkH71aFO7ysUDtU0j/yLtf0v4D GZ2Vyi00k8mBYvg9qkbUIxv6IO++pfMj4jKEKWVdYxw09EzuWTd0YXbPX+X/kNDq ELLLJB8B/4E5aX7OHg6tuHPh+HE0BBaPtJWHOBvMUXQfWAgrPNVXcrH54dpgjwgA GLP5oWtsRJt3Wkt0lqAgpagSB7EhDtSXbbr6K7SUAtfTSmXcR6GotjYHnCfUcjfO YuJrOacZGq4d7g4QJHBjkzuvOm2ndxPkZQubN3FOhNi04U7obZzRtgG0XIfCBsvG wU/JPON9awKDVg9CUlJWTIhqBrcMATeB2hSeaMMaA4odWJCqCKU7pY/AJOyzeexL MhOQOutEf/iB4XVvTJ/2X722G/Aa3yhHAGfYcyvAtvtunaZHnbzXFW+2p3SDVsQ/ Nyi8XVPByuphAx5okMM/IAlm2eUsv8G8DWDAytOoF/LaTdU1UyhprpFNf06nlvLH n8Edlh2T11YDUg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHPDCCBSSgAwIBAgIQIXB43OywqNsKFVzMlnhg7DANBgkqhkiG9w0BAQsFADCB pjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVu aWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRo b3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJ bnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMjAwMjI3MTIxOTE3WhcNMzUwMjIz MTIxOTE3WjCBwTELMAkGA1UEBhMCR1IxDzANBgNVBAcMBkF0aGVuczErMCkGA1UE CgwiR3JlZWsgVW5pdmVyc2l0aWVzIE5ldHdvcmsgKEdVbmV0KTEYMBYGA1UEYQwP VkFUR1ItMDk5MDI4MjIwMTcwNQYDVQQLDC5IZWxsZW5pYyBBY2FkZW1pYyBhbmQg UmVzZWFyY2ggSW5zdGl0dXRpb25zIENBMSEwHwYDVQQDDBhIQVJJQ0EgUVdBQyBS U0EgU3ViQ0EgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCWcf8M w2GfnFBZsYU0tB1nPreeMRWcvryKcn8bQ5BE37yem9z7Yp6NMXMBH99ZJM2zZErJ 0EGjKLXiWwEt8CjmmtCATowryoyrsSbS8IukoNXYOol+IZNZQPpeejJwpu4iyCa/ 0Y/gHYHjhU2mdb7gr3lr6Y7Et2LkJhmAL/Q9VlBQ6k93MqkyrvRU2+jXvOA4htR+ 6pdnyjcvuYueFF937zADdydkqNeq/PWJtNwNLriq2nTw+YUcqSJWxLwiHASi7kWq wz3GmpOyEcnf9A+U1t73br+0TVtJJy5Bp78CUafs/cBq8r+AxkCBk4ApKQdDmQ5u LaeWXY7G2BkRIFDhmjaDwvK+biReQSQfQAGB6AX7cao6pTmS+MtpPIlLaA35Vbkl CE0GzbdQP9CXJnQn0goq1KIsmQRG8G+3mFzijSUpg43xd2FMKDm0Ff1pOsSNmOij v3zigLeYi0cWuL05DUu1NFfxY/OipZhn1w8UdBzFn6M7H25BbZXhzkIQSA1UslHr 93W9eBECeIMEp8hgcGVLrpQHd8WVgEzyWCDfIBbY846o3aLvDQuLujbrMTEDIkc4 CasGo76Ty9ZngrsfYo+jH70VPeabnbBiQ0YSyK02e33paDFkO8QkJePXC9T8h85Y bZC9j67QnCAPc5bt3+jxTUVousDItDRvBBA+4wIDAQABo4IBRzCCAUMwEgYDVR0T AQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRxFWfIyMm9dV1y0DgYap3zcSRUCzBv BggrBgEFBQcBAQRjMGEwPAYIKwYBBQUHMAKGMGh0dHA6Ly9yZXBvLmhhcmljYS5n ci9jZXJ0cy9IYXJpY2FSb290Q0EyMDE1LmNydDAhBggrBgEFBQcwAYYVaHR0cDov L29jc3AuaGFyaWNhLmdyMBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAUBggr BgEFBQcDAgYIKwYBBQUHAwEwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5o YXJpY2EuZ3IvSGFyaWNhUm9vdENBMjAxNS5jcmwwHQYDVR0OBBYEFEgyx6h+Ykqe BQDezpf6Uxvgo0z8MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEA hcFWjGkd0/UjpintV+sgJZmZ8KN9LP2PTTzfO2YnWL0gjECuf+V7C/MewyYo7pYF dvpN51CCk5K9R+xCm3L1l7mB99SE/OT/zRW99tBIXHJEwXQkdqVt+8hq44zNTJ8Y p2ROZsb1tVhBJ9+grbf5naeqhypDicDmh0Kium3Q8Nk2tx3QLEYfsqgu3t3O+jO9 g8LZvPNMScrQoc6Q4nnRZwElGaQL4B/6iNGj9UO4M+1RNZvNAytiYHx48TGU1Hrz LhzjIYzMhGzZK2HhX3AohGW2WCrvhkv3JCRghanRHPzeja5xw8jDDdxw4Q5zbxRQ CyBu9IwE9NkBbOwQShEnrFXiQkUKTdxlyKCjIZQKl0p7kRuimIA/5fQ1V6aFq/KQ XBS5LicU5Dx7anSHm+ZEmUqYgK2H5EY+vgpnpGSVPkiN1LKYnuZk3CDxElfDvt1c AufCOjMo/gfBk2gYFA5rTYF9POCeoBk09P6QZP/XuJxLM+0zeSWYRuFLLe+Of+zu EJwEKSVzHxmykV9uAAluT6Ti5PeL1LBBu2vzVtz4BOHHreZBfPcbGxIy5fcizRWt 6jrraAeVMeCc65y4VNbfeqh2QEr4ICmqMViZjeLkVZ0nmeHR0La47FF8GAlYm2h1 XQCaeW+pD0kKjLOx1+steu72g1x7Jo4h6ww8ry6EMis= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDsDCCAzegAwIBAgIQLeNMWLAomwTlgs/tqNK8ijAKBggqhkjOPQQDAzCBqjEL MAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3Jp dHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0 aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTIwMDIyNzEyMjMyNVoXDTM1MDIy MzEyMjMyNVowfDELMAkGA1UEBhMCR1IxDzANBgNVBAcMBkF0aGVuczE3MDUGA1UE CgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD QTEjMCEGA1UEAwwaSEFSSUNBIEVWIFRMUyBFQ0MgU3ViQ0EgUjEwdjAQBgcqhkjO PQIBBgUrgQQAIgNiAAQlVxVllvJS5BEjt2fXKNi8OrgYJX44J1w+6bpRDyCmPeif QBFSorxK/J9Kfkw+tnkHS6+9nnr8mcOOuW0iEbWmasFTO+nI34QBG9rGAahm9d3l vwRZf9Ah9v0BBhycgHOjggFNMIIBSTASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1Ud IwQYMBaAFLQiC4KZJAEOnLvkDv2/+5cgk5kqMHIGCCsGAQUFBwEBBGYwZDA/Bggr BgEFBQcwAoYzaHR0cDovL3JlcG8uaGFyaWNhLmdyL2NlcnRzL0hhcmljYUVDQ1Jv b3RDQTIwMTUuY3J0MCEGCCsGAQUFBzABhhVodHRwOi8vb2NzcC5oYXJpY2EuZ3Iw EQYDVR0gBAowCDAGBgRVHSAAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD ATA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLmhhcmljYS5nci9IYXJpY2FF Q0NSb290Q0EyMDE1LmNybDAdBgNVHQ4EFgQUwX1XA/N7RYLruyLDCpwXxqka0lYw DgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMByJDtYdR9ugu++vNzId LGstg42xyoRAV9cN7WqwZXqYsfeXVmq4Tl/HU3lWIqDOLgIwHOv8z3jhWTi+/Wxq xBOU9d6DyxvbdByGfMaXgLSk0RdvhHj8RdMUQkaHO7vEknwG -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9zCCA32gAwIBAgIQAW2KnjaPE8IetCn0slsJVTAKBggqhkjOPQQDAzCBqjEL MAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3Jp dHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0 aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTIwMDIyNzEyMjc1OVoXDTM1MDIy MzEyMjc1OVowgcExCzAJBgNVBAYTAkdSMQ8wDQYDVQQHDAZBdGhlbnMxKzApBgNV BAoMIkdyZWVrIFVuaXZlcnNpdGllcyBOZXR3b3JrIChHVW5ldCkxGDAWBgNVBGEM D1ZBVEdSLTA5OTAyODIyMDE3MDUGA1UECwwuSGVsbGVuaWMgQWNhZGVtaWMgYW5k IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDQTEhMB8GA1UEAwwYSEFSSUNBIFFXQUMg RUNDIFN1YkNBIFIxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEmkQwIgXUIt7xz+Nd WVR6jSFpYqh2pXkJ+JBWPbB+JwowXBcRRdJBCe1gzRWVC72ELpiB2B5Op1NJQBKI 97gHXks4DT3OtnvKRkXDwIh3MRxDvKu25tLkPziJ211Manqzo4IBTTCCAUkwEgYD VR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBS0IguCmSQBDpy75A79v/uXIJOZ KjByBggrBgEFBQcBAQRmMGQwPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBvLmhhcmlj YS5nci9jZXJ0cy9IYXJpY2FFQ0NSb290Q0EyMDE1LmNydDAhBggrBgEFBQcwAYYV aHR0cDovL29jc3AuaGFyaWNhLmdyMBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUE FjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov L2NybC5oYXJpY2EuZ3IvSGFyaWNhRUNDUm9vdENBMjAxNS5jcmwwHQYDVR0OBBYE FLMy4iGg4FMbZtzQKnbMYznZVrwbMA4GA1UdDwEB/wQEAwIBhjAKBggqhkjOPQQD AwNoADBlAjBZ3AY2Aph/WnuR6qh/qpoYJaIatIVhukWyj+KRNxS3/9hYIcjG5ia4 SbkZt9n0yp8CMQCkBFol/kAkxfYEM3hxWRPRTTeHuzVPGYz7C0uj0Os7dLAX33tj R0Ppetn49er+5dg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFTCCA/2gAwIBAgIQAvfh+YK60Amv9H3JV0Gy9jANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMDQxMjA0MDdaFw0zMDAzMDQxMjA0MDdaMEoxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJDAiBgNVBAMTG0RpZ2lDZXJ0IEJhc2lj IFJTQSBDTiBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL49 9vplPYX4qjNjUI5QT6Ugcc8RjkWJFdcC2hMwvPbNQ6RLbjmvEBGHinnDlpBwb8FZ kBGWVv+Djnfe9825hBwEH2iaI0D6QpjEd6Rb5EhHVGjIS4IcumpKkd3Q9tQaWPce WB8TyC4H5XXPFRTR42t2K3qaZbdGPRp4PG3rsJLXgCG8M1cDVmi7cD9wMmji4kiy 0iL5/8VWajm09SHrHC0GFk5wwiGO7njyJqTU3afYaf5oXh1eBa1iK0FeHab7Cujx E1afj/69v82GCigrUHyxNqnmypxpGz3vQ77HCY/jKvbYJKskqScBF/RGDE+SKuxz w/+N2E42Iy//QT8bjLMCAwEAAaOCAd4wggHaMB0GA1UdDgQWBBQGvaabYHlQMb7V qQJKoNCVU4svNDAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNV HQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1Ud EwEB/wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRw Oi8vb2NzcC5kaWdpY2VydC5jbjBABgNVHR8EOTA3MDWgM6Axhi9odHRwOi8vY3Js LmRpZ2ljZXJ0LmNuL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDCB3QYDVR0gBIHV MIHSMIHFBglghkgBhv1sAQEwgbcwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRp Z2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFueSB1c2Ugb2YgdGhpcyBD ZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNlIG9mIHRoZSBSZWx5aW5n IFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBzOi8vd3d3LmRpZ2ljZXJ0 LmNvbS9ycGEtdWEwCAYGZ4EMAQICMA0GCSqGSIb3DQEBCwUAA4IBAQANZCJXBl6U B2ISUsgfnEc7dgLQM5X8vAOq1xlO5p2d70I1TCdnGM/+RAsrlHvQH5hyHq+7yqJ4 YsnpvM8GHn+2WIXVgFzeUf9o0gcIN1h5SWDooMXGjdS42MUosuAsTH2reeBuNL4U MDJoTw5mIwTRG2Qi3z74VVTJvXRPJYJL+SrY9HdRH382YEAXK5go4aRMaqvXY/Ob TfGIL0tKLy1Mg5oaWa1SlNTgmar+gEsSGLuB8LY1yR7vIpLMCbJEF83TnCcqw8hA NRJiGhVFyRB75UDuSHQi5rveZupfzfAf6OayAEk5NjemjOuD5AgeXvnyl83rPOJ3 wAx1cXMDxcLU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDzzCCAregAwIBAgIQA9AT517bpcP1M+1TBmlVUDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMDQxMjA0MjhaFw0zMDAzMDQxMjA0MjhaMEoxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJDAiBgNVBAMTG0RpZ2lDZXJ0IEJhc2lj IEVDQyBDTiBDQSBHMjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGObQczdhMoF VZP616qU3e+S3NkF/VYBFzCpYy+QfduSRn1Sfx8Sz7cWEWpzF74mHOe5Sg4GHfr0 abz0ej5OEcSjggFjMIIBXzAdBgNVHQ4EFgQUNWxfJbq68Z65g8HIOERSDqlJv9Ew HwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGG MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/ AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZGln aWNlcnQuY24wQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL2NybC5kaWdpY2VydC5j bi9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwYwYDVR0gBFwwWjA3BglghkgBhv1s AQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAL BglghkgBhv1sAQIwCAYGZ4EMAQIBMAgGBmeBDAECAjANBgkqhkiG9w0BAQsFAAOC AQEAbDZlZ2oSJua2h7IJe9rbETBI7oZAAWclb/slcyht63nSbHPmrz+8EFamKKzL YzfGxrzEXkskisAKI+FLpUwHfqzkMY7lncw4eW77Hlw4XHqRa3ko66RrFEkx46mA Rs0B/FazL6JELL6/zVWAfDV/qjjemvuLbIUv9zSrxGdV3ypww9mjQWWzP9J3mh2M rQ5PRzXCDQQGK4RCxyKcWkVua/D+AbBZUlMXmPkPR19ArKp071F5/hSyLo/sAToP yL7TOMEBh6S186z7xWd88tTupnwio2JdM9Vu37lZ4cNKrQLfTOkE1fUV9u5Mg+uX sLcOYNmrGtWISXBAQXFngIV+ng== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEmTCCA4GgAwIBAgIQA+t8nxUtCnWuoXPYH+IVdzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMwNDEyMDQzMloXDTMwMDMwNDEyMDQzMlowTTEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEnMCUGA1UEAxMeRGln aUNlcnQgQmFzaWMgRVYgUlNBIENOIENBIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAvS/qtI85q+CcUfzwTqOEVrGqPmwaCUu9qe9Lx2vlwoM4pkE+ modVmAwJsB79UZy5W/rOLy7BKukhaTZSgOrSAQPEA539iMvl6z3eEeh+Gpkg3iZ1 9lDp2b9FrH7DnaRgg/w1LDhcQUP5kLQkX25ivBMQFzcmjz1dKVRTypNu+TRi2zNZ ZXGJhuYPiStKAnvDElZvRAPk51etVJ7twoJdqQd5msKH2DR3QCnNkfhKjWdZorDg z6UeFp8HMbA2sATFM+u6nMnJ6rWeMeWpg7qonCZctuRBTnlf3qwnTV4Ds2D4Dw5E k1GcJsQnMUL6Zz83MlfTRaRy78CUriKv1t1eJQIDAQABo4IBVDCCAVAwHQYDVR0O BBYEFDGOZrFLmTYr0fUAGptJZTM12oAFMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY JhoIAu9jZCvDMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAzBggrBgEFBQcBAQQnMCUwIwYI KwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNuMEkGA1UdHwRCMEAwPqA8 oDqGOGh0dHA6Ly9jcmwuZGlnaWNlcnQuY24vRGlnaUNlcnRIaWdoQXNzdXJhbmNl RVZSb290Q0EuY3JsMEsGA1UdIAREMEIwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUH AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwDQYJKoZI hvcNAQELBQADggEBADjCvP2PaS45zeAE7RArKp6CdAHxp+Ox1hz3qXzi+7pPUTec /755leBD2JeUQD1AS54sxLdxjgscM2lEJcd6iCFk2yhg5H0mn0px+AbX/1Jw13fS /dnMJ1LYATOr39+4DjQ3A8SPiM2j4HW/jvl4+dIci1JFn8ougp0PNxm37fqDc075 0FmZsTUc4FLv8huq9leEjct5L7xd6dO/d2iOmfqoRYPJUOv0VM0XJouD9mzPuzu5 kvi0HNoY4nGs2OMgUoBE/dxMu1QZ6dCojf/EFbpxYL1wGqgf/rsy/Ps4Iah2q2HJ 4jrkgratZWepUyAmyhyGjKlpc5udEwSfwOoLnB8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDzjCCAragAwIBAgIQAk4VX0UF7zVGGRpydmwtRzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMwNDEyMDQzNloXDTMwMDMwNDEyMDQzNlowTTEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEnMCUGA1UEAxMeRGln aUNlcnQgQmFzaWMgRVYgRUNDIENOIENBIEcyMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAE1Gg3W5g+aSnGZYWYLxmKzeBL6dyM8wbMflIYxWT7gCewMMKU9KFEr7LI m3i8SsBAMCPvEfxUl318XZrpTlJ+BaOCAVQwggFQMB0GA1UdDgQWBBRs6jTu+TU+ 2tiO3pZn3SZ7hLNWfzAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAO BgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIG A1UdEwEB/wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdo dHRwOi8vb2NzcC5kaWdpY2VydC5jbjBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8v Y3JsLmRpZ2ljZXJ0LmNuL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNy bDBLBgNVHSAERDBCMDcGCWCGSAGG/WwCATAqMCgGCCsGAQUFBwIBFhxodHRwczov L3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMA0GCSqGSIb3DQEBCwUAA4IB AQAEkeBuba2LijNZNpyARoyCou5mchmhuu4GGPANkDnqAl3gH3fat8W7fW8rPMHg kU8dYXrpw2xJt7nKmd1/R67+zsCy/Bevkaf1MT+cNcE8xBebgauj+YQYIEjKOj1V 9rQN0l01BFmv4Ov6zflw0aQ0XBHHpFY9gFuloz9P/OKLrI0pDo/A9vIdFom+2ekK lsIEk99KCpfs04kvFNwn0AL8CFjAUq+GXPVJozGjOaDSKYzHIZVQAtV284t6La3L GqBY6W1jWdFybLhUq+7Z0xqBXIruuyrnpQBzx3qYVYtRLt38zLGnU6wQLo1vG7Ca IF1Vyoqbmgp1UVy3h1lqiA3B -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFDzCCA/egAwIBAgIQCxNitu5qnT6WiTDxbiB9OTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMDQxMjA0NDBaFw0zMDAzMDQxMjA0NDBaMEQxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFUdlb1RydXN0IFJTQSBD TiBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANA1OZJJtZUI 7zj4qFHT79g+Otks4TEfmUEDhrNKBEEjb/i29GBfnpvFdT36azCg2VODJRSjIzFn 4qADcc84EmfKiDEM97HFsQPp9RRkqxH5cB51EU2eBE9Ua95x+wQp/KSdCqITCQ/v yvm3J4Upjl0wlW8wRCPCWcYw3pKClGRkNzVtI1KXnfpn7fG3N84n7wlBb9IGKJFa c/6+hxvZx2qnfLsxdIKR0Q/biGoU6Z8Iy/R/p7GoPO8vamV090+QHEL5AdSzKtEh U9vdvcuWjjLxVnaJLfj/6WoGZj8UWn3zFbEoTVaAfp2xqdzW7yRvi2r148m9ev7l jDqHo8UX69sCAwEAAaOCAd4wggHaMB0GA1UdDgQWBBQkb5E/iYeHDjLCQBjfxUzr T8hJMjAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8E BAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI MAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz cC5kaWdpY2VydC5jbjBABgNVHR8EOTA3MDWgM6Axhi9odHRwOi8vY3JsLmRpZ2lj ZXJ0LmNuL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDCB3QYDVR0gBIHVMIHSMIHF BglghkgBhv1sAQEwgbcwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0 LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFueSB1c2Ugb2YgdGhpcyBDZXJ0aWZp Y2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNlIG9mIHRoZSBSZWx5aW5nIFBhcnR5 IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9y cGEtdWEwCAYGZ4EMAQICMA0GCSqGSIb3DQEBCwUAA4IBAQCzkcXq0TN0oSn4UeXp FBW7U8zrHBIhH9MXHNBp+Yy/yN19133UY05uuHXHaU2Uv0hxefckjPdkaX7ARso+ O3Ar6nf7YfBwCqSpqsNckKT7KKtf3Ot95wYFpKDa64jcRUfxzRWnmq12IVzczqHI sIvUZQINw/UHSQcWekdUnMg58bQSHyTjwkj9jcX2RURxaVZkr15wxo/Z3Ydo2PVK 3afEr0/vcuFvE7QeGXiI2DJdVt3JefatZ3rj4VTW2aUZwHGUiWWIUudBfQKR0JEp lJ8MFaKDh4/A2VEJnXILu1iwvc1m3jCaPuzZKdoHM/1234bznJI2aAfhfIhoHw90 tPO+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDyTCCArGgAwIBAgIQCkyNTJEX18cfrd2TMrWvtzANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMDQxMjA0NDVaFw0zMDAzMDQxMjA0NDVaMEQxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFUdlb1RydXN0IEVDQyBD TiBDQSBHMjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJ+FAVlySDcdoZHiLKor DvccWaxxN8lRH8/28VTZauCcYCKqg3sPBlZJz5V/f/3tj9wwf48397sda1UHDBDH rcmjggFjMIIBXzAdBgNVHQ4EFgQU+vAiHsE+mBhhh9tn/c5Go0JygggwHwYDVR0j BBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDMG CCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZGlnaWNlcnQu Y24wQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL2NybC5kaWdpY2VydC5jbi9EaWdp Q2VydEdsb2JhbFJvb3RDQS5jcmwwYwYDVR0gBFwwWjA3BglghkgBhv1sAQEwKjAo BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgB hv1sAQIwCAYGZ4EMAQIBMAgGBmeBDAECAjANBgkqhkiG9w0BAQsFAAOCAQEAdbYb +WqLYJOt64OqSthU+fdu+ysPZqk3FMpwyUwQwwHs489Z6xzTlMzrDH6U8RQaiTo5 t+E23Yqfe5pKqLZP/LCmqy/jhU7XA2zMvLiDJ6jwweetaUiZFvnXBZNINFNJVr2U ljDyfXPg+Y5zUUD56x9LdhIZx81E/tWeglNXyaxZpxt86kTlBLaoqO1HCJK5pJKn q+DxwHEMWo7LDfQ7kw+8awM1LuE2oSDmgGIjDnFDS7shuyu5xF6IaW2qrpyAcZHx GapBNuPebxXH7FjZ5ZSIJrLBgO6hZIVRKWwnM+yh82wzu9f4/jc9csVdFbu9hN02 UuCYg6Nc8ZgZWvzH3Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkzCCA3ugAwIBAgIQDTVsDF5hwKF0v0cky4GLhDANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMwNDEyMDQ0OVoXDTMwMDMwNDEyMDQ0OVowRzEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEhMB8GA1UEAxMYR2Vv VHJ1c3QgRVYgUlNBIENOIENBIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAtLVdJ1rPVPZqKcI8bAhz5+1N1I0c7hXh3gCfY0eJLzJD7H8tCMHN/8G3 J6apZ8xulTdIrDQ/ibawzDghUSUcPEJlN4+9mq6ZYITPgboItpz1r0Ykkrlbm3t9 Or+PZeDuYTLsQtSp9eTv0ahBifbM8BgTnAvU1vAHyizxCzGLqFWUfXFNz0Pp1m5W dopyQ/poKxuX6v+Xr3yg/U9b2NWMftAJDssWTLZAfj0jgPPrnCyXWlq+HOLsQkob QWEUd3x/RhtIHpkO8ZR/8tbfEA6iqtATKiBdNFi8x3xwVp8kWQ81d+yTp5wyOxM/ oxPYp9tGj6TqnBzJlSPgWQ9RtYas0wIDAQABo4IBVDCCAVAwHQYDVR0OBBYEFLrR rCQKcw0OGhOyK90rFFjVRJ8zMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9j ZCvDMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwEgYDVR0TAQH/BAgwBgEB/wIBADAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUH MAGGF2h0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNuMEkGA1UdHwRCMEAwPqA8oDqGOGh0 dHA6Ly9jcmwuZGlnaWNlcnQuY24vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290 Q0EuY3JsMEsGA1UdIAREMEIwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0 dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwDQYJKoZIhvcNAQEL BQADggEBAAmjaPTIm4xq9BxZL8W7eOLtO6FHgUbMcuvjSPpYVsG7IyUM+SnPAalS m4SyCJIBveJHLFWgwRIkNrw+fbH0Vq06mZyKBpkBwkE7BL9ySvqu0pA9a1T7a3XZ zM2dhajTKdZdu+cQD69zxpzzEKOMJQJxNWmSqrqqh2RkwETJMIR5SYpSwXI66964 7hVueO7Kyzg2e5sTp2sXTviEYrcbjssasv9V7hvqxCTX2Ms+/cTimlp4+TiIegX7 PuqFxT/IIH3gGJmgZ59DXGSXMH7dsZ+Qwe1zhyBbmL87UGs++7k0HRe8c3fwgdR2 IrOj1iajz2ozplAWO0Gr81rG5avhKwM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDyDCCArCgAwIBAgIQDXXOldk6nIwv83/6D6A7ojANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMwNDEyMDQ1NFoXDTMwMDMwNDEyMDQ1NFowRzEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEhMB8GA1UEAxMYR2Vv VHJ1c3QgRVYgRUNDIENOIENBIEcyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE V6MkUMYY5mvvLvzZ2TvfKicjKILuyjq8sW3cyKbha/G/rPUQmZXRnGd/0JSvO2dD ipuKXc+UQbOOsp2yirJPKaOCAVQwggFQMB0GA1UdDgQWBBSvktn0tvk4DKY7AuzY bHa5VHeGYzAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAOBgNVHQ8B Af8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB /wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8v b2NzcC5kaWdpY2VydC5jbjBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmRp Z2ljZXJ0LmNuL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDBLBgNV HSAERDBCMDcGCWCGSAGG/WwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k aWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMA0GCSqGSIb3DQEBCwUAA4IBAQCUpWxX Rxk4IamCa0/1e9dCUTWnF1YVrGLq9jEO7J3SfLmr2Cn9B2huup3xTkvQOzrOcemV 9tWwm+HcIYUT+qrp1tdDLibwKR5Qogg8Reo2P+RPluUSnyRYIyjXJPyIC6oFxCqb nIbsHTTsj1TyTPAlrk6Tfs+uKjZvfxogZmqH3ReNDXJGWQxWU0bETK+7rhJRKP+5 VyAlMFv5eTpP84tsSqK/1+IDRSaTMJT9ni//Dt6o8ItTEMgYP2gtH2eIBoBEz+xm qtNnd6NUMJLXB+OqOJvmHIzZmz79u8pfzuGbyC9s2vvGg7tRO1kmynCJcC41lmXJ 8feUOvNoe9exM1/v -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFKDCCBBCgAwIBAgIQCYb4gC9/81s8m2BXYGyIajANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMDQxMjA0NThaFw0zMDAzMDQxMjA0NThaMEgxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxIjAgBgNVBAMTGURpZ2lDZXJ0IFRydXN0 IFNlcnZpY2UgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCkurxx yvCFnAGKxcOg7wCa2vG5vExnuA2EARGZKbc9howpqzCScELA6BIEyQQDFlhP2rgm 3ayU8LNoOfw5GWpUS7vihvBXcQoNVEw9e5e4KN57d8YllX0RNOFLWCthhjECJU0K A2FbO5ry9VCqGX4ge6TNO3kGxHOkbI8QmqQQVEOII+T4icfjd9+YC4HF1Hyg+zu2 XiY0WGfUBpSoRDVPuigRxb8S3dy/Zh4S2ckdv1FBM5bOe2+je+sQ8EQbNI2z66O6 3j3c2nbptigey8FNGebSZiwpNvT/lIrbVC2rJDg55BrMahpLi4pQUKyyr0/flozt oH//0GNzGTPYJN8jAgMBAAGjggHzMIIB7zAdBgNVHQ4EFgQUhypi/tyf1LUxmgni B3pOw3dHYhUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0P AQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB Af8EBTADAQH/MD8GCCsGAQUFBwEBBDMwMTAvBggrBgEFBQcwAYYjaHR0cDovL29j c3AuZGlnaWNlcnQtdmFsaWRhdGlvbi5jb20wTAYDVR0fBEUwQzBBoD+gPYY7aHR0 cDovL2NybC5kaWdpY2VydC12YWxpZGF0aW9uLmNvbS9EaWdpQ2VydEdsb2JhbFJv b3RDQS5jcmwwgd0GA1UdIASB1TCB0jCBxQYJYIZIAYb9bAEBMIG3MCgGCCsGAQUF BwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+ DHxBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0 YW5jZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBo dHRwczovL3d3dy5kaWdpY2VydC5jb20vcnBhLXVhMAgGBmeBDAECAjANBgkqhkiG 9w0BAQsFAAOCAQEAdojUWZXS9qgDpPIR88iNEYEgggTV9ufeo1xC/mca4BVbOcPX gyaQjVfTSnt2zwArzod+lguBMDKXYuHPJAP25tfxadz2biVl5SSCPvph+VXtbgOe nKNHeG07r+4zIck+/RKk0Oix2I/twIloayZdwFmubfdUZYTZ5oSA/ZjRtIICgISI CctoEqzC8V2ALn2GvfIqeClTr5SywcKaDUi/ICQCLCMR2rllBVUDufQ6rK90d6qT vOHaLsfsKIrjtPHnSVkCTiPPHOpAkYv5a81nqN1KUdGoGxtFRY6GMlX82HkevNZO mZyWNDZjRba9Y1EfZW6WbXhnmZrZGDRAGa0BCw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQCLbeQXOBPZB2s9n9Qt0P8zANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMDQxMjA1MDNaFw0zMDAzMDQxMjA1MDNaMEwxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJjAkBgNVBAMTHURpZ2lDZXJ0IFRydXN0 IFNlcnZpY2UgRUNDIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbtA1qwL9 dWmA/a8HaeUJZURwAZ6DsiEeRwuVHGPWB8di5SurtGaZE8FzvojNshY9SsCiZNup fUFNa5JiUNmd66OCAXgwggF0MB0GA1UdDgQWBBRFaCUEGaasSPMN1aM9OIvyr6Kl ZzAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMB Af8wPwYIKwYBBQUHAQEEMzAxMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5kaWdp Y2VydC12YWxpZGF0aW9uLmNvbTBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3Js LmRpZ2ljZXJ0LXZhbGlkYXRpb24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNy bDBjBgNVHSAEXDBaMDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczov L3d3dy5kaWdpY2VydC5jb20vQ1BTMAsGCWCGSAGG/WwBAjAIBgZngQwBAgEwCAYG Z4EMAQICMA0GCSqGSIb3DQEBCwUAA4IBAQC2ui/HFWOwuffGEFd+pftOJb2Tk0gP OQKwGvx6mcyylu9E/C/t66LnmBebPhZPoR00ZqSkmCfLBhr+df+QadLq1PRU5W8Q zvc658967W+aFCAZLYjjSKEz09D7vpTn7he3LbSR/6ZFczgXjIZVVOHXtEmLT+XX lY5/Hka4shXzMgjK16/1D0Gc7Inuh4Uad+roD9NHRn66tZCMUXRa7BWnb53s97lM nBDbUpJoLFNhL8EJNFMNMJccVd3ZoxXLSq98tHzWFMovmkw2L+Ru8FrSq2aPzCPY KZgU1KSKhF5cEmlog4aBbj+c18CTCttXwxYGt4neQA4CSWYiv+JmCw8S -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuzCCA6OgAwIBAgIQCnGMig0JdIKjmIXYK2V7CDANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMwNDEyMDUwN1oXDTMwMDMwNDEyMDUwN1owWjEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzE0MDIGA1UEAxMrRGln aUNlcnQgSGlnaCBBc3N1cmFuY2UgVHJ1c3QgU2VydmljZSBFViBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALWhYO0PraF9FEfCnWwhoZ3nO1OHOpqy WvILwzAYr+cB6NRJ9WUgjUABgZjFV//TuaoYUmAYnLc4lHfb865mO7HvPbtuZR8C 3kyViT29ilNTmAuXe2iHw1uZbmk6MKJB24t60LSVnTPLLbFYHGgNp+wo+rHR4LJi 8txpupRmAWzsdKx0YeNbg7gh/h02hP+t17JU/rmeiCDyJDsvqszkVKXD0Cd5oKwJ 7zk9Vwc4H+aujr+GXvCTwmRF75/lj0e9ehK1DIZeLXiTFjpeWxtlB2m9Qzs1uDdX e4+2dvUklNuUbEh2W/E6TxHwOe79tae9S6tY2o4YBZSJofzPfK3cwQECAwEAAaOC AWkwggFlMB0GA1UdDgQWBBRqNxzsIaDsK20/PSnJJNhZyb/1ADAfBgNVHSMEGDAW gBSxPsNpA/i/RwHUmCYaCALvY2QrwzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYw FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wPwYIKwYBBQUH AQEEMzAxMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5kaWdpY2VydC12YWxpZGF0 aW9uLmNvbTBVBgNVHR8ETjBMMEqgSKBGhkRodHRwOi8vY3JsLmRpZ2ljZXJ0LXZh bGlkYXRpb24uY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDBL BgNVHSAERDBCMDcGCWCGSAGG/WwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3 dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMA0GCSqGSIb3DQEBCwUAA4IBAQB6 RGkNFzRuygjlzLhJ25z+8fw+nwHO1LETgdi76vSgh6xut490ePhkmBkeLiHGgUsQ Sv9Fa+Sg0YDv8AU5WiQy8oX9fP2HAAT3+KdC1d7KIAigBBacZn83ctLKl/ywEvnn vsZ46Wza2g2ndc6Hh38rpF38mSoA08VQWyXCC46XbvUPI7JevHuW6kexYKKllOCQ GZKGPeatQmtoT778X9tcjhYx3NhbwhMX6MUYTIsZfTnk5dBx0Z1fDyhrf/Z/+E0x jywp0kKbqRhxmybLUPGA5xpxovVYI608mTQhtLE4VPr6O+QET0PzrkSTHTV2c12B h6X5kzIzTT3NXgfDiTKx -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9DCCAtygAwIBAgIQA4DMmh0GJbgI/mcjT/pAnDANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMwNDEyMDUxMVoXDTMwMDMwNDEyMDUxMVowXjEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzE4MDYGA1UEAxMvRGln aUNlcnQgSGlnaCBBc3N1cmFuY2UgVHJ1c3QgU2VydmljZSBFQ0MgRVYgQ0EwWTAT BgcqhkjOPQIBBggqhkjOPQMBBwNCAAT1Sz+8wRBSH2RvQd4ti/u4igA/OGAFavLu 1U9PrLbqud9N7nKpSdM3kq++8G3tG7zveBn4ANKnXZLKPie6nsRZo4IBaTCCAWUw HQYDVR0OBBYEFEPN+FFzFvD0yMAwMrecApmIWD30MB8GA1UdIwQYMBaAFLE+w2kD +L9HAdSYJhoIAu9jZCvDMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zA/BggrBgEFBQcBAQQzMDEw LwYIKwYBBQUHMAGGI2h0dHA6Ly9vY3NwLmRpZ2ljZXJ0LXZhbGlkYXRpb24uY29t MFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly9jcmwuZGlnaWNlcnQtdmFsaWRhdGlv bi5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMEsGA1UdIARE MEIwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2lj ZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwDQYJKoZIhvcNAQELBQADggEBAFCcubCzQSnY Ps1UMy3l+k/86S/63jH+XuYZIvHIrtFUSbBEd+SQ3qoKAE2yk9cJRwaqtyjZZ+XF eDniGpXiA4gUH0SrOTf85vfW/AAlN4vQybZY6VYDwvaG+Y1U3tf1ebsGojyJPLCG QKTQUXyKlFQl/Gr5pfr7l0TrWOkfJ7uLiJQIHBQtfS9QFVyVrZKXBWYWjAp5TvZj Ps4Z6vh1LZp7m4rbuTdmVGzNV6wezGkHI6prrfEDGm/ZG3RJ4HVh4MhezGUNe/ja qUhoz518opfc21CTqVDUhQjOiX88Vio+lkvNBAGDHII/VH6cG647kUrqK/3Upglb 53ZqxfDVcLE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF7DCCA9SgAwIBAgIQNuiS1whuAwLW0pVNFhTiYTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MzA1MDAwMDAwWhcNMzAwMzA1MjM1OTU5WjBMMQswCQYDVQQGEwJMVTEkMCIGA1UE CgwbQ2VudHJhbE5pYyBMdXhlbWJvdXJnIFPDoHJsMRcwFQYDVQQDEw5HbG9iZVNT TCBFViBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMLRzEEEZA0V es4gougGSzeCPjPj43MM6+KfP09nis1RNyAFBj1op+eo/Ru6rpl38KIwO8/8g4X7 2/65oDxHd6Yqp3E2t/THSHaVxyiEw1sO7G4CsVe7ea9DD+l/Q82ZKxaaobouR9Gt yTEAf/jnF4mExxa5jqaND2sHWkphGY0iCLxz/r+bY12fpnKMuMaeU2Vi1cmtqXeo elGmfeml3uSb0BbaCIdJw/2zgEU+hrpkbfiz2bwwN9i8s+oipzDTdYNBVUowh0vo igaDaNs4fuJqdUEUpDf2BtcUC7rxdd7AXrgnPDJR4x+t1GLKhmrndWbbdOeDinxA SZiflL6Oul0CAwEAAaOCAYswggGHMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvA nfKyA2bLMB0GA1UdDgQWBBSfLizQ/vjIUuVkNJ/9NWDKYTfoKzAOBgNVHQ8BAf8E BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEWF2h0dHBz Oi8vc2VjdGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwu dXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5 LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNl cnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcw AYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEA d1dl73D527K491wnx6fgtamqUw3gkBHh2zEw2PUqJLsh6io06QlwY1Osyw1+UYyd WuSqUElwaakFRkQSAf0iG/AW/wLggub09/UXGItGHh+zbUImUZ8TcU2FvJSIoe6o p5J4xQ+OtvJ2rik+g9REVza/f1oTdH+uBR6EnZgSrv074CJ6Nh1YM0YTfDJI5me5 yqnHEum//pFQS9w5/RRPm36PKbPckb79K++yL1oZG37dNEFOQBEB/nJVb1wOkX5f OnH0HItDT4hRZ3ZG8P4nmh2I9OEdM1/XBrsdbdOdZ4S5DMh/DzBtzi+MoGeUkwVq 6wKklwrTjjjIbwzvlDqwv/l0ujMRVrp0v+6DVXxmHX/3dkrBjDZeqQZb9DeCvIeN AGBQ5KOLDBnwXLyuL/nrBSr7j+NRE/BNEm/ZK1AHuIf+GUFKgw1DbXjoT/hzdVpZ 7LlPMTO9r0Jp6nCArDWLJ/mLlTaJjICyVY+HUGDFWOhPmgJaf6VjpLvoag6vOFJU PZJQUHfD1/TZkAfQ1Aj6ascO05v/uYPZ2SHtLVkxTxWg5NJPZFLCjStmPzaxvia0 dbjYzuoORBn0/nSyQNRh1EnnHrG2IHA29YOshdqDaTAjAZvD3eHzgR+B06lovMWc DBIg6LPUpBzXP64Z1FM/nCQqsAJUeMpBRUmo0stBpRM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF1zCCA7+gAwIBAgIRAPbOzfYzVQu5OuiqxUzioa4wDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDMwNTAwMDAwMFoXDTMwMDMwNTIzNTk1OVowTDELMAkGA1UEBhMCTFUxJDAiBgNV BAoMG0NlbnRyYWxOaWMgTHV4ZW1ib3VyZyBTw6BybDEXMBUGA1UEAxMOR2xvYmVT U0wgRFYgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV65DbSyKx OEqEGlDPgbDN/N8R9zUn1gO5MAj9IeZnf+quUcdtgA2gAsh48SBaTfJQmpW9nU7l LHwIzMREt3bdNcdBj5LLQtpBY9B9S1uWB9EvtskWLI+YIEAPCooo06vxDdo4iXhG u2KyFnwt2/glZ4O7XVcdqL/gEMCl58Vr47TZ26CgfAFfVCLVZVXnlmIFDmS1rEil DXNIvPuoUQAXcrYlM2Kw58VuqMz0zgCocEF+GXnGfpcseZ9SHMgpX59hRRxI1i/k 6qF1WWbEWhwRU6YkLclTETo0GxmFdUc9h27MaX7F4IwXOnB74Jkj7SCBbDL0tKi8 9CB6ZpUnda1TAgMBAAGjggF1MIIBcTAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dib wJ3ysgNmyzAdBgNVHQ4EFgQU/Z4i+HrI6Hl+U31DmmHev9sPHQkwDgYDVR0PAQH/ BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAhswCAYGZ4EMAQIBMFAG A1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1 c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgw PwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RS U0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRy dXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAZmz4QCTho//gO6nGU0VxANXt8RnQ EMyYDw4Ym4L9gPjWF8d89+3OPRCfJHhR0KNwr8QKTWpp/EVwzfJWq0PSzJRrZIXS n57tDco1IVZHEn5sWHGo32xX/ttjvhg/8APwivmpZGPX7u7uySd3yWagVh0l7/sR IeKuuGa+lu9jCIkPFjy0Y5pmYT0SDbcyN1vpaBuYUYCEPGvwO9ARrqgCbj53uG9/ pZtVLYO5RTZa7Yagay+ujD9OHuqtcHNWNW83QYuid1XZokwVTID4wHYcY0tBKIIj QEyQYARBgzgKnm8zLSUwIPhyTFs4CoXRBo7qR+HvSRY85V8d4s0hfXJEErsD+0vz ijmvut0RHYDn/BkwVXxCBvHBo985Z4IuyK9DQ6gV/B09bEQhxllAWnbWBRM3hAdW MsE4778KI6TDbRryjJLbQ6AvS/h2w0HODT3uSIObsnhDqWFbP7Y+iW4GkxVLrga4 RnqYkcij1PYnO3OYQzR8bVEaSOqv7ON4Giy18oIcX0K9e+Qa+MW6+QkN8A0hPCc7 JTKXyBZES+gRoWbrp0+AnnF5UdN7oBRCfkRDUZieuhA53hjWvI46qNu1Reu95ekG Q34PGG/Dyf1LmKdzL2d3bfpMBDi+LRXUkQRudLbFHqU+EPOxeCGnM5ByYyc8ml3A AKhKahHLhIzy2M8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDiDCCAw6gAwIBAgIQdCGSYf65zMt/wR6GHPrFZjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMzA1 MDAwMDAwWhcNMzAwMzA1MjM1OTU5WjB0MQswCQYDVQQGEwJCUjEtMCsGA1UEChMk Q0VSVERBVEEgU0VSVklDT1MgREUgSU5GT1JNQUNBTyBMVERBMTYwNAYDVQQDDC1D RVJUREFUQSBTTUlNRSBPViBFQ0MgQ0EgIFtSdW4gYnkgdGhlIElzc3Vlcl0wWTAT BgcqhkjOPQIBBggqhkjOPQMBBwNCAATjAVqOncXxZtecTtCtzyeEYvHoR2mdvKhU R1in9GeR2XRTLS3V71Xj/Fz6bRP3htjlQ6Poj7VHytdwriAsiTCUo4IBazCCAWcw HwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYEFAKxT/In 8Yp/pH553vxgZrzu374yMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/ AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAYBgNVHSAEETAPMA0G CysGAQQBsjEBAgJQMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2 BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RFQ0NBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0 cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggqhkjOPQQDAwNoADBlAjA1svvX2gUC ORzoUUdQW2nd/9JaHTBkjywzctAITFiu6T9rB/FVXhoYZwQRJZT9+VgCMQDr8oy3 KWPjFG4rczMRfIYz7av2R/SB+ywEQqdjIJIV654jx5uM9pqwC8cAimWCzyI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8DCCA9igAwIBAgIQA3eFCc1xJkPTTUzn3h60vTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MzA1MDAwMDAwWhcNMzAwMzA1MjM1OTU5WjBwMQswCQYDVQQGEwJCUjEtMCsGA1UE ChMkQ0VSVERBVEEgU0VSVklDT1MgREUgSU5GT1JNQUNBTyBMVERBMTIwMAYDVQQD DClDRVJUREFUQSBTTUlNRSBPViBDQSAgW1J1biBieSB0aGUgSXNzdWVyXTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZrZZ2xx/vy+ynpBYKESSxaJEI2 7lAh9qsvlZlhbvQfZ0eoJd6esb3kC7/iIxVv0omPLKQTuxAQ7gsxN9pBJMZ1lJzU yhHxFR23/PzaYtw5LUks+zW3vqFvc3l4J1VBMI4Lardi9omASWufX/iKi2mP60oz tF94fRwC3Shza6WHWo4zQvQ7XONqQHeCwv0WA2OnTjQrlsXN0zxHE47gkUNhMKJS 0NrudgUdBe7l85MQRAzPslWQ+opjiVrcsZX0tWr9Yfcntpha36P7ASVMzrWFVJiW 3AeXSd6BSvtYZDi1jGTmo4q00Jp2Vsso3FjUo2QVGD2Wom+ozpHFxSBbmDsCAwEA AaOCAWswggFnMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1Ud DgQWBBSb2jn/cHhaO+cfqiEIbOrF//57PjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwGAYD VR0gBBEwDzANBgsrBgEEAbIxAQICUDBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8v Y3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhv cml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0 LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYB BQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQAD ggIBADytOwwMGCS8ID8khjrItes0Ev1v5BObVWDySU/vw7/WkF+ylnF88AK5s2zz xRlFlIFmBxVqvzwJED1QP3w6m5btVnMuLXShQnvnVHNfn9HrKnhj58+Dmv9U+HGa OMVTy3WsvJim6syr6I2iGnuYan3JUNSnVxzx4hNyPHrldv09vmXkcvphDwRZWPeQ jREkE08SbQE6atxs3Ece2C1odoviA1MQ/UO21LCS+3bRTawRH/ly0jAFF0YeMzZ4 aY/uw15pLkUsIBsGWCinajthJc8htUlz5HftEpxb+/akxWn4E/GiYmO5vEDLAV6o HouYOnxxsuxdOIBHc2Wmu36J+yp0JLCWwRw1QMgI/6cHN8pEODEa+10tGfBQkBce mG4sVYMh0FY9se9EZ+gSaCzZl3xk5eTNtriyRdOy/zY81AMb8E5tFowXL+ECWhGc A1BkAij/Og+2M/kejeGQ50qP9XGtohfyzKBD/v+XSa5CpnIe9ZDygTQ6ZZalPdOF 6V5SLfpeKaHys+zbs5RF1g9Y6Q4ZsWDb+MvOcBkHrLs7dr0ziC3X3M9Zz/qPIXZG 6n6z9PWeiFpsxNVBP5W6jW10rThjcjp22Ng3zZxB7gzgAMmSDJgACk0WGD7Btru0 /tg9ii0C66DC4XdyW4mxZ3pTo3WNY3cgkVWlJ2W8Q8kyd97l -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF+TCCA+GgAwIBAgIRAIvZZLBXSMLn5+v5b24HbBEwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDMwNTAwMDAwMFoXDTMwMDMwNTIzNTk1OVowbjELMAkGA1UEBhMCQlIxLTArBgNV BAoTJENFUlREQVRBIFNFUlZJQ09TIERFIElORk9STUFDQU8gTFREQTEwMC4GA1UE AwwnQ0VSVERBVEEgU1NMIE9WIENBICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiQs8c2QfHYQuELtQaPTSPu4GdspT nFWcvYG8QaFRg/JOB5AUNLEHZ5YHuMVTK+EyRmVhKC1pXkiWS6N5Gc2OqXQwT5ka 2P87b3JC+x/+iuKqZFYw1r4h8mbdhhnKoom0NloT2mBCajrxSyBqlfJQiSiikDPp 9uXVqQoTpAji1Hd16ksX0h1VbRTj37eZdDedalXGdj+qTU54MseHQKAHjA0BUXM5 igXOLIZNiI8BWOk4MZUv0LM+nBmI41I20Xuxi0TzySRAUB4ruXRnZhetJ5I7RLAn FCkJ3tLdqZVL6gaM2RbhrYQsqcpPC60YACPtBBQL+ORC4QthDiqqGNdJrQIDAQAB o4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0O BBYEFE2GLx9CyQxYVpZ43Nao2JdAspfKMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNV HSAEGzAZMA0GCysGAQQBsjEBAgJQMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5j cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI hvcNAQEMBQADggIBABvvE1Ea8SepuFrIQWeKusHEGS9Il61mxZGaqPQt+eXFTBCt gCbKV7OIjqheJxW2SXtYRCULUFBgJWhAscwAfEZBKc+qqzheD9IfhEU/+mjPLNwV sGSmBcTg0u/u36d+SpOgyoeezYuKSYriQAa65mwOxQakOGeyPatENCICyezvuPX3 aspim6ud2JlcTcYOqhSWmt7F46LDHWKaSiEzhvsEbszdnbWf5jaIQ6PPJee1BXKa U6NCL2mrrqqKzlS8X6TkWL0ZQN5x0y+MCJXbWBpm67z/C2TE2R9JHvsOlitH0vwH tgP/lmbm1Qxx9bldTzkx7jXiURzvz3sQdrt/snbC4kNrmW/IJPajKnbXoQPO8KX2 MdD2KLbnbLSmHrmDSiV55e9boD5qRDTSE7nt4S/es3XbFPoH0b3n8SFr0tp1DEXZ 4LE2BSccFLHNmqvsVWyZ9L/xOMOxokO3RG28YvZp2cYJctpxHpO/P40Ln4yhCVfL om5VEfFhfjgVGx+W/oWi55G3vw5SQ7RQZzpCIwWJFiS2WlNT1t8B4H9wWaJ74TlM Aplo8GM30Ko0SnfRdwktiJRaN8HISysaBMZyQLaaBWiIq8GqvugSqMsEuOZYAqUS HnYUqV9ZeDZpB6vcOB+BzbT1wvapn738axoqqWp9cSPOIREgpKxe/RKvJdZ8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF+TCCA+GgAwIBAgIRAILC4+1cI419GZH4pWlHDm4wDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDMwNTAwMDAwMFoXDTMwMDMwNTIzNTk1OVowbjELMAkGA1UEBhMCQlIxLTArBgNV BAoTJENFUlREQVRBIFNFUlZJQ09TIERFIElORk9STUFDQU8gTFREQTEwMC4GA1UE AwwnQ0VSVERBVEEgU1NMIERWIENBICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA36bZuv7VFIn964VeA9SyDE0H1Y6g YUpcIozT0baX8QCOUTqair9gm+R00TW+Xh7LDF4KgbBUklnz0Qo55gJmJwdbSw6i dTKAOIyfOJjAX+P49dnO5nuEOG0dcbLLMct6nSrSZceeWEpN6KvTuggp8SAiH7xS 4yAdYs0MtJJgOfoXW6QmG9zIxIYMKxcc7fA+XjiloTjG2JXGkc8SPx/kyC8RQnhn VUL+ydSucsoGlgFBESZlCvdphmn3OPZ2kggDnwGnwH6YTIZTmBZqQTM/nVwgQh84 LwHhwejwEwZSfb+nK1f548iWRvlmeQcKar+6/ulg+YdIEGMRhAs/YqQ2sQIDAQAB o4IBdTCCAXEwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0O BBYEFAPmL0/6jAxxYOfetGr9EE6ivDZjMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNV HSAEGzAZMA0GCysGAQQBsjEBAgJQMAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5j cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI hvcNAQEMBQADggIBAE0jBwKn0yFlDeg16DlqgLRXEZ66tMl0LWVgCh6HDax27bLA b8DjlXFGlFHGg7prxNS/L4TKnz5DM7oXyvZK9l6XYH1l8GU+o/N/I12dpcgc7Q3a qSSnMXnO6LljOMLwAVbJ/NBrxYQlJO0ymoU548kz5C8p2BpuEK5X7wgYGc5Pw5HV U4Ajoi3ophj+qnLQj9iQV0/NImKd80a10gnkhFEB3lsEaN06rUnEhnuJzXBBSrd5 /NCksHY8NScK09rhUn5ZOoSvXYag/M6rOs7iSGvcNHu1/6ipnH/scOT9q9Pbkl3h YY1mHdwWqG/erf4PVTIU40pPPghlO7QRHDT/vN1IFKDNFURvWls1LnuqDjglyqSu FyqN6BeJagW+Wj4HMy3jSN40mlItGQLXMUyFowEtolHH3L2awu2teUi1kR3nZpUE nVvE9ZlLX7ebZ7d2DNs4jjkDe3xl7qMWX0QjH/6guUpUTHh/y7iP135xfd7qbTqV B3AigDu10R+lxyxrpuXgBU2e1zeqb44wb3VaAuXNS69hcc5eHRS1t32KoO+3dDfz Co4pnjJArxFoIDAenNmf8zXgXYvSanIe7xFTjX/FnD8d465ndFQHWBKSdVfs2O3k eLCw10+my0t7pIPeTBOaI7/ek3/xSRTIIiF6zBX+5GJGOkR+6vXAFH5PYhyd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjzCCAxagAwIBAgIQRpgPJDoqr328hGfxCO/KzDAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMzA1 MDAwMDAwWhcNMzAwMzA1MjM1OTU5WjByMQswCQYDVQQGEwJCUjEtMCsGA1UEChMk Q0VSVERBVEEgU0VSVklDT1MgREUgSU5GT1JNQUNBTyBMVERBMTQwMgYDVQQDDCtD RVJUREFUQSBTU0wgRFYgRUNDIENBICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAEYmyFvdwZgaQY12ATxdd+zV58oiVc1IAM9bqN CK4xV1ZKAPQTpjXoMtxMRUU9He3WCVa8I/Mq9aQKy547XhCIr6OCAXUwggFxMB8G A1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBS8/ls4inTB L0pstFMDOfgMfohyvzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsr BgEEAbIxAQICUDAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2Ny bC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3Jp dHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51 c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUF BzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2cAMGQC MGY4bjYmlJ1Qnk6YNz83drEfzswokcPj/46H0LnpWm+U5NtclzObAjCjCgemaHqb BQIwRTyxDxX0KCO5Trw7cxZQx/9F7qwHTtzSfspT8vU1QcQJ0xepwKOQtuX17vEJ sJjs -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDjCCA/agAwIBAgIQE8GB/p6VMU6Y8XD171I6qzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MzA1MDAwMDAwWhcNMzAwMzA1MjM1OTU5WjBuMQswCQYDVQQGEwJCUjEtMCsGA1UE ChMkQ0VSVERBVEEgU0VSVklDT1MgREUgSU5GT1JNQUNBTyBMVERBMTAwLgYDVQQD DCdDRVJUREFUQSBTU0wgRVYgQ0EgIFtSdW4gYnkgdGhlIElzc3Vlcl0wggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDR5e7/geqsKG45H07K6F2ET8MD1YfO 7/zkND7rffxtL+C4+Fw+LHwAawMfd44jrFeFNZ2WEl7rlzukAgHUMZmx20tR1jJI yi+SE/ut3p6MKe3SFlFTRy3iI2HG4ON6TNSs7cc/2Pqdg65imY3WmPatLnDnRdMv ZiQhEAvpdGift689K7e3a1Uiow0WZIvO4R+flXhLBWqGhZomJe4zg1o51AvQpK+G sTlnI6EF9QdWWWNe7Y9rmUZQHB0WRRYYHEP+l15XN+c/4fDwnUk/AYKiwHjOvByQ 0LzhXnP/isuMTRaAJflE/AFg+I0ALufqNi/xymNIHwkerqG4Uk5ITEpJAgMBAAGj ggGLMIIBhzAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4E FgQUOUgkhp/TN7VJcarIqEA0+GuHzNkwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1Ud IAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29t L0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20v VVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUH AQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3Nw LnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBACXwgw62CgUxbXeA2JKQ j7bGjH/mBhGQaBGua/oQSwf12ZiXV1n2Ede4RYIU4yc91LNSaSWMU3gdDdhSj0Gj KNe91qR3I9MkyUTLPgJp+e6sgtoqqVxwhFK5+gBFxGcfK+3JH3qcSYXEQUeYGp+n g9dzxrYQ/CAPf1yvosgfqMgKSQCEjOOFaRZA/BB9ckIdPuRPTamSyCkpRp5NfsBN kP9FGzB3kid5R9cYydFAo/pOWFVg11gYdQhOA1e25bh79/NVGK2TbclGPAmEViLW 5iZ6WSlszcShibn13kSONzdrLNB5Ufx0uqBpjZ+xqfnazoSs6ZwhTx9kkcwGMaSD aIt/boAr46lEXwcCSU0qxhnCSPkyEwqG62cXG9S2KNHVysPpP4bPkKIi9Uxq9rMG f/45multA6r7yi0hNZO13HHsX1Qs9a3HIdyxkBSXfEgiZkmDmQHBEzH56zQq7NSX MqXfrYlOoLyYBDiz4asF3Ls8vO2KvwiIeKayjNxuln2ovvfx6s/+Y5E1IDrzFgNM oBNhPt7vYnkX53YDUJgr79JR7BPFQbsEPT8Tk4p+CSBVYBTyPzvdnAbYG0bBvGYo fIQ8B2HPceQR1Etsj5Y4PtMn/Jsv9j/wvdcYjR5GeaxkQi8wBD2bEYKh2nTkc8QO CRc9BafdXCWawjzdINqGWTQ7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkTCCAxagAwIBAgIQIPEMUZavRenaqX5S1o0zDDAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMzA1 MDAwMDAwWhcNMzAwMzA1MjM1OTU5WjByMQswCQYDVQQGEwJCUjEtMCsGA1UEChMk Q0VSVERBVEEgU0VSVklDT1MgREUgSU5GT1JNQUNBTyBMVERBMTQwMgYDVQQDDCtD RVJUREFUQSBTU0wgT1YgRUNDIENBICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAEXnDAuJqX534THqMS0OSX4WCUp2IAQgkfI1GL S4X0tDLanStMGX4HSaOmERqVXWuagRX8hRWSKfxHRP3Ux9M0QKOCAXUwggFxMB8G A1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBQrPO8DdoBt tKIv6st0xxrVoWPHuTAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsr BgEEAbIxAQICUDAIBgZngQwBAgIwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2Ny bC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3Jp dHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51 c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0MCUGCCsGAQUF BzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2kAMGYC MQCHb8U966XlqN56ZoHs4ROU3qR8xUwKluLfpPFp3RddfXXpyeGe0di+bAVTYV+e UXECMQDJvR3Gev0QwLxa0i+p31gedvAYTevJDwtxpvfFib1XVBFxtsUpxsjUvCyX EqDXka4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpzCCAy2gAwIBAgIRAKaGCEpPZGzIv8x9UTU8mBwwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDMw NTAwMDAwMFoXDTMwMDMwNTIzNTk1OVowcjELMAkGA1UEBhMCQlIxLTArBgNVBAoT JENFUlREQVRBIFNFUlZJQ09TIERFIElORk9STUFDQU8gTFREQTE0MDIGA1UEAwwr Q0VSVERBVEEgU1NMIEVWIEVDQyBDQSAgW1J1biBieSB0aGUgSXNzdWVyXTBZMBMG ByqGSM49AgEGCCqGSM49AwEHA0IABNs9D3PQfMRxW7k1yV2doZqFN8Fgo+TezDRN g3UxfGYF/Zpo/J/Xe0DwMuBPVhVaMqyjBkX1loKEVV+lj+l8x/OjggGLMIIBhzAf BgNVHSMEGDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQU9fGWKEvm dS1YHEsiJDN3Ub1UiGswDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYE VR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzBQBgNV HR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0 RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8G CCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUND QWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVz dC5jb20wCgYIKoZIzj0EAwMDaAAwZQIxAODYW8bEwHWEEFDWBbe6wYZn92s/mL1u A/QUcEio7mwlUlvGJI9kDT4izSBrfVgmewIwJwFdlIHjwOMTbwvVfvrr28UJr+LP OFvELMSehplSO8u5B6h/Z6XWFQKVH8+ohiLn -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF1jCCA76gAwIBAgIQXTuyjLLuLTnF7/EBRS217zANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw MzA1MDAwMDAwWhcNMzAwMzA1MjM1OTU5WjBMMQswCQYDVQQGEwJMVTEkMCIGA1UE CgwbQ2VudHJhbE5pYyBMdXhlbWJvdXJnIFPDoHJsMRcwFQYDVQQDEw5HbG9iZVNT TCBPViBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIShIeqBiC85 sZQE02CGWAnqg62JRTimY1xlLJmSIeS91i2YHRSnAgrLBei9Vx40KoFHaXY7O309 O+9/JumBB1qUwufLhG7BB66GwkDZlK/noygHFfBTFhcP9l88dZVqGSWX4UR8qe07 p8ZkJpND3S1eSNLyyiZYdf2lGp7QjfR3VII/SC2/Ve3l5kS0EgXKcKGTf8vDBayr kjbdeUGVbnS+hfaY+S64jbjajuoJmnLl6wAIEO1TTQF2ZF2sJ/k1YTzIx5yL3kHB oDcFYNtrEyj/0JuFPLWC6saIp/7/gFGDz9/mryppHTIrtWSAaWB9OhRjAlR20EIZ oNzbrn8ADUsCAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvA nfKyA2bLMB0GA1UdDgQWBBQfshQpo2wlxu9u86N0nTqAG7B8oDAOBgNVHQ8BAf8E BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICGzAIBgZngQwBAgIwUAYD VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz dFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/ BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT QUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1 c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAtazxqE5YoAUVEs0+tT4KNa/BSkBUL xsbOAnq3DuSY4z0PQjPY+JFoKLg+4AgLErlRih1k8PAyHW0lsuKKk1bSmnspLVyK bimSk4LNFSBQVh2mXB+m9yYtahL4+qGkvxMoC5viJxqJW6iWgKRhkgz27wblmwwE a6JlNcRy1p8J3JwM6five7+IrPkPRQElq566CTEF2mMj3EQqzzYHoUAj5MWI8r4M xWSxzrog7xKhN34QdDdOq1c4+3HJ+i0P8cRmkp9kxyMETEYwyIcANgF4fAKIo1am +YXcHoUR+RLjkIyBfbgFpTWYOi7bhslPIxTljC1BkJb5MmPyrqvyJgZxrL2qYVuW KAeSUM/Olh7XlMC8AmBWxcqVa5mY7u6nMwCTqGKCAxlVwE0ri6n5J4oaOgCLBPml WioU4kzPPilD3BFoWUPR1X3EMXYF5SXfcrExl2vkAwIyl/fZK6/ZKcAQ/tTtb2Bn VljLKCoNYRntAQqp35xQegYZx6uduBbwgBkWnVPP945zIL/ypHuZSsUMBPx2ipFs ysXKRW3CCdzC5gdCI0qe3vNTn+nGHZDM/HC0VistV3r0p6dtWvu6b0ucC27m1hrw DhgoGjTCNsVs7N+QxlbeylUYe8FT4AJ8ov3TGXfBrk2X2JC8fFE+u+3V3oVnYx42 29YkaTUgdvzwMA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFATCCA+mgAwIBAgIUXV2dyqOY67+42nvzko6YpHzL908wDQYJKoZIhvcNAQEL BQAwgaQxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1Bh bmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4x JzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UE AwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMTAeFw0yMDAzMDUyMTEyMDlaFw0yOTEy MzAyMzU5NTlaMFcxCzAJBgNVBAYTAlBBMSQwIgYDVQQKDBtUcnVzdENvciBTeXN0 ZW1zIFMuIGRlIFIuTC4xIjAgBgNVBAMMGVRydXN0Q29yIElWIEVtYWlsIENBIC0g RzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDjwcci4DrPCr5nqqOJ gEc6NVJQvCzJoPDSoG017s4FPpiJvcP4qUDPnVIV6aAYuSPjc6KuQJKKW8SWRXlv 7kX2EyJZiW0YkP+Nd02FNWndX6Mcld1HyHAD4TzXUcx7SrETKDlVky+5pJCshoTY fr3OjRzAkotdEuAKxtULQkwXgvTCztwhSzeH9oOScQjnNUA43ZmPqK/JD58Gcz3V EEmKIml5kX+EYJpSTbFYMVjb3EWfMETr2OIkNW/OaiLGq2lQrCCXnM8hy44/xdrl rgYBE1PL2I3C55M7BoxOfOb0Y8+yEfGuTNYHpV/nOxfkA++Xhr1SVEG8EZO61+6A mEEtAgMBAAGjggF1MIIBcTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQSLtcp +k2/5f8nTlVXhHOE/1CULjAfBgNVHSMEGDAWgBTua0k8ej8N47EJt4rIqxmfczNQ 5zAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwQwTQYDVR0gBEYw RDBCBgsrBgEEAYLXfwEBCTAzMDEGCCsGAQUFBwIBFiVodHRwOi8vdHJ1c3Rjb3Iu Y29tL3Jlc291cmNlcy9jcHMucGRmMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9j cmwudHJ1c3Rjb3IuY2Evcm9vdC9jYTEuY3JsMHQGCCsGAQUFBwEBBGgwZjAjBggr BgEFBQcwAYYXaHR0cDovL29jc3AudHJ1c3Rjb3IuY2EwPwYIKwYBBQUHMAKGM2h0 dHA6Ly90cnVzdGNvci5jb20vY2VydHMvVHJ1c3RDb3JfUm9vdENlcnRfQ0ExLnBl bTANBgkqhkiG9w0BAQsFAAOCAQEASAX+NfVVoMY58O+QoAS+KJ1VCrgwiKlau615 SA0Hq1Zd91fNzu+dIajjKNEkTBe7rXuzEHK0uYXwwV5Ka34KFvFzpCp2uOa7nuEN 4cM7YmdSw4eLMzu+mYj/Ow7mlUcREG9F+Av5BL+wcerBe9ZeP07fh3S5fcVvptpc 8udYn+mRBjxzHhC8PNXnvuzgYk0u2NtM8HF1vu+8VrRHq4IPIIXc0dYU8G6/DbVX sQTTJXPgj0m+Rsx2g0Sz4dDOvMg0IwXzLYhBBGPtDpvz4KLSQVaZey6ZL5gtw8o+ TedpfbDnIrJwj1sn9gUzKks/n5efNsMST6RZTF4PmoH20K3uRA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHATCCBOmgAwIBAgIUOokaVU3hQpO4oQv6Q5usW9dMZrgwDQYJKoZIhvcNAQEN BQAwgaQxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1Bh bmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4x JzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UE AwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0yMDAzMDUyMTM1MTNaFw0yOTEy MzAyMzU5NTlaMFcxCzAJBgNVBAYTAlBBMSQwIgYDVQQKDBtUcnVzdENvciBTeXN0 ZW1zIFMuIGRlIFIuTC4xIjAgBgNVBAMMGVRydXN0Q29yIE9WIEVtYWlsIENBIC0g RzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDruMVlXXT0z7J0/EUV NG3rSbDBAeo1wHtJGmH6/wzi1m5K6QePnUcTQ2uSE38nH58VucBmPrntrM21SDqj u/LA0w5Jz9oecAKX2Vg7isBJmOSRyj+j0kBpXU4XGgV7IXesFcr8Q2rXj0KVO3kc yMU3DJr4vExn9h2wRZRzMqjBHg/bW8fxRbzGZK6t+uSm/HelPFKpF7G16BV1Wg+x A4i3ntmUqsmfVo+ZnhuxAlRI4tll7OwfRvTnw4WwdINxgKqVE219gvHz/ugjO9jQ AfnxrRQItqn9Z5Gk8Wi4DK+HmXiuIQ+PfopjsmvgudJxTDxBFnOs2SGPG0Qpjhq5 qYz/jK1+zitOId93sp8D12s4/5tIIQWB6OF0hHxSylFENsznGGkQEVt73ZvYy2tM lwwHxSfe7yccOM22cVLz/yTQNmEqGD+HTD/zttzh4M7F1it3wrKoKdLmuG6NcXbQ RTfDwVOlCAr+y6uIW1fx8uD9ACVeJ7KSM/zYGnGAArsRSAHKTuv7zbmL0fExKl/K 6TN/r4IYqR3r/lbdp/wvy3tXhKB2ZrYdKgzhcpE5B1V/n4uMpBMldvXMxwtm2+8P M/GViL6zr/wRKQnc83tnkS9NoAFupOo/4Q9Q/XQRtVVmEbrCaLdrXlQmCWSSX4YR 2K0vQfxqb2cuodZk6LelomE6hwIDAQABo4IBdTCCAXEwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUyFAxysd52n/Dcefs9WmYoNoYVy8wHwYDVR0jBBgwFoAU2f4h QG6UnrybPZx9mCAZ5YwwYrIwDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsG AQUFBwMEME0GA1UdIARGMEQwQgYLKwYBBAGC138BAQkwMzAxBggrBgEFBQcCARYl aHR0cDovL3RydXN0Y29yLmNvbS9yZXNvdXJjZXMvY3BzLnBkZjA0BgNVHR8ELTAr MCmgJ6AlhiNodHRwOi8vY3JsLnRydXN0Y29yLmNhL3Jvb3QvY2EyLmNybDB0Bggr BgEFBQcBAQRoMGYwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnRydXN0Y29yLmNh MD8GCCsGAQUFBzAChjNodHRwOi8vdHJ1c3Rjb3IuY29tL2NlcnRzL1RydXN0Q29y X1Jvb3RDZXJ0X0NBMi5wZW0wDQYJKoZIhvcNAQENBQADggIBABSCTEENpDqTqd+N 4MxNjZvBUq25/4czSxcEclgnpoRBwe3SRXt+BwbwBZzi1BtmhWRUkZZ5rRxANGyK 6/QKBYnizeBkP6KY9kE+BfOXrOKGbDW0pyZHm7UTF5rb42+526BJNxh38JMcTi/U gYwsNUarMTbN7qC5gU/eyF7H/FTwEFCyOsDJBi4ZfwlYzmd4RQORQyKtLXcXxjKm 9sw8c0Fjv3PXOMhZkIbT/LlpGO5/w3DosrL8pm0tyKyZgTk84YIji9qQudAoFu7m YsXJdm7OuOZJbeySq3XKounjyJKM5JsQjCNNjd2ttBEO8x5/lp6fUcof+r89GWaF IhBenlimIvGNkiaqEfe1QOfQHq6MRdvX/9g18NU9wNTS4C4mmmkwVny0MfBP/Ktu zw80iv/6YpPcnc4FCATjuht6m/K/Q7GRdiHmKp13IkZmyVQOhMkDWI8uxXhjNiCP JKllQPox+x7DHNM3PYG+eL3IAN8gL77u6Xo6C+RCWJMcrSi6fHFwTbyZDIi5TiBf GIFv0XRA6qkuE1dcuPjpQGE/Ts8zjV7CMDOSNSCXqP0XdiTnsulmwhQ0wNq7aaJ9 w1rrMV9daRhXJx1/GJ64bb+T5opIdDYSPK1KOnyhFEDxDkY1W3BQnO76N6oBr2dL uHZMrja1LQn96AJDhptSViwMLAO8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFCTCCA/GgAwIBAgIUKovf56gGbRis1wiRs49luaW2zVkwDQYJKoZIhvcNAQEL BQAwgaQxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1Bh bmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4x JzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UE AwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMTAeFw0yMDAzMDUyMTM5NDJaFw0yOTEy MzAyMzU5NTlaMFUxCzAJBgNVBAYTAlBBMSQwIgYDVQQKDBtUcnVzdENvciBTeXN0 ZW1zIFMuIGRlIFIuTC4xIDAeBgNVBAMMF1RydXN0Q29yIERWIFNTTCBDQSAtIEcy MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4+0aFtH0MDAbePMJkMSs TZt5ylgaiDcpcWJZZ9+63SEcJU+4uxQ7T21eppaxKMORlPfptBmrrTVEFKiqHSpu EvrzYYGiiwIu4VYnbOeADDvXKjVjRR+zyxabA23sMDzFB5SJmTjs9nKq15J/KJBm EonWBNFsp9uOMym+t+Y6Rrh/mashRirINkam/AiDdidizvoqEsWxJUWOeX/hQo8V KliK/TVReDhtIvDao3oRr6mEfEAmD8/Q2pMMGza+77F83uK8nW5ALpH97tvfKDpA In2hqH1+wRWp8ABG8S/U0OSJFsjA/Ja6M7zfhXnyZsPgW6/9gMzz/M95DIzztv6q IwIDAQABo4IBfzCCAXswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUbnfmkaQ2 RWuAssFeuiPz166OLJUwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw DgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBN BgNVHSAERjBEMEIGCysGAQQBgtd/AQEJMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly90 cnVzdGNvci5jb20vcmVzb3VyY2VzL2Nwcy5wZGYwNAYDVR0fBC0wKzApoCegJYYj aHR0cDovL2NybC50cnVzdGNvci5jYS9yb290L2NhMS5jcmwwdAYIKwYBBQUHAQEE aDBmMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC50cnVzdGNvci5jYTA/BggrBgEF BQcwAoYzaHR0cDovL3RydXN0Y29yLmNvbS9jZXJ0cy9UcnVzdENvcl9Sb290Q2Vy dF9DQTEucGVtMA0GCSqGSIb3DQEBCwUAA4IBAQBHcFle2YZwKDHesvAd7mL3tgdD nMgxtIvzn0CoTbsaHj9VlHuz8WTcVRo0km2ITLS/Rh+ecsVSdxW+519o9bJewjBU h6p3ggPmMn7n1L95g0gLDWd3ppo5nKdRuaqRX87Ig2MWdk67yZnvQ44PklnDq9O/ z1ey9g2GxE++d6spHuYVHJwx2EkwTt6JUxus5+x42l1AXXLyfoslT8WG9WjRflBG 9S2DPZW+yfCrEMvDYcF9XHGxpEubNzF+4IJ4ChIyDtHBjh5nulL6kXJdsKlZdyPo KY7M6rjyDMloL84kNMun9P3ZpBqk30UoEDxyWiym0ZERw+FR6T8ZU4HBjEQO -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHCTCCBPGgAwIBAgIUU9wiyeK+6p9NvhHmhL70TYz3QogwDQYJKoZIhvcNAQEN BQAwgaQxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1Bh bmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4x JzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UE AwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0yMDAzMDUyMTQzMDJaFw0yOTEy MzAyMzU5NTlaMFUxCzAJBgNVBAYTAlBBMSQwIgYDVQQKDBtUcnVzdENvciBTeXN0 ZW1zIFMuIGRlIFIuTC4xIDAeBgNVBAMMF1RydXN0Q29yIE9WIFNTTCBDQSAtIEcy MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtF/7DobnSBuk9jzr10wP VLCLfLoc5jqXsNQatCWPlGEEzDvI6sFdzbtO0RSe5RX9Yma7a4jCfmBFlLJ8qcqf ZLoXrW+0lfJ9zpZ5Rn35dM6RIQcE+6MWy9jbQTHNt6XUKZIFvDwHRvx5yPx2bxwb PGU1NjC2TsJAAuFcRHMB0cvqZ75gc9IBpqYDpEHn9v5LztSDrORzTONvJBbpj21H +RZG/h00cqx369hfWnuFqQGCutZ1f24rhridB347iYyUKXmIeqnVtVsHdCcLQI72 vuazjmZ0uYkJxbWFjombU3pbBXPpDv85BcvxuwMfRX86pa+yaw8t8jTSqjt64wpP VLPRKTRnxwKgJk5FImKbKAb4qegfsqhH63s6joE770R7yv0suJkzfeZRhSiSIi/k p96dJyfnSLSr2EQbHCb4uocABJcD3AtktLJJFDjRVgrFElEWaA4ImibxSj+E3FTR 037j81hP0Tav4Q1bzdArp5CvmqBCjoImvh5RxIZlXkMCn+IPDbwyJMI/QnYMdKpd bPAqCxHpna8AfyDAYJ5czfqZ3tXtO/9uDG2A2eq5FdfzHvMFUePj/AzHrhRr+2fj Iz0c1Puz+/vqAuT+hO11yKnwqeTgIsMVXKT+8U3kAqdVthE63cgKr1vZ9bGVbmst D+sQ83AgRbKREh32ghvVjEkCAwEAAaOCAX8wggF7MA8GA1UdEwEB/wQFMAMBAf8w HQYDVR0OBBYEFH6ETY6gPUahM0lv9FDLc7pGHptEMB8GA1UdIwQYMBaAFNn+IUBu lJ68mz2cfZggGeWMMGKyMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwTQYDVR0gBEYwRDBCBgsrBgEEAYLXfwEBCTAzMDEGCCsG AQUFBwIBFiVodHRwOi8vdHJ1c3Rjb3IuY29tL3Jlc291cmNlcy9jcHMucGRmMDQG A1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwudHJ1c3Rjb3IuY2Evcm9vdC9jYTIu Y3JsMHQGCCsGAQUFBwEBBGgwZjAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AudHJ1 c3Rjb3IuY2EwPwYIKwYBBQUHMAKGM2h0dHA6Ly90cnVzdGNvci5jb20vY2VydHMv VHJ1c3RDb3JfUm9vdENlcnRfQ0EyLnBlbTANBgkqhkiG9w0BAQ0FAAOCAgEATaCI L3lvYGA79q7+RBxeX/EZWN2sKXSU1qzHNAXv6LpBGxaFF9aOxRlYCeMIAX3gSdnf YBnBBP4j/+dm5z/c7NNbDzGoWqNM4BDuFKRphJX1VUK3xS7wyfm+TlUxRMwFREPp 47StOZZBhru5us/OQuo06+e0+mKxfY33T7oaX+6KTg7XlxTFMWY88b8UPcnQf05V /4eqc7xu25/o2R1lpsH+Qijn3xyyAiZIZ+yW0lpPSpwuKjkoS8nC6YUnE1blHq7d tLbdrj2PQ3Bdkv7xoy7MxJdk36jS8IueoruRSg/HV0Eo7UpuXUhCtGAxraSKhBQM 6n6C+i9IBVgAkUi5BlQynMg+CkcNjAPMziXCcJbg9oZra9tGCYf+uH2kKm/x5lb+ P397HlOZmUSQOCHriH3Wc3LavxdfuoXYawi9u0q13/Q6tq9di/7E4VarhriN1KLE xSMOFsCC8Ghka4wdqWA6c5eBueH/crZN+026VMwrHGq0J01CmYpDo9ja7ZrIZTZa 5n6zzNr9LOXZ48zFEjxKtevHrQ/PvTERzCwBG04004sULVDVSVOGnDkiKVQDhxJK k3I/PhJCRBYLncf72TKC/fiOZgle47yY+mvagAk68PCfKEGleG2nWQS/XBCoXNH8 JOAZi14KMG1GuOroMo2O+ymQxTZmCmBRVDBAICk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtDCCA5ygAwIBAgIUAyceQb0WUHBWvCALxSnJ527lUS8wDQYJKoZIhvcNAQEL BQAwVzELMAkGA1UEBhMCUEExJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4g ZGUgUi5MLjEiMCAGA1UEAwwZVHJ1c3RDb3IgSVYgRW1haWwgQ0EgLSBHMjAeFw0y MDAzMDUyMTUwMjBaFw0yOTEyMzAyMjU5NTlaMF0xCzAJBgNVBAYTAlBBMSQwIgYD VQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xKDAmBgNVBAMMH1RydXN0 Q29yIElWIEVtYWlsIENBIC0gRzIgLSBSU0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCml6/q3ABFnT4I21VCIKvikFJLQeSzUL4JDO6mnZKqq2jYPLov Sj39U9NgBX9s6VQsv+Qdc3d84XB5e86fFHX9Bd426F6An9j674hD62BOiCM47X/+ vYeXwB4NxgTXysi8GKkZ6pK1ers9HESfNmVPQQ6tD2czJCsXc0qZBOICQBuf7XVq Q+8jTUIlt5FeQioZD8zkkahG4qlOwEyKsvEGqRTSkCS8eYEDMHn4XHSDwZhG0cbH YIhj1td2CORXRE9BJpQJns45Y2nvgrU0JzXahmFWkQFxQcoSeDyKl1l9cFw3AAG3 L9xYAVKPJHFcVj4gQIhvlKeutIdtrc03lb0LAgMBAAGjggFwMIIBbDAPBgNVHRMB Af8EBTADAQH/MB0GA1UdDgQWBBTPIaxxkH5F86mRh+HxloFb21MGiDAfBgNVHSME GDAWgBQSLtcp+k2/5f8nTlVXhHOE/1CULjAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0l BAwwCgYIKwYBBQUHAwQwTQYDVR0gBEYwRDBCBgsrBgEEAYLXfwEBCTAzMDEGCCsG AQUFBwIBFiVodHRwOi8vdHJ1c3Rjb3IuY29tL3Jlc291cmNlcy9jcHMucGRmMDgG A1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly9jcmwudHJ1c3Rjb3IuY2Evc3ViL2l2LWVt YWlsLmNybDBrBggrBgEFBQcBAQRfMF0wIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3Nw LnRydXN0Y29yLmNhMDYGCCsGAQUFBzAChipodHRwOi8vdHJ1c3Rjb3IuY29tL2Nl cnRzL3N1Yi9pdi1lbWFpbC5wZW0wDQYJKoZIhvcNAQELBQADggEBAHkbBjWJd5DO Epxt2DCalJbcLmQ4rcXXU2R5UpFcJOIwbKKzQK4MPS3A5OJMJsf+XojO2m8Sy6hO jTQ+SoeNQnhLRtrPqxUydEU/b+VMtueRyakMrNVVQ4pQtEsg9aakd0RsLRNyCHCm Ypz/8e4XBXMpKTV6aHtqFi0sUD0ilZyjvZfnbDjui0LdiDrbgRHOmtgQjqbg6nbB 2zaRzEGp4L3+F2Zj4BFOvw8Ke5Jmm8QzJgSSRMGeZdDqadSDmmUj56pt0G6XAOkz w/HWg/0IYyKGVZz7JRK7+9nlyrc/9UCvratN+2HdINZ4WCfuuXvo1eQ3kGUhzei3 XPK4J184aMI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGtDCCBJygAwIBAgIUKd8+ev91BJb+Sq7jUZ78U5Jxs8cwDQYJKoZIhvcNAQEN BQAwVzELMAkGA1UEBhMCUEExJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4g ZGUgUi5MLjEiMCAGA1UEAwwZVHJ1c3RDb3IgT1YgRW1haWwgQ0EgLSBHMjAeFw0y MDAzMDUyMTUxNDVaFw0yOTEyMzAyMjU5NTlaMF0xCzAJBgNVBAYTAlBBMSQwIgYD VQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xKDAmBgNVBAMMH1RydXN0 Q29yIE9WIEVtYWlsIENBIC0gRzIgLSBSU0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDUU7/pB/FBhxHxIV+Q0YSI835tId8kERvHCPj0AV5UdrPKt1J3 gXh4XFLxg5HkLKOBCpF+FfcNgr0H2nhvkFtl3vm9VYF28rcL79fbhGrQYn+Z5tPu PT0ETjk/D/OZaJzomtq45VjWoeXMWAmlYbFkQXPLn8Cc0B0TaGN548D3elfQrjp1 4u3CGJVk53VJaW/hT7bg7Vsq79d276OldS2eLx+S2v6YfiPQhCzjyKRqCSCe0x6H WMEYZAh/YVuWpv9wpwAX5tvp99MlcpjQdqQ0u1SygrzY8eQ3e8j/opzPqyiS7/R0 q6QZxGzx6j9cjkEH5h4yhBDjS1NS/JvDWpnyzo43OaZzQkXQLL2qQ+IxgkSieWAj n0jIGwlwXePhv7JdVuIUYNRFSzqiZsseD9UtB9+ThpCdUR386ELacqhOlLTiQk1i KQavWfHfTHtLzvYL6+tf7F+Q2l5H/yn3o+MXHoVInwsRGmWiwMyl86UKCsBvrcFG /9P6CiO7WvUqmNiR3uM1tzIk4e3aqvEvB+PLWXQuwnKohfu5FknEhDaYLLCxMgSx oWoBWl/UFbU3aVGFJUxXLYRhXT0rS63K0zOxiF7SyXslMmEcQFje1c4r6EEaPcEY A1tXzwwS/2mdAZli51QtY3po75bAIJmjscgOxlImwW9rWVrIsv4JogWKZwIDAQAB o4IBcDCCAWwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUG4mXQQQjqKMc8/5x VtxbV+1cDYEwHwYDVR0jBBgwFoAUyFAxysd52n/Dcefs9WmYoNoYVy8wDgYDVR0P AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMEME0GA1UdIARGMEQwQgYLKwYB BAGC138BAQkwMzAxBggrBgEFBQcCARYlaHR0cDovL3RydXN0Y29yLmNvbS9yZXNv dXJjZXMvY3BzLnBkZjA4BgNVHR8EMTAvMC2gK6AphidodHRwOi8vY3JsLnRydXN0 Y29yLmNhL3N1Yi9vdi1lbWFpbC5jcmwwawYIKwYBBQUHAQEEXzBdMCMGCCsGAQUF BzABhhdodHRwOi8vb2NzcC50cnVzdGNvci5jYTA2BggrBgEFBQcwAoYqaHR0cDov L3RydXN0Y29yLmNvbS9jZXJ0cy9zdWIvb3YtZW1haWwucGVtMA0GCSqGSIb3DQEB DQUAA4ICAQBdBLd8jQGkQiO0VsRenHA6psdLwCLF45wm8/yRzt1vksBByy5RATfj OdzZEXC3rMe6Ll2jl4HQ4BrmcZ7aRsei7FwHfGU2ekdgtSehO+NwaMaNY0j9Sg/e FKQABrtY6gmC7X0/jbZuH9a7lvpVGLGvdMk1+NSlTlQqERjxsFVetGpiP4pzC9bQ gD9JycO9dQRCy/gfA0PO0XNsqEArjndhU1+IxwTFSbxizdFYrgh7y5nHAxnnQzFd xQ5cFz13bL4e4zhmfYTDVTTF6vCG5rxDZYr+WYUJkOFr/xZweundGzoDgW0aMG1V L9xzCIbIVuSPUDC0Ym4a4WU6wb/wSvcN/ITPKZBFIr4KNoUQNdJZGTIQwRQO+ua+ Mnk2KYtJUGa/28MEw8tBKgEyYkptzFT0gojMeO7op3UpTLuNECrecmGYVfIo69X0 Ln19AFE2L4Jvmi4P4pwF2xEbtQyTtzh7j9aw66VXP1dfHO7PTZBHjAzBimLkE1zT cO8sr56i8cM/cJErVWSomEgiNsyWqDBrfVY+fSg84VTST28yY0wkB/O2ock8VlQ5 yJn/iVzBEm1GdnklpGASffsHBPIKWaKWS4d95WCG0cJ+8RRxTazdiWILWgbbKYjk KCqkp4JGEbkmC2L753wYoSFCbiTF9OPaUD0b6ax9kscLxTZ9+ocvoA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtjCCA56gAwIBAgIUIkYvfVtKEOOpNHBTTXF6pfTWoj8wDQYJKoZIhvcNAQEL BQAwVTELMAkGA1UEBhMCUEExJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4g ZGUgUi5MLjEgMB4GA1UEAwwXVHJ1c3RDb3IgRFYgU1NMIENBIC0gRzIwHhcNMjAw MzA1MjE1NDAxWhcNMjkxMjMwMjI1OTU5WjBbMQswCQYDVQQGEwJQQTEkMCIGA1UE CgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMSYwJAYDVQQDDB1UcnVzdENv ciBEViBTU0wgQ0EgLSBHMiAtIFJTQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALEVKy+loaptP8EfBgK6wq3gxIFeDA1d319wdoSPapIKLD5Ls/V3yAsA zdK/MTGOcgHCwRB8B0G3LPhglCE0kdDSlwU25uBm4KayyAiWd2fouMJScXAy2T/n WlpUPNoVjioy7pGoliNs8taeZZ5fdg0cwkszmitHlRItZHHwi8giOekkO2pcFFmq gKrd9xXCNZjxg6GXFqlexpIVMgG0wNMSPkGy8z+8kXND9wCQ7uTBwB6rgoz4nNoq IjTjZ0iHqOwSyTR4VRZPemkQJtEXEtUeEAIRQxH4L0i8B8KdMA+2f5ue3K/RZsOy cOy3OILEDfSfPeOHSbBGg4EiSWdOHaMCAwEAAaOCAXYwggFyMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFBLsHpy0/8MkF4ue8Lxw1R4vYHRXMB8GA1UdIwQYMBaA FG535pGkNkVrgLLBXroj89eujiyVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAU BggrBgEFBQcDAQYIKwYBBQUHAwIwTQYDVR0gBEYwRDBCBgsrBgEEAYLXfwEBCTAz MDEGCCsGAQUFBwIBFiVodHRwOi8vdHJ1c3Rjb3IuY29tL3Jlc291cmNlcy9jcHMu cGRmMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudHJ1c3Rjb3IuY2Evc3Vi L2R2LXNzbC5jcmwwaQYIKwYBBQUHAQEEXTBbMCMGCCsGAQUFBzABhhdodHRwOi8v b2NzcC50cnVzdGNvci5jYTA0BggrBgEFBQcwAoYoaHR0cDovL3RydXN0Y29yLmNv bS9jZXJ0cy9zdWIvZHYtc3NsLnBlbTANBgkqhkiG9w0BAQsFAAOCAQEAjm3KMK6T 3q5XdoWxBUIB46oe3uCX+nHkTTA4lM8oVEv9Yc/wQDF43EleANUXOTd7VVzsxCQX qGgy8gharCsO9KyM6PalIG22dT3+cUgVA6uOVhROEwVzMc16DpJ+S9bNNSfB1KuZ f/6KxFKokWbEclDpKwEXnE478LE5jixUYlbJ99q5R+oHoxoNYONsgsjg4CcLxOFS UmDxsoCqXk3xaUmGhB8Ch4U2bAqOiGv0NpfR8LxyM0GjwrDNHuw8qagj1F1yOfpF b4E4xsgQxzp+nLQjdIKWsy831fXctkMqeRGVKMQoQepnb+oYM3dOGYmnNX7zATbw hwbcIuwalcXUqA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGtjCCBJ6gAwIBAgIUNgrXLJtc9UZZSWnVyPezpsnQOQowDQYJKoZIhvcNAQEN BQAwVTELMAkGA1UEBhMCUEExJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4g ZGUgUi5MLjEgMB4GA1UEAwwXVHJ1c3RDb3IgT1YgU1NMIENBIC0gRzIwHhcNMjAw MzA1MjE1NTUzWhcNMjkxMjMwMjI1OTU5WjBbMQswCQYDVQQGEwJQQTEkMCIGA1UE CgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMSYwJAYDVQQDDB1UcnVzdENv ciBPViBTU0wgQ0EgLSBHMiAtIFJTQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC AgoCggIBALyc5Csh4FoAYBR3LvWCdkZTv0ES2r5fFkskSN9xOkinkV8CezabuFQu oEnu4QLXcCK3Uef/QJ3vsc+Wavcvsg3ylPPgKxuHJ2dDLGqhGQXzwRiAwdiNopXU No6QQkhNGLDc3276WFooMLxNQ+mgesq2sNy/TDj0G5RjCYhpkDkShDMnBM9wwpz3 hOJK0yWgRgSodhy4ece1kxnMktr4YJQEr/Ad0P+cv7+DVKfEPKWDgy565i6RMzDW W67eepsRofO8Lr5WZuDW28iaSQ5U9zr49pQkLs4FJXyIKGJgv6xgXULsKJtbfy28 G51hayDS1ifiyCKgD/Jea/Z7U98i+SasoFyjKhVzAHIsd31fIKFi1xR/zCuB1bTO vybz9Nu3zJDSIVJMOoFtckHAwmEI6ALgdmZcJweecnnScdZ8WEY0iRDGdEWziLlX DRdlYvnkj/RrUzSuCoI0LxInL1Smkbv8FbCM4nsqAcYJ4NIqZmKM3J0Hyi5Ge3WX IGxIZJ3jbEOVH/3zZd2RNAXkTQC+tDdRJM2IJ5unOfGbhX1vdpeCcPBCDtL8Xak6 wPKDSQAxGl88B5vx1Hol0chPD6ZMAOzrj/5eWitRVuXns9rl+ObEY7gbTblCwvvL wlmJGlWmFSJx9VCxl21dM7UJclQFdWy6BJ4rkQHz8tJjY5Re1NdBAgMBAAGjggF2 MIIBcjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSZw8EjOKrFIHsKcXsDkNSD YlixVjAfBgNVHSMEGDAWgBR+hE2OoD1GoTNJb/RQy3O6Rh6bRDAOBgNVHQ8BAf8E BAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCME0GA1UdIARGMEQw QgYLKwYBBAGC138BAQkwMzAxBggrBgEFBQcCARYlaHR0cDovL3RydXN0Y29yLmNv bS9yZXNvdXJjZXMvY3BzLnBkZjA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3Js LnRydXN0Y29yLmNhL3N1Yi9vdi1zc2wuY3JsMGkGCCsGAQUFBwEBBF0wWzAjBggr BgEFBQcwAYYXaHR0cDovL29jc3AudHJ1c3Rjb3IuY2EwNAYIKwYBBQUHMAKGKGh0 dHA6Ly90cnVzdGNvci5jb20vY2VydHMvc3ViL292LXNzbC5wZW0wDQYJKoZIhvcN AQENBQADggIBAHVjh8acqMTiAHurxq8z6Cm/N36dXmB1uskpU0PhNa1RlCozfBhg 2JB50fQ+R213CM655QidbsSpZ6EYsN6zyu8NDPS09diXHsolMxd+HSimXvJDMEKI 1GAJwigf6R4KOyZ8Aa/Dy2lL0dxFmnyZcpDGsdQeaHZABfHlRq/7xv/khhFPFaBp I/M9NH6g0KYEQYxDzp9oJAbeEOWA7g5OfSG+ISPnuYiXO68/lOwuqkrFi3/GMnYz jOcomCQqr53sSG0hUOfu5Kk5kYjNiokAghz9ppXGFGt3yzxDOjw48RpJ0MN/GDay VFytNy/2F4o0OCXR0Uu2dXXLefXowUOOWuCPNDTXjdJ9rpbR+1f63acJN88umT++ a0b77XJB6syOB5h8sTi1ASXe2XqS4WhxOS3Yy8yMwhWoC3gcAcJbyp2xpvqCbFLo rW5JrBk9bPgIJVfzmz6V4XVX8EVOAmsJ0UT55LggeJsn0PLiBlVDL/T3Cwsv+k28 4AR1Jdw1S7RgljPduQBwCPrqWURUygwwu3dUySF+KF3YpxpMYOi/LOj1TBex5049 U3Vnm32xSpcQGVgtOo40TSvofhkfrPFEk83L+b3xgtvtMMtz0dNCvGn4KjtxfOoI CQOgzrDvFDWE+G4ko4yOED5vj0RyF/TSxnlJ6zfD7YZtTlkWnu+gwiad -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFCDCCA/CgAwIBAgIQBsk1GubwrG6wBvsMKqcyQTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMTMxMjAwMDBaFw0zMDAzMTMxMjAwMDBaMEwxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJjAkBgNVBAMTHURpZ2lDZXJ0IFNlY3Vy ZSBTaXRlIENOIENBIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA 8FvLH8zXOPwMrB5ZEdaUtfupXVj3ADIIt9uabxZnmnOJVeER4gBDBmuZ/5zvatiK LqzE05lw03rvSXjiWjAwGSZQWbxz4qUIxGxOpvypsW5tbvcnKkPG9vs2tj+u+KSK CCMA792c4rroXOBHjlQHl+ET+xnWc3nxobw7yL1vThEcBkCsLiu4BE5eETMzEplu Z5hVT31EISTkU+L2qoVPqvl2vCLKmb4iKJYHpGIm1qVGRgf54kxfhRl9rEu4k2rQ eUaJh4r5dKz1y0TFBwLIAM4nwGVc61H5S874Mt1Zw5i2kxnRymMNg5FFuCkQFIrj UlFvlDohMoBNRvbtzHQAHQIDAQABo4IBzzCCAcswHQYDVR0OBBYEFETZyEozjtNS jaeSlGEfmsilt+zLMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4G A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYD VR0TAQH/BAgwBgEB/wIBADAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0 dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNuMEAGA1UdHwQ5MDcwNaAzoDGGL2h0dHA6Ly9j cmwuZGlnaWNlcnQuY24vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMIHOBgNVHSAE gcYwgcMwgcAGBFUdIAAwgbcwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2lj ZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFueSB1c2Ugb2YgdGhpcyBDZXJ0 aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNlIG9mIHRoZSBSZWx5aW5nIFBh cnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNv bS9ycGEtdWEwDQYJKoZIhvcNAQELBQADggEBAIEbzergTPhY7dFwqeIB+fRlzYgI fo40x1uqb+sH3imvCC5V57mSVVPXwEe2hDHCpo2+zGGqot60EkVtLF0+bUpCXffc 3mzVx6ti7GX+znUK5Vh41aoNy1AUara/iWQbcUXo32BrRPmXE+kMzt3VWxQE6ybP r/l4SAcusEOmuwCTzzkTRttvWCa9VLgY5SsZ0jIj+/eRvQJRxv8x24/HrTI95OMo +cTFs6iaigj+k85GmxtbpYEJJ4M8E6AtrBQ/i6/jhVY5RssEcxn0sUEvl8Lpxnlr vyedD9l6digYDmB5jATBq8i8aaLiD7gyah3GHeziwuKmebv3CeTy44o+ORM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEjTCCA3WgAwIBAgIQAUNxaCjUej51B0V9WT7W2DANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMxMzEyMDAzNVoXDTMwMDMxMzEyMDAzNVowTzEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEpMCcGA1UEAxMgRGln aUNlcnQgU2VjdXJlIFNpdGUgRVYgQ04gQ0EgRzMwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDlRbx619l0dI7GEcikCjtz++LQ1+lqW1bkwZHjOwO/MZKG Cvgu9/IgRQOIwJaR2mP6CGz2uVqKjchxSyKFlLi8dTE1vXyBKFB75beO5pOD+N99 CZ++jDrj0ewOX6MjFm0YB7Wpq/9u7S84Vi3v0OT9JEyzGtCSCeIsA0vA2ZmCu7Ax ZNgZa9AneiClLWwQ9SRrqauvh8YCCXXiBG7/tP61DOJbZndiGZfVCk9QurYJDNy3 njZFAxQJ14klpvu0hGEuDqHcTIjB6Gxypm8xA6VRiLkUYYveOEhK6zzCnZkL9TCx FZHhxiWmNSl9jJ+XlHVOIwH34yGuQSrFDSkvjODxAgMBAAGjggFGMIIBQjAdBgNV HQ4EFgQUfods1gw6MxgUm8sePK+NEdPbSKIwHwYDVR0jBBgwFoAUsT7DaQP4v0cB 1JgmGggC72NkK8MwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAj BggrBgEFBQcwAYYXaHR0cDovL29jc3AuZGlnaWNlcnQuY24wSQYDVR0fBEIwQDA+ oDygOoY4aHR0cDovL2NybC5kaWdpY2VydC5jbi9EaWdpQ2VydEhpZ2hBc3N1cmFu Y2VFVlJvb3RDQS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEW HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEB ALK3PoMjykZ2Vo0AlCwLu3G1RMjqhH97EObR04DtfMUipEkrLmQ3Mur/aPHrAq84 7HfztoK7GqBn+xN073Gwtr/vsbKXgpqRMB9sLFfsa57MP0KSavBZDLEUp4vT73X2 pE3hfLIk4jtCjckUOawvakwECtdUxXcCnArXtNxg+dKYV8O1Xy8lvs0cMQnJ4fQp +WtZ/5lDCELdsroB+FEXu7LwUsH49LC7UvG+4UwzxVbGqWXaK90SCzJJsdZjC/ws f+B7eocYInosraC1cfDzlzaAPdXBtPxuxKLbtpA7PBvS5yDTDlSPzHJDcCDKPVj3 npRkOI3dm+zOs+AiqOkHhd8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxjCCAq6gAwIBAgIQD/qSztoqMWdgQPxaBiDAJzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMxMzEyMDA0M1oXDTMwMDMxMzEyMDA0M1owUzEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEtMCsGA1UEAxMkRGln aUNlcnQgU2VjdXJlIFNpdGUgRVYgRUNDIENOIENBIEczMFkwEwYHKoZIzj0CAQYI KoZIzj0DAQcDQgAErE19AEs2dzWefVxA5vXMNIeQL3Kksyfo06w6O04l16AEB9QH jEcOnO+/fcq+lbhh+0rTKC6QA2qP6RT6URh4/aOCAUYwggFCMB0GA1UdDgQWBBRy SmaWanRK1XGzavjksJBQeC7ypTAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALv Y2QrwzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF BwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUF BzABhhdodHRwOi8vb2NzcC5kaWdpY2VydC5jbjBJBgNVHR8EQjBAMD6gPKA6hjho dHRwOi8vY3JsLmRpZ2ljZXJ0LmNuL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9v dENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6 Ly93d3cuZGlnaWNlcnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAAe2E8e9x q04yhub22uF0DPrM4krlKEoeZG3tKbmXcIrOBSH40VXGj212nrp0095/seKyi5dI HeTvouo0FHemtpdnRuY2fWOxpeg2nfJnZkdv1f1TJmeB4qPv3ZJ/Jorjd9D0nIVj V4Xd29M8i2BoWQZq/KwliXIzG80ee0oYGM6i0Mxb1cgX7puoi94GllBgdrTHYrgr /EDBRkXMbppVEQwDr86uH8C7+OVZXYh/SjJ9yOspckFTRb/4YvWltH0jJYFVYC6W m998ZrVQxrcM2J6cfru9a0s9Hu1ZXczAiE+3EtN5oj+KPkO8ZF2yGxRtX28CD3ch AooDaTD//zQ8dQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFDDCCA/SgAwIBAgIQBR8Mft3IjbrwDFDihfQiZTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMTMxMjAwNDhaFw0zMDAzMTMxMjAwNDhaMFAxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKjAoBgNVBAMTIURpZ2lDZXJ0IFNlY3Vy ZSBTaXRlIFBybyBDTiBDQSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALqD6tXbzIpRYNzoznLbHwz+chdbruBQJ80/GqdVld/xtIvi2yIE0aPZ/awW D7yc353pX9eNysCtYMr+uLlqHxSU3DgMh+HdZG3wam+rGbO2I6l5tjxJKP5BSysG oxnL2ZnONKTiDOu5RL5JrD35R64w6FWGFx+DsKW/e3WnR80NDH+JWFFzwi/bzHFh HJ6gsaeAiWqMunCyxbejtHnPcmDs7Mca0d8tb7vqs8KbHwEjMMTfE8lLGYL2rHy3 q/uSfMUminrjr4TTgVoHhhjABA0y5f0FF8S4SNBDB9GbUrToL4nuX9AtuC65j+u/ cQ6I/T1Tdyks5seRKiFamCtMxo0CAwEAAaOCAc8wggHLMB0GA1UdDgQWBBR7o/r/ 9dUJXR75Kv+FU+2vR6jXejAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3R VTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MBIGA1UdEwEB/wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzAB hhdodHRwOi8vb2NzcC5kaWdpY2VydC5jbjBABgNVHR8EOTA3MDWgM6Axhi9odHRw Oi8vY3JsLmRpZ2ljZXJ0LmNuL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDCBzgYD VR0gBIHGMIHDMIHABgRVHSAAMIG3MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k aWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMg Q2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUgUmVseWlu ZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5kaWdpY2Vy dC5jb20vcnBhLXVhMA0GCSqGSIb3DQEBCwUAA4IBAQCFMP6Exs4uwBILlV3yCOg1 9T0GhyY1XFLHJkG/zgYmdoFZc4N0I7NIuMKEZkcaOc13Wt6QkS6GpMO3aZkXYTfl 9zpDtwdqSpL43nkCxd+nxB1A3N+9D/ZswoOUeBi0FI/fhKTh4B8sdRoVBYRJEhef 5J0LRssXrSRiYxmITdX2N2zCcIL6/17YXds2BTxvfCHDWGWnnAys4i0W5ccgQ5bt nPHVW3hEZCO9nbrAOl4swdyFTV1Q0UUG/wZRYZEkFKdpfBOjCWDDrKo1SGV1Qys8 6y96+AgqbDB91mdnxIr1MuTtHGn/Q1YE2x9OSTb2f2k0ArhFxFdcjKTfLLewG1xD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDszCCApugAwIBAgIQAm7tbyg79F8Er3c2unM51TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMTMxMjAwNTNaFw0zMDAzMTMxMjAwNTNaMFQxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxLjAsBgNVBAMTJURpZ2lDZXJ0IFNlY3Vy ZSBTaXRlIFBybyBFQ0MgQ04gQ0EgRzMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC AAQOpzOStVJjgRYLXcyjWglb72/AIGofkgEYo3zxDHcb7mhCpg3D/ILIDs1Xg3sN BlgQuQGvc52CspMJLHN8Y6p/o4IBPTCCATkwHQYDVR0OBBYEFJ0AS7KU5w1e3w/9 tBc0yLHsCZn2MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4GA1Ud DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T AQH/BAgwBgEB/wIBADAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6 Ly9vY3NwLmRpZ2ljZXJ0LmNuMEAGA1UdHwQ5MDcwNaAzoDGGL2h0dHA6Ly9jcmwu ZGlnaWNlcnQuY24vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMD0GA1UdIAQ2MDQw MgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v Q1BTMA0GCSqGSIb3DQEBCwUAA4IBAQB15MfIfjZSg9xPlf0251ejUXl5JnuMrwOT 8cWX1kOxvIdzY1LkJXe4N+oANypSxl0GjXhmzL2+Euh/6gW28K8fKa88rBm5eCkj t1SrA7QKU7o43FOktyXcpUrHuxKhQ3d8SvIsSA1raLiJivUQTtVgPL1VQ0pZkYSW zlfxUXT7fdOZsLoWfNFqlcEUUbJh5o4dQuQC6B9VbsItRYcuEt/aXusVJNM5Mm+l zM8ndeVWedlkhqys7joyTzy/+NE9Vg59hTWGjb7fEkBnxpW0IDuLAgH8nnFh/Hp8 836UYCrVb5mNAwDvbSdCWpK1b5gKrT2tqBtJTPsB6r0BJ1mH+zVe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIQCf6w1wx1BN5oUOvhiYeJ+jANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMxMzEyMDEwMFoXDTMwMDMxMzEyMDEwMFowUzEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEtMCsGA1UEAxMkRGln aUNlcnQgU2VjdXJlIFNpdGUgUHJvIEVWIENOIENBIEczMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAveLmWDpLSC5abHASt6q94wj2s//wE7PlV+h4kgqR lgbzHqtJsbDkPwXtwixrIAsMckJt+VG2v1PMj/AGTFHwuR89kBL8znwq+1h9cFmo jcuNbS+oeBEI41cSPeS5frgg+RFGIpEcHXIn0WUPYE+TiNCjYA2sVBEoGlEVE7YV /Z0tOZpeEQvuA5tMg0J4WOPmqWfcsN3F65BvHzCT8J9QdZ5h/k9vv6XhS+HIX9o/ 8F3wAT3J/YbptGphsfjrdIwseNjgl6MFpsmqRVMoOJKyP+z6nsq39ou8EQihlHts q2mBOjMcsZD5ZMSu1wHoIxW/HCNvhombdRI98lRj6UpDdwIDAQABo4IBRjCCAUIw HQYDVR0OBBYEFBZeaGe8liBi7jZM1GTD6aIo1mPCMB8GA1UdIwQYMBaAFLE+w2kD +L9HAdSYJhoIAu9jZCvDMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAzBggrBgEFBQcBAQQn MCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNuMEkGA1UdHwRC MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZGlnaWNlcnQuY24vRGlnaUNlcnRIaWdoQXNz dXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUF BwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUA A4IBAQAFF+g/iZ5Gp3StW3F1QLQtr1uSVle8uHD8UNda+97OqfzSUnymRKSBO1gr rYUqHGxohIKJlIVQfWpomgqIAM/cgO75AeVgzyUF5y1uhS4NRzYDrUhiDXaave1+ DkPXfnN/veof1Wu9HB7hVywXU5RtB7zrq+ED64AbNzxzjCQfhzIstHwpqmCH+iT0 GCcCwdNlF7WnMmNehqGjsNGz4Ow+EcmGSGhnfwIAt7XUKwbq8bAtVDGsLW90v3aC 2yRQOElRvfbwsmgZxKxOQIvmiHUTMk4sMklz+G6+qftEz3HU2pjDuZGtx45d3beE vxZMPvPk++pLe0RY2RBqoZj0UJrQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDyjCCArKgAwIBAgIQB5WZAz3ntiAVatgizPGmsjANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMxMzEyMDEwN1oXDTMwMDMxMzEyMDEwN1owVzEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzExMC8GA1UEAxMoRGln aUNlcnQgU2VjdXJlIFNpdGUgUHJvIEVWIEVDQyBDTiBDQSBHMzBZMBMGByqGSM49 AgEGCCqGSM49AwEHA0IABFyr4n71tYLBZ4yfbR3C4BecHss9+urw1qt0W1DGSNRw YsTHs1YymDGYJtcapH7sfVIOEGjHK4oRBl+zh5IqHs6jggFGMIIBQjAdBgNVHQ4E FgQU2z1NHIzVactlRHaf6bmvJEdWJu0wHwYDVR0jBBgwFoAUsT7DaQP4v0cB1Jgm GggC72NkK8MwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr BgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggr BgEFBQcwAYYXaHR0cDovL29jc3AuZGlnaWNlcnQuY24wSQYDVR0fBEIwQDA+oDyg OoY4aHR0cDovL2NybC5kaWdpY2VydC5jbi9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VF VlJvb3RDQS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEBALw1 MqA721+QRK5BcSFoYr9bduynchpuyP3Zc87sGUrYW7BsCTY3dHwcZr8gDryFk39x bCKKnBVEfyMzBrVwMkAhTk8DsS3VdJ8Y5p8m2ZEvHzRxqKmrDWPr9kTtcSM6Q9Ks p2Beviqx6nhDPchcJn8ccXN91Uhf0fe0ZmFckZjt7yP/T1o7FcnZg/8X9mcuOOJX dugOQKG1+cJZfNhILczK0CysFJQqLg/C31oEcQIjGf1afDF7COHmzObr8QE4suzU DPPAU/4tkImnwtsYUmbKz7mlg8DfffTT95B1otbQC19aA803yIGhLnJ+3MBIFuqr bfEYxgo4ZOuulPHeuVc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE/jCCA+agAwIBAgIQClM80TYUE3dN68AmBPfI6TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMTMxMjAxMTJaFw0zMDAzMTMxMjAxMTJaMEIxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHDAaBgNVBAMTE1RoYXd0ZSBSU0EgQ04g Q0EgRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyxZ3VUnJ5+DbQ eXPgvKXtiTyXNfbW2IIuyUTH5x7+8YNi4zIpJ9nCAher46uQwUKbQzcCLz8RYrX0 +mjfIPg8ZSCvem1Tx9Si0/BGGHyaYlB+3HGNxR4T1MLQXJ2+pRsRWPEVDZyJ9LDt djZhOOrbLwFbLGVoaNgdpZIbjneGuTqUYbO/CUomCE3MOQqEqGR0fzrShXHBm3Ni ipoqjmra0YcmcXd0IoYOA0xpF/f12E2V586QqXX7UFVA+alf6a102BYyFFa/aH2+ 3AwA3/SAhO6htn/Sn6YMnWyV5g85lkc/5o+XUVFopFtivcCoii+a/LC+VDRrd5HZ JQGzRCeRAgMBAAGjggHPMIIByzAdBgNVHQ4EFgQU/2dd3IjNPLphj0vTKvBOkA0z cG0wHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG AQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Au ZGlnaWNlcnQuY24wQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL2NybC5kaWdpY2Vy dC5jbi9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwgc4GA1UdIASBxjCBwzCBwAYE VR0gADCBtzAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ UzCBigYIKwYBBQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNv bnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVt ZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL3JwYS11YTAN BgkqhkiG9w0BAQsFAAOCAQEAWRivCd1UrRlTWr3lSEVugjRCD6y8RVC7tD+wqdPD hk23AwbjNDzfuwf0tgn+sD7OeAcCQzJMr9RpgEPJGCky0OE0VW77+YsDKj3YjlYq KRg2UdtNKheKyCG4zl6mpF6FAHpGWy0AMz0mhwzFmcUXqWMP23vbbH2PCbSyM8Jw dK6xz+ljlNa+kEOgZv6FqIYFqD6ZExferSBFqhQzU8VOukZd7cktlW8+TtYTc9KL VcW0lHK8AMX07CUvCS07u3gEtivg9vZQl7Njk+83vvET/Em+poZle2wjoXO0ofDn 88EHxRz7HRtnfJgNdILqAN93w0KTdnUy0XNvFkeo2mtUrg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgIQAs4VS4Y6TvS9eF4z+Vq5njANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMTMxMjAxMTlaFw0zMDAzMTMxMjAxMTlaMEIxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHDAaBgNVBAMTE1RoYXd0ZSBFQ0MgQ04g Q0EgRzIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQOZOUenKHK6osgKV3RJQTH UY3ClV0wNaPg/DGcBXSo4xFtOjcB4kpVKUsVQ88x6mu3PZhYwgZ03z5LTi9eCZ5J o4IBPTCCATkwHQYDVR0OBBYEFGJN/s/Hk0iW5JEiBnCbpl0ktWBXMB8GA1UdIwQY MBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAzBggr BgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNu MEAGA1UdHwQ5MDcwNaAzoDGGL2h0dHA6Ly9jcmwuZGlnaWNlcnQuY24vRGlnaUNl cnRHbG9iYWxSb290Q0EuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUF BwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUA A4IBAQBsAFUjekwwDFML01JqQjzuISUguM7okr/IIDRiODEs9RU8y8XgpercPGU9 BYX562S4qgkSMnIejRWZWUS7+0T7bVmk2yVxcjNhqiqx8iBOF3V3TuLAyUsUw0Qt 0Gm3h7TE7mrrkwgU+MMmjmVpEYD21bMUva8sWqHCUiCly1PEsCNCpeD9cLHPKBkK QMDdodVF9Bh7gAOIbJC1P28yrZMDlU2OTqvVC1cu+oMH0OWj/5sdis66OtzrmqgI hg4ioDFc0kwNDQn9OlAwm36pQZkPpeO7HaswLsireRySL/MLVVYktxev7tXwIiU7 wzkx/HDfJdt47kbO1mWgPP1Z0C/l -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEgzCCA2ugAwIBAgIQBTr4fojD0b9ZW0LcEhiNpzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMxMzEyMDEyNVoXDTMwMDMxMzEyMDEyNVowRTEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEfMB0GA1UEAxMWVGhh d3RlIEVWIFJTQSBDTiBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMdMqP4p7kEjIsTjJXYnwHgh8wmN8kPwqqx+yVPLa0y6IxXS/lZ5ZVY0qJX9 Hh1GZpDsoD7r65vP3HPvDq6eq2HHO5M512+Y3d3cJDmwj8hnMFsQpI05okzbdR1F JFcX4sLGvNRNApuHz/0dz9QRjFWuQjf6E6QGnmJlxa+CxbhATF+M5tJRALqDer9q YBKrEmwoLhRu2baG0Ymw9rShx4kYRqLXiCkYT2t/bUIXSfaasMRSqdULXT8OiSRr ykSm+qWRGn/Ou8SvUkExJL8H0hHscET4e3ldtS1SNLIkBPlqqszLgePokjuOER2N X2/Df+3rOI7LnIf/kam1IU66N5sCAwEAAaOCAUYwggFCMB0GA1UdDgQWBBRD2sOo peBrukaEZ06zNKNe2cyx7zAfBgNVHSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2Qr wzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MBIGA1UdEwEB/wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzAB hhdodHRwOi8vb2NzcC5kaWdpY2VydC5jbjBJBgNVHR8EQjBAMD6gPKA6hjhodHRw Oi8vY3JsLmRpZ2ljZXJ0LmNuL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENB LmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93 d3cuZGlnaWNlcnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEAaGfrSgxDcAUu BEgHZEFBaWLodkHxRT+kvU+BOf/11lcfp8hbZTUucNHEQLSozTW0oKpIwwcHTDD/ kE67nLmk0rjKPyhmJKzR3LQVFiwvTho6w1I4YuUBxi2x606Zqsa8BuUu2zWJ46R+ 0f+Xm43p78VZKCVV7j+2SkugqB2As/NW3JRyznNUGNsuiY6GMMLSsH3F/FJA/1Cx h+QqRdpCUPh9SPAx+bJv5UdMd1LdpOJmtz4lpOjdy/7SKR696PX+P03nmdVWsftD S2muLt3QcQbhCIwB+FlGjinWW79HA2YjfzMdgHNRYUZPJl13h+QoiMuRIYtR/A34 vK49nk/hQg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQA7fGFnyirY496hbH2lGmAjANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMxMzEyMDEzMVoXDTMwMDMxMzEyMDEzMVowRTEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEfMB0GA1UEAxMWVGhh d3RlIEVWIEVDQyBDTiBDQSBHMjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPDZ AhPaMm/aeEtym/GJUpNwKQXJPMBgQIeKb0o53tq1P8IlwemwZueQLB5zDsB5T7Sp 3uyHgb2bJwQdGh00q3CjggFGMIIBQjAdBgNVHQ4EFgQUNH4tvv7Tg10Nb7SvoVi1 4f4iuyowHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDgYDVR0PAQH/ BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8E CDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29j c3AuZGlnaWNlcnQuY24wSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2NybC5kaWdp Y2VydC5jbi9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwPQYDVR0g BDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0 LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEBACdVKkXtzGTX+xUQP5z6oS3a62Is bVcXi3AH3DV6xe3RukovoX4TbNrbJgFIOgaorLhK7J/aJPqlCdz2zImauRhYCxqq XQo6Wx/w9uzLZ/eiHz3oey6ylDLWdwgqqe5SrKVZMmgwd8tQmhK2AZZpU0z04XbF fR1xKlJnxRG2KsDDqU+s3Jj2+qDsiYK7ObKbQCdmKi+AiaM4BSYXCxrAk9XPtqmD yO++DhzgVc7GT9GfTUuTmkk4ikkx/C4efZSvHHynvk/1rP4aumjmGp5FuyETVcgg vMVpQm8deJl3zaG1IZlRWQMkian82e9sminnY7ZZ6Q15LjsOLr+hON0iseI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFTCCA/2gAwIBAgIQA2eKFk1ifRDufW4CDsceeTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMTMxMjAxMzlaFw0zMDAzMTMxMjAxMzlaMFkxCzAJBgNVBAYTAkNO MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSMwIQYDVQQD ExpUcnVzdEFzaWEgT1YgVExTIFBybyBDQSBHMzCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBANIdr+aGJ7xGU+BAfTfOUHsO0kLHBXDi/Z2olNgF62fOlJGp TLXMkequ82wMpQf8nUi8PBEimKStocB7pjqJ7twveLDo18h/8S54zoHCsfZu5n52 ukwtxEmMVSULZfRW0pVPXfijRsFfC8zivC/AfNmqdgTnojfKvlmm9I0VgsN5O5fl 9rZOcyO0W70rbsi6GTFsMZDRDFvK+EzfrgFNFnS+qrSekesCJrOPprOsq5XHx1vc eLJ4gzgwC+OmEowmv9QWv0/+MWJkQyRJesFfUlxcugsmMD3pl0zRz2KInrjK3pKJ OdjY6ccX2t/IXl3L4IQuc5V7HOpuazis3ZpdSuUCAwEAAaOCAc8wggHLMB0GA1Ud DgQWBBSa2Q0QycRfTDLS5/AbrUqmLSU71DAfBgNVHSMEGDAWgBQD3lA1VtFMu2bw o+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMG CCsGAQUFBzABhhdodHRwOi8vb2NzcC5kaWdpY2VydC5jbjBABgNVHR8EOTA3MDWg M6Axhi9odHRwOi8vY3JsLmRpZ2ljZXJ0LmNuL0RpZ2lDZXJ0R2xvYmFsUm9vdENB LmNybDCBzgYDVR0gBIHGMIHDMIHABgRVHSAAMIG3MCgGCCsGAQUFBwIBFhxodHRw czovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNl IG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0 aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3 dy5kaWdpY2VydC5jb20vcnBhLXVhMA0GCSqGSIb3DQEBCwUAA4IBAQA6MKUuIRRC njqOPc/jhrB5VDcrzHRabp5haEvpZV+SR2M+wQwjOZ/tf7KhEYXbBB7eUQpPUQ3I TRg1CdjGT3li2VC2xsVLESbBGka34nyvLrICPQ6Mm7vNqi+GjRtuZ1CT3YU7NpaJ Ku34y7zkAtWKlefLL1w3nn0g+XkxC2uV5PD7Ua/Q/kcYgxjj83klxKts0YCqhaVJ 0QYbsDS14J48CGoR7Xf1JwbZ9coUtB5FII6zUFuvH9p0PogH7LgAlOM+9zNyUZo+ WmIUJ04rZbJ/hHuXgOteHENYtzqr6PGRYRuAFdUPOZSsM8S6Dgp04VKe7OcD281Q H/Na2A0CL0NW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQDxmszflM/X/yG0I7qFVpMjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMTMxMjAxNDZaFw0zMDAzMTMxMjAxNDZaMF0xCzAJBgNVBAYTAkNO MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMScwJQYDVQQD Ex5UcnVzdEFzaWEgRUNDIE9WIFRMUyBQcm8gQ0EgRzMwWTATBgcqhkjOPQIBBggq hkjOPQMBBwNCAAQP3jr+1TqhWdA8vJGOg4G1/sQ50Zgst6j6LvJViMu1dG/Nn4AS /KG/3z/gZGqeeVWe2leql4S3ZAp+3PgSF3dAo4IBPTCCATkwHQYDVR0OBBYEFFu2 CfG9fE6qMJeYs/8nQkL5ENV5MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5ey PdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwEgYDVR0TAQH/BAgwBgEB/wIBADAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUH MAGGF2h0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNuMEAGA1UdHwQ5MDcwNaAzoDGGL2h0 dHA6Ly9jcmwuZGlnaWNlcnQuY24vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMD0G A1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdp Y2VydC5jb20vQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQCepMQamuUSUPdxbebn2MiD crxoa9949Y5eB99rbsF3yctyYpgMNd8wlDidbLVNIZ8Q/DgLjB5uD432K45N3aLF CsQgaJS2tE5WrL82KdKFLWEFkgWWg3S31eoHcnrX0l2QQynst8nyeZu3AL847SP2 GWvSXB5GMhJeCg+iA1plBoGK5u7UWXeytgs09IBcqxma5Nuj7VOPas8dEY7uPzw6 +/1iHZ2faxQ9EO88fpBRLzqNoKspCaZAYhegGzZh/HrMzo/S9H0wCUONM7eT8mgm fD2ikPvHRCDvoM23ZPJE8yH+gBYvoiWonIVdko6oX73unaHYM1Ott9dPCOfBi+4L -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIElzCCA3+gAwIBAgIQCcxeird29+KxR6+87sF+sTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMxMzEyMDE1MVoXDTMwMDMxMzEyMDE1MVowWTEL MAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIElu Yy4xIzAhBgNVBAMTGlRydXN0QXNpYSBFViBUTFMgUHJvIENBIEczMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoGZKVEgqko3R3EsjuqKpH4qJ/M+uAf56 Cb2HgtE7cM93vmTWvVfTXT9BZcg7OatP+LZVpJOgJdIIwOgVSAwAguHT3xLRImGB vdl7BKE1bIcZ7PofYqj0MhcTC77LAiUtgDffXe8M3xNM7oybG4uKo1yNbqB3nWEH Sfxw3oZEIy5gOIF/sBYz5YQN0Wn7eu/DG3pyB659h972CmYPTyOA1mL7U7noXcgy fGjvmQVRuRRX+4sxqG+2GURQUbn8le+tYwUnjXSr4feH/hMmvtJ+j8oiOkWE08mn 4FOlV2HXHCj6BFd2UO34/Wv6oMtTkUrdU2IuAJGFeToT719CtjcqYQIDAQABo4IB RjCCAUIwHQYDVR0OBBYEFKU2WjxmE3oGNnIsHYRtfEMPh1ADMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAU BggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAzBggrBgEF BQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNuMEkG A1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuZGlnaWNlcnQuY24vRGlnaUNlcnRI aWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgG CCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA0GCSqGSIb3 DQEBCwUAA4IBAQAKYIfUik5lg2D2JQbnzFMsHulGj7360VwfBwyFbNdy1EL4PbDe JxjJzhOFOd5NmUxFi+t6g+7urU+qAxuBSZMqIIOUTdNi6xxfE0flY6dhHtG4VsUA heGpyjVOgTFjISBLSk5qzQbOEyX9HVPG5CrlpVghfexDI5fXYSmMJrZqUo+mt+aV 3co939KuRBcE/RoRNmRl7rOBROgpuLFSpCrbfaxIiTlTl75lqq4vbulCOSl34spO tRZfbG74YmMhzUCNLIztINON0/s01PaxrcIgaroQHLuVVnsEV68sR8ncr6SKlf/f dZgHOCq2uEQgEm0TuKYVflSJ5FtK/lVEmR+J -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID0DCCArigAwIBAgIQCN4LodXTTTRzZ9sm7AooQTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDMxMzEyMDE1N1oXDTMwMDMxMzEyMDE1N1owXTEL MAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIElu Yy4xJzAlBgNVBAMTHlRydXN0QXNpYSBFQ0MgRVYgVExTIFBybyBDQSBHMzBZMBMG ByqGSM49AgEGCCqGSM49AwEHA0IABAX+UXlU7qCTdzvO2S4v8OvP+SI7VixP+yCg pThqxJao4e9xIMLbIiGAXSTiBWYLPdxUdEOvJnQN6Fxl4a1BbgWjggFGMIIBQjAd BgNVHQ4EFgQUyGi0kdsF1zMrIYlWf9suYMJhwVAwHwYDVR0jBBgwFoAUsT7DaQP4 v0cB1JgmGggC72NkK8MwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcw JTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZGlnaWNlcnQuY24wSQYDVR0fBEIw QDA+oDygOoY4aHR0cDovL2NybC5kaWdpY2VydC5jbi9EaWdpQ2VydEhpZ2hBc3N1 cmFuY2VFVlJvb3RDQS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQAD ggEBAFWP3d5sQ6WQ/wNNnxkK+zl5OD54yNTKrMrnDjHvuxt1UjZWGZs7s9luCN54 /iB+r9v6ToxH8If5SggzdEhgw41rRNZZdGqabkPc7YxQ/dG5+qaO/t1braD7Y6nf Bek+xEIdXrA8OO8KRA2oakroIYbhXNwx5xC3mFF4AejGDW/UY4XMNoWJf0b0tfB7 3Z8hQn31jIA0jV5e+KuYonv6PK9iAO5coJ4n6qwZ1DYw3LPGRpSHO6t06i94ij+1 /8sVnBrMmClpkN0v03qd/SgleCazj/f/O0ErgAtx65E97ZKNDj6LXbr14aSHNTOH HNssrRZKpOebHRRepIgmA8De6nE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQBfFKs8nt70Spz7EYtFBxJTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDAzMTMxMjE0MTlaFw0zMDAzMTMxMjE0MTlaMFAxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKjAoBgNVBAMTIURpZ2lDZXJ0IFNlY3Vy ZSBTaXRlIEVDQyBDTiBDQSBHMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBmu 6gqnrcj0xWh8JUkXSuqi1ca9xiWR1u1QH0VLUL5SLYSfOD+1zWZmfGBVe16719OE QxNy6Mr6WVQz6F10fjCjggE9MIIBOTAdBgNVHQ4EFgQUGrVojGwJUfdHATvhk+3l ABbPu5UwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/ BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8E CDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29j c3AuZGlnaWNlcnQuY24wQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL2NybC5kaWdp Y2VydC5jbi9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwPQYDVR0gBDYwNDAyBgRV HSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMw DQYJKoZIhvcNAQELBQADggEBAAqotWRWfzzjRoIYMNXRxFxo0YgTM076s/nj+BRA Ogf06eWQCOVu89vV4J+d2EdtmavD9PgPM2dalCe7k1TUYw9NQD/E6iCWbEmgRRC8 MWH27i7d3qWWlcSqN0a1PNHxGdfOVf57ao4/M0T5hWdQnjUegKBDra03q/4LtP2l TTD2KYPpZmsluNKpCdQcR7IVqg2XQTAJdRquiyxY23nZHybvhBJmbeSLJc0EMUbG 2BRRuEbSW2Lu1IELnhp83EqAHEEt+w5Q9B3sKWqbdlPTNvTtyNMiTrHDO2nhN4f2 BCyB5j5fwrWTkKA8wqQzAXykhgRDVRlfgQDXZ8oVIy/KP2I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFbzCCA1egAwIBAgIUZem81T55HfIt/+tezCvHpViNCIMwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0yMDAzMTYxOTM5NDJaFw0z MDAzMTQxOTM5NDJaMEoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKDA5EaWdpQ2VydCwg SW5jLjEiMCAGA1UEAwwZRGlnaUNlcnQgUVYgRVYgVExTIElDQSBHMTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhwn6I+pGrJsnisnzP7EU5cFN9UT5XF auA13F3jHeUUZmBOcMSOJEhx/e7oeVScTnmKpe7t7uey7lIIC9DWFmP8klbtLBgL 0jY4MPlCkVyxUIhZ73EHCPqDCX9bo+rMB6C758/tKZOPcoWRixQypPwoC4cXNOOk ntqFPRxFSZoBdTDNlAmkAQJCRsXGCEC5pZ0JqzGcAA0/Pw1fB8lSPAti3trubYmd aaPFAKzGK7vsexxpuSUKO0opNkFWbLdHZ8jkr86R80oo1vhURJXWNeMS74ws5nbt Ll9sJTDW33MQPS0/JO3xYI7bQcW3K1sPSERa4BahqgOJvEXMk1eWRcUCAwEAAaOC AU0wggFJMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU7edvdlq/YOxJ W8ald7tyFnGbxD0wOgYIKwYBBQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8v b2NzcC5xdW92YWRpc2dsb2JhbC5jb20wSwYDVR0gBEQwQjAHBgVngQwBATA3Bglg hkgBhv1sAgEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t L0NQUzAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwOwYDVR0fBDQwMjAw oC6gLIYqaHR0cDovL2NybC5xdW92YWRpc2dsb2JhbC5jb20vcXZyY2EyZzMuY3Js MB0GA1UdDgQWBBQTL6fobnFR9uIMmEeDnn+deHk08zAOBgNVHQ8BAf8EBAMCAYYw DQYJKoZIhvcNAQELBQADggIBAEoOxze3kgnR39LX8M63EjiNxx0LThZHROqYqev6 5ox/c5NNitk8/ODA8osdPpvnUBAlmE0+gqBvnTBRPVrJFd9bOr5BK8z6Os9/U0ed c3UINkWLS05B7ChC9s6Zw1Vd/WlW08TQJ80GpvAIbEKcg8EO/DXPniHxC4cMtv1T jtNeh98XiVgQXHL1FY+u/l413J8C4utKi4ZOQeCJDqvlSDzRsOi+tHsXrCJxnMWN 2QBgMGgdPW37zwf0EffoH0Gee3pTgg7I5SzmvBq0t5xRDfv4N0OdM/sN1mc5f3o7 0YCd9WXhyDCV5W2O8QIbrd42CK5k1rlM6gXwOyDmYY5CVAl1QeXEeRfDk/zNjU/1 +LnH/Dv88VcZhODYq+VGbyM8bpNr0v95PY3yaH4kzpWGqWAN5i9LosfcaqRPmyL4 PcKTQwcA9AVTjITExFua/QtGrXLPvMVxR248G9IQpJMxP3JEGkjlKCenmc29r2u1 KE4TeCs2xxjR1PusTfX91bBW3YAoAPDTRQKZjolegLUY44j3uKSzAdhMEbZQhovH Lraqx1WjTayTuq1Vuakcia5shmgFVSNcE+NVgLEIe32oTOm/G6Kd1lcm9C4Ph1Cg nfDuqohZrk76kJTk8poAY5aFCQHhVzbpSw3zooMGjjvWnkG+/DC6SZM8rKoOdKiB cy+N -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFbTCCA1WgAwIBAgIUcVIORg5UrvMi45+sFsDpelG9lXIwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0yMDAzMTYxOTQyMjJaFw0z MDAzMTQxOTQyMjJaMEcxCzAJBgNVBAYTAlVTMRcwFQYDVQQKDA5EaWdpQ2VydCwg SW5jLjEfMB0GA1UEAwwWRGlnaUNlcnQgUVYgVExTIElDQSBHMTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAOiCO+RS/VMMfgdhTV/n0zjv0bdaASpcpHq9 RYMcrQpwC+uXp3lGW8VnzkhmN/4hcNtThu0QLfG945sLlkhJGjrrDtA6HYBsfb2z Y/6E38cVXeFDIWi4bQc3lJJ33kkAxq6NLHyfqkde6vPvyiyJz+InxFQXnVH3tdnp GXtjXlgYciTDG0+atl9maYtNEKtZgsNlmsFuEQgrppt8FptTZ11rfvb7hpgjUxsr oSCw6zE8oBlCrAcR8LztpEupk8/C7Mt6bVqnJNE1p+6lYzViSLMztNbjPkatvhYe 04KkeaMEtHvIk1NhmFWHZgBf1mJDPY3/U3uPM3rVcScNrqiO9ocCAwEAAaOCAU4w ggFKMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU7edvdlq/YOxJW8al d7tyFnGbxD0wOgYIKwYBBQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2Nz cC5xdW92YWRpc2dsb2JhbC5jb20wTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAo BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwB AgIwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMDsGA1UdHwQ0MDIwMKAu oCyGKmh0dHA6Ly9jcmwucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMmczLmNybDAd BgNVHQ4EFgQUyGA9Ed0GVhDgqaHI+LFwKudMTGkwDgYDVR0PAQH/BAQDAgGGMA0G CSqGSIb3DQEBCwUAA4ICAQBZgHP9sZEa0Ju495m8z2/7mecXaPm/lLp4BiluRfNP UL+S7AS6wa9Y4CIqq8e9qrxvamlG7fDysfPPXD63cxD5vzexhHB+nBYYyQhZR13N GW9oxxQT0EXfJCjakagQ9/OwWwZa3XDzpT7ZTtax2bzPcfMDjxSzknfipfsrdFsd qFNPmor5KR4hg1LY1MyAcc0qKrlSAuieius+COIIIohvEuUZi7eJdHAiXwAXfcio mzGOGxClcthjnf663bdmknCdcOrd/hD4diCAZ3BzpbT+S9oUKMpPRvWS4am1jDnr JjjDHEnB0jN+8qn7I6N7hsMCQMr3AlOt/z2iDbc0Ha8HbcetVRkyGOLrHd3UsPi3 iGaoLZTbpoUmJxWVVRexMO1nJKcVY6+dbkAq1mEWNuAbWGBlndGpZ6b4fXTQ1a8H d8XtnPryadjQ0nfEO6yppXuaXGUkNrc1QjVag1D4byZ0T1uaTQq1wJL6QDQc0z6A gXGljtphIh4UHU4BhfiV9mhaJPnUnzNzqCS9JP3GvVRJRIIgC2DLHF7QRrskPtyT r88pIpd3XmzrbBZ+qMFz92urVSiWM0puULGgCngPPGw2qUDgoTcu7sbQnpdn2nqJ kpLSfmEQvk/Uy2QdSbvzcu6Y+VutQikwLpCdErACFvAQbVM9ZebjwCox5Pt7QwDf nQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGVTCCBD2gAwIBAgIRAJ9bB84uVlF/Q6X4MOWX/PMwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDMyMDAwMDAwMFoXDTM4MDExODIzNTk1OVowYDELMAkGA1UEBhMCR0IxGDAWBgNV BAoTD1NlY3RpZ28gTGltaXRlZDE3MDUGA1UEAxMuU2VjdGlnbyBQYXJ0bmVycyAt IFNlcnZlciBBdXRoZW50aWNhdGlvbiAtIFJTQTCCAaIwDQYJKoZIhvcNAQEBBQAD ggGPADCCAYoCggGBAJQ+UeGSUt5O1oBImyuPeKfuZJD0bjRijTXqpfHbxc8DsxY8 RbrE+/hw1k7kN+cBxYyuNKBdjgfUEawRVNMvcHFX4nPF3niUVVDbjwI2LaTuahmT k8oNwnabkZ31763aXvD9mYWyGIwXHY+8ysUEuytcm/sxXbS3sOVGIOMyZK/NyRDl Wolema6u/AOPuOS+f1GGJsvMf4eODambohYFyUxQI/cRsNeExkHW+fdmR8bPv5qx LaqLErKw9lU9yDYvUzOnI4WCDi7jfzMTpFAdGF1R6b24YqCPM/nCZyrtXEhh08uZ Q1FX4s9LSnlMMUBoZF5JFXSSYCiSrbUXQ585uBKExelW3Lw+xH+ufApmxOXRZU8D 1pVbJ5HPvBeJ1Lo8ZzrD+2LEdTHnAhRp/Qci2oonZKfW4PT6n7Pqsf2q/F/IQHKM 0Xh4HpLlb3F0PszlnIxINvwzXIyjXh1vqZHhlYkfbQRrqOMlFDj/ieZZI6JmR8Ea a07YIVxtgyaRvtTsNQIDAQABo4IBXzCCAVswHwYDVR0jBBgwFoAUU3m/WqorSs9U gOHYm8Cd8rIDZsswHQYDVR0OBBYEFNY6En8H2HXyLCOW8rSWunrvJIZyMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjARBgNVHSAECjAIMAYGBFUdIAAwUAYDVR0fBEkwRzBFoEOg QYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmlj YXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA6BggrBgEFBQcwAoYu aHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFBQUNBLmNydDAl BggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0B AQwFAAOCAgEAWfUARrkY5hZF1Uhze0pO7Uyr/+33IxtRWSAUsa3mC3gqsEncs15r WTHuhUEq5F2CDh4SIYRETlsqQzge9zYnC9TB1q7jo6H/5J11928vDY8RqBHzr5mr OS8SO8899HNdI+9UqADUlaDSpQEnujfJ3soQV9swUpr96FbZ7l8UCxH8h/g5r0BQ g1LkwvB/WYggCNJD9DwrIP0/gfSSF+SV4/RCNPgPZ8/vcM6azjeJvOfnSdmFh5I5 McJ8hlADMhwSmP7UjXoeFd5thmk+zzEl/LlRaVGR9Y5TDNBYea5VbvGcgR9qLYFo tiILipoSiB5gVylPj+0DoTcZ+KzfgKEOk1vbQVe36IYOg24DWEwoqaDLR74vePpc 8/BRJxfluPS7q4hUy+sZLr+A2upqetQ2S5FOv+mNbiZwKX6aZRDe0rEvrX/3O5kk q3SVBiOsWIH2ujR56sg8HZr8llk+EFbM7/g0U9k6m+7rstIFn2td7Wh5w5n6343F 961baLzO6y0MOOtRkl98L3ot2MMFzRqiXMV+wIqJQCl3+ImqjGTmh2m4uhgBSeiJ z+Q/Hez7YUX14DUKtPeIlzGJWxCqCM1ZK/txDIP4yL40fEAw+ILl7TyRTwqEyC8h gK1LkFenz+SH3M1exJIsNY1aSzIirfq3w0AesyFxrUo0t8PE6+g2+Ek= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhTCCAwygAwIBAgIRAMB4zx9FIUBtUTa3E38vWKowCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDMy MDAwMDAwMFoXDTM4MDExODIzNTk1OVowYDELMAkGA1UEBhMCR0IxGDAWBgNVBAoT D1NlY3RpZ28gTGltaXRlZDE3MDUGA1UEAxMuU2VjdGlnbyBQYXJ0bmVycyAtIFNl cnZlciBBdXRoZW50aWNhdGlvbiAtIEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA BGEFYWQ2Dtc+3FHJR8KCZW60rUnjoC1LWFip+JX5nkrcX3fXC8wiMrnb+nkXAq5E Sjg2I39ftvEg4Bd/kbuHgFPsnbh1UEwOewtT/gtmYnJbCo4QZj2j1xijqKOT7K9r nKOCAV8wggFbMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1Ud DgQWBBTTupl7PH0N45BBsBb6xiEjdlr7SjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0T AQH/BAgwBgEB/wIBATAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEQYD VR0gBAowCDAGBgRVHSAAMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl cnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy bDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RFQ0NBQUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6 Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDZwAwZAIwSz2AjDCpljmd rAs+Vfp9Wzdvd5ccYhmwScKzOoOQtWcjaX92tkbixA5Vyt2gWAPIAjBSzyudq9sz tR+FzzjBP1wEeLieizVZtlxhbZLbZanFWbhpwlK7tO2gKsm1CJUX8hw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDlTCCAxygAwIBAgIQY/EmOxR5MZsYGXoQxhBgADAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwMzIw MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjBxMQswCQYDVQQGEwJHQjEYMBYGA1UEChMP U2VjdGlnbyBMaW1pdGVkMUgwRgYDVQQDEz9TZWN0aWdvIFBhcnRuZXJzIC0gQ2xp ZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBTZWN1cmUgRW1haWwgLSBFQ0MwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAASxsdH8tMxgx68JxSUQ5VCZLkZp8JyKhf/OAKF8pOJd t2inBHp6yYUrHGGvbvdC+zwPuCYfQfv/pdl3KMfyWARKaUFreqcbp98WP5HumQQZ fVR7RvBk6LF4aKrUq7wXew2jggFfMIIBWzAfBgNVHSMEGDAWgBQ64QmG1M8ZwpZ2 dEl23OA1xmNjmjAdBgNVHQ4EFgQUpnTuy4EUW6TrG3cuI62/ycSWuaQwDgYDVR0P AQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0lBBYwFAYIKwYBBQUH AwIGCCsGAQUFBwMEMBEGA1UdIAQKMAgwBgYEVR0gADBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUFBzAChi5o dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQUFBQ0EuY3J0MCUG CCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMD A2cAMGQCMFkQAkxh3LUjcMVgXoehdsC4IbPRmlO7ir9ibEDMyKDXjEUAJqhEm89p wLM93ndXbAIwKny/Zl824atSh6b/pEScK3qGg1DIMD0MI/fK0wvsZL6VqOcPAbwr /8/zXIAVlY8o -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGZjCCBE6gAwIBAgIRAO6oLzpx2hTEy7KSDuhPO5owDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDMyMDAwMDAwMFoXDTM4MDExODIzNTk1OVowcTELMAkGA1UEBhMCR0IxGDAWBgNV BAoTD1NlY3RpZ28gTGltaXRlZDFIMEYGA1UEAxM/U2VjdGlnbyBQYXJ0bmVycyAt IENsaWVudCBBdXRoZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIC0gUlNBMIIB ojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAy4IQgzC0EDTDY2vyUgBuKiXT fjbxhZPCa9g2gO/gYrBlaRv6OX6MKroBFJhan/17ywuvRAGhmxV0nive63SMxwCi ZRulW7thln1glXz6iwsNBkYdTV2mEOf5k7HgMc2B8ziycO9fdV70/D0N4Ydkx0q1 sj2YiRWqbrwTP+OOCEE0qJh6z4tuJ7NUGSV2oSwLf51Vw2G6jo7+sivylJ9jT1xY 4hudPsgLxw0wPMltsGArJ3felwm6W3UALnjnsLSqFDm/GAnzcVeQvBRTVqUny248 3cc4OCPwPU+1M6f6/XJ1OQnz1BRGA+k8x3WpPjJCsutb2liA0R8gsWkVBYAA8kGS IWhal+c+n8mwsZjbRpF80XE9LFeE8g6PX/jAxtlffFAg49VkvVkbe/7GkguWcwnk wc0gldmdkv9sek1ruAdd27A5wUkx0Jq2Y/l8hHh61/ryviY8zEaXCiM/dzrM/51+ DSXfmnbwJZjZ0H9UY8MOFyFwexqwDKAIIUhaqGKbAgMBAAGjggFfMIIBWzAfBgNV HSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUT85OsK0GOArc bRSmrGjH3mmJf1MwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQEw HQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBEGA1UdIAQKMAgwBgYEVR0g ADBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEE ZTBjMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRy dXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1 c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBRb/VgRRxwDr4v9umcCRnmeOwZGGUB ow89wOAQ0ypHHXFw1UMdwbhoUFLBWBBVfGRAnR6ltOAXmNW1mvOpo7Fs/wWJwNoH Xx3Wpy1EW55CCd0kbWDwX71WQqU4hbUUyxQNkHijcEX/rPOPn6R91uYMoO9rh8it GVNaRjCSzp6bR67NjYYMODHAzetgFTTuLTfbS0GgGxtL1HtVx8dc4zeS8r/Xvqp9 Lm1TsM7tZtWwQak7j5D9fEr73SkPkT6yuvXtPP+8PqrEJ/kwJmSH5PxvwdXAbn1r FbRTDVN85kYOyVuEoVZVCd2N82Gbr3kjiClgV9YNlSgef7gSX/e6LQHieRMEUba8 GWtTpw63hdH7hnMipEAhcDcM2kAomG9jBmrkJBM1JmqXT2AH//mFNh0gj6JTfxVD CTz6xZlEpGN7kl5KnPI5Gcsjt0pRn9eQBoR0eK9kQ9mvE44CDIyKGb334qMgXHxC GFn3Dly2v3dc3okuRVdoxdji4xVxzZRgL8HtAZM+uP0B5i1BI2A573Oi+AP+CNn6 StXysq9C8/c4GUkR0aLGCOV6dvys0JjRIzxdby27fd9U7MhvgyoYuLx5JWm5LhgT OoHiqjXzOTbs536cKW9sYej7dy6OVkk5w+3q1C660vvTICmzdASoqXR7VNXzNM65 Vbxs+wWdc6xmsQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFeDCCBGCgAwIBAgIQDm0uI4Rl7wmY/8qVcvvvXTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwMzI1MTIwMzI2WhcNMjUwMzI1MTIwMzI2WjBFMQswCQYDVQQG EwJKUDEbMBkGA1UEChMSWklQQUlSIFRva3lvLCBLLksuMRkwFwYDVQQDExBaSVBB SVItUHVibGljLUNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzOat +etF6essm9U1oSL7cPoOWDsNYWkGwoqrQ32+k/fad1bWOCI39vM1vlYnwCSbrnCL wxLeDPQoDuCPApWsXGbiBOgeHtWXuAK2dRvOSd913Z3AdXnuGbZs21AMcXEI01JM N6RvtvI38HppUjguTX3oOyNsXpcTN80H3VOR8P+NnmcVetSDoD62lMbuuBekmENp xpXIJpEYKM0DD5qwnSXj9Um6ZpjmBV/EBQlr5qZb2mc6o7GGR4kl8xxG3ieo8vc+ +2WpMwNr8HdxflW+EXPSukvoI8rCnqXkU7Pv8QI65lEkEv5fxUa1m18USB7ZeIlc 6rSR/QL3OfwdLB1WRQIDAQABo4ICQjCCAj4wHQYDVR0OBBYEFMzJbGiNjGuBsBJj vQUlFdP/37HyMB8GA1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWXNqfWMA4GA1Ud DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwEgYDVR0T AQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6 Ly9vY3NwLmRpZ2ljZXJ0LmNvbTCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2Ny bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNybDA6oDig NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v dEcyLmNybDCB0wYDVR0gBIHLMIHIMIHFBglghkgBhv1sBQIwgbcwKAYIKwYBBQUH AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4M fEFueSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRh bmNlIG9mIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0 dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwKQYDVR0RBCIwIKQeMBwxGjAY BgNVBAMTEURpZ2lDZXJ0UEtJLTMtMTYyMA0GCSqGSIb3DQEBCwUAA4IBAQAHExeA QET1JLI7hBgf/HzsZX4EyHIy9n5YqtCvqy7gW4wnmo9NXL/ppUy6i7l7Xtgrr2Ny BHBHfhwfIM2KTePV/3XH8XJTg2GkGw4S5dIPZbONidrL4IBVTCa84GRrVmVQTo+6 w0LQlWIfpQwPa89vZ7hxqsYE2WN9iML5/yGkjrEgMg+Pwd69PmskMMO1K5hW/Un6 4b6engEOqBaH02sFp2sA+mHnHoRelzFLghWJLIeYTmbmdKYSBgN2vfjm/vIT/FEV QeQFc3MXHiMoLZ35D6RdMabdIF7djkNzbO5dLw/RgyrH5/O3vSqEoz9y8RsIrF61 K1NAZLzVgbdfmpz+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFojCCBIqgAwIBAgIQCdsXKYjK2TzSdDTgNMqemDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwMzI1MTIwMzI5WhcNMzAwMzI1MTIwMzI5WjBvMQswCQYDVQQG EwJVUzEtMCsGA1UEChMkVGhvbXNvbiBSZXV0ZXJzIFNwZWNpYWwgU2VydmljZXMg TExDMTEwLwYDVQQDEyhUaG9tc29uIFJldXRlcnMgU3BlY2lhbCBTZXJ2aWNlcyBD QSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq9gaqdzY2wM5 WOcNb2iuLwS5KyaVFAIQfAPV5Vq3SUGVejSPUO+W1bzZeAQ8lOSFPvpxEMT+FUA7 dZ/gUWejIGiP0LwTmw1FDaa78beG/z/PL78E5oouwnlwovw4f7V5FftP/ZdJntz9 GRMzfHVkxgZzK1kBL+whzpC5Qyq3HFqBYuysPwqHckmwas85sXr16DyMHuPZN4BS JfSeJfmoQw0jtDGCApZHsLmPSHt+zZoprkoeCOoYNLmgxagvfxg1cNE5Old4SoFV dsDU4W/DIy6U2oJCSuE4m2t5VgfCFLtcUFEPYHM/kXw2N7RTSkZ1bp2ryN6n2y/b RtkkqPmsnQIDAQABo4ICQjCCAj4wHQYDVR0OBBYEFNc9XVzt3o149Ju5W3K8fEWH tRnWMB8GA1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWXNqfWMA4GA1UdDwEB/wQE AwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwEgYDVR0TAQH/BAgw BgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw LmRpZ2ljZXJ0LmNvbTCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDMuZGln aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNybDA6oDigNoY0aHR0 cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNy bDCB0wYDVR0gBIHLMIHIMIHFBglghkgBhv1sBQIwgbcwKAYIKwYBBQUHAgEWHGh0 dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFueSB1 c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNlIG9m IHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBzOi8v d3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwKQYDVR0RBCIwIKQeMBwxGjAYBgNVBAMT EURpZ2lDZXJ0UEtJLTMtMTY0MA0GCSqGSIb3DQEBCwUAA4IBAQCM1zF5+k6nNKf7 XE6q+LkdDoZWbx32RwgShn/HKYXegI+OIsAtOD4FzSDR/lmXo4+x5nd4sPVY/HeL ZsfVnxsihE08g3ShggnBs26iPj9+BtXqqbJ//Rb6HE6cbKmBdjJeb1J9zYUuVYPW acanaQOOcQpebvXEKW6sdUYbsrEnumt9V40OGW3OOCtUs+gWqFqwd1LcQtLiw52T M/CWGkICAs2WiAKNZPIDyaKfiSOJcshydr0IZ6MO69cy16f6XsPCkgiaKoS1Xt4l kVYQ6pUsyrc0HpUw8k4sa5eBhIyDBm6kl9JeiVIkQhaq3po+PE/T1b/sO9YcKo3Z 8kQPmsa3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFXTCCBEWgAwIBAgIQAU05p3K1/6qTdSe9iTGzJDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwMzI1MTIzNTE0WhcNMzAwMzI1MTIzNTE0WjBMMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSYwJAYDVQQDEx1EaWdpQ2VydCBB c3N1cmVkIElEIFRMUyBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMsmaq8lNtgD32xrD/O5iyTS41E6DNbjOroPrpldPbLcej26k5F435sOvy7V o/Nj41o/01b7JE3K3lzlCiGcFCEUWhpeAOJVS8MZzungyHCigG4idbvVS2wlNwBU vTXRzELysP9L4y/V9mKEIXelGGhnejPv1emYkboEBbv5tXfMR8Q98LOgxZ9d+ART 0lGPbKehn/otZgGGr+kFKhlAfnyzKWBwbSmTi9YuMO2YQ2qqDnERXMSSuMwoDawC kCAOX7PwxrYQGvkaq185ZbXuoVPmbU4wpuxYIzLDW0BNg6n86cxAE41rHL61LCQu 34hhwzU9mnQEb6q2/FnaC75heW8CAwEAAaOCAiAwggIcMB0GA1UdDgQWBBQA70HD Tsm9Lmt1hd9gGLxDPAoR6DAfBgNVHSMEGDAWgBTOw0q5mVXyuNtgv6l+vVa1lzan 1jAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC MBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAB hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgYEGA1UdHwR6MHgwOqA4oDaGNGh0 dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5j cmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy ZWRJRFJvb3RHMi5jcmwwgdwGA1UdIASB1DCB0TCBxQYJYIZIAYb9bAIBMIG3MCgG CCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEF BQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMg YWNjZXB0YW5jZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRl ZCBhdCBodHRwczovL3d3dy5kaWdpY2VydC5jb20vcnBhLXVhMAcGBWeBDAEBMA0G CSqGSIb3DQEBCwUAA4IBAQBWtVBKtsdRNmvKabfUzrvOuaDrP8eI089v+NxIjf3m oW1lr/8y1vc2USHEBfcREmq7G8MoCb6MiaLtE8KHIwB8lt+L3pqujVVrpAquN+Rm ErCAlUG69/l7jrImug86kNAhRHOY+UNUIYPs3Fz4pneUceNOma/MWpFz1q+eiBss ELD+fxAGLnHjGGitbM3XsLgQSRb+VtolXGmig8HlBC4d0xmwOp4iGmwMEP1dtZq7 XQ4/tZEDIqTiPJDpCor/nAUJUFEAmjrKYG0JcVDj34xwRdhsVmXaQXAMF+eBYkWx 3YoLlZcZqJEPZP+mjQjJQiRjCo3Nb+DKWJWGH7kJWoIK -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwzCCA6ugAwIBAgIRAJrwahLNLOB6BLBEUu8LVIEwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDQwMTAwMDAwMFoXDTMwMDQwMTIzNTk1OVowPzELMAkGA1UEBhMCQ04xFDASBgNV BAoTC0JhaWR1LCBJbmMuMRowGAYDVQQDExFCYWlkdSwgSW5jLiBPViBDQTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKhq7CvNLkZvJYki92h8FQNKzcDN LTOLUMER05FwwE3t3xtKE7aMzPFL0QGhQsofWdZRgjsbSikhkbdH8SsmCtYrBXKA 2dr1OyCdUkc/EJBJseB2lcGpK9MAxVzuQ3aMwC9HEFuK+a0qEiyJAcQ9QPIwCXfF h4zTjDb3DBPKVOxVzay7Nsf8/PPGIixonns+NqRrxwpuYWdD42s7Qq95ZCZNxtco kTGGUIj6MVzKAHpwWQzueE4dczzHUqOqmUOK96O4x1LRgb7gW+M6rSEIW3/Klu6W 4ysZb1u6s8zxAxX4kBOXYppkFO6reapz/tAv5jFZT3jAto6M0jtGjJEgFc8CAwEA AaOCAW4wggFqMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1Ud DgQWBBQ3gXHH6PSDAlDMx7cTjMDlhJV32DAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYD VR0gBBQwEjAGBgRVHSAAMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BBhj9odHRw Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1 dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8v Y3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYI KwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEM BQADggIBACpDyWxqbXnIT+meN6nVfE1lIlUf0GErrKJFuWaAISFv+/DMox/v0R1g 6QvC8DGpo5hUAdO4Hb4E+q0fLg8iJgBldImIMXCPo9aDmpCZfiHDCDRvBOPcsufd nZzhWUhis4YnaI5uxKws0UDIJpl8/rwtNRx8/7aDi2rwNYKpkDp2E3qa4RDesp0+ AdPsgT/yjwABbksqh98jpNy2911LpG8LAyEoqsCzO7GZ2JguKoDxpnq9t08KwWAr VQ214WMSCEP60W9NdFZXS7zyWB0HcL7p+fs2/e3pleQm0WX8OYHpLzg3jioAh8DG vBbHKcr+m0yP2utw31M26G1EQBLZJRJMkXWcyZowELNMD72dSQGj11hRW9LtgRaT P0mnbZ1g33OmwV8LvWBo7U6GYbwWgxqmeIu3WUGusfA8o/z8rJ3dlxmH4kEQ6Vff vJpFDgi/1Rru2rn9Uhbi0cQoe9lFEgJAeKsKqQM2U60ClmAwqtqqDHo7TIlIPjSl tTV1ZmpKliFf4mmn/rZkHy9Y0nJRZRSGKEVxVE7aoBtchdM9C37XvBjL+xNGDOVC WtPFoUquRC+aoV43ZvpgjlOPBfjDhR9aY8Q3zbKRPQFDmtmZ9C8SaVmfSO81IaBX 3d4zpdzi/nXE6VlRpH9FcuslcbSXi8XiOCCFUM5Y/WIFrcoyhFuP -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEfDCCA2SgAwIBAgIRAMgg4L6eNeCxmyCeeRyzYhswDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yMDA0MDEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaMFUxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExp bWl0ZWQxLDAqBgNVBAMTI1NlY3RpZ28gU0hBLTI1NiBEViBTZWN1cmUgU2VydmVy IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqkLSwI1+KQBSTZjn rGq4hFW3nrB403nU1+Ywh3d7LJlRs+zGdWiL/qI5dLnreHxNI6IDrN++ANqtHDk9 2k8ETW2UASZAblUXHe1Rpf4LppPKXmfrO1lovP/yR1KyuGjo3G/pWTGzEinzRoBB X0EsOgoo9umn7fhbh+71/SiPcFX2v//qsVgvT83TV/6CTj7cDXum0U1WZR0G3oF5 RHZmrVHC7lVfS0jYNM9azcQ7TzX4HMk8ssw+zW7IhIwTlcx6bnB6x3H+8GftAGql byS7wM24IomEeLswQgsobA9WRYQcbvINJiz+XeVdHw+5xWJWkVIpjkokQjY2oWm4 HBG8fwIDAQABo4IBHzCCARswHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9Aw pLQwHQYDVR0OBBYEFGZSuGUuqrTyQXsKdP+YwgNo586AMA4GA1UdDwEB/wQEAwIB hjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQIBMEMGA1UdHwQ8MDowOKA2 oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmljYXRlU2Vydmlj ZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au Y29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBqUWCzcno0B+RcHhp+RJ85 /rET65L8RtDmYjTeJwfrs6g1BW3D2iUadhabWS8npNhcZQDubjbr6FNVplp4WOgR iN5jGss1Nh3Q0I1LYr5Z6ZgvFeNE/OqZXpe96xCdBGl4wcNWFEdzAizQDs0BSZmk +1XWycJ4lE3p5hJVR7wfUG+Sy0OVHBH+E4C97sCcZ+hMZb7Yi6QjElFyx/aIfhH1 1dCG5TajVtkhg/6q5v5k3/Re0v1mJm2q2C0qJDx8Z+3eZ1wK2pdLppqHwL+l5hRO 84A6Ezt8uB0vIXdUd5onnMYyc1GZV0eTzSOWcjNOezXCJeZ4ScSObJJc1GHfcWKb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqDCCA5CgAwIBAgIRANK3WrigvXoSZbq1sLZSg+IwDQYJKoZIhvcNAQELBQAw gYExCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMScwJQYD VQQDEx5DT01PRE8gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwNDAxMDAw MDAwWhcNMzAxMjMxMjM1OTU5WjBXMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2Vj dGlnbyBMaW1pdGVkMS4wLAYDVQQDEyVTZWN0aWdvIFNIQS0yNTYgRVYgU2VjdXJl IFNlcnZlciBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhJOi 9mDOLI5TSxgy2ihEPeKXm9QtT9H9DRriLeXp7zVt3fDZgOnV5qlJnS8NFEZz6SQl tr8xtktrNsVAabB1HjR1+CkUKxvYaythc/RhZQa5K+h2SceX+tdqs8FuHLubV7+q cf2ZZTzr8WisBiB1Rl+FVRiQm6WRPyiKjbNF/qgVkDPO0dEyQrz02b3MIrTWHeZU FcvI0C6PcG8H+Y+Fd+kaWRfv2TiTqZvPsgcq7eP8adem/VwLGZaGY7kLZUdXnJOU 7p/jboTPgh5R6BRcW+E/z+oCGipl6ct7dkVbcXrWwl4g3420UiTtGxeChVqMOyB0 dA+S5uB/syiwUvfCfQIDAQABo4IBQjCCAT4wHwYDVR0jBBgwFoAUC1jli8ZMFTek QKkwqSG+RzZaVv8wHQYDVR0OBBYEFOLlVQe8wbyvEPbp5MnbAnocF4Y5MA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjA4BgNVHSAEMTAvMC0GBFUdIAAwJTAjBggrBgEFBQcCARYX aHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDov L2NybC5jb21vZG9jYS5jb20vQ09NT0RPQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5j cmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21v ZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEBADP27KFhy56aOOiSFPzdMDHM61Ca QB9X5v/8Tc2ef8C1LvyJSOTO5dGukoNqxUYh8jsPnUB3ZyyMWZ/UPQegsS5XIRRo HrtBGY5o6OMKkUxhHgfselKLv/eCNEX4pAK30n+XrULoiW2aYazhoUS1Aawe7Z9e yzfLFkYN73wJZWwWoiIyW9cm2nRFVyZL1Vcr/sHsCECJKYaF/Wyf3G3PRxiUVMvs J5dviPleBsZ24r8+WwWG5/dU3XUFBKfaG4DwYqNhgk2hKbM9A1MrPp04WNSnwyNd Q2LUGiRq8fP2Y259IXrhrUvcGFOeFA10BV/ObLVzvBD2NSXsR74SBxQMBrM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEfDCCA2SgAwIBAgIRAONaE0BUjAMEn7ijP6lKhlkwDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yMDA0MDEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaMFUxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExp bWl0ZWQxLDAqBgNVBAMTI1NlY3RpZ28gU0hBLTI1NiBPViBTZWN1cmUgU2VydmVy IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi9dODoyvqLHqOEKa wSaFcZSx5GgQevkRrBqO4pG7ltn9o2EGVPYBpptGyyL7RgG9YHsn0Tx4mII5/zYe zr4+53e7r6OER4SGnbewxrv6JOqPHgAc9IMsq33U4WXc94i84Gji1cgCOLURvs8M YeARz9Aii5vbzZ8NOoWI3B/ChCWXhfRbMEbVKZyYHGUMrdrA+Z98TX68oGrTnMud ClRFed0clGXMVIciR6x9q9diGGE3R9DjAMQtNVHLbFVXipE15UQZ9oXc05UCuZVH /V7lMHPIggJDfytAGfdiT0j6ECcckgjh3NixqKK0fHvh9B+mmxq65RF5i6bWR+2a i4bB9wIDAQABo4IBHzCCARswHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9Aw pLQwHQYDVR0OBBYEFGIVH4kWOBheNOv63IYHEIrU7VZqMA4GA1UdDwEB/wQEAwIB hjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQICMEMGA1UdHwQ8MDowOKA2 oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmljYXRlU2Vydmlj ZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au Y29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBAtvap35qabbNChxinBt6s g5LK9P+jkQ3YR0HMQMHhVzF3tSy20wNPEjID9A+QkihaH5yPychlVHHna0zC9/rq ad4NSMIZwgt54S4zLUETFVZd19qME7jjXgXm/BYgxbJwD9f5G20cl0wKNYxSuid7 TUZLOY/jGhI4mJz8y9ZKgIbrdeNu/okqENE5Gbvi7GjeQr2ntVWOrwpOYD29s+nT PuVM+2ztJlmerETMQlOChGtDv3ruE/fbDFpQQxR3zpbg+9Dk+RllyF3e87X7Wt2X qSfL95/8DfmzvZuiSsWScoa4Hdm/fc1GOxmV5CiNuRlsXhynP3rimEGdlAKJJQvE -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEmTCCA4GgAwIBAgIRAOevSvR8tqm/q00QCVq7xrkwDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yMDA0MDEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaMFUxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExp bWl0ZWQxLDAqBgNVBAMTI1NlY3RpZ28gU0hBLTI1NiBFViBTZWN1cmUgU2VydmVy IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvBGkUq59/askCsp2 SA7hF4NIwwAegIMr1WzPHrdC1kFEGb24eUnvI+AVsjc8KzoewphkH8r5tbVLkgmV LVxMPEeXFqaZry9mh0doOxOKN9PPKIUqUr4LjQhlWrwhrSlGXXnwVvsivVV/yWAh KlFuk1oYk1y6qXkP39HmX+bmo+QocMJelemCrEMXeM1945PY/s6oTy6tSP8LuK3w bEvEFaFwjVGK7zRDbvgLwrCRgNS9NyeelC6+pnWMxsyT+VjWuziMXFuJhafs18vv l71flWJDoyCXcrVsK5veEccIEwV5SG3cvuVAe94FcpgeHjEr1BM5m4TDmmQlmTfS IEAWzQIDAQABo4IBPDCCATgwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9Aw pLQwHQYDVR0OBBYEFAHblKhitGAIU5X21Kge+/YEo0aqMA4GA1UdDwEB/wQEAwIB hjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjA4BgNVHSAEMTAvMC0GBFUdIAAwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9z ZWN0aWdvLmNvbS9DUFMwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI hvcNAQELBQADggEBAKGQtIOP+c8LC3Sw6wWKQKXbgDB8BOpdO1sHugBSWlgB9NrC Au07YHkVahqwdeCHgoZ0StjeFuQOvqOTQoVE9h5MdlmUiLvWUeSDa4y9/puC5hU1 6Twy/UWOwQidmVL/MI6eV9BhcwFjLvNhjFQMDP3VvAyT9XGVJhNP/TV+ffCh3Ppi hM2xyohIU7oTT/843EEmcOnx9aQF9Rvrpu0Z4dwYbCHpYEy8LFQCgy5U6VVcxshi VBZYF3Sx7e+8ZX6JHBHP4QATiEqNoo6YbJkShr1tXv+ckRBTN+gL8DqncUtDRpsK Q5UXGuMaRl5UmH9M16MyhD7QBEDxdlzkd40wuBY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEijCCA3KgAwIBAgIQPXLCWcdPRWSkgGXiMC8syDANBgkqhkiG9w0BAQsFADCB gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0yMDA0MDEwMDAw MDBaFw0zMDEyMzEyMzU5NTlaMFcxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0 aWdvIExpbWl0ZWQxLjAsBgNVBAMTJVNlY3RpZ28gU0hBLTI1NiBPViBTZWN1cmUg U2VydmVyIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDY/P2S JGjrFxNghY8LKNmjtgwcZ76/0/t5f47nSl24GwWWptIW4WOlby/Ess/ArF8cIOl1 2vNXblRWEzlGXbiHWDlPDihXI3idqkTxQW71VkWg8LFypui9kwZPl8by6Ulh79kl vg1fnJONX2VEZmpSEx/xXT5vxX7+dCzdLgdcqXAimlKF6PJIfZLJg/Hsk8xhQwl7 8ENgeuaOCr/BJCX7uv4IfYw8StQhAsqlwS5jxlz3ogBDMYVtmSAtBbEYRG3Hbqvp /chQNqL2wYs9N0CUT7DnBp6B03tDWta+7nOTWt00ynOi4FOCCuplkl585Tk2KzGf n640nGbYcfalJx2LAgMBAAGjggElMIIBITAfBgNVHSMEGDAWgBQLWOWLxkwVN6RA qTCpIb5HNlpW/zAdBgNVHQ4EFgQUA/chrsFvGa20c1IEGLqfPzO1bqYwDgYDVR0P AQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMBsGA1UdIAQUMBIwBgYEVR0gADAIBgZngQwBAgIwSQYDVR0f BEIwQDA+oDygOoY4aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RPQ2VydGlm aWNhdGlvbkF1dGhvcml0eS5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAB hhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEBALzj X3LdXUiIE3vjOKMAI/WlihwUCYShRPWRiBWSNNx74ZzGXSf9F0CE/PG+t1pqlLGn sEfoBZ7i//IMBazAZRQrDbrH7pFyVzXyPRHHiISy58OgkSFyPYLeFOpnOZ1Jjby8 TzFw8qCwmTT6k7moB/2vSUbadujgaMdlON+VFQ6U/qAhjZyKOatuEcDTo8vpYoLs d7qyaCMPTk6PQ4BtzeB48aZ5I3qsof46UhDz4TX9mPGN0Ww2KkfZ6wy1wNjwsRhU SrV0/CMvRbD2Otdw7HWwgviaTz6B4ltazeFdaWlytzX9VshinbYLahlX5IfnDsLi 12rLf2TvGIVViSPEKaA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3zCCA8egAwIBAgIQK0iO2JjLvnCPoVuzATCqMzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw NDAxMDAwMDAwWhcNMzAwNDAxMjM1OTU5WjA/MQswCQYDVQQGEwJDTjEUMBIGA1UE ChMLQmFpZHUsIEluYy4xGjAYBgNVBAMTEUJhaWR1LCBJbmMuIEVWIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAilOL9CnmSZqn5RCw7u4xDOcAgx3x CsDRCtUrhphJddSVzihJ2rN2bii0332/NywxAyemMOKiKfcmKV21A+7wvx/bIQ67 RTTHHDYCpKtVIusMd6M6+YTHeQRd8Ia33XzVlJ2Ot8DqqcupGPMPxnCi8fI6T3n/ nx0uvpgt8JWa3FAlo8+RUAj1OiAf+hDrSBGzg4rU5iFOz4GYjl/zZQpQqsTaL45G FRMWfulagfNchHTdi/MVUl/X/DwxsBaPZ+Mrkx1zoYeFGHmo2nr3wCKCL6lLWev7 xNnyWzKihgzzloghYfgeo2mBmjQoLEE8ZwMeT8/CKgobqmBUs9jPMbGCCwIDAQAB o4IBizCCAYcwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0O BBYEFIUahTNItySfI6RVWGsy4uO93Ub2MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4BgNV HSAEMTAvMC0GBFUdIAAwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNv bS9DUFMwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29t L1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUF BwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VT RVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2Nz cC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBT2CsjI+brJsAVXEB/ lvSfQWIsSVU77TRMQNPoxFtVmWBUpOMAvJv1plZX4bkX4ixZKcgF3osxoBqZRLOd KAjZhjll3tMm+cVXke6fj7GSmn97XpH/ZMn4Hu+ldm7tzjll+Z4yPnBUMblC37/L yEgDkAEBPu0gEq1V3DKQP/yhgg28HxSlwPfH16yORIDLrGy0qCbn/wJ3Ax6NLbzk 13xZBf+WMsKBYYn+A6aXFK4vQz29d+tGQ9kk5nTorQAI8AKi3TNTooDYWevc/MhU c6qXNckuDlb4DonRZfZw6NbykI+wYxPWbVCEAEG83gVBD+ymh4TaoQfsylVzlh3/ 8+q8wqok+FdohfPNnqGlGqmua7VQlbym0+OabQWjsck4ID2OGNtIUL/ZT+q+4X6C zPS+ociaq0w2h+dsosZJa653tTCerDBH5iHG9jMja7aE5ncId73HcdKn+2E7YZOr kJZ9zuNXxDUwCJ8B9D6xJGGSYdLYtasSvW2WeO0cv0LvU6kzZMRUAyeZ8Z5xTTYA Jxn8ZLIkpRDga86Qr49ve2SjnirlALGmK62Hs6wyHKkEcShohtKCR74+7Fi9AG2r zrt6iFDy+WGZExGnlAC65ZGlKX3okLbQRL172C60jjimysQguSSeWa5vrZYhVZIc iESJ8q8BOmhJo6nvO8e5sINrYw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwjCCA6qgAwIBAgIQR0LTUZ6/FDR8L12t5TfdEjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw NDAxMDAwMDAwWhcNMzAwNDAxMjM1OTU5WjA/MQswCQYDVQQGEwJDTjEUMBIGA1UE ChMLQmFpZHUsIEluYy4xGjAYBgNVBAMTEUJhaWR1LCBJbmMuIERWIENBMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzlMpUY9l4tMZQl4gonqZdwqqtz+u 8fblX1F44zjaP25ttZ0suqg9akJ7WXHndl2M0ICkFJ5R4qqdx6TVZ6+1XvBF3Zr4 FjIiMKIqxFMMGb96vHN+sshhGcJKUyAO7AmdIR2FRwhUTz3pQnne/uLUzJnYmYhx 8Ti7M1iJ1scXQgV5Tx/rnFAufnFHMNon1Ia3Jor2aWfncHdMCGA+Mj3vjY7DCa4V p+j65xckWgmmOjWtp/zAl8Z7g3Fccr1Ki/MgMqeBY4ZukbTYVr9K85FoV7bNnkyg rnVTaJChmo1ZGg1XL8Y0pqxqEsAYywOaBdbRSaG8Vo5ae82MOc5itI7K+QIDAQAB o4IBbjCCAWowHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0O BBYEFN89SAdm+eCRW3ixqtc8WTAXO02FMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNV HSAEFDASMAYGBFUdIAAwCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6 Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0 aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9j cnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggr BgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwF AAOCAgEAaCp581xitsN4IWCA1WE/vUpve/v59Ik8cusF9YjOjrnalqIZd/r3lgPk cRwH1TJsLUCKg88X3e6nacp1nPl8p8Hg+pXVeyX2cbyagcFT6pJD8ph0xsFZBzc+ YiNeePfSTu+4LdfStir4gstY/j/qz1IzhMt7rtASC5nPHktneU365PIb/cErc8ls XFogAesi/vHY680PlmXY/ve8njJq1ZigKeWQoHevFc/L16a2cahZP5KU3DudpKjM RlajM2Rmvn211740s/G+fxDZV97OkP8p/80cSnLIIK9SnOem0W8DwzhvQdnIIPZh Y+XxMIk9sIr0IpP8PdRHu0IrTsTE/8AE2NfwZwngLtAofnQFg6U6+FqrwYE7zDFx 0UvUFurX9y5Wy9eZjcP8Os+futiqlWwlrW8xscTN/vSOmCcaW4B1cvHFbn4hdJn4 ERE4D+2dVaY/yxMAd8de24dpIbTxu+/yJOBijPFv5ahISRTWyV/n2C4yMdmANEi2 /igiLvlx3rH2Jx6dEdxf9xjlguvXugXHr2dW3tMruSWjr/v93gojRIwZ+bOJKctc FrhpYYv0mJKhB9oa8EXROpAsAlhllaAsuGAgpku2IN2G9nbdn5QokiE+Th3u/k80 IhGYkrKef0RI4xtz0m9ZbUr9Rpi0B+G3PuZoym2EzdKTVZIyEsk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEizCCA3OgAwIBAgIRANTyYjaVwp7MRvGOgusBIEcwDQYJKoZIhvcNAQELBQAw gYExCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMScwJQYD VQQDEx5DT01PRE8gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwNDAxMDAw MDAwWhcNMzAxMjMxMjM1OTU5WjBXMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2Vj dGlnbyBMaW1pdGVkMS4wLAYDVQQDEyVTZWN0aWdvIFNIQS0yNTYgRFYgU2VjdXJl IFNlcnZlciBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgq7X NvVu+Su1Vy+7sRvOsO5y7hQtaF6ai2BGpNpHHDzfBz5nnBf4xFbiYFttV/GljF2m YCUslYY8SYTsgrdQz12jS2+cOnR+l/AoPNYB/gJoR4oanUwV1NvCs+NzjJM2BoqT t8UD7orQEU8GdfiIT2Y5n1JmW/8K+fU/3DNmg18zeyWBfAZF83ygMITvBjPN0Ck6 mEb7qk4BcTrnupgkV4JWAk3trMetKf07x3o30fDLkhlDle9j793XMcZI07YubW4g 4YgY/82iXdFHTkNcWghhGeZ+0BZjyTt52M7xu0g8ctWhpyQ65sxiz20pbGKX1Qpr Skl+6VgJB8cUHlmSXQIDAQABo4IBJTCCASEwHwYDVR0jBBgwFoAUC1jli8ZMFTek QKkwqSG+RzZaVv8wHQYDVR0OBBYEFDRS6q8JOsN3UZGZh5VAI8WeAlHSMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQIBMEkGA1Ud HwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET0NlcnRp ZmljYXRpb25BdXRob3JpdHkuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcw AYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAF Q53AnA5nC2Ja+b8KjLjinod3LaiBWHm8PFM8lZ5kI8GbCgM96wwr03ODiXZ/1eUU Hx6C1fKHR8e6FlIOmBa7Pq39PLp4r2Z3N7kW6s9IzIoLtOkK4xGMDLjroLf7OQvM s/K0bEtRyLSrHnqdRSeJ/Ap8/UspkWG/7+wrSXY1XQ822ZxhJgd4Ad/lQMImT4VO 3ksjJkHgyFUdvTyjznFroyvNR/D7tTY78EbBqITIhY0LxyAW78ANrjvhsVKnaIRp 8Vz5AHWn9pN2PzBoD0KvKT1/l+aKrhK3Yd0YrK+OqeqOP14c5fYTYVDanJJPQ86T OWpvRBGFtLA7B1Ng/10W -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF6jCCA9KgAwIBAgIRAPhHOM8WO4I7nSzRr+A6OAMwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDQwMTAwMDAwMFoXDTMwMDQwMTIzNTk1OVowaTELMAkGA1UEBhMCQ04xIzAhBgNV BAoTGk1lU2luY2UgVGVjaG5vbG9neSBMaW1pdGVkMTUwMwYDVQQDDCxNZVNpbmNl IFNlY3VyZSBFbWFpbCBDQSAgW1J1biBieSB0aGUgSXNzdWVyXTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKeqMVUZJZiPJnCcyNeATG3/bvWmSIyU0i4J Nka0IqIQ4qAQlIQuTEWYYFs8kQECg1SO7QwTyMkdRQ0wx3bAS3uxrrXjtYbpB99/ MEucZ6DtgyQqhH7M0k2dDPvDiw0Ol4n/vncHxRi7757rqIUW3xHlq1yn2eoSIoYK ODu9XJGNacPx6J3XOMO2+y9kr8MtUC/wX7s8I6YB9FZxouXw813n4DULlYeN3rxQ ynJLUTD1JorMjFcB9OaEq52fz7XuNKxO/CBltamMYJbHeB9qMsA6VaK8PFkqnip+ Fov8TTkHsOH8VrPTcBMfAoOmNEdKEcj85iMVSm2beGeU5Dna0msCAwEAAaOCAWsw ggFnMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBSC tWxv1jJAKkYpdUxA2rAw8vb3PjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgw BgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwGAYDVR0gBBEw DzANBgsrBgEEAbIxAQICUTBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVz ZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5j cmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0 cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGG GWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAFCx Ome08VjWYD7DYJMZSMtl4GXeHV04ywVUca3ef+BhkhtltAmnDVisDWsHuM0+m3sU auKJxTCDhWmEbeZab1mGSr9WUdftMmzvxn/urbiyZylAFGOPTr9OykOuKbCY+isu mi7N5SdrQolSR0zcqHh9c+jQoN+76Qg9XnkFc+6Yr9fYnk/uOIrK4TEZat61GhVL L0FsSGE5Aqh+0DG+iQvo4vCXWgG/Zohtmt7jAeLsNU/4XoYUBb7A9CuyvHp7Psx3 z017M4yo6OtPYAfZ2z9ecwejVbu7i4a2PS1rJZOU/y+EPQbALZvbjqaoSKo2TKqf RCacI5cEf9/iyK+zsKsF+FtS0C90a5arcOTB19LjZqcNpJmyxEt+USaCdKhlzzrE u/qsraB4xr4lU0yw4DZKyzRTEIAlxKeJh2BGH8CuMIunSzS8+LUD3J8qUdMvtI+8 iD0UxBj5Uw+HHwOs8Tvg3zmcJ8dcB8ULWnpiM+rNxPzgvsq7diRfhPJTFTQmgyh9 WF7jh3lmbKA2TaQ3sCUvRvvb9L0t1POEkewcwVNgx0w02im86UOFwq7rtscX3cs8 qiEnguhkdbcLiT9AzI6TdQ2Ajc4MsfoLcEpbyPxWUBvGRi7FPJsTTZKc6JNAe6DW LT+rne/7nhkj1LOm4t9ld9p+7jnhMkC8hYgpmSKq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWzCCBEOgAwIBAgIQVkZ/t7GwD1w/oStGyIXRMzANBgkqhkiG9w0BAQwFADBN MQswCQYDVQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMScwJQYDVQQDDB5E LVRSVVNUIFJvb3QgQ2xhc3MgMyBDQSAyIDIwMDkwHhcNMjAwNDIxMDgxNjE0WhcN MjkxMTA1MDgzNTU4WjBEMQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBH bWJIMR4wHAYDVQQDExVELVRSVVNUIFNTTCBDQSAyIDIwMjAwdjAQBgcqhkjOPQIB BgUrgQQAIgNiAAQ240HUj+j2VbYhATCfG5KDIKISlLfcOqdG2pL1Ia2sf5weNeF/ M0pJszvsvGtZoVTx6v9ukNBsljpZxMRB4vdgAPStBtRKmgOz1cUCagPtX0yGY7Qx nzk+5K5d4QrdzTSjggLsMIIC6DAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwHwYDVR0jBBgwFoAU/doUxJ8w3iG9HkI5/KtjI0ng8YQwggEaBggrBgEFBQcB AQSCAQwwggEIMDQGCCsGAQUFBzABhihodHRwOi8vcm9vdC1jMy1jYTItMjAwOS5v Y3NwLmQtdHJ1c3QubmV0ME0GCCsGAQUFBzAChkFodHRwOi8vd3d3LmQtdHJ1c3Qu bmV0L2NnaS1iaW4vRC1UUlVTVF9Sb290X0NsYXNzXzNfQ0FfMl8yMDA5LmNydDCB gAYIKwYBBQUHMAKGdGxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQvQ049RC1U UlVTVCUyMFJvb3QlMjBDbGFzcyUyMDMlMjBDQSUyMDIlMjAyMDA5LE89RC1UcnVz dCUyMEdtYkgsQz1ERT9jQUNlcnRpZmljYXRlP2Jhc2U/MG8GA1UdIARoMGYwCAYG BACPegEGMFoGCysGAQQBpTQCgUoDMEswSQYIKwYBBQUHAgEWPWh0dHA6Ly93d3cu ZC10cnVzdC5uZXQvaW50ZXJuZXQvZmlsZXMvRC1UUlVTVF9DU01fUEtJX0NQUy5w ZGYwgdMGA1UdHwSByzCByDBDoEGgP4Y9aHR0cDovL2NybC5kLXRydXN0Lm5ldC9j cmwvZC10cnVzdF9yb290X2NsYXNzXzNfY2FfMl8yMDA5LmNybDCBgKB+oHyGemxk YXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQvQ049RC1UUlVTVCUyMFJvb3QlMjBD bGFzcyUyMDMlMjBDQSUyMDIlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9j ZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MB0GA1UdDgQWBBS5E/JxvGv1jzeTwkyl h+/KSx/xPDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkq hkiG9w0BAQwFAAOCAQEAweAbWPSi9cPL9tsSA/6oilFfWzzVVlxlHFjUF8i94mnA UhYuw6Q+CdQBOTisxgDa92OEnrMD2jUGbKc5h+kUTB9Uyg0WidvhV1zmmhQxyLIS 0mrfe9Wa/qGnDx/faDLHB/9Fgow3Er8SCj5krJBS6dx0/4z1MSfoN2xcWOaL99wR 8TfcxtujYpg+WUcjvl3F7MplyqQYSgMlGvg/EPVx7OWBEJNgYptzUjN+ZQtnuegZ FrDzWXoanmzbAXFK/B9Zi0ubXGMx2WxodbIkQ5buk6x4xSwgew7VMhUxI5clUHXA LS8zbwVIDWbfjkf8w/sjfQoV1P7XNjvGYscUqW9vNg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHMjCCBhqgAwIBAgIQShA9s+HZJmJlKzvcauXC8zANBgkqhkiG9w0BAQsFADBQ MQswCQYDVQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMSowKAYDVQQDDCFE LVRSVVNUIFJvb3QgQ2xhc3MgMyBDQSAyIEVWIDIwMDkwHhcNMjAwNDIxMDgyNzA4 WhcNMjkxMTA1MDg1MDQ2WjBGMQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVz dCBHbWJIMSAwHgYDVQQDExdWUiBJREVOVCBFViBTU0wgQ0EgMjAyMDCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBANdLSzouA2XHyRDMJUYzFPpd/c3/NoVw fUdsYDU55ecboYNG3xBkWQU/0LgIMdjaWdlwkKIj4sBUEZT+GdXTcP/lOHDJWLy1 mZf59xDX5b5ur/9DFHTn0iZnh3RGd1mb0ewbUAwkjYvLSGOLkSIp0eSFDZB+DsiX 1YfAjMw1PtH/QCyz1KYAC4ApdaeNximJqOpvBDBMK4ObQ5VGsVECDEEzVJPOVdAi bynRwKTwmimm2oojj/PDxviwuLPJMinL2Ju04x215lvLFdnAxC0C+h6nQJ+C29k3 Elv5CwZeW9zj6UCmN5wAdTA6am0vm95QfsAkRyzE/HsyPLVhW6/ZHmtExEVAL1FP rCSnIMqZqswfpUYUcbXwfAxFdYmun7EWZSMIJmoNpFSYJIA3rrwpX13TEMIQI23t srEAgZNYPEPob8+IbwJ6mg7PxJLn//UXcCD/1QFv5lhb8M/TbPr1v3sCDui/ribW /c/gSMdC8Bxa9zdG0AOehl864APAeyq9/suWUctb3n4R9pxknQs/VGMJfBCPJivY z8n6yl3SJXCkOenGiy+v2wFeV8kikfttJtDPJPCAQ/I2nIHI6GsUv3ijwvgYvyZP G3vMywjwzi4nT4+MeplprZoRu1DYcqNm+n095bWeGZjgAyLhXvipnokqOBMJ4oMj eqe6uGB2pBI1AgMBAAGjggMQMIIDDDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB BQUHAwIwHwYDVR0jBBgwFoAU05SKTGITKhkuzK9yin0215oc3GcwggElBggrBgEF BQcBAQSCARcwggETMDcGCCsGAQUFBzABhitodHRwOi8vcm9vdC1jMy1jYTItZXYt MjAwOS5vY3NwLmQtdHJ1c3QubmV0MFAGCCsGAQUFBzAChkRodHRwOi8vd3d3LmQt dHJ1c3QubmV0L2NnaS1iaW4vRC1UUlVTVF9Sb290X0NsYXNzXzNfQ0FfMl9FVl8y MDA5LmNydDCBhQYIKwYBBQUHMAKGeWxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5u ZXQvQ049RC1UUlVTVCUyMFJvb3QlMjBDbGFzcyUyMDMlMjBDQSUyMDIlMjBFViUy MDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NBQ2VydGlmaWNhdGU/YmFzZT8w fgYDVR0gBHcwdTBaBgsrBgEEAaU0AoFmATBLMEkGCCsGAQUFBwIBFj1odHRwOi8v d3d3LmQtdHJ1c3QubmV0L2ludGVybmV0L2ZpbGVzL0QtVFJVU1RfQ1NNX1BLSV9D UFMucGRmMAgGBgQAj3oBBDANBgsrBgEEAaU0AoFKATCB3QYDVR0fBIHVMIHSMEag RKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh c3NfM19jYV8yX2V2XzIwMDkuY3JsMIGHoIGEoIGBhn9sZGFwOi8vZGlyZWN0b3J5 LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0 ZXJldm9jYXRpb25saXN0MB0GA1UdDgQWBBQMcBtUmtKzmvhxtBqd9HILKZpT/TAO BgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF AAOCAQEAlFzEOJ6MYH1OzOfVMisiGwL/B6xQx4mut03nURiq7X78J6DWUI0OAGsV lLgyn3qI9G+s/3wI+HZBb6cc6+mxdde/M33VEB+jSC2CjCfuJzy5aoGAmxxN2+iM pj6/mXPGYXmegd1b61o387rdh4D0e7cwW8EOj1Z/DmJkjG9P40KrGRJGQBxodHQU LxGH5wyGSmbzIqaf4Nu3y23Z/c07u1+QoAX3lrXKePfbeGvpCNWw+wZStCWmBnb7 /y27mA6voU0zXUtHEQ2juGrsiU2lk5Xenh4L9hXrNxgLQyu4n2YS+Kl3GK6zxH4j qGJEGhh8z78sifxVayF82R9io0BBvQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHFzCCBf+gAwIBAgIQYDQ5U886jKQrtEpEKSy69DANBgkqhkiG9w0BAQsFADBN MQswCQYDVQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMScwJQYDVQQDDB5E LVRSVVNUIFJvb3QgQ2xhc3MgMyBDQSAyIDIwMDkwHhcNMjAwNDIxMDgzNzQ4WhcN MjkxMTA1MDgzNTU4WjBDMQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBH bWJIMR0wGwYDVQQDExRWUiBJREVOVCBTU0wgQ0EgMjAyMDCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBANOviIAGpYX3kNsqLlWkHt8BMYSGH1EQa2LNUaGS ifCZKk/JyDqO1U65Ej0t09S6ehFsuIKbU71c8QYUDs5MPfQr8jEXOOcm7tl8yRHG 0QuOIX35P1JANDaAtJXnj5Vx77n1nTbvw/LMSQUqH/+XP7K+I3WOHN2Kzm1IWWSC PzJ20x7cG4tKV5oPpuQdRcL+rFMInoHiGsrt5Fy6zJRA3GMixUgBCG6J3Cc9k3zo ohDYqcjLt0fArLErGkBabVGXXAKi62IemihSJIeIAY1GdsSHBH8rzhz/kedlz17l oAHrvuaskxi13UTZIKM66xkQP4zOKqTM3zVejgBGdvxgVlNn8xeSiCbVOeOy2HjQ aLcJ5pd7X4V+J+iLpohwpoxg4sqTSD+lgWanwpczmK7D5oRTBTqC2XbXhNwm0Ngl CG3laSs6afQz8XwI4xUIl8ZUXJK4Xa7dUwaWd9VfqxxKlRRPIHQsbN9tcNaPjwMm D0QYaSp9E7sQXA7MuxB5DCfSKVlv6Fgu1SVoImm5ilcvkcNZOaHbkt+N1/evYJi7 H5ZwuaAKu6afT89zkKUr9RaTj+Y3jA5BhRYj19SdwBl/6DYqSpQCuIDe1ftYG4ws FRW1e5zd6GJek1eln8h5qktnhga0tXs39qrqeUec0CF9XbkbTuVDwxTuEfz4t1QS X/iJAgMBAAGjggL7MIIC9zAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw HwYDVR0jBBgwFoAU/doUxJ8w3iG9HkI5/KtjI0ng8YQwggEaBggrBgEFBQcBAQSC AQwwggEIMDQGCCsGAQUFBzABhihodHRwOi8vcm9vdC1jMy1jYTItMjAwOS5vY3Nw LmQtdHJ1c3QubmV0ME0GCCsGAQUFBzAChkFodHRwOi8vd3d3LmQtdHJ1c3QubmV0 L2NnaS1iaW4vRC1UUlVTVF9Sb290X0NsYXNzXzNfQ0FfMl8yMDA5LmNydDCBgAYI KwYBBQUHMAKGdGxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQvQ049RC1UUlVT VCUyMFJvb3QlMjBDbGFzcyUyMDMlMjBDQSUyMDIlMjAyMDA5LE89RC1UcnVzdCUy MEdtYkgsQz1ERT9jQUNlcnRpZmljYXRlP2Jhc2U/MH4GA1UdIAR3MHUwWgYLKwYB BAGlNAKBZgIwSzBJBggrBgEFBQcCARY9aHR0cDovL3d3dy5kLXRydXN0Lm5ldC9p bnRlcm5ldC9maWxlcy9ELVRSVVNUX0NTTV9QS0lfQ1BTLnBkZjAIBgYEAI96AQcw DQYLKwYBBAGlNAKBSgIwgdMGA1UdHwSByzCByDBDoEGgP4Y9aHR0cDovL3d3dy5k LXRydXN0Lm5ldC9jcmwvZC10cnVzdF9yb290X2NsYXNzXzNfY2FfMl8yMDA5LmNy bDCBgKB+oHyGemxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQvQ049RC1UUlVT VCUyMFJvb3QlMjBDbGFzcyUyMDMlMjBDQSUyMDIlMjAyMDA5LE89RC1UcnVzdCUy MEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MB0GA1UdDgQWBBTJ HGRorGwYyiHVTVR7U1aikJOqkTAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw BgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEAT3GcFJCtNwOtYjQjq3GzDG8jFJ8d nD6d54N5Eeb/G0ivNsR1VIL+SylECekP3QqkpLgx7CLLHIREtc4igME+RXZC3HCs V1criKLjzQ+PbrMVtr6Skk28g4rs14Sbr6Q5AA2HOTdKXYCCHE53nvb2hT7SOWrE VbjL5leB2Ji52MGEp79Vp3XfjH0URqct1Jd3HrLR/MBRT+Qfxb35VAmu/lJkiArv gxD6iK5iFkw4ZabiuKyG7HJgGD828S2zsft4/xHeccIMputW6683k/+2gmD1NWXW X4HZNqlEGZy+lW+HlX4NOGPbaKdX5WUMHnriOEPM9YuATFzd+qdicjKwSA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFRzCCBC+gAwIBAgIQdpnSyNIP34Vzu82bf2ifoTANBgkqhkiG9w0BAQsFADBF MQswCQYDVQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMR8wHQYDVQQDDBZE LVRSVVNUIFJvb3QgQ0EgMyAyMDEzMB4XDTIwMDQyMTA4NTY1OVoXDTI4MDkyMDA4 MjU1MVowRTELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEfMB0G A1UEAxMWVW5pcGVyIEdyb3VwIENBIDMgMjAyMDCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAOJdBL2A1iUTESnuK1xZ5PqV+Da+lNysjzBIIJshJmt2rlYX 3lYnfpndxraCnzNypE2siwV/B2Zw5Nk2VrqK+Fi2yTGxrtASsskz3HFb9MsN2rBf X+sjNGFANtCm/O9MU5THyR7Rt4rXW4P6SYQ5Xg8YnxC68I4u6W6PjsJXx0TyiMPo 5pT/7vfsO8T2W0rWzG8vEAurceG2j6nbyaVW6Rf8JccW5gpXuIU1ZkEMBmmbONKM YhcA8MoWRbPBDiabcEb7aITdtian4aNMf9PLDfXX/TTbgPxy1V8hNwHijSNYxega 8U7vxVrdV8tr715mShdIG2w7t3jo+29jIl0fTQsCAwEAAaOCAjEwggItMB0GA1Ud JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAfBgNVHSMEGDAWgBQ/kMh9xxVv8ySP qcMvS6IPIbIv5zCB1QYIKwYBBQUHAQEEgcgwgcUwMgYIKwYBBQUHMAGGJmh0dHA6 Ly9yb290LWNhLTMtMjAxMy5vY3NwLmQtdHJ1c3QubmV0MEgGCCsGAQUFBzAChjxo dHRwOi8vcGtpY2RwLnVuaXBlcmFwcHMuY29tL2NlcnQvRC1UUlVTVF9Sb290X0NB XzNfMjAxMy5jcnQwRQYIKwYBBQUHMAKGOWh0dHA6Ly93d3cuZC10cnVzdC5uZXQv Y2dpLWJpbi9ELVRSVVNUX1Jvb3RfQ0FfM18yMDEzLmNydDBFBgNVHSAEPjA8MDoG CysGAQQBpTQCgVQBMCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vd3d3LnVuaXBlci5l bmVyZ3kvcGtpMIGLBgNVHR8EgYMwgYAwQaA/oD2GO2h0dHA6Ly9wa2ljZHAudW5p cGVyYXBwcy5jb20vY3JsL2QtdHJ1c3Rfcm9vdF9jYV8zXzIwMTMuY3JsMDugOaA3 hjVodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2FfM18y MDEzLmNybDAdBgNVHQ4EFgQUjMYeZSv9Y9uA+NTdPdrwUdCdXyIwDgYDVR0PAQH/ BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJVKgR+8 2oJM4yx8k2Eq/TOmBmHwp4wKf5H3oYQWTQvqay+k3qlEfrzxYwSYLYJucLkrEZjw IE9psgECNYj61NdZ7g4Jst8J2ftMcLvwNZrjM4CO+T6tZ/gUyUywiYEJRgRvYJYW A6L+cZWibUbK3T0vfrcKjXnZjl8yO9nnUHjmLM2V/sc6J0XocWqBI0kf/B3Y6pRc nQWAg7FXOnSITSaymLLHCpLDdr4nNYC5nfZGOjNFIJI0vV7y4kIOHPmpz2m8Ur0i FQI4425EjV76j3qdAQOxqdlGEGeIaa/VRB5r8X2Go8Gl7RKoCoRRw2LbffXbONxr DFGAzetf1fhNtRA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFZTCCBE2gAwIBAgIQZSQXICOUuCCnq7jaeMEdpDANBgkqhkiG9w0BAQsFADBF MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMR8wHQYDVQQDExZV bmlwZXIgR3JvdXAgQ0EgMyAyMDIwMB4XDTIwMDQyMTEwNDMxOVoXDTI4MDkyMDA4 MjU1MVowWDELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1VuaXBlciBIb2xkaW5nIEdt YkgxCzAJBgNVBAsTAkNBMR4wHAYDVQQDExVVbmlwZXIgQ0EgMyAyMDIwIFhYWEkw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1bi0llXLOJESMYwWXxfZI Rgk8aVMu3VqZRhZgIDUEcWwqwMPz/Vj4hvyHXDeHG6CG6mIPbSYK3DCZYkF2sfbU 0JtZWkNZCn/yyYcA7EZKUclFjWd3Y9TvoHtis6dPKgJ0j+/EMCSGkbwXOUL/srxp aBHu4aCWLszdUYSYfr4kYMflto0/9amfxsKX1vYJ44wZdZsFR8/d/UQErTrVVVPC uSb7rzBBquOrQCuLPxywE70/gVl1az58a1bVox9KMv6UhXbOkkUka3IGLG9kEZoK YUMz9MO12v8+89KNjiVlJu/zJqOB/omHyWVFJutaQLkNtjgTMmiDTU23HVLkzfUz AgMBAAGjggI8MIICODAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwHwYD VR0jBBgwFoAUjMYeZSv9Y9uA+NTdPdrwUdCdXyIwgd0GCCsGAQUFBwEBBIHQMIHN MDoGCCsGAQUFBzABhi5odHRwOi8vdW5pcGVyLWdyb3VwLWNhLTMtMjAyMC5vY3Nw LmQtdHJ1c3QubmV0MEgGCCsGAQUFBzAChjxodHRwOi8vcGtpY2RwLnVuaXBlcmFw cHMuY29tL2NlcnQvVW5pcGVyX0dyb3VwX0NBXzNfMjAyMC5jcnQwRQYIKwYBBQUH MAKGOWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY2dpLWJpbi9VbmlwZXJfR3JvdXBf Q0FfM18yMDIwLmNydDBFBgNVHSAEPjA8MDoGCysGAQQBpTQCgVQBMCswKQYIKwYB BQUHAgEWHWh0dHBzOi8vd3d3LnVuaXBlci5lbmVyZ3kvcGtpMIGLBgNVHR8EgYMw gYAwQaA/oD2GO2h0dHA6Ly9wa2ljZHAudW5pcGVyYXBwcy5jb20vY3JsL3VuaXBl cl9ncm91cF9jYV8zXzIwMjAuY3JsMDugOaA3hjVodHRwOi8vY3JsLmQtdHJ1c3Qu bmV0L2NybC91bmlwZXJfZ3JvdXBfY2FfM18yMDIwLmNybDAdBgNVHQ4EFgQU0KiN 4f2YnMuCyiDZ7V3/cd3bLf8wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB Af8CAQAwDQYJKoZIhvcNAQELBQADggEBAGpBUVGZ+Gxko/WYWt5sErs7qAxWSAQu /GhSqRNO9jTKjL1GWCRJGgc6WAV4ZV8yW+Tw0x8Z5/sU0tCUfFacsma2IJfzsKa8 fE/Fmz82DXqHTuSiy0V+XRN3cy3HbvxRIc4TmPMshR0z1L/4odRMNJpu1E6LAepO CkZ9XIiARjtprp37BzPKpaxgeE6o/bzeVopcSzZP7qDJTowYURjdiDsjI3PqvGDe 3CXOVg3SE466ArfTJaiAWRr0+R03sJCbyRVGVYEV8LT7w4kM7Iz0lmCsYIkhla0F x/QsCplEgKt9Ab+Z9lUpGKHdGdl25c1jjH3u+XbiABK98wODDKuPKm8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFZjCCBE6gAwIBAgIQekkzCo/qVhZKzl4Mr5SfgjANBgkqhkiG9w0BAQsFADBF MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMR8wHQYDVQQDExZV bmlwZXIgR3JvdXAgQ0EgMyAyMDIwMB4XDTIwMDQyMTEwNTQwMVoXDTI4MDkyMDA4 MjU1MVowWTELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1VuaXBlciBIb2xkaW5nIEdt YkgxCzAJBgNVBAsTAkNBMR8wHQYDVQQDExZVbmlwZXIgQ0EgMyAyMDIwIFhYWElJ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw86c71zOC/JlnF2NrEot uqnIVCmPHiTSDMG9RAU3DtAVJPFNyLpuXV1jEwHagJxCZ1liFYm0t1k3TUQWd8zg PCw312vyj8YtR5IN5ybVv8DZtakc4Iq/h8TDZGnBxWX7DVRGETUAjqpPneNMuFHW 6atApN9T37lRzPl2EGTykU0zz+OYYkjNOBRKDSGG4OYedI/TG3pTCXTQr8nf2hdY RPRSuVrsZS+Zwdwh43nJJqMT4jbhP5JHEEYEh4JD4LMOoOD7/vNq4zfwBDqxdRmu e3HUf68gRroZPSI+AheoDYo2e+EnLdUq/1AXBNb34o/Zlh6kBiEIjmob5kq4bszS 9QIDAQABo4ICPDCCAjgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB8G A1UdIwQYMBaAFIzGHmUr/WPbgPjU3T3a8FHQnV8iMIHdBggrBgEFBQcBAQSB0DCB zTA6BggrBgEFBQcwAYYuaHR0cDovL3VuaXBlci1ncm91cC1jYS0zLTIwMjAub2Nz cC5kLXRydXN0Lm5ldDBIBggrBgEFBQcwAoY8aHR0cDovL3BraWNkcC51bmlwZXJh cHBzLmNvbS9jZXJ0L1VuaXBlcl9Hcm91cF9DQV8zXzIwMjAuY3J0MEUGCCsGAQUF BzAChjlodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NnaS1iaW4vVW5pcGVyX0dyb3Vw X0NBXzNfMjAyMC5jcnQwRQYDVR0gBD4wPDA6BgsrBgEEAaU0AoFUATArMCkGCCsG AQUFBwIBFh1odHRwczovL3d3dy51bmlwZXIuZW5lcmd5L3BraTCBiwYDVR0fBIGD MIGAMEGgP6A9hjtodHRwOi8vcGtpY2RwLnVuaXBlcmFwcHMuY29tL2NybC91bmlw ZXJfZ3JvdXBfY2FfM18yMDIwLmNybDA7oDmgN4Y1aHR0cDovL2NybC5kLXRydXN0 Lm5ldC9jcmwvdW5pcGVyX2dyb3VwX2NhXzNfMjAyMC5jcmwwHQYDVR0OBBYEFFbt 0t9dQGsVHWxXIA14kU8gnJ1XMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG AQH/AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQDCEorVJ/XSH6TsagjLY9L25XO/r2aC 1e0JnWjJF750GI/gHePuqFN/8fbADAWlqY+qXd7JMn2eW7pDyuDBb4tW/GgqYeIO EcFE/4rxOz7gyVleSWw0xj3hgu8Ij/s7RVlNnTYI6kEN6Mipm0bP/ZdjRIfqgNC0 EpGZqlrIlgjz9/mBIy4HzdUD+xV691kXTWEv9D+6gyHvFuDOgppvPRJ/Zb8nzgE4 M3xlfnxIUoK7Em5QoIuj7BGv7LqwQ633wLtpATJOvWgaQFtd8UhVtMniWxddQ8Mc J2PYDhqcoLWUA815ZsMZzDv+HaSNzd5FvQSp5Yc6QGyPbJXERLHKhcih -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFZzCCBE+gAwIBAgIQdwxMdQ+cNM2PV1ZVVft9gDANBgkqhkiG9w0BAQsFADBF MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMR8wHQYDVQQDExZV bmlwZXIgR3JvdXAgQ0EgMyAyMDIwMB4XDTIwMDQyMTExMDMyNloXDTI4MDkyMDA4 MjU1MVowWjELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1VuaXBlciBIb2xkaW5nIEdt YkgxCzAJBgNVBAsTAkNBMSAwHgYDVQQDExdVbmlwZXIgQ0EgMyAyMDIwIFhYWElJ STCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK8qJEuJizvmOI/hZytt pp05hrHXu3Yw17BBx4LmywLsizQSCkEmX61yHuo6Qgj7cn4T0u8pmqczui3YQjbV lMqld/DeUuGdDalVIaCY/o6Ngb1PYwEKkIL4mm10h0C98Lq1OkMAUKFZ3Dot6DEH t8jpjlLLcGpV8rkAAJ8F4My2PRGTKM9eaY1rGGx98QoV3NeVb50oQis3a3ojjsN4 cp6CYjeMfzygDclyCOrzNTfmvi2ieFUh1NUSxBrhRtPTzD9SnKgfXdllmspMb8Hs A/uwC49dQTf0luhRTwLOXBi9+2r1U0CzYSjvJI6zADOs+Ir2zvgaU8E85zyoZ9Hs eRsCAwEAAaOCAjwwggI4MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAf BgNVHSMEGDAWgBSMxh5lK/1j24D41N092vBR0J1fIjCB3QYIKwYBBQUHAQEEgdAw gc0wOgYIKwYBBQUHMAGGLmh0dHA6Ly91bmlwZXItZ3JvdXAtY2EtMy0yMDIwLm9j c3AuZC10cnVzdC5uZXQwSAYIKwYBBQUHMAKGPGh0dHA6Ly9wa2ljZHAudW5pcGVy YXBwcy5jb20vY2VydC9VbmlwZXJfR3JvdXBfQ0FfM18yMDIwLmNydDBFBggrBgEF BQcwAoY5aHR0cDovL3d3dy5kLXRydXN0Lm5ldC9jZ2ktYmluL1VuaXBlcl9Hcm91 cF9DQV8zXzIwMjAuY3J0MEUGA1UdIAQ+MDwwOgYLKwYBBAGlNAKBVAEwKzApBggr BgEFBQcCARYdaHR0cHM6Ly93d3cudW5pcGVyLmVuZXJneS9wa2kwgYsGA1UdHwSB gzCBgDBBoD+gPYY7aHR0cDovL3BraWNkcC51bmlwZXJhcHBzLmNvbS9jcmwvdW5p cGVyX2dyb3VwX2NhXzNfMjAyMC5jcmwwO6A5oDeGNWh0dHA6Ly9jcmwuZC10cnVz dC5uZXQvY3JsL3VuaXBlcl9ncm91cF9jYV8zXzIwMjAuY3JsMB0GA1UdDgQWBBQ+ 08eWNJIc0KgCvLh4qETUXwZWqzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw BgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEAPWc9gST5H8dCdkWdCxeg9JA8ima2 Ybzj720K783ceRrc7F+20ec/J8L600UMRwa3cwkvFlHuP7MUYdVfQ8K4OhuFnP4D wDFYoNPKrGkHH2vsW134P3ZDK5+w9/+rkrploD1LG3MDfzjgFtknzHpB4lK1JB7Z 1RzmpOce/2iLbd8/ErdVDo2ODPAKMnvR5VSI3Cwdho4THnNS/Vg5qIyJa8cZtxP2 7d09xoYmR3IFjUU/2y9PVWtPscHrf4wJ6PC8VULXvMQOvuyMSVTFY1vTfMs8kFMg 8JgAAMTWdvv9jvxZCQntGZSSiyfogVb5w2pNMPvCnOPgK+5pQcovwjJ5uQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDsjCCAzigAwIBAgIQDKuq0c7E6XzCZliB0CE49zAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0yMDA0MjkxMjM0NTJaFw0zMDA0MTAyMzU5NTlaMFExCzAJBgNVBAYTAlVTMRMw EQYDVQQKEwpBcHBsZSBJbmMuMS0wKwYDVQQDEyRBcHBsZSBQdWJsaWMgRVYgU2Vy dmVyIEVDQyBDQSAxIC0gRzEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQp+OFa uYdEBJj/FpCG+eDhQmVfhv0DGPzGz40TW8BeWxipYTOa4FLieAYoU+3t2tg9FZKt A4BDTO43YprLZm6zo4IB4DCCAdwwHQYDVR0OBBYEFOCFSH0TptMQGZ9cy2t4JJL4 rhuuMB8GA1UdIwQYMBaAFLPbSKT5ocXYrjZBzBFjaWIpvEvGMA4GA1UdDwEB/wQE AwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgw BgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw LmRpZ2ljZXJ0LmNvbTBCBgNVHR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdp Y2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290RzMuY3JsMIHcBgNVHSAEgdQwgdEw gcUGCWCGSAGG/WwCATCBtzAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl cnQuY29tL0NQUzCBigYIKwYBBQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRp ZmljYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFy dHkgQWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t L3JwYS11YTAHBgVngQwBATAKBggqhkjOPQQDAwNoADBlAjEAyHLAT/4iBuxi4/NH hZde4PZO8CnG2/A3oGO0Nsjpoe2SV94Hr+JpYHrBzT8hyeKSAjBnRXyRac9sM8KN Fdg3+7LWIiW9sUjtJC6kGmRyGm6vV4oAhEDd9jdk4q+7b5zlid4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFMjCCBBqgAwIBAgIQBxd5EQBdImf2iJL2j4tQWDANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDQyOTEyNTQ1MFoXDTMwMDQxMDIzNTk1OVowUTEL MAkGA1UEBhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xLTArBgNVBAMTJEFwcGxl IFB1YmxpYyBFViBTZXJ2ZXIgUlNBIENBIDIgLSBHMTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAOIA/aXfX7k4cUnrupPYw00z3FwU6nAvwepTO8ueUcBU smQGppcx5BeEyngvZ8PSieH0GHHK7RnHbgLChyon2H9EpgYo7NQ1yrcC5THvo3Vr lAP6U746ORSDxUbbv4z15kAsyvABUCFi8S7IXkzDIjhOICNrA8fXUpUKbIccI2Jv Mz7Rvw5GeG7caa2u+vSI3TmBnwMcjVqlsScqY6tbE/ji7C/XDw7wUpMHyaQMVGPO 7mJfi0/QbiUPWwnCJPYAqPpvBVjeBh0avUCGaP2ZtZc2Jns1C8h9ebJG+Z3awdgB qQPYD2I+fy/aBtnTOkhnBJti8jxh1ThNV65S9SucZecCAwEAAaOCAekwggHlMB0G A1UdDgQWBBRQVatDoa+pSCtawaKHiQTkeg7K2jAfBgNVHSMEGDAWgBSxPsNpA/i/ RwHUmCYaCALvY2QrwzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAm MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSwYDVR0fBEQw QjBAoD6gPIY6aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFz c3VyYW5jZUVWUm9vdENBLmNybDCB3AYDVR0gBIHUMIHRMIHFBglghkgBhv1sAgEw gbcwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoG CCsGAQUFBwICMH4MfEFueSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0 dXRlcyBhY2NlcHRhbmNlIG9mIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBs b2NhdGVkIGF0IGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwBwYFZ4EM AQEwDQYJKoZIhvcNAQELBQADggEBAKZebFC2ZVwrTj+u6nDo3O03e0/g/hN+6U5i A7X9dBGmQx3C7NkPNAV0mUoaklsceIBIQ/bC7utdgwnSKTnm5HdVipASyLloU7TP 2jAtDQdAxBavmLnFwcwXBp6n17uLp+uPU4DZgubM96LyUQilUlYERbgu66rCK18j RmobDvFT8E71oU13o1Oe/1WUHFbTynRkKW73JDd2rZ21Pim7LEJVY3OcRmtYNHaM /lunYx1ZQ+0fw7Hc5J/xR7vlRiuyP+fJ9ucuDYupLg333Di5R7JZIfnX42ecX0Dd 0wIeuFj0HBjH6c25FUov/Fa5Zjr0VPjmmgN6PnoMArUZXDkQe3M= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFHjCCBAagAwIBAgIQBPIuzCH8tDgqwouPLWQfwDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0yMDA0MjkxMjU1MzRaFw0zMDA0MTAyMzU5NTlaMFExCzAJBgNVBAYTAlVT MRMwEQYDVQQKEwpBcHBsZSBJbmMuMS0wKwYDVQQDEyRBcHBsZSBQdWJsaWMgRVYg U2VydmVyIFJTQSBDQSAxIC0gRzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDfn5fdV0A4cCNFu0EvUgduZVPyPZity4q8Re1TcE9qGyWoVpzHm9OluDlq wcvudbLwBe25PWA2Z9xFpVKK9jGW6Vt79N7if7dfi9w2+2zG+/wJu1Z6TA8RENTV uJTaMwqQXw1dTkZEOgjCEKa75uyzXl+mIa0s4GdxkCBclGI9WDsUFlLj3A6eBIze TomTl7LhIV+nQUEWTqkwG5Pcxckiv7Xn1mu7EVWUukZWY8uL+KhcTJQZYtxNj3Pe M73WZ3fraixPA+RBkVnG5NgObRnrk5VHwjntbit9892kp7EISZK4Izfm99QgP4V2 IqHFsKxfCnZqfwUHikxftIVkjXIdAgMBAAGjggHgMIIB3DAdBgNVHQ4EFgQU073B PKDPNbk0xdTb2hAOTN5q/lgwHwYDVR0jBBgwFoAUTiJUIBiV5uNu5g/6+rkS7QYX jzkwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD AjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcw AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0 dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmww gdwGA1UdIASB1DCB0TCBxQYJYIZIAYb9bAIBMIG3MCgGCCsGAQUFBwIBFhxodHRw czovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNl IG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0 aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3 dy5kaWdpY2VydC5jb20vcnBhLXVhMAcGBWeBDAEBMA0GCSqGSIb3DQEBCwUAA4IB AQBD9c6SmtMxGjRwc/A1bPiM+r1qj5xbDzGn6s6m6oggm9UeBLCSUNJthKffNPqq wtULeeUddssewaOZX+uHjG9bY/O9J1VQtGtXI2hndyAPiloqNjf5iBW16h3ZIUFQ L319hISioItFVJZnVe4gjNEWio1ZRwO5A4e/H69/lPAX294yGtYGllAdv2NexhUM fjODhCajoTJmkXbyIpYzTNkgDXvQptTecrvr0rPzEMWfTtGSppbOC+s/5jG3aJ6G Jn49Ram1ZLEGHTx9PWUoHth9Lj7vwFBD9667x9m9nUhuET9a3XvNep+N7w96ZqH2 fAqUBW1kl6u3u67D6mvDsCQr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFnTCCBIWgAwIBAgIQCOpLrdu2g4Q1w9NLKOlvhjANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwNDI5MTI1NTU4WhcNMzAwNDI5MTI1NTU4WjBqMQswCQYDVQQG EwJDSDEuMCwGA1UEChMlU1RNaWNyb2VsZWN0cm9uaWNzIEludGVybmF0aW9uYWwg Ti5WLjErMCkGA1UEAxMiU1RNaWNyb2VsZWN0cm9uaWNzIFB1YmxpYyBVc2VyIENB MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3fLbDCu99j+T6lH8R3 jscukSJxadqhYX/xqWJdJiSTE0yuWOzRJ0ucZyOI0eSnEW66AtCWmjl0X+sfGLv0 Vy3e+HvVkIL383ObkZQDqWFr+m+AQTVs2E18vWBoYHf3Go3k0iPgpg9VdoTKeTAU vppSsdjh7Q2ipzHEtAPVSWI+BMvnU1W8WLv/hNPCcFJeXBH2fGclDpvG1wdFYWK6 uM6bYgLWqGNArKxCFlFw0L2swlfz92s4qd2FNATcFkP4LoSPxsL1O+IIxQ7zdxro bALiOgmvwLGVVNpFj961u7XorocmALMYDjwc5zgtFNQ/aGzrQR90tYD9+XzQBPmT g9cCAwEAAaOCAkIwggI+MB0GA1UdDgQWBBQV10oBDEhicl8jJOWgQBRbAAHWHzAf BgNVHSMEGDAWgBTOw0q5mVXyuNtgv6l+vVa1lzan1jAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYBAf8C AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp Y2VydC5jb20wgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0 LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwOqA4oDaGNGh0dHA6Ly9j cmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwgdMG A1UdIASByzCByDCBxQYJYIZIAYb9bAUCMIG3MCgGCCsGAQUFBwIBFhxodHRwczov L3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9m IHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUg UmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5k aWdpY2VydC5jb20vcnBhLXVhMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFEaWdp Q2VydFBLSS0zLTE4MTANBgkqhkiG9w0BAQsFAAOCAQEAQFZU+N+hh0rSlk32GULm pPEG6VjJHBUxJa1Tv2M/jocGqKzPjPpebmHOB6T734WrZ/pEECzXowYbXan8DgEA CoKfdsQPSpvdeXxmfSFBhr2zk/mevrPxvZK3dgbJeLKfJnirKqRhAlGDnxPlwUEV FLy5v8O9yWgjQLX3BmUpN+iumhJB5vB5+UL7gKlL/O6SonlOg5gKD82sgg2VwtLp 6M7vmIIrMgmRMWnnFHvJE0DqIcbLM9fi7J+nMw4kuX143Vg93SSLE5ez2Deg1MFx XdgRzBbz4Hk2MKedhGXrUcTcV4hJzERLxBQnfF8ads2GIkE2rstrwL0c/MJwkfd+ hw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8DCCA9igAwIBAgIQVoFL4pfjDOsuZZiFR69QSjANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTIwMDUxODEx MjYyMVoXDTI1MDUxODExMjYyMVowdDELMAkGA1UEBhMCQ04xNjA0BgNVBAoMLUJl aWppbmcgWGluY2hhY2hhIENyZWRpdCBNYW5hZ2VtZW50IENvLiwgTHRkLjEtMCsG A1UEAwwkWGluQ2hhQ2hhIFRydXN0IFNTTCBEb21haW4gVmFsaWRhdGVkMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArzpwHSZxkvnO/av5GP0B1bKmSVIX 4+gp/QMFfbGMlB0LIgsb2ZNu3U8ayiTarALhA7jpeOuLfZ7Pu01PLhNawa286WDZ cQqGZDqZpwxCBzJ2Upz37iYSJg/z/QIgiPupCP7iwH+qJhXd1qn1tPdBXsZGK6eZ qjrna2tqTofneOlzGH1qg61JEXQ+sbspRs37d7ClhK8vkL5qIvCDQkiPsksFw1rH LL+VTbTWeZE+mItJNQOlr5yxGqImv4gTC2bTyecb7GlYcIflaYb17l7waRp1Gm9U RnZv3CLt86rvyEWjE0rVoBoTs4tLLX5uj8IfuoP5kHQLC/lLUszR6n1EDQIDAQAB o4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUeGwFw28BrVzX 0s6Klw9y6QbyVU0wHwYDVR0jBBgwFoAUVJndm//opw6jGZ1bvkJX3zD8jzIwDgYD VR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA4BgNV HR8EMTAvMC2gK6AphidodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9nc2Nhc2hh Mi5jcmwwbgYIKwYBBQUHAQEEYjBgMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eu b2NzcC1jZXJ0dW0uY29tMDQGCCsGAQUFBzAChihodHRwOi8vcmVwb3NpdG9yeS5j ZXJ0dW0ucGwvZ3NjYXNoYTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsG AQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQAD ggEBAFGf4E2o9UexwsHiM5q0vLs7PxrFZuRCfYygUUOQSn+JKBBqv+sQ3xTolCW6 rY8sheADWxFoaGFSYgkLT7vCJLnwCFaLC7KpaFKnnLOmlHXOZR9S5+JUrAdd06uk L4ma7vJuV/hOyr+UkJETNJXi36OznnT7mninM0WaBeHF02trhGhClSGArNaVgJ8X YaHSFW70op9zirU4vTTnzKUykQg4wI+5Ney8EZdSqSS1OojTNucjUFn5HR+0uUDs E0wSDj7RXyHS2TCYEATtP9T526JVvdIeTajRDtagGqslXkTNQ0+0iiQkhapp3xnQ sOs3XnWBrVdMZ+obz+3CEYpqFeg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8jCCA9qgAwIBAgIQQr5QsaZ1PDZAmgN4iKYOqzANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTIwMDUxODEx MjczM1oXDTI1MDUxODExMjczM1owdjELMAkGA1UEBhMCQ04xNjA0BgNVBAoMLUJl aWppbmcgWGluY2hhY2hhIENyZWRpdCBNYW5hZ2VtZW50IENvLiwgTHRkLjEvMC0G A1UEAwwmWGluQ2hhQ2hhIFRydXN0IFNTTCBFeHRlbmRlZCBWYWxpZGF0ZWQwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDrvccbCf574JaAfs2cTOGuea/C LXEsAqajfaC9G3ORQhML1Fdqfdakn/ACQiNHqB+E/J/NvQHxCGwwwCGeTxzn7Zig UW6TJTOT3kGbVgWa0a89nTrQZWqAkTa8Mrl79pWVuPCc8jJo49ezEuDDLHXVQMhA +bXtVku9yX7Pb1uibT1aJbAzHX/ISkCvARaEMpE0GWN3xt400baMoX4XGaOm2p2X 6Kr/GaylvlriCjTzD4dL66lV/bcW+NIyomuvRIKCyez/I0kTqOL20KZlIp8nvFeB laXGcGAHNqSRRzZuIxuhVa+PS1cuDrRA1wv1WSJmmOlQlsCIgInvossBGRA5AgMB AAGjggFsMIIBaDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQepLL9GAau Pz/P/I44G2cJdNx9ATAfBgNVHSMEGDAWgBRUmd2b/+inDqMZnVu+QlffMPyPMjAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgG A1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly9zdWJjYS5jcmwuY2VydHVtLnBsL2dzY2Fz aGEyLmNybDBuBggrBgEFBQcBAQRiMGAwKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJj YS5vY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5 LmNlcnR1bS5wbC9nc2Nhc2hhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYI KwYBBQUHAgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQsF AAOCAQEAcMYkt6pgMkikUiWZXyTvQMwfU0Gmz2bTc4eMVL+oTLn1CFzdiE68OXB1 wk2+pI2JUd36iPJAqiG4epTBU0Jc5pV0QgfYvs8gxtlFfSECFfekzSRy60vhnM+0 jVOnJvrp4fmQjk0FxIhhntbSgfvuAEOSBLeUvxmQIiDeaVtHPKsqyNeDR7YGwUe1 lsKHzFWIc+95B65zXKuZBvB2rKMF5bh7G2bYq5vLfXXIfvx0eq472nspV3K+WnXA 2kErRrbgKXuKIbDSSMHsffM4q5k7ZwRdDJosQn1Ryx71OoNGrnvDk0T96pTanhe2 h49kiHqZugx5/dwo+ImwcV7bSoZO8Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE9jCCA96gAwIBAgIQCgVHG6hV0WnPhPM2bOsJ7DANBgkqhkiG9w0BAQsFADCB gzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEnMCUG A1UEAxMeQ2VydHVtIEdsb2JhbCBTZXJ2aWNlcyBDQSBTSEEyMB4XDTIwMDUxODEx MjgwNVoXDTI1MDUxODExMjgwNVowejELMAkGA1UEBhMCQ04xNjA0BgNVBAoMLUJl aWppbmcgWGluY2hhY2hhIENyZWRpdCBNYW5hZ2VtZW50IENvLiwgTHRkLjEzMDEG A1UEAwwqWGluQ2hhQ2hhIFRydXN0IFNTTCBPcmdhbml6YXRpb24gVmFsaWRhdGVk MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxxY+53qCwebnymntpBZG EbSP11AqRd4HAv/2pVVrHxubPtI28x1RHE1wn0IGsM0wFPjfQCi7lhfvkXiUCdAp PWasmNm+yyimHTaNAhavBnDYTyUSawvWUBQhOOiuYYFSRPmbXOBMi07kahqNjNi1 x9wn8/oCFZyVLhoPHovJomQUGBY3tQsekxWI9rFrY6FWbqhysAt3WFnCSbSW57Ze uSjAi6okDAfmkc+wlTgVm4u7g+JfC/5hK8dSK8kK3H894ofQ6vR5Ro7syTfgvkvL 7ERDUE7RN1Q4EhHAAMtsXF+PpWw4nM+qnmm5j+Zt2fP5w35ceMCHimhArRv1/MN7 UwIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUIDKD v5dUeRF1jP+kZzBVD0Dn08QwHwYDVR0jBBgwFoAUVJndm//opw6jGZ1bvkJX3zD8 jzIwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD AjA4BgNVHR8EMTAvMC2gK6AphidodHRwOi8vc3ViY2EuY3JsLmNlcnR1bS5wbC9n c2Nhc2hhMi5jcmwwbgYIKwYBBQUHAQEEYjBgMCgGCCsGAQUFBzABhhxodHRwOi8v c3ViY2Eub2NzcC1jZXJ0dW0uY29tMDQGCCsGAQUFBzAChihodHRwOi8vcmVwb3Np dG9yeS5jZXJ0dW0ucGwvZ3NjYXNoYTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAm MCQGCCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcN AQELBQADggEBAEccg1oH9hTCYSZ87wNeAu4hQZObAaj2FLr0JmxapBCApcLEJxMK oNl/DDRa6oOcC4ODGBlYY2YUtOyKVZv9vya8NCecgp4z83xnqOT5+I+PRMRfRSaj RNLBeIsx0POPijyltz530RdgGwiuYJpHuKdKvNjdp2+vYzShrZeZk5YkeO9flGl8 AociaFbGG1CGep4k2KLr2S1jiLVIvU2ZW3fLEWsACSisII8rckvVar+X+g8fl8il /ZU2zP/8cUUGO/5DVpee38M9nVboh4g7Gox7KCy309iU+vdzDBTrxX5veOD1+bis ene523ArTgW2mf9UD7RfHUOeAICeei+GZcE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFADCCA+igAwIBAgIQd46aQSDCIUIeIgZGpD416TANBgkqhkiG9w0BAQsFADBj MQswCQYDVQQGEwJCRTEVMBMGA1UECxMMVHJ1c3RlZCBSb290MRkwFwYDVQQKExBH bG9iYWxTaWduIG52LXNhMSIwIAYDVQQDExlUcnVzdGVkIFJvb3QgQ0EgU0hBMjU2 IEcyMB4XDTIwMDUyMDAwMDAwMFoXDTI3MDQyNTAwMDAwMFowVTELMAkGA1UEBhMC VVMxGTAXBgNVBAoTEENyb3dkU3RyaWtlIEluYy4xKzApBgNVBAMTIkNyb3dkU3Ry aWtlIE9WIFNTTCBJc3N1aW5nIENBIDIwMjAwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCn33G1MvS6JmBns3IhBhnjUchwq0Qar4x2k8VG64ALRJ+tsLkQ B6fJefGhDCNl8pHNbPr6rFBTLqZ4OrbkWJkeBIhS7YIYvnVCYlqGPU+yArYRuBRm eP1FYIzFPOwqtR9kln1jeU+dW4b+PlBSKqalMRVE6LZZn5twFSZT6OdEPuF31XNU turYZhBWpqFNGmvHxhddv0afAqMmhVAkFNmY949eGh+dDLJ/zHe6zk0o+TgG3V3t nKCg2JW+5kJ9OUXIzx8hAOQlof9BPlEUmiY4D53LSp/QLyOu107zNN8PvOJwMiUM JgBEs9iU2x88VG71APhe2Ecxs3W2yvb4bBb9AgMBAAGjggG8MIIBuDAOBgNVHQ8B Af8EBAMCAYYwJwYDVR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcD CTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBS42MF1b7sF80bB8demnJp2 PqUoHjAfBgNVHSMEGDAWgBTIY5sIaVTCmMjZzeMzt1Be+MkBmzCBjQYIKwYBBQUH AQEEgYAwfjA3BggrBgEFBQcwAYYraHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29t L3RydXN0cm9vdHNoYTJnMjBDBggrBgEFBQcwAoY3aHR0cDovL3NlY3VyZS5nbG9i YWxzaWduLmNvbS9jYWNlcnQvdHJ1c3Ryb290c2hhMmcyLmNydDBBBgNVHR8EOjA4 MDagNKAyhjBodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL2dzL3RydXN0cm9vdHNo YTJnMi5jcmwwVgYDVR0gBE8wTTBBBgkrBgEEAaAyARQwNDAyBggrBgEFBQcCARYm aHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wCAYGZ4EMAQIC MA0GCSqGSIb3DQEBCwUAA4IBAQAlVwIesHz27/v9/Zf0tnThURWGJVfTaHvPvQnj rz13npLa0CE5az5s9E17t4nvGwPRhD5uUVAao3VzOkBkoPRnml93/uvwy1MjF85Z cgQeC7yXFmS+234FQ/YG0vVcGzNohH9LzhzEnv7MT96uOh+s40XqmLEQC2K+syVM eZo9qwGABcE2iFl+wR45ESPYUx+NLZr33zmL0nzHfbB2yDFdExAafyVVJmPIUaV4 Cff0iqlAR4PaIVBFTGBdvq0YGEyt5lCmF1pQVlPKGKFY3A9vn+4R7EBnhcboWIaJ N0AXFB9jkAt9vLjcw4T+U+hb0b4XVCasecKDc/3jrMFwHTBl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFHTCCBAWgAwIBAgIJIrmxbafm87u6MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMjAwNTIw MDcxMDM1WhcNMjkwNTI5MDUwMDM5WjCBjDELMAkGA1UEBhMCSlAxJTAjBgNVBAoT HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNFQ09NIFBh c3Nwb3J0IGZvciBNZW1iZXIgMi4wIFBVQjEqMCgGA1UEAxMhU0VDT00gUGFzc3Bv cnQgZm9yIE1lbWJlciBQVUIgQ0E1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA1wdiK3zK1kAesoeWXMKKbNwI+XUgENS5nLKgJJuLcwCp38AGQjikW1ab jHOl/JFk9qgHTBAjpJRwWJ6oGqVd+v2/0g9xRKNU0PlUoC4z6gh6nkmmYSdloKzt ViGy7y9Y3IRiprjhHKi39SK/SgHKloZv5Wg6cRv7XozDJGKtv+OJnN1PsmDMXkmN BQoD+wuIj/4hXdzZutebEUzHxxku4nJ3pPgE5d8ReMkCpTDCNC+eRTkYWdaMJMLh 5O3vcgttWWUPJqIvP5HGDkMqIBLJXSTq7zH5W4tp6TmqQEHUlDAM8DQE0+OSpdRT QpVu/jc0jg+5Vb1hFhWW9nbm0AOLcwIDAQABo4IBrjCCAaowHQYDVR0OBBYEFIk5 QWSR6UakFlkH8iuvUn99S9qSMB8GA1UdIwQYMBaAFAqFqXdlBZh8QIH4D5csOPEK 7DzPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC MEAwPqA8oDqGOGh0dHA6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJv b3QyL1NDUm9vdDJDUkwuY3JsMFIGA1UdIARLMEkwRwYKKoMIjJsbZIcFBDA5MDcG CCsGAQUFBwIBFitodHRwczovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0Mt Um9vdDIvMIGFBggrBgEFBQcBAQR5MHcwMAYIKwYBBQUHMAGGJGh0dHA6Ly9zY3Jv b3RjYTIub2NzcC5zZWNvbXRydXN0Lm5ldDBDBggrBgEFBQcwAoY3aHR0cDovL3Jl cG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0MtUm9vdDIvU0NSb290MmNhLmNlcjAd BgNVHSUEFjAUBggrBgEFBQcDBAYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEB AH8X3JR4dnFhjqSyVbz7Ac2aEnqEmnnnlVbLPMdgFwFyF5yD538Fa2tVGGuBjkeE bLT38cHChGXZEf2+NhyNgC87VlW1PYslZ9S6nGQh+bBuqqlVQcrM2C7yfC730yJ+ JSjqm4kjxXM0n5JiBHgKZNhgY51cZ+Fr2WoJQu1+USWfxL8S9AjRUyP+TRp6eP8X Gn/RsR4pC6rzg9qI2DeVB8dtK/sllKfvaVQekIg5gdoM6PqiW48oLrdSJ/lfr2YT OSPpWjSE+g+CAbYQgwqRLE/cIlwl+XE/MLYjgrNfLphvD2fP80yPG8ugFO5js1iv GY8AxrZy+aiSokSoJ2fdtBc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEWzCCA0OgAwIBAgIQQAm3l56tCrIb/S1vLGJmkTANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTIwMDUyNzAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowNTELMAkGA1UEBhMCS1IxDTALBgNVBAoTBEtJQ0ExFzAVBgNV BAMTDktJQ0EgUlNBIE9WIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEA1Rm7lc2N04hcIY+7xL9eVeAJyuwXX988Y0SHkGviT5Lgyv59ctK+tfuIygWC E4LDTJWJxx04Zrzh01fNhiFVfi6Qw0NcMkew6rS7NU6BUWZFuXy69ByfjEi2bjp8 AGpvErpX8YZZT9IEh8Rb3qyksaKA1ZLbRbGQ/UzjJKHNJlBYuRytSr4IfgUh9g5A a4EmKsQxTkngF1rUKKUeKW4EiA0wfFLbgnWVqaDdMZIqK0Qiu/4w9kVfQx1gGvgP XtPxm+92x4yqG8BoDonre6HvMEHYXU5p3FVYYwbgrg7qIZJaRvxwHU6lrCLL2EKL rARCgIJKYHd7sxo9CLrqxQr5ZwIDAQABo4IBHzCCARswHwYDVR0jBBgwFoAUoBEK Iz6W8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFABZzaC70pLwvu5vUoupzjd0wSBI MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQIC MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNl cnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcw AYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQCb wCmqK+MxNjFhMx/zmY+y/Jd3Bqt1bRyXJmiS+cwOzqeSQ96PvXSQHJOLwmmQgTiI ldnX0l5UYz6MpKLRlsmNnFQdQkP75sPHfW31ThNSoaC8/2BqeHuAHGTs1Bke7v8a BMAFBBvfypAq77x9MdHNGc0Whr/gBMB5U9SJyEsQHrMzaDK6nfUUfqCZyYVpPtDj 634xdrF1xFx8iqYMN6Scz48XgiBRMVut8mPvwmzhoaK5vwZKKnXftSK5X1r82HCU wlbUt33hKbiU+Pdi8P53xM5qPMvuo686iGP8J+1PEKeaa2ECFozDnnyrSlVwFBH6 P4rDDpwYU04Zr1UzEn9j -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEWzCCA0OgAwIBAgIQT7cxHGT9kPGYHf/B5LCYvTANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTIwMDUyNzAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowNTELMAkGA1UEBhMCS1IxDTALBgNVBAoTBEtJQ0ExFzAVBgNV BAMTDktJQ0EgUlNBIERWIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEA1fQXd166CHH5+6RLOKOGCN9WKQeYoPWc7ogxpGpQh+rfyOQvvsW4sz1VpLA3 UdWWffG3G+/MOhgX4WOPTkWGHm+owoD/YOPPeK+gHN93QLtBroqiwBxMf1WbCyKM BCNtgHsHTRNhfWsUdhOWk8xPztekazIAVVAnEZza2TENiDGWUIvOVSyDogtSCgDg 4KxFBmCNtaj/Y+PLaXH6A6wdKpQ+G9VMaLDlHP92dxLBZnjIzH3dPMCzQlWcw3hb SXeH0vHUgjkdU5t8pRZnGqziV1CV6p2tMlSpV9D4GRQNi16/HwbYyoIx2lskw5an z5U4PTVrCnqa1EwWdYywvRhr8wIDAQABo4IBHzCCARswHwYDVR0jBBgwFoAUoBEK Iz6W8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFACyhYjxpuX174IlBE75Zc5GwREL MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQIB MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNl cnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcw AYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAc PXWNpDa5gyl9Rv+dc77EzmD9pQZE6JByb4f53riITW07+D9JXDRilTlRU2H2dFrW nIBzaJwY7R/1m70kBkfd0uPgOiw6DV/5U4HS/IiAKnqXgH4UzAbA1oMAxrXtp2BM 8PpwafDjoI+8TYjXK2f5qVXWmPIpUBIHEKkx1jUCeIm7ol5c/3LNVLobpfJ4hwvS ixfdO0AZMHghA7qsh8ukzHdqz07bU+/Y3YF9RTP0u/JdrQuu4s1Mo88gpe5F0d04 e2l1eehJwxfcl+26MaBwpPIlI+vIl/cdwQNdFVzfGQH80b12VocjgU/xClJ/kPtl aiB+4GkaQn9In82v+AuH -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvTCCBKWgAwIBAgIQB0eWToV4BAJ742fDL795iTANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDUyODEyMTMwMFoXDTMxMTEwOTA0NTk1OVowTDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEmMCQGA1UEAxMdRGln aUNlcnQgSGlnaCBBc3N1cmFuY2UgQ0EtM2IwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDeGpVQq5XTXhSGOeAlfuEKIbg9Ail4aN2CM7+lyr+fcmTFjCNh +naWzgR0w6+MPLs7/XEMj1q5T1B83TAlok792M3jvHdWq9rJbV7Dxt8Kl9FDKJfq NBeLwsIMCK8FhwIa8AGXsakVsQ/uOl3Hzf7KzAXguOobVr5Vvlo/EEaCCR/bCdvP Kciwou2bLS63vkIiIc133FgOAWq38NFZz/KF9YgDJA/vtoxG0N9RPaY+gmAF3iey R6zPQMFuWHgMgmhU4QdUsTlcbZzGoX5+Xex0HvlDRBb6WONj6XNqKa+XqGGI+eg0 gROy0hUkq6hmmUxFLN9Y61rWfIUMPzEsIunrAgMBAAGjggJ5MIICdTAdBgNVHQ4E FgQUMRaRonVMwWo1VdlLIWJ3H6nme+YwHwYDVR0jBBgwFoAUsT7DaQP4v0cB1Jgm GggC72NkK8MwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr BgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMH8GCCsGAQUFBwEBBHMwcTAkBggr BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEkGCCsGAQUFBzAChj1o dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNl RVZSb290Q0EuY3J0MIGPBgNVHR8EgYcwgYQwQKA+oDyGOmh0dHA6Ly9jcmwzLmRp Z2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwQKA+ oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFu Y2VFVlJvb3RDQS5jcmwwgdwGA1UdIASB1DCB0TCBxgYKYIZIAYb9bAACBDCBtzAo BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBigYIKwYB BQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVz IGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50IGxvY2F0 ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL3JwYS11YTAGBgRVHSAAMA0G CSqGSIb3DQEBCwUAA4IBAQBfv3Ea6UPoVpMXl9e9qg4Oy1v9miRr1J7VZM/maYaf vgjEsBzq8bbUxVgWZlNtYVzRNFXp2V0KZvRSyXh1Oz0RMJHsnlFkwJu4T3Vr3O4P is4gwQA0YdZPf9qvpbyDIHaI0UY5/JSa9QmkTIUWAfogcnyySB5OWDCyHvyroaUn cjltfVqdbn+aYJzdJWx9ciOucHpP4QoJH7tSv2OOA52WKl1s7Gayn+58pPQJUtug GbasC1VJT6AZ5AEIfmCg82BZceXi5Rp9677564UHKCFRKwDuLEt/dSKog3xYiYon LYLN2Hw7ifA/NMACfSOdF7HnJ0u00e/T8MjQqgRPbXDX -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHpDCCBYygAwIBAgILbItGbUoEQ1rR+8wwDQYJKoZIhvcNAQELBQAwgawxCzAJ BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3Mg YXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMy ODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEnMCUGA1UEAxMeR2xvYmFs IENoYW1iZXJzaWduIFJvb3QgLSAyMDA4MB4XDTIwMDYwNDA4MDkyOFoXDTMwMDYw MjA4MDkyOFowgacxCzAJBgNVBAYTAlBUMUIwQAYDVQQKDDlNVUxUSUNFUlQgLSBT ZXJ2acOnb3MgZGUgQ2VydGlmaWNhw6fDo28gRWxlY3Ryw7NuaWNhIFMuQS4xIDAe BgNVBAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTIwMAYDVQQDDClNVUxUSUNF UlQgU1NMIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IDAwNTCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBAL/5JeQouzz6qT84UE5iwdM8qkbYQrKfj8riRiTA ejpQn/FgtYfDkv9w7eM0LX5araOxNqmW76oeJfjD0sK+nSKVALK7CNDsfDj5CqWe lF8Qjohnctv0N8ZCndvWnfQdBt7A2H/lq9IplE9KanFI1IFqu+rlxG37eMRXikyh j7H+m5ghl3BT+UetpKpFf7QyWHh08tJiUI1HP06pRIRlCp2pv8OIkscWV4svYwVG QJDnmS2lthirsdnszEVv0pcElVlpeVH5Y32YWQ/Oilr4OuHdUSpVGCXuhHoSMRXY QohRQTo2hzK2yo8DuPiL+6B97hgHlJgCoH61XjRnK80tAdGskUOLWAFJlabJneAP UAhAnp5c9kU/MkgQo55yERg7TQgLVd6E69pgKBHsHTouLV4AF07xv2PBIVovAaYg 2qJdM9oANbZaWLf3dQAaSo2qiSqjGTkssNYMlKCMJAK4bOtjPUHaU6mB9YQ0uuPl Tc5ZRd5yQ+tZaNMroLYNSFV5Z1KjRq8nbOlhGDSBeScmn8h71x19fXFWRqF8O50R Z2wS1ER7gYwORwhkgbgWJvDzoL8w16hbxsnQ36rfFb0O/3mB6o6Mx9uofYZNxXIB y1WCnYyPbfGb4D0e7Eh2AkQCAKRiA3IXjC2UyJ7H981Ur/zgdUBozgIynKxjfgIV dCM7AgMBAAGjggHIMIIBxDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQl oAEyqsp3o3q+54o6RIsZtU1ILTAfBgNVHSMEGDAWgBS5CcqcHtvTbDprru1U8VuT BjUuXjB9BggrBgEFBQcBAQRxMG8wRQYIKwYBBQUHMAKGOWh0dHA6Ly93d3cuY2Ft ZXJmaXJtYS5jb20vY2VydHMvcm9vdF9jaGFtYmVyc2lnbi0yMDA4LmNydDAmBggr BgEFBQcwAYYaaHR0cDovL29jc3AuY2FtZXJmaXJtYS5jb20wDgYDVR0PAQH/BAQD AgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATBABgNVHSAEOTA3MDUG BmeBDAECAjArMCkGCCsGAQUFBwIBFh1odHRwczovL3BvbGljeS5jYW1lcmZpcm1h LmNvbTB+BgNVHR8EdzB1MDigNqA0hjJodHRwOi8vY3JsLmNhbWVyZmlybWEuY29t L2NoYW1iZXJzaWducm9vdC0yMDA4LmNybDA5oDegNYYzaHR0cDovL2NybDEuY2Ft ZXJmaXJtYS5jb20vY2hhbWJlcnNpZ25yb290LTIwMDguY3JsMA0GCSqGSIb3DQEB CwUAA4ICAQCL8R+fQd2tTXZvoOzsLz3uZznUjI50muBlkR1aRLcN9EH4FEmNziKQ EGgKSEFwkJNVRsh/u19C3NcTQNKTQOxX7cyX6F9kxtijAjf5VcE69yn7i8QWyUsy yzETF2QMAmWJ4K3PwSHguoq5r/vOTmYJlJuNOKlfGC5SuhJaIVz+sqDBtung8Xzs MMolbexKj8qlfmGSwTk7mxSQdZEt4JuRHT8eD6BE0IxTzphQkhgxhgBSR9gLRL0K Ub3j/lOYsOyswwdajiyollFNplieTKmPnmSTj6jNDpCylEQ6vG7C3lR8VApyTWkS jaANf69OBqHs0CK2TXuMYGoZGFAMpYhSSHXY7ny9MDeqqDrBfA+IWO+sJu3K+Fd0 dX9l0ZyBA7zNNBwLX50RvRGV2OAMG62JnUpclmDLrqmmoP0FIvQnR25RvZs4KGHh OOAngsFqZz4c2OKUjMY7QnKQGjnDXxmMxdECQjb15gFzIchrL+0ar/5n3HBBYxSW i3UsfJ2zZc5YvBC4gMx1HorC6gS0aQsqEk4eDhnQVQ11n67rfdK3nY+oZEca755i ECBYeuQZCAe7OfPDRmoTT5N4PbVOni12L3GrNLQchyy3VuhZryXf3y3iK8YgMHM5 Mr07d/42P73iXUcPW7ROfvrZFVBs8APpVXQ8TKKxQ1oVfpnsicBYHg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9jCCA96gAwIBAgIQLKBTi7rBj09mERFTTwE4rjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw NjA5MDAwMDAwWhcNMzAwNjA5MjM1OTU5WjBxMQswCQYDVQQGEwJDTjEtMCsGA1UE Cgwk5LiK5rW36ZSQ5oiQ5L+h5oGv56eR5oqA5pyJ6ZmQ5YWs5Y+4MTMwMQYDVQQD DCrkuIrmtbfplJDmiJDkv6Hmga/np5HmioDmnInpmZDlhazlj7ggT1YgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDXS/F9OWsmfpE9Y4MHqqNYWhY9 95xpc/kUEM4bqR69Rln+7bHZLys5tOIIzZo6npbS9zU/5rG5RvGtMWOVuEJDsBbC bsvdJQq3WqQ5oWNm8BlnPrJlW5B+DWtZJooiH1BSqoJCM1IbrY/wOmllrUetVW4u Ns4MG1DIqiVToMXMVssrBoT6tPzM75V07aHW9EiyYDn6u8mnDOh8M0WZtv3ubotj igoZBnn8vEnQMgmdGX6Pl7JlHmwpvaWzcKzAxmSTTgDkxqkDkwbl8RJ2XaETTm0p 0YHnvBJaoKrhXRes9wweKxw2DaFJIAlveSRYgK99Kfp1rgeVQf3bOYK/+hXDAgMB AAGjggFwMIIBbDAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNV HQ4EFgQU6I2cdDR8/GtNhYqj+l7cDTgwNqwwDgYDVR0PAQH/BAQDAgGGMBIGA1Ud EwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIG A1UdIAQbMBkwDQYLKwYBBAGyMQECAlQwCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBD oEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZp Y2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKG Lmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBQUFDQS5jcnQw JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcN AQEMBQADggIBABH5mbpI4fMZOSrkr37xb9DnZS4n7ayskAx7l3S5p8t4BWoj73CK FFTOFbKMburdqCrhgEu3y3BEsLE8I5Zv9uoT4OKMQF9lJggRYAnI3iP49Gyghf4u oyEjj/hBDYkk+ZshsrMjw64f+pHgDLoCEzW6Z08vjgcp7OieSmpcXsYs7p4FrkiC jCv17Q8ECKUNJczz0U6GK5s3EXbaoV8MF1BsEUY1Yg36tsvyD3gPGuDMUfCkFRyu EqOrTUmkFp2h3AtOegDkku537GzzcKtsCz3LLlCYVc0j92tDabcb/FlDfaYdg8zX aPVuEd+/huw1edRQDbVNCH53DpH/IcdEDPuUg6ViZ2f5Ji1ld6+W80BhnoRmSr71 RwpkmvBDRHINKDZXM/0yPryMsJEwdA3MlqdHmqZ8mzRQ7mJGfKbFsZKVsgicKYIX BqEuKhQc4ZAPHk1xnueL6qGHun2BKSofPiOFycNoMgCJ7rOk+aYGGSyepi31x+d+ Uu18ELAnuGKFfUpO4q27n8zumK4ehsHfD+COxJx+qhE3zHv4QQBLrw92wWjM0+Cs O/8nZuXrNl2MASvNIoiwVLor4brfqGuH42bId2zu/qRw6o7B/+RkWxwPJ9deQclb xDJKGdT7C5fVlN6y/qauX46mMv9rCdkZOG4aB0BXjBztA/fkHdAUV8Uj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDDCCA/SgAwIBAgIQf2D5FE6hHhvlz3UHR0hbzTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw NjA5MDAwMDAwWhcNMzAwNjA5MjM1OTU5WjBxMQswCQYDVQQGEwJDTjEtMCsGA1UE Cgwk5LiK5rW36ZSQ5oiQ5L+h5oGv56eR5oqA5pyJ6ZmQ5YWs5Y+4MTMwMQYDVQQD DCrkuIrmtbfplJDmiJDkv6Hmga/np5HmioDmnInpmZDlhazlj7ggRVYgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJO0nF1oZhDxBlYvRz/HPf+wwj xFeNe+FYrZced3uagb/DsdI31Y0rdk0rr08Y46jYDvKA6mFyU3BqIpMBUBxYE9bp rKGFl15MFUFyk1It1X2Wocp7D4V1lo6mPLXEYXp6tKgFum69x4F0Rn0jdJYokLic TRY998EX2ct15e532mL6hezxEOWOiOiWHvyMVwk1WiQmzTSxu92meiX/6bAu9GqM gFYheYQSe1Z2GQfOKAM1yovx8F9vrtYJs3bNb0eNMMSy37SexUGJzPwRye54mdFJ 9eVqGNokuHVmotbtZLQWdoUF+sh32QhoRdriWoQBNsuNloJr8VtHQrCOO0CRAgMB AAGjggGGMIIBgjAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNV HQ4EFgQUul2vcDF0NefYqwuSC1nE1DIxqKIwDgYDVR0PAQH/BAQDAgGGMBIGA1Ud EwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgG A1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28u Y29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5j b20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYB BQUHAQEEZTBjMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20v VVNFUlRydXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51 c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBnqgc/935yMNwMMihvHae1 llMNn6hvXQ5auDpsO1DixqjcIMUyWv/719LKW/yLyed5P6UAk1uiXpoEp262emaT 7u7B3JFWu+oewI63OCIoyOXwxjAi1+oeec09JX+ixzGbbpgIU4qnR8MPgZNOZwcn crGGPzqaeY+YsOxTrMs9APpD1V8KOc3RoIus5qw4lP7REIBU/HYfHOg1E9BGzqrN lZF1qdjqU6NES8/rxHDsqCk/2S+wgUek3k9K1ZB5v4d3ugYQ4USG6LQs41GqqifH xHlcArYC4EOwK4jekXSCBzJsKXTPre9kEVTzPejdjyb1RDdAhwm+Q/y3sjNEYR+9 bt+9YHt2h/tre+9zRph5/h9H1QGBXkaglJzU8CCnUpUrJkW4/OqimKM8MDyYDrcO ugBNddsgaMQ+bBZVBj6kdrXJBR5lrl/T8zH71xttbmexzJGIltrCL7URFwxdTn5k AWVhab0VCoYVISR6y7I51Ap9uF1uCOq+dmwvEFanPxoUXyVDKtGZE4RPCJmj0Msw 7RMuMnHw0d0vO5JzzqHJL1T63HxGCLxWVSpm1ISAlEyDSm2CXVX7fNR9ny4kXtCF d+i5jRUMJHL0OPxnDjduQJ0QKkMjFV/KeYmW5XitEtFQp9xtuqbGR4/eQ0voJ07L OHmi6GFJfzipZDpfAV6fFw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9jCCA96gAwIBAgIQKxD7EhRcgCQj++wKwddc1zANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw NjA5MDAwMDAwWhcNMzAwNjA5MjM1OTU5WjB7MQswCQYDVQQGEwJDTjEtMCsGA1UE Cgwk5LiK5rW36ZSQ5oiQ5L+h5oGv56eR5oqA5pyJ6ZmQ5YWs5Y+4MT0wOwYDVQQD DDTkuIrmtbfplJDmiJDkv6Hmga/np5HmioDmnInpmZDlhazlj7ggU2VjdXJlIEVt YWlsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlsBtrkuQB5J8 1bb8H/C2i6GGYyBNUjsyglAQ2tWfXE43nGBLeWgA7By5ZJHtHXFYuPEj+X9dZG9h F280NtMnWGKCM7W+22Iu7Sp2TpSzoq121chmB9f730afItGVH0JOapf1L9eEz52i HJYMrcxDzf1H8hAqiiP2VHzRjzfO83YVeOlvk1wRo/Mqm3pW/cs+u/zZF8+thpa2 aGftI7tAh9aKJ/gfjygiOq78b5gwo6B4OftwoLqCfVE66gzuEd+j5ZlcRMi9uA5P mHmT4Gje4aKae76PrCGujl1nFXpMcK6iFwOqTvCo3HdHW/SaUXHoARCF1TTt8/sP 0iTI7yGCBwIDAQABo4IBZjCCAWIwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd 8rIDZsswHQYDVR0OBBYEFCv24JBSXgKXjqthjIibPUVdDjHEMA4GA1UdDwEB/wQE AwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr BgEFBQcDBDAYBgNVHSAEETAPMA0GCysGAQQBsjEBAgJUMFAGA1UdHwRJMEcwRaBD oEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZp Y2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKG Lmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBQUFDQS5jcnQw JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcN AQEMBQADggIBAAwEYnm3JK0Qgv9dH0Tzw7FKXnrcjfx99NL10vUyESKaH/7PGUxW 4ZZKBUUWu59dDqid6pEih2lCYpAvy/NOMbqL6F+aNE1bDA1ZDS5dkGvca+LB5Oqn K9DuPIFU7UDe1A9ZqYR0bYLdoc4jBtLPf6ofIoir5d5RAczfsMvLSR1nD8OLkwhp JOUNeyEbam5TwxSEAdMBZvYfqZaFQTuQhxx74cIry8OIjNBb/kvYXhstsGFlNKRf l+x3760cNokSFRnB2FC4j6xJX+Z0dMoBUX2mHFqNSudjFEKewG6xcnTTHYfAIUWc iRzg8A/G2deojBdRDwzvXPbOAEKvguBfpUDVB3r66gBm1sn09UWddbcWVa+bdeDG GgQ9HKznF/i8FVxvfiWF9WKL5OEeUWXzMm+4sJLKyeJttzKDTIBHvU7sBlICyjfg 5UWlfyhxaK+5PsBLgEo8rjJz8TyCNGDrSiCgZwgD3hagn1ZEIEuiMNGf/jFVFDJY CognuYHqXPDQB1oBuJgCU3kZCxd0Ps8T3AchzDqI/BVZe4Kz3Yl8866PflwAOFcj L2GdZsRkbI3SaruyiX0OR3vCYiNYMf6b8X3ZZ2YJ17B13ASLapfYX78Yw9+xn61Y jiw5qlGDA8eo8RgXbm+cLxBDoXkbq+y1Fsqk7M0mpIqaK83+sAcVtFuj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9jCCA96gAwIBAgIQC4BruOGpKB2Qlx9HCMmv/TANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw NjA5MDAwMDAwWhcNMzAwNjA5MjM1OTU5WjBxMQswCQYDVQQGEwJDTjEtMCsGA1UE Cgwk5LiK5rW36ZSQ5oiQ5L+h5oGv56eR5oqA5pyJ6ZmQ5YWs5Y+4MTMwMQYDVQQD DCrkuIrmtbfplJDmiJDkv6Hmga/np5HmioDmnInpmZDlhazlj7ggRFYgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPXDYZzbcqm0YfHlUyNK9hHNuY kLy8wgpx2/5mYtLR8S3hJbe1V1wPGpvwlzbI+vbFPwMJ9nyi/Cuq1idC3w9q6RLj 0nBYsVk9FRIWtPr/+LnFR07hfgF3wK1ZUDV0zRmjIsfPGbIjegad01hhZhpz6HcI cu6omAa/gcvvRak3Ywsj9mfnnou/BaSCJuJtlh4XH0Eak52fhHluKhuTY0x5I7Un C/jG39K7uXGsdRqopiajK0g5NdtTwiS+3uF6ywsBgcg9bRkwoFD60dEfKh94UKhi p5f/iz+EEaLsHtapk/E+RVqjqetlojEI1q1ILOYwF7YaSsAQklfCg+EjHbv7AgMB AAGjggFwMIIBbDAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNV HQ4EFgQUWVA5MpiLt8cTdszwEGixvXQHpi0wDgYDVR0PAQH/BAQDAgGGMBIGA1Ud EwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIG A1UdIAQbMBkwDQYLKwYBBAGyMQECAlQwCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBD oEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZp Y2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKG Lmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBQUFDQS5jcnQw JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcN AQEMBQADggIBAARABbXPNlFOB89JgihpucRWtPZ/oqo2+gD253F96ejik70JDUq4 E2VEg+4JJCIXJdxJYhVhYOTwzsbdzFn6tiecj7yB2RVQnsjA0DfkRjgJb9ZksSY2 rR9bwwyZDprQCyqKZ5O9TAP9OyvTGix7973K0chqpnmLpqhWg8LeyuW4KMaY8WHk YLb0VIEvaSQcOjpZLJeOXSzwMkmWqlCiF1sDMyIvBr1/u3kGetOaTbamT6DeB9Uu 8FxKJyR8S9vqdWQJEVtfpQArV8OXxMFpvSGcfELcFZGdZg3l70hqGXY4Cunc9o5v qqD4rdaSzNHu/9fdWfZ+GGrABFxN+HEhyV2RXIOZWFor1PSgfQlviXQTGGa5C2L7 9TTUvJvNcK2rzm17FFZc+/QJNksoSm48Out1Yim7HWUvUke/cBY6gUWvKC+CJ3/k wjee6AjtZ0cejlauQB7eOUGbMVrnLpW/dvLZy4kbjcNlvKstTWochF79t3LGoLqp KPm/K8XuITo3gH/rHodLW3tHDazCp8qTXwAEdY3ZuykEDUU2TiBttNEGidTUDHdC inLfbWsqSNwrwGfJJ1a+K+1xJaMNr6YAOvFiqzb26s9vUrpjgFv5KCUYik5OeA7S auzBC4NVKFgxjZP1Z8SBEH6OpXy/LRypMkXVG3cwi4X/EhrVLUsziN+T -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFiTCCBHGgAwIBAgIQBNu9QFVDvD/toNREACqasjANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwNjA5MTI1NDAzWhcNMzAwNjA5MTI1NDAzWjBWMQswCQYDVQQG EwJBVTEXMBUGA1UEChMOTkJOIENvIExpbWl0ZWQxLjAsBgNVBAMTJU5CTiBDTyBM aW1pdGVkIFB1YmxpYyBJc3N1aW5nIENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDMVZXJwRWqDSrfP3/gXy99eQN73EgjdwJxrwKe4UoDQ3W8 53vUgDYQGyLVga9tLuEV17XOUnamlpuh9+NGhP+IS1ihhJNr9V7c0vX3dcAVdvAm qss5Xe5R+hjEObbQNFykqKiznekYRqdA7UFBQcybdoe3QpvBRZ+KNlDAfzjPPwAv 2dHC2swL0pg2SXLKnCEuzKsyXdvPMAcYLmXSLjs35jUe3ds2pzd+h3DDlo+A5CQd OSSUMX6DSuhJZ1t2s2Hmf9Nd+3pks0fx/Lzce3XZtzQFJAYpVntubwJbFTjKqrXJ LYD9ZN6j8FDboRY/l9G25GTryciHeeoLBhvcKWW3AgMBAAGjggJCMIICPjAdBgNV HQ4EFgQU3vjrSMgLXYCCfYB4IBV5uLLDCJ4wHwYDVR0jBBgwFoAUzsNKuZlV8rjb YL+pfr1WtZc2p9YwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMC BggrBgEFBQcDBDASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAk BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMIGBBgNVHR8EejB4 MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVk SURSb290RzIuY3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGln aUNlcnRBc3N1cmVkSURSb290RzIuY3JsMIHTBgNVHSAEgcswgcgwgcUGCWCGSAGG /WwFAjCBtzAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ UzCBigYIKwYBBQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNv bnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVt ZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL3JwYS11YTAp BgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRRGlnaUNlcnRQS0ktMy0xOTYwDQYJKoZI hvcNAQELBQADggEBAAakQjzsnGTxNBTqp7weVZ431B/zVqi3Hi9GXIoM21EFD1RL 7W4R54xNX0baTiGupxtcod+R6MaGq/2SVNwHyEwA8o2H31U6aswXO0G1V0y2ESNa hWm73au/CrJx3P6r4IOgxdvF1D2T4AkQH5JJwf86takSosnKLVUUYRgDpwHAsexQ /gy8172A/BrPP7BUdxY9nP9MmGpECUmhNqnjA9LKH/nWItLrSaCPYz5vsvWWoUHW vugR+bBBzURC0YxQiphyBz1r4vFWWOXnMjkYyLx80vCtBlab+4Y3i53OVpNPYXeu v1+fatrNKCnsmKjVf2lnC4U2U1o1bb+KN6RuJ8A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFADCCA+igAwIBAgIQBaqk8rvBAqYMJoom/W4eUzANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDA2MDkxMjU0MzJaFw0zMDA2MDkxMjU0MzJaMEQxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFUdlb1RydXN0IFJTQSBD TiBDQSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANv66EW9JqB2 v9PiD5IJhMyhq2eyfd6jry6jZ1LZlhO5BLFgSw++pHLnWd580jHYHUST6/rd3t4f vlbgKXO5zcDtDs7oyQlsumJz5+I4xk/g+hfIcHEcJXPliAXbWUrhWMHgfnVa6dum p0QVSLiLpIE2EAkCPFIbpEA0xdNPyrBa6sep9l25E3cpx38sfWd1pQjdflNmDxAm Pup+lB6d7p6JKTiwoSHUW+hzLqEgF/dFNbVddV6K1Dsz5oi8Vwpo7/ZbAQMPVOFr mtnRwmDi3ks0vJdZFOXRqln+ruj9dpkTmXKt70AgfpqF/pRDbJO9Ph965PDnl2k3 N3vhp1CYta8CAwEAAaOCAc8wggHLMB0GA1UdDgQWBBRHFCZczI0niilBbEMwlRtF L8R1yDAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8E BAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI MAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz cC5kaWdpY2VydC5jbjBABgNVHR8EOTA3MDWgM6Axhi9odHRwOi8vY3JsLmRpZ2lj ZXJ0LmNuL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDCBzgYDVR0gBIHGMIHDMIHA BgRVHSAAMIG3MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v Q1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUg Y29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBBZ3Jl ZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5kaWdpY2VydC5jb20vcnBhLXVh MA0GCSqGSIb3DQEBCwUAA4IBAQCxMnN/9QbsmupckpJnA0U55GCuZlzkEegalVg+ fT8OaCslKOKnbNV9dDzsZwuxx89CXj2pVHEUPjIGdbB0fGnfreDS3za94jOi0L9M 29N9380NTixcUZRRJ4X+gzFNX5doNWCBIUuvnRI+o74RKUlrcZcT6rAUw9xGH+CA K1WTjaRt8ysYGI/x1uQnwFe6GkcrnZ7QcOdha8sbNcfyQNAAHmD4eL0hJjnebCT8 Vt8OlJIo6ett6BndhsOK3GQgtGeX+2U6m6rE0sR6Z9TdwmBWucfwpMH9pdddwgI9 q7mXJLtKZPoQSo+9eEKVwogdrkaM6h+KajLfCCIft5CsWtEb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDozCCAougAwIBAgIQD1GIO1682ob2anzIe5cQxDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDA2MDkxMjU0NDNaFw0zMDA2MDkxMjU0NDNaMEQxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFUdlb1RydXN0IEVDQyBD TiBDQSBHMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJgnRydCw9b+bQ8DBBQh j6+16m0Qr172AMXCGnIXGGiaaOLHOWIIbHsrXiYtlvLDMxFvm0CseFdn80IE2InG U5ajggE9MIIBOTAdBgNVHQ4EFgQU9/ze19+gtwn8gAv4hnIBtngxD+swHwYDVR0j BBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDMG CCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZGlnaWNlcnQu Y24wQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL2NybC5kaWdpY2VydC5jbi9EaWdp Q2VydEdsb2JhbFJvb3RDQS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYB BQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQEL BQADggEBALhHNFzIF/V0kfVruGl2sjHobWuHxwXZ30/XAYG2TkU87u7wIuHEiGwq CXzwbnHy4mGVEQj3+nj/ObFEQsWhI7YV9Enwt7nlYxcvvhDFh/L9VTdPOfh9UdL1 AJRS2yX5RSemC2A4owYv0xVxGQgPbvjk3hGgVwadpJFzuJK9k0kfc4MopUI5yDB+ hcUIMffJO84rstzg0kHykudc/o6DFxBo1VXDZG6hL2sQmDZTopBpkfcP4ZcDT5tC rwlXEL4NrAo4pNv27rhgQI61CzouO+bZPeCoaHOUAiRH3pN0IEzu6KtjrCUPeqyd ScpWRe7jG4COQDWehOKM3w78lfxfMA0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFHDCCBASgAwIBAgIQBg1bPA4gYzI0+zXlAjzBaDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDA2MDkxMjU1MzhaFw0zMDA2MDkxMjU1MzhaMEsxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJTAjBgNVBAMTHERpZ2lDZXJ0IFRydXN0 IFNlcnZpY2UgQ0EgRzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDI kwhLLm8Lh0DZ0Gw9PvUiWqk4ryzA2zdvu1+ynTNAnpZlPKIIRSWnPQY1ecUzUyO8 /g8s3mEoNWsFphrl45qLmU2GaV4NBJiYEBFzegmi1unZYkjmpxtlXiOdiV9EpQ0q hG3VwlFatMhB9rL2rLWx6A4Zg5whb+sxPlC+90lTaEESRnRYhUbo9e0RsuSH9WD9 Q6yFSybuKwGwI1CvGYxObkvcO3hBVCnqVcmRktUNfDp3vxwF3HS6Z96CCA246SZY dyhGwuq2F0c7dKZ1MvtxfXc3/kbIRa6aBzwsuALdmcr6XqDwvnHS5vJcAAgplCkc h7P8QTBQSGktxV1DA0vHAgMBAAGjggHkMIIB4DAdBgNVHQ4EFgQUu+fGIAov3JYb 577Kg2Div6Bq3EcwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYD VR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNV HRMBAf8EBTADAQH/MD8GCCsGAQUFBwEBBDMwMTAvBggrBgEFBQcwAYYjaHR0cDov L29jc3AuZGlnaWNlcnQtdmFsaWRhdGlvbi5jb20wTAYDVR0fBEUwQzBBoD+gPYY7 aHR0cDovL2NybC5kaWdpY2VydC12YWxpZGF0aW9uLmNvbS9EaWdpQ2VydEdsb2Jh bFJvb3RDQS5jcmwwgc4GA1UdIASBxjCBwzCBwAYEVR0gADCBtzAoBggrBgEFBQcC ARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBigYIKwYBBQUHAgIwfgx8 QW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFu Y2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0 cHM6Ly93d3cuZGlnaWNlcnQuY29tL3JwYS11YTANBgkqhkiG9w0BAQsFAAOCAQEA aN9N4B6lCvTi5S4vUFLSLLY/WQyT8YNi2e2v6D2BH6yiANADnsJ4PWNjh6BSXLd8 4KpbcZ7UgQt6ex2C48szfSQjpqt7Of8MXTNnt1dqGFc/noEVksaCgnhZx5wt2vyT Vav5ypnEE+9Q8Bi20IK7cYr95hiKi15sX+39NUskbMVsVMVJXJE/4SydeoCMg5dh 5xprJ9g/0Bl6m/NdKsgrTqDwP952daWcFLvQMvYgPP3GfT7oBNuFDjWnDh67NzEC 8UKjieKwA+1Afj/RGbXfwA/dZHi5KhMvJw+615+ZXJcdBC2M2MhJhrlBDxk8g3FM gX3bPJWD13jb5PCM7Oqlcg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIQDaLXyI4fEuNfySxqGup6YjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDA2MTIxMjQ0MjdaFw0zMDA2MTIxMjQ0MjdaME8xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKTAnBgNVBAMTIERpZ2lDZXJ0IFRydXN0 IFNlcnZpY2UgRUNDIENBIEcyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEN7wG kNoeVd8Cxok+U2HpUrCARp7mEDj2+9WFbEt7m5h/cFrKN/+9x4vVcVCRm4JtURM/ 6gShF4JjOVMidGksP6OCAVIwggFOMB0GA1UdDgQWBBQu05Kw1wrvgYxSrV73plOC jqde1jAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8E BAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQF MAMBAf8wPwYIKwYBBQUHAQEEMzAxMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5k aWdpY2VydC12YWxpZGF0aW9uLmNvbTBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8v Y3JsLmRpZ2ljZXJ0LXZhbGlkYXRpb24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENB LmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93 d3cuZGlnaWNlcnQuY29tL0NQUzANBgkqhkiG9w0BAQsFAAOCAQEA4Gj2ZFZ3Yslj rnveii9ouDFql7owz1+Ycb8uuX5L5qjmFNEowPYuqmorPYanVk4Hzs8C3b1hJ7dU b7GgmCmZXQ2q65+4vnW/qmiJJYhqBdGYGFOuqd6nX3ZFYqq0Y+Q+6KPX+kRV6vG5 GqXsvM9BecJvI0064M17bLQ99GVPh0vYs8p8kCMaVxrsOG+sr0Xo2UjDLZv3LOiv 4Ctc+5qEsTGKGyWBvgLNEtQXh7IR0HK9HKrO6GCDSQZfrxr8b+4z7eDHhCk5yt7z NbxgXRHAjtqway7EP5OaQMrn5lb9agqBvHb4SW4IZscBtYb6tgkjZdhuY+VHwCbq 2wa6XsscYQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGJTCCBQ2gAwIBAgIOSUEs5ABrfCJra1ao+20wDQYJKoZIhvcNAQELBQAwgacx CzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEVMBMGA1UECgwMTmV0TG9j ayBLZnQuMTcwNQYDVQQLDC5UYW7DunPDrXR2w6FueWtpYWTDs2sgKENlcnRpZmlj YXRpb24gU2VydmljZXMpMTUwMwYDVQQDDCxOZXRMb2NrIEFyYW55IChDbGFzcyBH b2xkKSBGxZF0YW7DunPDrXR2w6FueTAeFw0yMDA2MTcxMDA5MzNaFw0yODA5MTcx MDA5MzNaME0xCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEVMBMGA1UE CgwMTkVUTE9DSyBMdGQuMRQwEgYDVQQDDAtNS0IgU3ViQ0EgNTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALcBXbJEUXFl1/F6rPW0Sfulxyb2PUGGocIc PIWVCyud045B/zDO5KDyP317KRfetMsPDUWDCLmKXCFcVD6KXzmlLDNkyfaqESNz 8CCiTR+gvAKPqyZ0qUAH6qO4NPDF2NzEh778Y/Dg+5mkYY3aY2KSOG7EnUkba6Ga pNzHO3C10C7R7hZrZbgZ9YPJkQveAysFFoWs5bNRgKevn4J7x2+uQjylGVEw6xTM SiuPHfaz5DMAu8bDk131rg5ATfCmvBx+uAaOQWnz41Hz56JJf1d1Q3mTYi2+12bY 2aOvOLonR7pES3jfPEszle7Bypjkq/ySUR0iJmq1m/aEVJfyWAkCAwEAAaOCAqYw ggKiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaA FMz6Z5PwtrjQpcAe81P9jFPfg9eWMB0GA1UdDgQWBBTe7bJVc1AbOmR2hxt3VRLe wSrwcDCCAT4GCCsGAQUFBwEBBIIBMDCCASwwLAYIKwYBBQUHMAGGIGh0dHA6Ly9v Y3NwMS5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRwOi8vb2Nz cDIubmV0bG9jay5odS9nb2xkLmNnaTAsBggrBgEFBQcwAYYgaHR0cDovL29jc3Az Lm5ldGxvY2suaHUvZ29sZC5jZ2kwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWExLm5l dGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0dHA6Ly9h aWEyLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwNAYIKwYBBQUHMAKGKGh0 dHA6Ly9haWEzLm5ldGxvY2suaHUvaW5kZXguY2dpP2NhPWdvbGQwgZ4GA1UdHwSB ljCBkzAvoC2gK4YpaHR0cDovL2NybDEubmV0bG9jay5odS9pbmRleC5jZ2k/Y3Js PWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwyLm5ldGxvY2suaHUvaW5kZXguY2dpP2Ny bD1nb2xkMC+gLaArhilodHRwOi8vY3JsMy5uZXRsb2NrLmh1L2luZGV4LmNnaT9j cmw9Z29sZDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDov L3d3dy5uZXRsb2NrLmh1L2RvY3MwHwYDVR0lBBgwFgYKKwYBBAGCNwoDDAYIKwYB BQUHAwQwDQYJKoZIhvcNAQELBQADggEBAL+8wgsjxxeyL6UoFWOc1ucpK5booX7w iVLEadCHBU+Ql2Ye7LtS+c65tqcvrXrRdwSiD6QUswYQJyd5IZtHvCQ2xA/pJW0m Re4kfBltKkTwS5+QN6SxeRiCYc94/+AfZVsAa3eyQCXBfUkkJ1K/l0cmq6FAsi/n kjLP/bUYiqPsFH8R1+MzYFr/Yt8YAiiZc2oohrW6NdM5Vd9kJ3DFPAFWJLDmBVMB OvnnTTdNAZ2DuHRbiNwIqiP+QIYuQmDKIkrKkanhetRpY9Kzbni4imhYlZ2wNGJq MlUiqjvEzhxmmJ6JAUmjmpIfTL4xad8AkEG+E2NgrovPKGpARapHK50= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYjCCBEqgAwIBAgIQd70NbNs2+RrqIQ/E8FjTDTANBgkqhkiG9w0BAQsFADBX MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIwMDYx OTAwMDA0MloXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFIx MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAthECix7joXebO9y/lD63 ladAPKH9gvl9MgaCcfb2jH/76Nu8ai6Xl6OMS/kr9rH5zoQdsfnFl97vufKj6bwS iV6nqlKr+CMny6SxnGPb15l+8Ape62im9MZaRw1NEDPjTrETo8gYbEvs/AmQ351k KSUjB6G00j0uYODP0gmHu81I8E3CwnqIiru6z1kZ1q+PsAewnjHxgsHA3y6mbWwZ DrXYfiYaRQM9sHmklCitD38m5agI/pboPGiUU+6DOogrFZYJsuB6jC511pzrp1Zk j5ZPaK49l8KEj8C8QMALXL32h7M1bKwYUH+E4EzNktMg6TO8UpmvMrUpsyUqtEj5 cuHKZPfmghCN6J3Cioj6OGaK/GP5Afl4/Xtcd/p2h/rs37EOeZVXtL0m79YB0esW CruOC7XFxYpVq9Os6pFLKcwZpDIlTirxZUTQAs6qzkm06p98g7BAe+dDq6dso499 iYH6TKX/1Y7DzkvgtdizjkXPdsDtQCv9Uw+wp9U7DbGKogPeMa3Md+pvez7W35Ei Eua++tgy/BBjFFFy3l3WFpO9KWgz7zpm7AeKJt8T11dleCfeXkkUAKIAf5qoIbap sZWwpbkNFhHax2xIPEDgfg1azVY80ZcFuctL7TlLnMQ/0lUTbiSw1nH69MG6zO0b 9f6BQdgAmD06yK56mDcYBZUCAwEAAaOCATgwggE0MA4GA1UdDwEB/wQEAwIBhjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTkrysmcRorSCeFL1JmLO/wiRNxPjAf BgNVHSMEGDAWgBRge2YaRQ2XyolQL30EzTSo//z9SzBgBggrBgEFBQcBAQRUMFIw JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnBraS5nb29nL2dzcjEwKQYIKwYBBQUH MAKGHWh0dHA6Ly9wa2kuZ29vZy9nc3IxL2dzcjEuY3J0MDIGA1UdHwQrMCkwJ6Al oCOGIWh0dHA6Ly9jcmwucGtpLmdvb2cvZ3NyMS9nc3IxLmNybDA7BgNVHSAENDAy MAgGBmeBDAECATAIBgZngQwBAgIwDQYLKwYBBAHWeQIFAwIwDQYLKwYBBAHWeQIF AwMwDQYJKoZIhvcNAQELBQADggEBADSkHrEoo9C0dhemMXoh6dFSPsjbdBZBiLg9 NR3t5P+T4Vxfq7vqfM/b5A3Ri1fyJm9bvhdGaJQ3b2t6yMAYN/olUazsaL+yyEn9 WprKASOshIArAoyZl+tJaox118fessmXn1hIVw41oeQa1v1vg4Fv74zPl6/AhSrw 9U5pCZEt4Wi4wStz6dTZ/CLANx8LZh1J7QJVj2fhMtfTJr9w4z30Z209fOU0iOMy +qduBmpvvYuR7hZL6Dupszfnw0Skfths18dG9ZKb59UhvmaSGZRVbNQpsg3BZlvi d0lIKO2d1xozclOzgjXPYovJJIultzkMu34qQb9Sz/yilrbCgj8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFUzCCBDugAwIBAgIQC3ITqfbjiPK/YCLdc2Oe0DANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0yMDA3MDIxMjQyMTVaFw0zMDA3MDIxMjQyMTVaMFsxCzAJBgNVBAYTAkRF MSEwHwYDVQQKExhMZWdhY3kgVGVjaG5vbG9naWVzIEdtYkgxKTAnBgNVBAMTIExl Z2FjeSBUZWNobm9sb2dpZXMgSW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAtKyHxVHwLzxaKUfUkDGEaPL2EeBRkPM8XOo3AIaLHhtG jUQ4dnweBSFtmTf8xXwMcN+MFLLuG6FY9+g/n7RZwplpcnaITSn1xg5OL65RypRp AnGZ7DVS/DLYdbifu77N2liM6TJZtqUCuCS6rn3SdWNlyyZJ6L8ifHHclIwArZKu XKYzlFLkLOvxtstcL1uCy0ct1qnwrSukQTjvlymmK7mY2BBCZeR5+D+U366WCkyD rFfsR419d7MFKXSjVocVN1DM7nZHxsX19ms/J1b+SatzyBjXx9dIb3nsUcO54iV+ zh5QRf6qIoJRnK0RF64LxRfzirKiCcYvsGZ8mprGIQIDAQABo4ICCzCCAgcwHQYD VR0OBBYEFO9UC2XGNdXx4nGuntnFJ+oXYancMB8GA1UdIwQYMBaAFE4iVCAYlebj buYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYw JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTB7BgNVHR8EdDBy MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxS b290RzIuY3JsMDegNaAzhjFodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNl cnRHbG9iYWxSb290RzIuY3JsMIHOBgNVHSAEgcYwgcMwgcAGBFUdIAAwgbcwKAYI KwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUF BwICMH4MfEFueSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBh Y2NlcHRhbmNlIG9mIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVk IGF0IGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwDQYJKoZIhvcNAQEL BQADggEBAGZxjeLaWCcmYQVQ2IzVogI84UumqHvVvbMERwOYxIPcaTnZim3+8sJb PjipkfDP2YEhok+b4MTNXfKLJVfCdhMLXAq2l13l7X0v6S4zcXvp5SPcMTQCzwUY AXEC1rbHP/SJzqe8cAq0fj9hmpEw5U/VfP9u6CAyUM6/vGpoZYwja1apA/J84KDD V4ubiWgj+8KvEjHVNLzWts2fyuEYGAyNq2Y6f2JDc5yFmBcM1cAkbVy9SHAmnH8p f/YIE7vWn5g5LFfpUbt0tnIi+6LlZKclXx06QcbPHjtV1sBn3KNBXJPB23IViHNG wj/QoKrz2KMrOJPN/ru+79Ep8G12UnI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFPDCCBCSgAwIBAgIQAWePH++IIlXYsKcOa3uyIDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0yMDA3MDIxMjQyNTBaFw0zMDA3MDIxMjQyNTBaMEQxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFURpZ2lDZXJ0IEVWIFJT QSBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK0eZsx/neTr f4MXJz0R2fJTIDfN8AwUAu7hy4gI0vp7O8LAAHx2h3bbf8wl+pGMSxaJK9ffDDCD 63FqqFBqE9eTmo3RkgQhlu55a04LsXRLcK6crkBOO0djdonybmhrfGrtBqYvbRat xenkv0Sg4frhRl4wYh4dnW0LOVRGhbt1G5Q19zm9CqMlq7LlUdAE+6d3a5++ppfG cnWLmbEVEcLHPAnbl+/iKauQpQlU1Mi+wEBnjE5tK8Q778naXnF+DsedQJ7NEi+b QoonTHEz9ryeEcUHuQTv7nApa/zCqes5lXn1pMs4LZJ3SVgbkTLj+RbBov/uiwTX tkBEWawvZH8CAwEAAaOCAgswggIHMB0GA1UdDgQWBBRqTlC/mGidW3sgddRZAXlI ZpIyBjAfBgNVHSMEGDAWgBROIlQgGJXm427mD/r6uRLtBhePOTAOBgNVHQ8BAf8E BAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI MAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5kaWdpY2VydC5jb20wewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2NybDMuZGln aWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDA3oDWgM4YxaHR0cDov L2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDCBzgYD VR0gBIHGMIHDMIHABgRVHSAAMIG3MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k aWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMg Q2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUgUmVseWlu ZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5kaWdpY2Vy dC5jb20vcnBhLXVhMA0GCSqGSIb3DQEBCwUAA4IBAQBSMgrCdY2+O9spnYNvwHiG +9lCJbyELR0UsoLwpzGpSdkHD7pVDDFJm3//B8Es+17T1o5Hat+HRDsvRr7d3MEy o9iXkkxLhKEgApA2Ft2eZfPrTolc95PwSWnn3FZ8BhdGO4brTA4+zkPSKoMXi/X+ WLBNN29Z/nbCS7H/qLGt7gViEvTIdU8x+H4l/XigZMUDaVmJ+B5d7cwSK7yOoQdf oIBGmA5Mp4LhMzo52rf//kXPfE3wYIZVHqVuxxlnTkFYmffCX9/Lon7SWaGdg6Rc k4RHhHLWtmz2lTZ5CEo2ljDsGzCFGJP7oT4q6Q8oFC38irvdKIJ95cUxYzj4tnOI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFPDCCBCSgAwIBAgIQDWASYsinchpuqwNh5WGVgDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0yMDA3MDIxMjQyNTdaFw0zMDA3MDIxMjQyNTdaMEQxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFUdlb1RydXN0IEVWIFJT QSBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDSvFMMGIOI D2N+rpyaGTPfyItp3atCyimRJCPtAakU984EB19Zugrb82ui0iy0zLKMDrOuN+Ku H6jF4F4ZCoHjN7tFdMtSsCUAbrpFVO/5BLY+VTIg7YUN5LwRHUb2QVSGwKyIeYS+ SqPV8mzTMkG9GnWjG1IQT0F1+Xu7+uAGRFVnIdYCSBgl7iG4qOWZjcPKnW+3OJRO dZtwGE39E7WoasoW8Nvpu5FFp2WIsvY6B/0whr3w+xKeBYb2WNKI1ZXvk4y+AmUa BdRTY0HPBZ4+6Ipcq2Rl+QLQXQuGXH95YujYNYpbnV7ASU5/dVmqVPY0LHnp2sNK IN65/n+DbcsCAwEAAaOCAgswggIHMB0GA1UdDgQWBBQo0s/uCYR13bWytb881aDG c4hdHzAfBgNVHSMEGDAWgBROIlQgGJXm427mD/r6uRLtBhePOTAOBgNVHQ8BAf8E BAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI MAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5kaWdpY2VydC5jb20wewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2NybDMuZGln aWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDA3oDWgM4YxaHR0cDov L2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDCBzgYD VR0gBIHGMIHDMIHABgRVHSAAMIG3MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k aWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcCAjB+DHxBbnkgdXNlIG9mIHRoaXMg Q2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNjZXB0YW5jZSBvZiB0aGUgUmVseWlu ZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBhdCBodHRwczovL3d3dy5kaWdpY2Vy dC5jb20vcnBhLXVhMA0GCSqGSIb3DQEBCwUAA4IBAQBVbQs8KD6qRnOf/dtOHNAy ieoRcA1Zk3lGMLwqNfuLpTb9gDQFpvxGN/3X7i0mAEtRhN/r9fDv8oiVLn6gfpm0 UUN47vFJCzf5dqkV/N7LkMTqlhDA0Ve/GBJ3A2E5yFT7TgAGN4wJ9cCZrKbqKHVU RatwJ+T58jmhbvtEM7t2ucB7u+Dmu4KoOTEx8LR8+qn8OyLh1VLq75vzDTsnhTN5 3AgPdMVFk6F8sjT2P2xbvAb0kAlyAtldAtpGvBzXhacmRs7rTqz/oTDwYZLkrm+q EltdmGwUOWvFPjwucH6tS+gQgiUYiNJqijzI1jr8TZ01VGOSTW7rRUKgkN5WJqDA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFOjCCBCKgAwIBAgIQB8LG0yxvDgqrrA3Q+fzVszANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0yMDA3MDIxMjQzMDJaFw0zMDA3MDIxMjQzMDJaMEIxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHDAaBgNVBAMTE1RoYXd0ZSBFViBSU0Eg Q0EgRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ6jsIHs3bmIoe 7DvnuSvGX375jpWKv25Gf7uz8GZQT3DFVHeRS0NKn5WosqMVNYJKKEImR1Gb2dxl 90/GDypngguJeBVxdTtgGWPpGnuKPXfc6Qy8yKS1SRQsEs2q2EHl0tEU+/vyNro0 DDZcox947My8htb1dLx0Q/y9KjEuagQ5AXeLidtiaiAyKnThZRslD8EK/EcHRvkP AVMSfGyCVmho3VLBP7LAlLA/RyrAX282OfK8lPZqsASNsOQhmsZPT3IuQhXz7RXc nCpBM+GfZoFSP6+uO5j8TZMkqLTAuVAsSyGY8zNbzYupA7QmPcIfAwqG1oD9dGah 2GgKoeTnAgMBAAGjggILMIICBzAdBgNVHQ4EFgQUbC7kYbTDub3wyq2mwWh6uNTM HaAwHwYDVR0jBBgwFoAUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQD AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au ZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwN6A1oDOGMWh0dHA6Ly9j cmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwgc4GA1Ud IASBxjCBwzCBwAYEVR0gADCBtzAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGln aWNlcnQuY29tL0NQUzCBigYIKwYBBQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENl cnRpZmljYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcg UGFydHkgQWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQu Y29tL3JwYS11YTANBgkqhkiG9w0BAQsFAAOCAQEADf6H4Rxu128yUZjIR/vkWEv0 PnYKWUQkGXwbqaioq/zjVC/+LrIwBKwEH2aBQyBO/uvMwF+4PSThZKinw51Pfp8w PcaBMeuQR1PEIYjQN3+NjRpMIFb2CUtbnMsHybKqKSW3rsTT2r2EIBtDrZ3EfeEg 5bfneV6PKvGqcQRZq5BBNTH11tedhcLJB+7F7GRVz8cKCTz0INpQk8gthjBND1+7 CR+ZHTWPqdXGRqiFJ09NTVmohj4dgL3VyOIArpmPbigODbp80fxzoQJepkHFef6q mniWnIl7HApTrTIV/UN22gbCcL5dosGv69wnOVQomQsalcOkujetA5BruTiB9A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGbjCCBVagAwIBAgIQAf0pjz0zJHWvKD7zSGgdczANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwNzAyMTI0MzE4WhcNMzAwNzAyMTI0MzE4WjBAMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMVk13YXJlLCBJbmMuMRowGAYDVQQDExFWTXdhcmUgSXNz dWluZyBTTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMeJ/piY0bC1 3OibGu9qMIAHARH9ossB6+zihswhLxRHGfu7kAHZ28w6RLTD1fB/Q3gLhMuvchUA GjzbTPKd0RtwRoVvE5G3XQeeHRpefxKmo1sjM/z9ew+a5dp0L/3cFwdpkiETYlS+ qRzLV0qHmFiDGB2dR8+96b1AlyyLyBmr13osxg3FcHgi6e6Wxq4ZKmC3eJVOxTgn iDu/o+141oj+ElwZ/0+h/DRPKHkKAqe37gDkOmy+NQzc+pTQX4nCgmHH3RV/cKxF dZHD53ffXhGp0u/IjdPwXXhadWKSW/7472q6E6bGw0c8euQuofdEt0/Jcn0TfK99 TaI8b1L0iu3YW7RNv61ZULgDgqTPJ41dPUvJYfjlXiv+qT7uGx7TumEzthq8q48b lSrzcYhk/4hV+2upHM6L94IC0aXBtFkNbM+IgAfXgTSAwRKvuZ3qnszIBori5IsO 5hY4ZLnAzEzPWdyqFTTjNNwPR9Uehq8LG3tMEDo6//Qe+zbkAW9Op5FBWPO/1kvg vQiAfM+020XI7pEzXqcs/ZA6MxPE5KsiaYHbh7ooBxsiRcSinmI5pBPMcBI+dA65 xHNEu+DCK62S4L417R+PA/sZ+/X7z/OwV3/DMkLxsZQ0+SPqXTv+t95C4uFLQBib fFUO5hNBuFMAKqQmzRJMS2zFG1bSLOvRAgMBAAGjggI9MIICOTAdBgNVHQ4EFgQU BwydF+g3CZjn7wJgu0tgu0XYvnwwHwYDVR0jBBgwFoAUzsNKuZlV8rjbYL+pfr1W tZc2p9YwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDBDASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEF BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMIGBBgNVHR8EejB4MDqgOKA2 hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290 RzIuY3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRB c3N1cmVkSURSb290RzIuY3JsMIHTBgNVHSAEgcswgcgwgcUGCWCGSAGG/WwFAjCB tzAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBigYI KwYBBQUHAgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1 dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50IGxv Y2F0ZWQgYXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL3JwYS11YTAkBgNVHREE HTAbpBkwFzEVMBMGA1UEAxMMU1lNQy00MDk2LTc3MA0GCSqGSIb3DQEBCwUAA4IB AQCjQRprV4Do/ROak60N1coo5r0nBqtdiiQf7De4PHSLMA1BA8f6WlXD6Vt76ECL h1DDa/7JgaEs6yRm6/leqp2VMWFTfH3HLhl98DCiJgYB1XsAvkldfLAkhVWW3FuD JdA/O2Isq0dL7ZVUxRS0Z5QYJQEbTHpdAbPHesQXljLPZ7SCl7PybZatfGAVFeTN mrHQl35IjAqwEOBD7t4qJsSjeUDZL0rGktaAgw2xXNOfAK+foU88iiQpuo3y0xV8 /o7OtItb4x0sYWLaBoJElEh6u78nRB7kEDLh4XupJdhfb5wEs6HYOyCS0qBpiqpf t18BLRONE6bdOPrB1sw26arD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE1jCCA76gAwIBAgITMwAAABuBYchfBitbzgAAAAAAGzANBgkqhkiG9w0BAQsF ADBtMQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lT VEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH bG9iYWwgUm9vdCBHQiBDQTAeFw0yMDA3MDQxNTEyMjFaFw0zOTEyMDExNTEwMzFa MEwxCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSswKQYDVQQDEyJXSVNl S2V5IENlcnRpZnlJRCBQZXJzb25hbCBHQiBDQSAzMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA4cA6tdKsNDPOBN92GLKvgHtRfihS0BdiIzr/6GXWz5+0 /Um1Ytk/ePBZEJNAdWms/doTRsNUTqKK2Ao6mpVy0Ng3Icmv3rVYcJyEhDxIXYvf C5xDK9VPL014+682tRsHPbrKqV1yA1/nltcn2HInkc3QjxFYzanMac+NV52TeceM CwIMNXImPXUrnOFGsuLd625UqxJxJCR91yiyXyd+edvuK5JbKGTKFrAwkJtx2NO+ CzFQk3WpT4R9Ra3hdMuJUq3QMRPRLkJ/d7mK/yMVuSbjbUEii8/eqSoqNWvlPZIe +8GSWIeiymrcmBG4eYc29EsPKehJhLwiyqGGYa4KqwIDAQABo4IBjjCCAYowHQYD VR0OBBYEFOWndkBVsAF/9AD6TMosb+qcELA2MB8GA1UdIwQYMBaAFDUPyDZjXuKj 7Pk7ZhXOUVLjkZo9MDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9wdWJsaWMud2lz ZWtleS5jb20vY3JsL293Z3JnYmNhLmNybDBsBggrBgEFBQcBAQRgMF4wNgYIKwYB BQUHMAKGKmh0dHA6Ly9wdWJsaWMud2lzZWtleS5jb20vY3J0L293Z3JnYmNhLmNy dDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Aud2lzZWtleS5jb20vMEIGA1UdIAQ7 MDkwNwYEVR0gADAvMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3Lndpc2VrZXkuY29t L3JlcG9zaXRvcnkwNQYDVR0lBC4wLAYIKwYBBQUHAwQGCCsGAQUFBwMCBgorBgEE AYI3FAICBgorBgEEAYI3CgMMMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/ BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQAd57kZoN16RGmIhbBwX15BKYrRMQ3N Sjo7j3p4WiMNtBRqr+/3tC/3PFLJvUuZC77qFoNZyCgQMv6xIYOon5tb7Qwz4eMz /PtdysDoBKG1RyIMf2c+S8sPRbs65znIx6ID8yNJxywx6A2/yDxCXhD+LX1yjdwj kWZlQpaPCXBufFDFHjCIeb1XvXqiSDuIVKM9jcB+1TDZHO8Aec5vAaScMxIjuAK/ ODRewFwTIazaA2jCE9xcgEn0agNCpbSJ8JW1rkIwht/A1JrV3dsEq5++L214ESFj ra6U3DTjtY8LniJgH6MMBcPI6EJ1hAo1VPk9djPH3doyS94zc5HWgIwg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvjCCA6agAwIBAgITMwAAABzNh2vJdU6nywAAAAAAHDANBgkqhkiG9w0BAQsF ADBtMQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lT VEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH bG9iYWwgUm9vdCBHQiBDQTAeFw0yMDA3MDQxNTIwMjZaFw0zNTA3MDQxNTMwMjZa MEwxCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSswKQYDVQQDEyJXSVNl S2V5IENlcnRpZnlJRCBQZXJzb25hbCBHQiBDQSA0MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAsL4uMagNTJAAQIqfngQ+idSu0CnOKSs01xdVCJd4J/L6 FE26lvJJQKvr8Kw44571K9WsPDP4vyvbAhMnCAq5z9ukb9PqGwQu7zaM/YKRLspw SFaG7H3F5xqAQOzOClsW8gVYxrOUe6Uzq8s29wdMgZu3lPG92WzxyGHnVaV1sa4b uzWiOqTsgkBZuBXOmIDpgEJtsX70RpHoLTKS5vgI0KqljhfJpoYwdNO1zc37GpX5 b/f5YYazfa52lK/i7qO0p6fu8VPvDtNObdZhD+5sMga96F/XO/c7su5/WTGa+AgT yv3k5aHJKspZU0uuMpfQClhdLgs/ScFjeNl5EGKfKwIDAQABo4IBdjCCAXIwHQYD VR0OBBYEFNtoLANXesw9bGmhOaCbv7CKGVexMB8GA1UdIwQYMBaAFDUPyDZjXuKj 7Pk7ZhXOUVLjkZo9MDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9wdWJsaWMud2lz ZWtleS5jb20vY3JsL293Z3JnYmNhLmNybDBsBggrBgEFBQcBAQRgMF4wNgYIKwYB BQUHMAKGKmh0dHA6Ly9wdWJsaWMud2lzZWtleS5jb20vY3J0L293Z3JnYmNhLmNy dDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Aud2lzZWtleS5jb20vMEIGA1UdIAQ7 MDkwNwYEVR0gADAvMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3Lndpc2VrZXkuY29t L3JlcG9zaXRvcnkwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMCMBIGA1Ud EwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IB AQC+kC2vXY3///B9YT1zK7D2d5gOpeSjqVNceddRnrfDk+ks+FtRyW7La8b9oK/h piakkqLmuOzesbgok+Ta740l7tOxt94UjWpMLqmLJMwA/lCyj7ZVVMFOdxGhWlG5 saSSqagXqoxrSdRwsmQs/YYMZf6OEA2P4Tss1flpdlsydmFpJ2qZtYusF0WiAvOY VYasXHCUI3Zb5BmU0rbya3RRQKuFYAIL9F/MfNj4T31HaCEfX+t3axRc6g+E9/yx 8uSHF8aaeJhpkSwitCibz03dD+Jb7C3f30XkmyNCpGB47/r40TxmSxafVdhI6Ysc LiV7qbjs2n3zZHCMzjBXDJ/h -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgITMwAAAB1sHJ4B1ms5uQAAAAAAHTANBgkqhkiG9w0BAQsF ADBtMQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lT VEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH bG9iYWwgUm9vdCBHQiBDQTAeFw0yMDA3MDQxNTI1MjZaFw0zNTA3MDQxNTM1MjZa MEcxCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSYwJAYDVQQDEx1XSVNl S2V5IENlcnRpZnlJRCBTU0wgR0IgQ0EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAPskiJ2KuwQyuDILa9u+q2DamhpomWIrrCxyjq2w2rY95wJyqf74 cLEwHEJ89L9F0z5MFpF0FgW2CVZCLTLwHiDEtaRz0I5xLQA4x6W1cbonXiK857hS ASEGsZoXdljjkH1lo1B3f2VvVdQ0frgF3nU4swwHE9kg+LI6Ed9n36/iYuMQY9Rp YqYFBJcIdcEgyyI11g93mNnGg3CZifiqBjVq4jIaKSAkIa3bXQr2gylcaERQPaiD o0KRxTP+xQu04uirsJhzpqB/ps63IiIJHb7pXvZf/n97JU1rlanOtZFUzjjjye5G Q0oslh0gCH8INBMH2ta/a+xI7/ULBfcqFXsCAwEAAaOCAXYwggFyMB0GA1UdDgQW BBRfG8UKezh9PsO3Mb+k+xQjUuGNGzAfBgNVHSMEGDAWgBQ1D8g2Y17io+z5O2YV zlFS45GaPTA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vcHVibGljLndpc2VrZXku Y29tL2NybC9vd2dyZ2JjYS5jcmwwbAYIKwYBBQUHAQEEYDBeMDYGCCsGAQUFBzAC hipodHRwOi8vcHVibGljLndpc2VrZXkuY29tL2NydC9vd2dyZ2JjYS5jcnQwJAYI KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLndpc2VrZXkuY29tLzBCBgNVHSAEOzA5MDcG BFUdIAAwLzAtBggrBgEFBQcCARYhaHR0cDovL3d3dy53aXNla2V5LmNvbS9yZXBv c2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8E CDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEABRDe syjqWXCR4JmGdGqDaXZ2yxVF6GMUTzbyCMbwSGr/NzQcuHeUGCapHMxSX9HRG1he /+pIW3+FVckuQG+4ZNQ9b8+QTo1GH3fbbsm7I/PHofp8mv4f8beEDXS7AW/lfKNZ T1SMJoFifazqARMHZ3fe+e1S3IcAfbj0ZiIXGEnbj5ZfFpgmVBcUxp07CI+xMw2W Vd4P4HjapTeZ7wEL8eWj+NFqwHtJwCdrScEFlvOWGJxV9NoPlhRyuisC2OUQvFM6 u5hVMJ/InGvaY4vr0cYLkcRl/rcEUN9iwn9J/3z8JypI2xrHwI8mttJBkgSZYHPU 4qNBNzctN63j7u1OgQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8jCCA9qgAwIBAgIQd70NkN5DlZmaBhVLShIamjANBgkqhkiG9w0BAQsFADBQ MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEmMCQGA1UE AxMdVHJ1c3RlZCBSb290IFRMUyBDQSBTSEEyNTYgRzMwHhcNMjAwNzA1MDAwMDAw WhcNMjYwMjI0MDAwMDAwWjBfMQswCQYDVQQGEwJCUjE3MDUGA1UEChMuU09MVVRJ IC0gU09MVUNPRVMgRU0gTkVHT0NJT1MgSU5URUxJR0VOVEVTIFMvQTEXMBUGA1UE AxMOU29sdXRpIENBIC0gRVYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDRrAkXiaEMqbWuTbA14L9TBdVppjMF9fKPfMs1sd7mUgL7Bbrf2rs1oeXVM6Uy jvsNxe4BfLp+z3fkHEXiyRYu22P4iyT23suaGMp47BErHGh4bBn4cBIMXrAW7wrh zhBLUEVuMfkhU2sZyK9Ci6PLnHH4jE1Phu1Ql+HZkswE4cn4bUImSb+9L9449gg9 Jvyok4xvEcnKg9RCtlWxXCG34Cz3o/417Ud0cWMK289AA9SPZbf7s5EbfJBe39XV vCwEhZM6i7FyYOQ31V/PjZ2bVM18UuHC6qdtNBV30TC9G0ZNga9bNTUsGQqgv3vN Scm0Afg7hh21jAMBU40z0UFnAgMBAAGjggG3MIIBszAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0OBBYEFCQIvAqAXDm6uBZ3fpKRSjLyuskqMB8GA1UdIwQYMBaAFN5P 190nrtV/WIHhLEesI7fGe1fvMIGTBggrBgEFBQcBAQSBhjCBgzA5BggrBgEFBQcw AYYtaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290dGxzc2hhMmcz MEYGCCsGAQUFBzAChjpodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2Vy dC90cnVzdHJvb3R0bHNzaGEyZzMuY3J0MEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6 Ly9jcmwuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290dGxzc2hhMmczLmNybDBVBgNV HSAETjBMMEEGCSsGAQQBoDIBATA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5n bG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAHBgVngQwBATANBgkqhkiG9w0BAQsF AAOCAQEAZ2tltks5szTM9wFCPnDhKVLlIPD04L+oSP2kUyMXrTy44xWEOef7b6Wc Xg0ttTkR2J4EgVSjNTUJG1kQYvFN+2hnOayOyY+H19em0TZ3BL7asLQRARdp2YxS biOkOgtB46x7WnT+gt7TlMeXZ1+0L53HELPQZl/+MfzC8qoZex/RH68LnTSOvkBa fpahn/cdnMwvtK7JvaQQXeOIIJJPJShsGTfdLzmkoIPJLvEE5gtf/t6XyoMcNuaa YkvFj3pWYOKbVO03zetR59nl09HV8RBqEirvd9I4MfC7pJrKDOUErlqLGuwtl39t Ei2qOsK+mDBK7RY0FyUNDaE3NtWP5g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFLTCCBBWgAwIBAgIQd70NdUhoHC9yKezCm/Dn2jANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MDUwMDAwMDBaFw0y NzA0MjUxMTAwMDBaMFMxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMSkwJwYDVQQDEyBUcnVzdGVkIFJvb3Qgbm9uVExTIENBIFNIQTI1NiBH MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKa6/NHEy+nGQa9NlAbK Wbd8BDpdSjHZVQq9zCx6gBSberLXiphVpx6sHY7SuzRaZTQi7EkaOO8sy6EEb+BW qdAZb+D2qgE3D+LHNC/+xZGh3Zc1YXtGLsOHInVDC+moikLloie4uO7Xt3qLdngs tBR7UWt7RsJ1NLUBOTI3KKHs2xA4ci31bMBSfA4gM8+SnBGK3bYy48c3sFwP21ag jr2dNUvP4JgC8KWHWyiatpvzHMCjrn+Dj7O/GodveV7hUY6NIb6/Fe2MVwxY74pb nUVrie7pqNeibRiVckd6nYVvgfn2mPRrh02v+UHWkFhk3Sgc7AfELfAf3PjJURo4 0s8CAwEAAaOCAgIwggH+MA4GA1UdDwEB/wQEAwIBhjCBnQYDVR0lBIGVMIGSBggr BgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwQGCysGAQQBgjcKAwQBBgorBgEE AYI3CgMLBgorBgEEAYI3FAIBBgorBgEEAYI3FAICBgkrBgEEAYI3FRMGCSsGAQQB gjcVBQYJKwYBBAGCNxUGBgorBgEEAYI3CgMMBggrBgEFBQcDBwYIKwYBBQUHAw4w DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUKfFcg2Jb9z8c1hIFK0mgmyars5kw HwYDVR0jBBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7wwegYIKwYBBQUHAQEEbjBs MC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjMw OwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0 L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFs c2lnbi5jb20vcm9vdC1yMy5jcmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYB BQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0G CSqGSIb3DQEBCwUAA4IBAQAmhCUxriNrFpmD9yB54aZN2r0+OtlzOICoss8Lqo0m uP0QmzwFIVwzUelILF+vhgi9YXnr6nzkNsA2WB/vmieprUg7xvGVs2m5KdCV79qw 7iaLyQsui3ZuLfkd/+RHmFbWrLYyUG0/akTvJYtaBAVJd1LE2sBnmDF8KytCPpck YHUpSiEP1WlIklZQjeCHRvS4W5SNmb1O9qNGpjB2xfn/1yLo41CJ96F5OkcMKX9+ 7ALLu/Zqw+Uy6eaxi9A4hwci/6U6XLyp9pGqfi/88PYHoDp9kpSeWKNoCCyyalHK vT7+Btn3hCaPtJMx9fDnDIuNgqG+kTCRcrazkqAtJark -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5DCCA8ygAwIBAgIQd70Nh+gxFRq///agUzKcozANBgkqhkiG9w0BAQsFADBQ MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEmMCQGA1UE AxMdVHJ1c3RlZCBSb290IFRMUyBDQSBTSEEyNTYgRzMwHhcNMjAwNzA1MDAwMDAw WhcNMjYwMjI0MDAwMDAwWjBfMQswCQYDVQQGEwJCUjE3MDUGA1UEChMuU09MVVRJ IC0gU09MVUNPRVMgRU0gTkVHT0NJT1MgSU5URUxJR0VOVEVTIFMvQTEXMBUGA1UE AxMOU29sdXRpIENBIC0gRFYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDfSHqaA6r8TlKODVnmmc0FmtGbOikRqwkjm5ILI5uyI3tAyKCQR0ED7liWcDdH CwaGjFIpJcFVCYXkMMvlm81y5iuKWnI04ocrgePKc+Ar4HtAPqYst8utGH0qoeEo gTHI2u6bO1lkv5P6A/GAwG9xLsR+31vuCXXidDM6+A0DS0NsDJelHOGdobdlp88Y r4cz692zZ2ZmU1CP7wAadzVuYZWhky9xfVoa32vU/OrYmpGIY3Ye8poEoDFbYR9V /9xgj+HmCkJZV6WR4RQd6nqctkCn+nVLhzdCb2XCNZWoH6Cvvarla8pDUICTLVEv lgK0vN5oUpqGUiAVBnOpZ8/NAgMBAAGjggGpMIIBpTAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0OBBYEFIfhAyBlC/oDSaT2czPJoGa/14dSMB8GA1UdIwQYMBaAFN5P 190nrtV/WIHhLEesI7fGe1fvMIGTBggrBgEFBQcBAQSBhjCBgzA5BggrBgEFBQcw AYYtaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290dGxzc2hhMmcz MEYGCCsGAQUFBzAChjpodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2Vy dC90cnVzdHJvb3R0bHNzaGEyZzMuY3J0MEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6 Ly9jcmwuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290dGxzc2hhMmczLmNybDBHBgNV HSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFs c2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAKCrYW+Jgmfl 84efiAdj89JydKfaO6KzcPiz/C73URDyQI7viTsduqsJ9CznTcwOphjrclGH3fmw 1LGPlTE90+erhxnJN2GQw5ZH4FDpoR1cr97qGp0Lo59jybe0scgKGBp0zqsTuIac DuQdmwK+ul58pbVw6MjtwkwMA9Q4rWmvhfWRuqkuetKbirp7QJEwLN3upSmbftv/ nEmBTudQ+OIWvBl1d6HVUiQbRQoHm7alW83mxyx+N8M8SUf/8Dl17p67ecjv4OoG PExbZSvCuBBqBuTkx+cvaoVn6VwoP1sLVhP4fM/GUqdUzgOIlDPxBc2ons/03Ztl /ipzdvhwF1w= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE+DCCA+CgAwIBAgIQd70NrbPiwI2vSwhjGuic4DANBgkqhkiG9w0BAQsFADBQ MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEmMCQGA1UE AxMdVHJ1c3RlZCBSb290IFRMUyBDQSBTSEEyNTYgRzMwHhcNMjAwNzA1MDAwMDAw WhcNMjYwNTE1MDAwMDAwWjBkMQswCQYDVQQGEwJCUjExMC8GA1UEChMoUmVkZSBO YWNpb25hbCBkZSBFbnNpbm8gZSBQZXNxdWlzYSAtIFJOUDEiMCAGA1UEAxMZUk5Q IElDUEVkdSBPViBTU0wgQ0EgMjAxOTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKXy0aVSFMG4AXgSL5oDnUPqls7zPa1Fuik4KqTfSTaz1Q7ucOLl++mg y+a0QsNCgunY3fXTwWmKMZABj4+K5OCzyNIuaAZdG7VN4+euIWrHS6MDycpR31R/ oz7Rle0bxv7mvEUBXoP/UIicYuM3jerIVCg6MsfvA9Zf96wW+Ay5wEmmGwhmNLST ULwKFLYzrxNoirAfgSFqOveSE4tjrpFuIuZYj/E587tpT14sPklK8iuQmbfe32Jd sZ9kUKgAOjTnaFH3S1xaKAYsHHlOAlcond2TDneTAdU1B6fvfKHc8lWcGL1luzag Xy8otoMTjLLAIMusMeGLKchPwUvHyrcCAwEAAaOCAbgwggG0MA4GA1UdDwEB/wQE AwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgw BgEB/wIBADAdBgNVHQ4EFgQUqzDHByhLy3qOW/5haffUerKFm0gwHwYDVR0jBBgw FoAU3k/X3Seu1X9YgeEsR6wjt8Z7V+8wgZMGCCsGAQUFBwEBBIGGMIGDMDkGCCsG AQUFBzABhi1odHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS90cnVzdHJvb3R0bHNz aGEyZzMwRgYIKwYBBQUHMAKGOmh0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20v Y2FjZXJ0L3RydXN0cm9vdHRsc3NoYTJnMy5jcnQwQQYDVR0fBDowODA2oDSgMoYw aHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS90cnVzdHJvb3R0bHNzaGEyZzMuY3Js MFYGA1UdIARPME0wQQYJKwYBBAGgMgEUMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v d3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMAgGBmeBDAECAjANBgkqhkiG 9w0BAQsFAAOCAQEAof/6KIQsQwsczUZDJrQQD1RpJMQdfh2QqWQ7SXdR1zxKiSgM QvvJan2LhxfHW8v4gViMDQayixxTF6P6rrj58NU8lBHVWSoRtWCvnlDit1908xyY vecmxAuBTJhpFlDycyGBn41Dsg7cAUKuYQSySESaOm10P1aHKA1LyL95FUNbCyx7 PACfMdbvIqGvzspH/WV4N8he97btZqBsPCjlINMhtNV1fjMB80wVbGRBtDCEURg7 VOACkZGeJejOO/HWsONdW76g4YhIEsnmQXJRSND6mTWpaQv2fRVlK4Z0x4Xtoxy9 iHifx41Q834r5XErkk8cOU6H4mRQy1hLr+0bog== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqTCCA5GgAwIBAgIQd70NdT8uGWAb1U4KAkRGdjANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MDUwMDAwMDBaFw0y NzA0MjUxMTAwMDBaMFAxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMSYwJAYDVQQDEx1UcnVzdGVkIFJvb3QgVExTIENBIFNIQTI1NiBHMzCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKXRe6ZnoR+4xcoJL/S5vx1D qMMe4LCFB+zMMOCi5stfYUfK6bBgilYKilk42F85z5o1eLKUfj4ycGfnaUVLdSsj waP1HMlobr2xBMiH9+q1KgyWui1v8KRv+IhdPaxRojgLLM4jlPLlHvqvorcmGHQl x0wi2VM8Grqf+cdkhYXHGTBRvBLhAofAhgoWTVzrwTZ6MtAPaCATJ+gcSVQHw9LL XM7xVQukmUwMMpp1mixfKbmIv+DETaMk9O+kt5R4nPLt7M8lUS1CaezdivbKvvnL 4Wnc7nXzRC/NNLtuWs+6i154Yj4a9JB19oGBrInMm673GanbB1r8IuZoROKdGakC AwEAAaOCAYEwggF9MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcD AQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU3k/X3Seu1X9Y geEsR6wjt8Z7V+8wHwYDVR0jBBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7wwegYI KwYBBQUHAQEEbjBsMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWdu LmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1cmUuZ2xvYmFsc2ln bi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6 Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwRwYDVR0gBEAwPjA8BgRV HSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3Jl cG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQAW8OVBjtYaLZ+QvyJta++B4k8B DklbV6XCiJaapjYbZoHssAMd4o+GDr24R0MOmm83sWLdo4gOuNlEwhSVyezr42EJ 2QBLZEJSZwHnMpfPddc2mlZ5gMN6PECZrz4W+t2xmSgOYQi1uIHIiDAoSm4/eppe 8/SLClJTYk/mgF5FfnmNDeOhDE+e836s83RyaVzLxTbl3ZfDSCw2WWglSbrXheWg ydDeEOmWtqeQjlrTmVX/UwFutWPc4W+v8xZ9KT3vcpG4PZd3ZH0GnckeNjBcFiAi dXm4Aymp9y9XHFAsTfHPH3UMmR7WIVc+iboT/14tlK9n2oASLiJjPaACGnpU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdDCCBFygAwIBAgIQd70NfGZ3X/lwu9Bpg6ZrWDANBgkqhkiG9w0BAQsFADBT MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEpMCcGA1UE AxMgVHJ1c3RlZCBSb290IG5vblRMUyBDQSBTSEEyNTYgRzMwHhcNMjAwNzA1MDAw MDAwWhcNMjcwMjIyMDAwMDAwWjBcMQswCQYDVQQGEwJKUDEPMA0GA1UEChMGSklQ REVDMR0wGwYDVQQLExRKQ0FOIFB1YmxpYyBDQTEgLSBHNDEdMBsGA1UEAxMUSkNB TiBQdWJsaWMgQ0ExIC0gRzQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDK6tyYGw/vkFz+af4YD0dMc/Jq6nP5BFOhC1yssDJsKP/rq5EHyT6UdI5qWV9t Mqgb8J41uRECvx8r98JfFCywAG1USCWKlNUgYZmoBL2qME8TuRremNb1SWPvmdF8 WQjfISYSTAbzD04QBo3srBTh0UoOs2ySVxUq4+xEtpUnPHXsj6SG7hOMUHlEpRv6 bUDt/B3/hux0MPE+6SHNwb7sPlR8eRgeL0u69e/whgpA0HN/G81JmIke+lXmStOp BQmqA92fYuBWuId3vqhX8OS59VJA3klnnvP5h1xGFP1+LuVpgS/IRmEMqITnLJrv 8XAmFZ6gYnYhwcKNFc6do5DtAgMBAAGjggI5MIICNTAOBgNVHQ8BAf8EBAMCAQYw gZ0GA1UdJQSBlTCBkgYIKwYBBQUHAwQGCCsGAQUFBwMCBgorBgEEAYI3CgMEBgsr BgEEAYI3CgMEAQYKKwYBBAGCNwoDCwYKKwYBBAGCNxQCAQYKKwYBBAGCNxQCAgYJ KwYBBAGCNxUTBgkrBgEEAYI3FQUGCSsGAQQBgjcVBgYKKwYBBAGCNwoDDAYIKwYB BQUHAwcGCCsGAQUFBwMOMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLmO zfHsei6cuetvCxzE1KwZrqFUMB8GA1UdIwQYMBaAFCnxXINiW/c/HNYSBStJoJsm q7OZMIGZBggrBgEFBQcBAQSBjDCBiTA8BggrBgEFBQcwAYYwaHR0cDovL29jc3Au Z2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290bm9udGxzc2hhMmczMEkGCCsGAQUFBzAC hj1odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC90cnVzdHJvb3Ru b250bHNzaGEyZzMuY3J0MEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZ2xv YmFsc2lnbi5jb20vdHJ1c3Ryb290bm9udGxzc2hhMmczLmNybDBNBgNVHSAERjBE MEIGCisGAQQBoDIBKBQwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFs c2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAGEIpRAK2/K8 LaDv/F2xLakQtYpbqsQWgf95sJQ5eDQDEjmKLvuQP7yJ0EHwfXVWsOk2vO5yMRBz KOffnz6YWcX68gNR4vCLfo0GVyZXGKc5U6ORhPLGhymA0j3x1IdzB5XabJuBLuM2 /SIFyWvOtns79j2klKQEHnBAsrt9X7aQF5QYZDtESzSaadmZn5c2OUXzBKerfXQZ 2Uj0mnu68oEKxZ4MoxKudfZ7jnYKLkPTXDScvtRK/CPc2EWTQ12RVVxrYerxLmog 3VOGpWnxG5mj2Ai3kiF/3r6lgmPKZ4JE0OkbJJETtfB4WydLONb8ABsmqsXH6uHc SEV5wqqcCsM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8zCCA9ugAwIBAgIQd70Ni9g5PmbUkvijnd/wBDANBgkqhkiG9w0BAQsFADBQ MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEmMCQGA1UE AxMdVHJ1c3RlZCBSb290IFRMUyBDQSBTSEEyNTYgRzMwHhcNMjAwNzA1MDAwMDAw WhcNMjYwMjI0MDAwMDAwWjBfMQswCQYDVQQGEwJCUjE3MDUGA1UEChMuU09MVVRJ IC0gU09MVUNPRVMgRU0gTkVHT0NJT1MgSU5URUxJR0VOVEVTIFMvQTEXMBUGA1UE AxMOU29sdXRpIENBIC0gT1YwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDeVNxdmst2nKvut2N5tLzCGgcCVLEm3S6Qja9jC5N3XmwBjdu53tDRFplNeI1P 3Di6682foY9VmP2pkGGCONV6QvLiX290N9DPnPesEE+GAClYrT1NdkB4XfniD3H4 XZt8nJVarvnfD7/MwWklTutbFhLyVg38ttJ1GLJz6riyYaShwlZRKJuUzx5qlUd+ hHdMvYg6oI3UpW2UPHi4ge41Bqv2apntVI1cxNR4pH/CDhDGYZXitqpnCukcwB9J 2EtdDe4EprjS8tlKsHMIgaKWFsgoF90WdWgZk0Sa64b2N6TfFZCncXaaoMikntyP gi7xjlhP+8Wr7QTmYuhBn0FvAgMBAAGjggG4MIIBtDAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0OBBYEFIl0C7uxUXURk+5LSyDvYW64oQfmMB8GA1UdIwQYMBaAFN5P 190nrtV/WIHhLEesI7fGe1fvMIGTBggrBgEFBQcBAQSBhjCBgzA5BggrBgEFBQcw AYYtaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290dGxzc2hhMmcz MEYGCCsGAQUFBzAChjpodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2Vy dC90cnVzdHJvb3R0bHNzaGEyZzMuY3J0MEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6 Ly9jcmwuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290dGxzc2hhMmczLmNybDBWBgNV HSAETzBNMEEGCSsGAQQBoDIBFDA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5n bG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAIBgZngQwBAgIwDQYJKoZIhvcNAQEL BQADggEBABGKFQiY6Z2vCsRHBuTD3jRPnBV+0YrWKYIkpOqVG74Go8L1tnOYSHz0 5vAKhZhhGflfQRBA77ylnIj27vNvwav7NHkUPxEfkUlqjJKPBCsAAwa53QzF9icU oxR715PRWKDwVC4tYla40lI2IFK3ee100eiUdrgwF/NNmqhFmCg85dfCV69J1NVf 1H+nWkVvboSLHSxGJGFLURGTICvnn1XlGbIdXmCZjQ3/krGowK1y5qI2mDW8P2Ha irCFjLWMAaeYuGrZTbeh7WyT2fOd19SKQPx74V1zIyksk8gpNXTV07S0eXTqozjM /+mUs7WvVhPXdx+GA+fzXuc+Q2geAiY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHcDCCBVigAwIBAgIQEnN3l6MViG3+t2x+aloDVDANBgkqhkiG9w0BAQsFADBr MQswCQYDVQQGEwJJVDEOMAwGA1UEBwwFTWlsYW4xIzAhBgNVBAoMGkFjdGFsaXMg Uy5wLkEuLzAzMzU4NTIwOTY3MScwJQYDVQQDDB5BY3RhbGlzIEF1dGhlbnRpY2F0 aW9uIFJvb3QgQ0EwHhcNMjAwNzA2MDYzNjUwWhcNMzAwOTIyMTEyMjAyWjCBhDEL MAkGA1UEBhMCSVQxEDAOBgNVBAgMB0JlcmdhbW8xGTAXBgNVBAcMEFBvbnRlIFNh biBQaWV0cm8xFzAVBgNVBAoMDkFjdGFsaXMgUy5wLkEuMS8wLQYDVQQDDCZBY3Rh bGlzIERvbWFpbiBWYWxpZGF0aW9uIFNlcnZlciBDQSBHMzCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBALVGM4gsi80jpqFUmuK3Z0QKmhrCyEytbycoy44/ 0IN9lOxS8RHPHgqOOCwrK+WaFlELgfpv2Yx9HI4bMvZUeKKSBNgOTpxceBzUIIv7 T9eoeN9lrzSlbcdLq0TZFl2iNuBFKzMVhu3W+bb+UKR3JvrxFmjfHv9KuUJK6LgI xlfQaLCpXf25FMk1lSCqmgSVmRc59rIa2PNwHTnRcGqOHCX7kPQJ88JHjNGLHbVj 8QuOCLdZB7rADR2jsJ1p7rZAMksbNJ9gWdlmA3H0s9Z/4SJIU7R4RIcOpVzNqHo8 Jv4OhDo4ZoBysdaxDN7sRvTJos/2QAVB7/aPFanIQlaZpFBnZIzufAQ58FkbcBJY ZQf9lysjemiHJbqYrokqseaQ0NXOh36D2cEk6CIFK4j6D388K1gi1scikGz3GTei QXAxCaHwuco8e7cjzHRV5C+a/DBhEcErKNp0i1w20gYOdKpQTiu8IETYu8epjmIH 2BSJKWDwlDIDpiJAvtNmrKj2xYL+1F8nOJyEcx/M4mMrK5wdN2oWWSIiUwA0zUhg 0K21w2is0J2QuCBnDE+fL9FTud5V7Uq9w4ZaKgsQtzAjq9+vhIzfEbAZZnnr1odI VTSCcPVSd4mm6RDBWpbKIYCPpctov0kIYyowjUzZ4H26AsjVuOHk1Y0KszIQIvWz gDIpAgMBAAGjggH0MIIB8DAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFFLY iDrIn3hm7YnzezhwlMkCAjbQMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAYYl aHR0cDovL29jc3AwNS5hY3RhbGlzLml0L1ZBL0FVVEgtUk9PVDBFBgNVHSAEPjA8 MDoGBFUdIAAwMjAwBggrBgEFBQcCARYkaHR0cHM6Ly93d3cuYWN0YWxpcy5pdC9h cmVhLWRvd25sb2FkMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATCB4wYD VR0fBIHbMIHYMIGWoIGToIGQhoGNbGRhcDovL2xkYXAwNS5hY3RhbGlzLml0L2Nu JTNkQWN0YWxpcyUyMEF1dGhlbnRpY2F0aW9uJTIwUm9vdCUyMENBLG8lM2RBY3Rh bGlzJTIwUy5wLkEuJTJmMDMzNTg1MjA5NjcsYyUzZElUP2NlcnRpZmljYXRlUmV2 b2NhdGlvbkxpc3Q7YmluYXJ5MD2gO6A5hjdodHRwOi8vY3JsMDUuYWN0YWxpcy5p dC9SZXBvc2l0b3J5L0FVVEgtUk9PVC9nZXRMYXN0Q1JMMB0GA1UdDgQWBBRCg22A fAmEZ/2AV6vxJvV3yCKCcTAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQAD ggIBACeAFKdmcRaIJbdy6mSR+NXzZulMEx3D3gsmOtd8Or0xcK351UH+uKZuAOQJ T/9vODD7/kVD46Ln2M9soJigiyxSRc+Pano2cpT/viqyYZEwIC1JKQWy1dsZNI4k c3gJMuN+KOu9gSjlXgyn+pTcjiFC7iWbpO4tt3HNtKjRkCBXGtp9mE4pQr7eyn3l 14Rf+E++3eMVsp39YZ7yUjUJzFiMGoPuwPaEsqnj0FYytJ7vqLzsHXGhvr3C3K8S Xzs5yQdgmGUDrkSHI1Bg0mlSQ1I9g4L3NKzZVJFbBW4p5AvbjmWQFMek0MOSVFNA 0J6NduiOMRCMtdCrEySiK8rai+UwVHXMDJwy016aodBsjmlydSgbSq9CWlKNQaUs tB3NHgzbZRexvXMP0BaPB0QyzWLZ2cMQ9DtaTtsvWFQn7J00FYPV9ZG3MMkBId+5 qk/q8c6UZ3u5kdehslZ31p40ptT1cNK0U/mRnMg2OzAR/l62Uq5v+Z6ZTiD469iR 2Tb24vQGa7G4NB8nMyC/MxPtmKlwLd1PTIlLpnkqvX266b3HAPGDyJj2B7NzEtIm 9WSR5HM+J+GFzssAyI/feJxA1cdLiOIyHtdMMRMjlsUxaMWsNzf55bifWl7Zttxm M14ovZrkI+kjvfoT83bXDOgsB5E5TZFg6q5azRdkx6AHC8ah -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHdTCCBV2gAwIBAgIQXDs/N638KP4Pz9Or+D+FUTANBgkqhkiG9w0BAQsFADBr MQswCQYDVQQGEwJJVDEOMAwGA1UEBwwFTWlsYW4xIzAhBgNVBAoMGkFjdGFsaXMg Uy5wLkEuLzAzMzU4NTIwOTY3MScwJQYDVQQDDB5BY3RhbGlzIEF1dGhlbnRpY2F0 aW9uIFJvb3QgQ0EwHhcNMjAwNzA2MDcyMDU1WhcNMzAwOTIyMTEyMjAyWjCBiTEL MAkGA1UEBhMCSVQxEDAOBgNVBAgMB0JlcmdhbW8xGTAXBgNVBAcMEFBvbnRlIFNh biBQaWV0cm8xFzAVBgNVBAoMDkFjdGFsaXMgUy5wLkEuMTQwMgYDVQQDDCtBY3Rh bGlzIE9yZ2FuaXphdGlvbiBWYWxpZGF0ZWQgU2VydmVyIENBIEczMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAs73Ch+t2owm3ayTkyqy0OPuCTiybxTyS 4cU4y0t2RGSwCNjLh/rcutO0yoriZxVtPrNMcIRQ544BQhHFt/ypW7e+t8wWKrHa r3BkKwSUbqNwpDWP1bXs7IJTVhHXWGAm7Ak1FhrrBmtXk8QtdzTzDDuxfFBK7sCL N0Jdqoqb1V1z3wsWqAvr4KlSCFW05Nh4baWm/kXOmb8U+XR6kUmuoVvia3iBhotR TzAHTO9SWWkgjTcir/nhBvyL2RoqkgYyP/k50bznaVOGFnFWzfl0XnrM/salfCBh O0/1vNaoU8elR6AtbdCFAupgQy95GuFIRVS8n/cF0QupfPjUl+kGSLzvGAc+6oNE alpAhKIS/+P0uODzRrS9Eq0WX1iSj6KHtQMNN4ZKsS4nsuvYCahnAc0QwQyoduAW iU/ynhU9WTIEe1VIoEDE79NPOI2/80RqbZqdpAKUaf0FvuqVXhEcjiJJu+d0w9YN b7gurd6xkaSXemW/fP4idBiNkd8aCVAdshGQYn6yh+na0Lu5IG88Z2kSIFcXDtwy zjcxkW86pwkO6GekEomVBNKcv0Cey2Smf8uhpZk15TSCeyFDrZBWH9OsDst/Tnhz pN156Huw3M3RRdEegt33fcyPykgt0HThxrEv9DwOzhs6lCQ5RNQJO7ZvZF1ZiqgT FOJ6vs1xMqECAwEAAaOCAfQwggHwMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgw FoAUUtiIOsifeGbtifN7OHCUyQICNtAwQQYIKwYBBQUHAQEENTAzMDEGCCsGAQUF BzABhiVodHRwOi8vb2NzcDA1LmFjdGFsaXMuaXQvVkEvQVVUSC1ST09UMEUGA1Ud IAQ+MDwwOgYEVR0gADAyMDAGCCsGAQUFBwIBFiRodHRwczovL3d3dy5hY3RhbGlz Lml0L2FyZWEtZG93bmxvYWQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB MIHjBgNVHR8EgdswgdgwgZaggZOggZCGgY1sZGFwOi8vbGRhcDA1LmFjdGFsaXMu aXQvY24lM2RBY3RhbGlzJTIwQXV0aGVudGljYXRpb24lMjBSb290JTIwQ0EsbyUz ZEFjdGFsaXMlMjBTLnAuQS4lMmYwMzM1ODUyMDk2NyxjJTNkSVQ/Y2VydGlmaWNh dGVSZXZvY2F0aW9uTGlzdDtiaW5hcnkwPaA7oDmGN2h0dHA6Ly9jcmwwNS5hY3Rh bGlzLml0L1JlcG9zaXRvcnkvQVVUSC1ST09UL2dldExhc3RDUkwwHQYDVR0OBBYE FJ+KsbXxsd6C9Cd8vojN3qlDgaNLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B AQsFAAOCAgEAJbygMnKJ5M6byr5Ectq05ODqwNMtky8TEF3O55g6RHhxblf6OegZ 4ui4+ElHNOIXjycbeuUGuFA4LScCC9fnI1Rnn8TI2Q7OP5YWifEfnrdp99t/tJzQ hfdi7ZTdRRZZGV9x+grfR/RtjT2C3Lt9X4lcbuSxTea3PHAwwi0A3bYRR1L5ciPm eAnYtG9kpat8/RuC22oxiZZ5FdjU6wrRWkASRLiIwNcFIYfvpUbMWElaCUhqaB2y YvWF8o02pnaYb4bvTCg4cVabVnojUuuXH81LeQhhsSXLwcdwSdew0NL4zCiNCn2Q iDZpz2biCWDggibmWxsUUF6AbqMHnwsdS8vsKXiFQJHeAdNAhA+kwpqYAdhUiCdj RTUdtRNUucLvZEN1OAvVYyog9xYCfhtkqgXQROMANP+Z/+yaZahaP/Vgak/V00se Hdh7F+B6h5HVdwdh+17E2jl+aMTfyvBFcg2H/9Qjyl4TY8NW/6v0DPK52sVt8a35 I+7xLGLPohAl4z6pEf2OxgjMNfXXCXS33smRgz1dLQFo8UpAb3rf84zkXaqEI6Qi 2P+5pibVFQigRbn4RcE+K2a/nm2M/o+WZTSio+E+YXacnNk71VcO82biOof+jBKT iC3Xi7rAlypmme+QFBw9F1J89ig3smV/HaN8tO0lfTpvm7Zvzd5TkMs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHcjCCBVqgAwIBAgIQA6ihwkJqJUS5KwuYph1/xTANBgkqhkiG9w0BAQsFADBr MQswCQYDVQQGEwJJVDEOMAwGA1UEBwwFTWlsYW4xIzAhBgNVBAoMGkFjdGFsaXMg Uy5wLkEuLzAzMzU4NTIwOTY3MScwJQYDVQQDDB5BY3RhbGlzIEF1dGhlbnRpY2F0 aW9uIFJvb3QgQ0EwHhcNMjAwNzA2MDczNjE0WhcNMzAwOTIyMTEyMjAyWjCBhjEL MAkGA1UEBhMCSVQxEDAOBgNVBAgMB0JlcmdhbW8xGTAXBgNVBAcMEFBvbnRlIFNh biBQaWV0cm8xFzAVBgNVBAoMDkFjdGFsaXMgUy5wLkEuMTEwLwYDVQQDDChBY3Rh bGlzIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VydmVyIENBIEczMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAw0vN0YzE9FFYNLnaBhFZn/fUXY7gk0Uqb9o2 SkY/8NqSSjkms9dlP81zvv1RButC+GZ0wwap8gouorbgGpTWbrkK6dOBUe/M+2g7 4EVJGIxktFhtmMpZFE5/xU4+jk9AHsJjU9+ZYW2JwVCbCeUrlyQHwINf9mP32fCq 2DshelzaKisIYH0HJmp3PWq1RySvfGMbZJ16yDVkrdGz3/NtExpU2Y/rH/GaCCfQ 7o8HDj5/YdcVCAXTMLolFaqnFzI/bazfy+mhRSEkrFsGNV/4mVkraanJb7FY9bvl Qwj9DUlw1ehDIpbWDPl9QOFNiOlKXUe+MkCVV9eVzWn8GFu2cEm5cqrONKQhJinJ SEfWC6h7CwDEKCt5lJYMc3vcxWOPK4c2n8OBD0U2yZCXm486OzXkHN8D0kvyoXTV jbtVuZbB6b7duBuydtx/k1xkQnLbBFv3MIPg+5FFmk2rcyOtSFaFUCHVfKnQec5/ 50Lz5A4Dg97pvFZIgfJFq4KM0gm0clr3JKop7393WrOlSVC0a0cfB854j79Y0VDJ ZSXNTDC1yJ72DWuDGycE2b2kN2zSVlfIxMPeoNN3LVZO5QTJ+ts54YfWT5dbZ6JF QoAfi65OhTtjaCkafIdKk5ewnURQ1ZeocOEvhsRdeKoV669eOQBQMz8N/kKdJCVq ffS9xLECAwEAAaOCAfQwggHwMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU UtiIOsifeGbtifN7OHCUyQICNtAwQQYIKwYBBQUHAQEENTAzMDEGCCsGAQUFBzAB hiVodHRwOi8vb2NzcDA1LmFjdGFsaXMuaXQvVkEvQVVUSC1ST09UMEUGA1UdIAQ+ MDwwOgYEVR0gADAyMDAGCCsGAQUFBwIBFiRodHRwczovL3d3dy5hY3RhbGlzLml0 L2FyZWEtZG93bmxvYWQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMIHj BgNVHR8EgdswgdgwgZaggZOggZCGgY1sZGFwOi8vbGRhcDA1LmFjdGFsaXMuaXQv Y24lM2RBY3RhbGlzJTIwQXV0aGVudGljYXRpb24lMjBSb290JTIwQ0EsbyUzZEFj dGFsaXMlMjBTLnAuQS4lMmYwMzM1ODUyMDk2NyxjJTNkSVQ/Y2VydGlmaWNhdGVS ZXZvY2F0aW9uTGlzdDtiaW5hcnkwPaA7oDmGN2h0dHA6Ly9jcmwwNS5hY3RhbGlz Lml0L1JlcG9zaXRvcnkvQVVUSC1ST09UL2dldExhc3RDUkwwHQYDVR0OBBYEFKtB c/BvUNBp/XMXq4mza2LtvXxLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAnWMeR4BLRiemkhxXVt1Xc06ip2isGdixlsVsmsNUPzzrgNOpJrb4G9vR WehI5KXRBROYEnvUSL9/59nDj6fS0Qnh6s8zL8ATeEGzsYiKS2wgTeP7kNfEPlbZ qEATY1VK8Yn8+MBO+o3xjnLxddV3GdDOgitmHAEjc5QdO0Di0hCCfH/5/FT5f56o cisJtQOm2Sohnd7v8wlS+pBG0tffqKIlI9dyEp1X5Ko80UY7MROIhc4eAu8Acycj +R9FiFLXSk8KRszRVE8gmBd5P7Ug3nflv3MACOelxkbDu/CREsAv9IXQcwGDzhpx UMvWAKfqHUwFcAigG6mhqFZ5TXTE/eIW6p0IkojsamuAc5BaroO9uDF0esxaFG1O o1LP1UR1uUMcCwGtJm7JZBmUcSp5+pQmLav4EkIBhIULbhtnxO36TeYyRZRySw9h 0N1XnROIncQdaUlAMeNsJYEFr4OTDJCfy8nhguiV9+7fTdK4VSB2wTEBY0ZBGAOT yHmaCz0iX+ZNBf058Fy2xsyMMBJ01Ae1aKcTJO2c/4fP+82p2uk40ak+ZT5kQVtG TkFoHkGquXTAx9zgeXihddz2LrxyeePZ6Va8Z2ZLBcBRE/cpGIQvtRMeXB/F/uOO Hjdno388OrB6CiPlz8C6KBTPdHjuUHkvGQxImgYIfC2MxdE50IU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHbTCCBVWgAwIBAgIQFxA+3j2KHLXKBlGT58pDazANBgkqhkiG9w0BAQsFADBr MQswCQYDVQQGEwJJVDEOMAwGA1UEBwwFTWlsYW4xIzAhBgNVBAoMGkFjdGFsaXMg Uy5wLkEuLzAzMzU4NTIwOTY3MScwJQYDVQQDDB5BY3RhbGlzIEF1dGhlbnRpY2F0 aW9uIFJvb3QgQ0EwHhcNMjAwNzA2MDg0NTQ3WhcNMzAwOTIyMTEyMjAyWjCBgTEL MAkGA1UEBhMCSVQxEDAOBgNVBAgMB0JlcmdhbW8xGTAXBgNVBAcMEFBvbnRlIFNh biBQaWV0cm8xFzAVBgNVBAoMDkFjdGFsaXMgUy5wLkEuMSwwKgYDVQQDDCNBY3Rh bGlzIENsaWVudCBBdXRoZW50aWNhdGlvbiBDQSBHMzCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAO3mh5ahwaS27cJCVfc/Dw8iYF8T4KZDiIZJkXkcGy8a UA/cRgHu9ro6hsxRYe/ED4AIcSlarRh82HqtFSVQs4ZwikQW1V/icCIS91C2IVAG a1YlKfedqgweqky+bBniUvRevVT0keZOqRTcO5hw007dL6FhYNmlZBt5IaJs1V6I niRjokOHR++qWgrUGy5LefY6ACs9gZ8Bi0OMK9PZ37pibeQCsdmMRytl4Ej7JVWe M/BtNIIprHwO1LY0/8InpGOmdG+5LC6xHLzg53B0HvVUqzUQNePUhNwJZFmmTP46 FXovxmH4/SuY5IkXop0eJqjN+dxRHHizngYUk1EaTHUOcLFy4vQ0kxgbjb+GsNg6 M2/6gZZIRk78JPdpotIwHnBNtkp9wPVH61NqdcP7kbPkyLXkNMTtAfydpmNnGqqH LEvUrK4iBpUPG9C09KOjm9OyhrT2uf5SLzJsee9g79r/rw4hAgcsZtR3YI6fCbRO JncmD+hgbHCck+9TWcNc1x5xZMgm8UXmoPamkkfceAlVV49QQ5jUTgqneTQHyF1F 2ExXmf47pEIoJMVxloRIXywQuB2uqcIs8/X6tfsMDynFmhfT/0mTrgQ6xt9DIsgm WuuhvZhLReWS7oeKxnyqscuGeTMXnLs7fjGZq0inyhnlznhA/4rl+WdNjNaO4jEv AgMBAAGjggH0MIIB8DAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFFLYiDrI n3hm7YnzezhwlMkCAjbQMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAYYlaHR0 cDovL29jc3AwNS5hY3RhbGlzLml0L1ZBL0FVVEgtUk9PVDBFBgNVHSAEPjA8MDoG BFUdIAAwMjAwBggrBgEFBQcCARYkaHR0cHM6Ly93d3cuYWN0YWxpcy5pdC9hcmVh LWRvd25sb2FkMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDCB4wYDVR0f BIHbMIHYMIGWoIGToIGQhoGNbGRhcDovL2xkYXAwNS5hY3RhbGlzLml0L2NuJTNk QWN0YWxpcyUyMEF1dGhlbnRpY2F0aW9uJTIwUm9vdCUyMENBLG8lM2RBY3RhbGlz JTIwUy5wLkEuJTJmMDMzNTg1MjA5NjcsYyUzZElUP2NlcnRpZmljYXRlUmV2b2Nh dGlvbkxpc3Q7YmluYXJ5MD2gO6A5hjdodHRwOi8vY3JsMDUuYWN0YWxpcy5pdC9S ZXBvc2l0b3J5L0FVVEgtUk9PVC9nZXRMYXN0Q1JMMB0GA1UdDgQWBBS+l6mqhL+A vxBTfQky+eEuMhvPdzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIB ACab5xtZDXSzEgPp51X3hICFzULDO2EcV8em5hLfSCKxZR9amCnjcODVfMbaKfdU ZXtevMIIZmHgkz9dBan7ijGbJXjZCPP29zwZGSyCjpfadg5s9hnNCN1r3DGwIHfy LgbcfffDyV/2wW+XTGbhldnazZsX892q+srRmC8XnX4ygg+eWL/AkHDenvbFuTlJ vUyd5I7e1nb3dYXMObPu24ZTQ9/K1hSQbs7pqecaptTUjoIDpBUpSp4Us+h1I4MA WonemKYoPS9f0y65JrRCKcfsKSI+1kwPSanDDMiydKzeo46XrS0hlA5NzQjqUJ7U suGvPtDvknqc0v03nNXBnUjejYtvwO3sEDXdUW5m9kjNqlQZXzdHumZJVqPUGKTW cn9Hf3d7qbCmmxPXjQoNUuHg56fLCanZWkEO4SP1GAgIA7SyJu/yffv0ts7sBFrS TD3L2mCAXM3Y8BfblvvDSf2bvySm/fPe9brmuzrCXsTxUQc1+/z5ydvzV3E3cLnU oSXP6XfXNyEVO6sPkcUSnISHM798xLkCTB5EkjPCjPE2zs4v9L9JVOkkskvW6RnW WccdfR3fELNHL/kep8re6IbbYs8Hn5GM0Ohs8CMDPYEox+QX/6/SnOfyaqqSilBo nMQBstsymBBgdEKO+tTHHCMnJQVvZn7jRQ20wXgxMrvN -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFjTCCBHWgAwIBAgIQa4crboHY9a08fWQW63QGgTANBgkqhkiG9w0BAQsFADA8 MR4wHAYDVQQDDBVBdG9zIFRydXN0ZWRSb290IDIwMTExDTALBgNVBAoMBEF0b3Mx CzAJBgNVBAYTAkRFMB4XDTIwMDcwNzA2MTk0MVoXDTMwMDcwNTA2MTk0MVowRjEo MCYGA1UEAwwfQXRvcyBUcnVzdGVkUm9vdCBDbGllbnQtQ0EgMjAyMDENMAsGA1UE CgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCf4V1Zyni09kfp2I3ulSLam+dujxBVVPe24vlcX3mdk+oSSusS0KSzreRm RDH0VzaS9hic85CemVTH+jfyNNFBxhXa2kKLydt1yxtJ3TRFAMRUEWK5aVkKkV7g 101n6O82bW5M7PaxnlLwb6C7+XwlpKHzMaSmiBFOiBMCxJP0AGB0hgU+F0XhvNwQ P+Wx4rq6v7m5DJqx8qoe0nyA+dOEDJJiOF7o330he2QkbkAzgxd0MoQ+T9igaLaj SwywwxGpuKE/Vt/y/YC025hWYS6htwFeJqtcjWStKiINuqOLBQeI+orAg3nGyQaP hp6h5gIlKO4saEye6KaFYBYWiuLHAgMBAAGjggJ/MIICezASBgNVHRMBAf8ECDAG AQH/AgEAMB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMHYGCCsGAQUF BwEBBGowaDBABggrBgEFBQcwAoY0aHR0cDovL3BraS5hdG9zLm5ldC9Eb3dubG9h ZC9BdG9zVHJ1c3RlZFJvb3QyMDExLmNlcjAkBggrBgEFBQcwAYYYaHR0cDovL3Br aS1vY3NwLmF0b3MubmV0MEUGA1UdIAQ+MDwwOgYMKwYBBAGwLQUBAQEBMCowKAYI KwYBBQUHAgEWHGh0dHA6Ly9wa2kuYXRvcy5uZXQvRG93bmxvYWQwQgYDVR0lBDsw OQYIKwYBBQUHAwIGCCsGAQUFBwMEBgsrBgEEAYI3CgMEAQYKKwYBBAGCNwoDBAYK KwYBBAGCNxQCAjCCARAGA1UdHwSCAQcwggEDMIHAoHygeoZ4bGRhcDovL3BraS1s ZGFwLmF0b3MubmV0L2NuPUF0b3MlMjBUcnVzdGVkUm9vdCUyMDIwMTEsb3U9Q0Es b3U9QXRvcyUyMFRDLG89QXRvcyxkYz1hdG9zLGRjPW5ldD9jZXJ0aWZpY2F0ZVJl dm9jYXRpb25MaXN0okCkPjA8MR4wHAYDVQQDDBVBdG9zIFRydXN0ZWRSb290IDIw MTExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMD6gPKA6hjhodHRwOi8vcGtp LWNybC5hdG9zLm5ldC9jcmwvQXRvc19UcnVzdGVkUm9vdF9DQV8yMDExLmNybDAd BgNVHQ4EFgQUic/rfY3vSDFHRv5Ls216VKPjrQMwDgYDVR0PAQH/BAQDAgGGMA0G CSqGSIb3DQEBCwUAA4IBAQBC9Zgk2914Z1W+KQdVj7z6Mc3UtR5lDfJysKKiXUkH Ua0v31hRcyrdXspXxddBdaRAdQIl8/S6AR9yJ0vMszqqpE7Cv0xewklx/jaV6Zpo lezUex0dx2xUW7uAcLSX3ixXfuIBO4zzhJPVRzViK4GmeuqVncuDcGF++PB1x1rP wzc93BpkW51x0e/g5zTrOR5BMt/OPv1dlOExDunoT1V7C+Lx++qffftVlu7NmGz7 ooM8CovTmdBou8nL1Mmqt1sbXbvKCWkg8KSKpGMkOJ+ZIagYyFKjbcQrYBwmXuGM kWHfSxUu3WoGhIrtJ6fWM3ZyN78aG07Fx7kiJDyV1902 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHQzCCBSugAwIBAgIQb0MAHcMhZr/fKa/XOYax9TANBgkqhkiG9w0BAQsFADCB pjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVu aWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRo b3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJ bnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMjAwNzA4MDgxNzAzWhcNMzUwNzA1 MDgxNzAzWjCBvDELMAkGA1UEBhMCR1IxKzApBgNVBAoMIkdyZWVrIFVuaXZlcnNp dGllcyBOZXR3b3JrIChHVW5ldCkxGDAWBgNVBGEMD1ZBVEdSLTA5OTAyODIyMDE3 MDUGA1UECwwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 aW9ucyBDQTEtMCsGA1UEAwwkSEFSSUNBIEluc3RpdHV0aW9uYWwgQ2xpZW50IFN1 YkNBIFIxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAhqPiZy8PBAk0 eEhA93m++nJ5mMFETtgYJrwAJPL3VZkDtO/+wySSLGoe/S3foj6dAMu6y+2u71Y3 ec40rESoe/iLbfnc0oO0lOmiu6nwNhN+B/+tmRN2biR32eRW36aQ9MmXnYUauZR1 SQ/LRYdFc905dhSlr0SbPeaMb7ISlUp4TkdwLVxfx6NsRi9F6cvG+uPa9wmkr6aF /0kld4pC8Z9iqDKugoUMaI3nLFU3Wy6aejGSe1Lo6g7ZRMmiSZ2UtPdM0Zi8TD0t +7WkOv4U4nmPHUO3WEqgjdB1LaEoJ3VW8Oi1woOYsrRY9DVev6/uVM3VJVyEP5M9 VQb59gx0Z/piOuaYXQxKYzmoc2i3q4FiIuvuMpob95BB6OQK3ltjvvJsN5e2ajMP tMxHM6l52UiCwa7HQw2ovXqtu4aFZJHK6UGJdJG1NSjbe/GsWAI4OEggUk7bzW44 CQhAkXQij7/k5nYxeMdWCufB/Gpq9KHOIh42oEDUUD+tZjJObyBhL3+shx6osfZ1 je5UhdrTWHQSE+49b+0FHuGgQHg8mYaJJctljAbsO36vQ0n8UlVnbUFq8HM9L8xi xLAlH0tkX/3EfPGg94zkJKnoLFTO+XsO0+OI+8M93y5czCD0a4JIyFt1/9XXl3+T 8q7Vhb6Y6K/4ZPcigHS3kN4aRqd79OsCAwEAAaOCAVMwggFPMBIGA1UdEwEB/wQI MAYBAf8CAQAwHwYDVR0jBBgwFoAUcRVnyMjJvXVdctA4GGqd83EkVAswbwYIKwYB BQUHAQEEYzBhMDwGCCsGAQUFBzAChjBodHRwOi8vcmVwby5oYXJpY2EuZ3IvY2Vy dHMvSGFyaWNhUm9vdENBMjAxNS5jcnQwIQYIKwYBBQUHMAGGFWh0dHA6Ly9vY3Nw LmhhcmljYS5ncjARBgNVHSAECjAIMAYGBFUdIAAwKQYDVR0lBCIwIAYIKwYBBQUH AwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6 Ly9jcmwuaGFyaWNhLmdyL0hhcmljYVJvb3RDQTIwMTUuY3JsMB0GA1UdDgQWBBTN 6UtrXSizepINisRf5E4w9athaTAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL BQADggIBAF94rSwsHZHLww/rgO/TmQMLrkEPumpGpgGNjwvPBroJ3/A6lW/O9fOC CdFguWBs5GMKPoQeKtskumhiKq3jOuLXK0SH3oNYfiU6DJ/fIz03rE7STuX2hNYW UIcInzfSO4DnWLOcOX/9dq4uYfpVh3WFSSk8xlPycXsv0QGCJjyquQaY23wJDrQ/ drpP7ZhZ2qpa1BhI4trwuijGMCFuHRXVPhcRkquI//MPUoRXf0vPjgqbP4S9etC8 y5mV5rfVvvX26jIjpN8UnJEJetRhUQmt762fNseHEdLCzHVuX9wBU17rsD/VUL2b HWUXgASLB4mgXAGkGiAohDU8u51QsZg8Rej6V6PsyVw5nbtm/Bw5YoKX2rX6x5lq 5tvK6XA1ybTkG6Caf+1xgMWoCOUJsHOyrfHw4vP/LPfW5e1i/mp99K15qIDX7ZXN OJhQ9bQ03tG/nQ3L8SS1tMCTfryhiHOeDSzYGhHrUDKZds9MlVHqUos92ndbGYmE NqA4XU0uygWvnEcgGRbfXADQy0sU/S71kkfAzKESTU8YLKr5PXnC28i5pgdpszXl NB0svDtr/hMcYk1KQQglzTypOalWKUG3IW0dRjGoNjoYG1b+cL5xAPKeRPkM2z3h fDn6pi2iEH4PDy68HRuwOERrUZ4Mb+tYvFpClafMNcOo70N71C7b -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFfjCCBGagAwIBAgIQYLhZ8Y/3NW90Cn5tPWQvdTANBgkqhkiG9w0BAQsFADA8 MR4wHAYDVQQDDBVBdG9zIFRydXN0ZWRSb290IDIwMTExDTALBgNVBAoMBEF0b3Mx CzAJBgNVBAYTAkRFMB4XDTIwMDcwODA5MTMwNVoXDTMwMDcwNjA5MTMwNVowXDE+ MDwGA1UEAww1QXRvcyBUcnVzdGVkUm9vdCBDbGllbnQtQ0EgZm9yIFdpbnRlcnNo YWxsIERlYSAyIDIwMjAxDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsVfSFeOnxMJyckTrmOMZjAybEXwv dWfWz5aIzDPGTw5Cvw43TrgdUL18HVoabvkc3bEiI3fkwlhTGaeeARQVK0tMefrJ INCJ5da/u5A353q7S8McMA0+7yiqeE8B3fJQh0BMdU1mZD/FOVfK1unZk92R5lPW ct5wLUiVVL6MuiwNXWtbDLaYlhcNoaywXbkGj2j/DV4hlE6Q1Pjkljz1GdOkLEe5 SBi0/jDyxT9skVuyWOeKOP6rJNYtcnmwNwMuSdWZDftQRdIrb31DzU2DN4l7FWDt nELojRAbGkLvYVH1ZzzIgNaRCgtGyYepK7EK9UME8jo6UgH1DJ85GqVgnwIDAQAB o4ICWjCCAlYwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSnpQaxLKYJ YO7Rl+lwrrw7GWzbITB2BggrBgEFBQcBAQRqMGgwQAYIKwYBBQUHMAKGNGh0dHA6 Ly9wa2kuYXRvcy5uZXQvRG93bmxvYWQvQXRvc1RydXN0ZWRSb290MjAxMS5jZXIw JAYIKwYBBQUHMAGGGGh0dHA6Ly9wa2ktb2NzcC5hdG9zLm5ldDBFBgNVHSAEPjA8 MDoGDCsGAQQBsC0FAQEBATAqMCgGCCsGAQUFBwIBFhxodHRwOi8vcGtpLmF0b3Mu bmV0L0Rvd25sb2FkMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDCCARAG A1UdHwSCAQcwggEDMIHAoHygeoZ4bGRhcDovL3BraS1sZGFwLmF0b3MubmV0L2Nu PUF0b3MlMjBUcnVzdGVkUm9vdCUyMDIwMTEsb3U9Q0Esb3U9QXRvcyUyMFRDLG89 QXRvcyxkYz1hdG9zLGRjPW5ldD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0okCk PjA8MR4wHAYDVQQDDBVBdG9zIFRydXN0ZWRSb290IDIwMTExDTALBgNVBAoMBEF0 b3MxCzAJBgNVBAYTAkRFMD6gPKA6hjhodHRwOi8vcGtpLWNybC5hdG9zLm5ldC9j cmwvQXRvc19UcnVzdGVkUm9vdF9DQV8yMDExLmNybDAdBgNVHQ4EFgQU8aa9Ba8D p+V5duEQIMG19gnSmw8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB AQAd+NLOZxxrb7uuOOZRbQsnDsKebgLDGlf9fMfrGPCKaW4L3QgkSN3UY890GNAe jYAITGQoYmCRuO/7p7Eou+k2oe36ggkZ3dQWGKD5QxaOsBPrgcuyqBICBfte9dl4 bGvQHjKl/I6R6e0UqHJU/jjTcqiqAOFEzcGLx/OZa6MZQsaVi5KXznp41WuD2dVO 1Dd42Zpm6MUKecmQyNQYp0D7vTDRL5uSnz64nIQFjcn5Wa2tFXGc6Ku9KZ9bcSeI 76zFLlJlbw+ZkDcOQT1xipuuYu6H2iws5qtPnjNb5wHTwfTfStnXy6zaMGZD2LUx jyEQNE5dW4yFZoBdddYz96tf -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFnTCCBIWgAwIBAgIQcBgKxB6x9gstwDBDop0uCjANBgkqhkiG9w0BAQsFADA8 MR4wHAYDVQQDDBVBdG9zIFRydXN0ZWRSb290IDIwMTExDTALBgNVBAoMBEF0b3Mx CzAJBgNVBAYTAkRFMB4XDTIwMDcwODA5MTcxM1oXDTMwMDcwNjA5MTcxM1owVjE4 MDYGA1UEAwwvQXRvcyBUcnVzdGVkUm9vdCBDbGllbnQtQ0EgZm9yIFdvcmxkbGlu ZSAyIDIwMjAxDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmVRv6NeAzm+yAMyO7/gqTyCm63JgqAOcQ9VA dE2w0N+cOSFngg9G52zfmYB6H2GxTrL1etIh1aFzqjxXBBm218yOpA5dfAY3Wnbc taNuguM1ry1Xin562xyyjIKKXym0Ca0mcA+CvGXlLJICRwyh+xHzRePG9+u5L4Hg 75S0qlWciRLcGnxpZNPmr8rNFWWkL/CVCA9FbBx4SSxZVUH7cWRiH2klSguNWNUm 3Fgp3WmeHu/0pKRa+lXHdiQRQFLrgpEafiedP3D/4+F1oXkphcAgOs+szg1YoIyX bunsgsXlLZEmb1sEMrdnDGy8RbQyi1+9/zBAkybHHXUSi33nSwIDAQABo4ICfzCC AnswEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSnpQaxLKYJYO7Rl+lw rrw7GWzbITB2BggrBgEFBQcBAQRqMGgwQAYIKwYBBQUHMAKGNGh0dHA6Ly9wa2ku YXRvcy5uZXQvRG93bmxvYWQvQXRvc1RydXN0ZWRSb290MjAxMS5jZXIwJAYIKwYB BQUHMAGGGGh0dHA6Ly9wa2ktb2NzcC5hdG9zLm5ldDBFBgNVHSAEPjA8MDoGDCsG AQQBsC0FAQEBATAqMCgGCCsGAQUFBwIBFhxodHRwOi8vcGtpLmF0b3MubmV0L0Rv d25sb2FkMEIGA1UdJQQ7MDkGCCsGAQUFBwMCBggrBgEFBQcDBAYLKwYBBAGCNwoD BAEGCisGAQQBgjcKAwQGCisGAQQBgjcUAgIwggEQBgNVHR8EggEHMIIBAzCBwKB8 oHqGeGxkYXA6Ly9wa2ktbGRhcC5hdG9zLm5ldC9jbj1BdG9zJTIwVHJ1c3RlZFJv b3QlMjAyMDExLG91PUNBLG91PUF0b3MlMjBUQyxvPUF0b3MsZGM9YXRvcyxkYz1u ZXQ/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdKJApD4wPDEeMBwGA1UEAwwVQXRv cyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTA+ oDygOoY4aHR0cDovL3BraS1jcmwuYXRvcy5uZXQvY3JsL0F0b3NfVHJ1c3RlZFJv b3RfQ0FfMjAxMS5jcmwwHQYDVR0OBBYEFD5N2tgdJ2Jin1r28IJmoQvu60HCMA4G A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAapIPWZLTM94lZYnEqP0k Br8ElWwBYItbdiGIQHAuKA/E0wHHUv1mCJQbYfCXUGAVtrcKfbo0Ys0iJFtcS7CP tVQer8idXBSFgOrP4sN3ZZ1aEKXGjqKrnbYtLpcYLGAyXEddCMZsosMdzkupxhci FeaaKtHcjRw4/y9r7zfWvO/JihuIO2wIYBpjZEd5nVz/yEwRktUzSGDPE+WYZCsh sJxIeNRFQwTkZfERLRR9eAft1U6QAuG4pZvSaSBszZmvYDax9fYwDOsOqhQWKkTG LqO/2O4BqG5eFRd61UAL6hNblkmZDI7Ga+4KAxjhgSg9o1V2odXCsKQZJWEHZ6rk Tw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGdTCCBV2gAwIBAgIQOexs/CYaz76Jj6FFcFybCjANBgkqhkiG9w0BAQsFADCB gjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNl cnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAj BgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMjAwNzA5MDgy MjA2WhcNMzAwNzA5MjM1OTU5WjBdMQswCQYDVQQGEwJERTEcMBoGA1UECgwTRGV1 dHNjaGUgVGVsZWtvbSBBRzEwMC4GA1UEAwwnRGV1dHNjaGUgVGVsZWtvbSBBRyBz ZWN1cmUgZW1haWwgQ0EgRTAzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAy5M9+EQVHsqVmNXrXC5cl6buFoT7jSwBAF225pQcqKS4rZjsQhcCHcKdrr8E 5m+WTYVv4FypgnHMIV70jLnn/8JVoeQM3goNz+jJSYDKmTLB57SOvX+XpEgH50u5 CiATD7QbNoB2U6XHPSlZn1dyZBFdvwlPe7XfHeNkCfeyxjE5LNrG5m5SHNKIGUD8 jTq2f2FQGVDkGoJsF78fjIGNseFOo9GWqOvOe7GfONnhyMccBditlJs2O3qUtrWM HTL+BZuSOvcJ8K5UD8//TH2CcbAjhvftTVUkFmLlPMxd0JzxyACIDk+IfokcAQin xJTmGbdhBIhXUo+sc7xlGkmHHwIDAQABo4IDCTCCAwUwDgYDVR0PAQH/BAQDAgGG MB4GA1UdJQQXMBUGCCsGAQUFBwMEBgkrBgEEAYI3FQUwHQYDVR0OBBYEFAdHrRAe BvSndBFgpb2hKzeK8/NdMB8GA1UdIwQYMBaAFL9ZIDYAeaCgImuM1fJh0rgsy4JK MBIGA1UdEwEB/wQIMAYBAf8CAQAwUgYDVR0gBEswSTBHBgkrBgEEAb1HDRowOjA4 BggrBgEFBQcCARYsaHR0cDovL2NvcnBvcmF0ZS1wa2kudGVsZWtvbS5kZS9jcHMv Y3BraS5odG0wgfoGA1UdHwSB8jCB7zA6oDigNoY0aHR0cDovL2NybC1jcGtpLnRl bGVrb20uZGUvcmwvR2xvYmFsUm9vdF9DbGFzc18yLmNybDCBsKCBraCBqoaBp2xk YXA6Ly9sZGFwLWNwa2kudGVsZWtvbS5kZS9DTj1ULVRlbGVTZWMlMjBHbG9iYWxS b290JTIwQ2xhc3MlMjAyLE9VPVQtVGVsZVNlYyUyMFRydXN0JTIwQ2VudGVyLE89 VC1TeXN0ZW1zJTIwRW50ZXJwcmlzZSUyMFNlcnZpY2VzJTIwR21iSCxDPURFP2F1 dGhvcml0eVJldm9jYXRpb25MaXN0MIIBLAYIKwYBBQUHAQEEggEeMIIBGjAoBggr BgEFBQcwAYYcaHR0cDovL29jc3AudGVsZWtvbS5kZS9vY3NwcjBBBggrBgEFBQcw AoY1aHR0cDovL2NydC1jcGtpLnRlbGVrb20uZGUvY3J0L0dsb2JhbFJvb3RfQ2xh c3NfMi5jZXIwgaoGCCsGAQUFBzAChoGdbGRhcDovL2xkYXAtY3BraS50ZWxla29t LmRlL0NOPVQtVGVsZVNlYyUyMEdsb2JhbFJvb3QlMjBDbGFzcyUyMDIsT1U9VC1U ZWxlU2VjJTIwVHJ1c3QlMjBDZW50ZXIsTz1ULVN5c3RlbXMlMjBFbnRlcnByaXNl JTIwU2VydmljZXMlMjBHbWJILEM9REU/Y0FDZXJ0aWZpY2F0ZTANBgkqhkiG9w0B AQsFAAOCAQEAeVnaV3f2BmqczOBf8OLdFKrEHZoKP0BIOY3LMd+nPYddYhx5QyE0 RSJH10voeykK0djL8XP33WysjjcQgj5yWiDeqmtskwRN1RhdEOek3PkOVjeICC9+ Gw6gvFFtxv6dpaZImzDxCRhLz4LbL6i2619RAMQDWZr12CXoSBwFwjZ/NTOVVdpl pGo7z1v8FjGcoF2Y+YghJirrOKLkL2J1jb8+mwsLOjVJ2nvkI4Pc8TdIPLpbi/9X 3Aw4sge3BVyPP2ZLkd3RGVc7CozSYgJGpNshVECs5foMvYnnYRoTaxxTcoVtfTSD GOfYyqspsbEI+GmJDJZT8P6c2cQM1PSd/w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE9TCCA92gAwIBAgIJIrmxcvqTGlt0MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMjAwNzEw MDQ0ODU2WhcNMjkwNTI5MDUwMDM5WjBvMQswCQYDVQQGEwJKUDEqMCgGA1UEChMh SmFwYW4gUmVnaXN0cnkgU2VydmljZXMgQ28uLCBMdGQuMTQwMgYDVQQDEytKUFJT IE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAugEUcFm77dwcABYYJs+l8ubkpp0US4zC DOeIvvHsb/Z+RqD80kMLPlWTjB17UgKT4oG7wQGoWWdxoXB4sd58cKhf1+mFBRH/ 9myD9e0hloK3iWn8KfffpvywLD8iNOYisOaJaW5HDnmwRLeNNsRtuG0jPAghQ4wu 2Sl0kTts7/u3nTQGDdNlnhfhYikR2mSCVLEFndUZreoUq2q5nuPAzxT943Ct6sAd orC8F+B1GZNk/Q3rwCTYuIb/3l1wB1jYugZQiYH8jrN+H3Q1ncgla5lhq7Mow2Vm sUgo7Ut/PuqHfs0eVK8oxra97RxS4dL6nOJNWupXJzsFCMjU87Lf7wIDAQABo4IB pDCCAaAwHQYDVR0OBBYEFKEQFdgb/p5Omk4d8rZfQROCHUFTMB8GA1UdIwQYMBaA FAqFqXdlBZh8QIH4D5csOPEK7DzPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0P AQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9yZXBvc2l0b3J5LnNl Y29tdHJ1c3QubmV0L1NDLVJvb3QyL1NDUm9vdDJDUkwuY3JsMFIGA1UdIARLMEkw RwYKKoMIjJsbZIcFBDA5MDcGCCsGAQUFBwIBFitodHRwczovL3JlcG9zaXRvcnku c2Vjb210cnVzdC5uZXQvU0MtUm9vdDIvMIGFBggrBgEFBQcBAQR5MHcwMAYIKwYB BQUHMAGGJGh0dHA6Ly9zY3Jvb3RjYTIub2NzcC5zZWNvbXRydXN0Lm5ldDBDBggr BgEFBQcwAoY3aHR0cDovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0MtUm9v dDIvU0NSb290MmNhLmNlcjATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B AQsFAAOCAQEAjxg0fHoBxx3WPV4ITiCeWZWcbnN2t1mJZpIzozaJHJW5jT77U7OE mHOsujQUqSUgxVU5/zpVzCvAGNZSVTkK8QKQnhP6H27GKeUqldt5cX/eb31VpChb 7+w5hTsEZtG0d5V5mq9b6KcorGXHWda26Pny2FQO4+3rFYFjdflr9WtLxiMSZdg/ 8n4xRLvz7zJmoVgH+yvFxwkeVuzYGaNpvf/omzAuWEzrdfzaHhATl34w/yuAsIky 5on53pY6O5uLRX7xXj0mrSWW0tcpjeRkkN4OZsdK7YJSwVNK3HRA8uJ9wR9txR38 SUDJGJto605NrIE8kN13Bw1GTjbrSpa70w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE/DCCA+SgAwIBAgIQIrmxdeNaJz67b17uAq2d2DANBgkqhkiG9w0BAQsFADBd MQswCQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4s TFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4X DTIwMDcxMDEyNDc0MVoXDTI5MDUyOTA1MDAzOVowbzELMAkGA1UEBhMCSlAxKjAo BgNVBAoTIUphcGFuIFJlZ2lzdHJ5IFNlcnZpY2VzIENvLiwgTHRkLjE0MDIGA1UE AxMrSlBSUyBPcmdhbml6YXRpb24gVmFsaWRhdGlvbiBBdXRob3JpdHkgLSBHMzCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALoBFHBZu+3cHAAWGCbPpfLm 5KadFEuMwgzniL7x7G/2fkag/NJDCz5Vk4wde1ICk+KBu8EBqFlncaFweLHefHCo X9fphQUR//Zsg/XtIZaCt4lp/Cn336b8sCw/IjTmIrDmiWluRw55sES3jTbEbbht IzwIIUOMLtkpdJE7bO/7t500Bg3TZZ4X4WIpEdpkglSxBZ3VGa3qFKtquZ7jwM8U /eNwrerAHaKwvBfgdRmTZP0N68Ak2LiG/95dcAdY2LoGUImB/I6zfh90NZ3IJWuZ YauzKMNlZrFIKO1Lfz7qh37NHlSvKMa2ve0cUuHS+pziTVrqVyc7BQjI1POy3+8C AwEAAaOCAaQwggGgMB0GA1UdDgQWBBShEBXYG/6eTppOHfK2X0ETgh1BUzAfBgNV HSMEGDAWgBQKhal3ZQWYfECB+A+XLDjxCuw8zzASBgNVHRMBAf8ECDAGAQH/AgEA MA4GA1UdDwEB/wQEAwIBBjBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vcmVwb3Np dG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290Mi9TQ1Jvb3QyQ1JMLmNybDBSBgNV HSAESzBJMEcGCiqDCIybG2SHBQQwOTA3BggrBgEFBQcCARYraHR0cHM6Ly9yZXBv c2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJvb3QyLzCBhQYIKwYBBQUHAQEEeTB3 MDAGCCsGAQUFBzABhiRodHRwOi8vc2Nyb290Y2EyLm9jc3Auc2Vjb210cnVzdC5u ZXQwQwYIKwYBBQUHMAKGN2h0dHA6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0 L1NDLVJvb3QyL1NDUm9vdDJjYS5jZXIwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJ KoZIhvcNAQELBQADggEBAI9f6Zp4RGKZH24do0uY4rIMfcN7b4ReMu+PzVcU83VI TWz8t9emVs9NsJPdohMpgSRmqoHU6HuSlKbx73L/owf+8aBPG7bPhZ0xAYOQwI8g LT/V6gfBrICukGspfASqcVmDCeTN/zXHxXkfi7ob0F/oQcAPwBBjVKFCoIvyPK0Q IBfSra4M84LG95QcshK36DD6UCQOjtewQXHRJHUSTNr/Kg7OUWlUss5biWidAhjx UFQwbq++nNqn0RWJkQOuPo06AVoSsrcomMAAacuYcKJDByJkQMS2TomSaNOrvgLL JE2HY8DmuGjgr5SECorLEfpfAHZ+gBdpqXEIZ1YW77w= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtjCCA56gAwIBAgIQd70N32OE/7HRSj7dg4PIaTANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MTEwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMEsxCzAJBgNVBAYTAkRFMRkwFwYDVQQKExBEZXV0c2NoZSBQ b3N0IEFHMSEwHwYDVQQDExhEUERITCBHbG9iYWwgVExTIENBIC0gSTUwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDq/LPe8xgyLgwimOeFnrqppaa6Srlj 91063O+bA0Ppi6XQFWsL+jcJlZtNXqAfuZQuvW0Qiat4lx2/4xAyQEP+Q8ekMcSb Tc8ExKew/83H+mKHdOPB8J4QOhMvOPQbQa5WoI+lCLdWJcYdYnAc59TQWYZ7vMz4 qcjw66LXL26oalzp445gGkTw2xqAvP57FfmlCpZ9BtVpqXTgWM9eXECIcA+PHazY HnbXION18s+T/rtnCtgyKrDHTr2KigsQwT9V4Seh5p1U96ZmA+68iO1YMjvddWOs vbskCfWWjfx8LQ2fyr0250dotq50BUtiG04DEimwfas0otGaPMpSNdLZAgMBAAGj ggGTMIIBjzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFO9b9EuG+db5OlOJ CbwgjrwayiJgMB8GA1UdIwQYMBaAFI/wS3+oLkUkrk1Q+mOai97i3Ru8MHoGCCsG AQUFBwEBBG4wbDAtBggrBgEFBQcwAYYhaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5j b20vcm9vdHIzMDsGCCsGAQUFBzAChi9odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24u Y29tL2NhY2VydC9yb290LXIzLmNydDA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8v Y3JsLmdsb2JhbHNpZ24uY29tL3Jvb3QtcjMuY3JsMFYGA1UdIARPME0wCAYGZ4EM AQICMEEGCSsGAQQBoDIBFDA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9i YWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAwaGX1W8P hVIMRwVxEjdRip4vb5UUw9RlFZ7qej9/irzpFGdoa+6YqRpDc1kxpRxx9COzE3m3 QVyYw4XfHIknJCNqCfAdFzgtk1DdRRCO4PV3DGHqu8NQPWnvvx6kw8a+tJs4Eoif 10EN1hw4JEE+7106updRbPIJz3RErtc/3iee1BHaK4hiV9rOM5LsJ0qWRXXAVjmn tnLVdTR805UFnI1KiSCURz5JTSIuYhtsdlo+iK51WXxYfaEOB0XvwIxpJ2Pq35VN heh/whbOI5vUAVzXY9aVlOdXETchFy4UopYOZhKEbig1oeVXavNoqmMcRyELaPuq 1/x47/8wT0zxIA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFrTCCBJWgAwIBAgIQCDlejq4ufZybNuIz+VhRpDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwNzE2MTI0MzQwWhcNMzAwNzE2MTI0MzQwWjB6MQswCQYDVQQG EwJTQTEzMDEGA1UEChMqU2F1ZGkgQmFzaWMgSW5kdXN0cmllcyBDb3Jwb3JhdGlv biAoU0FCSUMpMTYwNAYDVQQDEy1TYXVkaSBCYXNpYyBJbmR1c3RyaWVzIENvcnBv cmF0aW9uIElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDek8ODhuJVuSlT3nk5h+37G0VtAvrjp4eXv5Tc1/+7+6rtFpOtbrqQq6IZyJo1 5tsXfKpF56+Mno7oAxU7ZWP4SVVwv1gLHnUlb3KbEua8S+8f0j3/6l/aQ29dHmJR 7aYAkEGyXNneYzrUOLqVTR0MLcNQUiCZpKKe21dI94GMg40eVZ8+Bc1BmXdtO9Hc DquxIIM6jS21OXlcOUwHbzNVWDM4MZQD/skcLD07x2MkdHfOS7F14SKP0eDOmhEx 3/8ccjzIF6yu1qiibpSZnYvUiqiaA7WKndfqWA3Ff8VK4Sa5/Wk0rnS/uRuwCiqS SRXQq7vsyIjNQDrLRFWn/ORrAgMBAAGjggJCMIICPjAdBgNVHQ4EFgQUZwHFXOAh 1rM+Fgvl1BYEi881EFwwHwYDVR0jBBgwFoAUzsNKuZlV8rjbYL+pfr1WtZc2p9Yw DgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAS BgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMIGBBgNVHR8EejB4MDqgOKA2hjRodHRw Oi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3Js MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVk SURSb290RzIuY3JsMIHTBgNVHSAEgcswgcgwgcUGCWCGSAGG/WwFAjCBtzAoBggr BgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBigYIKwYBBQUH AgIwfgx8QW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVzIGFj Y2VwdGFuY2Ugb2YgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50IGxvY2F0ZWQg YXQgaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL3JwYS11YTApBgNVHREEIjAgpB4w HDEaMBgGA1UEAxMRRGlnaUNlcnRQS0ktMy0yMTMwDQYJKoZIhvcNAQELBQADggEB AMQ4Xh1Tno0jKP/MIYaWeaMbF3+/TS8dDxZp+HxtpUfXFYBZIFu9MavyDXHsBP9u nVx564BeFi/Rlzb0fxr3ePimGQp6lh7dhMstnCca+NmN/UYnON1XUmD4RHF9JPv9 D+8omaVtCuxAO26VNpzZ8v1oibuKvr5fGTEmk3OrNim7VcaVQCshjzM6WWPF67ab YMzRJg5f8hIM9ErUsEtFS91UNn9AH1m+YFmAp8WTkfGuPEnl+O7yjgnhbR1TZUfZ bYQ6TtDgqDzFp/ojc4cpfukO8aiPV7g+ROUdi3tQ0iWbvrdTuhLUk7gpC0qz2JH9 gCcBb5sv0UxADGVS21Df/hA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFnjCCBIagAwIBAgIQBvNpsuMhAtgw3DIzPu010zANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwNzE2MTI0NDIyWhcNMzAwNzE2MTI0NDIyWjBrMQswCQYDVQQG EwJTRzEpMCcGA1UEChMgTmF0aW9uYWwgVW5pdmVyc2l0eSBvZiBTaW5nYXBvcmUx MTAvBgNVBAMTKE5hdGlvbmFsIFVuaXZlcnNpdHkgb2YgU2luZ2Fwb3JlIENBIC0g RzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyPXKoYynclY8uYRtR acGIS0RiEAmSeZPNhYutjpn358+PUhLMC7BTNWdmDdTJKUkoej1yqzmykU2suYW2 VZ4IjGiRDSyMNodZIb22jluWe8FhBCZYeXRRwiDus6gwfxnk4MafT+wNkKDegzCF SGdWGy1zFnCL8j7o6Y9WT3kykmz1KBmIKLVtYaSFlIGQ5no9EFufkrCNWITXEaMb 4JjWcN4ZB/o78ogGLxSAEPICvCG547gGh7o6jc4WD/rVbDgw3mhKA+KeI1HafRIs pkln4jO+9mE3PR9eeiSucpRQaqBLq/jDpedMDsDBrPKnHx2ZG6A9/Ru36tzbQ1gv IjtXAgMBAAGjggJCMIICPjAdBgNVHQ4EFgQULrDioVT2MW0/Rl/J8AyygSNUWlEw HwYDVR0jBBgwFoAUzsNKuZlV8rjbYL+pfr1WtZc2p9YwDgYDVR0PAQH/BAQDAgGG MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDASBgNVHRMBAf8ECDAGAQH/ AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln aWNlcnQuY29tMIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2Vy dC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMDqgOKA2hjRodHRwOi8v Y3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMIHT BgNVHSAEgcswgcgwgcUGCWCGSAGG/WwFAjCBtzAoBggrBgEFBQcCARYcaHR0cHM6 Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBigYIKwYBBQUHAgIwfgx8QW55IHVzZSBv ZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhl IFJlbHlpbmcgUGFydHkgQWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93d3cu ZGlnaWNlcnQuY29tL3JwYS11YTApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRRGln aUNlcnRQS0ktMy0yMDgwDQYJKoZIhvcNAQELBQADggEBADh2ANvwVs17bPgXRwXO H+IfXjm4q5j49ZOPd5+qKxwTlFv+zanXdld7MFk1m04q/R/Vgur8NafhSMgQjof1 f1shUIf8CBmV6wZwvCntUyZEBTBedV//Pwnv68ZVT1IRDXrHwE3TVNyeVBRoKVfv ZH5IiaY5iUaCZGgaYx5SUZWntErCQvQTyGFhgmCkfAPqvO/mKhCVheTyMqYXQmaM SWLL2UC3Ykj22nvVkPYQjGdWWVeTT8gJIwKThp4V1bXH6zeynZMUYpqfg4ADxcgH 45WwgEWNrKKtPMUDy2NBoLDMbTj9TfNlhfi4gf47dC3wqbSP9q0975To45XTqg29 E08= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIUKKIwimvEDTefdvWRnf4zoYu8/FwwDQYJKoZIhvcNAQEL BQAwVDELMAkGA1UEBhMCQk0xGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxKjAo BgNVBAMMIVF1b1ZhZGlzIEVudGVycHJpc2UgVHJ1c3QgQ0EgMyBHMzAeFw0yMDA3 MTYxNzMzMTlaFw0zMTA2MDYwMDAwMDBaMDwxCzAJBgNVBAYTAk5MMREwDwYDVQQK DAhLUE4gQi5WLjEaMBgGA1UEAwwRS1BOIENsYXNzIDIgQ0EgRzIwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQDC1Cv7jAp9b4ODT/UOTxF6EHkuizBO3khT kzHIdajGCLoZ2+x2vn99W/PXkuwlPvTAxZYnwkZ0y/t/4tWoAbfLUdNyueB87NIP G8YAUhK5QFMIYh0UDyKbWo4ndYX/3yhDDj36majS6bkykbqZs5VK6j+EK/IIDoHY 1ujAczl8Um1fNVf6GCas4Rsy7SLL/sgb8yGwrR/NKUytKw1lVMYNsBlfcPG78lrp x5KcQsV/9YAWk5EBqc2/+UOzFuioCcA1fmNU9GyKd9zsJvg9SLKhhwFprxJnym+F wkP1EH1u4iAAi2t7t4N0KmYeOQPn/CnzMJlpvqVgArkPZ5ZEnW5o4QgsTHNeY2PK EqHRRg341TXDyHNU3IHk2/VU9DboZSnLpFLXYp7YgOUKb9iiWoJdYmBu5OuOCMpR aZvsaVHbEsEMEDZpIWldvEwhzOFj8Y+UvtNy3bQYg23ozsm0RF46kyqDNRz/YkBt c8bEt/EETPTDmH6wfvpwo0pbRp3V7dKKyWRLrsfldANWjn5JvTsRUYD6xGaroMqS Gaut26Lzzwz8Zp2DNfm+Q9fxMlrfsluh9+QiNQAWQJH9g8urB55ynXyGT59tQhTd hifKYe3fahk1RuMvCggRWKEluDMqUYYVGhu3IIs2mMfQmR1whveR8g7iI7BEWShq /hsvPayT2QIDAQABo4IBoDCCAZwwEgYDVR0TAQH/BAgwBgEB/wIBATAfBgNVHSME GDAWgBTwFmAimDWJL4b8zdmHHA1jVW06RzA6BggrBgEFBQcBAQQuMCwwKgYIKwYB BQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3ZhZGlzZ2xvYmFsLmNvbTAnBgNVHREEIDAe pBwwGjEYMBYGA1UEAwwPTVBLSS00MDk2LTEtMjgxME8GA1UdIARIMEYwRAYJKwYB BAG+WAADMDcwNQYIKwYBBQUHAgEWKWh0dHBzOi8vd3d3LnF1b3ZhZGlzZ2xvYmFs LmNvbS9yZXBvc2l0b3J5MEEGA1UdJQQ6MDgGCCsGAQUFBwMCBggrBgEFBQcDBAYK KwYBBAGCNwoDDAYKKwYBBAGCNwoDBAYKKwYBBAGCNxQCAjA9BgNVHR8ENjA0MDKg MKAuhixodHRwOi8vY3JsLnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdmVudGNhM2czLmNy bDAdBgNVHQ4EFgQUUL0zBvqEQv2+CTbdqOL0bZsUe88wDgYDVR0PAQH/BAQDAgEG MA0GCSqGSIb3DQEBCwUAA4ICAQBzeftADuDOBjOAVFYVPG3DV7xLDhk5JcoBiXVm 8b4OLuZGdauX4/JI8UVxqPWzLppZqPS02jrbnfvlvQhA/7A8l5xyKaBLCyTdu9p/ j3wPnvnyuOl0uJ/CywAs+g4ffEBt1da0fO+ywJ8SwterhhAn/DTEvRGpoWbPoudW pp2kSjY1WoxlwIMZ1XJp1CrpY0pwcFHhC1PASt00SgqpXJ77mCF0xRjalLByL9sG yQvsfCshrxoCDG7dQsPXvXWguoufhqMO4cKCdWNZIFY2lRnsn924sHczyBMY3kTv /Ad9t8QJhet6YmLR5C+fZx/6JfjX8Lm6TMPTgrzw6Vs+7LQKjXQRGQNbmV3bGp0L gCcrT+YgurAjdczQgOaQZMwZKI05EJYHhJAytsve++xdiT1VFlZ4fwL7AyTWkLU9 myPNPtASs1ok9ZHVl+igbgQWOW4sbl/K+8dPB1W8yvdIMNTmMwkhEHblj7WTrTn+ pEaivt89GJC1bjKqhBPYz0DdKZBqgXEPWZXUJXXn5yZVRpgOMyHHcEYutOukWDlC uaXAph2k4jkEMpKmX4Uivoir6Kp1oqxrl7COthLygRJk6FYM3BsH2eek4IAAZ2vu Q8yoN07GHUFyvp7lPORZgpT1CfdoYJwF30NC+zKkF6wsRVbA/9+tswDcMx7qlaSs Df8kOA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG3DCCBMSgAwIBAgIRAMcn9R+PkisCAAAAAFVl2K0wDQYJKoZIhvcNAQENBQAw gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 MB4XDTIwMDcyMDE1NDYyMVoXDTM3MTIyMDE2MTYyMVowVzEwMC4GA1UEAwwnRW50 cnVzdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEFBVEwxMRYwFAYDVQQKDA1F bnRydXN0LCBJbmMuMQswCQYDVQQGEwJVUzCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAKKEHAlgvl7w7LCEr9hxW+TSTVDqBRbE1BTzVmB8BARbqT+0Rzvo ZPBfQLvrwnJXMoc6+iNbuh0D59VNtWVO30XGiyBNWMVtnf0MxJt2a9dQnIskEsKc AW6QWwiEWvZs2Jot5Q3HuHlqFAA3dIZ3IMY2FNRNF3uQbc3LR8FPcAoa1G/OW79d MZPob2hBEWPyfOzoV328vxhRoVnfT7YlNss2CQjhY3ZDlP0O1TighoMzbcSOxGED YaMRYQotrFHEd+Ezpnj8WwDK6s+Em5DV58BSX/NwdUSwCEGcL13v/mUdEk0LOzXR mVrwdFtBg2bsiDHe8m/XLJqGd36uQ/BiW/td4GI666S/OdK8yDwV8zrSQYUB41qp I7LqaR+jAI4DBKYZDg1gaNLM0w8T9a23GaWsrchTHytJqO0f+rK8ugEKURCdwvJk b7AFla0tknD0ORJb2X/nkmYBGlumg1k8XQNUAi5Iw7Lcqmgtv/P9+F+6laIIy8en 5h/vHqUH8rh14mN83ZPPntuJR5DeZfTG1xEmpI4Z8zsO67xU/7SBdeYrO3k+hfD7 b+IZNaMjTRfEqT0V+L9WSD+auKcoiuteSGidiyQvtHE25ovZOgrHrMkaYntqkDkH cTLnAPDP4RqA+L8nfiUQ/tDK7tbsR8yvguqkn/kWACyRfImWyjSx3As7AgMBAAGj ggE5MIIBNTAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBATAqBgNV HSUEIzAhBgorBgEEAYI3CgMMBgkqhkiG9y8BAQUGCCsGAQUFBwMEMDsGA1UdIAQ0 MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0 L3JwYTAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVu dHJ1c3QubmV0MDEGA1UdHwQqMCgwJqAkoCKGICBodHRwOi8vY3JsLmVudHJ1c3Qu bmV0L2c0Y2EuY3JsMB0GA1UdDgQWBBRj8YTdA76jn2T6dnpHxFZ+wG2gIDAfBgNV HSMEGDAWgBSfOMRWI8M56KBxbOhUTOToOrG/ZzANBgkqhkiG9w0BAQ0FAAOCAgEA fZvwnjoK7QkDKArcYjdJvs9l5ecWAdEtrH2ChzLadgjmPobcPm4+nsuicJeO3/Bi ezQibkwUr+uLyKaUzGCg6R2zNWOcw9WDpb0/11zwJI7fzJookmMWnqnlBY2PRj6N OisEFr2rSI6SLBpzNIeemBoYg7xe80h1K3/qWBQVj59jkuYJbXBe3mWnqNssZJjU T62+xOtJuoBdJmEIfu8rVh5pyE71+UHbz/aVG7Cc1rdoUoj3R4u7E3HRNRRvi8AZ uQaOoHMVRhCkJwK2G+QLkaRWLJZW+y/shKDj63RGOHl3QbhrQ+n2QXPm5UJTCseG u2O4uIJge4Nk7B90zc5238clvxdiJBESeuGJcFrDRE7BH94QdA0BF5QS3tScHl3Z ZD/j0M6r2CwscoCZTVhVC9w+cbYWCHIg74g+RVMLwgh/8gRSeQ0FarZsbVvXGXiz RyTGpL760Zquvv4bwZPeAvOd5o17JH7vClHMrPWdhhbt+HUP3iOMTlN0IITf068C bhxX8tQwxwHBmfzII4BNRLTEwz8l8E9jXsFj8BW1HBjonsuFVGBHAA3FH2IlOaRy T53C5ZUm0GEgt1G+XZBY4+QLG+4YamG5Vyfp4swoUIVHfwwdkpsR8KBASN8xKpCI HdAXsdCGIJo/0EU9FiKURWL3iah8q5QVJzTg9wcjl6U= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGtDCCBJygAwIBAgIUOgIDIraBbBi3Ksu1kr73TdeGqLgwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0yMDA3MjAxODAzMTBaFw0z MDA3MTgxODAzMTBaMFYxCzAJBgNVBAYTAk5MMSAwHgYDVQQKDBdRdW9WYWRpcyBU cnVzdGxpbmsgQi5WLjElMCMGA1UEAwwcUXVvVmFkaXMgRXVyb3BlIEVWIFNTTCBD QSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKrPG2c5Ys5v+NBI iWlMBF8GmvdKOYCvS5U+T7AiZPKXVSD62aps1emdYaB0zOWLcVg0EBRtuCbq11Bb WCsX07/PQAs2HB46FZ0QaGr8nUjMQKc6chtdKVio3x2w/LcyjvSHOb55hYKzH5ul 7cfxBZLNtkltNKhD2Jct8wxSb8nWG+BRstfwTr/74DNnEnIFO5kCZwO+UzIntbrY jcDiyT51ZPbS5v3DFed6NDF5tCkWSsSxuSWpukMqNEIkh7claOeNoZ9q29bnXT4n OsrxlmvXbW22jg2rnSeqPr8SB1fVHcyKElzNvYdkDkfG0ynW/XDSV+XnsGtEI5KS VmdE5IL2ZvyuJUQ9L/7HUktHYWfXsgZjvScdixB8XHr8CyS7TWjd4K2Ckl5hNjNL FZu/Pb4gLPcQ7dwby0gnpcpaeUPQjo5YfHs3uUIurIW5vWnMM2g9gMew0e1Zru2D Dl3NI0TbDOsX22r3T895pSC2rj57hkbXwgUdxkfZq77tIr4/LLoqBw59MaNFurMf /sUfMzULsEqy+zU2B+yQtdiFPaF2QzWY9u5x1f3Wp2lqiZOZ2tw26/m+RxSuoV6K FgfxtOSaEsDow8GVVx8J37vZ6FWsYoQyYlokl+k9WtoUukzZ1JDvZHCxwrfKmgEn H7xPq8Hgdm1l4pEVIarBqbR1Z41PAgMBAAGjggGGMIIBgjASBgNVHRMBAf8ECDAG AQH/AgEAMB8GA1UdIwQYMBaAFO3nb3Zav2DsSVvGpXe7chZxm8Q9MHQGCCsGAQUF BwEBBGgwZjA4BggrBgEFBQcwAoYsaHR0cDovL3RydXN0LnF1b3ZhZGlzZ2xvYmFs LmNvbS9xdnJjYTJnMy5jcnQwKgYIKwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3Zh ZGlzZ2xvYmFsLmNvbTBKBgNVHSAEQzBBMD8GBFUdIAAwNzA1BggrBgEFBQcCARYp aHR0cHM6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL3JlcG9zaXRvcnkwHQYDVR0l BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6 Ly9jcmwucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMmczLmNybDAdBgNVHQ4EFgQU ST0O3HnFy9sSo9UNq/LPqa/jZqkwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB CwUAA4ICAQBLq8aTwO+Wvdtt+j5DIlt1wXU6uy48p27SJbcQLhHEbXWGpn9xIQBA mGuIxzh2dcAPRo34cnBjOOIluG8xw9oDW5ZEhP9/qFVMgkNZYELs4UQ/oNncIdzt /AJDjaoDICa5SZuVcng3WGl1tNV6HR7Z7B6Me5C3oglpxz/qnsjW0WFzkk3H7pc1 0TtOpkcDdw4jHKXi534RhoHJUbyasFMaIWwt3oIV7ouio1mU+UjfkezfqnN0uTde ypS71ItW+Cpfi/dMsypgshd34SeLYKAfaZx8/i52dIF1P8FfO9mjIisQSchdDiB3 LmEhje1B+LI5h3syzXJ90JJSHt7j3fG2eWpULSwqiVZbpAV6BnkNIcnhziCZbhPR 5LMl84do9ql5tGmyROe8Y6NPXppBuDB9MhTo6mPjSsIQzNgilBPmi0ywADtMK2y+ uVNVdUoi2i8d8NHmGnQs7R0fXWxOEfOvtCIangPT6h98rxV+c/2afHO5ykH2IAB/ 16TPO99YkPDmmlWVH+Ut1dtpIcKVOSctwtULLTnR+/ow4CezaBfxySVjd+LjgV+s wJymghxkcN/lNw6cKKWkD57w3zP5OOJstLcEbTwpWTih/mySRHe637bIk2qqmgcC cby5saCrgucuk5exvOqwqkkCSqWyL5UBE44jIMJ/dRrD2/CaYBAUtQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGtzCCBJ+gAwIBAgIUPB6WE37kIFeXPOSYy1DarkwePEgwDQYJKoZIhvcNAQEL BQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZ BgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0yMDA3MjExODAzMDdaFw0zMDA3 MTkxODAzMDdaMGAxCzAJBgNVBAYTAlVTMTAwLgYDVQQKDCdIeWRyYW50SUQgKEF2 YWxhbmNoZSBDbG91ZCBDb3Jwb3JhdGlvbikxHzAdBgNVBAMMFkh5ZHJhbnRJRCBF ViBTU0wgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDT8S4Q fbSeKHgGGhoE8fP2oTI7sLfg6pE6PFNikH735pFuiE9GFyFkO9RLhiC+9Q5rGqmp MZZefazVZ0a9YZE6Eoxa36csvFYAXaNFYjTds4kPkNDBQgCzZ8yuy7K6AWTjgBWb ur+9rhGWBBX036M9GTe+932MB0h36xOlOTbacsRZka3MWcvTr1rAH+jdq7eDhbYJ Euao8WiP+94hqh2cghyFNnL6Ag5Vm0VolL4E1dVliQMRyCm4+xZE88yE//e/Ira0 NldWLpEGa+92DbFEQPAmvkly0EcbOYHwV1khqSTF0NrqiaZJ8jd4ZWTd/0w3K3W7 +I6lkCstOkzJKnZoOlt9e5L7RrPx4aySN7CIIkOlL43r8AhRSnQIOCELnntv724m 9CRaRNTUIGurcxiBT80VTtO89MBpoz/WCk217HD3aCGf2lCgKBWoYw/VUShovAzk nH+zyJdQENhiytzxWC+2KnY7rSLn/eavGXDlhlXdb053POq00mMjbhJY4uzF6W8M ZtaiUE5XtEA4f9o3HEFvpDKaVO6owPs3C7UFyF8kIZBmTL8686VLDR06lWKjtntZ VI/l3j4TY1WibMFeloP645sbocUyWdu2bYcn7iB/yrS/hR2E5HfOTgXM1ZPsG3D+ CBZpmN13Bejfqi6axP04HQr5CEhwPf3/PMBgHQIDAQABo4IBgjCCAX4wEgYDVR0T AQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBQahGK8SEwzJQTU7tD2A8QZRtGUazBy BggrBgEFBQcBAQRmMGQwNgYIKwYBBQUHMAKGKmh0dHA6Ly90cnVzdC5xdW92YWRp c2dsb2JhbC5jb20vcXZyY2EyLmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3Au cXVvdmFkaXNnbG9iYWwuY29tMEoGA1UdIARDMEEwPwYEVR0gADA3MDUGCCsGAQUF BwIBFilodHRwczovL3d3dy5xdW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeTAd BgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwOQYDVR0fBDIwMDAuoCygKoYo aHR0cDovL2NybC5xdW92YWRpc2dsb2JhbC5jb20vcXZyY2EyLmNybDAdBgNVHQ4E FgQUtoWFXyB8D8FScaKE9a6DsBXg0EIwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 DQEBCwUAA4ICAQBKoYxV593DTOkLKTV7kjgzvHkprbfaxLfVIAgIw9uKw7bZFC+H mAlKGqlCQGPfKJjG6JSVshArAN7fZCyMCjaSZV4+0xnhmnqwxP+37/v9y6mGNu2n nSnVrQuEF6dW3J+5uYGDNVHbJGw71M85zdC4Wnp7FVqEToIa/0Otyo+3gAz+P/eM VTM44uwhHnLszO0Zpe0MQZWHhqUSOGvKnuV309852zc5AgfuZs/ouasXBTw9tjVZ bk8506psprpsb51aQg3Mdm5v5aLmfivmQQuXFUQPYGaD0mVzq8Bx+HToPndv2FEG B7shSkZhxIracf5S1fIUPR9ikA94xE0MxKztsnUFD0fE0UIhIm3FOICyqMLMy+TP mL3L/Uy3dSNq4M9++Il7RAi/eoRkxYYhAbLeuWNlBSyx+6dM1RSMJojOCjyv9H8X 0Q0y/3CKN+hmdPWC8YYoojF82nk4lsAHYvxBnw+9CxQ3tDyDtA/1/D5f0D7E02TD bEuoDHwY7IIrqc8py1NFKvzO9aIzajSXUt1kYW9zcmFw7EubSkOJFlNcDdT7oVSF BP9zdIRyTfFPJGfidwJy8u8UryXBvOpn4wTt2TsTJC/H6nY5F3tIh/qPA0MluQnc pDtK9BDeTIR2UbzPwjLz7doQz+c+LrUZ7cKkhmXPXOzEA34VoRGfu4/mEg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE+zCCA+OgAwIBAgIQIrmxfns7F+n+5DAoDCwvWTANBgkqhkiG9w0BAQsFADBd MQswCQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4s TFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4X DTIwMDcyMjEwMjMyOFoXDTI5MDUyOTA1MDAzOVowbzELMAkGA1UEBhMCSlAxKjAo BgNVBAoTIUphcGFuIFJlZ2lzdHJ5IFNlcnZpY2VzIENvLiwgTHRkLjE0MDIGA1UE AxMrSlBSUyBPcmdhbml6YXRpb24gVmFsaWRhdGlvbiBBdXRob3JpdHkgLSBHNDCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN5quYp5pdUNBPOSehxFlAks Ucr5fmD5qGc/yKxNdIiTHHhyWX71SGIny4EoNGy+DmtQXESK+q3WixU+saNeIkuR VjPj2mVkYyDtaqM3OsmpYM82K3n/EbprzvXQtYDOPUwnuCvLq3z3kmVscc+bOkax J19qSIeDZl5Ooq9Cb5LWNArhd+zVAaqexxAt/bMqklnA2rPL+zSV5i/LfTCEeIye eHX20seBAWSLLWEt+wKone3G1GvO1hqZ4iEjiolNuL3xlLjw/YrQTj58BIWqgWqP Pe6aatV53SBJOMtEhze/fS8WIWkxmYEMI3G4t/M4FwPID6ZiiDyK1xdjDD7dwH8C AwEAAaOCAaMwggGfMB0GA1UdDgQWBBTVNa7E1DJugCkVKtQAHLTtI7krODAfBgNV HSMEGDAWgBQKhal3ZQWYfECB+A+XLDjxCuw8zzASBgNVHRMBAf8ECDAGAQH/AgEA MA4GA1UdDwEB/wQEAwIBBjBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vcmVwb3Np dG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290Mi9TQ1Jvb3QyQ1JMLmNybDBRBgNV HSAESjBIMEYGCiqDCIybG2SHBQQwODA2BggrBgEFBQcCARYqaHR0cDovL3JlcG9z aXRvcnkuc2Vjb210cnVzdC5uZXQvU0MtUm9vdDIvMIGFBggrBgEFBQcBAQR5MHcw MAYIKwYBBQUHMAGGJGh0dHA6Ly9zY3Jvb3RjYTIub2NzcC5zZWNvbXRydXN0Lm5l dDBDBggrBgEFBQcwAoY3aHR0cDovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQv U0MtUm9vdDIvU0NSb290MmNhLmNlcjATBgNVHSUEDDAKBggrBgEFBQcDATANBgkq hkiG9w0BAQsFAAOCAQEAjX311G7z8o0GMlkpBEh+8upL/z70B1r96U9dfaObFMOy pv03Wp/wQ5Dfqw1XyJ59FDFbGpD/1oAhzIWwFF6aYgSKk37eJdRJx2mKDM4NVNPg houBNNZfmdMIAjd8U6vXHxrxEZPqSX5n2w+WJUIUndT4w1DBRsdUVAK9npDlVsM/ 86zb6makPLj5U5eHoKjrtZTsLGuJLIjYFFmjke3zqvkc+/SYtcbey2YpUVijDOh7 i0fpJlA5Jyt0Rpxg5uB/Z3dmW5XqSy8sGE/03VOB9uuLTqpGEzkVsAieGp2ixktn KJas83uFo7lT0LyRKyLaesoKqW2KYQH/9DQm5WOYUA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE9TCCA92gAwIBAgIQIrmxfwXkilXm9e8ZiAL/uTANBgkqhkiG9w0BAQsFADBd MQswCQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4s TFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4X DTIwMDcyMjEwNDA1M1oXDTI5MDUyOTA1MDAzOVowaTELMAkGA1UEBhMCSlAxKjAo BgNVBAoTIUphcGFuIFJlZ2lzdHJ5IFNlcnZpY2VzIENvLiwgTHRkLjEuMCwGA1UE AxMlSlBSUyBEb21haW4gVmFsaWRhdGlvbiBBdXRob3JpdHkgLSBHNDCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAK0FlRqq+G11zNB0er6dCpx39+QETwtz SeS58nBeRxWpBtjCz+TkunHZ4Lq/Am6bPJnXMu5Xq29NE/uNqxOn7qX7Bau6vL8p 1g5KX69nsGET2Zsq1MADrXs0GkXTUUQEELlZzIuA7JroNjm5cWdkl734A/M1gjoV fAuzu0FKFgQ0duiOm2KeepZvBbyZn00R20umulucE83dIe8i/rDBhgU2fTrKAqQz WwI+zebmJysyEVUASxSygu6e+tj4KX+cuC0Jt+X/QV0SVJddUGvsIT5m/rS+Bn9r rvo/9EY7DuOmBtdFB12sIlMrbPhJ2MaghswSJ0tiOKAVMVwxxGqTDhMCAwEAAaOC AaMwggGfMB0GA1UdDgQWBBR8JM4NpDgtx7NjXqd4eo0dTC7HFTAfBgNVHSMEGDAW gBQKhal3ZQWYfECB+A+XLDjxCuw8zzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud DwEB/wQEAwIBBjBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vcmVwb3NpdG9yeS5z ZWNvbXRydXN0Lm5ldC9TQy1Sb290Mi9TQ1Jvb3QyQ1JMLmNybDBRBgNVHSAESjBI MEYGCiqDCIybG2SHBQQwODA2BggrBgEFBQcCARYqaHR0cDovL3JlcG9zaXRvcnku c2Vjb210cnVzdC5uZXQvU0MtUm9vdDIvMIGFBggrBgEFBQcBAQR5MHcwMAYIKwYB BQUHMAGGJGh0dHA6Ly9zY3Jvb3RjYTIub2NzcC5zZWNvbXRydXN0Lm5ldDBDBggr BgEFBQcwAoY3aHR0cDovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0MtUm9v dDIvU0NSb290MmNhLmNlcjATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B AQsFAAOCAQEAgfEcL6hdF7gGJ5ZmormGBwuaUVG/8HZUxi2kDSiRWJWHNeN90Md9 Haz7MH/cmip64h8afXNMKWNvEs6Fns/CB6dlsItSMQgpzQQuD3KQNCFB8F4cHkQk 5+Hz+4T0OfVgv8F1WpcHzfHCyBwBbYW3+AOANl7KvhSonSZWUe9QUNvvQUuOR0b/ Ynp0ehKPOeIPdZlfIlsamRD36c189P5mgQFwujxGPmtD3aOhpsRPRmzr6d4lnDqC Pc6o+1Tr3k4IrZAHCuec81WDKXp/zqs+vuL+5bREDP2hI4SMt7m7KrljH7C0dFlv Z9ccuremd0sxBZslpqcxY/jQnG/BQQ1eFw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGtTCCBJ2gAwIBAgIUU72Nwg1KRr2WL11oWtoPBlkgf/0wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0yMDA3MjIxODIzNDBaFw0z MDA3MjAxODIzNDBaMFcxCzAJBgNVBAYTAk5MMSAwHgYDVQQKDBdRdW9WYWRpcyBU cnVzdGxpbmsgQi5WLjEmMCQGA1UEAwwdUXVvVmFkaXMgUXVhbGlmaWVkIFdlYiBJ Q0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCu0uHRUnf7r/GY 0XEc6ETNuC8ctNkayL47kvnmZjfxCvmZ+NpaQ61Lscr5Q+YhcOYEIB0M4GbgyJzF JUynIrsrzpLPAOAnFDjuLRIhC96jtliUPVqVRfcyRVj/dyzgXF1LrjWX2LLnDK4S Ubrq6J7epNUSaNmWXBjYjHbpWT8wgeQGwliPxLoZuN+v9fSQrLKEQBsD0cWy2xDN UNtME988lcmY4aeAUgTTJj5CMMJfLro4L8B2+FPGwjH4H6T8mnZndQEt+fFJYOLO k32xhT1gNbvTaBnhAP1f3Pakzf7wS2usHuONr/xGQIiJibkqBH1uHWHIT9eYV8eP AORs76hYJtg5D5kpnBdpuAkiKeynWEJyo90XIkxdpgRe0gWhGQ6sBh375jnmJAUc d23sotpvb8JP4XOQx07PxKLQYlmROtfOHHdPStxqmk+IcGRwciYiuBS5ffO5kWas 3U6UsLsc3yq40ipFfDKrCM4lSF3pTWrs9nEl6kF7KRlb2Xedl1VE0RsOSkJhTcMP MxIXCIOsb1ORrT7AuqTFsC+MCX30xiT3T58gb5TAvvfykNOk1GR70GuoIdOZvjvt pUBArWam2IUaHh/Rmlq3Cs6XwBQ7XJXbzMrFpFnm0bXWClsLa7n582KaNOnSLsa2 WDh+kZ13OCjf4qwyzITqlsgtpion7wIDAQABo4IBhjCCAYIwEgYDVR0TAQH/BAgw BgEB/wIBATAfBgNVHSMEGDAWgBTt5292Wr9g7ElbxqV3u3IWcZvEPTB0BggrBgEF BQcBAQRoMGYwOAYIKwYBBQUHMAKGLGh0dHA6Ly90cnVzdC5xdW92YWRpc2dsb2Jh bC5jb20vcXZyY2EyZzMuY3J0MCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5xdW92 YWRpc2dsb2JhbC5jb20wSgYDVR0gBEMwQTA/BgRVHSAAMDcwNQYIKwYBBQUHAgEW KWh0dHBzOi8vd3d3LnF1b3ZhZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5MB0GA1Ud JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATA7BgNVHR8ENDAyMDCgLqAshipodHRw Oi8vY3JsLnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTJnMy5jcmwwHQYDVR0OBBYE FLzrXvvYDeiCroZGvTt8sm/RLH8KMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B AQsFAAOCAgEAKkbd+r1vZdmFSfcIGR44ukg18YFbuMdWfwqCFbMnQHjZpxgY7+Mm qbPpyX40BkS81JfqIieKwKintYx2Foen20zhoYNRTQljm/on8FslZJl6QxlYAdi8 EmAvtcQ/C/DJBkEcUPAXUemlPe5WulBIc2nr/W2Y2dMVuk3YqwSNNkmcdHHwzp/O aOK2NwW+ZNHIsS/1STpWRq2u8nGQDnlAenL63V9wYyGweO3aCaRhRHxy6bYJgxxh 2VDJMxigMDz0PpCCe59ITdqpaCe/pBv+FbOTG1ufBYQ0Hh4+9wmpf67Sd7ZolVJH cX1IgqVBG2uy9ogHbKUaR/hoAmlNwpy/ix8P/rt/7l6zMjKiepMInBjmaWKOqC8f zTapWZ3DcXc0wvRLbcNDzKSbg5L/Lgr4Gb0BX3WBvSMeUqmvKySryrWoibXAl8qt Wcuhenk4tXqSxwL9tgXWgx3gSa5bPrMYQmQTM9WioJnlFPmprI9r12V0n4RHXYb5 xmpvRPTm+5dSKtUzLYDU6hjONzCeuIVukh5/ZDwDyPv/zqiVH7lQFoBjJVi4UnLE wZPiR0TPN/Phr4vpAQ2jfoh9zABFeEIXeLwg6qps9bmJMGyOZrHAm7YMwUUk00Kt YoITfE0j48hd7+sydAHv3meZoX/GaKkdL/jCezlyMSmLPC7hZf2/rK4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGuzCCBKOgAwIBAgIUe9y7b81NAhnIfUh59PTXFba4NK4wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0yMDA3MjIxODI1NDZaFw0z MDA3MjAxODI1NDZaMF0xCzAJBgNVBAYTAkNIMSYwJAYDVQQKDB1RdW9WYWRpcyBU cnVzdGxpbmsgU2Nod2VpeiBBRzEmMCQGA1UEAwwdUXVvVmFkaXMgU3dpc3MgQWR2 YW5jZWQgQ0EgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCWCCLm qkNcSCawQpAXws7CAKPEDqs7Y52TBE2P0FkVYaNtnFyG+te4kWJ8l782VXyo3ZvK jwnUYbHLrrA3Y3KlUXvGwFDvGpVJbTnVHnfm37EOxpoKu89i5P4A50lIN1oNnGzF kbWSzLggZ8W34Kz7AO8b2A+j72OSigH90mE6ZCgHz5x+cUBmirtKtodkdwgNUMjO HdKQl6f7etm65MfxXtRFHZ+AHh3+55jQrGWKRZLi1S7rcxY1daRbSADNymRt2rC/ ftFpnOZuF8Q5nJFIMZjIzIw+M9Jo3fe73LTVoKzPx+5tk8UJXZ5ussaPMWmL5Vnw pA0NfzS+peQCNb6P0jpG2BS9YKZboFDb1+zU0jl0NdA6pmSR+14wiKUdfhaTQVmU OANm4psQkT0nvBM4JInxSa8g9uOkf6V1tNETi1Ptt3ogHn/PWUSuLg0GkWz3Sx8G 6C/S3xEU5i/vzHexhBakUNwi0YQ6dK/wCnPNUr/DwMAwO4yStadLp83/Been3Zrv CB+C47/oEIoRQPoNv+dQUmdo+FFYSgP9CaltMZxVumIMqe4WNHzEbmApuguc6oXh 2VvczcIH1vtW4iBGpEz/duLd6gKzfHUMYB4964WqkwE7uBc8T298yl8wgmK3pGAr xaeTM+hHGxBywBO3yfEHSifAFr93opQpJ23JWwIDAQABo4IBhjCCAYIwEgYDVR0T AQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSjl9bzXqIQ4atFnzwXZDzuAXCczDB0 BggrBgEFBQcBAQRoMGYwOAYIKwYBBQUHMAKGLGh0dHA6Ly90cnVzdC5xdW92YWRp c2dsb2JhbC5jb20vcXZyY2ExZzMuY3J0MCoGCCsGAQUFBzABhh5odHRwOi8vb2Nz cC5xdW92YWRpc2dsb2JhbC5jb20wSgYDVR0gBEMwQTA/BgRVHSAAMDcwNQYIKwYB BQUHAgEWKWh0dHBzOi8vd3d3LnF1b3ZhZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5 MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDA7BgNVHR8ENDAyMDCgLqAs hipodHRwOi8vY3JsLnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTFnMy5jcmwwHQYD VR0OBBYEFJUB41nXVXPkwjYNqDuSS9nmHhB+MA4GA1UdDwEB/wQEAwIBBjANBgkq hkiG9w0BAQsFAAOCAgEANws58UnY0ZPPISiTcEEWLDwavD9hJiBJ5slRMsK5i4/b WeFivV9lJzrqVhRV8+o0sgbuY+TAJeKoS6w5uzAeZIE+U3QPJo9WJ3Q1zZ8ednrn vsFdEANprlh7OMWWVWHRndrEqchaDQyTEGKASsDhyolIths0xZD8xj3GjvQp4CWE gxLhtibCEaSpE38c1JJG4UNQTlV7wahAsll7XZa/yQKLlzHKQw7T06wk6kgKT0GY Y60BBtDbAkvK7vPczbYbEBiHCONWEbG23IqLJtc50PROf0QXJc7oKhuWxfSoccWD aQnk2m8U5ujkgIu2R4a5Ow01VZ/n4i1mpZAwubZxnjdGCV7Wpz7GXCwcwTUmXKxb vy+IXih58X8B+PWaHiRdMBrUKi2s7KxL9cxX5Eq7AKuS5VtwCnCE/u2nH0aUcr9T W0eCb3/PmGbsQP2GQjAi31lOVCgCm8rqUlRPPOsz6OokU+BYs5Qbuf+u5sRlqjqT Q1c+brsIyVyxlOOqORd5jnlNlM38tCab5OUplFaZlyzA1Y5/AeRgq850YARn7El4 D0OMFbfA4qm6n/mlnLAolpiRC763/WWB/JZEj8oAHoeY2Ra0AJuvDUvw8cbmLrwq bRNhWOzHt5lHnWLFqrUIzneAViFjyVe9TiOEB+qm+lkQLy0nG3Ef71avF28+Im8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwjCCBKqgAwIBAgIUCr4SlJWYEinfIhk3QB6SFAram90wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0yMDA3MjIxODI3NTZaFw0z MDA3MjAxODI3NTZaMGQxCzAJBgNVBAYTAkRFMSwwKgYDVQQKDCNRdW9WYWRpcyBU cnVzdGxpbmsgRGV1dHNjaGxhbmQgR21iSDEnMCUGA1UEAwweUXVvVmFkaXMgRXVy b3BlIEFkdmFuY2VkIENBIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC AgEAy/Fh1th2UcVD0Eex/qf31/UI8dyabT+o/dbc21i6B27HHxU8MqXEFMqeh4rW tGZoa/Iny09/PkEmkAS6Ov2dJgM5uCaWSOqql9r3aOqW6q5BoH4I1Kg4E5bdrBHC OOKBG6MoYnWXAhxcMJovorWXkCyAlUMgh5WtDqqFLPdxK2PKBC/U78Q3JqBNfPE2 Ys7h+fH7pjHwC+mdhlc30ol6oIyy9mxHVpj+amXS1sSh1DIjmf49Z17tJsrHVRyl 0XDaq9n3ZIl0tYHG9eI+Jqdo96AB4x4l9NqQ5qhmjTLVF2iSsY31dlvywc/WUyUK eh4ereYu/egTAxbNCUTXFPBc+7FirvLIakQQIybn7P25+UPBIWW8Lz/+UGGLqpgu l/jAnHMF8tMS63Mi0LpDfkzZ6hLKC8CH3seHUhUfaoXXTaQexWE1O0H9j9ZJtNbW krkhPEzfFXyFzo9tXwDxFf5plxy+tv3H6WAjvfwjoCVDdINkS6LrpUUVZc3lcmCP g9P6kIwxiLVp4yESjb2eNsUlf83HPH6qTmkFm/evfnSwKcVMhdYTfF47rqmAWcH0 To2tZEpUCkJMgqHH7abQkeXYRSBToX6b2tEKFIomWIk7rSMEVOUfc4tC6BF7Fegc TsvTLoAPOZGTzD/SFJbvsSH/PrQqXCRxJRocZaJNRz1a5TUCAwEAAaOCAYYwggGC MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUo5fW816iEOGrRZ88F2Q8 7gFwnMwwdAYIKwYBBQUHAQEEaDBmMDgGCCsGAQUFBzAChixodHRwOi8vdHJ1c3Qu cXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMWczLmNydDAqBggrBgEFBQcwAYYeaHR0 cDovL29jc3AucXVvdmFkaXNnbG9iYWwuY29tMEoGA1UdIARDMEEwPwYEVR0gADA3 MDUGCCsGAQUFBwIBFilodHRwczovL3d3dy5xdW92YWRpc2dsb2JhbC5jb20vcmVw b3NpdG9yeTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwOwYDVR0fBDQw MjAwoC6gLIYqaHR0cDovL2NybC5xdW92YWRpc2dsb2JhbC5jb20vcXZyY2ExZzMu Y3JsMB0GA1UdDgQWBBTcCJCyHua7YOzqO0e1Rolx6nP8rDAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQELBQADggIBAAgyRX4RPNi9wEtSQr/B8/wegwn/hOhEjKkw kc0+0N6WGxWDzrtYYIfgWSEPCE0QfRomOjFkTf7mB6P+ode9kT4odS5Xq4HCGiqJ e7X8fudRoTwpKKlXWuyv8tJnvZp+KCe4kcsZQjPS6Kkb4boANvyISySsdg9Y2e1Z r8o+E1mpqWFvGqugeYurEUZwPCPqnpwDsFaV0UMoiIEMss9QLpsE8mukm1pDV4zP +NDXKQYyGHsBGuMtzTXduAjOYm1WycJthq/rJyyVg9TILC10nbwjkGL+xe8Ll27a wEBRMwtenjdNWmuaO4scqUgbWz2UfOV2Ymi8MggtMs0mAruoDNVCotgEhE8WqjKk jqnnoZ0Nq6t7I/NkjsSXd7GCBAXUziu3Xp5oMQSBz0cTRPkpuI/V3y96yMQ2anOJ ger2a1JQziZxm7EYfruR2tqzGoX0YwussvsrRLwFX03WF+9dGJe5h6/jxGlga0pQ Dip3PCl4ABmidy8OdnoGMynv2/cdQgglNevDpuKBeci2zpFH4Qefe826yypd7b7S N7T1Sq0cozct3RvH2D9ugzU1mr0/6fOBYcV4Bzu3zrGDNKn6WSGA64gsE/YPNqsL CrkE16xW3mCmD/zwPjLw/RK7IuA6Dq6WyWjcsX2VL7eoICtjYoTmfE2AAP5qGFUE Vjm88frm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGoTCCBImgAwIBAgIUA1/hN80FUeTB8bAL66Wu5T+VJzQwDQYJKoZIhvcNAQEL BQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZ BgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0yMDA3MjIxODMxMTdaFw0zMDA3 MjAxODMxMTdaMEoxCzAJBgNVBAYTAkRFMRwwGgYDVQQKDBNGaWR1Y2lhICYgR0FE IElUIEFHMR0wGwYDVQQDDBRWUiBJREVOVCBTU0wgQ0EgMjAyMDCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAKkXPXrwVCL6BNlH/zrPL+ZH8nVv9tG10em9 jN9rK/cY3zHfJlSjjnXKApuvs5YMQfElulRZNtRWpghLpOV2TbxnRMctccs6R3dm dkiGaQaoA3Y+j1mm2p4PJ47edWGMDUnBP7bx4sAxQVCPdyMaDUznl9DksP7DhfMh 5hw1s1p0CcFNDFdXGJKtnlS/LdGrNg+U5sTvN4PgyHZ79DhwdiRhSjZzZ5BAJXu0 /m9V7gtTUU2CWIjxBXQO0Y+AjPloAYWazgQKxdeAboipZOjXbz+Kp4GqrAokVTcA 6JphTCSRhDdJn40Dr/2SyLRo1UJfxp7w8+/SFrRXCCthxUbKE27WyheW9VVAlzvK 57wSz4VIO6nrDCrSS0n1yVQzKZRapr1248VQ1s19hjXseW46UxZKQkO7mlJDO7Mp XK0SatL/HW/CytilCSDR8qZHyyi4Tl3jlykCUc9RAPh8R/Bn40oiJGNTgMMku615 IniliSUNQEka4MG8WRrjcLCgGNh3W+KgvsunIpj6IUerfeDc4LuSP0pNzf25azeA aDrd/V5KaoztNR4HJuIBhnuuV+jXpO6Fn5IeWohLaRkczw+IOU6us/jZNoJknpM6 vTMGIxdPgcuYF07ihFuNNwgVtALtTfcM4jZYhQEZQibnaHoQ70XaXOUTe2AlvzmS eiHKPa7hAgMBAAGjggGCMIIBfjASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQY MBaAFBqEYrxITDMlBNTu0PYDxBlG0ZRrMHIGCCsGAQUFBwEBBGYwZDA2BggrBgEF BQcwAoYqaHR0cDovL3RydXN0LnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTIuY3J0 MCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5xdW92YWRpc2dsb2JhbC5jb20wSgYD VR0gBEMwQTA/BgRVHSAAMDcwNQYIKwYBBQUHAgEWKWh0dHBzOi8vd3d3LnF1b3Zh ZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr BgEFBQcDATA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnF1b3ZhZGlzZ2xv YmFsLmNvbS9xdnJjYTIuY3JsMB0GA1UdDgQWBBTHd2LrwybB/QHCfpRwUEdM2Ygp xjAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAH0wwAhyVpiki+9B YnxhjlCvSFOtYAb0fdthBbiLJVLqzF0R245P5HP6xlx+LfhWbCy+nn1JJyZqMEbo GZF8cLpG/ro+eFI8bAzXIIH4IADpehwJAzZmftQih84ZbEBZngmgeiFByR4mrvD+ upvJHesYyAKv8ZIYI59AZfg9NPWjLHi842OQz3Amsnlt8ini/dvVAJxUyovo1SZj SMMny9APUuPOxfW3BGMUVFqO5vS047XJhOTn2RVVM5mueSqIxmXIhsGFinLDNGX1 ZDpHbnT7a/JLvvJ/mLyLZZbAReKTYGxwMq/kvhGxvyeFXL/7v2x4x5TlG0wxdO/6 n2+1N5YtEUGIoDSs/334aYtNeVtfsXbk0P7CtW3cOqVyqtdxGdXXkSY+9vQtIxHM ISbm6LBI0PrcBwsaeiTCyO9hw0uHp2Y1PzqCEqbEg8nA+0u8nD7qq4edCojhYkOm ceJbdhwr90l197VkUEufl3NRiYGZDKIWx8kpc/jRo5l4QdGEIqb/Hz9NJUookXe/ qQeoXru2XVV95adf96/X04rRkIYcLGm0l06RTxEHkpmz0Tuwg2V0r0+nwbIkw1xT Um69LUNV/NJ5PbPJVQsWGze9FV5/rw09za9piYMJ4ebHFxUcvWhulNLYK/6/GwoI qwLcTRdgn1OSjsY8p+5FQ/2B3It1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGsTCCBJmgAwIBAgIUcaqqYoSEEUxZH9dLn+n/3lsp+n4wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0yMDA3MjIxODMzMTFaFw0z MDA3MjAxODMzMTFaMFMxCzAJBgNVBAYTAk5MMSAwHgYDVQQKDBdRdW9WYWRpcyBU cnVzdGxpbmsgQi5WLjEiMCAGA1UEAwwZUXVvVmFkaXMgRXVyb3BlIFNTTCBDQSBH MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJsBv9jg+xGq241BLjp9 5MtUcVBamKCWYvyYc0qHqhz2VX/ey/El++cglIUUmLHETvxR/gwh3R9noj1bBcCC xElQ4+j/0/f3OqRk7dJWQm5Bd86wgWeonbn8lGo5WTQUdutikZpJe1VlNXJYYmQ1 UcwIRTYIzbZiEQI0EqdA4erbr0OJSePZXiR6taFruZ0RHOxJjWVer/TWP9IwyP8S KEloQEAAKZqy9ZEem6LcE99FBzOvRTTF4GCyV+AO4rVYr3hGp2CFxC8r6bpO56hu PMic9rYlUrKMLdmelxDa0GNqxC0n7qYWKp6khaa0/MRMiCo2z5gZ6kOR7ARmOgDs PL623JzCNhAohziRpB1+Fb113TCAPylNKc8mF3OKI6PTm1SRyjqjUecmysDpoR4o WmeETcl+TvIpUxxFWnWBc7F3mEFGIjvj7WrT4jjuYvb21UNnomipKbk9BzspLjyW serJAQpFkmbPfqKpkQqDHOMj9wWec8H1YcFgUFLTa+IjKAs6urga/NsyViOJd0t6 3g2WRENeZBkVguUqJeju1/HhKneBlbDFYQLkpl+VtNOUVd1OvQDWaYV0kWw3g837 qn8DLrxaLXrqjK0Wz3K6x7tf1xZ7Nfb3OdB1UFmGDpB4D2wIadAnWpBD50VfAr1k 0VDRbvjjSlqWpLKl5paFPuobAgMBAAGjggGGMIIBgjASBgNVHRMBAf8ECDAGAQH/ AgEAMB8GA1UdIwQYMBaAFO3nb3Zav2DsSVvGpXe7chZxm8Q9MHQGCCsGAQUFBwEB BGgwZjA4BggrBgEFBQcwAoYsaHR0cDovL3RydXN0LnF1b3ZhZGlzZ2xvYmFsLmNv bS9xdnJjYTJnMy5jcnQwKgYIKwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3ZhZGlz Z2xvYmFsLmNvbTBKBgNVHSAEQzBBMD8GBFUdIAAwNzA1BggrBgEFBQcCARYpaHR0 cHM6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL3JlcG9zaXRvcnkwHQYDVR0lBBYw FAYIKwYBBQUHAwIGCCsGAQUFBwMBMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9j cmwucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMmczLmNybDAdBgNVHQ4EFgQUL61k qs8pDTDay0Q+P9ZPuhqf8XgwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUA A4ICAQAsJWaVoCRLhoMhkjI3ah4Nm6vXxT/8MrnB1Y6r9+bydBjhHHm9UyGVP4am iJ58pWc1gMn8fPrTwHfuFPr+dB55QbMEJRDyfuNkHlkP2WGj+lHTHzrK2QBmdgE0 vcav9kWX2eHSYGDoqEbhqscwkZGEAhQjupgjEbj586z6KeoyIIbI5XZYGtdAsbIE y+Z3jKs1f71ViyVrIzmQeXuoXazPzQxaBWDM+netGUtPN988VhgsiWU5QWbu7n2B epJ2k/+NK8N9gs6R15E/blUTGTExP0+z4XVT54oxe5WhKvqMjr5Cx/77oNtQf583 rCMxp7enclMpn8xpbNFb5xC+PF/W9oPvGdpTJjPeLmOZijT3NzBQkE0O2Yq4KEuw +O2+5malqZgVPxBndhAJX39X4Stm+Hm/WyuHPl1da+sVmSqOHCLkK09mYkO0fBsp X3QxHCFCZISdJiDimt/8tShz+z/Hu8Sc3k0iaoGJkUkNeyxkmk5AYff23pPFbI3F 62eKKGsVKytW9hb+TbhaCiZTBf75K47XkBxp8ucJbT9pIQq7EJuYRKlUCRPG8P5X XSrgWF5v+Za310A+w4D6zZosZtsTVys1VRtdYJzFFUPiffilQYwhuDcmQ6YeofLR tSsvR4GuztTNRiLsUGWilt8pL+qLcYcuHELoLU2ZhfajFC1UlQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGpDCCBIygAwIBAgIUdUFRzBHsibZGSbIwrYCQILseZqUwDQYJKoZIhvcNAQEL BQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZ BgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0yMDA3MjIxODM1MjVaFw0zMDA3 MjAxODM1MjVaME0xCzAJBgNVBAYTAkRFMRwwGgYDVQQKDBNGaWR1Y2lhICYgR0FE IElUIEFHMSAwHgYDVQQDDBdWUiBJREVOVCBFViBTU0wgQ0EgMjAyMDCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBALLkG5A2CoVB1AFi2GtDhr3CIJRfr2P8 4Un6RetLJf0emmppFPBk7v2PZrjpjJiXQWBj7ZglJ7uv7ZGxMoimWwraPjSydy9j pvtMDLNsAdnAvgQgdS2W1gCkBfycKxYaCRwDESRFm1u0WyRNka16V1P98p1x2fD8 xtrY224/HZ9c9K0xxMJKSZyclTSvhXHA71UgtFq5tiyUfS2yN7sylNP1r3ltohVF 67jzAmtjopwcDmjDA4z3dayH4F6BgcBQ4/LJz6GqyOJQV46FcuLIVQPBFrt/6Cnq vm5oJ1aarPefgPu68DJ9wmYTE1RLyUfCtXgl8hXgte2dJW2e1wo7gluDSh7VqwNT hw0zZil0uXSHFbY5Ca6KEcSkOWQ36jmmy4lgtyU1wQME3/gBky41n03Yiu+RhQiP xReTzLh6KavZs4Z2LgM2anXyLbq01QeG/UfyBS8pMkdbqLa9O4TjyrE9n1s8OOQv 0HZrUgRMnpFWqLTm59hpFx4Z2rJzv4uR17NlME2KCVjuxoypC/5a0lTtZWP+PtR6 1hig1O8/fASEbQS2Gr8P0CRQDYm8TLTQLwfucos3tL5a67b6OHXG8Ky1cs88/ydQ lshmZlSOUmtAoJdp+aqHmqvvYo7w32dGACuWmMAgMRxPQibeMVQ7z6IA1bxALZse V50P18HuTHWLAgMBAAGjggGCMIIBfjASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1Ud IwQYMBaAFBqEYrxITDMlBNTu0PYDxBlG0ZRrMHIGCCsGAQUFBwEBBGYwZDA2Bggr BgEFBQcwAoYqaHR0cDovL3RydXN0LnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTIu Y3J0MCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5xdW92YWRpc2dsb2JhbC5jb20w SgYDVR0gBEMwQTA/BgRVHSAAMDcwNQYIKwYBBQUHAgEWKWh0dHBzOi8vd3d3LnF1 b3ZhZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUFBwMC BggrBgEFBQcDATA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnF1b3ZhZGlz Z2xvYmFsLmNvbS9xdnJjYTIuY3JsMB0GA1UdDgQWBBQra7Aj2PQyEqo0TD0B7PDN ml3qwjAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAFjju/rMzVtF 9DRc7ndTjL1Lw/mWE2wIHOrqPOUtVjA05WdeFRKUYqQtZtUqVkNni9otzdhnyenj xyxOD4Og4tJC8RA2H4HhgGediF73HmmnF8eJDkO85kIGrrY8lnHYvH25EeMIjWrx aM0aGzoVpIBJzCva+vo7giQaLfJ3nNkornW3nqhgztAaFnE9rYLCdONihryPzP81 HNA9tgwtK1hcnk+x3sT1AH/wA7P4kJK/nUskCqj+jWLRI7SAKJbTdw/4FZaZCmZC Zd3pQaTOBpFNj8ddu/5OSCxnwrFuGLNr4LR7XBhYOr1T3e5e14eY+4qw/Hv8YrnJ BcUjYtRE5/PEE43FeH9qyTzTY/SDIS9KNPvaS+otkMxcyj5SAbKVV9inAQUzCKdP jJI6Et3sflw2ROPEfKlRO7CN5bALwCPJBA6PH5FaRHppe/MDhk9xPKP5CTs/kCHM aHBWS9xY60cnuCuN5PWlx6ub9RmADsSNKOBm7YkK2R0fvGk03eM5Rm1wNSyGI3T/ 7B35aZaATtLdJc3J7an/4N7QA1vUjzpBTZ5QBu6fGCJDO4WQ6FxrqsMT4Perz8vZ JrUmZatoZ9DcdHuVvtQHB4MYMI0Lf53pDGetOERRcXH//cmzUIyXj1DLLky9Fqnq yX5l9RmoSoTWunQAe2JgTN0l63C5ZVXe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwjCCBKqgAwIBAgIUZATFT9lJXNOKXnLfCnBb3dm1oqMwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0yMDA3MjMxOTU0MzFaFw0z NTA3MjAxOTU0MzFaMFsxCzAJBgNVBAYTAk5MMSAwHgYDVQQKDBdRdW9WYWRpcyBU cnVzdGxpbmsgQi5WLjEqMCgGA1UEAwwhUXVvVmFkaXMgRW50ZXJwcmlzZSBUcnVz dCBDQSAxIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuWFBTtvT 4eNAyfAC8Kp9ga6yv0iZ4zHm0ecAgdViUn8WW/Kg2JHh56iGV89utJVudmov0sRm 5CXMAWR2S1reSLry4z73pPJb/md5fjniG46uJWgKfBJqh9SH+UbZq7CMr+FqYHD7 /NjRd87D6qfELb3tNB2lPD6PnmmMd4P76A2CLdwCFrjjW/RWsuKz7L1raESQRm5A HHmBSRt6yo73wUXwgkTs8+QEpLwsV9ym6uH+bUUny9m4lBZA2pJitURlUJJ20MJ6 73Zgajmchg/Sasm438ZVDrUIHQF5iEBtJ4vRYNPuj0ugUf4wSt8qE/VixQnpsP9E 36XZ+S7XjmOpmXeLBlpeVf668OnljockPegRfoyevPJuSWNbz8kMXmqvxG3Mhzjh 9VaKe3MOgtJOrEJi262tFmpZTAsGodwvrwxjPrG4f3yrcUY1F2qFwmZgzK7cY/8o dssC972abUK9oMI9RYr3DSkb1fL3dmGZ0X8BY9Y8riHV3eM6zMOGNrc/BnhuIiTO nv9sZju0qx6k0bhGSVG0T3WNznogbl1LYKfC3hgpu2M2SE56Jv4KT8Ru+LdUHxUQ PPUVNEwXQP1HtVRAEL2at2tx8vX+QMpzoM3boKo9KwlVnA941CgK9ZEm7EHAMcpA bCD9sqP90hCK5ye6X3dGSJ100G98dLVMmIMCAwEAAaOCAY8wggGLMA8GA1UdEwEB /wQFMAMBAf8wHwYDVR0jBBgwFoAUo5fW816iEOGrRZ88F2Q87gFwnMwwdAYIKwYB BQUHAQEEaDBmMDgGCCsGAQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9i YWwuY29tL3F2cmNhMWczLmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVv dmFkaXNnbG9iYWwuY29tMEoGA1UdIARDMEEwPwYEVR0gADA3MDUGCCsGAQUFBwIB FilodHRwczovL3d3dy5xdW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeTApBgNV HSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwwOwYDVR0fBDQw MjAwoC6gLIYqaHR0cDovL2NybC5xdW92YWRpc2dsb2JhbC5jb20vcXZyY2ExZzMu Y3JsMB0GA1UdDgQWBBScUqwY05aHiQ+owa41tB7MfCqLcTAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQELBQADggIBAAAa+L/KdIj+lNW44LGg9MxkA5LRa5Ga+Pm+ nylSlqRa9qi3hKZj1GY+jo7kkzenJ0fbGwow0PTjUXjFTl4E0x41bMXJ17FgjA7o O5lJUM4j+kO5gKSl3Tzq8SHTnKUw9UEt7pmTvc1KRGIsYmGgTsldA3t8fsMWJ3F2 J8lYIZPoH6TGY10BLaJw+/5cGKGj+XrDXRjtaY/hDV3WdIGcMPnXY9nw/rn8nZ08 QNmNzVug727BLFl1rOgooW5nlaa8qRIVg+N5bdbmjx19nMId+RaJF0lAhT4N5BGP Jhh7baTTEu0jMH52S7WiuYQcS8KGx5AhHjFjmnJw/nKdZlVSQVPysxFMoAjPeA4Y i7mRTXMtF7vYX6FwKqdUkL6RCX11UQv82AAhBtFkG4gJ4ZMyAm5qQxHjDoDh0HNB 5QMHpDJZIEbLuqvGaTdBSBwFiOGONsa36jXJB+VEFL3ow0Gv2rjfUFNHpfaj/P3q mauQ0AF5Kqk5nuFi0+St81AS+S96RUZThpcQMa4Wp/Uv9AlDubQ0rCS0jcrt+xsH 4ObkPn++jERvfoUk3w4KTNKJ6biBd3+J6f1hHoA12ybh5HB8TotOb7dRxOYKiEzA mlwqRimqD0TJgjSUmNCThX8uKpJMjg0jtyzsbwZCy+xk+sfAuKk+shsZm9vSDF9C jwLsGTS5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGtjCCBJ6gAwIBAgIUQdJlG/V9ruxZQibPVWOcTDKFwkwwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0yMDA3MjMxOTU1NDJaFw0z NTA3MjAxOTU1NDJaMFsxCzAJBgNVBAYTAk5MMSAwHgYDVQQKDBdRdW9WYWRpcyBU cnVzdGxpbmsgQi5WLjEqMCgGA1UEAwwhUXVvVmFkaXMgRW50ZXJwcmlzZSBUcnVz dCBDQSAyIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxdAMllFt va5rm4RxE8R/cGzxaUnqMtNkIJp70+uAeSm+Rp4mJdyffaiDW6ZeboLl/gmytgOr WzzrvVnvyTROYV5R3SeKKJACRuzJpw65N0T+/HRZfJyHVniZYYC5T7lt3oBfYg5S kZEI/hQFv+1/VJ44Z2l9XuUF25FZgpasKwkQhUzw5GPlJq+1HEdc0aRkf7Y9hHh8 OhqRSUoPbwQxIRX4levpMmqNJXdR4qfPnbSUIGHipl/sLUZBqsvVFRptubuf1b+9 vwXqAnx14oHTeFqXKun3IDoLpSVMIZ3pq1BI/ZtMC//KeUdPaP3gLWb/rM+4L9i0 MycKMXU6SqEVLRVDbat90qwGhsKch7U/J0QCXpT4pa5GQhbDyxk455ZEXLEuuypd O+0OGjCBTchkgdUhlFa/haPppe8dLM7HeWND8H8QjNMafW2IbCb8FzgpINoag1Iq 9E3O2aGY2MQGHUCsdZMYCX5nA/IB+mfMz+EWlbdPSOO2b49jw6bVqnmjkW1jPMDj x6iiuIahdt3v5gMmvmeMoHf+95m3Mish4BFB/qcPojiiHaqVrlQkyRiyOicUMVSo rtV144ZKHAerNKe4jQyXL1hQHr7r6u2HZzkwirjXBIdFXxkIBZK26ooNX7BtSAtk E7QJZINWraNgn0sINf+apt0aCBuVeLrbUCcCAwEAAaOCAYMwggF/MA8GA1UdEwEB /wQFMAMBAf8wHwYDVR0jBBgwFoAU7edvdlq/YOxJW8ald7tyFnGbxD0wdAYIKwYB BQUHAQEEaDBmMDgGCCsGAQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9i YWwuY29tL3F2cmNhMmczLmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVv dmFkaXNnbG9iYWwuY29tMEoGA1UdIARDMEEwPwYEVR0gADA3MDUGCCsGAQUFBwIB FilodHRwczovL3d3dy5xdW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeTAdBgNV HSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwOwYDVR0fBDQwMjAwoC6gLIYqaHR0 cDovL2NybC5xdW92YWRpc2dsb2JhbC5jb20vcXZyY2EyZzMuY3JsMB0GA1UdDgQW BBQ3cXmZ6YXu59LABexGqwDktRg6rDAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcN AQELBQADggIBACnqZJd3oVFuq9VPZlz4JY6aELlQre3HFSjPMduJ7NjJhixbHOjY S5LQGsOMJ1npU9tWmEjhi6a5rqHRbBsvteoZsRrAm5GQWdmoP1eZzM3SaN09NU+G W/ov2Dr5Q2tTBAMcj3hvYpdtmLrNbVS/8Um3AFIxUZgK9o1exT5XPG/bVXi2eUDV WVa/kFwpon3GYgWIoqK1LgPUwFsxmW4ub6aZow5frAFfRUxHMEOBtD661BpDKAlY MQV4M4yz3RoubrZpjp9g7V01ivgKSnt3L2irqm3BT35NjBgCoiUkn+3BVhTp3RJa YkIYh9iazjnT81KtlUnLkJJNI/39X+p/zlyUQZG/DIL/hlsFowJEvXeEylPpIHlh NKtZn87cXGT45vyi4lZ7p8YUI6TQAIgTNrBabASP17JCcMPhackzanveyNpDRCGF FfudX7jGoi1OoDn/ogFPK34mrDavbw+4v/OWVbrByOgUcF+Q6CaaF4J148rwMcYF dwM7mE2g0KCVRlcqWt9cA/e6gKDUegdUaBwTVgsPoelC/UGE4rAAt8OItFSFB3nJ TPHo3KtnX2Ycz33WGDhP63DyN7VH9vjm+gnhkLB/2WPpmorO6bJ6703me5kGWGe+ rvHbUztLGX+2hbGBQnx9Xb/eT9tirNBT5ep1vl4AuyTC2hV59CU3hmK5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG8zCCBNugAwIBAgIURpsucQw1FB8mFccmruku5LQrNCAwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0yMDA3MjMxOTU2NDVaFw0z NTA3MjAxOTU2NDVaMFsxCzAJBgNVBAYTAk5MMSAwHgYDVQQKDBdRdW9WYWRpcyBU cnVzdGxpbmsgQi5WLjEqMCgGA1UEAwwhUXVvVmFkaXMgRW50ZXJwcmlzZSBUcnVz dCBDQSAzIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvNHpZsqV IdBhi2xM5oFrCdUcuAPKzGVvFSuMnLhz5636DuULjTc/fxC05PzzOF5oz48yvYg/ 5KTeTh5EM7PdXt+a6+jWJaCO2T2YsLzEZt6A5QtVG73ZMrpv4dnqGdNKWBIyqSoy LWrRXwaGslc9/Re7YbeYFs8GlYKUwjVGitWKH1Yfn9njZRuxLtuGO1oYf320+wy9 xY+O5v9sEG6xidJH8hC/VRM1+j7BXiyRH8fk087iM3452a7qvaOW6pgVXAJ0F4RV NCSz+fBBAs5+dTxg9MvFAhNYgAzr0K9Imj7nRkWeJ9cWsZcFN3ib/WWH0hFltnqb sFKse1Bs/xCQNZBzWOPIrPSiu7nCjsptq08XV68FD7AP9WhPrmM5mk+UTBB2tPGU YfzCc+hmWS4BAGS5IITmersym3eIUlWvo2NimTDyZnNKyUMPTW037ruJwWCmacfw 7u0M1KsgUOEEHYf7We4ptsfDcM8cE3ks5+QNqy0sjANF9k3pyCnDV/6rP2DohO3B WRafmZV/r8VK6eUwIUN2kvgx6v8fnmJMcdX1ef3WHKyPvf+QLmT3caZQwVrGX4Cn qG1CjxQeSobW2x8ubOHqAqnNYkuTa7EtgBpKrOzzFY4X+GnYVcJx4O5nCfeea28V i5gPAZ20iV10nz43VPwTzBIgBm+lI8w2BcUCAwEAAaOCAcAwggG8MA8GA1UdEwEB /wQFMAMBAf8wHwYDVR0jBBgwFoAUxhfQvKjqAkPyGwaZXSuQILnXnOQwdAYIKwYB BQUHAQEEaDBmMDgGCCsGAQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9i YWwuY29tL3F2cmNhM2czLmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVv dmFkaXNnbG9iYWwuY29tMEoGA1UdIARDMEEwPwYEVR0gADA3MDUGCCsGAQUFBwIB FilodHRwczovL3d3dy5xdW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeTBaBgNV HSUEUzBRBggrBgEFBQcDAgYKKwYBBAGCN0MBAQYIKwYBBQUHAwQGCisGAQQBgjcK AwwGCysGAQQBgjcKAwQBBgorBgEEAYI3CgMEBgorBgEEAYI3FAICMDsGA1UdHwQ0 MDIwMKAuoCyGKmh0dHA6Ly9jcmwucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhM2cz LmNybDAdBgNVHQ4EFgQUrwCU1mtcTB86HLeJ+tBpyYb4w3QwDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBCwUAA4ICAQCyS1vRisq2F8kPBc/hUuAueoy0VvzJKmZ6 cEEZZLoPU6mScTaPmor9zZeYJvkmufaGgraRkL19igGIfam8Vd9G72lijA3clSil LyHghvceymtTGplC4Fq76KpSKMnm5p3p7f6SCQ85X1HIvHeA4Nbtqry2r0sNzxlw yfUGlz4X9sfqMf67s083vnY0bflfSYwVgYXXiX+9KU5nVLW1U4+Dd0XHDdTQtTo4 ZvBrAjG8C6WYEKSqxg0vQPXb96BS2ZDBnc+tcLXgaUzoMR6R3vtk8I2vTtdMBK7z QK914bG94lN3JAq6Vm9+JZ7oapuA0yWXKB4qjbmLxyH49BxqcVjwlgaZ18JiEu3B nunjyAXrjw17mSkzEjH0tR7YSmXFEFP7dpOp2rJU174O8sJnqoELlkHmexxjUGU6 QN2TdvVu6ajf1zDwoPP4G6M6y8B+inrMJRTGDpNH9qrZ/qAeFbmn80+bQzKvV+p0 3ZYdtyN86+M0eewUfBwu6fWskNOPUhBREcgqHtJVla1uKjiH+9KQMrYpmN10Sfui ybLiyr6DjNUGU6LoM0dO418mJusQrKS8Z1ywclm66T96SEQkm7EJVdKpPH5YBh+y PLy1ymHTwht5haRMJy+77NyIt82TyBmv6GlAmbSjmuyb2dRekMWPlbw64aOCV5+A mSeodOMDfw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGpDCCBIygAwIBAgIQE+40jkkvjda1xJzwc/cUqzANBgkqhkiG9w0BAQ0FADBX MTAwLgYDVQQDDCdFbnRydXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gQUFU TDExFjAUBgNVBAoMDUVudHJ1c3QsIEluYy4xCzAJBgNVBAYTAlVTMB4XDTIwMDcy NzE0MzkwN1oXDTM3MTIxOTIzNTkwMFowgYUxNDAyBgNVBAMTK0VudHJ1c3QgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkgLSBFUyBRU2VhbDExGDAWBgNVBGETD1ZBVEVT LUI4MTE4ODA0NzEmMCQGA1UEChMdRW50cnVzdCBEYXRhY2FyZCBFdXJvcGUsIFMu TC4xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA 2dFdff4pYlZXfbteFzTcnigA/dvDoFrfkMw5IWSAUUfRCGU6MVF9ZBN9T61qyp/q KInm8f2ePPOIaFFrkAdiXg71eJ/pxiABrMh9ioUZFdqtPTQlwfmYJUZRooiNbQVE Khqki+ETXuYYH8jtI81mRkxsRkeHf7PLcglEcwGsDxr4k5fdneMG9lIJdmbGt3lI zeb7ThwrM0rcvX/qZnuL26+6dRrfGPqmUcFpp3w0jMXgx4MlLMMblqqW47zAsl4d VbvIHYlrUeeZJ13kGm/dFRVqf7knmJYz+O+oBYbQqfCif8kFg3DeUhyXOdqVU9vT NtOE6OyysCrhs1LfAXaEDSUhxoKKtdAi3wgurDIBEMkKUX7an8u+x7nB4s7K24rc JwlsrA51i7Sk/O4kfOnIOJTjTSGbgrwahEco/Ndtn6M1y9AHSpaNZq5l3hkgBJoK 3Yu1DILUnMSNO+aqGnzJR1HWQEWfLT19eiEh70vo96y5KLOPhsBlpV6txLehL8Da QvF6HK+RD7ev+TZo3VXrwpXiS2HvHZR2LmIudY9uVxY4HHD0KXWIKJzpN4Oq9vBm XYpCdbHqWA8pU60sMc2+Snc9qO2uTsLBSnT61eqwXUK+hnHj3RqtsL14vlT28Tes eq2OUETDL0iUO7KgFgsBf1cpA0rwiuEljc4ysWE/j8sCAwEAAaOCATswggE3MA4G A1UdDwEB/wQEAwIBhjAqBgNVHSUEIzAhBggrBgEFBQcDBAYKKwYBBAGCNwoDDAYJ KoZIhvcvAQEFMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFFaAFSOVcX/n LZDQzQY6T2djfT11MB8GA1UdIwQYMBaAFGPxhN0DvqOfZPp2ekfEVn7AbaAgMDMG CCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5u ZXQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbnRydXN0Lm5ldC9hYXRs MWNhLmNybDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDov L3d3dy5lbnRydXN0Lm5ldC9ycGEwDQYJKoZIhvcNAQENBQADggIBAEa5J5j6+v8u s3u+jNXuF+URtl+RLUD4jFlj4fRnyUqGeIUjfQFLyJe/NUBOOm+LZQx5/pr/p+Bo 2O5HPUcIdQLLWoOd8AZIbO1XYnIGLNMHiJwEmKLkxiLvCAIgvVerymDlRXQTh0Ly u8q+R73Mlx+714RioW8UHzs2H9bXxqVDYqBfi86dXI/iC9MGEsfCvOh6+LaqiCci ECdxQbfzEOmU+SLSxNAoKrGRhkf5XHolZdiWYT4nhP74P/i6nQdRW7iPJE1ZFx00 dEhb070FJs4Nx+X+bbSWIARoNiZqPZUghBWYw3jf8l7866ULNHjd9N0VccjqWQhK 0/e4sHnbDcLYAIqJ/ox+vT1lsxXxaX1VN+v2NK8auqsuLZeE+sfRAg8Y0S7HPCcR bFqM14sGR8SL6ffmuITtbSW34jtP1goRE2hFHtTBgys29JvWislnqaNvt1h7zWZp /Rj/E9uxgdcQf0MTQhAv0A/IhViDInJATxH74qHEAgMagbmFqOLe2rtTeu03dLuH XLjgen22G4ySg8Yaz4NQmdymeO64eVPxX1hKjMUHHwf+IZNmhboGQk7W7D+qMUd1 nyOGL6j347c6kbPinRLfO6htRNaWtROtzDoWFX6WWvCIZfLEXiepal8yjaO3yN6r Ek96pgOZU7IitxSm0o2L4BryuD4fqORf -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGqDCCBJCgAwIBAgIQF5zFbcgtve1Vc8eZmZf2RjANBgkqhkiG9w0BAQ0FADBX MTAwLgYDVQQDDCdFbnRydXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gQUFU TDExFjAUBgNVBAoMDUVudHJ1c3QsIEluYy4xCzAJBgNVBAYTAlVTMB4XDTIwMDcy NzE0NDI1OFoXDTM3MTIxOTIzNTkwMFowgYkxNDAyBgNVBAMTK0VudHJ1c3QgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkgLSBERSBRU2VhbDExGDAWBgNVBGETD1ZBVERF LTExOTI2NDMxNjEqMCgGA1UEChMhRW50cnVzdCBEYXRhY2FyZCBEZXV0c2NobGFu ZCBHbWJIMQswCQYDVQQGEwJERTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBANJXTkdjPtUxcGugQsLRIZB4C+SOlSniqbPRIjwlkVb9kqhxcMy+wEGImp5X T21TAXlnSaCoQcYfSIbW5uaw3CaReGjS8EDNSKcWzRoYNEJh79h41MYs6CnnBi+H NlDasV/AI8rJTWgvjxPnE+/OxASrYJlbf7GV5ok3FuRw4sDIrbkMf2zgzRbDhl+J 4SXfFgPbBNJlnuhy5XEVuNIWHHra6XB0R0k+UcMpYqHNCqYqNeO2GtG/8z9mgX1w SU+3u0M2AsMgXp0tVVDrwJ5aRet1bcM4a6UemyMA01Wvu3s/bgksQzSJthXk1ZjZ PLXIB+iZm1nfrkNGaFHPCMv+dQ014KGb/uA86CBRcb6Gdpx5nUPgq6zbKS++WJli S8lrEm8K3C0Z5osV0y2mQKWmpuAs6hujNsh6ilisUV+9h+G0XRYtbeBcFPZo+r+k weRQnymFbgGjQzQvm3RJxN+UCD0eUvAgy3lB3Genb8i3XXxf1BniHViTdRzWjeqs yYW+Cv84AEH3dDXhwTcooV6oqIp1x0LWawuzLIB6L1oZns6D2ttdSWklk043iyRo c3tZs4q1JBZqETdxD42D9x/KBU4ixbF6Ju1ZX3Fu91d+F4v4DSYBJYt4Djhqjerh oAOGBlq8v/XN6NPtbTsKsxJP0UqJVRG0564aAs7W+H6cqOMFAgMBAAGjggE7MIIB NzAOBgNVHQ8BAf8EBAMCAYYwKgYDVR0lBCMwIQYIKwYBBQUHAwQGCisGAQQBgjcK AwwGCSqGSIb3LwEBBTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRthmWE jFJshi+K9/AuW5tFcmaMfDAfBgNVHSMEGDAWgBRj8YTdA76jn2T6dnpHxFZ+wG2g IDAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1 c3QubmV0MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW50cnVzdC5uZXQv YWF0bDFjYS5jcmwwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0 dHA6Ly93d3cuZW50cnVzdC5uZXQvcnBhMA0GCSqGSIb3DQEBDQUAA4ICAQA1cG3z qD6EU8prP04Yp7HhK+n6T/DlntApxLyoY1OFrV2BL64hGMKX+LlFyNCvrlTE/qhE qIBEjvyosL8saG79BOQy9coMbLfu/hTg+r8kLGZdSZ9gU+tT50uG1YWeRbPstuY2 +MGzGBJNY8spQKHzqpoKVa7YCRHy1B7cp8eakH9tXbCBEzNucN9p8WtR3kdkacj4 ob2vFCZ7fhcVNcFTl56b4YxA6yhh+DwyYJa6tWWv2x6dXg9PrEoYkId1GpZh4+pd kazyn5QWma7aKXJM+S5Kc04JvCtGS0m0/YirtmYeZb5z6A/Cu1XFGRURhiJKw5gE hXh9AimFvEzpyslsjpT6z+sodYiukiJvOL8JYvdOhXiXroO75paBXM2URf1kzzBm iNwprhVGSnbNdCisjQ9r4zJl6Fl+WtkZH8LBGFp9/92tV4q5eVhD5qLEr0otr0hP T3JMS1Z54C2zO47BfIr8AS9krLloGEPLKptIBzLaotGlMgnlK6D0E9XoObmVpH07 MDKZPZl6FPQVlcqpwYAttKuGddnrHxoQlgwQgR/KuQj1dX/7AHBtrhZwFez38/SZ SOdO3mz6zERyhKqNJ11IM/3b2nce+zhaVNbEo65d77XuG0HOxmC9XjSbMiQqyD4Y ZPWnye6QizoRPpaBKEuEG45VtejhWKiMJtbzrw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG4TCCBMmgAwIBAgIUYMHuaNuSHaJgja6hN4Wz0kjyrJ8wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0yMDA3MjcxOTAzNTFaFw0y ODA3MjUxOTAzNTFaMF4xCzAJBgNVBAYTAkNIMSYwJAYDVQQKDB1RdW9WYWRpcyBU cnVzdExpbmsgU2Nod2VpeiBBRzEnMCUGA1UEAwweUXVvVmFkaXMgU3dpc3MgUmVn dWxhdGVkIENBIEczMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwFkm YZHtvtSoHi54gbTbJ9npukWmLom2kjyOI/OK2oBpKKW7AQlT5O21DqWAD2l+8c2e dJ3sbDETrpr5oCRNI8OtY4+M1gNtQO2QIe/4VIr3nRx7iVZTKSIeaZ5kSNK3RGRS yImW7WAX3/rTgjBoRhnZi2psYuEmJ9bHtRw3K4Pb/2DXK4FfLxAa1JDQBL59MAcl Rb7BBnWHRkEVaG3bH6P2f+D3+SeUnOPQVdC5leu9JPiVivBabgy6HxmZJbFKrBU5 VP8ylP1Na79OXG8DhnZ77etb/32u22DWuqlqhrXBMXtvnox0n8E7zt251v+jRizJ BA9zx6KlfjoNJ71d34VXlEUe9qD4lN6hsPHIYgII6k1/g1lZkIVD3nvdEhqEX8k+ 4f3bmFlpNoO0uK4s4SRHlGcoII0+yJ1/+TwFJdxYriQRU/FLIubzgiWPxt6+ehk/ byjihV+dhJCEB0qSDhIJHA6m/aDmpJY0kl4UETXs52zvCNXow7SZtJKb2JWGb2hu 8scy/zZjHmLlON3FWmr/qI+SdNpvbe8Fh9+JlJIl6LvsXcKpr2MtQ1o5eG1chUQU gJ6AD7KTmf5+RFBS4Mp+haHjAW8IUbrXk9bPnKLHwbugrf5J0IooVL3YswNrk1vr wu6XvZfX9D0vr/qmzg7WiQ44YQnRxqgeCdAzSWUCAwEAAaOCAaswggGnMBIGA1Ud EwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUo5fW816iEOGrRZ88F2Q87gFwnMww dAYIKwYBBQUHAQEEaDBmMDgGCCsGAQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFk aXNnbG9iYWwuY29tL3F2cmNhMWczLmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29j c3AucXVvdmFkaXNnbG9iYWwuY29tMG8GA1UdIARoMGYwZAYEVR0gADBcMDUGCCsG AQUFBwIBFilodHRwczovL3d3dy5xdW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9y eTAjBggrBgEFBQcCAjAXDBVyZWd1bGF0ZWQgY2VydGlmaWNhdGUwHQYDVR0lBBYw FAYIKwYBBQUHAwIGCCsGAQUFBwMEMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9j cmwucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMWczLmNybDAdBgNVHQ4EFgQUcQEa i0YM4DVFTtZ+7NDtOY1G1mkwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUA A4ICAQA0jIzaNsKk823ENpLEFp4cnlFKGuT9KyyZGLN/+ziHHfNyAiu9jC7uXwZX Te+X4I9EiUEnLiZuLogeTqozeuBA7rzkZwLkdLvxjX5xg1gLVRKJ8ZRwHFaocgc3 ictvH2vVyILdq0hIVuuyNwrsCgPMfsZxaaneLQ8AnxacUTr+Ddn4DlEgVgZJj3cC aloTmGylmKtKtCt/a7JVnLghSEFYnO16/tdndWy8KHDxkxHw9ygOo2iI8Kb6MHic 0x0XHNcBAO3240AmqVoveo1sUpTCht6MO2RSdVS2+lWU7J6JV7ACvG3wTG4zS5iD EuYL+DiQRK8/TbpsThLGSjgB7A3I1ETMjjnQVvMFAscV5HMz24OE6eHcnOKiJf6j ggb1QnEBr6+z5hrsQn59Umg6aNdnwK9+3ulJE6/FkvFPrBOORTn7pIMWy7KHbEEa Sh1noapHhi2Gworp/pUX/dSfNbpZ8xKTNNCOCGUDAbnoXW+oKJLToaisob+4XLW9 BY4PizDO3k1lI/S4FD0qUXKM0/dLG9VYfLaFyzMRe4vIZ/+QBMwJ1/nuZ5t+WcL2 AEJEtWDaPcnI6MGt78BpoEiAOq7/0hmbJCejM86WrO7y6wJnHIDdiaS9BjImIQ5/ W4PfKAlQAb1Gq4xMYMxTo0wBMjZsCQHBFInCHNfykQ0u1XmxWw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEpDCCA4ygAwIBAgIQeAMYWGakf/vHAnBwTN6H/zANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MjgwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMEMxCzAJBgNVBAYTAkRFMRkwFwYDVQQKExBEZXV0c2NoZSBQ b3N0IEFHMRkwFwYDVQQDExBEUERITCBVc2VyIENBIEk1MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAsEkP5rc6MYY06GDnqt5R1OVrmw+XWslTJhBT6InH Xl9mJB5IkILkE19JeCeEpmfHcronCPWUPrKB0ij+DM6LnVt07IcKfDqvQdd6hlV9 bqGeA80laqacrtoNiJMo6XdtrQYEsPzAYMWwWZvBJAtfpST+wN9zVuUsNK7Kk+m1 zaYePK/a30p3tKRNK1F0mMckDem+EAnKDB4ll6R/pVJz6I0G2++yHpyfQ8OeOdMF 6cFWKAy0bW/BCFkJgJ8hDxd1RjAEj2NFKFvdzn5Au+MsHVpsC1P8vGYJ74FtIia8 6J2lZFmkRrrl1OQuQuv756aDCnENoTeW1O8RHyzkgYP9awIDAQABo4IBiTCCAYUw DgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAS BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTTtA8bB9x/fg7gAtrUVlIORpzJ JzAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpjmove4t0bvDB6BggrBgEFBQcBAQRu MGwwLQYIKwYBBQUHMAGGIWh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29tL3Jvb3Ry MzA7BggrBgEFBQcwAoYvaHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9jYWNl cnQvcm9vdC1yMy5jcnQwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i YWxzaWduLmNvbS9yb290LXIzLmNybDBMBgNVHSAERTBDMEEGCSsGAQQBoDIBKDA0 MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0 b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAlLVpOzNL7eG3Sm6u05CJxvNdPzcVBVOR mJ4BB+PKGsYvT6/jV+Z9mzZypoG8LfqTCFTILXWBvyuvBkTFnqw9yfX/BT1U5ub7 in/n0Yjvey5tagYpIIVy1/JRI0kgeLUKSHsb6MqgvmSGc0fzDCxv/ZswlNUnhQPN P4C+XfWIHkatx4kS8TgoLwX3KCZ/nTn1mjZHIzup31HQkEbO5166dEQl9QRxh+QS k+4dzLQf6v8mE75Onzo6LlFxPg92kBaUt3HbH3ICXbJmrTMqIYHoZwZKF3Vxbcqx wc862flXphovvp2NvYM3XNYHL3fofbJeWev0+JT+Bt2HKYn3VibObA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtjCCA56gAwIBAgIQeAMYYHb81ngUVR0WyMTzqzANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MjgwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFQxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMSowKAYDVQQDEyFHbG9iYWxTaWduIEF0bGFzIFIzIFNNSU1FIENBIDIw MjAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvLe9xPU9WdpiHLAvX 7kFnaFZPuJLey7LYaMO8P/xSngB9IN73mVc7YiLov12Fekdtn5kL8PjmDBEvTYmW suQS6VBo3vdlqqXZ0M9eMkjcKqijrmDRleudEoPDzTumwQ18VB/3I+vbN039HIaR Q5x+NHGiPHVfk6Rxc6KAbYceyeqqfuJEcq23vhTdium/Bf5hHqYUhuJwnBQ+dAUc FndUKMJrth6lHeoifkbw2bv81zxJI9cvIy516+oUekqiSFGfzAqByv41OrgLV4fL GCDH3yRh1tj7EtV3l2TngqtrDLUs5R+sWIItPa/4AJXB1Q3nGNl2tNjVpcSn0uJ7 aFPbAgMBAAGjggGKMIIBhjAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYB BQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHzM CmjXouseLHIb0c1dlW+N+/JjMB8GA1UdIwQYMBaAFI/wS3+oLkUkrk1Q+mOai97i 3Ru8MHsGCCsGAQUFBwEBBG8wbTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AyLmds b2JhbHNpZ24uY29tL3Jvb3RyMzA7BggrBgEFBQcwAoYvaHR0cDovL3NlY3VyZS5n bG9iYWxzaWduLmNvbS9jYWNlcnQvcm9vdC1yMy5jcnQwNgYDVR0fBC8wLTAroCmg J4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBMBgNVHSAE RTBDMEEGCSsGAQQBoDIBKDA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9i YWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEANyYcO+9J ZYyqQt41TMwvFWAw3vLoLOQIfIn48/yea/ekOcParTb0mbhsvVSZ6sGn+txYAZb3 3wIb1f4wK4xQ7+RUYBfITuTPL7olF9hDpojC2F6Eu8nuEf1XD9qNI8zFd4kfjg4r b+AME0L81WaCL/WhP2kDCnRU4jm6TryBCHhZqtxkIvXGPGHjwJJazJBnX5NayIce 4fGuUEJ7HkuCthVZ3Rws0UyHSAXesT/0tXATND4mNr1XEl6adiSQy619ybVERnRi 5aDe1PTwE+qNiotEEaeujz1a/+yYaaTY+k+qJcVxi7tbyQ0hi0UB3myMA/z2HmGE wO8hx7hDjKmKbA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFtzCCBJ+gAwIBAgIQeAMYPf5Y0M7aTbTlFPQHljANBgkqhkiG9w0BAQwFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MjgwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMSgwJgYDVQQDEx9HbG9iYWxTaWduIFNlY3VyZSBNYWlsIFJvb3QgUjQ1 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3HnMbQb5bbvgVgRsf+B1 zC0FSehL3FTsW3eVcr9/Yp2FqYokUF9T5dt0b6QpWxMqCa2axS/C93Y7oUVGqkPm JP4rsG8ycBlGWnkmL/w9fV9ky1fMYWGo2ZVu45Wgbn9HEhjW7wPJ+4r6mr2CFalV d0sRT1nga8Nx8wzYVNWBaD4TuRUuh4o8RCc2YiRu+CwFcjBhvUKRI8SdJafZVJoU ozGtgHkMp2NsmKOsV0czH2WW4dDSNdr5cfehpiW1QV3fPmDY0fafpfK4zBOqj/my buGDLZPdPoUa3eixXCYBy0mF/PzS1H+FYoZ0+cvsNSKiDDCPO6t561by+kLz7fkf RYlAKa3qknTqUv1WtCvaou11wm6rzlKQS/be8EmPmkjUiBltRebMjLndZGBgAkD4 uc+8WOs9hbnGCtOcB2aPxxg5I0bhPB6jL1Bhkgs9K2zxo0c4V5GrDY/GnU0E0iZS XOWl/SotFioBaeepfeE2t7Eqxdmxjb25i87Mi6E+C0jNUJU0xNgIWdhrJvS+9dQi FwBXya6bBDAznwv731aiyW5Udtqxl2InWQ8RiiIbZJY/qPG3JEqNPFN8bYN2PbIm SHP1RBYBLQkqjhaWUNBzBl27IkiCTApGWj+A/1zy8pqsLAjg1urwEjiBT6YQ7Uar zBacC89kppkChURnRq39TecCAwEAAaOCAY0wggGJMA4GA1UdDwEB/wQEAwIBhjAp BgNVHSUEIjAgBggrBgEFBQcDBAYJKwYBBAGCNxUFBgkrBgEEAYI3FQYwDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQUoJMVKG7ujwiyNcaeYnl0p7EOK3swHwYDVR0j BBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7wwegYIKwYBBQUHAQEEbjBsMC0GCCsG AQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYB BQUHMAKGL2h0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3Qt cjMuY3J0MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5j b20vcm9vdC1yMy5jcmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEW Jmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3 DQEBDAUAA4IBAQA6+XNA7Y97PasCLIcUOE37MgTcgAco6pb3l2DHIn1XdTE9IF5l ddmQpBjaQ70N6i+YtWIwWZ/xH+d7yjzCdrOeJuafAleT2rlucQUDXnZnJyBWd5Gd jMs4FbCFiWSgJDyxmKBXS4X2sJanx4lVu4XjdhWj7uFFR1J4DhU4EGL+vNMnkRD3 dzyN27mtfLGEZ+Xc1BaldK521Ootr01tUMDHpNU/PXOrT5V/Cfj8U592FEM88YWE c6nZg5FWuRaVBxJboOvpjuo+xskVwkUTWouEEkne+HLoTHol6B/magRuSXRMxFzC aUim5YQ9PCiJBhhUveY2RQcfecyi6zqK18CW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDbDCCAvOgAwIBAgIQeAMYPGVP0dRzzH4eRopRzzAKBggqhkjOPQQDAzBQMSQw IgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjUxEzARBgNVBAoTCkds b2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMjAwNzI4MDAwMDAwWhcN MzcwNzI4MDAwMDAwWjBSMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2ln biBudi1zYTEoMCYGA1UEAxMfR2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IEU0 NTB2MBAGByqGSM49AgEGBSuBBAAiA2IABPl5i4FHN4mWP0VJUH8aJguTMn4uwMCn CJrDbo+bPgsi7DdTt2+KsLwnN0ttqUY72R//paFEuy1zv55BB1xTm1EIOlq7bzjH FpF4wkoTaR2C31ovAIiWoi4cdPmdfmY3iqOCAY4wggGKMA4GA1UdDwEB/wQEAwIB hjApBgNVHSUEIjAgBggrBgEFBQcDBAYJKwYBBAGCNxUFBgkrBgEEAYI3FQYwDwYD VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU3xNei1/CQAL9VreUTLYe1aaxFJYwHwYD VR0jBBgwFoAUPeYpSJvqB8ohREom3m7e0oPQn1kwewYIKwYBBQUHAQEEbzBtMC4G CCsGAQUFBzABhiJodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHI1MDsG CCsGAQUFBzAChi9odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9y b290LXI1LmNydDA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNp Z24uY29tL3Jvb3QtcjUuY3JsMEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUF BwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAKBggq hkjOPQQDAwNnADBkAjAVvY6WHb5D2P4Q1rKMjYEcyS7NZs/GHIkXKH3mdSOQw1P8 2k25bFnu9eKZvxOz6isCMBKZPTaOgQ8DMAdtPBbwG9l+gX5tJZH/QTIXe5Kb0YCx idTYGZiZU1Qonq9vWTvspg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEsDCCA5igAwIBAgIQd70OB0LV2enQSdd00CpvmjANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MjgwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFMxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMSkwJwYDVQQDEyBHbG9iYWxTaWduIEdDQyBSMyBEViBUTFMgQ0EgMjAy MDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxnlJV/de+OpwyvCXAJ IcxPCqkFPh1lttW2oljS3oUqPKq8qX6m7K0OVKaKG3GXi4CJ4fHVUgZYE6HRdjqj hhnuHY6EBCBegcUFgPG0scB12Wi8BHm9zKjWxo3Y2bwhO8Fvr8R42pW0eINc6OTb QXC0VWFCMVzpcqgz6X49KMZowAMFV6XqtItcG0cMS//9dOJs4oBlpuqX9INxMTGp 6EASAF9cnlAGy/RXkVS9nOLCCa7pCYV+WgDKLTF+OK2Vxw3RUJ/p8009lQeUARv2 UCcNNPCifYX1xIspvarkdjzLwzOdLahDdQbJON58zN4V+lMj0msg+c0KnywPIRp3 BMkCAwEAAaOCAYUwggGBMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUDZjA c3+rvb3ZR0tJrQpKDKw+x3wwHwYDVR0jBBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLd G7wwewYIKwYBBQUHAQEEbzBtMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcDIuZ2xv YmFsc2lnbi5jb20vcm9vdHIzMDsGCCsGAQUFBzAChi9odHRwOi8vc2VjdXJlLmds b2JhbHNpZ24uY29tL2NhY2VydC9yb290LXIzLmNydDA2BgNVHR8ELzAtMCugKaAn hiVodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jvb3QtcjMuY3JsMEcGA1UdIARA MD4wPAYEVR0gADA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWdu LmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAy8j/c550ea86oCkf r2W+ptTCYe6iVzvo7H0V1vUEADJOWelTv07Obf+YkEatdN1Jg09ctgSNv2h+LMTk KRZdAXmsE3N5ve+z1Oa9kuiu7284LjeS09zHJQB4DJJJkvtIbjL/ylMK1fbMHhAW i0O194TWvH3XWZGXZ6ByxTUIv1+kAIql/Mt29PmKraTT5jrzcVzQ5A9jw16yysuR XRrLODlkS1hyBjsfyTNZrmL1h117IFgntBA5SQNVl9ckedq5r4RSAU85jV8XK5UL REjRZt2I6M9Po9QL7guFLu4sPFJpwR1sPJvubS2THeo7SxYoNDtdyBHs7euaGcMa D/fayQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEsjCCA5qgAwIBAgIQeAMYIM8CNvOmhRi677f3ATANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MjgwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFUxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMSswKQYDVQQDEyJHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSAy MDIwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiadP0GINVgdrVQ2m H8m0i+g3Wi/SjCBCpz9LZ989eWRrag4zjUc5s2WJ9PWv1XObF0bhLtNnrz0bCoaw tQun6dNl5mHYB1fbFIiSIU++I9V9bGHs49abmgAPWLSF4UfpKoJhJ/bdj9DX3/LP CZ+70/sRXXG/qsLYI05WGWEtqnVn4wXEL+hWoCn8yQjsbwUwACq0MjIgRypabmT3 OROLGE6/2fHuQ5P0IHjLUpovkFzIiTdoX33LGFGts3Hc7+DaIW8MsU1bt2UJrknl LhGZl39APhnalmf5AqFwscOlCkq05pmvYRycvi5Voov+BSc5qYE2LcS4qk39EC56 Qn/vBQIDAQABo4IBhTCCAYEwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRC bVctTx8md3SmJ2T2gPqPSGj+fDAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpjmove 4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwMi5n bG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1cmUu Z2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0wK6Ap oCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwRwYDVR0g BEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNp Z24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQAi5uFmB7bAY7Ey yc8XLXoMO6x3qoj1IXhR+XMQF4XI4nMtMCOnu68TTuG10JnKjTVgG1nEx6THkhWp 9gABl4W9qxQjSpWBfnqffokXOjN513rN3/wJ2ZQ+G0xZmqfQuuICpYaXebK7wqZv Cj5cT1LK+FwY0rWUbvoCkZsWgcte4sXdoGVjKBpJpB5tZelIABdSiPjD43/x0utk zw4BBcD8J2uQKdkK+NTX47klgcddkRduQnfLApsKlS/PlgRTn1fgcgsWfkw2Fhuq JwGNLMwQmK3FBOE4o9ZhkkA6wTNFJVuRYnTIRqV7j1nWGmDwAVmWqheoEPn39qqM K6oYIXfj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwDCCBKigAwIBAgIQeAMYKvvs2J6xkwm7SiW9qjANBgkqhkiG9w0BAQwFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MjgwMDAwMDBaFw0z MDA3MjgwMDAwMDBaMFUxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMSswKQYDVQQDEyJHbG9iYWxTaWduIEF0bGFzIFI2IEVWIFRMUyBDQSAy MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtQ8IiN2Ukq/Clynv HhqugFQg5SXIyVO4ZRnxo0hNnaek78LRn4Bkaqcwv6Ls0Ftn4bK2zvBaS1zsfUTA vfup/s86zHCRvOqAL8zO/WiMV1G5ikHSlD6RtpIOHRX4y0oIGW59ADY0ANwDeDWL x/RgSltuQIqeGXwZnyZFwWtxVkSE4p5tn2Lb6USzwcD22taiXmeYsPMWfJfmWPRj ZuYBgxn6tvUVRO+ZzAUKEEaJK/LVLieAVEmfR6anEJ/gWczxz12Lwu6qF5ov0OQt AP0rfruyje/EJt6xHjpJ2OgDzCWYstXOpRPDHYS3klpaRbowAlpJdYMRAqY5CNiP RAx3wvsWCVI5UkzKVD6RuHHVpfzfdKAfsjHa/aSunHtTpE+NUf3Q/3qHXW5cyDnP Jt6VTVVVevjTquwH1xrUigukDbeopV1owsqIA5aw2io7RbBorwPBA0veinHN4vP9 X8jbTiIiLjlfJOnHZe7pIhb3T9WCqhwwsBNPQpKizGHCj5kL2UJe7N5u4RywFOZE l5mbTX4zO6Vj3WM9ZVbZgXVNwEjS5mYq/rvC1yr9obNUJ8br6JAd2ZBnzhA5Zn4s bIP99TlUBZWczw+vPM7g1S4e4cyd+8CULVhVs87QlyvwWnRbH7fXZo8xLzhzMCjB 8Y0cNdL1S6QKrrhC6Pf6tV/JU20CAwEAAaOCAZMwggGPMA4GA1UdDwEB/wQEAwIB hjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHQ4EFgQUhNwhC8eoXXKXhId+8tW2+nFWTvswHwYDVR0jBBgwFoAU rmwFo5MT4qLn4tcc1sfwf8hnU6AwewYIKwYBBQUHAQEEbzBtMC4GCCsGAQUFBzAB hiJodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHI2MDsGCCsGAQUFBzAC hi9odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9yb290LXI2LmNy dDA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jv b3QtcjYuY3JsMFUGA1UdIAROMEwwQQYJKwYBBAGgMgEBMDQwMgYIKwYBBQUHAgEW Jmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMAcGBWeBDAEB MA0GCSqGSIb3DQEBDAUAA4ICAQBD+97H2N1BgiliKQFrb+jcWjkmPP8cdF/eiBW1 cEzOOhsuVqxbyIk8qdw3UueHSDjqWUjHYoo8TV3DLqUXmIy1Ks3MkESsFKeLpEbk VMZga0lbDnqqRc5a2yzrXmwVYDeWVeD20s5vPoKCnFzmcR+2v9TKD4bI6XWVl84q GzfFRVdY9f8KN+7891+47ZhptvxtNqJKVI2O+EAP/PvTpwes983LkFzsev4/+Qxs EszD7/pE+Byj3t9CMat2XoX0jfJjbEXgewFb/gCwHvqNKLNWrYfE9qN8b6qm4xQk qGQKTrFKsBJx4TU+h10qXDhpmOBswiJqoG16XCV32oSn0JUYvXVAvP6YjueOv/jr 0ZMTWGh8wCz6v3XBaXR0rxDAz9GImpU+xPx2XjuHac7OnYbN+i8p7cJPUxABjHiA LWXIZtCn5ziCfvYC6+SCp8x9TPJzAIfJ4NKv/8SpvvzuchVkAQqlQaGFBEdkX84R I/WYYG+2BliFIpbQnfljYWCURbfsYz7+Zxb94+4yzva49p8T6lALoK3s2kqIVLKN s6qAnk/qX6JihkaR3W+iViHMC5tqQX/pd8QIXccF3PA2OdeNGU4iUNZqUbYB4VZd AaOaeaUl0LwAta6DB5w344eUIqDgaitSwQZBnxppmwL3tGzP1ero2e2RvBmphbxI atIdxA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFsDCCBJigAwIBAgIQeAMYJwLPmxq6uGBGoPaorjANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MjgwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFQxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMSowKAYDVQQDEyFHbG9iYWxTaWduIEdDQyBSMyBFViBRV0FDIENBIDIw MjAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDH0k91xenVHxRcK0fD ZRY76vkldwhOkbWrHfzF+3XZBfFi+uJg3KhJnxT1vuVn3Qm50ZsN66DwO9utuFVz YAwOp+al1i4hQRxlzf89V2PN94XfF2bOoIhvb6L3F6NjWQ38M1ZYNmWY/OpzNTPw 64qzDImVGyjYgny9xegBWp/6pecFnpFm+vIy2PzWJSK8ws93nLTOgi5FCtxvk9uv Ac1qPDAil8CWI1zjM/dxa8lAGOflhJSJOIbJ7w3S17CuOSykGgTeH3IZy1ayMH0T R/GphmRWIi9I3UfBJ6BhtnDEST6j22a9T7USTP3RRYAMg5ELTHkzuqj7bG0C0vSo oEjdH+8f8ZxAizNV2rsGO9wbweMLG07yQWkUV1RBUlsVqS6wZKpXWmAak+kKgeNj MqzNpzJPv9NaQcSnpRpLvdumQ3vv/oB50H245jpYaXJAkFbCyTEtjIdFyvyqwrG1 4YaKMdGQosEx4LioZAkMf2uBjtpf1Hws9HSPTQE94l3vC+BM0QJLJ/htneuSOYuw U2N/4XbRcvJVqAy9csRW+d/QE5Q/0j+KFfGNVbv6oSXQKZRQdm8AM+kpCRob137o P480/sWS9e36GIemHCtjnvJy8eYskXe0yx2GJDr/yveXA3TA4LglLHqUlS/9pgei aSGWlyl5ejIMPn2mMzlIsuc9cwIDAQABo4IBhDCCAYAwDgYDVR0PAQH/BAQDAgGG MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/ AgEAMB0GA1UdDgQWBBTcvd5Zrf2bVRfncEwGV58hIrB3ADAfBgNVHSMEGDAWgBSP 8Et/qC5FJK5NUPpjmove4t0bvDB6BggrBgEFBQcBAQRuMGwwLQYIKwYBBQUHMAGG IWh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29tL3Jvb3RyMzA7BggrBgEFBQcwAoYv aHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQvcm9vdC1yMy5jcnQw NgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290 LXIzLmNybDBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6 Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQAD ggEBADyP8nlvL/TafTGLBcYloz3NDFCCsDOTGOcmO24u5eeLvbVe9S0JvNpUV2df xN/J9wqDHIXq0EvuF50sS/2RUOmixlvA24u3C2+DjSVCTVLzntRrXm+kkXO2kxed GpEiohvItrwWMQU6IME5emWBpEOkcdREyj+aHzbi1SM4afSNc6V8SZLE8KHaKdVt pKmAGr6zaJkLBx0BVQMH2KQu7fP2CsMMigcPt6s9CL0u2yoOJGesrbPe5QKt1g3s CJ24KUpV54+EFZ3ShSzODN9T7bg5JuLWOFqQaW6Cxdf5UHTsFicR51WHQY6x7rvW F1V3nxtv8BDjEhQwt5ot7ouvP7g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEujCCA6KgAwIBAgIQeAMYO0c63yZRQcr/8WGjcTANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA3MjgwMDAwMDBaFw0y OTAzMTgwMDAwMDBaME4xCzAJBgNVBAYTAlVTMRkwFwYDVQQKExBBVFQgU2Vydmlj ZXMgSW5jMSQwIgYDVQQDExtBVFQgQXRsYXMgUjMgT1YgVExTIENBIDIwMjAwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaJuOf1WrE0WFYWfQYfB7wTtgy clDtkWBLB4gKVjkqlfjAHrEr50uGemRxHWWeDVfnnVCpBx6iSnYqu5uFI2clk3z9 nKr90y60dUpl6EkROTwcEdVvICDMTIG7i1IWfJEV0bH7oJbD97TtNthmW20V0aWt 0mpTl6X8zRXy33FezKkDJfJgex+4oygAc/igkfR/1RC+rlLZTZ0CCmDE9ReHbgsS pVOCmGzWJQnFs7zIhMS01b2NQKHbBl6p9VTvElJvefq/G65uNTWt24mOHrtiCHlW JVFr5PICPEU5mx9PQ6xHciiqQslqwUCWOuFtZT1EK4hTNIKG99NkyL692fa9AgMB AAGjggGUMIIBkDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFNAjaKwnvVAp BWNOFPIcN2fnhirwMB8GA1UdIwQYMBaAFI/wS3+oLkUkrk1Q+mOai97i3Ru8MHsG CCsGAQUFBwEBBG8wbTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AyLmdsb2JhbHNp Z24uY29tL3Jvb3RyMzA7BggrBgEFBQcwAoYvaHR0cDovL3NlY3VyZS5nbG9iYWxz aWduLmNvbS9jYWNlcnQvcm9vdC1yMy5jcnQwNgYDVR0fBC8wLTAroCmgJ4YlaHR0 cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBWBgNVHSAETzBNMAgG BmeBDAECAjBBBgkrBgEEAaAyARQwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cu Z2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAB/N 0PPEvmprw9mYuEYFJELxRYh2yNvL3jdknzDd8r8Way33mRbHYKW6T1fKSw1l+JK3 rG9gDPloMH4CmAH4FWMMMd8EAyS7Dytkeifqmjiv2KTN1rs+VsHPMvFPdXwJse39 ikXt2UIh0XeB1CbBvCN4djBB+kXSvgIMZIfbgoHffI1rtEWU+BOFWFMROyPFNLdS supTYW4+cUm+1P5ihLN7M7KF0/0zBz/wWgk7MV1Eln+RYaKscFVCM+6DUOZ5lmoA nQdJGi2zfqDDj3RZEMF/95x9JiBuJg6kM/QwwBmRXPPIJgDq3Qsb8Y5LREXOX6G+ uBF+cdm2Vg5J87oTRLo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFTCCA/2gAwIBAgIRAK8cBLKsjP+bAAAAAFHOGOMwDQYJKoZIhvcNAQELBQAw gbQxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAwPgYDVQQLFDd3d3cuZW50cnVzdC5u ZXQvQ1BTXzIwNDggaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYD VQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRy dXN0Lm5ldCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAoMjA0OCkwHhcNMjAwNzI5 MTU0ODMwWhcNMjkwNjI5MTYxODMwWjCBpTELMAkGA1UEBhMCVVMxFjAUBgNVBAoT DUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMg aW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMTAgRW50 cnVzdCwgSW5jLjEiMCAGA1UEAxMZRW50cnVzdCBDbGFzcyAyIENsaWVudCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQyjULQnhmdW5BaEEy1EAAh uQdI3q5ugNb/FFAG6HWva0aO56VPrcOMsPp74BmR/fBjrXFJ86gcH6s0GSBOS1Tp AJO+cAgx3olTrFe8JO8qj0LU9+qVJV0UdtLNpxL6G7K0XGFAvV/dV5tEVdjFiRk8 ZT256NSlLcIs0+qDMaIIPF5ZrhIuKgqMXvOzMa4KrX7ssEkJ/KcuIh5oZDSdFuOm PQMxQBb3lPZLGTTJl+YinEjeZKCDC1gFmMQiRokF/aO+9klMYQMWpPgKmRziwMZ+ aQIyV5ADrwCUobnczq/v9HwYzjALyof41V8fWVHYiwu5OMZYwlN82ibU2/K9kM0C AwEAAaOCAS0wggEpMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcD BAYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAzBggrBgEFBQcBAQQnMCUw IwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDIGA1UdHwQrMCkw J6AloCOGIWh0dHA6Ly9jcmwuZW50cnVzdC5uZXQvMjA0OGNhLmNybDA7BgNVHSAE NDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL3d3dy5lbnRydXN0Lm5l dC9ycGEwHQYDVR0OBBYEFAmRpbrp8i4qdd/Nfv53yvLea5skMB8GA1UdIwQYMBaA FFXkgdERgL7YibkIozH5oSQJFrlwMA0GCSqGSIb3DQEBCwUAA4IBAQA/vekQdfNC p9FsgSahRiBXEiQVWrIMCH/dR7k/QpOkCq9MEe7MazD0tCyE3goXkPl4NK6uJkV2 BTUkg8CTc5lPpXJxY7QJiBHLbG7vlJXVSTfPoQDwDUsUUUb0aHGy/mChNw8l/O8g WjPGqYfJ6lL212lIls5azxCb9rcBwzohpchDwISdA/jFNAiHy4sKg1yqIyvp/7je p0kObTIVgTDIJ/TA/s8adcyHu7oRoYJlUAWf80WSh6BFuBnnX/hGClvM2F1rFpFM FZVq4+T83gZ09mxU3cQl8GkW1uoOP1m+AWL5YJ8dQLMx9xCcL/mKRGbYYAJOMRCx 9peO/iCDvU1K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGpzCCBI+gAwIBAgIQW7jdZymYotXG883URqrDojANBgkqhkiG9w0BAQ0FADBX MTAwLgYDVQQDDCdFbnRydXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gQUFU TDExFjAUBgNVBAoMDUVudHJ1c3QsIEluYy4xCzAJBgNVBAYTAlVTMB4XDTIwMDcy OTE2MzEwM1oXDTM3MTIxOTIzNTkwMFowgYgxMzAxBgNVBAMTKkVudHJ1c3QgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkgLSBERSBRU2lnMTEYMBYGA1UEYRMPVkFUREUt MTE5MjY0MzE2MSowKAYDVQQKEyFFbnRydXN0IERhdGFjYXJkIERldXRzY2hsYW5k IEdtYkgxCzAJBgNVBAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC AgEAshIYhD7/9ZY2nzyq/D2n8zla6P8AvHoaV/V2CL9n6AgEMXOCct2nvndGg1o1 A5zKo6mkhG27TeorkTtoa1bH9K/zEMXti/4Bhu0ISBZrRmsiiqLDCt6Qn72IgwgS Jq96vHgz5ouzZEAbHGFMe3TUItS4jR8GmTrU14jKkNlDcXisZz8PY4XXzQqzFsNd kzEI/opMl9Zh7HpcxN36jLaZj7+lrykoW0omWujYlrc67GmNzUMTv/i9joRJVyw/ vCm6NtsgFpodj/MWzLj2R9LFGoQsEU7QdkrVZthccx/vzBjv/1J3fDISIX8sx/Nk /5mzgS9XxM4/uuyPaVXRs7sBnkyojH0g0E70G9PgMfD74/ExG/00aq5wjUy+thAO F0OG4nX+55MILKyKaRq84zgsohDnWMavfIEeqs3heMFxZKpN5yoxIQh/lNT72jMf FZddcoNiq9v2WYswtBbaKLd95pMjbl6kI7XSQaJOM5Ssnjt9V6XZ7+DP4pAwVgNG F2f/4lgJGFl40HFYEyW4I+pDOKAh4tLLSvo5Jp2KzlVXKbLDL+fz/pUfUk6wT2Y5 /Bv7waT1GLhBOSH8zfvPhYWcAcuXF0LcWW1lWSf0faoevNPgFn/lD1BUEU6xHsAN pwlZ8UOXpzuBVLczo7BsYZQQUfrizSHr3OejAEdlIEyrLF0CAwEAAaOCATswggE3 MA4GA1UdDwEB/wQEAwIBhjAqBgNVHSUEIzAhBggrBgEFBQcDBAYKKwYBBAGCNwoD DAYJKoZIhvcvAQEFMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFDHsBxMw x+LRLV4R+DelfaljX1NkMB8GA1UdIwQYMBaAFGPxhN0DvqOfZPp2ekfEVn7AbaAg MDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVz dC5uZXQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbnRydXN0Lm5ldC9h YXRsMWNhLmNybDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0 cDovL3d3dy5lbnRydXN0Lm5ldC9ycGEwDQYJKoZIhvcNAQENBQADggIBAAvcdUL6 ZtAlD1Vq0J6124djuLz770UDa/dz0GmI7U2pSzqZcsGHk27/XqbGngq9vF5TNJlV l8FbTKPdXnsrHl00kAH1okx+AITvoKx0dpBj0xmlB9emoiyR6/M0za9BzULYLHlE ziuW+kx0f+/Omsq7O0TJT+VSSuJ31jKDxkrd65FP0o9xn7NSmos/3XrVDzISK0Sn 0klfD2PTIq/cJL+E2pWTaBsUF8AZF4iiKSh45kA7RFF8anWMQuctDpHNoQWl/89E x078uyL2jdAJ7e52tpJMHKWREy+F+ei49nRbZHqpzJOu+r84mFYm9QfVIc3qqsAv Q3z93xd4AynNs2AcsUOj9w9wB8rSOwlu3hqYNca79uXGgSEZoz+mLKtGHFSzBaFg f0SOs7bIUrCL+DWwG7ceygvQrUbAeF5l6LzU6/yKkxeyxLcPI6fPBx5XY72Z9oP8 uAaNwAylTGxScahsgCkRIyfCprsezDWm92bqZZTqcbmsdmCCOnjfHWvoUFzEgc0N 5Jb6gsQOZTUzSEYFX/FeUHjZjvDd4aKlu8EJasFVI7CsGKpnBtrKkye5jYfRnScG RYbEV2todpjxdTk6CPj/YVkIO/0wKNhxiQlsA5swyt57Z80U8R2g+5BkWMySB9I5 YseOSa7f5taNWaO3dYmUQ+BS2oltZaQrJItD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGozCCBIugAwIBAgIQRJHKWCW+eYQrKbDDcoYhXzANBgkqhkiG9w0BAQ0FADBX MTAwLgYDVQQDDCdFbnRydXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gQUFU TDExFjAUBgNVBAoMDUVudHJ1c3QsIEluYy4xCzAJBgNVBAYTAlVTMB4XDTIwMDcy OTE2MzMwMFoXDTM3MTIxOTIzNTkwMFowgYQxMzAxBgNVBAMTKkVudHJ1c3QgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkgLSBFUyBRU2lnMTEYMBYGA1UEYRMPVkFURVMt QjgxMTg4MDQ3MSYwJAYDVQQKEx1FbnRydXN0IERhdGFjYXJkIEV1cm9wZSwgUy5M LjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0 G/GJ++yxCAnevmBeXKlPJL7y+cgA+DUFjNLKkkfGuYQkr5SQVcIx5+TEoOYN+Hy7 Sz/y6FG6gy0keJj0n094/FPyTJHS8D5sD38LDgRgkUzplEpt3zYTCBCgbDZDpb0T qPIX+6RLO+Jo/BtyFMKVwVElMwmZx0sKCPl4mPyTLUIpGuU9OV1irqMOCOtVI41f 7FuySw3vaeDtX+rQKCPQx2J5Wzg4mSUXGbAr86dMncjxpwm5A29TmfF3VUEzmAeQ AOX/Q+qQmnAI2Dp9Nj/pk78RmwXLmq09l+jlfzRJbC7ov2EtUMmJApPUDQT2Vv8z c/JG92UHQlTbd5ehIAT+At2dmVaykMWfiZ8s7TauoeEpDPNr321uddC1zS+SxKAN Ldq22Pz3I4K6zpq5IYBj8Iswz4p6cCBRFofpr9wDSVFj4pTeKlsI6LDhSKUExwvt vXCUXUqJenCXn7VP2qNwxeERX0OaCjzivpu1+x68vFfajkV5QQyAHowZatPJ4iDP ar4a9bFLLo0sLrlCs0ukDRyS1cnjbE8nB/rnQVC975qP/VtzceatzOxJFlxpViSq Xrq005zMkbKUFgZ9lcU8UMcvJyMt34NSi25xmgOoMUMLVVz/kxb5IY+hPks6OYar 7WoHh8TKB0VkNHQOc2jH4zfdRsRNd2sJ2LFtL9XtWwIDAQABo4IBOzCCATcwDgYD VR0PAQH/BAQDAgGGMCoGA1UdJQQjMCEGCCsGAQUFBwMEBgorBgEEAYI3CgMMBgkq hkiG9y8BAQUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUWlMIimEwqQ3q 1UOX05g7lR4ubQIwHwYDVR0jBBgwFoAUY/GE3QO+o59k+nZ6R8RWfsBtoCAwMwYI KwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5l dDAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1c3QubmV0L2FhdGwx Y2EuY3JsMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8v d3d3LmVudHJ1c3QubmV0L3JwYTANBgkqhkiG9w0BAQ0FAAOCAgEAaPxyjsaegc83 /3wCW7HMXmPSMPdB6bEYO5kOdPLbdbaBNJM2LuGSbv+DoxqbuIsnK/jS1+rVpTn/ xAawEotfE0pF2UIiLpzPgrH5Mew/f1yf8+JoPP98wuWQ3eHyVCSNpTdyE5tr7s2Q NV6o6Yrie7HlUI9vE6qZvzl4Xh3fN/eOW6z/Wbo5NImZODy/nNCih+xT4VxEl9SD do0acoCLKe7exfGz3taeegvEOisn+wRDkXP8G5cxwbWWh9VsoRUsmDahckJsFxJ0 Cqno8Qt1muk/a7MMWwDfz0OAQPyW7+jdW3Wma7qJnG3v7mDetHxQ7B3IMUAurDJs IZNcJ8KUl0wWlBpriiGXoLsb8fVIQvbxcsfxTreCXf6Xqr6/aogMwiqTg4FnIk5i boRU0r2Jt1Zei9eP3saspCTgHn8IzBNVx6+SYNSlHPkEg3FPmHPhKLYkeTJh4fUQ 9F+dLlNPKtLnHvVFMbecS7qsTM8l9ltSXsrKrt4rqUiQ1SEBQrwitaXDzYkGGw/4 v+ezab9HVb0VQ7X89iyY+KIVRPFJ9aDtmaHSzMQiduSAy7bGBT6LFN8dUE3qqDVd ZFwU5VW6U9y76lhoile/tOVH+gLBfh5SqKmmIlUvd6eYlGG59743qOeiP8Yct67a pk9HadUSQ8STL7Vj3zzD2yZfrh00jmA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFADCCA+igAwIBAgIRAOyKJpsJ606dAAAAAFHTlCMwDQYJKoZIhvcNAQELBQAw gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg MjAwOSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MB4XDTIwMDcyOTE5MTYwOFoXDTMwMTEyOTE5NDYwOFowgYgxMzAxBgNVBAMMKkVu dHJ1c3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBERSBRV0FDMTEYMBYGA1UE YQwPVkFUREUtMTE5MjY0MzE2MSowKAYDVQQKDCFFbnRydXN0IERhdGFjYXJkIERl dXRzY2hsYW5kIEdtYkgxCzAJBgNVBAYTAkRFMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA69NU+CcX7vuD3CjdzDZqOQrskUpvuZs1y0JXS4MapSjCTKCz JAHZjMdkpAiRZS4SZ8ptx1o3Hh/SXHqEwAQzTPbvA/5RPNp+XD6vsACs84jEEyM5 qAcKbTias6tSw30N3FM41NUknS2wwOC1FlX0QQByIBcHfIT/qujfnm5uBVATkTC7 MaZ1vuRJ6Z0k3VWCuaQSNHkPhlR9UUuGIGUCUC7Fhhu6/d94o3VGKMTTCsXNKe3M p4oTwAJ0+x4j8iOaua7mhQcl/R8M0FmIWdfw2Cr3Xh5BkWEDKo92u+6JE+v1vHTZ RCHzbAEKCZiFwiA46+TfsxLe2AR1KXaeGsUs8wIDAQABo4IBKzCCAScwDgYDVR0P AQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpo dHRwOi8vd3d3LmVudHJ1c3QubmV0L3JwYTAzBggrBgEFBQcBAQQnMCUwIwYIKwYB BQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDAGA1UdHwQpMCcwJaAjoCGG H2h0dHA6Ly9jcmwuZW50cnVzdC5uZXQvZzJjYS5jcmwwHQYDVR0OBBYEFBkjOudG 6+TYlOL32vGz+KqVNA5jMB8GA1UdIwQYMBaAFGpyJnrQHu995ztpUdRsjZ+QEmar MA0GCSqGSIb3DQEBCwUAA4IBAQCgSwDNw/VBrUrX9hI2vqbVy24xRKsYFO381pbV 6ZDUhvAyq7mEIGXGev2aHP1KdHz6RZjqfVEI22JgZyOFFRQO32r1pO0IJdl75+Vw ZY5dh+cYGBRRG/NFd3aqTgAbE0SwKApKw+9+VM+Omv7bzYaQWbHNPtjTqKMp1iSg XWZID49S8DZCuMfmX4g8VmqYVEowKNYgTne2kAzLmWUOmcdXaifLL4bHxyPaWH+v bK2UvK2ImsIrsk5aEXWMdm2WI/USKzOvqc6K/fjK+f+Q33TrAw0JZZm995O+yXxC JpkBZtqJZpzyjh+csjDHCPnYHsgO0OohSowxlsa13p7TmNFF -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG8TCCBNmgAwIBAgIQVHsoVDwxEslytvKRXyMYdTANBgkqhkiG9w0BAQsFADBR MQswCQYDVQQGEwJFUzFCMEAGA1UEAww5QXV0b3JpZGFkIGRlIENlcnRpZmljYWNp b24gRmlybWFwcm9mZXNpb25hbCBDSUYgQTYyNjM0MDY4MB4XDTIwMDczMDA5MjYw NFoXDTMwMTIzMTA0MDI1NVowgZMxCzAJBgNVBAYTAkVTMRMwEQYDVQQKDApTSUdO RSBTLkEuMRgwFgYDVQRhDA9WQVRFUy1BMTEwMjkyNzkxIzAhBgNVBAsMGkF1dG9y aWRhZCBkZSBDZXJ0aWZpY2FjaW9uMTAwLgYDVQQDDCdTSUdORSBBdXRvcmlkYWQg ZGUgQ2VydGlmaWNhY2lvbiAtIDIwMjAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQDP/y8ZpE+Ak9SxmXjllE1E5lIRo1sc4xuD9GEzpyj8XsoySviv4E2y 4mji9SpeeJ/JUm1DnQkWN9MuknbGoBv7os6JyWr5hCL8SrmOE3vjug+Ccwd7fCS2 4AmrTIsAI7WHDcF7lI4VXEfKlLmTI52LqSrxI9jHYnqZeRcwz3Tgjwtt2sUlRd1N SbNDP11L3bg0DE05McZ49EEA4i5EFp8M5JdNdxfPCrGHv+EyZdKN84Y5qZ4Zfn/I iqOyM7V1YOeTq3sjUgjItWVI+8l9tbmKyiTROIBh9okawRrlQOHXqUvltFb+oDnW TJRib1+S0SRjY2M31IOqk33n4v1nb4DaURRwZNYTFiuDpGdJ3+eQqGK6EqCLkXrv a/FySshF+Cyb0Zy4aKZPIBjmDij7ws5uhO0sSKXwxKiJ8n02rgrsT7RbHmhdnt98 aPSRTAjRVVYvAAACYtKQLgWWs2wc/aZEaefGNA6YIKy4uuSpk9ijsy0DSXWpjUPg VDyEvt2XwMFgFi8Bm3k9HwXRVq6agMGpjkhIJbOFyIyWld8b2fAK/aOSQ91kVwjm A6XitbuKUkxNDqi3XRyebVTtB46du41dn3cfL5i88hkecalBDKRTqWeA+3xsQ7Mk riXpbsJGePbZejo9VspMUirJe6HLxyK3KN1j7GhcDT8Mri3tqcQM1wIDAQABo4IB gDCCAXwwdAYIKwYBBQUHAQEEaDBmMDYGCCsGAQUFBzAChipodHRwOi8vY3JsLmZp cm1hcHJvZmVzaW9uYWwuY29tL2Nhcm9vdC5jcnQwLAYIKwYBBQUHMAGGIGh0dHA6 Ly9vY3NwLmZpcm1hcHJvZmVzaW9uYWwuY29tMB0GA1UdDgQWBBQiOoLmqD+p4+oj oKv2jQRLSHtozDASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFGXN66s1 HgA+ftV0wBy0c0cOGmQvMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIB FiNodHRwOi8vd3d3LmZpcm1hcHJvZmVzaW9uYWwuY29tL2NwczA7BgNVHR8ENDAy MDCgLqAshipodHRwOi8vY3JsLmZpcm1hcHJvZmVzaW9uYWwuY29tL2Zwcm9vdC5j cmwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDANBgkqhkiG9w0BAQsFAAOCAgEABc2EBUX4WVdXlpqLyMdbwU/+wiOipbEYanb3 P5OIFlSb8P6p84yvBLKJXIB/u02UD6OpI8RQHgdIJM7OJOTvFjLPyR1RBDw5hxCA 0RflOfc59U+NQ7xFTnGoqsB9xxLv4KhXnJvYJPT2BzEndceAgX+qd3iVJTNJgJGV 0gqmD/nqR19uLbY/5zMeyUZlQ6r+vq5Uz4kO00IHZrs1VXf+VfTLPOSNIjxubfuT NdPhUfysWo5N3UskCClb0gtt5+efq7kpIprCCorlcMoaI2yCCVsNuKUB7GR4lR1u 21s2Mpp98SosWDXXrjDbYtOyCmVNoJiU0jlzzGc1IAnqdpxaWl8rAGoJEA8wl46I fIKeaLwUcq/diDn3id7/5NUMspQQFfmKQJbvctKt5ClP8kjnXc+yVWt+38qQnUMo 789NAzXGIMX5Qt0dkK/JF2xgZ/qcik++uJjj1Y+moxnkWO+jZ3MKNndHSzULE+JF wjp0w67vxvHLjpYeuSiFy1J1gi/wc1/0c7RWdudBTsna2uFR5KD7mm9hRma1mUD5 75HkvzQF0CSPjfeZ4FW60wXn1ldywF7DJQPzgu2qe+ILDrq+KQ3q4fRlevUF+rzf g1c/tjNQ1IzvxUthnujATYi+f3/urkX9EJRBPnSHiGwHtxhdwhVX864IbIQkc1x2 KCqOoIQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEyDCCA7CgAwIBAgIRAPq7J93/gNCaAAAAAFHTlEAwDQYJKoZIhvcNAQELBQAw gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg MjAwOSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MB4XDTIwMDgxMDE0MTE0OFoXDTMwMTExMDE0NDE0OFowUTEwMC4GA1UEAwwnU2ll bWVucyBJc3N1aW5nIENBIEludGVybmV0IFNlcnZlciAyMDIwMRAwDgYDVQQKDAdT aWVtZW5zMQswCQYDVQQGEwJERTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAKaObolX8HfJIwgopTC1irrqYKnjpjiX2a4rzCH5RI3tGW/KI6k+enrvztSM SZY2J1wVBwdyMFzhQZA0sf7LVs96FW3UyMrxyGUUzm18/+Qn4O93gFjaleZCL/Xe 9lwp8hk7EZrmgPTJ+SAaHAobFbjdZffWd1EbbvMoB2pvkRzthCNRkYiiq3S1BU27 rA2VBh4s449VW28AK7nBX4HNOSx6TF/IRYiAmyohvO/DGvAsBJPiXrqtCRdVoAYc P35oV/FJdZdRaLC6Upm2VooXMQK2FDhA7uilx99OJ8jfFsd45sxeLjt6ySC/QPCL 6uobSnyDd1/iIk2WatcU9jVQIwsCAwEAAaOCASswggEnMA4GA1UdDwEB/wQEAwIB hjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL3d3 dy5lbnRydXN0Lm5ldC9ycGEwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdo dHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8v Y3JsLmVudHJ1c3QubmV0L2cyY2EuY3JsMB0GA1UdDgQWBBTJp1fLhslhB8bCtIZl qR7ByuECmzAfBgNVHSMEGDAWgBRqciZ60B7vfec7aVHUbI2fkBJmqzANBgkqhkiG 9w0BAQsFAAOCAQEAZfy1vyfxE6cHBwi5qTk1GTDarGfFEYVpTHeeQjpAzYdjDDwi Nk7Tth2NwlAUqtaI143Koo/1xhls2scU6Z9RD/DLq4VXCkxgKOqZYno98rMS2xqI dLTeionXSLxWeI64HwqTFlvwDB+BBCQOy5O6g+XKKa+U6Xy5NAEFpyYrxdGLHGQ4 oWSW23NophBqs7w7+71OsKzL97a3BRlxBWDq2i4Cdt63jsQ+1NOC3SSi/ZcRxknb h+Is9n+O184HAfI7HVeYhalK+ZaFKxEaVrxJBSPPDMbJiTn6g31lG9da4h12geiX aKGvQEbW1PvXjbAvLFAEGxfp4Sgnen4c+zHz2w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG7DCCBNSgAwIBAgIUMpkuGUziLq6U6WyLtHU3mhHixM8wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0yMDA4MTIxODI2NDRaFw0y OTA4MTAxODI2NDRaMIGBMQswCQYDVQQGEwJOTDEgMB4GA1UECgwXUXVvVmFkaXMg VHJ1c3RsaW5rIEIuVi4xFzAVBgNVBGEMDk5UUk5MLTMwMjM3NDU5MTcwNQYDVQQD DC5RdW9WYWRpcyBFVSBJc3N1aW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEc2 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxOgePhJvHWFxWe/U8aod +3zwBJBdzS67u8JRls4SyEuYDpZDIexZ0S+Xp2CRQRfxtWfA8qc3Ey4wwxYPPdMP 6+GPpvWoTJ7p6MWYJs1fzxkEUfZZT/L8R2Ny7kDWoyVGRQlphPMa0MttROazrc2h RBzwDlnIDYo7Su5lkBaX6TCZ9BZYmVUoiUjn6O3xMBVNOawvBN0zIsGbI0o8TxYo 9gjFZ2Ro68tCgYwQUcGDsQbvIqbtCwEf90QhKty9jEMibWBHTaIS7iifdPEyrR13 /L09VvUQkYbxobnicpuPASPNbpK6freTgLhF1m/rTXfIf9HEKlcaem/ymFV0r5F6 4mdzblp1SrnmnGHmOyFf2oKWMK8AU3TcUeV45h/hX5s9K72RVVf5g1G7ZXPIXaUq 62BksJ6QvFf+NMiZAbjVx3hLO1I5xKKGStJG7B/Nme8Ao/uMkIj/TkVKIwB9SuQw OyyW4OfNJfM39gAS42kR4MytrJV6FRiUITk8iOtFUBn5BLQHhXReK087wpi2pTw0 LUhV9c2glJRdCe40FLvlxQprxaJca2sWlSI7jt8g9788r52ngXCOjQmvpR6Ckrmp hNqlCKk/1FR8FhNmyc1Csy48PM0Hr5q+qw99KXPCjj26tHrAGlRdJzB3Mfceobds kZP5MO1rtwkgPZjQCNMhKbsCAwEAAaOCAZIwggGOMBIGA1UdEwEB/wQIMAYBAf8C AQEwHwYDVR0jBBgwFoAUo5fW816iEOGrRZ88F2Q87gFwnMwwdAYIKwYBBQUHAQEE aDBmMDgGCCsGAQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29t L3F2cmNhMWczLmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVvdmFkaXNn bG9iYWwuY29tMEoGA1UdIARDMEEwPwYEVR0gADA3MDUGCCsGAQUFBwIBFilodHRw czovL3d3dy5xdW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeTApBgNVHSUEIjAg BggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwwOwYDVR0fBDQwMjAwoC6g LIYqaHR0cDovL2NybC5xdW92YWRpc2dsb2JhbC5jb20vcXZyY2ExZzMuY3JsMB0G A1UdDgQWBBSsPz1Uci/fH+D2GYWsmpFegMwArTAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQELBQADggIBAJ2a13SxHHdSS+1zKPD/dbuNtcmm36nvmBeKxykkjB34 TYa3m8JrX4ueXkPsrZ7mf2n0d6KzSFj7sOZUO/Q0UgbEPUZxHI9atDKgppJpWcnn OMsQ1yEwbZRmCP3py6RzBtECkSBUbBpzh/P2pnxyvJOM4uGEBh0fPx6KnF4pJ23e QmfQJ6NG7x0SemO8VBCxCHdl9035hHJrtllthjDKaQTQCR80kgyMW51c1PYoRC2n BhZusNcqq/pxH3mBbKvsVY36FtJcNhMUtbg7v/dP2mwW/r9UZ3E/G7nvLGOQtJLp pZQMWIjOn0dQPjTmQ9e/f333GRfwj/mfAty9ankCyRDPaYMFgUZWw+y/PA/CCwba T+QyATixqA3KVvjaXNr3STJLPLsPbdF2pxzE7JYsUREJrMRzi893sSVKX14Q6QRq UkkjzWXwwb0lwuIdx6vzerk3j38TfKfIAj+zJbkqTn+Zuad1lyUCXEN4TCTLg1bq PeZMxXQOjJ4ozmErKyH5YHvXojrJdMDbzUMu07UHPCR1SnR0jRhhulgjyGgH0UEG ACjORxobmD4S1Ok9iOngBUavJJwZS3z1YI+NakLE55PuflTlr2UwBD8G0EyaogQg luGJZHdkk1KN/vF8FyDxOarVF6WdGL8ZUW7htpEW5wkt3FfOt9Jw3lTLvUMavTkg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG4jCCBMqgAwIBAgIUW/OexkUzYOApf0zF19iIKKypFMIwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0yMDA4MTIxODI4MzBaFw0y OTA4MTAxODI4MzBaMHgxCzAJBgNVBAYTAkJFMSUwIwYDVQQKDBxEaWdpQ2VydCBF dXJvcGUgQmVsZ2l1bSBCLlYuMRkwFwYDVQRhDBBOVFJCRS0wNTM3Njk4MzE4MScw JQYDVQQDDB5RdW9WYWRpcyBCZWxnaXVtIElzc3VpbmcgQ0EgRzQwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQDitrWoACAEeXc6YxEl4NvH5sFzpeMn5t9D PshimDKScLHXt58Xt2KhQG8dDtqm3EUYCTwXZ850M8fIdWLGuvJY3LConAb8TMeU oJvnQCOf3hyq2otQXccWFJraK3j3OHbucmbHxhR2cWzVj89bb/NjFheevj7KWZ5c aUu/2Sbc3WDHdS3mJKdonzbG5xlvDOclRyialixIJAfim8049el5rCuaLbZheJxJ v4ehFAB+nYLTewqSc2iXjBzryJWKlH9mcWxOnb52NDH428suH0pGhoYb7/6KlhNm xCuLfqfjVWRzOJIU+yMaS0GO5uat0PFQeD1nXjmjwLpoGj5UsrgviM1cKP3I0e/S okMEe0/CJfZEI2REHfgqNjfLOwdlC8Qyl73Y/+VOVWIJgJgO5mNx5AF/ilxoI9gP KObkFJV4H62jfsIt5tf3IrKMlXtQ/G5ldlSiX5Q7l6NMx5pn6xLxuy5T0G/1pGwe zWwL8JwU6w+Bp7kguDUisU76P9eV7gkRpHBoexGm/ZgIdhKlCq1ppj1RV+NpPyoq KApu4uMusegHdRcm+Nmq8zW/GX0W6SiK9q9OJsDOU42fY+0hQ4rRwoZW1oLbYpDP e1HFsB3HWZDi6WtYFjYIsvuPIIukcXgMmtMQVJBgnEPyYKpwJR5uU/ABeb8z1tQq 1PBcOA7XRQIDAQABo4IBkjCCAY4wEgYDVR0TAQH/BAgwBgEB/wIBATAfBgNVHSME GDAWgBSjl9bzXqIQ4atFnzwXZDzuAXCczDB0BggrBgEFBQcBAQRoMGYwOAYIKwYB BQUHMAKGLGh0dHA6Ly90cnVzdC5xdW92YWRpc2dsb2JhbC5jb20vcXZyY2ExZzMu Y3J0MCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5xdW92YWRpc2dsb2JhbC5jb20w SgYDVR0gBEMwQTA/BgRVHSAAMDcwNQYIKwYBBQUHAgEWKWh0dHBzOi8vd3d3LnF1 b3ZhZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5MCkGA1UdJQQiMCAGCCsGAQUFBwMC BggrBgEFBQcDBAYKKwYBBAGCNwoDDDA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8v Y3JsLnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTFnMy5jcmwwHQYDVR0OBBYEFMb+ Ruky4eIJ2XuvbJsgXqerADCOMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAi/eIFYaiEW0fvPHchUpj1dY0ZEkYDRnIRCnHixYCqIZgL0y6UrhwbDi9 fGjPxwvEVkNqe8Gf0r7ooYT0hnrL1x80Qs06Jasf1cI4Fm1wwov6iMY1Jf4g9x/C /Z6AlQ8lvb/cQQnnW9OEXMJNKOTYED3IJPLGaLWXbjG/3LOSZd1rFMFvxZrqs1Ql 6eqDfGefWswO1tVHrfHU3Fm8lPYhtRa+UjJTelkwkJ1CRsJRUg1HqOgaYYvcERSi UEF7rxKaap4w5JBgq87fOtT0ApFTUZlORmyjwskTLAw+5XUwXHwRaPzCJKx6BGwt TF8lEcfmeDG6ff9Z7gyFdYa5KI6TgQBHCCNwqoaXtK5lML1560qh1cIHjpsA/rZm eVXz9GpOX+qE1AdjCIKqVlQtduHHEbYnG/G9englAsp5ePKUvVFW11HuDkE9F/GX 8pOAcFBNsniDX38cSJYNw35zktGdOqolIAqJhNmA414qU5s4BFkQbCspWop8POgP HhTpWHNe98wv7zsQf56ddsGbfrtKz6M7x+pooTLTR4WzLR76PzbuXI6Gxs653R6P apwwShzZMTHuBHNbBw3ONwT3/ybii6QxVtcgc1rSCh5vF+AcArcIaVFzLCv0c9I1 g6ySWCjr3JM5CmcIccTKWja/SgvxjP2B9ZHyIHpPBFdEc+c0l84= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGvDCCBKSgAwIBAgIQQAFz5DrTFUD8HSw8GTqeEDANBgkqhkiG9w0BAQsFADBN MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMjAwODEyMTk1MjA3WhcN MjgwODEyMTk1MjA3WjBoMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 MRcwFQYDVQQLEw5UcnVzdElEIFNlcnZlcjEsMCoGA1UEAxMjSWRlblRydXN0IFB1 YmxpYyBTZWN0b3IgU2VydmVyIENBIDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQD5T0OgoLBlfZ8v+YC6TZc3mK7gwdGMkZvWG1SjjEnU78XwpmD+4pq+ io7GSee6w/74kIbIYaJBWL4ivKB1eaOLHAzanZP/woymKQAy1mz0t5I1lBLc7Xmk ClORH+roXXgCCNaahfgX3nDzLSYE7zmMbAbTIFEsJgHaQXvKtcl1U1ycn0TWIDa+ ikd2IHG+vgg0xwKTuucyAOIe51qoyjToIFLRtQbawP6Lu9Du1LW52zaQmxXWCYPe ao2eQCOIQxm8+6Ov7gNk1HrDbbl9+6pi8t4EJgO2oXovGi2kpa9ktubt/8OEavBr kJnyHdgpXg0pHRAxKlumM0wDis16R1GtAgMBAAGjggJ7MIICdzASBgNVHRMBAf8E CDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjCBgQYIKwYBBQUHAQEEdTBzMCwGCCsG AQUFBzABhiBodHRwOi8vcHVibGljLm9jc3AuaWRlbnRydXN0LmNvbTBDBggrBgEF BQcwAoY3aHR0cDovL3ZhbGlkYXRpb24uaWRlbnRydXN0LmNvbS9yb290cy9wdWJs aWNyb290Y2ExLnA3YzAfBgNVHSMEGDAWgBTjceCe2KdC2dtxkWuUk+vDo9EUozCC ASQGA1UdIASCARswggEXMIIBEwYEVR0gADCCAQkwSgYIKwYBBQUHAgEWPmh0dHBz Oi8vc2VjdXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9p bmRleC5odG1sMIG6BggrBgEFBQcCAjCBrQyBqlRoaXMgVHJ1c3RJRCBDZXJ0aWZp Y2F0ZSBoYXMgYmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIElkZW5UcnVz dCdzIFRydXN0SUQgQ2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8v c2VjdXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRl eC5odG1sMEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly92YWxpZGF0aW9uLmlkZW50 cnVzdC5jb20vY3JsL3B1YmxpY3Jvb3RjYTEuY3JsMB0GA1UdDgQWBBRflx7JLykP kp4mjoIPuFgLi9JEBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJ KoZIhvcNAQELBQADggIBACwOy4GDh4qkc4mCBFUc4lAfMpyQvfqRC3ydapHfk6wu Upe+0kCI63BPwdT+nsgZnC1IRyEUSUGpaqAAEz3FFF7X1n7Ri57Xh8wH5CTlcCRp IPlT1BwhlTQ0wSGRqqPSao+iCp2kLTwrptW1M1a4cNTi9XNf10V5SFoNhyyo2lbL NnJ+1N2sBqXkb9yEMC+MKu4eFxS5+DVhLoz6xMh6Sl3/5YlhOukfvQpoMO+f56EM a5+so74xaFWYjscBCsVSZmjIARA4NO0kLidpN9LA8jgZdIb/u7PfdvjFgB3KfRPR 9ljj4vZ6N5hdTZaYV4vr9VCQObW4yTic5oSb5kFdz3Qm+3DRkrw56z4W5PivhSGU x5nIu0m7ieB3A9ZP0NZInAQ/0fuVaFjnb24PvyLyEnRQBPii7099PVaHWEDkX8BY DH9JyIchTliAvsLrXfO67ycd0nMjftBgLMoVENK7nBdnYzNUl852KWfLqGGCHGXM AnduWiQaqbi57QJyDiaPc4BWwV7iftEBL72okBifsXyUTht+FHry22xHSL1oF5Qz SxX7i6xN0SVXqBBNbGfMg1SopPBtj0VIznILYLpKvE/HaMGhXmg4LGCs6Uv6obgS EJud9QgW6oEwJZjGWtjTgjgS26XYmpV+95mKG77PWuTPltFqukZ8AW9/qastsDH3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDFjCCAp2gAwIBAgINAgCOsljntZQMH/kARDAKBggqhkjOPQQDAzBHMQswCQYD VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG A1UEAxMLR1RTIFJvb3QgUjQwHhcNMjAwODEzMDAwMDQyWhcNMjUwOTMwMDAwMDQy WjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz IExMQzETMBEGA1UEAxMKR1RTIENBIDJBMTBZMBMGByqGSM49AgEGCCqGSM49AwEH A0IABADfm7MZo8aDj2QQNzCIfwnQ/yd9f+b0YdzHZXrVztMw/k63A+MGTzK1XTLF +LYj7csyP62BImmiRSAXwF6iiIijggFtMIIBaTAOBgNVHQ8BAf8EBAMCAYYwEwYD VR0lBAwwCgYIKwYBBQUHAwEwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU kxhjkRd2mlrmO38uM4OEhmse1PkwHwYDVR0jBBgwFoAUgEzW63T/STaj1dj8tT7F avCUHYwwaAYIKwYBBQUHAQEEXDBaMCYGCCsGAQUFBzABhhpodHRwOi8vb2NzcC5w a2kuZ29vZy9ndHNyNDAwBggrBgEFBQcwAoYkaHR0cDovL3BraS5nb29nL3JlcG8v Y2VydHMvZ3RzcjQuZGVyMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwucGtp Lmdvb2cvZ3RzcjQvZ3RzcjQuY3JsME4GA1UdIARHMEUwCAYGZ4EMAQIBMDkGCysG AQQB1nkCBQMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vcGtpLmdvb2cvcmVwb3Np dG9yeS8wCgYIKoZIzj0EAwMDZwAwZAIwGwr6MqSiPwW7UNI4MBn9y49+F3u1aDRB aUe+j3DUewN1wLSsjcooVET/QQ+zv4CpAjBXUKDTWCX9qnQAmahU9GbEFKQAipFT p9OeLCFphFg0RfJpdmbc2RsvyvmB+K3BbXI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U +o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl 1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFjDCCA3SgAwIBAgINAgCOsgIzNmWLZM3bmzANBgkqhkiG9w0BAQsFADBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFENDCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKvAqqPCE27l0w9zC8dTPIE89bA+xTmDaG7y7VfQ4c+mOWhl UebUQpK0yv2r678RJExK0HWDjeq+nLIHN1Em5j6rARZixmyRSjhIR0KOQPGBMUld saztIIJ7O0g/82qj/vGDl//3t4tTqxiRhLQnTLXJdeB+2DhkdU6IIgx6wN7E5NcU H3Rcsejcqj8p5Sj19vBm6i1FhqLGymhMFroWVUGO3xtIH91dsgy4eFKcfKVLWK3o 2190Q0Lm/SiKmLbRJ5Au4y1euFJm2JM9eB84Fkqa3ivrXWUeVtye0CQdKvsY2Fka zvxtxvusLJzLWYHk55zcRAacDA2SeEtBbQfD1qsCAwEAAaOCAXYwggFyMA4GA1Ud DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUJeIYDrJXkZQq5dRdhpCD3lOzuJIwHwYD VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsME0G A1UdIARGMEQwCAYGZ4EMAQIBMDgGCisGAQQB1nkCBQMwKjAoBggrBgEFBQcCARYc aHR0cHM6Ly9wa2kuZ29vZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAgEA IVToy24jwXUr0rAPc924vuSVbKQuYw3nLflLfLh5AYWEeVl/Du18QAWUMdcJ6o/q FZbhXkBH0PNcw97thaf2BeoDYY9Ck/b+UGluhx06zd4EBf7H9P84nnrwpR+4GBDZ K+Xh3I0tqJy2rgOqNDflr5IMQ8ZTWA3yltakzSBKZ6XpF0PpqyCRvp/NCGv2KX2T uPCJvscp1/m2pVTtyBjYPRQ+QuCQGAJKjtN7R5DFrfTqMWvYgVlpCJBkwlu7+7KY 3cTIfzE7cmALskMKNLuDz+RzCcsYTsVaU7Vp3xL60OYhqFkuAOOxDZ6pHOj9+OJm YgPmOT4X3+7L51fXJyRH9KfLRP6nT31D5nmsGAOgZ26/8T9hsBW1uo9ju5fZLZXV VS5H0HyIBMEKyGMIPhFWrlt/hFS28N1zaKI0ZBGD3gYgDLbiDT9fGXstpk+Fmc4o lVlWPzXe81vdoEnFbr5M272HdgJWo+WhT9BYM0Ji+wdVmnRffXgloEoluTNcWzc4 1dFpgJu8fF3LG0gl2ibSYiCi9a6hvU0TppjJyIWXhkJTcMJlPrWx1VytEUGrX2l0 JDwRjW/656r0KVB02xHRKvm2ZKI03TglLIpmVCK3kBKkKNpBNkFt8rhafcCKOb9J x/9tpNFlQTl7B39rJlJWkR17QnZqVptFePFORoZmFzM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFjDCCA3SgAwIBAgINAgO8UKMnU/CRgCLt8TANBgkqhkiG9w0BAQsFADBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFQNTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBALOC8CSMvy2Hr7LZp676yrpE1ls+/rL3smUW3N4Q6E8tEFha KIaHoe5qs6DZdU9/oVIBi1WoSlsGSMg2EiWrifnyI1+dYGX5XNq+OuhcbX2c0IQY hTDNTpvsPNiz4ZbU88ULZduPsHTL9h7zePGslcXdc8MxiIGvdKpv/QzjBZXwxRBP ZWP6oK/GGD3Fod+XedcFibMwsHSuPZIQa4wVd90LBFf7gQPd6iI01eVWsvDEjUGx wwLbYuyA0P921IbkBBq2tgwrYnF92a/Z8V76wB7KoBlcVfCA0SoMB4aQnzXjKCtb 7yPIox2kozru/oPcgkwlsE3FUa2em9NbhMIaWukCAwEAAaOCAXYwggFyMA4GA1Ud DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU1fyeDd8eyt0Il5duK8VfxSv17LgwHwYD VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsME0G A1UdIARGMEQwOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAgEA bGMn7iPf5VJoTYFmkYXffWXlWzcxCCayB12avrHKAbmtv5139lEd15jFC0mhe6HX 02jlRA+LujbdQoJ30o3d9T/768gHmJPuWtC1Pd5LHC2MTex+jHv+TkD98LSzWQIQ UVzjwCv9twZIUX4JXj8P3Kf+l+d5xQ5EiXjFaVkpoJo6SDYpppSTVS24R7XplrWf B82mqz4yisCGg8XBQcifLzWODcAHeuGsyWW1y4qn3XHYYWU5hKwyPvd6NvFWn1ep QW1akKfbOup1gAxjC2l0bwdMFfM3KKUZpG719iDNY7J+xCsJdYna0Twuck82GqGe RNDNm6YjCD+XoaeeWqX3CZStXXZdKFbRGmZRUQd73j2wyO8weiQtvrizhvZL9/C1 T//Oxvn2PyonCA8JPiNax+NCLXo25D2YlmA5mOrR22Mq63gJsU4hs463zj6S8ZVc pDnQwCvIUxX10i+CzQZ0Z5mQdzcKly3FHB700FvpFePqAgnIE9cTcGW/+4ibWiW+ dwnhp2pOEXW5Hk3xABtqZnmOw27YbaIiom0F+yzy8VDloNHYnzV9/HCrWSoC8b6w 0/H4zRK5aiWQW+OFIOb12stAHBk0IANhd7p/SA9JCynr52Fkx2PRR+sc4e6URu85 c8zuTyuN3PtYp7NlIJmVuftVb9eWbpQ99HqSjmMd320= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDYjCCAumgAwIBAgIQDpoltJgUr83lkFY/75UkaDAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwODE4 MDAwMDAwWhcNMzAwODE3MjM1OTU5WjBKMQswCQYDVQQGEwJTRzEcMBoGA1UEChMT Q2VydENsb3VkIFB0ZS4gTHRkLjEdMBsGA1UEAxMUQ2VydENsb3VkIEVDQyBUTFMg Q0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASQfmimvw0mE+EXv2+E6tl80/+p iLnHZz/FfDkWF+7YjNZxJemUNpqPENUHB0DHi78sv1774TyMd5/OT5CYjAdvo4IB cDCCAWwwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0OBBYE FA6zrONuAPtxjhLQbrS01pqPjHUxMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8E CDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAE GzAZMA0GCysGAQQBsjEBAgJVMAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BBhj9o dHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlv bkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUFBzAChi5odHRw Oi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQUFBQ0EuY3J0MCUGCCsG AQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2cA MGQCMHfmuXJECeB2Lu5KMREt+SHR2In6YQWqBFR19JK0UTiprcew+E/nQhWlfyO4 Z/fnzgIwAnasdx/lP6AFYaTjgy/GwQQGEyGIFldYeiPDJ8vLIYOrG3YtMvBkCJLK 5IyzJh7C -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfjCCAwOgAwIBAgIRAJ7JDmFGaAFg9VNXYQqCA4YwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDgx ODAwMDAwMFoXDTMwMDgxNzIzNTk1OVowTTELMAkGA1UEBhMCU0cxHDAaBgNVBAoT E0NlcnRDbG91ZCBQdGUuIEx0ZC4xIDAeBgNVBAMTF0NlcnRDbG91ZCBFQ0MgRVYg VExTIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1pQVCJf5QjRlTsqaUINz MEr030mUn91UVBDdz09vxxcrpm1V0W/1nUlXzJLwRwWgVKqbX2/prxfaUUTiQwcA QKOCAYYwggGCMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2OaMB0GA1Ud DgQWBBR6zo6a5CxsVGx46z88cYhD4H73eDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwOAYD VR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5j b20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNv bS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEF BQcBAQRlMGMwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9V U0VSVHJ1c3RFQ0NBQUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVz ZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaQAwZgIxAJrwEhcANH9VTvdochJUGFkY 7ZlMpCHouISux8pUNAAPcZJA9JmHjhbRNsAIgGYJIgIxAMVYg1nGlk8KTQMHW7m0 zP2fFGWhWvan4q58EIeLCGxykppkUj7HW7Uorfx9eNWKsg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF6DCCA9CgAwIBAgIQZXHZuD2hrM0yoWbcJYWAxDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw ODE4MDAwMDAwWhcNMzAwODE3MjM1OTU5WjBNMQswCQYDVQQGEwJTRzEcMBoGA1UE ChMTQ2VydENsb3VkIFB0ZS4gTHRkLjEgMB4GA1UEAxMXQ2VydENsb3VkIFJTQSBF ViBUTFMgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDfxjTCHbpO 9LYyKjrhzqd7jdkMbtwPI6x6NPq4LJLm8vpkEu+bRtTENv/st5Nq0utXl0E+XXiY Xbx8sXnjJlS+v6JJHsgzHhbg98pZClF/JFD6cd8VDXHPWjrJg8EGibYlRfdPnLHC +E4mkC+4hluJcKTIe5/vzaWNb553EXk5wghvpjYlQ6e16NjKT8GTL4738i/Hgt6y +JFFKoI70Qz6JZsgCGcRgvUVUI/+WbYTTkSG0HKWujlbLkIr8fH52icLs6C+XA0C sdyvTAQUHUIFMiTlZ9mn15RD5BXdzdn02jlzue6SQFQM4k5ng9nLgZomwjFTI8aN 6WKz9A1YtipbAgMBAAGjggGGMIIBgjAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dib wJ3ysgNmyzAdBgNVHQ4EFgQUnbHHlQZa0CLaflngIayPVYGu1gowDgYDVR0PAQH/ BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIBFhdodHRw czovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0 eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVz ZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlo dHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAsthx9 jWF9WObf+BgbBW6iVdS9tcyEXWR72TlgoekiwHNvMZqNU87Ogtt9hwGdF8zGqpOX quIeLv+WIqscgUKMBMkWmOsBAzg2b8a7jjDLHA33SvPLSSeRqxvd1S/RbpyJQq1i /HIOW10iwd1UUzNcCfEaaOR33LO4X25LaYS9TqQKmFt2rOc19Y07D6Vz+VV9X6IW WpF2iQPLB3WXRQwbPWchrLbwQ9D9mBKktRkgMbav+lpEMy8nwiOfsn+yNvWZnatQ YrX7PYZ6yLjhofqk9ltzi0FfKAK7c8Y51MIceMIHgxee9NpTW5vb6ZgSA4brbqbE nXoiuaOtwmLtJQMd0MhWE2Z5gtxxIPcOKq1zydFvrLC4mVAK46cO9tEt+ZdC84ap 3UM3SJX6VAM7GaI43QoibqtGBzqcGKYISey9Lp7YLYe3Ns7V5jLurS5/4ft+tNYj bkg1ComgkTKdXIEajNn+4gmDR66lhD2Iwqlagy5Xr3F4d0yUFKxzESYNOVjtAkBG NdPLoVciABBOLJuqY/sLyinYxgC13q1x16USa6r91nflBQmU3aR8HqkUnjw0a4kL NTXzNAVlfEe/uzrh7kC1XpI+A3lvdAcqzJn2AM3tgLgqvqy0gyhZTLpxPZnbzAHh lyaht9NWx3t2Af6Uz+hJTQZGdQq+XuNM8xm7Ug== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0zCCA7ugAwIBAgIRAJrBCAXEkf9f72li/xI6BfkwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDgxODAwMDAwMFoXDTMwMDgxNzIzNTk1OVowTTELMAkGA1UEBhMCU0cxHDAaBgNV BAoTE0NlcnRDbG91ZCBQdGUuIEx0ZC4xIDAeBgNVBAMTF0NlcnRDbG91ZCBSU0Eg T1YgVExTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiPwsIstz EDS9Py1d5DPqAG/DhonCpyK+C9A53R/4c37BO00DG/I0y46mE6Pna5JpRQVv+xOb 8fuNIKETm3EVP4zBUubCPJb8Rw8DJsuIL0cfLqBEnbV7yjHxKzmEkVAHskTt7uhi U9yZZfTTVv6Yl+uuktKPPdOtnpAVcMHy/XqtwWCKNlkBht3pD8LZ6aXLxYokQvwW ZfZb4rNfGWgsKumP22LlwfP5NpKyrxtw9knMZNxSMFxjv8s7AFbh98Yj0hs6bqRb NtDzh7QGS6dOvO31tTbdwA2gTx9YsRScvlM9sun8nS7btVg8vTGDkb5uSuGOrOBh wPyTKg4HO9XxcQIDAQABo4IBcDCCAWwwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHY m8Cd8rIDZsswHQYDVR0OBBYEFNUmyuz2qmus6E5RPIoUiDVMpgizMA4GA1UdDwEB /wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgJVMAgGBmeBDAECAjBQ BgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRy dXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBj MDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0 UlNBQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3Qu Y29tMA0GCSqGSIb3DQEBDAUAA4ICAQAfbzMZtLliee3L+g2sIS6/8c485jAe5ydD mktJBp/ys8nhwbkuQCMWtooHaAExGCJAPNqVmMUtF27pKmJFZx1nuKFRmg24Ytvr dBQS772EbwVGVVMZyfKBtxMgNWXJTlr8GTVxVvLDdcFCs2DjoGQC+U5Vib/Ml4Ad UVA8b+bFL5dmOBO8ArHjD1qfJ45+kq3MDCjqGGuwa3F+alHBi85R0vaR2azXoUMs 8FPSkkE/VJHE/7JZs1HOhz7yVzAkBICYX05ZDh3EDoYSbcOS56w2AvZYKwKmGzis dWCFnjt/AMIEpwbBKqe6i3sIweQoX/hv4iANt0xrsH0Jya8ErjDB7RrQ3fXGMKA2 wHzRRYOcJqBaSZOrIheavVLWQDpECLCKgN63Hw6cp4Qfx5tRvF2McKXctzF2ThGl du80EW6cRJhFDJ3SkgwSGu2i337/nQSfHnsbRa7qIT9jMUSV5SohPMqc6eAw2/bi Wv6HhvvoWiyTj8QdwYoPRXZfHJ1YzeGWKTc2htZgd5Ks1h3AUKaHrWX1shFtcYme vMaAMujjoxt0/AFNsltRDBX88nXBgxgoLhQxSR94SF9XmdfMPwPORn2WS67VxspO bYZcpO0V9D02n30yBM/anotXdhzeggMDL7Y8Mx68PJjDJmdqfcFePnd/EOuEP/la DDF0cyPQ3w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzzCCA7egAwIBAgIQCoH0DEPa6Jmzl+SdkdkF6DANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw ODE4MDAwMDAwWhcNMzAwODE3MjM1OTU5WjBKMQswCQYDVQQGEwJTRzEcMBoGA1UE ChMTQ2VydENsb3VkIFB0ZS4gTHRkLjEdMBsGA1UEAxMUQ2VydENsb3VkIFJTQSBU TFMgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6YTyUcvcodqTp 9K2nDpy7MEEB1+b9OdRxHVuz5NL0oh/Uc5vY98oI7jsb/6Ps8m243jadrTMi/Bsn 9TSpoDvcGUOKKEormXPK3GNlrYfYdaKUOQXBQxntB6CSrbf0sjtJszxDR2pBnyjE udxIUwM841+8BiE7/vTZR7u1e+jaj6BvEeHnwAHoBemLQAwY6XOKfbWUkg9XKQA8 4urUl5OUQlER3pRdO6HSxSZJELW/wfPEd7HGN5KxzeX/V0wqjX0XuM+IuCDZyOuy 2JTne7qRIFkHqerANTgMTEHWBwBC0dsb7X2yK6tzahRJ2yfA7u+wqn4WsMtrN1sY xk3CeOvfAgMBAAGjggFwMIIBbDAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3y sgNmyzAdBgNVHQ4EFgQULiXODJvkyIMz7/ZPPeMqMx/ybqcwDgYDVR0PAQH/BAQD AgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAlUwCAYGZ4EMAQIBMFAGA1Ud HwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RS U0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYI KwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FB QUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w DQYJKoZIhvcNAQEMBQADggIBABd1TLX6r4fs2l0iLBTMtK4NuLX/8i5/UnvzenUN +9WrqOSVRX2GkjSDuzoVhOT25RGXRj2G9+gtdvuAl2VmfMmgYIh0xAjAxX79Qb6J zThroP5EwYtod+xmjBWYruVPcPDgDOome+SK6sKuhy8jmMqa/FiMK+L6lP8IDHnd 5Lpzoxds0XPxH0Zyn351hlFJyG4mxaIdS/AQHx7m7Hlq4QAI9h5SGu4an036d50z YtV0VEcDcOBVdXLcVESBn0uwKJuGyb2x0/aHbV6NuluyRJqaq9MUFIukNyakaHzh 9sLRvVuzt09DTTWrSWqMCwiMiv65e8VFu2eSLtWy96fgiR5IhfVzX/11mReE0jhf MK8d+nbkLgpOST+6mp8E6xZd6dlJxBDPtM3j0SQmKYMgSkzT9Sa9jUoK3MIvuVh1 FdcGm7TbMq5LE6JznYlFt2y+23RIiRd8EFEgtk6855GF2X3pfqUeFy7SCOAYCfzw 4sDRl0uYJ+yHbM5AfghAnaNihhtGHpyozFOZQWi15BV2ZRZ5S3Th6paCYMHx/I04 Ys0ApXpGyAXhsPp9I1b20r54OX4sJLzuPNvZ+RthFTlAeK++i1D17KGPy7yAdcT6 Rgod8isK+eLPZafcrlPHIJUXSCGbXR8xPezYAHDBNd/R7RsxcFxoSeEdZW6OCptN jWdS -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDZjCCAuygAwIBAgIQU4Vt3W/rXizP2fnWEZakFDAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwODE4 MDAwMDAwWhcNMzAwODE3MjM1OTU5WjBNMQswCQYDVQQGEwJTRzEcMBoGA1UEChMT Q2VydENsb3VkIFB0ZS4gTHRkLjEgMB4GA1UEAxMXQ2VydENsb3VkIEVDQyBPViBU TFMgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR8yrV151j2tW67GR6EnEtd KmJAxTxI90rD7GUjh6HuEsOZcrIr6KPoj63DKr4B2Arbk2PX+SaoWHFkn/zfkKaH o4IBcDCCAWwwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5owHQYDVR0O BBYEFHuHci5Ay7+7PmzSyteizqmJeDc1MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMB Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNV HSAEGzAZMA0GCysGAQQBsjEBAgJVMAgGBmeBDAECAjBQBgNVHR8ESTBHMEWgQ6BB hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNh dGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUFBzAChi5o dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQUFBQ0EuY3J0MCUG CCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMD A2gAMGUCMCUmcWOl7ljZw1DDG+6UaT3efv2hEli2njdKuu480nLEKN/oM7Dgs0RW EWO7JFfDDwIxAKUdVgBVOHik0qzuymjSn2M9jCLE6tSuQ4ov5EqmEB/tK5QW3Qpa u7FcWdjTaeFOGg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF1jCCA76gAwIBAgIRAN7Pp4Hxh4doloy3fLGv2+owDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MDgxODAwMDAwMFoXDTMwMDgxNzIzNTk1OVowWjELMAkGA1UEBhMCU0cxHDAaBgNV BAoTE0NlcnRDbG91ZCBQdGUuIEx0ZC4xLTArBgNVBAMTJENlcnRDbG91ZCBTZWN1 cmUgQ2xpZW50IGFuZCBFbWFpbCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAILVrYhkkEcRnuFHI8zz/Njvfg6nHN5X41GQX7lo1YBqa1hmYEaamUsh QkBu20UK3uXICEUN3xsSj6yxtFmc9J4+OKzcmXKlKTPsUnbw+45TEl5qJN32Uacl XE0OJ5/8zv1fSmMG+QDv6xIT/N4fb0b0zNcUnoZvcaLeg2Oc8ZjHQLbSt9COUnl1 pv2Tz5tLXmg1YduDiZpQKz+7YWiK8jV9AMRYTmVNLRS0sNL0A6xWGtjkxRt0I7Em 6kZybYGP6a/ZWNDRIcwfs3i4UW7ZBXPT1BmjGkS3ZvFV6Oicy7Vi+tnAm4jPudOu XKs/OsF/l4uqS4SCp7iPJB5YY3NPF4sCAwEAAaOCAWYwggFiMB8GA1UdIwQYMBaA FFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBQqy5xLH9NlxFFJ+prjsWpO OPB/bTAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUE FjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwGAYDVR0gBBEwDzANBgsrBgEEAbIxAQIC VTBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEE ZTBjMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRy dXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1 c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBb0aeillMHbXt0rXVbWkLn2y/kiFDl T6wg9aDWRg1GNj3F32k73dbJEUZFPVdAMJO1EiLESKqqB4kKqZwSCqm7AGuWv6DX 93YmOlotmXo9V/5yVVSHd//vgIUXpt60yu2WAWMWv7unlP28h5PJLvEZD7s3ujnc ruSaWwMk6ReKV50V5ppczSjrVMw+Uzv2CCMu7gUkg2wGW3XaUin81DLcccn+2x8V Wp6G3npQSlzjPEHOXXpR/taeAaB5WJNLWZWnHday8O2dofo4ZBG+tvz4gqyvKtpG SYaSNsPE1LU4SB5jIQiAL3MalrIRQA8m9qzEJaZ+7u9rea9rZPHMsxtPpmtNLjAt zDUWhGbz9JMeqIIfso/sFzgwBzH0PJDZnEFASvd+8CSQZ+T4zo+eRHOSX3ePQavk JBMqIPjOav6iTMoU+EJ0xXQOKNRVqmXhtkkSoUYznXmLKAzfw64fb24QXfi4wYXm 7kB7MbOczOHS0GScPAyKwyjZUgMfymAW9Q3QBw1dX4KbmsItAu2ifyKwzX/pJc1h k4sNKWsE3pW6j2rN0WTOh75fK/qmSMOjShvihPBrKoRBI2kJfwDSLBoHZXgjan/b Sl5usJ4ayF+CcPbY5eBE8LTGVl/O09P80Jpl3ZucCJiJfPZUru3KLJEwGcNauLsG wHUmeHkgp4gDgQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExjCCA66gAwIBAgIQeAMaoOu10y3VvjItu3VWmzANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA4MTkwMDAwMDBaFw0y OTAzMTgwMDAwMDBaME8xCzAJBgNVBAYTAkdCMRowGAYDVQQKDBFFcm5zdCAmIFlv dW5nIExMUDEkMCIGA1UEAxMbRVkgTExQIEdDQyBSMyBTTUlNRSBDQSAyMDIwMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArSRStF0TsXVBtuytWGle9DO0 ziMsVXkxhfShLVxHcAZQBOzUq/JLlq+u/S4bQyyWLDSUalQuoyNk3SDCiDjowVKw YsLxnEzr1QfBfJZpKwmtz60bNiGQ1xjg387VPCMpZiZqKmjkrXpOdEYi9zlk7k0s oSSK63/ZspS60egiUBQLyqasyv6opqgHX9akpsWYykJtJD/zZxPhhTvW72EwAkoE lC2Wg9juhChQz9eI5qGOuyMvw+rX8EPV/42sBjF2bvR0bijIwjyLQaDfru+6GLkM hDW0OIawmKe1KMckDQGoySQxE2iXBCoS3j6RZircYvB4Sy1MuQvkZjypZMJqQQID AQABo4IBnzCCAZswDgYDVR0PAQH/BAQDAgGGMDMGA1UdJQQsMCoGCCsGAQUFBwMC BggrBgEFBQcDBAYJKwYBBAGCNxUFBgkrBgEEAYI3FQYwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHQ4EFgQUV2K9aJRpNxwG7NM+jNC39ygr24swHwYDVR0jBBgwFoAU j/BLf6guRSSuTVD6Y5qL3uLdG7wwegYIKwYBBQUHAQEEbjBsMC0GCCsGAQUFBzAB hiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKG L2h0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0 MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9v dC1yMy5jcmwwTAYDVR0gBEUwQzBBBgkrBgEEAaAyASgwNDAyBggrBgEFBQcCARYm aHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcN AQELBQADggEBADfGWtSLuHua7cMATPJqHFnoJmeErQDwveRVxspXN8ini+k9K1t6 FEA2Fvzl7AK54dHfaF8WrFhO5z9N3WPVGiiN3sLlKVKcLbYJN8gEhMuHMYdJzK6a G+DwIKVDJf+iLqj0iL/+1d32sHeS8thip+cD9dbF/xAz7Vs84z2C9Z6zas5kqOYq UFwxi4jzeRiHuCMRbpNJwba2GVO4FjHKLS+uHXu/+Ztr1RVAWJvffBi6ks2cW6Up IE5pKR6ZRT6MJOrjEn5XU5O9tosDTRBF0vH1SRK3NnF0kEFt9ZSnbpEcWmvvAXz1 6ajl2e82O4oVsjkM2rcS0eRGaKR3O8i9HGU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGxzCCBK+gAwIBAgIQeAMalP7ZKBZ89k2M+9DgPzANBgkqhkiG9w0BAQwFADBX MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEtMCsGA1UE AxMkR2xvYmFsU2lnbiBDQSBmb3IgQUFUTCAtIFNIQTM4NCAtIEc0MB4XDTIwMDgx OTAwMDAwMFoXDTMwMDgxOTAwMDAwMFowTDELMAkGA1UEBhMCVVMxFTATBgNVBAoT DEFiYlZpZSwgSW5jLjEmMCQGA1UEAxMdQWJiVmllIEF0bGFzIFI2IEFBVEwgSUNB IDIwMjAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCxIWHFMrBgfPnr Z4t/PAmzXXqGGUjBANdoh09kL3SRvZXPQ7XmepY9acff1oPYDTDXyxjKFh0auOvf pXGTytem9fB6eWg4AuCdvn/NzNkvlJkQVRltJkbPcirWDKvczVvf0b/CJJNBV/4g hkMcvDgL/JBjl41JIuHs/bH0h0zbtXrWKchVgcXRSOEnCjRSv5/9hGDhJ1NP3RK+ aN9xWAR+z7JlMxIQxVTvtIMVs0A/oM7ubOyJHBE/S+fcu5dbrEHfek3CXRwgjmPA I/k6HK8csVMk88GIWwAZXaOT3pRWYCd9xXL6SoKYT+eplV9p+QBTBQpZF0W6a2gh wuG4biE+dnzatPH/6Qv5Wuz+vEZkjUJVSXXxw+lYG1ZGbZ1PAk60Xp1l9Pv2FTel N5npoxBzFJtwLEQHk4qyIkejIel8A9iAAeIDKUEfMpfog/ivDKK4jCw+xImrS5Ow PjAIMYTmJA5ynKCg2dQhHxhOgxoMdImGRKlau8pnzF0HLyNpnonxATXjpHG/Vq/e 0Wg8wkO8Eo4kGZSAYhlGDtUwjbYjL+F+MeW69VCsHkdHywGpUdJffzah3MPsU2tu tRE3+lxuK+wDZFU1RvoJILPq91ucsBN4aPeOTpksmUvzl5k29kX6py/Bxj3/JDRL 8C0IM8EXDd3Yesqh3obonnlUGHRcwQIDAQABo4IBmDCCAZQwDgYDVR0PAQH/BAQD AgGGMBQGA1UdJQQNMAsGCSqGSIb3LwEBBTASBgNVHRMBAf8ECDAGAQH/AgEAMB0G A1UdDgQWBBTJ+ecxI+MBoaNo3IEzCjT4kwFpZDAfBgNVHSMEGDAWgBSJ73Vxel9H G5cj3JBKy//AJjYI1TCBiAYIKwYBBQUHAQEEfDB6MDYGCCsGAQUFBzABhipodHRw Oi8vb2NzcC5nbG9iYWxzaWduLmNvbS9jYS9nc2FhdGxzaGEyZzQwQAYIKwYBBQUH MAKGNGh0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYWF0bHNo YTJnNC5jcnQwPgYDVR0fBDcwNTAzoDGgL4YtaHR0cDovL2NybC5nbG9iYWxzaWdu LmNvbS9jYS9nc2FhdGxzaGEyZzQuY3JsME0GA1UdIARGMEQwQgYKKwYBBAGgMgEo HjA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBv c2l0b3J5LzANBgkqhkiG9w0BAQwFAAOCAgEAHgMQYSgAZ8Y4ZzxTuu1AeLip6RXU 2fbXCQMOkZuMy6wlBkyIqxFjboaBaalCsSc8Om2uvehl1RjOqHMUwfix53a7oRz4 8mCFnXp4DsOzW5R6ERigNdFLuXJYery7oWP2ZfZVrU4RoG3X40eew+3MM6QgqJgC +HmDxtLEkU7cLCKGTeSI4+wL7cma0gjVGKSOh0AYC3S0G1TzsrOORrfQSQnNuE7q eRFl3IT7UyYpTn7OKCYrkSHWTtQ+xEK8DboCCpmwznzUdRZq0Pumj5uUBTO29nZu 6e0DoE/VGv1qHEORmDHhgiICU/7EQs8Y3+m4/japrdDyP6QSzc/j5oxLfuxWaSSb +Va37X0gxeLUB1QYy60Ivr41/JRHhnYR511MSVsQIEzJe8RYV9x/XXc1jmYJ9oUR 13eqri39cS5+LllSlINdeMrWM69ggs7KZEGO13T0wqHJjxDXQxYdDD3md/bw4efw ijVoYZ/WfLt7YwdHw7mGdfkwUMp+ZCpPIf6EQy1gAw8qu0pIOx4UwFvtBYrIBSZZ t9X5RJ7xR68B3apcGVKfMxNkk2Fs6XpfmaSE6B55LBmniRExizS990uiWPi7inqI yHREhPLruMlrvcVf0JbT0fkb17WhQgSA6yyICuSvOuJlbp5xIo9lVa8pGU4UvZEU VD1GWg8pHLG0EN4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDajCCAvCgAwIBAgIQeAMapQq7bryFyqrojWQvYDAKBggqhkjOPQQDAzBQMSQw IgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjUxEzARBgNVBAoTCkds b2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMjAwODE5MDAwMDAwWhcN MzAwODE5MDAwMDAwWjBYMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2ln biBudi1zYTEuMCwGA1UEAxMlR2xvYmFsU2lnbiBBdGxhcyBFQ0NSNSBEViBUTFMg Q0EgMjAyMDB2MBAGByqGSM49AgEGBSuBBAAiA2IABJk4+mZIkW1K/u9RhYzrZUwu PXKbE/GVfh5MUfipeVqutoArFF7lQtNVyb5bQiLKmSy0hjp8gUydFTeptXaWhNYU /ALTyvKM2FWNTBTdQDOYnGY+ii5oNYEFQ7JzuNUHg6OCAYUwggGBMA4GA1UdDwEB /wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/ BAgwBgEB/wIBADAdBgNVHQ4EFgQUQNhmyJ7rexKy6jBIM0OJIOEXsBMwHwYDVR0j BBgwFoAUPeYpSJvqB8ohREom3m7e0oPQn1kwewYIKwYBBQUHAQEEbzBtMC4GCCsG AQUFBzABhiJodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHI1MDsGCCsG AQUFBzAChi9odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9yb290 LXI1LmNydDA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24u Y29tL3Jvb3QtcjUuY3JsMEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIB FiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAKBggqhkjO PQQDAwNoADBlAjABqlr39Lb2vqOuFA8xzFpdHA1RmZhQzw7F/4xEkzofLYVFc/HD OCxQhc0mojFKbToCMQDPptflhZ4Ah2IeDY0B8wZR72797QgqNcveYkreiADibVtK mZiWcDioi0FZvnHeBdI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvzCCA6egAwIBAgIQeAMao0/80Rin2RzNXuxThDANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA4MTkwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFQxCzAJBgNVBAYTAlVTMRkwFwYDVQQKExBDcm93ZFN0cmlr ZSBJbmMuMSowKAYDVQQDEyFDcm93ZFN0cmlrZSBHQ0MgUjMgVExTIE9WIENBIDIw MjAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzmwrOeDyjzgMzG5pc DyFTbM3rYIbsNBkFBTp8zrAJZGeNnqEzQEWVCwQmuuY4NUyjjbJfVPl1ZxAy84Ap dS8yc55V2hfUpoZjeokMC+hSoji0dJm5sAQDiMHyTKIqZlNhU8hVrF+wglLm5Vkj 3Pcc0MAYQDC1BwhXIA5s1tm8utYekKqcJjpCjvbdyrCv/CA6TwTOSKddqMIYQutX qvlNLDL/BASfaYBxmVt/x7taCl+wxSwt3miQYWC42EfjXfuSXBe8gD+59jwChM73 /0iknZPbi212SPj0hq1m5BK5lBpS35OzVD8QdxBvQ7X2S0icCN5zEXFtBwu1aqeu QrpfAgMBAAGjggGTMIIBjzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFDRG WsSWhGsR1OcJMK8ByqadP32WMB8GA1UdIwQYMBaAFI/wS3+oLkUkrk1Q+mOai97i 3Ru8MHoGCCsGAQUFBwEBBG4wbDAtBggrBgEFBQcwAYYhaHR0cDovL29jc3AuZ2xv YmFsc2lnbi5jb20vcm9vdHIzMDsGCCsGAQUFBzAChi9odHRwOi8vc2VjdXJlLmds b2JhbHNpZ24uY29tL2NhY2VydC9yb290LXIzLmNydDA2BgNVHR8ELzAtMCugKaAn hiVodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jvb3QtcjMuY3JsMFYGA1UdIARP ME0wCAYGZ4EMAQICMEEGCSsGAQQBoDIBFDA0MDIGCCsGAQUFBwIBFiZodHRwczov L3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOC AQEASGRtet9bF7dXw406NrUZhXL3lky7JmYddzw1RHVbDVjVTSqWEs86Y21lEm2t I96RuvxeNHfd+/EkzK5WS+F5eH4UNPmwwjdgpumte8Xf6zbW7hWVQ6yjuS+GbNI+ Xm90WmzbVDe2PaCtzpszIaaJo3fOtm7M1aLJAhNnkDm2TWBSkOyhWIW6LhZgJamN hzXW6sHHTmzT9xTK3u9zxkVuK9fCc9APDMnscIDcxDfFnq4w74Pn8wzj+Kvbpe0+ ORcslO4rjST0Vn3o+LO/lSCvLuowzkmpxG5wjSUmZPwEzrPEW+CNC1qIWV+cRPK3 Mh2y+WTQyPxrFHO2q+VuBxpK8g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFAjCCA+qgAwIBAgIQeAMam0ZVkCw8TMHuMnEpEDANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA4MTkwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMIGKMQswCQYDVQQGEwJNWDE1MDMGA1UECgwsUXXDoWxpdGFz IENvbXBhw7HDrWEgZGUgU2VndXJvcyBTLkEuIGRlIEMuVi4xRDBCBgNVBAMMO1F1 w6FsaXRhcyBDb21wYcOxw61hIGRlIFNlZ3Vyb3MgUy5BLiBkZSBDLlYuIEdDQyBS MyBDQSAyMDIwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoPPxd8l8 CyRv+3UYSKo3ugherNZhB4E3JNdxWcVvY3pqhspL8nZQAGApnhtRk/jYw4Xol26g 7o0TJfaoX6vpmWC3TCaq2dgE3qCrIa6UKHNsxPGveuodYNrDIiPakvB2gUqj0BfA 2B+BzTpj/IxnpXAGvM0V8FuookNt/rZpR/Bn1m6bKAAfkfqy4Cl+enhBF8SYlVSN 6mNKEya4AOO6LXQTAFo6/Ae4jKRDUpSgfkBV4Sffg7fTEW3JaHXSIQ+u9uecQSeu UzYf3lNhA8P17xPaQJU320tXHlaBZGrKqWr+oQr5nSBVQX9UZUg0PDXL/KC2xVfA /XWdGwSz8KneVQIDAQABo4IBnzCCAZswDgYDVR0PAQH/BAQDAgGGMDMGA1UdJQQs MCoGCCsGAQUFBwMCBggrBgEFBQcDBAYJKwYBBAGCNxUFBgkrBgEEAYI3FQYwEgYD VR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUteYTA7fp6bpPJvofCbzFnI+0sfYw HwYDVR0jBBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7wwegYIKwYBBQUHAQEEbjBs MC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjMw OwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0 L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFs c2lnbi5jb20vcm9vdC1yMy5jcmwwTAYDVR0gBEUwQzBBBgkrBgEEAaAyASgwNDAy BggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9y eS8wDQYJKoZIhvcNAQELBQADggEBACZP4x3UIAa3R5KUMejfH9JeC8HcODVKYo4J buzB2NoLvTGCwcYZ7MAwgX+BO3NNNLDVObsdImdtid3lbkR52hQbf0uOBtqOkSTN TFszJQrjjSk9FWCkiueyDDI+Z+PiDEhATf/Vd97dQFFk52zY1aUAIHzIr/h4m/vV Nc4mdkdSRtuI7EtDVpWtMBf3QA2RQJpzdbHIV4ncFLRJmF/BzNXJtaM/5M9U7ClF SgcVL9KIZZXTo532/oqutZs+TkYl9/gbjT6JVUmJKQH+bI6LJ/neiUc+YBf0F3kb RZgsPy9Ywhl5qdXRxgZEBaTPSXJ82qrq4CkZujPyrry/+gaNEms= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExzCCA6+gAwIBAgIQeAMamkAzrmyfmYCZ9Tf2VjANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA4MTkwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9DUkIgR3JvdXAs IEluYy4xJzAlBgNVBAMTHkNSQiBHcm91cCBHQ0MgUjMgU01JTUUgQ0EgMjAyMDCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANvTrTlQ7U1WE6LVnrhxd2EO KwVlQQZjfT2l/tc5QnYl8QgvC4KlR3lok32MmD8gGUUNEdN+ZeZOkVYaH6vRYPPt lIARSiT93OXttC1neITOV3mzuJzAT1MOJYNYTzZooAXVuv+ah69qg09TRHKh1HW6 kPnLkWZV+GIx9bUMtJiGUfjH9Qq5MxALc5j6kJYrWhHvlD0ELxn/zzgZ7JyblhXW x/z9s1XV8lWBzCL8V3sGE7kPfvdmKs1MS/LEF8Lkur7NPDBsxLWS+KMTZsVOGqk5 6DwbvZ3+6Ctnp9+155tW1+namC+DJ3W9yNSzTAwVLiNFSP/ZJaqlBHO7U1i+NTMC AwEAAaOCAZ8wggGbMA4GA1UdDwEB/wQEAwIBhjAzBgNVHSUELDAqBggrBgEFBQcD AgYIKwYBBQUHAwQGCSsGAQQBgjcVBQYJKwYBBAGCNxUGMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFMklSeKU9mnaj1ILes75tnjVygRrMB8GA1UdIwQYMBaA FI/wS3+oLkUkrk1Q+mOai97i3Ru8MHoGCCsGAQUFBwEBBG4wbDAtBggrBgEFBQcw AYYhaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIzMDsGCCsGAQUFBzAC hi9odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9yb290LXIzLmNy dDA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jv b3QtcjMuY3JsMEwGA1UdIARFMEMwQQYJKwYBBAGgMgEoMDQwMgYIKwYBBQUHAgEW Jmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3 DQEBCwUAA4IBAQBh+QRFc1B5TfSLrM+hzowWmbD20aUNGqdqNF8kkCPZudSANHyY YJ6cljxNGn8WrWUmvXIfpT2vRVimuX6NbpoSR6xpMqE3Zd2iy4A25ISb478yhOXP wD0dEfjwkIxvLYdzvr5LpJdooY/2Ww6XYKkpMleQ9pECmXdOFJMk2Ff/w1Jt9aXQ /jLeZFTdcQAT0iYBnLFhY7KFc+9bUuNAfC4ctFeLictJjsEjsscA3DiUQmuemFcY LyA/5LWmjeJ6l8Rr1utM1nq3idH0BIelvPVvyYx5gUoeZCjovhYMhn7Xr0f6u1+c T2Dm4zcG653Hcn4DafzOpuvNP873b9pwXOKg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEzTCCA7WgAwIBAgIQeAMaoyuD6cHweXqsrLyBNTANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA4MTkwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFYxCzAJBgNVBAYTAkdCMR8wHQYDVQQKExZIeXBlcmlvbiBT ZXJ2aWNlcyBMdGQuMSYwJAYDVQQDEx1IeXBlcmlvbiBHQ0MgUjMgU01JTUUgQ0Eg MjAyMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0ON2bZOY7AEIH/ z0p/BbVUllkvNXLNv1oqRzARtu1WGhOfqi9yGp7wKulBNtC9NQvqIK8ghno/BAwD VrZ4tT90AwqkB604TbNwsFjAjMC8MNu4U0TIWR/tXgkpMXIagyaqSr5QwVK70cp+ U21jX6rcZMSaw1Ir/JiEuipuqOAjJ2NJjQeS8HmWtudwVlyb+IOKIIVrRdzRYwJL E99TR9tjwlOL65RoUrE4AOBHN4REWUqe5sZXvv4vyMfLl2GtBhnpVKA5Vd0mz3TT xBAiPk7tlNxm99Q5CzRIsWRVWSkunsva+T9qk4X6aYl6gtOXGaVSJbaD7lNAbUp3 ehbFzmsCAwEAAaOCAZ8wggGbMA4GA1UdDwEB/wQEAwIBhjAzBgNVHSUELDAqBggr BgEFBQcDAgYIKwYBBQUHAwQGCSsGAQQBgjcVBQYJKwYBBAGCNxUGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0OBBYEFI+VCR7L0yMuN5WHM2mH1mtMOLVeMB8GA1Ud IwQYMBaAFI/wS3+oLkUkrk1Q+mOai97i3Ru8MHoGCCsGAQUFBwEBBG4wbDAtBggr BgEFBQcwAYYhaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIzMDsGCCsG AQUFBzAChi9odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9yb290 LXIzLmNydDA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24u Y29tL3Jvb3QtcjMuY3JsMEwGA1UdIARFMEMwQQYJKwYBBAGgMgEoMDQwMgYIKwYB BQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0G CSqGSIb3DQEBCwUAA4IBAQA5BOjPldyEcDf8xqWtz7hZEPMF3r9c7xIAzaM2xzls 4UMGEeD3mFD1MGL/yyHtJzQV7hRideBK/+hAsKyXwIrxTAX+/Qzz40pnWkXwgIzg RlwTaS5u+/hCpXtTNhxChZ3SSyWnNwHHltXttPBT1lDlAouG0A7yzXCUahB3UGr1 5zeGNNw1CftxJdYy570763STg5oGqnFxKuLrw5mvF6FIxkwyRIOTB3sk+hE8uw5e yCOpsSkQehsEceuu1RZ2ApKD8xK/RmNsns/kX6Kt2rWYqBzxE5J5kvi6JSjRkJTr ZRNi2eJzg59s3hC9PxFpyfygyhehh8MVmVYGiapZGHC/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE6DCCA9CgAwIBAgIQeAMana3bxAYDWC8GMaR5azANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA4MTkwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMHExCzAJBgNVBAYTAlVTMScwJQYDVQQKEx5BY2NlbnR1cmUg RmVkZXJhbCBTZXJ2aWNlcyBMTEMxOTA3BgNVBAMTMEFjY2VudHVyZSBGZWRlcmFs IFNlcnZpY2VzIEdDQyBSMyBHbG9iYWwgQ0EgMjAyMDCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBALOwpdavYjAymz3OyGjYFjLF+NlpvBmRblQJ213cTntE whpIhBB7e8SBUQ8MWgoxQOwTbFWP7qeeLFogy0YTdIIhGe7ArHhVirN1c90Fu+E0 dYENWKdWWhuipQ79FzjWQMe1Y7zUeYotTRyNy2A829ZzAhpL9S1nsT3TqeDPWDC5 rjZvNRwi6c894VwnHZ5nVOtqpVkHU34efxFy7zVIf2z5AvYWWKCHclfzkbNMrzPY Kf9OGoIjv2jkTmv/jamm5eEdSLeOOqnjOiYhuIAi3vbqp/QoiB4opG0kqnN4lbjn 7Uw5wXbyxNRUEx+DTDuj+UoLd2Ov2x8OQZ2f80ZYmQUCAwEAAaOCAZ8wggGbMA4G A1UdDwEB/wQEAwIBhjAzBgNVHSUELDAqBggrBgEFBQcDAgYIKwYBBQUHAwQGCSsG AQQBgjcVBQYJKwYBBAGCNxUGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE FJrwxX1guvQPVoKicPRAW8u09T+rMB8GA1UdIwQYMBaAFI/wS3+oLkUkrk1Q+mOa i97i3Ru8MHoGCCsGAQUFBwEBBG4wbDAtBggrBgEFBQcwAYYhaHR0cDovL29jc3Au Z2xvYmFsc2lnbi5jb20vcm9vdHIzMDsGCCsGAQUFBzAChi9odHRwOi8vc2VjdXJl Lmdsb2JhbHNpZ24uY29tL2NhY2VydC9yb290LXIzLmNydDA2BgNVHR8ELzAtMCug KaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jvb3QtcjMuY3JsMEwGA1Ud IARFMEMwQQYJKwYBBAGgMgEoMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmds b2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQBmGVQP 58vdVnpwviN5BeTuMPjalbPyT1xmMHQBpGgmRoW0Byc44qrV4lEBrcxk07Le6ZRm xbNZMd6BQSKOH+xSWvsRzEh2yPMzBxlofqjCwHYebAmLY3GWr6aInkjcT73OZd9/ fwtK9c43eGhVE9vM2NbdiMk2fKm91NzboNeV3Z/fbeshUeqTaw0GZongw90dcSI0 xLvUL/HHbQZQG+3s6pEZKZMU/zlV40C7q3vmZMaQz/ULf7AyzDC42JkjR70daMoh a8ASxA00wkUR4sIhYTYMEOBY8Hj4et7KaylWKneBqJGG6NfCNCwJgdsuyVIHzFAk hFX6XA0C/2JcB8st -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE4zCCA8ugAwIBAgIQeAMaoK5k/3VXqdvkqsuh+DANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA4MTkwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMGwxCzAJBgNVBAYTAkRFMSMwIQYDVQQKExpHUk9CLVdFUktF IEdtYkggdW5kIENvLiBLRzE4MDYGA1UEAxMvR1JPQi1XRVJLRSBHbWJIIHVuZCBD by4gS0cgR0NDIFIzIFNNSU1FIENBIDIwMjAwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCV3/Jp9K05DK7k3b07yUXEImDNzd+i8P/V4RN42Fxxk4BT/qAi QnrLZIF3guGQB2xsdOAcS8hx7LBpV0N7l6EaCrmefafZhXafL8sTqGRKh/Js/wgs hftl4Dbd2yPFK5XskJ87t9pwk+cpkp8KQe/pTox9//qg2JrHnfYRnLdQGCPnKn7O TPVgfcgj5HFP9c6whmm9NkvrDiE8aJyyv45a0rOkivcLPpkf9ehHfRBVi7PSBw0X z3FU7IUciaL+UbkNMMqTa5Fj4nY9f0ozJ9cn9yzDae4+dF71S/9rxLjCRme04UBE MIb4mOQOM/XFnR9aHbYyi5iE6n6z7pyZocizAgMBAAGjggGfMIIBmzAOBgNVHQ8B Af8EBAMCAYYwMwYDVR0lBCwwKgYIKwYBBQUHAwIGCCsGAQUFBwMEBgkrBgEEAYI3 FQUGCSsGAQQBgjcVBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRaGKJ8 RX491diPptZQDOgsZtzpQjAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpjmove4t0b vDB6BggrBgEFBQcBAQRuMGwwLQYIKwYBBQUHMAGGIWh0dHA6Ly9vY3NwLmdsb2Jh bHNpZ24uY29tL3Jvb3RyMzA7BggrBgEFBQcwAoYvaHR0cDovL3NlY3VyZS5nbG9i YWxzaWduLmNvbS9jYWNlcnQvcm9vdC1yMy5jcnQwNgYDVR0fBC8wLTAroCmgJ4Yl aHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBMBgNVHSAERTBD MEEGCSsGAQQBoDIBKDA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxz aWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEADao2+TIcMoFe skk9rfsGyQVC77MPzZbRxUjMBGQiErAA8nbE8Ca0AtT04+tQ64bmeYqwWFSjyz6d Q11UFYQojE1E+Xx0HfyLtWj1gTQ3nB3DNk1r1OVCOWxRBcumL//MdJjkLQcc9rg6 V67lRqxI3vpNmYT6KXCLcVToFt7kjXzfXUTOwlQlWLVjl0lN8a5skUFXHn56TVWC y2HaYnReM1iaCqs7vcA4IOPh1qxqnUVXn1sWKcoaGpJ0PxqcF7xNVXai9fIieFoa 1iDA/6trxYNkqOrrxm7rw2e5yVnZ8blIncII2Cw3h3NcaM6JmLpzTdA9ClgjS0iQ V8ND8NXNGw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEzDCCA7SgAwIBAgIQeAMamolAXWpzEV8D8xda7DANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA4MTkwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFUxCzAJBgNVBAYTAlVTMRowGAYDVQQKExFEZXhLbyBHbG9i YWwgSW5jLjEqMCgGA1UEAxMhRGV4S28gR2xvYmFsIEdDQyBSMyBTTUlNRSBDQSAy MDIwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3LflneX8SBzuy5+e NXko+VrWcPnRWhbb5V4EJ4EWFQc12NYFYz0pKaRCVExWIirvrWlki+9zCYDp+tNZ F9o+wWTK1ahFJ/1oHWa2fIGrje/K31HJf0qobAE4NuMj3UZp2/Jl8Hwavd8nHgr3 jXYYsO9OVfsD3QD5MCDkHbMFCZe3D8mPx+NJNNdlZjjlmogmcq8JZttc4l0GXsJ4 1DqxtH6WEVgT/HA04BZKpTuwz7yxyp2PeTtcWMKPNnOWEnY7aQd8/sWOVlHjS2Oi Aeu/tg+c3xgK6KGk9DLGxF6JwVFurq2AnJ0qZ1uG1l81qRm6nAbA2wK1kDkojKID T7qoqQIDAQABo4IBnzCCAZswDgYDVR0PAQH/BAQDAgGGMDMGA1UdJQQsMCoGCCsG AQUFBwMCBggrBgEFBQcDBAYJKwYBBAGCNxUFBgkrBgEEAYI3FQYwEgYDVR0TAQH/ BAgwBgEB/wIBADAdBgNVHQ4EFgQUPe9B8J3l16rrtSI0O954zXCAgA0wHwYDVR0j BBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7wwegYIKwYBBQUHAQEEbjBsMC0GCCsG AQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYB BQUHMAKGL2h0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3Qt cjMuY3J0MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5j b20vcm9vdC1yMy5jcmwwTAYDVR0gBEUwQzBBBgkrBgEEAaAyASgwNDAyBggrBgEF BQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJ KoZIhvcNAQELBQADggEBAHx6cMhuXqfIoyunzsuyjauZKUd39WyZfMcuS/uu67WP oKVgkbRO9l2p21G8iN/yFItsd5OCLfbs1SnYQ5N2Umlv/kuzeFsSRruFqD8gAvWa lnYIOsJ8uFMZEmtUkmK3cAA2hYh6imddvjPeyTrAUYRrrEFSxEWEkZcatN0dc1fc bmkZeK2VkUsuDuFaJe9bj4YCaAkQTM1GFJsK8oL4rpn1JvL15r9ScCn8cZVvZj52 gvElFQ5bkQ8fXKdqVpxzFWy7ELdh8vfsSJMN8lKIWIP1+fmjGpqWkHeBCipcsN1l He2xheXgwwMgaAbhtgxa3YY07+8Ac63Tr4ccNMRWrbw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEyzCCA7OgAwIBAgIQeAManMpO0yK0Jr0oTnz4mjANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA4MTkwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFQxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRMaW5RdWVzdCBD b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTGluUXVlc3QgR0NDIFIzIFNNSU1FIENBIDIw MjAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVqObgQOQ0WGs2H5pG 5yUpEZkLMkifZrZOvDBj+LgwJnRw1YcK/iYKw6W7L5MtOZfWBCurM5yv/ILtIZ8Y eMZauVu6Qy5RiHXMh9BpGu0+4tmDng/nrt8vMyLjKYXWRzHmO+dN1xHrmBGW5mXD j7crzhkYzgfiXWeA6HEnJMvfIB6I8NJlaONGPQUO37brATvSHZ5YsTu94KN7fuiS r1OkD2qveQpOmEZ4+yaXDyeftD/tc0TI/WqFwxFYXEpVrolOuVPU0V3xLPb3nUx5 DdJWFg7TB90gzHchxj7JR19GCATsNqkbj8PMNqUssoV5btmV9MiLuIvWie2iwcWC EE/jAgMBAAGjggGfMIIBmzAOBgNVHQ8BAf8EBAMCAYYwMwYDVR0lBCwwKgYIKwYB BQUHAwIGCCsGAQUFBwMEBgkrBgEEAYI3FQUGCSsGAQQBgjcVBjASBgNVHRMBAf8E CDAGAQH/AgEAMB0GA1UdDgQWBBTT6yEhmsm+0opNURq6jwM1mR2uSTAfBgNVHSME GDAWgBSP8Et/qC5FJK5NUPpjmove4t0bvDB6BggrBgEFBQcBAQRuMGwwLQYIKwYB BQUHMAGGIWh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29tL3Jvb3RyMzA7BggrBgEF BQcwAoYvaHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQvcm9vdC1y My5jcnQwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNv bS9yb290LXIzLmNybDBMBgNVHSAERTBDMEEGCSsGAQQBoDIBKDA0MDIGCCsGAQUF BwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkq hkiG9w0BAQsFAAOCAQEAbppZtuVMfQXPp11rPj7JmnP1LeItTIdNI3kpJZ+90vDn elT2HmG3E9plQ171Vptl3jPwdVfP+ii7nl18ktWNs9b1F7c7hsw234xr5aBOAkmc 3Q7dnT0rzY6PlL0VEYN0TiHFHLlWBGvKo19OY1+jbDmLTScS3VtzRPKIQj//46dU /Ay9i2d7Y3wWu+vVbUSbwPuKswxAad7scix/2fpAoGLfOHA4b6jWVX4srz72GAQ8 yK5vTfIS07OSstl6Jdxhc/XHDp5SIIybi2Dfb65ylgFBKcTliznqUnzKFS2VGhZa /WjhxMLgJWrk51briY/qSUPe5VLVyucz4Uhtd6Tv0g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE4TCCA8mgAwIBAgIQeAManmHI3Fl9YHmRyej4lTANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA4MTkwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMGoxCzAJBgNVBAYTAkJSMTcwNQYDVQQKEy5DT01QQU5ISUEg QlJBU0lMRUlSQSBERSBNRVRBTFVSR0lBIEUgTUlORVJBQ0FPMSIwIAYDVQQDExlD Qk1NIEdDQyBSMyBTTUlNRSBDQSAyMDIwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAooAdMIJKgM0zid2ryYerPNXDTTudkIU9rhGvJdToO4xo2co2HMfQ bMoeXL5rUHMSvE7TBHYy7MP6zI+hjSFAFzHh0orGhVbawUhEReL3j6g2QxXddJ5Q ryz2iFQKSMneXcT0WyBjg448Nz/PB0LsD1un+vwXMSsFwlbD05M9OJLH+lemdd53 TEPLGAjY5WEZ+ZkV2aYALuop39doqdxXQ7Zv4zWdYYxodrPGGS2ntl8ATbT23rL0 zGjMUXsz5tyieVbZeEy/rgaEPZbwdSpP1oAwplsfNxRE0WyuLLF2pKUED5jRpeyD JK2+98aKR/91OzcY+LHOKpmNe3SchrpoowIDAQABo4IBnzCCAZswDgYDVR0PAQH/ BAQDAgGGMDMGA1UdJQQsMCoGCCsGAQUFBwMCBggrBgEFBQcDBAYJKwYBBAGCNxUF BgkrBgEEAYI3FQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUR0n8nXzc OukuGEka8F+EAcb4WHIwHwYDVR0jBBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7ww egYIKwYBBQUHAQEEbjBsMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxz aWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1cmUuZ2xvYmFs c2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0wK6ApoCeGJWh0 dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwTAYDVR0gBEUwQzBB BgkrBgEEAaAyASgwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2ln bi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBABEGA1jHY4pm1L4X ns61voRjoWERjBok6S5FhOLOqAOJDS4nKoZ5K5WmYrq5H+2L9lT0qiEAn9ODeK0b ydtN5WsLMIRLRNCohnjcYH+2X39AQ761pUEphAz0/Hc7p6ya0wRNh/ISZh1FBxvL yGymyQPm2ZpcafJcy4QTOGyp1tgITzLo572cjdC5WyqYCUWpE8u7ZO2SVsNCQtNs LR4Oduxlt4VmfwK64yKRO0pbTVed6WAqHnclxMrJLvhDAQBEPVFCOS5fllFWhkli XQ8hRyebn+ZwOcLd2i7hTbWoFgT6dR8B6Wn8YMjLE3vUPj30FbOgZnsNx+3KAvn8 wgXnF0Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGtTCCBJ2gAwIBAgIULKjNxbjtdQeAxy4zksmUHA/7iCYwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0yMDA4MjgwMDU4NThaFw0z MDA4MjYwMDU4NThaMFcxCzAJBgNVBAYTAk5MMSAwHgYDVQQKDBdRdW9WYWRpcyBU cnVzdGxpbmsgQi5WLjEmMCQGA1UEAwwdUXVvVmFkaXMgUXVhbGlmaWVkIFdlYiBJ Q0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChfGr6wcVF3h+E Zo0Kh0Q+HzJw2vZN3y/epYSzh9DQaHss99SnALka1hM0G61WO/P7stWZRP4rVmjZ l3jPV330JzvWw+rBOoesI0N6xIMLbbnUVozUapF/XBYmGbwYnshQX6RTFPcpiRMO gp814sWBADWAcpcoVBMfmxGxumSjai58JYPAh6fcYIcH/agrzRaxHsCa8uKKU6PH GR+v6w/ytfsbmLsYIQMIHyKiIlMo5vrOGiSCT/0e78sgvEX3OSYTl4yYp3AKbJG3 EI/+Bb/W2tJCFsnP7rOT9Whjcm3D9FIjmzzxWjbL86UPZfGuJi9Jx6k0xOWr1+bJ Uq/9kazBi4sJaMZ4j+o3v8gQWu2G7o0O9840LyOnYnHnGQoFBiQzaIEOR7XNITHs tmzmUmdO6/Ko8b9l54tECNXh6dN/k/vlDC1gOaB1+qHqkFO3tk6LBVKprwrt9I16 vbkA0sq7xGHtY9d/hj0PGaUnfgOT9wlhYq2wYLwI0CH/NrTWULH24Uhhstt+jR2N yJmO2BtJWA603CeYYnfWwHHm3bJMmGwzp1fDQm/PZlLo1WWaN5+/zVBLXfLVgDSa mv/vExynEESG248O9K/2TM9WdjX/qZwGcXDbZZjnxkcDxWA6CtX+SP4wO2fLY8lT XzrzFYWGp0ZCNeC4jDaUTgXFqrzNtQIDAQABo4IBhjCCAYIwEgYDVR0TAQH/BAgw BgEB/wIBATAfBgNVHSMEGDAWgBTt5292Wr9g7ElbxqV3u3IWcZvEPTB0BggrBgEF BQcBAQRoMGYwOAYIKwYBBQUHMAKGLGh0dHA6Ly90cnVzdC5xdW92YWRpc2dsb2Jh bC5jb20vcXZyY2EyZzMuY3J0MCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5xdW92 YWRpc2dsb2JhbC5jb20wSgYDVR0gBEMwQTA/BgRVHSAAMDcwNQYIKwYBBQUHAgEW KWh0dHBzOi8vd3d3LnF1b3ZhZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5MB0GA1Ud JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATA7BgNVHR8ENDAyMDCgLqAshipodHRw Oi8vY3JsLnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTJnMy5jcmwwHQYDVR0OBBYE FNL0fkOhZHZhby2JB8fjYA733MuCMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B AQsFAAOCAgEACbVTsbKH5DcJ02cc3bO7sB2BUAl/HMv/QcCXPbQRsog+1N7E0c9u EXPIJU+dmGjT3XVE67QseWW6ybua5z6b19PLMwAzwE+tiTGECbe2RGAptnt2qTdt Ndn5DoGEVL83bg0vqqp5MXzJm4vjUdA0LPaL9Cts70yPd0d3IWDyQvxeBkDRRnXW rvMP25xVgsaScEpELUo4L2boFSBjwxMnca8UIxERK3mFKU2uS2S7F7TQl2XLkKIo Ho1JEvEJONKlgDry+OxL4z5yoVI6AvGdx74fYRhoHeX77Xxa5n2DhO8ZdL7i4x65 27s+nr0xuzjD9ZBV9en/vGLnZNVpbPSy7VT+QVAKnQfJAeW18UUidK7G7f60O9D6 irXR2IqZyPUsxtp0PghMIsOpIAXoZCH/DvCAbphRGv9jiTY2OmnIs9kAVWv4N/bP gwrzhC2fuMBkbjajwzWgGJxVyyxSBk9TuRfKIo+AxuKbykgrYd7jBJo6G7vKkyOS KMkrepmLcytAuNwUkUaXK2YT57LoVUwBCwviDxheuucr2eMwYqnYfIN0Ob4DQet6 Gyudnk3kVWJpLd1TvcqdeEwXbArsSl7gOnNSxz7UMkb+fralgOQJNkerckUZnyYm HdK7ln8hVWLLLobTGGzeiaciuYN0cDLCWOSF07GWHqYCyTgV2T2shY0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwTCCBKmgAwIBAgIUTagCu/I0w0cHRqxOR/zemut8w78wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0yMDA4MzExOTA0MDhaFw0z MDA4MjkxOTA0MDhaMFcxCzAJBgNVBAYTAkJFMSUwIwYDVQQKDBxEaWdpQ2VydCBF dXJvcGUgQmVsZ2l1bSBCLlYuMSEwHwYDVQQDDBhpdHNtZSBTaWduIElzc3Vpbmcg Q0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDArbBnvS/CdlET szG+s0WUdzWgFm+ebYVEf1BHa2Fq5s7i/M4VuPNprEzlezIKoxxmootA+oHSwdmK k7ZGLczc2grUSpccYcNKK58hBH/dbiVyI00AyKHobGqDcXwM83xrBOjQvE8hfQ4/ vtuB3g0YdOzfudZW8qf0aubuMA14cqW9XsyrPz/A7SSAptwK+70o/eNwP1DB0be2 cfTDcpb8TIxX73y5vad10qCBaShp7aWqS1d5+76uVJ25lk+lsRT65Ob7Eqa+cBA2 KEN31NdwnpMhZhhQNKHDL9HzQERrZcMJLxOALg4+FzHpK8QUbGRHw5rKJirOhf9W SsTXkFBYIphg6ffXxtZZq5NHdCk974l/vYlsl9vDz/DKt3spa72XR3NO2bdGM8Qw TGxJtELQWeUjfNS7sSW+MA71dQA2HLtqf3mnXj5gZZnx201urhSGcyK0HZ6tKAS7 OBwYOXlTIa+SXhDT+1GceUcSNbsNQSzyDZubASitVNQsgkzQ9MCaYDMzdF0wxoNn RcUp3W2pAg9/JWIlFcTFOBobSdApT5XftWq5Y+5ZTOFhkPDgV+DJvW5gjxP8fkOO EFsfdufuK0w6WKGWI7yXiPF06yazEUyX/LrHo7pTmIOjrI4MSdI2aGWZK+Pf8xnK cjshjqXk22onzUGWmPJsPc83/oJPbwIDAQABo4IBkjCCAY4wEgYDVR0TAQH/BAgw BgEB/wIBADAfBgNVHSMEGDAWgBSjl9bzXqIQ4atFnzwXZDzuAXCczDB0BggrBgEF BQcBAQRoMGYwOAYIKwYBBQUHMAKGLGh0dHA6Ly90cnVzdC5xdW92YWRpc2dsb2Jh bC5jb20vcXZyY2ExZzMuY3J0MCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5xdW92 YWRpc2dsb2JhbC5jb20wSgYDVR0gBEMwQTA/BgRVHSAAMDcwNQYIKwYBBQUHAgEW KWh0dHBzOi8vd3d3LnF1b3ZhZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5MCkGA1Ud JQQiMCAGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNwoDDDA7BgNVHR8ENDAy MDCgLqAshipodHRwOi8vY3JsLnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTFnMy5j cmwwHQYDVR0OBBYEFOHztE/RydsTY15P3GYUOtGgK3ytMA4GA1UdDwEB/wQEAwIB BjANBgkqhkiG9w0BAQsFAAOCAgEAShR70+dqY13xJ4T20iJcym64HZmae7k6NTXm tSi+dVANmzooCpb+z/QLzCDfvR5wNllw0x8fjLc1S4gtfdKcBRieY6pn/6Q2h8P1 WMjrhOHjNTXprIor0b+NiUOlqKIoUQs8huCsBcPyqStmGnT3VOOyiIz24WB0U7UF e2Q+5lPwraiF2gOyMPo4fxQASNg2E7gWyOoi+umsHas1WRUq2AgCVh3F+vSKi7nc izHbT7vXhA8jXv66+HcU8yZGL+EgAJy1Ruu6ADCyxT8sdfvf2tqqUHJ8BrAyePMj /mH0wP0HF69YL4u+w2fI1dOJm1YkdyHjQ+SgbCWUmDpO3rcosqzWSfi/Wm+qL0E8 iy/tDJ3eXofXuX8P34WdlYyd5xWW/cZ7YCvEmg9EFeVseBfaP+OhBKVI0jbXb2JA WA7yMi+BsufWRad3gYlHpMhqzRWbDofYY7Voyctujz06wFxEbI7ffyoICY18V405 HM1L/ODuPaQG7gCK5VlgnOPWwlVwpfys5atoBdigVXFOqnTT7EYLFVJQtoKbx9ml 8k6Xy0PP7PoA9kVl7sKMlqMjOeRJ1kqFdqnMPPWPLx2ukhM9776KtdBEp4WLFv05 G31bexe41A7aP8T7nBFyymdFMn3u7aC0DJlAhOQmb86uy5vDuI2GHjNMA2klr2QC w0vQ74M= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICxjCCAk2gAwIBAgIRALO93/inhFu86QOgQTWzSkUwCgYIKoZIzj0EAwMwTzEL MAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNo IEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDIwHhcNMjAwOTA0MDAwMDAwWhcN MjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3MgRW5j cnlwdDELMAkGA1UEAxMCRTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQkXC2iKv0c S6Zdl3MnMayyoGli72XoprDwrEuf/xwLcA/TmC9N/A8AmzfwdAVXMpcuBe8qQyWj +240JxP2T35p0wKZXuskR5LBJJvmsSGPwSSB/GjMH2m6WPUZIvd0xhajggEIMIIB BDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFFrz7Sv8NsI3eblSMOpUb89V yy6sMB8GA1UdIwQYMBaAFHxClq7eS0g7+pL4nozPbYupcjeVMDIGCCsGAQUFBwEB BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gyLmkubGVuY3Iub3JnLzAnBgNVHR8E IDAeMBygGqAYhhZodHRwOi8veDIuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYG Z4EMAQIBMA0GCysGAQQBgt8TAQEBMAoGCCqGSM49BAMDA2cAMGQCMHt01VITjWH+ Dbo/AwCd89eYhNlXLr3pD5xcSAQh8suzYHKOl9YST8pE9kLJ03uGqQIwWrGxtO3q YJkgsTgDyj2gJrjubi1K9sZmHzOa25JK1fUpE8ZwYii6I4zPPS/Lgul/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW +1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 /q4AaOeMSQ+2b1tbFfLn -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYDCCAkigAwIBAgIQB55JKIY3b9QISMI/xjHkYzANBgkqhkiG9w0BAQsFADBP MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yMDA5MDQwMDAwMDBa Fw0yNTA5MTUxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5l dCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgy MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H ttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7 AlF9ItgKbppbd9/w+kHsOdx1ymgHDB/qo4HlMIHiMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR8Qpau3ktIO/qS+J6Mz22LqXI3lTAf BgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQw IgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wJwYDVR0fBCAwHjAc oBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzAiBgNVHSAEGzAZMAgGBmeBDAEC ATANBgsrBgEEAYLfEwEBATANBgkqhkiG9w0BAQsFAAOCAgEAG38lK5B6CHYAdxjh wy6KNkxBfr8XS+Mw11sMfpyWmG97sGjAJETM4vL80erb0p8B+RdNDJ1V/aWtbdIv P0tywC6uc8clFlfCPhWt4DHRCoSEbGJ4QjEiRhrtekC/lxaBRHfKbHtdIVwH8hGR Ib/hL8Lvbv0FIOS093nzLbs3KvDGsaysUfUfs1oeZs5YBxg4f3GpPIO617yCnpp2 D56wKf3L84kHSBv+q5MuFCENX6+Ot1SrXQ7UW0xx0JLqPaM2m3wf4DtVudhTU8yD ZrtK3IEGABiL9LPXSLETQbnEtp7PLHeOQiALgH6fxatI27xvBI1sRikCDXCKHfES c7ZGJEKeKhcY46zHmMJyzG0tdm3dLCsmlqXPIQgb5dovy++fc5Ou+DZfR4+XKM6r 4pgmmIv97igyIintTJUJxCD6B+GGLET2gUfA5GIy7R3YPEiIlsNekbave1mk7uOG nMeIWMooKmZVm4WAuR3YQCvJHBM8qevemcIWQPb1pK4qJWxSuscETLQyu/w4XKAM YXtX7HdOUM+vBqIPN4zhDtLTLxq9nHE+zOH40aijvQT2GcD5hq/1DhqqlWvvykdx S2McTZbbVSMKnQ+BdaDmQPVkRgNuzvpqfQbspDQGdNpT2Lm4xiN9qfgqLaSCpi4t EcrmzTFYeYXmchynn9NM0GbQp7s= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICxjCCAkygAwIBAgIQTtI99q9+x/mwxHJv+VEqdzAKBggqhkjOPQQDAzBPMQsw CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw0y NTA5MTUxNjAwMDBaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNy eXB0MQswCQYDVQQDEwJFMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABCOaLO3lixmN YVWex+ZVYOiTLgi0SgNWtU4hufk50VU4Zp/LbBVDxCsnsI7vuf4xp4Cu+ETNggGE yBqJ3j8iUwe5Yt/qfSrRf1/D5R58duaJ+IvLRXeASRqEL+VkDXrW3qOCAQgwggEE MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEw EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUbZkq9U0C6+MRwWC6km+NPS7x 6kQwHwYDVR0jBBgwFoAUfEKWrt5LSDv6kviejM9ti6lyN5UwMgYIKwYBBQUHAQEE JjAkMCIGCCsGAQUFBzAChhZodHRwOi8veDIuaS5sZW5jci5vcmcvMCcGA1UdHwQg MB4wHKAaoBiGFmh0dHA6Ly94Mi5jLmxlbmNyLm9yZy8wIgYDVR0gBBswGTAIBgZn gQwBAgEwDQYLKwYBBAGC3xMBAQEwCgYIKoZIzj0EAwMDaAAwZQIxAPJCN9qpyDmZ tX8K3m8UYQvK51BrXclM6WfrdeZlUBKyhTXUmFAtJw4X6A0x9mQFPAIwJa/No+KQ UAM1u34E36neL/Zba7ombkIOchSgx1iVxzqtFWGddgoG+tppRPWhuhhn -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG /kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX nLRbwHOoq7hHwg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFjCCAv6gAwIBAgIRAIp5IlCr5SxSbO7Pf8lC3WIwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDELMAkGA1UEAxMCUjQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCzKNx3KdPnkb7ztwoAx/vyVQslImNTNq/pCCDfDa8oPs3Gq1e2naQlGaXS Mm1Jpgi5xy+hm5PFIEBrhDEgoo4wYCVg79kaiT8faXGy2uo/c0HEkG9m/X2eWNh3 z81ZdUTJoQp7nz8bDjpmb7Z1z4vLr53AcMX/0oIKr13N4uichZSk5gA16H5OOYHH IYlgd+odlvKLg3tHxG0ywFJ+Ix5FtXHuo+8XwgOpk4nd9Z/buvHa4H6Xh3GBHhqC VuQ+fBiiCOUWX6j6qOBIUU0YFKAMo+W2yrO1VRJrcsdafzuM+efZ0Y4STTMzAyrx E+FCPMIuWWAubeAHRzNl39Jnyk2FAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFDadPuCxQPYnLHy/jZ0xivZUpkYmMB8GA1UdIwQYMBaA FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCJbu5CalWO+H+Az0lmIG14DXmlYHQE k26umjuCyioWs2icOlZznPTcZvbfq02YPHGTCu3ctggVDULJ+fwOxKekzIqeyLNk p8dyFwSAr23DYBIVeXDpxHhShvv0MLJzqqDFBTHYe1X5X2Y7oogy+UDJxV2N24/g Z8lxG4Vr2/VEfUOrw4Tosl5Z+1uzOdvTyBcxD/E5rGgTLczmulctHy3IMTmdTFr0 FnU0/HMQoquWQuODhFqzMqNcsdbjANUBwOEQrKI8Sy6+b84kHP7PtO+S4Ik8R2k7 ZeMlE1JmxBi/PZU860YlwT8/qOYToCHVyDjhv8qutbf2QnUl3SV86th2I1QQE14s 0y7CdAHcHkw3sAEeYGkwCA74MO+VFtnYbf9B2JBOhyyWb5087rGzitu5MTAW41X9 DwTeXEg+a24tAeht+Y1MionHUwa4j7FB/trN3Fnb/r90+4P66ZETVIEcjseUSMHO w6yqv10/H/dw/8r2EDUincBBX3o9DL3SadqragkKy96HtMiLcqMMGAPm0gti1b6f bnvOdr0mrIVIKX5nzOeGZORaYLoSD4C8qvFT7U+Um6DMo36cVDNsPmkF575/s3C2 CxGiCPQqVxPgfNSh+2CPd2Xv04lNeuw6gG89DlOhHuoFKRlmPnom+gwqhz3ZXMfz TfmvjrBokzCICA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIErDCCA5SgAwIBAgIRAMPgD58ALsVZugLEpfJgDF8wDQYJKoZIhvcNAQELBQAw fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0yMDA5MDkwODAyNTRa Fw0yODA5MDkwODAyNTRaMEExCzAJBgNVBAYTAlVTMRswGQYDVQQKDBJSb290IE5l dHdvcmtzLCBMTEMxFTATBgNVBAMMDFJvb3QgQ0EgLSBHMzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMUiL5hGHyQbL7wgWfsagEWVVZhxCnBnbnQsft5E KUPSjZ1a0BrK0QNWmzH6DObUQSdMuBC/bCuYqfAePBFiMA0hHn7FOBeVTJ/lspN6 Xu2vi3TzBEAQnabcAgJP6eDlZ7HA2CT9KARwL8mNPeYk/UOasuCWkI7hyiJhsS3u m0V+EE7MfVLE2cL+/JVc8WOnKABK/r5fTZEZrIg78l3HTmx1AAQCxCDAM0nQfvw2 JfYW2qHU9aqFgDN1CkHAIvwQP2K+QdnDbLKRCNxYWh32T1lyc1L5b3hz2RFZQpDA nde4ChTpf6rnk9XyooSS03Dr82BWda76yVvHpb6+jI5Ghb0CAwEAAaOCAWAwggFc MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJdR8YjL3V0fYHEMujcLD/5o M7SzMB8GA1UdIwQYMBaAFAh2zcsH/yT2xc3tu5C84oQ3RnX3MA4GA1UdDwEB/wQE AwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwLwYDVR0fBCgwJjAk oCKgIIYeaHR0cDovL2NybC5jZXJ0dW0ucGwvY3RuY2EuY3JsMGsGCCsGAQUFBwEB BF8wXTAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2VydHVtLmNvbTAx BggrBgEFBQcwAoYlaHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBsL2N0bmNhLmNl cjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0cDovL3d3dy5j ZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQC+khmGmE6GRVOgXBWDLQbm CGXB07CggWngBF1TNqJIbHH1HbKa5KIoeOLCAosFoHqxSQ/Jvj8FzrINN0yiTDB8 kucNC1OSJph0Co8vNg3ceHA/cRGDsSRvSnwaRIZ95r202Tnjfqzibd/zmvVCaITS zQChOiaqqUbmSXkDGSgDTRNe8vWNxd8rzhZgr5/mY/ki4N0Md7t8SJGYsN/lNE1m SblJt84HmQDI578hplp3ePNjWJovf9syXCYuxtTbgHJ0vOo6XMQJhDzr3RkN2mmN qnG9t0ln8Lb8CXLLuKfQE3R9X2tYrFzjH949FRrJpbGiLKtdADkRD2OktgnEiUQf -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvDCCA6SgAwIBAgIQeEqpEhjRpCYIUTzTZlVDozANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA5MTYwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFsxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMTEwLwYDVQQDEyhHbG9iYWxTaWduIEdDQyBSMyBQZXJzb25hbFNpZ24g MSBDQSAyMDIwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvxvJBqEa paux2/z3J7fFslROWjKVJ5rCMfWGsg17dmD7NSnG7Spoa8d3htXsls1IMxoO8Pyo uQajNQqYmlYoxinlqenMNv7CJyEKMOAtglBmD6C/QC7kT+dSx4HfSTs8xmv8veJO ldMzF8S/BEn/tD4w/Dvpg+oXOqDyOiHPTacRFK0QHoq5eEbBmVS8W0rwcaRotO9f GTA+NjF0My7GLRNK0eMPGh2hcPZURQhXy7wRQ8XFIfEA6kaQHHN22ncnVtwqiTmA wTR+4GNNVinG3KjNZLAVSnGrdCvT2I4Zo19hKy5PX6o7wrVXvMR4zV5VBFwV6ZDM +xewao7Mup+SbwIDAQABo4IBiTCCAYUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQW MBQGCCsGAQUFBwMCBggrBgEFBQcDBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud DgQWBBSFu/DMxDa1CmJ2o5kuj7s6aq3FUTAfBgNVHSMEGDAWgBSP8Et/qC5FJK5N UPpjmove4t0bvDB6BggrBgEFBQcBAQRuMGwwLQYIKwYBBQUHMAGGIWh0dHA6Ly9v Y3NwLmdsb2JhbHNpZ24uY29tL3Jvb3RyMzA7BggrBgEFBQcwAoYvaHR0cDovL3Nl Y3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQvcm9vdC1yMy5jcnQwNgYDVR0fBC8w LTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBM BgNVHSAERTBDMEEGCSsGAQQBoDIBKDA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3 dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEA WWtqju12g524FdD2HwUXU1rSxeM5aSU1cUC1V/xBjXW0IjA7/3/vG2cietPPP/g3 lpoQePVJpQAKZml81fHwPPivFK9Ja41jJkgqGzkORSC0xYkh2gGeQg1JVaCzcrRz JElRjT442m6FpbLHCebxIHLu0WBNjLZreB6MYMaqdPL6ItbXtD/BU4k517cEuUbc zoBFZArajq7oUBWXuroln5AMnRwVNwgJN4Np0s4kkJ94KepzbFOLzcbnfUB0+xT4 foXmbM0GmmcPGOy0qvqEHJsBwDZXDxIk8oqCnnLngi7N94Sn4eTcmpZ9NH2dDN1O TEPVXgRG5X1pBcNtMWG6MA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzDCCA7SgAwIBAgIQeEqpCvuP+7xUW0sot/yjUzANBgkqhkiG9w0BAQwFADBX MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEtMCsGA1UE AxMkR2xvYmFsU2lnbiBDQSBmb3IgQUFUTCAtIFNIQTM4NCAtIEc0MB4XDTIwMDkx NjAwMDAwMFoXDTMwMDkxNjAwMDAwMFowUTELMAkGA1UEBhMCQkUxGTAXBgNVBAoT EEdsb2JhbFNpZ24gbnYtc2ExJzAlBgNVBAMTHkdsb2JhbFNpZ24gR0NDIFI2IEFB VEwgQ0EgMjAyMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMI1Jp14 T95zBiOIXrtDdbwE5o+oW08OJI5x1s+ZfuF+jcpfhbOJPPK95Ih9hTqWQJEluM3g VPSTur6lSBMAnvIoUpOege7AcUiG3Df8uabQaPs4b8AYMPlPIyX5jCkteOUCGqkD ZlDJDI5nYBK1qK326XUKFV/NH80hxwV+HohoQBLhtFfQ68gKrMDvwF7S57q4adaP wO2gE47MHUJvQ2SbtjGjx7DCN80qtHpXGMDJIR9Bpounp2CNQMG4lNpy+R/JYcZs 5DsvjzkLC+zn8L7hzTzjpvh+lW83/UXqHmXwj8vwS/1WbW6Rj6GbkJhE01yBpvRf CDYDP2a4Q0TQPY0CAwEAAaOCAZgwggGUMA4GA1UdDwEB/wQEAwIBhjAUBgNVHSUE DTALBgkqhkiG9y8BAQUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUdyLZ awqinL/F1uwRVjQEPK4K028wHwYDVR0jBBgwFoAUie91cXpfRxuXI9yQSsv/wCY2 CNUwgYgGCCsGAQUFBwEBBHwwejA2BggrBgEFBQcwAYYqaHR0cDovL29jc3AuZ2xv YmFsc2lnbi5jb20vY2EvZ3NhYXRsc2hhMmc0MEAGCCsGAQUFBzAChjRodHRwOi8v c2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9nc2FhdGxzaGEyZzQuY3J0MD4G A1UdHwQ3MDUwM6AxoC+GLWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vY2EvZ3Nh YXRsc2hhMmc0LmNybDBNBgNVHSAERjBEMEIGCisGAQQBoDIBKB4wNDAyBggrBgEF BQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJ KoZIhvcNAQEMBQADggIBAC/n7wJw4n2q266yVLD2Gk71VEtE9wjh5xovU4sUbHpz 3aSQlC/HVqGKE/eDDAyYFSx8Vll1PlvSz41jWhma8YXrYRoTn3dRRssnDnbPARlW TmTv3EY+9YcY7kdHpo7rxFUBH+Th9AdGjrqe5vdd4uJ9NG/MEeL2ZMliRzeoLIIu VOSsQzA2xalLzVfJfmnTPv5a0innAfuPQAKNAqArVhVO48bmCwsmkF8aSeGVNnbQ goHeXmBAiW/SB+PukKJ2U8AGGeIYdA1uUngyuhwPrD7/EKasZUONxvrEbCJPgUo5 GO5Lr5T2Gc2eZvxIPk7LHzCPewN4r1rds1Vs3BNAy6/V285MBxcgbvaHhvpAaGaH ZOb8W194gWoIkq3sP6VBMww1GGHE7ggon3JFHVgEk6gv3VaZoRCGk3KmkR945xdZ AGOcurSO2u1Hkavik0WgIvumMP78OqEOJN7nhxpM9b7eXBC3G+E4immDwekYB2nU XmXGqBhVbXITrgI4WtIBDDPPvE+RRft9//DpMk77qj/mJG6iR+ydBDuv0TdJPc/J qW7p70tRpEwv6aUAHIV/lj8/XOrhqvKslvb18xQImESPlW1sqKZUG+JVwmk29p8H 8zXemuwcBayISKAIqncGmOGMBHtwlWlVPeqZzl2VWjB8j+u08j8+9P/1r/A/ZlYF -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFtTCCBJ2gAwIBAgIQeEqpJrbnW++td7NIAblS0DANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA5MTYwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFkxCzAJBgNVBAYTAkdCMRswGQYDVQQKExJHTU8gR2xvYmFs U2lnbiBMdGQxLTArBgNVBAMTJEdsb2JhbFNpZ24gR0NDIFIzIFVLIEVWIFFXQUMg Q0EgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANb8rtddi5/y jm2toox7VSaHcs1oda93dEOEaLfEtyxwg72oNvwgR48PxufwfoKwCLq8RYmGzGDF Famw1Ff3+7eBsj9Y1yt4/2HqBPBzkTZk96gvUpQ90EHwMbat0Nsxagess1WrDXUv 9U4NYwBeZo52MqFYvny2uuu+T41RPmNqbfzMNgBSamqvqEIDGr3XZ5xRviLG+d6H nYyy+zIENDoBpzSNV5ni4y0KTs7A5r7bsZAveiAu2mO69jKDHxegisLutWzbOElf KWQ0w+xuh46gb/d5/6CF/uGCohWOJZKB+cb8JYMUENH8fNu3ZcLJNihynxONLlmM dT30wW6vUe/1vKpoZJhVLpi+yJ9Bt5Y3zQRLVge52qvaRuVqccydyTTR8N0VuvyD f7WJXJ2lE4cmwoXMB4O4YxCnQZLfrCtQRXkjh6UVzWmIkTzFIWRi8b/tM7Q8/h7z coFMdNR8iH2msYN5dHFai5w4a4isbnSxX8QU4lgROh5SQTyWKSEwY4N0LFUA9YWo U9v76ucTr9Nq/gJJG02ue2ZN6mYzY34qSQyBrwW4lp3z7wReFKZ54SKzzuWbXnd2 MG9i18n5W36PjXZlYtG86Dlhiwyr5MUihtA3k0PLdlIeBfxL/puxjJB/lH3TpPdg kSxwUGo0Jl65tUGGtdKwRUvw488Nx0PJAgMBAAGjggGEMIIBgDAOBgNVHQ8BAf8E BAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQI MAYBAf8CAQAwHQYDVR0OBBYEFAeUNkpRlUn97ioGeTZ/wjc7Ttu/MB8GA1UdIwQY MBaAFI/wS3+oLkUkrk1Q+mOai97i3Ru8MHoGCCsGAQUFBwEBBG4wbDAtBggrBgEF BQcwAYYhaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIzMDsGCCsGAQUF BzAChi9odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9yb290LXIz LmNydDA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29t L3Jvb3QtcjMuY3JsMEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIBFiZo dHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0B AQsFAAOCAQEAYTUdDFCkY6pGCgQWAI7Y/n1Dpk5BqieG7dYxX8e3uKMAVEObEpbo NixYe4tnICApgFay9FERbc4QIJjCfLKpcgJGn5oWg0WRUSiuuwx5oATplUn012wx SfBPRUzEYTQVzihSGiDa1u/4Y55WE7hzf34DRfPi8a4pQfHc+TMdL10lMbIZdUTO p84lkKnHza4bze+p+TCwJxJmrMvI+9m5Ml9+dStsbEG+wXkPLNxPYEAlFT/IrvUj 6uMLhsUMlogMUC07e6kz7G/XuXVIYTFsvkwPvwO2VGPL2ScSfeb5dS93QzWHYWyt 34qNN2lYl2srnoCe5T0AAE3EL7SQuqEubw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFDTCCA/WgAwIBAgIQeEqpED+lv77edQixNJMdADANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDA5MTYwMDAwMDBaFw0y ODA5MTYwMDAwMDBaMFsxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu IG52LXNhMTEwLwYDVQQDEyhHbG9iYWxTaWduIEdDQyBSMyBQZXJzb25hbFNpZ24g MiBDQSAyMDIwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvbCmXCcs bZ/a0fRIQMBxp4gJnnyeneFYpEtNydrZZ+GeKSMdHiDgXD1UnRSIudKo+moQ6YlC Ou4trVWO/EiXfYnK7zeop26ry1RpKtogB7/O115zultAz64ydQYLe+a1e/czkALg 3sgTcOOcFZTXk38eaqsXsipoX1vsNurqPtnC27TWsA7pk4uKXscFjkeUE8JZu9BD KaswZygxBOPBQBwrA5+20Wxlk6k1e6EKaaNaNZUy30q3ArEf30ZDpXyfCtiXnupj SK8WU2cK4qsEtj09JS4+mhi0CTCrCnXAzum3tgcHcHRg0prcSzzEUDQWoFxyuqwi whHu3sPQNmFOMwIDAQABo4IB2jCCAdYwDgYDVR0PAQH/BAQDAgGGMGAGA1UdJQRZ MFcGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNxQCAgYKKwYBBAGCNwoDBAYJ KwYBBAGCNxUGBgorBgEEAYI3CgMMBggrBgEFBQcDBwYIKwYBBQUHAxEwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUljPR5lgXWzR1ioFWZNW+SN6hj88wHwYD VR0jBBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7wwegYIKwYBBQUHAQEEbjBsMC0G CCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYI KwYBBQUHMAKGL2h0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jv b3QtcjMuY3J0MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2ln bi5jb20vcm9vdC1yMy5jcmwwWgYDVR0gBFMwUTALBgkrBgEEAaAyASgwQgYKKwYB BAGgMgEoCjA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNv bS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAdAXk/XCnDeAOd9nNEUvW PxblOQ/5o/q6OIeTYvoEvUUi2qHUOtbfjBGdTptFsXXe4RgjVF9b6DuizgYfy+cI Lmvi5hfk3Iq8MAZsgtW+A/otQsJvK2wRatLE61RbzkX89/OXEZ1zT7t/q2RiJqzp vV8NChxIj+P7WTtepPm9AIj0Keue+gS2qvzAZAY34ZZeRHgA7g5O4TPJ/oTd+4rg iU++wLDlcZYd/slFkaT3xg4qWDepEMjT4T1qFOQIL+ijUArYS4owpPg9NISTKa1q qKWJjFoyms0d0GwOniIIbBvhI2MJ7BSY9MYtWVT5jJO3tsVHwj4cp92CSFuGwunF Mw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGnjCCBIagAwIBAgIUK6/F8KjSE0CdpC52H2GayRmEvNQwDQYJKoZIhvcNAQEL BQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZ BgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0yMDA5MjIxOTIxMTJaFw0yNjA1 MjMxNTI3MDJaMEcxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p dGVkMR0wGwYDVQQDExRRdW9WYWRpcyBHcmlkIElDQSBHMjCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBANg3D8Nowe7J1akat//nm17yKAxum/gkmx4MI0/G eFhxAh9hgQoaOyVfr5B+oCefTXWVmqgocA9wJoXbaLCvnpt+AKZpK1YXq7AK1sUW UgFKHiSb5FBoLMUVBQrppaXctxosBu1XCMwIYVpzFCihQ9sDKTcTqs0I+9C5Z8Gi D8aGvF12xR2Xfh125ZLnP6WYR1+721gHnI7sxyNy71PPNECy4h7dTK3i4V7px7gj 772eFLz0UnGSkwVkkuFLv7shoUuJxNxy8qsxzZ1RXgW344avJqRttOZM0LN+CoVO OiNvbZg4mxYqhLrF3ZjnwpuyA8pUxAq/DqDlMUatzQ91z7XC2OoAxuEbmiTPQFwS xkWi9k2QsKwZU/KkupoP96y2i86aFZGY1C/i1l5C2kDim0VTDbl6E4cRW8Dy8F4w 07OkyUzpMn98jQTAslDVzG0P3NiO0QaRJED5cww9F3mXXIEBFtBQsqz3ymt4mkeW w5cVQi6GcHuenyHKyQPzZJLVioTg8kD2tfBaWt8Mi+MEXz3aSolxIiYmNC2zsnQE C42jHLBN8yK+ArpRMGLm6LkwaELcEcSVkqvHE1WYzqnvtGolRYTbuA7fPQCrcQUW 1K4tJHk0q7uVyZO8Ss0Tot6kC6e9ip9lbw6QLCp2cw8KCjxrL+CfygTLiZ1Dmlk0 iQ9pAgMBAAGjggGCMIIBfjASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaA FBqEYrxITDMlBNTu0PYDxBlG0ZRrMHIGCCsGAQUFBwEBBGYwZDA2BggrBgEFBQcw AoYqaHR0cDovL3RydXN0LnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTIuY3J0MCoG CCsGAQUFBzABhh5odHRwOi8vb2NzcC5xdW92YWRpc2dsb2JhbC5jb20wSgYDVR0g BEMwQTA/BgRVHSAAMDcwNQYIKwYBBQUHAgEWKWh0dHBzOi8vd3d3LnF1b3ZhZGlz Z2xvYmFsLmNvbS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnF1b3ZhZGlzZ2xvYmFs LmNvbS9xdnJjYTIuY3JsMB0GA1UdDgQWBBS3XXWClyyy+27+HBlQ4Ctv5N+6MDAO BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBABARGZGT6tt5pnZl3I3i AHM1O0gnrgEUXaiBIV1sEMjqdOn0jd3KeDISIOwZjfwotJCus2LqXWzfS1D+XJ9b tU67TXr2H3OP13Cxiw4oIFq/faWxVrJZIgIYBo4PqHQL2Y+FC6nsZQYoxcht/cej WQYbQaqXc2Ue9NTB49sgoCnWPLfiAgBcIYsPEm5SeEqbLIAZBF9pNQLd+4Xq4LcS bCtJ/88JBgkq2ueeuALTg1lMnMoOGmVlwIPF8tEUmdDkTvEgnQfF/qNwTeXEWePm XVSlBud1+H1FSJR741CuWePMP5DgAUFknEAtJ8elESVsZBIKLKwkNuf9bDCXj408 nLDEyc4rqQxdMtv49PiEVgUq1MHKty4oRdyc0besH8xf5R4wlsBgAL8zUxDKo3fQ 9cj0melQeLHJ8GmoVPMl94JJyCK7ScYR+kTdwxjfSM2VSFtsooAYHrG6zqjCyAx3 kygSH+BEubs+ztu7LHyoN7d1Erc3+a/JqVepPSM6Myh2NRznxRhYXFTzPqy2bxrN H4UfpKHEpG9sqapzHroNGEGGNrrxSlkSX2p0IjNC8f+TBDPYPryDG1ZVqW9BE7JU Q485ggSVfjuoi7YHRrqU5YZ/eGy0Mcg0GMGUt/p0sT4CJDo4Qi0gNrv7pzXQD6h0 uhfq/saaCAxSoOO0gqsHaZBu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGrzCCBJegAwIBAgIUMahPJ4u+SmluTLL0FaLkRzvcyjgwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0yMDA5MjIxOTI4NTlaFw0z MTA2MDYxNDE2NDBaMFQxCzAJBgNVBAYTAkJNMRkwFwYDVQQKDBBRdW9WYWRpcyBM aW1pdGVkMSowKAYDVQQDDCFRdW9WYWRpcyBFbnRlcnByaXNlIFRydXN0IENBIDIg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC8uNEaRwSSvuZABUo+ RKza7R61thEWOwCPJF/TjUr2+3p290tjYCfOrBxLcBRhaGgd/edePwXUkjYZy4uO 5IWeR92VqUaJtK5nkOe9OS1GxD6I+DCs2xL+VRf3RQvPVUP79v9lVVrsGfUq6j4K UXgE+heAokZScee6vC2pyVJ63QK+KOVT8dTKj1Ee0FlYhoxxrIuRB/3Suf22X9wQ o85pDkC+AGwIeqqLGYsIDFxtPX0Byphd1BLjur9SimTb/ePsSgAONCno+mNu7h9S VYqIF4/5nxu91MfQeF9mG+BS+gCTTygmJXCHNR4QYJg10DzmOhYC4wt5re5eyxvj CF8vbczE0OFqPrtX1OZdqHqDLCajgLiVrwtqj4TzUqPhOMvZE/aqQtQ0UoC3Hods fv73pRdZTt2mQjY5DA4uyZRNa8y67nHl75noop59MszWHBJU8GPdcF36Vkxz4z0N GykiIEAqZQR7lH1gjhGA3odGTmW08HlXJHcWoMbV2pjpKR3TV6FhQveBR9mqpEOn gYmMqDMbV0KsAiWWGv9T/yM683J2hdXmJrbtGPb33/D/mkT4QBCK1ge8UOvGewFF bcEI5A53aX4+krPeY6Dun4+XUpRDSBEac8De/FEq2MifDKjF0SDopSkm8AHVtTnw 2wuXnylA3Q/mvaHm1VzQmwrAqwIDAQABo4IBgzCCAX8wDwYDVR0TAQH/BAUwAwEB /zAfBgNVHSMEGDAWgBTt5292Wr9g7ElbxqV3u3IWcZvEPTB0BggrBgEFBQcBAQRo MGYwOAYIKwYBBQUHMAKGLGh0dHA6Ly90cnVzdC5xdW92YWRpc2dsb2JhbC5jb20v cXZyY2EyZzMuY3J0MCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5xdW92YWRpc2ds b2JhbC5jb20wSgYDVR0gBEMwQTA/BgRVHSAAMDcwNQYIKwYBBQUHAgEWKWh0dHBz Oi8vd3d3LnF1b3ZhZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQG CCsGAQUFBwMCBggrBgEFBQcDATA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3Js LnF1b3ZhZGlzZ2xvYmFsLmNvbS9xdnJjYTJnMy5jcmwwHQYDVR0OBBYEFGTjBYsm vvM19Z8xEgj45BacKqhiMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC AgEATvNnN5+pH6CsD8szdS/SDclJuY0VcpFv08LOMboSYOj0psFdOHRhfu4uez42 rwp6ruDh2CYTb71i0Y4EZgie6RC6kR71zX117U8PGySFNW/yLJhmXUUWiIGEu39a heGAqVs/6kGcdM+BXgflqvUFrhaVoUGCnHFLih26ZidCx9dt8SiK+u2zK4Blgw5X gLwvJfA+4HvJS1NW+CNBkCFvi6M90GDaDbBVxkFE59uGJHt8IKnaEZlI2awIJ3wI ydhnHX0Sy5nAUf6Rhc15AF7JmiQNNi8+TBldyY6XiNncIkvEkrzpuY59Nr0ejFPP rPxarHYlrpqMbhaP42eGmIq4Jf5AXPTL2/bynbp21kf5mXEf94tPmtaD+tQKm0nA 826RS087rhLflGUOr1+8/BDO9TgL2c3+jSl0o5MhkDaWa6JsyYn6e95ZKTGCZ5CN 9/9CgXay3i8H7mOW8agCem5u2yPrwdV+1flb4F+o/HLcsaQ+BzwZu3rtl2OQTShT GJePq809UMc6pTDMl1lEiCFpgV+hSEmBZa2D7tyhxXi2dHcJmGDkqo05HyebYoZF e2IYyDTBdoXlVVD2GBKXrzXQfmAb9/ZFaXVcDyJ80v7mVPOjnE32oG9IWwHLaWPV Xi20kSqokwRho+R5YkdGjzomZ5q1ui2DGfdxF+OcbuL3N9Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE6DCCA9CgAwIBAgIQAnQuqhfKjiHHF7sf/P0MoDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDA5MjMwMDAwMDBaFw0zMDA5MjIyMzU5NTlaME0xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83 nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f /ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0 /RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAa4wggGqMB0GA1UdDgQWBBQPgGEcgjFh 1S8o541GOLQs4cbZ4jAfBgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAO BgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIG A1UdEwEB/wQIMAYBAf8CAQAwdgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhho dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNl cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcnQwewYDVR0f BHQwcjA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xv YmFsUm9vdENBLmNybDA3oDWgM4YxaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0Rp Z2lDZXJ0R2xvYmFsUm9vdENBLmNybDAwBgNVHSAEKTAnMAcGBWeBDAEBMAgGBmeB DAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMA0GCSqGSIb3DQEBCwUAA4IBAQB3MR8I l9cSm2PSEWUIpvZlubj6kgPLoX7hyA2MPrQbkb4CCF6fWXF7Ef3gwOOPWdegUqHQ S1TSSJZI73fpKQbLQxCgLzwWji3+HlU87MOY7hgNI+gH9bMtxKtXc1r2G1O6+x/6 vYzTUVEgR17vf5irF0LKhVyfIjc0RXbyQ14AniKDrN+v0ebHExfppGlkTIBn6rak f4994VH6npdn6mkus5CkHBXIrMtPKex6XF2firjUDLuU7tC8y7WlHgjPxEEDDb0G w6D0yDdVSvG/5XlCNatBmO/8EznDu1vr72N8gJzISUZwa6CCUD7QBLbKJcXBBVVf 8nwvV9GvlW+sbXlr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE4DCCA8igAwIBAgIQCoH9k4LCpNdG8PhoHyo7QDANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw MDkyNDAwMDAwMFoXDTI1MDUxMTIzNTk1OVowWTELMAkGA1UEBhMCVVMxFTATBgNV BAoTDERpZ2lDZXJ0IEluYzEzMDEGA1UEAxMqRGlnaUNlcnQgQmFsdGltb3JlIFRM UyBSU0EgU0hBMjU2IDIwMjAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAwE3UchUD1ZcHyHkf6x3jYwPoFAW9IiMoSSa94t00CDxv+1WJsedR0V1N 4DepZkhEDvrTQBp34C7/JIsb2aJV4uC6Qrto81NsnnQhsr36tgTvdiHjU5VY9C02 BTroFSU9awUWpHoPGNK8+M6iDClttvuKbWMdFV7HJ6CE3dvZ2Xv4GozSot1XvZ1p 0Bi9U22PD7laFEakIrkup97EIeguFnBk7xqv1Fu3pumQbhQ5+yHBjFPofh4f32GK 1+B2lhSZmOG8+ja3YGyhQ1Qi+0/HwcLnoRT9ukaxBCVrAR6zkb0XrYReKCZ+8LBf X1icjT//DS8xsN4WCknPz6rnYj9nPQIDAQABo4IBoTCCAZ0wHQYDVR0OBBYEFPJW mweGB5lTfhIs+H0v5tUm2JNUMB8GA1UdIwQYMBaAFOWdWTCCR1jMrPoIVDaGezq1 BE3wMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwEgYDVR0TAQH/BAgwBgEB/wIBADB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUH MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDov L2NhY2VydHMuZGlnaWNlcnQuY29tL0JhbHRpbW9yZUN5YmVyVHJ1c3RSb290LmNy dDBrBgNVHR8EZDBiMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vT21u aXJvb3QyMDI1LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL09t bmlyb290MjAyNS5jcmwwMAYDVR0gBCkwJzAHBgVngQwBATAIBgZngQwBAgEwCAYG Z4EMAQICMAgGBmeBDAECAzANBgkqhkiG9w0BAQsFAAOCAQEAM3lQOKAwEZj1SmvC tY+MQlC6mHgxaW+gLuOkDXLD6EW2NedYWRl5AVwc+FzraYzRt3jd0LjmyXlPpCGV bNEDlMNtypjcP/m7Qmhkd2efXIFFWOwKa5c3aBcbWJQ75R5F1Hh1FYlKQ/BMnZxA P0kyeyDh9l1ADbs0e02NXOojAiQSFsSg+Sg9Rq6qeibScMuqIL4BiWaVesshmgbW PdxG5YjBQGiZQpR/00AN/M45UloKVg/MAbudpQe3VbAhp7wc1yWKFIltotHPdU2A GSjU2aua+DN/CGEW+ytD0mUPtOZWierV7wD54Dc3b3f5e70o4Bc65mu1CyLVj6fe xOFpmA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE9DCCA9ygAwIBAgIQCF+UwC2Fe+jMFP9T7aI+KjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0yMDA5MjQwMDAwMDBaFw0zMDA5MjMyMzU5NTlaMFkxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMzAxBgNVBAMTKkRpZ2lDZXJ0IEdsb2Jh bCBHMiBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAMz3EGJPprtjb+2QUlbFbSd7ehJWivH0+dbn4Y+9lavyYEEV cNsSAPonCrVXOFt9slGTcZUOakGUWzUb+nv6u8W+JDD+Vu/E832X4xT1FE3LpxDy FuqrIvAxIhFhaZAmunjZlx/jfWardUSVc8is/+9dCopZQ+GssjoP80j812s3wWPc 3kbW20X+fSP9kOhRBx5Ro1/tSUZUfyyIxfQTnJcVPAPooTncaQwywa8WV0yUR0J8 osicfebUTVSvQpmowQTCd5zWSOTOEeAqgJnwQ3DPP3Zr0UxJqyRewg2C/Uaoq2yT zGJSQnWS+Jr6Xl6ysGHlHx+5fwmY6D36g39HaaECAwEAAaOCAa4wggGqMB0GA1Ud DgQWBBR0hYDAZsffN97PvSk3qgMdvu3NFzAfBgNVHSMEGDAWgBROIlQgGJXm427m D/r6uRLtBhePOTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEG CCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwdgYIKwYBBQUHAQEEajBoMCQG CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQAYIKwYBBQUHMAKG NGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RH Mi5jcnQwewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29t L0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDA3oDWgM4YxaHR0cDovL2NybDQuZGln aWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDAwBgNVHSAEKTAnMAcG BWeBDAEBMAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMA0GCSqGSIb3DQEB CwUAA4IBAQB1i8A8W+//cFxrivUh76wx5kM9gK/XVakew44YbHnT96xC34+IxZ20 dfPJCP2K/lHz8p0gGgQ1zvi2QXmv/8yWXpTTmh1wLqIxi/ulzH9W3xc3l7/BjUOG q4xmfrnti/EPjLXUVa9ciZ7gpyptsqNjMhg7y961n4OzEQGsIA2QlxK3KZw1tdeR Du9Ab21cO72h2fviyy52QNI6uyy/FgvqvQNbTpg6Ku0FUAcVkzxzOZGUWkgOxtNK Aa9mObm9QjQc2wgD80D8EuiuPKuK1ftyeWSm4w5VsTuVP61gM2eKrLanXPDtWlIb 1GHhJRLmB7WqlLLwKPZhJl5VHPgB63dx -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG+TCCBOGgAwIBAgIQDwUv1kqXXvH7DpFh+zsqqjANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg RzQwHhcNMjAwOTI0MDAwMDAwWhcNMzAwOTIzMjM1OTU5WjBaMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTQwMgYDVQQDEytEaWdpQ2VydCBUcnVz dGVkIEc0IFRMUyBSU0EgU0hBMzg0IDIwMjAgQ0ExMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA8H+0pAPB49e6lFDVDHeV8Q+TLQQUhbPh3vAOcTpY8ARz ugXJflej7vfGTk6Ba4fkFcLPE7I7hfT+Nx4l6uqZAZBqLLMNwVHBY5w2jzFu9N89 1nxbGEzqxRbuDdWVlzJXdM7jzI47wBxkirqRr20sy7lmDZiaMGDIlRbydtbh7NOU J7oFDHcVQYpCAybsk7o78yXmbCyCkAAf9MPT1HTP8C6Kz3mP/TVgFYcCXR05nnDc l/RtPwwcY6fc6hNIdspeCUZGVFhP6U8N3rMVXae9FyCFH3x/Yh6mnRIwJbdRVvSN qXeXaG9LAKJiuG4nLXKcfEaVMqAhIrVdSTrIYZHEq0NsR4Zv6W7doGDGNeF3s7yx 0rVb3LHsKqfcMwnRPBvPUw38E6maUGH7J6CCvjOD1lW8wGvshKKQczmPQUUxy0mM lhSLDebBt56WB3nIHLlesftP9Lh6mXYxPujPm4v69f/cgzjI+csbDLwc9kTgUoYd NtrSlbuntJWXntQicwAcBmhyjeI1QjlahOR4ft0CeC4vnlonSyOq1ZHTK4zuJX14 yLMOMqdj8wb/ibOXfC0zSYuGjpc820DPBfdkOYHDHETPp+YNyKvbdkW0nbvMJcqz nKsoovU53OteAvDjKmjc08A7NJeVkX65VkRVXzs4etMHIplGhWJtU1pnKpLlh5UC AwEAAaOCAbEwggGtMB0GA1UdDgQWBBS2bDknVs6XWn4YnAoTssGhbLgauzAfBgNV HSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAw dwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy dC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E aWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MH0GA1UdHwR2MHQwOKA2oDSGMmh0dHA6 Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMDig NqA0hjJodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v dEc0LmNybDAwBgNVHSAEKTAnMAcGBWeBDAEBMAgGBmeBDAECATAIBgZngQwBAgIw CAYGZ4EMAQIDMA0GCSqGSIb3DQEBDAUAA4ICAQCI9leyFDgwWKUZECI9A0Ttsvlk fo/R4Do6eo8yuJA0FGtHKUdvpaHMLD3oDFKPJjuRHhfNO7lBpwTHTE9WDFG7Wdh3 UuiSpbJBLABJMBwj7XbLI6ciGgzd7zNBgqresB8kArJ2qTJXHPxtRbMjOOv4TaSE cjbkAyIOLBo0dL13vOhEzPxi+2Dqqi7DC8kw/+LZm+d8CHH2jnqwhBeMG5K6k3tP nZmrlnQAj2qKTv22KVqXKyxx9bn/QdMUcXNJ5OMAJi9rOMQvqh2TW+QpOcBVGxxZ pMFYndoFiJBthqbTpLMZFaCN3F2rzJEjRk24UZYbsxN6gcq9uXziFhjwt26cTPwx +csvHm4g22lG7KDNQUe2yulJjrz5Qwo7N1qmAvpkBafaivtigMbwsaNTxxhJRBbK i2CDI2GgfCvxrkEbISL0kxZuLTl76hjlcQDNrd4AWFa5mchZ5p3U/U0J+S0TvIWR pZw2cxR+g8gmGIyLLrN4v4KJetAs/5EnPkOMvi8JOjO2DM8flYanxsVEQvRpv3fV +sEKQ7l/bnYplNPvp9wFdK1x+GFA0A756En4RkfOO6ebSGgM1k4gObZPo8WZbas+ oZ2V7tMc5wN4YPVqbt2kEgUG4YW27OgseUJncJqu0oQwDaQO5bPmKKT5Zcv3HdgL p7NpKJOLg+y/3BOqYA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE2jCCA8KgAwIBAgIQCuhT5kpmdr7njBXR9vj4rTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0yMDA5MjQwMDAwMDBaFw0zMDA5MjMyMzU5NTlaMD8xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxCbG9vbWJlcmcgTFAxGTAXBgNVBAMTEEJsb29tYmVyZyBUTFMg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJcDijY9lVPNHXr40U fWUUv4cMQkBeohKE9pni9BQBfQMaaYCv9wtpBI0vJU+w0HuvpbcNMcB730hm0999 WkAJiDWjrezjiv8CgBbRwZf0V1xP6JXzkLwfF0Qa3+kfNlAkl5F07AjUUVawB+mX EK5opgeZrn/7BID0nwCTcjcNIqJEonyqHDuDnGcJt2cJKDg3uCXtZGf2dFk19VOH 9fTljK75cB6NG7YSMRkAGdKNElwOAOrJHlikHvheos0749M/tfPTpc2diDjxVVb3 YIsfyOfJwDq2Hml2OzxfWBSh6i1Z56vcdYwgCrOJu7LDHOPsTTRJoORvC14tVo/h +S+XAgMBAAGjggGuMIIBqjAdBgNVHQ4EFgQUYSm11Fct0Af3RKwqrtH9e0Ay7qEw HwYDVR0jBBgwFoAUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGG MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/ AgEAMHYGCCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln aWNlcnQuY29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j b20vRGlnaUNlcnRHbG9iYWxSb290RzIuY3J0MHsGA1UdHwR0MHIwN6A1oDOGMWh0 dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmww N6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJv b3RHMi5jcmwwMAYDVR0gBCkwJzAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQIC MAgGBmeBDAECAzANBgkqhkiG9w0BAQsFAAOCAQEAsoSMFjdqiXkJD91uX518TfU5 WFrcVOxi3pBB007sHVOsvkrdhMU6zGe3E4czk1dNfLXyTJd4t2V1/D5u3KFuHlzD KU0ldfxB56m28b3z+mSC1tRIb30I3gy3r16vDBDhxsZxkTeYzXQNTtsdieh/jWR8 mGJzl0QnI1q8Tm7Pt6VArACMUrXCbnvHXcOhp9Ls2aU8pO5dcuEKeyT/ss9ZDLOw t2nYIF+/lZY29HkBLb7Kci1yR3veu5cYINB60dR4f1N8S2YBEGC0u5KWxD2JPqrM RbTOABfjM6l0hjAU0E90EcDVorxFGU5Uaj8XjXhabrN1LIoVHrfU8xVSWO+brQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE4TCCA8mgAwIBAgIQDCGuyojk9pVYqb7P9qDRmTANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDA5MjQwMDAwMDBaFw0yNjA3MTIxMjI4MjhaMEYxCzAJBgNVBAYTAlVT MRwwGgYDVQQKExNDaXNjbyBTeXN0ZW1zLCBJbmMuMRkwFwYDVQQDExBDaXNjbyBN ZXJha2kgQ0EyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwGfNdt1y yX9WfnM6bYw/xZIgfUNWt+6xuWtVZxhu0DkYNtrphYla0oTIJiBYHYNNG4SBzBec /5fmimEo+YVbw3U7t0g/lMAoRk0YJ1oNKVOK19E8wHlQGcPjb4y9RytyKKLCcDvo mnYJcNCRq4hwzVA1CZDLg5glszPb/bTlfmBGY6MqBOOQratjsVnPE7QaQr9h78kJ P6dcbYfJyOLJctJvnYWf+QXi3QP9TTai/ikz6AMxt+4PHBqfRcQp/Z/RZuPKG0de n9iJgvUX+JQMn+I/JxXRQmAzgCydDsgFv84quOzOdhY3eRymrA2F3Wb7Cq9Ddcpm WzRmTrVT5GxzawIDAQABo4IBrjCCAaowHQYDVR0OBBYEFCNO2cJ3aEC3EM6upNLQ Z0t56DBbMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4GA1UdDwEB /wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/ BAgwBgEB/wIBADB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v Y3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2NhY2VydHMuZGln aWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNydDB7BgNVHR8EdDByMDeg NaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290 Q0EuY3JsMDegNaAzhjFodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRH bG9iYWxSb290Q0EuY3JsMDAGA1UdIAQpMCcwBwYFZ4EMAQEwCAYGZ4EMAQIBMAgG BmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEBAH90J3BWXtMBsVJ/ 6+0xBW0mhjsmi+laauAOKGyBolvD7B53CqIMImApPkk5CJxvBBgjJtRwCqMwShBp NbvHueYXrzFWkt9TzuGTzdBq87Sw1QLun5TWUT7NpuO2Qs24sSU0Cog5u9pHURR7 vS5m8Azek4d03mOCZBEN6K4S4mU4V510P/u3Rzr4yekPPw/AzkkkcoaNGyuSleAk FWLOuqVn+/9y8g7NVxerX6nSvqez7WsZIZ7RdkxGvDmUA4AGJWJX2IdXCQr3BEAe qx18/6pG8pFuEqRvD5AX5WsBj3zc5DgOu0oSobMA9jslKNBlkDxc1T1EHZLK4HcE 6VwZWG0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE1TCCA72gAwIBAgIQCysJJAQBl9qEk/bL8ArZ1TANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw MDkyNDAwMDAwMFoXDTI1MDUxMTIzNTk1OVowWzELMAkGA1UEBhMCVVMxFTATBgNV BAoTDERpZ2lDZXJ0IEluYzE1MDMGA1UEAxMsRGlnaUNlcnQgQmFsdGltb3JlIFNN SU1FIFJTQSBTSEEyNTYgMjAyMCBDQTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCzAc+Sre+znybM+vw7GsxfKZC4vk//qw6+Ri9l33MBoiY2KqWY6KWr PaHnCK/oa0xqmgaDckTcNSdrvPSRsteP0OrF9sTzoPK16oWEhYvagyEwbYjobAU5 0fRpGY8DCzkU0LN1fi765PYlbauwJ2Zp9Hyhrtb+/KVWrjOHaPIvHekcqDcRY8Mf zraSua3B4raeMlXoZ2f7Q31ap3eoi6hNAb1GVYsAG1rqV+f3U3zC1lpDSUSV5iXz fa8pIqLbj975t0ArWbn0ta3ZLSn6syyEIN9a1ITVUhBgWIwj1aHoKZD04mKLlIby TYpQkN+dihqxeLboYqknGoTB536vrM9fAgMBAAGjggGUMIIBkDAdBgNVHQ4EFgQU g5pV3UIHHTsE8sJISmWe4/4sIrUwHwYDVR0jBBgwFoAU5Z1ZMIJHWMys+ghUNoZ7 OrUETfAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDBDASBgNVHRMBAf8ECDAGAQH/AgEAMHkGCCsGAQUFBwEBBG0wazAkBggrBgEF BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRw Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vQmFsdGltb3JlQ3liZXJUcnVzdFJvb3Qu Y3J0MGsGA1UdHwRkMGIwL6AtoCuGKWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9P bW5pcm9vdDIwMjUuY3JsMC+gLaArhilodHRwOi8vY3JsNC5kaWdpY2VydC5jb20v T21uaXJvb3QyMDI1LmNybDAjBgNVHSAEHDAaMAsGCWCGSAGG/WwEATALBglghkgB hv1sBAIwDQYJKoZIhvcNAQELBQADggEBAAwdtDt76nSCMj+iYFI6Vc3Q40l97V98 rSV+XWMzjN5UkToYii9A/dedtywtMzbTKMdAc+na41CRpmQxNrF7MOexa3wn5YlD 7VsjDqyjOrHnHcyEJmofkKBCkZp+58Bh5WR0sE5IEFVwUTUI4ysPabrVH5ktYZhE BsVda5D+gm8efODq+nlpo3wnBaW8npGvXnNqxFj1VAUnijbSN2OvtzyPYoACPwEy MffP2mlhQkwO4GV39eFaS8AFhxCjLiNs7G7OvwQoBhIML39InIMWO6KnfxCQOHHj sEcpCSu5LC6Jv4VQjvvPXaNVFCuBd8DD2zADIbkxqlPPgQJrpHckh/E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFEDCCA/igAwIBAgIQBiBJfLntFNoOiPWuKG+WqDANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMDkyNDAwMDAwMFoXDTI1MDUxOTIzNTk1OVowTDEL MAkGA1UEBhMCVVMxEzARBgNVBAoTClBsZXgsIEluYy4xKDAmBgNVBAMTH1BsZXgg RGV2aWNlcyBIaWdoIEFzc3VyYW5jZSBDQTMwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDINYhtcvGtW+6h+j5YDn3nTkalb0NF+IZKn331NZDsqAD3X8Ax Wo6/a2ANgYtIQJvcL3m1luU0rmIWVCIuigTKlGEXSS+y12v7C9t2vwpoJsnQ0B/3 MSY4XHFY23iI6itHmTg/i0BjpzcKHzrPtL5a1er8ykMhDOJJqBqJ6gBZbdSukr68 Bwno4V1WseRzv4tyJJPyJSNE/DtaFWKEjYmF1mFxyocTdcb+d9XrBYxGcJn7ap6U 4Sp1NDZXJVpI2tu/VLnW2b8e1bR/H1xoVfwpaY7+aTmiCGLFnpwnU3BXq0yEDx3U LZcyttiLLpqSGjq1ar2HJeAYW0AIWp9+HK2XAgMBAAGjggHMMIIByDAdBgNVHQ4E FgQU8D+toY17ddQeuPWGYv9VaL3hjV4wHwYDVR0jBBgwFoAUsT7DaQP4v0cB1Jgm GggC72NkK8MwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr BgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMH8GCCsGAQUFBwEBBHMwcTAkBggr BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEkGCCsGAQUFBzAChj1o dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNl RVZSb290Q0EuY3J0MIGPBgNVHR8EgYcwgYQwQKA+oDyGOmh0dHA6Ly9jcmwzLmRp Z2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwQKA+ oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFu Y2VFVlJvb3RDQS5jcmwwMAYDVR0gBCkwJzAHBgVngQwBATAIBgZngQwBAgEwCAYG Z4EMAQICMAgGBmeBDAECAzANBgkqhkiG9w0BAQsFAAOCAQEAs/lybvFmxpIgHmK4 Bump8Ucli2C+Nzob/HAsHQ9p+GWYn3gSqEse2IkIfxdTVXm4bas/i5VXqPmUSEWw NvCO0gouBTRs8ai0c9Z1mR/ytxSfZc7W2DyvqSrmkQXQIxpDzEfJR8WyZElx22Ue fNV8o4J0Vx2nRutWYyMU+Gst/2CnHTf6PczYoNNzdrm9Amgq+22BHQwaJJvpwuk1 vof0ZjjsI/ILnbEGUN79gn8UvkeWpqeX43iY9OQnLB9g+6f1Rd+ca+alXAK1/rbQ fMUrXFCdP2AjSMu3GJZK90APWW6pdwVhfVTjUANseMltj+HiNHuHeXY0vFgVWHyO r1/aew== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF7jCCA9agAwIBAgIQEVTFPTSIGxR3ay7Ox+7xoDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw OTI1MDAwMDAwWhcNMzAwOTI1MjM1OTU5WjBTMQswCQYDVQQGEwJVUzEoMCYGA1UE ChMfSU5URUdSSVRZIFNlY3VyaXR5IFNlcnZpY2VzIExMQzEaMBgGA1UEAxMRSVNT QXV0aCBSU0EgRVYgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCD l8mMTBYN1meCFb0vNyq+Czz2h2eda8PKf2TGarVbkaPp+HJ91LADvSqSIEn+IAxd jlZsfj6sO8y+yXW3gGEe64dMNWFfzjn5EeXpzHXS7i5TW+zJsURa9XrP16h2oCpp D5HlZCEF6nf4ssqLgmE13kl7bTsZjtvI+ZE1uZgPW+4cLNgL69LtiZBXIO6cAY0q mjFWUJUEqCJ/hu2dwEydui+8afuXyq6ZXQ7rtwWp9xw5nYTMHwh81HJw+3QnLREp dL+Volot54KEx75nOl330QArY5DqEUkbJg1anO8VnbGolGqzlTgGChPB103Q0s3n cGedl+ibewH1MX6hMr5XAgMBAAGjggGGMIIBgjAfBgNVHSMEGDAWgBRTeb9aqitK z1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUcATo5D+MKMhDtiYoN3jOCS27MaEwDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIB FhdodHRwczovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRw Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1 dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUFBzAChi5odHRwOi8v Y3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUF BzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4IC AQAl8UQVTNcAXUqq8/naxOaLZmR33sIiDCB/+9ELHNZMn9IgjWP6mVNdBKSVguOg QEVphTIWvtvzLH9okhxjmSkD2CpRg5pD12gFNwcv8irKr1WF8VvlhwNsJA2REkTH eRJoCqyRuuBqO4NcknV47uLu72RAuZk3bD8vZ6Xu6DWPNmfrI2H6a+kNYWsNXyhA +fw+pHOEbbLwv3FYAJygarAJAK04QAWFZ0s4GU7eueMliMWQ0V85JEXNDK7JoP2/ drY1ozl2iPCqtp1t7eweNFSZ/Al2xdCAoK3HA5Rex/488AOABKlv0olcZWWJFUSI 5Az6oFZ5OEpVpnHRWff+xCNOQ2HQXbua1LyDVZh8Lo1aI4/gdr8kA1qqICteNj27 TQt4711R46CUKu/RcescyGEB81ilfdWL2YvrLhZW1MHdHM0ALO1eMqT93fpfuhyv 71hCS2diRSLBqut1i3oZy5JjXx4cVFt7ESxRp49ZalTQMJoECR+TGQq19wSUHvbx Emi8DvvzkfdaiyZ6Y8LxTM8JVmH//wqSWmk7bsX3ToHDKK7TsswAhv5mrnJHugJj dyUQs2JFanV16jXoBT9vRbjghm7CWZF6uYGV+fQLfaSOm0PJA05G/Hz0yHAmp0Kh skr9TK2vQhCsJ3tKAyS5ppHt7Frw0q3Psus/3cQ3ZvKZkQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFBTCCA+2gAwIBAgIQAenf+vK0K/oftv6tA+j3LDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwOTI1MDAwMDAwWhcNMzAwOTI0MjM1OTU5WjBLMQswCQYDVQQG EwJVUzETMBEGA1UEChMKRmFubmllIE1hZTEnMCUGA1UEAxMeRmFubmllIE1hZSBT aGFyZWQgT25saW5lIENBIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAzM/f/A2T+HQIP9XJ0BTWP9UvTveLTh9qgXLR/Eqfgnle96hnOKbQl1dh8EKo Iv918NQFIExgZ6CX1YRXXu3gYyRA1bY7N1zTI1HFgVx8esyMFePFwXJLDzrqJ99I cEwokt1oC2uuRAXRxxS9Vw7tynZfr06FNRZZKa68qBKdGqicyXAC/Vl0Atf4uvbp mhGoT9WX7sUEdp4WxnZcDHHZSFEwFcDZBT03J25JQoD4YisNTTJ/PLZXkRqkNDgB ZqWLNMZXwaXMGZi3gbcMIgRtw3S6QF8gSlcFKCGNUthJike7BmceZJMZkooY5cp3 virSdZdN7ha3GZQzigx6qxgOlQIDAQABo4IByTCCAcUwHQYDVR0OBBYEFP8tLpE0 /PLPxtGc0fkpN62qysFSMB8GA1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWXNqfW MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw EgYDVR0TAQH/BAgwBgEB/wIBADB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGG GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2Nh Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNydDCB gQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lD ZXJ0QXNzdXJlZElEUm9vdEcyLmNybDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNl cnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNybDAWBgNVHSAEDzANMAsG CWCGSAGG/WwEAjApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRRGlnaUNlcnRQS0kt My0yMzgwDQYJKoZIhvcNAQELBQADggEBAEzaEH9zLxs6KK3byoHA0uFcORmBD+5q nmR228ZbDhU7LfnTH0tg1b/XiR7fRxdrp7iCzySpkCgiV9PSjadQSRe45+FKRNEV Nos+gxfGAMd6BB0qmIcgXEbgLcvZCMu+geZs+tfzKVjLER4gnw2rz1yglnV03nwD GCHMi94wvBCg/UjyFnO8nq5t2UH8jeKnlXdecFk4AcaRtANRkyECvfvtdXYa/VJ8 zehP4g87ahN+tXIybnG7ZstVIPmXfwXzVs/Nht1zHNW+JrbhnkvBXk1yC7XnzQdP gPBLVb3iYahaDY3YSP4TpdVbldDdjMBiRHxHG36lEXABP/ScuRZ04pg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAwmgAwIBAgIRAKcjdcSRMbRQ+7bdSWoKyHYwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDky NTAwMDAwMFoXDTMwMDkyNTIzNTk1OVowUzELMAkGA1UEBhMCVVMxKDAmBgNVBAoT H0lOVEVHUklUWSBTZWN1cml0eSBTZXJ2aWNlcyBMTEMxGjAYBgNVBAMTEUlTU0F1 dGggRUNDIEVWIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmfj63qeyii9l yEii1MoIMhsLgr19J4JX7srE9r+Wk5EbC+tS8c9MHJa4lyCvdG34DMu3C20L6zuv 2pI8EYs/7KOCAYYwggGCMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2Oa MB0GA1UdDgQWBBTYFOMkVbt+KKkT/ttnmQvOdsiPnjAOBgNVHQ8BAf8EBAMCAYYw EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2Vj dGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBx BggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0 LmNvbS9VU0VSVHJ1c3RFQ0NBQUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9v Y3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaQAwZgIxAKF0oRaMchuAPyqk IwJQcEci/+LhrPwnOYX0Q5Oj3M/2Vt/uHd+JfUvKq5GoFfHE8gIxANrPMe4cPUpd iz0DHKAyt6cE5zSp38rvkaO4Sr7O/Szu2lF/fihR/GCxjumd3vDECw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5jCCA86gAwIBAgIQDxcaSMbyI4CSGM0u1t3A6DANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMDA5MjUwMDAwMDBaFw0zMDA5MjQyMzU5NTlaMEsxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJTAjBgNVBAMTHERpZ2lDZXJ0IENsb3Vk IFNlcnZpY2VzIENBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDR rfaHFHlUJ1fHLwVoPJs8zWfsRRAshPKkR8TZU0JFCbvk/jPB17xGL9GL5re1Z3h8 anC+/bjltlTPTF6suCJ0c1UpCHPIZPfQlQkOeYNQv1/11MybQmGOgAS5QarOThKZ m6zWxb5bAnO1FqSrcWLUmOpAOYWm9rsv6OeHwov2nDLN7Pg+v4nndCOCS9rqv3Om JTz9v6nlaP/4MKJgxzsuo/PFfzs7/Q8xoXx0D9C/FMS9aPGl52un35sAfkYlTubo E/P2BsfUbwsnIEJdYbw/YNJ8lnLJfLCL//lIBVME+iKvt81RXW3dkHQD8DNP9MfA PlZGR69zIIvcej6j8l3/AgMBAAGjggGuMIIBqjAdBgNVHQ4EFgQU3VHQojFzqXOu j7QBfl2MV8uf8PcwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYD VR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNV HRMBAf8ECDAGAQH/AgEAMHYGCCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0 cDovL29jc3AuZGlnaWNlcnQuY29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0 cy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3J0MHsGA1UdHwR0 MHIwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2Jh bFJvb3RDQS5jcmwwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdp Q2VydEdsb2JhbFJvb3RDQS5jcmwwMAYDVR0gBCkwJzAHBgVngQwBATAIBgZngQwB AgEwCAYGZ4EMAQICMAgGBmeBDAECAzANBgkqhkiG9w0BAQsFAAOCAQEANJE52TD/ zFvmYQGp0P3ntVzclyqsN7Aga/s2SmhGoow32hcBWc6OVgQILYjXndBwRdTn6/97 nb+5a0sEfMoc7mto2ALmLim+XgZ6bg2nQX1A2lWYUoFou0YDHzGsKUNcLQOjoJU4 t9UMxv6+Je7RB77+j3mVmsNxBF13Q+LEHWiY+IJSazVqv7w73izbAFo6cF9sK0hp qdmSKdB/MNfnT9YF4/WYlyCwFhpaK3mPuU2XiOzGswPhMMRwgawnk4XTNemtHPSq fP/JzQHsefL75Tx5c8tHJAcp3C/QD+JcUUHocUPuW62x79wO9pNl5N5U4jIVFa4k x6pNQytYvwMPeg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2DCCA8CgAwIBAgIQBwBn96SGf7kziQ3aF1/EqjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw OTI1MDAwMDAwWhcNMzAwOTI1MjM1OTU5WjBTMQswCQYDVQQGEwJVUzEoMCYGA1UE ChMfSU5URUdSSVRZIFNlY3VyaXR5IFNlcnZpY2VzIExMQzEaMBgGA1UEAxMRSVNT QXV0aCBSU0EgRFYgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCE jt5e9I4KAXffZq9fgK+RQtonSvTlHwbsJGKgnpx/QkFl2GM4GMtsuGidTH18xhZS jRl5G/9x47tB4b8r5kXysnVuK5Z064ZQPM5SoN4k5HmQsOX8nCvRjdBAtsYUn7jn P/+ZMl5ngith0QLqsmNnLT18cpvuJrMGhkktZ814sD4paKi3hsXFgnVA5NwlCNWo bgWGDIl/2Mdw4AnUzRvE3j7JxgbZNtwSdXW4B8qu4714X20B5jYlyYXwdDG4Ue6f kWFTnGs/aE4csx/bUjDyBg7ZEGhvsw1PEnye+DPLcOGJhFDUY1ijXW1ARZLQ9DzQ 63Oigzns+cW82XANNZa/AgMBAAGjggFwMIIBbDAfBgNVHSMEGDAWgBRTeb9aqitK z1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUSydKq9e+76j+Y4QOrVGhnVXDHG8wDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAlYwCAYGZ4EM AQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V U0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB AQRlMGMwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VS VHJ1c3RSU0FBQUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0 cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAFPVZXT7eqyYw3fhh8CejhJquTv7 fdZ0mrcQNccUnkzBXB1qz3mOV1Zmx7WHj9R41l8y+JZq66B4tDI4KJCEG/s6leL8 8EhEiZkXM7LN/H4uq32E+b04EW96XS4qPgzbHJ2S4DaiIQPb7o4RhBxBwHhbDcL1 bjrpfjNsAe/wBrIUWEZJ7mnAlY0zFzXo21z+AyeH5lFeF10JQmJS4R96SjMdrvVL X3aC3ARt1eCbM0sAJ6NlNjRC5ml/bgkzsCm8XVDiA3ahQnTPl5DDBhyzM33nwmkH Q/EMy4MqyP583wH0vbPSBou+uE9ea0Q4Fo3dYNahg+K54o00nP0N48xBmGp81f3m k/KY5X3sYufYX3PEnrukLGbzJb1lHgDPw5FHNPid9siijZ4RIYm16UVCbGFTNcxS IHXiOSTmNtrgxd6i7R6QXHpU9fpv3Mn8fli91cks4fx8xsLa62bwSQstIyDvaG/T Gap9o72fh9bdChS8xGQia9DEcrfd9Nh6l/g05PzS5QzaPTVWMM4q/LTtvytst/9D IPAV6+wAQrI/DUBpZU8xtlvBKW8YOltV9rhSr9n52sfDPXZ0ZKtIX677gp1HNkJ9 KlIH/LwZAIFBaxnYITnWMCge4hVqiIAFjj6GUZaQhFUwZYI9t1DCqXtBATEq5vv5 G1z6mNT4uET4WMSM -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDbDCCAvKgAwIBAgIQA8K3gYaTSmChwcXJ7lTTmjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAwOTI1 MDAwMDAwWhcNMzAwOTI1MjM1OTU5WjBTMQswCQYDVQQGEwJVUzEoMCYGA1UEChMf SU5URUdSSVRZIFNlY3VyaXR5IFNlcnZpY2VzIExMQzEaMBgGA1UEAxMRSVNTQXV0 aCBFQ0MgRFYgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQmNgLnSddakVhi 2gyfVILdnHEu038kVVUf1dlWYI7puHkPKNn4BPGMBSAr/T1q5CgD0sta2mwSYKo8 vwO6FQgEo4IBcDCCAWwwHwYDVR0jBBgwFoAUOuEJhtTPGcKWdnRJdtzgNcZjY5ow HQYDVR0OBBYEFCAvDl2owfjtP1XhSCaILbg4BRqMMA4GA1UdDwEB/wQEAwIBhjAS BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD AjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgJWMAgGBmeBDAECATBQBgNVHR8ESTBH MEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2Vy dGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUF BzAChi5odHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQUFBQ0Eu Y3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqG SM49BAMDA2gAMGUCMA6w8fsyHnuld0rXW1unoww4ngXTje5bFu0vJi4ocuAP+QgE RWPIX78Z3WTp+DvKTQIxAPacRdzcirqQgyYAt5w11joVz3qJsy0pijclFfo6RrXx 5UcQJniWGn9/C9ta8tOfcg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2DCCA8CgAwIBAgIQcJdvE3juyOY39YqHZcA/BjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw OTI1MDAwMDAwWhcNMzAwOTI1MjM1OTU5WjBTMQswCQYDVQQGEwJVUzEoMCYGA1UE ChMfSU5URUdSSVRZIFNlY3VyaXR5IFNlcnZpY2VzIExMQzEaMBgGA1UEAxMRSVNT QXV0aCBSU0EgT1YgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDq Kq8ZoiQhNuT3s5oIRg/AcFEjyORN3ndO8mlqXvDCjgL/7X8VuJVabWRaSAgttoQ6 nvmlmXEZLthBw9mJIE8XPShR53SX35PQHRDycueQK9mbJNIWTCdZXyX5KQmyg6J4 fsZd45Ds27sADf8xA5l62Kk14RDVhL+R4IYZlFNxV4QIBT0yZD3rRUMUGfzMsKaC 7PsVohUuIyUrZfd6JHcveQG/zI/RUJ7FpdKvjRbGOajMEFueIBe6tZrMjkoYdOVJ EHwxgXnjY0sE45sX7aEIFHRJ3YQsKG11QoIJ6THzjTwXeaS4zsRl7Yyb/EJUNXZh CWuFg/Ypnpc1/adZ/jv7AgMBAAGjggFwMIIBbDAfBgNVHSMEGDAWgBRTeb9aqitK z1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUgDr+FzBsS9PKFFihRtp5M823QScwDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAlYwCAYGZ4EM AQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V U0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB AQRlMGMwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VS VHJ1c3RSU0FBQUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0 cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAHKBSc5Q90rinhHsb6S2boH0Ag+g yftuumXaO/LpgIAr6XIbwQBUZ6d8nRJuB5+USvb7M9RHUIIdZ4sg8GNWXonI8H6S KdtZ8k5TvCG0VfIjWoSNfHyzXlPErij4sRa69m/RYpkVFiKqZ1HAoeLXz/BQkNPz 9MWVUMomg1tmSp/frNF5V34dLGMUIxu9ImozX+iZUM8JY4BIPB5znRquQW3if35x tQz/wIRy6tBWrQsFUka7naRo6zAXqqMplY5GQeh/QNU57CmfHqXN2323UcAUU7dI dgZNFZiblH6GToLl9vW/pVtwxwE/y7uLs79pzEmejA0jis5QLoMycApRifaRWWqG oqfNqFH8C79lDmi2/y3A+KrUxoqq3N+3OWFXRa27VqbTOlCLYgPabTGHOMEfVRRA Vk3PVBHVrbUZ/XSVajfE32uFW2nF3fYVey+iIfnthKvvN4AyZCLzFQ/nXe0Jw9jE ehyl5AEIjmjCpEv1P8ykhDf6eRstOl0QB/WnTFlZRFf99mRB3oSfWGixmUph+rOJ IL0jRByzci6oWSPPSDJ+Bzi5EgJnE6CfwrmKXCf7+hyiBX4ioRB0sB1g/JEmgEF3 zhqizcRT6K7SP8gk4V5dLsmUo8sKnK3GG/lIeV0S3obsSS3msajVED3QeWt8TtxM MHLos6xuDHZDbE9Z -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFIjCCBAqgAwIBAgIQBbZnenLiGNMIJX5oMgDneTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwOTI1MDAwMDAwWhcNMzAwOTI0MjM1OTU5WjBoMQswCQYDVQQG EwJBVTEuMCwGA1UEChMlRnVqaSBYZXJveCBCdXNpbmVzc2ZvcmNlIFB0eS4gTGlt aXRlZDEpMCcGA1UEAxMgRnVqaSBYZXJveCBCdXNpbmVzc2ZvcmNlIENBIC0gRzIw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtvR5yv/E7+OrMhRShuAKj Iwt9vUyXo6UB4sy7hd1py6x5iAwXLBuWE0gERvIxTrYaViCS+3SM3ASb38iLaKR1 t/ITCnLq/wVQCr42qVyw4+CnbuzsHe3AyoyP0NZIigmf+WYSbkPslir98zJW+Y0l b9OEk+Ndxm+/004bClboPvk/dTHr0RbW73yuDUMCr4gUA9sF1grp7l226GR9C/R4 3I7RNwrEtKI23iy+u2elJeBXhDANUFoe19sXS3ylAvSllbXR8K8Sd1hvaaOCBfN/ 60k73QBJE24mpUESccsUJ4XU5CjSo1mcLeDTBBKBYQOZwxXpybhF/KXKZ+zdFQMx AgMBAAGjggHJMIIBxTAdBgNVHQ4EFgQUBNC9Wg8qL7URLgEXK7i/Udl47eAwHwYD VR0jBBgwFoAUzsNKuZlV8rjbYL+pfr1WtZc2p9YwDgYDVR0PAQH/BAQDAgGGMB0G A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDASBgNVHRMBAf8ECDAGAQH/AgEA MHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl cnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v RGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRo dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIu Y3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1 cmVkSURSb290RzIuY3JsMBYGA1UdIAQPMA0wCwYJYIZIAYb9bAQCMCkGA1UdEQQi MCCkHjAcMRowGAYDVQQDExFEaWdpQ2VydFBLSS0zLTIzNTANBgkqhkiG9w0BAQsF AAOCAQEAr9stwxJ0fxPWs4xqq59fQp7hoZ8ViVKUlZty7/+O8eNg9GkK7EqaDXdW LzojfnDyQbx1yFwy5fcFab/YsYzcgDjdvpfe3f/TZ+1yvxYLOTp1ouB3y02T5SCP k3det9dsOZeJGBQ21xkOqQz1ve+bYNnuN1Hjopp+piFGagaam7qTOlHcoFCTbDda l72HJTKZmhc+j8vBDBXEYefywXofBCtXdRjuCrjsYKMab3cr5CUZo5P5rn0AlnLT /57AJK6Dpsx+43JLjTXss6lr2SrfLWTwSWbp9lqQvayTjeAmPYWk4onKHxpU2stU 3ttX10B43u+Gdt+l88HkG2z1PE/LxQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFHDCCBASgAwIBAgIQBQ4ubkXGxYu0PqWEb82BqTANBgkqhkiG9w0BAQwFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwOTI1MDAwMDAwWhcNMzAwOTI0MjM1OTU5WjBiMQswCQYDVQQG EwJERTEjMCEGA1UEChMaRGFpaWNoaSBTYW5reW8gRXVyb3BlIEdtYkgxLjAsBgNV BAMTJURhaWljaGkgU2Fua3lvIEV1cm9wZSBHbWJIIElzc3VpbmcgQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCkJVrdYiOKBjjGy77AckEUouqFrBFh c+qXiePsbHDweul2/mKowBlWuoinfgpNPdnTz8wGVTZInzK7EyHPbcPXSqxEvL6a d0GmMOrVhem/WE4k6HXNxV2+DvaQtGLGImcUXS/u25myu4qYeNpeC3i7yL8TvcVy P5IRXtRMsW5FnZKgO9Hr0cM5qNcX03BvFJjiKt/v5SeAGOfJ7Id0a7b2v+yai8oD 8qszTc/IOKiCmdIIwHYnoirTiqAUJk1IzOhJ+xuimtlJa3dbOFZVIdrv1TeywB4r maP5383L5MrcMvPITLwd786ttxOWIdIQuLyv7+jUh7SvjIAfLRnHKfsnAgMBAAGj ggHJMIIBxTAdBgNVHQ4EFgQUvmgni//d+RHvRrfNE/ii0YmFZR8wHwYDVR0jBBgw FoAUzsNKuZlV8rjbYL+pfr1WtZc2p9YwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQW MBQGCCsGAQUFBwMCBggrBgEFBQcDBDASBgNVHRMBAf8ECDAGAQH/AgEAMHkGCCsG AQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t MEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl cnRBc3N1cmVkSURSb290RzIuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8v Y3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMDqg OKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS b290RzIuY3JsMBYGA1UdIAQPMA0wCwYJYIZIAYb9bAQCMCkGA1UdEQQiMCCkHjAc MRowGAYDVQQDExFEaWdpQ2VydFBLSS0zLTIzMzANBgkqhkiG9w0BAQwFAAOCAQEA XzsvwdJgI6IukyF+lN40HHCLnJWJ9EZVLEF/wqr9ncGvXdt8a9Gtf/hwaLFplklP EvwjcFGCH83Tl//vQJrfLGq9ske63jm8s+cETiQ1fP3pyILejqFWFJTNJqRH6w1u GgHgIcu04HoYF+r0vLSReyXsfniz9/5wPENvewWus6nsc6GbUACet7FCS2ObD4zE CBRW/LvD9TKpgQtrtEq50p+0NBooRfVT65BE9AtLIDwI/JeezMid4Mzg8dkHrNfP qfT7A7xgUc//TodhCKqokKYt0+ClTU9Na3Fk6P9Zxsmk8ihajhD77XFxHjMOZqvz DZykz3vqebzu5N1E6Kfaag== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGTCCBAGgAwIBAgIQB6hTFlGn93i7ASjKbVF3rTANBgkqhkiG9w0BAQwFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwOTI1MDAwMDAwWhcNMzAwOTI0MjM1OTU5WjBfMQswCQYDVQQG EwJERTEfMB0GA1UEChMWT1NSQU0gQ29udGluZW50YWwgR21iSDEvMC0GA1UEAxMm T1NSQU0gQ29udGluZW50YWwgU2VjdXJlIEVtYWlsIENBIC0gRzIwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJpoC8dNec3LhIoBmFD34534lzKijfzBn+ YvcH079zhMFT9O3rLWOuwGzlDPuYrHZbFTDLlsbUwoFXyqADnWirWQQrTW9Srb6v NAAlwwbjJBtivhcMuxseHB6hxwiumqv+WkYsGo3fRkSmyxLYr125mNdDZvGSajRd s15PEUR/RaLc+FndoR6mbHLObZ5BaCYoDoA9130RV4KUdvK58mPGMcTP8C9hrk2A VS9iueVQvdkh3UWYqNr7y1JsNDTmFEDbCtUE6CFoZdM7QCvKaZfMYku0FG1BwD/9 w5VNo7U+tosOfcN23Trgdk1aBfexjqIfR5A2Jid9/0pqc/9Jjud5AgMBAAGjggHJ MIIBxTAdBgNVHQ4EFgQUr6Ru6XdRRlyyhUToXCoZE1/FZ2UwHwYDVR0jBBgwFoAU zsNKuZlV8rjbYL+pfr1WtZc2p9YwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG CCsGAQUFBwMCBggrBgEFBQcDBDASBgNVHRMBAf8ECDAGAQH/AgEAMHkGCCsGAQUF BwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMG CCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRB c3N1cmVkSURSb290RzIuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3Js My5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMDqgOKA2 hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290 RzIuY3JsMBYGA1UdIAQPMA0wCwYJYIZIAYb9bAQCMCkGA1UdEQQiMCCkHjAcMRow GAYDVQQDExFEaWdpQ2VydFBLSS0zLTIzMTANBgkqhkiG9w0BAQwFAAOCAQEAsPH7 WUHo2APrfRpu4cpgUjNRCtnJfB+w1x0BOKle3l5F3PohxtEyHLHIeDI6F0cuzDns 6EBA0nabA+0WVvvgVkaTzJh1FMZ/m4LG1PL5OwHlHYhHG2ynG71sXhofezwzCXkL 0fYCw8WGFr07vr+PpfmYKrGhIci9o7TfhrPucTVYoSNcUf+No6WN92E452B9hLY1 aZlud8KsoCjmk6O6aOT+9ZL3u/sBn4k4S+ZxawovI0nOU9QJ/YXw3xK+HAwvQuw+ Jfw70vTW/HpJF+DWXlxAgx8CJ7ZcDblmyBCrso/z3LWhVpuwcAYhOMWr7lyDdNn+ TMx/9QixlQcH/LkSGw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFIzCCBAugAwIBAgIQA5e1gY21ChdhRg3kGfhJjzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwOTI1MDAwMDAwWhcNMzAwOTI0MjM1OTU5WjBpMQswCQYDVQQG EwJVUzElMCMGA1UEChMcSG9uZXl3ZWxsIEludGVybmF0aW9uYWwgSW5jLjEzMDEG A1UEAxMqSG9uZXl3ZWxsIEludGVybmF0aW9uYWwgQ28tYnJhbmRlZCBDQSAtIEcy MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlQ2/IMA+u1kKfGXq8wLK eEyH7cxhITehZ6oNWcibV1sKHLHZPcThItC3wp+dFLdO0kB+vgZKyt+wSjbOdA6+ nPuCCT8nKggT8kVp+rLWIt5Hys85rWy6MqqCcCvxdIRv0KoVwPv0k7edZs1QPHL6 XSZQrMjRXj3BdXbnuwwkdnCA+ksGgMucYNXapzK9fRtTbxzyquQ9mmovskzULLAf QLmVTALE4bVFkZA2k42eD5mHV+NmQeZg0Iw+TR65rGtI7j68QB78FayW7WdueRvp bXZdATik546VKuKz7cHQB4KPi4L91AwG6f4G8+71PCngjcG0E8e9ghF/H1i1JrpZ BwIDAQABo4IByTCCAcUwHQYDVR0OBBYEFEWZtL9DBSlo6Z1zN9bOD6Yq/s8EMB8G A1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWXNqfWMA4GA1UdDwEB/wQEAwIBhjAd BgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwEgYDVR0TAQH/BAgwBgEB/wIB ADB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2lj ZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29t L0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNydDCBgQYDVR0fBHoweDA6oDigNoY0 aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcy LmNybDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNz dXJlZElEUm9vdEcyLmNybDAWBgNVHSAEDzANMAsGCWCGSAGG/WwEAjApBgNVHREE IjAgpB4wHDEaMBgGA1UEAxMRRGlnaUNlcnRQS0ktMy0yMzkwDQYJKoZIhvcNAQEL BQADggEBACsX73EZ2n+j92wr/qoPkdnTjCg1mUfa7BR1qZ91jFqZvY/q6bg/szcm 3IVKRZzVB2DlOkcK3EqTeq6vYYMrS9DlDO+ukNzwHxP+CFlYagKH8B+V1ZncDG2L wdeR9fPG23tSAoVDwLzRMmGwmaA1b9ZnymMw5t+toYo2iFCyU5bg47gMcCuDC6Xd bqttOahP6NjLY1ARdHei4Y3td3kagC7FBWddo+3uyuAjHfm0kDy/bGTExK/4RqCv U4yYkT5yOmeQlWIaDcM+V4AGPQJwnpz4Muqx/6hqSJL+VLAmq3+tm1NDbgxLhJ1f FKORMxzUQFaqp3k2OtMz4BLNPAZvbWc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8jCCA9qgAwIBAgIQEAylgF2UktNyaT9N8tSsiDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw OTI1MDAwMDAwWhcNMzAwOTI1MjM1OTU5WjB3MQswCQYDVQQGEwJVUzEoMCYGA1UE ChMfSU5URUdSSVRZIFNlY3VyaXR5IFNlcnZpY2VzIExMQzE+MDwGA1UEAxM1SVNT QXV0aCBSU0EgQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBTZWN1cmUgRW1haWwg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCHf31FAS9pwJNndqzu Tp6C6Mf7YS+0D4g0RidOnQGNhfPxa+Q2FgxAvcLa7t1NEftUB+VPlOWXM3Aj/+Xz SinM/pHMgh282h2xw7vcNbWZt2cuFfb5vKdLTVz/xRf2P4TVOoy05hEa77VKswsy O6dBZT1ff2S1LTmwibdNre0dErJIx1vIyaec/AIDw2wlDTuV5i5r7H8Lb01lyr9S ei5T7fimVjnolyIaQl//zotb6Ip6rHcvW2QZQ9OHfmabk43rtB4pf3d01aRvCIZU kzvW691FbI6K5Sih0KiY892siCHqs2LHXmUmhG+MbUf8/gDPw/JYhoPdZEiDBf4h KLWPAgMBAAGjggFmMIIBYjAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNm yzAdBgNVHQ4EFgQUFBs7AdII5sDhmPvMCKSYl6aFuk8wDgYDVR0PAQH/BAQDAgGG MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF BwMEMBgGA1UdIAQRMA8wDQYLKwYBBAGyMQECAlYwUAYDVR0fBEkwRzBFoEOgQYY/ aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRp b25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA6BggrBgEFBQcwAoYuaHR0 cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUFBQUNBLmNydDAlBggr BgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwF AAOCAgEAa0Gn/7+hikV1B0d0uPnRSKDTmk6+Yz6Z0J+y2Yna53EFGn2F3ueE0ckh 7ipG7EFIMPzTewkZYX+y3v05Z52Nq565WWwIAYKLItP2/+Et9k0O+o01lYEV0X+K ecm4iOsS0x6JnpWT6sR95UV9ZFZ0GDv/FKYuFw6/vBbd5ATzyd12sBSQIBBsL/Zl B7XiLrmaJHIyCtFVpT9JSt+srs/cYLmMZWyojV42W/zJMcEPFmxv3wvwoOwaG9cY ZfMSKCtaMQNIDEmPqHlR3SV7+Q7g2ABrk1pTDHCmyitOuWwdilhK8UYCMa7RoYze PHLcGr0mNZGSApCK7ZBfUxqK5m1KZytOgbUE1uhHpFdDvJJE5O8+TN7oPBIPaCYU J9gTlQ0ksqXX2l2F+e+GuTbq2qJkHmSGqygVP9swwU6zRBfx0muoR5TEOPoomSDG hqZttHZBPtUKoMAIBsUUQ3RZVpRwkxE6zatOXWpT64t94IHm/2e3Tm+a6T6v6R4/ olOE8IDPgjFJnweLJ1zSU8AUn0MxUfkdVnpUk94DbZB4HyDtehwtWrbpY6IsY749 eaUmFsLeJDGVDT5+wIkHYO7vjRcKxphl63RF3eiNEJbqYGqwHAi0rOl8ffZBWBMc qDTmrU+BzTcJH7ehC6mNKMaOVBPgG4CxB/oiubhULTFM/66mYpE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFCjCCA/KgAwIBAgIQDkRPRcgzPCq2SNnSu5IKOTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwOTI1MDAwMDAwWhcNMzAwOTI0MjM1OTU5WjBQMQswCQYDVQQG EwJVUzEhMB8GA1UEChMYR2VuZXJhbCBFbGVjdHJpYyBDb21wYW55MR4wHAYDVQQD ExVHRSBTTUlNRSBJc3N1aW5nIENBIDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDGVWm8DdPWpEw59b0p8L1zyBqgioeaU/YVpbCg6ykbfNSL5hKVSGtJ Xkuc27jqteWVDinBstD1PeHH227wukI3bEYlvrMMiYfFZ+q7PnxD+RBUR36VoNcf bff5nJWAicbuoY6DvyqPl+JRqZgFj0v/hHGq25TEJhpW2OmPIPZPF258oYgsCswB 0OxMQKI6QBNoLNzeebsnBwt7YbWMwiCTWaqSqpoQVdK1jJjyQas7vxFU5AVhsGuI SsyvGBKfnZAu+alo7Tfjy7huXZ73vv8p4fUzjefLMYp7y+c6CeKaOkL8dE+CFVMQ RB4zhEaDxSICMu658aJeRg7C+ToKb8H7AgMBAAGjggHJMIIBxTAdBgNVHQ4EFgQU 6l22f92/7zCajVFWsMAXE3dqM5kwHwYDVR0jBBgwFoAUzsNKuZlV8rjbYL+pfr1W tZc2p9YwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDBDASBgNVHRMBAf8ECDAGAQH/AgEAMHkGCCsGAQUFBwEBBG0wazAkBggrBgEF BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRw Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIu Y3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v RGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMDqgOKA2hjRodHRwOi8vY3JsNC5k aWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290RzIuY3JsMBYGA1UdIAQP MA0wCwYJYIZIAYb9bAQCMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFEaWdpQ2Vy dFBLSS0zLTIzNDANBgkqhkiG9w0BAQsFAAOCAQEAXIR6NgNxzF/YkwUloQB1Ytxc usDtCnmiNS5I36sH2zjiGssT2iW57kUWTsMzKF3lAYXRXE0mGAkvvOJEY5zX4nsO zAbpbzThAaPBgJH957B/0rDA9WhCZ4Ap/Pxmy7eYvVl0355SSwgrb6+YQSgHr37X byTc1hnsYGsN3H2/pgBAaDGrv5O39Tkk9XH5XgfIvrINDZguSQMQQz3m5jD6aoNW pC3qZ6/nMffgl4q+YD8kbZwE0WWGkiXA5syrcTVym1XxdfrptwOXSWrdZ7S1Ye6/ 7mXrBuTYjdJuDw2/niLqh2IeyHA0n7MXgrTySpoGW9zT+bTzkCH4AkXpf0mTeg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGDCCBACgAwIBAgIQDs4EFJGIIQWkdw3RGaWQBDANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAwOTI1MDAwMDAwWhcNMzAwOTI0MjM1OTU5WjBeMQswCQYDVQQG EwJVUzEsMCoGA1UEChMjQ29tbW9uIFNlY3VyaXRpemF0aW9uIFNvbHV0aW9ucyBM TEMxITAfBgNVBAMTGENTUyBQdWJsaWMgSXNzdWluZyBDQSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKeJqEpnnc6MPDia9sC5lnPP91l4utq5q6V/ sm/UZjKe1IWZid2eX/3gvBSulbusQ4hStYx3uo9RkZ6igBtzA2vyN6brQp8+/LCB EiwBuBVqDaimXWC7iTHmHp0OyhEBhlnTr4PWZs3U2nQcBO3TEmzFB6T9HCwXSMyZ aUwNoh4/4poascC9ySWxHGNygqNgjItLhW0jxMc8b9oEGjXOcgTNBJrp41l5N1Kp XyTf3PRY4CxSwEgeUfTyLto7E6pdC3f7hq88y9g8oVTC14Xm16pC0ETrBYy6kwGd f0Qy6cbeb4Ri1vmnRE8Qdhg1CU749JjNCtcknK76mrKpdVdxrusCAwEAAaOCAckw ggHFMB0GA1UdDgQWBBQjebS6O0v/F5HlVzyQruvXgXoqwzAfBgNVHSMEGDAWgBTO w0q5mVXyuNtgv6l+vVa1lzan1jAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYI KwYBBQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYBAf8CAQAweQYIKwYBBQUH AQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYI KwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz c3VyZWRJRFJvb3RHMi5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwz LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwOqA4oDaG NGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RH Mi5jcmwwFgYDVR0gBA8wDTALBglghkgBhv1sBAIwKQYDVR0RBCIwIKQeMBwxGjAY BgNVBAMTEURpZ2lDZXJ0UEtJLTMtMjMyMA0GCSqGSIb3DQEBCwUAA4IBAQCOxm3L XrDEew+kbixvOmOLh6v8GdovYTLmaM+R+U+W4oVYaYpq5hL33lnAw8vsJWWVJp0X pB4OyVSk7g/QqZBO+Y4DV/yppBb1XDMuN1Xo4KjoIiO0AIoWmE0mfTLOstj2GPzP se/w4A+VdGRNgPkj6HNLqIE6DWFZy4NF+8mTv/4fZ3DJrmgfzY64m+K3bYXluICO BLcMnTupBkemtw5L/dmPt+wYDHQ3gaVMboUhXA/DIks252b+VEkXHLqB1zofAEa1 d89iYFXfpUuClPoGaQzkrc2biCJn1UwxxbiLMmCS8AZP0dDmNd+gK85Q5dGPs9yN 65+xkqbKO7IwxzDj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDbDCCAvOgAwIBAgIRAP/W2AxlInm3+tncBdKhGLQwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMDky NTAwMDAwMFoXDTMwMDkyNTIzNTk1OVowUzELMAkGA1UEBhMCVVMxKDAmBgNVBAoT H0lOVEVHUklUWSBTZWN1cml0eSBTZXJ2aWNlcyBMTEMxGjAYBgNVBAMTEUlTU0F1 dGggRUNDIE9WIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAET7WFoVKv4g1o zT8QFyZ3o3lL4g1FtdZEKTgwYIB/HDNvqF6W52ibgDOlU0KdwPj7ytsP7d39+KJJ Au9d4J13p6OCAXAwggFsMB8GA1UdIwQYMBaAFDrhCYbUzxnClnZ0SXbc4DXGY2Oa MB0GA1UdDgQWBBQvMLxuZxF8e+ghCmzv9xzh+bilCTAOBgNVHQ8BAf8EBAMCAYYw EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICVjAIBgZngQwBAgIwUAYDVR0fBEkw RzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0Nl cnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA6BggrBgEF BQcwAoYuaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FBQUNB LmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTAKBggq hkjOPQQDAwNnADBkAjBxabnQHJ68VrsI649pVjUNo0VN1XgtAVAs4ffPh3roWHYp ax4jAEK+XwSPcZzVU1ACMAGH7QmYqKkOoavmdAF9vx8x2LVoI3in0UPL6jVekE2h 4oUzJIfTgYi56vrBNjr1ew== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGyTCCBLGgAwIBAgIUcjtv5cJSdU0hibCRVVIaMYeRbbgwDQYJKoZIhvcNAQEL BQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZ BgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0yMDA5MjkxOTM1NDJaFw0zMDA5 MjcxOTM1NDJaMF0xCzAJBgNVBAYTAlVTMTAwLgYDVQQKDCdIeWRyYW50SUQgKEF2 YWxhbmNoZSBDbG91ZCBDb3Jwb3JhdGlvbikxHDAaBgNVBAMME0h5ZHJhbnRJRCBT U0wgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC5att6aX7K datB6wOwa1A6gkR/d5lIHnnsxy8ZEFT/VOo/TVVMfBWjAz1yq0+bMre+ijgZ3JQ3 R1sc16SeyvSDhnpH8WwNYCa9gg/2N4kq7xpvJs3rqgmQWNejYBSOfqCGSrbyts/U J1iiSQyDTIHHqvLg00Beugm7fiV4RplMumC2KK0B3pZbj5U/qc5wp2e1Mz5/q+S+ XqwS/uYH/Dl7IplBu458m8DjrteuS9wCGpnWW4du07yUIKlFQqD6n1optsEbr0zQ WOa/QGEnGOXVPiRXfMFbuzfNuSJ88JuRnkstp+jsEFQtC4AyXcTAEassmdk6rb6n 0Jdwze1oxiQsZn9q+4IsbMRPE2w+3CQVd4h6E8doXdzgu5d/BTnal2SuR0jMIsyS sOsxoEyuf7kfAQWBV/mPYDudteB5cVlbjNT5krHKeIeqJroYy+3q30x2eRgji77r 8eDwxGfHSPsinHhQoYiNWC2X0cN8LZw8Ba3+RkekrknBCeQ13JV2x0lVdQtTxTp+ cLhueUZ3orRzrsj0+lu1r06DFp+FYLQ2GSYtQivz8sMJ0fzTYlq/Vy15nIkRhJE3 xOjpfptTf3xr5yGUisMQ5LQSHR2lK/hqeRoo5mc3URwxuB1HMnjaN77JRG5jhLgq /sbxHyrdT/NVPhuX6dLzXVd1qKrgIN7dWwIDAQABo4IBlzCCAZMwEgYDVR0TAQH/ BAgwBgEB/wIBADAfBgNVHSMEGDAWgBQahGK8SEwzJQTU7tD2A8QZRtGUazByBggr BgEFBQcBAQRmMGQwNgYIKwYBBQUHMAKGKmh0dHA6Ly90cnVzdC5xdW92YWRpc2ds b2JhbC5jb20vcXZyY2EyLmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVv dmFkaXNnbG9iYWwuY29tMF8GA1UdIARYMFYwCAYGZ4EMAQICMEoGDCsGAQQBvlgA A4cEADA6MDgGCCsGAQUFBwIBFixodHRwczovL3d3dy5oeWRyYW50aWQuY29tL3N1 cHBvcnQvcmVwb3NpdG9yeTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEw OQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL2NybC5xdW92YWRpc2dsb2JhbC5jb20v cXZyY2EyLmNybDAdBgNVHQ4EFgQUzKLzOK32xVQnMkbFOV9JchMTgHkwDgYDVR0P AQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAKlx95q0w2rX6l/dWONsKj7yr2 SmafArwYZcC5FlHG0HcDeXABVD0yfOdFQw7CC1WjMbY4efAndKZ9f9ucSBP7u7wo ddpT4MFpWAqohtCZPQqE++Jn/q1eL7+Ed43PwBkoFNm0o1p+nBVbkC4C5rkToCq8 ppXcv8P5SL1Bpv8nATnzdHeZR2zreuGF6gfBCXe3QuczzjV+mXdfFbN+BovWxZii J8vUFq+Dc3uLo33UrSdJmzllc2Dr8VzTQUoQz0AXy6fYlg+Loc0cjEhOset/vwgW 6smNbKHJ65z2KUE6m2Bu/17z6KtaD2GzjI3LL8TjJgQyJAu8rCIR9TTArGwr1hFt Txz7dUk+dVw6PQivMGYiqf0gspKzGOqdV70kIvz4nnHsYQrl1u9hAnWROuASSCti tX4z++r4owzuL8bnauvDdReisTUhcovHWtRFvuHg1wqtbxEJTchIM9XKXobNfeM3 uJGJ1an8v5dbzSDhFHidq7xCN2O4giLpa7n6cpvC02TBuMXc1wf0pidqzxeENEM+ r+ZeiZkpt1s8jhzwTTwMaSPFjale/eKx07ppDalxltGJEZExYbHx0XJ6I4qOK/xL l69NrgFZk2uhcMvMplpSZb5SjXdZnpnF0J0AgcZAn/LpwSOAMUHyhL0B4Rag5xT4 aXiEWbYkhYIp9/UEqA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGWTCCBEGgAwIBAgIQJ2I3gEihs2KNUH4pIg3iIDANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAx MDA1MDAwMDAwWhcNMzUxMDA0MjM1OTU5WjBlMQswCQYDVQQGEwJFUzEcMBoGA1UE ChMTU2VjdGlnbyAoRXVyb3BlKSBTTDE4MDYGA1UEAxMvU2VjdGlnbyBRdWFsaWZp ZWQgV2Vic2l0ZSBBdXRoZW50aWNhdGlvbiBDQSBSMzUwggGiMA0GCSqGSIb3DQEB AQUAA4IBjwAwggGKAoIBgQDM22r2ErDUlj/oI7CQ6ex30UeqGqLXS9PBwLUcE7mj g7BLPEcXb1axVekRweC5IxEXsJrzrTc5Jqsk+idax7butIvU7TBP8YWxEPcZPj/w M07LEY4I51c/dJNBokyjJZttCejrQ/jYfHPaYsCP6NpHxnupjZoOKyFHIABxriY3 Mb77rEpP4gvxEC7OtBdV+AFQp4XBxIc29540tUs6lDbVc6NsjEgEWEnNMpQp07Mu wjDCypQrEtKaepo/iGUWwkecV662K8mifLTDRSDf+kF3m+kWZe2eylEPzH9hnOOG 7LF0ivpmjujwUJP0zs96KH98yWp1jDJdP1Y/k2h6tVPjV+RV/qd7HKr8E2RWwT+H vX+3OHjdn8B20+M2JEVsR7cJpTtcWznYGm4ZmbZ46o0kbVIFILTDBRLH64IIQcsY ObED5hjMJfqYaoLIPZI2DvFBdDLn2K6iYsgjowbGM+ZO5dDYtRZN9Mke14QPmNnM FvEhckY/h7h5ZP2qDdPuuWECAwEAAaOCAV8wggFbMB8GA1UdIwQYMBaAFFN5v1qq K0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTrNSUqBjbo1gHlaZOE0vMsO6zerzAO BgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwEQYDVR0gBAowCDAGBgRVHSAAMFAGA1UdHwRJMEcw RaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0 aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUH MAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBQUFDQS5j cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI hvcNAQEMBQADggIBAGBpLCiwnPEtnVgL81NkkYC/ZmwWOvc1vPPkia7EJALzPqnd +4EO/xMhkgY0zMz6YOxZYRM35Q1R2b4KQ+UnK7OZu6anT1sudlwAa8r56Y3UpfTd za6mQcyCn6rBdiYWHhE5QkSQmVa6eM1rQGK/N6Afl3oKLU83R+vwDdbUopEjlPws 0ZIqxjonmhox+MSCQVD303cPMNxwDIznQrAfQF5swgYepHQqXBihDrafYHQmrU2k LSLVMPFsx2FY936YypA6Wht8lOtC30NsZcp8cc31JoaIJHC9PYuU7iJqEBLR30sY uc7RrPIL/vcCAHjV5eVnV+yyFg0Sy+zDHs7kEkBRXIrv/AaHXKaZ87YugRyGWk3v d4w6ogGilUtMn673/5DbeeDmReXhHjZnfCd2v2eOGI8GYuEAlu6pp8Qfz+vDh+CQ sCeMs+QS31jLveOsnI93bAE8JU3rWFIlIB31jx2ecVerffb/8PfC1cSYGE/y8Yxq JBlkjZ2d4NV1kPOEYE332NnkGi0K3+Llnhbun/Qg/OasbYdwCII89G6tK/XhbklE O/Da2WbWbDzLuEOgXvTi01H8T5qAP6XY+ShBHmysuv36J6bkDHlkxCiyNB7PEzLM swjjSYsb3V6WCDopz9jbhfrXzDy+Tu/QO5y4nlWplvX/ZdOM6NMmf1pYg12r -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDbjCCAvSgAwIBAgIRAJ5WjSHe2JMHw0CA/y2ZWQEwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMTAw NTAwMDAwMFoXDTM1MTAwNDIzNTk1OVowZTELMAkGA1UEBhMCRVMxHDAaBgNVBAoT E1NlY3RpZ28gKEV1cm9wZSkgU0wxODA2BgNVBAMTL1NlY3RpZ28gUXVhbGlmaWVk IFdlYnNpdGUgQXV0aGVudGljYXRpb24gQ0EgRTM1MFkwEwYHKoZIzj0CAQYIKoZI zj0DAQcDQgAEoZ/maiXB18YoY6sIFi0kuyZTQltgwxwjnljRZ8u/VLF3L4b1NgZA lNTwGR1QLIYgGOBZx2k8c8r+E4wS3gARlaOCAV8wggFbMB8GA1UdIwQYMBaAFDrh CYbUzxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBQBELB9TETSoLJg+ejaffuKr56v WTAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAU BggrBgEFBQcDAQYIKwYBBQUHAwIwEQYDVR0gBAowCDAGBgRVHSAAMFAGA1UdHwRJ MEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0ND ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYIKwYB BQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBQUFD QS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYI KoZIzj0EAwMDaAAwZQIxAPdGdzU3wUj6nUMuGR88wpKNe8anlEp+iIkEqq9E4Trb /Vsl+0Kza3bZxD1+TpLXIwIwSn26MmiP43/g/EVOPLSG/jw9EEodK6gdSA8irfkW i7SmhFPLMduOCbAGR7MVbVBV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGwjCCBKqgAwIBAgIUSTmVZkbGVrI7R9bguTzB/P0h4y4wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0yMDEwMDUxMzQ2MjBaFw0z MDEwMDMxMzQ2MjBaMFgxCzAJBgNVBAYTAkJFMSUwIwYDVQQKDBxEaWdpQ2VydCBF dXJvcGUgQmVsZ2l1bSBCLlYuMSIwIAYDVQQDDBlpdHNtZSBTaWduIElzc3Vpbmcg Q0EgRzJ4MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlu2TxSZoibW8 vdeIWPSVR5RYmp0lEnYq6h4VaHl4MSvIJokk8cpi7ZrFJaIxJ/PfxJfjuiXKRxMM JSvplbAsWKrGWrjbKK1jUH2/Aw9nL1P59Tm0Blm0bJy1O4H7ZKsMQog9t5SD0Xh2 IxVJ6gtgPiM3COXTJTuBio0Max7zSa9JYoRuW0OVHaOImbarJdvBAHl1wSp84rsC qu5rub/F86X83KbJOZkGy1B7B7L4wZFi9FUbkUJtY1vxA3C02KRdiJ34vCiPnvfY DuEpZBDHs7V0gmvIOAfwfk7LrPE48M1FwSMV48yF1AUJVYffN5ngyFV39qpl3U/i xfM+Qrebbvzcqyei/u+bHm+n3u0dpgQ1nvmOYpoXSSNEZ1etRl97k1vCI3PRjson qBv829LaWPmk1or7xTZNUrCVEAwf04OkuxF4N5QeMBBY3TuwZ+4BQhIpBTQrl01S kYXlGhyGyQrUQ/Hm+HtNas3gPjCDqwTnUTiCRt3lPRiT28wIru0+vY3YLakAhuPY 7XfDHOxhdzVv0fzaanfU1chEaxNjw61mSFbGmm2dVVFWpG5pgfE8eHirEdDVdXSs Ek0FwtoupYwLzBCxJpFcQt4wxcCbGi25Khiz25FTRs5oQngBarALybiMG/QBWRqM Ut1u7OYZDfl8JNE1BRLD2kL5CWsklr0CAwEAAaOCAZIwggGOMBIGA1UdEwEB/wQI MAYBAf8CAQAwHwYDVR0jBBgwFoAUo5fW816iEOGrRZ88F2Q87gFwnMwwdAYIKwYB BQUHAQEEaDBmMDgGCCsGAQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9i YWwuY29tL3F2cmNhMWczLmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVv dmFkaXNnbG9iYWwuY29tMEoGA1UdIARDMEEwPwYEVR0gADA3MDUGCCsGAQUFBwIB FilodHRwczovL3d3dy5xdW92YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeTApBgNV HSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwwOwYDVR0fBDQw MjAwoC6gLIYqaHR0cDovL2NybC5xdW92YWRpc2dsb2JhbC5jb20vcXZyY2ExZzMu Y3JsMB0GA1UdDgQWBBQdO4P0uaVK8ck8pstGGhle3WtuijAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQELBQADggIBAH/52/7ZtE3AwoEt+5orHTxxJHNaUNU1fbBk SSGgcCxPfQsGEvmHGnb7OlAvCGujBvmtfrL7uuowHZx5H9BlNAaWRYQzkNjHwGfg THEulNPuXSd8pHsiZ8GL6PQnWnP0KJvWw2+4ISIGkrdrptV3i5PrlNNaDHu9Jrzo lGrPbOb8LQ9T+Jn7g5S89dvFNBTY/FqPZKnT6tEdOkMIiBz6ZORcq1gcZ0Rcebnf wSljmK64URSy57WW5kgs+apNGAv2e830gb5nUwwHYkehDrIva4563nBAKV+0AtLq ipvxiO/uUyho5b2/qn6Mn8VT+1gtGwZ1H0Z2XOP1RsvU5aagUSkHS0gtPdcudTZK Zx5seNtoj0pE7Q1Wgf8M84oAREUiMDiTGvxiFV0VR6hECXS2BJRHyzWZ8oMwizpC N1uBIk5eCOC4dB83CWDkpMXWgLGxuuSQqybUlVQfCirYh9JX8rZ/Rk4BZQrHUzYG wDuSH2wqoadTAvq4lse2dd3sIOHqAOudoNveS98XrPA6ODIHaLaV6d+cCVLOFFYb jm44b7oGiXQte2LaJxKOPgdiB1QGZwNBUmODOmeq4I78dSud7p1R1Vjh4j2G0lkY UdzOfYZdjSoP7ZW4WLuaGPzhHmnzX5vZg6RHljt1doDs87aVxB4RnynZrEGVW41L YLm1saaB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDeTCCAwCgAwIBAgIRALH9J5w/JzJRc1vki2qBYhUwCgYIKoZIzj0EAwMwgYgx CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIwMTAw NjAwMDAwMFoXDTMwMTAwNTIzNTk1OVowQzELMAkGA1UEBhMCQ1oxFjAUBgNVBAoT DUFscGlybyBzLnIuby4xHDAaBgNVBAMTE0FscGlyb1NTTCBFQ0MgT1YgQ0EwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAAQnYDEKjn3+/ntFRpiB28WqZYBDCielVDYg6DL9 US0UvSzFHDBUEfgjItAAEkryY4JyVhHlA14LVVx+L2J3pAn4zHSss6YwOsnD2xs8 E456uQ643bKRyrv0nDI9XBXraaijggFwMIIBbDAfBgNVHSMEGDAWgBQ64QmG1M8Z wpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQUfhRVXuIXlACjeufDmxtt/QK2DX8wDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGyMQECAlcwCAYGZ4EM AQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V U0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB AQRlMGMwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VS VHJ1c3RFQ0NBQUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0 cnVzdC5jb20wCgYIKoZIzj0EAwMDZwAwZAIwTLsepbhOBIyFfQg7S2QwSqAu2LKB cODA+dbhuqAZWAuskrBd7DYsKaQG856m4POiAjBti4lxOvE+zfeytds8XhIl6VTR vi2EqhwzeQbO/RlQZv6IklLHhczX11efJqclSlM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGyTCCBLGgAwIBAgIRAOi9aInk33lJILgXLp0lgCIwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MTAwNjAwMDAwMFoXDTMwMTAwNTIzNTk1OVowQzELMAkGA1UEBhMCQ1oxFjAUBgNV BAoTDUFscGlybyBzLnIuby4xHDAaBgNVBAMTE0FscGlyb1NTTCBSU0EgT1YgQ0Ew ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDZZxvWFwcj1gRBZ33vi5gQ cLrX8AhGSt5QpoBN1atdKXX0mspU62S+rf1Dq+IHk6o1VrZqICgi+0W5wkpoxNwW 1mRR9R8HHUyuOxUZMl9pQqiJPsJ2EMXVyaloN5ebvrqRWs3gRpdQt8iL97iaOPnV /J/MLNdM5byASOPgPrRtI+IS179kItbE5tp05C3ckxkNbTjcWKuBOYwvAg6JNuZN iCQS92SUfzlo77pvLCpy7sHjpeUowT1+yDiJ1CUg4Jswpj8BbmAVSRbkanK7nKOE 81mBmsGJzGA1EHb882sg2+igP5x9VZza57WRjG+RJ0o/xloj3UgQocndNa5titTO +2sb5px9SCkbthHcDXKKtYMYB6b6ZrHvX6CjWCOSHzCMHMDkLXnnWzy8iubCMd85 D10fcGB619E9BpxUylEwwY/qdRuDwVGhn/hGpTuP+XGSf0UNUh9xmwwoboBtHadW R4mNix1e0uBMpccGRo4l9Ev72ZQh/CjKIQkkW6797Q/Pt1L6gHEo09ytQg8nepoi L63Ddym6fu+6h43YhuI+/xOho6/eDKXRJFUwjurWnKTt7/xdSOgS1jFwr8cPNsP8 9RFKVA4U/l8/riWw6l87esSsMW1Igk/lnghheIalgEH0RYheYNm9siYDtTfgPnWZ 9LpSMbCzRobQz1XqQXTCJwIDAQABo4IBcDCCAWwwHwYDVR0jBBgwFoAUU3m/Wqor Ss9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFIbm/csESJm2MWNcdgg7gUHSCir4MA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgJXMAgGBmeB DAECAjBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20v VVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUH AQEEZTBjMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2Vy dHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAsC8KMqwcRV2ax8DJQc11w+Hts n5x457tLsJEP7xZ/6/M+i2A2yrPj7lC8HNVrkmnBF+KOFjALk/Fa/lFvIS8JM0sd Du8Yu4grAZ1Qt7RLoVMyEgmSRphBTSSekP4dxXR8zIVICVblBzcCC8hK7pPcsQIU ralau0Y8V4Xu1+SfyvYxFC6bI7JyoltsTI9QqQfMv7uZgzy84MZs+ffMR7UP8cxB UMsMNgbq9+ju6JXCKH5iVZlcqzXvNPaGBJJKoEPVE5BvUIxDyNMPcmFFcFBlAfp4 sxhadeEJhSbyfDqXk0jwsPC0WBO9mBRHPKdX8IBRFBIeRFYRrB8u2Cnx0thMVqjr bWO4MEp/sSO2LqKu3XGVLo9H5hCImdshH/r1BZ/qVDVRXI6L9SnmzWe5zGhsCWxY n7Shi8weKsbem2fxLYa0Q5v1oHjiFGJF5/9+lILYe5tMPqaFs9g9GBHZyrZ0133+ +kC1gWnH0RP/6pNDJgskm4+m2XufxqzMi5OYq0+29+KcIA/TikKeHNetqsab8pG7 c5Z4Isew++fDSgtxlvKh9GBi3BrGQkf9rafkTZbcvdWSGY3YPMEgw7pCFSLljSMN FJ4+ENjObA7W4k5eWi+huvnriB8T5Ka4TerVvN2QuFrWpeH9FGsMxeBw32ZsLYxK nyWxFKSlbcy/uzDrzg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG3jCCBMagAwIBAgIQJ5y2QRm8YdwkTl0BmX+6EjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAx MDA2MDAwMDAwWhcNMzAxMDA1MjM1OTU5WjBDMQswCQYDVQQGEwJDWjEWMBQGA1UE ChMNQWxwaXJvIHMuci5vLjEcMBoGA1UEAxMTQWxwaXJvU1NMIFJTQSBFViBDQTCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJBBrAmLd66N83+iuCvkd0cJ K1ip02oIAjgtBcW+xeQe8sae4MnR09BG/MAstSR2BJRQetrl2bUjsLd8Qmsa1/vp A+WPMrmzGihF70bxQMN60QEzMDu+VKg0691u2AQyVeHJusiDn+musB6IpRkG7rjH qkaYuLH/DXCVAKYjHG814rsW8MSSXxYXVh4x5PgvDkBP9WmuRoPOEYiEnA3KyJii 2liznvHJlK48CF91p1hdtbQSEUfrgWhK4Y6ghk6Zfw8kC5qjymNhOkw0hj9BXE33 zDjbiGVVMeHpVjfWxIGjMpZaOQHYgTP9wbWKP6GLHtAHOnTMikuVWjKDxZp3BFv1 CvN824GWhvJPPeILaNDvpVagpOsvGMcgA+yUfITnO0cxqYyO+aX7u755RY9zk0fX Z+KOim6C6yKgMjjNPYczkfmtEP3hNiBhoMbnrjd2JVyI2XTpnwOAAa6tEOf7GMdy seSRYu2hefANlyOlfuS+aNm/a4neqRKG4Cm6MVNcxAJhN7z7AbIbxfQ6kKXtbt5t 8UWy2KfP5YZUV9rTQ6+VUxdV7a8piNk4+E1T2bPVWQzPWtTOBqz9KaX5bpSEZlxb t2odKew0XM29S7ablXP4rMinutUVnBLlHyCN/c3VCm8vgZqHrwuHuMD+8DIQ39jr 9AGWnUIwwfv2XF7z0wwZAgMBAAGjggGGMIIBgjAfBgNVHSMEGDAWgBRTeb9aqitK z1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQU6DVyISrU0KVHqRynz4xrFUPRXHwwDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUFBwIB FhdodHRwczovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9odHRw Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1 dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUFBzAChi5odHRwOi8v Y3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUF BzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4IC AQBwj+VGYMeFgYDwxDaHB08ySimZS4DPSx1DL3udlMEu5vIXjhW+0Squj+K1kCQh IPV5FUObb7TArL6NbxyFAQ8cLLUuv+SIZQ1OWdvh8y2lBF059Zhqu5B5wLxpML61 9dKaiCjEutzVxtaOjIUu6om08x3A7FGtydJS75W+dbwGZFwPL4dxdymW3hN4kitb A86a8In6aFyIJLNHSK94eFw24Mm/fU3j8fkgfZ5jT7/dJdHLV2IMwyQU25MOSmf2 6ipW5U+pNzsOv0tsrDLl2qi4yrERO8iu6fY5cjZ5mlz1ze3wv9Jj8Tuwp2SB4PAU i4RsQKSchAAYUQ3iOJ21+zsVO5xwDftsJn+X700BCDyP1agXg44buYV9aFthqGYd Tc7NapZHrtFXB+Z6aB3bViGOj0bkxMgGpIRMsMGorhRGCrZdNtbDSxNdLFob52A/ RzMiUMOJisKkFfQDdbAh6oillWsfHMNyp5ZiqihEoCatMaG+OZreUBfXWsTqWQO6 aj9CWEYiHv+CgBZ7go5YHcKMO67dLFb6dLX9qhbICrCaKwD/yBMEsRhsR24wZYQ3 5Be/sJuITOH5G6m6eRtrn4bDAPJUgkhQ5yCd12AWQ9lJDLYf3yS9g28BZw3oegaO 3cRW8J4It2b5EUGeJTOoc8u+wlHTrbnCtkynEcC4CU4ymg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGyTCCBLGgAwIBAgIRAKVq9kV4o/TSh6FnapN1/7cwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MTAwNjAwMDAwMFoXDTMwMTAwNTIzNTk1OVowQzELMAkGA1UEBhMCQ1oxFjAUBgNV BAoTDUFscGlybyBzLnIuby4xHDAaBgNVBAMTE0FscGlyb1NTTCBSU0EgRFYgQ0Ew ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCmXKMIyP50AvoSosyxkEiR pxo/zc9hEcvPBzWbFBVK/L13aBPiHfOhVa/JlZGZz7WBEDjdS/hwemGZaa5shXkO v2JtuwIwbvTC68DdcIsk+WnR+pPpuD1vXb2SkW/fneyLpAr99AQu3Sby7N4mFy5h BqUux3aRkH2YkTLa6dCzBvCBeBPU98ih4ZbnnCOLHXiEMME254KhmUNlmr4FSttO UbMrVpsI/27B6Gt3Qq/H7ws/tBrjsI+XAcTe6gSTLQPAw3PBkpmbqaMEqKYQN1ZS Nr46memNoY68wGN1szhpbp4vSUHU3WiebafcBFrD52cRYgXsxjaWVtILhEucCeVF 1myr2tsZ05C4usQiIxInKc6PV1n9DEUWxSRHG/n4PIIWyObHH3BjkPE9HpykNsyQ DQNngVYD932pQJbK7pIsqVLBdBWYnKqB6915vre03F3DXkhzTAYD2YUEFKTHsVZB CNMzrjzUDDIwelUTFyVW6CvTu1ZYJOz8zbrFQUtowwVJKjaNQON2qxofwQ0f/GMH g2jBhxSiBDwBD7b5EpBHo8n6oqp7193sr5D1+juoxmkxHFYVaohLuT94JA7qOuii tt+u2uvCeqnIrtodGt/OcU3dZLh3DqdpQFYZbKZHhlxP6biVEsuBecqF+q8ledli TJqmPMRNSeakeDrRchMT1QIDAQABo4IBcDCCAWwwHwYDVR0jBBgwFoAUU3m/Wqor Ss9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFBOcIjqoZEAXLLUmmNoFyTUlK79bMA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEBAgJXMAgGBmeB DAECATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20v VVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUH AQEEZTBjMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNF UlRydXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2Vy dHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBszc4i4JVdf3fiReOOFUlEi7Cs vpTveNDO5DrYMDsRIf8GjmEX0MeWcLDcE4oEPzPjk5yvrmf8GqZIiDVSCjgoNavP kQYGr4C3zglQy6+iGlIAOzQNq8SC8CDPtC3xyzNDl6mWjqDiqocXcaiuO+u5itDA VS4Utd6pX/ixFTdMM4chBUN1lapTOmrQkfEKsVwKlpT1mpRHR1fhSxzWmk2wfVlS M2qXZQLS1Sm1+48LjJ77O+7ANWPdQvwMB2CcVejR05yBJDJd5b3dyT06ZeURSJGW YV2gIoFqsImJs7M9d2hSUIDJ5kmtcrpI3SSzvPENoxfw7NblWY8jG7ec2EWNZ1pu zlxDo5qLlu3M5qOE753nvY49tx96n4MzYjAmak7tQN85pksWEz/HYXecT1G4CqCG hjW7sXKzcybByTicCpIcps0qDzG6znuMjK3pcIy8AovgXw+tMuHzE3d8m2IYQy4N B66IjJqu/C6+S5SImDsoRH7+KVNy5RbTN6ewfq4QV6BbobFeT4qu9cJD68RENI7+ 5GPDdKEtA4a9QJoArMYhrO8G/6sY8kBzJ2jjxdDjfDhdln2MuYxOjhQupm2Fx8gw AlwJmEsZt1a8srqSbgjN0jxktv0+jCm31r6sXRGNLhF6ADnnkJyDr4ogDeTYZQLe DNDNeO4vhlJw5jxOQA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG4zCCBMugAwIBAgIRAJP5mMntp3K8vhdXOD2S+7kwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MTAwNjAwMDAwMFoXDTMwMTAwNTIzNTk1OVowZzELMAkGA1UEBhMCQ1oxFjAUBgNV BAoTDUFscGlybyBzLnIuby4xQDA+BgNVBAMTN0FscGlyb1NTTCBSU0EgQ2xpZW50 IEF1dGhlbnRpY2F0aW9uIGFuZCBTZWN1cmUgRW1haWwgQ0EwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQDeC0+nfb95e9KNDAMK30HDVsPhc8sWheZrnjdo 2C6rXjC5os//q25bSgoS7S2h4TkX0RloAzlp55XFx55m+WsMwI40jNrSJnSiStgK ZhvX7CshMoye7dnOiIvPvcrLlHgLZTcT4zirCKpiafN3N4dZygB9+hceiOZXXu20 DX2I2GXSLe+H6AAoIO9QqBjXEIzVv1O21wlGJQM5SEeI2MAQP5xBJrjjTFeCeb3n pNzsETeDzgkDoW+65LNyuZV6VT1AqE4JxhRayHlF3f1bNEWfGcP2+Lilk8rIBbaU aNgohPo6UdslrX47k8+5wn3sLqBFbu6yFsO7cjBn0L7Rvm2Hb8CkkOEgHapnVpdH MQ9SWt7AMukNRAavmMFoLf76Nd/ZI5oNjEQIxqJlxHO63kXq3znd+9X3a8+qoJYO 4yR+m77zEhltjX4GsOvnMXNcEOcv/RWRS2cNBLPFWqx6N5RUa37ekCI1dJkuzp5p qwQPCzmJ/4aSgybLD2XmnazX/GO4sGXgpxjDq/4lZIH/lw78HBysWXghWAi/Pn3p uHg7y5Wkxn39dhvivjD/WzzRkoLAoLloJOXPHA1ml/bMI6f/1hTf9dIWTmZd1Qo4 xWTVELrWdfBGU8MIkSCNO6sZs+ktJBBzVngok+kuLIM64qsUUTOWlQWea7MWJolo 9hLB1QIDAQABo4IBZjCCAWIwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rID ZsswHQYDVR0OBBYEFBqmErIw5CDQOgTmHx6XqFTKZ46DMA4GA1UdDwEB/wQEAwIB hjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDBDAYBgNVHSAEETAPMA0GCysGAQQBsjEBAgJXMFAGA1UdHwRJMEcwRaBDoEGG P2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0 aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKGLmh0 dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBQUFDQS5jcnQwJQYI KwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEM BQADggIBAFYJ8O1llKBvVn7nJvDPInyCGaq6zA6GTy0pdsq25B3ZpngEU4pQwt5y ytI/VX8bn+2DeP8NI2vcLgW0mMW649sG+rtcH7CEJ9oq3QrJ4CyG5nN5jVXx2hAL Z1i+PsPLoOeSVvQxkKCueWEwLbZ3MEtcaVp/Jq0tvzQdJdNoB9fFH5yFgtYWuPGg Oev3PlrcBEmFWJdcTxoptJ9BmHe6e1Ky92bD8slniiIeF/UF5aHQnonu9N9UEo+w 6QqwbCKmUi0RvSLB9rB5klPRxy5G7+icVx+YCskPTY1Vpw8HiwQqV//6zp6MWj7C sNBXzf1XpSSH6FsphXXu/0wL+VwreCdGU4hd/br8uH1FEg7C3zq0Vqq8mUAhHMa/ t/3hijmW8XSWwI6JcApW1Kx7KaQsfYJ5S1impAo4ROGkYfAcIJ7Zb6SR0N6XGOcu 5NoEbu3IRpOfE9v6WaUE60xBl81E8uaeALdF5f0ZAavXSj5zJoSe3O159wGNoTwd cJRK52Z21zcSAufs9hEDatQ9UIIjmUOrG6vQYXCJFWc8DD7S8f0Tt9qZ2ruYLwEe qauBQYx6AbbTwDfqcfSs6chaqKS+S91imHN81cXbP5YfBUZvAnVHZcQk3Th3TBeY WHJ9VN77/yVhEoXDCy0Q+NGKhxAPoGJ/ObGx5ktvQoxLMxfL7Eoz -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDeDCCAv+gAwIBAgIQMgDrw8WpnjUR7l2xImSYkzAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAxMDA2 MDAwMDAwWhcNMzAxMDA1MjM1OTU5WjBDMQswCQYDVQQGEwJDWjEWMBQGA1UEChMN QWxwaXJvIHMuci5vLjEcMBoGA1UEAxMTQWxwaXJvU1NMIEVDQyBEViBDQTB2MBAG ByqGSM49AgEGBSuBBAAiA2IABCi2Ugy57n6Mjm4yf8ppR765FbebABXsWaW6fPMj zmOCLj9L/PZ8LZ+Xmej/z3qSbj7mtrfyCbAEb8DA0N4I8WJroR6wrMtSeZgbxY3o OJrRpfPYsd7QAqU59rANALLOnqOCAXAwggFsMB8GA1UdIwQYMBaAFDrhCYbUzxnC lnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBRAYAlol8GyYta8ZBNZtqQSQqcW2jAOBgNV HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICVzAIBgZngQwB AgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VT RVJUcnVzdEVDQ0NlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEB BGUwYzA6BggrBgEFBQcwAoYuaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJU cnVzdEVDQ0FBQUNBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRy dXN0LmNvbTAKBggqhkjOPQQDAwNnADBkAjAwapZG4ZJ3fiDHFXCS1rX/dwMMJbw8 vyA0SOxdV3LXUoWzwvCW2ZCjJH50Zgbq0zgCMA9b2jdn+H1FIGCCelBYOm3MNVWZ 2rRmYxG4Eu7iRLcllGLm5+bqB2KfYPMVRaol3w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjzCCAxWgAwIBAgIQK+hz3P1g4I3jLRl0NDtUYzAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAxMDA2 MDAwMDAwWhcNMzAxMDA1MjM1OTU5WjBDMQswCQYDVQQGEwJDWjEWMBQGA1UEChMN QWxwaXJvIHMuci5vLjEcMBoGA1UEAxMTQWxwaXJvU1NMIEVDQyBFViBDQTB2MBAG ByqGSM49AgEGBSuBBAAiA2IABD8rNZrJBsx2oJoXuQj4ONZxI9oDppOSH/3d2xwT a7vNtyPoVWPzHHYqX0t0sIA3z+H3iJ6K5UvpSG7z97ggUqfyCLktmS2ARxGFvL25 iXFstM1RBCrV5Kx2Q8mIjrdHgKOCAYYwggGCMB8GA1UdIwQYMBaAFDrhCYbUzxnC lnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBTmr0PkpmSss2TYz1d2UaHkjo7XJzAOBgNV HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEF BQcDAQYIKwYBBQUHAwIwOAYDVR0gBDEwLzAtBgRVHSAAMCUwIwYIKwYBBQUHAgEW F2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6 Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0 aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKGLmh0dHA6Ly9j cnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NBQUFDQS5jcnQwJQYIKwYBBQUH MAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaAAwZQIx ANLAzbCsmZrE/3ZCBpjt9z7DL6Y65/cf/AuNT8fCRRXvtuvAHf8XMnjixJm5Rz2l 9gIwaaFF3uHAqtiRgQWE/vbec8JbYK69q3hIflwBaik6dN7tPrZ2sjMMQQSNu08b FJTs -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHKjCCBRKgAwIBAgIQQr9s0Yh7vujevXmAHqLX0DANBgkqhkiG9w0BAQsFADB6 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x ETAPBgNVBAoMCFNTTCBDb3JwMTYwNAYDVQQDDC1TU0wuY29tIFNTTCBFbnRlcnBy aXNlIEludGVybWVkaWF0ZSBDQSBSU0EgUjEwHhcNMjAxMDA2MTY1MjU5WhcNMzAx MDA0MTY1MjU5WjBuMQswCQYDVQQGEwJDSDEPMA0GA1UECAwGTHV6ZXJuMQ8wDQYD VQQHDAZMdXplcm4xFTATBgNVBAoMDHN3aXNzbnMgR21iSDEmMCQGA1UEAwwdU3dp c3NOUyBUTFMgSXNzdWluZyBSU0EgQ0EgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCEqPgvDoXMujspvDS4HkhIMLvqKuPyC8ISwoZZosYuOIexpcxs e/BF8N0WJw6s5twuGJkC2NtD7lNJFMRES9eoyEqjRvdouzuVQtSLHkqKSjtRkO4n mW85JpaXXLeW46vSF9Lkid7Woj/N43JgOAhKZdlpvGshrniMLIFUS5nAY46xYHbA 8RH/ikDqAy0ZwTR+ADPhwgkxfZTxKAyvzDQKSqdRq0I0wQcoDogTTgGIbq0eIwwM V2dzTSUiPcRmYTTeCuk0JiLITIEJIyuHVdPkPL9n7gmL0sq1hRMAa/O1hPH8TuA5 oedXHHiu7t0PCIjUcffqoH2KCfOzSF9eXnvfpL0DhPKkjoGesR/vfNb0t4XR7DNZ MIFr+3VaAQ5QRS6rGiX4qKLwFiCCokOtVBJeFCKZPJg1kilNFq9g0cyj1tSrdOIS cLndjVxfYdNJLfPzC/gmVk6i/BoClYO+GmgeMuI8qRrzAsVntf+lQeVxDe4qkAGK hBiHPWmIDddI175LjMVaQ7iEtqneR9uLv9YAcxxk/eacYMxQYaNn2Ju7QyUtoR0v /N+FDkler+dQff1lWz4q4i3sY6xhz/ZwQeQDDtHmxftntXvu1PzCBlqqOkGwzFF6 5DUNS+DZOHXc5NobvLp9HtoDQwvNED2v/atVXg3MnXUFKCLd3WZIqtqMjQIDAQAB o4IBtjCCAbIwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBTQPeqimAdd RIXPA/vKvzQKnxDEaDCBkQYIKwYBBQUHAQEEgYQwgYEwXQYIKwYBBQUHMAKGUWh0 dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTC5jb20tRW50ZXJwcmlzZS1J bnRlcm1lZGlhdGUtU1NMLVJTQS00MDk2LVIxLmNydDAgBggrBgEFBQcwAYYUaHR0 cDovL29jc3BzLnNzbC5jb20wPwYDVR0gBDgwNjA0BgRVHSAAMCwwKgYIKwYBBQUH AgEWHmh0dHBzOi8vd3d3LnNzbC5jb20vcmVwb3NpdG9yeTAdBgNVHSUEFjAUBggr BgEFBQcDAgYIKwYBBQUHAwEwWAYDVR0fBFEwTzBNoEugSYZHaHR0cDovL2NybHMu c3NsLmNvbS9TU0wuY29tLUVudGVycHJpc2UtSW50ZXJtZWRpYXRlLVNTTC1SU0Et NDA5Ni1SMS5jcmwwHQYDVR0OBBYEFIoJ2UdR4lwOqLqxkNTAWfEL2tUMMA4GA1Ud DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAJmiC4qCPw/idcTGdU6OnjWQe chjowRn1N1gFOGroljKI1h4O6q6s/3V7Kb3q7hkU280o19/86r7tXyrqr8u1kCzC miveGuz26cOvSJmZwBSRbHeBqcEwk3eJTxjNm0SM89rlKb7u7a2Vr3XZZQFHG8Lk 1AsQ92EfNeVfz4k9e7La0xVFwwkEbmNH0M5fPn7GBQcQ+AxLtRUC++PsXmodeAAN umbNK7ntQneliK8WsOot8drWCw3bkljExTtT1x2Otpt1tDhatiwgdDJPfSTVnhq5 xe2WdWOTR1bT/FPmPAPQHkHDAcA2uo6SVoFtSTA66Y4iwkT9gTGG2ClIqcp3siN4 8nfxx8kW3WhvCMZqqpRNJ5hJR1eiureOotAYVXN0nXAG17lIU2i4eSsMHzh3oJ/+ thiNqL8RECwPq702bskFSBcNBklPqmz0gzgRCXu2h1uBwGYMWdLOtBRgth0J6YRG RAwEhkHK48qgRzkYyS8lhra7b1wQB3OeM/eAeGttY5/XCEi62TrLKlHFLJG7+kG/ +fVcGl+v3GiGbYRol4DaQMiLoEYSj8BWZoYt6jZjOWEBsoQAfwzs/XSnUx3iaexj WqHc3spg/mFjhLHY8G3UMz5vcmi3nteZuB2hiLzrIwMsQSTP0iNNwnuIKhXmapjo dzT2uBtJpxi/vacae6g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHNDCCBRygAwIBAgIQMWgk5Za8obEUrABKpVpPkDANBgkqhkiG9w0BAQsFADB6 MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x ETAPBgNVBAoMCFNTTCBDb3JwMTYwNAYDVQQDDC1TU0wuY29tIFNTTCBFbnRlcnBy aXNlIEludGVybWVkaWF0ZSBDQSBSU0EgUjEwHhcNMjAxMDA2MTY1NzQ3WhcNMzAx MDA0MTY1NzQ3WjB4MQswCQYDVQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYD VQQHDAZMb25kb24xHjAcBgNVBAoMFUFuc29uIE5ldHdvcmsgTGltaXRlZDEnMCUG A1UEAwweQW5zb25OZXQgVExTIElzc3VpbmcgUlNBIENBIFIxMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEA46VRNuI6C9YTcXQ65wbEjfzh5ke6hfBAA4Iz GZNrXugOmVUEKsZm3B4hlGfyVQ0jHjk63Qo7nHSiaSa2Rd67Zg4lvqNK8xs8Ww3X zk48cETKydXXRSdd09arWx/VGBP5p7SaSpsVs248pllv6yS5SDMxxKONDJ3xymuH HirLU4WCCAQrodyQm8ZSQDkZm/YOYjoKgiSu42YQW+ouqiWINzaC3LThhwf2ERyq BaYCbGf0po57zuNRvvIs3/a016pKfoh5whJ1V34bnCrbuQ2hu9otqSFWVf6MHawn AnYkR5ufrc5bi499xnaJFp21QOUbsEKwWaS+eux6AR5NArdDiyHdNHvrY6ePp7te P474Q4ZRlC+YOg0FjfozjpxF9hAy+4GINxK04OkY8w2d9mdjdUR2EbFhEelWwaLb rjzQOnJX/WNMzP3VxELantb4y4uIku9zv9yRkFNQeXCDiwxW1Hnlc8lCZ/cMUi21 hkFLlWjb9eaCPR6r00LyhJ6oRztuHnHjoHoRO9eCO7d6gS59A9QXjIHP5z2dESL5 JWAYbtUYDNUt1xIXZVNfvErTg39gd+d46Y8Zmv9gZMhQKpnZwdI755LIslu3P+8w UiADnoXIOeGfm77/uRR6Bda5tDXOFx5Eu17bD94z94TFNR0VuklXDVwsUueNm8xD MN6jMecCAwEAAaOCAbYwggGyMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgw FoAU0D3qopgHXUSFzwP7yr80Cp8QxGgwgZEGCCsGAQUFBwEBBIGEMIGBMF0GCCsG AQUFBzAChlFodHRwOi8vd3d3LnNzbC5jb20vcmVwb3NpdG9yeS9TU0wuY29tLUVu dGVycHJpc2UtSW50ZXJtZWRpYXRlLVNTTC1SU0EtNDA5Ni1SMS5jcnQwIAYIKwYB BQUHMAGGFGh0dHA6Ly9vY3Nwcy5zc2wuY29tMD8GA1UdIAQ4MDYwNAYEVR0gADAs MCoGCCsGAQUFBwIBFh5odHRwczovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkwHQYD VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMFgGA1UdHwRRME8wTaBLoEmGR2h0 dHA6Ly9jcmxzLnNzbC5jb20vU1NMLmNvbS1FbnRlcnByaXNlLUludGVybWVkaWF0 ZS1TU0wtUlNBLTQwOTYtUjEuY3JsMB0GA1UdDgQWBBScvtjLr0DJHdsvnRCvmTRZ bBJO1jAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAH4A0Uw1fYgQ LtOjQd02oIT9KuPTvg0EXQgrH9gUpc0ZQ/gQIPEwvom6ffcW9Kve2Ebf5khCvgZ1 /xaBMkq8+m9dnjW3VWCIDAbSs6DENnPHBXAs0J7AmIJI+fKp5HOYSg+4WjRaGcmN 57XZOIwHD6lCqCWH88QppDq8TZXsXiNJiatVP2vqq9wTgkq+08o84q+q7HEBAat6 pIkEr6DkhJyWYOF4+E5KsgYvchbKVCoTEtZI2pJfuoUI+0SzaXuMx/gC+dbqs2oS kOx8LPtk9ysvShUqJbVPpakGN1Uvnjb5SgdEuYrn+dtYH91aBMWucnGXY6MLsmPf 7swD2ri0kplpti1gvlENvyMcQdBhMGh7o0zlribVmbbVcQvzaaV5pr5gCnKgRvcH VPSXbxVdpc1BLndzHrqn/ET4sffjCTt5dvmEE0qBd8BTROFWmnRRfa9lJolJ5SF/ 2zl8woWcq2b/WmTmneGl4wSdz9/c3BO5hqklggTGfR6E0Szw2Zz3cQ/8h/09XwIX LluTUIpj179jDuJYFRnDI0NYvmooOvLHS48Q4wdhm4110FCSxbw0/ETv5x5RA+nX FzFdtbPvBo1Ucqo1aIwNNe1gZbF3FqBaacyGfwtIS8pW8JXsk3KT/Ro5G5UUFoGC i0Bf3FM7bX4wy9KK9MdaCGV4ihct0rwO -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG2zCCBMOgAwIBAgITBy8w6cJRgYKNrE9ffeSvyHrRMjANBgkqhkiG9w0BAQsF ADCBiDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAwDgYDVQQHDAdD aGljYWdvMSEwHwYDVQQKDBhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xMTAvBgNV BAMMKFRydXN0d2F2ZSBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN MjAxMDA4MDY0OTQwWhcNMzAxMDA4MDY0ODQwWjBWMQswCQYDVQQGEwJVUzEUMBIG A1UEChMLU2VjdXJlVHJ1c3QxMTAvBgNVBAMTKFNlY3VyZVRydXN0IFRXRyBTZWN1 cmUgRW1haWwgQ0EsIExldmVsIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQCcD5Wc7H480gOv3ae6SELBls0oNOvpw1ZFjK55nLw+W6PhgqTGNEHlO/Ga Wt13yS1iO1/WzRaUc2XsFRGcjv3QIfDZb+6UzhL1LL9ZE8zcs0B6fepn4smQg1yK gtAWGoD70Z9kEBtypkG23sO5xIiRACJWgRWVZ/891pQBBz+ElCxUnIyDGghHlWCD zn5dLoBIVic69Pfpi384uNoNfHV/WATUQEEnwY+5yMMUALAWrRD6Jeh5R4m9qKxG UlrO9ObDebK9mFEJvrCPtkTIWT1He4ZD58Lt0NIkaItQ7KsKF9wgwH7BTsRGwQXb P6/0LvfO8UDRKNE/4C39u9dwUw/Zpu2iNXTadVWBtaSDsrPFVb5rBu+pvn4l4Hw5 jtySyHAOWn4mhuxDXMuKBtaoTi/qF94d7N0CbqPdN9WSN79Cy2O0BexTGHSJVndX EbKyn96b5STPshKVpG9DmUekfnDtnHR9dmH74a05X/A8k/XeSJWXphM6NvyZap2A WiIkrS7MsfwnCdZlX+9WGY2qHxnm4Y6JdNah0qxozBbQHkqHsSN4k8O7zr2lfZhC uarm0Q1t6tjsmp7PUh26u6PCe0m+MctIrD6ZckUzZeuPduRb55K2p8MxjQSVNH1S J2aaHp77qOYV+rvHXIL7le4OR5lDWyzYtXLc8u17/kLbUtgnmQIDAQABo4IBbTCC AWkwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAww CgYIKwYBBQUHAwQwHQYDVR0OBBYEFKpD9MNsQCriSoEcg6nez7XhG7bOMB8GA1Ud IwQYMBaAFJngGWcNYtt2s9o9uFvo/ULSMQ6HMEEGA1UdIAQ6MDgwNgYEVR0gADAu MCwGCCsGAQUFBwIBFiBodHRwczovL2NlcnRzLnNlY3VyZXRydXN0LmNvbS9DQTA1 BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vY3JsLnNlY3VyZXRydXN0LmNvbS9UV0dD QS5jcmwwdAYIKwYBBQUHAQEEaDBmMCgGCCsGAQUFBzABhhxodHRwOi8vb2NzcC5z ZWN1cmV0cnVzdC5jb20vMDoGCCsGAQUFBzAChi5odHRwOi8vY2VydHMuc2VjdXJl dHJ1c3QuY29tL2lzc3VlcnMvVFdHQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQBb tCXryLFewOafyNENB3NzgAQVVztwaWSyvF5FYSqav95JKcoHZzy3wG7aKlTPtGnq 1QzJst03qPmZJ3j63obz2AvfEEzLEMlsPmOTy3B9oIrNzd2QhpGW1oF6pIgGB/VP 5zh7U2ibUC+zRLmihwt+j2+7NBbuLbPozgxDTWh2f9O4rJb5bv98Q8RdbGrypBb9 hOhDvmNCCfjSe+Q8myqsvawEG5p7s8gsIK/V3xbyqDihXjsGc7xeEWNftlU91jBL KPRbrLmXhhWnHJjYs4y5IHu735HA3aAT4TqURS9dGHOMVDRumkFpLqR2W7ptpDki OtIFZjO5smU29OD4AlcNUXqQuKEFasyTtkRlORnWhU37c36HB8dc57xWQKOf8pMq 7lK+ublO9G4mO1Aqr9mioTN4oMONFJG4W5dWwG9baNg682ZACkvPaw45MqSztL3A Kb4s2cDTWu/D34hV3oafkTwu8B7B2mFZnWRJ9q4akPmZF45uw4RZx2ALaYGGGs67 +r5qS300As9ONg8hxfVkFQSHOc00IiBkgi3OpoCofEKTgDwZwHVqOJyyPjk6H9Sh ZANmUOT2mGDLwl86Ar5bTu8ipzlsyDYQMFjho7WaVs8I5OXyVdONXDYLIOtpITGT 1fRcXFzxYHhrNuFwrdj2zBVyvVD4O6xV97/9nv2Eng== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqjCCAy+gAwIBAgITBy8w6cWNkd75in+esmZs/nvh7jAKBggqhkjOPQQDAzCB kTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGlj YWdvMSEwHwYDVQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xOjA4BgNVBAMT MVRydXN0d2F2ZSBHbG9iYWwgRUNDIFAzODQgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwHhcNMjAxMDA4MDY0OTQxWhcNMzAxMDA4MDY0ODQxWjBiMQswCQYDVQQGEwJV UzEUMBIGA1UEChMLU2VjdXJlVHJ1c3QxPTA7BgNVBAMTNFNlY3VyZVRydXN0IFRX RyBFQ0RTQSBQLTM4NCBTZWN1cmUgRW1haWwgQ0EsIExldmVsIDIwdjAQBgcqhkjO PQIBBgUrgQQAIgNiAAR4nTJ6MvtPBb7+L3tklhdDw0tr5FNY5Q1hsp6NR5OzZVeG x/X3VrCvkOsae1OEZHNqWCnnI1s/ix9qn/2+q0pPpXrT6wkN/HOQzpQaJWzCF7yX IfIB0o+x1Pr17UOX2qGjggF1MIIBcTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDBDAdBgNVHQ4EFgQUJd3xyUp6 6EP6L9hCmkRrWAcU2mwwHwYDVR0jBBgwFoAUVamEidLBMr0Yy2ymB07I552+gpAw QQYDVR0gBDowODA2BgRVHSAAMC4wLAYIKwYBBQUHAgEWIGh0dHBzOi8vY2VydHMu c2VjdXJldHJ1c3QuY29tL0NBMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu c2VjdXJldHJ1c3QuY29tL1RXR1AzODRDQS5jcmwweAYIKwYBBQUHAQEEbDBqMCgG CCsGAQUFBzABhhxodHRwOi8vb2NzcC5zZWN1cmV0cnVzdC5jb20vMD4GCCsGAQUF BzAChjJodHRwOi8vY2VydHMuc2VjdXJldHJ1c3QuY29tL2lzc3VlcnMvVFdHUDM4 NENBLmNydDAKBggqhkjOPQQDAwNpADBmAjEA8X5zwZHtdHjLIn60rwG3Z3NAa6cU 6gOFxyF+ksTCXvWCUP0oFUqsRPMKMYE2mtdQAjEA2diuEHTPUgCQ0ynhLjged8BO FyzL3UlFieGGp90v58gUpfjoFq0BReAw7MPYo/Qa -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDbTCCAxKgAwIBAgITBy8w6cRicAHez+v2v107EGbX4zAKBggqhkjOPQQDAjCB kTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGlj YWdvMSEwHwYDVQQKExhUcnVzdHdhdmUgSG9sZGluZ3MsIEluYy4xOjA4BgNVBAMT MVRydXN0d2F2ZSBHbG9iYWwgRUNDIFAyNTYgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwHhcNMjAxMDA4MDY0OTQxWhcNMzAxMDA4MDY0ODQxWjBiMQswCQYDVQQGEwJV UzEUMBIGA1UEChMLU2VjdXJlVHJ1c3QxPTA7BgNVBAMTNFNlY3VyZVRydXN0IFRX RyBFQ0RTQSBQLTI1NiBTZWN1cmUgRW1haWwgQ0EsIExldmVsIDIwWTATBgcqhkjO PQIBBggqhkjOPQMBBwNCAAT4KazLm94aiykBGkNQVkBrjmK77RlP627D2n3EwK3s 49ljRkN6wiTWXHx3jPD5BBE/7mWhGWnphzGu1Deb6yzco4IBdTCCAXEwEgYDVR0T AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUH AwQwHQYDVR0OBBYEFHMQ2nwjQr8tFHfBImxM7ct8lbBYMB8GA1UdIwQYMBaAFKNB BqyQbdFK63WlShCZs7Ghi0r3MEEGA1UdIAQ6MDgwNgYEVR0gADAuMCwGCCsGAQUF BwIBFiBodHRwczovL2NlcnRzLnNlY3VyZXRydXN0LmNvbS9DQTA5BgNVHR8EMjAw MC6gLKAqhihodHRwOi8vY3JsLnNlY3VyZXRydXN0LmNvbS9UV0dQMjU2Q0EuY3Js MHgGCCsGAQUFBwEBBGwwajAoBggrBgEFBQcwAYYcaHR0cDovL29jc3Auc2VjdXJl dHJ1c3QuY29tLzA+BggrBgEFBQcwAoYyaHR0cDovL2NlcnRzLnNlY3VyZXRydXN0 LmNvbS9pc3N1ZXJzL1RXR1AyNTZDQS5jcnQwCgYIKoZIzj0EAwIDSQAwRgIhAN8G PwKUpMgV3LZjq7fuKS96f15BrwBjmTlKhOwgX83BAiEA9WpWhzRRoKeJGAqqXrMk Z8RE9xRtOFBqYdv9H5CeTVk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIElDCCA3ygAwIBAgITBy8w6cgfifMK28S5F2SkECtSUzANBgkqhkiG9w0BAQsF ADCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNv bTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQD EyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAxMDA4 MDY0OTQxWhcNMzAxMDA4MDY0ODQxWjBSMQswCQYDVQQGEwJVUzEUMBIGA1UEChML U2VjdXJlVHJ1c3QxLTArBgNVBAMTJFNlY3VyZVRydXN0IFNlY3VyZSBFbWFpbCBD QSwgTGV2ZWwgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM+bRTPK iAumsw0ohPsXoRsd1wkbjmRea7tQAKkwM0oUe27kcCv6LFgZ6+L8p+fd/TUvcv+R OUG25tDW9ASQKMtB3i1kMZQzWIVjAnKfyF/iCGdktuGS89j9aq1n/ph+t8Xj/mXu 9Mb7le0dD08kGwNYRYHpfPZgdcz8iBQDBjamDkilLMF3J0hi0AwlDp8uLcaWfl63 Hcz0KChg+n+bavQCsvVj/YTZuBWRB3lxMvx2Srl/uW7q9DFnLtt1a/5Mb2mJcjvB lt0AP7CHSedtTBA3aN1K+bbY8d+P8VLZ4Glvr8TeEP4T7E+64qAE4RwS87jYwFSF gvWuIPzNvzOaOp0CAwEAAaOCATAwggEsMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYD VR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMEMB0GA1UdDgQWBBTzycMh tpZns6y9uaBiKBzuW4fCvzAfBgNVHSMEGDAWgBTGT6I9BmOECZzOYuQErI1ctem2 GzBBBgNVHSAEOjA4MDYGBFUdIAAwLjAsBggrBgEFBQcCARYgaHR0cHM6Ly9jZXJ0 cy5zZWN1cmV0cnVzdC5jb20vQ0EwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL2Ny bC5zZWN1cmV0cnVzdC5jb20vWEdDQS5jcmwwOAYIKwYBBQUHAQEELDAqMCgGCCsG AQUFBzABhhxodHRwOi8vb2NzcC5zZWN1cmV0cnVzdC5jb20vMA0GCSqGSIb3DQEB CwUAA4IBAQAHLROENBGb+ZkmDHXvUAB1QQwKvA/3y90+RyAQ3W0ZOh50n7B77Ifw 8x8kmX/ztv0G7jwjnY2mCQX3paJH+Zb6F0Ftw1NTbGHE6xEfs2u8xBdHhcISqU4d J3DNL7u/dfQmlnXpWevwtefg6lURu0QiEa+nfE5eJYLGeMEhnn/SUQJhjbMkP6aM HSxARt7EUhgjL/459s+tPXg++XdYxS7ZA8HPwBE2GVGvLw4JjvBlOfcDAVVLBne5 mC/XFb04E2glxwVNxrCN0HiprEkhLiNYTb7nPVX2DXqViBCwx0NF3cdn3odrP1ki xBaVG/s8WF6dFgIghWQYL59xI/vCcOOD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE/TCCA+WgAwIBAgIQCFYPogq2pABFB5JiA0FS7jANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMjAxMDA5MDAwMDAwWhcNMjUwODI1MTIwMDAwWjBUMQswCQYDVQQG EwJVUzEaMBgGA1UEChMRRnJlc2VuaXVzIEthYmkgQUcxKTAnBgNVBAMTIERhdGEg TWFuYWdlbWVudCBJbnRlcm1lZGlhdGUgQ0EyMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEArbKTH7vQfsKnQB02dJdoI/b3GiUofX7UhgXb9qkUp9vHQGzs 2lAhXCXdgA98HFAjp61vmomDJpyvVIUvZic7bA+nNOCOUtN8MmGNBoGMPH870hed MTvSihtXvt2qmw3pyAlOToNmi+M6pUqd2paLm7u+jPbrlhhUlSQ8tCfe04i9eOvZ RoP/lcwhFKXLJ4jCLjrlwIkVgDn8pK7own99jLVbMznN+LKOy4Km+jytItdZaluw hfo15yEbY8n3FOWPs6LWtkOyIee4hJq2y3QW0/KEvUaWTyHqAD36n98zEQ7rAWf7 qEPw1w0Jn+kaU+U73sYEP3a5xUaIS/2njEElpQIDAQABo4IBuDCCAbQwHQYDVR0O BBYEFHboRKcLNUy90SQMvErb9jFs7HI0MB8GA1UdIwQYMBaAFEXroq/0ksuCMS1R i6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI KwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADB5BggrBgEFBQcBAQRtMGswJAYI KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3 aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v dENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQu Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2Ny bDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDAwBgNV HSAEKTAnMAcGBWeBDAEBMAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMA0G CSqGSIb3DQEBCwUAA4IBAQBvAR+zrnsFSvz9DFT/do43O702e9KCpjVfT1qn23dO EF6CSxgNkLUGMg9PaksLbTMN/wWbD2Fb+86BQEnhpBmrEwdk/3rEblS+4tNF4hQF avZYjsvgDvWkMewE2FKtZ3sxyxxtDeFz95uwMknt9rXn80hATAacrRHN1CNjX1Mi Vul35nL4OBz5CvA7doByyh46JhJt0AVSSnJUslpHAj5xolclyak3mbvzyX2h1NX+ hSqC1ZOeX0hpowexLoOzDsfAgj62Ugkz2ZdEt676ybdmMOphyuNprn9+47Hjy3DI g5Ypn3fX4loB7vDcAVNOUZuDsusWFZ16tuhe6EzQsxj1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8DCCA9igAwIBAgIQBxUbVYkBIPVxreWVvtLPxTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMjAxMDA5MDAwMDAwWhcNMzAxMDA4MjM1OTU5WjBHMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSEwHwYDVQQDExhEaWdpQ2VydCBT ZWN1cmUgQXV0aCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCq dau2gm5M55n/H9eb/eOxO05l0dcESbsMfyEfRPW1KtgOKKqMvbWr9pKrRFjzLl5i T1IqQqyMzbBKrc93kKCDuxtBFO2rRM9bbBjAsr1/I+y0Dv8QCr20sG4ZV6aZuPTT aCiAMxkgOYB+ACFkG42Uyjb2VTkFMsrkT8V8WQ60rFm3EQPVrJrlRVkDcpF8Gbb9 MWUmyQ5qecd2CWKv+sEC/I1Eg/2XanHH3byGHMhNDGzI2D0/LMXy6ycVhAxsdNDk YdWWuFNAgyJRIJAiXYR/eI5SbEkJ5459OQjZOARHCSOcPFOw7IrfBZNeROvuW3bm njcdgtjbEOa9DE6PX2GXAgMBAAGjggG4MIIBtDAdBgNVHQ4EFgQUR+AvqI6aQbxo PYjcxUoc3c/WnuswHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDgYD VR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNV HRMBAf8ECDAGAQH/AgEAMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0 cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0 cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGBBgNV HR8EejB4MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRB c3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5j b20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDAGA1UdIAQpMCcwBwYFZ4EM AQEwCAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQAD ggEBAEZgwFuCG7VFpARoxlrf0bnQ4Bfzj4S6F2Zl7NfesuVhwBNAVWM+V7C5nR6d DCRT+AP7CEAC0sXsd6ArDjzmZKnvATfWo6jAQmc5AFVBFDtiGkP+g2xIf8nlVcls Ljbo0UXPjc4aKocA2bMMXsgL1/Z3885zPHelZdqZeqJGORWCTLMghkIu3A9krPf0 WOq3v43X2DqOhX/DFtl+Fnm0B+5aJsEb+2ZLxbcDlwMjsZmD5ffee2YLLWDK/v+5 zX2Lx09UUHOEB0KVoHsHHSsEtAWQ+BsRUWAVo+eqWUWF2SDqIvs1q7eJx43zQdgQ HrqVXUBVjeGFhXgh3HGmLvnuBlo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGDCCBACgAwIBAgIQCaGtSAX+0pT13k71h9TIOzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAxMDIxMDAwMDAwWhcNMzAxMDIwMjM1OTU5WjBeMQswCQYDVQQG EwJVUzEZMBcGA1UEChMQQ2l0eSBvZiBOZXcgWW9yazE0MDIGA1UEAxMrQ2l0eSBv ZiBOZXcgWW9yayBPZmZpY2Ugb2YgdGhlIEFjdHVhcnkgLSBHMzCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAMIkRfQaSAXhHHBmvPvkGGlZE2mqfHxFir8X 3OXUhDpbvkt0MM0HMbooCCP0HAVlbyk1+aJAza6llEoWVq8+Gs0ORhCOPxiZJaVo u6iAVGs62qJCPJiwQxre6UpKLxEeaqHgiHAWnNzGjjdmNgjT01ExcSYdL6GoRX8Y /EH7LeF/IGo03JTmt17XDf/kl3f2uF4OQymV/Q9DO9gV06nsl1ZwwFah4GTIKWLq Xx01UXm8SRsDKaRhwdrtQ/plswzH06OEa2ua9NO3j6FuJxfJWziky7ywxQkxCBzv Mbyndo/e9Y9GU2KEegOhfZJxHM2qSbkyaGEzFExBkQSimtAdncsCAwEAAaOCAckw ggHFMB0GA1UdDgQWBBTF8wvK1FfyKxnMbNPowH4wW6DYMDAfBgNVHSMEGDAWgBTO w0q5mVXyuNtgv6l+vVa1lzan1jAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYI KwYBBQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYBAf8CAQAweQYIKwYBBQUH AQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYI KwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz c3VyZWRJRFJvb3RHMi5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwz LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcmwwOqA4oDaG NGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RH Mi5jcmwwFgYDVR0gBA8wDTALBglghkgBhv1sBAIwKQYDVR0RBCIwIKQeMBwxGjAY BgNVBAMTEURpZ2lDZXJ0UEtJLTMtMjQ0MA0GCSqGSIb3DQEBCwUAA4IBAQASJB3l Ri1cQVumpXGICFE/pksQU9/86r8XqkeBY5lHinnDAChDhGO1LIaXKMpLrNrT/2oz L7PCuXxMsLOxaqNpMbQ4JK/CrceM0IvqLdUwdXP5ZKCHYQi/LDNRIXaE18C6DyfP 0Z2nRGmt/rJ6RhR9G3ZM2JsLmTe9FNcz/nznXYYVowmH0VGkESGyDzx0EP2Mry29 jzjiG2cbZh4Hx9RM5P0vVQSrbQ9RX99VBh8EcCUaYfl/maIUlG1fhGE1DM+cOQRZ cx8Lm3eZ48L2vZ5F4O+wN44lczmedimJDCfty4N6HZ7rglWXa8Jjx/2MhawY+iLZ e/bzWNRdAGBmXdyk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExjCCA66gAwIBAgIQeEqqEgu2t8okwy1177jkrjANBgkqhkiG9w0BAQsFADBM MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMDEwMjEwMDAwMDBaFw0y OTAzMTgwMDAwMDBaMFkxCzAJBgNVBAYTAkdUMSMwIQYDVQQKDBpEU0lHTkVSLCBT T0NJRURBRCBBTsOTTklNQTElMCMGA1UEAxMcRFNpZ25lciBHQ0MgUjMgU01JTUUg Q0EgMjAyMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALO60kUNezaj hduMbSfaGV9WQ6uC+nlcoMWrtpjbFCSmTxuQh0fBLy0HPzn/8Pl3NCibb2MlLwGB uUAfBwqdxH3WHG0sSxuiyvE4dMEsH82PaL+hoIrmZkum2q+SqJvD0LzlWNvKAdSo iW/7pLmQiFO3XdRWMMiq6z5veZ4aYpL3quudziA7eT3cliEph2GOzAr9CpU5QmjR bulNk5ZCE163U6WOn8xwZ9eQOWPmX7Q0ze3i5Alpt/hOWlB1h0p/yG0ETtHBzxON zdVSCS+UqjeMjy9HWyNT9EmCrHDnLLoSjU4dkJAZcxlVuwEq+NXzv5HNzYb9xYnH /Ii+ILohvgcCAwEAAaOCAZUwggGRMA4GA1UdDwEB/wQEAwIBhjApBgNVHSUEIjAg BggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHQ4EFgQUzfOlZr8gThaSTlHvLfP5WFRRhZYwHwYDVR0jBBgwFoAU j/BLf6guRSSuTVD6Y5qL3uLdG7wwegYIKwYBBQUHAQEEbjBsMC0GCCsGAQUFBzAB hiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKG L2h0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0 MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9v dC1yMy5jcmwwTAYDVR0gBEUwQzBBBgkrBgEEAaAyASgwNDAyBggrBgEFBQcCARYm aHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJKoZIhvcN AQELBQADggEBAAxJjp1Q0XY/VlMA266JIaEXw3JSBldeMAD0j2xlfJ6RNuqnKWY8 u/uaABpEXgVzGAn2dDaASGbDdIjbyw2TLnUkK3grXFD41NTk94dNu2p//gFILsY/ K5hXqLpkwnDvC6Onq8P8OiuB9N4nS8+0lC5O8Y4IUGNTnV27nXv/Nc2Ma/BBNqL8 JQ4U3uR9xAW7QnTfXtZCQijhafdxKMsayUT6FrpC7AINT50cZdFsM8CDHBTu1jaO 1voz/Nl5nlnzLkatpUhp04RSF17LCccaniro0/Fv5kpinHshEDNf/SCHQGGlRALZ IcGfNWLpVaWPNN9IJJTv+nWkEBoXENPP+EQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFJjCCBA6gAwIBAgIQCYOYgd2HFpgysxPXmaOTJjANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAxMDIxMDAwMDAwWhcNMzAxMDIwMjM1OTU5WjBsMQswCQYDVQQG EwJVUzElMCMGA1UEChMcSG9uZXl3ZWxsIEludGVybmF0aW9uYWwgSW5jLjE2MDQG A1UEAxMtSG9uZXl3ZWxsIEludGVybmF0aW9uYWwgQ28tYnJhbmRlZCBRQSBDQSAt IEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMtz9F4xNHLu5i7T wtF+otpBHhQDP98rQEWTvcrnARqrEeNU1MfMF5k2IMsFvNrOowO1737MlfpP1wp+ 8mq69LkQVhHs7uV3Ulv59kDKH3MsZS87ZMI2as3xcjjiazq9uF+4KkDIeQHQafgK fap9nbluzS1E+vtQNINgB2snr+uv5zx8OA48ixpRuZlupp6O2lxN7YN6xC++rrgT 9vJSh+vkH7RB3t62jsgrklJus4laU14+hG5Je8pHCplKGQ2ln0ieT8x2T2Q81Gpb CZC2+/cHfLR2aTo4QOOdoV0j2qUJ5fFKjhuvqGoG1HX2nDUl7IMOi3L5GQDt//Qk 7hv2RQIDAQABo4IByTCCAcUwHQYDVR0OBBYEFOpc5decUj7A7uByQ5ijpDGKld61 MB8GA1UdIwQYMBaAFM7DSrmZVfK422C/qX69VrWXNqfWMA4GA1UdDwEB/wQEAwIB hjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwEgYDVR0TAQH/BAgwBgEB /wIBADB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdEcyLmNydDCBgQYDVR0fBHoweDA6oDig NoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v dEcyLmNybDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 QXNzdXJlZElEUm9vdEcyLmNybDAWBgNVHSAEDzANMAsGCWCGSAGG/WwEAjApBgNV HREEIjAgpB4wHDEaMBgGA1UEAxMRRGlnaUNlcnRQS0ktMy0yNDYwDQYJKoZIhvcN AQELBQADggEBAFaIBUYcidPNlnkpu6bCFchGlSvIM6NRagHhWuIrfinv9s8bimD1 iJXG6khG2Nf/fXd+zodwvYUPO8XLV1zAmqdmqIP6YWXdu/vB2M8G5nY1Ga8duhPC OnMJwxoVqu4Q5GK9wumrKE6Iw03BCga7ifVGj4H0PivITHduukhj4w6NjowZpqQj AoKicMKaywOFtAQ57N2Ea9qQEBirluKNisM+4+KZa14YEe1bOg8x7Dhd/CJE8jvV N3SiJE6UUow/0z5g9hU6Gaq2BvUyDPWfDUYIZYGNVtIMiD80C/r8yWryz9r00hwA IG1tC4VdawIW31wvx0ft78Sfw6ROn8nEaZc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGqTCCBJGgAwIBAgIUcjSPT7WWfoQJ5rDM7W+imbHM1JEwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0yMDEwMjExODQ2NTVaFw0z MDEwMTkxODQ2NTVaMEkxCzAJBgNVBAYTAkJNMRkwFwYDVQQKDBBRdW9WYWRpcyBM aW1pdGVkMR8wHQYDVQQDDBZRdW9WYWRpcyBSQ0ExRzMgVExTIENBMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArqaHzuglBCy/xJrtRK6eArGv+EfQt4aF NTXAdG9huBYc3GJcvZQ79cb/Jj118MecLPNF7acIa4Syehy0h+Zhgaq6ajSrwz+B Z87fuGbPNj5L8A/ZHy5N9kf/x3UkUSqM5bn2bbPwyTF2EnhIvSyfY+uJfS53QnS0 F9qGfk96uINDjGd1cf1JelfrGlc4X7qopY7W3ze+gYqehrO9B4I+15gbknkPnRdF SX1759PT847lFjdIIOuzr9Ynsf1zgYAKt2GjbumIFUVK1J/CMS2LTNhyRq+nRmPn k8Sf3qq9Isv+q8Cjua/fR4MHdYDQ4ilIxEMRXnCTKTeqKbzpuqelBgmbJRiafxYF slLqpQUzoAXGdDnNMMQ2mFhEkgsrc4Xb/+hr7Nbo4KbtL5f2RVRGb9YziFtlq4op FIERSgN1Y6UQSoZT8PDryYreW6+Q/3wlGNf7xCGBrUHVvTZCLMxi7jfASanyeFIz V7+nwpRzwA/Qjbz82DrwGgYNHuuQswAv1XUbYnZQ7uTvAkwFF/R4Avs0AmDpERZ6 XYGoKv904jiPIl1EfanYjcBnpD8KaUgZTunOqTUs0r9ifMDsCrGzvy8F8oD+R9qF FzdKKnEm5XwRwY5h4+dEDmYr3Ejcc9FC8iruv2+gF+WMDn9ouzUYhOp5n3zDD0KF Bnnjg2I+X30CAwEAAaOCAYgwggGEMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0j BBgwFoAUo5fW816iEOGrRZ88F2Q87gFwnMwwdAYIKwYBBQUHAQEEaDBmMDgGCCsG AQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMWcz LmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVvdmFkaXNnbG9iYWwuY29t MEwGA1UdIARFMEMwQQYGZ4EMAQICMDcwNQYIKwYBBQUHAgEWKWh0dHBzOi8vd3d3 LnF1b3ZhZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUF BwMCBggrBgEFBQcDATA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3JsLnF1b3Zh ZGlzZ2xvYmFsLmNvbS9xdnJjYTFnMy5jcmwwHQYDVR0OBBYEFBZGoedojh0lKEtQ 0IhHOeMuPzGbMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAaXHL eIZgQ0bF+Su+i5T/Gts2L+DsmmJHQwwvgbBtUJYD04vAJIGI1ht+IZFOmsAmkSFF LaUiACDBNJxZf9fTy1XZirmeVLpR2DAFhm2hPs6Bi9zUxMtdBjgtiBiJ65+G52L1 C2IjuiCPM9y2debuqf1bF1a5Sh3poCmNbPn3iXVLu6ltOjY3C0aWPc4X6QCyuc8A VYUdi09q3IDgIU88yxFaQBpNMl4JDacLRBy9FIW0AkAThVHJ9+prjwJh1dWd225R aJnHTLwyNx9AmDTXbPAFLTPvr8kCapbPORJ9N7h4LAposmOr8e3euEo+aWtw0XP3 gtdg2yp2RiUlnITMnrT7de02/+V/3nfCaCrSYgaTG9q5JME5JSTvtJHAp+Ofn2di FSmpBrlcAeZgKouXkPTG3dpgoD7GudYN/8pGBZTbJoBPzW93alA5G4+h7bMQR2As R5RlYhOiHlJX794HP5C2z/c+wYcWG+Kdw0ZnGeoJXaohB5GrLV8AeAPR2qsDYRyi NAoe14H11TC1GkYvYlogUDEGGCzds4TA3KznHg+zxd4etLgtgWfnuebuyKncM7IH XA/jf4F1WByOaejOpxWHZSv/2XlMYdCv+Zoi+xVNYZu1zq1+eD1MbwFTubY1x/Z6 k35ejgf52jXMQJT/iJlH2mcpA9Nqn+ShBoEwQrQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGqTCCBJGgAwIBAgIUGNrgUaiXcV6wiZ3c+zOxzwgQ7sAwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0yMDEwMjExODU1NTJaFw0z MDEwMTkxODU1NTJaMEkxCzAJBgNVBAYTAkJNMRkwFwYDVQQKDBBRdW9WYWRpcyBM aW1pdGVkMR8wHQYDVQQDDBZRdW9WYWRpcyBSQ0EzRzMgVExTIENBMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA641uLRjmybfeGYjvT19lXOUsJVgkCXPf oqREVTD/4TEEyRzbrVfqkkqUcvPG7Y1lO5PjgBmzeN9V8ONUz0XrPde50XRQHjYh j6gLqsL7DtJ0o/rrAjkQN/P2nReeDISyM0Y9/JLFIVzfV3I9QRuPU7wf2uXcQEB8 9uvQGkpTr+r3mzZQCB4C1QNAutPn/MRdK3QOdRDJEUKplUh9PaQ6dft/WLceZMDC Pfp3+OC8NOoF0qZqSmSaP30Bjp1H4I98v1V6Dbtu3e1/INYDgcjgxX3gVmTx9K5R k//+gXlYCW6cG2reE+u/rdpaTHCQI1/ldmPNSeAmeW4SlYJqjfh4Kj2mkxCqoVG+ AvAMjECMfj5awF/s3jnIBVZREeeRQ+E8xkHcem35rIo+1OAuL1ZnVQyOQ8TPTNuK sWOtEbYaE/ZHZ8KNQizBIDqb+qv8QCLqvgOFY31DO0rEVaJYq8P93WHdLDtds0kn 4SJgDF6OsUDb1VwvjjpYW9lT2cqe1bxEL7Qtxg8fqhmSGNyRBYRREShb36zS/7Ic 0ABM/B6AaOx05psvo6m2GliHci3EitfMLQkN0085lb6cV5YHULgvGbN5PHotlZEK y5H6BDFnVP80LV7mUhKF/sdiS9qY7FxsAHZ7IE9HHIyskQ8UsnakZTobfGcOyklQ TK0iPbmSEZ0CAwEAAaOCAYgwggGEMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0j BBgwFoAUxhfQvKjqAkPyGwaZXSuQILnXnOQwdAYIKwYBBQUHAQEEaDBmMDgGCCsG AQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhM2cz LmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVvdmFkaXNnbG9iYWwuY29t MEwGA1UdIARFMEMwQQYGZ4EMAQICMDcwNQYIKwYBBQUHAgEWKWh0dHBzOi8vd3d3 LnF1b3ZhZGlzZ2xvYmFsLmNvbS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsGAQUF BwMCBggrBgEFBQcDATA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3JsLnF1b3Zh ZGlzZ2xvYmFsLmNvbS9xdnJjYTNnMy5jcmwwHQYDVR0OBBYEFLcBPfNeG5atYTkT +Kov9dawk8YrMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEATpkO 0mP56xBQXwc42YKpJZblRuaCcYnw6SxD/SfviILrdD4mKsgD82oAamWCP7+bZBtU sicyb2B3Vb/F30yOjt/4ReECqKKEg2FUlH+nPSoq42BHyRlDne8S1lFQwRfIcwXG rMaqzi/cLDccKzAfY3sq0Si6fVRIYrfeR8WjGsgYn2xYSrO9RmmMRVvH+Ys03Fhv F6RFkS7mHWJzJcJT5GPvJhYvTKr4J6BCLO8Nao/RXyPjyWJ1cUErKmOFS9Em8HFB 8aBJF2tBmxLPZHrBspvv5hVRJmEaKJVNoprg7jO1Grnxxm7kvC0FEyvgOjqeyWQc 4Mcd8/97/hYyUZ1Y79UEN+89y997x2WNyOlcS3FQ85sVhHjHMYNKXXuRUZw0KCNa 3txAN71/UkQVU4E8s1LhdG1s17raIx4/d4WQi837BSlfLVYg8/RKo6Mq0L3EMqGa ZKGLwO8+sR2RT15NhgFy7VldRhyKVSIjowjFInHXa58Di1uSVTJNYfFBRNbTq2Lk dHWlIIdPoZb9GLE+ESoKdnrf7w50P2zjWXTkpKSznUBMlMtykitUKadrU5fl5v+I 0cLVHmZgoQA7GbQNSYXEOvQDcUNltLMfMwJ7Neq2LaPWgDvHT7A8Ks20SHPZK9TE g87xdX6vthFdS/GSJ3yZytSwOz9bpnSa6Rx1rQ4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGojCCBIqgAwIBAgIUKwfBZBU5bVPNBfelQsykhn4Fxo0wDQYJKoZIhvcNAQEL BQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZ BgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0yMDEwMjExOTA4NTFaFw0zMDEw MTkxOTA4NTFaMEkxCzAJBgNVBAYTAkJNMRkwFwYDVQQKDBBRdW9WYWRpcyBMaW1p dGVkMR8wHQYDVQQDDBZRdW9WYWRpcyBSQ0EzRzEgVExTIENBMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAy2wAgqwk913++pLm1lpzIc4+42rvY8w1J1FI HcpwHHGQKoV34nN2NfrvtO7KI8v6EXy2AU2kCqKcfhFk0qm75IPlS6ImxIuq64Kt vmd3i6wNpe8Xty+RpmyFf1+ZJSGG4WJCJ+cwxKpTD60yPGsLs1THrub/7j2jf5fA D+gHQ0llvpXrt0bLaqPgg0jMW1BnGKE4qu2K//k4eZcF+hgYwiyGYv3qoSvDOCUg D/cxy0XMXLKTgQNc/Z6MnZxdHAt4Zxrm74b+JSe7EccBK3tk5x3qt4HAEYU449aZ 9HVnRvWPvpowDlwGr+gkLnYnG8egQJxa2TtYsZtRWiqeEYNr8+I0656ieBhwmlci EA8gq09kFL/7QJ7FjuqX++dRCyrDB37WFov5z+pQhGYDxMembufPsdgNTzhysTmm RreFzwj6xnWzLFJxuFbUxt0Rr1XSxDKjMlbLwf4aB+msHe3lGbg/TIKsiAvmZz1O EQ9pVMRG9KBlPpE6xdZ0B+eSkZ3RJeivPQu8y9Dz+gxoBtTi3c5qwUHKUOZ1JCBQ ODnYrmb1/lVTyTZis63gfp/ZEw6gonYkixd5vj7m8Sfm0YAq7tuCNJ4afeU2rILj vs6oM85JiB/qlLNP6MRDtXxb7NVKjQ+MG0/elbtZDcRj7i3HyqYe17Oya00hT/QN bwqbvGUCAwEAAaOCAYQwggGAMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgw FoAU8sAT4IJDPvvuL2cyljVc27jLAtAwcgYIKwYBBQUHAQEEZjBkMDYGCCsGAQUF BzAChipodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMy5jcnQw KgYIKwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3ZhZGlzZ2xvYmFsLmNvbTBMBgNV HSAERTBDMEEGBmeBDAECAjA3MDUGCCsGAQUFBwIBFilodHRwczovL3d3dy5xdW92 YWRpc2dsb2JhbC5jb20vcmVwb3NpdG9yeTAdBgNVHSUEFjAUBggrBgEFBQcDAgYI KwYBBQUHAwEwOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL2NybC5xdW92YWRpc2ds b2JhbC5jb20vcXZyY2EzLmNybDAdBgNVHQ4EFgQUL1iluJzmUsPetc81IV/ypLxR rGYwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQDBNFD84g7RQDL1 aVS8KWP5tOxstEj8OlyBE6FszXPb0VRVzAnJv6Xme9+07mDGJfxH0cI3R3qIZs9F sw1p2bscUHGRia1XEoitiD8/xsMuOlQt0C+tqdIzRdmXoOvP+JmKIanrbsQ0qF3a xV4dknRKGbqxFMFaGCgS07Pc3LvwxvsXqHUzZtTcwoKNov1HfVOF6Cix2XIAF8Hr e249ETqIVspQINKBdWpNfqoOk5ipMKI7Re/VhoQ87pqzJ8jUB9HqNzRIOGLoYv/w WbKcnfBL6WkDntrUM7d/6MWSc1boU12hRpjdHX4m6JO828etb91KKhdwR2aDhqF7 riAEkgOhRZt28sozIevhsyAXP9zBysvTd5n3kD5j61oGsWSEmoZU/ULOWUxptcrJ tydvPOUqOPo2gttknH443Js4Vzv3mLetz8rZ12fe6sDIxaSTjOQvyC1hb1TBeaWC FXJMxgJDKh7EcG0me8gAJk7X2vZJWlForswLCPD79PZCxv0J/wtU/WY3KDefoHaZ pCO1JPMUnMN5IQbXO8SIedmzmzmRInYV+gjTbjZ5tNHPeXDgXzsYd2TV6zvAHt5N t3SIJl02jEiyhybZL4yKg3srsVmmA464gvw7HAqJ097gL5u9dMZzkAbqO8v5V5P7 rDexaByRZVSNAjuhJIzl+0hko2c5sg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFJDCCBAygAwIBAgIQDAA71vU6dIlkedcx3GPLfzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAxMDI4MDAwMDAwWhcNMzAxMDI3MjM1OTU5WjBqMQswCQYDVQQG EwJBVTElMCMGA1UEChMcQXR0b3JuZXkgR2VuZXJhbHMgRGVwYXJ0bWVudDE0MDIG A1UEAxMrQXR0b3JuZXkgR2VuZXJhbHMgRGVwYXJ0bWVudCBQdWJsaWMgQ0EgLSBH MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM2gNvTU3ZTjivKD+39A lt2uY8te3VGQcVcGtW5UaYgsjUJLujAwo0OwY7l6TyvLY6+TzVaQjCbsu/0VC9DR CwddcdbWTiceQMPGo4W2C0i4fSO1jEHyXiXAyUyZTXodXjdGs/1NKh8Pr5iXfZQH cIFclqaTW4Qc+kefRzWzshPSPZpI8MYTElJ6RxSxjd5gXtrA6ep2Bcgd8Rt4JMvt QxRDkA1ySh1XMMxVUbQUtvOswRvFilSZx2ighpZAIdeXCNKA51PznljbF6enejrX MZgIKIqPRIo3cf8OWEesBy1lpl1C4rJjOzxYg9tU1Q28PvvOLOLZaoOS4mDsXej6 hWsCAwEAAaOCAckwggHFMB0GA1UdDgQWBBS4IPuG8TpFOFrMdwMOcdFnFuHxOTAf BgNVHSMEGDAWgBTOw0q5mVXyuNtgv6l+vVa1lzan1jAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMBIGA1UdEwEB/wQIMAYBAf8C AQAweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcnQwgYEGA1UdHwR6MHgwOqA4oDaG NGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RH Mi5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz c3VyZWRJRFJvb3RHMi5jcmwwFgYDVR0gBA8wDTALBglghkgBhv1sBAIwKQYDVR0R BCIwIKQeMBwxGjAYBgNVBAMTEURpZ2lDZXJ0UEtJLTMtMjQ1MA0GCSqGSIb3DQEB CwUAA4IBAQDZ2qka/ZM7u3dWoKLzCe3vqUxM+rtNlRdgNjHIDASikJi3n7km/hrE I84PoPs6KqSrSvt/wJW/QnwyuPZ3tFG7ey9K4YNy5jmdv/+Vul7+mQdQC/YzV8vL MltqgidElh6RkYBB866gzgbU5cAiVJ5UTr9VQcaFkPALHtpT/3SsIJW+kLNaTQq2 P8TVZGICiq+NdpL4Ha6S7DUaVS5z7lgE6lSdY4rUKF+Y2Q4Hu7xJFHAiiqro9m5r AigvLtqsRrr54kugRpgKVzFL2fq+BMYNyLU8GzU2CDUltc0ZL5MJt7GjhW+/ncdt 64nZtdtnK4GUceWKpeyNn67aA+532yrV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGmzCCBIOgAwIBAgIPAXW7sd1S8GyCqFhfsY0kMA0GCSqGSIb3DQEBCwUAMEQx CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0yMDExMTIwODU4MTZaFw00MzExMjUwODU4 MTZaMEYxCzAJBgNVBAYTAlNFMRkwFwYDVQQKDBBUZWxpYSBDb21wYW55IEFCMRww GgYDVQQDDBNUZWxpYSBDbGFzcyAzIENBIHYxMIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEAyf0I1AekLycOW8jJRyZ4zN3B8a2+E6DoYRF+9rIZ1ptMzlCI QbdOAyiwAfsyRtVotv7U8IP5Jto5PbrN2wUifR9vL7YbGDCkaoeqLcj0EjkAD/Vy +y7/UAt2el5hHgRGAPdJbzDL9nEuXxwZYyr9b4v1+TvxUWxx9FNWhrvivcx3wK+W iWkFyaxp8MvaTUtytWwLBhZyZJYVoGyVlQy3SrLqqhDrqpPy/Z7jUYWtmeQ5VCUm Iey+EzsYlotombG6+VTQ524A8wNbDlWhTZH0UxlSO4dEppaAG1a+8Yvi4TidHZIK eMG3VPwY+Z7Mo2nLhbuVIDY0oP+du0IQEDO9t7YcqPpLGz2gAxREIx1iiAWxsoJg j36F9+7TrOBbO9PNIPOjwdGuYry6hLIBgp5i7ZHWDvdk1d3GOG8AP4VnxeQkUfnN Evyhct98m5B3SzYMneyKEbngWhxmn/E07p6Ly1Yvek7HuylFeAd0x5zbHt3zdujE 1Bux3shB4jul+U/rc9rmr3doHwJP10Eod4uGi3lJA42BB9T3ZS/HFC/sMzeknK0W a+RjvHHz318JYDbS10l4OWPA5XA6MGTusqiexWochXS6Q7ZMXiQDcnrbfGpjIs3H ev2CiNRA7Nh3Zk9EhhQBt2zacbPFoM6q69ufN205n0GqB5Jm/dqzK7Gs7rsCAwEA AaOCAYYwggGCMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1Ud DgQWBBQZvmGKXzS//5GHt1/e1SVjCQtQxDAOBgNVHQ8BAf8EBAMCAQYwRAYDVR0g BD0wOzA5BgwrBgEEAYIPAgMBAQ0wKTAnBggrBgEFBQcCARYbaHR0cHM6Ly9jcHMu dHJ1c3QudGVsaWEuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwQQYDVR0fBDowODA2 oDSgMoYwaHR0cDovL2h0dHBjcmwudHJ1c3QudGVsaWEuY29tL3RlbGlhcm9vdGNh djIuY3JsMCAGA1UdJQQZMBcGCSqGSIb3LwEBBQYKKwYBBAGCNwoDDDBxBggrBgEF BQcBAQRlMGMwJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3NwLnRydXN0LnRlbGlhLmNv bTA4BggrBgEFBQcwAoYsaHR0cDovL2Nwcy50cnVzdC50ZWxpYS5jb20vdGVsaWFy b290Y2F2Mi5jZXIwDQYJKoZIhvcNAQELBQADggIBACWIwFPJnFT9AGswgmSDLNKX 1Ie9wXRNo35hImR5fvp1is8SG8Hsu/btBEyjMQCugHcAqofdK1DbQWrWXPOf+q6H loqrnOCc+F/O9XBtnNkplDf8t8F/i4l1AGoKZKzP9fxVXljlFPUJ/fLA33uvpd+W QmBaxbcojYlTs4VrhcJ4hpWAT0F8BRNBYJs3l/OVrDikAAVzJdco7ftWnDoGdRnQ 66XahbcrBfapFXVxy90Yoie/SAZTZentDc4AzAEfZqnpAsDZI2pIW4NBZskwbVaA 2eiKWdWcSdPtvWUp0zmD6rkHHOX2B+rg6OZIeCjES7PfgobMwJCPO7/thNYL3Ue6 KX8M0qd3DJ70sGv0zGyKqxgwa06R4Ju3asWzc1cqqBH2DmAWQ0hMy8g98wMqwN73 8V2uiedLfK+mkBuZLfAxscWcAvuxBc4pq15iZ+eD/JuZQRBk6xgr38m8UJMaX2of d3HN0o2TfWhkyJ1RCxDHI7fG41G/t1X1jwJMaaYxNS6GWAdVOIzqOsb9JVu6G5y4 +WMGeHbmtQO0fU0xVgfsbPxazbW5aluKl8u3l+L7fxZdU6ySSaDTExGvJ62nCfo1 V8EyuOVZfkIkDuR5SFlWOS3KogL4lxa3BnPn3H/HY5EZPA6Z/xX4seZs8QbRbBND UW0lNG6KcgIy+WUBWM4f -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGYjCCBEqgAwIBAgIRAIY4Cy0+ZbmAEDBIHg50Ni4wDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw MTExNzAwMDAwMFoXDTM1MTExNjIzNTk1OVowbTELMAkGA1UEBhMCRVMxHDAaBgNV BAoTE1NlY3RpZ28gKEV1cm9wZSkgU0wxQDA+BgNVBAMTN1NlY3RpZ28gUXVhbGlm aWVkIFdlYnNpdGUgQXV0aGVudGljYXRpb24gQ0EgTmF0dXJhbCBSMzUwggGiMA0G CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCS4LLVDvbssJS2PweSixvfCBGazQ7T znTNK92y/ugYCMD5rfZVeBbaAg8p3arP5nGGN2iIJVdNoKpWcqSWKu4qV8DM8t6T /tFT/9MbbZj6uG+pNqtwv5WGiOnozxRZfaR0T+9OBs6S8iSrllbPWprnBcypp2eH K4qWlXMv+qqDNEJm+mlSEkMihzcI/iGvvGh8p6sBpGADS61/fvQUzBM3IVTlX4ES j4DZpzX+1p/tyPmefCn639KidHzILG0lGW1KYkCXifbHZYQR3uBTF3sd6sfyv7Tf widIj8m436eBpjGYMjlCQ2n25Ycf2g975wD1t/h3ZlWpXanchPxIRqE6npza2mXF uaOAqqf2HQsJ1wDN4wV5MU5SWS009bU1y91tZ6yF9MX038eLxoqm2UGzWzx0A5nC q4ZLGd0ngtYOD13MEgPeigtxKBj3g8HEqsUHPIfO2ARBw1rvAQVeLv5VQKckk58u cAaLzGOd5qm2dkqVhXgvQcldThcnXeloebcCAwEAAaOCAV8wggFbMB8GA1UdIwQY MBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTl1tBBwkfAxHKBpT4t GVjpWyUpODAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEQYDVR0gBAowCDAGBgRVHSAAMFAG A1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1 c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMw OgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RS U0FBQUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5j b20wDQYJKoZIhvcNAQEMBQADggIBADPLTHB1IB0tREzMLGQGvNWYeFUjVkHv+X6H uGkFj2RZCAdb47dDs9BOxkKExJuIdSdbynz7WHngZxWS6M7JfvRgUY/gIGN1LaQe R/yrcASXaQfVnB93oOB0QMpghrQ7FS6ZruY8QrMp7hmb6HHK7b/AD3kgccoT8Noe n8RUvydRManKJlvPkGI4TnnCZ7UvozUqux/IZ7NvQ6G6vHIvOSssJZhZ/MnFnuyk uSGYgp4CWvd97f0uTX6e1FNROGRLPtpx34O+BGc2lvR2ivqBO6xx2nBt9qSJLk5k lUJ6c+YbO1bAxIK57ciUrSOXArsy/54AET0B7e0r/hAL+e8E9gdiZhMGdmEPIi3V jn0RU4QfpOZv4TKEDuh8ToXofXFk6zm1TWuiDUSwId6g7oS2srPHOKZOvi3d091g 117yup4PqsCf+uiPxODAeZNxsdBB2kOoc3r7qTrsoFcxzGP/i1XzDVbwWlrUiNTi XD1TWKzZGfcswT4dStLM3Pw59gp+EpYrV3oB0H1GqM//MFOyxHFityo1ehvaNB4l HYGe8D0mgfzNTdky2lQ4EENvbhYBpsWzze79R7QvJwaZ+W1S/LLxlkEnsUp0zuzT 2XocVIMDHJ8AIfjdGp9dfaR8QKFR+qbhrSW5SasYkfxjjgVlX96c0ekGNRUewsKF KEzk16QT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdDCCAvugAwIBAgIQaGbVc3fydlfagmignj+utTAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAxMTE3 MDAwMDAwWhcNMzUxMTE2MjM1OTU5WjBtMQswCQYDVQQGEwJFUzEcMBoGA1UEChMT U2VjdGlnbyAoRXVyb3BlKSBTTDFAMD4GA1UEAxM3U2VjdGlnbyBRdWFsaWZpZWQg V2Vic2l0ZSBBdXRoZW50aWNhdGlvbiBDQSBOYXR1cmFsIEUzNTBZMBMGByqGSM49 AgEGCCqGSM49AwEHA0IABCQzEZK6e64f9fcv4Vm51++8RKtzZt9TApgcW+zVNLBM 5N3YBvmjb41s708BiVNb+5RVj0SOOFAAZ1+HSpcW6NGjggFfMIIBWzAfBgNVHSME GDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQUVy25bdRf++aTI2b1 N+s/HmAHHaAwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBEGA1UdIAQKMAgwBgYEVR0gADBQ BgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRy dXN0RUNDQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBj MDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0 RUNDQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3Qu Y29tMAoGCCqGSM49BAMDA2cAMGQCMEQ4GfdC+xyjCQVSCDuZ3cgsYEEpyBZsNjmd LtpvNhSISieNy1dLkaaE1UoVPIEjbgIwbuRK+OThKs5/A13n7j9/Ra5KmQn+92zV Z3oxcX0ytAjOMiZxEAFMvfMaRVGum/G8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGJzCCBQ+gAwIBAgIOSUEs5ABwTS+LFt3dRBUwDQYJKoZIhvcNAQELBQAwgacx CzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEVMBMGA1UECgwMTmV0TG9j ayBLZnQuMTcwNQYDVQQLDC5UYW7DunPDrXR2w6FueWtpYWTDs2sgKENlcnRpZmlj YXRpb24gU2VydmljZXMpMTUwMwYDVQQDDCxOZXRMb2NrIEFyYW55IChDbGFzcyBH b2xkKSBGxZF0YW7DunPDrXR2w6FueTAeFw0yMDExMjMxMDAyNDNaFw0yODA3MjQx MDAyNDNaME8xCzAJBgNVBAYTAkhVMRUwEwYDVQQKDAxORVRMT0NLIEtmdC4xKTAn BgNVBAMMIE5FVExPQ0sgVHJ1c3QgUXVhbGlmaWVkIFJRU0NEIENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx+WBDX982j1vay9xPYwP58B7C+tXQDub iyvSFOzaWNbmWazLO1Wum9gs2D/nrpqOa6sHaS372ln2YfU9fwrti6EvCCSwxI0L IIafWcaFYTYaq0MwmfKUbEh6XDSehYAsXTSWZw3VRhoafGsyDs4Um3crRuhovh24 l9uOWH6jei0f3T6aPFDpX0KG6jmHimA2Nu5u/byMlcYRWtQAdALX5WRayG0916vJ 4mYQwrZJi9EyFJYSxqvp3VshlyvbhoVUwwvhJB4w9bBEJBxeVcJcK+p2wiL/ot6c BXdDSfJLacQ2H6fw2mcuE097vEzvACkeConxu18bqoZ+zcoUDtG76QIDAYilo4IC pjCCAqIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgw FoAUzPpnk/C2uNClwB7zU/2MU9+D15YwHQYDVR0OBBYEFFZ9hZmKpeLNXf9qxRE6 wEPX7ChJMIIBPgYIKwYBBQUHAQEEggEwMIIBLDAsBggrBgEFBQcwAYYgaHR0cDov L29jc3AxLm5ldGxvY2suaHUvZ29sZC5jZ2kwLAYIKwYBBQUHMAGGIGh0dHA6Ly9v Y3NwMi5uZXRsb2NrLmh1L2dvbGQuY2dpMCwGCCsGAQUFBzABhiBodHRwOi8vb2Nz cDMubmV0bG9jay5odS9nb2xkLmNnaTA0BggrBgEFBQcwAoYoaHR0cDovL2FpYTEu bmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0BggrBgEFBQcwAoYoaHR0cDov L2FpYTIubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDA0BggrBgEFBQcwAoYo aHR0cDovL2FpYTMubmV0bG9jay5odS9pbmRleC5jZ2k/Y2E9Z29sZDCBngYDVR0f BIGWMIGTMC+gLaArhilodHRwOi8vY3JsMS5uZXRsb2NrLmh1L2luZGV4LmNnaT9j cmw9Z29sZDAvoC2gK4YpaHR0cDovL2NybDIubmV0bG9jay5odS9pbmRleC5jZ2k/ Y3JsPWdvbGQwL6AtoCuGKWh0dHA6Ly9jcmwzLm5ldGxvY2suaHUvaW5kZXguY2dp P2NybD1nb2xkMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpodHRw Oi8vd3d3Lm5ldGxvY2suaHUvZG9jczAfBgNVHSUEGDAWBgorBgEEAYI3CgMMBggr BgEFBQcDBDANBgkqhkiG9w0BAQsFAAOCAQEAWW2WgPAfEdMI72E2DHWT0uQ0uQnS jZtC+UfB4HuBsk8lkw10O1/PazW4ii+aWVKqxDgHOTdL9x8ZDem2yLGfY0Ctm5LX Upwi/h21xSXIC8thiLr307mJLcTeEMucJmDj7xyEv44XHh+uA/UlfP8fOzgyl4ma OUxzZRGrwm9nMhOa2Lq4xuPs5kVtlDmTtlfglkxvjlN4yKruIL41qltpBLUGrGxO WjckHTvOo7Zq0hYPjUd7a+Go3maEwzm+pIIg2S0Rleupph/+Qkct/9CqCnzmgO9Y Gm3L/eLzyfbnNERCmn7p7SxhN9mBckWKFatUdOUm7TYGOIRy7d/g89R0Tw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEsDCCA5igAwIBAgIQBxnDcO2NwmMwV7G9KPsgGTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMjAxMjA4MDAwMDAwWhcNMzAxMjA3MjM1OTU5WjBeMQswCQYDVQQG EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xNjA0BgNVBAMTLURpZ2lDZXJ0 IEFzc3VyZWQgSUQgU01JTUUgUlNBIFNIQTI1NiAyMDIwIENBMTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAOat+TJAurhrR2jdr1POY6GzD2LPaPPUjk4b niByo7bxz0+a+rXCeXLR9hBevGE2I3SmeOkTvESS0tZvMuGWEHilu0XwcIgvayHg FurkqnZlhO8ZK0DAOoR4Wu8GRjZGLSHYInQANdCX3ObhjGmaEHCNtEfjR8ga+osD 16hjN3L2bIaD7BiOV26bCvQy15Mugim9w34VzNTXS2Sn/k5QgAopQoBDThnE6pPf v6TY1oKxe4+lXcvmaohqBRAcA5qLFJbdU9ITY99fXhGNmWrNxELbLKl2+f6XPdJE LAL29xvsxHHbp0fMCBWIPkbjuIx3z5NSanwS7iEBXQjAgUch4AECAwEAAaOCAWEw ggFdMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFPjdkvPLSs9OLvHo5bwh rrpkeIH7MB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB /wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDBAYIKwYBBQUHAwIweQYIKwYBBQUH AQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYI KwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz c3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL2NybDMu ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDAWBgNVHSAE DzANMAsGCWCGSAGG/WwEAjANBgkqhkiG9w0BAQsFAAOCAQEABSOaZn3fxha7aPt9 7pH1v354C9h7GW6gmFsyxwf8/2j5azwU8yQgjaYDcEuEBpqflmAekyO8S+orpKoH yUhAERJ7o1SU0P5DRsovdxVhT/880f5MrRDL0DEGSCG2GdDxin21rs4LQIOMA1M9 +dXimBrR7WzJpjpCutjwf7KPbvRDeLeJmjFxhZZ3tvr00tYeiyKe0c+ivIiqtWrf wFbvUYpDdU0KSSROwgOV5QKpfco8Df6zgBELbWN0cPaLDxL5U4fjz2MuJ/8m/1WB 14rW2x4mKmaBEkjj9xPlXzyHKLr/rV4KWkkJHoQKvh1AT+nr3M8MK0CCNcKd/ajW 9IO35A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE8DCCA9igAwIBAgIQIrmxhYemmUO17DaPTK9o9zANBgkqhkiG9w0BAQsFADBd MQswCQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4s TFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4X DTIwMTIxNTA4NDYyMloXDTI5MDUyOTA1MDAzOVowWjELMAkGA1UEBhMCSlAxJTAj BgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJDAiBgNVBAMTG05J SSBPcGVuIERvbWFpbiBDQSAtIEc3IFJTQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAOHaJ3DQzdvvkszIkKU0AeCvy8Zl53Q3zUYTXgzxMLH1G4PITOkt tDEtBEoj9zpFEBR+IPArMCQbJtDmfqTi5fbxgaoIp3tnbA3fATXkHKrrBJ/xfvF5 QvmoD8KwFn8O4YWqs1YHAJnErOkiG2NUKQ3eCC5/mX3FRjssLDwwm0K3zTITeFxa PUqvp3n/aFI4y3wsE6ZlTIhZGi4wlff79w9j+GxyiLGKcCe8N2ApDNuGC5Bme4NN VeQaA+P0z3U6lfuHTk5hAZ+P3YO3wmMyr+4qafzmgA9z9AJk4FaVKwPA5jAwRSAl +1IRoxgBC2PINe/RbSo1p4mcLmeFbzg5v4ECAwEAAaOCAa0wggGpMB0GA1UdDgQW BBSwLuVR7fxKz6OH8ROQdi2djpSh4zAfBgNVHSMEGDAWgBQKhal3ZQWYfECB+A+X LDjxCuw8zzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwSQYDVR0fBEIwQDA+oDygOoY4aHR0 cDovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0MtUm9vdDIvU0NSb290MkNS TC5jcmwwUQYDVR0gBEowSDBGBgoqgwiMmxtkhwUEMDgwNgYIKwYBBQUHAgEWKmh0 dHA6Ly9yZXBvc2l0b3J5LnNlY29tdHJ1c3QubmV0L1NDLVJvb3QyLzCBhQYIKwYB BQUHAQEEeTB3MDAGCCsGAQUFBzABhiRodHRwOi8vc2Nyb290Y2EyLm9jc3Auc2Vj b210cnVzdC5uZXQwQwYIKwYBBQUHMAKGN2h0dHA6Ly9yZXBvc2l0b3J5LnNlY29t dHJ1c3QubmV0L1NDLVJvb3QyL1NDUm9vdDJjYS5jZXIwDQYJKoZIhvcNAQELBQAD ggEBADt1vNOq90svOLWKA8nfTq/sIAoaStQD6GgQJmlb/nep45X+/HMk2y381g8r sWEXozVZmAJcIcwBjInCJLeqsZxQ2s5LLFLIrIch0OLNZD0aZbH+NwHd7B7NTp75 YT1cp1t7wHXdHdOUFlIzZF4+Ei3K2IXWe0JaotITWKlxicb8oR2zwYYf6QD1SCk0 3CAbmsh4O529JOfB2GM0T7o6w1oa7kGy4/MCJszfiRb8D4ZJlYDt9Zy20n9Zec4F 7pksJIrHt+V3GFFnco6++2BYKsgZdCkSE8T72HQBEohIzV1Bt8N8QbnBncDIpvqb +mQ7E4SSevEUAvASheCe1pd/S4c= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEmzCCA4OgAwIBAgIQCFpOGSecTFArUyfCgdxJZTANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMjAxMjE3MDAwMDAwWhcNMzAxMjE2MjM1OTU5WjBJMQswCQYDVQQG EwJVUzEkMCIGA1UEChMbVW5pdGVkIExhdW5jaCBBbGxpYW5jZSwgTExDMRQwEgYD VQQDEwtVTEEgQ0EgLSBHNDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ALGIsTLw26Dg46ITkcr1DHWbsPW2dPfpuMk7E1GH4R6fWYN9WV1Ox86G8BvFbTRY w2jtBgM1ldYgIFbsD5aOMp9immc6HEZ6jDvF7YHXeW2yePJqoxgeakgPtve31oY4 W2Celh/ygxOsJo+UdQ4ZxnDhUsxzKwWCI8RvaHWlxTm+oM4RdE3X7Tk1FTmXEke3 VRmNulEVd0DkcUEfMRb3uDxBPjr2qU/eOQOOTW8s0t2HZxFRtXDu0TdLJsTPKP+7 MW5EIuXZX6QtwKd7mUW01qq66j0Sfanx7Ji+9l1On3sgd69uZieGCONYsLLGrcIM Fja30d7OiJrytjduH46IplcCAwEAAaOCAWEwggFdMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0OBBYEFB9NgPDU9i09W5QMF7OrOMfmju1CMB8GA1UdIwQYMBaAFM7D SrmZVfK422C/qX69VrWXNqfWMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggr BgEFBQcDBAYIKwYBBQUHAwIweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhho dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNl cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RHMi5jcnQwRQYD VR0fBD4wPDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 QXNzdXJlZElEUm9vdEcyLmNybDAWBgNVHSAEDzANMAsGCWCGSAGG/WwEAjANBgkq hkiG9w0BAQsFAAOCAQEABBWSg7/VqOPpL/XaJKkJpb095BCr6bEutei4jggnQsUt 6I/w5jMPN0pijji7yPtlNdEazn7dysTuGOtGMecA3P5MrVM3GL6LycWg3e0lC6wh 6N+zIg1Y9nmRJHDsD3wr6HCQJhN/PPoOXrWIjU2MO3eAmRmq0Il6SX1a9MmWBYsG qv6TeJE5GbC5REZOEZNCEcIsCd/vJOmDC64r21L74dAGNhRwBeyYeQaYi60SKeOZ rtm73kJAHmqxh4kSLjQY1bN+4D+/nqc6VKVbOg3YrtpunA29NZXfM9lDWXST9may PB8K4Bp67jyOrIYUfVeR6Fu46wQut6bmJnzr5u8crA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGzCCAwOgAwIBAgIQBmcDW7sU/WOvwNaoU07+FjANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMTIxNzAwMDAwMFoXDTMwMTIxNjIzNTk1OVowZzEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMT8wPQYDVQQDEzZE aWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBUTFMgSHlicmlkIEVDQyBTSEEyNTYgMjAy MCBDQTEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARnvW/xPOudvtC252wTq9ef 6fbdFeWPkOscfpRTkciuHj7UcumQSH3lzkPEIx0KpesWa8epsks7QwkZ4fU/Tkf9 o4IBhzCCAYMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUUGGmoNI1xBEq II0fD6xC8M0pz0swHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDgYD VR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB/Bggr BgEFBQcBAQRzMHEwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNv bTBJBggrBgEFBQcwAoY9aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lD ZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNydDBLBgNVHR8ERDBCMECgPqA8hjpo dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZS b290Q0EuY3JsMDAGA1UdIAQpMCcwCAYGZ4EMAQICMAgGBmeBDAECAzAHBgVngQwB ATAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAHMQH8hhiBfNbxwEwxbbTAnu jPyUh/oi0JrfZI3u9JuiLqca720D6foS/AB5+4EIxpm7CMG4MdN/l7oAiDipaCPv mOmpYUpnT7A63Cr0q4g84rI1ZmdqA40lVUUf6qC6E34tC73qDQF8TJSrfscWFdCl RXR9J4QGrkZ2VNMSDzlDRzWCaA95MfO8x01l+ZdopdE8FvM78gGd4zxeWb8v991+ mBxTDepqKuy/jF5Rm6Bhfxr33ADRs60s1t16dtZ3pOYLALBTPD5KhZ6a+/dk5dnh 6c4PaeZQYBUAh+GuxfaBlU4qQ8EtjBMCQHreMIwXHYHW5FRYGjgR4NMuaIw2jD0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE3zCCA8egAwIBAgIQCXcYScMZgFRc/uqdk2sJATANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTIwMTIxNzAwMDAwMFoXDTMwMTIxNjIzNTk1OVowYDEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTgwNgYDVQQDEy9E aWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMv2zJsE9TrhfFy3Ar8D2i7U +GP1kACyx4gQo3TUa+3u7lz5SUZ8VvHHp76EjL44U9PHNth46zihIdn0Zo90zSEw mS6bjuTUFYOwRWUOAWQejlDXSX2d9ghJ0EVF8NJTBipQ/EdBjD/13G8UeYjRzLXk U7UZ67wEqV3bP9fauDIJ1sVXo6qfVrb9gh9grcyrBLzyhRQ17JR6oJKtE4vHxoyr QVBOckTj6ZTpszOxbvtEozCorxUHROi1gVfStYfJNRzCtEQ2UT/SFLUBQkC7D8DM O+ed4r4yAFw7TTZ1Z8xxzMED8Sr7UyYZ5NPeHM7TcgoqXWjIueVqEOul35n1KikC AwEAAaOCAYcwggGDMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFImW3npk HMvdTna3b6s32yr5gMXTMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9jZCvD MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw fwYIKwYBBQUHAQEEczBxMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy dC5jb20wSQYIKwYBBQUHMAKGPWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E aWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcnQwSwYDVR0fBEQwQjBAoD6g PIY6aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5j ZUVWUm9vdENBLmNybDAwBgNVHSAEKTAnMAgGBmeBDAECAjAIBgZngQwBAgMwBwYF Z4EMAQEwCAYGZ4EMAQIBMA0GCSqGSIb3DQEBCwUAA4IBAQBSZGQYUhWxmJVt7vLV 7nEN1t0X4cstxLSzPqbX7SBa+elm3W1t6auSR8dxZWs714zICvkKuLFqQs1kl64E uR1LGfy6+rCCJLNZe9CxsJp/ZIGqxJQOZOUqqpPdl5Q4MaPeKjSIVpC4SCqBYseL Au3kkMigDeQVwV+QfkOL5EASVhKbmIPr2vLya4ueWQ06GUYy/aSzAsE/JeALrB9N +akxiAlF4RUiEVWk6yY+fRSthZ8a6rs2WjoePCnidf+lT+1rTYbzz9tooIbGB1XZ mahmYeLkdcFWxFjaL9EhljuMMRzTRCPGxX4QJ2cMcZrDemLEkV8WaK6LWALDBE0Y 8erf -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFzDCCA7SgAwIBAgIQeEqqkOCsDApLaTiaECTYZTANBgkqhkiG9w0BAQsFADBS MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UE AxMfR2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IFI0NTAeFw0yMDEyMTcwMDAw MDBaFw0zMDEyMTcwMDAwMDBaMEQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQKEwZSV0Ug QUcxJDAiBgNVBAMTG1JXRSBBdGxhcyBSNDUgU01JTUUgQ0EgMjAyMDCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMHaLPBBFJtqnBq/8YMHJVgBUtnw+Oh0 YVNMfjZgn9e4+FdvZWiTRa/tR+A/HNwQ6n47M1hMX58Pvf47ca82cYTfLWAR5uec A9H7mbWKWTP7GGRxrwZiD0ejHy42Zctdw8Lvxn4owaY4JaQj7+o0mWJ9d+oSQ0+H purs9TMgqm3A+s5xlVhk/sWCoP6oqqqkFVpR5fiM1pPHbjUT+3yXEAybfMH+eauC H5DNFcIiRSTXjwGe/zRaOTO04z83dJMnzG9wIBEN7OqgTjujnyHnGbKD+rAMVl0K IGou8HGyb21S7kVF8KIya5T7vusJw9uXt4hdm0h5qR24oJv9DmQhHr0CAwEAAaOC AaowggGmMA4GA1UdDwEB/wQEAwIBhjApBgNVHSUEIjAgBggrBgEFBQcDBAYJKwYB BAGCNxUFBgkrBgEEAYI3FQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU r/1e+9ChJWr9NCMRStKbVu9tPKcwHwYDVR0jBBgwFoAUoJMVKG7ujwiyNcaeYnl0 p7EOK3swgYkGCCsGAQUFBwEBBH0wezAzBggrBgEFBQcwAYYnaHR0cDovL29jc3Au Z2xvYmFsc2lnbi5jb20vc21pbWVyb290cjQ1MEQGCCsGAQUFBzAChjhodHRwOi8v c2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9yM3NtcjQ1Y3Jvc3MyMDIwLmNy dDA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Nt aW1lcm9vdHI0NS5jcmwwTAYDVR0gBEUwQzBBBgkrBgEEAaAyASgwNDAyBggrBgEF BQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDQYJ KoZIhvcNAQELBQADggIBANKou23AtUxPNNmqUwgd0GOT+zlmUBU9HNOjadQKlwQG tAaKoupzSoqI2T4Ify423lQW4FGd896QlxLGCuHyA/GPrFAIG8dX2rxkUUu+c4kO M8MUZY2qEJHZNvGaFSE642SaiTWEnyhvo4BgwHZyKm8sw3TsafJsa9RUro8//iDp OK1cVfry+ScbYlwkB+8yxGUf1tVdytqlI+eAc1MTGdJCwk7xOAKrOn7JlohnOSVg Ma6HUlClYkSmGS5mFXnc4MRk0wh5+yVfD3gmp5ijrmNN1MWxjicL5EEVpCccZWUS Rj94PjL08qX3tDCI2iElBZpHZqwaci/eOCq0dS+JFkA8e0fVdiUTXEfWnd8Sv2jS eawuUgjPyaH4sEdAINUkKITaGEBs5ip3ozNvILq2Ho6QKEKvzQmN/9Tgqy6FRIYi AmIqR5yy1A4Q/FE2o9252UjHUajj1JhuVH6pLZehZh3CQ/C4gw8Gzth7+cr3YrDI 3KDDhqnE2UBPelhG8gDfVIkWqCx/Zw0IICtqiVDlSwWDVVTXtXV9NFjx0HE9b1HW E29ORa7mmqOui0rx03DbT8hEbn/xL6D8+/xxvg4suevPd9scwiZmdrxAk07/NrZ5 ryHVUmMS43n2SCOgiexzay285uxTecF1gmxfGmQC74rnwf7vfUXO1c2umUYYy7GB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDlDCCAxmgAwIBAgIQKJfNs9RoQEKB9YnkWWFQXjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjEwMTAx MDAwMDAwWhcNMzAxMjMxMjM1OTU5WjBkMQswCQYDVQQGEwJDTjE3MDUGA1UECgwu c3NsVHJ1cyAo5LiK5rW36ZSQ5oiQ5L+h5oGv56eR5oqA5pyJ6ZmQ5YWs5Y+4KTEc MBoGA1UEAxMTc3NsVHJ1cyAoRUNDKSBFViBDQTBZMBMGByqGSM49AgEGCCqGSM49 AwEHA0IABKLfmrJP/3JUIL6x4NeI1RO6wwMvtE7lUGTSICh4LKqTPPwciLXZFqZ9 S35nSaffgumGE0arHjMQNOwZ6I26NLSjggGGMIIBgjAfBgNVHSMEGDAWgBQ64QmG 1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQUFGwSyCx0DHSgUiiXuhMENVKL0VUw DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdIAQxMC8wLQYEVR0gADAlMCMGCCsGAQUF BwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzBQBgNVHR8ESTBHMEWgQ6BBhj9o dHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQ2VydGlmaWNhdGlv bkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUFBzAChi5odHRw Oi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0RUNDQUFBQ0EuY3J0MCUGCCsG AQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49BAMDA2kA MGYCMQCPXlLgOj8i3GxpIaoGCUkIgu2SY9QDAVQT/74gVQIvxTEU8yNZxCSl41U5 LnHBNPgCMQDN3P0h3gDyYEeUvCrByslgfPFoS4pzD69ei/DNQgOhkyUBLkkbDnqB HbfX2BWCEZU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwzCCA6ugAwIBAgIRANdtqqL1lP2wjo1HSeoxrfEwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIx MDEwMTAwMDAwMFoXDTMwMTIzMTIzNTk1OVowPTELMAkGA1UEBhMCQ04xEDAOBgNV BAoTB3NzbFRydXMxHDAaBgNVBAMTE3NzbFRydXMgKFJTQSkgRFYgQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJ11mItxCppn7NUZiwO9TjQM59M8Yc BjmWe2cOfuIkhVC3tc6YXZmmz01onVQ8t4uWW8caeNceESWe8O+TJQslOThMvR/S 89q/D0BQKIKgaWq4U/ifb/Md8PJdmO1s/dMhsvbl8BJ4K2lNtA5nf6RT5yfAijbc a2mFbvKIMwzLN3WuwV8rA1hJ+lWdABaSUxHKcnPwwD0wxVCXkGx2Ss7AttfJG0DF /jskdy60IRkQy4nOSEX+KzTvfyMkX0e5+FOv3zD7ckfD4eNQkC55JR9JAqn+XNWM VU6ehZScTRP8LSmz7XxXnQ+SpwwrrB7x1D76H77G4w0g0wt4Z53gVYZXAgMBAAGj ggFwMIIBbDAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4E FgQUM2pQsuzMQCwNrLVVQi/RH9O5ybAwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1Ud IAQbMBkwDQYLKwYBBAGyMQECAlQwCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGG P2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0 aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKGLmh0 dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBQUFDQS5jcnQwJQYI KwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEM BQADggIBAA9CNeMQAVbcJkMjQtiT1Kyg1Y20jFnBjbI0sWmssOXXdHoYJHje9214 nGu0Jyi5/HQZLpCoUDC4HJC+OHFKeXNq6m2u6YVPKu51eJmmtUna9qb9CJOM01uL mLi7FcPOKPAAM4RTMbkmEGs0sqPKKMZ8+m8hB2sYYUsjk+ocymDhVK7PkYMi8lyA nWq+E4ZyETEjST0+qmar0DgY/piyCatFYVTPG/jHTXXIbZoJ3+w7rdXYmA3xdK5X +xIL7IZ9dz8sBN3Fvi6OcIIrvB8PcDt6qxbaQvNVPCcHmO4WqlkD/VcstWHP9THv zxu2aBK95BsprNYhUX5w2IHOzpOpws0OCN8evNt0/4io2v3etlECy4gqgVZLPj92 il3Dhy/KmUz3tWx1X2WMXObc15flmT2Vfajp8VzaJFuSdCDc1PkSIJ6kAH0wPjDp pOWgtYLdS9vuw75FNGbEm1l38DCuCt1r9xwK1koXYIKgvS7NqGGovUFnWvYQcZ/W VmrnEru8oSoePBOtHIYXb+Oyn1XMgwiUcm91l2NZupaRsjdJJvPpT4iyrXRE5rSY T9Aqacw088vDh8NGWXE8H8QNC5/um/ZR2uYjaOej5OdiOGAQLg5nbNuQJwONosiZ q5s17afjuqnHUNhopzhl+leQdg1oww0v9xEfQ5WP5Q82mbmwe0XJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVzCCAtygAwIBAgIQSEXjPpLlMB2X65WI50iYXjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjEwMTAx MDAwMDAwWhcNMzAxMjMxMjM1OTU5WjA9MQswCQYDVQQGEwJDTjEQMA4GA1UEChMH c3NsVHJ1czEcMBoGA1UEAxMTc3NsVHJ1cyAoRUNDKSBEViBDQTBZMBMGByqGSM49 AgEGCCqGSM49AwEHA0IABPnhVNUG3MK3i1NJ+B4rAT2vMmy604yDo725ASwI/77D PPPeOtGWob7IUnBfNLXbrIFx09Bx6tVUAI8Zbz862C+jggFwMIIBbDAfBgNVHSME GDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQU/bt2a7Th/LpQZu6T R8wdiTUh+kMwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGy MQECAlQwCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl cnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy bDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RFQ0NBQUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6 Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaQAwZgIxANznrqp45oCQ ldqj+PTbb/gzS0M7mdYRCoCIaNZIlW1sr5y1GMwlevCU0eL8LXYwPwIxAMYox2hp KooQxzvxwXr6l3xddEZuAqcvXGKi4lJBPFt27zg/V4kh3tdYi72YlvhYmg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwzCCA6ugAwIBAgIRAIW9PkwvxiLY3p4Ygdwck7IwDQYJKoZIhvcNAQEMBQAw gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIx MDEwMTAwMDAwMFoXDTMwMTIzMTIzNTk1OVowPTELMAkGA1UEBhMCQ04xEDAOBgNV BAoTB3NzbFRydXMxHDAaBgNVBAMTE3NzbFRydXMgKFJTQSkgT1YgQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+stDLnpmqDpXIK6ojHoxKqdshnOa1 8xfKLKN7FMXaU06skYL5clBwpDDRp58WUgQbz2SX+0+bugBiilMGi8M2TDtIU8yU ZoxPWW3cvkT4U/cY/xoi7Cyl6CPjZetpEcp39EPNEH8jnWe63i/UkrCzjQy69w5R i5Y/gSMSNiMvihcZ2dMfnZYyOlf62NGcEc2vtiP5JiZuTnN8w0bAaieMgGZaTHdB p1O4sTCc6b6qnxRq7tqlRW8zvSqgM5me53BOaLufBp8nGZGYNH1BRFLcgmxhKG7x 8G/w2J1wGmrsF+pUH49rDInENfqG+j4YnBgzsfr2nayzqSJJw7tkdfFxAgMBAAGj ggFwMIIBbDAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4E FgQUxlReWmSYhsP71A9IiStbK/OxIK8wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB /wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1Ud IAQbMBkwDQYLKwYBBAGyMQECAlQwCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGG P2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0 aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKGLmh0 dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBQUFDQS5jcnQwJQYI KwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEM BQADggIBAHtxRs/J+gexVvIo6Wf5zaYdAyNU4jP61bdP+3rlJ2sSw5yxEwqrC/Ja 6kD0TZvRv4wksUB0vIP2Dg34XsncX3SA8pq/BiPHsqSIkUGMUl1AOYIZwZtWoqz/ cTlhSGvxd9YRgJ57QHQ7HQ9SLVFULpNrzFD36gdeu4cIUsS3od4Xohj2+M3CkfYv qnIcXw2BJ+Uc0c6+7OHPXgjvSRhJXGU8xQ8VkrQP0RCWSE2JXlYlvaZfzfsb3kfr qAO2AS9GoNgfl6D+5ZXp5A/DxebheUCQPjQGac4xooI5im2AnSQ8oITyXbE43CAr oxXjoKpDeEHUguO3IxpGnqBHF6ivd/vLbxwPcOWzOvCCvAShoBGaomvgmL4pqtpd PDm3pp7vCauw6E8MneKJnbYffv92LZK68dvZ7IwvOsFE7pXZEH8EpinTvIjECTDa Sketwk3r7X/rFvxICpGYzBVy1R//NlGBGOjfwQbAEODhImpyUiTUngXOHs6wkZDR AyKnKNy4NvGmQNt9MdfN56HBsENjTdfrXtUgKlVFHgkuSqMW0pn3lRtH/AbhS3zR LBocG7H8P+qW5PEdWKHK+tt7I8xHxsa6JkMwYvNk8sCaQbtFDUejEzu1JEe7vJHA DkxxLfZ5M7TOcaTwYt+DMw0ot2GLLl4W5DytSZUSzu9gihgu2c3q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF/zCCA+egAwIBAgIQIPqMANyfHxYpF9tPDcf/zjANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjEw MTAxMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjBkMQswCQYDVQQGEwJDTjE3MDUGA1UE Cgwuc3NsVHJ1cyAo5LiK5rW36ZSQ5oiQ5L+h5oGv56eR5oqA5pyJ6ZmQ5YWs5Y+4 KTEcMBoGA1UEAxMTc3NsVHJ1cyAoUlNBKSBFViBDQTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBALEl5/pWczUsGs5mp2hlzBC70yn/BeOabkdNgTuFk4wQ ZZYWLBOJs2W5LD/wlSvow34JdCtIRXn2vViXCyJL9nenPOj6F/RAp0oWKp+4z9eK v9yCIgxAtLi7SRfltF6FdXpfJhbCXUhXZW0rSobDoZegMnyP0KuMMVuqhVlgMHz7 gPrdhoUlVvYsZ5vXK5dekfg1+cPotsKkgXnGbTuEP33vBn9xH+7/9o5UXO/oOW6j D+bm1lWBntN1JcSei2Xzt39+kZ13O4ZHv10h+WfKbTyC6or5xKV0feRwSucfjVX8 mI7sgU2GDu5ZWlFFC1WD0MY1e5Y7FiFRU0yLY4LBY0ECAwEAAaOCAYYwggGCMB8G A1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBSBO1B95Ywd Evo9F+/zYcezGuMSFTAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwOAYDVR0gBDEwLzAtBgRV HSAAMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMFAGA1Ud HwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RS U0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOgYI KwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FB QUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w DQYJKoZIhvcNAQEMBQADggIBADpJuD5iUwhf3wAujsi2qjfzuR2xTleNJT6D9ugT l/gSRbjXcuXX6cEf4dHez6iljoz4STdCFQJhi3iDM+FiKDaufHc6kCyJNR8p3Yva /qotW7vLALYqi3y6qCVkC40yZxjjOiuFqp9vBBmP0mVtDb+XxZIC8XCm/dlOwzdr AwabfL1OgxfuW+9F8Muv/8nPSbEyHnUMsI2q8W/MPcBcHC/QPQtbWlJ+B8EM6+8p 9VxHtoLe96nL2oj6nNdKh/g42DPglYXwJdQG69l4rage3Qsgj9uL1qYbchRN5g69 ARpVx2d4PKDQkK84MWyLY9qccMnWQkEjRNWha9sbmlIkzR+VRylZ9WRqsE5YZjps p+FZ4CHJKdqpHa09Nf5Hdzl4KvPl2mdfx4XWoSYlGDf6jxib/FcP+HWntI3Tkm17 VVwnZM1Tqh+foTkSyDOQ8JslTnZrm+lDJ/kNsZvkpmAD+LSNAiRbokJ8l5bqyhjo jVB8XTY9kLqccJ4+jt55XnWkIi297D1stHY1bbQGh1R9h6h94uRT+oXMZkAUVkMC eg4R1zN/+w7KKCkqf/1LHI4+cVAWfPbt9OwCJ1WfMOaZCgPjUfZIuxCDPh7JYsEj 99oQdBqjspcmYjEyBNBcdqr8LgRjUXILrOqDbp7iHjSS2gwN5nbG0rpeJeymdhX0 9LGr -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVjCCAtygAwIBAgIQRGjtk17oimTIUBCCyKO68DAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjEwMTAx MDAwMDAwWhcNMzAxMjMxMjM1OTU5WjA9MQswCQYDVQQGEwJDTjEQMA4GA1UEChMH c3NsVHJ1czEcMBoGA1UEAxMTc3NsVHJ1cyAoRUNDKSBPViBDQTBZMBMGByqGSM49 AgEGCCqGSM49AwEHA0IABHl5lR0qY1Kqmo0N+1d5OWsKVPV8gTcyhBbzO8gnDH3V nIbuU830D3qhoQZ8rGMtfPA/fQfuUzMHRa0nn/SSSwWjggFwMIIBbDAfBgNVHSME GDAWgBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAdBgNVHQ4EFgQUDEyxM6ooYMhsp8BO toMZ1ZuAR8kwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGy MQECAlQwCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl cnRydXN0LmNvbS9VU0VSVHJ1c3RFQ0NDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy bDBxBggrBgEFBQcBAQRlMGMwOgYIKwYBBQUHMAKGLmh0dHA6Ly9jcnQudXNlcnRy dXN0LmNvbS9VU0VSVHJ1c3RFQ0NBQUFDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6 Ly9vY3NwLnVzZXJ0cnVzdC5jb20wCgYIKoZIzj0EAwMDaAAwZQIxAKGOzgTunk+/ jJnqQ0MZqT4Hw4NxVSNxWOXCGZECmc5ngb/l+NQXOXyk9ZfVA+xonwIwPBsz4EpG YZFPwSqYHf21y33UZ3cT0vw8HUO5gp1MJa391vgSP9W6W2HbBU5p/Dja -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgDCCA2igAwIBAgIUKDfVw8K1cpS+z5mv6Lvc0bsLIPEwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0yMTAxMDYyMDUwNTFaFw0z MTAxMDQyMDUwNTFaMFkxCzAJBgNVBAYTAlVTMRYwFAYDVQQKDA1EaWdpQ2VydCwg SW5jMTIwMAYDVQQDDClEaWdpQ2VydCBRdW9WYWRpcyBUTFMgSUNBIFFWIFJvb3Qg Q0EgMSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALMrbkb9kz/4 y00r7tfK+uDRomMNd5iCDVMWOvSx1VygKoBn3aavw7gq9Vfb2fIMIWkWG0GMxWbG cx3wDHLWemd7yl9MxRUTGXkvH6/dNEavAQhUTL9TSf/N2e8f7q2dRDNYT7lXi/vR fTBiYlY7BLNha8C3sPHsKduaJN32cjdjVFH51rFDRdhUXlo2hhOjgB6bqoqs75A3 Y3w88AdbMkapT63oGsCDO6N/uX2Mo9GSWREvlxHiXSMFf5qFw41vn5QIa5ADL1MP CzlLmJSHXE138H1+cG5IutD7tIieKjo/t+66PGMo8xicj3yUd8rHEmBqClG4Ty3d fF+bETFjLIUCAwEAAaOCAU8wggFLMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0j BBgwFoAUo5fW816iEOGrRZ88F2Q87gFwnMwwdAYIKwYBBQUHAQEEaDBmMDgGCCsG AQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMWcz LmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVvdmFkaXNnbG9iYWwuY29t MBMGA1UdIAQMMAowCAYGZ4EMAQICMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3JsLnF1b3ZhZGlzZ2xvYmFs LmNvbS9xdnJjYTFnMy5jcmwwHQYDVR0OBBYEFJkRfemwrS1iWnDTPI2HIK3a2i5B MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAb6tTptzzi4ssb+jA n2O2vAjAo7ydlfN9v+QH0ZuGHlUc9bm8dpNpBo9yt6fWHIprGLJjVOF7HwVDQcJD DhX4638Q7ETDrbTVQ4/edX6Yesq6C1G8Pza1LwStXD/jCQHFvWbPud86V0ikS4rS qlmu3fzUrGZ2/Q+n5jrnRqM5IS8TXYcnzLD3azH1+aZjkwQt9HP4IuvAe/Bg9aWE XeDmksbg0SqQInrWn+BVYtD+hCZNz8K0GnKKpx3Q9VxzRv+BMbO5e9iqK1Hcj5Wv ZXvU45j2r5y9WML4fc8CvphzbF6ezr1e51i+yabNmfld33gRX48V5oNk16wX32ed kQ83sKNomQm1dXURWK8aSDcZFAvJQ8vKTLIE9wiQmtjfSGoJzQhKLaN+egrp4L9y fjpFIeK4zgAH39P4s4kaPWTdfXe2n6P5o7Xolp4R22SVkI76d8d+5Iv7Rtqd+mqI y1hkwyTBbOBLtyF7yMtJQewkkZ0MWxkPvWg193RbYVRx8w1EycnxMgNwy2sJw7MR XM6Mihkw910BkvlbsFUXw4uSvRkkRWSBWVrkM5hvZGtbIJkqrdnj55RSk4DLOOT/ LUyji/KpgD7YCi7emFA4tH6OpkNrjUJ3gdRnD4GwQj/87tYeoQWZ6uCl0MHDUCmw 73bpxSkjPrYbmKo9mGEAMhW1ZxY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFhTCCA22gAwIBAgIUD3xNgeLm+YKMdFKtYwTMeUhkIrswDQYJKoZIhvcNAQEL BQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZ BgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0yMTAxMDYyMDUyNTZaFw0zMTAx MDQyMDUyNTZaMFwxCzAJBgNVBAYTAlVTMRYwFAYDVQQKDA1EaWdpQ2VydCwgSW5j MTUwMwYDVQQDDCxEaWdpQ2VydCBRdW9WYWRpcyBUTFMgSUNBIFF1b1ZhZGlzIFJv b3QgQ0EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMAnbPqFlNP/ J+CE+VEOIq3IglQP2PSZtUy8xbly85F3LhidGEtQd4B0aCDvJBLYzybE/UC4AIdx T6K3Ny5QsjDm/U1SFZ/X9qdAIE+8ayue88+qygTAqs/0zAeCcQ230sO9Q2HGfiv/ bWCpm2ftTUR6E3HDdcuP6wgND24Tayhf9e7s1PS7dDoch8a7tONEnTMEqM0KyNEx JSr723lCJig52k6AedJoxnwuy+aP008Ly4wED1P3sYLe7z59T9alxcqod+5TDT/F /ufN1i1gMANdf0b1jVRDSadDXZp8M1LzO+POydeiI8m7Aj++Uo+0IUbBaFy46JmW GXybOfATGZkCAwEAAaOCAVQwggFQMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0j BBgwFoAUGoRivEhMMyUE1O7Q9gPEGUbRlGswcgYIKwYBBQUHAQEEZjBkMDYGCCsG AQUFBzAChipodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMi5j cnQwKgYIKwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3ZhZGlzZ2xvYmFsLmNvbTAc BgNVHSAEFTATMAcGBWeBDAEBMAgGBmeBDAECAjAdBgNVHSUEFjAUBggrBgEFBQcD AgYIKwYBBQUHAwEwOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL2NybC5xdW92YWRp c2dsb2JhbC5jb20vcXZyY2EyLmNybDAdBgNVHQ4EFgQUz5LTMFSrg1pTz+1GGrYM qzz+w2AwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQA1p3fuWQ84 FbVgpsvav/rV+7NbEqhfNPJFZhNX2X6OjYMlQCLY58I3/8JxOVPfDrVxJwBZ88JZ ns6BIuiyyJ7edd2l8sQdIeBY81hzdEH1lDMiOz4cAwd9BWz5zGioJu3JuJ3Uip1P CSprl64JuGmDOew2+RvrCCE1Rjk3m8sfKjU49RSrjtQOpeUOQyNjieZVze8aHg08 oqCZcq5j3nk4GZLdUz9dId+Uf8obdFTFWVu6nvqHbewzMWI242I6gJmkvH9CF/07 bAECg6anrCPo5/5inKCBvcfii3+6Afau49wXum7FDH6ISRR0nOkje7nKOEx5Nks4 SZpshBHo8TKwlBL0jmOMpZ5exD0oXmEjP5X1qHZIkt1KP29KR23OgFTcxnpXx+// 0CpTDacSkgbPLVl0M2cTXjI4g385FYUSQpVfxbhRd4bxbTS2hyGJtOPgEAXF+UNs tDQXId3TO+JOqpIPi9fz8GtI+cHeV0YK1G9m5Gplx0nPeG0K+tvAgS6ubaiBpqPn 28iqw9jzRDrk8WFOTJ9PgPnCbjXV1nmU8/B9tI7BjzabKC57DZF488ptx0vU+dCx E4Xb4K3VRlqKB+vdWQpxRffZ3rFDZjYgLVlJaFC/3zQn+X8rCYmm7sD410RM5eac 0LVGCuV+/A4lnBYic3a8h3SiVQENch+eyQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdjCCA16gAwIBAgIUSBCJadJnyw4+QrXgR+5WgKeRFNswDQYJKoZIhvcNAQEL BQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZ BgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0yMTAxMDYyMDU0MjVaFw0zMTAx MDQyMDU0MjVaMFYxCzAJBgNVBAYTAlVTMRYwFAYDVQQKDA1EaWdpQ2VydCwgSW5j MS8wLQYDVQQDDCZEaWdpQ2VydCBRdW9WYWRpcyBUTFMgSUNBIFFWIFJvb3QgQ0Eg MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL6Mm0E5fD+Yy2zb2Z9N wzhhgOUWXwUH4bQLDMG5sPtjVdJRSuv6eZU0Mavvm5TLXbZ/lgcPjhxyNxyoRASS lb/2gHLDbD2xAJpU135pFDQtGgsoXKaxW4AiGM4N3LRtInkszh/lPTssApFVjt1H PKxO+5Fyie8SYk03ZDN6PEXeWAPqXebmdY7Bl456d9pbVAoPm4desg5Pkzl44R1J 70Iuv08Ar4Fsh9ojYsJIJOr4yPkk0cTcHl2GxyfUsbvLTnCtOZdve4Ut4VP9JBnh FaFnI7NeAmloVs26vqPF7ibqJuRaS7eX1pmoHwXMJTmYbmiE8JOW6NRAzJMzRPrl KH8CAwEAAaOCAUswggFHMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU 8sAT4IJDPvvuL2cyljVc27jLAtAwcgYIKwYBBQUHAQEEZjBkMDYGCCsGAQUFBzAC hipodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhMy5jcnQwKgYI KwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3ZhZGlzZ2xvYmFsLmNvbTATBgNVHSAE DDAKMAgGBmeBDAECAjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwOQYD VR0fBDIwMDAuoCygKoYoaHR0cDovL2NybC5xdW92YWRpc2dsb2JhbC5jb20vcXZy Y2EzLmNybDAdBgNVHQ4EFgQUIzlUcvrV+WRljx07Zw9C2c7mSJEwDgYDVR0PAQH/ BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQAzzWXDfIDGoy7ztsGxScDNgKniQAFn HzimEjPEAnJvlHUy4IpffiHVyjP9usRsh2edVJ+7Hq3m5hoXh5dwAM1/X7K6UZGp 23m132EaizIRELLD0m6hys5MH81CA7T1cnM6jN1ghktZDmXO40PGjRJMSa26bJsh HLKSjAZRkarN1A2YxVX3P0N+BHlOluuKC4zoO5aS/n0a0pvDcf1TCyC1QMMkvb6j q52oKJwpN02Vv6rejDLTsiU2F5IZUOyrxiz4WfFevQ5E8nCEq4ufhE6oSXz/ddH8 gpGKFTFmeLgVsgMBAAOJKXOVacfa/maV6yI10HfI8kf/LQAuJ49FfGmqnRJwdsNk XKFSkSo9aQd0V2QYHO//+EY/wp3VRbRWZfXuSK8HyEbjB6QW+zJXRYat7STb5Yrj mk0RzYjCWgekxpt0Jf1is2PmgzoYWRimtQi6Eay/9GgDZOMzWp2vngLLS8jI9ERU MMOKVB/5xUMekEazeTDHKNgZ44v/We3AUtCk7qQiajcXGwA+/FuRw2EsTUpgWyZB mfwYx+uAfSB9mGcB/4xHbo259vvQ9nUHx3d5/q2CnFgxih1HkKbj+RQYS3kAb0bZ wRQOSr0NUuU9kCMys9WMX7MBmBLJwFFkX4rqQMUA/ujfiUUt5LFxSlPkS617pv0P ezhK137tL+CGkQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgDCCA2igAwIBAgIUQn3TOo/1HYFS6BPH3sk7p2MSp9gwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0yMTAxMDYyMDU1NDBaFw0z MTAxMDQyMDU1NDBaMFkxCzAJBgNVBAYTAlVTMRYwFAYDVQQKDA1EaWdpQ2VydCwg SW5jMTIwMAYDVQQDDClEaWdpQ2VydCBRdW9WYWRpcyBUTFMgSUNBIFFWIFJvb3Qg Q0EgMyBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALxNTdqnFD+A MhketYfVfVUWQKPkVEuyYj7Y2uwXBMRP4RStO4CoQih+hX/h94vRlObOIsqcNnyC ElwBnLbmusaWYLYnDEWoROL8uN0pkWk0asfhhEsXTkAJ6FLHUD85WBkED4gIVWPi Sp4AOwiA+/zpbwgVAgdjJTO3jjMsp4F1lBrdViYSwoPRACH1ZMjJG572oXTpZkQX uWmEKLUOnik1i5cbqGLnwXiDvTAhxit7aBlj/C5IDvONWVQL34ZTYppvo8S3Hhy9 xX0S4HCpTpeBe3mas7VOrjsXNlEoFvejrxcQ+fB/gUf6fLUPxUhcPtm8keBPQuxc qP12/+KG0WECAwEAAaOCAU8wggFLMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0j BBgwFoAUxhfQvKjqAkPyGwaZXSuQILnXnOQwdAYIKwYBBQUHAQEEaDBmMDgGCCsG AQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9iYWwuY29tL3F2cmNhM2cz LmNydDAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVvdmFkaXNnbG9iYWwuY29t MBMGA1UdIAQMMAowCAYGZ4EMAQICMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDATA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3JsLnF1b3ZhZGlzZ2xvYmFs LmNvbS9xdnJjYTNnMy5jcmwwHQYDVR0OBBYEFDNm+y+RBcyzYlLvzTz1fhzOpxeW MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAY0ZuDgyM4I4MO9ll D8qFUPQ8xtcGOuJgSRhDS2onIJ0M8yOGOYJCobIEGIgqyx94kI/n/1Xw+Wvsnhwb OYOtVedx6VGDu6IuSKTVgPPhzwKP5ZA7wtmgKR8+W4E3DM1VerA9Po9ycDK9qCdl K4tuF37grKEzlQKovG+kn0z+Zi0D/E1kN1Q8YmX35HHRenJWKEnAL9QROh0X9jFi SlsHPrxWC3adOdAW+B+kVG0cM2nurd0Ic2YkiLKOOaSd5hbCQY/fCZwohtest+ZU Ajyd+FVzSNvEFrwPzZwKfcdemvD4kew8lx5sG6BUL4GkFWnotxSr+F9Huwgj4pC+ cxE2841a/9r/gliuwDM/8jkt16epFAdw0fXemyM8FdHJDnB++3d8SyjOOQ8j+VHW 31NWx27sORa5CgRchlldXWDzIIEwbc82a1OAfGUmNAsdEHjMl1HMcZHbjCmdSdsw fmyldZrj2YmvOI5ZlE9z4vzi35KyqlxWCtu9O/SJq/rBvYS0TPmm8HbhJQbeMe6p vJGrxcb1muSBANn9T9wvukjiNNw32ciSDCjZ0h4N+CGxbzoZtgIAQ29IunYdnJix ZiP+ED6xvwgVRBkDSgWD2W/hex/+z4fNmGQJDcri51/tZCqHHv2Y7XReuf4Fk+nP l8Sd/Kpqwde/sJkoqwDcBSJygh0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDajCCAu+gAwIBAgIQBBxdKC6zcQ5rcsLavSZxbzAKBggqhkjOPQQDAzBOMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDQxNDAwMDAwMFoXDTMx MDQxMzIzNTk1OVowVDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ bmMuMSwwKgYDVQQDEyNEaWdpQ2VydCBHNSBUTFMgRUNDIFNIQTM4NCAyMDIxIENB MTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLzRK0f/iJs+T+i9//yOWT++GUuwRjML dbsA+9YQsrHFyayUZeqYRATordp1DcodGY/1DxRAwDDEi0cmkfHX08nLQ0ujF1Vh dlBxYUPol2HLYjN3EzVAcDC8V5uiQc5zCqOCAYowggGGMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFJtY3I2mZZjnvAb+GqQVoG/L5qmQMB8GA1UdIwQYMBaA FMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAU BggrBgEFBQcDAQYIKwYBBQUHAwIwegYIKwYBBQUHAQEEbjBsMCQGCCsGAQUFBzAB hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRAYIKwYBBQUHMAKGOGh0dHA6Ly9j YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRMU0VDQ1AzODRSb290RzUuY3J0 MEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdp Q2VydFRMU0VDQ1AzODRSb290RzUuY3JsMD0GA1UdIAQ2MDQwCwYJYIZIAYb9bAIB MAcGBWeBDAEBMAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMAoGCCqGSM49 BAMDA2kAMGYCMQDt1p2aebRUXBPN1FXg+V6oG+mRLdRC49k8dSxwRG77lsj1YqTO IvZuhDckSAkMNGICMQD4lvGyMGMQirgiqAaMdybUTpcDTLtRQPKiGVZOoSaRtq8o gRocsHZfwG69pfWn10Y= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXDCCAuGgAwIBAgIQBg5FPpv3aMZZM2pbArRxEzAKBggqhkjOPQQDAzBKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xIjAgBgNVBAMTGURp Z2lDZXJ0IEVDQyBQMzg0IFJvb3QgRzUwHhcNMjEwNDE0MDAwMDAwWhcNMzEwNDEz MjM1OTU5WjBQMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x KDAmBgNVBAMTH0RpZ2lDZXJ0IEc1IEVDQyBTSEEzODQgMjAyMSBDQTEwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAASAxkIHzJgR7AbL24XhUsAhWIBGyDctd7SLM4KKnZjo jBl8rgSnIBPNJq4C1D8NSoDrShtZRCIDKhxRcu8qKte/ZadbMdMAXIRjGLbOJ1nT H+wcnqBZdW0/BIFOH4Ghe92jggGEMIIBgDASBgNVHRMBAf8ECDAGAQH/AgEAMB0G A1UdDgQWBBTPlXaPLdRfmzWC7vLInLgKENEH4TAfBgNVHSMEGDAWgBSSlvfmutUR uvkiLnt+WtnwJeUFGzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH AwEGCCsGAQUFBwMCMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDov L29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5k aWdpY2VydC5jb20vRGlnaUNlcnRFQ0NQMzg0Um9vdEc1LmNydDBDBgNVHR8EPDA6 MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRFQ0NQMzg0 Um9vdEc1LmNybDA9BgNVHSAENjA0MAsGCWCGSAGG/WwCATAHBgVngQwBATAIBgZn gQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzAKBggqhkjOPQQDAwNpADBmAjEAz4Pf c3Y8KN849HGh0kHVomh/HqNeph/fcdn5JoBxwXqV0U78wWol1G11rM3qAAooAjEA 3aIUxc8+gI9fbOz+dE1Ia/XFWhKYvbuMrXdrO93Z6oshtDxJzWsIJmUBtLQ0MwqB -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvjCCA6agAwIBAgIQBtjZBNVYQ0b2ii+nVCJ+xDANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaME8xCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKTAnBgNVBAMTIERpZ2lDZXJ0IFRMUyBS U0EgU0hBMjU2IDIwMjAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAwUuzZUdwvN1PWNvsnO3DZuUfMRNUrUpmRh8sCuxkB+Uu3Ny5CiDt3+PE0J6a qXodgojlEVbbHp9YwlHnLDQNLtKS4VbL8Xlfs7uHyiUDe5pSQWYQYE9XE0nw6Ddn g9/n00tnTCJRpt8OmRDtV1F0JuJ9x8piLhMbfyOIJVNvwTRYAIuE//i+p1hJInuW raKImxW8oHzf6VGo1bDtN+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB Afr5yjK7tI4nhyfFK3TUqNaX3sNk+crOU6JWvHgXjkkDKa77SU+kFbnO8lwZV21r eacroicgE7XQPUDTITAHk+qZ9QIDAQABo4IBgjCCAX4wEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHQ4EFgQUt2ui6qiqhIx56rTaD5iyxZV2ufQwHwYDVR0jBBgwFoAU A95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGG GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2Nh Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNydDBCBgNV HR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRH bG9iYWxSb290Q0EuY3JsMD0GA1UdIAQ2MDQwCwYJYIZIAYb9bAIBMAcGBWeBDAEB MAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMA0GCSqGSIb3DQEBCwUAA4IB AQCAMs5eC91uWg0Kr+HWhMvAjvqFcO3aXbMM9yt1QP6FCvrzMXi3cEsaiVi6gL3z ax3pfs8LulicWdSQ0/1s/dCYbbdxglvPbQtaCdB73sRD2Cqk3p5BJl+7j5nL3a7h qG+fh/50tx8bIKuxT8b1Z11dmzzp/2n3YWzW2fP9NsarA4h20ksudYbj/NhVfSbC EXffPgK2fPOre3qGNm+499iTcc+G33Mw+nur7SpZyEKEOxEXGlLzyQ4UfaJbcme6 ce1XR2bFuAJKZTRei9AqPCCcUZlM51Ke92sRKw2Sfh3oius2FkOH6ipjv3U/697E A7sKPPcw7+uvTPyLNhBzPvOk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFzCCAv+gAwIBAgIQB/LzXIeod6967+lHmTUlvTANBgkqhkiG9w0BAQwFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaMFYxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMDAuBgNVBAMTJ0RpZ2lDZXJ0IFRMUyBI eWJyaWQgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA BMEbxppbmNmkKaDp1AS12+umsmxVwP/tmMZJLwYnUcu/cMEFesOxnYeJuq20ExfJ qLSDyLiQ0cx0NTY8g3KwtdD3ImnI8YDEe0CPz2iHJlw5ifFNkU3aiYvkA8ND5b8v c6OCAYIwggF+MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFAq8CCkXjKU5 bXoOzjPHLrPt+8N6MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4G A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYI KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp Q2VydEdsb2JhbFJvb3RDQS5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDA9BgNVHSAE NjA0MAsGCWCGSAGG/WwCATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgG BmeBDAECAzANBgkqhkiG9w0BAQwFAAOCAQEAR1mBf9QbH7Bx9phdGLqYR5iwfnYr 6v8ai6wms0KNMeZK6BnQ79oU59cUkqGS8qcuLa/7Hfb7U7CKP/zYFgrpsC62pQsY kDUmotr2qLcy/JUjS8ZFucTP5Hzu5sn4kL1y45nDHQsFfGqXbbKrAjbYwrwsAZI/ BKOLdRHHuSm8EdCGupK8JvllyDfNJvaGEwwEqonleLHBTnm8dqMLUeTF0J5q/hos Vq4GNiejcxwIfZMy0MJEGdqN9A57HSgDKwmKdsp33Id6rHtSJlWncg+d0ohP/rEh xRqhqjn1VtvChMQ1H3Dau0bwhr9kAMQ+959GG50jBbl9s08PqUU643QwmA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDeTCCAv+gAwIBAgIQCwDpLU1tcx/KMFnHyx4YhjAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaMFkxCzAJBgNVBAYTAlVTMRUw EwYDVQQKEwxEaWdpQ2VydCBJbmMxMzAxBgNVBAMTKkRpZ2lDZXJ0IEdsb2JhbCBH MyBUTFMgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA BHipnHWuiF1jpK1dhtgQSdavklljQyOF9EhlMM1KNJWmDj7ZfAjXVwUoSJ4Lq+vC 05ae7UXSi4rOAUsXQ+Fzz21zSDTcAEYJtVZUyV96xxMH0GwYF2zK28cLJlYujQf1 Z6OCAYIwggF+MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFIoj655r1/k3 XfltITl2mqFn3hCoMB8GA1UdIwQYMBaAFLPbSKT5ocXYrjZBzBFjaWIpvEvGMA4G A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYI KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp Q2VydEdsb2JhbFJvb3RHMy5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEczLmNybDA9BgNVHSAE NjA0MAsGCWCGSAGG/WwCATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgG BmeBDAECAzAKBggqhkjOPQQDAwNoADBlAjB+Jlhu7ojsDN0VQe56uJmZcNFiZU+g IJ5HsVvBsmcxHcxyeq8ickBCbmWE/odLDxkCMQDmv9auNIdbP2fHHahv1RJ4teaH MUSpXca4eMzP79QyWBH/OoUGPB2Eb9P1+dozHKQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGuzCCBKOgAwIBAgIQDmRY51TsnMe6yDIx1flNWDANBgkqhkiG9w0BAQwFADBN MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwNDE0MDAwMDAwWhcN MzEwNDEzMjM1OTU5WjBYMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs IEluYy4xMDAuBgNVBAMTJ0RpZ2lDZXJ0IEc1IFRMUyBSU0E0MDk2IFNIQTM4NCAy MDIxIENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMnB9AAUezLy ZIJWqclXdCRODlmfOnlRYNvE3OR/WaHipH5TnngNfRz4nT97RDaZx9Mc5Sdo9c/R 7N7juzv/5XSQIRYp488dRYQOuej2QkdfDKHDBunwqa7shUpm+2NXouQbQqNi3Tkf NURyVFntX+tL014KdjNr0w5KZXAzCsHTie0ZPb9JMn4MQfzKcfHcLDtytiHxCE5M OjEpm6O4YDQgEoPvBXTvjD/SQu4JM+f4jRhPWFzdssuTEcyGy9po/0h2xoCP/exh e8EabVWhqSgz5UWAG1Wn1gLsFzQwR3fYy882OiRJ+uqisbi+QIsD5Dhgmxfo4Voo vUcvairFFdDwQp7nTwPL1p5iZ6u2OuZS/HI0d1Yj5p9aYpi6nZR+S+iJD0hBqtSw EHmmAFzGgTwDBJqHKzanwvsyiUeGP7lmd323M8ZcRKGvRBjH8Caa4vZpkcYaKGAV K/gDUr5vEUAfs30r0NC8cQpPLaLfkA/+tJOvSpRPiPkHk/I7xMq1bJ4zcdlqZ6CC 5hw76litkmt2mFFCg0/JtApRQavIfoaEvwrqxwTxg29ZjvE2tWo8YhwPRf4mogjQ XsbgXLksXThVv5oVjhzKrrydwU1KNbzmmZNRWesFGYhq/aUCEmpROkhvcHqj7233 6gjU8xeBTxbB1KZM3oT9R9JoH3CGYZmrAgMBAAGjggGKMIIBhjASBgNVHRMBAf8E CDAGAQH/AgEAMB0GA1UdDgQWBBSuupQzuu83TQvXGO9K5KENvAe2czAfBgNVHSME GDAWgBRRMxztNkCvF9MlzWlo8q9OIz6zQTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHoGCCsGAQUFBwEBBG4wbDAkBggrBgEF BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEQGCCsGAQUFBzAChjhodHRw Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUTFNSU0E0MDk2Um9vdEc1 LmNydDBGBgNVHR8EPzA9MDugOaA3hjVodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v RGlnaUNlcnRUTFNSU0E0MDk2Um9vdEc1LmNybDA9BgNVHSAENjA0MAsGCWCGSAGG /WwCATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzANBgkq hkiG9w0BAQwFAAOCAgEAm5n6ds96TsvAgH4+P/HASmAPv4gJGTkgXjflouTbHJqx FAOsExKNfs0G7BlrdqcFnIOcNR20t0hDvikyZvLT9yBAJYB3uAoYZP/7HIkdkjQB 1EfX2A9VLzEhAitWYnv4A1vwIVgI7nKaSTz2wGd0Be6cAu+4xxjKieCYAQduI14t ebbHEapLulqRuvemZc/dAIeAVVrC01GKhPkGrb2iAXCRmZzo9IYh59l4u8K9LoHb 7Hf4Ff2uDUgIa1Zabg4wXjwYvoAhxPhRa/5lSn/tGCRg/JSpi3dF0Hry1EIueLL3 q3QfX4kjs6qTqWSHGL98sLjWDowRQWDAbgjylkGAVZBG4aqvlgEhKCLNtgzdN250 4XWLJbcCj1F1Bi+WoXSGlpm3x+1otDJgkSnCjXs0uRxrHsB8kWzMR+WpTROqsDVQ /9+NAbtkLNFc6RdRHPBnvNrah8Z8tfKcGJrzjncmyBae1BdFhZ09keXQ+Zj5Fu/o P8gHuJhmwIPsIE5tEs33q1BUXaP6vQU+v/lmvb6Vy2xj3U091m9cYSYt1xObnOLS HeL48nhq1fIhJQfXWX2neiOmZxeVi+g0nZ9Ws7MpARDSTBsR8NBsWBBVcmTUKJhv g/cqkTWFeprxB41VkxJc79K3VL8yo01JYIUfAiTwNecb6/mvBAV/yOzGCYSqff0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGrTCCBJWgAwIBAgIQDo0oQK5IJZBWGLOoqeF6RzANBgkqhkiG9w0BAQwFADBJ MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xITAfBgNVBAMT GERpZ2lDZXJ0IFJTQTQwOTYgUm9vdCBHNTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0 MTMyMzU5NTlaMFQxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5j LjEsMCoGA1UEAxMjRGlnaUNlcnQgRzUgUlNBNDA5NiBTSEEzODQgMjAyMSBDQTEw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDCwLlUmeGwUTj93uzejg2I tHjaSqm+knZ8az09cBAZFLFU9sKDzBHgf43/GpIWIHGLDUGXXZkKtkjJhl6POqda XWt/4avSsQgkELz2uefSxhzELBl4o1U50EULTlri3zUBQ11Jr/hfJLxdMAJqKv21 iVD8GfFDs12Hy08h7IxuA5ROVdBQS2OiU/6Vd4A3uVpzyjaxQsfAvkwz9+3jsozf G+kWW+6Fxa3Vt4EbX+3afaBLeIyBlQvPd3pUY8irY3T6MHlglEblraxyGZ3ifvFu Vt7S98D5+U4CMFzzGSzCCqMxTkgasTMhP8+PjXRN+mL56xyfw/uVmN9vRPqgbRUD g95zx+CRFXgpUQ8yslpl+ECSqCe0cYxm+jWz00VFWtUZAwpE4REGOVdmNGrfNR16 h7dggpFVfeFy7qCwd9up/sWkBmkZB1zL9ENjg68EH5aEbh+jlbF6HuLv4+jibVlD /r+ZW/vJgnMXmUYW1gDl3L//vQ/V4ElqRYzxsSVsq3dwW0SYzI31PKFEb8sqI5IN P10MtFtZ1DgISF9I8LJ35dBDqguoonGC0/d+iq2S7ipcpFIo/u3tK/Nu0QvKMEN6 Dlx6Yhssscj2PhiADKjhRnweWUj/2eKuX8Cb6UmXvh+R4Dm0iEIGop1/r37GUo0z nqNszrYZz1zd4GWG6puFWQIDAQABo4IBhDCCAYAwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHQ4EFgQUbYE39zhEfkdCe1al7Lt3ZyEJ9DwwHwYDVR0jBBgwFoAUYm23 kU/E6qNiYI+g0L61jwZ8aAAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0 dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2Vy dHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0UlNBNDA5NlJvb3RHNS5jcnQwQwYDVR0f BDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0UlNB NDA5NlJvb3RHNS5jcmwwPQYDVR0gBDYwNDALBglghkgBhv1sAgEwBwYFZ4EMAQEw CAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQEMBQADggIB AGHJE9aY60MSsfdEfqIcrdE0c1dXxis9E1l9at6g18Jpyc1C6PsUHdmo6rJWq8Xe NNPkD/4fKhJsrd9TRlUlpIgKiJZW1ituKHV6Ghm7DIRSyx0aMpP9NJ3heV3CIgZr MLtJEFuG5WfolWIfu7sle2lYjA3HxA/xQo803jGOhxbEDX/BTzHo/1X7YGvwpRqJ +7J1B+2l+TA1r9vAlLfIDQRazVYRNxHpJDOwU0ffKaEPbRrgPtogO+8hLSml9Zoe Y8w94f31XbvBFxSbSVpX+/QctNdwx2VuIoRcT8WZ0lZ9aenna5q5AE1C8oTtbw2T qoz4NCaM5XPgjvb0DGPBeH8jWveNo1BmClQA2qYXL55f00m8AZ4Hf6oYANt/zbuM QPhAoSHWwW4V4Pug3XPXM70LlY50y9kPD/57eHryhO2oXQLLx+l6mg8xzL6vKsHT E30whFM32vVTpjejLZ9hJBAJURFaUrH2TZyAmoVbCNy50yuHYQ6FooYpbsbnpYPi KW/E9bc201rqm/GQOWJ4zOJ8a5Etn3zY+rlPaxjJvxc3pSMfgtwwrm9KGXHsI1Gf ULMwUbXclKV2qR8d6ECtUOIRxoQKutN85lmwB05yddu6uQQg0hHeaGFUk7EU90SV ib/FA/op9sXfS3CkOnHQISY0JbWxrzC6eHaKeQi6lR1I -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDITCCAqagAwIBAgINAhZoJeFwBEBhJJH1QDAKBggqhkjOPQQDAzBHMQswCQYD VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG A1UEAxMLR1RTIFJvb3QgUjQwHhcNMjIxMDA1MDAwMDQyWhcNMjcwOTMwMDAwMDQy WjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz IExMQzETMBEGA1UEAxMKR1RTIENBIDJQMjBZMBMGByqGSM49AgEGCCqGSM49AwEH A0IABKdQkzjAHqOUsb/TkH7cz5lRtD374tNZ8rYrCUb1mxypE+VmCb1Jgzq+93tR dE78GRzPI4+q6raha1TEyWgoniOjggF2MIIBcjAOBgNVHQ8BAf8EBAMCAYYwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0OBBYEFIcjqVBIDgeJVApxMPYz0gpH9p2sMB8GA1UdIwQYMBaAFIBM1ut0 /0k2o9XY/LU+xWrwlB2MMGgGCCsGAQUFBwEBBFwwWjAmBggrBgEFBQcwAYYaaHR0 cDovL29jc3AucGtpLmdvb2cvZ3RzcjQwMAYIKwYBBQUHMAKGJGh0dHA6Ly9wa2ku Z29vZy9yZXBvL2NlcnRzL2d0c3I0LmRlcjA0BgNVHR8ELTArMCmgJ6AlhiNodHRw Oi8vY3JsLnBraS5nb29nL2d0c3I0L2d0c3I0LmNybDBNBgNVHSAERjBEMAgGBmeB DAECATA4BgorBgEEAdZ5AgUDMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vcGtpLmdv b2cvcmVwb3NpdG9yeS8wCgYIKoZIzj0EAwMDaQAwZgIxAMnbIiQb5fsdexUuVGoB MVwsDPGd7VC13Y0OBezt7FqFHDwqm8nnVdV/FkNyXNv9/AIxAN51NGqMcbexMOYK pLC0zXfjNwvqBsZhmzCCQIM6MVyBID0rjjxPu7laIaHqAu6T5Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDNDCCArmgAwIBAgIQYE2K+NALqHSLlVhTFyxfLjAKBggqhkjOPQQDAzBOMQsw CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMTAyMTE3MDIyM1oXDTM3 MTAxNzE3MDIyMlowTzELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh dGlvbjEmMCQGA1UEAwwdU1NMLmNvbSBUTFMgVHJhbnNpdCBFQ0MgQ0EgUjIwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAARk532ZA1NckR7q+NgjraG/LOJjie8oaPbt1/Ds q2iudyvkdpcbUOvbWSgtb7g2uauNl8pMIp7uidkCP/16czqQjSvMLzo3g9oNtC1F G3NyCWVfeCE954tmP0f9CSnWFA+jggFZMIIBVTASBgNVHRMBAf8ECDAGAQH/AgEB MB8GA1UdIwQYMBaAFImPL6PoK6AUVHvzVrgmX2c4C5zQMEwGCCsGAQUFBwEBBEAw PjA8BggrBgEFBQcwAoYwaHR0cDovL2NlcnQuc3NsLmNvbS9TU0xjb20tVExTLVJv b3QtMjAyMi1FQ0MuY2VyMD8GA1UdIAQ4MDYwNAYEVR0gADAsMCoGCCsGAQUFBwIB Fh5odHRwczovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkwHQYDVR0lBBYwFAYIKwYB BQUHAwIGCCsGAQUFBwMBMEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9jcmxzLnNz bC5jb20vU1NMY29tLVRMUy1Sb290LTIwMjItRUNDLmNybDAdBgNVHQ4EFgQUMqLH 2FiL/3/APPJVaTPszswfvJcwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kA MGYCMQC4SkI+e2cts1nTN9MCRil97z624WxLAp94hT7tNZGPZLe9YiLIyzgKqW/b E0b2h9ACMQCvV5XMRcunAylQaCQc4J/GwR1p7yrPC0DRWWeyLAkQWi5Ylta9DxlX 74QFFksFCP0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGgjCCBGqgAwIBAgIQICgd04YXHr8FIEWzN/K9hjANBgkqhkiG9w0BAQsFADBO MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMTAyMTE3MDIzNloX DTM3MTAxNzE3MDIzNVowTzELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw b3JhdGlvbjEmMCQGA1UEAwwdU1NMLmNvbSBUTFMgVHJhbnNpdCBSU0EgQ0EgUjIw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC6lZ8Z2WYAqAXZr43sbFCd az+5MU8liFkrqzD5CcOL8AOaKtB1Ggx5t8GjUibUAYvuCNXeUzd4awBM4ARRoWp8 xzRI+AG9YxUH5lWtsmyhfyW4E7VvpRpi5s3tOyQVv8rCpdNB0R/HYM4+wPxigadb L2Cc46fTcbeV2MBPOc9lyVJASewIXQQhI0+CsKOVA4AD3Cj27QhnpvJONchn+hVg vTTDVSkmlrvaFjH3KPzEJsRIiv6Wyc1bpkDyV6+bPzkzXtntXhdXb/RrAcky7ldx N5I0xZd2ESfMUU6yQbqkIfAaBj1Uxd7y780ir5beWijPQU1VsU4NcEpxwQ8CkcFK 7GosXIAOS1XhFbbO7QpfF6Nxe8QGAcC5Dx38f5vubR3PMheivltQSxlGJOhMlidq xehxbaxH47wRQoT2p/3MXHBDydUetOwJLlRxct6ms9px9qD8ubnUX4TmUc88tfWz FM8tWrKNrhQjo/GB/585rBv+MZ+8JwjySCjY0Tiy4WcwBo3sacCyXXWGoJH2hoq2 QbVHW0QpQLSQ2wXClnyo6juVXRW++ZwtCu2MOx5xnadnqD2u/2fH+EAHsCplAtIC VR8j/GeFQGWbdPSXTUrSy0OKm9BiQjJ9GCw4eUZa8zYbOKnsFH+2NtZN4pYLP3M7 wS8IWceGUEkSP5Izm+qWZwIDAQABo4IBWTCCAVUwEgYDVR0TAQH/BAgwBgEB/wIB ATAfBgNVHSMEGDAWgBT7Ljfu44R6Jy7NGTWxM3z/1ERCuTBMBggrBgEFBQcBAQRA MD4wPAYIKwYBBQUHMAKGMGh0dHA6Ly9jZXJ0LnNzbC5jb20vU1NMY29tLVRMUy1S b290LTIwMjItUlNBLmNlcjA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcC ARYeaHR0cHM6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5MB0GA1UdJQQWMBQGCCsG AQUFBwMCBggrBgEFBQcDATBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vY3Jscy5z c2wuY29tL1NTTGNvbS1UTFMtUm9vdC0yMDIyLVJTQS5jcmwwHQYDVR0OBBYEFCFB NGOOHZEMw922JLCoh3uNZWAIMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF AAOCAgEASMJp5E+woUa2Uu9yVvrR1tGxKKSGHsD7yw1vBNLsYeE1yi2yiBJ6FZ3D Q0RMyNIQ+9/ibKRXw6gdml7W19cWhcH+pegCWMKnmoDp7L2fgIcJ2a5nH23QMbXQ 5D0qwZyxetXDLU+ejrhIvAemFVD/cyWmE4+D9olNeeTAXNB6XnMbjLKOHyDn7EqM x6rCOVgCHkM96hRlTpbsbXCMudpWKyxcKv2TbIIwhGITogPF/DDffWij1T//wJq5 BzDac7SR4nHv1qn273hbF61asQT3IJNk32GQ1O7SrspLetSOMat1mxn6oZ0p7EBI b5iulITa70zlFnCExOAbxDU1wht31cMfvonZpJW9FVDc7y4qEDiH1LiMEEbruf4O 3E2z184nnN7RGHfs1lUcfaMjlCQ77TjYALeErR+wuJPLsOw4ALABnY8vcLlCgFOL 0DnWh3e5+Ya10HN7Z9igUcNYjlAFsfF/2O8OKNmaj+a7WwEhiP0xK8GhvCpWaUjn hWy1In/eZLpcKwP/UFuAwRQrOh4d2jgycI8nD6m9E/xwNCeD5ERAfsPq6U0oQ/VQ u/eC/UQzY34gcA2Y0o55QDUmNaHuTWX/C+uqG2KEwanQ5MYmKtMkhEtoL+RPXUuj LqqH8ax8mFQAxyKw0yLLnJTS676AI8rvB3PCmbSBfYA28zYw0ec= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5DCCAmqgAwIBAgIQLD+iaS9BE707f+W2BLSdTTAKBggqhkjOPQQDAzBPMQsw CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSYwJAYDVQQDDB1T U0wuY29tIFRMUyBUcmFuc2l0IEVDQyBDQSBSMjAeFw0yMzEwMzExNzE3NDlaFw0z MzEwMjgxNzE3NDhaMFIxCzAJBgNVBAYTAlVTMRkwFwYDVQQKDBBDTE9VREZMQVJF LCBJTkMuMSgwJgYDVQQDDB9DbG91ZGZsYXJlIFRMUyBJc3N1aW5nIEVDQyBDQSAx MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEByHHIHytNSzTS+F3JA7hHMDGd2cp cY9i3MLTKmE6DJTKc6JwvW50pwKodvd2Qj4RAAy2jSejsVgw5jeh6syt3KOCASMw ggEfMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUMqLH2FiL/3/APPJV aTPszswfvJcwSAYIKwYBBQUHAQEEPDA6MDgGCCsGAQUFBzAChixodHRwOi8vY2Vy dC5zc2wuY29tL1NTTC5jb20tVExTLVQtRUNDLVIyLmNlcjARBgNVHSAECjAIMAYG BFUdIAAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMD0GA1UdHwQ2MDQw MqAwoC6GLGh0dHA6Ly9jcmxzLnNzbC5jb20vU1NMLmNvbS1UTFMtVC1FQ0MtUjIu Y3JsMB0GA1UdDgQWBBScxAlyRxgXe6caibOSNdXhA4z+kjAOBgNVHQ8BAf8EBAMC AYYwCgYIKoZIzj0EAwMDaAAwZQIxAL0Sk3RweR6uG1aSHF3JgHQptubP9xoZyUmz HSa+SSdY5wTGSx5qAowrLPCpLio2PAIwXQGgYzf5QzD/1Bsu87WrUcIVtLixr5KQ wKBaFAyIJ7OOiWgW0HV/NA1UeuSe0zmN -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFUDCCAzigAwIBAgIQVd+QyTw1kJUIhgZviwCzbDANBgkqhkiG9w0BAQsFADBP MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSYwJAYDVQQD DB1TU0wuY29tIFRMUyBUcmFuc2l0IFJTQSBDQSBSMjAeFw0yMzEwMzExNzE4NTZa Fw0zMzEwMjgxNzE4NTVaMFIxCzAJBgNVBAYTAlVTMRkwFwYDVQQKDBBDTE9VREZM QVJFLCBJTkMuMSgwJgYDVQQDDB9DbG91ZGZsYXJlIFRMUyBJc3N1aW5nIFJTQSBD QSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk4EBjvfL2f3hibzS R3cEvMRR1omxX/mrrPIEFhA7ybTrvBk/QCe29KDCQBlvxjAMdYuo3WawooMtAxZW 5OEt+50/moVOgfDpGI57L0X5qL1Ci1FYDtNYXlH3HX9u31YWoyaIfPEic/SNuY4q lif+psVIWBn+DYpt3/yZNCfFAuETaSXy6pjV+0o7mWdZF5mpeGe/LA2aAz2i9BPa 1PQy7HTCc0yLEkqIL9XDPZ32d0x/GuHeWSCRP+ODv39iwzT7o7GdR1g0CV8VnPZZ RkO6oAuRCsmQO+MgYXEFudj5MAutuTdX2Wq9BuE+dnTre1MVDZPUg+rSPrA44YI2 2jUnhwIDAQABo4IBIzCCAR8wEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAW gBQhQTRjjh2RDMPdtiSwqId7jWVgCDBIBggrBgEFBQcBAQQ8MDowOAYIKwYBBQUH MAKGLGh0dHA6Ly9jZXJ0LnNzbC5jb20vU1NMLmNvbS1UTFMtVC1SU0EtUjIuY2Vy MBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH AwEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybHMuc3NsLmNvbS9TU0wuY29t LVRMUy1ULVJTQS1SMi5jcmwwHQYDVR0OBBYEFAVttNnJWBfh0AGn9S8gakg9mvQX MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEANR6LWA13F8P6Nm2/ 8UpyUrnSm7Meh/QYCWKGW/c23q9/MtRh+GanyEWf94zNdDIZATOvyAZzIbRDuNV0 //bHiRn0qjzsikap63YK6qVwAg/25iYKh1DeWWAkFs3XtpudhvZQ5YYlQEz7mD7+ vXgQGl3DldryfZjMV9yKuEPo9obfdjuSU0vQOlct/UQU2seYhQXMfd0DqnFN4rZW yDSvGrflVFcK4kvxBCTEaAeWmevtEwMlTyu4L1EQvFT2gsnFEjqBr15VwTu3Jb5Y cB4d+H/DszM9PA3b2FvT9U6nd6ZwLfv9GHwnZr7hempe8ZJOUh9Owd1K3HEsszuP e+CyTuNeCHfE3ktu0nOEW5FYNaa88z8xGaIgmba95L35vFRahkzbFyGY9942tsDN Ktd1UmJuDCoz2NpB9QgK+viAoARxYniuWj4i0b/EWKy7+nTQWNH+MYp+iZuGyuL9 o7nk0kM9SFB2U0d25LD0BVNI/6JpjX1TRAXDTcSh28AYiJg0ioJICOWXrQENYY6H 2hfT2Abo1QP+NFfr3Tu0KtZTgkGx/5vO+T2akhQOKXFr6aMVNQ44BLhUgu7FaJsi H80kFZYIm9CzfnR0oQGZr+/jF2ttPm5hvApPGmbkfR/eweYpYZSz/52cwc50rdQy 0kNwcFYebGYXu73qou65FGzSSx0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDejCCAmKgAwIBAgIQf+UwvzMTQ77dghYQST2KGzANBgkqhkiG9w0BAQsFADBX MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIzMTEx NTAzNDMyMVoXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFI0 MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE83Rzp2iLYK5DuDXFgTB7S0md+8Fhzube Rr1r1WEYNa5A3XP3iZEwWus87oV8okB2O6nGuEfYKueSkWpz6bFyOZ8pn6KY019e WIZlD6GEZQbR3IvJx3PIjGov5cSr0R2Ko4H/MIH8MA4GA1UdDwEB/wQEAwIBhjAd BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAd BgNVHQ4EFgQUgEzW63T/STaj1dj8tT7FavCUHYwwHwYDVR0jBBgwFoAUYHtmGkUN l8qJUC99BM00qP/8/UswNgYIKwYBBQUHAQEEKjAoMCYGCCsGAQUFBzAChhpodHRw Oi8vaS5wa2kuZ29vZy9nc3IxLmNydDAtBgNVHR8EJjAkMCKgIKAehhxodHRwOi8v Yy5wa2kuZ29vZy9yL2dzcjEuY3JsMBMGA1UdIAQMMAowCAYGZ4EMAQIBMA0GCSqG SIb3DQEBCwUAA4IBAQAYQrsPBtYDh5bjP2OBDwmkoWhIDDkic574y04tfzHpn+cJ odI2D4SseesQ6bDrarZ7C30ddLibZatoKiws3UL9xnELz4ct92vID24FfVbiI1hY +SW6FoVHkNeWIP0GCbaM4C6uVdF5dTUsMVs/ZbzNnIdCp5Gxmx5ejvEau8otR/Cs kGN+hr/W5GvT1tMBjgWKZ1i4//emhA1JG1BbPzoLJQvyEotc03lXjTaCzv8mEbep 8RqZ7a2CPsgRbuvTPBwcOMBBmuFeU88+FSBX6+7iP0il8b4Z0QFqIwwMHfs/L6K1 vepuoxtGzi4CZ68zJpiq1UvSqTbFJjtbD4seiMHl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFATCCA+mgAwIBAgIQIrmxoS2R8YGtenttvrOOpzANBgkqhkiG9w0BAQsFADBd MQswCQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4s TFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4X DTIzMTIxMzA2Mjg0NVoXDTI5MDUyOTA1MDAzOVowYTELMAkGA1UEBhMCSlAxIzAh BgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMS0wKwYDVQQDEyRDeWJl cnRydXN0IEphcGFuIFN1cmVTZXJ2ZXIgRVYgQ0EgRzMwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDYmMs2IL6hXgb7zE6a/VjXorqu/FDKq/V1Y57gs/Q1 9UN0mmuN+LZ+C1xPM9McRQ4qA9KTbz5EEGw1XOEcqgXHRzNzUdFJZEeNnfEba2Zg jtbPd3LIWywDuhh9piYQOuVI2DRLNxv5nhvxDO+n8YT5+dnL1jdHeCEj/utLE9CK iI8PvODDkOCnnfcb3oiLCPEEzogDlzkaErLbzrs0/mtwnJrRyR1nQc9nlD1Fy6qt XvlHQ4sjlnz7K41teEEbLROiMdaFDt5GyKvJ0hujtoR1Rx0iB/GC84h7HGupK/Bi ArC6TRJvZYw64FZN03CMf4cGW6CLPiwonHZ62BkDdcNHAgMBAAGjggG3MIIBszAd BgNVHQ4EFgQUgmx1XVP1RWm8JS2kTInmsrdBh6MwHwYDVR0jBBgwFoAUCoWpd2UF mHxAgfgPlyw48QrsPM8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC AQYwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL3JlcG9zaXRvcnkuc2Vjb210cnVz dC5uZXQvU0MtUm9vdDIvU0NSb290MkNSTC5jcmwwWwYDVR0gBFQwUjAHBgVngQwB ATBHBgoqgwiMmxtkhVEBMDkwNwYIKwYBBQUHAgEWK2h0dHBzOi8vcmVwb3NpdG9y eS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290Mi8wgYUGCCsGAQUFBwEBBHkwdzAwBggr BgEFBQcwAYYkaHR0cDovL3Njcm9vdGNhMi5vY3NwLnNlY29tdHJ1c3QubmV0MEMG CCsGAQUFBzAChjdodHRwOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1S b290Mi9TQ1Jvb3QyY2EuY2VyMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD AjANBgkqhkiG9w0BAQsFAAOCAQEAcr/yh9/+76PwMDluBP8hvn954FbK34U31c+j 67e1MMK8hgrh+s2CIeSi5CbTR5N1IAdiTyvs/P8Zp7sXa/hxr3UJz91Wwn5xrqBF /1fK3pC1g+7yqCGW1/TpPcBKFF+hm4VuqBAkS0H2zrmb//UzP6I0a/qPEnhaO6d7 7dLNs3bos/KGbxrsgKTPuPiJgsWy2rpQQDOfiQUfpLOQAR33Y5EDGN727r+bLvw8 IX37KQG9dWpzel8uDnRyMcCHk/zFkAd0IOljbl/L6nx/jUbICZp5j1rV6K2G6XZZ Udpigo0bZ2KtHph3ZEmjZeT9Xr1hW2nO1wGbZVixtBGFMNc3Qw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICnzCCAiWgAwIBAgIQf/MZd5csIkp2FV0TttaF4zAKBggqhkjOPQQDAzBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIwMTQw MDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZp Y2VzMQwwCgYDVQQDEwNXRTEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARvzTr+ Z1dHTCEDhUDCR127WEcPQMFcF4XGGTfn1XzthkubgdnXGhOlCgP4mMTG6J7/EFmP LCaY9eYmJbsPAvpWo4H+MIH7MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU kHeSNWfE/6jMqeZ72YB5e8yT+TgwHwYDVR0jBBgwFoAUgEzW63T/STaj1dj8tT7F avCUHYwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAChhhodHRwOi8vaS5wa2ku Z29vZy9yNC5jcnQwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2MucGtpLmdvb2cv ci9yNC5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwCgYIKoZIzj0EAwMDaAAwZQIx AOcCq1HW90OVznX+0RGU1cxAQXomvtgM8zItPZCuFQ8jSBJSjz5keROv9aYsAm5V sQIwJonMaAFi54mrfhfoFNZEfuNMSQ6/bIBiNLiyoX46FohQvKeIoJ99cx7sUkFN 7uJW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFCzCCAvOgAwIBAgIQf9niwtIEigR0tieibQhopzANBgkqhkiG9w0BAQsFADBH MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIw MTQwMDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNl cnZpY2VzMQwwCgYDVQQDEwNXUjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDPbjYWircr7kaYAx1TcA937qNLoHK+jyMtwkfGj1yN+T3mGo7uMyINyRFI uLBizvRpDXICfd7VJg/DbpvPfg7XIM/GkDujggbaOp3/bFa/3OlhlEXkabxPD8kT wK1hRHIggdAPK55oamJqj4oiV3lpK+IkM352YyxdvFFpfiMHsf92gfHuuFi1azUV 76HmSCg5lzHZBx+Vp56uz5i8no2KA+Gwl01Qb5NMSh/4233xkJkVf+OW7e4xgepy PVId3yVkpQtwqp7oqLlHyKdaECVgb0Lh1z/njwzwwoNGMyDmS3cEdqFop10VGO/Y KHc1rQ6tRuRibuKq+MzvN34PJrMHAgMBAAGjgf4wgfswDgYDVR0PAQH/BAQDAgGG MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/ AgEAMB0GA1UdDgQWBBRmaUnU3iqckQPPiQ4kuA4wA26ILjAfBgNVHSMEGDAWgBTk rysmcRorSCeFL1JmLO/wiRNxPjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAKG GGh0dHA6Ly9pLnBraS5nb29nL3IxLmNydDArBgNVHR8EJDAiMCCgHqAchhpodHRw Oi8vYy5wa2kuZ29vZy9yL3IxLmNybDATBgNVHSAEDDAKMAgGBmeBDAECATANBgkq hkiG9w0BAQsFAAOCAgEATuazCBEgkWAn+VGQTQIY7rjBidUihJfm1t/mTjo7KQR+ 3iDx4o2L06oeF0Q3wpKYpQgI/TeMqUlYMWQmZbWPE0PX8pfsVAE5E5tVOjh34bNA JwDPVnsZVJwzN3nw5BGQ7sxRspFzIcM/qbbTpNeXf9II4Wsk2+Tv6FSVFZUL3/0u HradbruDWjRQ4IZ7mYqKiEqk08dpOZ+TmBzwykEGy1/IXberb6Ap1SSnn2+RI7t6 N/fqPCrwwFjp8kg1G6etRATGBaPYCx+GjJMFPX+k97Alvoj3/98SvqdegLPYEPjv xUclHpiKLD63NMmVarVQddIL6kOvTe5k0pnxRnR+mndGHIQc77TLbcZFeja56Pyn lSqmer578c7CBrPqo1BVmPyWUK+v6sGuzs7Mq7QQaxVs4710cI/MpPp1ovxMVt17 ENKxLk34LpEKAKVmqwnzbHHRjhXNeCC984XDOwLEp0K4MzHl8ZOWJQAakCdVlFC+ PyA3GP2JX/QLoqWNHGuN9c9vLObDhHVs/L+65De+OdnnjpFGI9xxtsNyRsyaHdFA f5z7ulOoXDXkHCCej/Ehs5docReNt16W2xbH/EBuirJrOzFE2rtALxksl1TdEjOf IKXOJfUqQeVI5+hA7V+n1+A/n7Npg0S+5ODytWh5XW54ccN1drJnMK54ttozh0c= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICljCCAhugAwIBAgIQf/Tlzjamofpe4ZFsCNObfDAKBggqhkjOPQQDAzBHMQsw CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIwMTQw MDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZp Y2VzMQwwCgYDVQQDEwNBRTEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR9Clzb GcDZDNJ5v+Jo/EXiF/q+TVkbiR3KwDlvjO3AR6EviCv1zDSG9ZtRjQwwV/HYAWTb lGC54Faji+ZJgGqqo4H0MIHxMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggr BgEFBQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRIiWD5o30M6gAk otyfB85GiKgyOjAfBgNVHSMEGDAWgBSATNbrdP9JNqPV2Py1PsVq8JQdjDA0Bggr BgEFBQcBAQQoMCYwJAYIKwYBBQUHMAKGGGh0dHA6Ly9pLnBraS5nb29nL3I0LmNy dDArBgNVHR8EJDAiMCCgHqAchhpodHRwOi8vYy5wa2kuZ29vZy9yL3I0LmNybDAT BgNVHSAEDDAKMAgGBmeBDAECATAKBggqhkjOPQQDAwNpADBmAjEAmdMod3458+nB HDNg8KNDbxBK27go5UPnjRbgl/QweOAgXHA8hFzoCYMp8QlSzjwrAjEA+Vf20EHl KBYnP1hBSz11CIZ1MTXazV+wEL1Ep45WDR1/Pb3+QzLbviujkatk3MMe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqK a2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBO VHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgw gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZw i9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAH3KdNEVCQdqk0LKyuNImTKdRJY1C 2uw2SJajuhqkyGPY8C+zzsufZ+mgnhnq1A2KVQOSykOEnUbx1cy637rBAihx97r+ bcwbZM6sTDIaEriR/PLk6LKs9Be0uoVxgOKDcpG9svD33J+G9Lcfv1K9luDmSTgG 6XNFIN5vfI5gs/lMPyojEMdIzK9blcl2/1vKxO8WGCcjvsQ1nJ/Pwt8LQZBfOFyV XP8ubAp/au3dc4EKWG9MO5zcx1qT9+NXRGdVWxGvmBFRAajciMfXME1ZuGmk3/GO koAM7ZkjZmleyokP1LGzmfJcUd9s7eeu1/9/eg5XlXd/55GtYjAM+C4DG5i7eaNq cm2F+yxYIPt6cbbtYVNJCGfHWqHEQ4FYStUyFnv8sjyqU8ypgZaNJ9aVcWSICLOI E1/Qv/7oKsnZCWJ926wU6RqG1OYPGOi1zuABhLw61cuPVDT28nQS/e6z95cJXq0e K1BcaJ6fJZsmbjRgD5p3mvEf5vdQM7MCEvU0tHbsx2I5mHHJoABHb8KVBgWp/lcX GWiWaeOyB7RP+OfDtvi2OsapxXiV7vNVs7fMlrRjY1joKaqmmycnBvAq14AEbtyL sVfOS66B8apkeFX2NY4XPEYV4ZSCe8VHPrdrERk2wILG3T/EGmSIkCYVUMSnjmJd VQD9F6Na/+zmXCc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEVzCCAj+gAwIBAgIRALBXPpFzlydw27SHyzpFKzgwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDELMAkGA1UEAxMCRTYwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATZ8Z5G h/ghcWCoJuuj+rnq2h25EqfUJtlRFLFhfHWWvyILOR/VvtEKRqotPEoJhC6+QJVV 6RlAN2Z17TJOdwRJ+HB7wxjnzvdxEP6sdNgA1O1tHHMWMxCcOrLqbGL0vbijgfgw gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSTJ0aYA6lRaI6Y1sRCSNsj v1iU0jAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAfYt7SiA1sgWGCIpunk46r4AExIRc MxkKgUhNlrrv1B21hOaXN/5miE+LOTbrcmU/M9yvC6MVY730GNFoL8IhJ8j8vrOL pMY22OP6baS1k9YMrtDTlwJHoGby04ThTUeBDksS9RiuHvicZqBedQdIF65pZuhp eDcGBcLiYasQr/EO5gxxtLyTmgsHSOVSBcFOn9lgv7LECPq9i7mfH3mpxgrRKSxH pOoZ0KXMcB+hHuvlklHntvcI0mMMQ0mhYj6qtMFStkF1RpCG3IPdIwpVCQqu8GV7 s8ubknRzs+3C/Bm19RFOoiPpDkwvyNfvmQ14XkyqqKK5oZ8zhD32kFRQkxa8uZSu h4aTImFxknu39waBxIRXE4jKxlAmQc4QjFZoq1KmQqQg0J/1JF8RlFvJas1VcjLv YlvUB2t6npO6oQjB3l+PNf0DpQH7iUx3Wz5AjQCi6L25FjyE06q6BZ/QlmtYdl/8 ZYao4SRqPEs/6cAiF+Qf5zg2UkaWtDphl1LKMuTNLotvsX99HP69V2faNyegodQ0 LyTApr/vT01YPE46vNsDLgK+4cL6TrzC/a4WcmF5SRJ938zrv/duJHLXQIku5v0+ EwOy59Hdm0PT/Er/84dDV0CSjdR/2XuZM3kpysSKLgD1cKiDA+IRguODCxfO9cyY Ig46v9mFmBvyH04= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEVzCCAj+gAwIBAgIRAKp18eYrjwoiCWbTi7/UuqEwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDELMAkGA1UEAxMCRTcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARB6AST CFh/vjcwDMCgQer+VtqEkz7JANurZxLP+U9TCeioL6sp5Z8VRvRbYk4P1INBmbef QHJFHCxcSjKmwtvGBWpl/9ra8HW0QDsUaJW2qOJqceJ0ZVFT3hbUHifBM/2jgfgw gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSuSJ7chx1EoG/aouVgdAR4 wpwAgDAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAjx66fDdLk5ywFn3CzA1w1qfylHUD aEf0QZpXcJseddJGSfbUUOvbNR9N/QQ16K1lXl4VFyhmGXDT5Kdfcr0RvIIVrNxF h4lqHtRRCP6RBRstqbZ2zURgqakn/Xip0iaQL0IdfHBZr396FgknniRYFckKORPG yM3QKnd66gtMst8I5nkRQlAg/Jb+Gc3egIvuGKWboE1G89NTsN9LTDD3PLj0dUMr OIuqVjLB8pEC6yk9enrlrqjXQgkLEYhXzq7dLafv5Vkig6Gl0nuuqjqfp0Q1bi1o yVNAlXe6aUXw92CcghC9bNsKEO1+M52YY5+ofIXlS/SEQbvVYYBLZ5yeiglV6t3S M6H+vTG0aP9YHzLn/KVOHzGQfXDP7qM5tkf+7diZe7o2fw6O7IvN6fsQXEQQj8TJ UXJxv2/uJhcuy/tSDgXwHM8Uk34WNbRT7zGTGkQRX0gsbjAea/jYAoWv0ZvQRwpq Pe79D/i7Cep8qWnA+7AE/3B3S/3dEEYmc0lpe1366A/6GEgk3ktr9PEoQrLChs6I tu3wnNLB2euC8IKGLQFpGtOO/2/hiAKjyajaBP25w1jF0Wl8Bbqne3uZ2q1GyPFJ YRmT7/OXpmOH/FVLtwS+8ng1cAmpCujPwteJZNcDG0sF2n/sc0+SQf49fdyUK0ty +VUwFj9tmWxyR/M= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB 9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0 RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8 otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2 HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1 Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/ jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS u1igv3OefnWjSQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEVjCCAj6gAwIBAgIQPxMQ4JDWqro5xbc4i97cEzANBgkqhkiG9w0BAQsFADBP MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF bmNyeXB0MQswCQYDVQQDEwJFOTB2MBAGByqGSM49AgEGBSuBBAAiA2IABKBc3EWf O6zmAqlYSV0MFToiAnzppo1ZSJfbXGjprjBkydFbYBekcgrlJEmt5787R4P1grbP tgd3oUBlfoMzWHihpjXWkojvlceMmUYqvVbQc39pCD3RiYjDCr7WpuIqc6OB+DCB 9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFF130U2sTSJ4WbKGWY5DHLdk WRNBMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBXnLSlc0Gensx9lwlwHOuj6gafwSHI Ex4AhPjD6aMOCfuMP5iEn3Mb1QadTZafQ075SWQo1npjZyaH5M1N8cewGo2/2fjc z+2joCAeXBxTAbIiOIbaJwjgeUXQAFtpb7OffZdj7fmN5dAplWuau3ssY7vhmMfI zxMW7ILj0Uwj99AGtg6YQmo5UVFJbLu41sTpLXFP4eeI5L+cbsHxgMnXaHB7G1Wl Htlyp2iDlfzHdR28GBf05Ztex/S/kwFP3TUD5udUpaGZ/wAM8Vz0PnES0YN9Pwkg fz1kxBO37E1nmGtF8mBVzBvGAiVL2AfgDn6eaKuerWrbtXEBCp0JawPcJRYRRu3e lp1fqkvihMKBwXwA4xjM4BOvbGDPr9zkFN8NTwvL2sOuLDRlX6ZV6ILJ3uEMuJ17 8b+fUymtArsbbSsbcCW8yb95gy9corS6RLCND8GU5+ampNzgNx0+PP7QFP4/eqLC 68CJNOctb5eDwbGsmF1vrfltenYU375le6FZILjP8O69hD3BPrNIie8VlrqBSiDg M+ZF/E4uwcNxU62tYmKs9/WZyMJAR084fkEwXOw322x6OCwzyemZVq3kYKFg0y/m E9NYU8ijBkUBB3uW1AC4btGCOSo9cnEz9TlRO1HOo7DMZkuuz5K0Rcal0LGLL11d KsApwwSJLRbh7A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFBTCCAu2gAwIBAgIQS6hSk/eaL6JzBkuoBI110DANBgkqhkiG9w0BAQsFADBP MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa Fw0yNzAzMTIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF bmNyeXB0MQwwCgYDVQQDEwNSMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDPV+XmxFQS7bRH/sknWHZGUCiMHT6I3wWd1bUYKb3dtVq/+vbOo76vACFL YlpaPAEvxVgD9on/jhFD68G14BQHlo9vH9fnuoE5CXVlt8KvGFs3Jijno/QHK20a /6tYvJWuQP/py1fEtVt/eA0YYbwX51TGu0mRzW4Y0YCF7qZlNrx06rxQTOr8IfM4 FpOUurDTazgGzRYSespSdcitdrLCnF2YRVxvYXvGLe48E1KGAdlX5jgc3421H5KR mudKHMxFqHJV8LDmowfs/acbZp4/SItxhHFYyTr6717yW0QrPHTnj7JHwQdqzZq3 DZb3EoEmUVQK7GH29/Xi8orIlQ2NAgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgGG MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/ AgEAMB0GA1UdDgQWBBS7vMNHpeS8qcbDpHIMEI2iNeHI6DAfBgNVHSMEGDAWgBR5 tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKG Fmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0gBAwwCjAIBgZngQwBAgEwJwYD VR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0B AQsFAAOCAgEAkrHnQTfreZ2B5s3iJeE6IOmQRJWjgVzPw139vaBw1bGWKCIL0vIo zwzn1OZDjCQiHcFCktEJr59L9MhwTyAWsVrdAfYf+B9haxQnsHKNY67u4s5Lzzfd u6PUzeetUK29v+PsPmI2cJkxp+iN3epi4hKu9ZzUPSwMqtCceb7qPVxEbpYxY1p9 1n5PJKBLBX9eb9LU6l8zSxPWV7bK3lG4XaMJgnT9x3ies7msFtpKK5bDtotij/l0 GaKeA97pb5uwD9KgWvaFXMIEt8jVTjLEvwRdvCn294GPDF08U8lAkIv7tghluaQh 1QnlE4SEN4LOECj8dsIGJXpGUk3aU3KkJz9icKy+aUgA+2cP21uh6NcDIS3XyfaZ QjmDQ993ChII8SXWupQZVBiIpcWO4RqZk3lr7Bz5MUCwzDIA359e57SSq5CCkY0N 4B6Vulk7LktfwrdGNVI5BsC9qqxSwSKgRJeZ9wygIaehbHFHFhcBaMDKpiZlBHyz rsnnlFXCb5s8HKn5LsUgGvB24L7sGNZP2CX7dhHov+YhD+jozLW2p9W4959Bz2Ei RmqDtmiXLnzqTpXbI+suyCsohKRg6Un0RC47+cpiVwHiXZAW+cn8eiNIjqbVgXLx KPpdzvvtTnOPlC7SQZSYmdunr3Bf9b77AiC/ZidstK36dRILKz7OA54= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFBjCCAu6gAwIBAgIRAIp9PhPWLzDvI4a9KQdrNPgwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw WhcNMjcwMzEyMjM1OTU5WjAzMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDEMMAoGA1UEAxMDUjExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAuoe8XBsAOcvKCs3UZxD5ATylTqVhyybKUvsVAbe5KPUoHu0nsyQYOWcJ DAjs4DqwO3cOvfPlOVRBDE6uQdaZdN5R2+97/1i9qLcT9t4x1fJyyXJqC4N0lZxG AGQUmfOx2SLZzaiSqhwmej/+71gFewiVgdtxD4774zEJuwm+UE1fj5F2PVqdnoPy 6cRms+EGZkNIGIBloDcYmpuEMpexsr3E+BUAnSeI++JjF5ZsmydnS8TbKF5pwnnw SVzgJFDhxLyhBax7QG0AtMJBP6dYuC/FXJuluwme8f7rsIU5/agK70XEeOtlKsLP Xzze41xNG/cLJyuqC0J3U095ah2H2QIDAQABo4H4MIH1MA4GA1UdDwEB/wQEAwIB hjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHQ4EFgQUxc9GpOr0w8B6bJXELbBeki8m47kwHwYDVR0jBBgwFoAU ebRZ5nu25eQBc4AIiMgaWPbpm24wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzAC hhZodHRwOi8veDEuaS5sZW5jci5vcmcvMBMGA1UdIAQMMAowCAYGZ4EMAQIBMCcG A1UdHwQgMB4wHKAaoBiGFmh0dHA6Ly94MS5jLmxlbmNyLm9yZy8wDQYJKoZIhvcN AQELBQADggIBAE7iiV0KAxyQOND1H/lxXPjDj7I3iHpvsCUf7b632IYGjukJhM1y v4Hz/MrPU0jtvfZpQtSlET41yBOykh0FX+ou1Nj4ScOt9ZmWnO8m2OG0JAtIIE38 01S0qcYhyOE2G/93ZCkXufBL713qzXnQv5C/viOykNpKqUgxdKlEC+Hi9i2DcaR1 e9KUwQUZRhy5j/PEdEglKg3l9dtD4tuTm7kZtB8v32oOjzHTYw+7KdzdZiw/sBtn UfhBPORNuay4pJxmY/WrhSMdzFO2q3Gu3MUBcdo27goYKjL9CTF8j/Zz55yctUoV aneCWs/ajUX+HypkBTA+c8LGDLnWO2NKq0YD/pnARkAnYGPfUDoHR9gVSp/qRx+Z WghiDLZsMwhN1zjtSC0uBWiugF3vTNzYIEFfaPG7Ws3jDrAMMYebQ95JQ+HIBD/R PBuHRTBpqKlyDnkSHDHYPiNX3adPoPAcgdF3H2/W0rmoswMWgTlLn1Wu0mrks7/q pdWfS6PJ1jty80r2VKsM/Dj3YIDfbjXKdaFU5C+8bhfJGqU3taKauuz0wHVGT3eo 6FlWkWYtbt4pgdamlwVeZEW+LM7qZEJEsMNPrfC03APKmZsJgpWCDWOKZvkZcvjV uYkQ4omYCTX5ohy+knMjdOmdH9c7SpqEWBDC86fiNex+O0XOMEZSa8DA -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFBjCCAu6gAwIBAgIRAMISMktwqbSRcdxA9+KFJjwwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw WhcNMjcwMzEyMjM1OTU5WjAzMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDEMMAoGA1UEAxMDUjEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA2pgodK2+lP474B7i5Ut1qywSf+2nAzJ+Npfs6DGPpRONC5kuHs0BUT1M 5ShuCVUxqqUiXXL0LQfCTUA83wEjuXg39RplMjTmhnGdBO+ECFu9AhqZ66YBAJpz kG2Pogeg0JfT2kVhgTU9FPnEwF9q3AuWGrCf4yrqvSrWmMebcas7dA8827JgvlpL Thjp2ypzXIlhZZ7+7Tymy05v5J75AEaz/xlNKmOzjmbGGIVwx1Blbzt05UiDDwhY XS0jnV6j/ujbAKHS9OMZTfLuevYnnuXNnC2i8n+cF63vEzc50bTILEHWhsDp7CH4 WRt/uTp8n1wBnWIEwii9Cq08yhDsGwIDAQABo4H4MIH1MA4GA1UdDwEB/wQEAwIB hjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHQ4EFgQUALUp8i2ObzHom0yteD763OkM0dIwHwYDVR0jBBgwFoAU ebRZ5nu25eQBc4AIiMgaWPbpm24wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzAC hhZodHRwOi8veDEuaS5sZW5jci5vcmcvMBMGA1UdIAQMMAowCAYGZ4EMAQIBMCcG A1UdHwQgMB4wHKAaoBiGFmh0dHA6Ly94MS5jLmxlbmNyLm9yZy8wDQYJKoZIhvcN AQELBQADggIBAI910AnPanZIZTKS3rVEyIV29BWEjAK/duuz8eL5boSoVpHhkkv3 4eoAeEiPdZLj5EZ7G2ArIK+gzhTlRQ1q4FKGpPPaFBSpqV/xbUb5UlAXQOnkHn3m FVj+qYv87/WeY+Bm4sN3Ox8BhyaU7UAQ3LeZ7N1X01xxQe4wIAAE3JVLUCiHmZL+ qoCUtgYIFPgcg350QMUIWgxPXNGEncT921ne7nluI02V8pLUmClqXOsCwULw+PVO ZCB7qOMxxMBoCUeL2Ll4oMpOSr5pJCpLN3tRA2s6P1KLs9TSrVhOk+7LX28NMUlI usQ/nxLJID0RhAeFtPjyOCOscQBA53+NRjSCak7P4A5jX7ppmkcJECL+S0i3kXVU y5Me5BbrU8973jZNv/ax6+ZK6TM8jWmimL6of6OrX7ZU6E2WqazzsFrLG3o2kySb zlhSgJ81Cl4tv3SbYiYXnJExKQvzf83DYotox3f0fwv7xln1A2ZLplCb0O+l/AK0 YE0DS2FPxSAHi0iwMfW2nNHJrXcY3LLHD77gRgje4Eveubi2xxa+Nmk/hmhLdIET iVDFanoCrMVIpQ59XWHkzdFmoHXHBV7oibVjGSO7ULSQ7MJ1Nz51phuDJSgAIU7A 0zrLnOrAj/dfrlEWRhCvAgbuwLZX1A2sjNjXoPOHbsPiy+lO1KF8/XY7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFBTCCAu2gAwIBAgIQWgDyEtjUtIDzkkFX6imDBTANBgkqhkiG9w0BAQsFADBP MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa Fw0yNzAzMTIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF bmNyeXB0MQwwCgYDVQQDEwNSMTMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQClZ3CN0FaBZBUXYc25BtStGZCMJlA3mBZjklTb2cyEBZPs0+wIG6BgUUNI fSvHSJaetC3ancgnO1ehn6vw1g7UDjDKb5ux0daknTI+WE41b0VYaHEX/D7YXYKg L7JRbLAaXbhZzjVlyIuhrxA3/+OcXcJJFzT/jCuLjfC8cSyTDB0FxLrHzarJXnzR yQH3nAP2/Apd9Np75tt2QnDr9E0i2gB3b9bJXxf92nUupVcM9upctuBzpWjPoXTi dYJ+EJ/B9aLrAek4sQpEzNPCifVJNYIKNLMc6YjCR06CDgo28EdPivEpBHXazeGa XP9enZiVuppD0EqiFwUBBDDTMrOPAgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgGG MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/ AgEAMB0GA1UdDgQWBBTnq58PLDOgU9NeT3jIsoQOO9aSMzAfBgNVHSMEGDAWgBR5 tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKG Fmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0gBAwwCjAIBgZngQwBAgEwJwYD VR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0B AQsFAAOCAgEAUTdYUqEimzW7TbrOypLqCfL7VOwYf/Q79OH5cHLCZeggfQhDconl k7Kgh8b0vi+/XuWu7CN8n/UPeg1vo3G+taXirrytthQinAHGwc/UdbOygJa9zuBc VyqoH3CXTXDInT+8a+c3aEVMJ2St+pSn4ed+WkDp8ijsijvEyFwE47hulW0Ltzjg 9fOV5Pmrg/zxWbRuL+k0DBDHEJennCsAen7c35Pmx7jpmJ/HtgRhcnz0yjSBvyIw 6L1QIupkCv2SBODT/xDD3gfQQyKv6roV4G2EhfEyAsWpmojxjCUCGiyg97FvDtm/ NK2LSc9lybKxB73I2+P2G3CaWpvvpAiHCVu30jW8GCxKdfhsXtnIy2imskQqVZ2m 0Pmxobb28Tucr7xBK7CtwvPrb79os7u2XP3O5f9b/H66GNyRrglRXlrYjI1oGYL/ f4I1n/Sgusda6WvA6C190kxjU15Y12mHU4+BxyR9cx2hhGS9fAjMZKJss28qxvz6 Axu4CaDmRNZpK/pQrXF17yXCXkmEWgvSOEZy6Z9pcbLIVEGckV/iVeq0AOo2pkg9 p4QRIy0tK2diRENLSF2KysFwbY6B26BFeFs3v1sYVRhFW9nLkOrQVporCS0KyZmf wVD89qSTlnctLcZnIavjKsKUu1nA1iU0yYMdYepKR7lWbnwhdx3ewok= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFBjCCAu6gAwIBAgIRAL7zc3iocCqewKR6uSGlBqswDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw WhcNMjcwMzEyMjM1OTU5WjAzMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDEMMAoGA1UEAxMDUjE0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAzWhUbJkv1MTfFF7ihLylp5jaitXVng6yEeruE71/c0TLq/bZ438PLiPN r3I1qp66HaqOANbQ6ETg0SjuBbWng7VLHG4M1vQnx40EyXb4MnqeiwIucbyfEras GfTsS7E0ulC7uJ3G80OeAGQl76Rvq/qOYOR8n9VofZfbSKiQkHjUE4yP18YKub7E y8L0i7+WibZd7OYLtcGDxZwgr56r5iSYSVFl6c4ihop2I81g2BkBGPYLygDSktVW Vz1/cnjHH+u7ubt5hhlw/GwsOaJfIjrFhw3KafQJyvJxanpfCSSTShzR9whLTSKV lH2A1761dHaceWkBRqcV3HkuFIGIlQIDAQABo4H4MIH1MA4GA1UdDwEB/wQEAwIB hjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwEgYDVR0TAQH/BAgwBgEB /wIBADAdBgNVHQ4EFgQU5RCV2LYMUdencjVjClRobgZT+PswHwYDVR0jBBgwFoAU ebRZ5nu25eQBc4AIiMgaWPbpm24wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzAC hhZodHRwOi8veDEuaS5sZW5jci5vcmcvMBMGA1UdIAQMMAowCAYGZ4EMAQIBMCcG A1UdHwQgMB4wHKAaoBiGFmh0dHA6Ly94MS5jLmxlbmNyLm9yZy8wDQYJKoZIhvcN AQELBQADggIBACA3LtFXH8eQXLovPGzp7c2XE0/jmEp7tokiecuSdHfIUoMMYLjI TpCNbi92Czp+qraLmp0eLy6QEE5wnvMe5f9fgE24yk8EpsLw0JEr9L8tqWUXC1Kp jsT3ydhbWR70i4gElBvXnjGJc6HnU80veqABHEOU8TuAVwerBqH479ZLZSX+ezAf n9QcYiU9r8kVMbeSoSiQY39L6QK/3w4lmMZ9XoGM+9YhJldIbpBNgikoNgcOp3ya QxsfsE6ixjBZ/G6OSdi7KY41a/QdzeIiSy4dDV8R4pYF9FEhogpU/T/fD9tE7gEO 81vGLOyhUSlI2EzsJeH0lAt9NIN5CPtcooj9ZV3gkuYwhQMdhiBM/giI1CX+3JUh w6zKwXr3EjiY4Emw12U6ACaMSJxFxakt1zjmBn/DNgx0rP4WyeSJrewrQsYjW9Us bpO7GGrbADy72exibqrULU3Hp/PWHdXn+j3dKweU5ZL5li67ckqf1ixqQtoQuyjb F4+flbcU7AdHYnNHNUHMz5TWXYKWP6fFk9PSggS8DmYtYozN3npRSCHTC56Rxa81 ApdD9Ab0dF7fOvlnmniGxfqCRSh/RMGGEaTxdAfhp/m/yaR4xtm8VTAn8d65h/3D fKOGZ34UnvZmJ/bHqnU4zkLWc51iC1i9OIQWzoePK6qNPUq7k+oKUMSj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4jCCAsqgAwIBAgIRAKXNs7ZFMh9j9U+my0V4kbwwDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNDA2MjEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaMFIxCzAJBgNVBAYTAlVTMRgwFgYDVQQKDA9TU0wgQ29ycG9y YXRpb24xKTAnBgNVBAMMIFNTTC5jb20gRVYgVExTIElzc3VpbmcgRUNDIENBIFIx MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEM/pGFcs8jVjOroleCuLfLMeOz2TSKqWR BvJZ4oJ96u+/B5AA0TIL9WCiaBtSIBstmdcY5xFDnQ12GjcUfgyIHsPAwAtuz3H5 es9VTnm7TUBBAkTICUy2PMJvvLWcIkLYo4IBNjCCATIwHwYDVR0jBBgwFoAUoBEK Iz6W8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFJuJcI6nVx1hlSmdqanuV5Rb9upa MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjAyBgNVHSAEKzApMAcGBWeBDAEBMA4GDCsGAQQB gqkwAQMBBDAOBgwrBgEEAYKpMAEDAQYwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDov L2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYI KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5j b20wDQYJKoZIhvcNAQELBQADggEBAA+LXHuzWKyZDQbcXE+rcGA4C+39XIpxqLoD AiZoSj0od2JNmuOoQI2TAI9tqYTNYlYdoHhM7QbWpBrMQ+PabkoZL5HeGSk8tK52 xHu9YZytDLleqLd9snJ8hTdHwD96p5RJXu/JqxPxOhh5fDj2vP5SHbpoV/mjLGTW AXxdJIrO1QF9lMt6vnA2alTvh/x0iAShlYxlIQtX/fg4cNwbUySWP1NW8lcRuCKa 41UYBhUjhI0BQweV5q2dZxJpb9oDcntbzFYVFLkR8ttFll0cv4rkpOyb8r2358O4 StkXdeM0fSVkASS2EIqJMynizJqYq8kfmU9Kaa1kFtaaAeUtPu0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFEDCCA/igAwIBAgIRAK5qlGpMiN4PtQMiv0DZk9IwDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNDA2MjEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaMFIxCzAJBgNVBAYTAlVTMRgwFgYDVQQKDA9TU0wgQ29ycG9y YXRpb24xKTAnBgNVBAMMIFNTTC5jb20gRVYgVExTIElzc3VpbmcgUlNBIENBIFIx MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAmnX1X20hDNR3MyjSi48k cUysud1DwBCj6DvZnDgXHfd7AHYllKCNHw05rcudx64UobX5r+bv9txPT9AYoJpk qytioJGHq8BBQRIZJAYKLK0MOZ42WU72hj09UPsc0DtMrGIKGN4GOCBT8xNvULnx 7WkkdrCqJkAT8rbdRzWZHVMkopikFcH7vszZT3Rc+bwgiIpMoXO9rs+8rgfCZo+W 4rkzom+D9tFwjaZJcTGoRKYATg9rYxvZKr1d//nm1ds73/as8zhZBmPfAwK9L0af wTKrJ2AjdZEY2gD/1MNy9D28bk1FwtBhrPunM4dID4rSAlCWKyA4LDvrJ0uLK1mh gDNv/LSJcQRnTppc5gGX3d8ZWydrZH+2Yod+NPZ8G5lfAuvqctfozbfNo7f3a4oI pjbWR9oATC3CZ6UtEYTcpqJ6i5jgn4Hyb5N9RltzPPLmn7k6s10g/sGOIfgMaiFa 8i4SHaYt0MMbYLqqYuHGUsFiTH0Y2u7km37fMbD9MlcfAgMBAAGjggE2MIIBMjAf BgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQU13x58JsI sWuQbz0MORUe8rYfl5IwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDIGA1UdIAQrMCkwBwYF Z4EMAQEwDgYMKwYBBAGCqTABAwEEMA4GDCsGAQQBgqkwAQMBBjBDBgNVHR8EPDA6 MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9BQUFDZXJ0aWZpY2F0ZVNl cnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v Y3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAT93zZUez4Orbsos/ JdvhkOOBw8G68AR9X1KMNqSlEdw5hC0pMkr6EJXDrp0lq1dcgza+2zVNjy8G3LKe +j+zeNFTAY0WCsY5sawbIMlVDvboo3eSwFxjhwZ7C3soyYZRg6o6bpZFsyuhgN/4 VUEktIq4KIlkMhq45gijJlwRd0Y4f0B/jEf+Q9FwEN1YNgHlc5hatRpGdaJjX5vH e1ROI+/I0T2jDqnIKm1OHNJQ3t26uOVFgoT/TxhVo0t4yT3dz0GxP2komfA+33+3 btzKq74YQnBaEmjtiV++3rapRN2GTN2tAPrHM0BHPskolSwwzfs/VeIn/+vQoLbq niidWA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4TCCAsmgAwIBAgIQdeCi5PcGhffHR+OwfQy4pjANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI0MDYyMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowUjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh dGlvbjEpMCcGA1UEAwwgU1NMLmNvbSBFViBUTFMgVHJhbnNpdCBFQ0MgQ0EgUjIw djAQBgcqhkjOPQIBBgUrgQQAIgNiAARoZ0k39KG8pepJcSTmu2rzyo/qWlHOqs6F g0HV4Nk9gQzD/ZothSUrXdmB5U1d9ZhWm9p4YFpqQAZD2N3CB7TkY/YgRKBzACzu fL7Igvd13FFBf024ED7x62XdXURWlQKjggE2MIIBMjAfBgNVHSMEGDAWgBSgEQoj PpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUNzAeZC0ZaPP9brFyDe9s+wpATJAw DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0lBBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMDIGA1UdIAQrMCkwBwYFZ4EMAQEwDgYMKwYBBAGC qTABAwEEMA4GDCsGAQQBgqkwAQMBBjBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8v Y3JsLmNvbW9kb2NhLmNvbS9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0Bggr BgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNv bTANBgkqhkiG9w0BAQsFAAOCAQEAgCf00xq8APKgadawUmy0AmwnC3yfFNOfgqqc Uu2sFwv5Ib2OwoCH5XkYZMj+wFZmUdRTXpovHtyZ4L5C1c+ouC3TmKzZ6/2yOAea PxC/N6oe/fkISBFp8y/2UktB10iekBStkk1THmoBZqZWHArpbu+IsD8/13eBQSBu oPNUlgWTIH86Wfq8Ik0/t7luIy+0FZt9VqTGpqzy78FpNpwfH1m9IDHReVOE9+B/ Fb5zIzLwkn3ExgkNgNHpiMgsgU0QGntPPJuIYu6DrT4lg/A1EoCTIj46lHGtxeK/ c6MOzu4krYeNwIMxeTi51lAcarIvmPVGOUY2IG4rpTw6y1s66g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFjzCCBHegAwIBAgIQWCo1JB/IwtZeGvdM+e0L8TANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI0MDYyMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowUjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh dGlvbjEpMCcGA1UEAwwgU1NMLmNvbSBFViBUTFMgVHJhbnNpdCBSU0EgQ0EgUjIw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDhfU+kKz4OXLTlrJFsTk2y gohkGnwF/e5d73sCZo2ToDHAN2N6wctCCIjOGuQkJHtxtuljQOfMwmWG+BTyoy/v GH5N5hucCT3LzpM54pKsx2QcMy29f5luNW77US9Wd4XE5V7aBFXjF/nEuCdUrrA7 HYx+XAOs1pSbPgfNmSMLMZkyGsV3o1eyxQNsr/xCJfBJjaFkE8y+AJ2FifhTWjnl yeFn/0GDzya+aao6lWXucc7z4IxKdpuFWteq296i9MWCLamH4rq10IEPGFhHQN4B 2CwZYCuIdh2eMhJsMSWzOdIOBDanETAesDuR5MVQ1YxnkaXEunt5wr6eLbX6FJ0M QKxBuXpirRXCiYk9h0cX/9QJmVQr3vE/pdkA2bB0Dn2196yiKSUfMqrWJXT0MF/t wCf/WlVCY+kzWiST6KaFlSQadYWPaoowP0e0jOUIHQm9H7ZG9+IUTV93DbeEq6Xp kgcUMOlQwKOTFoW1jVZQbsbz4O04ehvzpWBOtM611krW8Sn8H5hZBWPPXho78/zX fvLSVVeymUHfbpCxchmuXZuDpytJm8jQRb0zZzaPTahWVsMDrW86yZA4yMormeuq ZsfdcGtrb2taigJcQA23XKj2kQ8LL00MiNDUnQeVi2vDpOhdpJZ0iiRjTjgPnuyJ L7k70xDgX5PyCffzOmJFtwIDAQABo4IBNjCCATIwHwYDVR0jBBgwFoAUoBEKIz6W 8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFG8NL6X6dfU68d/uYwvTLCfKA091MA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjAyBgNVHSAEKzApMAcGBWeBDAEBMA4GDCsGAQQBgqkw AQMBBDAOBgwrBgEEAYKpMAEDAQYwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2Ny bC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYB BQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20w DQYJKoZIhvcNAQELBQADggEBAFqqliERmsstMGUuOqLehV1dyqringyyRAGsz8nk X/KA5vecTQ1kiRM4NdxJHeFdkvoyB3hW+QnrXHP9uKPHtreOUMROfCEiyCieFpwU cCp5/f30ZCz+bf0BfQqR3AG9gfstfghqW6qGMAghjv/kKsdis6aXs6WWwfJX2VKG ly/J6VNMHnhu6Xi2D0t75yGOAgRZXKnKJPX8AdHvIyukKjwWqWHC6t3UxeE7+1gw 0n16IP3NcqJAMNF0OHY8TmFWZ2BqeZkis/q3X69vatmafaK5zePcYPBjUL5HB8rk GFLLBPw7z3yIZDn0YgPCSRuYwk/OXs8NvJHjNvrE0zRoFRc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID0jCCArqgAwIBAgIRAM5Qt7RdOf6f5NfHPsazUT4wDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNDA2MjEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaMFExCzAJBgNVBAYTAlVTMRgwFgYDVQQKDA9TU0wgQ29ycG9y YXRpb24xKDAmBgNVBAMMH1NTTC5jb20gSVYgVExTIElzc3VpbmcgRUNDIENBIDEw djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQxZ3TZKQJ5/orM2Y+/uP0rDgI7y2l9Lvtk F7jKnh0Pj4fbhgGalYwWwYq3DE86VDgNJaDNILt8uhJvra0TqRABR8B37Ku7W6wC VM3v10ViDJ57zsdbksOZhIP4QimBSe6jggEnMIIBIzAfBgNVHSMEGDAWgBSgEQoj PpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUJpEvtoqAvnFzEwoBt4x9d79bJhQw DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMCMGA1UdIAQcMBowCAYGZ4EMAQIDMA4GDCsGAQQB gqkwAQMBAzBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNv bS9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYI KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsF AAOCAQEAVae+QPlPd9+40OtrbTKuMrNoO9Q6+QJTUmKjYFhgRMMenZ853UBH7yUp vCBIsxHcsZYU7ZxmpCi6oWKIygqfx2Nu0g5Q9jVnehwJwlZOpIszPDzqqgTTouNs 6Cz6cm96Nkhy7zuZx+8QMGSSv8ADBgPSyLdtdpp99M/pflWzf/d4Jg++gWx7/ij7 rrab81IuNK6Tg1DC4GtIPrcfKqv09L61m45pQ1ExixY+1EjLB1h0LbCmODiFdFiu bFdxYRLvepKufIliRJkiqt7rw6mu2nPkp8ZOUgEmmSgZU5A49L+ebuvCBTCcM/pK HkNEQXDKYCouTwVAZA38N5Vnmd4iBg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFADCCA+igAwIBAgIRAPr6WIYeTsXvlnMIFqoWMf0wDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNDA2MjEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaMFExCzAJBgNVBAYTAlVTMRgwFgYDVQQKDA9TU0wgQ29ycG9y YXRpb24xKDAmBgNVBAMMH1NTTC5jb20gSVYgVExTIElzc3VpbmcgUlNBIENBIDEw ggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCdKCtakRaln+iha5zvcbzZ sVHEHAoBUuGcAK8ZwEmZtKUw2p6tEHQUBtm30KTSpgCdzQn0g0QRXQj3l3ykDK2f 9GfuuyVbTbcd1teEEtUFrqMzRU8kiDVhPY7GWLGAtt0eXrJd24UvHlEsfa5IlOUE PHXYhT2PEHIg81gXWbxnrGetUThh52uwmWKlbUW30Grwz2UjYUm2JGS7UOrmyRml 66/GO3cW3UeuyAEWrszBUlNFdVKFNXdJ1V5sNYKqz2dWrjxPOq3WZdpnQhuEXJI8 CuhnK0kppO1LovdRQkm1/xg28zQNmmOosEjrJzkuqoM+mr7koTcBInJD5rsy79ub 0hKqyMIJbFoapijhuTN8hUGRBR0PfZ642oOlMnVz61c5JSkDRi/Mj5Y6F5ZsI7iu uLfu6mb/rDSkYMvkPSbcMpfv8cZS9+egnbZfiaKt9yEWMblkxWYc9jepIhkWvlQq HH/OrAOZUnnkDZI9MhvUoWfbB4mS31a5obGcOm/GmpUCAwEAAaOCAScwggEjMB8G A1UdIwQYMBaAFKARCiM+lvEH7OKvKe+CpX/QMKS0MB0GA1UdDgQWBBSufRb79DIn 8JVWhSSGFFi0XdGaFzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIB ADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIwYDVR0gBBwwGjAIBgZn gQwBAgMwDgYMKwYBBAGCqTABAwEDMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9j cmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsG AQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29t MA0GCSqGSIb3DQEBCwUAA4IBAQCQEqFRWOhmUjYXj9awUjQkejDpPQcUCFo6Wrvz 4J8OgOtYTedIxxFkV1CgVpYrqN3QkkVSzWU6WwX+d+y2Js4nxkGHhZWwc1/poUqr ZJ83cF2qNRDUF/fODq6ASsr1ry24QKzDwx62VgMQopKCowPTGQo2n/C1DuSMKWKM x+I/kEyWZGUhqJPe2fqp6ixubaDwZbZYs28K3UDaUTZAyzp9kKb+KAnKJmLWmQGH fGZY1wtv6LRE4mKt/kXoIMoRrvfTH10Dg1FX7vcAlCneSq/xdY8v4sfbHjFLCBpT X1WwydtixLvK/yIJP25G7YyttzDjCpIvGXGE/aqet808B5Tj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID0TCCArmgAwIBAgIQCkQaR7Uo2NfBKeMRNU046zANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI0MDYyMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowUTELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh dGlvbjEoMCYGA1UEAwwfU1NMLmNvbSBJViBUTFMgVHJhbnNpdCBFQ0MgQ0EgMTB2 MBAGByqGSM49AgEGBSuBBAAiA2IABLFhlniSt1UT1EMVninNreIHv2yFBrxdCK4L BPRpxOYkp1ujy0iEKvpk93QuhQAOwQIEAJ2+so8NFhluiqlWy2Y1rJpPNGmqdzbs 4So8q30xOAavHUHeRSwo8vA8Rp3xuqOCAScwggEjMB8GA1UdIwQYMBaAFKARCiM+ lvEH7OKvKe+CpX/QMKS0MB0GA1UdDgQWBBSzOfOcAkLY0j3ZwdXqQWWTvNgKCzAO BgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwIwYDVR0gBBwwGjAIBgZngQwBAgMwDgYMKwYBBAGC qTABAwEDMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29t L0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggr BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUA A4IBAQCPmXl4BgAjwMtY89V5mTL37dyVN9bSIfvmCkio8ki9I1jZamG/I+HvKlyM RRWy8vDREM/ZzrO5AEpO+uHBW6ArTLtpQnMBHXsdc/VbECHROFItqTI6Ny0kaciV st9+VjyObGkxYhGZR4RERRu4dos5H5dAQcyLavABlOp5OQ+MzJ6SebY0Ww90tffp 9ZVLnSvNVntjhxK3KXNbOC7ELsXiN5Ju5PuVXiS5d4iCc5befmZKtnRUMhTncWVG nANQFtw6Z8ZKQIF/cBwLWYqm1HNZLq0oE4FOIwIAiOoe9x+GWvcb0g/ZyqikM82f tDixVW5Y3qZVDDp4Z66gI/q03muH -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFfzCCBGegAwIBAgIQenz30vS2/AcnvyWN2uu6yDANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI0MDYyMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowUTELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh dGlvbjEoMCYGA1UEAwwfU1NMLmNvbSBJViBUTFMgVHJhbnNpdCBSU0EgQ0EgMTCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM3Ew9BDEqfJWTBEJnlrpS0k 3JYd4pKpYDrv1XjpIO0aG0ag/BZUDQAjpAd5RsqqcBIWCf9+09fOFg+5uDhOJlDH vXVnqPBMQ8zF/+QDlBU5GQ3U465adlTtnE4ZAgd4YeNK0b3koEm5sfsUsa6RaCzE msVGBtwewlk9Zlv/T3KMg3qGtmLqMem1flIhbfIV2sXavVi+HozQtZq3x3eZ9N0b rjKxVMMKrSnDP4RaqI9J/Y8+JCYp5dXML671yV94YgkAbhhodSxk/t5rlzDqiQB/ EBFYNSVLXYskbPsdzt4bvhT6qiN0nH3z4w0xmQ10EWymWw9iEBRdjit9aRR91YAL pEzRsvtDZVioqX37nxGKuPRQrGU3aQpLjrWQBL116ElPflWy3PRZc8Pb/RHiS16B XBhAJ8LIYndu2ZUh8k6cRHk1idhQrVO++kXh9j9HW51/g8e7TWNatzg+UCZ4AA9G jM+dodIrZ+7ZikKfVyAnFrNd6ha2WNtYtEwn8nJyyTwH6AQpSNANzBXJl8k94nBS avvy0+GslEL0P82VH2adyebxEPsZYNMqBUclMPToZyRnwVhcKbU6Tq6P/Qn/HY6A TFadi/ZUaHsgYBdjOLzZF4k7eX16L8Nysj0o5uufjBQ8eouaJPwK0RId+e3pT3l3 +56NkPG3mN6ahd60mbc7AgMBAAGjggEnMIIBIzAfBgNVHSMEGDAWgBSgEQojPpbx B+zirynvgqV/0DCktDAdBgNVHQ4EFgQUrtsRjGGL8M5FA87qmt0f7NeLmH8wDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMCMGA1UdIAQcMBowCAYGZ4EMAQIDMA4GDCsGAQQBgqkw AQMBAzBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9B QUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYB BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOC AQEASrFcB1n6PP4V5mH1sBvsP8QV5iuH6EomhPCVcaVQbEEWJSlNZrF8dh7qGqAQ cagWoH0tNpnU/9g4YbzpjdI9GyDjS9/SHmn8NygnCgtT9Bp2yeRJ24sLqjPVggaI VIepCkVWrXBqGqq9WartbVLL3qMmO4QT8buvVdbFnTdp93EnVQciSXh3+bBmm83X +nif1MlpevOHTxWkKgq8/alK1Ihp0tna8D7IaifbBg9P+mIeMcIByWTKVHoLfYET +YKX1t6w031I/jFj/4eX6V1V3w/UxjPdKLhmTpxbGxUP0ovB/7mEkTUjSzkfoupm XbMvTXAhS5fZrwyP9ki5v4FZOg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4TCCAsmgAwIBAgIQP0O2nX9rP+O1A05zifFePjANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI0MDYyMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowUTELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh dGlvbjEoMCYGA1UEAwwfU1NMLmNvbSBPViBUTFMgSXNzdWluZyBFQ0MgQ0EgMTB2 MBAGByqGSM49AgEGBSuBBAAiA2IABANxF9T40/FfOUt6rB28nAoStiQL6ceFMTS5 UfdsS0Zd67V0R5mUC2SG1gijEeuxg7fu064cRRywqf0zmzehyNl7iuEfn/2kmy3/ mLLGmrv8vgD51NZd8qU343eapnFOuqOCATcwggEzMB8GA1UdIwQYMBaAFKARCiM+ lvEH7OKvKe+CpX/QMKS0MB0GA1UdDgQWBBTVr76GWmRW63QEVM5oWhWLAB5quTAO BgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwMwYDVR0gBCwwKjAIBgZngQwBAgIwDgYMKwYBBAGC qTABAwECMA4GDCsGAQQBgqkwAQMBBTBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8v Y3JsLmNvbW9kb2NhLmNvbS9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0Bggr BgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNv bTANBgkqhkiG9w0BAQsFAAOCAQEAVb5T7FT+0BjHgTELK0+VxRKtt3q7E/gtZxRc ipPbyt0/Nt0daKX4I262nNWtWqK1xazIVJfOzPjID4Ht3prfuWMiXUs6izbItG39 jZk008yrHUqzwJVhzQZrGkcLGFUREH+7/b/vSz2AL8ME/Mk93o6xP4diuRC53BhB M9BSBdN/tv3BhZke9qOZl/GWfqO9b4XPdd5GHOs7FAdxkkZA0rXw1R7B8Xwnneed B4p0u01cYmFe7QQmc/lvf+SdtQxwlevA4iDZ4vduVtLQcqrqJ4XCoGn1wIlECmv3 3GU95pKvZhUJZlRWDc7iN+rpipMBGfgDhZ+Uwv7UOFXWrptLhw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFDzCCA/egAwIBAgIQNmN4kk0lL3cFlCFGSz3axDANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI0MDYyMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowUTELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh dGlvbjEoMCYGA1UEAwwfU1NMLmNvbSBPViBUTFMgSXNzdWluZyBSU0EgQ0EgMTCC AaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAMlOeGZZVJUlUuNGU/lKqpxS qrPgskDpW1WwmOqiGYSuAPZOxSdLDmA4mDCwrvilegbiHygCUVGgo2fmf7j4VMmY /TFufPoQA0zuddvHct/bdil0lG+KoqBT5Oh+DrzqYp/RHlfZ/OAyQD6bJCkFZ+FH FMiOc4VROppyjkr5aR1+rmoUUvfumkGL2UmX0MFCD+lHOw48wnsPO36CLH+doomA 2TzL9LDN6Jys0sIcBPA65yM16ofgBohJHhXJrtAvYbUvxz+lZhQvtb1zicj/Iulo sLr1d8yiQlzvm/r85PlILq4Jj0X7h8UzTKE/uk5H0UZXaFRM+xsHW+N6qZHl2JPY NOsZIulzIGKvxsXvuzd5wnowwTUf4Y+DL2xQVevj2JBR7Xck1ajAvcMA/ULB86HS poHsIwvfCl8lBwCFZfnm2DmAhtwb3uvCJque/dzPLcfL84Db1wyA/HwbQLoHB9gP NYylslCoy9IE+Y3BUlSD1YkYRbzeVMavLDJEmNBw+QIDAQABo4IBNzCCATMwHwYD VR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFEWiFIXTFUqZ cPkCRtzNGOroJgI6MA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEA MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAzBgNVHSAELDAqMAgGBmeB DAECAjAOBgwrBgEEAYKpMAEDAQIwDgYMKwYBBAGCqTABAwEFMEMGA1UdHwQ8MDow OKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmljYXRlU2Vy dmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29j c3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBd0nv8ziYaAjwwleKt YhxtegIKDsAgfhwyFFAJnrFiqR+yuuwVFapLVz7aTrOefz9DUdwQ4f9Hmemy38ft 9k0SQKoJRp173bnPPUTMQv7v0SKcvoZTvlbQMoeaw5xgExi0D8e1uUYqAtf/jpWB LHN1nZh/JDyYmRkQJ7RqWiy8CwIEioKoAUKS04ta9/NhJUZVlCeen1lSx9OogInB TK6Ga32y8yrwNP+dUdK0LH/ALA444ZI3JJNlhpM1yRUS2r9B6AXdcNu38tOpegUN ewBdi/V2I1bIQBwiQ9Vg6V7K7PoItbUN/Q/oKUtyk6Wx2RXr516KRAK6SU4XqYwv f8wk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4jCCAsqgAwIBAgIRAITWGBJ/92drg0qg8GC3e0owDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNDA2MjEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaMFExCzAJBgNVBAYTAlVTMRgwFgYDVQQKDA9TU0wgQ29ycG9y YXRpb24xKDAmBgNVBAMMH1NTTC5jb20gT1YgVExTIFRyYW5zaXQgRUNDIENBIDEw djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQgX3EMKj4exPnwYlTTzrzvvKIARs7H5ZfS kUr8rsrKGjjJlJH3LorYwcv3grNUjIUN0Rg0EaGO0zu6dRSGPs+8VrmHwIyIAZKm r7lLPyMQ4uaeC17bCvvYoezVF2Ct6xCjggE3MIIBMzAfBgNVHSMEGDAWgBSgEQoj PpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUseDZv51LfKEvymlDVihWT2mcF20w DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0lBBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMDMGA1UdIAQsMCowCAYGZ4EMAQICMA4GDCsGAQQB gqkwAQMBAjAOBgwrBgEEAYKpMAEDAQUwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDov L2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYI KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5j b20wDQYJKoZIhvcNAQELBQADggEBAAQ8UEAptET6LwOKj6txjkPgBS7diGYbMsPD jYKrvRIsF7S3k3KTyTHxIBU/NUuDfB9nMeiPLgY23rxWSdodarpVb5QLITnn2GHa kYdoH6MPyFa2btooajYu4ER6T2fPnL7Vw9CZiq1XEG4ML+uZM6rlQBhY2nE3/P/d DG0ppmewG/uLweD2Pn7TgtQxkJLYTpEdQzbttx784PhZp09BUwQLUpQLaH65waPr a4tUiw3pBUIGyPIDZOg/Rx5IoUfW/mJ7358CslcOBLIfm/pivCvHD24Tcu+yMoBf rn+YO74zTxVdiQbD0bN6GG+aUl4N2pptulQ4ZSi739GVk6kOl/A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkDCCBHigAwIBAgIRAJB+gsmzjFpFvICEw35Q9Q8wDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNDA2MjEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaMFExCzAJBgNVBAYTAlVTMRgwFgYDVQQKDA9TU0wgQ29ycG9y YXRpb24xKDAmBgNVBAMMH1NTTC5jb20gT1YgVExTIFRyYW5zaXQgUlNBIENBIDEw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCBUbLecMYFpK+0dc/Kbwp1 iJN3zb+0Qkx7deHQxpE9jEAUOJmx1ICJN8WbrbOtHRtFuSuoIEgOmhcgmhf86572 Q2QUMO3k5DugOSM9Zu5c5K7ksnPiq+V1C826CZwVh/htpzF8mlIHRQZ6EBIx1uYD HNkhZXUhaL3ZdPPPNlP965qm9VUWeClrOWrIZOEEdQics6UVpDN16czcHaN1DhXW LcukXEIGjR8LawohmU792m/yN8nPTGzcnYvfXIEeCuoUpzavktnbY9TqFMijJqyM V4BY/Zm/g/SYhz4Y9UWfDJYM0/rBBoM9q5AV1Hzl32nUlPPo8SvZo0gDAMLUZQ/8 rYzi70Gvd7MrQ83D1Ro8nd7jmTDrhBCt90tshw7bve6y05UaD3V4C1s3DM3szd08 M3JZyyCauqs6PX7VCv/gXF42QihxXXeuDTdJjWTzrJK9EqUGbIYpcJuMr/dykUUo SQ/FeZoIwOISc5TcBeH/vEPXCNv30N2a4dhZT6jKY98SgK2TVO3xPFFSktCq23gD LzlBT6Dg/o31gsIawByBgGXT858moqMyYJ8Sn2sGvfOcSiQVfQ6XzHX4kh7WeOCo 5YQS+w7sQjmngtnyvGmtVYsJTDDczxGwrw3cKJO9DvoS5w1IamvgBUH9Ms31ofES ZA48QaIv5wbVGrIjtHLBzwIDAQABo4IBNzCCATMwHwYDVR0jBBgwFoAUoBEKIz6W 8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFOSr63Uz3YRbSO7NZm6xUxnrCIuWMA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjAzBgNVHSAELDAqMAgGBmeBDAECAjAOBgwrBgEEAYKp MAEDAQIwDgYMKwYBBAGCqTABAwEFMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9j cmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsG AQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29t MA0GCSqGSIb3DQEBCwUAA4IBAQCUXpsgr/wbjgSySnnEJ5rZ2RJy8MEpbRj53EGj zvCvyT7oeNKOX5QsVYn7pS4koqvvHyF65GMBBBDCA/RUxxVm2vrdmYCdy3mjs20F H3RC+BkKZtm069nmwqAu2JZcJTdrVNtEGRDT4tku6CehyOZw/vdgI7j+WVBXOR/M qgGhyf6YzGOnFNaTrgAUWlVAR2A606WUFh0ozFXpHnjf62S1BLvjDAUfSmtWPIby iYUPLM+/70Rje5INRSjMgNoOghq8OIp7AsNLjqtZsXR8UIHjJByPKLZl0Ntrhftt W8H9zR7Xe5jsw5T1QyaCX6d6qNsPcEckH6qKQDqqbFXJvoq2 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDzzCCAregAwIBAgIQc4MRQp9zCJcSzUr9bRb63TANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI0MDYyMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowTzELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh dGlvbjEmMCQGA1UEAwwdU1NMLmNvbSBUTFMgSXNzdWluZyBFQ0MgQ0EgUjIwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAATW47D5Jj9R0bn6C9WsOHGBS8DYaqCkMWxUiekw mabE+rDw7gGw4vRhyj/MFuC+qO4fj3zn6CKTaynRLe7hFUfc2/Fnql2gPOO2na5q RxcAt45CH4r36BYtDsEuaKMMMbWjggEnMIIBIzAfBgNVHSMEGDAWgBSgEQojPpbx B+zirynvgqV/0DCktDAdBgNVHQ4EFgQUTrlSWrGPftYwU0Plyl2iBIxMFPQwDgYD VR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYB BQUHAwEGCCsGAQUFBwMCMCMGA1UdIAQcMBowCAYGZ4EMAQIBMA4GDCsGAQQBgqkw AQMBATBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9B QUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYB BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOC AQEAVpdsOkUivRCeDLnK10taQR321En5G/H3wYrmMqLP8ESiUHKQC6m2I+X69Ndo JUSYfz90J0Ow/ZvFLTZrvoAu6qMRd1WHqjOuVXaqsVx+nfDviDr7e25t9scMRqaQ 1dkFuNiLPVOEM3idQGLY8s12NnmsvD6AjI28KlOCoLGcEM1DEt6Hu5PfRgziJWQK HWXtStDSCYl5zxTl7Th49D56T6do39mPOxhsQqVqWX5eZQ4uhuqFd2GQBxhCGe0u IS38bYHVspzrz3RKuNK6dlCSBP+UXzZj8Fp08o3l0KPe4k2H5K7e00cyMPXEHeP0 Z2cFax+utXCEfhHER20vx6DwKA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE/jCCA+agAwIBAgIRAMT4RcgnYpHswrPdHceMh00wDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNDA2MjEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaME8xCzAJBgNVBAYTAlVTMRgwFgYDVQQKDA9TU0wgQ29ycG9y YXRpb24xJjAkBgNVBAMMHVNTTC5jb20gVExTIElzc3VpbmcgUlNBIENBIFIxMIIB ojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEArBsCFEDaO9kp5LVy+Q61qs0c eyTudkfMpnOW86WVgjxn1Ol3GVEEJeGnAJacW6Me3/DElI3p/oAiH+RozfSaV1xq zXYaFLr5xwzP3DjUiV8ez41QLh14JZLR+WV6VcNfYY0X1BtmvgmbjhICpycy/9DR ibURLan6zcuisqA89B/2vVYnQG+ACJh4mTi7kWggWT5/vVII/U1kxUxH3b3F9KK/ LxZxmhcNZbeqU655LLUB/WqmAcfneAg41ZDWiE2qCS2xvByaNZZmUvkWdlWWUxp9 vFoOQ3TcqZVscwVTHL/s4btRCiJakhrrx516K9ohURYwctW1XYu7EflaLuD1GsPx EB+Ly0WBxzNq1L/2eah3Iw8Xxfglx63oxEtD2mGgPxCybn0nDfyMYpGiDkVrgSFK 69+KXC4/mxU5cq+QlhhWyRSXlrM+QkBcUdySWtZpM3xx2YhNSWYKI82i2Mysc7R9 iG4rz5zJjJVIS7biFu4dSTRjXgQ/W+6RnfiFz84bAgMBAAGjggEnMIIBIzAfBgNV HSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUebqUd6ANGd00 5jmk/Eyl0lpt9YwwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCMGA1UdIAQcMBowCAYGZ4EM AQIBMA4GDCsGAQQBgqkwAQMBATBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3Js LmNvbW9kb2NhLmNvbS9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEF BQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAN BgkqhkiG9w0BAQsFAAOCAQEAFTEjMQzlG8JU3bIPbc+vWUtusUzRXSoVmY7Y4Ybx phiK7+coZgU0MOHYdSjmSGp16wly0l0L3acKwBanu5WqUnaeXyPqkgUOOD6w0JHc FBcLXCCqPD7hnhYAjQuaU8t50OCEkCEYK4R5nh75paChmYPFci0XJRCFQHOK7xCo boWSRjszDM/0/YYu/GV0fMAPxbMvKbr7WrCgGHsCl96mhPoRvUH8+cP4wLkoN81V mv+BjERE6JwxadQFa9pxLacnCBNA7KfGteVkI2xN1MbiuATZujRQ7MxEBv+aZ7Sb LZwAQqijFKgzcvRBeETD8JmmeKO7Ksf/XkPOvOA99wK5dQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID0DCCArigAwIBAgIRAK2NLfZGgaDTZEfqqU+ic8EwDQYJKoZIhvcNAQELBQAw ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNDA2MjEwMDAwMDBaFw0y ODEyMzEyMzU5NTlaME8xCzAJBgNVBAYTAlVTMRgwFgYDVQQKDA9TU0wgQ29ycG9y YXRpb24xJjAkBgNVBAMMHVNTTC5jb20gVExTIFRyYW5zaXQgRUNDIENBIFIyMHYw EAYHKoZIzj0CAQYFK4EEACIDYgAEZOd9mQNTXJEe6vjYI62hvyziY4nvKGj27dfw 7Ktorncr5HaXG1Dr21koLW+4NrmrjZfKTCKe7onZAj/9enM6kI0rzC86N4PaDbQt RRtzcgllX3ghPeeLZj9H/Qkp1hQPo4IBJzCCASMwHwYDVR0jBBgwFoAUoBEKIz6W 8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFDKix9hYi/9/wDzyVWkz7M7MH7yXMA4G A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjAjBgNVHSAEHDAaMAgGBmeBDAECATAOBgwrBgEEAYKp MAEDAQEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsG AQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQAD ggEBAB4oL4ChKaKGZVZK8uAXjj8wvFdm45uvhU/t14QeH5bwETeKiQQXBga4/Nyz zvpfuoEycantX+tHl/muwpmuHT0Z6IKYoICaMxOIktcTF4qHvxQW2WItHjOglrTj qlXJXVL+3HCO60TEloSX8eUGsqfLQkc//z3Lb4gz117+fkDbnPt8+2REq3SCvaAG hlh/lWWfHqTAiHed/qqzBSYqqvfjNlhIfXnPnhfAv/PpOUO1PmxCEAEYrg+VoS+O +EBd1zkT0V7CfrPpj30cAMs2h+k4pPMwcLuB3Ku4TncBTRyt5K0gbJ3pQ0Rk9Hmu wOz5QAZ+2n1q4TlApJzBfwFrCDg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFfTCCBGWgAwIBAgIQUl2fDZZ6EH1gqmdbOsHpyDANBgkqhkiG9w0BAQsFADB7 MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI0MDYyMTAwMDAwMFoXDTI4 MTIzMTIzNTk1OVowTzELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh dGlvbjEmMCQGA1UEAwwdU1NMLmNvbSBUTFMgVHJhbnNpdCBSU0EgQ0EgUjIwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC6lZ8Z2WYAqAXZr43sbFCdaz+5 MU8liFkrqzD5CcOL8AOaKtB1Ggx5t8GjUibUAYvuCNXeUzd4awBM4ARRoWp8xzRI +AG9YxUH5lWtsmyhfyW4E7VvpRpi5s3tOyQVv8rCpdNB0R/HYM4+wPxigadbL2Cc 46fTcbeV2MBPOc9lyVJASewIXQQhI0+CsKOVA4AD3Cj27QhnpvJONchn+hVgvTTD VSkmlrvaFjH3KPzEJsRIiv6Wyc1bpkDyV6+bPzkzXtntXhdXb/RrAcky7ldxN5I0 xZd2ESfMUU6yQbqkIfAaBj1Uxd7y780ir5beWijPQU1VsU4NcEpxwQ8CkcFK7Gos XIAOS1XhFbbO7QpfF6Nxe8QGAcC5Dx38f5vubR3PMheivltQSxlGJOhMlidqxehx baxH47wRQoT2p/3MXHBDydUetOwJLlRxct6ms9px9qD8ubnUX4TmUc88tfWzFM8t WrKNrhQjo/GB/585rBv+MZ+8JwjySCjY0Tiy4WcwBo3sacCyXXWGoJH2hoq2QbVH W0QpQLSQ2wXClnyo6juVXRW++ZwtCu2MOx5xnadnqD2u/2fH+EAHsCplAtICVR8j /GeFQGWbdPSXTUrSy0OKm9BiQjJ9GCw4eUZa8zYbOKnsFH+2NtZN4pYLP3M7wS8I WceGUEkSP5Izm+qWZwIDAQABo4IBJzCCASMwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs 4q8p74Klf9AwpLQwHQYDVR0OBBYEFCFBNGOOHZEMw922JLCoh3uNZWAIMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdJQQWMBQGCCsGAQUF BwMBBggrBgEFBQcDAjAjBgNVHSAEHDAaMAgGBmeBDAECATAOBgwrBgEEAYKpMAED AQEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFB Q2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUF BzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEB ACZcAf5T5xGRWOoV+HvXXdj8P61F5OxDxY/lC/6feUgFY8qUO9yPipfxlDOgelM0 YgFkHK4GLCuIKgfP+QpREuKMkJP6k4tylKAEdr+DdFgwHJEWwbPFg/sZHYWzUPEN c1ypStXWHXOXlk/fbIylocSSbqN9oRM50+YKeLFy6+1jK12QJVJKMiLYKxiRvhCa WyqLhFsVGeNNgbOdrkjRBNTYSv8s2qJA2xZSYF1bkeo3bK94qx/FTbwCOigSsK6y eLeb585rLBNiO5MhPTY85Cbb8aZfkUryrqJoy993BoyKp9YDiM8QA3Mome64gxVZ FNKy3ieVQFNDMoHK9DZgfLk= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/inter-L1-expired.pem ================================================ -----BEGIN CERTIFICATE----- MIIEizCCA/agAwIBAgIISfg49he9h+AwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDA0MTEyMjU2MzdaFw0xNDA0MTEyMzAx MzdaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0 APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT 7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7 STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GDMIGAMA4GA1UdDwEB/wQEAwIApDAS BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAaBgNVHREEEzARgg9j ZnNzbC1pbnRlci5jb20wCwYJKoZIhvcNAQELA4GBAJg3FejhZNUWht3AFoFz9Pmn 2B4+Rhcz3Vy2AkGTI6tNR3TkaDIejyBkeEtf4pmR480tq3xFZkCZ6BZY2f7mvRto DWo3AdXcLeYDtbDmNGJFL6mAlyG1A87n7EgUnP8hEjtiYP8dyCGJD0JOKZAy/kMq XFzYgAa1t27VSc/XkiG7 -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/inter-L1-sha1.pem ================================================ -----BEGIN CERTIFICATE----- MIIEhDCCA++gAwIBAgIIQsTa4VjjFPswCwYJKoZIhvcNAQEFMH0xCzAJBgNVBAYT AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG A1UEAwwNQ0ZTU0xfVEVTVF9DQTAgFw0xNDA5MjMxODQ5NThaGA8yMTE0MDkyNDE4 NTQ1OFowgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYD VQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv MRMwEQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVy LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOUKdX6+PSxU/LxK ocsCUj7HCc+FaDOPZV68Po3PVm7UF5DmbnLgJYJ/4aZEZM/v5r8LnXQXDqumYicH Q2DHHBDasLTx8m0KeKOUYf9WMQ8gdjmVFoCiZwzxGDHok66/0Glkkqmv2nJQxXnc l5ZFta4sfmcQx3KT02l61LaBbG3j8PbRCWEr+0eRE6twuYRR13AgZ3ATwnMjzxzv sW67qmAy0cq+XgYYfTK9vhPs+8J0fxXa0Iftu3yuhd30xLIVXLu45GR+i6KnsSxV ERSaVxjkS+lHXjUpdtmqI5CK6wn67vqYRRA2TzAJHX8Jb+KL2/UEo5WNfAJ8S0he ODQA8nHVU1JIfpegOlQRMv55DgnQUv1c1uwO5hqvv7MPQ3X/m9Kjccs1FBH1/SVu zKyxYEQ34LErX3HI+6avbVnRtTR/UHkfnZVIXSrcjUm73BGj33hrtiKl0ZyZnaUK GZPuvebOUFNiXemhTbqrfi/zAb1Tsm/h+xkn5EZ5sMj5NHdAbpih3TqX2gRhnFZc FjtJM6zzC5O7eG5Kdqf8iladXTXtWxzrUPkb5CupzFl1dyS3dqdkoIXvkmlScnu+ 6jBOaYeVvwogxr2Y69y4Zfg/qbPyBOLZquX9ovbuSP1DQmC//LV5t7YHHY/1MXr5 U0MMvcn+9JWUV6ou3at4AgEqfK0vAgMBAAGjezB5MA4GA1UdDwEB/wQEAwIApDAT BgNVHSUEDDAKBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQW BBSIYLoYpHe4QQQb1e93UcJbFLogPzAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+ VbNnOg2SPjALBgkqhkiG9w0BAQUDgYEAXSegwl0vRG7N9FBO+9u1Neh9oeQNm5Ld U5FK1qs4BhI/F4MRW4hxN8D25B6tPMtKR93Rkeg/wGz3DPwAhvjVFCOQlzFfW0S9 dEduUgl2j8ICcgLawFDp7eYsUJfcBwffGOS/RAtUG59Q52tt8FNXU9QtaKaSn/Vq mrb08gYFNzg= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/inter-L1.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIFGzCCAwUCAQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJl LWludGVyLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOUKdX6+ PSxU/LxKocsCUj7HCc+FaDOPZV68Po3PVm7UF5DmbnLgJYJ/4aZEZM/v5r8LnXQX DqumYicHQ2DHHBDasLTx8m0KeKOUYf9WMQ8gdjmVFoCiZwzxGDHok66/0Glkkqmv 2nJQxXncl5ZFta4sfmcQx3KT02l61LaBbG3j8PbRCWEr+0eRE6twuYRR13AgZ3AT wnMjzxzvsW67qmAy0cq+XgYYfTK9vhPs+8J0fxXa0Iftu3yuhd30xLIVXLu45GR+ i6KnsSxVERSaVxjkS+lHXjUpdtmqI5CK6wn67vqYRRA2TzAJHX8Jb+KL2/UEo5WN fAJ8S0heODQA8nHVU1JIfpegOlQRMv55DgnQUv1c1uwO5hqvv7MPQ3X/m9Kjccs1 FBH1/SVuzKyxYEQ34LErX3HI+6avbVnRtTR/UHkfnZVIXSrcjUm73BGj33hrtiKl 0ZyZnaUKGZPuvebOUFNiXemhTbqrfi/zAb1Tsm/h+xkn5EZ5sMj5NHdAbpih3TqX 2gRhnFZcFjtJM6zzC5O7eG5Kdqf8iladXTXtWxzrUPkb5CupzFl1dyS3dqdkoIXv kmlScnu+6jBOaYeVvwogxr2Y69y4Zfg/qbPyBOLZquX9ovbuSP1DQmC//LV5t7YH HY/1MXr5U0MMvcn+9JWUV6ou3at4AgEqfK0vAgMBAAGgSzBJBgkqhkiG9w0BCQ4x PDA6MDgGA1UdEQQxMC+CFGNsb3VkZmxhcmUtaW50ZXIuY29tghd3d3djbG91ZGZs YXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQ0DggIBAHtSt/v+IHQmSK5UiQWwjRWA ZezIWVlJuselW8DEPNHzDtnraVhjPSFP995Cqh9fc89kx2Bt9hDhjNteTB+pJW6B aCRRZygJ6/m3Ii1XqTFgfEJBWwuIX1Req0PCW/ayegdLzzYbSZ31wRICCveBQyGw vRtzIBUeMvz9MgLJ8zx7eN7fDhrvy+Y1SkC4g0sAQTYYfM9P/He4k5hx79hmd2YC mUDAlNZV0g0dY0qR4cITmhniIFW5iZBplY7DmqooUXrj5yEga2QMj/RA16lPzHbz 7ceUlcH2L6/V6zMR/rfCiGRoWInxWSuuJhLIVLmoEo0590w6KVEZifHxsRpl4l09 imvzwTSQGIrY8jF9AxOD0rRA9wXCT9h8XtBWyJZ1/DmzJG8+7oZ/HdE9XhzwNujD Q6lBOj+dznju7k/snYCZVq501JLPeql8vQrq0O/xSqSK4yN1IG4NisZeDK2BZEOy QhnKXodIKf+zXnFw86lZ/ZwHQFr6jOSxmbrZ2OiY34m7Yd9oeIaMPviysRih2x4Q O6DFz72f97+xFZuXIbmn8DPQV8U9bk/gbrfUCPnx/icS8UoPsBKc9Gio0FZO4+8A 4/ac3oeN0zy/WjsBP+J50CRUXMrRI9KO+/bI4pcT14B31YbuSo6ygIkIkj7YDh36 +4ZG6HnUPQI8HteF9hzp -----END CERTIFICATE REQUEST----- ================================================ FILE: bundler/testdata/inter-L1.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIIJKAIBAAKCAgEA5Qp1fr49LFT8vEqhywJSPscJz4VoM49lXrw+jc9WbtQXkOZu cuAlgn/hpkRkz+/mvwuddBcOq6ZiJwdDYMccENqwtPHybQp4o5Rh/1YxDyB2OZUW gKJnDPEYMeiTrr/QaWSSqa/aclDFedyXlkW1rix+ZxDHcpPTaXrUtoFsbePw9tEJ YSv7R5ETq3C5hFHXcCBncBPCcyPPHO+xbruqYDLRyr5eBhh9Mr2+E+z7wnR/FdrQ h+27fK6F3fTEshVcu7jkZH6LoqexLFURFJpXGORL6UdeNSl22aojkIrrCfru+phF EDZPMAkdfwlv4ovb9QSjlY18AnxLSF44NADycdVTUkh+l6A6VBEy/nkOCdBS/VzW 7A7mGq+/sw9Ddf+b0qNxyzUUEfX9JW7MrLFgRDfgsStfccj7pq9tWdG1NH9QeR+d lUhdKtyNSbvcEaPfeGu2IqXRnJmdpQoZk+695s5QU2Jd6aFNuqt+L/MBvVOyb+H7 GSfkRnmwyPk0d0BumKHdOpfaBGGcVlwWO0kzrPMLk7t4bkp2p/yKVp1dNe1bHOtQ +RvkK6nMWXV3JLd2p2Sghe+SaVJye77qME5ph5W/CiDGvZjr3Lhl+D+ps/IE4tmq 5f2i9u5I/UNCYL/8tXm3tgcdj/UxevlTQwy9yf70lZRXqi7dq3gCASp8rS8CAwEA AQKCAgBPyl/6Qm3vNsBBHELXBTz/r7lEOTZ+19K5uRyVrIhw3aRED3KkxF9s4f4L PUJdija5kWNN4QZ0V+dTr10SpuqpGHZ84tjQkdhLLFMjb7Rxj56AGucW8vyxboA+ SsbAFwSU4ruRL7kLIAZbmLSaXjiXr9ptL1Q8HzGESo0180qB0enNIi+BUaAdY3YV wJRwe05xOmiui8Ou9uedLgeDCw+kqa+aUM1SlE9xUNaZ/HIMYScwxuTkpbYuDmKG W1H2tCh1IUk3lTox9Pds+UmVAtuayVWEtB8mqAZGd9Yh8bNF68w7MrbEmhbmJhbH fdMjehOrfO08GWj9OK3FTUWJIFdVFdjE6M5F/9kKjZhTH6Q6N0GU2M65v+R5CRWW 3vJu7Nhfek4gRa9zWVjHNQbpBoDDnB0MC5s7MQ6HnVQ3u4dZMDYo/XQrc/uIeaT+ cuN8IW1u9nEGdNT0+xmV40oRgXGMcWH9kkzctSHyt7d+BiWZLL2PFGV/RprNUklp 1kFl2p7piof4mgueiU/iJvosl9E1eVdWQgrrz33NMuO+Ox+PHgIyWHC6A9FDdscd 9FQ3AFmGIVNgRzJi3V0/v5ESqkdJ/QpmHwS0uoP7zdK4/zeCz6Nav/QdmkEOV6Si GLn7k0xxdRUNW5dHjLXacmy279fB3rM8PxkAUbLh4VKHVlGNyQKCAQEA54YN0wRv AI/lY/Z6wpolMpA7Gt2305yfFP+9oTORWxR8MKtO/aCmuxqF9qX/PMRa1HeXxCCM O9zD3BqChNS3kwKSVlt79KiY4Q6HflTTeG55kXsmRxxljoi46zgcuwJPPlexciO4 nMoaac3/pQXnuwu65iLyg0/8Nw609C9xXyjQM1szeow9dL46/i2g5kh43Qu560Um Mjcv9TOV4G+efatOv0sQGUgHHoKQVw2kVvImYRkiXHg/aaRqGSk3zlvoVTQVN+hJ rn0Sh+AlBY7NiG0r/wT7p+PGASq/vG3JX+cJ0V6KXaI0s9f7NLNkWMx6cITO77Je pbKmIYaoadeASwKCAQEA/UE19ErMQyX1o2pScaWZ4JpKY2R4i13VvPbhL0ztDJdv iPhO/HaaWTyn29Tve7KpRlbr5PMWy3Szk4NnL6Tn/PCywHRPniW/UzgScm5fYhBe x5KJZS8q9ImgJNiwM8yow31CJNr+l/d3pcKl3SoeBv/lUqAI0M1AhsyBkpcRm76W jVOD+BYCV8E3q2hx/3aWOcJdPAsS9rb3qBBsuMgdl2NI+pidGr9+Xpwc+Xmk7KwI 9bKhS3ecVs0ujmNlpzKcNbIWbmpnJFEMwEPoLFdb+i4eZqzlDLAaag07wEL6akEl OJ421YHqFZe3oJLNjV+6BzswOweA5qiH3TAoRR1gLQKCAQEAnvnMuk38Do3APLC9 wKxpyFuDSkJefJ66GYg15N/s+naJhD3NQpiyhB2FSUTYixhlKiloe9LBmEVR8+v8 HUuXNgn5A/VTmz69oyP/475JaxOoxD2kngWgsoutNk7UY5EFatB6Vt6yYG7iTi6W UPFKGoTGdEog7gvZKtEdbeK53VbAB9Oi+I4dkPEivvAD4Lx4yYfIxQU5YhfFBYDD dFYQpUghDXd0eXec89VBWZVTeCRUOC4zCv3CxT6RX++Ok1NGqGLYAwist3TIaaZ+ pV9WQEx+fmEkkDb1+k0pVTCpqwGRG0PojLzZpXgz1Q8tY1Ac7vAyzCJVnT+blb/K GstQGwKCAQA14kIQkDmVr+XrtxuDgrCS0UEylJXxUS3A3uZaogttumrIwcxMew+s HPO6Gjw6HXFWvffC5tXaxCHRKQwzXurdLnlZ6WVnSLDEjBGgt0skGkeQPuVs2fRR w1aHgHM9EjZ2IZiJLu8sdkLGyftwax2ob5njUpmNk54/EBQhlHLyqEJwH2zcxBIL idjGZ5qZuCmOcIRV2iVWyOc4owX+6tUg+Mb2SrJilovUpXKkwfUNRi1B2Zfn7rMc 5NsbAJsIUARciF+tboYze+synUAw7wVq3ZUqU28InA+CsP4dkiKlqOa6fS89jj64 CWfQimuhwNRb5YQFizsp2IHP1gc7bVyhAoIBADuUUe4J/SH6GqweX6IcuAmOgcio o5kMr6EM5g8Ly3P1FgeshlK4Jyt+ufKD6yr91Td7TBIa8xnPHlnU3Rji0O4F/jyn DMIcdFVQkbXtWum/NrprWiDAaWKl1JtmKs+l8fpeL/V8pbjlFx5A7H5qjlTswfq+ vsbrNUkA1DB4yyq8DJzgkVT3LpD14dvROSI2mAJRd8aaGEBmvNX/pJF2cjevmwnz HB1AU2Pex0yCBi17FYe+72SG9XHR3u4CZ1gT+X62v0TsuKa6WMneVkMraB3M2ltO f2WuVcay35mPGAnKjvSuj4j3NvgeELmSo97CC5A/bc2d4pDjmb1pkYbrOiQ= -----END RSA PRIVATE KEY----- ================================================ FILE: bundler/testdata/inter-L1.pem ================================================ -----BEGIN CERTIFICATE----- MIIEfzCCA+igAwIBAgIUEvxiFE387bDlHt8NSYEYLPYpJwIwDQYJKoZIhvcNAQEF BQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxhcmUxFDASBgNVBAsMC0RF Vl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NBMCAXDTE2MDIxODA1MjUw MFoYDzIxMTYwMTI1MDUyNTAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNs b3VkZmxhcmUtaW50ZXIuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC AgEA5Qp1fr49LFT8vEqhywJSPscJz4VoM49lXrw+jc9WbtQXkOZucuAlgn/hpkRk z+/mvwuddBcOq6ZiJwdDYMccENqwtPHybQp4o5Rh/1YxDyB2OZUWgKJnDPEYMeiT rr/QaWSSqa/aclDFedyXlkW1rix+ZxDHcpPTaXrUtoFsbePw9tEJYSv7R5ETq3C5 hFHXcCBncBPCcyPPHO+xbruqYDLRyr5eBhh9Mr2+E+z7wnR/FdrQh+27fK6F3fTE shVcu7jkZH6LoqexLFURFJpXGORL6UdeNSl22aojkIrrCfru+phFEDZPMAkdfwlv 4ovb9QSjlY18AnxLSF44NADycdVTUkh+l6A6VBEy/nkOCdBS/VzW7A7mGq+/sw9D df+b0qNxyzUUEfX9JW7MrLFgRDfgsStfccj7pq9tWdG1NH9QeR+dlUhdKtyNSbvc EaPfeGu2IqXRnJmdpQoZk+695s5QU2Jd6aFNuqt+L/MBvVOyb+H7GSfkRnmwyPk0 d0BumKHdOpfaBGGcVlwWO0kzrPMLk7t4bkp2p/yKVp1dNe1bHOtQ+RvkK6nMWXV3 JLd2p2Sghe+SaVJye77qME5ph5W/CiDGvZjr3Lhl+D+ps/IE4tmq5f2i9u5I/UNC YL/8tXm3tgcdj/UxevlTQwy9yf70lZRXqi7dq3gCASp8rS8CAwEAAaNmMGQwDgYD VR0PAQH/BAQDAgIEMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFIhguhik d7hBBBvV73dRwlsUuiA/MB8GA1UdIwQYMBaAFLhe765nULfW8wflar5Vs2c6DZI+ MA0GCSqGSIb3DQEBBQUAA4GBAGIW4csKSyGxYuYUQKtPDVjsy+/bD4cLVm78rO/r Qo5IjkaYvN/R6Y0OWgOLPHaxWfC8TRyyrW8cBZBbUcEhFIm9JCGRU5qctqWGdBo4 X1M9WCQXr7RS0WVEnn+h83Giot5hdOktSNqCO1QuZBxlLUqZEhnA1XnZEEDG/YWi 9JCk -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/inter-L2-direct.pem ================================================ -----BEGIN CERTIFICATE----- MIICzzCCAjigAwIBAgIUfJGxbzjhmIdNEUxPBZWFlCGJ8XAwDQYJKoZIhvcNAQEF BQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxhcmUxFDASBgNVBAsMC0RF Vl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NBMB4XDTE5MDUwMTAwMDAw MFoXDTI4MDYxNTA4MDAwMFowgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxp Zm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZs YXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91 ZGZsYXJlLWludGVyLmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABCFZIzSRsH9x dF1iR+8kElbcbqAYnYuSTbEOxYcREHGRJd2/v9YhetEwWNmIuisCbgOpyBO9zyFx snzYU4cOA/AomW2nJEP7n4M9g8r8clhQz8y6+013jP9MEqf4pqMVnqNmMGQwDgYD VR0PAQH/BAQDAgKkMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFD3f3FiG mOjKKSDupXSse/XS6RdXMB8GA1UdIwQYMBaAFLhe765nULfW8wflar5Vs2c6DZI+ MA0GCSqGSIb3DQEBBQUAA4GBACqG60D598ioNRvJSQNW+bPeUXu6BwrjYGzlL3bT a6meHLlYyd3v8sZMUecv1n1QEBbDkyEn10NMB4N1o03jJfkh1FD3RM88hVKO1ZTp X0y5CZ2dYzbgwtd6xvOtPxBdzZaix7WuM4DzZSKzaWBq+clk2aeAsvkrRkeMfqLF 2YKA -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/inter-L2.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIB0jCCAVcCAQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJl LWludGVyLmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABCFZIzSRsH9xdF1iR+8k ElbcbqAYnYuSTbEOxYcREHGRJd2/v9YhetEwWNmIuisCbgOpyBO9zyFxsnzYU4cO A/AomW2nJEP7n4M9g8r8clhQz8y6+013jP9MEqf4pqMVnqBLMEkGCSqGSIb3DQEJ DjE8MDowOAYDVR0RBDEwL4IUY2xvdWRmbGFyZS1pbnRlci5jb22CF3d3d2Nsb3Vk ZmxhcmUtaW50ZXIuY29tMAoGCCqGSM49BAMDA2kAMGYCMQD6kSGGc3/DeFAWrPUX qSlnTTm57DpzUoHQE306DfbFB6DFfoORNM5Z98chnZ+Ell4CMQCzYhOvIh3+GPGF MuYYIAfQV2JG+n7pjfpJ+X1Ee2bOtA4ZO39P9/FTEtJUXt+Ivqw= -----END CERTIFICATE REQUEST----- ================================================ FILE: bundler/testdata/inter-L2.key ================================================ -----BEGIN EC PRIVATE KEY----- MIGkAgEBBDAVVKPnV+KoCmQRq1zGg6n5PjjBFZdVPcKi9fNe78ZqMAMfLSfycPcS e6HJVt8ylCegBwYFK4EEACKhZANiAAQhWSM0kbB/cXRdYkfvJBJW3G6gGJ2Lkk2x DsWHERBxkSXdv7/WIXrRMFjZiLorAm4DqcgTvc8hcbJ82FOHDgPwKJltpyRD+5+D PYPK/HJYUM/MuvtNd4z/TBKn+KajFZ4= -----END EC PRIVATE KEY----- ================================================ FILE: bundler/testdata/inter-L2.pem ================================================ -----BEGIN CERTIFICATE----- MIIEYDCCAkigAwIBAgIUGkS6ZR3pGG1whBdM98/+hASRNpEwDQYJKoZIhvcNAQEN BQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQL ExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMw EQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNv bTAeFw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGMMQswCQYDVQQGEwJV UzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmlu ZzEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wdjAQBgcqhkjOPQIBBgUr gQQAIgNiAAQhWSM0kbB/cXRdYkfvJBJW3G6gGJ2Lkk2xDsWHERBxkSXdv7/WIXrR MFjZiLorAm4DqcgTvc8hcbJ82FOHDgPwKJltpyRD+5+DPYPK/HJYUM/MuvtNd4z/ TBKn+KajFZ6jZjBkMA4GA1UdDwEB/wQEAwICpDASBgNVHRMBAf8ECDAGAQH/AgEB MB0GA1UdDgQWBBQ939xYhpjoyikg7qV0rHv10ukXVzAfBgNVHSMEGDAWgBSIYLoY pHe4QQQb1e93UcJbFLogPzANBgkqhkiG9w0BAQ0FAAOCAgEAr3FzjsRoTUo5WocP xpUaeS5PPIY5uBmMZQU+JQuCzBTGwAONkzwEZUMHW9SNrD9g7qcWouy+1t4Sz6dJ iKa+6vvo60bJvINELLnbu5Z+t99f7R3PAdcIccQVxPIFxKKq6HYhgDx+jOvCTuGA TXIL9vkYL8rR/9YmMJBp6Re4+sWq97kzRJt7zIU4+pL/3Inx8KUuXlh8K/aa4ShY yRIeAYixnGjDQ8YMVLFyjVeg0wiv+qAkgomi81hts7DUhawzMRC81A6oIwvWNBfB 2CUijERzpBjxmMZwaUOj6yKhGbigt7lxvcSkzJZTJ4s+HE05k9OYnJ8+PF+mo3uS nG2dg/NqIipdh8/9fvHubW3QL7cwbaI7T0lVYkopNkL8TP7gOZjkeNCTvhHun4+7 apjbFeylj8kkTaL6+6Y+7JLGmsD8amuy45Qu/NKqIZyYF/vxBSqi3w2Rm8IwYvQ7 ci2jN+RJvPQVy2hioXyOUzoyBED7GhZjV59i7N62clQ8+g3gxjxF5/lYU6Ok3UEg a6JLchBWgq0y/M4cGtidJCGWdLZAldQtnRb7qj0yt64byy+SECZHHlKroGARu0qv osbE6riZvhmUlnrBDS02LGwG0dni21iERJu56I8ltHaJsZUIu4jOEUBENQwIAULo ZPYOEUU9GGgoGpUdqNtpfZZWmvw= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/intermediates.crt ================================================ -----BEGIN CERTIFICATE----- MIIEfzCCA+igAwIBAgIUEvxiFE387bDlHt8NSYEYLPYpJwIwDQYJKoZIhvcNAQEF BQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxhcmUxFDASBgNVBAsMC0RF Vl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NBMCAXDTE2MDIxODA1MjUw MFoYDzIxMTYwMTI1MDUyNTAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNs b3VkZmxhcmUtaW50ZXIuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC AgEA5Qp1fr49LFT8vEqhywJSPscJz4VoM49lXrw+jc9WbtQXkOZucuAlgn/hpkRk z+/mvwuddBcOq6ZiJwdDYMccENqwtPHybQp4o5Rh/1YxDyB2OZUWgKJnDPEYMeiT rr/QaWSSqa/aclDFedyXlkW1rix+ZxDHcpPTaXrUtoFsbePw9tEJYSv7R5ETq3C5 hFHXcCBncBPCcyPPHO+xbruqYDLRyr5eBhh9Mr2+E+z7wnR/FdrQh+27fK6F3fTE shVcu7jkZH6LoqexLFURFJpXGORL6UdeNSl22aojkIrrCfru+phFEDZPMAkdfwlv 4ovb9QSjlY18AnxLSF44NADycdVTUkh+l6A6VBEy/nkOCdBS/VzW7A7mGq+/sw9D df+b0qNxyzUUEfX9JW7MrLFgRDfgsStfccj7pq9tWdG1NH9QeR+dlUhdKtyNSbvc EaPfeGu2IqXRnJmdpQoZk+695s5QU2Jd6aFNuqt+L/MBvVOyb+H7GSfkRnmwyPk0 d0BumKHdOpfaBGGcVlwWO0kzrPMLk7t4bkp2p/yKVp1dNe1bHOtQ+RvkK6nMWXV3 JLd2p2Sghe+SaVJye77qME5ph5W/CiDGvZjr3Lhl+D+ps/IE4tmq5f2i9u5I/UNC YL/8tXm3tgcdj/UxevlTQwy9yf70lZRXqi7dq3gCASp8rS8CAwEAAaNmMGQwDgYD VR0PAQH/BAQDAgIEMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFIhguhik d7hBBBvV73dRwlsUuiA/MB8GA1UdIwQYMBaAFLhe765nULfW8wflar5Vs2c6DZI+ MA0GCSqGSIb3DQEBBQUAA4GBAGIW4csKSyGxYuYUQKtPDVjsy+/bD4cLVm78rO/r Qo5IjkaYvN/R6Y0OWgOLPHaxWfC8TRyyrW8cBZBbUcEhFIm9JCGRU5qctqWGdBo4 X1M9WCQXr7RS0WVEnn+h83Giot5hdOktSNqCO1QuZBxlLUqZEhnA1XnZEEDG/YWi 9JCk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYDCCAkigAwIBAgIUGkS6ZR3pGG1whBdM98/+hASRNpEwDQYJKoZIhvcNAQEN BQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQL ExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMw EQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNv bTAeFw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGMMQswCQYDVQQGEwJV UzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmlu ZzEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wdjAQBgcqhkjOPQIBBgUr gQQAIgNiAAQhWSM0kbB/cXRdYkfvJBJW3G6gGJ2Lkk2xDsWHERBxkSXdv7/WIXrR MFjZiLorAm4DqcgTvc8hcbJ82FOHDgPwKJltpyRD+5+DPYPK/HJYUM/MuvtNd4z/ TBKn+KajFZ6jZjBkMA4GA1UdDwEB/wQEAwICpDASBgNVHRMBAf8ECDAGAQH/AgEB MB0GA1UdDgQWBBQ939xYhpjoyikg7qV0rHv10ukXVzAfBgNVHSMEGDAWgBSIYLoY pHe4QQQb1e93UcJbFLogPzANBgkqhkiG9w0BAQ0FAAOCAgEAr3FzjsRoTUo5WocP xpUaeS5PPIY5uBmMZQU+JQuCzBTGwAONkzwEZUMHW9SNrD9g7qcWouy+1t4Sz6dJ iKa+6vvo60bJvINELLnbu5Z+t99f7R3PAdcIccQVxPIFxKKq6HYhgDx+jOvCTuGA TXIL9vkYL8rR/9YmMJBp6Re4+sWq97kzRJt7zIU4+pL/3Inx8KUuXlh8K/aa4ShY yRIeAYixnGjDQ8YMVLFyjVeg0wiv+qAkgomi81hts7DUhawzMRC81A6oIwvWNBfB 2CUijERzpBjxmMZwaUOj6yKhGbigt7lxvcSkzJZTJ4s+HE05k9OYnJ8+PF+mo3uS nG2dg/NqIipdh8/9fvHubW3QL7cwbaI7T0lVYkopNkL8TP7gOZjkeNCTvhHun4+7 apjbFeylj8kkTaL6+6Y+7JLGmsD8amuy45Qu/NKqIZyYF/vxBSqi3w2Rm8IwYvQ7 ci2jN+RJvPQVy2hioXyOUzoyBED7GhZjV59i7N62clQ8+g3gxjxF5/lYU6Ok3UEg a6JLchBWgq0y/M4cGtidJCGWdLZAldQtnRb7qj0yt64byy+SECZHHlKroGARu0qv osbE6riZvhmUlnrBDS02LGwG0dni21iERJu56I8ltHaJsZUIu4jOEUBENQwIAULo ZPYOEUU9GGgoGpUdqNtpfZZWmvw= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/nss.pem ================================================ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # Issuer: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc. # Subject: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc. # Label: "GTE CyberTrust Global Root" # Serial: 421 # MD5 Fingerprint: ca:3d:d3:68:f1:03:5c:d0:32:fa:b8:2b:59:e8:5a:db # SHA1 Fingerprint: 97:81:79:50:d8:1c:96:70:cc:34:d8:09:cf:79:44:31:36:7e:f4:74 # SHA256 Fingerprint: a5:31:25:18:8d:21:10:aa:96:4b:02:c7:b7:c6:da:32:03:17:08:94:e5:fb:71:ff:fb:66:67:d5:e6:81:0a:36 -----BEGIN CERTIFICATE----- MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ -----END CERTIFICATE----- # Issuer: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division # Subject: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division # Label: "Thawte Server CA" # Serial: 1 # MD5 Fingerprint: c5:70:c4:a2:ed:53:78:0c:c8:10:53:81:64:cb:d0:1d # SHA1 Fingerprint: 23:e5:94:94:51:95:f2:41:48:03:b4:d5:64:d2:a3:a3:f5:d8:8b:8c # SHA256 Fingerprint: b4:41:0b:73:e2:e6:ea:ca:47:fb:c4:2f:8f:a4:01:8a:f4:38:1d:c5:4c:fa:a8:44:50:46:1e:ed:09:45:4d:e9 -----BEGIN CERTIFICATE----- MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3 dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3 DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91 yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG 7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ qdq5snUb9kLy78fyGPmJvKP/iiMucEc= -----END CERTIFICATE----- # Issuer: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division # Subject: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division # Label: "Thawte Premium Server CA" # Serial: 1 # MD5 Fingerprint: 06:9f:69:79:16:66:90:02:1b:8c:8c:a2:c3:07:6f:3a # SHA1 Fingerprint: 62:7f:8d:78:27:65:63:99:d2:7d:7f:90:44:c9:fe:b3:f3:3e:fa:9a # SHA256 Fingerprint: ab:70:36:36:5c:71:54:aa:29:c2:c2:9f:5d:41:91:16:3b:16:2a:22:25:01:13:57:d5:6d:07:ff:a7:bc:1f:72 -----BEGIN CERTIFICATE----- MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG 9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== -----END CERTIFICATE----- # Issuer: O=Equifax OU=Equifax Secure Certificate Authority # Subject: O=Equifax OU=Equifax Secure Certificate Authority # Label: "Equifax Secure CA" # Serial: 903804111 # MD5 Fingerprint: 67:cb:9d:c0:13:24:8a:82:9b:b2:17:1e:d1:1b:ec:d4 # SHA1 Fingerprint: d2:32:09:ad:23:d3:14:23:21:74:e4:0d:7f:9d:62:13:97:86:63:3a # SHA256 Fingerprint: 08:29:7a:40:47:db:a2:36:80:c7:31:db:6e:31:76:53:ca:78:48:e1:be:bd:3a:0b:01:79:a7:07:f9:2c:f1:78 -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 -----END CERTIFICATE----- # Issuer: O=Digital Signature Trust Co. OU=DSTCA E1 # Subject: O=Digital Signature Trust Co. OU=DSTCA E1 # Label: "Digital Signature Trust Co. Global CA 1" # Serial: 913315222 # MD5 Fingerprint: 25:7a:ba:83:2e:b6:a2:0b:da:fe:f5:02:0f:08:d7:ad # SHA1 Fingerprint: 81:96:8b:3a:ef:1c:dc:70:f5:fa:32:69:c2:92:a3:63:5b:d1:23:d3 # SHA256 Fingerprint: 63:04:19:ae:c4:78:cb:b4:bb:80:83:de:9d:9c:f2:79:75:2f:03:9d:ef:16:e4:64:71:b6:79:ca:93:00:2d:b0 -----BEGIN CERTIFICATE----- MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5 fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i +DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+ gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl -----END CERTIFICATE----- # Issuer: O=Digital Signature Trust Co. OU=DSTCA E2 # Subject: O=Digital Signature Trust Co. OU=DSTCA E2 # Label: "Digital Signature Trust Co. Global CA 3" # Serial: 913232846 # MD5 Fingerprint: 93:c2:8e:11:7b:d4:f3:03:19:bd:28:75:13:4a:45:4a # SHA1 Fingerprint: ab:48:f3:33:db:04:ab:b9:c0:72:da:5b:0c:c1:d0:57:f0:36:9b:46 # SHA256 Fingerprint: 8f:62:d7:73:6f:99:db:d3:3e:e0:0e:10:c7:e3:29:33:9c:98:8a:5b:47:ef:25:f4:08:29:3c:f2:42:6b:4d:44 -----BEGIN CERTIFICATE----- MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/ k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3 MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5 WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID -----END CERTIFICATE----- # Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority # Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority # Label: "Verisign Class 3 Public Primary Certification Authority" # Serial: 149843929435818692848040365716851702463 # MD5 Fingerprint: 10:fc:63:5d:f6:26:3e:0d:f3:25:be:5f:79:cd:67:67 # SHA1 Fingerprint: 74:2c:31:92:e6:07:e4:24:eb:45:49:54:2b:e1:bb:c5:3e:61:74:e2 # SHA256 Fingerprint: e7:68:56:34:ef:ac:f6:9a:ce:93:9a:6b:25:5b:7b:4f:ab:ef:42:93:5b:50:a2:65:ac:b5:cb:60:27:e4:4e:70 -----BEGIN CERTIFICATE----- MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k -----END CERTIFICATE----- # Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network # Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network # Label: "Verisign Class 3 Public Primary Certification Authority - G2" # Serial: 167285380242319648451154478808036881606 # MD5 Fingerprint: a2:33:9b:4c:74:78:73:d4:6c:e7:c1:f3:8d:cb:5c:e9 # SHA1 Fingerprint: 85:37:1c:a6:e5:50:14:3d:ce:28:03:47:1b:de:3a:09:e8:f8:77:0f # SHA256 Fingerprint: 83:ce:3c:12:29:68:8a:59:3d:48:5f:81:97:3c:0f:91:95:43:1e:da:37:cc:5e:36:43:0e:79:c7:a8:88:63:8b -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY oJ2daZH9 -----END CERTIFICATE----- # Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA # Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA # Label: "GlobalSign Root CA" # Serial: 4835703278459707669005204 # MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a # SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c # SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- # Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 # Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 # Label: "GlobalSign Root CA - R2" # Serial: 4835703278459682885658125 # MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30 # SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe # SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG 3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO 291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- # Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority # Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority # Label: "ValiCert Class 1 VA" # Serial: 1 # MD5 Fingerprint: 65:58:ab:15:ad:57:6c:1e:a8:a7:b5:69:ac:bf:ff:eb # SHA1 Fingerprint: e5:df:74:3c:b6:01:c4:9b:98:43:dc:ab:8c:e8:6a:81:10:9f:e4:8e # SHA256 Fingerprint: f4:c1:49:55:1a:30:13:a3:5b:c7:bf:fe:17:a7:f3:44:9b:c1:ab:5b:5a:0a:e7:4b:06:c2:3b:90:00:4c:01:04 -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+ TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0 LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI -----END CERTIFICATE----- # Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority # Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority # Label: "ValiCert Class 2 VA" # Serial: 1 # MD5 Fingerprint: a9:23:75:9b:ba:49:36:6e:31:c2:db:f2:e7:66:ba:87 # SHA1 Fingerprint: 31:7a:2a:d0:7f:2b:33:5e:f5:a1:c3:4e:4b:57:e8:b7:d8:f1:fc:a6 # SHA256 Fingerprint: 58:d0:17:27:9c:d4:dc:63:ab:dd:b1:96:a6:c9:90:6c:30:c4:e0:87:83:ea:e8:c1:60:99:54:d6:93:55:59:6b -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd -----END CERTIFICATE----- # Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority # Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority # Label: "RSA Root Certificate 1" # Serial: 1 # MD5 Fingerprint: a2:6f:53:b7:ee:40:db:4a:68:e7:fa:18:d9:10:4b:72 # SHA1 Fingerprint: 69:bd:8c:f4:9c:d3:00:fb:59:2e:17:93:ca:55:6a:f3:ec:aa:35:fb # SHA256 Fingerprint: bc:23:f9:8a:31:3c:b9:2d:e3:bb:fc:3a:5a:9f:44:61:ac:39:49:4c:4a:e1:5a:9e:9d:f1:31:e9:9b:73:01:9a -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs 2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu -----END CERTIFICATE----- # Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only # Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only # Label: "Verisign Class 3 Public Primary Certification Authority - G3" # Serial: 206684696279472310254277870180966723415 # MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09 # SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6 # SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44 -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te 2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- # Issuer: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only # Subject: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only # Label: "Verisign Class 4 Public Primary Certification Authority - G3" # Serial: 314531972711909413743075096039378935511 # MD5 Fingerprint: db:c8:f2:27:2e:b1:ea:6a:29:23:5d:fe:56:3e:33:df # SHA1 Fingerprint: c8:ec:8c:87:92:69:cb:4b:ab:39:e9:8d:7e:57:67:f3:14:95:73:9d # SHA256 Fingerprint: e3:89:36:0d:0f:db:ae:b3:d2:50:58:4b:47:30:31:4e:22:2f:39:c1:56:a0:20:14:4e:8d:96:05:61:79:15:06 -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ +mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c 2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== -----END CERTIFICATE----- # Issuer: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited # Subject: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited # Label: "Entrust.net Secure Server CA" # Serial: 927650371 # MD5 Fingerprint: df:f2:80:73:cc:f1:e6:61:73:fc:f5:42:e9:c5:7c:ee # SHA1 Fingerprint: 99:a6:9b:e6:1a:fe:88:6b:4d:2b:82:00:7c:b8:54:fc:31:7e:15:39 # SHA256 Fingerprint: 62:f2:40:27:8c:56:4c:4d:d8:bf:7d:9d:4f:6f:36:6e:a8:94:d2:2f:5f:34:d9:89:a9:83:ac:ec:2f:ff:ed:50 -----BEGIN CERTIFICATE----- MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN 95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd 2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= -----END CERTIFICATE----- # Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited # Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited # Label: "Entrust.net Premium 2048 Secure Server CA" # Serial: 946059622 # MD5 Fingerprint: ba:21:ea:20:d6:dd:db:8f:c1:57:8b:40:ad:a1:fc:fc # SHA1 Fingerprint: 80:1d:62:d0:7b:44:9d:5c:5c:03:5c:98:ea:61:fa:44:3c:2a:58:fe # SHA256 Fingerprint: d1:c3:39:ea:27:84:eb:87:0f:93:4f:c5:63:4e:4a:a9:ad:55:05:01:64:01:f2:64:65:d3:7a:57:46:63:35:9f -----BEGIN CERTIFICATE----- MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH 4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy vUxFnmG6v4SBkgPR0ml8xQ== -----END CERTIFICATE----- # Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust # Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust # Label: "Baltimore CyberTrust Root" # Serial: 33554617 # MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 # SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 # SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- # Issuer: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc. # Subject: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc. # Label: "Equifax Secure Global eBusiness CA" # Serial: 1 # MD5 Fingerprint: 8f:5d:77:06:27:c4:98:3c:5b:93:78:e7:d7:7d:9b:cc # SHA1 Fingerprint: 7e:78:4a:10:1c:82:65:cc:2d:e1:f1:6d:47:b4:40:ca:d9:0a:19:45 # SHA256 Fingerprint: 5f:0b:62:ea:b5:e3:53:ea:65:21:65:16:58:fb:b6:53:59:f4:43:28:0a:4a:fb:d1:04:d7:7d:10:f9:f0:4c:07 -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc 58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv 8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV -----END CERTIFICATE----- # Issuer: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc. # Subject: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc. # Label: "Equifax Secure eBusiness CA 1" # Serial: 4 # MD5 Fingerprint: 64:9c:ef:2e:44:fc:c6:8f:52:07:d0:51:73:8f:cb:3d # SHA1 Fingerprint: da:40:18:8b:91:89:a3:ed:ee:ae:da:97:fe:2f:9d:f5:b7:d1:8a:41 # SHA256 Fingerprint: cf:56:ff:46:a4:a1:86:10:9d:d9:65:84:b5:ee:b5:8a:51:0c:42:75:b0:e5:f9:4f:40:bb:ae:86:5e:19:f6:73 -----BEGIN CERTIFICATE----- MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN /Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== -----END CERTIFICATE----- # Issuer: O=Equifax Secure OU=Equifax Secure eBusiness CA-2 # Subject: O=Equifax Secure OU=Equifax Secure eBusiness CA-2 # Label: "Equifax Secure eBusiness CA 2" # Serial: 930140085 # MD5 Fingerprint: aa:bf:bf:64:97:da:98:1d:6f:c6:08:3a:95:70:33:ca # SHA1 Fingerprint: 39:4f:f6:85:0b:06:be:52:e5:18:56:cc:10:e1:80:e8:82:b3:85:cc # SHA256 Fingerprint: 2f:27:4e:48:ab:a4:ac:7b:76:59:33:10:17:75:50:6d:c3:0e:e3:8e:f6:ac:d5:c0:49:32:cf:e0:41:23:42:20 -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0 NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/ BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy 0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1 E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN -----END CERTIFICATE----- # Issuer: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network # Subject: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network # Label: "AddTrust Low-Value Services Root" # Serial: 1 # MD5 Fingerprint: 1e:42:95:02:33:92:6b:b9:5f:c0:7f:da:d6:b2:4b:fc # SHA1 Fingerprint: cc:ab:0e:a0:4c:23:01:d6:69:7b:dd:37:9f:cd:12:eb:24:e3:94:9d # SHA256 Fingerprint: 8c:72:09:27:9a:c0:4e:27:5e:16:d0:7f:d3:b7:75:e8:01:54:b5:96:80:46:e3:1f:52:dd:25:76:63:24:e9:a7 -----BEGIN CERTIFICATE----- MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC +Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X 7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz 43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= -----END CERTIFICATE----- # Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network # Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network # Label: "AddTrust External Root" # Serial: 1 # MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f # SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68 # SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2 -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE----- # Issuer: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network # Subject: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network # Label: "AddTrust Public Services Root" # Serial: 1 # MD5 Fingerprint: c1:62:3e:23:c5:82:73:9c:03:59:4b:2b:e9:77:49:7f # SHA1 Fingerprint: 2a:b6:28:48:5e:78:fb:f3:ad:9e:79:10:dd:6b:df:99:72:2c:96:e5 # SHA256 Fingerprint: 07:91:ca:07:49:b2:07:82:aa:d3:c7:d7:bd:0c:df:c9:48:58:35:84:3e:b2:d7:99:60:09:ce:43:ab:6c:69:27 -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV 6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH 1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF 62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh 4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= -----END CERTIFICATE----- # Issuer: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network # Subject: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network # Label: "AddTrust Qualified Certificates Root" # Serial: 1 # MD5 Fingerprint: 27:ec:39:47:cd:da:5a:af:e2:9a:01:65:21:a9:4c:bb # SHA1 Fingerprint: 4d:23:78:ec:91:95:39:b5:00:7f:75:8f:03:3b:21:1e:c5:4d:8b:cf # SHA256 Fingerprint: 80:95:21:08:05:db:4b:bc:35:5e:44:28:d8:fd:6e:c2:cd:e3:ab:5f:b9:7a:99:42:98:8e:b8:f4:dc:d0:60:16 -----BEGIN CERTIFICATE----- MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G 87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i 2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no xqE= -----END CERTIFICATE----- # Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. # Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. # Label: "Entrust Root Certification Authority" # Serial: 1164660820 # MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 # SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 # SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi 94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP 9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m 0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- # Issuer: O=RSA Security Inc OU=RSA Security 2048 V3 # Subject: O=RSA Security Inc OU=RSA Security 2048 V3 # Label: "RSA Security 2048 v3" # Serial: 13297492616345471454730593562152402946 # MD5 Fingerprint: 77:0d:19:b1:21:fd:00:42:9c:3e:0c:a5:dd:0b:02:8e # SHA1 Fingerprint: 25:01:90:19:cf:fb:d9:99:1c:b7:68:25:74:8d:94:5f:30:93:95:42 # SHA256 Fingerprint: af:8b:67:62:a1:e5:28:22:81:61:a9:5d:5c:55:9e:e2:66:27:8f:75:d7:9e:83:01:89:a5:03:50:6a:bd:6b:4c -----BEGIN CERTIFICATE----- MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg /9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch 6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 7CAFYd4= -----END CERTIFICATE----- # Issuer: CN=GeoTrust Global CA O=GeoTrust Inc. # Subject: CN=GeoTrust Global CA O=GeoTrust Inc. # Label: "GeoTrust Global CA" # Serial: 144470 # MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5 # SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12 # SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a -----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU 1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV 5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== -----END CERTIFICATE----- # Issuer: CN=GeoTrust Global CA 2 O=GeoTrust Inc. # Subject: CN=GeoTrust Global CA 2 O=GeoTrust Inc. # Label: "GeoTrust Global CA 2" # Serial: 1 # MD5 Fingerprint: 0e:40:a7:6c:de:03:5d:8f:d1:0f:e4:d1:8d:f9:6c:a9 # SHA1 Fingerprint: a9:e9:78:08:14:37:58:88:f2:05:19:b0:6d:2b:0d:2b:60:16:90:7d # SHA256 Fingerprint: ca:2d:82:a0:86:77:07:2f:8a:b6:76:4f:f0:35:67:6c:fe:3e:5e:32:5e:01:21:72:df:3f:92:09:6d:b7:9b:85 -----BEGIN CERTIFICATE----- MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL 5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe 2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv /NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz 4iIprn2DQKi6bA== -----END CERTIFICATE----- # Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc. # Subject: CN=GeoTrust Universal CA O=GeoTrust Inc. # Label: "GeoTrust Universal CA" # Serial: 1 # MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48 # SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79 # SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12 -----BEGIN CERTIFICATE----- MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB /wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG 9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= -----END CERTIFICATE----- # Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. # Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. # Label: "GeoTrust Universal CA 2" # Serial: 1 # MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7 # SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79 # SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m 1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH 6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----END CERTIFICATE----- # Issuer: CN=America Online Root Certification Authority 1 O=America Online Inc. # Subject: CN=America Online Root Certification Authority 1 O=America Online Inc. # Label: "America Online Root Certification Authority 1" # Serial: 1 # MD5 Fingerprint: 14:f1:08:ad:9d:fa:64:e2:89:e7:1c:cf:a8:ad:7d:5e # SHA1 Fingerprint: 39:21:c1:15:c1:5d:0e:ca:5c:cb:5b:c4:f0:7d:21:d8:05:0b:56:6a # SHA256 Fingerprint: 77:40:73:12:c6:3a:15:3d:5b:c0:0b:4e:51:75:9c:df:da:c2:37:dc:2a:33:b6:79:46:e9:8e:9b:fa:68:0a:e3 -----BEGIN CERTIFICATE----- MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2 MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym 1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb 2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 -----END CERTIFICATE----- # Issuer: CN=America Online Root Certification Authority 2 O=America Online Inc. # Subject: CN=America Online Root Certification Authority 2 O=America Online Inc. # Label: "America Online Root Certification Authority 2" # Serial: 1 # MD5 Fingerprint: d6:ed:3c:ca:e2:66:0f:af:10:43:0d:77:9b:04:09:bf # SHA1 Fingerprint: 85:b5:ff:67:9b:0c:79:96:1f:c8:6e:44:22:00:46:13:db:17:92:84 # SHA256 Fingerprint: 7d:3b:46:5a:60:14:e5:26:c0:af:fc:ee:21:27:d2:31:17:27:ad:81:1c:26:84:2d:00:6a:f3:73:06:cc:80:bd -----BEGIN CERTIFICATE----- MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2 MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC 206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2 JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9 BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67 Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3 +L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2 LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8 CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw RY8mkaKO/qk= -----END CERTIFICATE----- # Issuer: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association # Subject: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association # Label: "Visa eCommerce Root" # Serial: 25952180776285836048024890241505565794 # MD5 Fingerprint: fc:11:b8:d8:08:93:30:00:6d:23:f9:7e:eb:52:1e:02 # SHA1 Fingerprint: 70:17:9b:86:8c:00:a4:fa:60:91:52:22:3f:9f:3e:32:bd:e0:05:62 # SHA256 Fingerprint: 69:fa:c9:bd:55:fb:0a:c7:8d:53:bb:ee:5c:f1:d5:97:98:9f:d0:aa:ab:20:a2:51:51:bd:f1:73:3e:e7:d1:22 -----BEGIN CERTIFICATE----- MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h 2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq 299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd 7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw ++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt 398znM/jra6O1I7mT1GvFpLgXPYHDw== -----END CERTIFICATE----- # Issuer: CN=Certum CA O=Unizeto Sp. z o.o. # Subject: CN=Certum CA O=Unizeto Sp. z o.o. # Label: "Certum Root CA" # Serial: 65568 # MD5 Fingerprint: 2c:8f:9f:66:1d:18:90:b1:47:26:9d:8e:86:82:8c:a9 # SHA1 Fingerprint: 62:52:dc:40:f7:11:43:a2:2f:de:9e:f7:34:8e:06:42:51:b1:81:18 # SHA256 Fingerprint: d8:e0:fe:bc:1d:b2:e3:8d:00:94:0f:37:d2:7d:41:34:4d:99:3e:73:4b:99:d5:65:6d:97:78:d4:d8:14:36:24 -----BEGIN CERTIFICATE----- MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs 6GAqm4VKQPNriiTsBhYscw== -----END CERTIFICATE----- # Issuer: CN=AAA Certificate Services O=Comodo CA Limited # Subject: CN=AAA Certificate Services O=Comodo CA Limited # Label: "Comodo AAA Services root" # Serial: 1 # MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 # SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 # SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe 3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- # Issuer: CN=Secure Certificate Services O=Comodo CA Limited # Subject: CN=Secure Certificate Services O=Comodo CA Limited # Label: "Comodo Secure Services root" # Serial: 1 # MD5 Fingerprint: d3:d9:bd:ae:9f:ac:67:24:b3:c8:1b:52:e1:b9:a9:bd # SHA1 Fingerprint: 4a:65:d5:f4:1d:ef:39:b8:b8:90:4a:4a:d3:64:81:33:cf:c7:a1:d1 # SHA256 Fingerprint: bd:81:ce:3b:4f:65:91:d1:1a:67:b5:fc:7a:47:fd:ef:25:52:1b:f9:aa:4e:18:b9:e3:df:2e:34:a7:80:3b:e8 -----BEGIN CERTIFICATE----- MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk 3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz 6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= -----END CERTIFICATE----- # Issuer: CN=Trusted Certificate Services O=Comodo CA Limited # Subject: CN=Trusted Certificate Services O=Comodo CA Limited # Label: "Comodo Trusted Services root" # Serial: 1 # MD5 Fingerprint: 91:1b:3f:6e:cd:9e:ab:ee:07:fe:1f:71:d2:b3:61:27 # SHA1 Fingerprint: e1:9f:e3:0e:8b:84:60:9e:80:9b:17:0d:72:a8:c5:ba:6e:14:09:bd # SHA256 Fingerprint: 3f:06:e5:56:81:d4:96:f5:be:16:9e:b5:38:9f:9f:2b:8f:f6:1e:17:08:df:68:81:72:48:49:cd:5d:27:cb:69 -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW 1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi -----END CERTIFICATE----- # Issuer: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority # Subject: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority # Label: "QuoVadis Root CA" # Serial: 985026699 # MD5 Fingerprint: 27:de:36:fe:72:b7:00:03:00:9d:f4:f0:1e:6c:04:24 # SHA1 Fingerprint: de:3f:40:bd:50:93:d3:9b:6c:60:f6:da:bc:07:62:01:00:89:76:c9 # SHA256 Fingerprint: a4:5e:de:3b:bb:f0:9c:8a:e1:5c:72:ef:c0:72:68:d6:93:a2:1c:99:6f:d5:1e:67:ca:07:94:60:fd:6d:88:73 -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK SnQ2+Q== -----END CERTIFICATE----- # Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited # Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited # Label: "QuoVadis Root CA 2" # Serial: 1289 # MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b # SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 # SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp +ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og /zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y 4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza 8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- # Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited # Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited # Label: "QuoVadis Root CA 3" # Serial: 1478 # MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf # SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 # SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB 4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd 8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A 4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd +LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B 4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK 4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- # Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 # Subject: O=SECOM Trust.net OU=Security Communication RootCA1 # Label: "Security Communication Root CA" # Serial: 0 # MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a # SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 # SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== -----END CERTIFICATE----- # Issuer: CN=Sonera Class2 CA O=Sonera # Subject: CN=Sonera Class2 CA O=Sonera # Label: "Sonera Class 2 Root CA" # Serial: 29 # MD5 Fingerprint: a3:ec:75:0f:2e:88:df:fa:48:01:4e:0b:5c:48:6f:fb # SHA1 Fingerprint: 37:f7:6d:e6:07:7c:90:c5:b1:3e:93:1a:b7:41:10:b4:f2:e4:9a:27 # SHA256 Fingerprint: 79:08:b4:03:14:c1:38:10:0b:51:8d:07:35:80:7f:fb:fc:f8:51:8a:00:95:33:71:05:ba:38:6b:15:3d:d9:27 -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt 5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s 3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu 8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ 3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M -----END CERTIFICATE----- # Issuer: CN=Staat der Nederlanden Root CA O=Staat der Nederlanden # Subject: CN=Staat der Nederlanden Root CA O=Staat der Nederlanden # Label: "Staat der Nederlanden Root CA" # Serial: 10000010 # MD5 Fingerprint: 60:84:7c:5a:ce:db:0c:d4:cb:a7:e9:fe:02:c6:a9:c0 # SHA1 Fingerprint: 10:1d:fa:3f:d5:0b:cb:bb:9b:b5:60:0c:19:55:a4:1a:f4:73:3a:04 # SHA256 Fingerprint: d4:1d:82:9e:8c:16:59:82:2a:f9:3f:ce:62:bf:fc:de:26:4f:c8:4e:8b:95:0c:5f:f2:75:d0:52:35:46:95:a3 -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71 9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA 7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k /rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6 u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy 7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== -----END CERTIFICATE----- # Issuer: O=TDC Internet OU=TDC Internet Root CA # Subject: O=TDC Internet OU=TDC Internet Root CA # Label: "TDC Internet Root CA" # Serial: 986490188 # MD5 Fingerprint: 91:f4:03:55:20:a1:f8:63:2c:62:de:ac:fb:61:1c:8e # SHA1 Fingerprint: 21:fc:bd:8e:7f:6c:af:05:1b:d1:b3:43:ec:a8:e7:61:47:f2:0f:8a # SHA256 Fingerprint: 48:98:c6:88:8c:0c:ff:b0:d3:e3:1a:ca:8a:37:d4:e3:51:5f:f7:46:d0:26:35:d8:66:46:cf:a0:a3:18:5a:e7 -----BEGIN CERTIFICATE----- MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a 0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1 4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3 WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ 2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89 9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0 jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38 aQNiuJkFBT1reBK9sG9l -----END CERTIFICATE----- # Issuer: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com # Subject: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com # Label: "UTN DATACorp SGC Root CA" # Serial: 91374294542884689855167577680241077609 # MD5 Fingerprint: b3:a5:3e:77:21:6d:ac:4a:c0:c9:fb:d5:41:3d:ca:06 # SHA1 Fingerprint: 58:11:9f:0e:12:82:87:ea:50:fd:d9:87:45:6f:4f:78:dc:fa:d6:d4 # SHA256 Fingerprint: 85:fb:2f:91:dd:12:27:5a:01:45:b6:36:53:4f:84:02:4a:d6:8b:69:b8:ee:88:68:4f:f7:11:37:58:05:b3:48 -----BEGIN CERTIFICATE----- MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK 4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv 2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- # Issuer: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com # Subject: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com # Label: "UTN USERFirst Hardware Root CA" # Serial: 91374294542884704022267039221184531197 # MD5 Fingerprint: 4c:56:41:e5:0d:bb:2b:e8:ca:a3:ed:18:08:ad:43:39 # SHA1 Fingerprint: 04:83:ed:33:99:ac:36:08:05:87:22:ed:bc:5e:46:00:e3:be:f9:d7 # SHA256 Fingerprint: 6e:a5:47:41:d0:04:66:7e:ed:1b:48:16:63:4a:a3:a7:9e:6e:4b:96:95:0f:82:79:da:fc:8d:9b:d8:81:21:37 -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn 0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM //bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t 3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== -----END CERTIFICATE----- # Issuer: CN=Chambers of Commerce Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org # Subject: CN=Chambers of Commerce Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org # Label: "Camerfirma Chambers of Commerce Root" # Serial: 0 # MD5 Fingerprint: b0:01:ee:14:d9:af:29:18:94:76:8e:f1:69:33:2a:84 # SHA1 Fingerprint: 6e:3a:55:a4:19:0c:19:5c:93:84:3c:c0:db:72:2e:31:30:61:f0:b1 # SHA256 Fingerprint: 0c:25:8a:12:a5:67:4a:ef:25:f2:8b:a7:dc:fa:ec:ee:a3:48:e5:41:e6:f5:cc:4e:e6:3b:71:b3:61:60:6a:c3 -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq 7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p 26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi 1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu tGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- # Issuer: CN=Global Chambersign Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org # Subject: CN=Global Chambersign Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org # Label: "Camerfirma Global Chambersign Root" # Serial: 0 # MD5 Fingerprint: c5:e6:7b:bf:06:d0:4f:43:ed:c4:7a:65:8a:fb:6b:19 # SHA1 Fingerprint: 33:9b:6b:14:50:24:9b:55:7a:01:87:72:84:d9:e0:2f:c3:d2:d8:e9 # SHA256 Fingerprint: ef:3c:b4:17:fc:8e:bf:6f:97:87:6c:9e:4e:ce:39:de:1e:a5:fe:64:91:41:d1:02:8b:7d:11:c0:b2:29:8c:ed -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- # Issuer: CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok # Subject: CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok # Label: "NetLock Notary (Class A) Root" # Serial: 259 # MD5 Fingerprint: 86:38:6d:5e:49:63:6c:85:5c:db:6d:dc:94:b7:d0:f7 # SHA1 Fingerprint: ac:ed:5f:65:53:fd:25:ce:01:5f:1f:7a:48:3b:6a:74:9f:61:78:c6 # SHA256 Fingerprint: 7f:12:cd:5f:7e:5e:29:0e:c7:d8:51:79:d5:b7:2c:20:a5:be:75:08:ff:db:5b:f8:1a:b9:68:4a:7f:c9:f6:67 -----BEGIN CERTIFICATE----- MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0 dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0 N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi 3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8 WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4 QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0 YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3 Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6 ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1 YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP 0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK 8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI -----END CERTIFICATE----- # Issuer: CN=NetLock Uzleti (Class B) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok # Subject: CN=NetLock Uzleti (Class B) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok # Label: "NetLock Business (Class B) Root" # Serial: 105 # MD5 Fingerprint: 39:16:aa:b9:6a:41:e1:14:69:df:9e:6c:3b:72:dc:b6 # SHA1 Fingerprint: 87:9f:4b:ee:05:df:98:58:3b:e3:60:d6:33:e7:0d:3f:fe:98:71:af # SHA256 Fingerprint: 39:df:7b:68:2b:7b:93:8f:84:71:54:81:cc:de:8d:60:d8:f2:2e:c5:98:87:7d:0a:aa:c1:2b:59:18:2b:03:12 -----BEGIN CERTIFICATE----- MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05 OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0 IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06 sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS NitjrFgBazMpUIaD8QFI -----END CERTIFICATE----- # Issuer: CN=NetLock Expressz (Class C) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok # Subject: CN=NetLock Expressz (Class C) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok # Label: "NetLock Express (Class C) Root" # Serial: 104 # MD5 Fingerprint: 4f:eb:f1:f0:70:c2:80:63:5d:58:9f:da:12:3c:a9:c4 # SHA1 Fingerprint: e3:92:51:2f:0a:cf:f5:05:df:f6:de:06:7f:75:37:e1:65:ea:57:4b # SHA256 Fingerprint: 0b:5e:ed:4e:84:64:03:cf:55:e0:65:84:84:40:ed:2a:82:75:8b:f5:b9:aa:1f:25:3d:46:13:cf:a0:80:ff:3f -----BEGIN CERTIFICATE----- MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC 2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0 YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0 aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4 Fp1hBWeAyNDYpQcCNJgEjTME1A== -----END CERTIFICATE----- # Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com # Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com # Label: "XRamp Global CA Root" # Serial: 107108908803651509692980124233745014957 # MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 # SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 # SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ O+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- # Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority # Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority # Label: "Go Daddy Class 2 CA" # Serial: 0 # MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 # SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 # SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h /t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf ReYNnyicsbkqWletNw+vHX/bvZ8= -----END CERTIFICATE----- # Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority # Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority # Label: "Starfield Class 2 CA" # Serial: 0 # MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 # SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a # SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf 8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN +lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA 1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- # Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing # Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing # Label: "StartCom Certification Authority" # Serial: 1 # MD5 Fingerprint: 22:4d:8f:8a:fc:f7:35:c2:bb:57:34:90:7b:8b:22:16 # SHA1 Fingerprint: 3e:2b:f7:f2:03:1b:96:f3:8c:e6:c4:d8:a8:5d:3e:2d:58:47:6a:0f # SHA256 Fingerprint: c7:66:a9:be:f2:d4:07:1c:86:3a:31:aa:49:20:e8:13:b2:d1:98:60:8c:b7:b7:cf:e2:11:43:b8:36:df:09:ea -----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ 9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= -----END CERTIFICATE----- # Issuer: O=Government Root Certification Authority # Subject: O=Government Root Certification Authority # Label: "Taiwan GRCA" # Serial: 42023070807708724159991140556527066870 # MD5 Fingerprint: 37:85:44:53:32:45:1f:20:f0:f3:95:e1:25:c4:43:4e # SHA1 Fingerprint: f4:8b:11:bf:de:ab:be:94:54:20:71:e6:41:de:6b:be:88:2b:40:b9 # SHA256 Fingerprint: 76:00:29:5e:ef:e8:5b:9e:1f:d6:24:db:76:06:2a:aa:ae:59:81:8a:54:d2:77:4c:d4:c0:b2:c0:11:31:e1:b3 -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl pYYsfPQS -----END CERTIFICATE----- # Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 # Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 # Label: "Firmaprofesional Root CA" # Serial: 1 # MD5 Fingerprint: 11:92:79:40:3c:b1:83:40:e5:ab:66:4a:67:92:80:df # SHA1 Fingerprint: a9:62:8f:4b:98:a9:1b:48:35:ba:d2:c1:46:32:86:bb:66:64:6a:8c # SHA256 Fingerprint: c1:cf:0b:52:09:64:35:e3:f1:b7:1d:aa:ec:45:5a:23:11:c8:40:4f:55:83:a9:e2:13:c6:9d:85:7d:94:33:05 -----BEGIN CERTIFICATE----- MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMx IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1 dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w HhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTELMAkGA1UEBhMCRVMx IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1 dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5u Cp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdY rv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3z hxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPay BQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcL iam8NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcb AgMBAAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lv bmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0 MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E FgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQADggEBAEdz/o0n VPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36m hoEyIwOdyPdfwUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzfl ZKG+TQyTmAyX9odtsz/ny4Cm7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBp QWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YGVM+h4k0460tQtcsm9MracEpqoeJ5 quGnM/b9Sh/22WA= -----END CERTIFICATE----- # Issuer: CN=Wells Fargo Root Certificate Authority O=Wells Fargo OU=Wells Fargo Certification Authority # Subject: CN=Wells Fargo Root Certificate Authority O=Wells Fargo OU=Wells Fargo Certification Authority # Label: "Wells Fargo Root CA" # Serial: 971282334 # MD5 Fingerprint: 20:0b:4a:7a:88:a7:a9:42:86:8a:5f:74:56:7b:88:05 # SHA1 Fingerprint: 93:e6:ab:22:03:03:b5:23:28:dc:da:56:9e:ba:e4:d1:d1:cc:fb:65 # SHA256 Fingerprint: 03:45:8b:6a:be:ec:c2:14:95:3d:97:14:9a:f4:53:91:69:1d:e9:f9:cd:cc:26:47:86:3a:3d:67:c9:5c:24:3b -----BEGIN CERTIFICATE----- MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMC VVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9v dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDAxMDExMTY0MTI4WhcNMjEwMTE0 MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSww KgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0G A1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n13 5zHCLielTWi5MbqNQ1mXx3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHE SxP9cMIlrCL1dQu3U+SlK93OvRw6esP3E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4O JgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5OEL8pahbSCOz6+MlsoCu ltQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4jsNtlAHCE AQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMB AAGjYTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcB CzAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRw b2xpY3kwDQYJKoZIhvcNAQEFBQADggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo 7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrvm+0fazbuSCUlFLZWohDo7qd/ 0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0ROhPs7fpvcmR7 nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ 33ZwmVxwQ023tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= -----END CERTIFICATE----- # Issuer: CN=Swisscom Root CA 1 O=Swisscom OU=Digital Certificate Services # Subject: CN=Swisscom Root CA 1 O=Swisscom OU=Digital Certificate Services # Label: "Swisscom Root CA 1" # Serial: 122348795730808398873664200247279986742 # MD5 Fingerprint: f8:38:7c:77:88:df:2c:16:68:2e:c2:e2:52:4b:b8:f9 # SHA1 Fingerprint: 5f:3a:fc:0a:8b:64:f6:86:67:34:74:df:7e:a9:a2:fe:f9:fa:7a:51 # SHA256 Fingerprint: 21:db:20:12:36:60:bb:2e:d4:18:20:5d:a1:1e:e7:a8:5a:65:e2:bc:6e:55:b5:af:7e:78:99:c8:a2:66:d9:2e -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo 19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e 3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 MBr1mmz0DlP5OlvRHA== -----END CERTIFICATE----- # Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com # Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com # Label: "DigiCert Assured ID Root CA" # Serial: 17154717934120587862167794914071425081 # MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 # SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 # SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- # Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com # Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com # Label: "DigiCert Global Root CA" # Serial: 10944719598952040374951832963794454346 # MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e # SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 # SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- # Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com # Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com # Label: "DigiCert High Assurance EV Root CA" # Serial: 3553400076410547919724730734378100087 # MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a # SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 # SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- # Issuer: CN=Class 2 Primary CA O=Certplus # Subject: CN=Class 2 Primary CA O=Certplus # Label: "Certplus Class 2 Primary CA" # Serial: 177770208045934040241468760488327595043 # MD5 Fingerprint: 88:2c:8c:52:b8:a2:3c:f3:f7:bb:03:ea:ae:ac:42:0b # SHA1 Fingerprint: 74:20:74:41:72:9c:dd:92:ec:79:31:d8:23:10:8d:c2:81:92:e2:bb # SHA256 Fingerprint: 0f:99:3c:8a:ef:97:ba:af:56:87:14:0e:d5:9a:d1:82:1b:b4:af:ac:f0:aa:9a:58:b5:d5:7a:33:8a:3a:fb:cb -----BEGIN CERTIFICATE----- MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 l7+ijrRU -----END CERTIFICATE----- # Issuer: CN=DST Root CA X3 O=Digital Signature Trust Co. # Subject: CN=DST Root CA X3 O=Digital Signature Trust Co. # Label: "DST Root CA X3" # Serial: 91299735575339953335919266965803778155 # MD5 Fingerprint: 41:03:52:dc:0f:f7:50:1b:16:f0:02:8e:ba:6f:45:c5 # SHA1 Fingerprint: da:c9:02:4f:54:d8:f6:df:94:93:5f:b1:73:26:38:ca:6a:d7:7c:13 # SHA256 Fingerprint: 06:87:26:03:31:a7:24:03:d9:09:f1:05:e6:9b:cf:0d:32:e1:bd:24:93:ff:c6:d9:20:6d:11:bc:d6:77:07:39 -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- # Issuer: CN=DST ACES CA X6 O=Digital Signature Trust OU=DST ACES # Subject: CN=DST ACES CA X6 O=Digital Signature Trust OU=DST ACES # Label: "DST ACES CA X6" # Serial: 17771143917277623872238992636097467865 # MD5 Fingerprint: 21:d8:4c:82:2b:99:09:33:a2:eb:14:24:8d:8e:5f:e8 # SHA1 Fingerprint: 40:54:da:6f:1c:3f:40:74:ac:ed:0f:ec:cd:db:79:d1:53:fb:90:1d # SHA256 Fingerprint: 76:7c:95:5a:76:41:2c:89:af:68:8e:90:a1:c7:0f:55:6c:fd:6b:60:25:db:ea:10:41:6d:7e:b6:83:1f:8c:40 -----BEGIN CERTIFICATE----- MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= -----END CERTIFICATE----- # Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı O=(c) 2005 TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. # Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı O=(c) 2005 TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. # Label: "TURKTRUST Certificate Services Provider Root 1" # Serial: 1 # MD5 Fingerprint: f1:6a:22:18:c9:cd:df:ce:82:1d:1d:b7:78:5c:a9:a5 # SHA1 Fingerprint: 79:98:a3:08:e1:4d:65:85:e6:c2:1e:15:3a:71:9f:ba:5a:d3:4a:d9 # SHA256 Fingerprint: 44:04:e3:3b:5e:14:0d:cf:99:80:51:fd:fc:80:28:c7:c8:16:15:c5:ee:73:7b:11:1b:58:82:33:a9:b5:35:a0 -----BEGIN CERTIFICATE----- MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOc UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMQswCQYDVQQGDAJUUjEPMA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykg MjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMxMDI3MTdaFw0xNTAz MjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2Vy dGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYD VQQHDAZBTktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kg xLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEu xZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7 XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GXyGl8hMW0kWxsE2qkVa2k heiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8iSi9BB35J YbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5C urKZ8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1 JuTm5Rh8i27fbMx4W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51 b0dewQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV 9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46sWrv7/hg0Uw2ZkUd82YCdAR7 kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxEq8Sn5RTOPEFh fEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdA aLX/7KfS0zgYnNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKS RGQDJereW26fyfJOrN3H -----END CERTIFICATE----- # Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. (c) Kasım 2005 # Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. (c) Kasım 2005 # Label: "TURKTRUST Certificate Services Provider Root 2" # Serial: 1 # MD5 Fingerprint: 37:a5:6e:d4:b1:25:84:97:b7:fd:56:15:7a:f9:a2:00 # SHA1 Fingerprint: b4:35:d4:e1:11:9d:1c:66:90:a7:49:eb:b3:94:bd:63:7b:a7:82:b7 # SHA256 Fingerprint: c4:70:cf:54:7e:23:02:b9:77:fb:29:dd:71:a8:9a:7b:6c:1f:60:77:7b:03:29:f5:60:17:f3:28:bf:4f:6b:e6 -----BEGIN CERTIFICATE----- MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3 WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI= -----END CERTIFICATE----- # Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG # Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG # Label: "SwissSign Gold CA - G2" # Serial: 13492815561806991280 # MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 # SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 # SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c 6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn 8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a 77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- # Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG # Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG # Label: "SwissSign Silver CA - G2" # Serial: 5700383053117599563 # MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 # SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb # SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH 6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ 2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- # Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. # Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. # Label: "GeoTrust Primary Certification Authority" # Serial: 32798226551256963324313806436981982369 # MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf # SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96 # SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c -----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl 4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= -----END CERTIFICATE----- # Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only # Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only # Label: "thawte Primary Root CA" # Serial: 69529181992039203566298953787712940909 # MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12 # SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81 # SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta 3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk 6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 /qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 jVaMaA== -----END CERTIFICATE----- # Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only # Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only # Label: "VeriSign Class 3 Public Primary Certification Authority - G5" # Serial: 33037644167568058970164719475676101450 # MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c # SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5 # SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- # Issuer: CN=SecureTrust CA O=SecureTrust Corporation # Subject: CN=SecureTrust CA O=SecureTrust Corporation # Label: "SecureTrust CA" # Serial: 17199774589125277788362757014266862032 # MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 # SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 # SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO 0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj 7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS 8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ 3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- # Issuer: CN=Secure Global CA O=SecureTrust Corporation # Subject: CN=Secure Global CA O=SecureTrust Corporation # Label: "Secure Global CA" # Serial: 9751836167731051554232119481456978597 # MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de # SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b # SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa /FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- # Issuer: CN=COMODO Certification Authority O=COMODO CA Limited # Subject: CN=COMODO Certification Authority O=COMODO CA Limited # Label: "COMODO Certification Authority" # Serial: 104350513648249232941998508985834464573 # MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 # SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b # SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI 2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp +2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW /zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB ZQ== -----END CERTIFICATE----- # Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. # Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. # Label: "Network Solutions Certificate Authority" # Serial: 116697915152937497490437556386812487904 # MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e # SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce # SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH /nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- # Issuer: CN=WellsSecure Public Root Certificate Authority O=Wells Fargo WellsSecure OU=Wells Fargo Bank NA # Subject: CN=WellsSecure Public Root Certificate Authority O=Wells Fargo WellsSecure OU=Wells Fargo Bank NA # Label: "WellsSecure Public Root Certificate Authority" # Serial: 1 # MD5 Fingerprint: 15:ac:a5:c2:92:2d:79:bc:e8:7f:cb:67:ed:02:cf:36 # SHA1 Fingerprint: e7:b4:f6:9d:61:ec:90:69:db:7e:90:a7:40:1a:3c:f4:7d:4f:e8:ee # SHA256 Fingerprint: a7:12:72:ae:aa:a3:cf:e8:72:7f:7f:b3:9f:0f:b3:d1:e5:42:6e:90:60:b0:6e:e6:f1:3e:9a:3c:58:33:cd:43 -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd /ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv 2G0xffX8oRAHh84vWdw+WNs= -----END CERTIFICATE----- # Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited # Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited # Label: "COMODO ECC Certification Authority" # Serial: 41578283867086692638256921589707938090 # MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 # SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 # SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 -----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- # Issuer: CN=IGC/A O=PM/SGDN OU=DCSSI # Subject: CN=IGC/A O=PM/SGDN OU=DCSSI # Label: "IGC/A" # Serial: 245102874772 # MD5 Fingerprint: 0c:7f:dd:6a:f4:2a:b9:c8:9b:bd:20:7e:a9:db:5c:37 # SHA1 Fingerprint: 60:d6:89:74:b5:c2:65:9e:8a:0f:c1:88:7c:88:d2:46:69:1b:18:2c # SHA256 Fingerprint: b9:be:a7:86:0a:96:2e:a3:61:1d:ab:97:ab:6d:a3:e2:1c:10:68:b9:7d:55:57:5e:d0:e1:12:79:c1:1c:89:32 -----BEGIN CERTIFICATE----- MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYT AkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQ TS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG 9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMB4XDTAyMTIxMzE0MjkyM1oXDTIw MTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAM BgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEO MAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2 LmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaI s9z4iPf930Pfeo2aSVz2TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2 xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCWSo7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4 u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYyHF2fYPepraX/z9E0+X1b F8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNdfrGoRpAx Vs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGd PDPQtQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNV HSAEDjAMMAoGCCqBegF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAx NjAfBgNVHSMEGDAWgBSjBS8YYFDCiQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUF AAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RKq89toB9RlPhJy3Q2FLwV3duJ L92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3QMZsyK10XZZOY YLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2a NjSaTFR+FwNIlQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R 0982gaEbeC9xs/FZTEYYKKuF0mBWWg== -----END CERTIFICATE----- # Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication EV RootCA1 # Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication EV RootCA1 # Label: "Security Communication EV RootCA1" # Serial: 0 # MD5 Fingerprint: 22:2d:a6:01:ea:7c:0a:f7:f0:6c:56:43:3f:77:76:d3 # SHA1 Fingerprint: fe:b8:c4:32:dc:f9:76:9a:ce:ae:3d:d8:90:8f:fd:28:86:65:64:7d # SHA256 Fingerprint: a2:2d:ba:68:1e:97:37:6e:2d:39:7d:72:8a:ae:3a:9b:62:96:b9:fd:ba:60:bc:2e:11:f6:47:f2:c6:75:fb:37 -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 -----END CERTIFICATE----- # Issuer: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed # Subject: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed # Label: "OISTE WISeKey Global Root GA CA" # Serial: 86718877871133159090080555911823548314 # MD5 Fingerprint: bc:6c:51:33:a7:e9:d3:66:63:54:15:72:1b:21:92:93 # SHA1 Fingerprint: 59:22:a1:e1:5a:ea:16:35:21:f8:98:39:6a:46:46:b0:44:1b:0f:a9 # SHA256 Fingerprint: 41:c9:23:86:6a:b4:ca:d6:b7:ad:57:80:81:58:2e:02:07:97:a6:cb:df:4f:ff:78:ce:83:96:b3:89:37:d7:f5 -----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg 4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ /L7fCg0= -----END CERTIFICATE----- # Issuer: CN=Microsec e-Szigno Root CA O=Microsec Ltd. OU=e-Szigno CA # Subject: CN=Microsec e-Szigno Root CA O=Microsec Ltd. OU=e-Szigno CA # Label: "Microsec e-Szigno Root CA" # Serial: 272122594155480254301341951808045322001 # MD5 Fingerprint: f0:96:b6:2f:c5:10:d5:67:8e:83:25:32:e8:5e:2e:e5 # SHA1 Fingerprint: 23:88:c9:d3:71:cc:9e:96:3d:ff:7d:3c:a7:ce:fc:d6:25:ec:19:0d # SHA256 Fingerprint: 32:7a:3d:76:1a:ba:de:a0:34:eb:99:84:06:27:5c:b1:a4:77:6e:fd:ae:2f:df:6d:01:68:ea:1c:4f:55:67:d0 -----BEGIN CERTIFICATE----- MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAw cjELMAkGA1UEBhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNy b3NlYyBMdGQuMRQwEgYDVQQLEwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9z ZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0MDYxMjI4NDRaFw0xNzA0MDYxMjI4 NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEWMBQGA1UEChMN TWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMTGU1p Y3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2u uO/TEdyB5s87lozWbxXGd36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+ LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/NoqdNAoI/gqyFxuEPkEeZlApxcpMqyabA vjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjcQR/Ji3HWVBTji1R4P770 Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJPqW+jqpx 62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcB AQRbMFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3Aw LQYIKwYBBQUHMAKGIWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAP BgNVHRMBAf8EBTADAQH/MIIBcwYDVR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIB AQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3LmUtc3ppZ25vLmh1L1NaU1ov MIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0AdAB2AOEAbgB5 ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABT AHoAbwBsAGcA4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABh ACAAcwB6AGUAcgBpAG4AdAAgAGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABo AHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMAegBpAGcAbgBvAC4AaAB1AC8AUwBa AFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6Ly93d3cuZS1zemln bm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NOPU1p Y3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxP PU1pY3Jvc2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZv Y2F0aW9uTGlzdDtiaW5hcnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuB EGluZm9AZS1zemlnbm8uaHWkdzB1MSMwIQYDVQQDDBpNaWNyb3NlYyBlLVN6aWdu w7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhTWjEWMBQGA1UEChMNTWlj cm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhVMIGsBgNV HSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJI VTERMA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDAS BgNVBAsTC2UtU3ppZ25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBS b290IENBghEAzLjnv04pGv2i3GalHCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS 8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMTnGZjWS7KXHAM/IO8VbH0jgds ZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FEaGAHQzAxQmHl 7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a 86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfR hUZLphK3dehKyVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/ MPMMNz7UwiiAc7EBt51alhQBS6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= -----END CERTIFICATE----- # Issuer: CN=Certigna O=Dhimyotis # Subject: CN=Certigna O=Dhimyotis # Label: "Certigna" # Serial: 18364802974209362175 # MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff # SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 # SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q 130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG 9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- # Issuer: CN=AC Raíz Certicámara S.A. O=Sociedad Cameral de Certificación Digital - Certicámara S.A. # Subject: CN=AC Raíz Certicámara S.A. O=Sociedad Cameral de Certificación Digital - Certicámara S.A. # Label: "AC Ra\xC3\xADz Certic\xC3\xA1mara S.A." # Serial: 38908203973182606954752843738508300 # MD5 Fingerprint: 93:2a:3e:f6:fd:23:69:0d:71:20:d4:2b:47:99:2b:a6 # SHA1 Fingerprint: cb:a1:c5:f8:b0:e3:5e:b8:b9:45:12:d3:f9:34:a2:e9:06:10:d3:36 # SHA256 Fingerprint: a6:c5:1e:0d:a5:ca:0a:93:09:d2:e4:c0:e4:0c:2a:f9:10:7a:ae:82:03:85:7f:e1:98:e3:e7:69:e3:43:08:5c -----BEGIN CERTIFICATE----- MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4 Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ 54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50 7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6 xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/ Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42 gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0 jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+ XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/ RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk BYn8eNZcLCZDqQ== -----END CERTIFICATE----- # Issuer: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA # Subject: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA # Label: "TC TrustCenter Class 2 CA II" # Serial: 941389028203453866782103406992443 # MD5 Fingerprint: ce:78:33:5c:59:78:01:6e:18:ea:b9:36:a0:b9:2e:23 # SHA1 Fingerprint: ae:50:83:ed:7c:f4:5c:bc:8f:61:c6:21:fe:68:5d:79:42:21:15:6e # SHA256 Fingerprint: e6:b8:f8:76:64:85:f8:07:ae:7f:8d:ac:16:70:46:1f:07:c0:a1:3e:ef:3a:1f:f7:17:53:8d:7a:ba:d3:91:b4 -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK 8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99 5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3 kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6 Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8 au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ== -----END CERTIFICATE----- # Issuer: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA # Subject: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA # Label: "TC TrustCenter Class 3 CA II" # Serial: 1506523511417715638772220530020799 # MD5 Fingerprint: 56:5f:aa:80:61:12:17:f6:67:21:e6:2b:6d:61:56:8e # SHA1 Fingerprint: 80:25:ef:f4:6e:70:c8:d4:72:24:65:84:fe:40:3b:8a:8d:6a:db:f5 # SHA256 Fingerprint: 8d:a0:84:fc:f9:9c:e0:77:22:f8:9b:32:05:93:98:06:fa:5c:b8:11:e1:c8:13:f6:a1:08:c7:d3:36:b3:40:8e -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2 1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1 Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6 Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8 TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6 g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB 95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A== -----END CERTIFICATE----- # Issuer: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA # Subject: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA # Label: "TC TrustCenter Universal CA I" # Serial: 601024842042189035295619584734726 # MD5 Fingerprint: 45:e1:a5:72:c5:a9:36:64:40:9e:f5:e4:58:84:67:8c # SHA1 Fingerprint: 6b:2f:34:ad:89:58:be:62:fd:b0:6b:5c:ce:bb:9d:d9:4f:4e:39:f3 # SHA256 Fingerprint: eb:f3:c0:2a:87:89:b1:fb:7d:51:19:95:d6:63:b7:29:06:d9:13:ce:0d:5e:10:56:8a:8a:77:e2:58:61:67:e7 -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1 7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn 8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/ 2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY -----END CERTIFICATE----- # Issuer: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center # Subject: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center # Label: "Deutsche Telekom Root CA 2" # Serial: 38 # MD5 Fingerprint: 74:01:4a:91:b1:08:c4:58:ce:47:cd:f0:dd:11:53:08 # SHA1 Fingerprint: 85:a4:08:c0:9c:19:3e:5d:51:58:7d:cd:d6:13:30:fd:8c:de:37:bf # SHA256 Fingerprint: b6:19:1a:50:d0:c3:97:7f:7d:a9:9b:cd:aa:c8:6a:22:7d:ae:b9:67:9e:c7:0b:a3:b0:c9:d9:22:71:c1:70:d3 -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl 6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- # Issuer: CN=ComSign Secured CA O=ComSign # Subject: CN=ComSign Secured CA O=ComSign # Label: "ComSign Secured CA" # Serial: 264725503855295744117309814499492384489 # MD5 Fingerprint: 40:01:25:06:8d:21:43:6a:0e:43:00:9c:e7:43:f3:d5 # SHA1 Fingerprint: f9:cd:0e:2c:da:76:24:c1:8f:bd:f0:f0:ab:b6:45:b8:f7:fe:d5:7a # SHA256 Fingerprint: 50:79:41:c7:44:60:a0:b4:70:86:22:0d:4e:99:32:57:2a:b5:d1:b5:bb:cb:89:80:ab:1c:b1:76:51:a8:44:d2 -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu MQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwx GzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjEL MAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGtWhf HZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs49oh gHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sW v+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ue Mv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr 9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt 6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7 MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNl Y3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58 ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkq hkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7p iL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtC dsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAmlaxMDPWL kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== -----END CERTIFICATE----- # Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc # Subject: CN=Cybertrust Global Root O=Cybertrust, Inc # Label: "Cybertrust Global Root" # Serial: 4835703278459682877484360 # MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1 # SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6 # SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3 -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW WL1WMRJOEcgh4LMRkWXbtKaIOM5V -----END CERTIFICATE----- # Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority # Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority # Label: "ePKI Root Certification Authority" # Serial: 28956088682735189655030529057352760477 # MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 # SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 # SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS /jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D hNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- # Issuer: CN=TÜBİTAK UEKAE Kök Sertifika Hizmet Sağlayıcısı - Sürüm 3 O=Türkiye Bilimsel ve Teknolojik Araştırma Kurumu - TÜBİTAK OU=Ulusal Elektronik ve Kriptoloji Araştırma Enstitüsü - UEKAE/Kamu Sertifikasyon Merkezi # Subject: CN=TÜBİTAK UEKAE Kök Sertifika Hizmet Sağlayıcısı - Sürüm 3 O=Türkiye Bilimsel ve Teknolojik Araştırma Kurumu - TÜBİTAK OU=Ulusal Elektronik ve Kriptoloji Araştırma Enstitüsü - UEKAE/Kamu Sertifikasyon Merkezi # Label: "T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3" # Serial: 17 # MD5 Fingerprint: ed:41:f5:8c:50:c5:2b:9c:73:e6:ee:6c:eb:c2:a8:26 # SHA1 Fingerprint: 1b:4b:39:61:26:27:6b:64:91:a2:68:6d:d7:02:43:21:2d:1f:1d:96 # SHA256 Fingerprint: e4:c7:34:30:d7:a5:b5:09:25:df:43:37:0a:0d:21:6e:9a:79:b9:d6:db:83:73:a0:c6:9e:b1:cc:31:c7:c5:2a -----BEGIN CERTIFICATE----- MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2 ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0 aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/ BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM 7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs yZyQ2uypQjyttgI= -----END CERTIFICATE----- # Issuer: CN=Buypass Class 2 CA 1 O=Buypass AS-983163327 # Subject: CN=Buypass Class 2 CA 1 O=Buypass AS-983163327 # Label: "Buypass Class 2 CA 1" # Serial: 1 # MD5 Fingerprint: b8:08:9a:f0:03:cc:1b:0d:c8:6c:0b:76:a1:75:64:23 # SHA1 Fingerprint: a0:a1:ab:90:c9:fc:84:7b:3b:12:61:e8:97:7d:5f:d3:22:61:d3:cc # SHA256 Fingerprint: 0f:4e:9c:dd:26:4b:02:55:50:d1:70:80:63:40:21:4f:e9:44:34:c9:b0:2f:69:7e:c7:10:fc:5f:ea:fb:5e:38 -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg Q2xhc3MgMiBDQSAxMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzEL MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD VQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7McXA0 ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLX l18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVB HfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B 5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3 WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLP gcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+ DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKu BctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHs h7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+oRxKaJyOk LY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho -----END CERTIFICATE----- # Issuer: CN=Buypass Class 3 CA 1 O=Buypass AS-983163327 # Subject: CN=Buypass Class 3 CA 1 O=Buypass AS-983163327 # Label: "Buypass Class 3 CA 1" # Serial: 2 # MD5 Fingerprint: df:3c:73:59:81:e7:39:50:81:04:4c:34:a2:cb:b3:7b # SHA1 Fingerprint: 61:57:3a:11:df:0e:d8:7e:d5:92:65:22:ea:d0:56:d7:44:b3:23:71 # SHA256 Fingerprint: b7:b1:2b:17:1f:82:1d:aa:99:0c:d0:fe:50:87:b1:28:44:8b:a8:e5:18:4f:84:c5:1e:02:b5:c8:fb:96:2b:24 -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI +MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+ mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2 mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 -----END CERTIFICATE----- # Issuer: CN=EBG Elektronik Sertifika Hizmet Sağlayıcısı O=EBG Bilişim Teknolojileri ve Hizmetleri A.Ş. # Subject: CN=EBG Elektronik Sertifika Hizmet Sağlayıcısı O=EBG Bilişim Teknolojileri ve Hizmetleri A.Ş. # Label: "EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1" # Serial: 5525761995591021570 # MD5 Fingerprint: 2c:20:26:9d:cb:1a:4a:00:85:b5:b7:5a:ae:c2:01:37 # SHA1 Fingerprint: 8c:96:ba:eb:dd:2b:07:07:48:ee:30:32:66:a0:f3:98:6e:7c:ae:58 # SHA256 Fingerprint: 35:ae:5b:dd:d8:f7:ae:63:5c:ff:ba:56:82:a8:f0:0b:95:f4:84:62:c7:10:8e:e9:a0:e5:29:2b:07:4a:af:b2 -----BEGIN CERTIFICATE----- MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNV BAMML0VCRyBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMTcwNQYDVQQKDC5FQkcgQmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXpt ZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAeFw0wNjA4MTcwMDIxMDlaFw0xNjA4 MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25payBTZXJ0aWZpa2Eg SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2ltIFRl a25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h 4fuXd7hxlugTlkaDT7byX3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAk tiHq6yOU/im/+4mRDGSaBUorzAzu8T2bgmmkTPiab+ci2hC6X5L8GCcKqKpE+i4s tPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfreYteIAbTdgtsApWjluTL dlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZTqNGFav4 c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8Um TDGyY5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z +kI2sSXFCjEmN1ZnuqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0O Lna9XvNRiYuoP1Vzv9s6xiQFlpJIqkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMW OeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vmExH8nYQKE3vwO9D8owrXieqW fo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0Nokb+Clsi7n2 l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB /wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgw FoAU587GT/wWZ5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+ 8ygjdsZs93/mQJ7ANtyVDR2tFcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI 6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgmzJNSroIBk5DKd8pNSe/iWtkqvTDO TLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64kXPBfrAowzIpAoHME wfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqTbCmY Iai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJn xk1Gj7sURT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4Q DgZxGhBM/nV+/x5XOULK1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9q Kd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11t hie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQY9iJSrSq3RZj9W6+YKH4 7ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9AahH3eU7 QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT -----END CERTIFICATE----- # Issuer: O=certSIGN OU=certSIGN ROOT CA # Subject: O=certSIGN OU=certSIGN ROOT CA # Label: "certSIGN ROOT CA" # Serial: 35210227249154 # MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 # SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b # SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do 0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ 44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN 9u6wWk5JRFRYX0KD -----END CERTIFICATE----- # Issuer: CN=CNNIC ROOT O=CNNIC # Subject: CN=CNNIC ROOT O=CNNIC # Label: "CNNIC ROOT" # Serial: 1228079105 # MD5 Fingerprint: 21:bc:82:ab:49:c4:13:3b:4b:b2:2b:5c:6b:90:9c:19 # SHA1 Fingerprint: 8b:af:4c:9b:1d:f0:2a:92:f7:da:12:8e:b9:1b:ac:f4:98:60:4b:6f # SHA256 Fingerprint: e2:83:93:77:3d:a8:45:a6:79:f2:08:0c:c7:fb:44:a3:b7:a1:c3:79:2c:b7:eb:77:29:fd:cb:6a:8d:99:ae:a7 -----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2 MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6 dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO 76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj 2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE= -----END CERTIFICATE----- # Issuer: O=Japanese Government OU=ApplicationCA # Subject: O=Japanese Government OU=ApplicationCA # Label: "ApplicationCA - Japanese Government" # Serial: 49 # MD5 Fingerprint: 7e:23:4e:5b:a7:a5:b4:25:e9:00:07:74:11:62:ae:d6 # SHA1 Fingerprint: 7f:8a:b0:cf:d0:51:87:6a:66:f3:36:0f:47:c8:8d:8c:d3:35:fc:74 # SHA256 Fingerprint: 2d:47:43:7d:e1:79:51:21:5a:12:f3:c5:8e:51:c7:29:a5:80:26:ef:1f:cc:0a:5f:b3:d9:dc:01:2f:60:0d:19 -----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55 IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm /qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+ eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL rosot4LKGAfmt1t06SAZf7IbiVQ= -----END CERTIFICATE----- # Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only # Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only # Label: "GeoTrust Primary Certification Authority - G3" # Serial: 28809105769928564313984085209975885599 # MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05 # SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd # SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4 -----BEGIN CERTIFICATE----- MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz +uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn 5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G spki4cErx5z481+oghLrGREt -----END CERTIFICATE----- # Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only # Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only # Label: "thawte Primary Root CA - G2" # Serial: 71758320672825410020661621085256472406 # MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f # SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12 # SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57 -----BEGIN CERTIFICATE----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- # Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only # Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only # Label: "thawte Primary Root CA - G3" # Serial: 127614157056681299805556476275995414779 # MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31 # SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2 # SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA 2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu MdRAGmI0Nj81Aa6sY6A= -----END CERTIFICATE----- # Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only # Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only # Label: "GeoTrust Primary Certification Authority - G2" # Serial: 80682863203381065782177908751794619243 # MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a # SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0 # SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66 -----BEGIN CERTIFICATE----- MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz rD6ogRLQy7rQkgu2npaqBA+K -----END CERTIFICATE----- # Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only # Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only # Label: "VeriSign Universal Root Certification Authority" # Serial: 85209574734084581917763752644031726877 # MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19 # SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54 # SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF 9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN /BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz 4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 7M2CYfE45k+XmCpajQ== -----END CERTIFICATE----- # Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only # Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only # Label: "VeriSign Class 3 Public Primary Certification Authority - G4" # Serial: 63143484348153506665311985501458640051 # MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41 # SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a # SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79 -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC 4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- # Issuer: CN=NetLock Arany (Class Gold) Főtanúsítvány O=NetLock Kft. OU=Tanúsítványkiadók (Certification Services) # Subject: CN=NetLock Arany (Class Gold) Főtanúsítvány O=NetLock Kft. OU=Tanúsítványkiadók (Certification Services) # Label: "NetLock Arany (Class Gold) Főtanúsítvány" # Serial: 80544274841616 # MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 # SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 # SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C +C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- # Issuer: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden # Subject: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden # Label: "Staat der Nederlanden Root CA - G2" # Serial: 10000012 # MD5 Fingerprint: 7c:a5:0f:f8:5b:9a:7d:6d:30:ae:54:5a:e3:42:a2:8a # SHA1 Fingerprint: 59:af:82:79:91:86:c7:b4:75:07:cb:cf:03:57:46:eb:04:dd:b7:16 # SHA256 Fingerprint: 66:8c:83:94:7d:a6:3b:72:4b:ec:e1:74:3c:31:a0:e6:ae:d0:db:8e:c5:b3:1b:e3:77:bb:78:4f:91:b6:71:6f -----BEGIN CERTIFICATE----- MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp 5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy 5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv 6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen 5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL +63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== -----END CERTIFICATE----- # Issuer: CN=CA Disig O=Disig a.s. # Subject: CN=CA Disig O=Disig a.s. # Label: "CA Disig" # Serial: 1 # MD5 Fingerprint: 3f:45:96:39:e2:50:87:f7:bb:fe:98:0c:3c:20:98:e6 # SHA1 Fingerprint: 2a:c8:d5:8b:57:ce:bf:2f:49:af:f2:fc:76:8f:51:14:62:90:7a:41 # SHA256 Fingerprint: 92:bf:51:19:ab:ec:ca:d0:b1:33:2d:c4:e1:d0:5f:ba:75:b5:67:90:44:ee:0c:a2:6e:93:1f:74:4f:2f:33:cf -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzET MBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UE AxMIQ0EgRGlzaWcwHhcNMDYwMzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQsw CQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcg YS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgmGErE Nx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnX mjxUizkDPw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYD XcDtab86wYqg6I7ZuUUohwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhW S8+2rT+MitcE5eN4TPWGqvWP+j1scaMtymfraHtuM6kMgiioTGohQBUgDCZbg8Kp FhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8wgfwwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0PAQH/BAQD AgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cu ZGlzaWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5z ay9jYS9jcmwvY2FfZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2sv Y2EvY3JsL2NhX2Rpc2lnLmNybDAaBgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEw DQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59tWDYcPQuBDRIrRhCA/ec8J9B6 yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3mkkp7M5+cTxq EEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeB EicTXxChds6KezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFN PGO+I++MzVpQuGhU+QqZMxEA4Z7CRneC9VkGjCFMhwnN5ag= -----END CERTIFICATE----- # Issuer: CN=Juur-SK O=AS Sertifitseerimiskeskus # Subject: CN=Juur-SK O=AS Sertifitseerimiskeskus # Label: "Juur-SK" # Serial: 999181308 # MD5 Fingerprint: aa:8e:5d:d9:f8:db:0a:58:b7:8d:26:87:6c:82:35:55 # SHA1 Fingerprint: 40:9d:4b:d9:17:b5:5c:27:b6:9b:64:cb:98:22:44:0d:cd:09:b8:89 # SHA256 Fingerprint: ec:c3:e9:c3:40:75:03:be:e0:91:aa:95:2f:41:34:8f:f8:8b:aa:86:3b:22:64:be:fa:c8:07:90:15:74:e9:39 -----BEGIN CERTIFICATE----- MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMw MVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQ MA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOB SvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkz ABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH LCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMP PbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL 2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8w ggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwIC MIHDHoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDk AGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0 AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABz AGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABhAG0AaQBz AGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f BCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcY P2/v6X2+MA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOi CfP+JmeaUOTDBS8rNXiRTHyoERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+g kcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyLabVAyJRld/JXIWY7zoVAtjNjGr95 HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678IIbsSt4beDI3poHS na9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkhMp6q qIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0Z TbvGRNs2yyqcjg== -----END CERTIFICATE----- # Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post # Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post # Label: "Hongkong Post Root CA 1" # Serial: 1000 # MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca # SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58 # SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2 -----BEGIN CERTIFICATE----- MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi AmvZWg== -----END CERTIFICATE----- # Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. # Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. # Label: "SecureSign RootCA11" # Serial: 1 # MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 # SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 # SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 -----BEGIN CERTIFICATE----- MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni 8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN QSdJQO7e5iNEOdyhIta6A/I= -----END CERTIFICATE----- # Issuer: CN=ACEDICOM Root O=EDICOM OU=PKI # Subject: CN=ACEDICOM Root O=EDICOM OU=PKI # Label: "ACEDICOM Root" # Serial: 7029493972724711941 # MD5 Fingerprint: 42:81:a0:e2:1c:e3:55:10:de:55:89:42:65:96:22:e6 # SHA1 Fingerprint: e0:b4:32:2e:b2:f6:a5:68:b6:54:53:84:48:18:4a:50:36:87:43:84 # SHA256 Fingerprint: 03:95:0f:b4:9a:53:1f:3e:19:91:94:23:98:df:a9:e0:ea:32:d7:ba:1c:dd:9b:c8:5d:b5:7e:d9:40:0b:43:4a -----BEGIN CERTIFICATE----- MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UE AwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00x CzAJBgNVBAYTAkVTMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEW MBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZF RElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC AgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHkWLn7 09gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7 XBZXehuDYAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5P Grjm6gSSrj0RuVFCPYewMYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAK t0SdE3QrwqXrIhWYENiLxQSfHY9g5QYbm8+5eaA9oiM/Qj9r+hwDezCNzmzAv+Yb X79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbkHQl/Sog4P75n/TSW9R28 MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTTxKJxqvQU fecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI 2Sf23EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyH K9caUPgn6C9D4zq92Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEae ZAwUswdbxcJzbPEHXEUkFDWug/FqTYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAP BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz4SsrSbbXc6GqlPUB53NlTKxQ MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU9QHnc2VMrFAw RAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWIm fQwng4/F9tqgaHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3 gvoFNTPhNahXwOf9jU8/kzJPeGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKe I6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1PwkzQSulgUV1qzOMPPKC8W64iLgpq0i 5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1ThCojz2GuHURwCRi ipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oIKiMn MCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZ o5NjEFIqnxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6 zqylfDJKZ0DcMDQj3dcEI2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacN GHk0vFQYXlPKNFHtRQrmjseCNj6nOGOpMCwXEGCSn1WHElkQwg9naRHMTh5+Spqt r0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3otkYNbn5XOmeUwssfnHdK Z05phkOTOPu220+DkdRgfks+KzgHVZhepA== -----END CERTIFICATE----- # Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority # Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority # Label: "Verisign Class 3 Public Primary Certification Authority" # Serial: 80507572722862485515306429940691309246 # MD5 Fingerprint: ef:5a:f1:33:ef:f1:cd:bb:51:02:ee:12:14:4b:96:c4 # SHA1 Fingerprint: a1:db:63:93:91:6f:17:e4:18:55:09:40:04:15:c7:02:40:b0:ae:6b # SHA256 Fingerprint: a4:b6:b3:99:6f:c2:f3:06:b3:fd:86:81:bd:63:41:3d:8c:50:09:cc:4f:a3:29:c2:cc:f0:e2:fa:1b:14:03:05 -----BEGIN CERTIFICATE----- MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i 2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ 2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ -----END CERTIFICATE----- # Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. # Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. # Label: "Microsec e-Szigno Root CA 2009" # Serial: 14014712776195784473 # MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 # SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e # SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 +rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c 2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW -----END CERTIFICATE----- # Issuer: CN=e-Guven Kok Elektronik Sertifika Hizmet Saglayicisi O=Elektronik Bilgi Guvenligi A.S. # Subject: CN=e-Guven Kok Elektronik Sertifika Hizmet Saglayicisi O=Elektronik Bilgi Guvenligi A.S. # Label: "E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi" # Serial: 91184789765598910059173000485363494069 # MD5 Fingerprint: 3d:41:29:cb:1e:aa:11:74:cd:5d:b0:62:af:b0:43:5b # SHA1 Fingerprint: dd:e1:d2:a9:01:80:2e:1d:87:5e:84:b3:80:7e:4b:b1:fd:99:41:34 # SHA256 Fingerprint: e6:09:07:84:65:a4:19:78:0c:b6:ac:4c:1c:0b:fb:46:53:d9:d9:cc:6e:b3:94:6e:b7:f3:d6:99:97:ba:d5:98 -----BEGIN CERTIFICATE----- MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1 MQswCQYDVQQGEwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxp Z2kgQS5TLjE8MDoGA1UEAxMzZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZp a2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3MDEwNDExMzI0OFoXDTE3MDEwNDEx MzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0cm9uaWsgQmlsZ2kg R3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9uaWsg U2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdU MZTe1RK6UxYC6lhj71vY8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlT L/jDj/6z/P2douNffb7tC+Bg62nsM+3YjfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H 5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAIJjjcJRFHLfO6IxClv7wC 90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk9Ok0oSy1 c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/ BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoE VtstxNulMA0GCSqGSIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLP qk/CaOv/gKlR6D1id4k9CnU58W5dF4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S /wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwqD2fK/A+JYZ1lpTzlvBNbCNvj /+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4Vwpm+Vganf2X KWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX -----END CERTIFICATE----- # Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 # Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 # Label: "GlobalSign Root CA - R3" # Serial: 4835703278459759426209954 # MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 # SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad # SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH WD9f -----END CERTIFICATE----- # Issuer: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA # Subject: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA # Label: "TC TrustCenter Universal CA III" # Serial: 2010889993983507346460533407902964 # MD5 Fingerprint: 9f:dd:db:ab:ff:8e:ff:45:21:5f:f0:6c:9d:8f:fe:2b # SHA1 Fingerprint: 96:56:cd:7b:57:96:98:95:d0:e1:41:46:68:06:fb:b8:c6:11:06:87 # SHA256 Fingerprint: 30:9b:4a:87:f6:ca:56:c9:31:69:aa:a9:9c:6d:98:88:54:d7:89:2b:d5:43:7e:2d:07:b2:9c:be:da:55:d3:5d -----BEGIN CERTIFICATE----- MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF 5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI 4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== -----END CERTIFICATE----- # Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 # Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 # Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" # Serial: 6047274297262753887 # MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 # SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa # SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF 6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF 661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS 3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF 3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V -----END CERTIFICATE----- # Issuer: CN=Izenpe.com O=IZENPE S.A. # Subject: CN=Izenpe.com O=IZENPE S.A. # Label: "Izenpe.com" # Serial: 917563065490389241595536686991402621 # MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 # SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 # SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- # Issuer: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. # Subject: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. # Label: "Chambers of Commerce Root - 2008" # Serial: 11806822484801597146 # MD5 Fingerprint: 5e:80:9e:84:5a:0e:65:0b:17:02:f3:55:18:2a:3e:d7 # SHA1 Fingerprint: 78:6a:74:ac:76:ab:14:7f:9c:6a:30:50:ba:9e:a8:7e:fe:9a:ce:3c # SHA256 Fingerprint: 06:3e:4a:fa:c4:91:df:d3:32:f3:08:9b:85:42:e9:46:17:d8:93:d7:fe:94:4e:10:a7:93:7e:e2:9d:96:93:c0 -----BEGIN CERTIFICATE----- MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR 5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s +12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 +HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF 5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ d0jQ -----END CERTIFICATE----- # Issuer: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. # Subject: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. # Label: "Global Chambersign Root - 2008" # Serial: 14541511773111788494 # MD5 Fingerprint: 9e:80:ff:78:01:0c:2e:c1:36:bd:fe:96:90:6e:08:f3 # SHA1 Fingerprint: 4a:bd:ee:ec:95:0d:35:9c:89:ae:c7:52:a1:2c:5b:29:f6:d6:aa:0c # SHA256 Fingerprint: 13:63:35:43:93:34:a7:69:80:16:a0:d3:24:de:72:28:4e:07:9d:7b:52:20:bb:8f:bd:74:78:16:ee:be:ba:ca -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r 6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B -----END CERTIFICATE----- # Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. # Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. # Label: "Go Daddy Root Certificate Authority - G2" # Serial: 0 # MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 # SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b # SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH /PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu 9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo 2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI 4uJEvlz36hz1 -----END CERTIFICATE----- # Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. # Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. # Label: "Starfield Root Certificate Authority - G2" # Serial: 0 # MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 # SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e # SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg 8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- # Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. # Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. # Label: "Starfield Services Root Certificate Authority - G2" # Serial: 0 # MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 # SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f # SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk 6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn 0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN sSi6 -----END CERTIFICATE----- # Issuer: CN=AffirmTrust Commercial O=AffirmTrust # Subject: CN=AffirmTrust Commercial O=AffirmTrust # Label: "AffirmTrust Commercial" # Serial: 8608355977964138876 # MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 # SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 # SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- # Issuer: CN=AffirmTrust Networking O=AffirmTrust # Subject: CN=AffirmTrust Networking O=AffirmTrust # Label: "AffirmTrust Networking" # Serial: 8957382827206547757 # MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f # SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f # SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp 6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- # Issuer: CN=AffirmTrust Premium O=AffirmTrust # Subject: CN=AffirmTrust Premium O=AffirmTrust # Label: "AffirmTrust Premium" # Serial: 7893706540734352110 # MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 # SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 # SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ +jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S 5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B 8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc 0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e KeC2uAloGRwYQw== -----END CERTIFICATE----- # Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust # Subject: CN=AffirmTrust Premium ECC O=AffirmTrust # Label: "AffirmTrust Premium ECC" # Serial: 8401224907861490260 # MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d # SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb # SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D 0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== -----END CERTIFICATE----- # Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority # Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority # Label: "Certum Trusted Network CA" # Serial: 279744 # MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 # SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e # SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- # Issuer: CN=Certinomis - Autorité Racine O=Certinomis OU=0002 433998903 # Subject: CN=Certinomis - Autorité Racine O=Certinomis OU=0002 433998903 # Label: "Certinomis - Autorité Racine" # Serial: 1 # MD5 Fingerprint: 7f:30:78:8c:03:e3:ca:c9:0a:e2:c9:ea:1e:aa:55:1a # SHA1 Fingerprint: 2e:14:da:ec:28:f0:fa:1e:8e:38:9a:4e:ab:eb:26:c0:0a:d3:83:c3 # SHA256 Fingerprint: fc:bf:e2:88:62:06:f7:2b:27:59:3c:8b:07:02:97:e1:2d:76:9e:d1:0e:d7:93:07:05:a8:09:8e:ff:c1:4d:17 -----BEGIN CERTIFICATE----- MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4 Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0 aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N 8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K /OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu 7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC 28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6 lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB 0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09 5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q 619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn 2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG 5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0 BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5 -----END CERTIFICATE----- # Issuer: CN=Root CA Generalitat Valenciana O=Generalitat Valenciana OU=PKIGVA # Subject: CN=Root CA Generalitat Valenciana O=Generalitat Valenciana OU=PKIGVA # Label: "Root CA Generalitat Valenciana" # Serial: 994436456 # MD5 Fingerprint: 2c:8c:17:5e:b1:54:ab:93:17:b5:36:5a:db:d1:c6:f2 # SHA1 Fingerprint: a0:73:e5:c5:bd:43:61:0d:86:4c:21:13:0a:85:58:57:cc:9c:ea:46 # SHA256 Fingerprint: 8c:4e:df:d0:43:48:f3:22:96:9e:7e:29:a4:cd:4d:ca:00:46:55:06:1c:16:e1:b0:76:42:2e:f3:42:ad:63:0e -----BEGIN CERTIFICATE----- MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJF UzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJ R1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcN MDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3WjBoMQswCQYDVQQGEwJFUzEfMB0G A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScw JQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+ WmmmO3I2F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKj SgbwJ/BXufjpTjJ3Cj9BZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGl u6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQD0EbtFpKd71ng+CT516nDOeB0/RSrFOy A8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXteJajCq+TA81yc477OMUxk Hl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMBAAGjggM7 MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBr aS5ndmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIIC IwYKKwYBBAG/VQIBADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8A cgBpAGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIA YQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIAYQBsAGkAdABhAHQAIABWAGEA bABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQByAGEAYwBpAPMA bgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMA aQBvAG4AYQBtAGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQA ZQAgAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEA YwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBuAHQAcgBhACAAZQBuACAAbABhACAA ZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAAOgAvAC8AdwB3AHcA LgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0dHA6 Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+y eAT8MIGVBgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQsw CQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0G A1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVu Y2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRhTvW1yEICKrNcda3Fbcrn lD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdzCkj+IHLt b8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg 9J63NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XF ducTZnV+ZfsBn5OHiJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmC IoaZM3Fa6hlXPZHNqcCjbgcTpsnt+GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= -----END CERTIFICATE----- # Issuer: CN=A-Trust-nQual-03 O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH OU=A-Trust-nQual-03 # Subject: CN=A-Trust-nQual-03 O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH OU=A-Trust-nQual-03 # Label: "A-Trust-nQual-03" # Serial: 93214 # MD5 Fingerprint: 49:63:ae:27:f4:d5:95:3d:d8:db:24:86:b8:9c:07:53 # SHA1 Fingerprint: d3:c0:63:f2:19:ed:07:3e:34:ad:5d:75:0b:32:76:29:ff:d5:9a:f2 # SHA256 Fingerprint: 79:3c:bf:45:59:b9:fd:e3:8a:b2:2d:f1:68:69:f6:98:81:ae:14:c4:b0:13:9a:c7:88:a7:8a:1a:fc:ca:02:fb -----BEGIN CERTIFICATE----- MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJB VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5R dWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5RdWFsLTAzMB4XDTA1MDgxNzIyMDAw MFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgwRgYDVQQKDD9BLVRy dXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0ZW52 ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMM EEEtVHJ1c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCtPWFuA/OQO8BBC4SAzewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUj lUC5B3ilJfYKvUWG6Nm9wASOhURh73+nyfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZ znF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPESU7l0+m0iKsMrmKS1GWH 2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4iHQF63n1 k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs 2e3Vcuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYD VR0OBAoECERqlWdVeRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC AQEAVdRU0VlIXLOThaq/Yy/kgM40ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fG KOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmrsQd7TZjTXLDR8KdCoLXEjq/+ 8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZdJXDRZslo+S4R FGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmE DNuxUCAKGkq6ahq97BvIxYSazQ== -----END CERTIFICATE----- # Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA # Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA # Label: "TWCA Root Certification Authority" # Serial: 1 # MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 # SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 # SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx 3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- # Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 # Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 # Label: "Security Communication RootCA2" # Serial: 0 # MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 # SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 # SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy 1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- # Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority # Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority # Label: "Hellenic Academic and Research Institutions RootCA 2011" # Serial: 0 # MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9 # SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d # SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71 -----BEGIN CERTIFICATE----- MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD 75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp 5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p 6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI l7WdmplNsDz4SgCbZN2fOUvRJ9e4 -----END CERTIFICATE----- # Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 # Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 # Label: "Actalis Authentication Root CA" # Serial: 6271844772424770508 # MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 # SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac # SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX 4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ 51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- # Issuer: O=Trustis Limited OU=Trustis FPS Root CA # Subject: O=Trustis Limited OU=Trustis FPS Root CA # Label: "Trustis FPS Root CA" # Serial: 36053640375399034304724988975563710553 # MD5 Fingerprint: 30:c9:e7:1e:6b:e6:14:eb:65:b2:16:69:20:31:67:4d # SHA1 Fingerprint: 3b:c0:38:0b:33:c3:f6:a6:0c:86:15:22:93:d9:df:f5:4b:81:c0:04 # SHA256 Fingerprint: c1:b4:82:99:ab:a5:20:8f:e9:63:0a:ce:55:ca:68:a0:3e:da:5a:51:9c:88:02:a0:d3:a6:73:be:8f:8e:55:7d -----BEGIN CERTIFICATE----- MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA 0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN ZetX2fNXlrtIzYE= -----END CERTIFICATE----- # Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing # Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing # Label: "StartCom Certification Authority" # Serial: 45 # MD5 Fingerprint: c9:3b:0d:84:41:fc:a4:76:79:23:08:57:de:10:19:16 # SHA1 Fingerprint: a3:f1:33:3f:e2:42:bf:cf:c5:d1:4e:8f:39:42:98:40:68:10:d1:a0 # SHA256 Fingerprint: e1:78:90:ee:09:a3:fb:f4:f4:8b:9c:41:4a:17:d6:37:b7:a5:06:47:e9:bc:75:23:22:72:7f:cc:17:42:a9:11 -----BEGIN CERTIFICATE----- MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst 0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK 1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ 8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm fyWl8kgAwKQB2j8= -----END CERTIFICATE----- # Issuer: CN=StartCom Certification Authority G2 O=StartCom Ltd. # Subject: CN=StartCom Certification Authority G2 O=StartCom Ltd. # Label: "StartCom Certification Authority G2" # Serial: 59 # MD5 Fingerprint: 78:4b:fb:9e:64:82:0a:d3:b8:4c:62:f3:64:f2:90:64 # SHA1 Fingerprint: 31:f1:fd:68:22:63:20:ee:c6:3b:3f:9d:ea:4a:3e:53:7c:7c:39:17 # SHA256 Fingerprint: c7:ba:65:67:de:93:a7:98:ae:1f:aa:79:1e:71:2d:37:8f:ae:1f:93:c4:39:7f:ea:44:1b:b7:cb:e6:fd:59:95 -----BEGIN CERTIFICATE----- MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1 OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/ Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM 0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9 Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K 2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl 6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK 9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI -----END CERTIFICATE----- # Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 # Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 # Label: "Buypass Class 2 Root CA" # Serial: 2 # MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 # SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 # SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr 6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN 9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h 9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo +fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h 3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= -----END CERTIFICATE----- # Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 # Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 # Label: "Buypass Class 3 Root CA" # Serial: 2 # MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec # SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 # SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX 0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c /3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D 34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv 033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq 4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= -----END CERTIFICATE----- # Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center # Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center # Label: "T-TeleSec GlobalRoot Class 3" # Serial: 1 # MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef # SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 # SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN 8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ 1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT 91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p TpPDpFQUWw== -----END CERTIFICATE----- # Issuer: CN=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus # Subject: CN=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus # Label: "EE Certification Centre Root CA" # Serial: 112324828676200291871926431888494945866 # MD5 Fingerprint: 43:5e:88:d4:7d:1a:4a:7e:fd:84:2e:52:eb:01:d4:6f # SHA1 Fingerprint: c9:a8:b9:e7:55:80:5e:58:e3:53:77:a7:25:eb:af:c3:7b:27:cc:d7 # SHA256 Fingerprint: 3e:84:ba:43:42:90:85:16:e7:75:73:c0:99:2f:09:79:ca:08:4e:46:85:68:1f:f1:95:cc:ba:8a:22:9b:8a:76 -----BEGIN CERTIFICATE----- MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE 1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/osx.pem ================================================ -----BEGIN CERTIFICATE----- MIIDXTCCAkWgAwIBAgIDAOJCMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNVBAYTAkFU MRAwDgYDVQQKEwdBLVRydXN0MRkwFwYDVQQLExBBLVRydXN0LW5RdWFsLTAxMRkw FwYDVQQDExBBLVRydXN0LW5RdWFsLTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEz MDIzMDAwMFowVTELMAkGA1UEBhMCQVQxEDAOBgNVBAoTB0EtVHJ1c3QxGTAXBgNV BAsTEEEtVHJ1c3QtblF1YWwtMDExGTAXBgNVBAMTEEEtVHJ1c3QtblF1YWwtMDEw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD/9RyAEZ6eHmhYzNJ328f0 jmdSUFi6EqRqOxb3jHNPTIpK82CR6z5lmSnZQNUuCPD+htbNZffd2DKVB06NOyZ1 2zcOMCgj4GtkZoqE0zPpPT3bpoE55nkZZe/qWEX/64wz/L/4EdkvKDSKG/UsP75M tmCVY5m2Eg73RVFRz4ccBIMpHel4lzEqSkdDtZOY5fnkrE333hx67nxq21vY8Eyf 8O4fPQ5RtN8eohQCcPQ1z6ypU1R7N9jPRpnI+yzMOiwd3+QcKhHi1miCzo0pkOaB 1CwmfsTyNl8qU0NJUL9Ta6cea7WThwTiWol2yD88cd2cy388xpbNkfrCPmZNGLoV AgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECE5ZzscCMocwMA4G A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEA69I9R1hU9Gbl9vV7W7AH QpUJAlFAvv2It/eY8p2ouQUPVaSZikaKtAYrCD/arzfXB43Qet+dM6CpHsn8ikYR vQKePjXv3Evf+C1bxwJAimcnZV6W+bNOTpdo8lXljxkmfN+Z5S+XzvK2ttUtP4Et YOVaxHw2mPMNbvDeY+foJkiBn3KYjGabMaR8moZqof5ofj4iS/WyamTZti6v/fKx n1vII+/uWkcxV5DT5+r9HLon0NYF0Vg317Wh+gWDV59VZo+dcwJDb+keYqMFYoqp 77SGkZGu41S8NGYkQY3X9rNHRkDbLfpKYDmy6NanpOE1EHW1/sNSFAs43qZZKJEQ xg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJB VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5R dWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5RdWFsLTAzMB4XDTA1MDgxNzIyMDAw MFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgwRgYDVQQKDD9BLVRy dXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0ZW52 ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMM EEEtVHJ1c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCtPWFuA/OQO8BBC4SAzewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUj lUC5B3ilJfYKvUWG6Nm9wASOhURh73+nyfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZ znF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPESU7l0+m0iKsMrmKS1GWH 2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4iHQF63n1 k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs 2e3Vcuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYD VR0OBAoECERqlWdVeRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC AQEAVdRU0VlIXLOThaq/Yy/kgM40ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fG KOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmrsQd7TZjTXLDR8KdCoLXEjq/+ 8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZdJXDRZslo+S4R FGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmE DNuxUCAKGkq6ahq97BvIxYSazQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEUzCCAzugAwIBAgIDAOJDMA0GCSqGSIb3DQEBBQUAMIHPMQswCQYDVQQGEwJB VDGBizCBiAYDVQQKHoGAAEEALQBUAHIAdQBzAHQAIABHAGUAcwAuACAAZgD8AHIA IABTAGkAYwBoAGUAcgBoAGUAaQB0AHMAcwB5AHMAdABlAG0AZQAgAGkAbQAgAGUA bABlAGsAdAByAC4AIABEAGEAdABlAG4AdgBlAHIAawBlAGgAcgAgAEcAbQBiAEgx GDAWBgNVBAsTD0EtVHJ1c3QtUXVhbC0wMTEYMBYGA1UEAxMPQS1UcnVzdC1RdWFs LTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEzMDIzMDAwMFowgc8xCzAJBgNVBAYT AkFUMYGLMIGIBgNVBAoegYAAQQAtAFQAcgB1AHMAdAAgAEcAZQBzAC4AIABmAPwA cgAgAFMAaQBjAGgAZQByAGgAZQBpAHQAcwBzAHkAcwB0AGUAbQBlACAAaQBtACAA ZQBsAGUAawB0AHIALgAgAEQAYQB0AGUAbgB2AGUAcgBrAGUAaAByACAARwBtAGIA SDEYMBYGA1UECxMPQS1UcnVzdC1RdWFsLTAxMRgwFgYDVQQDEw9BLVRydXN0LVF1 YWwtMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmhgdxIbxTGEOH fXGiewI3NFldAWKFWfLofO+5I1UbvA5avt7IgsGXz/tI/f5HGUbascI0i7xG0tqV lA5ctQgLRqxgxHtgTkMcqsAEYdsz3LZsCdXO1QrvEBGLTSABdxiL/gSWJ6z77CSw x7Xg02HwxPV82cjGkSF3ENGJntuIAAnRDWn/ORHjFatNRymoMbHaOEZXSGhf7Y5F rrHEqGyi9E6sv784De/T1aTvskn8cWeUmDzv//omiG/a/V9KQex/61XN8OthUQVn X+u/liL2NKx74I2C/GgHX5B0WkPNqsSOgmlvJ/cKuT0PveUgVFDAA0oYBgcE1KDM lBbN0kmPAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECEs8jB2F 6W+tMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAIUusmJzMJRiQ 8TAHrJAOelfuWoTGcqdIv7Tys/fNl2yF2fjvHT8J01aKialFVpbVeQ2XKb1O2bHO QYAKgsdZ2jZ/sdL2UVFRTHmidLu6PdgWCBRhJYQELQophO9QVvfhAA0TwbESYqTz +nlI5Gr7CZe8f6HEmhJmCtUQsdQCufGglRh4T+tIGiNGcnyVEHZ93mSVepFr1VA2 9CTRPteuGjA81jeAz9peYiFE1CXvxK9cJiv0BcALFLWmADCoRLzIRZhA+sAwYUmw M1rqVCPA3kBQvIC95tyQvNy2dG0Vs+O6PwLaNX/suSlElQ06X2l1VwMaYb4vZKFq N0bOhBXEVg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDyzCCArOgAwIBAgIDAOJIMA0GCSqGSIb3DQEBBQUAMIGLMQswCQYDVQQGEwJB VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1 YWwtMDIxGDAWBgNVBAMMD0EtVHJ1c3QtUXVhbC0wMjAeFw0wNDEyMDIyMzAwMDBa Fw0xNDEyMDIyMzAwMDBaMIGLMQswCQYDVQQGEwJBVDFIMEYGA1UECgw/QS1UcnVz dCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy a2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1YWwtMDIxGDAWBgNVBAMMD0Et VHJ1c3QtUXVhbC0wMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJaR q9eOsFm4Ab20Hq2Z/aH86gyWa48uSUjY6eQkguHYuszr3gdcSMYZggFHQgnhfLmf ro/27l5rqKhWiDhWs+b+yZ1PNDhRPJy+86ycHMg9XJqErveULBSyZDdgjhSwOyrN ibUir/fkf+4sKzP5jjytTKJXD/uCxY4fAd9TjMEVpN3umpIS0ijpYhclYDHvzzGU 833z5Dwhq5D8bc9jp8YSAHFJ1xzIoO1jmn3jjyjdYPnY5harJtHQL73nDQnfbtTs 5ThT9GQLulrMgLU4WeyAWWWEMWpfVZFMJOUkmoOEer6A8e5fIAeqdxdsC+JVqpZ4 CAKel/Arrlj1gFA//jsCAwEAAaM2MDQwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4E CgQIQj0rJKbBRc4wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBG yxFjUA2bPkXUSC2SfJ29tmrbiLKal+g6a9M8Xwd+Ejo+oYkNP6F4GfeDtAXpm7xb 9Ly8lhdbHcpRhzCUQHJ1tBCiGdLgmhSx7TXjhhanKOdDgkdsC1T+++piuuYL72TD gUy2Sb1GHlJ1Nc6rvB4fpxSDAOHqGpUq9LWsc3tFkXqRqmQVtqtR77npKIFBioc6 2jTBwDMPX3hDJDR1DSPc6BnZliaNw2IHdiMQ0mBoYeRnFdq+TyDKsjmJOOQPLzzL /saaw6F891+gBjLFEFquDyR73lAPJS279R3csi8WWk4ZYUC/1V8H3Ktip/J6ac8e qhLCbmJ81Lo92JGHz/ot -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe 3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4 Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ 54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50 7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6 xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/ Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42 gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0 jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+ XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/ RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk BYn8eNZcLCZDqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX 4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ 51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC +Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X 7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz 43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV 6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH 1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF 62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh 4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G 87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i 2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no xqE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFVTCCBD2gAwIBAgIEO/OB0DANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJj aDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQDEw1BZG1pbi1Sb290LUNB MB4XDTAxMTExNTA4NTEwN1oXDTIxMTExMDA3NTEwN1owbDELMAkGA1UEBhMCY2gx DjAMBgNVBAoTBWFkbWluMREwDwYDVQQLEwhTZXJ2aWNlczEiMCAGA1UECxMZQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdGllczEWMBQGA1UEAxMNQWRtaW4tUm9vdC1DQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMvgr0QUIv5qF0nyXZ3PXAJi C4C5Wr+oVTN7oxIkXkxvO0GJToM9n7OVJjSmzBL0zJ2HXj0MDRcvhSY+KiZZc6Go vDvr5Ua481l7ILFeQAFtumeza+vvxeL5Nd0Maga2miiacLNAKXbAcUYRa0Ov5VZB ++YcOYNNt/aisWbJqA2y8He+NsEgJzK5zNdayvYXQTZN+7tVgWOck16Da3+4FXdy fH1NCWtZlebtMKtERtkVAaVbiWW24CjZKAiVfggjsiLo3yVMPGj3budLx5D9hEEm vlyDOtcjebca+AcZglppWMX/iHIrx7740y0zd6cWEqiLIcZCrnpkr/KzwO135GkC AwEAAaOCAf0wggH5MA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIASBkTCBjjCBiwYI YIV0AREDAQAwfzArBggrBgEFBQcCAjAfGh1UaGlzIGlzIHRoZSBBZG1pbi1Sb290 LUNBIENQUzBQBggrBgEFBQcCARZEaHR0cDovL3d3dy5pbmZvcm1hdGlrLmFkbWlu LmNoL1BLSS9saW5rcy9DUFNfMl8xNl83NTZfMV8xN18zXzFfMC5wZGYwfwYDVR0f BHgwdjB0oHKgcKRuMGwxFjAUBgNVBAMTDUFkbWluLVJvb3QtQ0ExIjAgBgNVBAsT GUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxETAPBgNVBAsTCFNlcnZpY2VzMQ4w DAYDVQQKEwVhZG1pbjELMAkGA1UEBhMCY2gwHQYDVR0OBBYEFIKf+iNzIPGXi7JM Tb5CxX9mzWToMIGZBgNVHSMEgZEwgY6AFIKf+iNzIPGXi7JMTb5CxX9mzWTooXCk bjBsMQswCQYDVQQGEwJjaDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZp Y2VzMSIwIAYDVQQLExlDZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQD Ew1BZG1pbi1Sb290LUNBggQ784HQMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B AQUFAAOCAQEAeE96XCYRpy6umkPKXDWCRn7INo96ZrWpMggcDORuofHIwdTkgOeM vWOxDN/yuT7CC3FAaUajbPRbDw0hRMcqKz0aC8CgwcyIyhw/rFK29mfNTG3EviP9 QSsEbnelFnjpm1wjz4EaBiFjatwpUbI6+Zv3XbEt9QQXBn+c6DeFLe4xvC4B+MTr a440xTk59pSYux8OHhEvqIwHCkiijGqZhTS3KmGFeBopaR+dJVBRBMoXwzk4B3Hn 0Zib1dEYFZa84vPJZyvxCbLOnPRDJgH6V2uQqbG+6DXVaf/wORVOvF/wzzv0viM/ RWbEtJZdvo8N3sdtCULzifnxP/V0T9+4ZQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIETTCCAzWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJDSDEO MAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0aWVzMRcwFQYDVQQDEw5BZG1pbkNBLUNELVQwMTAe Fw0wNjAxMjUxMzM2MTlaFw0xNjAxMjUxMjM2MTlaMG0xCzAJBgNVBAYTAkNIMQ4w DAYDVQQKEwVhZG1pbjERMA8GA1UECxMIU2VydmljZXMxIjAgBgNVBAsTGUNlcnRp ZmljYXRpb24gQXV0aG9yaXRpZXMxFzAVBgNVBAMTDkFkbWluQ0EtQ0QtVDAxMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0jQlMZmpLDhV+GNR9TAoSNle JgQB4xAXJELQf5/ySMfoFA4MmjKqYXQkB6MGPuQKwR9XRRSPf61vqb8YPsdjRmgp byHBcUd5t0N8RX6wRZUnPMW+bCCo2VqAU4XFbnlc2gHKaam0wdTtbBTXEkv0ieIH fxCfFxXqSsSr60IkF/2/xbrAgV/QD5yHk6Ie8feAVWwi5UtaFqtu4LiFEh2QMyxs Oyz1OcvKzkM2g873tyiE7jzMgZP+Ww3tibk2F9+e6ZeiB37TLOmVtvgpmrws4fiI rFNXEYSWBVrUTbn81U47yWzOgf5fEHP07bRV5QOCzCm99qNimsbL6CG7nT78CQID AQABo4H3MIH0MBIGA1UdEwEB/wQIMAYBAf8CAQAwga4GA1UdIASBpjCBozCBoAYI YIV0AREDFQEwgZMwSAYIKwYBBQUHAgIwPBo6VGhpcyBpcyB0aGUgQWRtaW5DQS1D RC1UMDEgQ2VydGlmaWNhdGUgUHJhY3RpY2UgU3RhdGVtZW50LjBHBggrBgEFBQcC ARY7aHR0cDovL3d3dy5wa2kuYWRtaW4uY2gvcG9saWN5L0NQU18yXzE2Xzc1Nl8x XzE3XzNfMjFfMS5wZGYwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQqxGkKocZV xgNucM6GgbOkD6oZ2zANBgkqhkiG9w0BAQUFAAOCAQEAn356bbusjI5glGXRQ1DR v21qQf0S4s3GHyZm7cqdOkFleM70ArBT+kOP5Nm7rlSAFyVgEkmBdOg7s9tlXClU yeZFnp6UEYRUcijPN8D1VaNRK6PIUObpDBQT0C+kAfxG9z4v29T0SxT4sgAdC/xQ Fyv58Fp9bPn7owuKwKcyCH1XSyi/Bp4XFELlLOaigBZO/w+dPBz4FcJSdZjU+BaJ 0E3nKAjHlShO5ouBSZnaJz3p+nkw2Wyo36s6GxCK0XbkSP45iniIG4FmwwZkonYF ypQntHbx2oL7tUQQY0PDo8bGBMcPy/G2j+dciqZRlsnfgMy10SCzQ9MUx92xUG2V eg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp 6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ +jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S 5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B 8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc 0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e KeC2uAloGRwYQw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D 0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2 MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym 1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb 2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2 MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC 206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2 JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9 BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67 Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3 +L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2 LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8 CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw RY8mkaKO/qk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAwMFoXDTM3MTEyMDE1 MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U 0pPlLYnKhHw/EEMbjIt8hFj4JHxIzyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItI TuLCxFlpMGK2MKKMCxGZYTVtfu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAf RC+iYkGzuxgh28pxPIzstrkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqF zQ6axOAAsNUl6twr5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqh BC4aMqiaILGcLCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEA AaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jY PXy+XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/ BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNMeUWn 9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7CegCgTXT Ct8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77BfWgDrvq2g+EQF Z7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oTLW4jYYehY0KswsuX n2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCzvhGbRWeDhhmH05i9CBoW H1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmwX7A5KGgOc90lmt4S -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAwMFoXDTM3MDkyODIz NDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ 7ouZzU9AhqS2TcnZsdw8TQ2FTBVsRotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilb m2BPJoPRYxJWSXakFsKlnUWsi4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOY xFSMFkpBd4aVdQxHAWZg/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZ YYCLqJV+FNwSbKTQ2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbq JS5Gr42whTg0ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fx I2rSAG2X+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETz kxmlJ85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNoKk/S Btc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJKg71ZDIM gtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1ExMVCgyhwn2RAu rda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaAFE9pbQN+nZ8HGEO8txBO 1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAO/Ouyugu h4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0cnAxa8cZmIDJgt43d15Ui47y6mdP yXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRFASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q 7C+qPBR7V8F+GBRn7iTGvboVsNIYvbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKT RuidDV29rs4prWPVVRaAMCf/drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ ClTluUI8JPu3B5wwn3la5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyB M5kYJRF3p+v9WAksmWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQ my8YJPamTQr5O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xO AU++CrYD062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT 9Y41xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOLZ8/5 fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0 MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+ +FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1 XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3 R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93 d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0 YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7 R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX UKqK1drk/NAJBzewdXUh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIIAeDltYNno+AwDQYJKoZIhvcNAQEMBQAwZzEbMBkGA1UE AwwSQXBwbGUgUm9vdCBDQSAtIEcyMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMw HhcNMTQwNDMwMTgxMDA5WhcNMzkwNDMwMTgxMDA5WjBnMRswGQYDVQQDDBJBcHBs ZSBSb290IENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgREkhI2imKScUcx+xuM23+TfvgHN6s XuI2pyT5f1BrTM65MFQn5bPW7SXmMLYFN14UIhHF6Kob0vuy0gmVOKTvKkmMXT5x ZgM4+xb1hYjkWpIMBDLyyED7Ul+f9sDx47pFoFDVEovy3d6RhiPw9bZyLgHaC/Yu OQhfGaFjQQscp5TBhsRTL3b2CtcM0YM/GlMZ81fVJ3/8E7j4ko380yhDPLVoACVd J2LT3VXdRCCQgzWTxb+4Gftr49wIQuavbfqeQMpOhYV4SbHXw8EwOTKrfl+q04tv ny0aIWhwZ7Oj8ZhBbZF8+NfbqOdfIRqMM78xdLe40fTgIvS/cjTf94FNcX1RoeKz 8NMoFnNvzcytN31O661A4T+B/fc9Cj6i8b0xlilZ3MIZgIxbdMYs0xBTJh0UT8TU gWY8h2czJxQI6bR3hDRSj4n4aJgXv8O7qhOTH11UL6jHfPsNFL4VPSQ08prcdUFm IrQB1guvkJ4M6mL4m1k8COKWNORj3rw31OsMiANDC1CvoDTdUE0V+1ok2Az6DGOe HwOx4e7hqkP0ZmUoNwIx7wHHHtHMn23KVDpA287PT0aLSmWaasZobNfMmRtHsHLD d4/E92GcdB/O/WuhwpyUgquUoue9G7q5cDmVF8Up8zlYNPXEpMZ7YLlmQ1A/bmH8 DvmGqmAMQ0uVAgMBAAGjQjBAMB0GA1UdDgQWBBTEmRNsGAPCe8CjoA1/coB6HHcm jTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwF AAOCAgEAUabz4vS4PZO/Lc4Pu1vhVRROTtHlznldgX/+tvCHM/jvlOV+3Gp5pxy+ 8JS3ptEwnMgNCnWefZKVfhidfsJxaXwU6s+DDuQUQp50DhDNqxq6EWGBeNjxtUVA eKuowM77fWM3aPbn+6/Gw0vsHzYmE1SGlHKy6gLti23kDKaQwFd1z4xCfVzmMX3z ybKSaUYOiPjjLUKyOKimGY3xn83uamW8GrAlvacp/fQ+onVJv57byfenHmOZ4VxG /5IFjPoeIPmGlFYl5bRXOJ3riGQUIUkhOb9iZqmxospvPyFgxYnURTbImHy99v6Z SYA7LNKmp4gDBDEZt7Y6YUX6yfIjyGNzv1aJMbDZfGKnexWoiIqrOEDCzBL/FePw N983csvMmOa/orz6JopxVtfnJBtIRD6e/J/JzBrsQzwBvDR4yGn1xuZW7AYJNpDr FEobXsmII9oDMJELuDY++ee1KG++P+w8j2Ud5cAeh6Squpj9kuNsJnfdBrRkBof0 Tta6SqoWqPQFZ2aWuuJVecMsXUmPgEkrihLHdoBR37q9ZV0+N0djMenl9MU/S60E inpxLK8JQzcPqOMyT/RFtm2XNuyE9QoB6he7hY1Ck3DDUOUUi78/w0EP3SIEIwiK um1xRKtzCTrJ+VKACd+66eYWyi4uTLLT3OUEVLLUNIAytbwPF+E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwS QXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcN MTQwNDMwMTgxOTA2WhcNMzkwNDMwMTgxOTA2WjBnMRswGQYDVQQDDBJBcHBsZSBS b290IENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9y aXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzB2MBAGByqGSM49 AgEGBSuBBAAiA2IABJjpLz1AcqTtkyJygRMc3RCV8cWjTnHcFBbZDuWmBSp3ZHtf TjjTuxxEtX/1H7YyYl3J6YRbTzBPEVoA/VhYDKX1DyxNB0cTddqXl5dvMVztK517 IDvYuVTZXpmkOlEKMaNCMEAwHQYDVR0OBBYEFLuw3qFYM4iapIqZ3r6966/ayySr MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gA MGUCMQCD6cHEFl4aXTQY2e3v9GwOAEZLuN+yRhHFD/3meoyhpmvOwgPUnPWTxnS4 at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM 6BgD56KyKA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFujCCBKKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhjELMAkGA1UEBhMCVVMx HTAbBgNVBAoTFEFwcGxlIENvbXB1dGVyLCBJbmMuMS0wKwYDVQQLEyRBcHBsZSBD b21wdXRlciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIEFwcGxlIFJv b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA1MDIxMDAwMTgxNFoXDTI1MDIx MDAwMTgxNFowgYYxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBcHBsZSBDb21wdXRl ciwgSW5jLjEtMCsGA1UECxMkQXBwbGUgQ29tcHV0ZXIgQ2VydGlmaWNhdGUgQXV0 aG9yaXR5MSkwJwYDVQQDEyBBcHBsZSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOSRqQkfkdseR1DrBe1e eYQt6zaiV0xV7IsZid75S2z1B6siMALoGD74UAnTf0GomPnRymacJGsR0KO75Bsq wx+VnnoMpEeLW9QWNzPLxA9NzhRp0ckZcvVdDtV/X5vyJQO6VY9NXQ3xZDUjFUsV WR2zlPf2nJ7PULrBWFBnjwi0IPfLrCwgb3C2PwEwjLdDzw+dPfMrSSgayP7OtbkO 2V4c1ss9tTqt9A8OAJILsSEWLnTVPA3bYharo3GSR1NVwa8vQbP4++NwzeajTEV+ H0xrUJZBicR0YgsQg0GHM4qBsTBY7FoEMoxos48d3mVz/2deZbxJ2HafMxRloXeU yS0CAwEAAaOCAi8wggIrMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ MB0GA1UdDgQWBBQr0GlHlHYJ/vRrjS5ApvdHTX8IXjAfBgNVHSMEGDAWgBQr0GlH lHYJ/vRrjS5ApvdHTX8IXjCCASkGA1UdIASCASAwggEcMIIBGAYJKoZIhvdjZAUB MIIBCTBBBggrBgEFBQcCARY1aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmlj YXRlYXV0aG9yaXR5L3Rlcm1zLmh0bWwwgcMGCCsGAQUFBwICMIG2GoGzUmVsaWFu Y2Ugb24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2Nl cHRhbmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5k IGNvbmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRp ZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wRAYDVR0fBD0wOzA5oDegNYYz aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L3Jvb3Qu Y3JsMFUGCCsGAQUFBwEBBEkwRzBFBggrBgEFBQcwAoY5aHR0cHM6Ly93d3cuYXBw bGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L2Nhc2lnbmVycy5odG1sMA0GCSqG SIb3DQEBBQUAA4IBAQCd2i0oWC99dgS5BNM+zrdmY06PL9T+S61yvaM5xlJNBZhS 9YlRASR5vhoy9+VEi0tEBzmC1lrKtCBe2a4VXR2MHTK/ODFiSF3H4ZCx+CRA+F9Y m1FdV53B5f88zHIhbsTp6aF31ywXJsM/65roCwO66bNKcuszCVut5mIxauivL9Wv Hld2j383LS4CXN1jyfJxuCZA3xWNdUQ/eb3mHZnhQyw+rW++uaT+DjUZUWOxw961 kj5ReAFziqQjyqSI8R5cH0EWLX6VCqrpiUGYGxrdyyC/R14MJsVVNU3GMIuZZxTH CR+6R8faAQmHJEKVvRNgGQrv6n8Obs3BREM6StXj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJKUDEO MAwGA1UEChMFTEdQS0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMB4XDTA2 MDMzMTE1MDAwMFoXDTE2MDMzMTE0NTk1OVowOTELMAkGA1UEBhMCSlAxDjAMBgNV BAoTBUxHUEtJMRowGAYDVQQLExFBcHBsaWNhdGlvbiBDQSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALk1xhD422jbB8RATLAdHjbcw0H2z1UVbQh/ XMZoVeXnV/GWUebhTXgPbkAVcDtl/hHf59PWWDU74Z8C/JRSRi6znmCbAp7JgtL2 464JT4REtmKbAFFouDqt7GTRMkvplESDtA7OIYlrsDbAmMZLnMI+W2AqCTErLatM 3rGg/VhWwoMdILzEhAmHe6iVl8YljoPgPpMN0cd9c6mo/BkAQC4iuHozQfV4/Vpx 54LZSIhc7KiFhy1tgIlnGmm+EMBaju2IfT5vLDhrN85H2KIxMN5+U2Vsi4ZTQSBs vUilfq8AWlYSWIHR3IlZ+bXu+E2a2EQpi3mn9yKq6nxctBaIIA0CAwEAAaOBsjCB rzAdBgNVHQ4EFgQUf7hdjsQYa8Z9zC7prs405xdd4KEwDgYDVR0PAQH/BAQDAgEG MEwGA1UdHwRFMEMwQaA/oD2kOzA5MQswCQYDVQQGEwJKUDEOMAwGA1UEChMFTEdQ S0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMA8GA1UdEwEB/wQFMAMBAf8w HwYDVR0jBBgwFoAUf7hdjsQYa8Z9zC7prs405xdd4KEwDQYJKoZIhvcNAQEFBQAD ggEBADzYczZABkhKVBn1J0g5JaVuQue2zRvLOTS3m+xPKr535MqE/B3rmyJA1fT7 aIdy/Eddag5SSuO1XUjGIpbmM21tq/bN18skWoyoRZ4+YYJ9lNUF8Bo1X3EvLlS1 QQXvhg1S75yYG/EsTDrR84bTjD56L4ZFjoMyJlu/U8oOUVbcmsJaMBkNp57Vqpsg OWl4IfSXbdEOEUwu0xtasPmXeFwqj1Jl7kxCJcI3MA5tKzWUgwbor0U7BGanMLv5 4CE7Y259RF06alPvERck/VSyWmxzViHJbC2XpEKzJ2EFIWNt6ii8TxpvQtyYq1XT HhvAkj+bweY7F1bixJhDJe62ywA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55 IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm /qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+ eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL rosot4LKGAfmt1t06SAZf7IbiVQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgILMTI1MzcyODI4MjgwDQYJKoZIhvcNAQELBQAwWDELMAkG A1UEBhMCSlAxHDAaBgNVBAoTE0phcGFuZXNlIEdvdmVybm1lbnQxDTALBgNVBAsT BEdQS0kxHDAaBgNVBAMTE0FwcGxpY2F0aW9uQ0EyIFJvb3QwHhcNMTMwMzEyMTUw MDAwWhcNMzMwMzEyMTUwMDAwWjBYMQswCQYDVQQGEwJKUDEcMBoGA1UEChMTSmFw YW5lc2UgR292ZXJubWVudDENMAsGA1UECxMER1BLSTEcMBoGA1UEAxMTQXBwbGlj YXRpb25DQTIgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKaq rSVl1gAR1uh6dqr05rRL88zDUrSNrKZPtZJxb0a11a2LEiIXJc5F6BR6hZrkIxCo +rFnUOVtR+BqiRPjrq418fRCxQX3TZd+PCj8sCaRHoweOBqW3FhEl2LjMsjRFUFN dZh4vqtoqV7tR76kuo6hApfek3SZbWe0BSXulMjtqqS6MmxCEeu+yxcGkOGThchk KM4fR8fAXWDudjbcMztR63vPctgPeKgZggiQPhqYjY60zxU2pm7dt+JNQCBT2XYq 0HisifBPizJtROouurCp64ndt295D6uBbrjmiykLWa+2SQ1RLKn9nShjZrhwlXOa 2Po7M7xCQhsyrLEy+z0CAwEAAaOBwTCBvjAdBgNVHQ4EFgQUVqesqgIdsqw9kA6g by5Bxnbne9owDgYDVR0PAQH/BAQDAgEGMHwGA1UdEQR1MHOkcTBvMQswCQYDVQQG EwJKUDEYMBYGA1UECgwP5pel5pys5Zu95pS/5bqcMRswGQYDVQQLDBLmlL/lupzo qo3oqLzln7rnm6QxKTAnBgNVBAMMIOOCouODl+ODquOCseODvOOCt+ODp+ODs0NB MiBSb290MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH+aCXWs B9FydC53VzDCBJzUgKaD56WgG5/+q/OAvdVKo6GPtkxgEefK4WCB10jBIFmlYTKL nZ6X02aD2mUuWD7b5S+lzYxzplG+WCigeVxpL0PfY7KJR8q73rk0EWOgDiUX5Yf0 HbCwpc9BqHTG6FPVQvSCLVMJEWgmcZR1E02qdog8dLHW40xPYsNJTE5t8XB+w3+m Bcx4m+mB26jIx1ye/JKSLaaX8ji1bnOVDMA/zqaUMLX6BbfeniCq/BNkyYq6ZO/i Y+TYmK5rtT6mVbgzPixy+ywRAPtbFi+E0hOe+gXFwctyTiLdhMpLvNIthhoEdlkf SUJiOxMfFui61/0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF 6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF 661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS 3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF 3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIJmzCCB4OgAwIBAgIBATANBgkqhkiG9w0BAQwFADCCAR4xPjA8BgNVBAMTNUF1 dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s YW5vMQswCQYDVQQGEwJWRTEQMA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlz dHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0 aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBlcmludGVuZGVuY2lh IGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUwIwYJ KoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyMjE4MDgy MVoXDTMwMTIxNzIzNTk1OVowggEeMT4wPAYDVQQDEzVBdXRvcmlkYWQgZGUgQ2Vy dGlmaWNhY2lvbiBSYWl6IGRlbCBFc3RhZG8gVmVuZXpvbGFubzELMAkGA1UEBhMC VkUxEDAOBgNVBAcTB0NhcmFjYXMxGTAXBgNVBAgTEERpc3RyaXRvIENhcGl0YWwx NjA0BgNVBAoTLVNpc3RlbWEgTmFjaW9uYWwgZGUgQ2VydGlmaWNhY2lvbiBFbGVj dHJvbmljYTFDMEEGA1UECxM6U3VwZXJpbnRlbmRlbmNpYSBkZSBTZXJ2aWNpb3Mg ZGUgQ2VydGlmaWNhY2lvbiBFbGVjdHJvbmljYTElMCMGCSqGSIb3DQEJARYWYWNy YWl6QHN1c2NlcnRlLmdvYi52ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBAME77xNS8ZlW47RsBeEaaRZhJoZ4rw785UAFCuPZOAVMqNS1wMYqzy95q6Gk UO81ER/ugiQX/KMcq/4HBn83fwdYWxPZfwBfK7BP2p/JsFgzYeFP0BXOLmvoJIzl Jb6FW+1MPwGBjuaZGFImWZsSmGUclb51mRYMZETh9/J5CLThR1exStxHQptwSzra zNFpkQY/zmj7+YZNA9yDoroVFv6sybYOZ7OxNDo7zkSLo45I7gMwtxqWZ8VkJZkC 8+p0dX6mkhUT0QAV64Zc9HsZiH/oLhEkXjhrgZ28cF73MXIqLx1fyM4kPH1yOJi/ R72nMwL7D+Sd6mZgI035TxuHXc2/uOwXfKrrTjaJDz8Jp6DdessOkxIgkKXRjP+F K3ze3n4NUIRGhGRtyvEjK95/2g02t6PeYiYVGur6ruS49n0RAaSS0/LJb6XzaAAe 0mmO2evnEqxIKwy2mZRNPfAVW1l3wCnWiUwryBU6OsbFcFFrQm+00wOicXvOTHBM aiCVAVZTb9RSLyi+LJ1llzJZO3pq3IRiiBj38Nooo+2ZNbMEciSgmig7YXaUcmud SVQvLSL+Yw+SqawyezwZuASbp7d/0rutQ59d81zlbMt3J7yB567rT2IqIydQ8qBW k+fmXzghX+/FidYsh/aK+zZ7Wy68kKHuzEw1Vqkat5DGs+VzAgMBAAGjggLeMIIC 2jASBgNVHRMBAf8ECDAGAQH/AgECMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52 ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMB0GA1UdDgQWBBStuyIdxuDS Aaj9dlBSk+2YwU2u0zCCAVAGA1UdIwSCAUcwggFDgBStuyIdxuDSAaj9dlBSk+2Y wU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRpZmlj YWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAw DgYDVQQHEwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYD VQQKEy1TaXN0ZW1hIE5hY2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25p Y2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5kZW5jaWEgZGUgU2VydmljaW9zIGRlIENl cnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG9w0BCQEWFmFjcmFpekBz dXNjZXJ0ZS5nb2IudmWCAQEwDgYDVR0PAQH/BAQDAgEGMDcGA1UdEQQwMC6CD3N1 c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMFQGA1Ud HwRNMEswJKAioCCGHmhodHA6Ly93d3cuc3VzY2VydGUuZ29iLnZlL2xjcjAjoCGg H4YdbGRhcDovL2FjcmFpei5zdXNjZXJ0ZS5nb2IudmUwNwYIKwYBBQUHAQEEKzAp MCcGCCsGAQUFBzABhhtoaHRwOi8vb2NzcC5zdXNjZXJ0ZS5nb2IudmUwQAYDVR0g BDkwNzA1BgVghl4BAjAsMCoGCCsGAQUFBwIBFh5odHRwOi8vd3d3LnN1c2NlcnRl LmdvYi52ZS9kcGMwDQYJKoZIhvcNAQEMBQADggIBAK4qy/zmZ9zBwfW3yOYtLcBT Oy4szJyPz7/RhNH3bPVH7HbDTGpi6JZ4YXdXMBeJE5qBF4a590Kgj8Rlnltt+Rbo OFQOU1UDqKuTdBsA//Zry5899fmn8jBUkg4nh09jhHHbLlaUScdz704Zz2+UVg7i s/r3Legxap60KzmdrmTAE9VKte1TQRgavQwVX5/2mO/J+SCas//UngI+h8SyOucq mjudYEgBrZaodUsagUfn/+AzFNrGLy+al+5nZeHb8JnCfLHWS0M9ZyhgoeO/czyn 99+5G93VWNv4zfc4KiavHZKrkn8F9pg0ycIZh+OwPT/RE2zq4gTazBMlP3ACIe/p olkNaOEa8KvgzW96sjBZpMW49zFmyINYkcj+uaNCJrVGsXgdBmkuRGJNWFZ9r0cG woIaxViFBypsz045r1ESfYPlfDOavBhZ/giR/Xocm9CHkPRY2BApMMR0DUCyGETg Ql+L3kfdTKzuDjUp2DM9FqysQmaM81YDZufWkMhlZPfHwC7KbNougoLroa5Umeos bqAXWmk46SwIdWRPLLqbUpDTKooynZKpSYIkkotdgJoVZUUCY+RCO8jsVPEU6ece SxztNUm5UOta1OJPMwSAKRHOo3ilVb9c6lAixDdvV8MeNbqe6asM1mpCHWbJ/0rg 5Ls9Cxx8hracyp0ev7b0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIIKv++n6Lw6YcwDQYJKoZIhvcNAQEFBQAwKDELMAkGA1UE BhMCQkUxGTAXBgNVBAMTEEJlbGdpdW0gUm9vdCBDQTIwHhcNMDcxMDA0MTAwMDAw WhcNMjExMjE1MDgwMDAwWjAoMQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1 bSBSb290IENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZzQh6S /3UPi790hqc/7bIYLS2X+an7mEoj39WN4IzGMhwWLQdC1i22bi+n9fzGhYJdld61 IgDMqFNAn68KNaJ6x+HK92AQZw6nUHMXU5WfIp8MXW+2QbyM69odRr2nlL/zGsvU +40OHjPIltfsjFPekx40HopQcSZYtF3CiInaYNKJIT/e1wEYNm7hLHADBGXvmAYr XR5i3FVr/mZkIV/4L+HXmymvb82fqgxG0YjFnaKVn6w/Fa7yYd/vw2uaItgscf1Y HewApDgglVrH1Tdjuk+bqv5WRi5j2Qsj1Yr6tSPwiRuhFA0m2kHwOI8w7QUmecFL TqG4flVSOmlGhHUCAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4CQEBMC4wLAYIKwYBBQUHAgEWIGh0dHA6 Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSFiuv0xbu+DlkD lN7WgAEV4xCcOTARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUhYrr9MW7 vg5ZA5Te1oABFeMQnDkwDQYJKoZIhvcNAQEFBQADggEBAFHYhd27V2/MoGy1oyCc UwnzSgEMdL8rs5qauhjyC4isHLMzr87lEwEnkoRYmhC598wUkmt0FoqW6FHvv/pK JaeJtmMrXZRY0c8RcrYeuTlBFk0pvDVTC9rejg7NqZV3JcqUWumyaa7YwBO+mPyW nIR/VRPmPIfjvCCkpDZoa01gZhz5v6yAlGYuuUGK02XThIAC71AdXkbc98m6tTR8 KvPG2F9fVJ3bTc0R5/0UAoNmXsimABKgX77OFP67H6dh96tK8QYUn8pJQsKpvO2F sauBQeYNxUJpU4c5nUwfAA4+Bw11V0SoU7Q2dmSZ3G7rPUZuFF1eR1ONeE3gJ7uO hXY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg Q2xhc3MgMiBDQSAxMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzEL MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD VQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7McXA0 ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLX l18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVB HfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B 5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3 WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLP gcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+ DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKu BctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHs h7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+oRxKaJyOk LY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr 6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN 9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h 9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo +fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h 3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI +MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+ mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2 mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX 0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c /3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D 34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv 033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq 4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzET MBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UE AxMIQ0EgRGlzaWcwHhcNMDYwMzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQsw CQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcg YS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgmGErE Nx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnX mjxUizkDPw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYD XcDtab86wYqg6I7ZuUUohwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhW S8+2rT+MitcE5eN4TPWGqvWP+j1scaMtymfraHtuM6kMgiioTGohQBUgDCZbg8Kp FhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8wgfwwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0PAQH/BAQD AgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cu ZGlzaWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5z ay9jYS9jcmwvY2FfZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2sv Y2EvY3JsL2NhX2Rpc2lnLmNybDAaBgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEw DQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59tWDYcPQuBDRIrRhCA/ec8J9B6 yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3mkkp7M5+cTxq EEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeB EicTXxChds6KezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFN PGO+I++MzVpQuGhU+QqZMxEA4Z7CRneC9VkGjCFMhwnN5ag= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQy MDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjEw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy3QRk D2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/o OI7bm+V8u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3A fQ+lekLZWnDZv6fXARz2m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJe IgpFy4QxTaz+29FHuvlglzmxZcfe+5nkCiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8n oc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTaYVKvJrT1cU/J19IG32PK /yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6vpmumwKj rckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD 3AjLLhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE 7cderVC6xkGbrPAXZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkC yC2fg69naQanMVXVz0tv/wQFx1isXxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLd qvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ04IwDQYJKoZI hvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaA SfX8MPWbTx9BLxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXo HqJPYNcHKfyyo6SdbhWSVhlMCrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpB emOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5GfbVSUZP/3oNn6z4eGBrxEWi1CXYBmC AMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85YmLLW1AL14FABZyb 7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKSds+x DzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvk F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka +elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q 130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG 9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4 Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0 aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N 8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K /OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu 7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC 28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6 lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB 0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09 5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q 619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn 2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG 5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0 BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb 5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ 0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ 8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do 0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ 44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN 9u6wWk5JRFRYX0KD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs 6GAqm4VKQPNriiTsBhYscw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0zCCA7ugAwIBAgIVALhZFHE/V9+PMcAzPdLWGXojF7TrMA0GCSqGSIb3DQEB DQUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dp ZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBIDIwHhcNMTExMDA2 MDgzOTU2WhcNNDYxMDA2MDgzOTU2WjCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoT GVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0 d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvfl4+ObV gAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC5SBLm9qbe7mZXdmbgEvXhEAr J9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Vaqp3cKcniNQfrcE1K1sGzVrih QTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ0WeNG0a+RzDVLnLRxWPa52N5 RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet/5oCl8HGUJKbAiy9qbk0WQq/ hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNeGWJoRVfkkIJCu0LW8GHgwaM9 ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcVWiNoidQ+3k4nsPBADLxNF8tN orMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbls+V1e9dBkQXcXWnjlQ1DufyD ljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZbMI28iQzV13D4h1L92u+sUS4H s07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+NqcnoYsylfzGuXIkosagpZ6w7xQ EmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbljnX98sy50IdbzAYQYLuDNbde Z95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUtqFUOQLDoD+Oirz61PgcptE6Dv0wDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBDQUAA4ICAQCdU8KBJdw1LK4K3VqbRjBWu9S0bEuG5gql 0pKKmo3cj7TudvQDy+ubAXirKmu1uiNOMXy1LN0taWczbmNdORgS+KAoU0SHq2rE kpYfKqIcup3dJ/tSTbCPWujtjcNo45KgJgyHkLAD6mplKAjERnjgW7oO8DPcJ7Z+ iD29kqSWfkGogAh71jYSvBAVmyS8q619EYkvMe340s9Tjuu0U6fnBMovpiLEEdzr mMkiXUFq3ApSBFu8LqB9x7aSuySg8zfRK0OozPFoeBp+b2OQe590yGvZC1X2eQM9 g8dBQJL7dgs3JRc8rz76PFwbhvlKDD+KxF4OmPGt7s/g/SE1xzNhzKI3GEN8M+mu doKCB0VIO8lnbq2jheiWVs+8u/qry7dXJ40aL5nzIzM0jspTY9NXNFBPz0nBBbrF qId744aP+0OiEumsUewEdkzw+o+5MRPpCLckCfmgtwc2WFfPxLt+SWaVNQS2dzW4 qVMpX5KF+FLEWk79BmE5+33QdkeSzOwrvYRu5ptFwX1isVMtnnWg58koUNflvKiq B3hquXS0YPOEjQPcrpHadEQNe0Kpd9YrfKHGbBNTIqkSmqX5TyhFNbCXT0ZlhcX0 /WKiomr8NDAGft8M4HOBlslEKt4fguxscletKWSk8cYpjjVgU85r2QK+OTB14Pdc Y2rwQMEsjQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq 7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p 26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi 1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu tGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR 5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s +12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 +HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF 5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ d0jQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC Q04xMjAwBgNVBAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24g Q2VudGVyMUcwRQYDVQQDDD5DaGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0 aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMgUm9vdDAeFw0xMDA4MzEwNzExMjVa Fw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAGA1UECgwpQ2hpbmEg SW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMMPkNo aW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRp ZmljYXRlcyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z 7r07eKpkQ0H1UN+U8i6yjUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA// DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV98YPjUesWgbdYavi7NifFy2cyjw1l1Vx zUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2HklY0bBoQCxfVWhyXWIQ8 hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23KzhmBsUs 4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54u gQEC7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oY NJKiyoOCWTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E FgQUfHJLOcfA22KlT5uqGDSSosqDglkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3 j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd50XPFtQO3WKwMVC/GVhMPMdoG 52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM7+czV0I664zB echNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrI zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy wy39FCqQmbkHzJ8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDQzCCAiugAwIBAgIQX/h7KCtU3I1CoxW1aMmt/zANBgkqhkiG9w0BAQUFADA1 MRYwFAYDVQQKEw1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENB IDIwNDgwHhcNMDQwNTE0MjAxNzEyWhcNMjkwNTE0MjAyNTQyWjA1MRYwFAYDVQQK Ew1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENBIDIwNDgwggEg MA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQCwmrmrp68Kd6ficba0ZmKUeIhH xmJVhEAyv8CrLqUccda8bnuoqrpu0hWISEWdovyD0My5jOAmaHBKeN8hF570YQXJ FcjPFto1YYmUQ6iEqDGYeJu5Tm8sUxJszR2tKyS7McQr/4NEb7Y9JHcJ6r8qqB9q VvYgDxFUl4F1pyXOWWqCZe+36ufijXWLbvLdT6ZeYpzPEApk0E5tzivMW/VgpSdH jWn0f84bcN5wGyDWbs2mAag8EtKpP6BrXruOIIt6keO1aO6g58QBdKhTCytKmg9l Eg6CTY5j/e/rmxrbU6YTYK/CfdfHbBcl1HP7R2RQgYCUTOG/rksc35LtLgXfAgED o1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJ/PI FR5umgIJFq0roIlgX9p7L6owEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEF BQADggEBAJ2dhISjQal8dwy3U8pORFBi71R803UXHOjgxkhLtv5MOhmBVrBW7hmW Yqpao2TB9k5UM8Z3/sUcuuVdJcr18JOagxEu5sv4dEX+5wW4q+ffy0vhN4TauYuX cB7w4ovXsNgOnbFp1iqRe6lJT37mjpXYgyc81WhJDtSd9i7rp77rMKSsH0T8lasz Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4 CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR 4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5 FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx lA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0f zGVuDLDQVoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHi TkVWaR94AoDa3EeRKbs2yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0G CSqGSIb3DQEBBQUAA4GBAFgVKTk8d6PaXCUDfGD67gmZPCcQcMgMCeazh88K4hiW NWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n0a3hUKw8fGJLj7qE1xIV Gx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZRjXZ+Hxb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68 DzFc6PLZ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 l7+ijrRU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCEAq6HgBiMui0NiZdH3zNiWYwDQYJKoZIhvcNAQEFBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G CSqGSIb3DQEBBQUAA4GBAIDToA+IyeVoW4R7gB+nt+MjWBEc9RTwWBKMi99x2ZAk EXyge8N6GRm9cr0gvwA63/rVeszC42JFi8tJg5jBcGnQnl6CjDVHjk8btB9jAa3k ltax7nosZm4XNq8afjgGhixrTcsnkm54vwDVAcCxB8MJqmSFKPKdc57PYDoKHUpI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn jBJ7xUS0rg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i 2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ 2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY oJ2daZH9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP T8qAkbYp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2 MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6 dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO 76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj 2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgIQKTZHquOKrIZKI1byyrdhrzANBgkqhkiG9w0BAQUFADBO MQswCQYDVQQGEwJ1czEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQ0wCwYDVQQL EwRGQkNBMRYwFAYDVQQDEw1Db21tb24gUG9saWN5MB4XDTA3MTAxNTE1NTgwMFoX DTI3MTAxNTE2MDgwMFowTjELMAkGA1UEBhMCdXMxGDAWBgNVBAoTD1UuUy4gR292 ZXJubWVudDENMAsGA1UECxMERkJDQTEWMBQGA1UEAxMNQ29tbW9uIFBvbGljeTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJeNvTMn5K1b+3i9L0dHbsd4 6ZOcpN7JHP0vGzk4rEcXwH53KQA7Ax9oD81Npe53uCxiazH2+nIJfTApBnznfKM9 hBiKHa4skqgf6F5PjY7rPxr4nApnnbBnTfAu0DDew5SwoM8uCjR/VAnTNr2kSVdS c+md/uRIeUYbW40y5KVIZPMiDZKdCBW/YDyD90ciJSKtKXG3d+8XyaK2lF7IMJCk FEhcVlcLQUwF1CpMP64Sm1kRdXAHImktLNMxzJJ+zM2kfpRHqpwJCPZLr1LoakCR xVW9QLHIbVeGlRfmH3O+Ry4+i0wXubklHKVSFzYIWcBCvgortFZRPBtVyYyQd+sC AwEAAaN7MHkwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFC9Yl9ipBZilVh/72at17wI8NjTHMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJ KwYBBAGCNxUCBBYEFHa3YJbdFFYprHWF03BjwbxHhhyLMA0GCSqGSIb3DQEBBQUA A4IBAQBgrvNIFkBypgiIybxHLCRLXaCRc+1leJDwZ5B6pb8KrbYq+Zln34PFdx80 CTj5fp5B4Ehg/uKqXYeI6oj9XEWyyWrafaStsU+/HA2fHprA1RRzOCuKeEBuMPdi 4c2Z/FFpZ2wR3bgQo2jeJqVW/TZsN5hs++58PGxrcD/3SDcJjwtCga1GRrgLgwb0 Gzigf0/NC++DiYeXHIowZ9z9VKEDfgHLhUyxCynDvux84T8PCVI8L6eaSP436REG WOE2QYrEtr+O3c5Ks7wawM36GpnScZv6z7zyxFSjiDV2zBssRm8MtNHDYXaSdBHq S4CNHIkRi+xb/xfJSPzn4AYR4oRe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI 2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp +2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW /zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB ZQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0 MRMwEQYDVQQDEwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQG EwJJTDAeFw0wNDAzMjQxMTMyMThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMT CkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNpZ24xCzAJBgNVBAYTAklMMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49qROR+WCf4C9DklBKK 8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTyP2Q2 98CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb 2CEJKHxNGGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxC ejVb7Us6eva1jsz/D3zkYDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7Kpi Xd3DTKaCQeQzC6zJMw9kglcq/QytNuEMrkvF7zuZ2SOzW120V+x0cAwqTwIDAQAB o4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2Zl ZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0PAQH/BAQD AgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRL AZs+VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWd foPPbrxHbvUanlR2QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0M cXS6hMTXcpuEfDhOZAYnKuGntewImbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq 8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb/627HOkthIDYIb6FUtnUdLlp hbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VGzT2ouvDzuFYk Res3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U AGegcQCCSA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGATCCA+mgAwIBAgIRAI9hcRW6eVgXjH0ROqzW264wDQYJKoZIhvcNAQELBQAw RTEfMB0GA1UEAxMWQ29tU2lnbiBHbG9iYWwgUm9vdCBDQTEVMBMGA1UEChMMQ29t U2lnbiBMdGQuMQswCQYDVQQGEwJJTDAeFw0xMTA3MTgxMDI0NTRaFw0zNjA3MTYx MDI0NTVaMEUxHzAdBgNVBAMTFkNvbVNpZ24gR2xvYmFsIFJvb3QgQ0ExFTATBgNV BAoTDENvbVNpZ24gTHRkLjELMAkGA1UEBhMCSUwwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCyKClzKh3rm6n1nvigmV/VU1D4hSwYW2ro3VqpzpPo0Ph3 3LguqjXd5juDwN4mpxTpD99d7Xu5X6KGTlMVtfN+bTbA4t3x7DU0Zqn0BE5XuOgs 3GLH41Vmr5wox1bShVpM+IsjcN4E/hMnDtt/Bkb5s33xCG+ohz5dlq0gA9qfr/g4 O9lkHZXTCeYrmVzd/il4x79CqNvGkdL3um+OKYl8rg1dPtD8UsytMaDgBAopKR+W igc16QJzCbvcinlETlrzP/Ny76BWPnAQgaYBULax/Q5thVU+N3sEOKp6uviTdD+X O6i96gARU4H0xxPFI75PK/YdHrHjfjQevXl4J37FJfPMSHAbgPBhHC+qn/014DOx 46fEGXcdw2BFeIIIwbj2GH70VyJWmuk/xLMCHHpJ/nIF8w25BQtkPpkwESL6esaU b1CyB4Vgjyf16/0nRiCAKAyC/DY/Yh+rDWtXK8c6QkXD2XamrVJo43DVNFqGZzbf 5bsUXqiVDOz71AxqqK+p4ek9374xPNMJ2rB5MLPAPycwI0bUuLHhLy6nAIFHLhut TNI+6Y/soYpi5JSaEjcY7pxI8WIkUAzr2r+6UoT0vAdyOt7nt1y8844a7szo/aKf woziHl2O1w6ZXUC30K+ptXVaOiW79pBDcbLZ9ZdbONhS7Ea3iH4HJNwktrBJLQID AQABo4HrMIHoMA8GA1UdEwEB/wQFMAMBAf8wgYQGA1UdHwR9MHswPKA6oDiGNmh0 dHA6Ly9mZWRpci5jb21zaWduLmNvLmlsL2NybC9jb21zaWduZ2xvYmFscm9vdGNh LmNybDA7oDmgN4Y1aHR0cDovL2NybDEuY29tc2lnbi5jby5pbC9jcmwvY29tc2ln bmdsb2JhbHJvb3RjYS5jcmwwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBQCRZPY DUhirGm6rgZbPvuqJpFQsTAfBgNVHSMEGDAWgBQCRZPYDUhirGm6rgZbPvuqJpFQ sTANBgkqhkiG9w0BAQsFAAOCAgEAk1V5V9701xsfy4mfX+tP9Ln5e9h3N+QMwUfj kr+k3e8iXOqADjTpUHeBkEee5tJq09ZLp/43F5tZ2eHdYq2ZEX7iWHCnOQet6Yw9 SU1TahsrGDA6JJD9sdPFnNZooGsU1520e0zNB0dNWwxrWAmu4RsBxvEpWCJbvzQL dOfyX85RWwli81OiVMBc5XvJ1mxsIIqli45oRynKtsWP7E+b0ISJ1n+XFLdQo/Nm WA/5sDfT0F5YPzWdZymudMbXitimxC+n4oQE4mbQ4Zm718Iwg3pP9gMMcSc7Qc1J kJHPH9O7gVubkKHuSYj9T3Ym6c6egL1pb4pz/uT7cT26Fiopc/jdqbe2EAfoJZkv hlp/zdzOoXTWjiKNA5zmgWnZn943FuE9KMRyKtyi/ezJXCh8ypnqLIKxeFfZl69C BwJsPXUTuqj8Fic0s3aZmmr7C4jXycP+Q8V+akMEIoHAxcd960b4wVWKqOcI/kZS Q0cYqWOY1LNjznRt9lweWEfwDBL3FhrHOmD4++1N3FkkM4W+Q1b2WOL24clDMj+i 2n9Iw0lc1llHMSMvA5D0vpsXZpOgcCVahfXczQKi9wQ3oZyonJeWx4/rXdMtagAB VBYGFuMEUEQtybI+eIbnp5peO2WAAblQI4eTy/jMVowe5tfMEXovV3sz9ULgmGb3 DscLP1I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu MQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwx GzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjEL MAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGtWhf HZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs49oh gHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sW v+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ue Mv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr 9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt 6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7 MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNl Y3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58 ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkq hkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7p iL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtC dsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAmlaxMDPWL kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp /hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y Johw1+qRzT65ysCQblrGXnRl11z+o+I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp 3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl 6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEBDCCAuygAwIBAgIIGHqpqMKWIQwwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEy MDIwMTIyMTIxNVoXDTI3MDIwMTIyMTIxNVoweTEtMCsGA1UEAwwkRGV2ZWxvcGVy IElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQLDB1BcHBsZSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UE BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJdk8GW5pB7qUj KwKjX9dzP8A1sIuECj8GJH+nlT/rTw6Tr7QO0Mg+5W0Ysx/oiUe/1wkI5P9WmCkV 55SduTWjCs20wOHiYPTK7Cl4RWlpYGtfipL8niPmOsIiszFPHLrytjRZQu6wqQID GJEEtrN4LjMfgEUNRW+7Dlpbfzrn2AjXCw4ybfuGNuRsq8QRinCEJqqfRNHxuMZ7 lBebSPcLWBa6I8WfFTl+yl3DMl8P4FJ/QOq+rAhklVvJGpzlgMofakQcbD7EsCYf Hex7r16gaj1HqVgSMT8gdihtHRywwk4RaSaLy9bQEYLJTg/xVnTQ2QhLZniiq6yn 4tJMh1nJAgMBAAGjgaYwgaMwHQYDVR0OBBYEFFcX7aLP3HyYoRDg/L6HLSzy4xdU MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/ CF4wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5j cmwwDgYDVR0PAQH/BAQDAgGGMBAGCiqGSIb3Y2QGAgYEAgUAMA0GCSqGSIb3DQEB CwUAA4IBAQBCOXRrodzGpI83KoyzHQpEvJUsf7xZuKxh+weQkjK51L87wVA5akR0 ouxbH3Dlqt1LbBwjcS1f0cWTvu6binBlgp0W4xoQF4ktqM39DHhYSQwofzPuAHob tHastrW7T9+oG53IGZdKC1ZnL8I+trPEgzrwd210xC4jUe6apQNvYPSlSKcGwrta 4h8fRkV+5Jf1JxC3ICJyb3LaxlB1xT0lj12jAOmfNoxIOY+zO+qQgC6VmmD0eM70 DgpTPqL6T9geroSVjTK8Vk2J6XgY4KyaQrp6RhuEoonOFOiI0ViL9q5WxCwFKkWv C9lLqQIPNKyIx2FViUTJJ3MH7oLlTvVw -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I 0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv 6pZjamVFkpUBtA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI 2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx 1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV 5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY 1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 sycX -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t 9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd +SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N 0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie 4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 /YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICZzCCAdCgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEY MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT A1BLSTEcMBoGA1UEAxMTRG9EIENMQVNTIDMgUm9vdCBDQTAeFw0wMDA1MTkxMzEz MDBaFw0yMDA1MTQxMzEzMDBaMGExCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMu IEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRwwGgYDVQQD ExNEb0QgQ0xBU1MgMyBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB gQC1MP5kvurMbe2BLPd/6Rm6DmlqKOGpqcuVWB/x5pppU+CIP5HFUbljl6jmIYwT XjY8qFf6+HAsTGrLvzCnTBbkMlz4ErBR+BZXjS+0TfouqJToKmHUVw1Hzm4sL36Y Z8wACKu2lhY1woWR5VugCsdmUmLzYXWVF668KlYppeArUwIDAQABoy8wLTAdBgNV HQ4EFgQUbJyl8FyPbUGNxBc7kFfCD6PNbf4wDAYDVR0TBAUwAwEB/zANBgkqhkiG 9w0BAQUFAAOBgQCvcUT5lyPMaGmMQwdBuoggsyIAQciYoFUczT9usZNcrfoYmrsc c2/9JEKPh59Rz76Gn+nXikhPCNlplKw/5g8tlw8ok3ZPYt//oM1h+KaGDDE0INx/ L6j7Ob6V7jhZAmLB3mwVT+DfnbvkeXMk/WNklfdKqJkfSGWVx3u/eDLneg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJVUzEY MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMjAeFw0wNDEyMTMxNTAwMTBaFw0y OTEyMDUxNTAwMTBaMFsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRYwFAYDVQQDEw1Eb0Qg Um9vdCBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCzB9o07 rP8/PNZxvrh0IgfscEEV/KtA4weqwcPYn/7aTDq/P8jYKHtLNgHArEUlw9IOCo+F GGQQPRoTcCpvjtfcjZOzQQ84Ic2tq8I9KgXTVxE3Dc2MUfmT48xGSSGOFLTNyxQ+ OM1yMe6rEvJl6jQuVl3/7mN1y226kTT8nvP0LRy+UMRC31mI/2qz+qhsPctWcXEF lrufgOWARVlnQbDrw61gpIB1BhecDvRD4JkOG/t/9bPMsoGCsf0ywbi+QaRktWA6 WlEwjM7eQSwZR1xJEGS5dKmHQa99brrBuKG/ZTE6BGf5tbuOkooAY7ix5ow4X4P/ UNU7ol1rshDMYwIDAQABoz8wPTAdBgNVHQ4EFgQUSXS7DF66ev4CVO97oMaVxgmA cJYwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBAJiRjT+JyLv1wGlzKTs1rLqzCHY9cAmS6YREIQF9FHYb7lFsHY0VNy17MWn0 mkS4r0bMNPojywMnGdKDIXUr5+AbmSbchECV6KjSzPZYXGbvP0qXEIIdugqi3VsG K52nZE7rLgE1pLQ/E61V5NVzqGmbEfGY8jEeb0DU+HifjpGgb3AEkGaqBivO4XqS tX3h4NGW56E6LcyxnR8FRO2HmdNNGnA5wQQM5X7Z8a/XIA7xInolpHOZzD+kByeW qKKV7YK5FtOeC4fCwfKI9WLfaN/HvGlR7bFc3FRUKQ8JOZqsA8HbDE2ubwp6Fknx v5HSOJTT9pUst2zJQraNypCNhdk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDOzCCAiOgAwIBAgIRANAeRlAAACmMAAAAAgAAAAIwDQYJKoZIhvcNAQEFBQAw PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD Ew5EU1QgUm9vdCBDQSBYNDAeFw0wMDA5MTMwNjIyNTBaFw0yMDA5MTMwNjIyNTBa MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEXMBUGA1UE AxMORFNUIFJvb3QgQ0EgWDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCthX3OFEYY8gSeIYur0O4ypOT68HnDrjLfIutL5PZHRwQGjzCPb9PFo/ihboJ8 RvfGhBAqpQCo47zwYEhpWm1jB+L/OE/dBBiyn98krfU2NiBKSom2J58RBeAwHGEy cO+lewyjVvbDDLUy4CheY059vfMjPAftCRXjqSZIolQb9FdPcAoa90mFwB7rKniE J7vppdrUScSS0+eBrHSUPLdvwyn4RGp+lSwbWYcbg5EpSpE0GRJdchic0YDjvIoC YHpe7Rkj93PYRTQyU4bhC88ck8tMqbvRYqMRqR+vobbkrj5LLCOQCHV5WEoxWh+0 E2SpIFe7RkV++MmpIAc0h1tZAgMBAAGjMjAwMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFPCD6nPIP1ubWzdf9UyPWvf0hki9MA0GCSqGSIb3DQEBBQUAA4IBAQCE G85wl5eEWd7adH6XW/ikGN5salvpq/Fix6yVTzE6CrhlP5LBdkf6kx1bSPL18M45 g0rw2zA/MWOhJ3+S6U+BE0zPGCuu8YQaZibR7snm3HiHUaZNMu5c8D0x0bcMxDjY AVVcHCoNiL53Q4PLW27nbY6wwG0ffFKmgV3blxrYWfuUDgGpyPwHwkfVFvz9qjaV mf12VJffL6W8omBPtgteb6UaT/k1oJ7YI0ldGf+ngpVbRhD+LC3cUtT6GO/BEPZu 8YTV/hbiDH5v3khVqMIeKT6o8IuXGG7F6a6vKwP1F1FwTXf4UC/ivhme7vdUH7B/ Vv4AEbT8dNfEeFxrkDbh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c 77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 +GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNV BAMML0VCRyBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMTcwNQYDVQQKDC5FQkcgQmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXpt ZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAeFw0wNjA4MTcwMDIxMDlaFw0xNjA4 MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25payBTZXJ0aWZpa2Eg SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2ltIFRl a25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h 4fuXd7hxlugTlkaDT7byX3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAk tiHq6yOU/im/+4mRDGSaBUorzAzu8T2bgmmkTPiab+ci2hC6X5L8GCcKqKpE+i4s tPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfreYteIAbTdgtsApWjluTL dlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZTqNGFav4 c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8Um TDGyY5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z +kI2sSXFCjEmN1ZnuqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0O Lna9XvNRiYuoP1Vzv9s6xiQFlpJIqkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMW OeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vmExH8nYQKE3vwO9D8owrXieqW fo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0Nokb+Clsi7n2 l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB /wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgw FoAU587GT/wWZ5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+ 8ygjdsZs93/mQJ7ANtyVDR2tFcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI 6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgmzJNSroIBk5DKd8pNSe/iWtkqvTDO TLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64kXPBfrAowzIpAoHME wfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqTbCmY Iai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJn xk1Gj7sURT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4Q DgZxGhBM/nV+/x5XOULK1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9q Kd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11t hie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQY9iJSrSq3RZj9W6+YKH4 7ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9AahH3eU7 QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICmDCCAgGgAwIBAgIBDjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJVUzEY MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNFQ0ExFDASBgNVBAMT C0VDQSBSb290IENBMB4XDTA0MDYxNDEwMjAwOVoXDTQwMDYxNDEwMjAwOVowSzEL MAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMD RUNBMRQwEgYDVQQDEwtFQ0EgUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEArkr2eXIS6oAKIpDkOlcQZdMGdncoygCEIU+ktqY3of5SVVXU7/it7kJ1 EUzR4ii2vthQtbww9aAnpQxcEmXZk8eEyiGEPy+cCQMllBY+efOtKgjbQNDZ3lB9 19qzUJwBl2BMxslU1XsJQw9SK10lPbQm4asa8E8e5zTUknZBWnECAwEAAaOBizCB iDAfBgNVHSMEGDAWgBT2uAQnDlYW2blj2f2hVGVBoAhILzAdBgNVHQ4EFgQU9rgE Jw5WFtm5Y9n9oVRlQaAISC8wDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB Af8wJQYDVR0gBB4wHDAMBgpghkgBZQMCAQwBMAwGCmCGSAFlAwIBDAIwDQYJKoZI hvcNAQEFBQADgYEAHh0EQY2cZ209aBb5q0wW1ER0dc4OGzsLyqjHfaQ4TEaMmUwL AJRta/c4KVWLiwbODsvgJk+CaWmSL03gRW/ciVb/qDV7qh9Pyd1cOlanZTAnPog2 i82yL3i2fK9DCC84uoxEQbgqK2jx9bIjFTwlAqITk9fGAm5mdT84IEwq1Gw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5zCCA8+gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCQ0Ex EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoTFEVj aG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNlcnZp Y2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMjAeFw0wNTEwMDYxMDQ5MTNa Fw0zMDEwMDcxMDQ5MTNaMIGNMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJp bzEQMA4GA1UEBxMHVG9yb250bzEdMBsGA1UEChMURWNob3dvcnggQ29ycG9yYXRp b24xHzAdBgNVBAsTFkNlcnRpZmljYXRpb24gU2VydmljZXMxGjAYBgNVBAMTEUVj aG93b3J4IFJvb3QgQ0EyMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA utU/5BkV15UBf+s+JQruKQxr77s3rjp/RpOtmhHILIiO5gsEWP8MMrfrVEiidjI6 Qh6ans0KAWc2Dw0/j4qKAQzOSyAZgjcdypNTBZ7muv212DA2Pu41rXqwMrlBrVi/ KTghfdLlNRu6JrC5y8HarrnRFSKF1Thbzz921kLDRoCi+FVs5eVuK5LvIfkhNAqA byrTgO3T9zfZgk8upmEkANPDL1+8y7dGPB/d6lk0I5mv8PESKX02TlvwgRSIiTHR k8++iOPLBWlGp7ZfqTEXkPUZhgrQQvxcrwCUo6mk8TqgxCDP5FgPoHFiPLef5szP ZLBJDWp7GLyE1PmkQI6WiwIBA6OCAVAwggFMMA8GA1UdEwEB/wQFMAMBAf8wCwYD VR0PBAQDAgEGMB0GA1UdDgQWBBQ74YEboKs/OyGC1eISrq5QqxSlEzCBugYDVR0j BIGyMIGvgBQ74YEboKs/OyGC1eISrq5QqxSlE6GBk6SBkDCBjTELMAkGA1UEBhMC Q0ExEDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoT FEVjaG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMoIBADBQBgNVHSAESTBH MEUGCysGAQQB+REKAQMBMDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuZWNob3dv cnguY29tL2NhL3Jvb3QyL2Nwcy5wZGYwDQYJKoZIhvcNAQEFBQADggEBAG+nrPi/ 0RpfEzrj02C6JGPUar4nbjIhcY6N7DWNeqBoUulBSIH/PYGNHYx7/lnJefiixPGE 7TQ5xPgElxb9bK8zoAApO7U33OubqZ7M7DlHnFeCoOoIAZnG1kuwKwD5CXKB2a74 HzcqNnFW0IsBFCYqrVh/rQgJOzDA8POGbH0DeD0xjwBBooAolkKT+7ZItJF1Pb56 QpDL9G+16F7GkmnKlAIYT3QTS3yFGYChnJcd+6txUPhKi9sSOOmAIaKHnkH9Scz+ A2cSi4A3wUYXVatuVNHpRb2lygfH3SuCX9MU8Ure3zBlSU1LALtMqI4JmcQmQpIq zIzvO2jHyu9PQqo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE 1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi 94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP 9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m 0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v 1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH 4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy vUxFnmG6v4SBkgPR0ml8xQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH 4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er fF6adulZkMV8gzURZVE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN 95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd 2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS /jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D hNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN /Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0 NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/ BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy 0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1 E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc 58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv 8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYDCCA0igAwIBAgICATAwDQYJKoZIhvcNAQELBQAwWTELMAkGA1UEBhMCVVMx GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UE AxMYRmVkZXJhbCBDb21tb24gUG9saWN5IENBMB4XDTEwMTIwMTE2NDUyN1oXDTMw MTIwMTE2NDUyN1owWTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu bWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UEAxMYRmVkZXJhbCBDb21tb24gUG9s aWN5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2HX7NRY0WkG/ Wq9cMAQUHK14RLXqJup1YcfNNnn4fNi9KVFmWSHjeavUeL6wLbCh1bI1FiPQzB6+ Duir3MPJ1hLXp3JoGDG4FyKyPn66CG3G/dFYLGmgA/Aqo/Y/ISU937cyxY4nsyOl 4FKzXZbpsLjFxZ+7xaBugkC7xScFNknWJidpDDSPzyd6KgqjQV+NHQOGgxXgVcHF mCye7Bpy3EjBPvmE0oSCwRvDdDa3ucc2Mnr4MrbQNq4iGDGMUHMhnv6DOzCIJOPp wX7e7ZjHH5IQip9bYi+dpLzVhW86/clTpyBLqtsgqyFOHQ1O5piF5asRR12dP8Qj wOMUBm7+nQIDAQABo4IBMDCCASwwDwYDVR0TAQH/BAUwAwEB/zCB6QYIKwYBBQUH AQsEgdwwgdkwPwYIKwYBBQUHMAWGM2h0dHA6Ly9odHRwLmZwa2kuZ292L2ZjcGNh L2NhQ2VydHNJc3N1ZWRCeWZjcGNhLnA3YzCBlQYIKwYBBQUHMAWGgYhsZGFwOi8v bGRhcC5mcGtpLmdvdi9jbj1GZWRlcmFsJTIwQ29tbW9uJTIwUG9saWN5JTIwQ0Es b3U9RlBLSSxvPVUuUy4lMjBHb3Zlcm5tZW50LGM9VVM/Y0FDZXJ0aWZpY2F0ZTti aW5hcnksY3Jvc3NDZXJ0aWZpY2F0ZVBhaXI7YmluYXJ5MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUrQx6dVzl85jEeZgOrCj9l/TnAvwwDQYJKoZIhvcNAQELBQAD ggEBAI9z2uF/gLGH9uwsz9GEYx728Yi3mvIRte9UrYpuGDco71wb5O9Qt2wmGCMi TR0mRyDpCZzicGJxqxHPkYnos/UqoEfAFMtOQsHdDA4b8Idb7OV316rgVNdF9IU+ 7LQd3nyKf1tNnJaK0KIyn9psMQz4pO9+c+iR3Ah6cFqgr2KBWfgAdKLI3VTKQVZH venAT+0g3eOlCd+uKML80cgX2BLHb94u6b2akfI8WpQukSKAiaGMWMyDeiYZdQKl Dn0KJnNR6obLB6jI/WNaNZvSr79PMUjBhHDbNXuaGQ/lj/RqDG8z2esccKIN47lQ A2EC/0rskqTcLe4qNJMHtyznGI8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU 1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV 5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl 4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz rD6ogRLQy7rQkgu2npaqBA+K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz +uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn 5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G spki4cErx5z481+oghLrGREt -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r 6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH WD9f -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs ewv4n4Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc 8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg 515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO xwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG 3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO 291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h /t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf ReYNnyicsbkqWletNw+vHX/bvZ8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH /PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu 9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo 2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI 4uJEvlz36hz1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFSzCCAzOgAwIBAgIRALZLiAfiI+7IXBKtpg4GofIwDQYJKoZIhvcNAQELBQAw PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTAeFw0xMjA5MjgwODU4NTFaFw0zNzEyMzExNTU5NTla MD8xCzAJBgNVBAYTAlRXMTAwLgYDVQQKDCdHb3Zlcm5tZW50IFJvb3QgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQC2/5c8gb4BWCQnr44BK9ZykjAyG1+bfNTUf+ihYHMwVxAA+lCWJP5Q5ow6ldFX eYTVZ1MMKoI+GFy4MCYa1l7GLbIEUQ7v3wxjR+vEEghRK5lxXtVpe+FdyXcdIOxW juVhYC386RyA3/pqg7sFtR4jEpyCygrzFB0g5AaPQySZn7YKk1pzGxY5vgW28Yyl ZJKPBeRcdvc5w88tvQ7Yy6gOMZvJRg9nU0MEj8iyyIOAX7ryD6uBNaIgIZfOD4k0 eA/PH07p+4woPN405+2f0mb1xcoxeNLOUNFggmOd4Ez3B66DNJ1JSUPUfr0t4urH cWWACOQ2nnlwCjyHKenkkpTqBpIpJ3jmrdc96QoLXvTg1oadLXLLi2RW5vSueKWg OTNYPNyoj420ai39iHPplVBzBN8RiD5C1gJ0+yzEb7xs1uCAb9GGpTJXA9ZN9E4K mSJ2fkpAgvjJ5E7LUy3Hsbbi08J1J265DnGyNPy/HE7CPfg26QrMWJqhGIZO4uGq s3NZbl6dtMIIr69c/aQCb/+4DbvVq9dunxpPkUDwH0ZVbaCSw4nNt7H/HLPLo5wK 4/7NqrwB7N1UypHdTxOHpPaY7/1J1lcqPKZc9mA3v9g+fk5oKiMyOr5u5CI9ByTP isubXVGzMNJxbc5Gim18SjNE2hIvNkvy6fFRCW3bapcOFwIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBTVZx3gnHosnMvFmOcdByYqhux0zTAOBgNV HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAJA75cJTQijq9TFOjj2Rnk0J 89ixUuZPrAwxIbvx6pnMg/y2KOTshAcOD06Xu29oRo8OURWV+Do7H1+CDgxxDryR T64zLiNB9CZrTxOH+nj2LsIPkQWXqmrBap+8hJ4IKifd2ocXhuGzyl3tOKkpboTe Rmv8JxlQpRJ6jH1i/NrnzLyfSa8GuCcn8on3Fj0Y5r3e9YwSkZ/jBI3+BxQaWqw5 ghvxOBnhY+OvbLamURfr+kvriyL2l/4QOl+UoEtTcT9a4RD4co+WgN2NApgAYT2N vC2xR8zaXeEgp4wxXPHj2rkKhkfIoT0Hozymc26Uke1uJDr5yTDRB6iBfSZ9fYTf hsmL5a4NHr6JSFEVg5iWL0rrczTXdM3Jb9DCuiv2mv6Z3WAUjhv5nDk8f0OJU+jl wqu+Iq0nOJt3KLejY2OngeepaUXrjnhWzAWEx/uttjB8YwWfLYwkf0uLkvw4Hp+g pVezbp3YZLhwmmBScMip0P/GnO0QYV7Ngw5u6E0CQUridgR51lQ/ipgyFKDdLZzn uoJxo4ZVKZnSKdt1OvfbQ/+2W/u3fjWAjg1srnm3Ni2XUqGwB5wH5Ss2zQOXlL0t DjQG/MAWifw3VOTWzz0TBPKR2ck2Lj7FWtClTILD/y58Jnb38/1FoqVuVa4uzM8s iTTa9g3nkagQ6hed8vbs -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD 75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp 5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p 6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI l7WdmplNsDz4SgCbZN2fOUvRJ9e4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi AmvZWg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+ TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0 LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs 2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFHjCCBAagAwIBAgIEAKA3oDANBgkqhkiG9w0BAQsFADCBtzELMAkGA1UEBhMC Q1oxOjA4BgNVBAMMMUkuQ0EgLSBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHksIDA5LzIwMDkxLTArBgNVBAoMJFBydm7DrSBjZXJ0aWZpa2HEjW7DrSBh dXRvcml0YSwgYS5zLjE9MDsGA1UECww0SS5DQSAtIEFjY3JlZGl0ZWQgUHJvdmlk ZXIgb2YgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlczAeFw0wOTA5MDEwMDAwMDBaFw0x OTA5MDEwMDAwMDBaMIG3MQswCQYDVQQGEwJDWjE6MDgGA1UEAwwxSS5DQSAtIFF1 YWxpZmllZCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSwgMDkvMjAwOTEtMCsGA1UE CgwkUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRhLCBhLnMuMT0wOwYDVQQL DDRJLkNBIC0gQWNjcmVkaXRlZCBQcm92aWRlciBvZiBDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtTaEy0KC8M9l 4lSaWHMs4+sVV1LwzyJYiIQNeCrv1HHm/YpGIdY/Z640ceankjQvIX7m23BK4OSC 6KO8kZYA3zopOz6GFCOKV2PvLukbc+c2imF6kLHEv6qNA8WxhPbR3xKwlHDwB2yh Wzo7V3QVgDRG83sugqQntKYC3LnlTGbJpNP+Az72gpO9AHUn/IBhFk4ksc8lYS2L 9GCy9CsmdKSBP78p9w8Lx7vDLqkDgt1/zBrcUWmSSb7AE/BPEeMryQV1IdI6nlGn BhWkXOYf6GSdayJw86btuxC7viDKNrbp44HjQRaSxnp6O3eto1x4DfiYdw/YbJFe 7EjkxSQBywIDAQABo4IBLjCCASowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwgecGA1UdIASB3zCB3DCB2QYEVR0gADCB0DCBzQYIKwYBBQUHAgIwgcAa gb1UZW50byBjZXJ0aWZpa2F0IGplIHZ5ZGFuIGpha28ga3ZhbGlmaWtvdmFueSBz eXN0ZW1vdnkgY2VydGlmaWthdCBwb2RsZSB6YWtvbmEgYy4gMjI3LzIwMDAgU2Iu IHYgcGxhdG5lbSB6bmVuaS9UaGlzIGlzIHF1YWxpZmllZCBzeXN0ZW0gY2VydGlm aWNhdGUgYWNjb3JkaW5nIHRvIEN6ZWNoIEFjdCBOby4gMjI3LzIwMDAgQ29sbC4w HQYDVR0OBBYEFHnL0CPpOmdwkXRP01Hi4CD94Sj7MA0GCSqGSIb3DQEBCwUAA4IB AQB9laU214hYaBHPZftbDS/2dIGLWdmdSbj1OZbJ8LIPBMxYjPoEMqzAR74tw96T i6aWRa5WdOWaS6I/qibEKFZhJAVXX5mkx2ewGFLJ+0Go+eTxnjLOnhVF2V2s+57b m8c8j6/bS6Ij6DspcHEYpfjjh64hE2r0aSpZDjGzKFM6YpqsCJN8qYe2X1qmGMLQ wvNdjG+nPzCJOOuUEypIWt555ZDLXqS5F7ZjBjlfyDZjEfS2Es9Idok8alf563Mi 9/o+Ba46wMYOkk3P1IlU0RqCajdbliioACKDztAqubONU1guZVzV8tuMASVzbJeL /GAB7ECTwe1RuKrLYtglMKI9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8DCCA9igAwIBAgIPBuhGJy8fCo/RhFzjafbVMA0GCSqGSIb3DQEBBQUAMDgx CzAJBgNVBAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXpl bnBlLmNvbTAeFw0wNzEyMTMxMzA4MjdaFw0zNzEyMTMwODI3MjVaMDgxCzAJBgNV BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXplbnBlLmNv bTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMnTesoPHqynhugWZWqx whtFMnGV2f4QW8yv56V5AY+Jw8ryVXH3d753lPNypCxE2J6SmxQ6oeckkAoKVo7F 2CaU4dlI4S0+2gpy3aOZFdqBoof0e24md4lYrdbrDLJBenNubdt6eEHpCIgSfocu ZhFjbFT7PJ1ywLwu/8K33Q124zrX97RovqL144FuwUZvXY3gTcZUVYkaMzEKsVe5 o4qYw+w7NMWVQWl+dcI8IMVhulFHoCCQk6GQS/NOfIVFVJrRBSZBsLVNHTO+xAPI JXzBcNs79AktVCdIrC/hxKw+yMuSTFM5NyPs0wH54AlETU1kwOENWocivK0bo/4m tRXzp/yEGensoYi0RGmEg/OJ0XQGqcwL1sLeJ4VQJsoXuMl6h1YsGgEebL4TrRCs tST1OJGh1kva8bvS3ke18byB9llrzxlT6Y0Vy0rLqW9E5RtBz+GGp8rQap+8TI0G M1qiheWQNaBiXBZO8OOi+gMatCxxs1gs3nsL2xoP694hHwZ3BgOwye+Z/MC5TwuG KP7Suerj2qXDR2kS4Nvw9hmL7Xtw1wLW7YcYKCwEJEx35EiKGsY7mtQPyvp10gFA Wo15v4vPS8+qFsGV5K1Mij4XkdSxYuWC5YAEpAN+jb/af6IPl08M0w3719Hlcn4c yHf/W5oPt64FRuXxqBbsR6QXAgMBAAGjgfYwgfMwgbAGA1UdEQSBqDCBpYEPaW5m b0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBB MDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEG A1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEw IFZpdG9yaWEtR2FzdGVpejAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUHRxlDqjyJXu0kc/ksbHmvVV0bAUwDQYJKoZIhvcNAQEFBQAD ggIBAMeBRm8hGE+gBe/n1bqXUKJg7aWSFBpSm/nxiEqg3Hh10dUflU7F57dp5iL0 +CmoKom+z892j+Mxc50m0xwbRxYpB2iEitL7sRskPtKYGCwkjq/2e+pEFhsqxPqg l+nqbFik73WrAGLRne0TNtsiC7bw0fRue0aHwp28vb5CO7dz0JoqPLRbEhYArxk5 ja2DUBzIgU+9Ag89njWW7u/kwgN8KRwCfr00J16vU9adF79XbOnQgxCvv11N75B7 XSus7Op9ACYXzAJcY9cZGKfsK8eKPlgOiofmg59OsjQerFQJTx0CCzl+gQgVuaBp E8gyK+OtbBPWg50jLbJtooiGfqgNASYJQNntKE6MkyQP2/EeTXp6WuKlWPHcj1+Z ggwuz7LdmMySlD/5CbOlliVbN/UShUHiGUzGigjB3Bh6Dx4/glmimj4/+eAJn/3B kUtdyXvWton83x18hqrNA/ILUpLxYm9/h+qrdslsUMIZgq+qHfUgKGgu1fxkN0/P pUTEvnK0jHS0bKf68r10OEMr3q/53NjgnZ/cPcqlY0S/kqJPTIAcuxrDmkoEVU3K 7iYLHL8CxWTTnn7S05EcS6L1HOUXHA0MUqORH5zwIe0ClG+poEnK6EOMxPQ02nwi o8ZmPrgbBYhdurz3vOXcFD2nhqi2WVIhA16L4wTtSyoeo09Q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXzCCA0egAwIBAgIBATANBgkqhkiG9w0BAQUFADCB0DELMAkGA1UEBhMCRVMx SDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMuVml0 b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwgTWVk aXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6MRMw EQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5wZS5j b20wHhcNMDMwMTMwMjMwMDAwWhcNMTgwMTMwMjMwMDAwWjCB0DELMAkGA1UEBhMC RVMxSDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMu Vml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwg TWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6 MRMwEQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5w ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1btoCXXhp3xIW D+Bxl8nUCxkyiazWfpt0e68t+Qt9+lZjKZSdEw2Omj4qvr+ovRmDXO3iWpWVOWDl 3JHJjAzFCe8ZEBNDH+QNYwZHmPBaMYFOYFdbAFVHWvys152C308hcFJ6xWWGmjvl 2eMiEl9P2nR2LWue368DCu+ak7j3gjAXaCOdP1a7Bfr+RW3X2SC5R4Xyp8iHlL5J PHJD/WBkLrezwzQPdACw8m9EG7q9kUwlNpL32mROujS3ZkT6mQTzJieLiE3X04s0 uIUqVkk5MhjcHFf7al0N5CzjtTcnXYJKN2Z9EDVskk4olAdGi46eSoZXbjUOP5gk Ej6wVZAXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MB0GA1UdDgQWBBTqVk/sPIOhFIh4gbIrBSLAB0FbQjANBgkqhkiG9w0BAQUFAAOC AQEAYp7mEzzhw6o5Hf5+T5kcI+t4BJyiIWy7vHlLs/G8dLYXO81aN/Mzg928eMTR TxxYZL8dd9uwsJ50TVfX6L0R4Dyw6wikh3fHRrat9ufXi63j5K91Ysr7aXqnF38d iAgHYkrwC3kuxHBb9C0KBz6h8Q45/KCyN7d37wWAq38yyhPDlaOvyoE6bdUuK5hT m5EYA5JmPyrhQ1moDOyueWBAjxzMEMj+OAY1H90cLv6wszsqerxRrdTOHBdv7MjB EIpvEEQkXUxVXAzFuuT6m2t91Lfnwfl/IvljHaVC7DlyyhRYHD6D4Rx+4QKp4tWL vpw6LkI+gKNJ/YdMCsRZQzEEFA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMw MVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQ MA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOB SvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkz ABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH LCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMP PbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL 2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8w ggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwIC MIHDHoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDk AGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0 AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABz AGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABhAG0AaQBz AGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f BCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcY P2/v6X2+MA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOi CfP+JmeaUOTDBS8rNXiRTHyoERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+g kcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyLabVAyJRld/JXIWY7zoVAtjNjGr95 HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678IIbsSt4beDI3poHS na9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkhMp6q qIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0Z TbvGRNs2yyqcjg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDczCCAlugAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN MAsGA1UECgwES0lTQTEuMCwGA1UECwwlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkgQ2VudHJhbDEWMBQGA1UEAwwNS0lTQSBSb290Q0EgMTAeFw0wNTA4MjQw ODA1NDZaFw0yNTA4MjQwODA1NDZaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKDARL SVNBMS4wLAYDVQQLDCVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 cmFsMRYwFAYDVQQDDA1LSVNBIFJvb3RDQSAxMIIBIDANBgkqhkiG9w0BAQEFAAOC AQ0AMIIBCAKCAQEAvATk+hM58DSWIGtsaLv623f/J/es7C/n/fB/bW+MKs0lCVsk 9KFo/CjsySXirO3eyDOE9bClCTqnsUdIxcxPjHmc+QZXfd3uOPbPFLKc6tPAXXdi 8EcNuRpAU1xkcK8IWsD3z3X5bI1kKB4g/rcbGdNaZoNy4rCbvdMlFQ0yb2Q3lIVG yHK+d9VuHygvx2nt54OJM1jT3qC/QOhDUO7cTWu8peqmyGGO9cNkrwYV3CmLP3WM vHFE2/yttRcdbYmDz8Yzvb9Fov4Kn6MRXw+5H5wawkbMnChmn3AmPC7fqoD+jMUE CSVPzZNHPDfqAmeS/vwiJFys0izgXAEzisEZ2wIBA6MyMDAwHQYDVR0OBBYEFL+2 J9gDWnZlTGEBQVYx5Yt7OtnMMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF BQADggEBABOvUQveimpb5poKyLGQSk6hAp3MiNKrZr097LuxQpVqslxa/6FjZJap aBV/JV6K+KRzwYCKhQoOUugy50X4TmWAkZl0Q+VFnUkq8JSV3enhMNITbslOsXfl BM+tWh6UCVrXPAgcrnrpFDLBRa3SJkhyrKhB2vAhhzle3/xk/2F0KpzZm4tfwjeT 2KM3LzuTa7IbB6d/CVDv0zq+IWuKkDsnSlFOa56ch534eJAx7REnxqhZvvwYC/uO fi5C4e3nCSG9uRPFVmf0JqZCQ5BEVLRxm3bkGhKsGigA35vB1fjbXKP4krG9tNT5 UNkAAk/bg9ART6RCVmE6fhMy04Qfybo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFUjCCBDqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN MAsGA1UEChMES0lTQTEuMCwGA1UECxMlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkgQ2VudHJhbDEWMBQGA1UEAxMNS0lTQSBSb290Q0EgMzAeFw0wNDExMTkw NjM5NTFaFw0xNDExMTkwNjM5NTFaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKEwRL SVNBMS4wLAYDVQQLEyVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 cmFsMRYwFAYDVQQDEw1LSVNBIFJvb3RDQSAzMIIBIDANBgkqhkiG9w0BAQEFAAOC AQ0AMIIBCAKCAQEA3rrtF2Wu0b1KPazbgHLMWOHn4ZPazDB6z+8Lri2nQ6u/p0LP CFYIpEcdffqG79gwlyY0YTyADvjU65/8IjAboW0+40zSVU4WQDfC9gdu2we1pYyW geKbXH6UYcjOhDyx+gDmctMJhXfp3F4hT7TkTvTiF6tQrxz/oTlYdVsSspa5jfBw YkhbVigqpYeRNrkeJPW5unu2UlFbF1pgBWycwubGjD756t08jP+J3kNwrB248XXN OMpTDUdoasY8GMq94bS+DvTQ49IT+rBRERHUQavo9DmO4TSETwuTqmo4/OXGeEeu dhf6oYA3BgAVCP1rI476cg2V1ktisWjC3TSbXQIBA6OCAg8wggILMB8GA1UdIwQY MBaAFI+B8NqmzXQ8vmb0FWtGpP4GKMyqMB0GA1UdDgQWBBSPgfDaps10PL5m9BVr RqT+BijMqjAOBgNVHQ8BAf8EBAMCAQYwggEuBgNVHSAEggElMIIBITCCAR0GBFUd IAAwggETMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LnJvb3RjYS5vci5rci9yY2Ev Y3BzLmh0bWwwgd4GCCsGAQUFBwICMIHRHoHOx3QAIMd4yZ3BHLKUACCs9cd4x3jJ ncEcx4WyyLLkACgAVABoAGkAcwAgAGMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGkA cwAgAGEAYwBjAHIAZQBkAGkAdABlAGQAIAB1AG4AZABlAHIAIABFAGwAZQBjAHQA cgBvAG4AaQBjACAAUwBpAGcAbgBhAHQAdQByAGUAIABBAGMAdAAgAG8AZgAgAHQA aABlACAAUgBlAHAAdQBiAGwAaQBjACAAbwBmACAASwBvAHIAZQBhACkwMwYDVR0R BCwwKqQoMCYxJDAiBgNVBAMMG+2VnOq1reygleuztOuztO2YuOynhO2dpeybkDAz BgNVHRIELDAqpCgwJjEkMCIGA1UEAwwb7ZWc6rWt7KCV67O067O07Zi47KeE7Z2l 7JuQMA8GA1UdEwEB/wQFMAMBAf8wDAYDVR0kBAUwA4ABADANBgkqhkiG9w0BAQUF AAOCAQEAz9b3Dv2wjG4FFY6oXCuyWtEeV6ZeGKqCEQj8mbdbp+PI0qLT+SQ09+Pk rolUR9NpScmAwRHr4inH9gaLX7riXs+rw87P7pIl3J85Hg4D9N6QW6FwmVzHc07J pHVJeyWhn4KSjU3sYcUMMqfHODiAVToqgx2cZHm5Dac1Smjvj/8F2LpOVmHY+Epw mAiWk9hgxzrsX58dKzVPSBShmrtv7tIDhlPxEMcHVGJeNo7iHCsdF03m9VrvirqC 6HfZKBF+N4dKlArJQOk1pTr7ZD7yXxZ683bXzu4/RB1Fql8RqlMcOh9SUWJUD6OQ Nc9Nb7rHviwJ8TX4Absk3TC8SA/u2Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdjCCAl6gAwIBAgIEOhsEBTANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJE SzEMMAoGA1UEChMDS01EMQ8wDQYDVQQLEwZLTUQtQ0ExIzAhBgNVBAMTGktNRC1D QSBLdmFsaWZpY2VyZXQgUGVyc29uMB4XDTAwMTEyMTIzMjQ1OVoXDTE1MTEyMjIz MjQ1OVowUTELMAkGA1UEBhMCREsxDDAKBgNVBAoTA0tNRDEPMA0GA1UECxMGS01E LUNBMSMwIQYDVQQDExpLTUQtQ0EgS3ZhbGlmaWNlcmV0IFBlcnNvbjCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBANriF4Xd6yD7ZlBE317UBDObn+vRMVc6 p3wNQODdEDJe2z1ncCz9NJvhoLGdOJhyg7VVPh0P2c+KZ9WI9mWOKZI2bp2WkLju jCcxbhTrurY3Wfc6gwLBqqFV8wWgaZKmvVWizjw9Kyi25f3yX4fOho6Qq2lvVbub tvVFXAd51GJ+/2Yed+a4Or2bz2RcqHS81B3pywsD4mgJR5xREv5jqPfwNP+V7bkc X+pfO4kVhZ/V+8MSPdQHgcV/iB3wP2mwgWyIBNc1reBidGTiz8unnWu55hcNfsvt LJbTs9OHhsR7naRuy+S402nDnD5vnONOFEsiHn46w+T0rtu7h6j4OvkCAwEAAaNW MFQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUeWLqmhI42Jxj7DifDsW+ DlQhKD0wHwYDVR0jBBgwFoAUeWLqmhI42Jxj7DifDsW+DlQhKD0wDQYJKoZIhvcN AQEFBQADggEBANML/P42OuJ9aUV/0fItuIyc1JhqWvSqn5bXj+9eyEegcp8bHLHY 42D1O+z0lNipdjYPSdMJ0wZOEUhr+150SdDQ1P/zQL8AUaLEBkRt7ZdzXPVH3PER qnf9IrpYBknZKfCAoVchA6Rr9WU3Sd8bMoRfMLKg8c0M8G6EPwCTcOFriSkbtvNG zd8r8I+WfUYIN/p8DI9JT9qfjVODnYPRMUm6KPvq27TsrGruKrqyaV94kWc8co8A v3zFLeCtghvUiRBdx+8Q7m5t4CkuSr0WINrqjIPFW2QrM1r82y09Fd16RkqL4LOg Lh6vB5KnTApv62rWdw7zWwYnjY6/vXYY1Aw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIEO8rJUjANBgkqhkiG9w0BAQUFADBmMQswCQYDVQQGEwJE SzEMMAoGA1UEChMDS01EMQ8wDQYDVQQLEwZLTUQtQ0ExFjAUBgNVBAMTDUtNRC1D QSBTZXJ2ZXIxIDAeBgoJkiaJk/IsZAEDFBBpbmZvY2FAa21kLWNhLmRrMB4XDTk4 MTAxNjE5MTkyMVoXDTE4MTAxMjE5MTkyMVowZjELMAkGA1UEBhMCREsxDDAKBgNV BAoTA0tNRDEPMA0GA1UECxMGS01ELUNBMRYwFAYDVQQDEw1LTUQtQ0EgU2VydmVy MSAwHgYKCZImiZPyLGQBAxQQaW5mb2NhQGttZC1jYS5kazCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAJsLpbSgFxQ7IhFgf5f+RfBxnbCkx5C7yTjfCZvp /BP2LBD3OKjgLRwvASoCU3I5NMhccho6uhZVf1HC+Ac5HmXUUd+v92a7gDnohPPy Rgv8c6f/+R2fFen37SBemYFDtZveamVXZ2To7xAxNiMKgPTPs/Rl7F6LDsYgv1bD 36FrjahNoSTmTbYRoK21eIOVwrZeNSzo9w3W8fj0n+V2IB1jsOh+AvjXkjbvAVky 0/57GMlyBNKP7JIGP7LXqwWfrBXuAph1DUMz467KlHZOMkPwCjTZOab7CcLQXCCY 12s5c5QAkwpf35hQRuOaNo6d/XFM6J9mofiWlGTT3Px1EX0CAwEAAaMQMA4wDAYD VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAPlA6VZ2C2cJbsI0SBIe9v+M9 GxI45QI7P0D7QGyrqM7oNqGq7hJdN6NFb0LyPcF3/pVzmtYVJzaGKF6spaxOEveB 9ki1xRoXUKpaCxSweBpTzEktWa43OytRy0sbryEmHJCQkz8MPufWssf2yXHzgFFo XMQpcMyT7JwxPlfYVvab9Kp+nW7fIyDOG0wdmBerZ+GEQJxJEkri1HskjigxhGze ziocJatBuOWgqw5KRylgGIQjUGRTCbODVta+Kmqb9d+cB7FStbYtt2HebOXzBIY3 XUM5KtGC++We7DqgU5Firek7brw8i2XsHPLKJTceb6Xo6DsSxLfBAWV6+8DCkQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 +rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c 2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C +C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC 2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0 YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0 aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4 Fp1hBWeAyNDYpQcCNJgEjTME1A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0 dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0 N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi 3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8 WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4 QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0 YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3 Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6 ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1 YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP 0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK 8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5 3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0 TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6 b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0 ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3 dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3 Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+ NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY 83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3 macqaJVmlaut74nLYKkGEsaUR+ko -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05 OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0 IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06 sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS NitjrFgBazMpUIaD8QFI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH /nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg 4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ /L7fCg0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp +ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og /zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y 4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza 8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB 4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd 8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A 4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd +LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B 4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK 4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK SnQ2+Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg /9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch 6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 7CAFYd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk 3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz 6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa /FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni 8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN QSdJQO7e5iNEOdyhIta6A/I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO 0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj 7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS 8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ 3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy 1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG 29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk 3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt 5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s 3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu 8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ 3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS /ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH 1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u 2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc 7uzXLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71 9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA 7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k /rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6 u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy 7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp 5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy 5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv 6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen 5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL +63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf 8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN +lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA 1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg 8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk 6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn 0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN sSi6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ 9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst 0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK 1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ 8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm fyWl8kgAwKQB2j8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1 OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/ Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM 0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9 Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K 2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl 6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK 9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo 19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e 3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 MBr1mmz0DlP5OlvRHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBk MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg Q0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2MjUwNzM4MTRaMGQxCzAJBgNVBAYT AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvEr jw0DzpPMLgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r 0rk0X2s682Q2zsKwzxNoysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f 2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJwDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVP ACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpHWrumnf2U5NGKpV+GY3aF y6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1aSgJA/MTA tukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL 6yxSNLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0 uPoTXGiTOmekl9AbmbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrAL acywlKinh/LTSlDcX3KwFnUey7QYYpqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velh k6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3qPyZ7iVNTA6z00yPhOgpD/0Q VAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw FDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqh b97iEoHF8TwuMA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4R fbgZPnm3qKhyN2abGu2sEzsOv2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv /2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ82YqZh6NM4OKb3xuqFp1mrjX2lhI REeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLzo9v/tdhZsnPdTSpx srpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcsa0vv aGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciAT woCqISxxOQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99n Bjx8Oto0QuFmtEYE3saWmA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5W t6NlUe07qxS/TFED6F+KBZvuim6c779o+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N 8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TCrvJcwhbtkj6EPnNgiLx2 9CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX5OfNeOI5 wSsSnqaeG8XmDtkx2Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAw ZzELMAkGA1UEBhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdp dGFsIENlcnRpZmljYXRlIFNlcnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290 IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcNMzEwNjI1MDg0NTA4WjBnMQswCQYD VQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2Vy dGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYgQ0Eg MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7Bx UglgRCgzo3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD 1ycfMQ4jFrclyxy0uYAyXhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPH oCE2G3pXKSinLr9xJZDzRINpUKTk4RtiGZQJo/PDvO/0vezbE53PnUgJUmfANykR HvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8LiqG12W0OfvrSdsyaGOx9/ 5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaHZa0zKcQv idm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHL OdAGalNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaC NYGu+HuB5ur+rPQam3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f 46Fq9mDU5zXNysRojddxyNMkM3OxbPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCB UWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDixzgHcgplwLa7JSnaFp6LNYth 7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/BAQDAgGGMB0G A1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWB bj2ITY1x0kbBbkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6x XCX5145v9Ydkn+0UjrgEjihLj6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98T PLr+flaYC/NUn81ETm484T4VvwYmneTwkLbUwp4wLh/vx3rEUMfqe9pQy3omywC0 Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7XwgiG/W9mR4U9s70 WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH59yL Gn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm 7JFe3VE/23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4S nr8PyQUQ3nqjsTzyP6WqJ3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VN vBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyAHmBR3NdUIR7KYndP+tiPsys6DXhyyWhB WkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/giuMod89a2GQ+fYWVq6nTI fI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuWl8PVP3wb I+2ksx0WckNLIOFZfsLorSa/ovc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtTCCAp2gAwIBAgIIBhDCeat3PfIwDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UE BhMCQ0gxEjAQBgNVBAoTCVN3aXNzU2lnbjEyMDAGA1UEAxMpU3dpc3NTaWduIENB IChSU0EgSUsgTWF5IDYgMTk5OSAxODowMDo1OCkxHzAdBgkqhkiG9w0BCQEWEGNh QFN3aXNzU2lnbi5jb20wHhcNMDAxMTI2MjMyNzQxWhcNMzExMTI2MjMyNzQxWjB2 MQswCQYDVQQGEwJDSDESMBAGA1UEChMJU3dpc3NTaWduMTIwMAYDVQQDEylTd2lz c1NpZ24gQ0EgKFJTQSBJSyBNYXkgNiAxOTk5IDE4OjAwOjU4KTEfMB0GCSqGSIb3 DQEJARYQY2FAU3dpc3NTaWduLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKw5fjnmNneLQlUCQG8jQLwwfbrOZoUwNX8cbNqhxK03/xUloFVgAt+S Te2RxNXaCAXLBPn5ZST35TLV57aLmbHCtifv3YZqaaQGvjedltIBMJihJhZ+h3LY SKsUb+xEJ3x5ZUf8jP+Q1g57y1s8SnBFWN/ni5NkF1Y1y31VwOi9wiOf/VISL+uu SC4i1CP1Kbz3BDs6Hht1GpRYCbJ/K0bc9oJSpWpT5PGONsGIawqMbJuyoDghsXQ1 pbn2e8K64BSscGZVZTNooSGgNiHmACNJBYXiWVWrwXPF4l6SddmC3Rj0aKXjgECc FkHLDQcsM5JsK2ZLryTDUsQFbxVP2ikCAwEAAaNHMEUwCwYDVR0PBAQDAgEGMAwG A1UdEwQFMAMBAf8wHQYDVR0OBBYEFJbXcc05KtT8iLGKq1N4ae+PR34WMAkGA1Ud IwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAKMy6W8HvZdS1fBpEUzl6Lvw50bgE1Xc HU1JypSBG9mhdcXZo5AlPB4sCvx9Dmfwhyrdsshc0TP2V3Vh6eQqnEF5qB4lVziT Bko9mW6Ot+pPnwsy4SHpx3rw6jCYnOqfUcZjWqqqRrq/3P1waz+Mn4cLMVEg3Xaz qYov/khvSqS0JniwjRlo2H6f/1oVUKZvP+dUhpQepfZrOqMAWZW4otp6FolyQyeU NN6UCRNiUKl5vTijbKwUUwfER/1Vci3M1/O1QCfttQ4vRN4Buc0xqYtGL3cd5WiO vWzyhlTzAI6VUdNkQhhHJSAyTpj6dmXDRzrryoFGa2PjgESxz7XBaSI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c 6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn 8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a 77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ 6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl +zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH 6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ 2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICqDCCAi2gAwIBAgIQIW4zpcvTiKRvKQe0JzzE2DAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAxIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAATXZrUb266zYO5G6ohjdTsqlG3zXxL24w+etgoUU0hS yNw6s8tIICYSTvqJhNTfkeQpfSgB2dsYQ2mhH7XThhbcx39nI9/fMTGDAzVwsUu3 yBe7UcvclBfb6gk7dhLeqrWjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRlwI0l9Qy6l3eQP54u4Fr1ztXh5DAKBggqhkjOPQQD AwNpADBmAjEApa7jRlP4mDbjIvouKEkN7jB+M/PsP3FezFWJeJmssv3cHFwzjim5 axfIEWi13IMHAjEAnMhE2mnCNsNUGRCFAtqdR+9B52wmnQk9922Q0QVEL7C8g5No 8gxFSTm/mQQc0xCg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9jCCAt6gAwIBAgIQJDJ18h0v0gkz97RqytDzmDANBgkqhkiG9w0BAQsFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAx IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHOddJZKmZgiJM6kXZBxbje/SD 6Jlz+muxNuCad6BAwoGNAcfMjL2Pffd543pMA03Z+/2HOCgs3ZqLVAjbZ/sbjP4o ki++t7JIp4Gh2F6Iw8w5QEFa0dzl2hCfL9oBTf0uRnz5LicKaTfukaMbasxEvxvH w9QRslBglwm9LiL1QYRmn81ApqkAgMEflZKf3vNI79sdd2H8f9/ulqRy0LY+/3gn r8uSFWkI22MQ4uaXrG7crPaizh5HmbmJtxLmodTNWRFnw2+F2EJOKL5ZVVkElauP N4C/DfD8HzpkMViBeNfiNfYgPym4jxZuPkjctUwH4fIa6n4KedaovetdhitNAgMB AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBQzQejIORIVk0jyljIuWvXalF9TYDANBgkqhkiG9w0BAQsFAAOCAQEAFeNzV7EX tl9JaUSm9l56Z6zS3nVJq/4lVcc6yUQVEG6/MWvL2QeTfxyFYwDjMhLgzMv7OWyP 4lPiPEAz2aSMR+atWPuJr+PehilWNCxFuBL6RIluLRQlKCQBZdbqUqwFblYSCT3Q dPTXvQbKqDqNVkL6jXI+dPEDct+HG14OelWWLDi3mIXNTTNEyZSPWjEwN0ujOhKz 5zbRIWhLLTjmU64cJVYIVgNnhJ3Gw84kYsdMNs+wBkS39V8C3dlU6S+QTnrIToNA DJqXPDe/v+z28LSFdyjBC8hnghAXOKK3Buqbvzr46SMHv3TgmDgVVXjucgBcGaP0 0jPg/73RVDkpDw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICqDCCAi2gAwIBAgIQNBdlEkA7t1aALYDLeVWmHjAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAyIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAATR2UqOTA2ESlG6fO/TzPo6mrWnYxM9AeBJPvrBR8mS szrX/m+c95o6D/UOCgrDP8jnEhSO1dVtmCyzcTIK6yq99tdqIAtnRZzSsr9TImYJ XdsR8/EFM1ij4rjPfM2Cm72jQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBQ9MvM6qQyQhPmijGkGYVQvh3L+BTAKBggqhkjOPQQD AwNpADBmAjEAyKapr0F/tckRQhZoaUxcuCcYtpjxwH+QbYfTjEYX8D5P/OqwCMR6 S7wIL8fip29lAjEA1lnehs5fDspU1cbQFQ78i5Ry1I4AWFPPfrFLDeVQhuuea9// KabYR9mglhjb8kWz -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9jCCAt6gAwIBAgIQZIKe/DcedF38l/+XyLH/QTANBgkqhkiG9w0BAQsFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAy IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNzOkFyGOFyz9AYxe9GPo15gRn V2WYKaRPyVyPDzTS+NqoE2KquB5QZ3iwFkygOakVeq7t0qLA8JA3KRgmXOgNPLZs ST/B4NzZS7YUGQum05bh1gnjGSYc+R9lS/kaQxwAg9bQqkmi1NvmYji6UBRDbfkx +FYW2TgCkc/rbN27OU6Z4TBnRfHU8I3D3/7yOAchfQBeVkSz5GC9kSucq1sEcg+y KNlyqwUgQiWpWwNqIBDMMfAr2jUs0Pual07wgksr2F82owstr2MNHSV/oW5cYqGN KD6h/Bwg+AEvulWaEbAZ0shQeWsOagXXqgQ2sqPy4V93p3ec5R7c6d9qwWVdAgMB AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBSHjCCVyJhK0daABkqQNETfHE2/sDANBgkqhkiG9w0BAQsFAAOCAQEAgY6ypWaW tyGltu9vI1pf24HFQqV4wWn99DzX+VxrcHIa/FqXTQCAiIiCisNxDY7FiZss7Y0L 0nJU9X3UXENX6fOupQIR9nYrgVfdfdp0MP1UR/bgFm6mtApI5ud1Bw8pGTnOefS2 bMVfmdUfS/rfbSw8DVSAcPCIC4DPxmiiuB1w2XaM/O6lyc+tHc+ZJVdaYkXLFmu9 Sc2lo4xpeSWuuExsi0BmSxY/zwIa3eFsawdhanYVKZl/G92IgMG/tY9zxaaWI4Sm KIYkM2oBLldzJbZev4/mHWGoQClnHYebHX+bn5nNMdZUvmK7OaxoEkiRIKXLsd3+ b/xa5IJVWa8xqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICpzCCAi2gAwIBAgIQTHm1miicdjFk9YlE0JEC3jAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAzIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAARXz+qzOU0/oSHgbi84csaHl/OFC0fnD1HI0fSZm8pZ Zf9M+eoLtyXV0vbsMS0yYhLXdoan+jjJZdT+c+KEOfhMSWIT3brViKBfPchPsD+P oVAR5JNGrcNfy/GkapVW6MCjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBQknbzScfcdwiW+IvGJpSwVOzQeXjAKBggqhkjOPQQD AwNoADBlAjEAuWZoZdsF0Dh9DvPIdWG40CjEsUozUVj78jwQyK5HeHbKZiQXhj5Q Vm6lLZmIuL0kAjAD6qfnqDzqnWLGX1TamPR3vU+PGJyRXEdrQE0QHbPhicoLIsga xcX+i93B3294n5E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9jCCA96gAwIBAgIQZWNxhdNvRcaPfzH5CYeSgjANBgkqhkiG9w0BAQwFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAz IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC3DrL6TbyachX7d1vb/UMPywv3 YC6zK34Mu1PyzE5l8xm7/zUd99Opu0Attd141Kb5N+qFBXttt+YTSwZ8+3ZjjyAd LTgrBIXy6LDRX01KIclq2JTqHgJQpqqQB6BHIepm+QSg5oPwxPVeluInTWHDs8GM IrZmoQDRVin77cF/JMo9+lqUsITDx7pDHP1kDvEo+0dZ8ibhMblE+avd+76+LDfj rAsY0/wBovGkCjWCR0yrvYpe3xOF/CDMSFmvr0FvyyPNypOn3dVfyGQ7/wEDoApP LW49hL6vyDKyUymQFfewBZoKPPa5BpDJpeFdoDuw/qi2v/WJKFckOiGGceTciotB VeweMCRZ0cBZuHivqlp03iWAMJjtMERvIXAc2xJTDtamKGaTLB/MTzwbgcW59nhv 0DI6CHLbaw5GF4WU87zvvPekXo7p6bVk5bdLRRIsTDe3YEMKTXEGAJQmNXQfu3o5 XE475rgD4seTi4QsJUlF3X8jlGAfy+nN9quX92Hn+39igcjcCjBcGHzmzu/Hbh6H fLPpysh7avRo/IOlDFa0urKNSgrHl5fFiDAVPRAIVBVycmczM/R8t84AJ1NlziTx WmTnNi/yLgLCl99y6AIeoPc9tftoYAP6M6nmEm0G4amoXU48/tnnAGWsthlNe4N/ NEfq4RhtsYsceavnnQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUOXEIAD7eyIbnkP/k/SEPziQZFvYwDQYJKoZIhvcN AQEMBQADggIBAFBriE1gSM5a4yLOZ3yEp80c/ekMA4w2rwqHDmquV64B0Da78v25 c8FftaiuTKL6ScsHRhY2vePIVzh+OOS/JTNgxtw3nGO7XpgeGrKC8K6mdxGAREeh KcXwszrOmPC47NMOgAZ3IzBM/3lkYyJbd5NDS3Wz2ztuO0rd8ciutTeKlYg6EGhw OLlbcH7VQ8n8X0/l5ns27vAg7UdXEyYQXhQGDXt2B8LGLRb0rqdsD7yID08sAraj 1yLmmUc12I2lT4ESOhF9s8wLdfMecKMbA+r6mujmLjY5zJnOOj8Mt674Q5mwk25v qtkPajGRu5zTtCj7g0x6c4JQZ9IOrO1gxbJdNZjPh34eWR0kvFa62qRa2MzmvB4Q jxuMjvPB27e+1LBbZY8WaPNWxSoZFk0PuGWHbSSDuGLc4EdhGoh7zk5//dzGDVqa pPO1TPbdMaboHREhMzAEYX0c4D5PjT+1ixIAWn2poQDUg+twuxj4pNIcgS23CBHI Jnu21OUPA0Zy1CVAHr5JXW2T8VyyO3VUaTqg7kwiuqya4gitRWMFSlI1dsQ09V4H Mq3cfCbRW4+t5OaqG3Wf61206MCpFXxOSgdy30bJ1JGSdVaw4e43NmUoxRXIK3bM bW8Zg/T92hXiQeczeUaDV/nxpbZt07zXU+fucW14qZen7iCcGRVyFT0E -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDcTCCAlmgAwIBAgIVAOYJ/nrqAGiM4CS07SAbH+9StETRMA0GCSqGSIb3DQEB BQUAMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGlj emVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIgUk9PVCBDQTAeFw0xMTEyMDYx MTEwNTdaFw0zMTEyMDYxMTEwNTdaMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIg Uk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxHL49ZMTml 6g3wpYwrvQKkvc0Kc6oJ5sxfgmp1qZfluwbv88BdocHSiXlY8NzrVYzuWBp7J/9K ULMAoWoTIzOQ6C9TNm4YbA9A1jdX1wYNL5Akylf8W5L/I4BXhT9KnlI6x+a7BVAm nr/Ttl+utT/Asms2fRfEsF2vZPMxH4UFqOAhFjxTkmJWf2Cu4nvRQJHcttB+cEAo ag/hERt/+tzo4URz6x6r19toYmxx4FjjBkUhWQw1X21re//Hof2+0YgiwYT84zLb eqDqCOMOXxvH480yGDkh/QoazWX3U75HQExT/iJlwnu7I1V6HXztKIwCBjsxffbH 3jOshCJtywcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFFOSo33/gnbwM9TrkmdHYTMbaDsqMA0GCSqGSIb3DQEBBQUA A4IBAQA5UFWd5EL/pBviIMm1zD2JLUCpp0mJG7JkwznIOzawhGmFFaxGoxAhQBEg haP+E0KR66oAwVC6xe32QUVSHfWqWndzbODzLB8yj7WAR0cDM45ZngSBPBuFE3Wu GLJX9g100ETfIX+4YBR/4NR/uvTnpnd9ete7Whl0ZfY94yuu4xQqB5QFv+P7IXXV lTOjkjuGXEcyQAjQzbFaT9vIABSbeCXWBbjvOXukJy6WgAiclzGNSYprre8Ryydd fmjW9HIGwsIO03EldivvqEYL1Hv1w/Pur+6FUEOaL68PEIUovfgwIB2BAw+vZDuw cH0mX548PojGyg434cDjkSXa3mHF -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi 1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP BSeOE6Fuwg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN 8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ 1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT 91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p TpPDpFQUWw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK 8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99 5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3 kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6 Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8 au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2 1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1 Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6 Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8 TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6 g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB 95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtjCCAp6gAwIBAgIOBcAAAQACQdAGCk3OdRAwDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDQgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDQgQ0EgSUkwHhcNMDYwMzIzMTQxMDIzWhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBALXNTJytrlG7fEjFDSmGehSt2VA9CXIgDRS2Y8b+WJ7gIV7z jyIZ3E6RIM1viCmis8GsKnK6i1S4QF/yqvhDhsIwXMynXX/GCEnkDjkvjhjWkd0j FnmA22xIHbzB3ygQY9GB493fL3l1oht48pQB5hBiecugfQLANIJ7x8CtHUzXapZ2 W78mhEj9h/aECqqSB5lIPGG8ToVYx5ct/YFKocabEvVCUNFkPologiJw3fX64yhC L04y87OjNopq1mJcrPoBbbTgci6VaLTxkwzGioLSHVPqfOA/QrcSWrjN2qUGZ8uh d32llvCSHmcOHUJG5vnt+0dTf1cERh9GX8eu4I8CAwEAAaNCMEAwDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFB/quz4lGwa9pd1iBX7G TFq/6A9DMA0GCSqGSIb3DQEBBQUAA4IBAQBYpCubTPfkpJKknGWYGWIi/HIy6QRd xMRwLVpG3kxHiiW5ot3u6hKvSI3vK2fbO8w0mCr3CEf/Iq978fTr4jgCMxh1KBue dmWsiANy8jhHHYz1nwqIUxAUu4DlDLNdjRfuHhkcho0UZ3iMksseIUn3f9MYv5x5 +F0IebWqak2SNmy8eesOPXmK2PajVnBd3ttPedJ60pVchidlvqDTB4FAVd0Qy+BL iILAkH0457+W4Ze6mqtCD9Of2J4VMxHL94J59bXAQVaS4d9VA61Iz9PyLrHHLVZM ZHQqMc7cdalUR6SnQnIJ5+ECpkeyBM1CE+FhDOB4OiIgohxgQoaH96Xm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1 7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn 8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/ 2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3zCCA8egAwIBAgIOGTMAAQACKBqaBLzyVUUwDQYJKoZIhvcNAQEFBQAwejEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUGA1UEAxMeVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMB4XDTA2MDMyMjE1NTgzNFoXDTMwMTIz MTIyNTk1OVowejELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVy IEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUG A1UEAxMeVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAi9R3azRs5TbYalxeOO781R15Azt7g2JEgk6I 7d6D/+7MUGIFBZWZdpj2ufJf2AaRksL2LWYXH/1TA+iojWOpbuHWG4y8mLOLO9Tk Lsp9hUkmW3m4GotAnn+7yT9jLM/RWny6KCJBElpN+Rd3/IX9wkngKhh/6aAsnPlE /AxoOUL1JwW+jhV6YJ3wO8c85j4WvK923mq3ouGrRkXrjGV90ZfzlxElq1nroCLZ gt2Y7X7i+qBhCkoy3iwX921E6oFHWZdXNwM53V6CItQzuPomCba8OYgvURVOm8M7 3xOCiN1LNPIz1pDp81PcNXzAw9l8eLPNcD+NauCjgUjkKa1juPD8KGQ7mbN9/pqd iPaZIgiRRxaJNXhdd6HPv0nh/SSUK2k2e+gc5iqQilvVOzRZQtxtz7sPQRxVzfUN Wy4WIibvYR6X/OJTyM9bo8ep8boOhhLLE8oVx+zkNo3aXBM9ZdIOXXB03L+PemrB Lg/Txl4PK1lszGFs/sBhTtnmT0ayWuIZFHCE+CAA7QGnl37DvRJckiMXoKUdRRcV I5qSCLUiiI3cKyTr4LEXaNOvYb3ZhXj2jbp4yjeNY77nrB/fpUcJucglMVRGURFV DYlcjdrSGC1z8rjVJ/VIIjfRYvd7Dcg4i6FKsPzQ8eu3hmPn4A5zf/1yUbXpfeJV BWR4Z38CAwEAAaNjMGEwHwYDVR0jBBgwFoAUzdeQoW6jv9sw1toyJZAM5jkegGUw DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFM3XkKFu o7/bMNbaMiWQDOY5HoBlMA0GCSqGSIb3DQEBBQUAA4ICAQB+FojoEw42zG4qhQc4 xlaJeuNHIWZMUAgxWlHQ/KZeFHXeTDvs8e3MfhEHSmHu6rOOOqQzxu2KQmZP8Tx7 yaUFQZmx7Cxb7tyW0ohTS3g0uW7muw/FeqZ8Dhjfbw90TNGp8aHp2FRkzF6WeKJW GsFzshXGVwXf2vdIJIqOf2qp+U3pPmrOYCx9LZAI9mOPFdAtnIz/8f38DBZQVhT7 upeG7rRJA1TuG1l/MDoCgoYhrv7wFfLfToPmmcW6NfcgkIw47XXP4S73BDD7Ua2O giRAyn0pXdXZ92Vk/KqfdLh9kl3ShCngE+qK99CrxK7vFcXCifJ7tjtJmGHzTnKR N4xJkunI7Cqg90lufA0kxmts8jgvynAF5X/fxisrgIDV2m/LQLvYG/AkyRDIRAJ+ LtOYqqIN8SvQ2vqOHP9U6OFKbt2o1ni1N6WsZNUUI8cOpevhCTjXwHxgpV2Yj4wC 1dxWqPNNWKkL1HxkdAEy8t8PSoqpAqKiHYR3wvHMl700GXRd4nQ+dSf3r7/ufA5t VIimVuImrTESPB5BeW0X6hNeH/Vcn0lZo7Ivo0LD+qh+v6WfSMlgYmIK371F3uNC tVGW/cT1Gpm4UqJEzS1hjBWPgdVdotSQPYxuQGHDWV3Y2eH2dEcieXR92sqjbzcV NvAsGnE8EXbfXRo+VGN4a2V+Hw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF 5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI 4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a 0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1 4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3 WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ 2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89 9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0 jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38 aQNiuJkFBT1reBK9sG9l -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr 2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s 2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9 BKNDLdr8C2LqL19iUw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ /jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs 81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG 9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDMDCCApmgAwIBAgIQDY4VEuGsu3eNOOMk34ww8jANBgkqhkiG9w0BAQUFADCB yzELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ Q2FwZSBUb3duMRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl IFBlcnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIxMDEwMTIzNTk1OVowgcsx CzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNh cGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0Nl cnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQ ZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNA dGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+C FeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeV oQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlW Cy4cgNrx454p7xS9CkT7G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB /zANBgkqhkiG9w0BAQUFAAOBgQCIO/64+XpCRhGgpKJkhc1IHJzVilHNL8F9sQfP 1wHeMj+W5IT+0V6tDH4OY0lqDhDkl9A/xacp2aZTHkseP1T6wIQ1c+qRqdxdk1cF BgwHua8LRDmIIaDugnOpRi9pbCV0qc3fp9f9hTAElDVKpxszJCxEFu0KxN+AqmUa v3Em8A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53 dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7 G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P 9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDPDCCAqWgAwIBAgIQEj3w59oqIkekOIngiu7JZzANBgkqhkiG9w0BAQUFADCB 0TELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ Q2FwZSBUb3duMRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3Rl IFBlcnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIxMDEwMTIzNTk1 OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNV BAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1Ro YXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29u YWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC gYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Z hx2G6qPduc6WZBrCFG5ErHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56 fAylS1V/Bhkpf56aJtVquzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYD VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAemGDU5fJUYLA9GoFkR/db o9lvwykLp9KpgUn2w22FFChFRAH0cVyVLhQPGivRqWvBX2c9FvFyIK++FsoOMF/J y6WTLMNnVB5yIoojdmyUHVFSbJ3E4EcC18y/8IB7GG4l3GJh1qb+wR1/2bP9jVxF EFrGZWSa6yz1A0/WSGL7Lg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa /RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei gQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDODCCAqGgAwIBAgIQQAWyU6AaRkNQCYGPEhB27DANBgkqhkiG9w0BAQUFADCB zzELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ Q2FwZSBUb3duMRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3Rl IFBlcnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMTAxMDEyMzU5NTla MIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQH EwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQL Ex9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3 dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwt cHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ Ztn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O 0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8f AHB8Zs8QJQi6+u4A6UYDZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMB Af8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBALpkCujztDHJJ2+idqAtNnHHhsAI wk7t2pokGYf8WiOcck0I361cwzskgR1Xj7YSpSID7xK90S1elo8mJk9LG3w7oFIa pag3hsRHKsrdQfho9cITQSma8AyozaH8FSMC23or1GJRQkfEox/00sVNVBDr2vDM p083DL08yxDjGugV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDNjCCAp+gAwIBAgIQNhIilsXjOKUgodJfTNcJVDANBgkqhkiG9w0BAQUFADCB zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIxMDEwMTIzNTk1OVow gc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcT CUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNV BAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRo YXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1z ZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560 ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j +ao6hnO2RlNYyIkFvYMRuHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/ BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBlkKyID1bZ5jA01CbH0FDxkt5r1DmI CSLGpmODA/eZd9iy5Ri4XWPz1HP7bJyZePFLeH0ZJMMrAoT4vCLZiiLXoPxx7JGH IPG47LHlVYCsPVLIOQ7C8MAFT9aCdYy9X9LcdpoFEsmvcsPcJX6kTY4XpeCHf+Ga WuFg3GQjPEIuTQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG 9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta 3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk 6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 /qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 jVaMaA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA 2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu MdRAGmI0Nj81Aa6sY6A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIjCCAougAwIBAgIQNKT/9jCvTKU8MxdCoZRmdTANBgkqhkiG9w0BAQUFADCB xDELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhh d3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjEwMTAxMjM1OTU5WjCBxDELMAkGA1UE BhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZl ciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8w DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl /Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF /rFrKbYvScg71CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982 OsK1ZiIS1ocNAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF BQADgYEAvkBpQW/G28GnvwfAReTQtUMeTJUzNelewj4o9qgNUNX/4gwP/FACjq6R ua00io2fJ3GqGcxL6ATK1BdrEhrWxl/WzV7/iXa/2EjYWb0IiokdV81FHlK6EpqE +hiJX+j5MDVqAWC5mYCDhQpu2vTJj15zLTFKY6B08h+LItIpPus= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3 dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3 DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91 yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG 7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ qdq5snUb9kLy78fyGPmJvKP/iiMucEc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICsDCCAhmgAwIBAgIQZ8jh6OO+HL38kTuOpiOHSTANBgkqhkiG9w0BAQUFADCB izELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxML RHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENl cnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcN OTcwMTAxMDAwMDAwWhcNMjEwMTAxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNV BAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNV BAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0A MIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u 6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522 FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzAR MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAS+mqF4EF+3kKMZ/F QfRWVKvpwuWXjhj+kckMPiZkyaFMJ2SnvQGTVXFuF0853BvcSTUQOSP/ypvIz2Y/ 3Ewa1IEGQlIf4SaxFhe65nByMUToTo1b5NP50OOPJWQx5yr4GIg2GlLFDUE1G2m3 JvUXzMEZXkt8XOKDgJH6L/uatxY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHDCCBASgAwIBAgIES45gAzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJE SzESMBAGA1UEChMJVFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQ cmltYXJ5IENBMB4XDTEwMDMwMzEyNDEzNFoXDTM3MTIwMzEzMTEzNFowRTELMAkG A1UEBhMCREsxEjAQBgNVBAoTCVRSVVNUMjQwODEiMCAGA1UEAxMZVFJVU1QyNDA4 IE9DRVMgUHJpbWFyeSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AJlJodr3U1Fa+v8HnyACHV81/wLevLS0KUk58VIABl6Wfs3LLNoj5soVAZv4LBi5 gs7E8CZ9w0F2CopW8vzM8i5HLKE4eedPdnaFqHiBZ0q5aaaQArW+qKJx1rT/AaXt alMB63/yvJcYlXS2lpexk5H/zDBUXeEQyvfmK+slAySWT6wKxIPDwVapauFY9QaG +VBhCa5jBstWS7A5gQfEvYqn6csZ3jW472kW6OFNz6ftBcTwufomGJBMkonf4ZLr 6t0AdRi9jflBPz3MNNRGxyjIuAmFqGocYFA/OODBRjvSHB2DygqQ8k+9tlpvzMRr kU7jq3RKL+83G1dJ3/LTjCLz4ryEMIC/OJ/gNZfE0qXddpPtzflIPtUFVffXdbFV 1t6XZFhJ+wBHQCpJobq/BjqLWUA86upsDbfwnePtmIPRCemeXkY0qabC+2Qmd2Fe xyZphwTyMnbqy6FG1tB65dYf3mOqStmLa3RcHn9+2dwNfUkh0tjO2FXD7drWcU0O I9DW8oAypiPhm/QCjMU6j6t+0pzqJ/S0tdAo+BeiXK5hwk6aR+sRb608QfBbRAs3 U/q8jSPByenggac2BtTN6cl+AA1Mfcgl8iXWNFVGegzd/VS9vINClJCe3FNVoUnR YCKkj+x0fqxvBLopOkJkmuZw/yhgMxljUi2qYYGn90OzAgMBAAGjggESMIIBDjAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHSAECjAIMAYGBFUd IAAwgZcGA1UdHwSBjzCBjDAsoCqgKIYmaHR0cDovL2NybC5vY2VzLnRydXN0MjQw OC5jb20vb2Nlcy5jcmwwXKBaoFikVjBUMQswCQYDVQQGEwJESzESMBAGA1UEChMJ VFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQcmltYXJ5IENBMQ0w CwYDVQQDEwRDUkwxMB8GA1UdIwQYMBaAFPZt+LFIs0FDAduGROUYBbdezAY3MB0G A1UdDgQWBBT2bfixSLNBQwHbhkTlGAW3XswGNzANBgkqhkiG9w0BAQsFAAOCAgEA VPAQGrT7dIjD3/sIbQW86f9CBPu0c7JKN6oUoRUtKqgJ2KCdcB5ANhCoyznHpu3m /dUfVUI5hc31CaPgZyY37hch1q4/c9INcELGZVE/FWfehkH+acpdNr7j8UoRZlkN 15b/0UUBfGeiiJG/ugo4llfoPrp8bUmXEGggK3wyqIPcJatPtHwlb6ympfC2b/Ld v/0IdIOzIOm+A89Q0utx+1cOBq72OHy8gpGb6MfncVFMoL2fjP652Ypgtr8qN9Ka /XOazktiIf+2Pzp7hLi92hRc9QMYexrV/nnFSQoWdU8TqULFUoZ3zTEC3F/g2yj+ FhbrgXHGo5/A4O74X+lpbY2XV47aSuw+DzcPt/EhMj2of7SA55WSgbjPMbmNX0rb oenSIte2HRFW5Tr2W+qqkc/StixgkKdyzGLoFx/xeTWdJkZKwyjqge2wJqws2upY EiThhC497+/mTiSuXd69eVUwKyqYp9SD2rTtNmF6TCghRM/dNsJOl+osxDVGcwvt WIVFF/Onlu5fu1NHXdqNEfzldKDUvCfii3L2iATTZyHwU9CALE+2eIA+PIaLgnM1 1oCfUnYBkQurTrihvzz9PryCVkLxiqRmBVvUz+D4N5G/wvvKDS6t6cPCS+hqM482 cbBsn0R9fFLO4El62S9eH1tqOzO20OAOK65yJIsOpSE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW 1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA 0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN ZetX2fNXlrtIzYE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2 ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0 aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/ BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM 7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs yZyQ2uypQjyttgI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOc UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMQswCQYDVQQGDAJUUjEPMA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykg MjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMxMDI3MTdaFw0xNTAz MjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2Vy dGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYD VQQHDAZBTktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kg xLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEu xZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7 XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GXyGl8hMW0kWxsE2qkVa2k heiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8iSi9BB35J YbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5C urKZ8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1 JuTm5Rh8i27fbMx4W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51 b0dewQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV 9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46sWrv7/hg0Uw2ZkUd82YCdAR7 kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxEq8Sn5RTOPEFh fEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdA aLX/7KfS0zgYnNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKS RGQDJereW26fyfJOrN3H -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3 WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOc UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xS S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg SGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4XDTA3MTIyNTE4Mzcx OVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxla3Ry b25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMC VFIxDzANBgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDE sGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7F ni4gKGMpIEFyYWzEsWsgMjAwNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9NYvDdE3ePYakqtdTyuTFY KTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQvKUmi8wUG +7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveG HtyaKhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6P IzdezKKqdfcYbwnTrqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M 733WB2+Y8a+xwXrXgTW4qhe04MsCAwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHk Yb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G CSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/sPx+EnWVUXKgW AkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5 mxRZNTZPz/OOXl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsa XRik7r4EW5nVcV9VZWRi1aKbBFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZ qxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAKpoRq0Tl9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF 10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz 0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc 46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm 4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL 1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh 15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW 6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy KwbQBM0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx 3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIBCDANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJDTjER MA8GA1UEChMIVW5pVHJ1c3QxGDAWBgNVBAMTD1VDQSBHbG9iYWwgUm9vdDAeFw0w ODAxMDEwMDAwMDBaFw0zNzEyMzEwMDAwMDBaMDoxCzAJBgNVBAYTAkNOMREwDwYD VQQKEwhVbmlUcnVzdDEYMBYGA1UEAxMPVUNBIEdsb2JhbCBSb290MIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2rPlBlA/9nP3xDK/RqUlYjOHsGj+p9+I A2N9Apb964fJ7uIIu527u+RBj8cwiQ9tJMAEbBSUgU2gDXRm8/CFr/hkGd656YGT 0CiFmUdCSiw8OCdKzP/5bBnXtfPvm65bNAbXj6ITBpyKhELVs6OQaG2BkO5NhOxM cE4t3iQ5zhkAQ5N4+QiGHUPR9HK8BcBn+sBR0smFBySuOR56zUHSNqth6iur8CBV mTxtLRwuLnWW2HKX4AzKaXPudSsVCeCObbvaE/9GqOgADKwHLx25urnRoPeZnnRc GQVmMc8+KlL+b5/zub35wYH1N9ouTIElXfbZlJrTNYsgKDdfUet9Ysepk9H50DTL qScmLCiQkjtVY7cXDlRzq6987DqrcDOsIfsiJrOGrCOp139tywgg8q9A9f9ER3Hd J90TKKHqdjn5EKCgTUCkJ7JZFStsLSS3JGN490MYeg9NEePorIdCjedYcaSrbqLA l3y74xNLytu7awj5abQEctXDRrl36v+6++nwOgw19o8PrgaEFt2UVdTvyie3AzzF HCYq9TyopZWbhvGKiWf4xwxmse1Bv4KmAGg6IjTuHuvlb4l0T2qqaqhXZ1LUIGHB zlPL/SR/XybfoQhplqCe/klD4tPq2sTxiDEhbhzhzfN1DiBEFsx9c3Q1RSw7gdQg 7LYJjD5IskkCAwEAAaOBojCBnzALBgNVHQ8EBAMCAQYwDAYDVR0TBAUwAwEB/zBj BgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcD BAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUHAwgGCCsGAQUF BwMJMB0GA1UdDgQWBBTZw9P4gJJnzF3SOqLXcaK0xDiALTANBgkqhkiG9w0BAQUF AAOCAgEA0Ih5ygiq9ws0oE4Jwul+NUiJcIQjL1HDKy9e21NrW3UIKlS6Mg7VxnGF sZdJgPaE0PC6t3GUyHlrpsVE6EKirSUtVy/m1jEp+hmJVCl+t35HNmktbjK81HXa QnO4TuWDQHOyXd/URHOmYgvbqm4FjMh/Rk85hZCdvBtUKayl1/7lWFZXbSyZoUkh 1WHGjGHhdSTBAd0tGzbDLxLMC9Z4i3WA6UG5iLHKPKkWxk4V43I29tSgQYWvimVw TbVEEFDs7d9t5tnGwBLxSzovc+k8qe4bqi81pZufTcU0hF8mFGmzI7GJchT46U1R IgP/SobEHOh7eQrbRyWBfvw0hKxZuFhD5D1DCVR0wtD92e9uWfdyYJl2b/Unp7uD pEqB7CmB9HdL4UISVdSGKhK28FWbAS7d9qjjGcPORy/AeGEYWsdl/J1GW1fcfA67 loMQfFUYCQSu0feLKj6g5lDWMDbX54s4U+xJRODPpN/xU3uLWrb2EZBL1nXz/gLz Ka/wI3J9FO2pXd96gZ6bkiL8HvgBRUGXx2sBYb4zaPKgZYRmvOAqpGjTcezHCN6j w8k2SjTxF+KAryAhk5Qe5hXTVGLxtTgv48y5ZwSpuuXu+RBuyy5+E6+SFP7zJ3N7 OPxzbbm5iPZujAv1/P8JDrMtXnt145Ik4ubhWD5LKAN1axibRww= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAmygAwIBAgIBCTANBgkqhkiG9w0BAQUFADAzMQswCQYDVQQGEwJDTjER MA8GA1UEChMIVW5pVHJ1c3QxETAPBgNVBAMTCFVDQSBSb290MB4XDTA0MDEwMTAw MDAwMFoXDTI5MTIzMTAwMDAwMFowMzELMAkGA1UEBhMCQ04xETAPBgNVBAoTCFVu aVRydXN0MREwDwYDVQQDEwhVQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBALNdB8qGJn1r4vs4CQ7MgsJqGgCiFV/W6dQBt1YDAVmP9ThpJHbC XivF9iu/r/tB/Q9a/KvXg3BNMJjRnrJ2u5LWu+kQKGkoNkTo8SzXWHwk1n8COvCB a2FgP/Qz3m3l6ihST/ypHWN8C7rqrsRoRuTej8GnsrZYWm0dLNmMOreIy4XU9+gD Xv2yTVDo1h//rgI/i0+WITyb1yXJHT/7mLFZ5PCpO6+zzYUs4mBGzG+OoOvwNMXx QhhgrhLtRnUc5dipllq+3lrWeGeWW5N3UPJuG96WUUqm1ktDdSFmjXfsAoR2XEQQ th1hbOSjIH23jboPkXXHjd+8AmCoKai9PUMCAwEAAaOBojCBnzALBgNVHQ8EBAMC AQYwDAYDVR0TBAUwAwEB/zBjBgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIG CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcD BwYIKwYBBQUHAwgGCCsGAQUFBwMJMB0GA1UdDgQWBBTbHzXza0z/QjFkm827Wh4d SBC37jANBgkqhkiG9w0BAQUFAAOCAQEAOGy3iPGt+lg3dNHocN6cJ1nL5BXXoMNg 14iABMUwTD3UGusGXllH5rxmy+AI/Og17GJ9ysDawXiv5UZv+4mCI4/211NmVaDe JRI7cTYWVRJ2+z34VFsxugAG+H1V5ad2g6pcSpemKijfvcZsCyOVjjN/Hl5AHxNU LJzltQ7dFyiuawHTUin1Ih+QOfTcYmjwPIZH7LgFRbu3DJaUxmfLI3HQjnQi1kHr A6i26r7EARK1s11AdgYg1GS4KUYGis4fk5oQ7vuqWrTcL9Ury/bXBYSYBZELhPc9 +tb5evosFeo2gkO3t7jj83EB7UNDogVFwygFBzXjAaU4HoDU18PZ3g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK 4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv 2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9 hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM 1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws 6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50 aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u 7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0 xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn 0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM //bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t 3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1 NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2 N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1 axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4 ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb QErNaLly7HF27FSOH4UMAWr6pjisH8SE -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3 dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo 5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+ pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU 4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5 81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHqTCCBZGgAwIBAgIQYwaGp8U3ZaVDkKhqWMzUMjANBgkqhkiG9w0BAQUFADCB jzELMAkGA1UEBhMCTFYxNTAzBgNVBAoTLFZBUyBMYXR2aWphcyBQYXN0cyAtIFZp ZW4ucmVnLk5yLjQwMDAzMDUyNzkwMSMwIQYDVQQLExpTZXJ0aWZpa2FjaWphcyBw YWthbHBvanVtaTEkMCIGA1UEAxMbVkFTIExhdHZpamFzIFBhc3RzIFNTSShSQ0Ep MB4XDTA2MDkxMzA5MjIxMFoXDTI0MDkxMzA5Mjc1N1owgY8xCzAJBgNVBAYTAkxW MTUwMwYDVQQKEyxWQVMgTGF0dmlqYXMgUGFzdHMgLSBWaWVuLnJlZy5Oci40MDAw MzA1Mjc5MDEjMCEGA1UECxMaU2VydGlmaWthY2lqYXMgcGFrYWxwb2p1bWkxJDAi BgNVBAMTG1ZBUyBMYXR2aWphcyBQYXN0cyBTU0koUkNBKTCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBAJu4+f1hVS9PpKUUtS6OuSSPrPuxVD9A/0/F5YZo e1OT+zWCNahQLpRSoNuDPnXaFXCsCc/ugkmtNkm5tHGLtAChQgbKCApjl7YI/O60 3Jh4GYLJ+H9kPqrJ/rGN67Bk9bzzxD46kOpOjj8bGbxqg8ORPGxV+wpSwOjhXXeF M8VJ3+xqv79sN/6OSaIVGM6LjmseOKMwb4iBfnJWRBrEejkP9sSPltSy6wBOXN67 5zu35iQFk2tN5pFEv+6YG8eFGxFBeyI2p74+6Ho33BjekJ2PzbLXmj/iF39bDOHv P2Y9biTksM7DDIhslNo4JXxSOeNzFLMARWOaDEJAXgTG93JkzsluM7Pk020klTeT fvIAXRmLH/NDc6ifRdIGqey0Qrv67gzHTz9RH9Gv0KwYf4eBIv6p3QeWbXz4TtlN OlBp1UF+xdp02I5z5X6D4cMZgbe9v0COvi6aogyqTgIuuyrhCF0xA8msJ7Cv3NXI FH1AnVWJIfmQzNTJYEFzq+jN2DpVOQqCmf6b9fU8HJHLwPpGVK4h/CqsXHveepdx /WxrzUiapNuBfBg3L5B9YZS9F8lctlQWd8oJSqrpvE+UdQFaVryS0o+515feVnQB 9xZxSbH1GEaZQe5i4bMsZXVpKXJDA/ibH/o49J7sQBCOrJfVsDO+nxjcLfdBeFRK YkTnAgMBAAGjggH9MIIB+TAOBgNVHQ8BAf8EBAMCAQYwGAYIKwYBBQUHAQMEDDAK MAgGBgQAjkYBATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTMw/Vm/3OsOFqW GyGJuIFMH8teJTAQBgkrBgEEAYI3FQEEAwIBADCCAYkGA1UdIASCAYAwggF8MIIB eAYLKwYBBAGBxFkBAQIwggFnMIIBOAYIKwYBBQUHAgIwggEqHoIBJgBTAGkAcwAg AGkAcgAgAHMAZQByAHQAaQBmAGkAawBhAHQAcwAsACAAawBvACAAaQB6AGQAZQB2 AGkAcwAgAFYAQQBTACAATABhAHQAdgBpAGoAYQBzACAAUABhAHMAdABzACwAIABu AG8AZAByAG8AcwBpAG4AbwB0ACAAYQB0AGIAaQBsAHMAdABpAGIAdQAgAEUAbABl AGsAdAByAG8AbgBpAHMAawBvACAAZABvAGsAdQBtAGUAbgB0AHUAIABsAGkAawB1 AG0AYQBtACAAdQBuACAARQBpAHIAbwBwAGEAcwAgAFAAYQByAGwAYQBtAGUAbgB0 AGEAIABkAGkAcgBlAGsAdABpAHYAYQBpACAAMQA5ADkAOQAvADkAMwAvAEUASzAp BggrBgEFBQcCARYdaHR0cDovL3d3dy5lLW1lLmx2L3JlcG9zaXRvcnkwDQYJKoZI hvcNAQEFBQADggIBAB8oSjWQIWNoCi94r6MegiaXoz8nGdJLo0J6BhNlW8EEy+t9 fO+U8vGJ9bffUgIhadLqljTloM+XuJxVDhCFoxReLAX4tTp28/l6uN62DCdp8suU kQsdudWOb5kvzfIZVjk6SFbwAf+Cdbay/dHU9fJjV0xNoX7MELoEae/0FPyzlx9F 7m9KKH/Rxie8x6Opa3vtghNvq94P+3HrXBEaqSzQMJ/8NjdW75XpurcTtq6fAmGt nuxrBG82nw+Z98LJyEwouSjUIdeeVNXAzvSO5FWUe48kxjj8q3qkVnc9qEXvZJKk 0Ep+u3OL9A1Sc7g6SF5DgNOpcHdi/8coHHMeQ+YnJFtJueY2pI79xS0veqV5EnrX IbIlbcgPosNhS+VI4le6n/KKId3bZPDaGd/OwJuAOcJ3d2MVU3KE+qSPBzeGIX1Q +j1qN9uRDjez/c4Lynth0Jx0nH04aG3pex3W8Sq07ztgUncF5gLCX4xbvPB9t3PH kWuyKrNjozTVq60lcUf/Gj56to2VdsPups0DCWzuRWeYz5lIdsHOinSaaFIBNCLI 7eIUC4S9bhCMsXKbvugI11fVf+q0AT1O5OLoZ+eMfunnQhHvlUbIkda+JxeAGTSY 58bfHvwhX56GPbx+8Jy9cp70R4JbcWfz+txUTKhc2FnH0AcOEzMnvPRp8Gsh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO 8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u 7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te 2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC 4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ +mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c 2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF 9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN /BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz 4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 7M2CYfE45k+XmCpajQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h 2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq 299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd 7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw ++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt 398znM/jra6O1I7mT1GvFpLgXPYHDw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID+TCCAuGgAwIBAgIQW1fXqEywr9nTb0ugMbTW4jANBgkqhkiG9w0BAQUFADB5 MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xKjAoBgNVBAMTIVZpc2EgSW5m b3JtYXRpb24gRGVsaXZlcnkgUm9vdCBDQTAeFw0wNTA2MjcxNzQyNDJaFw0yNTA2 MjkxNzQyNDJaMHkxCzAJBgNVBAYTAlVTMQ0wCwYDVQQKEwRWSVNBMS8wLQYDVQQL EyZWaXNhIEludGVybmF0aW9uYWwgU2VydmljZSBBc3NvY2lhdGlvbjEqMCgGA1UE AxMhVmlzYSBJbmZvcm1hdGlvbiBEZWxpdmVyeSBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyREA4R/QkkfpLx0cYjga/EhIPZpchH0MZsRZ FfP6C2ITtf/Wc+MtgD4yTK0yoiXvni3d+aCtEgK3GDvkdgYrgF76ROJFZwUQjQ9l x42gRT05DbXvWFoy7dTglCZ9z/Tt2Cnktv9oxKgmkeHY/CyfpCBg1S8xth2JlGMR 0ug/GMO5zANuegZOv438p5Lt5So+du2Gl+RMFQqEPwqN5uJSqAe0VtmB4gWdQ8on Bj2ZAM2R73QW7UW0Igt2vA4JaSiNtaAG/Y/58VXWHGgbq7rDtNK1R30X0kJV0rGA ib3RSwB3LpG7bOjbIucV5mQgJoVjoA1e05w6g1x/KmNTmOGRVwIDAQABo30wezAP BgNVHRMBAf8EBTADAQH/MDkGA1UdIAQyMDAwLgYFZ4EDAgEwJTAVBggrBgEFBQcC ARYJMS4yLjMuNC41MAwGCCsGAQUFBwICMAAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud DgQWBBRPitp2/2d3I5qmgH1924h1hfeBejANBgkqhkiG9w0BAQUFAAOCAQEACUW1 QdUHdDJydgDPmYt+telnG/Su+DPaf1cregzlN43bJaJosMP7NwjoJY/H2He4XLWb 5rXEkl+xH1UyUwF7mtaUoxbGxEvt8hPZSTB4da2mzXgwKvXuHyzF5Qjy1hOB0/pS WaF9ARpVKJJ7TOJQdGKBsF2Ty4fSCLqZLgfxbqwMsd9sysXI3rDXjIhekqvbgeLz PqZr+pfgFhwCCLSMQWl5Ll3u7Qk9wR094DZ6jj6+JCVCRUS3HyabH4OlM0Vc2K+j INsF/64Or7GNtRf9HYEJvrPxHINxl3JVwhYj4ASeaO4KwhVbwtw94Tc/XrGcexDo c5lC3rAi4/UZqweYCw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwKgAwIBAgIDAYagMA0GCSqGSIb3DQEBBQUAMIGjMQswCQYDVQQGEwJG STEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0ZXJpa2Vz a3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBTZXJ2aWNl czEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJLIEdvdi4g Um9vdCBDQTAeFw0wMjEyMTgxMzUzMDBaFw0yMzEyMTgxMzUxMDhaMIGjMQswCQYD VQQGEwJGSTEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0 ZXJpa2Vza3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBT ZXJ2aWNlczEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJL IEdvdi4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCF FdrIAzfQo0Y3bBseljDCWoUSZyPyu5/nioFgJ/gTqTy894aqqvTzJSm0/nWuHoGG igWyHWWyOOi0zCia+xc28ZPVec7Bg4shT8MNrUHfeJ1I4x9CRPw8bSEga60ihCRC jxdNwlAfZM0tOSJWiP2yY51U2kJpwMhP1xjiPshphJQ9LIDGfM6911Mf64i5psu7 hVfvV3ZdDIvTXhJBnyHAOfQmbQj6OLOhd7HuFtjQaNq0mKWgZUZKa41+qk1guPjI DfxxPu45h4G02fhukO4/DmHXHSto5i7hQkQmeCxY8n0Wf2HASSQqiYe2XS8pGfim 545SnkFLWg6quMJmQlMCAwEAAaNVMFMwDwYDVR0TAQH/BAUwAwEB/zARBglghkgB hvhCAQEEBAMCAAcwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBTb6eGb0tEkC/yr 46Bn6q6cS3f0sDANBgkqhkiG9w0BAQUFAAOCAQEArX1ID1QRnljurw2bEi8hpM2b uoRH5sklVSPj3xhYKizbXvfNVPVRJHtiZ+GxH0mvNNDrsczZog1Sf0JLiGCXzyVy t08pLWKfT6HAVVdWDsRol5EfnGTCKTIB6dTI2riBmCguGMcs/OubUpbf9MiQGS0j 8/G7cdqehSO9Gu8u5Hp5t8OdhkktY7ktdM9lDzJmid87Ie4pbzlj2RXBbvbfgD5Q eBmK3QOjFKU3p7UsfLYRh+cF8ry23tT/l4EohP7+bEaFEEGfTXWMB9SZZ291im/k UJL2mdUQuMSpe/cXjUu/15WfCdxEDx4yw8DP03kN5Mc7h/CQNIghYkmSBAQfvA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd /ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv 2G0xffX8oRAHh84vWdw+WNs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ O+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/partial-bundle.pem ================================================ -----BEGIN CERTIFICATE----- MIICvzCCAkSgAwIBAgIUEOTb+fwacUOxBc1ryZ3YHHR7hYIwCgYIKoZIzj0EAwMw gYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T YW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0 ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAe Fw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGLMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEG A1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEc MBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTB2MBAGByqGSM49AgEGBSuBBAAi A2IABNYivDDh3Iikkb+3/Oocity4JQXmxLP2njZThYNtR4y7Bxixp05KLoq8gtaz yccDklueu4OWFnpmkjyqPQ+0MIf/BJKoA4Q4iNiCN/ZfF690LR/pZPrMRZuWSGVb 2890L6NmMGQwDgYDVR0PAQH/BAQDAgKkMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYD VR0OBBYEFDmNWkY9a2tS8p4M9RGYi2MJRbo/MB8GA1UdIwQYMBaAFD3f3FiGmOjK KSDupXSse/XS6RdXMAoGCCqGSM49BAMDA2kAMGYCMQCKWVbXphd4qec03igIHUU9 lBIUdzWNwlN5Vy2TzwFW4cqdzOCv2FNOGGutweLezjcCMQCJOR7Q3WbWf7wear2i gaoQjQW55KjDYA5bJjbh+x3MCROR+tcnfdT94ALUN2CKxEk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYDCCAkigAwIBAgIUGkS6ZR3pGG1whBdM98/+hASRNpEwDQYJKoZIhvcNAQEN BQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQL ExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMw EQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNv bTAeFw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGMMQswCQYDVQQGEwJV UzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmlu ZzEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wdjAQBgcqhkjOPQIBBgUr gQQAIgNiAAQhWSM0kbB/cXRdYkfvJBJW3G6gGJ2Lkk2xDsWHERBxkSXdv7/WIXrR MFjZiLorAm4DqcgTvc8hcbJ82FOHDgPwKJltpyRD+5+DPYPK/HJYUM/MuvtNd4z/ TBKn+KajFZ6jZjBkMA4GA1UdDwEB/wQEAwICpDASBgNVHRMBAf8ECDAGAQH/AgEB MB0GA1UdDgQWBBQ939xYhpjoyikg7qV0rHv10ukXVzAfBgNVHSMEGDAWgBSIYLoY pHe4QQQb1e93UcJbFLogPzANBgkqhkiG9w0BAQ0FAAOCAgEAr3FzjsRoTUo5WocP xpUaeS5PPIY5uBmMZQU+JQuCzBTGwAONkzwEZUMHW9SNrD9g7qcWouy+1t4Sz6dJ iKa+6vvo60bJvINELLnbu5Z+t99f7R3PAdcIccQVxPIFxKKq6HYhgDx+jOvCTuGA TXIL9vkYL8rR/9YmMJBp6Re4+sWq97kzRJt7zIU4+pL/3Inx8KUuXlh8K/aa4ShY yRIeAYixnGjDQ8YMVLFyjVeg0wiv+qAkgomi81hts7DUhawzMRC81A6oIwvWNBfB 2CUijERzpBjxmMZwaUOj6yKhGbigt7lxvcSkzJZTJ4s+HE05k9OYnJ8+PF+mo3uS nG2dg/NqIipdh8/9fvHubW3QL7cwbaI7T0lVYkopNkL8TP7gOZjkeNCTvhHun4+7 apjbFeylj8kkTaL6+6Y+7JLGmsD8amuy45Qu/NKqIZyYF/vxBSqi3w2Rm8IwYvQ7 ci2jN+RJvPQVy2hioXyOUzoyBED7GhZjV59i7N62clQ8+g3gxjxF5/lYU6Ok3UEg a6JLchBWgq0y/M4cGtidJCGWdLZAldQtnRb7qj0yt64byy+SECZHHlKroGARu0qv osbE6riZvhmUlnrBDS02LGwG0dni21iERJu56I8ltHaJsZUIu4jOEUBENQwIAULo ZPYOEUU9GGgoGpUdqNtpfZZWmvw= -----END CERTIFICATE----- ================================================ FILE: bundler/testdata/reverse-partial-bundle.pem ================================================ -----BEGIN CERTIFICATE----- MIIEYDCCAkigAwIBAgIUGkS6ZR3pGG1whBdM98/+hASRNpEwDQYJKoZIhvcNAQEN BQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQL ExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMw EQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNv bTAeFw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGMMQswCQYDVQQGEwJV UzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmlu ZzEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wdjAQBgcqhkjOPQIBBgUr gQQAIgNiAAQhWSM0kbB/cXRdYkfvJBJW3G6gGJ2Lkk2xDsWHERBxkSXdv7/WIXrR MFjZiLorAm4DqcgTvc8hcbJ82FOHDgPwKJltpyRD+5+DPYPK/HJYUM/MuvtNd4z/ TBKn+KajFZ6jZjBkMA4GA1UdDwEB/wQEAwICpDASBgNVHRMBAf8ECDAGAQH/AgEB MB0GA1UdDgQWBBQ939xYhpjoyikg7qV0rHv10ukXVzAfBgNVHSMEGDAWgBSIYLoY pHe4QQQb1e93UcJbFLogPzANBgkqhkiG9w0BAQ0FAAOCAgEAr3FzjsRoTUo5WocP xpUaeS5PPIY5uBmMZQU+JQuCzBTGwAONkzwEZUMHW9SNrD9g7qcWouy+1t4Sz6dJ iKa+6vvo60bJvINELLnbu5Z+t99f7R3PAdcIccQVxPIFxKKq6HYhgDx+jOvCTuGA TXIL9vkYL8rR/9YmMJBp6Re4+sWq97kzRJt7zIU4+pL/3Inx8KUuXlh8K/aa4ShY yRIeAYixnGjDQ8YMVLFyjVeg0wiv+qAkgomi81hts7DUhawzMRC81A6oIwvWNBfB 2CUijERzpBjxmMZwaUOj6yKhGbigt7lxvcSkzJZTJ4s+HE05k9OYnJ8+PF+mo3uS nG2dg/NqIipdh8/9fvHubW3QL7cwbaI7T0lVYkopNkL8TP7gOZjkeNCTvhHun4+7 apjbFeylj8kkTaL6+6Y+7JLGmsD8amuy45Qu/NKqIZyYF/vxBSqi3w2Rm8IwYvQ7 ci2jN+RJvPQVy2hioXyOUzoyBED7GhZjV59i7N62clQ8+g3gxjxF5/lYU6Ok3UEg a6JLchBWgq0y/M4cGtidJCGWdLZAldQtnRb7qj0yt64byy+SECZHHlKroGARu0qv osbE6riZvhmUlnrBDS02LGwG0dni21iERJu56I8ltHaJsZUIu4jOEUBENQwIAULo ZPYOEUU9GGgoGpUdqNtpfZZWmvw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICvzCCAkSgAwIBAgIUEOTb+fwacUOxBc1ryZ3YHHR7hYIwCgYIKoZIzj0EAwMw gYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T YW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0 ZW1zIEVuZ2luZWVyaW5nMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAe Fw0xOTA1MDEwMDAwMDBaFw0yODA2MTUwODAwMDBaMIGLMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEG A1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEc MBoGA1UEAxMTY2xvdWRmbGFyZS1sZWFmLmNvbTB2MBAGByqGSM49AgEGBSuBBAAi A2IABNYivDDh3Iikkb+3/Oocity4JQXmxLP2njZThYNtR4y7Bxixp05KLoq8gtaz yccDklueu4OWFnpmkjyqPQ+0MIf/BJKoA4Q4iNiCN/ZfF690LR/pZPrMRZuWSGVb 2890L6NmMGQwDgYDVR0PAQH/BAQDAgKkMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYD VR0OBBYEFDmNWkY9a2tS8p4M9RGYi2MJRbo/MB8GA1UdIwQYMBaAFD3f3FiGmOjK KSDupXSse/XS6RdXMAoGCCqGSM49BAMDA2kAMGYCMQCKWVbXphd4qec03igIHUU9 lBIUdzWNwlN5Vy2TzwFW4cqdzOCv2FNOGGutweLezjcCMQCJOR7Q3WbWf7wear2i gaoQjQW55KjDYA5bJjbh+x3MCROR+tcnfdT94ALUN2CKxEk= -----END CERTIFICATE----- ================================================ FILE: certdb/README.md ================================================ # certdb usage Using a database enables additional functionality for existing commands when a db config is provided: - `sign` and `gencert` add a certificate to the certdb after signing it - `serve` enables database functionality for the sign and revoke endpoints A database is required for the following: - `revoke` marks certificates revoked in the database with an optional reason - `ocsprefresh` refreshes the table of cached OCSP responses - `ocspdump` outputs cached OCSP responses in a concatenated base64-encoded format ## Setup/Migration This directory stores [goose](https://bitbucket.org/liamstask/goose/) db migration scripts for various DB backends. Currently supported: - MySQL in mysql - PostgreSQL in pg - SQLite in sqlite ### Get goose go get bitbucket.org/liamstask/goose/cmd/goose ### Use goose to start and terminate a MySQL DB To start a MySQL using goose: goose -path certdb/mysql up To tear down a MySQL DB using goose goose -path certdb/mysql down Note: the administration of MySQL DB is not included. We assume the databases being connected to are already created and access control is properly handled. ### Use goose to start and terminate a PostgreSQL DB To start a PostgreSQL using goose: goose -path certdb/pg up To tear down a PostgreSQL DB using goose goose -path certdb/pg down Note: the administration of PostgreSQL DB is not included. We assume the databases being connected to are already created and access control is properly handled. ### Use goose to start and terminate a SQLite DB To start a SQLite DB using goose: goose -path certdb/sqlite up To tear down a SQLite DB using goose goose -path certdb/sqlite down ## CFSSL Configuration Several cfssl commands take a -db-config flag. Create a file with a JSON dictionary: {"driver":"sqlite3","data_source":"certs.db"} or {"driver":"postgres","data_source":"postgres://user:password@host/db"} or {"driver":"mysql","data_source":"user:password@tcp(hostname:3306)/db?parseTime=true"} ================================================ FILE: certdb/certdb.go ================================================ package certdb import ( "database/sql" "encoding/json" "time" "github.com/jmoiron/sqlx/types" ) // CertificateRecord encodes a certificate and its metadata // that will be recorded in a database. type CertificateRecord struct { Serial string `db:"serial_number"` AKI string `db:"authority_key_identifier"` CALabel string `db:"ca_label"` Status string `db:"status"` Reason int `db:"reason"` Expiry time.Time `db:"expiry"` RevokedAt time.Time `db:"revoked_at"` PEM string `db:"pem"` // the following fields will be empty for data inserted before migrate 002 has been run. IssuedAt *time.Time `db:"issued_at"` NotBefore *time.Time `db:"not_before"` MetadataJSON types.JSONText `db:"metadata"` SANsJSON types.JSONText `db:"sans"` CommonName sql.NullString `db:"common_name"` } // SetMetadata sets the metadata json func (c *CertificateRecord) SetMetadata(meta map[string]interface{}) error { marshaled, err := json.Marshal(meta) if err != nil { return err } c.MetadataJSON = types.JSONText(marshaled) return nil } // GetMetadata returns the json metadata func (c *CertificateRecord) GetMetadata() (map[string]interface{}, error) { var meta map[string]interface{} err := c.MetadataJSON.Unmarshal(&meta) return meta, err } // SetSANs sets the list of sans func (c *CertificateRecord) SetSANs(meta []string) error { marshaled, err := json.Marshal(meta) if err != nil { return err } c.SANsJSON = types.JSONText(marshaled) return nil } // GetSANs returns the json SANs func (c *CertificateRecord) GetSANs() ([]string, error) { var sans []string err := c.SANsJSON.Unmarshal(&sans) return sans, err } // OCSPRecord encodes a OCSP response body and its metadata // that will be recorded in a database. type OCSPRecord struct { Serial string `db:"serial_number"` AKI string `db:"authority_key_identifier"` Body string `db:"body"` Expiry time.Time `db:"expiry"` } // Accessor abstracts the CRUD of certdb objects from a DB. type Accessor interface { InsertCertificate(cr CertificateRecord) error GetCertificate(serial, aki string) ([]CertificateRecord, error) GetUnexpiredCertificates() ([]CertificateRecord, error) GetRevokedAndUnexpiredCertificates() ([]CertificateRecord, error) GetUnexpiredCertificatesByLabel(labels []string) (crs []CertificateRecord, err error) GetRevokedAndUnexpiredCertificatesByLabel(label string) ([]CertificateRecord, error) GetRevokedAndUnexpiredCertificatesByLabelSelectColumns(label string) ([]CertificateRecord, error) RevokeCertificate(serial, aki string, reasonCode int) error InsertOCSP(rr OCSPRecord) error GetOCSP(serial, aki string) ([]OCSPRecord, error) GetUnexpiredOCSPs() ([]OCSPRecord, error) UpdateOCSP(serial, aki, body string, expiry time.Time) error UpsertOCSP(serial, aki, body string, expiry time.Time) error } ================================================ FILE: certdb/dbconf/db_config.go ================================================ package dbconf import ( "encoding/json" "errors" "os" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/log" "github.com/jmoiron/sqlx" ) // DBConfig contains the database driver name and configuration to be passed to Open type DBConfig struct { DriverName string `json:"driver"` DataSourceName string `json:"data_source"` } // LoadFile attempts to load the db configuration file stored at the path // and returns the configuration. On error, it returns nil. func LoadFile(path string) (cfg *DBConfig, err error) { log.Debugf("loading db configuration file from %s", path) if path == "" { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path")) } var body []byte body, err = os.ReadFile(path) if err != nil { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file")) } cfg = &DBConfig{} err = json.Unmarshal(body, &cfg) if err != nil { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to unmarshal configuration: "+err.Error())) } if cfg.DataSourceName == "" || cfg.DriverName == "" { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid db configuration")) } return } // DBFromConfig opens a sql.DB from settings in a db config file func DBFromConfig(path string) (db *sqlx.DB, err error) { var dbCfg *DBConfig dbCfg, err = LoadFile(path) if err != nil { return nil, err } return sqlx.Open(dbCfg.DriverName, dbCfg.DataSourceName) } ================================================ FILE: certdb/dbconf/db_config_test.go ================================================ package dbconf import ( "testing" _ "github.com/mattn/go-sqlite3" // import just to initialize SQLite testing ) func TestLoadFile(t *testing.T) { config, err := LoadFile("testdata/db-config.json") if err != nil || config == nil { t.Fatal("Failed to load test db-config file ", err) } config, err = LoadFile("nonexistent") if err == nil || config != nil { t.Fatal("Expected failure loading nonexistent configuration file") } } func TestDBFromConfig(t *testing.T) { db, err := DBFromConfig("testdata/db-config.json") if err != nil || db == nil { t.Fatal("Failed to open db from test db-config file") } db, err = DBFromConfig("testdata/bad-db-config.json") if err == nil || db != nil { t.Fatal("Expected failure opening invalid db") } db, err = DBFromConfig("testdata/unreachable-db-config.json") if err == nil || db != nil { t.Fatal("Expected failure opening unreachable db") } } ================================================ FILE: certdb/dbconf/testdata/bad-db-config.json ================================================ {"driver":"invalid","data_source":"invalid"} ================================================ FILE: certdb/dbconf/testdata/db-config.json ================================================ {"driver":"sqlite3","data_source":"certs.db"} ================================================ FILE: certdb/dbconf/testdata/memory_db.json ================================================ {"driver":"sqlite3","data_source":":memory:"} ================================================ FILE: certdb/mysql/dbconf.yml ================================================ development: driver: mysql open: root@tcp(localhost:3306)/certdb_development?parseTime=true test: driver: mysql open: root@tcp(localhost:3306)/certdb_test?parseTime=true staging: driver: mysql open: root@tcp(localhost:3306)/certdb_staging?parseTime=true production: driver: mysql open: root@tcp(localhost:3306)/certdb_production?parseTime=true ================================================ FILE: certdb/mysql/migrations/001_CreateCertificates.sql ================================================ -- +goose Up -- SQL in section 'Up' is executed when this migration is applied CREATE TABLE certificates ( serial_number varbinary(128) NOT NULL, authority_key_identifier varbinary(128) NOT NULL, ca_label varbinary(128), status varbinary(128) NOT NULL, reason int, expiry timestamp DEFAULT '0000-00-00 00:00:00', revoked_at timestamp DEFAULT '0000-00-00 00:00:00', pem varbinary(4096) NOT NULL, PRIMARY KEY(serial_number, authority_key_identifier) ); CREATE TABLE ocsp_responses ( serial_number varbinary(128) NOT NULL, authority_key_identifier varbinary(128) NOT NULL, body varbinary(4096) NOT NULL, expiry timestamp DEFAULT '0000-00-00 00:00:00', PRIMARY KEY(serial_number, authority_key_identifier) ); -- +goose Down -- SQL section 'Down' is executed when this migration is rolled back DROP TABLE certificates; DROP TABLE ocsp_responses; ================================================ FILE: certdb/mysql/migrations/002_AddMetadataToCertificates.sql ================================================ -- +goose Up -- SQL in section 'Up' is executed when this migration is applied ALTER TABLE certificates ADD COLUMN issued_at timestamp DEFAULT '0000-00-00 00:00:00', ADD COLUMN not_before timestamp DEFAULT '0000-00-00 00:00:00', ADD COLUMN metadata JSON, ADD COLUMN sans JSON, ADD COLUMN common_name TEXT; -- +goose Down -- SQL section 'Down' is executed when this migration is rolled back ALTER TABLE certificates DROP COLUMN issued_at, DROP COLUMN not_before, DROP COLUMN metadata, DROP COLUMN sans, DROP COLUMN common_name; ================================================ FILE: certdb/ocspstapling/ocspstapling.go ================================================ // Package ocspstapling implements OCSP stapling of Signed Certificate // Timestamps (SCTs) into OCSP responses in a database. See RFC 6962. package ocspstapling import ( "crypto" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/base64" "errors" "github.com/cloudflare/cfssl/certdb" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" ct "github.com/google/certificate-transparency-go" "golang.org/x/crypto/ocsp" ) // sctExtOid is the OID of the OCSP Stapling SCT extension (see section 3.3. of RFC 6962). var sctExtOid = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5} // StapleSCTList inserts a list of Signed Certificate Timestamps into all OCSP // responses in a database wrapped by a given certdb.Accessor. // // NOTE: This function is patterned after the exported Sign method in // https://github.com/cloudflare/cfssl/blob/master/signer/local/local.go func StapleSCTList(acc certdb.Accessor, serial, aki string, scts []ct.SignedCertificateTimestamp, responderCert, issuer *x509.Certificate, priv crypto.Signer) error { ocspRecs, err := acc.GetOCSP(serial, aki) if err != nil { return err } if len(ocspRecs) == 0 { return cferr.Wrap(cferr.CertStoreError, cferr.RecordNotFound, errors.New("empty OCSPRecord")) } // This loop adds the SCTs to each OCSP response in ocspRecs. for _, rec := range ocspRecs { der, err := base64.StdEncoding.DecodeString(rec.Body) if err != nil { return cferr.Wrap(cferr.CertificateError, cferr.DecodeFailed, errors.New("failed to decode Base64-encoded OCSP response")) } response, err := ocsp.ParseResponse(der, nil) if err != nil { return cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("failed to parse DER-encoded OCSP response")) } serializedSCTList, err := helpers.SerializeSCTList(scts) if err != nil { return cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("failed to serialize SCT list")) } serializedSCTList, err = asn1.Marshal(serializedSCTList) if err != nil { return cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("failed to serialize SCT list")) } sctExtension := pkix.Extension{ Id: sctExtOid, Critical: false, Value: serializedSCTList, } // This loop finds the SCTListExtension in the ocsp response. var idxExt int for _, ext := range response.Extensions { if ext.Id.Equal(sctExtOid) { break } idxExt++ } newExtensions := make([]pkix.Extension, len(response.Extensions)) copy(newExtensions, response.Extensions) if idxExt >= len(response.Extensions) { // No SCT extension was found. newExtensions = append(newExtensions, sctExtension) } else { newExtensions[idxExt] = sctExtension } // Here we write the updated extensions to replace the old // response extensions when re-marshalling. newSN := *response.SerialNumber template := ocsp.Response{ Status: response.Status, SerialNumber: &newSN, ThisUpdate: response.ThisUpdate, NextUpdate: response.NextUpdate, Certificate: response.Certificate, ExtraExtensions: newExtensions, IssuerHash: response.IssuerHash, } // Finally, we re-sign the response to generate the new // DER-encoded response. der, err = ocsp.CreateResponse(issuer, responderCert, template, priv) if err != nil { return cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("failed to sign new OCSP response")) } body := base64.StdEncoding.EncodeToString(der) err = acc.UpdateOCSP(serial, aki, body, rec.Expiry) if err != nil { return err } } return nil } ================================================ FILE: certdb/ocspstapling/ocspstapling_test.go ================================================ package ocspstapling import ( "bytes" "crypto" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/base64" "math/big" "os" "testing" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/cloudflare/cfssl/helpers" ct "github.com/google/certificate-transparency-go" "golang.org/x/crypto/ocsp" ) func TestStapleSCTList(t *testing.T) { t.Skip("broken relating to https://github.com/cloudflare/cfssl/issues/1230") // issuer is a CA certificate. issuer, issuerPrivKey, err := makeCert(nil) if err != nil { t.Fatal(err) } // responderCert is a certificate for which to make an OCSP response. responderCert, _, err := makeCert(issuer) if err != nil { t.Fatal(err) } template := ocsp.Response{ SerialNumber: responderCert.SerialNumber, IssuerHash: crypto.SHA256, Status: ocsp.Good, } // respDER is an OCSP response to be added to the database. respDER, err := ocsp.CreateResponse(issuer, responderCert, template, issuerPrivKey) if err != nil { t.Fatal(err) } // testDB is an empty DB of OCSP responses. pwd, err := os.Getwd() if err != nil { t.Fatal(err) } dbPath := pwd + "/../testdb/certstore_development.db" testDB := sql.NewAccessor(testdb.SQLiteDB(dbPath)) // Next, we store the OCSP response in the DB. respSN := responderCert.SerialNumber.Text(16) testDB.InsertOCSP(certdb.OCSPRecord{ Serial: respSN, Body: base64.StdEncoding.EncodeToString(respDER), AKI: "Cornell CS 5152", }) var zeroSCT ct.SignedCertificateTimestamp err = StapleSCTList(testDB, respSN, "Cornell CS 5152", []ct.SignedCertificateTimestamp{zeroSCT}, responderCert, issuer, issuerPrivKey) if err != nil { t.Fatal(err) } // Lastly, we verify that the SCT was inserted. recs, err := testDB.GetOCSP(respSN, "Cornell CS 5152") if err != nil { t.Fatal(err) } if len(recs) == 0 { t.Fatal("SCT could not be retrieved from DB:", zeroSCT) } respDER, err = base64.StdEncoding.DecodeString(recs[0].Body) if err != nil { t.Fatal(err) } response, err := ocsp.ParseResponse(respDER, issuer) if err != nil { t.Fatal(err) } scts, err := helpers.SCTListFromOCSPResponse(response) if err != nil { t.Fatal(err) } if len(scts) == 0 { t.Fatal("No SCTs in OCSP response:", response) } // Here, we check the equivalence of the SCT we inserted with the SCT // returned by SCTListFromOCSPResponse. // sctEquals returns true if all fields of both SCTs are equivalent. sctEquals := func(sctA, sctB ct.SignedCertificateTimestamp) bool { if sctA.SCTVersion == sctB.SCTVersion && sctA.LogID == sctB.LogID && sctA.Timestamp == sctB.Timestamp && bytes.Equal(sctA.Extensions, sctB.Extensions) && sctA.Signature.Algorithm == sctB.Signature.Algorithm && bytes.Equal(sctA.Signature.Signature, sctA.Signature.Signature) { return true } return false } if !sctEquals(scts[0], zeroSCT) { t.Fatal("SCTs do not match:", "\nGot --", scts[0], "\nExpected --", zeroSCT) } } // serialCounter stores the next serial number to be issued by nextSN. var serialCounter int64 // nextSN returns a new big.Int for creating x509 certificates. func nextSN() *big.Int { i := big.NewInt(serialCounter) serialCounter++ return i } // makeCert returns a new x509 certificate with the given issuer certificate. // If issuer is nil, the certificate is self-signed. func makeCert(issuer *x509.Certificate) (*x509.Certificate, crypto.Signer, error) { // Create a new private key privKey, err := rsa.GenerateKey(rand.Reader, 1024) if err != nil { return nil, nil, err } template := x509.Certificate{ SerialNumber: nextSN(), Subject: pkix.Name{ Organization: []string{"Cornell CS 5152"}, }, AuthorityKeyId: []byte{42, 42, 42, 42}, } if issuer == nil { // the cert is self-signed issuer = &template } der, err := x509.CreateCertificate(rand.Reader, &template, issuer, privKey.Public(), privKey) if err != nil { return nil, nil, err } cert, err := x509.ParseCertificate(der) if err != nil { return nil, nil, err } return cert, privKey, nil } ================================================ FILE: certdb/pg/dbconf.yml ================================================ development: driver: postgres open: dbname=certdb_development sslmode=disable user=postgres test: driver: postgres open: dbname=certdb_test sslmode=disable staging: driver: postgres open: dbname=certdb_staging sslmode=disable production: driver: postgres open: dbname=certdb_production sslmode=disable ================================================ FILE: certdb/pg/migrations/001_CreateCertificates.sql ================================================ -- +goose Up -- SQL in section 'Up' is executed when this migration is applied CREATE TABLE certificates ( serial_number bytea NOT NULL, authority_key_identifier bytea NOT NULL, ca_label bytea, status bytea NOT NULL, reason int, expiry timestamptz, revoked_at timestamptz, pem bytea NOT NULL, PRIMARY KEY(serial_number, authority_key_identifier) ); CREATE TABLE ocsp_responses ( serial_number bytea NOT NULL, authority_key_identifier bytea NOT NULL, body bytea NOT NULL, expiry timestamptz, PRIMARY KEY(serial_number, authority_key_identifier), FOREIGN KEY(serial_number, authority_key_identifier) REFERENCES certificates(serial_number, authority_key_identifier) ); -- +goose Down -- SQL section 'Down' is executed when this migration is rolled back DROP TABLE ocsp_responses; DROP TABLE certificates; ================================================ FILE: certdb/pg/migrations/002_AddMetadataToCertificates.sql ================================================ -- +goose Up -- SQL in section 'Up' is executed when this migration is applied ALTER TABLE certificates ADD COLUMN issued_at timestamptz, ADD COLUMN not_before timestamptz, ADD COLUMN metadata jsonb, ADD COLUMN sans jsonb, ADD COLUMN common_name TEXT; -- +goose Down -- SQL section 'Down' is executed when this migration is rolled back ALTER TABLE certificates DROP COLUMN issued_at, DROP COLUMN not_before, DROP COLUMN metadata, DROP COLUMN sans, DROP COLUMN common_name; ================================================ FILE: certdb/sql/database_accessor.go ================================================ package sql import ( "errors" "fmt" "time" "github.com/cloudflare/cfssl/certdb" cferr "github.com/cloudflare/cfssl/errors" "github.com/jmoiron/sqlx" "github.com/kisielk/sqlstruct" ) // Match to sqlx func init() { sqlstruct.TagName = "db" } const ( insertSQL = ` INSERT INTO certificates (serial_number, authority_key_identifier, ca_label, status, reason, expiry, revoked_at, pem, issued_at, not_before, metadata, sans, common_name) VALUES (:serial_number, :authority_key_identifier, :ca_label, :status, :reason, :expiry, :revoked_at, :pem, :issued_at, :not_before, :metadata, :sans, :common_name);` selectSQL = ` SELECT %s FROM certificates WHERE (serial_number = ? AND authority_key_identifier = ?);` selectAllUnexpiredSQL = ` SELECT %s FROM certificates WHERE CURRENT_TIMESTAMP < expiry;` selectAllRevokedAndUnexpiredWithLabelSQL = ` SELECT %s FROM certificates WHERE CURRENT_TIMESTAMP < expiry AND status='revoked' AND ca_label= ?;` selectRevokedAndUnexpiredWithLabelSQL = ` SELECT serial_number, revoked_at FROM certificates WHERE CURRENT_TIMESTAMP < expiry AND status='revoked' AND ca_label= ?;` selectAllRevokedAndUnexpiredSQL = ` SELECT %s FROM certificates WHERE CURRENT_TIMESTAMP < expiry AND status='revoked';` updateRevokeSQL = ` UPDATE certificates SET status='revoked', revoked_at=CURRENT_TIMESTAMP, reason=:reason WHERE (serial_number = :serial_number AND authority_key_identifier = :authority_key_identifier);` insertOCSPSQL = ` INSERT INTO ocsp_responses (serial_number, authority_key_identifier, body, expiry) VALUES (:serial_number, :authority_key_identifier, :body, :expiry);` updateOCSPSQL = ` UPDATE ocsp_responses SET body = :body, expiry = :expiry WHERE (serial_number = :serial_number AND authority_key_identifier = :authority_key_identifier);` selectAllUnexpiredOCSPSQL = ` SELECT %s FROM ocsp_responses WHERE CURRENT_TIMESTAMP < expiry;` selectOCSPSQL = ` SELECT %s FROM ocsp_responses WHERE (serial_number = ? AND authority_key_identifier = ?);` ) // Accessor implements certdb.Accessor interface. type Accessor struct { db *sqlx.DB } var _ certdb.Accessor = &Accessor{} func wrapSQLError(err error) error { if err != nil { return cferr.Wrap(cferr.CertStoreError, cferr.Unknown, err) } return nil } func (d *Accessor) checkDB() error { if d.db == nil { return cferr.Wrap(cferr.CertStoreError, cferr.Unknown, errors.New("unknown db object, please check SetDB method")) } return nil } // NewAccessor returns a new Accessor. func NewAccessor(db *sqlx.DB) *Accessor { return &Accessor{db: db} } // SetDB changes the underlying sql.DB object Accessor is manipulating. func (d *Accessor) SetDB(db *sqlx.DB) { d.db = db return } // InsertCertificate puts a certdb.CertificateRecord into db. func (d *Accessor) InsertCertificate(cr certdb.CertificateRecord) error { err := d.checkDB() if err != nil { return err } var issuedAt, notBefore *time.Time if cr.IssuedAt != nil { t := cr.IssuedAt.UTC() issuedAt = &t } if cr.NotBefore != nil { t := cr.NotBefore.UTC() notBefore = &t } res, err := d.db.NamedExec(insertSQL, &certdb.CertificateRecord{ Serial: cr.Serial, AKI: cr.AKI, CALabel: cr.CALabel, Status: cr.Status, Reason: cr.Reason, Expiry: cr.Expiry.UTC(), RevokedAt: cr.RevokedAt.UTC(), PEM: cr.PEM, IssuedAt: issuedAt, NotBefore: notBefore, MetadataJSON: cr.MetadataJSON, SANsJSON: cr.SANsJSON, CommonName: cr.CommonName, }) if err != nil { return wrapSQLError(err) } numRowsAffected, err := res.RowsAffected() if numRowsAffected == 0 { return cferr.Wrap(cferr.CertStoreError, cferr.InsertionFailed, fmt.Errorf("failed to insert the certificate record")) } if numRowsAffected != 1 { return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected)) } return err } // GetCertificate gets a certdb.CertificateRecord indexed by serial. func (d *Accessor) GetCertificate(serial, aki string) (crs []certdb.CertificateRecord, err error) { err = d.checkDB() if err != nil { return nil, err } err = d.db.Select(&crs, fmt.Sprintf(d.db.Rebind(selectSQL), sqlstruct.Columns(certdb.CertificateRecord{})), serial, aki) if err != nil { return nil, wrapSQLError(err) } return crs, nil } // GetUnexpiredCertificates gets all unexpired certificate from db. func (d *Accessor) GetUnexpiredCertificates() (crs []certdb.CertificateRecord, err error) { err = d.checkDB() if err != nil { return nil, err } err = d.db.Select(&crs, fmt.Sprintf(d.db.Rebind(selectAllUnexpiredSQL), sqlstruct.Columns(certdb.CertificateRecord{}))) if err != nil { return nil, wrapSQLError(err) } return crs, nil } // GetUnexpiredCertificatesByLabel gets all unexpired certificate from db that have the provided label. func (d *Accessor) GetUnexpiredCertificatesByLabel(labels []string) (crs []certdb.CertificateRecord, err error) { err = d.checkDB() if err != nil { return nil, err } query, args, err := sqlx.In( fmt.Sprintf(`SELECT %s FROM certificates WHERE CURRENT_TIMESTAMP < expiry AND ca_label IN (?)`, sqlstruct.Columns(certdb.CertificateRecord{}), ), labels) if err != nil { return nil, wrapSQLError(err) } err = d.db.Select(&crs, d.db.Rebind(query), args...) if err != nil { return nil, wrapSQLError(err) } return crs, nil } // GetRevokedAndUnexpiredCertificates gets all revoked and unexpired certificate from db (for CRLs). func (d *Accessor) GetRevokedAndUnexpiredCertificates() (crs []certdb.CertificateRecord, err error) { err = d.checkDB() if err != nil { return nil, err } err = d.db.Select(&crs, fmt.Sprintf(d.db.Rebind(selectAllRevokedAndUnexpiredSQL), sqlstruct.Columns(certdb.CertificateRecord{}))) if err != nil { return nil, wrapSQLError(err) } return crs, nil } // GetRevokedAndUnexpiredCertificatesByLabel gets all revoked and unexpired certificate from db (for CRLs) with specified ca_label. func (d *Accessor) GetRevokedAndUnexpiredCertificatesByLabel(label string) (crs []certdb.CertificateRecord, err error) { err = d.checkDB() if err != nil { return nil, err } err = d.db.Select(&crs, fmt.Sprintf(d.db.Rebind(selectAllRevokedAndUnexpiredWithLabelSQL), sqlstruct.Columns(certdb.CertificateRecord{})), label) if err != nil { return nil, wrapSQLError(err) } return crs, nil } // GetRevokedAndUnexpiredCertificatesSelectColumnsByLabel gets serial_number and revoed_at from all revoked and unexpired certificate from db (for CRLs) with specified ca_label. func (d *Accessor) GetRevokedAndUnexpiredCertificatesByLabelSelectColumns(label string) (crs []certdb.CertificateRecord, err error) { err = d.checkDB() if err != nil { return nil, err } err = d.db.Select(&crs, d.db.Rebind(selectRevokedAndUnexpiredWithLabelSQL), label) if err != nil { return nil, wrapSQLError(err) } return crs, nil } // RevokeCertificate updates a certificate with a given serial number and marks it revoked. func (d *Accessor) RevokeCertificate(serial, aki string, reasonCode int) error { err := d.checkDB() if err != nil { return err } result, err := d.db.NamedExec(updateRevokeSQL, &certdb.CertificateRecord{ AKI: aki, Reason: reasonCode, Serial: serial, }) if err != nil { return wrapSQLError(err) } numRowsAffected, err := result.RowsAffected() if numRowsAffected == 0 { return cferr.Wrap(cferr.CertStoreError, cferr.RecordNotFound, fmt.Errorf("failed to revoke the certificate: certificate not found")) } if numRowsAffected != 1 { return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected)) } return err } // InsertOCSP puts a new certdb.OCSPRecord into the db. func (d *Accessor) InsertOCSP(rr certdb.OCSPRecord) error { err := d.checkDB() if err != nil { return err } result, err := d.db.NamedExec(insertOCSPSQL, &certdb.OCSPRecord{ AKI: rr.AKI, Body: rr.Body, Expiry: rr.Expiry.UTC(), Serial: rr.Serial, }) if err != nil { return wrapSQLError(err) } numRowsAffected, err := result.RowsAffected() if numRowsAffected == 0 { return cferr.Wrap(cferr.CertStoreError, cferr.InsertionFailed, fmt.Errorf("failed to insert the OCSP record")) } if numRowsAffected != 1 { return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected)) } return err } // GetOCSP retrieves a certdb.OCSPRecord from db by serial. func (d *Accessor) GetOCSP(serial, aki string) (ors []certdb.OCSPRecord, err error) { err = d.checkDB() if err != nil { return nil, err } err = d.db.Select(&ors, fmt.Sprintf(d.db.Rebind(selectOCSPSQL), sqlstruct.Columns(certdb.OCSPRecord{})), serial, aki) if err != nil { return nil, wrapSQLError(err) } return ors, nil } // GetUnexpiredOCSPs retrieves all unexpired certdb.OCSPRecord from db. func (d *Accessor) GetUnexpiredOCSPs() (ors []certdb.OCSPRecord, err error) { err = d.checkDB() if err != nil { return nil, err } err = d.db.Select(&ors, fmt.Sprintf(d.db.Rebind(selectAllUnexpiredOCSPSQL), sqlstruct.Columns(certdb.OCSPRecord{}))) if err != nil { return nil, wrapSQLError(err) } return ors, nil } // UpdateOCSP updates a ocsp response record with a given serial number. func (d *Accessor) UpdateOCSP(serial, aki, body string, expiry time.Time) error { err := d.checkDB() if err != nil { return err } result, err := d.db.NamedExec(updateOCSPSQL, &certdb.OCSPRecord{ AKI: aki, Body: body, Expiry: expiry.UTC(), Serial: serial, }) if err != nil { return wrapSQLError(err) } numRowsAffected, err := result.RowsAffected() if numRowsAffected == 0 { return cferr.Wrap(cferr.CertStoreError, cferr.RecordNotFound, fmt.Errorf("failed to update the OCSP record")) } if numRowsAffected != 1 { return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected)) } return err } // UpsertOCSP update a ocsp response record with a given serial number, // or insert the record if it doesn't yet exist in the db // Implementation note: // We didn't implement 'upsert' with SQL statement and we lost race condition // prevention provided by underlying DBMS. // Reasoning: // 1. it's difficult to support multiple DBMS backends in the same time, the // SQL syntax differs from one to another. // 2. we don't need a strict simultaneous consistency between OCSP and certificate // status. It's OK that a OCSP response still shows 'good' while the // corresponding certificate is being revoked seconds ago, as long as the OCSP // response catches up to be eventually consistent (within hours to days). // Write race condition between OCSP writers on OCSP table is not a problem, // since we don't have write race condition on Certificate table and OCSP // writers should periodically use Certificate table to update OCSP table // to catch up. func (d *Accessor) UpsertOCSP(serial, aki, body string, expiry time.Time) error { err := d.checkDB() if err != nil { return err } result, err := d.db.NamedExec(updateOCSPSQL, &certdb.OCSPRecord{ AKI: aki, Body: body, Expiry: expiry.UTC(), Serial: serial, }) if err != nil { return wrapSQLError(err) } numRowsAffected, err := result.RowsAffected() if numRowsAffected == 0 { return d.InsertOCSP(certdb.OCSPRecord{Serial: serial, AKI: aki, Body: body, Expiry: expiry}) } if numRowsAffected != 1 { return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected)) } return err } ================================================ FILE: certdb/sql/sql_mysql_test.go ================================================ //go:build mysql // +build mysql package sql import ( "testing" "github.com/cloudflare/cfssl/certdb/testdb" ) func TestMySQL(t *testing.T) { db := testdb.MySQLDB() ta := TestAccessor{ Accessor: NewAccessor(db), DB: db, } testEverything(ta, t) } ================================================ FILE: certdb/sql/sql_pq_test.go ================================================ //go:build postgresql // +build postgresql package sql import ( "testing" "github.com/cloudflare/cfssl/certdb/testdb" ) func TestPostgreSQL(t *testing.T) { db := testdb.PostgreSQLDB() ta := TestAccessor{ Accessor: NewAccessor(db), DB: db, } testEverything(ta, t) } ================================================ FILE: certdb/sql/sql_test.go ================================================ package sql import ( "math" "reflect" "testing" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/jmoiron/sqlx" ) const ( sqliteDBFile = "../testdb/certstore_development.db" fakeAKI = "fake_aki" ) func TestNoDB(t *testing.T) { dba := &Accessor{} _, err := dba.GetCertificate("foobar serial", "random aki") if err == nil { t.Fatal("should return error") } } type TestAccessor struct { Accessor certdb.Accessor DB *sqlx.DB } func (ta *TestAccessor) Truncate() { testdb.Truncate(ta.DB) } func TestSQLite(t *testing.T) { db := testdb.SQLiteDB(sqliteDBFile) ta := TestAccessor{ Accessor: NewAccessor(db), DB: db, } testEverything(ta, t) } // roughlySameTime decides if t1 and t2 are close enough. func roughlySameTime(t1, t2 time.Time) bool { // return true if the difference is smaller than 1 sec. return math.Abs(float64(t1.Sub(t2))) < float64(time.Second) } func testEverything(ta TestAccessor, t *testing.T) { testInsertCertificateAndGetCertificate(ta, t) testInsertCertificateAndGetUnexpiredCertificate(ta, t) testInsertCertificateAndGetUnexpiredCertificateNullCommonName(ta, t) testUpdateCertificateAndGetCertificate(ta, t) testInsertOCSPAndGetOCSP(ta, t) testInsertOCSPAndGetUnexpiredOCSP(ta, t) testUpdateOCSPAndGetOCSP(ta, t) testUpsertOCSPAndGetOCSP(ta, t) } func testInsertCertificateAndGetCertificate(ta TestAccessor, t *testing.T) { ta.Truncate() expiry := time.Date(2010, time.December, 25, 23, 0, 0, 0, time.UTC) want := certdb.CertificateRecord{ PEM: "fake cert data", Serial: "fake serial", AKI: fakeAKI, Status: "good", Reason: 0, Expiry: expiry, } want.SetMetadata(map[string]interface{}{"k": "v"}) if err := ta.Accessor.InsertCertificate(want); err != nil { t.Fatal(err) } rets, err := ta.Accessor.GetCertificate(want.Serial, want.AKI) if err != nil { t.Fatal(err) } if len(rets) != 1 { t.Fatal("should only return one record.") } got := rets[0] // reflection comparison with zero time objects are not stable as it seems if want.Serial != got.Serial || want.Status != got.Status || want.AKI != got.AKI || !got.RevokedAt.IsZero() || want.PEM != got.PEM || !roughlySameTime(got.Expiry, expiry) { t.Errorf("want Certificate %+v, got %+v", want, got) } gotMeta, err := got.GetMetadata() if err != nil { t.Fatal(err) } expected := map[string]interface{}{"k": "v"} if !reflect.DeepEqual(gotMeta, expected) { t.Fatalf("expected: %+v, got: %+v", expected, gotMeta) } unexpired, err := ta.Accessor.GetUnexpiredCertificates() if err != nil { t.Fatal(err) } if len(unexpired) != 0 { t.Error("should not have unexpired certificate record") } } func testInsertCertificateAndGetUnexpiredCertificate(ta TestAccessor, t *testing.T) { ta.Truncate() expiry := time.Now().Add(time.Minute) want := certdb.CertificateRecord{ PEM: "fake cert data", Serial: "fake serial 2", AKI: fakeAKI, Status: "good", Reason: 0, Expiry: expiry, CALabel: "foo", } if err := ta.Accessor.InsertCertificate(want); err != nil { t.Fatal(err) } rets, err := ta.Accessor.GetCertificate(want.Serial, want.AKI) if err != nil { t.Fatal(err) } if len(rets) != 1 { t.Fatal("should return exactly one record") } got := rets[0] // reflection comparison with zero time objects are not stable as it seems if want.Serial != got.Serial || want.Status != got.Status || want.AKI != got.AKI || !got.RevokedAt.IsZero() || want.PEM != got.PEM || !roughlySameTime(got.Expiry, expiry) { t.Errorf("want Certificate %+v, got %+v", want, got) } unexpired, err := ta.Accessor.GetUnexpiredCertificates() if err != nil { t.Fatal(err) } if len(unexpired) != 1 { t.Error("Should have 1 unexpired certificate record:", len(unexpired)) } unexpiredFiltered, err := ta.Accessor.GetUnexpiredCertificatesByLabel([]string{"foo"}) if err != nil { t.Fatal(err) } if l := len(unexpiredFiltered); l != 1 { t.Error("Should have 1 unexpiredFiltered certificate record:", l) } unexpiredFiltered, err = ta.Accessor.GetUnexpiredCertificatesByLabel([]string{"bar"}) if err != nil { t.Fatal(err) } if l := len(unexpiredFiltered); l != 0 { t.Error("Should have 0 unexpiredFiltered certificate record:", l) } } func testInsertCertificateAndGetUnexpiredCertificateNullCommonName(ta TestAccessor, t *testing.T) { ta.Truncate() expiry := time.Now().Add(time.Minute) want := certdb.CertificateRecord{ PEM: "fake cert data", Serial: "fake serial 2", AKI: fakeAKI, Status: "good", Reason: 0, Expiry: expiry, } if err := ta.Accessor.InsertCertificate(want); err != nil { t.Fatal(err) } // simulate situation where there are rows before migrate 002 has been run ta.DB.MustExec(`update certificates set issued_at = NULL, not_before = NULL, metadata = NULL, sans = NULL, common_name = NULL;`) rets, err := ta.Accessor.GetCertificate(want.Serial, want.AKI) if err != nil { t.Fatal(err) } if len(rets) != 1 { t.Fatal("should return exactly one record") } got := rets[0] // reflection comparison with zero time objects are not stable as it seems if want.Serial != got.Serial || want.Status != got.Status || want.AKI != got.AKI || !got.RevokedAt.IsZero() || want.PEM != got.PEM || !roughlySameTime(got.Expiry, expiry) { t.Errorf("want Certificate %+v, got %+v", want, got) } unexpired, err := ta.Accessor.GetUnexpiredCertificates() if err != nil { t.Fatal(err) } if len(unexpired) != 1 { t.Error("Should have 1 unexpired certificate record:", len(unexpired)) } } func testUpdateCertificateAndGetCertificate(ta TestAccessor, t *testing.T) { ta.Truncate() expiry := time.Now().Add(time.Hour) want := certdb.CertificateRecord{ PEM: "fake cert data", Serial: "fake serial 3", AKI: fakeAKI, Status: "good", Reason: 0, Expiry: expiry, } // Make sure the revoke on a non-existent cert fails if err := ta.Accessor.RevokeCertificate(want.Serial, want.AKI, 2); err == nil { t.Fatal("Expected error") } if err := ta.Accessor.InsertCertificate(want); err != nil { t.Fatal(err) } // reason 2 is CACompromise if err := ta.Accessor.RevokeCertificate(want.Serial, want.AKI, 2); err != nil { t.Fatal(err) } rets, err := ta.Accessor.GetCertificate(want.Serial, want.AKI) if err != nil { t.Fatal(err) } if len(rets) != 1 { t.Fatal("should return exactly one record") } got := rets[0] // reflection comparison with zero time objects are not stable as it seems if want.Serial != got.Serial || got.Status != "revoked" || want.AKI != got.AKI || got.RevokedAt.IsZero() || want.PEM != got.PEM { t.Errorf("want Certificate %+v, got %+v", want, got) } rets, err = ta.Accessor.GetRevokedAndUnexpiredCertificates() if err != nil { t.Fatal(err) } got = rets[0] // reflection comparison with zero time objects are not stable as it seems if want.Serial != got.Serial || got.Status != "revoked" || want.AKI != got.AKI || got.RevokedAt.IsZero() || want.PEM != got.PEM { t.Errorf("want Certificate %+v, got %+v", want, got) } rets, err = ta.Accessor.GetRevokedAndUnexpiredCertificatesByLabel("") if err != nil { t.Fatal(err) } got = rets[0] // reflection comparison with zero time objects are not stable as it seems if want.Serial != got.Serial || got.Status != "revoked" || want.AKI != got.AKI || got.RevokedAt.IsZero() || want.PEM != got.PEM { t.Errorf("want Certificate %+v, got %+v", want, got) } rets, err = ta.Accessor.GetRevokedAndUnexpiredCertificatesByLabelSelectColumns("") if err != nil { t.Fatal(err) } got = rets[0] // reflection comparison with zero time objects are not stable as it seems if want.Serial != got.Serial || got.RevokedAt.IsZero() { t.Errorf("want Certificate %+v, got %+v", want, got) } } func testInsertOCSPAndGetOCSP(ta TestAccessor, t *testing.T) { ta.Truncate() expiry := time.Date(2010, time.December, 25, 23, 0, 0, 0, time.UTC) want := certdb.OCSPRecord{ Serial: "fake serial", AKI: fakeAKI, Body: "fake body", Expiry: expiry, } setupGoodCert(ta, t, want) if err := ta.Accessor.InsertOCSP(want); err != nil { t.Fatal(err) } rets, err := ta.Accessor.GetOCSP(want.Serial, want.AKI) if err != nil { t.Fatal(err) } if len(rets) != 1 { t.Fatal("should return exactly one record") } got := rets[0] if want.Serial != got.Serial || want.Body != got.Body || !roughlySameTime(want.Expiry, got.Expiry) { t.Errorf("want OCSP %+v, got %+v", want, got) } unexpired, err := ta.Accessor.GetUnexpiredOCSPs() if err != nil { t.Fatal(err) } if len(unexpired) != 0 { t.Error("should not have unexpired certificate record") } } func testInsertOCSPAndGetUnexpiredOCSP(ta TestAccessor, t *testing.T) { ta.Truncate() want := certdb.OCSPRecord{ Serial: "fake serial 2", AKI: fakeAKI, Body: "fake body", Expiry: time.Now().Add(time.Minute), } setupGoodCert(ta, t, want) if err := ta.Accessor.InsertOCSP(want); err != nil { t.Fatal(err) } rets, err := ta.Accessor.GetOCSP(want.Serial, want.AKI) if err != nil { t.Fatal(err) } if len(rets) != 1 { t.Fatal("should return exactly one record") } got := rets[0] if want.Serial != got.Serial || want.Body != got.Body || !roughlySameTime(want.Expiry, got.Expiry) { t.Errorf("want OCSP %+v, got %+v", want, got) } unexpired, err := ta.Accessor.GetUnexpiredOCSPs() if err != nil { t.Fatal(err) } if len(unexpired) != 1 { t.Error("should not have other than 1 unexpired certificate record:", len(unexpired)) } } func testUpdateOCSPAndGetOCSP(ta TestAccessor, t *testing.T) { ta.Truncate() want := certdb.OCSPRecord{ Serial: "fake serial 3", AKI: fakeAKI, Body: "fake body", Expiry: time.Date(2010, time.December, 25, 23, 0, 0, 0, time.UTC), } setupGoodCert(ta, t, want) // Make sure the update fails if err := ta.Accessor.UpdateOCSP(want.Serial, want.AKI, want.Body, want.Expiry); err == nil { t.Fatal("Expected error") } if err := ta.Accessor.InsertOCSP(want); err != nil { t.Fatal(err) } want.Body = "fake body revoked" newExpiry := time.Now().Add(time.Hour) if err := ta.Accessor.UpdateOCSP(want.Serial, want.AKI, want.Body, newExpiry); err != nil { t.Fatal(err) } rets, err := ta.Accessor.GetOCSP(want.Serial, want.AKI) if err != nil { t.Fatal(err) } if len(rets) != 1 { t.Fatal("should return exactly one record") } got := rets[0] want.Expiry = newExpiry if want.Serial != got.Serial || got.Body != "fake body revoked" || !roughlySameTime(newExpiry, got.Expiry) { t.Errorf("want OCSP %+v, got %+v", want, got) } } func testUpsertOCSPAndGetOCSP(ta TestAccessor, t *testing.T) { ta.Truncate() want := certdb.OCSPRecord{ Serial: "fake serial 3", AKI: fakeAKI, Body: "fake body", Expiry: time.Date(2010, time.December, 25, 23, 0, 0, 0, time.UTC), } setupGoodCert(ta, t, want) if err := ta.Accessor.UpsertOCSP(want.Serial, want.AKI, want.Body, want.Expiry); err != nil { t.Fatal(err) } rets, err := ta.Accessor.GetOCSP(want.Serial, want.AKI) if err != nil { t.Fatal(err) } if len(rets) != 1 { t.Fatal("should return exactly one record") } got := rets[0] if want.Serial != got.Serial || want.Body != got.Body || !roughlySameTime(want.Expiry, got.Expiry) { t.Errorf("want OCSP %+v, got %+v", want, got) } newExpiry := time.Now().Add(time.Hour) if err := ta.Accessor.UpsertOCSP(want.Serial, want.AKI, "fake body revoked", newExpiry); err != nil { t.Fatal(err) } rets, err = ta.Accessor.GetOCSP(want.Serial, want.AKI) if err != nil { t.Fatal(err) } if len(rets) != 1 { t.Fatal("should return exactly one record") } got = rets[0] want.Expiry = newExpiry if want.Serial != got.Serial || got.Body != "fake body revoked" || !roughlySameTime(newExpiry, got.Expiry) { t.Errorf("want OCSP %+v, got %+v", want, got) } } func setupGoodCert(ta TestAccessor, t *testing.T, r certdb.OCSPRecord) { certWant := certdb.CertificateRecord{ AKI: r.AKI, CALabel: "default", Expiry: time.Now().Add(time.Minute), PEM: "fake cert data", Serial: r.Serial, Status: "good", Reason: 0, } if err := ta.Accessor.InsertCertificate(certWant); err != nil { t.Fatal(err) } } ================================================ FILE: certdb/sqlite/dbconf.yml ================================================ development: driver: sqlite3 open: ./certstore_development.db test: driver: sqlite3 open: ./certstore_test.db staging: driver: sqlite3 open: ./certstore_staging.db production: driver: sqlite3 open: ./certstore_production.db ================================================ FILE: certdb/sqlite/migrations/001_CreateCertificates.sql ================================================ -- +goose Up -- SQL in section 'Up' is executed when this migration is applied CREATE TABLE certificates ( serial_number blob NOT NULL, authority_key_identifier blob NOT NULL, ca_label blob, status blob NOT NULL, reason int, expiry timestamp, revoked_at timestamp, pem blob NOT NULL, PRIMARY KEY(serial_number, authority_key_identifier) ); CREATE TABLE ocsp_responses ( serial_number blob NOT NULL, authority_key_identifier blob NOT NULL, body blob NOT NULL, expiry timestamp, PRIMARY KEY(serial_number, authority_key_identifier), FOREIGN KEY(serial_number, authority_key_identifier) REFERENCES certificates(serial_number, authority_key_identifier) ); -- +goose Down -- SQL section 'Down' is executed when this migration is rolled back DROP TABLE ocsp_responses; DROP TABLE certificates; ================================================ FILE: certdb/sqlite/migrations/002_AddMetadataToCertificates.sql ================================================ -- +goose Up -- SQL in section 'Up' is executed when this migration is applied ALTER TABLE certificates ADD COLUMN "issued_at" timestamp; ALTER TABLE certificates ADD COLUMN "not_before" timestamp; ALTER TABLE certificates ADD COLUMN "metadata" text; ALTER TABLE certificates ADD COLUMN "sans" text; ALTER TABLE certificates ADD COLUMN "common_name" text; -- +goose Down -- SQL section 'Down' is executed when this migration is rolled back -- can't drop columns in sqlite ================================================ FILE: certdb/testdb/testdb.go ================================================ package testdb import ( "os" "strings" _ "github.com/go-sql-driver/mysql" // register mysql driver "github.com/jmoiron/sqlx" _ "github.com/lib/pq" // register postgresql driver _ "github.com/mattn/go-sqlite3" // register sqlite3 driver ) const ( mysqlTruncateTables = ` TRUNCATE certificates; TRUNCATE ocsp_responses; ` pgTruncateTables = ` CREATE OR REPLACE FUNCTION truncate_tables() RETURNS void AS $$ DECLARE statements CURSOR FOR SELECT tablename FROM pg_tables WHERE tablename != 'goose_db_version' AND tableowner = session_user AND schemaname = 'public'; BEGIN FOR stmt IN statements LOOP EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' CASCADE;'; END LOOP; END; $$ LANGUAGE plpgsql; SELECT truncate_tables(); ` sqliteTruncateTables = ` DELETE FROM certificates; DELETE FROM ocsp_responses; ` ) // MySQLDB returns a MySQL db instance for certdb testing. func MySQLDB() *sqlx.DB { connStr := "root@tcp(localhost:3306)/certdb_development?parseTime=true" if dbURL := os.Getenv("DATABASE_URL"); dbURL != "" { connStr = dbURL } db, err := sqlx.Open("mysql", connStr) if err != nil { panic(err) } Truncate(db) return db } // PostgreSQLDB returns a PostgreSQL db instance for certdb testing. func PostgreSQLDB() *sqlx.DB { connStr := "dbname=certdb_development sslmode=disable user=postgres" if dbURL := os.Getenv("DATABASE_URL"); dbURL != "" { connStr = dbURL } db, err := sqlx.Open("postgres", connStr) if err != nil { panic(err) } Truncate(db) return db } // SQLiteDB returns a SQLite db instance for certdb testing. func SQLiteDB(dbpath string) *sqlx.DB { db, err := sqlx.Open("sqlite3", dbpath) if err != nil { panic(err) } Truncate(db) return db } // Truncate truncates the DB func Truncate(db *sqlx.DB) { var sql []string switch db.DriverName() { case "mysql": sql = strings.Split(mysqlTruncateTables, "\n") case "postgres": sql = []string{pgTruncateTables} case "sqlite3": sql = []string{sqliteTruncateTables} default: panic("Unknown driver") } for _, expr := range sql { if len(strings.TrimSpace(expr)) == 0 { continue } if _, err := db.Exec(expr); err != nil { panic(err) } } } ================================================ FILE: certinfo/certinfo.go ================================================ package certinfo import ( "crypto/tls" "crypto/x509" "crypto/x509/pkix" "errors" "fmt" "net" "os" "strings" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/helpers" ) // Certificate represents a JSON description of an X.509 certificate. type Certificate struct { Subject Name `json:"subject,omitempty"` Issuer Name `json:"issuer,omitempty"` SerialNumber string `json:"serial_number,omitempty"` SANs []string `json:"sans,omitempty"` NotBefore time.Time `json:"not_before"` NotAfter time.Time `json:"not_after"` SignatureAlgorithm string `json:"sigalg"` AKI string `json:"authority_key_id"` SKI string `json:"subject_key_id"` RawPEM string `json:"pem"` } // Name represents a JSON description of a PKIX Name type Name struct { CommonName string `json:"common_name,omitempty"` SerialNumber string `json:"serial_number,omitempty"` Country string `json:"country,omitempty"` Organization string `json:"organization,omitempty"` OrganizationalUnit string `json:"organizational_unit,omitempty"` Locality string `json:"locality,omitempty"` Province string `json:"province,omitempty"` StreetAddress string `json:"street_address,omitempty"` PostalCode string `json:"postal_code,omitempty"` Names []interface{} `json:"names,omitempty"` // ExtraNames []interface{} `json:"extra_names,omitempty"` } // ParseName parses a new name from a *pkix.Name func ParseName(name pkix.Name) Name { n := Name{ CommonName: name.CommonName, SerialNumber: name.SerialNumber, Country: strings.Join(name.Country, ","), Organization: strings.Join(name.Organization, ","), OrganizationalUnit: strings.Join(name.OrganizationalUnit, ","), Locality: strings.Join(name.Locality, ","), Province: strings.Join(name.Province, ","), StreetAddress: strings.Join(name.StreetAddress, ","), PostalCode: strings.Join(name.PostalCode, ","), } for i := range name.Names { n.Names = append(n.Names, name.Names[i].Value) } // ExtraNames aren't supported in Go 1.4 // for i := range name.ExtraNames { // n.ExtraNames = append(n.ExtraNames, name.ExtraNames[i].Value) // } return n } func formatKeyID(id []byte) string { var s string for i, c := range id { if i > 0 { s += ":" } s += fmt.Sprintf("%02X", c) } return s } // ParseCertificate parses an x509 certificate. func ParseCertificate(cert *x509.Certificate) *Certificate { c := &Certificate{ RawPEM: string(helpers.EncodeCertificatePEM(cert)), SignatureAlgorithm: helpers.SignatureString(cert.SignatureAlgorithm), NotBefore: cert.NotBefore, NotAfter: cert.NotAfter, Subject: ParseName(cert.Subject), Issuer: ParseName(cert.Issuer), SANs: cert.DNSNames, AKI: formatKeyID(cert.AuthorityKeyId), SKI: formatKeyID(cert.SubjectKeyId), SerialNumber: cert.SerialNumber.String(), } for _, ip := range cert.IPAddresses { c.SANs = append(c.SANs, ip.String()) } return c } // ParseCertificateFile parses x509 certificate file. func ParseCertificateFile(certFile string) (*Certificate, error) { certPEM, err := os.ReadFile(certFile) if err != nil { return nil, err } return ParseCertificatePEM(certPEM) } // ParseCertificatePEM parses an x509 certificate PEM. func ParseCertificatePEM(certPEM []byte) (*Certificate, error) { cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { return nil, err } return ParseCertificate(cert), nil } // ParseCSRPEM uses the helper to parse an x509 CSR PEM. func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) { csrObject, err := helpers.ParseCSRPEM(csrPEM) if err != nil { return nil, err } return csrObject, nil } // ParseCSRFile uses the helper to parse an x509 CSR PEM file. func ParseCSRFile(csrFile string) (*x509.CertificateRequest, error) { csrPEM, err := os.ReadFile(csrFile) if err != nil { return nil, err } return ParseCSRPEM(csrPEM) } // ParseCertificateDomain parses the certificate served by the given domain. func ParseCertificateDomain(domain string) (cert *Certificate, err error) { var host, port string if host, port, err = net.SplitHostPort(domain); err != nil { host = domain port = "443" } var conn *tls.Conn conn, err = tls.DialWithDialer(&net.Dialer{Timeout: 10 * time.Second}, "tcp", net.JoinHostPort(host, port), &tls.Config{InsecureSkipVerify: true}) if err != nil { return } defer conn.Close() if len(conn.ConnectionState().PeerCertificates) == 0 { return nil, errors.New("received no server certificates") } cert = ParseCertificate(conn.ConnectionState().PeerCertificates[0]) return } // ParseSerialNumber parses the serial number and does a lookup in the data // storage used for certificates. The authority key is required for the lookup // to work and must be passed as a hex string. func ParseSerialNumber(serial, aki string, dbAccessor certdb.Accessor) (*Certificate, error) { normalizedAKI := strings.ToLower(aki) normalizedAKI = strings.Replace(normalizedAKI, ":", "", -1) certificates, err := dbAccessor.GetCertificate(serial, normalizedAKI) if err != nil { return nil, err } if len(certificates) < 1 { return nil, errors.New("no certificate found") } if len(certificates) > 1 { return nil, errors.New("more than one certificate found") } return ParseCertificatePEM([]byte(certificates[0].PEM)) } ================================================ FILE: certinfo/certinfo_test.go ================================================ package certinfo import ( "bytes" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "math/big" "strings" "testing" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" ) const ( sqliteDBFile = "../certdb/testdb/certstore_development.db" fakeAKI = "fake_aki" testSerial = 1337 ) func TestParseSerialNumber(t *testing.T) { db := testdb.SQLiteDB(sqliteDBFile) accessor := sql.NewAccessor(db) certificate, err := createCertificate() if err != nil { t.Logf("could not create certificate: %s", err.Error()) t.FailNow() } err = accessor.InsertCertificate( certdb.CertificateRecord{ Serial: big.NewInt(testSerial).String(), AKI: fakeAKI, PEM: certificate, }, ) if err != nil { t.Log(err.Error()) t.FailNow() } cases := []struct { description string serial string aki string errorShouldContain string }{ { description: "no certificate found - wrong serial", serial: "1", aki: fakeAKI, errorShouldContain: "no certificate found", }, { description: "no certificate found - wrong AKI", serial: "123456789", aki: "1", errorShouldContain: "no certificate found", }, { description: "certificate found", serial: big.NewInt(testSerial).String(), aki: fakeAKI, }, } for _, tc := range cases { t.Run(tc.description, func(t *testing.T) { cert, err := ParseSerialNumber(tc.serial, tc.aki, accessor) if tc.errorShouldContain != "" { if cert != nil { t.Error("no certificate should be returned if error occurs") } if err == nil { t.Error("err expected to not be nil") return } if !strings.Contains(err.Error(), tc.errorShouldContain) { t.Errorf("expected error to contain '%s' but was '%s'", tc.errorShouldContain, err.Error()) } return } if err != nil { t.Errorf("expected error to be nil but got '%s'", err.Error()) return } if cert.SerialNumber != tc.serial { t.Errorf("returned certificate doesn't match the serial queried for") } }) } } func createCertificate() (string, error) { key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return "", err } cert := &x509.Certificate{ SerialNumber: big.NewInt(testSerial), Subject: pkix.Name{ Country: []string{"SE"}, Organization: []string{"CFSSL Unit Testing"}, }, NotBefore: time.Now(), NotAfter: time.Now().AddDate(1, 0, 0), ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, BasicConstraintsValid: true, } certificate, err := x509.CreateCertificate(rand.Reader, cert, cert, &key.PublicKey, key) if err != nil { return "", err } return certificateToPEMBlock(certificate) } func certificateToPEMBlock(cert []byte) (string, error) { buf := &bytes.Buffer{} err := pem.Encode(buf, &pem.Block{ Type: "CERTIFICATE", Bytes: cert, }) if err != nil { return "", err } return buf.String(), nil } ================================================ FILE: cli/bundle/bundle.go ================================================ // Package bundle implements the bundle command. package bundle import ( "errors" "fmt" "github.com/cloudflare/cfssl/bundler" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/ubiquity" ) // Usage text of 'cfssl bundle' var bundlerUsageText = `cfssl bundle -- create a certificate bundle that contains the client cert Usage of bundle: - Bundle local certificate files cfssl bundle -cert file [-ca-bundle file] [-int-bundle file] [-int-dir dir] [-metadata file] [-key keyfile] [-flavor optimal|ubiquitous|force] [-password password] - Bundle certificate from remote server. cfssl bundle -domain domain_name [-ip ip_address] [-ca-bundle file] [-int-bundle file] [-int-dir dir] [-metadata file] Flags: ` // flags used by 'cfssl bundle' var bundlerFlags = []string{"cert", "key", "ca-bundle", "int-bundle", "flavor", "int-dir", "metadata", "domain", "ip", "password"} // bundlerMain is the main CLI of bundler functionality. func bundlerMain(args []string, c cli.Config) (err error) { bundler.IntermediateStash = c.IntDir ubiquity.LoadPlatforms(c.Metadata) flavor := bundler.BundleFlavor(c.Flavor) var b *bundler.Bundler // If it is a force bundle, don't require ca bundle and intermediate bundle // Otherwise, initialize a bundler with CA bundle and intermediate bundle. if flavor == bundler.Force { b = &bundler.Bundler{} } else { b, err = bundler.NewBundler(c.CABundleFile, c.IntBundleFile) if err != nil { return } } var bundle *bundler.Bundle if c.CertFile != "" { if c.CertFile == "-" { var certPEM, keyPEM []byte certPEM, err = cli.ReadStdin(c.CertFile) if err != nil { return } if c.KeyFile != "" { keyPEM, err = cli.ReadStdin(c.KeyFile) if err != nil { return } } bundle, err = b.BundleFromPEMorDER(certPEM, keyPEM, flavor, "") if err != nil { return } } else { // Bundle the client cert bundle, err = b.BundleFromFile(c.CertFile, c.KeyFile, flavor, c.Password) if err != nil { return } } } else if c.Domain != "" { bundle, err = b.BundleFromRemote(c.Domain, c.IP, flavor) if err != nil { return } } else { return errors.New("Must specify bundle target through -cert or -domain") } marshaled, err := bundle.MarshalJSON() if err != nil { return } fmt.Printf("%s", marshaled) return } // Command assembles the definition of Command 'bundle' var Command = &cli.Command{UsageText: bundlerUsageText, Flags: bundlerFlags, Main: bundlerMain} ================================================ FILE: cli/bundle/bundle_test.go ================================================ package bundle ================================================ FILE: cli/certinfo/certinfo.go ================================================ // Package certinfo implements the certinfo command package certinfo import ( "crypto/x509" "encoding/json" "errors" "fmt" "github.com/cloudflare/cfssl/certdb/dbconf" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certinfo" "github.com/cloudflare/cfssl/cli" "github.com/jmoiron/sqlx" ) // Usage text of 'cfssl certinfo' var dataUsageText = `cfssl certinfo -- output certinfo about the given cert Usage of certinfo: - Data from local certificate files cfssl certinfo -cert file - Data from local CSR file cfssl certinfo -csr file - Data from certificate from remote server. cfssl certinfo -domain domain_name - Data from CA storage cfssl certinfo -sn serial (requires -db-config and -aki) Flags: ` // flags used by 'cfssl certinfo' var certinfoFlags = []string{"aki", "cert", "csr", "db-config", "domain", "serial"} // certinfoMain is the main CLI of certinfo functionality func certinfoMain(args []string, c cli.Config) (err error) { var cert *certinfo.Certificate var csr *x509.CertificateRequest if c.CertFile != "" { if c.CertFile == "-" { var certPEM []byte if certPEM, err = cli.ReadStdin(c.CertFile); err != nil { return } if cert, err = certinfo.ParseCertificatePEM(certPEM); err != nil { return } } else { if cert, err = certinfo.ParseCertificateFile(c.CertFile); err != nil { return } } } else if c.CSRFile != "" { if c.CSRFile == "-" { var csrPEM []byte if csrPEM, err = cli.ReadStdin(c.CSRFile); err != nil { return } if csr, err = certinfo.ParseCSRPEM(csrPEM); err != nil { return } } else { if csr, err = certinfo.ParseCSRFile(c.CSRFile); err != nil { return } } } else if c.Domain != "" { if cert, err = certinfo.ParseCertificateDomain(c.Domain); err != nil { return } } else if c.Serial != "" && c.AKI != "" { if c.DBConfigFile == "" { return errors.New("need DB config file (provide with -db-config)") } var db *sqlx.DB db, err = dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return } dbAccessor := sql.NewAccessor(db) if cert, err = certinfo.ParseSerialNumber(c.Serial, c.AKI, dbAccessor); err != nil { return } } else { return errors.New("Must specify certinfo target through -cert, -csr, -domain or -serial + -aki") } var b []byte if cert != nil { b, err = json.MarshalIndent(cert, "", " ") } else if csr != nil { b, err = json.MarshalIndent(csr, "", " ") } if err != nil { return } fmt.Println(string(b)) return } // Command assembles the definition of Command 'certinfo' var Command = &cli.Command{UsageText: dataUsageText, Flags: certinfoFlags, Main: certinfoMain} ================================================ FILE: cli/cli.go ================================================ // Package cli provides the template for adding new cfssl commands package cli /* cfssl is the command line tool to issue/sign/bundle client certificate. It's also a tool to start a HTTP server to handle web requests for signing, bundling and verification. Usage: cfssl command [-flags] arguments The commands are defined in the cli subpackages and include bundle create a certificate bundle sign signs a certificate signing request (CSR) serve starts a HTTP server handling sign and bundle requests version prints the current cfssl version genkey generates a key and an associated CSR gencert generates a key and a signed certificate gencsr generates a certificate request selfsign generates a self-signed certificate ocspsign signs an OCSP response Use "cfssl [command] -help" to find out more about a command. */ import ( "encoding/base64" "encoding/json" "errors" "flag" "fmt" "io" "os" "github.com/cloudflare/cfssl/config" ) // Command holds the implementation details of a cfssl command. type Command struct { // The Usage Text UsageText string // Flags to look up in the global table Flags []string // Main runs the command, args are the arguments after flags Main func(args []string, c Config) error } var cmdName string // usage is the cfssl usage heading. It will be appended with names of defined commands in cmds // to form the final usage message of cfssl. const usage = `Usage: Available commands: ` // printDefaultValue is a helper function to print out a user friendly // usage message of a flag. It's useful since we want to write customized // usage message on selected subsets of the global flag set. It is // borrowed from standard library source code. Since flag value type is // not exported, default string flag values are printed without // quotes. The only exception is the empty string, which is printed as "". func printDefaultValue(f *flag.Flag) { format := " -%s=%s: %s\n" if f.DefValue == "" { format = " -%s=%q: %s\n" } fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage) } // PopFirstArgument returns the first element and the rest of a string // slice and return error if failed to do so. It is a helper function // to parse non-flag arguments previously used in cfssl commands. func PopFirstArgument(args []string) (string, []string, error) { if len(args) < 1 { return "", nil, errors.New("not enough arguments are supplied --- please refer to the usage") } return args[0], args[1:], nil } // Start is the entrance point of cfssl command line tools. func Start(cmds map[string]*Command) error { // cfsslFlagSet is the flag sets for cfssl. var cfsslFlagSet = flag.NewFlagSet("cfssl", flag.ExitOnError) var c Config registerFlags(&c, cfsslFlagSet) // Initial parse of command line arguments. By convention, only -h/-help is supported. if flag.Usage == nil { flag.Usage = func() { fmt.Fprintf(os.Stderr, usage) for name := range cmds { fmt.Fprintf(os.Stderr, "\t%s\n", name) } fmt.Fprintf(os.Stderr, "Top-level flags:\n") flag.PrintDefaults() } } flag.Parse() if flag.NArg() < 1 { fmt.Fprintf(os.Stderr, "No command is given.\n") flag.Usage() return errors.New("no command was given") } // Clip out the command name and args for the command cmdName = flag.Arg(0) args := flag.Args()[1:] cmd, found := cmds[cmdName] if !found { fmt.Fprintf(os.Stderr, "Command %s is not defined.\n", cmdName) flag.Usage() return errors.New("undefined command") } // always have flag 'loglevel' for each command cmd.Flags = append(cmd.Flags, "loglevel") // The usage of each individual command is re-written to mention // flags defined and referenced only in that command. cfsslFlagSet.Usage = func() { fmt.Fprintf(os.Stderr, "\t%s", cmd.UsageText) for _, name := range cmd.Flags { if f := cfsslFlagSet.Lookup(name); f != nil { printDefaultValue(f) } } } // Parse all flags and take the rest as argument lists for the command cfsslFlagSet.Parse(args) args = cfsslFlagSet.Args() var err error if c.ConfigFile != "" { c.CFG, err = config.LoadFile(c.ConfigFile) if err != nil { fmt.Fprintf(os.Stderr, "Failed to load config file: %v", err) return errors.New("failed to load config file") } } if err := cmd.Main(args, c); err != nil { fmt.Fprintln(os.Stderr, err) return err } return nil } // ReadStdin reads from stdin if the file is "-" func ReadStdin(filename string) ([]byte, error) { if filename == "-" { return io.ReadAll(os.Stdin) } return os.ReadFile(filename) } // PrintCert outputs a cert, key and csr to stdout func PrintCert(key, csrBytes, cert []byte) { out := map[string]string{} if cert != nil { out["cert"] = string(cert) } if key != nil { out["key"] = string(key) } if csrBytes != nil { out["csr"] = string(csrBytes) } jsonOut, err := json.Marshal(out) if err != nil { return } fmt.Printf("%s\n", jsonOut) } // PrintOCSPResponse outputs an OCSP response to stdout // ocspResponse is base64 encoded func PrintOCSPResponse(resp []byte) { b64Resp := base64.StdEncoding.EncodeToString(resp) out := map[string]string{"ocspResponse": b64Resp} jsonOut, err := json.Marshal(out) if err != nil { return } fmt.Printf("%s\n", jsonOut) } // PrintCRL outputs the CRL to stdout func PrintCRL(certList []byte) { b64Resp := base64.StdEncoding.EncodeToString(certList) fmt.Printf("%s\n", b64Resp) } ================================================ FILE: cli/cli_test.go ================================================ package cli import ( "flag" "os" "testing" ) var cfsslFlagSet = flag.NewFlagSet("cfssl", flag.ExitOnError) // The testing style from this package is borrowed from the Go flag // library's methodology for testing this. We set flag.Usage to nil, // then replace it with a closure to ensure the usage function was // called appropriately. // 'cfssl -help' should be supported. func TestHelp(t *testing.T) { called := false ResetForTesting(func() { called = true }) os.Args = []string{"cfssl", "-help"} Start(nil) if !called { t.Fatal("flag -help is not recognized correctly.") } } // 'cfssl -badflag' should trigger parse error and usage invocation. func TestUnknownFlag(t *testing.T) { called := false os.Args = []string{"cfssl", "-badflag"} ResetForTesting(func() { called = true }) Start(nil) if !called { t.Fatal("Bad flag is not caught.") } } // 'cfssl badcommand' should trigger parse error and usage invocation. func TestBadCommand(t *testing.T) { called := false ResetForTesting(func() { called = true }) os.Args = []string{"cfssl", "badcommand"} Start(nil) if !called { t.Fatal("Bad command is not caught.") } } func TestCommandHelp(t *testing.T) { called := false ResetCFSSLFlagSetForTesting(func() { called = true }) args := []string{"-help"} cfsslFlagSet.Parse(args) if !called { t.Fatal("sub-command -help is not recognized.") } } func TestCommandBadFlag(t *testing.T) { called := false ResetCFSSLFlagSetForTesting(func() { called = true }) args := []string{"-help", "-badflag"} cfsslFlagSet.Parse(args) if !called { t.Fatal("bad flag for sub-command is not caught.") } } // Additional routines derived from flag unit testing // ResetForTesting clears all flag state and sets the usage function as directed. // After calling ResetForTesting, parse errors in flag handling will not // exit the program. func ResetForTesting(usage func()) { flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError) flag.Usage = usage } // ResetCFSSLFlagSetForTesting reset cfsslFlagSet with flag.ContinueOnError so parse // errors in flag will not exit the program func ResetCFSSLFlagSetForTesting(usage func()) { var c Config cfsslFlagSet = flag.NewFlagSet("cfssl", flag.ContinueOnError) registerFlags(&c, cfsslFlagSet) cfsslFlagSet.Usage = usage } func TestReadStdin(t *testing.T) { fn, err := ReadStdin("./testdata/test.txt") if err != nil { t.Fatal(err) } if string(fn) != "This is a test file" { t.Fatal(err) } _, err = ReadStdin("-") if err != nil { t.Fatal(err) } } func TestPopFirstArg(t *testing.T) { s, str, err := PopFirstArgument([]string{"a", "b", "c"}) if s != "a" { t.Fatal("Did not pop first argument successfully") } if str == nil { t.Fatal("Did not return the rest of argument successfully") } if err != nil { t.Fatal(err) } //test invalid argument _, _, err = PopFirstArgument([]string{}) if err == nil { t.Fatal("No argument given, should return error") } } ================================================ FILE: cli/config.go ================================================ package cli import ( "flag" "time" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer/universal" ) // Config is a type to hold flag values used by cfssl commands. type Config struct { Hostname string CertFile string CSRFile string CAFile string CAKeyFile string TLSCertFile string TLSKeyFile string MutualTLSCAFile string MutualTLSCNRegex string TLSRemoteCAs string MutualTLSCertFile string MutualTLSKeyFile string KeyFile string IntermediatesFile string CABundleFile string IntBundleFile string Address string Port int MinTLSVersion string Password string ConfigFile string CFG *config.Config Profile string IsCA bool RenewCA bool IntDir string Flavor string Metadata string Domain string IP string Remote string Label string AuthKey string ResponderFile string ResponderKeyFile string Status string Reason string RevokedAt string Interval time.Duration List bool Family string Timeout time.Duration Scanner string CSVFile string NumWorkers int MaxHosts int Responses string Path string CRL string Usage string PGPPrivate string PGPName string Serial string CNOverride string AKI string DBConfigFile string CRLExpiration time.Duration Disable string } // registerFlags defines all cfssl command flags and associates their values with variables. func registerFlags(c *Config, f *flag.FlagSet) { f.StringVar(&c.Hostname, "hostname", "", "Hostname for the cert, could be a comma-separated hostname list") f.StringVar(&c.CertFile, "cert", "", "Client certificate that contains the public key") f.StringVar(&c.CSRFile, "csr", "", "Certificate signature request file for new public key") f.StringVar(&c.CAFile, "ca", "", "CA used to sign the new certificate -- accepts '[file:]fname' or 'env:varname'") f.StringVar(&c.CAKeyFile, "ca-key", "", "CA private key -- accepts '[file:]fname' or 'env:varname'") f.StringVar(&c.TLSCertFile, "tls-cert", "", "Other endpoint CA to set up TLS protocol") f.StringVar(&c.TLSKeyFile, "tls-key", "", "Other endpoint CA private key") f.StringVar(&c.MutualTLSCAFile, "mutual-tls-ca", "", "Mutual TLS - require clients be signed by this CA ") f.StringVar(&c.MutualTLSCNRegex, "mutual-tls-cn", "", "Mutual TLS - regex for whitelist of allowed client CNs") f.StringVar(&c.TLSRemoteCAs, "tls-remote-ca", "", "CAs to trust for remote TLS requests") f.StringVar(&c.MutualTLSCertFile, "mutual-tls-client-cert", "", "Mutual TLS - client certificate to call remote instance requiring client certs") f.StringVar(&c.MutualTLSKeyFile, "mutual-tls-client-key", "", "Mutual TLS - client key to call remote instance requiring client certs") f.StringVar(&c.KeyFile, "key", "", "private key for the certificate") f.StringVar(&c.IntermediatesFile, "intermediates", "", "intermediate certs") f.StringVar(&c.CABundleFile, "ca-bundle", "", "path to root certificate store") f.StringVar(&c.IntBundleFile, "int-bundle", "", "path to intermediate certificate store") f.StringVar(&c.Address, "address", "127.0.0.1", "Address to bind") f.IntVar(&c.Port, "port", 8888, "Port to bind") f.StringVar(&c.MinTLSVersion, "min-tls-version", "", "Minimum version of TLS to use, defaults to 1.0") f.StringVar(&c.ConfigFile, "config", "", "path to configuration file") f.StringVar(&c.Profile, "profile", "", "signing profile to use") f.BoolVar(&c.IsCA, "initca", false, "initialise new CA") f.BoolVar(&c.RenewCA, "renewca", false, "re-generate a CA certificate from existing CA certificate/key") f.StringVar(&c.IntDir, "int-dir", "", "specify intermediates directory") f.StringVar(&c.Flavor, "flavor", "ubiquitous", "Bundle Flavor: ubiquitous, optimal and force.") f.StringVar(&c.Metadata, "metadata", "", "Metadata file for root certificate presence. The content of the file is a json dictionary (k,v): each key k is SHA-1 digest of a root certificate while value v is a list of key store filenames.") f.StringVar(&c.Domain, "domain", "", "remote server domain name") f.StringVar(&c.IP, "ip", "", "remote server ip") f.StringVar(&c.Remote, "remote", "", "remote CFSSL server") f.StringVar(&c.Label, "label", "", "key label to use in remote CFSSL server") f.StringVar(&c.AuthKey, "authkey", "", "key to authenticate requests to remote CFSSL server") f.StringVar(&c.ResponderFile, "responder", "", "Certificate for OCSP responder") f.StringVar(&c.ResponderKeyFile, "responder-key", "", "private key for OCSP responder certificate") f.StringVar(&c.Status, "status", "good", "Status of the certificate: good, revoked, unknown") f.StringVar(&c.Reason, "reason", "0", "Reason code for revocation") f.StringVar(&c.RevokedAt, "revoked-at", "now", "Date of revocation (YYYY-MM-DD)") f.DurationVar(&c.Interval, "interval", 4*helpers.OneDay, "Interval between OCSP updates (default: 96h)") f.BoolVar(&c.List, "list", false, "list possible scanners") f.StringVar(&c.Family, "family", "", "scanner family regular expression") f.StringVar(&c.Scanner, "scanner", "", "scanner regular expression") f.DurationVar(&c.Timeout, "timeout", 5*time.Minute, "duration (ns, us, ms, s, m, h) to scan each host before timing out") f.StringVar(&c.CSVFile, "csv", "", "file containing CSV of hosts") f.IntVar(&c.NumWorkers, "num-workers", 10, "number of workers to use for scan") f.IntVar(&c.MaxHosts, "max-hosts", 100, "maximum number of hosts to scan") f.StringVar(&c.Responses, "responses", "", "file to load OCSP responses from") f.StringVar(&c.Path, "path", "/", "Path on which the server will listen") f.StringVar(&c.CRL, "crl", "", "CRL URL Override") f.StringVar(&c.Password, "password", "0", "Password for accessing PKCS #12 data passed to bundler") f.StringVar(&c.Usage, "usage", "", "usage of private key") f.StringVar(&c.PGPPrivate, "pgp-private", "", "file to load a PGP Private key decryption") f.StringVar(&c.PGPName, "pgp-name", "", "PGP public key name, can be a comma-separated key name list") f.StringVar(&c.Serial, "serial", "", "certificate serial number") f.StringVar(&c.CNOverride, "cn", "", "certificate common name (CN)") f.StringVar(&c.AKI, "aki", "", "certificate issuer (authority) key identifier") f.StringVar(&c.DBConfigFile, "db-config", "", "certificate db configuration file") f.DurationVar(&c.CRLExpiration, "expiry", 7*helpers.OneDay, "time from now after which the CRL will expire (default: one week)") f.IntVar(&log.Level, "loglevel", log.LevelInfo, "Log level (0 = DEBUG, 5 = FATAL)") f.StringVar(&c.Disable, "disable", "", "endpoints to disable") } // RootFromConfig returns a universal signer Root structure that can // be used to produce a signer. func RootFromConfig(c *Config) universal.Root { return universal.Root{ Config: map[string]string{ "cert-file": c.CAFile, "key-file": c.CAKeyFile, }, ForceRemote: c.Remote != "", } } ================================================ FILE: cli/crl/crl.go ================================================ // Package crl implements the crl command package crl import ( "os" "github.com/cloudflare/cfssl/certdb/dbconf" certsql "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/crl" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/jmoiron/sqlx" ) var crlUsageText = `cfssl crl -- generate a new Certificate Revocation List from Database Usage of crl: cfssl crl Flags: ` var crlFlags = []string{"db-config", "ca", "ca-key", "expiry"} func generateCRL(c cli.Config) (crlBytes []byte, err error) { if c.CAFile == "" { log.Error("need CA certificate (provide one with -ca)") return } if c.CAKeyFile == "" { log.Error("need CA key (provide one with -ca-key)") return } var db *sqlx.DB if c.DBConfigFile != "" { db, err = dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return nil, err } } else { log.Error("no Database specified!") return nil, err } dbAccessor := certsql.NewAccessor(db) log.Debug("loading CA: ", c.CAFile) ca, err := helpers.ReadBytes(c.CAFile) if err != nil { return nil, err } log.Debug("loading CA key: ", c.CAKeyFile) cakey, err := helpers.ReadBytes(c.CAKeyFile) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err) } // Parse the PEM encoded certificate issuerCert, err := helpers.ParseCertificatePEM(ca) if err != nil { return nil, err } strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD") password := []byte(strPassword) if strPassword == "" { password = nil } // Parse the key given key, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password) if err != nil { log.Debugf("malformed private key %v", err) return nil, err } certs, err := dbAccessor.GetRevokedAndUnexpiredCertificates() if err != nil { return nil, err } req, err := crl.NewCRLFromDB(certs, issuerCert, key, c.CRLExpiration) if err != nil { return nil, err } return req, nil } func crlMain(args []string, c cli.Config) (err error) { req, err := generateCRL(c) if err != nil { return err } cli.PrintCRL(req) return } // Command assembles the definition of Command 'crl' var Command = &cli.Command{UsageText: crlUsageText, Flags: crlFlags, Main: crlMain} ================================================ FILE: cli/crl/crl_test.go ================================================ package crl import ( "crypto/x509" "testing" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/helpers" ) var dbAccessor certdb.Accessor const ( fakeAKI = "fake aki" testCaFile = "../testdata/ca.pem" testCaKeyFile = "../testdata/ca-key.pem" ) func prepDB() (err error) { db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") expirationTime := time.Now().AddDate(1, 0, 0) var cert = certdb.CertificateRecord{ Serial: "1", AKI: fakeAKI, Expiry: expirationTime, PEM: "revoked cert", Status: "revoked", RevokedAt: time.Now(), Reason: 4, } dbAccessor = sql.NewAccessor(db) err = dbAccessor.InsertCertificate(cert) if err != nil { return err } return } func verifyCRL(t *testing.T, crlBytesDER []byte, serial string, expireAfter time.Duration) { parsedCrl, err := x509.ParseCRL(crlBytesDER) if err != nil { t.Fatal("failed to get certificate ", err) } if !parsedCrl.HasExpired(time.Now().Add(expireAfter)) { t.Fatal("the CRL should have expired") } certs := parsedCrl.TBSCertList.RevokedCertificates if len(certs) != 1 { t.Fatal("failed to get one certificate") } cert := certs[0] if cert.SerialNumber.String() != serial { t.Fatal("cert was not correctly inserted in CRL, serial was " + cert.SerialNumber.String()) } } func TestRevokeMain(t *testing.T) { err := prepDB() if err != nil { t.Fatal(err) } crlBytes, err := generateCRL(cli.Config{CAFile: testCaFile, CAKeyFile: testCaKeyFile, DBConfigFile: "../testdata/db-config.json"}) if err != nil { t.Fatal(err) } verifyCRL(t, crlBytes, "1", 7*helpers.OneDay+time.Second) } func TestRevokeExpiry(t *testing.T) { err := prepDB() if err != nil { t.Fatal(err) } crlBytes, err := generateCRL(cli.Config{CAFile: testCaFile, CAKeyFile: testCaKeyFile, DBConfigFile: "../testdata/db-config.json", CRLExpiration: 23 * time.Hour}) if err != nil { t.Fatal(err) } verifyCRL(t, crlBytes, "1", 23*time.Hour+time.Second) } ================================================ FILE: cli/gencert/gencert.go ================================================ // Package gencert implements the gencert command. package gencert import ( "encoding/json" "errors" "github.com/cloudflare/cfssl/api/generator" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/cli/genkey" "github.com/cloudflare/cfssl/cli/sign" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/initca" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer" ) var gencertUsageText = `cfssl gencert -- generate a new key and signed certificate Usage of gencert: Generate a new key and cert from CSR: cfssl gencert -initca CSRJSON cfssl gencert -ca cert -ca-key key [-config config] [-profile profile] [-hostname hostname] CSRJSON cfssl gencert -remote remote_host [-config config] [-profile profile] [-label label] [-hostname hostname] CSRJSON Re-generate a CA cert with the CA key and CSR: cfssl gencert -initca -ca-key key CSRJSON Re-generate a CA cert with the CA key and certificate: cfssl gencert -renewca -ca cert -ca-key key Arguments: CSRJSON: JSON file containing the request, use '-' for reading JSON from stdin Flags: ` var gencertFlags = []string{"initca", "remote", "ca", "ca-key", "config", "cn", "hostname", "profile", "label"} func gencertMain(args []string, c cli.Config) error { if c.RenewCA { log.Infof("re-generate a CA certificate from CA cert and key") cert, err := initca.RenewFromPEM(c.CAFile, c.CAKeyFile) if err != nil { log.Errorf("%v\n", err) return err } cli.PrintCert(nil, nil, cert) return nil } csrJSONFile, args, err := cli.PopFirstArgument(args) if err != nil { return err } if len(args) > 0 { return errors.New("only one argument is accepted, please check with usage") } csrJSONFileBytes, err := cli.ReadStdin(csrJSONFile) if err != nil { return err } req := csr.CertificateRequest{ KeyRequest: csr.NewKeyRequest(), } err = json.Unmarshal(csrJSONFileBytes, &req) if err != nil { return err } if c.CNOverride != "" { req.CN = c.CNOverride } switch { case c.IsCA: var key, csrPEM, cert []byte if c.CAKeyFile != "" { log.Infof("re-generate a CA certificate from CSR and CA key") cert, csrPEM, err = initca.NewFromPEM(&req, c.CAKeyFile) if err != nil { log.Errorf("%v\n", err) return err } } else { log.Infof("generating a new CA key and certificate from CSR") cert, csrPEM, key, err = initca.New(&req) if err != nil { return err } } cli.PrintCert(key, csrPEM, cert) default: if req.CA != nil { err = errors.New("ca section only permitted in initca") return err } if c.Hostname != "" { req.Hosts = signer.SplitHosts(c.Hostname) } // Remote can be forced on the command line or in the config if c.Remote == "" && c.CFG == nil { if c.CAFile == "" { log.Error("need a CA certificate (provide one with -ca)") return nil } if c.CAKeyFile == "" { log.Error("need a CA key (provide one with -ca-key)") return nil } } var key, csrBytes []byte g := &csr.Generator{Validator: genkey.Validator} csrBytes, key, err = g.ProcessRequest(&req) if err != nil { key = nil return err } s, err := sign.SignerFromConfig(c) if err != nil { return err } var cert []byte signReq := signer.SignRequest{ Request: string(csrBytes), Hosts: signer.SplitHosts(c.Hostname), Profile: c.Profile, Label: c.Label, } if c.CRL != "" { signReq.CRLOverride = c.CRL } cert, err = s.Sign(signReq) if err != nil { return err } // This follows the Baseline Requirements for the Issuance and // Management of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser // Forum (https://cabforum.org). Specifically, section 10.2.3 ("Information // Requirements"), states: // // "Applicant information MUST include, but not be limited to, at least one // Fully-Qualified Domain Name or IP address to be included in the Certificate’s // SubjectAltName extension." if len(signReq.Hosts) == 0 && len(req.Hosts) == 0 { log.Warning(generator.CSRNoHostMessage) } cli.PrintCert(key, csrBytes, cert) } return nil } // Command assembles the definition of Command 'gencert' var Command = &cli.Command{UsageText: gencertUsageText, Flags: gencertFlags, Main: gencertMain} ================================================ FILE: cli/gencert/gencert_test.go ================================================ package gencert import ( "os" "strings" "testing" "github.com/cloudflare/cfssl/cli" ) func TestGencertMain(t *testing.T) { c := cli.Config{ IsCA: true, } err := gencertMain([]string{"../testdata/csr.json"}, c) if err != nil { t.Fatal(err) } c = cli.Config{ IsCA: true, CAKeyFile: "../testdata/ca-key.pem", } err = gencertMain([]string{"../testdata/csr.json"}, c) if err != nil { t.Fatal(err) } c = cli.Config{ CAFile: "../testdata/ca.pem", CAKeyFile: "../testdata/ca-key.pem", } err = gencertMain([]string{"../testdata/csr.json"}, c) if err != nil { t.Fatal(err) } c = cli.Config{ RenewCA: true, CAFile: "../testdata/ca.pem", CAKeyFile: "../testdata/ca-key.pem", } err = gencertMain([]string{}, c) if err != nil { t.Fatal(err) } } func TestGencertFile(t *testing.T) { c := cli.Config{ IsCA: true, CAKeyFile: "file:../testdata/ca-key.pem", } err := gencertMain([]string{"../testdata/csr.json"}, c) if err != nil { t.Fatal(err) } c = cli.Config{ CAFile: "file:../testdata/ca.pem", CAKeyFile: "file:../testdata/ca-key.pem", } err = gencertMain([]string{"../testdata/csr.json"}, c) if err != nil { t.Fatal(err) } c = cli.Config{ RenewCA: true, CAFile: "file:../testdata/ca.pem", CAKeyFile: "file:../testdata/ca-key.pem", } err = gencertMain([]string{}, c) if err != nil { t.Fatal(err) } } func TestGencertEnv(t *testing.T) { tempCaCert, _ := os.ReadFile("../testdata/ca.pem") tempCaKey, _ := os.ReadFile("../testdata/ca-key.pem") os.Setenv("ca", string(tempCaCert)) os.Setenv("ca_key", string(tempCaKey)) c := cli.Config{ IsCA: true, CAKeyFile: "env:ca_key", } err := gencertMain([]string{"../testdata/csr.json"}, c) if err != nil { t.Fatal(err) } c = cli.Config{ CAFile: "env:ca", CAKeyFile: "env:ca_key", } err = gencertMain([]string{"../testdata/csr.json"}, c) if err != nil { t.Fatal(err) } c = cli.Config{ RenewCA: true, CAFile: "env:ca", CAKeyFile: "env:ca_key", } err = gencertMain([]string{}, c) if err != nil { t.Fatal(err) } } func TestBadGencertEnv(t *testing.T) { tempCaCert, _ := os.ReadFile("../testdata/ca.pem") tempCaKey, _ := os.ReadFile("../testdata/ca-key.pem") os.Setenv("ca", string(tempCaCert)) os.Setenv("ca_key", string(tempCaKey)) c := cli.Config{ RenewCA: true, CAFile: "ca", CAKeyFile: "env:ca_key", } err := gencertMain([]string{}, c) if err == nil { t.Fatal("No prefix provided, should report an error") } c = cli.Config{ RenewCA: true, CAFile: "env:ca", CAKeyFile: "ca_key", } err = gencertMain([]string{}, c) if err == nil { t.Fatal("No prefix provided, should report an error") } c = cli.Config{ RenewCA: true, CAFile: "env:ca", CAKeyFile: "en:ca_key", } err = gencertMain([]string{}, c) if err == nil { t.Fatal("Unsupported prefix, should report error") } c = cli.Config{ RenewCA: true, CAFile: "env:ca", CAKeyFile: "env:file:ca_key", } err = gencertMain([]string{}, c) if err == nil { t.Fatal("Multiple prefixes, should report error") } } func TestBadGencertMain(t *testing.T) { err := gencertMain([]string{"../testdata/csr.json"}, cli.Config{}) if err != nil { t.Fatal(err) } err = gencertMain([]string{"../testdata/csr.json"}, cli.Config{CAFile: "../testdata/ca.pem"}) if err != nil { t.Fatal(err) } err = gencertMain([]string{}, cli.Config{RenewCA: true}) if err == nil { t.Fatal("No CA or Key provided, should report error") } err = gencertMain([]string{}, cli.Config{}) if err == nil { t.Fatal("Not enough argument, should report error") } err = gencertMain([]string{"../testdata/bad_csr.json"}, cli.Config{}) if err == nil { t.Fatal("Bad CSR JSON, should report error") } err = gencertMain([]string{"../testdata/nothing"}, cli.Config{}) if err == nil { t.Fatal("Trying to read a non-existence file, should report error") } err = gencertMain([]string{"../testdata/csr.json"}, cli.Config{IsCA: true, CAKeyFile: "../../testdata/garbage.crt"}) if err == nil { t.Fatal("Bad CA, should report error") } err = gencertMain([]string{"../testdata/csr.json"}, cli.Config{CAFile: "../testdata/ca.pem", Remote: "123::::123"}) if err == nil { t.Fatal("Invalid remote, should reort error") } } func TestOidMain(t *testing.T) { c := cli.Config{ CAFile: "../testdata/ca.pem", CAKeyFile: "../testdata/ca-key.pem", } err := gencertMain([]string{"../testdata/bad_oid_csr.json"}, c) if err == nil { t.Fatal("Expected error") } if !strings.Contains(err.Error(), "invalid OID part abc") { t.Fatalf("Unexpected error: %s", err.Error()) } } ================================================ FILE: cli/gencrl/gencrl.go ================================================ // Package gencrl implements the gencrl command package gencrl import ( "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/crl" "strings" ) var gencrlUsageText = `cfssl gencrl -- generate a new Certificate Revocation List Usage of gencrl: cfssl gencrl INPUTFILE CERT KEY TIME Arguments: INPUTFILE: Text file with one serial number per line, use '-' for reading text from stdin CERT: The certificate that is signing this CRL, use '-' for reading text from stdin KEY: The private key of the certificate that is signing the CRL, use '-' for reading text from stdin TIME (OPTIONAL): The desired expiration from now, in seconds Flags: ` var gencrlFlags = []string{} func gencrlMain(args []string, c cli.Config) (err error) { serialList, args, err := cli.PopFirstArgument(args) if err != nil { return } serialListBytes, err := cli.ReadStdin(serialList) if err != nil { return } certFile, args, err := cli.PopFirstArgument(args) if err != nil { return } certFileBytes, err := cli.ReadStdin(certFile) if err != nil { return } keyFile, args, err := cli.PopFirstArgument(args) if err != nil { return } keyBytes, err := cli.ReadStdin(keyFile) if err != nil { return } // Default value if no expiry time is given timeString := string("0") if len(args) > 0 { timeArg, _, err := cli.PopFirstArgument(args) if err != nil { return err } timeString = string(timeArg) // This is used to get rid of newlines timeString = strings.TrimSpace(timeString) } req, err := crl.NewCRLFromFile(serialListBytes, certFileBytes, keyBytes, timeString) if err != nil { return } cli.PrintCRL(req) return nil } // Command assembles the definition of Command 'gencrl' var Command = &cli.Command{UsageText: gencrlUsageText, Flags: gencrlFlags, Main: gencrlMain} ================================================ FILE: cli/gencrl/gencrl_test.go ================================================ package gencrl import ( "testing" "github.com/cloudflare/cfssl/cli" ) func TestGencrl(t *testing.T) { var err error err = gencrlMain([]string{"testdata/serialList", "testdata/caTwo.pem", "testdata/ca-keyTwo.pem"}, cli.Config{}) if err != nil { t.Fatal(err) } } func TestGencrlTime(t *testing.T) { err := gencrlMain([]string{"testdata/serialList", "testdata/caTwo.pem", "testdata/ca-keyTwo.pem", "123"}, cli.Config{}) if err != nil { t.Fatal(err) } } ================================================ FILE: cli/gencrl/testdata/ca-keyTwo.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEA3VWwbwHztFoVqQOZfyRtHs97tUfrdaurLs9p4KeD8VqsJ95h pQohNpiKgKQf1Sm3XeQPlQqA7FuI0kBefUwEjK8bMI/6I78CTLQZr7nHsKsJ8sg3 Qd+U82MukQIe+ssvLw4uSRfMCZ+DP6XYgdqyGYEvXd3o8oM0IlkIdRe1GXZpRZiT UrZy7N45e3HY/boBRIYqQFvpRh5LfLp5prQDB4124dwcc8OQTZBVWKED1aYO1292 wgmbgVwnOOfLSkqWZVZM/Vq999vGG+TE9NTX4v+/3TO0TKV3Ofn/WVgi7YmvmEbC U9diYbmg025glIU1ZY5ifsEOl817pvLC0YW6cQIDAQABAoIBACVeh1hmsvfbUdbk ZbEivE28aD2WM/n9DvzrRgwJHGzOi0x77m6IBE2Mea34h+tcjLoMfFkEmfnOBo7B EXMEN6xtECEl3ezVHhVHPyL9MerxJc/Y4AN+NU7WixEuk35yebfvI/9xRiDFzsob PS/HddR6jD3D7sWrQ00dTSE/7HKsy+SGS9AjfMJtdKYY16KNXaf/TJQesdJCfQQt ihCc3DRm3bhmCk8jtNKYVF3u6/lIAIRJIb5EMWajlPdMocKKaHQkXmFu1onNHc2G c7QHVnQe5a20UnruEaO+W/Nswyi5ml7tN6GPZf7jcfQW5eZwYAb3ey723Iu+WqO1 Ixp/q9UCgYEA+jasIKG6UT2JIa/caHjuauSEm4u05iJFdwrbAYHPAvrfdcMwgD/v CfuTGY3vTLCYTAJyFkXrKRi6KvTsKEUC9vRypgEou2cp0Kqt87smbanVVAy0HTYG W4/Ezfu1IaW1+AxvEirAXv12ZrZMrht9aaszw8AS2G009Rw3zKl8/BMCgYEA4nQL +X6uJHaTJFhmu+7ZycBwIl+HVyXgNDB6SjcyZPZ3rZ2ldnaliUw/eQzDlByzxEKA KgNxZbATwRwJTw5YX5iSVxnfsVfPyk1HK05LZ58YSYNRDzRocpdaGhKi7A23AMJu Dy9tsOe2E+1QG7Xw8yTQbNpxVDTBPG+S5POc9+sCgYEAvpP35N7qJ8jD80mcimJZ zkcCDeuKPKMr37EAAJTblPx6SZsDDRwlOKhKcXNfKj1zsqlGNlrI88NmwSNN4Jo3 2Nt1m6VUXfEEs2/dEMCiU3LBDsSiR4GHtCO8Fdw7KUarZCQsUV0IqxFJJpCBtTcw /dQtmFJqyDfd1zfH9HW/wcsCgYEArsWJiGEw3Yt2PJLNlzXceE1BPgYkWiotQ5o2 h5jaF/nwm9oTnb4sPC7QvggP2fvc8hew+rv1hNnEJUISHSWhJwaFyxt4/VIcWLIT v2SJ5ctv3yyuHuH/ypDtRTok67IaD0f/0VB1hBcQ+4goT3q4H6/F/H0LAkZE7PPf lzw9ZUkCgYEA+T21RPB7YHkMUsQg2UvvcshIQ2yDq0IdEc/NAsNVl0HjgP8hb+gk mvEC7mm9BuCMHj9fbxONINbj7KvN6MOZ1ZrH3HdIqMP8dtB3AacIyWESQmjGBLIR pKEnFu1TxE0P6SCnKgKDUlc4yFUak4pM98PlezwtLzLeHeif2LqDT00= -----END RSA PRIVATE KEY----- ================================================ FILE: cli/gencrl/testdata/caTwo.pem ================================================ -----BEGIN CERTIFICATE----- MIID4jCCAsqgAwIBAgIIMijYd8KfFrswDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE BhMCVVMxFTATBgNVBAoTDFRlc3QgQ29tcGFueTEUMBIGA1UECxMLSVQgU2Vydmlj ZXMxFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWEx FDASBgNVBAMTC3Rlc3RMb2NhbENBMB4XDTE1MTAwODIzMjYwMFoXDTIwMTAwNjIz MjYwMFowfTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDFRlc3QgQ29tcGFueTEUMBIG A1UECxMLSVQgU2VydmljZXMxFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNV BAgTCkNhbGlmb3JuaWExFDASBgNVBAMTC3Rlc3RMb2NhbENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3VWwbwHztFoVqQOZfyRtHs97tUfrdaurLs9p 4KeD8VqsJ95hpQohNpiKgKQf1Sm3XeQPlQqA7FuI0kBefUwEjK8bMI/6I78CTLQZ r7nHsKsJ8sg3Qd+U82MukQIe+ssvLw4uSRfMCZ+DP6XYgdqyGYEvXd3o8oM0IlkI dRe1GXZpRZiTUrZy7N45e3HY/boBRIYqQFvpRh5LfLp5prQDB4124dwcc8OQTZBV WKED1aYO1292wgmbgVwnOOfLSkqWZVZM/Vq999vGG+TE9NTX4v+/3TO0TKV3Ofn/ WVgi7YmvmEbCU9diYbmg025glIU1ZY5ifsEOl817pvLC0YW6cQIDAQABo2YwZDAO BgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQU6jzK 7+HcNGKm+TONgxyrYy/02qEwHwYDVR0jBBgwFoAU6jzK7+HcNGKm+TONgxyrYy/0 2qEwDQYJKoZIhvcNAQELBQADggEBAHG0ufzYb4/JTseE/0zuCU2efM1HbSqxcYb0 Q275In83m9SqxjwGB5kPx1Mp16j8Gapb5s0U9jFwCoI26uvNsEHkyYSdpq73Wi7+ 3oY3PdqWj7vL1jHxFZ73TCLoPXWppWIBardTkN9xOagDyc5VmUGhAWC3EubVo0GE Ty14AlfKXOxx+cDR62lXRdiF3Pzywfy3pL4hMgPxNyIMbULHWbU8JpGzIqAyiBsg SFT1labSuCciHL7R7YM2eA9MculAiWPtKbRpY1xKDCD4kgRrb5YzPoujSn6AqFNi RAxvQNcf2ahMcbof4rbuUHsOXzWWbwckA1Tv492T3FvtKzbFJbA= -----END CERTIFICATE----- ================================================ FILE: cli/gencrl/testdata/serialList ================================================ 1 2 3 4 ================================================ FILE: cli/gencsr/gencsr.go ================================================ // Package gencsr implements the gencsr command. package gencsr import ( "encoding/json" "errors" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/signer" ) var gencsrUsageText = `cfssl gencsr -- generate a csr from a private key with existing CSR json specification or certificate Usage of gencsr: cfssl gencsr -key private_key_file [-host hostname_override] CSRJSON cfssl gencsr -key private_key_file [-host hostname_override] -cert certificate_file Arguments: CSRJSON: JSON file containing the request, use '-' for reading JSON from stdin Flags: ` var gencsrFlags = []string{"key", "cert"} func gencsrMain(args []string, c cli.Config) (err error) { if c.KeyFile == "" { return errors.New("private key file is required through '-key', please check with usage") } keyBytes, err := helpers.ReadBytes(c.KeyFile) if err != nil { return err } key, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { return err } // prepare a stub CertificateRequest req := &csr.CertificateRequest{ KeyRequest: csr.NewKeyRequest(), } if c.CertFile != "" { if len(args) > 0 { return errors.New("no argument is accepted with '-cert', please check with usage") } certBytes, err := helpers.ReadBytes(c.CertFile) if err != nil { return err } cert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { return err } req = csr.ExtractCertificateRequest(cert) } else { csrFile, args, err := cli.PopFirstArgument(args) if err != nil { return err } if len(args) > 0 { return errors.New("only one argument is accepted, please check with usage") } csrFileBytes, err := cli.ReadStdin(csrFile) if err != nil { return err } err = json.Unmarshal(csrFileBytes, req) if err != nil { return err } } if c.Hostname != "" { req.Hosts = signer.SplitHosts(c.Hostname) } csrBytes, err := csr.Generate(key, req) if err != nil { return err } cli.PrintCert(keyBytes, csrBytes, nil) return nil } // Command assembles the definition of Command 'gencsr' var Command = &cli.Command{UsageText: gencsrUsageText, Flags: gencsrFlags, Main: gencsrMain} ================================================ FILE: cli/gencsr/gencsr_test.go ================================================ package gencsr import ( "encoding/json" "errors" "io" "os" "testing" "github.com/cloudflare/cfssl/cli" ) const ( testKeyFile = "testdata/test-key.pem" testCAKeyFile = "../testdata/ca-key.pem" testCACertFile = "../testdata/ca.pem" ) type stdoutRedirect struct { r *os.File w *os.File saved *os.File } func newStdoutRedirect() (*stdoutRedirect, error) { r, w, err := os.Pipe() if err != nil { return nil, err } pipe := &stdoutRedirect{r, w, os.Stdout} os.Stdout = pipe.w return pipe, nil } func (pipe *stdoutRedirect) readAll() ([]byte, error) { pipe.w.Close() os.Stdout = pipe.saved return io.ReadAll(pipe.r) } func checkResponse(out []byte) error { var response map[string]interface{} if err := json.Unmarshal(out, &response); err != nil { return err } if response["key"] == nil { return errors.New("no key is outputted") } if response["csr"] == nil { return errors.New("no csr is outputted") } return nil } func TestGencsr(t *testing.T) { var pipe *stdoutRedirect var out []byte var err error if pipe, err = newStdoutRedirect(); err != nil { t.Fatal(err) } if err := gencsrMain([]string{"testdata/csr.json"}, cli.Config{KeyFile: testKeyFile}); err != nil { t.Fatal(err) } if out, err = pipe.readAll(); err != nil { t.Fatal(err) } if err := checkResponse(out); err != nil { t.Fatal(err) } } func TestGencsrFromCert(t *testing.T) { var pipe *stdoutRedirect var out []byte var err error if pipe, err = newStdoutRedirect(); err != nil { t.Fatal(err) } if err := gencsrMain([]string{}, cli.Config{KeyFile: testCAKeyFile, CertFile: testCACertFile}); err != nil { t.Fatal(err) } if out, err = pipe.readAll(); err != nil { t.Fatal(err) } if err := checkResponse(out); err != nil { t.Fatal(err) } } func TestGencsrError(t *testing.T) { if err := gencsrMain([]string{"testdata/csr.json"}, cli.Config{}); err == nil { t.Fatal("should have erred.") } } ================================================ FILE: cli/gencsr/testdata/csr.json ================================================ { "hosts": [ "cloudflare.com", "www.cloudflare.com" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "San Francisco", "O": "CloudFlare", "OU": "Systems Engineering", "ST": "California" } ] } ================================================ FILE: cli/gencsr/testdata/test-key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA1ZdFFYhVAGNGQqnT1TEynFboX1tzqHOXU80ctSHFpCduuwzV ZESuh4qQJXfUS2BwAT+2sw2dvJTAQzMAQk0qW9L//VkMdbHCOLczEo2qc42lQuvn 2CN8fH+9XSo//VrKtQvOLGlnvu+HNG0dv5+ki/7UX40AHnMbHVd1CPzKOpKF8zZl S9Uo3Wg+7kHMrPuCUI8pKBkmz/wWOG2PTeos8HtxjwjX+XJ67iMfS0gRTDFfNfZU s6eXkZeC/86Bq4L9I4cyUAnMogKd9v9lyEz7obM9UDrbCe+Rnxm4mzPHjc52v2JA Uslvm3xOHtGXE/YHzYzeG5+/81+0Ks8wLmMRCQIDAQABAoIBAQCUS4i9oIBT2pln o33eIWBgR77iph4xMMA6gMiTwjT0+iPZXtmx2jXLCZt3SDFvfC+HznLM8oE385dh kMF3RxhH1MHDZtZNyPNuaVPeZ9mWjRvW0O+Rk2HVFuOlEbaH80eWV/H3x98uJCQd dD0ZVH/sayuMg9s3SPfkcVpiuRC3hMp2yVNUYBBZkTyyMvjhgsEGYxUvHFdD/Yh4 8gJF90VpsvvnoReU9htP6e1vn/gG5d6mgDa9ySvAzB+kMbcJG6k9JDjIzX6sunca YzQsqz+iwtxbZ3q5Q4IHvJveFsyEKhRei7PkkS88VDIloquL0A7jQ5dPF2OQw9jH F3GEUeR5AoGBANtFavWnWQGa+cg25bHiFWxDfVo/G0N5mmu9bXQqU2QM1Gknz8lg QAnB9d02iGEhJ58MfjEOAqEoCM/NpcA69dmfh7rUtIelG7Cxc083RjtcQ3OIuwI0 AFCsSfOiFZDCVH9Q7ThaRPvyxbQBWeXOfVXyLaqNdv3jdORVapvLRZ17AoGBAPle RrQxY5utaLN7SS781px8jmgnSXHeK1Cg6BNaRCm1ngWht71ET9H23i5TGdIWunVj gOi1LypRtA4UHor8QWAX3ebUC1V4oBsqMPbY3S77aqO+xMFNlBeIfykXe+4/At6j pWnRn6CJJ2c1+0rLXT8fG5VYRKvTrQ0BvJ0ki2pLAoGAbW+/C24DgUac5e1oRJjH AmrItHMMo2ecx6saZsD9L9ErbnQ9Q49zRqt0j3y5ImkOwlXU4ZzReSdnBnfoAwIq U/xIHNouZAjmwhA+scmvls7cp1wVoercQWdL3XoG82HaFFUKoHaFOY4YWFfYS1b8 vRmK6zWBrwOIArIS7EDOtOMCgYEAw7Lg+fjomvvz9ycBwAZcxmJZwBNU6C/a/mPI vadRZwpJAVJwx/AcVELRCrncwatkmUuFlxrZ8PQ9we64KYreI3OXiddPLbyEqczq sE5xBrX4cpj8AFfJqM5OPQlZERgSQHddETaZd3srmSwcEg6XFzpqg0HKYq60WEjM pOZRIxECgYBvikh4H2K6Fi0KOoVnY9OqZwP9LYC9xXZXhyRMxmQOcdYlBtiK6x/o 4vE3gHsKY+l17/FI8cEZTl+FQgAwmZ1Rd4843uu4OySg0EFBbu46WKcJrvdXXwSv OeLJKG7fkUg7qxcDgxuhY9qLZaxi6DeLTw7ZB41GSr9w6KExw/nfqw== -----END RSA PRIVATE KEY----- ================================================ FILE: cli/genkey/genkey.go ================================================ // Package genkey implements the genkey command. package genkey import ( "encoding/json" "errors" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/initca" ) var genkeyUsageText = `cfssl genkey -- generate a new key and CSR Usage of genkey: cfssl genkey CSRJSON Arguments: CSRJSON: JSON file containing the request, use '-' for reading JSON from stdin Flags: ` var genkeyFlags = []string{"initca", "config"} func genkeyMain(args []string, c cli.Config) (err error) { csrFile, args, err := cli.PopFirstArgument(args) if err != nil { return } if len(args) > 0 { return errors.New("only one argument is accepted, please check with usage") } csrFileBytes, err := cli.ReadStdin(csrFile) if err != nil { return } req := csr.CertificateRequest{ KeyRequest: csr.NewKeyRequest(), } err = json.Unmarshal(csrFileBytes, &req) if err != nil { return } if c.IsCA { var key, csrPEM, cert []byte cert, csrPEM, key, err = initca.New(&req) if err != nil { return } cli.PrintCert(key, csrPEM, cert) } else { if req.CA != nil { err = errors.New("ca section only permitted in initca") return } var key, csrPEM []byte g := &csr.Generator{Validator: Validator} csrPEM, key, err = g.ProcessRequest(&req) if err != nil { key = nil return } cli.PrintCert(key, csrPEM, nil) } return nil } // Validator does nothing and will never return an error. It exists because creating a // csr.Generator requires a Validator. func Validator(req *csr.CertificateRequest) error { return nil } // Command assembles the definition of Command 'genkey' var Command = &cli.Command{UsageText: genkeyUsageText, Flags: genkeyFlags, Main: genkeyMain} ================================================ FILE: cli/genkey/genkey_test.go ================================================ package genkey import ( "encoding/json" "errors" "io" "os" "testing" "github.com/cloudflare/cfssl/cli" ) type stdoutRedirect struct { r *os.File w *os.File saved *os.File } func newStdoutRedirect() (*stdoutRedirect, error) { r, w, err := os.Pipe() if err != nil { return nil, err } pipe := &stdoutRedirect{r, w, os.Stdout} os.Stdout = pipe.w return pipe, nil } func (pipe *stdoutRedirect) readAll() ([]byte, error) { pipe.w.Close() os.Stdout = pipe.saved return io.ReadAll(pipe.r) } func checkResponse(out []byte) error { var response map[string]interface{} if err := json.Unmarshal(out, &response); err != nil { return err } if response["key"] == nil { return errors.New("no key is outputted") } if response["csr"] == nil { return errors.New("no csr is outputted") } return nil } func TestGenkey(t *testing.T) { var pipe *stdoutRedirect var out []byte var err error if pipe, err = newStdoutRedirect(); err != nil { t.Fatal(err) } if err := genkeyMain([]string{"testdata/csr.json"}, cli.Config{}); err != nil { t.Fatal(err) } if out, err = pipe.readAll(); err != nil { t.Fatal(err) } if err := checkResponse(out); err != nil { t.Fatal(err) } if pipe, err = newStdoutRedirect(); err != nil { t.Fatal(err) } if err := genkeyMain([]string{"testdata/csr.json"}, cli.Config{IsCA: true}); err != nil { t.Fatal(err) } if out, err = pipe.readAll(); err != nil { t.Fatal(err) } if err := checkResponse(out); err != nil { t.Fatal(err) } } ================================================ FILE: cli/genkey/testdata/csr.json ================================================ { "hosts": [ "cloudflare.com", "www.cloudflare.com" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "San Francisco", "O": "CloudFlare", "OU": "Systems Engineering", "ST": "California" } ] } ================================================ FILE: cli/info/info.go ================================================ // Package info implements the info command. package info import ( "encoding/json" "fmt" "github.com/cloudflare/cfssl/api/client" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/cli/sign" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/info" goerr "errors" ) var infoUsageTxt = `cfssl info -- get info about a remote signer Usage: Get info about a remote signer: cfssl info -remote remote_host [-label label] [-profile profile] [-label label] Flags: ` var infoFlags = []string{"remote", "label", "profile", "config"} func getInfoFromRemote(c cli.Config) (resp *info.Resp, err error) { req := new(info.Req) req.Label = c.Label req.Profile = c.Profile cert, err := helpers.LoadClientCertificate(c.MutualTLSCertFile, c.MutualTLSKeyFile) if err != nil { return } remoteCAs, err := helpers.LoadPEMCertPool(c.TLSRemoteCAs) if err != nil { return } serv := client.NewServerTLS(c.Remote, helpers.CreateTLSConfig(remoteCAs, cert)) reqJSON, _ := json.Marshal(req) resp, err = serv.Info(reqJSON) if err != nil { return } _, err = helpers.ParseCertificatePEM([]byte(resp.Certificate)) if err != nil { return } return } func getInfoFromConfig(c cli.Config) (resp *info.Resp, err error) { s, err := sign.SignerFromConfig(c) if err != nil { return } req := new(info.Req) req.Label = c.Label req.Profile = c.Profile resp, err = s.Info(*req) if err != nil { return } return } func infoMain(args []string, c cli.Config) (err error) { if len(args) > 0 { return goerr.New("argument is provided but not defined; please refer to the usage by flag -h.") } var resp *info.Resp if c.Remote != "" { resp, err = getInfoFromRemote(c) if err != nil { return } } else if c.CFG != nil { resp, err = getInfoFromConfig(c) if err != nil { return } } else { return goerr.New("Either -remote or -config must be given. Refer to cfssl info -h for usage.") } respJSON, err := json.Marshal(resp) if err != nil { return errors.NewBadRequest(err) } fmt.Print(string(respJSON)) return nil } // Command assembles the definition of Command 'info' var Command = &cli.Command{ UsageText: infoUsageTxt, Flags: infoFlags, Main: infoMain, } ================================================ FILE: cli/ocspdump/ocspdump.go ================================================ // Package ocspdump implements the ocspdump command. package ocspdump import ( "encoding/base64" "errors" "fmt" "github.com/cloudflare/cfssl/certdb/dbconf" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/cli" ) // Usage text of 'cfssl ocspdump' var ocspdumpUsageText = `cfssl ocspdump -- generates a series of concatenated OCSP responses for use with ocspserve from all OCSP responses in the cert db Usage of ocspdump: cfssl ocspdump -db-config db-config Flags: ` // Flags of 'cfssl ocspdump' var ocspdumpFlags = []string{"db-config"} // ocspdumpMain is the main CLI of OCSP dump functionality. func ocspdumpMain(args []string, c cli.Config) error { if c.DBConfigFile == "" { return errors.New("need DB config file (provide with -db-config)") } db, err := dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return err } dbAccessor := sql.NewAccessor(db) records, err := dbAccessor.GetUnexpiredOCSPs() if err != nil { return err } for _, certRecord := range records { fmt.Printf("%s\n", base64.StdEncoding.EncodeToString([]byte(certRecord.Body))) } return nil } // Command assembles the definition of Command 'ocspdump' var Command = &cli.Command{UsageText: ocspdumpUsageText, Flags: ocspdumpFlags, Main: ocspdumpMain} ================================================ FILE: cli/ocsprefresh/ocsprefresh.go ================================================ // Package ocsprefresh implements the ocsprefresh command. package ocsprefresh import ( "encoding/hex" "errors" "time" "github.com/cloudflare/cfssl/certdb/dbconf" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/ocsp" ) // Usage text of 'cfssl ocsprefresh' var ocsprefreshUsageText = `cfssl ocsprefresh -- refreshes the ocsp_responses table with new OCSP responses for all known unexpired certificates Usage of ocsprefresh: cfssl ocsprefresh -db-config db-config -ca cert -responder cert -responder-key key [-interval 96h] Flags: ` // Flags of 'cfssl ocsprefresh' var ocsprefreshFlags = []string{"ca", "responder", "responder-key", "db-config", "interval"} // ocsprefreshMain is the main CLI of OCSP refresh functionality. func ocsprefreshMain(args []string, c cli.Config) error { if c.DBConfigFile == "" { return errors.New("need DB config file (provide with -db-config)") } if c.ResponderFile == "" { return errors.New("need responder certificate (provide with -responder)") } if c.ResponderKeyFile == "" { return errors.New("need responder key (provide with -responder-key)") } if c.CAFile == "" { return errors.New("need CA certificate (provide with -ca)") } s, err := SignerFromConfig(c) if err != nil { log.Critical("Unable to create OCSP signer: ", err) return err } db, err := dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return err } dbAccessor := sql.NewAccessor(db) certs, err := dbAccessor.GetUnexpiredCertificates() if err != nil { return err } // Set an expiry timestamp for all certificates refreshed in this batch ocspExpiry := time.Now().Add(c.Interval) for _, certRecord := range certs { cert, err := helpers.ParseCertificatePEM([]byte(certRecord.PEM)) if err != nil { log.Critical("Unable to parse certificate: ", err) return err } req := ocsp.SignRequest{ Certificate: cert, Status: certRecord.Status, } if certRecord.Status == "revoked" { req.Reason = int(certRecord.Reason) req.RevokedAt = certRecord.RevokedAt } resp, err := s.Sign(req) if err != nil { log.Critical("Unable to sign OCSP response: ", err) return err } err = dbAccessor.UpsertOCSP(cert.SerialNumber.String(), hex.EncodeToString(cert.AuthorityKeyId), string(resp), ocspExpiry) if err != nil { log.Critical("Unable to save OCSP response: ", err) return err } } return nil } // SignerFromConfig creates a signer from a cli.Config as a helper for cli and serve func SignerFromConfig(c cli.Config) (ocsp.Signer, error) { //if this is called from serve then we need to use the specific responder key file //fallback to key for backwards-compatibility k := c.ResponderKeyFile if k == "" { k = c.KeyFile } return ocsp.NewSignerFromFile(c.CAFile, c.ResponderFile, k, time.Duration(c.Interval)) } // Command assembles the definition of Command 'ocsprefresh' var Command = &cli.Command{UsageText: ocsprefreshUsageText, Flags: ocsprefreshFlags, Main: ocsprefreshMain} ================================================ FILE: cli/ocsprefresh/ocsprefresh_test.go ================================================ package ocsprefresh import ( "encoding/hex" "os" "testing" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/helpers" "golang.org/x/crypto/ocsp" ) var dbAccessor certdb.Accessor func TestOCSPRefreshMain(t *testing.T) { db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") certPEM, err := os.ReadFile("../../ocsp/testdata/cert.pem") if err != nil { t.Fatal(err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } expirationTime := time.Now().AddDate(1, 0, 0) certRecord := certdb.CertificateRecord{ Serial: cert.SerialNumber.String(), AKI: hex.EncodeToString(cert.AuthorityKeyId), Expiry: expirationTime, PEM: string(certPEM), Status: "good", } dbAccessor = sql.NewAccessor(db) err = dbAccessor.InsertCertificate(certRecord) if err != nil { t.Fatal(err) } err = ocsprefreshMain([]string{}, cli.Config{ CAFile: "../../ocsp/testdata/ca.pem", ResponderFile: "../../ocsp/testdata/server.crt", ResponderKeyFile: "../../ocsp/testdata/server.key", DBConfigFile: "../testdata/db-config.json", Interval: helpers.OneDay, }) if err != nil { t.Fatal(err) } records, err := dbAccessor.GetUnexpiredOCSPs() if err != nil { t.Fatal("Failed to get OCSP responses") } if len(records) != 1 { t.Fatal("Expected one OCSP response") } var resp *ocsp.Response resp, err = ocsp.ParseResponse([]byte(records[0].Body), nil) if err != nil { t.Fatal("Failed to parse OCSP response") } if resp.Status != ocsp.Good { t.Fatal("Expected cert status 'good'") } err = dbAccessor.RevokeCertificate(certRecord.Serial, certRecord.AKI, ocsp.KeyCompromise) if err != nil { t.Fatal("Failed to revoke certificate") } err = ocsprefreshMain([]string{}, cli.Config{ CAFile: "../../ocsp/testdata/ca.pem", ResponderFile: "../../ocsp/testdata/server.crt", ResponderKeyFile: "../../ocsp/testdata/server.key", DBConfigFile: "../testdata/db-config.json", Interval: helpers.OneDay, }) if err != nil { t.Fatal(err) } records, err = dbAccessor.GetUnexpiredOCSPs() if err != nil { t.Fatal("Failed to get OCSP responses") } if len(records) != 1 { t.Fatal("Expected one OCSP response") } resp, err = ocsp.ParseResponse([]byte(records[0].Body), nil) if err != nil { t.Fatal("Failed to parse OCSP response") } if resp.Status != ocsp.Revoked { t.Fatal("Expected cert status 'revoked'") } } ================================================ FILE: cli/ocspserve/ocspserve.go ================================================ // Package ocspserve implements the ocspserve function. package ocspserve import ( "errors" "net" "net/http" "strconv" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/ocsp" ) // Usage text of 'cfssl serve' var ocspServerUsageText = `cfssl ocspserve -- set up an HTTP server that handles OCSP requests from either a file or directly from a database (see RFC 5019) Usage of ocspserve: cfssl ocspserve [-address address] [-port port] [-responses file] [-db-config db-config] Flags: ` // Flags used by 'cfssl serve' var ocspServerFlags = []string{"address", "port", "responses", "db-config"} // ocspServerMain is the command line entry point to the OCSP responder. // It sets up a new HTTP server that responds to OCSP requests. func ocspServerMain(args []string, c cli.Config) error { var src ocsp.Source // serve doesn't support arguments. if len(args) > 0 { return errors.New("argument is provided but not defined; please refer to the usage by flag -h") } if c.Responses != "" { s, err := ocsp.NewSourceFromFile(c.Responses) if err != nil { return errors.New("unable to read response file") } src = s } else if c.DBConfigFile != "" { s, err := ocsp.NewSourceFromDB(c.DBConfigFile) if err != nil { return errors.New("unable to read configuration file") } src = s } else { return errors.New( "no response file or db-config provided, please set the one of these using either -responses or -db-config flags", ) } log.Info("Registering OCSP responder handler") http.Handle(c.Path, ocsp.NewResponder(src, nil)) addr := net.JoinHostPort(c.Address, strconv.Itoa(c.Port)) log.Info("Now listening on ", addr) return http.ListenAndServe(addr, nil) } // Command assembles the definition of Command 'ocspserve' var Command = &cli.Command{UsageText: ocspServerUsageText, Flags: ocspServerFlags, Main: ocspServerMain} ================================================ FILE: cli/ocspsign/ocspsign.go ================================================ // Package ocspsign implements the ocspsign command. package ocspsign import ( "os" "time" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/ocsp" ) // Usage text of 'cfssl ocspsign' var ocspSignerUsageText = `cfssl ocspsign -- signs an OCSP response for a given CA, cert, and status. Returns a base64-encoded OCSP response. Usage of ocspsign: cfssl ocspsign -ca cert -responder cert -responder-key key -cert cert [-status status] [-reason code] [-revoked-at YYYY-MM-DD] [-interval 96h] Flags: ` // Flags of 'cfssl ocspsign' var ocspSignerFlags = []string{"ca", "responder", "responder-key", "reason", "status", "revoked-at", "interval"} // ocspSignerMain is the main CLI of OCSP signer functionality. func ocspSignerMain(args []string, c cli.Config) (err error) { // Read the cert to be revoked from file certBytes, err := os.ReadFile(c.CertFile) if err != nil { log.Critical("Unable to read certificate: ", err) return } cert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { log.Critical("Unable to parse certificate: ", err) return } req := ocsp.SignRequest{ Certificate: cert, Status: c.Status, } if c.Status == "revoked" { var reasonCode int reasonCode, err = ocsp.ReasonStringToCode(c.Reason) if err != nil { log.Critical("Invalid reason code: ", err) return } req.Reason = reasonCode req.RevokedAt = time.Now() if c.RevokedAt != "now" { req.RevokedAt, err = time.Parse("2006-01-02", c.RevokedAt) if err != nil { log.Critical("Malformed revocation time: ", c.RevokedAt) return } } } s, err := SignerFromConfig(c) if err != nil { log.Critical("Unable to create OCSP signer: ", err) return } resp, err := s.Sign(req) if err != nil { log.Critical("Unable to sign OCSP response: ", err) return } cli.PrintOCSPResponse(resp) return } // SignerFromConfig creates a signer from a cli.Config as a helper for cli and serve func SignerFromConfig(c cli.Config) (ocsp.Signer, error) { // if this is called from serve then we need to use the specific responder key file // fallback to key for backwards-compatibility k := c.ResponderKeyFile if k == "" { k = c.KeyFile } return ocsp.NewSignerFromFile(c.CAFile, c.ResponderFile, k, time.Duration(c.Interval)) } // Command assembles the definition of Command 'ocspsign' var Command = &cli.Command{UsageText: ocspSignerUsageText, Flags: ocspSignerFlags, Main: ocspSignerMain} ================================================ FILE: cli/printdefault/defaults.go ================================================ package printdefaults var defaults = map[string]string{ "config": `{ "signing": { "default": { "expiry": "168h" }, "profiles": { "www": { "expiry": "8760h", "usages": [ "signing", "key encipherment", "server auth" ] }, "client": { "expiry": "8760h", "usages": [ "signing", "key encipherment", "client auth" ] } } } } `, "csr": `{ "CN": "example.net", "hosts": [ "example.net", "www.example.net" ], "key": { "algo": "ecdsa", "size": 256 }, "names": [ { "C": "US", "ST": "CA", "L": "San Francisco" } ] } `, } ================================================ FILE: cli/printdefault/printdefault.go ================================================ package printdefaults import ( "fmt" "github.com/cloudflare/cfssl/cli" ) var printDefaultsUsage = `cfssl print-defaults -- print default configurations that can be used as a template Usage of print-defaults: cfssl print-defaults TYPE If "list" is used as the TYPE, the list of supported types will be printed. ` func printAvailable() { fmt.Println("Default configurations are available for:") for name := range defaults { fmt.Println("\t" + name) } } func printDefaults(args []string, c cli.Config) (err error) { arg, _, err := cli.PopFirstArgument(args) if err != nil { return } if arg == "list" { printAvailable() } else { if config, ok := defaults[arg]; !ok { printAvailable() } else { fmt.Println(config) } } return } // Command assembles the definition of Command 'print-defaults' var Command = &cli.Command{ UsageText: printDefaultsUsage, Flags: []string{}, Main: printDefaults, } ================================================ FILE: cli/revoke/revoke.go ================================================ // Package revoke implements the revoke command. package revoke import ( "errors" "github.com/cloudflare/cfssl/certdb/dbconf" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/ocsp" ) var revokeUsageTxt = `cfssl revoke -- revoke a certificate in the certificate store Usage: Revoke a certificate: cfssl revoke -db-config config_file -serial serial -aki authority_key_id [-reason reason] Reason can be an integer code or a string in ReasonFlags in RFC 5280 Flags: ` var revokeFlags = []string{"serial", "reason"} func revokeMain(args []string, c cli.Config) error { if len(args) > 0 { return errors.New("argument is provided but not defined; please refer to the usage by flag -h") } if len(c.Serial) == 0 { return errors.New("serial number is required but not provided") } if len(c.AKI) == 0 { return errors.New("authority key id is required but not provided") } if c.DBConfigFile == "" { return errors.New("need DB config file (provide with -db-config)") } db, err := dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return err } dbAccessor := sql.NewAccessor(db) reasonCode, err := ocsp.ReasonStringToCode(c.Reason) if err != nil { log.Error("Invalid reason code: ", err) return err } return dbAccessor.RevokeCertificate(c.Serial, c.AKI, reasonCode) } // Command assembles the definition of Command 'revoke' var Command = &cli.Command{ UsageText: revokeUsageTxt, Flags: revokeFlags, Main: revokeMain, } ================================================ FILE: cli/revoke/revoke_test.go ================================================ package revoke import ( "testing" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/cloudflare/cfssl/cli" "golang.org/x/crypto/ocsp" ) var dbAccessor certdb.Accessor const ( fakeAKI = "fake aki" ) func prepDB() (err error) { db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") expirationTime := time.Now().AddDate(1, 0, 0) var cert = certdb.CertificateRecord{ Serial: "1", AKI: fakeAKI, Expiry: expirationTime, PEM: "unexpired cert", } dbAccessor = sql.NewAccessor(db) err = dbAccessor.InsertCertificate(cert) if err != nil { return err } return } func TestRevokeMain(t *testing.T) { err := prepDB() if err != nil { t.Fatal(err) } err = revokeMain([]string{}, cli.Config{Serial: "1", AKI: fakeAKI, DBConfigFile: "../testdata/db-config.json"}) if err != nil { t.Fatal(err) } crs, err := dbAccessor.GetCertificate("1", fakeAKI) if err != nil { t.Fatal("Failed to get certificate") } if len(crs) != 1 { t.Fatal("Failed to get exactly one certificate") } cr := crs[0] if cr.Status != "revoked" { t.Fatal("Certificate not marked revoked after we revoked it") } err = revokeMain([]string{}, cli.Config{Serial: "1", AKI: fakeAKI, Reason: "2", DBConfigFile: "../testdata/db-config.json"}) if err != nil { t.Fatal(err) } crs, err = dbAccessor.GetCertificate("1", fakeAKI) if err != nil { t.Fatal("Failed to get certificate") } if len(crs) != 1 { t.Fatal("Failed to get exactly one certificate") } cr = crs[0] if cr.Reason != 2 { t.Fatal("Certificate revocation reason incorrect") } err = revokeMain([]string{}, cli.Config{Serial: "1", AKI: fakeAKI, Reason: "Superseded", DBConfigFile: "../testdata/db-config.json"}) if err != nil { t.Fatal(err) } crs, err = dbAccessor.GetCertificate("1", fakeAKI) if err != nil { t.Fatal("Failed to get certificate") } if len(crs) != 1 { t.Fatal("Failed to get exactly one certificate") } cr = crs[0] if cr.Reason != ocsp.Superseded { t.Fatal("Certificate revocation reason incorrect") } err = revokeMain([]string{}, cli.Config{Serial: "1", AKI: fakeAKI, Reason: "invalid_reason", DBConfigFile: "../testdata/db-config.json"}) if err == nil { t.Fatal("Expected error from invalid reason") } err = revokeMain([]string{}, cli.Config{Serial: "1", AKI: fakeAKI, Reason: "999", DBConfigFile: "../testdata/db-config.json"}) if err == nil { t.Fatal("Expected error from invalid reason") } err = revokeMain([]string{}, cli.Config{Serial: "2", AKI: fakeAKI, DBConfigFile: "../testdata/db-config.json"}) if err == nil { t.Fatal("Expected error from unrecognized serial number") } err = revokeMain([]string{}, cli.Config{AKI: fakeAKI, DBConfigFile: "../testdata/db-config.json"}) if err == nil { t.Fatal("Expected error from missing serial number") } err = revokeMain([]string{}, cli.Config{Serial: "1", AKI: fakeAKI}) if err == nil { t.Fatal("Expected error from missing db config") } err = revokeMain([]string{}, cli.Config{Serial: "1", DBConfigFile: "../testdata/db-config.json"}) if err == nil { t.Fatal("Expected error from missing aki") } } ================================================ FILE: cli/scan/scan.go ================================================ package scan import ( "encoding/csv" "encoding/json" "fmt" "io" "os" "sync" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/scan" ) var scanUsageText = `cfssl scan -- scan a host for issues Usage of scan: cfssl scan [-family regexp] [-scanner regexp] [-timeout duration] [-ip IPAddr] [-num-workers num] [-max-hosts num] [-csv hosts.csv] HOST+ cfssl scan -list Arguments: HOST: Host(s) to scan (including port) Flags: ` var scanFlags = []string{"list", "family", "scanner", "timeout", "ip", "ca-bundle", "num-workers", "csv", "max-hosts"} func printJSON(v interface{}) { b, err := json.MarshalIndent(v, "", " ") if err != nil { fmt.Println(err) } fmt.Printf("%s\n\n", b) } type context struct { sync.WaitGroup c cli.Config hosts chan string } func newContext(c cli.Config, numWorkers int) *context { ctx := &context{ c: c, hosts: make(chan string, numWorkers), } ctx.Add(numWorkers) for i := 0; i < numWorkers; i++ { go ctx.runWorker() } return ctx } func (ctx *context) runWorker() { for host := range ctx.hosts { fmt.Printf("Scanning %s...\n", host) results, err := scan.Default.RunScans(host, ctx.c.IP, ctx.c.Family, ctx.c.Scanner, ctx.c.Timeout) fmt.Printf("=== %s ===\n", host) if err != nil { log.Error(err) } else { printJSON(results) } } ctx.Done() } func parseCSV(hosts []string, csvFile string, maxHosts int) ([]string, error) { f, err := os.Open(csvFile) if err != nil { return nil, err } defer f.Close() r := csv.NewReader(f) for err == nil && len(hosts) < maxHosts { var record []string record, err = r.Read() hosts = append(hosts, record[len(record)-1]) } if err == io.EOF { err = nil } return hosts, err } func scanMain(args []string, c cli.Config) (err error) { if c.List { printJSON(scan.Default) } else { if err = scan.LoadRootCAs(c.CABundleFile); err != nil { return } if len(args) >= c.MaxHosts { log.Warningf("Only scanning max-hosts=%d out of %d args given", c.MaxHosts, len(args)) args = args[:c.MaxHosts] } else if c.CSVFile != "" { args, err = parseCSV(args, c.CSVFile, c.MaxHosts) if err != nil { return } } ctx := newContext(c, c.NumWorkers) // Execute for each HOST argument given for len(args) > 0 { var host string host, args, err = cli.PopFirstArgument(args) if err != nil { return } ctx.hosts <- host } close(ctx.hosts) ctx.Wait() } return } // Command assembles the definition of Command 'scan' var Command = &cli.Command{UsageText: scanUsageText, Flags: scanFlags, Main: scanMain} ================================================ FILE: cli/scan/scan_test.go ================================================ package scan import ( "testing" "github.com/cloudflare/cfssl/cli" ) var hosts = []string{"www.cloudflare.com", "google.com"} func TestScanMain(t *testing.T) { err := scanMain(hosts, cli.Config{}) if err != nil { t.Fatal(err) } err = scanMain(nil, cli.Config{Hostname: "www.cloudflare.com, google.com", List: true}) if err != nil { t.Fatal(err) } } ================================================ FILE: cli/selfsign/selfsign.go ================================================ // Package selfsign implements the selfsign command. package selfsign import ( "encoding/json" "errors" "fmt" "os" "time" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/cli/genkey" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/selfsign" ) var selfSignUsageText = `cfssl selfsign -- generate a new self-signed key and signed certificate Usage of gencert: cfssl selfsign HOSTNAME CSRJSON WARNING: this should ONLY be used for testing. This should never be used in production. WARNING: self-signed certificates are insecure; they do not provide the authentication required for secure systems. Use these at your own risk. Arguments: HOSTNAME: Hostname for the cert CSRJSON: JSON file containing the request, use '-' for reading JSON from stdin Flags: ` var selfSignFlags = []string{"config"} func selfSignMain(args []string, c cli.Config) (err error) { if c.Hostname == "" && !c.IsCA { c.Hostname, args, err = cli.PopFirstArgument(args) if err != nil { return } } csrFile, args, err := cli.PopFirstArgument(args) if err != nil { return } if len(args) > 0 { return errors.New("too many arguments are provided, please check with usage") } csrFileBytes, err := cli.ReadStdin(csrFile) if err != nil { return } var req = csr.New() err = json.Unmarshal(csrFileBytes, req) if err != nil { return } var key, csrPEM []byte g := &csr.Generator{Validator: genkey.Validator} csrPEM, key, err = g.ProcessRequest(req) if err != nil { key = nil return } priv, err := helpers.ParsePrivateKeyPEM(key) if err != nil { key = nil return } var profile *config.SigningProfile // If there is a config, use its signing policy. Otherwise, leave policy == nil // and NewSigner will use DefaultConfig(). if c.CFG != nil { if c.Profile != "" && c.CFG.Signing.Profiles != nil { profile = c.CFG.Signing.Profiles[c.Profile] } if profile == nil { profile = c.CFG.Signing.Default } } if profile == nil { profile = config.DefaultConfig() profile.Expiry = 2190 * time.Hour } cert, err := selfsign.Sign(priv, csrPEM, profile) if err != nil { key = nil priv = nil return } fmt.Fprintf(os.Stderr, `*** WARNING *** Self-signed certificates are dangerous. Use this self-signed certificate at your own risk. It is strongly recommended that these certificates NOT be used in production. *** WARNING *** `) cli.PrintCert(key, csrPEM, cert) return } // Command assembles the definition of Command 'selfsign' var Command = &cli.Command{UsageText: selfSignUsageText, Flags: selfSignFlags, Main: selfSignMain} ================================================ FILE: cli/selfsign/selfsign_test.go ================================================ package selfsign import ( "testing" "github.com/cloudflare/cfssl/cli" ) func TestSelfSignMain(t *testing.T) { err := selfSignMain([]string{"cloudflare.com", "../../testdata/csr.json"}, cli.Config{Hostname: ""}) if err != nil { t.Fatal(err) } } func TestBadSelfSignMain(t *testing.T) { err := selfSignMain([]string{"cloudflare.com"}, cli.Config{Hostname: ""}) if err == nil { t.Fatal("No CSR, should report error") } err = selfSignMain([]string{}, cli.Config{Hostname: ""}) if err == nil { t.Fatal("No server, should report error") } err = selfSignMain([]string{"cloudflare.com", "../../testdata/garbage.key"}, cli.Config{Hostname: ""}) if err == nil { t.Fatal("Wrong CSR file, should report error") } } ================================================ FILE: cli/serve/README.md ================================================ ## Compiling and serving static files using esc ``` go install github.com/mjibson/esc # Compile changes to static files esc -pkg serve -prefix cli/serve/static cli/serve/static > cli/serve/static.go # Build and run CFSSL go build ./cmd/cfssl/... ./cfssl serve ``` ================================================ FILE: cli/serve/serve.go ================================================ // Package serve implements the serve command for CFSSL's API. package serve import ( "crypto/tls" "embed" "errors" "fmt" "io/fs" "net" "net/http" "net/url" "os" "regexp" "strconv" "strings" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/api/bundle" "github.com/cloudflare/cfssl/api/certadd" "github.com/cloudflare/cfssl/api/certinfo" "github.com/cloudflare/cfssl/api/crl" "github.com/cloudflare/cfssl/api/gencrl" "github.com/cloudflare/cfssl/api/generator" "github.com/cloudflare/cfssl/api/health" "github.com/cloudflare/cfssl/api/info" "github.com/cloudflare/cfssl/api/initca" apiocsp "github.com/cloudflare/cfssl/api/ocsp" "github.com/cloudflare/cfssl/api/revoke" "github.com/cloudflare/cfssl/api/scan" "github.com/cloudflare/cfssl/api/signhandler" "github.com/cloudflare/cfssl/bundler" "github.com/cloudflare/cfssl/certdb/dbconf" certsql "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/cli" ocspsign "github.com/cloudflare/cfssl/cli/ocspsign" "github.com/cloudflare/cfssl/cli/sign" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/ocsp" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/ubiquity" "github.com/jmoiron/sqlx" ) // Usage text of 'cfssl serve' var serverUsageText = `cfssl serve -- set up a HTTP server handles CF SSL requests Usage of serve: cfssl serve [-address address] [-min-tls-version version] [-ca cert] [-ca-bundle bundle] \ [-ca-key key] [-int-bundle bundle] [-int-dir dir] [-port port] \ [-metadata file] [-remote remote_host] [-config config] \ [-responder cert] [-responder-key key] \ [-tls-cert cert] [-tls-key key] [-mutual-tls-ca ca] [-mutual-tls-cn regex] \ [-tls-remote-ca ca] [-mutual-tls-client-cert cert] [-mutual-tls-client-key key] \ [-db-config db-config] [-disable endpoint[,endpoint]] Flags: ` // Flags used by 'cfssl serve' var serverFlags = []string{"address", "port", "min-tls-version", "ca", "ca-key", "ca-bundle", "int-bundle", "int-dir", "metadata", "remote", "config", "responder", "responder-key", "tls-key", "tls-cert", "mutual-tls-ca", "mutual-tls-cn", "tls-remote-ca", "mutual-tls-client-cert", "mutual-tls-client-key", "db-config", "disable"} var ( conf cli.Config s signer.Signer ocspSigner ocsp.Signer db *sqlx.DB ) // V1APIPrefix is the prefix of all CFSSL V1 API Endpoints. var V1APIPrefix = "/api/v1/cfssl/" // v1APIPath prepends the V1 API prefix to endpoints not beginning with "/" func v1APIPath(path string) string { if !strings.HasPrefix(path, "/") { path = V1APIPrefix + path } return (&url.URL{Path: path}).String() } //go:embed static var staticContent embed.FS var staticRedirections = map[string]string{ "bundle": "index.html", "scan": "index.html", "packages": "index.html", } type staticFS struct { fs fs.FS redirections map[string]string } func (s *staticFS) Open(name string) (fs.File, error) { if strings.HasPrefix(name, V1APIPrefix) { return nil, os.ErrNotExist } if location, ok := s.redirections[name]; ok { return s.fs.Open(location) } return s.fs.Open(name) } var errBadSigner = errors.New("signer not initialized") var errNoCertDBConfigured = errors.New("cert db not configured (missing -db-config)") var endpoints = map[string]func() (http.Handler, error){ "sign": func() (http.Handler, error) { if s == nil { return nil, errBadSigner } h, err := signhandler.NewHandlerFromSigner(s) if err != nil { return nil, err } if conf.CABundleFile != "" && conf.IntBundleFile != "" { sh := h.Handler.(*signhandler.Handler) if err := sh.SetBundler(conf.CABundleFile, conf.IntBundleFile); err != nil { return nil, err } } return h, nil }, "authsign": func() (http.Handler, error) { if s == nil { return nil, errBadSigner } h, err := signhandler.NewAuthHandlerFromSigner(s) if err != nil { return nil, err } if conf.CABundleFile != "" && conf.IntBundleFile != "" { sh := h.(*api.HTTPHandler).Handler.(*signhandler.AuthHandler) if err := sh.SetBundler(conf.CABundleFile, conf.IntBundleFile); err != nil { return nil, err } } return h, nil }, "info": func() (http.Handler, error) { if s == nil { return nil, errBadSigner } return info.NewHandler(s) }, "crl": func() (http.Handler, error) { if s == nil { return nil, errBadSigner } if db == nil { return nil, errNoCertDBConfigured } return crl.NewHandler(certsql.NewAccessor(db), conf.CAFile, conf.CAKeyFile) }, "gencrl": func() (http.Handler, error) { if s == nil { return nil, errBadSigner } return gencrl.NewHandler(), nil }, "newcert": func() (http.Handler, error) { if s == nil { return nil, errBadSigner } h := generator.NewCertGeneratorHandlerFromSigner(generator.CSRValidate, s) if conf.CABundleFile != "" && conf.IntBundleFile != "" { cg := h.(api.HTTPHandler).Handler.(*generator.CertGeneratorHandler) if err := cg.SetBundler(conf.CABundleFile, conf.IntBundleFile); err != nil { return nil, err } } return h, nil }, "bundle": func() (http.Handler, error) { return bundle.NewHandler(conf.CABundleFile, conf.IntBundleFile) }, "newkey": func() (http.Handler, error) { return generator.NewHandler(generator.CSRValidate) }, "init_ca": func() (http.Handler, error) { return initca.NewHandler(), nil }, "scan": func() (http.Handler, error) { return scan.NewHandler(conf.CABundleFile) }, "scaninfo": func() (http.Handler, error) { return scan.NewInfoHandler(), nil }, "certinfo": func() (http.Handler, error) { if db != nil { return certinfo.NewAccessorHandler(certsql.NewAccessor(db)), nil } return certinfo.NewHandler(), nil }, "ocspsign": func() (http.Handler, error) { if ocspSigner == nil { return nil, errBadSigner } return apiocsp.NewHandler(ocspSigner), nil }, "revoke": func() (http.Handler, error) { if db == nil { return nil, errNoCertDBConfigured } return revoke.NewHandler(certsql.NewAccessor(db)), nil }, "/": func() (http.Handler, error) { subFS, _ := fs.Sub(staticContent, "static") return http.FileServer(http.FS(&staticFS{fs: subFS, redirections: staticRedirections})), nil }, "health": func() (http.Handler, error) { return health.NewHealthCheck(), nil }, "certadd": func() (http.Handler, error) { return certadd.NewHandler(certsql.NewAccessor(db), nil), nil }, } // registerHandlers instantiates various handlers and associate them to corresponding endpoints. func registerHandlers() { disabled := make(map[string]bool) if conf.Disable != "" { for _, endpoint := range strings.Split(conf.Disable, ",") { disabled[endpoint] = true } } for path, getHandler := range endpoints { log.Debugf("getHandler for %s", path) if _, ok := disabled[path]; ok { log.Infof("endpoint '%s' is explicitly disabled", path) } else if handler, err := getHandler(); err != nil { log.Warningf("endpoint '%s' is disabled: %v", path, err) } else { if path, handler, err = wrapHandler(path, handler, err); err != nil { log.Warningf("endpoint '%s' is disabled by wrapper: %v", path, err) } else { log.Infof("endpoint '%s' is enabled", path) http.Handle(path, handler) } } } log.Info("Handler set up complete.") } // serverMain is the command line entry point to the API server. It sets up a // new HTTP server to handle sign, bundle, and validate requests. func serverMain(args []string, c cli.Config) error { conf = c // serve doesn't support arguments. if len(args) > 0 { return errors.New("argument is provided but not defined; please refer to the usage by flag -h") } bundler.IntermediateStash = conf.IntDir var err error if err = ubiquity.LoadPlatforms(conf.Metadata); err != nil { return err } if c.DBConfigFile != "" { db, err = dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return err } } log.Info("Initializing signer") if s, err = sign.SignerFromConfigAndDB(c, db); err != nil { log.Warningf("couldn't initialize signer: %v", err) } if ocspSigner, err = ocspsign.SignerFromConfig(c); err != nil { log.Warningf("couldn't initialize ocsp signer: %v", err) } registerHandlers() addr := net.JoinHostPort(conf.Address, strconv.Itoa(conf.Port)) tlscfg := tls.Config{} if conf.MinTLSVersion != "" { tlscfg.MinVersion = helpers.StringTLSVersion(conf.MinTLSVersion) } if conf.TLSCertFile == "" || conf.TLSKeyFile == "" { log.Info("Now listening on ", addr) return http.ListenAndServe(addr, nil) } if conf.MutualTLSCAFile != "" { clientPool, err := helpers.LoadPEMCertPool(conf.MutualTLSCAFile) if err != nil { return fmt.Errorf("failed to load mutual TLS CA file: %s", err) } tlscfg.ClientAuth = tls.RequireAndVerifyClientCert tlscfg.ClientCAs = clientPool server := http.Server{ Addr: addr, TLSConfig: &tlscfg, } if conf.MutualTLSCNRegex != "" { log.Debugf(`Requiring CN matches regex "%s" for client connections`, conf.MutualTLSCNRegex) re, err := regexp.Compile(conf.MutualTLSCNRegex) if err != nil { return fmt.Errorf("malformed CN regex: %s", err) } server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r != nil && r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { if re.MatchString(r.TLS.PeerCertificates[0].Subject.CommonName) { http.DefaultServeMux.ServeHTTP(w, r) return } log.Warningf(`Rejected client cert CN "%s" does not match regex %s`, r.TLS.PeerCertificates[0].Subject.CommonName, conf.MutualTLSCNRegex) } http.Error(w, "Invalid CN", http.StatusForbidden) }) } log.Info("Now listening with mutual TLS on https://", addr) return server.ListenAndServeTLS(conf.TLSCertFile, conf.TLSKeyFile) } log.Info("Now listening on https://", addr) server := http.Server{ Addr: addr, TLSConfig: &tlscfg, } return server.ListenAndServeTLS(conf.TLSCertFile, conf.TLSKeyFile) } // Command assembles the definition of Command 'serve' var Command = &cli.Command{UsageText: serverUsageText, Flags: serverFlags, Main: serverMain} var wrapHandler = defaultWrapHandler // The default wrapper simply returns the normal handler and prefixes the path appropriately func defaultWrapHandler(path string, handler http.Handler, err error) (string, http.Handler, error) { return v1APIPath(path), handler, err } // SetWrapHandler sets the wrap handler which is called for all endpoints // A custom wrap handler may be provided in order to add arbitrary server-side pre or post processing // of server-side HTTP handling of requests. func SetWrapHandler(wh func(path string, handler http.Handler, err error) (string, http.Handler, error)) { wrapHandler = wh } // SetEndpoint can be used to add additional routes/endpoints to the HTTP server, or to override an existing route/endpoint func SetEndpoint(path string, getHandler func() (http.Handler, error)) { endpoints[path] = getHandler } ================================================ FILE: cli/serve/serve_test.go ================================================ package serve import ( "net/http" "net/http/httptest" "testing" "github.com/cloudflare/cfssl/cli" ) func TestServe(t *testing.T) { registerHandlers() ts := httptest.NewServer(http.DefaultServeMux) defer ts.Close() expected := make(map[string]int) for endpoint := range endpoints { expected[v1APIPath(endpoint)] = http.StatusOK } // Disabled endpoints should return '404 Not Found' expected[v1APIPath("sign")] = http.StatusNotFound expected[v1APIPath("authsign")] = http.StatusNotFound expected[v1APIPath("newcert")] = http.StatusNotFound expected[v1APIPath("info")] = http.StatusNotFound expected[v1APIPath("ocspsign")] = http.StatusNotFound expected[v1APIPath("crl")] = http.StatusNotFound expected[v1APIPath("gencrl")] = http.StatusNotFound expected[v1APIPath("revoke")] = http.StatusNotFound // Enabled endpoints should return '405 Method Not Allowed' expected[v1APIPath("init_ca")] = http.StatusMethodNotAllowed expected[v1APIPath("newkey")] = http.StatusMethodNotAllowed expected[v1APIPath("bundle")] = http.StatusMethodNotAllowed expected[v1APIPath("certinfo")] = http.StatusMethodNotAllowed expected[v1APIPath("certadd")] = http.StatusMethodNotAllowed // POST-only endpoints should return '400 Bad Request' expected[v1APIPath("scan")] = http.StatusBadRequest // Redirected HTML endpoints should return '200 OK' expected["/scan"] = http.StatusOK expected["/bundle"] = http.StatusOK // Non-existent endpoints should return '404 Not Found' expected["/bad_endpoint"] = http.StatusNotFound for endpoint, status := range expected { resp, err := http.Get(ts.URL + endpoint) if err != nil { t.Error(err) } if resp.StatusCode != status { t.Fatalf("%s: '%s' (expected '%s')", endpoint, resp.Status, http.StatusText(status)) } } var c cli.Config var test = []string{"test"} if err := serverMain(test, c); err == nil { t.Fatalf("There should be an error for argument") } } ================================================ FILE: cli/serve/static/assets/cfssl.js ================================================ (function() { 'use strict'; /* globals m */ // > framework extensions m.deferred.resolve = function (value) { var deferred = m.deferred(); deferred.resolve(value); return deferred.promise; }; m.deferred.reject = function (value) { var deferred = m.deferred(); deferred.reject(value); return deferred.promise; }; // < framework extensions function getProp(obj, prop) { var i = -1; while (obj && (++i < prop.length)) { var key = prop[i]; obj = obj[key]; } return obj; } var page = (function() { var title = ''; return { title: function(store) { if (arguments.length > 0) { title = store; if (!title.length) { document.title = 'CFSSL'; } else { document.title = title + ' | CFSSL'; } } return title; } }; }()); // > i18n support var phrases = { 'bundle.title': 'Bundle', 'bundle.action': 'Bundle', 'bundle.flavor': 'Flavor', 'bundle.ubiquitous': 'Ubiquitous', 'bundle.optimal': 'Optimal', 'bundle.force': 'Force', 'bundle.bundle.title': 'Bundled', 'common.server': 'Server', 'common.cipher': 'Cipher', 'common.packages': 'Packages', 'common.host': 'Host', 'scan.title': 'Scan', 'scan.action': 'Scan', 'scan.broad.title': 'Broad', 'scan.broad.description': 'Large scale scans of TLS hosts.', 'scan.broad.ICAs.title': 'Intermediate Certificate Authorities', 'scan.broad.ICAs.body': 'Scans a CIDR IP range for unknown Intermediate Certificate Authorities.', 'scan.connectivity.title': 'Connectivity', 'scan.connectivity.description': 'Scans for basic connectivity with the host through DNS and TCP/TLS dials.', 'scan.connectivity.DNSLookup.title': 'DNS Lookup', 'scan.connectivity.DNSLookup.body': 'Determines if the host can be resolved through DNS.', 'scan.connectivity.TCPDial.title': 'TCP Dial', 'scan.connectivity.TCPDial.body': 'Determines if host accepts TCP connection.', 'scan.connectivity.TLSDial.title': 'TLS Dial', 'scan.connectivity.TLSDial.body': 'Tests if host can perform TLS handshake.', 'scan.pki.title': 'Public-Key Infrastructure', 'scan.pki.description': 'Scans for the Public-Key Infrastructure.', 'scan.pki.ChainExpiration.title': 'Chain Expiration', 'scan.pki.ChainExpiration.body': 'Ensures host\'s chain hasn\'t expired and won\'t expire in the next 30 days.', 'scan.pki.ChainValidation.title': 'Chain Validation', 'scan.pki.ChainValidation.body': 'Looks at all certificate in the host\'s chain, and ensures they are all valid.', 'scan.tlshandshake.title': 'TLS Handshake', 'scan.tlshandshake.description': 'Scans for host\'s SSL and TLS versions and cipher suite negotiation.', 'scan.tlshandshake.CipherSuite.title': 'Cipher Suite Matrix', 'scan.tlshandshake.CipherSuite.body': 'Determines host\'s cipher suite accepted and preferred order.', 'scan.tlssession.title': 'TLS Session', 'scan.tlssession.description': 'Scans host\'s implementation of TLS session resumption using session ticket and session IDs.', 'scan.tlssession.SessionResume.title': 'Session Resumption', 'scan.tlssession.SessionResume.body': 'Confirms the host is able to resume sessions across all addresses.', 'scan.tlssession.SessionResume.supports_session_resume': 'Supports Session Resumption' }; // stub to replace with intl-messageformat function Tformat(key) { return phrases[key] || ''; } // < i18n support function appWrapper(module) { function navLink(selector, route, name) { var isActive = m.route().indexOf(route) === 0; selector += '[href="' + route + '"]'; return m('li' + (isActive ? '.active' : ''), [ m(selector, { config: m.route }, name) ]); } return [ m('nav.navbar.navbar-default.navbar-static-top', [ m('.container', [ m('.navbar-header', [ m('a.navbar-brand[href="/"]', { config: m.route }, 'CFSSL') ]), m('.collapse.navbar-collapse', [ m('ul.nav.navbar-nav', [ navLink('a', '/scan', Tformat('scan.title')), navLink('a', '/bundle', Tformat('bundle.title')) ]), m('ul.nav.navbar-nav.navbar-right', [ navLink('a', '/packages', Tformat('common.packages')), m('li', m('a[href="https://github.com/cloudflare/cfssl"]', 'GitHub')), ]) ]) ]) ]), m('.container', module), m('footer.container', { style: { paddingTop: '40px', paddingBottom: '40px', marginTop: '100px', borderTop: '1px solid #e5e5e5', textAlign: 'center' } }, [ m('p', [ 'Code licensed under ', m('a[href="https://github.com/cloudflare/cfssl/blob/master/LICENSE"]', 'BSD-2-Clause'), '.' ]) ]) ]; } var panel = { view: function(ctrl, args, children) { function gradeToGlyphicon(grade) { switch(grade) { case 'Good': return 'glyphicon-ok-sign'; case 'Warning': return 'glyphicon-exclamation-sign'; case 'Bad': return 'glyphicon-remove-sign'; default: return 'glyphicon-question-sign'; } } function gradeToPanel(grade) { switch(grade) { case 'Good': return 'panel-success'; case 'Warning': return 'panel-warning'; case 'Bad': return 'panel-danger'; default: return 'panel-default'; } } if (!args.grade) { return m('.panel.panel-default', [ m('.panel-heading', args.title), m('.panel-body', args.body), children ]); } return m('.panel.' + gradeToPanel(args.grade), [ m('.panel-heading', [ m('span.glyphicon.' + gradeToGlyphicon(args.grade)), ' ', args.title ]), m('.panel-body', args.body), children ]); } }; var table = { view: function(ctrl, args) { return m('table.table.table-bordered.table-striped', [ m('thead', [ m('tr', args.columns.map(function(column) { return m('th', column); })) ]), m('tbody', args.rows.map(function(row) { return m('tr', row.map(function(cell) { return m('td', cell); })); })) ]); } }; var listGroup = { view: function(ctrl, children) { return m('ul.list-group', children.map(function(item) { return m('li.list-group-item', item); })); } }; var home = { controller: function() { page.title(''); return; }, view: function() { return appWrapper([ m('h1.page-header', 'CFSSL: Cloudflare\'s PKI toolkit'), m('p', [ 'See ', m('a[href="https://blog.cloudflare.com/introducing-cfssl"]', 'blog post'), ' or ', m('a[href="https://github.com/cloudflare/cfssl"]', 'contribute on GitHub'), '.' ]) ]); } }; var packages = { controller: function() { page.title(Tformat('common.packages')); return; }, view: function() { return appWrapper([ m('h1.page-header', Tformat('common.packages')), m('ul', [ m('li', m('a[href="https://github.com/cloudflare/cfssl/releases"]', 'Download binaries (GitHub)')), m('li', m('a[href="https://hub.docker.com/r/cloudflare/cfssl"]', 'Docker images')), m('li', m('a[href="https://pkg.cloudflare.com/"]', 'Install from apt or yum')) ]) ]); } }; var scan = { vm: { init: function(domain) { scan.vm.domain = m.prop(domain ? domain : ''); scan.vm.loading = m.prop(false); scan.vm.Scan = m.prop(false); scan.vm.scan = function(evt) { var domain = scan.vm.domain(); scan.vm.Scan(false); scan.vm.loading(true); if (evt) { evt.preventDefault(); } setTimeout(function() { scan.Model.scan(domain).then(function(result) { scan.vm.loading(false); scan.vm.Scan(result); }); }, 0); }; // TODO: remove! if (domain) { scan.vm.loading(true); setTimeout(function() { scan.Model.scan(domain).then(function(result) { scan.vm.loading(false); scan.vm.Scan(result); }); }, 0); } } }, Model: function(data) { this.domain = m.prop(data.domain); this.IntermediateCAs = m.prop(data.IntermediateCAs); this.DNSLookup = m.prop(data.DNSLookup); this.TCPDial = m.prop(data.TCPDial); this.TLSDial = m.prop(data.TLSDial); this.ChainExpiration = m.prop(data.ChainExpiration); this.ChainValidation = m.prop(data.ChainValidation); this.CipherSuite = m.prop(data.CipherSuite); this.SessionResume = m.prop(data.SessionResume); }, controller: function() { scan.vm.init(m.route.param('domain')); page.title(Tformat('scan.title')); return; }, view: function() { function broad() { var ICAs = results.IntermediateCAs(); var out = []; out.push(m('h3.page-header', Tformat('scan.broad.title')), m('p', Tformat('scan.broad.description'))); if (getProp(ICAs, ['grade'])) { out.push(m.component(panel, { grade: ICAs.grade, title: Tformat('scan.broad.ICAs.title'), body: Tformat('scan.broad.ICAs.body') })); } if (out.length === 2) { return; } return out; } function connectivity() { var DNSLookup = results.DNSLookup(); var TCPDial = results.TCPDial(); var TLSDial = results.TLSDial(); var out = []; out.push(m('h3.page-header', Tformat('scan.connectivity.title')), m('p', Tformat('scan.connectivity.description'))); if (getProp(DNSLookup, ['grade'])) { out.push(m.component(panel, { grade: DNSLookup.grade, title: Tformat('scan.connectivity.DNSLookup.title'), body: Tformat('scan.connectivity.DNSLookup.body') }, m.component(listGroup, DNSLookup.output.sort()))); } if (getProp(TCPDial, ['grade'])) { out.push(m.component(panel, { grade: TCPDial.grade, title: Tformat('scan.connectivity.TCPDial.title'), body: Tformat('scan.connectivity.TCPDial.body') })); } if (getProp(TLSDial, ['grade'])) { out.push(m.component(panel, { grade: TLSDial.grade, title: Tformat('scan.connectivity.TLSDial.title'), body: Tformat('scan.connectivity.TLSDial.body') })); } if (out.length === 2) { return; } return out; } function tlssession() { var SessionResume = results.SessionResume(); var out = []; var body; out.push(m('h3.page-header', Tformat('scan.tlssession.title')), m('p', Tformat('scan.tlssession.description'))); if (getProp(SessionResume, ['grade'])) { body = null; if (SessionResume.output) { body = m.component(table, { columns: [Tformat('common.server'), Tformat('scan.tlssession.SessionResume.supports_session_resume')], rows: Object.keys(SessionResume.output).sort().map(function(ip) { var supported = SessionResume.output[ip]; return [ ip, m('span.glyphicon.glyphicon-' + (supported ? 'ok-sign' : 'remove-sign')) ]; }) }); } out.push(m.component(panel, { grade: SessionResume.grade, title: Tformat('scan.tlssession.SessionResume.title'), body: Tformat('scan.tlssession.SessionResume.body') }, body)); } if (out.length === 2) { return; } return out; } function pki() { var ChainExpiration = results.ChainExpiration(); var ChainValidation = results.ChainValidation(); var out = []; var body; out.push(m('h3.page-header', Tformat('scan.pki.title')), m('p', Tformat('scan.pki.description'))); if (getProp(ChainExpiration, ['grade'])) { body = null; if (ChainExpiration.output) { body = m.component(listGroup, [ m('time[datetime="' + ChainExpiration.output + '"]', (new Date(ChainExpiration.output)).toLocaleString('bestfit', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', timeZone: 'UTC', timeZoneName: 'short' })) ]); } out.push(m.component(panel, { grade: ChainExpiration.grade, title: Tformat('scan.pki.ChainExpiration.title'), body: Tformat('scan.pki.ChainExpiration.body') }, body)); } if (getProp(ChainValidation, ['grade'])) { body = null; if (ChainValidation.output && Array.isArray(ChainValidation.output)) { body = m.component(listGroup, ChainValidation.output); } out.push(m.component(panel, { grade: ChainValidation.grade, title: Tformat('scan.pki.ChainValidation.title'), body: Tformat('scan.pki.ChainValidation.body') }, body)); } if (out.length === 2) { return; } return out; } function tlshandshake() { var CipherSuite = results.CipherSuite(); var out = []; var body; out.push(m('h3.page-header', Tformat('scan.tlshandshake.title')), m('p', Tformat('scan.tlshandshake.description'))); if (getProp(CipherSuite, ['grade'])) { body = null; if (CipherSuite.output) { body = m.component(table, { columns: [Tformat('common.cipher'), 'TLS 1.2', 'TLS 1.1', 'TLS 1.0', 'SSL 3.0'], rows: CipherSuite.output.map(function(results) { var cipher = Object.keys(results)[0]; var result = results[cipher]; if (typeof result[0] === 'string') { return [ cipher, result.indexOf('TLS 1.2') !== -1 ? m('span.glyphicon.glyphicon-ok-sign') : '-', result.indexOf('TLS 1.1') !== -1 ? m('span.glyphicon.glyphicon-ok-sign') : '-', result.indexOf('TLS 1.0') !== -1 ? m('span.glyphicon.glyphicon-ok-sign') : '-', result.indexOf('SSL 3.0') !== -1 ? m('span.glyphicon.glyphicon-remove-sign') : '-' ]; } return [ cipher, getProp(result, [0, 'TLS 1.2', 0]) || '-', getProp(result, [1, 'TLS 1.1', 0]) || '-', getProp(result, [2, 'TLS 1.0', 0]) || '-', getProp(result, [3, 'SSL 3.0', 0]) || '-' ]; }) }); } out.push(m.component(panel, { grade: CipherSuite.grade, title: Tformat('scan.tlshandshake.CipherSuite.title'), body: Tformat('scan.tlshandshake.CipherSuite.body') }, body)); } if (out.length === 2) { return; } return out; } var results = scan.vm.Scan(); return appWrapper([ m('h1.page-header', Tformat('scan.title')), m('form.form-horizontal', [ m('.form-group', [ m('label.col-sm-2.control-label[for=scanhost]', Tformat('common.host')), m('.col-sm-8', [ m('input.form-control#scanhost[placeholder="cfssl.org"]', { value: scan.vm.domain(), onchange: m.withAttr('value', scan.vm.domain) }) ]) ]), m('.form-group', [ m('.col-sm-offset-2 col-sm-10', [ m('button.btn.btn-default[type="submit"]', { onclick: scan.vm.scan, disabled: scan.vm.loading() }, Tformat('scan.action')) ]) ]) ]), !scan.vm.loading() ? '' : [ m('p', 'Scanning ' + scan.vm.domain()) ], !results ? '' : [ m('h2.page-header', 'Results for ' + scan.vm.Scan().domain()), broad(), connectivity(), tlssession(), pki(), tlshandshake() ] ]); } }; scan.Model.scan = function(domain) { if (domain) { return m.request({ method: 'GET', url: '/api/v1/cfssl/scan', data: { host: domain }, unwrapSuccess: function(response) { if (!response.success) { throw new Error(response.messages.join(', ')); } return response.result; }, unwrapError: function(response) { return response.errors; } }) .then(function(response) { var results = new scan.Model({ domain: domain, IntermediateCAs: getProp(response, ['Broad', 'IntermediateCAs']), DNSLookup: getProp(response, ['Connectivity', 'DNSLookup']), TCPDial: getProp(response, ['Connectivity', 'TCPDial']), TLSDial: getProp(response, ['Connectivity', 'TLSDial']), ChainExpiration: getProp(response, ['PKI', 'ChainExpiration']), ChainValidation: getProp(response, ['PKI', 'ChainValidation']), CipherSuite: getProp(response, ['TLSHandshake', 'CipherSuite']), SessionResume: getProp(response, ['TLSSession', 'SessionResume']) }); return results; }); } return m.deferred.reject(); }; var bundle = { vm: { init: function(domain) { bundle.vm.domain = m.prop(domain ? domain : ''); bundle.vm.flavor = m.prop('ubiquitous'); bundle.vm.loading = m.prop(false); bundle.vm.Bundle = m.prop(false); bundle.vm.bundle = function(evt) { var domain = bundle.vm.domain(); var flavor = bundle.vm.flavor(); bundle.vm.Bundle(false); bundle.vm.loading(true); if (evt) { evt.preventDefault(); } setTimeout(function() { bundle.Model.bundle(domain, flavor).then(function(result) { bundle.vm.loading(false); bundle.vm.Bundle(result); }); }, 0); }; // TODO: remove! if (domain) { bundle.vm.loading(true); setTimeout(function() { bundle.Model.bundle(domain, bundle.vm.flavor()).then(function(result) { bundle.vm.loading(false); bundle.vm.Bundle(result); }); }, 0); } } }, Model: function(data) { this.domain = m.prop(data.domain); this.bundle = m.prop(data.bundle); this.expires = m.prop(data.expires); this.messages = m.prop(data.messages); this.oscp = m.prop(data.oscp); }, controller: function() { bundle.vm.init(m.route.param('domain')); page.title(Tformat('bundle.title')); return; }, view: function() { var results = bundle.vm.Bundle(); return appWrapper([ m('h1.page-header', Tformat('bundle.title')), m('form.form-horizontal', [ m('.form-group', [ m('label.col-sm-2.control-label[for=bundlehost]', Tformat('common.host')), m('.col-sm-8', [ m('input.form-control#bundlehost[placeholder="cfssl.org"]', { value: bundle.vm.domain(), onchange: m.withAttr('value', bundle.vm.domain) }) ]) ]), m('.form-group', [ m('label.col-sm-2.control-label[for=bundleflavor]', Tformat('bundle.flavor')), m('.col-sm-8', [ m('select#bundleflavor', { value: bundle.vm.flavor(), onchange: m.withAttr('value', bundle.vm.flavor) }, [ m('option[value="ubiquitous"]', Tformat('bundle.ubiquitous')), m('option[value="optimal"]', Tformat('bundle.optimal')), m('option[value="force"]', Tformat('bundle.force')) ]) ]) ]), m('.form-group', [ m('.col-sm-offset-2 col-sm-10', [ m('button.btn.btn-default[type="submit"]', { onclick: bundle.vm.bundle, disabled: bundle.vm.loading() }, Tformat('bundle.action')) ]) ]) ]), !bundle.vm.loading() ? '' : [ m('p', 'Bundling ' + bundle.vm.domain()) ], !results ? '' : [ m('h2.page-header', 'Results for ' + bundle.vm.Bundle().domain()), m.component(panel, { title: Tformat('bundle.bundle.title'), body: m('pre', results.bundle()) }, !results.messages().length ? '' : m.component(listGroup, results.messages())), ] ]); } }; bundle.Model.bundle = function(domain, flavor) { if (domain && flavor) { return m.request({ method: 'POST', url: '/api/v1/cfssl/bundle', data: { domain: domain, flavor: flavor }, unwrapSuccess: function(response) { if (!response.success) { throw new Error(response.messages.join(', ')); } return response.result; }, unwrapError: function(response) { return response.errors; } }) .then(function(response) { var results = new bundle.Model({ domain: domain, bundle: response.bundle, expires: response.expires, messages: response.status && response.status.messages || [], oscp: response.oscp_support }); return results; }); } return m.deferred.reject(); }; m.route.mode = 'pathname'; m.route(document.body, '/', { '/': home, '/bundle': bundle, '/bundle/:domain': bundle, '/scan': scan, '/scan/:domain': scan, '/packages': packages }); window.scan = scan; window.bundle = bundle; }()); ================================================ FILE: cli/serve/static/index.html ================================================ CFSSL
================================================ FILE: cli/sign/sign.go ================================================ // Package sign implements the sign command. package sign import ( "encoding/json" "errors" "os" "github.com/cloudflare/cfssl/certdb/dbconf" certsql "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/universal" "github.com/jmoiron/sqlx" ) // Usage text of 'cfssl sign' var signerUsageText = `cfssl sign -- signs a client cert with a host name by a given CA and CA key Usage of sign: cfssl sign -ca cert -ca-key key [mutual-tls-cert cert] [mutual-tls-key key] [-config config] [-profile profile] [-hostname hostname] [-db-config db-config] CSR [SUBJECT] cfssl sign -remote remote_host [mutual-tls-cert cert] [mutual-tls-key key] [-config config] [-profile profile] [-label label] [-hostname hostname] CSR [SUBJECT] Arguments: CSR: PEM file for certificate request, use '-' for reading PEM from stdin. Note: CSR can also be supplied via flag values; flag value will take precedence over the argument. SUBJECT is an optional file containing subject information to use for the certificate instead of the subject information in the CSR. Flags: ` // Flags of 'cfssl sign' var signerFlags = []string{"hostname", "csr", "ca", "ca-key", "config", "profile", "label", "remote", "mutual-tls-cert", "mutual-tls-key", "db-config"} // SignerFromConfigAndDB takes the Config and creates the appropriate // signer.Signer object with a specified db func SignerFromConfigAndDB(c cli.Config, db *sqlx.DB) (signer.Signer, error) { // If there is a config, use its signing policy. Otherwise create a default policy. var policy *config.Signing if c.CFG != nil { policy = c.CFG.Signing } else { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig(), } } // Make sure the policy reflects the new remote if c.Remote != "" { err := policy.OverrideRemotes(c.Remote) if err != nil { log.Infof("Invalid remote %v, reverting to configuration default", c.Remote) return nil, err } } if c.MutualTLSCertFile != "" && c.MutualTLSKeyFile != "" { err := policy.SetClientCertKeyPairFromFile(c.MutualTLSCertFile, c.MutualTLSKeyFile) if err != nil { log.Infof("Invalid mutual-tls-cert: %s or mutual-tls-key: %s, defaulting to no client auth", c.MutualTLSCertFile, c.MutualTLSKeyFile) return nil, err } log.Infof("Using client auth with mutual-tls-cert: %s and mutual-tls-key: %s", c.MutualTLSCertFile, c.MutualTLSKeyFile) } if c.TLSRemoteCAs != "" { err := policy.SetRemoteCAsFromFile(c.TLSRemoteCAs) if err != nil { log.Infof("Invalid tls-remote-ca: %s, defaulting to system trust store", c.TLSRemoteCAs) return nil, err } log.Infof("Using trusted CA from tls-remote-ca: %s", c.TLSRemoteCAs) } s, err := universal.NewSigner(cli.RootFromConfig(&c), policy) if err != nil { return nil, err } if db != nil { dbAccessor := certsql.NewAccessor(db) s.SetDBAccessor(dbAccessor) } return s, nil } // SignerFromConfig takes the Config and creates the appropriate // signer.Signer object func SignerFromConfig(c cli.Config) (s signer.Signer, err error) { var db *sqlx.DB if c.DBConfigFile != "" { db, err = dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return nil, err } } return SignerFromConfigAndDB(c, db) } // signerMain is the main CLI of signer functionality. // [TODO: zi] Decide whether to drop the argument list and only use flags to specify all the inputs. func signerMain(args []string, c cli.Config) (err error) { if c.CSRFile == "" { c.CSRFile, args, err = cli.PopFirstArgument(args) if err != nil { return } } var subjectData *signer.Subject if len(args) > 0 { var subjectFile string subjectFile, args, err = cli.PopFirstArgument(args) if err != nil { return } if len(args) > 0 { return errors.New("too many arguments are provided, please check with usage") } var subjectJSON []byte subjectJSON, err = os.ReadFile(subjectFile) if err != nil { return } subjectData = new(signer.Subject) err = json.Unmarshal(subjectJSON, subjectData) if err != nil { return } } csr, err := cli.ReadStdin(c.CSRFile) if err != nil { return } // Remote can be forced on the command line or in the config if c.Remote == "" && c.CFG == nil { if c.CAFile == "" { log.Error("need CA certificate (provide one with -ca)") return } if c.CAKeyFile == "" { log.Error("need CA key (provide one with -ca-key)") return } } s, err := SignerFromConfig(c) if err != nil { return } req := signer.SignRequest{ Hosts: signer.SplitHosts(c.Hostname), Request: string(csr), Subject: subjectData, Profile: c.Profile, Label: c.Label, } cert, err := s.Sign(req) if err != nil { return } cli.PrintCert(nil, csr, cert) return } // Command assembles the definition of Command 'sign' var Command = &cli.Command{UsageText: signerUsageText, Flags: signerFlags, Main: signerMain} ================================================ FILE: cli/sign/sign_test.go ================================================ package sign import ( "testing" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/cloudflare/cfssl/cli" ) func TestSignFromConfig(t *testing.T) { _, err := SignerFromConfig(cli.Config{CAFile: "../../testdata/server.crt", CAKeyFile: "../../testdata/server.key", Hostname: "www.cloudflare.com", Remote: "127.0.0.1:8888"}) if err != nil { t.Fatal(err) } } func TestSignerMain(t *testing.T) { err := signerMain([]string{"../../testdata/server.csr"}, cli.Config{CAFile: "../../testdata/server.crt", CAKeyFile: "../../testdata/server.key", Hostname: "www.cloudflare.com"}) if err != nil { t.Fatal(err) } } func TestBadSigner(t *testing.T) { err := signerMain([]string{"../../testdata/server.csr"}, cli.Config{CAFile: "", CAKeyFile: ""}) if err != nil { t.Fatal(err) } err = signerMain([]string{"../../testdata/server.csr"}, cli.Config{CAFile: "../../testdata/server.crt", CAKeyFile: ""}) if err != nil { t.Fatal(err) } } func TestSignerWithDB(t *testing.T) { db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") err := signerMain([]string{"../../testdata/server.csr"}, cli.Config{ CAFile: "../../testdata/server.crt", CAKeyFile: "../../testdata/server.key", Hostname: "www.cloudflare.com", DBConfigFile: "../testdata/db-config.json"}) if err != nil { t.Fatal(err) } dbAccessor := sql.NewAccessor(db) crs, err := dbAccessor.GetUnexpiredCertificates() if err != nil { t.Fatal("Failed to get unexpired certificates") } if len(crs) != 1 { t.Fatal("Expected 1 unexpired certificate in the database after signing 1") } } ================================================ FILE: cli/testdata/bad_csr.json ================================================ this is a bad csr json ================================================ FILE: cli/testdata/bad_oid_csr.json ================================================ { "hosts": [ "cloudflare.com", "www.cloudflare.com" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "San Francisco", "O": "CloudFlare", "OU": "Systems Engineering", "ST": "California", "OID": { "abc": "abc" } } ] } ================================================ FILE: cli/testdata/ca-key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA0IxFva4iCa87V2fxJas5h7oBXM8lHnUci9K8Lw5GSw6J+qUe xyNVWCjCgTaAVUBztCQhMORKzFPg1W1R0e7TGjggM3FiETqhgKneaOlu1XJMGDJ7 eGx/8VohaCA45dsjhMb0+hE/HgOqhQr/LHIaFIwvEJM8rD2HLvN5haRaeEJ9ZOGy ZQ80J3YBkB/q3B5DlTJ0tcErzfG92VJf7gLqvYg6/xkCFNUab8/wsnqdNXAg9Q/A JaPp6nzIWs1nuKRtOwn7KDC3L2d8P7owNdtnaOLgio1SSXTzZ/IqOxFKIyIAWtSC FQ3l8Za5LsSX/E1++pJ5RIN3LodKvSTqLR4i7wIDAQABAoIBAQDGefmVwDgcx2zO jtnuY7ro9Zl+XpaRGhwE5pa6ofc8T6X5qVRVacc7k+8pUlloyWJUu13rThnxxJJi DRylk4nNlkTvMKWIiChUb1aAukkFUzYggUsJHRnW9VR96My91YVERKW5qNhNFGgh HookHqO7kn7oY3iG5DfX81hgXD7N26GEaldiqq/r2EkmD86XSmLLygSbYp5i0hbk q/kSWZUsUxlOaXRB6yQkbC7iIcqkIPbSCStFPrs74W3BcYE8mqq7qUCty9rJ5Cob oFCqXwho7kZuFsS5kgRsSvC9xTpECNReEMYfnNm7fRWnSKk7ht2yYC+tObW+/pGE GMx5LtThAoGBANz3ZuMdQoeIJ9ZEGjdzA/LKfbMLbf+ubH9km96B1Eax1uFo2oP1 jLQdIXL9Ga56A66wC4H2xOp3VEmVbtWr80kENy8tBTca5xZugRPl/Rq+3VtRr3gn HRpJrY3/qp1GKZHz0XelI3HRbL5Eovf+sGR8hpe/HZND342Ujt6IpK5NAoGBAPGc 1Ce8BxxEpXlWMoB4apsKMI9nvPoG7MhrFJZ6E7fFlqG8c/hnOjCjnoDNS92VkPJy Mqqk+KPk+pW2BaAPwy/pDZ6n7i2XPUhQz5fkkGLtNTdaExU4RA6D6YEwdXemAgiu 7swMchcq7CFYwp0y69qSzpXlTde7WtH7R8fDjkwrAoGAYGzaCiv/l1NURw1q/12C kJXKqrJHKzc7g5As8LlpH/yFT9JI4SLrZsH7kclfRqNaLgYGz40XO1Ydgwrh1f52 aRuc1UppJzXnOAO68ir/+4bk4+/OiblP2uPiB8BU/NLcWyOx+esnf4irUpBzKZOL +B3bQicVSelpicgVXIj2jFUCgYEA1rjcpu9olku/j4T2XswlWeIFY/z6qm1rE3Zu loipa2HTS6uSmQkMYtuWaruIl8VrSrwIoTT5r5Y4yMI6X5SCj9qbewudFbFaCiGf TEsZsoFDEQ0g9nPJr+i1pVVun8XN+u+UU40f+8zui3g5hMETcG2V4QsnUfk0bnbV xQfbN38CgYA00m12NLlHyLZ1ks9gE2n3J9dq4/LcxBmpnRfCjzRDrTWS83IoHuho JoidlTLHqL60mGx1u8K+sR5Syr8eFUv9JITJGm0dM3mCVJqWNCfv20JNK2b/uNdk F3C/VbFSnT947+MUP9zo6szdZXikz8q00lV75E6+JsS/Av775cvj9w== -----END RSA PRIVATE KEY----- ================================================ FILE: cli/testdata/ca.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIC8jCCAdoCAQAwbTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNsb3VkRmxhcmUx HDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcTDVNhbiBGcmFu Y2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWEwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDQjEW9riIJrztXZ/ElqzmHugFczyUedRyL0rwvDkZLDon6pR7H I1VYKMKBNoBVQHO0JCEw5ErMU+DVbVHR7tMaOCAzcWIROqGAqd5o6W7VckwYMnt4 bH/xWiFoIDjl2yOExvT6ET8eA6qFCv8schoUjC8QkzysPYcu83mFpFp4Qn1k4bJl DzQndgGQH+rcHkOVMnS1wSvN8b3ZUl/uAuq9iDr/GQIU1Rpvz/Cyep01cCD1D8Al o+nqfMhazWe4pG07CfsoMLcvZ3w/ujA122do4uCKjVJJdPNn8io7EUojIgBa1IIV DeXxlrkuxJf8TX76knlEg3cuh0q9JOotHiLvAgMBAAGgQDA+BgkqhkiG9w0BCQ4x MTAvMC0GA1UdEQQmMCSCDmNsb3VkZmxhcmUuY29tghJ3d3cuY2xvdWRmbGFyZS5j b20wDQYJKoZIhvcNAQELBQADggEBAKt69g0/87votV8MoLcyV1HJSmBCrIkLrzc9 Lo0k37MFy8lCHsnh5AEcrhDVmQIs0QCIERPb7G+tp2NY4JSp/w73rHGhlkkgxSlP Q2zoSgNIBZVYABWkXqBR7fNRS0fbgIeFuyO47Pd9MK/ddvua7kVq538HZqZAcBye tsm/FbxI3LNi9i6ZyK3kfoPS/Npx7YdlebIVihWTngAndL3YRcte7ghTzCR4wX/d JCnatZIGWMkEBc4+CNZP4tDzMmLFXWEemdq/lQdU8a4hl2dpVSWxh7Uf5nBxKJaS aRm3VP9J+EO1Vec0PTWhP6t9UOpmV2VmgtXPMCD5x/FMkyVcvBM= -----END CERTIFICATE REQUEST----- ================================================ FILE: cli/testdata/ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIDwjCCAqqgAwIBAgIILxyvkXgyJskwDQYJKoZIhvcNAQELBQAwbTELMAkGA1UE BhMCVVMxEzARBgNVBAoTCkNsb3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5n aW5lZXJpbmcxFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlm b3JuaWEwHhcNMTUxMjA5MTgwMTAwWhcNMjAxMjA3MTgwMTAwWjBtMQswCQYDVQQG EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv cm5pYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANCMRb2uIgmvO1dn 8SWrOYe6AVzPJR51HIvSvC8ORksOifqlHscjVVgowoE2gFVAc7QkITDkSsxT4NVt UdHu0xo4IDNxYhE6oYCp3mjpbtVyTBgye3hsf/FaIWggOOXbI4TG9PoRPx4DqoUK /yxyGhSMLxCTPKw9hy7zeYWkWnhCfWThsmUPNCd2AZAf6tweQ5UydLXBK83xvdlS X+4C6r2IOv8ZAhTVGm/P8LJ6nTVwIPUPwCWj6ep8yFrNZ7ikbTsJ+ygwty9nfD+6 MDXbZ2ji4IqNUkl082fyKjsRSiMiAFrUghUN5fGWuS7El/xNfvqSeUSDdy6HSr0k 6i0eIu8CAwEAAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQIwHQYDVR0OBBYEFHuEaWWwGnbCXcbr7FLufYHVmScBMB8GA1UdIwQYMBaAFHuE aWWwGnbCXcbr7FLufYHVmScBMA0GCSqGSIb3DQEBCwUAA4IBAQAWw04UzJ8PRIkZ IvhPpoHx/LFmnkCqaOwo2S2D+2AjVJ3UQLdzcPrj4RH6l6hB46ndARIpYSCwqR6V QcOLMDP/NHsbKp+D842Wu/0w9/Zy1dg6HGLwhBuNehca7mt+6Ue52+nE83kMy8i5 GCxs/t6WUpykWv325fBIms4iftN4hB4qQXrpC8AE2APrHrARV7h0GN54rFneaFyu RHXAwdjArZD7OavcEcAhsalZetlt7Peq9bDuepyISEP/snLRuOGGRG/cn7/vbJh3 WTBqCMDNXB3UB6Kz9jTdf3KCncOqffYrx4fJWATFi2cabK6D6340gX/+jpD7ds84 vqD20/w3 -----END CERTIFICATE----- ================================================ FILE: cli/testdata/csr.json ================================================ { "hosts": [ "cloudflare.com", "www.cloudflare.com" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "San Francisco", "O": "CloudFlare", "OU": "Systems Engineering", "ST": "California", "OID": { "1.2.3.4.5": "abc" } } ], "delegation_enabled": true } ================================================ FILE: cli/testdata/db-config.json ================================================ {"driver":"sqlite3","data_source":"../../certdb/testdb/certstore_development.db"} ================================================ FILE: cli/testdata/test.txt ================================================ This is a test file ================================================ FILE: cli/version/version.go ================================================ // Package version implements the version command. package version import ( "fmt" "runtime" "github.com/cloudflare/cfssl/cli" ) var ( version = "dev" ) // Usage text for 'cfssl version' var versionUsageText = `cfssl version -- print out the version of CF SSL Usage of version: cfssl version ` // FormatVersion returns the formatted version string. func FormatVersion() string { return fmt.Sprintf("Version: %s\nRuntime: %s\n", version, runtime.Version()) } // The main functionality of 'cfssl version' is to print out the version info. func versionMain(args []string, c cli.Config) (err error) { fmt.Printf("%s", FormatVersion()) return nil } // Command assembles the definition of Command 'version' var Command = &cli.Command{UsageText: versionUsageText, Flags: nil, Main: versionMain} ================================================ FILE: cli/version/version_test.go ================================================ package version import ( "testing" "github.com/cloudflare/cfssl/cli" ) func TestVersionMain(t *testing.T) { args := []string{"cfssl", "version"} err := versionMain(args, cli.Config{}) if err != nil { t.Fatal("version main failed") } } ================================================ FILE: cmd/cfssl/cfssl.go ================================================ /* cfssl is the command line tool to issue/sign/bundle client certificate. It's also a tool to start a HTTP server to handle web requests for signing, bundling and verification. Usage: cfssl command [-flags] arguments The commands are bundle create a certificate bundle sign signs a certificate signing request (CSR) serve starts a HTTP server handling sign and bundle requests version prints the current cfssl version genkey generates a key and an associated CSR gencert generates a key and a signed certificate gencsr generates a certificate request selfsign generates a self-signed certificate Use "cfssl [command] -help" to find out more about a command. */ package main import ( "flag" "os" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/cli/bundle" "github.com/cloudflare/cfssl/cli/certinfo" "github.com/cloudflare/cfssl/cli/crl" "github.com/cloudflare/cfssl/cli/gencert" "github.com/cloudflare/cfssl/cli/gencrl" "github.com/cloudflare/cfssl/cli/gencsr" "github.com/cloudflare/cfssl/cli/genkey" "github.com/cloudflare/cfssl/cli/info" "github.com/cloudflare/cfssl/cli/ocspdump" "github.com/cloudflare/cfssl/cli/ocsprefresh" "github.com/cloudflare/cfssl/cli/ocspserve" "github.com/cloudflare/cfssl/cli/ocspsign" "github.com/cloudflare/cfssl/cli/printdefault" "github.com/cloudflare/cfssl/cli/revoke" "github.com/cloudflare/cfssl/cli/scan" "github.com/cloudflare/cfssl/cli/selfsign" "github.com/cloudflare/cfssl/cli/serve" "github.com/cloudflare/cfssl/cli/sign" "github.com/cloudflare/cfssl/cli/version" _ "github.com/go-sql-driver/mysql" // import to support MySQL _ "github.com/lib/pq" // import to support Postgres _ "github.com/mattn/go-sqlite3" // import to support SQLite3 ) // main defines the cfssl usage and registers all defined commands and flags. func main() { // Add command names to cfssl usage flag.Usage = nil // this is set to nil for testability // Register commands. cmds := map[string]*cli.Command{ "bundle": bundle.Command, "certinfo": certinfo.Command, "crl": crl.Command, "sign": sign.Command, "serve": serve.Command, "version": version.Command, "genkey": genkey.Command, "gencert": gencert.Command, "gencsr": gencsr.Command, "gencrl": gencrl.Command, "ocspdump": ocspdump.Command, "ocsprefresh": ocsprefresh.Command, "ocspsign": ocspsign.Command, "ocspserve": ocspserve.Command, "selfsign": selfsign.Command, "scan": scan.Command, "info": info.Command, "print-defaults": printdefaults.Command, "revoke": revoke.Command, } // If the CLI returns an error, exit with an appropriate status // code. err := cli.Start(cmds) if err != nil { os.Exit(1) } } ================================================ FILE: cmd/cfssl/cfssl_test.go ================================================ package main ================================================ FILE: cmd/cfssl-bundle/cfssl-bundle.go ================================================ package main import ( "flag" "fmt" "os" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/cli/bundle" "github.com/cloudflare/cfssl/config" ) // main defines the bundle usage and registers all defined commands and flags. func main() { var bundleFlagSet = flag.NewFlagSet("bundle", flag.ExitOnError) var c cli.Config var usageText = `cfssl-bundle -- create a certificate bundle that contains the client cert Usage of bundle: - Bundle local certificate files bundle -cert file [-ca-bundle file] [-int-bundle file] [-int-dir dir] [-metadata file] [-key keyfile] [-flavor optimal|ubiquitous|force] [-password password] - Bundle certificate from remote server. bundle -domain domain_name [-ip ip_address] [-ca-bundle file] [-int-bundle file] [-int-dir dir] [-metadata file] Flags: ` registerFlags(&c, bundleFlagSet) bundleFlagSet.Usage = func() { fmt.Fprintf(os.Stderr, "\t%s", usageText) for _, name := range bundle.Command.Flags { if f := bundleFlagSet.Lookup(name); f != nil { printDefaultValue(f) } } } args := os.Args[1:] bundleFlagSet.Parse(args) args = bundleFlagSet.Args() var err error c.CFG, err = config.LoadFile(c.ConfigFile) if c.ConfigFile != "" && err != nil { fmt.Fprintf(os.Stderr, "Failed to load config file: %v", err) } if err := bundle.Command.Main(args, c); err != nil { fmt.Fprintln(os.Stderr, err) } } // printDefaultValue is a helper function to print out a user friendly // usage message of a flag. It's useful since we want to write customized // usage message on selected subsets of the global flag set. It is // borrowed from standard library source code. Since flag value type is // not exported, default string flag values are printed without // quotes. The only exception is the empty string, which is printed as "". func printDefaultValue(f *flag.Flag) { format := " -%s=%s: %s\n" if f.DefValue == "" { format = " -%s=%q: %s\n" } fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage) } // registerFlags defines all cfssl command flags and associates their values with variables. func registerFlags(c *cli.Config, f *flag.FlagSet) { f.StringVar(&c.CertFile, "cert", "", "Client certificate that contains the public key") f.StringVar(&c.KeyFile, "key", "", "private key for the certificate") f.StringVar(&c.CABundleFile, "ca-bundle", "", "path to root certificate store") f.StringVar(&c.IntBundleFile, "int-bundle", "", "path to intermediate certificate store") f.StringVar(&c.Flavor, "flavor", "ubiquitous", "Bundle Flavor: ubiquitous, optimal and force.") f.StringVar(&c.IntDir, "int-dir", "", "specify intermediates directory") f.StringVar(&c.Metadata, "metadata", "", "Metadata file for root certificate presence. The content of the file is a json dictionary (k,v): each key k is SHA-1 digest of a root certificate while value v is a list of key store filenames.") f.StringVar(&c.Domain, "domain", "", "remote server domain name") f.StringVar(&c.IP, "ip", "", "remote server ip") f.StringVar(&c.Password, "password", "0", "Password for accessing PKCS #12 data passed to bundler") } ================================================ FILE: cmd/cfssl-certinfo/cfssl-certinfo.go ================================================ package main import ( "flag" "fmt" "os" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/cli/certinfo" "github.com/cloudflare/cfssl/config" _ "github.com/go-sql-driver/mysql" // import to support MySQL _ "github.com/lib/pq" // import to support Postgres _ "github.com/mattn/go-sqlite3" // import to support SQLite3 ) // main defines the newkey usage and registers all defined commands and flags. func main() { var certinfoFlagSet = flag.NewFlagSet("certinfo", flag.ExitOnError) var c cli.Config registerFlags(&c, certinfoFlagSet) var usageText = `cfssl-certinfo -- output certinfo about the given cert Usage of certinfo: - Data from local certificate files certinfo -cert file - Data from certificate from remote server. certinfo -domain domain_name - Data from CA storage certinfo -serial serial_number -aki authority_key_id (requires -db-config) Flags: ` certinfoFlagSet.Usage = func() { fmt.Fprintf(os.Stderr, "\t%s", usageText) for _, name := range certinfo.Command.Flags { if f := certinfoFlagSet.Lookup(name); f != nil { printDefaultValue(f) } } } args := os.Args[1:] certinfoFlagSet.Parse(args) args = certinfoFlagSet.Args() var err error c.CFG, err = config.LoadFile(c.ConfigFile) if c.ConfigFile != "" && err != nil { fmt.Fprintf(os.Stderr, "Failed to load config file: %v", err) } if err := certinfo.Command.Main(args, c); err != nil { fmt.Fprintln(os.Stderr, err) } } // printDefaultValue is a helper function to print out a user friendly // usage message of a flag. It's useful since we want to write customized // usage message on selected subsets of the global flag set. It is // borrowed from standard library source code. Since flag value type is // not exported, default string flag values are printed without // quotes. The only exception is the empty string, which is printed as "". func printDefaultValue(f *flag.Flag) { format := " -%s=%s: %s\n" if f.DefValue == "" { format = " -%s=%q: %s\n" } fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage) } // registerFlags defines all cfssl command flags and associates their values with variables. func registerFlags(c *cli.Config, f *flag.FlagSet) { f.StringVar(&c.CertFile, "cert", "", "Client certificate that contains the public key") f.StringVar(&c.Domain, "domain", "", "remote server domain name") f.StringVar(&c.Serial, "serial", "", "certificate serial number") f.StringVar(&c.AKI, "aki", "", "certificate issuer (authority) key identifier") f.StringVar(&c.DBConfigFile, "db-config", "", "certificate db configuration file") } ================================================ FILE: cmd/cfssl-newkey/cfssl-newkey.go ================================================ package main import ( "flag" "fmt" "os" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/cli/genkey" "github.com/cloudflare/cfssl/config" ) // main defines the newkey usage and registers all defined commands and flags. func main() { var newkeyFlagSet = flag.NewFlagSet("newkey", flag.ExitOnError) var c cli.Config var usageText = `cfssl-newkey -- generate a new key and CSR Usage of genkey: newkey CSRJSON Arguments: CSRJSON: JSON file containing the request, use '-' for reading JSON from stdin Flags: ` registerFlags(&c, newkeyFlagSet) newkeyFlagSet.Usage = func() { fmt.Fprintf(os.Stderr, "\t%s", usageText) for _, name := range genkey.Command.Flags { if f := newkeyFlagSet.Lookup(name); f != nil { printDefaultValue(f) } } } args := os.Args[1:] newkeyFlagSet.Parse(args) args = newkeyFlagSet.Args() var err error c.CFG, err = config.LoadFile(c.ConfigFile) if c.ConfigFile != "" && err != nil { fmt.Fprintf(os.Stderr, "Failed to load config file: %v", err) } if err := genkey.Command.Main(args, c); err != nil { fmt.Fprintln(os.Stderr, err) } } // printDefaultValue is a helper function to print out a user friendly // usage message of a flag. It's useful since we want to write customized // usage message on selected subsets of the global flag set. It is // borrowed from standard library source code. Since flag value type is // not exported, default string flag values are printed without // quotes. The only exception is the empty string, which is printed as "". func printDefaultValue(f *flag.Flag) { format := " -%s=%s: %s\n" if f.DefValue == "" { format = " -%s=%q: %s\n" } fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage) } // registerFlags defines all cfssl command flags and associates their values with variables. func registerFlags(c *cli.Config, f *flag.FlagSet) { f.BoolVar(&c.IsCA, "initca", false, "initialise new CA") f.StringVar(&c.ConfigFile, "config", "", "path to configuration file") } ================================================ FILE: cmd/cfssl-scan/cfssl-scan.go ================================================ package main import ( "flag" "fmt" "os" "time" "github.com/cloudflare/cfssl/cli" "github.com/cloudflare/cfssl/cli/scan" "github.com/cloudflare/cfssl/config" ) // main defines the scan usage and registers all defined commands and flags. func main() { var scanFlagSet = flag.NewFlagSet("scan", flag.ExitOnError) var c cli.Config var usageText = `cfssl scan -- scan a host for issues Usage of scan: cfssl scan [-family regexp] [-scanner regexp] [-timeout duration] [-ip IPAddr] [-num-workers num] [-max-hosts num] [-csv hosts.csv] HOST+ cfssl scan -list Arguments: HOST: Host(s) to scan (including port) Flags: ` registerFlags(&c, scanFlagSet) scanFlagSet.Usage = func() { fmt.Fprintf(os.Stderr, "\t%s", usageText) for _, name := range scan.Command.Flags { if f := scanFlagSet.Lookup(name); f != nil { printDefaultValue(f) } } } args := os.Args[1:] scanFlagSet.Parse(args) args = scanFlagSet.Args() var err error c.CFG, err = config.LoadFile(c.ConfigFile) if c.ConfigFile != "" && err != nil { fmt.Fprintf(os.Stderr, "Failed to load config file: %v", err) } if err := scan.Command.Main(args, c); err != nil { fmt.Fprintln(os.Stderr, err) } } // printDefaultValue is a helper function to print out a user friendly // usage message of a flag. It's useful since we want to write customized // usage message on selected subsets of the global flag set. It is // borrowed from standard library source code. Since flag value type is // not exported, default string flag values are printed without // quotes. The only exception is the empty string, which is printed as "". func printDefaultValue(f *flag.Flag) { format := " -%s=%s: %s\n" if f.DefValue == "" { format = " -%s=%q: %s\n" } fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage) } // registerFlags defines all cfssl command flags and associates their values with variables. func registerFlags(c *cli.Config, f *flag.FlagSet) { f.BoolVar(&c.List, "list", false, "list possible scanners") f.StringVar(&c.Family, "family", "", "scanner family regular expression") f.StringVar(&c.Scanner, "scanner", "", "scanner regular expression") f.DurationVar(&c.Timeout, "timeout", 5*time.Minute, "duration (ns, us, ms, s, m, h) to scan each host before timing out") f.StringVar(&c.CSVFile, "csv", "", "file containing CSV of hosts") f.IntVar(&c.NumWorkers, "num-workers", 10, "number of workers to use for scan") f.IntVar(&c.MaxHosts, "max-hosts", 100, "maximum number of hosts to scan") f.StringVar(&c.IP, "ip", "", "remote server ip") f.StringVar(&c.CABundleFile, "ca-bundle", "", "path to root certificate store") } ================================================ FILE: cmd/cfssljson/cfssljson.go ================================================ // cfssljson splits out JSON with cert, csr, and key fields to separate // files. package main import ( "encoding/base64" "encoding/json" "flag" "fmt" "io" "os" "github.com/cloudflare/cfssl/cli/version" ) func readFile(filespec string) ([]byte, error) { if filespec == "-" { return io.ReadAll(os.Stdin) } return os.ReadFile(filespec) } func writeFile(filespec, contents string, perms os.FileMode) { err := os.WriteFile(filespec, []byte(contents), perms) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } } // ResponseMessage represents the format of a CFSSL output for an error or message type ResponseMessage struct { Code int `json:"int"` Message string `json:"message"` } // Response represents the format of a CFSSL output type Response struct { Success bool `json:"success"` Result map[string]interface{} `json:"result"` Errors []ResponseMessage `json:"errors"` Messages []ResponseMessage `json:"messages"` } type outputFile struct { Filename string Contents string IsBinary bool Perms os.FileMode } func main() { bare := flag.Bool("bare", false, "the response from CFSSL is not wrapped in the API standard response") inFile := flag.String("f", "-", "JSON input") output := flag.Bool("stdout", false, "output the response instead of saving to a file") printVersion := flag.Bool("version", false, "print version and exit") flag.Parse() if *printVersion { fmt.Printf("%s", version.FormatVersion()) return } var baseName string if flag.NArg() == 0 { baseName = "cert" } else { baseName = flag.Arg(0) } var input = map[string]interface{}{} var outs []outputFile var cert string var key string var csr string fileData, err := readFile(*inFile) if err != nil { fmt.Fprintf(os.Stderr, "Failed to read input: %v\n", err) os.Exit(1) } if *bare { err = json.Unmarshal(fileData, &input) if err != nil { fmt.Fprintf(os.Stderr, "Failed to parse input: %v\n", err) os.Exit(1) } } else { var response Response err = json.Unmarshal(fileData, &response) if err != nil { fmt.Fprintf(os.Stderr, "Failed to parse input: %v\n", err) os.Exit(1) } if !response.Success { fmt.Fprintf(os.Stderr, "Request failed:\n") for _, msg := range response.Errors { fmt.Fprintf(os.Stderr, "\t%s\n", msg.Message) } os.Exit(1) } input = response.Result } if contents, ok := input["cert"]; ok { cert = contents.(string) } else if contents, ok = input["certificate"]; ok { cert = contents.(string) } if cert != "" { outs = append(outs, outputFile{ Filename: baseName + ".pem", Contents: cert, Perms: 0664, }) } if contents, ok := input["key"]; ok { key = contents.(string) } else if contents, ok = input["private_key"]; ok { key = contents.(string) } if key != "" { outs = append(outs, outputFile{ Filename: baseName + "-key.pem", Contents: key, Perms: 0600, }) } if contents, ok := input["encrypted_key"]; ok { encKey := contents.(string) outs = append(outs, outputFile{ Filename: baseName + "-key.enc", Contents: encKey, IsBinary: true, Perms: 0600, }) } if contents, ok := input["csr"]; ok { csr = contents.(string) } else if contents, ok = input["certificate_request"]; ok { csr = contents.(string) } if csr != "" { outs = append(outs, outputFile{ Filename: baseName + ".csr", Contents: csr, Perms: 0644, }) } if result, ok := input["result"].(map[string]interface{}); ok { if bundle, ok := result["bundle"].(map[string]interface{}); ok { // if we've gotten this deep then we're trying to parse out // a bundle, now we fail if we can't find the keys we need. certificateBundle, ok := bundle["bundle"].(string) if !ok { fmt.Fprintf(os.Stderr, "inner bundle parsing failed!\n") os.Exit(1) } rootCertificate, ok := bundle["root"].(string) if !ok { fmt.Fprintf(os.Stderr, "root parsing failed!\n") os.Exit(1) } outs = append(outs, outputFile{ Filename: baseName + "-bundle.pem", Contents: certificateBundle + "\n" + rootCertificate, Perms: 0644, }) outs = append(outs, outputFile{ Filename: baseName + "-root.pem", Contents: rootCertificate, Perms: 0644, }) } } if contents, ok := input["ocspResponse"]; ok { // ocspResponse is base64 encoded resp, err := base64.StdEncoding.DecodeString(contents.(string)) if err != nil { fmt.Fprintf(os.Stderr, "Failed to parse ocspResponse: %v\n", err) os.Exit(1) } outs = append(outs, outputFile{ Filename: baseName + "-response.der", Contents: string(resp), IsBinary: true, Perms: 0644, }) } for _, e := range outs { if *output { if e.IsBinary { e.Contents = base64.StdEncoding.EncodeToString([]byte(e.Contents)) } fmt.Fprintf(os.Stdout, "%s\n", e.Contents) } else { writeFile(e.Filename, e.Contents, e.Perms) } } } ================================================ FILE: cmd/cfssljson/cfssljson_test.go ================================================ package main import ( "testing" ) func TestReadFile(t *testing.T) { _, err := readFile("-") if err != nil { t.Fatal(err) } file, err := readFile("./testdata/test.txt") if err != nil { t.Fatal(err) } if string(file) != "This is a test file" { t.Fatal("File not read correctly") } } ================================================ FILE: cmd/cfssljson/testdata/test.txt ================================================ This is a test file ================================================ FILE: cmd/mkbundle/cert-bundle.crt ================================================ -----BEGIN CERTIFICATE----- MIIETTCCAzWgAwIBAgILBAAAAAABRE7wNjEwDQYJKoZIhvcNAQELBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw MDBaFw0yNDAyMjAxMDAwMDBaMEwxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMSIwIAYDVQQDExlBbHBoYVNTTCBDQSAtIFNIQTI1NiAtIEcy MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2gHs5OxzYPt+j2q3xhfj kmQy1KwA2aIPue3ua4qGypJn2XTXXUcCPI9A1p5tFM3D2ik5pw8FCmiiZhoexLKL dljlq10dj0CzOYvvHoN9ItDjqQAu7FPPYhmFRChMwCfLew7sEGQAEKQFzKByvkFs MVtI5LHsuSPrVU3QfWJKpbSlpFmFxSWRpv6mCZ8GEG2PgQxkQF5zAJrgLmWYVBAA cJjI4e00X9icxw3A1iNZRfz+VXqG7pRgIvGu0eZVRvaZxRsIdF+ssGSEj4k4HKGn kCFPAm694GFn1PhChw8K98kEbSqpL+9Cpd/do1PbmB6B+Zpye1reTz5/olig4het ZwIDAQABo4IBIzCCAR8wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQAwHQYDVR0OBBYEFPXN1TwIUPlqTzq3l9pWg+Zp0mj3MEUGA1UdIAQ+MDwwOgYE VR0gADAyMDAGCCsGAQUFBwIBFiRodHRwczovL3d3dy5hbHBoYXNzbC5jb20vcmVw b3NpdG9yeS8wMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nbG9iYWxzaWdu Lm5ldC9yb290LmNybDA9BggrBgEFBQcBAQQxMC8wLQYIKwYBBQUHMAGGIWh0dHA6 Ly9vY3NwLmdsb2JhbHNpZ24uY29tL3Jvb3RyMTAfBgNVHSMEGDAWgBRge2YaRQ2X yolQL30EzTSo//z9SzANBgkqhkiG9w0BAQsFAAOCAQEAYEBoFkfnFo3bXKFWKsv0 XJuwHqJL9csCP/gLofKnQtS3TOvjZoDzJUN4LhsXVgdSGMvRqOzm+3M+pGKMgLTS xRJzo9P6Aji+Yz2EuJnB8br3n8NA0VgYU8Fi3a8YQn80TsVD1XGwMADH45CuP1eG l87qDBKOInDjZqdUfy4oy9RU0LMeYmcI+Sfhy+NmuCQbiWqJRGXy2UzSWByMTsCV odTvZy84IOgu/5ZR8LrYPZJwR2UcnnNytGAMXOLRc3bgr07i5TelRS+KIz6HxzDm MTh89N1SyvNTBCVXVmaU6Avu5gMUTu79bZRknl7OedSyps9AsUSoPocZXun4IRZZ Uw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6 2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt 4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/ vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT 8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/ s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9 MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6 Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5 B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR pu/xO28QOG8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6 2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt 4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/ vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT 8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/ s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9 MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6 Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5 B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR pu/xO28QOG8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGCDCCA/CgAwIBAgIQKy5u6tl1NmwUim7bo3yMBzANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMjEy MDAwMDAwWhcNMjkwMjExMjM1OTU5WjCBkDELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxNjA0BgNVBAMTLUNPTU9ETyBSU0EgRG9tYWluIFZh bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAI7CAhnhoFmk6zg1jSz9AdDTScBkxwtiBUUWOqigwAwCfx3M28Sh bXcDow+G+eMGnD4LgYqbSRutA776S9uMIO3Vzl5ljj4Nr0zCsLdFXlIvNN5IJGS0 Qa4Al/e+Z96e0HqnU4A7fK31llVvl0cKfIWLIpeNs4TgllfQcBhglo/uLQeTnaG6 ytHNe+nEKpooIZFNb5JPJaXyejXdJtxGpdCsWTWM/06RQ1A/WZMebFEh7lgUq/51 UHg+TLAchhP6a5i84DuUHoVS3AOTJBhuyydRReZw3iVDpA3hSqXttn7IzW3uLh0n c13cRTCAquOyQQuvvUSH2rnlG51/ruWFgqUCAwEAAaOCAWUwggFhMB8GA1UdIwQY MBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBSQr2o6lFoL2JDqElZz 30O0Oija5zAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgG BmeBDAECATBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNv bS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB AQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9E T1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21v ZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAE4rdk+SHGI2ibp3wScF9BzWRJ2p mj6q1WZmAT7qSeaiNbz69t2Vjpk1mA42GHWx3d1Qcnyu3HeIzg/3kCDKo2cuH1Z/ e+FE6kKVxF0NAVBGFfKBiVlsit2M8RKhjTpCipj4SzR7JzsItG8kO3KdY3RYPBps P0/HEZrIqPW1N+8QRcZs2eBelSaz662jue5/DJpmNXMyYE7l3YphLG5SEXdoltMY dVEVABt0iN3hxzgEQyjpFv3ZBdRdRydg1vs4O2xyopT4Qhrf7W8GjEXCBgCq5Ojc 2bXhc3js9iPc0d1sjhqPpepUfJa3w/5Vjo1JXvxku88+vZbrac2/4EjxYoIQ5QxG V/Iz2tDIY+3GH5QFlkoakdH368+PUq4NCNk+qKBR6cGHdNXJ93SrLlP7u3r7l+L4 HyaPs9Kg4DdbKDsx5Q5XLVq4rXmsXiBmGqW5prU5wfWYQ//u+aen/e7KJD2AFsQX j4rBYKEMrltDR5FL1ZoXX/nUh8HCjLfn4g8wGTeGrODcQgPmlKidrv0PJFGUzpII 0fxQ8ANAe4hZ7Q7drNJ3gjTcBpUC2JD5Leo31Rpg0Gcg19hCC0Wvgmje3WYkN5Ap lBlGGSW4gNfL1IYoakRwJiNiqZ+Gb7+6kHDSVneFeO/qJakXzlByjAA6quPbYzSf +AZxAeKCINT+b72x -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEaTCCA1GgAwIBAgILBAAAAAABRE7wQkcwDQYJKoZIhvcNAQELBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw MDBaFw0yNDAyMjAxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMTwwOgYDVQQDEzNHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBW YWxpZGF0aW9uIENBIC0gU0hBMjU2IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDHDmw/I5N/zHClnSDDDlM/fsBOwphJykfVI+8DNIV0yKMCLkZc C33JiJ1Pi/D4nGyMVTXbv/Kz6vvjVudKRtkTIso21ZvBqOOWQ5PyDLzm+ebomchj SHh/VzZpGhkdWtHUfcKc1H/hgBKueuqI6lfYygoKOhJJomIZeg0k9zfrtHOSewUj mxK1zusp36QUArkBpdSmnENkiN74fv7j9R7l/tyjqORmMdlMJekYuYlZCa7pnRxt Nw9KHjUgKOKv1CGLAcRFrW4rY6uSa2EKTSDtc7p8zv4WtdufgPDWi2zZCHlKT3hl 2pK8vjX5s8T5J4BO/5ZS5gIg4Qdz6V0rvbLxAgMBAAGjggElMIIBITAOBgNVHQ8B Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUlt5h8b0cFilT HMDMfTuDAEDmGnwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0 dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMDMGA1UdHwQsMCow KKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwPQYIKwYB BQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNv bS9yb290cjEwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZI hvcNAQELBQADggEBAEYq7l69rgFgNzERhnF0tkZJyBAW/i9iIxerH4f4gu3K3w4s 32R1juUYcqeMOovJrKV3UPfvnqTgoI8UV6MqX+x+bRDmuo2wCId2Dkyy2VG7EQLy XN0cvfNVlg/UBsD84iOKJHDTu/B5GqdhcIOKrwbFINihY9Bsrk8y1658GEV1BSl3 30JAZGSGvip2CTFvHST0mdCF/vIhCPnG9vHQWe3WVjwIKANnuvD58ZAWR65n5ryA SOlCdjSXVWkkDoPWoC209fN5ikkodBpBocLTJIg1MGCUF7ThBCIxPTsvFwayuJ2G K1pp74P1S8SqtCr4fKGxhZSM9AyHDPSsQPhZSZg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE6DCCA9CgAwIBAgIQdIYhlpUQySkmKUvMi/gpLDANBgkqhkiG9w0BAQUFADBv MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF eHRlcm5hbCBDQSBSb290MB4XDTEwMDYyMjAwMDAwMFoXDTIwMDUzMDEwNDgzOFow bzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0dsb2JlIEhvc3RpbmcsIEluYy4xLDAq BgNVBAsTI0dsb2JlU1NMIERWIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRQwEgYD VQQDEwtHbG9iZVNTTCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AKBHBM6oNav/GGOIjsGJ+y0DD80tKJeh2tIQW4NPLEaYCxKY9LM5t5ejhl2AIgIz yJ26m6y62Xx+3vejuSpp6Bd7/FYvmYfaKqJ3pKxWjKz1Ht84T5fSOgNq9knDKnuz JlRMFeEA8wKQOKSZV9v9ipEB8XGWdd8h+RUZXRgrDnMQLQ5bVijL/WHstvBb+TwU 9kILys0X39l2X9ZUKUDReRX79UWpLW9UNddeOeamtQRbkNlvXC9YhQAA8GgRCBlA UEmM2ofpgpnThq7UwTaiVg4Iw7c2epHwJAx5jzCl4kyZnX523ZiB6ElGrAHIJfd+ BMWe+g3i97hA8UX85sLJb8cCAwEAAaOCAX4wggF6MB8GA1UdIwQYMBaAFK29mHo0 tCb3+sQmVO8DveAky1QaMB0GA1UdDgQWBBTDq6AC8Jv1Zn8oFZIildu4TtOTCDAO BgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAYBgNVHSAEETAPMA0G CysGAQQBsjEBAgIbMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRy dXN0LmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDCBswYIKwYBBQUHAQEE gaYwgaMwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9BZGRU cnVzdEV4dGVybmFsQ0FSb290LnA3YzA5BggrBgEFBQcwAoYtaHR0cDovL2NydC51 c2VydHJ1c3QuY29tL0FkZFRydXN0VVROU0dDQ0EuY3J0MCUGCCsGAQUFBzABhhlo dHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQBmnBNt 0n4s3WvWGpE3hYZRI01kY/Vegz6I/m9nhw7KhW27OzzVrfy6TbqLu8jB7SzUbcsQ wjPj52aXjyvlj4GP7bzdh7Xb3CNfrg9AkSmeB9SxztCCG24d0aQIUBKujw95Z6cA Z966kJtIvF+Qwxv+zLY6HtsVFbXeq3jjQaqTiuG/QxXsyWsh/u2h3+kLLcugcx/W PviYm0Z45K0lIEGGKNDefRSWBEesyLlr3QDwRxGfi36xou1H6RcjNOa9i2dBZGAK Gs11aYk5ZpXhModzkdCbg424x+C8Io8sJBPIwpSX+jEmIoIrte8FpqB+mgC0a+Oe WUO8dpjzPDDbHDAu -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEwzCCA6ugAwIBAgIQf3HB06ImsNKxE/PmgWdkPjANBgkqhkiG9w0BAQUFADBv MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF eHRlcm5hbCBDQSBSb290MB4XDTEwMTIwNzAwMDAwMFoXDTIwMDUzMDEwNDgzOFow UTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUludGVybmV0MjERMA8GA1UECxMISW5D b21tb24xGzAZBgNVBAMTEkluQ29tbW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAJd8x8j+s+kgaqOkT46ONFYGs3psqhCbSGErNpBp 4zQKR6e7e96qavvrgpWPyh1/r3WmqEzaIGdhGg2GwcrBh6+sTuTeYhsvnbGYr8YB +xdw26wUWexvPzN/ppgL5OI4r/V/hW0OdASd9ieGx5uP53EqCPQDAkBjJH1AV49U 4FR+thNIYfHezg69tvpNmLLZDY15puCqzQyRmqXfq3O7yhR4XEcpocrFup/H2mD3 /+d/8tnaoS0PSRan0wCSz4pH2U341ZVm03T5gGMAT0yEFh+z9SQfoU7e6JXWsgsJ iyxrx1wvjGPJmctSsWJ7cwFif2Ns2Gig7mqojR8p89AYrK0CAwEAAaOCAXcwggFz MB8GA1UdIwQYMBaAFK29mHo0tCb3+sQmVO8DveAky1QaMB0GA1UdDgQWBBRIT1r6 L0qaXuBQ82t7VaXe9b40XTAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB /wIBADARBgNVHSAECjAIMAYGBFUdIAAwRAYDVR0fBD0wOzA5oDegNYYzaHR0cDov L2NybC51c2VydHJ1c3QuY29tL0FkZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMIGz BggrBgEFBQcBAQSBpjCBozA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1 c3QuY29tL0FkZFRydXN0RXh0ZXJuYWxDQVJvb3QucDdjMDkGCCsGAQUFBzAChi1o dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vQWRkVHJ1c3RVVE5TR0NDQS5jcnQwJQYI KwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEF BQADggEBAJNmIYB0RYVLwqvOMrAp/t3f1iRbvwNqb1A+DhuzDYijW+7EpBI7Vu8G f89/IZVWO0Ex/uGqk9KV85UNPEerylwmrT7x+Yw0bhG+9GfjAkn5pnx7ZCXdF0by UOPjCiE6SSTNxoRlaGdosEUtR5nNnKuGKRFy3NacNkN089SXnlag/l9AWNLV1358 xY4asgRckmYOha0uBs7Io9jrFCeR3s8XMIFTtmYSrTfk9e+WXCAONumsYn0ZgYr1 kGGmSavOPN/mymTugmU5RZUWukEGAJi6DFZh5MbGhgHPZqkiKQLWPc/EKo2Z3vsJ FJ4O0dXG14HdrSSrrAcF4h1ow3BmX9M= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEtTCCA52gAwIBAgIQTfJOlaFbpVNJmpqJbwK+dTANBgkqhkiG9w0BAQUFADBv MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF eHRlcm5hbCBDQSBSb290MB4XDTExMTIwMjAwMDAwMFoXDTIwMDUzMDEwNDgzOFow PTELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB1NTTC5jb20xHDAaBgNVBAMTE1NTTC5j b20gRnJlZSBTU0wgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCB rEbV+7bWzGL2O3NQL8N466UsbFBt5S/Oh7JIErx/MECLLgJ0w4TRhs+xe9yjhr+5 h8Pygx3HpIUGWRUklH13M4x3M1p2cdSVesPwGprV6BbS7EEfK24AT7PKt/9mrBca gZ2g9bdZpTFKUJRDaVYnFzYbwSYl+2juETt1CGvJpyv8Fmm8RBzvlEyFgMkmri2o yqkRR+umtH09e2mr0eZQSzUY293QSxnL+Z5/R3yyyWavDlzPUzcFIoClsxKcpgWM FH4GxXLZv708O9HfqGiNyCpJedB41YnJm03vtJkQ0vtftuCU/RXqD+vlwe0iD4VB jbL0FpTGyhyAOoZBAQk3AgMBAAGjggF9MIIBeTAfBgNVHSMEGDAWgBStvZh6NLQm 9/rEJlTvA73gJMtUGjAdBgNVHQ4EFgQUTllmv/MlCAGyisKxM+E+AVF7gikwDgYD VR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwFwYDVR0gBBAwDjAMBgor BgEEAYKpMAEBMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0 LmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDCBswYIKwYBBQUHAQEEgaYw gaMwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9BZGRUcnVz dEV4dGVybmFsQ0FSb290LnA3YzA5BggrBgEFBQcwAoYtaHR0cDovL2NydC51c2Vy dHJ1c3QuY29tL0FkZFRydXN0VVROU0dDQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRw Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQAfc9TIvx20 699f6rUqg2kAAajfGuoXp1duVLJpPeZGK0ylelrlLLARtHj1dP6uCwhjf151aqo5 TSxNSVqHlAz3ipoRvTrgnczNtPtpzz8O/yEyl3W8GoQi1E1Zf5vV8cVpaQzYcP/e q4iUbge9lzJPBiqqMcGDHaEeoXSXUv0hyF3jcagy/zAVeQ8Lcg875CGo2qmIH4Wo j1fkh0BQGeagVRW1kU3RD8MgPa/y1aUIjOm21/LFurZUzZFpjaQzD6Pgv4tEJHkd gZjHJwlTJ5Hvdpt10xx58ieIJVK2XKznN/R9p2TD1NOVHs5+1VT4Yy2ngv3YMQsK pDl68CO8M3Fc -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXTCCA0WgAwIBAgILBAAAAAABRE7wSlUwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQwMjIwMTAwMDAwWhcNMjExMjE1 MDgwMDAwWjBiMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1z YTE4MDYGA1UEAxMvR2xvYmFsU2lnbiBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0g U0hBMjU2IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCj6qHS w0nl9xxdr8OSQq+KPNzvTOYvXwwrn4pQMGbvTshPIUr25/JOG4xTV7CeyFv3uEZV sxrtwmr+9BvsSEYOj+D74JEZ35kYby5Rr9r2mspkb5lUEHTqPMiqgE1DN/vIpH8F nTeSvZgANVqvu1t0FQ68vMbpt4bn7q5NSwRMK6C0ZUi4wzrNdbs3yUrAARHZvz8V hmAZazQgRvWGZg8k9Mxin5+eHf0QpJle8EHrsJT/LLM21usdpxdf385qd8eaxDJj pwat8xIbnTByWQvrcusq0nd7kXfbAPzYb/Uv2HrFDDqge16Q852EWcgB2ZE3VuU6 U5OtYEknJdnh2oLXAgMBAAGjggEoMIIBJDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0T AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU2kB3Q2Uc+P6n4/Rkgj5NQxMiMQIwRwYD VR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2Jh bHNpZ24uY29tL3JlcG9zaXRvcnkvMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9j cmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC1yMi5jcmwwPQYIKwYBBQUHAQEEMTAvMC0G CCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjIwHwYD VR0jBBgwFoAUm+IHV2ccHsBqBt5ZtJot39wZhi4wDQYJKoZIhvcNAQELBQADggEB AEDvEpCDdJaK+Tq6m1lKM9PvTBMrtZHLyZbtbvVsZPHGhLJGWVpYglLxNKBUQWQg q9hXO9QUdHEYNswTwcdwwPVFZg5xroevkpTrcUAJ9Mx39xuThYpKrjOF5nSu9RCm PslZg8P5XJb5KPc0e+k4xpE8T3FYdf7hVnV2zUDEFUA5qUH9ZBAPl4UH6Hlk0FtN TJsnl9NzXpJ+H0jiyrkFl07vLBxrTYpfeFOVzQI5wi/maU/2cdGZtX9tIN5Dj9sA G6M7N97RP23ztpB2Haydb4RPJJQJduCdqE33TTePpC9fS0HkSRaXzHtsrxHKllQJ iyRRrl3tovG7UxBNl/oadwM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5DCCA8ygAwIBAgIQT+PiZSEHqyA3QW5IcM7SwjANBgkqhkiG9w0BAQUFADBv MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF eHRlcm5hbCBDQSBSb290MB4XDTEwMDUyNTAwMDAwMFoXDTIwMDUzMDEwNDgzOFow azELMAkGA1UEBhMCVVMxLTArBgNVBAoTJFRydXN0ZWQgU2VjdXJlIENlcnRpZmlj YXRlIEF1dGhvcml0eTEtMCsGA1UEAxMkVHJ1c3RlZCBTZWN1cmUgQ2VydGlmaWNh dGUgQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgAtC xgZszyKzGp4RLkJuOb/oEq88QiESlUBdMrFtHCHRNOVPqNFDoiZOMH1zRCxzqsVN ZgEZ0upQWWXQaJ0FoHyheVPQIZBZDjfbHtySp4sNxPX45v+1NRraqLabIIVlxKJN 3/OUTWN+7okHr/7hugAVLcZ3jqP+rc8mVFrf/NLewq32siP9qIPlZb0n9ycaGFlq nhT2tIb/HFgUQ3OWJL8QQ9VcifDO9+GWFl4YSicokIAY/DL+9Me41oI9Na+7Shxb BXj2/VU+gnSyc7iJTvcbhZrYyrFasQAgQRQwKxQk7TcOMj4jiDl+udk4A+JM2Q1D QTMQ6zByU4j3UptPgQIDAQABo4IBfjCCAXowHwYDVR0jBBgwFoAUrb2YejS0Jvf6 xCZU7wO94CTLVBowHQYDVR0OBBYEFMwDW5ZanhbMJh69o3D748t5GfxNMA4GA1Ud DwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMBgGA1UdIAQRMA8wDQYLKwYB BAGyMQECAggwRAYDVR0fBD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3Qu Y29tL0FkZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMIGzBggrBgEFBQcBAQSBpjCB ozA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL0FkZFRydXN0 RXh0ZXJuYWxDQVJvb3QucDdjMDkGCCsGAQUFBzAChi1odHRwOi8vY3J0LnVzZXJ0 cnVzdC5jb20vQWRkVHJ1c3RVVE5TR0NDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6 Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEFBQADggEBAHvw/KEoR7wr tARzP0vdHtG5zRztfeXoy1H0kr/dnA1cbh2V7VtwUInUZ5oVVNGQCvoJaAYYu9cn 5JP/Q0iBO8hZSTXqrLauRrXU87jDxuSRv8k0/X7QWW5hoR9IY1SyfUa/yPrDv0hY mPZphKcWaQgnpCLLoizI326p7vhB3xuot/Pjrs6j/tknYFA/BH16ROp2QlzTVUbv J8VqSoDnNaCRxhumhpxaOwSDVDTX0YimNul/QCfaVgpQIZ0pi6CE7P5xI1MEGBlw Z4ZElXJAVfbdo7Q9LQlgpedf/Kw77AyRn/juarqyPP2VfZoH9LBlQ6L23324IUmE BO69zlOPDyk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGDjCCA/agAwIBAgIQBqdDgNTr/tQ1taP34Wq92DANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTIwMjEy MDAwMDAwWhcNMjcwMjExMjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQg VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAlVbeVLTf1QJJe9FbXKKyHo+cK2JMK40SKPMalaPGEP0p3uGf CzhAk9HvbpUQ/OGQF3cs7nU+e2PsYZJuTzurgElr3wDqAwB/L3XVKC/sVmePgIOj vdwDmZOLlJFWW6G4ajo/Br0OksxgnP214J9mMF/b5pTwlWqvyIqvgNnmiDkBfBzA xSr3e5Wg8narbZtyOTDr0VdVAZ1YEZ18bYSPSeidCfw8/QpKdhQhXBZzQCMZdMO6 WAqmli7eNuWf0MLw4eDBYuPCGEUZUaoXHugjddTI0JYT/8ck0YwLJ66eetw6YWNg iJctXQUL5Tvrrs46R3N2qPos3cCHF+msMJn4HwIDAQABo4IBaTCCAWUwHwYDVR0j BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFDna/8ooFIqodBMI ueQOqdL6fp1pMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMD4G A1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5j b21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAERCnUFRK0iIXZebeV4R AUpSGXtBLMeJPNBy3IX6WK/VJeQT+FhlZ58N/1eLqYVeyqZLsKeyLeCMIs37/3mk jCuN/gI9JN6pXV/kD0fQ22YlPodHDK4ixVAihNftSlka9pOlk7DgG4HyVsTIEFPk 1Hax0VtpS3ey4E/EhOfUoFDuPPpE/NBXueEoU/1Tzdy5H3pAvTA/2GzS8+cHnx8i teoiccsq8FZ8/qyo0QYPFBRSTP5kKwxpKrgNUG4+BAe/eiCL+O5lCeHHSQgyPQ0o fkkdt0rvAucNgBfIXOBhYsvss2B5JdoaZXOcOBCgJjqwyBZ9kzEi7nQLiMBciUEA KKlHMd99SUWa9eanRRrSjhMQ34Ovmw2tfn6dNVA0BM7pINae253UqNpktNEvWS5e ojZh1CSggjMziqHRbO9haKPl0latxf1eYusVqHQSTC8xjOnB3xBLAer2VBvNfzu9 XJ/B288ByvK6YBIhMe2pZLiySVgXbVrXzYxtvp5/4gJYp9vDLVj2dAZqmvZh+fYA tmnYOosxWd2R5nwnI4fdAw+PKowegwFOAWEMUnNt/AiiuSpm5HZNMaBWm9lTjaK2 jwLI5jqmBNFI+8NKAnb9L9K8E7bobTQk+p0pisehKxTxlgBzuRPpwLk6R1YCcYAn pLwltum95OmYdBbxN4SBB7SC -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4zCCA2qgAwIBAgIQTZVdIK+FxJ9pJfurfGZfiTAKBggqhkjOPQQDAzCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzQwHhcNMTIxMjIwMDAwMDAwWhcNMjIxMjE5MjM1OTU5WjCBizELMAkG A1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQL ExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMTwwOgYDVQQDEzNTeW1hbnRlYyBDbGFz cyAzIEVDQyAyNTYgYml0IEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EwWTATBgcqhkjO PQIBBggqhkjOPQMBBwNCAATdBD2y8pCTl8bpu7yR21Hwo4bt+8bThZMyBUngBINh llH/VyGuC9oO5wShf9sqHL3KmDXFcXNAzehqq1SEQybio4IBbTCCAWkwEgYDVR0T AQH/BAgwBgEB/wIBADA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLndzLnN5 bWFudGVjLmNvbS9wY2EzLWc0LmNybDAOBgNVHQ8BAf8EBAMCAQYwNwYIKwYBBQUH AQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC53cy5zeW1hbnRlYy5jb20w ZQYDVR0gBF4wXDBaBgRVHSAAMFIwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuc3lt YXV0aC5jb20vY3BzMCgGCCsGAQUFBwICMBwaGmh0dHA6Ly93d3cuc3ltYXV0aC5j b20vcnBhMCoGA1UdEQQjMCGkHzAdMRswGQYDVQQDExJTWU1DLUVDQy1DQS1wMjU2 LTMwHQYDVR0OBBYEFEgTZReU7J4WKip0XOhTLbT7g+uOMB8GA1UdIwQYMBaAFLMW kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2cAMGQCMFyb7oOjdk2MLQVM gjS6s77Oj+jDNIH7QHfoNGxbFys7rdWno9LzZsJPsrDIdpiPvwIwT8IvzpLFqb3O fU7UGztmJOpOzYKvVEqI7+O/OpNjVCF9EjDSMs2ryYGwpxFDe0Vm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2 4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1 itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn 4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly /D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF 0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae cPUeybQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEajCCA1KgAwIBAgIER4af5TANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQGEwJV UzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNl Y3VyZVRydXN0IENBMB4XDTA4MTIyMjIzNDczOVoXDTI4MTIyMjIzNDczOVowga4x CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJbGxpbm9pczEQMA4GA1UEBxMHQ2hpY2Fn bzEhMB8GA1UEChMYVHJ1c3R3YXZlIEhvbGRpbmdzLCBJbmMuMTYwNAYDVQQDEy1U cnVzdHdhdmUgT3JnYW5pemF0aW9uIFZhbGlkYXRpb24gQ0EsIExldmVsIDIxHzAd BgkqhkiG9w0BCQEWEGNhQHRydXN0d2F2ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDoFO6g2pe9ib0MzI3fCPsGCYOoI1FbAT802h8fbsHjWGXL Cvnzh8jI+qHM9XTiuK4tBoSAKG9awSJckpRCzRkCElwQYn6iRPsWXpxysazqBOYV qpnoWvhYuYck6HXNJYjiWJJehoN/iiNTrorooyF+g69ACRhJr+HQWrBPb+IxrfTx Nx/JKuGL1owSMdQnGt/qa554U+2aGbDORURbG+9kWSH6x7fR0wwey4ja/SM/9Kwr oE1h077K3hlhYSTx9py0lr2d6xefJDl46SNQ0wFQd9hSZC8+GU91uRex2o3g0O3b NxPcL+BfgGjX9Ie6wR8SeNAIJxd6mKaf0iG6Toe/AgMBAAGjgfQwgfEwDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQUXdmWmkDHJ8ssm6LszxmryK/MhkgwHwYDVR0j BBgwFoAUQjK2FvoE/f5dS3rD/fdMQB1aQ68wCwYDVR0PBAQDAgEGMDQGA1UdHwQt MCswKaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NUQ0EuY3JsMFsG A1UdIARUMFIwDAYKKwYBBAGB7RgDADBCBg8rBgEEAYHtGAMDAwMEBAMwLzAtBggr BgEFBQcCARYhaHR0cDovL3d3dy5zZWN1cmV0cnVzdC5jb20vbGVnYWwvMA0GCSqG SIb3DQEBBQUAA4IBAQBT8cigF+xsiIKxwCSv0QhYsyxve8FciZJviPxLwAJQky9a QZhZtuN/jBRjd31FPIhQXqaBUgDIxf5I7h9drd5EC0JYnOFnXEO2oIWY/xbUGii+ duEv4YT0frknqnfLNrP+w/rSF/bhYk7TzMyzGWXTS6jos9VM6vZOrsuuNEgfYMxY 5+d0yQE1/WrgWIrSFuvs6T678B3Ptv8eDLe7Oem3mBvAUiHrOj14OIypGV8npNB/ NmGrJH6f+C0/kiljvssQ2w1ANgKg1BeijX9+fJmvRVpAzaJrXL4O89OH/KEQyqoz t7pLwD2kIYwXnM/Yv+ZX/s3r+jAa1f7oJZepvjvq -----END CERTIFICATE----- ================================================ FILE: cmd/mkbundle/mkbundle.go ================================================ // mkbundle is a commandline tool for building certificate pool bundles. // All certificates in the input file paths are checked for revocation and bundled together. // // Usage: // // mkbundle -f bundle_file -nw number_of_workers certificate_file_path ... package main import ( "crypto/x509" "encoding/pem" "flag" "os" "path/filepath" "sync" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/revoke" ) // worker does all the parsing and validation of the certificate(s) // contained in a single file. It first reads all the data in the // file, then begins parsing certificates in the file. Those // certificates are then checked for revocation. func worker(paths chan string, bundler chan *x509.Certificate, pool *sync.WaitGroup) { defer (*pool).Done() for { path, ok := <-paths if !ok { return } log.Infof("Loading %s", path) fileData, err := os.ReadFile(path) if err != nil { log.Warningf("%v", err) continue } for { var block *pem.Block if len(fileData) == 0 { break } block, fileData = pem.Decode(fileData) if block == nil { log.Warningf("%s: no PEM data found", path) break } else if block.Type != "CERTIFICATE" { log.Info("Skipping non-certificate") continue } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { log.Warningf("Invalid certificate: %v", err) continue } log.Infof("Validating %+v", cert.Subject) revoked, ok := revoke.VerifyCertificate(cert) if !ok { log.Warning("Failed to verify certificate.") } else if !revoked { bundler <- cert } else { log.Info("Skipping revoked certificate") } } } } // supervisor sets up the workers and signals the bundler that all // certificates have been processed. func supervisor(paths chan string, bundler chan *x509.Certificate, numWorkers int) { var workerPool sync.WaitGroup for i := 0; i < numWorkers; i++ { workerPool.Add(1) go worker(paths, bundler, &workerPool) } workerPool.Wait() close(bundler) } // makeBundle opens the file for writing, and listens for incoming // certificates. These are PEM-encoded and written to file. func makeBundle(filename string, bundler chan *x509.Certificate) { file, err := os.Create(filename) if err != nil { log.Errorf("%v", err) return } defer file.Close() var total int for { cert, ok := <-bundler if !ok { break } block := &pem.Block{ Type: "CERTIFICATE", Bytes: cert.Raw, } err = pem.Encode(file, block) if err != nil { log.Errorf("Failed to write PEM block: %v", err) break } total++ } log.Infof("Wrote %d certificates.", total) } // scanFiles walks the files listed in the arguments. These files may // be either certificate files or directories containing certificates. func scanFiles(paths chan string) { walker := func(path string, info os.FileInfo, err error) error { log.Infof("Found %s", path) if err != nil { return err } if info.Mode().IsRegular() { paths <- path } return nil } for _, path := range flag.Args() { err := filepath.Walk(path, walker) if err != nil { log.Errorf("Walk failed: %v", err) } } close(paths) } func main() { bundleFile := flag.String("f", "cert-bundle.crt", "path to store certificate bundle") numWorkers := flag.Int("nw", 4, "number of workers") flag.Parse() paths := make(chan string) bundler := make(chan *x509.Certificate) go supervisor(paths, bundler, *numWorkers) go scanFiles(paths) makeBundle(*bundleFile, bundler) } ================================================ FILE: cmd/mkbundle/mkbundle_test.go ================================================ package main ================================================ FILE: cmd/multirootca/api.go ================================================ package main import ( "encoding/json" "fmt" "io" "net/http" "net/http/httputil" "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/auth" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/whitelist" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) // A SignatureResponse contains only a certificate, as there is no other // useful data for the CA to return at this time. type SignatureResponse struct { Certificate string `json:"certificate"` } type filter func(string, *signer.SignRequest) bool var filters = map[string][]filter{} var ( requests = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "requests_total", Help: "How many requests for each operation type and signer were succesfully processed.", }, []string{"operation", "signer"}, ) erroredRequests = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "requests_errored_total", Help: "How many requests for each operation type resulted in an error.", }, []string{"operation", "signer"}, ) badInputs = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "bad_inputs_total", Help: "How many times the input was malformed or not allowed.", }, []string{"operation"}, ) ) const ( signOperation = "sign" ) func fail(w http.ResponseWriter, req *http.Request, status, code int, msg, ad string) { badInputs.WithLabelValues(signOperation).Inc() if ad != "" { ad = " (" + ad + ")" } log.Errorf("[HTTP %d] %d - %s%s", status, code, msg, ad) dumpReq, err := httputil.DumpRequest(req, true) if err != nil { fmt.Printf("%v#v\n", req) } else { fmt.Printf("%s\n", dumpReq) } res := api.NewErrorResponse(msg, code) w.WriteHeader(status) jenc := json.NewEncoder(w) jenc.Encode(res) } func dispatchRequest(w http.ResponseWriter, req *http.Request) { if req.Method != "POST" { fail(w, req, http.StatusMethodNotAllowed, 1, "only POST is permitted", "") return } defer req.Body.Close() body, err := io.ReadAll(req.Body) if err != nil { fail(w, req, http.StatusInternalServerError, 1, err.Error(), "while reading request body") return } var authReq auth.AuthenticatedRequest err = json.Unmarshal(body, &authReq) if err != nil { fail(w, req, http.StatusBadRequest, 1, err.Error(), "while unmarshaling request body") return } var sigRequest signer.SignRequest err = json.Unmarshal(authReq.Request, &sigRequest) if err != nil { fail(w, req, http.StatusBadRequest, 1, err.Error(), "while unmarshalling authenticated request") return } if sigRequest.Label == "" { sigRequest.Label = defaultLabel } acl := whitelists[sigRequest.Label] if acl != nil { ip, err := whitelist.HTTPRequestLookup(req) if err != nil { fail(w, req, http.StatusInternalServerError, 1, err.Error(), "while getting request IP") return } if !acl.Permitted(ip) { fail(w, req, http.StatusForbidden, 1, "not authorised", "because IP is not whitelisted") return } } s, ok := signers[sigRequest.Label] if !ok { fail(w, req, http.StatusBadRequest, 1, "bad request", "request is for non-existent label "+sigRequest.Label) return } requests.WithLabelValues(signOperation, sigRequest.Label).Inc() // Sanity checks to ensure that we have a valid policy. This // should have been checked in NewAuthSignHandler. policy := s.Policy() if policy == nil { fail(w, req, http.StatusInternalServerError, 1, "invalid policy", "signer was initialised without a signing policy") return } profile := policy.Default if policy.Profiles != nil && sigRequest.Profile != "" { profile = policy.Profiles[sigRequest.Profile] if profile == nil { fail(w, req, http.StatusBadRequest, 1, "invalid profile", "failed to look up profile with name: "+sigRequest.Profile) return } } if profile == nil { fail(w, req, http.StatusInternalServerError, 1, "invalid profile", "signer was initialised without any valid profiles") return } if profile.Provider == nil { fail(w, req, http.StatusUnauthorized, 1, "authorisation required", "received unauthenticated request") return } validAuth := false if profile.Provider.Verify(&authReq) { validAuth = true } else if profile.PrevProvider != nil && profile.PrevProvider.Verify(&authReq) { validAuth = true } if !validAuth { fail(w, req, http.StatusBadRequest, 1, "invalid token", "received authenticated request with invalid token") return } if sigRequest.Request == "" { fail(w, req, http.StatusBadRequest, 1, "invalid request", "empty request") return } cert, err := s.Sign(sigRequest) if err != nil { erroredRequests.WithLabelValues(signOperation, sigRequest.Label).Inc() fail(w, req, http.StatusBadRequest, 1, "bad request", "signature failed: "+err.Error()) return } x509Cert, err := helpers.ParseCertificatePEM(cert) if err != nil { erroredRequests.WithLabelValues(signOperation, sigRequest.Label).Inc() fail(w, req, http.StatusInternalServerError, 1, "bad certificate", err.Error()) } log.Infof("signature: requester=%s, label=%s, profile=%s, serialno=%s", req.RemoteAddr, sigRequest.Label, sigRequest.Profile, x509Cert.SerialNumber) res := api.NewSuccessResponse(&SignatureResponse{Certificate: string(cert)}) jenc := json.NewEncoder(w) err = jenc.Encode(res) if err != nil { log.Errorf("error writing response: %v", err) } } func metricsDisallowed(w http.ResponseWriter, req *http.Request) { log.Warning("attempt to access metrics endpoint from external address ", req.RemoteAddr) http.NotFound(w, req) } ================================================ FILE: cmd/multirootca/ca.go ================================================ package main import ( "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "errors" "flag" "net" "net/http" "github.com/cloudflare/cfssl/api/info" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/multiroot/config" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/local" "github.com/cloudflare/cfssl/whitelist" "github.com/prometheus/client_golang/prometheus/promhttp" _ "github.com/go-sql-driver/mysql" // import to support MySQL _ "github.com/lib/pq" // import to support Postgres _ "github.com/mattn/go-sqlite3" // import to support SQLite ) func parseSigner(root *config.Root) (signer.Signer, error) { privateKey := root.PrivateKey switch priv := privateKey.(type) { case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey: s, err := local.NewSigner(priv, root.Certificate, signer.DefaultSigAlgo(priv), nil) if err != nil { return nil, err } s.SetPolicy(root.Config) if root.DB != nil { dbAccessor := sql.NewAccessor(root.DB) s.SetDBAccessor(dbAccessor) } return s, nil default: return nil, errors.New("unsupported private key type") } } var ( defaultLabel string signers = map[string]signer.Signer{} whitelists = map[string]whitelist.NetACL{} ) func main() { flagAddr := flag.String("a", ":8888", "listening address") flagRootFile := flag.String("roots", "", "configuration file specifying root keys") flagDefaultLabel := flag.String("l", "", "specify a default label") flagEndpointCert := flag.String("tls-cert", "", "server certificate") flagEndpointKey := flag.String("tls-key", "", "server private key") flag.IntVar(&log.Level, "loglevel", log.LevelInfo, "Log level (0 = DEBUG, 5 = FATAL)") flag.Parse() if *flagRootFile == "" { log.Fatal("no root file specified") } roots, err := config.Parse(*flagRootFile) if err != nil { log.Fatalf("%v", err) } for label, root := range roots { s, err := parseSigner(root) if err != nil { log.Criticalf("%v", err) } signers[label] = s if root.ACL != nil { whitelists[label] = root.ACL } log.Info("loaded signer ", label) } defaultLabel = *flagDefaultLabel infoHandler, err := info.NewMultiHandler(signers, defaultLabel) if err != nil { log.Criticalf("%v", err) } var localhost = whitelist.NewBasic() localhost.Add(net.ParseIP("127.0.0.1")) localhost.Add(net.ParseIP("::1")) http.HandleFunc("/api/v1/cfssl/authsign", dispatchRequest) http.Handle("/api/v1/cfssl/info", infoHandler) http.Handle("/metrics", promhttp.Handler()) if *flagEndpointCert == "" && *flagEndpointKey == "" { log.Info("Now listening on ", *flagAddr) log.Fatal(http.ListenAndServe(*flagAddr, nil)) } else { log.Info("Now listening on https:// ", *flagAddr) log.Fatal(http.ListenAndServeTLS(*flagAddr, *flagEndpointCert, *flagEndpointKey, nil)) } } ================================================ FILE: config/config.go ================================================ // Package config contains the configuration logic for CFSSL. package config import ( "crypto/tls" "crypto/x509" "encoding/asn1" "encoding/json" "errors" "fmt" "os" "regexp" "strconv" "strings" "time" "github.com/cloudflare/cfssl/auth" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" ocspConfig "github.com/cloudflare/cfssl/ocsp/config" // empty import of zlint/v3 required to have lints registered. _ "github.com/zmap/zlint/v3" "github.com/zmap/zlint/v3/lint" ) // A CSRWhitelist stores booleans for fields in the CSR. If a CSRWhitelist is // not present in a SigningProfile, all of these fields may be copied from the // CSR into the signed certificate. If a CSRWhitelist *is* present in a // SigningProfile, only those fields with a `true` value in the CSRWhitelist may // be copied from the CSR to the signed certificate. Note that some of these // fields, like Subject, can be provided or partially provided through the API. // Since API clients are expected to be trusted, but CSRs are not, fields // provided through the API are not subject to whitelisting through this // mechanism. type CSRWhitelist struct { Subject, PublicKeyAlgorithm, PublicKey, SignatureAlgorithm bool DNSNames, IPAddresses, EmailAddresses, URIs bool } // OID is our own version of asn1's ObjectIdentifier, so we can define a custom // JSON marshal / unmarshal. type OID asn1.ObjectIdentifier // CertificatePolicy represents the ASN.1 PolicyInformation structure from // https://tools.ietf.org/html/rfc3280.html#page-106. // Valid values of Type are "id-qt-unotice" and "id-qt-cps" type CertificatePolicy struct { ID OID Qualifiers []CertificatePolicyQualifier } // CertificatePolicyQualifier represents a single qualifier from an ASN.1 // PolicyInformation structure. type CertificatePolicyQualifier struct { Type string Value string } // AuthRemote is an authenticated remote signer. type AuthRemote struct { RemoteName string `json:"remote"` AuthKeyName string `json:"auth_key"` } // CAConstraint specifies various CA constraints on the signed certificate. // CAConstraint would verify against (and override) the CA // extensions in the given CSR. type CAConstraint struct { IsCA bool `json:"is_ca"` MaxPathLen int `json:"max_path_len"` MaxPathLenZero bool `json:"max_path_len_zero"` } // A SigningProfile stores information that the CA needs to store // signature policy. type SigningProfile struct { Usage []string `json:"usages"` IssuerURL []string `json:"issuer_urls"` OCSP string `json:"ocsp_url"` CRL string `json:"crl_url"` CAConstraint CAConstraint `json:"ca_constraint"` OCSPNoCheck bool `json:"ocsp_no_check"` ExpiryString string `json:"expiry"` BackdateString string `json:"backdate"` AuthKeyName string `json:"auth_key"` CopyExtensions bool `json:"copy_extensions"` PrevAuthKeyName string `json:"prev_auth_key"` // to support key rotation RemoteName string `json:"remote"` NotBefore time.Time `json:"not_before"` NotAfter time.Time `json:"not_after"` NameWhitelistString string `json:"name_whitelist"` AuthRemote AuthRemote `json:"auth_remote"` CTLogServers []string `json:"ct_log_servers"` AllowedExtensions []OID `json:"allowed_extensions"` CertStore string `json:"cert_store"` // LintErrLevel controls preissuance linting for the signing profile. // 0 = no linting is performed [default] // 2..3 = reserved // 3 = all lint results except pass are considered errors // 4 = all lint results except pass and notice are considered errors // 5 = all lint results except pass, notice and warn are considered errors // 6 = all lint results except pass, notice, warn and error are considered errors. // 7 = lint is performed, no lint results are treated as errors. LintErrLevel lint.LintStatus `json:"lint_error_level"` // ExcludeLints lists ZLint lint names to exclude from preissuance linting. ExcludeLints []string `json:"ignored_lints"` // ExcludeLintSources lists ZLint lint sources to exclude from preissuance // linting. ExcludeLintSources []string `json:"ignored_lint_sources"` Policies []CertificatePolicy Expiry time.Duration Backdate time.Duration Provider auth.Provider PrevProvider auth.Provider // to suppport key rotation RemoteProvider auth.Provider RemoteServer string RemoteCAs *x509.CertPool ClientCert *tls.Certificate CSRWhitelist *CSRWhitelist NameWhitelist *regexp.Regexp ExtensionWhitelist map[string]bool ClientProvidesSerialNumbers bool // LintRegistry is the collection of lints that should be used if // LintErrLevel is configured. By default all ZLint lints are used. If // ExcludeLints or ExcludeLintSources are set then this registry will be // filtered in populate() to exclude the named lints and lint sources. LintRegistry lint.Registry } // UnmarshalJSON unmarshals a JSON string into an OID. func (oid *OID) UnmarshalJSON(data []byte) (err error) { if data[0] != '"' || data[len(data)-1] != '"' { return errors.New("OID JSON string not wrapped in quotes." + string(data)) } data = data[1 : len(data)-1] parsedOid, err := parseObjectIdentifier(string(data)) if err != nil { return err } *oid = OID(parsedOid) return } // MarshalJSON marshals an oid into a JSON string. func (oid OID) MarshalJSON() ([]byte, error) { return []byte(fmt.Sprintf(`"%v"`, asn1.ObjectIdentifier(oid))), nil } func parseObjectIdentifier(oidString string) (oid asn1.ObjectIdentifier, err error) { validOID, err := regexp.MatchString("\\d(\\.\\d+)*", oidString) if err != nil { return } if !validOID { err = errors.New("Invalid OID") return } segments := strings.Split(oidString, ".") oid = make(asn1.ObjectIdentifier, len(segments)) for i, intString := range segments { oid[i], err = strconv.Atoi(intString) if err != nil { return } } return } const timeFormat = "2006-01-02T15:04:05" // populate is used to fill in the fields that are not in JSON // // First, the ExpiryString parameter is needed to parse // expiration timestamps from JSON. The JSON decoder is not able to // decode a string time duration to a time.Duration, so this is called // when loading the configuration to properly parse and fill out the // Expiry parameter. // This function is also used to create references to the auth key // and default remote for the profile. // It returns true if ExpiryString is a valid representation of a // time.Duration, and the AuthKeyString and RemoteName point to // valid objects. It returns false otherwise. func (p *SigningProfile) populate(cfg *Config) error { if p == nil { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("can't parse nil profile")) } var err error if p.RemoteName == "" && p.AuthRemote.RemoteName == "" { log.Debugf("parse expiry in profile") if p.ExpiryString == "" { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("empty expiry string")) } dur, err := time.ParseDuration(p.ExpiryString) if err != nil { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err) } log.Debugf("expiry is valid") p.Expiry = dur if p.BackdateString != "" { dur, err = time.ParseDuration(p.BackdateString) if err != nil { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err) } p.Backdate = dur } if !p.NotBefore.IsZero() && !p.NotAfter.IsZero() && p.NotAfter.Before(p.NotBefore) { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err) } if len(p.Policies) > 0 { for _, policy := range p.Policies { for _, qualifier := range policy.Qualifiers { if qualifier.Type != "" && qualifier.Type != "id-qt-unotice" && qualifier.Type != "id-qt-cps" { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid policy qualifier type")) } } } } } else if p.RemoteName != "" { log.Debug("match remote in profile to remotes section") if p.AuthRemote.RemoteName != "" { log.Error("profile has both a remote and an auth remote specified") return cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } if remote := cfg.Remotes[p.RemoteName]; remote != "" { if err := p.updateRemote(remote); err != nil { return err } } else { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to find remote in remotes section")) } } else { log.Debug("match auth remote in profile to remotes section") if remote := cfg.Remotes[p.AuthRemote.RemoteName]; remote != "" { if err := p.updateRemote(remote); err != nil { return err } } else { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to find remote in remotes section")) } } if p.AuthKeyName != "" { log.Debug("match auth key in profile to auth_keys section") if key, ok := cfg.AuthKeys[p.AuthKeyName]; ok { if key.Type == "standard" { p.Provider, err = auth.New(key.Key, nil) if err != nil { log.Debugf("failed to create new standard auth provider: %v", err) return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to create new standard auth provider")) } } else { log.Debugf("unknown authentication type %v", key.Type) return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("unknown authentication type")) } } else { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to find auth_key in auth_keys section")) } } if p.PrevAuthKeyName != "" { log.Debug("match previous auth key in profile to auth_keys section") if key, ok := cfg.AuthKeys[p.PrevAuthKeyName]; ok { if key.Type == "standard" { p.PrevProvider, err = auth.New(key.Key, nil) if err != nil { log.Debugf("failed to create new standard auth provider: %v", err) return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to create new standard auth provider")) } } else { log.Debugf("unknown authentication type %v", key.Type) return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("unknown authentication type")) } } else { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to find prev_auth_key in auth_keys section")) } } if p.AuthRemote.AuthKeyName != "" { log.Debug("match auth remote key in profile to auth_keys section") if key, ok := cfg.AuthKeys[p.AuthRemote.AuthKeyName]; ok { if key.Type == "standard" { p.RemoteProvider, err = auth.New(key.Key, nil) if err != nil { log.Debugf("failed to create new standard auth provider: %v", err) return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to create new standard auth provider")) } } else { log.Debugf("unknown authentication type %v", key.Type) return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("unknown authentication type")) } } else { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to find auth_remote's auth_key in auth_keys section")) } } if p.NameWhitelistString != "" { log.Debug("compiling whitelist regular expression") rule, err := regexp.Compile(p.NameWhitelistString) if err != nil { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to compile name whitelist section")) } p.NameWhitelist = rule } p.ExtensionWhitelist = map[string]bool{} for _, oid := range p.AllowedExtensions { p.ExtensionWhitelist[asn1.ObjectIdentifier(oid).String()] = true } // By default perform any required preissuance linting with all ZLint lints. p.LintRegistry = lint.GlobalRegistry() // If ExcludeLintSources are present in config build a lint.SourceList while // validating that no unknown sources were specified. var excludedSources lint.SourceList if len(p.ExcludeLintSources) > 0 { for _, sourceName := range p.ExcludeLintSources { var lintSource lint.LintSource lintSource.FromString(sourceName) if lintSource == lint.UnknownLintSource { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, fmt.Errorf("failed to build excluded lint source list: unknown source %q", sourceName)) } excludedSources = append(excludedSources, lintSource) } } opts := lint.FilterOptions{ ExcludeNames: p.ExcludeLints, ExcludeSources: excludedSources, } if !opts.Empty() { // If ExcludeLints or ExcludeLintSources were not empty then filter out the // lints we don't want to use for preissuance linting with this profile. filteredRegistry, err := p.LintRegistry.Filter(opts) if err != nil { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, fmt.Errorf("failed to build filtered lint registry: %v", err)) } p.LintRegistry = filteredRegistry } return nil } // updateRemote takes a signing profile and initializes the remote server object // to the hostname:port combination sent by remote. func (p *SigningProfile) updateRemote(remote string) error { if remote != "" { p.RemoteServer = remote } return nil } // OverrideRemotes takes a signing configuration and updates the remote server object // to the hostname:port combination sent by remote func (p *Signing) OverrideRemotes(remote string) error { if remote != "" { var err error for _, profile := range p.Profiles { err = profile.updateRemote(remote) if err != nil { return err } } err = p.Default.updateRemote(remote) if err != nil { return err } } return nil } // SetClientCertKeyPairFromFile updates the properties to set client certificates for mutual // authenticated TLS remote requests func (p *Signing) SetClientCertKeyPairFromFile(certFile string, keyFile string) error { if certFile != "" && keyFile != "" { cert, err := helpers.LoadClientCertificate(certFile, keyFile) if err != nil { return err } for _, profile := range p.Profiles { profile.ClientCert = cert } p.Default.ClientCert = cert } return nil } // SetRemoteCAsFromFile reads root CAs from file and updates the properties to set remote CAs for TLS // remote requests func (p *Signing) SetRemoteCAsFromFile(caFile string) error { if caFile != "" { remoteCAs, err := helpers.LoadPEMCertPool(caFile) if err != nil { return err } p.SetRemoteCAs(remoteCAs) } return nil } // SetRemoteCAs updates the properties to set remote CAs for TLS // remote requests func (p *Signing) SetRemoteCAs(remoteCAs *x509.CertPool) { for _, profile := range p.Profiles { profile.RemoteCAs = remoteCAs } p.Default.RemoteCAs = remoteCAs } // NeedsRemoteSigner returns true if one of the profiles has a remote set func (p *Signing) NeedsRemoteSigner() bool { for _, profile := range p.Profiles { if profile.RemoteServer != "" { return true } } return p.Default.RemoteServer != "" } // NeedsLocalSigner returns true if one of the profiles doe not have a remote set func (p *Signing) NeedsLocalSigner() bool { for _, profile := range p.Profiles { if profile.RemoteServer == "" { return true } } return p.Default.RemoteServer == "" } // Usages parses the list of key uses in the profile, translating them // to a list of X.509 key usages and extended key usages. The unknown // uses are collected into a slice that is also returned. func (p *SigningProfile) Usages() (ku x509.KeyUsage, eku []x509.ExtKeyUsage, unk []string) { for _, keyUse := range p.Usage { if kuse, ok := KeyUsage[keyUse]; ok { ku |= kuse } else if ekuse, ok := ExtKeyUsage[keyUse]; ok { eku = append(eku, ekuse) } else { unk = append(unk, keyUse) } } return } // A valid profile must be a valid local profile or a valid remote profile. // A valid local profile has defined at least key usages to be used, and a // valid local default profile has defined at least a default expiration. // A valid remote profile (default or not) has remote signer initialized. // In addition, a remote profile must has a valid auth provider if auth // key defined. A valid profile must not include a lint_error_level outside of // [0,8). func (p *SigningProfile) validProfile(isDefault bool) bool { if p == nil { return false } if p.AuthRemote.RemoteName == "" && p.AuthRemote.AuthKeyName != "" { log.Debugf("invalid auth remote profile: no remote signer specified") return false } if p.RemoteName != "" { log.Debugf("validate remote profile") if p.RemoteServer == "" { log.Debugf("invalid remote profile: no remote signer specified") return false } if p.AuthKeyName != "" && p.Provider == nil { log.Debugf("invalid remote profile: auth key name is defined but no auth provider is set") return false } if p.AuthRemote.RemoteName != "" { log.Debugf("invalid remote profile: auth remote is also specified") return false } } else if p.AuthRemote.RemoteName != "" { log.Debugf("validate auth remote profile") if p.RemoteServer == "" { log.Debugf("invalid auth remote profile: no remote signer specified") return false } if p.AuthRemote.AuthKeyName == "" || p.RemoteProvider == nil { log.Debugf("invalid auth remote profile: no auth key is defined") return false } } else { log.Debugf("validate local profile") if !isDefault { if len(p.Usage) == 0 { log.Debugf("invalid local profile: no usages specified") return false } else if _, _, unk := p.Usages(); len(unk) == len(p.Usage) { log.Debugf("invalid local profile: no valid usages") return false } } else { if p.Expiry == 0 { log.Debugf("invalid local profile: no expiry set") return false } } } if p.LintErrLevel < 0 || p.LintErrLevel >= 8 { log.Debugf("invalid profile: lint_error_level outside of range [0,8)") return false } log.Debugf("profile is valid") return true } // This checks if the SigningProfile object contains configurations that are only effective with a local signer // which has access to CA private key. func (p *SigningProfile) hasLocalConfig() bool { if p.Usage != nil || p.IssuerURL != nil || p.OCSP != "" || p.ExpiryString != "" || p.BackdateString != "" || p.CAConstraint.IsCA || !p.NotBefore.IsZero() || !p.NotAfter.IsZero() || p.NameWhitelistString != "" || len(p.CTLogServers) != 0 { return true } return false } // warnSkippedSettings prints a log warning message about skipped settings // in a SigningProfile, usually due to remote signer. func (p *Signing) warnSkippedSettings() { const warningMessage = `The configuration value by "usages", "issuer_urls", "ocsp_url", "crl_url", "ca_constraint", "expiry", "backdate", "not_before", "not_after", "cert_store" and "ct_log_servers" are skipped` if p == nil { return } if (p.Default.RemoteName != "" || p.Default.AuthRemote.RemoteName != "") && p.Default.hasLocalConfig() { log.Warning("default profile points to a remote signer: ", warningMessage) } for name, profile := range p.Profiles { if (profile.RemoteName != "" || profile.AuthRemote.RemoteName != "") && profile.hasLocalConfig() { log.Warningf("Profiles[%s] points to a remote signer: %s", name, warningMessage) } } } // Signing codifies the signature configuration policy for a CA. type Signing struct { Profiles map[string]*SigningProfile `json:"profiles"` Default *SigningProfile `json:"default"` } // Config stores configuration information for the CA. type Config struct { Signing *Signing `json:"signing"` OCSP *ocspConfig.Config `json:"ocsp"` AuthKeys map[string]AuthKey `json:"auth_keys,omitempty"` Remotes map[string]string `json:"remotes,omitempty"` } // Valid ensures that Config is a valid configuration. It should be // called immediately after parsing a configuration file. func (c *Config) Valid() bool { return c.Signing.Valid() } // Valid checks the signature policies, ensuring they are valid // policies. A policy is valid if it has defined at least key usages // to be used, and a valid default profile has defined at least a // default expiration. func (p *Signing) Valid() bool { if p == nil { return false } log.Debugf("validating configuration") if !p.Default.validProfile(true) { log.Debugf("default profile is invalid") return false } for _, sp := range p.Profiles { if !sp.validProfile(false) { log.Debugf("invalid profile") return false } } p.warnSkippedSettings() return true } // KeyUsage contains a mapping of string names to key usages. var KeyUsage = map[string]x509.KeyUsage{ "signing": x509.KeyUsageDigitalSignature, "digital signature": x509.KeyUsageDigitalSignature, "content commitment": x509.KeyUsageContentCommitment, "key encipherment": x509.KeyUsageKeyEncipherment, "key agreement": x509.KeyUsageKeyAgreement, "data encipherment": x509.KeyUsageDataEncipherment, "cert sign": x509.KeyUsageCertSign, "crl sign": x509.KeyUsageCRLSign, "encipher only": x509.KeyUsageEncipherOnly, "decipher only": x509.KeyUsageDecipherOnly, } // ExtKeyUsage contains a mapping of string names to extended key // usages. var ExtKeyUsage = map[string]x509.ExtKeyUsage{ "any": x509.ExtKeyUsageAny, "server auth": x509.ExtKeyUsageServerAuth, "client auth": x509.ExtKeyUsageClientAuth, "code signing": x509.ExtKeyUsageCodeSigning, "email protection": x509.ExtKeyUsageEmailProtection, "s/mime": x509.ExtKeyUsageEmailProtection, "ipsec end system": x509.ExtKeyUsageIPSECEndSystem, "ipsec tunnel": x509.ExtKeyUsageIPSECTunnel, "ipsec user": x509.ExtKeyUsageIPSECUser, "timestamping": x509.ExtKeyUsageTimeStamping, "ocsp signing": x509.ExtKeyUsageOCSPSigning, "microsoft sgc": x509.ExtKeyUsageMicrosoftServerGatedCrypto, "netscape sgc": x509.ExtKeyUsageNetscapeServerGatedCrypto, } // An AuthKey contains an entry for a key used for authentication. type AuthKey struct { // Type contains information needed to select the appropriate // constructor. For example, "standard" for HMAC-SHA-256, // "standard-ip" for HMAC-SHA-256 incorporating the client's // IP. Type string `json:"type"` // Key contains the key information, such as a hex-encoded // HMAC key. Key string `json:"key"` } // DefaultConfig returns a default configuration specifying basic key // usage and a 1 year expiration time. The key usages chosen are // signing, key encipherment, client auth and server auth. func DefaultConfig() *SigningProfile { d := helpers.OneYear return &SigningProfile{ Usage: []string{"signing", "key encipherment", "server auth", "client auth"}, Expiry: d, ExpiryString: "8760h", } } // LoadFile attempts to load the configuration file stored at the path // and returns the configuration. On error, it returns nil. func LoadFile(path string) (*Config, error) { log.Debugf("loading configuration file from %s", path) if path == "" { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path")) } body, err := os.ReadFile(path) if err != nil { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file")) } return LoadConfig(body) } // LoadConfig attempts to load the configuration from a byte slice. // On error, it returns nil. func LoadConfig(config []byte) (*Config, error) { var cfg = &Config{} err := json.Unmarshal(config, &cfg) if err != nil { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to unmarshal configuration: "+err.Error())) } if cfg.Signing == nil { return nil, errors.New("No \"signing\" field present") } if cfg.Signing.Default == nil { log.Debugf("no default given: using default config") cfg.Signing.Default = DefaultConfig() } else { if err := cfg.Signing.Default.populate(cfg); err != nil { return nil, err } } for k := range cfg.Signing.Profiles { if err := cfg.Signing.Profiles[k].populate(cfg); err != nil { return nil, err } } if !cfg.Valid() { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid configuration")) } log.Debugf("configuration ok") return cfg, nil } ================================================ FILE: config/config_test.go ================================================ package config import ( "encoding/json" "fmt" "testing" "time" ) var expiry = 1 * time.Minute var invalidProfileConfig = &Config{ Signing: &Signing{ Profiles: map[string]*SigningProfile{ "invalid": { Usage: []string{"wiretapping"}, Expiry: expiry, }, "empty": {}, "invalid-lint": { Usage: []string{"digital signature"}, Expiry: expiry, LintErrLevel: 9000, }, }, Default: &SigningProfile{ Usage: []string{"digital signature"}, Expiry: expiry, }, }, } var invalidDefaultConfig = &Config{ Signing: &Signing{ Profiles: map[string]*SigningProfile{ "key usage": { Usage: []string{"digital signature"}, }, }, Default: &SigningProfile{ Usage: []string{"s/mime"}, }, }, } var validConfig = &Config{ Signing: &Signing{ Profiles: map[string]*SigningProfile{ "valid": { Usage: []string{"digital signature"}, Expiry: expiry, }, "valid-lint": { Usage: []string{"digital signature"}, Expiry: expiry, LintErrLevel: 5, ExcludeLints: []string{"n_subject_common_name_included"}, ExcludeLintSources: []string{"ETSI-ESI"}, }, }, Default: &SigningProfile{ Usage: []string{"digital signature"}, Expiry: expiry, }, }, } var validMixedConfig = ` { "signing": { "profiles": { "CA": { "auth_key": "sample", "remote": "localhost" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } }` var validMinimalRemoteConfig = ` { "signing": { "default": { "auth_key": "sample", "remote": "localhost" } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } }` var validMinimalRemoteConfig2 = ` { "signing": { "default": { "auth_remote":{ "auth_key": "sample", "remote": "localhost" } } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } }` var invalidConflictRemoteConfig = ` { "signing": { "default": { "auth_remote":{ "auth_key": "sample", "remote": "localhost" }, "remote": "localhost" } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } }` var invalidRemoteConfig = ` { "signing": { "default": { "auth_remotes_typos":{ "auth_key": "sample", "remote": "localhost" } } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } }` var invalidAuthRemoteConfigMissingRemote = ` { "signing": { "default": { "auth_remote":{ "auth_key": "sample" } } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } }` var invalidAuthRemoteConfigMissingKey = ` { "signing": { "default": { "auth_remote":{ "remote": "localhost" } } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } }` var validMinimalLocalConfig = ` { "signing": { "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } } }` var validLocalConfigsWithCAConstraint = []string{ `{ "signing": { "default": { "usages": ["digital signature", "email protection"], "ca_constraint": { "is_ca": true }, "expiry": "8000h" } } }`, `{ "signing": { "default": { "usages": ["digital signature", "email protection"], "ca_constraint": { "is_ca": true, "max_path_len": 1 }, "expiry": "8000h" } } }`, `{ "signing": { "default": { "usages": ["digital signature", "email protection"], "ca_constraint": { "is_ca": true, "max_path_len_zero": true }, "expiry": "8000h" } } }`, } var copyExtensionWantedlLocalConfig = ` { "signing": { "default": { "expiry": "8000h", "copy_extensions": true } } }` var copyExtensionNotWantedlLocalConfig = ` { "signing": { "default": { "expiry": "8000h" } } }` func TestInvalidProfile(t *testing.T) { if invalidProfileConfig.Signing.Profiles["invalid"].validProfile(false) { t.Fatal("invalid profile accepted as valid") } if invalidProfileConfig.Signing.Profiles["empty"].validProfile(false) { t.Fatal("invalid profile accepted as valid") } if invalidProfileConfig.Signing.Profiles["invalid-lint"].validProfile(false) { t.Fatal("invalid profile accepted as valid") } if invalidProfileConfig.Valid() { t.Fatal("invalid config accepted as valid") } if !invalidProfileConfig.Signing.Profiles["invalid"].validProfile(true) { t.Fatal("invalid profile should be a valid default profile") } } func TestRemoteProfiles(t *testing.T) { var validRemoteProfile = &SigningProfile{ RemoteName: "localhost", RemoteServer: "localhost:8080", } var invalidRemoteProfile = &SigningProfile{ RemoteName: "localhost", } var invalidRemoteAuthProfile = &SigningProfile{ RemoteName: "localhost", RemoteServer: "localhost:8080", AuthKeyName: "blahblah", } if !validRemoteProfile.validProfile(true) || !validRemoteProfile.validProfile(false) { t.Fatal("valid remote profile is rejected.") } if invalidRemoteProfile.validProfile(true) || invalidRemoteProfile.validProfile(false) { t.Fatal("invalid remote profile is accepted.") } if invalidRemoteAuthProfile.validProfile(true) || invalidRemoteAuthProfile.validProfile(false) { t.Fatal("invalid remote profile is accepted.") } } func TestInvalidDefault(t *testing.T) { if invalidDefaultConfig.Signing.Default.validProfile(true) { t.Fatal("invalid default accepted as valid") } if invalidDefaultConfig.Valid() { t.Fatal("invalid config accepted as valid") } if !invalidDefaultConfig.Signing.Default.validProfile(false) { t.Fatal("invalid default profile should be a valid profile") } } func TestValidConfig(t *testing.T) { if !validConfig.Valid() { t.Fatal("Valid config is not valid") } bytes, _ := json.Marshal(validConfig) fmt.Printf("%v", string(bytes)) } func TestDefaultConfig(t *testing.T) { if !DefaultConfig().validProfile(false) { t.Fatal("global default signing profile should be a valid profile.") } if !DefaultConfig().validProfile(true) { t.Fatal("global default signing profile should be a valid default profile") } } func TestParse(t *testing.T) { var validProfiles = []*SigningProfile{ { ExpiryString: "8760h", }, { ExpiryString: "168h", }, { ExpiryString: "300s", }, } var invalidProfiles = []*SigningProfile{ nil, {}, { ExpiryString: "", }, { ExpiryString: "365d", }, { ExpiryString: "1y", }, { ExpiryString: "one year", }, } for _, p := range validProfiles { if p.populate(nil) != nil { t.Fatalf("Failed to parse ExpiryString=%s", p.ExpiryString) } } for _, p := range invalidProfiles { if p.populate(nil) == nil { if p != nil { t.Fatalf("ExpiryString=%s should not be parsable", p.ExpiryString) } t.Fatalf("Nil profile should not be parsable") } } } func TestPopulateLintRegistry(t *testing.T) { excludedLintName := "n_subject_common_name_included" etsiLintName := "w_qcstatem_qctype_web" profile := &SigningProfile{ ExpiryString: "300s", ExcludeLints: []string{excludedLintName}, ExcludeLintSources: []string{"ETSI_ESI"}, } if err := profile.populate(nil); err != nil { t.Fatal("unexpected error from profile populate") } // The LintRegistry shouldn't be nil. if profile.LintRegistry == nil { t.Errorf("expected to find non-nil lint registry after populate()") } // The excluded lint shouldn't be found in the registry if l := profile.LintRegistry.ByName(excludedLintName); l != nil { t.Errorf("expected lint name %q to be filtered out, found %v", excludedLintName, l) } // A lint from the excluded source category shouldn't be found in the registry. if l := profile.LintRegistry.ByName(etsiLintName); l != nil { t.Errorf("expected lint name %q to be filtered out, found %v", etsiLintName, l) } } func TestLoadFile(t *testing.T) { validConfigFiles := []string{ "testdata/valid_config.json", "testdata/valid_config_auth.json", "testdata/valid_config_no_default.json", "testdata/valid_config_auth_no_default.json", } for _, configFile := range validConfigFiles { _, err := LoadFile(configFile) if err != nil { t.Fatal("Load valid config file failed.", configFile, "error is ", err) } } } func TestLoadInvalidConfigFile(t *testing.T) { invalidConfigFiles := []string{"", "testdata/no_such_file", "testdata/invalid_default.json", "testdata/invalid_profiles.json", "testdata/invalid_usage.json", "testdata/invalid_config.json", "testdata/invalid_auth.json", "testdata/invalid_auth_bad_key.json", "testdata/invalid_no_auth_keys.json", "testdata/invalid_remote.json", "testdata/invalid_no_remotes.json", } for _, configFile := range invalidConfigFiles { _, err := LoadFile(configFile) if err == nil { t.Fatal("Invalid config is loaded.", configFile) } } } func TestNeedLocalSigner(t *testing.T) { c, err := LoadConfig([]byte(validMixedConfig)) if err != nil { t.Fatal("load valid config failed:", err) } // This signing config needs both local signer and remote signer. if c.Signing.NeedsLocalSigner() != true { t.Fatal("incorrect NeedsLocalSigner().") } if c.Signing.NeedsRemoteSigner() != true { t.Fatal("incorrect NeedsRemoteSigner()") } remoteConfig, err := LoadConfig([]byte(validMinimalRemoteConfig)) if err != nil { t.Fatal("Load valid config failed:", err) } if remoteConfig.Signing.NeedsLocalSigner() != false { t.Fatal("incorrect NeedsLocalSigner().") } if remoteConfig.Signing.NeedsRemoteSigner() != true { t.Fatal("incorrect NeedsRemoteSigner().") } localConfig, err := LoadConfig([]byte(validMinimalLocalConfig)) if localConfig.Signing.NeedsLocalSigner() != true { t.Fatal("incorrect NeedsLocalSigner().") } if localConfig.Signing.NeedsRemoteSigner() != false { t.Fatal("incorrect NeedsRemoteSigner().") } if err != nil { t.Fatal(err) } } func TestOverrideRemotes(t *testing.T) { c, err := LoadConfig([]byte(validMixedConfig)) if err != nil { t.Fatal("load valid config failed:", err) } host := "localhost:8888" c.Signing.OverrideRemotes(host) if c.Signing.Default.RemoteServer != host { t.Fatal("should override default profile's RemoteServer") } for _, p := range c.Signing.Profiles { if p.RemoteServer != host { t.Fatal("failed to override profile's RemoteServer") } } } func TestAuthRemoteConfig(t *testing.T) { c, err := LoadConfig([]byte(validMinimalRemoteConfig2)) if err != nil { t.Fatal("load valid config failed:", err) } if c.Signing.Default.RemoteServer != "127.0.0.1:8888" { t.Fatal("load valid config failed: incorrect remote server") } host := "localhost:8888" c.Signing.OverrideRemotes(host) if c.Signing.Default.RemoteServer != host { t.Fatal("should override default profile's RemoteServer") } for _, p := range c.Signing.Profiles { if p.RemoteServer != host { t.Fatal("failed to override profile's RemoteServer") } } } func TestDuplicateRemoteConfig(t *testing.T) { _, err := LoadConfig([]byte(invalidConflictRemoteConfig)) if err == nil { t.Fatal("fail to reject invalid config") } } func TestBadAuthRemoteConfig(t *testing.T) { _, err := LoadConfig([]byte(invalidRemoteConfig)) if err == nil { t.Fatal("load invalid config should failed") } _, err = LoadConfig([]byte(invalidAuthRemoteConfigMissingRemote)) if err == nil { t.Fatal("load invalid config should failed") } _, err = LoadConfig([]byte(invalidAuthRemoteConfigMissingKey)) if err == nil { t.Fatal("load invalid config should failed") } var p *Signing if p.Valid() { t.Fatal("nil Signing config should be invalid") } } func TestValidCAConstraint(t *testing.T) { for _, config := range validLocalConfigsWithCAConstraint { _, err := LoadConfig([]byte(config)) if err != nil { t.Fatal("can't parse valid ca constraint") } } } func TestWantCopyExtension(t *testing.T) { localConfig, err := LoadConfig([]byte(copyExtensionWantedlLocalConfig)) if localConfig.Signing.Default.CopyExtensions != true { t.Fatal("incorrect TestWantCopyExtension().") } if err != nil { t.Fatal(err) } } func TestDontWantCopyExtension(t *testing.T) { localConfig, err := LoadConfig([]byte(copyExtensionNotWantedlLocalConfig)) if localConfig.Signing.Default.CopyExtensions != false { t.Fatal("incorrect TestDontWantCopyExtension().") } if err != nil { t.Fatal(err) } } ================================================ FILE: config/testdata/invalid_auth.json ================================================ { "signing": { "profiles": { "CA": { "remote": "localhost", "auth_key": "garbage" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } }, "auth_keys": { "garbage": { "type":"stadardo", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } } ================================================ FILE: config/testdata/invalid_auth_bad_key.json ================================================ { "signing": { "profiles": { "CA": { "remote": "localhost", "auth_key": "garbage" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } }, "auth_keys": { "garbage": { "type":"standard", "key":"BAD_KEY" } }, "remotes": { "localhost": "127.0.0.1:8888" } } ================================================ FILE: config/testdata/invalid_config.json ================================================ { "signing": { "profiles": { "CA": { "usages": ["cert sign"], "expiry": "720h" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], } } } ================================================ FILE: config/testdata/invalid_default.json ================================================ { "signing": { "profiles": { "CA": { "usages": ["cert sign"], "expiry": "720h" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "invalid_expiry" } } } ================================================ FILE: config/testdata/invalid_no_auth_keys.json ================================================ { "signing": { "profiles": { "CA": { "remote": "localhost", "auth_key": "garbage" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } }, "auth_keys": { }, "remotes": { "localhost": "127.0.0.1:8888" } } ================================================ FILE: config/testdata/invalid_no_remotes.json ================================================ { "signing": { "profiles": { "CA": { "auth_key": "garbage", "remote": "localhoster" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } }, "auth_keys": { "garbage": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } } } ================================================ FILE: config/testdata/invalid_profile.json ================================================ { "signing": { "profiles": { "CA": { "usages": ["cert sign"], "expiry": "720h" }, "email": { "usages": ["s/mime"], "expiry": "invalid_expiry" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } } } ================================================ FILE: config/testdata/invalid_remotes.json ================================================ { "signing": { "profiles": { "CA": { "auth_key": "garbage", "remote": "localhoster" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } }, "auth_keys": { "garbage": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } } ================================================ FILE: config/testdata/invalid_usage.json ================================================ { "signing": { "profiles": { "CA": { "usages": ["cert sign"], "expiry": "720h" }, "email": { "usages": ["BAD_USAGE"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } } } ================================================ FILE: config/testdata/valid_config.json ================================================ { "signing": { "profiles": { "CA": { "usages": ["cert sign"], "expiry": "720h" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } }, "auth_key": { "garbage": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } } } ================================================ FILE: config/testdata/valid_config_auth.json ================================================ { "signing": { "profiles": { "CA": { "usages": ["cert sign"], "expiry": "720h", "auth_key": "garbage", "remote": "localhost" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } }, "auth_keys": { "garbage": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } } ================================================ FILE: config/testdata/valid_config_auth_no_default.json ================================================ { "signing": { "profiles": { "CA": { "auth_key": "garbage", "remote": "localhost" } } }, "auth_keys": { "garbage": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } } ================================================ FILE: config/testdata/valid_config_no_default.json ================================================ { "signing": { "profiles": { "CA": { "usages": ["cert sign"], "expiry": "720h" }, "email": { "usages": ["s/mime"], "expiry": "720h" } } } } ================================================ FILE: crl/crl.go ================================================ // Package crl exposes Certificate Revocation List generation functionality package crl import ( "crypto" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "math/big" "os" "strconv" "strings" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" ) // NewCRLFromFile takes in a list of serial numbers, one per line, as well as the issuing certificate // of the CRL, and the private key. This function is then used to parse the list and generate a CRL func NewCRLFromFile(serialList, issuerFile, keyFile []byte, expiryTime string) ([]byte, error) { var revokedCerts []pkix.RevokedCertificate var oneWeek = time.Duration(604800) * time.Second expiryInt, err := strconv.ParseInt(expiryTime, 0, 32) if err != nil { return nil, err } newDurationFromInt := time.Duration(expiryInt) * time.Second newExpiryTime := time.Now().Add(newDurationFromInt) if expiryInt == 0 { newExpiryTime = time.Now().Add(oneWeek) } // Parse the PEM encoded certificate issuerCert, err := helpers.ParseCertificatePEM(issuerFile) if err != nil { return nil, err } // Split input file by new lines individualCerts := strings.Split(string(serialList), "\n") // For every new line, create a new revokedCertificate and add it to slice for _, value := range individualCerts { if len(strings.TrimSpace(value)) == 0 { continue } tempBigInt := new(big.Int) tempBigInt.SetString(value, 10) tempCert := pkix.RevokedCertificate{ SerialNumber: tempBigInt, RevocationTime: time.Now(), } revokedCerts = append(revokedCerts, tempCert) } strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD") password := []byte(strPassword) if strPassword == "" { password = nil } // Parse the key given key, err := helpers.ParsePrivateKeyPEMWithPassword(keyFile, password) if err != nil { log.Debugf("Malformed private key %v", err) return nil, err } return CreateGenericCRL(revokedCerts, key, issuerCert, newExpiryTime) } // NewCRLFromDB takes in a list of CertificateRecords, as well as the issuing certificate // of the CRL, and the private key. This function is then used to parse the records and generate a CRL func NewCRLFromDB(certs []certdb.CertificateRecord, issuerCert *x509.Certificate, key crypto.Signer, expiryTime time.Duration) ([]byte, error) { var revokedCerts []pkix.RevokedCertificate newExpiryTime := time.Now().Add(expiryTime) // For every record, create a new revokedCertificate and add it to slice for _, certRecord := range certs { serialInt := new(big.Int) serialInt.SetString(certRecord.Serial, 10) tempCert := pkix.RevokedCertificate{ SerialNumber: serialInt, RevocationTime: certRecord.RevokedAt, } revokedCerts = append(revokedCerts, tempCert) } return CreateGenericCRL(revokedCerts, key, issuerCert, newExpiryTime) } // CreateGenericCRL is a helper function that takes in all of the information above, and then calls the createCRL // function. This outputs the bytes of the created CRL. func CreateGenericCRL(certList []pkix.RevokedCertificate, key crypto.Signer, issuingCert *x509.Certificate, expiryTime time.Time) ([]byte, error) { crlBytes, err := issuingCert.CreateCRL(rand.Reader, key, certList, time.Now(), expiryTime) if err != nil { log.Debugf("error creating CRL: %s", err) } return crlBytes, err } ================================================ FILE: crl/crl_test.go ================================================ package crl import ( "crypto/x509" "os" "testing" ) const ( serverCertFile = "testdata/ca.pem" serverKeyFile = "testdata/ca-key.pem" tryTwoCert = "testdata/caTwo.pem" tryTwoKey = "testdata/ca-keyTwo.pem" serialList = "testdata/serialList" ) func TestNewCRLFromFile(t *testing.T) { tryTwoKeyBytes, err := os.ReadFile(tryTwoKey) if err != nil { t.Fatal(err) } tryTwoCertBytes, err := os.ReadFile(tryTwoCert) if err != nil { t.Fatal(err) } serialListBytes, err := os.ReadFile(serialList) if err != nil { t.Fatal(err) } crl, err := NewCRLFromFile(serialListBytes, tryTwoCertBytes, tryTwoKeyBytes, "0") if err != nil { t.Fatal(err) } certList, err := x509.ParseDERCRL(crl) if err != nil { t.Fatal(err) } numCerts := len(certList.TBSCertList.RevokedCertificates) expectedNum := 4 if expectedNum != numCerts { t.Fatal("Wrong number of expired certificates") } } func TestNewCRLFromFileWithoutRevocations(t *testing.T) { tryTwoKeyBytes, err := os.ReadFile(tryTwoKey) if err != nil { t.Fatal(err) } tryTwoCertBytes, err := os.ReadFile(tryTwoCert) if err != nil { t.Fatal(err) } crl, err := NewCRLFromFile([]byte("\n \n"), tryTwoCertBytes, tryTwoKeyBytes, "0") if err != nil { t.Fatal(err) } certList, err := x509.ParseDERCRL(crl) if err != nil { t.Fatal(err) } numCerts := len(certList.TBSCertList.RevokedCertificates) expectedNum := 0 if expectedNum != numCerts { t.Fatal("Wrong number of expired certificates") } } ================================================ FILE: crl/testdata/ca-key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0 fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/ EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V -----END RSA PRIVATE KEY----- ================================================ FILE: crl/testdata/ca-keyTwo.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEA3VWwbwHztFoVqQOZfyRtHs97tUfrdaurLs9p4KeD8VqsJ95h pQohNpiKgKQf1Sm3XeQPlQqA7FuI0kBefUwEjK8bMI/6I78CTLQZr7nHsKsJ8sg3 Qd+U82MukQIe+ssvLw4uSRfMCZ+DP6XYgdqyGYEvXd3o8oM0IlkIdRe1GXZpRZiT UrZy7N45e3HY/boBRIYqQFvpRh5LfLp5prQDB4124dwcc8OQTZBVWKED1aYO1292 wgmbgVwnOOfLSkqWZVZM/Vq999vGG+TE9NTX4v+/3TO0TKV3Ofn/WVgi7YmvmEbC U9diYbmg025glIU1ZY5ifsEOl817pvLC0YW6cQIDAQABAoIBACVeh1hmsvfbUdbk ZbEivE28aD2WM/n9DvzrRgwJHGzOi0x77m6IBE2Mea34h+tcjLoMfFkEmfnOBo7B EXMEN6xtECEl3ezVHhVHPyL9MerxJc/Y4AN+NU7WixEuk35yebfvI/9xRiDFzsob PS/HddR6jD3D7sWrQ00dTSE/7HKsy+SGS9AjfMJtdKYY16KNXaf/TJQesdJCfQQt ihCc3DRm3bhmCk8jtNKYVF3u6/lIAIRJIb5EMWajlPdMocKKaHQkXmFu1onNHc2G c7QHVnQe5a20UnruEaO+W/Nswyi5ml7tN6GPZf7jcfQW5eZwYAb3ey723Iu+WqO1 Ixp/q9UCgYEA+jasIKG6UT2JIa/caHjuauSEm4u05iJFdwrbAYHPAvrfdcMwgD/v CfuTGY3vTLCYTAJyFkXrKRi6KvTsKEUC9vRypgEou2cp0Kqt87smbanVVAy0HTYG W4/Ezfu1IaW1+AxvEirAXv12ZrZMrht9aaszw8AS2G009Rw3zKl8/BMCgYEA4nQL +X6uJHaTJFhmu+7ZycBwIl+HVyXgNDB6SjcyZPZ3rZ2ldnaliUw/eQzDlByzxEKA KgNxZbATwRwJTw5YX5iSVxnfsVfPyk1HK05LZ58YSYNRDzRocpdaGhKi7A23AMJu Dy9tsOe2E+1QG7Xw8yTQbNpxVDTBPG+S5POc9+sCgYEAvpP35N7qJ8jD80mcimJZ zkcCDeuKPKMr37EAAJTblPx6SZsDDRwlOKhKcXNfKj1zsqlGNlrI88NmwSNN4Jo3 2Nt1m6VUXfEEs2/dEMCiU3LBDsSiR4GHtCO8Fdw7KUarZCQsUV0IqxFJJpCBtTcw /dQtmFJqyDfd1zfH9HW/wcsCgYEArsWJiGEw3Yt2PJLNlzXceE1BPgYkWiotQ5o2 h5jaF/nwm9oTnb4sPC7QvggP2fvc8hew+rv1hNnEJUISHSWhJwaFyxt4/VIcWLIT v2SJ5ctv3yyuHuH/ypDtRTok67IaD0f/0VB1hBcQ+4goT3q4H6/F/H0LAkZE7PPf lzw9ZUkCgYEA+T21RPB7YHkMUsQg2UvvcshIQ2yDq0IdEc/NAsNVl0HjgP8hb+gk mvEC7mm9BuCMHj9fbxONINbj7KvN6MOZ1ZrH3HdIqMP8dtB3AacIyWESQmjGBLIR pKEnFu1TxE0P6SCnKgKDUlc4yFUak4pM98PlezwtLzLeHeif2LqDT00= -----END RSA PRIVATE KEY----- ================================================ FILE: crl/testdata/ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIB5DCCAZCgAwIBAgIBATALBgkqhkiG9w0BAQUwLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UE AxMQdGVzdC5leGFtcGxlLmNvbTAeFw03MDAxMDEwMDE2NDBaFw03MDAxMDIwMzQ2NDBaMC0xEDAO BgNVBAoTB0FjbWUgQ28xGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wWjALBgkqhkiG9w0BAQED SwAwSAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0fd7Ai2KW5ToIwzFo fvJcS/STa6HA5gQenRUCAwEAAaOBnjCBmzAOBgNVHQ8BAf8EBAMCAAQwDwYDVR0TAQH/BAUwAwEB /zANBgNVHQ4EBgQEAQIDBDAPBgNVHSMECDAGgAQBAgMEMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBs ZS5jb20wDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAhoB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4 YW1wbGUuY29tMAsGCSqGSIb3DQEBBQNBAHKZKoS1wEQOGhgklx4+/yFYQlnqwKXvar/ZecQvJwui 0seMQnwBhwdBkHfVIU2Fu5VUMRyxlf0ZNaDXcpU581k= -----END CERTIFICATE----- ================================================ FILE: crl/testdata/caTwo.pem ================================================ -----BEGIN CERTIFICATE----- MIID4jCCAsqgAwIBAgIIMijYd8KfFrswDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE BhMCVVMxFTATBgNVBAoTDFRlc3QgQ29tcGFueTEUMBIGA1UECxMLSVQgU2Vydmlj ZXMxFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWEx FDASBgNVBAMTC3Rlc3RMb2NhbENBMB4XDTE1MTAwODIzMjYwMFoXDTIwMTAwNjIz MjYwMFowfTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDFRlc3QgQ29tcGFueTEUMBIG A1UECxMLSVQgU2VydmljZXMxFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNV BAgTCkNhbGlmb3JuaWExFDASBgNVBAMTC3Rlc3RMb2NhbENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3VWwbwHztFoVqQOZfyRtHs97tUfrdaurLs9p 4KeD8VqsJ95hpQohNpiKgKQf1Sm3XeQPlQqA7FuI0kBefUwEjK8bMI/6I78CTLQZ r7nHsKsJ8sg3Qd+U82MukQIe+ssvLw4uSRfMCZ+DP6XYgdqyGYEvXd3o8oM0IlkI dRe1GXZpRZiTUrZy7N45e3HY/boBRIYqQFvpRh5LfLp5prQDB4124dwcc8OQTZBV WKED1aYO1292wgmbgVwnOOfLSkqWZVZM/Vq999vGG+TE9NTX4v+/3TO0TKV3Ofn/ WVgi7YmvmEbCU9diYbmg025glIU1ZY5ifsEOl817pvLC0YW6cQIDAQABo2YwZDAO BgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQU6jzK 7+HcNGKm+TONgxyrYy/02qEwHwYDVR0jBBgwFoAU6jzK7+HcNGKm+TONgxyrYy/0 2qEwDQYJKoZIhvcNAQELBQADggEBAHG0ufzYb4/JTseE/0zuCU2efM1HbSqxcYb0 Q275In83m9SqxjwGB5kPx1Mp16j8Gapb5s0U9jFwCoI26uvNsEHkyYSdpq73Wi7+ 3oY3PdqWj7vL1jHxFZ73TCLoPXWppWIBardTkN9xOagDyc5VmUGhAWC3EubVo0GE Ty14AlfKXOxx+cDR62lXRdiF3Pzywfy3pL4hMgPxNyIMbULHWbU8JpGzIqAyiBsg SFT1labSuCciHL7R7YM2eA9MculAiWPtKbRpY1xKDCD4kgRrb5YzPoujSn6AqFNi RAxvQNcf2ahMcbof4rbuUHsOXzWWbwckA1Tv492T3FvtKzbFJbA= -----END CERTIFICATE----- ================================================ FILE: crl/testdata/cert.pem ================================================ -----BEGIN CERTIFICATE----- MIID4TCCAsugAwIBAgIIEoDcqfKl/s4wCwYJKoZIhvcNAQELMG0xCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMB4XDTE1MDQxOTE2MTkwMFoXDTE2MDQxODE2MTkwMFowXTELMAkGA1UEBhMC VVMxEDAOBgNVBAoTB0V4YW1wbGUxDzANBgNVBAsTBlRoaW5nczEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAK7jUnRUeD5QY9YPjbW6aiGkVWRWAebi4nZl++C+ HEBHSyB0jXX+J93y97PuhgeguCuMM6KZU7C0tPZKjwdxBSqpXeyFpvcj+UWMjZjz 9FrBAzZ1DIYquqfYuKUtavoFv29IomRqzyZ4FrMJ2qy0RudnWMTqn4P6/7DrWos+ oJMCpl/mdWl+YXMXypgW5JwM7ladx8GkEKQwGMtXrG9pop7qS6LNikN76tLPYWjR DhrWLBe8gCGjuXkwvxw78CeeJNyWF+P/+x4lVsWphip3jX57SUx/bjaRjsWSfpMz xHueHtuCrGffgCkFzYH1/Z60FZNxuHYqJeL4V3gcR8IIaZECAwEAAaOBmDCBlTAO BgNVHQ8BAf8EBAMCAKAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG A1UdEwEB/wQCMAAwHQYDVR0OBBYEFBnFrxc1gkG2CYImTYKL0DAaGxRBMB8GA1Ud IwQYMBaAFKvOM8/hjk8uyp7KnqJ12h8GOhGZMBYGA1UdEQQPMA2CC2V4YW1wbGUu Y29tMAsGCSqGSIb3DQEBCwOCAQEAX31Jk7R9gDMw/gepIxxeKx9m+c7eOYDxjJ12 bfXQVKNNPLZsO9M9r2/0BCTFsNTF2jh6ZTeIf7qy+Jw08YqTcO5m8jhiGzCjOYu5 tiGxCUe+cYjXcCRk83+XGkVrQm3fQ0cVtic0yfm/fez3iv915jH0GYO5X8/d7bKa 0kWJ3uOjur6tenfnisypEsuYYjPRcQdXSG6/qgHEc4r279Z2ltjy1bFFr86hHUbj DX7XNWH/MXFgqLzfQm5VzmqBj9om+0/tgTWdkgI1DK/Hnvm9A4YZfaxh4fxv7ITo Ce8FWW13Wj55x64peb8ZiW1jUyoaJQcxQxFpRHIVu26nXApWtg== -----END CERTIFICATE----- ================================================ FILE: crl/testdata/serialList ================================================ 1 2 3 4 ================================================ FILE: crl/testdata/server.crt ================================================ -----BEGIN CERTIFICATE----- MIICATCCAWoCCQDidF+uNJR6czANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 cyBQdHkgTHRkMB4XDTEyMDUwMTIyNTUxN1oXDTEzMDUwMTIyNTUxN1owRTELMAkG A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81 KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt +LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw== -----END CERTIFICATE----- ================================================ FILE: crl/testdata/server.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQC2mOWeh2HPfWQsQmh4tKRGau/yXt7GQa07RES0huKuP0EHLrhl dUETuSEoY7ZyczxTvKPDs21+H4i8KNlUDd3ZeodLc+Ou3geZT9wYI40Tz40Reip3 MtQM86LHWoMNEG9ezzUoBXaqHoJgdlt2qLGEN6uO8lwPg2x3uQTERl8e4QIDAQAB AoGAVxnsPojZ8X4g8LPk3d9dlXGhb/4tSmk9102jcHH/Y5ssy95Pe6ZJGr1uwbN+ 7m1l05PikpHeoxEryoW51cyfjDVkXUT0zPp2JC38DUA/0A8qWav/aENM64wg1I0P Dil8FywzZEonRNJst53+9cxFye70ely5br/tWxEp4/MsM1kCQQDqV4Lwn8BXOeKg xOwNmcL+0XPedvSPBSPUoGJCzu12rH6Z+UHXipXsqRNSyQ+KGlur14y0kCh5uiVA jmWYVEEjAkEAx3keAo1nFsVW35EPt5LIbh6L6ty7GrvGRvOVeSd6YLtixMety24k hpt1cEv2xlFnbjbBbMkr9eUiUNpttLT6KwJBANGKaLoSjqEwUFYjX1OV/wdtcGcn BOzx0qUouFQ2xZ0NBrNVbyt1bzPLx0yKHkwF35ybw+Qc1yRpby/3ZB6+j/MCQFLl vtcItOL9uBDJVGLSGYHKKBO/D/MYPlqWOHRVN8KjnXRyF4QHjh5y1OeKalAY3Ict Mk1nfWF/jDdVz2neHGkCQHHBR4Xt1/euDku+14z5aLpphTEQVuRD2vQoeKi/W/CY OgNmKj1DzucnCS6yRCrF8Q0Pn8l054a3Wdbl1gqI/gA= -----END RSA PRIVATE KEY----- ================================================ FILE: crypto/doc.go ================================================ // Package crypto contains implementations of crypto.Signer. package crypto ================================================ FILE: crypto/pkcs7/pkcs7.go ================================================ // Package pkcs7 implements the subset of the CMS PKCS #7 datatype that is typically // used to package certificates and CRLs. Using openssl, every certificate converted // to PKCS #7 format from another encoding such as PEM conforms to this implementation. // reference: https://www.openssl.org/docs/man1.1.0/apps/crl2pkcs7.html // // PKCS #7 Data type, reference: https://tools.ietf.org/html/rfc2315 // // The full pkcs#7 cryptographic message syntax allows for cryptographic enhancements, // for example data can be encrypted and signed and then packaged through pkcs#7 to be // sent over a network and then verified and decrypted. It is asn1, and the type of // PKCS #7 ContentInfo, which comprises the PKCS #7 structure, is: // // ContentInfo ::= SEQUENCE { // contentType ContentType, // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL // } // // There are 6 possible ContentTypes, data, signedData, envelopedData, // signedAndEnvelopedData, digestedData, and encryptedData. Here signedData, Data, and encrypted // Data are implemented, as the degenerate case of signedData without a signature is the typical // format for transferring certificates and CRLS, and Data and encryptedData are used in PKCS #12 // formats. // The ContentType signedData has the form: // // signedData ::= SEQUENCE { // version Version, // digestAlgorithms DigestAlgorithmIdentifiers, // contentInfo ContentInfo, // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, // signerInfos SignerInfos // } // // As of yet signerInfos and digestAlgorithms are not parsed, as they are not relevant to // this system's use of PKCS #7 data. Version is an integer type, note that PKCS #7 is // recursive, this second layer of ContentInfo is similar ignored for our degenerate // usage. The ExtendedCertificatesAndCertificates type consists of a sequence of choices // between PKCS #6 extended certificates and x509 certificates. Any sequence consisting // of any number of extended certificates is not yet supported in this implementation. // // The ContentType Data is simply a raw octet string and is parsed directly into a Go []byte slice. // // The ContentType encryptedData is the most complicated and its form can be gathered by // the go type below. It essentially contains a raw octet string of encrypted data and an // algorithm identifier for use in decrypting this data. package pkcs7 import ( "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" cferr "github.com/cloudflare/cfssl/errors" ) // Types used for asn1 Unmarshaling. type signedData struct { Version int DigestAlgorithms asn1.RawValue ContentInfo asn1.RawValue Certificates asn1.RawValue `asn1:"optional" asn1:"tag:0"` Crls asn1.RawValue `asn1:"optional"` SignerInfos asn1.RawValue } type initPKCS7 struct { Raw asn1.RawContent ContentType asn1.ObjectIdentifier Content asn1.RawValue `asn1:"tag:0,explicit,optional"` } // Object identifier strings of the three implemented PKCS7 types. const ( ObjIDData = "1.2.840.113549.1.7.1" ObjIDSignedData = "1.2.840.113549.1.7.2" ObjIDEncryptedData = "1.2.840.113549.1.7.6" ) // PKCS7 represents the ASN1 PKCS #7 Content type. It contains one of three // possible types of Content objects, as denoted by the object identifier in // the ContentInfo field, the other two being nil. SignedData // is the degenerate SignedData Content info without signature used // to hold certificates and crls. Data is raw bytes, and EncryptedData // is as defined in PKCS #7 standard. type PKCS7 struct { Raw asn1.RawContent ContentInfo string Content Content } // Content implements three of the six possible PKCS7 data types. Only one is non-nil. type Content struct { Data []byte SignedData SignedData EncryptedData EncryptedData } // SignedData defines the typical carrier of certificates and crls. type SignedData struct { Raw asn1.RawContent Version int Certificates []*x509.Certificate Crl *pkix.CertificateList } // Data contains raw bytes. Used as a subtype in PKCS12. type Data struct { Bytes []byte } // EncryptedData contains encrypted data. Used as a subtype in PKCS12. type EncryptedData struct { Raw asn1.RawContent Version int EncryptedContentInfo EncryptedContentInfo } // EncryptedContentInfo is a subtype of PKCS7EncryptedData. type EncryptedContentInfo struct { Raw asn1.RawContent ContentType asn1.ObjectIdentifier ContentEncryptionAlgorithm pkix.AlgorithmIdentifier EncryptedContent []byte `asn1:"tag:0,optional"` } // ParsePKCS7 attempts to parse the DER encoded bytes of a // PKCS7 structure. func ParsePKCS7(raw []byte) (msg *PKCS7, err error) { var pkcs7 initPKCS7 _, err = asn1.Unmarshal(raw, &pkcs7) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } msg = new(PKCS7) msg.Raw = pkcs7.Raw msg.ContentInfo = pkcs7.ContentType.String() switch { case msg.ContentInfo == ObjIDData: msg.ContentInfo = "Data" _, err = asn1.Unmarshal(pkcs7.Content.Bytes, &msg.Content.Data) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } case msg.ContentInfo == ObjIDSignedData: msg.ContentInfo = "SignedData" var signedData signedData _, err = asn1.Unmarshal(pkcs7.Content.Bytes, &signedData) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } if len(signedData.Certificates.Bytes) != 0 { msg.Content.SignedData.Certificates, err = x509.ParseCertificates(signedData.Certificates.Bytes) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } } if len(signedData.Crls.Bytes) != 0 { msg.Content.SignedData.Crl, err = x509.ParseDERCRL(signedData.Crls.Bytes) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } } msg.Content.SignedData.Version = signedData.Version msg.Content.SignedData.Raw = pkcs7.Content.Bytes case msg.ContentInfo == ObjIDEncryptedData: msg.ContentInfo = "EncryptedData" var encryptedData EncryptedData _, err = asn1.Unmarshal(pkcs7.Content.Bytes, &encryptedData) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } if encryptedData.Version != 0 { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Only support for PKCS #7 encryptedData version 0")) } msg.Content.EncryptedData = encryptedData default: return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Attempt to parse PKCS# 7 Content not of type data, signed data or encrypted data")) } return msg, nil } ================================================ FILE: csr/csr.go ================================================ // Package csr implements certificate requests for CFSSL. package csr import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/pem" "errors" "fmt" "io" "net" "net/mail" "net/url" "strconv" "strings" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/helpers/derhelpers" "github.com/cloudflare/cfssl/log" ) const ( curveP256 = 256 curveP384 = 384 curveP521 = 521 ) // A Name contains the SubjectInfo fields. type Name struct { C string `json:"C,omitempty" yaml:"C,omitempty"` // Country ST string `json:"ST,omitempty" yaml:"ST,omitempty"` // State L string `json:"L,omitempty" yaml:"L,omitempty"` // Locality O string `json:"O,omitempty" yaml:"O,omitempty"` // OrganisationName OU string `json:"OU,omitempty" yaml:"OU,omitempty"` // OrganisationalUnitName E string `json:"E,omitempty" yaml:"E,omitempty"` SerialNumber string `json:"SerialNumber,omitempty" yaml:"SerialNumber,omitempty"` OID map[string]string `json:"OID,omitempty", yaml:"OID,omitempty"` } // A KeyRequest contains the algorithm and key size for a new private key. type KeyRequest struct { A string `json:"algo" yaml:"algo"` S int `json:"size" yaml:"size"` } // NewKeyRequest returns a default KeyRequest. func NewKeyRequest() *KeyRequest { return &KeyRequest{"ecdsa", curveP256} } // Algo returns the requested key algorithm represented as a string. func (kr *KeyRequest) Algo() string { return kr.A } // Size returns the requested key size. func (kr *KeyRequest) Size() int { return kr.S } // Generate generates a key as specified in the request. Currently, // only ECDSA, RSA and ed25519 algorithms are supported. func (kr *KeyRequest) Generate() (crypto.PrivateKey, error) { log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo(), kr.Size()) switch kr.Algo() { case "rsa": if kr.Size() < 2048 { return nil, errors.New("RSA key is too weak") } if kr.Size() > 8192 { return nil, errors.New("RSA key size too large") } return rsa.GenerateKey(rand.Reader, kr.Size()) case "ecdsa": var curve elliptic.Curve switch kr.Size() { case curveP256: curve = elliptic.P256() case curveP384: curve = elliptic.P384() case curveP521: curve = elliptic.P521() default: return nil, errors.New("invalid curve") } return ecdsa.GenerateKey(curve, rand.Reader) case "ed25519": seed := make([]byte, ed25519.SeedSize) if _, err := io.ReadFull(rand.Reader, seed); err != nil { return nil, err } return ed25519.NewKeyFromSeed(seed), nil default: return nil, errors.New("invalid algorithm") } } // SigAlgo returns an appropriate X.509 signature algorithm given the // key request's type and size. func (kr *KeyRequest) SigAlgo() x509.SignatureAlgorithm { switch kr.Algo() { case "rsa": switch { case kr.Size() >= 4096: return x509.SHA512WithRSA case kr.Size() >= 3072: return x509.SHA384WithRSA case kr.Size() >= 2048: return x509.SHA256WithRSA default: return x509.SHA1WithRSA } case "ecdsa": switch kr.Size() { case curveP521: return x509.ECDSAWithSHA512 case curveP384: return x509.ECDSAWithSHA384 case curveP256: return x509.ECDSAWithSHA256 default: return x509.ECDSAWithSHA1 } case "ed25519": return x509.PureEd25519 default: return x509.UnknownSignatureAlgorithm } } // CAConfig is a section used in the requests initialising a new CA. type CAConfig struct { PathLength int `json:"pathlen" yaml:"pathlen"` PathLenZero bool `json:"pathlenzero" yaml:"pathlenzero"` Expiry string `json:"expiry" yaml:"expiry"` Backdate string `json:"backdate" yaml:"backdate"` } // A CertificateRequest encapsulates the API interface to the // certificate request functionality. type CertificateRequest struct { CN string `json:"CN" yaml:"CN"` Names []Name `json:"names" yaml:"names"` Hosts []string `json:"hosts" yaml:"hosts"` KeyRequest *KeyRequest `json:"key,omitempty" yaml:"key,omitempty"` CA *CAConfig `json:"ca,omitempty" yaml:"ca,omitempty"` SerialNumber string `json:"serialnumber,omitempty" yaml:"serialnumber,omitempty"` DelegationEnabled bool `json:"delegation_enabled,omitempty" yaml:"delegation_enabled,omitempty"` Extensions []pkix.Extension `json:"extensions,omitempty" yaml:"extensions,omitempty"` CRL string `json:"crl_url,omitempty" yaml:"crl_url,omitempty"` } // New returns a new, empty CertificateRequest with a // KeyRequest. func New() *CertificateRequest { return &CertificateRequest{ KeyRequest: NewKeyRequest(), } } // appendIf appends to a if s is not an empty string. func appendIf(s string, a *[]string) { if s != "" { *a = append(*a, s) } } // OIDFromString creates an ASN1 ObjectIdentifier from its string representation func OIDFromString(s string) (asn1.ObjectIdentifier, error) { var oid []int parts := strings.Split(s, ".") if len(parts) < 1 { return oid, fmt.Errorf("invalid OID string: %s", s) } for _, p := range parts { i, err := strconv.Atoi(p) if err != nil { return nil, fmt.Errorf("invalid OID part %s", p) } oid = append(oid, i) } return oid, nil } // Name returns the PKIX name for the request. func (cr *CertificateRequest) Name() (pkix.Name, error) { var name pkix.Name name.CommonName = cr.CN for _, n := range cr.Names { appendIf(n.C, &name.Country) appendIf(n.ST, &name.Province) appendIf(n.L, &name.Locality) appendIf(n.O, &name.Organization) appendIf(n.OU, &name.OrganizationalUnit) for k, v := range n.OID { oid, err := OIDFromString(k) if err != nil { return name, err } name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: oid, Value: v}) } if n.E != "" { name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: n.E}) } } name.SerialNumber = cr.SerialNumber return name, nil } // BasicConstraints CSR information RFC 5280, 4.2.1.9 type BasicConstraints struct { IsCA bool `asn1:"optional"` MaxPathLen int `asn1:"optional,default:-1"` } // ParseRequest takes a certificate request and generates a key and // CSR from it. It does no validation -- caveat emptor. It will, // however, fail if the key request is not valid (i.e., an unsupported // curve or RSA key size). The lack of validation was specifically // chosen to allow the end user to define a policy and validate the // request appropriately before calling this function. func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) { log.Info("received CSR") if req.KeyRequest == nil { req.KeyRequest = NewKeyRequest() } log.Infof("generating key: %s-%d", req.KeyRequest.Algo(), req.KeyRequest.Size()) priv, err := req.KeyRequest.Generate() if err != nil { err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err) return } switch priv := priv.(type) { case *rsa.PrivateKey: key = x509.MarshalPKCS1PrivateKey(priv) block := pem.Block{ Type: "RSA PRIVATE KEY", Bytes: key, } key = pem.EncodeToMemory(&block) case *ecdsa.PrivateKey: key, err = x509.MarshalECPrivateKey(priv) if err != nil { err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err) return } block := pem.Block{ Type: "EC PRIVATE KEY", Bytes: key, } key = pem.EncodeToMemory(&block) case ed25519.PrivateKey: key, err = derhelpers.MarshalEd25519PrivateKey(priv) if err != nil { err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err) return } block := pem.Block{ Type: "Ed25519 PRIVATE KEY", Bytes: key, } key = pem.EncodeToMemory(&block) default: panic("Generate should have failed to produce a valid key.") } csr, err = Generate(priv.(crypto.Signer), req) if err != nil { log.Errorf("failed to generate a CSR: %v", err) err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err) } return } // ExtractCertificateRequest extracts a CertificateRequest from // x509.Certificate. It is aimed to used for generating a new certificate // from an existing certificate. For a root certificate, the CA expiry // length is calculated as the duration between cert.NotAfter and cert.NotBefore. func ExtractCertificateRequest(cert *x509.Certificate) *CertificateRequest { req := New() req.CN = cert.Subject.CommonName req.Names = getNames(cert.Subject) req.Hosts = getHosts(cert) req.SerialNumber = cert.Subject.SerialNumber if cert.IsCA { req.CA = new(CAConfig) // CA expiry length is calculated based on the input cert // issue date and expiry date. req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String() req.CA.PathLength = cert.MaxPathLen req.CA.PathLenZero = cert.MaxPathLenZero } return req } func getHosts(cert *x509.Certificate) []string { var hosts []string for _, ip := range cert.IPAddresses { hosts = append(hosts, ip.String()) } hosts = append(hosts, cert.DNSNames...) hosts = append(hosts, cert.EmailAddresses...) for _, uri := range cert.URIs { hosts = append(hosts, uri.String()) } return hosts } // getNames returns an array of Names from the certificate // It only cares about Country, Organization, OrganizationalUnit, Locality, Province func getNames(sub pkix.Name) []Name { // anonymous func for finding the max of a list of integer max := func(v1 int, vn ...int) (max int) { max = v1 for i := 0; i < len(vn); i++ { if vn[i] > max { max = vn[i] } } return max } nc := len(sub.Country) norg := len(sub.Organization) nou := len(sub.OrganizationalUnit) nl := len(sub.Locality) np := len(sub.Province) n := max(nc, norg, nou, nl, np) names := make([]Name, n) for i := range names { if i < nc { names[i].C = sub.Country[i] } if i < norg { names[i].O = sub.Organization[i] } if i < nou { names[i].OU = sub.OrganizationalUnit[i] } if i < nl { names[i].L = sub.Locality[i] } if i < np { names[i].ST = sub.Province[i] } } return names } // A Generator is responsible for validating certificate requests. type Generator struct { Validator func(*CertificateRequest) error } // ProcessRequest validates and processes the incoming request. It is // a wrapper around a validator and the ParseRequest function. func (g *Generator) ProcessRequest(req *CertificateRequest) (csr, key []byte, err error) { log.Info("generate received request") err = g.Validator(req) if err != nil { log.Warningf("invalid request: %v", err) return nil, nil, err } csr, key, err = ParseRequest(req) if err != nil { return nil, nil, err } return } // IsNameEmpty returns true if the name has no identifying information in it. func IsNameEmpty(n Name) bool { empty := func(s string) bool { return strings.TrimSpace(s) == "" } if empty(n.C) && empty(n.ST) && empty(n.L) && empty(n.O) && empty(n.OU) { return true } return false } // Regenerate uses the provided CSR as a template for signing a new // CSR using priv. func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) { req, extra, err := helpers.ParseCSR(csr) if err != nil { return nil, err } else if len(extra) > 0 { return nil, errors.New("csr: trailing data in certificate request") } return x509.CreateCertificateRequest(rand.Reader, req, priv) } // GenerateDER creates a new CSR(ASN1 DER encoded) from a CertificateRequest structure and // an existing key. The KeyRequest field is ignored. func GenerateDER(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) { sigAlgo := helpers.SignerAlgo(priv) if sigAlgo == x509.UnknownSignatureAlgorithm { return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable) } subj, err := req.Name() if err != nil { return nil, err } var tpl = x509.CertificateRequest{ Subject: subj, SignatureAlgorithm: sigAlgo, } for i := range req.Hosts { if ip := net.ParseIP(req.Hosts[i]); ip != nil { tpl.IPAddresses = append(tpl.IPAddresses, ip) } else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil { tpl.EmailAddresses = append(tpl.EmailAddresses, email.Address) } else if uri, err := url.ParseRequestURI(req.Hosts[i]); err == nil && uri != nil { tpl.URIs = append(tpl.URIs, uri) } else { tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i]) } } tpl.ExtraExtensions = []pkix.Extension{} if req.CA != nil { err = appendCAInfoToCSR(req.CA, &tpl) if err != nil { err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err) return } } if req.DelegationEnabled { tpl.ExtraExtensions = append(tpl.Extensions, helpers.DelegationExtension) } if req.Extensions != nil { err = appendExtensionsToCSR(req.Extensions, &tpl) if err != nil { err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err) return } } csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv) if err != nil { log.Errorf("failed to generate a CSR: %v", err) err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err) return } return } // Generate creates a new CSR(PEM encoded) from a CertificateRequest structure and // an existing key. The KeyRequest field is ignored. func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) { csr, err = GenerateDER(priv, req) if err != nil { return } block := pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: csr, } log.Info("encoded CSR") csr = pem.EncodeToMemory(&block) return } // appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error { pathlen := reqConf.PathLength if pathlen == 0 && !reqConf.PathLenZero { pathlen = -1 } val, err := asn1.Marshal(BasicConstraints{true, pathlen}) if err != nil { return err } csr.ExtraExtensions = append(csr.ExtraExtensions, pkix.Extension{ Id: asn1.ObjectIdentifier{2, 5, 29, 19}, Value: val, Critical: true, }) return nil } // appendCAInfoToCSR appends user-defined extension to a CSR func appendExtensionsToCSR(extensions []pkix.Extension, csr *x509.CertificateRequest) error { csr.ExtraExtensions = append(csr.ExtraExtensions, extensions...) return nil } ================================================ FILE: csr/csr_test.go ================================================ package csr import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/pem" "os" "testing" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" ) // TestNew validate the CertificateRequest created to return with a KeyRequest // in KeyRequest field func TestNew(t *testing.T) { if cr := New(); cr.KeyRequest == nil { t.Fatalf("Should create a new, empty certificate request with KeyRequest") } } // TestKeyRequest ensures that key generation returns the same type of // key specified in the KeyRequest. func TestKeyRequest(t *testing.T) { kr := NewKeyRequest() priv, err := kr.Generate() if err != nil { t.Fatalf("%v", err) } switch priv.(type) { case *rsa.PrivateKey: if kr.Algo() != "rsa" { t.Fatal("RSA key generated, but expected", kr.Algo()) } case *ecdsa.PrivateKey: if kr.Algo() != "ecdsa" { t.Fatal("ECDSA key generated, but expected", kr.Algo()) } case ed25519.PrivateKey: if kr.Algo() != "ed25519" { t.Fatal("Ed25519 key generated, but expected", kr.Algo()) } } } // TestPKIXName validates building a pkix.Name structure from a // CertificateRequest. func TestPKIXName(t *testing.T) { var cr = &CertificateRequest{ CN: "Test Common Name", Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare, Inc.", OU: "Systems Engineering", }, { C: "GB", ST: "London", L: "London", O: "CloudFlare, Inc", OU: "Systems Engineering", }, }, Hosts: []string{"cloudflare.com", "www.cloudflare.com"}, KeyRequest: NewKeyRequest(), } name, err := cr.Name() if err != nil { t.Fatalf("Error getting name: %s", err.Error()) } if len(name.Country) != 2 { t.Fatal("Expected two countries in SubjInfo.") } else if len(name.Province) != 2 { t.Fatal("Expected two states in SubjInfo.") } else if len(name.Locality) != 2 { t.Fatal("Expected two localities in SubjInfo.") } else if len(name.Country) != 2 { t.Fatal("Expected two countries in SubjInfo.") } else if len(name.Organization) != 2 { t.Fatal("Expected two organization in SubjInfo.") } else if len(name.OrganizationalUnit) != 2 { t.Fatal("Expected two organizational units in SubjInfo.") } } // TestParseRequest ensures that a valid certificate request does not // error. func TestParseRequest(t *testing.T) { var cr = &CertificateRequest{ CN: "Test Common Name", Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare, Inc.", OU: "Systems Engineering", }, { C: "GB", ST: "London", L: "London", O: "CloudFlare, Inc", OU: "Systems Engineering", }, }, Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com", "https://www.cloudflare.com"}, KeyRequest: NewKeyRequest(), Extensions: []pkix.Extension{ { Id: asn1.ObjectIdentifier{1, 2, 3, 4, 5}, Value: []byte("AgEB"), }, }, } csrBytes, _, err := ParseRequest(cr) if err != nil { t.Fatalf("%v", err) } block, _ := pem.Decode(csrBytes) if block == nil { t.Fatalf("%v", err) } if block.Type != "CERTIFICATE REQUEST" { t.Fatalf("Incorrect block type: %s", block.Type) } csr, err := x509.ParseCertificateRequest(block.Bytes) if err != nil { t.Fatalf("%v", err) } found := false for _, ext := range csr.Extensions { if ext.Id.Equal(asn1.ObjectIdentifier{1, 2, 3, 4, 5}) { found = true break } } if !found { t.Fatalf("CSR did not include Custom Extension") } } // TestParseRequestCA ensures that a valid CA certificate request does not // error and the resulting CSR includes the BasicConstraint extension func TestParseRequestCA(t *testing.T) { var cr = &CertificateRequest{ CN: "Test Common Name", Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare, Inc.", OU: "Systems Engineering", }, { C: "GB", ST: "London", L: "London", O: "CloudFlare, Inc", OU: "Systems Engineering", }, }, CA: &CAConfig{ PathLength: 0, PathLenZero: true, }, KeyRequest: NewKeyRequest(), } csrBytes, _, err := ParseRequest(cr) if err != nil { t.Fatalf("%v", err) } block, _ := pem.Decode(csrBytes) if block == nil { t.Fatalf("%v", err) } if block.Type != "CERTIFICATE REQUEST" { t.Fatalf("Incorrect block type: %s", block.Type) } csr, err := x509.ParseCertificateRequest(block.Bytes) if err != nil { t.Fatalf("%v", err) } found := false for _, ext := range csr.Extensions { if ext.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) { found = true break } } if !found { t.Fatalf("CSR did not include BasicConstraint Extension") } } // TestParseRequestCANoPathlen ensures that a valid CA certificate request // with an unspecified pathlen does not error and the resulting CSR includes // the BasicConstraint extension func TestParseRequestCANoPathlen(t *testing.T) { var cr = &CertificateRequest{ CN: "Test Common Name", Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare, Inc.", OU: "Systems Engineering", }, { C: "GB", ST: "London", L: "London", O: "CloudFlare, Inc", OU: "Systems Engineering", }, }, CA: &CAConfig{ PathLength: 0, PathLenZero: false, }, KeyRequest: NewKeyRequest(), } csrBytes, _, err := ParseRequest(cr) if err != nil { t.Fatalf("%v", err) } block, _ := pem.Decode(csrBytes) if block == nil { t.Fatalf("%v", err) } if block.Type != "CERTIFICATE REQUEST" { t.Fatalf("Incorrect block type: %s", block.Type) } csr, err := x509.ParseCertificateRequest(block.Bytes) if err != nil { t.Fatalf("%v", err) } found := false for _, ext := range csr.Extensions { if ext.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) { bc := &BasicConstraints{} asn1.Unmarshal(ext.Value, bc) if bc.IsCA == true && bc.MaxPathLen == -1 { found = true break } } } if !found { t.Fatalf("CSR did not include BasicConstraint Extension") } } func whichCurve(sz int) elliptic.Curve { switch sz { case 256: return elliptic.P256() case 384: return elliptic.P384() case 521: return elliptic.P521() } return nil } // TestECGeneration ensures that the proper curve is used depending on // the bit size specified in a key request and that an appropriate // signature algorithm is returned. func TestECGeneration(t *testing.T) { var eckey *ecdsa.PrivateKey for _, sz := range []int{256, 384, 521} { kr := &KeyRequest{"ecdsa", sz} priv, err := kr.Generate() if err != nil { t.Fatalf("%v", err) } eckey = priv.(*ecdsa.PrivateKey) if eckey.Curve != whichCurve(sz) { t.Fatal("Generated key has wrong curve.") } if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm { t.Fatal("Invalid signature algorithm!") } } } func TestED25519Generation(t *testing.T) { kr := &KeyRequest{A: "ed25519"} priv, err := kr.Generate() if err != nil { t.Fatalf("%v", err) } _, ok := priv.(ed25519.PrivateKey) if !ok { t.Fatal("Expected ed25519 key") } if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm { t.Fatal("Invalid signature algorithm!") } } func TestRSAKeyGeneration(t *testing.T) { var rsakey *rsa.PrivateKey for _, sz := range []int{2048, 3072, 4096} { kr := &KeyRequest{"rsa", sz} priv, err := kr.Generate() if err != nil { t.Fatalf("%v", err) } rsakey = priv.(*rsa.PrivateKey) if rsakey.PublicKey.N.BitLen() != kr.Size() { t.Fatal("Generated key has wrong size.") } if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm { t.Fatal("Invalid signature algorithm!") } } } // TestBadKeyRequest ensures that generating a key from a KeyRequest // fails with an invalid algorithm, or an invalid RSA or ECDSA key // size. An invalid ECDSA key size is any size other than 256, 384, or // 521; an invalid RSA key size is any size less than 2048 bits. func TestBadKeyRequest(t *testing.T) { kr := &KeyRequest{"yolocrypto", 1024} if _, err := kr.Generate(); err == nil { t.Fatal("Key generation should fail with invalid algorithm") } else if sa := kr.SigAlgo(); sa != x509.UnknownSignatureAlgorithm { t.Fatal("The wrong signature algorithm was returned from SigAlgo!") } kr.A = "ecdsa" if _, err := kr.Generate(); err == nil { t.Fatal("Key generation should fail with invalid key size") } else if sa := kr.SigAlgo(); sa != x509.ECDSAWithSHA1 { t.Fatal("The wrong signature algorithm was returned from SigAlgo!") } kr.A = "rsa" if _, err := kr.Generate(); err == nil { t.Fatal("Key generation should fail with invalid key size") } else if sa := kr.SigAlgo(); sa != x509.SHA1WithRSA { t.Fatal("The wrong signature algorithm was returned from SigAlgo!") } kr = &KeyRequest{"tobig", 9216} kr.A = "rsa" if _, err := kr.Generate(); err == nil { t.Fatal("Key generation should fail with invalid key size") } else if sa := kr.SigAlgo(); sa != x509.SHA512WithRSA { t.Fatal("The wrong signature algorithm was returned from SigAlgo!") } } // TestDefaultKeyRequest makes sure that certificate requests without // explicit key requests fall back to the default key request. func TestDefaultKeyRequest(t *testing.T) { var req = &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com", "https://www.cloudflare.com"}, } _, priv, err := ParseRequest(req) if err != nil { t.Fatalf("%v", err) } // If the default key type changes, this will need to be changed. block, _ := pem.Decode(priv) if block == nil { t.Fatal("Bad private key was generated!") } DefaultKeyRequest := NewKeyRequest() switch block.Type { case "RSA PRIVATE KEY": if DefaultKeyRequest.Algo() != "rsa" { t.Fatal("Invalid default key request.") } case "EC PRIVATE KEY": if DefaultKeyRequest.Algo() != "ecdsa" { t.Fatal("Invalid default key request.") } case "Ed25519 PRIVATE KEY": if DefaultKeyRequest.Algo() != "ed25519" { t.Fatal("Invalid default key request.") } } } // TestRSACertRequest validates parsing a certificate request with an // RSA key. func TestRSACertRequest(t *testing.T) { var req = &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com", "https://www.cloudflare.com"}, KeyRequest: &KeyRequest{"rsa", 2048}, } _, _, err := ParseRequest(req) if err != nil { t.Fatalf("%v", err) } } // TestED25519CertRequest validates parsing a certificate request with an // ED25519 key. func TestED25519CertRequest(t *testing.T) { var req = &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com", "https://www.cloudflare.com"}, KeyRequest: &KeyRequest{A: "ed25519"}, } _, _, err := ParseRequest(req) if err != nil { t.Fatalf("%v", err) } } // TestBadCertRequest checks for failure conditions of ParseRequest. func TestBadCertRequest(t *testing.T) { var req = &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com", "www.cloudflare.com"}, KeyRequest: &KeyRequest{"yolo-crypto", 2048}, } _, _, err := ParseRequest(req) if err == nil { t.Fatal("ParseRequest should fail with a bad key algorithm.") } } // testValidator is a stripped-down validator that checks to make sure // the request has a common name. It should mimic some of the // functionality expected in an actual validator. func testValidator(req *CertificateRequest) error { if req.CN == "" { return errors.NewBadRequestMissingParameter("CN") } return nil } // TestGenerator ensures that a valid request is processed properly // and returns a certificate request and key. func TestGenerator(t *testing.T) { g := &Generator{testValidator} var req = &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com", "https://www.cloudflare.com"}, KeyRequest: &KeyRequest{"rsa", 2048}, } csrBytes, _, err := g.ProcessRequest(req) if err != nil { t.Fatal(err) } block, _ := pem.Decode([]byte(csrBytes)) if block == nil { t.Fatalf("bad CSR in PEM") } if block.Type != "CERTIFICATE REQUEST" { t.Fatalf("bad CSR in PEM") } csr, err := x509.ParseCertificateRequest(block.Bytes) if err != nil { t.Fatal(err) } if len(csr.DNSNames) != 2 { t.Fatal("SAN parsing error") } if len(csr.IPAddresses) != 1 { t.Fatal("SAN parsing error") } if len(csr.EmailAddresses) != 1 { t.Fatal("SAN parsing error") } if len(csr.URIs) != 1 { t.Fatal("SAN parsing error") } } // TestBadGenerator ensures that a request that fails the validator is // not processed. func TestBadGenerator(t *testing.T) { g := &Generator{testValidator} missingCN := &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, // Missing CN Hosts: []string{"cloudflare.com", "www.cloudflare.com"}, KeyRequest: &KeyRequest{"rsa", 2048}, } _, _, err := g.ProcessRequest(missingCN) if err == nil { t.Fatalf("Request should have failed.") } } func TestWeakCSR(t *testing.T) { weakKey := &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com", "https://www.cloudflare.com"}, KeyRequest: &KeyRequest{"rsa", 1024}, } g := &Generator{testValidator} _, _, err := g.ProcessRequest(weakKey) if err == nil { t.Fatalf("Request should have failed.") } } var testEmpty = []struct { name Name ok bool }{ { Name{}, true, }, { Name{C: "OK"}, false, }, { Name{ST: "OK"}, false, }, { Name{L: "OK"}, false, }, { Name{O: "OK"}, false, }, { Name{OU: "OK"}, false, }, } func TestIsNameEmpty(t *testing.T) { for i, c := range testEmpty { if IsNameEmpty(c.name) != c.ok { t.Fatalf("%d: expected IsNameEmpty to return %v, but have %v", i, c.ok, !c.ok) } } } func TestGenerate(t *testing.T) { var req = &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com", "https://www.cloudflare.com"}, KeyRequest: &KeyRequest{"ecdsa", 256}, } key, err := req.KeyRequest.Generate() if err != nil { t.Fatalf("%v", err) } priv, ok := key.(crypto.Signer) if !ok { t.Fatal("Private key is not a signer.") } csrPEM, err := Generate(priv, req) if err != nil { t.Fatalf("%v", err) } csr, _, err := helpers.ParseCSR(csrPEM) if err != nil { t.Fatalf("%v", err) } if len(csr.DNSNames) != 2 { t.Fatal("SAN parsing error") } if len(csr.IPAddresses) != 1 { t.Fatal("SAN parsing error") } if len(csr.EmailAddresses) != 1 { t.Fatal("SAN parsing error") } if len(csr.URIs) != 1 { t.Fatal("SAN parsing error") } } func TestGenerateASN1(t *testing.T) { var req = &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com", "https://www.cloudflare.com"}, KeyRequest: &KeyRequest{"ecdsa", 256}, } key, err := req.KeyRequest.Generate() if err != nil { t.Fatalf("%v", err) } priv, ok := key.(crypto.Signer) if !ok { t.Fatal("Private key is not a signer.") } csrDER, err := GenerateDER(priv, req) if err != nil { t.Fatalf("%v", err) } csr, err := helpers.ParseCSRDER(csrDER) if err != nil { t.Fatalf("%v", err) } if len(csr.DNSNames) != 2 { t.Fatal("SAN parsing error") } if len(csr.IPAddresses) != 1 { t.Fatal("SAN parsing error") } if len(csr.EmailAddresses) != 1 { t.Fatal("SAN parsing error") } if len(csr.URIs) != 1 { t.Fatal("SAN parsing error") } } // TestReGenerate ensures Regenerate() is abel to use the provided CSR as a template for signing a new // CSR using priv. func TestReGenerate(t *testing.T) { var req = &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"}, KeyRequest: &KeyRequest{"ecdsa", 256}, } _, key, err := ParseRequest(req) if err != nil { t.Fatalf("%v", err) } priv, err := helpers.ParsePrivateKeyPEM(key) if err != nil { t.Fatalf("%v", err) } csr, err := Generate(priv, req) if err != nil { t.Fatalf("%v", err) } if _, _, err = helpers.ParseCSR(csr); err != nil { t.Fatalf("%v", err) } _, err = Regenerate(priv, csr) if err != nil { t.Fatalf("%v", err) } } // TestBadReGenerator ensures that a request that fails the ParseCSR is // not processed. func TestBadReGenerate(t *testing.T) { var req = &CertificateRequest{ Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"}, KeyRequest: &KeyRequest{"ecdsa", 256}, } _, key, err := ParseRequest(req) if err != nil { t.Fatalf("%v", err) } priv, err := helpers.ParsePrivateKeyPEM(key) if err != nil { t.Fatalf("%v", err) } csr, err := Generate(priv, req) if err != nil { t.Fatalf("%v", err) } block := pem.Block{ Type: "CERTIFICATE REQUEST", Headers: map[string]string{ "Location": "UCSD", }, Bytes: csr, } csr = pem.EncodeToMemory(&block) _, err = Regenerate(priv, csr) if err == nil { t.Fatalf("%v", err) } } var testECDSACertificateFile = "testdata/test-ecdsa-ca.pem" func TestExtractCertificateRequest(t *testing.T) { certPEM, err := os.ReadFile(testECDSACertificateFile) if err != nil { t.Fatal(err) } // must parse ok cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } req := ExtractCertificateRequest(cert) if req.CN != "" { t.Fatal("Bad Certificate Request!") } if len(req.Names) != 1 { t.Fatal("Bad Certificate Request!") } name := req.Names[0] if name.C != "US" || name.ST != "California" || name.O != "CloudFlare, Inc." || name.OU != "Test Certificate Authority" || name.L != "San Francisco" { t.Fatal("Bad Certificate Request!") } if req.CA == nil || req.CA.PathLength != 2 { t.Fatal("Bad Certificate Request!") } } // TestDelegationCSR tests that we create requests with the DC extension func TestDelegationCSR(t *testing.T) { var cr = &CertificateRequest{ CN: "Test Common Name", Names: []Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare, Inc.", OU: "Systems Engineering", }, { C: "GB", ST: "London", L: "London", O: "CloudFlare, Inc", OU: "Systems Engineering", }, }, DelegationEnabled: true, Hosts: []string{"cloudflare.com", "www.cloudflare.com"}, KeyRequest: NewKeyRequest(), } csr, _, err := ParseRequest(cr) if err != nil { t.Fatal("could not generate csr") } unPem, _ := pem.Decode(csr) if unPem == nil { t.Fatal("Failed to decode pem") } res, err := x509.ParseCertificateRequest(unPem.Bytes) if err != nil { t.Fatalf("spat out nonsense as a csr: %v", err) } found := false for _, ext := range res.Extensions { if ext.Id.Equal(helpers.DelegationUsage) { found = true } } if !found { t.Fatal("generated csr has no extension") } } ================================================ FILE: csr/testdata/test-ecdsa-ca.pem ================================================ -----BEGIN CERTIFICATE----- MIICUDCCAfagAwIBAgIIec5PjdpJcNYwCgYIKoZIzj0EAwIwejELMAkGA1UEBhMC VVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNVBAsTGlRlc3QgQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYD VQQIEwpDYWxpZm9ybmlhMB4XDTE1MTAwODIzMDEwMFoXDTE1MTAwODIzMDYwMFow ejELMAkGA1UEBhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNV BAsTGlRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEoCV+bVOLTJMy38j50sc3vE5k41GMRgriFJt0g0OVX8yaOZ93CZTI7Lzf GbMU+KqWTgOwGhrPvpusep3fjw+dAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud EwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFDpLhSKBN3njfb6cXQCdRLzCZt0ZMB8G A1UdIwQYMBaAFDpLhSKBN3njfb6cXQCdRLzCZt0ZMAoGCCqGSM49BAMCA0gAMEUC IFU3BmzntGGeXZu2qWZx249nYn37S0AkCnQ3rUtI31bdAiEAsPICnZ+GB8yCN26N OL+N8dHvXiOvZ9/Vl488pyWOccY= -----END CERTIFICATE----- ================================================ FILE: doc/README.txt ================================================ CFSSL DOCUMENTATION GUIDE api/ API documentation authentication.txt A high-level overview of the CFSSL authentication system. cmd/ Documentation for the programs included in CFSSL, including configuration and operations. errorcode.txt Description of the error codes returned by CFSSL. ================================================ FILE: doc/api/endpoint_authsign.txt ================================================ THE AUTHENTICATED SIGNING ENDPOINT Endpoint: /api/v1/cfssl/authsign Method: POST Required parameters: * token: the authentication token * request: an encoded JSON signing request (e.g. as documented in endpoint_sign.txt). Optional parameters: The following parameters might be used by the authenticator as part of the authentication process. * timestamp: a Unix timestamp * remote_address: an address used in making the request. * bundle: a boolean specifying whether to include an "optimal" certificate bundle along with the certificate Result: The returned result is a JSON object with a single key: * certificate: a PEM-encoded certificate that has been signed by the server. * bundle: See the result of endpoint_bundle.txt (only included if the bundle parameter was set) The authentication documentation contains more information about how authentication with CFSSL works. ================================================ FILE: doc/api/endpoint_bundle.txt ================================================ THE BUNDLE ENDPOINT Endpoint: /api/v1/cfssl/bundle Method: POST Required parameters: One of the following two parameters is required; If both are present, "domain" becomes one of optional parameters with "certificate", read on for details. * certificate: the PEM-encoded certificate to be bundled. * domain: a domain name indicating a remote host to retrieve a certificate for. If the "certificate" parameter is present, the following four parameters are valid: * private_key: the PEM-encoded private key to be included with the bundle. This is valid only if the server is not running in "keyless" mode. * flavor: one of "ubiquitous", "force", or "optimal", with a default value of "ubiquitous". A ubiquitous bundle is one that has a higher probability of being verified everywhere, even by clients using outdated or unusual trust stores. Force will cause the endpoint to use the bundle provided in the "certificate" parameter, and will only verify that the bundle is a valid (verifiable) chain. * domain: the domain name to verify as the hostname of the certificate. * ip: the IP address to verify against the certificate IP SANs If only the "domain" parameter is present, the following parameter is valid: * ip: the IP address of the remote host; this will fetch the certificate from the IP, and verify that it is valid for the domain name. Result: The bundle endpoint returns a JSON object with the following keys: * bundle contains the concatenated list of PEM certificates forming the certificate chain; this forms the actual bundle. The remaining parameters are additional metadata supporting the bundle. * crl_support is true if CRL information is contained in the certificate. * crt contains the original certificate the bundle is built from. * expires contains the expiration date of the certificate. * hostnames contains the SAN hostnames for the certificate. * issuer contains the X.509 issuer information for the certificate. * key contains the private key for the certificate, if one was presented. * key_size contains the size of the key in bits for the certificate. It will be present even if the private key wasn't provided because this can be determined from the public key. * key_type contains a textual description of the key type, e.g. '2048-bit RSA'. * ocsp contains the OCSP URLs for the certificate, if present. * ocsp_support will be true if the certificate supports OCSP revocation checking. * signature contains the signature type used in the certificate, e.g. 'SHA1WithRSA'. * status contains a number of elements: * code is bit-encoded error code. 1st bit indicates whether there is a expiring certificate in the bundle. 2nd bit indicates whether there is a ubiquity issue with the bundle. * expiring_SKIs contains the SKIs (subject key identifiers) for any certificates that might expire soon (within 30 days). * messages is a list of human-readable warnings on bundle ubiquity and certificate expiration. For example, an expiration warning can be "The expiring cert is #1 in the chain", indicating the leaf certificate is expiring. Ubiquity warnings include SHA-1 deprecation warning (if the bundle triggers any major browser's SHA-1 deprecation policy), SHA-2 compatibility warning (if the bundle contains signatures using SHA-2 hash algorithms, it will be rejected by Windows XP SP2), ECDSA compatibility warning (if the bundle contains ECDSA certificates, it will be rejected by Windows XP, Android 2.2 and Android 2.3 etc) and root trust warning (if the bundle cannot be trusted by some major OSes or browsers). * rebundled indicates whether the server had to rebundle the certificate. The server will rebundle the uploaded certificate as needed; for example, if the certificate contains none of the required intermediates or a better set of intermediates was found. In this case, the server will mark rebundled as true. * untrusted_root_stores contains the names of any major OSes and browsers that doesn't trust the bundle. The names are used to construct the root trust warnings in the messages list * subject contains the X.509 subject identifier from the certificate. Example: $ curl -d '{"domain": "cloudflare.com"}' \ ${CFSSL_HOST}/api/v1/cfssl/bundle \ | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 11169 0 11141 100 28 19331 48 --:--:-- --:--:-- --:--:-- 19342 { "errors": [], "messages": [], "result": { "bundle": "-----BEGIN CERTIFICATE-----\nMIIHFDCCBfygAwIBAgIQXu3lLLTt9p4yFCuxChTXSTANBgkqhkiG9w0BAQUFADCB\njjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNDAyBgNV\nBAMTK0NPTU9ETyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIgQ0Ew\nHhcNMTUwMTA1MDAwMDAwWhcNMTUxMjMxMjM1OTU5WjCCARwxEDAOBgNVBAUTBzQ3\nMTA4NzUxEzARBgsrBgEEAYI3PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIBAhMIRGVs\nYXdhcmUxHTAbBgNVBA8TFFByaXZhdGUgT3JnYW5pemF0aW9uMQswCQYDVQQGEwJV\nUzEOMAwGA1UEERMFOTQxMDcxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJh\nbmNpc2NvMRkwFwYDVQQJExA2NjUgVGhpcmQgU3RyZWV0MRkwFwYDVQQKExBDbG91\nZEZsYXJlLCBJbmMuMRwwGgYDVQQLExNDbG91ZEZsYXJlIFNlY3VyaXR5MSMwIQYD\nVQQLExpDT01PRE8gRVYgTXVsdGktRG9tYWluIFNTTDCCASIwDQYJKoZIhvcNAQEB\nBQADggEPADCCAQoCggEBAN6yBr75KxUUNMatmcL/Ki8K3Z2kmBMq5k+9G2fyViq7\nEB+Rst+RYCDIOwOf9Fb5q82yMC/CLIu3a9hd+tfITcJ2VhlLYRU9XZPVyZ53yVD8\n67bviNsdKtM1WM40FuK/SG92MLiCPGWD+LkpcxzD5nPZxGuLZhkPjBXpVNiwWZyX\nASD7cKQSZ5Kngc1iANkrxUYL253yq2sqI2pvDjedp/BuTF8V5zUxRlyeUQfuZfEZ\nZsS6VGyHKO2KfrJrDOz7XjBx0bcliYW3bZi/VcxP+Q1kOXLOdtiLEZMbuL9oVHXC\ni7FKGwZIAgvxxupLQuIdQI9+GLSpCrSiQJwk4TOqqOECAwEAAaOCAtswggLXMB8G\nA1UdIwQYMBaAFIhEUf9QKmleLYj0IbrZDPLOy+p8MB0GA1UdDgQWBBTJ4NAMUXb3\nNbMVJu2NtfC7ll2rujAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNV\nHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0gBD8wPTA7BgwrBgEEAbIx\nAQIBBQEwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNvbS9D\nUFMwUwYDVR0fBEwwSjBIoEagRIZCaHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09N\nT0RPRXh0ZW5kZWRWYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGEBggrBgEF\nBQcBAQR4MHYwTgYIKwYBBQUHMAKGQmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NP\nTU9ET0V4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAkBggrBgEF\nBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMC0GA1UdEQQmMCSCDmNsb3Vk\nZmxhcmUuY29tghJ3d3cuY2xvdWRmbGFyZS5jb20wggEDBgorBgEEAdZ5AgQCBIH0\nBIHxAO8AdQBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUq6JZ63\nAAAEAwBGMEQCIDnMUQTV5uhtg3wo4WudmHrLsRGAPxgKahZ2qAheT2nJAiBXTr30\neD/Edkl+klFUUYJIN8ntqy1nOgw1cFGDSMcw+wB2AKS5CZC0GFgUh7sTosxncAo8\nNZgE+RvfuON3zQ7IDdwQAAABSrolns0AAAQDAEcwRQIhAOt2rMbzsavA074rVKZ6\nT+OYR0zL2HX6GjI4+ItnguYRAiA9It+jwuBjW2tocmYNAOgzBzuNNdgBtmqMwkLf\neXRojzANBgkqhkiG9w0BAQUFAAOCAQEAXl5mVmhHA6WcjPhmTMoHGvPCdsGVBWe0\nFr85yjuQsVSKCsZDD3ec01MnNyxwxf6GYFMxysv4j6rC9zlo55fecljtIrPSuftZ\nO4Uvo2a36b5s6sGBqfKQPQbjdbdJvw8yymLHMU25Df3ZZcj0T8bQZKjIZRv5IiDL\nSUlwyxhiiorMrqCPTyiniCXJvfdaFBUWdw37QZWNHyvVap7vUTXQpsHGkt+KL+0w\nC4/mhoakAMd8n+//pBDtHBWqsnxA7/S6vM9zP0+xRR8vHUsDGj28Ito8839WP18u\nfQrczSznX7YbZjCk++r5GpSCFAsBBh5ZmU9bu9XnzAZ2hlkKec/8HA==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFBjCCA+6gAwIBAgIQEaO00OyNt3+doM1dLVEvQjANBgkqhkiG9w0BAQUFADCB\ngTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV\nBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xMDA1MjQwMDAw\nMDBaFw0yMDA1MzAxMDQ4MzhaMIGOMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl\nYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P\nRE8gQ0EgTGltaXRlZDE0MDIGA1UEAxMrQ09NT0RPIEV4dGVuZGVkIFZhbGlkYXRp\nb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBAMxKljPNJY1n7iiWN4dG8PYEooR/U6qW5h+xAhxu7X0h1Nc8HqLYaS+ot/Wi\n7WRYZOFEZTZJQSABjTsT4gjzDPJXOZM3txyTRIOOvy3xoQV12m7ue28b6naDKHRK\nHCvT9cQDcpOvhs4JjDx11MkKL3Lzrb0OMDyEoXMfAyUUpY/D1vS15N2GevUZumjy\nhVSiMBHK0ZLLO3QGEqA3q2rYVBHfbJoWlLm0p2XGdC0x801S6VVRn8s+oo12mHDS\nb6ZlRS8bhbtbbfnywARmE4R6nc4n2PREnr+svpnba0/bWCGwiSe0jzLWS15ykV7f\nBZ3ZSS/0tm9QH3XLgJ3m0+TR8tMCAwEAAaOCAWkwggFlMB8GA1UdIwQYMBaAFAtY\n5YvGTBU3pECpMKkhvkc2Wlb/MB0GA1UdDgQWBBSIRFH/UCppXi2I9CG62Qzyzsvq\nfDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADA+BgNVHSAENzA1\nMDMGBFUdIAAwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNv\nbS9DUFMwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2NybC5jb21vZG9jYS5jb20v\nQ09NT0RPQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdAYIKwYBBQUHAQEEaDBm\nMD4GCCsGAQUFBzAChjJodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9BZGRU\ncnVzdFNlcnZlckNBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2Rv\nY2EuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQCaQ7+vpHJezX1vf/T8PYy7cOYe3QT9\nP9ydn7+JdpvyhjH8f7PtKpFTLOKqsOPILHH3FYojHPFpLoH7sbxiC6saVBzZIl40\nTKX2Iw9dej3bQ81pfhc3Us1TocIR1FN4J2TViUFNFlW7kMvw2OTd3dMJZEgo/zIj\nhC+Me1UvzymINzR4DzOq/7fylqSbRIC1vmxWVKukgZ4lGChUOn8sY89ZIIwYazgs\ntN3t40DeDDYlV5rA0WCeXgNol64aO+pF11GZSe5EWVYLXrGPaOqKnsrSyaADfnAl\n9DLJTlCDh6I0SD1PNXf82Ijq9n0ezkO21cJqfjhmY03n7jLvDyToKmf6\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIE8TCCA9mgAwIBAgIQS3VXgmk5DJvjLxLsX22UXjANBgkqhkiG9w0BAQUFADBv\nMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk\nZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF\neHRlcm5hbCBDQSBSb290MB4XDTEwMDIxMTAwMDAwMFoXDTIwMDUzMDEwNDgzOFow\ngYExCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\nBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMScwJQYD\nVQQDEx5DT01PRE8gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDQQIuLcuORG/dRwRtUBJjTqb/B5opdO4f7u4jO\nDeMvPwaW8KIpUJmu2zuhV7B0UXHN7UKRTUH+qcjYaoZ3RLtZZpdQXrTULHBEz9o3\nlUJpPDDEcbNS8CFNodi6OXwcnqMknfKDFpiqFnxDmxVbt640kf7UYiYYRpo/68H5\n8ZBX66x6DYvbcjBqZtXgRqNw3GjZ/wRIiXfeten7Z21B6bw5vTLZYgLxsag9bjec\n4i/i06Imi8a4VUOI4SM+pdIkOWpHqwDUobOpJf4NP6cdutNRwQuk2qw471VQJAVl\nRpM0Ty2NrcbUIRnSjsoFYXEHc0flihkSvQRNzk6cpUisuyb3AgMBAAGjggF0MIIB\ncDAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73gJMtUGjAdBgNVHQ4EFgQUC1jl\ni8ZMFTekQKkwqSG+RzZaVv8wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB\nAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9j\ncmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDCBswYI\nKwYBBQUHAQEEgaYwgaMwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0\nLmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LnA3YzA5BggrBgEFBQcwAoYtaHR0\ncDovL2NydC51c2VydHJ1c3QuY29tL0FkZFRydXN0VVROU0dDQ0EuY3J0MCUGCCsG\nAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBBQUA\nA4IBAQBNhw1QMPOCXcQ/1O/ujUjj572Qa8QyOMZeKKtcpa1h+Y67hRQ5IVFbjozc\nF5KAL4OUaYjBvieOT5+pg9i+14eScaO2/RF0uJWBKCB3DUN3dXY4HU0bLpeJjAob\nZhZS1BSab4BIFt4wwEJo6r+iuipETayJ4vPMU5vj5h1uT5if2Q5RUIbgGjQyJIB9\nOofzPOVaTbeLvQokDa7b9I9c0mYMghxyN7bRudCYNBsnbYteHkBzGPqo5MbokMOr\nGeTBoc1M1Dq2iMjz0GVhOr8Y9K8cVqnrlzjZICkfPyopR52KD2oSgUQCIdQ7Ohor\nHkBDfZSgaQ78LvtS9v0uMtjLa73r\n-----END CERTIFICATE-----", "crl_support": true, "crt": "-----BEGIN CERTIFICATE-----\nMIIHFDCCBfygAwIBAgIQXu3lLLTt9p4yFCuxChTXSTANBgkqhkiG9w0BAQUFADCB\njjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNDAyBgNV\nBAMTK0NPTU9ETyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIgQ0Ew\nHhcNMTUwMTA1MDAwMDAwWhcNMTUxMjMxMjM1OTU5WjCCARwxEDAOBgNVBAUTBzQ3\nMTA4NzUxEzARBgsrBgEEAYI3PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIBAhMIRGVs\nYXdhcmUxHTAbBgNVBA8TFFByaXZhdGUgT3JnYW5pemF0aW9uMQswCQYDVQQGEwJV\nUzEOMAwGA1UEERMFOTQxMDcxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJh\nbmNpc2NvMRkwFwYDVQQJExA2NjUgVGhpcmQgU3RyZWV0MRkwFwYDVQQKExBDbG91\nZEZsYXJlLCBJbmMuMRwwGgYDVQQLExNDbG91ZEZsYXJlIFNlY3VyaXR5MSMwIQYD\nVQQLExpDT01PRE8gRVYgTXVsdGktRG9tYWluIFNTTDCCASIwDQYJKoZIhvcNAQEB\nBQADggEPADCCAQoCggEBAN6yBr75KxUUNMatmcL/Ki8K3Z2kmBMq5k+9G2fyViq7\nEB+Rst+RYCDIOwOf9Fb5q82yMC/CLIu3a9hd+tfITcJ2VhlLYRU9XZPVyZ53yVD8\n67bviNsdKtM1WM40FuK/SG92MLiCPGWD+LkpcxzD5nPZxGuLZhkPjBXpVNiwWZyX\nASD7cKQSZ5Kngc1iANkrxUYL253yq2sqI2pvDjedp/BuTF8V5zUxRlyeUQfuZfEZ\nZsS6VGyHKO2KfrJrDOz7XjBx0bcliYW3bZi/VcxP+Q1kOXLOdtiLEZMbuL9oVHXC\ni7FKGwZIAgvxxupLQuIdQI9+GLSpCrSiQJwk4TOqqOECAwEAAaOCAtswggLXMB8G\nA1UdIwQYMBaAFIhEUf9QKmleLYj0IbrZDPLOy+p8MB0GA1UdDgQWBBTJ4NAMUXb3\nNbMVJu2NtfC7ll2rujAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNV\nHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0gBD8wPTA7BgwrBgEEAbIx\nAQIBBQEwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNvbS9D\nUFMwUwYDVR0fBEwwSjBIoEagRIZCaHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09N\nT0RPRXh0ZW5kZWRWYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGEBggrBgEF\nBQcBAQR4MHYwTgYIKwYBBQUHMAKGQmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NP\nTU9ET0V4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAkBggrBgEF\nBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMC0GA1UdEQQmMCSCDmNsb3Vk\nZmxhcmUuY29tghJ3d3cuY2xvdWRmbGFyZS5jb20wggEDBgorBgEEAdZ5AgQCBIH0\nBIHxAO8AdQBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUq6JZ63\nAAAEAwBGMEQCIDnMUQTV5uhtg3wo4WudmHrLsRGAPxgKahZ2qAheT2nJAiBXTr30\neD/Edkl+klFUUYJIN8ntqy1nOgw1cFGDSMcw+wB2AKS5CZC0GFgUh7sTosxncAo8\nNZgE+RvfuON3zQ7IDdwQAAABSrolns0AAAQDAEcwRQIhAOt2rMbzsavA074rVKZ6\nT+OYR0zL2HX6GjI4+ItnguYRAiA9It+jwuBjW2tocmYNAOgzBzuNNdgBtmqMwkLf\neXRojzANBgkqhkiG9w0BAQUFAAOCAQEAXl5mVmhHA6WcjPhmTMoHGvPCdsGVBWe0\nFr85yjuQsVSKCsZDD3ec01MnNyxwxf6GYFMxysv4j6rC9zlo55fecljtIrPSuftZ\nO4Uvo2a36b5s6sGBqfKQPQbjdbdJvw8yymLHMU25Df3ZZcj0T8bQZKjIZRv5IiDL\nSUlwyxhiiorMrqCPTyiniCXJvfdaFBUWdw37QZWNHyvVap7vUTXQpsHGkt+KL+0w\nC4/mhoakAMd8n+//pBDtHBWqsnxA7/S6vM9zP0+xRR8vHUsDGj28Ito8839WP18u\nfQrczSznX7YbZjCk++r5GpSCFAsBBh5ZmU9bu9XnzAZ2hlkKec/8HA==\n-----END CERTIFICATE-----", "expires": "2015-12-31T23:59:59Z", "hostnames": [ "cloudflare.com", "www.cloudflare.com" ], "issuer": "/Country=GB/Province=Greater Manchester/Locality=Salford/Organization=COMODO CA Limited/CommonName=COMODO Extended Validation Secure Server CA", "key": "", "key_size": 2048, "key_type": "2048-bit RSA", "ocsp": [ "http://ocsp.comodoca.com" ], "ocsp_support": true, "root": "-----BEGIN CERTIFICATE-----\nMIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU\nMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs\nIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290\nMB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux\nFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h\nbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v\ndDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt\nH7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9\nuMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX\nmk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX\na0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN\nE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0\nWicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD\nVR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0\nJvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU\ncnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx\nIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN\nAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH\nYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5\n6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC\nNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX\nc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a\nmnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=\n-----END CERTIFICATE-----", "signature": "SHA1WithRSA", "status": { "code": 0, "expiring_SKIs": null, "messages": null, "rebundled": false, "untrusted_root_stores": [] }, "subject": "/SerialNumber=4710875/=US/=Delaware/=Private Organization/Country=US/PostalCode=94107/Province=CA/Locality=San Francisco/StreetAddress=665 Third Street/Organization=CloudFlare, Inc./OrganizationalUnit=CloudFlare Security/OrganizationalUnit=COMODO EV Multi-Domain SSL" }, "success": true } ================================================ FILE: doc/api/endpoint_certinfo.txt ================================================ THE CERTINFO ENDPOINT Endpoint: /api/v1/cfssl/certinfo Method: POST Required parameters: One of the following parameters is required. * certificate: the PEM-encoded certificate to be parsed. * domain: a domain name indicating a remote host to retrieve a certificate for. * serial and authority_key_id: a certificate serial number and a matching authority key to look for in the database Result: The certinfo endpoint returns a JSON object with the following keys: * subject contains a JSON object corresponding to a PKIX Name, including: * common_name * serial_number * country * organization * organizational_unit * locality * province * street_address * postal_code * names * extra_names * sans is a list of Subject Alternative Names. * not_before is the certificate's start date. * not_after is the certificate's end date. * sigalg is the signature algorithm used to sign the certificate. Example: $ curl -d '{"domain": "cloudflare.com"}' \ ${CFSSL_HOST}/api/v1/cfssl/certinfo \ | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 3229 0 3201 100 28 66658 583 --:--:-- --:--:-- --:--:-- 68106 curl: (6) Could not resolve host: { "errors": [], "messages": [], "result": { "not_after": "2015-12-31T23:59:59Z", "not_before": "2015-01-05T00:00:00Z", "pem": "-----BEGIN CERTIFICATE-----\nMIIHFDCCBfygAwIBAgIQXu3lLLTt9p4yFCuxChTXSTANBgkqhkiG9w0BAQUFADCB\njjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNDAyBgNV\nBAMTK0NPTU9ETyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIgQ0Ew\nHhcNMTUwMTA1MDAwMDAwWhcNMTUxMjMxMjM1OTU5WjCCARwxEDAOBgNVBAUTBzQ3\nMTA4NzUxEzARBgsrBgEEAYI3PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIBAhMIRGVs\nYXdhcmUxHTAbBgNVBA8TFFByaXZhdGUgT3JnYW5pemF0aW9uMQswCQYDVQQGEwJV\nUzEOMAwGA1UEERMFOTQxMDcxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJh\nbmNpc2NvMRkwFwYDVQQJExA2NjUgVGhpcmQgU3RyZWV0MRkwFwYDVQQKExBDbG91\nZEZsYXJlLCBJbmMuMRwwGgYDVQQLExNDbG91ZEZsYXJlIFNlY3VyaXR5MSMwIQYD\nVQQLExpDT01PRE8gRVYgTXVsdGktRG9tYWluIFNTTDCCASIwDQYJKoZIhvcNAQEB\nBQADggEPADCCAQoCggEBAN6yBr75KxUUNMatmcL/Ki8K3Z2kmBMq5k+9G2fyViq7\nEB+Rst+RYCDIOwOf9Fb5q82yMC/CLIu3a9hd+tfITcJ2VhlLYRU9XZPVyZ53yVD8\n67bviNsdKtM1WM40FuK/SG92MLiCPGWD+LkpcxzD5nPZxGuLZhkPjBXpVNiwWZyX\nASD7cKQSZ5Kngc1iANkrxUYL253yq2sqI2pvDjedp/BuTF8V5zUxRlyeUQfuZfEZ\nZsS6VGyHKO2KfrJrDOz7XjBx0bcliYW3bZi/VcxP+Q1kOXLOdtiLEZMbuL9oVHXC\ni7FKGwZIAgvxxupLQuIdQI9+GLSpCrSiQJwk4TOqqOECAwEAAaOCAtswggLXMB8G\nA1UdIwQYMBaAFIhEUf9QKmleLYj0IbrZDPLOy+p8MB0GA1UdDgQWBBTJ4NAMUXb3\nNbMVJu2NtfC7ll2rujAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNV\nHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0gBD8wPTA7BgwrBgEEAbIx\nAQIBBQEwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNvbS9D\nUFMwUwYDVR0fBEwwSjBIoEagRIZCaHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09N\nT0RPRXh0ZW5kZWRWYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGEBggrBgEF\nBQcBAQR4MHYwTgYIKwYBBQUHMAKGQmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NP\nTU9ET0V4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAkBggrBgEF\nBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMC0GA1UdEQQmMCSCDmNsb3Vk\nZmxhcmUuY29tghJ3d3cuY2xvdWRmbGFyZS5jb20wggEDBgorBgEEAdZ5AgQCBIH0\nBIHxAO8AdQBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUq6JZ63\nAAAEAwBGMEQCIDnMUQTV5uhtg3wo4WudmHrLsRGAPxgKahZ2qAheT2nJAiBXTr30\neD/Edkl+klFUUYJIN8ntqy1nOgw1cFGDSMcw+wB2AKS5CZC0GFgUh7sTosxncAo8\nNZgE+RvfuON3zQ7IDdwQAAABSrolns0AAAQDAEcwRQIhAOt2rMbzsavA074rVKZ6\nT+OYR0zL2HX6GjI4+ItnguYRAiA9It+jwuBjW2tocmYNAOgzBzuNNdgBtmqMwkLf\neXRojzANBgkqhkiG9w0BAQUFAAOCAQEAXl5mVmhHA6WcjPhmTMoHGvPCdsGVBWe0\nFr85yjuQsVSKCsZDD3ec01MnNyxwxf6GYFMxysv4j6rC9zlo55fecljtIrPSuftZ\nO4Uvo2a36b5s6sGBqfKQPQbjdbdJvw8yymLHMU25Df3ZZcj0T8bQZKjIZRv5IiDL\nSUlwyxhiiorMrqCPTyiniCXJvfdaFBUWdw37QZWNHyvVap7vUTXQpsHGkt+KL+0w\nC4/mhoakAMd8n+//pBDtHBWqsnxA7/S6vM9zP0+xRR8vHUsDGj28Ito8839WP18u\nfQrczSznX7YbZjCk++r5GpSCFAsBBh5ZmU9bu9XnzAZ2hlkKec/8HA==\n-----END CERTIFICATE-----\n", "sans": [ "cloudflare.com", "www.cloudflare.com" ], "sigalg": "SHA1WithRSA", "subject": { "country": "US", "locality": "San Francisco", "names": [ "4710875", "US", "Delaware", "Private Organization", "US", "94107", "CA", "San Francisco", "665 Third Street", "CloudFlare, Inc.", "CloudFlare Security", "COMODO EV Multi-Domain SSL" ], "organization": "CloudFlare, Inc.", "organizational_unit": "CloudFlare Security,COMODO EV Multi-Domain SSL", "postal_code": "94107", "province": "CA", "serial_number": "4710875", "street_address": "665 Third Street" } }, "success": true } $curl -d '{"certificate": "-----BEGIN CERTIFICATE-----\nMIIHFDCCBfygAwIBAgIQXu3lLLTt9p4yFCuxChTXSTANBgkqhkiG9w0BAQUFADCB\njjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNDAyBgNV\nBAMTK0NPTU9ETyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIgQ0Ew\nHhcNMTUwMTA1MDAwMDAwWhcNMTUxMjMxMjM1OTU5WjCCARwxEDAOBgNVBAUTBzQ3\nMTA4NzUxEzARBgsrBgEEAYI3PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIBAhMIRGVs\nYXdhcmUxHTAbBgNVBA8TFFByaXZhdGUgT3JnYW5pemF0aW9uMQswCQYDVQQGEwJV\nUzEOMAwGA1UEERMFOTQxMDcxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJh\nbmNpc2NvMRkwFwYDVQQJExA2NjUgVGhpcmQgU3RyZWV0MRkwFwYDVQQKExBDbG91\nZEZsYXJlLCBJbmMuMRwwGgYDVQQLExNDbG91ZEZsYXJlIFNlY3VyaXR5MSMwIQYD\nVQQLExpDT01PRE8gRVYgTXVsdGktRG9tYWluIFNTTDCCASIwDQYJKoZIhvcNAQEB\nBQADggEPADCCAQoCggEBAN6yBr75KxUUNMatmcL/Ki8K3Z2kmBMq5k+9G2fyViq7\nEB+Rst+RYCDIOwOf9Fb5q82yMC/CLIu3a9hd+tfITcJ2VhlLYRU9XZPVyZ53yVD8\n67bviNsdKtM1WM40FuK/SG92MLiCPGWD+LkpcxzD5nPZxGuLZhkPjBXpVNiwWZyX\nASD7cKQSZ5Kngc1iANkrxUYL253yq2sqI2pvDjedp/BuTF8V5zUxRlyeUQfuZfEZ\nZsS6VGyHKO2KfrJrDOz7XjBx0bcliYW3bZi/VcxP+Q1kOXLOdtiLEZMbuL9oVHXC\ni7FKGwZIAgvxxupLQuIdQI9+GLSpCrSiQJwk4TOqqOECAwEAAaOCAtswggLXMB8G\nA1UdIwQYMBaAFIhEUf9QKmleLYj0IbrZDPLOy+p8MB0GA1UdDgQWBBTJ4NAMUXb3\nNbMVJu2NtfC7ll2rujAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNV\nHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0gBD8wPTA7BgwrBgEEAbIx\nAQIBBQEwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNvbS9D\nUFMwUwYDVR0fBEwwSjBIoEagRIZCaHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09N\nT0RPRXh0ZW5kZWRWYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGEBggrBgEF\nBQcBAQR4MHYwTgYIKwYBBQUHMAKGQmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NP\nTU9ET0V4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAkBggrBgEF\nBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMC0GA1UdEQQmMCSCDmNsb3Vk\nZmxhcmUuY29tghJ3d3cuY2xvdWRmbGFyZS5jb20wggEDBgorBgEEAdZ5AgQCBIH0\nBIHxAO8AdQBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUq6JZ63\nAAAEAwBGMEQCIDnMUQTV5uhtg3wo4WudmHrLsRGAPxgKahZ2qAheT2nJAiBXTr30\neD/Edkl+klFUUYJIN8ntqy1nOgw1cFGDSMcw+wB2AKS5CZC0GFgUh7sTosxncAo8\nNZgE+RvfuON3zQ7IDdwQAAABSrolns0AAAQDAEcwRQIhAOt2rMbzsavA074rVKZ6\nT+OYR0zL2HX6GjI4+ItnguYRAiA9It+jwuBjW2tocmYNAOgzBzuNNdgBtmqMwkLf\neXRojzANBgkqhkiG9w0BAQUFAAOCAQEAXl5mVmhHA6WcjPhmTMoHGvPCdsGVBWe0\nFr85yjuQsVSKCsZDD3ec01MnNyxwxf6GYFMxysv4j6rC9zlo55fecljtIrPSuftZ\nO4Uvo2a36b5s6sGBqfKQPQbjdbdJvw8yymLHMU25Df3ZZcj0T8bQZKjIZRv5IiDL\nSUlwyxhiiorMrqCPTyiniCXJvfdaFBUWdw37QZWNHyvVap7vUTXQpsHGkt+KL+0w\nC4/mhoakAMd8n+//pBDtHBWqsnxA7/S6vM9zP0+xRR8vHUsDGj28Ito8839WP18u\nfQrczSznX7YbZjCk++r5GpSCFAsBBh5ZmU9bu9XnzAZ2hlkKec/8HA==\n-----END CERTIFICATE-----\n"}' \ > ${CFSSL_HOST}/api/v1/cfssl/certinfo \ > | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 5776 0 3201 100 2575 552k 444k --:--:-- --:--:-- --:--:-- 625k { "errors": [], "messages": [], "result": { "not_after": "2015-12-31T23:59:59Z", "not_before": "2015-01-05T00:00:00Z", "pem": "-----BEGIN CERTIFICATE-----\nMIIHFDCCBfygAwIBAgIQXu3lLLTt9p4yFCuxChTXSTANBgkqhkiG9w0BAQUFADCB\njjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNDAyBgNV\nBAMTK0NPTU9ETyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIgQ0Ew\nHhcNMTUwMTA1MDAwMDAwWhcNMTUxMjMxMjM1OTU5WjCCARwxEDAOBgNVBAUTBzQ3\nMTA4NzUxEzARBgsrBgEEAYI3PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIBAhMIRGVs\nYXdhcmUxHTAbBgNVBA8TFFByaXZhdGUgT3JnYW5pemF0aW9uMQswCQYDVQQGEwJV\nUzEOMAwGA1UEERMFOTQxMDcxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJh\nbmNpc2NvMRkwFwYDVQQJExA2NjUgVGhpcmQgU3RyZWV0MRkwFwYDVQQKExBDbG91\nZEZsYXJlLCBJbmMuMRwwGgYDVQQLExNDbG91ZEZsYXJlIFNlY3VyaXR5MSMwIQYD\nVQQLExpDT01PRE8gRVYgTXVsdGktRG9tYWluIFNTTDCCASIwDQYJKoZIhvcNAQEB\nBQADggEPADCCAQoCggEBAN6yBr75KxUUNMatmcL/Ki8K3Z2kmBMq5k+9G2fyViq7\nEB+Rst+RYCDIOwOf9Fb5q82yMC/CLIu3a9hd+tfITcJ2VhlLYRU9XZPVyZ53yVD8\n67bviNsdKtM1WM40FuK/SG92MLiCPGWD+LkpcxzD5nPZxGuLZhkPjBXpVNiwWZyX\nASD7cKQSZ5Kngc1iANkrxUYL253yq2sqI2pvDjedp/BuTF8V5zUxRlyeUQfuZfEZ\nZsS6VGyHKO2KfrJrDOz7XjBx0bcliYW3bZi/VcxP+Q1kOXLOdtiLEZMbuL9oVHXC\ni7FKGwZIAgvxxupLQuIdQI9+GLSpCrSiQJwk4TOqqOECAwEAAaOCAtswggLXMB8G\nA1UdIwQYMBaAFIhEUf9QKmleLYj0IbrZDPLOy+p8MB0GA1UdDgQWBBTJ4NAMUXb3\nNbMVJu2NtfC7ll2rujAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNV\nHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0gBD8wPTA7BgwrBgEEAbIx\nAQIBBQEwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNvbS9D\nUFMwUwYDVR0fBEwwSjBIoEagRIZCaHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09N\nT0RPRXh0ZW5kZWRWYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGEBggrBgEF\nBQcBAQR4MHYwTgYIKwYBBQUHMAKGQmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NP\nTU9ET0V4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAkBggrBgEF\nBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMC0GA1UdEQQmMCSCDmNsb3Vk\nZmxhcmUuY29tghJ3d3cuY2xvdWRmbGFyZS5jb20wggEDBgorBgEEAdZ5AgQCBIH0\nBIHxAO8AdQBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUq6JZ63\nAAAEAwBGMEQCIDnMUQTV5uhtg3wo4WudmHrLsRGAPxgKahZ2qAheT2nJAiBXTr30\neD/Edkl+klFUUYJIN8ntqy1nOgw1cFGDSMcw+wB2AKS5CZC0GFgUh7sTosxncAo8\nNZgE+RvfuON3zQ7IDdwQAAABSrolns0AAAQDAEcwRQIhAOt2rMbzsavA074rVKZ6\nT+OYR0zL2HX6GjI4+ItnguYRAiA9It+jwuBjW2tocmYNAOgzBzuNNdgBtmqMwkLf\neXRojzANBgkqhkiG9w0BAQUFAAOCAQEAXl5mVmhHA6WcjPhmTMoHGvPCdsGVBWe0\nFr85yjuQsVSKCsZDD3ec01MnNyxwxf6GYFMxysv4j6rC9zlo55fecljtIrPSuftZ\nO4Uvo2a36b5s6sGBqfKQPQbjdbdJvw8yymLHMU25Df3ZZcj0T8bQZKjIZRv5IiDL\nSUlwyxhiiorMrqCPTyiniCXJvfdaFBUWdw37QZWNHyvVap7vUTXQpsHGkt+KL+0w\nC4/mhoakAMd8n+//pBDtHBWqsnxA7/S6vM9zP0+xRR8vHUsDGj28Ito8839WP18u\nfQrczSznX7YbZjCk++r5GpSCFAsBBh5ZmU9bu9XnzAZ2hlkKec/8HA==\n-----END CERTIFICATE-----\n", "sans": [ "cloudflare.com", "www.cloudflare.com" ], "sigalg": "SHA1WithRSA", "subject": { "country": "US", "locality": "San Francisco", "names": [ "4710875", "US", "Delaware", "Private Organization", "US", "94107", "CA", "San Francisco", "665 Third Street", "CloudFlare, Inc.", "CloudFlare Security", "COMODO EV Multi-Domain SSL" ], "organization": "CloudFlare, Inc.", "organizational_unit": "CloudFlare Security,COMODO EV Multi-Domain SSL", "postal_code": "94107", "province": "CA", "serial_number": "4710875", "street_address": "665 Third Street" } }, "success": true } ================================================ FILE: doc/api/endpoint_crl.txt ================================================ THE CRL ENDPOINT Endpoint: /api/v1/cfssl/crl Method: GET Optional URL Query parameters: * expiry: a value, in seconds, after which the CRL should expire from the moment of the request. Result: The returned result is an empty JSON object Example: $ curl ${CFSSL_HOST}/api/v1/cfssl/crl $ curl ${CFSSL_HOST}/api/v1/cfssl/crl?expiry=7200h ================================================ FILE: doc/api/endpoint_health.txt ================================================ THE HEALTH ENDPOINT Endpoint: /api/v1/cfssl/health Method: GET Result: The returned result is a JSON object with a single key: * healthy: a bool indicating if the API server is healthy Example: $ curl ${CFSSL_HOST}/api/v1/cfssl/health ================================================ FILE: doc/api/endpoint_info.txt ================================================ THE INFO ENDPOINT Endpoint: /api/v1/cfssl/info Method: POST Required parameters: * label: a string specifying the signer Optional parameters: * profile: a string specifying the signing profile for the signer. Signing profile specifies what key usages should be used and how long the expiry should be set Result: The returned result is a JSON object with three keys: * certificate: a PEM-encoded certificate of the signer * usage: a string array of key usages from the signing profile * expiry: the expiry string from the signing profile Example: $ curl -d '{"label": "primary"}' \ ${CFSSL_HOST}/api/v1/cfssl/info \ | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 943 100 924 100 19 44029 905 --:--:-- --:--:-- --:--:-- 46200 { "errors": [], "messages": [], "result": { "certificate": "-----BEGIN CERTIFICATE-----\nMIICATCCAWoCCQDidF+uNJR6czANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB\nVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\ncyBQdHkgTHRkMB4XDTEyMDUwMTIyNTUxN1oXDTEzMDUwMTIyNTUxN1owRTELMAkG\nA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0\nIFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl\nnodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj\nw7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81\nKAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF\nAAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp\niv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt\n+LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw==\n-----END CERTIFICATE-----", "expiry": "8760h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "success": true } ================================================ FILE: doc/api/endpoint_init_ca.txt ================================================ THE CA CERTIFICATE GENERATING ENDPOINT Endpoint: /api/v1/cfssl/init_ca Method: POST Required parameters: * hosts: the list of SANs (subject alternative names) for the requested CA certificate * names: the certificate subject for the requested CA certificate Optional parameters: * CN: the common name for the certificate subject in the requested CA certificate. * key: the key algorithm and size for the newly generated private key, default to ECDSA-256 * ca: the CA configuration of the requested CA, including CA pathlen and CA default expiry Result: The returned result is a JSON object with three keys: * private key: a PEM-encoded CA private key * certificate: a PEM-encoded self-signed CA certificate Example: $ curl -d '{"hosts":["www.example.com"], "names":[{"C":"US", "ST":"California", "L":"San Francisco", "O":"example.com"}], "CN": "www.example.com"}' \ ${CFSSL_HOST}/api/v1/cfssl/init_ca \ | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1287 100 1152 100 135 36806 4313 --:--:-- --:--:-- --:--:-- 37161 { "errors": [], "messages": [], "result": { "certificate": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIHSuWpkTLyX4pucRtUATncQaTYtTRJNDpt8j7cnBeVceoAoGCCqGSM49\nAwEHoUQDQgAEqj9wJFCAqvcLRRB+qSc/jxLgUHLTMUi6ko/JupAWI1V5SjZxuL4u\nh6HS3VE4fvCdcfa06PAAKiJBNsfPBcS/Ig==\n-----END EC PRIVATE KEY-----\n", "private_key": "-----BEGIN CERTIFICATE-----\nMIICMDCCAdagAwIBAgIIOdP968SD1xgwCgYIKoZIzj0EAwIwajELMAkGA1UEBhMC\nVVMxFDASBgNVBAoTC2V4YW1wbGUuY29tMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv\nMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20w\nHhcNMTUwODAzMDYyODAwWhcNMjAwODAxMDYyODAwWjBqMQswCQYDVQQGEwJVUzEU\nMBIGA1UEChMLZXhhbXBsZS5jb20xFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzAR\nBgNVBAgTCkNhbGlmb3JuaWExGDAWBgNVBAMTD3d3dy5leGFtcGxlLmNvbTBZMBMG\nByqGSM49AgEGCCqGSM49AwEHA0IABKo/cCRQgKr3C0UQfqknP48S4FBy0zFIupKP\nybqQFiNVeUo2cbi+Loeh0t1ROH7wnXH2tOjwACoiQTbHzwXEvyKjZjBkMA4GA1Ud\nDwEB/wQEAwIABjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBTH3jEBAIFt\nFFgJAI9lm8ktqxNt+DAfBgNVHSMEGDAWgBTH3jEBAIFtFFgJAI9lm8ktqxNt+DAK\nBggqhkjOPQQDAgNIADBFAiEA7s2UgPNJuQLzcXYNTQxhYqFq2+rbrJGC0WhYE8+r\n1yACIC5fsyyNNlw5HbSv4MDBwu3ozsMdfmoQTLVyijW/LC9r\n-----END CERTIFICATE-----\n" }, "success": true } ================================================ FILE: doc/api/endpoint_newcert.txt ================================================ THE CERTIFICATE GENERATING ENDPOINT Endpoint: /api/v1/cfssl/newcert Method: POST Required parameters: * request: a json object specifying the certificate request, exactly the one which can be sent to /api/v1/cfssl/newkey to generate a certificate signing request (referring to endpoint_newkey for how to write such object) Optional parameters: * label: a string specifying which signer to be appointed to sign the CSR, useful when interacting with cfssl server that stands in front of a remote multi-root CA signer * profile: a string specifying the signing profile for the signer * bundle: a boolean specifying whether to include an "optimal" certificate bundle along with the certificate Result: The returned result is a JSON object with four keys: * private key: a PEM-encoded private key * certificate_request: a PEM-encoded certificate request * certificate: a PEM-encoded certificate, signed by the server * sums: a JSON object holding both MD5 and SHA1 digests for the certificate request and the certificate; note that this is the digest of the DER contents of the certificate, not the PEM contents * bundle: See the result of endpoint_bundle.txt (only included if the bundle parameter was set) Example: $ curl -d '{ "request": {"hosts":["www.example.com"], "names":[{"C":"US", "ST":"California", "L":"San Francisco", "O":"example.com"}], "CN": "www.example.com"} }' \ ${CFSSL_HOST}/api/v1/cfssl/newcert \ | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 2487 0 2338 100 149 56536 3603 --:--:-- --:--:-- --:--:-- 57024 { "errors": [], "messages": [], "result": { "certificate": "-----BEGIN CERTIFICATE-----\nMIIDRzCCAjGgAwIBAgIIV2zafpyQtp4wCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG\nEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj\nbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVTVCBSb290\nIENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTUwODAzMDYx\nMjAwWhcNMTYwODAyMDYxMjAwWjBqMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLZXhh\nbXBsZS5jb20xFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlm\nb3JuaWExGDAWBgNVBAMTD3d3dy5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqG\nSM49AwEHA0IABK/CtZaQ4VliKE+DLIVGLwtSxJgtUKRzGvN1EwI3HRgKDQ3l3urB\nIzHtUcdMq6HZb8jX0O9fXYUOf4XWggrLk1ajgZwwgZkwDgYDVR0PAQH/BAQDAgCg\nMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0G\nA1UdDgQWBBTF8UwoRdK0rWK8FWiyRxl3H2Wr+TAfBgNVHSMEGDAWgBS30veEuqg5\n1fusEM4p/YuWpBPsvTAaBgNVHREEEzARgg93d3cuZXhhbXBsZS5jb20wCwYJKoZI\nhvcNAQELA4IBAQCT+9xoBO39nFesT0dmdqpwHExU09/IYrkvYwWesX5U9z/f3HYP\nLz/NnXIs6a+k8MglvZgHwr5R8nzVtayfPTWyML6L6AOX8EfV5UXbnXW4XRUhHAik\n+E1gYhOCD1dLQJyQkX8VVr725BUk1yQD3Kf0PJUvagLJjn8Gn7QoGWfvVgpR8iMd\ncBJqlx8Z9KCYcLrpXliD8OJqT7Z8TGbnehpcaNwPPI6dMX57wgXSNuP5g8OkxMcL\nxZEP3q9JRjN3ZiM5xIeoTc/zl1WhZ+YpOHSbv/T9DX3f74ms9GEc0JnR8iENJTu6\nRx0/qPDPpqZ+Fr9v/13/OvQ+jAY5qe/6l1d6\n-----END CERTIFICATE-----\n", "certificate_request": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBUjCB+QIBADBqMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLZXhhbXBsZS5jb20x\nFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExGDAW\nBgNVBAMTD3d3dy5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\nBK/CtZaQ4VliKE+DLIVGLwtSxJgtUKRzGvN1EwI3HRgKDQ3l3urBIzHtUcdMq6HZ\nb8jX0O9fXYUOf4XWggrLk1agLTArBgkqhkiG9w0BCQ4xHjAcMBoGA1UdEQQTMBGC\nD3d3dy5leGFtcGxlLmNvbTAKBggqhkjOPQQDAgNIADBFAiAcvfhXnsLtzep2sKSa\n36W7G9PRbHh8zVGlw3Hph8jR1QIhAKfrgplKwXcUctU5grjQ8KXkJV8RxQUo5KKs\ngFnXYtkb\n-----END CERTIFICATE REQUEST-----\n", "private_key": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIJfVVIvXclN1jCWefEwhYYq7y1ya2RjxO5o8QjehD3YdoAoGCCqGSM49\nAwEHoUQDQgAEr8K1lpDhWWIoT4MshUYvC1LEmC1QpHMa83UTAjcdGAoNDeXe6sEj\nMe1Rx0yrodlvyNfQ719dhQ5/hdaCCsuTVg==\n-----END EC PRIVATE KEY-----\n", "sums": { "certificate": { "md5": "E9308D1892F1B77E6721EA2F79C026BE", "sha-1": "4640E6DEC2C40B74F46C409C1D31928EE0073D25", "sha-256": "8812010B59EB8C00CDD9292078717216B131A710703F18A4DFB94AC166F507DF" }, "certificate_request": { "md5": "AA924136405006E36CEE39FED9CBA5D7", "sha-1": "DF955A43DF669D38E07BF0479789D13881DC9024", "sha-256": "C7600A68BDB689346E2E4438A374606DFC3FFD3B6B9722E0A8CB32AA88FBA686" } } }, "success": true } ================================================ FILE: doc/api/endpoint_newkey.txt ================================================ THE CSR GENERATING ENDPOINT Endpoint: /api/v1/cfssl/newkey Method: POST Required parameters: * hosts: the list of SANs (subject alternative names) for the requested CSR (certificate signing request) * names: the certificate subject for the requested CSR Optional parameters: * CN: the common name for the certificate subject in the requested CSR. * key: the key algorithm and size for the newly generated private key, default to ECDSA-256 * ca: the CA configuration of the requested CSR, including CA pathlen and CA default expiry Result: The returned result is a JSON object with three keys: * private key: a PEM-encoded private key * certificate_request: a PEM-encoded certificate request * sums: a JSON object holding both MD5 and SHA1 digests for the certificate request Example: $ curl -d '{"hosts":["www.example.com"], "names":[{"C":"US", "ST":"California", "L":"San Francisco", "O":"example.com"}], "CN": "www.example.com"}' \ ${CFSSL_HOST}/api/v1/cfssl/newkey \ | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1132 100 997 100 135 80572 10909 --:--:-- --:--:-- --:--:-- 83083 { "errors": [], "messages": [], "result": { "certificate_request": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBUTCB+QIBADBqMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLZXhhbXBsZS5jb20x\nFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExGDAW\nBgNVBAMTD3d3dy5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\nBKjGougrsMC6d8+kD4iACNHEGxo3SR4rhg/6n3HWlH4c9f2lNT92juNggq6cakNw\n5LexZmwHDi970YPgdFVSrJWgLTArBgkqhkiG9w0BCQ4xHjAcMBoGA1UdEQQTMBGC\nD3d3dy5leGFtcGxlLmNvbTAKBggqhkjOPQQDAgNHADBEAiBAfw0rotVugRtcqKWF\nnU9DwHXC7nKP4RUVodJo1oGuOwIgYH3hDgSMFsheuvhdzt7ZvLutWHkk6yIRLxJr\ncGsO9/c=\n-----END CERTIFICATE REQUEST-----\n", "private_key": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIO4Nlcbg29aPBqrBowuONq5U2HlvE/xOaCV65gXZ7NPQoAoGCCqGSM49\nAwEHoUQDQgAEqMai6CuwwLp3z6QPiIAI0cQbGjdJHiuGD/qfcdaUfhz1/aU1P3aO\n42CCrpxqQ3Dkt7FmbAcOL3vRg+B0VVKslQ==\n-----END EC PRIVATE KEY-----\n", "sums": { "certificate_request": { "md5": "95E25336DA65B58DA250C3B5FAA4B97F", "sha-1": "5F1ACE9D14F55E95FAA246A80474873C14E0F42F", "sha-256": "EA8409AE9117FE62A91DBD64F2C7496DC4CF3A06C5D513D5811A1CC1E8B2D180" } } }, "success": true } ================================================ FILE: doc/api/endpoint_revoke.txt ================================================ THE REVOKE ENDPOINT Endpoint: /api/v1/cfssl/revoke Method: POST Required parameters: * serial: a string specifying the serial number of a certificate in decimal format * authority_key_id: a string specifying the authority key identifier of the certificate to be revoked; this is used to distinguish which private key was used to sign the certificate. Should be formatted without colons and all lowercase. * reason: a string identifying why the certificate was revoked; see, for example, ReasonStringToCode in the ocsp package or section 4.2.1.13 of RFC 5280. The "reasons" used here are the ReasonFlag names in said RFC. Result: The returned result is an empty JSON object Example: $ curl -d '{"serial": "7961067322630364137", \ "authority_key_id": "a0b1c2d3e4f5", \ "reason": "superseded"}' \ ${CFSSL_HOST}/api/v1/cfssl/revoke ================================================ FILE: doc/api/endpoint_scan.txt ================================================ THE SCAN ENDPOINT Endpoint: /api/v1/cfssl/scan Method: GET Required parameters: * host: the hostname (optionally including port) to scan Optional parameters: * ip: IP Address to override DNS lookup of host * timeout: The amount of time allotted for the scan to complete (default: 1 minute) The following parameters are used by the scanner to select which scans to run. * family: regular expression specifying scan famil(ies) to run * scanner: regular expression specifying scanner(s) to run Result: The returned result is a JSON object with keys for each scan family. Each of these objects contains keys for each scanner run in that family pointing to objects possibly containing the following keys: * grade: a string describing the exit status of the scan. Can be: * "Good": host performing the expected state-of-the-art * "Warning": host with non-ideal configuration, possibly maintaining support for legacy clients * "Bad": host with serious misconfiguration or vulnerability * "Skipped": indicates that the scan was not performed for some reason * error: any error encountered during the scan process * output: arbitrary JSON data retrieved during the scan Example: $ curl ${CFSSL_HOST}/api/v1/cfssl/scan?host=cloudflare.com |python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 2358 0 2358 0 0 833 0 --:--:-- 0:00:02 --:--:-- 833 { "errors": [], "messages": [], "result": { "Broad": { "IntermediateCAs": { "grade": "Skipped" } }, "Connectivity": { "CloudFlareStatus": { "grade": "Good", "output": { "198.41.214.163": true, "198.41.215.163": true, "2400:cb00:2048:1::c629:d49d": true, "2400:cb00:2048:1::c629:d59d": true } }, "DNSLookup": { "grade": "Good", "output": [ "2400:cb00:2048:1::c629:d49d", "2400:cb00:2048:1::c629:d59d", "198.41.214.163", "198.41.215.163" ] }, "TCPDial": { "grade": "Good" }, "TLSDial": { "grade": "Good" } }, "PKI": { "ChainExpiration": { "grade": "Good", "output": "2015-12-31T23:59:59Z" }, "ChainValidation": { "grade": "Warning", "output": [ " is signed by RSAWithSHA1", "COMODO Extended Validation Secure Server CA is signed by RSAWithSHA1" ] }, "MultipleCerts": { "grade": "Good" } }, "TLSHandshake": { "CipherSuite": { "grade": "Good", "output": [ { "ECDHE-RSA-AES128-GCM-SHA256": [ { "TLS 1.2": [ "secp256r1" ] } ] }, { "ECDHE-RSA-AES128-SHA256": [ { "TLS 1.2": [ "secp256r1" ] } ] }, { "ECDHE-RSA-AES128-SHA": [ { "TLS 1.2": [ "secp256r1" ] }, { "TLS 1.1": [ "secp256r1" ] }, { "TLS 1.0": [ "secp256r1" ] } ] }, { "AES128-GCM-SHA256": [ "TLS 1.2" ] }, { "AES128-SHA256": [ "TLS 1.2" ] }, { "AES128-SHA": [ "TLS 1.2", "TLS 1.1", "TLS 1.0" ] }, { "ECDHE-RSA-AES256-GCM-SHA384": [ { "TLS 1.2": [ "secp256r1" ] } ] }, { "ECDHE-RSA-AES256-SHA384": [ { "TLS 1.2": [ "secp256r1" ] } ] }, { "ECDHE-RSA-AES256-SHA": [ { "TLS 1.2": [ "secp256r1" ] }, { "TLS 1.1": [ "secp256r1" ] }, { "TLS 1.0": [ "secp256r1" ] } ] }, { "AES256-GCM-SHA384": [ "TLS 1.2" ] }, { "AES256-SHA256": [ "TLS 1.2" ] }, { "AES256-SHA": [ "TLS 1.2", "TLS 1.1", "TLS 1.0" ] }, { "ECDHE-RSA-DES-CBC3-SHA": [ { "TLS 1.2": [ "secp256r1" ] }, { "TLS 1.1": [ "secp256r1" ] }, { "TLS 1.0": [ "secp256r1" ] } ] }, { "DES-CBC3-SHA": [ "TLS 1.2", "TLS 1.1", "TLS 1.0" ] } ] }, "SigAlgs": { "grade": "Good", "output": [ { "hash": "SHA1", "signature": "RSA" }, { "hash": "SHA1", "signature": "DSA" }, { "hash": "SHA1", "signature": "ECDSA" }, { "hash": "SHA224", "signature": "RSA" }, { "hash": "SHA224", "signature": "DSA" }, { "hash": "SHA224", "signature": "ECDSA" }, { "hash": "SHA256", "signature": "RSA" }, { "hash": "SHA256", "signature": "DSA" }, { "hash": "SHA256", "signature": "ECDSA" }, { "hash": "SHA384", "signature": "RSA" }, { "hash": "SHA384", "signature": "DSA" }, { "hash": "SHA384", "signature": "ECDSA" }, { "hash": "SHA512", "signature": "RSA" }, { "hash": "SHA512", "signature": "DSA" }, { "hash": "SHA512", "signature": "ECDSA" } ] } }, "TLSSession": { "SessionResume": { "grade": "Good", "output": { "198.41.214.163": true, "198.41.215.163": true, "2400:cb00:2048:1::c629:d49d": true, "2400:cb00:2048:1::c629:d59d": true } } } }, "success": true } $ curl "${CFSSL_HOST}/api/v1/cfssl/scan?host=cloudflare.com&ip=2400:cb00:2048:1::c629:d49d" |python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 3602 0 3602 0 0 337 0 --:--:-- 0:00:10 --:--:-- 1044 { "errors": [], "messages": [], "result": { "Connectivity": { "CloudFlareStatus": { "grade": "Good", "output": { "198.41.214.163": true, "198.41.215.163": true, "2400:cb00:2048:1::c629:d49d": true, "2400:cb00:2048:1::c629:d59d": true } }, "DNSLookup": { "grade": "Good", "output": [ "2400:cb00:2048:1::c629:d59d", "2400:cb00:2048:1::c629:d49d", "198.41.215.163", "198.41.214.163" ] }, "TCPDial": { "grade": "Good" }, "TLSDial": { "grade": "Good" } }, "PKI": { "ChainExpiration": { "grade": "Good", "output": "2015-12-31T23:59:59Z" }, "ChainValidation": { "grade": "Warning", "output": [ " is signed by RSAWithSHA1", "Certificate for COMODO Extended Validation Secure Server CA is valid for too long", "COMODO Extended Validation Secure Server CA is signed by RSAWithSHA1" ] }, "MultipleCerts": { "grade": "Good" } }, "TLSHandshake": { "CertsByCiphers": { "grade": "Good", "output": { "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": "SHA1WithRSA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": "SHA1WithRSA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": "SHA1WithRSA", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": "SHA1WithRSA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": "SHA1WithRSA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384": "SHA1WithRSA", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": "SHA1WithRSA", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": "SHA1WithRSA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA": "SHA1WithRSA", "TLS_RSA_WITH_AES_128_CBC_SHA": "SHA1WithRSA", "TLS_RSA_WITH_AES_128_CBC_SHA256": "SHA1WithRSA", "TLS_RSA_WITH_AES_128_GCM_SHA256": "SHA1WithRSA", "TLS_RSA_WITH_AES_256_CBC_SHA": "SHA1WithRSA", "TLS_RSA_WITH_AES_256_CBC_SHA256": "SHA1WithRSA", "TLS_RSA_WITH_AES_256_GCM_SHA384": "SHA1WithRSA" } }, "CertsBySigAlgs": { "grade": "Good", "output": { "{DSA,SHA1}": "SHA1WithRSA", "{DSA,SHA224}": "SHA1WithRSA", "{DSA,SHA256}": "SHA1WithRSA", "{DSA,SHA384}": "SHA1WithRSA", "{DSA,SHA512}": "SHA1WithRSA", "{ECDSA,SHA1}": "SHA1WithRSA", "{ECDSA,SHA224}": "SHA1WithRSA", "{ECDSA,SHA256}": "SHA1WithRSA", "{ECDSA,SHA384}": "SHA1WithRSA", "{ECDSA,SHA512}": "SHA1WithRSA", "{RSA,SHA1}": "SHA1WithRSA", "{RSA,SHA224}": "SHA1WithRSA", "{RSA,SHA256}": "SHA1WithRSA", "{RSA,SHA384}": "SHA1WithRSA", "{RSA,SHA512}": "SHA1WithRSA" } }, "CipherSuite": { "grade": "Good", "output": [ { "ECDHE-RSA-AES128-GCM-SHA256": [ { "TLS 1.2": [ "secp256r1" ] } ] }, { "ECDHE-RSA-AES128-SHA256": [ { "TLS 1.2": [ "secp256r1" ] } ] }, { "ECDHE-RSA-AES128-SHA": [ { "TLS 1.2": [ "secp256r1" ] }, { "TLS 1.1": [ "secp256r1" ] }, { "TLS 1.0": [ "secp256r1" ] } ] }, { "AES128-GCM-SHA256": [ "TLS 1.2" ] }, { "AES128-SHA256": [ "TLS 1.2" ] }, { "AES128-SHA": [ "TLS 1.2", "TLS 1.1", "TLS 1.0" ] }, { "ECDHE-RSA-AES256-GCM-SHA384": [ { "TLS 1.2": [ "secp256r1" ] } ] }, { "ECDHE-RSA-AES256-SHA384": [ { "TLS 1.2": [ "secp256r1" ] } ] }, { "ECDHE-RSA-AES256-SHA": [ { "TLS 1.2": [ "secp256r1" ] }, { "TLS 1.1": [ "secp256r1" ] }, { "TLS 1.0": [ "secp256r1" ] } ] }, { "AES256-GCM-SHA384": [ "TLS 1.2" ] }, { "AES256-SHA256": [ "TLS 1.2" ] }, { "AES256-SHA": [ "TLS 1.2", "TLS 1.1", "TLS 1.0" ] }, { "ECDHE-RSA-DES-CBC3-SHA": [ { "TLS 1.2": [ "secp256r1" ] }, { "TLS 1.1": [ "secp256r1" ] }, { "TLS 1.0": [ "secp256r1" ] } ] }, { "DES-CBC3-SHA": [ "TLS 1.2", "TLS 1.1", "TLS 1.0" ] } ] }, "SigAlgs": { "grade": "Good", "output": [ { "hash": "SHA1", "signature": "RSA" }, { "hash": "SHA1", "signature": "DSA" }, { "hash": "SHA1", "signature": "ECDSA" }, { "hash": "SHA224", "signature": "RSA" }, { "hash": "SHA224", "signature": "DSA" }, { "hash": "SHA224", "signature": "ECDSA" }, { "hash": "SHA256", "signature": "RSA" }, { "hash": "SHA256", "signature": "DSA" }, { "hash": "SHA256", "signature": "ECDSA" }, { "hash": "SHA384", "signature": "RSA" }, { "hash": "SHA384", "signature": "DSA" }, { "hash": "SHA384", "signature": "ECDSA" }, { "hash": "SHA512", "signature": "RSA" }, { "hash": "SHA512", "signature": "DSA" }, { "hash": "SHA512", "signature": "ECDSA" } ] } }, "TLSSession": { "SessionResume": { "grade": "Good", "output": { "2400:cb00:2048:1::c629:d49d": true } } } }, "success": true } ================================================ FILE: doc/api/endpoint_scaninfo.txt ================================================ THE SCANINFO ENDPOINT Endpoint: /api/v1/cfssl/scaninfo Method: GET Result: The returned result is a JSON object with keys for each scan family. For each family, there exists a `description` containing a string describing the family and a `scanners` object mapping each of the family's scanners to an object containing a `description` string. Example: $ curl ${CFSSL_HOST}/api/v1/cfssl/scaninfo | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1412 100 1412 0 0 391k 0 --:--:-- --:--:-- --:--:-- 459k { "errors": [], "messages": [], "result": { "Broad": { "description": "Large scale scans of TLS hosts", "scanners": { "IntermediateCAs": { "description": "Scans a CIDR IP range for unknown Intermediate CAs" } } }, "Connectivity": { "description": "Scans for basic connectivity with the host through DNS and TCP/TLS dials", "scanners": { "CloudFlareStatus": { "description": "Host is on CloudFlare" }, "DNSLookup": { "description": "Host can be resolved through DNS" }, "TCPDial": { "description": "Host accepts TCP connection" }, "TLSDial": { "description": "Host can perform TLS handshake" } } }, "PKI": { "description": "Scans for the Public Key Infrastructure", "scanners": { "ChainExpiration": { "description": "Host's chain hasn't expired and won't expire in the next 30 days" }, "ChainValidation": { "description": "All certificates in host's chain are valid" }, "MultipleCerts": { "description": "Host serves same certificate chain across all IPs" } } }, "TLSHandshake": { "description": "Scans for host's SSL/TLS version and cipher suite negotiation", "scanners": { "CipherSuite": { "description": "Determines host's cipher suites accepted and prefered order" }, "SigAlgs": { "description": "Determines host's accepted signature and hash algorithms" } } }, "TLSSession": { "description": "Scans host's implementation of TLS session resumption using session tickets/session IDs", "scanners": { "SessionResume": { "description": "Host is able to resume sessions across all addresses" } } } }, "success": true } ================================================ FILE: doc/api/endpoint_sign.txt ================================================ THE SIGNING ENDPOINT Endpoint: /api/v1/cfssl/sign Method: POST Required parameters: * certificate_request: the CSR bytes to be signed in PEM Optional parameters: * hosts: an array of SAN (subject alternative names) which overrides the ones in the CSR * subject: the certificate subject which overrides the ones in the CSR * serial_sequence: a string specify the prefix which the generated certificate serial should have * label: a string specifying which signer to be appointed to sign the CSR, useful when interacting with a remote multi-root CA signer * profile: a string specifying the signing profile for the signer, useful when interacting with a remote multi-root CA signer * bundle: a boolean specifying whether to include an "optimal" certificate bundle along with the certificate Result: The returned result is a JSON object with a single key: * certificate: a PEM-encoded certificate that has been signed by the server. * bundle: See the result of endpoint_bundle.txt (only included if the bundle parameter was set) Example: $ curl -d '{"certificate_request": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBUjCB+QIBADBqMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLZXhhbXBsZS5jb20x\nFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExGDAW\nBgNVBAMTD3d3dy5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA\nBK/CtZaQ4VliKE+DLIVGLwtSxJgtUKRzGvN1EwI3HRgKDQ3l3urBIzHtUcdMq6HZ\nb8jX0O9fXYUOf4XWggrLk1agLTArBgkqhkiG9w0BCQ4xHjAcMBoGA1UdEQQTMBGC\nD3d3dy5leGFtcGxlLmNvbTAKBggqhkjOPQQDAgNIADBFAiAcvfhXnsLtzep2sKSa\n36W7G9PRbHh8zVGlw3Hph8jR1QIhAKfrgplKwXcUctU5grjQ8KXkJV8RxQUo5KKs\ngFnXYtkb\n-----END CERTIFICATE REQUEST-----\n"}' \ ${CFSSL_HOST}/api/v1/cfssl/sign \ | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1859 100 1287 100 572 27265 12117 --:--:-- --:--:-- --:--:-- 27382 { { "errors": [], "messages": [], "result": { "certificate": "-----BEGIN CERTIFICATE-----\nMIIDRzCCAjGgAwIBAgIIHQdm46rELPQwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG\nEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj\nbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVTVCBSb290\nIENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTUwODAzMDYx\nNDAwWhcNMTYwODAyMDYxNDAwWjBqMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLZXhh\nbXBsZS5jb20xFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlm\nb3JuaWExGDAWBgNVBAMTD3d3dy5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqG\nSM49AwEHA0IABK/CtZaQ4VliKE+DLIVGLwtSxJgtUKRzGvN1EwI3HRgKDQ3l3urB\nIzHtUcdMq6HZb8jX0O9fXYUOf4XWggrLk1ajgZwwgZkwDgYDVR0PAQH/BAQDAgCg\nMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0G\nA1UdDgQWBBTF8UwoRdK0rWK8FWiyRxl3H2Wr+TAfBgNVHSMEGDAWgBS30veEuqg5\n1fusEM4p/YuWpBPsvTAaBgNVHREEEzARgg93d3cuZXhhbXBsZS5jb20wCwYJKoZI\nhvcNAQELA4IBAQBR86I/5ChcvdFxSypKOzZMT5CSJMN8rSFfjq+fAP2jMbdVvavR\n9cFdOncosNmDLhifqMx9Cj8pAXtOQcZ+BWEewwEsPYTYorPHSawroMMIO216tufm\nIRj0oPIL8PxRuKwRBtpeIU7F/Z/iGPblSwujunvetEu43i5Zsrh11YkpJ7bIKc9K\nOLaCNIER+tIj9noUA2r6VtMRqSyfwUVslSxirDit9GyuS9wrA563CVicMG5pqtyX\nnTNJqUAgcOy4u1JcJuv24ZNtMBJbzQA1nBI60YPd0VoWQLfnN0qVmR61Av5mTLau\n9Hzx3otLLWcsBUunMR/Zd/GDOlLByEVLRxD9\n-----END CERTIFICATE-----\n" }, "success": true } ================================================ FILE: doc/api/intro.txt ================================================ INTRODUCTION TO THE CFSSL API The CFSSL API allows applications to access the functionality of CFSSL over an unauthenticated HTTP connection. By default, the API is unauthenticated, it is important to understand that the CFSSL API server must be running in a trusted environment in this case. There are currently thirteen endpoints, each of which may be found under the path `/api/v1/cfssl/`. The documentation for each endpoint is found in the `doc/api` directory in the project source under the name `endpoint_`. These thirteen endpoints are: - authsign: authenticated signing endpoint - bundle: build certificate bundles - certinfo: lookup a certificate's info - crl: generates a CRL out of the certificate DB - health: return health status - info: obtain information about the CA, including the CA certificate - init_ca: initialise a new certificate authority - newcert: generate a new private key and certificate - newkey: generate a new private key and certificate signing request - revoke: revoke a certificate - scan: scan servers to determine the quality of their TLS set up - scaninfo: list options for scanning - sign: sign a certificate RESPONSES Responses take the form of the new CloudFlare API response format: { "result": , "success": true, "errors": [], "messages": [], } Both the "messages" and "errors" fields have the same general format: a message or error has the form { "code:" 1234, "message": "Informative message." } If "success" is not "true", the result should be discarded, and the errors examined to determine what happened. The CFSSL error codes are documented in the `doc/errors.txt` file in the project source. ================================================ FILE: doc/authentication.txt ================================================ CFSSL AUTHENTICATION In order to prevent a CFSSL signer from being directly available, an authentication mechanism is available to provide additional security. It is implemented as the concept of an authentication provider; a provider can generate "authentication tokens" for a given request, and verify that the token is valid for a given request. Requests are generally the JSON-encoded form of the request to be sent to the server. An authenticated request has the following fields: * token: this is a required field; it contains the computed authentication token. * request: this is a required field; the JSON-encoded request being made. * timestamp: an optional field containing a Unix timestamp. This might be used by an authentication provider; the standard authenticator does not use this. * remote_address: an optional field containing the address or hostname of the server; this may be used by an authentication provider. The standard authenticator does not use this field. The standard authenticator provided as a reference implementation uses HMAC-SHA-256 to compute the HMAC of the request, with the hex-encoded authentication key specified in the configuration file. The key may be specified in one of three ways: * hex-encoded string (e.g. "000102030405060708") * an environment variable prefixed with "env:" (e.g. "env:AUTH_KEY") that contains a hex-encoded string. * a path to a file containing the hex-encoded key, prefixed with "file:" (e.g. "file:/path/to/auth.key") ================================================ FILE: doc/ca-bundle.crt.metadata.sample ================================================ [ { "name":"Mozilla", "weight": 100, "hash_algo": "SHA2", "key_algo": "ECDSA256", "keystore": "misc/trusted_roots/nss.pem" } ] ================================================ FILE: doc/cmd/cfssl.txt ================================================ THE CFSSL PROGRAM The CFSSL program is a TLS / PKI tool that provides command line tools for * bundling certificates * create private keys, certificate signing requests, and certificates * signing certificate signing requests * scanning a host to evaluate its TLS security * signing OCSP requests * running a CA server * running an OCSP server The cfssl server can be used either as a standalone server or as a set of locally-running instances that talk to a remote CA. For example, a set of servers might run the cfssl program locally to facilitate generating certificates for services on the server. These local servers can be configured to send their certificate signing requests to a remote cfssl or multirootca server that actually contains the signing key(s). CONFIGURATION The configuration file for cfssl is a JSON dictionary with keys for signing profiles, OCSP configuration, authentication, and remote servers. AUTHENTICATION See also: authentication.txt Authentication is used to restrict access to the signing keys when cfssl is run as a server. A client making a request generates an authentication token for their request, submitting this token alongside the request. The authentication section is used to tell cfssl that authentication is required and how to authenticate. This section consists of a dictionary of authenticators under the key "auth_keys"; each authenticator should have the keys "type" and "key", both strings. For example, to use the standard authenticator with the (hex-encoded) key "0123456789ABCDEF0123456789ABCDEF" as the "primary" authenticator, the "auth_keys" section might look like "auth_keys": { "primary": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } } The authentication documentation covers available authenticators and their key formats. REMOTE SIGNERS A local cfssl instance can forward signing requests to another instance; this might be useful where the CA keys should remain on only one machine. A remote is specified as a host:port, or as a comma-separated list of host:ports. If the remote is a comma-separated list, each server will be tried in sequence until one succeeds. That is, if the list is "ca1.example.org:8888, ca2.example.org:8888, ca3.example.org:8888" each signing request will first go to ca1, falling back to ca2 if this fails, and finally falling back to ca3. SIGNING PROFILES CFSSL supports different profiles for generating various types of certificates, as well as a default profile to be used when no profile is given. A signing profile may contain the following fields, requiring at a minimum the expiry field. Fields that are not required may be left blank. + expiry: This should contain a time duration in the form understood by Go's time package[1]. This unfortunately means that the maximum unit of time that can be used here is the hour. + usages: strings of key usages. The following are acceptable key usages: + Key Usages + signing + digital signature + content commitment + key encipherment + key agreement + data encipherment + cert sign + crl sign + encipher only + decipher only + Ext Key Usages + any + server auth + client auth + code signing + email protection + s/mime + ipsec end system + ipsec tunnel + ipsec user + timestamping + ocsp signing + microsoft sgc + netscape sgc + issuer_urls: a list of Authority Information Access (RFC 5280 4.2.2.1) URLs pointing to the issuer certificate. + ocsp_url: the URL of the OCSP server that should be used to check the certificate's status. + crl_url: the URL of the CRL server for this CA. + ca_constraint: this object controls the CA bit and CA pathlen constraint of the returned certificates. For example, in order to issue a intermediate CA certificate with pathlen = 1, we put {"is_ca": true, "max_path_len":1}. For another example, to issue an intermediate CA certificate with pathlen = 0, we put {"is_ca": true, "max_path_len":0, "max_path_len_zero": true}. Notice the extra "max_path_len_zero" field: Without it, the intermediate CA certificate will have no pathlen constraint. + ocsp_no_check: this should be true if the id-pkix-ocsp-nocheck extension should be used (RFC 2560 4.2.2.2.1). + backdate: this is a time duration (the same used for the expiry field) that specifies an amount of backdating to be applied to new certificates. + auth_key: this should contain the name of an authentication key specified in the authentication portion of the configuration file. This key should be used by clients using the authentication scheme described in 'authentication.txt'. + remote: this should contain the name of a remote signer as specified in the remote signer section of the configuration file. This is used for unauthenticated CFSSL remotes. + auth_remote: this is an object containing an "auth_key" and "remote" key. This is an entry for an authenticated remote signer. The "auth_key" should contain the name of an authentication key specified in the authentication portion of the configuration file, and "remote" should contain the name of a remote signer as specified in the remote signer section of the configuration file. + not_before: if provided, this specifies an override for the Not Before date in certificates signed by the CA. + not_after: if provided, this specifies an override for the Not After date in certificates signed by the CA. + name_whitelist: if provided, this should be a regular expression for permitted SANs. The signing profiles reside in the "signing" dictionary. This may contain a "default" field which contains the profile to use by default for requests, and a "profiles" dictionary mapping profile names to their profile. If the default profile isn't present, the following default profile is used: { "usages": ["signing", "key encipherment", "server auth", "client auth"], "expiry": "8760h" } The expiration time of 8760h is equivalent to one year. A minimal configuration file might look like: { "signing": { "profiles": { "CA": { "usages": ["cert sign"], "expiry": "720h", "auth_key": "ca-auth", "remote": "localhost" }, "email": { "usages": ["s/mime"], "expiry": "720h" } }, "default": { "usages": ["digital signature", "email protection"], "expiry": "8000h" } }, "auth_keys": { "ca-auth": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "127.0.0.1:8888" } } [1] https://golang.org/pkg/time/#ParseDuration ================================================ FILE: doc/cmd/multiroot.txt ================================================ THE MULTIROOTCA PROGRAM The multirootca program is an authenticated-signer-only server that is intended to be used as a remote server for cfssl instances. The scenario it was originally intended for is + running cfssl as a service on servers to generate keys + using multirootca as a remote signer to manage the CA keys for issuing certificates. The multirootca configuration file is an ini-style configuration file; various examples can be found in `multirootca/config/testdata`. [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json nets = 10.0.2.1/24,172.16.3.1/24, 192.168.3.15/32 [ backup ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json dbconfig = testdata/db-config.json This defines two signers, labelled "primary" and "backup". These are both using the same key, but in practice these keys will be different. The private key format is described below. The certificate entry points the certificate PEM file on disk, and the config entry points to a cfssl configuration file to use for each signer; the format of this file is described in "cfssl.txt". Optionally, a nets entry points to a comma-separated list of networks that should be permitted access to the signer. This list forms a whitelist; if it's not present, all networks are whitelisted for that signer. A dbconfig entry points to a certdb configuration file containing database connection details, see `certdb/README.md`. SPECIFYING A PRIVATE KEY Key specification take the form of a URL. There are currently two supported types of keys: + private key files: these are specified with the "file://" protocol. The rest of the URL should specify a path on disk where the key may be found. + rofile: these are specified with the "rofile://" protocol. The path should point to a file that is encrypted using Red October[1]. If this private key type is specified, the following entries must also be provided: + ro_server: the hostname:port of the Red October server + ro_user: the username for the Red October server + ro_pass: the password for the Red October server Optionally: + ro_ca: this can be used to specify a CA roots file to override the system roots. [1] https://github.com/cloudflare/redoctober ================================================ FILE: doc/errorcode.txt ================================================ 1XXX: CertificateError 1000: Unknown 1001: ReadFailed 1002: DecodeFailed 1003: ParseFailed 1100: SelfSigned 12XX: VerifyFailed 121X: CertificateInvalid 1210: NotAuthorizedToSign 1211: Expired 1212: CANotAuthorizedForThisName 1213: TooManyIntermediates 1214: IncompatibleUsage 1220: UnknownAuthority 1300: BadRequest 1400: MissingSerial 2XXX: PrivateKeyError 2000: Unknown 2001: ReadFailed 2002: DecodeFailed 2003: ParseFailed 2100: Encrypted 2200: NotRSA 2300: KeyMismatch 3XXX: IntermediatesError 4XXX: RootError 5XXX: PolicyError 5100: NoKeyUsages 5200: InvalidPolicy 5300: InvalidRequest 5400: UnknownProfile 5500: UnmatchedWhitelist 6XXX: DialError 7XXX: APIClientError 7100: AuthenticationFailure 7200: JSONError 7300: IOError 7400: ClientHTTPError 7500: ServerRequestFailed 8XXX: OCSPError 8001: ReadFailed 8100: IssuerMismatch 8200: InvalidStatus 9XXX: CSRError 9001: ReadFailed 9002: DecodeFailed 9003: ParseFailed 9300: BadRequest 10XXX: CTError 10000: Unknown 10100: PrecertSubmissionFailed 11XXX: CertStoreError 11100: InsertFailed 11200: RecordNotFound ================================================ FILE: doc/transport.txt ================================================ Using the transport package =========================== The transport package is designed to provide automated mutually- authenticated and server-only TLS security with proper security settings for Go programs. Mutually-authenticated means that clients will strictly validate the server's certificate, and servers will require that clients present a valid client authentication certificate. Adding the transport package to a project consists of a few steps: 1. Planning the right communications model. 2. Determining the configuration. 3. Adding the transport package to the project. Each of these steps will be covered in sequence, with the examples under transport/example/ used as illustrations. Some terminology: certificate provider: an interface to a CA that will sign CSRs and return certificates. The only available certificate provider at this time is CFSSL. key provider: mechanism for providing keys and signing certificate signing requests (CSRs). The only available key provider at this time is a disk-backed key set. root: the public certificate for a certificate authority (CA). This certificate is used to verify the certificate of a remote system: a client authentication root specifies the CA that a server uses to verify clients. The unqualified term root usually refers to a CA certificate that a client uses to verify a server's certificate. Transport package communication models -------------------------------------- There are three models for communications: 1. A general TLS listener, such as a public HTTPS server. In this model, the server does not expect clients to authenticate themselves to the server using client authentication certificates. This listener doesn't need to configure any roots. 2. A mutually-authenticated TCP server. This can be an HTTPS server that requires client authentication, or any other TCP server that wants to set up mutually-authenticated communications. A server will construct a `Listener` and call the `Listen` method on that structure (this will be useful to remember later). 3. A mutually-authenticated TCP client. This can be an HTTPS client that supplies a client authentication certificate, or any other TCP client setting up a mutually-authenticated connection. A client will call `Dial` from a `Transport` structure. Once the model is determined, the configuration can be built. Transport package configuration ------------------------------- In general, the transport package is build around the `core.Identity` type. This contains several top-level fields: + `Request` contains a `CertificateRequest` from the CFSSL csr package (e.g. https://godoc.org/github.com/cloudflare/cfssl/csr#CertificateRequest). The JSON tag for this field is "request". + `Profiles` contains profiles for certificate and key providers. The JSON tag for this field is "profiles". + `Roots` specifies roots that are used by clients to verify server certificates. The JSON tag for this field is "roots". + `ClientRoots` specifies roots that are used by servers to verify client certificates. The JSON tag for this field is "client_roots". The `Identity` structure is set up so that it could be integrated into a current configuration set up, or it can be present as a standalone configuration. The example programs use the code // conf is a string contain the path to a JSON configuration // file. var id = new(core.Identity) data, err := os.ReadFile(conf) if err != nil { exlib.Err(1, err, "reading config file") } err = json.Unmarshal(data, id) if err != nil { exlib.Err(1, err, "parsing config file") } to load a standalone transport configuration file in JSON. The `Profiles` field configures both key providers and certificate authorities. Key providers use the key request in the `Request` field to determine what sort of key to generate, and the rest of the field to determine the certificate signing request to generate. The only key-provider supported right now is the "path" provider, which would be configured something like // id is a core.Identity value. id.Profiles["path"] = map[string]string{ "private_key": "/path/to/key.pem", "certificate": "/path/to/cert.pem", } The path provider determines whether a private key exists at the path provided; if it does not, a key is generated. If a certificate exists at the configured path, it is loaded --- if it's valid, it's kept. Otherwise, when the transport setup occurs, a new certificate will be requested. If the path fields are empty, then the keys will never be stored on disk; the "path" key must still be present though. // A path configuration for keys that are never stored on // disk. id["profiles"]["path"] = map[string]string{} When the key provider determines that its certificate is out of date (or, in the case of auto-updating, at some interval before the certificate expires), it will generate a CSR and pass it to a certificate provider. A CFSSL certificate provider points to a CFSSL server. It supports the following keys: + "remote" provides the hostname/IP and port for the CFSSL server. + "label" identifies which signer in a multiroot CFSSL should be used. An empty or missing label assumes the remote's default label will be used. + "profile" identifies the signing profile. An empty or missing profile assumes the remote's default profile will be used. + "auth-type" should be present if the remote CFSSL needs authentication. It tells the transport package what type of authentication to use. The authentication system in CFSSL is documented in "doc/authentication.txt"; for now, the only available authentication type is "standard". + "auth-key" specifies the authentication key in the case where the remote CFSSL requires authentication. Details are in "doc/authentication.txt", particularly the section covering key specification. As of now, The key may be specified in one of three ways: * hex-encoded string (e.g. "000102030405060708") * an environment variable prefixed with "env:" (e.g. "env:AUTH_KEY") that contains a hex-encoded string. * a path to a file containing the hex-encoded key, prefixed with "file:" (e.g. "file:/path/to/auth.key") A configuration that talks to the CFSSL instance running on ca.example.org might look like id["profiles"]["cfssl"] = map[string]string{ "remote": "ca.example.org:8888", "profile": "short-lived", "auth-type": "standard", "auth-key": "env:TRANSPORT_CA_AUTH_KEY", } where the auth key would be set up as $ TRANSPORT_CA_AUTH_KEY="000102030405060708" ./some-program The `Roots` and `ClientRoots` fields are set up the same way; they differ only in how they are used. The are an array of root structures. There are three supported types of roots, each specified with the "type" key: + system roots use the operating system's default set of roots + file load PEM-encoded certificates from a file + cfssl retrieves the CA certificate from a remote CFSSL instance The file and cfssl types should contain a "metadata" key that contains a `map[string]string` with further information. The file type looks for the "source" metadata key, which should contain a path to the file to be loaded. The cfssl type accepts the same arguments as the CFSSL certificate provider; note that CFSSL servers don't authenticate the info endpoint. If the metadata contains authentication information (e.g. because it was copied from the certificate provider specification), the authentication keys will be ignored. The following example loads the system roots, a set of root certificates stored in a "custom.pem" file, and the same CFSSL instance used above; they are used for server authentication in this example. id["roots"] = []*core.Root{ { Type: "system", }, { Type: "file", Metadata: map[string]string{ "source": "/etc/ssl/custom.pem", }, }, { Type: "cfssl", Metadata: map[string]string{ "remote": "ca.example.org:8888", "profile": "short-lived", }, }, } If the above configuration was placed into a JSON file, it would look like: { "request": { "CN": "Example Service Client", "hosts": [ "svc-client.example.org" ] }, "profiles": { "path": { "private_key": "/path/to/key.pem", "certificate": "/path/to/cert.pem" }, "cfssl": { "remote": "ca.example.org:8888", "profile": "short-lived", "auth-type": "standard", "auth-key": "env:TRANSPORT_CA_AUTH_KEY" } }, "roots": [ { "type": "system" }, { "type": "file", "metadata": { "source": "/etc/ssl/custom.pem" } }, { "type": "cfssl", "metadata": { "remote": "ca.example.org:8888", "profile": "short-lived" } } ] } This configuration would be used for a system using the third communications model discussed above. It could also be integrated into an existing configuration; an example of such a configuration would be type Configuration struct { Remote string // Server to connect to. Port int // Server's port. // Additional configuration fields follow Transport *core.Identity } Now that the service has a configuration, the transport package can be integrated into the code. Adding the transport package to a project ----------------------------------------- Somehow, the program needs to load the `Identity` described in the previous section. For the sake of this discussion, it's assumed to be in the `id` variable: var id core.Identity The next step is to build a `Transport` from this. A `Transport` is set up with a "before" time (how long before the certificate expires should the service attempt to update the certificate) and a `*Identity`. // The default is to get a new certificate one day prior to // its expiration. tr, err := transport.New(core.DefaultBefore, &id) if err != nil { log.Fatalf("failed to configure a new TLS transport: %s", err) } The auto-updater must be configured explicitly. It takes two arguments: the update channel and an error channel. If the update channel is non-nil, it will receive `time.Time` values indicating when the certificate was renewed. If the error channel is non-nil, it will receive `error` values from the auto updater. If an error in updating occurs, the updater will use a backoff to keep retrying. If the backoff isn't configured, a default backoff (using an interval of 5 minutes and a max delay of six hours) will be used. The values for the default interval and maximum duration are found in the `DefaultInterval` and `DefaultMaxDuration` variables in the `backoff` package; these can be changed to suit the program's needs. (c.f https://godoc.org/github.com/cloudflare/backoff#Backoff). Clients will call `AutoUpdate` on the `Transport` itself; servers should call `AutoUpdate` on the listener (discussed below). The following example logs update timestamps and errors for a client: updates := make(chan time.Time, 0) go func(updatesc <-chan time.Time) { for { t, ok := <-updatesc if !ok { return } log.Printf("certificate auto-updated at %s", t.Format(time.RFC3339)) } } errs := make(chan error, 0) go func(errsc <-chan error) { for { err, ok := <-errsc if !ok { return } log.Printf("certificate auto-update error: %s", err) } } go tr.AutoUpdate(updates, errs) A client may not want to start the auto-updater if the connection is expected to be short-lived. The package will check the certificate before the connection occurs, making sure it's still valid. At this point, the client can call the `Dial` function: conn, err := transport.Dial(address, tr) if err != nil { log.Fatalf("failed to dial remote host: %s", err) } The returned `conn` is a `*tls.Conn`, which is an implementation of `net.Conn`. Servers need one extra step before they are ready: l, err := transport.Listen(address, tr) if err != nil { loglFatalf("error setting up listener: %s", err) } // The same update channels go l.AutoUpdate(nil, nil) defer l.Close() for { conn, err := l.Accept() if err != nil { log.Printf("connection failed: %s", err) continue } log.Printf("connection from %s", conn.RemoteAddr()) go serveClient(conn) } Extending the transport package =============================== The package is set up to deliver a useful set of defaults, but these defaults won't be appropriate for everyone. There are several places where the behaviour can be altered. Additional root providers may be set up by adding the relevant entries to `roots.Providers`. This is a map of string names (e.g. the `Type` field) to a function that accepts the `Metadata` field (a `map[string]string`), and which returns a list of `*x509.Certificate`: var Providers map[string]func(map[string]string) ([]*x509.Certificate, error) The `NewKeyProvider` and `NewCA` functions provide a mechanism for choosing a key provider and CA from an identity. The default is to attempt to load the standard ("path") key provider and a CFSSL CA: var ( // NewKeyProvider is the function used to build key providers // from some identity. NewKeyProvider = func(id *core.Identity) (kp.KeyProvider, error) { return kp.NewStandardProvider(id) } // NewCA is used to load a configuration for a certificate // authority. NewCA = func(id *core.Identity) (ca.CertificateAuthority, error) { return ca.NewCFSSLProvider(id, nil) } ) By default, `AutoUpdate` checks the expiry on the certificate every thirty seconds. This behaviour may be changed by changing `transport.PollInterval`. If set to 0, the updater will just wait for the lifespan of the certificate. ================================================ FILE: errors/doc.go ================================================ /* Package errors provides error types returned in CF SSL. 1. Type Error is intended for errors produced by CF SSL packages. It formats to a json object that consists of an error message and a 4-digit code for error reasoning. Example: {"code":1002, "message": "Failed to decode certificate"} The index of codes are listed below: 1XXX: CertificateError 1000: Unknown 1001: ReadFailed 1002: DecodeFailed 1003: ParseFailed 1100: SelfSigned 12XX: VerifyFailed 121X: CertificateInvalid 1210: NotAuthorizedToSign 1211: Expired 1212: CANotAuthorizedForThisName 1213: TooManyIntermediates 1214: IncompatibleUsage 1220: UnknownAuthority 2XXX: PrivatekeyError 2000: Unknown 2001: ReadFailed 2002: DecodeFailed 2003: ParseFailed 2100: Encrypted 2200: NotRSA 2300: KeyMismatch 2400: GenerationFailed 2500: Unavailable 3XXX: IntermediatesError 4XXX: RootError 5XXX: PolicyError 5100: NoKeyUsages 5200: InvalidPolicy 5300: InvalidRequest 5400: UnknownProfile 6XXX: DialError 2. Type HttpError is intended for CF SSL API to consume. It contains a HTTP status code that will be read and returned by the API server. */ package errors ================================================ FILE: errors/error.go ================================================ package errors import ( "crypto/x509" "encoding/json" "fmt" ) // Error is the error type usually returned by functions in CF SSL package. // It contains a 4-digit error code where the most significant digit // describes the category where the error occurred and the rest 3 digits // describe the specific error reason. type Error struct { ErrorCode int `json:"code"` Message string `json:"message"` } // Category is the most significant digit of the error code. type Category int // Reason is the last 3 digits of the error code. type Reason int const ( // Success indicates no error occurred. Success Category = 1000 * iota // 0XXX // CertificateError indicates a fault in a certificate. CertificateError // 1XXX // PrivateKeyError indicates a fault in a private key. PrivateKeyError // 2XXX // IntermediatesError indicates a fault in an intermediate. IntermediatesError // 3XXX // RootError indicates a fault in a root. RootError // 4XXX // PolicyError indicates an error arising from a malformed or // non-existent policy, or a breach of policy. PolicyError // 5XXX // DialError indicates a network fault. DialError // 6XXX // APIClientError indicates a problem with the API client. APIClientError // 7XXX // OCSPError indicates a problem with OCSP signing OCSPError // 8XXX // CSRError indicates a problem with CSR parsing CSRError // 9XXX // CTError indicates a problem with the certificate transparency process CTError // 10XXX // CertStoreError indicates a problem with the certificate store CertStoreError // 11XXX ) // None is a non-specified error. const ( None Reason = iota ) // Warning code for a success const ( BundleExpiringBit int = 1 << iota // 0x01 BundleNotUbiquitousBit // 0x02 ) // Parsing errors const ( Unknown Reason = iota // X000 ReadFailed // X001 DecodeFailed // X002 ParseFailed // X003 ) // The following represent certificate non-parsing errors, and must be // specified along with CertificateError. const ( // SelfSigned indicates that a certificate is self-signed and // cannot be used in the manner being attempted. SelfSigned Reason = 100 * (iota + 1) // Code 11XX // VerifyFailed is an X.509 verification failure. The least two // significant digits of 12XX is determined as the actual x509 // error is examined. VerifyFailed // Code 12XX // BadRequest indicates that the certificate request is invalid. BadRequest // Code 13XX // MissingSerial indicates that the profile specified // 'ClientProvidesSerialNumbers', but the SignRequest did not include a serial // number. MissingSerial // Code 14XX ) const ( certificateInvalid = 10 * (iota + 1) //121X unknownAuthority //122x ) // The following represent private-key non-parsing errors, and must be // specified with PrivateKeyError. const ( // Encrypted indicates that the private key is a PKCS #8 encrypted // private key. At this time, CFSSL does not support decrypting // these keys. Encrypted Reason = 100 * (iota + 1) //21XX // NotRSAOrECCOrEd25519 indicates that they key is not an RSA or ECC or Ed25519 // private key; these are the only two private key types supported // at this time by CFSSL. NotRSAOrECCOrEd25519 //22XX // KeyMismatch indicates that the private key does not match // the public key or certificate being presented with the key. KeyMismatch //23XX // GenerationFailed indicates that a private key could not // be generated. GenerationFailed //24XX // Unavailable indicates that a private key mechanism (such as // PKCS #11) was requested but support for that mechanism is // not available. Unavailable ) // The following are policy-related non-parsing errors, and must be // specified along with PolicyError. const ( // NoKeyUsages indicates that the profile does not permit any // key usages for the certificate. NoKeyUsages Reason = 100 * (iota + 1) // 51XX // InvalidPolicy indicates that policy being requested is not // a valid policy or does not exist. InvalidPolicy // 52XX // InvalidRequest indicates a certificate request violated the // constraints of the policy being applied to the request. InvalidRequest // 53XX // UnknownProfile indicates that the profile does not exist. UnknownProfile // 54XX UnmatchedWhitelist // 55xx ) // The following are API client related errors, and should be // specified with APIClientError. const ( // AuthenticationFailure occurs when the client is unable // to obtain an authentication token for the request. AuthenticationFailure Reason = 100 * (iota + 1) // JSONError wraps an encoding/json error. JSONError // IOError wraps an io/ioutil error. IOError // ClientHTTPError wraps a net/http error. ClientHTTPError // ServerRequestFailed covers any other failures from the API // client. ServerRequestFailed ) // The following are OCSP related errors, and should be // specified with OCSPError const ( // IssuerMismatch ocurs when the certificate in the OCSP signing // request was not issued by the CA that this responder responds for. IssuerMismatch Reason = 100 * (iota + 1) // 81XX // InvalidStatus occurs when the OCSP signing requests includes an // invalid value for the certificate status. InvalidStatus ) // Certificate transparency related errors specified with CTError const ( // PrecertSubmissionFailed occurs when submitting a precertificate to // a log server fails PrecertSubmissionFailed = 100 * (iota + 1) // CTClientConstructionFailed occurs when the construction of a new // github.com/google/certificate-transparency client fails. CTClientConstructionFailed // PrecertMissingPoison occurs when a precert is passed to SignFromPrecert // and is missing the CT poison extension. PrecertMissingPoison // PrecertInvalidPoison occurs when a precert is passed to SignFromPrecert // and has a invalid CT poison extension value or the extension is not // critical. PrecertInvalidPoison ) // Certificate persistence related errors specified with CertStoreError const ( // InsertionFailed occurs when a SQL insert query failes to complete. InsertionFailed = 100 * (iota + 1) // RecordNotFound occurs when a SQL query targeting on one unique // record failes to update the specified row in the table. RecordNotFound ) // The error interface implementation, which formats to a JSON object string. func (e *Error) Error() string { marshaled, err := json.Marshal(e) if err != nil { panic(err) } return string(marshaled) } // New returns an error that contains an error code and message derived from // the given category, reason. Currently, to avoid confusion, it is not // allowed to create an error of category Success func New(category Category, reason Reason) *Error { errorCode := int(category) + int(reason) var msg string switch category { case OCSPError: switch reason { case ReadFailed: msg = "No certificate provided" case IssuerMismatch: msg = "Certificate not issued by this issuer" case InvalidStatus: msg = "Invalid revocation status" } case CertificateError: switch reason { case Unknown: msg = "Unknown certificate error" case ReadFailed: msg = "Failed to read certificate" case DecodeFailed: msg = "Failed to decode certificate" case ParseFailed: msg = "Failed to parse certificate" case SelfSigned: msg = "Certificate is self signed" case VerifyFailed: msg = "Unable to verify certificate" case BadRequest: msg = "Invalid certificate request" case MissingSerial: msg = "Missing serial number in request" default: panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category CertificateError.", reason)) } case PrivateKeyError: switch reason { case Unknown: msg = "Unknown private key error" case ReadFailed: msg = "Failed to read private key" case DecodeFailed: msg = "Failed to decode private key" case ParseFailed: msg = "Failed to parse private key" case Encrypted: msg = "Private key is encrypted." case NotRSAOrECCOrEd25519: msg = "Private key algorithm is not RSA or ECC or Ed25519" case KeyMismatch: msg = "Private key does not match public key" case GenerationFailed: msg = "Failed to new private key" case Unavailable: msg = "Private key is unavailable" default: panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PrivateKeyError.", reason)) } case IntermediatesError: switch reason { case Unknown: msg = "Unknown intermediate certificate error" case ReadFailed: msg = "Failed to read intermediate certificate" case DecodeFailed: msg = "Failed to decode intermediate certificate" case ParseFailed: msg = "Failed to parse intermediate certificate" default: panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category IntermediatesError.", reason)) } case RootError: switch reason { case Unknown: msg = "Unknown root certificate error" case ReadFailed: msg = "Failed to read root certificate" case DecodeFailed: msg = "Failed to decode root certificate" case ParseFailed: msg = "Failed to parse root certificate" default: panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category RootError.", reason)) } case PolicyError: switch reason { case Unknown: msg = "Unknown policy error" case NoKeyUsages: msg = "Invalid policy: no key usage available" case InvalidPolicy: msg = "Invalid or unknown policy" case InvalidRequest: msg = "Policy violation request" case UnknownProfile: msg = "Unknown policy profile" case UnmatchedWhitelist: msg = "Request does not match policy whitelist" default: panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PolicyError.", reason)) } case DialError: switch reason { case Unknown: msg = "Failed to dial remote server" default: panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category DialError.", reason)) } case APIClientError: switch reason { case AuthenticationFailure: msg = "API client authentication failure" case JSONError: msg = "API client JSON config error" case ClientHTTPError: msg = "API client HTTP error" case IOError: msg = "API client IO error" case ServerRequestFailed: msg = "API client error: Server request failed" default: panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category APIClientError.", reason)) } case CSRError: switch reason { case Unknown: msg = "CSR parsing failed due to unknown error" case ReadFailed: msg = "CSR file read failed" case ParseFailed: msg = "CSR Parsing failed" case DecodeFailed: msg = "CSR Decode failed" case BadRequest: msg = "CSR Bad request" default: panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category APIClientError.", reason)) } case CTError: switch reason { case Unknown: msg = "Certificate transparency parsing failed due to unknown error" case PrecertSubmissionFailed: msg = "Certificate transparency precertificate submission failed" case PrecertMissingPoison: msg = "Precertificate is missing CT poison extension" case PrecertInvalidPoison: msg = "Precertificate contains an invalid CT poison extension" default: panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CTError.", reason)) } case CertStoreError: switch reason { case Unknown: msg = "Certificate store action failed due to unknown error" default: panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CertStoreError.", reason)) } default: panic(fmt.Sprintf("Unsupported CFSSL error type: %d.", category)) } return &Error{ErrorCode: errorCode, Message: msg} } // Wrap returns an error that contains the given error and an error code derived from // the given category, reason and the error. Currently, to avoid confusion, it is not // allowed to create an error of category Success func Wrap(category Category, reason Reason, err error) *Error { errorCode := int(category) + int(reason) if err == nil { panic("Wrap needs a supplied error to initialize.") } // do not double wrap a error switch err.(type) { case *Error: panic("Unable to wrap a wrapped error.") } switch category { case CertificateError: // given VerifyFailed , report the status with more detailed status code // for some certificate errors we care. if reason == VerifyFailed { switch errorType := err.(type) { case x509.CertificateInvalidError: errorCode += certificateInvalid + int(errorType.Reason) case x509.UnknownAuthorityError: errorCode += unknownAuthority } } case PrivateKeyError, IntermediatesError, RootError, PolicyError, DialError, APIClientError, CSRError, CTError, CertStoreError, OCSPError: // no-op, just use the error default: panic(fmt.Sprintf("Unsupported CFSSL error type: %d.", category)) } return &Error{ErrorCode: errorCode, Message: err.Error()} } ================================================ FILE: errors/error_test.go ================================================ package errors import ( "crypto/x509" "encoding/json" "errors" "testing" ) func TestNew(t *testing.T) { err := New(CertificateError, Unknown) if err == nil { t.Fatal("Error creation failed.") } if err.ErrorCode != int(CertificateError)+int(Unknown) { t.Fatal("Error code construction failed.") } if err.Message != "Unknown certificate error" { t.Fatal("Error message construction failed.") } code := New(OCSPError, ReadFailed).ErrorCode if code != 8001 { t.Fatal("Improper error code") } code = New(OCSPError, IssuerMismatch).ErrorCode if code != 8100 { t.Fatal("Improper error code") } code = New(OCSPError, InvalidStatus).ErrorCode if code != 8200 { t.Fatal("Improper error code") } code = New(CertificateError, Unknown).ErrorCode if code != 1000 { t.Fatal("Improper error code") } code = New(CertificateError, ReadFailed).ErrorCode if code != 1001 { t.Fatal("Improper error code") } code = New(CertificateError, DecodeFailed).ErrorCode if code != 1002 { t.Fatal("Improper error code") } code = New(CertificateError, ParseFailed).ErrorCode if code != 1003 { t.Fatal("Improper error code") } code = New(CertificateError, SelfSigned).ErrorCode if code != 1100 { t.Fatal("Improper error code") } code = New(CertificateError, VerifyFailed).ErrorCode if code != 1200 { t.Fatal("Improper error code") } code = New(CertificateError, BadRequest).ErrorCode if code != 1300 { t.Fatal("Improper error code") } code = New(CertificateError, MissingSerial).ErrorCode if code != 1400 { t.Fatal("Improper error code") } code = New(PrivateKeyError, Unknown).ErrorCode if code != 2000 { t.Fatal("Improper error code") } code = New(PrivateKeyError, ReadFailed).ErrorCode if code != 2001 { t.Fatal("Improper error code") } code = New(PrivateKeyError, DecodeFailed).ErrorCode if code != 2002 { t.Fatal("Improper error code") } code = New(PrivateKeyError, ParseFailed).ErrorCode if code != 2003 { t.Fatal("Improper error code") } code = New(PrivateKeyError, Encrypted).ErrorCode if code != 2100 { t.Fatal("Improper error code") } code = New(PrivateKeyError, NotRSAOrECCOrEd25519).ErrorCode if code != 2200 { t.Fatal("Improper error code") } code = New(PrivateKeyError, KeyMismatch).ErrorCode if code != 2300 { t.Fatal("Improper error code") } code = New(PrivateKeyError, GenerationFailed).ErrorCode if code != 2400 { t.Fatal("Improper error code") } code = New(PrivateKeyError, Unavailable).ErrorCode if code != 2500 { t.Fatal("Improper error code") } code = New(IntermediatesError, Unknown).ErrorCode if code != 3000 { t.Fatal("Improper error code") } code = New(IntermediatesError, ReadFailed).ErrorCode if code != 3001 { t.Fatal("Improper error code") } code = New(IntermediatesError, DecodeFailed).ErrorCode if code != 3002 { t.Fatal("Improper error code") } code = New(IntermediatesError, ParseFailed).ErrorCode if code != 3003 { t.Fatal("Improper error code") } code = New(RootError, Unknown).ErrorCode if code != 4000 { t.Fatal("Improper error code") } code = New(RootError, ReadFailed).ErrorCode if code != 4001 { t.Fatal("Improper error code") } code = New(RootError, DecodeFailed).ErrorCode if code != 4002 { t.Fatal("Improper error code") } code = New(RootError, ParseFailed).ErrorCode if code != 4003 { t.Fatal("Improper error code") } code = New(PolicyError, Unknown).ErrorCode if code != 5000 { t.Fatal("Improper error code") } code = New(PolicyError, NoKeyUsages).ErrorCode if code != 5100 { t.Fatal("Improper error code") } code = New(PolicyError, InvalidPolicy).ErrorCode if code != 5200 { t.Fatal("Improper error code") } code = New(PolicyError, InvalidRequest).ErrorCode if code != 5300 { t.Fatal("Improper error code") } code = New(PolicyError, UnknownProfile).ErrorCode if code != 5400 { t.Fatal("Improper error code") } code = New(DialError, Unknown).ErrorCode if code != 6000 { t.Fatal("Improper error code") } code = New(APIClientError, AuthenticationFailure).ErrorCode if code != 7100 { t.Fatal("Improper error code") } code = New(APIClientError, JSONError).ErrorCode if code != 7200 { t.Fatal("Improper error code") } code = New(APIClientError, ClientHTTPError).ErrorCode if code != 7400 { t.Fatal("Improper error code") } code = New(APIClientError, IOError).ErrorCode if code != 7300 { t.Fatal("Improper error code") } code = New(APIClientError, ServerRequestFailed).ErrorCode if code != 7500 { t.Fatal("Improper error code") } code = New(CSRError, Unknown).ErrorCode if code != 9000 { t.Fatal("Improper error code") } code = New(CSRError, ReadFailed).ErrorCode if code != 9001 { t.Fatal("Improper error code") } code = New(CSRError, DecodeFailed).ErrorCode if code != 9002 { t.Fatal("Improper error code") } code = New(CSRError, ParseFailed).ErrorCode if code != 9003 { t.Fatal("Improper error code") } code = New(CSRError, KeyMismatch).ErrorCode if code != 9300 { t.Fatal("Improper error code") } code = New(CSRError, BadRequest).ErrorCode if code != 9300 { t.Fatal("Improper error code") } code = New(CTError, Unknown).ErrorCode if code != 10000 { t.Fatal("Improper error code") } code = New(CTError, PrecertSubmissionFailed).ErrorCode if code != 10100 { t.Fatal("Improper error code") } } func TestWrap(t *testing.T) { msg := "Arbitrary error message" err := Wrap(CertificateError, Unknown, errors.New(msg)) if err == nil { t.Fatal("Error creation failed.") } if err.ErrorCode != int(CertificateError)+int(Unknown) { t.Fatal("Error code construction failed.") } if err.Message != msg { t.Fatal("Error message construction failed.") } err = Wrap(CertificateError, VerifyFailed, x509.CertificateInvalidError{Reason: x509.Expired}) if err == nil { t.Fatal("Error creation failed.") } if err.ErrorCode != int(CertificateError)+int(VerifyFailed)+certificateInvalid+int(x509.Expired) { t.Fatal("Error code construction failed.") } errorString := "x509: certificate has expired or is not yet valid:" if err.Message[:49] != errorString[:49] { t.Fatal("Error message construction failed.") } err = Wrap(CertificateError, VerifyFailed, x509.UnknownAuthorityError{}) if err == nil { t.Fatal("Error creation failed.") } err = Wrap(RootError, Unknown, errors.New(msg)) if err == nil { t.Fatal("Error creation failed.") } if err.ErrorCode != int(RootError)+int(Unknown) { t.Fatal("Error code construction failed.") } if err.Message != msg { t.Fatal("Error message construction failed.") } } func TestMarshal(t *testing.T) { msg := "Arbitrary error message" err := Wrap(CertificateError, Unknown, errors.New(msg)) bytes, _ := json.Marshal(err) var received Error json.Unmarshal(bytes, &received) if received.ErrorCode != int(CertificateError)+int(Unknown) { t.Fatal("Error code construction failed.") } if received.Message != msg { t.Fatal("Error message construction failed.") } } func TestErrorString(t *testing.T) { msg := "Arbitrary error message" err := Wrap(CertificateError, Unknown, errors.New(msg)) str := err.Error() if str != `{"code":1000,"message":"`+msg+`"}` { t.Fatal("Incorrect Error():", str) } } func TestHTTP(t *testing.T) { err := NewMethodNotAllowed("GET") if err == nil { t.Fatal("New Mathod Check failed") } err = NewBadRequest(errors.New("Bad Request")) if err == nil { t.Fatal("New Bad Request Check failed") } if err.StatusCode != 400 { t.Fatal("New Bad Request error code construction failed") } err = NewBadRequestString("Bad Request String") if err == nil { t.Fatal("New Bad Request String Check failed") } if err.StatusCode != 400 { t.Fatal("New Bad Request String error code construction failed") } err = NewBadRequestMissingParameter("Request Missing Parameter") if err == nil { t.Fatal("New Bad Request Missing Parameter Check failed") } if err.StatusCode != 400 { t.Fatal("New Bad Request Missing Parameter error code construction failed") } err = NewBadRequestUnwantedParameter("Unwanted Parameter Present In Request") if err == nil { t.Fatal("New Bad Request Unwanted Parameter Check failed") } if err.StatusCode != 400 { t.Fatal("New Bad Request Unwanted Parameter error code construction failed") } } func TestHTTPErrorString(t *testing.T) { method := "GET" err := NewMethodNotAllowed(method) str := err.Error() if str != `Method is not allowed:"`+method+`"` { t.Fatal("Incorrect Error():", str) } } ================================================ FILE: errors/http.go ================================================ package errors import ( "errors" "net/http" ) // HTTPError is an augmented error with a HTTP status code. type HTTPError struct { StatusCode int error } // Error implements the error interface. func (e *HTTPError) Error() string { return e.error.Error() } // NewMethodNotAllowed returns an appropriate error in the case that // an HTTP client uses an invalid method (i.e. a GET in place of a POST) // on an API endpoint. func NewMethodNotAllowed(method string) *HTTPError { return &HTTPError{http.StatusMethodNotAllowed, errors.New(`Method is not allowed:"` + method + `"`)} } // NewBadRequest creates a HttpError with the given error and error code 400. func NewBadRequest(err error) *HTTPError { return &HTTPError{http.StatusBadRequest, err} } // NewBadRequestString returns a HttpError with the supplied message // and error code 400. func NewBadRequestString(s string) *HTTPError { return NewBadRequest(errors.New(s)) } // NewBadRequestMissingParameter returns a 400 HttpError as a required // parameter is missing in the HTTP request. func NewBadRequestMissingParameter(s string) *HTTPError { return NewBadRequestString(`Missing parameter "` + s + `"`) } // NewBadRequestUnwantedParameter returns a 400 HttpError as a unnecessary // parameter is present in the HTTP request. func NewBadRequestUnwantedParameter(s string) *HTTPError { return NewBadRequestString(`Unwanted parameter "` + s + `"`) } ================================================ FILE: go.mod ================================================ module github.com/cloudflare/cfssl go 1.20 require ( bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a github.com/cloudflare/redoctober v0.0.0-20211013234631-6a74ccc611f6 github.com/go-sql-driver/mysql v1.8.0 github.com/google/certificate-transparency-go v1.1.8 github.com/jmhodges/clock v1.2.0 github.com/jmoiron/sqlx v1.3.5 github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 github.com/lib/pq v1.10.9 github.com/mattn/go-sqlite3 v1.14.22 github.com/prometheus/client_golang v1.19.0 github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300 github.com/zmap/zlint/v3 v3.5.0 golang.org/x/crypto v0.21.0 ) require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/getsentry/sentry-go v0.11.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/kylelemons/go-gypsy v1.0.0 // indirect github.com/pelletier/go-toml v1.9.3 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/stretchr/testify v1.8.4 // indirect github.com/weppos/publicsuffix-go v0.30.0 // indirect github.com/ziutek/mymysql v1.5.4 // indirect golang.org/x/net v0.22.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.33.0 // indirect k8s.io/klog/v2 v2.120.1 // indirect ) ================================================ FILE: go.sum ================================================ bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c h1:bkb2NMGo3/Du52wvYj9Whth5KZfMV6d3O0Vbr3nz/UE= bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a h1:8d1CEOF1xldesKds5tRG3tExBsMOgWYownMHNCsev54= github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= github.com/cloudflare/redoctober v0.0.0-20211013234631-6a74ccc611f6 h1:QKzett0dn5FhjcIHNKSClEilabfhWCnsdijq3ftm9Ms= github.com/cloudflare/redoctober v0.0.0-20211013234631-6a74ccc611f6/go.mod h1:Ikt4Wfpln1YOrak+auA8BNxgiilj0Y2y7nO+aN2eMzk= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/getsentry/sentry-go v0.11.0 h1:qro8uttJGvNAMr5CLcFI9CHR0aDzXl0Vs3Pmw/oTPg8= github.com/getsentry/sentry-go v0.11.0/go.mod h1:KBQIxiZAetw62Cj8Ri964vAEWVdgfaUCn30Q3bCvANo= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.8.0 h1:UtktXaU2Nb64z/pLiGIxY4431SJ4/dR5cjMmlVHgnT4= github.com/go-sql-driver/mysql v1.8.0/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/certificate-transparency-go v1.1.8 h1:LGYKkgZF7satzgTak9R4yzfJXEeYVAjV6/EAEJOf1to= github.com/google/certificate-transparency-go v1.1.8/go.mod h1:bV/o8r0TBKRf1X//iiiSgWrvII4d7/8OiA+3vG26gI8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 h1:veS9QfglfvqAw2e+eeNT/SbGySq8ajECXJ9e4fPoLhY= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kylelemons/go-gypsy v1.0.0 h1:7/wQ7A3UL1bnqRMnZ6T8cwCOArfZCxFmb1iTxaOOo1s= github.com/kylelemons/go-gypsy v1.0.0/go.mod h1:chkXM0zjdpXOiqkCW1XcCHDfjfk14PH2KKkQWxfJUcU= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.31.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/weppos/publicsuffix-go v0.12.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.30.0 h1:QHPZ2GRu/YE7cvejH9iyavPOkVCB4dNxp2ZvtT+vQLY= github.com/weppos/publicsuffix-go v0.30.0/go.mod h1:kBi8zwYnR0zrbm8RcuN1o9Fzgpnnn+btVN8uWPMyXAY= github.com/weppos/publicsuffix-go/publicsuffix/generator v0.0.0-20220927085643-dc0d00c92642/go.mod h1:GHfoeIdZLdZmLjMlzBftbTDntahTttUMWjxZwQJhULE= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+TWveAxiVWk= github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300 h1:DZH5n7L3L8RxKdSyJHZt7WePgwdhHnPhQFdQSJaHF+o= github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300/go.mod h1:mOd4yUMgn2fe2nV9KXsa9AyQBFZGzygVPovsZR+Rl5w= github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= github.com/zmap/zlint/v3 v3.5.0 h1:Eh2B5t6VKgVH0DFmTwOqE50POvyDhUaU9T2mJOe1vfQ= github.com/zmap/zlint/v3 v3.5.0/go.mod h1:JkNSrsDJ8F4VRtBZcYUQSvnWFL7utcjDIn+FE64mlBI= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= ================================================ FILE: helpers/derhelpers/derhelpers.go ================================================ // Package derhelpers implements common functionality // on DER encoded data package derhelpers import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "crypto/x509" cferr "github.com/cloudflare/cfssl/errors" ) // ParsePrivateKeyDER parses a PKCS #1, PKCS #8, ECDSA, or Ed25519 DER-encoded // private key. The key must not be in PEM format. func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) { generalKey, err := x509.ParsePKCS8PrivateKey(keyDER) if err != nil { generalKey, err = x509.ParsePKCS1PrivateKey(keyDER) if err != nil { generalKey, err = x509.ParseECPrivateKey(keyDER) if err != nil { generalKey, err = ParseEd25519PrivateKey(keyDER) if err != nil { // We don't include the actual error into // the final error. The reason might be // we don't want to leak any info about // the private key. return nil, cferr.New(cferr.PrivateKeyError, cferr.ParseFailed) } } } } switch generalKey := generalKey.(type) { case *rsa.PrivateKey: return generalKey, nil case *ecdsa.PrivateKey: return generalKey, nil case ed25519.PrivateKey: return generalKey, nil } // should never reach here return nil, cferr.New(cferr.PrivateKeyError, cferr.ParseFailed) } ================================================ FILE: helpers/derhelpers/ed25519.go ================================================ package derhelpers import ( "crypto" "crypto/ed25519" "crypto/x509/pkix" "encoding/asn1" "errors" ) var errEd25519WrongID = errors.New("incorrect object identifier") var errEd25519WrongKeyType = errors.New("incorrect key type") // ed25519OID is the OID for the Ed25519 signature scheme: see // https://datatracker.ietf.org/doc/draft-ietf-curdle-pkix-04. var ed25519OID = asn1.ObjectIdentifier{1, 3, 101, 112} // subjectPublicKeyInfo reflects the ASN.1 object defined in the X.509 standard. // // This is defined in crypto/x509 as "publicKeyInfo". type subjectPublicKeyInfo struct { Algorithm pkix.AlgorithmIdentifier PublicKey asn1.BitString } // MarshalEd25519PublicKey creates a DER-encoded SubjectPublicKeyInfo for an // ed25519 public key, as defined in // https://tools.ietf.org/html/draft-ietf-curdle-pkix-04. This is analogous to // MarshalPKIXPublicKey in crypto/x509, which doesn't currently support Ed25519. func MarshalEd25519PublicKey(pk crypto.PublicKey) ([]byte, error) { pub, ok := pk.(ed25519.PublicKey) if !ok { return nil, errEd25519WrongKeyType } spki := subjectPublicKeyInfo{ Algorithm: pkix.AlgorithmIdentifier{ Algorithm: ed25519OID, }, PublicKey: asn1.BitString{ BitLength: len(pub) * 8, Bytes: pub, }, } return asn1.Marshal(spki) } // ParseEd25519PublicKey returns the Ed25519 public key encoded by the input. func ParseEd25519PublicKey(der []byte) (crypto.PublicKey, error) { var spki subjectPublicKeyInfo if rest, err := asn1.Unmarshal(der, &spki); err != nil { return nil, err } else if len(rest) > 0 { return nil, errors.New("SubjectPublicKeyInfo too long") } if !spki.Algorithm.Algorithm.Equal(ed25519OID) { return nil, errEd25519WrongID } if spki.PublicKey.BitLength != ed25519.PublicKeySize*8 { return nil, errors.New("SubjectPublicKeyInfo PublicKey length mismatch") } return ed25519.PublicKey(spki.PublicKey.Bytes), nil } // oneAsymmetricKey reflects the ASN.1 structure for storing private keys in // https://tools.ietf.org/html/draft-ietf-curdle-pkix-04, excluding the optional // fields, which we don't use here. // // This is identical to pkcs8 in crypto/x509. type oneAsymmetricKey struct { Version int Algorithm pkix.AlgorithmIdentifier PrivateKey []byte } // curvePrivateKey is the innter type of the PrivateKey field of // oneAsymmetricKey. type curvePrivateKey []byte // MarshalEd25519PrivateKey returns a DER encoding of the input private key as // specified in https://tools.ietf.org/html/draft-ietf-curdle-pkix-04. func MarshalEd25519PrivateKey(sk crypto.PrivateKey) ([]byte, error) { priv, ok := sk.(ed25519.PrivateKey) if !ok { return nil, errEd25519WrongKeyType } // Marshal the innter CurvePrivateKey. curvePrivateKey, err := asn1.Marshal(priv.Seed()) if err != nil { return nil, err } // Marshal the OneAsymmetricKey. asym := oneAsymmetricKey{ Version: 0, Algorithm: pkix.AlgorithmIdentifier{ Algorithm: ed25519OID, }, PrivateKey: curvePrivateKey, } return asn1.Marshal(asym) } // ParseEd25519PrivateKey returns the Ed25519 private key encoded by the input. func ParseEd25519PrivateKey(der []byte) (crypto.PrivateKey, error) { asym := new(oneAsymmetricKey) if rest, err := asn1.Unmarshal(der, asym); err != nil { return nil, err } else if len(rest) > 0 { return nil, errors.New("OneAsymmetricKey too long") } // Check that the key type is correct. if !asym.Algorithm.Algorithm.Equal(ed25519OID) { return nil, errEd25519WrongID } // Unmarshal the inner CurvePrivateKey. seed := new(curvePrivateKey) if rest, err := asn1.Unmarshal(asym.PrivateKey, seed); err != nil { return nil, err } else if len(rest) > 0 { return nil, errors.New("CurvePrivateKey too long") } return ed25519.NewKeyFromSeed(*seed), nil } ================================================ FILE: helpers/derhelpers/ed25519_test.go ================================================ package derhelpers import ( "bytes" "crypto/ed25519" "encoding/pem" "testing" ) var testPubKey = `-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE= -----END PUBLIC KEY----- ` var testPrivKey = `-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC -----END PRIVATE KEY-----` func TestParseMarshalEd25519PublicKey(t *testing.T) { block, rest := pem.Decode([]byte(testPubKey)) if len(rest) > 0 { t.Fatal("pem.Decode(); len(rest) > 0, want 0") } pk, err := ParseEd25519PublicKey(block.Bytes) if err != nil { t.Fatal(err) } if pkLen := len(pk.(ed25519.PublicKey)); pkLen != 32 { t.Fatalf("len(pk): got %d: want %d", pkLen, 32) } der, err := MarshalEd25519PublicKey(pk) if err != nil { t.Fatal(err) } if !bytes.Equal(der, block.Bytes) { t.Errorf("got %d bytes:\n%v \nwant %d bytes:\n%v", len(der), der, len(block.Bytes), block.Bytes) } } func TestParseMarshalEd25519PrivateKey(t *testing.T) { block, rest := pem.Decode([]byte(testPrivKey)) if len(rest) > 0 { t.Fatal("pem.Decode(); len(rest) > 0, want 0") } sk, err := ParseEd25519PrivateKey(block.Bytes) if err != nil { t.Fatal(err) } if skLen := len(sk.(ed25519.PrivateKey)); skLen != 64 { t.Fatalf("len(sk): got %d: want %d", skLen, 64) } der, err := MarshalEd25519PrivateKey(sk) if err != nil { t.Fatal(err) } if !bytes.Equal(der, block.Bytes) { t.Errorf("got %d bytes:\n%v \nwant %d bytes:\n%v", len(der), der, len(block.Bytes), block.Bytes) } } func TestKeyPair(t *testing.T) { block, rest := pem.Decode([]byte(testPrivKey)) if len(rest) > 0 { t.Fatal("pem.Decode(); len(rest) > 0, want 0") } sk, err := ParseEd25519PrivateKey(block.Bytes) if err != nil { t.Fatal(err) } block, rest = pem.Decode([]byte(testPubKey)) if len(rest) > 0 { t.Fatal("pem.Decode(); len(rest) > 0, want 0") } pub, err := ParseEd25519PublicKey(block.Bytes) if err != nil { t.Fatal(err) } pk := pub.(ed25519.PublicKey) pk2 := sk.(ed25519.PrivateKey).Public().(ed25519.PublicKey) if !bytes.Equal(pk, pk2) { t.Errorf("pk %d bytes:\n%v \nsk.Public() %d bytes:\n%v", len(pk), pk, len(pk2), pk2) } } ================================================ FILE: helpers/helpers.go ================================================ // Package helpers implements utility functionality common to many // CFSSL packages. package helpers import ( "bytes" "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rsa" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/pem" "errors" "fmt" "os" "strings" "time" "github.com/cloudflare/cfssl/crypto/pkcs7" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers/derhelpers" "github.com/cloudflare/cfssl/log" ct "github.com/google/certificate-transparency-go" cttls "github.com/google/certificate-transparency-go/tls" ctx509 "github.com/google/certificate-transparency-go/x509" "golang.org/x/crypto/ocsp" "golang.org/x/crypto/pkcs12" ) // OneYear is a time.Duration representing a year's worth of seconds. const OneYear = 8760 * time.Hour // OneDay is a time.Duration representing a day's worth of seconds. const OneDay = 24 * time.Hour // DelegationUsage is the OID for the DelegationUseage extensions var DelegationUsage = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44363, 44} // DelegationExtension var DelegationExtension = pkix.Extension{ Id: DelegationUsage, Critical: false, Value: []byte{0x05, 0x00}, // ASN.1 NULL } // InclusiveDate returns the time.Time representation of a date - 1 // nanosecond. This allows time.After to be used inclusively. func InclusiveDate(year int, month time.Month, day int) time.Time { return time.Date(year, month, day, 0, 0, 0, 0, time.UTC).Add(-1 * time.Nanosecond) } // Jul2012 is the July 2012 CAB Forum deadline for when CAs must stop // issuing certificates valid for more than 5 years. var Jul2012 = InclusiveDate(2012, time.July, 01) // Apr2015 is the April 2015 CAB Forum deadline for when CAs must stop // issuing certificates valid for more than 39 months. var Apr2015 = InclusiveDate(2015, time.April, 01) // KeyLength returns the bit size of ECDSA, RSA or Ed25519 PublicKey func KeyLength(key interface{}) int { if key == nil { return 0 } if ecdsaKey, ok := key.(*ecdsa.PublicKey); ok { return ecdsaKey.Curve.Params().BitSize } else if rsaKey, ok := key.(*rsa.PublicKey); ok { return rsaKey.N.BitLen() } else if _, ok := key.(ed25519.PublicKey); ok { return ed25519.PublicKeySize } return 0 } // ExpiryTime returns the time when the certificate chain is expired. func ExpiryTime(chain []*x509.Certificate) (notAfter time.Time) { if len(chain) == 0 { return } notAfter = chain[0].NotAfter for _, cert := range chain { if notAfter.After(cert.NotAfter) { notAfter = cert.NotAfter } } return } // MonthsValid returns the number of months for which a certificate is valid. func MonthsValid(c *x509.Certificate) int { issued := c.NotBefore expiry := c.NotAfter years := (expiry.Year() - issued.Year()) months := years*12 + int(expiry.Month()) - int(issued.Month()) // Round up if valid for less than a full month if expiry.Day() > issued.Day() { months++ } return months } // ValidExpiry determines if a certificate is valid for an acceptable // length of time per the CA/Browser Forum baseline requirements. // See https://cabforum.org/wp-content/uploads/CAB-Forum-BR-1.3.0.pdf func ValidExpiry(c *x509.Certificate) bool { issued := c.NotBefore var maxMonths int switch { case issued.After(Apr2015): maxMonths = 39 case issued.After(Jul2012): maxMonths = 60 case issued.Before(Jul2012): maxMonths = 120 } return MonthsValid(c) <= maxMonths } // SignatureString returns the TLS signature string corresponding to // an X509 signature algorithm. func SignatureString(alg x509.SignatureAlgorithm) string { switch alg { case x509.MD2WithRSA: return "MD2WithRSA" case x509.MD5WithRSA: return "MD5WithRSA" case x509.SHA1WithRSA: return "SHA1WithRSA" case x509.SHA256WithRSA: return "SHA256WithRSA" case x509.SHA384WithRSA: return "SHA384WithRSA" case x509.SHA512WithRSA: return "SHA512WithRSA" case x509.DSAWithSHA1: return "DSAWithSHA1" case x509.DSAWithSHA256: return "DSAWithSHA256" case x509.ECDSAWithSHA1: return "ECDSAWithSHA1" case x509.ECDSAWithSHA256: return "ECDSAWithSHA256" case x509.ECDSAWithSHA384: return "ECDSAWithSHA384" case x509.ECDSAWithSHA512: return "ECDSAWithSHA512" case x509.PureEd25519: return "Ed25519" default: return "Unknown Signature" } } // HashAlgoString returns the hash algorithm name contained in the signature // method. func HashAlgoString(alg x509.SignatureAlgorithm) string { switch alg { case x509.MD2WithRSA: return "MD2" case x509.MD5WithRSA: return "MD5" case x509.SHA1WithRSA: return "SHA1" case x509.SHA256WithRSA: return "SHA256" case x509.SHA384WithRSA: return "SHA384" case x509.SHA512WithRSA: return "SHA512" case x509.DSAWithSHA1: return "SHA1" case x509.DSAWithSHA256: return "SHA256" case x509.ECDSAWithSHA1: return "SHA1" case x509.ECDSAWithSHA256: return "SHA256" case x509.ECDSAWithSHA384: return "SHA384" case x509.ECDSAWithSHA512: return "SHA512" case x509.PureEd25519: return "Ed25519" default: return "Unknown Hash Algorithm" } } // StringTLSVersion returns underlying enum values from human names for TLS // versions, defaults to current golang default of TLS 1.0 func StringTLSVersion(version string) uint16 { switch version { case "1.2": return tls.VersionTLS12 case "1.1": return tls.VersionTLS11 default: return tls.VersionTLS10 } } // EncodeCertificatesPEM encodes a number of x509 certificates to PEM func EncodeCertificatesPEM(certs []*x509.Certificate) []byte { var buffer bytes.Buffer for _, cert := range certs { pem.Encode(&buffer, &pem.Block{ Type: "CERTIFICATE", Bytes: cert.Raw, }) } return buffer.Bytes() } // EncodeCertificatePEM encodes a single x509 certificates to PEM func EncodeCertificatePEM(cert *x509.Certificate) []byte { return EncodeCertificatesPEM([]*x509.Certificate{cert}) } // ParseCertificatesPEM parses a sequence of PEM-encoded certificate and returns them, // can handle PEM encoded PKCS #7 structures. func ParseCertificatesPEM(certsPEM []byte) ([]*x509.Certificate, error) { var certs []*x509.Certificate var err error certsPEM = bytes.TrimSpace(certsPEM) for len(certsPEM) > 0 { var cert []*x509.Certificate cert, certsPEM, err = ParseOneCertificateFromPEM(certsPEM) if err != nil { return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed) } else if cert == nil { break } certs = append(certs, cert...) } if len(certsPEM) > 0 { return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed) } return certs, nil } // ParseCertificatesDER parses a DER encoding of a certificate object and possibly private key, // either PKCS #7, PKCS #12, or raw x509. func ParseCertificatesDER(certsDER []byte, password string) (certs []*x509.Certificate, key crypto.Signer, err error) { certsDER = bytes.TrimSpace(certsDER) pkcs7data, err := pkcs7.ParsePKCS7(certsDER) if err != nil { var pkcs12data interface{} certs = make([]*x509.Certificate, 1) pkcs12data, certs[0], err = pkcs12.Decode(certsDER, password) if err != nil { certs, err = x509.ParseCertificates(certsDER) if err != nil { return nil, nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed) } } else { key = pkcs12data.(crypto.Signer) } } else { if pkcs7data.ContentInfo != "SignedData" { return nil, nil, cferr.Wrap(cferr.CertificateError, cferr.DecodeFailed, errors.New("can only extract certificates from signed data content info")) } certs = pkcs7data.Content.SignedData.Certificates } if certs == nil { return nil, key, cferr.New(cferr.CertificateError, cferr.DecodeFailed) } return certs, key, nil } // ParseSelfSignedCertificatePEM parses a PEM-encoded certificate and check if it is self-signed. func ParseSelfSignedCertificatePEM(certPEM []byte) (*x509.Certificate, error) { cert, err := ParseCertificatePEM(certPEM) if err != nil { return nil, err } if err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.VerifyFailed, err) } return cert, nil } // ParseCertificatePEM parses and returns a PEM-encoded certificate, // can handle PEM encoded PKCS #7 structures. func ParseCertificatePEM(certPEM []byte) (*x509.Certificate, error) { certPEM = bytes.TrimSpace(certPEM) cert, rest, err := ParseOneCertificateFromPEM(certPEM) if err != nil { // Log the actual parsing error but throw a default parse error message. log.Debugf("Certificate parsing error: %v", err) return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed) } else if cert == nil { return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed) } else if len(rest) > 0 { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PEM file should contain only one object")) } else if len(cert) > 1 { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PKCS7 object in the PEM file should contain only one certificate")) } return cert[0], nil } // ParseOneCertificateFromPEM attempts to parse one PEM encoded certificate object, // either a raw x509 certificate or a PKCS #7 structure possibly containing // multiple certificates, from the top of certsPEM, which itself may // contain multiple PEM encoded certificate objects. func ParseOneCertificateFromPEM(certsPEM []byte) ([]*x509.Certificate, []byte, error) { block, rest := pem.Decode(certsPEM) if block == nil { return nil, rest, nil } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { pkcs7data, err := pkcs7.ParsePKCS7(block.Bytes) if err != nil { return nil, rest, err } if pkcs7data.ContentInfo != "SignedData" { return nil, rest, errors.New("only PKCS #7 Signed Data Content Info supported for certificate parsing") } certs := pkcs7data.Content.SignedData.Certificates if certs == nil { return nil, rest, errors.New("PKCS #7 structure contains no certificates") } return certs, rest, nil } var certs = []*x509.Certificate{cert} return certs, rest, nil } // LoadPEMCertPool loads a pool of PEM certificates from file. func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) { if certsFile == "" { return nil, nil } pemCerts, err := os.ReadFile(certsFile) if err != nil { return nil, err } return PEMToCertPool(pemCerts) } // PEMToCertPool concerts PEM certificates to a CertPool. func PEMToCertPool(pemCerts []byte) (*x509.CertPool, error) { if len(pemCerts) == 0 { return nil, nil } certPool := x509.NewCertPool() if !certPool.AppendCertsFromPEM(pemCerts) { return nil, errors.New("failed to load cert pool") } return certPool, nil } // ParsePrivateKeyPEM parses and returns a PEM-encoded private // key. The private key may be either an unencrypted PKCS#8, PKCS#1, // or elliptic private key. func ParsePrivateKeyPEM(keyPEM []byte) (key crypto.Signer, err error) { return ParsePrivateKeyPEMWithPassword(keyPEM, nil) } // ParsePrivateKeyPEMWithPassword parses and returns a PEM-encoded private // key. The private key may be a potentially encrypted PKCS#8, PKCS#1, // or elliptic private key. func ParsePrivateKeyPEMWithPassword(keyPEM []byte, password []byte) (key crypto.Signer, err error) { keyDER, err := GetKeyDERFromPEM(keyPEM, password) if err != nil { return nil, err } return derhelpers.ParsePrivateKeyDER(keyDER) } // GetKeyDERFromPEM parses a PEM-encoded private key and returns DER-format key bytes. func GetKeyDERFromPEM(in []byte, password []byte) ([]byte, error) { // Ignore any EC PARAMETERS blocks when looking for a key (openssl includes // them by default). var keyDER *pem.Block for { keyDER, in = pem.Decode(in) if keyDER == nil || keyDER.Type != "EC PARAMETERS" { break } } if keyDER != nil { if procType, ok := keyDER.Headers["Proc-Type"]; ok { if strings.Contains(procType, "ENCRYPTED") { if password != nil { return x509.DecryptPEMBlock(keyDER, password) } return nil, cferr.New(cferr.PrivateKeyError, cferr.Encrypted) } } return keyDER.Bytes, nil } return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed) } // ParseCSR parses a PEM- or DER-encoded PKCS #10 certificate signing request. func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) { in = bytes.TrimSpace(in) p, rest := pem.Decode(in) if p != nil { if p.Type != "NEW CERTIFICATE REQUEST" && p.Type != "CERTIFICATE REQUEST" { return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest) } csr, err = x509.ParseCertificateRequest(p.Bytes) } else { csr, err = x509.ParseCertificateRequest(in) } if err != nil { return nil, rest, err } err = csr.CheckSignature() if err != nil { return nil, rest, err } return csr, rest, nil } // ParseCSRPEM parses a PEM-encoded certificate signing request. // It does not check the signature. This is useful for dumping data from a CSR // locally. func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) { block, _ := pem.Decode([]byte(csrPEM)) if block == nil { return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed) } csrObject, err := x509.ParseCertificateRequest(block.Bytes) if err != nil { return nil, err } return csrObject, nil } // ParseCSRDER parses a PEM-encoded certificate signing request. // It does not check the signature. This is useful for dumping data from a CSR // locally. func ParseCSRDER(csrDER []byte) (*x509.CertificateRequest, error) { csrObject, err := x509.ParseCertificateRequest(csrDER) if err != nil { return nil, err } err = csrObject.CheckSignature() if err != nil { return nil, err } return csrObject, nil } // SignerAlgo returns an X.509 signature algorithm from a crypto.Signer. func SignerAlgo(priv crypto.Signer) x509.SignatureAlgorithm { switch pub := priv.Public().(type) { case *rsa.PublicKey: bitLength := pub.N.BitLen() switch { case bitLength >= 4096: return x509.SHA512WithRSA case bitLength >= 3072: return x509.SHA384WithRSA case bitLength >= 2048: return x509.SHA256WithRSA default: return x509.SHA1WithRSA } case *ecdsa.PublicKey: switch pub.Curve { case elliptic.P521(): return x509.ECDSAWithSHA512 case elliptic.P384(): return x509.ECDSAWithSHA384 case elliptic.P256(): return x509.ECDSAWithSHA256 default: return x509.ECDSAWithSHA1 } case ed25519.PublicKey: return x509.PureEd25519 default: return x509.UnknownSignatureAlgorithm } } // LoadClientCertificate load key/certificate from pem files func LoadClientCertificate(certFile string, keyFile string) (*tls.Certificate, error) { if certFile != "" && keyFile != "" { cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { log.Criticalf("Unable to read client certificate from file: %s or key from file: %s", certFile, keyFile) return nil, err } log.Debug("Client certificate loaded ") return &cert, nil } return nil, nil } // CreateTLSConfig creates a tls.Config object from certs and roots func CreateTLSConfig(remoteCAs *x509.CertPool, cert *tls.Certificate) *tls.Config { var certs []tls.Certificate if cert != nil { certs = []tls.Certificate{*cert} } return &tls.Config{ Certificates: certs, RootCAs: remoteCAs, } } // SerializeSCTList serializes a list of SCTs. func SerializeSCTList(sctList []ct.SignedCertificateTimestamp) ([]byte, error) { list := ctx509.SignedCertificateTimestampList{} for _, sct := range sctList { sctBytes, err := cttls.Marshal(sct) if err != nil { return nil, err } list.SCTList = append(list.SCTList, ctx509.SerializedSCT{Val: sctBytes}) } return cttls.Marshal(list) } // DeserializeSCTList deserializes a list of SCTs. func DeserializeSCTList(serializedSCTList []byte) ([]ct.SignedCertificateTimestamp, error) { var sctList ctx509.SignedCertificateTimestampList rest, err := cttls.Unmarshal(serializedSCTList, &sctList) if err != nil { return nil, err } if len(rest) != 0 { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("serialized SCT list contained trailing garbage")) } list := make([]ct.SignedCertificateTimestamp, len(sctList.SCTList)) for i, serializedSCT := range sctList.SCTList { var sct ct.SignedCertificateTimestamp rest, err := cttls.Unmarshal(serializedSCT.Val, &sct) if err != nil { return nil, err } if len(rest) != 0 { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("serialized SCT contained trailing garbage")) } list[i] = sct } return list, nil } // SCTListFromOCSPResponse extracts the SCTList from an ocsp.Response, // returning an empty list if the SCT extension was not found or could not be // unmarshalled. func SCTListFromOCSPResponse(response *ocsp.Response) ([]ct.SignedCertificateTimestamp, error) { // This loop finds the SCTListExtension in the OCSP response. var SCTListExtension, ext pkix.Extension for _, ext = range response.Extensions { // sctExtOid is the ObjectIdentifier of a Signed Certificate Timestamp. sctExtOid := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5} if ext.Id.Equal(sctExtOid) { SCTListExtension = ext break } } // This code block extracts the sctList from the SCT extension. var sctList []ct.SignedCertificateTimestamp var err error if numBytes := len(SCTListExtension.Value); numBytes != 0 { var serializedSCTList []byte rest := make([]byte, numBytes) copy(rest, SCTListExtension.Value) for len(rest) != 0 { rest, err = asn1.Unmarshal(rest, &serializedSCTList) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err) } } sctList, err = DeserializeSCTList(serializedSCTList) } return sctList, err } // ReadBytes reads a []byte either from a file or an environment variable. // If valFile has a prefix of 'env:', the []byte is read from the environment // using the subsequent name. If the prefix is 'file:' the []byte is read from // the subsequent file. If no prefix is provided, valFile is assumed to be a // file path. func ReadBytes(valFile string) ([]byte, error) { switch splitVal := strings.SplitN(valFile, ":", 2); len(splitVal) { case 1: return os.ReadFile(valFile) case 2: switch splitVal[0] { case "env": return []byte(os.Getenv(splitVal[1])), nil case "file": return os.ReadFile(splitVal[1]) default: return nil, fmt.Errorf("unknown prefix: %s", splitVal[0]) } default: return nil, fmt.Errorf("multiple prefixes: %s", strings.Join(splitVal[:len(splitVal)-1], ", ")) } } ================================================ FILE: helpers/helpers_test.go ================================================ package helpers import ( "bytes" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/pem" "math" "os" "testing" "time" "github.com/google/certificate-transparency-go" "golang.org/x/crypto/ocsp" ) const ( testCertFile = "testdata/cert.pem" testCertDERFile = "testdata/cert.der" testBundleFile = "testdata/bundle.pem" testExtraWSCertFile = "testdata/cert_with_whitespace.pem" testExtraWSBundleFile = "testdata/bundle_with_whitespace.pem" testMessedUpBundleFile = "testdata/messed_up_bundle.pem" testMessedUpCertFile = "testdata/messedupcert.pem" testEmptyCertFile = "testdata/emptycert.pem" testPrivateRSAKey = "testdata/priv_rsa_key.pem" testPrivateECDSAKey = "testdata/private_ecdsa_key.pem" testPrivateEd25519Key = "testdata/private_ed25519_key.pem" testPrivateOpenSSLECKey = "testdata/openssl_secp384.pem" testUnsupportedECDSAKey = "testdata/secp256k1-key.pem" testMessedUpPrivateKey = "testdata/messed_up_priv_key.pem" testEncryptedPrivateKey = "testdata/enc_priv_key.pem" testEmptyPem = "testdata/empty.pem" testNoHeaderCert = "testdata/noheadercert.pem" testSinglePKCS7 = "testdata/cert_pkcs7.pem" // openssl crl2pkcs7 -nocrl -out cert_pkcs7.pem -in cert.pem testEmptyPKCS7DER = "testdata/empty_pkcs7.der" // openssl crl2pkcs7 -nocrl -out empty_pkcs7.der -outform der testEmptyPKCS7PEM = "testdata/empty_pkcs7.pem" // openssl crl2pkcs7 -nocrl -out empty_pkcs7.pem -outform pem testMultiplePKCS7 = "testdata/bundle_pkcs7.pem" testPKCS12EmptyPswd = "testdata/emptypasswordpkcs12.p12" testPKCS12Passwordispassword = "testdata/passwordpkcs12.p12" testPKCS12MultipleCerts = "testdata/multiplecerts.p12" testCSRPEM = "testdata/test.csr.pem" testCSRPEMBad = "testdata/test.bad.csr.pem" ) func TestParseCertificatesDER(t *testing.T) { var password = []string{"password", "", ""} for i, testFile := range []string{testPKCS12Passwordispassword, testPKCS12EmptyPswd, testCertDERFile} { testDER, err := os.ReadFile(testFile) if err != nil { t.Fatal(err) } if _, _, err := ParseCertificatesDER(testDER, password[i]); err != nil { t.Fatal(err) } // Incorrect Password for PKCS12 formatted files if _, _, err := ParseCertificatesDER(testDER, "incorrectpassword"); err == nil && i != 2 { t.Fatal(err) } } testDER, err := os.ReadFile(testEmptyPKCS7DER) if err != nil { t.Fatal(err) } // PKCS7 with no certificates if _, _, err := ParseCertificatesDER(testDER, ""); err == nil { t.Fatal(err) } } func TestKeyLength(t *testing.T) { expNil := 0 recNil := KeyLength(nil) if expNil != recNil { t.Fatal("KeyLength on nil did not return 0") } expNonsense := 0 inNonsense := "string?" outNonsense := KeyLength(inNonsense) if expNonsense != outNonsense { t.Fatal("KeyLength malfunctioning on nonsense input") } // test the ecdsa branch ecdsaPriv, _ := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) ecdsaIn, _ := ecdsaPriv.Public().(*ecdsa.PublicKey) expEcdsa := ecdsaIn.Curve.Params().BitSize outEcdsa := KeyLength(ecdsaIn) if expEcdsa != outEcdsa { t.Fatal("KeyLength malfunctioning on ecdsa input") } // test the rsa branch rsaPriv, _ := rsa.GenerateKey(rand.Reader, 256) rsaIn, _ := rsaPriv.Public().(*rsa.PublicKey) expRsa := rsaIn.N.BitLen() outRsa := KeyLength(rsaIn) if expRsa != outRsa { t.Fatal("KeyLength malfunctioning on rsa input") } //test the ed25519 branch _, ed25519priv, _ := ed25519.GenerateKey(rand.Reader) ed25519In, _ := ed25519priv.Public().(ed25519.PublicKey) expEd25519 := len(ed25519In) outEd25519 := KeyLength(ed25519In) if expEd25519 != outEd25519 { t.Fatal("KeyLength malfunctioning on ed25519 input") } } func TestExpiryTime(t *testing.T) { // nil case var expNil time.Time inNil := []*x509.Certificate{} outNil := ExpiryTime(inNil) if expNil != outNil { t.Fatal("Expiry time is malfunctioning on empty input") } // read a pem file and use that expiry date bytes, _ := os.ReadFile(testBundleFile) certs, err := ParseCertificatesPEM(bytes) if err != nil { t.Fatalf("%v", err) } expected := time.Date(2014, time.April, 15, 0, 0, 0, 0, time.UTC) out := ExpiryTime(certs) if out != expected { t.Fatalf("Expected %v, got %v", expected, out) } } func TestMonthsValid(t *testing.T) { var cert = &x509.Certificate{ NotBefore: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC), NotAfter: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC), } if MonthsValid(cert) != 0 { t.Fail() } cert.NotAfter = time.Date(2016, time.April, 01, 0, 0, 0, 0, time.UTC) if MonthsValid(cert) != 12 { t.Fail() } // extra days should be rounded up to 1 month cert.NotAfter = time.Date(2016, time.April, 02, 0, 0, 0, 0, time.UTC) if MonthsValid(cert) != 13 { t.Fail() } } func TestHasValidExpiry(t *testing.T) { // Issue period > April 1, 2015 var cert = &x509.Certificate{ NotBefore: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC), NotAfter: time.Date(2016, time.April, 01, 0, 0, 0, 0, time.UTC), } if !ValidExpiry(cert) { t.Fail() } cert.NotAfter = time.Date(2019, time.April, 01, 01, 0, 0, 0, time.UTC) if ValidExpiry(cert) { t.Fail() } // Issue period < July 1, 2012 cert.NotBefore = time.Date(2009, time.March, 01, 0, 0, 0, 0, time.UTC) if ValidExpiry(cert) { t.Fail() } // Issue period July 1, 2012 - April 1, 2015 cert.NotBefore = time.Date(2012, time.July, 01, 0, 0, 0, 0, time.UTC) cert.NotAfter = time.Date(2017, time.July, 01, 0, 0, 0, 0, time.UTC) if !ValidExpiry(cert) { t.Fail() } } func TestHashAlgoString(t *testing.T) { if HashAlgoString(x509.MD2WithRSA) != "MD2" { t.Fatal("standin") } if HashAlgoString(x509.MD5WithRSA) != "MD5" { t.Fatal("standin") } if HashAlgoString(x509.SHA1WithRSA) != "SHA1" { t.Fatal("standin") } if HashAlgoString(x509.SHA256WithRSA) != "SHA256" { t.Fatal("standin") } if HashAlgoString(x509.SHA384WithRSA) != "SHA384" { t.Fatal("standin") } if HashAlgoString(x509.SHA512WithRSA) != "SHA512" { t.Fatal("standin") } if HashAlgoString(x509.DSAWithSHA1) != "SHA1" { t.Fatal("standin") } if HashAlgoString(x509.DSAWithSHA256) != "SHA256" { t.Fatal("standin") } if HashAlgoString(x509.ECDSAWithSHA1) != "SHA1" { t.Fatal("standin") } if HashAlgoString(x509.ECDSAWithSHA256) != "SHA256" { t.Fatal("standin") } if HashAlgoString(x509.ECDSAWithSHA384) != "SHA384" { t.Fatal("standin") } if HashAlgoString(x509.ECDSAWithSHA512) != "SHA512" { t.Fatal("standin") } if HashAlgoString(x509.PureEd25519) != "Ed25519" { t.Fatal("standin") } if HashAlgoString(math.MaxInt32) != "Unknown Hash Algorithm" { t.Fatal("standin") } } func TestSignatureString(t *testing.T) { if SignatureString(x509.MD2WithRSA) != "MD2WithRSA" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.MD5WithRSA) != "MD5WithRSA" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.SHA1WithRSA) != "SHA1WithRSA" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.SHA256WithRSA) != "SHA256WithRSA" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.SHA384WithRSA) != "SHA384WithRSA" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.SHA512WithRSA) != "SHA512WithRSA" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.DSAWithSHA1) != "DSAWithSHA1" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.DSAWithSHA256) != "DSAWithSHA256" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.ECDSAWithSHA1) != "ECDSAWithSHA1" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.ECDSAWithSHA256) != "ECDSAWithSHA256" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.ECDSAWithSHA384) != "ECDSAWithSHA384" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.ECDSAWithSHA512) != "ECDSAWithSHA512" { t.Fatal("Signature String functioning improperly") } if SignatureString(x509.PureEd25519) != "Ed25519" { t.Fatal("Signature String functioning improperly") } if SignatureString(math.MaxInt32) != "Unknown Signature" { t.Fatal("Signature String functioning improperly") } } func TestParseCertificatePEM(t *testing.T) { for _, testFile := range []string{testCertFile, testExtraWSCertFile, testSinglePKCS7} { certPEM, err := os.ReadFile(testFile) if err != nil { t.Fatal(err) } if _, err := ParseCertificatePEM(certPEM); err != nil { t.Log(testFile) t.Fatal(err) } } for _, testFile := range []string{testBundleFile, testMessedUpCertFile, testEmptyPKCS7PEM, testEmptyCertFile, testMultiplePKCS7} { certPEM, err := os.ReadFile(testFile) if err != nil { t.Fatal(err) } if _, err := ParseCertificatePEM(certPEM); err == nil { t.Fatal("Incorrect cert failed to raise error") } } } func TestParseCertificatesPEM(t *testing.T) { // expected cases for _, testFile := range []string{testBundleFile, testExtraWSBundleFile, testSinglePKCS7, testMultiplePKCS7} { bundlePEM, err := os.ReadFile(testFile) if err != nil { t.Fatal(err) } if _, err := ParseCertificatesPEM(bundlePEM); err != nil { t.Log(testFile) t.Fatal(err) } } // test failure cases // few lines deleted, then headers removed for _, testFile := range []string{testMessedUpBundleFile, testEmptyPKCS7PEM, testNoHeaderCert} { bundlePEM, err := os.ReadFile(testFile) if err != nil { t.Fatal(err) } if _, err := ParseCertificatesPEM(bundlePEM); err == nil { t.Fatal("Incorrectly-formatted file failed to produce an error") } } } func TestSelfSignedCertificatePEM(t *testing.T) { testPEM, err := os.ReadFile(testCertFile) if err != nil { t.Fatal(err) } _, err = ParseSelfSignedCertificatePEM(testPEM) if err != nil { t.Fatalf("%v", err) } // a few lines deleted from the pem file wrongPEM, err := os.ReadFile(testMessedUpCertFile) if err != nil { t.Fatal(err) } _, err2 := ParseSelfSignedCertificatePEM(wrongPEM) if err2 == nil { t.Fatal("Improper pem file failed to raise an error") } // alter the signature of a valid certificate blk, _ := pem.Decode(testPEM) blk.Bytes[len(blk.Bytes)-10]++ // some hacking to get to the sig alteredBytes := pem.EncodeToMemory(blk) _, err = ParseSelfSignedCertificatePEM(alteredBytes) if err == nil { t.Fatal("Incorrect cert failed to produce an error") } } func TestParsePrivateKeyPEM(t *testing.T) { // expected cases testRSAPEM, err := os.ReadFile(testPrivateRSAKey) if err != nil { t.Fatal(err) } _, err = ParsePrivateKeyPEM(testRSAPEM) if err != nil { t.Fatal(err) } testECDSAPEM, err := os.ReadFile(testPrivateECDSAKey) if err != nil { t.Fatal(err) } _, err = ParsePrivateKeyPEM(testECDSAPEM) if err != nil { t.Fatal(err) } testEd25519PEM, err := os.ReadFile(testPrivateEd25519Key) if err != nil { t.Fatal(err) } _, err = ParsePrivateKeyPEM(testEd25519PEM) if err != nil { t.Fatal(err) } testOpenSSLECKey, err := os.ReadFile(testPrivateOpenSSLECKey) if err != nil { t.Fatal(err) } _, err = ParsePrivateKeyPEM(testOpenSSLECKey) if err != nil { t.Fatal(err) } // error cases errCases := []string{ testMessedUpPrivateKey, // a few lines deleted testEmptyPem, // empty file testEncryptedPrivateKey, // encrypted key testUnsupportedECDSAKey, // ECDSA curve not currently supported by Go standard library } for _, fname := range errCases { testPEM, _ := os.ReadFile(fname) _, err = ParsePrivateKeyPEM(testPEM) if err == nil { t.Fatal("Incorrect private key failed to produce an error") } } } // Imported from signers/local/testdata/ const ecdsaTestCSR = "testdata/ecdsa256.csr" func TestParseCSRPEM(t *testing.T) { in, err := os.ReadFile(ecdsaTestCSR) if err != nil { t.Fatalf("%v", err) } _, _, err = ParseCSR(in) if err != nil { t.Fatalf("%v", err) } in[12]++ _, _, err = ParseCSR(in) if err == nil { t.Fatalf("Expected an invalid CSR.") } in[12]-- } func TestParseCSRPEMMore(t *testing.T) { csrPEM, err := os.ReadFile(testCSRPEM) if err != nil { t.Fatal(err) } if _, err := ParseCSRPEM(csrPEM); err != nil { t.Fatal(err) } csrPEM, err = os.ReadFile(testCSRPEMBad) if err != nil { t.Fatal(err) } if _, err := ParseCSRPEM(csrPEM); err == nil { t.Fatal(err) } if _, err := ParseCSRPEM([]byte("not even pem")); err == nil { t.Fatal("Expected an invalid CSR.") } } // Imported from signers/local/testdata/ const rsaOldTestCSR = "testdata/rsa-old.csr" func TestParseOldCSR(t *testing.T) { in, err := os.ReadFile(rsaOldTestCSR) if err != nil { t.Fatalf("%v", err) } _, _, err = ParseCSR(in) if err != nil { t.Fatalf("%v", err) } } // Imported from signers/local/testdata/ const clientCertFile = "testdata/ca.pem" const clientKeyFile = "testdata/ca_key.pem" func TestClientCertParams(t *testing.T) { _, err := LoadClientCertificate(testCertFile, testPrivateRSAKey) if err == nil { t.Fatal("Unmatched cert/key should generate error") } cert, err := LoadClientCertificate("", "") if err != nil || cert != nil { t.Fatal("Certificate atempted to loaded with missing key and cert") } cert, err = LoadClientCertificate(clientCertFile, "") if err != nil || cert != nil { t.Fatal("Certificate atempted to loaded with missing key") } cert, err = LoadClientCertificate("", clientKeyFile) if err != nil || cert != nil { t.Fatal("Certificate atempted to loaded with missing cert") } cert, err = LoadClientCertificate(clientCertFile, clientKeyFile) if err != nil { t.Fatal(err) } if cert == nil { t.Fatal("cert not created") } } func TestLoadPEMCertPool(t *testing.T) { certPool, err := PEMToCertPool([]byte{}) if certPool != nil || err != nil { t.Fatal("Empty file name should not generate error or a cert pool") } in, err := os.ReadFile(testEmptyPem) if err != nil { t.Fatalf("%v", err) } certPool, err = PEMToCertPool(in) if certPool != nil { t.Fatal("Empty file should not generate a cert pool") } else if err == nil { t.Fatal("Expected error for empty file") } in, err = os.ReadFile(testEmptyCertFile) if err != nil { t.Fatalf("%v", err) } certPool, err = PEMToCertPool(in) if certPool != nil { t.Fatal("Empty cert should not generate a cert pool") } else if err == nil { t.Fatal("Expected error for empty cert") } in, err = os.ReadFile(clientCertFile) if err != nil { t.Fatalf("%v", err) } certPool, err = PEMToCertPool(in) if err != nil { t.Fatalf("%v", err) } else if certPool == nil { t.Fatal("cert pool not created") } } // sctEquals returns true if all fields of both SCTs are equivalent. func sctEquals(sctA, sctB ct.SignedCertificateTimestamp) bool { if sctA.SCTVersion == sctB.SCTVersion && sctA.LogID == sctB.LogID && sctA.Timestamp == sctB.Timestamp && bytes.Equal(sctA.Extensions, sctB.Extensions) && sctA.Signature.Algorithm == sctB.Signature.Algorithm && bytes.Equal(sctA.Signature.Signature, sctA.Signature.Signature) { return true } return false } // NOTE: TestDeserializeSCTList tests both DeserializeSCTList and // SerializeSCTList. func TestDeserializeSCTList(t *testing.T) { // Here we make sure that empty SCT lists return an error emptyLists := [][]byte{nil, {}} for _, emptyList := range emptyLists { _, err := DeserializeSCTList(emptyList) if err == nil { t.Fatalf("DeserializeSCTList(%v) should raise an error\n", emptyList) } } // Here we make sure that an SCT list with a zero SCT is deserialized // correctly var zeroSCT ct.SignedCertificateTimestamp serializedSCT, err := SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT}) if err != nil { t.Fatal(err) } deserializedSCTList, err := DeserializeSCTList(serializedSCT) if err != nil { t.Fatal(err) } if !sctEquals(zeroSCT, (deserializedSCTList)[0]) { t.Fatal("SCTs don't match") } // Here we verify that an error is raised when the SCT list length // field is greater than its actual length serializedSCT, err = SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT}) if err != nil { t.Fatal(err) } serializedSCT[0] = 15 _, err = DeserializeSCTList(serializedSCT) if err == nil { t.Fatalf("DeserializeSCTList should raise an error when " + "the SCT list length field and the list length don't match\n") } // Here we verify that an error is raised when the SCT list length // field is less than its actual length serializedSCT[0] = 0 serializedSCT[1] = 0 _, err = DeserializeSCTList(serializedSCT) if err == nil { t.Fatalf("DeserializeSCTList should raise an error when " + "the SCT list length field and the list length don't match\n") } // Here we verify that an error is raised when the SCT length field is // greater than its actual length serializedSCT[0] = 0 serializedSCT[1] = 49 serializedSCT[2] = 1 _, err = DeserializeSCTList(serializedSCT) if err == nil { t.Fatalf("DeserializeSCTList should raise an error when " + "the SCT length field and the SCT length don't match\n") } // Here we verify that an error is raised when the SCT length field is // less than its actual length serializedSCT[2] = 0 serializedSCT[3] = 0 _, err = DeserializeSCTList(serializedSCT) if err == nil { t.Fatalf("DeserializeSCTList should raise an error when " + "the SCT length field and the SCT length don't match\n") } } func TestSCTListFromOCSPResponse(t *testing.T) { var response ocsp.Response lst, err := SCTListFromOCSPResponse(&response) if err != nil { t.Fatal(err) } if len(lst) != 0 { t.Fatal("SCTListFromOCSPResponse should return an empty SCT list for an empty extension") } var zeroSCT ct.SignedCertificateTimestamp serializedSCTList, err := SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT}) if err != nil { t.Fatal("failed to serialize SCT list") } serializedSCTList, err = asn1.Marshal(serializedSCTList) if err != nil { t.Fatal("failed to serialize SCT list") } // The value of Id below is the object identifier of the OCSP Stapling // SCT extension (see section 3.3. of RFC 6962). response.Extensions = []pkix.Extension{{ Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5}, Critical: false, Value: serializedSCTList, }} lst, err = SCTListFromOCSPResponse(&response) if err != nil { t.Fatal(err) } if !sctEquals(zeroSCT, lst[0]) { t.Fatal("SCTs don't match") } } ================================================ FILE: helpers/testdata/bundle.pem ================================================ -----BEGIN CERTIFICATE----- MIIEczCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv cm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAw MDAwWhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNs b3VkZmxhcmUtaW50ZXIuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIVkjNJGw f3F0XWJH7yQSVtxuoBidi5JNsQ7FhxEQcZEl3b+/1iF60TBY2Yi6KwJuA6nIE73P IXGyfNhThw4D8CiZbackQ/ufgz2DyvxyWFDPzLr7TXeM/0wSp/imoxWeo4GIMIGF MA4GA1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRB +YoiUjIm34/wBwHdJGE4Wufs/DAfBgNVHSMEGDAWgBTXXUgpaSwO9HOrQBxGqOOS FHsHEDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0B AQsDggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJd FI1UjL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHF A145JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j 4WCv5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7c WWOay6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvT br6+bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs 369/Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2Ygh PsypDo33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpw EPVqTR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS /mg1t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH 0thnUGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkDCCA/ugAwIBAgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAw MDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0 APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT 7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7 STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDAS BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRj bG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/ fWznVvOEFAAYZByPFx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9 fC7vf45B2zCX0OW51QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnch DaMsXjQQTJu0iuG3qKEuCmUwOmc= -----END CERTIFICATE----- ================================================ FILE: helpers/testdata/bundle_pkcs7.pem ================================================ -----BEGIN PKCS7----- MIIJOAYJKoZIhvcNAQcCoIIJKTCCCSUCAQExADALBgkqhkiG9w0BBwGgggkLMIIE czCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQGEwJV UzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVl cmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5p YTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAwMDAw WhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNsb3Vk RmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcTDVNh biBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNsb3Vk ZmxhcmUtaW50ZXIuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIVkjNJGwf3F0 XWJH7yQSVtxuoBidi5JNsQ7FhxEQcZEl3b+/1iF60TBY2Yi6KwJuA6nIE73PIXGy fNhThw4D8CiZbackQ/ufgz2DyvxyWFDPzLr7TXeM/0wSp/imoxWeo4GIMIGFMA4G A1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRB+Yoi UjIm34/wBwHdJGE4Wufs/DAfBgNVHSMEGDAWgBTXXUgpaSwO9HOrQBxGqOOSFHsH EDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsD ggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJdFI1U jL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHFA145 JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j4WCv 5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7cWWOa y6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvTbr6+ bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs369/ Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2YghPsyp Do33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpwEPVq TR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS/mg1 t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH0thn UGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuTMIIEkDCCA/ugAwIB AgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYTAlVTMRMwEQYDVQQI DApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKDApD bG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQGA1UEAwwNQ0ZTU0xf VEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAwMDBaMIGMMQswCQYD VQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBF bmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2Fs aWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHLAlI+xwnPhWgzj2Ve vD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0NgxxwQ2rC08fJtCnij lGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeWRbWuLH5nEMdyk9Np etS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fuu6pgMtHKvl4GGH0y vb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREUmlcY5EvpR141KXbZ qiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0APJx1VNSSH6XoDpU ETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsyssWBEN+CxK19xyPum r21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT7r3mzlBTYl3poU26 q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7STOs8wuTu3huSnan /IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuowTmmHlb8KIMa9mOvc uGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VNDDL3J/vSVlFeqLt2r eAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAG AQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsHEDAfBgNVHSMEGDAW gBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWlu dGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/fWznVvOEFAAYZByP Fx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9fC7vf45B2zCX0OW5 1QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnchDaMsXjQQTJu0iuG3 qKEuCmUwOmehADEA -----END PKCS7----- ================================================ FILE: helpers/testdata/bundle_with_whitespace.pem ================================================ -----BEGIN CERTIFICATE----- MIIEczCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv cm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAw MDAwWhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNs b3VkZmxhcmUtaW50ZXIuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIVkjNJGw f3F0XWJH7yQSVtxuoBidi5JNsQ7FhxEQcZEl3b+/1iF60TBY2Yi6KwJuA6nIE73P IXGyfNhThw4D8CiZbackQ/ufgz2DyvxyWFDPzLr7TXeM/0wSp/imoxWeo4GIMIGF MA4GA1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRB +YoiUjIm34/wBwHdJGE4Wufs/DAfBgNVHSMEGDAWgBTXXUgpaSwO9HOrQBxGqOOS FHsHEDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0B AQsDggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJd FI1UjL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHF A145JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j 4WCv5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7c WWOay6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvT br6+bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs 369/Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2Ygh PsypDo33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpw EPVqTR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS /mg1t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH 0thnUGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkDCCA/ugAwIBAgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAw MDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0 APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT 7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7 STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDAS BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRj bG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/ fWznVvOEFAAYZByPFx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9 fC7vf45B2zCX0OW51QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnch DaMsXjQQTJu0iuG3qKEuCmUwOmc= -----END CERTIFICATE----- ================================================ FILE: helpers/testdata/ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIEmzCCA4OgAwIBAgIMAMSvNBgypwaaSQ5iMA0GCSqGSIb3DQEBBQUAMIGMMQsw CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy YW5jaXNjbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVT VCBSb290IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTIx MjEyMDIxMDMxWhcNMjIxMDIxMDIxMDMxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNV BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoT CkNGU1NMIFRFU1QxGzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqG SIb3DQEJARYPdGVzdEB0ZXN0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsRp1xSfIDoD/40Bo4Hls3sFn4dav5NgxbZGpVyGF7dJI9u0eEnL4 BUGssPaUFLWC83CZxujUEiEfE0oKX+uOhhGv3+j5xSTNM764m2eSiN53cdZtK05d hwq9uS8LtjKOQeN1mQ5qmiqxBMdjkKgMsVw5lMCgoYKo57kaKFyXzdpNVDzqw+pt HWmuNtDQjK3qT5Ma06mYPmIGYhIZYLY7oJGg9ZEaNR0GIw4zIT5JRsNiaSb5wTLw aa0n/4vLJyVjLJcYmJBvZWj8g+taK+C4INu/jGux+bmsC9hq14tbOaTNAn/NE0qN 8oHwcRBEqfOdEYdZkxI5NWPiKNW/Q+AeXQIDAQABo4H6MIH3MB0GA1UdDgQWBBS3 0veEuqg51fusEM4p/YuWpBPsvTCBxAYDVR0jBIG8MIG5gBS30veEuqg51fusEM4p /YuWpBPsvaGBkqSBjzCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju aWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkNGU1NMIFRFU1Qx GzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqGSIb3DQEJARYPdGVz dEB0ZXN0LmxvY2FsggwAxK80GDKnBppJDmIwDwYDVR0TBAgwBgEB/wIBADANBgkq hkiG9w0BAQUFAAOCAQEAJ7r1EZYDwed6rS0+YKHdkRGRQ5Rz6A9DIVBPXrSMAGj3 F5EF2m/GJbhpVbnNJTVlgP9DDyabOZNxzdrCr4cHMkYYnocDdgAodnkw6GZ/GJTc depbVTR4TpihFNzeDEGJePrEwM1DouGswpu97jyuCYZ3z1a60+a+3C1GwWaJ7Aet Uqm+yLTUrMISsfnDPqJdM1NeqW3jiZ4IgcqJkieCCSpag9Xuzrp9q6rjmePvlQkv qz020JGg6VijJ+c6Tf5y0XqbAhkBTqYtVamu9gEth9utn12EhdNjTZMPKMjjgFUd H0N6yOEuQMl4ky7RxZBM0iPyeob6i4z2LEQilgv9MQ== -----END CERTIFICATE----- ================================================ FILE: helpers/testdata/ca_key.pem ================================================ -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGnXFJ8gOgP/j QGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLzcJnG6NQSIR8T Sgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B43WZDmqaKrEE x2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepPkxrTqZg+YgZi EhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMslxiYkG9laPyD 61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850Rh1mTEjk1Y+Io 1b9D4B5dAgMBAAECggEAKHhjcSomDSptTwDo9mLI/h40HudwSlsc8GzYxZBjinUD N2n39T9QbeMUE1xFenX/9qFEgq+xxnLLJx1EQacSapCgIAqdCO/f9HMgvGJumdg8 c0cMq1i9Bp7tu+OESZ5D48qWlOM2eQRIb08g8W11eRIaFmPuUPoKnuktkQuXpPJc YbS/+JuA8SDwe6sV0cMCQuS+iHFfeGwWCKrDUkhLwcL3waW3od2XFyOeFFWFhl0h HmM/mWKRuRdqR7hrmArTwFZVkB+o/1ywVYXIv+JQm0eNZ5PKLNJGL2f5oxbMR/JI AoK0bAlJmYaFp96h1KpbPwLEL/0hHSWA7sAyJIgQAQKBgQDaEAZor/w4ZUTekT1+ cbId0yA+ikDXQOfXaNCSh9Pex+Psjd5zVVOqyVFJ29daRju3d7rmpN4Cm5V4h0l1 /2ad207rjCAnpCHtaddJWNyJzF2IL2IaoCZQRp0k7zOjBGQpoWDTwBaEin5CCv3P kkdQkKz6FDP1xskHSLZr21/QCQKBgQDP6jXutEgGjf3yKpMFk/69EamJdon8clbt hl7cOyWtobnZhdOWVZPe00Oo3Jag2aWgFFsm3EtwnUCnR4d4+fXRKS2LkhfIUZcz cKy17Ileggdd8UGhL4RDrF/En9tJL86WcVkcoOrqLcGB2FLWrVhVpHFK74eLMCH/ uc/+ioPItQKBgHYoDsD08s7AGMQcoNx90MyWVLduhFnegoFW+wUa8jOZzieka6/E wVQeR5yksZjpy3vLNYu6M83n7eLkM2rrm/fXGHlLcTTpm7SgEBZfPwivotKjEh5p PrlqucWEk082lutz1RqHz+u7e1Rfzk2F7nx6GDBdeBYpw03eGXJx6QW5AoGBAIJq 4puyAEAET1fZNtHX7IGCk7sDXTi6LCbgE57HhzHr8V0t4fQ6CABMuvMwM1gATjEk s6yjoLqqGUUUzDipanViBAy5fiuManC868lN7zkWDTLzQ3ytBqVAee4na/DziP27 ae9YTSLJwskE/alloLRP6zTbHUXE0n7LelmrX1DFAoGBAMFLl+Lu+WFgCHxBjn43 rHpJbQZQmsFhAMhkN4hsj6dJfAGn2gRLRiVRAika+8QF65xMZiVQWUVSUZADWERi 0SXGjzN1wYxO3Qzy3LYwws6fxFAq5lo79eb38yFT2lHdqK3x/QgiDSRVl+R6cExV xQB518/lp2eIeMpglWByDwJX -----END PRIVATE KEY----- ================================================ FILE: helpers/testdata/cert.pem ================================================ -----BEGIN CERTIFICATE----- MIIB7DCCAZKgAwIBAgIIE/Qz49ebG7kwCgYIKoZIzj0EAwIwTDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x EDAOBgNVBAoTB2FjbWUuY28wHhcNMTcwNTIzMTk1MTQ0WhcNMTcwODIzMDE1NjQ0 WjBMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHYWNtZS5jbzBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABEW8F+k/avvdBm/KRsuDnTZ3p+VuVdsqDF+aD9nIYeOhx5sj574y hEIZOpgbEsi3BvqY63y2jYyPFodf25+CA9GjXjBcMA4GA1UdDwEB/wQEAwIFoDAd BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNV HQ4EFgQUzDpu+HN89EC1M8aNl7f0Ln5JnnIwCgYIKoZIzj0EAwIDSAAwRQIgC4/r urbw/pzE3LDA6GpIts6TVyzgftLLEfU2BzQsjp0CIQDo+sn8t7XC6JN4KKRr2ABl ZI+JifgG+2KCy9ln2LxGJQ== -----END CERTIFICATE----- ================================================ FILE: helpers/testdata/cert_pkcs7.pem ================================================ -----BEGIN PKCS7----- MIICHQYJKoZIhvcNAQcCoIICDjCCAgoCAQExADALBgkqhkiG9w0BBwGgggHwMIIB 7DCCAZKgAwIBAgIIE/Qz49ebG7kwCgYIKoZIzj0EAwIwTDELMAkGA1UEBhMCVVMx EzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEDAO BgNVBAoTB2FjbWUuY28wHhcNMTcwNTIzMTk1MTQ0WhcNMTcwODIzMDE1NjQ0WjBM MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2Fu IEZyYW5jaXNjbzEQMA4GA1UEChMHYWNtZS5jbzBZMBMGByqGSM49AgEGCCqGSM49 AwEHA0IABEW8F+k/avvdBm/KRsuDnTZ3p+VuVdsqDF+aD9nIYeOhx5sj574yhEIZ OpgbEsi3BvqY63y2jYyPFodf25+CA9GjXjBcMA4GA1UdDwEB/wQEAwIFoDAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4E FgQUzDpu+HN89EC1M8aNl7f0Ln5JnnIwCgYIKoZIzj0EAwIDSAAwRQIgC4/rurbw /pzE3LDA6GpIts6TVyzgftLLEfU2BzQsjp0CIQDo+sn8t7XC6JN4KKRr2ABlZI+J ifgG+2KCy9ln2LxGJaEAMQA= -----END PKCS7----- ================================================ FILE: helpers/testdata/cert_with_whitespace.pem ================================================ -----BEGIN CERTIFICATE----- MIIB7DCCAZKgAwIBAgIIE/Qz49ebG7kwCgYIKoZIzj0EAwIwTDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x EDAOBgNVBAoTB2FjbWUuY28wHhcNMTcwNTIzMTk1MTQ0WhcNMTcwODIzMDE1NjQ0 WjBMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHYWNtZS5jbzBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABEW8F+k/avvdBm/KRsuDnTZ3p+VuVdsqDF+aD9nIYeOhx5sj574y hEIZOpgbEsi3BvqY63y2jYyPFodf25+CA9GjXjBcMA4GA1UdDwEB/wQEAwIFoDAd BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNV HQ4EFgQUzDpu+HN89EC1M8aNl7f0Ln5JnnIwCgYIKoZIzj0EAwIDSAAwRQIgC4/r urbw/pzE3LDA6GpIts6TVyzgftLLEfU2BzQsjp0CIQDo+sn8t7XC6JN4KKRr2ABl ZI+JifgG+2KCy9ln2LxGJQ== -----END CERTIFICATE----- ================================================ FILE: helpers/testdata/ecdsa256.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBgTCCASgCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBn9Ldie6BOcMHezn2dPuYqW z/NoLYMLGNBqhOxUyEidYClI0JW2pWyUgT3A2UazFp1WgE94y7Z+2YlfRz+vcrKg PzA9BgkqhkiG9w0BCQ4xMDAuMCwGA1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3 d3djbG91ZGZsYXJlLmNvbTAKBggqhkjOPQQDAgNHADBEAiBM+QRxe8u6rkdr10Jy cxbR6NxrGrNeg5QqiOqF96JEmgIgDbtjd5e3y3I8W/+ih2us3WtMxgnTXfqPd48i VLcv28Q= -----END CERTIFICATE REQUEST----- ================================================ FILE: helpers/testdata/empty.pem ================================================ ================================================ FILE: helpers/testdata/empty_pkcs7.pem ================================================ -----BEGIN PKCS7----- MCcGCSqGSIb3DQEHAqAaMBgCAQExADALBgkqhkiG9w0BBwGgAKEAMQA= -----END PKCS7----- ================================================ FILE: helpers/testdata/emptycert.pem ================================================ -----BEGIN CERTIFICATE----- -----END CERTIFICATE-----LSKFSKLF ================================================ FILE: helpers/testdata/enc_priv_key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,90B8A5792FA2FE75B2053582F3DF394F yVY2xuth5fdJBg9gg+6eP3qTsr0CJ2mGEDW6rvYmYuATSRF1hVERrsznxJYjYLaw JHec8FVr78y4aXxI/aFzlxLkS8f12WjTtIhzHwhzgSJDwVOXSRphnLAeHWnhEKLe 7kO+vzoTPIc3ECwdvtr6//z2tP1/sac+yIhL6C+x2rS5hFHhmDUXtILPxxfHJCiM qtKiiOZz3W6008CeJMC9ZPlKHDvpq7aIL4rfVP/GkZ+/teQkgWNpMxac7+gWLKuK 109v6pu+8KT49D6SMsaZPvAb5PXcIB79ZCPI1JX0V26CKcswba4RHG/h1xifwyAF OIvmK29mmFqbx5GPlUefRUuPwRJKCXFiK6LTdhCwLYodtXde4ibvOFYy4onGoVax I5WVaOhQMqp+mxA6z7odrIvuFcQGixIA+peaaSbpNZSZGuxRvVefcdxPbJ+26Ijs wq8uyalbwhKtjPTPNkMaaYzJdWS7wd2DS4RM9JT8Y1h6NTftCY3c+/txOlt5pQzW T8n+NTd4o+PFOHzMnmEnrtf9Y/SSzXDB2OPCD95YdIXItQDdKcjK0NmnY8GNfkWL G30NJNy3/DR7Sa5u4xuqNgcgTFhgZaOQ1IVB3p5VjknqAX3gWFu2DrqzbH45071A He7VbdbzBpMHI2EdiCVOuK9fD/5sv25u9vVC2NHtG/YcoEQv+RB52TNHn9kdiMj1 gLaywPqGjFmaPxI0xX07BrL+D9RruUT1GAEyw4JAHuJZIyq3+V98wmV/pEqwc7hp 8WuSi6YddetfF4NPA5cGWt8qZ1it+wD/1ydQEAQsxdANqi0XVudYpYox02EoRS02 up0sd9zqz83pN9RyOOKtGcHdt85gb9DYRVeff1UszMaoVULxqxYetwtzpiHn6grL DmnSk+DYgvXKOVt8tmSJysDTumhK1VN3xb34TYYJxeBOQJLzWFjGSELEpphZAQSj rS4OM1FwoP48wvASGiWD4VUJ6v+6F+NDvJr01S+zWGLg1EeUZJmXGHW5GrGd4Kgx 3rdeOsrED9oXKp2cpgx9avXJ9upixja9MbAPp7RkSyeHMPvsuaI44xvOP3f0crmG d/5CdBKVT7nFaeTGSx/78kHb3VJyopAMm9k0V3CheKwBXXSbXmV1+0muBxMHsEI3 aEKaI0y5cDfTewzo/U0l0kGtxF6kUPN1pdjFpAvssRlkGttFOC2nWxHwaNHpn7Kq gFAlN6P4cyB6kb+LvckIYTZ/tV39dx7PfL0KG5TWjJ4a9GSoL1IrAhQq+Qv6oUEt 1vlejZoKyZ/35fni0fmeYNho+pCPimm6l+sHTuXkrWgGLr0S9O00HFLz11D7R4o9 7mF4JkMNztT+ENOdT4xQBi3OGjRGMwtE6PsQPfDeu13Vq6eDtdEGUdhW1kAsGnBi eJRuysnGpnoWofJ7yS0+DhnS4GAVi907TMrQWwmez9V4CXl4NBc8X9T69TFL2LsW 2KU9NUXdiCRZqZHD41gd3+RuRA/oXh50V9oaow+uepwYKTFyzde5IH1/DgBd7tOd Fa2fM5/zSA0uFPRb3yCVhRg5d6J9t5yaPAz7Jp0D1mDDGsMBD1O/FYJvWoANEwUX -----END RSA PRIVATE KEY----- ================================================ FILE: helpers/testdata/messed_up_bundle.pem ================================================ -----BEGIN CERTIFICATE----- MIIEczCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv cm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAw MDAwWhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT FHsHEDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0B AQsDggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJd FI1UjL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHF A145JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j 4WCv5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7c WWOay6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvT br6+bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs 369/Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2Ygh PsypDo33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpw EPVqTR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS /mg1t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH 0thnUGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkDCCA/ugAwIBAgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAw MDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0 APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT 7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7 STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDAS BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRj bG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/ fWznVvOEFAAYZByPFx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9 fC7vf45B2zCX0OW51QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnch DaMsXjQQTJu0iuG3qKEuCmUwOmc= -----END CERTIFICATE----- SDFSDKjkfdlsdfj ================================================ FILE: helpers/testdata/messed_up_priv_key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAvGKyz9ZzIXI/BFrtqbVQMmKQkPZGndyfV3AzeSb2ulbS/s5k yNJMH/jKZiSCvZiJNnW+JNlJrgLxORMmPStPz/N/0L0vCTotQKZUiaBttFgHgobQ LFsbMnumt9It5W/uOwgWI9binuzvqyPXywLlYwOq3jkOmA22ymhflzRrl6a3jzcY hT9evxHl0gV4bN7KZ5p4wK/UUuG1uMEQLw87lUwRRHeW3ZG52VL38+redka+f5pa SGKyG5j0oe1NPLqAjckNgqvDdPMY2gicmCq0VSLzTNpHRsURTUSJvC/iv34vVfba gIYgTvm8BvGbJSlZqP4kEVlOfd3vmB0ttUeoDwIDAQABAoIBAHZdpXCFlA1d1U6N O2s4a01dNOyAcVpa9xtfelgTLU9jomtLj3PG/uHP1oxbQHKUVxKK5JAOnwbg/mQY LhydDCbjHlovpFAt56UJXXCkBoocDYvr3P0huXL80oIJY6EXtR4ONKsMJ5Qn12c2 vC3ogey2rzO1sf/EDigbcIR3AWtk1Tx8ZDUooktOFypIsDQgjjxXiURGssAlMPSh 6GVgO4JRRG6oRxEna7yDe7izmh/hC5sxSYLsEikCgYEAsBHhb/Qef5obRCSrfFuQ 41P7MCtGrXVxKD3iCDGQCzVbEbYGpmZnGsXSaHljp2FtnamaGGEudYziozGKPHjs pbTbsLIDbmNwxz1WcaZ1iyIjtOxcAEqDod8hY4hL6SaxypwTHn4Ydbw2NGzp11Eg Di4SVL82utjycATdKFvBzdsCgYB/3M+GMrt0Sh87rKcQLdL709Kzjcfhvm4HjIbJ GSXGPCZaYMKaXRTdNAjtRKxMawc9qcf0xSBEHL0GkB158TzusDQtjP1anTcYOnl6 GsO4bRivp314iNlP4r3S3bIXqBxCGH3HbrvpdPFAN//qjYmAki2lFQZywfvbQOE8 oFQHwQKBgHqJkTck2DGlXQIwA7jirLggISXjSPlsG4w4LuhY9ivyNKLUi4x5k1cE bX7SrRtJErQ1WaDN4TFG25xnysi5h+aPinuySatd0XmA5+dE1YjTqqShMO+lUpzi PrOQl6Eva/uw5BDAcUH4AaXTNRvvtXQptUil9qXyOh6fszikA9Mm -----END RSA PRIVATE KEY----- ================================================ FILE: helpers/testdata/messedupcert.pem ================================================ -----BEGIN CERTIFICATE----- MIIB7jCCAVmgAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTEyMDkwNzIyMDAwNFoXDTEzMDkwNzIy MDUwNFowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGd MAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1C cqhEvLFbu3MCAwEAAaMyMDAwDgYDVR0PAQH/BAQDAgCgMA0GA1UdDgQGBAQBAgME MA8GA1UdIwQIMAaABAECAwQwCwYJKoZIhvcNAQEFA4GBABndWRIcfi+QB9Sakr+m dYnXTgYCnFio53L2Z+6EHTGG+rEhWtUEGhL4p4pzXX4siAnjWvwcgXTo92cafcfi uB7wRfK+NL9CTJdpN6cdL+fiNHzH8hsl3bj1nL0CSmdn2hkUWVLbLhSgWlib/I8O aq+K7aVrgHkPnWeRiG6tl+ZA -----END CERTIFICATE----- ================================================ FILE: helpers/testdata/noheadercert.pem ================================================ MIIB7jCCAVmgAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTEyMDkwNzIyMDAwNFoXDTEzMDkwNzIy MDUwNFowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGd MAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1C cqhEvLFbu3MCAwEAAaMyMDAwDgYDVR0PAQH/BAQDAgCgMA0GA1UdDgQGBAQBAgME MA8GA1UdIwQIMAaABAECAwQwCwYJKoZIhvcNAQEFA4GBABndWRIcfi+QB9Sakr+m dYnXTgYCnFio53L2Z+6EHTGG+rEhWtUEGhL4p4pzXX4siAnjWvwcgXTo92cafcfi uB7wRfK+NL9CTJdpN6cdL+fiNHzH8hsl3bj1nL0CSmdn2hkUWVLbLhSgWlib/I8O aq+K7aVrgHkPnWeRiG6tl+ZA ================================================ FILE: helpers/testdata/openssl_secp384.pem ================================================ -----BEGIN EC PARAMETERS----- BgUrgQQAIg== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MIGkAgEBBDCn5safCQ6/JAUEbf1/BvOBvP9XHfcsEvQooEd0g0v4akMNmH53nXKQ qvsZBUP14X6gBwYFK4EEACKhZANiAAR1q1+sGy8Pmgdco9LEB10gJkIO0lBid8aK 0xmtEL7U1RTQnNyraswwI0hxHwzwSHHKojD8Msdy5uOngxKnGrUBTuMubezfGbWz ULOFvrTemUIlNmSsWMcrzEBEnZxvOqY= -----END EC PRIVATE KEY----- ================================================ FILE: helpers/testdata/priv_rsa_key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAvGKyz9ZzIXI/BFrtqbVQMmKQkPZGndyfV3AzeSb2ulbS/s5k yNJMH/jKZiSCvZiJNnW+JNlJrgLxORMmPStPz/N/0L0vCTotQKZUiaBttFgHgobQ LFsbMnumt9It5W/uOwgWI9binuzvqyPXywLlYwOq3jkOmA22ymhflzRrl6a3jzcY hT9evxHl0gV4bN7KZ5p4wK/UUuG1uMEQLw87lUwRRHeW3ZG52VL38+redka+f5pa SGKyG5j0oe1NPLqAjckNgqvDdPMY2gicmCq0VSLzTNpHRsURTUSJvC/iv34vVfba gIYgTvm8BvGbJSlZqP4kEVlOfd3vmB0ttUeoDwIDAQABAoIBAHZdpXCFlA1d1U6N O2s4a01dNOyAcVpa9xtfelgTLU9jomtLj3PG/uHP1oxbQHKUVxKK5JAOnwbg/mQY LhydDCbjHlovpFAt56UJXXCkBoocDYvr3P0huXL80oIJY6EXtR4ONKsMJ5Qn12c2 vC3ogey2rzO1sf/EDigbcIR3AWtk1Tx8ZDUooktOFypIsDQgjjxXiURGssAlMPSh 1BFz4StRUK4bESaja0GiHwbuxHa+XYEBlK5OqMo/fpWqpgHhV/42+7wdcBMJsMr8 rFBe6m+r6TTbLSGJNowyd05XrjoAI35qduckpJ3Voun90i4ynTudjdJ/vHpIqB74 qQLFW2ECgYEA+GSRVqobaKKakNUFGmK0I5T5Tikz5f137YXXER6aLtDQNiSrlXNi 0aphkC/EfRO3oNvamq5+55bmmgDVoNNPDfpajKz+LZyG8GC2EXlTKO0hZS64KRRl C+bd+ZsYiUDImNVRbIHN82f+BQgsgXlTaWpBOrEqmoePO/J44O4eX3cCgYEAwieq amY4UaY+MhWPJFRK1y9M3hM8+N9N/35CFewQUdFJosC6vVQ4t8jNkSOxVQdgbNwE i/bTBgIwg82JJYbBUPuCVeTT3i6zxymf/FLumrI73URD81IN6FiH1skg0hSFrvs0 6GVgO4JRRG6oRxEna7yDe7izmh/hC5sxSYLsEikCgYEAsBHhb/Qef5obRCSrfFuQ 41P7MCtGrXVxKD3iCDGQCzVbEbYGpmZnGsXSaHljp2FtnamaGGEudYziozGKPHjs pbTbsLIDbmNwxz1WcaZ1iyIjtOxcAEqDod8hY4hL6SaxypwTHn4Ydbw2NGzp11Eg Di4SVL82utjycATdKFvBzdsCgYB/3M+GMrt0Sh87rKcQLdL709Kzjcfhvm4HjIbJ GSXGPCZaYMKaXRTdNAjtRKxMawc9qcf0xSBEHL0GkB158TzusDQtjP1anTcYOnl6 GsO4bRivp314iNlP4r3S3bIXqBxCGH3HbrvpdPFAN//qjYmAki2lFQZywfvbQOE8 oFQHwQKBgHqJkTck2DGlXQIwA7jirLggISXjSPlsG4w4LuhY9ivyNKLUi4x5k1cE bX7SrRtJErQ1WaDN4TFG25xnysi5h+aPinuySatd0XmA5+dE1YjTqqShMO+lUpzi PrOQl6Eva/uw5BDAcUH4AaXTNRvvtXQptUil9qXyOh6fszikA9Mm -----END RSA PRIVATE KEY----- ================================================ FILE: helpers/testdata/private_ecdsa_key.pem ================================================ -----BEGIN EC PRIVATE KEY----- MGgCAQEEHCGXsrNo2xfy8+zd4Pzj8rcQ5KqQO43au1t/7nugBwYFK4EEACGhPAM6 AASJodCTtj5aYXnWxMiYhwjEgNQJJbNzJFEbsGJX9pCWZC673ammTWFHMjnMPkS/ 9eU5YeW40BHqfw== -----END EC PRIVATE KEY----- ================================================ FILE: helpers/testdata/private_ed25519_key.pem ================================================ -----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIEHfDC6M85b3uVU5GO82Y5D6Qkx5YehoCe2T1auTbTFN -----END PRIVATE KEY----- ================================================ FILE: helpers/testdata/rsa-old.csr ================================================ -----BEGIN NEW CERTIFICATE REQUEST----- MIIDCTCCAfMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTWdoYxX4KN51fP WxQAyGH++VsPbfpAoXIbCPXSmU04BvIxyjzpHQ0ChMKkT/2VNcUeFJwk2fCf+ZwU f0raTQTplofwkckE0gEYA3WcEfJp+hbvbTb/2recsf+JE6JACYJe2Uu5wsjtrE5j A+7aT2BEU9RWzBdSy/5281ZfW3PArqcWaf8+RUyA3WRxVWmjmhFsVB+mdNLhCpW0 C0QNMYR1ppEZiKVnEdao8gcI5sOvSd+35t8g82aPXcNSPU6jKcx1YNUPX5wgPEmu +anfc9RliQbYqqJYVODgBmV8IR5grw93yTsODoWKtFQ4PKVlnt9CD8AS/iSMQYm3 OUogqgMCAwEAAaA/MD0GCSqGSIb3DQEJDjEwMC4wLAYDVR0RBCUwI4IOY2xvdWRm bGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAsGCSqGSIb3DQEBCwOCAQEAl809 gk9uZkRK+MJVYDSLjgGR2xqk5qOwnhovnispA7N3Z1GshodJRQa6ngNCKuXIm2/6 AxB9kDGK14n186Qq4odXqHSHs8FG9i0zUcBXeLv1rPAKtwKTas/SLmsOpPgWPZFa iYiHHeu4HjOQoF987d7uGRYwc3xfstKwJsEXc12eCw2NH8TM1tJgSc/o6CzIpA91 QnZKhx6uGM4xI2gnOaJA1YikNhyFGBuOGMZgd0k2+/IcR2pg0z4pc5oQw1bXLANx anqlA/MDrCM9v9019bRJ73zK8LQ3k/FW61PA9nL7RZ8ku65R+uYcVEdLa8pUeqnH cJZNboDRsItpccZuRQ== -----END NEW CERTIFICATE REQUEST----- ================================================ FILE: helpers/testdata/secp256k1-key.pem ================================================ -----BEGIN EC PRIVATE KEY----- MHQCAQEEIJLKycmoCAk4HqlJGdsuFyHsxfIheKsLH91tS/TNP5OOoAcGBSuBBAAK oUQDQgAEBkmL7cvC2cgchzfSuUZPGnzH0FqBtf3kGhSllQiIzGDn4envPXNqp+93 V2NZ8VT+Aba4ln2Vbp9gYrKquut5Zg== -----END EC PRIVATE KEY----- ================================================ FILE: helpers/testdata/test.bad.csr.pem ================================================ -----BEGIN CERTIFICATE REQUEST----- MIICzDCCAbQCAQAwgYYxCzAJBgNVBAYTAkVOMQ0wCwYDVQQIDARub25lMQ0wCwYD VQQHDARub25lMRIwEAYDVQQKDAlXaWtpcGVkaWExDTALBgNVBAsMBG5vbmUxGDAW BgNVBAMMDyoud2lraXBlZGlhLm9yZzEcMBoGCSqGSIb3DQEJARYNbm9uZUBub25l LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMP/U8RlcCD6E8AL PT8LLUR9ygyygPCaSmIEC8zXGJung3ykElXFRz/Jc/bu0hxCxi2YDz5IjxBBOpB/ kieG83HsSmZZtR+drZIQ6vOsr/ucvpnB9z4XzKuabNGZ5ZiTSQ9L7Mx8FzvUTq5y 57HhA7ECAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4IBAQBn8OCVOIx+n0AS6WbEmYDR SspR9xOCoOwYfamB+2Bpmt82R01zJ/kaqzUtZUjaGvQvAaz5lUwoMdaO0X7I5Xfl sllMFDaYoGD4Rru4s8gz2qG/QHWA8uPXzJVAj6X0olbIdLTEqTKsnBj4Zr1AJCNy /YcG4ouLJr140o26MhwBpoCRpPjAgdYMH60BYfnc4/DILxMVqR9xqK1s98d6Ob/+ 3wHFK+S7BRWrJQXcM8veAexXuk9lHQ+FgGfD0eSYGz0kyP26Qa2pLTwumjt+nBPl rfJxaLHwTQ/1988G0H35ED0f9Md5fzoKi5evU1wG5WRxdEUPyt3QUXxdQ69i0C+7 -----END CERTIFICATE REQUEST----- ================================================ FILE: helpers/testdata/test.csr.pem ================================================ -----BEGIN CERTIFICATE REQUEST----- MIICzDCCAbQCAQAwgYYxCzAJBgNVBAYTAkVOMQ0wCwYDVQQIDARub25lMQ0wCwYD VQQHDARub25lMRIwEAYDVQQKDAlXaWtpcGVkaWExDTALBgNVBAsMBG5vbmUxGDAW BgNVBAMMDyoud2lraXBlZGlhLm9yZzEcMBoGCSqGSIb3DQEJARYNbm9uZUBub25l LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMP/U8RlcCD6E8AL PT8LLUR9ygyygPCaSmIEC8zXGJung3ykElXFRz/Jc/bu0hxCxi2YDz5IjxBBOpB/ kieG83HsSmZZtR+drZIQ6vOsr/ucvpnB9z4XzKuabNGZ5ZiTSQ9L7Mx8FzvUTq5y /ArIuM+FBeuno/IV8zvwAe/VRa8i0QjFXT9vBBp35aeatdnJ2ds50yKCsHHcjvtr 9/8zPVqqmhl2XFS3Qdqlsprzbgksom67OobJGjaV+fNHNQ0o/rzP//Pl3i7vvaEG 7Ff8tQhEwR9nJUR1T6Z7ln7S6cOr23YozgWVkEJ/dSr6LAopb+cZ88FzW5NszU6i 57HhA7ECAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4IBAQBn8OCVOIx+n0AS6WbEmYDR SspR9xOCoOwYfamB+2Bpmt82R01zJ/kaqzUtZUjaGvQvAaz5lUwoMdaO0X7I5Xfl sllMFDaYoGD4Rru4s8gz2qG/QHWA8uPXzJVAj6X0olbIdLTEqTKsnBj4Zr1AJCNy /YcG4ouLJr140o26MhwBpoCRpPjAgdYMH60BYfnc4/DILxMVqR9xqK1s98d6Ob/+ 3wHFK+S7BRWrJQXcM8veAexXuk9lHQ+FgGfD0eSYGz0kyP26Qa2pLTwumjt+nBPl rfJxaLHwTQ/1988G0H35ED0f9Md5fzoKi5evU1wG5WRxdEUPyt3QUXxdQ69i0C+7 -----END CERTIFICATE REQUEST----- ================================================ FILE: helpers/testsuite/testdata/cert_csr.json ================================================ { "hosts": [ "ca.example2.com" ], "names": [ { "C": "US", "ST": "California", "L": "San Francisco", "O": "Internet Widgets, LLC", "OU": "Certificate Authority" } ], "key": { "algo": "rsa", "size": 2048 } } ================================================ FILE: helpers/testsuite/testdata/initCA/ca_csr.json ================================================ { "cn": "example.com", "hosts": [ "ca.example.com" ], "names": [ { "C": "US", "ST": "California", "L": "San Francisco", "O": "Internet Widgets, LLC", "OU": "Certificate Authority" } ], "key": { "algo": "rsa", "size": 2048 }, "ca": { "pathlen": 1, "expiry": "1/1/2015" } } ================================================ FILE: helpers/testsuite/testdata/initCA/cfssl_output.pem ================================================ {"cert":"-----BEGIN CERTIFICATE-----\nMIIECjCCAvKgAwIBAgIIIrWBQ2reGCQwDQYJKoZIhvcNAQELBQAwgZAxCzAJBgNV\nBAYTAlVTMR4wHAYDVQQKExVJbnRlcm5ldCBXaWRnZXRzLCBMTEMxHjAcBgNVBAsT\nFUNlcnRpZmljYXRlIEF1dGhvcml0eTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET\nMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTUw\nOTA5MjExNjAwWhcNMTUwOTA5MjExNjAwWjCBkDELMAkGA1UEBhMCVVMxHjAcBgNV\nBAoTFUludGVybmV0IFdpZGdldHMsIExMQzEeMBwGA1UECxMVQ2VydGlmaWNhdGUg\nQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxp\nZm9ybmlhMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBALOFN1p4aaMQKqInRanzmf05CD4kYKKVygggOHhD3ZgwFgIG\n20Z0dlTHStY/UvY+2qkpB1Bp9trmys9YvPzt5ElX2szZ2deZc0TWvzZeuZDQVsbx\n0Ea6RGxRnEEoMrpaRFoe2TOKSVKW+SzLC/eoNUoxsZVo6cNsU4BeGqExOWCDFzjd\nCRLJeXqafYeL1dUiXZ028tOZVWLIjaLu3FKENHeDB36gr99KckFdeDnqaAVvu66V\nbF5QGvIv2RmK9y3cq7rIizYfayi/dBS8/AY31OOHcEGsVTZYjqB/s9aIocCOzfvQ\nV5++QdkDiYhIwokB3fT5b4wIb8CLr0GUnHnslnMCAwEAAaNmMGQwDgYDVR0PAQH/\nBAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFCL83Uiwa3VGSXwD\nf8XKgu1l+nX8MB8GA1UdIwQYMBaAFCL83Uiwa3VGSXwDf8XKgu1l+nX8MA0GCSqG\nSIb3DQEBCwUAA4IBAQCRP7HK4JHxY4uYE3VBkx5SSQouZrnpQCOnUhSof3vi5nk0\nlhfIU7nbS6HVyQC4mY47gDrBlKwTr++Kw9BKyK9EgfVWhct8vszcRexZk5mmO3yi\n3s4kqD158SP0t5AMahHGK/VviD/Id4kaX1PIPHW3TfU3Ly4LP6d/NlloaXc8qrsg\nKJO+AXTy9xnEkjtq7lvnP3JLwA1Y+nozqkp46kQv0K+Nz+MBqN5De12I9J7T0k6h\nij4MsiraPdeij6d1cp+OEW8DPe+MCIBYAvbJXtQY5zYPB2/F6JJHMeQ9AmluvUFn\nD3ipCSVbw1Tgpp8xcx+4rt9Vq6Oo8pGi4JR3C7TN\n-----END CERTIFICATE-----\n","csr":"-----BEGIN CERTIFICATE REQUEST-----\nMIIDAjCCAeoCAQAwgZAxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVJbnRlcm5ldCBX\naWRnZXRzLCBMTEMxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEWMBQG\nA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UE\nAxMLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz\nhTdaeGmjECqiJ0Wp85n9OQg+JGCilcoIIDh4Q92YMBYCBttGdHZUx0rWP1L2Ptqp\nKQdQafba5srPWLz87eRJV9rM2dnXmXNE1r82XrmQ0FbG8dBGukRsUZxBKDK6WkRa\nHtkziklSlvksywv3qDVKMbGVaOnDbFOAXhqhMTlggxc43QkSyXl6mn2Hi9XVIl2d\nNvLTmVViyI2i7txShDR3gwd+oK/fSnJBXXg56mgFb7uulWxeUBryL9kZivct3Ku6\nyIs2H2sov3QUvPwGN9Tjh3BBrFU2WI6gf7PWiKHAjs370FefvkHZA4mISMKJAd30\n+W+MCG/Ai69BlJx57JZzAgMBAAGgLDAqBgkqhkiG9w0BCQ4xHTAbMBkGA1UdEQQS\nMBCCDmNhLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQA2E/lSvOtUZjOj\ncOAcALpCVLLTSRdqF7745jSqIrHV8RuB+V6HFi55qoFzCKfJbc81SUqX7DhzoUtP\nNjdq5RfhEh/kWw3GeIN90Y5thVDm0i19A7GY+maJXMjw3LVWlKIo9a7rCOQvCi3O\nkA0QGO1Rc1d6/MneoWUR2tUHjJ83FvO089RaDUQhYpInBXV3GQByJGJeF8USJ/wS\nXy+SLDkaG9mC0TJwWNpldGoZQ57h/QeLtl2wfK3sLga5eVuQO0Lnzt6W3tYvvSAO\nckN/hrTMFMJ/vXHFUPXk8AYUBt0FqgYYHR5JxA9Wl2+Fr+Duw7Qee7/kcbwhbo1M\nLe9GgT/c\n-----END CERTIFICATE REQUEST-----\n","key":"-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAs4U3WnhpoxAqoidFqfOZ/TkIPiRgopXKCCA4eEPdmDAWAgbb\nRnR2VMdK1j9S9j7aqSkHUGn22ubKz1i8/O3kSVfazNnZ15lzRNa/Nl65kNBWxvHQ\nRrpEbFGcQSgyulpEWh7ZM4pJUpb5LMsL96g1SjGxlWjpw2xTgF4aoTE5YIMXON0J\nEsl5epp9h4vV1SJdnTby05lVYsiNou7cUoQ0d4MHfqCv30pyQV14OepoBW+7rpVs\nXlAa8i/ZGYr3LdyrusiLNh9rKL90FLz8BjfU44dwQaxVNliOoH+z1oihwI7N+9BX\nn75B2QOJiEjCiQHd9PlvjAhvwIuvQZSceeyWcwIDAQABAoIBAQCYD0cLwuL31EHI\niCtiAY12CFELEhUoomg26dPrStDwkAqUPOqPiyaQOR8SyyCipCrjDnW7j4YhdUxk\nxW2PcJHl7hzPV9hF3xzcOmpMy3+zQkW+ziT1Q+GhPp90MXCGmN881tRz67af1nHJ\nl1PTuw8ogV9Ch1M6zQ8NtKgp0WAgdn2YlkVrYv9/JaOZdh7ewNQPs+V68bC8tmmz\nEj0kuH06Lzr3zxfxOgAq8Xrv8b5GmFNjcRPOu5WWCRKt26FSwAcI/U5AXRuqVr8o\nthMiXKPA+RMSSy7bDF1EOFYdNyrWaLEzyrKLSxTXTvOT5kIfwVWKTTzdNug/BaYy\neesqkgtBAoGBAOafPTvJHYLHuyb11X2FYblvkLaw+orWvdy1E2sV62M3YiloOp5R\neWteEptvsEjo0ZXZyYqOK5WHsbkdTbPE7QPctKIYdVdztPb+3wWHM9hP1kGWuohW\n+S/kVIwf+ijH10Q3wQPgtsIGrj0Q/rkizD6qqmKz8gNizRwX2k3kkp/1AoGBAMdG\nabBuC9XHxFtVIEzHSXbVn38Z6tjxURcUK7hob8iRfl4JXbHtEKkoM2iIpY/a4YrA\nvjLBy0tNWnurTdT/Md7L3pqU4wVlMY0i5ysae7/vm2WV9ePdcHM1Oa4gFTSL3dW1\nLI3TLwxDD3vlqhP/Js3CMq7wtvTE1T1sWxjiLOPHAoGBAI9t49Bl8SOgAoZliARL\nyw5gE3l7siZdDbHRMCV+eWm4TSWBfEtwUnpzBFGFcfa2TXrL+ytf5j1WKjL9xZCT\nXfDz96eEXJ4qCRdARgYTIyxZ4t/h1Vrr9IhTkj2fuZ5ZQ0la/4Dg5ejf7Mdv5WvQ\n94PV8qf2UALJFNVvBEdDa+ltAoGAVjSYvhEtH4M254fQ3EYN+tF5GSPeG5FxUfmQ\n3EqZqPt/3jBRDwqN/Y99hcgvTycSENNGtHBvgJjq/rrhhbYMHeS13Mtx1kCrifHC\nbTwcsrB12iFgaP2/iqdI15HbeorTIYMpzgTAwp40EZYN2G61m6daA6Hwk7yevt6k\nHgSiBLsCgYEAoou8wIMi0+zyUgIo8MXYhexJFuYvEdHeyYvWN/FA4j/DZelixgW9\no4a0M9yOXStvjUUpG/TpaceJGqtwXk9bMBZML05fT7Im/3Qmh+44fF/a0q0Ard2N\nzdlIuaKlvcK5a6jD+mcN9vzOi4iuGUm1OhfTvHD/IS/rG4r6XhahHm4=\n-----END RSA PRIVATE KEY-----\n"} ================================================ FILE: helpers/testsuite/testing_helpers.go ================================================ // These functions are designed for use in testing other parts of the code. package testsuite import ( "bufio" "encoding/json" "errors" "fmt" "os" "os/exec" "strconv" "strings" "testing" "time" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" ) // CFSSLServerData is the data with which a server is initialized. These fields // can be left empty if desired. Any empty fields passed in to StartServer will // lead to the server being initialized with the default values defined by the // 'cfssl serve' command. type CFSSLServerData struct { CA []byte CABundle []byte CAKey []byte IntBundle []byte } // CFSSLServer is the type returned by StartCFSSLServer. It serves as a handle // to a running CFSSL server. type CFSSLServer struct { process *os.Process tempFiles []string } // StartCFSSLServer creates a local server listening on the given address and // port number. Both the address and port number are assumed to be valid. func StartCFSSLServer(address string, portNumber int, serverData CFSSLServerData) (*CFSSLServer, error) { // This value is explained below. startupTime := time.Second // We return this when an error occurs. nilServer := &CFSSLServer{nil, nil} args := []string{"serve", "-address", address, "-port", strconv.Itoa(portNumber)} var tempCAFile, tempCABundleFile, tempCAKeyFile, tempIntBundleFile string var err error var tempFiles []string if len(serverData.CA) > 0 { tempCAFile, err = createTempFile(serverData.CA) tempFiles = append(tempFiles, tempCAFile) args = append(args, "-ca") args = append(args, tempCAFile) } if len(serverData.CABundle) > 0 { tempCABundleFile, err = createTempFile(serverData.CABundle) tempFiles = append(tempFiles, tempCABundleFile) args = append(args, "-ca-bundle") args = append(args, tempCABundleFile) } if len(serverData.CAKey) > 0 { tempCAKeyFile, err = createTempFile(serverData.CAKey) tempFiles = append(tempFiles, tempCAKeyFile) args = append(args, "-ca-key") args = append(args, tempCAKeyFile) } if len(serverData.IntBundle) > 0 { tempIntBundleFile, err = createTempFile(serverData.IntBundle) tempFiles = append(tempFiles, tempIntBundleFile) args = append(args, "-int-bundle") args = append(args, tempIntBundleFile) } // If an error occurred in the creation of any file, return an error. if err != nil { for _, file := range tempFiles { os.Remove(file) } return nilServer, err } command := exec.Command("cfssl", args...) stdErrPipe, err := command.StderrPipe() if err != nil { for _, file := range tempFiles { os.Remove(file) } return nilServer, err } err = command.Start() if err != nil { for _, file := range tempFiles { os.Remove(file) } return nilServer, err } // We check to see if the address given is already in use. There is no way // to do this other than to just wait and see if an error message pops up. // Therefore we wait for startupTime, and if we don't see an error message // by then, we deem the server ready and return. errorOccurred := make(chan bool) go func() { scanner := bufio.NewScanner(stdErrPipe) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, "address already in use") { errorOccurred <- true } } }() select { case <-errorOccurred: for _, file := range tempFiles { os.Remove(file) } return nilServer, errors.New( "Error occurred on server: address " + address + ":" + strconv.Itoa(portNumber) + " already in use.") case <-time.After(startupTime): return &CFSSLServer{command.Process, tempFiles}, nil } } // Kill a running CFSSL server. func (server *CFSSLServer) Kill() error { for _, file := range server.tempFiles { os.Remove(file) } return server.process.Kill() } // CreateCertificateChain creates a chain of certificates from a slice of // requests. The first request is the root certificate and the last is the // leaf. The chain is returned as a slice of PEM-encoded bytes. func CreateCertificateChain(requests []csr.CertificateRequest) (certChain []byte, key []byte, err error) { // Create the root certificate using the first request. This will be // self-signed. certChain = make([]byte, 0) rootCert, prevKey, err := CreateSelfSignedCert(requests[0]) if err != nil { return nil, nil, err } certChain = append(certChain, rootCert...) // For each of the next requests, create a certificate signed by the // previous certificate. prevCert := rootCert for _, request := range requests[1:] { cert, key, err := SignCertificate(request, prevCert, prevKey) if err != nil { return nil, nil, err } certChain = append(certChain, byte('\n')) certChain = append(certChain, cert...) prevCert = cert prevKey = key } return certChain, key, nil } // CreateSelfSignedCert creates a self-signed certificate from a certificate // request. This function just calls the CLI "gencert" command. func CreateSelfSignedCert(request csr.CertificateRequest) (encodedCert, encodedKey []byte, err error) { // Marshall the request into JSON format and write it to a temporary file. jsonBytes, err := json.Marshal(request) if err != nil { return nil, nil, err } tempFile, err := createTempFile(jsonBytes) if err != nil { os.Remove(tempFile) return nil, nil, err } // Create the certificate with the CLI tools. command := exec.Command("cfssl", "gencert", "-initca", tempFile) CLIOutput, err := command.CombinedOutput() if err != nil { os.Remove(tempFile) return nil, nil, fmt.Errorf("%v - CLI output: %s", err, string(CLIOutput)) } err = checkCLIOutput(CLIOutput) if err != nil { os.Remove(tempFile) return nil, nil, err } encodedCert, err = cleanCLIOutput(CLIOutput, "cert") if err != nil { os.Remove(tempFile) return nil, nil, err } encodedKey, err = cleanCLIOutput(CLIOutput, "key") if err != nil { os.Remove(tempFile) return nil, nil, err } os.Remove(tempFile) return encodedCert, encodedKey, nil } // SignCertificate uses a certificate (input as signerCert) to create a signed // certificate for the input request. func SignCertificate(request csr.CertificateRequest, signerCert, signerKey []byte) (encodedCert, encodedKey []byte, err error) { // Marshall the request into JSON format and write it to a temporary file. jsonBytes, err := json.Marshal(request) if err != nil { return nil, nil, err } tempJSONFile, err := createTempFile(jsonBytes) if err != nil { os.Remove(tempJSONFile) return nil, nil, err } // Create a CSR file with the CLI tools. command := exec.Command("cfssl", "genkey", tempJSONFile) CLIOutput, err := command.CombinedOutput() if err != nil { os.Remove(tempJSONFile) return nil, nil, fmt.Errorf("%v - CLI output: %s", err, string(CLIOutput)) } err = checkCLIOutput(CLIOutput) if err != nil { os.Remove(tempJSONFile) return nil, nil, err } encodedCSR, err := cleanCLIOutput(CLIOutput, "csr") if err != nil { os.Remove(tempJSONFile) return nil, nil, err } encodedCSRKey, err := cleanCLIOutput(CLIOutput, "key") if err != nil { os.Remove(tempJSONFile) return nil, nil, err } // Now we write this encoded CSR and its key to file. tempCSRFile, err := createTempFile(encodedCSR) if err != nil { os.Remove(tempJSONFile) os.Remove(tempCSRFile) return nil, nil, err } // We also need to write the signer's certficate and key to temporary files. tempSignerCertFile, err := createTempFile(signerCert) if err != nil { os.Remove(tempJSONFile) os.Remove(tempCSRFile) os.Remove(tempSignerCertFile) return nil, nil, err } tempSignerKeyFile, err := createTempFile(signerKey) if err != nil { os.Remove(tempJSONFile) os.Remove(tempCSRFile) os.Remove(tempSignerCertFile) os.Remove(tempSignerKeyFile) return nil, nil, err } // Now we use the signer's certificate and key file along with the CSR file // to sign a certificate for the input request. We use the CLI tools to do // this. command = exec.Command( "cfssl", "sign", "-ca", tempSignerCertFile, "-ca-key", tempSignerKeyFile, "-hostname", request.CN, tempCSRFile, ) CLIOutput, err = command.CombinedOutput() if err != nil { return nil, nil, fmt.Errorf("%v - CLI output: %s", err, string(CLIOutput)) } err = checkCLIOutput(CLIOutput) if err != nil { return nil, nil, fmt.Errorf("%v - CLI output: %s", err, string(CLIOutput)) } encodedCert, err = cleanCLIOutput(CLIOutput, "cert") if err != nil { return nil, nil, err } // Clean up. os.Remove(tempJSONFile) os.Remove(tempCSRFile) os.Remove(tempSignerCertFile) os.Remove(tempSignerKeyFile) return encodedCert, encodedCSRKey, nil } // Creates a temporary file with the given data. Returns the file name. func createTempFile(data []byte) (fileName string, err error) { // Avoid overwriting a file in the currect directory by choosing an unused // file name. baseName := "temp" tempFileName := baseName tryIndex := 0 for { if _, err := os.Stat(tempFileName); err == nil { tempFileName = baseName + strconv.Itoa(tryIndex) tryIndex++ } else { break } } readWritePermissions := os.FileMode(0664) err = os.WriteFile(tempFileName, data, readWritePermissions) if err != nil { return "", err } return tempFileName, nil } // Checks the CLI Output for failure. func checkCLIOutput(CLIOutput []byte) error { outputString := string(CLIOutput) // Proper output will contain the substring "---BEGIN" somewhere failureOccurred := !strings.Contains(outputString, "---BEGIN") if failureOccurred { return errors.New("Failure occurred during CLI execution: " + outputString) } return nil } // Returns the cleaned up PEM encoding for the item specified (for example, // 'cert' or 'key'). func cleanCLIOutput(CLIOutput []byte, item string) (cleanedOutput []byte, err error) { outputString := string(CLIOutput) // The keyword will be surrounded by quotes. itemString := "\"" + item + "\"" // We should only search for the keyword beyond this point. eligibleSearchIndex := strings.Index(outputString, "{") outputString = outputString[eligibleSearchIndex:] // Make sure the item is present in the output. if !strings.Contains(outputString, itemString) { return nil, errors.New("Item " + item + " not found in CLI Output") } // We add 2 for the [:"] that follows the item startIndex := strings.Index(outputString, itemString) + len(itemString) + 2 outputString = outputString[startIndex:] endIndex := strings.Index(outputString, "\\n\"") outputString = outputString[:endIndex] outputString = strings.Replace(outputString, "\\n", "\n", -1) return []byte(outputString), nil } // NewConfig returns a config object from the data passed. func NewConfig(t *testing.T, configBytes []byte) *config.Config { conf, err := config.LoadConfig([]byte(configBytes)) if err != nil { t.Fatal("config loading error:", err) } if !conf.Valid() { t.Fatal("config is not valid") } return conf } // CSRTest holds information about CSR test files. type CSRTest struct { File string KeyAlgo string KeyLen int // Error checking function ErrorCallback func(*testing.T, error) } // CSRTests define a set of CSR files for testing. var CSRTests = []CSRTest{ { File: "../../signer/local/testdata/rsa2048.csr", KeyAlgo: "rsa", KeyLen: 2048, ErrorCallback: nil, }, { File: "../../signer/local/testdata/rsa3072.csr", KeyAlgo: "rsa", KeyLen: 3072, ErrorCallback: nil, }, { File: "../../signer/local/testdata/rsa4096.csr", KeyAlgo: "rsa", KeyLen: 4096, ErrorCallback: nil, }, { File: "../../signer/local/testdata/ecdsa256.csr", KeyAlgo: "ecdsa", KeyLen: 256, ErrorCallback: nil, }, { File: "../../signer/local/testdata/ecdsa384.csr", KeyAlgo: "ecdsa", KeyLen: 384, ErrorCallback: nil, }, { File: "../../signer/local/testdata/ecdsa521.csr", KeyAlgo: "ecdsa", KeyLen: 521, ErrorCallback: nil, }, } ================================================ FILE: helpers/testsuite/testing_helpers_test.go ================================================ package testsuite import ( "crypto/x509" "encoding/json" "math" "math/rand" "os" "os/exec" "reflect" "strconv" "strings" "testing" "time" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/helpers" ) const ( testDataDirectory = "testdata" initCADirectory = testDataDirectory + string(os.PathSeparator) + "initCA" preMadeOutput = initCADirectory + string(os.PathSeparator) + "cfssl_output.pem" csrFile = testDataDirectory + string(os.PathSeparator) + "cert_csr.json" ) var ( keyRequest = csr.KeyRequest{ A: "rsa", S: 2048, } CAConfig = csr.CAConfig{ PathLength: 1, Expiry: "1h", // issue a CA certificate only valid for 1 hour } baseRequest = csr.CertificateRequest{ CN: "example.com", Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "Internet Widgets, LLC", OU: "Certificate Authority", }, }, Hosts: []string{"ca.example.com"}, KeyRequest: &keyRequest, } CARequest = csr.CertificateRequest{ CN: "example.com", Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "Internet Widgets, LLC", OU: "Certificate Authority", }, }, Hosts: []string{"ca.example.com"}, KeyRequest: &keyRequest, CA: &CAConfig, } ) func TestStartCFSSLServer(t *testing.T) { // We will test on this address and port. Be sure that these are free or // the test will fail. addressToTest := "127.0.0.1" portToTest := 9775 CACert, CAKey, err := CreateSelfSignedCert(CARequest) if err != nil { t.Fatal(err.Error()) } // Set up a test server using our CA certificate and key. serverData := CFSSLServerData{CA: CACert, CAKey: CAKey} server, err := StartCFSSLServer(addressToTest, portToTest, serverData) if err != nil { t.Fatal(err.Error()) } // Try to start up a second server at the same address and port number. We // should get an 'address in use' error. _, err = StartCFSSLServer(addressToTest, portToTest, serverData) if err == nil || !strings.Contains(err.Error(), "Error occurred on server: address") { t.Fatal("Two servers allowed on same address and port.") } // Now make a request of our server and check that no error occurred. // First we need a request to send to our server. We marshall the request // into JSON format and write it to a temporary file. jsonBytes, err := json.Marshal(baseRequest) if err != nil { t.Fatal(err.Error()) } tempFile, err := createTempFile(jsonBytes) if err != nil { os.Remove(tempFile) panic(err) } // Now we make the request and check the output. remoteServerString := "-remote=" + "http://" + addressToTest + ":" + strconv.Itoa(portToTest) command := exec.Command( "cfssl", "gencert", remoteServerString, "-hostname="+baseRequest.CN, tempFile) CLIOutput, err := command.CombinedOutput() os.Remove(tempFile) if err != nil { t.Fatalf("%v: %s", err.Error(), string(CLIOutput)) } err = checkCLIOutput(CLIOutput) if err != nil { t.Fatal(err.Error()) } // The output should contain the certificate, request, and private key. _, err = cleanCLIOutput(CLIOutput, "cert") if err != nil { t.Fatal(err.Error()) } _, err = cleanCLIOutput(CLIOutput, "csr") if err != nil { t.Fatal(err.Error()) } _, err = cleanCLIOutput(CLIOutput, "key") if err != nil { t.Fatal(err.Error()) } // Finally, kill the server. err = server.Kill() if err != nil { t.Fatal(err.Error()) } } func TestCreateCertificateChain(t *testing.T) { // N is the number of certificates that will be chained together. N := 10 // --- TEST: Create a chain of one certificate. --- // encodedChainFromCode, _, err := CreateCertificateChain([]csr.CertificateRequest{CARequest}) if err != nil { t.Fatal(err.Error()) } // Now compare to a pre-made certificate chain using a JSON file containing // the same request data. CLIOutputFile := preMadeOutput CLIOutput, err := os.ReadFile(CLIOutputFile) if err != nil { t.Fatal(err.Error()) } encodedChainFromCLI, err := cleanCLIOutput(CLIOutput, "cert") if err != nil { t.Fatal(err.Error()) } chainFromCode, err := helpers.ParseCertificatesPEM(encodedChainFromCode) if err != nil { t.Fatal(err.Error()) } chainFromCLI, err := helpers.ParseCertificatesPEM(encodedChainFromCLI) if err != nil { t.Fatal(err.Error()) } if !chainsEqual(chainFromCode, chainFromCLI) { unequalFieldSlices := checkFieldsOfChains(chainFromCode, chainFromCLI) for i, unequalFields := range unequalFieldSlices { if len(unequalFields) > 0 { t.Log("The certificate chains held unequal fields for chain " + strconv.Itoa(i)) t.Log("The following fields were unequal:") for _, field := range unequalFields { t.Log("\t" + field) } } } t.Fatal("Certificate chains unequal.") } // --- TEST: Create a chain of N certificates. --- // // First we make a slice of N requests. We make each slightly different. cnGrabBag := []string{"example", "invalid", "test"} topLevelDomains := []string{".com", ".net", ".org"} subDomains := []string{"www.", "secure.", "ca.", ""} countryGrabBag := []string{"USA", "China", "England", "Vanuatu"} stateGrabBag := []string{"California", "Texas", "Alaska", "London"} localityGrabBag := []string{"San Francisco", "Houston", "London", "Oslo"} orgGrabBag := []string{"Internet Widgets, LLC", "CloudFlare, Inc."} orgUnitGrabBag := []string{"Certificate Authority", "Systems Engineering"} requests := make([]csr.CertificateRequest, N) requests[0] = CARequest for i := 1; i < N; i++ { requests[i] = baseRequest cn := randomElement(cnGrabBag) tld := randomElement(topLevelDomains) subDomain1 := randomElement(subDomains) subDomain2 := randomElement(subDomains) country := randomElement(countryGrabBag) state := randomElement(stateGrabBag) locality := randomElement(localityGrabBag) org := randomElement(orgGrabBag) orgUnit := randomElement(orgUnitGrabBag) requests[i].CN = cn + tld requests[i].Names = []csr.Name{ {C: country, ST: state, L: locality, O: org, OU: orgUnit, }, } hosts := []string{subDomain1 + requests[i].CN} if subDomain2 != subDomain1 { hosts = append(hosts, subDomain2+requests[i].CN) } requests[i].Hosts = hosts } // Now we make a certificate chain out of these requests. encodedCertChain, _, err := CreateCertificateChain(requests) if err != nil { t.Fatal(err.Error()) } // To test this chain, we compare the data encoded in each certificate to // each request we used to generate the chain. chain, err := helpers.ParseCertificatesPEM(encodedCertChain) if err != nil { t.Fatal(err.Error()) } if len(chain) != len(requests) { t.Log("Length of chain: " + strconv.Itoa(len(chain))) t.Log("Length of requests: " + strconv.Itoa(len(requests))) t.Fatal("Length of chain not equal to length of requests.") } mismatchOccurred := false for i := 0; i < len(chain); i++ { certEqualsRequest, unequalFields := certEqualsRequest(chain[i], requests[i]) if !certEqualsRequest { mismatchOccurred = true t.Log( "Certificate " + strconv.Itoa(i) + " and request " + strconv.Itoa(i) + " unequal.", ) t.Log("Unequal fields for index " + strconv.Itoa(i) + ":") for _, field := range unequalFields { t.Log("\t" + field) } } } // TODO: check that each certificate is actually signed by the previous one if mismatchOccurred { t.Fatal("Unequal certificate(s) and request(s) found.") } // --- TEST: Create a chain of certificates with invalid path lengths. --- // // Other invalid chains? } func TestCreateSelfSignedCert(t *testing.T) { // --- TEST: Create a self-signed certificate from a CSR. --- // // Generate a self-signed certificate from the request. encodedCertFromCode, _, err := CreateSelfSignedCert(CARequest) if err != nil { t.Fatal(err.Error()) } // Now compare to a pre-made certificate made using a JSON file with the // same request information. This JSON file is located in testdata/initCA // and is called ca_csr.json. CLIOutputFile := preMadeOutput CLIOutput, err := os.ReadFile(CLIOutputFile) if err != nil { t.Fatal(err.Error()) } encodedCertFromCLI, err := cleanCLIOutput(CLIOutput, "cert") if err != nil { t.Fatal(err.Error()) } certFromCode, err := helpers.ParseSelfSignedCertificatePEM(encodedCertFromCode) if err != nil { t.Fatal(err.Error()) } certFromCLI, err := helpers.ParseSelfSignedCertificatePEM(encodedCertFromCLI) if err != nil { t.Fatal(err.Error()) } // Nullify any fields of the certificates which are dependent upon the time // of the certificate's creation. nullifyTimeDependency(certFromCode) nullifyTimeDependency(certFromCLI) if !reflect.DeepEqual(certFromCode, certFromCLI) { unequalFields := checkFields( *certFromCode, *certFromCLI, reflect.TypeOf(*certFromCode)) t.Log("The following fields were unequal:") for _, field := range unequalFields { t.Log(field) } t.Fatal("Certificates unequal.") } } // Compare two x509 certificate chains. We only compare relevant data to // determine equality. func chainsEqual(chain1, chain2 []*x509.Certificate) bool { if len(chain1) != len(chain2) { return false } for i := 0; i < len(chain1); i++ { cert1 := nullifyTimeDependency(chain1[i]) cert2 := nullifyTimeDependency(chain2[i]) if !reflect.DeepEqual(cert1, cert2) { return false } } return true } // When comparing certificates created at different times for equality, we do // not want to worry about fields which are dependent on the time of creation. // Thus we nullify these fields before comparing the certificates. func nullifyTimeDependency(cert *x509.Certificate) *x509.Certificate { cert.Raw = nil cert.RawTBSCertificate = nil cert.RawSubject = nil cert.RawIssuer = nil cert.RawSubjectPublicKeyInfo = nil cert.Signature = nil cert.PublicKey = nil cert.SerialNumber = nil cert.NotBefore = time.Time{} cert.NotAfter = time.Time{} cert.Extensions = nil cert.SubjectKeyId = nil cert.AuthorityKeyId = nil cert.Subject.Names = nil cert.Subject.ExtraNames = nil cert.Issuer.Names = nil cert.Issuer.ExtraNames = nil return cert } // Compares two structs and returns a list containing the names of all fields // for which the two structs hold different values. func checkFields(struct1, struct2 interface{}, typeOfStructs reflect.Type) []string { v1 := reflect.ValueOf(struct1) v2 := reflect.ValueOf(struct2) var unequalFields []string for i := 0; i < v1.NumField(); i++ { if !reflect.DeepEqual(v1.Field(i).Interface(), v2.Field(i).Interface()) { unequalFields = append(unequalFields, typeOfStructs.Field(i).Name) } } return unequalFields } // Runs checkFields on the corresponding elements of chain1 and chain2. Element // i of the returned slice contains a slice of the fields for which certificate // i in chain1 had different values than certificate i of chain2. func checkFieldsOfChains(chain1, chain2 []*x509.Certificate) [][]string { minLen := math.Min(float64(len(chain1)), float64(len(chain2))) typeOfCert := reflect.TypeOf(*chain1[0]) var unequalFields [][]string for i := 0; i < int(minLen); i++ { unequalFields = append(unequalFields, checkFields( *chain1[i], *chain2[i], typeOfCert)) } return unequalFields } // Compares a certificate to a request. Returns (true, []) if both items // contain matching data (for the things that can match). Otherwise, returns // (false, unequalFields) where unequalFields contains the names of all fields // which did not match. func certEqualsRequest(cert *x509.Certificate, request csr.CertificateRequest) (bool, []string) { equal := true var unequalFields []string if cert.Subject.CommonName != request.CN { equal = false unequalFields = append(unequalFields, "Common Name") } nameData := make(map[string]map[string]bool) nameData["Country"] = make(map[string]bool) nameData["Organization"] = make(map[string]bool) nameData["OrganizationalUnit"] = make(map[string]bool) nameData["Locality"] = make(map[string]bool) nameData["Province"] = make(map[string]bool) for _, name := range request.Names { nameData["Country"][name.C] = true nameData["Organization"][name.O] = true nameData["OrganizationalUnit"][name.OU] = true nameData["Locality"][name.L] = true nameData["Province"][name.ST] = true } for _, country := range cert.Subject.Country { if _, exists := nameData["Country"][country]; !exists { equal = false unequalFields = append(unequalFields, "Country") } } for _, organization := range cert.Subject.Organization { if _, exists := nameData["Organization"][organization]; !exists { equal = false unequalFields = append(unequalFields, "Organization") } } for _, organizationalUnit := range cert.Subject.OrganizationalUnit { if _, exists := nameData["OrganizationalUnit"][organizationalUnit]; !exists { equal = false unequalFields = append(unequalFields, "OrganizationalUnit") } } for _, locality := range cert.Subject.Locality { if _, exists := nameData["Locality"][locality]; !exists { equal = false unequalFields = append(unequalFields, "Locality") } } for _, province := range cert.Subject.Province { if _, exists := nameData["Province"][province]; !exists { equal = false unequalFields = append(unequalFields, "Province") } } // TODO: check hosts if cert.BasicConstraintsValid && request.CA != nil { if cert.MaxPathLen != request.CA.PathLength { equal = false unequalFields = append(unequalFields, "Max Path Length") } // TODO: check expiry } // TODO: check isCA return equal, unequalFields } // Returns a random element of the input slice. func randomElement(set []string) string { return set[rand.Intn(len(set))] } ================================================ FILE: info/info.go ================================================ // Package info contains the definitions for the info endpoint package info // Req is the request struct for an info API request. type Req struct { Label string `json:"label"` Profile string `json:"profile"` } // Resp is the response for an Info API request. type Resp struct { Certificate string `json:"certificate"` Usage []string `json:"usages"` ExpiryString string `json:"expiry"` } ================================================ FILE: initca/initca.go ================================================ // Package initca contains code to initialise a certificate authority, // generating a new root key and certificate. package initca import ( "bytes" "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "errors" "time" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/local" ) // validator contains the default validation logic for certificate // authority certificates. The only requirement here is that the // certificate have a non-empty subject field. func validator(req *csr.CertificateRequest) error { if req.CN != "" { return nil } if len(req.Names) == 0 { return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information")) } for i := range req.Names { if csr.IsNameEmpty(req.Names[i]) { return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information")) } } return nil } // New creates a new root certificate from the certificate request. func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) { policy := CAPolicy() if req.CA != nil { if req.CA.Expiry != "" { policy.Default.ExpiryString = req.CA.Expiry policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry) if err != nil { return } } if req.CA.Backdate != "" { policy.Default.Backdate, err = time.ParseDuration(req.CA.Backdate) if err != nil { return } } policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength if req.CA.PathLength != 0 && req.CA.PathLenZero { log.Infof("ignore invalid 'pathlenzero' value") } else { policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero } } if req.CRL != "" { policy.Default.CRL = req.CRL } g := &csr.Generator{Validator: validator} csrPEM, key, err = g.ProcessRequest(req) if err != nil { log.Errorf("failed to process request: %v", err) key = nil return } priv, err := helpers.ParsePrivateKeyPEM(key) if err != nil { log.Errorf("failed to parse private key: %v", err) return } s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy) if err != nil { log.Errorf("failed to create signer: %v", err) return } signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)} cert, err = s.Sign(signReq) return } // NewFromPEM creates a new root certificate from the key file passed in. func NewFromPEM(req *csr.CertificateRequest, keyFile string) (cert, csrPEM []byte, err error) { privData, err := helpers.ReadBytes(keyFile) if err != nil { return nil, nil, err } priv, err := helpers.ParsePrivateKeyPEM(privData) if err != nil { return nil, nil, err } return NewFromSigner(req, priv) } // RenewFromPEM re-creates a root certificate from the CA cert and key // files. The resulting root certificate will have the input CA certificate // as the template and have the same expiry length. E.g. the existing CA // is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate // will be valid from now and expire in one year as well. func RenewFromPEM(caFile, keyFile string) ([]byte, error) { caBytes, err := helpers.ReadBytes(caFile) if err != nil { return nil, err } ca, err := helpers.ParseCertificatePEM(caBytes) if err != nil { return nil, err } keyBytes, err := helpers.ReadBytes(keyFile) if err != nil { return nil, err } key, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { return nil, err } return RenewFromSigner(ca, key) } // NewFromSigner creates a new root certificate from a crypto.Signer. func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) { policy := CAPolicy() if req.CA != nil { if req.CA.Expiry != "" { policy.Default.ExpiryString = req.CA.Expiry policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry) if err != nil { return nil, nil, err } } policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength if req.CA.PathLength != 0 && req.CA.PathLenZero { log.Infof("ignore invalid 'pathlenzero' value") } else { policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero } } csrPEM, err = csr.Generate(priv, req) if err != nil { return nil, nil, err } s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy) if err != nil { log.Errorf("failed to create signer: %v", err) return } signReq := signer.SignRequest{Request: string(csrPEM)} cert, err = s.Sign(signReq) return } // RenewFromSigner re-creates a root certificate from the CA cert and crypto.Signer. // The resulting root certificate will have ca certificate // as the template and have the same expiry length. E.g. the existing CA // is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate // will be valid from now and expire in one year as well. func RenewFromSigner(ca *x509.Certificate, priv crypto.Signer) ([]byte, error) { if !ca.IsCA { return nil, errors.New("input certificate is not a CA cert") } // matching certificate public key vs private key switch { case ca.PublicKeyAlgorithm == x509.RSA: var rsaPublicKey *rsa.PublicKey var ok bool if rsaPublicKey, ok = priv.Public().(*rsa.PublicKey); !ok { return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } if ca.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 { return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } case ca.PublicKeyAlgorithm == x509.ECDSA: var ecdsaPublicKey *ecdsa.PublicKey var ok bool if ecdsaPublicKey, ok = priv.Public().(*ecdsa.PublicKey); !ok { return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } if ca.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 { return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } case ca.PublicKeyAlgorithm == x509.Ed25519: var ed25519PublicKey ed25519.PublicKey var ok bool if ed25519PublicKey, ok = priv.Public().(ed25519.PublicKey); !ok { return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } if !(bytes.Equal(ca.PublicKey.(ed25519.PublicKey), ed25519PublicKey)) { return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } default: return nil, cferr.New(cferr.PrivateKeyError, cferr.NotRSAOrECCOrEd25519) } req := csr.ExtractCertificateRequest(ca) cert, _, err := NewFromSigner(req, priv) return cert, err } // CAPolicy contains the CA issuing policy as default policy. var CAPolicy = func() *config.Signing { return &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "43800h", Expiry: 5 * helpers.OneYear, CAConstraint: config.CAConstraint{IsCA: true}, }, } } // Update copies the CA certificate, updates the NotBefore and // NotAfter fields, and then re-signs the certificate. func Update(ca *x509.Certificate, priv crypto.Signer) (cert []byte, err error) { copy, err := x509.ParseCertificate(ca.Raw) if err != nil { return } validity := ca.NotAfter.Sub(ca.NotBefore) copy.NotBefore = time.Now().Round(time.Minute).Add(-5 * time.Minute) copy.NotAfter = copy.NotBefore.Add(validity) cert, err = x509.CreateCertificate(rand.Reader, copy, copy, priv.Public(), priv) if err != nil { return } cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert}) return } ================================================ FILE: initca/initca_test.go ================================================ package initca import ( "bytes" "crypto/ecdsa" "crypto/rsa" "os" "strings" "testing" "time" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/local" ) var validKeyParams = []csr.KeyRequest{ {A: "rsa", S: 2048}, {A: "rsa", S: 3072}, {A: "rsa", S: 4096}, {A: "ecdsa", S: 256}, {A: "ecdsa", S: 384}, {A: "ecdsa", S: 521}, {A: "ed25519"}, } var validCAConfigs = []csr.CAConfig{ {PathLength: 0, PathLenZero: true}, {PathLength: 0, PathLenZero: false}, {PathLength: 2}, {PathLength: 2, Expiry: "1h"}, // invalid PathLenZero value will be ignored {PathLength: 2, PathLenZero: true}, } var invalidCAConfig = csr.CAConfig{ PathLength: 2, // Expiry must be a duration string Expiry: "2116/12/31", } var csrFiles = []string{ "testdata/rsa2048.csr", "testdata/rsa3072.csr", "testdata/rsa4096.csr", "testdata/ecdsa256.csr", "testdata/ecdsa384.csr", "testdata/ecdsa521.csr", "testdata/ed25519.csr", } var testRSACAFile = "testdata/5min-rsa.pem" var testRSACAKeyFile = "testdata/5min-rsa-key.pem" var testECDSACAFile = "testdata/5min-ecdsa.pem" var testECDSACAKeyFile = "testdata/5min-ecdsa-key.pem" var testED25519CAFile = "testdata/5min-ed25519.pem" var testED25519CAKeyFile = "testdata/5min-ed25519-key.pem" var invalidCryptoParams = []csr.KeyRequest{ // Weak Key {A: "rsa", S: 1024}, // Bad param {A: "rsaCrypto", S: 2048}, {A: "ecdsa", S: 2000}, } func TestInitCA(t *testing.T) { var req *csr.CertificateRequest hostname := "cloudflare.com" crl := "http://crl.cloudflare.com/655c6a9b-01c6-4eea-bf21-be690cc315e0.crl" // cert_uuid.crl for _, param := range validKeyParams { for _, caconfig := range validCAConfigs { req = &csr.CertificateRequest{ Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: hostname, Hosts: []string{hostname, "www." + hostname}, KeyRequest: ¶m, CA: &caconfig, CRL: crl, } certBytes, _, keyBytes, err := New(req) if err != nil { t.Fatal("InitCA failed:", err) } key, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { t.Fatal("InitCA private key parsing failed:", err) } cert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal("InitCA cert parsing failed:", err) } // Verify if the CRL is set crlSet := false for _, certCrl := range cert.CRLDistributionPoints { if certCrl == crl { crlSet = true break } } if !crlSet { t.Fatal("Missing CRL on certificate") } // Verify key parameters. switch req.KeyRequest.Algo() { case "rsa": if cert.PublicKey.(*rsa.PublicKey).N.BitLen() != param.Size() { t.Fatal("Cert key length mismatch.") } if key.(*rsa.PrivateKey).N.BitLen() != param.Size() { t.Fatal("Private key length mismatch.") } case "ecdsa": if cert.PublicKey.(*ecdsa.PublicKey).Curve.Params().BitSize != param.Size() { t.Fatal("Cert key length mismatch.") } if key.(*ecdsa.PrivateKey).Curve.Params().BitSize != param.Size() { t.Fatal("Private key length mismatch.") } } // Verify CA MaxPathLen if caconfig.PathLength == 0 && cert.MaxPathLenZero != caconfig.PathLenZero { t.Fatalf("fail to init a CA cert with specified CA pathlen zero: expect %v, got %v", caconfig.PathLenZero, cert.MaxPathLenZero) } if caconfig.PathLength != 0 { if cert.MaxPathLen != caconfig.PathLength { t.Fatalf("fail to init a CA cert with specified CA pathlen: expect %d, got %d", caconfig.PathLength, cert.MaxPathLen) } if cert.MaxPathLenZero != false { t.Fatalf("fail to init a CA cert with specified CA pathlen zero: expect false, got %t", cert.MaxPathLenZero) } } // Replace the default CAPolicy with a test (short expiry) version and add a crl CAPolicy = func() *config.Signing { return &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "300s", Expiry: 300 * time.Second, CAConstraint: config.CAConstraint{IsCA: true}, CRL: crl, }, } } // Start a signer s, err := local.NewSigner(key, cert, signer.DefaultSigAlgo(key), nil) if err != nil { t.Fatal("Signer Creation error:", err) } s.SetPolicy(CAPolicy()) // Sign RSA, ECDSA and ed25519 customer CSRs. for _, csrFile := range csrFiles { csrBytes, err := os.ReadFile(csrFile) if err != nil { t.Fatal("CSR loading error:", err) } req := signer.SignRequest{ Request: string(csrBytes), Hosts: signer.SplitHosts(hostname), Profile: "", Label: "", } bytes, err := s.Sign(req) if err != nil { t.Fatal(err) } customerCert, _ := helpers.ParseCertificatePEM(bytes) if customerCert.SignatureAlgorithm != s.SigAlgo() { t.Fatal("Signature Algorithm mismatch") } err = customerCert.CheckSignatureFrom(cert) if err != nil { t.Fatal("Signing CSR failed.", err) } } } } } func TestInvalidCAConfig(t *testing.T) { hostname := "example.com" req := &csr.CertificateRequest{ Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: hostname, Hosts: []string{hostname, "www." + hostname}, KeyRequest: &validKeyParams[0], CA: &invalidCAConfig, } _, _, _, err := New(req) if err == nil { t.Fatalf("InitCA with bad CAConfig should fail: %v", invalidCAConfig) } } func TestInvalidCryptoParams(t *testing.T) { var req *csr.CertificateRequest hostname := "cloudflare.com" for _, invalidParam := range invalidCryptoParams { req = &csr.CertificateRequest{ Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: hostname, Hosts: []string{hostname, "www." + hostname}, KeyRequest: &invalidParam, } _, _, _, err := New(req) if err == nil { t.Fatalf("InitCA with bad CAConfig should fail: %v", invalidCAConfig) } if !strings.Contains(err.Error(), `"code":2400`) { t.Fatal(err) } } } type validation struct { r *csr.CertificateRequest v bool } var testValidations = []validation{ {&csr.CertificateRequest{}, false}, {&csr.CertificateRequest{ CN: "test CA", }, true}, {&csr.CertificateRequest{ Names: []csr.Name{{}}, }, false}, {&csr.CertificateRequest{ Names: []csr.Name{ {O: "Example CA"}, }, }, true}, } func TestValidations(t *testing.T) { for i, tv := range testValidations { err := validator(tv.r) if tv.v && err != nil { t.Fatalf("%v", err) } if !tv.v && err == nil { t.Fatalf("%d: expected error, but no error was reported", i) } } } func TestRenewRSA(t *testing.T) { certPEM, err := RenewFromPEM(testRSACAFile, testRSACAKeyFile) if err != nil { t.Fatal(err) } // must parse ok cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } if !cert.IsCA { t.Fatal("renewed CA certificate is not CA") } // cert expiry must be 5 minutes expiry := cert.NotAfter.Sub(cert.NotBefore).Seconds() if expiry >= 301 || expiry <= 299 { t.Fatal("expiry is not correct:", expiry) } // check subject if cert.Subject.CommonName != "" { t.Fatal("Bad CommonName") } if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "US" { t.Fatal("Bad Subject") } if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "CloudFlare, Inc." { t.Fatal("Bad Subject") } } func TestRenewED25519(t *testing.T) { certPEM, err := RenewFromPEM(testED25519CAFile, testED25519CAKeyFile) if err != nil { t.Fatal(err) } // must parse ok cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } if !cert.IsCA { t.Fatal("renewed CA certificate is not CA") } // cert expiry must be 5 minutes expiry := cert.NotAfter.Sub(cert.NotBefore).Seconds() if expiry >= 301 || expiry <= 299 { t.Fatal("expiry is not correct:", expiry) } // check subject if cert.Subject.CommonName != "" { t.Fatal("Bad CommonName") } if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "US" { t.Fatal("Bad Subject") } if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "CloudFlare, Inc." { t.Fatal("Bad Subject") } } func TestRenewECDSA(t *testing.T) { certPEM, err := RenewFromPEM(testECDSACAFile, testECDSACAKeyFile) if err != nil { t.Fatal(err) } // must parse ok cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } if !cert.IsCA { t.Fatal("renewed CA certificate is not CA") } // cert expiry must be 5 minutes expiry := cert.NotAfter.Sub(cert.NotBefore).Seconds() if expiry >= 301 || expiry <= 299 { t.Fatal("expiry is not correct:", expiry) } // check subject if cert.Subject.CommonName != "" { t.Fatal("Bad CommonName") } if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "US" { t.Fatal("Bad Subject") } if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "CloudFlare, Inc." { t.Fatal("Bad Subject") } } func TestRenewMismatch(t *testing.T) { _, err := RenewFromPEM(testECDSACAFile, testRSACAKeyFile) if err == nil { t.Fatal("Fail to detect cert/key mismatch") } } func TestRenew(t *testing.T) { in, err := os.ReadFile(testECDSACAFile) if err != nil { t.Fatal(err) } cert, err := helpers.ParseCertificatePEM(in) if err != nil { t.Fatal(err) } in, err = os.ReadFile(testECDSACAKeyFile) if err != nil { t.Fatal(err) } priv, err := helpers.ParsePrivateKeyPEM(in) if err != nil { t.Fatal(err) } renewed, err := Update(cert, priv) if err != nil { t.Fatal(err) } newCert, err := helpers.ParseCertificatePEM(renewed) if err != nil { t.Fatal(err) } if !bytes.Equal(newCert.RawSubjectPublicKeyInfo, cert.RawSubjectPublicKeyInfo) { t.Fatal("Update returned a certificate with different subject public key info") } if !bytes.Equal(newCert.RawSubject, cert.RawSubject) { t.Fatal("Update returned a certificate with different subject info") } if !bytes.Equal(newCert.RawIssuer, cert.RawIssuer) { t.Fatal("Update returned a certificate with different issuer info") } } ================================================ FILE: initca/testdata/5min-ecdsa-key.pem ================================================ -----BEGIN EC PRIVATE KEY----- MHcCAQEEIA8OzPeVZT0cXTAPdcXYefLRIqyUXa0f0SgYMJ2J1AVcoAoGCCqGSM49 AwEHoUQDQgAEoCV+bVOLTJMy38j50sc3vE5k41GMRgriFJt0g0OVX8yaOZ93CZTI 7LzfGbMU+KqWTgOwGhrPvpusep3fjw+dAQ== -----END EC PRIVATE KEY----- ================================================ FILE: initca/testdata/5min-ecdsa.pem ================================================ -----BEGIN CERTIFICATE----- MIICUDCCAfagAwIBAgIIec5PjdpJcNYwCgYIKoZIzj0EAwIwejELMAkGA1UEBhMC VVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNVBAsTGlRlc3QgQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYD VQQIEwpDYWxpZm9ybmlhMB4XDTE1MTAwODIzMDEwMFoXDTE1MTAwODIzMDYwMFow ejELMAkGA1UEBhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNV BAsTGlRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEoCV+bVOLTJMy38j50sc3vE5k41GMRgriFJt0g0OVX8yaOZ93CZTI7Lzf GbMU+KqWTgOwGhrPvpusep3fjw+dAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud EwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFDpLhSKBN3njfb6cXQCdRLzCZt0ZMB8G A1UdIwQYMBaAFDpLhSKBN3njfb6cXQCdRLzCZt0ZMAoGCCqGSM49BAMCA0gAMEUC IFU3BmzntGGeXZu2qWZx249nYn37S0AkCnQ3rUtI31bdAiEAsPICnZ+GB8yCN26N OL+N8dHvXiOvZ9/Vl488pyWOccY= -----END CERTIFICATE----- ================================================ FILE: initca/testdata/5min-ed25519-key.pem ================================================ -----BEGIN Ed25519 PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIO23h+PSszCu1BdPNn2HnmPexKh9p3HA3QxTOZ3cXQqx -----END Ed25519 PRIVATE KEY----- ================================================ FILE: initca/testdata/5min-ed25519.pem ================================================ -----BEGIN CERTIFICATE----- MIIB+DCCAaqgAwIBAgIUa7gAfTYxGHeXpbZBr25VR3IlEkAwBQYDK2VwMHoxCzAJ BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMSMwIQYDVQQLExpUZXN0 IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0yMDA1MTYwNjE3MDBaFw0yMDA1MTYw NjIyMDBaMHoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYD VQQHEw1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMSMw IQYDVQQLExpUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTAqMAUGAytlcAMhAFYw MXENHjM4ubp76CZbd8PNJEc5ElerX/gYhrACB6GNo0IwQDAOBgNVHQ8BAf8EBAMC AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUQIiayHREptI7YAr87AMfj8qB Tl8wBQYDK2VwA0EAnH3WcTatTHQ/jfCjVwsDmB+1SUoUz9mlPuttW+ZgVOAxTaQ3 pdbTDE0jKRZI/8fjf6BTwkGqodDAfHojdcEUCA== -----END CERTIFICATE----- ================================================ FILE: initca/testdata/5min-rsa-key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAtrYWs9ao2CpLWWLMyJJr3Bw7eJu3vSImzoqsBuhAREMaeuHm vAwqbByVpdxu1o+t0u6cMp/1M4YwDSxD4Ny3zEUUGse6yZpyph0+whdHSn1LOCxY KVwMtcYaEswenm0a+s/b9BYpbLv6lPoJ8+6bQNDuyyracDzlvGgk/HabemqDly4+ W64tlrMUDHBuHHIm5EMF1sqVcinLCS8KsVDVfg4qKfzsZbTw0dDo5GZh1lPslkk9 y8NzRltZjfJ3y5acv7SvIlETpy41VxScplR+Ot/6sXNJY3aEBT10smPXPABDeWjx FbnU5xacL/pC7pnKy734sL4lkvzKPDWZPsNMEwIDAQABAoIBAHIFHBHKib+sVS1I 7MbWKR1JOQvBEV6kK1eFTmlZEpIG1kWNJ/J+HRMum2zQLRMUwsL5SNyG2fv3Z5Ew 6IMw+joteahkr/oTuixT39A7uq+PlRtPAQ1+digRoj/MxebT65xNjtO56MwEWxIR H5jsdFJ0kDCVY4/bUPrMexhZ5Bj1xM3j8wpCPlVv2b9Ic/FUD9p6tOZDFhfSluiE 87VsFHUImNvu4p/BAKUuKiz58cPNDHPAABsPrJR2SVU59roC4QtEmaxbmDkXUtB1 +o+ypJQ0saqoffzHq7URebrJU9u+AV51UWaqHjg5OAe8eElOou6MHYX8R9cWZmJX UQKPyVECgYEAyLqstNHtA7R7+r4bW8Tr/kF7z+VvCfV9wB6TPT+ycuv3aU5+HYgR YRs2RBRtwI625hPk7AXEdbMt3SKoKjcMNMSD3qUK+fJFEyvOqRXiMJ2pLg04GlYZ cOInJd0T1q3O2cNLZwcWB1L0/KiV0dYHc4p+p5hisai3T9w7QthTUr8CgYEA6QVW jcsSBRFCokf/GKpTCVXIeqDSwrcEwoZh/RN6PlvgDwjw08G2IxKdAFs3/wxbKWHT xss+LQiMyBL8aRJvBUfotj5e5ZYESaSDqdeYv0Sydl1vfxcknHpTBRUdbyDtsOQn 4X1ZEmfa9vFWS5P9fTFBC0BU2zzrhSlfQb6g360CgYBmnT+zBGo07aw/p7XWuRmn lhRUWEbmgXAyqa69rfVs2IJXfD/umuO/j6izLvpYaNzJS7xIiD5BqUK1/ISZaCC+ TQPY6uhslFSJk2iHed9y2PZmy2010XQaCBLZQWZl5d6L5lGCrtWtEtSY4RoN9mtC vrc2uCkkB0sG8V/+MRaPgwKBgBiML2oQkn1mLBbcbssyZjz9hHkmqA1LKn0zmu8G NkKLezcaQgSMy5s2QsPe2C9OJexeGek/T/V+iRYqqdyHzJpJ0QIh3+1fuGPpqNUj mTvNCN/fR/ejgH/bgxNt/gPO/Ds+TdU7Vz7RIggRtH2RwYqGvctpo4bVDBqjGR3b 7yahAoGAAgH97uN2FU1ffK0OAfMA1N58ikq/bg07KnJxO2CP5hrgsWK2ZVfeHUmU 3k+xqQHCIuew55yO0tARTrFAh3Rj+zarA+PrtnzqW82wCIn8Fym3PFzbK2qrIMie yp0p4nBXsRmzinrPWKUYlFyRNY3Tcbstm5gUw2S4czSwwQeM/No= -----END RSA PRIVATE KEY----- ================================================ FILE: initca/testdata/5min-rsa.pem ================================================ -----BEGIN CERTIFICATE----- MIID3DCCAsSgAwIBAgIIfbm2I1hwBa8wDQYJKoZIhvcNAQELBQAwejELMAkGA1UE BhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNVBAsTGlRlc3Qg Q2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMw EQYDVQQIEwpDYWxpZm9ybmlhMB4XDTE1MTAwODIwMjEwMFoXDTE1MTAwODIwMjYw MFowejELMAkGA1UEBhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAh BgNVBAsTGlRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4g RnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAtrYWs9ao2CpLWWLMyJJr3Bw7eJu3vSImzoqsBuhAREMa euHmvAwqbByVpdxu1o+t0u6cMp/1M4YwDSxD4Ny3zEUUGse6yZpyph0+whdHSn1L OCxYKVwMtcYaEswenm0a+s/b9BYpbLv6lPoJ8+6bQNDuyyracDzlvGgk/HabemqD ly4+W64tlrMUDHBuHHIm5EMF1sqVcinLCS8KsVDVfg4qKfzsZbTw0dDo5GZh1lPs lkk9y8NzRltZjfJ3y5acv7SvIlETpy41VxScplR+Ot/6sXNJY3aEBT10smPXPABD eWjxFbnU5xacL/pC7pnKy734sL4lkvzKPDWZPsNMEwIDAQABo2YwZDAOBgNVHQ8B Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQUCHoGEI1RZ8JN 7UZ4zcTRll8nnnAwHwYDVR0jBBgwFoAUCHoGEI1RZ8JN7UZ4zcTRll8nnnAwDQYJ KoZIhvcNAQELBQADggEBAHRcbd6cSXV6IuT4jLV8k6OUUlxzobbiRnXJrLjy9Anx tyIUWv2XSh/4IEJa+/MLNIb28gU9Sa2y4GV1qAgOM5qUM2iQJyLem0pTg0WTVKlj ytEK1kUwQCNkc/xpDrPo5CbN3aDuW/VPntOJL1GSQzS7jzK3NeQ9sah9YYhk4Wsk jzHVI1sX+qzcuUqCIPhqmGR0JE8ZI5YzbMTZ4/B+oWxZ7EyzB8O+v6HVD4eQFBSq tyGhGbh7mUvuMpVJ8FIX4BA7QL+RwqNNtAMZKcxPjhy5I23nVclbTCz/NC2Dgp8H 13uQsEpUZ65clgiTo4LuPzPiIouZh5cBWP4gGqbyyS4= -----END CERTIFICATE----- ================================================ FILE: initca/testdata/README.md ================================================ 1. To generate 5min-rsa.pem and 5min-rsa-key.pem ``` $ cfssl gencert -initca ca_csr_rsa.json | cfssljson -bare 5min-rsa ``` 2. To generate 5min-ecdsa.pem and 5min-ecdsa-key.pem ``` $ cfssl gencert -initca ca_csr_ecdsa.json | cfssljson -bare 5min-ecdsa ``` 2. To generate 5min-ed25519.pem and 5min-ed25519-key.pem ``` $ cfssl gencert -initca ca_csr_ed25519.json | cfssljson -bare 5min-ed25519 ``` The above commands will generate 5min-rsa.csr, 5min-ecdsa.csr 5min-ed25519.csr accordingly, but those files can be ignored. ================================================ FILE: initca/testdata/ca_csr_ecdsa.json ================================================ { "key": { "algo": "ecdsa", "size": 256 }, "names": [ { "C": "US", "L": "San Francisco", "ST": "California", "O": "CloudFlare, Inc.", "OU": "Test Certificate Authority" } ], "ca": { "expiry": "5m" } } ================================================ FILE: initca/testdata/ca_csr_ed25519.json ================================================ { "key": { "algo": "ed25519" }, "names": [ { "C": "US", "L": "San Francisco", "ST": "California", "O": "CloudFlare, Inc.", "OU": "Test Certificate Authority" } ], "ca": { "expiry": "5m" } } ================================================ FILE: initca/testdata/ca_csr_rsa.json ================================================ { "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "San Francisco", "ST": "California", "O": "CloudFlare, Inc.", "OU": "Test Certificate Authority" } ], "ca": { "expiry": "5m" } } ================================================ FILE: initca/testdata/ecdsa256.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBgTCCASgCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBn9Ldie6BOcMHezn2dPuYqW z/NoLYMLGNBqhOxUyEidYClI0JW2pWyUgT3A2UazFp1WgE94y7Z+2YlfRz+vcrKg PzA9BgkqhkiG9w0BCQ4xMDAuMCwGA1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3 d3djbG91ZGZsYXJlLmNvbTAKBggqhkjOPQQDAgNHADBEAiBM+QRxe8u6rkdr10Jy cxbR6NxrGrNeg5QqiOqF96JEmgIgDbtjd5e3y3I8W/+ih2us3WtMxgnTXfqPd48i VLcv28Q= -----END CERTIFICATE REQUEST----- ================================================ FILE: initca/testdata/ecdsa384.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBvzCCAUUCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABBk/Q+zMsZOJGkufRzGCWtSUtRjq 0QqChDGWbHLaa0h6ODVeEoKYOMvFJTg4V186tuuBe97KEey0OPDegzCBp5kBIiwg HB/0xWoKdnfdRk6VyjmubPx399cGoZn8aCqgC6A/MD0GCSqGSIb3DQEJDjEwMC4w LAYDVR0RBCUwI4IOY2xvdWRmbGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAoG CCqGSM49BAMDA2gAMGUCMQC57VfwMXDyL5kM7vmO2ynbpgSAuFZT6Yd3C3NnV2jz Biozw3eqIDXqCb2LI09stZMCMGIwCuVARr2IRctxf7AmX7/O2SIaIhCpMFKRedQ7 RiWGZIucp5r6AfT9381PB29bHA== -----END CERTIFICATE REQUEST----- ================================================ FILE: initca/testdata/ecdsa521.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIICCjCCAWsCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAHt/s9KTZETzu94JIAjZ3BaS toSG65hGIc1e0Gt7PhdQxPp5FP2D8rQ1wc+pcZhD2O8525kPxopaqTd+fWKBuD3O AULzoH2OX+atIuumTQzLNbTsIbP0tY3dh7d8LItuERkZn1NfsNl3z6bnNAaR137m f4aWv49ImbA/Tkv8VmoKX279oD8wPQYJKoZIhvcNAQkOMTAwLjAsBgNVHREEJTAj gg5jbG91ZGZsYXJlLmNvbYIRd3d3Y2xvdWRmbGFyZS5jb20wCgYIKoZIzj0EAwQD gYwAMIGIAkIA8OX9LxWOVnyfB25DFBz6JkjhyDpBM/PXlgLnWb/n2mEuMMB44DOG pljDV768PSW11AC3DtULoIyR92z0TyLEKYoCQgHdGd6PwUtDW5mrAMJQDgebjsxu MwfcdthzKlFlSmRpHMBnRMOJjlg5f9CTBg9d6wEdv7ZIrQSO6eqQHDQRM0VMnw== -----END CERTIFICATE REQUEST----- ================================================ FILE: initca/testdata/ed25519.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBFzCBygIBADBqMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW MBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEUMBIGA1UEChMLZXhhbXBsZS5jb20xGDAW BgNVBAMTD3d3dy5leGFtcGxlLmNvbTAqMAUGAytlcAMhAIvEIdwMxpLmXW+ZKI+u hb4/H/1qaEOCSbWmWF95m1HzoC0wKwYJKoZIhvcNAQkOMR4wHDAaBgNVHREEEzAR gg93d3cuZXhhbXBsZS5jb20wBQYDK2VwA0EA/FCjbBOJT6z5wdBLgCJb3WrQGO9E lOizNutfEk9NlGJliNKkdZO3SZP9Uw/pKHiyxH+vWfUJ3E1DbtTVzmH8DA== -----END CERTIFICATE REQUEST----- ================================================ FILE: initca/testdata/rsa2048.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIDCTCCAfMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTWdoYxX4KN51fP WxQAyGH++VsPbfpAoXIbCPXSmU04BvIxyjzpHQ0ChMKkT/2VNcUeFJwk2fCf+ZwU f0raTQTplofwkckE0gEYA3WcEfJp+hbvbTb/2recsf+JE6JACYJe2Uu5wsjtrE5j A+7aT2BEU9RWzBdSy/5281ZfW3PArqcWaf8+RUyA3WRxVWmjmhFsVB+mdNLhCpW0 C0QNMYR1ppEZiKVnEdao8gcI5sOvSd+35t8g82aPXcNSPU6jKcx1YNUPX5wgPEmu +anfc9RliQbYqqJYVODgBmV8IR5grw93yTsODoWKtFQ4PKVlnt9CD8AS/iSMQYm3 OUogqgMCAwEAAaA/MD0GCSqGSIb3DQEJDjEwMC4wLAYDVR0RBCUwI4IOY2xvdWRm bGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAsGCSqGSIb3DQEBCwOCAQEAl809 gk9uZkRK+MJVYDSLjgGR2xqk5qOwnhovnispA7N3Z1GshodJRQa6ngNCKuXIm2/6 AxB9kDGK14n186Qq4odXqHSHs8FG9i0zUcBXeLv1rPAKtwKTas/SLmsOpPgWPZFa iYiHHeu4HjOQoF987d7uGRYwc3xfstKwJsEXc12eCw2NH8TM1tJgSc/o6CzIpA91 QnZKhx6uGM4xI2gnOaJA1YikNhyFGBuOGMZgd0k2+/IcR2pg0z4pc5oQw1bXLANx anqlA/MDrCM9v9019bRJ73zK8LQ3k/FW61PA9nL7RZ8ku65R+uYcVEdLa8pUeqnH cJZNboDRsItpccZuRQ== -----END CERTIFICATE REQUEST----- ================================================ FILE: initca/testdata/rsa3072.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIECTCCAnMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAL0zzgBv+VTwZOPy LtuLFweQrj5Lfrje2hnNB7Y3TD4+yCM/cA4yTILixCe/B+N7LQysJgVDbW8u6BZQ 8ZqeDKOP6KCt37WhmcbT45tLpHmH+Z/uAnCz0hVc/7AyJ3CJXo6PaDCcJjgLuUun W47iy4h79AxyuzELmUeZZGYcO8nqClqcnAzQ6sClGZvJwSbYg2QAFGoA2lHqZ9uN ygAxNLd+rX9cP+yFwAeKzuKtOnVPiJD5lT3wufSkAbd6M7lOoqmTYnbv0A1WfA/e upXno9lbgB6iwF5U0V7OtxdA1bTbvgJgNLlxFF1do0sB28CWmqCFNwLfzcPzt5A4 gLnOyLhNZOmUMXn35KOtp1Zv/yethlgZHxUYGcl6OYwMEFye3Du6dgnTwONzaLhA 7hMI8R60p2YrTLkgSKdFohAY/mKuxHyXxugOHHthlRCOn9m49edcdZ1HrkJXm9jd P9katjCXgTwSdTQlvaMJkfH7wF3ZMjAxPcDf4RKFEpF2wABeNQIDAQABoD8wPQYJ KoZIhvcNAQkOMTAwLjAsBgNVHREEJTAjgg5jbG91ZGZsYXJlLmNvbYIRd3d3Y2xv dWRmbGFyZS5jb20wCwYJKoZIhvcNAQEMA4IBgQBF/RCHNAAOAaRI4VyO0tRPA5Dw 0/1/pgmBm/VejHIwDJnMFCl9njh0RSo1RgsVLhw6ovYbk3ORb4OD4UczPTq3GrFp KP9uPR+2pR4FWJpCVfCl76YabQv6fUDdiT7ojzyRhsAmkd5rOdiMvWV3Rp+YmBuU KH/dwkukfn+OeJIbERS5unzOBtQL+g5dU4CHWAqJQIqHr373w38OlYN+JY9QLrYy sWU9Ye6RjdySXPJ5UzyfOEfc9Ji89RJsVeceB1+As5u5vBvtzGgIMSFUzN947RZo DZ48JiB71VpmKXbn9LIRn25dlbVMzxRdSeZ194L3JFVAf9OxJTsc1QNFhOacoFgy hqvtN2iKntEyPo2nacYhpz/FAdJ2JThNH+4WtpPWAqx8Lw/e1OttiDt+6M0FEuVz svkSHnK206yo+a9Md37nUDDYxtlJEB+9F2qUZNQ7Hv+dxjmJOIgHOXxy1pLEdpVU rGdGLVXeJNPCh9x+GK21QjdxZABmYAaF8k36Pv4= -----END CERTIFICATE REQUEST----- ================================================ FILE: initca/testdata/rsa4096.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIFCTCCAvMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANkKL22jMn3eFCpj T6lbeq4nC3aEqwTGrLARidAmO29WIhzs6LxRpM6xSMoPI6DvJVUGpMFEKF4xNTc5 X9/gSFrw2eI5Q3U3aGcaToSCxH4hXejwIzX8Ftlb/LfpXhbSsFr5MS3kiTY4zZxM n3dSy2gZljD/g0tlQf5BdHdR4WKRhWnqRiGng+BmW4rjbcO7SoN33jSXsMcguCg5 8dmYuf5G5KVXsqwEoCQBeKGnca9orcm4i90VnGt4qZUpfAn1cADzYGpRzX79USJ6 tol4ovgGPN08LJFqcVl+dK8VzJ03JWBhI1jePbWS4Bz5oNtkhQQXilU+G6FQxc6a UPf6KcFyOB+qMJmEwJZD9yaNK1YbsKfSztQEsb1JEezQnVHxp91Ch3AcWoikuOiY yCg0V5lcK15SLv1+5sj9YzF7ngMmThcIJ6B5gS3swpD5AX6FJaI1BrGwT/RXKKQP tRX1BySLx8RcINjFb5wv3q9QIE8vrW1BOk9f4dfmxiFYnc+6bCCbIrg7APQVtKTa ixNJFSqZz7fm9loeNPHHXfUT5RoW5yzVa8igc+yv4qeYsWHcZ4c/Y91OJp19HMjM bYm2alt8XagBgJjO0FW8wvsKwhhlhWK0WO6sQ7Fkl7fH1GtxEpc248hAW24SZMmS led3LblCT8IC3a9BLhqJ2q8cfPp9AgMBAAGgPzA9BgkqhkiG9w0BCQ4xMDAuMCwG A1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3d3djbG91ZGZsYXJlLmNvbTALBgkq hkiG9w0BAQ0DggIBAAgz3NuN43+F+8+WhQ9hb7DOp6Amut7XubOkEBtBVgP3R8U1 uSsgocR1rvnZ1/bhkeGyTly0eQPhcSEdMo/GgIrcn+co0KLcDyV6Rf3Cgksx9dUZ TzHSkxmFkxlxYfIGes6abH+2OPiacwK2gLvvmXFYIxEhv+LKzzteQi0xlinewv7R FnSykZ4QialsFyCgOjOxa11aEdRv6T8qKwhjUOk0VedtzOkt/k95aydTNLjXl2OV jloeTsbB00yWIqdyhG12+TgcJOa0pNP1zTjgFPodMuRUuiAcbT7Mt7sLCefKNzvZ Ln6b4y7e6N3YLOHALTIP+LI4y8ar47WlXCNw/zeOM2sW8udjYrukN6WOV3X68oMf Zsv6jqyGSaCDwdImR4VECUVvkabg9Sq4pz+ijTT+9cNA66omYL+/QAh0GahlROgW kDGI8zeEUoAC8RkAbFGMJA8jEbAfbT000ZwnLX2SZ8YRQX4Jd1FTmAH99FkvvT8N ovaGRSQQI5rWQGQYqF67So7PywEaEXeUHTBrv41Msva6CdaWHn7bh/fj4B21ETS7 VJvrk5DLJTyruqon7EVJU1pn38ppaXF4Z6a9n3C8TqudT/gdJUYn/SBo5jx20uGJ d9k6vDqixntvk/TRZ848k1AXiv5uUJTdnoPPhzSGjxEaeKuB0R1ZHomVdjU4 -----END CERTIFICATE REQUEST----- ================================================ FILE: log/log.go ================================================ // Package log implements a wrapper around the Go standard library's // logging package. Clients should set the current log level; only // messages below that level will actually be logged. For example, if // Level is set to LevelWarning, only log messages at the Warning, // Error, and Critical levels will be logged. package log import ( "fmt" "log" "os" ) // The following constants represent logging levels in increasing levels of seriousness. const ( // LevelDebug is the log level for Debug statements. LevelDebug = iota // LevelInfo is the log level for Info statements. LevelInfo // LevelWarning is the log level for Warning statements. LevelWarning // LevelError is the log level for Error statements. LevelError // LevelCritical is the log level for Critical statements. LevelCritical // LevelFatal is the log level for Fatal statements. LevelFatal ) var levelPrefix = [...]string{ LevelDebug: "DEBUG", LevelInfo: "INFO", LevelWarning: "WARNING", LevelError: "ERROR", LevelCritical: "CRITICAL", LevelFatal: "FATAL", } // Level stores the current logging level. var Level = LevelInfo // SyslogWriter specifies the necessary methods for an alternate output // destination passed in via SetLogger. // // SyslogWriter is satisfied by *syslog.Writer. type SyslogWriter interface { Debug(string) Info(string) Warning(string) Err(string) Crit(string) Emerg(string) } // syslogWriter stores the SetLogger() parameter. var syslogWriter SyslogWriter // SetLogger sets the output used for output by this package. // A *syslog.Writer is a good choice for the logger parameter. // Call with a nil parameter to revert to default behavior. func SetLogger(logger SyslogWriter) { syslogWriter = logger } func print(l int, msg string) { if l >= Level { if syslogWriter != nil { switch l { case LevelDebug: syslogWriter.Debug(msg) case LevelInfo: syslogWriter.Info(msg) case LevelWarning: syslogWriter.Warning(msg) case LevelError: syslogWriter.Err(msg) case LevelCritical: syslogWriter.Crit(msg) case LevelFatal: syslogWriter.Emerg(msg) } } else { log.Printf("[%s] %s", levelPrefix[l], msg) } } } func outputf(l int, format string, v []interface{}) { print(l, fmt.Sprintf(format, v...)) } func output(l int, v []interface{}) { print(l, fmt.Sprint(v...)) } // Fatalf logs a formatted message at the "fatal" level and then exits. The // arguments are handled in the same manner as fmt.Printf. func Fatalf(format string, v ...interface{}) { outputf(LevelFatal, format, v) os.Exit(1) } // Fatal logs its arguments at the "fatal" level and then exits. func Fatal(v ...interface{}) { output(LevelFatal, v) os.Exit(1) } // Criticalf logs a formatted message at the "critical" level. The // arguments are handled in the same manner as fmt.Printf. func Criticalf(format string, v ...interface{}) { outputf(LevelCritical, format, v) } // Critical logs its arguments at the "critical" level. func Critical(v ...interface{}) { output(LevelCritical, v) } // Errorf logs a formatted message at the "error" level. The arguments // are handled in the same manner as fmt.Printf. func Errorf(format string, v ...interface{}) { outputf(LevelError, format, v) } // Error logs its arguments at the "error" level. func Error(v ...interface{}) { output(LevelError, v) } // Warningf logs a formatted message at the "warning" level. The // arguments are handled in the same manner as fmt.Printf. func Warningf(format string, v ...interface{}) { outputf(LevelWarning, format, v) } // Warning logs its arguments at the "warning" level. func Warning(v ...interface{}) { output(LevelWarning, v) } // Infof logs a formatted message at the "info" level. The arguments // are handled in the same manner as fmt.Printf. func Infof(format string, v ...interface{}) { outputf(LevelInfo, format, v) } // Info logs its arguments at the "info" level. func Info(v ...interface{}) { output(LevelInfo, v) } // Debugf logs a formatted message at the "debug" level. The arguments // are handled in the same manner as fmt.Printf. func Debugf(format string, v ...interface{}) { outputf(LevelDebug, format, v) } // Debug logs its arguments at the "debug" level. func Debug(v ...interface{}) { output(LevelDebug, v) } ================================================ FILE: log/log_test.go ================================================ package log import ( "bytes" "log" "strings" "testing" ) const teststring = "asdf123" func TestOutputf(t *testing.T) { buf := new(bytes.Buffer) log.SetOutput(buf) Level = LevelDebug outputf(LevelDebug, teststring, nil) // outputf correctly prints string if !strings.Contains(buf.String(), teststring) { t.Fail() } return } func TestOutput(t *testing.T) { buf := new(bytes.Buffer) log.SetOutput(buf) Level = LevelDebug output(LevelDebug, nil) // outputf correctly prints string with proper Debug prefix if !strings.Contains(buf.String(), levelPrefix[LevelDebug]) { t.Fail() } return } func TestCriticalf(t *testing.T) { buf := new(bytes.Buffer) log.SetOutput(buf) Criticalf(teststring, nil) // outputf correctly prints string // should never fail because critical > debug if !strings.Contains(buf.String(), teststring) { t.Fail() } return } func TestCritical(t *testing.T) { buf := new(bytes.Buffer) log.SetOutput(buf) Critical(nil) // outputf correctly prints string if !strings.Contains(buf.String(), levelPrefix[LevelCritical]) { t.Fail() } return } func TestWarningf(t *testing.T) { buf := new(bytes.Buffer) log.SetOutput(buf) Warningf(teststring, nil) // outputf correctly prints string // should never fail because fatal critical > debug if !strings.Contains(buf.String(), teststring) { t.Fail() } return } func TestWarning(t *testing.T) { buf := new(bytes.Buffer) log.SetOutput(buf) Warning(nil) // outputf correctly prints string if !strings.Contains(buf.String(), levelPrefix[LevelWarning]) { t.Fail() } return } func TestInfof(t *testing.T) { buf := new(bytes.Buffer) log.SetOutput(buf) Infof(teststring, nil) // outputf correctly prints string // should never fail because fatal info > debug if !strings.Contains(buf.String(), teststring) { t.Fail() } return } func TestInfo(t *testing.T) { buf := new(bytes.Buffer) log.SetOutput(buf) Info(nil) // outputf correctly prints string if !strings.Contains(buf.String(), levelPrefix[LevelInfo]) { t.Fail() } return } func TestDebugf(t *testing.T) { buf := new(bytes.Buffer) log.SetOutput(buf) Level = LevelDebug Debugf(teststring, nil) // outputf correctly prints string // should never fail because fatal debug >= debug if !strings.Contains(buf.String(), teststring) { t.Fail() } return } func TestDebug(t *testing.T) { buf := new(bytes.Buffer) log.SetOutput(buf) Level = LevelDebug Debug(nil) // outputf correctly prints string if !strings.Contains(buf.String(), levelPrefix[LevelDebug]) { t.Fail() } return } type testSyslogger struct { *bytes.Buffer } func (l testSyslogger) Debug(s string) { l.WriteString("[DEBUG] ") _, _ = l.WriteString(s) } func (l testSyslogger) Info(s string) { l.WriteString("[INFO] ") _, _ = l.WriteString(s) } func (l testSyslogger) Warning(s string) { l.WriteString("[WARN] ") _, _ = l.WriteString(s) } func (l testSyslogger) Err(s string) { l.WriteString("[ERROR] ") _, _ = l.WriteString(s) } func (l testSyslogger) Crit(s string) { l.WriteString("[CRIT] ") _, _ = l.WriteString(s) } func (l testSyslogger) Emerg(s string) { l.WriteString("[FATAL] ") _, _ = l.WriteString(s) } func TestSetLogger(t *testing.T) { buf := new(bytes.Buffer) SetLogger(testSyslogger{buf}) Level = LevelDebug outputf(LevelDebug, teststring, nil) // outputf correctly prints string if !strings.Contains(buf.String(), teststring) { t.Fail() } SetLogger(nil) return } ================================================ FILE: multiroot/config/config.go ================================================ // Package config contains the multi-root configuration file parser. package config import ( "bufio" "crypto" "crypto/x509" "errors" "fmt" "net" "net/url" "os" "path/filepath" "regexp" "strings" "github.com/cloudflare/cfssl/certdb/dbconf" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/helpers/derhelpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/whitelist" "github.com/cloudflare/redoctober/client" "github.com/cloudflare/redoctober/core" "github.com/jmoiron/sqlx" ) // RawMap is shorthand for the type used as a map from string to raw Root struct. type RawMap map[string]map[string]string var ( configSection = regexp.MustCompile("^\\s*\\[\\s*(\\w+)\\s*\\]\\s*$") quotedConfigLine = regexp.MustCompile("^\\s*(\\w+)\\s*=\\s*[\"'](.*)[\"']\\s*$") configLine = regexp.MustCompile("^\\s*(\\w+)\\s*=\\s*(.*)\\s*$") commentLine = regexp.MustCompile("^#.*$") blankLine = regexp.MustCompile("^\\s*$") defaultSection = "default" ) // ParseToRawMap takes the filename as a string and returns a RawMap. func ParseToRawMap(fileName string) (cfg RawMap, err error) { var file *os.File cfg = make(RawMap, 0) file, err = os.Open(fileName) if err != nil { return } defer file.Close() scanner := bufio.NewScanner(file) var currentSection string for scanner.Scan() { line := scanner.Text() if commentLine.MatchString(line) { continue } else if blankLine.MatchString(line) { continue } else if configSection.MatchString(line) { section := configSection.ReplaceAllString(line, "$1") if !cfg.SectionInConfig(section) { cfg[section] = make(map[string]string, 0) } currentSection = section } else if configLine.MatchString(line) { regex := configLine if quotedConfigLine.MatchString(line) { regex = quotedConfigLine } if currentSection == "" { currentSection = defaultSection if !cfg.SectionInConfig(currentSection) { cfg[currentSection] = make(map[string]string, 0) } } key := regex.ReplaceAllString(line, "$1") val := regex.ReplaceAllString(line, "$2") cfg[currentSection][key] = val } else { err = fmt.Errorf("invalid config file") break } } return } // SectionInConfig determines whether a section is in the configuration. func (c *RawMap) SectionInConfig(section string) bool { for s := range *c { if section == s { return true } } return false } // A Root represents a single certificate authority root key pair. type Root struct { PrivateKey crypto.Signer Certificate *x509.Certificate Config *config.Signing ACL whitelist.NetACL DB *sqlx.DB } // LoadRoot parses a config structure into a Root structure func LoadRoot(cfg map[string]string) (*Root, error) { var root Root var err error spec, ok := cfg["private"] if !ok { return nil, ErrMissingPrivateKey } certPath, ok := cfg["certificate"] if !ok { return nil, ErrMissingCertificatePath } configPath, ok := cfg["config"] if !ok { return nil, ErrMissingConfigPath } root.PrivateKey, err = parsePrivateKeySpec(spec, cfg) if err != nil { return nil, err } in, err := os.ReadFile(certPath) if err != nil { return nil, err } root.Certificate, err = helpers.ParseCertificatePEM(in) if err != nil { return nil, err } conf, err := config.LoadFile(configPath) if err != nil { return nil, err } root.Config = conf.Signing nets := cfg["nets"] if nets != "" { root.ACL, err = parseACL(nets) if err != nil { return nil, err } } dbConfig := cfg["dbconfig"] if dbConfig != "" { db, err := dbconf.DBFromConfig(dbConfig) if err != nil { return nil, err } root.DB = db } return &root, nil } func parsePrivateKeySpec(spec string, cfg map[string]string) (crypto.Signer, error) { specURL, err := url.Parse(spec) if err != nil { return nil, err } var priv crypto.Signer switch specURL.Scheme { case "file": // A file spec will be parsed such that the root // directory of a relative path will be stored as the // hostname, and the remainder of the file's path is // stored in the Path field. log.Debug("loading private key file", specURL.Path) path := filepath.Join(specURL.Host, specURL.Path) in, err := os.ReadFile(path) if err != nil { return nil, err } log.Debug("attempting to load PEM-encoded private key") priv, err = helpers.ParsePrivateKeyPEM(in) if err != nil { log.Debug("file is not a PEM-encoded private key") log.Debug("attempting to load DER-encoded private key") priv, err = derhelpers.ParsePrivateKeyDER(in) if err != nil { return nil, err } } log.Debug("loaded private key") return priv, nil case "rofile": log.Warning("Red October support is currently experimental") path := filepath.Join(specURL.Host, specURL.Path) in, err := os.ReadFile(path) if err != nil { return nil, err } roServer := cfg["ro_server"] if roServer == "" { return nil, errors.New("config: no RedOctober server available") } // roCAPath can be empty; if it is, the client uses // the system default CA roots. roCAPath := cfg["ro_ca"] roUser := cfg["ro_user"] if roUser == "" { return nil, errors.New("config: no RedOctober user available") } roPass := cfg["ro_pass"] if roPass == "" { return nil, errors.New("config: no RedOctober passphrase available") } log.Debug("decrypting key via RedOctober Server") roClient, err := client.NewRemoteServer(roServer, roCAPath) if err != nil { return nil, err } req := core.DecryptRequest{ Name: roUser, Password: roPass, Data: in, } in, err = roClient.DecryptIntoData(req) if err != nil { return nil, err } log.Debug("attempting to load PEM-encoded private key") priv, err = helpers.ParsePrivateKeyPEM(in) if err != nil { log.Debug("file is not a PEM-encoded private key") log.Debug("attempting to load DER-encoded private key") priv, err = derhelpers.ParsePrivateKeyDER(in) if err != nil { return nil, err } } log.Debug("loaded private key") return priv, nil default: return nil, ErrUnsupportedScheme } } func parseACL(nets string) (whitelist.NetACL, error) { wl := whitelist.NewBasicNet() netList := strings.Split(nets, ",") for i := range netList { netList[i] = strings.TrimSpace(netList[i]) _, n, err := net.ParseCIDR(netList[i]) if err != nil { return nil, err } wl.Add(n) } return wl, nil } // A RootList associates a set of labels with the appropriate private // keys and their certificates. type RootList map[string]*Root var ( // ErrMissingPrivateKey indicates that the configuration is // missing a private key specifier. ErrMissingPrivateKey = errors.New("config: root is missing private key spec") // ErrMissingCertificatePath indicates that the configuration // is missing a certificate specifier. ErrMissingCertificatePath = errors.New("config: root is missing certificate path") // ErrMissingConfigPath indicates that the configuration lacks // a valid CFSSL configuration. ErrMissingConfigPath = errors.New("config: root is missing configuration file path") // ErrInvalidConfig indicates the configuration is invalid. ErrInvalidConfig = errors.New("config: invalid configuration") // ErrUnsupportedScheme indicates a private key scheme that is not currently supported. ErrUnsupportedScheme = errors.New("config: unsupported private key scheme") ) // Parse loads a RootList from a file. func Parse(filename string) (RootList, error) { cfgMap, err := ParseToRawMap(filename) if err != nil { return nil, err } var rootList = RootList{} for label, entries := range cfgMap { root, err := LoadRoot(entries) if err != nil { return nil, err } rootList[label] = root } return rootList, nil } ================================================ FILE: multiroot/config/config_test.go ================================================ package config import ( "crypto/rsa" "os" "testing" "github.com/cloudflare/cfssl/log" _ "github.com/mattn/go-sqlite3" // import just to initialize SQLite for testing ) // UnlinkIfExists removes a file if it exists. func UnlinkIfExists(file string) { _, err := os.Stat(file) if err != nil && os.IsNotExist(err) { panic("failed to remove " + file) } os.Remove(file) } // stringSlicesEqual compares two string lists, checking that they // contain the same elements. func stringSlicesEqual(slice1, slice2 []string) bool { if len(slice1) != len(slice2) { return false } for i := range slice1 { if slice1[i] != slice2[i] { return false } } for i := range slice2 { if slice1[i] != slice2[i] { return false } } return true } func TestGoodConfig(t *testing.T) { testFile := "testdata/test.conf" cmap, err := ParseToRawMap(testFile) if err != nil { t.Fatalf("%v", err) } else if len(cmap) != 2 { t.Fatal("expected 2 sections, have", len(cmap)) } } func TestGoodConfig2(t *testing.T) { testFile := "testdata/test2.conf" cmap, err := ParseToRawMap(testFile) if err != nil { t.Fatalf("%v", err) } else if len(cmap) != 1 { t.Fatal("expected 1 section, have", len(cmap)) } else if len(cmap["default"]) != 3 { t.Fatal("expected 3 items in default section, have", len(cmap["default"])) } } func TestBadConfig(t *testing.T) { testFile := "testdata/bad.conf" _, err := ParseToRawMap(testFile) if err == nil { t.Fatal("expected invalid config file to fail") } } func TestQuotedValue(t *testing.T) { testFile := "testdata/test.conf" cmap, _ := ParseToRawMap(testFile) val := cmap["sectionName"]["key4"] if val != " space at beginning and end " { t.Fatal("Wrong value in double quotes [", val, "]") } if !cmap.SectionInConfig("sectionName") { t.Fatal("expected SectionInConfig to return true") } val = cmap["sectionName"]["key5"] if val != " is quoted with single quotes " { t.Fatal("Wrong value in single quotes [", val, "]") } } func TestENoEnt(t *testing.T) { _, err := ParseToRawMap("testdata/enoent") if err == nil { t.Fatal("expected error on non-existent file") } } func TestLoadRoots(t *testing.T) { roots, err := Parse("testdata/roots.conf") if err != nil { t.Fatalf("%v", err) } if len(roots) != 2 { t.Fatal("expected one CA in the roots") } if root, ok := roots["primary"]; !ok { t.Fatal("expected a primary CA section") } else if _, ok := root.PrivateKey.(*rsa.PrivateKey); !ok { t.Fatal("expected an RSA private key") } } func TestLoadDERRoots(t *testing.T) { roots, err := Parse("testdata/roots_der.conf") if err != nil { t.Fatalf("%v", err) } if len(roots) != 2 { t.Fatal("expected one CA in the roots") } if root, ok := roots["primary"]; !ok { t.Fatal("expected a primary CA section") } else if _, ok := root.PrivateKey.(*rsa.PrivateKey); !ok { t.Fatal("expected an RSA private key") } } func TestLoadKSMRoot(t *testing.T) { _, err := Parse("testdata/roots_ksm.conf") if err == nil { t.Fatal("ksm specs are not supported yet") } } func TestLoadBadRootConfs(t *testing.T) { confs := []string{ "testdata/roots_bad_db.conf", "testdata/roots_bad_certificate.conf", "testdata/roots_bad_private_key.conf", "testdata/roots_badconfig.conf", "testdata/roots_badspec.conf", "testdata/roots_badspec2.conf", "testdata/roots_badspec3.conf", "testdata/roots_bad_whitelist.conf", "testdata/roots_bad_whitelist.conf2", "testdata/roots_missing_certificate.conf", "testdata/roots_missing_certificate_entry.conf", "testdata/roots_missing_private_key.conf", "testdata/roots_missing_private_key_entry.conf", } for _, cf := range confs { _, err := Parse(cf) if err == nil { t.Fatalf("expected config file %s to fail", cf) } log.Debugf("%s: %v", cf, err) } } const confWhitelist = "testdata/roots_whitelist.conf" func TestLoadWhitelist(t *testing.T) { roots, err := Parse(confWhitelist) if err != nil { t.Fatalf("%v", err) } if roots["backup"].ACL != nil { t.Fatal("Expected a nil ACL for the backup root") } if roots["primary"].ACL == nil { t.Fatal("Expected a non-nil ACL for the primary root") } validIPs := [][]byte{ {10, 0, 2, 3}, {10, 0, 2, 247}, {172, 16, 3, 9}, {192, 168, 3, 15}, } badIPs := [][]byte{ {192, 168, 0, 1}, {127, 0, 0, 1}, {192, 168, 3, 14}, {192, 168, 3, 16}, {255, 255, 0, 1}, {0, 0, 0, 0}, } wl := roots["primary"].ACL for i := range validIPs { if !wl.Permitted(validIPs[i]) { t.Fatalf("ACL should have permitted IP %v", validIPs[i]) } } for i := range badIPs { if wl.Permitted(badIPs[i]) { t.Fatalf("ACL should not have permitted IP %v", badIPs[i]) } } } const confWhitelistIPv6 = "testdata/roots_whitelist_ipv6.conf" func TestLoadIPv6Whitelist(t *testing.T) { roots, err := Parse(confWhitelistIPv6) if err != nil { t.Fatalf("%v", err) } if roots["backup"].ACL != nil { t.Fatal("Expected a nil ACL for the backup root") } if roots["primary"].ACL == nil { t.Fatal("Expected a non-nil ACL for the primary root") } validIPs := [][]byte{ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {253, 77, 152, 85, 16, 29, 230, 139, 0, 0, 0, 0, 0, 0, 0, 1}, {253, 77, 152, 85, 16, 29, 230, 139, 0, 0, 0, 0, 32, 0, 0, 1}, {10, 0, 4, 18}, } badIPs := [][]byte{ {192, 168, 0, 1}, {127, 0, 0, 1}, {192, 168, 3, 14}, {192, 168, 3, 16}, {255, 255, 0, 1}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}, {253, 77, 152, 85, 16, 29, 230, 140, 0, 0, 0, 0, 0, 0, 0, 1}, {254, 77, 152, 85, 16, 29, 230, 139, 0, 0, 0, 0, 0, 0, 0, 1}, } wl := roots["primary"].ACL for i := range validIPs { if !wl.Permitted(validIPs[i]) { t.Fatalf("ACL should have permitted IP %v", validIPs[i]) } } for i := range badIPs { if wl.Permitted(badIPs[i]) { t.Fatalf("ACL should not have permitted IP %v", badIPs[i]) } } } const confDBConfig = "testdata/roots_db.conf" func TestLoadDBConfig(t *testing.T) { roots, err := Parse(confDBConfig) if err != nil { t.Fatalf("%v", err) } if roots["backup"].DB != nil { t.Fatal("Expected a nil DB for the backup root") } if roots["primary"].DB == nil { t.Fatal("Expected a non-nil DB for the primary root") } } ================================================ FILE: multiroot/config/testdata/bad-db-config.json ================================================ {"driver":"invalid","data_source":"invalid"} ================================================ FILE: multiroot/config/testdata/bad.conf ================================================ [] key another key key = val ================================================ FILE: multiroot/config/testdata/badconfig.json ================================================ { "data": ================================================ FILE: multiroot/config/testdata/config.json ================================================ { "signing": { "default": { "expiry": "8760h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ], "auth_key": "default_auth" }, "profiles": { "client_auth": { "expiry": "168h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ], "auth_key": "client_auth" } } }, "auth_keys": { "default_auth": { "type": "standard", "key": "de1069ab43f7f385d9a31b76af27e7620e9aa2ad5dccd264367422a452aba67f" }, "client_auth": { "type": "standard", "key": "55292b4762b352e385adf6b117179bbf9d0f5604a462b982e52950a33d48b578" } } } ================================================ FILE: multiroot/config/testdata/db-config.json ================================================ {"driver":"sqlite3","data_source":"certs.db"} ================================================ FILE: multiroot/config/testdata/roots.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json [ backup ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_bad_certificate.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json [ backup ] private = file://testdata/server.key certificate = testdata/server.key config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_bad_db.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json dbconfig = testdata/bad-db-config.json [ backup ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_bad_private_key.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json [ backup ] private = file://testdata/server.crt certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_bad_whitelist.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json nets = 10.0.2.1/24,172.16.3.1/24,127.0.0.1 [ backup ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_bad_whitelist2.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json nets = 10.0.2.1/24,172.16.3.1/24,257.0.0.1/24 [ backup ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_badconfig.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/badconfig.json [ backup ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_badspec.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json [ backup ] private = file://testdata/nosuch.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_badspec2.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json [ backup ] private = ://nothing certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_badspec3.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json [ backup ] private = http://testdata/nosuch.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_db.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json dbconfig = testdata/db-config.json [ backup ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_der.conf ================================================ [ primary ] private = file://testdata/server.der certificate = testdata/server.crt config = testdata/config.json [ backup ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_ksm.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt [ backup ] private = ksm://test-signer certificate = testdata/server.crt ================================================ FILE: multiroot/config/testdata/roots_missing_certificate.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json [ backup ] private = file://testdata/server.key certificate = testdata/enoent config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_missing_certificate_entry.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json [ backup ] private = file://testdata/server.key something_else = nothing config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_missing_private.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt [ backup ] private = file://testdata/server.key certificate = testdata/enoent ================================================ FILE: multiroot/config/testdata/roots_missing_private_key_entry.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json [ backup ] certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_no_kdl_private_key.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt ================================================ FILE: multiroot/config/testdata/roots_whitelist.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json nets = 10.0.2.1/24,172.16.3.1/24, 192.168.3.15/32 [ backup ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/roots_whitelist_ipv6.conf ================================================ [ primary ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json nets = ::1/128, fd4d:9855:101d:e68b::/64, 10.0.4.1/24 [ backup ] private = file://testdata/server.key certificate = testdata/server.crt config = testdata/config.json ================================================ FILE: multiroot/config/testdata/server.crt ================================================ -----BEGIN CERTIFICATE----- MIICATCCAWoCCQDidF+uNJR6czANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 cyBQdHkgTHRkMB4XDTEyMDUwMTIyNTUxN1oXDTEzMDUwMTIyNTUxN1owRTELMAkG A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81 KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt +LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw== -----END CERTIFICATE----- ================================================ FILE: multiroot/config/testdata/server.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQC2mOWeh2HPfWQsQmh4tKRGau/yXt7GQa07RES0huKuP0EHLrhl dUETuSEoY7ZyczxTvKPDs21+H4i8KNlUDd3ZeodLc+Ou3geZT9wYI40Tz40Reip3 MtQM86LHWoMNEG9ezzUoBXaqHoJgdlt2qLGEN6uO8lwPg2x3uQTERl8e4QIDAQAB AoGAVxnsPojZ8X4g8LPk3d9dlXGhb/4tSmk9102jcHH/Y5ssy95Pe6ZJGr1uwbN+ 7m1l05PikpHeoxEryoW51cyfjDVkXUT0zPp2JC38DUA/0A8qWav/aENM64wg1I0P Dil8FywzZEonRNJst53+9cxFye70ely5br/tWxEp4/MsM1kCQQDqV4Lwn8BXOeKg xOwNmcL+0XPedvSPBSPUoGJCzu12rH6Z+UHXipXsqRNSyQ+KGlur14y0kCh5uiVA jmWYVEEjAkEAx3keAo1nFsVW35EPt5LIbh6L6ty7GrvGRvOVeSd6YLtixMety24k hpt1cEv2xlFnbjbBbMkr9eUiUNpttLT6KwJBANGKaLoSjqEwUFYjX1OV/wdtcGcn BOzx0qUouFQ2xZ0NBrNVbyt1bzPLx0yKHkwF35ybw+Qc1yRpby/3ZB6+j/MCQFLl vtcItOL9uBDJVGLSGYHKKBO/D/MYPlqWOHRVN8KjnXRyF4QHjh5y1OeKalAY3Ict Mk1nfWF/jDdVz2neHGkCQHHBR4Xt1/euDku+14z5aLpphTEQVuRD2vQoeKi/W/CY OgNmKj1DzucnCS6yRCrF8Q0Pn8l054a3Wdbl1gqI/gA= -----END RSA PRIVATE KEY----- ================================================ FILE: multiroot/config/testdata/test.conf ================================================ [ sectionName ] key1=some value key2 = some other value # we want to explain the importance and great forethought # in this next value. key3 = unintuitive value key4 = " space at beginning and end " key5 = ' is quoted with single quotes ' [ anotherSection ] key1 = a value key2 = yet another value key1 = overwrites previous value of a value ================================================ FILE: multiroot/config/testdata/test2.conf ================================================ key1 = some value key2 = some other value key3 = unintuitive value ================================================ FILE: ocsp/config/config.go ================================================ // Package config in the ocsp directory provides configuration data for an OCSP // signer. package config import "time" // Config contains configuration information required to set up an OCSP signer. type Config struct { CACertFile string ResponderCertFile string KeyFile string Interval time.Duration } ================================================ FILE: ocsp/ocsp.go ================================================ /* Package ocsp exposes OCSP signing functionality, much like the signer package does for certificate signing. It also provies a basic OCSP responder stack for serving pre-signed OCSP responses. */ package ocsp import ( "bytes" "crypto" "crypto/x509" "crypto/x509/pkix" "os" "strconv" "strings" "time" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "golang.org/x/crypto/ocsp" ) // revocationReasonCodes is a map between string reason codes // to integers as defined in RFC 5280 var revocationReasonCodes = map[string]int{ "unspecified": ocsp.Unspecified, "keycompromise": ocsp.KeyCompromise, "cacompromise": ocsp.CACompromise, "affiliationchanged": ocsp.AffiliationChanged, "superseded": ocsp.Superseded, "cessationofoperation": ocsp.CessationOfOperation, "certificatehold": ocsp.CertificateHold, "removefromcrl": ocsp.RemoveFromCRL, "privilegewithdrawn": ocsp.PrivilegeWithdrawn, "aacompromise": ocsp.AACompromise, } // StatusCode is a map between string statuses sent by cli/api // to ocsp int statuses var StatusCode = map[string]int{ "good": ocsp.Good, "revoked": ocsp.Revoked, "unknown": ocsp.Unknown, } // SignRequest represents the desired contents of a // specific OCSP response. type SignRequest struct { Certificate *x509.Certificate Status string Reason int RevokedAt time.Time Extensions []pkix.Extension // IssuerHash is the hashing function used to hash the issuer subject and public key // in the OCSP response. Valid values are crypto.SHA1, crypto.SHA256, crypto.SHA384, // and crypto.SHA512. If zero, the default is crypto.SHA1. IssuerHash crypto.Hash // If provided ThisUpdate will override the default usage of time.Now().Truncate(time.Hour) ThisUpdate *time.Time // If provided NextUpdate will override the default usage of ThisUpdate.Add(signerInterval) NextUpdate *time.Time } // Signer represents a general signer of OCSP responses. It is // responsible for populating all fields in the OCSP response that // are not reflected in the SignRequest. type Signer interface { Sign(req SignRequest) ([]byte, error) } // StandardSigner is the default concrete type of OCSP signer. // It represents a single responder (represented by a key and certificate) // speaking for a single issuer (certificate). It is assumed that OCSP // responses are issued at a regular interval, which is used to compute // the nextUpdate value based on the current time. type StandardSigner struct { issuer *x509.Certificate responder *x509.Certificate key crypto.Signer interval time.Duration } // ReasonStringToCode tries to convert a reason string to an integer code func ReasonStringToCode(reason string) (reasonCode int, err error) { // default to 0 if reason == "" { return 0, nil } reasonCode, present := revocationReasonCodes[strings.ToLower(reason)] if !present { reasonCode, err = strconv.Atoi(reason) if err != nil { return } if reasonCode >= ocsp.AACompromise || reasonCode <= ocsp.Unspecified { return 0, cferr.New(cferr.OCSPError, cferr.InvalidStatus) } } return } // NewSignerFromFile reads the issuer cert, the responder cert and the responder key // from PEM files, and takes an interval in seconds func NewSignerFromFile(issuerFile, responderFile, keyFile string, interval time.Duration) (Signer, error) { log.Debug("Loading issuer cert: ", issuerFile) issuerBytes, err := helpers.ReadBytes(issuerFile) if err != nil { return nil, err } log.Debug("Loading responder cert: ", responderFile) responderBytes, err := os.ReadFile(responderFile) if err != nil { return nil, err } log.Debug("Loading responder key: ", keyFile) keyBytes, err := os.ReadFile(keyFile) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err) } issuerCert, err := helpers.ParseCertificatePEM(issuerBytes) if err != nil { return nil, err } responderCert, err := helpers.ParseCertificatePEM(responderBytes) if err != nil { return nil, err } key, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { log.Debugf("Malformed private key %v", err) return nil, err } return NewSigner(issuerCert, responderCert, key, interval) } // NewSigner simply constructs a new StandardSigner object from the inputs, // taking the interval in seconds func NewSigner(issuer, responder *x509.Certificate, key crypto.Signer, interval time.Duration) (Signer, error) { return &StandardSigner{ issuer: issuer, responder: responder, key: key, interval: interval, }, nil } // Sign is used with an OCSP signer to request the issuance of // an OCSP response. func (s StandardSigner) Sign(req SignRequest) ([]byte, error) { if req.Certificate == nil { return nil, cferr.New(cferr.OCSPError, cferr.ReadFailed) } // Verify that req.Certificate is issued under s.issuer if bytes.Compare(req.Certificate.RawIssuer, s.issuer.RawSubject) != 0 { return nil, cferr.New(cferr.OCSPError, cferr.IssuerMismatch) } err := req.Certificate.CheckSignatureFrom(s.issuer) if err != nil { return nil, cferr.Wrap(cferr.OCSPError, cferr.VerifyFailed, err) } var thisUpdate, nextUpdate time.Time if req.ThisUpdate != nil { thisUpdate = *req.ThisUpdate } else { // Round thisUpdate times down to the nearest hour thisUpdate = time.Now().Truncate(time.Hour) } if req.NextUpdate != nil { nextUpdate = *req.NextUpdate } else { nextUpdate = thisUpdate.Add(s.interval) } status, ok := StatusCode[req.Status] if !ok { return nil, cferr.New(cferr.OCSPError, cferr.InvalidStatus) } // If the OCSP responder is the same as the issuer, there is no need to // include any certificate in the OCSP response, which decreases the byte size // of OCSP responses dramatically. certificate := s.responder if s.issuer == s.responder || bytes.Equal(s.issuer.Raw, s.responder.Raw) { certificate = nil } template := ocsp.Response{ Status: status, SerialNumber: req.Certificate.SerialNumber, ThisUpdate: thisUpdate, NextUpdate: nextUpdate, Certificate: certificate, ExtraExtensions: req.Extensions, IssuerHash: req.IssuerHash, } if status == ocsp.Revoked { template.RevokedAt = req.RevokedAt template.RevocationReason = req.Reason } return ocsp.CreateResponse(s.issuer, s.responder, template, s.key) } ================================================ FILE: ocsp/ocsp_test.go ================================================ package ocsp import ( "os" "testing" "time" "github.com/cloudflare/cfssl/helpers" "golang.org/x/crypto/ocsp" ) const ( serverCertFile = "testdata/ca.pem" serverKeyFile = "testdata/ca-key.pem" otherCertFile = "testdata/cert.pem" brokenServerCert = "testdata/server_broken.crt" brokenServerKey = "testdata/server_broken.key" wrongServerCertFile = "testdata/server.crt" wrongServerKeyFile = "testdata/server.key" ) func TestNewSignerFromFile(t *testing.T) { // arbitrary duration dur, _ := time.ParseDuration("1ms") // nonexistent files _, err := NewSignerFromFile("", "", "", dur) if err == nil { t.Fatal("Failed to issue error on improper file") } _, err = NewSignerFromFile(serverCertFile, "", "", dur) if err == nil { t.Fatal("Failed to issue error on improper file") } _, err = NewSignerFromFile(serverCertFile, otherCertFile, "", dur) if err == nil { t.Fatal("Failed to issue error on improper file") } // malformed certs _, err = NewSignerFromFile(brokenServerCert, otherCertFile, serverKeyFile, dur) if err == nil { t.Fatal("Didn't fail on malformed file") } _, err = NewSignerFromFile(serverCertFile, brokenServerCert, serverKeyFile, dur) if err == nil { t.Fatal("Didn't fail on malformed file") } _, err = NewSignerFromFile(serverCertFile, otherCertFile, brokenServerKey, dur) if err == nil { t.Fatal("Didn't fail on malformed file") } // expected case _, err = NewSignerFromFile(serverCertFile, otherCertFile, serverKeyFile, dur) if err != nil { t.Fatalf("Signer creation failed %v", err) } } func setup(t *testing.T) (SignRequest, time.Duration) { dur, _ := time.ParseDuration("1ms") certPEM, err := os.ReadFile(otherCertFile) if err != nil { t.Fatal(err) } leafCert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } req := SignRequest{ Certificate: leafCert, Status: "good", } return req, dur } func TestSignNoResponder(t *testing.T) { req, dur := setup(t) s, err := NewSignerFromFile(serverCertFile, serverCertFile, serverKeyFile, dur) if err != nil { t.Fatalf("Signer creation failed: %v", err) } respBytes, err := s.Sign(req) if err != nil { t.Fatal("Failed to sign with no responder cert") } resp, err := ocsp.ParseResponse(respBytes, nil) if err != nil { t.Fatal("Failed to fail on improper status code") } if resp.Certificate != nil { t.Fatal("Response contain responder cert even though it was identical to issuer") } } func TestSign(t *testing.T) { req, dur := setup(t) // expected case s, err := NewSignerFromFile(serverCertFile, otherCertFile, serverKeyFile, dur) if err != nil { t.Fatalf("Signer creation failed: %v", err) } _, err = s.Sign(SignRequest{}) if err == nil { t.Fatal("Signed request with nil certificate") } _, err = s.Sign(req) if err != nil { t.Fatal("Sign failed") } sMismatch, err := NewSignerFromFile(wrongServerCertFile, otherCertFile, wrongServerKeyFile, dur) if err != nil { t.Fatal("NewSigner failed:", err) } _, err = sMismatch.Sign(req) if err == nil { t.Fatal("Signed a certificate from the wrong issuer") } // incorrect status code req.Status = "aalkjsfdlkafdslkjahds" _, err = s.Sign(req) if err == nil { t.Fatal("Failed to fail on improper status code") } // revoked req.Status = "revoked" _, err = s.Sign(req) if err != nil { t.Fatal("Error on revoked certificate") } } func TestSignCustomInterval(t *testing.T) { req, _ := setup(t) dur := time.Hour s, err := NewSignerFromFile(serverCertFile, serverCertFile, serverKeyFile, dur) if err != nil { t.Fatalf("Signer creation failed: %v", err) } // default case n := time.Now().UTC().Truncate(time.Hour) respBytes, err := s.Sign(req) if err != nil { t.Fatalf("Error signing default request: %s", err) } resp, err := ocsp.ParseResponse(respBytes, nil) if err != nil { t.Fatalf("Error parsing response: %s", err) } if !resp.ThisUpdate.Equal(n) { t.Fatalf("Unexpected ThisUpdate: wanted %s, got %s", n, resp.ThisUpdate) } if !resp.NextUpdate.Equal(n.Add(dur)) { t.Fatalf("Unexpected NextUpdate: wanted %s, got %s", n.Add(dur), resp.NextUpdate) } // custom case, ThisUpdate only this := time.Now().UTC().Add(-time.Hour * 5).Truncate(time.Hour) req.ThisUpdate = &this respBytes, err = s.Sign(req) if err != nil { t.Fatalf("Error signing default request: %s", err) } resp, err = ocsp.ParseResponse(respBytes, nil) if err != nil { t.Fatalf("Error parsing response: %s", err) } if !resp.ThisUpdate.Equal(this) { t.Fatalf("Unexpected ThisUpdate: wanted %s, got %s", this, resp.ThisUpdate) } if !resp.NextUpdate.Equal(this.Add(dur)) { t.Fatalf("Unexpected NextUpdate: wanted %s, got %s", this.Add(dur), resp.NextUpdate) } // custom case, ThisUpdate and NextUpdate next := this.Add(time.Hour * 2) req.NextUpdate = &next respBytes, err = s.Sign(req) if err != nil { t.Fatalf("Error signing default request: %s", err) } resp, err = ocsp.ParseResponse(respBytes, nil) if err != nil { t.Fatalf("Error parsing response: %s", err) } if !resp.ThisUpdate.Equal(this) { t.Fatalf("Unexpected ThisUpdate: wanted %s, got %s", this, resp.ThisUpdate) } if !resp.NextUpdate.Equal(next) { t.Fatalf("Unexpected NextUpdate: wanted %s, got %s", next, resp.NextUpdate) } } ================================================ FILE: ocsp/responder.go ================================================ // Package ocsp implements an OCSP responder based on a generic storage backend. // It provides a couple of sample implementations. // Because OCSP responders handle high query volumes, we have to be careful // about how much logging we do. Error-level logs are reserved for problems // internal to the server, that can be fixed by an administrator. Any type of // incorrect input from a user should be logged and Info or below. For things // that are logged on every request, Debug is the appropriate level. package ocsp import ( "crypto" "crypto/sha256" "encoding/base64" "encoding/hex" "encoding/json" "errors" "fmt" "io" "net/http" "net/url" "os" "regexp" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/dbconf" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/log" "github.com/jmhodges/clock" "golang.org/x/crypto/ocsp" ) var ( malformedRequestErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x01} internalErrorErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x02} tryLaterErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x03} sigRequredErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x05} unauthorizedErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x06} // ErrNotFound indicates the request OCSP response was not found. It is used to // indicate that the responder should reply with unauthorizedErrorResponse. ErrNotFound = errors.New("Request OCSP Response not found") ) // Source represents the logical source of OCSP responses, i.e., // the logic that actually chooses a response based on a request. In // order to create an actual responder, wrap one of these in a Responder // object and pass it to http.Handle. By default the Responder will set // the headers Cache-Control to "max-age=(response.NextUpdate-now), public, no-transform, must-revalidate", // Last-Modified to response.ThisUpdate, Expires to response.NextUpdate, // ETag to the SHA256 hash of the response, and Content-Type to // application/ocsp-response. If you want to override these headers, // or set extra headers, your source should return a http.Header // with the headers you wish to set. If you don't want to set any // extra headers you may return nil instead. type Source interface { Response(*ocsp.Request) ([]byte, http.Header, error) } // An InMemorySource is a map from serialNumber -> der(response) type InMemorySource map[string][]byte // Response looks up an OCSP response to provide for a given request. // InMemorySource looks up a response purely based on serial number, // without regard to what issuer the request is asking for. func (src InMemorySource) Response(request *ocsp.Request) ([]byte, http.Header, error) { response, present := src[request.SerialNumber.String()] if !present { return nil, nil, ErrNotFound } return response, nil, nil } // DBSource represnts a source of OCSP responses backed by the certdb package. type DBSource struct { Accessor certdb.Accessor } // NewDBSource creates a new DBSource type with an associated dbAccessor. func NewDBSource(dbAccessor certdb.Accessor) Source { return DBSource{ Accessor: dbAccessor, } } // Response implements cfssl.ocsp.responder.Source, which returns the // OCSP response in the Database for the given request with the expiration // date furthest in the future. func (src DBSource) Response(req *ocsp.Request) ([]byte, http.Header, error) { if req == nil { return nil, nil, errors.New("called with nil request") } aki := hex.EncodeToString(req.IssuerKeyHash) sn := req.SerialNumber if sn == nil { return nil, nil, errors.New("request contains no serial") } strSN := sn.String() if src.Accessor == nil { log.Errorf("No DB Accessor") return nil, nil, errors.New("called with nil DB accessor") } records, err := src.Accessor.GetOCSP(strSN, aki) // Response() logs when there are errors obtaining the OCSP response // and returns nil, false. if err != nil { log.Errorf("Error obtaining OCSP response: %s", err) return nil, nil, fmt.Errorf("failed to obtain OCSP response: %s", err) } if len(records) == 0 { return nil, nil, ErrNotFound } // Response() finds the OCSPRecord with the expiration date furthest in the future. cur := records[0] for _, rec := range records { if rec.Expiry.After(cur.Expiry) { cur = rec } } return []byte(cur.Body), nil, nil } // NewSourceFromFile reads the named file into an InMemorySource. // The file read by this function must contain whitespace-separated OCSP // responses. Each OCSP response must be in base64-encoded DER form (i.e., // PEM without headers or whitespace). Invalid responses are ignored. // This function pulls the entire file into an InMemorySource. func NewSourceFromFile(responseFile string) (Source, error) { fileContents, err := os.ReadFile(responseFile) if err != nil { return nil, err } responsesB64 := regexp.MustCompile("\\s").Split(string(fileContents), -1) src := InMemorySource{} for _, b64 := range responsesB64 { // if the line/space is empty just skip if b64 == "" { continue } der, tmpErr := base64.StdEncoding.DecodeString(b64) if tmpErr != nil { log.Errorf("Base64 decode error %s on: %s", tmpErr, b64) continue } response, tmpErr := ocsp.ParseResponse(der, nil) if tmpErr != nil { log.Errorf("OCSP decode error %s on: %s", tmpErr, b64) continue } src[response.SerialNumber.String()] = der } log.Infof("Read %d OCSP responses", len(src)) return src, nil } // NewSourceFromDB reads the given database configuration file // and creates a database data source for use with the OCSP responder func NewSourceFromDB(DBConfigFile string) (Source, error) { // Load DB from cofiguration file db, err := dbconf.DBFromConfig(DBConfigFile) if err != nil { return nil, err } // Create accesor accessor := sql.NewAccessor(db) src := NewDBSource(accessor) return src, nil } // Stats is a basic interface that allows users to record information // about returned responses type Stats interface { ResponseStatus(ocsp.ResponseStatus) } // A Responder object provides the HTTP logic to expose a // Source of OCSP responses. type Responder struct { Source Source stats Stats clk clock.Clock } // NewResponder instantiates a Responder with the give Source. func NewResponder(source Source, stats Stats) *Responder { return &Responder{ Source: source, stats: stats, clk: clock.New(), } } func overrideHeaders(response http.ResponseWriter, headers http.Header) { for k, v := range headers { if len(v) == 1 { response.Header().Set(k, v[0]) } else if len(v) > 1 { response.Header().Del(k) for _, e := range v { response.Header().Add(k, e) } } } } type logEvent struct { IP string `json:"ip,omitempty"` UA string `json:"ua,omitempty"` Method string `json:"method,omitempty"` Path string `json:"path,omitempty"` Body string `json:"body,omitempty"` Received time.Time `json:"received,omitempty"` Took time.Duration `json:"took,omitempty"` Headers http.Header `json:"headers,omitempty"` Serial string `json:"serial,omitempty"` IssuerKeyHash string `json:"issuerKeyHash,omitempty"` IssuerNameHash string `json:"issuerNameHash,omitempty"` HashAlg string `json:"hashAlg,omitempty"` } // hashToString contains mappings for the only hash functions // x/crypto/ocsp supports var hashToString = map[crypto.Hash]string{ crypto.SHA1: "SHA1", crypto.SHA256: "SHA256", crypto.SHA384: "SHA384", crypto.SHA512: "SHA512", } // A Responder can process both GET and POST requests. The mapping // from an OCSP request to an OCSP response is done by the Source; // the Responder simply decodes the request, and passes back whatever // response is provided by the source. // Note: The caller must use http.StripPrefix to strip any path components // (including '/') on GET requests. // Do not use this responder in conjunction with http.NewServeMux, because the // default handler will try to canonicalize path components by changing any // strings of repeated '/' into a single '/', which will break the base64 // encoding. func (rs Responder) ServeHTTP(response http.ResponseWriter, request *http.Request) { le := logEvent{ IP: request.RemoteAddr, UA: request.UserAgent(), Method: request.Method, Path: request.URL.Path, Received: time.Now(), } defer func() { le.Headers = response.Header() le.Took = time.Since(le.Received) jb, err := json.Marshal(le) if err != nil { // we log this error at the debug level as if we aren't at that level anyway // we shouldn't really care about marshalling the log event object log.Debugf("failed to marshal log event object: %s", err) return } log.Debugf("Received request: %s", string(jb)) }() // By default we set a 'max-age=0, no-cache' Cache-Control header, this // is only returned to the client if a valid authorized OCSP response // is not found or an error is returned. If a response if found the header // will be altered to contain the proper max-age and modifiers. response.Header().Add("Cache-Control", "max-age=0, no-cache") // Read response from request var requestBody []byte var err error switch request.Method { case "GET": base64Request, err := url.QueryUnescape(request.URL.Path) if err != nil { log.Debugf("Error decoding URL: %s", request.URL.Path) response.WriteHeader(http.StatusBadRequest) return } // url.QueryUnescape not only unescapes %2B escaping, but it additionally // turns the resulting '+' into a space, which makes base64 decoding fail. // So we go back afterwards and turn ' ' back into '+'. This means we // accept some malformed input that includes ' ' or %20, but that's fine. base64RequestBytes := []byte(base64Request) for i := range base64RequestBytes { if base64RequestBytes[i] == ' ' { base64RequestBytes[i] = '+' } } // In certain situations a UA may construct a request that has a double // slash between the host name and the base64 request body due to naively // constructing the request URL. In that case strip the leading slash // so that we can still decode the request. if len(base64RequestBytes) > 0 && base64RequestBytes[0] == '/' { base64RequestBytes = base64RequestBytes[1:] } requestBody, err = base64.StdEncoding.DecodeString(string(base64RequestBytes)) if err != nil { log.Debugf("Error decoding base64 from URL: %s", string(base64RequestBytes)) response.WriteHeader(http.StatusBadRequest) return } case "POST": requestBody, err = io.ReadAll(request.Body) if err != nil { log.Errorf("Problem reading body of POST: %s", err) response.WriteHeader(http.StatusBadRequest) return } default: response.WriteHeader(http.StatusMethodNotAllowed) return } b64Body := base64.StdEncoding.EncodeToString(requestBody) log.Debugf("Received OCSP request: %s", b64Body) if request.Method == http.MethodPost { le.Body = b64Body } // All responses after this point will be OCSP. // We could check for the content type of the request, but that // seems unnecessariliy restrictive. response.Header().Add("Content-Type", "application/ocsp-response") // Parse response as an OCSP request // XXX: This fails if the request contains the nonce extension. // We don't intend to support nonces anyway, but maybe we // should return unauthorizedRequest instead of malformed. ocspRequest, err := ocsp.ParseRequest(requestBody) if err != nil { log.Debugf("Error decoding request body: %s", b64Body) response.WriteHeader(http.StatusBadRequest) response.Write(malformedRequestErrorResponse) if rs.stats != nil { rs.stats.ResponseStatus(ocsp.Malformed) } return } le.Serial = fmt.Sprintf("%x", ocspRequest.SerialNumber.Bytes()) le.IssuerKeyHash = fmt.Sprintf("%x", ocspRequest.IssuerKeyHash) le.IssuerNameHash = fmt.Sprintf("%x", ocspRequest.IssuerNameHash) le.HashAlg = hashToString[ocspRequest.HashAlgorithm] // Look up OCSP response from source ocspResponse, headers, err := rs.Source.Response(ocspRequest) if err != nil { if err == ErrNotFound { log.Infof("No response found for request: serial %x, request body %s", ocspRequest.SerialNumber, b64Body) response.Write(unauthorizedErrorResponse) if rs.stats != nil { rs.stats.ResponseStatus(ocsp.Unauthorized) } return } log.Infof("Error retrieving response for request: serial %x, request body %s, error: %s", ocspRequest.SerialNumber, b64Body, err) response.WriteHeader(http.StatusInternalServerError) response.Write(internalErrorErrorResponse) if rs.stats != nil { rs.stats.ResponseStatus(ocsp.InternalError) } return } parsedResponse, err := ocsp.ParseResponse(ocspResponse, nil) if err != nil { log.Errorf("Error parsing response for serial %x: %s", ocspRequest.SerialNumber, err) response.Write(internalErrorErrorResponse) if rs.stats != nil { rs.stats.ResponseStatus(ocsp.InternalError) } return } // Write OCSP response to response response.Header().Add("Last-Modified", parsedResponse.ThisUpdate.Format(time.RFC1123)) response.Header().Add("Expires", parsedResponse.NextUpdate.Format(time.RFC1123)) now := rs.clk.Now() maxAge := 0 if now.Before(parsedResponse.NextUpdate) { maxAge = int(parsedResponse.NextUpdate.Sub(now) / time.Second) } else { // TODO(#530): we want max-age=0 but this is technically an authorized OCSP response // (despite being stale) and 5019 forbids attaching no-cache maxAge = 0 } response.Header().Set( "Cache-Control", fmt.Sprintf( "max-age=%d, public, no-transform, must-revalidate", maxAge, ), ) responseHash := sha256.Sum256(ocspResponse) response.Header().Add("ETag", fmt.Sprintf("\"%X\"", responseHash)) if headers != nil { overrideHeaders(response, headers) } // RFC 7232 says that a 304 response must contain the above // headers if they would also be sent for a 200 for the same // request, so we have to wait until here to do this if etag := request.Header.Get("If-None-Match"); etag != "" { if etag == fmt.Sprintf("\"%X\"", responseHash) { response.WriteHeader(http.StatusNotModified) return } } response.WriteHeader(http.StatusOK) response.Write(ocspResponse) if rs.stats != nil { rs.stats.ResponseStatus(ocsp.Success) } } ================================================ FILE: ocsp/responder_test.go ================================================ package ocsp import ( "encoding/hex" "net/http" "net/http/httptest" "net/url" "os" "reflect" "testing" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/certdb/sql" "github.com/cloudflare/cfssl/certdb/testdb" "github.com/cloudflare/cfssl/helpers" "github.com/jmhodges/clock" goocsp "golang.org/x/crypto/ocsp" ) const ( responseFile = "testdata/resp64.pem" binResponseFile = "testdata/response.der" brokenResponseFile = "testdata/response_broken.pem" mixResponseFile = "testdata/response_mix.pem" ) type testSource struct{} func (ts testSource) Response(r *goocsp.Request) ([]byte, http.Header, error) { return []byte("hi"), nil, nil } type testCase struct { method, path string expected int } func TestOCSP(t *testing.T) { cases := []testCase{ {"OPTIONS", "/", http.StatusMethodNotAllowed}, {"GET", "/", http.StatusBadRequest}, // Bad URL encoding {"GET", "%ZZFQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusBadRequest}, // Bad URL encoding {"GET", "%%FQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusBadRequest}, // Bad base64 encoding {"GET", "==MFQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusBadRequest}, // Bad OCSP DER encoding {"GET", "AAAMFQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusBadRequest}, // Good encoding all around, including a double slash {"GET", "MFQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusOK}, // Good request, leading slash {"GET", "/MFQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D", http.StatusOK}, } responder := Responder{ Source: testSource{}, clk: clock.NewFake(), } for _, tc := range cases { rw := httptest.NewRecorder() responder.ServeHTTP(rw, &http.Request{ Method: tc.method, URL: &url.URL{ Path: tc.path, }, }) if rw.Code != tc.expected { t.Errorf("Incorrect response code: got %d, wanted %d", rw.Code, tc.expected) } } } var testResp = `308204f90a0100a08204f2308204ee06092b0601050507300101048204df308204db3081a7a003020100a121301f311d301b06035504030c146861707079206861636b65722066616b65204341180f32303135303932333231303630305a306c306a3042300906052b0e03021a0500041439e45eb0e3a861c7fa3a3973876be61f7b7d98860414fb784f12f96015832c9f177f3419b32e36ea41890209009cf1912ea8d509088000180f32303135303932333030303030305aa011180f32303330303832363030303030305a300d06092a864886f70d01010b05000382010100c17ed5f12c408d214092c86cb2d6ba9881637a9d5cafb8ddc05aed85806a554c37abdd83c2e00a4bb25b2d0dda1e1c0be65144377471bca53f14616f379ee0c0b436c697b400b7eba9513c5be6d92fbc817586d568156293cfa0099d64585146def907dee36eb650c424a00207b01813aa7ae90e65045339482eeef12b6fa8656315da8f8bb1375caa29ac3858f891adb85066c35b5176e154726ae746016e42e0d6016668ff10a8aa9637417d29be387a1bdba9268b13558034ab5f3e498a47fb096f2e1b39236b22956545884fbbed1884f1bc9686b834d8def4802bac8f79924a36867af87412f808977abaf6457f3cda9e7eccbd0731bcd04865b899ee41a08203193082031530820311308201f9a0030201020209009cf1912ea8d50908300d06092a864886f70d01010b0500301f311d301b06035504030c146861707079206861636b65722066616b65204341301e170d3135303430373233353033385a170d3235303430343233353033385a301f311d301b06035504030c146861707079206861636b65722066616b6520434130820122300d06092a864886f70d01010105000382010f003082010a0282010100c20a47799a05c512b27717633413d770f936bf99de62f130c8774d476deac0029aa6c9d1bb519605df32d34b336394d48e9adc9bbeb48652767dafdb5241c2fc54ce9650e33cb672298888c403642407270cc2f46667f07696d3dd62cfd1f41a8dc0ed60d7c18366b1d2cd462d34a35e148e8695a9a3ec62b656bd129a211a9a534847992d005b0412bcdffdde23085eeca2c32c2693029b5a79f1090fe0b1cb4a154b5c36bc04c7d5a08fa2a58700d3c88d5059205bc5560dc9480f1732b1ad29b030ed3235f7fb868f904fdc79f98ffb5c4e7d4b831ce195f171729ec3f81294df54e66bd3f83d81843b640aea5d7ec64d0905a9dbb03e6ff0e6ac523d36ab0203010001a350304e301d0603551d0e04160414fb784f12f96015832c9f177f3419b32e36ea4189301f0603551d23041830168014fb784f12f96015832c9f177f3419b32e36ea4189300c0603551d13040530030101ff300d06092a864886f70d01010b050003820101001df436be66ff938ccbfb353026962aa758763a777531119377845109e7c2105476c165565d5bbce1464b41bd1d392b079a7341c978af754ca9b3bd7976d485cbbe1d2070d2d4feec1e0f79e8fec9df741e0ea05a26a658d3866825cc1aa2a96a0a04942b2c203cc39501f917a899161dfc461717fe9301fce6ea1afffd7b7998f8941cf76f62def994c028bd1c4b49b17c4d243a6fb058c484968cf80501234da89347108b56b2640cb408e3c336fd72cd355c7f690a15405a7f4ba1e30a6be4a51d262b586f77f8472b207fdd194efab8d3a2683cc148abda7a11b9de1db9307b8ed5a9cd20226f668bd6ac5a3852fd449e42899b7bc915ee747891a110a971` type testHeaderSource struct { headers http.Header } func (ts testHeaderSource) Response(r *goocsp.Request) ([]byte, http.Header, error) { resp, _ := hex.DecodeString(testResp) return resp, ts.headers, nil } func TestOverrideHeaders(t *testing.T) { headers := http.Header(map[string][]string{ "Content-Type": {"yup"}, "Cache-Control": {"nope"}, "New": {"header"}, "Expires": {"0"}, "Last-Modified": {"now"}, "Etag": {"mhm"}, }) responder := Responder{ Source: testHeaderSource{headers: headers}, clk: clock.NewFake(), } rw := httptest.NewRecorder() responder.ServeHTTP(rw, &http.Request{ Method: "GET", URL: &url.URL{Path: "MFQwUjBQME4wTDAJBgUrDgMCGgUABBQ55F6w46hhx%2Fo6OXOHa%2BYfe32YhgQU%2B3hPEvlgFYMsnxd%2FNBmzLjbqQYkCEwD6Wh0MaVKu9gJ3By9DI%2F%2Fxsd4%3D"}, }) if !reflect.DeepEqual(rw.Header(), headers) { t.Fatalf("Unexpected Headers returned: wanted %s, got %s", headers, rw.Header()) } } func TestCacheHeaders(t *testing.T) { source, err := NewSourceFromFile(responseFile) if err != nil { t.Fatalf("Error constructing source: %s", err) } fc := clock.NewFake() fc.Set(time.Date(2015, 11, 12, 0, 0, 0, 0, time.UTC)) responder := Responder{ Source: source, clk: fc, } rw := httptest.NewRecorder() responder.ServeHTTP(rw, &http.Request{ Method: "GET", URL: &url.URL{ Path: "MEMwQTA/MD0wOzAJBgUrDgMCGgUABBSwLsMRhyg1dJUwnXWk++D57lvgagQU6aQ/7p6l5vLV13lgPJOmLiSOl6oCAhJN", }, }) if rw.Code != http.StatusOK { t.Errorf("Unexpected HTTP status code %d", rw.Code) } testCases := []struct { header string value string }{ {"Last-Modified", "Tue, 20 Oct 2015 00:00:00 UTC"}, {"Expires", "Sun, 20 Oct 2030 00:00:00 UTC"}, {"Cache-Control", "max-age=471398400, public, no-transform, must-revalidate"}, {"Etag", "\"8169FB0843B081A76E9F6F13FD70C8411597BEACF8B182136FFDD19FBD26140A\""}, } for _, tc := range testCases { headers, ok := rw.HeaderMap[tc.header] if !ok { t.Errorf("Header %s missing from HTTP response", tc.header) continue } if len(headers) != 1 { t.Errorf("Wrong number of headers in HTTP response. Wanted 1, got %d", len(headers)) continue } actual := headers[0] if actual != tc.value { t.Errorf("Got header %s: %s. Expected %s", tc.header, actual, tc.value) } } rw = httptest.NewRecorder() headers := http.Header{} headers.Add("If-None-Match", "\"8169FB0843B081A76E9F6F13FD70C8411597BEACF8B182136FFDD19FBD26140A\"") responder.ServeHTTP(rw, &http.Request{ Method: "GET", URL: &url.URL{ Path: "MEMwQTA/MD0wOzAJBgUrDgMCGgUABBSwLsMRhyg1dJUwnXWk++D57lvgagQU6aQ/7p6l5vLV13lgPJOmLiSOl6oCAhJN", }, Header: headers, }) if rw.Code != http.StatusNotModified { t.Fatalf("Got wrong status code: expected %d, got %d", http.StatusNotModified, rw.Code) } } func TestNewSourceFromFile(t *testing.T) { _, err := NewSourceFromFile("") if err == nil { t.Fatal("Didn't fail on non-file input") } // expected case _, err = NewSourceFromFile(responseFile) if err != nil { t.Fatal(err) } // binary-formatted file _, err = NewSourceFromFile(binResponseFile) if err != nil { t.Fatal(err) } // the response file from before, with stuff deleted _, err = NewSourceFromFile(brokenResponseFile) if err != nil { t.Fatal(err) } // mix of a correct and malformed responses _, err = NewSourceFromFile(mixResponseFile) if err != nil { t.Fatal(err) } } func TestSqliteTrivial(t *testing.T) { // First, read and parse certificate and issuer files needed to make // an OCSP request. certFile := "testdata/sqlite_ca.pem" issuerFile := "testdata/ca.pem" certContent, err := os.ReadFile(certFile) if err != nil { t.Errorf("Error reading cert file: %s", err) } issuerContent, err := os.ReadFile(issuerFile) if err != nil { t.Errorf("Error reading issuer file: %s", err) } cert, err := helpers.ParseCertificatePEM(certContent) if err != nil { t.Errorf("Error parsing cert file: %s", err) } issuer, err := helpers.ParseCertificatePEM(issuerContent) if err != nil { t.Errorf("Error parsing cert file: %s", err) } // Next, create the OCSP request. reqByte, err := goocsp.CreateRequest(cert, issuer, nil) if err != nil { t.Errorf("Error creating OCSP request: %s", err) } req, err := goocsp.ParseRequest(reqByte) if err != nil { t.Errorf("Error parsing OCSP request: %s", err) } sqliteDBfile := "testdata/sqlite_test.db" db := testdb.SQLiteDB(sqliteDBfile) accessor := sql.NewAccessor(db) // Populate the DB with the OCSPRecord, and check // that Response() handles the request appropiately. ocsp := certdb.OCSPRecord{ AKI: hex.EncodeToString(req.IssuerKeyHash), Body: "Test OCSP", Expiry: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), Serial: req.SerialNumber.String(), } err = accessor.InsertOCSP(ocsp) if err != nil { t.Errorf("Error inserting OCSP record into DB: %s", err) } // Use the created Accessor to create a new DBSource. src := NewDBSource(accessor) // Call Response() method on constructed request and check the output. response, _, err := src.Response(req) if err != nil { t.Error(err) } if string(response) != "Test OCSP" { t.Error("Incorrect response received from Sqlite DB") } } func TestSqliteRealResponse(t *testing.T) { sqliteDBfile := "testdata/sqlite_test.db" db := testdb.SQLiteDB(sqliteDBfile) accessor := sql.NewAccessor(db) certFile := "testdata/cert.pem" issuerFile := "testdata/ca.pem" certContent, err := os.ReadFile(certFile) if err != nil { t.Errorf("Error reading cert file: %s", err) } issuerContent, err := os.ReadFile(issuerFile) if err != nil { t.Errorf("Error reading issuer file: %s", err) } cert, err := helpers.ParseCertificatePEM(certContent) if err != nil { t.Errorf("Error parsing cert file: %s", err) } issuer, err := helpers.ParseCertificatePEM(issuerContent) if err != nil { t.Errorf("Error parsing cert file: %s", err) } // Create an OCSP request. reqByte, err := goocsp.CreateRequest(cert, issuer, nil) if err != nil { t.Errorf("Error creating OCSP request: %s", err) } req, err := goocsp.ParseRequest(reqByte) if err != nil { t.Errorf("Error parsing OCSP request: %s", err) } // Create the template to be used in making an OCSP response. template := goocsp.Response{ Status: goocsp.Good, SerialNumber: req.SerialNumber, ThisUpdate: time.Now(), NextUpdate: time.Now().AddDate(0, 1, 0), } keyPEM, err := os.ReadFile("testdata/ca-key.pem") if err != nil { t.Errorf("Error reading private key file: %s", err) } priv, err := helpers.ParsePrivateKeyPEM(keyPEM) if err != nil { t.Errorf("Error parsing private key: %s", err) } // Create an OCSP response to be inserted into the DB. response, err := goocsp.CreateResponse(issuer, cert, template, priv) if err != nil { t.Errorf("Error creating OCSP response: %s", err) } // Create record for the OCSP response and add the record to the DB. ocsp := certdb.OCSPRecord{ AKI: hex.EncodeToString(req.IssuerKeyHash), Body: string(response), Expiry: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), Serial: req.SerialNumber.String(), } err = accessor.InsertOCSP(ocsp) if err != nil { t.Errorf("Error inserting OCSP record into DB: %s", err) } // Use the created Accessor to create new DBSource. src := NewDBSource(accessor) // Call Response() method on constructed request and check the output. response, _, err = src.Response(req) if err != nil { t.Error(err) } // Attempt to parse the returned response and make sure it is well formed. _, err = goocsp.ParseResponse(response, issuer) if err != nil { t.Errorf("Error parsing response: %v", err) } // Manually run the query "SELECT max(version_id) FROM goose_db_version;" // on testdata/sqlite_test.db after running this test to verify that the // DB was properly connected to. } func TestNewSqliteSource(t *testing.T) { dbpath := "testdata/db-config.json" _, err := NewSourceFromDB(dbpath) if err != nil { t.Errorf("Error connecting to Sqlite DB: %v", err) } } ================================================ FILE: ocsp/testdata/ca-key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAvKOCXwP8Y6x1YkjcimQafnP1bRCF/iWY+z4ffuTWA150RRpA GnhwOen8muU5wxOEm1A2IkWhNfXQ9GYVdOnzXumTx9Go4Gm8/1nRCYG69GZbQAEr pNGx/l4wReLVj2iizCf/xkcch5ZM/5zplXWZXCQiavmKz6M+1aSYdsGP0mrLu31c yod2iJmlISt+nuP5yXkgoKxzGrKjP5qrs6XniVXrKMt+5g1Ta5blWUoft2pwM6yp 8+IAtxh+iYTIJc8dDHbVl9AjVfsfaYeS8SkHcIRyIuD8/3HgLmP/gMLDzuLXvH+W slOEYqLGMkSo2JPOwLguggDyjt1rI2cEcFkgJwIDAQABAoIBAQCTAZW6+D87ag28 f22nR+XBwBp2WVcivSggO8SNvkXuMDDKHW/xcQR8jZW3HIZMOSyxYOwe/0Zn595k aB22lA9+Wuc45HIIGT8ZfGREVV5d0lqwYXkio+xjgAF8pQ6rCO89zLouSgK4w2/U D/OU7yWJwfs0hK4hrGVuVywd+DBd2Fc7UfZ4oEcy89mwUIRVK8+eXrRCav6lGDrz I+GmW6GL16U8lS8vsUNciYyNYCzgSIIa/yyiZO/Aje93yJRVpmujAK2p6/w/7vmK OareeixlpNYpiY7Nk6o3w6sKEEVzf+AquDgeH5IkzD1nkYbd+JY7bdg1cgjz3kJg IhsiIER5AoGBAOkZpicTIsiAMxz43bzMt1IMYu1ezAEw4Vk2sVEbSfFXdbO5J9gW /Ou+AhwxhsDeO6vgh3mYkG+2s5U+ztk68X1BVIf87kYBQiz175XvxcLmDBFm5S6g eyTCwsop9J4XlgQQ5HNm80G9oHnF50oujCqpUiC5xj5fEd8vULmua5jTAoGBAM8r rTTpVBHKArDlzYF5EpyXDkcFT2uAgw9Xpc6xIl/UWQ+XU1qD5Te0fmjpdwo3VZTL W2e8eg0U9O2skrxBcRLREnh1U2znCMSIGTkwYQ2JDjhz2Jjbh8r/NhvSdydql9wQ LGyPOIpcURaD+ohOExF82EtEqWgNp4QfQHH70cbdAoGAPBoy7yxN8aishTHd6opW Uj+DWnTw4PW7hQdHHQSOQj4syRRao6r5t8ccQCy89AnZFO4lwEKIK2XOVBMHvpcm IQexRgb/YOl+KJ2ZEu3p7eDnB62iNi2G0ums0/eRbRnjwlSgsui+nBrKv9s5UbVC ytUxqeJ8rSRSNVu70sSYVaUCgYALYUrSbT7A+2fKb9UqF4x+LY4LOK90KEsKvLXO 9Mv+l5uMz7M0dapRtQh8mtZ/KSr6UXFj8WaC8XPC2of072NWtUVeeJNsmARTR2ab TZ0HMVAmqbZsLyL2c651OMpyz9gnrnvCOtvQPeH2aqmIc0F45HK9L7hejuF00IKp wDt1wQKBgQC8sjlF/8e03m3AfLs2ZW/w0Rsggz52TgBdH24BMUmvd5McVZlH8uZq zwx5ht3ppVjObG28JPEj8c/FtAmsUjURDD7EVdjb5bDxrMtH++8sHrXUuMMBeUxl DN2IU+xL9MwMh5H0cyJbXnE+LWGpSefCccDnH5qlEjwNXE5/RggOrw== -----END RSA PRIVATE KEY----- ================================================ FILE: ocsp/testdata/ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIDvjCCAqigAwIBAgIIWhorb65IXvUwCwYJKoZIhvcNAQELMG0xCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMB4XDTE1MDQxOTE2MTAwMFoXDTIwMDQxNzE2MTAwMFowbTELMAkGA1UEBhMC VVMxEzARBgNVBAoTCkNsb3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5l ZXJpbmcxFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3Ju aWEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8o4JfA/xjrHViSNyK ZBp+c/VtEIX+JZj7Ph9+5NYDXnRFGkAaeHA56fya5TnDE4SbUDYiRaE19dD0ZhV0 6fNe6ZPH0ajgabz/WdEJgbr0ZltAASuk0bH+XjBF4tWPaKLMJ//GRxyHlkz/nOmV dZlcJCJq+YrPoz7VpJh2wY/Sasu7fVzKh3aImaUhK36e4/nJeSCgrHMasqM/mquz peeJVesoy37mDVNrluVZSh+3anAzrKnz4gC3GH6JhMglzx0MdtWX0CNV+x9ph5Lx KQdwhHIi4Pz/ceAuY/+AwsPO4te8f5ayU4RiosYyRKjYk87AuC6CAPKO3WsjZwRw WSAnAgMBAAGjZjBkMA4GA1UdDwEB/wQEAwIABjASBgNVHRMBAf8ECDAGAQH/AgEC MB0GA1UdDgQWBBSrzjPP4Y5PLsqeyp6iddofBjoRmTAfBgNVHSMEGDAWgBSrzjPP 4Y5PLsqeyp6iddofBjoRmTALBgkqhkiG9w0BAQsDggEBAH7McpSm7+DeIZPQKYpF kFUlNn3N4MRvek5lxOw6jLE1QmzG3lTB79g6iBiGKsYLPoJqNS6VxMoLrMC+qFhM 0QM5eIzRpdfYa83IDIYcbUYx7fLG/azX+FMFh/O5yPtS+bqbxGinxofRIyuKGs9r dks6I5lGncRs0Liysp4mHJAjyj9G2W2onI3Y00BYhiOy4mYvZ5/S31KI4550HZ+p dnexuC29CsWGkOTXTOS7+e7Zmbh8UjsYcA5YOojew+EjJfETPVO+Pn7WGg/+XrFX 8UOG3o9k8M0ePQof4R6FTJ+BQxtSkWWdp1HrMQbZ1TXfZx84XkmFdcmy8FjYiHbP M+M= -----END CERTIFICATE----- ================================================ FILE: ocsp/testdata/cert.pem ================================================ -----BEGIN CERTIFICATE----- MIID4TCCAsugAwIBAgIIEoDcqfKl/s4wCwYJKoZIhvcNAQELMG0xCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMB4XDTE1MDQxOTE2MTkwMFoXDTE2MDQxODE2MTkwMFowXTELMAkGA1UEBhMC VVMxEDAOBgNVBAoTB0V4YW1wbGUxDzANBgNVBAsTBlRoaW5nczEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAK7jUnRUeD5QY9YPjbW6aiGkVWRWAebi4nZl++C+ HEBHSyB0jXX+J93y97PuhgeguCuMM6KZU7C0tPZKjwdxBSqpXeyFpvcj+UWMjZjz 9FrBAzZ1DIYquqfYuKUtavoFv29IomRqzyZ4FrMJ2qy0RudnWMTqn4P6/7DrWos+ oJMCpl/mdWl+YXMXypgW5JwM7ladx8GkEKQwGMtXrG9pop7qS6LNikN76tLPYWjR DhrWLBe8gCGjuXkwvxw78CeeJNyWF+P/+x4lVsWphip3jX57SUx/bjaRjsWSfpMz xHueHtuCrGffgCkFzYH1/Z60FZNxuHYqJeL4V3gcR8IIaZECAwEAAaOBmDCBlTAO BgNVHQ8BAf8EBAMCAKAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG A1UdEwEB/wQCMAAwHQYDVR0OBBYEFBnFrxc1gkG2CYImTYKL0DAaGxRBMB8GA1Ud IwQYMBaAFKvOM8/hjk8uyp7KnqJ12h8GOhGZMBYGA1UdEQQPMA2CC2V4YW1wbGUu Y29tMAsGCSqGSIb3DQEBCwOCAQEAX31Jk7R9gDMw/gepIxxeKx9m+c7eOYDxjJ12 bfXQVKNNPLZsO9M9r2/0BCTFsNTF2jh6ZTeIf7qy+Jw08YqTcO5m8jhiGzCjOYu5 tiGxCUe+cYjXcCRk83+XGkVrQm3fQ0cVtic0yfm/fez3iv915jH0GYO5X8/d7bKa 0kWJ3uOjur6tenfnisypEsuYYjPRcQdXSG6/qgHEc4r279Z2ltjy1bFFr86hHUbj DX7XNWH/MXFgqLzfQm5VzmqBj9om+0/tgTWdkgI1DK/Hnvm9A4YZfaxh4fxv7ITo Ce8FWW13Wj55x64peb8ZiW1jUyoaJQcxQxFpRHIVu26nXApWtg== -----END CERTIFICATE----- ================================================ FILE: ocsp/testdata/db-config.json ================================================ {"driver":"sqlite3","data_source":"sqlite_test.db"} ================================================ FILE: ocsp/testdata/resp64.pem ================================================ MIIFCAoBAKCCBQEwggT9BgkrBgEFBQcwAQEEggTuMIIE6jCBrKADAgEAoS0wKzEpMCcGA1UEAwwgY2Fja2xpbmcgY3J5cHRvZ3JhcGhlciBmYWtlIFJPT1QYDzIwMTUxMDIxMjEyNjAwWjBlMGMwOzAJBgUrDgMCGgUABBSwLsMRhyg1dJUwnXWk++D57lvgagQU6aQ/7p6l5vLV13lgPJOmLiSOl6oCAhJNgAAYDzIwMTUwOTAxMDAwMDAwWqARGA8yMDE0MDEwMTAwMDAwMFowDQYJKoZIhvcNAQELBQADggEBAHlFcNKa7mZDJeWzJt1S45kx4gDqOLzyeZzflFbSjsrHRrLA7Y3RKoy0i4Y9Vi6Jfhe7xj6dgDMJy1Z1qayI/Q8QvnaU6V2kFcnaD7pah9uALu2xNYMJPllq8KsQYvDLa1E2PMvQTqDhY2/QrIuxw3jkqtzeI5aG0idFm3aF1z/v3dt6XPWjE8IlAJfXY4CeUorLvA+mK2YHJ3V7MSgymVXZdyth1rg0/0cP9v77Rlb8hmWA/EUMcIPKQqErVQK+gZiVC0SfElaMO25CD9cjY+fd904oC5+ahvhHXxOSEbXVZBT1FY2teFCKEpx86gAVcZWpGmVwJO+dpsrkgwpN786gggMjMIIDHzCCAxswggIDoAMCAQICCQDNMc/iNkPNdTANBgkqhkiG9w0BAQsFADArMSkwJwYDVQQDDCBjYWNrbGluZyBjcnlwdG9ncmFwaGVyIGZha2UgUk9PVDAeFw0xNTEwMjEyMDExNTJaFw0yMDEwMTkyMDExNTJaMCsxKTAnBgNVBAMMIGNhY2tsaW5nIGNyeXB0b2dyYXBoZXIgZmFrZSBST09UMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+TbvalHXQYO6GhJUJZI5mF2k4+nZDIvqWyrjw+2k9+UAcekuLKPpSclu9aBRvUggw3XFHAW95qW6Dv2+5gvinUmTq9Ry7kVTUYAxyZu1ydHt+wDETmFJfeY6/fpBHHIsuGLItqpUGmr8D6LROGEqfFY2B9+08O7Zs+FufDRgLHWEvLTdpPkrzeDJs9Oo6g38jfT9b4+9Ahs+FvvwqneAkbeZgBC2NWKB+drMuNBTPbF/W1a8czAzHeOs6qy0dBlTHNjL62/o9cRKNiKe3IqwHJdd01V1aLSUgIbe2HrP9EC1djnUXWR3jx3ursaKt7PTKsC52UJkRqnai80MzQj0WwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU6aQ/7p6l5vLV13lgPJOmLiSOl6owDQYJKoZIhvcNAQELBQADggEBACuwILDTvaBrdorv2zMsYnZuKvXtknWAf/DTcvF4N5PMOPBNkeHuGfv0VDe6VXpBHiU5G9E2RdU435W7o0kRSn27YcqrxaXGt9m2kArW6e49136+MnFx47jjk0p4T48s6MeaL5JVLJzxYouu1ZOZqlVokwNPO+8bxn6ALumIVUOD1jSBN7Y9pgLUS2rzO5pe5pxS2Ak/eO7Q7M21r1sEuG/uPuWqBFogk+4Z9omKVZdRDbzm9vYUATgEZdlTe2tct3BVBQ2zWbe0R2svIuCs8XzERykvfv1JawxI68I9vN0Dh9vj/xDM6udorfALlhjgQdftmbHovRLpJ1ZSOMIUNGY= MIIFCAoBAKCCBQEwggT9BgkrBgEFBQcwAQEEggTuMIIE6jCBrKADAgEAoS0wKzEpMCcGA1UEAwwgY2Fja2xpbmcgY3J5cHRvZ3JhcGhlciBmYWtlIFJPT1QYDzIwMTUxMDIxMjA1NTAwWjBlMGMwOzAJBgUrDgMCGgUABBSwLsMRhyg1dJUwnXWk++D57lvgagQU6aQ/7p6l5vLV13lgPJOmLiSOl6oCAhJNgAAYDzIwMTUxMDIwMDAwMDAwWqARGA8yMDMwMTAyMDAwMDAwMFowDQYJKoZIhvcNAQELBQADggEBAFgnZ/Ft1LTDYPwPlecOtLykgwS4HZTelUaSi841nq/tgfLM11G3D1AUXAT2V2jxiG+0YTxzkWd5v44KJGB9Mm+qjafPMKR3ULjQkJHJ8goFHpWkUtLrIYurj8N+4HpwZ+RJccieuZIX8SMeSWRq5w83okWZPGoUrl6GRdQDteE7imrNkBa35zrzUWozPqY8k90ttKfhZHRXNCJe8YbVfJRDh0vVZABzlfHeW8V+ie15HPVDx/M341KC3tBMM88e5/bt3sLyUU8SwxGH5nOe/ohVpjhkjk2Pz4TPdwD2ZK5Auc09VBfivdLYRE84BMhd8/yOEt53VWGPIMxWUVtrUyegggMjMIIDHzCCAxswggIDoAMCAQICCQDNMc/iNkPNdTANBgkqhkiG9w0BAQsFADArMSkwJwYDVQQDDCBjYWNrbGluZyBjcnlwdG9ncmFwaGVyIGZha2UgUk9PVDAeFw0xNTEwMjEyMDExNTJaFw0yMDEwMTkyMDExNTJaMCsxKTAnBgNVBAMMIGNhY2tsaW5nIGNyeXB0b2dyYXBoZXIgZmFrZSBST09UMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+TbvalHXQYO6GhJUJZI5mF2k4+nZDIvqWyrjw+2k9+UAcekuLKPpSclu9aBRvUggw3XFHAW95qW6Dv2+5gvinUmTq9Ry7kVTUYAxyZu1ydHt+wDETmFJfeY6/fpBHHIsuGLItqpUGmr8D6LROGEqfFY2B9+08O7Zs+FufDRgLHWEvLTdpPkrzeDJs9Oo6g38jfT9b4+9Ahs+FvvwqneAkbeZgBC2NWKB+drMuNBTPbF/W1a8czAzHeOs6qy0dBlTHNjL62/o9cRKNiKe3IqwHJdd01V1aLSUgIbe2HrP9EC1djnUXWR3jx3ursaKt7PTKsC52UJkRqnai80MzQj0WwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU6aQ/7p6l5vLV13lgPJOmLiSOl6owDQYJKoZIhvcNAQELBQADggEBACuwILDTvaBrdorv2zMsYnZuKvXtknWAf/DTcvF4N5PMOPBNkeHuGfv0VDe6VXpBHiU5G9E2RdU435W7o0kRSn27YcqrxaXGt9m2kArW6e49136+MnFx47jjk0p4T48s6MeaL5JVLJzxYouu1ZOZqlVokwNPO+8bxn6ALumIVUOD1jSBN7Y9pgLUS2rzO5pe5pxS2Ak/eO7Q7M21r1sEuG/uPuWqBFogk+4Z9omKVZdRDbzm9vYUATgEZdlTe2tct3BVBQ2zWbe0R2svIuCs8XzERykvfv1JawxI68I9vN0Dh9vj/xDM6udorfALlhjgQdftmbHovRLpJ1ZSOMIUNGY= ================================================ FILE: ocsp/testdata/response_broken.pem ================================================ MIICGAoBAKCCAhEwggINBgkrBgEFBQcwAQEEggH+OZ4ZSKS2J85Kr9UaI2LAEFKvOM8/hjk8uyp7KnqJ12h8GOhGZAgIBdaADAQH/GA8wMDAxMDEwMTAwMDAwMFqgERgPMDAwMTAxMDEwMDAwMDBaMA0GCSqGSIb3DQEBCwUAA4IBAQCBGs+8UNwUdkEBladnajZIV+sHtmao/mMTIvpyPqnmV2Ab9KfNWlSDSDuMtZYKS4VsEwtbZ+4kKWI8DugE6egjP3o64R7VP2aqrh41IORwccLGVsexILBpxg4h602JbhXM0sxgXoh5WAt9f1oy6PsHAt/XAuJGSo7yMNv3nHKNFwjExmZt21sNLYlWlljjtX92rlo/mBTWKO0js4YRNyeNQhchARbn9oL18jW0yAVqB9a8rees+EippbTfoktFf0cIhnmkiknPZSZ+dN2qHkxiXIujWlymZzUZcqRTNtrmmhlOdt35QSg7Vw8eyw2rl8ZU94zaI5DPWn1QYn0dk7l9 ================================================ FILE: ocsp/testdata/server.crt ================================================ -----BEGIN CERTIFICATE----- MIICATCCAWoCCQDidF+uNJR6czANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 cyBQdHkgTHRkMB4XDTEyMDUwMTIyNTUxN1oXDTEzMDUwMTIyNTUxN1owRTELMAkG A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81 KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt +LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw== -----END CERTIFICATE----- ================================================ FILE: ocsp/testdata/server.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQC2mOWeh2HPfWQsQmh4tKRGau/yXt7GQa07RES0huKuP0EHLrhl dUETuSEoY7ZyczxTvKPDs21+H4i8KNlUDd3ZeodLc+Ou3geZT9wYI40Tz40Reip3 MtQM86LHWoMNEG9ezzUoBXaqHoJgdlt2qLGEN6uO8lwPg2x3uQTERl8e4QIDAQAB AoGAVxnsPojZ8X4g8LPk3d9dlXGhb/4tSmk9102jcHH/Y5ssy95Pe6ZJGr1uwbN+ 7m1l05PikpHeoxEryoW51cyfjDVkXUT0zPp2JC38DUA/0A8qWav/aENM64wg1I0P Dil8FywzZEonRNJst53+9cxFye70ely5br/tWxEp4/MsM1kCQQDqV4Lwn8BXOeKg xOwNmcL+0XPedvSPBSPUoGJCzu12rH6Z+UHXipXsqRNSyQ+KGlur14y0kCh5uiVA jmWYVEEjAkEAx3keAo1nFsVW35EPt5LIbh6L6ty7GrvGRvOVeSd6YLtixMety24k hpt1cEv2xlFnbjbBbMkr9eUiUNpttLT6KwJBANGKaLoSjqEwUFYjX1OV/wdtcGcn BOzx0qUouFQ2xZ0NBrNVbyt1bzPLx0yKHkwF35ybw+Qc1yRpby/3ZB6+j/MCQFLl vtcItOL9uBDJVGLSGYHKKBO/D/MYPlqWOHRVN8KjnXRyF4QHjh5y1OeKalAY3Ict Mk1nfWF/jDdVz2neHGkCQHHBR4Xt1/euDku+14z5aLpphTEQVuRD2vQoeKi/W/CY OgNmKj1DzucnCS6yRCrF8Q0Pn8l054a3Wdbl1gqI/gA= -----END RSA PRIVATE KEY----- ================================================ FILE: ocsp/testdata/server_broken.crt ================================================ -----BEGIN CERTIFICATE----- IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81 KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt +LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw== -----END CERTIFICATE----- ================================================ FILE: ocsp/testdata/server_broken.key ================================================ -----BEGIN RSA PRIVATE KEY----- jmWYVEEjAkEAx3keAo1nFsVW35EPt5LIbh6L6ty7GrvGRvOVeSd6YLtixMety24k hpt1cEv2xlFnbjbBbMkr9eUiUNpttLT6KwJBANGKaLoSjqEwUFYjX1OV/wdtcGcn BOzx0qUouFQ2xZ0NBrNVbyt1bzPLx0yKHkwF35ybw+Qc1yRpby/3ZB6+j/MCQFLl vtcItOL9uBDJVGLSGYHKKBO/D/MYPlqWOHRVN8KjnXRyF4QHjh5y1OeKalAY3Ict Mk1nfWF/jDdVz2neHGkCQHHBR4Xt1/euDku+14z5aLpphTEQVuRD2vQoeKi/W/CY OgNmKj1DzucnCS6yRCrF8Q0Pn8l054a3Wdbl1gqI/gA= -----END RSA PRIVATE KEY----- ================================================ FILE: ocsp/testdata/sqlite_ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIDqjCCApKgAwIBAgIUFqT7NscPhQ5kfZTYNhWTKXVekrswDQYJKoZIhvcNAQEL BQAwbTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMQ8wDQYDVQQHEwZJ dGhhY2ExLDAqBgNVBAoTI1RoZSBCZXN0IE9wZW4tU291cmNlIEhhY2thdGhvbiBU ZWFtMQwwCgYDVQQLEwNXV1cwHhcNMTcwMjExMTQxMDAwWhcNMjIwMjEwMTQxMDAw WjBtMQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxDzANBgNVBAcTBkl0 aGFjYTEsMCoGA1UEChMjVGhlIEJlc3QgT3Blbi1Tb3VyY2UgSGFja2F0aG9uIFRl YW0xDDAKBgNVBAsTA1dXVzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANR66Ky8dBV2FVyDOGXFM4bF63EJxI7PgCKg8yiJsYihwo5wsABpiI66offWsJNV rRKT8QhGohm4V1B/MOpdb3slOYVFXAInjoKyClPYDK3GMkJ8mo6mFysm3q/JqlEl KjvVIb8Yq7cgPAj/MOb4rBJu5+c3sM37CwpUbxCTdPiuVMGYDjVKauloJfTir0HQ RMwREsO6fyzSia4qvfj4ljWGzPtEVrRmzs7LguLr3DkUjXMSq7AI3L+oUdiYR6kV c3rLucMQKRCNGMcU3T8Sq9Pwt2sUeAFNqcXk9E1FqesYwFoEejStU24wpTd4ah0g tL1LyoEYG6etUehrxlRlMJsCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFANQ4+9iVQzAZdHhb0fNXtrb3krdMA0GCSqG SIb3DQEBCwUAA4IBAQA4SKVpdJj40xaeyVkHWtrY4O8wB2J7Z6rsUf9jlEySeQaH GWI4LUOKjrU0u/NtuvTybDHyfc1VrdgZmfaukE35VyQ1+xWa/47Q7KISSCH1x0cF L+WdJqKHD0q/tR2uz/fw9AUlV1LkBEeAZclhPxCLv32gLExQrNCBVa7c9Xkq1muB o0ootJF9sTZopqnsMldvMBWOl/9cb2dxPKu3AcNpCm28wt+rwqHIu+Fna9Fe/n+y SmWTaP3l/eiLskFUvmHKSUVwTEPC6kbK9rxKPz7ijQ3h/YuWxxz32L2CpsOfekgT 7jER0Y/xxZq7XykdwZ1VKKfZGnsH8mU2rU335Gd1 -----END CERTIFICATE----- ================================================ FILE: ocsp/universal/universal.go ================================================ package universal import ( "github.com/cloudflare/cfssl/ocsp" ocspConfig "github.com/cloudflare/cfssl/ocsp/config" ) // NewSignerFromConfig generates a new OCSP signer from a config object. func NewSignerFromConfig(cfg ocspConfig.Config) (ocsp.Signer, error) { return ocsp.NewSignerFromFile(cfg.CACertFile, cfg.ResponderCertFile, cfg.KeyFile, cfg.Interval) } ================================================ FILE: revoke/revoke.go ================================================ // Package revoke provides functionality for checking the validity of // a cert. Specifically, the temporal validity of the certificate is // checked first, then any CRL and OCSP url in the cert is checked. package revoke import ( "bytes" "crypto" "crypto/x509" "crypto/x509/pkix" "encoding/base64" "encoding/pem" "errors" "fmt" "io" "net/http" neturl "net/url" "sync" "time" "golang.org/x/crypto/ocsp" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" ) // HTTPClient is an instance of http.Client that will be used for all HTTP requests. var HTTPClient = http.DefaultClient // HardFail determines whether the failure to check the revocation // status of a certificate (i.e. due to network failure) causes // verification to fail (a hard failure). var HardFail = false // CRLSet associates a PKIX certificate list with the URL the CRL is // fetched from. var CRLSet = map[string]*pkix.CertificateList{} var crlLock = new(sync.Mutex) // We can't handle LDAP certificates, so this checks to see if the // URL string points to an LDAP resource so that we can ignore it. func ldapURL(url string) bool { u, err := neturl.Parse(url) if err != nil { log.Warningf("error parsing url %s: %v", url, err) return false } if u.Scheme == "ldap" { return true } return false } // revCheck should check the certificate for any revocations. It // returns a pair of booleans: the first indicates whether the certificate // is revoked, the second indicates whether the revocations were // successfully checked.. This leads to the following combinations: // // - false, false: an error was encountered while checking revocations. // - false, true: the certificate was checked successfully, and it is not revoked. // - true, true: the certificate was checked successfully, and it is revoked. // - true, false: failure to check revocation status causes verification to fail func revCheck(cert *x509.Certificate) (revoked, ok bool, err error) { for _, url := range cert.CRLDistributionPoints { if ldapURL(url) { log.Infof("skipping LDAP CRL: %s", url) continue } if revoked, ok, err := certIsRevokedCRL(cert, url); !ok { log.Warning("error checking revocation via CRL") if HardFail { return true, false, err } return false, false, err } else if revoked { log.Info("certificate is revoked via CRL") return true, true, err } } if revoked, ok, err := certIsRevokedOCSP(cert, HardFail); !ok { log.Warning("error checking revocation via OCSP") if HardFail { return true, false, err } return false, false, err } else if revoked { log.Info("certificate is revoked via OCSP") return true, true, err } return false, true, nil } // fetchCRL fetches and parses a CRL. func fetchCRL(url string) (*pkix.CertificateList, error) { resp, err := HTTPClient.Get(url) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode >= 300 { return nil, errors.New("failed to retrieve CRL") } body, err := crlRead(resp.Body) if err != nil { return nil, err } return x509.ParseCRL(body) } func getIssuer(cert *x509.Certificate) *x509.Certificate { var issuer *x509.Certificate var err error for _, issuingCert := range cert.IssuingCertificateURL { issuer, err = fetchRemote(issuingCert) if err != nil { continue } break } return issuer } // check a cert against a specific CRL. Returns the same bool pair // as revCheck, plus an error if one occurred. func certIsRevokedCRL(cert *x509.Certificate, url string) (revoked, ok bool, err error) { crlLock.Lock() crl, ok := CRLSet[url] if ok && crl == nil { ok = false delete(CRLSet, url) } crlLock.Unlock() var shouldFetchCRL = true if ok { if !crl.HasExpired(time.Now()) { shouldFetchCRL = false } } issuer := getIssuer(cert) if shouldFetchCRL { var err error crl, err = fetchCRL(url) if err != nil { log.Warningf("failed to fetch CRL: %v", err) return false, false, err } // check CRL signature if issuer != nil { err = issuer.CheckCRLSignature(crl) if err != nil { log.Warningf("failed to verify CRL: %v", err) return false, false, err } } crlLock.Lock() CRLSet[url] = crl crlLock.Unlock() } for _, revoked := range crl.TBSCertList.RevokedCertificates { if cert.SerialNumber.Cmp(revoked.SerialNumber) == 0 { log.Info("Serial number match: intermediate is revoked.") return true, true, err } } return false, true, err } // VerifyCertificate ensures that the certificate passed in hasn't // expired and checks the CRL for the server. func VerifyCertificate(cert *x509.Certificate) (revoked, ok bool) { revoked, ok, _ = VerifyCertificateError(cert) return revoked, ok } // VerifyCertificateError ensures that the certificate passed in hasn't // expired and checks the CRL for the server. func VerifyCertificateError(cert *x509.Certificate) (revoked, ok bool, err error) { if !time.Now().Before(cert.NotAfter) { msg := fmt.Sprintf("Certificate expired %s\n", cert.NotAfter) log.Info(msg) return true, true, fmt.Errorf(msg) } else if !time.Now().After(cert.NotBefore) { msg := fmt.Sprintf("Certificate isn't valid until %s\n", cert.NotBefore) log.Info(msg) return true, true, fmt.Errorf(msg) } return revCheck(cert) } func fetchRemote(url string) (*x509.Certificate, error) { resp, err := HTTPClient.Get(url) if err != nil { return nil, err } defer resp.Body.Close() in, err := remoteRead(resp.Body) if err != nil { return nil, err } p, _ := pem.Decode(in) if p != nil { return helpers.ParseCertificatePEM(in) } return x509.ParseCertificate(in) } var ocspOpts = ocsp.RequestOptions{ Hash: crypto.SHA1, } func certIsRevokedOCSP(leaf *x509.Certificate, strict bool) (revoked, ok bool, e error) { var err error ocspURLs := leaf.OCSPServer if len(ocspURLs) == 0 { // OCSP not enabled for this certificate. return false, true, nil } issuer := getIssuer(leaf) if issuer == nil { return false, false, nil } ocspRequest, err := ocsp.CreateRequest(leaf, issuer, &ocspOpts) if err != nil { return revoked, ok, err } for _, server := range ocspURLs { resp, err := sendOCSPRequest(server, ocspRequest, leaf, issuer) if err != nil { if strict { return revoked, ok, err } continue } // There wasn't an error fetching the OCSP status. ok = true if resp.Status != ocsp.Good { // The certificate was revoked. revoked = true } return revoked, ok, err } return revoked, ok, err } // sendOCSPRequest attempts to request an OCSP response from the // server. The error only indicates a failure to *fetch* the // certificate, and *does not* mean the certificate is valid. func sendOCSPRequest(server string, req []byte, leaf, issuer *x509.Certificate) (*ocsp.Response, error) { var resp *http.Response var err error if len(req) > 256 { buf := bytes.NewBuffer(req) resp, err = HTTPClient.Post(server, "application/ocsp-request", buf) } else { reqURL := server + "/" + neturl.QueryEscape(base64.StdEncoding.EncodeToString(req)) resp, err = HTTPClient.Get(reqURL) } if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, errors.New("failed to retrieve OSCP") } body, err := ocspRead(resp.Body) if err != nil { return nil, err } switch { case bytes.Equal(body, ocsp.UnauthorizedErrorResponse): return nil, errors.New("OSCP unauthorized") case bytes.Equal(body, ocsp.MalformedRequestErrorResponse): return nil, errors.New("OSCP malformed") case bytes.Equal(body, ocsp.InternalErrorErrorResponse): return nil, errors.New("OSCP internal error") case bytes.Equal(body, ocsp.TryLaterErrorResponse): return nil, errors.New("OSCP try later") case bytes.Equal(body, ocsp.SigRequredErrorResponse): return nil, errors.New("OSCP signature required") } return ocsp.ParseResponseForCert(body, leaf, issuer) } var crlRead = io.ReadAll // SetCRLFetcher sets the function to use to read from the http response body func SetCRLFetcher(fn func(io.Reader) ([]byte, error)) { crlRead = fn } var remoteRead = io.ReadAll // SetRemoteFetcher sets the function to use to read from the http response body func SetRemoteFetcher(fn func(io.Reader) ([]byte, error)) { remoteRead = fn } var ocspRead = io.ReadAll // SetOCSPFetcher sets the function to use to read from the http response body func SetOCSPFetcher(fn func(io.Reader) ([]byte, error)) { ocspRead = fn } ================================================ FILE: revoke/revoke_test.go ================================================ package revoke import ( "crypto/x509" // "crypto/x509/pkix" "encoding/pem" "fmt" "os" "testing" "time" ) // The first three test cases represent known revoked, expired, and good // certificates that were checked on the date listed in the log. The // good certificate will eventually need to be replaced in year 2029. // If there is a soft-fail, the test will pass to mimic the default // behaviour used in this software. However, it will print a warning // to indicate that this is the case. // 2014/05/22 14:18:17 Certificate expired 2014-04-04 14:14:20 +0000 UTC // 2014/05/22 14:18:17 Revoked certificate: misc/intermediate_ca/ActalisServerAuthenticationCA.crt var expiredCert = mustParse(`-----BEGIN CERTIFICATE----- MIIEXTCCA8agAwIBAgIEBycURTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds b2JhbCBSb290MB4XDTA3MDQwNDE0MTUxNFoXDTE0MDQwNDE0MTQyMFowejELMAkG A1UEBhMCSVQxFzAVBgNVBAoTDkFjdGFsaXMgUy5wLkEuMScwJQYDVQQLEx5DZXJ0 aWZpY2F0aW9uIFNlcnZpY2UgUHJvdmlkZXIxKTAnBgNVBAMTIEFjdGFsaXMgU2Vy dmVyIEF1dGhlbnRpY2F0aW9uIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAv6P0bhXbUQkVW8ox0HJ+sP5+j6pTwS7yg/wGEUektB/G1duQiT1v21fo LANr6F353jILQDCpHIfal3MhbSsHEMKU7XaqsyLWV93bcIKbIloS/eXDfkog6KB3 u0JHgrtNz584Jg/OLm9feffNbCJ38TiLo0/UWkAQ6PQWaOwZEgyKjVI5F3swoTB3 g0LZAzegvkU00Kfp13cSg+cJeU4SajwtfQ+g6s6dlaekaHy/0ef46PfiHHRuhEhE JWIpDtUN2ywTT33MSSUe5glDIiXYfcamJQrebzGsHEwyqI195Yaxb+FLNND4n3HM e7EI2OrLyT+r/WMvQbl+xNihwtv+HwIDAQABo4IBbzCCAWswEgYDVR0TAQH/BAgw BgEB/wIBADBTBgNVHSAETDBKMEgGCSsGAQQBsT4BADA7MDkGCCsGAQUFBwIBFi1o dHRwOi8vd3d3LnB1YmxpYy10cnVzdC5jb20vQ1BTL09tbmlSb290Lmh0bWwwDgYD VR0PAQH/BAQDAgEGMIGJBgNVHSMEgYEwf6F5pHcwdTELMAkGA1UEBhMCVVMxGDAW BgNVBAoTD0dURSBDb3Jwb3JhdGlvbjEnMCUGA1UECxMeR1RFIEN5YmVyVHJ1c3Qg U29sdXRpb25zLCBJbmMuMSMwIQYDVQQDExpHVEUgQ3liZXJUcnVzdCBHbG9iYWwg Um9vdIICAaUwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL3d3dy5wdWJsaWMtdHJ1 c3QuY29tL2NnaS1iaW4vQ1JMLzIwMTgvY2RwLmNybDAdBgNVHQ4EFgQUpi6OuXYt oxHC3cTezVLuraWpAFEwDQYJKoZIhvcNAQEFBQADgYEAAtjJBwjsvw7DBs+v7BQz gSGeg6nbYUuPL7+1driT5XsUKJ7WZjiwW2zW/WHZ+zGo1Ev8Dc574RpSrg/EIlfH TpBiBuFgiKtJksKdoxPZGSI8FitwcgeW+y8wotmm0CtDzWN27g2kfSqHb5eHfZY5 sESPRwHkcMUNdAp37FLweUw= -----END CERTIFICATE-----`) // 2014/05/22 14:18:31 Serial number match: intermediate is revoked. // 2014/05/22 14:18:31 certificate is revoked via CRL // 2014/05/22 14:18:31 Revoked certificate: misc/intermediate_ca/MobileArmorEnterpriseCA.crt var revokedCert = mustParse(`-----BEGIN CERTIFICATE----- MIIEEzCCAvugAwIBAgILBAAAAAABGMGjftYwDQYJKoZIhvcNAQEFBQAwcTEoMCYG A1UEAxMfR2xvYmFsU2lnbiBSb290U2lnbiBQYXJ0bmVycyBDQTEdMBsGA1UECxMU Um9vdFNpZ24gUGFydG5lcnMgQ0ExGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex CzAJBgNVBAYTAkJFMB4XDTA4MDMxODEyMDAwMFoXDTE4MDMxODEyMDAwMFowJTEj MCEGA1UEAxMaTW9iaWxlIEFybW9yIEVudGVycHJpc2UgQ0EwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCaEjeDR73jSZVlacRn5bc5VIPdyouHvGIBUxyS C6483HgoDlWrWlkEndUYFjRPiQqJFthdJxfglykXD+btHixMIYbz/6eb7hRTdT9w HKsfH+wTBIdb5AZiNjkg3QcCET5HfanJhpREjZWP513jM/GSrG3VwD6X5yttCIH1 NFTDAr7aqpW/UPw4gcPfkwS92HPdIkb2DYnsqRrnKyNValVItkxJiotQ1HOO3YfX ivGrHIbJdWYg0rZnkPOgYF0d+aIA4ZfwvdW48+r/cxvLevieuKj5CTBZZ8XrFt8r JTZhZljbZvnvq/t6ZIzlwOj082f+lTssr1fJ3JsIPnG2lmgTAgMBAAGjgfcwgfQw DgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFIZw ns4uzXdLX6xDRXUzFgZxWM7oME0GA1UdIARGMEQwQgYJKwYBBAGgMgE8MDUwMwYI KwYBBQUHAgIwJxolaHR0cDovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5 LzA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmdsb2JhbHNpZ24ubmV0L1Jv b3RTaWduUGFydG5lcnMuY3JsMB8GA1UdIwQYMBaAFFaE7LVxpedj2NtRBNb65vBI UknOMA0GCSqGSIb3DQEBBQUAA4IBAQBZvf+2xUJE0ekxuNk30kPDj+5u9oI3jZyM wvhKcs7AuRAbcxPtSOnVGNYl8By7DPvPun+U3Yci8540y143RgD+kz3jxIBaoW/o c4+X61v6DBUtcBPEt+KkV6HIsZ61SZmc/Y1I2eoeEt6JYoLjEZMDLLvc1cK/+wpg dUZSK4O9kjvIXqvsqIOlkmh/6puSugTNao2A7EIQr8ut0ZmzKzMyZ0BuQhJDnAPd Kz5vh+5tmytUPKA8hUgmLWe94lMb7Uqq2wgZKsqun5DAWleKu81w7wEcOrjiiB+x jeBHq7OnpWm+ccTOPCE6H4ZN4wWVS7biEBUdop/8HgXBPQHWAdjL -----END CERTIFICATE-----`) // A Comodo intermediate CA certificate with issuer url, CRL url and OCSP url var goodComodoCA = (`-----BEGIN CERTIFICATE----- MIIGCDCCA/CgAwIBAgIQKy5u6tl1NmwUim7bo3yMBzANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMjEy MDAwMDAwWhcNMjkwMjExMjM1OTU5WjCBkDELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxNjA0BgNVBAMTLUNPTU9ETyBSU0EgRG9tYWluIFZh bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAI7CAhnhoFmk6zg1jSz9AdDTScBkxwtiBUUWOqigwAwCfx3M28Sh bXcDow+G+eMGnD4LgYqbSRutA776S9uMIO3Vzl5ljj4Nr0zCsLdFXlIvNN5IJGS0 Qa4Al/e+Z96e0HqnU4A7fK31llVvl0cKfIWLIpeNs4TgllfQcBhglo/uLQeTnaG6 ytHNe+nEKpooIZFNb5JPJaXyejXdJtxGpdCsWTWM/06RQ1A/WZMebFEh7lgUq/51 UHg+TLAchhP6a5i84DuUHoVS3AOTJBhuyydRReZw3iVDpA3hSqXttn7IzW3uLh0n c13cRTCAquOyQQuvvUSH2rnlG51/ruWFgqUCAwEAAaOCAWUwggFhMB8GA1UdIwQY MBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBSQr2o6lFoL2JDqElZz 30O0Oija5zAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgG BmeBDAECATBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNv bS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB AQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9E T1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21v ZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAE4rdk+SHGI2ibp3wScF9BzWRJ2p mj6q1WZmAT7qSeaiNbz69t2Vjpk1mA42GHWx3d1Qcnyu3HeIzg/3kCDKo2cuH1Z/ e+FE6kKVxF0NAVBGFfKBiVlsit2M8RKhjTpCipj4SzR7JzsItG8kO3KdY3RYPBps P0/HEZrIqPW1N+8QRcZs2eBelSaz662jue5/DJpmNXMyYE7l3YphLG5SEXdoltMY dVEVABt0iN3hxzgEQyjpFv3ZBdRdRydg1vs4O2xyopT4Qhrf7W8GjEXCBgCq5Ojc 2bXhc3js9iPc0d1sjhqPpepUfJa3w/5Vjo1JXvxku88+vZbrac2/4EjxYoIQ5QxG V/Iz2tDIY+3GH5QFlkoakdH368+PUq4NCNk+qKBR6cGHdNXJ93SrLlP7u3r7l+L4 HyaPs9Kg4DdbKDsx5Q5XLVq4rXmsXiBmGqW5prU5wfWYQ//u+aen/e7KJD2AFsQX j4rBYKEMrltDR5FL1ZoXX/nUh8HCjLfn4g8wGTeGrODcQgPmlKidrv0PJFGUzpII 0fxQ8ANAe4hZ7Q7drNJ3gjTcBpUC2JD5Leo31Rpg0Gcg19hCC0Wvgmje3WYkN5Ap lBlGGSW4gNfL1IYoakRwJiNiqZ+Gb7+6kHDSVneFeO/qJakXzlByjAA6quPbYzSf +AZxAeKCINT+b72x -----END CERTIFICATE-----`) var goodCert = mustParse(goodComodoCA) func mustParse(pemData string) *x509.Certificate { block, _ := pem.Decode([]byte(pemData)) if block == nil { panic("Invalid PEM data.") } else if block.Type != "CERTIFICATE" { panic("Invalid PEM type.") } cert, err := x509.ParseCertificate([]byte(block.Bytes)) if err != nil { panic(err.Error()) } return cert } func TestRevoked(t *testing.T) { if revoked, ok := VerifyCertificate(revokedCert); !ok { fmt.Fprintf(os.Stderr, "Warning: soft fail checking revocation") } else if !revoked { t.Fatalf("revoked certificate should have been marked as revoked") } } func TestExpired(t *testing.T) { if revoked, ok := VerifyCertificate(expiredCert); !ok { fmt.Fprintf(os.Stderr, "Warning: soft fail checking revocation") } else if !revoked { t.Fatalf("expired certificate should have been marked as revoked") } } func TestGood(t *testing.T) { if revoked, ok := VerifyCertificate(goodCert); !ok { fmt.Fprintf(os.Stderr, "Warning: soft fail checking revocation") } else if revoked { t.Fatalf("good certificate should not have been marked as revoked") } } func TestLdap(t *testing.T) { ldapCert := mustParse(goodComodoCA) ldapCert.CRLDistributionPoints = append(ldapCert.CRLDistributionPoints, "ldap://myldap.example.com") if revoked, ok := VerifyCertificate(ldapCert); revoked || !ok { t.Fatalf("ldap certificate should have been recognized") } } func TestLdapURLErr(t *testing.T) { if ldapURL(":") { t.Fatalf("bad url does not cause error") } } func TestCertNotYetValid(t *testing.T) { notReadyCert := expiredCert notReadyCert.NotBefore = time.Date(3000, time.January, 1, 1, 1, 1, 1, time.Local) notReadyCert.NotAfter = time.Date(3005, time.January, 1, 1, 1, 1, 1, time.Local) if revoked, _ := VerifyCertificate(expiredCert); !revoked { t.Fatalf("not yet verified certificate should have been marked as revoked") } } func TestCRLFetchError(t *testing.T) { ldapCert := mustParse(goodComodoCA) ldapCert.CRLDistributionPoints[0] = "" if revoked, ok := VerifyCertificate(ldapCert); ok || revoked { t.Fatalf("Fetching error not encountered") } HardFail = true if revoked, ok := VerifyCertificate(ldapCert); ok || !revoked { t.Fatalf("Fetching error not encountered, hardfail not registered") } HardFail = false } func TestBadCRLSet(t *testing.T) { ldapCert := mustParse(goodComodoCA) ldapCert.CRLDistributionPoints[0] = "" CRLSet[""] = nil certIsRevokedCRL(ldapCert, "") if _, ok := CRLSet[""]; ok { t.Fatalf("key emptystring should be deleted from CRLSet") } delete(CRLSet, "") } func TestCachedCRLSet(t *testing.T) { VerifyCertificate(goodCert) if revoked, ok := VerifyCertificate(goodCert); !ok || revoked { t.Fatalf("Previously fetched CRL's should be read smoothly and unrevoked") } } func TestRemoteFetchError(t *testing.T) { badurl := ":" if _, err := fetchRemote(badurl); err == nil { t.Fatalf("fetching bad url should result in non-nil error") } } func TestNoOCSPServers(t *testing.T) { badIssuer := goodCert badIssuer.IssuingCertificateURL = []string{" "} certIsRevokedOCSP(badIssuer, true) noOCSPCert := goodCert noOCSPCert.OCSPServer = make([]string, 0) if revoked, ok, _ := certIsRevokedOCSP(noOCSPCert, true); revoked || !ok { t.Fatalf("OCSP falsely registered as enabled for this certificate") } } ================================================ FILE: scan/broad.go ================================================ package scan import ( "crypto/tls" "crypto/x509" "net" "sync" "time" "github.com/cloudflare/cfssl/bundler" ) // Broad contains scanners for large swaths of TLS hosts on the internet. var Broad = &Family{ Description: "Large scale scans of TLS hosts", Scanners: map[string]*Scanner{ "IntermediateCAs": { "Scans a CIDR IP range for unknown Intermediate CAs", intermediateCAScan, }, }, } func incrementBytes(bytes []byte) { lsb := len(bytes) - 1 bytes[lsb]++ if bytes[lsb] == 0 { incrementBytes(bytes[:lsb]) } } var ( caBundleFile = "/etc/cfssl/ca-bundle.crt" intBundleFile = "/etc/cfssl/int-bundle.crt" numWorkers = 32 timeout = time.Second ) // intermediateCAScan scans for new intermediate CAs not in the trust store. func intermediateCAScan(addr, hostname string) (grade Grade, output Output, err error) { cidr, port, _ := net.SplitHostPort(addr) _, ipnet, err := net.ParseCIDR(cidr) if err != nil { return Skipped, nil, nil } b, err := bundler.NewBundler(caBundleFile, intBundleFile) if err != nil { return } var wg sync.WaitGroup wg.Add(numWorkers) dialer := &net.Dialer{Timeout: timeout} config := &tls.Config{InsecureSkipVerify: true} addrs := make(chan string) chains := make(chan []*x509.Certificate, numWorkers) go func() { for chain := range chains { b.Bundle(chain, nil, bundler.Force) } }() for i := 0; i < numWorkers; i++ { go func() { for addr := range addrs { conn, err := tls.DialWithDialer(dialer, Network, addr, config) if err != nil { continue } conn.Close() if conn.ConnectionState().HandshakeComplete { chains <- conn.ConnectionState().PeerCertificates } } wg.Done() }() } for ip := ipnet.IP.To16(); ipnet.Contains(ip); incrementBytes(ip) { addrs <- net.JoinHostPort(ip.String(), port) } close(addrs) wg.Wait() close(chains) grade = Good return } ================================================ FILE: scan/connectivity.go ================================================ package scan import ( "bufio" "errors" "fmt" "io" "net" "github.com/cloudflare/cfssl/scan/crypto/tls" ) // Connectivity contains scanners testing basic connectivity to the host var Connectivity = &Family{ Description: "Scans for basic connectivity with the host through DNS and TCP/TLS dials", Scanners: map[string]*Scanner{ "DNSLookup": { "Host can be resolved through DNS", dnsLookupScan, }, "CloudFlareStatus": { "Host is on CloudFlare", onCloudFlareScan, }, "TCPDial": { "Host accepts TCP connection", tcpDialScan, }, "TLSDial": { "Host can perform TLS handshake", tlsDialScan, }, }, } // dnsLookupScan tests that DNS resolution of the host returns at least one address func dnsLookupScan(addr, hostname string) (grade Grade, output Output, err error) { addrs, err := net.LookupHost(hostname) if err != nil { return } if len(addrs) == 0 { err = errors.New("no addresses found for host") } grade, output = Good, addrs return } var ( cfNets []*net.IPNet cfNetsErr error ) func initOnCloudFlareScan() ([]*net.IPNet, error) { // Propagate previous errors and don't attempt to re-download. if cfNetsErr != nil { return nil, cfNetsErr } // Don't re-download ranges if we already have them. if len(cfNets) > 0 { return cfNets, nil } // Download CloudFlare CIDR ranges and parse them. v4resp, err := Client.Get("https://www.cloudflare.com/ips-v4") if err != nil { cfNetsErr = fmt.Errorf("Couldn't download CloudFlare IPs: %v", err) return nil, cfNetsErr } defer v4resp.Body.Close() v6resp, err := Client.Get("https://www.cloudflare.com/ips-v6") if err != nil { cfNetsErr = fmt.Errorf("Couldn't download CloudFlare IPs: %v", err) return nil, cfNetsErr } defer v6resp.Body.Close() scanner := bufio.NewScanner(io.MultiReader(v4resp.Body, v6resp.Body)) for scanner.Scan() { _, ipnet, err := net.ParseCIDR(scanner.Text()) if err != nil { cfNetsErr = fmt.Errorf("Couldn't parse CIDR range: %v", err) return nil, cfNetsErr } cfNets = append(cfNets, ipnet) } if err := scanner.Err(); err != nil { cfNetsErr = fmt.Errorf("Couldn't read IP bodies: %v", err) return nil, cfNetsErr } return cfNets, nil } func onCloudFlareScan(addr, hostname string) (grade Grade, output Output, err error) { var cloudflareNets []*net.IPNet if cloudflareNets, err = initOnCloudFlareScan(); err != nil { grade = Skipped return } _, addrs, err := dnsLookupScan(addr, hostname) if err != nil { return } cfStatus := make(map[string]bool) grade = Good for _, addr := range addrs.([]string) { ip := net.ParseIP(addr) for _, cfNet := range cloudflareNets { if cfNet.Contains(ip) { cfStatus[addr] = true break } } if !cfStatus[addr] { cfStatus[addr] = false grade = Bad } } output = cfStatus return } // tcpDialScan tests that the host can be connected to through TCP. func tcpDialScan(addr, hostname string) (grade Grade, output Output, err error) { conn, err := Dialer.Dial(Network, addr) if err != nil { return } conn.Close() grade = Good return } // tlsDialScan tests that the host can perform a TLS Handshake // and warns if the server's certificate can't be verified. func tlsDialScan(addr, hostname string) (grade Grade, output Output, err error) { var conn *tls.Conn config := defaultTLSConfig(hostname) if conn, err = tls.DialWithDialer(Dialer, Network, addr, config); err != nil { return } conn.Close() config.InsecureSkipVerify = false if conn, err = tls.DialWithDialer(Dialer, Network, addr, config); err != nil { grade = Warning return } conn.Close() grade = Good return } ================================================ FILE: scan/crypto/crypto.go ================================================ // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package crypto collects common cryptographic constants. package crypto import ( "hash" "io" "strconv" ) // Hash identifies a cryptographic hash function that is implemented in another // package. type Hash uint // HashFunc simply returns the value of h so that Hash implements SignerOpts. func (h Hash) HashFunc() Hash { return h } const ( MD4 Hash = 1 + iota // import golang.org/x/crypto/md4 MD5 // import crypto/md5 SHA1 // import crypto/sha1 SHA224 // import crypto/sha256 SHA256 // import crypto/sha256 SHA384 // import crypto/sha512 SHA512 // import crypto/sha512 MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA RIPEMD160 // import golang.org/x/crypto/ripemd160 SHA3_224 // import golang.org/x/crypto/sha3 SHA3_256 // import golang.org/x/crypto/sha3 SHA3_384 // import golang.org/x/crypto/sha3 SHA3_512 // import golang.org/x/crypto/sha3 SHA512_224 // import crypto/sha512 SHA512_256 // import crypto/sha512 maxHash ) var digestSizes = []uint8{ MD4: 16, MD5: 16, SHA1: 20, SHA224: 28, SHA256: 32, SHA384: 48, SHA512: 64, SHA512_224: 28, SHA512_256: 32, SHA3_224: 28, SHA3_256: 32, SHA3_384: 48, SHA3_512: 64, MD5SHA1: 36, RIPEMD160: 20, } // Size returns the length, in bytes, of a digest resulting from the given hash // function. It doesn't require that the hash function in question be linked // into the program. func (h Hash) Size() int { if h > 0 && h < maxHash { return int(digestSizes[h]) } panic("crypto: Size of unknown hash function") } var hashes = make([]func() hash.Hash, maxHash) // New returns a new hash.Hash calculating the given hash function. New panics // if the hash function is not linked into the binary. func (h Hash) New() hash.Hash { if h > 0 && h < maxHash { f := hashes[h] if f != nil { return f() } } panic("crypto: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable") } // Available reports whether the given hash function is linked into the binary. func (h Hash) Available() bool { return h < maxHash && hashes[h] != nil } // RegisterHash registers a function that returns a new instance of the given // hash function. This is intended to be called from the init function in // packages that implement hash functions. func RegisterHash(h Hash, f func() hash.Hash) { if h >= maxHash { panic("crypto: RegisterHash of unknown hash function") } hashes[h] = f } // PublicKey represents a public key using an unspecified algorithm. type PublicKey interface{} // PrivateKey represents a private key using an unspecified algorithm. type PrivateKey interface{} // Signer is an interface for an opaque private key that can be used for // signing operations. For example, an RSA key kept in a hardware module. type Signer interface { // Public returns the public key corresponding to the opaque, // private key. Public() PublicKey // Sign signs digest with the private key, possibly using entropy from // rand. For an RSA key, the resulting signature should be either a // PKCS#1 v1.5 or PSS signature (as indicated by opts). For an (EC)DSA // key, it should be a DER-serialised, ASN.1 signature structure. // // Hash implements the SignerOpts interface and, in most cases, one can // simply pass in the hash function used as opts. Sign may also attempt // to type assert opts to other types in order to obtain algorithm // specific values. See the documentation in each package for details. // // Note that when a signature of a hash of a larger message is needed, // the caller is responsible for hashing the larger message and passing // the hash (as digest) and the hash function (as opts) to Sign. Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error) } // SignerOpts contains options for signing with a Signer. type SignerOpts interface { // HashFunc returns an identifier for the hash function used to produce // the message passed to Signer.Sign, or else zero to indicate that no // hashing was done. HashFunc() Hash } // Decrypter is an interface for an opaque private key that can be used for // asymmetric decryption operations. An example would be an RSA key // kept in a hardware module. type Decrypter interface { // Public returns the public key corresponding to the opaque, // private key. Public() PublicKey // Decrypt decrypts msg. The opts argument should be appropriate for // the primitive used. See the documentation in each implementation for // details. Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error) } type DecrypterOpts interface{} ================================================ FILE: scan/crypto/md5/example_test.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package md5_test import ( "crypto/md5" "fmt" "io" ) func ExampleNew() { h := md5.New() io.WriteString(h, "The fog is getting thicker!") io.WriteString(h, "And Leon's getting laaarger!") fmt.Printf("%x", h.Sum(nil)) // Output: e2c569be17396eca2a2e3c11578123ed } func ExampleSum() { data := []byte("These pretzels are making me thirsty.") fmt.Printf("%x", md5.Sum(data)) // Output: b0804ec967f48520697662a204f5fe72 } ================================================ FILE: scan/crypto/md5/gen.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build ignore // +build ignore // This program generates md5block.go // Invoke as // // go run gen.go [-full] -output md5block.go // // The -full flag causes the generated code to do a full // (16x) unrolling instead of a 4x unrolling. package main import ( "bytes" "flag" "go/format" "log" "strings" "text/template" ) var filename = flag.String("output", "md5block.go", "output file name") func main() { flag.Parse() var buf bytes.Buffer t := template.Must(template.New("main").Funcs(funcs).Parse(program)) if err := t.Execute(&buf, data); err != nil { log.Fatal(err) } data, err := format.Source(buf.Bytes()) if err != nil { log.Fatal(err) } err = os.WriteFile(*filename, data, 0644) if err != nil { log.Fatal(err) } } type Data struct { a, b, c, d string Shift1 []int Shift2 []int Shift3 []int Shift4 []int Table1 []uint32 Table2 []uint32 Table3 []uint32 Table4 []uint32 Full bool } var funcs = template.FuncMap{ "dup": dup, "relabel": relabel, "rotate": rotate, } func dup(count int, x []int) []int { var out []int for i := 0; i < count; i++ { out = append(out, x...) } return out } func relabel(s string) string { return strings.NewReplacer("a", data.a, "b", data.b, "c", data.c, "d", data.d).Replace(s) } func rotate() string { data.a, data.b, data.c, data.d = data.d, data.a, data.b, data.c return "" // no output } func init() { flag.BoolVar(&data.Full, "full", false, "complete unrolling") } var data = Data{ a: "a", b: "b", c: "c", d: "d", Shift1: []int{7, 12, 17, 22}, Shift2: []int{5, 9, 14, 20}, Shift3: []int{4, 11, 16, 23}, Shift4: []int{6, 10, 15, 21}, // table[i] = int((1<<32) * abs(sin(i+1 radians))). Table1: []uint32{ // round 1 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, }, Table2: []uint32{ // round 2 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, }, Table3: []uint32{ // round3 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, }, Table4: []uint32{ // round 4 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }, } var program = `// Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // DO NOT EDIT. // Generate with: go run gen.go{{if .Full}} -full{{end}} -output md5block.go package md5 import ( "unsafe" "runtime" ) {{if not .Full}} var t1 = [...]uint32{ {{range .Table1}}{{printf "\t%#x,\n" .}}{{end}} } var t2 = [...]uint32{ {{range .Table2}}{{printf "\t%#x,\n" .}}{{end}} } var t3 = [...]uint32{ {{range .Table3}}{{printf "\t%#x,\n" .}}{{end}} } var t4 = [...]uint32{ {{range .Table4}}{{printf "\t%#x,\n" .}}{{end}} } {{end}} const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386" var littleEndian bool func init() { x := uint32(0x04030201) y := [4]byte{0x1, 0x2, 0x3, 0x4} littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y } func blockGeneric(dig *digest, p []byte) { a := dig.s[0] b := dig.s[1] c := dig.s[2] d := dig.s[3] var X *[16]uint32 var xbuf [16]uint32 for len(p) >= chunk { aa, bb, cc, dd := a, b, c, d // This is a constant condition - it is not evaluated on each iteration. if x86 { // MD5 was designed so that x86 processors can just iterate // over the block data directly as uint32s, and we generate // less code and run 1.3x faster if we take advantage of that. // My apologies. X = (*[16]uint32)(unsafe.Pointer(&p[0])) } else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 { X = (*[16]uint32)(unsafe.Pointer(&p[0])) } else { X = &xbuf j := 0 for i := 0; i < 16; i++ { X[i&15] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24 j += 4 } } {{if .Full}} // Round 1. {{range $i, $s := dup 4 .Shift1}} {{index $.Table1 $i | printf "a += (((c^d)&b)^d) + X[%d] + %d" $i | relabel}} {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} {{rotate}} {{end}} // Round 2. {{range $i, $s := dup 4 .Shift2}} {{index $.Table2 $i | printf "a += (((b^c)&d)^c) + X[(1+5*%d)&15] + %d" $i | relabel}} {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} {{rotate}} {{end}} // Round 3. {{range $i, $s := dup 4 .Shift3}} {{index $.Table3 $i | printf "a += (b^c^d) + X[(5+3*%d)&15] + %d" $i | relabel}} {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} {{rotate}} {{end}} // Round 4. {{range $i, $s := dup 4 .Shift4}} {{index $.Table4 $i | printf "a += (c^(b|^d)) + X[(7*%d)&15] + %d" $i | relabel}} {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} {{rotate}} {{end}} {{else}} // Round 1. for i := uint(0); i < 16; { {{range $s := .Shift1}} {{printf "a += (((c^d)&b)^d) + X[i&15] + t1[i&15]" | relabel}} {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} i++ {{rotate}} {{end}} } // Round 2. for i := uint(0); i < 16; { {{range $s := .Shift2}} {{printf "a += (((b^c)&d)^c) + X[(1+5*i)&15] + t2[i&15]" | relabel}} {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} i++ {{rotate}} {{end}} } // Round 3. for i := uint(0); i < 16; { {{range $s := .Shift3}} {{printf "a += (b^c^d) + X[(5+3*i)&15] + t3[i&15]" | relabel}} {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} i++ {{rotate}} {{end}} } // Round 4. for i := uint(0); i < 16; { {{range $s := .Shift4}} {{printf "a += (c^(b|^d)) + X[(7*i)&15] + t4[i&15]" | relabel}} {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} i++ {{rotate}} {{end}} } {{end}} a += aa b += bb c += cc d += dd p = p[chunk:] } dig.s[0] = a dig.s[1] = b dig.s[2] = c dig.s[3] = d } ` ================================================ FILE: scan/crypto/md5/md5.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:generate go run gen.go -full -output md5block.go // Package md5 implements the MD5 hash algorithm as defined in RFC 1321. package md5 import ( "crypto" "hash" ) func init() { crypto.RegisterHash(crypto.MD5, New) } // The size of an MD5 checksum in bytes. const Size = 16 // The blocksize of MD5 in bytes. const BlockSize = 64 const ( chunk = 64 init0 = 0x67452301 init1 = 0xEFCDAB89 init2 = 0x98BADCFE init3 = 0x10325476 ) // digest represents the partial evaluation of a checksum. type digest struct { s [4]uint32 x [chunk]byte nx int len uint64 } func (d *digest) Reset() { d.s[0] = init0 d.s[1] = init1 d.s[2] = init2 d.s[3] = init3 d.nx = 0 d.len = 0 } // New returns a new hash.Hash computing the MD5 checksum. func New() hash.Hash { d := new(digest) d.Reset() return d } func (d *digest) Size() int { return Size } func (d *digest) BlockSize() int { return BlockSize } func (d *digest) Write(p []byte) (nn int, err error) { nn = len(p) d.len += uint64(nn) if d.nx > 0 { n := copy(d.x[d.nx:], p) d.nx += n if d.nx == chunk { block(d, d.x[:]) d.nx = 0 } p = p[n:] } if len(p) >= chunk { n := len(p) &^ (chunk - 1) block(d, p[:n]) p = p[n:] } if len(p) > 0 { d.nx = copy(d.x[:], p) } return } func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0 so that caller can keep writing and summing. d := *d0 hash := d.checkSum() return append(in, hash[:]...) } func (d *digest) checkSum() [Size]byte { // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. len := d.len var tmp [64]byte tmp[0] = 0x80 if len%64 < 56 { d.Write(tmp[0 : 56-len%64]) } else { d.Write(tmp[0 : 64+56-len%64]) } // Length in bits. len <<= 3 for i := uint(0); i < 8; i++ { tmp[i] = byte(len >> (8 * i)) } d.Write(tmp[0:8]) if d.nx != 0 { panic("d.nx != 0") } var digest [Size]byte for i, s := range d.s { digest[i*4] = byte(s) digest[i*4+1] = byte(s >> 8) digest[i*4+2] = byte(s >> 16) digest[i*4+3] = byte(s >> 24) } return digest } // Sum returns the MD5 checksum of the data. func Sum(data []byte) [Size]byte { var d digest d.Reset() d.Write(data) return d.checkSum() } ================================================ FILE: scan/crypto/md5/md5_test.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package md5 import ( "crypto/rand" "fmt" "io" "testing" "unsafe" ) type md5Test struct { out string in string } var golden = []md5Test{ {"d41d8cd98f00b204e9800998ecf8427e", ""}, {"0cc175b9c0f1b6a831c399e269772661", "a"}, {"187ef4436122d1cc2f40dc2b92f0eba0", "ab"}, {"900150983cd24fb0d6963f7d28e17f72", "abc"}, {"e2fc714c4727ee9395f324cd2e7f331f", "abcd"}, {"ab56b4d92b40713acc5af89985d4b786", "abcde"}, {"e80b5017098950fc58aad83c8c14978e", "abcdef"}, {"7ac66c0f148de9519b8bd264312c4d64", "abcdefg"}, {"e8dc4081b13434b45189a720b77b6818", "abcdefgh"}, {"8aa99b1f439ff71293e95357bac6fd94", "abcdefghi"}, {"a925576942e94b2ef57a066101b48876", "abcdefghij"}, {"d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old."}, {"bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last."}, {"0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole."}, {"9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, {"a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered. -Tom Stoppard"}, {"e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign."}, {"637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program."}, {"834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine."}, {"de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, {"acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, {"e1c1384cb4d2221dfdd7c795a4222c9a", "size: a.out: bad magic"}, {"c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail. -Mark Horton"}, {"cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, {"83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you."}, {"277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams."}, {"fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway."}, {"469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!"}, {"63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, {"72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, {"132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++? -Paul Glick"}, } func TestGolden(t *testing.T) { for i := 0; i < len(golden); i++ { g := golden[i] s := fmt.Sprintf("%x", Sum([]byte(g.in))) if s != g.out { t.Fatalf("Sum function: md5(%s) = %s want %s", g.in, s, g.out) } c := New() buf := make([]byte, len(g.in)+4) for j := 0; j < 3+4; j++ { if j < 2 { io.WriteString(c, g.in) } else if j == 2 { io.WriteString(c, g.in[0:len(g.in)/2]) c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } else if j > 2 { // test unaligned write buf = buf[1:] copy(buf, g.in) c.Write(buf[:len(g.in)]) } s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("md5[%d](%s) = %s want %s", j, g.in, s, g.out) } c.Reset() } } } func TestLarge(t *testing.T) { const N = 10000 ok := "2bb571599a4180e1d542f76904adc3df" // md5sum of "0123456789" * 1000 block := make([]byte, 10004) c := New() for offset := 0; offset < 4; offset++ { for i := 0; i < N; i++ { block[offset+i] = '0' + byte(i%10) } for blockSize := 10; blockSize <= N; blockSize *= 10 { blocks := N / blockSize b := block[offset : offset+blockSize] c.Reset() for i := 0; i < blocks; i++ { c.Write(b) } s := fmt.Sprintf("%x", c.Sum(nil)) if s != ok { t.Fatalf("md5 TestLarge offset=%d, blockSize=%d = %s want %s", offset, blockSize, s, ok) } } } } // Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match. func TestBlockGeneric(t *testing.T) { gen, asm := New().(*digest), New().(*digest) buf := make([]byte, BlockSize*20) // arbitrary factor rand.Read(buf) blockGeneric(gen, buf) block(asm, buf) if *gen != *asm { t.Error("block and blockGeneric resulted in different states") } } var bench = New() var buf = make([]byte, 8192+1) var sum = make([]byte, bench.Size()) func benchmarkSize(b *testing.B, size int, unaligned bool) { b.SetBytes(int64(size)) buf := buf if unaligned { if uintptr(unsafe.Pointer(&buf[0]))&(unsafe.Alignof(uint32(0))-1) == 0 { buf = buf[1:] } } b.ResetTimer() for i := 0; i < b.N; i++ { bench.Reset() bench.Write(buf[:size]) bench.Sum(sum[:0]) } } func BenchmarkHash8Bytes(b *testing.B) { benchmarkSize(b, 8, false) } func BenchmarkHash1K(b *testing.B) { benchmarkSize(b, 1024, false) } func BenchmarkHash8K(b *testing.B) { benchmarkSize(b, 8192, false) } func BenchmarkHash8BytesUnaligned(b *testing.B) { benchmarkSize(b, 8, true) } func BenchmarkHash1KUnaligned(b *testing.B) { benchmarkSize(b, 1024, true) } func BenchmarkHash8KUnaligned(b *testing.B) { benchmarkSize(b, 8192, true) } ================================================ FILE: scan/crypto/md5/md5block.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // DO NOT EDIT. // Generate with: go run gen.go -full -output md5block.go package md5 import ( "runtime" "unsafe" ) const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386" var littleEndian bool func init() { x := uint32(0x04030201) y := [4]byte{0x1, 0x2, 0x3, 0x4} littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y } func blockGeneric(dig *digest, p []byte) { a := dig.s[0] b := dig.s[1] c := dig.s[2] d := dig.s[3] var X *[16]uint32 var xbuf [16]uint32 for len(p) >= chunk { aa, bb, cc, dd := a, b, c, d // This is a constant condition - it is not evaluated on each iteration. if x86 { // MD5 was designed so that x86 processors can just iterate // over the block data directly as uint32s, and we generate // less code and run 1.3x faster if we take advantage of that. // My apologies. X = (*[16]uint32)(unsafe.Pointer(&p[0])) } else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 { X = (*[16]uint32)(unsafe.Pointer(&p[0])) } else { X = &xbuf j := 0 for i := 0; i < 16; i++ { X[i&15] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24 j += 4 } } // Round 1. a += (((c ^ d) & b) ^ d) + X[0] + 3614090360 a = a<<7 | a>>(32-7) + b d += (((b ^ c) & a) ^ c) + X[1] + 3905402710 d = d<<12 | d>>(32-12) + a c += (((a ^ b) & d) ^ b) + X[2] + 606105819 c = c<<17 | c>>(32-17) + d b += (((d ^ a) & c) ^ a) + X[3] + 3250441966 b = b<<22 | b>>(32-22) + c a += (((c ^ d) & b) ^ d) + X[4] + 4118548399 a = a<<7 | a>>(32-7) + b d += (((b ^ c) & a) ^ c) + X[5] + 1200080426 d = d<<12 | d>>(32-12) + a c += (((a ^ b) & d) ^ b) + X[6] + 2821735955 c = c<<17 | c>>(32-17) + d b += (((d ^ a) & c) ^ a) + X[7] + 4249261313 b = b<<22 | b>>(32-22) + c a += (((c ^ d) & b) ^ d) + X[8] + 1770035416 a = a<<7 | a>>(32-7) + b d += (((b ^ c) & a) ^ c) + X[9] + 2336552879 d = d<<12 | d>>(32-12) + a c += (((a ^ b) & d) ^ b) + X[10] + 4294925233 c = c<<17 | c>>(32-17) + d b += (((d ^ a) & c) ^ a) + X[11] + 2304563134 b = b<<22 | b>>(32-22) + c a += (((c ^ d) & b) ^ d) + X[12] + 1804603682 a = a<<7 | a>>(32-7) + b d += (((b ^ c) & a) ^ c) + X[13] + 4254626195 d = d<<12 | d>>(32-12) + a c += (((a ^ b) & d) ^ b) + X[14] + 2792965006 c = c<<17 | c>>(32-17) + d b += (((d ^ a) & c) ^ a) + X[15] + 1236535329 b = b<<22 | b>>(32-22) + c // Round 2. a += (((b ^ c) & d) ^ c) + X[(1+5*0)&15] + 4129170786 a = a<<5 | a>>(32-5) + b d += (((a ^ b) & c) ^ b) + X[(1+5*1)&15] + 3225465664 d = d<<9 | d>>(32-9) + a c += (((d ^ a) & b) ^ a) + X[(1+5*2)&15] + 643717713 c = c<<14 | c>>(32-14) + d b += (((c ^ d) & a) ^ d) + X[(1+5*3)&15] + 3921069994 b = b<<20 | b>>(32-20) + c a += (((b ^ c) & d) ^ c) + X[(1+5*4)&15] + 3593408605 a = a<<5 | a>>(32-5) + b d += (((a ^ b) & c) ^ b) + X[(1+5*5)&15] + 38016083 d = d<<9 | d>>(32-9) + a c += (((d ^ a) & b) ^ a) + X[(1+5*6)&15] + 3634488961 c = c<<14 | c>>(32-14) + d b += (((c ^ d) & a) ^ d) + X[(1+5*7)&15] + 3889429448 b = b<<20 | b>>(32-20) + c a += (((b ^ c) & d) ^ c) + X[(1+5*8)&15] + 568446438 a = a<<5 | a>>(32-5) + b d += (((a ^ b) & c) ^ b) + X[(1+5*9)&15] + 3275163606 d = d<<9 | d>>(32-9) + a c += (((d ^ a) & b) ^ a) + X[(1+5*10)&15] + 4107603335 c = c<<14 | c>>(32-14) + d b += (((c ^ d) & a) ^ d) + X[(1+5*11)&15] + 1163531501 b = b<<20 | b>>(32-20) + c a += (((b ^ c) & d) ^ c) + X[(1+5*12)&15] + 2850285829 a = a<<5 | a>>(32-5) + b d += (((a ^ b) & c) ^ b) + X[(1+5*13)&15] + 4243563512 d = d<<9 | d>>(32-9) + a c += (((d ^ a) & b) ^ a) + X[(1+5*14)&15] + 1735328473 c = c<<14 | c>>(32-14) + d b += (((c ^ d) & a) ^ d) + X[(1+5*15)&15] + 2368359562 b = b<<20 | b>>(32-20) + c // Round 3. a += (b ^ c ^ d) + X[(5+3*0)&15] + 4294588738 a = a<<4 | a>>(32-4) + b d += (a ^ b ^ c) + X[(5+3*1)&15] + 2272392833 d = d<<11 | d>>(32-11) + a c += (d ^ a ^ b) + X[(5+3*2)&15] + 1839030562 c = c<<16 | c>>(32-16) + d b += (c ^ d ^ a) + X[(5+3*3)&15] + 4259657740 b = b<<23 | b>>(32-23) + c a += (b ^ c ^ d) + X[(5+3*4)&15] + 2763975236 a = a<<4 | a>>(32-4) + b d += (a ^ b ^ c) + X[(5+3*5)&15] + 1272893353 d = d<<11 | d>>(32-11) + a c += (d ^ a ^ b) + X[(5+3*6)&15] + 4139469664 c = c<<16 | c>>(32-16) + d b += (c ^ d ^ a) + X[(5+3*7)&15] + 3200236656 b = b<<23 | b>>(32-23) + c a += (b ^ c ^ d) + X[(5+3*8)&15] + 681279174 a = a<<4 | a>>(32-4) + b d += (a ^ b ^ c) + X[(5+3*9)&15] + 3936430074 d = d<<11 | d>>(32-11) + a c += (d ^ a ^ b) + X[(5+3*10)&15] + 3572445317 c = c<<16 | c>>(32-16) + d b += (c ^ d ^ a) + X[(5+3*11)&15] + 76029189 b = b<<23 | b>>(32-23) + c a += (b ^ c ^ d) + X[(5+3*12)&15] + 3654602809 a = a<<4 | a>>(32-4) + b d += (a ^ b ^ c) + X[(5+3*13)&15] + 3873151461 d = d<<11 | d>>(32-11) + a c += (d ^ a ^ b) + X[(5+3*14)&15] + 530742520 c = c<<16 | c>>(32-16) + d b += (c ^ d ^ a) + X[(5+3*15)&15] + 3299628645 b = b<<23 | b>>(32-23) + c // Round 4. a += (c ^ (b | ^d)) + X[(7*0)&15] + 4096336452 a = a<<6 | a>>(32-6) + b d += (b ^ (a | ^c)) + X[(7*1)&15] + 1126891415 d = d<<10 | d>>(32-10) + a c += (a ^ (d | ^b)) + X[(7*2)&15] + 2878612391 c = c<<15 | c>>(32-15) + d b += (d ^ (c | ^a)) + X[(7*3)&15] + 4237533241 b = b<<21 | b>>(32-21) + c a += (c ^ (b | ^d)) + X[(7*4)&15] + 1700485571 a = a<<6 | a>>(32-6) + b d += (b ^ (a | ^c)) + X[(7*5)&15] + 2399980690 d = d<<10 | d>>(32-10) + a c += (a ^ (d | ^b)) + X[(7*6)&15] + 4293915773 c = c<<15 | c>>(32-15) + d b += (d ^ (c | ^a)) + X[(7*7)&15] + 2240044497 b = b<<21 | b>>(32-21) + c a += (c ^ (b | ^d)) + X[(7*8)&15] + 1873313359 a = a<<6 | a>>(32-6) + b d += (b ^ (a | ^c)) + X[(7*9)&15] + 4264355552 d = d<<10 | d>>(32-10) + a c += (a ^ (d | ^b)) + X[(7*10)&15] + 2734768916 c = c<<15 | c>>(32-15) + d b += (d ^ (c | ^a)) + X[(7*11)&15] + 1309151649 b = b<<21 | b>>(32-21) + c a += (c ^ (b | ^d)) + X[(7*12)&15] + 4149444226 a = a<<6 | a>>(32-6) + b d += (b ^ (a | ^c)) + X[(7*13)&15] + 3174756917 d = d<<10 | d>>(32-10) + a c += (a ^ (d | ^b)) + X[(7*14)&15] + 718787259 c = c<<15 | c>>(32-15) + d b += (d ^ (c | ^a)) + X[(7*15)&15] + 3951481745 b = b<<21 | b>>(32-21) + c a += aa b += bb c += cc d += dd p = p[chunk:] } dig.s[0] = a dig.s[1] = b dig.s[2] = c dig.s[3] = d } ================================================ FILE: scan/crypto/md5/md5block_386.s ================================================ // Original source: // http://www.zorinaq.com/papers/md5-amd64.html // http://www.zorinaq.com/papers/md5-amd64.tar.bz2 // // Translated from Perl generating GNU assembly into // #defines generating 8a assembly, and adjusted for 386, // by the Go Authors. #include "textflag.h" // MD5 optimized for AMD64. // // Author: Marc Bevand // Licence: I hereby disclaim the copyright on this code and place it // in the public domain. #define ROUND1(a, b, c, d, index, const, shift) \ XORL c, BP; \ LEAL const(a)(DI*1), a; \ ANDL b, BP; \ XORL d, BP; \ MOVL (index*4)(SI), DI; \ ADDL BP, a; \ ROLL $shift, a; \ MOVL c, BP; \ ADDL b, a #define ROUND2(a, b, c, d, index, const, shift) \ LEAL const(a)(DI*1),a; \ MOVL d, DI; \ ANDL b, DI; \ MOVL d, BP; \ NOTL BP; \ ANDL c, BP; \ ORL DI, BP; \ MOVL (index*4)(SI),DI; \ ADDL BP, a; \ ROLL $shift, a; \ ADDL b, a #define ROUND3(a, b, c, d, index, const, shift) \ LEAL const(a)(DI*1),a; \ MOVL (index*4)(SI),DI; \ XORL d, BP; \ XORL b, BP; \ ADDL BP, a; \ ROLL $shift, a; \ MOVL b, BP; \ ADDL b, a #define ROUND4(a, b, c, d, index, const, shift) \ LEAL const(a)(DI*1),a; \ ORL b, BP; \ XORL c, BP; \ ADDL BP, a; \ MOVL (index*4)(SI),DI; \ MOVL $0xffffffff, BP; \ ROLL $shift, a; \ XORL c, BP; \ ADDL b, a TEXT ·block(SB),NOSPLIT,$24-16 MOVL dig+0(FP), BP MOVL p+4(FP), SI MOVL p_len+8(FP), DX SHRL $6, DX SHLL $6, DX LEAL (SI)(DX*1), DI MOVL (0*4)(BP), AX MOVL (1*4)(BP), BX MOVL (2*4)(BP), CX MOVL (3*4)(BP), DX CMPL SI, DI JEQ end MOVL DI, 16(SP) loop: MOVL AX, 0(SP) MOVL BX, 4(SP) MOVL CX, 8(SP) MOVL DX, 12(SP) MOVL (0*4)(SI), DI MOVL DX, BP ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7); ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12); ROUND1(CX,DX,AX,BX, 3,0x242070db,17); ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22); ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7); ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12); ROUND1(CX,DX,AX,BX, 7,0xa8304613,17); ROUND1(BX,CX,DX,AX, 8,0xfd469501,22); ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7); ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12); ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17); ROUND1(BX,CX,DX,AX,12,0x895cd7be,22); ROUND1(AX,BX,CX,DX,13,0x6b901122, 7); ROUND1(DX,AX,BX,CX,14,0xfd987193,12); ROUND1(CX,DX,AX,BX,15,0xa679438e,17); ROUND1(BX,CX,DX,AX, 0,0x49b40821,22); MOVL (1*4)(SI), DI MOVL DX, BP ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5); ROUND2(DX,AX,BX,CX,11,0xc040b340, 9); ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14); ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20); ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5); ROUND2(DX,AX,BX,CX,15, 0x2441453, 9); ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14); ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20); ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5); ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9); ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14); ROUND2(BX,CX,DX,AX,13,0x455a14ed,20); ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5); ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9); ROUND2(CX,DX,AX,BX,12,0x676f02d9,14); ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20); MOVL (5*4)(SI), DI MOVL CX, BP ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4); ROUND3(DX,AX,BX,CX,11,0x8771f681,11); ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16); ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23); ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4); ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11); ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16); ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23); ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4); ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11); ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16); ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23); ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4); ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11); ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16); ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23); MOVL (0*4)(SI), DI MOVL $0xffffffff, BP XORL DX, BP ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6); ROUND4(DX,AX,BX,CX,14,0x432aff97,10); ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15); ROUND4(BX,CX,DX,AX,12,0xfc93a039,21); ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6); ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10); ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15); ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21); ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6); ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10); ROUND4(CX,DX,AX,BX,13,0xa3014314,15); ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21); ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6); ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10); ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15); ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21); ADDL 0(SP), AX ADDL 4(SP), BX ADDL 8(SP), CX ADDL 12(SP), DX ADDL $64, SI CMPL SI, 16(SP) JB loop end: MOVL dig+0(FP), BP MOVL AX, (0*4)(BP) MOVL BX, (1*4)(BP) MOVL CX, (2*4)(BP) MOVL DX, (3*4)(BP) RET ================================================ FILE: scan/crypto/md5/md5block_amd64.s ================================================ // Original source: // http://www.zorinaq.com/papers/md5-amd64.html // http://www.zorinaq.com/papers/md5-amd64.tar.bz2 // // Translated from Perl generating GNU assembly into // #defines generating 6a assembly by the Go Authors. #include "textflag.h" // MD5 optimized for AMD64. // // Author: Marc Bevand // Licence: I hereby disclaim the copyright on this code and place it // in the public domain. TEXT ·block(SB),NOSPLIT,$0-32 MOVQ dig+0(FP), BP MOVQ p+8(FP), SI MOVQ p_len+16(FP), DX SHRQ $6, DX SHLQ $6, DX LEAQ (SI)(DX*1), DI MOVL (0*4)(BP), AX MOVL (1*4)(BP), BX MOVL (2*4)(BP), CX MOVL (3*4)(BP), DX CMPQ SI, DI JEQ end loop: MOVL AX, R12 MOVL BX, R13 MOVL CX, R14 MOVL DX, R15 MOVL (0*4)(SI), R8 MOVL DX, R9 #define ROUND1(a, b, c, d, index, const, shift) \ XORL c, R9; \ LEAL const(a)(R8*1), a; \ ANDL b, R9; \ XORL d, R9; \ MOVL (index*4)(SI), R8; \ ADDL R9, a; \ ROLL $shift, a; \ MOVL c, R9; \ ADDL b, a ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7); ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12); ROUND1(CX,DX,AX,BX, 3,0x242070db,17); ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22); ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7); ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12); ROUND1(CX,DX,AX,BX, 7,0xa8304613,17); ROUND1(BX,CX,DX,AX, 8,0xfd469501,22); ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7); ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12); ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17); ROUND1(BX,CX,DX,AX,12,0x895cd7be,22); ROUND1(AX,BX,CX,DX,13,0x6b901122, 7); ROUND1(DX,AX,BX,CX,14,0xfd987193,12); ROUND1(CX,DX,AX,BX,15,0xa679438e,17); ROUND1(BX,CX,DX,AX, 0,0x49b40821,22); MOVL (1*4)(SI), R8 MOVL DX, R9 MOVL DX, R10 #define ROUND2(a, b, c, d, index, const, shift) \ NOTL R9; \ LEAL const(a)(R8*1),a; \ ANDL b, R10; \ ANDL c, R9; \ MOVL (index*4)(SI),R8; \ ORL R9, R10; \ MOVL c, R9; \ ADDL R10, a; \ MOVL c, R10; \ ROLL $shift, a; \ ADDL b, a ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5); ROUND2(DX,AX,BX,CX,11,0xc040b340, 9); ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14); ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20); ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5); ROUND2(DX,AX,BX,CX,15, 0x2441453, 9); ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14); ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20); ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5); ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9); ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14); ROUND2(BX,CX,DX,AX,13,0x455a14ed,20); ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5); ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9); ROUND2(CX,DX,AX,BX,12,0x676f02d9,14); ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20); MOVL (5*4)(SI), R8 MOVL CX, R9 #define ROUND3(a, b, c, d, index, const, shift) \ LEAL const(a)(R8*1),a; \ MOVL (index*4)(SI),R8; \ XORL d, R9; \ XORL b, R9; \ ADDL R9, a; \ ROLL $shift, a; \ MOVL b, R9; \ ADDL b, a ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4); ROUND3(DX,AX,BX,CX,11,0x8771f681,11); ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16); ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23); ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4); ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11); ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16); ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23); ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4); ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11); ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16); ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23); ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4); ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11); ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16); ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23); MOVL (0*4)(SI), R8 MOVL $0xffffffff, R9 XORL DX, R9 #define ROUND4(a, b, c, d, index, const, shift) \ LEAL const(a)(R8*1),a; \ ORL b, R9; \ XORL c, R9; \ ADDL R9, a; \ MOVL (index*4)(SI),R8; \ MOVL $0xffffffff, R9; \ ROLL $shift, a; \ XORL c, R9; \ ADDL b, a ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6); ROUND4(DX,AX,BX,CX,14,0x432aff97,10); ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15); ROUND4(BX,CX,DX,AX,12,0xfc93a039,21); ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6); ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10); ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15); ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21); ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6); ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10); ROUND4(CX,DX,AX,BX,13,0xa3014314,15); ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21); ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6); ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10); ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15); ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21); ADDL R12, AX ADDL R13, BX ADDL R14, CX ADDL R15, DX ADDQ $64, SI CMPQ SI, DI JB loop end: MOVL AX, (0*4)(BP) MOVL BX, (1*4)(BP) MOVL CX, (2*4)(BP) MOVL DX, (3*4)(BP) RET ================================================ FILE: scan/crypto/md5/md5block_amd64p32.s ================================================ // Original source: // http://www.zorinaq.com/papers/md5-amd64.html // http://www.zorinaq.com/papers/md5-amd64.tar.bz2 // // Translated from Perl generating GNU assembly into // #defines generating 6a assembly by the Go Authors. // // Restrictions to make code safe for Native Client: // replace BP with R11, reloaded before use at return. // replace R15 with R11. #include "textflag.h" // MD5 optimized for AMD64. // // Author: Marc Bevand // Licence: I hereby disclaim the copyright on this code and place it // in the public domain. TEXT ·block(SB),NOSPLIT,$0-32 MOVL dig+0(FP), R11 MOVL p+4(FP), SI MOVL p_len+8(FP), DX SHRQ $6, DX SHLQ $6, DX LEAQ (SI)(DX*1), DI MOVL (0*4)(R11), AX MOVL (1*4)(R11), BX MOVL (2*4)(R11), CX MOVL (3*4)(R11), DX CMPQ SI, DI JEQ end loop: MOVL AX, R12 MOVL BX, R13 MOVL CX, R14 MOVL DX, R11 MOVL (0*4)(SI), R8 MOVL DX, R9 #define ROUND1(a, b, c, d, index, const, shift) \ XORL c, R9; \ LEAL const(a)(R8*1), a; \ ANDL b, R9; \ XORL d, R9; \ MOVL (index*4)(SI), R8; \ ADDL R9, a; \ ROLL $shift, a; \ MOVL c, R9; \ ADDL b, a ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7); ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12); ROUND1(CX,DX,AX,BX, 3,0x242070db,17); ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22); ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7); ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12); ROUND1(CX,DX,AX,BX, 7,0xa8304613,17); ROUND1(BX,CX,DX,AX, 8,0xfd469501,22); ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7); ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12); ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17); ROUND1(BX,CX,DX,AX,12,0x895cd7be,22); ROUND1(AX,BX,CX,DX,13,0x6b901122, 7); ROUND1(DX,AX,BX,CX,14,0xfd987193,12); ROUND1(CX,DX,AX,BX,15,0xa679438e,17); ROUND1(BX,CX,DX,AX, 0,0x49b40821,22); MOVL (1*4)(SI), R8 MOVL DX, R9 MOVL DX, R10 #define ROUND2(a, b, c, d, index, const, shift) \ NOTL R9; \ LEAL const(a)(R8*1),a; \ ANDL b, R10; \ ANDL c, R9; \ MOVL (index*4)(SI),R8; \ ORL R9, R10; \ MOVL c, R9; \ ADDL R10, a; \ MOVL c, R10; \ ROLL $shift, a; \ ADDL b, a ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5); ROUND2(DX,AX,BX,CX,11,0xc040b340, 9); ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14); ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20); ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5); ROUND2(DX,AX,BX,CX,15, 0x2441453, 9); ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14); ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20); ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5); ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9); ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14); ROUND2(BX,CX,DX,AX,13,0x455a14ed,20); ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5); ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9); ROUND2(CX,DX,AX,BX,12,0x676f02d9,14); ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20); MOVL (5*4)(SI), R8 MOVL CX, R9 #define ROUND3(a, b, c, d, index, const, shift) \ LEAL const(a)(R8*1),a; \ MOVL (index*4)(SI),R8; \ XORL d, R9; \ XORL b, R9; \ ADDL R9, a; \ ROLL $shift, a; \ MOVL b, R9; \ ADDL b, a ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4); ROUND3(DX,AX,BX,CX,11,0x8771f681,11); ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16); ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23); ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4); ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11); ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16); ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23); ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4); ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11); ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16); ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23); ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4); ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11); ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16); ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23); MOVL (0*4)(SI), R8 MOVL $0xffffffff, R9 XORL DX, R9 #define ROUND4(a, b, c, d, index, const, shift) \ LEAL const(a)(R8*1),a; \ ORL b, R9; \ XORL c, R9; \ ADDL R9, a; \ MOVL (index*4)(SI),R8; \ MOVL $0xffffffff, R9; \ ROLL $shift, a; \ XORL c, R9; \ ADDL b, a ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6); ROUND4(DX,AX,BX,CX,14,0x432aff97,10); ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15); ROUND4(BX,CX,DX,AX,12,0xfc93a039,21); ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6); ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10); ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15); ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21); ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6); ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10); ROUND4(CX,DX,AX,BX,13,0xa3014314,15); ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21); ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6); ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10); ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15); ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21); ADDL R12, AX ADDL R13, BX ADDL R14, CX ADDL R11, DX ADDQ $64, SI CMPQ SI, DI JB loop end: MOVL dig+0(FP), R11 MOVL AX, (0*4)(R11) MOVL BX, (1*4)(R11) MOVL CX, (2*4)(R11) MOVL DX, (3*4)(R11) RET ================================================ FILE: scan/crypto/md5/md5block_arm.s ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // ARM version of md5block.go #include "textflag.h" // Register definitions #define Rtable R0 // Pointer to MD5 constants table #define Rdata R1 // Pointer to data to hash #define Ra R2 // MD5 accumulator #define Rb R3 // MD5 accumulator #define Rc R4 // MD5 accumulator #define Rd R5 // MD5 accumulator #define Rc0 R6 // MD5 constant #define Rc1 R7 // MD5 constant #define Rc2 R8 // MD5 constant // r9, r10 are forbidden // r11 is OK provided you check the assembler that no synthetic instructions use it #define Rc3 R11 // MD5 constant #define Rt0 R12 // temporary #define Rt1 R14 // temporary // func block(dig *digest, p []byte) // 0(FP) is *digest // 4(FP) is p.array (struct Slice) // 8(FP) is p.len //12(FP) is p.cap // // Stack frame #define p_end end-4(SP) // pointer to the end of data #define p_data data-8(SP) // current data pointer #define buf buffer-(8+4*16)(SP) //16 words temporary buffer // 3 words at 4..12(R13) for called routine parameters TEXT ·block(SB), NOSPLIT, $84-16 MOVW p+4(FP), Rdata // pointer to the data MOVW p_len+8(FP), Rt0 // number of bytes ADD Rdata, Rt0 MOVW Rt0, p_end // pointer to end of data loop: MOVW Rdata, p_data // Save Rdata AND.S $3, Rdata, Rt0 // TST $3, Rdata not working see issue 5921 BEQ aligned // aligned detected - skip copy // Copy the unaligned source data into the aligned temporary buffer // memove(to=4(R13), from=8(R13), n=12(R13)) - Corrupts all registers MOVW $buf, Rtable // to MOVW $64, Rc0 // n MOVM.IB [Rtable,Rdata,Rc0], (R13) BL runtime·memmove(SB) // Point to the local aligned copy of the data MOVW $buf, Rdata aligned: // Point to the table of constants // A PC relative add would be cheaper than this MOVW $·table(SB), Rtable // Load up initial MD5 accumulator MOVW dig+0(FP), Rc0 MOVM.IA (Rc0), [Ra,Rb,Rc,Rd] // a += (((c^d)&b)^d) + X[index] + const // a = a<>(32-shift) + b #define ROUND1(Ra, Rb, Rc, Rd, index, shift, Rconst) \ EOR Rc, Rd, Rt0 ; \ AND Rb, Rt0 ; \ EOR Rd, Rt0 ; \ MOVW (index<<2)(Rdata), Rt1 ; \ ADD Rt1, Rt0 ; \ ADD Rconst, Rt0 ; \ ADD Rt0, Ra ; \ ADD Ra@>(32-shift), Rb, Ra ; MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND1(Ra, Rb, Rc, Rd, 0, 7, Rc0) ROUND1(Rd, Ra, Rb, Rc, 1, 12, Rc1) ROUND1(Rc, Rd, Ra, Rb, 2, 17, Rc2) ROUND1(Rb, Rc, Rd, Ra, 3, 22, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND1(Ra, Rb, Rc, Rd, 4, 7, Rc0) ROUND1(Rd, Ra, Rb, Rc, 5, 12, Rc1) ROUND1(Rc, Rd, Ra, Rb, 6, 17, Rc2) ROUND1(Rb, Rc, Rd, Ra, 7, 22, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND1(Ra, Rb, Rc, Rd, 8, 7, Rc0) ROUND1(Rd, Ra, Rb, Rc, 9, 12, Rc1) ROUND1(Rc, Rd, Ra, Rb, 10, 17, Rc2) ROUND1(Rb, Rc, Rd, Ra, 11, 22, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND1(Ra, Rb, Rc, Rd, 12, 7, Rc0) ROUND1(Rd, Ra, Rb, Rc, 13, 12, Rc1) ROUND1(Rc, Rd, Ra, Rb, 14, 17, Rc2) ROUND1(Rb, Rc, Rd, Ra, 15, 22, Rc3) // a += (((b^c)&d)^c) + X[index] + const // a = a<>(32-shift) + b #define ROUND2(Ra, Rb, Rc, Rd, index, shift, Rconst) \ EOR Rb, Rc, Rt0 ; \ AND Rd, Rt0 ; \ EOR Rc, Rt0 ; \ MOVW (index<<2)(Rdata), Rt1 ; \ ADD Rt1, Rt0 ; \ ADD Rconst, Rt0 ; \ ADD Rt0, Ra ; \ ADD Ra@>(32-shift), Rb, Ra ; MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND2(Ra, Rb, Rc, Rd, 1, 5, Rc0) ROUND2(Rd, Ra, Rb, Rc, 6, 9, Rc1) ROUND2(Rc, Rd, Ra, Rb, 11, 14, Rc2) ROUND2(Rb, Rc, Rd, Ra, 0, 20, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND2(Ra, Rb, Rc, Rd, 5, 5, Rc0) ROUND2(Rd, Ra, Rb, Rc, 10, 9, Rc1) ROUND2(Rc, Rd, Ra, Rb, 15, 14, Rc2) ROUND2(Rb, Rc, Rd, Ra, 4, 20, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND2(Ra, Rb, Rc, Rd, 9, 5, Rc0) ROUND2(Rd, Ra, Rb, Rc, 14, 9, Rc1) ROUND2(Rc, Rd, Ra, Rb, 3, 14, Rc2) ROUND2(Rb, Rc, Rd, Ra, 8, 20, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND2(Ra, Rb, Rc, Rd, 13, 5, Rc0) ROUND2(Rd, Ra, Rb, Rc, 2, 9, Rc1) ROUND2(Rc, Rd, Ra, Rb, 7, 14, Rc2) ROUND2(Rb, Rc, Rd, Ra, 12, 20, Rc3) // a += (b^c^d) + X[index] + const // a = a<>(32-shift) + b #define ROUND3(Ra, Rb, Rc, Rd, index, shift, Rconst) \ EOR Rb, Rc, Rt0 ; \ EOR Rd, Rt0 ; \ MOVW (index<<2)(Rdata), Rt1 ; \ ADD Rt1, Rt0 ; \ ADD Rconst, Rt0 ; \ ADD Rt0, Ra ; \ ADD Ra@>(32-shift), Rb, Ra ; MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND3(Ra, Rb, Rc, Rd, 5, 4, Rc0) ROUND3(Rd, Ra, Rb, Rc, 8, 11, Rc1) ROUND3(Rc, Rd, Ra, Rb, 11, 16, Rc2) ROUND3(Rb, Rc, Rd, Ra, 14, 23, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND3(Ra, Rb, Rc, Rd, 1, 4, Rc0) ROUND3(Rd, Ra, Rb, Rc, 4, 11, Rc1) ROUND3(Rc, Rd, Ra, Rb, 7, 16, Rc2) ROUND3(Rb, Rc, Rd, Ra, 10, 23, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND3(Ra, Rb, Rc, Rd, 13, 4, Rc0) ROUND3(Rd, Ra, Rb, Rc, 0, 11, Rc1) ROUND3(Rc, Rd, Ra, Rb, 3, 16, Rc2) ROUND3(Rb, Rc, Rd, Ra, 6, 23, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND3(Ra, Rb, Rc, Rd, 9, 4, Rc0) ROUND3(Rd, Ra, Rb, Rc, 12, 11, Rc1) ROUND3(Rc, Rd, Ra, Rb, 15, 16, Rc2) ROUND3(Rb, Rc, Rd, Ra, 2, 23, Rc3) // a += (c^(b|^d)) + X[index] + const // a = a<>(32-shift) + b #define ROUND4(Ra, Rb, Rc, Rd, index, shift, Rconst) \ MVN Rd, Rt0 ; \ ORR Rb, Rt0 ; \ EOR Rc, Rt0 ; \ MOVW (index<<2)(Rdata), Rt1 ; \ ADD Rt1, Rt0 ; \ ADD Rconst, Rt0 ; \ ADD Rt0, Ra ; \ ADD Ra@>(32-shift), Rb, Ra ; MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND4(Ra, Rb, Rc, Rd, 0, 6, Rc0) ROUND4(Rd, Ra, Rb, Rc, 7, 10, Rc1) ROUND4(Rc, Rd, Ra, Rb, 14, 15, Rc2) ROUND4(Rb, Rc, Rd, Ra, 5, 21, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND4(Ra, Rb, Rc, Rd, 12, 6, Rc0) ROUND4(Rd, Ra, Rb, Rc, 3, 10, Rc1) ROUND4(Rc, Rd, Ra, Rb, 10, 15, Rc2) ROUND4(Rb, Rc, Rd, Ra, 1, 21, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND4(Ra, Rb, Rc, Rd, 8, 6, Rc0) ROUND4(Rd, Ra, Rb, Rc, 15, 10, Rc1) ROUND4(Rc, Rd, Ra, Rb, 6, 15, Rc2) ROUND4(Rb, Rc, Rd, Ra, 13, 21, Rc3) MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3] ROUND4(Ra, Rb, Rc, Rd, 4, 6, Rc0) ROUND4(Rd, Ra, Rb, Rc, 11, 10, Rc1) ROUND4(Rc, Rd, Ra, Rb, 2, 15, Rc2) ROUND4(Rb, Rc, Rd, Ra, 9, 21, Rc3) MOVW dig+0(FP), Rt0 MOVM.IA (Rt0), [Rc0,Rc1,Rc2,Rc3] ADD Rc0, Ra ADD Rc1, Rb ADD Rc2, Rc ADD Rc3, Rd MOVM.IA [Ra,Rb,Rc,Rd], (Rt0) MOVW p_data, Rdata MOVW p_end, Rt0 ADD $64, Rdata CMP Rt0, Rdata BLO loop RET // MD5 constants table // Round 1 DATA ·table+0x00(SB)/4, $0xd76aa478 DATA ·table+0x04(SB)/4, $0xe8c7b756 DATA ·table+0x08(SB)/4, $0x242070db DATA ·table+0x0c(SB)/4, $0xc1bdceee DATA ·table+0x10(SB)/4, $0xf57c0faf DATA ·table+0x14(SB)/4, $0x4787c62a DATA ·table+0x18(SB)/4, $0xa8304613 DATA ·table+0x1c(SB)/4, $0xfd469501 DATA ·table+0x20(SB)/4, $0x698098d8 DATA ·table+0x24(SB)/4, $0x8b44f7af DATA ·table+0x28(SB)/4, $0xffff5bb1 DATA ·table+0x2c(SB)/4, $0x895cd7be DATA ·table+0x30(SB)/4, $0x6b901122 DATA ·table+0x34(SB)/4, $0xfd987193 DATA ·table+0x38(SB)/4, $0xa679438e DATA ·table+0x3c(SB)/4, $0x49b40821 // Round 2 DATA ·table+0x40(SB)/4, $0xf61e2562 DATA ·table+0x44(SB)/4, $0xc040b340 DATA ·table+0x48(SB)/4, $0x265e5a51 DATA ·table+0x4c(SB)/4, $0xe9b6c7aa DATA ·table+0x50(SB)/4, $0xd62f105d DATA ·table+0x54(SB)/4, $0x02441453 DATA ·table+0x58(SB)/4, $0xd8a1e681 DATA ·table+0x5c(SB)/4, $0xe7d3fbc8 DATA ·table+0x60(SB)/4, $0x21e1cde6 DATA ·table+0x64(SB)/4, $0xc33707d6 DATA ·table+0x68(SB)/4, $0xf4d50d87 DATA ·table+0x6c(SB)/4, $0x455a14ed DATA ·table+0x70(SB)/4, $0xa9e3e905 DATA ·table+0x74(SB)/4, $0xfcefa3f8 DATA ·table+0x78(SB)/4, $0x676f02d9 DATA ·table+0x7c(SB)/4, $0x8d2a4c8a // Round 3 DATA ·table+0x80(SB)/4, $0xfffa3942 DATA ·table+0x84(SB)/4, $0x8771f681 DATA ·table+0x88(SB)/4, $0x6d9d6122 DATA ·table+0x8c(SB)/4, $0xfde5380c DATA ·table+0x90(SB)/4, $0xa4beea44 DATA ·table+0x94(SB)/4, $0x4bdecfa9 DATA ·table+0x98(SB)/4, $0xf6bb4b60 DATA ·table+0x9c(SB)/4, $0xbebfbc70 DATA ·table+0xa0(SB)/4, $0x289b7ec6 DATA ·table+0xa4(SB)/4, $0xeaa127fa DATA ·table+0xa8(SB)/4, $0xd4ef3085 DATA ·table+0xac(SB)/4, $0x04881d05 DATA ·table+0xb0(SB)/4, $0xd9d4d039 DATA ·table+0xb4(SB)/4, $0xe6db99e5 DATA ·table+0xb8(SB)/4, $0x1fa27cf8 DATA ·table+0xbc(SB)/4, $0xc4ac5665 // Round 4 DATA ·table+0xc0(SB)/4, $0xf4292244 DATA ·table+0xc4(SB)/4, $0x432aff97 DATA ·table+0xc8(SB)/4, $0xab9423a7 DATA ·table+0xcc(SB)/4, $0xfc93a039 DATA ·table+0xd0(SB)/4, $0x655b59c3 DATA ·table+0xd4(SB)/4, $0x8f0ccc92 DATA ·table+0xd8(SB)/4, $0xffeff47d DATA ·table+0xdc(SB)/4, $0x85845dd1 DATA ·table+0xe0(SB)/4, $0x6fa87e4f DATA ·table+0xe4(SB)/4, $0xfe2ce6e0 DATA ·table+0xe8(SB)/4, $0xa3014314 DATA ·table+0xec(SB)/4, $0x4e0811a1 DATA ·table+0xf0(SB)/4, $0xf7537e82 DATA ·table+0xf4(SB)/4, $0xbd3af235 DATA ·table+0xf8(SB)/4, $0x2ad7d2bb DATA ·table+0xfc(SB)/4, $0xeb86d391 // Global definition GLOBL ·table(SB),8,$256 ================================================ FILE: scan/crypto/md5/md5block_decl.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build amd64 || amd64p32 || 386 || arm // +build amd64 amd64p32 386 arm package md5 //go:noescape func block(dig *digest, p []byte) ================================================ FILE: scan/crypto/md5/md5block_generic.go ================================================ // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !amd64 && !amd64p32 && !386 && !arm // +build !amd64,!amd64p32,!386,!arm package md5 var block = blockGeneric ================================================ FILE: scan/crypto/rsa/example_test.go ================================================ // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rsa import ( "crypto" "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/sha256" "encoding/hex" "fmt" "io" "os" ) // RSA is able to encrypt only a very limited amount of data. In order // to encrypt reasonable amounts of data a hybrid scheme is commonly // used: RSA is used to encrypt a key for a symmetric primitive like // AES-GCM. // // Before encrypting, data is “padded” by embedding it in a known // structure. This is done for a number of reasons, but the most // obvious is to ensure that the value is large enough that the // exponentiation is larger than the modulus. (Otherwise it could be // decrypted with a square-root.) // // In these designs, when using PKCS#1 v1.5, it's vitally important to // avoid disclosing whether the received RSA message was well-formed // (that is, whether the result of decrypting is a correctly padded // message) because this leaks secret information. // DecryptPKCS1v15SessionKey is designed for this situation and copies // the decrypted, symmetric key (if well-formed) in constant-time over // a buffer that contains a random key. Thus, if the RSA result isn't // well-formed, the implementation uses a random key in constant time. func ExampleDecryptPKCS1v15SessionKey() { // crypto/rand.Reader is a good source of entropy for blinding the RSA // operation. rng := rand.Reader // The hybrid scheme should use at least a 16-byte symmetric key. Here // we read the random key that will be used if the RSA decryption isn't // well-formed. key := make([]byte, 32) if _, err := io.ReadFull(rng, key); err != nil { panic("RNG failure") } rsaCiphertext, _ := hex.DecodeString("aabbccddeeff") if err := DecryptPKCS1v15SessionKey(rng, rsaPrivateKey, rsaCiphertext, key); err != nil { // Any errors that result will be “public” – meaning that they // can be determined without any secret information. (For // instance, if the length of key is impossible given the RSA // public key.) fmt.Fprintf(os.Stderr, "Error from RSA decryption: %s\n", err) return } // Given the resulting key, a symmetric scheme can be used to decrypt a // larger ciphertext. block, err := aes.NewCipher(key) if err != nil { panic("aes.NewCipher failed: " + err.Error()) } // Since the key is random, using a fixed nonce is acceptable as the // (key, nonce) pair will still be unique, as required. var zeroNonce [12]byte aead, err := cipher.NewGCM(block) if err != nil { panic("cipher.NewGCM failed: " + err.Error()) } ciphertext, _ := hex.DecodeString("00112233445566") plaintext, err := aead.Open(nil, zeroNonce[:], ciphertext, nil) if err != nil { // The RSA ciphertext was badly formed; the decryption will // fail here because the AES-GCM key will be incorrect. fmt.Fprintf(os.Stderr, "Error decrypting: %s\n", err) return } fmt.Printf("Plaintext: %s\n", string(plaintext)) } func ExampleSignPKCS1v15() { // crypto/rand.Reader is a good source of entropy for blinding the RSA // operation. rng := rand.Reader message := []byte("message to be signed") // Only small messages can be signed directly; thus the hash of a // message, rather than the message itself, is signed. This requires // that the hash function be collision resistant. SHA-256 is the // least-strong hash function that should be used for this at the time // of writing (2016). hashed := sha256.Sum256(message) signature, err := SignPKCS1v15(rng, rsaPrivateKey, crypto.SHA256, hashed[:]) if err != nil { fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err) return } fmt.Printf("Signature: %x\n", signature) } func ExampleVerifyPKCS1v15() { message := []byte("message to be signed") signature, _ := hex.DecodeString("ad2766728615cc7a746cc553916380ca7bfa4f8983b990913bc69eb0556539a350ff0f8fe65ddfd3ebe91fe1c299c2fac135bc8c61e26be44ee259f2f80c1530") // Only small messages can be signed directly; thus the hash of a // message, rather than the message itself, is signed. This requires // that the hash function be collision resistant. SHA-256 is the // least-strong hash function that should be used for this at the time // of writing (2016). hashed := sha256.Sum256(message) err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA256, hashed[:], signature) if err != nil { fmt.Fprintf(os.Stderr, "Error from verification: %s\n", err) return } // signature is a valid signature of message from the public key. } func ExampleEncryptOAEP() { secretMessage := []byte("send reinforcements, we're going to advance") label := []byte("orders") // crypto/rand.Reader is a good source of entropy for randomizing the // encryption function. rng := rand.Reader ciphertext, err := EncryptOAEP(sha256.New(), rng, &test2048Key.PublicKey, secretMessage, label) if err != nil { fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err) return } // Since encryption is a randomized function, ciphertext will be // different each time. fmt.Printf("Ciphertext: %x\n", ciphertext) } func ExampleDecryptOAEP() { ciphertext, _ := hex.DecodeString("4d1ee10e8f286390258c51a5e80802844c3e6358ad6690b7285218a7c7ed7fc3a4c7b950fbd04d4b0239cc060dcc7065ca6f84c1756deb71ca5685cadbb82be025e16449b905c568a19c088a1abfad54bf7ecc67a7df39943ec511091a34c0f2348d04e058fcff4d55644de3cd1d580791d4524b92f3e91695582e6e340a1c50b6c6d78e80b4e42c5b4d45e479b492de42bbd39cc642ebb80226bb5200020d501b24a37bcc2ec7f34e596b4fd6b063de4858dbf5a4e3dd18e262eda0ec2d19dbd8e890d672b63d368768360b20c0b6b8592a438fa275e5fa7f60bef0dd39673fd3989cc54d2cb80c08fcd19dacbc265ee1c6014616b0e04ea0328c2a04e73460") label := []byte("orders") // crypto/rand.Reader is a good source of entropy for blinding the RSA // operation. rng := rand.Reader plaintext, err := DecryptOAEP(sha256.New(), rng, test2048Key, ciphertext, label) if err != nil { fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err) return } fmt.Printf("Plaintext: %s\n", string(plaintext)) // Remember that encryption only provides confidentiality. The // ciphertext should be signed before authenticity is assumed and, even // then, consider that messages might be reordered. } ================================================ FILE: scan/crypto/rsa/pkcs1v15.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rsa import ( "crypto" "crypto/subtle" "errors" "io" "math/big" ) // This file implements encryption and decryption using PKCS#1 v1.5 padding. // PKCS1v15DecrypterOpts is for passing options to PKCS#1 v1.5 decryption using // the crypto.Decrypter interface. type PKCS1v15DecryptOptions struct { // SessionKeyLen is the length of the session key that is being // decrypted. If not zero, then a padding error during decryption will // cause a random plaintext of this length to be returned rather than // an error. These alternatives happen in constant time. SessionKeyLen int } // EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5. // The message must be no longer than the length of the public modulus minus 11 bytes. // // The rand parameter is used as a source of entropy to ensure that encrypting // the same message twice doesn't result in the same ciphertext. // // WARNING: use of this function to encrypt plaintexts other than session keys // is dangerous. Use RSA OAEP in new protocols. func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) { if err := checkPub(pub); err != nil { return nil, err } k := (pub.N.BitLen() + 7) / 8 if len(msg) > k-11 { err = ErrMessageTooLong return } // EM = 0x00 || 0x02 || PS || 0x00 || M em := make([]byte, k) em[1] = 2 ps, mm := em[2:len(em)-len(msg)-1], em[len(em)-len(msg):] err = nonZeroRandomBytes(ps, rand) if err != nil { return } em[len(em)-len(msg)-1] = 0 copy(mm, msg) m := new(big.Int).SetBytes(em) c := encrypt(new(big.Int), pub, m) copyWithLeftPad(em, c.Bytes()) out = em return } // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5. // If rand != nil, it uses RSA blinding to avoid timing side-channel attacks. // // Note that whether this function returns an error or not discloses secret // information. If an attacker can cause this function to run repeatedly and // learn whether each instance returned an error then they can decrypt and // forge signatures as if they had the private key. See // DecryptPKCS1v15SessionKey for a way of solving this problem. func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) { if err := checkPub(&priv.PublicKey); err != nil { return nil, err } valid, out, index, err := decryptPKCS1v15(rand, priv, ciphertext) if err != nil { return } if valid == 0 { return nil, ErrDecryption } out = out[index:] return } // DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding scheme from PKCS#1 v1.5. // If rand != nil, it uses RSA blinding to avoid timing side-channel attacks. // It returns an error if the ciphertext is the wrong length or if the // ciphertext is greater than the public modulus. Otherwise, no error is // returned. If the padding is valid, the resulting plaintext message is copied // into key. Otherwise, key is unchanged. These alternatives occur in constant // time. It is intended that the user of this function generate a random // session key beforehand and continue the protocol with the resulting value. // This will remove any possibility that an attacker can learn any information // about the plaintext. // See “Chosen Ciphertext Attacks Against Protocols Based on the RSA // Encryption Standard PKCS #1”, Daniel Bleichenbacher, Advances in Cryptology // (Crypto '98). // // Note that if the session key is too small then it may be possible for an // attacker to brute-force it. If they can do that then they can learn whether // a random value was used (because it'll be different for the same ciphertext) // and thus whether the padding was correct. This defeats the point of this // function. Using at least a 16-byte key will protect against this attack. func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) { if err := checkPub(&priv.PublicKey); err != nil { return err } k := (priv.N.BitLen() + 7) / 8 if k-(len(key)+3+8) < 0 { return ErrDecryption } valid, em, index, err := decryptPKCS1v15(rand, priv, ciphertext) if err != nil { return } if len(em) != k { // This should be impossible because decryptPKCS1v15 always // returns the full slice. return ErrDecryption } valid &= subtle.ConstantTimeEq(int32(len(em)-index), int32(len(key))) subtle.ConstantTimeCopy(valid, key, em[len(em)-len(key):]) return } // decryptPKCS1v15 decrypts ciphertext using priv and blinds the operation if // rand is not nil. It returns one or zero in valid that indicates whether the // plaintext was correctly structured. In either case, the plaintext is // returned in em so that it may be read independently of whether it was valid // in order to maintain constant memory access patterns. If the plaintext was // valid then index contains the index of the original message in em. func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, em []byte, index int, err error) { k := (priv.N.BitLen() + 7) / 8 if k < 11 { err = ErrDecryption return } c := new(big.Int).SetBytes(ciphertext) m, err := decrypt(rand, priv, c) if err != nil { return } em = leftPad(m.Bytes(), k) firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2) // The remainder of the plaintext must be a string of non-zero random // octets, followed by a 0, followed by the message. // lookingForIndex: 1 iff we are still looking for the zero. // index: the offset of the first zero byte. lookingForIndex := 1 for i := 2; i < len(em); i++ { equals0 := subtle.ConstantTimeByteEq(em[i], 0) index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) } // The PS padding must be at least 8 bytes long, and it starts two // bytes into em. validPS := subtle.ConstantTimeLessOrEq(2+8, index) valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1) & validPS index = subtle.ConstantTimeSelect(valid, index+1, 0) return valid, em, index, nil } // nonZeroRandomBytes fills the given slice with non-zero random octets. func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) { _, err = io.ReadFull(rand, s) if err != nil { return } for i := 0; i < len(s); i++ { for s[i] == 0 { _, err = io.ReadFull(rand, s[i:i+1]) if err != nil { return } // In tests, the PRNG may return all zeros so we do // this to break the loop. s[i] ^= 0x42 } } return } // These are ASN1 DER structures: // // DigestInfo ::= SEQUENCE { // digestAlgorithm AlgorithmIdentifier, // digest OCTET STRING // } // // For performance, we don't use the generic ASN1 encoder. Rather, we // precompute a prefix of the digest value that makes a valid ASN1 DER string // with the correct contents. var hashPrefixes = map[crypto.Hash][]byte{ crypto.MD5: {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}, crypto.SHA1: {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}, crypto.SHA224: {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c}, crypto.SHA256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, crypto.SHA384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, crypto.MD5SHA1: {}, // A special TLS case which doesn't use an ASN1 prefix. crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14}, } // SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5. // Note that hashed must be the result of hashing the input message using the // given hash function. If hash is zero, hashed is signed directly. This isn't // advisable except for interoperability. // // If rand is not nil then RSA blinding will be used to avoid timing side-channel attacks. // // This function is deterministic. Thus, if the set of possible messages is // small, an attacker may be able to build a map from messages to signatures // and identify the signed messages. As ever, signatures provide authenticity, // not confidentiality. func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) { hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) if err != nil { return } tLen := len(prefix) + hashLen k := (priv.N.BitLen() + 7) / 8 if k < tLen+11 { return nil, ErrMessageTooLong } // EM = 0x00 || 0x01 || PS || 0x00 || T em := make([]byte, k) em[1] = 1 for i := 2; i < k-tLen-1; i++ { em[i] = 0xff } copy(em[k-tLen:k-hashLen], prefix) copy(em[k-hashLen:k], hashed) m := new(big.Int).SetBytes(em) c, err := decryptAndCheck(rand, priv, m) if err != nil { return } copyWithLeftPad(em, c.Bytes()) s = em return } // VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature. // hashed is the result of hashing the input message using the given hash // function and sig is the signature. A valid signature is indicated by // returning a nil error. If hash is zero then hashed is used directly. This // isn't advisable except for interoperability. func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) { hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) if err != nil { return } tLen := len(prefix) + hashLen k := (pub.N.BitLen() + 7) / 8 if k < tLen+11 { err = ErrVerification return } c := new(big.Int).SetBytes(sig) m := encrypt(new(big.Int), pub, c) em := leftPad(m.Bytes(), k) // EM = 0x00 || 0x01 || PS || 0x00 || T ok := subtle.ConstantTimeByteEq(em[0], 0) ok &= subtle.ConstantTimeByteEq(em[1], 1) ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed) ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix) ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0) for i := 2; i < k-tLen-1; i++ { ok &= subtle.ConstantTimeByteEq(em[i], 0xff) } if ok != 1 { return ErrVerification } return nil } func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) { // Special case: crypto.Hash(0) is used to indicate that the data is // signed directly. if hash == 0 { return inLen, nil, nil } hashLen = hash.Size() if inLen != hashLen { return 0, nil, errors.New("crypto/rsa: input must be hashed message") } prefix, ok := hashPrefixes[hash] if !ok { return 0, nil, errors.New("crypto/rsa: unsupported hash function") } return } // copyWithLeftPad copies src to the end of dest, padding with zero bytes as // needed. func copyWithLeftPad(dest, src []byte) { numPaddingBytes := len(dest) - len(src) for i := 0; i < numPaddingBytes; i++ { dest[i] = 0 } copy(dest[numPaddingBytes:], src) } ================================================ FILE: scan/crypto/rsa/pkcs1v15_test.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rsa import ( "bytes" "crypto" "crypto/rand" "crypto/sha1" "encoding/base64" "encoding/hex" "io" "math/big" "testing" "testing/quick" ) func decodeBase64(in string) []byte { out := make([]byte, base64.StdEncoding.DecodedLen(len(in))) n, err := base64.StdEncoding.Decode(out, []byte(in)) if err != nil { return nil } return out[0:n] } type DecryptPKCS1v15Test struct { in, out string } // These test vectors were generated with `openssl rsautl -pkcs -encrypt` var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{ { "gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==", "x", }, { "Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==", "testing.", }, { "arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==", "testing.\n", }, { "WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==", "01234567890123456789012345678901234567890123456789012", }, } func TestDecryptPKCS1v15(t *testing.T) { decryptionFuncs := []func([]byte) ([]byte, error){ func(ciphertext []byte) (plaintext []byte, err error) { return DecryptPKCS1v15(nil, rsaPrivateKey, ciphertext) }, func(ciphertext []byte) (plaintext []byte, err error) { return rsaPrivateKey.Decrypt(nil, ciphertext, nil) }, } for _, decryptFunc := range decryptionFuncs { for i, test := range decryptPKCS1v15Tests { out, err := decryptFunc(decodeBase64(test.in)) if err != nil { t.Errorf("#%d error decrypting", i) } want := []byte(test.out) if !bytes.Equal(out, want) { t.Errorf("#%d got:%#v want:%#v", i, out, want) } } } } func TestEncryptPKCS1v15(t *testing.T) { random := rand.Reader k := (rsaPrivateKey.N.BitLen() + 7) / 8 tryEncryptDecrypt := func(in []byte, blind bool) bool { if len(in) > k-11 { in = in[0 : k-11] } ciphertext, err := EncryptPKCS1v15(random, &rsaPrivateKey.PublicKey, in) if err != nil { t.Errorf("error encrypting: %s", err) return false } var rand io.Reader if !blind { rand = nil } else { rand = random } plaintext, err := DecryptPKCS1v15(rand, rsaPrivateKey, ciphertext) if err != nil { t.Errorf("error decrypting: %s", err) return false } if !bytes.Equal(plaintext, in) { t.Errorf("output mismatch: %#v %#v", plaintext, in) return false } return true } config := new(quick.Config) if testing.Short() { config.MaxCount = 10 } quick.Check(tryEncryptDecrypt, config) } // These test vectors were generated with `openssl rsautl -pkcs -encrypt` var decryptPKCS1v15SessionKeyTests = []DecryptPKCS1v15Test{ { "e6ukkae6Gykq0fKzYwULpZehX+UPXYzMoB5mHQUDEiclRbOTqas4Y0E6nwns1BBpdvEJcilhl5zsox/6DtGsYg==", "1234", }, { "Dtis4uk/q/LQGGqGk97P59K03hkCIVFMEFZRgVWOAAhxgYpCRG0MX2adptt92l67IqMki6iVQyyt0TtX3IdtEw==", "FAIL", }, { "LIyFyCYCptPxrvTxpol8F3M7ZivlMsf53zs0vHRAv+rDIh2YsHS69ePMoPMe3TkOMZ3NupiL3takPxIs1sK+dw==", "abcd", }, { "bafnobel46bKy76JzqU/RIVOH0uAYvzUtauKmIidKgM0sMlvobYVAVQPeUQ/oTGjbIZ1v/6Gyi5AO4DtHruGdw==", "FAIL", }, } func TestEncryptPKCS1v15SessionKey(t *testing.T) { for i, test := range decryptPKCS1v15SessionKeyTests { key := []byte("FAIL") err := DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, decodeBase64(test.in), key) if err != nil { t.Errorf("#%d error decrypting", i) } want := []byte(test.out) if !bytes.Equal(key, want) { t.Errorf("#%d got:%#v want:%#v", i, key, want) } } } func TestEncryptPKCS1v15DecrypterSessionKey(t *testing.T) { for i, test := range decryptPKCS1v15SessionKeyTests { plaintext, err := rsaPrivateKey.Decrypt(rand.Reader, decodeBase64(test.in), &PKCS1v15DecryptOptions{SessionKeyLen: 4}) if err != nil { t.Fatalf("#%d: error decrypting: %s", i, err) } if len(plaintext) != 4 { t.Fatalf("#%d: incorrect length plaintext: got %d, want 4", i, len(plaintext)) } if test.out != "FAIL" && !bytes.Equal(plaintext, []byte(test.out)) { t.Errorf("#%d: incorrect plaintext: got %x, want %x", i, plaintext, test.out) } } } func TestNonZeroRandomBytes(t *testing.T) { random := rand.Reader b := make([]byte, 512) err := nonZeroRandomBytes(b, random) if err != nil { t.Errorf("returned error: %s", err) } for _, b := range b { if b == 0 { t.Errorf("Zero octet found") return } } } type signPKCS1v15Test struct { in, out string } // These vectors have been tested with // // openssl rsautl -verify -inkey pk -in signature | hexdump -C var signPKCS1v15Tests = []signPKCS1v15Test{ {"Test.\n", "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e336ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"}, } func TestSignPKCS1v15(t *testing.T) { for i, test := range signPKCS1v15Tests { h := sha1.New() h.Write([]byte(test.in)) digest := h.Sum(nil) s, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA1, digest) if err != nil { t.Errorf("#%d %s", i, err) } expected, _ := hex.DecodeString(test.out) if !bytes.Equal(s, expected) { t.Errorf("#%d got: %x want: %x", i, s, expected) } } } func TestVerifyPKCS1v15(t *testing.T) { for i, test := range signPKCS1v15Tests { h := sha1.New() h.Write([]byte(test.in)) digest := h.Sum(nil) sig, _ := hex.DecodeString(test.out) err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA1, digest, sig) if err != nil { t.Errorf("#%d %s", i, err) } } } func TestOverlongMessagePKCS1v15(t *testing.T) { ciphertext := decodeBase64("fjOVdirUzFoLlukv80dBllMLjXythIf22feqPrNo0YoIjzyzyoMFiLjAc/Y4krkeZ11XFThIrEvw\nkRiZcCq5ng==") _, err := DecryptPKCS1v15(nil, rsaPrivateKey, ciphertext) if err == nil { t.Error("RSA decrypted a message that was too long.") } } func TestUnpaddedSignature(t *testing.T) { msg := []byte("Thu Dec 19 18:06:16 EST 2013\n") // This base64 value was generated with: // % echo Thu Dec 19 18:06:16 EST 2013 > /tmp/msg // % openssl rsautl -sign -inkey key -out /tmp/sig -in /tmp/msg // // Where "key" contains the RSA private key given at the bottom of this // file. expectedSig := decodeBase64("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==") sig, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.Hash(0), msg) if err != nil { t.Fatalf("SignPKCS1v15 failed: %s", err) } if !bytes.Equal(sig, expectedSig) { t.Fatalf("signature is not expected value: got %x, want %x", sig, expectedSig) } if err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.Hash(0), msg, sig); err != nil { t.Fatalf("signature failed to verify: %s", err) } } func TestShortSessionKey(t *testing.T) { // This tests that attempting to decrypt a session key where the // ciphertext is too small doesn't run outside the array bounds. ciphertext, err := EncryptPKCS1v15(rand.Reader, &rsaPrivateKey.PublicKey, []byte{1}) if err != nil { t.Fatalf("Failed to encrypt short message: %s", err) } var key [32]byte if err := DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, ciphertext, key[:]); err != nil { t.Fatalf("Failed to decrypt short message: %s", err) } for _, v := range key { if v != 0 { t.Fatal("key was modified when ciphertext was invalid") } } } // In order to generate new test vectors you'll need the PEM form of this key: // -----BEGIN RSA PRIVATE KEY----- // MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0 // fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu // /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu // RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/ // EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A // IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS // tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V // -----END RSA PRIVATE KEY----- var rsaPrivateKey = &PrivateKey{ PublicKey: PublicKey{ N: fromBase10("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"), E: 65537, }, D: fromBase10("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861"), Primes: []*big.Int{ fromBase10("98920366548084643601728869055592650835572950932266967461790948584315647051443"), fromBase10("94560208308847015747498523884063394671606671904944666360068158221458669711639"), }, } ================================================ FILE: scan/crypto/rsa/pss.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rsa // This file implements the PSS signature scheme [1]. // // [1] http://www.rsa.com/rsalabs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf import ( "bytes" "crypto" "errors" "hash" "io" "math/big" ) func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) { // See [1], section 9.1.1 hLen := hash.Size() sLen := len(salt) emLen := (emBits + 7) / 8 // 1. If the length of M is greater than the input limitation for the // hash function (2^61 - 1 octets for SHA-1), output "message too // long" and stop. // // 2. Let mHash = Hash(M), an octet string of length hLen. if len(mHash) != hLen { return nil, errors.New("crypto/rsa: input must be hashed message") } // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. if emLen < hLen+sLen+2 { return nil, errors.New("crypto/rsa: encoding error") } em := make([]byte, emLen) db := em[:emLen-sLen-hLen-2+1+sLen] h := em[emLen-sLen-hLen-2+1+sLen : emLen-1] // 4. Generate a random octet string salt of length sLen; if sLen = 0, // then salt is the empty string. // // 5. Let // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; // // M' is an octet string of length 8 + hLen + sLen with eight // initial zero octets. // // 6. Let H = Hash(M'), an octet string of length hLen. var prefix [8]byte hash.Write(prefix[:]) hash.Write(mHash) hash.Write(salt) h = hash.Sum(h[:0]) hash.Reset() // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 // zero octets. The length of PS may be 0. // // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length // emLen - hLen - 1. db[emLen-sLen-hLen-2] = 0x01 copy(db[emLen-sLen-hLen-1:], salt) // 9. Let dbMask = MGF(H, emLen - hLen - 1). // // 10. Let maskedDB = DB \xor dbMask. mgf1XOR(db, hash, h) // 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in // maskedDB to zero. db[0] &= (0xFF >> uint(8*emLen-emBits)) // 12. Let EM = maskedDB || H || 0xbc. em[emLen-1] = 0xBC // 13. Output EM. return em, nil } func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { // 1. If the length of M is greater than the input limitation for the // hash function (2^61 - 1 octets for SHA-1), output "inconsistent" // and stop. // // 2. Let mHash = Hash(M), an octet string of length hLen. hLen := hash.Size() if hLen != len(mHash) { return ErrVerification } // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. emLen := (emBits + 7) / 8 if emLen < hLen+sLen+2 { return ErrVerification } // 4. If the rightmost octet of EM does not have hexadecimal value // 0xbc, output "inconsistent" and stop. if em[len(em)-1] != 0xBC { return ErrVerification } // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and // let H be the next hLen octets. db := em[:emLen-hLen-1] h := em[emLen-hLen-1 : len(em)-1] // 6. If the leftmost 8 * emLen - emBits bits of the leftmost octet in // maskedDB are not all equal to zero, output "inconsistent" and // stop. if em[0]&(0xFF<> uint(8*emLen-emBits)) if sLen == PSSSaltLengthAuto { FindSaltLength: for sLen = emLen - (hLen + 2); sLen >= 0; sLen-- { switch db[emLen-hLen-sLen-2] { case 1: break FindSaltLength case 0: continue default: return ErrVerification } } if sLen < 0 { return ErrVerification } } else { // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero // or if the octet at position emLen - hLen - sLen - 1 (the leftmost // position is "position 1") does not have hexadecimal value 0x01, // output "inconsistent" and stop. for _, e := range db[:emLen-hLen-sLen-2] { if e != 0x00 { return ErrVerification } } if db[emLen-hLen-sLen-2] != 0x01 { return ErrVerification } } // 11. Let salt be the last sLen octets of DB. salt := db[len(db)-sLen:] // 12. Let // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ; // M' is an octet string of length 8 + hLen + sLen with eight // initial zero octets. // // 13. Let H' = Hash(M'), an octet string of length hLen. var prefix [8]byte hash.Write(prefix[:]) hash.Write(mHash) hash.Write(salt) h0 := hash.Sum(nil) // 14. If H = H', output "consistent." Otherwise, output "inconsistent." if !bytes.Equal(h0, h) { return ErrVerification } return nil } // signPSSWithSalt calculates the signature of hashed using PSS [1] with specified salt. // Note that hashed must be the result of hashing the input message using the // given hash function. salt is a random sequence of bytes whose length will be // later used to verify the signature. func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) (s []byte, err error) { nBits := priv.N.BitLen() em, err := emsaPSSEncode(hashed, nBits-1, salt, hash.New()) if err != nil { return } m := new(big.Int).SetBytes(em) c, err := decryptAndCheck(rand, priv, m) if err != nil { return } s = make([]byte, (nBits+7)/8) copyWithLeftPad(s, c.Bytes()) return } const ( // PSSSaltLengthAuto causes the salt in a PSS signature to be as large // as possible when signing, and to be auto-detected when verifying. PSSSaltLengthAuto = 0 // PSSSaltLengthEqualsHash causes the salt length to equal the length // of the hash used in the signature. PSSSaltLengthEqualsHash = -1 ) // PSSOptions contains options for creating and verifying PSS signatures. type PSSOptions struct { // SaltLength controls the length of the salt used in the PSS // signature. It can either be a number of bytes, or one of the special // PSSSaltLength constants. SaltLength int // Hash, if not zero, overrides the hash function passed to SignPSS. // This is the only way to specify the hash function when using the // crypto.Signer interface. Hash crypto.Hash } // HashFunc returns pssOpts.Hash so that PSSOptions implements // crypto.SignerOpts. func (pssOpts *PSSOptions) HashFunc() crypto.Hash { return pssOpts.Hash } func (opts *PSSOptions) saltLength() int { if opts == nil { return PSSSaltLengthAuto } return opts.SaltLength } // SignPSS calculates the signature of hashed using RSASSA-PSS [1]. // Note that hashed must be the result of hashing the input message using the // given hash function. The opts argument may be nil, in which case sensible // defaults are used. func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) (s []byte, err error) { saltLength := opts.saltLength() switch saltLength { case PSSSaltLengthAuto: saltLength = (priv.N.BitLen()+7)/8 - 2 - hash.Size() case PSSSaltLengthEqualsHash: saltLength = hash.Size() } if opts != nil && opts.Hash != 0 { hash = opts.Hash } salt := make([]byte, saltLength) if _, err = io.ReadFull(rand, salt); err != nil { return } return signPSSWithSalt(rand, priv, hash, hashed, salt) } // VerifyPSS verifies a PSS signature. // hashed is the result of hashing the input message using the given hash // function and sig is the signature. A valid signature is indicated by // returning a nil error. The opts argument may be nil, in which case sensible // defaults are used. func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, opts *PSSOptions) error { return verifyPSS(pub, hash, hashed, sig, opts.saltLength()) } // verifyPSS verifies a PSS signature with the given salt length. func verifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, saltLen int) error { nBits := pub.N.BitLen() if len(sig) != (nBits+7)/8 { return ErrVerification } s := new(big.Int).SetBytes(sig) m := encrypt(new(big.Int), pub, s) emBits := nBits - 1 emLen := (emBits + 7) / 8 if emLen < len(m.Bytes()) { return ErrVerification } em := make([]byte, emLen) copyWithLeftPad(em, m.Bytes()) if saltLen == PSSSaltLengthEqualsHash { saltLen = hash.Size() } return emsaPSSVerify(hashed, em, emBits, saltLen, hash.New()) } ================================================ FILE: scan/crypto/rsa/pss_test.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rsa import ( "bufio" "bytes" "compress/bzip2" "crypto" _ "crypto/md5" "crypto/rand" "crypto/sha1" _ "crypto/sha256" "encoding/hex" "math/big" "os" "strconv" "strings" "testing" ) func TestEMSAPSS(t *testing.T) { // Test vector in file pss-int.txt from: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip msg := []byte{ 0x85, 0x9e, 0xef, 0x2f, 0xd7, 0x8a, 0xca, 0x00, 0x30, 0x8b, 0xdc, 0x47, 0x11, 0x93, 0xbf, 0x55, 0xbf, 0x9d, 0x78, 0xdb, 0x8f, 0x8a, 0x67, 0x2b, 0x48, 0x46, 0x34, 0xf3, 0xc9, 0xc2, 0x6e, 0x64, 0x78, 0xae, 0x10, 0x26, 0x0f, 0xe0, 0xdd, 0x8c, 0x08, 0x2e, 0x53, 0xa5, 0x29, 0x3a, 0xf2, 0x17, 0x3c, 0xd5, 0x0c, 0x6d, 0x5d, 0x35, 0x4f, 0xeb, 0xf7, 0x8b, 0x26, 0x02, 0x1c, 0x25, 0xc0, 0x27, 0x12, 0xe7, 0x8c, 0xd4, 0x69, 0x4c, 0x9f, 0x46, 0x97, 0x77, 0xe4, 0x51, 0xe7, 0xf8, 0xe9, 0xe0, 0x4c, 0xd3, 0x73, 0x9c, 0x6b, 0xbf, 0xed, 0xae, 0x48, 0x7f, 0xb5, 0x56, 0x44, 0xe9, 0xca, 0x74, 0xff, 0x77, 0xa5, 0x3c, 0xb7, 0x29, 0x80, 0x2f, 0x6e, 0xd4, 0xa5, 0xff, 0xa8, 0xba, 0x15, 0x98, 0x90, 0xfc, } salt := []byte{ 0xe3, 0xb5, 0xd5, 0xd0, 0x02, 0xc1, 0xbc, 0xe5, 0x0c, 0x2b, 0x65, 0xef, 0x88, 0xa1, 0x88, 0xd8, 0x3b, 0xce, 0x7e, 0x61, } expected := []byte{ 0x66, 0xe4, 0x67, 0x2e, 0x83, 0x6a, 0xd1, 0x21, 0xba, 0x24, 0x4b, 0xed, 0x65, 0x76, 0xb8, 0x67, 0xd9, 0xa4, 0x47, 0xc2, 0x8a, 0x6e, 0x66, 0xa5, 0xb8, 0x7d, 0xee, 0x7f, 0xbc, 0x7e, 0x65, 0xaf, 0x50, 0x57, 0xf8, 0x6f, 0xae, 0x89, 0x84, 0xd9, 0xba, 0x7f, 0x96, 0x9a, 0xd6, 0xfe, 0x02, 0xa4, 0xd7, 0x5f, 0x74, 0x45, 0xfe, 0xfd, 0xd8, 0x5b, 0x6d, 0x3a, 0x47, 0x7c, 0x28, 0xd2, 0x4b, 0xa1, 0xe3, 0x75, 0x6f, 0x79, 0x2d, 0xd1, 0xdc, 0xe8, 0xca, 0x94, 0x44, 0x0e, 0xcb, 0x52, 0x79, 0xec, 0xd3, 0x18, 0x3a, 0x31, 0x1f, 0xc8, 0x96, 0xda, 0x1c, 0xb3, 0x93, 0x11, 0xaf, 0x37, 0xea, 0x4a, 0x75, 0xe2, 0x4b, 0xdb, 0xfd, 0x5c, 0x1d, 0xa0, 0xde, 0x7c, 0xec, 0xdf, 0x1a, 0x89, 0x6f, 0x9d, 0x8b, 0xc8, 0x16, 0xd9, 0x7c, 0xd7, 0xa2, 0xc4, 0x3b, 0xad, 0x54, 0x6f, 0xbe, 0x8c, 0xfe, 0xbc, } hash := sha1.New() hash.Write(msg) hashed := hash.Sum(nil) encoded, err := emsaPSSEncode(hashed, 1023, salt, sha1.New()) if err != nil { t.Errorf("Error from emsaPSSEncode: %s\n", err) } if !bytes.Equal(encoded, expected) { t.Errorf("Bad encoding. got %x, want %x", encoded, expected) } if err = emsaPSSVerify(hashed, encoded, 1023, len(salt), sha1.New()); err != nil { t.Errorf("Bad verification: %s", err) } } // TestPSSGolden tests all the test vectors in pss-vect.txt from // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip func TestPSSGolden(t *testing.T) { inFile, err := os.Open("testdata/pss-vect.txt.bz2") if err != nil { t.Fatalf("Failed to open input file: %s", err) } defer inFile.Close() // The pss-vect.txt file contains RSA keys and then a series of // signatures. A goroutine is used to preprocess the input by merging // lines, removing spaces in hex values and identifying the start of // new keys and signature blocks. const newKeyMarker = "START NEW KEY" const newSignatureMarker = "START NEW SIGNATURE" values := make(chan string) go func() { defer close(values) scanner := bufio.NewScanner(bzip2.NewReader(inFile)) var partialValue string lastWasValue := true for scanner.Scan() { line := scanner.Text() switch { case len(line) == 0: if len(partialValue) > 0 { values <- strings.Replace(partialValue, " ", "", -1) partialValue = "" lastWasValue = true } continue case strings.HasPrefix(line, "# ======") && lastWasValue: values <- newKeyMarker lastWasValue = false case strings.HasPrefix(line, "# ------") && lastWasValue: values <- newSignatureMarker lastWasValue = false case strings.HasPrefix(line, "#"): continue default: partialValue += line } } if err := scanner.Err(); err != nil { panic(err) } }() var key *PublicKey var hashed []byte hash := crypto.SHA1 h := hash.New() opts := &PSSOptions{ SaltLength: PSSSaltLengthEqualsHash, } for marker := range values { switch marker { case newKeyMarker: key = new(PublicKey) nHex, ok := <-values if !ok { continue } key.N = bigFromHex(nHex) key.E = intFromHex(<-values) // We don't care for d, p, q, dP, dQ or qInv. for i := 0; i < 6; i++ { <-values } case newSignatureMarker: msg := fromHex(<-values) <-values // skip salt sig := fromHex(<-values) h.Reset() h.Write(msg) hashed = h.Sum(hashed[:0]) if err := VerifyPSS(key, hash, hashed, sig, opts); err != nil { t.Error(err) } default: t.Fatalf("unknown marker: " + marker) } } } // TestPSSOpenSSL ensures that we can verify a PSS signature from OpenSSL with // the default options. OpenSSL sets the salt length to be maximal. func TestPSSOpenSSL(t *testing.T) { hash := crypto.SHA256 h := hash.New() h.Write([]byte("testing")) hashed := h.Sum(nil) // Generated with `echo -n testing | openssl dgst -sign key.pem -sigopt rsa_padding_mode:pss -sha256 > sig` sig := []byte{ 0x95, 0x59, 0x6f, 0xd3, 0x10, 0xa2, 0xe7, 0xa2, 0x92, 0x9d, 0x4a, 0x07, 0x2e, 0x2b, 0x27, 0xcc, 0x06, 0xc2, 0x87, 0x2c, 0x52, 0xf0, 0x4a, 0xcc, 0x05, 0x94, 0xf2, 0xc3, 0x2e, 0x20, 0xd7, 0x3e, 0x66, 0x62, 0xb5, 0x95, 0x2b, 0xa3, 0x93, 0x9a, 0x66, 0x64, 0x25, 0xe0, 0x74, 0x66, 0x8c, 0x3e, 0x92, 0xeb, 0xc6, 0xe6, 0xc0, 0x44, 0xf3, 0xb4, 0xb4, 0x2e, 0x8c, 0x66, 0x0a, 0x37, 0x9c, 0x69, } if err := VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, nil); err != nil { t.Error(err) } } func TestPSSNilOpts(t *testing.T) { hash := crypto.SHA256 h := hash.New() h.Write([]byte("testing")) hashed := h.Sum(nil) SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, nil) } func TestPSSSigning(t *testing.T) { var saltLengthCombinations = []struct { signSaltLength, verifySaltLength int good bool }{ {PSSSaltLengthAuto, PSSSaltLengthAuto, true}, {PSSSaltLengthEqualsHash, PSSSaltLengthAuto, true}, {PSSSaltLengthEqualsHash, PSSSaltLengthEqualsHash, true}, {PSSSaltLengthEqualsHash, 8, false}, {PSSSaltLengthAuto, PSSSaltLengthEqualsHash, false}, {8, 8, true}, } hash := crypto.MD5 h := hash.New() h.Write([]byte("testing")) hashed := h.Sum(nil) var opts PSSOptions for i, test := range saltLengthCombinations { opts.SaltLength = test.signSaltLength sig, err := SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, &opts) if err != nil { t.Errorf("#%d: error while signing: %s", i, err) continue } opts.SaltLength = test.verifySaltLength err = VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, &opts) if (err == nil) != test.good { t.Errorf("#%d: bad result, wanted: %t, got: %s", i, test.good, err) } } } func bigFromHex(hex string) *big.Int { n, ok := new(big.Int).SetString(hex, 16) if !ok { panic("bad hex: " + hex) } return n } func intFromHex(hex string) int { i, err := strconv.ParseInt(hex, 16, 32) if err != nil { panic(err) } return int(i) } func fromHex(hexStr string) []byte { s, err := hex.DecodeString(hexStr) if err != nil { panic(err) } return s } ================================================ FILE: scan/crypto/rsa/rsa.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package rsa implements RSA encryption as specified in PKCS#1. // // RSA is a single, fundamental operation that is used in this package to // implement either public-key encryption or public-key signatures. // // The original specification for encryption and signatures with RSA is PKCS#1 // and the terms "RSA encryption" and "RSA signatures" by default refer to // PKCS#1 version 1.5. However, that specification has flaws and new designs // should use version two, usually called by just OAEP and PSS, where // possible. // // Two sets of interfaces are included in this package. When a more abstract // interface isn't neccessary, there are functions for encrypting/decrypting // with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract // over the public-key primitive, the PrivateKey struct implements the // Decrypter and Signer interfaces from the crypto package. package rsa import ( "crypto" "crypto/rand" "crypto/subtle" "errors" "hash" "io" "math/big" ) var bigZero = big.NewInt(0) var bigOne = big.NewInt(1) // A PublicKey represents the public part of an RSA key. type PublicKey struct { N *big.Int // modulus E int // public exponent } // OAEPOptions is an interface for passing options to OAEP decryption using the // crypto.Decrypter interface. type OAEPOptions struct { // Hash is the hash function that will be used when generating the mask. Hash crypto.Hash // Label is an arbitrary byte string that must be equal to the value // used when encrypting. Label []byte } var ( errPublicModulus = errors.New("crypto/rsa: missing public modulus") errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small") errPublicExponentLarge = errors.New("crypto/rsa: public exponent too large") ) // checkPub sanity checks the public key before we use it. // We require pub.E to fit into a 32-bit integer so that we // do not have different behavior depending on whether // int is 32 or 64 bits. See also // http://www.imperialviolet.org/2012/03/16/rsae.html. func checkPub(pub *PublicKey) error { if pub.N == nil { return errPublicModulus } if pub.E < 2 { return errPublicExponentSmall } if pub.E > 1<<31-1 { return errPublicExponentLarge } return nil } // A PrivateKey represents an RSA key type PrivateKey struct { PublicKey // public part. D *big.Int // private exponent Primes []*big.Int // prime factors of N, has >= 2 elements. // Precomputed contains precomputed values that speed up private // operations, if available. Precomputed PrecomputedValues } // Public returns the public key corresponding to priv. func (priv *PrivateKey) Public() crypto.PublicKey { return &priv.PublicKey } // Sign signs msg with priv, reading randomness from rand. If opts is a // *PSSOptions then the PSS algorithm will be used, otherwise PKCS#1 v1.5 will // be used. This method is intended to support keys where the private part is // kept in, for example, a hardware module. Common uses should use the Sign* // functions in this package. func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { if pssOpts, ok := opts.(*PSSOptions); ok { return SignPSS(rand, priv, pssOpts.Hash, msg, pssOpts) } return SignPKCS1v15(rand, priv, opts.HashFunc(), msg) } // Decrypt decrypts ciphertext with priv. If opts is nil or of type // *PKCS1v15DecryptOptions then PKCS#1 v1.5 decryption is performed. Otherwise // opts must have type *OAEPOptions and OAEP decryption is done. func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) { if opts == nil { return DecryptPKCS1v15(rand, priv, ciphertext) } switch opts := opts.(type) { case *OAEPOptions: return DecryptOAEP(opts.Hash.New(), rand, priv, ciphertext, opts.Label) case *PKCS1v15DecryptOptions: if l := opts.SessionKeyLen; l > 0 { plaintext = make([]byte, l) if _, err := io.ReadFull(rand, plaintext); err != nil { return nil, err } if err := DecryptPKCS1v15SessionKey(rand, priv, ciphertext, plaintext); err != nil { return nil, err } return plaintext, nil } else { return DecryptPKCS1v15(rand, priv, ciphertext) } default: return nil, errors.New("crypto/rsa: invalid options for Decrypt") } } type PrecomputedValues struct { Dp, Dq *big.Int // D mod (P-1) (or mod Q-1) Qinv *big.Int // Q^-1 mod P // CRTValues is used for the 3rd and subsequent primes. Due to a // historical accident, the CRT for the first two primes is handled // differently in PKCS#1 and interoperability is sufficiently // important that we mirror this. CRTValues []CRTValue } // CRTValue contains the precomputed Chinese remainder theorem values. type CRTValue struct { Exp *big.Int // D mod (prime-1). Coeff *big.Int // R·Coeff ≡ 1 mod Prime. R *big.Int // product of primes prior to this (inc p and q). } // Validate performs basic sanity checks on the key. // It returns nil if the key is valid, or else an error describing a problem. func (priv *PrivateKey) Validate() error { if err := checkPub(&priv.PublicKey); err != nil { return err } // Check that Πprimes == n. modulus := new(big.Int).Set(bigOne) for _, prime := range priv.Primes { // Any primes ≤ 1 will cause divide-by-zero panics later. if prime.Cmp(bigOne) <= 0 { return errors.New("crypto/rsa: invalid prime value") } modulus.Mul(modulus, prime) } if modulus.Cmp(priv.N) != 0 { return errors.New("crypto/rsa: invalid modulus") } // Check that de ≡ 1 mod p-1, for each prime. // This implies that e is coprime to each p-1 as e has a multiplicative // inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) = // exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1 // mod p. Thus a^de ≡ a mod n for all a coprime to n, as required. congruence := new(big.Int) de := new(big.Int).SetInt64(int64(priv.E)) de.Mul(de, priv.D) for _, prime := range priv.Primes { pminus1 := new(big.Int).Sub(prime, bigOne) congruence.Mod(de, pminus1) if congruence.Cmp(bigOne) != 0 { return errors.New("crypto/rsa: invalid exponents") } } return nil } // GenerateKey generates an RSA keypair of the given bit size using the // random source random (for example, crypto/rand.Reader). func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) { return GenerateMultiPrimeKey(random, 2, bits) } // GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit // size and the given random source, as suggested in [1]. Although the public // keys are compatible (actually, indistinguishable) from the 2-prime case, // the private keys are not. Thus it may not be possible to export multi-prime // private keys in certain formats or to subsequently import them into other // code. // // Table 1 in [2] suggests maximum numbers of primes for a given size. // // [1] US patent 4405829 (1972, expired) // [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err error) { priv = new(PrivateKey) priv.E = 65537 if nprimes < 2 { return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2") } primes := make([]*big.Int, nprimes) NextSetOfPrimes: for { todo := bits // crypto/rand should set the top two bits in each prime. // Thus each prime has the form // p_i = 2^bitlen(p_i) × 0.11... (in base 2). // And the product is: // P = 2^todo × α // where α is the product of nprimes numbers of the form 0.11... // // If α < 1/2 (which can happen for nprimes > 2), we need to // shift todo to compensate for lost bits: the mean value of 0.11... // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2 // will give good results. if nprimes >= 7 { todo += (nprimes - 2) / 5 } for i := 0; i < nprimes; i++ { primes[i], err = rand.Prime(random, todo/(nprimes-i)) if err != nil { return nil, err } todo -= primes[i].BitLen() } // Make sure that primes is pairwise unequal. for i, prime := range primes { for j := 0; j < i; j++ { if prime.Cmp(primes[j]) == 0 { continue NextSetOfPrimes } } } n := new(big.Int).Set(bigOne) totient := new(big.Int).Set(bigOne) pminus1 := new(big.Int) for _, prime := range primes { n.Mul(n, prime) pminus1.Sub(prime, bigOne) totient.Mul(totient, pminus1) } if n.BitLen() != bits { // This should never happen for nprimes == 2 because // crypto/rand should set the top two bits in each prime. // For nprimes > 2 we hope it does not happen often. continue NextSetOfPrimes } g := new(big.Int) priv.D = new(big.Int) y := new(big.Int) e := big.NewInt(int64(priv.E)) g.GCD(priv.D, y, e, totient) if g.Cmp(bigOne) == 0 { if priv.D.Sign() < 0 { priv.D.Add(priv.D, totient) } priv.Primes = primes priv.N = n break } } priv.Precompute() return } // incCounter increments a four byte, big-endian counter. func incCounter(c *[4]byte) { if c[3]++; c[3] != 0 { return } if c[2]++; c[2] != 0 { return } if c[1]++; c[1] != 0 { return } c[0]++ } // mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function // specified in PKCS#1 v2.1. func mgf1XOR(out []byte, hash hash.Hash, seed []byte) { var counter [4]byte var digest []byte done := 0 for done < len(out) { hash.Write(seed) hash.Write(counter[0:4]) digest = hash.Sum(digest[:0]) hash.Reset() for i := 0; i < len(digest) && done < len(out); i++ { out[done] ^= digest[i] done++ } incCounter(&counter) } } // ErrMessageTooLong is returned when attempting to encrypt a message which is // too large for the size of the public key. var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA public key size") func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int { e := big.NewInt(int64(pub.E)) c.Exp(m, e, pub.N) return c } // EncryptOAEP encrypts the given message with RSA-OAEP. // // OAEP is parameterised by a hash function that is used as a random oracle. // Encryption and decryption of a given message must use the same hash function // and sha256.New() is a reasonable choice. // // The random parameter is used as a source of entropy to ensure that // encrypting the same message twice doesn't result in the same ciphertext. // // The label parameter may contain arbitrary data that will not be encrypted, // but which gives important context to the message. For example, if a given // public key is used to decrypt two types of messages then distinct label // values could be used to ensure that a ciphertext for one purpose cannot be // used for another by an attacker. If not required it can be empty. // // The message must be no longer than the length of the public modulus less // twice the hash length plus 2. func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) { if err := checkPub(pub); err != nil { return nil, err } hash.Reset() k := (pub.N.BitLen() + 7) / 8 if len(msg) > k-2*hash.Size()-2 { err = ErrMessageTooLong return } hash.Write(label) lHash := hash.Sum(nil) hash.Reset() em := make([]byte, k) seed := em[1 : 1+hash.Size()] db := em[1+hash.Size():] copy(db[0:hash.Size()], lHash) db[len(db)-len(msg)-1] = 1 copy(db[len(db)-len(msg):], msg) _, err = io.ReadFull(random, seed) if err != nil { return } mgf1XOR(db, hash, seed) mgf1XOR(seed, hash, db) m := new(big.Int) m.SetBytes(em) c := encrypt(new(big.Int), pub, m) out = c.Bytes() if len(out) < k { // If the output is too small, we need to left-pad with zeros. t := make([]byte, k) copy(t[k-len(out):], out) out = t } return } // ErrDecryption represents a failure to decrypt a message. // It is deliberately vague to avoid adaptive attacks. var ErrDecryption = errors.New("crypto/rsa: decryption error") // ErrVerification represents a failure to verify a signature. // It is deliberately vague to avoid adaptive attacks. var ErrVerification = errors.New("crypto/rsa: verification error") // modInverse returns ia, the inverse of a in the multiplicative group of prime // order n. It requires that a be a member of the group (i.e. less than n). func modInverse(a, n *big.Int) (ia *big.Int, ok bool) { g := new(big.Int) x := new(big.Int) y := new(big.Int) g.GCD(x, y, a, n) if g.Cmp(bigOne) != 0 { // In this case, a and n aren't coprime and we cannot calculate // the inverse. This happens because the values of n are nearly // prime (being the product of two primes) rather than truly // prime. return } if x.Cmp(bigOne) < 0 { // 0 is not the multiplicative inverse of any element so, if x // < 1, then x is negative. x.Add(x, n) } return x, true } // Precompute performs some calculations that speed up private key operations // in the future. func (priv *PrivateKey) Precompute() { if priv.Precomputed.Dp != nil { return } priv.Precomputed.Dp = new(big.Int).Sub(priv.Primes[0], bigOne) priv.Precomputed.Dp.Mod(priv.D, priv.Precomputed.Dp) priv.Precomputed.Dq = new(big.Int).Sub(priv.Primes[1], bigOne) priv.Precomputed.Dq.Mod(priv.D, priv.Precomputed.Dq) priv.Precomputed.Qinv = new(big.Int).ModInverse(priv.Primes[1], priv.Primes[0]) r := new(big.Int).Mul(priv.Primes[0], priv.Primes[1]) priv.Precomputed.CRTValues = make([]CRTValue, len(priv.Primes)-2) for i := 2; i < len(priv.Primes); i++ { prime := priv.Primes[i] values := &priv.Precomputed.CRTValues[i-2] values.Exp = new(big.Int).Sub(prime, bigOne) values.Exp.Mod(priv.D, values.Exp) values.R = new(big.Int).Set(r) values.Coeff = new(big.Int).ModInverse(r, prime) r.Mul(r, prime) } } // decrypt performs an RSA decryption, resulting in a plaintext integer. If a // random source is given, RSA blinding is used. func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) { // TODO(agl): can we get away with reusing blinds? if c.Cmp(priv.N) > 0 { err = ErrDecryption return } var ir *big.Int if random != nil { // Blinding enabled. Blinding involves multiplying c by r^e. // Then the decryption operation performs (m^e * r^e)^d mod n // which equals mr mod n. The factor of r can then be removed // by multiplying by the multiplicative inverse of r. var r *big.Int for { r, err = rand.Int(random, priv.N) if err != nil { return } if r.Cmp(bigZero) == 0 { r = bigOne } var ok bool ir, ok = modInverse(r, priv.N) if ok { break } } bigE := big.NewInt(int64(priv.E)) rpowe := new(big.Int).Exp(r, bigE, priv.N) cCopy := new(big.Int).Set(c) cCopy.Mul(cCopy, rpowe) cCopy.Mod(cCopy, priv.N) c = cCopy } if priv.Precomputed.Dp == nil { m = new(big.Int).Exp(c, priv.D, priv.N) } else { // We have the precalculated values needed for the CRT. m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0]) m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1]) m.Sub(m, m2) if m.Sign() < 0 { m.Add(m, priv.Primes[0]) } m.Mul(m, priv.Precomputed.Qinv) m.Mod(m, priv.Primes[0]) m.Mul(m, priv.Primes[1]) m.Add(m, m2) for i, values := range priv.Precomputed.CRTValues { prime := priv.Primes[2+i] m2.Exp(c, values.Exp, prime) m2.Sub(m2, m) m2.Mul(m2, values.Coeff) m2.Mod(m2, prime) if m2.Sign() < 0 { m2.Add(m2, prime) } m2.Mul(m2, values.R) m.Add(m, m2) } } if ir != nil { // Unblind. m.Mul(m, ir) m.Mod(m, priv.N) } return } func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) { m, err = decrypt(random, priv, c) if err != nil { return nil, err } // In order to defend against errors in the CRT computation, m^e is // calculated, which should match the original ciphertext. check := encrypt(new(big.Int), &priv.PublicKey, m) if c.Cmp(check) != 0 { return nil, errors.New("rsa: internal error") } return m, nil } // DecryptOAEP decrypts ciphertext using RSA-OAEP. // OAEP is parameterised by a hash function that is used as a random oracle. // Encryption and decryption of a given message must use the same hash function // and sha256.New() is a reasonable choice. // // The random parameter, if not nil, is used to blind the private-key operation // and avoid timing side-channel attacks. Blinding is purely internal to this // function – the random data need not match that used when encrypting. // // The label parameter must match the value given when encrypting. See // EncryptOAEP for details. func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) { if err := checkPub(&priv.PublicKey); err != nil { return nil, err } k := (priv.N.BitLen() + 7) / 8 if len(ciphertext) > k || k < hash.Size()*2+2 { err = ErrDecryption return } c := new(big.Int).SetBytes(ciphertext) m, err := decrypt(random, priv, c) if err != nil { return } hash.Write(label) lHash := hash.Sum(nil) hash.Reset() // Converting the plaintext number to bytes will strip any // leading zeros so we may have to left pad. We do this unconditionally // to avoid leaking timing information. (Although we still probably // leak the number of leading zeros. It's not clear that we can do // anything about this.) em := leftPad(m.Bytes(), k) firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) seed := em[1 : hash.Size()+1] db := em[hash.Size()+1:] mgf1XOR(seed, hash, db) mgf1XOR(db, hash, seed) lHash2 := db[0:hash.Size()] // We have to validate the plaintext in constant time in order to avoid // attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal // Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1 // v2.0. In J. Kilian, editor, Advances in Cryptology. lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2) // The remainder of the plaintext must be zero or more 0x00, followed // by 0x01, followed by the message. // lookingForIndex: 1 iff we are still looking for the 0x01 // index: the offset of the first 0x01 byte // invalid: 1 iff we saw a non-zero byte before the 0x01. var lookingForIndex, index, invalid int lookingForIndex = 1 rest := db[hash.Size():] for i := 0; i < len(rest); i++ { equals0 := subtle.ConstantTimeByteEq(rest[i], 0) equals1 := subtle.ConstantTimeByteEq(rest[i], 1) index = subtle.ConstantTimeSelect(lookingForIndex&equals1, i, index) lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex) invalid = subtle.ConstantTimeSelect(lookingForIndex&^equals0, 1, invalid) } if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 { err = ErrDecryption return } msg = rest[index+1:] return } // leftPad returns a new slice of length size. The contents of input are right // aligned in the new slice. func leftPad(input []byte, size int) (out []byte) { n := len(input) if n > size { n = size } out = make([]byte, size) copy(out[len(out)-n:], input) return } ================================================ FILE: scan/crypto/rsa/rsa_test.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rsa import ( "bytes" "crypto" "crypto/rand" "crypto/sha1" "crypto/sha256" "math/big" "testing" ) func TestKeyGeneration(t *testing.T) { size := 1024 if testing.Short() { size = 128 } priv, err := GenerateKey(rand.Reader, size) if err != nil { t.Errorf("failed to generate key") } if bits := priv.N.BitLen(); bits != size { t.Errorf("key too short (%d vs %d)", bits, size) } testKeyBasics(t, priv) } func Test3PrimeKeyGeneration(t *testing.T) { size := 768 if testing.Short() { size = 256 } priv, err := GenerateMultiPrimeKey(rand.Reader, 3, size) if err != nil { t.Errorf("failed to generate key") } testKeyBasics(t, priv) } func Test4PrimeKeyGeneration(t *testing.T) { size := 768 if testing.Short() { size = 256 } priv, err := GenerateMultiPrimeKey(rand.Reader, 4, size) if err != nil { t.Errorf("failed to generate key") } testKeyBasics(t, priv) } func TestNPrimeKeyGeneration(t *testing.T) { primeSize := 64 maxN := 24 if testing.Short() { primeSize = 16 maxN = 16 } // Test that generation of N-prime keys works for N > 4. for n := 5; n < maxN; n++ { priv, err := GenerateMultiPrimeKey(rand.Reader, n, 64+n*primeSize) if err == nil { testKeyBasics(t, priv) } else { t.Errorf("failed to generate %d-prime key", n) } } } func TestGnuTLSKey(t *testing.T) { // This is a key generated by `certtool --generate-privkey --bits 128`. // It's such that de ≢ 1 mod φ(n), but is congruent mod the order of // the group. priv := &PrivateKey{ PublicKey: PublicKey{ N: fromBase10("290684273230919398108010081414538931343"), E: 65537, }, D: fromBase10("31877380284581499213530787347443987241"), Primes: []*big.Int{ fromBase10("16775196964030542637"), fromBase10("17328218193455850539"), }, } testKeyBasics(t, priv) } func testKeyBasics(t *testing.T, priv *PrivateKey) { if err := priv.Validate(); err != nil { t.Errorf("Validate() failed: %s", err) } if priv.D.Cmp(priv.N) > 0 { t.Errorf("private exponent too large") } pub := &priv.PublicKey m := big.NewInt(42) c := encrypt(new(big.Int), pub, m) m2, err := decrypt(nil, priv, c) if err != nil { t.Errorf("error while decrypting: %s", err) return } if m.Cmp(m2) != 0 { t.Errorf("got:%v, want:%v (%+v)", m2, m, priv) } m3, err := decrypt(rand.Reader, priv, c) if err != nil { t.Errorf("error while decrypting (blind): %s", err) } if m.Cmp(m3) != 0 { t.Errorf("(blind) got:%v, want:%v (%#v)", m3, m, priv) } } func fromBase10(base10 string) *big.Int { i, ok := new(big.Int).SetString(base10, 10) if !ok { panic("bad number: " + base10) } return i } var test2048Key *PrivateKey func init() { test2048Key = &PrivateKey{ PublicKey: PublicKey{ N: fromBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557"), E: 3, }, D: fromBase10("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731"), Primes: []*big.Int{ fromBase10("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433"), fromBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029"), }, } test2048Key.Precompute() } func BenchmarkRSA2048Decrypt(b *testing.B) { b.StopTimer() c := fromBase10("8472002792838218989464636159316973636630013835787202418124758118372358261975764365740026024610403138425986214991379012696600761514742817632790916315594342398720903716529235119816755589383377471752116975374952783629225022962092351886861518911824745188989071172097120352727368980275252089141512321893536744324822590480751098257559766328893767334861211872318961900897793874075248286439689249972315699410830094164386544311554704755110361048571142336148077772023880664786019636334369759624917224888206329520528064315309519262325023881707530002540634660750469137117568199824615333883758410040459705787022909848740188613313") b.StartTimer() for i := 0; i < b.N; i++ { decrypt(nil, test2048Key, c) } } func BenchmarkRSA2048Sign(b *testing.B) { b.StopTimer() hashed := sha256.Sum256([]byte("testing")) b.StartTimer() for i := 0; i < b.N; i++ { SignPKCS1v15(rand.Reader, test2048Key, crypto.SHA256, hashed[:]) } } func Benchmark3PrimeRSA2048Decrypt(b *testing.B) { b.StopTimer() priv := &PrivateKey{ PublicKey: PublicKey{ N: fromBase10("16346378922382193400538269749936049106320265317511766357599732575277382844051791096569333808598921852351577762718529818072849191122419410612033592401403764925096136759934497687765453905884149505175426053037420486697072448609022753683683718057795566811401938833367954642951433473337066311978821180526439641496973296037000052546108507805269279414789035461158073156772151892452251106173507240488993608650881929629163465099476849643165682709047462010581308719577053905787496296934240246311806555924593059995202856826239801816771116902778517096212527979497399966526283516447337775509777558018145573127308919204297111496233"), E: 3, }, D: fromBase10("10897585948254795600358846499957366070880176878341177571733155050184921896034527397712889205732614568234385175145686545381899460748279607074689061600935843283397424506622998458510302603922766336783617368686090042765718290914099334449154829375179958369993407724946186243249568928237086215759259909861748642124071874879861299389874230489928271621259294894142840428407196932444474088857746123104978617098858619445675532587787023228852383149557470077802718705420275739737958953794088728369933811184572620857678792001136676902250566845618813972833750098806496641114644760255910789397593428910198080271317419213080834885003"), Primes: []*big.Int{ fromBase10("1025363189502892836833747188838978207017355117492483312747347695538428729137306368764177201532277413433182799108299960196606011786562992097313508180436744488171474690412562218914213688661311117337381958560443"), fromBase10("3467903426626310123395340254094941045497208049900750380025518552334536945536837294961497712862519984786362199788654739924501424784631315081391467293694361474867825728031147665777546570788493758372218019373"), fromBase10("4597024781409332673052708605078359346966325141767460991205742124888960305710298765592730135879076084498363772408626791576005136245060321874472727132746643162385746062759369754202494417496879741537284589047"), }, } priv.Precompute() c := fromBase10("8472002792838218989464636159316973636630013835787202418124758118372358261975764365740026024610403138425986214991379012696600761514742817632790916315594342398720903716529235119816755589383377471752116975374952783629225022962092351886861518911824745188989071172097120352727368980275252089141512321893536744324822590480751098257559766328893767334861211872318961900897793874075248286439689249972315699410830094164386544311554704755110361048571142336148077772023880664786019636334369759624917224888206329520528064315309519262325023881707530002540634660750469137117568199824615333883758410040459705787022909848740188613313") b.StartTimer() for i := 0; i < b.N; i++ { decrypt(nil, priv, c) } } type testEncryptOAEPMessage struct { in []byte seed []byte out []byte } type testEncryptOAEPStruct struct { modulus string e int d string msgs []testEncryptOAEPMessage } func TestEncryptOAEP(t *testing.T) { sha1 := sha1.New() n := new(big.Int) for i, test := range testEncryptOAEPData { n.SetString(test.modulus, 16) public := PublicKey{n, test.e} for j, message := range test.msgs { randomSource := bytes.NewReader(message.seed) out, err := EncryptOAEP(sha1, randomSource, &public, message.in, nil) if err != nil { t.Errorf("#%d,%d error: %s", i, j, err) } if !bytes.Equal(out, message.out) { t.Errorf("#%d,%d bad result: %x (want %x)", i, j, out, message.out) } } } } func TestDecryptOAEP(t *testing.T) { random := rand.Reader sha1 := sha1.New() n := new(big.Int) d := new(big.Int) for i, test := range testEncryptOAEPData { n.SetString(test.modulus, 16) d.SetString(test.d, 16) private := new(PrivateKey) private.PublicKey = PublicKey{n, test.e} private.D = d for j, message := range test.msgs { out, err := DecryptOAEP(sha1, nil, private, message.out, nil) if err != nil { t.Errorf("#%d,%d error: %s", i, j, err) } else if !bytes.Equal(out, message.in) { t.Errorf("#%d,%d bad result: %#v (want %#v)", i, j, out, message.in) } // Decrypt with blinding. out, err = DecryptOAEP(sha1, random, private, message.out, nil) if err != nil { t.Errorf("#%d,%d (blind) error: %s", i, j, err) } else if !bytes.Equal(out, message.in) { t.Errorf("#%d,%d (blind) bad result: %#v (want %#v)", i, j, out, message.in) } } if testing.Short() { break } } } // testEncryptOAEPData contains a subset of the vectors from RSA's "Test vectors for RSA-OAEP". var testEncryptOAEPData = []testEncryptOAEPStruct{ // Key 1 {"a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb", 65537, "53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1", []testEncryptOAEPMessage{ // Example 1.1 { []byte{0x66, 0x28, 0x19, 0x4e, 0x12, 0x07, 0x3d, 0xb0, 0x3b, 0xa9, 0x4c, 0xda, 0x9e, 0xf9, 0x53, 0x23, 0x97, 0xd5, 0x0d, 0xba, 0x79, 0xb9, 0x87, 0x00, 0x4a, 0xfe, 0xfe, 0x34, }, []byte{0x18, 0xb7, 0x76, 0xea, 0x21, 0x06, 0x9d, 0x69, 0x77, 0x6a, 0x33, 0xe9, 0x6b, 0xad, 0x48, 0xe1, 0xdd, 0xa0, 0xa5, 0xef, }, []byte{0x35, 0x4f, 0xe6, 0x7b, 0x4a, 0x12, 0x6d, 0x5d, 0x35, 0xfe, 0x36, 0xc7, 0x77, 0x79, 0x1a, 0x3f, 0x7b, 0xa1, 0x3d, 0xef, 0x48, 0x4e, 0x2d, 0x39, 0x08, 0xaf, 0xf7, 0x22, 0xfa, 0xd4, 0x68, 0xfb, 0x21, 0x69, 0x6d, 0xe9, 0x5d, 0x0b, 0xe9, 0x11, 0xc2, 0xd3, 0x17, 0x4f, 0x8a, 0xfc, 0xc2, 0x01, 0x03, 0x5f, 0x7b, 0x6d, 0x8e, 0x69, 0x40, 0x2d, 0xe5, 0x45, 0x16, 0x18, 0xc2, 0x1a, 0x53, 0x5f, 0xa9, 0xd7, 0xbf, 0xc5, 0xb8, 0xdd, 0x9f, 0xc2, 0x43, 0xf8, 0xcf, 0x92, 0x7d, 0xb3, 0x13, 0x22, 0xd6, 0xe8, 0x81, 0xea, 0xa9, 0x1a, 0x99, 0x61, 0x70, 0xe6, 0x57, 0xa0, 0x5a, 0x26, 0x64, 0x26, 0xd9, 0x8c, 0x88, 0x00, 0x3f, 0x84, 0x77, 0xc1, 0x22, 0x70, 0x94, 0xa0, 0xd9, 0xfa, 0x1e, 0x8c, 0x40, 0x24, 0x30, 0x9c, 0xe1, 0xec, 0xcc, 0xb5, 0x21, 0x00, 0x35, 0xd4, 0x7a, 0xc7, 0x2e, 0x8a, }, }, // Example 1.2 { []byte{0x75, 0x0c, 0x40, 0x47, 0xf5, 0x47, 0xe8, 0xe4, 0x14, 0x11, 0x85, 0x65, 0x23, 0x29, 0x8a, 0xc9, 0xba, 0xe2, 0x45, 0xef, 0xaf, 0x13, 0x97, 0xfb, 0xe5, 0x6f, 0x9d, 0xd5, }, []byte{0x0c, 0xc7, 0x42, 0xce, 0x4a, 0x9b, 0x7f, 0x32, 0xf9, 0x51, 0xbc, 0xb2, 0x51, 0xef, 0xd9, 0x25, 0xfe, 0x4f, 0xe3, 0x5f, }, []byte{0x64, 0x0d, 0xb1, 0xac, 0xc5, 0x8e, 0x05, 0x68, 0xfe, 0x54, 0x07, 0xe5, 0xf9, 0xb7, 0x01, 0xdf, 0xf8, 0xc3, 0xc9, 0x1e, 0x71, 0x6c, 0x53, 0x6f, 0xc7, 0xfc, 0xec, 0x6c, 0xb5, 0xb7, 0x1c, 0x11, 0x65, 0x98, 0x8d, 0x4a, 0x27, 0x9e, 0x15, 0x77, 0xd7, 0x30, 0xfc, 0x7a, 0x29, 0x93, 0x2e, 0x3f, 0x00, 0xc8, 0x15, 0x15, 0x23, 0x6d, 0x8d, 0x8e, 0x31, 0x01, 0x7a, 0x7a, 0x09, 0xdf, 0x43, 0x52, 0xd9, 0x04, 0xcd, 0xeb, 0x79, 0xaa, 0x58, 0x3a, 0xdc, 0xc3, 0x1e, 0xa6, 0x98, 0xa4, 0xc0, 0x52, 0x83, 0xda, 0xba, 0x90, 0x89, 0xbe, 0x54, 0x91, 0xf6, 0x7c, 0x1a, 0x4e, 0xe4, 0x8d, 0xc7, 0x4b, 0xbb, 0xe6, 0x64, 0x3a, 0xef, 0x84, 0x66, 0x79, 0xb4, 0xcb, 0x39, 0x5a, 0x35, 0x2d, 0x5e, 0xd1, 0x15, 0x91, 0x2d, 0xf6, 0x96, 0xff, 0xe0, 0x70, 0x29, 0x32, 0x94, 0x6d, 0x71, 0x49, 0x2b, 0x44, }, }, // Example 1.3 { []byte{0xd9, 0x4a, 0xe0, 0x83, 0x2e, 0x64, 0x45, 0xce, 0x42, 0x33, 0x1c, 0xb0, 0x6d, 0x53, 0x1a, 0x82, 0xb1, 0xdb, 0x4b, 0xaa, 0xd3, 0x0f, 0x74, 0x6d, 0xc9, 0x16, 0xdf, 0x24, 0xd4, 0xe3, 0xc2, 0x45, 0x1f, 0xff, 0x59, 0xa6, 0x42, 0x3e, 0xb0, 0xe1, 0xd0, 0x2d, 0x4f, 0xe6, 0x46, 0xcf, 0x69, 0x9d, 0xfd, 0x81, 0x8c, 0x6e, 0x97, 0xb0, 0x51, }, []byte{0x25, 0x14, 0xdf, 0x46, 0x95, 0x75, 0x5a, 0x67, 0xb2, 0x88, 0xea, 0xf4, 0x90, 0x5c, 0x36, 0xee, 0xc6, 0x6f, 0xd2, 0xfd, }, []byte{0x42, 0x37, 0x36, 0xed, 0x03, 0x5f, 0x60, 0x26, 0xaf, 0x27, 0x6c, 0x35, 0xc0, 0xb3, 0x74, 0x1b, 0x36, 0x5e, 0x5f, 0x76, 0xca, 0x09, 0x1b, 0x4e, 0x8c, 0x29, 0xe2, 0xf0, 0xbe, 0xfe, 0xe6, 0x03, 0x59, 0x5a, 0xa8, 0x32, 0x2d, 0x60, 0x2d, 0x2e, 0x62, 0x5e, 0x95, 0xeb, 0x81, 0xb2, 0xf1, 0xc9, 0x72, 0x4e, 0x82, 0x2e, 0xca, 0x76, 0xdb, 0x86, 0x18, 0xcf, 0x09, 0xc5, 0x34, 0x35, 0x03, 0xa4, 0x36, 0x08, 0x35, 0xb5, 0x90, 0x3b, 0xc6, 0x37, 0xe3, 0x87, 0x9f, 0xb0, 0x5e, 0x0e, 0xf3, 0x26, 0x85, 0xd5, 0xae, 0xc5, 0x06, 0x7c, 0xd7, 0xcc, 0x96, 0xfe, 0x4b, 0x26, 0x70, 0xb6, 0xea, 0xc3, 0x06, 0x6b, 0x1f, 0xcf, 0x56, 0x86, 0xb6, 0x85, 0x89, 0xaa, 0xfb, 0x7d, 0x62, 0x9b, 0x02, 0xd8, 0xf8, 0x62, 0x5c, 0xa3, 0x83, 0x36, 0x24, 0xd4, 0x80, 0x0f, 0xb0, 0x81, 0xb1, 0xcf, 0x94, 0xeb, }, }, }, }, // Key 10 {"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb", 65537, "056b04216fe5f354ac77250a4b6b0c8525a85c59b0bd80c56450a22d5f438e596a333aa875e291dd43f48cb88b9d5fc0d499f9fcd1c397f9afc070cd9e398c8d19e61db7c7410a6b2675dfbf5d345b804d201add502d5ce2dfcb091ce9997bbebe57306f383e4d588103f036f7e85d1934d152a323e4a8db451d6f4a5b1b0f102cc150e02feee2b88dea4ad4c1baccb24d84072d14e1d24a6771f7408ee30564fb86d4393a34bcf0b788501d193303f13a2284b001f0f649eaf79328d4ac5c430ab4414920a9460ed1b7bc40ec653e876d09abc509ae45b525190116a0c26101848298509c1c3bf3a483e7274054e15e97075036e989f60932807b5257751e79", []testEncryptOAEPMessage{ // Example 10.1 { []byte{0x8b, 0xba, 0x6b, 0xf8, 0x2a, 0x6c, 0x0f, 0x86, 0xd5, 0xf1, 0x75, 0x6e, 0x97, 0x95, 0x68, 0x70, 0xb0, 0x89, 0x53, 0xb0, 0x6b, 0x4e, 0xb2, 0x05, 0xbc, 0x16, 0x94, 0xee, }, []byte{0x47, 0xe1, 0xab, 0x71, 0x19, 0xfe, 0xe5, 0x6c, 0x95, 0xee, 0x5e, 0xaa, 0xd8, 0x6f, 0x40, 0xd0, 0xaa, 0x63, 0xbd, 0x33, }, []byte{0x53, 0xea, 0x5d, 0xc0, 0x8c, 0xd2, 0x60, 0xfb, 0x3b, 0x85, 0x85, 0x67, 0x28, 0x7f, 0xa9, 0x15, 0x52, 0xc3, 0x0b, 0x2f, 0xeb, 0xfb, 0xa2, 0x13, 0xf0, 0xae, 0x87, 0x70, 0x2d, 0x06, 0x8d, 0x19, 0xba, 0xb0, 0x7f, 0xe5, 0x74, 0x52, 0x3d, 0xfb, 0x42, 0x13, 0x9d, 0x68, 0xc3, 0xc5, 0xaf, 0xee, 0xe0, 0xbf, 0xe4, 0xcb, 0x79, 0x69, 0xcb, 0xf3, 0x82, 0xb8, 0x04, 0xd6, 0xe6, 0x13, 0x96, 0x14, 0x4e, 0x2d, 0x0e, 0x60, 0x74, 0x1f, 0x89, 0x93, 0xc3, 0x01, 0x4b, 0x58, 0xb9, 0xb1, 0x95, 0x7a, 0x8b, 0xab, 0xcd, 0x23, 0xaf, 0x85, 0x4f, 0x4c, 0x35, 0x6f, 0xb1, 0x66, 0x2a, 0xa7, 0x2b, 0xfc, 0xc7, 0xe5, 0x86, 0x55, 0x9d, 0xc4, 0x28, 0x0d, 0x16, 0x0c, 0x12, 0x67, 0x85, 0xa7, 0x23, 0xeb, 0xee, 0xbe, 0xff, 0x71, 0xf1, 0x15, 0x94, 0x44, 0x0a, 0xae, 0xf8, 0x7d, 0x10, 0x79, 0x3a, 0x87, 0x74, 0xa2, 0x39, 0xd4, 0xa0, 0x4c, 0x87, 0xfe, 0x14, 0x67, 0xb9, 0xda, 0xf8, 0x52, 0x08, 0xec, 0x6c, 0x72, 0x55, 0x79, 0x4a, 0x96, 0xcc, 0x29, 0x14, 0x2f, 0x9a, 0x8b, 0xd4, 0x18, 0xe3, 0xc1, 0xfd, 0x67, 0x34, 0x4b, 0x0c, 0xd0, 0x82, 0x9d, 0xf3, 0xb2, 0xbe, 0xc6, 0x02, 0x53, 0x19, 0x62, 0x93, 0xc6, 0xb3, 0x4d, 0x3f, 0x75, 0xd3, 0x2f, 0x21, 0x3d, 0xd4, 0x5c, 0x62, 0x73, 0xd5, 0x05, 0xad, 0xf4, 0xcc, 0xed, 0x10, 0x57, 0xcb, 0x75, 0x8f, 0xc2, 0x6a, 0xee, 0xfa, 0x44, 0x12, 0x55, 0xed, 0x4e, 0x64, 0xc1, 0x99, 0xee, 0x07, 0x5e, 0x7f, 0x16, 0x64, 0x61, 0x82, 0xfd, 0xb4, 0x64, 0x73, 0x9b, 0x68, 0xab, 0x5d, 0xaf, 0xf0, 0xe6, 0x3e, 0x95, 0x52, 0x01, 0x68, 0x24, 0xf0, 0x54, 0xbf, 0x4d, 0x3c, 0x8c, 0x90, 0xa9, 0x7b, 0xb6, 0xb6, 0x55, 0x32, 0x84, 0xeb, 0x42, 0x9f, 0xcc, }, }, }, }, } ================================================ FILE: scan/crypto/sha1/example_test.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package sha1_test import ( "crypto/sha1" "fmt" "io" ) func ExampleNew() { h := sha1.New() io.WriteString(h, "His money is twice tainted:") io.WriteString(h, " 'taint yours and 'taint mine.") fmt.Printf("% x", h.Sum(nil)) // Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd } func ExampleSum() { data := []byte("This page intentionally left blank.") fmt.Printf("% x", sha1.Sum(data)) // Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96 } ================================================ FILE: scan/crypto/sha1/sha1.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package sha1 implements the SHA1 hash algorithm as defined in RFC 3174. package sha1 import ( "crypto" "hash" ) func init() { crypto.RegisterHash(crypto.SHA1, New) } // The size of a SHA1 checksum in bytes. const Size = 20 // The blocksize of SHA1 in bytes. const BlockSize = 64 const ( chunk = 64 init0 = 0x67452301 init1 = 0xEFCDAB89 init2 = 0x98BADCFE init3 = 0x10325476 init4 = 0xC3D2E1F0 ) // digest represents the partial evaluation of a checksum. type digest struct { h [5]uint32 x [chunk]byte nx int len uint64 } func (d *digest) Reset() { d.h[0] = init0 d.h[1] = init1 d.h[2] = init2 d.h[3] = init3 d.h[4] = init4 d.nx = 0 d.len = 0 } // New returns a new hash.Hash computing the SHA1 checksum. func New() hash.Hash { d := new(digest) d.Reset() return d } func (d *digest) Size() int { return Size } func (d *digest) BlockSize() int { return BlockSize } func (d *digest) Write(p []byte) (nn int, err error) { nn = len(p) d.len += uint64(nn) if d.nx > 0 { n := copy(d.x[d.nx:], p) d.nx += n if d.nx == chunk { block(d, d.x[:]) d.nx = 0 } p = p[n:] } if len(p) >= chunk { n := len(p) &^ (chunk - 1) block(d, p[:n]) p = p[n:] } if len(p) > 0 { d.nx = copy(d.x[:], p) } return } func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0 so that caller can keep writing and summing. d := *d0 hash := d.checkSum() return append(in, hash[:]...) } func (d *digest) checkSum() [Size]byte { len := d.len // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. var tmp [64]byte tmp[0] = 0x80 if len%64 < 56 { d.Write(tmp[0 : 56-len%64]) } else { d.Write(tmp[0 : 64+56-len%64]) } // Length in bits. len <<= 3 for i := uint(0); i < 8; i++ { tmp[i] = byte(len >> (56 - 8*i)) } d.Write(tmp[0:8]) if d.nx != 0 { panic("d.nx != 0") } var digest [Size]byte for i, s := range d.h { digest[i*4] = byte(s >> 24) digest[i*4+1] = byte(s >> 16) digest[i*4+2] = byte(s >> 8) digest[i*4+3] = byte(s) } return digest } // Sum returns the SHA1 checksum of the data. func Sum(data []byte) [Size]byte { var d digest d.Reset() d.Write(data) return d.checkSum() } ================================================ FILE: scan/crypto/sha1/sha1_test.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // SHA1 hash algorithm. See RFC 3174. package sha1 import ( "crypto/rand" "fmt" "io" "testing" ) type sha1Test struct { out string in string } var golden = []sha1Test{ {"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"}, {"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"}, {"81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd"}, {"03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde"}, {"1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef"}, {"2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg"}, {"425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh"}, {"c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi"}, {"d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij"}, {"ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old."}, {"e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last."}, {"45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole."}, {"55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, {"b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard"}, {"c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign."}, {"6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program."}, {"597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine."}, {"6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, {"514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, {"c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic"}, {"74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton"}, {"0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, {"3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you."}, {"410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams."}, {"841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway."}, {"163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!"}, {"32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, {"0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, {"6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick"}, } func TestGolden(t *testing.T) { for i := 0; i < len(golden); i++ { g := golden[i] s := fmt.Sprintf("%x", Sum([]byte(g.in))) if s != g.out { t.Fatalf("Sum function: sha1(%s) = %s want %s", g.in, s, g.out) } c := New() for j := 0; j < 3; j++ { if j < 2 { io.WriteString(c, g.in) } else { io.WriteString(c, g.in[0:len(g.in)/2]) c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out) } c.Reset() } } } func TestSize(t *testing.T) { c := New() if got := c.Size(); got != Size { t.Errorf("Size = %d; want %d", got, Size) } } func TestBlockSize(t *testing.T) { c := New() if got := c.BlockSize(); got != BlockSize { t.Errorf("BlockSize = %d; want %d", got, BlockSize) } } // Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match. func TestBlockGeneric(t *testing.T) { gen, asm := New().(*digest), New().(*digest) buf := make([]byte, BlockSize*20) // arbitrary factor rand.Read(buf) blockGeneric(gen, buf) block(asm, buf) if *gen != *asm { t.Error("block and blockGeneric resulted in different states") } } var bench = New() var buf = make([]byte, 8192) func benchmarkSize(b *testing.B, size int) { b.SetBytes(int64(size)) sum := make([]byte, bench.Size()) for i := 0; i < b.N; i++ { bench.Reset() bench.Write(buf[:size]) bench.Sum(sum[:0]) } } func BenchmarkHash8Bytes(b *testing.B) { benchmarkSize(b, 8) } func BenchmarkHash1K(b *testing.B) { benchmarkSize(b, 1024) } func BenchmarkHash8K(b *testing.B) { benchmarkSize(b, 8192) } ================================================ FILE: scan/crypto/sha1/sha1block.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package sha1 const ( _K0 = 0x5A827999 _K1 = 0x6ED9EBA1 _K2 = 0x8F1BBCDC _K3 = 0xCA62C1D6 ) // blockGeneric is a portable, pure Go version of the SHA1 block step. // It's used by sha1block_generic.go and tests. func blockGeneric(dig *digest, p []byte) { var w [16]uint32 h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] for len(p) >= chunk { // Can interlace the computation of w with the // rounds below if needed for speed. for i := 0; i < 16; i++ { j := i * 4 w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3]) } a, b, c, d, e := h0, h1, h2, h3, h4 // Each of the four 20-iteration rounds // differs only in the computation of f and // the choice of K (_K0, _K1, etc). i := 0 for ; i < 16; i++ { f := b&c | (^b)&d a5 := a<<5 | a>>(32-5) b30 := b<<30 | b>>(32-30) t := a5 + f + e + w[i&0xf] + _K0 a, b, c, d, e = t, a, b30, c, d } for ; i < 20; i++ { tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] w[i&0xf] = tmp<<1 | tmp>>(32-1) f := b&c | (^b)&d a5 := a<<5 | a>>(32-5) b30 := b<<30 | b>>(32-30) t := a5 + f + e + w[i&0xf] + _K0 a, b, c, d, e = t, a, b30, c, d } for ; i < 40; i++ { tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] w[i&0xf] = tmp<<1 | tmp>>(32-1) f := b ^ c ^ d a5 := a<<5 | a>>(32-5) b30 := b<<30 | b>>(32-30) t := a5 + f + e + w[i&0xf] + _K1 a, b, c, d, e = t, a, b30, c, d } for ; i < 60; i++ { tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] w[i&0xf] = tmp<<1 | tmp>>(32-1) f := ((b | c) & d) | (b & c) a5 := a<<5 | a>>(32-5) b30 := b<<30 | b>>(32-30) t := a5 + f + e + w[i&0xf] + _K2 a, b, c, d, e = t, a, b30, c, d } for ; i < 80; i++ { tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] w[i&0xf] = tmp<<1 | tmp>>(32-1) f := b ^ c ^ d a5 := a<<5 | a>>(32-5) b30 := b<<30 | b>>(32-30) t := a5 + f + e + w[i&0xf] + _K3 a, b, c, d, e = t, a, b30, c, d } h0 += a h1 += b h2 += c h3 += d h4 += e p = p[chunk:] } dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] = h0, h1, h2, h3, h4 } ================================================ FILE: scan/crypto/sha1/sha1block_386.s ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include "textflag.h" // SHA1 block routine. See sha1block.go for Go equivalent. // // There are 80 rounds of 4 types: // - rounds 0-15 are type 1 and load data (ROUND1 macro). // - rounds 16-19 are type 1 and do not load data (ROUND1x macro). // - rounds 20-39 are type 2 and do not load data (ROUND2 macro). // - rounds 40-59 are type 3 and do not load data (ROUND3 macro). // - rounds 60-79 are type 4 and do not load data (ROUND4 macro). // // Each round loads or shuffles the data, then computes a per-round // function of b, c, d, and then mixes the result into and rotates the // five registers a, b, c, d, e holding the intermediate results. // // The register rotation is implemented by rotating the arguments to // the round macros instead of by explicit move instructions. // Like sha1block_amd64.s, but we keep the data and limit pointers on the stack. // To free up the word pointer (R10 on amd64, DI here), we add it to e during // LOAD/SHUFFLE instead of during MIX. // // The stack holds the intermediate word array - 16 uint32s - at 0(SP) up to 64(SP). // The saved a, b, c, d, e (R11 through R15 on amd64) are at 64(SP) up to 84(SP). // The saved limit pointer (DI on amd64) is at 84(SP). // The saved data pointer (SI on amd64) is at 88(SP). #define LOAD(index, e) \ MOVL 88(SP), SI; \ MOVL (index*4)(SI), DI; \ BSWAPL DI; \ MOVL DI, (index*4)(SP); \ ADDL DI, e #define SHUFFLE(index, e) \ MOVL (((index)&0xf)*4)(SP), DI; \ XORL (((index-3)&0xf)*4)(SP), DI; \ XORL (((index-8)&0xf)*4)(SP), DI; \ XORL (((index-14)&0xf)*4)(SP), DI; \ ROLL $1, DI; \ MOVL DI, (((index)&0xf)*4)(SP); \ ADDL DI, e #define FUNC1(a, b, c, d, e) \ MOVL d, DI; \ XORL c, DI; \ ANDL b, DI; \ XORL d, DI #define FUNC2(a, b, c, d, e) \ MOVL b, DI; \ XORL c, DI; \ XORL d, DI #define FUNC3(a, b, c, d, e) \ MOVL b, SI; \ ORL c, SI; \ ANDL d, SI; \ MOVL b, DI; \ ANDL c, DI; \ ORL SI, DI #define FUNC4 FUNC2 #define MIX(a, b, c, d, e, const) \ ROLL $30, b; \ ADDL DI, e; \ MOVL a, SI; \ ROLL $5, SI; \ LEAL const(e)(SI*1), e #define ROUND1(a, b, c, d, e, index) \ LOAD(index, e); \ FUNC1(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x5A827999) #define ROUND1x(a, b, c, d, e, index) \ SHUFFLE(index, e); \ FUNC1(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x5A827999) #define ROUND2(a, b, c, d, e, index) \ SHUFFLE(index, e); \ FUNC2(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x6ED9EBA1) #define ROUND3(a, b, c, d, e, index) \ SHUFFLE(index, e); \ FUNC3(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x8F1BBCDC) #define ROUND4(a, b, c, d, e, index) \ SHUFFLE(index, e); \ FUNC4(a, b, c, d, e); \ MIX(a, b, c, d, e, 0xCA62C1D6) // func block(dig *digest, p []byte) TEXT ·block(SB),NOSPLIT,$92-16 MOVL dig+0(FP), BP MOVL p+4(FP), SI MOVL p_len+8(FP), DX SHRL $6, DX SHLL $6, DX LEAL (SI)(DX*1), DI MOVL (0*4)(BP), AX MOVL (1*4)(BP), BX MOVL (2*4)(BP), CX MOVL (3*4)(BP), DX MOVL (4*4)(BP), BP CMPL SI, DI JEQ end MOVL DI, 84(SP) loop: MOVL SI, 88(SP) MOVL AX, 64(SP) MOVL BX, 68(SP) MOVL CX, 72(SP) MOVL DX, 76(SP) MOVL BP, 80(SP) ROUND1(AX, BX, CX, DX, BP, 0) ROUND1(BP, AX, BX, CX, DX, 1) ROUND1(DX, BP, AX, BX, CX, 2) ROUND1(CX, DX, BP, AX, BX, 3) ROUND1(BX, CX, DX, BP, AX, 4) ROUND1(AX, BX, CX, DX, BP, 5) ROUND1(BP, AX, BX, CX, DX, 6) ROUND1(DX, BP, AX, BX, CX, 7) ROUND1(CX, DX, BP, AX, BX, 8) ROUND1(BX, CX, DX, BP, AX, 9) ROUND1(AX, BX, CX, DX, BP, 10) ROUND1(BP, AX, BX, CX, DX, 11) ROUND1(DX, BP, AX, BX, CX, 12) ROUND1(CX, DX, BP, AX, BX, 13) ROUND1(BX, CX, DX, BP, AX, 14) ROUND1(AX, BX, CX, DX, BP, 15) ROUND1x(BP, AX, BX, CX, DX, 16) ROUND1x(DX, BP, AX, BX, CX, 17) ROUND1x(CX, DX, BP, AX, BX, 18) ROUND1x(BX, CX, DX, BP, AX, 19) ROUND2(AX, BX, CX, DX, BP, 20) ROUND2(BP, AX, BX, CX, DX, 21) ROUND2(DX, BP, AX, BX, CX, 22) ROUND2(CX, DX, BP, AX, BX, 23) ROUND2(BX, CX, DX, BP, AX, 24) ROUND2(AX, BX, CX, DX, BP, 25) ROUND2(BP, AX, BX, CX, DX, 26) ROUND2(DX, BP, AX, BX, CX, 27) ROUND2(CX, DX, BP, AX, BX, 28) ROUND2(BX, CX, DX, BP, AX, 29) ROUND2(AX, BX, CX, DX, BP, 30) ROUND2(BP, AX, BX, CX, DX, 31) ROUND2(DX, BP, AX, BX, CX, 32) ROUND2(CX, DX, BP, AX, BX, 33) ROUND2(BX, CX, DX, BP, AX, 34) ROUND2(AX, BX, CX, DX, BP, 35) ROUND2(BP, AX, BX, CX, DX, 36) ROUND2(DX, BP, AX, BX, CX, 37) ROUND2(CX, DX, BP, AX, BX, 38) ROUND2(BX, CX, DX, BP, AX, 39) ROUND3(AX, BX, CX, DX, BP, 40) ROUND3(BP, AX, BX, CX, DX, 41) ROUND3(DX, BP, AX, BX, CX, 42) ROUND3(CX, DX, BP, AX, BX, 43) ROUND3(BX, CX, DX, BP, AX, 44) ROUND3(AX, BX, CX, DX, BP, 45) ROUND3(BP, AX, BX, CX, DX, 46) ROUND3(DX, BP, AX, BX, CX, 47) ROUND3(CX, DX, BP, AX, BX, 48) ROUND3(BX, CX, DX, BP, AX, 49) ROUND3(AX, BX, CX, DX, BP, 50) ROUND3(BP, AX, BX, CX, DX, 51) ROUND3(DX, BP, AX, BX, CX, 52) ROUND3(CX, DX, BP, AX, BX, 53) ROUND3(BX, CX, DX, BP, AX, 54) ROUND3(AX, BX, CX, DX, BP, 55) ROUND3(BP, AX, BX, CX, DX, 56) ROUND3(DX, BP, AX, BX, CX, 57) ROUND3(CX, DX, BP, AX, BX, 58) ROUND3(BX, CX, DX, BP, AX, 59) ROUND4(AX, BX, CX, DX, BP, 60) ROUND4(BP, AX, BX, CX, DX, 61) ROUND4(DX, BP, AX, BX, CX, 62) ROUND4(CX, DX, BP, AX, BX, 63) ROUND4(BX, CX, DX, BP, AX, 64) ROUND4(AX, BX, CX, DX, BP, 65) ROUND4(BP, AX, BX, CX, DX, 66) ROUND4(DX, BP, AX, BX, CX, 67) ROUND4(CX, DX, BP, AX, BX, 68) ROUND4(BX, CX, DX, BP, AX, 69) ROUND4(AX, BX, CX, DX, BP, 70) ROUND4(BP, AX, BX, CX, DX, 71) ROUND4(DX, BP, AX, BX, CX, 72) ROUND4(CX, DX, BP, AX, BX, 73) ROUND4(BX, CX, DX, BP, AX, 74) ROUND4(AX, BX, CX, DX, BP, 75) ROUND4(BP, AX, BX, CX, DX, 76) ROUND4(DX, BP, AX, BX, CX, 77) ROUND4(CX, DX, BP, AX, BX, 78) ROUND4(BX, CX, DX, BP, AX, 79) ADDL 64(SP), AX ADDL 68(SP), BX ADDL 72(SP), CX ADDL 76(SP), DX ADDL 80(SP), BP MOVL 88(SP), SI ADDL $64, SI CMPL SI, 84(SP) JB loop end: MOVL dig+0(FP), DI MOVL AX, (0*4)(DI) MOVL BX, (1*4)(DI) MOVL CX, (2*4)(DI) MOVL DX, (3*4)(DI) MOVL BP, (4*4)(DI) RET ================================================ FILE: scan/crypto/sha1/sha1block_amd64.s ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include "textflag.h" // SHA1 block routine. See sha1block.go for Go equivalent. // // There are 80 rounds of 4 types: // - rounds 0-15 are type 1 and load data (ROUND1 macro). // - rounds 16-19 are type 1 and do not load data (ROUND1x macro). // - rounds 20-39 are type 2 and do not load data (ROUND2 macro). // - rounds 40-59 are type 3 and do not load data (ROUND3 macro). // - rounds 60-79 are type 4 and do not load data (ROUND4 macro). // // Each round loads or shuffles the data, then computes a per-round // function of b, c, d, and then mixes the result into and rotates the // five registers a, b, c, d, e holding the intermediate results. // // The register rotation is implemented by rotating the arguments to // the round macros instead of by explicit move instructions. #define LOAD(index) \ MOVL (index*4)(SI), R10; \ BSWAPL R10; \ MOVL R10, (index*4)(SP) #define SHUFFLE(index) \ MOVL (((index)&0xf)*4)(SP), R10; \ XORL (((index-3)&0xf)*4)(SP), R10; \ XORL (((index-8)&0xf)*4)(SP), R10; \ XORL (((index-14)&0xf)*4)(SP), R10; \ ROLL $1, R10; \ MOVL R10, (((index)&0xf)*4)(SP) #define FUNC1(a, b, c, d, e) \ MOVL d, R9; \ XORL c, R9; \ ANDL b, R9; \ XORL d, R9 #define FUNC2(a, b, c, d, e) \ MOVL b, R9; \ XORL c, R9; \ XORL d, R9 #define FUNC3(a, b, c, d, e) \ MOVL b, R8; \ ORL c, R8; \ ANDL d, R8; \ MOVL b, R9; \ ANDL c, R9; \ ORL R8, R9 #define FUNC4 FUNC2 #define MIX(a, b, c, d, e, const) \ ROLL $30, b; \ ADDL R9, e; \ MOVL a, R8; \ ROLL $5, R8; \ LEAL const(e)(R10*1), e; \ ADDL R8, e #define ROUND1(a, b, c, d, e, index) \ LOAD(index); \ FUNC1(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x5A827999) #define ROUND1x(a, b, c, d, e, index) \ SHUFFLE(index); \ FUNC1(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x5A827999) #define ROUND2(a, b, c, d, e, index) \ SHUFFLE(index); \ FUNC2(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x6ED9EBA1) #define ROUND3(a, b, c, d, e, index) \ SHUFFLE(index); \ FUNC3(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x8F1BBCDC) #define ROUND4(a, b, c, d, e, index) \ SHUFFLE(index); \ FUNC4(a, b, c, d, e); \ MIX(a, b, c, d, e, 0xCA62C1D6) TEXT ·block(SB),NOSPLIT,$64-32 MOVQ dig+0(FP), BP MOVQ p_base+8(FP), SI MOVQ p_len+16(FP), DX SHRQ $6, DX SHLQ $6, DX LEAQ (SI)(DX*1), DI MOVL (0*4)(BP), AX MOVL (1*4)(BP), BX MOVL (2*4)(BP), CX MOVL (3*4)(BP), DX MOVL (4*4)(BP), BP CMPQ SI, DI JEQ end loop: MOVL AX, R11 MOVL BX, R12 MOVL CX, R13 MOVL DX, R14 MOVL BP, R15 ROUND1(AX, BX, CX, DX, BP, 0) ROUND1(BP, AX, BX, CX, DX, 1) ROUND1(DX, BP, AX, BX, CX, 2) ROUND1(CX, DX, BP, AX, BX, 3) ROUND1(BX, CX, DX, BP, AX, 4) ROUND1(AX, BX, CX, DX, BP, 5) ROUND1(BP, AX, BX, CX, DX, 6) ROUND1(DX, BP, AX, BX, CX, 7) ROUND1(CX, DX, BP, AX, BX, 8) ROUND1(BX, CX, DX, BP, AX, 9) ROUND1(AX, BX, CX, DX, BP, 10) ROUND1(BP, AX, BX, CX, DX, 11) ROUND1(DX, BP, AX, BX, CX, 12) ROUND1(CX, DX, BP, AX, BX, 13) ROUND1(BX, CX, DX, BP, AX, 14) ROUND1(AX, BX, CX, DX, BP, 15) ROUND1x(BP, AX, BX, CX, DX, 16) ROUND1x(DX, BP, AX, BX, CX, 17) ROUND1x(CX, DX, BP, AX, BX, 18) ROUND1x(BX, CX, DX, BP, AX, 19) ROUND2(AX, BX, CX, DX, BP, 20) ROUND2(BP, AX, BX, CX, DX, 21) ROUND2(DX, BP, AX, BX, CX, 22) ROUND2(CX, DX, BP, AX, BX, 23) ROUND2(BX, CX, DX, BP, AX, 24) ROUND2(AX, BX, CX, DX, BP, 25) ROUND2(BP, AX, BX, CX, DX, 26) ROUND2(DX, BP, AX, BX, CX, 27) ROUND2(CX, DX, BP, AX, BX, 28) ROUND2(BX, CX, DX, BP, AX, 29) ROUND2(AX, BX, CX, DX, BP, 30) ROUND2(BP, AX, BX, CX, DX, 31) ROUND2(DX, BP, AX, BX, CX, 32) ROUND2(CX, DX, BP, AX, BX, 33) ROUND2(BX, CX, DX, BP, AX, 34) ROUND2(AX, BX, CX, DX, BP, 35) ROUND2(BP, AX, BX, CX, DX, 36) ROUND2(DX, BP, AX, BX, CX, 37) ROUND2(CX, DX, BP, AX, BX, 38) ROUND2(BX, CX, DX, BP, AX, 39) ROUND3(AX, BX, CX, DX, BP, 40) ROUND3(BP, AX, BX, CX, DX, 41) ROUND3(DX, BP, AX, BX, CX, 42) ROUND3(CX, DX, BP, AX, BX, 43) ROUND3(BX, CX, DX, BP, AX, 44) ROUND3(AX, BX, CX, DX, BP, 45) ROUND3(BP, AX, BX, CX, DX, 46) ROUND3(DX, BP, AX, BX, CX, 47) ROUND3(CX, DX, BP, AX, BX, 48) ROUND3(BX, CX, DX, BP, AX, 49) ROUND3(AX, BX, CX, DX, BP, 50) ROUND3(BP, AX, BX, CX, DX, 51) ROUND3(DX, BP, AX, BX, CX, 52) ROUND3(CX, DX, BP, AX, BX, 53) ROUND3(BX, CX, DX, BP, AX, 54) ROUND3(AX, BX, CX, DX, BP, 55) ROUND3(BP, AX, BX, CX, DX, 56) ROUND3(DX, BP, AX, BX, CX, 57) ROUND3(CX, DX, BP, AX, BX, 58) ROUND3(BX, CX, DX, BP, AX, 59) ROUND4(AX, BX, CX, DX, BP, 60) ROUND4(BP, AX, BX, CX, DX, 61) ROUND4(DX, BP, AX, BX, CX, 62) ROUND4(CX, DX, BP, AX, BX, 63) ROUND4(BX, CX, DX, BP, AX, 64) ROUND4(AX, BX, CX, DX, BP, 65) ROUND4(BP, AX, BX, CX, DX, 66) ROUND4(DX, BP, AX, BX, CX, 67) ROUND4(CX, DX, BP, AX, BX, 68) ROUND4(BX, CX, DX, BP, AX, 69) ROUND4(AX, BX, CX, DX, BP, 70) ROUND4(BP, AX, BX, CX, DX, 71) ROUND4(DX, BP, AX, BX, CX, 72) ROUND4(CX, DX, BP, AX, BX, 73) ROUND4(BX, CX, DX, BP, AX, 74) ROUND4(AX, BX, CX, DX, BP, 75) ROUND4(BP, AX, BX, CX, DX, 76) ROUND4(DX, BP, AX, BX, CX, 77) ROUND4(CX, DX, BP, AX, BX, 78) ROUND4(BX, CX, DX, BP, AX, 79) ADDL R11, AX ADDL R12, BX ADDL R13, CX ADDL R14, DX ADDL R15, BP ADDQ $64, SI CMPQ SI, DI JB loop end: MOVQ dig+0(FP), DI MOVL AX, (0*4)(DI) MOVL BX, (1*4)(DI) MOVL CX, (2*4)(DI) MOVL DX, (3*4)(DI) MOVL BP, (4*4)(DI) RET ================================================ FILE: scan/crypto/sha1/sha1block_amd64p32.s ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include "textflag.h" // SHA1 block routine. See sha1block.go for Go equivalent. // // There are 80 rounds of 4 types: // - rounds 0-15 are type 1 and load data (ROUND1 macro). // - rounds 16-19 are type 1 and do not load data (ROUND1x macro). // - rounds 20-39 are type 2 and do not load data (ROUND2 macro). // - rounds 40-59 are type 3 and do not load data (ROUND3 macro). // - rounds 60-79 are type 4 and do not load data (ROUND4 macro). // // Each round loads or shuffles the data, then computes a per-round // function of b, c, d, and then mixes the result into and rotates the // five registers a, b, c, d, e holding the intermediate results. // // The register rotation is implemented by rotating the arguments to // the round macros instead of by explicit move instructions. // // amd64p32 version. // To ensure safety for Native Client, avoids use of BP and R15 // as well as two-register addressing modes. #define LOAD(index) \ MOVL (index*4)(SI), R10; \ BSWAPL R10; \ MOVL R10, (index*4)(SP) #define SHUFFLE(index) \ MOVL (((index)&0xf)*4)(SP), R10; \ XORL (((index-3)&0xf)*4)(SP), R10; \ XORL (((index-8)&0xf)*4)(SP), R10; \ XORL (((index-14)&0xf)*4)(SP), R10; \ ROLL $1, R10; \ MOVL R10, (((index)&0xf)*4)(SP) #define FUNC1(a, b, c, d, e) \ MOVL d, R9; \ XORL c, R9; \ ANDL b, R9; \ XORL d, R9 #define FUNC2(a, b, c, d, e) \ MOVL b, R9; \ XORL c, R9; \ XORL d, R9 #define FUNC3(a, b, c, d, e) \ MOVL b, R8; \ ORL c, R8; \ ANDL d, R8; \ MOVL b, R9; \ ANDL c, R9; \ ORL R8, R9 #define FUNC4 FUNC2 #define MIX(a, b, c, d, e, const) \ ROLL $30, b; \ ADDL R9, e; \ MOVL a, R8; \ ROLL $5, R8; \ LEAL const(e)(R10*1), e; \ ADDL R8, e #define ROUND1(a, b, c, d, e, index) \ LOAD(index); \ FUNC1(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x5A827999) #define ROUND1x(a, b, c, d, e, index) \ SHUFFLE(index); \ FUNC1(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x5A827999) #define ROUND2(a, b, c, d, e, index) \ SHUFFLE(index); \ FUNC2(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x6ED9EBA1) #define ROUND3(a, b, c, d, e, index) \ SHUFFLE(index); \ FUNC3(a, b, c, d, e); \ MIX(a, b, c, d, e, 0x8F1BBCDC) #define ROUND4(a, b, c, d, e, index) \ SHUFFLE(index); \ FUNC4(a, b, c, d, e); \ MIX(a, b, c, d, e, 0xCA62C1D6) TEXT ·block(SB),NOSPLIT,$64-32 MOVL dig+0(FP), R14 MOVL p_base+4(FP), SI MOVL p_len+8(FP), DX SHRQ $6, DX SHLQ $6, DX LEAQ (SI)(DX*1), DI MOVL (0*4)(R14), AX MOVL (1*4)(R14), BX MOVL (2*4)(R14), CX MOVL (3*4)(R14), DX MOVL (4*4)(R14), R13 CMPQ SI, DI JEQ end loop: #define BP R13 /* keep diff from sha1block_amd64.s small */ ROUND1(AX, BX, CX, DX, BP, 0) ROUND1(BP, AX, BX, CX, DX, 1) ROUND1(DX, BP, AX, BX, CX, 2) ROUND1(CX, DX, BP, AX, BX, 3) ROUND1(BX, CX, DX, BP, AX, 4) ROUND1(AX, BX, CX, DX, BP, 5) ROUND1(BP, AX, BX, CX, DX, 6) ROUND1(DX, BP, AX, BX, CX, 7) ROUND1(CX, DX, BP, AX, BX, 8) ROUND1(BX, CX, DX, BP, AX, 9) ROUND1(AX, BX, CX, DX, BP, 10) ROUND1(BP, AX, BX, CX, DX, 11) ROUND1(DX, BP, AX, BX, CX, 12) ROUND1(CX, DX, BP, AX, BX, 13) ROUND1(BX, CX, DX, BP, AX, 14) ROUND1(AX, BX, CX, DX, BP, 15) ROUND1x(BP, AX, BX, CX, DX, 16) ROUND1x(DX, BP, AX, BX, CX, 17) ROUND1x(CX, DX, BP, AX, BX, 18) ROUND1x(BX, CX, DX, BP, AX, 19) ROUND2(AX, BX, CX, DX, BP, 20) ROUND2(BP, AX, BX, CX, DX, 21) ROUND2(DX, BP, AX, BX, CX, 22) ROUND2(CX, DX, BP, AX, BX, 23) ROUND2(BX, CX, DX, BP, AX, 24) ROUND2(AX, BX, CX, DX, BP, 25) ROUND2(BP, AX, BX, CX, DX, 26) ROUND2(DX, BP, AX, BX, CX, 27) ROUND2(CX, DX, BP, AX, BX, 28) ROUND2(BX, CX, DX, BP, AX, 29) ROUND2(AX, BX, CX, DX, BP, 30) ROUND2(BP, AX, BX, CX, DX, 31) ROUND2(DX, BP, AX, BX, CX, 32) ROUND2(CX, DX, BP, AX, BX, 33) ROUND2(BX, CX, DX, BP, AX, 34) ROUND2(AX, BX, CX, DX, BP, 35) ROUND2(BP, AX, BX, CX, DX, 36) ROUND2(DX, BP, AX, BX, CX, 37) ROUND2(CX, DX, BP, AX, BX, 38) ROUND2(BX, CX, DX, BP, AX, 39) ROUND3(AX, BX, CX, DX, BP, 40) ROUND3(BP, AX, BX, CX, DX, 41) ROUND3(DX, BP, AX, BX, CX, 42) ROUND3(CX, DX, BP, AX, BX, 43) ROUND3(BX, CX, DX, BP, AX, 44) ROUND3(AX, BX, CX, DX, BP, 45) ROUND3(BP, AX, BX, CX, DX, 46) ROUND3(DX, BP, AX, BX, CX, 47) ROUND3(CX, DX, BP, AX, BX, 48) ROUND3(BX, CX, DX, BP, AX, 49) ROUND3(AX, BX, CX, DX, BP, 50) ROUND3(BP, AX, BX, CX, DX, 51) ROUND3(DX, BP, AX, BX, CX, 52) ROUND3(CX, DX, BP, AX, BX, 53) ROUND3(BX, CX, DX, BP, AX, 54) ROUND3(AX, BX, CX, DX, BP, 55) ROUND3(BP, AX, BX, CX, DX, 56) ROUND3(DX, BP, AX, BX, CX, 57) ROUND3(CX, DX, BP, AX, BX, 58) ROUND3(BX, CX, DX, BP, AX, 59) ROUND4(AX, BX, CX, DX, BP, 60) ROUND4(BP, AX, BX, CX, DX, 61) ROUND4(DX, BP, AX, BX, CX, 62) ROUND4(CX, DX, BP, AX, BX, 63) ROUND4(BX, CX, DX, BP, AX, 64) ROUND4(AX, BX, CX, DX, BP, 65) ROUND4(BP, AX, BX, CX, DX, 66) ROUND4(DX, BP, AX, BX, CX, 67) ROUND4(CX, DX, BP, AX, BX, 68) ROUND4(BX, CX, DX, BP, AX, 69) ROUND4(AX, BX, CX, DX, BP, 70) ROUND4(BP, AX, BX, CX, DX, 71) ROUND4(DX, BP, AX, BX, CX, 72) ROUND4(CX, DX, BP, AX, BX, 73) ROUND4(BX, CX, DX, BP, AX, 74) ROUND4(AX, BX, CX, DX, BP, 75) ROUND4(BP, AX, BX, CX, DX, 76) ROUND4(DX, BP, AX, BX, CX, 77) ROUND4(CX, DX, BP, AX, BX, 78) ROUND4(BX, CX, DX, BP, AX, 79) #undef BP ADDL (0*4)(R14), AX ADDL (1*4)(R14), BX ADDL (2*4)(R14), CX ADDL (3*4)(R14), DX ADDL (4*4)(R14), R13 MOVL AX, (0*4)(R14) MOVL BX, (1*4)(R14) MOVL CX, (2*4)(R14) MOVL DX, (3*4)(R14) MOVL R13, (4*4)(R14) ADDQ $64, SI CMPQ SI, DI JB loop end: RET ================================================ FILE: scan/crypto/sha1/sha1block_arm.s ================================================ // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // // ARM version of md5block.go #include "textflag.h" // SHA1 block routine. See sha1block.go for Go equivalent. // // There are 80 rounds of 4 types: // - rounds 0-15 are type 1 and load data (ROUND1 macro). // - rounds 16-19 are type 1 and do not load data (ROUND1x macro). // - rounds 20-39 are type 2 and do not load data (ROUND2 macro). // - rounds 40-59 are type 3 and do not load data (ROUND3 macro). // - rounds 60-79 are type 4 and do not load data (ROUND4 macro). // // Each round loads or shuffles the data, then computes a per-round // function of b, c, d, and then mixes the result into and rotates the // five registers a, b, c, d, e holding the intermediate results. // // The register rotation is implemented by rotating the arguments to // the round macros instead of by explicit move instructions. // Register definitions #define Rdata R0 // Pointer to incoming data #define Rconst R1 // Current constant for SHA round #define Ra R2 // SHA1 accumulator #define Rb R3 // SHA1 accumulator #define Rc R4 // SHA1 accumulator #define Rd R5 // SHA1 accumulator #define Re R6 // SHA1 accumulator #define Rt0 R7 // Temporary #define Rt1 R8 // Temporary // r9, r10 are forbidden // r11 is OK provided you check the assembler that no synthetic instructions use it #define Rt2 R11 // Temporary #define Rctr R12 // loop counter #define Rw R14 // point to w buffer // func block(dig *digest, p []byte) // 0(FP) is *digest // 4(FP) is p.array (struct Slice) // 8(FP) is p.len //12(FP) is p.cap // // Stack frame #define p_end end-4(SP) // pointer to the end of data #define p_data data-8(SP) // current data pointer (unused?) #define w_buf buf-(8+4*80)(SP) //80 words temporary buffer w uint32[80] #define saved abcde-(8+4*80+4*5)(SP) // saved sha1 registers a,b,c,d,e - these must be last (unused?) // Total size +4 for saved LR is 352 // w[i] = p[j]<<24 | p[j+1]<<16 | p[j+2]<<8 | p[j+3] // e += w[i] #define LOAD(Re) \ MOVBU 2(Rdata), Rt0 ; \ MOVBU 3(Rdata), Rt1 ; \ MOVBU 1(Rdata), Rt2 ; \ ORR Rt0<<8, Rt1, Rt0 ; \ MOVBU.P 4(Rdata), Rt1 ; \ ORR Rt2<<16, Rt0, Rt0 ; \ ORR Rt1<<24, Rt0, Rt0 ; \ MOVW.P Rt0, 4(Rw) ; \ ADD Rt0, Re, Re // tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] // w[i&0xf] = tmp<<1 | tmp>>(32-1) // e += w[i&0xf] #define SHUFFLE(Re) \ MOVW (-16*4)(Rw), Rt0 ; \ MOVW (-14*4)(Rw), Rt1 ; \ MOVW (-8*4)(Rw), Rt2 ; \ EOR Rt0, Rt1, Rt0 ; \ MOVW (-3*4)(Rw), Rt1 ; \ EOR Rt2, Rt0, Rt0 ; \ EOR Rt0, Rt1, Rt0 ; \ MOVW Rt0@>(32-1), Rt0 ; \ MOVW.P Rt0, 4(Rw) ; \ ADD Rt0, Re, Re // t1 = (b & c) | ((~b) & d) #define FUNC1(Ra, Rb, Rc, Rd, Re) \ MVN Rb, Rt1 ; \ AND Rb, Rc, Rt0 ; \ AND Rd, Rt1, Rt1 ; \ ORR Rt0, Rt1, Rt1 // t1 = b ^ c ^ d #define FUNC2(Ra, Rb, Rc, Rd, Re) \ EOR Rb, Rc, Rt1 ; \ EOR Rd, Rt1, Rt1 // t1 = (b & c) | (b & d) | (c & d) = // t1 = (b & c) | ((b | c) & d) #define FUNC3(Ra, Rb, Rc, Rd, Re) \ ORR Rb, Rc, Rt0 ; \ AND Rb, Rc, Rt1 ; \ AND Rd, Rt0, Rt0 ; \ ORR Rt0, Rt1, Rt1 #define FUNC4 FUNC2 // a5 := a<<5 | a>>(32-5) // b = b<<30 | b>>(32-30) // e = a5 + t1 + e + const #define MIX(Ra, Rb, Rc, Rd, Re) \ ADD Rt1, Re, Re ; \ MOVW Rb@>(32-30), Rb ; \ ADD Ra@>(32-5), Re, Re ; \ ADD Rconst, Re, Re #define ROUND1(Ra, Rb, Rc, Rd, Re) \ LOAD(Re) ; \ FUNC1(Ra, Rb, Rc, Rd, Re) ; \ MIX(Ra, Rb, Rc, Rd, Re) #define ROUND1x(Ra, Rb, Rc, Rd, Re) \ SHUFFLE(Re) ; \ FUNC1(Ra, Rb, Rc, Rd, Re) ; \ MIX(Ra, Rb, Rc, Rd, Re) #define ROUND2(Ra, Rb, Rc, Rd, Re) \ SHUFFLE(Re) ; \ FUNC2(Ra, Rb, Rc, Rd, Re) ; \ MIX(Ra, Rb, Rc, Rd, Re) #define ROUND3(Ra, Rb, Rc, Rd, Re) \ SHUFFLE(Re) ; \ FUNC3(Ra, Rb, Rc, Rd, Re) ; \ MIX(Ra, Rb, Rc, Rd, Re) #define ROUND4(Ra, Rb, Rc, Rd, Re) \ SHUFFLE(Re) ; \ FUNC4(Ra, Rb, Rc, Rd, Re) ; \ MIX(Ra, Rb, Rc, Rd, Re) // func block(dig *digest, p []byte) TEXT ·block(SB), 0, $352-16 MOVW p+4(FP), Rdata // pointer to the data MOVW p_len+8(FP), Rt0 // number of bytes ADD Rdata, Rt0 MOVW Rt0, p_end // pointer to end of data // Load up initial SHA1 accumulator MOVW dig+0(FP), Rt0 MOVM.IA (Rt0), [Ra,Rb,Rc,Rd,Re] loop: // Save registers at SP+4 onwards MOVM.IB [Ra,Rb,Rc,Rd,Re], (R13) MOVW $w_buf, Rw MOVW $0x5A827999, Rconst MOVW $3, Rctr loop1: ROUND1(Ra, Rb, Rc, Rd, Re) ROUND1(Re, Ra, Rb, Rc, Rd) ROUND1(Rd, Re, Ra, Rb, Rc) ROUND1(Rc, Rd, Re, Ra, Rb) ROUND1(Rb, Rc, Rd, Re, Ra) SUB.S $1, Rctr BNE loop1 ROUND1(Ra, Rb, Rc, Rd, Re) ROUND1x(Re, Ra, Rb, Rc, Rd) ROUND1x(Rd, Re, Ra, Rb, Rc) ROUND1x(Rc, Rd, Re, Ra, Rb) ROUND1x(Rb, Rc, Rd, Re, Ra) MOVW $0x6ED9EBA1, Rconst MOVW $4, Rctr loop2: ROUND2(Ra, Rb, Rc, Rd, Re) ROUND2(Re, Ra, Rb, Rc, Rd) ROUND2(Rd, Re, Ra, Rb, Rc) ROUND2(Rc, Rd, Re, Ra, Rb) ROUND2(Rb, Rc, Rd, Re, Ra) SUB.S $1, Rctr BNE loop2 MOVW $0x8F1BBCDC, Rconst MOVW $4, Rctr loop3: ROUND3(Ra, Rb, Rc, Rd, Re) ROUND3(Re, Ra, Rb, Rc, Rd) ROUND3(Rd, Re, Ra, Rb, Rc) ROUND3(Rc, Rd, Re, Ra, Rb) ROUND3(Rb, Rc, Rd, Re, Ra) SUB.S $1, Rctr BNE loop3 MOVW $0xCA62C1D6, Rconst MOVW $4, Rctr loop4: ROUND4(Ra, Rb, Rc, Rd, Re) ROUND4(Re, Ra, Rb, Rc, Rd) ROUND4(Rd, Re, Ra, Rb, Rc) ROUND4(Rc, Rd, Re, Ra, Rb) ROUND4(Rb, Rc, Rd, Re, Ra) SUB.S $1, Rctr BNE loop4 // Accumulate - restoring registers from SP+4 MOVM.IB (R13), [Rt0,Rt1,Rt2,Rctr,Rw] ADD Rt0, Ra ADD Rt1, Rb ADD Rt2, Rc ADD Rctr, Rd ADD Rw, Re MOVW p_end, Rt0 CMP Rt0, Rdata BLO loop // Save final SHA1 accumulator MOVW dig+0(FP), Rt0 MOVM.IA [Ra,Rb,Rc,Rd,Re], (Rt0) RET ================================================ FILE: scan/crypto/sha1/sha1block_decl.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build amd64 || amd64p32 || arm || 386 // +build amd64 amd64p32 arm 386 package sha1 //go:noescape func block(dig *digest, p []byte) ================================================ FILE: scan/crypto/sha1/sha1block_generic.go ================================================ // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !amd64 && !amd64p32 && !386 && !arm // +build !amd64,!amd64p32,!386,!arm package sha1 var block = blockGeneric ================================================ FILE: scan/crypto/sha256/sha256.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package sha256 implements the SHA224 and SHA256 hash algorithms as defined // in FIPS 180-4. package sha256 import ( "crypto" "hash" ) func init() { crypto.RegisterHash(crypto.SHA224, New224) crypto.RegisterHash(crypto.SHA256, New) } // The size of a SHA256 checksum in bytes. const Size = 32 // The size of a SHA224 checksum in bytes. const Size224 = 28 // The blocksize of SHA256 and SHA224 in bytes. const BlockSize = 64 const ( chunk = 64 init0 = 0x6A09E667 init1 = 0xBB67AE85 init2 = 0x3C6EF372 init3 = 0xA54FF53A init4 = 0x510E527F init5 = 0x9B05688C init6 = 0x1F83D9AB init7 = 0x5BE0CD19 init0_224 = 0xC1059ED8 init1_224 = 0x367CD507 init2_224 = 0x3070DD17 init3_224 = 0xF70E5939 init4_224 = 0xFFC00B31 init5_224 = 0x68581511 init6_224 = 0x64F98FA7 init7_224 = 0xBEFA4FA4 ) // digest represents the partial evaluation of a checksum. type digest struct { h [8]uint32 x [chunk]byte nx int len uint64 is224 bool // mark if this digest is SHA-224 } func (d *digest) Reset() { if !d.is224 { d.h[0] = init0 d.h[1] = init1 d.h[2] = init2 d.h[3] = init3 d.h[4] = init4 d.h[5] = init5 d.h[6] = init6 d.h[7] = init7 } else { d.h[0] = init0_224 d.h[1] = init1_224 d.h[2] = init2_224 d.h[3] = init3_224 d.h[4] = init4_224 d.h[5] = init5_224 d.h[6] = init6_224 d.h[7] = init7_224 } d.nx = 0 d.len = 0 } // New returns a new hash.Hash computing the SHA256 checksum. func New() hash.Hash { d := new(digest) d.Reset() return d } // New224 returns a new hash.Hash computing the SHA224 checksum. func New224() hash.Hash { d := new(digest) d.is224 = true d.Reset() return d } func (d *digest) Size() int { if !d.is224 { return Size } return Size224 } func (d *digest) BlockSize() int { return BlockSize } func (d *digest) Write(p []byte) (nn int, err error) { nn = len(p) d.len += uint64(nn) if d.nx > 0 { n := copy(d.x[d.nx:], p) d.nx += n if d.nx == chunk { block(d, d.x[:]) d.nx = 0 } p = p[n:] } if len(p) >= chunk { n := len(p) &^ (chunk - 1) block(d, p[:n]) p = p[n:] } if len(p) > 0 { d.nx = copy(d.x[:], p) } return } func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0 so that caller can keep writing and summing. d := *d0 hash := d.checkSum() if d.is224 { return append(in, hash[:Size224]...) } return append(in, hash[:]...) } func (d *digest) checkSum() [Size]byte { len := d.len // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. var tmp [64]byte tmp[0] = 0x80 if len%64 < 56 { d.Write(tmp[0 : 56-len%64]) } else { d.Write(tmp[0 : 64+56-len%64]) } // Length in bits. len <<= 3 for i := uint(0); i < 8; i++ { tmp[i] = byte(len >> (56 - 8*i)) } d.Write(tmp[0:8]) if d.nx != 0 { panic("d.nx != 0") } h := d.h[:] if d.is224 { h = d.h[:7] } var digest [Size]byte for i, s := range h { digest[i*4] = byte(s >> 24) digest[i*4+1] = byte(s >> 16) digest[i*4+2] = byte(s >> 8) digest[i*4+3] = byte(s) } return digest } // Sum256 returns the SHA256 checksum of the data. func Sum256(data []byte) [Size]byte { var d digest d.Reset() d.Write(data) return d.checkSum() } // Sum224 returns the SHA224 checksum of the data. func Sum224(data []byte) (sum224 [Size224]byte) { var d digest d.is224 = true d.Reset() d.Write(data) sum := d.checkSum() copy(sum224[:], sum[:Size224]) return } ================================================ FILE: scan/crypto/sha256/sha256_test.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // SHA256 hash algorithm. See FIPS 180-2. package sha256 import ( "fmt" "io" "testing" ) type sha256Test struct { out string in string } var golden = []sha256Test{ {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"}, {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"}, {"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"}, {"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd"}, {"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde"}, {"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef"}, {"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg"}, {"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh"}, {"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi"}, {"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij"}, {"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old."}, {"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last."}, {"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole."}, {"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, {"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered. -Tom Stoppard"}, {"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign."}, {"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program."}, {"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine."}, {"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, {"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, {"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size: a.out: bad magic"}, {"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail. -Mark Horton"}, {"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, {"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you."}, {"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams."}, {"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway."}, {"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!"}, {"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, {"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick"}, } var golden224 = []sha256Test{ {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""}, {"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", "a"}, {"db3cda86d4429a1d39c148989566b38f7bda0156296bd364ba2f878b", "ab"}, {"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"}, {"a76654d8e3550e9a2d67a0eeb6c67b220e5885eddd3fde135806e601", "abcd"}, {"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6", "abcde"}, {"7043631cb415556a275a4ebecb802c74ee9f6153908e1792a90b6a98", "abcdef"}, {"d1884e711701ad81abe0c77a3b0ea12e19ba9af64077286c72fc602d", "abcdefg"}, {"17eb7d40f0356f8598e89eafad5f6c759b1f822975d9c9b737c8a517", "abcdefgh"}, {"aeb35915346c584db820d2de7af3929ffafef9222a9bcb26516c7334", "abcdefghi"}, {"d35e1e5af29ddb0d7e154357df4ad9842afee527c689ee547f753188", "abcdefghij"}, {"19297f1cef7ddc8a7e947f5c5a341e10f7245045e425db67043988d7", "Discard medicine more than two years old."}, {"0f10c2eb436251f777fbbd125e260d36aecf180411726c7c885f599a", "He who has a shady past knows that nice guys finish last."}, {"4d1842104919f314cad8a3cd20b3cba7e8ed3e7abed62b57441358f6", "I wouldn't marry him with a ten foot pole."}, {"a8ba85c6fe0c48fbffc72bbb2f03fcdbc87ae2dc7a56804d1590fb3b", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, {"5543fbab26e67e8885b1a852d567d1cb8b9bfe42e0899584c50449a9", "The days of the digital watch are numbered. -Tom Stoppard"}, {"65ca107390f5da9efa05d28e57b221657edc7e43a9a18fb15b053ddb", "Nepal premier won't resign."}, {"84953962be366305a9cc9b5cd16ed019edc37ac96c0deb3e12cca116", "For every action there is an equal and opposite government program."}, {"35a189ce987151dfd00b3577583cc6a74b9869eecf894459cb52038d", "His money is twice tainted: 'taint yours and 'taint mine."}, {"2fc333713983edfd4ef2c0da6fb6d6415afb94987c91e4069eb063e6", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, {"cbe32d38d577a1b355960a4bc3c659c2dc4670859a19777a875842c4", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, {"a2dc118ce959e027576413a7b440c875cdc8d40df9141d6ef78a57e1", "size: a.out: bad magic"}, {"d10787e24052bcff26dc484787a54ed819e4e4511c54890ee977bf81", "The major problem is with sendmail. -Mark Horton"}, {"62efcf16ab8a893acdf2f348aaf06b63039ff1bf55508c830532c9fb", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, {"3e9b7e4613c59f58665104c5fa86c272db5d3a2ff30df5bb194a5c99", "If the enemy is within range, then so are you."}, {"5999c208b8bdf6d471bb7c359ac5b829e73a8211dff686143a4e7f18", "It's well we cannot hear the screams/That we create in others' dreams."}, {"3b2d67ff54eabc4ef737b14edf87c64280ef582bcdf2a6d56908b405", "You remind me of a TV show, but that's all right: I watch it anyway."}, {"d0733595d20e4d3d6b5c565a445814d1bbb2fd08b9a3b8ffb97930c6", "C is as portable as Stonehedge!!"}, {"43fb8aeed8a833175c9295c1165415f98c866ef08a4922959d673507", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, {"ec18e66e93afc4fb1604bc2baedbfd20b44c43d76e65c0996d7851c6", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, {"86ed2eaa9c75ba98396e5c9fb2f679ecf0ea2ed1e0ee9ceecb4a9332", "How can you write a big system without C++? -Paul Glick"}, } func TestGolden(t *testing.T) { for i := 0; i < len(golden); i++ { g := golden[i] s := fmt.Sprintf("%x", Sum256([]byte(g.in))) if s != g.out { t.Fatalf("Sum256 function: sha256(%s) = %s want %s", g.in, s, g.out) } c := New() for j := 0; j < 3; j++ { if j < 2 { io.WriteString(c, g.in) } else { io.WriteString(c, g.in[0:len(g.in)/2]) c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("sha256[%d](%s) = %s want %s", j, g.in, s, g.out) } c.Reset() } } for i := 0; i < len(golden224); i++ { g := golden224[i] s := fmt.Sprintf("%x", Sum224([]byte(g.in))) if s != g.out { t.Fatalf("Sum224 function: sha224(%s) = %s want %s", g.in, s, g.out) } c := New224() for j := 0; j < 3; j++ { if j < 2 { io.WriteString(c, g.in) } else { io.WriteString(c, g.in[0:len(g.in)/2]) c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("sha224[%d](%s) = %s want %s", j, g.in, s, g.out) } c.Reset() } } } func TestSize(t *testing.T) { c := New() if got := c.Size(); got != Size { t.Errorf("Size = %d; want %d", got, Size) } c = New224() if got := c.Size(); got != Size224 { t.Errorf("New224.Size = %d; want %d", got, Size224) } } func TestBlockSize(t *testing.T) { c := New() if got := c.BlockSize(); got != BlockSize { t.Errorf("BlockSize = %d want %d", got, BlockSize) } } var bench = New() var buf = make([]byte, 8192) func benchmarkSize(b *testing.B, size int) { b.SetBytes(int64(size)) sum := make([]byte, bench.Size()) for i := 0; i < b.N; i++ { bench.Reset() bench.Write(buf[:size]) bench.Sum(sum[:0]) } } func BenchmarkHash8Bytes(b *testing.B) { benchmarkSize(b, 8) } func BenchmarkHash1K(b *testing.B) { benchmarkSize(b, 1024) } func BenchmarkHash8K(b *testing.B) { benchmarkSize(b, 8192) } ================================================ FILE: scan/crypto/sha256/sha256block.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !386 && !amd64 // +build !386,!amd64 // SHA256 block step. // In its own file so that a faster assembly or C version // can be substituted easily. package sha256 var _K = []uint32{ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, } func block(dig *digest, p []byte) { var w [64]uint32 h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] for len(p) >= chunk { // Can interlace the computation of w with the // rounds below if needed for speed. for i := 0; i < 16; i++ { j := i * 4 w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3]) } for i := 16; i < 64; i++ { v1 := w[i-2] t1 := (v1>>17 | v1<<(32-17)) ^ (v1>>19 | v1<<(32-19)) ^ (v1 >> 10) v2 := w[i-15] t2 := (v2>>7 | v2<<(32-7)) ^ (v2>>18 | v2<<(32-18)) ^ (v2 >> 3) w[i] = t1 + w[i-7] + t2 + w[i-16] } a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7 for i := 0; i < 64; i++ { t1 := h + ((e>>6 | e<<(32-6)) ^ (e>>11 | e<<(32-11)) ^ (e>>25 | e<<(32-25))) + ((e & f) ^ (^e & g)) + _K[i] + w[i] t2 := ((a>>2 | a<<(32-2)) ^ (a>>13 | a<<(32-13)) ^ (a>>22 | a<<(32-22))) + ((a & b) ^ (a & c) ^ (b & c)) h = g g = f f = e e = d + t1 d = c c = b b = a a = t1 + t2 } h0 += a h1 += b h2 += c h3 += d h4 += e h5 += f h6 += g h7 += h p = p[chunk:] } dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 } ================================================ FILE: scan/crypto/sha256/sha256block_386.s ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // SHA256 block routine. See sha256block.go for Go equivalent. // // The algorithm is detailed in FIPS 180-4: // // http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 // // a = H0 // b = H1 // c = H2 // d = H3 // e = H4 // f = H5 // g = H6 // h = H7 // // for t = 0 to 63 { // T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt // T2 = BIGSIGMA0(a) + Maj(a,b,c) // h = g // g = f // f = e // e = d + T1 // d = c // c = b // b = a // a = T1 + T2 // } // // H0 = a + H0 // H1 = b + H1 // H2 = c + H2 // H3 = d + H3 // H4 = e + H4 // H5 = f + H5 // H6 = g + H6 // H7 = h + H7 // Wt = Mt; for 0 <= t <= 15 #define MSGSCHEDULE0(index) \ MOVL (index*4)(SI), AX; \ BSWAPL AX; \ MOVL AX, (index*4)(BP) // Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 // SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x) // SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x) #define MSGSCHEDULE1(index) \ MOVL ((index-2)*4)(BP), AX; \ MOVL AX, CX; \ RORL $17, AX; \ MOVL CX, DX; \ RORL $19, CX; \ SHRL $10, DX; \ MOVL ((index-15)*4)(BP), BX; \ XORL CX, AX; \ MOVL BX, CX; \ XORL DX, AX; \ RORL $7, BX; \ MOVL CX, DX; \ SHRL $3, DX; \ RORL $18, CX; \ ADDL ((index-7)*4)(BP), AX; \ XORL CX, BX; \ XORL DX, BX; \ ADDL ((index-16)*4)(BP), BX; \ ADDL BX, AX; \ MOVL AX, ((index)*4)(BP) // Calculate T1 in AX - uses AX, BX, CX and DX registers. // Wt is passed in AX. // T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt // BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x) // Ch(x, y, z) = (x AND y) XOR (NOT x AND z) #define SHA256T1(const, e, f, g, h) \ MOVL (h*4)(DI), BX; \ ADDL AX, BX; \ MOVL (e*4)(DI), AX; \ ADDL $const, BX; \ MOVL (e*4)(DI), CX; \ RORL $6, AX; \ MOVL (e*4)(DI), DX; \ RORL $11, CX; \ XORL CX, AX; \ MOVL (e*4)(DI), CX; \ RORL $25, DX; \ ANDL (f*4)(DI), CX; \ XORL AX, DX; \ MOVL (e*4)(DI), AX; \ NOTL AX; \ ADDL DX, BX; \ ANDL (g*4)(DI), AX; \ XORL CX, AX; \ ADDL BX, AX // Calculate T2 in BX - uses AX, BX, CX and DX registers. // T2 = BIGSIGMA0(a) + Maj(a, b, c) // BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x) // Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z) #define SHA256T2(a, b, c) \ MOVL (a*4)(DI), AX; \ MOVL (c*4)(DI), BX; \ RORL $2, AX; \ MOVL (a*4)(DI), DX; \ ANDL (b*4)(DI), BX; \ RORL $13, DX; \ MOVL (a*4)(DI), CX; \ ANDL (c*4)(DI), CX; \ XORL DX, AX; \ XORL CX, BX; \ MOVL (a*4)(DI), DX; \ MOVL (b*4)(DI), CX; \ RORL $22, DX; \ ANDL (a*4)(DI), CX; \ XORL CX, BX; \ XORL DX, AX; \ ADDL AX, BX // Calculate T1 and T2, then e = d + T1 and a = T1 + T2. // The values for e and a are stored in d and h, ready for rotation. #define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \ SHA256T1(const, e, f, g, h); \ MOVL AX, 292(SP); \ SHA256T2(a, b, c); \ MOVL 292(SP), AX; \ ADDL AX, BX; \ ADDL AX, (d*4)(DI); \ MOVL BX, (h*4)(DI) #define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \ MSGSCHEDULE0(index); \ SHA256ROUND(index, const, a, b, c, d, e, f, g, h) #define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \ MSGSCHEDULE1(index); \ SHA256ROUND(index, const, a, b, c, d, e, f, g, h) TEXT ·block(SB),0,$296-12 MOVL p_base+4(FP), SI MOVL p_len+8(FP), DX SHRL $6, DX SHLL $6, DX LEAL (SI)(DX*1), DI MOVL DI, 288(SP) CMPL SI, DI JEQ end LEAL 256(SP), DI // variables MOVL dig+0(FP), BP MOVL (0*4)(BP), AX // a = H0 MOVL AX, (0*4)(DI) MOVL (1*4)(BP), BX // b = H1 MOVL BX, (1*4)(DI) MOVL (2*4)(BP), CX // c = H2 MOVL CX, (2*4)(DI) MOVL (3*4)(BP), DX // d = H3 MOVL DX, (3*4)(DI) MOVL (4*4)(BP), AX // e = H4 MOVL AX, (4*4)(DI) MOVL (5*4)(BP), BX // f = H5 MOVL BX, (5*4)(DI) MOVL (6*4)(BP), CX // g = H6 MOVL CX, (6*4)(DI) MOVL (7*4)(BP), DX // h = H7 MOVL DX, (7*4)(DI) loop: MOVL SP, BP // message schedule SHA256ROUND0(0, 0x428a2f98, 0, 1, 2, 3, 4, 5, 6, 7) SHA256ROUND0(1, 0x71374491, 7, 0, 1, 2, 3, 4, 5, 6) SHA256ROUND0(2, 0xb5c0fbcf, 6, 7, 0, 1, 2, 3, 4, 5) SHA256ROUND0(3, 0xe9b5dba5, 5, 6, 7, 0, 1, 2, 3, 4) SHA256ROUND0(4, 0x3956c25b, 4, 5, 6, 7, 0, 1, 2, 3) SHA256ROUND0(5, 0x59f111f1, 3, 4, 5, 6, 7, 0, 1, 2) SHA256ROUND0(6, 0x923f82a4, 2, 3, 4, 5, 6, 7, 0, 1) SHA256ROUND0(7, 0xab1c5ed5, 1, 2, 3, 4, 5, 6, 7, 0) SHA256ROUND0(8, 0xd807aa98, 0, 1, 2, 3, 4, 5, 6, 7) SHA256ROUND0(9, 0x12835b01, 7, 0, 1, 2, 3, 4, 5, 6) SHA256ROUND0(10, 0x243185be, 6, 7, 0, 1, 2, 3, 4, 5) SHA256ROUND0(11, 0x550c7dc3, 5, 6, 7, 0, 1, 2, 3, 4) SHA256ROUND0(12, 0x72be5d74, 4, 5, 6, 7, 0, 1, 2, 3) SHA256ROUND0(13, 0x80deb1fe, 3, 4, 5, 6, 7, 0, 1, 2) SHA256ROUND0(14, 0x9bdc06a7, 2, 3, 4, 5, 6, 7, 0, 1) SHA256ROUND0(15, 0xc19bf174, 1, 2, 3, 4, 5, 6, 7, 0) SHA256ROUND1(16, 0xe49b69c1, 0, 1, 2, 3, 4, 5, 6, 7) SHA256ROUND1(17, 0xefbe4786, 7, 0, 1, 2, 3, 4, 5, 6) SHA256ROUND1(18, 0x0fc19dc6, 6, 7, 0, 1, 2, 3, 4, 5) SHA256ROUND1(19, 0x240ca1cc, 5, 6, 7, 0, 1, 2, 3, 4) SHA256ROUND1(20, 0x2de92c6f, 4, 5, 6, 7, 0, 1, 2, 3) SHA256ROUND1(21, 0x4a7484aa, 3, 4, 5, 6, 7, 0, 1, 2) SHA256ROUND1(22, 0x5cb0a9dc, 2, 3, 4, 5, 6, 7, 0, 1) SHA256ROUND1(23, 0x76f988da, 1, 2, 3, 4, 5, 6, 7, 0) SHA256ROUND1(24, 0x983e5152, 0, 1, 2, 3, 4, 5, 6, 7) SHA256ROUND1(25, 0xa831c66d, 7, 0, 1, 2, 3, 4, 5, 6) SHA256ROUND1(26, 0xb00327c8, 6, 7, 0, 1, 2, 3, 4, 5) SHA256ROUND1(27, 0xbf597fc7, 5, 6, 7, 0, 1, 2, 3, 4) SHA256ROUND1(28, 0xc6e00bf3, 4, 5, 6, 7, 0, 1, 2, 3) SHA256ROUND1(29, 0xd5a79147, 3, 4, 5, 6, 7, 0, 1, 2) SHA256ROUND1(30, 0x06ca6351, 2, 3, 4, 5, 6, 7, 0, 1) SHA256ROUND1(31, 0x14292967, 1, 2, 3, 4, 5, 6, 7, 0) SHA256ROUND1(32, 0x27b70a85, 0, 1, 2, 3, 4, 5, 6, 7) SHA256ROUND1(33, 0x2e1b2138, 7, 0, 1, 2, 3, 4, 5, 6) SHA256ROUND1(34, 0x4d2c6dfc, 6, 7, 0, 1, 2, 3, 4, 5) SHA256ROUND1(35, 0x53380d13, 5, 6, 7, 0, 1, 2, 3, 4) SHA256ROUND1(36, 0x650a7354, 4, 5, 6, 7, 0, 1, 2, 3) SHA256ROUND1(37, 0x766a0abb, 3, 4, 5, 6, 7, 0, 1, 2) SHA256ROUND1(38, 0x81c2c92e, 2, 3, 4, 5, 6, 7, 0, 1) SHA256ROUND1(39, 0x92722c85, 1, 2, 3, 4, 5, 6, 7, 0) SHA256ROUND1(40, 0xa2bfe8a1, 0, 1, 2, 3, 4, 5, 6, 7) SHA256ROUND1(41, 0xa81a664b, 7, 0, 1, 2, 3, 4, 5, 6) SHA256ROUND1(42, 0xc24b8b70, 6, 7, 0, 1, 2, 3, 4, 5) SHA256ROUND1(43, 0xc76c51a3, 5, 6, 7, 0, 1, 2, 3, 4) SHA256ROUND1(44, 0xd192e819, 4, 5, 6, 7, 0, 1, 2, 3) SHA256ROUND1(45, 0xd6990624, 3, 4, 5, 6, 7, 0, 1, 2) SHA256ROUND1(46, 0xf40e3585, 2, 3, 4, 5, 6, 7, 0, 1) SHA256ROUND1(47, 0x106aa070, 1, 2, 3, 4, 5, 6, 7, 0) SHA256ROUND1(48, 0x19a4c116, 0, 1, 2, 3, 4, 5, 6, 7) SHA256ROUND1(49, 0x1e376c08, 7, 0, 1, 2, 3, 4, 5, 6) SHA256ROUND1(50, 0x2748774c, 6, 7, 0, 1, 2, 3, 4, 5) SHA256ROUND1(51, 0x34b0bcb5, 5, 6, 7, 0, 1, 2, 3, 4) SHA256ROUND1(52, 0x391c0cb3, 4, 5, 6, 7, 0, 1, 2, 3) SHA256ROUND1(53, 0x4ed8aa4a, 3, 4, 5, 6, 7, 0, 1, 2) SHA256ROUND1(54, 0x5b9cca4f, 2, 3, 4, 5, 6, 7, 0, 1) SHA256ROUND1(55, 0x682e6ff3, 1, 2, 3, 4, 5, 6, 7, 0) SHA256ROUND1(56, 0x748f82ee, 0, 1, 2, 3, 4, 5, 6, 7) SHA256ROUND1(57, 0x78a5636f, 7, 0, 1, 2, 3, 4, 5, 6) SHA256ROUND1(58, 0x84c87814, 6, 7, 0, 1, 2, 3, 4, 5) SHA256ROUND1(59, 0x8cc70208, 5, 6, 7, 0, 1, 2, 3, 4) SHA256ROUND1(60, 0x90befffa, 4, 5, 6, 7, 0, 1, 2, 3) SHA256ROUND1(61, 0xa4506ceb, 3, 4, 5, 6, 7, 0, 1, 2) SHA256ROUND1(62, 0xbef9a3f7, 2, 3, 4, 5, 6, 7, 0, 1) SHA256ROUND1(63, 0xc67178f2, 1, 2, 3, 4, 5, 6, 7, 0) MOVL dig+0(FP), BP MOVL (0*4)(BP), AX // H0 = a + H0 ADDL (0*4)(DI), AX MOVL AX, (0*4)(DI) MOVL AX, (0*4)(BP) MOVL (1*4)(BP), BX // H1 = b + H1 ADDL (1*4)(DI), BX MOVL BX, (1*4)(DI) MOVL BX, (1*4)(BP) MOVL (2*4)(BP), CX // H2 = c + H2 ADDL (2*4)(DI), CX MOVL CX, (2*4)(DI) MOVL CX, (2*4)(BP) MOVL (3*4)(BP), DX // H3 = d + H3 ADDL (3*4)(DI), DX MOVL DX, (3*4)(DI) MOVL DX, (3*4)(BP) MOVL (4*4)(BP), AX // H4 = e + H4 ADDL (4*4)(DI), AX MOVL AX, (4*4)(DI) MOVL AX, (4*4)(BP) MOVL (5*4)(BP), BX // H5 = f + H5 ADDL (5*4)(DI), BX MOVL BX, (5*4)(DI) MOVL BX, (5*4)(BP) MOVL (6*4)(BP), CX // H6 = g + H6 ADDL (6*4)(DI), CX MOVL CX, (6*4)(DI) MOVL CX, (6*4)(BP) MOVL (7*4)(BP), DX // H7 = h + H7 ADDL (7*4)(DI), DX MOVL DX, (7*4)(DI) MOVL DX, (7*4)(BP) ADDL $64, SI CMPL SI, 288(SP) JB loop end: RET ================================================ FILE: scan/crypto/sha256/sha256block_amd64.s ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include "textflag.h" // SHA256 block routine. See sha256block.go for Go equivalent. // // The algorithm is detailed in FIPS 180-4: // // http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 // // a = H0 // b = H1 // c = H2 // d = H3 // e = H4 // f = H5 // g = H6 // h = H7 // // for t = 0 to 63 { // T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt // T2 = BIGSIGMA0(a) + Maj(a,b,c) // h = g // g = f // f = e // e = d + T1 // d = c // c = b // b = a // a = T1 + T2 // } // // H0 = a + H0 // H1 = b + H1 // H2 = c + H2 // H3 = d + H3 // H4 = e + H4 // H5 = f + H5 // H6 = g + H6 // H7 = h + H7 // Wt = Mt; for 0 <= t <= 15 #define MSGSCHEDULE0(index) \ MOVL (index*4)(SI), AX; \ BSWAPL AX; \ MOVL AX, (index*4)(BP) // Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 // SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x) // SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x) #define MSGSCHEDULE1(index) \ MOVL ((index-2)*4)(BP), AX; \ MOVL AX, CX; \ RORL $17, AX; \ MOVL CX, DX; \ RORL $19, CX; \ SHRL $10, DX; \ MOVL ((index-15)*4)(BP), BX; \ XORL CX, AX; \ MOVL BX, CX; \ XORL DX, AX; \ RORL $7, BX; \ MOVL CX, DX; \ SHRL $3, DX; \ RORL $18, CX; \ ADDL ((index-7)*4)(BP), AX; \ XORL CX, BX; \ XORL DX, BX; \ ADDL ((index-16)*4)(BP), BX; \ ADDL BX, AX; \ MOVL AX, ((index)*4)(BP) // Calculate T1 in AX - uses AX, CX and DX registers. // h is also used as an accumulator. Wt is passed in AX. // T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt // BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x) // Ch(x, y, z) = (x AND y) XOR (NOT x AND z) #define SHA256T1(const, e, f, g, h) \ ADDL AX, h; \ MOVL e, AX; \ ADDL $const, h; \ MOVL e, CX; \ RORL $6, AX; \ MOVL e, DX; \ RORL $11, CX; \ XORL CX, AX; \ MOVL e, CX; \ RORL $25, DX; \ ANDL f, CX; \ XORL AX, DX; \ MOVL e, AX; \ NOTL AX; \ ADDL DX, h; \ ANDL g, AX; \ XORL CX, AX; \ ADDL h, AX // Calculate T2 in BX - uses BX, CX, DX and DI registers. // T2 = BIGSIGMA0(a) + Maj(a, b, c) // BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x) // Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z) #define SHA256T2(a, b, c) \ MOVL a, DI; \ MOVL c, BX; \ RORL $2, DI; \ MOVL a, DX; \ ANDL b, BX; \ RORL $13, DX; \ MOVL a, CX; \ ANDL c, CX; \ XORL DX, DI; \ XORL CX, BX; \ MOVL a, DX; \ MOVL b, CX; \ RORL $22, DX; \ ANDL a, CX; \ XORL CX, BX; \ XORL DX, DI; \ ADDL DI, BX // Calculate T1 and T2, then e = d + T1 and a = T1 + T2. // The values for e and a are stored in d and h, ready for rotation. #define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \ SHA256T1(const, e, f, g, h); \ SHA256T2(a, b, c); \ MOVL BX, h; \ ADDL AX, d; \ ADDL AX, h #define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \ MSGSCHEDULE0(index); \ SHA256ROUND(index, const, a, b, c, d, e, f, g, h) #define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \ MSGSCHEDULE1(index); \ SHA256ROUND(index, const, a, b, c, d, e, f, g, h) TEXT ·block(SB),0,$264-32 MOVQ p_base+8(FP), SI MOVQ p_len+16(FP), DX SHRQ $6, DX SHLQ $6, DX LEAQ (SI)(DX*1), DI MOVQ DI, 256(SP) CMPQ SI, DI JEQ end MOVQ dig+0(FP), BP MOVL (0*4)(BP), R8 // a = H0 MOVL (1*4)(BP), R9 // b = H1 MOVL (2*4)(BP), R10 // c = H2 MOVL (3*4)(BP), R11 // d = H3 MOVL (4*4)(BP), R12 // e = H4 MOVL (5*4)(BP), R13 // f = H5 MOVL (6*4)(BP), R14 // g = H6 MOVL (7*4)(BP), R15 // h = H7 loop: MOVQ SP, BP // message schedule SHA256ROUND0(0, 0x428a2f98, R8, R9, R10, R11, R12, R13, R14, R15) SHA256ROUND0(1, 0x71374491, R15, R8, R9, R10, R11, R12, R13, R14) SHA256ROUND0(2, 0xb5c0fbcf, R14, R15, R8, R9, R10, R11, R12, R13) SHA256ROUND0(3, 0xe9b5dba5, R13, R14, R15, R8, R9, R10, R11, R12) SHA256ROUND0(4, 0x3956c25b, R12, R13, R14, R15, R8, R9, R10, R11) SHA256ROUND0(5, 0x59f111f1, R11, R12, R13, R14, R15, R8, R9, R10) SHA256ROUND0(6, 0x923f82a4, R10, R11, R12, R13, R14, R15, R8, R9) SHA256ROUND0(7, 0xab1c5ed5, R9, R10, R11, R12, R13, R14, R15, R8) SHA256ROUND0(8, 0xd807aa98, R8, R9, R10, R11, R12, R13, R14, R15) SHA256ROUND0(9, 0x12835b01, R15, R8, R9, R10, R11, R12, R13, R14) SHA256ROUND0(10, 0x243185be, R14, R15, R8, R9, R10, R11, R12, R13) SHA256ROUND0(11, 0x550c7dc3, R13, R14, R15, R8, R9, R10, R11, R12) SHA256ROUND0(12, 0x72be5d74, R12, R13, R14, R15, R8, R9, R10, R11) SHA256ROUND0(13, 0x80deb1fe, R11, R12, R13, R14, R15, R8, R9, R10) SHA256ROUND0(14, 0x9bdc06a7, R10, R11, R12, R13, R14, R15, R8, R9) SHA256ROUND0(15, 0xc19bf174, R9, R10, R11, R12, R13, R14, R15, R8) SHA256ROUND1(16, 0xe49b69c1, R8, R9, R10, R11, R12, R13, R14, R15) SHA256ROUND1(17, 0xefbe4786, R15, R8, R9, R10, R11, R12, R13, R14) SHA256ROUND1(18, 0x0fc19dc6, R14, R15, R8, R9, R10, R11, R12, R13) SHA256ROUND1(19, 0x240ca1cc, R13, R14, R15, R8, R9, R10, R11, R12) SHA256ROUND1(20, 0x2de92c6f, R12, R13, R14, R15, R8, R9, R10, R11) SHA256ROUND1(21, 0x4a7484aa, R11, R12, R13, R14, R15, R8, R9, R10) SHA256ROUND1(22, 0x5cb0a9dc, R10, R11, R12, R13, R14, R15, R8, R9) SHA256ROUND1(23, 0x76f988da, R9, R10, R11, R12, R13, R14, R15, R8) SHA256ROUND1(24, 0x983e5152, R8, R9, R10, R11, R12, R13, R14, R15) SHA256ROUND1(25, 0xa831c66d, R15, R8, R9, R10, R11, R12, R13, R14) SHA256ROUND1(26, 0xb00327c8, R14, R15, R8, R9, R10, R11, R12, R13) SHA256ROUND1(27, 0xbf597fc7, R13, R14, R15, R8, R9, R10, R11, R12) SHA256ROUND1(28, 0xc6e00bf3, R12, R13, R14, R15, R8, R9, R10, R11) SHA256ROUND1(29, 0xd5a79147, R11, R12, R13, R14, R15, R8, R9, R10) SHA256ROUND1(30, 0x06ca6351, R10, R11, R12, R13, R14, R15, R8, R9) SHA256ROUND1(31, 0x14292967, R9, R10, R11, R12, R13, R14, R15, R8) SHA256ROUND1(32, 0x27b70a85, R8, R9, R10, R11, R12, R13, R14, R15) SHA256ROUND1(33, 0x2e1b2138, R15, R8, R9, R10, R11, R12, R13, R14) SHA256ROUND1(34, 0x4d2c6dfc, R14, R15, R8, R9, R10, R11, R12, R13) SHA256ROUND1(35, 0x53380d13, R13, R14, R15, R8, R9, R10, R11, R12) SHA256ROUND1(36, 0x650a7354, R12, R13, R14, R15, R8, R9, R10, R11) SHA256ROUND1(37, 0x766a0abb, R11, R12, R13, R14, R15, R8, R9, R10) SHA256ROUND1(38, 0x81c2c92e, R10, R11, R12, R13, R14, R15, R8, R9) SHA256ROUND1(39, 0x92722c85, R9, R10, R11, R12, R13, R14, R15, R8) SHA256ROUND1(40, 0xa2bfe8a1, R8, R9, R10, R11, R12, R13, R14, R15) SHA256ROUND1(41, 0xa81a664b, R15, R8, R9, R10, R11, R12, R13, R14) SHA256ROUND1(42, 0xc24b8b70, R14, R15, R8, R9, R10, R11, R12, R13) SHA256ROUND1(43, 0xc76c51a3, R13, R14, R15, R8, R9, R10, R11, R12) SHA256ROUND1(44, 0xd192e819, R12, R13, R14, R15, R8, R9, R10, R11) SHA256ROUND1(45, 0xd6990624, R11, R12, R13, R14, R15, R8, R9, R10) SHA256ROUND1(46, 0xf40e3585, R10, R11, R12, R13, R14, R15, R8, R9) SHA256ROUND1(47, 0x106aa070, R9, R10, R11, R12, R13, R14, R15, R8) SHA256ROUND1(48, 0x19a4c116, R8, R9, R10, R11, R12, R13, R14, R15) SHA256ROUND1(49, 0x1e376c08, R15, R8, R9, R10, R11, R12, R13, R14) SHA256ROUND1(50, 0x2748774c, R14, R15, R8, R9, R10, R11, R12, R13) SHA256ROUND1(51, 0x34b0bcb5, R13, R14, R15, R8, R9, R10, R11, R12) SHA256ROUND1(52, 0x391c0cb3, R12, R13, R14, R15, R8, R9, R10, R11) SHA256ROUND1(53, 0x4ed8aa4a, R11, R12, R13, R14, R15, R8, R9, R10) SHA256ROUND1(54, 0x5b9cca4f, R10, R11, R12, R13, R14, R15, R8, R9) SHA256ROUND1(55, 0x682e6ff3, R9, R10, R11, R12, R13, R14, R15, R8) SHA256ROUND1(56, 0x748f82ee, R8, R9, R10, R11, R12, R13, R14, R15) SHA256ROUND1(57, 0x78a5636f, R15, R8, R9, R10, R11, R12, R13, R14) SHA256ROUND1(58, 0x84c87814, R14, R15, R8, R9, R10, R11, R12, R13) SHA256ROUND1(59, 0x8cc70208, R13, R14, R15, R8, R9, R10, R11, R12) SHA256ROUND1(60, 0x90befffa, R12, R13, R14, R15, R8, R9, R10, R11) SHA256ROUND1(61, 0xa4506ceb, R11, R12, R13, R14, R15, R8, R9, R10) SHA256ROUND1(62, 0xbef9a3f7, R10, R11, R12, R13, R14, R15, R8, R9) SHA256ROUND1(63, 0xc67178f2, R9, R10, R11, R12, R13, R14, R15, R8) MOVQ dig+0(FP), BP ADDL (0*4)(BP), R8 // H0 = a + H0 MOVL R8, (0*4)(BP) ADDL (1*4)(BP), R9 // H1 = b + H1 MOVL R9, (1*4)(BP) ADDL (2*4)(BP), R10 // H2 = c + H2 MOVL R10, (2*4)(BP) ADDL (3*4)(BP), R11 // H3 = d + H3 MOVL R11, (3*4)(BP) ADDL (4*4)(BP), R12 // H4 = e + H4 MOVL R12, (4*4)(BP) ADDL (5*4)(BP), R13 // H5 = f + H5 MOVL R13, (5*4)(BP) ADDL (6*4)(BP), R14 // H6 = g + H6 MOVL R14, (6*4)(BP) ADDL (7*4)(BP), R15 // H7 = h + H7 MOVL R15, (7*4)(BP) ADDQ $64, SI CMPQ SI, 256(SP) JB loop end: RET ================================================ FILE: scan/crypto/sha256/sha256block_decl.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build 386 || amd64 // +build 386 amd64 package sha256 //go:noescape func block(dig *digest, p []byte) ================================================ FILE: scan/crypto/sha512/sha512.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package sha512 implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256 // hash algorithms as defined in FIPS 180-4. package sha512 import ( "crypto" "hash" ) func init() { crypto.RegisterHash(crypto.SHA384, New384) crypto.RegisterHash(crypto.SHA512, New) crypto.RegisterHash(crypto.SHA512_224, New512_224) crypto.RegisterHash(crypto.SHA512_256, New512_256) } const ( // Size is the size, in bytes, of a SHA-512 checksum. Size = 64 // Size224 is the size, in bytes, of a SHA-512/224 checksum. Size224 = 28 // Size256 is the size, in bytes, of a SHA-512/256 checksum. Size256 = 32 // Size384 is the size, in bytes, of a SHA-384 checksum. Size384 = 48 // BlockSize is the block size, in bytes, of the SHA-512/224, // SHA-512/256, SHA-384 and SHA-512 hash functions. BlockSize = 128 ) const ( chunk = 128 init0 = 0x6a09e667f3bcc908 init1 = 0xbb67ae8584caa73b init2 = 0x3c6ef372fe94f82b init3 = 0xa54ff53a5f1d36f1 init4 = 0x510e527fade682d1 init5 = 0x9b05688c2b3e6c1f init6 = 0x1f83d9abfb41bd6b init7 = 0x5be0cd19137e2179 init0_224 = 0x8c3d37c819544da2 init1_224 = 0x73e1996689dcd4d6 init2_224 = 0x1dfab7ae32ff9c82 init3_224 = 0x679dd514582f9fcf init4_224 = 0x0f6d2b697bd44da8 init5_224 = 0x77e36f7304c48942 init6_224 = 0x3f9d85a86a1d36c8 init7_224 = 0x1112e6ad91d692a1 init0_256 = 0x22312194fc2bf72c init1_256 = 0x9f555fa3c84c64c2 init2_256 = 0x2393b86b6f53b151 init3_256 = 0x963877195940eabd init4_256 = 0x96283ee2a88effe3 init5_256 = 0xbe5e1e2553863992 init6_256 = 0x2b0199fc2c85b8aa init7_256 = 0x0eb72ddc81c52ca2 init0_384 = 0xcbbb9d5dc1059ed8 init1_384 = 0x629a292a367cd507 init2_384 = 0x9159015a3070dd17 init3_384 = 0x152fecd8f70e5939 init4_384 = 0x67332667ffc00b31 init5_384 = 0x8eb44a8768581511 init6_384 = 0xdb0c2e0d64f98fa7 init7_384 = 0x47b5481dbefa4fa4 ) // digest represents the partial evaluation of a checksum. type digest struct { h [8]uint64 x [chunk]byte nx int len uint64 function crypto.Hash } func (d *digest) Reset() { switch d.function { case crypto.SHA384: d.h[0] = init0_384 d.h[1] = init1_384 d.h[2] = init2_384 d.h[3] = init3_384 d.h[4] = init4_384 d.h[5] = init5_384 d.h[6] = init6_384 d.h[7] = init7_384 case crypto.SHA512_224: d.h[0] = init0_224 d.h[1] = init1_224 d.h[2] = init2_224 d.h[3] = init3_224 d.h[4] = init4_224 d.h[5] = init5_224 d.h[6] = init6_224 d.h[7] = init7_224 case crypto.SHA512_256: d.h[0] = init0_256 d.h[1] = init1_256 d.h[2] = init2_256 d.h[3] = init3_256 d.h[4] = init4_256 d.h[5] = init5_256 d.h[6] = init6_256 d.h[7] = init7_256 default: d.h[0] = init0 d.h[1] = init1 d.h[2] = init2 d.h[3] = init3 d.h[4] = init4 d.h[5] = init5 d.h[6] = init6 d.h[7] = init7 } d.nx = 0 d.len = 0 } // New returns a new hash.Hash computing the SHA-512 checksum. func New() hash.Hash { d := &digest{function: crypto.SHA512} d.Reset() return d } // New512_224 returns a new hash.Hash computing the SHA-512/224 checksum. func New512_224() hash.Hash { d := &digest{function: crypto.SHA512_224} d.Reset() return d } // New512_256 returns a new hash.Hash computing the SHA-512/256 checksum. func New512_256() hash.Hash { d := &digest{function: crypto.SHA512_256} d.Reset() return d } // New384 returns a new hash.Hash computing the SHA-384 checksum. func New384() hash.Hash { d := &digest{function: crypto.SHA384} d.Reset() return d } func (d *digest) Size() int { switch d.function { case crypto.SHA512_224: return Size224 case crypto.SHA512_256: return Size256 case crypto.SHA384: return Size384 default: return Size } } func (d *digest) BlockSize() int { return BlockSize } func (d *digest) Write(p []byte) (nn int, err error) { nn = len(p) d.len += uint64(nn) if d.nx > 0 { n := copy(d.x[d.nx:], p) d.nx += n if d.nx == chunk { block(d, d.x[:]) d.nx = 0 } p = p[n:] } if len(p) >= chunk { n := len(p) &^ (chunk - 1) block(d, p[:n]) p = p[n:] } if len(p) > 0 { d.nx = copy(d.x[:], p) } return } func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0 so that caller can keep writing and summing. d := new(digest) *d = *d0 hash := d.checkSum() switch d.function { case crypto.SHA384: return append(in, hash[:Size384]...) case crypto.SHA512_224: return append(in, hash[:Size224]...) case crypto.SHA512_256: return append(in, hash[:Size256]...) default: return append(in, hash[:]...) } } func (d *digest) checkSum() [Size]byte { // Padding. Add a 1 bit and 0 bits until 112 bytes mod 128. len := d.len var tmp [128]byte tmp[0] = 0x80 if len%128 < 112 { d.Write(tmp[0 : 112-len%128]) } else { d.Write(tmp[0 : 128+112-len%128]) } // Length in bits. len <<= 3 for i := uint(0); i < 16; i++ { tmp[i] = byte(len >> (120 - 8*i)) } d.Write(tmp[0:16]) if d.nx != 0 { panic("d.nx != 0") } h := d.h[:] if d.function == crypto.SHA384 { h = d.h[:6] } var digest [Size]byte for i, s := range h { digest[i*8] = byte(s >> 56) digest[i*8+1] = byte(s >> 48) digest[i*8+2] = byte(s >> 40) digest[i*8+3] = byte(s >> 32) digest[i*8+4] = byte(s >> 24) digest[i*8+5] = byte(s >> 16) digest[i*8+6] = byte(s >> 8) digest[i*8+7] = byte(s) } return digest } // Sum512 returns the SHA512 checksum of the data. func Sum512(data []byte) [Size]byte { d := digest{function: crypto.SHA512} d.Reset() d.Write(data) return d.checkSum() } // Sum384 returns the SHA384 checksum of the data. func Sum384(data []byte) (sum384 [Size384]byte) { d := digest{function: crypto.SHA384} d.Reset() d.Write(data) sum := d.checkSum() copy(sum384[:], sum[:Size384]) return } // Sum512_224 returns the Sum512/224 checksum of the data. func Sum512_224(data []byte) (sum224 [Size224]byte) { d := digest{function: crypto.SHA512_224} d.Reset() d.Write(data) sum := d.checkSum() copy(sum224[:], sum[:Size224]) return } // Sum512_256 returns the Sum512/256 checksum of the data. func Sum512_256(data []byte) (sum256 [Size256]byte) { d := digest{function: crypto.SHA512_256} d.Reset() d.Write(data) sum := d.checkSum() copy(sum256[:], sum[:Size256]) return } ================================================ FILE: scan/crypto/sha512/sha512_test.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // SHA512 hash algorithm. See FIPS 180-4. package sha512 import ( "encoding/hex" "hash" "io" "testing" ) type sha512Test struct { in string out224 string out256 string out384 string out512 string } var golden = []sha512Test{ { "", "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4", "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a", "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", }, { "a", "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327", "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8", "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", }, { "ab", "b35878d07bfedf39fc638af08547eb5d1072d8546319f247b442fbf5", "22d4d37ec6370571af7109fb12eae79673d5f7c83e6e677083faa3cfac3b2c14", "c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", "2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", }, { "abc", "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa", "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23", "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", }, { "abcd", "0c9f157ab030fb06e957c14e3938dc5908962e5dd7b66f04a36fc534", "d2891c7978be0e24948f37caa415b87cb5cbe2b26b7bad9dc6391b8a6f6ddcc9", "1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", "d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", }, { "abcde", "880e79bb0a1d2c9b7528d851edb6b8342c58c831de98123b432a4515", "de8322b46e78b67d4431997070703e9764e03a1237b896fd8b379ed4576e8363", "4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", "878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", }, { "abcdef", "236c829cfea4fd6d4de61ad15fcf34dca62342adaf9f2001c16f29b8", "e4fdcb11d1ac14e698743acd8805174cea5ddc0d312e3e47f6372032571bad84", "c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", "e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", }, { "abcdefg", "4767af672b3ed107f25018dc22d6fa4b07d156e13b720971e2c4f6bf", "a8117f680bdceb5d1443617cbdae9255f6900075422326a972fdd2f65ba9bee3", "9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", "d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", }, { "abcdefgh", "792e25e0ae286d123a38950007e037d3122e76c4ee201668c385edab", "a29b9645d2a02a8b582888d044199787220e316bf2e89d1422d3df26bf545bbe", "9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", "a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", }, { "abcdefghi", "56b275d36127dc070cda4019baf2ce2579a25d8c67fa2bc9be61b539", "b955095330f9c8188d11884ec1679dc44c9c5b25ff9bda700416df9cdd39188f", "ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", "f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", }, { "abcdefghij", "f809423cbb25e81a2a64aecee2cd5fdc7d91d5db583901fbf1db3116", "550762913d51eefbcd1a55068fcfc9b154fd11c1078b996df0d926ea59d2a68d", "a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", "ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", }, { "Discard medicine more than two years old.", "4c46e10b5b72204e509c3c06072cea970bc020cd45a61a0acdfa97ac", "690c8ad3916cefd3ad29226d9875965e3ee9ec0d4482eacc248f2ff4aa0d8e5b", "86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", "2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", }, { "He who has a shady past knows that nice guys finish last.", "cb0cef13c1848d91a6d02637c7c520de1914ad4a7aea824671cc328e", "25938ca49f7ef1178ce81620842b65e576245fcaed86026a36b516b80bb86b3b", "ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", "a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", }, { "I wouldn't marry him with a ten foot pole.", "6c7bd0f3a6544ea698006c2ea583a85f80ea2913590a186db8bb2f1b", "698e420c3a7038e53d8e73f4be2b02e03b93464ac1a61ebe69f557079921ef65", "40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", "8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", }, { "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "981323be3eca6ccfa598e58dd74ed8cb05d5f7f6653b7604b684f904", "839b414d7e3900ee243aa3d1f9b6955720e64041f5ab9bedd3eb0a08da5a2ca8", "e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", "26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", }, { "The days of the digital watch are numbered. -Tom Stoppard", "e6fbf82df5138bf361e826903cadf0612cb2986649ba47a57e1bca99", "5625ecb9d284e54c00b257b67a8cacb25a78db2845c60ef2d29e43c84f236e8e", "c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", "e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", }, { "Nepal premier won't resign.", "6ec2cb2ecafc1a9bddaf4caf57344d853e6ded398927d5694fd7714f", "9b81d06bca2f985e6ad3249096ff3c0f2a9ec5bb16ef530d738d19d81e7806f2", "a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", "420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", }, { "For every action there is an equal and opposite government program.", "7f62f36e716e0badaf4a4658da9d09bea26357a1bc6aeb8cf7c3ae35", "08241df8d91edfcd68bb1a1dada6e0ae1475a5c6e7b8f12d8e24ca43a38240a9", "5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", "d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", }, { "His money is twice tainted: 'taint yours and 'taint mine.", "45adffcb86a05ee4d91263a6115dda011b805d442c60836963cb8378", "4ff74d9213a8117745f5d37b5353a774ec81c5dfe65c4c8986a56fc01f2c551e", "ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", "9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", }, { "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "51cb518f1f68daa901a3075a0a5e1acc755b4e5c82cb47687537f880", "b5baf747c307f98849ec881cf0d48605ae4edd386372aea9b26e71db517e650b", "722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", "d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", }, { "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "3b59c5e64b0da7bfc18d7017bf458d90f2c83601ff1afc6263ac0993", "7eef0538ebd7ecf18611d23b0e1cd26a74d65b929a2e374197dc66e755ca4944", "dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", "b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", }, { "size: a.out: bad magic", "6a9525c0fac0f91b489bc4f0f539b9ec4a156a4e98bc15b655c2c881", "d05600964f83f55323104aadab434f32391c029718a7690d08ddb2d7e8708443", "1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", "3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", }, { "The major problem is with sendmail. -Mark Horton", "a1b2b2905b1527d682049c6a76e35c7d8c72551abfe7833ac1be595f", "53ed5f9b5c0b674ac0f3425d9f9a5d462655b07cc90f5d0f692eec093884a607", "5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", "b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", }, { "Give me a rock, paper and scissors and I will move the world. CCFestoon", "76cf045c76a5f2e3d64d56c3cdba6a25479334611bc375460526f8c1", "5a0147685a44eea2435dbd582724efca7637acd9c428e5e1a05115bc3bc2a0e0", "5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", "d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", }, { "If the enemy is within range, then so are you.", "4473671daeecfdb6f6c5bc06b26374aa5e497cc37119fe14144c430c", "1152c9b27a99dbf4057d21438f4e63dd0cd0977d5ff12317c64d3b97fcac875a", "1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", "19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", }, { "It's well we cannot hear the screams/That we create in others' dreams.", "6accb6394758523fcd453d47d37ebd10868957a0a9e81c796736abf8", "105e890f5d5cf1748d9a7b4cdaf58b69855779deebc2097747c2210a17b2cb51", "76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", "00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", }, { "You remind me of a TV show, but that's all right: I watch it anyway.", "6f173f4b6eac7f2a73eaa0833c4563752df2c869dc00b7d30219e12e", "74644ead770da1434365cd912656fe1aca2056d3039d39f10eb1151bddb32cf3", "12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", "91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", }, { "C is as portable as Stonehedge!!", "db05bf4d0f73325208755f4af96cfac6cb3db5dbfc323d675d68f938", "50a234625de5587581883dad9ef399460928032a5ea6bd005d7dc7b68d8cc3d6", "0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", "fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", }, { "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "05ffa71bb02e855de1aaee1777b3bdbaf7507646f19c4c6aa29933d0", "a7a3846005f8a9935a0a2d43e7fd56d95132a9a3609bf3296ef80b8218acffa0", "bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", "2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", }, { "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "3ad3c89e15b91e6273534c5d18adadbb528e7b840b288f64e81b8c6d", "688ff03e367680757aa9906cb1e2ad218c51f4526dc0426ea229a5ba9d002c69", "b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", "7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", }, { "How can you write a big system without C++? -Paul Glick", "e3763669d1b760c1be7bfcb6625f92300a8430419d1dbad57ec9f53c", "3fa46d52094b01021cff5af9a438982b887a5793f624c0a6644149b6b7c3f485", "1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", "833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", }, } func testHash(t *testing.T, name, in, outHex string, oneShotResult []byte, digestFunc hash.Hash) { if calculated := hex.EncodeToString(oneShotResult); calculated != outHex { t.Errorf("one-shot result for %s(%q) = %q, but expected %q", name, in, calculated, outHex) return } for pass := 0; pass < 3; pass++ { if pass < 2 { io.WriteString(digestFunc, in) } else { io.WriteString(digestFunc, in[:len(in)/2]) digestFunc.Sum(nil) io.WriteString(digestFunc, in[len(in)/2:]) } if calculated := hex.EncodeToString(digestFunc.Sum(nil)); calculated != outHex { t.Errorf("%s(%q) = %q (in pass #%d), but expected %q", name, in, calculated, pass, outHex) } digestFunc.Reset() } } func TestGolden(t *testing.T) { for _, test := range golden { in := []byte(test.in) sum224 := Sum512_224(in) sum256 := Sum512_256(in) sum384 := Sum384(in) sum512 := Sum512(in) testHash(t, "SHA512/224", test.in, test.out224, sum224[:], New512_224()) testHash(t, "SHA512/256", test.in, test.out256, sum256[:], New512_256()) testHash(t, "SHA384", test.in, test.out384, sum384[:], New384()) testHash(t, "SHA512", test.in, test.out512, sum512[:], New()) } } func TestSize(t *testing.T) { c := New() if got := c.Size(); got != Size { t.Errorf("Size = %d; want %d", got, Size) } c = New384() if got := c.Size(); got != Size384 { t.Errorf("New384.Size = %d; want %d", got, Size384) } c = New512_224() if got := c.Size(); got != Size224 { t.Errorf("New512224.Size = %d; want %d", got, Size224) } c = New512_256() if got := c.Size(); got != Size256 { t.Errorf("New512256.Size = %d; want %d", got, Size256) } } func TestBlockSize(t *testing.T) { c := New() if got := c.BlockSize(); got != BlockSize { t.Errorf("BlockSize = %d; want %d", got, BlockSize) } } var bench = New() var buf = make([]byte, 8192) func benchmarkSize(b *testing.B, size int) { b.SetBytes(int64(size)) sum := make([]byte, bench.Size()) for i := 0; i < b.N; i++ { bench.Reset() bench.Write(buf[:size]) bench.Sum(sum[:0]) } } func BenchmarkHash8Bytes(b *testing.B) { benchmarkSize(b, 8) } func BenchmarkHash1K(b *testing.B) { benchmarkSize(b, 1024) } func BenchmarkHash8K(b *testing.B) { benchmarkSize(b, 8192) } ================================================ FILE: scan/crypto/sha512/sha512block.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !amd64 // +build !amd64 // SHA512 block step. // In its own file so that a faster assembly or C version // can be substituted easily. package sha512 var _K = []uint64{ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, } func block(dig *digest, p []byte) { var w [80]uint64 h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] for len(p) >= chunk { for i := 0; i < 16; i++ { j := i * 8 w[i] = uint64(p[j])<<56 | uint64(p[j+1])<<48 | uint64(p[j+2])<<40 | uint64(p[j+3])<<32 | uint64(p[j+4])<<24 | uint64(p[j+5])<<16 | uint64(p[j+6])<<8 | uint64(p[j+7]) } for i := 16; i < 80; i++ { v1 := w[i-2] t1 := (v1>>19 | v1<<(64-19)) ^ (v1>>61 | v1<<(64-61)) ^ (v1 >> 6) v2 := w[i-15] t2 := (v2>>1 | v2<<(64-1)) ^ (v2>>8 | v2<<(64-8)) ^ (v2 >> 7) w[i] = t1 + w[i-7] + t2 + w[i-16] } a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7 for i := 0; i < 80; i++ { t1 := h + ((e>>14 | e<<(64-14)) ^ (e>>18 | e<<(64-18)) ^ (e>>41 | e<<(64-41))) + ((e & f) ^ (^e & g)) + _K[i] + w[i] t2 := ((a>>28 | a<<(64-28)) ^ (a>>34 | a<<(64-34)) ^ (a>>39 | a<<(64-39))) + ((a & b) ^ (a & c) ^ (b & c)) h = g g = f f = e e = d + t1 d = c c = b b = a a = t1 + t2 } h0 += a h1 += b h2 += c h3 += d h4 += e h5 += f h6 += g h7 += h p = p[chunk:] } dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 } ================================================ FILE: scan/crypto/sha512/sha512block_amd64.s ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include "textflag.h" // SHA512 block routine. See sha512block.go for Go equivalent. // // The algorithm is detailed in FIPS 180-4: // // http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79 // // a = H0 // b = H1 // c = H2 // d = H3 // e = H4 // f = H5 // g = H6 // h = H7 // // for t = 0 to 79 { // T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt // T2 = BIGSIGMA0(a) + Maj(a,b,c) // h = g // g = f // f = e // e = d + T1 // d = c // c = b // b = a // a = T1 + T2 // } // // H0 = a + H0 // H1 = b + H1 // H2 = c + H2 // H3 = d + H3 // H4 = e + H4 // H5 = f + H5 // H6 = g + H6 // H7 = h + H7 // Wt = Mt; for 0 <= t <= 15 #define MSGSCHEDULE0(index) \ MOVQ (index*8)(SI), AX; \ BSWAPQ AX; \ MOVQ AX, (index*8)(BP) // Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79 // SIGMA0(x) = ROTR(1,x) XOR ROTR(8,x) XOR SHR(7,x) // SIGMA1(x) = ROTR(19,x) XOR ROTR(61,x) XOR SHR(6,x) #define MSGSCHEDULE1(index) \ MOVQ ((index-2)*8)(BP), AX; \ MOVQ AX, CX; \ RORQ $19, AX; \ MOVQ CX, DX; \ RORQ $61, CX; \ SHRQ $6, DX; \ MOVQ ((index-15)*8)(BP), BX; \ XORQ CX, AX; \ MOVQ BX, CX; \ XORQ DX, AX; \ RORQ $1, BX; \ MOVQ CX, DX; \ SHRQ $7, DX; \ RORQ $8, CX; \ ADDQ ((index-7)*8)(BP), AX; \ XORQ CX, BX; \ XORQ DX, BX; \ ADDQ ((index-16)*8)(BP), BX; \ ADDQ BX, AX; \ MOVQ AX, ((index)*8)(BP) // Calculate T1 in AX - uses AX, CX and DX registers. // h is also used as an accumulator. Wt is passed in AX. // T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt // BIGSIGMA1(x) = ROTR(14,x) XOR ROTR(18,x) XOR ROTR(41,x) // Ch(x, y, z) = (x AND y) XOR (NOT x AND z) #define SHA512T1(const, e, f, g, h) \ MOVQ $const, DX; \ ADDQ AX, h; \ MOVQ e, AX; \ ADDQ DX, h; \ MOVQ e, CX; \ RORQ $14, AX; \ MOVQ e, DX; \ RORQ $18, CX; \ XORQ CX, AX; \ MOVQ e, CX; \ RORQ $41, DX; \ ANDQ f, CX; \ XORQ AX, DX; \ MOVQ e, AX; \ NOTQ AX; \ ADDQ DX, h; \ ANDQ g, AX; \ XORQ CX, AX; \ ADDQ h, AX // Calculate T2 in BX - uses BX, CX, DX and DI registers. // T2 = BIGSIGMA0(a) + Maj(a, b, c) // BIGSIGMA0(x) = ROTR(28,x) XOR ROTR(34,x) XOR ROTR(39,x) // Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z) #define SHA512T2(a, b, c) \ MOVQ a, DI; \ MOVQ c, BX; \ RORQ $28, DI; \ MOVQ a, DX; \ ANDQ b, BX; \ RORQ $34, DX; \ MOVQ a, CX; \ ANDQ c, CX; \ XORQ DX, DI; \ XORQ CX, BX; \ MOVQ a, DX; \ MOVQ b, CX; \ RORQ $39, DX; \ ANDQ a, CX; \ XORQ CX, BX; \ XORQ DX, DI; \ ADDQ DI, BX // Calculate T1 and T2, then e = d + T1 and a = T1 + T2. // The values for e and a are stored in d and h, ready for rotation. #define SHA512ROUND(index, const, a, b, c, d, e, f, g, h) \ SHA512T1(const, e, f, g, h); \ SHA512T2(a, b, c); \ MOVQ BX, h; \ ADDQ AX, d; \ ADDQ AX, h #define SHA512ROUND0(index, const, a, b, c, d, e, f, g, h) \ MSGSCHEDULE0(index); \ SHA512ROUND(index, const, a, b, c, d, e, f, g, h) #define SHA512ROUND1(index, const, a, b, c, d, e, f, g, h) \ MSGSCHEDULE1(index); \ SHA512ROUND(index, const, a, b, c, d, e, f, g, h) TEXT ·block(SB),0,$648-32 MOVQ p_base+8(FP), SI MOVQ p_len+16(FP), DX SHRQ $7, DX SHLQ $7, DX LEAQ (SI)(DX*1), DI MOVQ DI, 640(SP) CMPQ SI, DI JEQ end MOVQ dig+0(FP), BP MOVQ (0*8)(BP), R8 // a = H0 MOVQ (1*8)(BP), R9 // b = H1 MOVQ (2*8)(BP), R10 // c = H2 MOVQ (3*8)(BP), R11 // d = H3 MOVQ (4*8)(BP), R12 // e = H4 MOVQ (5*8)(BP), R13 // f = H5 MOVQ (6*8)(BP), R14 // g = H6 MOVQ (7*8)(BP), R15 // h = H7 loop: MOVQ SP, BP // message schedule SHA512ROUND0(0, 0x428a2f98d728ae22, R8, R9, R10, R11, R12, R13, R14, R15) SHA512ROUND0(1, 0x7137449123ef65cd, R15, R8, R9, R10, R11, R12, R13, R14) SHA512ROUND0(2, 0xb5c0fbcfec4d3b2f, R14, R15, R8, R9, R10, R11, R12, R13) SHA512ROUND0(3, 0xe9b5dba58189dbbc, R13, R14, R15, R8, R9, R10, R11, R12) SHA512ROUND0(4, 0x3956c25bf348b538, R12, R13, R14, R15, R8, R9, R10, R11) SHA512ROUND0(5, 0x59f111f1b605d019, R11, R12, R13, R14, R15, R8, R9, R10) SHA512ROUND0(6, 0x923f82a4af194f9b, R10, R11, R12, R13, R14, R15, R8, R9) SHA512ROUND0(7, 0xab1c5ed5da6d8118, R9, R10, R11, R12, R13, R14, R15, R8) SHA512ROUND0(8, 0xd807aa98a3030242, R8, R9, R10, R11, R12, R13, R14, R15) SHA512ROUND0(9, 0x12835b0145706fbe, R15, R8, R9, R10, R11, R12, R13, R14) SHA512ROUND0(10, 0x243185be4ee4b28c, R14, R15, R8, R9, R10, R11, R12, R13) SHA512ROUND0(11, 0x550c7dc3d5ffb4e2, R13, R14, R15, R8, R9, R10, R11, R12) SHA512ROUND0(12, 0x72be5d74f27b896f, R12, R13, R14, R15, R8, R9, R10, R11) SHA512ROUND0(13, 0x80deb1fe3b1696b1, R11, R12, R13, R14, R15, R8, R9, R10) SHA512ROUND0(14, 0x9bdc06a725c71235, R10, R11, R12, R13, R14, R15, R8, R9) SHA512ROUND0(15, 0xc19bf174cf692694, R9, R10, R11, R12, R13, R14, R15, R8) SHA512ROUND1(16, 0xe49b69c19ef14ad2, R8, R9, R10, R11, R12, R13, R14, R15) SHA512ROUND1(17, 0xefbe4786384f25e3, R15, R8, R9, R10, R11, R12, R13, R14) SHA512ROUND1(18, 0x0fc19dc68b8cd5b5, R14, R15, R8, R9, R10, R11, R12, R13) SHA512ROUND1(19, 0x240ca1cc77ac9c65, R13, R14, R15, R8, R9, R10, R11, R12) SHA512ROUND1(20, 0x2de92c6f592b0275, R12, R13, R14, R15, R8, R9, R10, R11) SHA512ROUND1(21, 0x4a7484aa6ea6e483, R11, R12, R13, R14, R15, R8, R9, R10) SHA512ROUND1(22, 0x5cb0a9dcbd41fbd4, R10, R11, R12, R13, R14, R15, R8, R9) SHA512ROUND1(23, 0x76f988da831153b5, R9, R10, R11, R12, R13, R14, R15, R8) SHA512ROUND1(24, 0x983e5152ee66dfab, R8, R9, R10, R11, R12, R13, R14, R15) SHA512ROUND1(25, 0xa831c66d2db43210, R15, R8, R9, R10, R11, R12, R13, R14) SHA512ROUND1(26, 0xb00327c898fb213f, R14, R15, R8, R9, R10, R11, R12, R13) SHA512ROUND1(27, 0xbf597fc7beef0ee4, R13, R14, R15, R8, R9, R10, R11, R12) SHA512ROUND1(28, 0xc6e00bf33da88fc2, R12, R13, R14, R15, R8, R9, R10, R11) SHA512ROUND1(29, 0xd5a79147930aa725, R11, R12, R13, R14, R15, R8, R9, R10) SHA512ROUND1(30, 0x06ca6351e003826f, R10, R11, R12, R13, R14, R15, R8, R9) SHA512ROUND1(31, 0x142929670a0e6e70, R9, R10, R11, R12, R13, R14, R15, R8) SHA512ROUND1(32, 0x27b70a8546d22ffc, R8, R9, R10, R11, R12, R13, R14, R15) SHA512ROUND1(33, 0x2e1b21385c26c926, R15, R8, R9, R10, R11, R12, R13, R14) SHA512ROUND1(34, 0x4d2c6dfc5ac42aed, R14, R15, R8, R9, R10, R11, R12, R13) SHA512ROUND1(35, 0x53380d139d95b3df, R13, R14, R15, R8, R9, R10, R11, R12) SHA512ROUND1(36, 0x650a73548baf63de, R12, R13, R14, R15, R8, R9, R10, R11) SHA512ROUND1(37, 0x766a0abb3c77b2a8, R11, R12, R13, R14, R15, R8, R9, R10) SHA512ROUND1(38, 0x81c2c92e47edaee6, R10, R11, R12, R13, R14, R15, R8, R9) SHA512ROUND1(39, 0x92722c851482353b, R9, R10, R11, R12, R13, R14, R15, R8) SHA512ROUND1(40, 0xa2bfe8a14cf10364, R8, R9, R10, R11, R12, R13, R14, R15) SHA512ROUND1(41, 0xa81a664bbc423001, R15, R8, R9, R10, R11, R12, R13, R14) SHA512ROUND1(42, 0xc24b8b70d0f89791, R14, R15, R8, R9, R10, R11, R12, R13) SHA512ROUND1(43, 0xc76c51a30654be30, R13, R14, R15, R8, R9, R10, R11, R12) SHA512ROUND1(44, 0xd192e819d6ef5218, R12, R13, R14, R15, R8, R9, R10, R11) SHA512ROUND1(45, 0xd69906245565a910, R11, R12, R13, R14, R15, R8, R9, R10) SHA512ROUND1(46, 0xf40e35855771202a, R10, R11, R12, R13, R14, R15, R8, R9) SHA512ROUND1(47, 0x106aa07032bbd1b8, R9, R10, R11, R12, R13, R14, R15, R8) SHA512ROUND1(48, 0x19a4c116b8d2d0c8, R8, R9, R10, R11, R12, R13, R14, R15) SHA512ROUND1(49, 0x1e376c085141ab53, R15, R8, R9, R10, R11, R12, R13, R14) SHA512ROUND1(50, 0x2748774cdf8eeb99, R14, R15, R8, R9, R10, R11, R12, R13) SHA512ROUND1(51, 0x34b0bcb5e19b48a8, R13, R14, R15, R8, R9, R10, R11, R12) SHA512ROUND1(52, 0x391c0cb3c5c95a63, R12, R13, R14, R15, R8, R9, R10, R11) SHA512ROUND1(53, 0x4ed8aa4ae3418acb, R11, R12, R13, R14, R15, R8, R9, R10) SHA512ROUND1(54, 0x5b9cca4f7763e373, R10, R11, R12, R13, R14, R15, R8, R9) SHA512ROUND1(55, 0x682e6ff3d6b2b8a3, R9, R10, R11, R12, R13, R14, R15, R8) SHA512ROUND1(56, 0x748f82ee5defb2fc, R8, R9, R10, R11, R12, R13, R14, R15) SHA512ROUND1(57, 0x78a5636f43172f60, R15, R8, R9, R10, R11, R12, R13, R14) SHA512ROUND1(58, 0x84c87814a1f0ab72, R14, R15, R8, R9, R10, R11, R12, R13) SHA512ROUND1(59, 0x8cc702081a6439ec, R13, R14, R15, R8, R9, R10, R11, R12) SHA512ROUND1(60, 0x90befffa23631e28, R12, R13, R14, R15, R8, R9, R10, R11) SHA512ROUND1(61, 0xa4506cebde82bde9, R11, R12, R13, R14, R15, R8, R9, R10) SHA512ROUND1(62, 0xbef9a3f7b2c67915, R10, R11, R12, R13, R14, R15, R8, R9) SHA512ROUND1(63, 0xc67178f2e372532b, R9, R10, R11, R12, R13, R14, R15, R8) SHA512ROUND1(64, 0xca273eceea26619c, R8, R9, R10, R11, R12, R13, R14, R15) SHA512ROUND1(65, 0xd186b8c721c0c207, R15, R8, R9, R10, R11, R12, R13, R14) SHA512ROUND1(66, 0xeada7dd6cde0eb1e, R14, R15, R8, R9, R10, R11, R12, R13) SHA512ROUND1(67, 0xf57d4f7fee6ed178, R13, R14, R15, R8, R9, R10, R11, R12) SHA512ROUND1(68, 0x06f067aa72176fba, R12, R13, R14, R15, R8, R9, R10, R11) SHA512ROUND1(69, 0x0a637dc5a2c898a6, R11, R12, R13, R14, R15, R8, R9, R10) SHA512ROUND1(70, 0x113f9804bef90dae, R10, R11, R12, R13, R14, R15, R8, R9) SHA512ROUND1(71, 0x1b710b35131c471b, R9, R10, R11, R12, R13, R14, R15, R8) SHA512ROUND1(72, 0x28db77f523047d84, R8, R9, R10, R11, R12, R13, R14, R15) SHA512ROUND1(73, 0x32caab7b40c72493, R15, R8, R9, R10, R11, R12, R13, R14) SHA512ROUND1(74, 0x3c9ebe0a15c9bebc, R14, R15, R8, R9, R10, R11, R12, R13) SHA512ROUND1(75, 0x431d67c49c100d4c, R13, R14, R15, R8, R9, R10, R11, R12) SHA512ROUND1(76, 0x4cc5d4becb3e42b6, R12, R13, R14, R15, R8, R9, R10, R11) SHA512ROUND1(77, 0x597f299cfc657e2a, R11, R12, R13, R14, R15, R8, R9, R10) SHA512ROUND1(78, 0x5fcb6fab3ad6faec, R10, R11, R12, R13, R14, R15, R8, R9) SHA512ROUND1(79, 0x6c44198c4a475817, R9, R10, R11, R12, R13, R14, R15, R8) MOVQ dig+0(FP), BP ADDQ (0*8)(BP), R8 // H0 = a + H0 MOVQ R8, (0*8)(BP) ADDQ (1*8)(BP), R9 // H1 = b + H1 MOVQ R9, (1*8)(BP) ADDQ (2*8)(BP), R10 // H2 = c + H2 MOVQ R10, (2*8)(BP) ADDQ (3*8)(BP), R11 // H3 = d + H3 MOVQ R11, (3*8)(BP) ADDQ (4*8)(BP), R12 // H4 = e + H4 MOVQ R12, (4*8)(BP) ADDQ (5*8)(BP), R13 // H5 = f + H5 MOVQ R13, (5*8)(BP) ADDQ (6*8)(BP), R14 // H6 = g + H6 MOVQ R14, (6*8)(BP) ADDQ (7*8)(BP), R15 // H7 = h + H7 MOVQ R15, (7*8)(BP) ADDQ $128, SI CMPQ SI, 640(SP) JB loop end: RET ================================================ FILE: scan/crypto/sha512/sha512block_decl.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build amd64 // +build amd64 package sha512 //go:noescape func block(dig *digest, p []byte) ================================================ FILE: scan/crypto/tls/alert.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import "strconv" type alert uint8 const ( // alert level alertLevelWarning = 1 alertLevelError = 2 ) const ( alertCloseNotify alert = 0 alertUnexpectedMessage alert = 10 alertBadRecordMAC alert = 20 alertDecryptionFailed alert = 21 alertRecordOverflow alert = 22 alertDecompressionFailure alert = 30 alertHandshakeFailure alert = 40 alertBadCertificate alert = 42 alertUnsupportedCertificate alert = 43 alertCertificateRevoked alert = 44 alertCertificateExpired alert = 45 alertCertificateUnknown alert = 46 alertIllegalParameter alert = 47 alertUnknownCA alert = 48 alertAccessDenied alert = 49 alertDecodeError alert = 50 alertDecryptError alert = 51 alertProtocolVersion alert = 70 alertInsufficientSecurity alert = 71 alertInternalError alert = 80 alertInappropriateFallback alert = 86 alertUserCanceled alert = 90 alertNoRenegotiation alert = 100 ) var alertText = map[alert]string{ alertCloseNotify: "close notify", alertUnexpectedMessage: "unexpected message", alertBadRecordMAC: "bad record MAC", alertDecryptionFailed: "decryption failed", alertRecordOverflow: "record overflow", alertDecompressionFailure: "decompression failure", alertHandshakeFailure: "handshake failure", alertBadCertificate: "bad certificate", alertUnsupportedCertificate: "unsupported certificate", alertCertificateRevoked: "revoked certificate", alertCertificateExpired: "expired certificate", alertCertificateUnknown: "unknown certificate", alertIllegalParameter: "illegal parameter", alertUnknownCA: "unknown certificate authority", alertAccessDenied: "access denied", alertDecodeError: "error decoding message", alertDecryptError: "error decrypting message", alertProtocolVersion: "protocol version not supported", alertInsufficientSecurity: "insufficient security level", alertInternalError: "internal error", alertInappropriateFallback: "inappropriate fallback", alertUserCanceled: "user canceled", alertNoRenegotiation: "no renegotiation", } func (e alert) String() string { s, ok := alertText[e] if ok { return s } return "alert(" + strconv.Itoa(int(e)) + ")" } func (e alert) Error() string { return e.String() } ================================================ FILE: scan/crypto/tls/cfsslscan_common.go ================================================ package tls import ( "fmt" ) type hashAlgID uint8 const ( HashNone hashAlgID = iota HashMD5 HashSHA1 HashSHA224 HashSHA256 HashSHA384 HashSHA512 ) func (h hashAlgID) String() string { switch h { case HashNone: return "None" case HashMD5: return "MD5" case HashSHA1: return "SHA1" case HashSHA224: return "SHA224" case HashSHA256: return "SHA256" case HashSHA384: return "SHA384" case HashSHA512: return "SHA512" default: return "Unknown" } } type sigAlgID uint8 // Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1) const ( SigAnon sigAlgID = iota SigRSA SigDSA SigECDSA ) func (sig sigAlgID) String() string { switch sig { case SigAnon: return "Anon" case SigRSA: return "RSA" case SigDSA: return "DSA" case SigECDSA: return "ECDSA" default: return "Unknown" } } // SignatureAndHash mirrors the TLS 1.2, SignatureAndHashAlgorithm struct. See // RFC 5246, section A.4.1. type SignatureAndHash struct { h hashAlgID s sigAlgID } func (sigAlg SignatureAndHash) String() string { return fmt.Sprintf("{%s,%s}", sigAlg.s, sigAlg.h) } func (sigAlg SignatureAndHash) MarshalJSON() ([]byte, error) { return []byte(fmt.Sprintf(`{"signature":"%s","hash":"%s"}`, sigAlg.s, sigAlg.h)), nil } func (sigAlg SignatureAndHash) internal() signatureAndHash { return signatureAndHash{uint8(sigAlg.h), uint8(sigAlg.s)} } // defaultSignatureAndHashAlgorithms contains the default signature and hash // algorithm paris supported by `crypto/tls` var defaultSignatureAndHashAlgorithms []signatureAndHash // AllSignatureAndHashAlgorithms contains all possible signature and // hash algorithm pairs that the can be advertised in a TLS 1.2 ClientHello. var AllSignatureAndHashAlgorithms []SignatureAndHash func init() { defaultSignatureAndHashAlgorithms = supportedSignatureAlgorithms for _, sighash := range supportedSignatureAlgorithms { AllSignatureAndHashAlgorithms = append(AllSignatureAndHashAlgorithms, SignatureAndHash{hashAlgID(sighash.hash), sigAlgID(sighash.signature)}) } } // TLSVersions is a list of the current SSL/TLS Versions implemented by Go var Versions = map[uint16]string{ VersionSSL30: "SSL 3.0", VersionTLS10: "TLS 1.0", VersionTLS11: "TLS 1.1", VersionTLS12: "TLS 1.2", } // CipherSuite describes an individual cipher suite, with long and short names // and security properties. type CipherSuite struct { Name, ShortName string // ForwardSecret cipher suites negotiate ephemeral keys, allowing forward secrecy. ForwardSecret bool EllipticCurve bool } // Returns the (short) name of the cipher suite. func (c CipherSuite) String() string { if c.ShortName != "" { return c.ShortName } return c.Name } // CipherSuites contains all values in the TLS Cipher Suite Registry // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml var CipherSuites = map[uint16]CipherSuite{ 0x0000: {Name: "TLS_NULL_WITH_NULL_NULL"}, 0x0001: {Name: "TLS_RSA_WITH_NULL_MD5"}, 0x0002: {Name: "TLS_RSA_WITH_NULL_SHA"}, 0x0003: {Name: "TLS_RSA_EXPORT_WITH_RC4_40_MD5", ShortName: "EXP-RC4-MD5"}, 0x0004: {Name: "TLS_RSA_WITH_RC4_128_MD5", ShortName: "RC4-MD5"}, 0x0005: {Name: "TLS_RSA_WITH_RC4_128_SHA", ShortName: "RC4-SHA"}, 0x0006: {Name: "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", ShortName: "EXP-RC2-CBC-MD5"}, 0x0007: {Name: "TLS_RSA_WITH_IDEA_CBC_SHA", ShortName: "IDEA-CBC-SHA"}, 0x0008: {Name: "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", ShortName: "EXP-DES-CBC-SHA"}, 0x0009: {Name: "TLS_RSA_WITH_DES_CBC_SHA", ShortName: "DES-CBC-SHA"}, 0x000A: {Name: "TLS_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "DES-CBC3-SHA"}, 0x000B: {Name: "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ShortName: "EXP-DH-DSS-DES-CBC-SHA"}, 0x000C: {Name: "TLS_DH_DSS_WITH_DES_CBC_SHA", ShortName: "DH-DSS-DES-CBC-SHA"}, 0x000D: {Name: "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", ShortName: "DH-DSS-DES-CBC3-SHA"}, 0x000E: {Name: "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ShortName: "EXP-DH-RSA-DES-CBC-SHA"}, 0x000F: {Name: "TLS_DH_RSA_WITH_DES_CBC_SHA", ShortName: "DH-RSA-DES-CBC-SHA"}, 0x0010: {Name: "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "DH-RSA-DES-CBC3-SHA"}, 0x0011: {Name: "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ShortName: "EXP-EDH-DSS-DES-CBC-SHA", ForwardSecret: true}, 0x0012: {Name: "TLS_DHE_DSS_WITH_DES_CBC_SHA", ShortName: "EDH-DSS-DES-CBC-SHA", ForwardSecret: true}, 0x0013: {Name: "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ShortName: "EDH-DSS-DES-CBC3-SHA", ForwardSecret: true}, 0x0014: {Name: "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ShortName: "EXP-EDH-RSA-DES-CBC-SHA", ForwardSecret: true}, 0x0015: {Name: "TLS_DHE_RSA_WITH_DES_CBC_SHA", ShortName: "EDH-RSA-DES-CBC-SHA", ForwardSecret: true}, 0x0016: {Name: "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "EDH-RSA-DES-CBC3-SHA", ForwardSecret: true}, 0x0017: {Name: "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"}, 0x0018: {Name: "TLS_DH_anon_WITH_RC4_128_MD5"}, 0x0019: {Name: "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"}, 0x001A: {Name: "TLS_DH_anon_WITH_DES_CBC_SHA"}, 0x001B: {Name: "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"}, 0x001E: {Name: "TLS_KRB5_WITH_DES_CBC_SHA"}, 0x001F: {Name: "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"}, 0x0020: {Name: "TLS_KRB5_WITH_RC4_128_SHA"}, 0x0021: {Name: "TLS_KRB5_WITH_IDEA_CBC_SHA"}, 0x0022: {Name: "TLS_KRB5_WITH_DES_CBC_MD5"}, 0x0023: {Name: "TLS_KRB5_WITH_3DES_EDE_CBC_MD5"}, 0x0024: {Name: "TLS_KRB5_WITH_RC4_128_MD5"}, 0x0025: {Name: "TLS_KRB5_WITH_IDEA_CBC_MD5"}, 0x0026: {Name: "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA"}, 0x0027: {Name: "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"}, 0x0028: {Name: "TLS_KRB5_EXPORT_WITH_RC4_40_SHA"}, 0x0029: {Name: "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"}, 0x002A: {Name: "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"}, 0x002B: {Name: "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"}, 0x002C: {Name: "TLS_PSK_WITH_NULL_SHA"}, 0x002D: {Name: "TLS_DHE_PSK_WITH_NULL_SHA", ForwardSecret: true}, 0x002E: {Name: "TLS_RSA_PSK_WITH_NULL_SHA"}, 0x002F: {Name: "TLS_RSA_WITH_AES_128_CBC_SHA", ShortName: "AES128-SHA"}, 0x0030: {Name: "TLS_DH_DSS_WITH_AES_128_CBC_SHA", ShortName: "DH-DSS-AES128-SHA"}, 0x0031: {Name: "TLS_DH_RSA_WITH_AES_128_CBC_SHA", ShortName: "DH-RSA-AES128-SHA"}, 0x0032: {Name: "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", ShortName: "DHE-DSS-AES128-SHA", ForwardSecret: true}, 0x0033: {Name: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", ShortName: "DHE-RSA-AES128-SHA", ForwardSecret: true}, 0x0034: {Name: "TLS_DH_anon_WITH_AES_128_CBC_SHA"}, 0x0035: {Name: "TLS_RSA_WITH_AES_256_CBC_SHA", ShortName: "AES256-SHA"}, 0x0036: {Name: "TLS_DH_DSS_WITH_AES_256_CBC_SHA", ShortName: "DH-DSS-AES256-SHA"}, 0x0037: {Name: "TLS_DH_RSA_WITH_AES_256_CBC_SHA", ShortName: "DH-RSA-AES256-SHA"}, 0x0038: {Name: "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", ShortName: "DHE-DSS-AES256-SHA", ForwardSecret: true}, 0x0039: {Name: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", ShortName: "DHE-RSA-AES256-SHA", ForwardSecret: true}, 0x003A: {Name: "TLS_DH_anon_WITH_AES_256_CBC_SHA"}, 0x003B: {Name: "TLS_RSA_WITH_NULL_SHA256"}, 0x003C: {Name: "TLS_RSA_WITH_AES_128_CBC_SHA256", ShortName: "AES128-SHA256"}, 0x003D: {Name: "TLS_RSA_WITH_AES_256_CBC_SHA256", ShortName: "AES256-SHA256"}, 0x003E: {Name: "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", ShortName: "DH-DSS-AES128-SHA256"}, 0x003F: {Name: "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", ShortName: "DH-RSA-AES128-SHA256"}, 0x0040: {Name: "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", ShortName: "DHE-DSS-AES128-SHA256", ForwardSecret: true}, 0x0041: {Name: "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", ShortName: "CAMELLIA128-SHA"}, 0x0042: {Name: "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", ShortName: "DH-DSS-CAMELLIA128-SHA"}, 0x0043: {Name: "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", ShortName: "DH-RSA-CAMELLIA128-SHA"}, 0x0044: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", ShortName: "DHE-DSS-CAMELLIA128-SHA", ForwardSecret: true}, 0x0045: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", ShortName: "DHE-RSA-CAMELLIA128-SHA", ForwardSecret: true}, 0x0046: {Name: "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA"}, 0x0067: {Name: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", ShortName: "DHE-RSA-AES128-SHA256", ForwardSecret: true}, 0x0068: {Name: "TLS_DH_DSS_WITH_AES_256_CBC_SHA256", ShortName: "DH-DSS-AES256-SHA256"}, 0x0069: {Name: "TLS_DH_RSA_WITH_AES_256_CBC_SHA256", ShortName: "DH-RSA-AES256-SHA256"}, 0x006A: {Name: "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", ShortName: "DHE-DSS-AES256-SHA256", ForwardSecret: true}, 0x006B: {Name: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", ShortName: "DHE-RSA-AES256-SHA256", ForwardSecret: true}, 0x006C: {Name: "TLS_DH_anon_WITH_AES_128_CBC_SHA256"}, 0x006D: {Name: "TLS_DH_anon_WITH_AES_256_CBC_SHA256"}, 0x0084: {Name: "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", ShortName: "CAMELLIA256-SHA"}, 0x0085: {Name: "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", ShortName: "DH-DSS-CAMELLIA256-SHA"}, 0x0086: {Name: "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", ShortName: "DH-RSA-CAMELLIA256-SHA"}, 0x0087: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", ShortName: "DHE-DSS-CAMELLIA256-SHA", ForwardSecret: true}, 0x0088: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", ShortName: "DHE-RSA-CAMELLIA256-SHA", ForwardSecret: true}, 0x0089: {Name: "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA"}, 0x008A: {Name: "TLS_PSK_WITH_RC4_128_SHA", ShortName: "PSK-RC4-SHA"}, 0x008B: {Name: "TLS_PSK_WITH_3DES_EDE_CBC_SHA", ShortName: "PSK-3DES-EDE-CBC-SHA"}, 0x008C: {Name: "TLS_PSK_WITH_AES_128_CBC_SHA", ShortName: "PSK-AES128-CBC-SHA"}, 0x008D: {Name: "TLS_PSK_WITH_AES_256_CBC_SHA", ShortName: "PSK-AES256-CBC-SHA"}, 0x008E: {Name: "TLS_DHE_PSK_WITH_RC4_128_SHA", ForwardSecret: true}, 0x008F: {Name: "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", ForwardSecret: true}, 0x0090: {Name: "TLS_DHE_PSK_WITH_AES_128_CBC_SHA", ForwardSecret: true}, 0x0091: {Name: "TLS_DHE_PSK_WITH_AES_256_CBC_SHA", ForwardSecret: true}, 0x0092: {Name: "TLS_RSA_PSK_WITH_RC4_128_SHA"}, 0x0093: {Name: "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"}, 0x0094: {Name: "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"}, 0x0095: {Name: "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"}, 0x0096: {Name: "TLS_RSA_WITH_SEED_CBC_SHA", ShortName: "SEED-SHA"}, 0x0097: {Name: "TLS_DH_DSS_WITH_SEED_CBC_SHA", ShortName: "DH-DSS-SEED-SHA"}, 0x0098: {Name: "TLS_DH_RSA_WITH_SEED_CBC_SHA", ShortName: "DH-RSA-SEED-SHA"}, 0x0099: {Name: "TLS_DHE_DSS_WITH_SEED_CBC_SHA", ShortName: "DHE-DSS-SEED-SHA", ForwardSecret: true}, 0x009A: {Name: "TLS_DHE_RSA_WITH_SEED_CBC_SHA", ShortName: "DHE-RSA-SEED-SHA", ForwardSecret: true}, 0x009B: {Name: "TLS_DH_anon_WITH_SEED_CBC_SHA"}, 0x009C: {Name: "TLS_RSA_WITH_AES_128_GCM_SHA256", ShortName: "AES128-GCM-SHA256"}, 0x009D: {Name: "TLS_RSA_WITH_AES_256_GCM_SHA384", ShortName: "AES256-GCM-SHA384"}, 0x009E: {Name: "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", ShortName: "DHE-RSA-AES128-GCM-SHA256", ForwardSecret: true}, 0x009F: {Name: "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", ShortName: "DHE-RSA-AES256-GCM-SHA384", ForwardSecret: true}, 0x00A0: {Name: "TLS_DH_RSA_WITH_AES_128_GCM_SHA256", ShortName: "DH-RSA-AES128-GCM-SHA256"}, 0x00A1: {Name: "TLS_DH_RSA_WITH_AES_256_GCM_SHA384", ShortName: "DH-RSA-AES256-GCM-SHA384"}, 0x00A2: {Name: "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", ShortName: "DHE-DSS-AES128-GCM-SHA256", ForwardSecret: true}, 0x00A3: {Name: "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", ShortName: "DHE-DSS-AES256-GCM-SHA384", ForwardSecret: true}, 0x00A4: {Name: "TLS_DH_DSS_WITH_AES_128_GCM_SHA256", ShortName: "DH-DSS-AES128-GCM-SHA256"}, 0x00A5: {Name: "TLS_DH_DSS_WITH_AES_256_GCM_SHA384", ShortName: "DH-DSS-AES256-GCM-SHA384"}, 0x00A6: {Name: "TLS_DH_anon_WITH_AES_128_GCM_SHA256"}, 0x00A7: {Name: "TLS_DH_anon_WITH_AES_256_GCM_SHA384"}, 0x00A8: {Name: "TLS_PSK_WITH_AES_128_GCM_SHA256"}, 0x00A9: {Name: "TLS_PSK_WITH_AES_256_GCM_SHA384"}, 0x00AA: {Name: "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", ForwardSecret: true}, 0x00AB: {Name: "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", ForwardSecret: true}, 0x00AC: {Name: "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"}, 0x00AD: {Name: "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"}, 0x00AE: {Name: "TLS_PSK_WITH_AES_128_CBC_SHA256"}, 0x00AF: {Name: "TLS_PSK_WITH_AES_256_CBC_SHA384"}, 0x00B0: {Name: "TLS_PSK_WITH_NULL_SHA256"}, 0x00B1: {Name: "TLS_PSK_WITH_NULL_SHA384"}, 0x00B2: {Name: "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", ForwardSecret: true}, 0x00B3: {Name: "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", ForwardSecret: true}, 0x00B4: {Name: "TLS_DHE_PSK_WITH_NULL_SHA256", ForwardSecret: true}, 0x00B5: {Name: "TLS_DHE_PSK_WITH_NULL_SHA384", ForwardSecret: true}, 0x00B6: {Name: "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"}, 0x00B7: {Name: "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"}, 0x00B8: {Name: "TLS_RSA_PSK_WITH_NULL_SHA256"}, 0x00B9: {Name: "TLS_RSA_PSK_WITH_NULL_SHA384"}, 0x00BA: {Name: "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256"}, 0x00BB: {Name: "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256"}, 0x00BC: {Name: "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256"}, 0x00BD: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true}, 0x00BE: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true}, 0x00BF: {Name: "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256"}, 0x00C0: {Name: "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256"}, 0x00C1: {Name: "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256"}, 0x00C2: {Name: "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256"}, 0x00C3: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", ForwardSecret: true}, 0x00C4: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", ForwardSecret: true}, 0x00C5: {Name: "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"}, 0x00FF: {Name: "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"}, 0xC001: {Name: "TLS_ECDH_ECDSA_WITH_NULL_SHA", EllipticCurve: true}, 0xC002: {Name: "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", ShortName: "ECDH-ECDSA-RC4-SHA", EllipticCurve: true}, 0xC003: {Name: "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDH-ECDSA-DES-CBC3-SHA", EllipticCurve: true}, 0xC004: {Name: "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", ShortName: "ECDH-ECDSA-AES128-SHA", EllipticCurve: true}, 0xC005: {Name: "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", ShortName: "ECDH-ECDSA-AES256-SHA", EllipticCurve: true}, 0xC006: {Name: "TLS_ECDHE_ECDSA_WITH_NULL_SHA", ForwardSecret: true, EllipticCurve: true}, 0xC007: {Name: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", ShortName: "ECDHE-ECDSA-RC4-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC008: {Name: "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDHE-ECDSA-DES-CBC3-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC009: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", ShortName: "ECDHE-ECDSA-AES128-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC00A: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", ShortName: "ECDHE-ECDSA-AES256-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC00B: {Name: "TLS_ECDH_RSA_WITH_NULL_SHA", EllipticCurve: true}, 0xC00C: {Name: "TLS_ECDH_RSA_WITH_RC4_128_SHA", ShortName: "ECDH-RSA-RC4-SHA", EllipticCurve: true}, 0xC00D: {Name: "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDH-RSA-DES-CBC3-SHA", EllipticCurve: true}, 0xC00E: {Name: "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", ShortName: "ECDH-RSA-AES128-SHA", EllipticCurve: true}, 0xC00F: {Name: "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", ShortName: "ECDH-RSA-AES256-SHA", EllipticCurve: true}, 0xC010: {Name: "TLS_ECDHE_RSA_WITH_NULL_SHA", ForwardSecret: true, EllipticCurve: true}, 0xC011: {Name: "TLS_ECDHE_RSA_WITH_RC4_128_SHA", ShortName: "ECDHE-RSA-RC4-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC012: {Name: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDHE-RSA-DES-CBC3-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC013: {Name: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", ShortName: "ECDHE-RSA-AES128-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC014: {Name: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", ShortName: "ECDHE-RSA-AES256-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC015: {Name: "TLS_ECDH_anon_WITH_NULL_SHA", EllipticCurve: true}, 0xC016: {Name: "TLS_ECDH_anon_WITH_RC4_128_SHA", EllipticCurve: true}, 0xC017: {Name: "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", EllipticCurve: true}, 0xC018: {Name: "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", EllipticCurve: true}, 0xC019: {Name: "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", EllipticCurve: true}, 0xC01A: {Name: "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", ShortName: "SRP-3DES-EDE-CBC-SHA"}, 0xC01B: {Name: "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "SRP-RSA-3DES-EDE-CBC-SHA"}, 0xC01C: {Name: "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", ShortName: "SRP-DSS-3DES-EDE-CBC-SHA"}, 0xC01D: {Name: "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", ShortName: "SRP-AES-128-CBC-SHA"}, 0xC01E: {Name: "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", ShortName: "SRP-RSA-AES-128-CBC-SHA"}, 0xC01F: {Name: "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", ShortName: "SRP-DSS-AES-128-CBC-SHA"}, 0xC020: {Name: "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", ShortName: "SRP-AES-256-CBC-SHA"}, 0xC021: {Name: "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", ShortName: "SRP-RSA-AES-256-CBC-SHA"}, 0xC022: {Name: "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", ShortName: "SRP-DSS-AES-256-CBC-SHA"}, 0xC023: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDHE-ECDSA-AES128-SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC024: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDHE-ECDSA-AES256-SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC025: {Name: "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDH-ECDSA-AES128-SHA256", EllipticCurve: true}, 0xC026: {Name: "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDH-ECDSA-AES256-SHA384", EllipticCurve: true}, 0xC027: {Name: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDHE-RSA-AES128-SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC028: {Name: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDHE-RSA-AES256-SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC029: {Name: "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDH-RSA-AES128-SHA256", EllipticCurve: true}, 0xC02A: {Name: "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDH-RSA-AES256-SHA384", EllipticCurve: true}, 0xC02B: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDHE-ECDSA-AES128-GCM-SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC02C: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDHE-ECDSA-AES256-GCM-SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC02D: {Name: "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDH-ECDSA-AES128-GCM-SHA256", EllipticCurve: true}, 0xC02E: {Name: "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDH-ECDSA-AES256-GCM-SHA384", EllipticCurve: true}, 0xC02F: {Name: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDHE-RSA-AES128-GCM-SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC030: {Name: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDHE-RSA-AES256-GCM-SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC031: {Name: "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDH-RSA-AES128-GCM-SHA256", EllipticCurve: true}, 0xC032: {Name: "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDH-RSA-AES256-GCM-SHA384", EllipticCurve: true}, 0xC033: {Name: "TLS_ECDHE_PSK_WITH_RC4_128_SHA", ForwardSecret: true, EllipticCurve: true}, 0xC034: {Name: "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", ForwardSecret: true, EllipticCurve: true}, 0xC035: {Name: "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", ForwardSecret: true, EllipticCurve: true}, 0xC036: {Name: "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", ForwardSecret: true, EllipticCurve: true}, 0xC037: {Name: "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC038: {Name: "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC039: {Name: "TLS_ECDHE_PSK_WITH_NULL_SHA", ForwardSecret: true, EllipticCurve: true}, 0xC03A: {Name: "TLS_ECDHE_PSK_WITH_NULL_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC03B: {Name: "TLS_ECDHE_PSK_WITH_NULL_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC03C: {Name: "TLS_RSA_WITH_ARIA_128_CBC_SHA256"}, 0xC03D: {Name: "TLS_RSA_WITH_ARIA_256_CBC_SHA384"}, 0xC03E: {Name: "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256"}, 0xC03F: {Name: "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384"}, 0xC040: {Name: "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256"}, 0xC041: {Name: "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384"}, 0xC042: {Name: "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true}, 0xC043: {Name: "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true}, 0xC044: {Name: "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true}, 0xC045: {Name: "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true}, 0xC046: {Name: "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256"}, 0xC047: {Name: "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384"}, 0xC048: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC049: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC04A: {Name: "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", EllipticCurve: true}, 0xC04B: {Name: "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", EllipticCurve: true}, 0xC04C: {Name: "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC04D: {Name: "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC04E: {Name: "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", EllipticCurve: true}, 0xC04F: {Name: "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", EllipticCurve: true}, 0xC050: {Name: "TLS_RSA_WITH_ARIA_128_GCM_SHA256"}, 0xC051: {Name: "TLS_RSA_WITH_ARIA_256_GCM_SHA384"}, 0xC052: {Name: "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true}, 0xC053: {Name: "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true}, 0xC054: {Name: "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256"}, 0xC055: {Name: "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384"}, 0xC056: {Name: "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true}, 0xC057: {Name: "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true}, 0xC058: {Name: "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256"}, 0xC059: {Name: "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384"}, 0xC05A: {Name: "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256"}, 0xC05B: {Name: "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384"}, 0xC05C: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC05D: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC05E: {Name: "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", EllipticCurve: true}, 0xC05F: {Name: "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", EllipticCurve: true}, 0xC060: {Name: "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC061: {Name: "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC062: {Name: "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", EllipticCurve: true}, 0xC063: {Name: "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", EllipticCurve: true}, 0xC064: {Name: "TLS_PSK_WITH_ARIA_128_CBC_SHA256"}, 0xC065: {Name: "TLS_PSK_WITH_ARIA_256_CBC_SHA384"}, 0xC066: {Name: "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true}, 0xC067: {Name: "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true}, 0xC068: {Name: "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256"}, 0xC069: {Name: "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384"}, 0xC06A: {Name: "TLS_PSK_WITH_ARIA_128_GCM_SHA256"}, 0xC06B: {Name: "TLS_PSK_WITH_ARIA_256_GCM_SHA384"}, 0xC06C: {Name: "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true}, 0xC06D: {Name: "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true}, 0xC06E: {Name: "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256"}, 0xC06F: {Name: "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384"}, 0xC070: {Name: "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC071: {Name: "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC072: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC073: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC074: {Name: "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", EllipticCurve: true}, 0xC075: {Name: "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", EllipticCurve: true}, 0xC076: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC077: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC078: {Name: "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", EllipticCurve: true}, 0xC079: {Name: "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", EllipticCurve: true}, 0xC07A: {Name: "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256"}, 0xC07B: {Name: "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384"}, 0xC07C: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true}, 0xC07D: {Name: "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true}, 0xC07E: {Name: "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256"}, 0xC07F: {Name: "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384"}, 0xC080: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true}, 0xC081: {Name: "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true}, 0xC082: {Name: "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256"}, 0xC083: {Name: "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384"}, 0xC084: {Name: "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256"}, 0xC085: {Name: "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384"}, 0xC086: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC087: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC088: {Name: "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", EllipticCurve: true}, 0xC089: {Name: "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", EllipticCurve: true}, 0xC08A: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC08B: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC08C: {Name: "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", EllipticCurve: true}, 0xC08D: {Name: "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", EllipticCurve: true}, 0xC08E: {Name: "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256"}, 0xC08F: {Name: "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384"}, 0xC090: {Name: "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true}, 0xC091: {Name: "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true}, 0xC092: {Name: "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256"}, 0xC093: {Name: "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384"}, 0xC094: {Name: "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256"}, 0xC095: {Name: "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384"}, 0xC096: {Name: "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true}, 0xC097: {Name: "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true}, 0xC098: {Name: "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256"}, 0xC099: {Name: "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384"}, 0xC09A: {Name: "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC09B: {Name: "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC09C: {Name: "TLS_RSA_WITH_AES_128_CCM"}, 0xC09D: {Name: "TLS_RSA_WITH_AES_256_CCM"}, 0xC09E: {Name: "TLS_DHE_RSA_WITH_AES_128_CCM", ForwardSecret: true}, 0xC09F: {Name: "TLS_DHE_RSA_WITH_AES_256_CCM", ForwardSecret: true}, 0xC0A0: {Name: "TLS_RSA_WITH_AES_128_CCM_8"}, 0xC0A1: {Name: "TLS_RSA_WITH_AES_256_CCM_8"}, 0xC0A2: {Name: "TLS_DHE_RSA_WITH_AES_128_CCM_8", ForwardSecret: true}, 0xC0A3: {Name: "TLS_DHE_RSA_WITH_AES_256_CCM_8", ForwardSecret: true}, 0xC0A4: {Name: "TLS_PSK_WITH_AES_128_CCM"}, 0xC0A5: {Name: "TLS_PSK_WITH_AES_256_CCM"}, 0xC0A6: {Name: "TLS_DHE_PSK_WITH_AES_128_CCM", ForwardSecret: true}, 0xC0A7: {Name: "TLS_DHE_PSK_WITH_AES_256_CCM", ForwardSecret: true}, 0xC0A8: {Name: "TLS_PSK_WITH_AES_128_CCM_8"}, 0xC0A9: {Name: "TLS_PSK_WITH_AES_256_CCM_8"}, 0xC0AA: {Name: "TLS_PSK_DHE_WITH_AES_128_CCM_8", ForwardSecret: true}, 0xC0AB: {Name: "TLS_PSK_DHE_WITH_AES_256_CCM_8", ForwardSecret: true}, 0xC0AC: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM", ForwardSecret: true, EllipticCurve: true}, 0xC0AD: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM", ForwardSecret: true, EllipticCurve: true}, 0xC0AE: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", ForwardSecret: true, EllipticCurve: true}, 0xC0AF: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", ForwardSecret: true, EllipticCurve: true}, // Non-IANA standardized cipher suites: // ChaCha20, Poly1305 cipher suites are defined in // https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 0xCC13: {Name: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xCC14: {Name: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xCC15: {Name: "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", ForwardSecret: true, EllipticCurve: true}, } var Curves = map[CurveID]string{ 0: "Unassigned", 1: "sect163k1", 2: "sect163r1", 3: "sect163r2", 4: "sect193r1", 5: "sect193r2", 6: "sect233k1", 7: "sect233r1", 8: "sect239k1", 9: "sect283k1", 10: "sect283r1", 11: "sect409k1", 12: "sect409r1", 13: "sect571k1", 14: "sect571r1", 15: "secp160k1", 16: "secp160r1", 17: "secp160r2", 18: "secp192k1", 19: "secp192r1", 20: "secp224k1", 21: "secp224r1", 22: "secp256k1", 23: "secp256r1", 24: "secp384r1", 25: "secp521r1", 26: "brainpoolP256r1", 27: "brainpoolP384r1", 28: "brainpoolP512r1", 65281: "arbitrary_explicit_prime_curves", 65282: "arbitrary_explicit_char2_curves", } ================================================ FILE: scan/crypto/tls/cfsslscan_handshake.go ================================================ package tls // SayHello constructs a simple Client Hello to a server, parses its serverHelloMsg response // and returns the negotiated ciphersuite ID, and, if an EC cipher suite, the curve ID func (c *Conn) SayHello(newSigAls []SignatureAndHash) (cipherID, curveType uint16, curveID CurveID, version uint16, certs [][]byte, err error) { // Set the supported signatures and hashes to the set `newSigAls` supportedSignatureAlgorithms := make([]signatureAndHash, len(newSigAls)) for i := range newSigAls { supportedSignatureAlgorithms[i] = newSigAls[i].internal() } hello := &clientHelloMsg{ vers: c.config.maxVersion(), compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), ocspStapling: true, serverName: c.config.ServerName, supportedCurves: c.config.curvePreferences(), supportedPoints: []uint8{pointFormatUncompressed}, nextProtoNeg: len(c.config.NextProtos) > 0, secureRenegotiation: true, cipherSuites: c.config.cipherSuites(), signatureAndHashes: supportedSignatureAlgorithms, } serverHello, err := c.sayHello(hello) if err != nil { return } // Prime the connection, if necessary, for key // exchange messages by reading off the certificate // message and, if necessary, the OCSP stapling // message var msg interface{} msg, err = c.readHandshake() if err != nil { return } certMsg, ok := msg.(*certificateMsg) if !ok || len(certMsg.certificates) == 0 { err = unexpectedMessageError(certMsg, msg) return } certs = certMsg.certificates if serverHello.ocspStapling { msg, err = c.readHandshake() if err != nil { return } certStatusMsg, ok := msg.(*certificateStatusMsg) if !ok { err = unexpectedMessageError(certStatusMsg, msg) return } } if CipherSuites[serverHello.cipherSuite].EllipticCurve { var skx *serverKeyExchangeMsg skx, err = c.exchangeKeys() if err != nil { return } if skx.raw[0] != typeServerKeyExchange { err = unexpectedMessageError(skx, msg) return } if len(skx.key) < 4 { err = unexpectedMessageError(skx, msg) return } curveType = uint16(skx.key[0]) // If we have a named curve, report which one it is. if curveType == 3 { curveID = CurveID(skx.key[1])<<8 | CurveID(skx.key[2]) } } cipherID, version = serverHello.cipherSuite, serverHello.vers return } // sayHello is the backend to SayHello that returns a full serverHelloMsg for processing. func (c *Conn) sayHello(hello *clientHelloMsg) (serverHello *serverHelloMsg, err error) { c.writeRecord(recordTypeHandshake, hello.marshal()) msg, err := c.readHandshake() if err != nil { return } serverHello, ok := msg.(*serverHelloMsg) if !ok { return nil, unexpectedMessageError(serverHello, msg) } return } // exchangeKeys continues the handshake to receive the serverKeyExchange message, // from which we can extract elliptic curve parameters func (c *Conn) exchangeKeys() (serverKeyExchange *serverKeyExchangeMsg, err error) { msg, err := c.readHandshake() if err != nil { return } serverKeyExchange, ok := msg.(*serverKeyExchangeMsg) if !ok { return nil, unexpectedMessageError(serverKeyExchange, msg) } return } ================================================ FILE: scan/crypto/tls/cipher_suites.go ================================================ // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "crypto/aes" "crypto/cipher" "crypto/des" "crypto/hmac" "crypto/rc4" "crypto/sha1" "crypto/x509" "hash" ) // a keyAgreement implements the client and server side of a TLS key agreement // protocol by generating and processing key exchange messages. type keyAgreement interface { // On the server side, the first two methods are called in order. // In the case that the key agreement protocol doesn't use a // ServerKeyExchange message, generateServerKeyExchange can return nil, // nil. generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error) processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error) // On the client side, the next two methods are called in order. // This method may not be called if the server doesn't send a // ServerKeyExchange message. processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) } const ( // suiteECDH indicates that the cipher suite involves elliptic curve // Diffie-Hellman. This means that it should only be selected when the // client indicates that it supports ECC with a curve and point format // that we're happy with. suiteECDHE = 1 << iota // suiteECDSA indicates that the cipher suite involves an ECDSA // signature and therefore may only be selected when the server's // certificate is ECDSA. If this is not set then the cipher suite is // RSA based. suiteECDSA // suiteTLS12 indicates that the cipher suite should only be advertised // and accepted when using TLS 1.2. suiteTLS12 // suiteSHA384 indicates that the cipher suite uses SHA384 as the // handshake hash. suiteSHA384 // suiteDefaultOff indicates that this cipher suite is not included by // default. suiteDefaultOff ) // A cipherSuite is a specific combination of key agreement, cipher and MAC // function. All cipher suites currently assume RSA key agreement. type cipherSuite struct { id uint16 // the lengths, in bytes, of the key material needed for each component. keyLen int macLen int ivLen int ka func(version uint16) keyAgreement // flags is a bitmask of the suite* values, above. flags int cipher func(key, iv []byte, isRead bool) interface{} mac func(version uint16, macKey []byte) macFunction aead func(key, fixedNonce []byte) cipher.AEAD } var cipherSuites = []*cipherSuite{ // Ciphersuite order is chosen so that ECDHE comes before plain RSA // and RC4 comes before AES (because of the Lucky13 attack). {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM}, {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM}, {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil}, {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM}, {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil}, {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil}, } func cipherRC4(key, iv []byte, isRead bool) interface{} { cipher, _ := rc4.NewCipher(key) return cipher } func cipher3DES(key, iv []byte, isRead bool) interface{} { block, _ := des.NewTripleDESCipher(key) if isRead { return cipher.NewCBCDecrypter(block, iv) } return cipher.NewCBCEncrypter(block, iv) } func cipherAES(key, iv []byte, isRead bool) interface{} { block, _ := aes.NewCipher(key) if isRead { return cipher.NewCBCDecrypter(block, iv) } return cipher.NewCBCEncrypter(block, iv) } // macSHA1 returns a macFunction for the given protocol version. func macSHA1(version uint16, key []byte) macFunction { if version == VersionSSL30 { mac := ssl30MAC{ h: sha1.New(), key: make([]byte, len(key)), } copy(mac.key, key) return mac } return tls10MAC{hmac.New(sha1.New, key)} } type macFunction interface { Size() int MAC(digestBuf, seq, header, data []byte) []byte } // fixedNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to // each call. type fixedNonceAEAD struct { // sealNonce and openNonce are buffers where the larger nonce will be // constructed. Since a seal and open operation may be running // concurrently, there is a separate buffer for each. sealNonce, openNonce []byte aead cipher.AEAD } func (f *fixedNonceAEAD) NonceSize() int { return 8 } func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() } func (f *fixedNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte { copy(f.sealNonce[len(f.sealNonce)-8:], nonce) return f.aead.Seal(out, f.sealNonce, plaintext, additionalData) } func (f *fixedNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) { copy(f.openNonce[len(f.openNonce)-8:], nonce) return f.aead.Open(out, f.openNonce, plaintext, additionalData) } func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD { aes, err := aes.NewCipher(key) if err != nil { panic(err) } aead, err := cipher.NewGCM(aes) if err != nil { panic(err) } nonce1, nonce2 := make([]byte, 12), make([]byte, 12) copy(nonce1, fixedNonce) copy(nonce2, fixedNonce) return &fixedNonceAEAD{nonce1, nonce2, aead} } // ssl30MAC implements the SSLv3 MAC function, as defined in // www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1 type ssl30MAC struct { h hash.Hash key []byte } func (s ssl30MAC) Size() int { return s.h.Size() } var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36} var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c} func (s ssl30MAC) MAC(digestBuf, seq, header, data []byte) []byte { padLength := 48 if s.h.Size() == 20 { padLength = 40 } s.h.Reset() s.h.Write(s.key) s.h.Write(ssl30Pad1[:padLength]) s.h.Write(seq) s.h.Write(header[:1]) s.h.Write(header[3:5]) s.h.Write(data) digestBuf = s.h.Sum(digestBuf[:0]) s.h.Reset() s.h.Write(s.key) s.h.Write(ssl30Pad2[:padLength]) s.h.Write(digestBuf) return s.h.Sum(digestBuf[:0]) } // tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3. type tls10MAC struct { h hash.Hash } func (s tls10MAC) Size() int { return s.h.Size() } func (s tls10MAC) MAC(digestBuf, seq, header, data []byte) []byte { s.h.Reset() s.h.Write(seq) s.h.Write(header) s.h.Write(data) return s.h.Sum(digestBuf[:0]) } func rsaKA(version uint16) keyAgreement { return rsaKeyAgreement{} } func ecdheECDSAKA(version uint16) keyAgreement { return &ecdheKeyAgreement{ sigType: signatureECDSA, version: version, } } func ecdheRSAKA(version uint16) keyAgreement { return &ecdheKeyAgreement{ sigType: signatureRSA, version: version, } } // mutualCipherSuite returns a cipherSuite given a list of supported // ciphersuites and the id requested by the peer. func mutualCipherSuite(have []uint16, want uint16) *cipherSuite { for _, id := range have { if id == want { for _, suite := range cipherSuites { if suite.id == want { return suite } } return nil } } return nil } // A list of the possible cipher suite ids. Taken from // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml const ( TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005 TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035 TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011 TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator // that the client is doing version fallback. See // https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00. TLS_FALLBACK_SCSV uint16 = 0x5600 ) ================================================ FILE: scan/crypto/tls/common.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "container/list" "crypto" "crypto/rand" "crypto/sha512" "crypto/x509" "errors" "fmt" "io" "math/big" "strings" "sync" "time" ) const ( VersionSSL30 = 0x0300 VersionTLS10 = 0x0301 VersionTLS11 = 0x0302 VersionTLS12 = 0x0303 ) const ( maxPlaintext = 16384 // maximum plaintext payload length maxCiphertext = 16384 + 2048 // maximum ciphertext payload length recordHeaderLen = 5 // record header length maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) minVersion = VersionTLS10 maxVersion = VersionTLS12 ) // TLS record types. type recordType uint8 const ( recordTypeChangeCipherSpec recordType = 20 recordTypeAlert recordType = 21 recordTypeHandshake recordType = 22 recordTypeApplicationData recordType = 23 ) // TLS handshake message types. const ( typeClientHello uint8 = 1 typeServerHello uint8 = 2 typeNewSessionTicket uint8 = 4 typeCertificate uint8 = 11 typeServerKeyExchange uint8 = 12 typeCertificateRequest uint8 = 13 typeServerHelloDone uint8 = 14 typeCertificateVerify uint8 = 15 typeClientKeyExchange uint8 = 16 typeFinished uint8 = 20 typeCertificateStatus uint8 = 22 typeNextProtocol uint8 = 67 // Not IANA assigned ) // TLS compression types. const ( compressionNone uint8 = 0 ) // TLS extension numbers const ( extensionServerName uint16 = 0 extensionStatusRequest uint16 = 5 extensionSupportedCurves uint16 = 10 extensionSupportedPoints uint16 = 11 extensionSignatureAlgorithms uint16 = 13 extensionALPN uint16 = 16 extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6 extensionSessionTicket uint16 = 35 extensionNextProtoNeg uint16 = 13172 // not IANA assigned extensionRenegotiationInfo uint16 = 0xff01 ) // TLS signaling cipher suite values const ( scsvRenegotiation uint16 = 0x00ff ) // CurveID is the type of a TLS identifier for an elliptic curve. See // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8 type CurveID uint16 const ( CurveP256 CurveID = 23 CurveP384 CurveID = 24 CurveP521 CurveID = 25 ) // TLS Elliptic Curve Point Formats // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9 const ( pointFormatUncompressed uint8 = 0 ) // TLS CertificateStatusType (RFC 3546) const ( statusTypeOCSP uint8 = 1 ) // Certificate types (for certificateRequestMsg) const ( certTypeRSASign = 1 // A certificate containing an RSA key certTypeDSSSign = 2 // A certificate containing a DSA key certTypeRSAFixedDH = 3 // A certificate containing a static DH key certTypeDSSFixedDH = 4 // A certificate containing a static DH key // See RFC4492 sections 3 and 5.5. certTypeECDSASign = 64 // A certificate containing an ECDSA-capable public key, signed with ECDSA. certTypeRSAFixedECDH = 65 // A certificate containing an ECDH-capable public key, signed with RSA. certTypeECDSAFixedECDH = 66 // A certificate containing an ECDH-capable public key, signed with ECDSA. // Rest of these are reserved by the TLS spec ) // Hash functions for TLS 1.2 (See RFC 5246, section A.4.1) const ( hashSHA1 uint8 = 2 hashSHA256 uint8 = 4 hashSHA384 uint8 = 5 ) // Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1) const ( signatureRSA uint8 = 1 signatureECDSA uint8 = 3 ) // signatureAndHash mirrors the TLS 1.2, SignatureAndHashAlgorithm struct. See // RFC 5246, section A.4.1. type signatureAndHash struct { hash, signature uint8 } // supportedSignatureAlgorithms contains the signature and hash algorithms that // the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2 // CertificateRequest. var supportedSignatureAlgorithms = []signatureAndHash{ {hashSHA256, signatureRSA}, {hashSHA256, signatureECDSA}, {hashSHA384, signatureRSA}, {hashSHA384, signatureECDSA}, {hashSHA1, signatureRSA}, {hashSHA1, signatureECDSA}, } // ConnectionState records basic TLS details about the connection. type ConnectionState struct { Version uint16 // TLS version used by the connection (e.g. VersionTLS12) HandshakeComplete bool // TLS handshake is complete DidResume bool // connection resumes a previous TLS connection CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...) NegotiatedProtocol string // negotiated next protocol (from Config.NextProtos) NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server ServerName string // server name requested by client, if any (server side only) PeerCertificates []*x509.Certificate // certificate chain presented by remote peer VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates SignedCertificateTimestamps [][]byte // SCTs from the server, if any OCSPResponse []byte // stapled OCSP response from server, if any // TLSUnique contains the "tls-unique" channel binding value (see RFC // 5929, section 3). For resumed sessions this value will be nil // because resumption does not include enough context (see // https://secure-resumption.com/#channelbindings). This will change in // future versions of Go once the TLS master-secret fix has been // standardized and implemented. TLSUnique []byte } // ClientAuthType declares the policy the server will follow for // TLS Client Authentication. type ClientAuthType int const ( NoClientCert ClientAuthType = iota RequestClientCert RequireAnyClientCert VerifyClientCertIfGiven RequireAndVerifyClientCert ) // ClientSessionState contains the state needed by clients to resume TLS // sessions. type ClientSessionState struct { sessionTicket []uint8 // Encrypted ticket used for session resumption with server vers uint16 // SSL/TLS version negotiated for the session cipherSuite uint16 // Ciphersuite negotiated for the session masterSecret []byte // MasterSecret generated by client on a full handshake serverCertificates []*x509.Certificate // Certificate chain presented by the server verifiedChains [][]*x509.Certificate // Certificate chains we built for verification } // ClientSessionCache is a cache of ClientSessionState objects that can be used // by a client to resume a TLS session with a given server. ClientSessionCache // implementations should expect to be called concurrently from different // goroutines. type ClientSessionCache interface { // Get searches for a ClientSessionState associated with the given key. // On return, ok is true if one was found. Get(sessionKey string) (session *ClientSessionState, ok bool) // Put adds the ClientSessionState to the cache with the given key. Put(sessionKey string, cs *ClientSessionState) } // ClientHelloInfo contains information from a ClientHello message in order to // guide certificate selection in the GetCertificate callback. type ClientHelloInfo struct { // CipherSuites lists the CipherSuites supported by the client (e.g. // TLS_RSA_WITH_RC4_128_SHA). CipherSuites []uint16 // ServerName indicates the name of the server requested by the client // in order to support virtual hosting. ServerName is only set if the // client is using SNI (see // http://tools.ietf.org/html/rfc4366#section-3.1). ServerName string // SupportedCurves lists the elliptic curves supported by the client. // SupportedCurves is set only if the Supported Elliptic Curves // Extension is being used (see // http://tools.ietf.org/html/rfc4492#section-5.1.1). SupportedCurves []CurveID // SupportedPoints lists the point formats supported by the client. // SupportedPoints is set only if the Supported Point Formats Extension // is being used (see // http://tools.ietf.org/html/rfc4492#section-5.1.2). SupportedPoints []uint8 } // A Config structure is used to configure a TLS client or server. // After one has been passed to a TLS function it must not be // modified. A Config may be reused; the tls package will also not // modify it. type Config struct { // Rand provides the source of entropy for nonces and RSA blinding. // If Rand is nil, TLS uses the cryptographic random reader in package // crypto/rand. // The Reader must be safe for use by multiple goroutines. Rand io.Reader // Time returns the current time as the number of seconds since the epoch. // If Time is nil, TLS uses time.Now. Time func() time.Time // Certificates contains one or more certificate chains // to present to the other side of the connection. // Server configurations must include at least one certificate // or else set GetCertificate. Certificates []Certificate // NameToCertificate maps from a certificate name to an element of // Certificates. Note that a certificate name can be of the form // '*.example.com' and so doesn't have to be a domain name as such. // See Config.BuildNameToCertificate // The nil value causes the first element of Certificates to be used // for all connections. NameToCertificate map[string]*Certificate // GetCertificate returns a Certificate based on the given // ClientHelloInfo. It will only be called if the client supplies SNI // information or if Certificates is empty. // // If GetCertificate is nil or returns nil, then the certificate is // retrieved from NameToCertificate. If NameToCertificate is nil, the // first element of Certificates will be used. GetCertificate func(clientHello *ClientHelloInfo) (*Certificate, error) // RootCAs defines the set of root certificate authorities // that clients use when verifying server certificates. // If RootCAs is nil, TLS uses the host's root CA set. RootCAs *x509.CertPool // NextProtos is a list of supported, application level protocols. NextProtos []string // ServerName is used to verify the hostname on the returned // certificates unless InsecureSkipVerify is given. It is also included // in the client's handshake to support virtual hosting unless it is // an IP address. ServerName string // ClientAuth determines the server's policy for // TLS Client Authentication. The default is NoClientCert. ClientAuth ClientAuthType // ClientCAs defines the set of root certificate authorities // that servers use if required to verify a client certificate // by the policy in ClientAuth. ClientCAs *x509.CertPool // InsecureSkipVerify controls whether a client verifies the // server's certificate chain and host name. // If InsecureSkipVerify is true, TLS accepts any certificate // presented by the server and any host name in that certificate. // In this mode, TLS is susceptible to man-in-the-middle attacks. // This should be used only for testing. InsecureSkipVerify bool // CipherSuites is a list of supported cipher suites. If CipherSuites // is nil, TLS uses a list of suites supported by the implementation. CipherSuites []uint16 // PreferServerCipherSuites controls whether the server selects the // client's most preferred ciphersuite, or the server's most preferred // ciphersuite. If true then the server's preference, as expressed in // the order of elements in CipherSuites, is used. PreferServerCipherSuites bool // SessionTicketsDisabled may be set to true to disable session ticket // (resumption) support. SessionTicketsDisabled bool // SessionTicketKey is used by TLS servers to provide session // resumption. See RFC 5077. If zero, it will be filled with // random data before the first server handshake. // // If multiple servers are terminating connections for the same host // they should all have the same SessionTicketKey. If the // SessionTicketKey leaks, previously recorded and future TLS // connections using that key are compromised. SessionTicketKey [32]byte // SessionCache is a cache of ClientSessionState entries for TLS session // resumption. ClientSessionCache ClientSessionCache // MinVersion contains the minimum SSL/TLS version that is acceptable. // If zero, then TLS 1.0 is taken as the minimum. MinVersion uint16 // MaxVersion contains the maximum SSL/TLS version that is acceptable. // If zero, then the maximum version supported by this package is used, // which is currently TLS 1.2. MaxVersion uint16 // CurvePreferences contains the elliptic curves that will be used in // an ECDHE handshake, in preference order. If empty, the default will // be used. CurvePreferences []CurveID serverInitOnce sync.Once // guards calling (*Config).serverInit // mutex protects sessionTicketKeys mutex sync.RWMutex // sessionTicketKeys contains zero or more ticket keys. If the length // is zero, SessionTicketsDisabled must be true. The first key is used // for new tickets and any subsequent keys can be used to decrypt old // tickets. sessionTicketKeys []ticketKey } // ticketKeyNameLen is the number of bytes of identifier that is prepended to // an encrypted session ticket in order to identify the key used to encrypt it. const ticketKeyNameLen = 16 // ticketKey is the internal representation of a session ticket key. type ticketKey struct { // keyName is an opaque byte string that serves to identify the session // ticket key. It's exposed as plaintext in every session ticket. keyName [ticketKeyNameLen]byte aesKey [16]byte hmacKey [16]byte } // ticketKeyFromBytes converts from the external representation of a session // ticket key to a ticketKey. Externally, session ticket keys are 32 random // bytes and this function expands that into sufficient name and key material. func ticketKeyFromBytes(b [32]byte) (key ticketKey) { hashed := sha512.Sum512(b[:]) copy(key.keyName[:], hashed[:ticketKeyNameLen]) copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16]) copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32]) return key } func (c *Config) serverInit() { if c.SessionTicketsDisabled { return } alreadySet := false for _, b := range c.SessionTicketKey { if b != 0 { alreadySet = true break } } if !alreadySet { if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil { c.SessionTicketsDisabled = true return } } c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)} } func (c *Config) ticketKeys() []ticketKey { c.mutex.RLock() // c.sessionTicketKeys is constant once created. SetSessionTicketKeys // will only update it by replacing it with a new value. ret := c.sessionTicketKeys c.mutex.RUnlock() return ret } // SetSessionTicketKeys updates the session ticket keys for a server. The first // key will be used when creating new tickets, while all keys can be used for // decrypting tickets. It is safe to call this function while the server is // running in order to rotate the session ticket keys. The function will panic // if keys is empty. func (c *Config) SetSessionTicketKeys(keys [][32]byte) { if len(keys) == 0 { panic("tls: keys must have at least one key") } newKeys := make([]ticketKey, len(keys)) for i, bytes := range keys { newKeys[i] = ticketKeyFromBytes(bytes) } c.mutex.Lock() c.sessionTicketKeys = newKeys c.mutex.Unlock() } func (c *Config) rand() io.Reader { r := c.Rand if r == nil { return rand.Reader } return r } func (c *Config) time() time.Time { t := c.Time if t == nil { t = time.Now } return t() } func (c *Config) cipherSuites() []uint16 { s := c.CipherSuites if s == nil { s = defaultCipherSuites() } return s } func (c *Config) minVersion() uint16 { if c == nil || c.MinVersion == 0 { return minVersion } return c.MinVersion } func (c *Config) maxVersion() uint16 { if c == nil || c.MaxVersion == 0 { return maxVersion } return c.MaxVersion } var defaultCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521} func (c *Config) curvePreferences() []CurveID { if c == nil || len(c.CurvePreferences) == 0 { return defaultCurvePreferences } return c.CurvePreferences } // mutualVersion returns the protocol version to use given the advertised // version of the peer. func (c *Config) mutualVersion(vers uint16) (uint16, bool) { minVersion := c.minVersion() maxVersion := c.maxVersion() if vers < minVersion { return 0, false } if vers > maxVersion { vers = maxVersion } return vers, true } // getCertificate returns the best certificate for the given ClientHelloInfo, // defaulting to the first element of c.Certificates. func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) { if c.GetCertificate != nil && (len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) { cert, err := c.GetCertificate(clientHello) if cert != nil || err != nil { return cert, err } } if len(c.Certificates) == 0 { return nil, errors.New("crypto/tls: no certificates configured") } if len(c.Certificates) == 1 || c.NameToCertificate == nil { // There's only one choice, so no point doing any work. return &c.Certificates[0], nil } name := strings.ToLower(clientHello.ServerName) for len(name) > 0 && name[len(name)-1] == '.' { name = name[:len(name)-1] } if cert, ok := c.NameToCertificate[name]; ok { return cert, nil } // try replacing labels in the name with wildcards until we get a // match. labels := strings.Split(name, ".") for i := range labels { labels[i] = "*" candidate := strings.Join(labels, ".") if cert, ok := c.NameToCertificate[candidate]; ok { return cert, nil } } // If nothing matches, return the first certificate. return &c.Certificates[0], nil } // BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate // from the CommonName and SubjectAlternateName fields of each of the leaf // certificates. func (c *Config) BuildNameToCertificate() { c.NameToCertificate = make(map[string]*Certificate) for i := range c.Certificates { cert := &c.Certificates[i] x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) if err != nil { continue } if len(x509Cert.Subject.CommonName) > 0 { c.NameToCertificate[x509Cert.Subject.CommonName] = cert } for _, san := range x509Cert.DNSNames { c.NameToCertificate[san] = cert } } } // A Certificate is a chain of one or more certificates, leaf first. type Certificate struct { Certificate [][]byte // PrivateKey contains the private key corresponding to the public key // in Leaf. For a server, this must implement crypto.Signer and/or // crypto.Decrypter, with an RSA or ECDSA PublicKey. For a client // (performing client authentication), this must be a crypto.Signer // with an RSA or ECDSA PublicKey. PrivateKey crypto.PrivateKey // OCSPStaple contains an optional OCSP response which will be served // to clients that request it. OCSPStaple []byte // SignedCertificateTimestamps contains an optional list of Signed // Certificate Timestamps which will be served to clients that request it. SignedCertificateTimestamps [][]byte // Leaf is the parsed form of the leaf certificate, which may be // initialized using x509.ParseCertificate to reduce per-handshake // processing for TLS clients doing client authentication. If nil, the // leaf certificate will be parsed as needed. Leaf *x509.Certificate } // A TLS record. type record struct { contentType recordType major, minor uint8 payload []byte } type handshakeMessage interface { marshal() []byte unmarshal([]byte) bool } // lruSessionCache is a ClientSessionCache implementation that uses an LRU // caching strategy. type lruSessionCache struct { sync.Mutex m map[string]*list.Element q *list.List capacity int } type lruSessionCacheEntry struct { sessionKey string state *ClientSessionState } // NewLRUClientSessionCache returns a ClientSessionCache with the given // capacity that uses an LRU strategy. If capacity is < 1, a default capacity // is used instead. func NewLRUClientSessionCache(capacity int) ClientSessionCache { const defaultSessionCacheCapacity = 64 if capacity < 1 { capacity = defaultSessionCacheCapacity } return &lruSessionCache{ m: make(map[string]*list.Element), q: list.New(), capacity: capacity, } } // Put adds the provided (sessionKey, cs) pair to the cache. func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) { c.Lock() defer c.Unlock() if elem, ok := c.m[sessionKey]; ok { entry := elem.Value.(*lruSessionCacheEntry) entry.state = cs c.q.MoveToFront(elem) return } if c.q.Len() < c.capacity { entry := &lruSessionCacheEntry{sessionKey, cs} c.m[sessionKey] = c.q.PushFront(entry) return } elem := c.q.Back() entry := elem.Value.(*lruSessionCacheEntry) delete(c.m, entry.sessionKey) entry.sessionKey = sessionKey entry.state = cs c.q.MoveToFront(elem) c.m[sessionKey] = elem } // Get returns the ClientSessionState value associated with a given key. It // returns (nil, false) if no value is found. func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) { c.Lock() defer c.Unlock() if elem, ok := c.m[sessionKey]; ok { c.q.MoveToFront(elem) return elem.Value.(*lruSessionCacheEntry).state, true } return nil, false } // TODO(jsing): Make these available to both crypto/x509 and crypto/tls. type dsaSignature struct { R, S *big.Int } type ecdsaSignature dsaSignature var emptyConfig Config func defaultConfig() *Config { return &emptyConfig } var ( once sync.Once varDefaultCipherSuites []uint16 ) func defaultCipherSuites() []uint16 { once.Do(initDefaultCipherSuites) return varDefaultCipherSuites } func initDefaultCipherSuites() { varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites)) for _, suite := range cipherSuites { if suite.flags&suiteDefaultOff != 0 { continue } varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id) } } func unexpectedMessageError(wanted, got interface{}) error { return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted) } func isSupportedSignatureAndHash(sigHash signatureAndHash, sigHashes []signatureAndHash) bool { for _, s := range sigHashes { if s == sigHash { return true } } return false } ================================================ FILE: scan/crypto/tls/conn.go ================================================ // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // TLS low level connection and record layer package tls import ( "bytes" "crypto/cipher" "crypto/subtle" "crypto/x509" "errors" "fmt" "io" "net" "sync" "sync/atomic" "time" ) // A Conn represents a secured connection. // It implements the net.Conn interface. type Conn struct { // constant conn net.Conn isClient bool // constant after handshake; protected by handshakeMutex handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex handshakeErr error // error resulting from handshake vers uint16 // TLS version haveVers bool // version has been negotiated config *Config // configuration passed to constructor handshakeComplete bool didResume bool // whether this connection was a session resumption cipherSuite uint16 ocspResponse []byte // stapled OCSP response scts [][]byte // signed certificate timestamps from server peerCertificates []*x509.Certificate // verifiedChains contains the certificate chains that we built, as // opposed to the ones presented by the server. verifiedChains [][]*x509.Certificate // serverName contains the server name indicated by the client, if any. serverName string // firstFinished contains the first Finished hash sent during the // handshake. This is the "tls-unique" channel binding value. firstFinished [12]byte clientProtocol string clientProtocolFallback bool // input/output in, out halfConn // in.Mutex < out.Mutex rawInput *block // raw input, right off the wire input *block // application data waiting to be read hand bytes.Buffer // handshake data waiting to be read // activeCall is an atomic int32; the low bit is whether Close has // been called. the rest of the bits are the number of goroutines // in Conn.Write. activeCall int32 tmp [16]byte } // Access to net.Conn methods. // Cannot just embed net.Conn because that would // export the struct field too. // LocalAddr returns the local network address. func (c *Conn) LocalAddr() net.Addr { return c.conn.LocalAddr() } // RemoteAddr returns the remote network address. func (c *Conn) RemoteAddr() net.Addr { return c.conn.RemoteAddr() } // SetDeadline sets the read and write deadlines associated with the connection. // A zero value for t means Read and Write will not time out. // After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. func (c *Conn) SetDeadline(t time.Time) error { return c.conn.SetDeadline(t) } // SetReadDeadline sets the read deadline on the underlying connection. // A zero value for t means Read will not time out. func (c *Conn) SetReadDeadline(t time.Time) error { return c.conn.SetReadDeadline(t) } // SetWriteDeadline sets the write deadline on the underlying connection. // A zero value for t means Write will not time out. // After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. func (c *Conn) SetWriteDeadline(t time.Time) error { return c.conn.SetWriteDeadline(t) } // A halfConn represents one direction of the record layer // connection, either sending or receiving. type halfConn struct { sync.Mutex err error // first permanent error version uint16 // protocol version cipher interface{} // cipher algorithm mac macFunction seq [8]byte // 64-bit sequence number bfree *block // list of free blocks additionalData [13]byte // to avoid allocs; interface method args escape nextCipher interface{} // next encryption state nextMac macFunction // next MAC algorithm // used to save allocating a new buffer for each MAC. inDigestBuf, outDigestBuf []byte } func (hc *halfConn) setErrorLocked(err error) error { hc.err = err return err } func (hc *halfConn) error() error { hc.Lock() err := hc.err hc.Unlock() return err } // prepareCipherSpec sets the encryption and MAC states // that a subsequent changeCipherSpec will use. func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) { hc.version = version hc.nextCipher = cipher hc.nextMac = mac } // changeCipherSpec changes the encryption and MAC states // to the ones previously passed to prepareCipherSpec. func (hc *halfConn) changeCipherSpec() error { if hc.nextCipher == nil { return alertInternalError } hc.cipher = hc.nextCipher hc.mac = hc.nextMac hc.nextCipher = nil hc.nextMac = nil for i := range hc.seq { hc.seq[i] = 0 } return nil } // incSeq increments the sequence number. func (hc *halfConn) incSeq() { for i := 7; i >= 0; i-- { hc.seq[i]++ if hc.seq[i] != 0 { return } } // Not allowed to let sequence number wrap. // Instead, must renegotiate before it does. // Not likely enough to bother. panic("TLS: sequence number wraparound") } // resetSeq resets the sequence number to zero. func (hc *halfConn) resetSeq() { for i := range hc.seq { hc.seq[i] = 0 } } // removePadding returns an unpadded slice, in constant time, which is a prefix // of the input. It also returns a byte which is equal to 255 if the padding // was valid and 0 otherwise. See RFC 2246, section 6.2.3.2 func removePadding(payload []byte) ([]byte, byte) { if len(payload) < 1 { return payload, 0 } paddingLen := payload[len(payload)-1] t := uint(len(payload)-1) - uint(paddingLen) // if len(payload) >= (paddingLen - 1) then the MSB of t is zero good := byte(int32(^t) >> 31) toCheck := 255 // the maximum possible padding length // The length of the padded data is public, so we can use an if here if toCheck+1 > len(payload) { toCheck = len(payload) - 1 } for i := 0; i < toCheck; i++ { t := uint(paddingLen) - uint(i) // if i <= paddingLen then the MSB of t is zero mask := byte(int32(^t) >> 31) b := payload[len(payload)-1-i] good &^= mask&paddingLen ^ mask&b } // We AND together the bits of good and replicate the result across // all the bits. good &= good << 4 good &= good << 2 good &= good << 1 good = uint8(int8(good) >> 7) toRemove := good&paddingLen + 1 return payload[:len(payload)-int(toRemove)], good } // removePaddingSSL30 is a replacement for removePadding in the case that the // protocol version is SSLv3. In this version, the contents of the padding // are random and cannot be checked. func removePaddingSSL30(payload []byte) ([]byte, byte) { if len(payload) < 1 { return payload, 0 } paddingLen := int(payload[len(payload)-1]) + 1 if paddingLen > len(payload) { return payload, 0 } return payload[:len(payload)-paddingLen], 255 } func roundUp(a, b int) int { return a + (b-a%b)%b } // cbcMode is an interface for block ciphers using cipher block chaining. type cbcMode interface { cipher.BlockMode SetIV([]byte) } // decrypt checks and strips the mac and decrypts the data in b. Returns a // success boolean, the number of bytes to skip from the start of the record in // order to get the application payload, and an optional alert value. func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) { // pull out payload payload := b.data[recordHeaderLen:] macSize := 0 if hc.mac != nil { macSize = hc.mac.Size() } paddingGood := byte(255) explicitIVLen := 0 // decrypt if hc.cipher != nil { switch c := hc.cipher.(type) { case cipher.Stream: c.XORKeyStream(payload, payload) case cipher.AEAD: explicitIVLen = 8 if len(payload) < explicitIVLen { return false, 0, alertBadRecordMAC } nonce := payload[:8] payload = payload[8:] copy(hc.additionalData[:], hc.seq[:]) copy(hc.additionalData[8:], b.data[:3]) n := len(payload) - c.Overhead() hc.additionalData[11] = byte(n >> 8) hc.additionalData[12] = byte(n) var err error payload, err = c.Open(payload[:0], nonce, payload, hc.additionalData[:]) if err != nil { return false, 0, alertBadRecordMAC } b.resize(recordHeaderLen + explicitIVLen + len(payload)) case cbcMode: blockSize := c.BlockSize() if hc.version >= VersionTLS11 { explicitIVLen = blockSize } if len(payload)%blockSize != 0 || len(payload) < roundUp(explicitIVLen+macSize+1, blockSize) { return false, 0, alertBadRecordMAC } if explicitIVLen > 0 { c.SetIV(payload[:explicitIVLen]) payload = payload[explicitIVLen:] } c.CryptBlocks(payload, payload) if hc.version == VersionSSL30 { payload, paddingGood = removePaddingSSL30(payload) } else { payload, paddingGood = removePadding(payload) } b.resize(recordHeaderLen + explicitIVLen + len(payload)) // note that we still have a timing side-channel in the // MAC check, below. An attacker can align the record // so that a correct padding will cause one less hash // block to be calculated. Then they can iteratively // decrypt a record by breaking each byte. See // "Password Interception in a SSL/TLS Channel", Brice // Canvel et al. // // However, our behavior matches OpenSSL, so we leak // only as much as they do. default: panic("unknown cipher type") } } // check, strip mac if hc.mac != nil { if len(payload) < macSize { return false, 0, alertBadRecordMAC } // strip mac off payload, b.data n := len(payload) - macSize b.data[3] = byte(n >> 8) b.data[4] = byte(n) b.resize(recordHeaderLen + explicitIVLen + n) remoteMAC := payload[n:] localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n]) if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 { return false, 0, alertBadRecordMAC } hc.inDigestBuf = localMAC } hc.incSeq() return true, recordHeaderLen + explicitIVLen, 0 } // padToBlockSize calculates the needed padding block, if any, for a payload. // On exit, prefix aliases payload and extends to the end of the last full // block of payload. finalBlock is a fresh slice which contains the contents of // any suffix of payload as well as the needed padding to make finalBlock a // full block. func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) { overrun := len(payload) % blockSize paddingLen := blockSize - overrun prefix = payload[:len(payload)-overrun] finalBlock = make([]byte, blockSize) copy(finalBlock, payload[len(payload)-overrun:]) for i := overrun; i < blockSize; i++ { finalBlock[i] = byte(paddingLen - 1) } return } // encrypt encrypts and macs the data in b. func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) { // mac if hc.mac != nil { mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:]) n := len(b.data) b.resize(n + len(mac)) copy(b.data[n:], mac) hc.outDigestBuf = mac } payload := b.data[recordHeaderLen:] // encrypt if hc.cipher != nil { switch c := hc.cipher.(type) { case cipher.Stream: c.XORKeyStream(payload, payload) case cipher.AEAD: payloadLen := len(b.data) - recordHeaderLen - explicitIVLen b.resize(len(b.data) + c.Overhead()) nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] payload := b.data[recordHeaderLen+explicitIVLen:] payload = payload[:payloadLen] copy(hc.additionalData[:], hc.seq[:]) copy(hc.additionalData[8:], b.data[:3]) hc.additionalData[11] = byte(payloadLen >> 8) hc.additionalData[12] = byte(payloadLen) c.Seal(payload[:0], nonce, payload, hc.additionalData[:]) case cbcMode: blockSize := c.BlockSize() if explicitIVLen > 0 { c.SetIV(payload[:explicitIVLen]) payload = payload[explicitIVLen:] } prefix, finalBlock := padToBlockSize(payload, blockSize) b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock)) c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix) c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock) default: panic("unknown cipher type") } } // update length to include MAC and any block padding needed. n := len(b.data) - recordHeaderLen b.data[3] = byte(n >> 8) b.data[4] = byte(n) hc.incSeq() return true, 0 } // A block is a simple data buffer. type block struct { data []byte off int // index for Read link *block } // resize resizes block to be n bytes, growing if necessary. func (b *block) resize(n int) { if n > cap(b.data) { b.reserve(n) } b.data = b.data[0:n] } // reserve makes sure that block contains a capacity of at least n bytes. func (b *block) reserve(n int) { if cap(b.data) >= n { return } m := cap(b.data) if m == 0 { m = 1024 } for m < n { m *= 2 } data := make([]byte, len(b.data), m) copy(data, b.data) b.data = data } // readFromUntil reads from r into b until b contains at least n bytes // or else returns an error. func (b *block) readFromUntil(r io.Reader, n int) error { // quick case if len(b.data) >= n { return nil } // read until have enough. b.reserve(n) for { m, err := r.Read(b.data[len(b.data):cap(b.data)]) b.data = b.data[0 : len(b.data)+m] if len(b.data) >= n { // TODO(bradfitz,agl): slightly suspicious // that we're throwing away r.Read's err here. break } if err != nil { return err } } return nil } func (b *block) Read(p []byte) (n int, err error) { n = copy(p, b.data[b.off:]) b.off += n return } // newBlock allocates a new block, from hc's free list if possible. func (hc *halfConn) newBlock() *block { b := hc.bfree if b == nil { return new(block) } hc.bfree = b.link b.link = nil b.resize(0) return b } // freeBlock returns a block to hc's free list. // The protocol is such that each side only has a block or two on // its free list at a time, so there's no need to worry about // trimming the list, etc. func (hc *halfConn) freeBlock(b *block) { b.link = hc.bfree hc.bfree = b } // splitBlock splits a block after the first n bytes, // returning a block with those n bytes and a // block with the remainder. the latter may be nil. func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) { if len(b.data) <= n { return b, nil } bb := hc.newBlock() bb.resize(len(b.data) - n) copy(bb.data, b.data[n:]) b.data = b.data[0:n] return b, bb } // RecordHeaderError results when a TLS record header is invalid. type RecordHeaderError struct { // Msg contains a human readable string that describes the error. Msg string // RecordHeader contains the five bytes of TLS record header that // triggered the error. RecordHeader [5]byte } func (e RecordHeaderError) Error() string { return "tls: " + e.Msg } func (c *Conn) newRecordHeaderError(msg string) (err RecordHeaderError) { err.Msg = msg copy(err.RecordHeader[:], c.rawInput.data) return err } // readRecord reads the next TLS record from the connection // and updates the record layer state. // c.in.Mutex <= L; c.input == nil. func (c *Conn) readRecord(want recordType) error { // Caller must be in sync with connection: // handshake data if handshake not yet completed, // else application data. (We don't support renegotiation.) switch want { default: c.sendAlert(alertInternalError) return c.in.setErrorLocked(errors.New("tls: unknown record type requested")) case recordTypeHandshake, recordTypeChangeCipherSpec: if c.handshakeComplete { c.sendAlert(alertInternalError) return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete")) } case recordTypeApplicationData: if !c.handshakeComplete { c.sendAlert(alertInternalError) return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete")) } } Again: if c.rawInput == nil { c.rawInput = c.in.newBlock() } b := c.rawInput // Read header, payload. if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil { // RFC suggests that EOF without an alertCloseNotify is // an error, but popular web sites seem to do this, // so we can't make it an error. // if err == io.EOF { // err = io.ErrUnexpectedEOF // } if e, ok := err.(net.Error); !ok || !e.Temporary() { c.in.setErrorLocked(err) } return err } typ := recordType(b.data[0]) // No valid TLS record has a type of 0x80, however SSLv2 handshakes // start with a uint16 length where the MSB is set and the first record // is always < 256 bytes long. Therefore typ == 0x80 strongly suggests // an SSLv2 client. if want == recordTypeHandshake && typ == 0x80 { c.sendAlert(alertProtocolVersion) return c.in.setErrorLocked(c.newRecordHeaderError("unsupported SSLv2 handshake received")) } vers := uint16(b.data[1])<<8 | uint16(b.data[2]) n := int(b.data[3])<<8 | int(b.data[4]) if c.haveVers && vers != c.vers { c.sendAlert(alertProtocolVersion) msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers) return c.in.setErrorLocked(c.newRecordHeaderError(msg)) } if n > maxCiphertext { c.sendAlert(alertRecordOverflow) msg := fmt.Sprintf("oversized record received with length %d", n) return c.in.setErrorLocked(c.newRecordHeaderError(msg)) } if !c.haveVers { // First message, be extra suspicious: this might not be a TLS // client. Bail out before reading a full 'body', if possible. // The current max version is 3.3 so if the version is >= 16.0, // it's probably not real. if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 { c.sendAlert(alertUnexpectedMessage) return c.in.setErrorLocked(c.newRecordHeaderError("first record does not look like a TLS handshake")) } } if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } if e, ok := err.(net.Error); !ok || !e.Temporary() { c.in.setErrorLocked(err) } return err } // Process message. b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n) ok, off, err := c.in.decrypt(b) if !ok { c.in.setErrorLocked(c.sendAlert(err)) } b.off = off data := b.data[b.off:] if len(data) > maxPlaintext { err := c.sendAlert(alertRecordOverflow) c.in.freeBlock(b) return c.in.setErrorLocked(err) } switch typ { default: c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) case recordTypeAlert: if len(data) != 2 { c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) break } if alert(data[1]) == alertCloseNotify { c.in.setErrorLocked(io.EOF) break } switch data[0] { case alertLevelWarning: // drop on the floor c.in.freeBlock(b) goto Again case alertLevelError: c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])}) default: c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) } case recordTypeChangeCipherSpec: if typ != want || len(data) != 1 || data[0] != 1 { c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) break } err := c.in.changeCipherSpec() if err != nil { c.in.setErrorLocked(c.sendAlert(err.(alert))) } case recordTypeApplicationData: if typ != want { c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) break } c.input = b b = nil case recordTypeHandshake: // TODO(rsc): Should at least pick off connection close. if typ != want { return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation)) } c.hand.Write(data) } if b != nil { c.in.freeBlock(b) } return c.in.err } // sendAlert sends a TLS alert message. // c.out.Mutex <= L. func (c *Conn) sendAlertLocked(err alert) error { switch err { case alertNoRenegotiation, alertCloseNotify: c.tmp[0] = alertLevelWarning default: c.tmp[0] = alertLevelError } c.tmp[1] = byte(err) c.writeRecord(recordTypeAlert, c.tmp[0:2]) // closeNotify is a special case in that it isn't an error: if err != alertCloseNotify { return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) } return nil } // sendAlert sends a TLS alert message. // L < c.out.Mutex. func (c *Conn) sendAlert(err alert) error { c.out.Lock() defer c.out.Unlock() return c.sendAlertLocked(err) } // writeRecord writes a TLS record with the given type and payload // to the connection and updates the record layer state. // c.out.Mutex <= L. func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) { b := c.out.newBlock() for len(data) > 0 { m := len(data) if m > maxPlaintext { m = maxPlaintext } explicitIVLen := 0 explicitIVIsSeq := false var cbc cbcMode if c.out.version >= VersionTLS11 { var ok bool if cbc, ok = c.out.cipher.(cbcMode); ok { explicitIVLen = cbc.BlockSize() } } if explicitIVLen == 0 { if _, ok := c.out.cipher.(cipher.AEAD); ok { explicitIVLen = 8 // The AES-GCM construction in TLS has an // explicit nonce so that the nonce can be // random. However, the nonce is only 8 bytes // which is too small for a secure, random // nonce. Therefore we use the sequence number // as the nonce. explicitIVIsSeq = true } } b.resize(recordHeaderLen + explicitIVLen + m) b.data[0] = byte(typ) vers := c.vers if vers == 0 { // Some TLS servers fail if the record version is // greater than TLS 1.0 for the initial ClientHello. vers = VersionTLS10 } b.data[1] = byte(vers >> 8) b.data[2] = byte(vers) b.data[3] = byte(m >> 8) b.data[4] = byte(m) if explicitIVLen > 0 { explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] if explicitIVIsSeq { copy(explicitIV, c.out.seq[:]) } else { if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil { break } } } copy(b.data[recordHeaderLen+explicitIVLen:], data) c.out.encrypt(b, explicitIVLen) _, err = c.conn.Write(b.data) if err != nil { break } n += m data = data[m:] } c.out.freeBlock(b) if typ == recordTypeChangeCipherSpec { err = c.out.changeCipherSpec() if err != nil { // Cannot call sendAlert directly, // because we already hold c.out.Mutex. c.tmp[0] = alertLevelError c.tmp[1] = byte(err.(alert)) c.writeRecord(recordTypeAlert, c.tmp[0:2]) return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) } } return } // readHandshake reads the next handshake message from // the record layer. // c.in.Mutex < L; c.out.Mutex < L. func (c *Conn) readHandshake() (interface{}, error) { for c.hand.Len() < 4 { if err := c.in.err; err != nil { return nil, err } if err := c.readRecord(recordTypeHandshake); err != nil { return nil, err } } data := c.hand.Bytes() n := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) if n > maxHandshake { return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError)) } for c.hand.Len() < 4+n { if err := c.in.err; err != nil { return nil, err } if err := c.readRecord(recordTypeHandshake); err != nil { return nil, err } } data = c.hand.Next(4 + n) var m handshakeMessage switch data[0] { case typeClientHello: m = new(clientHelloMsg) case typeServerHello: m = new(serverHelloMsg) case typeNewSessionTicket: m = new(newSessionTicketMsg) case typeCertificate: m = new(certificateMsg) case typeCertificateRequest: m = &certificateRequestMsg{ hasSignatureAndHash: c.vers >= VersionTLS12, } case typeCertificateStatus: m = new(certificateStatusMsg) case typeServerKeyExchange: m = new(serverKeyExchangeMsg) case typeServerHelloDone: m = new(serverHelloDoneMsg) case typeClientKeyExchange: m = new(clientKeyExchangeMsg) case typeCertificateVerify: m = &certificateVerifyMsg{ hasSignatureAndHash: c.vers >= VersionTLS12, } case typeNextProtocol: m = new(nextProtoMsg) case typeFinished: m = new(finishedMsg) default: return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) } // The handshake message unmarshallers // expect to be able to keep references to data, // so pass in a fresh copy that won't be overwritten. data = append([]byte(nil), data...) if !m.unmarshal(data) { return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) } return m, nil } var errClosed = errors.New("crypto/tls: use of closed connection") // Write writes data to the connection. func (c *Conn) Write(b []byte) (int, error) { // interlock with Close below for { x := atomic.LoadInt32(&c.activeCall) if x&1 != 0 { return 0, errClosed } if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) { defer atomic.AddInt32(&c.activeCall, -2) break } } if err := c.Handshake(); err != nil { return 0, err } c.out.Lock() defer c.out.Unlock() if err := c.out.err; err != nil { return 0, err } if !c.handshakeComplete { return 0, alertInternalError } // SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext // attack when using block mode ciphers due to predictable IVs. // This can be prevented by splitting each Application Data // record into two records, effectively randomizing the IV. // // http://www.openssl.org/~bodo/tls-cbc.txt // https://bugzilla.mozilla.org/show_bug.cgi?id=665814 // http://www.imperialviolet.org/2012/01/15/beastfollowup.html var m int if len(b) > 1 && c.vers <= VersionTLS10 { if _, ok := c.out.cipher.(cipher.BlockMode); ok { n, err := c.writeRecord(recordTypeApplicationData, b[:1]) if err != nil { return n, c.out.setErrorLocked(err) } m, b = 1, b[1:] } } n, err := c.writeRecord(recordTypeApplicationData, b) return n + m, c.out.setErrorLocked(err) } // Read can be made to time out and return a net.Error with Timeout() == true // after a fixed time limit; see SetDeadline and SetReadDeadline. func (c *Conn) Read(b []byte) (n int, err error) { if err = c.Handshake(); err != nil { return } if len(b) == 0 { // Put this after Handshake, in case people were calling // Read(nil) for the side effect of the Handshake. return } c.in.Lock() defer c.in.Unlock() // Some OpenSSL servers send empty records in order to randomize the // CBC IV. So this loop ignores a limited number of empty records. const maxConsecutiveEmptyRecords = 100 for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ { for c.input == nil && c.in.err == nil { if err := c.readRecord(recordTypeApplicationData); err != nil { // Soft error, like EAGAIN return 0, err } } if err := c.in.err; err != nil { return 0, err } n, err = c.input.Read(b) if c.input.off >= len(c.input.data) { c.in.freeBlock(c.input) c.input = nil } // If a close-notify alert is waiting, read it so that // we can return (n, EOF) instead of (n, nil), to signal // to the HTTP response reading goroutine that the // connection is now closed. This eliminates a race // where the HTTP response reading goroutine would // otherwise not observe the EOF until its next read, // by which time a client goroutine might have already // tried to reuse the HTTP connection for a new // request. // See https://codereview.appspot.com/76400046 // and https://golang.org/issue/3514 if ri := c.rawInput; ri != nil && n != 0 && err == nil && c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert { if recErr := c.readRecord(recordTypeApplicationData); recErr != nil { err = recErr // will be io.EOF on closeNotify } } if n != 0 || err != nil { return n, err } } return 0, io.ErrNoProgress } // Close closes the connection. func (c *Conn) Close() error { // Interlock with Conn.Write above. var x int32 for { x = atomic.LoadInt32(&c.activeCall) if x&1 != 0 { return errClosed } if atomic.CompareAndSwapInt32(&c.activeCall, x, x|1) { break } } if x != 0 { // io.Writer and io.Closer should not be used concurrently. // If Close is called while a Write is currently in-flight, // interpret that as a sign that this Close is really just // being used to break the Write and/or clean up resources and // avoid sending the alertCloseNotify, which may block // waiting on handshakeMutex or the c.out mutex. return c.conn.Close() } var alertErr error c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() if c.handshakeComplete { alertErr = c.sendAlert(alertCloseNotify) } if err := c.conn.Close(); err != nil { return err } return alertErr } // Handshake runs the client or server handshake // protocol if it has not yet been run. // Most uses of this package need not call Handshake // explicitly: the first Read or Write will call it automatically. func (c *Conn) Handshake() error { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() if err := c.handshakeErr; err != nil { return err } if c.handshakeComplete { return nil } if c.isClient { c.handshakeErr = c.clientHandshake() } else { c.handshakeErr = c.serverHandshake() } return c.handshakeErr } // ConnectionState returns basic TLS details about the connection. func (c *Conn) ConnectionState() ConnectionState { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() var state ConnectionState state.HandshakeComplete = c.handshakeComplete if c.handshakeComplete { state.Version = c.vers state.NegotiatedProtocol = c.clientProtocol state.DidResume = c.didResume state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback state.CipherSuite = c.cipherSuite state.PeerCertificates = c.peerCertificates state.VerifiedChains = c.verifiedChains state.ServerName = c.serverName state.SignedCertificateTimestamps = c.scts state.OCSPResponse = c.ocspResponse if !c.didResume { state.TLSUnique = c.firstFinished[:] } } return state } // OCSPResponse returns the stapled OCSP response from the TLS server, if // any. (Only valid for client connections.) func (c *Conn) OCSPResponse() []byte { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() return c.ocspResponse } // VerifyHostname checks that the peer certificate chain is valid for // connecting to host. If so, it returns nil; if not, it returns an error // describing the problem. func (c *Conn) VerifyHostname(host string) error { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() if !c.isClient { return errors.New("tls: VerifyHostname called on TLS server connection") } if !c.handshakeComplete { return errors.New("tls: handshake has not yet been performed") } if len(c.verifiedChains) == 0 { return errors.New("tls: handshake did not verify certificate chain") } return c.peerCertificates[0].VerifyHostname(host) } ================================================ FILE: scan/crypto/tls/conn_test.go ================================================ // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "testing" ) func TestRoundUp(t *testing.T) { if roundUp(0, 16) != 0 || roundUp(1, 16) != 16 || roundUp(15, 16) != 16 || roundUp(16, 16) != 16 || roundUp(17, 16) != 32 { t.Error("roundUp broken") } } var paddingTests = []struct { in []byte good bool expectedLen int }{ {[]byte{1, 2, 3, 4, 0}, true, 4}, {[]byte{1, 2, 3, 4, 0, 1}, false, 0}, {[]byte{1, 2, 3, 4, 99, 99}, false, 0}, {[]byte{1, 2, 3, 4, 1, 1}, true, 4}, {[]byte{1, 2, 3, 2, 2, 2}, true, 3}, {[]byte{1, 2, 3, 3, 3, 3}, true, 2}, {[]byte{1, 2, 3, 4, 3, 3}, false, 0}, {[]byte{1, 4, 4, 4, 4, 4}, true, 1}, {[]byte{5, 5, 5, 5, 5, 5}, true, 0}, {[]byte{6, 6, 6, 6, 6, 6}, false, 0}, } func TestRemovePadding(t *testing.T) { for i, test := range paddingTests { payload, good := removePadding(test.in) expectedGood := byte(255) if !test.good { expectedGood = 0 } if good != expectedGood { t.Errorf("#%d: wrong validity, want:%d got:%d", i, expectedGood, good) } if good == 255 && len(payload) != test.expectedLen { t.Errorf("#%d: got %d, want %d", i, len(payload), test.expectedLen) } } } var certExampleCom = `308201403081eda003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313138353835325a170d3132303933303138353835325a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31a301830160603551d11040f300d820b6578616d706c652e636f6d300b06092a864886f70d0101050341001a0b419d2c74474c6450654e5f10b32bf426ffdf55cad1c52602e7a9151513a3424c70f5960dcd682db0c33769cc1daa3fcdd3db10809d2392ed4a1bf50ced18` var certWildcardExampleCom = `308201423081efa003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303034365a170d3132303933303139303034365a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31c301a30180603551d110411300f820d2a2e6578616d706c652e636f6d300b06092a864886f70d0101050341001676f0c9e7c33c1b656ed5a6476c4e2ee9ec8e62df7407accb1875272b2edd0a22096cb2c22598d11604104d604f810eb4b5987ca6bb319c7e6ce48725c54059` var certFooExampleCom = `308201443081f1a003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303131345a170d3132303933303139303131345a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31e301c301a0603551d1104133011820f666f6f2e6578616d706c652e636f6d300b06092a864886f70d010105034100646a2a51f2aa2477add854b462cf5207ba16d3213ffb5d3d0eed473fbf09935019192d1d5b8ca6a2407b424cf04d97c4cd9197c83ecf81f0eab9464a1109d09f` var certDoubleWildcardExampleCom = `308201443081f1a003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303134315a170d3132303933303139303134315a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31e301c301a0603551d1104133011820f2a2e2a2e6578616d706c652e636f6d300b06092a864886f70d0101050341001c3de267975f56ef57771c6218ef95ecc65102e57bd1defe6f7efea90d9b26cf40de5bd7ad75e46201c7f2a92aaa3e907451e9409f65e28ddb6db80d726290f6` func TestCertificateSelection(t *testing.T) { config := Config{ Certificates: []Certificate{ { Certificate: [][]byte{fromHex(certExampleCom)}, }, { Certificate: [][]byte{fromHex(certWildcardExampleCom)}, }, { Certificate: [][]byte{fromHex(certFooExampleCom)}, }, { Certificate: [][]byte{fromHex(certDoubleWildcardExampleCom)}, }, }, } config.BuildNameToCertificate() pointerToIndex := func(c *Certificate) int { for i := range config.Certificates { if c == &config.Certificates[i] { return i } } return -1 } certificateForName := func(name string) *Certificate { clientHello := &ClientHelloInfo{ ServerName: name, } if cert, err := config.getCertificate(clientHello); err != nil { t.Errorf("unable to get certificate for name '%s': %s", name, err) return nil } else { return cert } } if n := pointerToIndex(certificateForName("example.com")); n != 0 { t.Errorf("example.com returned certificate %d, not 0", n) } if n := pointerToIndex(certificateForName("bar.example.com")); n != 1 { t.Errorf("bar.example.com returned certificate %d, not 1", n) } if n := pointerToIndex(certificateForName("foo.example.com")); n != 2 { t.Errorf("foo.example.com returned certificate %d, not 2", n) } if n := pointerToIndex(certificateForName("foo.bar.example.com")); n != 3 { t.Errorf("foo.bar.example.com returned certificate %d, not 3", n) } if n := pointerToIndex(certificateForName("foo.bar.baz.example.com")); n != 0 { t.Errorf("foo.bar.baz.example.com returned certificate %d, not 0", n) } } ================================================ FILE: scan/crypto/tls/example_test.go ================================================ // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls_test import ( "crypto/tls" "crypto/x509" ) func ExampleDial() { // Connecting with a custom root-certificate set. const rootPEM = ` -----BEGIN CERTIFICATE----- MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7 qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY /iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/ zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6 yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx -----END CERTIFICATE-----` // First, create the set of root certificates. For this example we only // have one. It's also possible to omit this in order to use the // default root set of the current operating system. roots := x509.NewCertPool() ok := roots.AppendCertsFromPEM([]byte(rootPEM)) if !ok { panic("failed to parse root certificate") } conn, err := tls.Dial("tcp", "mail.google.com:443", &tls.Config{ RootCAs: roots, }) if err != nil { panic("failed to connect: " + err.Error()) } conn.Close() } ================================================ FILE: scan/crypto/tls/generate_cert.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build ignore // +build ignore // Generate a self-signed X.509 certificate for a TLS server. Outputs to // 'cert.pem' and 'key.pem' and will overwrite existing files. package main import ( "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "flag" "fmt" "log" "math/big" "net" "os" "strings" "time" "github.com/cloudflare/cfssl/helpers/derhelpers" ) var ( host = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for") validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011") validFor = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for") isCA = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority") rsaBits = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set") ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521") ) func publicKey(priv interface{}) interface{} { switch k := priv.(type) { case *rsa.PrivateKey: return &k.PublicKey case *ed25519.PrivateKey: return &k.Public() case *ecdsa.PrivateKey: return &k.PublicKey default: return nil } } func pemBlockForKey(priv interface{}) *pem.Block { switch k := priv.(type) { case *rsa.PrivateKey: return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} case *ed25519.PrivateKey: b, err := derhelpers.MarshalEd25519PrivateKey(priv) if err != nil { fmt.Fprintf(os.Stderr, "Unable to marshal ED25519 private key: %v", err) os.Exit(2) } return &pem.Block{Type: "Ed25519 PRIVATE KEY", Bytes: b} case *ecdsa.PrivateKey: b, err := x509.MarshalECPrivateKey(k) if err != nil { fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err) os.Exit(2) } return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} default: return nil } } func main() { flag.Parse() if len(*host) == 0 { log.Fatalf("Missing required --host parameter") } var priv interface{} var err error switch *ecdsaCurve { case "": priv, err = rsa.GenerateKey(rand.Reader, *rsaBits) case "ED25519": _, priv, err = ed25519.GenerateKey(rand.Reader) case "P224": priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) case "P256": priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) case "P384": priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) case "P521": priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) default: fmt.Fprintf(os.Stderr, "Unrecognized elliptic curve: %q", *ecdsaCurve) os.Exit(1) } if err != nil { log.Fatalf("failed to generate private key: %s", err) } var notBefore time.Time if len(*validFrom) == 0 { notBefore = time.Now() } else { notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom) if err != nil { fmt.Fprintf(os.Stderr, "Failed to parse creation date: %s\n", err) os.Exit(1) } } notAfter := notBefore.Add(*validFor) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { log.Fatalf("failed to generate serial number: %s", err) } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"Acme Co"}, }, NotBefore: notBefore, NotAfter: notAfter, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } hosts := strings.Split(*host, ",") for _, h := range hosts { if ip := net.ParseIP(h); ip != nil { template.IPAddresses = append(template.IPAddresses, ip) } else { template.DNSNames = append(template.DNSNames, h) } } if *isCA { template.IsCA = true template.KeyUsage |= x509.KeyUsageCertSign } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) if err != nil { log.Fatalf("Failed to create certificate: %s", err) } certOut, err := os.Create("cert.pem") if err != nil { log.Fatalf("failed to open cert.pem for writing: %s", err) } pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) certOut.Close() log.Print("written cert.pem\n") keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { log.Print("failed to open key.pem for writing:", err) return } pem.Encode(keyOut, pemBlockForKey(priv)) keyOut.Close() log.Print("written key.pem\n") } ================================================ FILE: scan/crypto/tls/handshake_client.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "bytes" "crypto" "crypto/ecdsa" "crypto/rsa" "crypto/subtle" "crypto/x509" "errors" "fmt" "io" "net" "strconv" ) type clientHandshakeState struct { c *Conn serverHello *serverHelloMsg hello *clientHelloMsg suite *cipherSuite finishedHash finishedHash masterSecret []byte session *ClientSessionState } func (c *Conn) clientHandshake() error { if c.config == nil { c.config = defaultConfig() } if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify { return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") } nextProtosLength := 0 for _, proto := range c.config.NextProtos { if l := len(proto); l == 0 || l > 255 { return errors.New("tls: invalid NextProtos value") } else { nextProtosLength += 1 + l } } if nextProtosLength > 0xffff { return errors.New("tls: NextProtos values too large") } sni := c.config.ServerName // IP address literals are not permitted as SNI values. See // https://tools.ietf.org/html/rfc6066#section-3. if net.ParseIP(sni) != nil { sni = "" } hello := &clientHelloMsg{ vers: c.config.maxVersion(), compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), ocspStapling: true, scts: true, serverName: sni, supportedCurves: c.config.curvePreferences(), supportedPoints: []uint8{pointFormatUncompressed}, nextProtoNeg: len(c.config.NextProtos) > 0, secureRenegotiation: true, alpnProtocols: c.config.NextProtos, } possibleCipherSuites := c.config.cipherSuites() hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites)) NextCipherSuite: for _, suiteId := range possibleCipherSuites { for _, suite := range cipherSuites { if suite.id != suiteId { continue } // Don't advertise TLS 1.2-only cipher suites unless // we're attempting TLS 1.2. if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 { continue } hello.cipherSuites = append(hello.cipherSuites, suiteId) continue NextCipherSuite } } _, err := io.ReadFull(c.config.rand(), hello.random) if err != nil { c.sendAlert(alertInternalError) return errors.New("tls: short read from Rand: " + err.Error()) } if hello.vers >= VersionTLS12 { hello.signatureAndHashes = supportedSignatureAlgorithms } var session *ClientSessionState var cacheKey string sessionCache := c.config.ClientSessionCache if c.config.SessionTicketsDisabled { sessionCache = nil } if sessionCache != nil { hello.ticketSupported = true // Try to resume a previously negotiated TLS session, if // available. cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config) candidateSession, ok := sessionCache.Get(cacheKey) if ok { // Check that the ciphersuite/version used for the // previous session are still valid. cipherSuiteOk := false for _, id := range hello.cipherSuites { if id == candidateSession.cipherSuite { cipherSuiteOk = true break } } versOk := candidateSession.vers >= c.config.minVersion() && candidateSession.vers <= c.config.maxVersion() if versOk && cipherSuiteOk { session = candidateSession } } } if session != nil { hello.sessionTicket = session.sessionTicket // A random session ID is used to detect when the // server accepted the ticket and is resuming a session // (see RFC 5077). hello.sessionId = make([]byte, 16) if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil { c.sendAlert(alertInternalError) return errors.New("tls: short read from Rand: " + err.Error()) } } c.writeRecord(recordTypeHandshake, hello.marshal()) msg, err := c.readHandshake() if err != nil { return err } serverHello, ok := msg.(*serverHelloMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(serverHello, msg) } vers, ok := c.config.mutualVersion(serverHello.vers) if !ok || vers < VersionTLS10 { // TLS 1.0 is the minimum version supported as a client. c.sendAlert(alertProtocolVersion) return fmt.Errorf("tls: server selected unsupported protocol version %x", serverHello.vers) } c.vers = vers c.haveVers = true suite := mutualCipherSuite(hello.cipherSuites, serverHello.cipherSuite) if suite == nil { c.sendAlert(alertHandshakeFailure) return errors.New("tls: server chose an unconfigured cipher suite") } hs := &clientHandshakeState{ c: c, serverHello: serverHello, hello: hello, suite: suite, finishedHash: newFinishedHash(c.vers, suite), session: session, } isResume, err := hs.processServerHello() if err != nil { return err } // No signatures of the handshake are needed in a resumption. // Otherwise, in a full handshake, if we don't have any certificates // configured then we will never send a CertificateVerify message and // thus no signatures are needed in that case either. if isResume || len(c.config.Certificates) == 0 { hs.finishedHash.discardHandshakeBuffer() } hs.finishedHash.Write(hs.hello.marshal()) hs.finishedHash.Write(hs.serverHello.marshal()) if isResume { if err := hs.establishKeys(); err != nil { return err } if err := hs.readSessionTicket(); err != nil { return err } if err := hs.readFinished(c.firstFinished[:]); err != nil { return err } if err := hs.sendFinished(nil); err != nil { return err } } else { if err := hs.doFullHandshake(); err != nil { return err } if err := hs.establishKeys(); err != nil { return err } if err := hs.sendFinished(c.firstFinished[:]); err != nil { return err } if err := hs.readSessionTicket(); err != nil { return err } if err := hs.readFinished(nil); err != nil { return err } } if sessionCache != nil && hs.session != nil && session != hs.session { sessionCache.Put(cacheKey, hs.session) } c.didResume = isResume c.handshakeComplete = true c.cipherSuite = suite.id return nil } func (hs *clientHandshakeState) doFullHandshake() error { c := hs.c msg, err := c.readHandshake() if err != nil { return err } certMsg, ok := msg.(*certificateMsg) if !ok || len(certMsg.certificates) == 0 { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(certMsg, msg) } hs.finishedHash.Write(certMsg.marshal()) certs := make([]*x509.Certificate, len(certMsg.certificates)) for i, asn1Data := range certMsg.certificates { cert, err := x509.ParseCertificate(asn1Data) if err != nil { c.sendAlert(alertBadCertificate) return errors.New("tls: failed to parse certificate from server: " + err.Error()) } certs[i] = cert } if !c.config.InsecureSkipVerify { opts := x509.VerifyOptions{ Roots: c.config.RootCAs, CurrentTime: c.config.time(), DNSName: c.config.ServerName, Intermediates: x509.NewCertPool(), } for i, cert := range certs { if i == 0 { continue } opts.Intermediates.AddCert(cert) } c.verifiedChains, err = certs[0].Verify(opts) if err != nil { c.sendAlert(alertBadCertificate) return err } } switch certs[0].PublicKey.(type) { case *rsa.PublicKey, *ecdsa.PublicKey: break default: c.sendAlert(alertUnsupportedCertificate) return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey) } c.peerCertificates = certs if hs.serverHello.ocspStapling { msg, err = c.readHandshake() if err != nil { return err } cs, ok := msg.(*certificateStatusMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(cs, msg) } hs.finishedHash.Write(cs.marshal()) if cs.statusType == statusTypeOCSP { c.ocspResponse = cs.response } } msg, err = c.readHandshake() if err != nil { return err } keyAgreement := hs.suite.ka(c.vers) skx, ok := msg.(*serverKeyExchangeMsg) if ok { hs.finishedHash.Write(skx.marshal()) err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx) if err != nil { c.sendAlert(alertUnexpectedMessage) return err } msg, err = c.readHandshake() if err != nil { return err } } var chainToSend *Certificate var certRequested bool certReq, ok := msg.(*certificateRequestMsg) if ok { certRequested = true // RFC 4346 on the certificateAuthorities field: // A list of the distinguished names of acceptable certificate // authorities. These distinguished names may specify a desired // distinguished name for a root CA or for a subordinate CA; // thus, this message can be used to describe both known roots // and a desired authorization space. If the // certificate_authorities list is empty then the client MAY // send any certificate of the appropriate // ClientCertificateType, unless there is some external // arrangement to the contrary. hs.finishedHash.Write(certReq.marshal()) var rsaAvail, ecdsaAvail bool for _, certType := range certReq.certificateTypes { switch certType { case certTypeRSASign: rsaAvail = true case certTypeECDSASign: ecdsaAvail = true } } // We need to search our list of client certs for one // where SignatureAlgorithm is acceptable to the server and the // Issuer is in certReq.certificateAuthorities findCert: for i, chain := range c.config.Certificates { if !rsaAvail && !ecdsaAvail { continue } for j, cert := range chain.Certificate { x509Cert := chain.Leaf // parse the certificate if this isn't the leaf // node, or if chain.Leaf was nil if j != 0 || x509Cert == nil { if x509Cert, err = x509.ParseCertificate(cert); err != nil { c.sendAlert(alertInternalError) return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error()) } } switch { case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA: case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA: default: continue findCert } if len(certReq.certificateAuthorities) == 0 { // they gave us an empty list, so just take the // first cert from c.config.Certificates chainToSend = &chain break findCert } for _, ca := range certReq.certificateAuthorities { if bytes.Equal(x509Cert.RawIssuer, ca) { chainToSend = &chain break findCert } } } } msg, err = c.readHandshake() if err != nil { return err } } shd, ok := msg.(*serverHelloDoneMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(shd, msg) } hs.finishedHash.Write(shd.marshal()) // If the server requested a certificate then we have to send a // Certificate message, even if it's empty because we don't have a // certificate to send. if certRequested { certMsg = new(certificateMsg) if chainToSend != nil { certMsg.certificates = chainToSend.Certificate } hs.finishedHash.Write(certMsg.marshal()) c.writeRecord(recordTypeHandshake, certMsg.marshal()) } preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0]) if err != nil { c.sendAlert(alertInternalError) return err } if ckx != nil { hs.finishedHash.Write(ckx.marshal()) c.writeRecord(recordTypeHandshake, ckx.marshal()) } if chainToSend != nil { certVerify := &certificateVerifyMsg{ hasSignatureAndHash: c.vers >= VersionTLS12, } key, ok := chainToSend.PrivateKey.(crypto.Signer) if !ok { c.sendAlert(alertInternalError) return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey) } var signatureType uint8 switch key.Public().(type) { case *ecdsa.PublicKey: signatureType = signatureECDSA case *rsa.PublicKey: signatureType = signatureRSA default: c.sendAlert(alertInternalError) return fmt.Errorf("tls: failed to sign handshake with client certificate: unknown client certificate key type: %T", key) } certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureType) if err != nil { c.sendAlert(alertInternalError) return err } digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret) if err != nil { c.sendAlert(alertInternalError) return err } certVerify.signature, err = key.Sign(c.config.rand(), digest, hashFunc) if err != nil { c.sendAlert(alertInternalError) return err } hs.finishedHash.Write(certVerify.marshal()) c.writeRecord(recordTypeHandshake, certVerify.marshal()) } hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random) hs.finishedHash.discardHandshakeBuffer() return nil } func (hs *clientHandshakeState) establishKeys() error { c := hs.c clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) var clientCipher, serverCipher interface{} var clientHash, serverHash macFunction if hs.suite.cipher != nil { clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */) clientHash = hs.suite.mac(c.vers, clientMAC) serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */) serverHash = hs.suite.mac(c.vers, serverMAC) } else { clientCipher = hs.suite.aead(clientKey, clientIV) serverCipher = hs.suite.aead(serverKey, serverIV) } c.in.prepareCipherSpec(c.vers, serverCipher, serverHash) c.out.prepareCipherSpec(c.vers, clientCipher, clientHash) return nil } func (hs *clientHandshakeState) serverResumedSession() bool { // If the server responded with the same sessionId then it means the // sessionTicket is being used to resume a TLS session. return hs.session != nil && hs.hello.sessionId != nil && bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId) } func (hs *clientHandshakeState) processServerHello() (bool, error) { c := hs.c if hs.serverHello.compressionMethod != compressionNone { c.sendAlert(alertUnexpectedMessage) return false, errors.New("tls: server selected unsupported compression format") } clientDidNPN := hs.hello.nextProtoNeg clientDidALPN := len(hs.hello.alpnProtocols) > 0 serverHasNPN := hs.serverHello.nextProtoNeg serverHasALPN := len(hs.serverHello.alpnProtocol) > 0 if !clientDidNPN && serverHasNPN { c.sendAlert(alertHandshakeFailure) return false, errors.New("server advertised unrequested NPN extension") } if !clientDidALPN && serverHasALPN { c.sendAlert(alertHandshakeFailure) return false, errors.New("server advertised unrequested ALPN extension") } if serverHasNPN && serverHasALPN { c.sendAlert(alertHandshakeFailure) return false, errors.New("server advertised both NPN and ALPN extensions") } if serverHasALPN { c.clientProtocol = hs.serverHello.alpnProtocol c.clientProtocolFallback = false } c.scts = hs.serverHello.scts if hs.serverResumedSession() { // Restore masterSecret and peerCerts from previous state hs.masterSecret = hs.session.masterSecret c.peerCertificates = hs.session.serverCertificates c.verifiedChains = hs.session.verifiedChains return true, nil } return false, nil } func (hs *clientHandshakeState) readFinished(out []byte) error { c := hs.c c.readRecord(recordTypeChangeCipherSpec) if err := c.in.error(); err != nil { return err } msg, err := c.readHandshake() if err != nil { return err } serverFinished, ok := msg.(*finishedMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(serverFinished, msg) } verify := hs.finishedHash.serverSum(hs.masterSecret) if len(verify) != len(serverFinished.verifyData) || subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 { c.sendAlert(alertHandshakeFailure) return errors.New("tls: server's Finished message was incorrect") } hs.finishedHash.Write(serverFinished.marshal()) copy(out, verify) return nil } func (hs *clientHandshakeState) readSessionTicket() error { if !hs.serverHello.ticketSupported { return nil } c := hs.c msg, err := c.readHandshake() if err != nil { return err } sessionTicketMsg, ok := msg.(*newSessionTicketMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(sessionTicketMsg, msg) } hs.finishedHash.Write(sessionTicketMsg.marshal()) hs.session = &ClientSessionState{ sessionTicket: sessionTicketMsg.ticket, vers: c.vers, cipherSuite: hs.suite.id, masterSecret: hs.masterSecret, serverCertificates: c.peerCertificates, verifiedChains: c.verifiedChains, } return nil } func (hs *clientHandshakeState) sendFinished(out []byte) error { c := hs.c c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) if hs.serverHello.nextProtoNeg { nextProto := new(nextProtoMsg) proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos) nextProto.proto = proto c.clientProtocol = proto c.clientProtocolFallback = fallback hs.finishedHash.Write(nextProto.marshal()) c.writeRecord(recordTypeHandshake, nextProto.marshal()) } finished := new(finishedMsg) finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret) hs.finishedHash.Write(finished.marshal()) c.writeRecord(recordTypeHandshake, finished.marshal()) copy(out, finished.verifyData) return nil } // clientSessionCacheKey returns a key used to cache sessionTickets that could // be used to resume previously negotiated TLS sessions with a server. func clientSessionCacheKey(serverAddr net.Addr, config *Config) string { if len(config.ServerName) > 0 { return config.ServerName } return serverAddr.String() } // mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol // given list of possible protocols and a list of the preference order. The // first list must not be empty. It returns the resulting protocol and flag // indicating if the fallback case was reached. func mutualProtocol(protos, preferenceProtos []string) (string, bool) { for _, s := range preferenceProtos { for _, c := range protos { if s == c { return s, false } } } return protos[0], true } ================================================ FILE: scan/crypto/tls/handshake_client_test.go ================================================ // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "bytes" "crypto/ecdsa" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/binary" "encoding/pem" "fmt" "io" "net" "os" "os/exec" "path/filepath" "strconv" "strings" "testing" "time" ) // Note: see comment in handshake_test.go for details of how the reference // tests work. // blockingSource is an io.Reader that blocks a Read call until it's closed. type blockingSource chan bool func (b blockingSource) Read([]byte) (n int, err error) { <-b return 0, io.EOF } // clientTest represents a test of the TLS client handshake against a reference // implementation. type clientTest struct { // name is a freeform string identifying the test and the file in which // the expected results will be stored. name string // command, if not empty, contains a series of arguments for the // command to run for the reference server. command []string // config, if not nil, contains a custom Config to use for this test. config *Config // cert, if not empty, contains a DER-encoded certificate for the // reference server. cert []byte // key, if not nil, contains either a *rsa.PrivateKey or // *ecdsa.PrivateKey which is the private key for the reference server. key interface{} // extensions, if not nil, contains a list of extension data to be returned // from the ServerHello. The data should be in standard TLS format with // a 2-byte uint16 type, 2-byte data length, followed by the extension data. extensions [][]byte // validate, if not nil, is a function that will be called with the // ConnectionState of the resulting connection. It returns a non-nil // error if the ConnectionState is unacceptable. validate func(ConnectionState) error } var defaultServerCommand = []string{"openssl", "s_server"} // connFromCommand starts the reference server process, connects to it and // returns a recordingConn for the connection. The stdin return value is a // blockingSource for the stdin of the child process. It must be closed before // Waiting for child. func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, stdin blockingSource, err error) { cert := testRSACertificate if len(test.cert) > 0 { cert = test.cert } certPath := tempFile(string(cert)) defer os.Remove(certPath) var key interface{} = testRSAPrivateKey if test.key != nil { key = test.key } var pemType string var derBytes []byte switch key := key.(type) { case *rsa.PrivateKey: pemType = "RSA" derBytes = x509.MarshalPKCS1PrivateKey(key) case *ecdsa.PrivateKey: pemType = "EC" var err error derBytes, err = x509.MarshalECPrivateKey(key) if err != nil { panic(err) } default: panic("unknown key type") } var pemOut bytes.Buffer pem.Encode(&pemOut, &pem.Block{Type: pemType + " PRIVATE KEY", Bytes: derBytes}) keyPath := tempFile(string(pemOut.Bytes())) defer os.Remove(keyPath) var command []string if len(test.command) > 0 { command = append(command, test.command...) } else { command = append(command, defaultServerCommand...) } command = append(command, "-cert", certPath, "-certform", "DER", "-key", keyPath) // serverPort contains the port that OpenSSL will listen on. OpenSSL // can't take "0" as an argument here so we have to pick a number and // hope that it's not in use on the machine. Since this only occurs // when -update is given and thus when there's a human watching the // test, this isn't too bad. const serverPort = 24323 command = append(command, "-accept", strconv.Itoa(serverPort)) if len(test.extensions) > 0 { var serverInfo bytes.Buffer for _, ext := range test.extensions { pem.Encode(&serverInfo, &pem.Block{ Type: fmt.Sprintf("SERVERINFO FOR EXTENSION %d", binary.BigEndian.Uint16(ext)), Bytes: ext, }) } serverInfoPath := tempFile(serverInfo.String()) defer os.Remove(serverInfoPath) command = append(command, "-serverinfo", serverInfoPath) } cmd := exec.Command(command[0], command[1:]...) stdin = blockingSource(make(chan bool)) cmd.Stdin = stdin var out bytes.Buffer cmd.Stdout = &out cmd.Stderr = &out if err := cmd.Start(); err != nil { return nil, nil, nil, err } // OpenSSL does print an "ACCEPT" banner, but it does so *before* // opening the listening socket, so we can't use that to wait until it // has started listening. Thus we are forced to poll until we get a // connection. var tcpConn net.Conn for i := uint(0); i < 5; i++ { tcpConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{ IP: net.IPv4(127, 0, 0, 1), Port: serverPort, }) if err == nil { break } time.Sleep((1 << i) * 5 * time.Millisecond) } if err != nil { close(stdin) out.WriteTo(os.Stdout) cmd.Process.Kill() return nil, nil, nil, cmd.Wait() } record := &recordingConn{ Conn: tcpConn, } return record, cmd, stdin, nil } func (test *clientTest) dataPath() string { return filepath.Join("testdata", "Client-"+test.name) } func (test *clientTest) loadData() (flows [][]byte, err error) { in, err := os.Open(test.dataPath()) if err != nil { return nil, err } defer in.Close() return parseTestData(in) } func (test *clientTest) run(t *testing.T, write bool) { var clientConn, serverConn net.Conn var recordingConn *recordingConn var childProcess *exec.Cmd var stdin blockingSource if write { var err error recordingConn, childProcess, stdin, err = test.connFromCommand() if err != nil { t.Fatalf("Failed to start subcommand: %s", err) } clientConn = recordingConn } else { clientConn, serverConn = net.Pipe() } config := test.config if config == nil { config = testConfig } client := Client(clientConn, config) doneChan := make(chan bool) go func() { if _, err := client.Write([]byte("hello\n")); err != nil { t.Errorf("Client.Write failed: %s", err) } if test.validate != nil { if err := test.validate(client.ConnectionState()); err != nil { t.Errorf("validate callback returned error: %s", err) } } client.Close() clientConn.Close() doneChan <- true }() if !write { flows, err := test.loadData() if err != nil { t.Fatalf("%s: failed to load data from %s: %v", test.name, test.dataPath(), err) } for i, b := range flows { if i%2 == 1 { serverConn.Write(b) continue } bb := make([]byte, len(b)) _, err := io.ReadFull(serverConn, bb) if err != nil { t.Fatalf("%s #%d: %s", test.name, i, err) } if !bytes.Equal(b, bb) { t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i, bb, b) } } serverConn.Close() } <-doneChan if write { path := test.dataPath() out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { t.Fatalf("Failed to create output file: %s", err) } defer out.Close() recordingConn.Close() close(stdin) childProcess.Process.Kill() childProcess.Wait() if len(recordingConn.flows) < 3 { childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout) t.Fatalf("Client connection didn't work") } recordingConn.WriteTo(out) fmt.Printf("Wrote %s\n", path) } } func runClientTestForVersion(t *testing.T, template *clientTest, prefix, option string) { test := *template test.name = prefix + test.name if len(test.command) == 0 { test.command = defaultClientCommand } test.command = append([]string(nil), test.command...) test.command = append(test.command, option) test.run(t, *update) } func runClientTestTLS10(t *testing.T, template *clientTest) { runClientTestForVersion(t, template, "TLSv10-", "-tls1") } func runClientTestTLS11(t *testing.T, template *clientTest) { runClientTestForVersion(t, template, "TLSv11-", "-tls1_1") } func runClientTestTLS12(t *testing.T, template *clientTest) { runClientTestForVersion(t, template, "TLSv12-", "-tls1_2") } func TestHandshakeClientRSARC4(t *testing.T) { test := &clientTest{ name: "RSA-RC4", command: []string{"openssl", "s_server", "-cipher", "RC4-SHA"}, } runClientTestTLS10(t, test) runClientTestTLS11(t, test) runClientTestTLS12(t, test) } func TestHandshakeClientRSAAES128GCM(t *testing.T) { test := &clientTest{ name: "AES128-GCM-SHA256", command: []string{"openssl", "s_server", "-cipher", "AES128-GCM-SHA256"}, } runClientTestTLS12(t, test) } func TestHandshakeClientRSAAES256GCM(t *testing.T) { test := &clientTest{ name: "AES256-GCM-SHA384", command: []string{"openssl", "s_server", "-cipher", "AES256-GCM-SHA384"}, } runClientTestTLS12(t, test) } func TestHandshakeClientECDHERSAAES(t *testing.T) { test := &clientTest{ name: "ECDHE-RSA-AES", command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES128-SHA"}, } runClientTestTLS10(t, test) runClientTestTLS11(t, test) runClientTestTLS12(t, test) } func TestHandshakeClientECDHEECDSAAES(t *testing.T) { test := &clientTest{ name: "ECDHE-ECDSA-AES", command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA"}, cert: testECDSACertificate, key: testECDSAPrivateKey, } runClientTestTLS10(t, test) runClientTestTLS11(t, test) runClientTestTLS12(t, test) } func TestHandshakeClientECDHEECDSAAESGCM(t *testing.T) { test := &clientTest{ name: "ECDHE-ECDSA-AES-GCM", command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-GCM-SHA256"}, cert: testECDSACertificate, key: testECDSAPrivateKey, } runClientTestTLS12(t, test) } func TestHandshakeClientAES256GCMSHA384(t *testing.T) { test := &clientTest{ name: "ECDHE-ECDSA-AES256-GCM-SHA384", command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES256-GCM-SHA384"}, cert: testECDSACertificate, key: testECDSAPrivateKey, } runClientTestTLS12(t, test) } func TestHandshakeClientCertRSA(t *testing.T) { config := *testConfig cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM)) config.Certificates = []Certificate{cert} test := &clientTest{ name: "ClientCert-RSA-RSA", command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"}, config: &config, } runClientTestTLS10(t, test) runClientTestTLS12(t, test) test = &clientTest{ name: "ClientCert-RSA-ECDSA", command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"}, config: &config, cert: testECDSACertificate, key: testECDSAPrivateKey, } runClientTestTLS10(t, test) runClientTestTLS12(t, test) test = &clientTest{ name: "ClientCert-RSA-AES256-GCM-SHA384", command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384", "-verify", "1"}, config: &config, cert: testRSACertificate, key: testRSAPrivateKey, } runClientTestTLS12(t, test) } func TestHandshakeClientCertECDSA(t *testing.T) { config := *testConfig cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM)) config.Certificates = []Certificate{cert} test := &clientTest{ name: "ClientCert-ECDSA-RSA", command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"}, config: &config, } runClientTestTLS10(t, test) runClientTestTLS12(t, test) test = &clientTest{ name: "ClientCert-ECDSA-ECDSA", command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"}, config: &config, cert: testECDSACertificate, key: testECDSAPrivateKey, } runClientTestTLS10(t, test) runClientTestTLS12(t, test) } func TestClientResumption(t *testing.T) { serverConfig := &Config{ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, Certificates: testConfig.Certificates, } issuer, err := x509.ParseCertificate(testRSACertificateIssuer) if err != nil { panic(err) } rootCAs := x509.NewCertPool() rootCAs.AddCert(issuer) clientConfig := &Config{ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, ClientSessionCache: NewLRUClientSessionCache(32), RootCAs: rootCAs, ServerName: "example.golang", } testResumeState := func(test string, didResume bool) { _, hs, err := testHandshake(clientConfig, serverConfig) if err != nil { t.Fatalf("%s: handshake failed: %s", test, err) } if hs.DidResume != didResume { t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume) } if didResume && (hs.PeerCertificates == nil || hs.VerifiedChains == nil) { t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains) } } getTicket := func() []byte { return clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).state.sessionTicket } randomKey := func() [32]byte { var k [32]byte if _, err := io.ReadFull(serverConfig.rand(), k[:]); err != nil { t.Fatalf("Failed to read new SessionTicketKey: %s", err) } return k } testResumeState("Handshake", false) ticket := getTicket() testResumeState("Resume", true) if !bytes.Equal(ticket, getTicket()) { t.Fatal("first ticket doesn't match ticket after resumption") } key2 := randomKey() serverConfig.SetSessionTicketKeys([][32]byte{key2}) testResumeState("InvalidSessionTicketKey", false) testResumeState("ResumeAfterInvalidSessionTicketKey", true) serverConfig.SetSessionTicketKeys([][32]byte{randomKey(), key2}) ticket = getTicket() testResumeState("KeyChange", true) if bytes.Equal(ticket, getTicket()) { t.Fatal("new ticket wasn't included while resuming") } testResumeState("KeyChangeFinish", true) clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA} testResumeState("DifferentCipherSuite", false) testResumeState("DifferentCipherSuiteRecovers", true) clientConfig.ClientSessionCache = nil testResumeState("WithoutSessionCache", false) } func TestLRUClientSessionCache(t *testing.T) { // Initialize cache of capacity 4. cache := NewLRUClientSessionCache(4) cs := make([]ClientSessionState, 6) keys := []string{"0", "1", "2", "3", "4", "5", "6"} // Add 4 entries to the cache and look them up. for i := 0; i < 4; i++ { cache.Put(keys[i], &cs[i]) } for i := 0; i < 4; i++ { if s, ok := cache.Get(keys[i]); !ok || s != &cs[i] { t.Fatalf("session cache failed lookup for added key: %s", keys[i]) } } // Add 2 more entries to the cache. First 2 should be evicted. for i := 4; i < 6; i++ { cache.Put(keys[i], &cs[i]) } for i := 0; i < 2; i++ { if s, ok := cache.Get(keys[i]); ok || s != nil { t.Fatalf("session cache should have evicted key: %s", keys[i]) } } // Touch entry 2. LRU should evict 3 next. cache.Get(keys[2]) cache.Put(keys[0], &cs[0]) if s, ok := cache.Get(keys[3]); ok || s != nil { t.Fatalf("session cache should have evicted key 3") } // Update entry 0 in place. cache.Put(keys[0], &cs[3]) if s, ok := cache.Get(keys[0]); !ok || s != &cs[3] { t.Fatalf("session cache failed update for key 0") } // Adding a nil entry is valid. cache.Put(keys[0], nil) if s, ok := cache.Get(keys[0]); !ok || s != nil { t.Fatalf("failed to add nil entry to cache") } } func TestHandshakeClientALPNMatch(t *testing.T) { config := *testConfig config.NextProtos = []string{"proto2", "proto1"} test := &clientTest{ name: "ALPN", // Note that this needs OpenSSL 1.0.2 because that is the first // version that supports the -alpn flag. command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"}, config: &config, validate: func(state ConnectionState) error { // The server's preferences should override the client. if state.NegotiatedProtocol != "proto1" { return fmt.Errorf("Got protocol %q, wanted proto1", state.NegotiatedProtocol) } return nil }, } runClientTestTLS12(t, test) } func TestHandshakeClientALPNNoMatch(t *testing.T) { config := *testConfig config.NextProtos = []string{"proto3"} test := &clientTest{ name: "ALPN-NoMatch", // Note that this needs OpenSSL 1.0.2 because that is the first // version that supports the -alpn flag. command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"}, config: &config, validate: func(state ConnectionState) error { // There's no overlap so OpenSSL will not select a protocol. if state.NegotiatedProtocol != "" { return fmt.Errorf("Got protocol %q, wanted ''", state.NegotiatedProtocol) } return nil }, } runClientTestTLS12(t, test) } // sctsBase64 contains data from `openssl s_client -serverinfo 18 -connect ritter.vg:443` const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBsuEhWWrYpg2RtKp0=" func TestHandshakClientSCTs(t *testing.T) { config := *testConfig scts, err := base64.StdEncoding.DecodeString(sctsBase64) if err != nil { t.Fatal(err) } test := &clientTest{ name: "SCT", // Note that this needs OpenSSL 1.0.2 because that is the first // version that supports the -serverinfo flag. command: []string{"openssl", "s_server"}, config: &config, extensions: [][]byte{scts}, validate: func(state ConnectionState) error { expectedSCTs := [][]byte{ scts[8:125], scts[127:245], scts[247:], } if n := len(state.SignedCertificateTimestamps); n != len(expectedSCTs) { return fmt.Errorf("Got %d scts, wanted %d", n, len(expectedSCTs)) } for i, expected := range expectedSCTs { if sct := state.SignedCertificateTimestamps[i]; !bytes.Equal(sct, expected) { return fmt.Errorf("SCT #%d contained %x, expected %x", i, sct, expected) } } return nil }, } runClientTestTLS12(t, test) } func TestNoIPAddressesInSNI(t *testing.T) { for _, ipLiteral := range []string{"1.2.3.4", "::1"} { c, s := net.Pipe() go func() { client := Client(c, &Config{ServerName: ipLiteral}) client.Handshake() }() var header [5]byte if _, err := io.ReadFull(s, header[:]); err != nil { t.Fatal(err) } recordLen := int(header[3])<<8 | int(header[4]) record := make([]byte, recordLen) if _, err := io.ReadFull(s, record[:]); err != nil { t.Fatal(err) } s.Close() if bytes.Index(record, []byte(ipLiteral)) != -1 { t.Errorf("IP literal %q found in ClientHello: %x", ipLiteral, record) } } } func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) { // This checks that the server can't select a cipher suite that the // client didn't offer. See #13174. c, s := net.Pipe() errChan := make(chan error, 1) go func() { client := Client(c, &Config{ ServerName: "foo", CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, }) errChan <- client.Handshake() }() var header [5]byte if _, err := io.ReadFull(s, header[:]); err != nil { t.Fatal(err) } recordLen := int(header[3])<<8 | int(header[4]) record := make([]byte, recordLen) if _, err := io.ReadFull(s, record); err != nil { t.Fatal(err) } // Create a ServerHello that selects a different cipher suite than the // sole one that the client offered. serverHello := &serverHelloMsg{ vers: VersionTLS12, random: make([]byte, 32), cipherSuite: TLS_RSA_WITH_AES_256_GCM_SHA384, } serverHelloBytes := serverHello.marshal() s.Write([]byte{ byte(recordTypeHandshake), byte(VersionTLS12 >> 8), byte(VersionTLS12 & 0xff), byte(len(serverHelloBytes) >> 8), byte(len(serverHelloBytes)), }) s.Write(serverHelloBytes) s.Close() if err := <-errChan; !strings.Contains(err.Error(), "unconfigured cipher") { t.Fatalf("Expected error about unconfigured cipher suite but got %q", err) } } ================================================ FILE: scan/crypto/tls/handshake_messages.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import "bytes" type clientHelloMsg struct { raw []byte vers uint16 random []byte sessionId []byte cipherSuites []uint16 compressionMethods []uint8 nextProtoNeg bool serverName string ocspStapling bool scts bool supportedCurves []CurveID supportedPoints []uint8 ticketSupported bool sessionTicket []uint8 signatureAndHashes []signatureAndHash secureRenegotiation bool alpnProtocols []string } func (m *clientHelloMsg) equal(i interface{}) bool { m1, ok := i.(*clientHelloMsg) if !ok { return false } return bytes.Equal(m.raw, m1.raw) && m.vers == m1.vers && bytes.Equal(m.random, m1.random) && bytes.Equal(m.sessionId, m1.sessionId) && eqUint16s(m.cipherSuites, m1.cipherSuites) && bytes.Equal(m.compressionMethods, m1.compressionMethods) && m.nextProtoNeg == m1.nextProtoNeg && m.serverName == m1.serverName && m.ocspStapling == m1.ocspStapling && m.scts == m1.scts && eqCurveIDs(m.supportedCurves, m1.supportedCurves) && bytes.Equal(m.supportedPoints, m1.supportedPoints) && m.ticketSupported == m1.ticketSupported && bytes.Equal(m.sessionTicket, m1.sessionTicket) && eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) && m.secureRenegotiation == m1.secureRenegotiation && eqStrings(m.alpnProtocols, m1.alpnProtocols) } func (m *clientHelloMsg) marshal() []byte { if m.raw != nil { return m.raw } length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods) numExtensions := 0 extensionsLength := 0 if m.nextProtoNeg { numExtensions++ } if m.ocspStapling { extensionsLength += 1 + 2 + 2 numExtensions++ } if len(m.serverName) > 0 { extensionsLength += 5 + len(m.serverName) numExtensions++ } if len(m.supportedCurves) > 0 { extensionsLength += 2 + 2*len(m.supportedCurves) numExtensions++ } if len(m.supportedPoints) > 0 { extensionsLength += 1 + len(m.supportedPoints) numExtensions++ } if m.ticketSupported { extensionsLength += len(m.sessionTicket) numExtensions++ } if len(m.signatureAndHashes) > 0 { extensionsLength += 2 + 2*len(m.signatureAndHashes) numExtensions++ } if m.secureRenegotiation { extensionsLength += 1 numExtensions++ } if len(m.alpnProtocols) > 0 { extensionsLength += 2 for _, s := range m.alpnProtocols { if l := len(s); l == 0 || l > 255 { panic("invalid ALPN protocol") } extensionsLength++ extensionsLength += len(s) } numExtensions++ } if m.scts { numExtensions++ } if numExtensions > 0 { extensionsLength += 4 * numExtensions length += 2 + extensionsLength } x := make([]byte, 4+length) x[0] = typeClientHello x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) x[4] = uint8(m.vers >> 8) x[5] = uint8(m.vers) copy(x[6:38], m.random) x[38] = uint8(len(m.sessionId)) copy(x[39:39+len(m.sessionId)], m.sessionId) y := x[39+len(m.sessionId):] y[0] = uint8(len(m.cipherSuites) >> 7) y[1] = uint8(len(m.cipherSuites) << 1) for i, suite := range m.cipherSuites { y[2+i*2] = uint8(suite >> 8) y[3+i*2] = uint8(suite) } z := y[2+len(m.cipherSuites)*2:] z[0] = uint8(len(m.compressionMethods)) copy(z[1:], m.compressionMethods) z = z[1+len(m.compressionMethods):] if numExtensions > 0 { z[0] = byte(extensionsLength >> 8) z[1] = byte(extensionsLength) z = z[2:] } if m.nextProtoNeg { z[0] = byte(extensionNextProtoNeg >> 8) z[1] = byte(extensionNextProtoNeg & 0xff) // The length is always 0 z = z[4:] } if len(m.serverName) > 0 { z[0] = byte(extensionServerName >> 8) z[1] = byte(extensionServerName & 0xff) l := len(m.serverName) + 5 z[2] = byte(l >> 8) z[3] = byte(l) z = z[4:] // RFC 3546, section 3.1 // // struct { // NameType name_type; // select (name_type) { // case host_name: HostName; // } name; // } ServerName; // // enum { // host_name(0), (255) // } NameType; // // opaque HostName<1..2^16-1>; // // struct { // ServerName server_name_list<1..2^16-1> // } ServerNameList; z[0] = byte((len(m.serverName) + 3) >> 8) z[1] = byte(len(m.serverName) + 3) z[3] = byte(len(m.serverName) >> 8) z[4] = byte(len(m.serverName)) copy(z[5:], []byte(m.serverName)) z = z[l:] } if m.ocspStapling { // RFC 4366, section 3.6 z[0] = byte(extensionStatusRequest >> 8) z[1] = byte(extensionStatusRequest) z[2] = 0 z[3] = 5 z[4] = 1 // OCSP type // Two zero valued uint16s for the two lengths. z = z[9:] } if len(m.supportedCurves) > 0 { // http://tools.ietf.org/html/rfc4492#section-5.5.1 z[0] = byte(extensionSupportedCurves >> 8) z[1] = byte(extensionSupportedCurves) l := 2 + 2*len(m.supportedCurves) z[2] = byte(l >> 8) z[3] = byte(l) l -= 2 z[4] = byte(l >> 8) z[5] = byte(l) z = z[6:] for _, curve := range m.supportedCurves { z[0] = byte(curve >> 8) z[1] = byte(curve) z = z[2:] } } if len(m.supportedPoints) > 0 { // http://tools.ietf.org/html/rfc4492#section-5.5.2 z[0] = byte(extensionSupportedPoints >> 8) z[1] = byte(extensionSupportedPoints) l := 1 + len(m.supportedPoints) z[2] = byte(l >> 8) z[3] = byte(l) l-- z[4] = byte(l) z = z[5:] for _, pointFormat := range m.supportedPoints { z[0] = byte(pointFormat) z = z[1:] } } if m.ticketSupported { // http://tools.ietf.org/html/rfc5077#section-3.2 z[0] = byte(extensionSessionTicket >> 8) z[1] = byte(extensionSessionTicket) l := len(m.sessionTicket) z[2] = byte(l >> 8) z[3] = byte(l) z = z[4:] copy(z, m.sessionTicket) z = z[len(m.sessionTicket):] } if len(m.signatureAndHashes) > 0 { // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 z[0] = byte(extensionSignatureAlgorithms >> 8) z[1] = byte(extensionSignatureAlgorithms) l := 2 + 2*len(m.signatureAndHashes) z[2] = byte(l >> 8) z[3] = byte(l) z = z[4:] l -= 2 z[0] = byte(l >> 8) z[1] = byte(l) z = z[2:] for _, sigAndHash := range m.signatureAndHashes { z[0] = sigAndHash.hash z[1] = sigAndHash.signature z = z[2:] } } if m.secureRenegotiation { z[0] = byte(extensionRenegotiationInfo >> 8) z[1] = byte(extensionRenegotiationInfo & 0xff) z[2] = 0 z[3] = 1 z = z[5:] } if len(m.alpnProtocols) > 0 { z[0] = byte(extensionALPN >> 8) z[1] = byte(extensionALPN & 0xff) lengths := z[2:] z = z[6:] stringsLength := 0 for _, s := range m.alpnProtocols { l := len(s) z[0] = byte(l) copy(z[1:], s) z = z[1+l:] stringsLength += 1 + l } lengths[2] = byte(stringsLength >> 8) lengths[3] = byte(stringsLength) stringsLength += 2 lengths[0] = byte(stringsLength >> 8) lengths[1] = byte(stringsLength) } if m.scts { // https://tools.ietf.org/html/rfc6962#section-3.3.1 z[0] = byte(extensionSCT >> 8) z[1] = byte(extensionSCT) // zero uint16 for the zero-length extension_data z = z[4:] } m.raw = x return x } func (m *clientHelloMsg) unmarshal(data []byte) bool { if len(data) < 42 { return false } m.raw = data m.vers = uint16(data[4])<<8 | uint16(data[5]) m.random = data[6:38] sessionIdLen := int(data[38]) if sessionIdLen > 32 || len(data) < 39+sessionIdLen { return false } m.sessionId = data[39 : 39+sessionIdLen] data = data[39+sessionIdLen:] if len(data) < 2 { return false } // cipherSuiteLen is the number of bytes of cipher suite numbers. Since // they are uint16s, the number must be even. cipherSuiteLen := int(data[0])<<8 | int(data[1]) if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen { return false } numCipherSuites := cipherSuiteLen / 2 m.cipherSuites = make([]uint16, numCipherSuites) for i := 0; i < numCipherSuites; i++ { m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i]) if m.cipherSuites[i] == scsvRenegotiation { m.secureRenegotiation = true } } data = data[2+cipherSuiteLen:] if len(data) < 1 { return false } compressionMethodsLen := int(data[0]) if len(data) < 1+compressionMethodsLen { return false } m.compressionMethods = data[1 : 1+compressionMethodsLen] data = data[1+compressionMethodsLen:] m.nextProtoNeg = false m.serverName = "" m.ocspStapling = false m.ticketSupported = false m.sessionTicket = nil m.signatureAndHashes = nil m.alpnProtocols = nil m.scts = false if len(data) == 0 { // ClientHello is optionally followed by extension data return true } if len(data) < 2 { return false } extensionsLength := int(data[0])<<8 | int(data[1]) data = data[2:] if extensionsLength != len(data) { return false } for len(data) != 0 { if len(data) < 4 { return false } extension := uint16(data[0])<<8 | uint16(data[1]) length := int(data[2])<<8 | int(data[3]) data = data[4:] if len(data) < length { return false } switch extension { case extensionServerName: d := data[:length] if len(d) < 2 { return false } namesLen := int(d[0])<<8 | int(d[1]) d = d[2:] if len(d) != namesLen { return false } for len(d) > 0 { if len(d) < 3 { return false } nameType := d[0] nameLen := int(d[1])<<8 | int(d[2]) d = d[3:] if len(d) < nameLen { return false } if nameType == 0 { m.serverName = string(d[:nameLen]) break } d = d[nameLen:] } case extensionNextProtoNeg: if length > 0 { return false } m.nextProtoNeg = true case extensionStatusRequest: m.ocspStapling = length > 0 && data[0] == statusTypeOCSP case extensionSupportedCurves: // http://tools.ietf.org/html/rfc4492#section-5.5.1 if length < 2 { return false } l := int(data[0])<<8 | int(data[1]) if l%2 == 1 || length != l+2 { return false } numCurves := l / 2 m.supportedCurves = make([]CurveID, numCurves) d := data[2:] for i := 0; i < numCurves; i++ { m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1]) d = d[2:] } case extensionSupportedPoints: // http://tools.ietf.org/html/rfc4492#section-5.5.2 if length < 1 { return false } l := int(data[0]) if length != l+1 { return false } m.supportedPoints = make([]uint8, l) copy(m.supportedPoints, data[1:]) case extensionSessionTicket: // http://tools.ietf.org/html/rfc5077#section-3.2 m.ticketSupported = true m.sessionTicket = data[:length] case extensionSignatureAlgorithms: // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 if length < 2 || length&1 != 0 { return false } l := int(data[0])<<8 | int(data[1]) if l != length-2 { return false } n := l / 2 d := data[2:] m.signatureAndHashes = make([]signatureAndHash, n) for i := range m.signatureAndHashes { m.signatureAndHashes[i].hash = d[0] m.signatureAndHashes[i].signature = d[1] d = d[2:] } case extensionRenegotiationInfo: if length != 1 || data[0] != 0 { return false } m.secureRenegotiation = true case extensionALPN: if length < 2 { return false } l := int(data[0])<<8 | int(data[1]) if l != length-2 { return false } d := data[2:length] for len(d) != 0 { stringLen := int(d[0]) d = d[1:] if stringLen == 0 || stringLen > len(d) { return false } m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen])) d = d[stringLen:] } case extensionSCT: m.scts = true if length != 0 { return false } } data = data[length:] } return true } type serverHelloMsg struct { raw []byte vers uint16 random []byte sessionId []byte cipherSuite uint16 compressionMethod uint8 nextProtoNeg bool nextProtos []string ocspStapling bool scts [][]byte ticketSupported bool secureRenegotiation bool alpnProtocol string } func (m *serverHelloMsg) equal(i interface{}) bool { m1, ok := i.(*serverHelloMsg) if !ok { return false } if len(m.scts) != len(m1.scts) { return false } for i, sct := range m.scts { if !bytes.Equal(sct, m1.scts[i]) { return false } } return bytes.Equal(m.raw, m1.raw) && m.vers == m1.vers && bytes.Equal(m.random, m1.random) && bytes.Equal(m.sessionId, m1.sessionId) && m.cipherSuite == m1.cipherSuite && m.compressionMethod == m1.compressionMethod && m.nextProtoNeg == m1.nextProtoNeg && eqStrings(m.nextProtos, m1.nextProtos) && m.ocspStapling == m1.ocspStapling && m.ticketSupported == m1.ticketSupported && m.secureRenegotiation == m1.secureRenegotiation && m.alpnProtocol == m1.alpnProtocol } func (m *serverHelloMsg) marshal() []byte { if m.raw != nil { return m.raw } length := 38 + len(m.sessionId) numExtensions := 0 extensionsLength := 0 nextProtoLen := 0 if m.nextProtoNeg { numExtensions++ for _, v := range m.nextProtos { nextProtoLen += len(v) } nextProtoLen += len(m.nextProtos) extensionsLength += nextProtoLen } if m.ocspStapling { numExtensions++ } if m.ticketSupported { numExtensions++ } if m.secureRenegotiation { extensionsLength += 1 numExtensions++ } if alpnLen := len(m.alpnProtocol); alpnLen > 0 { if alpnLen >= 256 { panic("invalid ALPN protocol") } extensionsLength += 2 + 1 + alpnLen numExtensions++ } sctLen := 0 if len(m.scts) > 0 { for _, sct := range m.scts { sctLen += len(sct) + 2 } extensionsLength += 2 + sctLen numExtensions++ } if numExtensions > 0 { extensionsLength += 4 * numExtensions length += 2 + extensionsLength } x := make([]byte, 4+length) x[0] = typeServerHello x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) x[4] = uint8(m.vers >> 8) x[5] = uint8(m.vers) copy(x[6:38], m.random) x[38] = uint8(len(m.sessionId)) copy(x[39:39+len(m.sessionId)], m.sessionId) z := x[39+len(m.sessionId):] z[0] = uint8(m.cipherSuite >> 8) z[1] = uint8(m.cipherSuite) z[2] = uint8(m.compressionMethod) z = z[3:] if numExtensions > 0 { z[0] = byte(extensionsLength >> 8) z[1] = byte(extensionsLength) z = z[2:] } if m.nextProtoNeg { z[0] = byte(extensionNextProtoNeg >> 8) z[1] = byte(extensionNextProtoNeg & 0xff) z[2] = byte(nextProtoLen >> 8) z[3] = byte(nextProtoLen) z = z[4:] for _, v := range m.nextProtos { l := len(v) if l > 255 { l = 255 } z[0] = byte(l) copy(z[1:], []byte(v[0:l])) z = z[1+l:] } } if m.ocspStapling { z[0] = byte(extensionStatusRequest >> 8) z[1] = byte(extensionStatusRequest) z = z[4:] } if m.ticketSupported { z[0] = byte(extensionSessionTicket >> 8) z[1] = byte(extensionSessionTicket) z = z[4:] } if m.secureRenegotiation { z[0] = byte(extensionRenegotiationInfo >> 8) z[1] = byte(extensionRenegotiationInfo & 0xff) z[2] = 0 z[3] = 1 z = z[5:] } if alpnLen := len(m.alpnProtocol); alpnLen > 0 { z[0] = byte(extensionALPN >> 8) z[1] = byte(extensionALPN & 0xff) l := 2 + 1 + alpnLen z[2] = byte(l >> 8) z[3] = byte(l) l -= 2 z[4] = byte(l >> 8) z[5] = byte(l) l -= 1 z[6] = byte(l) copy(z[7:], []byte(m.alpnProtocol)) z = z[7+alpnLen:] } if sctLen > 0 { z[0] = byte(extensionSCT >> 8) z[1] = byte(extensionSCT) l := sctLen + 2 z[2] = byte(l >> 8) z[3] = byte(l) z[4] = byte(sctLen >> 8) z[5] = byte(sctLen) z = z[6:] for _, sct := range m.scts { z[0] = byte(len(sct) >> 8) z[1] = byte(len(sct)) copy(z[2:], sct) z = z[len(sct)+2:] } } m.raw = x return x } func (m *serverHelloMsg) unmarshal(data []byte) bool { if len(data) < 42 { return false } m.raw = data m.vers = uint16(data[4])<<8 | uint16(data[5]) m.random = data[6:38] sessionIdLen := int(data[38]) if sessionIdLen > 32 || len(data) < 39+sessionIdLen { return false } m.sessionId = data[39 : 39+sessionIdLen] data = data[39+sessionIdLen:] if len(data) < 3 { return false } m.cipherSuite = uint16(data[0])<<8 | uint16(data[1]) m.compressionMethod = data[2] data = data[3:] m.nextProtoNeg = false m.nextProtos = nil m.ocspStapling = false m.scts = nil m.ticketSupported = false m.alpnProtocol = "" if len(data) == 0 { // ServerHello is optionally followed by extension data return true } if len(data) < 2 { return false } extensionsLength := int(data[0])<<8 | int(data[1]) data = data[2:] if len(data) != extensionsLength { return false } for len(data) != 0 { if len(data) < 4 { return false } extension := uint16(data[0])<<8 | uint16(data[1]) length := int(data[2])<<8 | int(data[3]) data = data[4:] if len(data) < length { return false } switch extension { case extensionNextProtoNeg: m.nextProtoNeg = true d := data[:length] for len(d) > 0 { l := int(d[0]) d = d[1:] if l == 0 || l > len(d) { return false } m.nextProtos = append(m.nextProtos, string(d[:l])) d = d[l:] } case extensionStatusRequest: if length > 0 { return false } m.ocspStapling = true case extensionSessionTicket: if length > 0 { return false } m.ticketSupported = true case extensionRenegotiationInfo: if length != 1 || data[0] != 0 { return false } m.secureRenegotiation = true case extensionALPN: d := data[:length] if len(d) < 3 { return false } l := int(d[0])<<8 | int(d[1]) if l != len(d)-2 { return false } d = d[2:] l = int(d[0]) if l != len(d)-1 { return false } d = d[1:] if len(d) == 0 { // ALPN protocols must not be empty. return false } m.alpnProtocol = string(d) case extensionSCT: d := data[:length] if len(d) < 2 { return false } l := int(d[0])<<8 | int(d[1]) d = d[2:] if len(d) != l { return false } if l == 0 { continue } m.scts = make([][]byte, 0, 3) for len(d) != 0 { if len(d) < 2 { return false } sctLen := int(d[0])<<8 | int(d[1]) d = d[2:] if len(d) < sctLen { return false } m.scts = append(m.scts, d[:sctLen]) d = d[sctLen:] } } data = data[length:] } return true } type certificateMsg struct { raw []byte certificates [][]byte } func (m *certificateMsg) equal(i interface{}) bool { m1, ok := i.(*certificateMsg) if !ok { return false } return bytes.Equal(m.raw, m1.raw) && eqByteSlices(m.certificates, m1.certificates) } func (m *certificateMsg) marshal() (x []byte) { if m.raw != nil { return m.raw } var i int for _, slice := range m.certificates { i += len(slice) } length := 3 + 3*len(m.certificates) + i x = make([]byte, 4+length) x[0] = typeCertificate x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) certificateOctets := length - 3 x[4] = uint8(certificateOctets >> 16) x[5] = uint8(certificateOctets >> 8) x[6] = uint8(certificateOctets) y := x[7:] for _, slice := range m.certificates { y[0] = uint8(len(slice) >> 16) y[1] = uint8(len(slice) >> 8) y[2] = uint8(len(slice)) copy(y[3:], slice) y = y[3+len(slice):] } m.raw = x return } func (m *certificateMsg) unmarshal(data []byte) bool { if len(data) < 7 { return false } m.raw = data certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]) if uint32(len(data)) != certsLen+7 { return false } numCerts := 0 d := data[7:] for certsLen > 0 { if len(d) < 4 { return false } certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) if uint32(len(d)) < 3+certLen { return false } d = d[3+certLen:] certsLen -= 3 + certLen numCerts++ } m.certificates = make([][]byte, numCerts) d = data[7:] for i := 0; i < numCerts; i++ { certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) m.certificates[i] = d[3 : 3+certLen] d = d[3+certLen:] } return true } type serverKeyExchangeMsg struct { raw []byte key []byte } func (m *serverKeyExchangeMsg) equal(i interface{}) bool { m1, ok := i.(*serverKeyExchangeMsg) if !ok { return false } return bytes.Equal(m.raw, m1.raw) && bytes.Equal(m.key, m1.key) } func (m *serverKeyExchangeMsg) marshal() []byte { if m.raw != nil { return m.raw } length := len(m.key) x := make([]byte, length+4) x[0] = typeServerKeyExchange x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) copy(x[4:], m.key) m.raw = x return x } func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { m.raw = data if len(data) < 4 { return false } m.key = data[4:] return true } type certificateStatusMsg struct { raw []byte statusType uint8 response []byte } func (m *certificateStatusMsg) equal(i interface{}) bool { m1, ok := i.(*certificateStatusMsg) if !ok { return false } return bytes.Equal(m.raw, m1.raw) && m.statusType == m1.statusType && bytes.Equal(m.response, m1.response) } func (m *certificateStatusMsg) marshal() []byte { if m.raw != nil { return m.raw } var x []byte if m.statusType == statusTypeOCSP { x = make([]byte, 4+4+len(m.response)) x[0] = typeCertificateStatus l := len(m.response) + 4 x[1] = byte(l >> 16) x[2] = byte(l >> 8) x[3] = byte(l) x[4] = statusTypeOCSP l -= 4 x[5] = byte(l >> 16) x[6] = byte(l >> 8) x[7] = byte(l) copy(x[8:], m.response) } else { x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType} } m.raw = x return x } func (m *certificateStatusMsg) unmarshal(data []byte) bool { m.raw = data if len(data) < 5 { return false } m.statusType = data[4] m.response = nil if m.statusType == statusTypeOCSP { if len(data) < 8 { return false } respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) if uint32(len(data)) != 4+4+respLen { return false } m.response = data[8:] } return true } type serverHelloDoneMsg struct{} func (m *serverHelloDoneMsg) equal(i interface{}) bool { _, ok := i.(*serverHelloDoneMsg) return ok } func (m *serverHelloDoneMsg) marshal() []byte { x := make([]byte, 4) x[0] = typeServerHelloDone return x } func (m *serverHelloDoneMsg) unmarshal(data []byte) bool { return len(data) == 4 } type clientKeyExchangeMsg struct { raw []byte ciphertext []byte } func (m *clientKeyExchangeMsg) equal(i interface{}) bool { m1, ok := i.(*clientKeyExchangeMsg) if !ok { return false } return bytes.Equal(m.raw, m1.raw) && bytes.Equal(m.ciphertext, m1.ciphertext) } func (m *clientKeyExchangeMsg) marshal() []byte { if m.raw != nil { return m.raw } length := len(m.ciphertext) x := make([]byte, length+4) x[0] = typeClientKeyExchange x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) copy(x[4:], m.ciphertext) m.raw = x return x } func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { m.raw = data if len(data) < 4 { return false } l := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) if l != len(data)-4 { return false } m.ciphertext = data[4:] return true } type finishedMsg struct { raw []byte verifyData []byte } func (m *finishedMsg) equal(i interface{}) bool { m1, ok := i.(*finishedMsg) if !ok { return false } return bytes.Equal(m.raw, m1.raw) && bytes.Equal(m.verifyData, m1.verifyData) } func (m *finishedMsg) marshal() (x []byte) { if m.raw != nil { return m.raw } x = make([]byte, 4+len(m.verifyData)) x[0] = typeFinished x[3] = byte(len(m.verifyData)) copy(x[4:], m.verifyData) m.raw = x return } func (m *finishedMsg) unmarshal(data []byte) bool { m.raw = data if len(data) < 4 { return false } m.verifyData = data[4:] return true } type nextProtoMsg struct { raw []byte proto string } func (m *nextProtoMsg) equal(i interface{}) bool { m1, ok := i.(*nextProtoMsg) if !ok { return false } return bytes.Equal(m.raw, m1.raw) && m.proto == m1.proto } func (m *nextProtoMsg) marshal() []byte { if m.raw != nil { return m.raw } l := len(m.proto) if l > 255 { l = 255 } padding := 32 - (l+2)%32 length := l + padding + 2 x := make([]byte, length+4) x[0] = typeNextProtocol x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) y := x[4:] y[0] = byte(l) copy(y[1:], []byte(m.proto[0:l])) y = y[1+l:] y[0] = byte(padding) m.raw = x return x } func (m *nextProtoMsg) unmarshal(data []byte) bool { m.raw = data if len(data) < 5 { return false } data = data[4:] protoLen := int(data[0]) data = data[1:] if len(data) < protoLen { return false } m.proto = string(data[0:protoLen]) data = data[protoLen:] if len(data) < 1 { return false } paddingLen := int(data[0]) data = data[1:] if len(data) != paddingLen { return false } return true } type certificateRequestMsg struct { raw []byte // hasSignatureAndHash indicates whether this message includes a list // of signature and hash functions. This change was introduced with TLS // 1.2. hasSignatureAndHash bool certificateTypes []byte signatureAndHashes []signatureAndHash certificateAuthorities [][]byte } func (m *certificateRequestMsg) equal(i interface{}) bool { m1, ok := i.(*certificateRequestMsg) if !ok { return false } return bytes.Equal(m.raw, m1.raw) && bytes.Equal(m.certificateTypes, m1.certificateTypes) && eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) && eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) } func (m *certificateRequestMsg) marshal() (x []byte) { if m.raw != nil { return m.raw } // See http://tools.ietf.org/html/rfc4346#section-7.4.4 length := 1 + len(m.certificateTypes) + 2 casLength := 0 for _, ca := range m.certificateAuthorities { casLength += 2 + len(ca) } length += casLength if m.hasSignatureAndHash { length += 2 + 2*len(m.signatureAndHashes) } x = make([]byte, 4+length) x[0] = typeCertificateRequest x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) x[4] = uint8(len(m.certificateTypes)) copy(x[5:], m.certificateTypes) y := x[5+len(m.certificateTypes):] if m.hasSignatureAndHash { n := len(m.signatureAndHashes) * 2 y[0] = uint8(n >> 8) y[1] = uint8(n) y = y[2:] for _, sigAndHash := range m.signatureAndHashes { y[0] = sigAndHash.hash y[1] = sigAndHash.signature y = y[2:] } } y[0] = uint8(casLength >> 8) y[1] = uint8(casLength) y = y[2:] for _, ca := range m.certificateAuthorities { y[0] = uint8(len(ca) >> 8) y[1] = uint8(len(ca)) y = y[2:] copy(y, ca) y = y[len(ca):] } m.raw = x return } func (m *certificateRequestMsg) unmarshal(data []byte) bool { m.raw = data if len(data) < 5 { return false } length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) if uint32(len(data))-4 != length { return false } numCertTypes := int(data[4]) data = data[5:] if numCertTypes == 0 || len(data) <= numCertTypes { return false } m.certificateTypes = make([]byte, numCertTypes) if copy(m.certificateTypes, data) != numCertTypes { return false } data = data[numCertTypes:] if m.hasSignatureAndHash { if len(data) < 2 { return false } sigAndHashLen := uint16(data[0])<<8 | uint16(data[1]) data = data[2:] if sigAndHashLen&1 != 0 { return false } if len(data) < int(sigAndHashLen) { return false } numSigAndHash := sigAndHashLen / 2 m.signatureAndHashes = make([]signatureAndHash, numSigAndHash) for i := range m.signatureAndHashes { m.signatureAndHashes[i].hash = data[0] m.signatureAndHashes[i].signature = data[1] data = data[2:] } } if len(data) < 2 { return false } casLength := uint16(data[0])<<8 | uint16(data[1]) data = data[2:] if len(data) < int(casLength) { return false } cas := make([]byte, casLength) copy(cas, data) data = data[casLength:] m.certificateAuthorities = nil for len(cas) > 0 { if len(cas) < 2 { return false } caLen := uint16(cas[0])<<8 | uint16(cas[1]) cas = cas[2:] if len(cas) < int(caLen) { return false } m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen]) cas = cas[caLen:] } if len(data) > 0 { return false } return true } type certificateVerifyMsg struct { raw []byte hasSignatureAndHash bool signatureAndHash signatureAndHash signature []byte } func (m *certificateVerifyMsg) equal(i interface{}) bool { m1, ok := i.(*certificateVerifyMsg) if !ok { return false } return bytes.Equal(m.raw, m1.raw) && m.hasSignatureAndHash == m1.hasSignatureAndHash && m.signatureAndHash.hash == m1.signatureAndHash.hash && m.signatureAndHash.signature == m1.signatureAndHash.signature && bytes.Equal(m.signature, m1.signature) } func (m *certificateVerifyMsg) marshal() (x []byte) { if m.raw != nil { return m.raw } // See http://tools.ietf.org/html/rfc4346#section-7.4.8 siglength := len(m.signature) length := 2 + siglength if m.hasSignatureAndHash { length += 2 } x = make([]byte, 4+length) x[0] = typeCertificateVerify x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) y := x[4:] if m.hasSignatureAndHash { y[0] = m.signatureAndHash.hash y[1] = m.signatureAndHash.signature y = y[2:] } y[0] = uint8(siglength >> 8) y[1] = uint8(siglength) copy(y[2:], m.signature) m.raw = x return } func (m *certificateVerifyMsg) unmarshal(data []byte) bool { m.raw = data if len(data) < 6 { return false } length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) if uint32(len(data))-4 != length { return false } data = data[4:] if m.hasSignatureAndHash { m.signatureAndHash.hash = data[0] m.signatureAndHash.signature = data[1] data = data[2:] } if len(data) < 2 { return false } siglength := int(data[0])<<8 + int(data[1]) data = data[2:] if len(data) != siglength { return false } m.signature = data return true } type newSessionTicketMsg struct { raw []byte ticket []byte } func (m *newSessionTicketMsg) equal(i interface{}) bool { m1, ok := i.(*newSessionTicketMsg) if !ok { return false } return bytes.Equal(m.raw, m1.raw) && bytes.Equal(m.ticket, m1.ticket) } func (m *newSessionTicketMsg) marshal() (x []byte) { if m.raw != nil { return m.raw } // See http://tools.ietf.org/html/rfc5077#section-3.3 ticketLen := len(m.ticket) length := 2 + 4 + ticketLen x = make([]byte, 4+length) x[0] = typeNewSessionTicket x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) x[8] = uint8(ticketLen >> 8) x[9] = uint8(ticketLen) copy(x[10:], m.ticket) m.raw = x return } func (m *newSessionTicketMsg) unmarshal(data []byte) bool { m.raw = data if len(data) < 10 { return false } length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) if uint32(len(data))-4 != length { return false } ticketLen := int(data[8])<<8 + int(data[9]) if len(data)-10 != ticketLen { return false } m.ticket = data[10:] return true } func eqUint16s(x, y []uint16) bool { if len(x) != len(y) { return false } for i, v := range x { if y[i] != v { return false } } return true } func eqCurveIDs(x, y []CurveID) bool { if len(x) != len(y) { return false } for i, v := range x { if y[i] != v { return false } } return true } func eqStrings(x, y []string) bool { if len(x) != len(y) { return false } for i, v := range x { if y[i] != v { return false } } return true } func eqByteSlices(x, y [][]byte) bool { if len(x) != len(y) { return false } for i, v := range x { if !bytes.Equal(v, y[i]) { return false } } return true } func eqSignatureAndHashes(x, y []signatureAndHash) bool { if len(x) != len(y) { return false } for i, v := range x { v2 := y[i] if v.hash != v2.hash || v.signature != v2.signature { return false } } return true } ================================================ FILE: scan/crypto/tls/handshake_messages_test.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "math/rand" "reflect" "testing" "testing/quick" ) var tests = []interface{}{ &clientHelloMsg{}, &serverHelloMsg{}, &finishedMsg{}, &certificateMsg{}, &certificateRequestMsg{}, &certificateVerifyMsg{}, &certificateStatusMsg{}, &clientKeyExchangeMsg{}, &nextProtoMsg{}, &newSessionTicketMsg{}, &sessionState{}, } type testMessage interface { marshal() []byte unmarshal([]byte) bool equal(interface{}) bool } func TestMarshalUnmarshal(t *testing.T) { rand := rand.New(rand.NewSource(0)) for i, iface := range tests { ty := reflect.ValueOf(iface).Type() n := 100 if testing.Short() { n = 5 } for j := 0; j < n; j++ { v, ok := quick.Value(ty, rand) if !ok { t.Errorf("#%d: failed to create value", i) break } m1 := v.Interface().(testMessage) marshaled := m1.marshal() m2 := iface.(testMessage) if !m2.unmarshal(marshaled) { t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled) break } m2.marshal() // to fill any marshal cache in the message if !m1.equal(m2) { t.Errorf("#%d got:%#v want:%#v %x", i, m2, m1, marshaled) break } if i >= 3 { // The first three message types (ClientHello, // ServerHello and Finished) are allowed to // have parsable prefixes because the extension // data is optional and the length of the // Finished varies across versions. for j := 0; j < len(marshaled); j++ { if m2.unmarshal(marshaled[0:j]) { t.Errorf("#%d unmarshaled a prefix of length %d of %#v", i, j, m1) break } } } } } } func TestFuzz(t *testing.T) { rand := rand.New(rand.NewSource(0)) for _, iface := range tests { m := iface.(testMessage) for j := 0; j < 1000; j++ { len := rand.Intn(100) bytes := randomBytes(len, rand) // This just looks for crashes due to bounds errors etc. m.unmarshal(bytes) } } } func randomBytes(n int, rand *rand.Rand) []byte { r := make([]byte, n) for i := 0; i < n; i++ { r[i] = byte(rand.Int31()) } return r } func randomString(n int, rand *rand.Rand) string { b := randomBytes(n, rand) return string(b) } func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &clientHelloMsg{} m.vers = uint16(rand.Intn(65536)) m.random = randomBytes(32, rand) m.sessionId = randomBytes(rand.Intn(32), rand) m.cipherSuites = make([]uint16, rand.Intn(63)+1) for i := 0; i < len(m.cipherSuites); i++ { m.cipherSuites[i] = uint16(rand.Int31()) } m.compressionMethods = randomBytes(rand.Intn(63)+1, rand) if rand.Intn(10) > 5 { m.nextProtoNeg = true } if rand.Intn(10) > 5 { m.serverName = randomString(rand.Intn(255), rand) } m.ocspStapling = rand.Intn(10) > 5 m.supportedPoints = randomBytes(rand.Intn(5)+1, rand) m.supportedCurves = make([]CurveID, rand.Intn(5)+1) for i := range m.supportedCurves { m.supportedCurves[i] = CurveID(rand.Intn(30000)) } if rand.Intn(10) > 5 { m.ticketSupported = true if rand.Intn(10) > 5 { m.sessionTicket = randomBytes(rand.Intn(300), rand) } } if rand.Intn(10) > 5 { m.signatureAndHashes = supportedSignatureAlgorithms } m.alpnProtocols = make([]string, rand.Intn(5)) for i := range m.alpnProtocols { m.alpnProtocols[i] = randomString(rand.Intn(20)+1, rand) } if rand.Intn(10) > 5 { m.scts = true } return reflect.ValueOf(m) } func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &serverHelloMsg{} m.vers = uint16(rand.Intn(65536)) m.random = randomBytes(32, rand) m.sessionId = randomBytes(rand.Intn(32), rand) m.cipherSuite = uint16(rand.Int31()) m.compressionMethod = uint8(rand.Intn(256)) if rand.Intn(10) > 5 { m.nextProtoNeg = true n := rand.Intn(10) m.nextProtos = make([]string, n) for i := 0; i < n; i++ { m.nextProtos[i] = randomString(20, rand) } } if rand.Intn(10) > 5 { m.ocspStapling = true } if rand.Intn(10) > 5 { m.ticketSupported = true } m.alpnProtocol = randomString(rand.Intn(32)+1, rand) if rand.Intn(10) > 5 { numSCTs := rand.Intn(4) m.scts = make([][]byte, numSCTs) for i := range m.scts { m.scts[i] = randomBytes(rand.Intn(500), rand) } } return reflect.ValueOf(m) } func (*certificateMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &certificateMsg{} numCerts := rand.Intn(20) m.certificates = make([][]byte, numCerts) for i := 0; i < numCerts; i++ { m.certificates[i] = randomBytes(rand.Intn(10)+1, rand) } return reflect.ValueOf(m) } func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &certificateRequestMsg{} m.certificateTypes = randomBytes(rand.Intn(5)+1, rand) numCAs := rand.Intn(100) m.certificateAuthorities = make([][]byte, numCAs) for i := 0; i < numCAs; i++ { m.certificateAuthorities[i] = randomBytes(rand.Intn(15)+1, rand) } return reflect.ValueOf(m) } func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &certificateVerifyMsg{} m.signature = randomBytes(rand.Intn(15)+1, rand) return reflect.ValueOf(m) } func (*certificateStatusMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &certificateStatusMsg{} if rand.Intn(10) > 5 { m.statusType = statusTypeOCSP m.response = randomBytes(rand.Intn(10)+1, rand) } else { m.statusType = 42 } return reflect.ValueOf(m) } func (*clientKeyExchangeMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &clientKeyExchangeMsg{} m.ciphertext = randomBytes(rand.Intn(1000)+1, rand) return reflect.ValueOf(m) } func (*finishedMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &finishedMsg{} m.verifyData = randomBytes(12, rand) return reflect.ValueOf(m) } func (*nextProtoMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &nextProtoMsg{} m.proto = randomString(rand.Intn(255), rand) return reflect.ValueOf(m) } func (*newSessionTicketMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &newSessionTicketMsg{} m.ticket = randomBytes(rand.Intn(4), rand) return reflect.ValueOf(m) } func (*sessionState) Generate(rand *rand.Rand, size int) reflect.Value { s := &sessionState{} s.vers = uint16(rand.Intn(10000)) s.cipherSuite = uint16(rand.Intn(10000)) s.masterSecret = randomBytes(rand.Intn(100), rand) numCerts := rand.Intn(20) s.certificates = make([][]byte, numCerts) for i := 0; i < numCerts; i++ { s.certificates[i] = randomBytes(rand.Intn(10)+1, rand) } return reflect.ValueOf(s) } ================================================ FILE: scan/crypto/tls/handshake_server.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "crypto" "crypto/ecdsa" "crypto/rsa" "crypto/subtle" "crypto/x509" "encoding/asn1" "errors" "fmt" "io" ) // serverHandshakeState contains details of a server handshake in progress. // It's discarded once the handshake has completed. type serverHandshakeState struct { c *Conn clientHello *clientHelloMsg hello *serverHelloMsg suite *cipherSuite ellipticOk bool ecdsaOk bool rsaDecryptOk bool rsaSignOk bool sessionState *sessionState finishedHash finishedHash masterSecret []byte certsFromClient [][]byte cert *Certificate } // serverHandshake performs a TLS handshake as a server. func (c *Conn) serverHandshake() error { config := c.config // If this is the first server handshake, we generate a random key to // encrypt the tickets with. config.serverInitOnce.Do(config.serverInit) hs := serverHandshakeState{ c: c, } isResume, err := hs.readClientHello() if err != nil { return err } // For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3 if isResume { // The client has included a session ticket and so we do an abbreviated handshake. if err := hs.doResumeHandshake(); err != nil { return err } if err := hs.establishKeys(); err != nil { return err } // ticketSupported is set in a resumption handshake if the // ticket from the client was encrypted with an old session // ticket key and thus a refreshed ticket should be sent. if hs.hello.ticketSupported { if err := hs.sendSessionTicket(); err != nil { return err } } if err := hs.sendFinished(c.firstFinished[:]); err != nil { return err } if err := hs.readFinished(nil); err != nil { return err } c.didResume = true } else { // The client didn't include a session ticket, or it wasn't // valid so we do a full handshake. if err := hs.doFullHandshake(); err != nil { return err } if err := hs.establishKeys(); err != nil { return err } if err := hs.readFinished(c.firstFinished[:]); err != nil { return err } if err := hs.sendSessionTicket(); err != nil { return err } if err := hs.sendFinished(nil); err != nil { return err } } c.handshakeComplete = true return nil } // readClientHello reads a ClientHello message from the client and decides // whether we will perform session resumption. func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { config := hs.c.config c := hs.c msg, err := c.readHandshake() if err != nil { return false, err } var ok bool hs.clientHello, ok = msg.(*clientHelloMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return false, unexpectedMessageError(hs.clientHello, msg) } c.vers, ok = config.mutualVersion(hs.clientHello.vers) if !ok { c.sendAlert(alertProtocolVersion) return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers) } c.haveVers = true hs.hello = new(serverHelloMsg) supportedCurve := false preferredCurves := config.curvePreferences() Curves: for _, curve := range hs.clientHello.supportedCurves { for _, supported := range preferredCurves { if supported == curve { supportedCurve = true break Curves } } } supportedPointFormat := false for _, pointFormat := range hs.clientHello.supportedPoints { if pointFormat == pointFormatUncompressed { supportedPointFormat = true break } } hs.ellipticOk = supportedCurve && supportedPointFormat foundCompression := false // We only support null compression, so check that the client offered it. for _, compression := range hs.clientHello.compressionMethods { if compression == compressionNone { foundCompression = true break } } if !foundCompression { c.sendAlert(alertHandshakeFailure) return false, errors.New("tls: client does not support uncompressed connections") } hs.hello.vers = c.vers hs.hello.random = make([]byte, 32) _, err = io.ReadFull(config.rand(), hs.hello.random) if err != nil { c.sendAlert(alertInternalError) return false, err } hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation hs.hello.compressionMethod = compressionNone if len(hs.clientHello.serverName) > 0 { c.serverName = hs.clientHello.serverName } if len(hs.clientHello.alpnProtocols) > 0 { if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback { hs.hello.alpnProtocol = selectedProto c.clientProtocol = selectedProto } } else { // Although sending an empty NPN extension is reasonable, Firefox has // had a bug around this. Best to send nothing at all if // config.NextProtos is empty. See // https://golang.org/issue/5445. if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 { hs.hello.nextProtoNeg = true hs.hello.nextProtos = config.NextProtos } } if hs.cert, err = config.getCertificate(&ClientHelloInfo{ CipherSuites: hs.clientHello.cipherSuites, ServerName: hs.clientHello.serverName, SupportedCurves: hs.clientHello.supportedCurves, SupportedPoints: hs.clientHello.supportedPoints, }); err != nil { c.sendAlert(alertInternalError) return false, err } if hs.clientHello.scts { hs.hello.scts = hs.cert.SignedCertificateTimestamps } if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok { switch priv.Public().(type) { case *ecdsa.PublicKey: hs.ecdsaOk = true case *rsa.PublicKey: hs.rsaSignOk = true default: c.sendAlert(alertInternalError) return false, fmt.Errorf("crypto/tls: unsupported signing key type (%T)", priv.Public()) } } if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok { switch priv.Public().(type) { case *rsa.PublicKey: hs.rsaDecryptOk = true default: c.sendAlert(alertInternalError) return false, fmt.Errorf("crypto/tls: unsupported decryption key type (%T)", priv.Public()) } } if hs.checkForResumption() { return true, nil } var preferenceList, supportedList []uint16 if c.config.PreferServerCipherSuites { preferenceList = c.config.cipherSuites() supportedList = hs.clientHello.cipherSuites } else { preferenceList = hs.clientHello.cipherSuites supportedList = c.config.cipherSuites() } for _, id := range preferenceList { if hs.setCipherSuite(id, supportedList, c.vers) { break } } if hs.suite == nil { c.sendAlert(alertHandshakeFailure) return false, errors.New("tls: no cipher suite supported by both client and server") } // See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00. for _, id := range hs.clientHello.cipherSuites { if id == TLS_FALLBACK_SCSV { // The client is doing a fallback connection. if hs.clientHello.vers < c.config.maxVersion() { c.sendAlert(alertInappropriateFallback) return false, errors.New("tls: client using inappropriate protocol fallback") } break } } return false, nil } // checkForResumption reports whether we should perform resumption on this connection. func (hs *serverHandshakeState) checkForResumption() bool { c := hs.c if c.config.SessionTicketsDisabled { return false } var ok bool var sessionTicket = append([]uint8{}, hs.clientHello.sessionTicket...) if hs.sessionState, ok = c.decryptTicket(sessionTicket); !ok { return false } if hs.sessionState.vers > hs.clientHello.vers { return false } if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers { return false } cipherSuiteOk := false // Check that the client is still offering the ciphersuite in the session. for _, id := range hs.clientHello.cipherSuites { if id == hs.sessionState.cipherSuite { cipherSuiteOk = true break } } if !cipherSuiteOk { return false } // Check that we also support the ciphersuite from the session. if !hs.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) { return false } sessionHasClientCerts := len(hs.sessionState.certificates) != 0 needClientCerts := c.config.ClientAuth == RequireAnyClientCert || c.config.ClientAuth == RequireAndVerifyClientCert if needClientCerts && !sessionHasClientCerts { return false } if sessionHasClientCerts && c.config.ClientAuth == NoClientCert { return false } return true } func (hs *serverHandshakeState) doResumeHandshake() error { c := hs.c hs.hello.cipherSuite = hs.suite.id // We echo the client's session ID in the ServerHello to let it know // that we're doing a resumption. hs.hello.sessionId = hs.clientHello.sessionId hs.hello.ticketSupported = hs.sessionState.usedOldKey hs.finishedHash = newFinishedHash(c.vers, hs.suite) hs.finishedHash.discardHandshakeBuffer() hs.finishedHash.Write(hs.clientHello.marshal()) hs.finishedHash.Write(hs.hello.marshal()) c.writeRecord(recordTypeHandshake, hs.hello.marshal()) if len(hs.sessionState.certificates) > 0 { if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil { return err } } hs.masterSecret = hs.sessionState.masterSecret return nil } func (hs *serverHandshakeState) doFullHandshake() error { config := hs.c.config c := hs.c if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 { hs.hello.ocspStapling = true } hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled hs.hello.cipherSuite = hs.suite.id hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite) if config.ClientAuth == NoClientCert { // No need to keep a full record of the handshake if client // certificates won't be used. hs.finishedHash.discardHandshakeBuffer() } hs.finishedHash.Write(hs.clientHello.marshal()) hs.finishedHash.Write(hs.hello.marshal()) c.writeRecord(recordTypeHandshake, hs.hello.marshal()) certMsg := new(certificateMsg) certMsg.certificates = hs.cert.Certificate hs.finishedHash.Write(certMsg.marshal()) c.writeRecord(recordTypeHandshake, certMsg.marshal()) if hs.hello.ocspStapling { certStatus := new(certificateStatusMsg) certStatus.statusType = statusTypeOCSP certStatus.response = hs.cert.OCSPStaple hs.finishedHash.Write(certStatus.marshal()) c.writeRecord(recordTypeHandshake, certStatus.marshal()) } keyAgreement := hs.suite.ka(c.vers) skx, err := keyAgreement.generateServerKeyExchange(config, hs.cert, hs.clientHello, hs.hello) if err != nil { c.sendAlert(alertHandshakeFailure) return err } if skx != nil { hs.finishedHash.Write(skx.marshal()) c.writeRecord(recordTypeHandshake, skx.marshal()) } if config.ClientAuth >= RequestClientCert { // Request a client certificate certReq := new(certificateRequestMsg) certReq.certificateTypes = []byte{ byte(certTypeRSASign), byte(certTypeECDSASign), } if c.vers >= VersionTLS12 { certReq.hasSignatureAndHash = true certReq.signatureAndHashes = supportedSignatureAlgorithms } // An empty list of certificateAuthorities signals to // the client that it may send any certificate in response // to our request. When we know the CAs we trust, then // we can send them down, so that the client can choose // an appropriate certificate to give to us. if config.ClientCAs != nil { certReq.certificateAuthorities = config.ClientCAs.Subjects() } hs.finishedHash.Write(certReq.marshal()) c.writeRecord(recordTypeHandshake, certReq.marshal()) } helloDone := new(serverHelloDoneMsg) hs.finishedHash.Write(helloDone.marshal()) c.writeRecord(recordTypeHandshake, helloDone.marshal()) var pub crypto.PublicKey // public key for client auth, if any msg, err := c.readHandshake() if err != nil { return err } var ok bool // If we requested a client certificate, then the client must send a // certificate message, even if it's empty. if config.ClientAuth >= RequestClientCert { if certMsg, ok = msg.(*certificateMsg); !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(certMsg, msg) } hs.finishedHash.Write(certMsg.marshal()) if len(certMsg.certificates) == 0 { // The client didn't actually send a certificate switch config.ClientAuth { case RequireAnyClientCert, RequireAndVerifyClientCert: c.sendAlert(alertBadCertificate) return errors.New("tls: client didn't provide a certificate") } } pub, err = hs.processCertsFromClient(certMsg.certificates) if err != nil { return err } msg, err = c.readHandshake() if err != nil { return err } } // Get client key exchange ckx, ok := msg.(*clientKeyExchangeMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(ckx, msg) } hs.finishedHash.Write(ckx.marshal()) preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers) if err != nil { c.sendAlert(alertHandshakeFailure) return err } hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random) // If we received a client cert in response to our certificate request message, // the client will send us a certificateVerifyMsg immediately after the // clientKeyExchangeMsg. This message is a digest of all preceding // handshake-layer messages that is signed using the private key corresponding // to the client's certificate. This allows us to verify that the client is in // possession of the private key of the certificate. if len(c.peerCertificates) > 0 { msg, err = c.readHandshake() if err != nil { return err } certVerify, ok := msg.(*certificateVerifyMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(certVerify, msg) } // Determine the signature type. var signatureAndHash signatureAndHash if certVerify.hasSignatureAndHash { signatureAndHash = certVerify.signatureAndHash if !isSupportedSignatureAndHash(signatureAndHash, supportedSignatureAlgorithms) { return errors.New("tls: unsupported hash function for client certificate") } } else { // Before TLS 1.2 the signature algorithm was implicit // from the key type, and only one hash per signature // algorithm was possible. Leave the hash as zero. switch pub.(type) { case *ecdsa.PublicKey: signatureAndHash.signature = signatureECDSA case *rsa.PublicKey: signatureAndHash.signature = signatureRSA } } switch key := pub.(type) { case *ecdsa.PublicKey: if signatureAndHash.signature != signatureECDSA { err = errors.New("bad signature type for client's ECDSA certificate") break } ecdsaSig := new(ecdsaSignature) if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil { break } if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { err = errors.New("ECDSA signature contained zero or negative values") break } var digest []byte if digest, _, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil { break } if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) { err = errors.New("ECDSA verification failure") } case *rsa.PublicKey: if signatureAndHash.signature != signatureRSA { err = errors.New("bad signature type for client's RSA certificate") break } var digest []byte var hashFunc crypto.Hash if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil { break } err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature) } if err != nil { c.sendAlert(alertBadCertificate) return errors.New("tls: could not validate signature of connection nonces: " + err.Error()) } hs.finishedHash.Write(certVerify.marshal()) } hs.finishedHash.discardHandshakeBuffer() return nil } func (hs *serverHandshakeState) establishKeys() error { c := hs.c clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) var clientCipher, serverCipher interface{} var clientHash, serverHash macFunction if hs.suite.aead == nil { clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */) clientHash = hs.suite.mac(c.vers, clientMAC) serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */) serverHash = hs.suite.mac(c.vers, serverMAC) } else { clientCipher = hs.suite.aead(clientKey, clientIV) serverCipher = hs.suite.aead(serverKey, serverIV) } c.in.prepareCipherSpec(c.vers, clientCipher, clientHash) c.out.prepareCipherSpec(c.vers, serverCipher, serverHash) return nil } func (hs *serverHandshakeState) readFinished(out []byte) error { c := hs.c c.readRecord(recordTypeChangeCipherSpec) if err := c.in.error(); err != nil { return err } if hs.hello.nextProtoNeg { msg, err := c.readHandshake() if err != nil { return err } nextProto, ok := msg.(*nextProtoMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(nextProto, msg) } hs.finishedHash.Write(nextProto.marshal()) c.clientProtocol = nextProto.proto } msg, err := c.readHandshake() if err != nil { return err } clientFinished, ok := msg.(*finishedMsg) if !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(clientFinished, msg) } verify := hs.finishedHash.clientSum(hs.masterSecret) if len(verify) != len(clientFinished.verifyData) || subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 { c.sendAlert(alertHandshakeFailure) return errors.New("tls: client's Finished message is incorrect") } hs.finishedHash.Write(clientFinished.marshal()) copy(out, verify) return nil } func (hs *serverHandshakeState) sendSessionTicket() error { if !hs.hello.ticketSupported { return nil } c := hs.c m := new(newSessionTicketMsg) var err error state := sessionState{ vers: c.vers, cipherSuite: hs.suite.id, masterSecret: hs.masterSecret, certificates: hs.certsFromClient, } m.ticket, err = c.encryptTicket(&state) if err != nil { return err } hs.finishedHash.Write(m.marshal()) c.writeRecord(recordTypeHandshake, m.marshal()) return nil } func (hs *serverHandshakeState) sendFinished(out []byte) error { c := hs.c c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) finished := new(finishedMsg) finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret) hs.finishedHash.Write(finished.marshal()) c.writeRecord(recordTypeHandshake, finished.marshal()) c.cipherSuite = hs.suite.id copy(out, finished.verifyData) return nil } // processCertsFromClient takes a chain of client certificates either from a // Certificates message or from a sessionState and verifies them. It returns // the public key of the leaf certificate. func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (crypto.PublicKey, error) { c := hs.c hs.certsFromClient = certificates certs := make([]*x509.Certificate, len(certificates)) var err error for i, asn1Data := range certificates { if certs[i], err = x509.ParseCertificate(asn1Data); err != nil { c.sendAlert(alertBadCertificate) return nil, errors.New("tls: failed to parse client certificate: " + err.Error()) } } if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 { opts := x509.VerifyOptions{ Roots: c.config.ClientCAs, CurrentTime: c.config.time(), Intermediates: x509.NewCertPool(), KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, } for _, cert := range certs[1:] { opts.Intermediates.AddCert(cert) } chains, err := certs[0].Verify(opts) if err != nil { c.sendAlert(alertBadCertificate) return nil, errors.New("tls: failed to verify client's certificate: " + err.Error()) } c.verifiedChains = chains } if len(certs) > 0 { var pub crypto.PublicKey switch key := certs[0].PublicKey.(type) { case *ecdsa.PublicKey, *rsa.PublicKey: pub = key default: c.sendAlert(alertUnsupportedCertificate) return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey) } c.peerCertificates = certs return pub, nil } return nil, nil } // setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState // suite if that cipher suite is acceptable to use. // It returns a bool indicating if the suite was set. func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16) bool { for _, supported := range supportedCipherSuites { if id == supported { var candidate *cipherSuite for _, s := range cipherSuites { if s.id == id { candidate = s break } } if candidate == nil { continue } // Don't select a ciphersuite which we can't // support for this client. if candidate.flags&suiteECDHE != 0 { if !hs.ellipticOk { continue } if candidate.flags&suiteECDSA != 0 { if !hs.ecdsaOk { continue } } else if !hs.rsaSignOk { continue } } else if !hs.rsaDecryptOk { continue } if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 { continue } hs.suite = candidate return true } } return false } ================================================ FILE: scan/crypto/tls/handshake_server_test.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "bytes" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" "encoding/hex" "encoding/pem" "errors" "fmt" "io" "math/big" "net" "os" "os/exec" "path/filepath" "strings" "testing" "time" ) // zeroSource is an io.Reader that returns an unlimited number of zero bytes. type zeroSource struct{} func (zeroSource) Read(b []byte) (n int, err error) { for i := range b { b[i] = 0 } return len(b), nil } var testConfig *Config func allCipherSuites() []uint16 { ids := make([]uint16, len(cipherSuites)) for i, suite := range cipherSuites { ids[i] = suite.id } return ids } func init() { testConfig = &Config{ Time: func() time.Time { return time.Unix(0, 0) }, Rand: zeroSource{}, Certificates: make([]Certificate, 2), InsecureSkipVerify: true, MinVersion: VersionSSL30, MaxVersion: VersionTLS12, CipherSuites: allCipherSuites(), } testConfig.Certificates[0].Certificate = [][]byte{testRSACertificate} testConfig.Certificates[0].PrivateKey = testRSAPrivateKey testConfig.Certificates[1].Certificate = [][]byte{testSNICertificate} testConfig.Certificates[1].PrivateKey = testRSAPrivateKey testConfig.BuildNameToCertificate() } func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) { testClientHelloFailure(t, serverConfig, m, "") } func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) { // Create in-memory network connection, // send message to server. Should return // expected error. c, s := net.Pipe() go func() { cli := Client(c, testConfig) if ch, ok := m.(*clientHelloMsg); ok { cli.vers = ch.vers } cli.writeRecord(recordTypeHandshake, m.marshal()) c.Close() }() err := Server(s, serverConfig).Handshake() s.Close() if len(expectedSubStr) == 0 { if err != nil && err != io.EOF { t.Errorf("Got error: %s; expected to succeed", err) } } else if err == nil || !strings.Contains(err.Error(), expectedSubStr) { t.Errorf("Got error: %s; expected to match substring '%s'", err, expectedSubStr) } } func TestSimpleError(t *testing.T) { testClientHelloFailure(t, testConfig, &serverHelloDoneMsg{}, "unexpected handshake message") } var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205} func TestRejectBadProtocolVersion(t *testing.T) { for _, v := range badProtocolVersions { testClientHelloFailure(t, testConfig, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version") } } func TestNoSuiteOverlap(t *testing.T) { clientHello := &clientHelloMsg{ vers: 0x0301, cipherSuites: []uint16{0xff00}, compressionMethods: []uint8{0}, } testClientHelloFailure(t, testConfig, clientHello, "no cipher suite supported by both client and server") } func TestNoCompressionOverlap(t *testing.T) { clientHello := &clientHelloMsg{ vers: 0x0301, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, compressionMethods: []uint8{0xff}, } testClientHelloFailure(t, testConfig, clientHello, "client does not support uncompressed connections") } func TestNoRC4ByDefault(t *testing.T) { clientHello := &clientHelloMsg{ vers: 0x0301, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, compressionMethods: []uint8{0}, } serverConfig := *testConfig // Reset the enabled cipher suites to nil in order to test the // defaults. serverConfig.CipherSuites = nil testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server") } func TestDontSelectECDSAWithRSAKey(t *testing.T) { // Test that, even when both sides support an ECDSA cipher suite, it // won't be selected if the server's private key doesn't support it. clientHello := &clientHelloMsg{ vers: 0x0301, cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, compressionMethods: []uint8{0}, supportedCurves: []CurveID{CurveP256}, supportedPoints: []uint8{pointFormatUncompressed}, } serverConfig := *testConfig serverConfig.CipherSuites = clientHello.cipherSuites serverConfig.Certificates = make([]Certificate, 1) serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey serverConfig.BuildNameToCertificate() // First test that it *does* work when the server's key is ECDSA. testClientHello(t, &serverConfig, clientHello) // Now test that switching to an RSA key causes the expected error (and // not an internal error about a signing failure). serverConfig.Certificates = testConfig.Certificates testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server") } func TestDontSelectRSAWithECDSAKey(t *testing.T) { // Test that, even when both sides support an RSA cipher suite, it // won't be selected if the server's private key doesn't support it. clientHello := &clientHelloMsg{ vers: 0x0301, cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, compressionMethods: []uint8{0}, supportedCurves: []CurveID{CurveP256}, supportedPoints: []uint8{pointFormatUncompressed}, } serverConfig := *testConfig serverConfig.CipherSuites = clientHello.cipherSuites // First test that it *does* work when the server's key is RSA. testClientHello(t, &serverConfig, clientHello) // Now test that switching to an ECDSA key causes the expected error // (and not an internal error about a signing failure). serverConfig.Certificates = make([]Certificate, 1) serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey serverConfig.BuildNameToCertificate() testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server") } func TestRenegotiationExtension(t *testing.T) { clientHello := &clientHelloMsg{ vers: VersionTLS12, compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), secureRenegotiation: true, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, } var buf []byte c, s := net.Pipe() go func() { cli := Client(c, testConfig) cli.vers = clientHello.vers cli.writeRecord(recordTypeHandshake, clientHello.marshal()) buf = make([]byte, 1024) n, err := c.Read(buf) if err != nil { t.Fatalf("Server read returned error: %s", err) } buf = buf[:n] c.Close() }() Server(s, testConfig).Handshake() if len(buf) < 5+4 { t.Fatalf("Server returned short message of length %d", len(buf)) } // buf contains a TLS record, with a 5 byte record header and a 4 byte // handshake header. The length of the ServerHello is taken from the // handshake header. serverHelloLen := int(buf[6])<<16 | int(buf[7])<<8 | int(buf[8]) var serverHello serverHelloMsg // unmarshal expects to be given the handshake header, but // serverHelloLen doesn't include it. if !serverHello.unmarshal(buf[5 : 9+serverHelloLen]) { t.Fatalf("Failed to parse ServerHello") } if !serverHello.secureRenegotiation { t.Errorf("Secure renegotiation extension was not echoed.") } } func TestTLS12OnlyCipherSuites(t *testing.T) { // Test that a Server doesn't select a TLS 1.2-only cipher suite when // the client negotiates TLS 1.1. var zeros [32]byte clientHello := &clientHelloMsg{ vers: VersionTLS11, random: zeros[:], cipherSuites: []uint16{ // The Server, by default, will use the client's // preference order. So the GCM cipher suite // will be selected unless it's excluded because // of the version in this ClientHello. TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_RC4_128_SHA, }, compressionMethods: []uint8{compressionNone}, supportedCurves: []CurveID{CurveP256, CurveP384, CurveP521}, supportedPoints: []uint8{pointFormatUncompressed}, } c, s := net.Pipe() var reply interface{} var clientErr error go func() { cli := Client(c, testConfig) cli.vers = clientHello.vers cli.writeRecord(recordTypeHandshake, clientHello.marshal()) reply, clientErr = cli.readHandshake() c.Close() }() config := *testConfig config.CipherSuites = clientHello.cipherSuites Server(s, &config).Handshake() s.Close() if clientErr != nil { t.Fatal(clientErr) } serverHello, ok := reply.(*serverHelloMsg) if !ok { t.Fatalf("didn't get ServerHello message in reply. Got %v\n", reply) } if s := serverHello.cipherSuite; s != TLS_RSA_WITH_RC4_128_SHA { t.Fatalf("bad cipher suite from server: %x", s) } } func TestAlertForwarding(t *testing.T) { c, s := net.Pipe() go func() { Client(c, testConfig).sendAlert(alertUnknownCA) c.Close() }() err := Server(s, testConfig).Handshake() s.Close() if e, ok := err.(*net.OpError); !ok || e.Err != error(alertUnknownCA) { t.Errorf("Got error: %s; expected: %s", err, error(alertUnknownCA)) } } func TestClose(t *testing.T) { c, s := net.Pipe() go c.Close() err := Server(s, testConfig).Handshake() s.Close() if err != io.EOF { t.Errorf("Got error: %s; expected: %s", err, io.EOF) } } func testHandshake(clientConfig, serverConfig *Config) (serverState, clientState ConnectionState, err error) { c, s := net.Pipe() done := make(chan bool) go func() { cli := Client(c, clientConfig) cli.Handshake() clientState = cli.ConnectionState() c.Close() done <- true }() server := Server(s, serverConfig) err = server.Handshake() if err == nil { serverState = server.ConnectionState() } s.Close() <-done return } func TestVersion(t *testing.T) { serverConfig := &Config{ Certificates: testConfig.Certificates, MaxVersion: VersionTLS11, } clientConfig := &Config{ InsecureSkipVerify: true, } state, _, err := testHandshake(clientConfig, serverConfig) if err != nil { t.Fatalf("handshake failed: %s", err) } if state.Version != VersionTLS11 { t.Fatalf("Incorrect version %x, should be %x", state.Version, VersionTLS11) } } func TestCipherSuitePreference(t *testing.T) { serverConfig := &Config{ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, Certificates: testConfig.Certificates, MaxVersion: VersionTLS11, } clientConfig := &Config{ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA}, InsecureSkipVerify: true, } state, _, err := testHandshake(clientConfig, serverConfig) if err != nil { t.Fatalf("handshake failed: %s", err) } if state.CipherSuite != TLS_RSA_WITH_AES_128_CBC_SHA { // By default the server should use the client's preference. t.Fatalf("Client's preference was not used, got %x", state.CipherSuite) } serverConfig.PreferServerCipherSuites = true state, _, err = testHandshake(clientConfig, serverConfig) if err != nil { t.Fatalf("handshake failed: %s", err) } if state.CipherSuite != TLS_RSA_WITH_RC4_128_SHA { t.Fatalf("Server's preference was not used, got %x", state.CipherSuite) } } func TestSCTHandshake(t *testing.T) { expected := [][]byte{[]byte("certificate"), []byte("transparency")} serverConfig := &Config{ Certificates: []Certificate{{ Certificate: [][]byte{testRSACertificate}, PrivateKey: testRSAPrivateKey, SignedCertificateTimestamps: expected, }}, } clientConfig := &Config{ InsecureSkipVerify: true, } _, state, err := testHandshake(clientConfig, serverConfig) if err != nil { t.Fatalf("handshake failed: %s", err) } actual := state.SignedCertificateTimestamps if len(actual) != len(expected) { t.Fatalf("got %d scts, want %d", len(actual), len(expected)) } for i, sct := range expected { if !bytes.Equal(sct, actual[i]) { t.Fatalf("SCT #%d was %x, but expected %x", i, actual[i], sct) } } } // Note: see comment in handshake_test.go for details of how the reference // tests work. // serverTest represents a test of the TLS server handshake against a reference // implementation. type serverTest struct { // name is a freeform string identifying the test and the file in which // the expected results will be stored. name string // command, if not empty, contains a series of arguments for the // command to run for the reference server. command []string // expectedPeerCerts contains a list of PEM blocks of expected // certificates from the client. expectedPeerCerts []string // config, if not nil, contains a custom Config to use for this test. config *Config // expectHandshakeErrorIncluding, when not empty, contains a string // that must be a substring of the error resulting from the handshake. expectHandshakeErrorIncluding string // validate, if not nil, is a function that will be called with the // ConnectionState of the resulting connection. It returns false if the // ConnectionState is unacceptable. validate func(ConnectionState) error } var defaultClientCommand = []string{"openssl", "s_client", "-no_ticket"} // connFromCommand starts opens a listening socket and starts the reference // client to connect to it. It returns a recordingConn that wraps the resulting // connection. func (test *serverTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, err error) { l, err := net.ListenTCP("tcp", &net.TCPAddr{ IP: net.IPv4(127, 0, 0, 1), Port: 0, }) if err != nil { return nil, nil, err } defer l.Close() port := l.Addr().(*net.TCPAddr).Port var command []string command = append(command, test.command...) if len(command) == 0 { command = defaultClientCommand } command = append(command, "-connect") command = append(command, fmt.Sprintf("127.0.0.1:%d", port)) cmd := exec.Command(command[0], command[1:]...) cmd.Stdin = nil var output bytes.Buffer cmd.Stdout = &output cmd.Stderr = &output if err := cmd.Start(); err != nil { return nil, nil, err } connChan := make(chan interface{}) go func() { tcpConn, err := l.Accept() if err != nil { connChan <- err } connChan <- tcpConn }() var tcpConn net.Conn select { case connOrError := <-connChan: if err, ok := connOrError.(error); ok { return nil, nil, err } tcpConn = connOrError.(net.Conn) case <-time.After(2 * time.Second): output.WriteTo(os.Stdout) return nil, nil, errors.New("timed out waiting for connection from child process") } record := &recordingConn{ Conn: tcpConn, } return record, cmd, nil } func (test *serverTest) dataPath() string { return filepath.Join("testdata", "Server-"+test.name) } func (test *serverTest) loadData() (flows [][]byte, err error) { in, err := os.Open(test.dataPath()) if err != nil { return nil, err } defer in.Close() return parseTestData(in) } func (test *serverTest) run(t *testing.T, write bool) { var clientConn, serverConn net.Conn var recordingConn *recordingConn var childProcess *exec.Cmd if write { var err error recordingConn, childProcess, err = test.connFromCommand() if err != nil { t.Fatalf("Failed to start subcommand: %s", err) } serverConn = recordingConn } else { clientConn, serverConn = net.Pipe() } config := test.config if config == nil { config = testConfig } server := Server(serverConn, config) connStateChan := make(chan ConnectionState, 1) go func() { var err error if _, err = server.Write([]byte("hello, world\n")); err != nil { t.Logf("Error from Server.Write: %s", err) } if len(test.expectHandshakeErrorIncluding) > 0 { if err == nil { t.Errorf("Error expected, but no error returned") } else if s := err.Error(); !strings.Contains(s, test.expectHandshakeErrorIncluding) { t.Errorf("Error expected containing '%s' but got '%s'", test.expectHandshakeErrorIncluding, s) } } server.Close() serverConn.Close() connStateChan <- server.ConnectionState() }() if !write { flows, err := test.loadData() if err != nil { t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath()) } for i, b := range flows { if i%2 == 0 { clientConn.Write(b) continue } bb := make([]byte, len(b)) n, err := io.ReadFull(clientConn, bb) if err != nil { t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b) } if !bytes.Equal(b, bb) { t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b) } } clientConn.Close() } connState := <-connStateChan peerCerts := connState.PeerCertificates if len(peerCerts) == len(test.expectedPeerCerts) { for i, peerCert := range peerCerts { block, _ := pem.Decode([]byte(test.expectedPeerCerts[i])) if !bytes.Equal(block.Bytes, peerCert.Raw) { t.Fatalf("%s: mismatch on peer cert %d", test.name, i+1) } } } else { t.Fatalf("%s: mismatch on peer list length: %d (wanted) != %d (got)", test.name, len(test.expectedPeerCerts), len(peerCerts)) } if test.validate != nil { if err := test.validate(connState); err != nil { t.Fatalf("validate callback returned error: %s", err) } } if write { path := test.dataPath() out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { t.Fatalf("Failed to create output file: %s", err) } defer out.Close() recordingConn.Close() if len(recordingConn.flows) < 3 { childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout) if len(test.expectHandshakeErrorIncluding) == 0 { t.Fatalf("Handshake failed") } } recordingConn.WriteTo(out) fmt.Printf("Wrote %s\n", path) childProcess.Wait() } } func runServerTestForVersion(t *testing.T, template *serverTest, prefix, option string) { test := *template test.name = prefix + test.name if len(test.command) == 0 { test.command = defaultClientCommand } test.command = append([]string(nil), test.command...) test.command = append(test.command, option) test.run(t, *update) } func runServerTestSSLv3(t *testing.T, template *serverTest) { runServerTestForVersion(t, template, "SSLv3-", "-ssl3") } func runServerTestTLS10(t *testing.T, template *serverTest) { runServerTestForVersion(t, template, "TLSv10-", "-tls1") } func runServerTestTLS11(t *testing.T, template *serverTest) { runServerTestForVersion(t, template, "TLSv11-", "-tls1_1") } func runServerTestTLS12(t *testing.T, template *serverTest) { runServerTestForVersion(t, template, "TLSv12-", "-tls1_2") } func TestHandshakeServerRSARC4(t *testing.T) { test := &serverTest{ name: "RSA-RC4", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"}, } runServerTestSSLv3(t, test) runServerTestTLS10(t, test) runServerTestTLS11(t, test) runServerTestTLS12(t, test) } func TestHandshakeServerRSA3DES(t *testing.T) { test := &serverTest{ name: "RSA-3DES", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "DES-CBC3-SHA"}, } runServerTestSSLv3(t, test) runServerTestTLS10(t, test) runServerTestTLS12(t, test) } func TestHandshakeServerRSAAES(t *testing.T) { test := &serverTest{ name: "RSA-AES", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA"}, } runServerTestSSLv3(t, test) runServerTestTLS10(t, test) runServerTestTLS12(t, test) } func TestHandshakeServerAESGCM(t *testing.T) { test := &serverTest{ name: "RSA-AES-GCM", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256"}, } runServerTestTLS12(t, test) } func TestHandshakeServerAES256GCMSHA384(t *testing.T) { test := &serverTest{ name: "RSA-AES256-GCM-SHA384", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384"}, } runServerTestTLS12(t, test) } func TestHandshakeServerECDHEECDSAAES(t *testing.T) { config := *testConfig config.Certificates = make([]Certificate, 1) config.Certificates[0].Certificate = [][]byte{testECDSACertificate} config.Certificates[0].PrivateKey = testECDSAPrivateKey config.BuildNameToCertificate() test := &serverTest{ name: "ECDHE-ECDSA-AES", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-AES256-SHA"}, config: &config, } runServerTestTLS10(t, test) runServerTestTLS12(t, test) } func TestHandshakeServerALPN(t *testing.T) { config := *testConfig config.NextProtos = []string{"proto1", "proto2"} test := &serverTest{ name: "ALPN", // Note that this needs OpenSSL 1.0.2 because that is the first // version that supports the -alpn flag. command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"}, config: &config, validate: func(state ConnectionState) error { // The server's preferences should override the client. if state.NegotiatedProtocol != "proto1" { return fmt.Errorf("Got protocol %q, wanted proto1", state.NegotiatedProtocol) } return nil }, } runServerTestTLS12(t, test) } func TestHandshakeServerALPNNoMatch(t *testing.T) { config := *testConfig config.NextProtos = []string{"proto3"} test := &serverTest{ name: "ALPN-NoMatch", // Note that this needs OpenSSL 1.0.2 because that is the first // version that supports the -alpn flag. command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"}, config: &config, validate: func(state ConnectionState) error { // Rather than reject the connection, Go doesn't select // a protocol when there is no overlap. if state.NegotiatedProtocol != "" { return fmt.Errorf("Got protocol %q, wanted ''", state.NegotiatedProtocol) } return nil }, } runServerTestTLS12(t, test) } // TestHandshakeServerSNI involves a client sending an SNI extension of // "snitest.com", which happens to match the CN of testSNICertificate. The test // verifies that the server correctly selects that certificate. func TestHandshakeServerSNI(t *testing.T) { test := &serverTest{ name: "SNI", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"}, } runServerTestTLS12(t, test) } // TestHandshakeServerSNICertForName is similar to TestHandshakeServerSNI, but // tests the dynamic GetCertificate method func TestHandshakeServerSNIGetCertificate(t *testing.T) { config := *testConfig // Replace the NameToCertificate map with a GetCertificate function nameToCert := config.NameToCertificate config.NameToCertificate = nil config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) { cert, _ := nameToCert[clientHello.ServerName] return cert, nil } test := &serverTest{ name: "SNI-GetCertificate", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"}, config: &config, } runServerTestTLS12(t, test) } // TestHandshakeServerSNICertForNameNotFound is similar to // TestHandshakeServerSNICertForName, but tests to make sure that when the // GetCertificate method doesn't return a cert, we fall back to what's in // the NameToCertificate map. func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) { config := *testConfig config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) { return nil, nil } test := &serverTest{ name: "SNI-GetCertificateNotFound", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"}, config: &config, } runServerTestTLS12(t, test) } // TestHandshakeServerSNICertForNameError tests to make sure that errors in // GetCertificate result in a tls alert. func TestHandshakeServerSNIGetCertificateError(t *testing.T) { const errMsg = "TestHandshakeServerSNIGetCertificateError error" serverConfig := *testConfig serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) { return nil, errors.New(errMsg) } clientHello := &clientHelloMsg{ vers: 0x0301, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, compressionMethods: []uint8{0}, serverName: "test", } testClientHelloFailure(t, &serverConfig, clientHello, errMsg) } // TestHandshakeServerEmptyCertificates tests that GetCertificates is called in // the case that Certificates is empty, even without SNI. func TestHandshakeServerEmptyCertificates(t *testing.T) { const errMsg = "TestHandshakeServerEmptyCertificates error" serverConfig := *testConfig serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) { return nil, errors.New(errMsg) } serverConfig.Certificates = nil clientHello := &clientHelloMsg{ vers: 0x0301, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, compressionMethods: []uint8{0}, } testClientHelloFailure(t, &serverConfig, clientHello, errMsg) // With an empty Certificates and a nil GetCertificate, the server // should always return a “no certificates” error. serverConfig.GetCertificate = nil clientHello = &clientHelloMsg{ vers: 0x0301, cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, compressionMethods: []uint8{0}, } testClientHelloFailure(t, &serverConfig, clientHello, "no certificates") } // TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with // an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate. func TestCipherSuiteCertPreferenceECDSA(t *testing.T) { config := *testConfig config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA} config.PreferServerCipherSuites = true test := &serverTest{ name: "CipherSuiteCertPreferenceRSA", config: &config, } runServerTestTLS12(t, test) config = *testConfig config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA} config.Certificates = []Certificate{ { Certificate: [][]byte{testECDSACertificate}, PrivateKey: testECDSAPrivateKey, }, } config.BuildNameToCertificate() config.PreferServerCipherSuites = true test = &serverTest{ name: "CipherSuiteCertPreferenceECDSA", config: &config, } runServerTestTLS12(t, test) } func TestResumption(t *testing.T) { sessionFilePath := tempFile("") defer os.Remove(sessionFilePath) test := &serverTest{ name: "IssueTicket", command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath}, } runServerTestTLS12(t, test) test = &serverTest{ name: "Resume", command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath}, } runServerTestTLS12(t, test) } func TestResumptionDisabled(t *testing.T) { sessionFilePath := tempFile("") defer os.Remove(sessionFilePath) config := *testConfig test := &serverTest{ name: "IssueTicketPreDisable", command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath}, config: &config, } runServerTestTLS12(t, test) config.SessionTicketsDisabled = true test = &serverTest{ name: "ResumeDisabled", command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath}, config: &config, } runServerTestTLS12(t, test) // One needs to manually confirm that the handshake in the golden data // file for ResumeDisabled does not include a resumption handshake. } func TestFallbackSCSV(t *testing.T) { serverConfig := &Config{ Certificates: testConfig.Certificates, } test := &serverTest{ name: "FallbackSCSV", config: serverConfig, // OpenSSL 1.0.1j is needed for the -fallback_scsv option. command: []string{"openssl", "s_client", "-fallback_scsv"}, expectHandshakeErrorIncluding: "inappropriate protocol fallback", } runServerTestTLS11(t, test) } // cert.pem and key.pem were generated with generate_cert.go // Thus, they have no ExtKeyUsage fields and trigger an error // when verification is turned on. const clientCertificatePEM = ` -----BEGIN CERTIFICATE----- MIIB7TCCAVigAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTExMTIwODA3NTUxMloXDTEyMTIwNzA4 MDAxMlowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGc MAsGCSqGSIb3DQEBAQOBjAAwgYgCgYBO0Hsx44Jk2VnAwoekXh6LczPHY1PfZpIG hPZk1Y/kNqcdK+izIDZFI7Xjla7t4PUgnI2V339aEu+H5Fto5OkOdOwEin/ekyfE ARl6vfLcPRSr0FTKIQzQTW6HLlzF0rtNS0/Otiz3fojsfNcCkXSmHgwa2uNKWi7e E5xMQIhZkwIDAQABozIwMDAOBgNVHQ8BAf8EBAMCAKAwDQYDVR0OBAYEBAECAwQw DwYDVR0jBAgwBoAEAQIDBDALBgkqhkiG9w0BAQUDgYEANh+zegx1yW43RmEr1b3A p0vMRpqBWHyFeSnIyMZn3TJWRSt1tukkqVCavh9a+hoV2cxVlXIWg7nCto/9iIw4 hB2rXZIxE0/9gzvGnfERYraL7KtnvshksBFQRlgXa5kc0x38BvEO5ZaoDPl4ILdE GFGNEH5PlGffo05wc46QkYU= -----END CERTIFICATE-----` const clientKeyPEM = ` -----BEGIN RSA PRIVATE KEY----- MIICWgIBAAKBgE7QezHjgmTZWcDCh6ReHotzM8djU99mkgaE9mTVj+Q2px0r6LMg NkUjteOVru3g9SCcjZXff1oS74fkW2jk6Q507ASKf96TJ8QBGXq98tw9FKvQVMoh DNBNbocuXMXSu01LT862LPd+iOx81wKRdKYeDBra40paLt4TnExAiFmTAgMBAAEC gYBxvXd8yNteFTns8A/2yomEMC4yeosJJSpp1CsN3BJ7g8/qTnrVPxBy+RU+qr63 t2WquaOu/cr5P8iEsa6lk20tf8pjKLNXeX0b1RTzK8rJLbS7nGzP3tvOhL096VtQ dAo4ROEaro0TzYpHmpciSvxVIeEIAAdFDObDJPKqcJAxyQJBAJizfYgK8Gzx9fsx hxp+VteCbVPg2euASH5Yv3K5LukRdKoSzHE2grUVQgN/LafC0eZibRanxHegYSr7 7qaswKUCQQCEIWor/X4XTMdVj3Oj+vpiw75y/S9gh682+myZL+d/02IEkwnB098P RkKVpenBHyrGg0oeN5La7URILWKj7CPXAkBKo6F+d+phNjwIFoN1Xb/RA32w/D1I saG9sF+UEhRt9AxUfW/U/tIQ9V0ZHHcSg1XaCM5Nvp934brdKdvTOKnJAkBD5h/3 Rybatlvg/fzBEaJFyq09zhngkxlZOUtBVTqzl17RVvY2orgH02U4HbCHy4phxOn7 qTdQRYlHRftgnWK1AkANibn9PRYJ7mJyJ9Dyj2QeNcSkSTzrt0tPvUMf4+meJymN 1Ntu5+S1DLLzfxlaljWG6ylW6DNxujCyuXIV2rvA -----END RSA PRIVATE KEY-----` const clientECDSACertificatePEM = ` -----BEGIN CERTIFICATE----- MIIB/DCCAV4CCQCaMIRsJjXZFzAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0 eSBMdGQwHhcNMTIxMTE0MTMyNTUzWhcNMjIxMTEyMTMyNTUzWjBBMQswCQYDVQQG EwJBVTEMMAoGA1UECBMDTlNXMRAwDgYDVQQHEwdQeXJtb250MRIwEAYDVQQDEwlK b2VsIFNpbmcwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABACVjJF1FMBexFe01MNv ja5oHt1vzobhfm6ySD6B5U7ixohLZNz1MLvT/2XMW/TdtWo+PtAd3kfDdq0Z9kUs jLzYHQFMH3CQRnZIi4+DzEpcj0B22uCJ7B0rxE4wdihBsmKo+1vx+U56jb0JuK7q ixgnTy5w/hOWusPTQBbNZU6sER7m8TAJBgcqhkjOPQQBA4GMADCBiAJCAOAUxGBg C3JosDJdYUoCdFzCgbkWqD8pyDbHgf9stlvZcPE4O1BIKJTLCRpS8V3ujfK58PDa 2RU6+b0DeoeiIzXsAkIBo9SKeDUcSpoj0gq+KxAxnZxfvuiRs9oa9V2jI/Umi0Vw jWVim34BmT0Y9hCaOGGbLlfk+syxis7iI6CH8OFnUes= -----END CERTIFICATE-----` const clientECDSAKeyPEM = ` -----BEGIN EC PARAMETERS----- BgUrgQQAIw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MIHcAgEBBEIBkJN9X4IqZIguiEVKMqeBUP5xtRsEv4HJEtOpOGLELwO53SD78Ew8 k+wLWoqizS3NpQyMtrU8JFdWfj+C57UNkOugBwYFK4EEACOhgYkDgYYABACVjJF1 FMBexFe01MNvja5oHt1vzobhfm6ySD6B5U7ixohLZNz1MLvT/2XMW/TdtWo+PtAd 3kfDdq0Z9kUsjLzYHQFMH3CQRnZIi4+DzEpcj0B22uCJ7B0rxE4wdihBsmKo+1vx +U56jb0JuK7qixgnTy5w/hOWusPTQBbNZU6sER7m8Q== -----END EC PRIVATE KEY-----` func TestClientAuth(t *testing.T) { var certPath, keyPath, ecdsaCertPath, ecdsaKeyPath string if *update { certPath = tempFile(clientCertificatePEM) defer os.Remove(certPath) keyPath = tempFile(clientKeyPEM) defer os.Remove(keyPath) ecdsaCertPath = tempFile(clientECDSACertificatePEM) defer os.Remove(ecdsaCertPath) ecdsaKeyPath = tempFile(clientECDSAKeyPEM) defer os.Remove(ecdsaKeyPath) } config := *testConfig config.ClientAuth = RequestClientCert test := &serverTest{ name: "ClientAuthRequestedNotGiven", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"}, config: &config, } runServerTestTLS12(t, test) test = &serverTest{ name: "ClientAuthRequestedAndGiven", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", certPath, "-key", keyPath}, config: &config, expectedPeerCerts: []string{clientCertificatePEM}, } runServerTestTLS12(t, test) test = &serverTest{ name: "ClientAuthRequestedAndECDSAGiven", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath}, config: &config, expectedPeerCerts: []string{clientECDSACertificatePEM}, } runServerTestTLS12(t, test) } func bigFromString(s string) *big.Int { ret := new(big.Int) ret.SetString(s, 10) return ret } func fromHex(s string) []byte { b, _ := hex.DecodeString(s) return b } var testRSACertificate = fromHex("30820263308201cca003020102020900a273000c8100cbf3300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302631173015060355040a130e476f6f676c652054455354494e47310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100af8788f6201b95656c14ab4405af3b4514e3b76dfd00634d957ffe6a623586c04af9187cf6aa255e7a64316600baf48e92afc76bd876d4f35f41cb6e5615971b97c13c123921663d2b16d1bcdb1cc0a7dab7caadbadacbd52150ecde8dabd16b814b8902f3c4bec16c89b14484bd21d1047d9d164df98215f6effad60947f2fb0203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e0412041012508d896f1bd1dc544d6ecb695e06f4301b0603551d23041430128010bf3db6a966f2b840cfeab40378481a4130190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b050003818100927caf91551218965931a64840d52dd5eebb02a0f5c21e7c9bb3307d3cdc76da4f3dc0faae2d33246b037b1b67591121b511bc77b9d9e06ea82d2e35fa645f223e63106bbeff14866d0df01531a814381e3b84872ccb98ed5176b9b14fdddb9b84048640fa51ddbab48debe346de46b94f86c7f9a4c24134acccf6eab0ab3918") var testRSACertificateIssuer = fromHex("3082024d308201b6a003020102020827326bd913b7c43d300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100f0429a7b9f66a222c8453800452db355b34c4409fee09af2510a6589bfa35bdb4d453200d1de24338d6d5e5a91cc8301628445d6eb4e675927b9c1ea5c0f676acfb0f708ce4f19827e321c1898bf86df9823d5f0b05df2b6779888eff8abbc7f41c6e7d2667386a579b8cbaad3f6fd597cd7c4b187911a425aed1b555c1965190203010001a37a3078300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e04120410bf3db6a966f2b840cfeab40378481a41301b0603551d23041430128010bf3db6a966f2b840cfeab40378481a41300d06092a864886f70d01010b050003818100586e68c1219ed4f5782b7cfd53cf1a55750a98781b2023f8694bb831fff6d7d4aad1f0ac782b1ec787f00a8956bdd06b4a1063444fcafe955c07d679163a730802c568886a2cf8a3c2ab41176957131c4b9e077ebd7ffbb91fdad8b08b932e9aeefac04923ffdc0aa145563f7f061995317400203578f350e3e566deb29dec5e") var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186000400c4a1edbe98f90b4873367ec316561122f23d53c33b4d213dcd6b75e6f6b0dc9adf26c1bcb287f072327cb3642f1c90bcea6823107efee325c0483a69e0286dd33700ef0462dd0da09c706283d881d36431aa9e9731bd96b068c09b23de76643f1a5c7fe9120e5858b65f70dd9bd8ead5d7f5d5ccb9b69f30665b669a20e227e5bffe3b300906072a8648ce3d040103818c0030818802420188a24febe245c5487d1bacf5ed989dae4770c05e1bb62fbdf1b64db76140d311a2ceee0b7e927eff769dc33b7ea53fcefa10e259ec472d7cacda4e970e15a06fd00242014dfcbe67139c2d050ebd3fa38c25c13313830d9406bbd4377af6ec7ac9862eddd711697f857c56defb31782be4c7780daecbbe9e4e3624317b6a0f399512078f2a") var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a3323030300e0603551d0f0101ff0404030200a0300d0603551d0e0406040401020304300f0603551d2304083006800401020304300b06092a864886f70d0101050381810089c6455f1c1f5ef8eb1ab174ee2439059f5c4259bb1a8d86cdb1d056f56a717da40e95ab90f59e8deaf627c157995094db0802266eb34fc6842dea8a4b68d9c1389103ab84fb9e1f85d9b5d23ff2312c8670fbb540148245a4ebafe264d90c8a4cf4f85b0fac12ac2fc4a3154bad52462868af96c62c6525d652b6e31845bdcc") var testRSAPrivateKey = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: bigFromString("123260960069105588390096594560395120585636206567569540256061833976822892593755073841963170165000086278069699238754008398039246547214989242849418349143232951701395321381739566687846006911427966669790845430647688107009232778985142860108863460556510585049041936029324503323373417214453307648498561956908810892027L"), E: 65537, }, D: bigFromString("73196363031103823625826315929954946106043759818067219550565550066527203472294428548476778865091068522665312037075674791871635825938217363523103946045078950060973913307430314113074463630778799389010335923241901501086246276485964417618981733827707048660375428006201525399194575538037883519254056917253456403553L"), Primes: []*big.Int{ bigFromString("11157426355495284553529769521954035649776033703833034489026848970480272318436419662860715175517581249375929775774910501512841707465207184924996975125010787L"), bigFromString("11047436580963564307160117670964629323534448585520694947919342920137706075617545637058809770319843170934495909554506529982972972247390145716507031692656521L"), }, } var testECDSAPrivateKey = &ecdsa.PrivateKey{ PublicKey: ecdsa.PublicKey{ Curve: elliptic.P521(), X: bigFromString("2636411247892461147287360222306590634450676461695221912739908880441342231985950069527906976759812296359387337367668045707086543273113073382714101597903639351"), Y: bigFromString("3204695818431246682253994090650952614555094516658732116404513121125038617915183037601737180082382202488628239201196033284060130040574800684774115478859677243"), }, D: bigFromString("5477294338614160138026852784385529180817726002953041720191098180813046231640184669647735805135001309477695746518160084669446643325196003346204701381388769751"), } ================================================ FILE: scan/crypto/tls/handshake_test.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "bufio" "encoding/hex" "errors" "flag" "fmt" "io" "net" "os" "strconv" "strings" "sync" ) // TLS reference tests run a connection against a reference implementation // (OpenSSL) of TLS and record the bytes of the resulting connection. The Go // code, during a test, is configured with deterministic randomness and so the // reference test can be reproduced exactly in the future. // // In order to save everyone who wishes to run the tests from needing the // reference implementation installed, the reference connections are saved in // files in the testdata directory. Thus running the tests involves nothing // external, but creating and updating them requires the reference // implementation. // // Tests can be updated by running them with the -update flag. This will cause // the test files. Generally one should combine the -update flag with -test.run // to updated a specific test. Since the reference implementation will always // generate fresh random numbers, large parts of the reference connection will // always change. var update = flag.Bool("update", false, "update golden files on disk") // recordingConn is a net.Conn that records the traffic that passes through it. // WriteTo can be used to produce output that can be later be loaded with // ParseTestData. type recordingConn struct { net.Conn sync.Mutex flows [][]byte reading bool } func (r *recordingConn) Read(b []byte) (n int, err error) { if n, err = r.Conn.Read(b); n == 0 { return } b = b[:n] r.Lock() defer r.Unlock() if l := len(r.flows); l == 0 || !r.reading { buf := make([]byte, len(b)) copy(buf, b) r.flows = append(r.flows, buf) } else { r.flows[l-1] = append(r.flows[l-1], b[:n]...) } r.reading = true return } func (r *recordingConn) Write(b []byte) (n int, err error) { if n, err = r.Conn.Write(b); n == 0 { return } b = b[:n] r.Lock() defer r.Unlock() if l := len(r.flows); l == 0 || r.reading { buf := make([]byte, len(b)) copy(buf, b) r.flows = append(r.flows, buf) } else { r.flows[l-1] = append(r.flows[l-1], b[:n]...) } r.reading = false return } // WriteTo writes Go source code to w that contains the recorded traffic. func (r *recordingConn) WriteTo(w io.Writer) { // TLS always starts with a client to server flow. clientToServer := true for i, flow := range r.flows { source, dest := "client", "server" if !clientToServer { source, dest = dest, source } fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest) dumper := hex.Dumper(w) dumper.Write(flow) dumper.Close() clientToServer = !clientToServer } } func parseTestData(r io.Reader) (flows [][]byte, err error) { var currentFlow []byte scanner := bufio.NewScanner(r) for scanner.Scan() { line := scanner.Text() // If the line starts with ">>> " then it marks the beginning // of a new flow. if strings.HasPrefix(line, ">>> ") { if len(currentFlow) > 0 || len(flows) > 0 { flows = append(flows, currentFlow) currentFlow = nil } continue } // Otherwise the line is a line of hex dump that looks like: // 00000170 fc f5 06 bf (...) |.....X{&?......!| // (Some bytes have been omitted from the middle section.) if i := strings.IndexByte(line, ' '); i >= 0 { line = line[i:] } else { return nil, errors.New("invalid test data") } if i := strings.IndexByte(line, '|'); i >= 0 { line = line[:i] } else { return nil, errors.New("invalid test data") } hexBytes := strings.Fields(line) for _, hexByte := range hexBytes { val, err := strconv.ParseUint(hexByte, 16, 8) if err != nil { return nil, errors.New("invalid hex byte in test data: " + err.Error()) } currentFlow = append(currentFlow, byte(val)) } } if len(currentFlow) > 0 { flows = append(flows, currentFlow) } return flows, nil } // tempFile creates a temp file containing contents and returns its path. func tempFile(contents string) string { file, err := os.CreateTemp("", "go-tls-test") if err != nil { panic("failed to create temp file: " + err.Error()) } path := file.Name() file.WriteString(contents) file.Close() return path } ================================================ FILE: scan/crypto/tls/key_agreement.go ================================================ // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/md5" "crypto/rsa" "crypto/sha1" "crypto/x509" "encoding/asn1" "errors" "io" "math/big" ) var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message") var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message") // rsaKeyAgreement implements the standard TLS key agreement where the client // encrypts the pre-master secret to the server's public key. type rsaKeyAgreement struct{} func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { return nil, nil } func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { if len(ckx.ciphertext) < 2 { return nil, errClientKeyExchange } ciphertext := ckx.ciphertext if version != VersionSSL30 { ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1]) if ciphertextLen != len(ckx.ciphertext)-2 { return nil, errClientKeyExchange } ciphertext = ckx.ciphertext[2:] } priv, ok := cert.PrivateKey.(crypto.Decrypter) if !ok { return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter") } // Perform constant time RSA PKCS#1 v1.5 decryption preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48}) if err != nil { return nil, err } // We don't check the version number in the premaster secret. For one, // by checking it, we would leak information about the validity of the // encrypted pre-master secret. Secondly, it provides only a small // benefit against a downgrade attack and some implementations send the // wrong version anyway. See the discussion at the end of section // 7.4.7.1 of RFC 4346. return preMasterSecret, nil } func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { return errors.New("tls: unexpected ServerKeyExchange") } func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { preMasterSecret := make([]byte, 48) preMasterSecret[0] = byte(clientHello.vers >> 8) preMasterSecret[1] = byte(clientHello.vers) _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) if err != nil { return nil, nil, err } encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret) if err != nil { return nil, nil, err } ckx := new(clientKeyExchangeMsg) ckx.ciphertext = make([]byte, len(encrypted)+2) ckx.ciphertext[0] = byte(len(encrypted) >> 8) ckx.ciphertext[1] = byte(len(encrypted)) copy(ckx.ciphertext[2:], encrypted) return preMasterSecret, ckx, nil } // sha1Hash calculates a SHA1 hash over the given byte slices. func sha1Hash(slices [][]byte) []byte { hsha1 := sha1.New() for _, slice := range slices { hsha1.Write(slice) } return hsha1.Sum(nil) } // md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the // concatenation of an MD5 and SHA1 hash. func md5SHA1Hash(slices [][]byte) []byte { md5sha1 := make([]byte, md5.Size+sha1.Size) hmd5 := md5.New() for _, slice := range slices { hmd5.Write(slice) } copy(md5sha1, hmd5.Sum(nil)) copy(md5sha1[md5.Size:], sha1Hash(slices)) return md5sha1 } // hashForServerKeyExchange hashes the given slices and returns their digest // and the identifier of the hash function used. The sigAndHash argument is // only used for >= TLS 1.2 and precisely identifies the hash function to use. func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) { if version >= VersionTLS12 { if !isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) { return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer") } hashFunc, err := lookupTLSHash(sigAndHash.hash) if err != nil { return nil, crypto.Hash(0), err } h := hashFunc.New() for _, slice := range slices { h.Write(slice) } digest := h.Sum(nil) return digest, hashFunc, nil } if sigAndHash.signature == signatureECDSA { return sha1Hash(slices), crypto.SHA1, nil } return md5SHA1Hash(slices), crypto.MD5SHA1, nil } // pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a // ServerKeyExchange given the signature type being used and the client's // advertised list of supported signature and hash combinations. func pickTLS12HashForSignature(sigType uint8, clientList []signatureAndHash) (uint8, error) { if len(clientList) == 0 { // If the client didn't specify any signature_algorithms // extension then we can assume that it supports SHA1. See // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 return hashSHA1, nil } for _, sigAndHash := range clientList { if sigAndHash.signature != sigType { continue } if isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) { return sigAndHash.hash, nil } } return 0, errors.New("tls: client doesn't support any common hash functions") } func curveForCurveID(id CurveID) (elliptic.Curve, bool) { switch id { case CurveP256: return elliptic.P256(), true case CurveP384: return elliptic.P384(), true case CurveP521: return elliptic.P521(), true default: return nil, false } } // ecdheRSAKeyAgreement implements a TLS key agreement where the server // generates a ephemeral EC public/private key pair and signs it. The // pre-master secret is then calculated using ECDH. The signature may // either be ECDSA or RSA. type ecdheKeyAgreement struct { version uint16 sigType uint8 privateKey []byte curve elliptic.Curve x, y *big.Int } func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { var curveid CurveID preferredCurves := config.curvePreferences() NextCandidate: for _, candidate := range preferredCurves { for _, c := range clientHello.supportedCurves { if candidate == c { curveid = c break NextCandidate } } } if curveid == 0 { return nil, errors.New("tls: no supported elliptic curves offered") } var ok bool if ka.curve, ok = curveForCurveID(curveid); !ok { return nil, errors.New("tls: preferredCurves includes unsupported curve") } var x, y *big.Int var err error ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand()) if err != nil { return nil, err } ecdhePublic := elliptic.Marshal(ka.curve, x, y) // http://tools.ietf.org/html/rfc4492#section-5.4 serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic)) serverECDHParams[0] = 3 // named curve serverECDHParams[1] = byte(curveid >> 8) serverECDHParams[2] = byte(curveid) serverECDHParams[3] = byte(len(ecdhePublic)) copy(serverECDHParams[4:], ecdhePublic) sigAndHash := signatureAndHash{signature: ka.sigType} if ka.version >= VersionTLS12 { if sigAndHash.hash, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil { return nil, err } } digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, hello.random, serverECDHParams) if err != nil { return nil, err } priv, ok := cert.PrivateKey.(crypto.Signer) if !ok { return nil, errors.New("tls: certificate private key does not implement crypto.Signer") } var sig []byte switch ka.sigType { case signatureECDSA: _, ok := priv.Public().(*ecdsa.PublicKey) if !ok { return nil, errors.New("ECDHE ECDSA requires an ECDSA server key") } case signatureRSA: _, ok := priv.Public().(*rsa.PublicKey) if !ok { return nil, errors.New("ECDHE RSA requires a RSA server key") } default: return nil, errors.New("unknown ECDHE signature algorithm") } sig, err = priv.Sign(config.rand(), digest, hashFunc) if err != nil { return nil, errors.New("failed to sign ECDHE parameters: " + err.Error()) } skx := new(serverKeyExchangeMsg) sigAndHashLen := 0 if ka.version >= VersionTLS12 { sigAndHashLen = 2 } skx.key = make([]byte, len(serverECDHParams)+sigAndHashLen+2+len(sig)) copy(skx.key, serverECDHParams) k := skx.key[len(serverECDHParams):] if ka.version >= VersionTLS12 { k[0] = sigAndHash.hash k[1] = sigAndHash.signature k = k[2:] } k[0] = byte(len(sig) >> 8) k[1] = byte(len(sig)) copy(k[2:], sig) return skx, nil } func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 { return nil, errClientKeyExchange } x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:]) if x == nil { return nil, errClientKeyExchange } if !ka.curve.IsOnCurve(x, y) { return nil, errClientKeyExchange } x, _ = ka.curve.ScalarMult(x, y, ka.privateKey) preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3) xBytes := x.Bytes() copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) return preMasterSecret, nil } func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { if len(skx.key) < 4 { return errServerKeyExchange } if skx.key[0] != 3 { // named curve return errors.New("tls: server selected unsupported curve") } curveid := CurveID(skx.key[1])<<8 | CurveID(skx.key[2]) var ok bool if ka.curve, ok = curveForCurveID(curveid); !ok { return errors.New("tls: server selected unsupported curve") } publicLen := int(skx.key[3]) if publicLen+4 > len(skx.key) { return errServerKeyExchange } ka.x, ka.y = elliptic.Unmarshal(ka.curve, skx.key[4:4+publicLen]) if ka.x == nil { return errServerKeyExchange } if !ka.curve.IsOnCurve(ka.x, ka.y) { return errServerKeyExchange } serverECDHParams := skx.key[:4+publicLen] sig := skx.key[4+publicLen:] if len(sig) < 2 { return errServerKeyExchange } sigAndHash := signatureAndHash{signature: ka.sigType} if ka.version >= VersionTLS12 { // handle SignatureAndHashAlgorithm sigAndHash = signatureAndHash{hash: sig[0], signature: sig[1]} if sigAndHash.signature != ka.sigType { return errServerKeyExchange } sig = sig[2:] if len(sig) < 2 { return errServerKeyExchange } } sigLen := int(sig[0])<<8 | int(sig[1]) if sigLen+2 != len(sig) { return errServerKeyExchange } sig = sig[2:] digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, serverHello.random, serverECDHParams) if err != nil { return err } switch ka.sigType { case signatureECDSA: pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey) if !ok { return errors.New("ECDHE ECDSA requires a ECDSA server public key") } ecdsaSig := new(ecdsaSignature) if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil { return err } if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { return errors.New("ECDSA signature contained zero or negative values") } if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) { return errors.New("ECDSA verification failure") } case signatureRSA: pubKey, ok := cert.PublicKey.(*rsa.PublicKey) if !ok { return errors.New("ECDHE RSA requires a RSA server public key") } if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil { return err } default: return errors.New("unknown ECDHE signature algorithm") } return nil } func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { if ka.curve == nil { return nil, nil, errors.New("missing ServerKeyExchange message") } priv, mx, my, err := elliptic.GenerateKey(ka.curve, config.rand()) if err != nil { return nil, nil, err } x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv) preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3) xBytes := x.Bytes() copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) serialized := elliptic.Marshal(ka.curve, mx, my) ckx := new(clientKeyExchangeMsg) ckx.ciphertext = make([]byte, 1+len(serialized)) ckx.ciphertext[0] = byte(len(serialized)) copy(ckx.ciphertext[1:], serialized) return preMasterSecret, ckx, nil } ================================================ FILE: scan/crypto/tls/prf.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "crypto" "crypto/hmac" "crypto/md5" "crypto/sha1" "crypto/sha256" "crypto/sha512" "errors" "hash" ) // Split a premaster secret in two as specified in RFC 4346, section 5. func splitPreMasterSecret(secret []byte) (s1, s2 []byte) { s1 = secret[0 : (len(secret)+1)/2] s2 = secret[len(secret)/2:] return } // pHash implements the P_hash function, as defined in RFC 4346, section 5. func pHash(result, secret, seed []byte, hash func() hash.Hash) { h := hmac.New(hash, secret) h.Write(seed) a := h.Sum(nil) j := 0 for j < len(result) { h.Reset() h.Write(a) h.Write(seed) b := h.Sum(nil) todo := len(b) if j+todo > len(result) { todo = len(result) - j } copy(result[j:j+todo], b) j += todo h.Reset() h.Write(a) a = h.Sum(nil) } } // prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5. func prf10(result, secret, label, seed []byte) { hashSHA1 := sha1.New hashMD5 := md5.New labelAndSeed := make([]byte, len(label)+len(seed)) copy(labelAndSeed, label) copy(labelAndSeed[len(label):], seed) s1, s2 := splitPreMasterSecret(secret) pHash(result, s1, labelAndSeed, hashMD5) result2 := make([]byte, len(result)) pHash(result2, s2, labelAndSeed, hashSHA1) for i, b := range result2 { result[i] ^= b } } // prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5. func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) { return func(result, secret, label, seed []byte) { labelAndSeed := make([]byte, len(label)+len(seed)) copy(labelAndSeed, label) copy(labelAndSeed[len(label):], seed) pHash(result, secret, labelAndSeed, hashFunc) } } // prf30 implements the SSL 3.0 pseudo-random function, as defined in // www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6. func prf30(result, secret, label, seed []byte) { hashSHA1 := sha1.New() hashMD5 := md5.New() done := 0 i := 0 // RFC5246 section 6.3 says that the largest PRF output needed is 128 // bytes. Since no more ciphersuites will be added to SSLv3, this will // remain true. Each iteration gives us 16 bytes so 10 iterations will // be sufficient. var b [11]byte for done < len(result) { for j := 0; j <= i; j++ { b[j] = 'A' + byte(i) } hashSHA1.Reset() hashSHA1.Write(b[:i+1]) hashSHA1.Write(secret) hashSHA1.Write(seed) digest := hashSHA1.Sum(nil) hashMD5.Reset() hashMD5.Write(secret) hashMD5.Write(digest) done += copy(result[done:], hashMD5.Sum(nil)) i++ } } const ( tlsRandomLength = 32 // Length of a random nonce in TLS 1.1. masterSecretLength = 48 // Length of a master secret in TLS 1.1. finishedVerifyLength = 12 // Length of verify_data in a Finished message. ) var masterSecretLabel = []byte("master secret") var keyExpansionLabel = []byte("key expansion") var clientFinishedLabel = []byte("client finished") var serverFinishedLabel = []byte("server finished") func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) { switch version { case VersionSSL30: return prf30, crypto.Hash(0) case VersionTLS10, VersionTLS11: return prf10, crypto.Hash(0) case VersionTLS12: if suite.flags&suiteSHA384 != 0 { return prf12(sha512.New384), crypto.SHA384 } return prf12(sha256.New), crypto.SHA256 default: panic("unknown version") } } func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) { prf, _ := prfAndHashForVersion(version, suite) return prf } // masterFromPreMasterSecret generates the master secret from the pre-master // secret. See http://tools.ietf.org/html/rfc5246#section-8.1 func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte { seed := make([]byte, 0, len(clientRandom)+len(serverRandom)) seed = append(seed, clientRandom...) seed = append(seed, serverRandom...) masterSecret := make([]byte, masterSecretLength) prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed) return masterSecret } // keysFromMasterSecret generates the connection keys from the master // secret, given the lengths of the MAC key, cipher key and IV, as defined in // RFC 2246, section 6.3. func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) { seed := make([]byte, 0, len(serverRandom)+len(clientRandom)) seed = append(seed, serverRandom...) seed = append(seed, clientRandom...) n := 2*macLen + 2*keyLen + 2*ivLen keyMaterial := make([]byte, n) prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed) clientMAC = keyMaterial[:macLen] keyMaterial = keyMaterial[macLen:] serverMAC = keyMaterial[:macLen] keyMaterial = keyMaterial[macLen:] clientKey = keyMaterial[:keyLen] keyMaterial = keyMaterial[keyLen:] serverKey = keyMaterial[:keyLen] keyMaterial = keyMaterial[keyLen:] clientIV = keyMaterial[:ivLen] keyMaterial = keyMaterial[ivLen:] serverIV = keyMaterial[:ivLen] return } // lookupTLSHash looks up the corresponding crypto.Hash for a given // TLS hash identifier. func lookupTLSHash(hash uint8) (crypto.Hash, error) { switch hash { case hashSHA1: return crypto.SHA1, nil case hashSHA256: return crypto.SHA256, nil case hashSHA384: return crypto.SHA384, nil default: return 0, errors.New("tls: unsupported hash algorithm") } } func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash { var buffer []byte if version == VersionSSL30 || version >= VersionTLS12 { buffer = []byte{} } prf, hash := prfAndHashForVersion(version, cipherSuite) if hash != 0 { return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf} } return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf} } // A finishedHash calculates the hash of a set of handshake messages suitable // for including in a Finished message. type finishedHash struct { client hash.Hash server hash.Hash // Prior to TLS 1.2, an additional MD5 hash is required. clientMD5 hash.Hash serverMD5 hash.Hash // In TLS 1.2, a full buffer is sadly required. buffer []byte version uint16 prf func(result, secret, label, seed []byte) } func (h *finishedHash) Write(msg []byte) (n int, err error) { h.client.Write(msg) h.server.Write(msg) if h.version < VersionTLS12 { h.clientMD5.Write(msg) h.serverMD5.Write(msg) } if h.buffer != nil { h.buffer = append(h.buffer, msg...) } return len(msg), nil } func (h finishedHash) Sum() []byte { if h.version >= VersionTLS12 { return h.client.Sum(nil) } out := make([]byte, 0, md5.Size+sha1.Size) out = h.clientMD5.Sum(out) return h.client.Sum(out) } // finishedSum30 calculates the contents of the verify_data member of a SSLv3 // Finished message given the MD5 and SHA1 hashes of a set of handshake // messages. func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte { md5.Write(magic) md5.Write(masterSecret) md5.Write(ssl30Pad1[:]) md5Digest := md5.Sum(nil) md5.Reset() md5.Write(masterSecret) md5.Write(ssl30Pad2[:]) md5.Write(md5Digest) md5Digest = md5.Sum(nil) sha1.Write(magic) sha1.Write(masterSecret) sha1.Write(ssl30Pad1[:40]) sha1Digest := sha1.Sum(nil) sha1.Reset() sha1.Write(masterSecret) sha1.Write(ssl30Pad2[:40]) sha1.Write(sha1Digest) sha1Digest = sha1.Sum(nil) ret := make([]byte, len(md5Digest)+len(sha1Digest)) copy(ret, md5Digest) copy(ret[len(md5Digest):], sha1Digest) return ret } var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54} var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52} // clientSum returns the contents of the verify_data member of a client's // Finished message. func (h finishedHash) clientSum(masterSecret []byte) []byte { if h.version == VersionSSL30 { return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:]) } out := make([]byte, finishedVerifyLength) h.prf(out, masterSecret, clientFinishedLabel, h.Sum()) return out } // serverSum returns the contents of the verify_data member of a server's // Finished message. func (h finishedHash) serverSum(masterSecret []byte) []byte { if h.version == VersionSSL30 { return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:]) } out := make([]byte, finishedVerifyLength) h.prf(out, masterSecret, serverFinishedLabel, h.Sum()) return out } // selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a // client's CertificateVerify with, or an error if none can be found. func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) { if h.version < VersionTLS12 { // Nothing to negotiate before TLS 1.2. return signatureAndHash{signature: sigType}, nil } for _, v := range serverList { if v.signature == sigType && isSupportedSignatureAndHash(v, supportedSignatureAlgorithms) { return v, nil } } return signatureAndHash{}, errors.New("tls: no supported signature algorithm found for signing client certificate") } // hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash // id suitable for signing by a TLS client certificate. func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash, masterSecret []byte) ([]byte, crypto.Hash, error) { if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil { panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer") } if h.version == VersionSSL30 { if signatureAndHash.signature != signatureRSA { return nil, 0, errors.New("tls: unsupported signature type for client certificate") } md5Hash := md5.New() md5Hash.Write(h.buffer) sha1Hash := sha1.New() sha1Hash.Write(h.buffer) return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil } if h.version >= VersionTLS12 { hashAlg, err := lookupTLSHash(signatureAndHash.hash) if err != nil { return nil, 0, err } hash := hashAlg.New() hash.Write(h.buffer) return hash.Sum(nil), hashAlg, nil } if signatureAndHash.signature == signatureECDSA { return h.server.Sum(nil), crypto.SHA1, nil } return h.Sum(), crypto.MD5SHA1, nil } // discardHandshakeBuffer is called when there is no more need to // buffer the entirety of the handshake messages. func (h *finishedHash) discardHandshakeBuffer() { h.buffer = nil } ================================================ FILE: scan/crypto/tls/prf_test.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "encoding/hex" "testing" ) type testSplitPreMasterSecretTest struct { in, out1, out2 string } var testSplitPreMasterSecretTests = []testSplitPreMasterSecretTest{ {"", "", ""}, {"00", "00", "00"}, {"0011", "00", "11"}, {"001122", "0011", "1122"}, {"00112233", "0011", "2233"}, } func TestSplitPreMasterSecret(t *testing.T) { for i, test := range testSplitPreMasterSecretTests { in, _ := hex.DecodeString(test.in) out1, out2 := splitPreMasterSecret(in) s1 := hex.EncodeToString(out1) s2 := hex.EncodeToString(out2) if s1 != test.out1 || s2 != test.out2 { t.Errorf("#%d: got: (%s, %s) want: (%s, %s)", i, s1, s2, test.out1, test.out2) } } } type testKeysFromTest struct { version uint16 suite *cipherSuite preMasterSecret string clientRandom, serverRandom string masterSecret string clientMAC, serverMAC string clientKey, serverKey string macLen, keyLen int } func TestKeysFromPreMasterSecret(t *testing.T) { for i, test := range testKeysFromTests { in, _ := hex.DecodeString(test.preMasterSecret) clientRandom, _ := hex.DecodeString(test.clientRandom) serverRandom, _ := hex.DecodeString(test.serverRandom) masterSecret := masterFromPreMasterSecret(test.version, test.suite, in, clientRandom, serverRandom) if s := hex.EncodeToString(masterSecret); s != test.masterSecret { t.Errorf("#%d: bad master secret %s, want %s", i, s, test.masterSecret) continue } clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, test.suite, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0) clientMACString := hex.EncodeToString(clientMAC) serverMACString := hex.EncodeToString(serverMAC) clientKeyString := hex.EncodeToString(clientKey) serverKeyString := hex.EncodeToString(serverKey) if clientMACString != test.clientMAC || serverMACString != test.serverMAC || clientKeyString != test.clientKey || serverKeyString != test.serverKey { t.Errorf("#%d: got: (%s, %s, %s, %s) want: (%s, %s, %s, %s)", i, clientMACString, serverMACString, clientKeyString, serverKeyString, test.clientMAC, test.serverMAC, test.clientKey, test.serverKey) } } } func cipherSuiteById(id uint16) *cipherSuite { for _, cipherSuite := range cipherSuites { if cipherSuite.id == id { return cipherSuite } } panic("ciphersuite not found") } // These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 ` var testKeysFromTests = []testKeysFromTest{ { VersionTLS10, cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA), "0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5", "4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558", "4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db", "3d851bab6e5556e959a16bc36d66cfae32f672bfa9ecdef6096cbb1b23472df1da63dbbd9827606413221d149ed08ceb", "805aaa19b3d2c0a0759a4b6c9959890e08480119", "2d22f9fe519c075c16448305ceee209fc24ad109", "d50b5771244f850cd8117a9ccafe2cf1", "e076e33206b30507a85c32855acd0919", 20, 16, }, { VersionTLS10, cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA), "03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890", "4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106", "4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c", "7d64be7c80c59b740200b4b9c26d0baaa1c5ae56705acbcf2307fe62beb4728c19392c83f20483801cce022c77645460", "97742ed60a0554ca13f04f97ee193177b971e3b0", "37068751700400e03a8477a5c7eec0813ab9e0dc", "207cddbc600d2a200abac6502053ee5c", "df3f94f6e1eacc753b815fe16055cd43", 20, 16, }, { VersionTLS10, cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA), "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1", "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e", "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e", "1aff2e7a2c4279d0126f57a65a77a8d9d0087cf2733366699bec27eb53d5740705a8574bb1acc2abbe90e44f0dd28d6c", "3c7647c93c1379a31a609542aa44e7f117a70085", "0d73102994be74a575a3ead8532590ca32a526d4", "ac7581b0b6c10d85bbd905ffbf36c65e", "ff07edde49682b45466bd2e39464b306", 20, 16, }, { VersionSSL30, cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA), "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1", "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e", "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e", "a614863e56299dcffeea2938f22c2ba023768dbe4b3f6877bc9c346c6ae529b51d9cb87ff9695ea4d01f2205584405b2", "2c450d5b6f6e2013ac6bea6a0b32200d4e1ffb94", "7a7a7438769536f2fb1ae49a61f0703b79b2dc53", "f8f6b26c10f12855c9aafb1e0e839ccf", "2b9d4b4a60cb7f396780ebff50650419", 20, 16, }, } ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 01 00 59 02 00 00 55 03 01 38 1a 94 8d 84 |....Y...U..8....| 00000010 d7 a4 29 89 50 ad 07 97 5b c0 2c 7b 8c a6 75 0e |..).P...[.,{..u.| 00000020 97 51 62 10 07 87 c5 6f 0a 5f 86 20 1d ac 1d 05 |.Qb....o._. ....| 00000030 ea 85 48 84 73 d9 07 8d d0 81 56 99 81 10 7b 18 |..H.s.....V...{.| 00000040 e8 5e da a9 fe cd f9 91 88 31 9b 6e c0 09 00 00 |.^.......1.n....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| 00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0| 00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| 000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| 000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| 000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| 000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506| 000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063| 000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A| 00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some| 00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...| 00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit| 00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...| 00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..| 00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.| 00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.| 00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d| 00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i| 00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.| 000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#| 000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.| 000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.| 000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=| 000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.| 000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^| 00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......| 00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y| 00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.| 00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3| 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| 00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 68 |*............A.h| 00000280 37 18 3d 57 d2 5a 39 75 1e 7f 0a 3a 47 65 36 2e |7.=W.Z9u...:Ge6.| 00000290 6d cb 8f aa 0f 0d 45 5e 3f 14 82 f5 8c b1 11 0a |m.....E^?.......| 000002a0 8f e0 bc e4 07 d3 d5 bf 2d f4 82 ba cf c9 1c 88 |........-.......| 000002b0 33 72 a8 49 39 48 40 74 c6 96 c3 30 72 31 34 00 |3r.I9H@t...0r14.| 000002c0 8a 30 81 87 02 41 0e 43 2d 29 81 e9 c3 07 fc 5c |.0...A.C-).....\| 000002d0 ad c0 51 9e 0f cf c5 77 e4 bf 00 b6 66 f9 0e c6 |..Q....w....f...| 000002e0 40 c6 b5 49 a4 04 05 31 2c 7c 1f 24 38 80 1b 3f |@..I...1,|.$8..?| 000002f0 16 5f c7 4d a8 7d 98 50 7f 7d 6d ed e9 19 1d 19 |._.M.}.P.}m.....| 00000300 7b fd ec c5 4d 18 ab 02 42 01 00 db 37 b7 fa 39 |{...M...B...7..9| 00000310 4b 3f 16 06 eb b8 4a 22 c6 de 00 d8 a7 eb a2 9e |K?....J"........| 00000320 e1 6f f4 a4 32 e2 ca d0 72 3a e5 f3 14 27 a0 dd |.o..2...r:...'..| 00000330 c4 26 34 b3 6c a3 d0 03 90 7a 2e 0e bf 0b 63 63 |.&4.l....z....cc| 00000340 77 66 37 dd 1a 0f 7a 90 3f c8 a9 16 03 01 00 0e |wf7...z.?.......| 00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |.......@......| >>> Flow 3 (client to server) 00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| 00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1| 00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.| 00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat| 00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte| 00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty| 00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413| 00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132| 00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...| 000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS| 000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm| 000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo| 000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.| 000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....| 000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.| 00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N| 00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..| 00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.| 00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J| 00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A| 00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......| 00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN| 00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..| 00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.| 00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?| 000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH| 000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........| 000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...| 000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._| 000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.| 000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W| 00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..| 00000210 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d 19 |...F...BA...7...| 00000220 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..| 00000230 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..| 00000240 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.| 00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 90 0f |.h.A.Vk.Z.......| 00000260 00 00 8c 00 8a 30 81 87 02 41 51 c5 53 a8 0f cb |.....0...AQ.S...| 00000270 18 79 4a 59 53 62 17 bb 29 39 fa cd 56 6c 5c 29 |.yJYSb..)9..Vl\)| 00000280 1f e3 bc df fb 9a 29 fa 38 1a 73 aa 4c 79 6b 1c |......).8.s.Lyk.| 00000290 9f 1c 8e 95 c7 11 cc df 5d e9 c7 93 ce a3 9b e6 |........].......| 000002a0 94 17 24 3a 8e f8 9a a9 46 01 f9 02 42 01 a1 df |..$:....F...B...| 000002b0 c5 cc fe 8d 5b 34 fb 89 2f f5 b3 3f 75 d7 19 1b |....[4../..?u...| 000002c0 5e 0f 1a 2e 8f 2d 62 61 73 85 2c 03 3b 22 07 2f |^....-bas.,.;"./| 000002d0 6b f3 5c fb ba b2 87 54 1c ef d2 f8 82 f3 9e f8 |k.\....T........| 000002e0 ce 1b fa ce b0 6d d0 85 f8 62 6e d6 ba 93 cc 14 |.....m...bn.....| 000002f0 03 01 00 01 01 16 03 01 00 30 76 90 a8 a2 8d 25 |.........0v....%| 00000300 c5 c2 ff ef 2b 76 83 2c 7a 0d 44 37 99 67 02 d3 |....+v.,z.D7.g..| 00000310 6e 3b 28 83 21 cf f5 6a 71 61 2d 5b 24 57 b2 19 |n;(.!..jqa-[$W..| 00000320 63 d4 e5 96 0c 0c e1 f3 3a 99 |c.......:.| >>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 30 37 f0 ad 4c 11 |..........07..L.| 00000010 6d fb 54 90 13 d2 10 93 43 d8 be 3b d0 2b 14 a5 |m.T.....C..;.+..| 00000020 9d fb a6 5d 38 e0 f5 e9 a6 0a 8e 3d 99 a2 ec 96 |...]8......=....| 00000030 d8 ff 90 13 03 99 33 d7 15 29 5f |......3..)_| >>> Flow 5 (client to server) 00000000 17 03 01 00 20 f9 59 b0 e2 8b f9 2c dd 30 1b 8f |.... .Y....,.0..| 00000010 df 85 0f 17 88 23 5e ca c9 d3 ca 5f 52 d4 33 e0 |.....#^...._R.3.| 00000020 d2 62 54 17 f2 17 03 01 00 20 62 2d 28 d2 55 68 |.bT...... b-(.Uh| 00000030 77 ab 6e c0 ac d9 cd 31 1c 38 aa 07 b3 e8 0d 89 |w.n....1.8......| 00000040 7e e4 f3 a0 65 84 f6 b8 c8 91 15 03 01 00 20 b5 |~...e......... .| 00000050 95 69 90 d7 32 d1 5a a5 e0 e2 6c 0a dc 00 1c 5e |.i..2.Z...l....^| 00000060 d2 10 2b a2 3e ae a5 b2 63 9f c4 4e 62 56 db |..+.>...c..NbV.| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 01 00 51 02 00 00 4d 03 01 4e 15 d3 06 f6 |....Q...M..N....| 00000010 ec 13 16 c5 fa 59 cf 5e 2f ad 85 b9 38 e7 7f fb |.....Y.^/...8...| 00000020 85 cb da eb f2 2e 17 51 a2 b0 be 20 61 e4 32 c9 |.......Q... a.2.| 00000030 66 92 36 89 0c 0c f4 00 15 47 86 d9 e9 90 ab 2d |f.6......G.....-| 00000040 8f a3 e2 5e f6 44 2c 6a 1d 98 88 5c 00 05 00 00 |...^.D,j...\....| 00000050 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.| 00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....| 000002d0 0e 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |........@......| >>> Flow 3 (client to server) 00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| 00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1| 00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.| 00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat| 00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte| 00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty| 00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413| 00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132| 00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...| 000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS| 000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm| 000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo| 000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.| 000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....| 000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.| 00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N| 00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..| 00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.| 00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J| 00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A| 00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......| 00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN| 00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..| 00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.| 00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?| 000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH| 000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........| 000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...| 000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._| 000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.| 000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W| 00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..| 00000210 03 01 00 86 10 00 00 82 00 80 73 bd 73 65 92 86 |..........s.se..| 00000220 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 87 |#A.y......M.....| 00000230 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 53 |.2R.k..-.......S| 00000240 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 fe |.m.....o..#87...| 00000250 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 65 |...U...`}p&..T.e| 00000260 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 ff |...S_..:.3{.L...| 00000270 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b 52 |Z.6*G.....1x..kR| 00000280 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 4d |..........+.8..M| 00000290 e5 78 13 4e a4 38 46 42 dc 16 16 03 01 00 91 0f |.x.N.8FB........| 000002a0 00 00 8d 00 8b 30 81 88 02 42 01 45 b9 8f b1 1f |.....0...B.E....| 000002b0 72 80 2c 4f 2c 65 58 db 40 7e f1 d5 14 0b cc 4c |r.,O,eX.@~.....L| 000002c0 8b 50 5c ee 93 45 95 3d fe 00 5e 5e ca 13 56 8d |.P\..E.=..^^..V.| 000002d0 2b b3 1a 22 70 3f d2 41 cf 74 8f c3 0f 37 ba 97 |+.."p?.A.t...7..| 000002e0 cb 29 16 77 92 df 19 35 f9 8a a0 8e 02 42 01 00 |.).w...5.....B..| 000002f0 3f 8b ce b1 2a 01 43 e8 2c b5 27 d1 19 bc 04 b3 |?...*.C.,.'.....| 00000300 c3 ad bf e8 12 37 57 6f c9 01 7c 8e f4 4d 88 39 |.....7Wo..|..M.9| 00000310 4b 00 f6 ff fd 38 39 f8 3e 7f 49 d4 6a 82 94 6a |K....89.>.I.j..j| 00000320 d3 f4 17 f2 a9 e0 ef 85 1e 01 85 b6 ca 89 91 ee |................| 00000330 14 03 01 00 01 01 16 03 01 00 24 8d 82 24 82 55 |..........$..$.U| 00000340 c4 0e 45 8c f0 f3 e3 29 4e ff 6c ee 43 4b ca 68 |..E....)N.l.CK.h| 00000350 2e 12 98 cf ce b6 7e fa 73 07 e1 0f aa 7f 80 |......~.s......| >>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 24 21 a3 eb a6 f5 |..........$!....| 00000010 d0 17 38 9b 89 ec f3 39 23 33 f6 49 51 41 97 92 |..8....9#3.IQA..| 00000020 a6 64 bd 60 68 9d 0e 45 06 2f dd ff 79 b6 50 |.d.`h..E./..y.P| >>> Flow 5 (client to server) 00000000 17 03 01 00 1a d2 72 d5 91 9d fc 6c 22 02 cc 32 |......r....l"..2| 00000010 58 5c 8a f6 75 11 48 e1 3f e4 e5 81 29 63 62 15 |X\..u.H.?...)cb.| 00000020 03 01 00 16 b6 9a 1f 43 d4 ae b7 16 25 ce ae b7 |.......C....%...| 00000030 6c 37 f7 35 0a 26 7d ea 1f 80 |l7.5.&}...| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 01 00 59 02 00 00 55 03 01 eb ed 76 6a 07 |....Y...U....vj.| 00000010 65 02 ec 6f 93 a0 38 21 09 0d d7 bf 11 20 51 eb |e..o..8!..... Q.| 00000020 cc 00 08 9b 7a 98 c4 c5 02 ff c1 20 f9 1b c7 66 |....z...... ...f| 00000030 35 40 8c 67 8d 7f d5 c8 28 f0 cb d2 f9 da af 7a |5@.g....(......z| 00000040 ea 4e 42 f2 5d 44 1c cc 92 36 b1 10 c0 09 00 00 |.NB.]D...6......| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| 00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0| 00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| 000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| 000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| 000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| 000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506| 000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063| 000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A| 00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some| 00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...| 00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit| 00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...| 00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..| 00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.| 00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.| 00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d| 00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i| 00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.| 000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#| 000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.| 000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.| 000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=| 000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.| 000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^| 00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......| 00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y| 00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.| 00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3| 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| 00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 34 |*............A.4| 00000280 47 57 64 b3 20 6d eb 17 9c 36 d4 aa 78 8b 20 26 |GWd. m...6..x. &| 00000290 6f 22 10 79 5f 96 69 62 1d ae 9f c7 40 17 1e 30 |o".y_.ib....@..0| 000002a0 10 db d1 13 51 d8 63 61 ef 8e fb 34 d6 02 95 ac |....Q.ca...4....| 000002b0 fb 33 72 a9 46 ff 27 b1 15 ca dd 81 8f 5a 58 00 |.3r.F.'......ZX.| 000002c0 8a 30 81 87 02 41 5c 09 1a 87 40 f3 1a 87 84 31 |.0...A\...@....1| 000002d0 62 6c e5 a5 c0 3c cc ba 5d 4a 5e 65 ea e0 60 83 |bl...<..]J^e..`.| 000002e0 fe fe 99 1d 66 4a bb 6c 0d 5e 25 64 e3 92 ce eb |....fJ.l.^%d....| 000002f0 15 39 42 a6 b0 98 a1 d3 79 65 c7 fc e7 c7 64 c7 |.9B.....ye....d.| 00000300 69 9c 2f 7e 00 c1 a3 02 42 01 f2 61 91 ae 8e f6 |i./~....B..a....| 00000310 88 99 70 55 32 4a fe 08 31 f0 8d d6 e6 1d fa a1 |..pU2J..1.......| 00000320 76 b6 16 98 58 8e 46 30 b1 00 b6 dd 5d 70 bb e1 |v...X.F0....]p..| 00000330 81 89 bd aa ac b5 7f 9b d3 c0 8b 4b c3 36 00 87 |...........K.6..| 00000340 47 0c 34 92 27 c3 aa bd 0d 7c 36 16 03 01 00 0e |G.4.'....|6.....| 00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |.......@......| >>> Flow 3 (client to server) 00000000 16 03 01 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| 00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.| 00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| 00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0| 00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807| 00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080| 00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...| 00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.| 00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0| 000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........| 000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.| 000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...| 000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.| 000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...| 000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..| 00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn| 00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..| 00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...| 00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000| 00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0| 00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.| 00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0| 00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........| 00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....| 00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2| 000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...| 000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.| 000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.| 000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..| 000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.| 000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....| 00000200 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 86 |..h.A.Vk.Z......| 00000250 0f 00 00 82 00 80 1e 4d 89 4e e2 82 ca 5d 31 8a |.......M.N...]1.| 00000260 66 c7 c2 d6 00 4d 2e 1e 94 34 61 6b 86 3d 78 60 |f....M...4ak.=x`| 00000270 70 e1 71 93 22 df 5d 81 d3 d7 33 10 f5 01 f9 1d |p.q.".]...3.....| 00000280 e2 4a 91 22 67 ae 5b 2f 4c d9 43 31 35 c6 01 ad |.J."g.[/L.C15...| 00000290 59 86 03 a1 9b c5 ea a5 2d aa ef 46 5a a8 70 57 |Y.......-..FZ.pW| 000002a0 50 59 ea 7a 07 32 bb a6 a1 11 33 05 d8 88 2e 42 |PY.z.2....3....B| 000002b0 d8 7b f7 34 be 5e 5f 42 9f 6a 90 ed d7 4b c4 7e |.{.4.^_B.j...K.~| 000002c0 f9 5c a5 ff 28 f8 a1 f1 8f 1c e0 7a 37 a0 49 e5 |.\..(......z7.I.| 000002d0 ce 11 46 ef 5f 06 14 03 01 00 01 01 16 03 01 00 |..F._...........| 000002e0 30 cb 08 f0 3c d4 21 f2 3a 7d db 59 75 80 48 24 |0...<.!.:}.Yu.H$| 000002f0 27 6f 2c 26 50 a4 7d 6c 91 d5 5d f7 c9 b4 bd 15 |'o,&P.}l..].....| 00000300 a8 8a 12 d5 40 8c 9a 0f 56 67 66 89 dd 12 36 d8 |....@...Vgf...6.| 00000310 d3 |.| >>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 30 02 e3 be 9d 2d |..........0....-| 00000010 6f 2c 9a b7 b4 f1 a5 30 ec 3e ae 05 e6 02 19 2f |o,.....0.>...../| 00000020 a4 ac d1 6e ac de 75 4e cc 14 e6 78 5a ea 27 7f |...n..uN...xZ.'.| 00000030 4e 45 c4 9d b2 da a6 ea b7 d2 7e |NE........~| >>> Flow 5 (client to server) 00000000 17 03 01 00 20 e0 71 e9 54 11 6e 48 4b be a2 2a |.... .q.T.nHK..*| 00000010 b1 70 d2 2c 74 c0 f4 74 05 f1 d3 d6 84 29 58 f7 |.p.,t..t.....)X.| 00000020 87 90 84 2b c8 17 03 01 00 20 b6 a2 e9 e0 f0 0d |...+..... ......| 00000030 d5 ef d7 32 6d cb 99 5d a6 37 c2 6e f9 c3 8e 6f |...2m..].7.n...o| 00000040 76 71 d8 a6 c5 ae 4e 04 77 06 15 03 01 00 20 f2 |vq....N.w..... .| 00000050 09 ab dc 37 90 78 3a 2a 41 ab 9b a9 c1 78 2a 64 |...7.x:*A....x*d| 00000060 a8 3f 21 c4 bb af 76 b3 c6 2f e1 20 a3 b1 1e |.?!...v../. ...| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 01 00 51 02 00 00 4d 03 01 e5 d7 4b 56 7b |....Q...M....KV{| 00000010 a8 2c 07 33 fc 66 d7 79 e9 26 91 56 7d 9d 99 1d |.,.3.f.y.&.V}...| 00000020 b2 24 36 2c f6 78 3a e7 63 15 f6 20 9f e1 d4 07 |.$6,.x:.c.. ....| 00000030 a9 75 3d b9 3b 8c 46 cb a7 37 36 56 af 4e 99 cf |.u=.;.F..76V.N..| 00000040 90 49 e1 e9 69 25 81 0f fd 22 48 e6 00 05 00 00 |.I..i%..."H.....| 00000050 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.| 00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....| 000002d0 0e 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |........@......| >>> Flow 3 (client to server) 00000000 16 03 01 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| 00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.| 00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| 00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0| 00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807| 00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080| 00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...| 00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.| 00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0| 000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........| 000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.| 000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...| 000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.| 000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...| 000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..| 00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn| 00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..| 00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...| 00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000| 00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0| 00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.| 00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0| 00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........| 00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....| 00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2| 000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...| 000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.| 000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.| 000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..| 000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.| 000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....| 00000200 16 03 01 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.| 00000210 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....| 00000220 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......| 00000230 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..| 00000240 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.| 00000250 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..| 00000260 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k| 00000270 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..| 00000280 4d e5 78 13 4e a4 38 46 42 dc 16 16 03 01 00 86 |M.x.N.8FB.......| 00000290 0f 00 00 82 00 80 3d f7 ff c1 72 82 b8 90 42 a3 |......=...r...B.| 000002a0 10 24 b5 01 44 60 98 39 e4 36 86 56 09 55 e5 73 |.$..D`.9.6.V.U.s| 000002b0 3a d9 9d 00 ae 05 23 6f 78 4e 49 28 c1 cc 7a ff |:.....#oxNI(..z.| 000002c0 8f 67 92 cd 94 c0 d2 68 7f 48 ec 10 83 48 9e 02 |.g.....h.H...H..| 000002d0 b8 10 b2 1b f0 ba 8f 5a c8 85 d9 19 53 c2 8d 37 |.......Z....S..7| 000002e0 8e 86 4c ca ee 0f c4 97 20 f9 a5 4e 94 b8 c5 c5 |..L..... ..N....| 000002f0 53 0c c1 b6 e5 a1 4e d6 15 b3 6b 08 c2 25 c3 de |S.....N...k..%..| 00000300 e7 69 85 85 56 31 16 ad 68 7e 00 8f 1b fc f8 9f |.i..V1..h~......| 00000310 d7 50 87 08 0d c5 14 03 01 00 01 01 16 03 01 00 |.P..............| 00000320 24 eb 0c f3 4f 56 04 e3 54 b0 a8 e4 bb af 3a 44 |$...OV..T.....:D| 00000330 c7 d6 f0 24 2f fc e6 79 93 f4 4e ec c5 1f 5b 99 |...$/..y..N...[.| 00000340 32 37 c2 f1 ad |27...| >>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 24 75 ac 09 a6 28 |..........$u...(| 00000010 60 ce 7f 81 a2 75 86 af 84 95 dc 3f e1 07 1c 02 |`....u.....?....| 00000020 bc 3c 90 db 1e 1a 35 06 93 60 22 69 b9 05 bb |.<....5..`"i...| >>> Flow 5 (client to server) 00000000 17 03 01 00 1a f4 67 a7 d8 0a 67 8d 3a 11 53 7e |......g...g.:.S~| 00000010 49 91 bf 92 85 e0 35 24 25 72 92 26 63 9b 09 15 |I.....5$%r.&c...| 00000020 03 01 00 16 98 bb a0 ca 40 70 26 6f 2d 73 35 3d |........@p&o-s5=| 00000030 90 8c ff 01 e0 b1 50 52 e3 57 |......PR.W| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 01 00 59 02 00 00 55 03 01 78 09 57 86 09 |....Y...U..x.W..| 00000010 64 7e 35 c7 c7 b9 44 9c 09 ae f0 49 cb 1c 1f 58 |d~5...D....I...X| 00000020 89 ef 65 16 9e 32 73 cd 4d 1b 8f 20 10 4d 5b cf |..e..2s.M.. .M[.| 00000030 d0 24 59 dd e8 47 c9 a2 ad 9c 98 b5 eb 16 46 6b |.$Y..G........Fk| 00000040 7d 33 6e 53 0a 3d 81 71 a1 bc 43 7a c0 09 00 00 |}3nS.=.q..Cz....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| 00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0| 00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| 000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| 000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| 000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| 000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506| 000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063| 000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A| 00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some| 00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...| 00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit| 00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...| 00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..| 00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.| 00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.| 00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d| 00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i| 00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.| 000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#| 000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.| 000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.| 000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=| 000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.| 000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^| 00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......| 00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y| 00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.| 00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3| 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| 00000270 2a 16 03 01 00 d6 0c 00 00 d2 03 00 17 41 04 51 |*............A.Q| 00000280 39 70 43 9c 01 de 29 df 3c d0 f8 31 54 70 34 53 |9pC...).<..1Tp4S| 00000290 0e ab e8 e0 b0 8b 21 66 63 ac a9 68 7c 92 6f f8 |......!fc..h|.o.| 000002a0 cf a3 ba cb 6d 39 f4 5c f5 2e ff 1d d7 1b b9 e7 |....m9.\........| 000002b0 08 13 59 f8 64 7e 23 e0 1d 04 cf 37 47 d6 b7 00 |..Y.d~#....7G...| 000002c0 8b 30 81 88 02 42 01 cd 1d 01 46 68 da 4c b6 0d |.0...B....Fh.L..| 000002d0 67 05 39 0d aa 6c c5 40 e4 5d bf 4f 2a 92 78 8d |g.9..l.@.].O*.x.| 000002e0 08 0e c0 07 8c 68 cc 55 4e 54 a9 9d 22 f9 a6 4a |.....h.UNT.."..J| 000002f0 e4 38 9f 53 4a 60 e8 eb 81 02 50 75 7e 13 31 2a |.8.SJ`....Pu~.1*| 00000300 ff 3e 17 cd b4 d1 d4 75 02 42 01 95 ba b6 a0 12 |.>.....u.B......| 00000310 23 59 9f ae 1c c0 60 d2 8f 59 6b 35 ee b3 3f ac |#Y....`..Yk5..?.| 00000320 e4 42 9a 23 d0 f4 fd a1 3c 36 1b 31 33 76 8d f0 |.B.#....<6.13v..| 00000330 b6 66 fd 92 9a 2a 27 8b 06 11 72 41 09 bd 27 55 |.f...*'...rA..'U| 00000340 c7 1b a9 d1 49 5e 8f 85 dc aa 9d be 16 03 01 00 |....I^..........| 00000350 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 01 00 30 64 61 7f ea 98 8e e7 c9 0f ea |.....0da........| 00000060 0a b3 52 ba 3d 01 36 a4 47 24 7b 2d 19 b5 7e 92 |..R.=.6.G${-..~.| 00000070 04 b7 8c 4f fc 02 5d 79 15 3e 50 72 05 3c df d2 |...O..]y.>Pr.<..| 00000080 c6 a3 b3 c8 7c 48 |....|H| >>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 30 7d 49 8d e9 da |..........0}I...| 00000010 87 77 18 4d 10 63 17 ed 1f 34 7a d4 be e3 dd b6 |.w.M.c...4z.....| 00000020 8b f3 a7 06 bc de 76 8e 04 be 8a 95 5b 24 19 ec |......v.....[$..| 00000030 66 55 8a 1b e0 df 0b a1 57 cb 67 |fU......W.g| >>> Flow 5 (client to server) 00000000 17 03 01 00 20 2d a3 e5 55 13 3f 73 8e ba 41 79 |.... -..U.?s..Ay| 00000010 65 e0 83 d5 3a ea cd e9 a8 b4 4b 3c d0 0c bf 06 |e...:.....K<....| 00000020 75 2a 67 f2 f7 17 03 01 00 20 a0 8d 3c a2 ca b3 |u*g...... ..<...| 00000030 f3 e5 36 dc 44 a4 3b ad cd 03 be a9 70 a8 75 51 |..6.D.;.....p.uQ| 00000040 0f 8e 9f 7c a7 3c 03 84 38 88 15 03 01 00 20 75 |...|.<..8..... u| 00000050 0f db fe 48 b4 7e 04 3b f5 5b 47 5b 0a ab 69 18 |...H.~.;.[G[..i.| 00000060 37 bb 89 d3 a8 40 ba 53 3b 5f 6d 8b 06 ff ae |7....@.S;_m....| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 01 00 59 02 00 00 55 03 01 90 3d f6 98 16 |....Y...U...=...| 00000010 55 0f 73 94 05 96 4c ab ad f4 98 7a db c5 ca 26 |U.s...L....z...&| 00000020 1b c8 d9 15 a8 79 8e 2b 10 67 54 20 b2 8e 45 24 |.....y.+.gT ..E$| 00000030 6d 82 ec f5 30 41 2e 32 10 fa c0 76 3f 84 81 39 |m...0A.2...v?..9| 00000040 1e 5d 98 c1 33 d9 0d 4f 21 e1 0d 47 c0 13 00 00 |.]..3..O!..G....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..| 00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.| 00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| 00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...| 000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1| 000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo| 000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000| 000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000| 000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go| 000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.| 00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...| 00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0| 00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.| 00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..| 00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd| 00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A| 00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.| 00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P| 00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.| 00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....| 000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.| 000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........| 000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.| 000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......| 000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.| 000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..| 00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#| 00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..| 00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0| 00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan| 00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........| 00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H| 00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}| 00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.| 00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5| 00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...| 000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..| 000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......| 000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....| 000002d0 b0 ab 39 18 16 03 01 00 cb 0c 00 00 c7 03 00 17 |..9.............| 000002e0 41 04 d9 ae 3f 05 64 d3 77 d9 1d b8 37 8a d4 ac |A...?.d.w...7...| 000002f0 51 f4 af 65 70 da c0 64 76 00 53 50 a2 d4 6c bc |Q..ep..dv.SP..l.| 00000300 9c 62 ab 2f 7b 02 48 fe b2 0d 0b bb be 8f 34 55 |.b./{.H.......4U| 00000310 fb ce ee 93 43 76 d5 ce 3b b5 79 ab 3d 74 6e 19 |....Cv..;.y.=tn.| 00000320 a9 7d 00 80 05 cf 57 f2 f7 e0 ad 71 f1 75 d0 8b |.}....W....q.u..| 00000330 f5 9d 83 1a 7e 0a 71 10 d7 9e fe bd 9d 47 62 45 |....~.q......GbE| 00000340 8d 1b 9c 33 fa 2c 5c aa ce 9e 62 dc ad 56 ac 87 |...3.,\...b..V..| 00000350 84 54 f5 32 87 d1 bb 8b d9 d7 6d 3c 6c 6d b7 79 |.T.2......m>> Flow 3 (client to server) 00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 01 00 30 73 96 2d 54 e3 9a bc 54 f5 9e |.....0s.-T...T..| 00000060 e5 c7 46 35 b8 e1 d6 f6 14 95 92 f1 95 81 5a 9d |..F5..........Z.| 00000070 4b df cc 96 77 f2 39 60 5d 5d da 94 b0 bf a0 80 |K...w.9`]]......| 00000080 bd 28 55 b1 6a c3 |.(U.j.| >>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 30 c9 46 7a 8b be |..........0.Fz..| 00000010 cd eb 5c 83 13 9c 9b 9f 70 84 38 3b 48 8c f4 11 |..\.....p.8;H...| 00000020 b3 ca 10 09 38 d0 8e c8 9f 66 db b9 8a 95 15 6b |....8....f.....k| 00000030 5e f8 1d 39 25 75 3d f1 b9 32 a3 |^..9%u=..2.| >>> Flow 5 (client to server) 00000000 17 03 01 00 20 04 69 a9 01 42 f4 1a fd 5a 4e 12 |.... .i..B...ZN.| 00000010 2b 6d cd 68 6b 94 70 b2 80 07 cf 79 a4 43 69 bf |+m.hk.p....y.Ci.| 00000020 27 25 b5 ae e7 17 03 01 00 20 bf 1e cd 83 64 af |'%....... ....d.| 00000030 6f cc 89 21 bf 16 e7 e8 86 29 f3 0a 36 ab a4 e3 |o..!.....)..6...| 00000040 fa c0 7e 7a 78 ca 29 17 11 9c 15 03 01 00 20 94 |..~zx.)....... .| 00000050 7a dd 17 eb fd 67 b1 cc 58 c9 c3 ae db b6 b0 a4 |z....g..X.......| 00000060 68 15 36 ca 33 22 ec 03 fb cf 2f f5 70 d6 9d |h.6.3"..../.p..| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv10-RSA-RC4 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 01 00 51 02 00 00 4d 03 01 1c 0e e9 7a c6 |....Q...M.....z.| 00000010 91 fe 7e 8c 6f 0b 8e cf 23 f5 07 29 10 de 05 a6 |..~.o...#..)....| 00000020 20 72 11 65 4f 2b 45 95 96 02 62 20 43 a8 93 34 | r.eO+E...b C..4| 00000030 e7 c0 29 d5 fb 26 f9 c2 59 37 94 dc e6 b5 c4 ed |..)..&..Y7......| 00000040 ae 7a d7 94 d1 f4 d8 0b 02 ad 20 1b 00 05 00 00 |.z........ .....| 00000050 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.| 00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....| 000002d0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 01 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.| 00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....| 00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......| 00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..| 00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.| 00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..| 00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k| 00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..| 00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 01 00 01 |M.x.N.8FB.......| 00000090 01 16 03 01 00 24 ae a9 da 45 6b 5e 76 57 02 62 |.....$...Ek^vW.b| 000000a0 63 d4 1f 40 bf c9 47 27 a9 7a 24 c0 f0 e9 c2 c4 |c..@..G'.z$.....| 000000b0 9c 07 84 df ae c7 66 40 d2 b0 |......f@..| >>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 24 e9 84 92 41 c5 |..........$...A.| 00000010 31 e1 3c a9 78 18 d1 7b e1 b1 0b 0a ef 18 54 19 |1.<.x..{......T.| 00000020 7c ba c7 59 ca c8 7b 4d c9 f4 ad d6 7b 77 fb ||..Y..{M....{w.| >>> Flow 5 (client to server) 00000000 17 03 01 00 1a 1a dc 95 e2 4f ec f1 f6 68 9d 15 |.........O...h..| 00000010 56 d5 7b 06 1a f5 be bb b1 ca b2 a6 d3 9e 28 15 |V.{...........(.| 00000020 03 01 00 16 64 fe 4a 37 d3 32 a8 55 38 9e 0f 76 |....d.J7.2.U8..v| 00000030 50 de e2 2e aa 77 15 2b e5 21 |P....w.+.!| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 02 00 59 02 00 00 55 03 02 07 ae a6 e4 1a |....Y...U.......| 00000010 f7 7a 0c bc ea 21 0e 86 e3 d0 b4 2c fc d9 97 a3 |.z...!.....,....| 00000020 8b 29 5f 59 3e a9 06 fb ca d9 57 20 cd 45 e7 cd |.)_Y>.....W .E..| 00000030 6c 4c 56 cd 7c 4c 51 2c 8f 8c 67 a2 05 51 26 f5 |lLV.|LQ,..g..Q&.| 00000040 17 cc 18 c2 a1 29 94 4b e2 02 cc 1c c0 09 00 00 |.....).K........| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 02 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| 00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0| 00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| 000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| 000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| 000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| 000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506| 000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063| 000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A| 00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some| 00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...| 00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit| 00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...| 00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..| 00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.| 00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.| 00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d| 00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i| 00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.| 000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#| 000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.| 000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.| 000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=| 000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.| 000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^| 00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......| 00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y| 00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.| 00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3| 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| 00000270 2a 16 03 02 00 d6 0c 00 00 d2 03 00 17 41 04 cd |*............A..| 00000280 9d 30 75 8d 98 17 b5 1b 2f 4e af ea 69 52 a1 c1 |.0u...../N..iR..| 00000290 86 73 6a 56 54 f8 ed b6 35 e5 4e 34 a0 6f b1 85 |.sjVT...5.N4.o..| 000002a0 95 8e be 77 c5 1a 56 9a 59 d1 69 79 ea d6 2b c7 |...w..V.Y.iy..+.| 000002b0 c1 4a fb bc f8 98 c3 49 1c f3 ce 33 ef 98 20 00 |.J.....I...3.. .| 000002c0 8b 30 81 88 02 42 00 8b 15 7e 3b 4f 73 b0 8e ca |.0...B...~;Os...| 000002d0 67 e0 7c d8 89 70 f1 b2 6b 9c 19 84 fa aa 6e 15 |g.|..p..k.....n.| 000002e0 8b 46 95 57 d5 ac 79 f3 e8 2a e5 7a a8 1e c3 d7 |.F.W..y..*.z....| 000002f0 0a b2 02 cd d6 32 34 2f 37 65 41 c8 61 c6 ed e5 |.....24/7eA.a...| 00000300 d2 6f 0f e8 1a 49 b6 c7 02 42 00 d1 00 f4 05 65 |.o...I...B.....e| 00000310 dd 43 42 db 8b 0b 95 9d f5 62 51 e6 58 60 20 9b |.CB......bQ.X` .| 00000320 46 84 e6 1f 76 4a 92 42 e4 4d 77 5b 76 a5 78 a0 |F...vJ.B.Mw[v.x.| 00000330 b0 f0 50 7d f9 4f ca 43 9d c2 50 cb 20 1c 40 52 |..P}.O.C..P. .@R| 00000340 0f a8 c4 43 7a 9d d5 61 de 26 30 b5 16 03 02 00 |...Cz..a.&0.....| 00000350 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| 00000060 00 00 00 00 00 00 c0 81 e7 e8 40 f3 24 45 ed 74 |..........@.$E.t| 00000070 86 31 7b 39 d1 3c a2 67 99 28 06 b1 34 b6 3c a6 |.1{9.<.g.(..4.<.| 00000080 1d ce 39 aa 56 c9 72 0d f1 e0 c1 5a 51 a0 5d f2 |..9.V.r....ZQ.].| 00000090 44 4d e6 d7 0e 84 |DM....| >>> Flow 4 (server to client) 00000000 14 03 02 00 01 01 16 03 02 00 40 82 8d c7 e3 7b |..........@....{| 00000010 f8 9d 33 a1 c2 08 8c 24 d9 af 66 64 6e e8 61 8e |..3....$..fdn.a.| 00000020 3c 03 65 2d c3 64 a2 26 23 a5 25 3f a2 a4 f9 40 |<.e-.d.&#.%?...@| 00000030 ec 9f 0e b8 57 b1 5f 84 ea 94 72 1a 3e 60 f1 dd |....W._...r.>`..| 00000040 af 2e 81 f7 16 de 43 85 21 51 49 |......C.!QI| >>> Flow 5 (client to server) 00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| 00000010 00 00 00 00 00 43 8f 88 82 c8 e1 55 37 76 d7 a5 |.....C.....U7v..| 00000020 83 c6 d2 94 26 fe 30 1f e2 24 ca d7 27 22 33 47 |....&.0..$..'"3G| 00000030 5f a9 74 9d ad 15 03 02 00 30 00 00 00 00 00 00 |_.t......0......| 00000040 00 00 00 00 00 00 00 00 00 00 49 8e ee 5c ec 86 |..........I..\..| 00000050 e7 64 a7 ac 0d 5c c4 43 a6 45 a4 22 b7 3d 21 06 |.d...\.C.E.".=!.| 00000060 11 67 08 99 9a 08 a1 7c e0 1e |.g.....|..| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 02 00 59 02 00 00 55 03 02 0c 74 28 d1 02 |....Y...U...t(..| 00000010 15 8f 15 9c ec 8c 4e 34 97 d8 14 ab 0c ed 1b 38 |......N4.......8| 00000020 af 7f e6 d3 41 db fd ad a0 8d 4f 20 03 71 4a d6 |....A.....O .qJ.| 00000030 32 23 57 6c e1 55 34 1d 48 6f 9d e0 9a db 15 9d |2#Wl.U4.Ho......| 00000040 5b 45 a7 3e 4e 98 31 7d f5 d4 b6 36 c0 13 00 00 |[E.>N.1}...6....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 02 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..| 00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.| 00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| 00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...| 000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1| 000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo| 000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000| 000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000| 000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go| 000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.| 00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...| 00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0| 00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.| 00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..| 00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd| 00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A| 00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.| 00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P| 00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.| 00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....| 000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.| 000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........| 000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.| 000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......| 000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.| 000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..| 00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#| 00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..| 00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0| 00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan| 00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........| 00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H| 00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}| 00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.| 00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5| 00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...| 000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..| 000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......| 000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....| 000002d0 b0 ab 39 18 16 03 02 00 cb 0c 00 00 c7 03 00 17 |..9.............| 000002e0 41 04 2c e8 55 b8 19 d6 cd e5 c7 96 a4 aa 61 af |A.,.U.........a.| 000002f0 aa b2 f1 fc b3 ac 9a 90 02 d0 0a 86 61 9a c1 2e |............a...| 00000300 3e fd 42 0b ba 07 95 77 2b 92 a2 5b 1f 44 ad 6b |>.B....w+..[.D.k| 00000310 78 7a f4 b3 4b 04 d3 d5 2d eb 20 2d 73 02 4c db |xz..K...-. -s.L.| 00000320 7e ac 00 80 79 b0 c6 b9 a8 50 e4 bf de 97 c6 1f |~...y....P......| 00000330 ae 5f 89 77 6e e4 23 8c 8d 1a 49 f8 d4 92 cf 0d |._.wn.#...I.....| 00000340 f0 08 bd 3a 88 9c 55 46 fc be 9e 7c 70 ff 6f 70 |...:..UF...|p.op| 00000350 7b 94 b3 7b 82 c3 58 53 f7 20 13 3c 83 6e 10 55 |{..{..XS. .<.n.U| 00000360 9d 51 cb 53 8c 93 dc 0e 02 06 40 d4 df ce 57 e4 |.Q.S......@...W.| 00000370 e0 9a ba e2 b3 9b 01 98 0e 12 ca e9 96 5b 7a f2 |.............[z.| 00000380 b1 ac 9c 44 e7 6e 2e c6 51 63 99 68 26 93 ca e2 |...D.n..Qc.h&...| 00000390 40 31 e5 9a 80 ce 83 8f ca 80 90 c4 e8 ab 89 b2 |@1..............| 000003a0 ca d6 30 a5 16 03 02 00 04 0e 00 00 00 |..0..........| >>> Flow 3 (client to server) 00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| 00000060 00 00 00 00 00 00 7d 87 6f 44 8f b9 92 51 5a b7 |......}.oD...QZ.| 00000070 d2 6c 22 7f 62 a1 4e 30 61 f8 42 cd b0 05 c0 24 |.l".b.N0a.B....$| 00000080 1f e0 49 a8 36 ce 8a 68 94 b7 37 c7 e8 d9 d8 05 |..I.6..h..7.....| 00000090 be fb 5e 48 ba d1 |..^H..| >>> Flow 4 (server to client) 00000000 14 03 02 00 01 01 16 03 02 00 40 7d ed 01 b9 5a |..........@}...Z| 00000010 34 f4 e1 63 70 84 13 86 e6 4d 90 92 da 3c 9b 35 |4..cp....M...<.5| 00000020 77 92 7f 0a fd 69 09 75 30 5b c3 2c 6e 8e d0 59 |w....i.u0[.,n..Y| 00000030 08 08 5c c9 eb 53 45 f3 a6 12 16 f2 95 06 27 82 |..\..SE.......'.| 00000040 6d 9b 9e 6a bb 52 79 65 ca 94 9b |m..j.Rye...| >>> Flow 5 (client to server) 00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| 00000010 00 00 00 00 00 bb 2d 28 50 1f a4 8f be 94 b9 99 |......-(P.......| 00000020 e6 0b dd cf 50 fc 72 92 ec 1d 72 9b 27 9a 36 18 |....P.r...r.'.6.| 00000030 3e e3 d7 cc 69 15 03 02 00 30 00 00 00 00 00 00 |>...i....0......| 00000040 00 00 00 00 00 00 00 00 00 00 61 ca 39 3c 7e 9f |..........a.9<~.| 00000050 1c c8 c2 2a 42 4a d0 c4 f3 80 41 04 b4 35 d0 41 |...*BJ....A..5.A| 00000060 3d 47 1b 16 2c 71 27 04 7c 81 |=G..,q'.|.| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv11-RSA-RC4 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 02 00 51 02 00 00 4d 03 02 59 22 be 64 85 |....Q...M..Y".d.| 00000010 71 af 54 70 5f a8 50 ff 68 52 a0 9e a7 79 4d 90 |q.Tp_.P.hR...yM.| 00000020 cd bc c7 9c 4f 62 bc 4d a6 b9 0c 20 e1 94 8f 01 |....Ob.M... ....| 00000030 fa 7f 9e 6f 01 72 82 ef cc 41 ed 4d 7e 76 ee e1 |...o.r...A.M~v..| 00000040 21 34 f3 5c e0 b4 4b e2 73 37 a8 40 00 05 00 00 |!4.\..K.s7.@....| 00000050 05 ff 01 00 01 00 16 03 02 02 71 0b 00 02 6d 00 |..........q...m.| 00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 02 00 |..A4......9.....| 000002d0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 02 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.| 00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....| 00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......| 00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..| 00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.| 00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..| 00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k| 00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..| 00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 02 00 01 |M.x.N.8FB.......| 00000090 01 16 03 02 00 24 0b 7b 3e 32 fb 94 95 66 26 a9 |.....$.{>2...f&.| 000000a0 4c 21 5e 18 59 cb 80 57 1b 9a 89 c8 91 c5 30 1f |L!^.Y..W......0.| 000000b0 1a e2 80 9a 0f 03 8e 7b 4c 7d |.......{L}| >>> Flow 4 (server to client) 00000000 14 03 02 00 01 01 16 03 02 00 24 06 7f be 82 45 |..........$....E| 00000010 79 c6 67 fb d3 1e 3f ca d9 0f 8f 81 36 cc 80 77 |y.g...?.....6..w| 00000020 b8 48 f3 88 29 fa f1 3a b2 d4 fd 10 e5 8c 43 |.H..)..:......C| >>> Flow 5 (client to server) 00000000 17 03 02 00 1a 29 4d a2 80 38 2c 9e 96 bb 29 8b |.....)M..8,...).| 00000010 22 69 ea 85 3e d8 a9 66 39 b8 58 12 ae 67 db 15 |"i..>..f9.X..g..| 00000020 03 02 00 16 8c b2 f4 c1 35 5d 28 dc 5c bc 30 95 |........5](.\.0.| 00000030 99 3e f6 c6 ff 4f 5c f4 85 1a |.>...O\...| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 51 02 00 00 4d 03 03 e7 18 39 61 14 |....Q...M....9a.| 00000010 47 69 40 34 ae 4e 58 4b 32 2d ed 2a 52 09 c5 2f |Gi@4.NXK2-.*R../| 00000020 07 f6 44 0b 2b 9c 43 4b bb 79 b6 20 48 f4 ff f1 |..D.+.CK.y. H...| 00000030 c6 72 77 e5 3a e0 8d 08 b9 cd 8b bf e3 9b ec 41 |.rw.:..........A| 00000040 1d d9 86 1b 35 7b 8c 04 e0 83 0d d3 00 9c 00 00 |....5{..........| 00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002d0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.| 00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....| 00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......| 00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..| 00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.| 00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..| 00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k| 00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..| 00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 03 00 01 |M.x.N.8FB.......| 00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 8a 9b |.....(..........| 000000a0 29 1d 64 2e ee 0d 39 d9 c5 86 b9 02 9d c3 bd 74 |).d...9........t| 000000b0 39 9d 53 9f 1a ee 84 64 82 82 41 81 f8 2f |9.S....d..A../| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 60 71 25 f9 f9 |..........(`q%..| 00000010 89 cd f8 6f 00 a6 0e 92 f8 3e 84 08 79 6f 91 cd |...o.....>..yo..| 00000020 e2 62 d5 da 96 79 c3 0d f4 34 26 bd 47 9c 30 aa |.b...y...4&.G.0.| 00000030 1b 5f 24 |._$| >>> Flow 5 (client to server) 00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 44 05 c9 |.............D..| 00000010 2b 82 55 26 ab 4b 65 b1 94 e5 8a 81 bf 44 a5 cb |+.U&.Ke......D..| 00000020 22 f0 0a 15 03 03 00 1a 00 00 00 00 00 00 00 02 |"...............| 00000030 59 8d 6f 5d 30 47 4d 3e ed aa 87 5f ca 39 44 a4 |Y.o]0GM>..._.9D.| 00000040 9b fc |..| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 51 02 00 00 4d 03 03 08 e2 40 1b 1a |....Q...M....@..| 00000010 54 dc 66 60 e1 e0 8d 94 c6 dd 2c eb 95 e0 e9 2f |T.f`......,..../| 00000020 fb 49 17 d8 34 d7 a2 7a 1b e1 60 20 26 a3 4b 7c |.I..4..z..` &.K|| 00000030 40 cc df 4b 9c 72 a9 e6 61 89 1e 20 b2 e5 e3 1e |@..K.r..a.. ....| 00000040 4e a3 b6 32 ce fc 94 0d ab 13 74 f8 00 9d 00 00 |N..2......t.....| 00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002d0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.| 00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....| 00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......| 00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..| 00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.| 00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..| 00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k| 00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..| 00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 03 00 01 |M.x.N.8FB.......| 00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 28 9a |.....(........(.| 000000a0 46 23 21 fa a9 ec 6d 57 d1 27 2f 53 58 a9 00 48 |F#!...mW.'/SX..H| 000000b0 7e 82 82 b8 23 f3 c4 a8 d3 2c a3 99 76 2e |~...#....,..v.| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 0c c8 0a e1 b8 |..........(.....| 00000010 95 b9 84 bc 0f 48 eb d4 4a a5 63 c2 92 58 8a 91 |.....H..J.c..X..| 00000020 27 30 36 28 23 f5 50 bd d6 a9 e9 61 54 10 f9 72 |'06(#.P....aT..r| 00000030 98 d1 0e |...| >>> Flow 5 (client to server) 00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 b9 55 ce |..............U.| 00000010 5a ab 7e 7e 58 4f c9 5a bc 0e 93 98 4f 87 86 98 |Z.~~XO.Z....O...| 00000020 a6 40 7e 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.@~.............| 00000030 57 0c 6f d9 28 87 d4 a6 de 14 91 a7 79 cc 19 e5 |W.o.(.......y...| 00000040 28 66 |(f| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ALPN ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 9d 01 00 00 99 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 4e 33 74 00 00 00 05 00 05 01 00 00 00 |...N3t..........| 00000060 00 00 0a 00 08 00 06 00 17 00 18 00 19 00 0b 00 |................| 00000070 02 01 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 |................| 00000080 03 02 01 02 03 ff 01 00 01 00 00 10 00 10 00 0e |................| 00000090 06 70 72 6f 74 6f 32 06 70 72 6f 74 6f 31 00 12 |.proto2.proto1..| 000000a0 00 00 |..| >>> Flow 2 (server to client) 00000000 16 03 03 00 66 02 00 00 62 03 03 a2 7d b9 7c f9 |....f...b...}.|.| 00000010 bf fb cb b2 d5 11 c0 99 19 73 3d b4 eb 6b 39 f8 |.........s=..k9.| 00000020 1b 7c 1d 6b 17 4d 66 a3 ed 20 5b 20 ee 87 d7 1f |.|.k.Mf.. [ ....| 00000030 cf 60 6c 75 12 8b de 56 f6 ca da 4a 92 76 49 43 |.`lu...V...J.vIC| 00000040 70 18 0a e7 7b 2a 0c f3 44 a6 d8 dd c0 2f 00 00 |p...{*..D..../..| 00000050 1a ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 10 |................| 00000060 00 09 00 07 06 70 72 6f 74 6f 31 16 03 03 02 71 |.....proto1....q| 00000070 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 |...m..j..g0..c0.| 00000080 01 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 |...........s....| 00000090 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......| 000000a0 00 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |.0+1.0...U....Go| 000000b0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e |ogle TESTING1.0.| 000000c0 06 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e |..U....Go Root0.| 000000d0 17 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 |..150101000000Z.| 000000e0 0d 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 |.250101000000Z0&| 000000f0 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c |1.0...U....Googl| 00000100 65 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 |e TESTING1.0...U| 00000110 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 |....Go0..0...*.H| 00000120 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 |............0...| 00000130 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 |....... ..el..D.| 00000140 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 |.;E...m..cM...jb| 00000150 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 |5..J..|..%^zd1f.| 00000160 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 |......k.v.._A.nV| 00000170 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db |.....<.9!f=+....| 00000180 1c c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d |...........!P...| 00000190 ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 |..k.K......l..D.| 000001a0 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 |.!..}..M........| 000001b0 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e |G..........0..0.| 000001c0 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d |..U...........0.| 000001d0 06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 |..U.%..0...+....| 000001e0 07 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 |.....+.......0..| 000001f0 03 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 |.U.......0.0...U| 00000200 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d |.......P..o...TM| 00000210 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 |n.i^..0...U.#..0| 00000220 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 |....=..f..@....x| 00000230 48 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e |H.A0...U....0...| 00000240 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d |example.golang0.| 00000250 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 |..*.H...........| 00000260 00 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d |..|..U...Y1.H@.-| 00000270 d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 |........|..0}<.v| 00000280 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 |.O=...-3$k.{.gY.| 00000290 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f |!...w...n.-.5.d_| 000002a0 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 |">c.k....m...1..| 000002b0 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db |8.;..,...Qv..O..| 000002c0 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 |....@.Q......F.F| 000002d0 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 |.O.....A4......9| 000002e0 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 41 |.............A.A| 000002f0 a4 1f 6f ea 6d 59 68 72 1a 6d 47 c7 b4 a0 08 01 |..o.mYhr.mG.....| 00000300 b9 b3 d8 7a 95 75 c0 58 2a d9 29 91 e7 d9 78 b2 |...z.u.X*.)...x.| 00000310 97 1d 52 72 2d 18 cb ce 83 8a 07 f4 bd dd 7e a1 |..Rr-.........~.| 00000320 d2 45 51 9d bf f1 bf 01 33 3a 10 94 6c 2b 99 04 |.EQ.....3:..l+..| 00000330 01 00 80 63 8f 03 6d b4 4d f7 27 d0 1f f2 0f ff |...c..m.M.'.....| 00000340 af 27 c2 97 21 68 8c 32 8b 14 67 0e b5 75 3a 5b |.'..!h.2..g..u:[| 00000350 73 08 9a c7 fd ad 8d 50 2a de e7 d6 c5 87 7a b2 |s......P*.....z.| 00000360 06 29 0a 09 dd d4 81 d5 a7 2b 4d 20 50 72 6f be |.).......+M Pro.| 00000370 35 9b c6 2d b0 1e 8f a2 cf 10 33 d4 53 0b 33 95 |5..-......3.S.3.| 00000380 b8 a5 34 38 1b db 1e 45 07 36 3a 86 c7 f1 b1 3a |..48...E.6:....:| 00000390 2e 5d 82 b2 1d 3e e1 27 8f f2 f4 2c 8c c3 27 e9 |.]...>.'...,..'.| 000003a0 f0 9a 8f 6d 20 b1 19 8e 23 d5 04 69 e4 eb 0d eb |...m ...#..i....| 000003b0 97 fb 71 16 03 03 00 04 0e 00 00 00 |..q.........| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 15 94 |.....(..........| 00000060 6f 5b 35 9d eb 14 c8 be 23 a7 05 8c 14 86 35 a7 |o[5.....#.....5.| 00000070 5c 91 76 4f 85 b1 09 f8 0f 58 9f ec d2 a9 |\.vO.....X....| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 e7 7f 99 c9 fa |..........(.....| 00000010 e0 a3 e3 77 68 74 37 62 26 90 d6 be ec a1 ae 5a |...wht7b&......Z| 00000020 de af 10 f1 2e a0 42 f0 88 ed 89 54 04 b2 b9 eb |......B....T....| 00000030 b0 91 b8 |...| >>> Flow 5 (client to server) 00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 be e7 77 |...............w| 00000010 f9 92 ac 51 d0 34 25 34 e6 35 9e ea f0 d3 89 45 |...Q.4%4.5.....E| 00000020 84 1b 93 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| 00000030 1a 27 54 01 c9 7c 86 4b 61 c8 98 1b d3 15 1f 93 |.'T..|.Ka.......| 00000040 f9 42 |.B| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 96 01 00 00 92 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 47 33 74 00 00 00 05 00 05 01 00 00 00 |...G3t..........| 00000060 00 00 0a 00 08 00 06 00 17 00 18 00 19 00 0b 00 |................| 00000070 02 01 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 |................| 00000080 03 02 01 02 03 ff 01 00 01 00 00 10 00 09 00 07 |................| 00000090 06 70 72 6f 74 6f 33 00 12 00 00 |.proto3....| >>> Flow 2 (server to client) 00000000 16 03 03 00 59 02 00 00 55 03 03 18 3d 15 59 fb |....Y...U...=.Y.| 00000010 0a a4 93 d7 43 50 59 7f 6c f9 64 db b5 47 cc 17 |....CPY.l.d..G..| 00000020 8c cd 91 b5 04 02 3f c0 5d 60 b7 20 75 ed d2 e9 |......?.]`. u...| 00000030 b6 72 2d f7 66 34 2e 2f d2 b9 80 66 eb c3 36 f6 |.r-.f4./...f..6.| 00000040 b2 61 77 79 a9 c2 db cd 57 5a b2 6b c0 2f 00 00 |.awy....WZ.k./..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..| 00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.| 00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| 00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...| 000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1| 000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo| 000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000| 000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000| 000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go| 000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.| 00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...| 00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0| 00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.| 00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..| 00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd| 00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A| 00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.| 00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P| 00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.| 00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....| 000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.| 000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........| 000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.| 000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......| 000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.| 000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..| 00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#| 00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..| 00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0| 00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan| 00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........| 00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H| 00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}| 00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.| 00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5| 00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...| 000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..| 000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......| 000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....| 000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............| 000002e0 41 04 62 52 78 76 89 36 e7 b9 a6 cc df 8e f8 c3 |A.bRxv.6........| 000002f0 52 54 b6 42 9b 68 65 65 27 91 bf 1b 0f 21 ab a9 |RT.B.hee'....!..| 00000300 f4 00 62 dd 70 25 b8 ec d0 3d 9b 0c 53 16 6e eb |..b.p%...=..S.n.| 00000310 a8 c3 1a ad a9 de ec 27 64 07 e8 9b b8 bf 5a 6c |.......'d.....Zl| 00000320 87 f4 04 01 00 80 05 ec 2b f7 2e a4 5e 79 85 6f |........+...^y.o| 00000330 64 7a b5 fb 9a e9 f1 12 ae 28 93 4b 6d 8e a0 2f |dz.......(.Km../| 00000340 94 bc 38 26 01 64 ab fb 03 c8 3d 17 bc b4 43 09 |..8&.d....=...C.| 00000350 19 c8 e9 ac 60 40 67 57 71 e3 72 22 cf b1 a7 38 |....`@gWq.r"...8| 00000360 ac 86 88 9d 47 6f 70 c9 43 82 75 b6 bf 42 4e 72 |....Gop.C.u..BNr| 00000370 12 48 d1 2b ce 74 02 5d 30 56 66 6f 71 8f 9b 82 |.H.+.t.]0Vfoq...| 00000380 70 3b 92 5d fb 37 d3 cf d3 23 27 d2 d5 8d 72 22 |p;.].7...#'...r"| 00000390 d4 b4 92 6d 64 06 d9 0b e0 bb 34 eb bf 42 ec 6a |...md.....4..B.j| 000003a0 ea e3 56 68 85 a0 16 03 03 00 04 0e 00 00 00 |..Vh...........| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 97 34 |.....(.........4| 00000060 d5 c2 64 97 f6 a9 f5 60 bc 17 f3 d3 02 3f 42 a8 |..d....`.....?B.| 00000070 2f ba eb c6 50 3c ec 9b 8d 3b 22 ed ec 35 |/...P<...;"..5| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 9a e5 f5 51 5c |..........(...Q\| 00000010 cb be 5d a1 67 cc 55 aa ba db e7 0a ab 96 3b 33 |..].g.U.......;3| 00000020 5f 2c 8c 61 20 f1 0d 6e ce 90 d8 39 27 d7 fb 68 |_,.a ..n...9'..h| 00000030 d9 dd da |...| >>> Flow 5 (client to server) 00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 a8 be 7c |...............|| 00000010 05 48 ea df 62 4a 7a 45 68 e4 dc e6 42 ff 06 f2 |.H..bJzEh...B...| 00000020 02 33 1a 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.3..............| 00000030 66 68 f4 de da 69 b4 f9 80 9c 80 c6 46 e5 2b ae |fh...i......F.+.| 00000040 0e d1 |..| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 59 02 00 00 55 03 03 f0 5c 85 c8 ff |....Y...U...\...| 00000010 c5 57 76 99 3d 75 e6 2e db 31 26 c0 0c 81 c5 6b |.Wv.=u...1&....k| 00000020 30 79 e6 72 86 77 48 01 ec 43 1a 20 f8 fd ad b5 |0y.r.wH..C. ....| 00000030 a0 7b f3 35 27 df ad 95 f9 56 f9 79 6c a2 6c 23 |.{.5'....V.yl.l#| 00000040 51 4c ef fc 92 fb fa 59 97 e9 63 27 c0 09 00 00 |QL.....Y..c'....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| 00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0| 00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| 000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| 000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| 000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| 000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506| 000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063| 000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A| 00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some| 00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...| 00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit| 00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...| 00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..| 00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.| 00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.| 00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d| 00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i| 00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.| 000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#| 000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.| 000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.| 000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=| 000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.| 000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^| 00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......| 00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y| 00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.| 00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3| 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| 00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 51 |*............A.Q| 00000280 1e 2e 40 c5 a1 13 15 f0 bc 8a 04 e1 9a 57 74 10 |..@..........Wt.| 00000290 7e b3 17 bf 0c c9 85 9b 5f bd 6b 39 c7 a6 c0 50 |~......._.k9...P| 000002a0 0e 5e 9b b1 8c cc 57 39 e8 0f 94 02 be 28 19 16 |.^....W9.....(..| 000002b0 94 73 2b c1 3c a7 0f c9 e7 b0 89 ac 13 53 f9 04 |.s+.<........S..| 000002c0 03 00 8b 30 81 88 02 42 01 1b e0 ab 94 02 aa 27 |...0...B.......'| 000002d0 fa 7b 99 9c 68 36 d8 2d 2e e0 92 84 c7 7b 37 74 |.{..h6.-.....{7t| 000002e0 6a ad a8 f5 50 3f 74 d5 e8 8e 5a db 31 43 c8 98 |j...P?t...Z.1C..| 000002f0 d3 ee 61 43 80 9a 72 eb 2d 2b 21 b8 33 aa 61 0a |..aC..r.-+!.3.a.| 00000300 cd dc 85 88 29 26 83 ee 3c b2 02 42 00 b6 ea 34 |....)&..<..B...4| 00000310 30 71 5c 0a 9a 6d a2 25 62 1c 3e 13 90 9c a3 b8 |0q\..m.%b.>.....| 00000320 0d 97 a8 06 26 9e 31 50 88 9a b9 ff 12 63 a8 14 |....&.1P.....c..| 00000330 18 f3 c2 b0 af d1 27 25 a9 ec ef 69 85 7a 72 c6 |......'%...i.zr.| 00000340 b0 88 d2 c1 41 43 f4 69 62 25 13 eb f9 f8 16 03 |....AC.ib%......| 00000350 03 00 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 |......&...@.....| 00000360 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| 00000370 01 03 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 |................| 00000380 00 |.| >>> Flow 3 (client to server) 00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| 00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1| 00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.| 00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat| 00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte| 00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty| 00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413| 00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132| 00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...| 000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS| 000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm| 000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo| 000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.| 000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....| 000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.| 00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N| 00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..| 00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.| 00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J| 00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A| 00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......| 00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN| 00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..| 00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.| 00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?| 000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH| 000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........| 000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...| 000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._| 000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.| 000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W| 00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..| 00000210 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d 19 |...F...BA...7...| 00000220 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..| 00000230 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..| 00000240 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.| 00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 93 0f |.h.A.Vk.Z.......| 00000260 00 00 8f 05 03 00 8b 30 81 88 02 42 00 8a 82 c2 |.......0...B....| 00000270 c0 30 8c a1 12 c4 4a ed d1 00 3f 2d ee bd 8e 9c |.0....J...?-....| 00000280 a5 a0 d9 6f 44 27 49 60 e9 75 01 ee b4 0d 87 25 |...oD'I`.u.....%| 00000290 2a 8d 67 f1 e3 d9 49 6f a0 34 90 76 93 52 f9 17 |*.g...Io.4.v.R..| 000002a0 fb 1b cc d0 5a f4 50 37 9c 4c 44 b6 61 5f 02 42 |....Z.P7.LD.a_.B| 000002b0 01 ad 85 38 e9 3a 69 35 ea 74 76 2c 09 6b ab d4 |...8.:i5.tv,.k..| 000002c0 e0 dc d1 d5 03 41 22 8e 8b 53 98 b7 f1 b6 e9 29 |.....A"..S.....)| 000002d0 d2 57 34 dc e0 b6 71 77 79 bd 57 61 7c 30 77 00 |.W4...qwy.Wa|0w.| 000002e0 7a 42 2d 1f ed e8 14 da 16 33 c6 31 e4 3d 53 3a |zB-......3.1.=S:| 000002f0 9a 37 14 03 03 00 01 01 16 03 03 00 40 00 00 00 |.7..........@...| 00000300 00 00 00 00 00 00 00 00 00 00 00 00 00 d4 fe c1 |................| 00000310 a6 fb 21 78 21 80 af 0d da a1 80 68 e2 9c ec 0b |..!x!......h....| 00000320 57 8c 2a 7e f1 11 3b 52 ea 17 00 d1 d4 14 78 c5 |W.*~..;R......x.| 00000330 81 39 12 ad 30 98 93 1b 29 77 45 7d 00 |.9..0...)wE}.| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 f7 0a 50 d0 87 |..........@..P..| 00000010 fb f9 be b0 6b 8d 9b a5 8b d2 56 27 67 7d 3c 51 |....k.....V'g}>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| 00000010 00 00 00 00 00 ef 81 cf 63 f1 b5 6b b2 30 6f 00 |........c..k.0o.| 00000020 0e c0 0c 5d d4 85 76 d2 30 db 6b 14 06 e4 75 0b |...]..v.0.k...u.| 00000030 cf fc 72 aa 64 15 03 03 00 30 00 00 00 00 00 00 |..r.d....0......| 00000040 00 00 00 00 00 00 00 00 00 00 ef 28 8a e7 15 51 |...........(...Q| 00000050 0d 0d 27 4f 36 35 f6 43 28 d2 16 dc a3 35 33 3e |..'O65.C(....53>| 00000060 be 80 db 31 a9 89 3d 17 c2 58 |...1..=..X| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 51 02 00 00 4d 03 03 e8 b5 19 bd df |....Q...M.......| 00000010 e5 18 78 4b 01 f1 3f 7f ab 91 05 78 98 77 50 bf |..xK..?....x.wP.| 00000020 60 f5 a4 76 7b 3c 40 9f 54 56 68 20 a1 99 57 a7 |`..v{<@.TVh ..W.| 00000030 a8 46 ca 26 22 d8 bb 8d 93 12 48 ff be 8e d3 d4 |.F.&".....H.....| 00000040 e0 fd cd ce f5 d9 a9 2e fe d4 cd 85 00 05 00 00 |................| 00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002d0 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 06 |....&...@.......| 000002e0 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................| 000002f0 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 00 |...............| >>> Flow 3 (client to server) 00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| 00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1| 00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.| 00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat| 00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte| 00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty| 00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413| 00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132| 00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...| 000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS| 000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm| 000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo| 000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.| 000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....| 000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.| 00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N| 00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..| 00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.| 00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J| 00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A| 00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......| 00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN| 00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..| 00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.| 00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?| 000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH| 000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........| 000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...| 000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._| 000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.| 000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W| 00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..| 00000210 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 86 |..........s.se..| 00000220 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 87 |#A.y......M.....| 00000230 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 53 |.2R.k..-.......S| 00000240 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 fe |.m.....o..#87...| 00000250 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 65 |...U...`}p&..T.e| 00000260 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 ff |...S_..:.3{.L...| 00000270 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b 52 |Z.6*G.....1x..kR| 00000280 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 4d |..........+.8..M| 00000290 e5 78 13 4e a4 38 46 42 dc 16 16 03 03 00 92 0f |.x.N.8FB........| 000002a0 00 00 8e 05 03 00 8a 30 81 87 02 42 01 4c f6 31 |.......0...B.L.1| 000002b0 4f ec 64 bb ce d0 96 4d 66 f3 8d 64 78 c9 2d 47 |O.d....Mf..dx.-G| 000002c0 39 02 88 31 49 84 7f cc a8 af c1 17 35 fb 46 b1 |9..1I.......5.F.| 000002d0 dc 07 58 71 13 6b 8e 71 2b 94 fd 41 7c 26 45 39 |..Xq.k.q+..A|&E9| 000002e0 28 b1 aa f7 5b 89 04 de 84 d1 b5 d9 9f f3 02 41 |(...[..........A| 000002f0 4e f6 2a ed 39 ee 63 68 da f5 ae 1b 4d f5 01 0f |N.*.9.ch....M...| 00000300 bc f7 05 d2 96 42 67 e3 8f ff 27 d5 bf c4 53 bf |.....Bg...'...S.| 00000310 8a d7 46 58 05 54 94 d8 73 a9 d9 38 40 5f cb 8c |..FX.T..s..8@_..| 00000320 c7 d1 94 56 2a e1 61 32 29 f7 c9 c1 e8 95 30 e3 |...V*.a2).....0.| 00000330 33 14 03 03 00 01 01 16 03 03 00 24 b1 86 d2 50 |3..........$...P| 00000340 fc ea 68 b1 d9 3d b7 2c fd 2c 87 f0 d4 44 2b 22 |..h..=.,.,...D+"| 00000350 b8 47 74 77 46 14 6d 18 b3 08 9c 3a d4 a1 ba cb |.GtwF.m....:....| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 24 70 c7 ee d4 d3 |..........$p....| 00000010 d3 ad dc 5a d1 a3 01 89 4d ae 0f b9 7b 97 91 4a |...Z....M...{..J| 00000020 c0 5b e2 94 ef 5f 2f e0 90 1a 18 8a e8 50 9d |.[..._/......P.| >>> Flow 5 (client to server) 00000000 17 03 03 00 1a e8 e8 00 30 71 09 61 65 55 90 c8 |........0q.aeU..| 00000010 d6 fd 8d 5d a9 fb e6 2b d4 45 a9 8c ea 2f 0b 15 |...]...+.E.../..| 00000020 03 03 00 16 f2 d3 36 ce 26 42 59 1b d7 15 c5 c4 |......6.&BY.....| 00000030 8b 0b 06 0a d0 fd 78 62 3d 39 |......xb=9| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 59 02 00 00 55 03 03 f5 6d a6 9a 3d |....Y...U...m..=| 00000010 b4 32 c7 59 b9 f7 09 bb 56 7e 06 26 02 ac eb dd |.2.Y....V~.&....| 00000020 78 91 e4 cd f9 f4 e7 98 7f 13 f0 20 6d d5 42 4a |x.......... m.BJ| 00000030 85 ac 86 9a a6 78 6d 5c d7 ef 9d 16 dc ff 5a 41 |.....xm\......ZA| 00000040 91 5a 54 ff ba f6 90 f4 2a 4f fd 37 c0 30 00 00 |.ZT.....*O.7.0..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..| 00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.| 00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| 00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...| 000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1| 000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo| 000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000| 000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000| 000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go| 000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.| 00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...| 00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0| 00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.| 00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..| 00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd| 00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A| 00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.| 00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P| 00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.| 00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....| 000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.| 000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........| 000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.| 000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......| 000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.| 000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..| 00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#| 00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..| 00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0| 00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan| 00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........| 00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H| 00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}| 00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.| 00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5| 00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...| 000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..| 000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......| 000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....| 000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............| 000002e0 41 04 2a 2a b7 63 a8 8e 34 67 32 18 57 6e fe 2a |A.**.c..4g2.Wn.*| 000002f0 51 41 41 5f 65 a3 a7 e9 d6 0b 42 7f 77 fb 40 09 |QAA_e.....B.w.@.| 00000300 c8 7a a2 9b fd 5f 6e 2b ce 85 f6 24 c2 8d e8 bb |.z..._n+...$....| 00000310 69 3e dc 51 15 6f a8 db a4 fb 11 10 70 04 82 6a |i>.Q.o......p..j| 00000320 7b 81 04 01 00 80 7a a3 c9 1b e6 02 33 39 55 36 |{.....z.....39U6| 00000330 dc f9 2d f7 00 5b 8d f4 de 7a f7 3b 1b 4c 9a 27 |..-..[...z.;.L.'| 00000340 f6 db 3c d1 6b f8 d6 7a 20 53 33 5f 88 9f f6 73 |..<.k..z S3_...s| 00000350 90 2f 35 9e f6 05 b5 80 96 4f c8 85 e6 72 95 ba |./5......O...r..| 00000360 3b 42 43 94 c3 0b db 91 ff 6b 24 c6 b1 78 de 18 |;BC......k$..x..| 00000370 9f d5 3b 33 53 22 45 bf cb b2 d2 77 ce 03 56 7b |..;3S"E....w..V{| 00000380 b7 56 b6 ec 04 64 62 04 f7 f8 52 1a 47 49 01 71 |.V...db...R.GI.q| 00000390 29 9e ee 68 1f e9 c6 36 fb 77 4c 9a 14 90 e1 70 |)..h...6.wL....p| 000003a0 7d 7e 77 92 a6 18 16 03 03 00 2e 0d 00 00 26 03 |}~w...........&.| 000003b0 01 02 40 00 1e 06 01 06 02 06 03 05 01 05 02 05 |..@.............| 000003c0 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................| 000003d0 02 02 03 00 00 0e 00 00 00 |.........| >>> Flow 3 (client to server) 00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| 00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.| 00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| 00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0| 00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807| 00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080| 00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...| 00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.| 00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0| 000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........| 000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.| 000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...| 000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.| 000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...| 000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..| 00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn| 00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..| 00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...| 00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000| 00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0| 00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.| 00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0| 00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........| 00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....| 00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2| 000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...| 000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.| 000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.| 000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..| 000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.| 000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....| 00000200 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 88 |..h.A.Vk.Z......| 00000250 0f 00 00 84 05 01 00 80 45 11 dc 3c 2a fc 5f aa |........E..<*._.| 00000260 60 09 59 47 45 cc a7 74 e3 9d 0c c3 a4 08 b0 2a |`.YGE..t.......*| 00000270 44 47 cd 66 ed 94 54 8f d7 74 fd 47 a3 90 56 69 |DG.f..T..t.G..Vi| 00000280 5a b6 c5 b0 bd c2 16 a2 1e af 58 37 88 cb d1 4b |Z.........X7...K| 00000290 5c ee e6 0f 16 9b e0 d7 43 b3 e6 0a b2 90 fa 21 |\.......C......!| 000002a0 78 95 3e 7f fc c1 b3 df a1 bf fc eb bc e8 37 63 |x.>...........7c| 000002b0 87 33 3e c3 9a e4 6c 0f 3d 0d 9f e8 db 2d 82 ad |.3>...l.=....-..| 000002c0 3c 6d f7 4a 5e 81 21 4f 19 0e 60 2d ef c1 40 8d |>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 b1 23 11 48 69 |..........(.#.Hi| 00000010 52 44 34 f1 9a 69 2b 79 fb 68 b4 53 d5 d7 08 08 |RD4..i+y.h.S....| 00000020 34 95 5f 56 b2 57 eb 91 31 6c 32 25 b5 68 8a 8e |4._V.W..1l2%.h..| 00000030 f1 68 6e |.hn| >>> Flow 5 (client to server) 00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 03 ab 9e |................| 00000010 f0 a6 6c f1 ea 23 20 63 42 a3 9d c6 5d 41 96 c1 |..l..# cB...]A..| 00000020 44 b2 8b 15 03 03 00 1a 00 00 00 00 00 00 00 02 |D...............| 00000030 e9 73 41 50 28 b0 d3 00 46 81 d6 c9 1a ca ab cd |.sAP(...F.......| 00000040 44 9b |D.| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 59 02 00 00 55 03 03 2a 01 f8 3e d1 |....Y...U..*..>.| 00000010 52 41 2e 9a 8d 56 ff 52 3d 6a fe 65 ab 91 bb b7 |RA...V.R=j.e....| 00000020 82 be f1 60 40 3b 80 a1 f8 dc 95 20 48 87 41 46 |...`@;..... H.AF| 00000030 6a d2 f3 b8 d8 68 20 40 45 b7 fe 19 21 bc 84 00 |j....h @E...!...| 00000040 5d 40 40 21 58 3e 7d fb a7 e3 30 37 c0 09 00 00 |]@@!X>}...07....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| 00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0| 00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| 000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| 000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| 000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| 000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506| 000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063| 000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A| 00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some| 00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...| 00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit| 00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...| 00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..| 00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.| 00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.| 00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d| 00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i| 00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.| 000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#| 000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.| 000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.| 000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=| 000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.| 000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^| 00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......| 00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y| 00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.| 00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3| 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| 00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 00 |*............A..| 00000280 9e 90 3a 3d 00 37 0a c0 43 92 6e bf b4 23 d9 64 |..:=.7..C.n..#.d| 00000290 99 d2 90 9e eb 88 b6 d6 6f 15 4a 22 72 f0 bf 5e |........o.J"r..^| 000002a0 72 80 93 90 aa f1 d1 9c 45 c6 6e 3a f8 a9 6f fe |r.......E.n:..o.| 000002b0 fb 24 dc b1 4d 52 39 91 f5 48 36 06 f6 15 0e 04 |.$..MR9..H6.....| 000002c0 03 00 8b 30 81 88 02 42 00 a9 54 74 a7 a8 d0 04 |...0...B..Tt....| 000002d0 ae ef e4 64 38 74 21 e6 18 f0 79 b2 d7 7e 7b 0e |...d8t!...y..~{.| 000002e0 f6 74 75 52 f0 b8 15 3c 3d 15 52 75 9f 60 03 63 |.tuR...<=.Ru.`.c| 000002f0 15 b8 1e b8 0e 5c 58 c7 e7 2f 6d 76 c7 c8 42 7a |.....\X../mv..Bz| 00000300 df 15 26 4b dc 9c 3b 4d b3 b6 02 42 00 a5 fd bf |..&K..;M...B....| 00000310 a9 5d fc 87 42 24 f9 0b 7a 17 97 7c ee 45 1c 29 |.]..B$..z..|.E.)| 00000320 3a 07 5f df 4d f2 d3 cb fc a6 fd 84 34 2c 40 84 |:._.M.......4,@.| 00000330 06 76 bf 43 35 d2 f6 9a 7c d6 1b 5e d8 fd 08 35 |.v.C5...|..^...5| 00000340 1b 90 0e 24 a7 48 9d 71 ab 4a 11 92 d3 6e 16 03 |...$.H.q.J...n..| 00000350 03 00 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 |......&...@.....| 00000360 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| 00000370 01 03 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 |................| 00000380 00 |.| >>> Flow 3 (client to server) 00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| 00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.| 00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| 00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0| 00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807| 00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080| 00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...| 00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.| 00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0| 000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........| 000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.| 000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...| 000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.| 000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...| 000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..| 00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn| 00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..| 00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...| 00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000| 00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0| 00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.| 00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0| 00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........| 00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....| 00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2| 000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...| 000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.| 000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.| 000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..| 000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.| 000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....| 00000200 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 88 |..h.A.Vk.Z......| 00000250 0f 00 00 84 05 01 00 80 20 ef 4b 1c d7 67 37 6e |........ .K..g7n| 00000260 24 12 9e e9 59 b1 6d da e5 3e 6b 11 03 f4 96 e4 |$...Y.m..>k.....| 00000270 2e fb 03 e1 13 af 73 4d 15 11 c1 80 e2 ed 11 c6 |......sM........| 00000280 73 6a 96 ce d1 26 e4 bc fe 71 c9 48 32 fd d8 70 |sj...&...q.H2..p| 00000290 01 9d 18 7b ed a3 bd 6a 68 df 45 a0 d5 77 79 d2 |...{...jh.E..wy.| 000002a0 5b e2 8c 96 68 95 46 8d 7d e6 b6 26 fa e1 c4 05 |[...h.F.}..&....| 000002b0 4c d1 39 4e 35 e3 0c 1b 26 37 2e 0b 9b 0b cf f7 |L.9N5...&7......| 000002c0 25 c3 da 27 18 70 83 18 49 ff ee ba e3 f8 70 75 |%..'.p..I.....pu| 000002d0 e8 9b 2d 89 d7 b2 00 a5 14 03 03 00 01 01 16 03 |..-.............| 000002e0 03 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 |..@.............| 000002f0 00 00 00 d3 33 79 85 64 14 07 a6 93 74 f8 f8 55 |....3y.d....t..U| 00000300 0f fb fc 8e 1b 4c 38 21 b6 61 c5 4b b2 d4 17 b2 |.....L8!.a.K....| 00000310 c4 be a6 4b d6 3f a3 5f 3c ff 5f 1d 93 a2 c4 82 |...K.?._<._.....| 00000320 96 90 eb |...| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 80 b0 df ff b3 |..........@.....| 00000010 34 11 03 f5 2d fb c7 c2 38 15 df 41 97 55 0e 1d |4...-...8..A.U..| 00000020 36 f7 a5 35 5b 63 d7 c5 a6 fd fc a1 91 32 9d cd |6..5[c.......2..| 00000030 34 66 75 4c 5d 27 ee 89 ed d4 4a ec 67 b0 da e7 |4fuL]'....J.g...| 00000040 f0 e7 36 eb db b9 22 97 74 30 cd |..6...".t0.| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| 00000010 00 00 00 00 00 62 24 32 e9 40 38 c8 c3 dd 07 42 |.....b$2.@8....B| 00000020 05 c8 7c 3d d1 27 68 00 e4 91 6c 2d 08 c1 a1 b6 |..|=.'h...l-....| 00000030 8a 89 3d 1d c1 15 03 03 00 30 00 00 00 00 00 00 |..=......0......| 00000040 00 00 00 00 00 00 00 00 00 00 d1 c8 bc cb cb a5 |................| 00000050 24 1e ad c5 bf 23 92 4b 81 a6 c0 77 19 e0 46 30 |$....#.K...w..F0| 00000060 48 51 0c cc 39 cd 4b 8d e5 a7 |HQ..9.K...| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 51 02 00 00 4d 03 03 60 8e 1c c9 6d |....Q...M..`...m| 00000010 de 9d 2a dc 6a a6 82 71 9a 3f 8f 5b 18 52 44 4e |..*.j..q.?.[.RDN| 00000020 4d 72 0d e7 c8 a1 b0 81 64 8c 1f 20 06 a8 17 35 |Mr......d.. ...5| 00000030 b8 0b 96 52 30 f7 b3 d4 2a 25 94 c0 ba a8 a2 f7 |...R0...*%......| 00000040 86 5c 18 18 3c 68 3a 71 0f bc 3f 12 00 05 00 00 |.\..c.k| 00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002d0 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 06 |....&...@.......| 000002e0 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................| 000002f0 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 00 |...............| >>> Flow 3 (client to server) 00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| 00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.| 00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| 00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0| 00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807| 00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080| 00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...| 00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.| 00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0| 000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........| 000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.| 000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...| 000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.| 000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...| 000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..| 00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn| 00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..| 00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...| 00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000| 00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0| 00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.| 00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0| 00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........| 00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....| 00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2| 000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...| 000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.| 000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.| 000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..| 000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.| 000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....| 00000200 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.| 00000210 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....| 00000220 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......| 00000230 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..| 00000240 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.| 00000250 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..| 00000260 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k| 00000270 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..| 00000280 4d e5 78 13 4e a4 38 46 42 dc 16 16 03 03 00 88 |M.x.N.8FB.......| 00000290 0f 00 00 84 05 01 00 80 21 58 47 70 c2 2e 1c 4a |........!XGp...J| 000002a0 fa 97 b2 cf 8d f8 93 f4 b0 8c b3 e0 e7 33 a6 ea |.............3..| 000002b0 d7 fe 8e 25 e7 f3 f5 a1 8d 09 b7 0b 01 ec a1 15 |...%............| 000002c0 5b 67 06 53 2a 7d 31 e5 a8 16 bc e3 1d ed 5a 77 |[g.S*}1.......Zw| 000002d0 0b 78 78 c5 fc c5 62 8e 41 49 d3 ea cd 69 10 3f |.xx...b.AI...i.?| 000002e0 34 9e 86 df f9 9f f6 02 0c 29 c4 66 a0 45 cf 7b |4........).f.E.{| 000002f0 ce 51 ec 0a 26 b4 9d 3d 9e 63 5d 40 1a e8 84 4e |.Q..&..=.c]@...N| 00000300 24 f5 42 48 b5 3e f8 92 c4 f2 e6 5d f4 ad 67 01 |$.BH.>.....]..g.| 00000310 f8 a7 a7 2b b5 fc be e8 14 03 03 00 01 01 16 03 |...+............| 00000320 03 00 24 f0 ec 1d f5 39 1c d2 d2 c7 f4 1f 3b 0c |..$....9......;.| 00000330 cd 25 e4 8e ed c4 bb 02 9d 38 e5 a7 91 e0 ea 00 |.%.......8......| 00000340 73 a8 9a 63 c9 e7 7d |s..c..}| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 24 0b c5 7d ca a6 |..........$..}..| 00000010 87 7f 50 7b 88 9c d9 8e ea 78 a0 40 6b 8e 92 0b |..P{.....x.@k...| 00000020 78 88 97 46 ec 7c 20 5b 1f fc da 49 d8 6a be |x..F.| [...I.j.| >>> Flow 5 (client to server) 00000000 17 03 03 00 1a 16 25 97 df 98 e4 d6 8e d1 2c 0c |......%.......,.| 00000010 27 74 67 e5 b7 f1 c7 58 41 5f 04 f5 e4 74 dc 15 |'tg....XA_...t..| 00000020 03 03 00 16 df 55 01 0d 53 5b b4 36 c7 88 8d b0 |.....U..S[.6....| 00000030 22 53 ec 87 1b 07 c7 9d af 89 |"S........| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 59 02 00 00 55 03 03 8a ae 27 5b 39 |....Y...U....'[9| 00000010 8b c4 a6 d5 fa 9e 67 9e 6c fe 53 ed ab ec e0 04 |......g.l.S.....| 00000020 8d 7c f8 1f d0 db 2e cb 22 4d a1 20 ee 80 5f fc |.|......"M. .._.| 00000030 f8 77 8a 23 23 c5 95 81 7f a6 12 f5 e0 19 91 50 |.w.##..........P| 00000040 da 75 42 c2 eb 45 bf e2 a5 54 ed 6e c0 09 00 00 |.uB..E...T.n....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| 00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0| 00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| 000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| 000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| 000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| 000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506| 000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063| 000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A| 00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some| 00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...| 00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit| 00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...| 00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..| 00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.| 00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.| 00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d| 00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i| 00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.| 000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#| 000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.| 000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.| 000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=| 000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.| 000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^| 00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......| 00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y| 00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.| 00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3| 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| 00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 3e |*............A.>| 00000280 e3 d6 d6 7b d7 ec 6f 4b 88 50 53 26 5a 2b a6 69 |...{..oK.PS&Z+.i| 00000290 25 6f 30 a7 c3 a5 39 5c e2 ca b6 35 a5 30 35 9a |%o0...9\...5.05.| 000002a0 35 8f e3 65 bd 4c 47 30 72 9a 4b 32 c4 6d 01 c9 |5..e.LG0r.K2.m..| 000002b0 a5 91 d1 cd 0b 79 e2 04 0f a9 9c c2 72 cd 58 04 |.....y......r.X.| 000002c0 03 00 8a 30 81 87 02 41 70 01 8c dd 0a 32 db e3 |...0...Ap....2..| 000002d0 0b 04 9c d0 64 a1 08 06 b1 cf e3 66 79 1f c0 c1 |....d......fy...| 000002e0 14 34 87 a6 e5 52 11 20 12 24 a5 b6 c2 50 63 86 |.4...R. .$...Pc.| 000002f0 31 6a e3 85 7d 19 2d 3b 68 bf b7 64 20 37 c7 f9 |1j..}.-;h..d 7..| 00000300 76 38 b5 32 84 0b f9 b6 71 02 42 01 89 e3 93 85 |v8.2....q.B.....| 00000310 d6 16 8e 44 66 72 d6 9f b3 b1 e9 22 ad 2e f8 49 |...Dfr....."...I| 00000320 41 8f 80 f9 0e d4 fd de 35 67 cf 09 ba 65 f7 a1 |A.......5g...e..| 00000330 17 a8 c0 b5 a3 cc c0 17 83 af 68 92 5b 5c a9 ce |..........h.[\..| 00000340 ce 11 92 93 fe 39 b9 80 19 20 f2 b6 3b 16 03 03 |.....9... ..;...| 00000350 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| 00000060 00 00 00 00 00 00 39 19 e6 fb c7 28 b4 c9 f5 ba |......9....(....| 00000070 a2 44 0a 74 70 18 86 1f 5f c2 3d 99 f5 d7 17 04 |.D.tp..._.=.....| 00000080 88 07 a5 06 01 6a 2c 13 55 0b fc 82 75 b5 24 54 |.....j,.U...u.$T| 00000090 a0 63 9e f0 ce 92 |.c....| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 15 37 89 e6 1f |..........@.7...| 00000010 20 f6 91 b9 1f fb 29 e9 3e 07 ab c2 09 96 06 89 | .....).>.......| 00000020 69 c2 dd 63 e1 24 5d cd af 08 e2 ed df 46 45 6b |i..c.$]......FEk| 00000030 1e 9f 62 b6 89 27 04 3f fc f2 77 71 23 04 24 37 |..b..'.?..wq#.$7| 00000040 74 8a 0a 64 a8 10 e3 1c dc 53 64 |t..d.....Sd| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| 00000010 00 00 00 00 00 ae 4e e7 3a 25 9d 8f fa 06 99 49 |......N.:%.....I| 00000020 2e b8 0f 49 d0 54 2d 06 b4 d7 4c 60 51 f1 13 11 |...I.T-...L`Q...| 00000030 c1 b3 f5 d0 bc 15 03 03 00 30 00 00 00 00 00 00 |.........0......| 00000040 00 00 00 00 00 00 00 00 00 00 80 de bf db 10 74 |...............t| 00000050 da 3f d8 77 ca 37 cc f3 96 bd d3 e1 34 9c f2 0a |.?.w.7......4...| 00000060 70 60 5e 7c a4 7e c9 bd 89 5f |p`^|.~..._| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 59 02 00 00 55 03 03 42 ab c5 81 f5 |....Y...U..B....| 00000010 c0 5b 73 64 f6 1b e0 59 30 b0 fd c5 e6 b3 57 f2 |.[sd...Y0.....W.| 00000020 28 3f 5c d2 e8 05 7d a8 29 84 2e 20 8e 18 6b 52 |(?\...}.).. ..kR| 00000030 1b ee 03 02 64 52 fb 24 44 4f 39 f2 d3 0f e6 9d |....dR.$DO9.....| 00000040 50 31 31 b3 39 9e c1 3a b3 67 41 a0 c0 2b 00 00 |P11.9..:.gA..+..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| 00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0| 00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| 000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| 000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| 000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| 000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506| 000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063| 000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A| 00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some| 00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...| 00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit| 00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...| 00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..| 00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.| 00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.| 00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d| 00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i| 00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.| 000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#| 000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.| 000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.| 000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=| 000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.| 000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^| 00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......| 00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y| 00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.| 00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3| 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| 00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 7a |*............A.z| 00000280 01 b4 2c 50 85 34 6e 2c 2c 52 bc fa cf 71 82 e5 |..,P.4n,,R...q..| 00000290 98 8d b0 f1 65 5f 7d bc c8 1b 7c 84 3e 46 45 c5 |....e_}...|.>FE.| 000002a0 43 0e 72 e1 90 63 40 26 1c 22 dc 9a 3b b8 12 26 |C.r..c@&."..;..&| 000002b0 a9 d6 1c e1 44 cf c7 38 db 9e 1b d0 b9 bb 06 04 |....D..8........| 000002c0 03 00 8b 30 81 88 02 42 01 6b af f8 34 ae 89 50 |...0...B.k..4..P| 000002d0 df 44 20 16 0b f9 ef a9 99 63 39 48 39 08 69 2d |.D ......c9H9.i-| 000002e0 2d 9d 8b 3a e8 8a 9c 2f e9 d2 85 f2 d3 54 53 ec |-..:.../.....TS.| 000002f0 b7 18 5b b0 76 3c 38 02 85 cc 00 20 45 9d e7 ba |..[.v<8.... E...| 00000300 c0 3f c0 b5 1f df 64 42 fd 34 02 42 00 fa e5 dd |.?....dB.4.B....| 00000310 04 c4 60 60 ff 9b 95 a2 a4 b4 80 87 9f 59 b4 8e |..``.........Y..| 00000320 72 bf 53 8e 61 b6 df 99 9d 81 05 c5 71 a2 00 cb |r.S.a.......q...| 00000330 80 bd e5 2a c3 51 d0 45 2f a3 8b 6d 21 6e 6c 80 |...*.Q.E/..m!nl.| 00000340 4e f1 28 23 6d 76 df 55 77 69 a1 be 39 05 16 03 |N.(#mv.Uwi..9...| 00000350 03 00 04 0e 00 00 00 |.......| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 94 ba |.....(..........| 00000060 0a c6 38 6b 65 60 95 5e df fc 42 7e ac 9f 5a 25 |..8ke`.^..B~..Z%| 00000070 39 0e a9 7a 61 b3 17 80 77 82 e5 80 0a af |9..za...w.....| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 ef 8d ac 17 6f |..........(....o| 00000010 88 03 88 8f f3 d5 a0 60 28 a9 4d e8 20 ae 0c 21 |.......`(.M. ..!| 00000020 fd d1 50 9b c3 d1 e9 cd 27 ed d7 8b 92 60 49 47 |..P.....'....`IG| 00000030 ed 9a 74 |..t| >>> Flow 5 (client to server) 00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 1d 4f 3c |..............O<| 00000010 c5 d1 39 01 46 ab 7d d1 75 59 e7 f5 cd fa 02 0b |..9.F.}.uY......| 00000020 dd 02 17 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| 00000030 e9 a5 d5 0c 05 2a 82 fe a5 6c 03 6e d0 c4 7d cb |.....*...l.n..}.| 00000040 32 f3 |2.| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 59 02 00 00 55 03 03 ed 6d 5a 1c 89 |....Y...U...mZ..| 00000010 a4 f3 35 0b e4 74 7e e2 05 a5 36 4d 4a 55 b3 7c |..5..t~...6MJU.|| 00000020 a1 a6 42 a3 fc 35 8c e0 97 5b 4b 20 a1 4a 06 28 |..B..5...[K .J.(| 00000030 4d 40 0b fc 47 d5 4d 9b d5 43 b0 0d 0d c6 ae 30 |M@..G.M..C.....0| 00000040 79 59 00 d4 90 96 98 92 d2 3a 57 07 c0 2c 00 00 |yY.......:W..,..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| 00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0| 00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| 000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| 000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| 000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| 000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506| 000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063| 000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A| 00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some| 00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...| 00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit| 00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...| 00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..| 00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.| 00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.| 00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d| 00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i| 00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.| 000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#| 000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.| 000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.| 000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=| 000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.| 000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^| 00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......| 00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y| 00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.| 00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3| 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| 00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 89 |*............A..| 00000280 e6 6d 6a 56 3e e5 4e 72 df 2b 41 11 de a0 c0 3e |.mjV>.Nr.+A....>| 00000290 22 04 9a b5 a8 d6 22 30 2a e5 bd 83 1c 7a 8e 6c |"....."0*....z.l| 000002a0 93 ab 8f d7 64 9e fe 89 c0 da 9a 45 7d 76 91 69 |....d......E}v.i| 000002b0 0a 11 c5 59 26 49 ec 69 99 b3 91 a5 4b 2b 89 04 |...Y&I.i....K+..| 000002c0 03 00 8a 30 81 87 02 42 01 17 1d ff 9a 99 76 20 |...0...B......v | 000002d0 13 8a e1 5a a8 04 8a 1e 84 57 fd b0 95 c1 6c af |...Z.....W....l.| 000002e0 b2 66 13 b5 75 36 ce 86 69 67 3d dc 82 2f 06 57 |.f..u6..ig=../.W| 000002f0 19 14 56 54 0e 8e 04 74 0b 73 49 61 92 8e d1 9a |..VT...t.sIa....| 00000300 b5 60 7f 65 a8 f8 99 eb ac 56 02 41 57 a3 78 57 |.`.e.....V.AW.xW| 00000310 8a dd fa 9c 3d 24 a0 f2 0a 74 1a 8a 8f 6c 82 55 |....=$...t...l.U| 00000320 4c cd d8 5d 79 99 87 93 41 e7 78 f4 28 0d ef 63 |L..]y...A.x.(..c| 00000330 fb da 8e 93 86 31 6e 3e ca 6f 6b 1b fd 7a a3 86 |.....1n>.ok..z..| 00000340 6e bb 17 35 90 d9 a4 df 12 d0 54 5e 25 16 03 03 |n..5......T^%...| 00000350 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 9d e7 |.....(..........| 00000060 31 2a 0a 46 84 fd d9 18 c2 b0 b1 31 eb 63 4d 2d |1*.F.......1.cM-| 00000070 ee 17 59 e6 b4 0f c6 d8 3d 8c e9 57 83 a8 |..Y.....=..W..| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 e0 85 25 02 b4 |..........(..%..| 00000010 86 32 57 70 3c 7e 6b e5 75 e0 3a 43 c8 c2 fe f8 |.2Wp<~k.u.:C....| 00000020 2e 04 fe 73 e4 7b 2c 9a e0 65 2e d6 53 ae f1 19 |...s.{,..e..S...| 00000030 dd 6f 1a |.o.| >>> Flow 5 (client to server) 00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 29 b2 e6 |.............)..| 00000010 c3 2e 72 ba cc ac d9 3b c7 0c 1d 53 b2 30 39 71 |..r....;...S.09q| 00000020 6e dd 79 15 03 03 00 1a 00 00 00 00 00 00 00 02 |n.y.............| 00000030 88 c9 92 fe 6c 1f 6c fd bd 7b fb 0a 8a b5 cc c9 |....l.l..{......| 00000040 94 90 |..| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 59 02 00 00 55 03 03 2a 6a a8 b3 97 |....Y...U..*j...| 00000010 d5 c8 5e b4 22 7e d0 a5 c7 46 af 89 60 44 77 5e |..^."~...F..`Dw^| 00000020 1a f8 3a 30 08 6d 5f 4c 61 36 c5 20 57 79 91 3e |..:0.m_La6. Wy.>| 00000030 1f 40 d1 f1 33 d7 a9 fb 93 eb 16 0d e1 39 e3 a3 |.@..3........9..| 00000040 80 e3 4f 58 a6 f8 a4 be 19 dd ef ee c0 13 00 00 |..OX............| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..| 00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.| 00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| 00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...| 000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1| 000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo| 000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000| 000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000| 000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go| 000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.| 00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...| 00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0| 00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.| 00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..| 00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd| 00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A| 00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.| 00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P| 00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.| 00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....| 000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.| 000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........| 000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.| 000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......| 000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.| 000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..| 00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#| 00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f..@..| 00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0| 00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan| 00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........| 00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H| 00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}| 00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.| 00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5| 00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...| 000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..| 000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O......@.Q......| 000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....| 000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............| 000002e0 41 04 8e c8 e8 42 7c 8a 01 c2 ff 01 cb 0b e1 20 |A....B|........ | 000002f0 50 42 d4 3a 1b 34 ff 74 59 81 2f a2 0e 29 b2 f9 |PB.:.4.tY./..)..| 00000300 47 cf 0d 08 97 cf aa 9f fe f0 7f e8 f4 fd 3a fa |G.............:.| 00000310 a6 b6 47 32 d3 25 78 87 bf 77 cc 12 37 02 6a ad |..G2.%x..w..7.j.| 00000320 cf 2c 04 01 00 80 13 a1 95 17 7b 21 86 7f f2 02 |.,........{!....| 00000330 9f ed 88 2d 1f 2c 38 96 bc fa 5a 39 85 4b 9f ff |...-.,8...Z9.K..| 00000340 5c 7a 02 1e 5f c9 4a 69 51 d3 83 34 9f dc 8c 39 |\z.._.JiQ..4...9| 00000350 fe 81 76 fc c3 59 ff e2 a8 81 ca 6f f6 52 c9 44 |..v..Y.....o.R.D| 00000360 a0 3f 5e 5e 92 20 db d9 2e 0b e3 ab 75 e7 79 f6 |.?^^. ......u.y.| 00000370 b2 73 17 e1 94 1e 12 62 e9 b0 0f 04 e7 5d 83 ac |.s.....b.....]..| 00000380 71 ca a5 62 40 dd 69 b1 3f cf bb 3d c7 3e 51 6c |q..b@.i.?..=.>Ql| 00000390 11 f2 cf 39 f1 b5 72 bd 52 d4 3d 3c c0 90 34 c8 |...9..r.R.=<..4.| 000003a0 4b 22 55 39 1c 2b 16 03 03 00 04 0e 00 00 00 |K"U9.+.........| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| 00000060 00 00 00 00 00 00 a2 6e de ea 78 0c 4d 20 ad 1f |.......n..x.M ..| 00000070 1a f5 6b 15 09 f1 50 bb cd 40 0e c7 d9 ed 7f e1 |..k...P..@......| 00000080 4b bc d3 26 5d 89 b7 26 c5 6c 0e 59 6f 84 51 5d |K..&]..&.l.Yo.Q]| 00000090 2f 75 d8 0f 2e e8 |/u....| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 dd d8 e7 63 89 |..........@...c.| 00000010 8e cc 3e e0 df 6d 5a 42 b3 49 1b 66 e8 79 e9 f0 |..>..mZB.I.f.y..| 00000020 8a c3 0e 5e d7 01 ac 04 81 6a e1 60 14 60 b9 a6 |...^.....j.`.`..| 00000030 4c a5 46 43 74 df 30 1e f8 74 77 4c b5 42 e5 25 |L.FCt.0..twL.B.%| 00000040 81 9d b1 04 bc 02 46 bd b1 55 d0 |......F..U.| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| 00000010 00 00 00 00 00 35 49 6d a7 3f a1 39 5d 37 8d 2e |.....5Im.?.9]7..| 00000020 c5 1e 90 3b f9 60 58 d3 47 e3 db 73 8b aa 6c 9e |...;.`X.G..s..l.| 00000030 b5 82 55 09 62 15 03 03 00 30 00 00 00 00 00 00 |..U.b....0......| 00000040 00 00 00 00 00 00 00 00 00 00 71 b3 7b c7 d4 27 |..........q.{..'| 00000050 f9 77 7f d0 80 25 1b 43 d0 0e 92 38 8c f3 2f 50 |.w...%.C...8../P| 00000060 eb 96 22 fb e6 09 45 ec 7f 16 |.."...E...| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-RSA-RC4 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 51 02 00 00 4d 03 03 79 8f 56 ac 75 |....Q...M..y.V.u| 00000010 4f a9 fc 2c b9 53 82 a6 b4 c8 0d 4e 50 9a 9e aa |O..,.S.....NP...| 00000020 8d ed 21 21 91 5d a2 cc 99 1b 68 20 0c e7 35 50 |..!!.]....h ..5P| 00000030 67 02 70 2a 45 0d 6c 4c 46 df 75 dc 5f 6e 2f 79 |g.p*E.lLF.u._n/y| 00000040 03 26 da 45 53 25 50 23 c0 85 3b 8c 00 05 00 00 |.&.ES%P#..;.....| 00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002d0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.| 00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....| 00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......| 00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..| 00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.| 00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..| 00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k| 00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..| 00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 03 00 01 |M.x.N.8FB.......| 00000090 01 16 03 03 00 24 72 bd b1 13 05 73 26 c0 0b ec |.....$r....s&...| 000000a0 e6 39 08 6a 2d 87 00 51 58 9d e3 8d da be 60 98 |.9.j-..QX.....`.| 000000b0 0a ee 0c 96 13 f4 e5 30 90 85 |.......0..| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 24 d4 ad ab a0 01 |..........$.....| 00000010 1b 87 9c aa c4 27 08 b5 8c 4a 7f fc 03 df a6 d6 |.....'...J......| 00000020 f8 6c d1 61 7c d3 1f 6d 18 c3 8d 88 5c 7b cf |.l.a|..m....\{.| >>> Flow 5 (client to server) 00000000 17 03 03 00 1a 33 a8 7a 61 46 09 7b 64 e6 aa f8 |.....3.zaF.{d...| 00000010 8a 43 d3 a9 0c e9 2e c0 89 7c 72 fb 75 50 50 15 |.C.......|r.uPP.| 00000020 03 03 00 16 2b b9 b5 eb f8 bd 53 20 ea 67 bc 47 |....+.....S .g.G| 00000030 83 cf c5 6e f9 4f 9e 12 f5 1a |...n.O....| ================================================ FILE: scan/crypto/tls/testdata/Client-TLSv12-SCT ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./| 00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| 00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....| 00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............| 00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| 00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| 00000080 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 01 c6 02 00 01 c2 03 03 5d d8 84 38 51 |...........]..8Q| 00000010 c6 51 9e 6c d3 e0 b2 d7 81 2a 9b 1c 06 0b 11 c8 |.Q.l.....*......| 00000020 54 90 f3 d1 66 83 7a 68 2f 65 8b 20 ac 8b 35 9a |T...f.zh/e. ..5.| 00000030 31 25 04 c9 89 31 27 80 8f 10 74 8e 3c 4f 20 bc |1%...1'...t..zz2..| 000000b0 60 74 de 08 da 05 91 4c 2f 02 20 73 54 1b 6e 7f |`t.....L/. sT.n.| 000000c0 a1 b0 7d 11 bc e6 f3 85 2f 97 66 1a f7 8a e4 10 |..}...../.f.....| 000000d0 25 8f 12 f4 6f 39 0f d2 9e 18 f0 00 76 00 68 f6 |%...o9......v.h.| 000000e0 98 f8 1f 64 82 be 3a 8c ee b9 28 1d 4c fc 71 51 |...d..:...(.L.qQ| 000000f0 5d 67 93 d4 44 d1 0a 67 ac bb 4f 4f fb c4 00 00 |]g..D..g..OO....| 00000100 01 47 97 e1 b5 70 00 00 04 03 00 47 30 45 02 20 |.G...p.....G0E. | 00000110 32 21 14 38 06 d8 72 2e 00 30 64 1a e2 e8 6d 4e |2!.8..r..0d...mN| 00000120 5a e1 d9 42 1e 82 4b 96 25 89 d5 26 13 d3 9c fa |Z..B..K.%..&....| 00000130 02 21 00 8f 12 28 64 51 4f 44 d5 8c 18 62 23 b2 |.!...(dQOD...b#.| 00000140 43 93 33 05 f3 43 55 a1 d9 ee cd c5 71 35 91 dd |C.3..CU.....q5..| 00000150 49 d1 0b 00 76 00 ee 4b bd b7 75 ce 60 ba e1 42 |I...v..K..u.`..B| 00000160 69 1f ab e1 9e 66 a3 0f 7e 5f b0 72 d8 83 00 c4 |i....f..~_.r....| 00000170 7b 89 7a a8 fd cb 00 00 01 48 5c 64 8a 87 00 00 |{.z......H\d....| 00000180 04 03 00 47 30 45 02 20 29 89 d6 b0 53 d3 d2 e9 |...G0E. )...S...| 00000190 91 bc f1 b5 40 be 1e 2e e7 5c b4 74 27 ed 8f 9b |....@....\.t'...| 000001a0 02 e9 fa c2 4c ba a2 be 02 21 00 af 43 64 52 71 |....L....!..CdRq| 000001b0 15 29 58 40 91 c7 08 16 96 03 a8 73 a5 65 a0 6c |.)X@.......s.e.l| 000001c0 b8 48 56 5a b6 29 83 64 6d 2a 9d 16 03 03 02 71 |.HVZ.).dm*.....q| 000001d0 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 |...m..j..g0..c0.| 000001e0 01 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 |...........s....| 000001f0 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......| 00000200 00 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |.0+1.0...U....Go| 00000210 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e |ogle TESTING1.0.| 00000220 06 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e |..U....Go Root0.| 00000230 17 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 |..150101000000Z.| 00000240 0d 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 |.250101000000Z0&| 00000250 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c |1.0...U....Googl| 00000260 65 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 |e TESTING1.0...U| 00000270 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 |....Go0..0...*.H| 00000280 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 |............0...| 00000290 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 |....... ..el..D.| 000002a0 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 |.;E...m..cM...jb| 000002b0 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 |5..J..|..%^zd1f.| 000002c0 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 |......k.v.._A.nV| 000002d0 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db |.....<.9!f=+....| 000002e0 1c c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d |...........!P...| 000002f0 ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 |..k.K......l..D.| 00000300 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 |.!..}..M........| 00000310 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e |G..........0..0.| 00000320 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d |..U...........0.| 00000330 06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 |..U.%..0...+....| 00000340 07 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 |.....+.......0..| 00000350 03 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 |.U.......0.0...U| 00000360 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d |.......P..o...TM| 00000370 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 |n.i^..0...U.#..0| 00000380 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 |....=..f..@....x| 00000390 48 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e |H.A0...U....0...| 000003a0 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d |example.golang0.| 000003b0 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 |..*.H...........| 000003c0 00 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d |..|..U...Y1.H@.-| 000003d0 d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 |........|..0}<.v| 000003e0 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 |.O=...-3$k.{.gY.| 000003f0 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f |!...w...n.-.5.d_| 00000400 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 |">c.k....m...1..| 00000410 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db |8.;..,...Qv..O..| 00000420 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 |....@.Q......F.F| 00000430 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 |.O.....A4......9| 00000440 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 1e |.............A..| 00000450 d1 1c 5c d3 00 41 84 cd f7 e2 78 ad b5 7d 5b f2 |..\..A....x..}[.| 00000460 23 5b 1a 18 44 3f 86 8e 3e 52 f2 4b b6 7d 84 b4 |#[..D?..>R.K.}..| 00000470 1d 98 83 8f 2f 58 07 92 1f 58 2a 8d 8c e3 fa b7 |..../X...X*.....| 00000480 aa 78 7e 33 9a 64 b9 b6 cb 78 94 be 2b c3 ac 04 |.x~3.d...x..+...| 00000490 01 00 80 65 9f 42 e3 24 5c cd 18 aa 08 8e 6b bf |...e.B.$\.....k.| 000004a0 39 15 2a a3 e6 42 1c 9d 6b 34 39 a2 2c 58 f5 5f |9.*..B..k49.,X._| 000004b0 3e fb 2a 4c 01 2b e5 20 4e f5 69 77 c1 62 8f 68 |>.*L.+. N.iw.b.h| 000004c0 be b4 c4 77 27 c9 4a 97 6d 18 7f 45 fd c9 9e 24 |...w'.J.m..E...$| 000004d0 19 6b d9 00 c5 52 1a 34 a3 c9 cb eb 92 fc f6 48 |.k...R.4.......H| 000004e0 3d 89 8a ff 82 be 55 c9 92 e2 24 86 b0 99 c6 e8 |=.....U...$.....| 000004f0 a5 4c b7 bc 5a e5 f3 81 94 ee 15 47 e7 5e 8c 66 |.L..Z......G.^.f| 00000500 32 72 7d 81 78 61 fe 25 98 dd 07 a2 92 4c eb ed |2r}.xa.%.....L..| 00000510 f1 a7 17 16 03 03 00 04 0e 00 00 00 |............| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 f0 4f |.....(.........O| 00000060 fe 22 53 9e e1 61 f4 45 4e 41 ff 5e e4 63 25 f7 |."S..a.ENA.^.c%.| 00000070 b2 f6 0a ea 89 75 7f d4 e7 3a cc e8 c2 2c |.....u...:...,| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 ad 49 0a 66 16 |..........(.I.f.| 00000010 6d 64 42 c2 ab 38 bf 81 3d d9 14 13 d6 69 27 81 |mdB..8..=....i'.| 00000020 ea 5c 53 fd 6c bf 81 6c 06 81 a5 67 f2 cd ed a3 |.\S.l..l...g....| 00000030 d4 c2 08 |...| >>> Flow 5 (client to server) 00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 5c ab e3 |.............\..| 00000010 f9 61 72 9e 44 46 1a 05 e9 00 eb 5b e0 73 22 03 |.ar.DF.....[.s".| 00000020 9f 90 f9 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| 00000030 04 28 a4 9d 07 79 95 40 0f f0 eb b9 5d 97 bf 87 |.(...y.@....]...| 00000040 4a b6 |J.| ================================================ FILE: scan/crypto/tls/testdata/Server-SSLv3-RSA-3DES ================================================ >>> Flow 1 (client to server) 00000000 16 03 00 00 30 01 00 00 2c 03 00 50 32 2f f9 d5 |....0...,..P2/..| 00000010 8f 83 ac 79 0e 0b e5 65 2c 87 79 01 7d 15 73 00 |...y...e,.y.}.s.| 00000020 46 7c dc c6 6d 70 0b f3 d2 dc de 00 00 04 00 0a |F|..mp..........| 00000030 00 ff 02 01 00 |.....| >>> Flow 2 (server to client) 00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 00 00 84 10 00 00 80 48 96 89 e9 d2 e6 c6 |.........H......| 00000010 eb 9d f8 46 dd c7 d8 01 95 57 76 1a 59 1c 79 21 |...F.....Wv.Y.y!| 00000020 94 0b 83 b2 c9 5e c1 5f 4f 12 00 10 63 12 d3 f9 |.....^._O...c...| 00000030 ae ae 31 18 fa b4 33 37 eb b9 23 15 55 7e cf 62 |..1...37..#.U~.b| 00000040 20 a7 cb eb 69 35 e0 35 32 e4 0a 4c c0 33 e9 7d | ...i5.52..L.3.}| 00000050 f2 a8 4b e2 fe 90 62 7a 09 df c5 46 03 0c 52 7a |..K...bz...F..Rz| 00000060 fb 96 dd fd 55 aa e5 be 3c 35 65 03 be e1 51 0f |....U...<5e...Q.| 00000070 7b b3 05 6b e9 af 9b 0e e4 ea d9 34 69 a5 c2 9a |{..k.......4i...| 00000080 71 a8 cc 0a 94 ef 91 14 88 14 03 00 00 01 01 16 |q...............| 00000090 03 00 00 40 0c 34 26 4c cf f0 d4 a0 08 b9 b7 6b |...@.4&L.......k| 000000a0 0a 69 55 48 91 2c 92 4c 9b e7 66 d0 b8 da 2d e7 |.iUH.,.L..f...-.| 000000b0 89 ca f5 a4 3d 11 ff 87 22 07 c0 ed 72 9c ad 19 |....=..."...r...| 000000c0 7d 63 2b 67 43 e3 33 76 a1 ac 69 77 55 bb 60 ba |}c+gC.3v..iwU.`.| 000000d0 57 00 4e 2a |W.N*| >>> Flow 4 (server to client) 00000000 14 03 00 00 01 01 16 03 00 00 40 dd e1 34 c5 4a |..........@..4.J| 00000010 96 76 81 49 df 1b 3d 48 cc 6c b0 3b ee 77 a9 62 |.v.I..=H.l.;.w.b| 00000020 91 b3 16 b0 e1 79 4b 2a 95 d8 54 98 7b 5e ac 0f |.....yK*..T.{^..| 00000030 07 3b 06 36 e1 38 dc 75 6a af f7 ce a4 b2 3f 9e |.;.6.8.uj.....?.| 00000040 36 b1 44 ce e9 6c 34 ba ce 97 02 17 03 00 00 18 |6.D..l4.........| 00000050 5b be 71 2f a1 15 2f e9 9b 83 8e f1 9b e7 5b 4a |[.q/../.......[J| 00000060 a1 85 13 03 c0 f2 30 0c 17 03 00 00 28 2c d9 9e |......0.....(,..| 00000070 f4 d2 70 2a 37 76 66 e7 f4 5c c7 55 be d8 82 49 |..p*7vf..\.U...I| 00000080 77 e0 4f 0f 87 4b c0 b1 f3 d2 a3 63 df 62 bc ee |w.O..K.....c.b..| 00000090 5c c2 50 2a 96 15 03 00 00 18 8b 0a 68 8a d8 64 |\.P*........h..d| 000000a0 4e 3f f9 ee c6 b2 21 51 03 10 6b 73 3b 8c a4 bb |N?....!Q..ks;...| 000000b0 6d f2 |m.| ================================================ FILE: scan/crypto/tls/testdata/Server-SSLv3-RSA-AES ================================================ >>> Flow 1 (client to server) 00000000 16 03 00 00 30 01 00 00 2c 03 00 36 b0 f3 52 13 |....0...,..6..R.| 00000010 00 17 16 8f 6e 44 24 06 84 05 5b 03 e6 8a 55 ee |....nD$...[...U.| 00000020 75 9c a8 77 9e e0 7b 15 f9 60 6e 00 00 04 00 2f |u..w..{..`n..../| 00000030 00 ff 02 01 00 |.....| >>> Flow 2 (server to client) 00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| 00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 00 00 84 10 00 00 80 2d 0b b1 1c 96 72 65 |.........-....re| 00000010 e5 3b 5b 48 35 91 b8 2e 18 b5 6c 36 a4 91 10 0e |.;[H5.....l6....| 00000020 15 63 de fb 7e ea 44 cd 2e 2f 37 2c 88 96 30 d4 |.c..~.D../7,..0.| 00000030 07 ff 02 9b af 84 2c 43 6c 3a 1f 75 17 4c 5e 8b |......,Cl:.u.L^.| 00000040 4a d9 df 68 fe ad 72 c9 0c f7 a5 0c a1 70 8b 9f |J..h..r......p..| 00000050 e7 8e 1d 32 61 8e 80 e5 3a 3a 61 ea 22 1a 67 e5 |...2a...::a.".g.| 00000060 06 6a 5e 0c 65 bd c7 32 9c 13 c1 53 ad 8e f1 be |.j^.e..2...S....| 00000070 4d 6c 53 89 8f 9c 49 d2 85 58 04 b5 e8 53 b4 82 |MlS...I..X...S..| 00000080 84 46 9d 70 fa 0a 34 15 1d 14 03 00 00 01 01 16 |.F.p..4.........| 00000090 03 00 00 40 71 c7 4b ef 6b 7a f4 a2 29 dd c0 4b |...@q.K.kz..)..K| 000000a0 ef 04 7d ea 1c 31 16 38 ae 85 f9 89 db 2f a8 04 |..}..1.8...../..| 000000b0 ad 61 b7 33 73 8c 31 9b 72 5a f6 8b 10 71 0c af |.a.3s.1.rZ...q..| 000000c0 99 89 14 63 b8 19 f8 0e 2c 0f 14 c6 d6 0a bd 4f |...c....,......O| 000000d0 96 59 0d 60 |.Y.`| >>> Flow 4 (server to client) 00000000 14 03 00 00 01 01 16 03 00 00 40 28 76 de 29 3b |..........@(v.);| 00000010 48 77 56 f1 e5 97 21 20 88 9c 7d 5e 02 3d bb c9 |HwV...! ..}^.=..| 00000020 2f b1 ce 2e 65 ac 53 ea a2 06 0e fb cf 53 28 1d |/...e.S......S(.| 00000030 df b3 24 48 52 7a 28 d6 9e 50 83 64 da 34 c1 f4 |..$HRz(..P.d.4..| 00000040 c9 bf ec 42 33 c4 8a 6f 89 aa 1c 17 03 00 00 20 |...B3..o....... | 00000050 f2 af bb 38 4f 37 58 0e c4 2b 28 45 01 45 89 e9 |...8O7X..+(E.E..| 00000060 31 5a 6d 8d 4d 1b 49 bd 7d 87 8a 62 e6 c8 03 43 |1Zm.M.I.}..b...C| 00000070 17 03 00 00 30 60 ec e4 6f ec 88 33 d8 89 49 73 |....0`..o..3..Is| 00000080 3a aa 67 ab 45 9f de c7 3f 0e 39 3d 9a 30 99 9c |:.g.E...?.9=.0..| 00000090 2d 10 5f f0 7d 70 10 d5 8e ca 18 91 25 e8 9d d1 |-._.}p......%...| 000000a0 36 b0 a7 90 9b 15 03 00 00 20 63 e9 92 98 7d b1 |6........ c...}.| 000000b0 9a 88 07 37 b2 27 99 95 b9 16 17 74 c2 42 9c dc |...7.'.....t.B..| 000000c0 80 32 de f4 f6 87 cb f1 87 d8 |.2........| ================================================ FILE: scan/crypto/tls/testdata/Server-SSLv3-RSA-RC4 ================================================ >>> Flow 1 (client to server) 00000000 16 03 00 00 30 01 00 00 2c 03 00 3c 64 40 96 81 |....0...,..>> Flow 2 (server to client) 00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 00 00 84 10 00 00 80 00 e0 40 dd e4 0f 54 |...........@...T| 00000010 40 66 62 06 72 2a 7a 06 2d a9 0f 16 3b 5c 63 9b |@fb.r*z.-...;\c.| 00000020 95 82 9c d4 95 57 c0 37 d1 30 6a 33 e1 5a ec 93 |.....W.7.0j3.Z..| 00000030 12 ec 2a 94 c6 9c b3 6c a3 4f ef cd f1 80 25 a7 |..*....l.O....%.| 00000040 54 ca 6a 6e b9 80 0b fc f1 e9 60 a0 f5 33 24 3b |T.jn......`..3$;| 00000050 13 04 9a f1 8a 37 cd 11 cf 95 ae 71 ba 73 8e 00 |.....7.....q.s..| 00000060 86 17 6a 3b d5 9e a9 04 87 fd 62 ed 4c b5 01 55 |..j;......b.L..U| 00000070 65 a2 fb e8 1d 86 a5 58 2a ad e7 fd d3 44 2f 7d |e......X*....D/}| 00000080 25 b7 3b c7 75 39 5c 45 f6 14 03 00 00 01 01 16 |%.;.u9\E........| 00000090 03 00 00 3c e6 58 15 b2 fb 0d 44 ed 43 d5 ff a8 |...<.X....D.C...| 000000a0 41 25 83 41 46 da f6 8e 70 34 39 c6 6c 2c ea 1b |A%.AF...p49.l,..| 000000b0 2a 02 5c 4b e4 87 58 33 6c d0 22 2e ce 85 df 31 |*.\K..X3l."....1| 000000c0 0d 71 4c 1a f9 9c 64 d7 87 53 eb c9 1a 0a 16 dc |.qL...d..S......| >>> Flow 4 (server to client) 00000000 14 03 00 00 01 01 16 03 00 00 3c 17 a2 5b 4a 06 |..........<..[J.| 00000010 63 6a 4b f9 ef 66 ed 31 f6 87 75 20 8b 08 8d 5d |cjK..f.1..u ...]| 00000020 0f 72 87 dd 8d db 99 d5 06 42 2b a3 84 77 35 f2 |.r.......B+..w5.| 00000030 1d 11 ae 0b 0c df ed 10 6e 23 27 93 29 65 25 f6 |........n#'.)e%.| 00000040 60 b9 76 c8 95 2b 0c 17 03 00 00 21 df 08 e8 1f |`.v..+.....!....| 00000050 2f ea 5a 61 d6 d4 4a c0 c1 b5 59 bc e1 89 6e 88 |/.Za..J...Y...n.| 00000060 bb 8d 16 db 64 87 31 6c 2d d6 c7 d2 ed 15 03 00 |....d.1l-.......| 00000070 00 16 a9 53 32 af 7a a4 88 02 93 6b aa 95 84 4f |...S2.z....k...O| 00000080 17 5a 97 93 67 87 3b 07 |.Z..g.;.| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 5f 01 00 00 5b 03 01 ad 87 94 6b 8a |...._...[.....k.| 00000010 38 9e 70 d6 94 8a 73 a9 39 d8 d7 25 ab 47 92 4c |8.p...s.9..%.G.L| 00000020 b1 20 8e 4d f3 7b cd 84 5e 13 c1 00 00 04 c0 0a |. .M.{..^.......| 00000030 00 ff 02 01 00 00 2d 00 0b 00 04 03 00 01 02 00 |......-.........| 00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................| 00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................| 00000060 0f 00 01 01 |....| >>> Flow 2 (server to client) 00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 0a 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 01 02 0e 0b 00 02 0a 00 |................| 00000040 02 07 00 02 04 30 82 02 00 30 82 01 62 02 09 00 |.....0...0..b...| 00000050 b8 bf 2d 47 a0 d2 eb f4 30 09 06 07 2a 86 48 ce |..-G....0...*.H.| 00000060 3d 04 01 30 45 31 0b 30 09 06 03 55 04 06 13 02 |=..0E1.0...U....| 00000070 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| 00000080 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| 00000090 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| 000000a0 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 32 |ts Pty Ltd0...12| 000000b0 31 31 32 32 31 35 30 36 33 32 5a 17 0d 32 32 31 |1122150632Z..221| 000000c0 31 32 30 31 35 30 36 33 32 5a 30 45 31 0b 30 09 |120150632Z0E1.0.| 000000d0 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U| 000000e0 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!| 000000f0 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne| 00000100 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt| 00000110 64 30 81 9b 30 10 06 07 2a 86 48 ce 3d 02 01 06 |d0..0...*.H.=...| 00000120 05 2b 81 04 00 23 03 81 86 00 04 00 c4 a1 ed be |.+...#..........| 00000130 98 f9 0b 48 73 36 7e c3 16 56 11 22 f2 3d 53 c3 |...Hs6~..V.".=S.| 00000140 3b 4d 21 3d cd 6b 75 e6 f6 b0 dc 9a df 26 c1 bc |;M!=.ku......&..| 00000150 b2 87 f0 72 32 7c b3 64 2f 1c 90 bc ea 68 23 10 |...r2|.d/....h#.| 00000160 7e fe e3 25 c0 48 3a 69 e0 28 6d d3 37 00 ef 04 |~..%.H:i.(m.7...| 00000170 62 dd 0d a0 9c 70 62 83 d8 81 d3 64 31 aa 9e 97 |b....pb....d1...| 00000180 31 bd 96 b0 68 c0 9b 23 de 76 64 3f 1a 5c 7f e9 |1...h..#.vd?.\..| 00000190 12 0e 58 58 b6 5f 70 dd 9b d8 ea d5 d7 f5 d5 cc |..XX._p.........| 000001a0 b9 b6 9f 30 66 5b 66 9a 20 e2 27 e5 bf fe 3b 30 |...0f[f. .'...;0| 000001b0 09 06 07 2a 86 48 ce 3d 04 01 03 81 8c 00 30 81 |...*.H.=......0.| 000001c0 88 02 42 01 88 a2 4f eb e2 45 c5 48 7d 1b ac f5 |..B...O..E.H}...| 000001d0 ed 98 9d ae 47 70 c0 5e 1b b6 2f bd f1 b6 4d b7 |....Gp.^../...M.| 000001e0 61 40 d3 11 a2 ce ee 0b 7e 92 7e ff 76 9d c3 3b |a@......~.~.v..;| 000001f0 7e a5 3f ce fa 10 e2 59 ec 47 2d 7c ac da 4e 97 |~.?....Y.G-|..N.| 00000200 0e 15 a0 6f d0 02 42 01 4d fc be 67 13 9c 2d 05 |...o..B.M..g..-.| 00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7| 00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.| 00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1| 00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 01 00 d6 0c 00 |{j.9....*.......| 00000250 00 d2 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5| 00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >| 00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l| 00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.| 00000290 41 03 56 6b dc 5a 89 00 8b 30 81 88 02 42 00 8b |A.Vk.Z...0...B..| 000002a0 48 d5 a3 a0 35 5c 31 f5 0b e8 72 7c 87 31 79 af |H...5\1...r|.1y.| 000002b0 7f 12 93 9a f9 df d5 44 bf 08 5a 6b 1c 68 dd 73 |.......D..Zk.h.s| 000002c0 67 0f 32 41 45 53 bf 74 cf 91 54 e7 7a 88 41 7a |g.2AES.t..T.z.Az| 000002d0 15 ea 3d e3 b8 93 c0 3f 24 4c fb ee 25 f1 20 80 |..=....?$L..%. .| 000002e0 02 42 01 ab 97 5f 8b 8d 22 71 f9 f5 a3 59 69 42 |.B..._.."q...YiB| 000002f0 06 bd 12 f5 61 53 cb c8 a1 b4 90 87 12 94 9b f8 |....aS..........| 00000300 b3 1d 34 d9 cd 64 20 9c 92 ec b5 72 35 01 44 3a |..4..d ....r5.D:| 00000310 86 e4 54 46 0d 74 1d 4e d8 41 16 eb ac c3 8a 2f |..TF.t.N.A...../| 00000320 20 11 ad bc 16 03 01 00 04 0e 00 00 00 | ............| >>> Flow 3 (client to server) 00000000 16 03 01 00 46 10 00 00 42 41 04 38 ca 59 61 cd |....F...BA.8.Ya.| 00000010 17 4a cf a8 0b 81 c6 b7 7f 52 dd 95 d7 57 9d 24 |.J.......R...W.$| 00000020 bb b1 02 af 57 ee b9 f9 c5 a0 c3 20 44 e1 9a e4 |....W...... D...| 00000030 83 64 7d a1 fa 9d 2e 3b 5e be 0f af ed 96 f3 09 |.d}....;^.......| 00000040 62 a2 22 21 72 f8 84 89 8a fd 10 14 03 01 00 01 |b."!r...........| 00000050 01 16 03 01 00 30 bd e6 23 e0 32 b8 4c ef ce 9e |.....0..#.2.L...| 00000060 22 a5 77 2c f1 7e 2f 8d 8b 9e a5 92 42 f9 0f 02 |".w,.~/.....B...| 00000070 eb 2e 94 f1 6d a3 24 3f c0 ae bb c0 c4 99 08 51 |....m.$?.......Q| 00000080 47 28 8b 4e f9 02 |G(.N..| >>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 30 11 a9 f0 95 27 |..........0....'| 00000010 ac 0a b7 8e 0d 42 0a 2a f8 f8 e2 4f 4f 4a 79 d1 |.....B.*...OOJy.| 00000020 73 e6 4d 42 90 3c 06 f8 7b da 26 cc 58 be 97 f6 |s.MB.<..{.&.X...| 00000030 41 32 fb 39 2f fa e1 bc 59 2b 45 17 03 01 00 20 |A2.9/...Y+E.... | 00000040 93 6a a1 a6 a2 e6 be bb be 2f 8f 0c 52 39 1c 6a |.j......./..R9.j| 00000050 6d 4c af 38 f7 60 8b ad 0e c7 62 0c 8b a4 42 14 |mL.8.`....b...B.| 00000060 17 03 01 00 30 da b0 1b ef cf 45 86 09 e9 be aa |....0.....E.....| 00000070 0f 71 af a3 86 d0 0f 2d e8 76 39 9a c4 1f f5 c2 |.q.....-.v9.....| 00000080 82 0a ee 34 0e a6 3b 19 b8 2c 10 ad fc 03 33 31 |...4..;..,....31| 00000090 10 42 9b 6e 7b 15 03 01 00 20 ac 73 4d 4b 92 30 |.B.n{.... .sMK.0| 000000a0 bf 4c bc 77 c1 87 d7 20 ad 82 bd 75 31 82 0d 34 |.L.w... ...u1..4| 000000b0 cb b2 86 fd 4f 9c 84 a3 80 af |....O.....| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv10-RSA-3DES ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 37 01 00 00 33 03 01 8d f4 8c 3d bd |....7...3.....=.| 00000010 d8 81 53 bb f5 bc 18 69 07 09 0d 05 93 4f 6f eb |..S....i.....Oo.| 00000020 fa fb 03 65 d4 49 a3 df 9f c3 a5 00 00 04 00 0a |...e.I..........| 00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............| >>> Flow 2 (server to client) 00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 01 00 86 10 00 00 82 00 80 6b 00 e3 47 e3 |...........k..G.| 00000010 0d 22 44 53 7a b9 d1 14 4e e4 47 17 a1 e2 f5 d2 |."DSz...N.G.....| 00000020 f7 82 2f 1b e2 3a 60 aa 79 36 fa 74 05 72 66 88 |../..:`.y6.t.rf.| 00000030 3f 6a 57 8d 10 8a a1 80 3c 74 5b 29 c3 a1 b8 57 |?jW.....>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 28 f4 cf 23 f8 86 |..........(..#..| 00000010 83 df 44 af 1c 25 b1 51 84 5b 6a f3 0e 6b 47 5c |..D..%.Q.[j..kG\| 00000020 2a 59 67 db 42 11 f9 53 58 4e db 6f 00 b2 20 5b |*Yg.B..SXN.o.. [| 00000030 ae a3 43 17 03 01 00 18 df e0 22 d6 05 ab 79 c7 |..C......."...y.| 00000040 87 8a 82 83 01 bc 06 45 36 74 4d 1c 40 96 97 5f |.......E6tM.@.._| 00000050 17 03 01 00 28 49 bd b7 e9 41 6b eb b1 aa 89 60 |....(I...Ak....`| 00000060 21 91 df bf f4 7a 49 9d 54 04 4a 16 1a d1 44 9a |!....zI.T.J...D.| 00000070 09 6c 4f 01 3d c0 2f d5 a3 72 a3 b2 fe 15 03 01 |.lO.=./..r......| 00000080 00 18 5c 7a de a0 ef ed 56 99 99 01 5f b4 32 b3 |..\z....V..._.2.| 00000090 00 be c6 cc 7e bb 6f 82 7d f7 |....~.o.}.| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv10-RSA-AES ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 37 01 00 00 33 03 01 39 72 8e 06 ed |....7...3..9r...| 00000010 d2 74 5c 02 74 0e 2b 7a bd 54 ce be 17 a0 4f 1a |.t\.t.+z.T....O.| 00000020 c5 72 b1 e8 3e 2e 90 68 ff fc 6e 00 00 04 00 2f |.r..>..h..n..../| 00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............| >>> Flow 2 (server to client) 00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| 00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 01 00 86 10 00 00 82 00 80 0e a2 23 fe 89 |.............#..| 00000010 46 08 20 98 da 4d 91 a4 48 40 ab 03 df 1f 00 67 |F. ..M..H@.....g| 00000020 f3 fb fb 22 f7 8e d6 65 2c 43 a7 f4 9c 0e 25 cc |..."...e,C....%.| 00000030 d9 3b b5 58 df bd 93 27 1c df 69 37 27 01 cb 0d |.;.X...'..i7'...| 00000040 b4 f4 a6 8d 91 fe ef dc 9a e2 09 7c 53 1a 73 6d |...........|S.sm| 00000050 b9 f6 89 0a 1f 94 f0 26 25 ef 73 54 20 d5 8d 77 |.......&%.sT ..w| 00000060 36 2e e7 4c 9a f1 4a be ae 6e b6 be 16 10 31 42 |6..L..J..n....1B| 00000070 9e d2 49 41 2c 32 52 11 bc 85 2d fa 39 80 9b f9 |..IA,2R...-.9...| 00000080 95 fe e8 88 2a a2 57 65 7e 38 b2 14 03 01 00 01 |....*.We~8......| 00000090 01 16 03 01 00 30 1c 6f 91 45 16 ed 25 82 ee 5f |.....0.o.E..%.._| 000000a0 f9 f0 09 0c a4 ad 56 61 e5 b7 a2 05 50 02 b8 80 |......Va....P...| 000000b0 ef 73 d1 11 3c 25 50 44 0d ba b5 7c fd 5d 7a df |.s..<%PD...|.]z.| 000000c0 14 62 1b 29 be 29 |.b.).)| >>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 30 5e 8c b1 dc 1f |..........0^....| 00000010 b3 18 85 4a 46 02 fb 34 e4 05 56 78 4c e3 34 63 |...JF..4..VxL.4c| 00000020 06 08 b4 ee 36 e2 28 ab c9 98 ee 26 4e 5b 5d 42 |....6.(....&N[]B| 00000030 5f f8 e1 d1 2f 8b c8 ef 5a 65 40 17 03 01 00 20 |_.../...Ze@.... | 00000040 e7 92 6e b1 60 b9 f8 cd 53 d3 37 5b 44 74 1c af |..n.`...S.7[Dt..| 00000050 90 93 13 8e 55 25 cc 9f 57 8c f3 06 f7 ba e0 f9 |....U%..W.......| 00000060 17 03 01 00 30 fc 83 e6 4e 8c 65 8f d1 7c c7 f4 |....0...N.e..|..| 00000070 8b 68 0d 5d da 8e 49 45 68 ea 4c e3 7f 7d 84 87 |.h.]..IEh.L..}..| 00000080 2f 63 e0 fb 43 24 04 cd e2 38 32 50 0a 4c 43 ce |/c..C$...82P.LC.| 00000090 3b 12 a5 6b 99 15 03 01 00 20 2a 42 d8 57 26 79 |;..k..... *B.W&y| 000000a0 51 ee 79 9d b2 83 b8 49 a4 e9 a2 08 34 73 c4 f5 |Q.y....I....4s..| 000000b0 53 21 4b 78 ec 5b ce b4 4e a0 |S!Kx.[..N.| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv10-RSA-RC4 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 37 01 00 00 33 03 01 b3 82 99 50 b0 |....7...3.....P.| 00000010 1e 7a 46 48 9d 8e 93 32 3b 01 bc 50 e9 5c eb 91 |.zFH...2;..P.\..| 00000020 25 4b c1 ea 0a 91 c9 b3 2b 54 90 00 00 04 00 05 |%K......+T......| 00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............| >>> Flow 2 (server to client) 00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 01 00 86 10 00 00 82 00 80 05 1c 93 2a 69 |..............*i| 00000010 f7 0b 1d 59 ea ca c2 4a b1 7c ef 22 4c 7b 31 5f |...Y...J.|."L{1_| 00000020 18 8d 32 b6 db 75 8c f8 45 07 27 e1 9f 3f 9d 0b |..2..u..E.'..?..| 00000030 02 ac 2c 3f aa bf 79 fb d4 af 98 0c b2 c0 03 4b |..,?..y........K| 00000040 86 26 c3 30 f3 ea 2b 1a ab 70 90 8d 01 2b 0e ff |.&.0..+..p...+..| 00000050 4c 10 9a 29 75 cb 14 bb 85 80 98 35 fb 82 e8 b5 |L..)u......5....| 00000060 80 6f 9d e6 3b b6 14 36 bb 61 8e 18 f2 6b da 09 |.o..;..6.a...k..| 00000070 71 9c 6d 1e c3 60 a9 c5 8b 4e 77 41 db ec 12 49 |q.m..`...NwA...I| 00000080 a4 c2 e2 10 ce 7f 18 05 b9 74 aa 14 03 01 00 01 |.........t......| 00000090 01 16 03 01 00 24 3d 90 d0 f6 6f 15 94 05 a0 fb |.....$=...o.....| 000000a0 43 83 55 b5 b1 ef e5 fd fc 00 d3 d5 25 b4 7c 9f |C.U.........%.|.| 000000b0 e0 82 99 2a 6d 5a 26 7c 05 21 |...*mZ&|.!| >>> Flow 4 (server to client) 00000000 14 03 01 00 01 01 16 03 01 00 24 28 d0 1f ec 1d |..........$(....| 00000010 9e 1d e3 80 6b 6d 3e 8b c5 f7 9c 14 a9 0b c3 53 |....km>........S| 00000020 fd 48 d0 b3 eb d1 49 97 97 71 e9 36 b9 e6 3a 17 |.H....I..q.6..:.| 00000030 03 01 00 21 c3 b6 2e 02 05 86 0f 57 04 dd 88 33 |...!.......W...3| 00000040 0a ed 1d d5 a8 0f 55 54 c5 8c 87 5b 11 b7 80 7f |......UT...[....| 00000050 30 79 e0 64 ee 15 03 01 00 16 b1 50 de 3d 18 05 |0y.d.......P.=..| 00000060 2f db 37 4c db 62 f1 c8 d5 19 ca c2 fb a5 8a 37 |/.7L.b.........7| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv11-FallbackSCSV ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 cf 01 00 00 cb 03 02 ee 33 c1 3f a6 |............3.?.| 00000010 62 ba a6 4f c7 32 25 0f 15 66 f7 35 a2 cf c0 cd |b..O.2%..f.5....| 00000020 48 93 77 1c 04 1f fb 65 41 37 ca 00 00 70 c0 14 |H.w....eA7...p..| 00000030 c0 0a 00 39 00 38 00 37 00 36 00 88 00 87 00 86 |...9.8.7.6......| 00000040 00 85 c0 0f c0 05 00 35 00 84 c0 13 c0 09 00 33 |.......5.......3| 00000050 00 32 00 31 00 30 00 9a 00 99 00 98 00 97 00 45 |.2.1.0.........E| 00000060 00 44 00 43 00 42 c0 0e c0 04 00 2f 00 96 00 41 |.D.C.B...../...A| 00000070 00 07 c0 11 c0 07 c0 0c c0 02 00 05 00 04 c0 12 |................| 00000080 c0 08 00 16 00 13 00 10 00 0d c0 0d c0 03 00 0a |................| 00000090 00 15 00 12 00 0f 00 0c 00 09 00 ff 56 00 02 01 |............V...| 000000a0 00 00 31 00 0b 00 04 03 00 01 02 00 0a 00 1c 00 |..1.............| 000000b0 1a 00 17 00 19 00 1c 00 1b 00 18 00 1a 00 16 00 |................| 000000c0 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 23 00 00 00 |............#...| 000000d0 0f 00 01 01 |....| >>> Flow 2 (server to client) 00000000 15 03 02 00 02 02 56 |......V| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv11-RSA-RC4 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 37 01 00 00 33 03 02 95 4a cf f5 14 |....7...3...J...| 00000010 56 9b d6 be 0c ba 0d b2 ad 65 47 d2 c6 ce 84 c9 |V........eG.....| 00000020 f4 80 2a 4e 75 df ff 48 cf 48 9b 00 00 04 00 05 |..*Nu..H.H......| 00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............| >>> Flow 2 (server to client) 00000000 16 03 02 00 31 02 00 00 2d 03 02 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 02 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 02 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 02 00 86 10 00 00 82 00 80 19 c3 d4 f2 e4 |................| 00000010 bf 4a 52 90 a4 65 f6 e7 29 1a 7f ef 0e a4 1e b4 |.JR..e..).......| 00000020 c2 df b2 83 43 4a 1a f4 b6 cd 51 a5 24 62 3f e1 |....CJ....Q.$b?.| 00000030 fb 5f 7e b1 10 08 3b 8a ab eb 3a a3 72 ba 31 1c |._~...;...:.r.1.| 00000040 23 bd ef 2e 3d 13 dc 61 88 a6 af ca 80 82 5d e4 |#...=..a......].| 00000050 d6 a2 d3 13 80 87 c6 ad a5 13 4e f1 b6 a0 5d fa |..........N...].| 00000060 ed a7 0d 37 58 f1 54 38 18 f5 be db 90 9f 07 4a |...7X.T8.......J| 00000070 67 25 c9 8d 9d 5e 07 62 ca db 72 74 b5 bd a0 ed |g%...^.b..rt....| 00000080 d0 95 9f 3e cd 37 b8 96 df df 3b 14 03 02 00 01 |...>.7....;.....| 00000090 01 16 03 02 00 24 80 53 7a 8f 23 06 a7 6b e6 be |.....$.Sz.#..k..| 000000a0 61 c2 1a c8 35 30 6b e2 2f 82 f3 46 ff e3 1d bd |a...50k./..F....| 000000b0 68 e9 a2 78 49 33 05 ca d9 41 |h..xI3...A| >>> Flow 4 (server to client) 00000000 14 03 02 00 01 01 16 03 02 00 24 8f 06 3e 7b 8c |..........$..>{.| 00000010 fb f2 3d 9e 5c a9 46 56 79 2a 3a ba ad 25 30 57 |..=.\.FVy*:..%0W| 00000020 f9 f1 16 70 51 5d 73 7e 47 74 8d c0 84 b0 31 17 |...pQ]s~Gt....1.| 00000030 03 02 00 21 76 09 88 df 7e f7 2f c9 3d 86 b9 30 |...!v...~./.=..0| 00000040 b0 5c ac ea db c6 d0 d5 69 55 91 7b a1 72 0b 4d |.\......iU.{.r.M| 00000050 7d ae 6f aa 50 15 03 02 00 16 8c 31 73 86 1a c7 |}.o.P......1s...| 00000060 ef 08 52 8a 7d 30 b8 00 3b 62 4d 21 7b 81 2c 76 |..R.}0..;bM!{.,v| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-ALPN ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 01 4d 01 00 01 49 03 03 ac 76 61 d8 20 |....M...I...va. | 00000010 b3 c3 1d c2 3d c2 a4 b9 e2 46 a2 a1 0a 5e 08 56 |....=....F...^.V| 00000020 4a aa 59 43 42 d6 21 9c 46 0c 21 00 00 b6 c0 30 |J.YCB.!.F.!....0| 00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........| 00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7| 00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*| 00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../| 00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........| 00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1| 00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C| 000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......| 000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........| 000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................| 000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................| 000000e0 00 09 00 ff 02 01 00 00 69 00 0b 00 04 03 00 01 |........i.......| 000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................| 00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................| 00000110 0a 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 |..#..... .......| 00000120 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................| 00000130 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 00 10 |................| 00000140 00 10 00 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 |.....proto2.prot| 00000150 6f 31 |o1| >>> Flow 2 (server to client) 00000000 16 03 03 00 42 02 00 00 3e 03 03 00 00 00 00 00 |....B...>.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..| 00000030 16 00 23 00 00 ff 01 00 01 00 00 10 00 09 00 07 |..#.............| 00000040 06 70 72 6f 74 6f 31 16 03 03 02 71 0b 00 02 6d |.proto1....q...m| 00000050 00 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 |..j..g0..c0.....| 00000060 02 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d |.......s......0.| 00000070 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 |..*.H........0+1| 00000080 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google| 00000090 20 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 | TESTING1.0...U.| 000000a0 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 |...Go Root0...15| 000000b0 30 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 |0101000000Z..250| 000000c0 31 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 |101000000Z0&1.0.| 000000d0 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 |..U....Google TE| 000000e0 53 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 |STING1.0...U....| 000000f0 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 |Go0..0...*.H....| 00000100 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af |........0.......| 00000110 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 |... ..el..D..;E.| 00000120 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a |..m..cM...jb5..J| 00000130 f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 |..|..%^zd1f.....| 00000140 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 |..k.v.._A.nV....| 00000150 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da |.<.9!f=+........| 00000160 b7 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 |.......!P.....k.| 00000170 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 |K......l..D..!..| 00000180 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 |}..M........G...| 00000190 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d |.......0..0...U.| 000001a0 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d |..........0...U.| 000001b0 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 |%..0...+........| 000001c0 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 |.+.......0...U..| 000001d0 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 |.....0.0...U....| 000001e0 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e |...P..o...TMn.i^| 000001f0 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf |..0...U.#..0....| 00000200 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 |=..f..@....xH.A0| 00000210 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d |...U....0...exam| 00000220 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 |ple.golang0...*.| 00000230 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af |H.............|.| 00000240 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 |.U...Y1.H@.-....| 00000250 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 |....|..0}<.v.O=.| 00000260 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc |..-3$k.{.gY.!...| 00000270 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 |w...n.-.5.d_">c.| 00000280 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 |k....m...1..8.;.| 00000290 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 |.,...Qv..O......| 000002a0 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 |@.Q......F.F.O..| 000002b0 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 |...A4......9....| 000002c0 00 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d |.........A...7..| 000002d0 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 000002e0 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 000002f0 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000300 a6 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 aa |..h.A.Vk.Z......| 00000310 8c a6 e1 51 65 fc 99 37 cf 63 d8 fd 04 52 d5 50 |...Qe..7.c...R.P| 00000320 1f 0a f5 90 58 48 19 8d d8 0b 64 23 e4 24 56 b4 |....XH....d#.$V.| 00000330 e5 87 0f 88 a1 7a 29 fa 88 79 99 75 6d 53 a9 50 |.....z)..y.umS.P| 00000340 a4 9c b9 47 c2 51 87 10 b9 a5 e3 6f a9 38 b8 83 |...G.Q.....o.8..| 00000350 0d 39 b5 28 27 5f ec 9d a3 2d 1c 53 6b da 93 0d |.9.('_...-.Sk...| 00000360 cc cf 0c 27 7e d2 f0 05 d5 c0 04 dc 6d d4 2e 03 |...'~.......m...| 00000370 a7 16 98 58 e4 8d fd 14 6b bb 0c 09 b0 16 35 9e |...X....k.....5.| 00000380 78 3a 29 21 b5 2f 13 37 94 ae f7 fe 54 89 c0 16 |x:)!./.7....T...| 00000390 03 03 00 04 0e 00 00 00 |........| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 35 ca 56 91 15 |....F...BA.5.V..| 00000010 4f dd af 97 f2 2d fb df 54 2b 80 98 18 bb 33 54 |O....-..T+....3T| 00000020 3f 7e 66 21 d3 81 38 f9 a4 b5 b9 a6 46 9a 52 8b |?~f!..8.....F.R.| 00000030 98 f7 81 1f 77 81 78 38 01 c5 3b fb 7a b7 53 e7 |....w.x8..;.z.S.| 00000040 ae c3 4c 2e 73 f4 8e 3a 36 0d 43 14 03 03 00 01 |..L.s..:6.C.....| 00000050 01 16 03 03 00 28 38 26 8e 03 ad 81 9b a0 41 d9 |.....(8&......A.| 00000060 c0 11 3f 36 dc 6b ab 6c 29 dc df 02 a3 fe b0 0f |..?6.k.l).......| 00000070 2e b1 c6 44 39 42 d5 ef 29 30 d8 e0 f1 f9 |...D9B..)0....| >>> Flow 4 (server to client) 00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| 00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| 00000030 6f ec 80 83 61 fb fb 41 b1 31 e9 71 75 43 c3 74 |o...a..A.1.quC.t| 00000040 a1 a0 ac fb 97 b7 69 ee a6 2f e3 a3 dd 9f de e4 |......i../......| 00000050 80 9d d7 69 1a 2c 0b b4 02 bd ef e2 6a c1 ca 30 |...i.,......j..0| 00000060 8b 9d 60 f9 fe 33 94 53 3a 14 a3 1a aa 5a ba ff |..`..3.S:....Z..| 00000070 1e 94 fd 4f e7 90 0b 09 ee 80 f3 d6 d5 c0 48 83 |...O..........H.| 00000080 98 20 d7 a4 07 99 e0 14 03 03 00 01 01 16 03 03 |. ..............| 00000090 00 28 00 00 00 00 00 00 00 00 0d 66 de 91 4a 97 |.(.........f..J.| 000000a0 21 c6 d2 d7 df 68 9b 7e f6 43 73 02 66 b3 5a d6 |!....h.~.Cs.f.Z.| 000000b0 92 48 c2 c1 11 fc cd 1e 2e 4b 17 03 03 00 25 00 |.H.......K....%.| 000000c0 00 00 00 00 00 00 01 72 0c 48 75 fa b2 8b 23 09 |.......r.Hu...#.| 000000d0 be 76 36 a4 bc e0 62 ef bd 79 8e de 6b 39 4b 55 |.v6...b..y..k9KU| 000000e0 8d 3c ca 14 15 03 03 00 1a 00 00 00 00 00 00 00 |.<..............| 000000f0 02 74 5f 79 31 41 4f f5 4d 02 96 bc c3 9a 85 92 |.t_y1AO.M.......| 00000100 44 e1 76 |D.v| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 01 4d 01 00 01 49 03 03 73 f2 f2 44 4f |....M...I..s..DO| 00000010 87 05 77 e2 e7 07 ca c7 d4 36 37 4e d9 17 ba ff |..w......67N....| 00000020 b0 e1 47 65 f8 7f fd 7a b4 85 39 00 00 b6 c0 30 |..Ge...z..9....0| 00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........| 00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7| 00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*| 00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../| 00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........| 00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1| 00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C| 000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......| 000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........| 000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................| 000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................| 000000e0 00 09 00 ff 02 01 00 00 69 00 0b 00 04 03 00 01 |........i.......| 000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................| 00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................| 00000110 0a 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 |..#..... .......| 00000120 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................| 00000130 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 00 10 |................| 00000140 00 10 00 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 |.....proto2.prot| 00000150 6f 31 |o1| >>> Flow 2 (server to client) 00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..| 00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.| 00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..| 00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....| 00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........| 00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo| 00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..| 00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..| 000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..| 000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1| 000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google| 000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.| 000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.| 000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....| 00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..| 00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5| 00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..| 00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.| 00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....| 00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....| 00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..| 00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G| 00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..| 00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..| 000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....| 000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...| 000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.| 000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn| 000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.| 000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f..@....xH| 00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e| 00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..| 00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............| 00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H@.-.| 00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.| 00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!| 00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"| 00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8| 00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...| 00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |...@.Q......F.F.| 000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.| 000002b0 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 1e 18 |............A...| 000002c0 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f |7...Q.5uq..T[...| 000002d0 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b |.g..$ >.V...(^.+| 000002e0 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 |-O....lK[.V.2B.X| 000002f0 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 05 01 |..I..h.A.Vk.Z...| 00000300 00 80 97 89 a3 7f 30 d1 7b 70 26 3d a4 d5 66 2e |......0.{p&=..f.| 00000310 cd fc 02 f5 37 a5 cd 09 69 7a c6 2f b2 62 e8 a6 |....7...iz./.b..| 00000320 88 e2 3a c4 0a 8c 77 ad d3 c9 29 49 84 81 9c cd |..:...w...)I....| 00000330 33 44 59 2d b5 2e e7 ce 12 c5 3b 46 13 6d 4a c8 |3DY-......;F.mJ.| 00000340 6d f6 1f e7 f1 99 13 01 ca 43 79 fa b5 78 c7 1a |m........Cy..x..| 00000350 7d 8f 85 dd 3b ca 56 22 c3 d0 41 11 1b 13 8c 07 |}...;.V"..A.....| 00000360 02 75 87 7a ea 68 43 30 0b 2a 38 52 b2 8f cc ea |.u.z.hC0.*8R....| 00000370 a3 a3 cb 71 fb 97 cd 3e 74 d0 5b 9b bd 17 13 f0 |...q...>t.[.....| 00000380 d9 fe 16 03 03 00 04 0e 00 00 00 |...........| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 ba 5b 0f e7 ec |....F...BA..[...| 00000010 8e c8 ad 51 8c c0 50 f1 8a 2a 68 32 74 d0 95 03 |...Q..P..*h2t...| 00000020 0c 61 f1 1c 89 ed 95 5d 9a 4a 14 ee cc 14 9a 73 |.a.....].J.....s| 00000030 f6 db 46 dd b7 47 8a 82 3d 7a b8 9f 45 d1 a2 3f |..F..G..=z..E..?| 00000040 f4 34 9b b6 6d 7d 41 87 c9 d5 cd 14 03 03 00 01 |.4..m}A.........| 00000050 01 16 03 03 00 28 1e ae f6 90 a9 91 eb 4b ca 23 |.....(.......K.#| 00000060 6e bf 9e 67 5b 38 ab f6 d6 ee 12 aa b9 b6 d0 6e |n..g[8.........n| 00000070 a7 dd 45 91 34 45 78 a0 04 9e d8 85 48 48 |..E.4Ex.....HH| >>> Flow 4 (server to client) 00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| 00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| 00000030 6f ec 80 83 61 4f 7f 09 64 32 96 26 b5 71 46 6a |o...aO..d2.&.qFj| 00000040 29 7d fd 0b bb 49 13 0e c8 c5 de 06 ed 47 e8 cb |)}...I.......G..| 00000050 d8 9f 18 82 69 af ab 24 d2 78 90 ba 9a c8 24 95 |....i..$.x....$.| 00000060 46 53 19 2e e8 33 94 3c 22 73 26 d6 86 4e 01 a4 |FS...3.<"s&..N..| 00000070 34 ea a8 bf f2 ca b5 0d fc f6 08 b9 31 b3 42 e7 |4...........1.B.| 00000080 c1 92 96 f9 bf 9a 00 14 03 03 00 01 01 16 03 03 |................| 00000090 00 28 00 00 00 00 00 00 00 00 bd 51 1d 0e bd 51 |.(.........Q...Q| 000000a0 a3 b1 03 f2 df f4 ba 9b 1e a5 a8 22 e7 ce 7c 19 |..........."..|.| 000000b0 1a bf 37 3d 42 f4 4d 6f 63 75 17 03 03 00 25 00 |..7=B.Mocu....%.| 000000c0 00 00 00 00 00 00 01 52 8a d2 34 52 70 f1 cf 87 |.......R..4Rp...| 000000d0 54 4e fd e6 11 a7 76 1a f4 7b 70 e8 34 ef 01 c8 |TN....v..{p.4...| 000000e0 6c 4a f8 6d 15 03 03 00 1a 00 00 00 00 00 00 00 |lJ.m............| 000000f0 02 8a 4c f9 7c d1 61 a6 cd 2a e6 3a 5b b0 cb aa |..L.|.a..*.:[...| 00000100 91 2e 8b |...| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 01 35 01 00 01 31 03 03 00 02 67 8e 1d |....5...1....g..| 00000010 3b d2 26 20 63 c5 6a b6 68 25 02 72 ce 86 6b c7 |;.& c.j.h%.r..k.| 00000020 97 1a 9f 4d be 02 98 ac 24 5e 82 00 00 b6 c0 30 |...M....$^.....0| 00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........| 00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7| 00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*| 00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../| 00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........| 00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1| 00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C| 000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......| 000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........| 000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................| 000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................| 000000e0 00 09 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 |........Q.......| 000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................| 00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................| 00000110 0a 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 |.... ...........| 00000120 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 |................| 00000130 01 02 02 02 03 00 0f 00 01 01 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 0a 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 03 02 0e 0b 00 02 0a 00 |................| 00000040 02 07 00 02 04 30 82 02 00 30 82 01 62 02 09 00 |.....0...0..b...| 00000050 b8 bf 2d 47 a0 d2 eb f4 30 09 06 07 2a 86 48 ce |..-G....0...*.H.| 00000060 3d 04 01 30 45 31 0b 30 09 06 03 55 04 06 13 02 |=..0E1.0...U....| 00000070 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| 00000080 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| 00000090 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| 000000a0 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 32 |ts Pty Ltd0...12| 000000b0 31 31 32 32 31 35 30 36 33 32 5a 17 0d 32 32 31 |1122150632Z..221| 000000c0 31 32 30 31 35 30 36 33 32 5a 30 45 31 0b 30 09 |120150632Z0E1.0.| 000000d0 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U| 000000e0 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!| 000000f0 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne| 00000100 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt| 00000110 64 30 81 9b 30 10 06 07 2a 86 48 ce 3d 02 01 06 |d0..0...*.H.=...| 00000120 05 2b 81 04 00 23 03 81 86 00 04 00 c4 a1 ed be |.+...#..........| 00000130 98 f9 0b 48 73 36 7e c3 16 56 11 22 f2 3d 53 c3 |...Hs6~..V.".=S.| 00000140 3b 4d 21 3d cd 6b 75 e6 f6 b0 dc 9a df 26 c1 bc |;M!=.ku......&..| 00000150 b2 87 f0 72 32 7c b3 64 2f 1c 90 bc ea 68 23 10 |...r2|.d/....h#.| 00000160 7e fe e3 25 c0 48 3a 69 e0 28 6d d3 37 00 ef 04 |~..%.H:i.(m.7...| 00000170 62 dd 0d a0 9c 70 62 83 d8 81 d3 64 31 aa 9e 97 |b....pb....d1...| 00000180 31 bd 96 b0 68 c0 9b 23 de 76 64 3f 1a 5c 7f e9 |1...h..#.vd?.\..| 00000190 12 0e 58 58 b6 5f 70 dd 9b d8 ea d5 d7 f5 d5 cc |..XX._p.........| 000001a0 b9 b6 9f 30 66 5b 66 9a 20 e2 27 e5 bf fe 3b 30 |...0f[f. .'...;0| 000001b0 09 06 07 2a 86 48 ce 3d 04 01 03 81 8c 00 30 81 |...*.H.=......0.| 000001c0 88 02 42 01 88 a2 4f eb e2 45 c5 48 7d 1b ac f5 |..B...O..E.H}...| 000001d0 ed 98 9d ae 47 70 c0 5e 1b b6 2f bd f1 b6 4d b7 |....Gp.^../...M.| 000001e0 61 40 d3 11 a2 ce ee 0b 7e 92 7e ff 76 9d c3 3b |a@......~.~.v..;| 000001f0 7e a5 3f ce fa 10 e2 59 ec 47 2d 7c ac da 4e 97 |~.?....Y.G-|..N.| 00000200 0e 15 a0 6f d0 02 42 01 4d fc be 67 13 9c 2d 05 |...o..B.M..g..-.| 00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7| 00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.| 00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1| 00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 d8 0c 00 |{j.9....*.......| 00000250 00 d4 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5| 00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >| 00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l| 00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.| 00000290 41 03 56 6b dc 5a 89 05 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B| 000002a0 01 bc 56 16 22 ad fd e7 ac ba c8 f5 3f c0 d7 f8 |..V.".......?...| 000002b0 8c 64 e0 ba 09 30 c3 66 49 90 7e d2 68 86 07 72 |.d...0.fI.~.h..r| 000002c0 20 87 a1 e1 36 92 a7 68 e2 c3 6e 34 93 a9 ca e8 | ...6..h..n4....| 000002d0 68 3d 9e 42 c4 1e 8e 2d 95 05 ee a6 a4 2c 8d be |h=.B...-.....,..| 000002e0 e3 88 02 42 01 16 18 77 b9 99 0e f8 46 90 46 07 |...B...w....F.F.| 000002f0 f9 67 a9 26 68 d7 da c8 a1 d9 67 55 ec 37 11 2d |.g.&h.....gU.7.-| 00000300 4b f3 52 f4 96 6a 0e 8a 6a 14 21 94 63 ea f9 70 |K.R..j..j.!.c..p| 00000310 2d 57 05 8a 72 29 6e d2 60 a1 97 af 08 5b c3 cf |-W..r)n.`....[..| 00000320 3a 82 a3 81 11 cf 16 03 03 00 04 0e 00 00 00 |:..............| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 8c 80 0c da 24 |....F...BA.....$| 00000010 d6 66 ff cc 1b 26 d5 3f 37 37 16 8f 16 ee 0d 5f |.f...&.?77....._| 00000020 c3 0e 62 7c e4 52 2d 43 29 e9 6b da 49 bc 99 16 |..b|.R-C).k.I...| 00000030 28 46 8e 43 20 7f 12 66 1c 94 1c 03 55 6f 05 53 |(F.C ..f....Uo.S| 00000040 6f b7 dc 8b 70 9d 9d c5 1f da 5b 14 03 03 00 01 |o...p.....[.....| 00000050 01 16 03 03 00 40 17 60 dd e5 b2 58 fd 74 10 38 |.....@.`...X.t.8| 00000060 95 b1 73 7e 8f 7a 2b d0 f5 65 80 0c dc b1 ca 29 |..s~.z+..e.....)| 00000070 06 25 e1 f9 c3 c0 7c 88 e4 ad d3 16 0a 8a dd 1f |.%....|.........| 00000080 a7 86 86 0f ac c7 ea f5 0f 1f 2b 97 85 b3 81 f7 |..........+.....| 00000090 5d 42 2f 3b 72 80 |]B/;r.| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| 00000010 00 00 00 00 00 00 00 00 00 00 00 82 01 fd 38 ae |..............8.| 00000020 a4 07 8f bd 72 0a a2 b5 c5 78 09 89 65 1b 6d 1e |....r....x..e.m.| 00000030 56 52 9d 4f de 02 15 2d 93 d8 8f d7 1f bb 07 3b |VR.O...-.......;| 00000040 e9 62 3c 19 3e 19 65 ac 10 aa e5 17 03 03 00 40 |.b<.>.e........@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000060 18 61 1d 26 f3 b9 34 20 00 6c 27 75 fc 35 f5 c2 |.a.&..4 .l'u.5..| 00000070 6f 71 ca 9b 0d 70 30 46 57 7c 07 86 7d 52 a9 d6 |oq...p0FW|..}R..| 00000080 ab fc 89 a5 48 79 ae 60 03 05 4b 17 b2 d9 6b 39 |....Hy.`..K...k9| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| 000000a0 00 00 00 00 00 8f 8d 88 88 c5 1e f5 bf 06 f2 45 |...............E| 000000b0 e7 fe f0 24 c7 4c 92 5a 80 a7 89 c8 2b ac 49 d9 |...$.L.Z....+.I.| 000000c0 39 00 ca 57 ec |9..W.| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 01 35 01 00 01 31 03 03 ed 84 e2 1a c1 |....5...1.......| 00000010 d9 3f a5 ba 70 0b 5f 3f 3b 87 79 18 27 03 92 ee |.?..p._?;.y.'...| 00000020 b1 9f c7 36 26 e3 0b 6d fc d5 ed 00 00 b6 c0 30 |...6&..m.......0| 00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........| 00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7| 00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*| 00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../| 00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........| 00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1| 00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C| 000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......| 000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........| 000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................| 000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................| 000000e0 00 09 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 |........Q.......| 000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................| 00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................| 00000110 0a 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 |.... ...........| 00000120 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 |................| 00000130 01 02 02 02 03 00 0f 00 01 01 |..........| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 14 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...| 000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..| 000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..| 000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.| 000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 7c 5c |.h.A.Vk.Z.....|\| 00000300 f6 68 cc 07 f0 bd ec 30 07 d0 70 1b c6 95 a4 14 |.h.....0..p.....| 00000310 67 3a 83 a1 43 ff 0a c3 f0 b7 ee 59 f8 c7 09 65 |g:..C......Y...e| 00000320 08 ac 18 34 d4 8f 46 c4 2c 91 7b 57 95 e0 54 03 |...4..F.,.{W..T.| 00000330 d8 8e b6 53 61 74 77 8b a3 5f 23 f0 06 dc 3a 56 |...Satw.._#...:V| 00000340 61 80 5e 31 d5 75 c3 05 9f d0 06 1f c5 32 ba 79 |a.^1.u.......2.y| 00000350 fd 14 a9 54 5a 18 b4 2b 09 0e 19 ab 76 0b 12 5d |...TZ..+....v..]| 00000360 52 27 ce b8 dd 4c f8 f2 d2 70 56 43 19 53 b3 13 |R'...L...pVC.S..| 00000370 b9 b7 65 ce cd 50 ed 4a 9f 42 96 c7 3c b9 16 03 |..e..P.J.B..<...| 00000380 03 00 04 0e 00 00 00 |.......| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 36 1c 6c f5 0a |....F...BA.6.l..| 00000010 7f 52 84 ac 5a 27 45 76 79 a6 89 f1 1d d9 30 30 |.R..Z'Evy.....00| 00000020 b6 64 af c7 34 11 12 b3 b9 72 83 e6 78 bc 06 74 |.d..4....r..x..t| 00000030 a7 a4 10 01 34 77 5c 05 88 82 0f a9 cf 8d e8 68 |....4w\........h| 00000040 09 80 c7 79 b6 e9 5a 2a 5f 80 5e 14 03 03 00 01 |...y..Z*_.^.....| 00000050 01 16 03 03 00 40 ef f9 3c 34 cd 26 70 c9 7b 60 |.....@..<4.&p.{`| 00000060 a7 27 0a 2b 86 18 2f 10 ad 48 3f 2e 9e 88 13 d6 |.'.+../..H?.....| 00000070 d8 c6 fd 35 99 be 09 e6 dd ae 02 06 ea df 60 62 |...5..........`b| 00000080 e0 f8 67 ea 9d c8 8c 11 d8 5a e7 6a a6 b2 eb 62 |..g......Z.j...b| 00000090 23 b2 d2 be 75 58 |#...uX| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| 00000010 00 00 00 00 00 00 00 00 00 00 00 a6 52 02 4f 20 |............R.O | 00000020 f6 d7 2d 2d 7c 65 4e 7b 43 33 32 50 9b c6 68 2c |..--|eN{C32P..h,| 00000030 c0 6a 02 6f c6 bc 38 d8 06 c0 42 ba c1 41 ce 5c |.j.o..8...B..A.\| 00000040 d0 a0 5f fc 8a 31 33 26 a2 79 9a 17 03 03 00 40 |.._..13&.y.....@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000060 f2 42 8f e8 79 0d f3 c0 a0 b7 8a 5e de b8 52 c4 |.B..y......^..R.| 00000070 b6 9d b2 10 00 e8 a3 19 27 12 ac 38 e7 d8 ec 89 |........'..8....| 00000080 af 7d 68 15 03 e8 c4 c8 08 34 ad ad 15 7b 69 bb |.}h......4...{i.| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| 000000a0 00 00 00 00 00 a0 a5 02 ff b1 77 9a 8f e0 fc ca |..........w.....| 000000b0 86 ee ca 9c 7c 3b ca 61 33 7f f9 12 54 79 41 97 |....|;.a3...TyA.| 000000c0 b0 7d bd 9b 93 |.}...| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 5b 01 00 00 57 03 03 55 46 9e 3b 51 |....[...W..UF.;Q| 00000010 e7 cd bf df bc fe 0d 5a 5a de a6 09 6c 72 cb ea |.......ZZ...lr..| 00000020 ab f8 a6 fd 9a 5b be 77 7d 25 20 00 00 04 00 05 |.....[.w}% .....| 00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....| 00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| 00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |.......@........| 000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................| 000002d0 00 |.| >>> Flow 3 (client to server) 00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| 00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1| 00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.| 00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat| 00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte| 00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty| 00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413| 00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132| 00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...| 000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS| 000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm| 000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo| 000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.| 000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....| 000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.| 00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N| 00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..| 00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.| 00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J| 00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A| 00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......| 00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN| 00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..| 00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.| 00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?| 000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH| 000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........| 000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...| 000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._| 000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.| 000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W| 00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..| 00000210 03 03 00 86 10 00 00 82 00 80 03 64 6f 74 1b 0e |...........dot..| 00000220 df 6b a4 8e f8 ec b5 02 c2 d6 7a 9a f3 bf 3e 32 |.k........z...>2| 00000230 ba 41 dd 61 33 8a 63 fb 71 e6 87 68 32 9c 41 d5 |.A.a3.c.q..h2.A.| 00000240 59 ee 93 55 16 e9 0a 01 72 14 93 23 82 73 91 3a |Y..U....r..#.s.:| 00000250 6d 3c e6 e0 a8 33 34 84 80 59 65 6b c1 6d 01 19 |m<...34..Yek.m..| 00000260 cc d5 4f 1d f6 88 4f cc b5 c6 3c 9c 68 4a be 47 |..O...O...<.hJ.G| 00000270 c2 67 61 a4 e3 c3 00 c0 9c d4 83 ed b5 65 25 a4 |.ga..........e%.| 00000280 2e 1c 8d 47 3f 80 b8 1d 5b 74 a2 bf fa b9 b7 e2 |...G?...[t......| 00000290 58 94 ba ec a9 cf 1c 56 ef 0a 16 03 03 00 92 0f |X......V........| 000002a0 00 00 8e 04 03 00 8a 30 81 87 02 41 75 cf 19 3a |.......0...Au..:| 000002b0 a1 9e e9 69 c7 f3 63 0b 46 c2 60 35 e1 cc 95 0d |...i..c.F.`5....| 000002c0 ee 0f ad 28 17 b4 b2 09 ea 38 18 c7 08 84 b6 ac |...(.....8......| 000002d0 65 03 b9 49 c3 ea ff e4 45 d3 15 14 3a 94 14 0c |e..I....E...:...| 000002e0 cb 48 ce 75 c2 a4 4a 0e 7d d8 f0 c5 5f 02 42 01 |.H.u..J.}..._.B.| 000002f0 99 dd c7 54 ce ee 38 bb 18 16 eb 92 0a 53 0b 92 |...T..8......S..| 00000300 d8 73 73 48 b3 0a 3b ea 12 ea 62 d3 88 99 00 54 |.ssH..;...b....T| 00000310 bc 92 28 7d 66 b3 17 7f e7 5f 69 50 d1 a1 4c 6a |..(}f...._iP..Lj| 00000320 99 60 00 59 0a 4d 6c 97 05 54 ee 82 5a e1 c5 88 |.`.Y.Ml..T..Z...| 00000330 1b 14 03 03 00 01 01 16 03 03 00 24 80 64 11 aa |...........$.d..| 00000340 cc 9d 1c 83 b6 2f 56 dc 48 cb 33 e5 0f 25 a2 42 |...../V.H.3..%.B| 00000350 df b8 a6 cc 64 93 10 63 ad 76 91 27 3f c7 8f d4 |....d..c.v.'?...| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 24 24 8d e5 5f d9 |..........$$.._.| 00000010 99 7d d4 f2 5f f4 4b e3 b4 8e 33 84 7a c3 cb bf |.}.._.K...3.z...| 00000020 21 00 94 db 7b 7f 6c fa a0 f2 9f 0e e9 3b 27 17 |!...{.l......;'.| 00000030 03 03 00 21 67 f8 3a ff c1 3b cb de 04 bf 49 a6 |...!g.:..;....I.| 00000040 9a 45 56 ab 64 99 06 7e 40 cc a7 f6 4e 1e ca cb |.EV.d..~@...N...| 00000050 11 87 da 58 b7 15 03 03 00 16 10 1b 62 97 25 bf |...X........b.%.| 00000060 84 c1 23 d6 76 4a a1 da 07 c7 25 68 f6 6e 63 55 |..#.vJ....%h.ncU| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 5b 01 00 00 57 03 03 87 41 6f c5 67 |....[...W...Ao.g| 00000010 07 3b 12 46 ad aa d2 be 0d 08 98 e3 c7 4b ac 48 |.;.F.........K.H| 00000020 67 02 6b 3b dc 84 79 c5 57 e9 89 00 00 04 00 05 |g.k;..y.W.......| 00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....| 00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| 00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |.......@........| 000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................| 000002d0 00 |.| >>> Flow 3 (client to server) 00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| 00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.| 00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| 00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0| 00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807| 00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080| 00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...| 00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.| 00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0| 000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........| 000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.| 000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...| 000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.| 000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...| 000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..| 00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn| 00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..| 00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...| 00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000| 00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0| 00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.| 00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0| 00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........| 00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....| 00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2| 000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...| 000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.| 000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.| 000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..| 000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.| 000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....| 00000200 16 03 03 00 86 10 00 00 82 00 80 79 a7 23 10 fc |...........y.#..| 00000210 64 a7 ab 17 ce d6 8b ab ff c2 44 40 3b ba b4 c6 |d.........D@;...| 00000220 86 b7 66 7d be 9b fa 66 f9 f6 bb e4 f7 02 16 ea |..f}...f........| 00000230 0f 13 9c 8a 98 3a 34 e6 58 82 dc dc 27 3a 3d 5c |.....:4.X...':=\| 00000240 99 09 db 48 54 a5 5a a2 16 7f ba 99 d9 0d ca fb |...HT.Z.........| 00000250 4a 9e b7 f6 3a ab 26 ef f9 df a2 0c 4c 45 19 3b |J...:.&.....LE.;| 00000260 b2 9f 21 cd ff fc cc c7 fb 91 fa 54 93 a9 42 a9 |..!........T..B.| 00000270 4c 48 4a 8c 7b 9a d7 90 97 f6 21 89 03 f6 a5 86 |LHJ.{.....!.....| 00000280 83 6f 21 19 2f 5b f8 ec a6 36 e9 16 03 03 00 88 |.o!./[...6......| 00000290 0f 00 00 84 04 01 00 80 0f 9d 15 cc c0 0b 71 8a |..............q.| 000002a0 b9 95 ca 9a 86 ff bf 93 8d da 64 ce 99 28 e2 6e |..........d..(.n| 000002b0 6d 6f 34 c9 03 fa 87 96 b0 1d 4f b2 3c 9e 4d 2c |mo4.......O.<.M,| 000002c0 df be 7d fb 53 fe 90 6f 45 f3 f0 d9 ab 70 d4 df |..}.S..oE....p..| 000002d0 5a 95 a4 53 12 02 c1 45 15 c2 2b 69 7e 5f 6f cd |Z..S...E..+i~_o.| 000002e0 b3 eb 5d ff 48 36 94 ad 28 29 fe 47 40 ab 9c eb |..].H6..().G@...| 000002f0 02 f9 ca 7d e0 48 9f 6e a4 9f 1e c2 d7 fd 16 18 |...}.H.n........| 00000300 db ad d9 35 27 89 96 c8 c4 70 10 be a4 5d 6b b4 |...5'....p...]k.| 00000310 d8 61 70 93 08 00 0f c9 14 03 03 00 01 01 16 03 |.ap.............| 00000320 03 00 24 7b ee b7 23 12 63 f0 80 ca b3 6f d3 b8 |..${..#.c....o..| 00000330 ca cc 4a 54 06 ea e5 3e 73 f2 de 1d d6 16 7e 61 |..JT...>s.....~a| 00000340 32 76 eb f8 8a 66 74 |2v...ft| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 24 64 d5 a4 78 e9 |..........$d..x.| 00000010 f1 1d d1 34 f7 b3 95 87 18 f6 cf 65 c6 f0 02 08 |...4.......e....| 00000020 69 f5 6d aa f2 da fc 2c ac fc aa f8 25 aa 50 17 |i.m....,....%.P.| 00000030 03 03 00 21 9f 94 f8 78 46 58 2c 21 0d 30 04 89 |...!...xFX,!.0..| 00000040 bd 35 03 dc 04 b6 0f 6f 22 65 db 3d 8d 96 00 0c |.5.....o"e.=....| 00000050 db bf e5 b3 59 15 03 03 00 16 a6 35 f2 07 5e 32 |....Y......5..^2| 00000060 4e 09 e4 31 3a f6 4a 83 c2 03 db b9 bf b0 eb 6d |N..1:.J........m| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 5b 01 00 00 57 03 03 9a 56 e0 d9 b8 |....[...W...V...| 00000010 ac d5 88 c7 2f d1 87 1b 44 c6 ff 7b 4f 6f f0 2a |..../...D..{Oo.*| 00000020 56 a1 9e 46 86 4b 6f 91 29 29 3b 00 00 04 00 05 |V..F.Ko.));.....| 00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....| 00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| 00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |.......@........| 000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................| 000002d0 00 |.| >>> Flow 3 (client to server) 00000000 16 03 03 00 07 0b 00 00 03 00 00 00 16 03 03 00 |................| 00000010 86 10 00 00 82 00 80 3a 72 91 a2 c3 ba 83 75 1b |.......:r.....u.| 00000020 d3 f6 1c 07 7f 92 a8 b0 1f 47 42 cc 8d 4e 7e 1e |.........GB..N~.| 00000030 23 49 44 29 53 19 9f 3b 5c bb 5d ed 6c d9 49 5d |#ID)S..;\.].l.I]| 00000040 6e f9 d1 59 9d 40 67 b3 0c ee 41 85 6c 4a 4d 3b |n..Y.@g...A.lJM;| 00000050 c1 e6 c8 7f 93 15 cb 2a 17 64 da 70 f3 2a c3 7c |.......*.d.p.*.|| 00000060 a2 02 48 19 fb 74 5a dc 52 0d 80 6b ed c0 8c 15 |..H..tZ.R..k....| 00000070 3e 3b 34 7c 55 6e 95 e0 d1 4a 7f b0 bc 33 67 a7 |>;4|Un...J...3g.| 00000080 3b 40 bb eb 83 58 4a fb fb 01 9b 0d fa ef 83 c4 |;@...XJ.........| 00000090 87 10 75 0c a7 ad 91 14 03 03 00 01 01 16 03 03 |..u.............| 000000a0 00 24 18 ce de 8d ab c1 6e 3b 0b 51 fe 94 ae 0a |.$......n;.Q....| 000000b0 39 9c 4d a2 90 53 d4 1e 5f f6 96 5a 51 f2 39 c1 |9.M..S.._..ZQ.9.| 000000c0 d6 06 c0 4e 58 99 |...NX.| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 24 8b 7e 57 f3 7d |..........$.~W.}| 00000010 ab 44 f0 c7 53 2d 39 08 14 32 12 4e 4b 45 9a e3 |.D..S-9..2.NKE..| 00000020 1c 43 36 16 59 a0 4b e4 78 43 d2 a5 dc 96 b1 17 |.C6.Y.K.xC......| 00000030 03 03 00 21 54 89 75 23 de 7d c7 c6 80 a6 a6 69 |...!T.u#.}.....i| 00000040 d0 a8 95 77 71 a0 89 34 f4 c3 31 73 bb b0 ac d7 |...wq..4..1s....| 00000050 e5 e4 83 4b 10 15 03 03 00 16 0d 44 43 67 21 cc |...K.......DCg!.| 00000060 6c c1 7e 72 99 aa 7f a1 de 10 0b 36 ae 05 d9 9e |l.~r.......6....| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 83 01 00 00 7f 03 03 ec 8e d0 43 01 |..............C.| 00000010 8e 81 3f d8 1f 7e 96 f1 de 4c 94 18 09 1d c5 8c |..?..~...L......| 00000020 3a 58 68 5b 3e 7d 46 66 fe 04 74 00 00 04 c0 0a |:Xh[>}Ff..t.....| 00000030 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 02 00 |......Q.........| 00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................| 00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................| 00000060 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 |.. .............| 00000070 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................| 00000080 02 02 03 00 0f 00 01 01 |........| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 0a 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 03 02 0e 0b 00 02 0a 00 |................| 00000040 02 07 00 02 04 30 82 02 00 30 82 01 62 02 09 00 |.....0...0..b...| 00000050 b8 bf 2d 47 a0 d2 eb f4 30 09 06 07 2a 86 48 ce |..-G....0...*.H.| 00000060 3d 04 01 30 45 31 0b 30 09 06 03 55 04 06 13 02 |=..0E1.0...U....| 00000070 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| 00000080 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| 00000090 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| 000000a0 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 32 |ts Pty Ltd0...12| 000000b0 31 31 32 32 31 35 30 36 33 32 5a 17 0d 32 32 31 |1122150632Z..221| 000000c0 31 32 30 31 35 30 36 33 32 5a 30 45 31 0b 30 09 |120150632Z0E1.0.| 000000d0 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U| 000000e0 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!| 000000f0 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne| 00000100 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt| 00000110 64 30 81 9b 30 10 06 07 2a 86 48 ce 3d 02 01 06 |d0..0...*.H.=...| 00000120 05 2b 81 04 00 23 03 81 86 00 04 00 c4 a1 ed be |.+...#..........| 00000130 98 f9 0b 48 73 36 7e c3 16 56 11 22 f2 3d 53 c3 |...Hs6~..V.".=S.| 00000140 3b 4d 21 3d cd 6b 75 e6 f6 b0 dc 9a df 26 c1 bc |;M!=.ku......&..| 00000150 b2 87 f0 72 32 7c b3 64 2f 1c 90 bc ea 68 23 10 |...r2|.d/....h#.| 00000160 7e fe e3 25 c0 48 3a 69 e0 28 6d d3 37 00 ef 04 |~..%.H:i.(m.7...| 00000170 62 dd 0d a0 9c 70 62 83 d8 81 d3 64 31 aa 9e 97 |b....pb....d1...| 00000180 31 bd 96 b0 68 c0 9b 23 de 76 64 3f 1a 5c 7f e9 |1...h..#.vd?.\..| 00000190 12 0e 58 58 b6 5f 70 dd 9b d8 ea d5 d7 f5 d5 cc |..XX._p.........| 000001a0 b9 b6 9f 30 66 5b 66 9a 20 e2 27 e5 bf fe 3b 30 |...0f[f. .'...;0| 000001b0 09 06 07 2a 86 48 ce 3d 04 01 03 81 8c 00 30 81 |...*.H.=......0.| 000001c0 88 02 42 01 88 a2 4f eb e2 45 c5 48 7d 1b ac f5 |..B...O..E.H}...| 000001d0 ed 98 9d ae 47 70 c0 5e 1b b6 2f bd f1 b6 4d b7 |....Gp.^../...M.| 000001e0 61 40 d3 11 a2 ce ee 0b 7e 92 7e ff 76 9d c3 3b |a@......~.~.v..;| 000001f0 7e a5 3f ce fa 10 e2 59 ec 47 2d 7c ac da 4e 97 |~.?....Y.G-|..N.| 00000200 0e 15 a0 6f d0 02 42 01 4d fc be 67 13 9c 2d 05 |...o..B.M..g..-.| 00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7| 00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.| 00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1| 00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 d8 0c 00 |{j.9....*.......| 00000250 00 d4 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5| 00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >| 00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l| 00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.| 00000290 41 03 56 6b dc 5a 89 05 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B| 000002a0 01 08 89 99 1c 91 97 fb e8 5b 69 5f f5 36 66 d6 |.........[i_.6f.| 000002b0 dd 53 04 09 c8 7f c1 25 28 8c 28 57 55 3a 95 3f |.S.....%(.(WU:.?| 000002c0 ab 09 47 9a 27 74 83 84 44 cf 86 b7 5e 7f fe db |..G.'t..D...^...| 000002d0 05 33 3c 1a b7 f6 bc ff 0d 33 e4 ec 3c e2 1d e2 |.3<......3..<...| 000002e0 6e ab 02 42 00 92 4e 45 a7 86 e4 bd 40 82 b7 04 |n..B..NE....@...| 000002f0 12 fe 34 ab e3 c9 4a 05 1f 4e 58 79 67 58 94 53 |..4...J..NXygX.S| 00000300 e8 1b ba 60 76 92 00 99 a7 5f 0a 98 cb e3 1e de |...`v...._......| 00000310 0c df 18 76 58 d5 e1 f1 ef a5 da 9a a3 62 77 50 |...vX........bwP| 00000320 37 d0 22 d0 31 90 16 03 03 00 04 0e 00 00 00 |7.".1..........| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 9e 94 25 4f 70 |....F...BA...%Op| 00000010 a8 e0 87 3a 09 6c 58 4f 5e 76 d9 63 dc c3 d5 63 |...:.lXO^v.c...c| 00000020 be f2 75 ff 23 23 79 6b 82 fe 56 f5 b9 7a 55 55 |..u.##yk..V..zUU| 00000030 32 3b ee c5 f0 1f 7b e9 82 01 21 8d 06 03 48 95 |2;....{...!...H.| 00000040 21 b8 fa 9d 18 2a 08 9c 71 a8 4d 14 03 03 00 01 |!....*..q.M.....| 00000050 01 16 03 03 00 40 31 f0 7b 5f e8 94 a3 7f b0 12 |.....@1.{_......| 00000060 a9 80 87 26 eb cf b6 87 61 e7 5b 9b 36 3d 11 bb |...&....a.[.6=..| 00000070 21 55 5c f7 e8 f3 b7 1e f2 06 0d c5 a9 8d f8 48 |!U\............H| 00000080 c2 2b 8f 83 be 17 4f ec ff 8e 24 44 74 25 09 40 |.+....O...$Dt%.@| 00000090 90 fd 70 4d fb bb |..pM..| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| 00000010 00 00 00 00 00 00 00 00 00 00 00 13 eb 4e 56 3d |.............NV=| 00000020 1b 10 2e e8 08 65 b9 53 9e 56 49 b7 e9 25 35 94 |.....e.S.VI..%5.| 00000030 c7 df 7d f7 78 2e f3 8b 9c 2b 9d 42 90 91 5c 97 |..}.x....+.B..\.| 00000040 22 20 ca 6d a2 83 b3 d8 b3 71 64 17 03 03 00 40 |" .m.....qd....@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000060 97 f1 c4 2e bf 6d 85 d5 3d 4b 4a 8b ee 53 08 5a |.....m..=KJ..S.Z| 00000070 db 8b 75 49 d9 cb db e3 86 90 ac 93 ce e7 9a 70 |..uI...........p| 00000080 4c dc 4a f4 c9 f6 b5 fd f0 3f 9f e9 f9 c3 b3 c6 |L.J......?......| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| 000000a0 00 00 00 00 00 5e b1 b7 21 7d 89 65 66 17 d8 79 |.....^..!}.ef..y| 000000b0 26 db ad 08 28 2c e7 7a c4 ec 93 19 4f c8 bb 5c |&...(,.z....O..\| 000000c0 c2 9e 09 56 07 |...V.| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-IssueTicket ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 5f 01 00 00 5b 03 03 6e cc 37 81 0a |...._...[..n.7..| 00000010 b9 fe 58 30 8e 32 61 3c b1 38 1e 2b f6 ab 44 ee |..X0.2a<.8.+..D.| 00000020 f2 cc fe 6e fe 40 65 49 d9 ba aa 00 00 04 00 05 |...n.@eI........| 00000030 00 ff 02 01 00 00 2d 00 23 00 00 00 0d 00 20 00 |......-.#..... .| 00000040 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................| 00000050 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................| 00000060 0f 00 01 01 |....| >>> Flow 2 (server to client) 00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| 00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.| 00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..| 00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....| 00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........| 00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo| 00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..| 00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..| 000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..| 000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1| 000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google| 000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.| 000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.| 000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....| 00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..| 00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5| 00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..| 00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.| 00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....| 00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....| 00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..| 00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G| 00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..| 00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..| 000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....| 000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...| 000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.| 000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn| 000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.| 000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f..@....xH| 00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e| 00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..| 00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............| 00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H@.-.| 00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.| 00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!| 00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"| 00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8| 00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...| 00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |...@.Q......F.F.| 000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.| 000002b0 16 03 03 00 04 0e 00 00 00 |.........| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 5d f3 3b c6 24 |...........].;.$| 00000010 34 17 eb e1 6c de fa cd ed 6f 42 74 01 5f 4b 22 |4...l....oBt._K"| 00000020 9e 79 da 68 9f e9 f8 af 84 6b b7 38 52 f3 5e a1 |.y.h.....k.8R.^.| 00000030 e2 aa d1 48 15 1e 39 6e 18 59 3e dc 57 4a fb b1 |...H..9n.Y>.WJ..| 00000040 18 18 40 ae 84 da d8 76 50 65 3b a5 d9 7a 72 b1 |..@....vPe;..zr.| 00000050 51 07 65 08 0e 1d 05 f5 47 a8 7d 79 89 1e fe 00 |Q.e.....G.}y....| 00000060 89 af 01 7f 4d 0c 11 d7 02 cf 88 7b be 03 c5 65 |....M......{...e| 00000070 44 77 32 56 5c da 01 53 d1 dd d9 b4 5f 42 85 da |Dw2V\..S...._B..| 00000080 82 0b 95 59 45 a3 7a 48 d4 00 22 14 03 03 00 01 |...YE.zH..".....| 00000090 01 16 03 03 00 24 dd 06 a2 4b a0 8e 8b 31 f2 26 |.....$...K...1.&| 000000a0 b2 6f d4 5d ff 34 eb 31 42 16 e7 c2 26 3d f7 16 |.o.].4.1B...&=..| 000000b0 ed bd 41 4b 6f d4 03 fb b7 83 |..AKo.....| >>> Flow 4 (server to client) 00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| 00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| 00000030 6f 2c b5 83 61 4d 51 5f 33 46 48 fe 9e e9 83 f4 |o,..aMQ_3FH.....| 00000040 b1 aa c9 b1 61 2a b2 9d 0f 17 c4 09 f6 26 7a 75 |....a*.......&zu| 00000050 f1 19 99 db 36 d8 32 f0 94 61 4f 8f ed 80 33 51 |....6.2..aO...3Q| 00000060 f3 c6 15 84 6b 33 94 c8 4f 84 b7 7c 27 6d 8f fe |....k3..O..|'m..| 00000070 41 8e b2 92 ca 80 e8 6c ba 75 77 f5 3a 87 17 ae |A......l.uw.:...| 00000080 f8 b9 6b 10 f9 85 da 14 03 03 00 01 01 16 03 03 |..k.............| 00000090 00 24 70 bd b9 24 02 ce 69 8a 07 c7 c8 7e cf b7 |.$p..$..i....~..| 000000a0 4e 2b e2 dc 47 fc f7 3a c8 2d ab a0 9a ed 27 d9 |N+..G..:.-....'.| 000000b0 71 ea 45 29 d6 25 17 03 03 00 21 d9 28 ee 99 04 |q.E).%....!.(...| 000000c0 35 ff ca 3d 30 3f 76 fb 08 1a 56 73 f5 72 c3 fa |5..=0?v...Vs.r..| 000000d0 cd 9e 3c 1b 3f 43 4d 56 92 38 9e a6 15 03 03 00 |..<.?CMV.8......| 000000e0 16 6f 55 57 7b 81 6f 7d fa 90 76 0b 5b 6d 95 35 |.oUW{.o}..v.[m.5| 000000f0 39 9f a8 c9 dc b7 80 |9......| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 5f 01 00 00 5b 03 03 54 25 f9 0f b8 |...._...[..T%...| 00000010 2d 52 a0 17 b6 62 1c 60 38 31 30 67 f1 55 9c c8 |-R...b.`810g.U..| 00000020 d3 74 65 bf cd 34 fb 6f f2 60 7c 00 00 04 00 05 |.te..4.o.`|.....| 00000030 00 ff 02 01 00 00 2d 00 23 00 00 00 0d 00 20 00 |......-.#..... .| 00000040 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................| 00000050 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................| 00000060 0f 00 01 01 |....| >>> Flow 2 (server to client) 00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| 00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.| 00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..| 00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....| 00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........| 00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo| 00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..| 00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..| 000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..| 000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1| 000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google| 000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.| 000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.| 000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....| 00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..| 00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5| 00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..| 00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.| 00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....| 00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....| 00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..| 00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G| 00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..| 00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..| 000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....| 000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...| 000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.| 000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn| 000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.| 000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f..@....xH| 00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e| 00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..| 00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............| 00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H@.-.| 00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.| 00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!| 00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"| 00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8| 00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...| 00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |...@.Q......F.F.| 000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.| 000002b0 16 03 03 00 04 0e 00 00 00 |.........| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 19 db c8 25 14 |..............%.| 00000010 e0 7b 6e 87 7b 59 2d 85 8b 47 ce 31 d7 3a 53 06 |.{n.{Y-..G.1.:S.| 00000020 ff cf 89 ae 45 fd 59 d2 50 c2 31 33 48 81 a8 d7 |....E.Y.P.13H...| 00000030 47 36 b9 bd 8d f3 f9 f8 c2 6d 6a 8a 6b c4 e5 53 |G6.......mj.k..S| 00000040 24 52 40 66 49 a9 56 74 4c 94 bc 85 5b 79 5a e1 |$R@fI.VtL...[yZ.| 00000050 66 3c 42 d8 ca e1 3f c5 36 b8 b5 8c b2 ea 87 68 |f>> Flow 4 (server to client) 00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| 00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| 00000030 6f 2c b5 83 61 01 55 65 2a 95 38 d4 d5 5f 41 c1 |o,..a.Ue*.8.._A.| 00000040 45 e4 f8 4b 3b 08 44 df 0b 72 11 93 cd d4 ff 36 |E..K;.D..r.....6| 00000050 0f 4f 3a a9 4c 9f ab c7 ae 88 97 bc 1e ff 2d 27 |.O:.L.........-'| 00000060 39 a8 82 84 ae 33 94 48 8b 1c 58 9d 60 65 3c 3f |9....3.H..X.`e>> Flow 1 (client to server) 00000000 16 03 01 00 5b 01 00 00 57 03 03 1e c8 d0 4c b2 |....[...W.....L.| 00000010 8d 37 e1 88 c7 0f e0 6a 21 3c 5e 8a bf fa 97 1f |.7.....j!<^.....| 00000020 5b 28 bc 6d 47 32 0a 6b f7 11 f5 00 00 04 00 0a |[(.mG2.k........| 00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....| 00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| 00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 4d c2 e0 9b 40 |...........M...@| 00000010 44 52 aa 55 06 71 0b bc 17 89 3a 94 d8 d0 1d ed |DR.U.q....:.....| 00000020 70 d3 21 30 1b be 97 e0 72 30 60 05 de 9a a9 dd |p.!0....r0`.....| 00000030 8c 0c 81 78 3a 15 9c 1c c6 22 81 0a 10 57 d1 9a |...x:...."...W..| 00000040 17 5c 74 9e 58 79 4b f1 70 d9 d9 21 d8 79 64 fa |.\t.XyK.p..!.yd.| 00000050 aa a5 e6 93 2a 16 57 23 a7 17 fb 71 b6 c2 d3 5b |....*.W#...q...[| 00000060 3d 22 50 16 47 17 5f 15 e8 f1 30 da 10 69 84 25 |="P.G._...0..i.%| 00000070 05 d0 b5 f0 e8 69 72 4e 93 d3 7c 1a 01 6d 37 fb |.....irN..|..m7.| 00000080 cf e1 af f9 da dd 71 56 9b 08 24 14 03 03 00 01 |......qV..$.....| 00000090 01 16 03 03 00 30 53 ab b5 09 5a 36 36 df b1 ed |.....0S...Z66...| 000000a0 d2 69 5c 45 0b a9 02 8f 6d 25 d4 01 da 5f 27 ab |.i\E....m%..._'.| 000000b0 ba 89 6e ee d8 91 24 f8 5e ca 6e 4d 51 41 88 3c |..n...$.^.nMQA.<| 000000c0 f8 67 b4 fb d3 cb |.g....| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 30 00 00 00 00 00 |..........0.....| 00000010 00 00 00 50 83 52 65 2d 6e 76 aa 8d 2d 46 06 12 |...P.Re-nv..-F..| 00000020 1a e7 25 79 28 61 9e 2d 07 0b fb 3c 77 38 d8 b0 |..%y(a.-...>> Flow 1 (client to server) 00000000 16 03 01 00 5b 01 00 00 57 03 03 5a ba 29 44 35 |....[...W..Z.)D5| 00000010 c4 48 64 61 06 84 70 5c b5 65 ad 01 9b b2 29 0d |.Hda..p\.e....).| 00000020 d1 46 17 3a 27 fb 92 d8 aa 21 aa 00 00 04 00 2f |.F.:'....!...../| 00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....| 00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| 00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| 00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 ad e8 09 aa 07 |................| 00000010 c0 3c 8b 39 d2 a8 bd ca 59 eb cf 0a de 33 3e d2 |.<.9....Y....3>.| 00000020 4f 76 1f 7a 96 50 b3 52 6b 04 9e 6f f1 06 2b 4a |Ov.z.P.Rk..o..+J| 00000030 7f 01 f2 51 a3 a7 1e f6 20 a7 27 4e 97 68 61 98 |...Q.... .'N.ha.| 00000040 9f fd bd aa e8 e6 80 4d 9a 65 51 35 11 44 e4 2c |.......M.eQ5.D.,| 00000050 a2 47 33 d1 b6 b7 d5 40 c0 17 34 ff e2 12 8e 00 |.G3....@..4.....| 00000060 41 e6 4f 3e 56 2f d9 30 6b d9 99 e3 9f ce 10 ba |A.O>V/.0k.......| 00000070 7c 95 3b 49 c9 5f 1e 97 37 90 e4 da 9a e0 01 5f ||.;I._..7......_| 00000080 b8 6f 95 19 40 0f ca 63 76 6b 2a 14 03 03 00 01 |.o..@..cvk*.....| 00000090 01 16 03 03 00 40 86 cb f5 69 1b ee 67 6e 3b be |.....@...i..gn;.| 000000a0 e0 de 22 06 8c d4 f4 98 a6 45 1c 2f e5 f0 b4 25 |.."......E./...%| 000000b0 f4 c0 87 7f e8 1c 2c 1d 20 52 50 fe dc a3 0c 22 |......,. RP...."| 000000c0 b7 7f d3 9c 42 b8 23 d0 3e fd 93 be a2 50 28 dd |....B.#.>....P(.| 000000d0 79 f3 c6 90 c7 bb |y.....| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| 00000010 00 00 00 00 00 00 00 00 00 00 00 70 e5 19 ef 25 |...........p...%| 00000020 05 0b 02 79 2b 79 49 e6 2c ad c0 e7 03 b3 40 68 |...y+yI.,.....@h| 00000030 67 98 31 7c 7e 85 86 a8 5c de 72 3f d1 59 12 20 |g.1|~...\.r?.Y. | 00000040 87 95 44 57 64 35 03 f5 68 61 20 17 03 03 00 40 |..DWd5..ha ....@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000060 1b 17 7c bb 04 4f 31 7b da 40 5e 93 64 97 4a 8d |..|..O1{.@^.d.J.| 00000070 98 cf 77 2d 01 53 37 53 2c 59 8f ca ac 65 ae f3 |..w-.S7S,Y...e..| 00000080 f8 d4 ae 67 74 c8 72 21 67 51 9a 1b 71 f2 0e 04 |...gt.r!gQ..q...| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| 000000a0 00 00 00 00 00 fd 36 99 3d c7 44 1b 30 39 4a a7 |......6.=.D.09J.| 000000b0 40 43 e3 01 2b 22 3d c6 8c a1 0d 73 d5 16 d2 25 |@C..+"=....s...%| 000000c0 19 c8 d7 76 ee |...v.| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 83 01 00 00 7f 03 03 19 c7 02 a0 bf |................| 00000010 5a fb c2 d4 f5 68 0a 19 0f 5e 3a 6b c5 88 17 0b |Z....h...^:k....| 00000020 35 ff df ee 06 32 ad 32 99 0e c9 00 00 04 c0 2f |5....2.2......./| 00000030 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 02 00 |......Q.........| 00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................| 00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................| 00000060 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 |.. .............| 00000070 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................| 00000080 02 02 03 00 0f 00 01 01 |........| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 2f 00 00 |............./..| 00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...| 000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..| 000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..| 000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.| 000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 97 53 |.h.A.Vk.Z......S| 00000300 cc 1f a2 55 e2 52 69 a6 b3 78 4f 7e 34 3e 37 e4 |...U.Ri..xO~4>7.| 00000310 e0 bb 15 ff 96 f8 1d 9c 11 03 2c 68 ca 6d 2b 3c |..........,h.m+<| 00000320 b3 96 64 21 d6 3f 81 42 07 c0 1b 85 7e a9 65 54 |..d!.?.B....~.eT| 00000330 23 89 33 c1 71 b9 29 72 47 8a 0e 71 75 20 d7 b6 |#.3.q.)rG..qu ..| 00000340 9d c2 ac c1 a8 dc 6c 0e 7e 29 93 fc b2 68 83 2e |......l.~)...h..| 00000350 e1 fe e5 eb 54 d7 c3 30 f2 8f 9d 91 49 48 4f 84 |....T..0....IHO.| 00000360 1a d5 47 75 27 bf c8 09 65 4a a8 7c 65 a0 d0 23 |..Gu'...eJ.|e..#| 00000370 9f 26 d6 57 62 cb e1 06 64 90 16 73 1b d4 16 03 |.&.Wb...d..s....| 00000380 03 00 04 0e 00 00 00 |.......| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1a 94 a7 1a 36 |....F...BA.....6| 00000010 d1 ca ad d7 e8 64 03 84 b4 a6 9f dc 30 a2 a3 60 |.....d......0..`| 00000020 a0 5a 1f a0 3d 8e d1 b8 96 75 37 ee a6 3f d6 ad |.Z..=....u7..?..| 00000030 93 b6 7d 58 99 53 04 4b 6e c6 7f 04 bf 60 f9 ba |..}X.S.Kn....`..| 00000040 e7 b8 04 73 10 77 ff 22 93 b2 7b 14 03 03 00 01 |...s.w."..{.....| 00000050 01 16 03 03 00 28 29 6b 2b 14 21 a7 e4 84 c0 9d |.....()k+.!.....| 00000060 92 07 cd dd 0b eb c1 b0 76 06 71 48 46 93 b8 05 |........v.qHF...| 00000070 1a 2b 53 14 da 34 ac 05 4c cc 4d 47 12 28 |.+S..4..L.MG.(| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....| 00000010 00 00 00 b9 c9 6f cb 58 df 1c a1 0a 79 4e fa 8f |.....o.X....yN..| 00000020 41 55 8a 0a f8 d1 83 88 28 fb 44 00 8a a5 11 39 |AU......(.D....9| 00000030 5b d4 83 17 03 03 00 25 00 00 00 00 00 00 00 01 |[......%........| 00000040 85 4f 2a 54 aa c0 ce 7b 1e 4e e4 64 56 57 68 5e |.O*T...{.N.dVWh^| 00000050 fa 41 67 8a da 9d f4 78 a6 c6 13 76 7c 15 03 03 |.Ag....x...v|...| 00000060 00 1a 00 00 00 00 00 00 00 02 38 71 21 c6 82 bc |..........8q!...| 00000070 2e 37 14 1d 15 2f 74 9d 7c 99 d8 66 |.7.../t.|..f| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 83 01 00 00 7f 03 03 55 9b 71 e2 46 |...........U.q.F| 00000010 88 58 c4 16 6a 6e 14 3d 3a 5a f9 fe ec 68 71 24 |.X..jn.=:Z...hq$| 00000020 d0 06 6f a1 56 8f d6 15 42 6b ba 00 00 04 c0 30 |..o.V...Bk.....0| 00000030 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 02 00 |......Q.........| 00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................| 00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................| 00000060 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 |.. .............| 00000070 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................| 00000080 02 02 03 00 0f 00 01 01 |........| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..| 00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...| 000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..| 000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..| 000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.| 000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 7f 44 |.h.A.Vk.Z......D| 00000300 af 7b 21 01 6b f0 1c 75 d3 6b 28 99 68 e1 0e d3 |.{!.k..u.k(.h...| 00000310 a8 cb 5a 2e 23 ad d7 92 73 46 5b 66 88 bd f1 d6 |..Z.#...sF[f....| 00000320 5d 52 d1 07 53 88 9c 64 e3 ce 80 b3 39 7f 9e 2b |]R..S..d....9..+| 00000330 0a 02 a7 e1 3e 00 70 51 3b b4 52 d1 3c 4a e9 f7 |....>.pQ;.R.>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 d8 85 85 d2 78 |....F...BA.....x| 00000010 27 a5 0a bb 10 67 ec a9 d8 11 f0 ba b9 d7 21 39 |'....g........!9| 00000020 ed c7 0a a0 a2 69 ab fb 9b 15 e0 d7 ec ca 97 c8 |.....i..........| 00000030 c0 b2 66 0b 2c 68 37 ac f0 34 fa 3a 07 dd f2 ae |..f.,h7..4.:....| 00000040 8e f6 e3 eb de 08 1f 56 e5 66 eb 14 03 03 00 01 |.......V.f......| 00000050 01 16 03 03 00 28 f5 2d 89 00 0c 9d d9 0e 54 1b |.....(.-......T.| 00000060 71 84 4d c7 bb 98 36 8c 29 b6 06 d8 7b df d9 92 |q.M...6.)...{...| 00000070 01 00 16 44 5e e3 db f3 8f b7 fa 43 0c f7 |...D^......C..| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....| 00000010 00 00 00 a4 82 dc d1 67 ed 17 ae 22 13 0d ac d2 |.......g..."....| 00000020 f4 58 44 5b b4 c6 25 29 80 b6 bc 63 0e 67 22 6e |.XD[..%)...c.g"n| 00000030 18 92 48 17 03 03 00 25 00 00 00 00 00 00 00 01 |..H....%........| 00000040 a0 fe 37 25 fb 4d 29 96 f9 01 67 19 d8 83 26 68 |..7%.M)...g...&h| 00000050 d0 e8 58 2c ef 90 a3 b5 26 51 26 a9 28 15 03 03 |..X,....&Q&.(...| 00000060 00 1a 00 00 00 00 00 00 00 02 91 4b d5 54 4a ef |...........K.TJ.| 00000070 22 88 ab b7 a2 bb 20 5a b2 3e 7b 36 |"..... Z.>{6| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-RSA-RC4 ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 5b 01 00 00 57 03 03 ec 96 78 51 74 |....[...W....xQt| 00000010 1b f2 21 ad f2 4f 50 aa 67 f1 20 e2 4f d3 4d 0e |..!..OP.g. .O.M.| 00000020 54 91 df 91 d8 81 e3 75 bb 20 c2 00 00 04 00 05 |T......u. ......| 00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....| 00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| 00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 05 4b 04 74 76 |............K.tv| 00000010 73 3a 92 04 4d 8b 3b 59 c2 43 c5 f4 07 e8 bc a3 |s:..M.;Y.C......| 00000020 62 44 b7 80 9f 8f bc 43 8a 67 09 64 a7 93 9f f9 |bD.....C.g.d....| 00000030 2c 55 03 4b e5 87 9d 18 a2 c3 48 4f 02 6e e0 23 |,U.K......HO.n.#| 00000040 0b 2f 57 81 e4 38 50 11 d6 b1 71 4f c2 e5 a4 03 |./W..8P...qO....| 00000050 34 a4 eb a1 42 47 79 05 bc 7b b8 26 5b c1 f9 82 |4...BGy..{.&[...| 00000060 fc 58 49 eb 04 52 fe 57 3c ed 5c 2b d8 fe 49 d7 |.XI..R.W<.\+..I.| 00000070 d2 2e 6c e8 74 74 0d 87 b3 f6 2d f0 ff 03 f0 2d |..l.tt....-....-| 00000080 c8 a2 20 89 3f 3f 11 e1 fb 93 85 14 03 03 00 01 |.. .??..........| 00000090 01 16 03 03 00 24 9a 81 c0 9e 76 b6 3d 78 37 8e |.....$....v.=x7.| 000000a0 ab 33 48 93 bb 0d f4 86 3c ff 72 28 10 35 c2 10 |.3H.....<.r(.5..| 000000b0 f0 a0 ff 0c 20 f3 c4 29 83 a6 |.... ..)..| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 24 93 15 62 c5 2b |..........$..b.+| 00000010 4f 8a d7 0f 70 1f 9d 11 fc 8f 9a a9 b7 d7 44 50 |O...p.........DP| 00000020 6e 0e 5b d7 3b de 15 7d 17 35 31 42 1f a4 40 17 |n.[.;..}.51B..@.| 00000030 03 03 00 21 a9 ca 73 e9 ce 2d 21 ef 7d bc 40 91 |...!..s..-!.}.@.| 00000040 41 c9 53 62 af 09 8e b4 37 0f fa ab b7 76 8f 5b |A.Sb....7....v.[| 00000050 7d 0f 04 48 49 15 03 03 00 16 76 b1 d7 91 88 6f |}..HI.....v....o| 00000060 b4 e7 a4 f1 d2 c2 ac 50 db 31 ae 5c f7 53 a1 68 |.......P.1.\.S.h| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-Resume ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 f7 01 00 00 f3 03 03 35 70 0b ed 1c |...........5p...| 00000010 83 57 b1 7b 0a 47 ce d4 07 3a 49 96 93 4c a1 83 |.W.{.G...:I..L..| 00000020 4b ab b7 ab 7d b0 14 be dd 91 92 20 09 34 b7 de |K...}...... .4..| 00000030 bd 43 e8 cd 8e f3 43 aa 04 64 8f 0a 55 a6 58 ed |.C....C..d..U.X.| 00000040 31 8b 3d 4c 84 4f 2c 6d b0 b1 75 6f 00 04 00 05 |1.=L.O,m..uo....| 00000050 00 ff 02 01 00 00 a5 00 23 00 78 50 46 ad c1 db |........#.xPF...| 00000060 a8 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 |.8.{+....B>.....| 00000070 00 00 00 00 00 00 00 00 00 00 00 94 6f 2c b5 83 |............o,..| 00000080 61 4d 51 5f 33 46 48 fe 9e e9 83 f4 b1 aa c9 b1 |aMQ_3FH.........| 00000090 61 2a b2 9d 0f 17 c4 09 f6 26 7a 75 f1 19 99 db |a*.......&zu....| 000000a0 36 d8 32 f0 94 61 4f 8f ed 80 33 51 f3 c6 15 84 |6.2..aO...3Q....| 000000b0 6b 33 94 c8 4f 84 b7 7c 27 6d 8f fe 41 8e b2 92 |k3..O..|'m..A...| 000000c0 ca 80 e8 6c ba 75 77 f5 3a 87 17 ae f8 b9 6b 10 |...l.uw.:.....k.| 000000d0 f9 85 da 00 0d 00 20 00 1e 06 01 06 02 06 03 05 |...... .........| 000000e0 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 |................| 000000f0 03 02 01 02 02 02 03 00 0f 00 01 01 |............| >>> Flow 2 (server to client) 00000000 16 03 03 00 51 02 00 00 4d 03 03 00 00 00 00 00 |....Q...M.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 20 09 34 b7 de |........... .4..| 00000030 bd 43 e8 cd 8e f3 43 aa 04 64 8f 0a 55 a6 58 ed |.C....C..d..U.X.| 00000040 31 8b 3d 4c 84 4f 2c 6d b0 b1 75 6f 00 05 00 00 |1.=L.O,m..uo....| 00000050 05 ff 01 00 01 00 14 03 03 00 01 01 16 03 03 00 |................| 00000060 24 18 67 37 5a c6 ea 3f 5f 06 2d c3 f1 2a ff d3 |$.g7Z..?_.-..*..| 00000070 45 ce fe 38 1a e6 39 25 e7 e5 01 4d 6e fd 23 af |E..8..9%...Mn.#.| 00000080 dc 67 1b 1d e2 |.g...| >>> Flow 3 (client to server) 00000000 14 03 03 00 01 01 16 03 03 00 24 b5 75 e6 1d 1d |..........$.u...| 00000010 cb 2c 5d 9f d1 07 de 23 11 84 c2 59 50 55 72 27 |.,]....#...YPUr'| 00000020 f2 5e 34 e2 c1 53 bf 21 5f f4 c4 2c f1 e1 7a |.^4..S.!_..,..z| >>> Flow 4 (server to client) 00000000 17 03 03 00 21 93 92 dd 07 a3 8f 3d 34 6d b8 94 |....!......=4m..| 00000010 a7 6f 18 27 e7 cd 30 0a 08 4f b6 9b cb 43 93 27 |.o.'..0..O...C.'| 00000020 b6 8b 83 ae d6 8a 15 03 03 00 16 68 a1 a4 f8 66 |...........h...f| 00000030 8a c0 e7 d3 97 83 cb 35 94 84 7a e6 47 3c 97 8c |.......5..z.G<..| 00000040 69 |i| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-ResumeDisabled ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 f7 01 00 00 f3 03 03 2b 89 3f 02 47 |...........+.?.G| 00000010 f6 14 64 3b 64 08 84 6e 9c e1 c9 4d 4f 30 92 06 |..d;d..n...MO0..| 00000020 d1 19 58 5d 93 30 41 4d a6 2c f6 20 53 3c e7 f4 |..X].0AM.,. S<..| 00000030 23 7e 59 b1 32 c4 2d db 0b 6f ab 64 4a 72 c9 31 |#~Y.2.-..o.dJr.1| 00000040 d9 b9 38 a8 b4 4e 0c 39 f8 f4 61 7a 00 04 00 05 |..8..N.9..az....| 00000050 00 ff 02 01 00 00 a5 00 23 00 78 50 46 ad c1 db |........#.xPF...| 00000060 a8 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 |.8.{+....B>.....| 00000070 00 00 00 00 00 00 00 00 00 00 00 94 6f 2c b5 83 |............o,..| 00000080 61 01 55 65 2a 95 38 d4 d5 5f 41 c1 45 e4 f8 4b |a.Ue*.8.._A.E..K| 00000090 3b 08 44 df 0b 72 11 93 cd d4 ff 36 0f 4f 3a a9 |;.D..r.....6.O:.| 000000a0 4c 9f ab c7 ae 88 97 bc 1e ff 2d 27 39 a8 82 84 |L.........-'9...| 000000b0 ae 33 94 48 8b 1c 58 9d 60 65 3c 3f 17 9d 6a eb |.3.H..X.`e>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| 00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| 00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| 00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| 00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| 00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | 00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| 00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| 000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| 000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| 000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| 000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| 000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| 000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| 00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| 00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| 00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| 00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| 00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| 00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| 00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| 00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| 00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| 00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| 000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| 000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| 000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| 000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| 000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| 000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| 00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| 00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| 00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| 00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| 00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| 00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| 00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| 00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| 00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| 00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| 000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| 000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 ab d9 61 5e d3 |.............a^.| 00000010 87 d7 eb 21 12 6f f9 61 dd 8b de 76 d7 14 70 2f |...!.o.a...v..p/| 00000020 9c 0f 3c d4 4c 77 41 e2 ac 73 18 c3 0f 66 f2 b1 |..<.LwA..s...f..| 00000030 fd 4b 1e d9 cb 5c 94 16 4d c2 98 f9 0d 55 f7 79 |.K...\..M....U.y| 00000040 e2 8d 2c 87 96 e7 10 fb 78 fb ce 27 5d 9f ac 97 |..,.....x..']...| 00000050 d6 54 6f 0c 78 dc 7b 2e 49 4c e2 42 24 b9 3d de |.To.x.{.IL.B$.=.| 00000060 89 5f 1a 40 54 33 11 96 89 6f 59 25 5e 89 60 40 |._.@T3...oY%^.`@| 00000070 83 8c 0e 92 0e 7d 68 9d 17 74 ba 39 e8 6f e3 43 |.....}h..t.9.o.C| 00000080 44 80 e6 62 4b 35 43 21 5b eb 32 14 03 03 00 01 |D..bK5C![.2.....| 00000090 01 16 03 03 00 24 77 1a b5 2c 88 d7 a6 83 f5 30 |.....$w..,.....0| 000000a0 a0 c3 b4 45 a6 af 9b c2 ac 55 cf 73 4f a0 ba e5 |...E.....U.sO...| 000000b0 2a be 9c 97 d2 d2 0b e9 95 0e |*.........| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 24 a9 ae 0c a5 ed |..........$.....| 00000010 51 10 d9 14 71 41 40 bd be f5 44 98 11 2f d8 0f |Q...qA@...D../..| 00000020 4d 42 bf 28 53 bf 02 7e d6 16 92 7f dd 03 ec 17 |MB.(S..~........| 00000030 03 03 00 21 46 c2 68 a1 6a 35 67 e7 7d 62 71 43 |...!F.h.j5g.}bqC| 00000040 6b ea d6 fc 22 fc 2d ad 45 d6 6d 98 9e e5 88 a0 |k...".-.E.m.....| 00000050 ac 80 f7 6f 05 15 03 03 00 16 0c ae f4 fc 0e 09 |...o............| 00000060 0b 09 73 69 83 0d 00 89 39 ff f6 20 4e 2b 88 3d |..si....9.. N+.=| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-SNI ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 6f 01 00 00 6b 03 03 07 0f b6 b9 cc |....o...k.......| 00000010 db 23 57 92 d0 9b 37 72 9d ad 9a 0d 17 6b dd b8 |.#W...7r.....k..| 00000020 81 b7 7c 54 dd 68 fe 4e 28 00 39 00 00 04 00 2f |..|T.h.N(.9..../| 00000030 00 ff 02 01 00 00 3d 00 00 00 10 00 0e 00 00 0b |......=.........| 00000040 73 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 |snitest.com... .| 00000050 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................| 00000060 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................| 00000070 0f 00 01 01 |....| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| 00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................| 00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...| 00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| 00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A| 00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...| 00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...| 00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1| 000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.| 000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| 000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite| 000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H| 000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....| 000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..| 00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..| 00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~| 00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....| 00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T| 00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}| 00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f| 00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-| 00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.| 00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.| 00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#| 000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.| 000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.| 000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.| 000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....| 000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n| 000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....| 00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@| 00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.| 00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...| 00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......| 00000240 0e 00 00 00 |....| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 72 6a 6f a8 c9 |...........rjo..| 00000010 3e 4c 33 da 92 23 97 68 fc 4e ca 74 77 98 f3 88 |>L3..#.h.N.tw...| 00000020 ba a0 55 b6 a0 6f ff c8 db 2b 90 17 1f 45 bc 26 |..U..o...+...E.&| 00000030 62 6e b9 91 96 b9 03 5d eb f2 a2 59 87 7b 81 4a |bn.....]...Y.{.J| 00000040 0c f9 e2 23 60 e3 c7 4d 53 4f 3a 1f c5 5f dd 15 |...#`..MSO:.._..| 00000050 cc 78 c5 21 fd 33 02 68 77 7c 8d 5f e8 80 a7 84 |.x.!.3.hw|._....| 00000060 a7 2c b3 1f 64 df 8a 63 e9 b3 24 02 c1 6a 94 bd |.,..d..c..$..j..| 00000070 a1 62 e5 32 e5 d9 83 25 0d 0f 1a 02 90 8a cd 79 |.b.2...%.......y| 00000080 1c bd 4a c2 f4 5d a0 24 c6 c1 ae 14 03 03 00 01 |..J..].$........| 00000090 01 16 03 03 00 40 1f 1a 17 47 15 25 5b 3d 5f e5 |.....@...G.%[=_.| 000000a0 f4 d9 64 47 5f 80 09 f7 dd 5a ff 58 19 08 b5 db |..dG_....Z.X....| 000000b0 38 88 a4 44 07 01 fb 80 1d 89 b2 d4 af 95 80 b3 |8..D............| 000000c0 75 13 82 0e 24 12 1d 5c 29 72 1d 21 d4 69 16 e0 |u...$..\)r.!.i..| 000000d0 b5 4b 46 62 fe f7 |.KFb..| >>> Flow 4 (server to client) 00000000 15 03 03 00 02 02 14 |.......| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 6f 01 00 00 6b 03 03 fe d6 ce b5 1b |....o...k.......| 00000010 1c 50 0c db 9c 35 5d 0e f2 ee 57 3f 65 83 9f 28 |.P...5]...W?e..(| 00000020 96 50 1c e0 7f 95 f9 17 39 4f c3 00 00 04 00 2f |.P......9O...../| 00000030 00 ff 02 01 00 00 3d 00 00 00 10 00 0e 00 00 0b |......=.........| 00000040 73 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 |snitest.com... .| 00000050 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................| 00000060 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................| 00000070 0f 00 01 01 |....| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| 00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................| 00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...| 00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| 00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A| 00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...| 00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...| 00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1| 000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.| 000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| 000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite| 000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H| 000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....| 000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..| 00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..| 00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~| 00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....| 00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T| 00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}| 00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f| 00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-| 00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.| 00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.| 00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#| 000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.| 000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.| 000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.| 000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....| 000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n| 000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....| 00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@| 00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.| 00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...| 00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......| 00000240 0e 00 00 00 |....| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 6f bc 33 c8 2d |...........o.3.-| 00000010 5a 50 65 2f 06 1a 45 16 9e 5b ab 97 43 b1 9e 96 |ZPe/..E..[..C...| 00000020 b5 4a fe c3 7c e8 e4 07 ea 00 47 d2 51 23 11 ae |.J..|.....G.Q#..| 00000030 11 a8 79 71 b9 c6 82 17 40 ae c7 fc cd 05 4d 6d |..yq....@.....Mm| 00000040 cb bc f1 ce 30 d0 10 37 4a e6 aa d3 14 fb bc 62 |....0..7J......b| 00000050 eb 6c fa ec e1 e1 dd 63 39 95 0b 87 71 a0 83 ba |.l.....c9...q...| 00000060 bf 25 f8 a9 d3 c4 35 e1 88 23 85 56 c6 f4 0b 10 |.%....5..#.V....| 00000070 d1 70 f8 0a 3d a1 08 17 ce 27 2d 4c a7 c5 b5 0d |.p..=....'-L....| 00000080 f2 43 b7 b9 02 21 7a eb 40 d2 66 14 03 03 00 01 |.C...!z.@.f.....| 00000090 01 16 03 03 00 40 0a 93 47 0b 6e 40 ff cd 09 a5 |.....@..G.n@....| 000000a0 bc a4 c5 a8 c3 1c 0a fb d4 2e 8a 2f 0c f3 d6 e1 |.........../....| 000000b0 de 1f 56 2f 09 61 2d 31 d5 b1 29 6b f2 18 8b f2 |..V/.a-1..)k....| 000000c0 0c 0e 09 5f ec 11 56 af 44 8b e5 2d 09 68 eb c2 |..._..V.D..-.h..| 000000d0 91 4d 04 b2 10 02 |.M....| >>> Flow 4 (server to client) 00000000 15 03 03 00 02 02 14 |.......| ================================================ FILE: scan/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound ================================================ >>> Flow 1 (client to server) 00000000 16 03 01 00 6f 01 00 00 6b 03 03 64 29 6e 67 3d |....o...k..d)ng=| 00000010 5a 13 48 8a ae a5 67 6b 2f 5b 76 d2 c1 df 23 c6 |Z.H...gk/[v...#.| 00000020 f9 52 26 33 ce 0b 03 f6 53 a7 db 00 00 04 00 2f |.R&3....S....../| 00000030 00 ff 02 01 00 00 3d 00 00 00 10 00 0e 00 00 0b |......=.........| 00000040 73 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 |snitest.com... .| 00000050 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................| 00000060 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................| 00000070 0f 00 01 01 |....| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| 00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................| 00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...| 00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| 00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A| 00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...| 00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...| 00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1| 000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.| 000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| 000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite| 000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H| 000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....| 000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..| 00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..| 00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~| 00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....| 00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T| 00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}| 00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f| 00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-| 00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.| 00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.| 00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#| 000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.| 000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.| 000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.| 000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....| 000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n| 000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....| 00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@| 00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.| 00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...| 00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......| 00000240 0e 00 00 00 |....| >>> Flow 3 (client to server) 00000000 16 03 03 00 86 10 00 00 82 00 80 7b 3b b8 73 f0 |...........{;.s.| 00000010 78 2c 75 91 ee 4a ac 6e 9d 08 8e ef dd 52 fb 38 |x,u..J.n.....R.8| 00000020 d7 6f b3 39 8a 8c 3c dc 4b e0 a9 2b 0b de 9a d6 |.o.9..<.K..+....| 00000030 38 72 ae 0f 76 87 4b f6 45 17 f6 fa b2 5a 07 30 |8r..v.K.E....Z.0| 00000040 5b ef e7 40 e0 95 98 bf 8d 8d 5e 7a 6a ea 2d 2e |[..@......^zj.-.| 00000050 9c 99 e4 47 6b 4f 16 32 fb 0d a7 01 36 2e 06 f2 |...GkO.2....6...| 00000060 65 74 b6 ed 07 51 60 7a 98 d6 77 36 f4 c7 f6 b1 |et...Q`z..w6....| 00000070 f1 6a 3e 38 7c 79 5c c6 b4 53 5c 85 fb 0b 2c f9 |.j>8|y\..S\...,.| 00000080 2c 60 97 c8 73 f7 22 ef 52 4c 10 14 03 03 00 01 |,`..s.".RL......| 00000090 01 16 03 03 00 40 4c 73 6e 5e 66 9d 53 2e fa b7 |.....@Lsn^f.S...| 000000a0 90 2d 52 55 13 d2 67 28 aa 1a 6f 62 42 ef 2f 4d |.-RU..g(..obB./M| 000000b0 04 1d ef 64 8f 1a 70 c0 d0 bf 06 72 ee db 3e 43 |...d..p....r..>C| 000000c0 7f ed 37 bb a1 62 0c c5 c8 a9 c0 51 8f 77 95 b3 |..7..b.....Q.w..| 000000d0 72 7e 01 89 c4 32 |r~...2| >>> Flow 4 (server to client) 00000000 15 03 03 00 02 02 14 |.......| ================================================ FILE: scan/crypto/tls/ticket.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/hmac" "crypto/sha256" "crypto/subtle" "errors" "io" ) // sessionState contains the information that is serialized into a session // ticket in order to later resume a connection. type sessionState struct { vers uint16 cipherSuite uint16 masterSecret []byte certificates [][]byte // usedOldKey is true if the ticket from which this session came from // was encrypted with an older key and thus should be refreshed. usedOldKey bool } func (s *sessionState) equal(i interface{}) bool { s1, ok := i.(*sessionState) if !ok { return false } if s.vers != s1.vers || s.cipherSuite != s1.cipherSuite || !bytes.Equal(s.masterSecret, s1.masterSecret) { return false } if len(s.certificates) != len(s1.certificates) { return false } for i := range s.certificates { if !bytes.Equal(s.certificates[i], s1.certificates[i]) { return false } } return true } func (s *sessionState) marshal() []byte { length := 2 + 2 + 2 + len(s.masterSecret) + 2 for _, cert := range s.certificates { length += 4 + len(cert) } ret := make([]byte, length) x := ret x[0] = byte(s.vers >> 8) x[1] = byte(s.vers) x[2] = byte(s.cipherSuite >> 8) x[3] = byte(s.cipherSuite) x[4] = byte(len(s.masterSecret) >> 8) x[5] = byte(len(s.masterSecret)) x = x[6:] copy(x, s.masterSecret) x = x[len(s.masterSecret):] x[0] = byte(len(s.certificates) >> 8) x[1] = byte(len(s.certificates)) x = x[2:] for _, cert := range s.certificates { x[0] = byte(len(cert) >> 24) x[1] = byte(len(cert) >> 16) x[2] = byte(len(cert) >> 8) x[3] = byte(len(cert)) copy(x[4:], cert) x = x[4+len(cert):] } return ret } func (s *sessionState) unmarshal(data []byte) bool { if len(data) < 8 { return false } s.vers = uint16(data[0])<<8 | uint16(data[1]) s.cipherSuite = uint16(data[2])<<8 | uint16(data[3]) masterSecretLen := int(data[4])<<8 | int(data[5]) data = data[6:] if len(data) < masterSecretLen { return false } s.masterSecret = data[:masterSecretLen] data = data[masterSecretLen:] if len(data) < 2 { return false } numCerts := int(data[0])<<8 | int(data[1]) data = data[2:] s.certificates = make([][]byte, numCerts) for i := range s.certificates { if len(data) < 4 { return false } certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3]) data = data[4:] if certLen < 0 { return false } if len(data) < certLen { return false } s.certificates[i] = data[:certLen] data = data[certLen:] } if len(data) > 0 { return false } return true } func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) { serialized := state.marshal() encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size) keyName := encrypted[:ticketKeyNameLen] iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] macBytes := encrypted[len(encrypted)-sha256.Size:] if _, err := io.ReadFull(c.config.rand(), iv); err != nil { return nil, err } key := c.config.ticketKeys()[0] copy(keyName, key.keyName[:]) block, err := aes.NewCipher(key.aesKey[:]) if err != nil { return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) } cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], serialized) mac := hmac.New(sha256.New, key.hmacKey[:]) mac.Write(encrypted[:len(encrypted)-sha256.Size]) mac.Sum(macBytes[:0]) return encrypted, nil } func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) { if c.config.SessionTicketsDisabled || len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size { return nil, false } keyName := encrypted[:ticketKeyNameLen] iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] macBytes := encrypted[len(encrypted)-sha256.Size:] keys := c.config.ticketKeys() keyIndex := -1 for i, candidateKey := range keys { if bytes.Equal(keyName, candidateKey.keyName[:]) { keyIndex = i break } } if keyIndex == -1 { return nil, false } key := &keys[keyIndex] mac := hmac.New(sha256.New, key.hmacKey[:]) mac.Write(encrypted[:len(encrypted)-sha256.Size]) expected := mac.Sum(nil) if subtle.ConstantTimeCompare(macBytes, expected) != 1 { return nil, false } block, err := aes.NewCipher(key.aesKey[:]) if err != nil { return nil, false } ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size] plaintext := ciphertext cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) state := &sessionState{usedOldKey: keyIndex > 0} ok := state.unmarshal(plaintext) return state, ok } ================================================ FILE: scan/crypto/tls/tls.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package tls partially implements TLS 1.2, as specified in RFC 5246. package tls // BUG(agl): The crypto/tls package does not implement countermeasures // against Lucky13 attacks on CBC-mode encryption. See // http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and // https://www.imperialviolet.org/2013/02/04/luckythirteen.html. import ( "crypto" "crypto/ecdsa" "crypto/rsa" "crypto/x509" "encoding/pem" "errors" "fmt" "net" "os" "strings" "time" ) // Server returns a new TLS server side connection // using conn as the underlying transport. // The configuration config must be non-nil and must include // at least one certificate or else set GetCertificate. func Server(conn net.Conn, config *Config) *Conn { return &Conn{conn: conn, config: config} } // Client returns a new TLS client side connection // using conn as the underlying transport. // The config cannot be nil: users must set either ServerName or // InsecureSkipVerify in the config. func Client(conn net.Conn, config *Config) *Conn { return &Conn{conn: conn, config: config, isClient: true} } // A listener implements a network listener (net.Listener) for TLS connections. type listener struct { net.Listener config *Config } // Accept waits for and returns the next incoming TLS connection. // The returned connection c is a *tls.Conn. func (l *listener) Accept() (c net.Conn, err error) { c, err = l.Listener.Accept() if err != nil { return } c = Server(c, l.config) return } // NewListener creates a Listener which accepts connections from an inner // Listener and wraps each connection with Server. // The configuration config must be non-nil and must include // at least one certificate or else set GetCertificate. func NewListener(inner net.Listener, config *Config) net.Listener { l := new(listener) l.Listener = inner l.config = config return l } // Listen creates a TLS listener accepting connections on the // given network address using net.Listen. // The configuration config must be non-nil and must include // at least one certificate or else set GetCertificate. func Listen(network, laddr string, config *Config) (net.Listener, error) { if config == nil || (len(config.Certificates) == 0 && config.GetCertificate == nil) { return nil, errors.New("tls: neither Certificates nor GetCertificate set in Config") } l, err := net.Listen(network, laddr) if err != nil { return nil, err } return NewListener(l, config), nil } type timeoutError struct{} func (timeoutError) Error() string { return "tls: DialWithDialer timed out" } func (timeoutError) Timeout() bool { return true } func (timeoutError) Temporary() bool { return true } // DialWithDialer connects to the given network address using dialer.Dial and // then initiates a TLS handshake, returning the resulting TLS connection. Any // timeout or deadline given in the dialer apply to connection and TLS // handshake as a whole. // // DialWithDialer interprets a nil configuration as equivalent to the zero // configuration; see the documentation of Config for the defaults. func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { // We want the Timeout and Deadline values from dialer to cover the // whole process: TCP connection and TLS handshake. This means that we // also need to start our own timers now. timeout := dialer.Timeout if !dialer.Deadline.IsZero() { deadlineTimeout := dialer.Deadline.Sub(time.Now()) if timeout == 0 || deadlineTimeout < timeout { timeout = deadlineTimeout } } var errChannel chan error if timeout != 0 { errChannel = make(chan error, 2) time.AfterFunc(timeout, func() { errChannel <- timeoutError{} }) } rawConn, err := dialer.Dial(network, addr) if err != nil { return nil, err } colonPos := strings.LastIndex(addr, ":") if colonPos == -1 { colonPos = len(addr) } hostname := addr[:colonPos] if config == nil { config = defaultConfig() } // If no ServerName is set, infer the ServerName // from the hostname we're connecting to. if config.ServerName == "" { // Make a copy to avoid polluting argument or default. c := *config c.ServerName = hostname config = &c } conn := Client(rawConn, config) if timeout == 0 { err = conn.Handshake() } else { go func() { errChannel <- conn.Handshake() }() err = <-errChannel } if err != nil { rawConn.Close() return nil, err } return conn, nil } // Dial connects to the given network address using net.Dial // and then initiates a TLS handshake, returning the resulting // TLS connection. // Dial interprets a nil configuration as equivalent to // the zero configuration; see the documentation of Config // for the defaults. func Dial(network, addr string, config *Config) (*Conn, error) { return DialWithDialer(new(net.Dialer), network, addr, config) } // LoadX509KeyPair reads and parses a public/private key pair from a pair of // files. The files must contain PEM encoded data. On successful return, // Certificate.Leaf will be nil because the parsed form of the certificate is // not retained. func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { certPEMBlock, err := os.ReadFile(certFile) if err != nil { return Certificate{}, err } keyPEMBlock, err := os.ReadFile(keyFile) if err != nil { return Certificate{}, err } return X509KeyPair(certPEMBlock, keyPEMBlock) } // X509KeyPair parses a public/private key pair from a pair of // PEM encoded data. On successful return, Certificate.Leaf will be nil because // the parsed form of the certificate is not retained. func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { fail := func(err error) (Certificate, error) { return Certificate{}, err } var cert Certificate var skippedBlockTypes []string for { var certDERBlock *pem.Block certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) if certDERBlock == nil { break } if certDERBlock.Type == "CERTIFICATE" { cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) } else { skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type) } } if len(cert.Certificate) == 0 { if len(skippedBlockTypes) == 0 { return fail(errors.New("crypto/tls: failed to find any PEM data in certificate input")) } else if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") { return fail(errors.New("crypto/tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched")) } else { return fail(fmt.Errorf("crypto/tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) } } skippedBlockTypes = skippedBlockTypes[:0] var keyDERBlock *pem.Block for { keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) if keyDERBlock == nil { if len(skippedBlockTypes) == 0 { return fail(errors.New("crypto/tls: failed to find any PEM data in key input")) } else if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" { return fail(errors.New("crypto/tls: found a certificate rather than a key in the PEM for the private key")) } else { return fail(fmt.Errorf("crypto/tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) } } if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { break } skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type) } var err error cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) if err != nil { return fail(err) } // We don't need to parse the public key for TLS, but we so do anyway // to check that it looks sane and matches the private key. x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) if err != nil { return fail(err) } switch pub := x509Cert.PublicKey.(type) { case *rsa.PublicKey: priv, ok := cert.PrivateKey.(*rsa.PrivateKey) if !ok { return fail(errors.New("crypto/tls: private key type does not match public key type")) } if pub.N.Cmp(priv.N) != 0 { return fail(errors.New("crypto/tls: private key does not match public key")) } case *ecdsa.PublicKey: priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) if !ok { return fail(errors.New("crypto/tls: private key type does not match public key type")) } if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { return fail(errors.New("crypto/tls: private key does not match public key")) } default: return fail(errors.New("crypto/tls: unknown public key algorithm")) } return cert, nil } // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates // PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. // OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { return key, nil } if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { switch key := key.(type) { case *rsa.PrivateKey, *ecdsa.PrivateKey: return key, nil default: return nil, errors.New("crypto/tls: found unknown private key type in PKCS#8 wrapping") } } if key, err := x509.ParseECPrivateKey(der); err == nil { return key, nil } return nil, errors.New("crypto/tls: failed to parse private key") } ================================================ FILE: scan/crypto/tls/tls_test.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tls import ( "bytes" "errors" "fmt" "io" "net" "strings" "testing" "time" ) var rsaCertPEM = `-----BEGIN CERTIFICATE----- MIIB0zCCAX2gAwIBAgIJAI/M7BYjwB+uMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQwHhcNMTIwOTEyMjE1MjAyWhcNMTUwOTEyMjE1MjAyWjBF MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANLJ hPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wok/4xIA+ui35/MmNa rtNuC+BdZ1tMuVCPFZcCAwEAAaNQME4wHQYDVR0OBBYEFJvKs8RfJaXTH08W+SGv zQyKn0H8MB8GA1UdIwQYMBaAFJvKs8RfJaXTH08W+SGvzQyKn0H8MAwGA1UdEwQF MAMBAf8wDQYJKoZIhvcNAQEFBQADQQBJlffJHybjDGxRMqaRmDhX0+6v02TUKZsW r5QuVbpQhH6u+0UgcW0jp9QwpxoPTLTWGXEWBBBurxFwiCBhkQ+V -----END CERTIFICATE----- ` var rsaKeyPEM = `-----BEGIN RSA PRIVATE KEY----- MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G 6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g== -----END RSA PRIVATE KEY----- ` // keyPEM is the same as rsaKeyPEM, but declares itself as just // "PRIVATE KEY", not "RSA PRIVATE KEY". https://golang.org/issue/4477 var keyPEM = `-----BEGIN PRIVATE KEY----- MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G 6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g== -----END PRIVATE KEY----- ` var ecdsaCertPEM = `-----BEGIN CERTIFICATE----- MIIB/jCCAWICCQDscdUxw16XFDAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0 eSBMdGQwHhcNMTIxMTE0MTI0MDQ4WhcNMTUxMTE0MTI0MDQ4WjBFMQswCQYDVQQG EwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lk Z2l0cyBQdHkgTHRkMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBY9+my9OoeSUR lDQdV/x8LsOuLilthhiS1Tz4aGDHIPwC1mlvnf7fg5lecYpMCrLLhauAc1UJXcgl 01xoLuzgtAEAgv2P/jgytzRSpUYvgLBt1UA0leLYBy6mQQbrNEuqT3INapKIcUv8 XxYP0xMEUksLPq6Ca+CRSqTtrd/23uTnapkwCQYHKoZIzj0EAQOBigAwgYYCQXJo A7Sl2nLVf+4Iu/tAX/IF4MavARKC4PPHK3zfuGfPR3oCCcsAoz3kAzOeijvd0iXb H5jBImIxPL4WxQNiBTexAkF8D1EtpYuWdlVQ80/h/f4pBcGiXPqX5h2PQSQY7hP1 +jwM1FGS4fREIOvlBYr/SzzQRtwrvrzGYxDEDbsC0ZGRnA== -----END CERTIFICATE----- ` var ecdsaKeyPEM = `-----BEGIN EC PARAMETERS----- BgUrgQQAIw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MIHcAgEBBEIBrsoKp0oqcv6/JovJJDoDVSGWdirrkgCWxrprGlzB9o0X8fV675X0 NwuBenXFfeZvVcwluO7/Q9wkYoPd/t3jGImgBwYFK4EEACOhgYkDgYYABAFj36bL 06h5JRGUNB1X/Hwuw64uKW2GGJLVPPhoYMcg/ALWaW+d/t+DmV5xikwKssuFq4Bz VQldyCXTXGgu7OC0AQCC/Y/+ODK3NFKlRi+AsG3VQDSV4tgHLqZBBus0S6pPcg1q kohxS/xfFg/TEwRSSws+roJr4JFKpO2t3/be5OdqmQ== -----END EC PRIVATE KEY----- ` var keyPairTests = []struct { algo string cert string key string }{ {"ECDSA", ecdsaCertPEM, ecdsaKeyPEM}, {"RSA", rsaCertPEM, rsaKeyPEM}, {"RSA-untyped", rsaCertPEM, keyPEM}, // golang.org/issue/4477 } func TestX509KeyPair(t *testing.T) { var pem []byte for _, test := range keyPairTests { pem = []byte(test.cert + test.key) if _, err := X509KeyPair(pem, pem); err != nil { t.Errorf("Failed to load %s cert followed by %s key: %s", test.algo, test.algo, err) } pem = []byte(test.key + test.cert) if _, err := X509KeyPair(pem, pem); err != nil { t.Errorf("Failed to load %s key followed by %s cert: %s", test.algo, test.algo, err) } } } func TestX509KeyPairErrors(t *testing.T) { _, err := X509KeyPair([]byte(rsaKeyPEM), []byte(rsaCertPEM)) if err == nil { t.Fatalf("X509KeyPair didn't return an error when arguments were switched") } if subStr := "been switched"; !strings.Contains(err.Error(), subStr) { t.Fatalf("Expected %q in the error when switching arguments to X509KeyPair, but the error was %q", subStr, err) } _, err = X509KeyPair([]byte(rsaCertPEM), []byte(rsaCertPEM)) if err == nil { t.Fatalf("X509KeyPair didn't return an error when both arguments were certificates") } if subStr := "certificate"; !strings.Contains(err.Error(), subStr) { t.Fatalf("Expected %q in the error when both arguments to X509KeyPair were certificates, but the error was %q", subStr, err) } const nonsensePEM = ` -----BEGIN NONSENSE----- Zm9vZm9vZm9v -----END NONSENSE----- ` _, err = X509KeyPair([]byte(nonsensePEM), []byte(nonsensePEM)) if err == nil { t.Fatalf("X509KeyPair didn't return an error when both arguments were nonsense") } if subStr := "NONSENSE"; !strings.Contains(err.Error(), subStr) { t.Fatalf("Expected %q in the error when both arguments to X509KeyPair were nonsense, but the error was %q", subStr, err) } } func TestX509MixedKeyPair(t *testing.T) { if _, err := X509KeyPair([]byte(rsaCertPEM), []byte(ecdsaKeyPEM)); err == nil { t.Error("Load of RSA certificate succeeded with ECDSA private key") } if _, err := X509KeyPair([]byte(ecdsaCertPEM), []byte(rsaKeyPEM)); err == nil { t.Error("Load of ECDSA certificate succeeded with RSA private key") } } func newLocalListener(t *testing.T) net.Listener { ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { ln, err = net.Listen("tcp6", "[::1]:0") } if err != nil { t.Fatal(err) } return ln } func TestDialTimeout(t *testing.T) { if testing.Short() { t.Skip("skipping in short mode") } listener := newLocalListener(t) addr := listener.Addr().String() defer listener.Close() complete := make(chan bool) defer close(complete) go func() { conn, err := listener.Accept() if err != nil { t.Error(err) return } <-complete conn.Close() }() dialer := &net.Dialer{ Timeout: 10 * time.Millisecond, } var err error if _, err = DialWithDialer(dialer, "tcp", addr, nil); err == nil { t.Fatal("DialWithTimeout completed successfully") } if !strings.Contains(err.Error(), "timed out") { t.Errorf("resulting error not a timeout: %s", err) } } // tests that Conn.Read returns (non-zero, io.EOF) instead of // (non-zero, nil) when a Close (alertCloseNotify) is sitting right // behind the application data in the buffer. func TestConnReadNonzeroAndEOF(t *testing.T) { // This test is racy: it assumes that after a write to a // localhost TCP connection, the peer TCP connection can // immediately read it. Because it's racy, we skip this test // in short mode, and then retry it several times with an // increasing sleep in between our final write (via srv.Close // below) and the following read. if testing.Short() { t.Skip("skipping in short mode") } var err error for delay := time.Millisecond; delay <= 64*time.Millisecond; delay *= 2 { if err = testConnReadNonzeroAndEOF(t, delay); err == nil { return } } t.Error(err) } func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error { ln := newLocalListener(t) defer ln.Close() srvCh := make(chan *Conn, 1) var serr error go func() { sconn, err := ln.Accept() if err != nil { serr = err srvCh <- nil return } serverConfig := *testConfig srv := Server(sconn, &serverConfig) if err := srv.Handshake(); err != nil { serr = fmt.Errorf("handshake: %v", err) srvCh <- nil return } srvCh <- srv }() clientConfig := *testConfig conn, err := Dial("tcp", ln.Addr().String(), &clientConfig) if err != nil { t.Fatal(err) } defer conn.Close() srv := <-srvCh if srv == nil { return serr } buf := make([]byte, 6) srv.Write([]byte("foobar")) n, err := conn.Read(buf) if n != 6 || err != nil || string(buf) != "foobar" { return fmt.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf) } srv.Write([]byte("abcdef")) srv.Close() time.Sleep(delay) n, err = conn.Read(buf) if n != 6 || string(buf) != "abcdef" { return fmt.Errorf("Read = %d, buf= %q; want 6, abcdef", n, buf) } if err != io.EOF { return fmt.Errorf("Second Read error = %v; want io.EOF", err) } return nil } func TestTLSUniqueMatches(t *testing.T) { ln := newLocalListener(t) defer ln.Close() serverTLSUniques := make(chan []byte) go func() { for i := 0; i < 2; i++ { sconn, err := ln.Accept() if err != nil { t.Fatal(err) } serverConfig := *testConfig srv := Server(sconn, &serverConfig) if err := srv.Handshake(); err != nil { t.Fatal(err) } serverTLSUniques <- srv.ConnectionState().TLSUnique } }() clientConfig := *testConfig clientConfig.ClientSessionCache = NewLRUClientSessionCache(1) conn, err := Dial("tcp", ln.Addr().String(), &clientConfig) if err != nil { t.Fatal(err) } if !bytes.Equal(conn.ConnectionState().TLSUnique, <-serverTLSUniques) { t.Error("client and server channel bindings differ") } conn.Close() conn, err = Dial("tcp", ln.Addr().String(), &clientConfig) if err != nil { t.Fatal(err) } defer conn.Close() if !conn.ConnectionState().DidResume { t.Error("second session did not use resumption") } if !bytes.Equal(conn.ConnectionState().TLSUnique, <-serverTLSUniques) { t.Error("client and server channel bindings differ when session resumption is used") } } func TestVerifyHostname(t *testing.T) { c, err := Dial("tcp", "www.google.com:https", nil) if err != nil { t.Fatal(err) } if err := c.VerifyHostname("www.google.com"); err != nil { t.Fatalf("verify www.google.com: %v", err) } if err := c.VerifyHostname("www.yahoo.com"); err == nil { t.Fatalf("verify www.yahoo.com succeeded") } c, err = Dial("tcp", "www.google.com:https", &Config{InsecureSkipVerify: true}) if err != nil { t.Fatal(err) } if err := c.VerifyHostname("www.google.com"); err == nil { t.Fatalf("verify www.google.com succeeded with InsecureSkipVerify=true") } if err := c.VerifyHostname("www.yahoo.com"); err == nil { t.Fatalf("verify www.google.com succeeded with InsecureSkipVerify=true") } } func TestVerifyHostnameResumed(t *testing.T) { config := &Config{ ClientSessionCache: NewLRUClientSessionCache(32), } for i := 0; i < 2; i++ { c, err := Dial("tcp", "www.google.com:https", config) if err != nil { t.Fatalf("Dial #%d: %v", i, err) } cs := c.ConnectionState() if i > 0 && !cs.DidResume { t.Fatalf("Subsequent connection unexpectedly didn't resume") } if cs.VerifiedChains == nil { t.Fatalf("Dial #%d: cs.VerifiedChains == nil", i) } if err := c.VerifyHostname("www.google.com"); err != nil { t.Fatalf("verify www.google.com #%d: %v", i, err) } c.Close() } } func TestConnCloseBreakingWrite(t *testing.T) { ln := newLocalListener(t) defer ln.Close() srvCh := make(chan *Conn, 1) var serr error var sconn net.Conn go func() { var err error sconn, err = ln.Accept() if err != nil { serr = err srvCh <- nil return } serverConfig := *testConfig srv := Server(sconn, &serverConfig) if err := srv.Handshake(); err != nil { serr = fmt.Errorf("handshake: %v", err) srvCh <- nil return } srvCh <- srv }() cconn, err := net.Dial("tcp", ln.Addr().String()) if err != nil { t.Fatal(err) } defer cconn.Close() conn := &changeImplConn{ Conn: cconn, } clientConfig := *testConfig tconn := Client(conn, &clientConfig) if err := tconn.Handshake(); err != nil { t.Fatal(err) } srv := <-srvCh if srv == nil { t.Fatal(serr) } defer sconn.Close() connClosed := make(chan struct{}) conn.closeFunc = func() error { close(connClosed) return nil } inWrite := make(chan bool, 1) var errConnClosed = errors.New("conn closed for test") conn.writeFunc = func(p []byte) (n int, err error) { inWrite <- true <-connClosed return 0, errConnClosed } closeReturned := make(chan bool, 1) go func() { <-inWrite tconn.Close() // test that this doesn't block forever. closeReturned <- true }() _, err = tconn.Write([]byte("foo")) if err != errConnClosed { t.Errorf("Write error = %v; want errConnClosed", err) } <-closeReturned if err := tconn.Close(); err != errClosed { t.Errorf("Close error = %v; want errClosed", err) } } // changeImplConn is a net.Conn which can change its Write and Close // methods. type changeImplConn struct { net.Conn writeFunc func([]byte) (int, error) closeFunc func() error } func (w *changeImplConn) Write(p []byte) (n int, err error) { if w.writeFunc != nil { return w.writeFunc(p) } return w.Conn.Write(p) } func (w *changeImplConn) Close() error { if w.closeFunc != nil { return w.closeFunc() } return w.Conn.Close() } ================================================ FILE: scan/pki.go ================================================ package scan import ( "bytes" "crypto/x509" "fmt" "time" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/revoke" "github.com/cloudflare/cfssl/scan/crypto/tls" ) // PKI contains scanners for the Public Key Infrastructure. var PKI = &Family{ Description: "Scans for the Public Key Infrastructure", Scanners: map[string]*Scanner{ "ChainExpiration": { "Host's chain hasn't expired and won't expire in the next 30 days", chainExpiration, }, "ChainValidation": { "All certificates in host's chain are valid", chainValidation, }, "MultipleCerts": { "Host serves same certificate chain across all IPs", multipleCerts, }, }, } // getChain is a helper function that retreives the host's certificate chain. func getChain(addr string, config *tls.Config) (chain []*x509.Certificate, err error) { var conn *tls.Conn conn, err = tls.DialWithDialer(Dialer, Network, addr, config) if err != nil { return } err = conn.Close() if err != nil { return } chain = conn.ConnectionState().PeerCertificates if len(chain) == 0 { err = fmt.Errorf("%s returned empty certificate chain", addr) } return } type expiration time.Time func (e expiration) String() string { return time.Time(e).Format("Jan 2 15:04:05 2006 MST") } func chainExpiration(addr, hostname string) (grade Grade, output Output, err error) { chain, err := getChain(addr, defaultTLSConfig(hostname)) if err != nil { return } expirationTime := helpers.ExpiryTime(chain) output = expirationTime if time.Now().After(expirationTime) { return } // Warn if cert will expire in the next 30 days if time.Now().Add(time.Hour * 24 * 30).After(expirationTime) { grade = Warning return } grade = Good return } func chainValidation(addr, hostname string) (grade Grade, output Output, err error) { chain, err := getChain(addr, defaultTLSConfig(hostname)) if err != nil { return } var warnings []string for i := 0; i < len(chain)-1; i++ { cert, parent := chain[i], chain[i+1] valid := helpers.ValidExpiry(cert) if !valid { warnings = append(warnings, fmt.Sprintf("Certificate for %s is valid for too long", cert.Subject.CommonName)) } revoked, ok := revoke.VerifyCertificate(cert) if !ok { warnings = append(warnings, fmt.Sprintf("couldn't check if %s is revoked", cert.Subject.CommonName)) } if revoked { err = fmt.Errorf("%s is revoked", cert.Subject.CommonName) return } if !parent.IsCA { err = fmt.Errorf("%s is not a CA", parent.Subject.CommonName) return } if !bytes.Equal(cert.AuthorityKeyId, parent.SubjectKeyId) { err = fmt.Errorf("%s AuthorityKeyId differs from %s SubjectKeyId", cert.Subject.CommonName, parent.Subject.CommonName) return } if err = cert.CheckSignatureFrom(parent); err != nil { return } switch cert.SignatureAlgorithm { case x509.ECDSAWithSHA1: warnings = append(warnings, fmt.Sprintf("%s is signed by ECDSAWithSHA1", cert.Subject.CommonName)) case x509.SHA1WithRSA: warnings = append(warnings, fmt.Sprintf("%s is signed by RSAWithSHA1", cert.Subject.CommonName)) } } if len(warnings) == 0 { grade = Good } else { grade = Warning output = warnings } return } func multipleCerts(addr, hostname string) (grade Grade, output Output, err error) { config := defaultTLSConfig(hostname) firstChain, err := getChain(addr, config) if err != nil { return } grade, _, err = multiscan(addr, func(addrport string) (g Grade, o Output, e error) { g = Good chain, e1 := getChain(addrport, config) if e1 != nil { return } if !chain[0].Equal(firstChain[0]) { e = fmt.Errorf("%s not equal to %s", chain[0].Subject.CommonName, firstChain[0].Subject.CommonName) g = Bad return } return }) return } ================================================ FILE: scan/scan_common.go ================================================ package scan import ( "crypto/x509" "net" "net/http" "regexp" "sync" "time" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/scan/crypto/tls" ) var ( // Network is the default network to use. Network = "tcp" // Dialer is the default dialer to use, with a 1s timeout. Dialer = &net.Dialer{Timeout: time.Second} // Client is the default HTTP Client. Client = &http.Client{Transport: &http.Transport{Dial: Dialer.Dial}} // RootCAs defines the default root certificate authorities to be used for scan. RootCAs *x509.CertPool ) // Grade gives a subjective rating of the host's success in a scan. type Grade int const ( // Bad describes a host with serious misconfiguration or vulnerability. Bad Grade = iota // Warning describes a host with non-ideal configuration that maintains support for Warning clients. Warning // Good describes host performing the expected state-of-the-art. Good // Skipped descibes the "grade" of a scan that has been skipped. Skipped ) // String gives the name of the Grade as a string. func (g Grade) String() string { switch g { case Bad: return "Bad" case Warning: return "Warning" case Good: return "Good" case Skipped: return "Skipped" default: return "Invalid" } } // Output is the result of a scan, to be stored for potential use by later Scanners. type Output interface{} // multiscan scans all DNS addresses returned for the host, returning the lowest grade // and the concatenation of all the output. func multiscan(host string, scan func(string) (Grade, Output, error)) (grade Grade, output Output, err error) { domain, port, _ := net.SplitHostPort(host) var addrs []string addrs, err = net.LookupHost(domain) if err != nil { return } grade = Good out := make(map[string]Output) for _, addr := range addrs { var g Grade var o Output g, o, err = scan(net.JoinHostPort(addr, port)) if err != nil { grade = Bad return } if g < grade { grade = g } out[addr] = o } output = out return } // Scanner describes a type of scan to perform on a host. type Scanner struct { // Description describes the nature of the scan to be performed. Description string `json:"description"` // scan is the function that scans the given host and provides a Grade and Output. scan func(string, string) (Grade, Output, error) } // Scan performs the scan to be performed on the given host and stores its result. func (s *Scanner) Scan(addr, hostname string) (Grade, Output, error) { grade, output, err := s.scan(addr, hostname) if err != nil { log.Debugf("scan: %v", err) return grade, output, err } return grade, output, err } // Family defines a set of related scans meant to be run together in sequence. type Family struct { // Description gives a short description of the scans performed scan/scan_common.goon the host. Description string `json:"description"` // Scanners is a list of scanners that are to be run in sequence. Scanners map[string]*Scanner `json:"scanners"` } // FamilySet contains a set of Families to run Scans from. type FamilySet map[string]*Family // Default contains each scan Family that is defined var Default = FamilySet{ "Connectivity": Connectivity, "TLSHandshake": TLSHandshake, "TLSSession": TLSSession, "PKI": PKI, "Broad": Broad, } // ScannerResult contains the result for a single scan. type ScannerResult struct { Grade string `json:"grade"` Output Output `json:"output,omitempty"` Error string `json:"error,omitempty"` } // FamilyResult contains a scan response for a single Family type FamilyResult map[string]ScannerResult // A Result contains a ScannerResult along with it's scanner and family names. type Result struct { Family, Scanner string ScannerResult } type context struct { sync.WaitGroup addr, hostname string familyRegexp, scannerRegexp *regexp.Regexp resultChan chan *Result } func newContext(addr, hostname string, familyRegexp, scannerRegexp *regexp.Regexp, numFamilies int) *context { ctx := &context{ addr: addr, hostname: hostname, familyRegexp: familyRegexp, scannerRegexp: scannerRegexp, resultChan: make(chan *Result), } ctx.Add(numFamilies) go func() { ctx.Wait() close(ctx.resultChan) }() return ctx } type familyContext struct { sync.WaitGroup ctx *context } func (ctx *context) newfamilyContext(numScanners int) *familyContext { familyCtx := &familyContext{ctx: ctx} familyCtx.Add(numScanners) go func() { familyCtx.Wait() familyCtx.ctx.Done() }() return familyCtx } func (ctx *context) copyResults(timeout time.Duration) map[string]FamilyResult { results := make(map[string]FamilyResult) for { var result *Result select { case <-time.After(timeout): log.Warningf("Scan timed out after %v", timeout) return results case result = <-ctx.resultChan: if result == nil { return results } } if results[result.Family] == nil { results[result.Family] = make(FamilyResult) } results[result.Family][result.Scanner] = result.ScannerResult } } func (familyCtx *familyContext) runScanner(familyName, scannerName string, scanner *Scanner) { if familyCtx.ctx.familyRegexp.MatchString(familyName) && familyCtx.ctx.scannerRegexp.MatchString(scannerName) { grade, output, err := scanner.Scan(familyCtx.ctx.addr, familyCtx.ctx.hostname) result := &Result{ familyName, scannerName, ScannerResult{ Grade: grade.String(), Output: output, }, } if err != nil { result.Error = err.Error() } familyCtx.ctx.resultChan <- result } familyCtx.Done() } // RunScans iterates over AllScans, running each scan that matches the family // and scanner regular expressions concurrently. func (fs FamilySet) RunScans(host, ip, family, scanner string, timeout time.Duration) (map[string]FamilyResult, error) { hostname, port, err := net.SplitHostPort(host) if err != nil { hostname = host port = "443" } var addr string if net.ParseIP(ip) != nil { addr = net.JoinHostPort(ip, port) } else { addr = net.JoinHostPort(hostname, port) } familyRegexp, err := regexp.Compile(family) if err != nil { return nil, err } scannerRegexp, err := regexp.Compile(scanner) if err != nil { return nil, err } ctx := newContext(addr, hostname, familyRegexp, scannerRegexp, len(fs)) for familyName, family := range fs { familyCtx := ctx.newfamilyContext(len(family.Scanners)) for scannerName, scanner := range family.Scanners { go familyCtx.runScanner(familyName, scannerName, scanner) } } return ctx.copyResults(timeout), nil } // LoadRootCAs loads the default root certificate authorities from file. func LoadRootCAs(caBundleFile string) (err error) { if caBundleFile != "" { log.Debugf("Loading scan RootCAs: %s", caBundleFile) RootCAs, err = helpers.LoadPEMCertPool(caBundleFile) } return } func defaultTLSConfig(hostname string) *tls.Config { return &tls.Config{ ServerName: hostname, RootCAs: RootCAs, InsecureSkipVerify: true, } } ================================================ FILE: scan/scan_common_test.go ================================================ package scan import ( "fmt" "testing" ) var TestingScanner = &Scanner{ Description: "Tests common scan functions", scan: func(addr, hostname string) (Grade, Output, error) { switch addr { case "bad.example.com:443": return Bad, "bad.com", nil case "Warning.example.com:443": return Warning, "Warning.com", nil case "good.example.com:443": return Good, "good.com", nil case "skipped.example.com:443/0": return Skipped, "skipped", nil default: return Grade(-1), "invalid", fmt.Errorf("scan: invalid grade") } }, } var TestingFamily = &Family{ Description: "Tests the scan_common", Scanners: map[string]*Scanner{ "TestingScanner": TestingScanner, }, } func TestCommon(t *testing.T) { if TestingFamily.Scanners["TestingScanner"] != TestingScanner { t.FailNow() } var grade Grade var output Output var err error grade, output, err = TestingScanner.Scan("bad.example.com:443", "bad.example.com") if grade != Bad || output.(string) != "bad.com" || err != nil { t.FailNow() } grade, output, err = TestingScanner.Scan("Warning.example.com:443", "Warning.example.com") if grade != Warning || output.(string) != "Warning.com" || err != nil { t.FailNow() } grade, output, err = TestingScanner.Scan("good.example.com:443", "good.example.com") if grade != Good || output.(string) != "good.com" || err != nil { t.FailNow() } grade, output, err = TestingScanner.Scan("skipped.example.com:443/0", "") if grade != Skipped || output.(string) != "skipped" || err != nil { t.FailNow() } _, _, err = TestingScanner.Scan("invalid", "invalid") if err == nil { t.FailNow() } } ================================================ FILE: scan/tls_handshake.go ================================================ package scan import ( "bytes" "errors" "fmt" "net" "strings" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/scan/crypto/tls" ) // Sentinel for failures in sayHello. Should always be caught. var errHelloFailed = errors.New("Handshake failed in sayHello") // TLSHandshake contains scanners testing host cipher suite negotiation var TLSHandshake = &Family{ Description: "Scans for host's SSL/TLS version and cipher suite negotiation", Scanners: map[string]*Scanner{ "CipherSuite": { "Determines host's cipher suites accepted and preferred order", cipherSuiteScan, }, "SigAlgs": { "Determines host's accepted signature and hash algorithms", sigAlgsScan, }, "CertsBySigAlgs": { "Determines host's certificate signature algorithm matching client's accepted signature and hash algorithms", certSigAlgsScan, }, "CertsByCiphers": { "Determines host's certificate signature algorithm matching client's accepted ciphers", certSigAlgsScanByCipher, }, "ECCurves": { "Determines the host's ec curve support for TLS 1.2", ecCurveScan, }, }, } func getCipherIndex(ciphers []uint16, serverCipher uint16) (cipherIndex int, err error) { //func getCipherIndex(ciphers []uint16, serverCipher uint16) (cipherIndex int, err error) { // fmt.Println(serverCipher, ciphers) var cipherID uint16 for cipherIndex, cipherID = range ciphers { if serverCipher == cipherID { return } } err = fmt.Errorf("server negotiated ciphersuite we didn't send: %s", tls.CipherSuites[serverCipher]) return } func getCurveIndex(curves []tls.CurveID, serverCurve tls.CurveID) (curveIndex int, err error) { var curveID tls.CurveID for curveIndex, curveID = range curves { if serverCurve == curveID { return } } err = fmt.Errorf("server negotiated elliptic curve we didn't send: %s", tls.Curves[serverCurve]) return } func sayHello(addr, hostname string, ciphers []uint16, curves []tls.CurveID, vers uint16, sigAlgs []tls.SignatureAndHash) (cipherIndex, curveIndex int, certs [][]byte, err error) { tcpConn, err := net.Dial(Network, addr) if err != nil { return } config := defaultTLSConfig(hostname) config.MinVersion = vers config.MaxVersion = vers if ciphers == nil { ciphers = allCiphersIDs() } config.CipherSuites = ciphers if curves == nil { curves = allCurvesIDs() } config.CurvePreferences = curves if sigAlgs == nil { sigAlgs = tls.AllSignatureAndHashAlgorithms } conn := tls.Client(tcpConn, config) serverCipher, serverCurveType, serverCurve, serverVersion, certificates, err := conn.SayHello(sigAlgs) certs = certificates conn.Close() if err != nil { err = errHelloFailed return } if serverVersion != vers { err = fmt.Errorf("server negotiated protocol version we didn't send: %s", tls.Versions[serverVersion]) return } cipherIndex, err = getCipherIndex(ciphers, serverCipher) if tls.CipherSuites[serverCipher].EllipticCurve { if curves == nil { curves = allCurvesIDs() } if serverCurveType != 3 { err = fmt.Errorf("server negotiated non-named ECDH parameters; we didn't analyze them. Server curve type: %d", serverCurveType) return } curveIndex, err = getCurveIndex(curves, serverCurve) } return } func allCiphersIDs() []uint16 { ciphers := make([]uint16, 0, len(tls.CipherSuites)) for cipherID := range tls.CipherSuites { ciphers = append(ciphers, cipherID) } return ciphers } func allECDHECiphersIDs() []uint16 { var ecdheCiphers = map[uint16]tls.CipherSuite{ 0xC006: {Name: "TLS_ECDHE_ECDSA_WITH_NULL_SHA", ForwardSecret: true, EllipticCurve: true}, 0xC007: {Name: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", ShortName: "ECDHE-ECDSA-RC4-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC008: {Name: "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDHE-ECDSA-DES-CBC3-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC009: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", ShortName: "ECDHE-ECDSA-AES128-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC00A: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", ShortName: "ECDHE-ECDSA-AES256-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC010: {Name: "TLS_ECDHE_RSA_WITH_NULL_SHA", ForwardSecret: true, EllipticCurve: true}, 0xC011: {Name: "TLS_ECDHE_RSA_WITH_RC4_128_SHA", ShortName: "ECDHE-RSA-RC4-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC012: {Name: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDHE-RSA-DES-CBC3-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC013: {Name: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", ShortName: "ECDHE-RSA-AES128-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC014: {Name: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", ShortName: "ECDHE-RSA-AES256-SHA", ForwardSecret: true, EllipticCurve: true}, 0xC023: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDHE-ECDSA-AES128-SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC024: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDHE-ECDSA-AES256-SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC027: {Name: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDHE-RSA-AES128-SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC028: {Name: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDHE-RSA-AES256-SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC02B: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDHE-ECDSA-AES128-GCM-SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC02C: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDHE-ECDSA-AES256-GCM-SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC02F: {Name: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDHE-RSA-AES128-GCM-SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC030: {Name: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDHE-RSA-AES256-GCM-SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC048: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC049: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC04C: {Name: "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC04D: {Name: "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC05D: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC060: {Name: "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC061: {Name: "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC072: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC073: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC076: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC077: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC086: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC087: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC08A: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xC08B: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true}, 0xC08C: {Name: "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", EllipticCurve: true}, 0xC0AC: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM", ForwardSecret: true, EllipticCurve: true}, 0xC0AD: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM", ForwardSecret: true, EllipticCurve: true}, 0xC0AE: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", ForwardSecret: true, EllipticCurve: true}, 0xC0AF: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", ForwardSecret: true, EllipticCurve: true}, // Non-IANA standardized cipher suites: // ChaCha20, Poly1305 cipher suites are defined in // https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 0xCC13: {Name: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", ForwardSecret: true, EllipticCurve: true}, 0xCC14: {Name: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", ForwardSecret: true, EllipticCurve: true}, } ciphers := make([]uint16, 0, len(ecdheCiphers)) for cipherID := range ecdheCiphers { ciphers = append(ciphers, cipherID) } return ciphers } func allCurvesIDs() []tls.CurveID { curves := make([]tls.CurveID, 0, len(tls.Curves)) for curveID := range tls.Curves { // No unassigned or explicit curves in the scan, per http://tools.ietf.org/html/rfc4492#section-5.4 if curveID == 0 || curveID == 65281 || curveID == 65282 { continue } else { curves = append(curves, curveID) } } return curves } type cipherDatum struct { versionID uint16 curves []tls.CurveID } // cipherVersions contains lists of host's supported cipher suites based on SSL/TLS Version. // If a cipher suite uses ECC, also contains a list of supported curves by SSL/TLS Version. type cipherVersions struct { cipherID uint16 data []cipherDatum } type cipherVersionList []cipherVersions func (cvList cipherVersionList) String() string { cvStrings := make([]string, len(cvList)) for i, c := range cvList { versStrings := make([]string, len(c.data)) for j, d := range c.data { curveStrings := make([]string, len(d.curves)) for k, c := range d.curves { curveStrings[k] = tls.Curves[c] } versStrings[j] = fmt.Sprintf("%s: [ %s ]", tls.Versions[d.versionID], strings.Join(curveStrings, ",")) } cvStrings[i] = fmt.Sprintf("%s\t%s", tls.CipherSuites[c.cipherID], strings.Join(versStrings, ",")) } return strings.Join(cvStrings, "\n") } func (cvList cipherVersionList) MarshalJSON() ([]byte, error) { b := new(bytes.Buffer) cvStrs := make([]string, len(cvList)) for i, cv := range cvList { versStrings := make([]string, len(cv.data)) for j, d := range cv.data { curveStrings := make([]string, len(d.curves)) if len(d.curves) > 0 { for k, c := range d.curves { curveStrings[k] = fmt.Sprintf("\"%s\"", tls.Curves[c]) } versStrings[j] = fmt.Sprintf("{\"%s\":[%s]}", tls.Versions[d.versionID], strings.Join(curveStrings, ",")) } else { versStrings[j] = fmt.Sprintf("\"%s\"", tls.Versions[d.versionID]) } } cvStrs[i] = fmt.Sprintf("{\"%s\":[%s]}", tls.CipherSuites[cv.cipherID].String(), strings.Join(versStrings, ",")) } fmt.Fprintf(b, "[%s]", strings.Join(cvStrs, ",")) return b.Bytes(), nil } func doCurveScan(addr, hostname string, vers, cipherID uint16, ciphers []uint16) (supportedCurves []tls.CurveID, err error) { allCurves := allCurvesIDs() curves := make([]tls.CurveID, len(allCurves)) copy(curves, allCurves) for len(curves) > 0 { var curveIndex int _, curveIndex, _, err = sayHello(addr, hostname, []uint16{cipherID}, curves, vers, nil) if err != nil { // This case is expected, because eventually we ask only for curves the server doesn't support if err == errHelloFailed { err = nil break } return } curveID := curves[curveIndex] supportedCurves = append(supportedCurves, curveID) curves = append(curves[:curveIndex], curves[curveIndex+1:]...) } return } // cipherSuiteScan returns, by TLS Version, the sort list of cipher suites // supported by the host func cipherSuiteScan(addr, hostname string) (grade Grade, output Output, err error) { var cvList cipherVersionList allCiphers := allCiphersIDs() var vers uint16 for vers = tls.VersionTLS12; vers >= tls.VersionSSL30; vers-- { ciphers := make([]uint16, len(allCiphers)) copy(ciphers, allCiphers) for len(ciphers) > 0 { var cipherIndex int cipherIndex, _, _, err = sayHello(addr, hostname, ciphers, nil, vers, nil) if err != nil { if err == errHelloFailed { err = nil break } return } if vers == tls.VersionSSL30 { grade = Warning } cipherID := ciphers[cipherIndex] // If this is an EC cipher suite, do a second scan for curve support var supportedCurves []tls.CurveID if tls.CipherSuites[cipherID].EllipticCurve { supportedCurves, err = doCurveScan(addr, hostname, vers, cipherID, ciphers) if len(supportedCurves) == 0 { err = errors.New("couldn't negotiate any curves") } } for i, c := range cvList { if cipherID == c.cipherID { cvList[i].data = append(c.data, cipherDatum{vers, supportedCurves}) goto exists } } cvList = append(cvList, cipherVersions{cipherID, []cipherDatum{{vers, supportedCurves}}}) exists: ciphers = append(ciphers[:cipherIndex], ciphers[cipherIndex+1:]...) } } if len(cvList) == 0 { err = errors.New("couldn't negotiate any cipher suites") return } if grade != Warning { grade = Good } output = cvList return } // sigAlgsScan returns the accepted signature and hash algorithms of the host func sigAlgsScan(addr, hostname string) (grade Grade, output Output, err error) { var supportedSigAlgs []tls.SignatureAndHash for _, sigAlg := range tls.AllSignatureAndHashAlgorithms { _, _, _, e := sayHello(addr, hostname, nil, nil, tls.VersionTLS12, []tls.SignatureAndHash{sigAlg}) if e == nil { supportedSigAlgs = append(supportedSigAlgs, sigAlg) } } if len(supportedSigAlgs) > 0 { grade = Good output = supportedSigAlgs } else { err = errors.New("no SigAlgs supported") } return } // certSigAlgScan returns the server certificate with various sigature and hash algorithms in the ClientHello func certSigAlgsScan(addr, hostname string) (grade Grade, output Output, err error) { var certSigAlgs = make(map[string]string) for _, sigAlg := range tls.AllSignatureAndHashAlgorithms { _, _, derCerts, e := sayHello(addr, hostname, nil, nil, tls.VersionTLS12, []tls.SignatureAndHash{sigAlg}) if e == nil { if len(derCerts) == 0 { return Bad, nil, errors.New("no certs returned") } certs, _, err := helpers.ParseCertificatesDER(derCerts[0], "") if err != nil { return Bad, nil, err } certSigAlgs[sigAlg.String()] = helpers.SignatureString(certs[0].SignatureAlgorithm) //certSigAlgs = append(certSigAlgs, certs[0].SignatureAlgorithm) } } if len(certSigAlgs) > 0 { grade = Good output = certSigAlgs } else { err = errors.New("no SigAlgs supported") } return } // certSigAlgScan returns the server certificate with various ciphers in the ClientHello func certSigAlgsScanByCipher(addr, hostname string) (grade Grade, output Output, err error) { var certSigAlgs = make(map[string]string) for cipherID := range tls.CipherSuites { _, _, derCerts, e := sayHello(addr, hostname, []uint16{cipherID}, nil, tls.VersionTLS12, []tls.SignatureAndHash{}) if e == nil { if len(derCerts) == 0 { return Bad, nil, errors.New("no certs returned") } certs, _, err := helpers.ParseCertificatesDER(derCerts[0], "") if err != nil { return Bad, nil, err } certSigAlgs[tls.CipherSuites[cipherID].Name] = helpers.SignatureString(certs[0].SignatureAlgorithm) //certSigAlgs = append(certSigAlgs, certs[0].SignatureAlgorithm) } } if len(certSigAlgs) > 0 { grade = Good output = certSigAlgs } else { err = errors.New("no cipher supported") } return } // ecCurveScan returns the elliptic curves supported by the host. func ecCurveScan(addr, hostname string) (grade Grade, output Output, err error) { allCurves := allCurvesIDs() curves := make([]tls.CurveID, len(allCurves)) copy(curves, allCurves) var supportedCurves []string for len(curves) > 0 { var curveIndex int _, curveIndex, _, err = sayHello(addr, hostname, allECDHECiphersIDs(), curves, tls.VersionTLS12, nil) if err != nil { // This case is expected, because eventually we ask only for curves the server doesn't support if err == errHelloFailed { err = nil break } return } curveID := curves[curveIndex] supportedCurves = append(supportedCurves, tls.Curves[curveID]) curves = append(curves[:curveIndex], curves[curveIndex+1:]...) } output = supportedCurves grade = Good return } ================================================ FILE: scan/tls_session.go ================================================ package scan import "github.com/cloudflare/cfssl/scan/crypto/tls" // TLSSession contains tests of host TLS Session Resumption via // Session Tickets and Session IDs var TLSSession = &Family{ Description: "Scans host's implementation of TLS session resumption using session tickets/session IDs", Scanners: map[string]*Scanner{ "SessionResume": { "Host is able to resume sessions across all addresses", sessionResumeScan, }, }, } // SessionResumeScan tests that host is able to resume sessions across all addresses. func sessionResumeScan(addr, hostname string) (grade Grade, output Output, err error) { config := defaultTLSConfig(hostname) config.ClientSessionCache = tls.NewLRUClientSessionCache(1) conn, err := tls.DialWithDialer(Dialer, Network, addr, config) if err != nil { return } if err = conn.Close(); err != nil { return } return multiscan(addr, func(addrport string) (g Grade, o Output, e error) { var conn *tls.Conn if conn, e = tls.DialWithDialer(Dialer, Network, addrport, config); e != nil { return } conn.Close() if o = conn.ConnectionState().DidResume; o.(bool) { g = Good } return }) } ================================================ FILE: selfsign/selfsign.go ================================================ // Package selfsign implements certificate selfsigning. This is very // dangerous and should never be used in production. package selfsign import ( "crypto" "crypto/rand" "crypto/sha1" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/pem" "errors" "math" "math/big" "time" "github.com/cloudflare/cfssl/config" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/signer" ) const threeMonths = 2190 * time.Hour // parseCertificateRequest takes an incoming certificate request and // builds a certificate template from it. func parseCertificateRequest(priv crypto.Signer, csrBytes []byte) (template *x509.Certificate, err error) { csr, err := x509.ParseCertificateRequest(csrBytes) if err != nil { err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err) return } if err = csr.CheckSignature(); err != nil { err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err) return } template = &x509.Certificate{ Subject: csr.Subject, PublicKeyAlgorithm: csr.PublicKeyAlgorithm, PublicKey: csr.PublicKey, SignatureAlgorithm: signer.DefaultSigAlgo(priv), DNSNames: csr.DNSNames, EmailAddresses: csr.EmailAddresses, IPAddresses: csr.IPAddresses, URIs: csr.URIs, ExtraExtensions: csr.Extensions, } return } type subjectPublicKeyInfo struct { Algorithm pkix.AlgorithmIdentifier SubjectPublicKey asn1.BitString } // Sign creates a new self-signed certificate. func Sign(priv crypto.Signer, csrPEM []byte, profile *config.SigningProfile) ([]byte, error) { if profile == nil { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("no profile for self-signing")) } p, _ := pem.Decode(csrPEM) if p == nil || p.Type != "CERTIFICATE REQUEST" { return nil, cferr.New(cferr.CSRError, cferr.BadRequest) } template, err := parseCertificateRequest(priv, p.Bytes) if err != nil { return nil, err } pub := template.PublicKey encodedpub, err := x509.MarshalPKIXPublicKey(pub) if err != nil { return nil, err } var subPKI subjectPublicKeyInfo _, err = asn1.Unmarshal(encodedpub, &subPKI) if err != nil { return nil, err } pubhash := sha1.New() pubhash.Write(subPKI.SubjectPublicKey.Bytes) var ( eku []x509.ExtKeyUsage ku x509.KeyUsage expiry time.Duration crlURL, ocspURL string ) // The third value returned from Usages is a list of unknown key usages. // This should be used when validating the profile at load, and isn't used // here. ku, eku, _ = profile.Usages() expiry = profile.Expiry if ku == 0 && len(eku) == 0 { err = cferr.New(cferr.PolicyError, cferr.NoKeyUsages) return nil, err } if expiry == 0 { expiry = threeMonths } now := time.Now() serialNumber, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) if err != nil { err = cferr.Wrap(cferr.CSRError, cferr.Unknown, err) return nil, err } template.SerialNumber = serialNumber template.NotBefore = now.Add(-5 * time.Minute).UTC() template.NotAfter = now.Add(expiry).UTC() template.KeyUsage = ku template.ExtKeyUsage = eku template.BasicConstraintsValid = true template.IsCA = profile.CAConstraint.IsCA template.SubjectKeyId = pubhash.Sum(nil) if ocspURL != "" { template.OCSPServer = []string{ocspURL} } if crlURL != "" { template.CRLDistributionPoints = []string{crlURL} } if len(profile.IssuerURL) != 0 { template.IssuingCertificateURL = profile.IssuerURL } cert, err := x509.CreateCertificate(rand.Reader, template, template, pub, priv) if err != nil { return nil, err } cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert}) return cert, nil } ================================================ FILE: selfsign/selfsign_test.go ================================================ package selfsign import ( "crypto/x509" "encoding/pem" "encoding/asn1" "net" "net/url" "os" "reflect" "testing" "time" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/helpers" ) const ( keyFile = "testdata/localhost.key" csrFile = "testdata/localhost.csr" csr2File = "testdata/sans.csr" extCsrFile = "testdata/extension.csr" ) func TestDefaultSign(t *testing.T) { csrBytes, err := os.ReadFile(csrFile) if err != nil { t.Fatal(err) } keyBytes, err := os.ReadFile(keyFile) if err != nil { t.Fatal(err) } priv, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { t.Fatal(err) } profile := config.DefaultConfig() profile.Expiry = 10 * time.Hour _, err = Sign(priv, csrBytes, profile) if err != nil { t.Fatal(err) } } func TestSANs(t *testing.T) { t.Skip("broken relating to https://github.com/cloudflare/cfssl/issues/1230") csrBytes, err := os.ReadFile(csr2File) if err != nil { t.Fatal(err) } keyBytes, err := os.ReadFile(keyFile) if err != nil { t.Fatal(err) } priv, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { t.Fatal(err) } profile := config.DefaultConfig() profile.Expiry = 10 * time.Hour certPEM, err := Sign(priv, csrBytes, profile) if err != nil { t.Fatal(err) } p, _ := pem.Decode(certPEM) if p == nil || p.Type != "CERTIFICATE" { // this seems unlikely t.Fatalf("failed creating certificate") } cert, err := x509.ParseCertificate(p.Bytes) if err != nil { t.Fatal(err) } expectedEmailAddresses := []string{"jdoe@example.com"} if !reflect.DeepEqual(cert.EmailAddresses, expectedEmailAddresses) { t.Errorf("cert should have contained EmailAddresses %#v but had %#v", expectedEmailAddresses, cert.EmailAddresses) } expectedDNSNames := []string{"cloudflare.com", "www.cloudflare.com"} if !reflect.DeepEqual(cert.DNSNames, expectedDNSNames) { t.Errorf("cert should have contained DNSNames %#v but had %#v", expectedDNSNames, cert.DNSNames) } expectedIPAddresses := []net.IP{{0xc0, 0xa8, 0x0, 0x1}} if !reflect.DeepEqual(cert.IPAddresses, expectedIPAddresses) { t.Errorf("cert should have contained IPAddresses %#v but had %#v", expectedIPAddresses, cert.IPAddresses) } expectedURIs := []*url.URL{{Scheme: "https", Host: "www.cloudflare.com"}} if !reflect.DeepEqual(cert.URIs, expectedURIs) { t.Errorf("cert should have contained URIs %#v but had %#v", expectedURIs, cert.URIs) } } func TestExtensions(t *testing.T){ csrBytes, err := os.ReadFile(extCsrFile) if err != nil { t.Fatal(err) } keyBytes, err := os.ReadFile(keyFile) if err != nil { t.Fatal(err) } priv, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { t.Fatal(err) } profile := config.DefaultConfig() profile.Expiry = 10 * time.Hour certData, err := Sign(priv, csrBytes, profile) if err != nil { t.Fatal(err) } cert, err := helpers.ParseCertificatePEM(certData) if err != nil { t.Fatal(err) } // Testing for 1.3.6.1.4.1.311.84.1.1=ASN1:UTF8String:example1 extFound := false sampleCustomOid := asn1.ObjectIdentifier{1,3,6,1,4,1,311,84,1,1} sampleValue := "example1" for _, e := range cert.Extensions { if(e.Id.Equal(sampleCustomOid) ){ var extValue string _, err = asn1.Unmarshal(e.Value, &extValue) if err != nil { t.Fatal(err) } if(extValue == sampleValue){ extFound = true } } } if !extFound { t.Errorf("Custom x509 extension not found in certificate.") } } ================================================ FILE: selfsign/testdata/extension.csr ================================================ Certificate Request: Data: Version: 1 (0x0) Subject: CN = example.com, C = ER, ST = Everywhere, L = Somewhere Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (3072 bit) Modulus: 00:c2:9f:3d:fb:4e:2d:06:d6:6e:b2:21:2e:66:cf: 72:41:91:81:32:27:09:1f:16:b4:1c:5a:4e:7a:91: 58:e3:dc:d8:7a:f8:44:95:dc:94:4d:cf:49:d7:d6: 5c:56:b7:ec:40:2f:a9:fd:2f:e5:26:9d:b4:5d:ea: 8d:07:1d:34:c4:73:3c:7b:a3:3c:1e:f3:62:24:71: aa:7c:ac:9a:41:33:11:78:87:50:8b:a7:01:17:e2: cc:4e:bd:68:dd:09:2e:25:04:db:81:f8:01:87:15: a2:e4:be:03:48:23:1f:e6:ef:f1:0f:69:96:7e:dc: 7d:f0:d1:7e:43:b2:3a:5e:69:94:ce:94:b9:cd:75: ff:0d:b1:6c:9f:75:3a:e5:c2:17:f4:cc:23:f9:44: 45:bf:ca:e8:68:c0:52:c2:45:9f:85:aa:89:1a:50: 20:99:fa:e8:b1:1d:3e:7d:a2:ff:67:33:a5:42:38: 28:3d:c5:65:70:9d:2f:67:5f:ab:5b:04:d0:77:65: ae:9d:78:01:0d:54:cf:38:e6:0e:b0:d9:e8:ec:26: bf:5c:2b:96:5b:51:90:01:3a:6f:ae:f8:77:cc:88: 39:18:f7:6d:81:93:2d:b4:6d:6d:5b:6c:62:d9:58: d6:ba:74:cc:17:2f:45:77:d1:aa:4b:d1:6b:d2:f1: 97:89:b6:7d:26:9e:68:b5:07:74:b9:7e:3c:06:4e: 4b:1e:cb:4c:88:02:bc:f9:27:8f:2e:7b:ff:dc:af: 83:90:71:0e:71:3c:02:79:ea:4d:e5:42:23:a0:7d: 31:3b:45:78:ff:1f:6a:e5:50:82:eb:0a:48:7d:59: c9:40:3d:33:3d:fa:99:88:71:27:05:90:c7:50:4f: e6:8b:99:c9:03:33:30:8c:8d:d6:58:4b:ed:18:7e: 5c:46:2a:d9:23:8e:56:0e:45:7d:5d:ee:ef:b8:7f: d3:f5:f6:c3:9e:ec:26:3c:23:18:56:2e:d2:3a:5b: 8d:d3:9f:6b:3d:f4:f7:51:ec:93 Exponent: 65537 (0x10001) Attributes: Requested Extensions: X509v3 Subject Key Identifier: 14:1E:80:FB:13:4C:2E:A3:99:BE:0C:DE:6F:FE:76:1A:E5:55:6D:2D X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: critical TLS Web Server Authentication, TLS Web Client Authentication 1.3.6.1.4.1.311.84.1.1: ..example1 X509v3 Subject Alternative Name: DNS:example.com Signature Algorithm: sha256WithRSAEncryption a6:28:f3:bf:2a:eb:1b:85:24:57:10:f2:0e:ac:4c:af:0f:fb: b0:e0:19:2c:9c:a8:b4:a9:29:f0:10:68:66:67:dd:fd:db:be: 3d:33:fb:50:4a:ad:74:0a:8d:9f:4e:6e:8b:22:e8:1f:9b:d4: ad:d4:9e:20:aa:e0:60:01:81:c5:1c:36:6c:e2:df:53:0e:34: 42:d3:77:6e:fa:8b:45:1f:13:cc:56:6a:c0:65:8b:d1:33:b8: 01:3d:06:99:41:16:e9:5b:11:6a:a3:0b:b3:e3:df:cb:5d:34: 13:dd:59:c2:69:be:c9:73:f5:92:19:52:ba:33:30:bd:38:c5: 34:3a:ed:b3:cc:5f:2a:83:e2:6d:d9:e0:7c:b7:b3:6a:26:52: 4c:dd:fd:6a:50:42:35:4b:60:aa:4c:66:dc:fe:08:ca:ca:2d: 2e:aa:78:81:af:84:8f:da:db:fe:54:e6:f1:94:0e:59:36:de: c8:4a:bf:ea:ce:e1:83:11:07:b3:ca:f5:98:eb:d8:ff:0c:f0: 1d:97:ec:b2:dd:f5:01:4e:29:42:45:ba:45:ee:13:77:50:92: 7e:17:01:d0:b5:03:29:01:f3:72:d6:28:d1:ad:86:a5:9e:c8: 4e:43:c9:09:de:45:eb:1b:c4:ed:10:45:2c:74:6e:66:8a:81: 8d:4d:54:72:7d:42:60:32:57:6f:ea:b3:76:96:58:68:3a:45: bb:78:3d:60:9d:4d:8a:27:f4:31:fd:df:7b:97:08:3b:9d:84: 14:47:6a:31:99:94:f5:0e:66:bd:62:5c:59:80:6d:a9:5e:dc: a0:a5:0f:be:ec:e3:d5:36:07:b8:39:80:2e:26:aa:18:fe:bf: 77:ac:85:d9:4d:08:08:e2:9f:d5:57:88:45:54:b0:a6:e8:3e: 90:41:19:c3:a7:b6:df:eb:5a:d6:0d:4d:92:3b:94:cf:16:45: cb:67:52:f4:5d:4e:e7:18:cb:ba:9f:a4:50:21:3d:ab:38:48: 05:9f:bf:1c:72:b5 -----BEGIN CERTIFICATE REQUEST----- MIIEKTCCApECAQAwTDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xCzAJBgNVBAYTAkVS MRMwEQYDVQQIDApFdmVyeXdoZXJlMRIwEAYDVQQHDAlTb21ld2hlcmUwggGiMA0G CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDCnz37Ti0G1m6yIS5mz3JBkYEyJwkf FrQcWk56kVjj3Nh6+ESV3JRNz0nX1lxWt+xAL6n9L+UmnbRd6o0HHTTEczx7ozwe 82Ikcap8rJpBMxF4h1CLpwEX4sxOvWjdCS4lBNuB+AGHFaLkvgNIIx/m7/EPaZZ+ 3H3w0X5DsjpeaZTOlLnNdf8NsWyfdTrlwhf0zCP5REW/yuhowFLCRZ+FqokaUCCZ +uixHT59ov9nM6VCOCg9xWVwnS9nX6tbBNB3Za6deAENVM845g6w2ejsJr9cK5Zb UZABOm+u+HfMiDkY922Bky20bW1bbGLZWNa6dMwXL0V30apL0WvS8ZeJtn0mnmi1 B3S5fjwGTksey0yIArz5J48ue//cr4OQcQ5xPAJ56k3lQiOgfTE7RXj/H2rlUILr Ckh9WclAPTM9+pmIcScFkMdQT+aLmckDMzCMjdZYS+0YflxGKtkjjlYORX1d7u+4 f9P19sOe7CY8IxhWLtI6W43Tn2s99PdR7JMCAwEAAaCBlzCBlAYJKoZIhvcNAQkO MYGGMIGDMB0GA1UdDgQWBBQUHoD7E0wuo5m+DN5v/nYa5VVtLTAOBgNVHQ8BAf8E BAMCBaAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBgGCisGAQQB gjdUAQEECgwIZXhhbXBsZTEwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20wDQYJKoZI hvcNAQELBQADggGBAKYo878q6xuFJFcQ8g6sTK8P+7DgGSycqLSpKfAQaGZn3f3b vj0z+1BKrXQKjZ9Obosi6B+b1K3UniCq4GABgcUcNmzi31MONELTd276i0UfE8xW asBli9EzuAE9BplBFulbEWqjC7Pj38tdNBPdWcJpvslz9ZIZUrozML04xTQ67bPM XyqD4m3Z4Hy3s2omUkzd/WpQQjVLYKpMZtz+CMrKLS6qeIGvhI/a2/5U5vGUDlk2 3shKv+rO4YMRB7PK9Zjr2P8M8B2X7LLd9QFOKUJFukXuE3dQkn4XAdC1AykB83LW KNGthqWeyE5DyQneResbxO0QRSx0bmaKgY1NVHJ9QmAyV2/qs3aWWGg6Rbt4PWCd TYon9DH933uXCDudhBRHajGZlPUOZr1iXFmAbale3KClD77s49U2B7g5gC4mqhj+ v3eshdlNCAjin9VXiEVUsKboPpBBGcOntt/rWtYNTZI7lM8WRctnUvRdTucYy7qf pFAhPas4SAWfvxxytQ== -----END CERTIFICATE REQUEST----- ================================================ FILE: selfsign/testdata/localhost.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIEDDCCAnQCAQAwgZkxFjAUBgNVBAYTDUdyZWF0IENvdW50cnkxGDAWBgNVBAgT D0hpc3RvcmljIHJlZ2lvbjEXMBUGA1UEBxMOQmVhdXRpZnVsIENpdHkxGDAWBgNV BAoTD0F3ZXNvbWUgY29tcGFueTESMBAGA1UECxMJQ29vbCB0ZWFtMR4wHAYDVQQD ExVsb2NhbGhvc3QgY2VydGlmaWNhdGUwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw ggGKAoIBgQDCnz37Ti0G1m6yIS5mz3JBkYEyJwkfFrQcWk56kVjj3Nh6+ESV3JRN z0nX1lxWt+xAL6n9L+UmnbRd6o0HHTTEczx7ozwe82Ikcap8rJpBMxF4h1CLpwEX 4sxOvWjdCS4lBNuB+AGHFaLkvgNIIx/m7/EPaZZ+3H3w0X5DsjpeaZTOlLnNdf8N sWyfdTrlwhf0zCP5REW/yuhowFLCRZ+FqokaUCCZ+uixHT59ov9nM6VCOCg9xWVw nS9nX6tbBNB3Za6deAENVM845g6w2ejsJr9cK5ZbUZABOm+u+HfMiDkY922Bky20 bW1bbGLZWNa6dMwXL0V30apL0WvS8ZeJtn0mnmi1B3S5fjwGTksey0yIArz5J48u e//cr4OQcQ5xPAJ56k3lQiOgfTE7RXj/H2rlUILrCkh9WclAPTM9+pmIcScFkMdQ T+aLmckDMzCMjdZYS+0YflxGKtkjjlYORX1d7u+4f9P19sOe7CY8IxhWLtI6W43T n2s99PdR7JMCAwEAAaAtMCsGCSqGSIb3DQEJDjEeMBwwGgYDVR0RBBMwEYIJbG9j YWxob3N0hwR/AAABMA0GCSqGSIb3DQEBDAUAA4IBgQDCHOWlwBHcwttNkEzpmbjz j4clXiyWXSx1VOD2BvPTTfzPXzRkBDzjeK9wXGptT5dN0r3xY142RFP40UGTG5fn j3XPdZ8OMg1z9ncR4xGjqQnbH2+LlOXX+2KcoVocsUohizFJCiraQBaQVppNcZMI GZld72P7WDwWIrOQOa7VfG3Y94Rpn2UeDuHK4y1LJs/J7n0363mkG2apU9FgRahg 4X5B4WmMUV+E76553LxoxtXpxQ+eK/973hIh94qYU0xUf/bME5Nmk+0WU7SYgd7o tvPv0QlIu0Kqbx8y1miYM8Ypl0GDp7QcORalAYjKupSS2W+cTqtUNsA5Dk1IW/tq gzL7eTH9yX7j+EIhrypYPLbo01E0pFWZ6gB5smqOGgnVhXZDxdJOr9Bh4Q2o7UB8 XOzdlo6RZTd3BSOdtMLr/UwrwgMRNAnyRBzTxBmmmgxYPxNTFCdMEMw5OavBn5qG CISYsiLvNXk0PYLoLDAT21blLSYsNwGxKrU0XF35uMI= -----END CERTIFICATE REQUEST----- ================================================ FILE: selfsign/testdata/localhost.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIIG5AIBAAKCAYEAwp89+04tBtZusiEuZs9yQZGBMicJHxa0HFpOepFY49zYevhE ldyUTc9J19ZcVrfsQC+p/S/lJp20XeqNBx00xHM8e6M8HvNiJHGqfKyaQTMReIdQ i6cBF+LMTr1o3QkuJQTbgfgBhxWi5L4DSCMf5u/xD2mWftx98NF+Q7I6XmmUzpS5 zXX/DbFsn3U65cIX9Mwj+URFv8roaMBSwkWfhaqJGlAgmfrosR0+faL/ZzOlQjgo PcVlcJ0vZ1+rWwTQd2WunXgBDVTPOOYOsNno7Ca/XCuWW1GQATpvrvh3zIg5GPdt gZMttG1tW2xi2VjWunTMFy9Fd9GqS9Fr0vGXibZ9Jp5otQd0uX48Bk5LHstMiAK8 +SePLnv/3K+DkHEOcTwCeepN5UIjoH0xO0V4/x9q5VCC6wpIfVnJQD0zPfqZiHEn BZDHUE/mi5nJAzMwjI3WWEvtGH5cRirZI45WDkV9Xe7vuH/T9fbDnuwmPCMYVi7S OluN059rPfT3UeyTAgMBAAECggGBAKYtwIfPRaUb/aL9sBg7M20HJ9DCAgjYouu+ tFn1t3fA/9toF2/6y2rw/zVbpLarDv/zcutsNPbXG8ZBWy/i4UaIuvE6/T/UQ02o /JC99GyNhXJr3/uOmuFhV2A4XMy3ZP5Y+nEsaWmFsPQtxrGWxEu1PxkQ6F7kOGkj B/QXv70T2+rUlR35jdGMWJqDR8odA8WTdXgGsqPERtQCu+eD+WTxq2WbW2r/EicB OHWgcwIU2BwFxV6RKT+SB4L17mOmZDXjnHzyepdgArW6BUFIXXZ+uaVD2Qj/SQ0Q KSlvXldC67HaqhqAovBimbd/dDs1j/kxSVdwROa8JBLj4KzfLrwNZV6sELAdbIKh Iebcfw3qfkUl197OjE/Xn9zN9wXy82nkzYEr28IhfBGd82R3ZTzfEmpZwU75cAcz e/N777BrkV67jc9QoIUab1dk/Q6PRNCmjZpw1ZnBtAcXpw1VxKbZiQIBHzGqBRrm TASMRBOt1Y/ygAXn+3GZGfRtWFBHwQKBwQDEN34UAG7LL9diRCTgvH0xENcZvPkE AqRagI0gPHIJ9JqQ6qfzMOrzTH6LTklKAnYicA5X7tWoSdnIwnr5ckWQcPS1nbm1 FaSFZO5J2rRjaa5BMZA2fprBotBpS0CpCm4d8krPeOADZKm3ibkMS45RKBE0dVhf YoHoDjZvBDQo+VXWlpJWQEhdqMwft0PGT+leFoJsEq+xCt5LSPnqRKO4DGvWES9Y XmthQ++XDPelTa2vq6gHf/8vmvq7c5DV1CECgcEA/etdNQamTRf63RDbOifLAqXh JCURsSx7OqVhOv2gNyU2Nrxz2GZ9i3bKtVcy6jUJFq3goF6BVizZubRNf8gyvsX4 9lwrGVWG4PQx+MqANVxWjznlYI1MucvjSIbaHne08vu6uMwNI7agVBeei7G5N0D+ auJU9HgiS6AOI8QQdcKkKWXPyqM47EfA71pyOiVhwub6i5ta3OvAEqB6u/jIV952 CT/e0la/NY9DqR4h9V8xr7GTexILt5AYhUpGg2ozAoHAPgbAvzfnzilAb9rUwYo0 FQeax5MaMK9ZHxbWBeO1tPnyxm63SsQi8Wgz9Ht55YBjsb00e42PUtSNmM4Jq8L4 xJFAegzzAJBn4pcmUIhnT6m/oPI3AVMCPsXmFfLo7MbUSnkmNvGh9tCiadeKfJ2B zpvY3Hlfxz9Pi3i6sltk1bMD9ILCnatSdPEAHeKD9TObtNduwRUjHtctsCTQg8LQ 8kRS7meeTNQEI8oi+d/qhQHKLucXhc9rbrQSIKGGnmGhAoHAfJojAwJgWTSLRjAf ZEpitMnx0WrfY7IQRpchP3F2TZlVIUcZEfg5Y1bH4nUH5yZfb2Gj+Q5nKYKY1ShF X48+V5+OrFZOUABIT9uFKjE0+Pp2/5HJnbe5DvOedNi38HuNsC8XUdfQGtZjluCA TMzJtvON5aVrSwwoyDOivKpZ6W+6XxY3AZlXNZuAcfRQWXg+oQX3rMpvrDmD56AY mmVa6sOf6KoPDejDq+TBrxu6Tk6Ic08QsDQKy+lKHx5zu8lBAoHBALFWc3xQT/ie b5TOouhon67WUQMZ3eCZebpZ20jbmIyud2lkxnrlWQCeece1J1KMViXwS0S/pp4i WRSFd1v5WykdcN8J4xE5deIfmmNqQNI/OJ0i8vY5kmNkwo/CXnQowN42aIODmkXI npZ0cKnJNL5LwZlElvF8QKGdIxxpIiNf9dhYYEV2LJYYugHHef8ExgBDNaiw+FbK 8c17UoxEFDejNLJbnlAlitevVz3Qye2RPP6gVqHK3J0fmDWNMDYXew== -----END RSA PRIVATE KEY----- ================================================ FILE: selfsign/testdata/sans.csr ================================================ Certificate Request: Data: Version: 0 (0x0) Subject: CN=irrelevant Subject Public Key Info: Public Key Algorithm: id-ecPublicKey EC Public Key: pub: 04:9f:e6:ab:90:2a:dc:22:c8:d3:f5:30:9c:0d:8a: 35:9c:6e:e3:ab:1b:e4:4c:35:3f:a6:de:c6:96:a0: 25:2c:80:df:95:cd:f7:8e:49:f3:d9:8a:c8:9e:3f: 3b:64:c8:37:51:30:ed:97:6f:83:27:cc:59:39:12: a5:e5:75:5e:5b ASN1 OID: prime256v1 Attributes: Requested Extensions: X509v3 Subject Alternative Name: DNS:cloudflare.com, DNS:www.cloudflare.com, email:jdoe@example.com, IP Address:192.168.0.1, URI:https://www.cloudflare.com Signature Algorithm: ecdsa-with-SHA256 30:46:02:21:00:c8:98:66:6c:e6:98:83:89:72:b7:c0:64:f7: 5d:b7:ed:5a:0c:e2:90:16:a4:70:92:ac:d2:26:c5:4c:6a:7e: 1a:02:21:00:e2:3a:2a:7c:3b:7c:c3:f4:7b:01:89:3d:67:63: c8:84:ea:52:0d:29:b1:8a:22:ef:26:ed:6f:a6:3d:d5:0e:2e -----BEGIN CERTIFICATE REQUEST----- MIIBRTCB6wIBADAVMRMwEQYDVQQDEwppcnJlbGV2YW50MFkwEwYHKoZIzj0CAQYI KoZIzj0DAQcDQgAEn+arkCrcIsjT9TCcDYo1nG7jqxvkTDU/pt7GlqAlLIDflc33 jknz2YrInj87ZMg3UTDtl2+DJ8xZORKl5XVeW6B0MHIGCSqGSIb3DQEJDjFlMGMw YQYDVR0RBFowWIIOY2xvdWRmbGFyZS5jb22CEnd3dy5jbG91ZGZsYXJlLmNvbYEQ amRvZUBleGFtcGxlLmNvbYcEwKgAAYYaaHR0cHM6Ly93d3cuY2xvdWRmbGFyZS5j b20wCgYIKoZIzj0EAwIDSQAwRgIhAMiYZmzmmIOJcrfAZPddt+1aDOKQFqRwkqzS JsVMan4aAiEA4joqfDt8w/R7AYk9Z2PIhOpSDSmxiiLvJu1vpj3VDi4= -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/local.go ================================================ // Package local implements certificate signature functionality for CFSSL. package local import ( "bytes" "context" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "database/sql" "encoding/asn1" "encoding/hex" "encoding/pem" "errors" "fmt" "io" "math/big" "net" "net/http" "net/mail" "net/url" "os" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/config" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/info" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer" ct "github.com/google/certificate-transparency-go" "github.com/google/certificate-transparency-go/client" "github.com/google/certificate-transparency-go/jsonclient" zx509 "github.com/zmap/zcrypto/x509" "github.com/zmap/zlint/v3" "github.com/zmap/zlint/v3/lint" ) // Signer contains a signer that uses the standard library to // support both ECDSA and RSA CA keys. type Signer struct { ca *x509.Certificate priv crypto.Signer // lintPriv is generated randomly when pre-issuance linting is configured and // used to sign TBSCertificates for linting. lintPriv crypto.Signer policy *config.Signing sigAlgo x509.SignatureAlgorithm dbAccessor certdb.Accessor } // NewSigner creates a new Signer directly from a // private key and certificate, with optional policy. func NewSigner(priv crypto.Signer, cert *x509.Certificate, sigAlgo x509.SignatureAlgorithm, policy *config.Signing) (*Signer, error) { if policy == nil { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig()} } if !policy.Valid() { return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } var lintPriv crypto.Signer // If there is at least one profile (including the default) that configures // pre-issuance linting then generate the one-off lintPriv key. for _, profile := range policy.Profiles { if profile.LintErrLevel > 0 || policy.Default.LintErrLevel > 0 { // In the future there may be demand for specifying the type of signer used // for pre-issuance linting in configuration. For now we assume that signing // with a randomly generated P-256 ECDSA private key is acceptable for all cases // where linting is requested. k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, cferr.New(cferr.PrivateKeyError, cferr.GenerationFailed) } lintPriv = k break } } return &Signer{ ca: cert, priv: priv, lintPriv: lintPriv, sigAlgo: sigAlgo, policy: policy, }, nil } // NewSignerFromFile generates a new local signer from a caFile // and a caKey file, both PEM encoded. func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signer, error) { log.Debug("Loading CA: ", caFile) ca, err := helpers.ReadBytes(caFile) if err != nil { return nil, err } log.Debug("Loading CA key: ", caKeyFile) cakey, err := helpers.ReadBytes(caKeyFile) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err) } parsedCa, err := helpers.ParseCertificatePEM(ca) if err != nil { return nil, err } strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD") password := []byte(strPassword) if strPassword == "" { password = nil } priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password) if err != nil { log.Debugf("Malformed private key %v", err) return nil, err } return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy) } // LintError is an error type returned when pre-issuance linting is configured // in a signing profile and a TBS Certificate fails linting. It wraps the // concrete zlint LintResults so that callers can further inspect the cause of // the failing lints. type LintError struct { ErrorResults map[string]lint.LintResult } func (e *LintError) Error() string { return fmt.Sprintf("pre-issuance linting found %d error results", len(e.ErrorResults)) } // lint performs pre-issuance linting of a given TBS certificate template when // the provided errLevel is > 0. Note that the template is provided by-value and // not by-reference. This is important as the lint function needs to mutate the // template's signature algorithm to match the lintPriv. func (s *Signer) lint(template x509.Certificate, errLevel lint.LintStatus, lintRegistry lint.Registry) error { // Always return nil when linting is disabled (lint.Reserved == 0). if errLevel == lint.Reserved { return nil } // without a lintPriv key to use to sign the tbsCertificate we can't lint it. if s.lintPriv == nil { return cferr.New(cferr.PrivateKeyError, cferr.Unavailable) } // The template's SignatureAlgorithm must be mutated to match the lintPriv or // x509.CreateCertificate will error because of the mismatch. At the time of // writing s.lintPriv is always an ECDSA private key. This switch will need to // be expanded if the lint key type is made configurable. switch s.lintPriv.(type) { case *ecdsa.PrivateKey: template.SignatureAlgorithm = x509.ECDSAWithSHA256 default: return cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } prelintBytes, err := x509.CreateCertificate(rand.Reader, &template, s.ca, template.PublicKey, s.lintPriv) if err != nil { return cferr.Wrap(cferr.CertificateError, cferr.Unknown, err) } prelintCert, err := zx509.ParseCertificate(prelintBytes) if err != nil { return cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } errorResults := map[string]lint.LintResult{} results := zlint.LintCertificateEx(prelintCert, lintRegistry) for name, res := range results.Results { if res.Status > errLevel { errorResults[name] = *res } } if len(errorResults) > 0 { return &LintError{ ErrorResults: errorResults, } } return nil } func (s *Signer) sign(template *x509.Certificate, lintErrLevel lint.LintStatus, lintRegistry lint.Registry) (cert []byte, err error) { var initRoot bool if s.ca == nil { if !template.IsCA { err = cferr.New(cferr.PolicyError, cferr.InvalidRequest) return } template.DNSNames = nil template.EmailAddresses = nil template.URIs = nil s.ca = template initRoot = true } if err := s.lint(*template, lintErrLevel, lintRegistry); err != nil { return nil, err } derBytes, err := x509.CreateCertificate(rand.Reader, template, s.ca, template.PublicKey, s.priv) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err) } if initRoot { s.ca, err = x509.ParseCertificate(derBytes) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } } cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) log.Infof("signed certificate with serial number %d", template.SerialNumber) return } // replaceSliceIfEmpty replaces the contents of replaced with newContents if // the slice referenced by replaced is empty func replaceSliceIfEmpty(replaced, newContents *[]string) { if len(*replaced) == 0 { *replaced = *newContents } } // PopulateSubjectFromCSR has functionality similar to Name, except // it fills the fields of the resulting pkix.Name with req's if the // subject's corresponding fields are empty func PopulateSubjectFromCSR(s *signer.Subject, req pkix.Name) pkix.Name { // if no subject, use req if s == nil { return req } name := s.Name() if name.CommonName == "" { name.CommonName = req.CommonName } replaceSliceIfEmpty(&name.Country, &req.Country) replaceSliceIfEmpty(&name.Province, &req.Province) replaceSliceIfEmpty(&name.Locality, &req.Locality) replaceSliceIfEmpty(&name.Organization, &req.Organization) replaceSliceIfEmpty(&name.OrganizationalUnit, &req.OrganizationalUnit) if name.SerialNumber == "" { name.SerialNumber = req.SerialNumber } return name } // OverrideHosts fills template's IPAddresses, EmailAddresses, DNSNames, and URIs with the // content of hosts, if it is not nil. func OverrideHosts(template *x509.Certificate, hosts []string) { if hosts != nil { template.IPAddresses = []net.IP{} template.EmailAddresses = []string{} template.DNSNames = []string{} template.URIs = []*url.URL{} } for i := range hosts { if ip := net.ParseIP(hosts[i]); ip != nil { template.IPAddresses = append(template.IPAddresses, ip) } else if email, err := mail.ParseAddress(hosts[i]); err == nil && email != nil { template.EmailAddresses = append(template.EmailAddresses, email.Address) } else if uri, err := url.ParseRequestURI(hosts[i]); err == nil && uri != nil { template.URIs = append(template.URIs, uri) } else { template.DNSNames = append(template.DNSNames, hosts[i]) } } } // Sign signs a new certificate based on the PEM-encoded client // certificate or certificate request with the signing profile, // specified by profileName. func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) { profile, err := signer.Profile(s, req.Profile) if err != nil { return } block, _ := pem.Decode([]byte(req.Request)) if block == nil { return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed) } if block.Type != "NEW CERTIFICATE REQUEST" && block.Type != "CERTIFICATE REQUEST" { return nil, cferr.Wrap(cferr.CSRError, cferr.BadRequest, errors.New("not a csr")) } csrTemplate, err := signer.ParseCertificateRequest(s, profile, block.Bytes) if err != nil { return nil, err } // Copy out only the fields from the CSR authorized by policy. safeTemplate := x509.Certificate{} // If the profile contains no explicit whitelist, assume that all fields // should be copied from the CSR. if profile.CSRWhitelist == nil { safeTemplate = *csrTemplate } else { if profile.CSRWhitelist.Subject { safeTemplate.Subject = csrTemplate.Subject } if profile.CSRWhitelist.PublicKeyAlgorithm { safeTemplate.PublicKeyAlgorithm = csrTemplate.PublicKeyAlgorithm } if profile.CSRWhitelist.PublicKey { safeTemplate.PublicKey = csrTemplate.PublicKey } if profile.CSRWhitelist.SignatureAlgorithm { safeTemplate.SignatureAlgorithm = csrTemplate.SignatureAlgorithm } if profile.CSRWhitelist.DNSNames { safeTemplate.DNSNames = csrTemplate.DNSNames } if profile.CSRWhitelist.IPAddresses { safeTemplate.IPAddresses = csrTemplate.IPAddresses } if profile.CSRWhitelist.EmailAddresses { safeTemplate.EmailAddresses = csrTemplate.EmailAddresses } if profile.CSRWhitelist.URIs { safeTemplate.URIs = csrTemplate.URIs } } if req.CRLOverride != "" { safeTemplate.CRLDistributionPoints = []string{req.CRLOverride} } if safeTemplate.IsCA { if !profile.CAConstraint.IsCA { log.Error("local signer policy disallows issuing CA certificate") return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest) } if s.ca != nil && s.ca.MaxPathLen > 0 { if safeTemplate.MaxPathLen >= s.ca.MaxPathLen { log.Error("local signer certificate disallows CA MaxPathLen extending") // do not sign a cert with pathlen > current return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest) } } else if s.ca != nil && s.ca.MaxPathLen == 0 && s.ca.MaxPathLenZero { log.Error("local signer certificate disallows issuing CA certificate") // signer has pathlen of 0, do not sign more intermediate CAs return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest) } } OverrideHosts(&safeTemplate, req.Hosts) safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject) // If there is a whitelist, ensure that both the Common Name and SAN DNSNames match if profile.NameWhitelist != nil { if safeTemplate.Subject.CommonName != "" { if profile.NameWhitelist.Find([]byte(safeTemplate.Subject.CommonName)) == nil { return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist) } } for _, name := range safeTemplate.DNSNames { if profile.NameWhitelist.Find([]byte(name)) == nil { return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist) } } for _, name := range safeTemplate.EmailAddresses { if profile.NameWhitelist.Find([]byte(name)) == nil { return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist) } } for _, name := range safeTemplate.URIs { if profile.NameWhitelist.Find([]byte(name.String())) == nil { return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist) } } } if profile.ClientProvidesSerialNumbers { if req.Serial == nil { return nil, cferr.New(cferr.CertificateError, cferr.MissingSerial) } safeTemplate.SerialNumber = req.Serial } else { // RFC 5280 4.1.2.2: // Certificate users MUST be able to handle serialNumber // values up to 20 octets. Conforming CAs MUST NOT use // serialNumber values longer than 20 octets. // // If CFSSL is providing the serial numbers, it makes // sense to use the max supported size. serialNumber := make([]byte, 20) _, err = io.ReadFull(rand.Reader, serialNumber) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err) } // SetBytes interprets buf as the bytes of a big-endian // unsigned integer. The leading byte should be masked // off to ensure it isn't negative. serialNumber[0] &= 0x7F safeTemplate.SerialNumber = new(big.Int).SetBytes(serialNumber) } if len(req.Extensions) > 0 { for _, ext := range req.Extensions { oid := asn1.ObjectIdentifier(ext.ID) if !profile.ExtensionWhitelist[oid.String()] { return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest) } rawValue, err := hex.DecodeString(ext.Value) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.InvalidRequest, err) } safeTemplate.ExtraExtensions = append(safeTemplate.ExtraExtensions, pkix.Extension{ Id: oid, Critical: ext.Critical, Value: rawValue, }) } } var distPoints = safeTemplate.CRLDistributionPoints err = signer.FillTemplate(&safeTemplate, s.policy.Default, profile, req.NotBefore, req.NotAfter) if err != nil { return nil, err } if distPoints != nil && len(distPoints) > 0 { safeTemplate.CRLDistributionPoints = distPoints } var certTBS = safeTemplate if len(profile.CTLogServers) > 0 || req.ReturnPrecert { // Add a poison extension which prevents validation var poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}} var poisonedPreCert = certTBS poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension) cert, err = s.sign(&poisonedPreCert, profile.LintErrLevel, profile.LintRegistry) if err != nil { return } if req.ReturnPrecert { return cert, nil } derCert, _ := pem.Decode(cert) prechain := []ct.ASN1Cert{{Data: derCert.Bytes}, {Data: s.ca.Raw}} var sctList []ct.SignedCertificateTimestamp for _, server := range profile.CTLogServers { log.Infof("submitting poisoned precertificate to %s", server) ctclient, err := client.New(server, nil, jsonclient.Options{}) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.PrecertSubmissionFailed, err) } var resp *ct.SignedCertificateTimestamp ctx := context.Background() resp, err = ctclient.AddPreChain(ctx, prechain) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.PrecertSubmissionFailed, err) } sctList = append(sctList, *resp) } var serializedSCTList []byte serializedSCTList, err = helpers.SerializeSCTList(sctList) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err) } // Serialize again as an octet string before embedding serializedSCTList, err = asn1.Marshal(serializedSCTList) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err) } var SCTListExtension = pkix.Extension{Id: signer.SCTListOID, Critical: false, Value: serializedSCTList} certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension) } var signedCert []byte signedCert, err = s.sign(&certTBS, profile.LintErrLevel, profile.LintRegistry) if err != nil { return nil, err } // Get the AKI from signedCert. This is required to support Go 1.9+. // In prior versions of Go, x509.CreateCertificate updated the // AuthorityKeyId of certTBS. parsedCert, _ := helpers.ParseCertificatePEM(signedCert) if s.dbAccessor != nil { now := time.Now() var certRecord = certdb.CertificateRecord{ Serial: certTBS.SerialNumber.String(), // this relies on the specific behavior of x509.CreateCertificate // which sets the AuthorityKeyId from the signer's SubjectKeyId AKI: hex.EncodeToString(parsedCert.AuthorityKeyId), CALabel: req.Label, Status: "good", Expiry: certTBS.NotAfter, PEM: string(signedCert), IssuedAt: &now, NotBefore: &certTBS.NotBefore, CommonName: sql.NullString{String: certTBS.Subject.CommonName, Valid: true}, } if err := certRecord.SetMetadata(req.Metadata); err != nil { return nil, err } if err := certRecord.SetSANs(certTBS.DNSNames); err != nil { return nil, err } if err := s.dbAccessor.InsertCertificate(certRecord); err != nil { return nil, err } log.Debug("saved certificate with serial number ", certTBS.SerialNumber) } return signedCert, nil } // SignFromPrecert creates and signs a certificate from an existing precertificate // that was previously signed by Signer.ca and inserts the provided SCTs into the // new certificate. The resulting certificate will be a exact copy of the precert // except for the removal of the poison extension and the addition of the SCT list // extension. SignFromPrecert does not verify that the contents of the certificate // still match the signing profile of the signer, it only requires that the precert // was previously signed by the Signers CA. Similarly, any linting configured // by the profile used to sign the precert will not be re-applied to the final // cert and must be done separately by the caller. func (s *Signer) SignFromPrecert(precert *x509.Certificate, scts []ct.SignedCertificateTimestamp) ([]byte, error) { // Verify certificate was signed by s.ca if err := precert.CheckSignatureFrom(s.ca); err != nil { return nil, err } // Verify certificate is a precert isPrecert := false poisonIndex := 0 for i, ext := range precert.Extensions { if ext.Id.Equal(signer.CTPoisonOID) { if !ext.Critical { return nil, cferr.New(cferr.CTError, cferr.PrecertInvalidPoison) } // Check extension contains ASN.1 NULL if bytes.Compare(ext.Value, []byte{0x05, 0x00}) != 0 { return nil, cferr.New(cferr.CTError, cferr.PrecertInvalidPoison) } isPrecert = true poisonIndex = i break } } if !isPrecert { return nil, cferr.New(cferr.CTError, cferr.PrecertMissingPoison) } // Serialize SCTs into list format and create extension serializedList, err := helpers.SerializeSCTList(scts) if err != nil { return nil, err } // Serialize again as an octet string before embedding serializedList, err = asn1.Marshal(serializedList) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err) } sctExt := pkix.Extension{Id: signer.SCTListOID, Critical: false, Value: serializedList} // Create the new tbsCert from precert. Do explicit copies of any slices so that we don't // use memory that may be altered by us or the caller at a later stage. tbsCert := x509.Certificate{ SignatureAlgorithm: precert.SignatureAlgorithm, PublicKeyAlgorithm: precert.PublicKeyAlgorithm, PublicKey: precert.PublicKey, Version: precert.Version, SerialNumber: precert.SerialNumber, Issuer: precert.Issuer, Subject: precert.Subject, NotBefore: precert.NotBefore, NotAfter: precert.NotAfter, KeyUsage: precert.KeyUsage, BasicConstraintsValid: precert.BasicConstraintsValid, IsCA: precert.IsCA, MaxPathLen: precert.MaxPathLen, MaxPathLenZero: precert.MaxPathLenZero, PermittedDNSDomainsCritical: precert.PermittedDNSDomainsCritical, } if len(precert.Extensions) > 0 { tbsCert.ExtraExtensions = make([]pkix.Extension, len(precert.Extensions)) copy(tbsCert.ExtraExtensions, precert.Extensions) } // Remove the poison extension from ExtraExtensions tbsCert.ExtraExtensions = append(tbsCert.ExtraExtensions[:poisonIndex], tbsCert.ExtraExtensions[poisonIndex+1:]...) // Insert the SCT list extension tbsCert.ExtraExtensions = append(tbsCert.ExtraExtensions, sctExt) // Sign the tbsCert. Linting is always disabled because there is no way for // this API to know the correct lint settings to use because there is no // reference to the signing profile of the precert available. return s.sign(&tbsCert, 0, nil) } // Info return a populated info.Resp struct or an error. func (s *Signer) Info(req info.Req) (resp *info.Resp, err error) { cert, err := s.Certificate(req.Label, req.Profile) if err != nil { return } profile, err := signer.Profile(s, req.Profile) if err != nil { return } resp = new(info.Resp) if cert.Raw != nil { resp.Certificate = string(bytes.TrimSpace(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}))) } resp.Usage = profile.Usage resp.ExpiryString = profile.ExpiryString return } // SigAlgo returns the RSA signer's signature algorithm. func (s *Signer) SigAlgo() x509.SignatureAlgorithm { return s.sigAlgo } // Certificate returns the signer's certificate. func (s *Signer) Certificate(label, profile string) (*x509.Certificate, error) { cert := *s.ca return &cert, nil } // SetPolicy sets the signer's signature policy. func (s *Signer) SetPolicy(policy *config.Signing) { s.policy = policy } // SetDBAccessor sets the signers' cert db accessor func (s *Signer) SetDBAccessor(dba certdb.Accessor) { s.dbAccessor = dba } // GetDBAccessor returns the signers' cert db accessor func (s *Signer) GetDBAccessor() certdb.Accessor { return s.dbAccessor } // SetReqModifier does nothing for local func (s *Signer) SetReqModifier(func(*http.Request, []byte)) { // noop } // Policy returns the signer's policy. func (s *Signer) Policy() *config.Signing { return s.policy } ================================================ FILE: signer/local/local_test.go ================================================ package local import ( "bytes" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/hex" "encoding/pem" "errors" "math/big" "net" "net/http" "net/http/httptest" "net/url" "os" "reflect" "regexp" "sort" "strings" "testing" "time" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/signer" ct "github.com/google/certificate-transparency-go" "github.com/zmap/zlint/v3/lint" ) const ( fullSubjectCSR = "testdata/test.csr" testCSR = "testdata/ecdsa256.csr" testSANCSR = "testdata/san_domain.csr" testCaFile = "testdata/ca.pem" testCaKeyFile = "testdata/ca_key.pem" testECDSACaFile = "testdata/ecdsa256_ca.pem" testECDSACaKeyFile = "testdata/ecdsa256_ca_key.pem" ) var expiry = 1 * time.Minute // Start a signer with the testing RSA CA cert and key. func newTestSigner(t *testing.T) (s *Signer) { s, err := NewSignerFromFile(testCaFile, testCaKeyFile, nil) if err != nil { t.Fatal(err) } return } func TestNewSignerFromFilePolicy(t *testing.T) { var CAConfig = &config.Config{ Signing: &config.Signing{ Profiles: map[string]*config.SigningProfile{ "signature": { Usage: []string{"digital signature"}, Expiry: expiry, }, }, Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "43800h", Expiry: expiry, CAConstraint: config.CAConstraint{IsCA: true}, }, }, } signer, err := NewSignerFromFile(testCaFile, testCaKeyFile, CAConfig.Signing) if err != nil { t.Fatal(err) } if signer.lintPriv != nil { t.Error("expected signer with LintErrLevel == 0 to have lintPriv == nil") } } func TestNewSignerFromFileInvalidPolicy(t *testing.T) { var invalidConfig = &config.Config{ Signing: &config.Signing{ Profiles: map[string]*config.SigningProfile{ "invalid": { Usage: []string{"wiretapping"}, Expiry: expiry, }, "empty": {}, }, Default: &config.SigningProfile{ Usage: []string{"digital signature"}, Expiry: expiry, }, }, } _, err := NewSignerFromFile(testCaFile, testCaKeyFile, invalidConfig.Signing) if err == nil { t.Fatal(err) } if !strings.Contains(err.Error(), `"code":5200`) { t.Fatal(err) } } func TestNewSignerFromFileNoUsageInPolicy(t *testing.T) { var invalidConfig = &config.Config{ Signing: &config.Signing{ Profiles: map[string]*config.SigningProfile{ "invalid": { Usage: []string{}, Expiry: expiry, }, "empty": {}, }, Default: &config.SigningProfile{ Usage: []string{"digital signature"}, Expiry: expiry, }, }, } _, err := NewSignerFromFile(testCaFile, testCaKeyFile, invalidConfig.Signing) if err == nil { t.Fatal("expect InvalidPolicy error") } if !strings.Contains(err.Error(), `"code":5200`) { t.Fatal(err) } } func TestNewSignerFromFileEdgeCases(t *testing.T) { res, err := NewSignerFromFile("nil", "nil", nil) if res != nil && err == nil { t.Fatal("Incorrect inputs failed to produce correct results") } res, err = NewSignerFromFile(testCaFile, "nil", nil) if res != nil && err == nil { t.Fatal("Incorrect inputs failed to produce correct results") } res, err = NewSignerFromFile("../../helpers/testdata/messedupcert.pem", "local.go", nil) if res != nil && err == nil { t.Fatal("Incorrect inputs failed to produce correct results") } res, err = NewSignerFromFile("../../helpers/testdata/cert.pem", "../../helpers/testdata/messed_up_priv_key.pem", nil) if res != nil && err == nil { t.Fatal("Incorrect inputs failed to produce correct results") } } func TestNewSignerFromFilePolicyLinting(t *testing.T) { // CAConfig is a config that has an explicit "signature" profile that enables // pre-issuance linting. var CAConfig = &config.Config{ Signing: &config.Signing{ Profiles: map[string]*config.SigningProfile{ "signature": { Usage: []string{"digital signature"}, Expiry: expiry, LintErrLevel: 3, }, }, Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "43800h", Expiry: expiry, CAConstraint: config.CAConstraint{IsCA: true}, }, }, } signer, err := NewSignerFromFile(testCaFile, testCaKeyFile, CAConfig.Signing) if err != nil { t.Fatal(err) } // A CAConfig with a signing profile that sets LintErrLevel > 0 should have // a lintPriv key generated. if signer.lintPriv == nil { t.Error("expected signer with profile LintErrLevel > 0 to have lintPriv != nil") } // Reconfigure caConfig so that the explicit "signature" profile doesn't // enable pre-issuance linting but the default profile does. CAConfig.Signing.Profiles["signature"].LintErrLevel = 0 CAConfig.Signing.Default.LintErrLevel = 3 signer, err = NewSignerFromFile(testCaFile, testCaKeyFile, CAConfig.Signing) if err != nil { t.Fatal(err) } // A CAConfig with a default profile that sets LintErrLevel > 0 should have // a lintPriv key generated. if signer.lintPriv == nil { t.Error("expected signer with default profile LintErrLevel > 0 to have lintPriv != nil") } } func TestSign(t *testing.T) { s, err := NewSignerFromFile("testdata/ca.pem", "testdata/ca_key.pem", nil) if err != nil { t.Fatal("Failed to produce signer") } // test the empty request _, err = s.Sign(signer.SignRequest{}) if err == nil { t.Fatalf("Empty request failed to produce an error") } // not a csr certPem, err := os.ReadFile("../../helpers/testdata/cert.pem") if err != nil { t.Fatal(err) } // csr with ip as hostname pem, err := os.ReadFile("testdata/ip.csr") if err != nil { t.Fatal(err) } // improper request validReq := signer.SignRequest{Hosts: signer.SplitHosts(testHostName), Request: string(certPem)} _, err = s.Sign(validReq) if err == nil { t.Fatal("A bad case failed to raise an error") } validReq = signer.SignRequest{Hosts: signer.SplitHosts("128.84.126.213"), Request: string(pem)} _, err = s.Sign(validReq) if err != nil { t.Fatal("A bad case failed to raise an error") } pem, err = os.ReadFile("testdata/ex.csr") validReq = signer.SignRequest{ Request: string(pem), Hosts: []string{"example.com"}, } s.Sign(validReq) if err != nil { t.Fatal("Failed to sign") } } func TestCertificate(t *testing.T) { s, err := NewSignerFromFile("testdata/ca.pem", "testdata/ca_key.pem", nil) if err != nil { t.Fatal(err) } c, err := s.Certificate("", "") if !reflect.DeepEqual(*c, *s.ca) || err != nil { t.Fatal("Certificate() producing incorrect results") } } func TestPolicy(t *testing.T) { s, err := NewSignerFromFile("testdata/ca.pem", "testdata/ca_key.pem", nil) if err != nil { t.Fatal(err) } sgn := config.Signing{} s.SetPolicy(&sgn) if s.Policy() != &sgn { t.Fatal("Policy is malfunctioning") } } func newCustomSigner(t *testing.T, testCaFile, testCaKeyFile string) (s *Signer) { s, err := NewSignerFromFile(testCaFile, testCaKeyFile, nil) if err != nil { t.Fatal(err) } return } func TestNewSignerFromFile(t *testing.T) { newTestSigner(t) } const ( testHostName = "localhost" ) func testSignFile(t *testing.T, certFile string) ([]byte, error) { s := newTestSigner(t) pem, err := os.ReadFile(certFile) if err != nil { t.Fatal(err) } return s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(testHostName), Request: string(pem)}) } type csrTest struct { file string keyAlgo string keyLen int // Error checking function errorCallback func(*testing.T, error) } // A helper function that returns a errorCallback function which expects an error. func ExpectError() func(*testing.T, error) { return func(t *testing.T, err error) { if err == nil { t.Fatal("Expected error. Got nothing.") } } } var csrTests = []csrTest{ { file: "testdata/rsa2048.csr", keyAlgo: "rsa", keyLen: 2048, errorCallback: nil, }, { file: "testdata/rsa3072.csr", keyAlgo: "rsa", keyLen: 3072, errorCallback: nil, }, { file: "testdata/rsa4096.csr", keyAlgo: "rsa", keyLen: 4096, errorCallback: nil, }, { file: "testdata/ecdsa256.csr", keyAlgo: "ecdsa", keyLen: 256, errorCallback: nil, }, { file: "testdata/ecdsa384.csr", keyAlgo: "ecdsa", keyLen: 384, errorCallback: nil, }, { file: "testdata/ecdsa521.csr", keyAlgo: "ecdsa", keyLen: 521, errorCallback: nil, }, { file: "testdata/rsa-old.csr", keyAlgo: "rsa", keyLen: 2048, errorCallback: nil, }, { file: "testdata/ed25519.csr", keyAlgo: "ed25519", keyLen: 256, errorCallback: nil, }, } func TestSignCSRs(t *testing.T) { s := newTestSigner(t) hostname := "cloudflare.com" for _, test := range csrTests { csr, err := os.ReadFile(test.file) if err != nil { t.Fatal("CSR loading error:", err) } // It is possible to use different SHA2 algorithm with RSA CA key. rsaSigAlgos := []x509.SignatureAlgorithm{x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA} for _, sigAlgo := range rsaSigAlgos { s.sigAlgo = sigAlgo certBytes, err := s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(hostname), Request: string(csr)}) if test.errorCallback != nil { test.errorCallback(t, err) } else { if err != nil { t.Fatalf("Expected no error. Got %s. Param %s %d", err.Error(), test.keyAlgo, test.keyLen) } cert, _ := helpers.ParseCertificatePEM(certBytes) if cert.SignatureAlgorithm != s.SigAlgo() { t.Fatal("Cert Signature Algorithm does not match the issuer.") } } } } } func TestECDSASigner(t *testing.T) { s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) hostname := "cloudflare.com" for _, test := range csrTests { csr, err := os.ReadFile(test.file) if err != nil { t.Fatal("CSR loading error:", err) } // Try all ECDSA SignatureAlgorithm SigAlgos := []x509.SignatureAlgorithm{x509.ECDSAWithSHA1, x509.ECDSAWithSHA256, x509.ECDSAWithSHA384, x509.ECDSAWithSHA512} for _, sigAlgo := range SigAlgos { s.sigAlgo = sigAlgo certBytes, err := s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(hostname), Request: string(csr)}) if test.errorCallback != nil { test.errorCallback(t, err) } else { if err != nil { t.Fatalf("Expected no error. Got %s. Param %s %d", err.Error(), test.keyAlgo, test.keyLen) } cert, _ := helpers.ParseCertificatePEM(certBytes) if cert.SignatureAlgorithm != s.SigAlgo() { t.Fatal("Cert Signature Algorithm does not match the issuer.") } } } } } const ( ecdsaInterCSR = "testdata/ecdsa256-inter.csr" ecdsaInterKey = "testdata/ecdsa256-inter.key" rsaInterCSR = "testdata/rsa2048-inter.csr" rsaInterKey = "testdata/rsa2048-inter.key" ) func TestCAIssuing(t *testing.T) { var caCerts = []string{testCaFile, testECDSACaFile} var caKeys = []string{testCaKeyFile, testECDSACaKeyFile} var interCSRs = []string{ecdsaInterCSR, rsaInterCSR} var interKeys = []string{ecdsaInterKey, rsaInterKey} var CAPolicy = &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "1h", Expiry: 1 * time.Hour, CAConstraint: config.CAConstraint{IsCA: true, MaxPathLenZero: true}, }, } var hostname = "cloudflare-inter.com" // Each RSA or ECDSA root CA issues two intermediate CAs (one ECDSA and one RSA). // For each intermediate CA, use it to issue additional RSA and ECDSA intermediate CSRs. for i, caFile := range caCerts { caKeyFile := caKeys[i] s := newCustomSigner(t, caFile, caKeyFile) s.policy = CAPolicy for j, csr := range interCSRs { csrBytes, _ := os.ReadFile(csr) certBytes, err := s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(hostname), Request: string(csrBytes)}) if err != nil { t.Fatal(err) } interCert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal(err) } keyBytes, _ := os.ReadFile(interKeys[j]) interKey, _ := helpers.ParsePrivateKeyPEM(keyBytes) interSigner := &Signer{ ca: interCert, priv: interKey, policy: CAPolicy, sigAlgo: signer.DefaultSigAlgo(interKey), } for _, anotherCSR := range interCSRs { anotherCSRBytes, _ := os.ReadFile(anotherCSR) bytes, err := interSigner.Sign( signer.SignRequest{ Hosts: signer.SplitHosts(hostname), Request: string(anotherCSRBytes), }) if err != nil { t.Fatal(err) } cert, err := helpers.ParseCertificatePEM(bytes) if err != nil { t.Fatal(err) } if cert.SignatureAlgorithm != interSigner.SigAlgo() { t.Fatal("Cert Signature Algorithm does not match the issuer.") } if cert.MaxPathLen != 0 { t.Fatal("CA Cert Max Path is not zero.") } if cert.MaxPathLenZero != true { t.Fatal("CA Cert Max Path is not zero.") } } } } } func TestPopulateSubjectFromCSR(t *testing.T) { // a subject with all its fields full. fullSubject := &signer.Subject{ CN: "CN", Names: []csr.Name{ { C: "C", ST: "ST", L: "L", O: "O", OU: "OU", }, }, SerialNumber: "deadbeef", } fullName := pkix.Name{ CommonName: "CommonName", Country: []string{"Country"}, Province: []string{"Province"}, Organization: []string{"Organization"}, OrganizationalUnit: []string{"OrganizationalUnit"}, SerialNumber: "SerialNumber", } noCN := *fullSubject noCN.CN = "" name := PopulateSubjectFromCSR(&noCN, fullName) if name.CommonName != "CommonName" { t.Fatal("Failed to replace empty common name") } noC := *fullSubject noC.Names[0].C = "" name = PopulateSubjectFromCSR(&noC, fullName) if !reflect.DeepEqual(name.Country, fullName.Country) { t.Fatal("Failed to replace empty country") } noL := *fullSubject noL.Names[0].L = "" name = PopulateSubjectFromCSR(&noL, fullName) if !reflect.DeepEqual(name.Locality, fullName.Locality) { t.Fatal("Failed to replace empty locality") } noO := *fullSubject noO.Names[0].O = "" name = PopulateSubjectFromCSR(&noO, fullName) if !reflect.DeepEqual(name.Organization, fullName.Organization) { t.Fatal("Failed to replace empty organization") } noOU := *fullSubject noOU.Names[0].OU = "" name = PopulateSubjectFromCSR(&noOU, fullName) if !reflect.DeepEqual(name.OrganizationalUnit, fullName.OrganizationalUnit) { t.Fatal("Failed to replace empty organizational unit") } noSerial := *fullSubject noSerial.SerialNumber = "" name = PopulateSubjectFromCSR(&noSerial, fullName) if name.SerialNumber != fullName.SerialNumber { t.Fatalf("Failed to replace empty serial number: want %#v, got %#v", fullName.SerialNumber, name.SerialNumber) } } func TestOverrideSubject(t *testing.T) { csrPEM, err := os.ReadFile(fullSubjectCSR) if err != nil { t.Fatalf("%v", err) } req := &signer.Subject{ Names: []csr.Name{ {O: "example.net"}, }, } s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) request := signer.SignRequest{ Hosts: []string{"127.0.0.1", "localhost", "xyz@example.com", "https://www.cloudflare.com"}, Request: string(csrPEM), Subject: req, } certPEM, err := s.Sign(request) if err != nil { t.Fatalf("%v", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } block, _ := pem.Decode(csrPEM) template, err := x509.ParseCertificateRequest(block.Bytes) if err != nil { t.Fatal(err.Error()) } if cert.Subject.Organization[0] != "example.net" { t.Fatalf("Failed to override subject: want example.net but have %s", cert.Subject.Organization[0]) } if cert.Subject.Country[0] != template.Subject.Country[0] { t.Fatal("Failed to override Country") } if cert.Subject.Locality[0] != template.Subject.Locality[0] { t.Fatal("Failed to override Locality") } if cert.Subject.Organization[0] == template.Subject.Organization[0] { t.Fatal("Shouldn't have overrode Organization") } if cert.Subject.OrganizationalUnit[0] != template.Subject.OrganizationalUnit[0] { t.Fatal("Failed to override OrganizationalUnit") } log.Info("Overrode subject info") } func TestOverwriteHosts(t *testing.T) { for _, csrFile := range []string{testCSR, testSANCSR} { csrPEM, err := os.ReadFile(csrFile) if err != nil { t.Fatal(err) } csrDER, _ := pem.Decode([]byte(csrPEM)) if err != nil { t.Fatal(err) } csr, err := x509.ParseCertificateRequest(csrDER.Bytes) if err != nil { t.Fatal(err) } csrHosts := csr.DNSNames for _, ip := range csr.IPAddresses { csrHosts = append(csrHosts, ip.String()) } sort.Strings(csrHosts) s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) for _, hosts := range [][]string{ nil, {}, {"127.0.0.1", "localhost", "xyz@example.com", "https://www.cloudflare.com"}, } { request := signer.SignRequest{ Hosts: hosts, Request: string(csrPEM), Subject: nil, } certPEM, err := s.Sign(request) if err != nil { t.Fatalf("%v", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } // get the hosts, and add the ips and email addresses certHosts := cert.DNSNames for _, ip := range cert.IPAddresses { certHosts = append(certHosts, ip.String()) } for _, email := range cert.EmailAddresses { certHosts = append(certHosts, email) } for _, uri := range cert.URIs { certHosts = append(certHosts, uri.String()) } // compare the sorted host lists sort.Strings(certHosts) sort.Strings(request.Hosts) if len(request.Hosts) > 0 && !reflect.DeepEqual(certHosts, request.Hosts) { t.Fatalf("Hosts not the same. cert hosts: %v, expected: %v", certHosts, request.Hosts) } if request.Hosts == nil && !reflect.DeepEqual(certHosts, csrHosts) { t.Fatalf("Hosts not the same. cert hosts: %v, expected csr hosts: %v", certHosts, csrHosts) } if request.Hosts != nil && len(request.Hosts) == 0 && len(certHosts) != 0 { t.Fatalf("Hosts not the same. cert hosts: %v, expected: %v", certHosts, request.Hosts) } } } } func TestOverrideValidity(t *testing.T) { csrPEM, err := os.ReadFile(fullSubjectCSR) if err != nil { t.Fatalf("%v", err) } s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) req := signer.SignRequest{ Request: string(csrPEM), } // The default expiry value. expiry := 8760 * time.Hour // default case now := time.Now().UTC() certPEM, err := s.Sign(req) if err != nil { t.Fatalf("Error signing default request: %s", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } if !cert.NotBefore.After(now.Add(-10*time.Minute)) || !cert.NotBefore.Before(now.Add(10*time.Minute)) { t.Fatalf("Unexpected NotBefore: wanted %s +/-10 minutes, got %s", now, cert.NotBefore) } expectedNotAfter := now.Round(time.Minute).Add(expiry) if !cert.NotAfter.After(expectedNotAfter.Add(-10*time.Minute)) || !cert.NotAfter.Before(expectedNotAfter.Add(10*time.Minute)) { t.Fatalf("Unexpected NotAfter: wanted %s +/-10 minutes, got %s", now, cert.NotAfter) } // custom case, NotBefore only now = time.Now().UTC() req.NotBefore = now.Add(-time.Hour * 5).Truncate(time.Hour) req.NotAfter = time.Time{} certPEM, err = s.Sign(req) if err != nil { t.Fatalf("Error signing default request: %s", err) } cert, err = helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } if !cert.NotBefore.Equal(req.NotBefore) { t.Fatalf("Unexpected NotBefore: wanted %s, got %s", req.NotBefore, cert.NotBefore) } expectedNotAfter = req.NotBefore.Add(expiry) if !cert.NotAfter.After(expectedNotAfter.Add(-10*time.Minute)) || !cert.NotAfter.Before(expectedNotAfter.Add(10*time.Minute)) { t.Fatalf("Unexpected NotAfter: wanted %s +/-10 minutes, got %s", expectedNotAfter, cert.NotAfter) } // custom case, NotAfter only now = time.Now().UTC() req.NotBefore = time.Time{} req.NotAfter = now.Add(-time.Hour * 5).Truncate(time.Hour) certPEM, err = s.Sign(req) if err != nil { t.Fatalf("Error signing default request: %s", err) } cert, err = helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } if !cert.NotBefore.After(now.Add(-10*time.Minute)) || !cert.NotBefore.Before(now.Add(10*time.Minute)) { t.Fatalf("Unexpected NotBefore: wanted %s +/-10 minutes, got %s", now, cert.NotBefore) } if !cert.NotAfter.Equal(req.NotAfter) { t.Fatalf("Unexpected NotAfter: wanted %s, got %s", req.NotAfter, cert.NotAfter) } // custom case, NotBefore and NotAfter now = time.Now().UTC() req.NotBefore = now.Add(-time.Hour * 5).Truncate(time.Hour) req.NotAfter = now.Add(time.Hour * 5).Truncate(time.Hour) certPEM, err = s.Sign(req) if err != nil { t.Fatalf("Error signing default request: %s", err) } cert, err = helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } if !cert.NotBefore.Equal(req.NotBefore) { t.Fatalf("Unexpected NotBefore: wanted %s, got %s", req.NotBefore, cert.NotBefore) } if !cert.NotAfter.Equal(req.NotAfter) { t.Fatalf("Unexpected NotAfter: wanted %s, got %s", req.NotAfter, cert.NotAfter) } } func expectOneValueOf(t *testing.T, s []string, e, n string) { if len(s) != 1 { t.Fatalf("Expected %s to have a single value, but it has %d values", n, len(s)) } if s[0] != e { t.Fatalf("Expected %s to be '%s', but it is '%s'", n, e, s[0]) } } func expectEmpty(t *testing.T, s []string, n string) { if len(s) != 0 { t.Fatalf("Expected no values in %s, but have %d values: %v", n, len(s), s) } } func TestCASignPathlen(t *testing.T) { var csrPathlenTests = []struct { name string caCertFile string caKeyFile string caProfile bool csrFile string err error pathlen int isZero bool isCA bool }{ { name: "pathlen 1 signing pathlen 0", caCertFile: testECDSACaFile, caKeyFile: testECDSACaKeyFile, caProfile: true, csrFile: "testdata/inter_pathlen_0.csr", err: nil, pathlen: 0, isZero: true, isCA: true, }, { name: "pathlen 1 signing pathlen 1", caCertFile: testECDSACaFile, caKeyFile: testECDSACaKeyFile, caProfile: true, csrFile: "testdata/inter_pathlen_1.csr", err: cferr.New(cferr.PolicyError, cferr.InvalidRequest), }, { name: "pathlen 0 signing pathlen 0", caCertFile: testCaFile, caKeyFile: testCaKeyFile, caProfile: true, csrFile: "testdata/inter_pathlen_0.csr", err: cferr.New(cferr.PolicyError, cferr.InvalidRequest), }, { name: "pathlen 0 signing pathlen 1", caCertFile: testCaFile, caKeyFile: testCaKeyFile, caProfile: true, csrFile: "testdata/inter_pathlen_1.csr", err: cferr.New(cferr.PolicyError, cferr.InvalidRequest), }, { name: "pathlen 0 signing pathlen unspecified", caCertFile: testCaFile, caKeyFile: testCaKeyFile, caProfile: true, csrFile: "testdata/inter_pathlen_unspecified.csr", err: cferr.New(cferr.PolicyError, cferr.InvalidRequest), }, { name: "pathlen 1 signing unspecified pathlen", caCertFile: testECDSACaFile, caKeyFile: testECDSACaKeyFile, caProfile: true, csrFile: "testdata/inter_pathlen_unspecified.csr", err: nil, // golang x509 parses unspecified pathlen as MaxPathLen == -1 and // MaxPathLenZero == false pathlen: -1, isZero: false, isCA: true, }, { name: "non-ca singing profile signing pathlen 0", caCertFile: testECDSACaFile, caKeyFile: testECDSACaKeyFile, caProfile: false, csrFile: "testdata/inter_pathlen_0.csr", err: cferr.New(cferr.PolicyError, cferr.InvalidRequest), }, { name: "non-ca singing profile signing pathlen 1", caCertFile: testECDSACaFile, caKeyFile: testECDSACaKeyFile, caProfile: false, csrFile: "testdata/inter_pathlen_1.csr", err: cferr.New(cferr.PolicyError, cferr.InvalidRequest), }, { name: "non-ca singing profile signing pathlen 0", caCertFile: testECDSACaFile, caKeyFile: testECDSACaKeyFile, caProfile: false, csrFile: "testdata/inter_pathlen_unspecified.csr", err: cferr.New(cferr.PolicyError, cferr.InvalidRequest), }, } for _, testCase := range csrPathlenTests { csrPEM, err := os.ReadFile(testCase.csrFile) if err != nil { t.Fatalf("%v", err) } req := &signer.Subject{ Names: []csr.Name{ {O: "sam certificate authority"}, }, CN: "localhost", } s := newCustomSigner(t, testCase.caCertFile, testCase.caKeyFile) // No policy CSR whitelist: the normal set of CSR fields get passed through to // certificate. s.policy = &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "1h", Expiry: 1 * time.Hour, CAConstraint: config.CAConstraint{IsCA: testCase.caProfile, MaxPathLen: testCase.pathlen, MaxPathLenZero: testCase.isZero, }, }, } request := signer.SignRequest{ Hosts: []string{"127.0.0.1", "localhost"}, Request: string(csrPEM), Subject: req, } certPEM, err := s.Sign(request) if !reflect.DeepEqual(err, testCase.err) { t.Fatalf("%s: expected: %v, actual: %v", testCase.name, testCase.err, err) } if err == nil { cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%s: %v", testCase.name, err) } if cert.IsCA != testCase.isCA { t.Fatalf("%s: unexpected IsCA value: %v", testCase.name, cert.IsCA) } if cert.MaxPathLen != testCase.pathlen { t.Fatalf("%s: unexpected pathlen value: %v", testCase.name, cert.MaxPathLen) } if cert.MaxPathLenZero != testCase.isZero { t.Fatalf("%s: unexpected pathlen value: %v", testCase.name, cert.MaxPathLenZero) } } } } func TestNoWhitelistSign(t *testing.T) { csrPEM, err := os.ReadFile(fullSubjectCSR) if err != nil { t.Fatalf("%v", err) } req := &signer.Subject{ Names: []csr.Name{ {O: "sam certificate authority"}, }, CN: "localhost", } s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) // No policy CSR whitelist: the normal set of CSR fields get passed through to // certificate. s.policy = &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "1h", Expiry: 1 * time.Hour, CAConstraint: config.CAConstraint{IsCA: true}, }, } request := signer.SignRequest{ Hosts: []string{"127.0.0.1", "localhost"}, Request: string(csrPEM), Subject: req, } certPEM, err := s.Sign(request) if err != nil { t.Fatalf("%v", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } name := cert.Subject if name.CommonName != "localhost" { t.Fatalf("Expected certificate common name to be 'localhost' but have '%v'", name.CommonName) } // CSR has: Subject: C=US, O=CloudFlare, OU=WWW, L=Ithaca, ST=New York // Expect all to be passed through. expectOneValueOf(t, name.Organization, "sam certificate authority", "O") expectOneValueOf(t, name.OrganizationalUnit, "WWW", "OU") expectOneValueOf(t, name.Province, "New York", "ST") expectOneValueOf(t, name.Locality, "Ithaca", "L") expectOneValueOf(t, name.Country, "US", "C") } func TestWhitelistSign(t *testing.T) { csrPEM, err := os.ReadFile(fullSubjectCSR) if err != nil { t.Fatalf("%v", err) } req := &signer.Subject{ Names: []csr.Name{ {O: "sam certificate authority"}, }, } s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) // Whitelist only key-related fields. Subject, DNSNames, etc shouldn't get // passed through from CSR. s.policy = &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "1h", Expiry: 1 * time.Hour, CAConstraint: config.CAConstraint{IsCA: true}, CSRWhitelist: &config.CSRWhitelist{ PublicKey: true, PublicKeyAlgorithm: true, SignatureAlgorithm: true, }, }, } request := signer.SignRequest{ Hosts: []string{"127.0.0.1", "localhost"}, Request: string(csrPEM), Subject: req, } certPEM, err := s.Sign(request) if err != nil { t.Fatalf("%v", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } name := cert.Subject if name.CommonName != "" { t.Fatalf("Expected empty certificate common name under policy without "+ "Subject whitelist, got %v", name.CommonName) } // O is provided by the signing API request, not the CSR, so it's allowed to // be copied into the certificate. expectOneValueOf(t, name.Organization, "sam certificate authority", "O") expectEmpty(t, name.OrganizationalUnit, "OU") expectEmpty(t, name.Province, "ST") expectEmpty(t, name.Locality, "L") expectEmpty(t, name.Country, "C") if cert.PublicKeyAlgorithm != x509.RSA { t.Fatalf("Expected public key algorithm to be RSA") } // Signature algorithm is allowed to be copied from CSR, but is overridden by // DefaultSigAlgo. if cert.SignatureAlgorithm != x509.ECDSAWithSHA256 { t.Fatalf("Expected public key algorithm to be ECDSAWithSHA256, got %v", cert.SignatureAlgorithm) } } func TestNameWhitelistSign(t *testing.T) { csrPEM, err := os.ReadFile(fullSubjectCSR) if err != nil { t.Fatalf("%v", err) } subInvalid := &signer.Subject{ CN: "localhost.com", } subValid := &signer.Subject{ CN: "1lab41.cf", } wl := regexp.MustCompile("^1[a-z]*[0-9]*\\.cf$") s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) // Whitelist only key-related fields. Subject, DNSNames, etc shouldn't get // passed through from CSR. s.policy = &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "1h", Expiry: 1 * time.Hour, CAConstraint: config.CAConstraint{IsCA: true}, NameWhitelist: wl, }, } request := signer.SignRequest{ Hosts: []string{"127.0.0.1", "1machine23.cf"}, Request: string(csrPEM), } _, err = s.Sign(request) if err != nil { t.Fatalf("%v", err) } request = signer.SignRequest{ Hosts: []string{"invalid.cf", "1machine23.cf"}, Request: string(csrPEM), } _, err = s.Sign(request) if err == nil { t.Fatalf("expected a policy error") } request = signer.SignRequest{ Hosts: []string{"1machine23.cf"}, Request: string(csrPEM), Subject: subInvalid, } _, err = s.Sign(request) if err == nil { t.Fatalf("expected a policy error") } request = signer.SignRequest{ Hosts: []string{"1machine23.cf"}, Request: string(csrPEM), Subject: subValid, } _, err = s.Sign(request) if err != nil { t.Fatalf("%v", err) } } func TestExtensionSign(t *testing.T) { csrPEM, err := os.ReadFile(testCSR) if err != nil { t.Fatalf("%v", err) } s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) // By default, no extensions should be allowed request := signer.SignRequest{ Request: string(csrPEM), Extensions: []signer.Extension{ {ID: config.OID(asn1.ObjectIdentifier{1, 2, 3, 4})}, }, } _, err = s.Sign(request) if err == nil { t.Fatalf("expected a policy error") } // Whitelist a specific extension. The extension with OID 1.2.3.4 should be // allowed through, but the one with OID 1.2.3.5 should not. s.policy = &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "1h", Expiry: 1 * time.Hour, CAConstraint: config.CAConstraint{IsCA: true}, ExtensionWhitelist: map[string]bool{"1.2.3.4": true}, }, } // Test that a forbidden extension triggers a sign error request = signer.SignRequest{ Request: string(csrPEM), Extensions: []signer.Extension{ {ID: config.OID(asn1.ObjectIdentifier{1, 2, 3, 5})}, }, } _, err = s.Sign(request) if err == nil { t.Fatalf("expected a policy error") } extValue := []byte{0x05, 0x00} extValueHex := hex.EncodeToString(extValue) // Test that an allowed extension makes it through request = signer.SignRequest{ Request: string(csrPEM), Extensions: []signer.Extension{ { ID: config.OID(asn1.ObjectIdentifier{1, 2, 3, 4}), Critical: false, Value: extValueHex, }, }, } certPEM, err := s.Sign(request) if err != nil { t.Fatalf("%v", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } foundAllowed := false for _, ext := range cert.Extensions { if ext.Id.String() == "1.2.3.4" { foundAllowed = true if ext.Critical { t.Fatalf("Extensions should not be marked critical") } if !bytes.Equal(extValue, ext.Value) { t.Fatalf("Extension has wrong value: %s != %s", hex.EncodeToString(ext.Value), extValueHex) } } } if !foundAllowed { t.Fatalf("Custom extension not included in the certificate") } } func TestCTFailure(t *testing.T) { // start a fake CT server that returns bad request ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(400) })) defer ts.Close() var config = &config.Signing{ Default: &config.SigningProfile{ Expiry: helpers.OneYear, CAConstraint: config.CAConstraint{IsCA: true}, Usage: []string{"signing", "key encipherment", "server auth", "client auth"}, ExpiryString: "8760h", CTLogServers: []string{ts.URL}, }, } testSigner, err := NewSignerFromFile(testCaFile, testCaKeyFile, config) if err != nil { t.Fatalf("%v", err) } var pem []byte pem, err = os.ReadFile("testdata/ex.csr") if err != nil { t.Fatalf("%v", err) } validReq := signer.SignRequest{ Request: string(pem), Hosts: []string{"example.com"}, } _, err = testSigner.Sign(validReq) if err == nil { t.Fatal("Expected CT log submission failure") } } func TestCTSuccess(t *testing.T) { // start a fake CT server that will accept the submission ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`{"sct_version":0,"id":"KHYaGJAn++880NYaAY12sFBXKcenQRvMvfYE9F1CYVM=","timestamp":1337,"extensions":"","signature":"BAMARjBEAiAIc21J5ZbdKZHw5wLxCP+MhBEsV5+nfvGyakOIv6FOvAIgWYMZb6Pw///uiNM7QTg2Of1OqmK1GbeGuEl9VJN8v8c="}`)) w.WriteHeader(200) })) defer ts.Close() var config = &config.Signing{ Default: &config.SigningProfile{ Expiry: helpers.OneYear, CAConstraint: config.CAConstraint{IsCA: true}, Usage: []string{"signing", "key encipherment", "server auth", "client auth"}, ExpiryString: "8760h", CTLogServers: []string{ts.URL}, }, } testSigner, err := NewSignerFromFile(testCaFile, testCaKeyFile, config) if err != nil { t.Fatalf("%v", err) } var pem []byte pem, err = os.ReadFile("testdata/ex.csr") if err != nil { t.Fatalf("%v", err) } validReq := signer.SignRequest{ Request: string(pem), Hosts: []string{"example.com"}, } _, err = testSigner.Sign(validReq) if err != nil { t.Fatal("Expected CT log submission success") } } func TestReturnPrecert(t *testing.T) { var config = &config.Signing{ Default: &config.SigningProfile{ Expiry: helpers.OneYear, CAConstraint: config.CAConstraint{IsCA: true}, Usage: []string{"signing", "key encipherment", "server auth", "client auth"}, ExpiryString: "8760h", }, } testSigner, err := NewSignerFromFile(testCaFile, testCaKeyFile, config) if err != nil { t.Fatalf("%v", err) } csr, err := os.ReadFile("testdata/ex.csr") if err != nil { t.Fatalf("%v", err) } validReq := signer.SignRequest{ Request: string(csr), Hosts: []string{"example.com"}, ReturnPrecert: true, } certBytes, err := testSigner.Sign(validReq) if err != nil { t.Fatal("Failed to sign request") } block, _ := pem.Decode(certBytes) cert, err := x509.ParseCertificate(block.Bytes) if err != nil { t.Fatalf("Failed to parse signed cert: %s", err) } // check cert with poison extension was returned poisoned := false for _, ext := range cert.Extensions { if ext.Id.Equal(signer.CTPoisonOID) { poisoned = true break } } if !poisoned { t.Fatal("Certificate without poison CT extension was returned") } } func TestSignFromPrecert(t *testing.T) { var config = &config.Signing{ Default: &config.SigningProfile{ Expiry: helpers.OneYear, CAConstraint: config.CAConstraint{IsCA: true}, Usage: []string{"signing", "key encipherment", "server auth", "client auth"}, ExpiryString: "8760h", }, } testSigner, err := NewSignerFromFile(testCaFile, testCaKeyFile, config) if err != nil { t.Fatalf("%v", err) } // Generate a precert k, err := rsa.GenerateKey(rand.Reader, 1024) if err != nil { t.Fatalf("Failed to generate test key: %s", err) } _uri, _ := url.Parse("https://www.cloudflare.com") precertBytes, err := testSigner.sign(&x509.Certificate{ SignatureAlgorithm: x509.SHA512WithRSA, PublicKey: k.Public(), SerialNumber: big.NewInt(10), Subject: pkix.Name{CommonName: "CN"}, NotBefore: time.Now(), NotAfter: time.Now().Add(time.Hour), ExtraExtensions: []pkix.Extension{ {Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}}, }, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, SubjectKeyId: []byte{0, 1}, AuthorityKeyId: []byte{1, 0}, OCSPServer: []string{"ocsp?"}, IssuingCertificateURL: []string{"url"}, DNSNames: []string{"example.com"}, EmailAddresses: []string{"email@example.com"}, URIs: []*url.URL{_uri}, IPAddresses: []net.IP{net.ParseIP("1.1.1.1")}, CRLDistributionPoints: []string{"crl"}, PolicyIdentifiers: []asn1.ObjectIdentifier{{1, 2, 3}}, }, 0, nil) if err != nil { t.Fatalf("Failed to sign request: %s", err) } block, _ := pem.Decode(precertBytes) precert, err := x509.ParseCertificate(block.Bytes) if err != nil { t.Fatalf("Failed to parse signed cert: %s", err) } // Create a cert from the precert scts := []ct.SignedCertificateTimestamp{{}} certBytes, err := testSigner.SignFromPrecert(precert, scts) if err != nil { t.Fatalf("Failed to sign cert from precert: %s", err) } block, _ = pem.Decode(certBytes) cert, err := x509.ParseCertificate(block.Bytes) if err != nil { t.Fatalf("Failed to parse signed cert: %s", err) } // check cert doesn't contains poison extension poisoned := false for _, ext := range cert.Extensions { if ext.Id.Equal(signer.CTPoisonOID) { poisoned = true break } } if poisoned { t.Fatal("Certificate with poison CT extension was returned") } // check cert contains SCT list extension list := false for _, ext := range cert.Extensions { if ext.Id.Equal(signer.SCTListOID) { list = true break } } if !list { t.Fatal("Certificate without SCT list extension was returned") } // Break poison extension precert.Extensions[7].Value = []byte{1, 3, 3, 7} _, err = testSigner.SignFromPrecert(precert, scts) if err == nil { t.Fatal("SignFromPrecert didn't fail with invalid poison extension") } precert.Extensions[7].Critical = false _, err = testSigner.SignFromPrecert(precert, scts) if err == nil { t.Fatal("SignFromPrecert didn't fail with non-critical poison extension") } precert.Extensions = append(precert.Extensions[:7], precert.Extensions[8:]...) _, err = testSigner.SignFromPrecert(precert, scts) if err == nil { t.Fatal("SignFromPrecert didn't fail with missing poison extension") } precert.Signature = []byte("nop") _, err = testSigner.SignFromPrecert(precert, scts) if err == nil { t.Fatal("SignFromPrecert didn't fail with signature not from CA") } } func TestLint(t *testing.T) { k, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) serial := big.NewInt(1337) // jankyTemplate is an x509 cert template that mostly passes through zlint // without errors/warnings. It is used as the basis of both the signer's issuing // certificate and the end entity certificate that is linted. jankyTemplate := &x509.Certificate{ Subject: pkix.Name{ CommonName: "janky.cert", }, SerialNumber: serial, NotBefore: time.Now(), NotAfter: time.Now().AddDate(0, 0, 90), KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, PolicyIdentifiers: []asn1.ObjectIdentifier{ {1, 2, 3}, }, BasicConstraintsValid: true, IsCA: true, IssuingCertificateURL: []string{"http://ca.cpu"}, SubjectKeyId: []byte("⚿"), PublicKey: k.Public(), } // Create a self-signed issuer certificate to use as the CA issuerDer, _ := x509.CreateCertificate(rand.Reader, jankyTemplate, jankyTemplate, k.Public(), k) issuerCert, _ := x509.ParseCertificate(issuerDer) lintSigner := &Signer{ lintPriv: k, ca: issuerCert, } // Reconfigure the template for an end-entity certificate. // On purpose this template will trip the following lints: // 1. e_sub_cert_aia_does_not_contain_ocsp_url because there is no OCSP URL. // 2. e_dnsname_not_valid_tld because `.cert` is not a real TLD serial = big.NewInt(1338) jankyTemplate.SerialNumber = serial jankyTemplate.Subject.CommonName = "www.janky.cert" jankyTemplate.DNSNames = []string{"janky.cert", "www.janky.cert"} jankyTemplate.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment jankyTemplate.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth} jankyTemplate.IsCA = false ignoredLintNameRegistry, err := lint.GlobalRegistry().Filter(lint.FilterOptions{ ExcludeNames: []string{"e_dnsname_not_valid_tld"}, }) if err != nil { t.Fatalf("failed to construct ignoredLintNamesRegistry: %v", err) } ignoredLintSourcesRegistry, err := lint.GlobalRegistry().Filter(lint.FilterOptions{ ExcludeSources: lint.SourceList{lint.CABFBaselineRequirements}, ExcludeNames: []string{"e_ecdsa_allowed_ku"}, }) if err != nil { t.Fatalf("failed to construct ignoredLintSourcesRegistry: %v", err) } testCases := []struct { name string signer *Signer lintErrLevel lint.LintStatus lintRegistry lint.Registry expectedErr error expectedErrResults map[string]lint.LintResult }{ { name: "linting disabled", signer: lintSigner, }, { name: "signer without lint key", signer: &Signer{}, lintErrLevel: lint.NA, expectedErr: errors.New(`{"code":2500,"message":"Private key is unavailable"}`), }, { name: "lint results above err level", signer: lintSigner, lintErrLevel: lint.Notice, expectedErr: errors.New("pre-issuance linting found 3 error results"), expectedErrResults: map[string]lint.LintResult{ "e_sub_cert_aia_does_not_contain_ocsp_url": {Status: 6}, "e_dnsname_not_valid_tld": {Status: 6}, "e_ecdsa_allowed_ku": {Status: 6, Details: "Certificate contains invalid key usage(s): KeyUsageKeyEncipherment"}, }, }, { name: "lint results below err level", signer: lintSigner, lintErrLevel: lint.Warn, expectedErr: errors.New("pre-issuance linting found 3 error results"), expectedErrResults: map[string]lint.LintResult{ "e_sub_cert_aia_does_not_contain_ocsp_url": {Status: 6}, "e_dnsname_not_valid_tld": {Status: 6}, "e_ecdsa_allowed_ku": {Status: 6, Details: "Certificate contains invalid key usage(s): KeyUsageKeyEncipherment"}, }, }, { name: "ignored lint names, lint results above err level", signer: lintSigner, lintErrLevel: lint.Notice, lintRegistry: ignoredLintNameRegistry, expectedErr: errors.New("pre-issuance linting found 2 error results"), expectedErrResults: map[string]lint.LintResult{ "e_sub_cert_aia_does_not_contain_ocsp_url": {Status: 6}, "e_ecdsa_allowed_ku": {Status: 6, Details: "Certificate contains invalid key usage(s): KeyUsageKeyEncipherment"}, }, }, { name: "ignored lint sources, lint results above err level", signer: lintSigner, lintErrLevel: lint.Notice, lintRegistry: ignoredLintSourcesRegistry, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := tc.signer.lint(*jankyTemplate, tc.lintErrLevel, tc.lintRegistry) if err != nil && tc.expectedErr == nil { t.Errorf("Expected no err, got %#v", err) } else if err == nil && tc.expectedErr != nil { t.Errorf("Expected err %v, got nil", tc.expectedErr) } else if err != nil && tc.expectedErr != nil { actual := err.Error() expected := tc.expectedErr.Error() if expected != actual { t.Fatalf("expected: %v, got: %v", expected, actual) } if len(tc.expectedErrResults) > 0 { le, ok := err.(*LintError) if !ok { t.Fatalf("expected LintError type err, got %v", err) } if !reflect.DeepEqual(tc.expectedErrResults, le.ErrorResults) { t.Fatalf("expected: %v, got: %v", tc.expectedErrResults, le.ErrorResults) } } } }) } } ================================================ FILE: signer/local/testdata/build_inter_pathlen_csrs.sh ================================================ echo '{ "CN": "Pathlen 0 Issuer", "ca": { "pathlen": 0, "pathlenzero": true } }' | cfssl genkey -initca - | cfssljson -bare inter_pathlen_0 echo '{ "CN": "Pathlen 1 Issuer", "ca": { "pathlen": 1 } }' | cfssl genkey -initca - | cfssljson -bare inter_pathlen_1 echo '{ "CN": "Pathlen Unspecified", "ca": {} }' | cfssl genkey -initca - | cfssljson -bare inter_pathlen_unspecified ================================================ FILE: signer/local/testdata/ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIEmzCCA4OgAwIBAgIMAMSvNBgypwaaSQ5iMA0GCSqGSIb3DQEBBQUAMIGMMQsw CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy YW5jaXNjbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVT VCBSb290IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTIx MjEyMDIxMDMxWhcNMjIxMDIxMDIxMDMxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNV BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoT CkNGU1NMIFRFU1QxGzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqG SIb3DQEJARYPdGVzdEB0ZXN0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsRp1xSfIDoD/40Bo4Hls3sFn4dav5NgxbZGpVyGF7dJI9u0eEnL4 BUGssPaUFLWC83CZxujUEiEfE0oKX+uOhhGv3+j5xSTNM764m2eSiN53cdZtK05d hwq9uS8LtjKOQeN1mQ5qmiqxBMdjkKgMsVw5lMCgoYKo57kaKFyXzdpNVDzqw+pt HWmuNtDQjK3qT5Ma06mYPmIGYhIZYLY7oJGg9ZEaNR0GIw4zIT5JRsNiaSb5wTLw aa0n/4vLJyVjLJcYmJBvZWj8g+taK+C4INu/jGux+bmsC9hq14tbOaTNAn/NE0qN 8oHwcRBEqfOdEYdZkxI5NWPiKNW/Q+AeXQIDAQABo4H6MIH3MB0GA1UdDgQWBBS3 0veEuqg51fusEM4p/YuWpBPsvTCBxAYDVR0jBIG8MIG5gBS30veEuqg51fusEM4p /YuWpBPsvaGBkqSBjzCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju aWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkNGU1NMIFRFU1Qx GzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqGSIb3DQEJARYPdGVz dEB0ZXN0LmxvY2FsggwAxK80GDKnBppJDmIwDwYDVR0TBAgwBgEB/wIBADANBgkq hkiG9w0BAQUFAAOCAQEAJ7r1EZYDwed6rS0+YKHdkRGRQ5Rz6A9DIVBPXrSMAGj3 F5EF2m/GJbhpVbnNJTVlgP9DDyabOZNxzdrCr4cHMkYYnocDdgAodnkw6GZ/GJTc depbVTR4TpihFNzeDEGJePrEwM1DouGswpu97jyuCYZ3z1a60+a+3C1GwWaJ7Aet Uqm+yLTUrMISsfnDPqJdM1NeqW3jiZ4IgcqJkieCCSpag9Xuzrp9q6rjmePvlQkv qz020JGg6VijJ+c6Tf5y0XqbAhkBTqYtVamu9gEth9utn12EhdNjTZMPKMjjgFUd H0N6yOEuQMl4ky7RxZBM0iPyeob6i4z2LEQilgv9MQ== -----END CERTIFICATE----- ================================================ FILE: signer/local/testdata/ca_key.pem ================================================ -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGnXFJ8gOgP/j QGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLzcJnG6NQSIR8T Sgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B43WZDmqaKrEE x2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepPkxrTqZg+YgZi EhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMslxiYkG9laPyD 61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850Rh1mTEjk1Y+Io 1b9D4B5dAgMBAAECggEAKHhjcSomDSptTwDo9mLI/h40HudwSlsc8GzYxZBjinUD N2n39T9QbeMUE1xFenX/9qFEgq+xxnLLJx1EQacSapCgIAqdCO/f9HMgvGJumdg8 c0cMq1i9Bp7tu+OESZ5D48qWlOM2eQRIb08g8W11eRIaFmPuUPoKnuktkQuXpPJc YbS/+JuA8SDwe6sV0cMCQuS+iHFfeGwWCKrDUkhLwcL3waW3od2XFyOeFFWFhl0h HmM/mWKRuRdqR7hrmArTwFZVkB+o/1ywVYXIv+JQm0eNZ5PKLNJGL2f5oxbMR/JI AoK0bAlJmYaFp96h1KpbPwLEL/0hHSWA7sAyJIgQAQKBgQDaEAZor/w4ZUTekT1+ cbId0yA+ikDXQOfXaNCSh9Pex+Psjd5zVVOqyVFJ29daRju3d7rmpN4Cm5V4h0l1 /2ad207rjCAnpCHtaddJWNyJzF2IL2IaoCZQRp0k7zOjBGQpoWDTwBaEin5CCv3P kkdQkKz6FDP1xskHSLZr21/QCQKBgQDP6jXutEgGjf3yKpMFk/69EamJdon8clbt hl7cOyWtobnZhdOWVZPe00Oo3Jag2aWgFFsm3EtwnUCnR4d4+fXRKS2LkhfIUZcz cKy17Ileggdd8UGhL4RDrF/En9tJL86WcVkcoOrqLcGB2FLWrVhVpHFK74eLMCH/ uc/+ioPItQKBgHYoDsD08s7AGMQcoNx90MyWVLduhFnegoFW+wUa8jOZzieka6/E wVQeR5yksZjpy3vLNYu6M83n7eLkM2rrm/fXGHlLcTTpm7SgEBZfPwivotKjEh5p PrlqucWEk082lutz1RqHz+u7e1Rfzk2F7nx6GDBdeBYpw03eGXJx6QW5AoGBAIJq 4puyAEAET1fZNtHX7IGCk7sDXTi6LCbgE57HhzHr8V0t4fQ6CABMuvMwM1gATjEk s6yjoLqqGUUUzDipanViBAy5fiuManC868lN7zkWDTLzQ3ytBqVAee4na/DziP27 ae9YTSLJwskE/alloLRP6zTbHUXE0n7LelmrX1DFAoGBAMFLl+Lu+WFgCHxBjn43 rHpJbQZQmsFhAMhkN4hsj6dJfAGn2gRLRiVRAika+8QF65xMZiVQWUVSUZADWERi 0SXGjzN1wYxO3Qzy3LYwws6fxFAq5lo79eb38yFT2lHdqK3x/QgiDSRVl+R6cExV xQB518/lp2eIeMpglWByDwJX -----END PRIVATE KEY----- ================================================ FILE: signer/local/testdata/ecdsa256-inter.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBezCCASECAQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJl LWludGVyLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgOKlWwIAIeURde yvDMhgfn6xPp1gn8oUeLmsniBm7I+j84IsVzUso8/MpjMZ9nB8lQUanhv3Kmqcyj HNj+iFegMjAwBgkqhkiG9w0BCQ4xIzAhMB8GA1UdEQQYMBaCFGNsb3VkZmxhcmUt aW50ZXIuY29tMAoGCCqGSM49BAMCA0gAMEUCIEJcy2mn2YyK8lVE+HHmr2OsmdbH 4CLDVXFBwxke8ObqAiEAx/il1cDKvQ/I36b4XjBnOX2jcQ5oaCNPFFBE74WQ/ps= -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/ecdsa256-inter.key ================================================ -----BEGIN EC PRIVATE KEY----- MHcCAQEEILbwI4u4bw+HtafMqFnrL7LOrqNEZH5rW5ygSrigfrVLoAoGCCqGSM49 AwEHoUQDQgAEuA4qVbAgAh5RF17K8MyGB+frE+nWCfyhR4uayeIGbsj6PzgixXNS yjz8ymMxn2cHyVBRqeG/cqapzKMc2P6IVw== -----END EC PRIVATE KEY----- ================================================ FILE: signer/local/testdata/ecdsa256.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBgTCCASgCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBn9Ldie6BOcMHezn2dPuYqW z/NoLYMLGNBqhOxUyEidYClI0JW2pWyUgT3A2UazFp1WgE94y7Z+2YlfRz+vcrKg PzA9BgkqhkiG9w0BCQ4xMDAuMCwGA1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3 d3djbG91ZGZsYXJlLmNvbTAKBggqhkjOPQQDAgNHADBEAiBM+QRxe8u6rkdr10Jy cxbR6NxrGrNeg5QqiOqF96JEmgIgDbtjd5e3y3I8W/+ih2us3WtMxgnTXfqPd48i VLcv28Q= -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/ecdsa256_ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIDUzCCAj2gAwIBAgIIbjeSyheUvjYwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj bzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVTVCBSb290 IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTQwNTI0MDQ1 MTQwWhcNMTUwNTI0MDQ1NjQwWjCBizELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHDAaBgNVBAMTE2Ns b3VkZmxhcmUtbGVhZi5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASMRv3x vcv4I5QF7we+23hES2waKDffBRhQMVVAOSIJcpb4JnzcVJiPJjNlMPbczi5vbzkQ K2kkjOP+okqQia3go4GGMIGDMA4GA1UdDwEB/wQEAwIABDAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQU 4t+cr91ma5IxOPeiezgN8W9FBNowHwYDVR0jBBgwFoAUt9L3hLqoOdX7rBDOKf2L lqQT7L0wCwYJKoZIhvcNAQELA4IBAQAWloyDhrcYFSaZjzb8+UKxnukPUzd7BGaX BvLktbN7hrX+z+ntA5UgXWo7uNgf2L3VwS0mVnRowwmrGV8Pbw9FX5WSisBQ+JJJ JC4ABYT2N7N+B488zKZuMZY8NmSR/ples0Suz3oArUn4ZBGxANyOR6haBbYfupDF LaCtAdQwZzNPfHAo2NsENSOlzGVhV0r1ZqalzkBf70K0KuAoLRbNG3Og17UeMb8K 5sXa7WvubgZ7/D3lr//F56yJYyfTq8SWcIi4e9AUWY5qK+Sr+7W9/gSY3baaHxY9 T9SO4O1ENFJ8ecWRPdsiBNCpl53qMuYW2lh72N35Iyug6qKFDYg5 -----END CERTIFICATE----- ================================================ FILE: signer/local/testdata/ecdsa256_ca_key.pem ================================================ -----BEGIN EC PRIVATE KEY----- MHcCAQEEIC2qaVydr67HuwWMrPQ3ljCVSsnbV7HbN78KqEX6a0GuoAoGCCqGSM49 AwEHoUQDQgAEjEb98b3L+COUBe8Hvtt4REtsGig33wUYUDFVQDkiCXKW+CZ83FSY jyYzZTD23M4ub285ECtpJIzj/qJKkImt4A== -----END EC PRIVATE KEY----- ================================================ FILE: signer/local/testdata/ecdsa384.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBvzCCAUUCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABBk/Q+zMsZOJGkufRzGCWtSUtRjq 0QqChDGWbHLaa0h6ODVeEoKYOMvFJTg4V186tuuBe97KEey0OPDegzCBp5kBIiwg HB/0xWoKdnfdRk6VyjmubPx399cGoZn8aCqgC6A/MD0GCSqGSIb3DQEJDjEwMC4w LAYDVR0RBCUwI4IOY2xvdWRmbGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAoG CCqGSM49BAMDA2gAMGUCMQC57VfwMXDyL5kM7vmO2ynbpgSAuFZT6Yd3C3NnV2jz Biozw3eqIDXqCb2LI09stZMCMGIwCuVARr2IRctxf7AmX7/O2SIaIhCpMFKRedQ7 RiWGZIucp5r6AfT9381PB29bHA== -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/ecdsa521.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIICCjCCAWsCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAHt/s9KTZETzu94JIAjZ3BaS toSG65hGIc1e0Gt7PhdQxPp5FP2D8rQ1wc+pcZhD2O8525kPxopaqTd+fWKBuD3O AULzoH2OX+atIuumTQzLNbTsIbP0tY3dh7d8LItuERkZn1NfsNl3z6bnNAaR137m f4aWv49ImbA/Tkv8VmoKX279oD8wPQYJKoZIhvcNAQkOMTAwLjAsBgNVHREEJTAj gg5jbG91ZGZsYXJlLmNvbYIRd3d3Y2xvdWRmbGFyZS5jb20wCgYIKoZIzj0EAwQD gYwAMIGIAkIA8OX9LxWOVnyfB25DFBz6JkjhyDpBM/PXlgLnWb/n2mEuMMB44DOG pljDV768PSW11AC3DtULoIyR92z0TyLEKYoCQgHdGd6PwUtDW5mrAMJQDgebjsxu MwfcdthzKlFlSmRpHMBnRMOJjlg5f9CTBg9d6wEdv7ZIrQSO6eqQHDQRM0VMnw== -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/ed25519.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBFzCBygIBADBqMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW MBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEUMBIGA1UEChMLZXhhbXBsZS5jb20xGDAW BgNVBAMTD3d3dy5leGFtcGxlLmNvbTAqMAUGAytlcAMhAIvEIdwMxpLmXW+ZKI+u hb4/H/1qaEOCSbWmWF95m1HzoC0wKwYJKoZIhvcNAQkOMR4wHDAaBgNVHREEEzAR gg93d3cuZXhhbXBsZS5jb20wBQYDK2VwA0EA/FCjbBOJT6z5wdBLgCJb3WrQGO9E lOizNutfEk9NlGJliNKkdZO3SZP9Uw/pKHiyxH+vWfUJ3E1DbtTVzmH8DA== -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/ex.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBnzCCAQgCAQAwXzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMQ8wDQYDVQQH DAZJdGhhY2ExHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQxFDASBgNVBAMM C2V4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBPmzv1c1e QAa1yTtJ45oPOCARrhqDYV66urzNX1zHDZzi4lruIfI3q+1McACs4FIGJAkBUC2O ZCamsR6ym5PaL9+dGfgVvf6w/GoBb65bxuw/IgHnzhfEHsk9nV8WthTEHmT9m9lh kPMZBVDIVFW6iOCCpAwR6I9XXB30oKTINwIDAQABoAAwDQYJKoZIhvcNAQELBQAD gYEAndd8OjJ+Jr74jqwuV9cUDqlItsLc84TYn+lly0EPezGQIIYz2KUoDyHQ+PQ9 7JI3G3FWR8Wpow7HooLJRxHNWOw7u8ekLCP0LjkoHse+Dou5C0jzo99jfrjXNWGt DZO0Wrpu2eDclqwMJO/DtiovzcmOsGC52NHUW6+Moo9N2lM= -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/inter_pathlen_0.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIH4MIGfAgEAMBsxGTAXBgNVBAMTEFBhdGhsZW4gMCBJc3N1ZXIwWTATBgcqhkjO PQIBBggqhkjOPQMBBwNCAASpwsWOMhWxFRhj5Kejzx9oqsxaTR8sElCDHBALtYEy 8eBZ7znb9cLWlJ8Kx6Jlw1pY7R7Ys9J9SuJ5jaBIBib1oCIwIAYJKoZIhvcNAQkO MRMwETAPBgNVHRMECDAGAQH/AgEAMAoGCCqGSM49BAMCA0gAMEUCIQDVsX+lxlvu JDEDEDnaVtN5NhxDYsomk9DpJwwoCa+A8wIgMboDaCkxGh4z+LejGkP+JvNKPX5E 0mlgWQaOp/5qfbI= -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/inter_pathlen_1.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIH5MIGfAgEAMBsxGTAXBgNVBAMTEFBhdGhsZW4gMSBJc3N1ZXIwWTATBgcqhkjO PQIBBggqhkjOPQMBBwNCAARJV1R1nX2e3Ev2NxG9V9R67Gkg1T0VSXargQSUhHQj ZNyYaoUKkke6lL3sG7H2t8yoC0AJcE5r30OWQoK1rB8goCIwIAYJKoZIhvcNAQkO MRMwETAPBgNVHRMECDAGAQH/AgEBMAoGCCqGSM49BAMCA0kAMEYCIQCJdPdRGltY hIvSBob0vcb5JmQEVByxLwKrWAivXDvMfAIhAP8fO0+Xkx0rNB9KnINeZtMGYy3X tk1GxikrK7klEnvN -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/inter_pathlen_unspecified.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIH3MIGfAgEAMB4xHDAaBgNVBAMTE1BhdGhsZW4gVW5zcGVjaWZpZWQwWTATBgcq hkjOPQIBBggqhkjOPQMBBwNCAAS01AiSXS4086rrC0SvnEoKz+tAj5+oAXomw/DQ PljnAeMdUvYSa0HxIoszeSGyx6prN3VnfuR/1nMRGtXAQGREoB8wHQYJKoZIhvcN AQkOMRAwDjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCIHPU8Jml1HUc L7v5mp4/njpWoVxPH0XkPYwdgk7nUnOZAiAaS3MpwrXz/l5v550T5nilkomRWeeX BdXmSA24AN562A== -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/ip.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBlTCB/wIBADBWMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTlkxDzANBgNVBAcM Bkl0aGFjYTEQMA4GA1UECgwHQ29ybmVsbDEXMBUGA1UEAwwOMTI4Ljg0LjEyNi4y MTMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAME+bO/VzV5ABrXJO0njmg84 IBGuGoNhXrq6vM1fXMcNnOLiWu4h8jer7UxwAKzgUgYkCQFQLY5kJqaxHrKbk9ov 350Z+BW9/rD8agFvrlvG7D8iAefOF8QeyT2dXxa2FMQeZP2b2WGQ8xkFUMhUVbqI 4IKkDBHoj1dcHfSgpMg3AgMBAAGgADANBgkqhkiG9w0BAQsFAAOBgQBS7FBieNEN PfXQRhPeiZ86QatshBBrj+TmhdC4GjtJ9lQA2NSRg2HnSHDErxdezZ7tw1ordd5D hZpJ8XkPggsb7mghwPD7Zzgp0M/ldqbZ9fFEtNcpiEL05vKtap5uSGzNn32NDbQa g+4QnDavffTQuzfuOoGJ9bG3jQtxo9HZCA== -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQCbp/6OQ/a3mr+8zRgBRlmSGr8QBgP4vUIxLn2Mk4uiZ8OcpRY4 YqL+TtREGDUc0ve+bv8RINrNlYXL2X+eJtbE2RJQ+RAiu+saw2K+RFTNeTCA1fwg 3ws5gBDcFbECqK1dOkuN/gV4JMHobn2/15iUBfeSJxdF1j5yqES8sVu7cwIDAQAB AoGBALZOnnBV3aLRlnw04kar9MCQnvLPeNteHyanQtjg/oxqZ8sR9+J2dFzSSv6u M5bc6Nmb+xY+msZqt9g3l6bN6n+qCvNnLauIY/YPjd577uMTpx/QTOQSK8oc5Dhi WgdU8GCtUmY+LE8qYx2NFitKCN4hubdrI76c+rnezIPVncZRAkEA9T5+vlfwk/Zl DOte+JtbXx3RtXKFJPMirOFqNVp1qnIlUm8XtBW6760ugiNYbVbGHgbd8JsZnkPH NC17TNLVJwJBAKJ7pDlJ2mvVr0cLrFhjAibz45dOipt8B4+dKtDIEuqbtKzJCGuP SCk4X2SgYz0gC5kH62S7rn6Bsa9lM98dztUCQASdLWNFYkhWXWZV006YFar/c5+X TPv5+xAHmajxT79qMFuRrX983Sx/NJ3MLnC4LjgIZwqM0HmSyt+nb2dtnAcCQCKi nIUhuw+Vg0FvuZM1t7W581/DfERckfgJFqFepLmh60eRqtvStR0kSSFYFw9mj1JV n9XfM/j/iHLM7du3rOkCQAw9R64yjcIBwcoSQxW/dr0Q9j+SnYgt+EhyXYXT30DS DdOJ06GXtb/P0peFBp26BnQU4CSS75yseZ1TdB4ZqaA= -----END RSA PRIVATE KEY----- ================================================ FILE: signer/local/testdata/rsa-old.csr ================================================ -----BEGIN NEW CERTIFICATE REQUEST----- MIIDCTCCAfMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTWdoYxX4KN51fP WxQAyGH++VsPbfpAoXIbCPXSmU04BvIxyjzpHQ0ChMKkT/2VNcUeFJwk2fCf+ZwU f0raTQTplofwkckE0gEYA3WcEfJp+hbvbTb/2recsf+JE6JACYJe2Uu5wsjtrE5j A+7aT2BEU9RWzBdSy/5281ZfW3PArqcWaf8+RUyA3WRxVWmjmhFsVB+mdNLhCpW0 C0QNMYR1ppEZiKVnEdao8gcI5sOvSd+35t8g82aPXcNSPU6jKcx1YNUPX5wgPEmu +anfc9RliQbYqqJYVODgBmV8IR5grw93yTsODoWKtFQ4PKVlnt9CD8AS/iSMQYm3 OUogqgMCAwEAAaA/MD0GCSqGSIb3DQEJDjEwMC4wLAYDVR0RBCUwI4IOY2xvdWRm bGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAsGCSqGSIb3DQEBCwOCAQEAl809 gk9uZkRK+MJVYDSLjgGR2xqk5qOwnhovnispA7N3Z1GshodJRQa6ngNCKuXIm2/6 AxB9kDGK14n186Qq4odXqHSHs8FG9i0zUcBXeLv1rPAKtwKTas/SLmsOpPgWPZFa iYiHHeu4HjOQoF987d7uGRYwc3xfstKwJsEXc12eCw2NH8TM1tJgSc/o6CzIpA91 QnZKhx6uGM4xI2gnOaJA1YikNhyFGBuOGMZgd0k2+/IcR2pg0z4pc5oQw1bXLANx anqlA/MDrCM9v9019bRJ73zK8LQ3k/FW61PA9nL7RZ8ku65R+uYcVEdLa8pUeqnH cJZNboDRsItpccZuRQ== -----END NEW CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/rsa2048-inter.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIDCjCCAfQCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOLFLykOd2j31AQn kaToYtstGvw5wLb4YnlzipQ6aULlD0H0GHM9IwhdSmcTWUWPb/U83g/ma1uD3Pp2 IdWd6xfjyOJF5XhgkyfRY65wS6vPZRm2MNSFXem+0AKHdhxIhb/QPMASqC/yaiPi nvtOpBiCNl1Q2N4y9pkV0oD/T4rrn3RXP6iL1k4CNRS54JPCd+aI5Om+axVPU8Id ZeUXQwXISaFrcC/bFXAHGX5hBMVu34lhCxvR4smweZkVmW++bIv26az8TSb5nVn4 TstLJIaOoOqot0sis04+0oX/GXfTPfkWyzfTVFN7cb9H+gz0FZJKtXQZv6qdntji 9FdR+pkCAwEAAaBAMD4GCSqGSIb3DQEJDjExMC8wLQYDVR0RBCYwJIIOY2xvdWRm bGFyZS5jb22CEnd3dy5jbG91ZGZsYXJlLmNvbTALBgkqhkiG9w0BAQsDggEBABfM 9XTMqMqmfAAymWC4/W+vbh301KBoydcTnDQ/7B+ftHRE0O3FUsdL3wobj3qBieJo MiQwiL7+GksszHvN9+YOUi70wpFuKghLhadb7p5GzL0+JgK2eQnLYb37/lQSiWwn hht1YMOzErR/KHlxNUafk71bDEeytUcOvvtujf86nZiEnBpvp47zDjMkDersczM0 wj7S50IY8/vRsc2Q8vy+Q7D2FPEwjs4wCGVSqzwX2NPn3fZb/2pWRCie9kxHUfUP L5xO4WoFGuirT6E2GnUWDdH661Pj5yEKvmr+qPl+eVoLjrtx0g5rAmA7rGlGrkqp r4idH/BbJUaDlRHM/Hk= -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/rsa2048-inter.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEA4sUvKQ53aPfUBCeRpOhi2y0a/DnAtvhieXOKlDppQuUPQfQY cz0jCF1KZxNZRY9v9TzeD+ZrW4Pc+nYh1Z3rF+PI4kXleGCTJ9FjrnBLq89lGbYw 1IVd6b7QAod2HEiFv9A8wBKoL/JqI+Ke+06kGII2XVDY3jL2mRXSgP9PiuufdFc/ qIvWTgI1FLngk8J35ojk6b5rFU9Twh1l5RdDBchJoWtwL9sVcAcZfmEExW7fiWEL G9HiybB5mRWZb75si/bprPxNJvmdWfhOy0skho6g6qi3SyKzTj7Shf8Zd9M9+RbL N9NUU3txv0f6DPQVkkq1dBm/qp2e2OL0V1H6mQIDAQABAoIBAQCzT3HcCAlZoeUu p88dU3efkUnuOQhuZXcQS9E/JfTHpXHsF8Qhky0ZVxMW8BC91Q6VHt0EO5GWWm0o SrK0Q9t6F25npRcumUaizIoCi9756tMpgouX8CDzTCMUbOJyuNGxe0oeImKFDyzo VTCazHMqwgOUw/HHuQqOv9ekkrzlva8U+Z5MGZB4B2acHIAJHO9uYGzdeAjF3grm dQ3QFGXJM0JzPmXfnUiDeOWIoVbo4YROFhf7qNlcnyLdkrYe0/XsSYQM9dRGKRPK nkOkMv0sC8rOqNuJUn3tf1OOjzVQxlzB8Key6MOQ1c+kqsdCnL88/93CvI5NHazx hwUmesmBAoGBAPpkDtgeWjxeIjOfuxXDYb04XbVmKquKNOIEk5OADmaacSGzdemh XLRaNVMEYMcgMJViDDKW8g4k+zuZgzooMxNynlLNU5wfazwX2LLjReJFvZb/SxMM N9+vQo8fcGz+p5g1tbeE6w86mpsTiAGx9Wa4J4GnY8jF6XUjZHO0X91pAoGBAOfZ qrDkPMDSiVk62FP6LlPrj09bt1NTkBfv5dWhN/XeHjuus7unDhNiRmphhgF0VZse XPtT/PUO0YgYlyaYJDDDE0IxgHuoK9wvEb2sqEtkZSw7IUhehheZ/+YfXzSA5fwa vhXt0ghB0d9oVJuRoxb17MncjpjDAKy0QR5drR2xAoGBAMlNwkVseZ2JDLQ2WgHQ N/cZpvUc83dAQO3pQgBW9rz0s7mlf0naqh5xW+enYGsW7RhcYHQXuPk4MCelbsRF 53JeNv1ZCDw/YkZI4bZIVDnrWdZY3zGsJAuY6skIPKnUPkd3/uVRXm267ut4U2MR gLsZmOF7AxU6UEwVrT/8pwnpAoGAKxbVFlMUx3FZfW/mTJUujwI0fDc7dw0MtqYr POzdjaBeVhE97h46C3g0Rgkh8ptAXbfi6ALP/GtonbaUQOP9teJLbf3tNw4mOKG2 1l2EWZ6q/vFuWhjXKwO//3DNLODX3WbK9SBh7I7vBmpJbzA980J5Y3rONa3oLjDB +XbHecECgYEArOEv2D3fE3Hd6rEbxXinqekxMa+V1OCDO1IPz4wwr9RDMVUMxwqF f0es1PQ2eMJGrAMbySxPfSZG05ou/tA+zR0qPwc/+dX0BbaXCiNT3gbhvL1L2fBc 7wr+MIUe2fi54JUWrUNMDHngRhXRKt2rZZRTfqVaFmZX02Y3fMZ2dWg= -----END RSA PRIVATE KEY----- ================================================ FILE: signer/local/testdata/rsa2048.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIDCTCCAfMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTWdoYxX4KN51fP WxQAyGH++VsPbfpAoXIbCPXSmU04BvIxyjzpHQ0ChMKkT/2VNcUeFJwk2fCf+ZwU f0raTQTplofwkckE0gEYA3WcEfJp+hbvbTb/2recsf+JE6JACYJe2Uu5wsjtrE5j A+7aT2BEU9RWzBdSy/5281ZfW3PArqcWaf8+RUyA3WRxVWmjmhFsVB+mdNLhCpW0 C0QNMYR1ppEZiKVnEdao8gcI5sOvSd+35t8g82aPXcNSPU6jKcx1YNUPX5wgPEmu +anfc9RliQbYqqJYVODgBmV8IR5grw93yTsODoWKtFQ4PKVlnt9CD8AS/iSMQYm3 OUogqgMCAwEAAaA/MD0GCSqGSIb3DQEJDjEwMC4wLAYDVR0RBCUwI4IOY2xvdWRm bGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAsGCSqGSIb3DQEBCwOCAQEAl809 gk9uZkRK+MJVYDSLjgGR2xqk5qOwnhovnispA7N3Z1GshodJRQa6ngNCKuXIm2/6 AxB9kDGK14n186Qq4odXqHSHs8FG9i0zUcBXeLv1rPAKtwKTas/SLmsOpPgWPZFa iYiHHeu4HjOQoF987d7uGRYwc3xfstKwJsEXc12eCw2NH8TM1tJgSc/o6CzIpA91 QnZKhx6uGM4xI2gnOaJA1YikNhyFGBuOGMZgd0k2+/IcR2pg0z4pc5oQw1bXLANx anqlA/MDrCM9v9019bRJ73zK8LQ3k/FW61PA9nL7RZ8ku65R+uYcVEdLa8pUeqnH cJZNboDRsItpccZuRQ== -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/rsa3072.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIECTCCAnMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAL0zzgBv+VTwZOPy LtuLFweQrj5Lfrje2hnNB7Y3TD4+yCM/cA4yTILixCe/B+N7LQysJgVDbW8u6BZQ 8ZqeDKOP6KCt37WhmcbT45tLpHmH+Z/uAnCz0hVc/7AyJ3CJXo6PaDCcJjgLuUun W47iy4h79AxyuzELmUeZZGYcO8nqClqcnAzQ6sClGZvJwSbYg2QAFGoA2lHqZ9uN ygAxNLd+rX9cP+yFwAeKzuKtOnVPiJD5lT3wufSkAbd6M7lOoqmTYnbv0A1WfA/e upXno9lbgB6iwF5U0V7OtxdA1bTbvgJgNLlxFF1do0sB28CWmqCFNwLfzcPzt5A4 gLnOyLhNZOmUMXn35KOtp1Zv/yethlgZHxUYGcl6OYwMEFye3Du6dgnTwONzaLhA 7hMI8R60p2YrTLkgSKdFohAY/mKuxHyXxugOHHthlRCOn9m49edcdZ1HrkJXm9jd P9katjCXgTwSdTQlvaMJkfH7wF3ZMjAxPcDf4RKFEpF2wABeNQIDAQABoD8wPQYJ KoZIhvcNAQkOMTAwLjAsBgNVHREEJTAjgg5jbG91ZGZsYXJlLmNvbYIRd3d3Y2xv dWRmbGFyZS5jb20wCwYJKoZIhvcNAQEMA4IBgQBF/RCHNAAOAaRI4VyO0tRPA5Dw 0/1/pgmBm/VejHIwDJnMFCl9njh0RSo1RgsVLhw6ovYbk3ORb4OD4UczPTq3GrFp KP9uPR+2pR4FWJpCVfCl76YabQv6fUDdiT7ojzyRhsAmkd5rOdiMvWV3Rp+YmBuU KH/dwkukfn+OeJIbERS5unzOBtQL+g5dU4CHWAqJQIqHr373w38OlYN+JY9QLrYy sWU9Ye6RjdySXPJ5UzyfOEfc9Ji89RJsVeceB1+As5u5vBvtzGgIMSFUzN947RZo DZ48JiB71VpmKXbn9LIRn25dlbVMzxRdSeZ194L3JFVAf9OxJTsc1QNFhOacoFgy hqvtN2iKntEyPo2nacYhpz/FAdJ2JThNH+4WtpPWAqx8Lw/e1OttiDt+6M0FEuVz svkSHnK206yo+a9Md37nUDDYxtlJEB+9F2qUZNQ7Hv+dxjmJOIgHOXxy1pLEdpVU rGdGLVXeJNPCh9x+GK21QjdxZABmYAaF8k36Pv4= -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/rsa4096.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIFCTCCAvMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANkKL22jMn3eFCpj T6lbeq4nC3aEqwTGrLARidAmO29WIhzs6LxRpM6xSMoPI6DvJVUGpMFEKF4xNTc5 X9/gSFrw2eI5Q3U3aGcaToSCxH4hXejwIzX8Ftlb/LfpXhbSsFr5MS3kiTY4zZxM n3dSy2gZljD/g0tlQf5BdHdR4WKRhWnqRiGng+BmW4rjbcO7SoN33jSXsMcguCg5 8dmYuf5G5KVXsqwEoCQBeKGnca9orcm4i90VnGt4qZUpfAn1cADzYGpRzX79USJ6 tol4ovgGPN08LJFqcVl+dK8VzJ03JWBhI1jePbWS4Bz5oNtkhQQXilU+G6FQxc6a UPf6KcFyOB+qMJmEwJZD9yaNK1YbsKfSztQEsb1JEezQnVHxp91Ch3AcWoikuOiY yCg0V5lcK15SLv1+5sj9YzF7ngMmThcIJ6B5gS3swpD5AX6FJaI1BrGwT/RXKKQP tRX1BySLx8RcINjFb5wv3q9QIE8vrW1BOk9f4dfmxiFYnc+6bCCbIrg7APQVtKTa ixNJFSqZz7fm9loeNPHHXfUT5RoW5yzVa8igc+yv4qeYsWHcZ4c/Y91OJp19HMjM bYm2alt8XagBgJjO0FW8wvsKwhhlhWK0WO6sQ7Fkl7fH1GtxEpc248hAW24SZMmS led3LblCT8IC3a9BLhqJ2q8cfPp9AgMBAAGgPzA9BgkqhkiG9w0BCQ4xMDAuMCwG A1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3d3djbG91ZGZsYXJlLmNvbTALBgkq hkiG9w0BAQ0DggIBAAgz3NuN43+F+8+WhQ9hb7DOp6Amut7XubOkEBtBVgP3R8U1 uSsgocR1rvnZ1/bhkeGyTly0eQPhcSEdMo/GgIrcn+co0KLcDyV6Rf3Cgksx9dUZ TzHSkxmFkxlxYfIGes6abH+2OPiacwK2gLvvmXFYIxEhv+LKzzteQi0xlinewv7R FnSykZ4QialsFyCgOjOxa11aEdRv6T8qKwhjUOk0VedtzOkt/k95aydTNLjXl2OV jloeTsbB00yWIqdyhG12+TgcJOa0pNP1zTjgFPodMuRUuiAcbT7Mt7sLCefKNzvZ Ln6b4y7e6N3YLOHALTIP+LI4y8ar47WlXCNw/zeOM2sW8udjYrukN6WOV3X68oMf Zsv6jqyGSaCDwdImR4VECUVvkabg9Sq4pz+ijTT+9cNA66omYL+/QAh0GahlROgW kDGI8zeEUoAC8RkAbFGMJA8jEbAfbT000ZwnLX2SZ8YRQX4Jd1FTmAH99FkvvT8N ovaGRSQQI5rWQGQYqF67So7PywEaEXeUHTBrv41Msva6CdaWHn7bh/fj4B21ETS7 VJvrk5DLJTyruqon7EVJU1pn38ppaXF4Z6a9n3C8TqudT/gdJUYn/SBo5jx20uGJ d9k6vDqixntvk/TRZ848k1AXiv5uUJTdnoPPhzSGjxEaeKuB0R1ZHomVdjU4 -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/san_domain.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIDATCCAekCAQAwQTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQH DA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQLDARBQ01FMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAy5owAK9W3y4RBV6T0/z1/Tnwj/jeI8APpLIszT1c1QY8 GssT0SuSF6l2KsIotWrjIHYgxjPU914moacJ90lluJ467QtrBLvcT8HMd6771olL CYxw6AlDLUcIN7paegaBVrKoxZ2daFBeu4bfRD4AiuaOOXZd7NjAb/EX+KKehWgM svkrxXSqgOgpo46Dm9bvNxnX6PS2PF11C7Mwz48YAbec2wyajXtQSIwVOSuHNikW juy9DPMq6lcmgMLFQftZLMUY4qf27JBTstbpLVc9kqWeJYemmBblUVN+54oQD+YQ GkZrfzAOe+TVGcdu8cTQL+roK9bpxxAKCG//VzEh9QIDAQABoHsweQYJKoZIhvcN AQkOMWwwajAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DBQBgNVHREESTBHgg5rYi5l eGFtcGxlLmNvbYIUaGVscGRlc2suZXhhbXBsZS5vcmeCE3N5c3RlbXMuZXhhbXBs ZS5uZXSHBMCoAQGHBMCoRQ4wDQYJKoZIhvcNAQEFBQADggEBAJ/0z/+f2sqzZIB8 GoOHAEa0xslNW/3igoKM8iO6H3bylHNeB2sBAgfgppGVNItu2QkVnP/eYfZXLD91 Fj44evp9L8PBIM1/pxaEUqMXNTRXgnshyq6tUc1akD7rA6CkF/v0OsyYLhxMvQBP A9hjw1CDmfX9djSot9GCVjoWFY8Vi+SvkyopWhtJ5+k8MvMMdgptShAguu3OZkSh 39KG2jAPr5PFuE2BceJafECyvUqt+gNjp7x++oTRivx6W+E4GvZQ2yAy5MSuraUb ZplmAEZckDkXZOc2bHoDwQubFTwyGW0dgqknTp9abBBdxtt04sVQCpWM3NfBYOlV SSEZghc= -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/local/testdata/test.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIC0TCCAbsCAQAwVDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNsb3VkRmxhcmUx DDAKBgNVBAsTA1dXVzEPMA0GA1UEBxMGSXRoYWNhMREwDwYDVQQIEwhOZXcgWW9y azCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANRGyaKqITV+IdyBWQ5y 2cDjWdDCq2sfv1YVQ720GnsdWgC+v3HcAV1+LxU/7LYbGeHIDsx7XcnbY1fWWvCt knf/1eW0dGgyDPinrZuZKrldO/48I1mdCcb2MujolwjEj0yzczTeqi3jWMo0NdvX mVprMkmz9FGwRgMbmXEyfmaG7/qgn/nG/zP0dikrYuR+WNbBPIIDuDIVHPHIln+7 H5SNLmgVr+q5V9Pqt1DdOBf3Zwo0KyLQa4LDxzQzQ62LNWYG+AtPSb6VVt/ZWtsx vd2WrE875UGM1wgCfU6g0XaQs+8xblOteMRaqpVKqw/frpeoG9W8bdJhtiL2DqqN wKsCAwEAAaA6MDgGCSqGSIb3DQEJDjErMCkwJwYDVR0RBCAwHoILZXhhbXBsZS5j b22CD3d3dy5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEBAB7fimhMshyrk/sk BQIKtsOHCFFAEyj0A/mfJO7Cx2Ys16s+u+EOv6eyJssePBb+XyM9a253bt6nKL4y wETMnp98f2svsaVLZC1BzmVRxfraJzgP5J8m2L0eCYTMd920KpEx7iyCqyeoHRCs 1P8H7z0Azrx2D/dfNw1L+5VUT1Hm8xFFzke7WdwlTxYhIhe2Hds0xqDLoZK765xx tLOKmrcVE/5ZcSkL/APFXX1U87vAeECMl/KTtGYw8lLjS6mXfN3sPNk8aw2VcV0U n0ZaV96ppWUQHsBWvkomj7829QLn9yalrqdz0F49ni562d4rIuogCSdUGawpEJfN 8xnNVaU= -----END CERTIFICATE REQUEST----- ================================================ FILE: signer/remote/remote.go ================================================ package remote import ( "crypto/x509" "encoding/json" "errors" "net/http" "github.com/cloudflare/cfssl/api/client" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/config" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/info" "github.com/cloudflare/cfssl/signer" ) // A Signer represents a CFSSL instance running as signing server. // fulfills the signer.Signer interface type Signer struct { policy *config.Signing reqModifier func(*http.Request, []byte) } // NewSigner creates a new remote Signer directly from a // signing policy. func NewSigner(policy *config.Signing) (*Signer, error) { if policy != nil { if !policy.Valid() { return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } return &Signer{policy: policy}, nil } return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } // Sign sends a signature request to the remote CFSSL server, // receiving a signed certificate or an error in response. The hostname, // csr, and profileName are used as with a local signing operation, and // the label is used to select a signing root in a multi-root CA. func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) { resp, err := s.remoteOp(req, req.Profile, "sign") if err != nil { return } if cert, ok := resp.([]byte); ok { return cert, nil } return } // Info sends an info request to the remote CFSSL server, receiving an // Resp struct or an error in response. func (s *Signer) Info(req info.Req) (resp *info.Resp, err error) { respInterface, err := s.remoteOp(req, req.Profile, "info") if err != nil { return } if resp, ok := respInterface.(*info.Resp); ok { return resp, nil } return } // Helper function to perform a remote sign or info request. func (s *Signer) remoteOp(req interface{}, profile, target string) (resp interface{}, err error) { jsonData, err := json.Marshal(req) if err != nil { return nil, cferr.Wrap(cferr.APIClientError, cferr.JSONError, err) } p, err := signer.Profile(s, profile) if err != nil { return } server := client.NewServerTLS(p.RemoteServer, helpers.CreateTLSConfig(p.RemoteCAs, p.ClientCert)) if server == nil { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("failed to connect to remote")) } server.SetReqModifier(s.reqModifier) // There's no auth provider for the "info" method if target == "info" { resp, err = server.Info(jsonData) } else if p.RemoteProvider != nil { resp, err = server.AuthSign(jsonData, nil, p.RemoteProvider) } else { resp, err = server.Sign(jsonData) } if err != nil { return nil, err } return } // SigAlgo returns the RSA signer's signature algorithm. func (s *Signer) SigAlgo() x509.SignatureAlgorithm { // TODO: implement this as a remote info call return x509.UnknownSignatureAlgorithm } // SetPolicy sets the signer's signature policy. func (s *Signer) SetPolicy(policy *config.Signing) { s.policy = policy } // SetDBAccessor sets the signers' cert db accessor, currently noop. func (s *Signer) SetDBAccessor(dba certdb.Accessor) { // noop } // GetDBAccessor returns the signers' cert db accessor, currently noop. func (s *Signer) GetDBAccessor() certdb.Accessor { return nil } // SetReqModifier sets the function to call to modify the HTTP request prior to sending it func (s *Signer) SetReqModifier(mod func(*http.Request, []byte)) { s.reqModifier = mod } // Policy returns the signer's policy. func (s *Signer) Policy() *config.Signing { return s.policy } ================================================ FILE: signer/remote/remote_test.go ================================================ package remote import ( "bytes" "crypto/tls" "crypto/x509" "fmt" "math/big" "net/http" "net/http/httptest" "os" "testing" "time" apiinfo "github.com/cloudflare/cfssl/api/info" apisign "github.com/cloudflare/cfssl/api/signhandler" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/helpers/testsuite" "github.com/cloudflare/cfssl/info" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/local" ) const ( testCaFile = "testdata/ca.pem" testCaKeyFile = "testdata/ca_key.pem" testServerFile = "testdata/server.pem" testServerKeyFile = "testdata/server-key.pem" testClientFile = "testdata/client.pem" testClientKeyFile = "testdata/client-key.pem" ) var validMinimalRemoteConfig = ` { "signing": { "default": { "remote": "localhost" } }, "remotes": { "localhost": "http://127.0.0.1:80" } }` var validMinimalAuthRemoteConfig = ` { "signing": { "default": { "auth_key": "sample", "remote": "localhost" } }, "auth_keys": { "sample": { "type":"standard", "key":"0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "http://127.0.0.1:80" } }` func TestNewSigner(t *testing.T) { remoteConfig := testsuite.NewConfig(t, []byte(validMinimalRemoteConfig)) _, err := NewSigner(remoteConfig.Signing) if err != nil { t.Fatal("fail to init remote signer:", err) } } func TestNewAuthSigner(t *testing.T) { remoteAuthConfig := testsuite.NewConfig(t, []byte(validMinimalAuthRemoteConfig)) _, err := NewSigner(remoteAuthConfig.Signing) if err != nil { t.Fatal("fail to init remote signer:", err) } } func TestRemoteInfo(t *testing.T) { remoteServer := newTestInfoServer(t, false, nil) defer closeTestServer(t, remoteServer) remoteConfig := testsuite.NewConfig(t, []byte(validMinimalRemoteConfig)) // override with test server address remoteConfig.Signing.OverrideRemotes(remoteServer.URL) verifyRemoteInfo(t, remoteConfig) } func TestRemoteTLSInfo(t *testing.T) { remoteTLSInfo(t, false) } func TestRemoteMutualTLSInfo(t *testing.T) { remoteTLSInfo(t, true) } func remoteTLSInfo(t *testing.T, isMutual bool) { certPool, err := helpers.LoadPEMCertPool(testCaFile) if err != nil { t.Fatal(err) } var clientCA *x509.CertPool if isMutual { clientCA = certPool } remoteServer := newTestInfoServer(t, true, clientCA) defer closeTestServer(t, remoteServer) remoteConfig := testsuite.NewConfig(t, []byte(validMinimalRemoteConfig)) // override with full server URL to get https in protocol" t.Log("remote is:", remoteServer.URL) remoteConfig.Signing.OverrideRemotes(remoteServer.URL) remoteConfig.Signing.SetRemoteCAs(certPool) if isMutual { remoteConfig.Signing.SetClientCertKeyPairFromFile(testClientFile, testClientKeyFile) } verifyRemoteInfo(t, remoteConfig) } func verifyRemoteInfo(t *testing.T, remoteConfig *config.Config) { s := newRemoteSigner(t, remoteConfig.Signing) req := info.Req{} resp, err := s.Info(req) if err != nil { t.Fatal("remote info failed:", err) } caBytes, err := os.ReadFile(testCaFile) caBytes = bytes.TrimSpace(caBytes) if err != nil { t.Fatal("fail to read test CA cert:", err) } if bytes.Compare(caBytes, []byte(resp.Certificate)) != 0 { t.Fatal("Get a different CA cert through info api.", len(resp.Certificate), len(caBytes)) } } func TestRemoteSign(t *testing.T) { remoteServer := newTestSignServer(t, false, nil) defer closeTestServer(t, remoteServer) remoteConfig := testsuite.NewConfig(t, []byte(validMinimalRemoteConfig)) // override with test server address remoteConfig.Signing.OverrideRemotes(remoteServer.URL) verifyRemoteSign(t, remoteConfig) } func TestRemoteTLSSign(t *testing.T) { remoteTLSSign(t, false) } func TestRemoteMutualTLSSign(t *testing.T) { remoteTLSSign(t, true) } func remoteTLSSign(t *testing.T, isMutual bool) { certPool, err := helpers.LoadPEMCertPool(testCaFile) if err != nil { t.Fatal(err) } var clientCA *x509.CertPool if isMutual { clientCA = certPool } remoteServer := newTestSignServer(t, true, clientCA) defer closeTestServer(t, remoteServer) remoteConfig := testsuite.NewConfig(t, []byte(validMinimalRemoteConfig)) // override with full server URL to get https in protocol" remoteConfig.Signing.OverrideRemotes(remoteServer.URL) remoteConfig.Signing.SetRemoteCAs(certPool) if isMutual { remoteConfig.Signing.SetClientCertKeyPairFromFile(testClientFile, testClientKeyFile) } verifyRemoteSign(t, remoteConfig) } func verifyRemoteSign(t *testing.T, remoteConfig *config.Config) { s := newRemoteSigner(t, remoteConfig.Signing) hosts := []string{"cloudflare.com"} for _, test := range testsuite.CSRTests { csr, err := os.ReadFile(test.File) if err != nil { t.Fatal("CSR loading error:", err) } testSerial := big.NewInt(0x7007F) certBytes, err := s.Sign(signer.SignRequest{ Hosts: hosts, Request: string(csr), Serial: testSerial, }) if test.ErrorCallback != nil { test.ErrorCallback(t, err) } else { if err != nil { t.Fatalf("Expected no error. Got %s. Param %s %d", err.Error(), test.KeyAlgo, test.KeyLen) } cert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal("Fail to parse returned certificate:", err) } sn := fmt.Sprintf("%X", cert.SerialNumber) if sn != "7007F" { t.Fatal("Serial Number was incorrect:", sn) } } } } func TestRemoteSignBadServerAndOverride(t *testing.T) { remoteServer := newTestSignServer(t, false, nil) defer closeTestServer(t, remoteServer) // remoteConfig contains port 80 that no test server will listen on remoteConfig := testsuite.NewConfig(t, []byte(validMinimalRemoteConfig)) s := newRemoteSigner(t, remoteConfig.Signing) hosts := []string{"cloudflare.com"} csr, err := os.ReadFile("../local/testdata/rsa2048.csr") if err != nil { t.Fatal("CSR loading error:", err) } _, err = s.Sign(signer.SignRequest{Hosts: hosts, Request: string(csr)}) if err == nil { t.Fatal("Should return error") } remoteConfig.Signing.OverrideRemotes(remoteServer.URL) s.SetPolicy(remoteConfig.Signing) certBytes, err := s.Sign(signer.SignRequest{ Hosts: hosts, Request: string(csr), Serial: big.NewInt(1), }) if err != nil { t.Fatalf("Expected no error. Got %s.", err.Error()) } _, err = helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal("Fail to parse returned certificate:", err) } } // helper functions func newRemoteSigner(t *testing.T, policy *config.Signing) *Signer { s, err := NewSigner(policy) if err != nil { t.Fatal("fail to init remote signer:", err) } return s } func newTestSignHandler(t *testing.T) (h http.Handler) { h, err := newHandler(t, testCaFile, testCaKeyFile, "sign") if err != nil { t.Fatal(err) } return } func newTestInfoHandler(t *testing.T) (h http.Handler) { h, err := newHandler(t, testCaFile, testCaKeyFile, "info") if err != nil { t.Fatal(err) } return } func newTestServer(t *testing.T, path string, handler http.Handler, isTLS bool, certPool *x509.CertPool) *httptest.Server { mux := http.NewServeMux() mux.Handle(path, handler) ts := httptest.NewUnstartedServer(mux) if isTLS { cert, err := tls.LoadX509KeyPair(testServerFile, testServerKeyFile) if err != nil { t.Fatal(err) } clientCertRequired := tls.NoClientCert if certPool != nil { clientCertRequired = tls.RequireAndVerifyClientCert } ts.TLS = &tls.Config{ Certificates: []tls.Certificate{cert}, ClientCAs: certPool, ClientAuth: clientCertRequired, } ts.TLS.BuildNameToCertificate() ts.StartTLS() } else { ts.Start() } return ts } func newTestSignServer(t *testing.T, isTLS bool, certPool *x509.CertPool) *httptest.Server { ts := newTestServer(t, "/api/v1/cfssl/sign", newTestSignHandler(t), isTLS, certPool) t.Log(ts.URL) return ts } func newTestInfoServer(t *testing.T, isTLS bool, certPool *x509.CertPool) *httptest.Server { ts := newTestServer(t, "/api/v1/cfssl/info", newTestInfoHandler(t), isTLS, certPool) t.Log(ts.URL) return ts } func closeTestServer(t *testing.T, ts *httptest.Server) { t.Log("Finalizing test server.") ts.Close() } // newHandler generates a new sign handler (or info handler) using the certificate // authority private key and certficate to sign certificates. func newHandler(t *testing.T, caFile, caKeyFile, op string) (http.Handler, error) { var expiry = 1 * time.Minute var CAConfig = &config.Config{ Signing: &config.Signing{ Profiles: map[string]*config.SigningProfile{ "signature": { Usage: []string{"digital signature"}, Expiry: expiry, }, }, Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "43800h", Expiry: expiry, CAConstraint: config.CAConstraint{IsCA: true}, ClientProvidesSerialNumbers: true, }, }, } s, err := local.NewSignerFromFile(testCaFile, testCaKeyFile, CAConfig.Signing) if err != nil { t.Fatal(err) } if op == "sign" { return apisign.NewHandlerFromSigner(s) } else if op == "info" { return apiinfo.NewHandler(s) } t.Fatal("Bad op code") return nil, nil } ================================================ FILE: signer/remote/testdata/README.md ================================================ Instructions to generate client key/certificate ----------------------------------------------- Use CFSSL to generate the client certificate if they expire ``` cfssl gencert -ca=ca.pem -ca-key=ca_key.pem -config=config.json -profile=client client.json | cfssljson -bare client cfssl gencert -ca=ca.pem -ca-key=ca_key.pem -config=config.json -profile=server server.json | cfssljson -bare server ``` ================================================ FILE: signer/remote/testdata/ca.pem ================================================ -----BEGIN CERTIFICATE----- MIIDuTCCAqGgAwIBAgIUcOn8GUmkTPcEdhSLwG3YR8P9FBYwDQYJKoZIhvcNAQEL BQAwbDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNGU1NMIFRFU1QxGzAZBgNVBAMMEkNG U1NMIFRFU1QgUm9vdCBDQTAeFw0yNTAyMDgyMTM4MTNaFw0zNTAyMDYyMTM4MTNa MGwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T YW4gRnJhbmNpc2NvMRMwEQYDVQQKDApDRlNTTCBURVNUMRswGQYDVQQDDBJDRlNT TCBURVNUIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx GnXFJ8gOgP/jQGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLz cJnG6NQSIR8TSgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B 43WZDmqaKrEEx2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepP kxrTqZg+YgZiEhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMs lxiYkG9laPyD61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850R h1mTEjk1Y+Io1b9D4B5dAgMBAAGjUzBRMB0GA1UdDgQWBBS30veEuqg51fusEM4p /YuWpBPsvTAfBgNVHSMEGDAWgBS30veEuqg51fusEM4p/YuWpBPsvTAPBgNVHRMB Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBxK+nimCu++fe6S+LL2KSGjiNZ mMZd2B2RH8Ou9FWC+ZxDzY8sUj6uTl1qlwRSKG5mL/c/lhAHgViLu5fe88ZOkCS5 Gf2FlL7owhzmv8SkMr03YpNkOamB/tks28ikYdtxRaC1aQnEvwFzhTIsI27RnVUI YckIoAmDrPpmWtjUeoEugI32qQGWQh69gSwH5ycwhk+W/dNhR8xILvNz2PFKl7wN w2EX+I9saTT9Y/f/0AMu+AiS+KVK665BNHWK2AVS9wBDorAZ4fNPtq1Ar6f0ThmG 5Fhgxrhw6J3sWFlLFccSmVn3vMHiC3PyBfL0fAo5up+rxHginFuoPOKL7Aly -----END CERTIFICATE----- ================================================ FILE: signer/remote/testdata/ca_key.pem ================================================ -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGnXFJ8gOgP/j QGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLzcJnG6NQSIR8T Sgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B43WZDmqaKrEE x2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepPkxrTqZg+YgZi EhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMslxiYkG9laPyD 61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850Rh1mTEjk1Y+Io 1b9D4B5dAgMBAAECggEAKHhjcSomDSptTwDo9mLI/h40HudwSlsc8GzYxZBjinUD N2n39T9QbeMUE1xFenX/9qFEgq+xxnLLJx1EQacSapCgIAqdCO/f9HMgvGJumdg8 c0cMq1i9Bp7tu+OESZ5D48qWlOM2eQRIb08g8W11eRIaFmPuUPoKnuktkQuXpPJc YbS/+JuA8SDwe6sV0cMCQuS+iHFfeGwWCKrDUkhLwcL3waW3od2XFyOeFFWFhl0h HmM/mWKRuRdqR7hrmArTwFZVkB+o/1ywVYXIv+JQm0eNZ5PKLNJGL2f5oxbMR/JI AoK0bAlJmYaFp96h1KpbPwLEL/0hHSWA7sAyJIgQAQKBgQDaEAZor/w4ZUTekT1+ cbId0yA+ikDXQOfXaNCSh9Pex+Psjd5zVVOqyVFJ29daRju3d7rmpN4Cm5V4h0l1 /2ad207rjCAnpCHtaddJWNyJzF2IL2IaoCZQRp0k7zOjBGQpoWDTwBaEin5CCv3P kkdQkKz6FDP1xskHSLZr21/QCQKBgQDP6jXutEgGjf3yKpMFk/69EamJdon8clbt hl7cOyWtobnZhdOWVZPe00Oo3Jag2aWgFFsm3EtwnUCnR4d4+fXRKS2LkhfIUZcz cKy17Ileggdd8UGhL4RDrF/En9tJL86WcVkcoOrqLcGB2FLWrVhVpHFK74eLMCH/ uc/+ioPItQKBgHYoDsD08s7AGMQcoNx90MyWVLduhFnegoFW+wUa8jOZzieka6/E wVQeR5yksZjpy3vLNYu6M83n7eLkM2rrm/fXGHlLcTTpm7SgEBZfPwivotKjEh5p PrlqucWEk082lutz1RqHz+u7e1Rfzk2F7nx6GDBdeBYpw03eGXJx6QW5AoGBAIJq 4puyAEAET1fZNtHX7IGCk7sDXTi6LCbgE57HhzHr8V0t4fQ6CABMuvMwM1gATjEk s6yjoLqqGUUUzDipanViBAy5fiuManC868lN7zkWDTLzQ3ytBqVAee4na/DziP27 ae9YTSLJwskE/alloLRP6zTbHUXE0n7LelmrX1DFAoGBAMFLl+Lu+WFgCHxBjn43 rHpJbQZQmsFhAMhkN4hsj6dJfAGn2gRLRiVRAika+8QF65xMZiVQWUVSUZADWERi 0SXGjzN1wYxO3Qzy3LYwws6fxFAq5lo79eb38yFT2lHdqK3x/QgiDSRVl+R6cExV xQB518/lp2eIeMpglWByDwJX -----END PRIVATE KEY----- ================================================ FILE: signer/remote/testdata/client-key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA7hbVh/h56cdQwhH8YW/l4NnI3dQ5GrMmU/kwbYv1wCfC6ybj FohoHHMspUZmMRtfHmshMfsYpYLd2sGUAKbL4qxgzv+R843AcW0H4gp5z03TO9St YbGYYxFJKccKQuhYeOEUa2QQ30yX+R2qD4kd1rd7AswtEoRhy5sdk9SdyGnJ9+u/ n30PkitchkioolLhg41YwLtCHpMeAOGiz2M7jtt12XOM2jLn3rrWQyAKmB5Mh1T8 O5e+PWa+sy9GMrewVQvISNem363TntqpG2JfycgEqxOT9aEn5Imftug02mu3Dg3C a7AUDPuNqtOvNiwWXaUoUqhV7sR6vwpkY3HW6QIDAQABAoIBAQCKd8c6K/2jQ+Mo 61LvzCdSrPaQZNPNPnHFFsDehS6o0bcgEd6yhSSfnzBQ8u+OEdAxHbcRnWpJICIt DrYn5tne+8fVu3dDwaYxkWqrQNJ1CVsXiepITgRFYZE+dd726LBDpQu+JVVWuPIN 1P3JyUIMVWt6RgrUoR9LTexWxKn7GsRJR8/jkS51miE4whjk9IF4NKCKIsV39lPH XjzhKcX5+JIE3IHrZ7IbkHHwQaOQ4IxqisVTG7iw0jAAwaKpo+hYnWENxBsvZ3hC wWJHsPyDYuZSPQSS1Mlb/K+GXWrcCY8F+2TvfL0voO+Brh8zdl8gYOQPRdDe/MnP iMpEmZcBAoGBAPTlBwl9SbGoIQumEeci1W73FgnW3QrbA6VYtdmdyEqSccbfPe9q TDqN49IiYXWIA2MES7yU7sPQsyReAvh9koYkGGCEjldIQY6rfqrjT8i5/BhJm6i1 gRmU5u/E4zijt9duubaN3dZGajQw6YpUG/WoEp7BRtvf3AeewYGkhlNJAoGBAPji zXAGKKI4/uYmseKmfzKW2WC4eroOcN2rLFd6/7p7sZ/J1xu95VZEmvy8Kt+08Osk s49qy6ME2gQLWPjnLDQs15Z3OFGFvZvM5XCIm8svowWRFhSqYMnUvIP8RqatASj5 /eMvcwKRLWgnho8gsM9LGGosfil8/L3dhnUVJcahAoGADgFbGavUnxhia2wf8fwI AMSYug9TrN9Boh8kp0FixwEBCMKTpDGMEn0y3j2hHTueFfeU7UAHN6Oj2xyVRujH jGxcCIkMKumy9hnQsK03Tt90D1+GS2u16mSdoHC+HesfBG8Mp+gNG8gDIuD5OjP9 NVtbVUDwcHqo9raZknR6SiECgYBavK0zOzuTMP5VQCQ4QoU7F1328irkLCGf3ykS V6hl/3SZkceXuJqk4ewzWhKzbk8rGz1Pexr0uu8U7GIqlHU8LGEI3TwuFHk1FPVN GrDZ2eswO132eMtCqgl0gQPs/kPfAY07R3BBrlYEk+xtv/hWCsXC56ezTnsCaYH8 q5ITIQKBgQDFnr8j+2boqWG/6qm4cOfTwfT53NA3RL3h1wHew4Rx/1V90GF6FhgR ya31hw9UKQO+xYNrq1daVEyT3mSOy03PnkSS+p9SizK3O20V//bu+jy00BhbqHKN Fce/OXGzfSC0tRTfDQ8by/5bpfDzCIxBUa0xciS90t64du0wD+dk8Q== -----END RSA PRIVATE KEY----- ================================================ FILE: signer/remote/testdata/client.json ================================================ { "CN": "cfssl-client", "hosts": [ "" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "San Francisco", "O": "CloudFlare", "OU": "Systems Engineering", "ST": "California" } ] } ================================================ FILE: signer/remote/testdata/client.pem ================================================ -----BEGIN CERTIFICATE----- MIIEAzCCAuugAwIBAgIUdTh1VcpCV698YecqTUUrD1SXL8kwDQYJKoZIhvcNAQEL BQAwbDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNGU1NMIFRFU1QxGzAZBgNVBAMMEkNG U1NMIFRFU1QgUm9vdCBDQTAeFw0yNTAyMDgyMTQyMDBaFw0zMDAyMDcyMTQyMDBa MIGEMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lz dGVtcyBFbmdpbmVlcmluZzEVMBMGA1UEAxMMY2Zzc2wtY2xpZW50MIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7hbVh/h56cdQwhH8YW/l4NnI3dQ5GrMm U/kwbYv1wCfC6ybjFohoHHMspUZmMRtfHmshMfsYpYLd2sGUAKbL4qxgzv+R843A cW0H4gp5z03TO9StYbGYYxFJKccKQuhYeOEUa2QQ30yX+R2qD4kd1rd7AswtEoRh y5sdk9SdyGnJ9+u/n30PkitchkioolLhg41YwLtCHpMeAOGiz2M7jtt12XOM2jLn 3rrWQyAKmB5Mh1T8O5e+PWa+sy9GMrewVQvISNem363TntqpG2JfycgEqxOT9aEn 5Imftug02mu3Dg3Ca7AUDPuNqtOvNiwWXaUoUqhV7sR6vwpkY3HW6QIDAQABo4GD MIGAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDAjAMBgNVHRMB Af8EAjAAMB0GA1UdDgQWBBRAKewk7YKPCXMsb/Qfn04HmabtkTAfBgNVHSMEGDAW gBS30veEuqg51fusEM4p/YuWpBPsvTALBgNVHREEBDACggAwDQYJKoZIhvcNAQEL BQADggEBAKxlLcJqT/gMicxga0OIAHAZ+DgxtKLrV8HjSeBSMQL6bhOvoftjiDlb Q0ECyfax3ErWGDJNqz0208DOCBtGR5EcrQafQa18Hw9bxGwDxFydUJVQTkFSuMbv Jl7fcjEo0akyqjTzo5SbsOtgl2q2ZPcFgODed6qa7fKEiaNZcrj2qmxrIBuXC/AI 6R53vdyZYbve70RudD73GGRow8aHtJk0MSRi5N5stZGS4miYSvJsZCWIZ6wHvilv PkV760GaTfqxL5UXHTr6G9cgyNt+s6sLMkMQb6WqA+M/KxM28bq9MR80rmmkZ8TG I1QS3kdMEIkcxUDQV9yWRvd70Mc57yM= -----END CERTIFICATE----- ================================================ FILE: signer/remote/testdata/config.json ================================================ { "signing": { "default": { "expiry": "43800h" }, "profiles": { "client": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "client auth" ] }, "server": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth" ] } } } } ================================================ FILE: signer/remote/testdata/server-key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAuGKO/P24lXG0MRi/zuY7Cp8IwQaziqMl4ti+w7aHIY115JF5 SZOCwIzBtr7knxwmQC0CgoFWQn2f51GQsN/vO0g9CvnxFzcYRR4ARdlPNBUfvf9F +qhJVORMZ6j1ffwg88sJ6zu1scloDXbi7kkrsqVMnseNemvVHBeWuL3HCtR+ebOU 0Ixmey0OX2C5VsBqeyimadwgwiWQKR9TqxJ1KXrqYTvG9xbkxWierhXw3g0P8Bep M5VWvB55ypGWkyjE2D/RfNJQNEzNu51pBxVHPaFlMVLK/sCiEhpTUSEEQJP7SRtR IhW9iV46tfapdWyzfY6BkDuS0UAE787nss85BwIDAQABAoIBAAfa6wyMIpj7Rxnw W/uMg2dobw8KIgv991c6tKXR2N/tDuC18dzYk/FwDbCjYUoGAPsq77hvmiUrBOzt 5KQkZiS4ZyFYlJTQnBAVvx06rM0jOT726RxMnxMmxrqD0DGV1DGOrNWArbTtR6mL Lw/HvjzWHfWFutlETsfrmVg1fY1Qfa/THU1IoLQN0TOPQ3d3p6EjeCTknGRUtfP6 TB9lQj+aO3qJNR+ocrSrwyLImzaGAaoxojDPrlvvd05c375Z0/Id9zl6f48ei8Nw LHjpG6zM7AGN3hhthrYQVJxoYgaRlPFBhMRi+3hw4a2GcMhVgZPgVN492jb8rv1/ xhexRgECgYEA2F45OExSBmt4ITAs5buOFzuiqujJBe/er/fOCLUaKrjz1qdYgC9M ITUafunh0miJPHC5qyUbofLgGzCsM4aok4ZDIlJX2SdTGD5/4oH9V4GMP4eBKHQs mN///bgjk8RYCCGG2HyER8D1ZsnfTeKpGyF/Y1vD5rWprUQd430b9KECgYEA2iib oioxweyiG0UqYUr0yr1nylMo/iCpsS8YEZc39OeuZ6TrYF/ar0oG/WySMZxHqO9L QJVFs7iSbXiBEVT5v0MkK+qA+Lx2JM1xJ8u701Gqtk6wqJDZEO9wpR4Ilf28umm8 /xLi5Pb0vJh1Z2wLTiWaa1sYRbRC5/mO8eusJKcCgYBYpcol0cctkCyI1HcgrMZb qHhOM8/g2dVQHWRR1vlglaR5xtiQtFAprtsrMmHuVhwcIkc/4pU+tgaxvTBgcARz ZOfukPQjKWR3I2w7/mwwxQgUI018qJR5EhWM+zvAWAqFUk8wNVvxFhK1SXJvM7V7 Qy8xIzDRPo7FSYpBYUnp4QKBgEhoYf+Y8Zrj54oVktNoBYelBeXpZBm0zZ25e8ua 3T+0Bfbwjg8WwYack2VZu8wrir1PbzKoWNIl2LPs4ynVgm8w4biRxOzJ4Iymg4Ap 5tVkrbyEsa3BJcqxLjoflcnyxck5fzlKE3TbYq+WCqGhAr+VS4OGYLAB/JLyCbfR +PjRAoGBANATNIlYL0qL72m4AccXFnU0G6/Idi7Zx0cX0lcTOKe3HBtbjnhUkUaG pllJwbVWGWAOsfj4mKsaIWoDaHswenlSg6YUt4aK6rdfmDC7W2sfpdLocJ3pdVfV GIaSCDrlULpZLUHlmXdbZgEI9WlMfmZ80/DDwTFYheT+0ZJbQB6n -----END RSA PRIVATE KEY----- ================================================ FILE: signer/remote/testdata/server.json ================================================ { "CN": "CloudFlare server", "hosts": [ "cloudflare.com", "www.cloudflare.com", "127.0.0.1" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "San Francisco", "O": "CloudFlare", "OU": "Systems Engineering", "ST": "California" } ] } ================================================ FILE: signer/remote/testdata/server.pem ================================================ -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIUd6tO8qVnZO/2pxWUxglf3XV3MpAwDQYJKoZIhvcNAQEL BQAwbDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNGU1NMIFRFU1QxGzAZBgNVBAMMEkNG U1NMIFRFU1QgUm9vdCBDQTAeFw0yNTAyMDgyMTQzMDBaFw0zMDAyMDcyMTQzMDBa MIGJMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lz dGVtcyBFbmdpbmVlcmluZzEaMBgGA1UEAxMRQ2xvdWRGbGFyZSBzZXJ2ZXIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4Yo78/biVcbQxGL/O5jsKnwjB BrOKoyXi2L7DtochjXXkkXlJk4LAjMG2vuSfHCZALQKCgVZCfZ/nUZCw3+87SD0K +fEXNxhFHgBF2U80FR+9/0X6qElU5ExnqPV9/CDzywnrO7WxyWgNduLuSSuypUye x416a9UcF5a4vccK1H55s5TQjGZ7LQ5fYLlWwGp7KKZp3CDCJZApH1OrEnUpeuph O8b3FuTFaJ6uFfDeDQ/wF6kzlVa8HnnKkZaTKMTYP9F80lA0TM27nWkHFUc9oWUx Usr+wKISGlNRIQRAk/tJG1EiFb2JXjq19ql1bLN9joGQO5LRQATvzueyzzkHAgMB AAGjgaswgagwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwG A1UdEwEB/wQCMAAwHQYDVR0OBBYEFOCNRPyWGduIgabJFh4dhIAafM/DMB8GA1Ud IwQYMBaAFLfS94S6qDnV+6wQzin9i5akE+y9MDMGA1UdEQQsMCqCDmNsb3VkZmxh cmUuY29tghJ3d3cuY2xvdWRmbGFyZS5jb22HBH8AAAEwDQYJKoZIhvcNAQELBQAD ggEBAC3ePC0REiDDGiCa+YiiK5ymNAn5/MTqkKNaOUnDSYZnjfkNyj+DuVDTmbYA 3rTiHiMmz8LCIrh7x3sSt6pzCb1TxDE1stQhLcrNhGWA1gTbBNyWTYDh1JUaXJ8Z R8h7tHCNK2aIxSa3hFwAcdvIEkfw8E+MuncC97prPRt4UxtCAp/Bg0kQ93QCo4se D0Vcz8JyJWy+KqpQgFafAY73l15PG/7Gi13pBqwyUxSmVAlY+ggmrGz/8EqIrNgb 5SJ5rcSS3dChkBwOfGJwpba8PUEfVOSeTm2LntgJDoG0KSIhKk13HLF5e3VPnvw3 N3b8EndBKVvNb+wKuHBSs4MAwzs= -----END CERTIFICATE----- ================================================ FILE: signer/signer.go ================================================ // Package signer implements certificate signature functionality for CFSSL. package signer import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rsa" "crypto/sha1" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "math/big" "net/http" "strings" "time" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/info" ) // Subject contains the information that should be used to override the // subject information when signing a certificate. type Subject struct { CN string Names []csr.Name `json:"names"` SerialNumber string } // Extension represents a raw extension to be included in the certificate. The // "value" field must be hex encoded. type Extension struct { ID config.OID `json:"id"` Critical bool `json:"critical"` Value string `json:"value"` } // SignRequest stores a signature request, which contains the hostname, // the CSR, optional subject information, and the signature profile. // // Extensions provided in the signRequest are copied into the certificate, as // long as they are in the ExtensionWhitelist for the signer's policy. // Extensions requested in the CSR are ignored, except for those processed by // ParseCertificateRequest (mainly subjectAltName) and DelegationUsage. type SignRequest struct { Hosts []string `json:"hosts"` Request string `json:"certificate_request"` Subject *Subject `json:"subject,omitempty"` Profile string `json:"profile"` CRLOverride string `json:"crl_override"` Label string `json:"label"` Serial *big.Int `json:"serial,omitempty"` Extensions []Extension `json:"extensions,omitempty"` // If provided, NotBefore will be used without modification (except // for canonicalization) as the value of the notBefore field of the // certificate. In particular no backdating adjustment will be made // when NotBefore is provided. NotBefore time.Time // If provided, NotAfter will be used without modification (except // for canonicalization) as the value of the notAfter field of the // certificate. NotAfter time.Time // If ReturnPrecert is true a certificate with the CT poison extension // will be returned from the Signer instead of attempting to retrieve // SCTs and populate the tbsCert with them itself. This precert can then // be passed to SignFromPrecert with the SCTs in order to create a // valid certificate. ReturnPrecert bool // Arbitrary metadata to be stored in certdb. Metadata map[string]interface{} `json:"metadata"` } // appendIf appends to a if s is not an empty string. func appendIf(s string, a *[]string) { if s != "" { *a = append(*a, s) } } // Name returns the PKIX name for the subject. func (s *Subject) Name() pkix.Name { var name pkix.Name name.CommonName = s.CN for _, n := range s.Names { appendIf(n.C, &name.Country) appendIf(n.ST, &name.Province) appendIf(n.L, &name.Locality) appendIf(n.O, &name.Organization) appendIf(n.OU, &name.OrganizationalUnit) } name.SerialNumber = s.SerialNumber return name } // SplitHosts takes a comma-spearated list of hosts and returns a slice // with the hosts split func SplitHosts(hostList string) []string { if hostList == "" { return nil } return strings.Split(hostList, ",") } // A Signer contains a CA's certificate and private key for signing // certificates, a Signing policy to refer to and a SignatureAlgorithm. type Signer interface { Info(info.Req) (*info.Resp, error) Policy() *config.Signing SetDBAccessor(certdb.Accessor) GetDBAccessor() certdb.Accessor SetPolicy(*config.Signing) SigAlgo() x509.SignatureAlgorithm Sign(req SignRequest) (cert []byte, err error) SetReqModifier(func(*http.Request, []byte)) } // Profile gets the specific profile from the signer func Profile(s Signer, profile string) (*config.SigningProfile, error) { var p *config.SigningProfile policy := s.Policy() if policy != nil && policy.Profiles != nil && profile != "" { p = policy.Profiles[profile] } if p == nil && policy != nil { p = policy.Default } if p == nil { return nil, cferr.Wrap(cferr.APIClientError, cferr.ClientHTTPError, errors.New("profile must not be nil")) } return p, nil } // DefaultSigAlgo returns an appropriate X.509 signature algorithm given // the CA's private key. func DefaultSigAlgo(priv crypto.Signer) x509.SignatureAlgorithm { pub := priv.Public() switch pub := pub.(type) { case *rsa.PublicKey: keySize := pub.N.BitLen() switch { case keySize >= 4096: return x509.SHA512WithRSA case keySize >= 3072: return x509.SHA384WithRSA case keySize >= 2048: return x509.SHA256WithRSA default: return x509.SHA1WithRSA } case *ecdsa.PublicKey: switch pub.Curve { case elliptic.P256(): return x509.ECDSAWithSHA256 case elliptic.P384(): return x509.ECDSAWithSHA384 case elliptic.P521(): return x509.ECDSAWithSHA512 default: return x509.ECDSAWithSHA1 } case ed25519.PublicKey: return x509.PureEd25519 default: return x509.UnknownSignatureAlgorithm } } func isCommonAttr(t []int) bool { return (len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 && (t[3] == 3 || (t[3] >= 5 && t[3] <= 11) || t[3] == 17)) } // ParseCertificateRequest takes an incoming certificate request and // builds a certificate template from it. func ParseCertificateRequest(s Signer, p *config.SigningProfile, csrBytes []byte) (template *x509.Certificate, err error) { csrv, err := x509.ParseCertificateRequest(csrBytes) if err != nil { err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err) return } var r pkix.RDNSequence _, err = asn1.Unmarshal(csrv.RawSubject, &r) if err != nil { err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err) return } var subject pkix.Name subject.FillFromRDNSequence(&r) for _, v := range r { for _, vv := range v { if !isCommonAttr(vv.Type) { subject.ExtraNames = append(subject.ExtraNames, vv) } } } err = csrv.CheckSignature() if err != nil { err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err) return } template = &x509.Certificate{ Subject: subject, PublicKeyAlgorithm: csrv.PublicKeyAlgorithm, PublicKey: csrv.PublicKey, SignatureAlgorithm: s.SigAlgo(), DNSNames: csrv.DNSNames, IPAddresses: csrv.IPAddresses, EmailAddresses: csrv.EmailAddresses, URIs: csrv.URIs, Extensions: csrv.Extensions, ExtraExtensions: []pkix.Extension{}, } for _, val := range csrv.Extensions { // Check the CSR for the X.509 BasicConstraints (RFC 5280, 4.2.1.9) // extension and append to template if necessary if val.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) { var constraints csr.BasicConstraints var rest []byte if rest, err = asn1.Unmarshal(val.Value, &constraints); err != nil { return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err) } else if len(rest) != 0 { return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, errors.New("x509: trailing data after X.509 BasicConstraints")) } template.BasicConstraintsValid = true template.IsCA = constraints.IsCA template.MaxPathLen = constraints.MaxPathLen template.MaxPathLenZero = template.MaxPathLen == 0 } else if val.Id.Equal(helpers.DelegationUsage) { template.ExtraExtensions = append(template.ExtraExtensions, val) } else { // If the profile has 'copy_extensions' to true then lets add it if p.CopyExtensions { template.ExtraExtensions = append(template.ExtraExtensions, val) } } } return } type subjectPublicKeyInfo struct { Algorithm pkix.AlgorithmIdentifier SubjectPublicKey asn1.BitString } // ComputeSKI derives an SKI from the certificate's public key in a // standard manner. This is done by computing the SHA-1 digest of the // SubjectPublicKeyInfo component of the certificate. func ComputeSKI(template *x509.Certificate) ([]byte, error) { pub := template.PublicKey encodedPub, err := x509.MarshalPKIXPublicKey(pub) if err != nil { return nil, err } var subPKI subjectPublicKeyInfo _, err = asn1.Unmarshal(encodedPub, &subPKI) if err != nil { return nil, err } pubHash := sha1.Sum(subPKI.SubjectPublicKey.Bytes) return pubHash[:], nil } // FillTemplate is a utility function that tries to load as much of // the certificate template as possible from the profiles and current // template. It fills in the key uses, expiration, revocation URLs // and SKI. func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.SigningProfile, notBefore time.Time, notAfter time.Time) error { ski, err := ComputeSKI(template) if err != nil { return err } var ( eku []x509.ExtKeyUsage ku x509.KeyUsage backdate time.Duration expiry time.Duration crlURL, ocspURL string issuerURL = profile.IssuerURL ) // The third value returned from Usages is a list of unknown key usages. // This should be used when validating the profile at load, and isn't used // here. ku, eku, _ = profile.Usages() if profile.IssuerURL == nil { issuerURL = defaultProfile.IssuerURL } if ku == 0 && len(eku) == 0 { return cferr.New(cferr.PolicyError, cferr.NoKeyUsages) } if expiry = profile.Expiry; expiry == 0 { expiry = defaultProfile.Expiry } if crlURL = profile.CRL; crlURL == "" { crlURL = defaultProfile.CRL } if ocspURL = profile.OCSP; ocspURL == "" { ocspURL = defaultProfile.OCSP } if notBefore.IsZero() { if !profile.NotBefore.IsZero() { notBefore = profile.NotBefore } else { if backdate = profile.Backdate; backdate == 0 { backdate = -5 * time.Minute } else { backdate = -1 * profile.Backdate } notBefore = time.Now().Round(time.Minute).Add(backdate) } } notBefore = notBefore.UTC() if notAfter.IsZero() { if !profile.NotAfter.IsZero() { notAfter = profile.NotAfter } else { notAfter = notBefore.Add(expiry) } } notAfter = notAfter.UTC() template.NotBefore = notBefore template.NotAfter = notAfter template.KeyUsage = ku template.ExtKeyUsage = eku template.BasicConstraintsValid = true template.IsCA = profile.CAConstraint.IsCA if template.IsCA { template.MaxPathLen = profile.CAConstraint.MaxPathLen if template.MaxPathLen == 0 { template.MaxPathLenZero = profile.CAConstraint.MaxPathLenZero } template.DNSNames = nil template.EmailAddresses = nil template.URIs = nil } template.SubjectKeyId = ski if ocspURL != "" { template.OCSPServer = []string{ocspURL} } if crlURL != "" { template.CRLDistributionPoints = []string{crlURL} } if len(issuerURL) != 0 { template.IssuingCertificateURL = issuerURL } if len(profile.Policies) != 0 { err = addPolicies(template, profile.Policies) if err != nil { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err) } } if profile.OCSPNoCheck { ocspNoCheckExtension := pkix.Extension{ Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1, 5}, Critical: false, Value: []byte{0x05, 0x00}, } template.ExtraExtensions = append(template.ExtraExtensions, ocspNoCheckExtension) } return nil } type policyInformation struct { PolicyIdentifier asn1.ObjectIdentifier Qualifiers []interface{} `asn1:"tag:optional,omitempty"` } type cpsPolicyQualifier struct { PolicyQualifierID asn1.ObjectIdentifier Qualifier string `asn1:"tag:optional,ia5"` } type userNotice struct { ExplicitText string `asn1:"tag:optional,utf8"` } type userNoticePolicyQualifier struct { PolicyQualifierID asn1.ObjectIdentifier Qualifier userNotice } var ( // Per https://tools.ietf.org/html/rfc3280.html#page-106, this represents: // iso(1) identified-organization(3) dod(6) internet(1) security(5) // mechanisms(5) pkix(7) id-qt(2) id-qt-cps(1) iDQTCertificationPracticeStatement = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 2, 1} // iso(1) identified-organization(3) dod(6) internet(1) security(5) // mechanisms(5) pkix(7) id-qt(2) id-qt-unotice(2) iDQTUserNotice = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 2, 2} // CTPoisonOID is the object ID of the critical poison extension for precertificates // https://tools.ietf.org/html/rfc6962#page-9 CTPoisonOID = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3} // SCTListOID is the object ID for the Signed Certificate Timestamp certificate extension // https://tools.ietf.org/html/rfc6962#page-14 SCTListOID = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2} ) // addPolicies adds Certificate Policies and optional Policy Qualifiers to a // certificate, based on the input config. Go's x509 library allows setting // Certificate Policies easily, but does not support nested Policy Qualifiers // under those policies. So we need to construct the ASN.1 structure ourselves. func addPolicies(template *x509.Certificate, policies []config.CertificatePolicy) error { asn1PolicyList := []policyInformation{} for _, policy := range policies { pi := policyInformation{ // The PolicyIdentifier is an OID assigned to a given issuer. PolicyIdentifier: asn1.ObjectIdentifier(policy.ID), } for _, qualifier := range policy.Qualifiers { switch qualifier.Type { case "id-qt-unotice": pi.Qualifiers = append(pi.Qualifiers, userNoticePolicyQualifier{ PolicyQualifierID: iDQTUserNotice, Qualifier: userNotice{ ExplicitText: qualifier.Value, }, }) case "id-qt-cps": pi.Qualifiers = append(pi.Qualifiers, cpsPolicyQualifier{ PolicyQualifierID: iDQTCertificationPracticeStatement, Qualifier: qualifier.Value, }) default: return errors.New("Invalid qualifier type in Policies " + qualifier.Type) } } asn1PolicyList = append(asn1PolicyList, pi) } asn1Bytes, err := asn1.Marshal(asn1PolicyList) if err != nil { return err } template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{ Id: asn1.ObjectIdentifier{2, 5, 29, 32}, Critical: false, Value: asn1Bytes, }) return nil } ================================================ FILE: signer/signer_test.go ================================================ package signer import ( "bytes" "crypto/x509" "encoding/asn1" "encoding/hex" "fmt" "reflect" "testing" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" ) func TestAppendIf(t *testing.T) { s := "" a := make([]string, 0, 5) appendIf(s, &a) if len(a) != 0 { t.Fatal("appendIf should not append to a with an empty s") } s = "test" appendIf(s, &a) if len(a[0]) != 4 { t.Fatal("appendIf should append s to a") } } func TestSplitHosts(t *testing.T) { list := SplitHosts("") if list != nil { t.Fatal("SplitHost should return nil with empty input") } list = SplitHosts("single.domain") if len(list) != 1 { t.Fatal("SplitHost fails to split single domain") } list = SplitHosts("comma,separated,values") if len(list) != 3 { t.Fatal("SplitHost fails to split multiple domains") } if list[0] != "comma" || list[1] != "separated" || list[2] != "values" { t.Fatal("SplitHost fails to split multiple domains") } } func TestAddPolicies(t *testing.T) { var cert x509.Certificate addPolicies(&cert, []config.CertificatePolicy{ { ID: config.OID([]int{1, 2, 3, 4}), }, }) if len(cert.ExtraExtensions) != 1 { t.Fatal("No extension added") } ext := cert.ExtraExtensions[0] if !reflect.DeepEqual(ext.Id, asn1.ObjectIdentifier{2, 5, 29, 32}) { t.Fatal(fmt.Sprintf("Wrong OID for policy qualifier %v", ext.Id)) } if ext.Critical { t.Fatal("Policy qualifier marked critical") } expectedBytes, _ := hex.DecodeString("3007300506032a0304") if !bytes.Equal(ext.Value, expectedBytes) { t.Fatal(fmt.Sprintf("Value didn't match expected bytes: got %s, expected %s", hex.EncodeToString(ext.Value), hex.EncodeToString(expectedBytes))) } } func TestAddPoliciesWithQualifiers(t *testing.T) { var cert x509.Certificate addPolicies(&cert, []config.CertificatePolicy{ { ID: config.OID([]int{1, 2, 3, 4}), Qualifiers: []config.CertificatePolicyQualifier{ { Type: "id-qt-cps", Value: "http://example.com/cps", }, { Type: "id-qt-unotice", Value: "Do What Thou Wilt", }, }, }, }) if len(cert.ExtraExtensions) != 1 { t.Fatal("No extension added") } ext := cert.ExtraExtensions[0] if !reflect.DeepEqual(ext.Id, asn1.ObjectIdentifier{2, 5, 29, 32}) { t.Fatal(fmt.Sprintf("Wrong OID for policy qualifier %v", ext.Id)) } if ext.Critical { t.Fatal("Policy qualifier marked critical") } expectedBytes, _ := hex.DecodeString("304e304c06032a03043045302206082b060105050702011616687474703a2f2f6578616d706c652e636f6d2f637073301f06082b0601050507020230130c11446f20576861742054686f752057696c74") if !bytes.Equal(ext.Value, expectedBytes) { t.Fatal(fmt.Sprintf("Value didn't match expected bytes: %s vs %s", hex.EncodeToString(ext.Value), hex.EncodeToString(expectedBytes))) } } func TestName(t *testing.T) { sub := &Subject{ CN: "foobar", Names: []csr.Name{ { C: "US", ST: "CA", L: "Cool Locality", O: "Cool Org", OU: "Really Cool Sub Org", }, { L: "Another Cool Locality", }, }, SerialNumber: "deadbeef", } name := sub.Name() if name.CommonName != sub.CN { t.Errorf("CommonName: want %#v, got %#v", sub.CN, name.CommonName) } if name.SerialNumber != sub.SerialNumber { t.Errorf("SerialNumber: want %#v, got %#v", sub.SerialNumber, name.SerialNumber) } if !reflect.DeepEqual([]string{"US"}, name.Country) { t.Errorf("Country: want %s, got %s", []string{"US"}, name.Country) } if !reflect.DeepEqual([]string{"CA"}, name.Province) { t.Errorf("Province: want %s, got %s", []string{"CA"}, name.Province) } if !reflect.DeepEqual([]string{"Cool Org"}, name.Organization) { t.Errorf("Organization: want %s, got %s", []string{"Cool Org"}, name.Organization) } if !reflect.DeepEqual([]string{"Really Cool Sub Org"}, name.OrganizationalUnit) { t.Errorf("Organizational Unit: want %s, got %s", []string{"Really Cool Sub Org"}, name.OrganizationalUnit) } if !reflect.DeepEqual([]string{"Cool Locality", "Another Cool Locality"}, name.Locality) { t.Errorf("Locality: want %s, got %s", []string{"CA"}, name.Locality) } } ================================================ FILE: signer/universal/universal.go ================================================ // Package universal implements a signer that can do remote or local package universal import ( "crypto/x509" "net/http" "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/config" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/info" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/local" "github.com/cloudflare/cfssl/signer/remote" ) // Signer represents a universal signer which is both local and remote // to fulfill the signer.Signer interface. type Signer struct { local signer.Signer remote signer.Signer policy *config.Signing } // Root is used to define where the universal signer gets its public // certificate and private keys for signing. type Root struct { Config map[string]string ForceRemote bool } // a localSignerCheck looks at the Config keys in the Root, and // decides whether it has enough information to produce a signer. type localSignerCheck func(root *Root, policy *config.Signing) (signer.Signer, bool, error) // fileBackedSigner determines whether a file-backed local signer is supported. func fileBackedSigner(root *Root, policy *config.Signing) (signer.Signer, bool, error) { keyFile := root.Config["key-file"] certFile := root.Config["cert-file"] if keyFile == "" { return nil, false, nil } signer, err := local.NewSignerFromFile(certFile, keyFile, policy) return signer, true, err } var localSignerList = []localSignerCheck{ fileBackedSigner, } // PrependLocalSignerToList prepends signer to the local signer's list func PrependLocalSignerToList(signer localSignerCheck) { localSignerList = append([]localSignerCheck{signer}, localSignerList...) } func newLocalSigner(root Root, policy *config.Signing) (s signer.Signer, err error) { // shouldProvide indicates whether the // function *should* have produced a key. If // it's true, we should use the signer and // error returned. Otherwise, keep looking for // signers. var shouldProvide bool // localSignerList is a list of signers defined // here or in the universal_signers*.go files. // These activate and deactivate signers based // on build flags. for _, possibleSigner := range localSignerList { s, shouldProvide, err = possibleSigner(&root, policy) if shouldProvide { break } } if s == nil { err = cferr.New(cferr.PrivateKeyError, cferr.Unknown) } return s, err } func newUniversalSigner(root Root, policy *config.Signing) (*Signer, error) { ls, err := newLocalSigner(root, policy) if err != nil { return nil, err } rs, err := remote.NewSigner(policy) if err != nil { return nil, err } s := &Signer{ policy: policy, local: ls, remote: rs, } return s, err } // NewSigner generates a new certificate signer from a Root structure. // This is one of two standard signers: local or remote. If the root // structure specifies a force remote, then a remote signer is created, // otherwise either a remote or local signer is generated based on the // policy. For a local signer, the CertFile and KeyFile need to be // defined in Root. func NewSigner(root Root, policy *config.Signing) (signer.Signer, error) { if policy == nil { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig(), } } if !policy.Valid() { return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } var s signer.Signer var err error if root.ForceRemote { s, err = remote.NewSigner(policy) } else { if policy.NeedsLocalSigner() && policy.NeedsRemoteSigner() { s, err = newUniversalSigner(root, policy) } else { if policy.NeedsLocalSigner() { s, err = newLocalSigner(root, policy) } if policy.NeedsRemoteSigner() { s, err = remote.NewSigner(policy) } } } return s, err } // getMatchingProfile returns the SigningProfile that matches the profile passed. // if an empty profile string is passed it returns the default profile. func (s *Signer) getMatchingProfile(profile string) (*config.SigningProfile, error) { if profile == "" { return s.policy.Default, nil } for p, signingProfile := range s.policy.Profiles { if p == profile { return signingProfile, nil } } return nil, cferr.New(cferr.PolicyError, cferr.UnknownProfile) } // Sign sends a signature request to either the remote or local signer, // receiving a signed certificate or an error in response. func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) { profile, err := s.getMatchingProfile(req.Profile) if err != nil { return cert, err } if profile.RemoteServer != "" { return s.remote.Sign(req) } return s.local.Sign(req) } // Info sends an info request to the remote or local CFSSL server // receiving an Resp struct or an error in response. func (s *Signer) Info(req info.Req) (resp *info.Resp, err error) { profile, err := s.getMatchingProfile(req.Profile) if err != nil { return resp, err } if profile.RemoteServer != "" { return s.remote.Info(req) } return s.local.Info(req) } // SetDBAccessor sets the signer's cert db accessor. func (s *Signer) SetDBAccessor(dba certdb.Accessor) { s.local.SetDBAccessor(dba) } // GetDBAccessor returns the signer's cert db accessor. func (s *Signer) GetDBAccessor() certdb.Accessor { return s.local.GetDBAccessor() } // SetReqModifier sets the function to call to modify the HTTP request prior to sending it func (s *Signer) SetReqModifier(mod func(*http.Request, []byte)) { s.local.SetReqModifier(mod) s.remote.SetReqModifier(mod) } // SigAlgo returns the RSA signer's signature algorithm. func (s *Signer) SigAlgo() x509.SignatureAlgorithm { if s.local != nil { return s.local.SigAlgo() } // currently remote.SigAlgo just returns // x509.UnknownSignatureAlgorithm. return s.remote.SigAlgo() } // SetPolicy sets the signer's signature policy. func (s *Signer) SetPolicy(policy *config.Signing) { s.policy = policy } // Policy returns the signer's policy. func (s *Signer) Policy() *config.Signing { return s.policy } ================================================ FILE: signer/universal/universal_test.go ================================================ package universal import ( "bytes" "math/big" "net/http" "net/http/httptest" "os" "strings" "testing" "time" apiinfo "github.com/cloudflare/cfssl/api/info" apisign "github.com/cloudflare/cfssl/api/signhandler" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/helpers/testsuite" "github.com/cloudflare/cfssl/info" "github.com/cloudflare/cfssl/signer" ) const ( testCaFile = "../local/testdata/ca.pem" testCaKeyFile = "../local/testdata/ca_key.pem" ) var expiry = 1 * time.Minute var validLocalConfig = &config.Config{ Signing: &config.Signing{ Profiles: map[string]*config.SigningProfile{ "valid": { Usage: []string{"digital signature"}, Expiry: expiry, }, }, Default: &config.SigningProfile{ Usage: []string{"digital signature"}, Expiry: expiry, }, }, } var validMinimalRemoteConfig = ` { "signing": { "profiles": { "CA": { "usages": [ "cert sign", "crl sign" ], "expiry": "720h", "auth_key": "ca-auth" } }, "default": { "usages": [ "digital signature", "email protection" ], "expiry": "8000h" } }, "auth_keys": { "ca-auth": { "type": "standard", "key": "0123456789ABCDEF0123456789ABCDEF" } } }` var validMinimalUniversalConfig = ` { "signing": { "profiles": { "CA": { "usages": [ "cert sign", "crl sign" ], "expiry": "720h", "auth_key": "local-auth", "auth_remote": { "remote": "localhost", "auth_key": "ca-auth" } }, "email": { "usages": [ "s/mime" ], "expiry": "720h" } }, "default": { "usages": [ "digital signature", "email protection" ], "expiry": "8000h" } }, "auth_keys": { "local-auth": { "type": "standard", "key": "123456789ABCDEF0123456789ABCDEF0" }, "ca-auth": { "type": "standard", "key": "0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "http://127.0.0.1:1234" } }` var validRemoteConfig = ` { "signing": { "profiles": { "CA": { "usages": [ "cert sign", "crl sign" ], "expiry": "720h", "auth_key": "ca-auth" }, "ipsec": { "usages": [ "ipsec tunnel" ], "expiry": "720h" } }, "default": { "usages": [ "digital signature", "email protection" ], "expiry": "8000h" } }, "auth_keys": { "ca-auth": { "type": "standard", "key": "0123456789ABCDEF0123456789ABCDEF" } } }` var validUniversalConfig = ` { "signing": { "profiles": { "CA": { "usages": [ "cert sign", "crl sign" ], "expiry": "720h", "auth_key": "local-auth", "auth_remote": { "remote": "localhost", "auth_key": "ca-auth" } }, "ipsec": { "usages": [ "ipsec tunnel" ], "expiry": "720h", "remote": "localhost" }, "email": { "usages": [ "s/mime" ], "expiry": "720h" } }, "default": { "usages": [ "digital signature", "email protection" ], "expiry": "8000h" } }, "auth_keys": { "local-auth": { "type": "standard", "key": "123456789ABCDEF0123456789ABCDEF0" }, "ca-auth": { "type": "standard", "key": "0123456789ABCDEF0123456789ABCDEF" } }, "remotes": { "localhost": "http://127.0.0.1:1234" } }` var validNoAuthRemoteConfig = ` { "signing": { "profiles": { "CA": { "usages": [ "cert sign", "crl sign" ], "expiry": "720h" }, "ipsec": { "usages": [ "ipsec tunnel" ], "expiry": "720h" } }, "default": { "usages": [ "digital signature", "email protection" ], "expiry": "8000h" } } }` var validNoAuthUniversalConfig = ` { "signing": { "profiles": { "CA": { "usages": [ "cert sign", "crl sign" ], "expiry": "720h", "remote": "localhost" }, "ipsec": { "usages": [ "ipsec tunnel" ], "expiry": "720h", "remote": "localhost" }, "email": { "usages": [ "s/mime" ], "expiry": "720h" } }, "default": { "usages": [ "digital signature", "email protection" ], "expiry": "8000h" } }, "remotes": { "localhost": "127.0.0.1:1234" } }` func TestNewSigner(t *testing.T) { h := map[string]string{ "key-file": testCaKeyFile, "cert-file": testCaFile, } r := &Root{ Config: h, ForceRemote: false, } _, err := NewSigner(*r, validLocalConfig.Signing) if err != nil { t.Fatal(err) } } func checkInfo(t *testing.T, s signer.Signer, name string, profile *config.SigningProfile) { req := info.Req{ Profile: name, } resp, err := s.Info(req) if err != nil { t.Fatal("remote info failed:", err) } if strings.Join(profile.Usage, ",") != strings.Join(resp.Usage, ",") { t.Fatalf("Expected usage for profile %s to be %+v, got %+v", name, profile.Usage, resp.Usage) } caBytes, err := os.ReadFile(testCaFile) caBytes = bytes.TrimSpace(caBytes) if err != nil { t.Fatal("fail to read test CA cert:", err) } if bytes.Compare(caBytes, []byte(resp.Certificate)) != 0 { t.Fatal("Get a different CA cert through info api.", len(resp.Certificate), len(caBytes)) } } func TestUniversalRemoteAndLocalInfo(t *testing.T) { // set up remote server remoteConfig := testsuite.NewConfig(t, []byte(validMinimalRemoteConfig)) remoteServer := newTestInfoServer(t, newTestUniversalSigner(t, remoteConfig.Signing)) defer closeTestServer(t, remoteServer) universalConfig := testsuite.NewConfig(t, []byte(validMinimalUniversalConfig)) // override with test server address for name, profile := range universalConfig.Signing.Profiles { if profile.RemoteServer != "" { universalConfig.Signing.Profiles[name].RemoteServer = remoteServer.URL } } s := newTestUniversalSigner(t, universalConfig.Signing) for name, profile := range universalConfig.Signing.Profiles { checkInfo(t, s, name, profile) } // add check for default profile checkInfo(t, s, "", universalConfig.Signing.Default) } func TestUniversalMultipleRemoteAndLocalInfo(t *testing.T) { // set up remote server remoteConfig := testsuite.NewConfig(t, []byte(validRemoteConfig)) remoteServer := newTestInfoServer(t, newTestUniversalSigner(t, remoteConfig.Signing)) defer closeTestServer(t, remoteServer) universalConfig := testsuite.NewConfig(t, []byte(validUniversalConfig)) // override with test server address for name, profile := range universalConfig.Signing.Profiles { if profile.RemoteServer != "" { universalConfig.Signing.Profiles[name].RemoteServer = remoteServer.URL } } s := newTestUniversalSigner(t, universalConfig.Signing) for name, profile := range universalConfig.Signing.Profiles { checkInfo(t, s, name, profile) } // add check for default profile checkInfo(t, s, "", universalConfig.Signing.Default) } func TestUniversalRemoteAndLocalSign(t *testing.T) { // set up remote server remoteConfig := testsuite.NewConfig(t, []byte(validNoAuthRemoteConfig)) remoteServer := newTestSignServer(t, newTestUniversalSigner(t, remoteConfig.Signing)) defer closeTestServer(t, remoteServer) universalConfig := testsuite.NewConfig(t, []byte(validNoAuthUniversalConfig)) // override with test server address for name, profile := range universalConfig.Signing.Profiles { if profile.RemoteServer != "" { universalConfig.Signing.Profiles[name].RemoteServer = remoteServer.URL } } s := newTestUniversalSigner(t, universalConfig.Signing) checkSign := func(name string, profile *config.SigningProfile) { hosts := []string{"cloudflare.com"} for _, test := range testsuite.CSRTests { csr, err := os.ReadFile(test.File) if err != nil { t.Fatalf("CSR loading error (%s): %v", name, err) } testSerial := big.NewInt(0x7007F) certBytes, err := s.Sign(signer.SignRequest{ Hosts: hosts, Request: string(csr), Serial: testSerial, Profile: name, }) if test.ErrorCallback != nil { test.ErrorCallback(t, err) } else { if err != nil { t.Fatalf("Expected no error. Got %s. Param %s %d", err.Error(), test.KeyAlgo, test.KeyLen) } cert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal("Fail to parse returned certificate:", err) } ku, _, _ := profile.Usages() if cert.KeyUsage != ku { t.Fatalf("Key usage was incorrect expected %+v, got %+v", ku, cert.KeyUsage) } } } } for name, profile := range universalConfig.Signing.Profiles { checkSign(name, profile) } // add check for default profile checkSign("", universalConfig.Signing.Default) } func newTestUniversalSigner(t *testing.T, policy *config.Signing) signer.Signer { h := map[string]string{ "key-file": testCaKeyFile, "cert-file": testCaFile, } r := &Root{ Config: h, ForceRemote: false, } s, err := NewSigner(*r, policy) if err != nil { t.Fatal("fail to init universal signer:", err) } return s } func newTestSignHandler(t *testing.T, s signer.Signer) (h http.Handler) { h, err := apisign.NewHandlerFromSigner(s) if err != nil { t.Fatal(err) } return } func newTestInfoHandler(t *testing.T, s signer.Signer) (h http.Handler) { h, err := apiinfo.NewHandler(s) if err != nil { t.Fatal(err) } return } func newTestSignServer(t *testing.T, s signer.Signer) *httptest.Server { mux := http.NewServeMux() mux.Handle("/api/v1/cfssl/sign", newTestSignHandler(t, s)) ts := httptest.NewUnstartedServer(mux) ts.Start() t.Log(ts.URL) return ts } func newTestInfoServer(t *testing.T, s signer.Signer) *httptest.Server { mux := http.NewServeMux() mux.Handle("/api/v1/cfssl/info", newTestInfoHandler(t, s)) ts := httptest.NewUnstartedServer(mux) ts.Start() t.Log(ts.URL) return ts } func closeTestServer(t *testing.T, ts *httptest.Server) { t.Log("Finalizing test server.") ts.Close() } ================================================ FILE: test.sh ================================================ #!/bin/bash set -e # Build and install all binaries in PATH export GOBIN="${HOME}/bin" export PATH="${PATH}:${GOBIN}" make install # Run go tests echo "" > coverage.txt for package in $(go list ./...); do if echo "$package" | grep -q "/scan/crypto"; then echo "skipped $package" continue fi # only run the race detector on x86_64 if [ "$(uname -m)" = "x86_64" ]; then go test -mod=vendor -tags "$BUILD_TAGS" -race -coverprofile=profile.out -covermode=atomic $package else go test -mod=vendor -tags "$BUILD_TAGS" -coverprofile=profile.out $package fi if [ -f profile.out ]; then cat profile.out >> coverage.txt rm profile.out fi done ================================================ FILE: testdata/csr.json ================================================ { "hosts": [ "cloudflare.com", "www.cloudflare.com" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "San Francisco", "O": "CloudFlare", "OU": "Systems Engineering", "ST": "California" } ] } ================================================ FILE: testdata/garbage.crt ================================================ -----BEGIN CERTIFICATE----- MIICATCCAWoCCQDidF+uNJR6czANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB cyBQdHkgTHRkMB4XDTEyMDUwMTIyNTUxN1oXDTEzMDUwMTIyNTUxN1owRTELMAkG A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81 IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt +LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw== -----END CERTIFICATE----- ================================================ FILE: testdata/garbage.key ================================================ -----BEGIN RSA PRIVATE KEY----- BOzx0qUouFQ2xZ0NBrNVbyt1bzPLx0yKHkwF35ybw+Qc1yRpby/3ZB6+j/MCQFLl Dil8FywzZEonRNJst53+9cxFye70ely5br/tWxEp4/MsM1kCQQDqV4Lwn8BXOeKg dUETuSEoY7ZyczxTvKPDs21+H4i8KNlUDd3ZeodLc+Ou3geZT9wYI40Tz40Reip3 MtQM86LHWoMNEG9ezzUoBXaqHoJgdlt2qLGEN6uO8lwPg2x3uQTERl8e4QIDAQAB AoGAVxnsPojZ8X4g8LPk3d9dlXGhb/4tSmk9102jcHH/Y5ssy95Pe6ZJGr1uwbN+ 7m1l05PikpHeoxEryoW51cyfjDVkXUT0zPp2JC38DUA/0A8qWav/aENM64wg1I0P xOwNmcL+0XPedvSPBSPUoGJCzu12rH6Z+UHXipXsqRNSyQ+KGlur14y0kCh5uiVA jmWYVEEjAkEAx3keAo1nFsVW35EPt5LIbh6L6ty7GrvGRvOVeSd6YLtixMety24k hpt1cEv2xlFnbjbBbMkr9eUiUNpttLT6KwJBANGKaLoSjqEwUFYjX1OV/wdtcGcn vtcItOL9uBDJVGLSGYHKKBO/D/MYPlqWOHRVN8KjnXRyF4QHjh5y1OeKalAY3Ict MIICXAIBAAKBgQC2mOWeh2HPfWQsQmh4tKRGau/yXt7GQa07RES0huKuP0EHLrhl Mk1nfWF/jDdVz2neHGkCQHHBR4Xt1/euDku+14z5aLpphTEQVuRD2vQoeKi/W/CY OgNmKj1DzucnCS6yRCrF8Q0Pn8l054a3Wdbl1gqI/gA= -----END RSA PRIVATE KEY----- ================================================ FILE: testdata/gd_bundle.crt ================================================ -----BEGIN CERTIFICATE----- MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ 6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o 0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV U+4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv 2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1 QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd -----END CERTIFICATE----- ================================================ FILE: testdata/good_config.json ================================================ { "signing": { "default": { "expiry": "168h" }, "profiles": { "www": { "usages": [ "signing", "key encipherment", "server auth" ], "name_whitelist": "^.*\\.cloudflare.com$" } } } } ================================================ FILE: testdata/roots/httplib2_cacerts.txt ================================================ # Certifcate Authority certificates for validating SSL connections. # # This file contains PEM format certificates generated from # http://mxr.mozilla.org/seamonkey/source/security/nss/lib/ckfw/builtins/certdata.txt # # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is the Netscape security libraries. # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1994-2000 # the Initial Developer. All Rights Reserved. # # Contributor(s): # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # ***** END LICENSE BLOCK ***** Verisign/RSA Secure Server CA ============================= -----BEGIN CERTIFICATE----- MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0 MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII 0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3 YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc 1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA== -----END CERTIFICATE----- Thawte Personal Basic CA ======================== -----BEGIN CERTIFICATE----- MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53 dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7 G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P 9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== -----END CERTIFICATE----- Thawte Personal Premium CA ========================== -----BEGIN CERTIFICATE----- MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ -----END CERTIFICATE----- Thawte Personal Freemail CA =========================== -----BEGIN CERTIFICATE----- MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa /RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei gQ== -----END CERTIFICATE----- Thawte Server CA ================ -----BEGIN CERTIFICATE----- MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3 dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3 DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91 yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG 7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ qdq5snUb9kLy78fyGPmJvKP/iiMucEc= -----END CERTIFICATE----- Thawte Premium Server CA ======================== -----BEGIN CERTIFICATE----- MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG 9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== -----END CERTIFICATE----- Equifax Secure CA ================= -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 -----END CERTIFICATE----- Verisign Class 1 Public Primary Certification Authority ======================================================= -----BEGIN CERTIFICATE----- MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR 4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5 FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx lA== -----END CERTIFICATE----- Verisign Class 2 Public Primary Certification Authority ======================================================= -----BEGIN CERTIFICATE----- MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority ======================================================= -----BEGIN CERTIFICATE----- MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k -----END CERTIFICATE----- Verisign Class 1 Public Primary Certification Authority - G2 ============================================================ -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68 DzFc6PLZ -----END CERTIFICATE----- Verisign Class 2 Public Primary Certification Authority - G2 ============================================================ -----BEGIN CERTIFICATE----- MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn jBJ7xUS0rg== -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority - G2 ============================================================ -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY oJ2daZH9 -----END CERTIFICATE----- Verisign Class 4 Public Primary Certification Authority - G2 ============================================================ -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP T8qAkbYp -----END CERTIFICATE----- Verisign Class 1 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO 8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== -----END CERTIFICATE----- Verisign Class 2 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u 7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te 2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- Verisign Class 4 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ +mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c 2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== -----END CERTIFICATE----- Equifax Secure Global eBusiness CA ================================== -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc 58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv 8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV -----END CERTIFICATE----- Equifax Secure eBusiness CA 1 ============================= -----BEGIN CERTIFICATE----- MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN /Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== -----END CERTIFICATE----- Equifax Secure eBusiness CA 2 ============================= -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0 NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/ BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy 0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1 E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN -----END CERTIFICATE----- Thawte Time Stamping CA ======================= -----BEGIN CERTIFICATE----- MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCWkEx FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAd BgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcwMTAxMDAwMDAwWhcN MjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4g Q2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsG A1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1l c3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYrWHhhRYZT 6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQa Wt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL 8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB Af8wDQYJKoZIhvcNAQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC 9RAIDb/LogWK0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQ pgCed/r8zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZ CayJSdM= -----END CERTIFICATE----- thawte Primary Root CA ====================== -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta 3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk 6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 /qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 jVaMaA== -----END CERTIFICATE----- VeriSign Class 3 Public Primary Certification Authority - G5 ============================================================ -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- Entrust.net Secure Server Certification Authority ================================================= -----BEGIN CERTIFICATE----- MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN 95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd 2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= -----END CERTIFICATE----- Go Daddy Certification Authority Root Certificate Bundle ======================================================== -----BEGIN CERTIFICATE----- MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ 6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o 0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV U+4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv 2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1 QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd -----END CERTIFICATE----- GeoTrust Global CA ================== -----BEGIN CERTIFICATE----- MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0 aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S -----END CERTIFICATE----- ================================================ FILE: testdata/server.crt ================================================ -----BEGIN CERTIFICATE----- MIICATCCAWoCCQDidF+uNJR6czANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 cyBQdHkgTHRkMB4XDTEyMDUwMTIyNTUxN1oXDTEzMDUwMTIyNTUxN1owRTELMAkG A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81 KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt +LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw== -----END CERTIFICATE----- ================================================ FILE: testdata/server.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQC2mOWeh2HPfWQsQmh4tKRGau/yXt7GQa07RES0huKuP0EH LrhldUETuSEoY7ZyczxTvKPDs21+H4i8KNlUDd3ZeodLc+Ou3geZT9wYI40Tz40R eip3MtQM86LHWoMNEG9ezzUoBXaqHoJgdlt2qLGEN6uO8lwPg2x3uQTERl8e4QID AQABoAAwDQYJKoZIhvcNAQEFBQADgYEALOuXHteRZ7f+vH5mv2Odz8KHgFm+YfdD YSRDiFGnMXZ4/Z5440Jl+lsytH9XRdU+CAvMwXISCLx6NI8JfNpSMvltDNRmBGfM HjTdVKPDb9xns7by8sgwuSNnOONuefbZNXPGbjDfKzEa2UdHJT+YaLOVzCDPlPBr BUo2gGkLUAs= -----END CERTIFICATE REQUEST----- ================================================ FILE: testdata/server.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQC2mOWeh2HPfWQsQmh4tKRGau/yXt7GQa07RES0huKuP0EHLrhl dUETuSEoY7ZyczxTvKPDs21+H4i8KNlUDd3ZeodLc+Ou3geZT9wYI40Tz40Reip3 MtQM86LHWoMNEG9ezzUoBXaqHoJgdlt2qLGEN6uO8lwPg2x3uQTERl8e4QIDAQAB AoGAVxnsPojZ8X4g8LPk3d9dlXGhb/4tSmk9102jcHH/Y5ssy95Pe6ZJGr1uwbN+ 7m1l05PikpHeoxEryoW51cyfjDVkXUT0zPp2JC38DUA/0A8qWav/aENM64wg1I0P Dil8FywzZEonRNJst53+9cxFye70ely5br/tWxEp4/MsM1kCQQDqV4Lwn8BXOeKg xOwNmcL+0XPedvSPBSPUoGJCzu12rH6Z+UHXipXsqRNSyQ+KGlur14y0kCh5uiVA jmWYVEEjAkEAx3keAo1nFsVW35EPt5LIbh6L6ty7GrvGRvOVeSd6YLtixMety24k hpt1cEv2xlFnbjbBbMkr9eUiUNpttLT6KwJBANGKaLoSjqEwUFYjX1OV/wdtcGcn BOzx0qUouFQ2xZ0NBrNVbyt1bzPLx0yKHkwF35ybw+Qc1yRpby/3ZB6+j/MCQFLl vtcItOL9uBDJVGLSGYHKKBO/D/MYPlqWOHRVN8KjnXRyF4QHjh5y1OeKalAY3Ict Mk1nfWF/jDdVz2neHGkCQHHBR4Xt1/euDku+14z5aLpphTEQVuRD2vQoeKi/W/CY OgNmKj1DzucnCS6yRCrF8Q0Pn8l054a3Wdbl1gqI/gA= -----END RSA PRIVATE KEY----- ================================================ FILE: testdata/ssl-verifier.sh ================================================ #!/bin/bash KEY=$1 CRT=$2 IMM=$3 if [ "`cat $KEY | grep ENCRYPTED`" ]; then echo >&2 "Key is password-protected" exit 1 fi KEYMOD=`openssl rsa -noout -modulus -in $KEY` CRTMOD=`openssl x509 -noout -modulus -in $CRT` if [ "$KEYMOD" != "$CRTMOD" ]; then echo >&2 "Key doesn't match the certificate" exit 1 fi if [ -n "$IMM" ]; then cat $CRT $IMM > bundle.crt if [ "`openssl verify bundle.crt`" == "$CRT: OK" ]; then echo "Done (bundle ok)" exit 0 fi fi while true; do if [ "`openssl verify $CRT`" == "$CRT: OK" ]; then echo "Done" exit 0 fi NEXT=`openssl x509 -noout -issuer_hash -in $CRT` if [ ! -f $NEXT ]; then echo >&2 "Could not generate trusted bundle" exit 1 fi cat $CRT $NEXT > tmp.crt mv tmp.crt bundle.crt CRT="bundle.crt" done ================================================ FILE: testdata/temp.crt ================================================ -----BEGIN CERTIFICATE----- MIIDADCCAeqgAwIBAgIICYNCnX0enRAwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj bzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVTVCBSb290 IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTQwNDI5MjIy MjQyWhcNMTkwNDI5MjIyNzQyWjAAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB gQC2mOWeh2HPfWQsQmh4tKRGau/yXt7GQa07RES0huKuP0EHLrhldUETuSEoY7Zy czxTvKPDs21+H4i8KNlUDd3ZeodLc+Ou3geZT9wYI40Tz40Reip3MtQM86LHWoMN EG9ezzUoBXaqHoJgdlt2qLGEN6uO8lwPg2x3uQTERl8e4QIDAQABo3kwdzAOBgNV HQ8BAf8EBAMCAKAwDwYDVR0TAQH/BAUwAwIBADAdBgNVHQ4EFgQUv8IODn80eHdL LQRdN5bJmn8wjNcwHwYDVR0jBBgwFoAUt9L3hLqoOdX7rBDOKf2LlqQT7L0wFAYD VR0RBA0wC4IJbG9jYWxob3N0MAsGCSqGSIb3DQEBCwOCAQEAnuCKD+UzlDjFKFIm eMmXi77DDjOx3YmL8idPuglMwL75ZYCTwhctN3yC+xWS8TpurIMfyXtyINSRv6lW oBt8hj6NhXRyo/tC5CMRPoasB5FyhcLivD1117zYdDoouGxIOlEPw/nVQGgNQKvS ebXGkgDwMNm+qkQ69V38NzNeS36BzwvX9ElUmAS9PH78CRM3RteUMfi6JtWQjDWq U6pATxkKJ4mQA2D0SFoNe64DilbAZyKhHd07K9rZoM1bZ7ND6F8Qiow7/qQz3BW2 kOfSlY9zanzbOrF35H0dDCd9i0VQBkwZbWC06ZH2bgdHOCh8zn3WC2AOy9SaIuC8 L4mJZQ== -----END CERTIFICATE----- ================================================ FILE: testdata/test.py ================================================ import sys from m2ext import SSL from M2Crypto import X509 print "Validating certificate %s using CApath %s" % (sys.argv[1], sys.argv[2]) cert = X509.load_cert(sys.argv[1]) ctx = SSL.Context() ctx.load_verify_locations(capath=sys.argv[2]) if ctx.validate_certificate(cert): print "valid" else: print "invalid" ================================================ FILE: tools.go ================================================ //go:build tools // +build tools package tools import ( _ "bitbucket.org/liamstask/goose/cmd/goose" ) ================================================ FILE: transport/ca/cert_provider.go ================================================ // Package ca provides the CertificateAuthority interface for the // transport package, which provides an interface to get a CSR signed // by some certificate authority. package ca // A CertificateAuthority is capable of signing certificates given // certificate signing requests. type CertificateAuthority interface { // SignCSR submits a PKCS #10 certificate signing request to a // CA for signing. SignCSR(csrPEM []byte) (cert []byte, err error) // CACertificate returns the certificate authority's // certificate. CACertificate() (cert []byte, err error) } ================================================ FILE: transport/ca/cfssl_provider.go ================================================ package ca import ( "crypto/x509" "encoding/json" "encoding/pem" "errors" "fmt" "net" "path/filepath" "github.com/cloudflare/cfssl/api/client" "github.com/cloudflare/cfssl/auth" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/info" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/transport/core" ) type authError struct { authType string } func (err *authError) Error() string { return fmt.Sprintf("transport: unsupported CFSSL authentication method %s", err.authType) } // This approach allows us to quickly add other providers later, such // as the TPM. var authTypes = map[string]func(config.AuthKey, []byte) (auth.Provider, error){ "standard": newStandardProvider, } // Create a standard provider without providing any additional data. func newStandardProvider(ak config.AuthKey, ad []byte) (auth.Provider, error) { return auth.New(ak.Key, ad) } // Create a new provider from an authentication key and possibly // additional data. func newProvider(ak config.AuthKey, ad []byte) (auth.Provider, error) { // If no auth key was provided, use unauthenticated // requests. This is useful when a local CFSSL is being used. if ak.Type == "" && ak.Key == "" { return nil, nil } f, ok := authTypes[ak.Type] if !ok { return nil, &authError{authType: ak.Type} } return f(ak, ad) } // ErrNoAuth is returned when a client is talking to a CFSSL remote // that is not on a loopback address and doesn't have an // authentication provider set. var ErrNoAuth = errors.New("transport: authentication is required for non-local remotes") var v4Loopback = net.IPNet{ IP: net.IP{127, 0, 0, 0}, Mask: net.IPv4Mask(255, 0, 0, 0), } func ipIsLocal(ip net.IP) bool { if ip.To4() == nil { return ip.Equal(net.IPv6loopback) } return v4Loopback.Contains(ip) } // The only time a client should be doing unauthenticated requests is // when a local CFSSL is being used. func (cap *CFSSL) validateAuth() error { // The client is using some form of authentication, and the best way // to figure out that the auth is invalid is when it's used. Therefore, // we'll delay checking the credentials until that time. if cap.provider != nil { return nil } hosts := cap.remote.Hosts() for i := range hosts { ips, err := net.LookupIP(hosts[i]) if err != nil { return err } for _, ip := range ips { if !ipIsLocal(ip) { return ErrNoAuth } } } return nil } var cfsslConfigDirs = []string{ "/usr/local/cfssl", "/etc/cfssl", "/state/etc/cfssl", } // The CFSSL standard is to have a configuration file for a label as // .json. func findLabel(label string) *config.Config { for _, dir := range cfsslConfigDirs { cfgFile := filepath.Join(dir, label+".json") cfg, err := config.LoadFile(cfgFile) if err == nil { return cfg } } return nil } func getProfile(cfg *config.Config, profileName string) (*config.SigningProfile, bool) { if cfg == nil || cfg.Signing == nil || cfg.Signing.Default == nil { return nil, false } var ok bool profile := cfg.Signing.Default if profileName != "" { if cfg.Signing.Profiles == nil { return nil, false } profile, ok = cfg.Signing.Profiles[profileName] if !ok { return nil, false } } return profile, true } // loadAuth loads an authentication provider from the client config's // explicitly set auth key. func (cap *CFSSL) loadAuth() error { var err error cap.provider, err = newProvider(cap.DefaultAuth, nil) return err } func getRemote(cfg *config.Config, profile *config.SigningProfile) (string, bool) { // NB: Loading the config will validate that the remote is // present in the config's remote section. if profile.RemoteServer != "" { return profile.RemoteServer, true } return "", false } func (cap *CFSSL) setRemoteAndAuth() error { if cap.Label != "" { cfsslConfig := findLabel(cap.Label) profile, ok := getProfile(cfsslConfig, cap.Profile) if ok { remote, ok := getRemote(cfsslConfig, profile) if ok { cap.remote = client.NewServerTLS(remote, helpers.CreateTLSConfig(profile.RemoteCAs, profile.ClientCert)) cap.provider = profile.Provider return nil } // The profile may not have a remote set, but // it may have an authentication provider. cap.provider = profile.Provider } } cap.remote = cap.DefaultRemote if cap.provider != nil { return nil } return cap.loadAuth() } // CFSSL provides support for signing certificates via // CFSSL. type CFSSL struct { remote client.Remote provider auth.Provider Profile string Label string DefaultRemote client.Remote DefaultAuth config.AuthKey } // SignCSR requests a certificate from a CFSSL signer. func (cap *CFSSL) SignCSR(csrPEM []byte) (cert []byte, err error) { p, _ := pem.Decode(csrPEM) if p == nil || p.Type != "CERTIFICATE REQUEST" { return nil, errors.New("transport: invalid PEM-encoded certificate signing request") } csr, err := x509.ParseCertificateRequest(p.Bytes) if err != nil { return nil, err } hosts := make([]string, len(csr.DNSNames), len(csr.DNSNames)+len(csr.IPAddresses)+len(csr.URIs)) copy(hosts, csr.DNSNames) for i := range csr.IPAddresses { hosts = append(hosts, csr.IPAddresses[i].String()) } for i := range csr.URIs { hosts = append(hosts, csr.URIs[i].String()) } sreq := &signer.SignRequest{ Hosts: hosts, Request: string(csrPEM), Profile: cap.Profile, Label: cap.Label, } out, err := json.Marshal(sreq) if err != nil { return nil, err } if cap.provider != nil { return cap.remote.AuthSign(out, nil, cap.provider) } return cap.remote.Sign(out) } // CACertificate returns the certificate for a CFSSL CA. func (cap *CFSSL) CACertificate() ([]byte, error) { req := &info.Req{ Label: cap.Label, Profile: cap.Profile, } out, err := json.Marshal(req) if err != nil { return nil, err } resp, err := cap.remote.Info(out) if err != nil { return nil, err } return []byte(resp.Certificate), nil } // NewCFSSLProvider takes the configuration information from an // Identity (and an optional default remote), returning a CFSSL // instance. There should be a profile in id called "cfssl", which // should contain label and profile fields as needed. func NewCFSSLProvider(id *core.Identity, defaultRemote client.Remote) (*CFSSL, error) { if id == nil { return nil, errors.New("transport: the identity hasn't been initialised. Has it been loaded from disk?") } cap := &CFSSL{ DefaultRemote: defaultRemote, } cfssl := id.Profiles["cfssl"] if cfssl != nil { cap.Label = cfssl["label"] cap.Profile = cfssl["profile"] if cap.DefaultRemote == nil { cert, err := helpers.LoadClientCertificate(cfssl["mutual-tls-cert"], cfssl["mutual-tls-key"]) if err != nil { return nil, err } remoteCAs, err := helpers.LoadPEMCertPool(cfssl["tls-remote-ca"]) if err != nil { return nil, err } cap.DefaultRemote = client.NewServerTLS(cfssl["remote"], helpers.CreateTLSConfig(remoteCAs, cert)) } cap.DefaultAuth.Type = cfssl["auth-type"] cap.DefaultAuth.Key = cfssl["auth-key"] } err := cap.setRemoteAndAuth() if err != nil { return nil, err } return cap, nil } ================================================ FILE: transport/ca/localca/signer.go ================================================ // Package localca implements a localca that is useful for testing the // transport package. To use the localca, see the New and Load // functions. package localca import ( "crypto/x509" "encoding/pem" "errors" "fmt" "time" "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/initca" "github.com/cloudflare/cfssl/signer" "github.com/cloudflare/cfssl/signer/local" ) // CA is a local transport CertificateAuthority that is useful for // tests. type CA struct { s *local.Signer disabled bool // Label and Profile are used to select the CFSSL signer // components if they should be anything but the default. Label string `json:"label"` Profile string `json:"profile"` // The KeyFile and CertFile are required when using Load to // construct a CA. KeyFile string `json:"private_key,omitempty"` CertFile string `json:"certificate,omitempty"` } // Toggle switches the CA between operable mode and inoperable // mode. This is useful in testing to verify behaviours when a CA is // unavailable. func (lca *CA) Toggle() { lca.disabled = !lca.disabled } var errNotSetup = errors.New("transport: local CA has not been setup") // CACertificate returns the certificate authority's certificate. func (lca *CA) CACertificate() ([]byte, error) { if lca.s == nil { return nil, errNotSetup } cert, err := lca.s.Certificate(lca.Label, lca.Profile) if err != nil { return nil, err } p := &pem.Block{ Type: "CERTIFICATE", Bytes: cert.Raw, } return pem.EncodeToMemory(p), nil } var errDisabled = errors.New("transport: local CA is deactivated") // SignCSR submits a PKCS #10 certificate signing request to a CA for // signing. func (lca *CA) SignCSR(csrPEM []byte) ([]byte, error) { if lca == nil || lca.s == nil { return nil, errNotSetup } if lca.disabled { return nil, errDisabled } p, _ := pem.Decode(csrPEM) if p == nil || p.Type != "CERTIFICATE REQUEST" { return nil, errors.New("transport: invalid PEM-encoded certificate signing request") } csr, err := x509.ParseCertificateRequest(p.Bytes) if err != nil { return nil, err } hosts := make([]string, 0, len(csr.DNSNames)+len(csr.IPAddresses)) copy(hosts, csr.DNSNames) for i := range csr.IPAddresses { hosts = append(hosts, csr.IPAddresses[i].String()) } sreq := signer.SignRequest{ Hosts: hosts, Request: string(csrPEM), Profile: lca.Profile, Label: lca.Label, } return lca.s.Sign(sreq) } // ExampleRequest can be used as a sample request, or the returned // request can be modified. func ExampleRequest() *csr.CertificateRequest { return &csr.CertificateRequest{ Hosts: []string{"localhost"}, KeyRequest: &csr.KeyRequest{ A: "ecdsa", S: 256, }, CN: "Transport Failover Test Local CA", CA: &csr.CAConfig{ PathLength: 1, Expiry: "30m", }, } } // ExampleSigningConfig returns a sample config.Signing with only a // default profile. func ExampleSigningConfig() *config.Signing { return &config.Signing{ Default: &config.SigningProfile{ Expiry: 15 * time.Minute, Usage: []string{ "server auth", "client auth", "signing", "key encipherment", }, }, } } // New generates a new CA from a certificate request and signing profile. func New(req *csr.CertificateRequest, profiles *config.Signing) (*CA, error) { certPEM, _, keyPEM, err := initca.New(req) if err != nil { return nil, err } // If initca returns successfully, the following (which are // all CFSSL internal functions) should not return an // error. If they do, we should abort --- something about // CFSSL has become inconsistent, and it can't be trusted. priv, err := helpers.ParsePrivateKeyPEM(keyPEM) if err != nil { return nil, fmt.Errorf("CFSSL-generated private key can't be parsed: %w", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { return nil, fmt.Errorf("CFSSL-generated private key can't be parsed: %w", err) } s, err := local.NewSigner(priv, cert, helpers.SignerAlgo(priv), profiles) if err != nil { return nil, fmt.Errorf("a signer could not be constructed: %w", err) } return NewFromSigner(s), nil } // NewFromSigner constructs a local CA from a CFSSL signer. func NewFromSigner(s *local.Signer) *CA { return &CA{s: s} } // Load reads the key and certificate from the files specified in the // CA. func Load(lca *CA, profiles *config.Signing) (err error) { lca.s, err = local.NewSignerFromFile(lca.CertFile, lca.KeyFile, profiles) return err } ================================================ FILE: transport/ca/localca/signer_test.go ================================================ package localca import ( "encoding/pem" "errors" "os" "path/filepath" "testing" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/initca" ) func TestEncodePEM(t *testing.T) { p := &pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: []byte(`¯\_(ツ)_/¯`), } t.Logf("PEM:\n%s\n\n", string(pem.EncodeToMemory(p))) } func TestLoadSigner(t *testing.T) { lca := &CA{} certPEM, csrPEM, keyPEM, err := initca.New(ExampleRequest()) if err != nil { t.Fatal(err) } _, err = lca.CACertificate() if !errors.Is(err, errNotSetup) { t.Fatalf("expected an errNotSetup (%v), got: %v", errNotSetup, err) } _, err = lca.SignCSR(csrPEM) if !errors.Is(err, errNotSetup) { t.Fatalf("expected an errNotSetup (%v), got: %v", errNotSetup, err) } tmpDir := t.TempDir() lca.KeyFile = filepath.Join(tmpDir, "KeyFile") lca.CertFile = filepath.Join(tmpDir, "CertFile") err = os.WriteFile(lca.KeyFile, keyPEM, 0644) if err != nil { t.Fatal(err) } err = os.WriteFile(lca.CertFile, certPEM, 0644) if err != nil { t.Fatal(err) } err = Load(lca, ExampleSigningConfig()) if err != nil { t.Fatal(err) } } var testRequest = &csr.CertificateRequest{ CN: "Transport Test Identity", KeyRequest: &csr.KeyRequest{ A: "ecdsa", S: 256, }, Hosts: []string{"127.0.0.1"}, } func TestNewSigner(t *testing.T) { req := ExampleRequest() lca, err := New(req, ExampleSigningConfig()) if err != nil { t.Fatal(err) } csrPEM, _, err := csr.ParseRequest(testRequest) if err != nil { t.Fatal(err) } certPEM, err := lca.SignCSR(csrPEM) if err != nil { t.Fatal(err) } _, err = helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } certPEM, err = lca.CACertificate() if err != nil { t.Fatal(err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } if cert.Subject.CommonName != req.CN { t.Fatalf("common names don't match: '%s' != '%s'", cert.Subject.CommonName, req.CN) } lca.Toggle() _, err = lca.SignCSR(csrPEM) if !errors.Is(err, errDisabled) { t.Fatalf("expected an errDisabled (%v), got: %v", errDisabled, err) } lca.Toggle() _, err = lca.SignCSR(certPEM) if err == nil { t.Fatal("shouldn't be able to sign non-CSRs") } p := &pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: []byte(`¯\_(ツ)_/¯`), } junkCSR := pem.EncodeToMemory(p) _, err = lca.SignCSR(junkCSR) if err == nil { t.Fatal("signing a junk CSR should fail") } t.Logf("error: %s", err) } ================================================ FILE: transport/client.go ================================================ package transport import ( "crypto/tls" "net" "os" "time" "github.com/cloudflare/backoff" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/revoke" "github.com/cloudflare/cfssl/transport/ca" "github.com/cloudflare/cfssl/transport/core" "github.com/cloudflare/cfssl/transport/kp" "github.com/cloudflare/cfssl/transport/roots" ) func envOrDefault(key, def string) string { val := os.Getenv(key) if val == "" { return def } return val } var ( // NewKeyProvider is the function used to build key providers // from some identity. NewKeyProvider = func(id *core.Identity) (kp.KeyProvider, error) { return kp.NewStandardProvider(id) } // NewCA is used to load a configuration for a certificate // authority. NewCA = func(id *core.Identity) (ca.CertificateAuthority, error) { return ca.NewCFSSLProvider(id, nil) } ) // A Transport is capable of providing transport-layer security using // TLS. type Transport struct { // Before defines how long before the certificate expires the // transport should start attempting to refresh the // certificate. For example, if this is 24h, then 24 hours // before the certificate expires the Transport will start // attempting to replace it. Before time.Duration // Provider contains a key management provider. Provider kp.KeyProvider // CA contains a mechanism for obtaining signed certificates. CA ca.CertificateAuthority // TrustStore contains the certificates trusted by this // transport. TrustStore *roots.TrustStore // ClientTrustStore contains the certificate authorities to // use in verifying client authentication certificates. ClientTrustStore *roots.TrustStore // Identity contains information about the entity that will be // used to construct certificates. Identity *core.Identity // Backoff is used to control the behaviour of a Transport // when it is attempting to automatically update a certificate // as part of AutoUpdate. Backoff *backoff.Backoff // RevokeSoftFail, if true, will cause a failure to check // revocation (such that the revocation status of a // certificate cannot be checked) to not be treated as an // error. RevokeSoftFail bool } // TLSClientAuthClientConfig returns a new client authentication TLS // configuration that can be used for a client using client auth // connecting to the named host. func (tr *Transport) TLSClientAuthClientConfig(host string) (*tls.Config, error) { cert, err := tr.getCertificate() if err != nil { return nil, err } return &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: tr.TrustStore.Pool(), ServerName: host, CipherSuites: core.CipherSuites, MinVersion: tls.VersionTLS12, ClientAuth: tls.RequireAndVerifyClientCert, }, nil } // TLSClientAuthServerConfig returns a new client authentication TLS // configuration for servers expecting mutually authenticated // clients. The clientAuth parameter should contain the root pool used // to authenticate clients. func (tr *Transport) TLSClientAuthServerConfig() (*tls.Config, error) { cert, err := tr.getCertificate() if err != nil { return nil, err } return &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: tr.TrustStore.Pool(), ClientCAs: tr.ClientTrustStore.Pool(), ClientAuth: tls.RequireAndVerifyClientCert, CipherSuites: core.CipherSuites, MinVersion: tls.VersionTLS12, }, nil } // TLSServerConfig is a general server configuration that should be // used for non-client authentication purposes, such as HTTPS. func (tr *Transport) TLSServerConfig() (*tls.Config, error) { cert, err := tr.getCertificate() if err != nil { return nil, err } return &tls.Config{ Certificates: []tls.Certificate{cert}, CipherSuites: core.CipherSuites, MinVersion: tls.VersionTLS12, }, nil } // New builds a new transport from an identity and a before time. The // before time tells the transport how long before the certificate // expires to start attempting to update when auto-updating. If before // is longer than the certificate's lifetime, every update check will // trigger a new certificate to be generated. func New(before time.Duration, identity *core.Identity) (*Transport, error) { var tr = &Transport{ Before: before, Identity: identity, Backoff: &backoff.Backoff{}, } store, err := roots.New(identity.Roots) if err != nil { return nil, err } tr.TrustStore = store if len(identity.ClientRoots) > 0 { store, err = roots.New(identity.ClientRoots) if err != nil { return nil, err } tr.ClientTrustStore = store } tr.Provider, err = NewKeyProvider(identity) if err != nil { return nil, err } tr.CA, err = NewCA(identity) if err != nil { return nil, err } return tr, nil } // Lifespan returns how much time is left before the transport's // certificate expires, or 0 if the certificate is not present or // expired. func (tr *Transport) Lifespan() time.Duration { cert := tr.Provider.Certificate() if cert == nil { return 0 } now := time.Now() if now.After(cert.NotAfter) { return 0 } now = now.Add(tr.Before) ls := cert.NotAfter.Sub(now) log.Debugf(" LIFESPAN:\t%s", ls) if ls < 0 { return 0 } return ls } // RefreshKeys will make sure the Transport has loaded keys and has a // valid certificate. It will handle any persistence, check that the // certificate is valid (i.e. that its expiry date is within the // Before date), and handle certificate reissuance as needed. func (tr *Transport) RefreshKeys() (err error) { if !tr.Provider.Ready() { log.Debug("key and certificate aren't ready, loading") err = tr.Provider.Load() if err != nil && err != kp.ErrCertificateUnavailable { log.Debugf("failed to load keypair: %v", err) kr := tr.Identity.Request.KeyRequest if kr == nil { kr = csr.NewKeyRequest() } err = tr.Provider.Generate(kr.Algo(), kr.Size()) if err != nil { log.Debugf("failed to generate key: %v", err) return err } } } lifespan := tr.Lifespan() if lifespan < tr.Before { log.Debugf("transport's certificate is out of date (lifespan %s)", lifespan) req, err := tr.Provider.CertificateRequest(tr.Identity.Request) if err != nil { log.Debugf("couldn't get a CSR: %v", err) if tr.Provider.SignalFailure(err) { return tr.RefreshKeys() } return err } log.Debug("requesting certificate from CA") cert, err := tr.CA.SignCSR(req) if err != nil { if tr.Provider.SignalFailure(err) { return tr.RefreshKeys() } log.Debugf("failed to get the certificate signed: %v", err) return err } log.Debug("giving the certificate to the provider") err = tr.Provider.SetCertificatePEM(cert) if err != nil { log.Debugf("failed to set the provider's certificate: %v", err) if tr.Provider.SignalFailure(err) { return tr.RefreshKeys() } return err } if tr.Provider.Persistent() { log.Debug("storing the certificate") err = tr.Provider.Store() if err != nil { log.Debugf("the provider failed to store the certificate: %v", err) if tr.Provider.SignalFailure(err) { return tr.RefreshKeys() } return err } } } return nil } func (tr *Transport) getCertificate() (cert tls.Certificate, err error) { if !tr.Provider.Ready() { log.Debug("transport isn't ready; attempting to refresh keypair") err = tr.RefreshKeys() if err != nil { log.Debugf("transport couldn't get a certificate: %v", err) return } } cert, err = tr.Provider.X509KeyPair() if err != nil { log.Debugf("couldn't generate an X.509 keypair: %v", err) } return } // Dial initiates a TLS connection to an outbound server. It returns a // TLS connection to the server. func Dial(address string, tr *Transport) (*tls.Conn, error) { host, _, err := net.SplitHostPort(address) if err != nil { // Assume address is a hostname, and that it should // use the HTTPS port number. host = address address = net.JoinHostPort(address, "443") } cfg, err := tr.TLSClientAuthClientConfig(host) if err != nil { return nil, err } conn, err := tls.Dial("tcp", address, cfg) if err != nil { return nil, err } state := conn.ConnectionState() if len(state.VerifiedChains) == 0 { return nil, errors.New(errors.CertificateError, errors.VerifyFailed) } for _, chain := range state.VerifiedChains { for _, cert := range chain { revoked, ok := revoke.VerifyCertificate(cert) if (!tr.RevokeSoftFail && !ok) || revoked { return nil, errors.New(errors.CertificateError, errors.VerifyFailed) } } } return conn, nil } // AutoUpdate will automatically update the listener. If a non-nil // certUpdates chan is provided, it will receive timestamps for // reissued certificates. If errChan is non-nil, any errors that occur // in the updater will be passed along. func (tr *Transport) AutoUpdate(certUpdates chan<- time.Time, errChan chan<- error) { defer func() { if r := recover(); r != nil { log.Criticalf("AutoUpdate panicked: %v", r) } }() for { // Wait until it's time to update the certificate. target := time.Now().Add(tr.Lifespan()) if PollInterval == 0 { <-time.After(tr.Lifespan()) } else { pollWait(target) } // Keep trying to update the certificate until it's // ready. for { log.Debugf("attempting to refresh keypair") err := tr.RefreshKeys() if err == nil { break } delay := tr.Backoff.Duration() log.Debugf("failed to update certificate, will try again in %s", delay) if errChan != nil { errChan <- err } <-time.After(delay) } log.Debugf("certificate updated") if certUpdates != nil { certUpdates <- time.Now() } tr.Backoff.Reset() } } ================================================ FILE: transport/core/defs.go ================================================ // Package core contains core definitions for the transport package, // the most salient of which is likely the Identity type. This type is // used to build a Transport instance. // // The TLS configurations provided here are designed for three // scenarios: mutual authentication for a clients, mutual // authentication for servers, and a general-purpose server // configuration applicable where mutual authentication is not // appropriate. package core import ( "time" "github.com/cloudflare/cfssl/csr" ) // A Root stores information about a trusted root. type Root struct { // Type should contain a string identifier for the type. Type string `json:"type"` // Metadata contains the information needed to load the // root(s). Metadata map[string]string `json:"metadata"` } // Identity is used to store information about a particular transport. type Identity struct { // Request contains metadata for constructing certificate requests. Request *csr.CertificateRequest `json:"request"` // Roots contains a list of sources for trusted roots. Roots []*Root `json:"roots"` // ClientRoots contains a list of sources for trusted client // certificates. ClientRoots []*Root `json:"client_roots"` // Profiles contains a dictionary of names to dictionaries; // this is intended to allow flexibility in supporting // multiple configurations. Profiles map[string]map[string]string `json:"profiles"` } // DefaultBefore is a sensible default; attempt to regenerate certificates the // day before they expire. var DefaultBefore = 24 * time.Hour // CipherSuites are the TLS cipher suites that should be used by CloudFlare programs. var CipherSuites = []uint16{ // These are manually specified because the SHA384 suites are // not specified in Go 1.4; in Go 1.4, they won't actually // be sent. 0xc030, // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xc02c, // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xc02f, // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xc02b, // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 } ================================================ FILE: transport/core/rand.go ================================================ package core import ( "crypto/rand" "encoding/binary" "io" mrand "math/rand" "github.com/cloudflare/cfssl/log" ) var seeded bool func seed() error { if seeded { return nil } var buf [8]byte _, err := io.ReadFull(rand.Reader, buf[:]) if err != nil { return err } n := int64(binary.LittleEndian.Uint64(buf[:])) mrand.Seed(n) seeded = true return nil } func init() { err := seed() if err != nil { log.Errorf("seeding mrand failed: %v", err) } } ================================================ FILE: transport/doc.go ================================================ // Package transport implements functions for facilitating proper TLS-secured // communications for clients and servers. // // Clients should build an identity (of the core.identity) type, such as // // var id = &core.Identity{ // Request: &csr.CertificateRequest{ // CN: "localhost test certificate", // }, // Profiles: map[string]map[string]string{ // "paths": map[string]string{ // "private_key": "client.key", // "certificate": "client.pem", // }, // "cfssl": { // "label": "", // "profile": "client-ca", // "remote": "ca.example.net", // "auth-type": "standard", // "auth-key": "000102030405060708090a0b0c0d0e0f", // }, // }, // } // // The New function will return a transport built using the // NewKeyProvider and NewCA functions. These functions may be changed // by other packages to provide common key provider and CA // configurations. Clients can then use RefreshKeys (or launch // AutoUpdate in a goroutine) to ensure the certificate and key are // loaded and correct. The Listen and Dial functions then provide the // necessary connection support. // // The AutoUpdate function will handle automatic certificate // issuance. Servers and clients are not required to take any special // action when the certificate is updated: the key and certificate are // only used when establishing a connection, and therefore existing // connections are not affected---there is no need to reset or restart // any existing connections. Clients should run AutoUpdate if they // plan on making multiple connections or will be reconnecting; for a // one-off connection, it isn't necessary. package transport ================================================ FILE: transport/example/README.md ================================================ # Transport Package Examples `maserver` and `maclient` are a mutually authenticated server and client; the client will connect to the server and send a few messages. ## Set up A running CFSSL is needed. The `genca.sh` script should generate everything that's needed to run CFSSL locally. In a terminal for the CA: ``` $ basename $(pwd) example $ ./genca.sh 2015/10/27 14:00:29 [INFO] generating a new CA key and certificate from CSR 2015/10/27 14:00:29 [INFO] generate received request 2015/10/27 14:00:29 [INFO] received CSR 2015/10/27 14:00:29 [INFO] generating key: rsa-4096 2015/10/27 14:00:32 [INFO] encoded CSR 2015/10/27 14:00:33 [INFO] signed certificate with serial number 2940131150448804266 $ cfssl serve -ca ca.pem -ca-key ca-key.pem -config config.json ... 2015/10/27 14:00:35 [INFO] Setting up '/api/v1/cfssl/sign' endpoint ``` The providing `config.json` contains the CFSSL configuration; the `client.json` and `server.json` configurations are based on this config. ## Running the server The server expects a `server.json` in the same directory containing the configuration. One is provided in the server source, or it may be overridden using the `-f` command line flag. ``` $ basename $(pwd) example $ cd maserver/ $ go run server.go -a 127.0.0.1:9876 $ go run server.go -a 127.0.0.1:9876 2015/10/27 14:05:47 [INFO] using client auth 2015/10/27 14:05:47 [DEBUG] transport isn't ready; attempting to refresh keypair 2015/10/27 14:05:47 [DEBUG] key and certificate aren't ready, loading 2015/10/27 14:05:47 [DEBUG] failed to load keypair: open server.key: no such file or directory 2015/10/27 14:05:47 [DEBUG] transport's certificate is out of date (lifespan 0) 2015/10/27 14:05:47 [INFO] encoded CSR 2015/10/27 14:05:47 [DEBUG] requesting certificate from CA 2015/10/27 14:05:47 [DEBUG] giving the certificate to the provider 2015/10/27 14:05:47 [DEBUG] storing the certificate 2015/10/27 14:05:47 [INFO] setting up auto-update 2015/10/27 14:05:47 [INFO] listening on 127.0.0.1:9876 ``` At this point, the clients can start talking to the server. ## Running a client At this point, clients just connect and send a few messages, ensuring the server acknowledges the messages. The client also expects a `client.json` configuration in the same directory; once is provided in the source directory, or it may be overridden using the `-f` command line flag. ``` $ basename $(pwd) example $ go run client.go 2015/10/27 14:08:34 [DEBUG] transport isn't ready; attempting to refresh keypair 2015/10/27 14:08:34 [DEBUG] key and certificate aren't ready, loading 2015/10/27 14:08:34 [DEBUG] failed to load keypair: open client.key: no such file or directory 2015/10/27 14:08:34 [DEBUG] transport's certificate is out of date (lifespan 0) 2015/10/27 14:08:34 [INFO] encoded CSR 2015/10/27 14:08:34 [DEBUG] requesting certificate from CA 2015/10/27 14:08:34 [DEBUG] giving the certificate to the provider 2015/10/27 14:08:34 [DEBUG] storing the certificate OK $ ``` ## Auth Examples The CA, server, and client ship with a `_auth.json` configuration file that will use an authenticated CFSSL. The commands change to: ``` $ cfssl serve -ca ca.pem -ca-key ca-key.pem -config config_auth.json $ go run server.go -a 127.0.0.1:9876 -f server_auth.json $ go run client.go -f client_auth.json ``` ================================================ FILE: transport/example/ca.json ================================================ { "hosts": [ "dropsonde.net" ], "key": { "algo": "rsa", "size": 4096 }, "names": [ { "C": "US", "L": "San Francisco", "OU": "Dropsonde Certificate Authority", "ST": "California" } ] } ================================================ FILE: transport/example/config.json ================================================ { "signing": { "default": { "expiry": "168h" }, "profiles": { "client": { "expiry": "1h", "usages": [ "signing", "key encipherment", "client auth" ] }, "server": { "expiry": "1h", "usages": [ "signing", "key encipherment", "server auth" ] } } } } ================================================ FILE: transport/example/config_auth.json ================================================ { "auth_keys": { "client": { "type": "standard", "key": "52abb3ac91971bb72bce17e7a289cd04476490b19e0d8eb7810dc42d4ac16c41" }, "server": { "type": "standard", "key": "4f4f26686209f672e0ec7b19cbbc8b6d94fdd12cc0b20326f9005d5f234e6e3e" } }, "signing": { "default": { "expiry": "168h" }, "profiles": { "client": { "auth_key": "client", "expiry": "1h", "usages": [ "signing", "key encipherment", "client auth" ] }, "server": { "auth_key": "server", "expiry": "8760h", "usages": [ "signing", "key encipherment", "server auth" ] } } } } ================================================ FILE: transport/example/exlib/exlib.go ================================================ // Package exlib contains common library code for the examples. package exlib import ( "encoding/binary" "errors" "fmt" "io" "os" "path/filepath" "time" ) var progname = filepath.Base(os.Args[0]) // Before set to 5 minutes; certificates will attempt to auto-update 5 // minutes before they expire. var Before = 5 * time.Minute // Err displays a formatting error message to standard error, // appending the error string, and exits with the status code from // `exit`, à la err(3). func Err(exit int, err error, format string, a ...interface{}) { format = fmt.Sprintf("[%s] %s", progname, format) format += ": %v\n" a = append(a, err) fmt.Fprintf(os.Stderr, format, a...) os.Exit(exit) } // Errx displays a formatted error message to standard error and exits // with the status code from `exit`, à la errx(3). func Errx(exit int, format string, a ...interface{}) { format = fmt.Sprintf("[%s] %s", progname, format) format += "\n" fmt.Fprintf(os.Stderr, format, a...) os.Exit(exit) } // Warn displays a formatted error message to standard output, // appending the error string, à la warn(3). func Warn(err error, format string, a ...interface{}) (int, error) { format = fmt.Sprintf("[%s] %s", progname, format) format += ": %v\n" a = append(a, err) return fmt.Fprintf(os.Stderr, format, a...) } // Unpack reads a message from an io.Reader. func Unpack(r io.Reader) ([]byte, error) { var bl [2]byte _, err := io.ReadFull(r, bl[:]) if err != nil { return nil, err } n := binary.LittleEndian.Uint16(bl[:]) buf := make([]byte, int(n)) _, err = io.ReadFull(r, buf) return buf, err } const messageMax = 1 << 16 // Pack writes a message to an io.Writer. func Pack(w io.Writer, buf []byte) error { if len(buf) > messageMax { return errors.New("message is too large") } var bl [2]byte binary.LittleEndian.PutUint16(bl[:], uint16(len(buf))) _, err := w.Write(bl[:]) if err != nil { return err } _, err = w.Write(buf) return err } ================================================ FILE: transport/example/genca.sh ================================================ #!/bin/sh cfssl gencert -initca ca.json | cfssljson -bare ca ================================================ FILE: transport/example/maclient/client.go ================================================ package main import ( "bytes" "encoding/json" "flag" "fmt" "os" "github.com/cloudflare/cfssl/transport" "github.com/cloudflare/cfssl/transport/core" "github.com/cloudflare/cfssl/transport/example/exlib" ) // maclient is a mutual-authentication client, meant to demonstrate // using the client-side mutual authentication side of the transport // package. var messages = []string{"hello world", "hello", "world"} func main() { var addr, conf string flag.StringVar(&addr, "a", "127.0.0.1:9876", "`address` of server") flag.StringVar(&conf, "f", "client.json", "config `file` to use") flag.Parse() var id = new(core.Identity) data, err := os.ReadFile(conf) if err != nil { exlib.Err(1, err, "reading config file") } err = json.Unmarshal(data, id) if err != nil { exlib.Err(1, err, "parsing config file") } tr, err := transport.New(exlib.Before, id) if err != nil { exlib.Err(1, err, "creating transport") } conn, err := transport.Dial(addr, tr) if err != nil { exlib.Err(1, err, "dialing %s", addr) } defer conn.Close() for _, msg := range messages { if err = exlib.Pack(conn, []byte(msg)); err != nil { exlib.Err(1, err, "sending message") } var resp []byte resp, err = exlib.Unpack(conn) if err != nil { exlib.Err(1, err, "receiving message") } if !bytes.Equal(resp, []byte("OK")) { exlib.Errx(1, "server didn't send an OK message; received '%s'", resp) } } err = exlib.Pack(conn, []byte{}) if err != nil { exlib.Err(1, err, "sending shutdown message failed") } fmt.Println("OK") } ================================================ FILE: transport/example/maclient/client.json ================================================ { "request": { "CN": "test client", "hosts": ["127.0.0.1"] }, "profiles": { "paths": { "private_key": "client.key", "certificate": "client.pem" }, "cfssl": { "profile": "client", "remote": "127.0.0.1:8888" } }, "roots": [ { "type": "system" }, { "type": "cfssl", "metadata": { "host": "127.0.0.1:8888", "profile": "server" } } ] } ================================================ FILE: transport/example/maclient/client_auth.json ================================================ { "request": { "CN": "test client", "hosts": ["127.0.0.1"] }, "profiles": { "paths": { "private_key": "client.key", "certificate": "client.pem" }, "cfssl": { "profile": "client", "remote": "127.0.0.1:8888", "auth-type": "standard", "auth-key": "52abb3ac91971bb72bce17e7a289cd04476490b19e0d8eb7810dc42d4ac16c41" } }, "roots": [ { "type": "system" }, { "type": "cfssl", "metadata": { "host": "127.0.0.1:8888", "profile": "server" } } ] } ================================================ FILE: transport/example/maserver/server.go ================================================ package main import ( "encoding/json" "flag" "net" "os" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/transport" "github.com/cloudflare/cfssl/transport/core" "github.com/cloudflare/cfssl/transport/example/exlib" ) // maclient is a mutual-authentication server, meant to demonstrate // using the client-side mutual authentication side of the transport // package. func main() { var addr, conf string flag.StringVar(&addr, "a", "127.0.0.1:9876", "`address` of server") flag.StringVar(&conf, "f", "server.json", "config `file` to use") flag.Parse() var id = new(core.Identity) data, err := os.ReadFile(conf) if err != nil { exlib.Err(1, err, "reading config file") } err = json.Unmarshal(data, id) if err != nil { exlib.Err(1, err, "parsing config file") } tr, err := transport.New(exlib.Before, id) if err != nil { exlib.Err(1, err, "creating transport") } l, err := transport.Listen(addr, tr) if err != nil { exlib.Err(1, err, "setting up listener") } var errChan = make(chan error, 0) go func(ec <-chan error) { for { err, ok := <-ec if !ok { log.Warning("error channel closed, future errors will not be reported") break } log.Errorf("auto update error: %v", err) } }(errChan) log.Info("setting up auto-update") go l.AutoUpdate(nil, errChan) log.Info("listening on ", addr) exlib.Warn(serve(l), "serving listener") } func connHandler(conn net.Conn) { defer conn.Close() for { buf, err := exlib.Unpack(conn) if err != nil { exlib.Warn(err, "unpack message") return } if len(buf) == 0 { log.Info(conn.RemoteAddr(), " sent empty record, closing connection") return } log.Infof("received %d-byte message: %s", len(buf), buf) err = exlib.Pack(conn, []byte("OK")) if err != nil { exlib.Warn(err, "pack message") return } } } func serve(l net.Listener) error { defer l.Close() for { conn, err := l.Accept() if err != nil { exlib.Warn(err, "client connection failed") continue } log.Info("connection from ", conn.RemoteAddr()) go connHandler(conn) } } ================================================ FILE: transport/example/maserver/server.json ================================================ { "request": { "CN": "test server", "hosts": [ "127.0.0.1" ] }, "profiles": { "paths": { "private_key": "server.key", "certificate": "server.pem" }, "cfssl": { "profile": "server", "remote": "127.0.0.1:8888" } }, "roots": [ { "type": "system" } ], "client_roots": [ { "type": "cfssl", "metadata": { "host": "127.0.0.1:8888", "profile": "maclient" } } ] } ================================================ FILE: transport/example/maserver/server_auth.json ================================================ { "request": { "CN": "test server", "hosts": ["127.0.0.1"] }, "profiles": { "paths": { "private_key": "server.key", "certificate": "server.pem" }, "cfssl": { "profile": "server", "remote": "127.0.0.1:8888", "auth-type": "standard", "auth-key": "4f4f26686209f672e0ec7b19cbbc8b6d94fdd12cc0b20326f9005d5f234e6e3e" } }, "roots": [{ "type": "system" }], "client_roots": [{ "type": "cfssl", "metadata": { "host": "127.0.0.1:8888", "profile": "client" } }] } ================================================ FILE: transport/kp/key_provider.go ================================================ // Package kp describes transport key providers and provides a reference // implementation. // // KeyProviders are used by clients and servers as a mechanism for // providing keys and signing CSRs. It is a mechanism designed to // allow switching out how private keys and their associated // certificates are managed, such as supporting PKCS #11. The // StandardProvider provides disk-backed PEM-encoded certificates and // private keys. DiskFallback is a provider that will attempt to // retrieve the certificate from a CA first, falling back to a // disk-backed pair. This is useful for test a CA while providing a // failover solution. package kp import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "encoding/pem" "errors" "io" "os" "strings" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/helpers/derhelpers" "github.com/cloudflare/cfssl/transport/core" ) const ( curveP256 = 256 curveP384 = 384 curveP521 = 521 ) // A KeyProvider provides some mechanism for managing private keys and // certificates. It is not required to store the crypto.Signer itself. type KeyProvider interface { // Certificate returns the associated certificate, or nil if // one isn't ready. Certificate() *x509.Certificate // Given some metadata about a certificate request, the // provider should be able to generate a new CSR. CertificateRequest(*csr.CertificateRequest) ([]byte, error) // Check returns an error if the provider has an invalid setup. Check() error // Generate should trigger the creation of a new private // key. This will invalidate any certificates stored in the // key provider. Generate(algo string, size int) error // Load causes a private key and certificate associated with // this provider to be loaded into memory and be prepared for // use. Load() error // Persistent returns true if the provider keeps state on disk. Persistent() bool // Ready returns true if the provider has a key and // certificate. Ready() bool // SetCertificatePEM takes a PEM-encoded certificate and // associates it with this key provider. SetCertificatePEM([]byte) error // SignalFailure is used to notify the KeyProvider that an // error has occurred obtaining a certificate. If this returns // true, the caller should re-attempt to refresh the // keys. This, for example, can be used to implement failover // key providers that require different keys. SignalFailure(err error) bool // SignCSR allows a templated CSR to be signed. SignCSR(csr *x509.CertificateRequest) ([]byte, error) // Store should perform whatever actions are necessary such // that a call to Load later will reload the key and // certificate associated with this provider. Store() error // X509KeyPair returns a tls.Certficate. The returns // tls.Certificate should have a parsed Leaf certificate. X509KeyPair() (tls.Certificate, error) } // StandardPaths contains a path to a key file and certificate file. type StandardPaths struct { KeyFile string `json:"private_key"` CertFile string `json:"certificate"` } // StandardProvider provides unencrypted PEM-encoded certificates and // private keys. If paths are provided, the key and certificate will // be stored on disk. type StandardProvider struct { Paths StandardPaths `json:"paths"` internal struct { priv crypto.Signer cert *x509.Certificate // The PEM-encoded private key and certificate. This // is stored alongside the crypto.Signer and // x509.Certificate for convenience in marshaling and // calling tls.X509KeyPair directly. keyPEM []byte certPEM []byte } } // NewStandardProvider sets up new StandardProvider from the // information contained in an Identity. func NewStandardProvider(id *core.Identity) (*StandardProvider, error) { if id == nil { return nil, errors.New("transport: the identity hasn't been initialised. Has it been loaded from disk?") } paths := id.Profiles["paths"] if paths == nil { return &StandardProvider{}, nil } sp := &StandardProvider{ Paths: StandardPaths{ KeyFile: paths["private_key"], CertFile: paths["certificate"], }, } err := sp.Check() if err != nil { return nil, err } return sp, nil } func (sp *StandardProvider) resetCert() { sp.internal.cert = nil sp.internal.certPEM = nil } func (sp *StandardProvider) resetKey() { sp.internal.priv = nil sp.internal.keyPEM = nil } var ( // ErrMissingKeyPath is returned if the StandardProvider has // specified a certificate path but not a key path. ErrMissingKeyPath = errors.New("transport: standard provider is missing a private key path to accompany the certificate path") // ErrMissingCertPath is returned if the StandardProvider has // specified a private key path but not a certificate path. ErrMissingCertPath = errors.New("transport: standard provider is missing a certificate path to accompany the certificate path") ) // Check ensures that the paths are valid for the provider. func (sp *StandardProvider) Check() error { if sp.Paths.KeyFile == "" && sp.Paths.CertFile == "" { return nil } if sp.Paths.KeyFile == "" { return ErrMissingKeyPath } if sp.Paths.CertFile == "" { return ErrMissingCertPath } return nil } // Persistent returns true if the key and certificate will be stored // on disk. func (sp *StandardProvider) Persistent() bool { return sp.Paths.KeyFile != "" && sp.Paths.CertFile != "" } // Generate generates a new private key. func (sp *StandardProvider) Generate(algo string, size int) (err error) { sp.resetKey() sp.resetCert() algo = strings.ToLower(algo) switch algo { case "rsa": var priv *rsa.PrivateKey if size < 2048 { return errors.New("transport: RSA keys must be at least 2048 bits") } priv, err = rsa.GenerateKey(rand.Reader, size) if err != nil { return err } keyPEM := x509.MarshalPKCS1PrivateKey(priv) p := &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: keyPEM, } sp.internal.keyPEM = pem.EncodeToMemory(p) sp.internal.priv = priv case "ecdsa": var priv *ecdsa.PrivateKey var curve elliptic.Curve switch size { case curveP256: curve = elliptic.P256() case curveP384: curve = elliptic.P384() case curveP521: curve = elliptic.P521() default: return errors.New("transport: invalid elliptic curve key size; only 256-, 384-, and 521-bit keys are accepted") } priv, err = ecdsa.GenerateKey(curve, rand.Reader) if err != nil { return err } var keyPEM []byte keyPEM, err = x509.MarshalECPrivateKey(priv) if err != nil { return err } p := &pem.Block{ Type: "EC PRIVATE KEY", Bytes: keyPEM, } sp.internal.keyPEM = pem.EncodeToMemory(p) sp.internal.priv = priv case "ed25519": seed := make([]byte, ed25519.SeedSize) if _, err := io.ReadFull(rand.Reader, seed); err != nil { return err } priv := ed25519.NewKeyFromSeed(seed) keyPEM, err := derhelpers.MarshalEd25519PrivateKey(priv) if err != nil { return err } p := &pem.Block{ Type: "Ed25519 PRIVATE KEY", Bytes: keyPEM, } sp.internal.keyPEM = pem.EncodeToMemory(p) sp.internal.priv = priv default: return errors.New("transport: invalid key algorithm; only RSA, Ed25519 and ECDSA are supported") } return nil } // Certificate returns the associated certificate, or nil if // one isn't ready. func (sp *StandardProvider) Certificate() *x509.Certificate { return sp.internal.cert } // CertificateRequest takes some metadata about a certificate request, // and attempts to produce a certificate signing request suitable for // sending to a certificate authority. func (sp *StandardProvider) CertificateRequest(req *csr.CertificateRequest) ([]byte, error) { if sp.internal.priv == nil { if req.KeyRequest == nil { return nil, errors.New("transport: invalid key request in csr.CertificateRequest") } sp.Generate(req.KeyRequest.Algo(), req.KeyRequest.Size()) } return csr.Generate(sp.internal.priv, req) } // ErrCertificateUnavailable is returned when a key is available, but // there is no accompanying certificate. var ErrCertificateUnavailable = errors.New("transport: certificate unavailable") // Load a private key and certificate from disk. func (sp *StandardProvider) Load() (err error) { if !sp.Persistent() { return } var clearKey = true defer func() { if err != nil { if clearKey { sp.resetKey() } sp.resetCert() } }() sp.internal.keyPEM, err = os.ReadFile(sp.Paths.KeyFile) if err != nil { return } sp.internal.priv, err = helpers.ParsePrivateKeyPEM(sp.internal.keyPEM) if err != nil { return } clearKey = false sp.internal.certPEM, err = os.ReadFile(sp.Paths.CertFile) if err != nil { return ErrCertificateUnavailable } sp.internal.cert, err = helpers.ParseCertificatePEM(sp.internal.certPEM) if err != nil { err = errors.New("transport: invalid certificate") return } p, _ := pem.Decode(sp.internal.keyPEM) switch sp.internal.cert.PublicKey.(type) { case *rsa.PublicKey: if p.Type != "RSA PRIVATE KEY" { err = errors.New("transport: PEM type " + p.Type + " is invalid for an RSA key") return } case *ecdsa.PublicKey: if p.Type != "EC PRIVATE KEY" { err = errors.New("transport: PEM type " + p.Type + " is invalid for an ECDSA key") return } case ed25519.PublicKey: if p.Type != "Ed25519 PRIVATE KEY" { err = errors.New("transport: PEM type" + p.Type + "is invalid for an Ed25519 key") return } default: err = errors.New("transport: invalid public key type") } if err != nil { clearKey = true return } return nil } // Ready returns true if the provider has a key and certificate // loaded. The certificate should be checked by the end user for // validity. func (sp *StandardProvider) Ready() bool { switch { case sp.internal.priv == nil: return false case sp.internal.cert == nil: return false case sp.internal.keyPEM == nil: return false case sp.internal.certPEM == nil: return false default: return true } } // SetCertificatePEM receives a PEM-encoded certificate and loads it // into the provider. func (sp *StandardProvider) SetCertificatePEM(certPEM []byte) error { cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { return errors.New("transport: invalid certificate") } sp.internal.certPEM = certPEM sp.internal.cert = cert return nil } // SignalFailure is provided to implement the KeyProvider interface, // and always returns false. func (sp *StandardProvider) SignalFailure(err error) bool { return false } // SignCSR takes a template certificate request and signs it. func (sp *StandardProvider) SignCSR(tpl *x509.CertificateRequest) ([]byte, error) { return x509.CreateCertificateRequest(rand.Reader, tpl, sp.internal.priv) } // Store writes the key and certificate to disk, if necessary. func (sp *StandardProvider) Store() error { if !sp.Ready() { return errors.New("transport: provider does not have a key and certificate") } err := os.WriteFile(sp.Paths.CertFile, sp.internal.certPEM, 0644) if err != nil { return err } return os.WriteFile(sp.Paths.KeyFile, sp.internal.keyPEM, 0600) } // X509KeyPair returns a tls.Certificate for the provider. func (sp *StandardProvider) X509KeyPair() (tls.Certificate, error) { cert, err := tls.X509KeyPair(sp.internal.certPEM, sp.internal.keyPEM) if err != nil { return tls.Certificate{}, err } if cert.Leaf == nil { cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) if err != nil { return tls.Certificate{}, err } } return cert, nil } ================================================ FILE: transport/kp/key_provider_test.go ================================================ package kp import ( "os" "testing" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/transport/core" ) const ( testKey = "testdata/test.key" testCert = "testdata/test.pem" ) var testIdentity = &core.Identity{ Request: &csr.CertificateRequest{ CN: "localhost test certificate", }, Profiles: map[string]map[string]string{ "paths": { "private_key": testKey, "certificate": testCert, }, }, } func removeIfPresent(path string) error { if _, err := os.Stat(path); !os.IsNotExist(err) { return os.Remove(path) } return nil } func TestMain(m *testing.M) { exitCode := m.Run() err := removeIfPresent(testKey) if err == nil { err = removeIfPresent(testCert) } if err != nil { os.Exit(1) } os.Exit(exitCode) } var kp KeyProvider func TestNewStandardProvider(t *testing.T) { var err error kp, err = NewStandardProvider(testIdentity) if err != nil { t.Fatalf("%v", err) } if kp.Ready() { t.Fatalf("key provider should not be ready yet") } if err = kp.Check(); err != nil { t.Fatalf("calling check should return no error") } if nil != kp.Certificate() { t.Fatal("key provider should not have a certificate yet") } if kp.Ready() { t.Fatal("key provider should not be ready") } if !kp.Persistent() { t.Fatal("key provider should be persistent") } } func TestGenerate(t *testing.T) { err := kp.Load() if err == nil { t.Fatal("key provider shouldn't have a key yet") } err = kp.Generate("rsa", 2048) if err != nil { t.Fatalf("key provider couldn't generate key: %v", err) } err = kp.Generate("ecdsa", 256) if err != nil { t.Fatalf("key provider couldn't generate key: %v", err) } err = kp.Generate("ed25519", 256) // ed25519 key size is ignored if err != nil { t.Fatalf("key provider couldn't generate key: %v", err) } } ================================================ FILE: transport/listener.go ================================================ package transport import ( "crypto/tls" "net" "time" "github.com/cloudflare/cfssl/log" ) // A Listener is a TCP network listener for TLS-secured connections. type Listener struct { *Transport net.Listener } // Listen sets up a new server. If an error is returned, it means // the server isn't ready to begin listening. func Listen(address string, tr *Transport) (*Listener, error) { var err error l := &Listener{Transport: tr} config, err := tr.getConfig() if err != nil { return nil, err } l.Listener, err = tls.Listen("tcp", address, config) return l, err } func (tr *Transport) getConfig() (*tls.Config, error) { if tr.ClientTrustStore != nil { log.Info("using client auth") return tr.TLSClientAuthServerConfig() } log.Info("not using client auth") return tr.TLSServerConfig() } // PollInterval is how often to check whether a new certificate has // been found. var PollInterval = 30 * time.Second func pollWait(target time.Time) { for { <-time.After(PollInterval) if time.Now().After(target) { break } } } // AutoUpdate will automatically update the listener. If a non-nil // certUpdates chan is provided, it will receive timestamps for // reissued certificates. If errChan is non-nil, any errors that occur // in the updater will be passed along. func (l *Listener) AutoUpdate(certUpdates chan<- time.Time, errChan chan<- error) { defer func() { if r := recover(); r != nil { log.Criticalf("AutoUpdate panicked: %v", r) } }() for { // Wait until it's time to update the certificate. target := time.Now().Add(l.Lifespan()) if PollInterval == 0 { <-time.After(l.Lifespan()) } else { pollWait(target) } // Keep trying to update the certificate until it's // ready. for { log.Debug("refreshing certificate") err := l.RefreshKeys() if err == nil { break } delay := l.Transport.Backoff.Duration() log.Debugf("failed to update certificate, will try again in %s", delay) if errChan != nil { errChan <- err } <-time.After(delay) } if certUpdates != nil { certUpdates <- time.Now() } config, err := l.getConfig() if err != nil { log.Debugf("immediately after getting a new certificate, the Transport is reporting errors: %v", err) if errChan != nil { errChan <- err } } address := l.Listener.Addr().String() lnet := l.Listener.Addr().Network() l.Listener, err = tls.Listen(lnet, address, config) if err != nil { log.Debugf("immediately after getting a new certificate, the Transport is reporting errors: %v", err) if errChan != nil { errChan <- err } } log.Debug("listener: auto update of certificate complete") l.Transport.Backoff.Reset() } } ================================================ FILE: transport/roots/cfssl.go ================================================ package roots import ( "crypto/x509" "encoding/json" "errors" "github.com/cloudflare/cfssl/api/client" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/info" ) // This package contains CFSSL integration. // NewCFSSL produces a new CFSSL root. func NewCFSSL(metadata map[string]string) ([]*x509.Certificate, error) { host, ok := metadata["host"] if !ok { return nil, errors.New("transport: CFSSL root provider requires a host") } label := metadata["label"] profile := metadata["profile"] cert, err := helpers.LoadClientCertificate(metadata["mutual-tls-cert"], metadata["mutual-tls-key"]) if err != nil { return nil, err } remoteCAs, err := helpers.LoadPEMCertPool(metadata["tls-remote-ca"]) if err != nil { return nil, err } srv := client.NewServerTLS(host, helpers.CreateTLSConfig(remoteCAs, cert)) data, err := json.Marshal(info.Req{Label: label, Profile: profile}) if err != nil { return nil, err } resp, err := srv.Info(data) if err != nil { return nil, err } return helpers.ParseCertificatesPEM([]byte(resp.Certificate)) } ================================================ FILE: transport/roots/doc.go ================================================ // Package roots includes support for loading trusted roots from // various sources. // // The following are supported trusted roout sources provided: // // The "system" type does not take any metadata. It will use the // default system certificates provided by the operating system. // // The "cfssl" provider takes keys for the CFSSL "host", "label", and // "profile", and loads the returned certificate into the trust store. // // The "file" provider takes a source file (specified under the // "source" key) that contains one or more certificates and adds // them into the source tree. package roots ================================================ FILE: transport/roots/provider.go ================================================ package roots import ( "crypto/sha256" "crypto/x509" "errors" "os" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/transport/core" "github.com/cloudflare/cfssl/transport/roots/system" ) // Providers is a mapping of supported providers and the functions // that can build them. var Providers = map[string]func(map[string]string) ([]*x509.Certificate, error){ "system": system.New, "cfssl": NewCFSSL, "file": TrustPEM, } // A TrustStore contains a pool of certificate that are trusted for a // given TLS configuration. type TrustStore struct { roots map[string]*x509.Certificate } // Pool returns a certificate pool containing the certificates // loaded into the provider. func (ts *TrustStore) Pool() *x509.CertPool { var pool = x509.NewCertPool() for _, cert := range ts.roots { pool.AddCert(cert) } return pool } // Certificates returns a slice of the loaded certificates. func (ts *TrustStore) Certificates() []*x509.Certificate { var roots = make([]*x509.Certificate, 0, len(ts.roots)) for _, cert := range ts.roots { roots = append(roots, cert) } return roots } func (ts *TrustStore) addCerts(certs []*x509.Certificate) { if ts.roots == nil { ts.roots = map[string]*x509.Certificate{} } for _, cert := range certs { digest := sha256.Sum256(cert.Raw) ts.roots[string(digest[:])] = cert } } // Trusted contains a store of trusted certificates. type Trusted interface { // Certificates returns a slice containing the certificates // that are loaded into the provider. Certificates() []*x509.Certificate // AddCert adds a new certificate into the certificate pool. AddCert(cert *x509.Certificate) // AddPEM adds a one or more PEM-encoded certificates into the // certificate pool. AddPEM(cert []byte) bool } // New produces a new trusted root provider from a collection of // roots. If there are no roots, the system roots will be used. func New(rootDefs []*core.Root) (*TrustStore, error) { var err error var store = &TrustStore{} var roots []*x509.Certificate if len(rootDefs) == 0 { roots, err = system.New(nil) if err != nil { return nil, err } store.addCerts(roots) return store, nil } err = errors.New("transport: no supported root providers found") for _, root := range rootDefs { pfn, ok := Providers[root.Type] if ok { roots, err = pfn(root.Metadata) if err != nil { break } store.addCerts(roots) } } if err != nil { store = nil } return store, err } // TrustPEM takes a source file containing one or more certificates // and adds them to the trust store. func TrustPEM(metadata map[string]string) ([]*x509.Certificate, error) { sourceFile, ok := metadata["source"] if !ok { return nil, errors.New("transport: PEM source requires a source file") } in, err := os.ReadFile(sourceFile) if err != nil { return nil, err } return helpers.ParseCertificatesPEM(in) } ================================================ FILE: transport/roots/system/nilref_nil_darwin.go ================================================ // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build cgo && !arm && !arm64 && !ios && !go1.10 // +build cgo,!arm,!arm64,!ios,!go1.10 package system /* #cgo LDFLAGS: -framework CoreFoundation -framework Security #include */ import "C" // For Go versions before 1.10, nil values for Apple's CoreFoundation // CF*Ref types were represented by nil. See: // https://github.com/golang/go/commit/b868616b63a8 func setNilCFRef(v *C.CFDataRef) { *v = nil } func isNilCFRef(v C.CFDataRef) bool { return v == nil } ================================================ FILE: transport/roots/system/nilref_zero_darwin.go ================================================ // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build cgo && !arm && !arm64 && !ios && go1.10 // +build cgo,!arm,!arm64,!ios,go1.10 package system /* #cgo LDFLAGS: -framework CoreFoundation -framework Security #include */ import "C" // For Go versions >= 1.10, nil values for Apple's CoreFoundation // CF*Ref types are represented by zero. See: // https://github.com/golang/go/commit/b868616b63a8 func setNilCFRef(v *C.CFDataRef) { *v = 0 } func isNilCFRef(v C.CFDataRef) bool { return v == 0 } ================================================ FILE: transport/roots/system/root.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package system import ( "crypto/x509" "encoding/pem" "errors" ) func appendPEM(roots []*x509.Certificate, pemCerts []byte) ([]*x509.Certificate, bool) { var ok bool for len(pemCerts) > 0 { var block *pem.Block block, pemCerts = pem.Decode(pemCerts) if block == nil { break } if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { continue } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { continue } roots = append(roots, cert) ok = true } return roots, ok } // New returns a new certificate pool loaded with the system // roots. The provided argument is not used; it is included for // compatibility with other functions. func New(metadata map[string]string) ([]*x509.Certificate, error) { roots := initSystemRoots() if len(roots) == 0 { return nil, errors.New("transport: unable to find system roots") } return roots, nil } ================================================ FILE: transport/roots/system/root_bsd.go ================================================ // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build dragonfly || freebsd || netbsd || openbsd // +build dragonfly freebsd netbsd openbsd package system // Possible certificate files; stop after finding one. var certFiles = []string{ "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly "/etc/ssl/cert.pem", // OpenBSD "/etc/openssl/certs/ca-certificates.crt", // NetBSD } ================================================ FILE: transport/roots/system/root_cgo_darwin.go ================================================ // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build darwin && cgo && !arm && !arm64 && !ios // +build darwin,cgo,!arm,!arm64,!ios package system /* #cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060 #cgo LDFLAGS: -framework CoreFoundation -framework Security #include #include // FetchPEMRootsCFSSLTransport fetches the system's list of trusted X.509 root certificates. // // On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root // certificates of the system. On failure, the function returns -1. // // Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after // we've consumed its content. int FetchPEMRootsCFSSLTransport(CFDataRef *pemRoots) { if (pemRoots == NULL) { return -1; } CFArrayRef certs = NULL; OSStatus err = SecTrustCopyAnchorCertificates(&certs); if (err != noErr) { return -1; } CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0); int i, ncerts = CFArrayGetCount(certs); for (i = 0; i < ncerts; i++) { CFDataRef data = NULL; SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i); if (cert == NULL) { continue; } // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport. // Once we support weak imports via cgo we should prefer that, and fall back to this // for older systems. err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); if (err != noErr) { continue; } if (data != NULL) { CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data)); CFRelease(data); } } CFRelease(certs); *pemRoots = combinedData; return 0; } */ import "C" import ( "crypto/x509" "unsafe" ) func initSystemRoots() []*x509.Certificate { var roots []*x509.Certificate var data C.CFDataRef setNilCFRef(&data) err := C.FetchPEMRootsCFSSLTransport(&data) if err == -1 { return nil } defer C.CFRelease(C.CFTypeRef(data)) buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data))) roots, _ = appendPEM(roots, buf) return roots } ================================================ FILE: transport/roots/system/root_darwin.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go package system import ( "crypto/x509" "errors" "os/exec" ) func execSecurityRoots() ([]*x509.Certificate, error) { cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain") data, err := cmd.Output() if err != nil { return nil, err } roots, ok := appendPEM(nil, data) if !ok { return nil, errors.New("transport: no system roots found") } return roots, nil } ================================================ FILE: transport/roots/system/root_darwin_armx.go ================================================ // Created by root_darwin_arm_gen --output root_darwin_armx.go; DO NOT EDIT // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build cgo && darwin && (arm || arm64 || ios) // +build cgo // +build darwin // +build arm arm64 ios package system func initSystemRoots() { systemRoots = NewCertPool() systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM)) } const systemRootsPEM = ` -----BEGIN CERTIFICATE----- MIIF8DCCA9igAwIBAgIPBuhGJy8fCo/RhFzjafbVMA0GCSqGSIb3DQEBBQUAMDgx CzAJBgNVBAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXpl bnBlLmNvbTAeFw0wNzEyMTMxMzA4MjdaFw0zNzEyMTMwODI3MjVaMDgxCzAJBgNV BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXplbnBlLmNv bTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMnTesoPHqynhugWZWqx whtFMnGV2f4QW8yv56V5AY+Jw8ryVXH3d753lPNypCxE2J6SmxQ6oeckkAoKVo7F 2CaU4dlI4S0+2gpy3aOZFdqBoof0e24md4lYrdbrDLJBenNubdt6eEHpCIgSfocu ZhFjbFT7PJ1ywLwu/8K33Q124zrX97RovqL144FuwUZvXY3gTcZUVYkaMzEKsVe5 o4qYw+w7NMWVQWl+dcI8IMVhulFHoCCQk6GQS/NOfIVFVJrRBSZBsLVNHTO+xAPI JXzBcNs79AktVCdIrC/hxKw+yMuSTFM5NyPs0wH54AlETU1kwOENWocivK0bo/4m tRXzp/yEGensoYi0RGmEg/OJ0XQGqcwL1sLeJ4VQJsoXuMl6h1YsGgEebL4TrRCs tST1OJGh1kva8bvS3ke18byB9llrzxlT6Y0Vy0rLqW9E5RtBz+GGp8rQap+8TI0G M1qiheWQNaBiXBZO8OOi+gMatCxxs1gs3nsL2xoP694hHwZ3BgOwye+Z/MC5TwuG KP7Suerj2qXDR2kS4Nvw9hmL7Xtw1wLW7YcYKCwEJEx35EiKGsY7mtQPyvp10gFA Wo15v4vPS8+qFsGV5K1Mij4XkdSxYuWC5YAEpAN+jb/af6IPl08M0w3719Hlcn4c yHf/W5oPt64FRuXxqBbsR6QXAgMBAAGjgfYwgfMwgbAGA1UdEQSBqDCBpYEPaW5m b0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBB MDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEG A1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEw IFZpdG9yaWEtR2FzdGVpejAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUHRxlDqjyJXu0kc/ksbHmvVV0bAUwDQYJKoZIhvcNAQEFBQAD ggIBAMeBRm8hGE+gBe/n1bqXUKJg7aWSFBpSm/nxiEqg3Hh10dUflU7F57dp5iL0 +CmoKom+z892j+Mxc50m0xwbRxYpB2iEitL7sRskPtKYGCwkjq/2e+pEFhsqxPqg l+nqbFik73WrAGLRne0TNtsiC7bw0fRue0aHwp28vb5CO7dz0JoqPLRbEhYArxk5 ja2DUBzIgU+9Ag89njWW7u/kwgN8KRwCfr00J16vU9adF79XbOnQgxCvv11N75B7 XSus7Op9ACYXzAJcY9cZGKfsK8eKPlgOiofmg59OsjQerFQJTx0CCzl+gQgVuaBp E8gyK+OtbBPWg50jLbJtooiGfqgNASYJQNntKE6MkyQP2/EeTXp6WuKlWPHcj1+Z ggwuz7LdmMySlD/5CbOlliVbN/UShUHiGUzGigjB3Bh6Dx4/glmimj4/+eAJn/3B kUtdyXvWton83x18hqrNA/ILUpLxYm9/h+qrdslsUMIZgq+qHfUgKGgu1fxkN0/P pUTEvnK0jHS0bKf68r10OEMr3q/53NjgnZ/cPcqlY0S/kqJPTIAcuxrDmkoEVU3K 7iYLHL8CxWTTnn7S05EcS6L1HOUXHA0MUqORH5zwIe0ClG+poEnK6EOMxPQ02nwi o8ZmPrgbBYhdurz3vOXcFD2nhqi2WVIhA16L4wTtSyoeo09Q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH 4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er fF6adulZkMV8gzURZVE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ 6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl +zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX 4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ 51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp 6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq 7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p 26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi 1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu tGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe 3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI 2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp +2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW /zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB ZQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJVUzEY MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMjAeFw0wNDEyMTMxNTAwMTBaFw0y OTEyMDUxNTAwMTBaMFsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRYwFAYDVQQDEw1Eb0Qg Um9vdCBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCzB9o07 rP8/PNZxvrh0IgfscEEV/KtA4weqwcPYn/7aTDq/P8jYKHtLNgHArEUlw9IOCo+F GGQQPRoTcCpvjtfcjZOzQQ84Ic2tq8I9KgXTVxE3Dc2MUfmT48xGSSGOFLTNyxQ+ OM1yMe6rEvJl6jQuVl3/7mN1y226kTT8nvP0LRy+UMRC31mI/2qz+qhsPctWcXEF lrufgOWARVlnQbDrw61gpIB1BhecDvRD4JkOG/t/9bPMsoGCsf0ywbi+QaRktWA6 WlEwjM7eQSwZR1xJEGS5dKmHQa99brrBuKG/ZTE6BGf5tbuOkooAY7ix5ow4X4P/ UNU7ol1rshDMYwIDAQABoz8wPTAdBgNVHQ4EFgQUSXS7DF66ev4CVO97oMaVxgmA cJYwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBAJiRjT+JyLv1wGlzKTs1rLqzCHY9cAmS6YREIQF9FHYb7lFsHY0VNy17MWn0 mkS4r0bMNPojywMnGdKDIXUr5+AbmSbchECV6KjSzPZYXGbvP0qXEIIdugqi3VsG K52nZE7rLgE1pLQ/E61V5NVzqGmbEfGY8jEeb0DU+HifjpGgb3AEkGaqBivO4XqS tX3h4NGW56E6LcyxnR8FRO2HmdNNGnA5wQQM5X7Z8a/XIA7xInolpHOZzD+kByeW qKKV7YK5FtOeC4fCwfKI9WLfaN/HvGlR7bFc3FRUKQ8JOZqsA8HbDE2ubwp6Fknx v5HSOJTT9pUst2zJQraNypCNhdk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 l7+ijrRU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v 1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9jCCAt6gAwIBAgIQZIKe/DcedF38l/+XyLH/QTANBgkqhkiG9w0BAQsFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAy IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNzOkFyGOFyz9AYxe9GPo15gRn V2WYKaRPyVyPDzTS+NqoE2KquB5QZ3iwFkygOakVeq7t0qLA8JA3KRgmXOgNPLZs ST/B4NzZS7YUGQum05bh1gnjGSYc+R9lS/kaQxwAg9bQqkmi1NvmYji6UBRDbfkx +FYW2TgCkc/rbN27OU6Z4TBnRfHU8I3D3/7yOAchfQBeVkSz5GC9kSucq1sEcg+y KNlyqwUgQiWpWwNqIBDMMfAr2jUs0Pual07wgksr2F82owstr2MNHSV/oW5cYqGN KD6h/Bwg+AEvulWaEbAZ0shQeWsOagXXqgQ2sqPy4V93p3ec5R7c6d9qwWVdAgMB AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBSHjCCVyJhK0daABkqQNETfHE2/sDANBgkqhkiG9w0BAQsFAAOCAQEAgY6ypWaW tyGltu9vI1pf24HFQqV4wWn99DzX+VxrcHIa/FqXTQCAiIiCisNxDY7FiZss7Y0L 0nJU9X3UXENX6fOupQIR9nYrgVfdfdp0MP1UR/bgFm6mtApI5ud1Bw8pGTnOefS2 bMVfmdUfS/rfbSw8DVSAcPCIC4DPxmiiuB1w2XaM/O6lyc+tHc+ZJVdaYkXLFmu9 Sc2lo4xpeSWuuExsi0BmSxY/zwIa3eFsawdhanYVKZl/G92IgMG/tY9zxaaWI4Sm KIYkM2oBLldzJbZev4/mHWGoQClnHYebHX+bn5nNMdZUvmK7OaxoEkiRIKXLsd3+ b/xa5IJVWa8xqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn 0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM //bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t 3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h 2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq 299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd 7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw ++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt 398znM/jra6O1I7mT1GvFpLgXPYHDw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2 MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC 206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2 JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9 BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67 Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3 +L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2 LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8 CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw RY8mkaKO/qk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 +rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c 2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHqTCCBZGgAwIBAgIQYwaGp8U3ZaVDkKhqWMzUMjANBgkqhkiG9w0BAQUFADCB jzELMAkGA1UEBhMCTFYxNTAzBgNVBAoTLFZBUyBMYXR2aWphcyBQYXN0cyAtIFZp ZW4ucmVnLk5yLjQwMDAzMDUyNzkwMSMwIQYDVQQLExpTZXJ0aWZpa2FjaWphcyBw YWthbHBvanVtaTEkMCIGA1UEAxMbVkFTIExhdHZpamFzIFBhc3RzIFNTSShSQ0Ep MB4XDTA2MDkxMzA5MjIxMFoXDTI0MDkxMzA5Mjc1N1owgY8xCzAJBgNVBAYTAkxW MTUwMwYDVQQKEyxWQVMgTGF0dmlqYXMgUGFzdHMgLSBWaWVuLnJlZy5Oci40MDAw MzA1Mjc5MDEjMCEGA1UECxMaU2VydGlmaWthY2lqYXMgcGFrYWxwb2p1bWkxJDAi BgNVBAMTG1ZBUyBMYXR2aWphcyBQYXN0cyBTU0koUkNBKTCCAiIwDQYJKoZIhvcN AQEBBQADggIPADCCAgoCggIBAJu4+f1hVS9PpKUUtS6OuSSPrPuxVD9A/0/F5YZo e1OT+zWCNahQLpRSoNuDPnXaFXCsCc/ugkmtNkm5tHGLtAChQgbKCApjl7YI/O60 3Jh4GYLJ+H9kPqrJ/rGN67Bk9bzzxD46kOpOjj8bGbxqg8ORPGxV+wpSwOjhXXeF M8VJ3+xqv79sN/6OSaIVGM6LjmseOKMwb4iBfnJWRBrEejkP9sSPltSy6wBOXN67 5zu35iQFk2tN5pFEv+6YG8eFGxFBeyI2p74+6Ho33BjekJ2PzbLXmj/iF39bDOHv P2Y9biTksM7DDIhslNo4JXxSOeNzFLMARWOaDEJAXgTG93JkzsluM7Pk020klTeT fvIAXRmLH/NDc6ifRdIGqey0Qrv67gzHTz9RH9Gv0KwYf4eBIv6p3QeWbXz4TtlN OlBp1UF+xdp02I5z5X6D4cMZgbe9v0COvi6aogyqTgIuuyrhCF0xA8msJ7Cv3NXI FH1AnVWJIfmQzNTJYEFzq+jN2DpVOQqCmf6b9fU8HJHLwPpGVK4h/CqsXHveepdx /WxrzUiapNuBfBg3L5B9YZS9F8lctlQWd8oJSqrpvE+UdQFaVryS0o+515feVnQB 9xZxSbH1GEaZQe5i4bMsZXVpKXJDA/ibH/o49J7sQBCOrJfVsDO+nxjcLfdBeFRK YkTnAgMBAAGjggH9MIIB+TAOBgNVHQ8BAf8EBAMCAQYwGAYIKwYBBQUHAQMEDDAK MAgGBgQAjkYBATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTMw/Vm/3OsOFqW GyGJuIFMH8teJTAQBgkrBgEEAYI3FQEEAwIBADCCAYkGA1UdIASCAYAwggF8MIIB eAYLKwYBBAGBxFkBAQIwggFnMIIBOAYIKwYBBQUHAgIwggEqHoIBJgBTAGkAcwAg AGkAcgAgAHMAZQByAHQAaQBmAGkAawBhAHQAcwAsACAAawBvACAAaQB6AGQAZQB2 AGkAcwAgAFYAQQBTACAATABhAHQAdgBpAGoAYQBzACAAUABhAHMAdABzACwAIABu AG8AZAByAG8AcwBpAG4AbwB0ACAAYQB0AGIAaQBsAHMAdABpAGIAdQAgAEUAbABl AGsAdAByAG8AbgBpAHMAawBvACAAZABvAGsAdQBtAGUAbgB0AHUAIABsAGkAawB1 AG0AYQBtACAAdQBuACAARQBpAHIAbwBwAGEAcwAgAFAAYQByAGwAYQBtAGUAbgB0 AGEAIABkAGkAcgBlAGsAdABpAHYAYQBpACAAMQA5ADkAOQAvADkAMwAvAEUASzAp BggrBgEFBQcCARYdaHR0cDovL3d3dy5lLW1lLmx2L3JlcG9zaXRvcnkwDQYJKoZI hvcNAQEFBQADggIBAB8oSjWQIWNoCi94r6MegiaXoz8nGdJLo0J6BhNlW8EEy+t9 fO+U8vGJ9bffUgIhadLqljTloM+XuJxVDhCFoxReLAX4tTp28/l6uN62DCdp8suU kQsdudWOb5kvzfIZVjk6SFbwAf+Cdbay/dHU9fJjV0xNoX7MELoEae/0FPyzlx9F 7m9KKH/Rxie8x6Opa3vtghNvq94P+3HrXBEaqSzQMJ/8NjdW75XpurcTtq6fAmGt nuxrBG82nw+Z98LJyEwouSjUIdeeVNXAzvSO5FWUe48kxjj8q3qkVnc9qEXvZJKk 0Ep+u3OL9A1Sc7g6SF5DgNOpcHdi/8coHHMeQ+YnJFtJueY2pI79xS0veqV5EnrX IbIlbcgPosNhS+VI4le6n/KKId3bZPDaGd/OwJuAOcJ3d2MVU3KE+qSPBzeGIX1Q +j1qN9uRDjez/c4Lynth0Jx0nH04aG3pex3W8Sq07ztgUncF5gLCX4xbvPB9t3PH kWuyKrNjozTVq60lcUf/Gj56to2VdsPups0DCWzuRWeYz5lIdsHOinSaaFIBNCLI 7eIUC4S9bhCMsXKbvugI11fVf+q0AT1O5OLoZ+eMfunnQhHvlUbIkda+JxeAGTSY 58bfHvwhX56GPbx+8Jy9cp70R4JbcWfz+txUTKhc2FnH0AcOEzMnvPRp8Gsh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzET MBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UE AxMIQ0EgRGlzaWcwHhcNMDYwMzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQsw CQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcg YS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgmGErE Nx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnX mjxUizkDPw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYD XcDtab86wYqg6I7ZuUUohwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhW S8+2rT+MitcE5eN4TPWGqvWP+j1scaMtymfraHtuM6kMgiioTGohQBUgDCZbg8Kp FhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8wgfwwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0PAQH/BAQD AgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cu ZGlzaWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5z ay9jYS9jcmwvY2FfZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2sv Y2EvY3JsL2NhX2Rpc2lnLmNybDAaBgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEw DQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59tWDYcPQuBDRIrRhCA/ec8J9B6 yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3mkkp7M5+cTxq EEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeB EicTXxChds6KezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFN PGO+I++MzVpQuGhU+QqZMxEA4Z7CRneC9VkGjCFMhwnN5ag= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXTCCAkWgAwIBAgIDAOJCMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNVBAYTAkFU MRAwDgYDVQQKEwdBLVRydXN0MRkwFwYDVQQLExBBLVRydXN0LW5RdWFsLTAxMRkw FwYDVQQDExBBLVRydXN0LW5RdWFsLTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEz MDIzMDAwMFowVTELMAkGA1UEBhMCQVQxEDAOBgNVBAoTB0EtVHJ1c3QxGTAXBgNV BAsTEEEtVHJ1c3QtblF1YWwtMDExGTAXBgNVBAMTEEEtVHJ1c3QtblF1YWwtMDEw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD/9RyAEZ6eHmhYzNJ328f0 jmdSUFi6EqRqOxb3jHNPTIpK82CR6z5lmSnZQNUuCPD+htbNZffd2DKVB06NOyZ1 2zcOMCgj4GtkZoqE0zPpPT3bpoE55nkZZe/qWEX/64wz/L/4EdkvKDSKG/UsP75M tmCVY5m2Eg73RVFRz4ccBIMpHel4lzEqSkdDtZOY5fnkrE333hx67nxq21vY8Eyf 8O4fPQ5RtN8eohQCcPQ1z6ypU1R7N9jPRpnI+yzMOiwd3+QcKhHi1miCzo0pkOaB 1CwmfsTyNl8qU0NJUL9Ta6cea7WThwTiWol2yD88cd2cy388xpbNkfrCPmZNGLoV AgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECE5ZzscCMocwMA4G A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEA69I9R1hU9Gbl9vV7W7AH QpUJAlFAvv2It/eY8p2ouQUPVaSZikaKtAYrCD/arzfXB43Qet+dM6CpHsn8ikYR vQKePjXv3Evf+C1bxwJAimcnZV6W+bNOTpdo8lXljxkmfN+Z5S+XzvK2ttUtP4Et YOVaxHw2mPMNbvDeY+foJkiBn3KYjGabMaR8moZqof5ofj4iS/WyamTZti6v/fKx n1vII+/uWkcxV5DT5+r9HLon0NYF0Vg317Wh+gWDV59VZo+dcwJDb+keYqMFYoqp 77SGkZGu41S8NGYkQY3X9rNHRkDbLfpKYDmy6NanpOE1EHW1/sNSFAs43qZZKJEQ xg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9 hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM 1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws 6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50 aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u 7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0 xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ +jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S 5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B 8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc 0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e KeC2uAloGRwYQw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV 6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH 1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF 62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh 4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEajCCA1KgAwIBAgIBATANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJKUDEN MAsGA1UECgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24g Rm9yIEpQS0kxETAPBgNVBAsMCEJyaWRnZUNBMB4XDTAzMTIyNzA1MDgxNVoXDTEz MTIyNjE0NTk1OVowWjELMAkGA1UEBhMCSlAxDTALBgNVBAoMBEpQS0kxKTAnBgNV BAsMIFByZWZlY3R1cmFsIEFzc29jaWF0aW9uIEZvciBKUEtJMREwDwYDVQQLDAhC cmlkZ2VDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANTnUmg7K3m8 52vd77kwkq156euwoWm5no8E8kmaTSc7x2RABPpqNTlMKdZ6ttsyYrqREeDkcvPL yF7yf/I8+innasNtsytcTAy8xY8Avsbd4JkCGW9dyPjk9pzzc3yLQ64Rx2fujRn2 agcEVdPCr/XpJygX8FD5bbhkZ0CVoiASBmlHOcC3YpFlfbT1QcpOSOb7o+VdKVEi MMfbBuU2IlYIaSr/R1nO7RPNtkqkFWJ1/nKjKHyzZje7j70qSxb+BTGcNgTHa1YA UrogKB+UpBftmb4ds+XlkEJ1dvwokiSbCDaWFKD+YD4B2s0bvjCbw8xuZFYGhNyR /2D5XfN1s2MCAwEAAaOCATkwggE1MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MG0GA1UdHwRmMGQwYqBgoF6kXDBaMQswCQYDVQQGEwJKUDENMAsGA1UE CgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24gRm9yIEpQ S0kxETAPBgNVBAsMCEJyaWRnZUNBMIGDBgNVHREEfDB6pHgwdjELMAkGA1UEBhMC SlAxJzAlBgNVBAoMHuWFrOeahOWAi+S6uuiqjeiovOOCteODvOODk+OCuTEeMBwG A1UECwwV6YO96YGT5bqc55yM5Y2U6K2w5LyaMR4wHAYDVQQLDBXjg5bjg6rjg4Pj grjoqo3oqLzlsYAwHQYDVR0OBBYEFNQXMiCqQNkR2OaZmQgLtf8mR8p8MA0GCSqG SIb3DQEBBQUAA4IBAQATjJo4reTNPC5CsvAKu1RYT8PyXFVYHbKsEpGt4GR8pDCg HEGAiAhHSNrGh9CagZMXADvlG0gmMOnXowriQQixrtpkmx0TB8tNAlZptZWkZC+R 8TnjOkHrk2nFAEC3ezbdK0R7MR4tJLDQCnhEWbg50rf0wZ/aF8uAaVeEtHXa6W0M Xq3dSe0XAcrLbX4zZHQTaWvdpLAIjl6DZ3SCieRMyoWUL+LXaLFdTP5WBCd+No58 IounD9X4xxze2aeRVaiV/WnQ0OSPNS7n7YXy6xQdnaOU4KRW/Lne1EDf5IfWC/ih bVAmhZMbcrkWWcsR6aCPG+2mV3zTD6AUzuKPal8Y -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7 5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7 ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a 0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1 4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3 WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ 2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89 9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0 jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38 aQNiuJkFBT1reBK9sG9l -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs ewv4n4Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK SnQ2+Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi 1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP BSeOE6Fuwg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ /jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs 81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG 9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta 3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk 6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 /qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 jVaMaA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAmygAwIBAgIBCTANBgkqhkiG9w0BAQUFADAzMQswCQYDVQQGEwJDTjER MA8GA1UEChMIVW5pVHJ1c3QxETAPBgNVBAMTCFVDQSBSb290MB4XDTA0MDEwMTAw MDAwMFoXDTI5MTIzMTAwMDAwMFowMzELMAkGA1UEBhMCQ04xETAPBgNVBAoTCFVu aVRydXN0MREwDwYDVQQDEwhVQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBALNdB8qGJn1r4vs4CQ7MgsJqGgCiFV/W6dQBt1YDAVmP9ThpJHbC XivF9iu/r/tB/Q9a/KvXg3BNMJjRnrJ2u5LWu+kQKGkoNkTo8SzXWHwk1n8COvCB a2FgP/Qz3m3l6ihST/ypHWN8C7rqrsRoRuTej8GnsrZYWm0dLNmMOreIy4XU9+gD Xv2yTVDo1h//rgI/i0+WITyb1yXJHT/7mLFZ5PCpO6+zzYUs4mBGzG+OoOvwNMXx QhhgrhLtRnUc5dipllq+3lrWeGeWW5N3UPJuG96WUUqm1ktDdSFmjXfsAoR2XEQQ th1hbOSjIH23jboPkXXHjd+8AmCoKai9PUMCAwEAAaOBojCBnzALBgNVHQ8EBAMC AQYwDAYDVR0TBAUwAwEB/zBjBgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIG CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcD BwYIKwYBBQUHAwgGCCsGAQUFBwMJMB0GA1UdDgQWBBTbHzXza0z/QjFkm827Wh4d SBC37jANBgkqhkiG9w0BAQUFAAOCAQEAOGy3iPGt+lg3dNHocN6cJ1nL5BXXoMNg 14iABMUwTD3UGusGXllH5rxmy+AI/Og17GJ9ysDawXiv5UZv+4mCI4/211NmVaDe JRI7cTYWVRJ2+z34VFsxugAG+H1V5ad2g6pcSpemKijfvcZsCyOVjjN/Hl5AHxNU LJzltQ7dFyiuawHTUin1Ih+QOfTcYmjwPIZH7LgFRbu3DJaUxmfLI3HQjnQi1kHr A6i26r7EARK1s11AdgYg1GS4KUYGis4fk5oQ7vuqWrTcL9Ury/bXBYSYBZELhPc9 +tb5evosFeo2gkO3t7jj83EB7UNDogVFwygFBzXjAaU4HoDU18PZ3g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg 4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ /L7fCg0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDlDCCAnygAwIBAgIQWAsFbFMk27JQVxhf+eWmUDANBgkqhkiG9w0BAQUFADAn MQswCQYDVQQGEwJCRTEYMBYGA1UEAxMPQmVsZ2l1bSBSb290IENBMB4XDTAzMDEy NjIzMDAwMFoXDTE0MDEyNjIzMDAwMFowJzELMAkGA1UEBhMCQkUxGDAWBgNVBAMT D0JlbGdpdW0gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AMihcekcRkJ5eHFvna6pqKsot03HIOswkVp19eLSz8hMFJhCWK3HEcVAQGpa+XQS J4fpnOVxTiIs0RIYqjBeoiG52bv/9nTrMQHnO35YD5EWTXaJqAFPrSJmcPpLHZXB MFjqvNll2Jq0iOtJRlLf0lMVdssUXRlJsW9q09P9vMIt7EU/CT9YvvzU7wCMgTVy v/cY6pZifSsofxVsY9LKyn0FrMhtB20yvmi4BUCuVJhWPmbxMOjvxKuTXgfeMo8S dKpbNCNUwOpszv42kqgJF+qhLc9s44Qd3ocuMws8dOIhUDiVLlzg5cYx+dtA+mqh pIqTm6chBocdJ9PEoclMsG8CAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4AQEBMC4wLAYIKwYBBQUHAgEW IGh0dHA6Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQQ8AxW m2HqVzq2NZdtn925FI7b5jARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAU EPAMVpth6lc6tjWXbZ/duRSO2+YwDQYJKoZIhvcNAQEFBQADggEBAMhtIlGKYfgP lm7VILKB+MbcoxYA2s1q52sq+llIp0xJN9dzoWoBZV4yveeX09AuPHPTjHuD79ZC wT+oqV0PN7p20kC9zC0/00RBSZz9Wyn0AiMiW3Ebv1jZKE4tRfTa57VjRUQRDSp/ M382SbTObqkCMa5c/ciJv0J71/Fg8teH9lcuen5qE4Ad3OPQYx49cTGxYNSeCMqr 8JTHSHVUgfMbrXec6LKP24OsjzRr6L/D2fVDw2RV6xq9NoY2uiGMlxoh1OotO6y6 7Kcdq765Sps1LxxcHVGnH1TtEpf/8m6HfUbJdNbv6z195lluBpQE5KJVhzgoaiJe 4r50ErAEQyo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp 3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBk MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg Q0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2MjUwNzM4MTRaMGQxCzAJBgNVBAYT AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvEr jw0DzpPMLgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r 0rk0X2s682Q2zsKwzxNoysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f 2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJwDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVP ACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpHWrumnf2U5NGKpV+GY3aF y6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1aSgJA/MTA tukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL 6yxSNLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0 uPoTXGiTOmekl9AbmbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrAL acywlKinh/LTSlDcX3KwFnUey7QYYpqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velh k6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3qPyZ7iVNTA6z00yPhOgpD/0Q VAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw FDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqh b97iEoHF8TwuMA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4R fbgZPnm3qKhyN2abGu2sEzsOv2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv /2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ82YqZh6NM4OKb3xuqFp1mrjX2lhI REeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLzo9v/tdhZsnPdTSpx srpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcsa0vv aGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciAT woCqISxxOQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99n Bjx8Oto0QuFmtEYE3saWmA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5W t6NlUe07qxS/TFED6F+KBZvuim6c779o+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N 8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TCrvJcwhbtkj6EPnNgiLx2 9CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX5OfNeOI5 wSsSnqaeG8XmDtkx2Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3 dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo 5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+ pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU 4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5 81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIIKv++n6Lw6YcwDQYJKoZIhvcNAQEFBQAwKDELMAkGA1UE BhMCQkUxGTAXBgNVBAMTEEJlbGdpdW0gUm9vdCBDQTIwHhcNMDcxMDA0MTAwMDAw WhcNMjExMjE1MDgwMDAwWjAoMQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1 bSBSb290IENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZzQh6S /3UPi790hqc/7bIYLS2X+an7mEoj39WN4IzGMhwWLQdC1i22bi+n9fzGhYJdld61 IgDMqFNAn68KNaJ6x+HK92AQZw6nUHMXU5WfIp8MXW+2QbyM69odRr2nlL/zGsvU +40OHjPIltfsjFPekx40HopQcSZYtF3CiInaYNKJIT/e1wEYNm7hLHADBGXvmAYr XR5i3FVr/mZkIV/4L+HXmymvb82fqgxG0YjFnaKVn6w/Fa7yYd/vw2uaItgscf1Y HewApDgglVrH1Tdjuk+bqv5WRi5j2Qsj1Yr6tSPwiRuhFA0m2kHwOI8w7QUmecFL TqG4flVSOmlGhHUCAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4CQEBMC4wLAYIKwYBBQUHAgEWIGh0dHA6 Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSFiuv0xbu+DlkD lN7WgAEV4xCcOTARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUhYrr9MW7 vg5ZA5Te1oABFeMQnDkwDQYJKoZIhvcNAQEFBQADggEBAFHYhd27V2/MoGy1oyCc UwnzSgEMdL8rs5qauhjyC4isHLMzr87lEwEnkoRYmhC598wUkmt0FoqW6FHvv/pK JaeJtmMrXZRY0c8RcrYeuTlBFk0pvDVTC9rejg7NqZV3JcqUWumyaa7YwBO+mPyW nIR/VRPmPIfjvCCkpDZoa01gZhz5v6yAlGYuuUGK02XThIAC71AdXkbc98m6tTR8 KvPG2F9fVJ3bTc0R5/0UAoNmXsimABKgX77OFP67H6dh96tK8QYUn8pJQsKpvO2F sauBQeYNxUJpU4c5nUwfAA4+Bw11V0SoU7Q2dmSZ3G7rPUZuFF1eR1ONeE3gJ7uO hXY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp 5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy 5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv 6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen 5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL +63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc 8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg 515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO xwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r 6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3zCCA8egAwIBAgIOGTMAAQACKBqaBLzyVUUwDQYJKoZIhvcNAQEFBQAwejEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUGA1UEAxMeVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMB4XDTA2MDMyMjE1NTgzNFoXDTMwMTIz MTIyNTk1OVowejELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVy IEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUG A1UEAxMeVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAi9R3azRs5TbYalxeOO781R15Azt7g2JEgk6I 7d6D/+7MUGIFBZWZdpj2ufJf2AaRksL2LWYXH/1TA+iojWOpbuHWG4y8mLOLO9Tk Lsp9hUkmW3m4GotAnn+7yT9jLM/RWny6KCJBElpN+Rd3/IX9wkngKhh/6aAsnPlE /AxoOUL1JwW+jhV6YJ3wO8c85j4WvK923mq3ouGrRkXrjGV90ZfzlxElq1nroCLZ gt2Y7X7i+qBhCkoy3iwX921E6oFHWZdXNwM53V6CItQzuPomCba8OYgvURVOm8M7 3xOCiN1LNPIz1pDp81PcNXzAw9l8eLPNcD+NauCjgUjkKa1juPD8KGQ7mbN9/pqd iPaZIgiRRxaJNXhdd6HPv0nh/SSUK2k2e+gc5iqQilvVOzRZQtxtz7sPQRxVzfUN Wy4WIibvYR6X/OJTyM9bo8ep8boOhhLLE8oVx+zkNo3aXBM9ZdIOXXB03L+PemrB Lg/Txl4PK1lszGFs/sBhTtnmT0ayWuIZFHCE+CAA7QGnl37DvRJckiMXoKUdRRcV I5qSCLUiiI3cKyTr4LEXaNOvYb3ZhXj2jbp4yjeNY77nrB/fpUcJucglMVRGURFV DYlcjdrSGC1z8rjVJ/VIIjfRYvd7Dcg4i6FKsPzQ8eu3hmPn4A5zf/1yUbXpfeJV BWR4Z38CAwEAAaNjMGEwHwYDVR0jBBgwFoAUzdeQoW6jv9sw1toyJZAM5jkegGUw DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFM3XkKFu o7/bMNbaMiWQDOY5HoBlMA0GCSqGSIb3DQEBBQUAA4ICAQB+FojoEw42zG4qhQc4 xlaJeuNHIWZMUAgxWlHQ/KZeFHXeTDvs8e3MfhEHSmHu6rOOOqQzxu2KQmZP8Tx7 yaUFQZmx7Cxb7tyW0ohTS3g0uW7muw/FeqZ8Dhjfbw90TNGp8aHp2FRkzF6WeKJW GsFzshXGVwXf2vdIJIqOf2qp+U3pPmrOYCx9LZAI9mOPFdAtnIz/8f38DBZQVhT7 upeG7rRJA1TuG1l/MDoCgoYhrv7wFfLfToPmmcW6NfcgkIw47XXP4S73BDD7Ua2O giRAyn0pXdXZ92Vk/KqfdLh9kl3ShCngE+qK99CrxK7vFcXCifJ7tjtJmGHzTnKR N4xJkunI7Cqg90lufA0kxmts8jgvynAF5X/fxisrgIDV2m/LQLvYG/AkyRDIRAJ+ LtOYqqIN8SvQ2vqOHP9U6OFKbt2o1ni1N6WsZNUUI8cOpevhCTjXwHxgpV2Yj4wC 1dxWqPNNWKkL1HxkdAEy8t8PSoqpAqKiHYR3wvHMl700GXRd4nQ+dSf3r7/ufA5t VIimVuImrTESPB5BeW0X6hNeH/Vcn0lZo7Ivo0LD+qh+v6WfSMlgYmIK371F3uNC tVGW/cT1Gpm4UqJEzS1hjBWPgdVdotSQPYxuQGHDWV3Y2eH2dEcieXR92sqjbzcV NvAsGnE8EXbfXRo+VGN4a2V+Hw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo 19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e 3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 MBr1mmz0DlP5OlvRHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK 4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv 2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEBDCCAuygAwIBAgIIGHqpqMKWIQwwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEy MDIwMTIyMTIxNVoXDTI3MDIwMTIyMTIxNVoweTEtMCsGA1UEAwwkRGV2ZWxvcGVy IElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQLDB1BcHBsZSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UE BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJdk8GW5pB7qUj KwKjX9dzP8A1sIuECj8GJH+nlT/rTw6Tr7QO0Mg+5W0Ysx/oiUe/1wkI5P9WmCkV 55SduTWjCs20wOHiYPTK7Cl4RWlpYGtfipL8niPmOsIiszFPHLrytjRZQu6wqQID GJEEtrN4LjMfgEUNRW+7Dlpbfzrn2AjXCw4ybfuGNuRsq8QRinCEJqqfRNHxuMZ7 lBebSPcLWBa6I8WfFTl+yl3DMl8P4FJ/QOq+rAhklVvJGpzlgMofakQcbD7EsCYf Hex7r16gaj1HqVgSMT8gdihtHRywwk4RaSaLy9bQEYLJTg/xVnTQ2QhLZniiq6yn 4tJMh1nJAgMBAAGjgaYwgaMwHQYDVR0OBBYEFFcX7aLP3HyYoRDg/L6HLSzy4xdU MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/ CF4wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5j cmwwDgYDVR0PAQH/BAQDAgGGMBAGCiqGSIb3Y2QGAgYEAgUAMA0GCSqGSIb3DQEB CwUAA4IBAQBCOXRrodzGpI83KoyzHQpEvJUsf7xZuKxh+weQkjK51L87wVA5akR0 ouxbH3Dlqt1LbBwjcS1f0cWTvu6binBlgp0W4xoQF4ktqM39DHhYSQwofzPuAHob tHastrW7T9+oG53IGZdKC1ZnL8I+trPEgzrwd210xC4jUe6apQNvYPSlSKcGwrta 4h8fRkV+5Jf1JxC3ICJyb3LaxlB1xT0lj12jAOmfNoxIOY+zO+qQgC6VmmD0eM70 DgpTPqL6T9geroSVjTK8Vk2J6XgY4KyaQrp6RhuEoonOFOiI0ViL9q5WxCwFKkWv C9lLqQIPNKyIx2FViUTJJ3MH7oLlTvVw -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd /ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv 2G0xffX8oRAHh84vWdw+WNs= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICqDCCAi2gAwIBAgIQIW4zpcvTiKRvKQe0JzzE2DAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAxIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAATXZrUb266zYO5G6ohjdTsqlG3zXxL24w+etgoUU0hS yNw6s8tIICYSTvqJhNTfkeQpfSgB2dsYQ2mhH7XThhbcx39nI9/fMTGDAzVwsUu3 yBe7UcvclBfb6gk7dhLeqrWjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRlwI0l9Qy6l3eQP54u4Fr1ztXh5DAKBggqhkjOPQQD AwNpADBmAjEApa7jRlP4mDbjIvouKEkN7jB+M/PsP3FezFWJeJmssv3cHFwzjim5 axfIEWi13IMHAjEAnMhE2mnCNsNUGRCFAtqdR+9B52wmnQk9922Q0QVEL7C8g5No 8gxFSTm/mQQc0xCg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1 7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn 8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/ 2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtjCCAp6gAwIBAgIOBcAAAQACQdAGCk3OdRAwDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDQgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDQgQ0EgSUkwHhcNMDYwMzIzMTQxMDIzWhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBALXNTJytrlG7fEjFDSmGehSt2VA9CXIgDRS2Y8b+WJ7gIV7z jyIZ3E6RIM1viCmis8GsKnK6i1S4QF/yqvhDhsIwXMynXX/GCEnkDjkvjhjWkd0j FnmA22xIHbzB3ygQY9GB493fL3l1oht48pQB5hBiecugfQLANIJ7x8CtHUzXapZ2 W78mhEj9h/aECqqSB5lIPGG8ToVYx5ct/YFKocabEvVCUNFkPologiJw3fX64yhC L04y87OjNopq1mJcrPoBbbTgci6VaLTxkwzGioLSHVPqfOA/QrcSWrjN2qUGZ8uh d32llvCSHmcOHUJG5vnt+0dTf1cERh9GX8eu4I8CAwEAAaNCMEAwDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFB/quz4lGwa9pd1iBX7G TFq/6A9DMA0GCSqGSIb3DQEBBQUAA4IBAQBYpCubTPfkpJKknGWYGWIi/HIy6QRd xMRwLVpG3kxHiiW5ot3u6hKvSI3vK2fbO8w0mCr3CEf/Iq978fTr4jgCMxh1KBue dmWsiANy8jhHHYz1nwqIUxAUu4DlDLNdjRfuHhkcho0UZ3iMksseIUn3f9MYv5x5 +F0IebWqak2SNmy8eesOPXmK2PajVnBd3ttPedJ60pVchidlvqDTB4FAVd0Qy+BL iILAkH0457+W4Ze6mqtCD9Of2J4VMxHL94J59bXAQVaS4d9VA61Iz9PyLrHHLVZM ZHQqMc7cdalUR6SnQnIJ5+ECpkeyBM1CE+FhDOB4OiIgohxgQoaH96Xm -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC +Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X 7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz 43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2 MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym 1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb 2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t 9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd +SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N 0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie 4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 /YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0 MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+ +FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1 XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3 R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93 d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0 YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7 R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX UKqK1drk/NAJBzewdXUh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC Q04xMjAwBgNVBAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24g Q2VudGVyMUcwRQYDVQQDDD5DaGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0 aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMgUm9vdDAeFw0xMDA4MzEwNzExMjVa Fw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAGA1UECgwpQ2hpbmEg SW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMMPkNo aW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRp ZmljYXRlcyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z 7r07eKpkQ0H1UN+U8i6yjUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA// DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV98YPjUesWgbdYavi7NifFy2cyjw1l1Vx zUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2HklY0bBoQCxfVWhyXWIQ8 hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23KzhmBsUs 4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54u gQEC7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oY NJKiyoOCWTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E FgQUfHJLOcfA22KlT5uqGDSSosqDglkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3 j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd50XPFtQO3WKwMVC/GVhMPMdoG 52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM7+czV0I664zB echNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrI zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy wy39FCqQmbkHzJ8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp +ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og /zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y 4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza 8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMw MVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQ MA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOB SvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkz ABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH LCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMP PbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL 2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8w ggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwIC MIHDHoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDk AGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0 AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABz AGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABhAG0AaQBz AGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f BCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcY P2/v6X2+MA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOi CfP+JmeaUOTDBS8rNXiRTHyoERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+g kcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyLabVAyJRld/JXIWY7zoVAtjNjGr95 HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678IIbsSt4beDI3poHS na9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkhMp6q qIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0Z TbvGRNs2yyqcjg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwS QXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcN MTQwNDMwMTgxOTA2WhcNMzkwNDMwMTgxOTA2WjBnMRswGQYDVQQDDBJBcHBsZSBS b290IENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9y aXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzB2MBAGByqGSM49 AgEGBSuBBAAiA2IABJjpLz1AcqTtkyJygRMc3RCV8cWjTnHcFBbZDuWmBSp3ZHtf TjjTuxxEtX/1H7YyYl3J6YRbTzBPEVoA/VhYDKX1DyxNB0cTddqXl5dvMVztK517 IDvYuVTZXpmkOlEKMaNCMEAwHQYDVR0OBBYEFLuw3qFYM4iapIqZ3r6966/ayySr MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gA MGUCMQCD6cHEFl4aXTQY2e3v9GwOAEZLuN+yRhHFD/3meoyhpmvOwgPUnPWTxnS4 at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM 6BgD56KyKA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp /hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y Johw1+qRzT65ysCQblrGXnRl11z+o+I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO 0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj 7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS 8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ 3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDczCCAlugAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN MAsGA1UECgwES0lTQTEuMCwGA1UECwwlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkgQ2VudHJhbDEWMBQGA1UEAwwNS0lTQSBSb290Q0EgMTAeFw0wNTA4MjQw ODA1NDZaFw0yNTA4MjQwODA1NDZaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKDARL SVNBMS4wLAYDVQQLDCVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 cmFsMRYwFAYDVQQDDA1LSVNBIFJvb3RDQSAxMIIBIDANBgkqhkiG9w0BAQEFAAOC AQ0AMIIBCAKCAQEAvATk+hM58DSWIGtsaLv623f/J/es7C/n/fB/bW+MKs0lCVsk 9KFo/CjsySXirO3eyDOE9bClCTqnsUdIxcxPjHmc+QZXfd3uOPbPFLKc6tPAXXdi 8EcNuRpAU1xkcK8IWsD3z3X5bI1kKB4g/rcbGdNaZoNy4rCbvdMlFQ0yb2Q3lIVG yHK+d9VuHygvx2nt54OJM1jT3qC/QOhDUO7cTWu8peqmyGGO9cNkrwYV3CmLP3WM vHFE2/yttRcdbYmDz8Yzvb9Fov4Kn6MRXw+5H5wawkbMnChmn3AmPC7fqoD+jMUE CSVPzZNHPDfqAmeS/vwiJFys0izgXAEzisEZ2wIBA6MyMDAwHQYDVR0OBBYEFL+2 J9gDWnZlTGEBQVYx5Yt7OtnMMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF BQADggEBABOvUQveimpb5poKyLGQSk6hAp3MiNKrZr097LuxQpVqslxa/6FjZJap aBV/JV6K+KRzwYCKhQoOUugy50X4TmWAkZl0Q+VFnUkq8JSV3enhMNITbslOsXfl BM+tWh6UCVrXPAgcrnrpFDLBRa3SJkhyrKhB2vAhhzle3/xk/2F0KpzZm4tfwjeT 2KM3LzuTa7IbB6d/CVDv0zq+IWuKkDsnSlFOa56ch534eJAx7REnxqhZvvwYC/uO fi5C4e3nCSG9uRPFVmf0JqZCQ5BEVLRxm3bkGhKsGigA35vB1fjbXKP4krG9tNT5 UNkAAk/bg9ART6RCVmE6fhMy04Qfybo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD 75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp 5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p 6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI l7WdmplNsDz4SgCbZN2fOUvRJ9e4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C +C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk 3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz 6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0zCCA7ugAwIBAgIVALhZFHE/V9+PMcAzPdLWGXojF7TrMA0GCSqGSIb3DQEB DQUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dp ZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBIDIwHhcNMTExMDA2 MDgzOTU2WhcNNDYxMDA2MDgzOTU2WjCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoT GVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0 d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvfl4+ObV gAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC5SBLm9qbe7mZXdmbgEvXhEAr J9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Vaqp3cKcniNQfrcE1K1sGzVrih QTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ0WeNG0a+RzDVLnLRxWPa52N5 RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet/5oCl8HGUJKbAiy9qbk0WQq/ hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNeGWJoRVfkkIJCu0LW8GHgwaM9 ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcVWiNoidQ+3k4nsPBADLxNF8tN orMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbls+V1e9dBkQXcXWnjlQ1DufyD ljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZbMI28iQzV13D4h1L92u+sUS4H s07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+NqcnoYsylfzGuXIkosagpZ6w7xQ EmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbljnX98sy50IdbzAYQYLuDNbde Z95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUtqFUOQLDoD+Oirz61PgcptE6Dv0wDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBDQUAA4ICAQCdU8KBJdw1LK4K3VqbRjBWu9S0bEuG5gql 0pKKmo3cj7TudvQDy+ubAXirKmu1uiNOMXy1LN0taWczbmNdORgS+KAoU0SHq2rE kpYfKqIcup3dJ/tSTbCPWujtjcNo45KgJgyHkLAD6mplKAjERnjgW7oO8DPcJ7Z+ iD29kqSWfkGogAh71jYSvBAVmyS8q619EYkvMe340s9Tjuu0U6fnBMovpiLEEdzr mMkiXUFq3ApSBFu8LqB9x7aSuySg8zfRK0OozPFoeBp+b2OQe590yGvZC1X2eQM9 g8dBQJL7dgs3JRc8rz76PFwbhvlKDD+KxF4OmPGt7s/g/SE1xzNhzKI3GEN8M+mu doKCB0VIO8lnbq2jheiWVs+8u/qry7dXJ40aL5nzIzM0jspTY9NXNFBPz0nBBbrF qId744aP+0OiEumsUewEdkzw+o+5MRPpCLckCfmgtwc2WFfPxLt+SWaVNQS2dzW4 qVMpX5KF+FLEWk79BmE5+33QdkeSzOwrvYRu5ptFwX1isVMtnnWg58koUNflvKiq B3hquXS0YPOEjQPcrpHadEQNe0Kpd9YrfKHGbBNTIqkSmqX5TyhFNbCXT0ZlhcX0 /WKiomr8NDAGft8M4HOBlslEKt4fguxscletKWSk8cYpjjVgU85r2QK+OTB14Pdc Y2rwQMEsjQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDQzCCAiugAwIBAgIQX/h7KCtU3I1CoxW1aMmt/zANBgkqhkiG9w0BAQUFADA1 MRYwFAYDVQQKEw1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENB IDIwNDgwHhcNMDQwNTE0MjAxNzEyWhcNMjkwNTE0MjAyNTQyWjA1MRYwFAYDVQQK Ew1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENBIDIwNDgwggEg MA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQCwmrmrp68Kd6ficba0ZmKUeIhH xmJVhEAyv8CrLqUccda8bnuoqrpu0hWISEWdovyD0My5jOAmaHBKeN8hF570YQXJ FcjPFto1YYmUQ6iEqDGYeJu5Tm8sUxJszR2tKyS7McQr/4NEb7Y9JHcJ6r8qqB9q VvYgDxFUl4F1pyXOWWqCZe+36ufijXWLbvLdT6ZeYpzPEApk0E5tzivMW/VgpSdH jWn0f84bcN5wGyDWbs2mAag8EtKpP6BrXruOIIt6keO1aO6g58QBdKhTCytKmg9l Eg6CTY5j/e/rmxrbU6YTYK/CfdfHbBcl1HP7R2RQgYCUTOG/rksc35LtLgXfAgED o1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJ/PI FR5umgIJFq0roIlgX9p7L6owEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEF BQADggEBAJ2dhISjQal8dwy3U8pORFBi71R803UXHOjgxkhLtv5MOhmBVrBW7hmW Yqpao2TB9k5UM8Z3/sUcuuVdJcr18JOagxEu5sv4dEX+5wW4q+ffy0vhN4TauYuX cB7w4ovXsNgOnbFp1iqRe6lJT37mjpXYgyc81WhJDtSd9i7rp77rMKSsH0T8lasz Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4 CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg 8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJB VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5R dWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5RdWFsLTAzMB4XDTA1MDgxNzIyMDAw MFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgwRgYDVQQKDD9BLVRy dXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0ZW52 ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMM EEEtVHJ1c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCtPWFuA/OQO8BBC4SAzewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUj lUC5B3ilJfYKvUWG6Nm9wASOhURh73+nyfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZ znF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPESU7l0+m0iKsMrmKS1GWH 2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4iHQF63n1 k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs 2e3Vcuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYD VR0OBAoECERqlWdVeRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC AQEAVdRU0VlIXLOThaq/Yy/kgM40ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fG KOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmrsQd7TZjTXLDR8KdCoLXEjq/+ 8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZdJXDRZslo+S4R FGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmE DNuxUCAKGkq6ahq97BvIxYSazQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA 2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu MdRAGmI0Nj81Aa6sY6A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFHjCCBAagAwIBAgIEAKA3oDANBgkqhkiG9w0BAQsFADCBtzELMAkGA1UEBhMC Q1oxOjA4BgNVBAMMMUkuQ0EgLSBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHksIDA5LzIwMDkxLTArBgNVBAoMJFBydm7DrSBjZXJ0aWZpa2HEjW7DrSBh dXRvcml0YSwgYS5zLjE9MDsGA1UECww0SS5DQSAtIEFjY3JlZGl0ZWQgUHJvdmlk ZXIgb2YgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlczAeFw0wOTA5MDEwMDAwMDBaFw0x OTA5MDEwMDAwMDBaMIG3MQswCQYDVQQGEwJDWjE6MDgGA1UEAwwxSS5DQSAtIFF1 YWxpZmllZCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSwgMDkvMjAwOTEtMCsGA1UE CgwkUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRhLCBhLnMuMT0wOwYDVQQL DDRJLkNBIC0gQWNjcmVkaXRlZCBQcm92aWRlciBvZiBDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtTaEy0KC8M9l 4lSaWHMs4+sVV1LwzyJYiIQNeCrv1HHm/YpGIdY/Z640ceankjQvIX7m23BK4OSC 6KO8kZYA3zopOz6GFCOKV2PvLukbc+c2imF6kLHEv6qNA8WxhPbR3xKwlHDwB2yh Wzo7V3QVgDRG83sugqQntKYC3LnlTGbJpNP+Az72gpO9AHUn/IBhFk4ksc8lYS2L 9GCy9CsmdKSBP78p9w8Lx7vDLqkDgt1/zBrcUWmSSb7AE/BPEeMryQV1IdI6nlGn BhWkXOYf6GSdayJw86btuxC7viDKNrbp44HjQRaSxnp6O3eto1x4DfiYdw/YbJFe 7EjkxSQBywIDAQABo4IBLjCCASowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwgecGA1UdIASB3zCB3DCB2QYEVR0gADCB0DCBzQYIKwYBBQUHAgIwgcAa gb1UZW50byBjZXJ0aWZpa2F0IGplIHZ5ZGFuIGpha28ga3ZhbGlmaWtvdmFueSBz eXN0ZW1vdnkgY2VydGlmaWthdCBwb2RsZSB6YWtvbmEgYy4gMjI3LzIwMDAgU2Iu IHYgcGxhdG5lbSB6bmVuaS9UaGlzIGlzIHF1YWxpZmllZCBzeXN0ZW0gY2VydGlm aWNhdGUgYWNjb3JkaW5nIHRvIEN6ZWNoIEFjdCBOby4gMjI3LzIwMDAgQ29sbC4w HQYDVR0OBBYEFHnL0CPpOmdwkXRP01Hi4CD94Sj7MA0GCSqGSIb3DQEBCwUAA4IB AQB9laU214hYaBHPZftbDS/2dIGLWdmdSbj1OZbJ8LIPBMxYjPoEMqzAR74tw96T i6aWRa5WdOWaS6I/qibEKFZhJAVXX5mkx2ewGFLJ+0Go+eTxnjLOnhVF2V2s+57b m8c8j6/bS6Ij6DspcHEYpfjjh64hE2r0aSpZDjGzKFM6YpqsCJN8qYe2X1qmGMLQ wvNdjG+nPzCJOOuUEypIWt555ZDLXqS5F7ZjBjlfyDZjEfS2Es9Idok8alf563Mi 9/o+Ba46wMYOkk3P1IlU0RqCajdbliioACKDztAqubONU1guZVzV8tuMASVzbJeL /GAB7ECTwe1RuKrLYtglMKI9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ 9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst 0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK 1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ 8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm fyWl8kgAwKQB2j8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0 MRMwEQYDVQQDEwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQG EwJJTDAeFw0wNDAzMjQxMTMyMThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMT CkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNpZ24xCzAJBgNVBAYTAklMMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49qROR+WCf4C9DklBKK 8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTyP2Q2 98CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb 2CEJKHxNGGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxC ejVb7Us6eva1jsz/D3zkYDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7Kpi Xd3DTKaCQeQzC6zJMw9kglcq/QytNuEMrkvF7zuZ2SOzW120V+x0cAwqTwIDAQAB o4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2Zl ZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0PAQH/BAQD AgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRL AZs+VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWd foPPbrxHbvUanlR2QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0M cXS6hMTXcpuEfDhOZAYnKuGntewImbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq 8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb/627HOkthIDYIb6FUtnUdLlp hbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VGzT2ouvDzuFYk Res3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U AGegcQCCSA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1 NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2 N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1 axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4 ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb QErNaLly7HF27FSOH4UMAWr6pjisH8SE -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIETTCCAzWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJDSDEO MAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0aWVzMRcwFQYDVQQDEw5BZG1pbkNBLUNELVQwMTAe Fw0wNjAxMjUxMzM2MTlaFw0xNjAxMjUxMjM2MTlaMG0xCzAJBgNVBAYTAkNIMQ4w DAYDVQQKEwVhZG1pbjERMA8GA1UECxMIU2VydmljZXMxIjAgBgNVBAsTGUNlcnRp ZmljYXRpb24gQXV0aG9yaXRpZXMxFzAVBgNVBAMTDkFkbWluQ0EtQ0QtVDAxMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0jQlMZmpLDhV+GNR9TAoSNle JgQB4xAXJELQf5/ySMfoFA4MmjKqYXQkB6MGPuQKwR9XRRSPf61vqb8YPsdjRmgp byHBcUd5t0N8RX6wRZUnPMW+bCCo2VqAU4XFbnlc2gHKaam0wdTtbBTXEkv0ieIH fxCfFxXqSsSr60IkF/2/xbrAgV/QD5yHk6Ie8feAVWwi5UtaFqtu4LiFEh2QMyxs Oyz1OcvKzkM2g873tyiE7jzMgZP+Ww3tibk2F9+e6ZeiB37TLOmVtvgpmrws4fiI rFNXEYSWBVrUTbn81U47yWzOgf5fEHP07bRV5QOCzCm99qNimsbL6CG7nT78CQID AQABo4H3MIH0MBIGA1UdEwEB/wQIMAYBAf8CAQAwga4GA1UdIASBpjCBozCBoAYI YIV0AREDFQEwgZMwSAYIKwYBBQUHAgIwPBo6VGhpcyBpcyB0aGUgQWRtaW5DQS1D RC1UMDEgQ2VydGlmaWNhdGUgUHJhY3RpY2UgU3RhdGVtZW50LjBHBggrBgEFBQcC ARY7aHR0cDovL3d3dy5wa2kuYWRtaW4uY2gvcG9saWN5L0NQU18yXzE2Xzc1Nl8x XzE3XzNfMjFfMS5wZGYwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQqxGkKocZV xgNucM6GgbOkD6oZ2zANBgkqhkiG9w0BAQUFAAOCAQEAn356bbusjI5glGXRQ1DR v21qQf0S4s3GHyZm7cqdOkFleM70ArBT+kOP5Nm7rlSAFyVgEkmBdOg7s9tlXClU yeZFnp6UEYRUcijPN8D1VaNRK6PIUObpDBQT0C+kAfxG9z4v29T0SxT4sgAdC/xQ Fyv58Fp9bPn7owuKwKcyCH1XSyi/Bp4XFELlLOaigBZO/w+dPBz4FcJSdZjU+BaJ 0E3nKAjHlShO5ouBSZnaJz3p+nkw2Wyo36s6GxCK0XbkSP45iniIG4FmwwZkonYF ypQntHbx2oL7tUQQY0PDo8bGBMcPy/G2j+dciqZRlsnfgMy10SCzQ9MUx92xUG2V eg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFVTCCBD2gAwIBAgIEO/OB0DANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJj aDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQDEw1BZG1pbi1Sb290LUNB MB4XDTAxMTExNTA4NTEwN1oXDTIxMTExMDA3NTEwN1owbDELMAkGA1UEBhMCY2gx DjAMBgNVBAoTBWFkbWluMREwDwYDVQQLEwhTZXJ2aWNlczEiMCAGA1UECxMZQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdGllczEWMBQGA1UEAxMNQWRtaW4tUm9vdC1DQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMvgr0QUIv5qF0nyXZ3PXAJi C4C5Wr+oVTN7oxIkXkxvO0GJToM9n7OVJjSmzBL0zJ2HXj0MDRcvhSY+KiZZc6Go vDvr5Ua481l7ILFeQAFtumeza+vvxeL5Nd0Maga2miiacLNAKXbAcUYRa0Ov5VZB ++YcOYNNt/aisWbJqA2y8He+NsEgJzK5zNdayvYXQTZN+7tVgWOck16Da3+4FXdy fH1NCWtZlebtMKtERtkVAaVbiWW24CjZKAiVfggjsiLo3yVMPGj3budLx5D9hEEm vlyDOtcjebca+AcZglppWMX/iHIrx7740y0zd6cWEqiLIcZCrnpkr/KzwO135GkC AwEAAaOCAf0wggH5MA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIASBkTCBjjCBiwYI YIV0AREDAQAwfzArBggrBgEFBQcCAjAfGh1UaGlzIGlzIHRoZSBBZG1pbi1Sb290 LUNBIENQUzBQBggrBgEFBQcCARZEaHR0cDovL3d3dy5pbmZvcm1hdGlrLmFkbWlu LmNoL1BLSS9saW5rcy9DUFNfMl8xNl83NTZfMV8xN18zXzFfMC5wZGYwfwYDVR0f BHgwdjB0oHKgcKRuMGwxFjAUBgNVBAMTDUFkbWluLVJvb3QtQ0ExIjAgBgNVBAsT GUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxETAPBgNVBAsTCFNlcnZpY2VzMQ4w DAYDVQQKEwVhZG1pbjELMAkGA1UEBhMCY2gwHQYDVR0OBBYEFIKf+iNzIPGXi7JM Tb5CxX9mzWToMIGZBgNVHSMEgZEwgY6AFIKf+iNzIPGXi7JMTb5CxX9mzWTooXCk bjBsMQswCQYDVQQGEwJjaDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZp Y2VzMSIwIAYDVQQLExlDZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQD Ew1BZG1pbi1Sb290LUNBggQ784HQMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B AQUFAAOCAQEAeE96XCYRpy6umkPKXDWCRn7INo96ZrWpMggcDORuofHIwdTkgOeM vWOxDN/yuT7CC3FAaUajbPRbDw0hRMcqKz0aC8CgwcyIyhw/rFK29mfNTG3EviP9 QSsEbnelFnjpm1wjz4EaBiFjatwpUbI6+Zv3XbEt9QQXBn+c6DeFLe4xvC4B+MTr a440xTk59pSYux8OHhEvqIwHCkiijGqZhTS3KmGFeBopaR+dJVBRBMoXwzk4B3Hn 0Zib1dEYFZa84vPJZyvxCbLOnPRDJgH6V2uQqbG+6DXVaf/wORVOvF/wzzv0viM/ RWbEtJZdvo8N3sdtCULzifnxP/V0T9+4ZQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5 3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0 TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6 b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0 ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3 dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3 Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+ NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY 83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3 macqaJVmlaut74nLYKkGEsaUR+ko -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 sycX -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIBCDANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJDTjER MA8GA1UEChMIVW5pVHJ1c3QxGDAWBgNVBAMTD1VDQSBHbG9iYWwgUm9vdDAeFw0w ODAxMDEwMDAwMDBaFw0zNzEyMzEwMDAwMDBaMDoxCzAJBgNVBAYTAkNOMREwDwYD VQQKEwhVbmlUcnVzdDEYMBYGA1UEAxMPVUNBIEdsb2JhbCBSb290MIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2rPlBlA/9nP3xDK/RqUlYjOHsGj+p9+I A2N9Apb964fJ7uIIu527u+RBj8cwiQ9tJMAEbBSUgU2gDXRm8/CFr/hkGd656YGT 0CiFmUdCSiw8OCdKzP/5bBnXtfPvm65bNAbXj6ITBpyKhELVs6OQaG2BkO5NhOxM cE4t3iQ5zhkAQ5N4+QiGHUPR9HK8BcBn+sBR0smFBySuOR56zUHSNqth6iur8CBV mTxtLRwuLnWW2HKX4AzKaXPudSsVCeCObbvaE/9GqOgADKwHLx25urnRoPeZnnRc GQVmMc8+KlL+b5/zub35wYH1N9ouTIElXfbZlJrTNYsgKDdfUet9Ysepk9H50DTL qScmLCiQkjtVY7cXDlRzq6987DqrcDOsIfsiJrOGrCOp139tywgg8q9A9f9ER3Hd J90TKKHqdjn5EKCgTUCkJ7JZFStsLSS3JGN490MYeg9NEePorIdCjedYcaSrbqLA l3y74xNLytu7awj5abQEctXDRrl36v+6++nwOgw19o8PrgaEFt2UVdTvyie3AzzF HCYq9TyopZWbhvGKiWf4xwxmse1Bv4KmAGg6IjTuHuvlb4l0T2qqaqhXZ1LUIGHB zlPL/SR/XybfoQhplqCe/klD4tPq2sTxiDEhbhzhzfN1DiBEFsx9c3Q1RSw7gdQg 7LYJjD5IskkCAwEAAaOBojCBnzALBgNVHQ8EBAMCAQYwDAYDVR0TBAUwAwEB/zBj BgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcD BAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUHAwgGCCsGAQUF BwMJMB0GA1UdDgQWBBTZw9P4gJJnzF3SOqLXcaK0xDiALTANBgkqhkiG9w0BAQUF AAOCAgEA0Ih5ygiq9ws0oE4Jwul+NUiJcIQjL1HDKy9e21NrW3UIKlS6Mg7VxnGF sZdJgPaE0PC6t3GUyHlrpsVE6EKirSUtVy/m1jEp+hmJVCl+t35HNmktbjK81HXa QnO4TuWDQHOyXd/URHOmYgvbqm4FjMh/Rk85hZCdvBtUKayl1/7lWFZXbSyZoUkh 1WHGjGHhdSTBAd0tGzbDLxLMC9Z4i3WA6UG5iLHKPKkWxk4V43I29tSgQYWvimVw TbVEEFDs7d9t5tnGwBLxSzovc+k8qe4bqi81pZufTcU0hF8mFGmzI7GJchT46U1R IgP/SobEHOh7eQrbRyWBfvw0hKxZuFhD5D1DCVR0wtD92e9uWfdyYJl2b/Unp7uD pEqB7CmB9HdL4UISVdSGKhK28FWbAS7d9qjjGcPORy/AeGEYWsdl/J1GW1fcfA67 loMQfFUYCQSu0feLKj6g5lDWMDbX54s4U+xJRODPpN/xU3uLWrb2EZBL1nXz/gLz Ka/wI3J9FO2pXd96gZ6bkiL8HvgBRUGXx2sBYb4zaPKgZYRmvOAqpGjTcezHCN6j w8k2SjTxF+KAryAhk5Qe5hXTVGLxtTgv48y5ZwSpuuXu+RBuyy5+E6+SFP7zJ3N7 OPxzbbm5iPZujAv1/P8JDrMtXnt145Ik4ubhWD5LKAN1axibRww= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdjCCAl6gAwIBAgIEOhsEBTANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJE SzEMMAoGA1UEChMDS01EMQ8wDQYDVQQLEwZLTUQtQ0ExIzAhBgNVBAMTGktNRC1D QSBLdmFsaWZpY2VyZXQgUGVyc29uMB4XDTAwMTEyMTIzMjQ1OVoXDTE1MTEyMjIz MjQ1OVowUTELMAkGA1UEBhMCREsxDDAKBgNVBAoTA0tNRDEPMA0GA1UECxMGS01E LUNBMSMwIQYDVQQDExpLTUQtQ0EgS3ZhbGlmaWNlcmV0IFBlcnNvbjCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBANriF4Xd6yD7ZlBE317UBDObn+vRMVc6 p3wNQODdEDJe2z1ncCz9NJvhoLGdOJhyg7VVPh0P2c+KZ9WI9mWOKZI2bp2WkLju jCcxbhTrurY3Wfc6gwLBqqFV8wWgaZKmvVWizjw9Kyi25f3yX4fOho6Qq2lvVbub tvVFXAd51GJ+/2Yed+a4Or2bz2RcqHS81B3pywsD4mgJR5xREv5jqPfwNP+V7bkc X+pfO4kVhZ/V+8MSPdQHgcV/iB3wP2mwgWyIBNc1reBidGTiz8unnWu55hcNfsvt LJbTs9OHhsR7naRuy+S402nDnD5vnONOFEsiHn46w+T0rtu7h6j4OvkCAwEAAaNW MFQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUeWLqmhI42Jxj7DifDsW+ DlQhKD0wHwYDVR0jBBgwFoAUeWLqmhI42Jxj7DifDsW+DlQhKD0wDQYJKoZIhvcN AQEFBQADggEBANML/P42OuJ9aUV/0fItuIyc1JhqWvSqn5bXj+9eyEegcp8bHLHY 42D1O+z0lNipdjYPSdMJ0wZOEUhr+150SdDQ1P/zQL8AUaLEBkRt7ZdzXPVH3PER qnf9IrpYBknZKfCAoVchA6Rr9WU3Sd8bMoRfMLKg8c0M8G6EPwCTcOFriSkbtvNG zd8r8I+WfUYIN/p8DI9JT9qfjVODnYPRMUm6KPvq27TsrGruKrqyaV94kWc8co8A v3zFLeCtghvUiRBdx+8Q7m5t4CkuSr0WINrqjIPFW2QrM1r82y09Fd16RkqL4LOg Lh6vB5KnTApv62rWdw7zWwYnjY6/vXYY1Aw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAw ZzELMAkGA1UEBhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdp dGFsIENlcnRpZmljYXRlIFNlcnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290 IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcNMzEwNjI1MDg0NTA4WjBnMQswCQYD VQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2Vy dGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYgQ0Eg MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7Bx UglgRCgzo3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD 1ycfMQ4jFrclyxy0uYAyXhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPH oCE2G3pXKSinLr9xJZDzRINpUKTk4RtiGZQJo/PDvO/0vezbE53PnUgJUmfANykR HvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8LiqG12W0OfvrSdsyaGOx9/ 5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaHZa0zKcQv idm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHL OdAGalNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaC NYGu+HuB5ur+rPQam3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f 46Fq9mDU5zXNysRojddxyNMkM3OxbPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCB UWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDixzgHcgplwLa7JSnaFp6LNYth 7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/BAQDAgGGMB0G A1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWB bj2ITY1x0kbBbkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6x XCX5145v9Ydkn+0UjrgEjihLj6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98T PLr+flaYC/NUn81ETm484T4VvwYmneTwkLbUwp4wLh/vx3rEUMfqe9pQy3omywC0 Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7XwgiG/W9mR4U9s70 WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH59yL Gn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm 7JFe3VE/23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4S nr8PyQUQ3nqjsTzyP6WqJ3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VN vBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyAHmBR3NdUIR7KYndP+tiPsys6DXhyyWhB WkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/giuMod89a2GQ+fYWVq6nTI fI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuWl8PVP3wb I+2ksx0WckNLIOFZfsLorSa/ovc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDczCCAlugAwIBAgIQMDAwMDk3Mzc1NzM4NjAwMDANBgkqhkiG9w0BAQUFADBV MQswCQYDVQQGEwJGUjETMBEGA1UEChMKQ2VydGlOb21pczEcMBoGA1UECxMTQUMg UmFjaW5lIC0gUm9vdCBDQTETMBEGA1UEAxMKQ2VydGlOb21pczAeFw0wMDExMDkw MDAwMDBaFw0xMjExMDkwMDAwMDBaMFUxCzAJBgNVBAYTAkZSMRMwEQYDVQQKEwpD ZXJ0aU5vbWlzMRwwGgYDVQQLExNBQyBSYWNpbmUgLSBSb290IENBMRMwEQYDVQQD EwpDZXJ0aU5vbWlzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8SWb 4mS5RXB3ENSIcfrEzCj/TRUQuT1tMCU0YUfXFSgcPdWglIzCv3kvh07QoB+8xMl+ fQHvSSduAxnNewz0GBY9rApCPKlP6CcnJr74OSVZIiWt9wLfl4wwhNhZOiikIpZp EdOXWqRc84P5cUlN3Lwmr1sjCWmHfTSS4cAKxfDbFLfE61etosyoFZUTQbIhb1Bf JL5xRXAUZudQiU42n/yAoSUrN4FLUfPQNlOe1AB81pIgX8g2ojwxDjfgqSs1JmBF uLKJ45uVLEenQBPmQCGjL3maV86IRmR3a9UGlgvKAk0NBdh8mrQyQvcUlLBIQBCm l7wppt6maQHUNEPQSwIDAQABoz8wPTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQU+F4ho6ijFeb4tRG7/kIEXU2OgnowDQYJKoZIhvcNAQEF BQADggEBACe9FJayK6bXkJQrilBFMh75QPdFOks9PJuo86OMUlBDZGYFTCh9Arex N3KYCnAEzazYIALwr7eASJJDIQMu1Q+pkx/7ACde4kP47F27M2rm+v5HnGooCLz2 s7Fe/WUycTQqgwF5lNp03m1ce/TvovgkEZeVN5wM/7+SsZLJGDigXGeq48j2g2hn 8OckX9Ciyo0U3/1IVeigNBisiaOlsHSZOEPBZQRiZULob+NVbXVPo8nM1OyP3aHI LQex1yYcCr9m93nOiZyKkur3Uedf1yMTBe+fflnPFKGYnVqvTGXCKVdHzQBfpILA AuaC+5ykZhSiSMf8nmL2oPMcLO7YQw4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN 8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ 1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT 91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p TpPDpFQUWw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG 3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO 291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgIQKTZHquOKrIZKI1byyrdhrzANBgkqhkiG9w0BAQUFADBO MQswCQYDVQQGEwJ1czEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQ0wCwYDVQQL EwRGQkNBMRYwFAYDVQQDEw1Db21tb24gUG9saWN5MB4XDTA3MTAxNTE1NTgwMFoX DTI3MTAxNTE2MDgwMFowTjELMAkGA1UEBhMCdXMxGDAWBgNVBAoTD1UuUy4gR292 ZXJubWVudDENMAsGA1UECxMERkJDQTEWMBQGA1UEAxMNQ29tbW9uIFBvbGljeTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJeNvTMn5K1b+3i9L0dHbsd4 6ZOcpN7JHP0vGzk4rEcXwH53KQA7Ax9oD81Npe53uCxiazH2+nIJfTApBnznfKM9 hBiKHa4skqgf6F5PjY7rPxr4nApnnbBnTfAu0DDew5SwoM8uCjR/VAnTNr2kSVdS c+md/uRIeUYbW40y5KVIZPMiDZKdCBW/YDyD90ciJSKtKXG3d+8XyaK2lF7IMJCk FEhcVlcLQUwF1CpMP64Sm1kRdXAHImktLNMxzJJ+zM2kfpRHqpwJCPZLr1LoakCR xVW9QLHIbVeGlRfmH3O+Ry4+i0wXubklHKVSFzYIWcBCvgortFZRPBtVyYyQd+sC AwEAAaN7MHkwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFC9Yl9ipBZilVh/72at17wI8NjTHMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJ KwYBBAGCNxUCBBYEFHa3YJbdFFYprHWF03BjwbxHhhyLMA0GCSqGSIb3DQEBBQUA A4IBAQBgrvNIFkBypgiIybxHLCRLXaCRc+1leJDwZ5B6pb8KrbYq+Zln34PFdx80 CTj5fp5B4Ehg/uKqXYeI6oj9XEWyyWrafaStsU+/HA2fHprA1RRzOCuKeEBuMPdi 4c2Z/FFpZ2wR3bgQo2jeJqVW/TZsN5hs++58PGxrcD/3SDcJjwtCga1GRrgLgwb0 Gzigf0/NC++DiYeXHIowZ9z9VKEDfgHLhUyxCynDvux84T8PCVI8L6eaSP436REG WOE2QYrEtr+O3c5Ks7wawM36GpnScZv6z7zyxFSjiDV2zBssRm8MtNHDYXaSdBHq S4CNHIkRi+xb/xfJSPzn4AYR4oRe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1 OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/ Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM 0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9 Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K 2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl 6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK 9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt 5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s 3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu 8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ 3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJKUDEO MAwGA1UEChMFTEdQS0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMB4XDTA2 MDMzMTE1MDAwMFoXDTE2MDMzMTE0NTk1OVowOTELMAkGA1UEBhMCSlAxDjAMBgNV BAoTBUxHUEtJMRowGAYDVQQLExFBcHBsaWNhdGlvbiBDQSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALk1xhD422jbB8RATLAdHjbcw0H2z1UVbQh/ XMZoVeXnV/GWUebhTXgPbkAVcDtl/hHf59PWWDU74Z8C/JRSRi6znmCbAp7JgtL2 464JT4REtmKbAFFouDqt7GTRMkvplESDtA7OIYlrsDbAmMZLnMI+W2AqCTErLatM 3rGg/VhWwoMdILzEhAmHe6iVl8YljoPgPpMN0cd9c6mo/BkAQC4iuHozQfV4/Vpx 54LZSIhc7KiFhy1tgIlnGmm+EMBaju2IfT5vLDhrN85H2KIxMN5+U2Vsi4ZTQSBs vUilfq8AWlYSWIHR3IlZ+bXu+E2a2EQpi3mn9yKq6nxctBaIIA0CAwEAAaOBsjCB rzAdBgNVHQ4EFgQUf7hdjsQYa8Z9zC7prs405xdd4KEwDgYDVR0PAQH/BAQDAgEG MEwGA1UdHwRFMEMwQaA/oD2kOzA5MQswCQYDVQQGEwJKUDEOMAwGA1UEChMFTEdQ S0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMA8GA1UdEwEB/wQFMAMBAf8w HwYDVR0jBBgwFoAUf7hdjsQYa8Z9zC7prs405xdd4KEwDQYJKoZIhvcNAQEFBQAD ggEBADzYczZABkhKVBn1J0g5JaVuQue2zRvLOTS3m+xPKr535MqE/B3rmyJA1fT7 aIdy/Eddag5SSuO1XUjGIpbmM21tq/bN18skWoyoRZ4+YYJ9lNUF8Bo1X3EvLlS1 QQXvhg1S75yYG/EsTDrR84bTjD56L4ZFjoMyJlu/U8oOUVbcmsJaMBkNp57Vqpsg OWl4IfSXbdEOEUwu0xtasPmXeFwqj1Jl7kxCJcI3MA5tKzWUgwbor0U7BGanMLv5 4CE7Y259RF06alPvERck/VSyWmxzViHJbC2XpEKzJ2EFIWNt6ii8TxpvQtyYq1XT HhvAkj+bweY7F1bixJhDJe62ywA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICZzCCAdCgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEY MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT A1BLSTEcMBoGA1UEAxMTRG9EIENMQVNTIDMgUm9vdCBDQTAeFw0wMDA1MTkxMzEz MDBaFw0yMDA1MTQxMzEzMDBaMGExCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMu IEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRwwGgYDVQQD ExNEb0QgQ0xBU1MgMyBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB gQC1MP5kvurMbe2BLPd/6Rm6DmlqKOGpqcuVWB/x5pppU+CIP5HFUbljl6jmIYwT XjY8qFf6+HAsTGrLvzCnTBbkMlz4ErBR+BZXjS+0TfouqJToKmHUVw1Hzm4sL36Y Z8wACKu2lhY1woWR5VugCsdmUmLzYXWVF668KlYppeArUwIDAQABoy8wLTAdBgNV HQ4EFgQUbJyl8FyPbUGNxBc7kFfCD6PNbf4wDAYDVR0TBAUwAwEB/zANBgkqhkiG 9w0BAQUFAAOBgQCvcUT5lyPMaGmMQwdBuoggsyIAQciYoFUczT9usZNcrfoYmrsc c2/9JEKPh59Rz76Gn+nXikhPCNlplKw/5g8tlw8ok3ZPYt//oM1h+KaGDDE0INx/ L6j7Ob6V7jhZAmLB3mwVT+DfnbvkeXMk/WNklfdKqJkfSGWVx3u/eDLneg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFUjCCBDqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN MAsGA1UEChMES0lTQTEuMCwGA1UECxMlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkgQ2VudHJhbDEWMBQGA1UEAxMNS0lTQSBSb290Q0EgMzAeFw0wNDExMTkw NjM5NTFaFw0xNDExMTkwNjM5NTFaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKEwRL SVNBMS4wLAYDVQQLEyVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 cmFsMRYwFAYDVQQDEw1LSVNBIFJvb3RDQSAzMIIBIDANBgkqhkiG9w0BAQEFAAOC AQ0AMIIBCAKCAQEA3rrtF2Wu0b1KPazbgHLMWOHn4ZPazDB6z+8Lri2nQ6u/p0LP CFYIpEcdffqG79gwlyY0YTyADvjU65/8IjAboW0+40zSVU4WQDfC9gdu2we1pYyW geKbXH6UYcjOhDyx+gDmctMJhXfp3F4hT7TkTvTiF6tQrxz/oTlYdVsSspa5jfBw YkhbVigqpYeRNrkeJPW5unu2UlFbF1pgBWycwubGjD756t08jP+J3kNwrB248XXN OMpTDUdoasY8GMq94bS+DvTQ49IT+rBRERHUQavo9DmO4TSETwuTqmo4/OXGeEeu dhf6oYA3BgAVCP1rI476cg2V1ktisWjC3TSbXQIBA6OCAg8wggILMB8GA1UdIwQY MBaAFI+B8NqmzXQ8vmb0FWtGpP4GKMyqMB0GA1UdDgQWBBSPgfDaps10PL5m9BVr RqT+BijMqjAOBgNVHQ8BAf8EBAMCAQYwggEuBgNVHSAEggElMIIBITCCAR0GBFUd IAAwggETMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LnJvb3RjYS5vci5rci9yY2Ev Y3BzLmh0bWwwgd4GCCsGAQUFBwICMIHRHoHOx3QAIMd4yZ3BHLKUACCs9cd4x3jJ ncEcx4WyyLLkACgAVABoAGkAcwAgAGMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGkA cwAgAGEAYwBjAHIAZQBkAGkAdABlAGQAIAB1AG4AZABlAHIAIABFAGwAZQBjAHQA cgBvAG4AaQBjACAAUwBpAGcAbgBhAHQAdQByAGUAIABBAGMAdAAgAG8AZgAgAHQA aABlACAAUgBlAHAAdQBiAGwAaQBjACAAbwBmACAASwBvAHIAZQBhACkwMwYDVR0R BCwwKqQoMCYxJDAiBgNVBAMMG+2VnOq1reygleuztOuztO2YuOynhO2dpeybkDAz BgNVHRIELDAqpCgwJjEkMCIGA1UEAwwb7ZWc6rWt7KCV67O067O07Zi47KeE7Z2l 7JuQMA8GA1UdEwEB/wQFMAMBAf8wDAYDVR0kBAUwA4ABADANBgkqhkiG9w0BAQUF AAOCAQEAz9b3Dv2wjG4FFY6oXCuyWtEeV6ZeGKqCEQj8mbdbp+PI0qLT+SQ09+Pk rolUR9NpScmAwRHr4inH9gaLX7riXs+rw87P7pIl3J85Hg4D9N6QW6FwmVzHc07J pHVJeyWhn4KSjU3sYcUMMqfHODiAVToqgx2cZHm5Dac1Smjvj/8F2LpOVmHY+Epw mAiWk9hgxzrsX58dKzVPSBShmrtv7tIDhlPxEMcHVGJeNo7iHCsdF03m9VrvirqC 6HfZKBF+N4dKlArJQOk1pTr7ZD7yXxZ683bXzu4/RB1Fql8RqlMcOh9SUWJUD6OQ Nc9Nb7rHviwJ8TX4Absk3TC8SA/u2Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH WD9f -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR 5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s +12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 +HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF 5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ d0jQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c 6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn 8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a 77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q 130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG 9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI +MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+ mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2 mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu MQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwx GzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjEL MAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGtWhf HZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs49oh gHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sW v+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ue Mv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr 9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt 6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7 MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNl Y3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58 ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkq hkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7p iL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtC dsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAmlaxMDPWL kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz +uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn 5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G spki4cErx5z481+oghLrGREt -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS /jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D hNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXzCCA0egAwIBAgIBATANBgkqhkiG9w0BAQUFADCB0DELMAkGA1UEBhMCRVMx SDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMuVml0 b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwgTWVk aXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6MRMw EQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5wZS5j b20wHhcNMDMwMTMwMjMwMDAwWhcNMTgwMTMwMjMwMDAwWjCB0DELMAkGA1UEBhMC RVMxSDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMu Vml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwg TWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6 MRMwEQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5w ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1btoCXXhp3xIW D+Bxl8nUCxkyiazWfpt0e68t+Qt9+lZjKZSdEw2Omj4qvr+ovRmDXO3iWpWVOWDl 3JHJjAzFCe8ZEBNDH+QNYwZHmPBaMYFOYFdbAFVHWvys152C308hcFJ6xWWGmjvl 2eMiEl9P2nR2LWue368DCu+ak7j3gjAXaCOdP1a7Bfr+RW3X2SC5R4Xyp8iHlL5J PHJD/WBkLrezwzQPdACw8m9EG7q9kUwlNpL32mROujS3ZkT6mQTzJieLiE3X04s0 uIUqVkk5MhjcHFf7al0N5CzjtTcnXYJKN2Z9EDVskk4olAdGi46eSoZXbjUOP5gk Ej6wVZAXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MB0GA1UdDgQWBBTqVk/sPIOhFIh4gbIrBSLAB0FbQjANBgkqhkiG9w0BAQUFAAOC AQEAYp7mEzzhw6o5Hf5+T5kcI+t4BJyiIWy7vHlLs/G8dLYXO81aN/Mzg928eMTR TxxYZL8dd9uwsJ50TVfX6L0R4Dyw6wikh3fHRrat9ufXi63j5K91Ysr7aXqnF38d iAgHYkrwC3kuxHBb9C0KBz6h8Q45/KCyN7d37wWAq38yyhPDlaOvyoE6bdUuK5hT m5EYA5JmPyrhQ1moDOyueWBAjxzMEMj+OAY1H90cLv6wszsqerxRrdTOHBdv7MjB EIpvEEQkXUxVXAzFuuT6m2t91Lfnwfl/IvljHaVC7DlyyhRYHD6D4Rx+4QKp4tWL vpw6LkI+gKNJ/YdMCsRZQzEEFA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH /nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF 9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN /BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz 4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 7M2CYfE45k+XmCpajQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I 0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx 3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5zCCA8+gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCQ0Ex EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoTFEVj aG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNlcnZp Y2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMjAeFw0wNTEwMDYxMDQ5MTNa Fw0zMDEwMDcxMDQ5MTNaMIGNMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJp bzEQMA4GA1UEBxMHVG9yb250bzEdMBsGA1UEChMURWNob3dvcnggQ29ycG9yYXRp b24xHzAdBgNVBAsTFkNlcnRpZmljYXRpb24gU2VydmljZXMxGjAYBgNVBAMTEUVj aG93b3J4IFJvb3QgQ0EyMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA utU/5BkV15UBf+s+JQruKQxr77s3rjp/RpOtmhHILIiO5gsEWP8MMrfrVEiidjI6 Qh6ans0KAWc2Dw0/j4qKAQzOSyAZgjcdypNTBZ7muv212DA2Pu41rXqwMrlBrVi/ KTghfdLlNRu6JrC5y8HarrnRFSKF1Thbzz921kLDRoCi+FVs5eVuK5LvIfkhNAqA byrTgO3T9zfZgk8upmEkANPDL1+8y7dGPB/d6lk0I5mv8PESKX02TlvwgRSIiTHR k8++iOPLBWlGp7ZfqTEXkPUZhgrQQvxcrwCUo6mk8TqgxCDP5FgPoHFiPLef5szP ZLBJDWp7GLyE1PmkQI6WiwIBA6OCAVAwggFMMA8GA1UdEwEB/wQFMAMBAf8wCwYD VR0PBAQDAgEGMB0GA1UdDgQWBBQ74YEboKs/OyGC1eISrq5QqxSlEzCBugYDVR0j BIGyMIGvgBQ74YEboKs/OyGC1eISrq5QqxSlE6GBk6SBkDCBjTELMAkGA1UEBhMC Q0ExEDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoT FEVjaG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMoIBADBQBgNVHSAESTBH MEUGCysGAQQB+REKAQMBMDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuZWNob3dv cnguY29tL2NhL3Jvb3QyL2Nwcy5wZGYwDQYJKoZIhvcNAQEFBQADggEBAG+nrPi/ 0RpfEzrj02C6JGPUar4nbjIhcY6N7DWNeqBoUulBSIH/PYGNHYx7/lnJefiixPGE 7TQ5xPgElxb9bK8zoAApO7U33OubqZ7M7DlHnFeCoOoIAZnG1kuwKwD5CXKB2a74 HzcqNnFW0IsBFCYqrVh/rQgJOzDA8POGbH0DeD0xjwBBooAolkKT+7ZItJF1Pb56 QpDL9G+16F7GkmnKlAIYT3QTS3yFGYChnJcd+6txUPhKi9sSOOmAIaKHnkH9Scz+ A2cSi4A3wUYXVatuVNHpRb2lygfH3SuCX9MU8Ure3zBlSU1LALtMqI4JmcQmQpIq zIzvO2jHyu9PQqo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK 8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99 5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3 kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6 Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8 au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ O+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDOzCCAiOgAwIBAgIRANAeRlAAACmMAAAAAgAAAAIwDQYJKoZIhvcNAQEFBQAw PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD Ew5EU1QgUm9vdCBDQSBYNDAeFw0wMDA5MTMwNjIyNTBaFw0yMDA5MTMwNjIyNTBa MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEXMBUGA1UE AxMORFNUIFJvb3QgQ0EgWDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCthX3OFEYY8gSeIYur0O4ypOT68HnDrjLfIutL5PZHRwQGjzCPb9PFo/ihboJ8 RvfGhBAqpQCo47zwYEhpWm1jB+L/OE/dBBiyn98krfU2NiBKSom2J58RBeAwHGEy cO+lewyjVvbDDLUy4CheY059vfMjPAftCRXjqSZIolQb9FdPcAoa90mFwB7rKniE J7vppdrUScSS0+eBrHSUPLdvwyn4RGp+lSwbWYcbg5EpSpE0GRJdchic0YDjvIoC YHpe7Rkj93PYRTQyU4bhC88ck8tMqbvRYqMRqR+vobbkrj5LLCOQCHV5WEoxWh+0 E2SpIFe7RkV++MmpIAc0h1tZAgMBAAGjMjAwMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFPCD6nPIP1ubWzdf9UyPWvf0hki9MA0GCSqGSIb3DQEBBQUAA4IBAQCE G85wl5eEWd7adH6XW/ikGN5salvpq/Fix6yVTzE6CrhlP5LBdkf6kx1bSPL18M45 g0rw2zA/MWOhJ3+S6U+BE0zPGCuu8YQaZibR7snm3HiHUaZNMu5c8D0x0bcMxDjY AVVcHCoNiL53Q4PLW27nbY6wwG0ffFKmgV3blxrYWfuUDgGpyPwHwkfVFvz9qjaV mf12VJffL6W8omBPtgteb6UaT/k1oJ7YI0ldGf+ngpVbRhD+LC3cUtT6GO/BEPZu 8YTV/hbiDH5v3khVqMIeKT6o8IuXGG7F6a6vKwP1F1FwTXf4UC/ivhme7vdUH7B/ Vv4AEbT8dNfEeFxrkDbh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW 1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa /FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID+TCCAuGgAwIBAgIQW1fXqEywr9nTb0ugMbTW4jANBgkqhkiG9w0BAQUFADB5 MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xKjAoBgNVBAMTIVZpc2EgSW5m b3JtYXRpb24gRGVsaXZlcnkgUm9vdCBDQTAeFw0wNTA2MjcxNzQyNDJaFw0yNTA2 MjkxNzQyNDJaMHkxCzAJBgNVBAYTAlVTMQ0wCwYDVQQKEwRWSVNBMS8wLQYDVQQL EyZWaXNhIEludGVybmF0aW9uYWwgU2VydmljZSBBc3NvY2lhdGlvbjEqMCgGA1UE AxMhVmlzYSBJbmZvcm1hdGlvbiBEZWxpdmVyeSBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyREA4R/QkkfpLx0cYjga/EhIPZpchH0MZsRZ FfP6C2ITtf/Wc+MtgD4yTK0yoiXvni3d+aCtEgK3GDvkdgYrgF76ROJFZwUQjQ9l x42gRT05DbXvWFoy7dTglCZ9z/Tt2Cnktv9oxKgmkeHY/CyfpCBg1S8xth2JlGMR 0ug/GMO5zANuegZOv438p5Lt5So+du2Gl+RMFQqEPwqN5uJSqAe0VtmB4gWdQ8on Bj2ZAM2R73QW7UW0Igt2vA4JaSiNtaAG/Y/58VXWHGgbq7rDtNK1R30X0kJV0rGA ib3RSwB3LpG7bOjbIucV5mQgJoVjoA1e05w6g1x/KmNTmOGRVwIDAQABo30wezAP BgNVHRMBAf8EBTADAQH/MDkGA1UdIAQyMDAwLgYFZ4EDAgEwJTAVBggrBgEFBQcC ARYJMS4yLjMuNC41MAwGCCsGAQUFBwICMAAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud DgQWBBRPitp2/2d3I5qmgH1924h1hfeBejANBgkqhkiG9w0BAQUFAAOCAQEACUW1 QdUHdDJydgDPmYt+telnG/Su+DPaf1cregzlN43bJaJosMP7NwjoJY/H2He4XLWb 5rXEkl+xH1UyUwF7mtaUoxbGxEvt8hPZSTB4da2mzXgwKvXuHyzF5Qjy1hOB0/pS WaF9ARpVKJJ7TOJQdGKBsF2Ty4fSCLqZLgfxbqwMsd9sysXI3rDXjIhekqvbgeLz PqZr+pfgFhwCCLSMQWl5Ll3u7Qk9wR094DZ6jj6+JCVCRUS3HyabH4OlM0Vc2K+j INsF/64Or7GNtRf9HYEJvrPxHINxl3JVwhYj4ASeaO4KwhVbwtw94Tc/XrGcexDo c5lC3rAi4/UZqweYCw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk 6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn 0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN sSi6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf 8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN +lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA 1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1 OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2 1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1 Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6 Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8 TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6 g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB 95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl 4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH 6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ 2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE 1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55 IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm /qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+ eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL rosot4LKGAfmt1t06SAZf7IbiVQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG 29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk 3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr 2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s 2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9 BKNDLdr8C2LqL19iUw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg /9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch 6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 7CAFYd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF 6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF 661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS 3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF 3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN /Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH /PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu 9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo 2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI 4uJEvlz36hz1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb 5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ 0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ 8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFujCCBKKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhjELMAkGA1UEBhMCVVMx HTAbBgNVBAoTFEFwcGxlIENvbXB1dGVyLCBJbmMuMS0wKwYDVQQLEyRBcHBsZSBD b21wdXRlciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIEFwcGxlIFJv b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA1MDIxMDAwMTgxNFoXDTI1MDIx MDAwMTgxNFowgYYxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBcHBsZSBDb21wdXRl ciwgSW5jLjEtMCsGA1UECxMkQXBwbGUgQ29tcHV0ZXIgQ2VydGlmaWNhdGUgQXV0 aG9yaXR5MSkwJwYDVQQDEyBBcHBsZSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOSRqQkfkdseR1DrBe1e eYQt6zaiV0xV7IsZid75S2z1B6siMALoGD74UAnTf0GomPnRymacJGsR0KO75Bsq wx+VnnoMpEeLW9QWNzPLxA9NzhRp0ckZcvVdDtV/X5vyJQO6VY9NXQ3xZDUjFUsV WR2zlPf2nJ7PULrBWFBnjwi0IPfLrCwgb3C2PwEwjLdDzw+dPfMrSSgayP7OtbkO 2V4c1ss9tTqt9A8OAJILsSEWLnTVPA3bYharo3GSR1NVwa8vQbP4++NwzeajTEV+ H0xrUJZBicR0YgsQg0GHM4qBsTBY7FoEMoxos48d3mVz/2deZbxJ2HafMxRloXeU yS0CAwEAAaOCAi8wggIrMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ MB0GA1UdDgQWBBQr0GlHlHYJ/vRrjS5ApvdHTX8IXjAfBgNVHSMEGDAWgBQr0GlH lHYJ/vRrjS5ApvdHTX8IXjCCASkGA1UdIASCASAwggEcMIIBGAYJKoZIhvdjZAUB MIIBCTBBBggrBgEFBQcCARY1aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmlj YXRlYXV0aG9yaXR5L3Rlcm1zLmh0bWwwgcMGCCsGAQUFBwICMIG2GoGzUmVsaWFu Y2Ugb24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2Nl cHRhbmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5k IGNvbmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRp ZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wRAYDVR0fBD0wOzA5oDegNYYz aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L3Jvb3Qu Y3JsMFUGCCsGAQUFBwEBBEkwRzBFBggrBgEFBQcwAoY5aHR0cHM6Ly93d3cuYXBw bGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L2Nhc2lnbmVycy5odG1sMA0GCSqG SIb3DQEBBQUAA4IBAQCd2i0oWC99dgS5BNM+zrdmY06PL9T+S61yvaM5xlJNBZhS 9YlRASR5vhoy9+VEi0tEBzmC1lrKtCBe2a4VXR2MHTK/ODFiSF3H4ZCx+CRA+F9Y m1FdV53B5f88zHIhbsTp6aF31ywXJsM/65roCwO66bNKcuszCVut5mIxauivL9Wv Hld2j383LS4CXN1jyfJxuCZA3xWNdUQ/eb3mHZnhQyw+rW++uaT+DjUZUWOxw961 kj5ReAFziqQjyqSI8R5cH0EWLX6VCqrpiUGYGxrdyyC/R14MJsVVNU3GMIuZZxTH CR+6R8faAQmHJEKVvRNgGQrv6n8Obs3BREM6StXj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4 Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ 54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50 7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6 xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/ Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42 gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0 jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+ XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/ RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk BYn8eNZcLCZDqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg Q2xhc3MgMiBDQSAxMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzEL MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD VQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7McXA0 ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLX l18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVB HfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B 5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3 WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQD AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLP gcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+ DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKu BctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHs h7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+oRxKaJyOk LY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4 Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0 aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N 8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K /OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu 7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC 28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6 lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB 0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09 5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q 619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn 2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG 5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0 BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do 0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ 44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN 9u6wWk5JRFRYX0KD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB 4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd 8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A 4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd +LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B 4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK 4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2 MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6 dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO 76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj 2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU 1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV 5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDyzCCArOgAwIBAgIDAOJIMA0GCSqGSIb3DQEBBQUAMIGLMQswCQYDVQQGEwJB VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1 YWwtMDIxGDAWBgNVBAMMD0EtVHJ1c3QtUXVhbC0wMjAeFw0wNDEyMDIyMzAwMDBa Fw0xNDEyMDIyMzAwMDBaMIGLMQswCQYDVQQGEwJBVDFIMEYGA1UECgw/QS1UcnVz dCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy a2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1YWwtMDIxGDAWBgNVBAMMD0Et VHJ1c3QtUXVhbC0wMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJaR q9eOsFm4Ab20Hq2Z/aH86gyWa48uSUjY6eQkguHYuszr3gdcSMYZggFHQgnhfLmf ro/27l5rqKhWiDhWs+b+yZ1PNDhRPJy+86ycHMg9XJqErveULBSyZDdgjhSwOyrN ibUir/fkf+4sKzP5jjytTKJXD/uCxY4fAd9TjMEVpN3umpIS0ijpYhclYDHvzzGU 833z5Dwhq5D8bc9jp8YSAHFJ1xzIoO1jmn3jjyjdYPnY5harJtHQL73nDQnfbtTs 5ThT9GQLulrMgLU4WeyAWWWEMWpfVZFMJOUkmoOEer6A8e5fIAeqdxdsC+JVqpZ4 CAKel/Arrlj1gFA//jsCAwEAAaM2MDQwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4E CgQIQj0rJKbBRc4wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBG yxFjUA2bPkXUSC2SfJ29tmrbiLKal+g6a9M8Xwd+Ejo+oYkNP6F4GfeDtAXpm7xb 9Ly8lhdbHcpRhzCUQHJ1tBCiGdLgmhSx7TXjhhanKOdDgkdsC1T+++piuuYL72TD gUy2Sb1GHlJ1Nc6rvB4fpxSDAOHqGpUq9LWsc3tFkXqRqmQVtqtR77npKIFBioc6 2jTBwDMPX3hDJDR1DSPc6BnZliaNw2IHdiMQ0mBoYeRnFdq+TyDKsjmJOOQPLzzL /saaw6F891+gBjLFEFquDyR73lAPJS279R3csi8WWk4ZYUC/1V8H3Ktip/J6ac8e qhLCbmJ81Lo92JGHz/ot -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi 94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP 9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m 0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICpzCCAi2gAwIBAgIQTHm1miicdjFk9YlE0JEC3jAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAzIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAARXz+qzOU0/oSHgbi84csaHl/OFC0fnD1HI0fSZm8pZ Zf9M+eoLtyXV0vbsMS0yYhLXdoan+jjJZdT+c+KEOfhMSWIT3brViKBfPchPsD+P oVAR5JNGrcNfy/GkapVW6MCjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBQknbzScfcdwiW+IvGJpSwVOzQeXjAKBggqhkjOPQQD AwNoADBlAjEAuWZoZdsF0Dh9DvPIdWG40CjEsUozUVj78jwQyK5HeHbKZiQXhj5Q Vm6lLZmIuL0kAjAD6qfnqDzqnWLGX1TamPR3vU+PGJyRXEdrQE0QHbPhicoLIsga xcX+i93B3294n5E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHDCCBASgAwIBAgIES45gAzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJE SzESMBAGA1UEChMJVFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQ cmltYXJ5IENBMB4XDTEwMDMwMzEyNDEzNFoXDTM3MTIwMzEzMTEzNFowRTELMAkG A1UEBhMCREsxEjAQBgNVBAoTCVRSVVNUMjQwODEiMCAGA1UEAxMZVFJVU1QyNDA4 IE9DRVMgUHJpbWFyeSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AJlJodr3U1Fa+v8HnyACHV81/wLevLS0KUk58VIABl6Wfs3LLNoj5soVAZv4LBi5 gs7E8CZ9w0F2CopW8vzM8i5HLKE4eedPdnaFqHiBZ0q5aaaQArW+qKJx1rT/AaXt alMB63/yvJcYlXS2lpexk5H/zDBUXeEQyvfmK+slAySWT6wKxIPDwVapauFY9QaG +VBhCa5jBstWS7A5gQfEvYqn6csZ3jW472kW6OFNz6ftBcTwufomGJBMkonf4ZLr 6t0AdRi9jflBPz3MNNRGxyjIuAmFqGocYFA/OODBRjvSHB2DygqQ8k+9tlpvzMRr kU7jq3RKL+83G1dJ3/LTjCLz4ryEMIC/OJ/gNZfE0qXddpPtzflIPtUFVffXdbFV 1t6XZFhJ+wBHQCpJobq/BjqLWUA86upsDbfwnePtmIPRCemeXkY0qabC+2Qmd2Fe xyZphwTyMnbqy6FG1tB65dYf3mOqStmLa3RcHn9+2dwNfUkh0tjO2FXD7drWcU0O I9DW8oAypiPhm/QCjMU6j6t+0pzqJ/S0tdAo+BeiXK5hwk6aR+sRb608QfBbRAs3 U/q8jSPByenggac2BtTN6cl+AA1Mfcgl8iXWNFVGegzd/VS9vINClJCe3FNVoUnR YCKkj+x0fqxvBLopOkJkmuZw/yhgMxljUi2qYYGn90OzAgMBAAGjggESMIIBDjAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHSAECjAIMAYGBFUd IAAwgZcGA1UdHwSBjzCBjDAsoCqgKIYmaHR0cDovL2NybC5vY2VzLnRydXN0MjQw OC5jb20vb2Nlcy5jcmwwXKBaoFikVjBUMQswCQYDVQQGEwJESzESMBAGA1UEChMJ VFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQcmltYXJ5IENBMQ0w CwYDVQQDEwRDUkwxMB8GA1UdIwQYMBaAFPZt+LFIs0FDAduGROUYBbdezAY3MB0G A1UdDgQWBBT2bfixSLNBQwHbhkTlGAW3XswGNzANBgkqhkiG9w0BAQsFAAOCAgEA VPAQGrT7dIjD3/sIbQW86f9CBPu0c7JKN6oUoRUtKqgJ2KCdcB5ANhCoyznHpu3m /dUfVUI5hc31CaPgZyY37hch1q4/c9INcELGZVE/FWfehkH+acpdNr7j8UoRZlkN 15b/0UUBfGeiiJG/ugo4llfoPrp8bUmXEGggK3wyqIPcJatPtHwlb6ympfC2b/Ld v/0IdIOzIOm+A89Q0utx+1cOBq72OHy8gpGb6MfncVFMoL2fjP652Ypgtr8qN9Ka /XOazktiIf+2Pzp7hLi92hRc9QMYexrV/nnFSQoWdU8TqULFUoZ3zTEC3F/g2yj+ FhbrgXHGo5/A4O74X+lpbY2XV47aSuw+DzcPt/EhMj2of7SA55WSgbjPMbmNX0rb oenSIte2HRFW5Tr2W+qqkc/StixgkKdyzGLoFx/xeTWdJkZKwyjqge2wJqws2upY EiThhC497+/mTiSuXd69eVUwKyqYp9SD2rTtNmF6TCghRM/dNsJOl+osxDVGcwvt WIVFF/Onlu5fu1NHXdqNEfzldKDUvCfii3L2iATTZyHwU9CALE+2eIA+PIaLgnM1 1oCfUnYBkQurTrihvzz9PryCVkLxiqRmBVvUz+D4N5G/wvvKDS6t6cPCS+hqM482 cbBsn0R9fFLO4El62S9eH1tqOzO20OAOK65yJIsOpSE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc 58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv 8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNV BAMML0VCRyBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMTcwNQYDVQQKDC5FQkcgQmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXpt ZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAeFw0wNjA4MTcwMDIxMDlaFw0xNjA4 MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25payBTZXJ0aWZpa2Eg SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2ltIFRl a25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h 4fuXd7hxlugTlkaDT7byX3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAk tiHq6yOU/im/+4mRDGSaBUorzAzu8T2bgmmkTPiab+ci2hC6X5L8GCcKqKpE+i4s tPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfreYteIAbTdgtsApWjluTL dlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZTqNGFav4 c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8Um TDGyY5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z +kI2sSXFCjEmN1ZnuqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0O Lna9XvNRiYuoP1Vzv9s6xiQFlpJIqkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMW OeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vmExH8nYQKE3vwO9D8owrXieqW fo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0Nokb+Clsi7n2 l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB /wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgw FoAU587GT/wWZ5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+ 8ygjdsZs93/mQJ7ANtyVDR2tFcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI 6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgmzJNSroIBk5DKd8pNSe/iWtkqvTDO TLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64kXPBfrAowzIpAoHME wfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqTbCmY Iai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJn xk1Gj7sURT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4Q DgZxGhBM/nV+/x5XOULK1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9q Kd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11t hie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQY9iJSrSq3RZj9W6+YKH4 7ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9AahH3eU7 QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2 ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0 aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/ BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM 7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs yZyQ2uypQjyttgI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOc UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xS S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg SGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4XDTA3MTIyNTE4Mzcx OVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxla3Ry b25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMC VFIxDzANBgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDE sGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7F ni4gKGMpIEFyYWzEsWsgMjAwNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9NYvDdE3ePYakqtdTyuTFY KTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQvKUmi8wUG +7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveG HtyaKhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6P IzdezKKqdfcYbwnTrqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M 733WB2+Y8a+xwXrXgTW4qhe04MsCAwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHk Yb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G CSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/sPx+EnWVUXKgW AkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5 mxRZNTZPz/OOXl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsa XRik7r4EW5nVcV9VZWRi1aKbBFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZ qxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAKpoRq0Tl9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYDCCA0igAwIBAgICATAwDQYJKoZIhvcNAQELBQAwWTELMAkGA1UEBhMCVVMx GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UE AxMYRmVkZXJhbCBDb21tb24gUG9saWN5IENBMB4XDTEwMTIwMTE2NDUyN1oXDTMw MTIwMTE2NDUyN1owWTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu bWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UEAxMYRmVkZXJhbCBDb21tb24gUG9s aWN5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2HX7NRY0WkG/ Wq9cMAQUHK14RLXqJup1YcfNNnn4fNi9KVFmWSHjeavUeL6wLbCh1bI1FiPQzB6+ Duir3MPJ1hLXp3JoGDG4FyKyPn66CG3G/dFYLGmgA/Aqo/Y/ISU937cyxY4nsyOl 4FKzXZbpsLjFxZ+7xaBugkC7xScFNknWJidpDDSPzyd6KgqjQV+NHQOGgxXgVcHF mCye7Bpy3EjBPvmE0oSCwRvDdDa3ucc2Mnr4MrbQNq4iGDGMUHMhnv6DOzCIJOPp wX7e7ZjHH5IQip9bYi+dpLzVhW86/clTpyBLqtsgqyFOHQ1O5piF5asRR12dP8Qj wOMUBm7+nQIDAQABo4IBMDCCASwwDwYDVR0TAQH/BAUwAwEB/zCB6QYIKwYBBQUH AQsEgdwwgdkwPwYIKwYBBQUHMAWGM2h0dHA6Ly9odHRwLmZwa2kuZ292L2ZjcGNh L2NhQ2VydHNJc3N1ZWRCeWZjcGNhLnA3YzCBlQYIKwYBBQUHMAWGgYhsZGFwOi8v bGRhcC5mcGtpLmdvdi9jbj1GZWRlcmFsJTIwQ29tbW9uJTIwUG9saWN5JTIwQ0Es b3U9RlBLSSxvPVUuUy4lMjBHb3Zlcm5tZW50LGM9VVM/Y0FDZXJ0aWZpY2F0ZTti aW5hcnksY3Jvc3NDZXJ0aWZpY2F0ZVBhaXI7YmluYXJ5MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUrQx6dVzl85jEeZgOrCj9l/TnAvwwDQYJKoZIhvcNAQELBQAD ggEBAI9z2uF/gLGH9uwsz9GEYx728Yi3mvIRte9UrYpuGDco71wb5O9Qt2wmGCMi TR0mRyDpCZzicGJxqxHPkYnos/UqoEfAFMtOQsHdDA4b8Idb7OV316rgVNdF9IU+ 7LQd3nyKf1tNnJaK0KIyn9psMQz4pO9+c+iR3Ah6cFqgr2KBWfgAdKLI3VTKQVZH venAT+0g3eOlCd+uKML80cgX2BLHb94u6b2akfI8WpQukSKAiaGMWMyDeiYZdQKl Dn0KJnNR6obLB6jI/WNaNZvSr79PMUjBhHDbNXuaGQ/lj/RqDG8z2esccKIN47lQ A2EC/0rskqTcLe4qNJMHtyznGI8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC 4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1 c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF 5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI 4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDcTCCAlmgAwIBAgIVAOYJ/nrqAGiM4CS07SAbH+9StETRMA0GCSqGSIb3DQEB BQUAMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGlj emVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIgUk9PVCBDQTAeFw0xMTEyMDYx MTEwNTdaFw0zMTEyMDYxMTEwNTdaMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIg Uk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxHL49ZMTml 6g3wpYwrvQKkvc0Kc6oJ5sxfgmp1qZfluwbv88BdocHSiXlY8NzrVYzuWBp7J/9K ULMAoWoTIzOQ6C9TNm4YbA9A1jdX1wYNL5Akylf8W5L/I4BXhT9KnlI6x+a7BVAm nr/Ttl+utT/Asms2fRfEsF2vZPMxH4UFqOAhFjxTkmJWf2Cu4nvRQJHcttB+cEAo ag/hERt/+tzo4URz6x6r19toYmxx4FjjBkUhWQw1X21re//Hof2+0YgiwYT84zLb eqDqCOMOXxvH480yGDkh/QoazWX3U75HQExT/iJlwnu7I1V6HXztKIwCBjsxffbH 3jOshCJtywcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFFOSo33/gnbwM9TrkmdHYTMbaDsqMA0GCSqGSIb3DQEBBQUA A4IBAQA5UFWd5EL/pBviIMm1zD2JLUCpp0mJG7JkwznIOzawhGmFFaxGoxAhQBEg haP+E0KR66oAwVC6xe32QUVSHfWqWndzbODzLB8yj7WAR0cDM45ZngSBPBuFE3Wu GLJX9g100ETfIX+4YBR/4NR/uvTnpnd9ete7Whl0ZfY94yuu4xQqB5QFv+P7IXXV lTOjkjuGXEcyQAjQzbFaT9vIABSbeCXWBbjvOXukJy6WgAiclzGNSYprre8Ryydd fmjW9HIGwsIO03EldivvqEYL1Hv1w/Pur+6FUEOaL68PEIUovfgwIB2BAw+vZDuw cH0mX548PojGyg434cDjkSXa3mHF -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3 WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICqDCCAi2gAwIBAgIQNBdlEkA7t1aALYDLeVWmHjAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAyIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAATR2UqOTA2ESlG6fO/TzPo6mrWnYxM9AeBJPvrBR8mS szrX/m+c95o6D/UOCgrDP8jnEhSO1dVtmCyzcTIK6yq99tdqIAtnRZzSsr9TImYJ XdsR8/EFM1ij4rjPfM2Cm72jQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBQ9MvM6qQyQhPmijGkGYVQvh3L+BTAKBggqhkjOPQQD AwNpADBmAjEAyKapr0F/tckRQhZoaUxcuCcYtpjxwH+QbYfTjEYX8D5P/OqwCMR6 S7wIL8fip29lAjEA1lnehs5fDspU1cbQFQ78i5Ry1I4AWFPPfrFLDeVQhuuea9// KabYR9mglhjb8kWz -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX 0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c /3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D 34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv 033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq 4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9jCCA96gAwIBAgIQZWNxhdNvRcaPfzH5CYeSgjANBgkqhkiG9w0BAQwFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAz IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC3DrL6TbyachX7d1vb/UMPywv3 YC6zK34Mu1PyzE5l8xm7/zUd99Opu0Attd141Kb5N+qFBXttt+YTSwZ8+3ZjjyAd LTgrBIXy6LDRX01KIclq2JTqHgJQpqqQB6BHIepm+QSg5oPwxPVeluInTWHDs8GM IrZmoQDRVin77cF/JMo9+lqUsITDx7pDHP1kDvEo+0dZ8ibhMblE+avd+76+LDfj rAsY0/wBovGkCjWCR0yrvYpe3xOF/CDMSFmvr0FvyyPNypOn3dVfyGQ7/wEDoApP LW49hL6vyDKyUymQFfewBZoKPPa5BpDJpeFdoDuw/qi2v/WJKFckOiGGceTciotB VeweMCRZ0cBZuHivqlp03iWAMJjtMERvIXAc2xJTDtamKGaTLB/MTzwbgcW59nhv 0DI6CHLbaw5GF4WU87zvvPekXo7p6bVk5bdLRRIsTDe3YEMKTXEGAJQmNXQfu3o5 XE475rgD4seTi4QsJUlF3X8jlGAfy+nN9quX92Hn+39igcjcCjBcGHzmzu/Hbh6H fLPpysh7avRo/IOlDFa0urKNSgrHl5fFiDAVPRAIVBVycmczM/R8t84AJ1NlziTx WmTnNi/yLgLCl99y6AIeoPc9tftoYAP6M6nmEm0G4amoXU48/tnnAGWsthlNe4N/ NEfq4RhtsYsceavnnQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUOXEIAD7eyIbnkP/k/SEPziQZFvYwDQYJKoZIhvcN AQEMBQADggIBAFBriE1gSM5a4yLOZ3yEp80c/ekMA4w2rwqHDmquV64B0Da78v25 c8FftaiuTKL6ScsHRhY2vePIVzh+OOS/JTNgxtw3nGO7XpgeGrKC8K6mdxGAREeh KcXwszrOmPC47NMOgAZ3IzBM/3lkYyJbd5NDS3Wz2ztuO0rd8ciutTeKlYg6EGhw OLlbcH7VQ8n8X0/l5ns27vAg7UdXEyYQXhQGDXt2B8LGLRb0rqdsD7yID08sAraj 1yLmmUc12I2lT4ESOhF9s8wLdfMecKMbA+r6mujmLjY5zJnOOj8Mt674Q5mwk25v qtkPajGRu5zTtCj7g0x6c4JQZ9IOrO1gxbJdNZjPh34eWR0kvFa62qRa2MzmvB4Q jxuMjvPB27e+1LBbZY8WaPNWxSoZFk0PuGWHbSSDuGLc4EdhGoh7zk5//dzGDVqa pPO1TPbdMaboHREhMzAEYX0c4D5PjT+1ixIAWn2poQDUg+twuxj4pNIcgS23CBHI Jnu21OUPA0Zy1CVAHr5JXW2T8VyyO3VUaTqg7kwiuqya4gitRWMFSlI1dsQ09V4H Mq3cfCbRW4+t5OaqG3Wf61206MCpFXxOSgdy30bJ1JGSdVaw4e43NmUoxRXIK3bM bW8Zg/T92hXiQeczeUaDV/nxpbZt07zXU+fucW14qZen7iCcGRVyFT0E -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv 6pZjamVFkpUBtA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEUzCCAzugAwIBAgIDAOJDMA0GCSqGSIb3DQEBBQUAMIHPMQswCQYDVQQGEwJB VDGBizCBiAYDVQQKHoGAAEEALQBUAHIAdQBzAHQAIABHAGUAcwAuACAAZgD8AHIA IABTAGkAYwBoAGUAcgBoAGUAaQB0AHMAcwB5AHMAdABlAG0AZQAgAGkAbQAgAGUA bABlAGsAdAByAC4AIABEAGEAdABlAG4AdgBlAHIAawBlAGgAcgAgAEcAbQBiAEgx GDAWBgNVBAsTD0EtVHJ1c3QtUXVhbC0wMTEYMBYGA1UEAxMPQS1UcnVzdC1RdWFs LTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEzMDIzMDAwMFowgc8xCzAJBgNVBAYT AkFUMYGLMIGIBgNVBAoegYAAQQAtAFQAcgB1AHMAdAAgAEcAZQBzAC4AIABmAPwA cgAgAFMAaQBjAGgAZQByAGgAZQBpAHQAcwBzAHkAcwB0AGUAbQBlACAAaQBtACAA ZQBsAGUAawB0AHIALgAgAEQAYQB0AGUAbgB2AGUAcgBrAGUAaAByACAARwBtAGIA SDEYMBYGA1UECxMPQS1UcnVzdC1RdWFsLTAxMRgwFgYDVQQDEw9BLVRydXN0LVF1 YWwtMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmhgdxIbxTGEOH fXGiewI3NFldAWKFWfLofO+5I1UbvA5avt7IgsGXz/tI/f5HGUbascI0i7xG0tqV lA5ctQgLRqxgxHtgTkMcqsAEYdsz3LZsCdXO1QrvEBGLTSABdxiL/gSWJ6z77CSw x7Xg02HwxPV82cjGkSF3ENGJntuIAAnRDWn/ORHjFatNRymoMbHaOEZXSGhf7Y5F rrHEqGyi9E6sv784De/T1aTvskn8cWeUmDzv//omiG/a/V9KQex/61XN8OthUQVn X+u/liL2NKx74I2C/GgHX5B0WkPNqsSOgmlvJ/cKuT0PveUgVFDAA0oYBgcE1KDM lBbN0kmPAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECEs8jB2F 6W+tMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAIUusmJzMJRiQ 8TAHrJAOelfuWoTGcqdIv7Tys/fNl2yF2fjvHT8J01aKialFVpbVeQ2XKb1O2bHO QYAKgsdZ2jZ/sdL2UVFRTHmidLu6PdgWCBRhJYQELQophO9QVvfhAA0TwbESYqTz +nlI5Gr7CZe8f6HEmhJmCtUQsdQCufGglRh4T+tIGiNGcnyVEHZ93mSVepFr1VA2 9CTRPteuGjA81jeAz9peYiFE1CXvxK9cJiv0BcALFLWmADCoRLzIRZhA+sAwYUmw M1rqVCPA3kBQvIC95tyQvNy2dG0Vs+O6PwLaNX/suSlElQ06X2l1VwMaYb4vZKFq N0bOhBXEVg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIJmzCCB4OgAwIBAgIBATANBgkqhkiG9w0BAQwFADCCAR4xPjA8BgNVBAMTNUF1 dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s YW5vMQswCQYDVQQGEwJWRTEQMA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlz dHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0 aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBlcmludGVuZGVuY2lh IGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUwIwYJ KoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyMjE4MDgy MVoXDTMwMTIxNzIzNTk1OVowggEeMT4wPAYDVQQDEzVBdXRvcmlkYWQgZGUgQ2Vy dGlmaWNhY2lvbiBSYWl6IGRlbCBFc3RhZG8gVmVuZXpvbGFubzELMAkGA1UEBhMC VkUxEDAOBgNVBAcTB0NhcmFjYXMxGTAXBgNVBAgTEERpc3RyaXRvIENhcGl0YWwx NjA0BgNVBAoTLVNpc3RlbWEgTmFjaW9uYWwgZGUgQ2VydGlmaWNhY2lvbiBFbGVj dHJvbmljYTFDMEEGA1UECxM6U3VwZXJpbnRlbmRlbmNpYSBkZSBTZXJ2aWNpb3Mg ZGUgQ2VydGlmaWNhY2lvbiBFbGVjdHJvbmljYTElMCMGCSqGSIb3DQEJARYWYWNy YWl6QHN1c2NlcnRlLmdvYi52ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBAME77xNS8ZlW47RsBeEaaRZhJoZ4rw785UAFCuPZOAVMqNS1wMYqzy95q6Gk UO81ER/ugiQX/KMcq/4HBn83fwdYWxPZfwBfK7BP2p/JsFgzYeFP0BXOLmvoJIzl Jb6FW+1MPwGBjuaZGFImWZsSmGUclb51mRYMZETh9/J5CLThR1exStxHQptwSzra zNFpkQY/zmj7+YZNA9yDoroVFv6sybYOZ7OxNDo7zkSLo45I7gMwtxqWZ8VkJZkC 8+p0dX6mkhUT0QAV64Zc9HsZiH/oLhEkXjhrgZ28cF73MXIqLx1fyM4kPH1yOJi/ R72nMwL7D+Sd6mZgI035TxuHXc2/uOwXfKrrTjaJDz8Jp6DdessOkxIgkKXRjP+F K3ze3n4NUIRGhGRtyvEjK95/2g02t6PeYiYVGur6ruS49n0RAaSS0/LJb6XzaAAe 0mmO2evnEqxIKwy2mZRNPfAVW1l3wCnWiUwryBU6OsbFcFFrQm+00wOicXvOTHBM aiCVAVZTb9RSLyi+LJ1llzJZO3pq3IRiiBj38Nooo+2ZNbMEciSgmig7YXaUcmud SVQvLSL+Yw+SqawyezwZuASbp7d/0rutQ59d81zlbMt3J7yB567rT2IqIydQ8qBW k+fmXzghX+/FidYsh/aK+zZ7Wy68kKHuzEw1Vqkat5DGs+VzAgMBAAGjggLeMIIC 2jASBgNVHRMBAf8ECDAGAQH/AgECMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52 ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMB0GA1UdDgQWBBStuyIdxuDS Aaj9dlBSk+2YwU2u0zCCAVAGA1UdIwSCAUcwggFDgBStuyIdxuDSAaj9dlBSk+2Y wU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRpZmlj YWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAw DgYDVQQHEwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYD VQQKEy1TaXN0ZW1hIE5hY2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25p Y2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5kZW5jaWEgZGUgU2VydmljaW9zIGRlIENl cnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG9w0BCQEWFmFjcmFpekBz dXNjZXJ0ZS5nb2IudmWCAQEwDgYDVR0PAQH/BAQDAgEGMDcGA1UdEQQwMC6CD3N1 c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMFQGA1Ud HwRNMEswJKAioCCGHmhodHA6Ly93d3cuc3VzY2VydGUuZ29iLnZlL2xjcjAjoCGg H4YdbGRhcDovL2FjcmFpei5zdXNjZXJ0ZS5nb2IudmUwNwYIKwYBBQUHAQEEKzAp MCcGCCsGAQUFBzABhhtoaHRwOi8vb2NzcC5zdXNjZXJ0ZS5nb2IudmUwQAYDVR0g BDkwNzA1BgVghl4BAjAsMCoGCCsGAQUFBwIBFh5odHRwOi8vd3d3LnN1c2NlcnRl LmdvYi52ZS9kcGMwDQYJKoZIhvcNAQEMBQADggIBAK4qy/zmZ9zBwfW3yOYtLcBT Oy4szJyPz7/RhNH3bPVH7HbDTGpi6JZ4YXdXMBeJE5qBF4a590Kgj8Rlnltt+Rbo OFQOU1UDqKuTdBsA//Zry5899fmn8jBUkg4nh09jhHHbLlaUScdz704Zz2+UVg7i s/r3Legxap60KzmdrmTAE9VKte1TQRgavQwVX5/2mO/J+SCas//UngI+h8SyOucq mjudYEgBrZaodUsagUfn/+AzFNrGLy+al+5nZeHb8JnCfLHWS0M9ZyhgoeO/czyn 99+5G93VWNv4zfc4KiavHZKrkn8F9pg0ycIZh+OwPT/RE2zq4gTazBMlP3ACIe/p olkNaOEa8KvgzW96sjBZpMW49zFmyINYkcj+uaNCJrVGsXgdBmkuRGJNWFZ9r0cG woIaxViFBypsz045r1ESfYPlfDOavBhZ/giR/Xocm9CHkPRY2BApMMR0DUCyGETg Ql+L3kfdTKzuDjUp2DM9FqysQmaM81YDZufWkMhlZPfHwC7KbNougoLroa5Umeos bqAXWmk46SwIdWRPLLqbUpDTKooynZKpSYIkkotdgJoVZUUCY+RCO8jsVPEU6ece SxztNUm5UOta1OJPMwSAKRHOo3ilVb9c6lAixDdvV8MeNbqe6asM1mpCHWbJ/0rg 5Ls9Cxx8hracyp0ev7b0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGATCCA+mgAwIBAgIRAI9hcRW6eVgXjH0ROqzW264wDQYJKoZIhvcNAQELBQAw RTEfMB0GA1UEAxMWQ29tU2lnbiBHbG9iYWwgUm9vdCBDQTEVMBMGA1UEChMMQ29t U2lnbiBMdGQuMQswCQYDVQQGEwJJTDAeFw0xMTA3MTgxMDI0NTRaFw0zNjA3MTYx MDI0NTVaMEUxHzAdBgNVBAMTFkNvbVNpZ24gR2xvYmFsIFJvb3QgQ0ExFTATBgNV BAoTDENvbVNpZ24gTHRkLjELMAkGA1UEBhMCSUwwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCyKClzKh3rm6n1nvigmV/VU1D4hSwYW2ro3VqpzpPo0Ph3 3LguqjXd5juDwN4mpxTpD99d7Xu5X6KGTlMVtfN+bTbA4t3x7DU0Zqn0BE5XuOgs 3GLH41Vmr5wox1bShVpM+IsjcN4E/hMnDtt/Bkb5s33xCG+ohz5dlq0gA9qfr/g4 O9lkHZXTCeYrmVzd/il4x79CqNvGkdL3um+OKYl8rg1dPtD8UsytMaDgBAopKR+W igc16QJzCbvcinlETlrzP/Ny76BWPnAQgaYBULax/Q5thVU+N3sEOKp6uviTdD+X O6i96gARU4H0xxPFI75PK/YdHrHjfjQevXl4J37FJfPMSHAbgPBhHC+qn/014DOx 46fEGXcdw2BFeIIIwbj2GH70VyJWmuk/xLMCHHpJ/nIF8w25BQtkPpkwESL6esaU b1CyB4Vgjyf16/0nRiCAKAyC/DY/Yh+rDWtXK8c6QkXD2XamrVJo43DVNFqGZzbf 5bsUXqiVDOz71AxqqK+p4ek9374xPNMJ2rB5MLPAPycwI0bUuLHhLy6nAIFHLhut TNI+6Y/soYpi5JSaEjcY7pxI8WIkUAzr2r+6UoT0vAdyOt7nt1y8844a7szo/aKf woziHl2O1w6ZXUC30K+ptXVaOiW79pBDcbLZ9ZdbONhS7Ea3iH4HJNwktrBJLQID AQABo4HrMIHoMA8GA1UdEwEB/wQFMAMBAf8wgYQGA1UdHwR9MHswPKA6oDiGNmh0 dHA6Ly9mZWRpci5jb21zaWduLmNvLmlsL2NybC9jb21zaWduZ2xvYmFscm9vdGNh LmNybDA7oDmgN4Y1aHR0cDovL2NybDEuY29tc2lnbi5jby5pbC9jcmwvY29tc2ln bmdsb2JhbHJvb3RjYS5jcmwwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBQCRZPY DUhirGm6rgZbPvuqJpFQsTAfBgNVHSMEGDAWgBQCRZPYDUhirGm6rgZbPvuqJpFQ sTANBgkqhkiG9w0BAQsFAAOCAgEAk1V5V9701xsfy4mfX+tP9Ln5e9h3N+QMwUfj kr+k3e8iXOqADjTpUHeBkEee5tJq09ZLp/43F5tZ2eHdYq2ZEX7iWHCnOQet6Yw9 SU1TahsrGDA6JJD9sdPFnNZooGsU1520e0zNB0dNWwxrWAmu4RsBxvEpWCJbvzQL dOfyX85RWwli81OiVMBc5XvJ1mxsIIqli45oRynKtsWP7E+b0ISJ1n+XFLdQo/Nm WA/5sDfT0F5YPzWdZymudMbXitimxC+n4oQE4mbQ4Zm718Iwg3pP9gMMcSc7Qc1J kJHPH9O7gVubkKHuSYj9T3Ym6c6egL1pb4pz/uT7cT26Fiopc/jdqbe2EAfoJZkv hlp/zdzOoXTWjiKNA5zmgWnZn943FuE9KMRyKtyi/ezJXCh8ypnqLIKxeFfZl69C BwJsPXUTuqj8Fic0s3aZmmr7C4jXycP+Q8V+akMEIoHAxcd960b4wVWKqOcI/kZS Q0cYqWOY1LNjznRt9lweWEfwDBL3FhrHOmD4++1N3FkkM4W+Q1b2WOL24clDMj+i 2n9Iw0lc1llHMSMvA5D0vpsXZpOgcCVahfXczQKi9wQ3oZyonJeWx4/rXdMtagAB VBYGFuMEUEQtybI+eIbnp5peO2WAAblQI4eTy/jMVowe5tfMEXovV3sz9ULgmGb3 DscLP1I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICmDCCAgGgAwIBAgIBDjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJVUzEY MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNFQ0ExFDASBgNVBAMT C0VDQSBSb290IENBMB4XDTA0MDYxNDEwMjAwOVoXDTQwMDYxNDEwMjAwOVowSzEL MAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMD RUNBMRQwEgYDVQQDEwtFQ0EgUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEArkr2eXIS6oAKIpDkOlcQZdMGdncoygCEIU+ktqY3of5SVVXU7/it7kJ1 EUzR4ii2vthQtbww9aAnpQxcEmXZk8eEyiGEPy+cCQMllBY+efOtKgjbQNDZ3lB9 19qzUJwBl2BMxslU1XsJQw9SK10lPbQm4asa8E8e5zTUknZBWnECAwEAAaOBizCB iDAfBgNVHSMEGDAWgBT2uAQnDlYW2blj2f2hVGVBoAhILzAdBgNVHQ4EFgQU9rgE Jw5WFtm5Y9n9oVRlQaAISC8wDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB Af8wJQYDVR0gBB4wHDAMBgpghkgBZQMCAQwBMAwGCmCGSAFlAwIBDAIwDQYJKoZI hvcNAQEFBQADgYEAHh0EQY2cZ209aBb5q0wW1ER0dc4OGzsLyqjHfaQ4TEaMmUwL AJRta/c4KVWLiwbODsvgJk+CaWmSL03gRW/ciVb/qDV7qh9Pyd1cOlanZTAnPog2 i82yL3i2fK9DCC84uoxEQbgqK2jx9bIjFTwlAqITk9fGAm5mdT84IEwq1Gw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI 2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx 1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV 5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY 1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFSzCCAzOgAwIBAgIRALZLiAfiI+7IXBKtpg4GofIwDQYJKoZIhvcNAQELBQAw PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTAeFw0xMjA5MjgwODU4NTFaFw0zNzEyMzExNTU5NTla MD8xCzAJBgNVBAYTAlRXMTAwLgYDVQQKDCdHb3Zlcm5tZW50IFJvb3QgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQC2/5c8gb4BWCQnr44BK9ZykjAyG1+bfNTUf+ihYHMwVxAA+lCWJP5Q5ow6ldFX eYTVZ1MMKoI+GFy4MCYa1l7GLbIEUQ7v3wxjR+vEEghRK5lxXtVpe+FdyXcdIOxW juVhYC386RyA3/pqg7sFtR4jEpyCygrzFB0g5AaPQySZn7YKk1pzGxY5vgW28Yyl ZJKPBeRcdvc5w88tvQ7Yy6gOMZvJRg9nU0MEj8iyyIOAX7ryD6uBNaIgIZfOD4k0 eA/PH07p+4woPN405+2f0mb1xcoxeNLOUNFggmOd4Ez3B66DNJ1JSUPUfr0t4urH cWWACOQ2nnlwCjyHKenkkpTqBpIpJ3jmrdc96QoLXvTg1oadLXLLi2RW5vSueKWg OTNYPNyoj420ai39iHPplVBzBN8RiD5C1gJ0+yzEb7xs1uCAb9GGpTJXA9ZN9E4K mSJ2fkpAgvjJ5E7LUy3Hsbbi08J1J265DnGyNPy/HE7CPfg26QrMWJqhGIZO4uGq s3NZbl6dtMIIr69c/aQCb/+4DbvVq9dunxpPkUDwH0ZVbaCSw4nNt7H/HLPLo5wK 4/7NqrwB7N1UypHdTxOHpPaY7/1J1lcqPKZc9mA3v9g+fk5oKiMyOr5u5CI9ByTP isubXVGzMNJxbc5Gim18SjNE2hIvNkvy6fFRCW3bapcOFwIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBTVZx3gnHosnMvFmOcdByYqhux0zTAOBgNV HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAJA75cJTQijq9TFOjj2Rnk0J 89ixUuZPrAwxIbvx6pnMg/y2KOTshAcOD06Xu29oRo8OURWV+Do7H1+CDgxxDryR T64zLiNB9CZrTxOH+nj2LsIPkQWXqmrBap+8hJ4IKifd2ocXhuGzyl3tOKkpboTe Rmv8JxlQpRJ6jH1i/NrnzLyfSa8GuCcn8on3Fj0Y5r3e9YwSkZ/jBI3+BxQaWqw5 ghvxOBnhY+OvbLamURfr+kvriyL2l/4QOl+UoEtTcT9a4RD4co+WgN2NApgAYT2N vC2xR8zaXeEgp4wxXPHj2rkKhkfIoT0Hozymc26Uke1uJDr5yTDRB6iBfSZ9fYTf hsmL5a4NHr6JSFEVg5iWL0rrczTXdM3Jb9DCuiv2mv6Z3WAUjhv5nDk8f0OJU+jl wqu+Iq0nOJt3KLejY2OngeepaUXrjnhWzAWEx/uttjB8YwWfLYwkf0uLkvw4Hp+g pVezbp3YZLhwmmBScMip0P/GnO0QYV7Ngw5u6E0CQUridgR51lQ/ipgyFKDdLZzn uoJxo4ZVKZnSKdt1OvfbQ/+2W/u3fjWAjg1srnm3Ni2XUqGwB5wH5Ss2zQOXlL0t DjQG/MAWifw3VOTWzz0TBPKR2ck2Lj7FWtClTILD/y58Jnb38/1FoqVuVa4uzM8s iTTa9g3nkagQ6hed8vbs -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D 0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr 6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN 9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h 9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo +fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h 3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQy MDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjEw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy3QRk D2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/o OI7bm+V8u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3A fQ+lekLZWnDZv6fXARz2m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJe IgpFy4QxTaz+29FHuvlglzmxZcfe+5nkCiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8n oc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTaYVKvJrT1cU/J19IG32PK /yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6vpmumwKj rckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD 3AjLLhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE 7cderVC6xkGbrPAXZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkC yC2fg69naQanMVXVz0tv/wQFx1isXxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLd qvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ04IwDQYJKoZI hvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaA SfX8MPWbTx9BLxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXo HqJPYNcHKfyyo6SdbhWSVhlMCrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpB emOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5GfbVSUZP/3oNn6z4eGBrxEWi1CXYBmC AMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85YmLLW1AL14FABZyb 7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKSds+x DzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvk F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9jCCAt6gAwIBAgIQJDJ18h0v0gkz97RqytDzmDANBgkqhkiG9w0BAQsFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAx IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHOddJZKmZgiJM6kXZBxbje/SD 6Jlz+muxNuCad6BAwoGNAcfMjL2Pffd543pMA03Z+/2HOCgs3ZqLVAjbZ/sbjP4o ki++t7JIp4Gh2F6Iw8w5QEFa0dzl2hCfL9oBTf0uRnz5LicKaTfukaMbasxEvxvH w9QRslBglwm9LiL1QYRmn81ApqkAgMEflZKf3vNI79sdd2H8f9/ulqRy0LY+/3gn r8uSFWkI22MQ4uaXrG7crPaizh5HmbmJtxLmodTNWRFnw2+F2EJOKL5ZVVkElauP N4C/DfD8HzpkMViBeNfiNfYgPym4jxZuPkjctUwH4fIa6n4KedaovetdhitNAgMB AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBQzQejIORIVk0jyljIuWvXalF9TYDANBgkqhkiG9w0BAQsFAAOCAQEAFeNzV7EX tl9JaUSm9l56Z6zS3nVJq/4lVcc6yUQVEG6/MWvL2QeTfxyFYwDjMhLgzMv7OWyP 4lPiPEAz2aSMR+atWPuJr+PehilWNCxFuBL6RIluLRQlKCQBZdbqUqwFblYSCT3Q dPTXvQbKqDqNVkL6jXI+dPEDct+HG14OelWWLDi3mIXNTTNEyZSPWjEwN0ujOhKz 5zbRIWhLLTjmU64cJVYIVgNnhJ3Gw84kYsdMNs+wBkS39V8C3dlU6S+QTnrIToNA DJqXPDe/v+z28LSFdyjBC8hnghAXOKK3Buqbvzr46SMHv3TgmDgVVXjucgBcGaP0 0jPg/73RVDkpDw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka +elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h /t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf ReYNnyicsbkqWletNw+vHX/bvZ8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwKgAwIBAgIDAYagMA0GCSqGSIb3DQEBBQUAMIGjMQswCQYDVQQGEwJG STEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0ZXJpa2Vz a3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBTZXJ2aWNl czEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJLIEdvdi4g Um9vdCBDQTAeFw0wMjEyMTgxMzUzMDBaFw0yMzEyMTgxMzUxMDhaMIGjMQswCQYD VQQGEwJGSTEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0 ZXJpa2Vza3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBT ZXJ2aWNlczEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJL IEdvdi4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCF FdrIAzfQo0Y3bBseljDCWoUSZyPyu5/nioFgJ/gTqTy894aqqvTzJSm0/nWuHoGG igWyHWWyOOi0zCia+xc28ZPVec7Bg4shT8MNrUHfeJ1I4x9CRPw8bSEga60ihCRC jxdNwlAfZM0tOSJWiP2yY51U2kJpwMhP1xjiPshphJQ9LIDGfM6911Mf64i5psu7 hVfvV3ZdDIvTXhJBnyHAOfQmbQj6OLOhd7HuFtjQaNq0mKWgZUZKa41+qk1guPjI DfxxPu45h4G02fhukO4/DmHXHSto5i7hQkQmeCxY8n0Wf2HASSQqiYe2XS8pGfim 545SnkFLWg6quMJmQlMCAwEAAaNVMFMwDwYDVR0TAQH/BAUwAwEB/zARBglghkgB hvhCAQEEBAMCAAcwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBTb6eGb0tEkC/yr 46Bn6q6cS3f0sDANBgkqhkiG9w0BAQUFAAOCAQEArX1ID1QRnljurw2bEi8hpM2b uoRH5sklVSPj3xhYKizbXvfNVPVRJHtiZ+GxH0mvNNDrsczZog1Sf0JLiGCXzyVy t08pLWKfT6HAVVdWDsRol5EfnGTCKTIB6dTI2riBmCguGMcs/OubUpbf9MiQGS0j 8/G7cdqehSO9Gu8u5Hp5t8OdhkktY7ktdM9lDzJmid87Ie4pbzlj2RXBbvbfgD5Q eBmK3QOjFKU3p7UsfLYRh+cF8ry23tT/l4EohP7+bEaFEEGfTXWMB9SZZ291im/k UJL2mdUQuMSpe/cXjUu/15WfCdxEDx4yw8DP03kN5Mc7h/CQNIghYkmSBAQfvA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71 9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA 7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k /rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6 u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy 7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy 1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G 87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i 2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no xqE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH 4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy vUxFnmG6v4SBkgPR0ml8xQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIIAeDltYNno+AwDQYJKoZIhvcNAQEMBQAwZzEbMBkGA1UE AwwSQXBwbGUgUm9vdCBDQSAtIEcyMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMw HhcNMTQwNDMwMTgxMDA5WhcNMzkwNDMwMTgxMDA5WjBnMRswGQYDVQQDDBJBcHBs ZSBSb290IENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgREkhI2imKScUcx+xuM23+TfvgHN6s XuI2pyT5f1BrTM65MFQn5bPW7SXmMLYFN14UIhHF6Kob0vuy0gmVOKTvKkmMXT5x ZgM4+xb1hYjkWpIMBDLyyED7Ul+f9sDx47pFoFDVEovy3d6RhiPw9bZyLgHaC/Yu OQhfGaFjQQscp5TBhsRTL3b2CtcM0YM/GlMZ81fVJ3/8E7j4ko380yhDPLVoACVd J2LT3VXdRCCQgzWTxb+4Gftr49wIQuavbfqeQMpOhYV4SbHXw8EwOTKrfl+q04tv ny0aIWhwZ7Oj8ZhBbZF8+NfbqOdfIRqMM78xdLe40fTgIvS/cjTf94FNcX1RoeKz 8NMoFnNvzcytN31O661A4T+B/fc9Cj6i8b0xlilZ3MIZgIxbdMYs0xBTJh0UT8TU gWY8h2czJxQI6bR3hDRSj4n4aJgXv8O7qhOTH11UL6jHfPsNFL4VPSQ08prcdUFm IrQB1guvkJ4M6mL4m1k8COKWNORj3rw31OsMiANDC1CvoDTdUE0V+1ok2Az6DGOe HwOx4e7hqkP0ZmUoNwIx7wHHHtHMn23KVDpA287PT0aLSmWaasZobNfMmRtHsHLD d4/E92GcdB/O/WuhwpyUgquUoue9G7q5cDmVF8Up8zlYNPXEpMZ7YLlmQ1A/bmH8 DvmGqmAMQ0uVAgMBAAGjQjBAMB0GA1UdDgQWBBTEmRNsGAPCe8CjoA1/coB6HHcm jTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwF AAOCAgEAUabz4vS4PZO/Lc4Pu1vhVRROTtHlznldgX/+tvCHM/jvlOV+3Gp5pxy+ 8JS3ptEwnMgNCnWefZKVfhidfsJxaXwU6s+DDuQUQp50DhDNqxq6EWGBeNjxtUVA eKuowM77fWM3aPbn+6/Gw0vsHzYmE1SGlHKy6gLti23kDKaQwFd1z4xCfVzmMX3z ybKSaUYOiPjjLUKyOKimGY3xn83uamW8GrAlvacp/fQ+onVJv57byfenHmOZ4VxG /5IFjPoeIPmGlFYl5bRXOJ3riGQUIUkhOb9iZqmxospvPyFgxYnURTbImHy99v6Z SYA7LNKmp4gDBDEZt7Y6YUX6yfIjyGNzv1aJMbDZfGKnexWoiIqrOEDCzBL/FePw N983csvMmOa/orz6JopxVtfnJBtIRD6e/J/JzBrsQzwBvDR4yGn1xuZW7AYJNpDr FEobXsmII9oDMJELuDY++ee1KG++P+w8j2Ud5cAeh6Squpj9kuNsJnfdBrRkBof0 Tta6SqoWqPQFZ2aWuuJVecMsXUmPgEkrihLHdoBR37q9ZV0+N0djMenl9MU/S60E inpxLK8JQzcPqOMyT/RFtm2XNuyE9QoB6he7hY1Ck3DDUOUUi78/w0EP3SIEIwiK um1xRKtzCTrJ+VKACd+66eYWyi4uTLLT3OUEVLLUNIAytbwPF+E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtDCCApygAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJKUDEc MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEOMAwGA1UECxMFTVBIUFQxJjAk BgNVBAsTHU1QSFBUIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTAyMDMxNDA3 NTAyNloXDTEyMDMxMzE0NTk1OVowYzELMAkGA1UEBhMCSlAxHDAaBgNVBAoTE0ph cGFuZXNlIEdvdmVybm1lbnQxDjAMBgNVBAsTBU1QSFBUMSYwJAYDVQQLEx1NUEhQ VCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAI3GUWlK9G9FVm8DhpKu5t37oxZbj6lZcFvEZY07YrYojWO657ub z56WE7q/PI/6Sm7i7qYE+Vp80r6thJvfmn7SS3BENrRqiapSenhooYD12jIe3iZQ 2SXqx7WgYwyBGdQwGaYTijzbRFpgc0K8o4a99fIoHhz9J8AKqXasddMCqfJRaH30 YJ7HnOvRYGL6HBrGhJ7X4Rzijyk9a9+3VOBsYcnIlx9iODoiYhA6r0ojuIu8/JA1 oTTZrS0MyU/SLdFdJze2O1wnqTULXQybzJz3ad6oC/F5a69c0m92akYd9nGBrPxj EhucaQynC/QoCLs3aciLgioAnEJqy7i3EgUCAwEAAaNzMHEwHwYDVR0jBBgwFoAU YML3pLoA0h93Yngl8Gb/UgAh73owHQYDVR0OBBYEFGDC96S6ANIfd2J4JfBm/1IA Ie96MAwGA1UdEwQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQE AwIABTANBgkqhkiG9w0BAQUFAAOCAQEANPR8DN66iWZBs/lSm1vOzhqRkXDLT6xL LvJtjPLqmE469szGyFSKzsof6y+/8YgZlOoeX1inF4ox/SH1ATnwdIIsPbXuRLjt axboXvBh5y2ffC3hmzJVvJ87tb6mVWQeL9VFUhNhAI0ib+9OIZVEYI/64MFkDk4e iWG5ts6oqIJH1V7dVZg6pQ1Tc0Ckhn6N1m1hD30S0/zoPn/20Wq6OCF3he8VJrRG dcW9BD/Bkesko1HKhMBDjHVrJ8cFwbnDSoo+Ki47eJWaz/cOzaSsaMVUsR5POava /abhhgHn/eOJdXiVslyK0DYscjsdB3aBUfwZlomxYOzG6CgjQPhJdw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgILMTI1MzcyODI4MjgwDQYJKoZIhvcNAQELBQAwWDELMAkG A1UEBhMCSlAxHDAaBgNVBAoTE0phcGFuZXNlIEdvdmVybm1lbnQxDTALBgNVBAsT BEdQS0kxHDAaBgNVBAMTE0FwcGxpY2F0aW9uQ0EyIFJvb3QwHhcNMTMwMzEyMTUw MDAwWhcNMzMwMzEyMTUwMDAwWjBYMQswCQYDVQQGEwJKUDEcMBoGA1UEChMTSmFw YW5lc2UgR292ZXJubWVudDENMAsGA1UECxMER1BLSTEcMBoGA1UEAxMTQXBwbGlj YXRpb25DQTIgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKaq rSVl1gAR1uh6dqr05rRL88zDUrSNrKZPtZJxb0a11a2LEiIXJc5F6BR6hZrkIxCo +rFnUOVtR+BqiRPjrq418fRCxQX3TZd+PCj8sCaRHoweOBqW3FhEl2LjMsjRFUFN dZh4vqtoqV7tR76kuo6hApfek3SZbWe0BSXulMjtqqS6MmxCEeu+yxcGkOGThchk KM4fR8fAXWDudjbcMztR63vPctgPeKgZggiQPhqYjY60zxU2pm7dt+JNQCBT2XYq 0HisifBPizJtROouurCp64ndt295D6uBbrjmiykLWa+2SQ1RLKn9nShjZrhwlXOa 2Po7M7xCQhsyrLEy+z0CAwEAAaOBwTCBvjAdBgNVHQ4EFgQUVqesqgIdsqw9kA6g by5Bxnbne9owDgYDVR0PAQH/BAQDAgEGMHwGA1UdEQR1MHOkcTBvMQswCQYDVQQG EwJKUDEYMBYGA1UECgwP5pel5pys5Zu95pS/5bqcMRswGQYDVQQLDBLmlL/lupzo qo3oqLzln7rnm6QxKTAnBgNVBAMMIOOCouODl+ODquOCseODvOOCt+ODp+ODs0NB MiBSb290MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH+aCXWs B9FydC53VzDCBJzUgKaD56WgG5/+q/OAvdVKo6GPtkxgEefK4WCB10jBIFmlYTKL nZ6X02aD2mUuWD7b5S+lzYxzplG+WCigeVxpL0PfY7KJR8q73rk0EWOgDiUX5Yf0 HbCwpc9BqHTG6FPVQvSCLVMJEWgmcZR1E02qdog8dLHW40xPYsNJTE5t8XB+w3+m Bcx4m+mB26jIx1ye/JKSLaaX8ji1bnOVDMA/zqaUMLX6BbfeniCq/BNkyYq6ZO/i Y+TYmK5rtT6mVbgzPixy+ywRAPtbFi+E0hOe+gXFwctyTiLdhMpLvNIthhoEdlkf SUJiOxMfFui61/0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz rD6ogRLQy7rQkgu2npaqBA+K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS /ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH 1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u 2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc 7uzXLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl 6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c 77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 +GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtTCCAp2gAwIBAgIIBhDCeat3PfIwDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UE BhMCQ0gxEjAQBgNVBAoTCVN3aXNzU2lnbjEyMDAGA1UEAxMpU3dpc3NTaWduIENB IChSU0EgSUsgTWF5IDYgMTk5OSAxODowMDo1OCkxHzAdBgkqhkiG9w0BCQEWEGNh QFN3aXNzU2lnbi5jb20wHhcNMDAxMTI2MjMyNzQxWhcNMzExMTI2MjMyNzQxWjB2 MQswCQYDVQQGEwJDSDESMBAGA1UEChMJU3dpc3NTaWduMTIwMAYDVQQDEylTd2lz c1NpZ24gQ0EgKFJTQSBJSyBNYXkgNiAxOTk5IDE4OjAwOjU4KTEfMB0GCSqGSIb3 DQEJARYQY2FAU3dpc3NTaWduLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKw5fjnmNneLQlUCQG8jQLwwfbrOZoUwNX8cbNqhxK03/xUloFVgAt+S Te2RxNXaCAXLBPn5ZST35TLV57aLmbHCtifv3YZqaaQGvjedltIBMJihJhZ+h3LY SKsUb+xEJ3x5ZUf8jP+Q1g57y1s8SnBFWN/ni5NkF1Y1y31VwOi9wiOf/VISL+uu SC4i1CP1Kbz3BDs6Hht1GpRYCbJ/K0bc9oJSpWpT5PGONsGIawqMbJuyoDghsXQ1 pbn2e8K64BSscGZVZTNooSGgNiHmACNJBYXiWVWrwXPF4l6SddmC3Rj0aKXjgECc FkHLDQcsM5JsK2ZLryTDUsQFbxVP2ikCAwEAAaNHMEUwCwYDVR0PBAQDAgEGMAwG A1UdEwQFMAMBAf8wHQYDVR0OBBYEFJbXcc05KtT8iLGKq1N4ae+PR34WMAkGA1Ud IwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAKMy6W8HvZdS1fBpEUzl6Lvw50bgE1Xc HU1JypSBG9mhdcXZo5AlPB4sCvx9Dmfwhyrdsshc0TP2V3Vh6eQqnEF5qB4lVziT Bko9mW6Ot+pPnwsy4SHpx3rw6jCYnOqfUcZjWqqqRrq/3P1waz+Mn4cLMVEg3Xaz qYov/khvSqS0JniwjRlo2H6f/1oVUKZvP+dUhpQepfZrOqMAWZW4otp6FolyQyeU NN6UCRNiUKl5vTijbKwUUwfER/1Vci3M1/O1QCfttQ4vRN4Buc0xqYtGL3cd5WiO vWzyhlTzAI6VUdNkQhhHJSAyTpj6dmXDRzrryoFGa2PjgESxz7XBaSI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA 0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN ZetX2fNXlrtIzYE= -----END CERTIFICATE----- ` ================================================ FILE: transport/roots/system/root_darwin_test.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package system import ( "crypto/x509" "runtime" "testing" ) func TestSystemRoots(t *testing.T) { switch runtime.GOARCH { case "arm", "arm64": t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH) } sysRoots := initSystemRoots() // actual system roots execRoots, err := execSecurityRoots() // non-cgo roots if err != nil { t.Fatalf("failed to read system roots: %v", err) } for _, tt := range [][]*x509.Certificate{sysRoots, execRoots} { if tt == nil { t.Fatal("no system roots") } // On Mavericks, there are 212 bundled certs; require only // 150 here, since this is just a sanity check, and the // exact number will vary over time. if want, have := 150, len(tt); have < want { t.Fatalf("want at least %d system roots, have %d", want, have) } } // Check that the two cert pools are roughly the same; // |A∩B| > max(|A|, |B|) / 2 should be a reasonably robust check. isect := make(map[string]bool, len(sysRoots)) for _, c := range sysRoots { isect[string(c.Raw)] = true } have := 0 for _, c := range execRoots { if isect[string(c.Raw)] { have++ } } var want int if nsys, nexec := len(sysRoots), len(execRoots); nsys > nexec { want = nsys / 2 } else { want = nexec / 2 } if have < want { t.Errorf("insufficient overlap between cgo and non-cgo roots; want at least %d, have %d", want, have) } } ================================================ FILE: transport/roots/system/root_linux.go ================================================ // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package system // Possible certificate files; stop after finding one. var certFiles = []string{ "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL "/etc/ssl/ca-bundle.pem", // OpenSUSE "/etc/pki/tls/cacert.pem", // OpenELEC } ================================================ FILE: transport/roots/system/root_nacl.go ================================================ // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package system // Possible certificate files; stop after finding one. var certFiles = []string{} ================================================ FILE: transport/roots/system/root_nocgo_darwin.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !cgo // +build !cgo package system import "crypto/x509" func initSystemRoots() []*x509.Certificate { roots, _ := execSecurityRoots() return roots } ================================================ FILE: transport/roots/system/root_plan9.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build plan9 // +build plan9 package system import ( "crypto/x509" ) // Possible certificate files; stop after finding one. var certFiles = []string{ "/sys/lib/tls/ca.pem", } func initSystemRoots() (roots []*x509.Certificate) { for _, file := range certFiles { data, err := os.ReadFile(file) if err == nil { roots, _ = appendPEM(roots, data) return } } // All of the files failed to load. systemRoots will be nil which will // trigger a specific error at verification time. return nil } ================================================ FILE: transport/roots/system/root_solaris.go ================================================ // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package system // Possible certificate files; stop after finding one. var certFiles = []string{ "/etc/certs/ca-certificates.crt", // Solaris 11.2+ "/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS "/etc/ssl/cacert.pem", // OmniOS } ================================================ FILE: transport/roots/system/root_unix.go ================================================ // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris // +build dragonfly freebsd linux nacl netbsd openbsd solaris package system import ( "crypto/x509" "os" ) // Possible directories with certificate files; stop after successfully // reading at least one file from a directory. var certDirectories = []string{ "/system/etc/security/cacerts", // Android } func initSystemRoots() []*x509.Certificate { var roots []*x509.Certificate for _, file := range certFiles { data, err := os.ReadFile(file) if err == nil { roots, _ = appendPEM(roots, data) return roots } } for _, directory := range certDirectories { fis, err := os.ReadDir(directory) if err != nil { continue } rootsAdded := false for _, fi := range fis { var ok bool data, err := os.ReadFile(directory + "/" + fi.Name()) if err == nil { if roots, ok = appendPEM(roots, data); ok { rootsAdded = true } } } if rootsAdded { return roots } } // All of the files failed to load. systemRoots will be nil which will // trigger a specific error at verification time. return nil } ================================================ FILE: transport/roots/system/root_windows.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package system import ( "crypto/x509" "errors" "syscall" "unsafe" ) // Creates a new *syscall.CertContext representing the leaf certificate in an in-memory // certificate store containing itself and all of the intermediate certificates specified // in the opts.Intermediates CertPool. // // A pointer to the in-memory store is available in the returned CertContext's Store field. // The store is automatically freed when the CertContext is freed using // syscall.CertFreeCertificateContext. func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertContext, error) { var storeCtx *syscall.CertContext leafCtx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &leaf.Raw[0], uint32(len(leaf.Raw))) if err != nil { return nil, err } defer syscall.CertFreeCertificateContext(leafCtx) handle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0) if err != nil { return nil, err } defer syscall.CertCloseStore(handle, 0) err = syscall.CertAddCertificateContextToStore(handle, leafCtx, syscall.CERT_STORE_ADD_ALWAYS, &storeCtx) if err != nil { return nil, err } if opts.Intermediates != nil { for _, intermediate := range opts.Intermediates.certs { ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw))) if err != nil { return nil, err } err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil) syscall.CertFreeCertificateContext(ctx) if err != nil { return nil, err } } } return storeCtx, nil } // extractSimpleChain extracts the final certificate chain from a CertSimpleChain. func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error) { if simpleChain == nil || count == 0 { return nil, errors.New("x509: invalid simple chain") } simpleChains := (*[1 << 20]*syscall.CertSimpleChain)(unsafe.Pointer(simpleChain))[:] lastChain := simpleChains[count-1] elements := (*[1 << 20]*syscall.CertChainElement)(unsafe.Pointer(lastChain.Elements))[:] for i := 0; i < int(lastChain.NumElements); i++ { // Copy the buf, since ParseCertificate does not create its own copy. cert := elements[i].CertContext encodedCert := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:] buf := make([]byte, cert.Length) copy(buf, encodedCert[:]) parsedCert, err := ParseCertificate(buf) if err != nil { return nil, err } chain = append(chain, parsedCert) } return chain, nil } // checkChainTrustStatus checks the trust status of the certificate chain, translating // any errors it finds into Go errors in the process. func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error { if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR { status := chainCtx.TrustStatus.ErrorStatus switch status { case syscall.CERT_TRUST_IS_NOT_TIME_VALID: return CertificateInvalidError{c, Expired} default: return UnknownAuthorityError{c, nil, nil} } } return nil } // checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for // use as a certificate chain for a SSL/TLS server. func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error { servernamep, err := syscall.UTF16PtrFromString(opts.DNSName) if err != nil { return err } sslPara := &syscall.SSLExtraCertChainPolicyPara{ AuthType: syscall.AUTHTYPE_SERVER, ServerName: servernamep, } sslPara.Size = uint32(unsafe.Sizeof(*sslPara)) para := &syscall.CertChainPolicyPara{ ExtraPolicyPara: uintptr(unsafe.Pointer(sslPara)), } para.Size = uint32(unsafe.Sizeof(*para)) status := syscall.CertChainPolicyStatus{} err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status) if err != nil { return err } // TODO(mkrautz): use the lChainIndex and lElementIndex fields // of the CertChainPolicyStatus to provide proper context, instead // using c. if status.Error != 0 { switch status.Error { case syscall.CERT_E_EXPIRED: return CertificateInvalidError{c, Expired} case syscall.CERT_E_CN_NO_MATCH: return HostnameError{c, opts.DNSName} case syscall.CERT_E_UNTRUSTEDROOT: return UnknownAuthorityError{c, nil, nil} default: return UnknownAuthorityError{c, nil, nil} } } return nil } // Note(kyle): not sure how this works on windows, or if this does. func initSystemRoots() []*x509.Certificate { return nil } ================================================ FILE: transport/transport_test.go ================================================ package transport import ( "encoding/json" "os" "testing" "time" "github.com/cloudflare/cfssl/api/client" "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/info" "github.com/cloudflare/cfssl/log" "github.com/cloudflare/cfssl/transport/core" ) var ( testRemote = envOrDefault("CFSSL_REMOTE", "http://127.0.0.1:8888") testLabel = envOrDefault("CFSSL_LABEL", "") testProfile = envOrDefault("CFSSL_PROFILE", "transport-test") disableTests bool ) func cfsslIsAvailable() bool { defaultRemote := client.NewServer(testRemote) infoReq := info.Req{ Profile: testProfile, Label: testLabel, } out, err := json.Marshal(infoReq) if err != nil { return false } _, err = defaultRemote.Info(out) if err != nil { log.Debug("CFSSL remote is unavailable, skipping tests") return false } return true } func removeIfPresent(path string) error { if _, err := os.Stat(path); !os.IsNotExist(err) { return os.Remove(path) } return nil } func TestMain(m *testing.M) { if fi, err := os.Stat("testdata"); os.IsNotExist(err) { err = os.Mkdir("testdata", 0755) if err != nil { log.Fatalf("unable to setup testdata directory: %v", err) } } else if fi != nil && !fi.Mode().IsDir() { log.Fatalf("testdata exists but isn't a directory") } else if err != nil { log.Fatalf("%v", err) } var exitCode int if cfsslIsAvailable() { exitCode = m.Run() } err := removeIfPresent(testKey) if err == nil { err = removeIfPresent(testCert) } if err != nil { os.Exit(1) } err = removeIfPresent(testLKey) if err == nil { err = removeIfPresent(testLCert) } if err != nil { os.Exit(1) } os.Exit(exitCode) } var ( tr *Transport testKey = "testdata/test.key" testCert = "testdata/test.pem" testIdentity = &core.Identity{ Request: &csr.CertificateRequest{ CN: "localhost test certificate", }, Roots: []*core.Root{ { Type: "system", }, { Type: "cfssl", Metadata: map[string]string{ "host": testRemote, "label": testLabel, "profile": testProfile, }, }, }, Profiles: map[string]map[string]string{ "paths": { "private_key": testKey, "certificate": testCert, }, "cfssl": { "label": testLabel, "profile": testProfile, "remote": testRemote, }, }, } ) func TestTransportSetup(t *testing.T) { var before = 55 * time.Second var err error tr, err = New(before, testIdentity) if err != nil { t.Fatalf("failed to set up transport: %v", err) } } func TestRefreshKeys(t *testing.T) { err := tr.RefreshKeys() if err != nil { t.Fatalf("%v", err) } } func TestAutoUpdate(t *testing.T) { // To force a refresh, make sure that the certificate is // updated 5 seconds from now. cert := tr.Provider.Certificate() if cert == nil { t.Fatal("no certificate from provider") } certUpdates := make(chan time.Time, 0) errUpdates := make(chan error, 0) oldBefore := tr.Before before := cert.NotAfter.Sub(time.Now()) before -= 5 * time.Second tr.Before = before defer func() { tr.Before = oldBefore PollInterval = 30 * time.Second }() PollInterval = 2 * time.Second go tr.AutoUpdate(certUpdates, errUpdates) log.Debugf("waiting for certificate update or error from auto updater") select { case <-certUpdates: // Nothing needs to be done case err := <-errUpdates: t.Fatalf("%v", err) case <-time.After(15 * time.Second): t.Fatal("timeout waiting for update") } } var ( l *Listener testLKey = "testdata/server.key" testLCert = "testdata/server.pem" testLIdentity = &core.Identity{ Request: &csr.CertificateRequest{ CN: "localhost test certificate", Hosts: []string{"127.0.0.1"}, }, Profiles: map[string]map[string]string{ "paths": { "private_key": testLKey, "certificate": testLCert, }, "cfssl": { "label": testLabel, "profile": testProfile, "remote": testRemote, }, }, Roots: []*core.Root{ { Type: "system", }, { Type: "cfssl", Metadata: map[string]string{ "host": testRemote, "label": testLabel, "profile": testProfile, }, }, }, } ) func testListen(t *testing.T) { log.Debug("listener waiting for connection") conn, err := l.Accept() if err != nil { panic(err.Error()) } log.Debugf("client has connected") conn.Write([]byte("hello")) conn.Close() } func TestListener(t *testing.T) { var before = 55 * time.Second trl, err := New(before, testLIdentity) if err != nil { t.Fatalf("failed to set up transport: %v", err) } trl.Identity.Request.CN = "localhost test server" err = trl.RefreshKeys() if err != nil { t.Fatalf("%v", err) } l, err = Listen("127.0.0.1:8765", trl) if err != nil { t.Fatalf("%v", err) } errChan := make(chan error, 0) go func() { err := <-errChan if err != nil { panic("listener auto update failed: " + err.Error()) } }() cert := trl.Provider.Certificate() before = cert.NotAfter.Sub(time.Now()) before -= 5 * time.Second trl.Before = before go l.AutoUpdate(nil, errChan) go testListen(t) <-time.After(1 * time.Second) log.Debug("dialer making connection") conn, err := Dial("127.0.0.1:8765", tr) if err != nil { log.Debugf("certificate time: %s-%s / %s", trl.Provider.Certificate().NotBefore, trl.Provider.Certificate().NotAfter, time.Now().UTC()) log.Debugf("%#v", trl.Provider.Certificate()) t.Fatalf("%v", err) } log.Debugf("client connected to server") conn.Close() } ================================================ FILE: ubiquity/filter.go ================================================ // Package ubiquity contains the ubiquity scoring logic for CFSSL bundling. package ubiquity // Ubiquity is addressed as selecting the chains that are most likely being accepted for different client systems. // To select, we decide to do multi-round filtering from different ranking perpectives. import ( "crypto/x509" ) // RankingFunc returns the relative rank between chain1 and chain2. // Return value: // // - positive integer if rank(chain1) > rank(chain2), // - negative integer if rank(chain1) < rank(chain2), // - 0 if rank(chain1) == (chain2). type RankingFunc func(chain1, chain2 []*x509.Certificate) int // Filter filters out the chains with highest rank according to the ranking function f. func Filter(chains [][]*x509.Certificate, f RankingFunc) [][]*x509.Certificate { // If there are no chain or only 1 chain, we are done. if len(chains) <= 1 { return chains } bestChain := chains[0] var candidateChains [][]*x509.Certificate for _, chain := range chains { r := f(bestChain, chain) if r < 0 { bestChain = chain candidateChains = [][]*x509.Certificate{chain} } else if r == 0 { candidateChains = append(candidateChains, chain) } } return candidateChains } ================================================ FILE: ubiquity/performance.go ================================================ package ubiquity // In this file, we include chain ranking functions based on security and performance import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" "crypto/x509" "time" "github.com/cloudflare/cfssl/helpers" ) // Compute the priority of different hash algorithm based on security // SHA2 > SHA1 >> MD = Others = Unknown func hashPriority(cert *x509.Certificate) int { switch cert.SignatureAlgorithm { case x509.ECDSAWithSHA1, x509.DSAWithSHA1, x509.SHA1WithRSA: return 10 case x509.ECDSAWithSHA256, x509.ECDSAWithSHA384, x509.ECDSAWithSHA512, x509.DSAWithSHA256, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA: return 100 default: return 0 } } // Compute the priority of different key algorithm based performance and security // ECDSA>RSA>DSA>Unknown func keyAlgoPriority(cert *x509.Certificate) int { switch cert.PublicKeyAlgorithm { case x509.ECDSA: switch cert.PublicKey.(*ecdsa.PublicKey).Curve { case elliptic.P256(): return 100 case elliptic.P384(): return 120 case elliptic.P521(): return 140 default: return 100 } case x509.RSA: switch cert.PublicKey.(*rsa.PublicKey).N.BitLen() { case 4096: return 70 case 3072: return 50 case 2048: return 30 // key size <= 1024 are discouraged. default: return 0 } // we do not want to bundle a DSA cert. case x509.DSA: return 0 default: return 0 } } // HashPriority returns the hash priority of the chain as the average of hash priority of certs in it. func HashPriority(certs []*x509.Certificate) int { ret := 0.0 for i, cert := range certs { f1 := 1.0 / (float64(i) + 1.0) f2 := 1.0 - f1 ret = ret*f2 + float64(hashPriority(cert))*f1 } return int(ret) } // KeyAlgoPriority returns the key algorithm priority of the chain as the average of key algorithm priority of certs in it. func KeyAlgoPriority(certs []*x509.Certificate) int { ret := 0.0 for i, cert := range certs { f1 := 1.0 / (float64(i) + 1.0) f2 := 1.0 - f1 ret = float64(keyAlgoPriority(cert))*f1 + ret*f2 } return int(ret) } // CompareChainHashPriority ranks chains with more current hash functions higher. func CompareChainHashPriority(chain1, chain2 []*x509.Certificate) int { hp1 := HashPriority(chain1) hp2 := HashPriority(chain2) return hp1 - hp2 } // CompareChainKeyAlgoPriority ranks chains with more current key algorithm higher. func CompareChainKeyAlgoPriority(chain1, chain2 []*x509.Certificate) int { kap1 := KeyAlgoPriority(chain1) kap2 := KeyAlgoPriority(chain2) return kap1 - kap2 } // CompareChainCryptoSuite ranks chains with more current crypto suite higher. func CompareChainCryptoSuite(chain1, chain2 []*x509.Certificate) int { cs1 := HashPriority(chain1) + KeyAlgoPriority(chain1) cs2 := HashPriority(chain2) + KeyAlgoPriority(chain2) return cs1 - cs2 } // CompareChainLength ranks shorter chain higher. func CompareChainLength(chain1, chain2 []*x509.Certificate) int { return len(chain2) - len(chain1) } func compareTime(t1, t2 time.Time) int { if t1.After(t2) { return 1 } else if t1.Before(t2) { return -1 } return 0 } // CompareChainExpiry ranks chain that lasts longer higher. func CompareChainExpiry(chain1, chain2 []*x509.Certificate) int { t1 := helpers.ExpiryTime(chain1) t2 := helpers.ExpiryTime(chain2) return compareTime(t1, t2) } ================================================ FILE: ubiquity/sha1.go ================================================ package ubiquity import ( "crypto/x509" "fmt" "time" "github.com/cloudflare/cfssl/helpers" ) // DeprecationSeverity encodes the severity of a deprecation policy type DeprecationSeverity int const ( // None indicates there is no deprecation None DeprecationSeverity = iota // Low indicates the deprecation policy won't affect user experience Low // Medium indicates the deprecation policy will affect user experience // either in a minor way or for a limited scope of users. Medium // High indicates the deprecation policy will strongly affect user experience High ) // SHA1DeprecationPolicy encodes how a platform deprecates the support of SHA1 type SHA1DeprecationPolicy struct { // the name of platform Platform string `json:"platform"` // policy severity, policies of the same platform will only trigger the one of highest severity Severity DeprecationSeverity `json:"severity"` // a human readable message describing the deprecation effects Description string `json:"description"` // the date when the policy is effective. zero value means effective immediately EffectiveDate time.Time `json:"effective_date"` // the expiry deadline indicates the latest date which a end-entity // certificate with SHA1 can be valid through. ExpiryDeadline time.Time `json:"expiry_deadline"` // the date beyond which SHA1 cert should not be issued. NeverIssueAfter time.Time `json:"never_issue_after"` } // SHA1DeprecationPolicys ia a list of various SHA1DeprecationPolicy's // proposed by major browser producers var SHA1DeprecationPolicys = []SHA1DeprecationPolicy{ // Chrome: // if the leaf certificate expires between 01-01-2016 and 01-01-2017 // and the chain (excluding root) contains SHA-1 cert, show "minor errors". { Platform: "Google Chrome", Description: "shows the SSL connection has minor problems", Severity: Medium, ExpiryDeadline: time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC), }, // Chrome: // if the leaf certificate expires after Jan. 1st 2017 // and the chain (excluding root) contains SHA-1 cert, show "untrusted SSL". { Platform: "Google Chrome", Description: "shows the SSL connection is untrusted", Severity: High, ExpiryDeadline: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC), }, // Mozilla Firefox: // if the leaf certificate expires after Jan. 1st 2017, and // the chain (excluding root) contains SHA-1 cert, show a warning in the developer console. { Platform: "Mozilla Firefox", Description: "gives warning in the developer console", Severity: Low, ExpiryDeadline: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC), }, // Mozilla Firefox: // if a new certificate is issued after Jan. 1st 2016, and // it is a SHA-1 cert, reject it. { Platform: "Mozilla Firefox", Description: "shows the SSL connection is untrusted", Severity: Medium, EffectiveDate: time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC), NeverIssueAfter: time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC), }, // Mozilla Firefox: // deprecate all valid SHA-1 cert chain on Jan. 1st 2017 { Platform: "Mozilla Firefox", Description: "shows the SSL connection is untrusted", Severity: High, EffectiveDate: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC), ExpiryDeadline: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC), }, // Microsoft Windows: // deprecate all valid SHA-1 cert chain on Jan. 1st 2017 { Platform: "Microsoft Windows Vista and later", Description: "shows the SSL connection is untrusted", Severity: High, EffectiveDate: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC), ExpiryDeadline: time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC), }, } // Flag returns whether the policy flags the cert chain as deprecated for matching its deprecation criteria func (p SHA1DeprecationPolicy) Flag(chain []*x509.Certificate) bool { leaf := chain[0] if time.Now().After(p.EffectiveDate) { // Reject newly issued leaf certificate with SHA-1 after the specified deadline. if !p.NeverIssueAfter.IsZero() && leaf.NotBefore.After(p.NeverIssueAfter) { // Check hash algorithm of non-root leaf cert. if len(chain) > 1 && helpers.HashAlgoString(leaf.SignatureAlgorithm) == "SHA1" { return true } } // Reject certificate chain with SHA-1 that are still valid after expiry deadline. if !p.ExpiryDeadline.IsZero() && leaf.NotAfter.After(p.ExpiryDeadline) { // Check hash algorithm of non-root certs. for i, cert := range chain { if i < len(chain)-1 { if helpers.HashAlgoString(cert.SignatureAlgorithm) == "SHA1" { return true } } } } } return false } // SHA1DeprecationMessages returns a list of human-readable messages. Each message describes // how one platform rejects the chain based on SHA1 deprecation policies. func SHA1DeprecationMessages(chain []*x509.Certificate) []string { // record the most severe deprecation policy by each platform selectedPolicies := map[string]SHA1DeprecationPolicy{} for _, policy := range SHA1DeprecationPolicys { if policy.Flag(chain) { // only keep the policy with highest severity if selectedPolicies[policy.Platform].Severity < policy.Severity { selectedPolicies[policy.Platform] = policy } } } // build the message list list := []string{} for _, policy := range selectedPolicies { if policy.Severity > None { list = append(list, fmt.Sprintf("%s %s due to SHA-1 deprecation", policy.Platform, policy.Description)) } } return list } ================================================ FILE: ubiquity/testdata/ca.pem.metadata ================================================ [ { "name":"Browser Everywhere", "weight": 0, "hash_algo": "SHA2", "key_algo": "ECDSA256" }, { "name":"Pineapple", "weight": 1, "hash_algo": "SHA2", "key_algo": "ECDSA521", "keystore": "pineapple.pem" } ] ================================================ FILE: ubiquity/testdata/ecdsa256sha2.pem ================================================ -----BEGIN CERTIFICATE----- MIICsDCCAjegAwIBAgIIDmHBNS+T0F8wCgYIKoZIzj0EAwMwgYwxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAeFw0xNDA0MTEyMTIy MzhaFw0xOTA0MTEyMTI3MzhaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xv dWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEcMBoGA1UEAxMTY2xv dWRmbGFyZS1sZWFmLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIxG/fG9 y/gjlAXvB77beERLbBooN98FGFAxVUA5IglylvgmfNxUmI8mM2Uw9tzOLm9vORAr aSSM4/6iSpCJreCjgYEwfzAOBgNVHQ8BAf8EBAMCAKQwEgYDVR0TAQH/BAgwBgEB /wIBATAdBgNVHQ4EFgQU4t+cr91ma5IxOPeiezgN8W9FBNowHwYDVR0jBBgwFoAU QfmKIlIyJt+P8AcB3SRhOFrn7PwwGQYDVR0RBBIwEIIOY2Zzc2wtbGVhZi5jb20w CgYIKoZIzj0EAwMDZwAwZAIwYQWcWr79DPrIBnphpHZPuxnGust6NtD0aSffB1cF NlYtggjJZDbLijAgD0Bwi3THAjA639xrNxVgc/LkJcHfSRhs8Jhv9cxQxIVf3g8w 6tBymEgJ6L8aIPGgXNRJGs7FmPs= -----END CERTIFICATE----- ================================================ FILE: ubiquity/testdata/ecdsa384sha2.pem ================================================ -----BEGIN CERTIFICATE----- MIICzzCCAlSgAwIBAgIIbOxERQylZJMwCgYIKoZIzj0EAwMwgYwxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAeFw0xNDA0MTEyMTIy MzhaFw0xOTA0MTEyMTI3MzhaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xv dWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEcMBoGA1UEAxMTY2xv dWRmbGFyZS1sZWFmLmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABNYivDDh3Iik kb+3/Oocity4JQXmxLP2njZThYNtR4y7Bxixp05KLoq8gtazyccDklueu4OWFnpm kjyqPQ+0MIf/BJKoA4Q4iNiCN/ZfF690LR/pZPrMRZuWSGVb2890L6OBgTB/MA4G A1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTiTQoJ uFODtNnEnbYaxy+He8lO+DAfBgNVHSMEGDAWgBRB+YoiUjIm34/wBwHdJGE4Wufs /DAZBgNVHREEEjAQgg5jZnNzbC1sZWFmLmNvbTAKBggqhkjOPQQDAwNpADBmAjEA q/sUd8AQAornMMiLZ5spBu+g6x6qx66wNPw9WE5a+T0hndHJsAqads5ndW7/5fuo AjEAiQ9wR1ugYaY56mj9UfjCZbwvo19unlB+CTLr48fh/RhvX6xjnpWXxJeXzU3G GhTH -----END CERTIFICATE----- ================================================ FILE: ubiquity/testdata/ecdsa521sha2.pem ================================================ -----BEGIN CERTIFICATE----- MIIC9TCCAnqgAwIBAgIIUbwCGeeEj4AwCgYIKoZIzj0EAwMwgYwxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAeFw0xNDA0MTEyMTIy MzhaFw0xOTA0MTEyMTI3MzhaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xv dWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEcMBoGA1UEAxMTY2xv dWRmbGFyZS1sZWFmLmNvbTCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEASndSqqg ml7pRXvL1hHdrxKAymhGi1Io2p4D0kqL7cvITqnnDdawQ2/JyHUNBzhOrue8fiCN E+o7vnbV5exuasBjAQrcXVF17EUknncNoq5Sdg6qIjmlwcqNMOqSvYIAGHdwTXUe Da88d/je+kynzaiMoXM21IkFKedXtpv36D7OK96oo4GBMH8wDgYDVR0PAQH/BAQD AgCkMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFDYrMNrJaqxCJjszycul XPsseU/yMB8GA1UdIwQYMBaAFEH5iiJSMibfj/AHAd0kYTha5+z8MBkGA1UdEQQS MBCCDmNmc3NsLWxlYWYuY29tMAoGCCqGSM49BAMDA2kAMGYCMQCKWeIUGeuvt9kb 5DtYw3++X5m7Nxf8CE67BuyoLV/3OpmTpo0Qp2LnapyXP63hAY8CMQCm1P3S/6+S U6oMFvMrpAcIFm6B1TtuTnSRGx89eZqoCdEJHVZuBWRyFABBnkKSf0Q= -----END CERTIFICATE----- ================================================ FILE: ubiquity/testdata/godzilla.pem ================================================ -----BEGIN CERTIFICATE----- MIIC1jCCAj+gAwIBAgIUJhxh1ENJRZoFuCN+XB0xlP1zgeYwDQYJKoZIhvcNAQEL BQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxhcmUxFDASBgNVBAsMC0RF Vl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NBMB4XDTI1MDIwODIwMTYy N1oXDTM1MDIwNjIwMTYyN1owfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm b3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxh cmUxFDASBgNVBAsMC0RFVl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NB MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbp/6OQ/a3mr+8zRgBRlmSGr8Q BgP4vUIxLn2Mk4uiZ8OcpRY4YqL+TtREGDUc0ve+bv8RINrNlYXL2X+eJtbE2RJQ +RAiu+saw2K+RFTNeTCA1fwg3ws5gBDcFbECqK1dOkuN/gV4JMHobn2/15iUBfeS JxdF1j5yqES8sVu7cwIDAQABo1MwUTAdBgNVHQ4EFgQUuF7vrmdQt9bzB+VqvlWz ZzoNkj4wHwYDVR0jBBgwFoAUuF7vrmdQt9bzB+VqvlWzZzoNkj4wDwYDVR0TAQH/ BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQALmrNPUPlCyhabvgC8RsMZPhJjtxr9 TotLuoa49zsHH18djRZLrm8mNzBwUVVNJ1hgwSpRnyrc7T4HQTTvjpCnyXEVRil/ 9HQbpVPBSw5W6oK3koLG0rFnZXHocqK+Qri4FkbwsTK5qlea35OJWkODiUY/ykVM E4sm6QDE79e0Iw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfDCCAwKgAwIBAgIIUYJhG37C300wCgYIKoZIzj0EAwMwgYwxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAeFw0xNDA0MTEyMTIy MzhaFw0xOTA0MTEyMTI3MzhaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xv dWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEcMBoGA1UEAxMTY2xv dWRmbGFyZS1sZWFmLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANAukkrF37rHtiFfPuoUmKkj0HaEMGeQWEJ0sbispQKwqzF8fCRh6yT+j4+xsUZh +NL/bvVcGb3K0DpvMlE7swBH9ind7r15lSiW9r3NAaKbH5aUhDixLnXU0h5R4HVR 8paqW8we2a5sl17lk7UxRGhpj1VJlnDgTsuqXP+4Wb+x5E42hy0Lv7qIYnPzYztK CWmlMHbOprsEwjUpjL7b6D+dackCXrmY2CKFp57vvw27WWJh+OFWxw9FPrkjSi2W uG3lqg6uWQ8ELxFZLi6i999WsM4CH9GuG4T/rnNZHVl2fFfvGgW6rauoOqPR3a84 DUUfvUtxLxHpQq8blsPRUN0CAwEAAaOBgTB/MA4GA1UdDwEB/wQEAwIApDASBgNV HRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBShnoK2Oquaq/XjlNBMxs5yPTSJvjAf BgNVHSMEGDAWgBRB+YoiUjIm34/wBwHdJGE4Wufs/DAZBgNVHREEEjAQgg5jZnNz bC1sZWFmLmNvbTAKBggqhkjOPQQDAwNoADBlAjAhMWEJzBwuN5bVACPCAoVPSWI2 +0DQi4Tu6sBNQl+dsyO+FPyA3+aYc0NgnBwcj+0CMQC7JOdfdWJPZj6rOAXvGV3I jGJRHZmu5q5K+9teIK1b9mustpnDJgniKAHtBGecXy4= -----END CERTIFICATE----- ================================================ FILE: ubiquity/testdata/macrosoft.pem ================================================ -----BEGIN CERTIFICATE----- MIIC1jCCAj+gAwIBAgIUJhxh1ENJRZoFuCN+XB0xlP1zgeYwDQYJKoZIhvcNAQEL BQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxhcmUxFDASBgNVBAsMC0RF Vl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NBMB4XDTI1MDIwODIwMTYy N1oXDTM1MDIwNjIwMTYyN1owfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm b3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxh cmUxFDASBgNVBAsMC0RFVl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NB MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbp/6OQ/a3mr+8zRgBRlmSGr8Q BgP4vUIxLn2Mk4uiZ8OcpRY4YqL+TtREGDUc0ve+bv8RINrNlYXL2X+eJtbE2RJQ +RAiu+saw2K+RFTNeTCA1fwg3ws5gBDcFbECqK1dOkuN/gV4JMHobn2/15iUBfeS JxdF1j5yqES8sVu7cwIDAQABo1MwUTAdBgNVHQ4EFgQUuF7vrmdQt9bzB+VqvlWz ZzoNkj4wHwYDVR0jBBgwFoAUuF7vrmdQt9bzB+VqvlWzZzoNkj4wDwYDVR0TAQH/ BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQALmrNPUPlCyhabvgC8RsMZPhJjtxr9 TotLuoa49zsHH18djRZLrm8mNzBwUVVNJ1hgwSpRnyrc7T4HQTTvjpCnyXEVRil/ 9HQbpVPBSw5W6oK3koLG0rFnZXHocqK+Qri4FkbwsTK5qlea35OJWkODiUY/ykVM E4sm6QDE79e0Iw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfDCCAwKgAwIBAgIIUYJhG37C300wCgYIKoZIzj0EAwMwgYwxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAeFw0xNDA0MTEyMTIy MzhaFw0xOTA0MTEyMTI3MzhaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xv dWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEcMBoGA1UEAxMTY2xv dWRmbGFyZS1sZWFmLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANAukkrF37rHtiFfPuoUmKkj0HaEMGeQWEJ0sbispQKwqzF8fCRh6yT+j4+xsUZh +NL/bvVcGb3K0DpvMlE7swBH9ind7r15lSiW9r3NAaKbH5aUhDixLnXU0h5R4HVR 8paqW8we2a5sl17lk7UxRGhpj1VJlnDgTsuqXP+4Wb+x5E42hy0Lv7qIYnPzYztK CWmlMHbOprsEwjUpjL7b6D+dackCXrmY2CKFp57vvw27WWJh+OFWxw9FPrkjSi2W uG3lqg6uWQ8ELxFZLi6i999WsM4CH9GuG4T/rnNZHVl2fFfvGgW6rauoOqPR3a84 DUUfvUtxLxHpQq8blsPRUN0CAwEAAaOBgTB/MA4GA1UdDwEB/wQEAwIApDASBgNV HRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBShnoK2Oquaq/XjlNBMxs5yPTSJvjAf BgNVHSMEGDAWgBRB+YoiUjIm34/wBwHdJGE4Wufs/DAZBgNVHREEEjAQgg5jZnNz bC1sZWFmLmNvbTAKBggqhkjOPQQDAwNoADBlAjAhMWEJzBwuN5bVACPCAoVPSWI2 +0DQi4Tu6sBNQl+dsyO+FPyA3+aYc0NgnBwcj+0CMQC7JOdfdWJPZj6rOAXvGV3I jGJRHZmu5q5K+9teIK1b9mustpnDJgniKAHtBGecXy4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICsDCCAjegAwIBAgIIDmHBNS+T0F8wCgYIKoZIzj0EAwMwgYwxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAeFw0xNDA0MTEyMTIy MzhaFw0xOTA0MTEyMTI3MzhaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xv dWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEcMBoGA1UEAxMTY2xv dWRmbGFyZS1sZWFmLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIxG/fG9 y/gjlAXvB77beERLbBooN98FGFAxVUA5IglylvgmfNxUmI8mM2Uw9tzOLm9vORAr aSSM4/6iSpCJreCjgYEwfzAOBgNVHQ8BAf8EBAMCAKQwEgYDVR0TAQH/BAgwBgEB /wIBATAdBgNVHQ4EFgQU4t+cr91ma5IxOPeiezgN8W9FBNowHwYDVR0jBBgwFoAU QfmKIlIyJt+P8AcB3SRhOFrn7PwwGQYDVR0RBBIwEIIOY2Zzc2wtbGVhZi5jb20w CgYIKoZIzj0EAwMDZwAwZAIwYQWcWr79DPrIBnphpHZPuxnGust6NtD0aSffB1cF NlYtggjJZDbLijAgD0Bwi3THAjA639xrNxVgc/LkJcHfSRhs8Jhv9cxQxIVf3g8w 6tBymEgJ6L8aIPGgXNRJGs7FmPs= -----END CERTIFICATE----- ================================================ FILE: ubiquity/testdata/pineapple.pem ================================================ -----BEGIN CERTIFICATE----- MIIC1jCCAj+gAwIBAgIUJhxh1ENJRZoFuCN+XB0xlP1zgeYwDQYJKoZIhvcNAQEL BQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxhcmUxFDASBgNVBAsMC0RF Vl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NBMB4XDTI1MDIwODIwMTYy N1oXDTM1MDIwNjIwMTYyN1owfTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm b3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkNsb3VkRmxh cmUxFDASBgNVBAsMC0RFVl9URVNUSU5HMRYwFAYDVQQDDA1DRlNTTF9URVNUX0NB MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbp/6OQ/a3mr+8zRgBRlmSGr8Q BgP4vUIxLn2Mk4uiZ8OcpRY4YqL+TtREGDUc0ve+bv8RINrNlYXL2X+eJtbE2RJQ +RAiu+saw2K+RFTNeTCA1fwg3ws5gBDcFbECqK1dOkuN/gV4JMHobn2/15iUBfeS JxdF1j5yqES8sVu7cwIDAQABo1MwUTAdBgNVHQ4EFgQUuF7vrmdQt9bzB+VqvlWz ZzoNkj4wHwYDVR0jBBgwFoAUuF7vrmdQt9bzB+VqvlWzZzoNkj4wDwYDVR0TAQH/ BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQALmrNPUPlCyhabvgC8RsMZPhJjtxr9 TotLuoa49zsHH18djRZLrm8mNzBwUVVNJ1hgwSpRnyrc7T4HQTTvjpCnyXEVRil/ 9HQbpVPBSw5W6oK3koLG0rFnZXHocqK+Qri4FkbwsTK5qlea35OJWkODiUY/ykVM E4sm6QDE79e0Iw== -----END CERTIFICATE----- ================================================ FILE: ubiquity/testdata/rsa1024sha1.pem ================================================ -----BEGIN CERTIFICATE----- MIICyDCCAjGgAwIBAgIJAPCgd7rafQZGMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNV BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp c2NvMRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEW MBQGA1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDA0MTExNjQyMjBaFw0yNDA0MDgx NjQyMjBaMH0xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYD VQQHDA1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQL DAtERVZfVEVTVElORzEWMBQGA1UEAwwNQ0ZTU0xfVEVTVF9DQTCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1CMS59jJOL omfDnKUWOGKi/k7URBg1HNL3vm7/ESDazZWFy9l/nibWxNkSUPkQIrvrGsNivkRU zXkwgNX8IN8LOYAQ3BWxAqitXTpLjf4FeCTB6G59v9eYlAX3kicXRdY+cqhEvLFb u3MCAwEAAaNQME4wHQYDVR0OBBYEFLhe765nULfW8wflar5Vs2c6DZI+MB8GA1Ud IwQYMBaAFLhe765nULfW8wflar5Vs2c6DZI+MAwGA1UdEwQFMAMBAf8wDQYJKoZI hvcNAQEFBQADgYEABYqqOUq3ZrtMYaTAoeA7Cr/OBMjBV+/TiOe8fRNoPZ7+aKSg E1baohCGqougm+/XOtBXeLv5tVQihz/2iKdwHmX4HjkxzevAXyazjxeW4IDA21Jl fKd7xUJHM0Du/opoDkXWr/vRVztOB33ndlAK7ruSLfTR3E9HoUe3aRH7ceQ= -----END CERTIFICATE----- ================================================ FILE: ubiquity/testdata/rsa2048sha2.pem ================================================ -----BEGIN CERTIFICATE----- MIIDfDCCAwKgAwIBAgIIUYJhG37C300wCgYIKoZIzj0EAwMwgYwxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAeFw0xNDA0MTEyMTIy MzhaFw0xOTA0MTEyMTI3MzhaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xv dWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEcMBoGA1UEAxMTY2xv dWRmbGFyZS1sZWFmLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANAukkrF37rHtiFfPuoUmKkj0HaEMGeQWEJ0sbispQKwqzF8fCRh6yT+j4+xsUZh +NL/bvVcGb3K0DpvMlE7swBH9ind7r15lSiW9r3NAaKbH5aUhDixLnXU0h5R4HVR 8paqW8we2a5sl17lk7UxRGhpj1VJlnDgTsuqXP+4Wb+x5E42hy0Lv7qIYnPzYztK CWmlMHbOprsEwjUpjL7b6D+dackCXrmY2CKFp57vvw27WWJh+OFWxw9FPrkjSi2W uG3lqg6uWQ8ELxFZLi6i999WsM4CH9GuG4T/rnNZHVl2fFfvGgW6rauoOqPR3a84 DUUfvUtxLxHpQq8blsPRUN0CAwEAAaOBgTB/MA4GA1UdDwEB/wQEAwIApDASBgNV HRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBShnoK2Oquaq/XjlNBMxs5yPTSJvjAf BgNVHSMEGDAWgBRB+YoiUjIm34/wBwHdJGE4Wufs/DAZBgNVHREEEjAQgg5jZnNz bC1sZWFmLmNvbTAKBggqhkjOPQQDAwNoADBlAjAhMWEJzBwuN5bVACPCAoVPSWI2 +0DQi4Tu6sBNQl+dsyO+FPyA3+aYc0NgnBwcj+0CMQC7JOdfdWJPZj6rOAXvGV3I jGJRHZmu5q5K+9teIK1b9mustpnDJgniKAHtBGecXy4= -----END CERTIFICATE----- ================================================ FILE: ubiquity/testdata/rsa3072sha2.pem ================================================ -----BEGIN CERTIFICATE----- MIID/DCCA4KgAwIBAgIIFVfMGJwEBdcwCgYIKoZIzj0EAwMwgYwxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAeFw0xNDA0MTEyMTIy MzhaFw0xOTA0MTEyMTI3MzhaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xv dWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEcMBoGA1UEAxMTY2xv dWRmbGFyZS1sZWFmLmNvbTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGB APcWAQ6FdrT8fJamf2x/8C76D7INfwl3pJ70XDbscNYLunNyCQaymZZBbYlOmPBQ A4lATlWm/2NHEP/RHXgdrKzx+DOSjYj3VmT4MQEVp0auRM/Kb1QEj9hNmcmtVJx+ YiQWrvHuksAZfFGl5xsHAPglL/hV3GbXaBYdC6rdwHSLUDpB1Y0hOgn4r+ZbEltI pDHKBxThzabOP/QOAP4K4k+ZUQ6kCMnDe1g9pOPmila3glsW0rXlN+ciAyVejxlL cPJONWqyfpMLsGDN/mJJUdA7I9EcV59O6C6p3+iHjVKIBoTVTu0by3aX764ZXrx1 V5pmI+NH5Bo1NeSpGTiooDMP4AyJyOknNo6fKD1/bY5GkGJBdrewFjqtNZYeU5Xj CKARVKlXMvl/6no5WtCWighMrf34j1KO/0oLnMhZfBqyn0nRC1DiseVa9mWePEEn yJV5XvrRrRQ9AGFLDtLndMHJVuQvoPBNu62k7keEWmTo/P6Zge1zQ7M8MUP/e3QU aQIDAQABo4GBMH8wDgYDVR0PAQH/BAQDAgCkMBIGA1UdEwEB/wQIMAYBAf8CAQEw HQYDVR0OBBYEFFRI3nOBTv9Gq7OQNv8dWdCiysNQMB8GA1UdIwQYMBaAFEH5iiJS Mibfj/AHAd0kYTha5+z8MBkGA1UdEQQSMBCCDmNmc3NsLWxlYWYuY29tMAoGCCqG SM49BAMDA2gAMGUCMQDAZV84hdNMZORoY35qBjTBSDfgZH2RN7EQHBr01G3rRfrr 0pfr7IGqmUfC8ca/Dc0CMDM0Gk9ulfiXhBg/Ewzpru8UVX6/hgbhPnH9GiGq/8XZ 5HC9JXjnDj10F8BHD11QzQ== -----END CERTIFICATE----- ================================================ FILE: ubiquity/testdata/rsa4096sha2.pem ================================================ -----BEGIN CERTIFICATE----- MIIEezCCBAKgAwIBAgIIZP3PePNium4wCgYIKoZIzj0EAwMwgYwxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y bmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAeFw0xNDA0MTEyMTIy MzhaFw0xOTA0MTEyMTI3MzhaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xv dWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMN U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEcMBoGA1UEAxMTY2xv dWRmbGFyZS1sZWFmLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB ALWN7ERQNnJsJuGxLbcdU1URDSZ3da3t34kfGHHFD3J5md7jWNbH52hIh307MZNd IWyzqNuHXmAGUgusOFtRKxmZzzttZE63ZSlMrJqn8C3Iyxr04+/9xyp26XxUMd7F fdfiJyORz9eNZp+/P2YMNtkmYs8rG59cdEKZ4yvVhWS3WOqO4TZAKedycfYPOT4k UTnC4fhB+ljJMVFCsfc4ntDD8nRZIgZUfpxmfUjuQxjyiRj1ZO2BeZ9l0DQVlF1K vnC6orAJEjqexQdQK8jIkAi1aehQE7fwkVwNDt3dIXfR4q5y1OkDH+koILmMxcP1 Y1hewKAnV4DYbQKPIQecEd/7KyJ0YQ89mCoXEwvBeoFBKwlymOkBfEFfCPB9dPw6 6djCcJcVtfQH5khaICLP2OSj59JDJnFIbTLTLcdcWttTnZm4A9L2zBROnKqCnUmH yJoSubSn2sYELv4z5bIQc7WKeo17ZX3GFUOK3JxzP4apuhyTuIYeeVOsK8Nzhr/x 0n8I7Ot6EiSYKi87PFllSSmoVqMwqLcgBqyBfv5gnLHIjJuzbFllrD4swdu+Zw1o dbeM4VKt1j+AOOpJWahdlLjQpMSbIeA4M/AtsTEXkZj5Azf4UxPYjjwLp5PMS9Xa raKC8Rkin6DuGC5QYBKmKLbaHRBRty1BMnKbOuZuHiAJAgMBAAGjgYEwfzAOBgNV HQ8BAf8EBAMCAKQwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUliwSq0YZ SDgIUZ7+1t5Ntzb8sYkwHwYDVR0jBBgwFoAUQfmKIlIyJt+P8AcB3SRhOFrn7Pww GQYDVR0RBBIwEIIOY2Zzc2wtbGVhZi5jb20wCgYIKoZIzj0EAwMDZwAwZAIwGTkD /FuSQ+VDGKZ8UM6kYAFS30rvi5/vScTIkAFmAISfyJF63Puk7gesDzkzV0uNAjAZ QPl9/aXIud70gp7SRmTEWtqc2sohR2UT2OBw6neTVxxM6GWZqAGTZCu7++Z2fDw= -----END CERTIFICATE----- ================================================ FILE: ubiquity/ubiquity_crypto.go ================================================ package ubiquity // In this file, we mainly cover crypto ubiquity. import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" "crypto/x509" "math" "github.com/cloudflare/cfssl/helpers" ) // HashUbiquity represents a score for how ubiquitous a given hash // algorithm is; the higher the score, the more preferable the algorithm // is. type HashUbiquity int // KeyAlgoUbiquity represents a score for how ubiquitous a given // public-key algorithm is; the higher the score, the more preferable // the algorithm is. type KeyAlgoUbiquity int // SHA1 is ubiquitous. SHA2 is not supported on some legacy platforms. // We consider MD2/MD5 is harmful and thus assign them lowest ubiquity. const ( UnknownHashUbiquity HashUbiquity = 0 SHA2Ubiquity HashUbiquity = 70 SHA1Ubiquity HashUbiquity = 100 MD5Ubiquity HashUbiquity = 0 MD2Ubiquity HashUbiquity = 0 ) // RSA and DSA are considered ubiquitous. ECDSA256 and ECDSA384 should be // supported by TLS 1.2 and have limited support from TLS 1.0 and // 1.1, based on RFC6460, but ECDSA521 is less well-supported as // a standard. const ( RSAUbiquity KeyAlgoUbiquity = 100 DSAUbiquity KeyAlgoUbiquity = 100 ECDSA256Ubiquity KeyAlgoUbiquity = 70 ECDSA384Ubiquity KeyAlgoUbiquity = 70 ECDSA521Ubiquity KeyAlgoUbiquity = 30 UnknownAlgoUbiquity KeyAlgoUbiquity = 0 ) // hashUbiquity computes the ubiquity of the hash algorithm in the // signature algorithm of a cert. // SHA1 > SHA2 > MD > Others func hashUbiquity(cert *x509.Certificate) HashUbiquity { switch cert.SignatureAlgorithm { case x509.ECDSAWithSHA1, x509.DSAWithSHA1, x509.SHA1WithRSA: return SHA1Ubiquity case x509.ECDSAWithSHA256, x509.ECDSAWithSHA384, x509.ECDSAWithSHA512, x509.DSAWithSHA256, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA: return SHA2Ubiquity case x509.MD5WithRSA, x509.MD2WithRSA: return MD5Ubiquity default: return UnknownHashUbiquity } } // keyAlgoUbiquity compute the ubiquity of the cert's public key algorithm // RSA, DSA>ECDSA>Unknown func keyAlgoUbiquity(cert *x509.Certificate) KeyAlgoUbiquity { switch cert.PublicKeyAlgorithm { case x509.ECDSA: switch cert.PublicKey.(*ecdsa.PublicKey).Curve { case elliptic.P256(): return ECDSA256Ubiquity case elliptic.P384(): return ECDSA384Ubiquity case elliptic.P521(): return ECDSA521Ubiquity default: return UnknownAlgoUbiquity } case x509.RSA: if cert.PublicKey.(*rsa.PublicKey).N.BitLen() >= 1024 { return RSAUbiquity } return UnknownAlgoUbiquity case x509.DSA: return DSAUbiquity default: return UnknownAlgoUbiquity } } // ChainHashUbiquity scores a chain based on the hash algorithms used // by the certificates in the chain. func ChainHashUbiquity(chain []*x509.Certificate) HashUbiquity { ret := math.MaxInt32 for _, cert := range chain { uscore := int(hashUbiquity(cert)) if ret > uscore { ret = uscore } } return HashUbiquity(ret) } // ChainKeyAlgoUbiquity scores a chain based on the public-key algorithms // used by the certificates in the chain. func ChainKeyAlgoUbiquity(chain []*x509.Certificate) KeyAlgoUbiquity { ret := math.MaxInt32 for _, cert := range chain { uscore := int(keyAlgoUbiquity(cert)) if ret > uscore { ret = uscore } } return KeyAlgoUbiquity(ret) } // CompareChainHashUbiquity returns a positive, zero, or negative value // if the hash ubiquity of the first chain is greater, equal, or less // than the second chain. func CompareChainHashUbiquity(chain1, chain2 []*x509.Certificate) int { hu1 := ChainHashUbiquity(chain1) hu2 := ChainHashUbiquity(chain2) return int(hu1) - int(hu2) } // CompareChainKeyAlgoUbiquity returns a positive, zero, or negative value // if the public-key ubiquity of the first chain is greater, equal, // or less than the second chain. func CompareChainKeyAlgoUbiquity(chain1, chain2 []*x509.Certificate) int { kau1 := ChainKeyAlgoUbiquity(chain1) kau2 := ChainKeyAlgoUbiquity(chain2) return int(kau1) - int(kau2) } // CompareExpiryUbiquity ranks two certificate chains based on the expiry dates of intermediates and roots. // Certs expire later are ranked higher than ones expire earlier. The ranking between chains are determined by // the first pair of intermediates, scanned from the root level, that are ranked differently. func CompareExpiryUbiquity(chain1, chain2 []*x509.Certificate) int { for i := 0; ; i++ { if i >= len(chain1) || i >= len(chain2) { break } c1 := chain1[len(chain1)-1-i] c2 := chain2[len(chain2)-1-i] t1 := c1.NotAfter t2 := c2.NotAfter // Check if expiry dates valid. Return if one or other is invalid. // Otherwise rank by expiry date. Later is ranked higher. c1Valid := helpers.ValidExpiry(c1) c2Valid := helpers.ValidExpiry(c2) if c1Valid && !c2Valid { return 1 } if !c1Valid && c2Valid { return -1 } r := compareTime(t1, t2) // Return when we find rank difference. if r != 0 { return r } } return 0 } ================================================ FILE: ubiquity/ubiquity_platform.go ================================================ package ubiquity // This is for cross-platform ubiquity. Basically, here we deal with issues about whether a cert chain // is acceptable for different platforms, including desktop and mobile ones., and about how to compare // two chains under the context of cross-platform ubiquity. import ( "crypto/sha1" "crypto/x509" "encoding/json" "fmt" "os" "path" "path/filepath" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/log" ) // SHA1RawPublicKey returns a SHA1 hash of the raw certificate public key func SHA1RawPublicKey(cert *x509.Certificate) string { return fmt.Sprintf("%x", sha1.Sum(cert.RawSubjectPublicKeyInfo)) } // CertSet is a succint set of x509 certificates which only stores certificates' SHA1 hashes. type CertSet map[string]bool // Lookup returns whether a certificate is stored in the set. func (s CertSet) Lookup(cert *x509.Certificate) bool { return s[SHA1RawPublicKey(cert)] } // Add adds a certificate to the set. func (s CertSet) Add(cert *x509.Certificate) { s[SHA1RawPublicKey(cert)] = true } // A Platform contains ubiquity information on supported crypto algorithms and root certificate store name. type Platform struct { Name string `json:"name"` Weight int `json:"weight"` HashAlgo string `json:"hash_algo"` KeyAlgo string `json:"key_algo"` KeyStoreFile string `json:"keystore"` KeyStore CertSet HashUbiquity HashUbiquity KeyAlgoUbiquity KeyAlgoUbiquity } // Trust returns whether the platform has the root cert in the trusted store. func (p Platform) Trust(root *x509.Certificate) bool { // the key store is empty iff the platform doesn't carry a root store and trust whatever root store // is supplied. An example is Chrome. Such platforms should not show up in the untrusted platform // list. So always return true here. Also this won't hurt ubiquity scoring because such platforms give // no differentiation on root cert selection. if len(p.KeyStore) == 0 { return true } return p.KeyStore.Lookup(root) } func (p Platform) hashUbiquity() HashUbiquity { switch p.HashAlgo { case "SHA1": return SHA1Ubiquity case "SHA2": return SHA2Ubiquity default: return UnknownHashUbiquity } } func (p Platform) keyAlgoUbiquity() KeyAlgoUbiquity { switch p.KeyAlgo { case "RSA": return RSAUbiquity case "ECDSA256": return ECDSA256Ubiquity case "ECDSA384": return ECDSA384Ubiquity case "ECDSA521": return ECDSA521Ubiquity default: return UnknownAlgoUbiquity } } // ParseAndLoad converts HashAlgo and KeyAlgo to corresponding ubiquity value and load // certificates into internal KeyStore from KeyStoreFiles func (p *Platform) ParseAndLoad() (ok bool) { p.HashUbiquity = p.hashUbiquity() p.KeyAlgoUbiquity = p.keyAlgoUbiquity() p.KeyStore = map[string]bool{} if p.KeyStoreFile != "" { pemBytes, err := os.ReadFile(p.KeyStoreFile) if err != nil { log.Error(err) return false } // Best effort parsing the PEMs such that ignore all borken pem, // since some of CA certs have negative serial number which trigger errors. for len(pemBytes) > 0 { var certs []*x509.Certificate certs, rest, err := helpers.ParseOneCertificateFromPEM(pemBytes) // If one certificate object is parsed, possibly a PKCS#7 // structure containing multiple certs, record the raw SHA1 hash(es). if err == nil && certs != nil { for _, cert := range certs { p.KeyStore.Add(cert) } } if len(rest) < len(pemBytes) { pemBytes = rest } else { // No progress in bytes parsing, bail out. break } } } if p.HashUbiquity <= UnknownHashUbiquity || p.KeyAlgoUbiquity <= UnknownAlgoUbiquity { return false } return true } // Platforms is the list of platforms against which ubiquity bundling will be optimized. var Platforms []Platform // LoadPlatforms reads the file content as a json object array and convert it // to Platforms. func LoadPlatforms(filename string) error { // if filename is empty, skip the metadata loading if filename == "" { return nil } relativePath := filepath.Dir(filename) // Attempt to load root certificate metadata log.Debug("Loading platform metadata: ", filename) bytes, err := os.ReadFile(filename) if err != nil { return fmt.Errorf("platform metadata failed to load: %v", err) } var rawPlatforms []Platform if bytes != nil { err = json.Unmarshal(bytes, &rawPlatforms) if err != nil { return fmt.Errorf("platform metadata failed to parse: %v", err) } } for _, platform := range rawPlatforms { if platform.KeyStoreFile != "" { platform.KeyStoreFile = path.Join(relativePath, platform.KeyStoreFile) } ok := platform.ParseAndLoad() if !ok { // erase all loaded platforms Platforms = nil return fmt.Errorf("fail to finalize the parsing of platform metadata: %v", platform) } log.Infof("Platform metadata is loaded: %v %v", platform.Name, len(platform.KeyStore)) Platforms = append(Platforms, platform) } return nil } // UntrustedPlatforms returns a list of platforms which don't trust the root certificate. func UntrustedPlatforms(root *x509.Certificate) []string { ret := []string{} for _, platform := range Platforms { if !platform.Trust(root) { ret = append(ret, platform.Name) } } return ret } // CrossPlatformUbiquity returns a ubiquity score (presumably relecting the market share in percentage) // based on whether the given chain can be verified with the different platforms' root certificate stores. func CrossPlatformUbiquity(chain []*x509.Certificate) int { // There is no root store info, every chain is equal weighted as 0. if len(Platforms) == 0 { return 0 } totalWeight := 0 // A chain is viable with the platform if // 1. the root is in the platform's root store // 2. the chain satisfy the minimal constraints on hash function and key algorithm. root := chain[len(chain)-1] for _, platform := range Platforms { if platform.Trust(root) { switch { case platform.HashUbiquity <= ChainHashUbiquity(chain) && platform.KeyAlgoUbiquity <= ChainKeyAlgoUbiquity(chain): totalWeight += platform.Weight } } } return totalWeight } // ComparePlatformUbiquity compares the cross-platform ubiquity between chain1 and chain2. func ComparePlatformUbiquity(chain1, chain2 []*x509.Certificate) int { w1 := CrossPlatformUbiquity(chain1) w2 := CrossPlatformUbiquity(chain2) return w1 - w2 } // SHA2Homogeneity returns 1 if the chain contains only SHA-2 certs (excluding root). Otherwise it returns 0. func SHA2Homogeneity(chain []*x509.Certificate) int { for i := 0; i < len(chain)-1; i++ { if hashUbiquity(chain[i]) != SHA2Ubiquity { return 0 } } return 1 } // CompareSHA2Homogeneity compares the chains based on SHA2 homogeneity. Full SHA-2 chain (excluding root) is rated higher that the rest. func CompareSHA2Homogeneity(chain1, chain2 []*x509.Certificate) int { w1 := SHA2Homogeneity(chain1) w2 := SHA2Homogeneity(chain2) return w1 - w2 } ================================================ FILE: ubiquity/ubiquity_test.go ================================================ package ubiquity import ( "crypto/x509" "fmt" "os" "testing" "time" "github.com/cloudflare/cfssl/helpers" ) const ( rsa1024 = "testdata/rsa1024sha1.pem" rsa2048 = "testdata/rsa2048sha2.pem" rsa3072 = "testdata/rsa3072sha2.pem" rsa4096 = "testdata/rsa4096sha2.pem" ecdsa256 = "testdata/ecdsa256sha2.pem" ecdsa384 = "testdata/ecdsa384sha2.pem" ecdsa521 = "testdata/ecdsa521sha2.pem" caMetadata = "testdata/ca.pem.metadata" ) var rsa1024Cert, rsa2048Cert, rsa3072Cert, rsa4096Cert, ecdsa256Cert, ecdsa384Cert, ecdsa521Cert *x509.Certificate func readCert(filename string) *x509.Certificate { bytes, _ := os.ReadFile(filename) cert, _ := helpers.ParseCertificatePEM(bytes) return cert } func init() { rsa1024Cert = readCert(rsa1024) rsa2048Cert = readCert(rsa2048) rsa3072Cert = readCert(rsa3072) rsa4096Cert = readCert(rsa4096) ecdsa256Cert = readCert(ecdsa256) ecdsa384Cert = readCert(ecdsa384) ecdsa521Cert = readCert(ecdsa521) } func TestCertHashPriority(t *testing.T) { if hashPriority(rsa1024Cert) > hashPriority(rsa2048Cert) { t.Fatal("Incorrect hash priority") } if hashPriority(rsa2048Cert) > hashPriority(rsa3072Cert) { t.Fatal("Incorrect hash priority") } if hashPriority(rsa3072Cert) > hashPriority(rsa4096Cert) { t.Fatal("Incorrect hash priority") } if hashPriority(rsa4096Cert) > hashPriority(ecdsa256Cert) { t.Fatal("Incorrect hash priority") } if hashPriority(ecdsa256Cert) > hashPriority(ecdsa384Cert) { t.Fatal("Incorrect hash priority") } if hashPriority(ecdsa384Cert) > hashPriority(ecdsa256Cert) { t.Fatal("Incorrect hash priority") } } func TestCertKeyAlgoPriority(t *testing.T) { if keyAlgoPriority(rsa2048Cert) > keyAlgoPriority(rsa3072Cert) { t.Fatal("Incorrect hash priority") } if keyAlgoPriority(rsa3072Cert) > keyAlgoPriority(rsa4096Cert) { t.Fatal("Incorrect hash priority") } if keyAlgoPriority(rsa4096Cert) > keyAlgoPriority(ecdsa256Cert) { t.Fatal("Incorrect hash priority") } if keyAlgoPriority(ecdsa256Cert) > keyAlgoPriority(ecdsa384Cert) { t.Fatal("Incorrect hash priority") } if keyAlgoPriority(ecdsa384Cert) > keyAlgoPriority(ecdsa521Cert) { t.Fatal("Incorrect hash priority") } } func TestChainHashPriority(t *testing.T) { var chain []*x509.Certificate var p int chain = []*x509.Certificate{rsa2048Cert, rsa3072Cert} p = HashPriority(chain) if p != (hashPriority(rsa2048Cert)+hashPriority(rsa3072Cert))/2 { t.Fatal("Incorrect chain hash priority") } } func TestChainKeyAlgoPriority(t *testing.T) { var chain []*x509.Certificate var p int chain = []*x509.Certificate{rsa2048Cert, rsa3072Cert} p = KeyAlgoPriority(chain) if p != (keyAlgoPriority(rsa2048Cert)+keyAlgoPriority(rsa3072Cert))/2 { t.Fatal("Incorrect chain key algo priority") } } func TestCertHashUbiquity(t *testing.T) { if hashUbiquity(rsa2048Cert) != SHA2Ubiquity { t.Fatal("incorrect hash ubiquity") } if hashUbiquity(rsa3072Cert) != SHA2Ubiquity { t.Fatal("incorrect hash ubiquity") } if hashUbiquity(rsa4096Cert) != SHA2Ubiquity { t.Fatal("incorrect hash ubiquity") } if hashUbiquity(rsa2048Cert) < hashUbiquity(rsa3072Cert) { t.Fatal("incorrect hash ubiquity") } if hashUbiquity(rsa3072Cert) < hashUbiquity(rsa4096Cert) { t.Fatal("Incorrect hash ubiquity") } if hashUbiquity(rsa4096Cert) < hashUbiquity(ecdsa256Cert) { t.Fatal("Incorrect hash ubiquity") } if hashUbiquity(ecdsa256Cert) < hashUbiquity(ecdsa384Cert) { t.Fatal("Incorrect hash ubiquity") } if hashUbiquity(ecdsa384Cert) < hashUbiquity(ecdsa256Cert) { t.Fatal("Incorrect hash ubiquity") } } func TestCertKeyAlgoUbiquity(t *testing.T) { if keyAlgoUbiquity(rsa2048Cert) != RSAUbiquity { t.Fatal("incorrect hash ubiquity") } if keyAlgoUbiquity(rsa3072Cert) != RSAUbiquity { t.Fatal("incorrect hash ubiquity") } if keyAlgoUbiquity(rsa4096Cert) != RSAUbiquity { t.Fatal("incorrect hash ubiquity") } if keyAlgoUbiquity(ecdsa256Cert) != ECDSA256Ubiquity { t.Fatal("incorrect hash ubiquity") } if keyAlgoUbiquity(ecdsa384Cert) != ECDSA384Ubiquity { t.Fatal("incorrect hash ubiquity") } if keyAlgoUbiquity(ecdsa521Cert) != ECDSA521Ubiquity { t.Fatal("incorrect hash ubiquity") } if keyAlgoUbiquity(rsa2048Cert) < keyAlgoUbiquity(rsa3072Cert) { t.Fatal("incorrect hash ubiquity") } if keyAlgoUbiquity(rsa3072Cert) < keyAlgoUbiquity(rsa4096Cert) { t.Fatal("Incorrect hash ubiquity") } if keyAlgoUbiquity(rsa4096Cert) < keyAlgoUbiquity(ecdsa256Cert) { t.Fatal("Incorrect hash ubiquity") } if keyAlgoUbiquity(ecdsa256Cert) < keyAlgoUbiquity(ecdsa384Cert) { t.Fatal("Incorrect hash ubiquity") } if keyAlgoUbiquity(ecdsa384Cert) < keyAlgoUbiquity(ecdsa256Cert) { t.Fatal("Incorrect hash ubiquity") } } func TestChainHashUbiquity(t *testing.T) { chain := []*x509.Certificate{rsa1024Cert, rsa2048Cert} if ChainHashUbiquity(chain) != hashUbiquity(rsa2048Cert) { t.Fatal("Incorrect chain hash ubiquity") } } func TestChainKeyAlgoUbiquity(t *testing.T) { chain := []*x509.Certificate{rsa1024Cert, rsa2048Cert} if ChainKeyAlgoUbiquity(chain) != keyAlgoUbiquity(rsa2048Cert) { t.Fatal("Incorrect chain hash ubiquity") } chain = []*x509.Certificate{ecdsa256Cert, rsa2048Cert} if ChainKeyAlgoUbiquity(chain) != keyAlgoUbiquity(ecdsa256Cert) { t.Fatal("Incorrect chain hash ubiquity") } } func TestChainExpiryUbiquity(t *testing.T) { // rsa1024Cert expires at year 2024 // rsa2048Cert expires at year 2019 // ecdsa256Cert expires at year 2019 chain1 := []*x509.Certificate{ecdsa256Cert, rsa2048Cert} chain2 := []*x509.Certificate{ecdsa256Cert, rsa1024Cert} // CompareExpiryUbiquity should return < 0 because chain1 // has a worse expiry ubiquity than chain2. if CompareExpiryUbiquity(chain1, chain2) < 0 { t.Fatal("Incorrect chain expiry ubiquity") } // CompareExpiryUbiquity should return > 0 because chain2 has // a better expiry ubiquity than chain1. if CompareExpiryUbiquity(chain2, chain1) > 0 { t.Fatal("Incorrect chain expiry ubiquity") } if CompareExpiryUbiquity(chain1, chain1) != 0 { t.Fatal("Incorrect chain expiry ubiquity") } } func TestCompareChainExpiry(t *testing.T) { // rsa1024Cert expires at 2024 // rsa2048Cert expires at 2019 // ecdsa256Cert expires at 2019 // both chain expires at year 2019. chain1 := []*x509.Certificate{ecdsa256Cert, rsa2048Cert} chain2 := []*x509.Certificate{ecdsa256Cert, rsa1024Cert} if CompareChainExpiry(chain1, chain2) != 0 { t.Fatal("Incorrect chain expiry") } if CompareExpiryUbiquity(chain1, chain1) != 0 { t.Fatal("Incorrect chain expiry") } } func TestCompareChainLength(t *testing.T) { chain1 := []*x509.Certificate{ecdsa256Cert, rsa2048Cert} chain2 := []*x509.Certificate{rsa1024Cert} chain3 := []*x509.Certificate{rsa2048Cert} // longer chain is ranked lower if CompareChainLength(chain1, chain2) >= 0 { t.Fatal("Incorrect chain length comparison") } if CompareChainLength(chain2, chain3) != 0 { t.Fatal("Incorrect chain length comparison") } } func TestPlatformKeyStoreUbiquity(t *testing.T) { cert1 := rsa1024Cert cert2 := rsa2048Cert cert3 := ecdsa256Cert // load Platforms with test data // "Macrosoft" has all three certs. // "Godzilla" has two certs, cert1 and cert2. // "Pineapple" has cert1. // "Colorful" has no key store data, default to trust any cert // All platforms support the same crypto suite. platformA := Platform{Name: "MacroSoft", Weight: 100, HashAlgo: "SHA2", KeyAlgo: "ECDSA256", KeyStoreFile: "testdata/macrosoft.pem"} platformB := Platform{Name: "Godzilla", Weight: 100, HashAlgo: "SHA2", KeyAlgo: "ECDSA256", KeyStoreFile: "testdata/godzilla.pem"} platformC := Platform{Name: "Pineapple", Weight: 100, HashAlgo: "SHA2", KeyAlgo: "ECDSA256", KeyStoreFile: "testdata/pineapple.pem"} platformD := Platform{Name: "Colorful", Weight: 100, HashAlgo: "SHA2", KeyAlgo: "ECDSA256", KeyStoreFile: ""} platformA.ParseAndLoad() platformB.ParseAndLoad() platformC.ParseAndLoad() platformD.ParseAndLoad() Platforms = []Platform{platformA, platformB, platformC, platformD} // chain1 with root cert1 (RSA1024, SHA1), has the largest platform coverage. // chain2 with root cert2 (RSA2048, SHA2), has the second largest coverage. // chain3 with root cert3 (ECDSA256, SHA2), has the least coverage. chain1 := []*x509.Certificate{cert1} chain2 := []*x509.Certificate{cert1, cert2} chain3 := []*x509.Certificate{cert1, cert2, cert3} if CrossPlatformUbiquity(chain1) < CrossPlatformUbiquity(chain2) { t.Fatal("Incorrect cross platform ubiquity") } if CrossPlatformUbiquity(chain2) < CrossPlatformUbiquity(chain3) { t.Fatal("Incorrect cross platform ubiquity") } if ComparePlatformUbiquity(chain1, chain2) < 0 { t.Fatal("Incorrect cross platform ubiquity") } if ComparePlatformUbiquity(chain2, chain3) < 0 { t.Fatal("Incorrect cross platform ubiquity") } // test UntrustedPlatforms() u1 := UntrustedPlatforms(cert1) if len(u1) != 0 { t.Fatal("Incorrect UntrustedPlatforms") } u2 := UntrustedPlatforms(cert2) if len(u2) != 1 { t.Fatal("Incorrect UntrustedPlatforms") } u3 := UntrustedPlatforms(cert3) if len(u3) != 2 { t.Fatal("Incorrect UntrustedPlatforms") } } func TestEmptyPlatformList(t *testing.T) { Platforms = []Platform{} cert := rsa1024Cert chain := []*x509.Certificate{cert} if CrossPlatformUbiquity(chain) != 0 { t.Fatal("Incorrect cross platform ubiquity when Platforms is empty") } // test UntrustedPlatforms() u1 := UntrustedPlatforms(cert) if len(u1) != 0 { t.Fatal("Incorrect UntrustedPlatforms when Platforms is empty") } } func TestLoadPlatforms(t *testing.T) { err := LoadPlatforms(caMetadata) if err != nil { t.Fatal(err) } } func TestPlatformCryptoUbiquity(t *testing.T) { cert1 := rsa1024Cert cert2 := rsa2048Cert cert3 := ecdsa256Cert // load Platforms with test data // All platforms have the same trust store but are with various crypto suite. platformA := Platform{Name: "TinySoft", Weight: 100, HashAlgo: "SHA1", KeyAlgo: "RSA", KeyStoreFile: "testdata/macrosoft.pem"} platformB := Platform{Name: "SmallSoft", Weight: 100, HashAlgo: "SHA2", KeyAlgo: "RSA", KeyStoreFile: "testdata/macrosoft.pem"} platformC := Platform{Name: "LargeSoft", Weight: 100, HashAlgo: "SHA2", KeyAlgo: "ECDSA256", KeyStoreFile: "testdata/macrosoft.pem"} platformD := Platform{Name: "MediumSoft", Weight: 100, HashAlgo: "SHA2", KeyAlgo: "ECDSA384", KeyStoreFile: "testdata/macrosoft.pem"} platformA.ParseAndLoad() platformB.ParseAndLoad() platformC.ParseAndLoad() platformD.ParseAndLoad() Platforms = []Platform{platformA, platformB, platformC} // chain1 with root cert1 (RSA1024, SHA1), has the largest platform coverage. // chain2 with root cert2 (RSA2048, SHA2), has the second largest coverage. // chain3 with root cert3 (ECDSA256, SHA2), has the least coverage. chain1 := []*x509.Certificate{cert1} chain2 := []*x509.Certificate{cert1, cert2} chain3 := []*x509.Certificate{cert1, cert2, cert3} if CrossPlatformUbiquity(chain1) < CrossPlatformUbiquity(chain2) { t.Fatal("Incorrect cross platform ubiquity") } if CrossPlatformUbiquity(chain2) < CrossPlatformUbiquity(chain3) { t.Fatal("Incorrect cross platform ubiquity") } if ComparePlatformUbiquity(chain1, chain2) < 0 { t.Fatal("Incorrect cross platform ubiquity") } if ComparePlatformUbiquity(chain1, chain2) < 0 { t.Fatal("Incorrect cross platform ubiquity") } } func TestSHA2Homogeneity(t *testing.T) { // root-only chain is always SHA2-Homogeneous. chain0 := []*x509.Certificate{rsa1024Cert} if SHA2Homogeneity(chain0) != 1 { t.Fatal("SHA2Homogeneity(chain0) != 1") } chain1 := []*x509.Certificate{rsa1024Cert, rsa2048Cert, rsa1024Cert} if SHA2Homogeneity(chain1) != 0 { t.Fatal("SHA2Homogeneity(chain1) != 0") } chain2 := []*x509.Certificate{rsa2048Cert, rsa2048Cert, rsa1024Cert} if SHA2Homogeneity(chain2) != 1 { t.Fatal("SHA2Homogeneity(chain2) != 1") } chain3 := []*x509.Certificate{ecdsa256Cert, rsa2048Cert, rsa1024Cert} if SHA2Homogeneity(chain3) != 1 { t.Fatal("SHA2Homogeneity(chain3) != 1") } chain4 := []*x509.Certificate{ecdsa256Cert, ecdsa384Cert, rsa1024Cert} if SHA2Homogeneity(chain4) != 1 { t.Fatal("SHA2Homogeneity(chain4) != 1") } } func TestCompareSHA2Homogeneity(t *testing.T) { chain1 := []*x509.Certificate{rsa1024Cert, rsa2048Cert, rsa1024Cert} chain2 := []*x509.Certificate{rsa2048Cert, rsa2048Cert, rsa1024Cert} chain3 := []*x509.Certificate{ecdsa256Cert, rsa2048Cert, rsa1024Cert} chain4 := []*x509.Certificate{ecdsa256Cert, ecdsa384Cert, rsa1024Cert} if CompareSHA2Homogeneity(chain1, chain2) >= 0 { t.Fatal("CompareSHA2Homogeneity(chain1, chain2) >= 0") } if CompareSHA2Homogeneity(chain1, chain3) >= 0 { t.Fatal("CompareSHA2Homogeneity(chain1, chain3) >= 0") } if CompareSHA2Homogeneity(chain1, chain4) >= 0 { t.Fatal("CompareSHA2Homogeneity(chain1, chain4) >= 0") } if CompareSHA2Homogeneity(chain2, chain3) != 0 || CompareSHA2Homogeneity(chain3, chain4) != 0 { t.Fatal("CompareSHA2Homogeneity failed.") } } func TestFilterTrivial(t *testing.T) { var chain []*x509.Certificate var chains [][]*x509.Certificate ret := Filter(chains, CompareChainHashPriority) if len(ret) != 0 { t.Fatal("Incorrect filtering") } chain = []*x509.Certificate{rsa2048Cert} chains = [][]*x509.Certificate{chain} ret = Filter(chains, CompareChainHashPriority) if len(ret) != 1 { t.Fatal("Incorrect filtering") } } func TestFilterChainHashPriority(t *testing.T) { var chain1, chain2 []*x509.Certificate chain1 = []*x509.Certificate{rsa2048Cert} // SHA256 chain2 = []*x509.Certificate{ecdsa384Cert} // SHA384 // SHA256 <= SHA384 if CompareChainHashPriority(chain1, chain2) > 0 { t.Fatal("Incorrect chain hash priority comparison") } chains := [][]*x509.Certificate{chain2, chain1} ret := Filter(chains, CompareChainHashPriority) // check there is no reordering if ret[0][0] != ecdsa384Cert { t.Fatal("Incorrect chain hash priority filtering") } } func TestFilterChainKeyAlgoPriority(t *testing.T) { var chain1, chain2 []*x509.Certificate chain1 = []*x509.Certificate{rsa2048Cert} // RSA chain2 = []*x509.Certificate{ecdsa384Cert} // ECDSA // RSA <= ECDSA if CompareChainKeyAlgoPriority(chain1, chain2) >= 0 { t.Fatal("Incorrect chain key algo priority comparison") } chains := [][]*x509.Certificate{chain1, chain2} ret := Filter(chains, CompareChainKeyAlgoPriority) // check there is reordering if ret[0][0] != ecdsa384Cert { t.Fatal("Incorrect chain key algo priority filtering") } } func TestFilterChainCipherSuite(t *testing.T) { var chain1, chain2 []*x509.Certificate chain1 = []*x509.Certificate{rsa2048Cert} chain2 = []*x509.Certificate{ecdsa384Cert} // RSA2048 < ECDSA384 if CompareChainCryptoSuite(chain1, chain2) >= 0 { t.Fatal("Incorrect chain key algo priority comparison") } chains := [][]*x509.Certificate{chain1, chain2} ret := Filter(chains, CompareChainCryptoSuite) // check there is reordering if ret[0][0] != ecdsa384Cert { t.Fatal("Incorrect chain key algo priority filtering") } } func TestFilterChainHashUbiquity(t *testing.T) { var chain1, chain2 []*x509.Certificate chain1 = []*x509.Certificate{rsa2048Cert} // SHA256 chain2 = []*x509.Certificate{ecdsa384Cert} // SHA384 // SHA256 == SHA384 if CompareChainHashUbiquity(chain1, chain2) != 0 { t.Fatal("Incorrect chain hash priority comparison") } chains := [][]*x509.Certificate{chain2, chain1} ret := Filter(chains, CompareChainHashUbiquity) // check there is no reordering if ret[0][0] != ecdsa384Cert { t.Fatal("Incorrect chain hash priority filtering") } } func TestFilterChainKeyAlgoUbiquity(t *testing.T) { var chain1, chain2 []*x509.Certificate chain1 = []*x509.Certificate{rsa2048Cert} // RSA chain2 = []*x509.Certificate{ecdsa384Cert} // ECDSA // RSA >= ECDSA if CompareChainKeyAlgoUbiquity(chain1, chain2) < 0 { t.Fatal("Incorrect chain key algo priority comparison") } chains := [][]*x509.Certificate{chain1, chain2} ret := Filter(chains, CompareChainKeyAlgoUbiquity) // check there is no reordering if ret[0][0] != rsa2048Cert { t.Fatal("Incorrect chain key algo priority filtering") } } func TestFlagBySHA1DeprecationPolicy(t *testing.T) { cert1 := rsa1024Cert cert2 := rsa2048Cert Jan1st2014 := time.Date(2014, time.January, 1, 0, 0, 0, 0, time.UTC) Jan1st2100 := time.Date(2100, time.January, 1, 0, 0, 0, 0, time.UTC) policy1 := SHA1DeprecationPolicy{ Description: "SHA1 should be gone years ago", ExpiryDeadline: Jan1st2014, } policy2 := SHA1DeprecationPolicy{ Description: "SHA1 is perfect for another century", ExpiryDeadline: Jan1st2100, } policy3 := SHA1DeprecationPolicy{ Description: "effectively one century later, reject SHA1 expires on 2014", EffectiveDate: Jan1st2100, ExpiryDeadline: Jan1st2014, } policy4 := SHA1DeprecationPolicy{ Description: "no more new SHA1 cert", NeverIssueAfter: Jan1st2014, } // chain1 is accepted univerally. It's not flagged because root cert is not subject to SHA1 deprecation. chain1 := []*x509.Certificate{cert1} if policy1.Flag(chain1) || policy2.Flag(chain1) || policy3.Flag(chain1) || policy4.Flag(chain1) { t.Fatal("Incorrect SHA1 deprecation") } // chain2 is accepted by policy2 and policy3. It's flagged by policy1 and policy4 chain2 := []*x509.Certificate{cert1, cert1} if !policy1.Flag(chain2) || policy2.Flag(chain2) || policy3.Flag(chain2) || !policy4.Flag(chain2) { t.Fatal("Incorrect SHA1 deprecation") } // chain3 is accepted by universally since the leaf cert and the intermediate are signed by SHA-256 chain3 := []*x509.Certificate{cert2, cert2, cert1} if policy1.Flag(chain3) || policy2.Flag(chain3) || policy3.Flag(chain3) || policy4.Flag(chain3) { t.Fatal("Incorrect SHA1 deprecation") } } func TestSHA1DeprecationMessages(t *testing.T) { cert1 := rsa1024Cert cert2 := rsa2048Cert chain1 := []*x509.Certificate{cert1} chain2 := []*x509.Certificate{cert1, cert1} chain3 := []*x509.Certificate{cert2, cert1, cert1} chain4 := []*x509.Certificate{cert2, cert2, cert1} var messages []string Jan1st2014 := time.Date(2014, time.January, 1, 0, 0, 0, 0, time.UTC) Jan1st2100 := time.Date(2100, time.January, 1, 0, 0, 0, 0, time.UTC) policy1 := SHA1DeprecationPolicy{ Platform: "Browser A", Description: "minor warning", Severity: Low, ExpiryDeadline: Jan1st2014, } policy2 := SHA1DeprecationPolicy{ Platform: "Browser A", Description: "minor warning", Severity: Medium, ExpiryDeadline: Jan1st2014, } policy3 := SHA1DeprecationPolicy{ Platform: "Browser B", Description: "reject", Severity: High, NeverIssueAfter: Jan1st2014, } policy4 := SHA1DeprecationPolicy{ Platform: "Browser C", Description: "reject but not now", Severity: High, NeverIssueAfter: Jan1st2014, EffectiveDate: Jan1st2100, } // The only policy has severity low SHA1DeprecationPolicys = []SHA1DeprecationPolicy{policy1} messages = SHA1DeprecationMessages(chain1) // chain1 with only root is not subject to deprecation if len(messages) != 0 { t.Fatal("Incorrect SHA1 deprecation reporting") } // chain2 has SHA-1 leaf cert, subject to deprecation messages = SHA1DeprecationMessages(chain2) if len(messages) != 1 { t.Fatal("Incorrect SHA1 deprecation reporting") } // chain3 has SHA-1 intermediate cert, subject to deprecation messages = SHA1DeprecationMessages(chain3) if len(messages) != 1 { t.Fatal("Incorrect SHA1 deprecation reporting") } // chain4 has no SHA-1 leaf or intermediate, not subject to deprecation messages = SHA1DeprecationMessages(chain4) if len(messages) != 0 { t.Fatal("Incorrect SHA1 deprecation reporting") } // A second policy that has higher severity , so it should takes effect and override lower one. SHA1DeprecationPolicys = []SHA1DeprecationPolicy{policy1, policy2} // chain1 only has root cert, not subject to deprecation policy messages = SHA1DeprecationMessages(chain1) if len(messages) != 0 { t.Fatal("Incorrect SHA1 deprecation reporting") } // chain2 has a SHA-1 leaf cert, will have a message from policy2 messages = SHA1DeprecationMessages(chain2) if len(messages) != 1 || messages[0] != fmt.Sprintf("%s %s due to SHA-1 deprecation", policy2.Platform, policy2.Description) { t.Fatal("Incorrect SHA1 deprecation reporting") } // chain3 has a SHA-1 intermediate cert, will have a message from policy2 messages = SHA1DeprecationMessages(chain3) if len(messages) != 1 || messages[0] != fmt.Sprintf("%s %s due to SHA-1 deprecation", policy2.Platform, policy2.Description) { t.Fatal("Incorrect SHA1 deprecation reporting") } // chain4 is not subject to any deprecation policy messages = SHA1DeprecationMessages(chain4) if len(messages) != 0 { t.Fatal("Incorrect SHA1 deprecation reporting") } // Add two policies. One tests for newly issued leaf certificate after a deadline, the other is the same, // but takes effect at the 22nd century. SHA1DeprecationPolicys = []SHA1DeprecationPolicy{policy1, policy2, policy3, policy4} // chain1 only has root cert, not subject to any deprecation policy messages = SHA1DeprecationMessages(chain1) if len(messages) != 0 { t.Fatal("Incorrect SHA1 deprecation reporting") } // chain2 now is flagged by two policies: policy2 and policy3 messages = SHA1DeprecationMessages(chain2) if len(messages) != 2 { t.Fatal("Incorrect SHA1 deprecation reporting") } // chain3 is not flagged by policy3 but policy2 messages = SHA1DeprecationMessages(chain3) if len(messages) != 1 || messages[0] != fmt.Sprintf("%s %s due to SHA-1 deprecation", policy2.Platform, policy2.Description) { t.Fatal("Incorrect SHA1 deprecation reporting") } // chain4 is not subject to any deprecation policy messages = SHA1DeprecationMessages(chain4) if len(messages) != 0 { t.Fatal("Incorrect SHA1 deprecation reporting") } } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/cmd/goose/cmd.go ================================================ package main import ( "flag" ) // shamelessly snagged from the go tool // each command gets its own set of args, // defines its own entry point, and provides its own help type Command struct { Run func(cmd *Command, args ...string) Flag flag.FlagSet Name string Usage string Summary string Help string } func (c *Command) Exec(args []string) { c.Flag.Usage = func() { // helpFunc(c, c.Name) } c.Flag.Parse(args) c.Run(c, c.Flag.Args()...) } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/cmd/goose/cmd_create.go ================================================ package main import ( "bitbucket.org/liamstask/goose/lib/goose" "fmt" "log" "os" "path/filepath" "time" ) var createCmd = &Command{ Name: "create", Usage: "", Summary: "Create the scaffolding for a new migration", Help: `create extended help here...`, Run: createRun, } func createRun(cmd *Command, args ...string) { if len(args) < 1 { log.Fatal("goose create: migration name required") } migrationType := "go" // default to Go migrations if len(args) >= 2 { migrationType = args[1] } conf, err := dbConfFromFlags() if err != nil { log.Fatal(err) } if err = os.MkdirAll(conf.MigrationsDir, 0777); err != nil { log.Fatal(err) } n, err := goose.CreateMigration(args[0], migrationType, conf.MigrationsDir, time.Now()) if err != nil { log.Fatal(err) } a, e := filepath.Abs(n) if e != nil { log.Fatal(e) } fmt.Println("goose: created", a) } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/cmd/goose/cmd_dbversion.go ================================================ package main import ( "bitbucket.org/liamstask/goose/lib/goose" "fmt" "log" ) var dbVersionCmd = &Command{ Name: "dbversion", Usage: "", Summary: "Print the current version of the database", Help: `dbversion extended help here...`, Run: dbVersionRun, } func dbVersionRun(cmd *Command, args ...string) { conf, err := dbConfFromFlags() if err != nil { log.Fatal(err) } current, err := goose.GetDBVersion(conf) if err != nil { log.Fatal(err) } fmt.Printf("goose: dbversion %v\n", current) } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/cmd/goose/cmd_down.go ================================================ package main import ( "bitbucket.org/liamstask/goose/lib/goose" "log" ) var downCmd = &Command{ Name: "down", Usage: "", Summary: "Roll back the version by 1", Help: `down extended help here...`, Run: downRun, } func downRun(cmd *Command, args ...string) { conf, err := dbConfFromFlags() if err != nil { log.Fatal(err) } current, err := goose.GetDBVersion(conf) if err != nil { log.Fatal(err) } previous, err := goose.GetPreviousDBVersion(conf.MigrationsDir, current) if err != nil { log.Fatal(err) } if err = goose.RunMigrations(conf, conf.MigrationsDir, previous); err != nil { log.Fatal(err) } } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/cmd/goose/cmd_redo.go ================================================ package main import ( "bitbucket.org/liamstask/goose/lib/goose" "log" ) var redoCmd = &Command{ Name: "redo", Usage: "", Summary: "Re-run the latest migration", Help: `redo extended help here...`, Run: redoRun, } func redoRun(cmd *Command, args ...string) { conf, err := dbConfFromFlags() if err != nil { log.Fatal(err) } current, err := goose.GetDBVersion(conf) if err != nil { log.Fatal(err) } previous, err := goose.GetPreviousDBVersion(conf.MigrationsDir, current) if err != nil { log.Fatal(err) } if err := goose.RunMigrations(conf, conf.MigrationsDir, previous); err != nil { log.Fatal(err) } if err := goose.RunMigrations(conf, conf.MigrationsDir, current); err != nil { log.Fatal(err) } } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/cmd/goose/cmd_status.go ================================================ package main import ( "bitbucket.org/liamstask/goose/lib/goose" "database/sql" "fmt" "log" "path/filepath" "time" ) var statusCmd = &Command{ Name: "status", Usage: "", Summary: "dump the migration status for the current DB", Help: `status extended help here...`, Run: statusRun, } type StatusData struct { Source string Status string } func statusRun(cmd *Command, args ...string) { conf, err := dbConfFromFlags() if err != nil { log.Fatal(err) } // collect all migrations min := int64(0) max := int64((1 << 63) - 1) migrations, e := goose.CollectMigrations(conf.MigrationsDir, min, max) if e != nil { log.Fatal(e) } db, e := goose.OpenDBFromDBConf(conf) if e != nil { log.Fatal("couldn't open DB:", e) } defer db.Close() // must ensure that the version table exists if we're running on a pristine DB if _, e := goose.EnsureDBVersion(conf, db); e != nil { log.Fatal(e) } fmt.Printf("goose: status for environment '%v'\n", conf.Env) fmt.Println(" Applied At Migration") fmt.Println(" =======================================") for _, m := range migrations { printMigrationStatus(db, m.Version, filepath.Base(m.Source)) } } func printMigrationStatus(db *sql.DB, version int64, script string) { var row goose.MigrationRecord q := fmt.Sprintf("SELECT tstamp, is_applied FROM goose_db_version WHERE version_id=%d ORDER BY tstamp DESC LIMIT 1", version) e := db.QueryRow(q).Scan(&row.TStamp, &row.IsApplied) if e != nil && e != sql.ErrNoRows { log.Fatal(e) } var appliedAt string if row.IsApplied { appliedAt = row.TStamp.Format(time.ANSIC) } else { appliedAt = "Pending" } fmt.Printf(" %-24s -- %v\n", appliedAt, script) } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/cmd/goose/cmd_up.go ================================================ package main import ( "bitbucket.org/liamstask/goose/lib/goose" "log" ) var upCmd = &Command{ Name: "up", Usage: "", Summary: "Migrate the DB to the most recent version available", Help: `up extended help here...`, Run: upRun, } func upRun(cmd *Command, args ...string) { conf, err := dbConfFromFlags() if err != nil { log.Fatal(err) } target, err := goose.GetMostRecentDBVersion(conf.MigrationsDir) if err != nil { log.Fatal(err) } if err := goose.RunMigrations(conf, conf.MigrationsDir, target); err != nil { log.Fatal(err) } } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/cmd/goose/main.go ================================================ package main import ( "bitbucket.org/liamstask/goose/lib/goose" "flag" "fmt" "os" "strings" "text/template" ) // global options. available to any subcommands. var flagPath = flag.String("path", "db", "folder containing db info") var flagEnv = flag.String("env", "development", "which DB environment to use") var flagPgSchema = flag.String("pgschema", "", "which postgres-schema to migrate (default = none)") // helper to create a DBConf from the given flags func dbConfFromFlags() (dbconf *goose.DBConf, err error) { return goose.NewDBConf(*flagPath, *flagEnv, *flagPgSchema) } var commands = []*Command{ upCmd, downCmd, redoCmd, statusCmd, createCmd, dbVersionCmd, } func main() { flag.Usage = usage flag.Parse() args := flag.Args() if len(args) == 0 || args[0] == "-h" { flag.Usage() return } var cmd *Command name := args[0] for _, c := range commands { if strings.HasPrefix(c.Name, name) { cmd = c break } } if cmd == nil { fmt.Printf("error: unknown command %q\n", name) flag.Usage() os.Exit(1) } cmd.Exec(args[1:]) } func usage() { fmt.Print(usagePrefix) flag.PrintDefaults() usageTmpl.Execute(os.Stdout, commands) } var usagePrefix = ` goose is a database migration management system for Go projects. Usage: goose [options] [subcommand options] Options: ` var usageTmpl = template.Must(template.New("usage").Parse( ` Commands:{{range .}} {{.Name | printf "%-10s"}} {{.Summary}}{{end}} `)) ================================================ FILE: vendor/bitbucket.org/liamstask/goose/lib/goose/dbconf.go ================================================ package goose import ( "database/sql" "errors" "fmt" "os" "path/filepath" "github.com/kylelemons/go-gypsy/yaml" "github.com/lib/pq" ) // DBDriver encapsulates the info needed to work with // a specific database driver type DBDriver struct { Name string OpenStr string Import string Dialect SqlDialect } type DBConf struct { MigrationsDir string Env string Driver DBDriver PgSchema string } // extract configuration details from the given file func NewDBConf(p, env string, pgschema string) (*DBConf, error) { cfgFile := filepath.Join(p, "dbconf.yml") f, err := yaml.ReadFile(cfgFile) if err != nil { return nil, err } drv, err := f.Get(fmt.Sprintf("%s.driver", env)) if err != nil { return nil, err } drv = os.ExpandEnv(drv) open, err := f.Get(fmt.Sprintf("%s.open", env)) if err != nil { return nil, err } open = os.ExpandEnv(open) // Automatically parse postgres urls if drv == "postgres" { // Assumption: If we can parse the URL, we should if parsedURL, err := pq.ParseURL(open); err == nil && parsedURL != "" { open = parsedURL } } d := newDBDriver(drv, open) // allow the configuration to override the Import for this driver if imprt, err := f.Get(fmt.Sprintf("%s.import", env)); err == nil { d.Import = imprt } // allow the configuration to override the Dialect for this driver if dialect, err := f.Get(fmt.Sprintf("%s.dialect", env)); err == nil { d.Dialect = dialectByName(dialect) } if !d.IsValid() { return nil, errors.New(fmt.Sprintf("Invalid DBConf: %v", d)) } return &DBConf{ MigrationsDir: filepath.Join(p, "migrations"), Env: env, Driver: d, PgSchema: pgschema, }, nil } // Create a new DBDriver and populate driver specific // fields for drivers that we know about. // Further customization may be done in NewDBConf func newDBDriver(name, open string) DBDriver { d := DBDriver{ Name: name, OpenStr: open, } switch name { case "postgres": d.Import = "github.com/lib/pq" d.Dialect = &PostgresDialect{} case "mymysql": d.Import = "github.com/ziutek/mymysql/godrv" d.Dialect = &MySqlDialect{} case "mysql": d.Import = "github.com/go-sql-driver/mysql" d.Dialect = &MySqlDialect{} case "sqlite3": d.Import = "github.com/mattn/go-sqlite3" d.Dialect = &Sqlite3Dialect{} } return d } // ensure we have enough info about this driver func (drv *DBDriver) IsValid() bool { return len(drv.Import) > 0 && drv.Dialect != nil } // OpenDBFromDBConf wraps database/sql.DB.Open() and configures // the newly opened DB based on the given DBConf. // // Callers must Close() the returned DB. func OpenDBFromDBConf(conf *DBConf) (*sql.DB, error) { db, err := sql.Open(conf.Driver.Name, conf.Driver.OpenStr) if err != nil { return nil, err } // if a postgres schema has been specified, apply it if conf.Driver.Name == "postgres" && conf.PgSchema != "" { if _, err := db.Exec("SET search_path TO " + conf.PgSchema); err != nil { return nil, err } } return db, nil } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/lib/goose/dialect.go ================================================ package goose import ( "database/sql" "github.com/mattn/go-sqlite3" ) // SqlDialect abstracts the details of specific SQL dialects // for goose's few SQL specific statements type SqlDialect interface { createVersionTableSql() string // sql string to create the goose_db_version table insertVersionSql() string // sql string to insert the initial version table row dbVersionQuery(db *sql.DB) (*sql.Rows, error) } // drivers that we don't know about can ask for a dialect by name func dialectByName(d string) SqlDialect { switch d { case "postgres": return &PostgresDialect{} case "mysql": return &MySqlDialect{} case "sqlite3": return &Sqlite3Dialect{} } return nil } //////////////////////////// // Postgres //////////////////////////// type PostgresDialect struct{} func (pg PostgresDialect) createVersionTableSql() string { return `CREATE TABLE goose_db_version ( id serial NOT NULL, version_id bigint NOT NULL, is_applied boolean NOT NULL, tstamp timestamp NULL default now(), PRIMARY KEY(id) );` } func (pg PostgresDialect) insertVersionSql() string { return "INSERT INTO goose_db_version (version_id, is_applied) VALUES ($1, $2);" } func (pg PostgresDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) { rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY id DESC") // XXX: check for postgres specific error indicating the table doesn't exist. // for now, assume any error is because the table doesn't exist, // in which case we'll try to create it. if err != nil { return nil, ErrTableDoesNotExist } return rows, err } //////////////////////////// // MySQL //////////////////////////// type MySqlDialect struct{} func (m MySqlDialect) createVersionTableSql() string { return `CREATE TABLE goose_db_version ( id serial NOT NULL, version_id bigint NOT NULL, is_applied boolean NOT NULL, tstamp timestamp NULL default now(), PRIMARY KEY(id) );` } func (m MySqlDialect) insertVersionSql() string { return "INSERT INTO goose_db_version (version_id, is_applied) VALUES (?, ?);" } func (m MySqlDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) { rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY id DESC") // XXX: check for mysql specific error indicating the table doesn't exist. // for now, assume any error is because the table doesn't exist, // in which case we'll try to create it. if err != nil { return nil, ErrTableDoesNotExist } return rows, err } //////////////////////////// // sqlite3 //////////////////////////// type Sqlite3Dialect struct{} func (m Sqlite3Dialect) createVersionTableSql() string { return `CREATE TABLE goose_db_version ( id INTEGER PRIMARY KEY AUTOINCREMENT, version_id INTEGER NOT NULL, is_applied INTEGER NOT NULL, tstamp TIMESTAMP DEFAULT (datetime('now')) );` } func (m Sqlite3Dialect) insertVersionSql() string { return "INSERT INTO goose_db_version (version_id, is_applied) VALUES (?, ?);" } func (m Sqlite3Dialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) { rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY id DESC") switch err.(type) { case sqlite3.Error: return nil, ErrTableDoesNotExist } return rows, err } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/lib/goose/migrate.go ================================================ package goose import ( "database/sql" "errors" "fmt" "log" "os" "path/filepath" "sort" "strconv" "strings" "text/template" "time" _ "github.com/go-sql-driver/mysql" _ "github.com/lib/pq" _ "github.com/mattn/go-sqlite3" _ "github.com/ziutek/mymysql/godrv" ) var ( ErrTableDoesNotExist = errors.New("table does not exist") ErrNoPreviousVersion = errors.New("no previous version found") ) type MigrationRecord struct { VersionId int64 TStamp time.Time IsApplied bool // was this a result of up() or down() } type Migration struct { Version int64 Next int64 // next version, or -1 if none Previous int64 // previous version, -1 if none Source string // path to .go or .sql script } type migrationSorter []*Migration // helpers so we can use pkg sort func (ms migrationSorter) Len() int { return len(ms) } func (ms migrationSorter) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] } func (ms migrationSorter) Less(i, j int) bool { return ms[i].Version < ms[j].Version } func newMigration(v int64, src string) *Migration { return &Migration{v, -1, -1, src} } func RunMigrations(conf *DBConf, migrationsDir string, target int64) (err error) { db, err := OpenDBFromDBConf(conf) if err != nil { return err } defer db.Close() return RunMigrationsOnDb(conf, migrationsDir, target, db) } // Runs migration on a specific database instance. func RunMigrationsOnDb(conf *DBConf, migrationsDir string, target int64, db *sql.DB) (err error) { current, err := EnsureDBVersion(conf, db) if err != nil { return err } migrations, err := CollectMigrations(migrationsDir, current, target) if err != nil { return err } if len(migrations) == 0 { fmt.Printf("goose: no migrations to run. current version: %d\n", current) return nil } ms := migrationSorter(migrations) direction := current < target ms.Sort(direction) fmt.Printf("goose: migrating db environment '%v', current version: %d, target: %d\n", conf.Env, current, target) for _, m := range ms { switch filepath.Ext(m.Source) { case ".go": err = runGoMigration(conf, m.Source, m.Version, direction) case ".sql": err = runSQLMigration(conf, db, m.Source, m.Version, direction) } if err != nil { return errors.New(fmt.Sprintf("FAIL %v, quitting migration", err)) } fmt.Println("OK ", filepath.Base(m.Source)) } return nil } // collect all the valid looking migration scripts in the // migrations folder, and key them by version func CollectMigrations(dirpath string, current, target int64) (m []*Migration, err error) { // extract the numeric component of each migration, // filter out any uninteresting files, // and ensure we only have one file per migration version. filepath.Walk(dirpath, func(name string, info os.FileInfo, err error) error { if v, e := NumericComponent(name); e == nil { for _, g := range m { if v == g.Version { log.Fatalf("more than one file specifies the migration for version %d (%s and %s)", v, g.Source, filepath.Join(dirpath, name)) } } if versionFilter(v, current, target) { m = append(m, newMigration(v, name)) } } return nil }) return m, nil } func versionFilter(v, current, target int64) bool { if target > current { return v > current && v <= target } if target < current { return v <= current && v > target } return false } func (ms migrationSorter) Sort(direction bool) { // sort ascending or descending by version if direction { sort.Sort(ms) } else { sort.Sort(sort.Reverse(ms)) } // now that we're sorted in the appropriate direction, // populate next and previous for each migration for i, m := range ms { prev := int64(-1) if i > 0 { prev = ms[i-1].Version ms[i-1].Next = m.Version } ms[i].Previous = prev } } // look for migration scripts with names in the form: // XXX_descriptivename.ext // where XXX specifies the version number // and ext specifies the type of migration func NumericComponent(name string) (int64, error) { base := filepath.Base(name) if ext := filepath.Ext(base); ext != ".go" && ext != ".sql" { return 0, errors.New("not a recognized migration file type") } idx := strings.Index(base, "_") if idx < 0 { return 0, errors.New("no separator found") } n, e := strconv.ParseInt(base[:idx], 10, 64) if e == nil && n <= 0 { return 0, errors.New("migration IDs must be greater than zero") } return n, e } // retrieve the current version for this DB. // Create and initialize the DB version table if it doesn't exist. func EnsureDBVersion(conf *DBConf, db *sql.DB) (int64, error) { rows, err := conf.Driver.Dialect.dbVersionQuery(db) if err != nil { if err == ErrTableDoesNotExist { return 0, createVersionTable(conf, db) } return 0, err } defer rows.Close() // The most recent record for each migration specifies // whether it has been applied or rolled back. // The first version we find that has been applied is the current version. toSkip := make([]int64, 0) for rows.Next() { var row MigrationRecord if err = rows.Scan(&row.VersionId, &row.IsApplied); err != nil { log.Fatal("error scanning rows:", err) } // have we already marked this version to be skipped? skip := false for _, v := range toSkip { if v == row.VersionId { skip = true break } } if skip { continue } // if version has been applied we're done if row.IsApplied { return row.VersionId, nil } // latest version of migration has not been applied. toSkip = append(toSkip, row.VersionId) } panic("failure in EnsureDBVersion()") } // Create the goose_db_version table // and insert the initial 0 value into it func createVersionTable(conf *DBConf, db *sql.DB) error { txn, err := db.Begin() if err != nil { return err } d := conf.Driver.Dialect if _, err := txn.Exec(d.createVersionTableSql()); err != nil { txn.Rollback() return err } version := 0 applied := true if _, err := txn.Exec(d.insertVersionSql(), version, applied); err != nil { txn.Rollback() return err } return txn.Commit() } // wrapper for EnsureDBVersion for callers that don't already have // their own DB instance func GetDBVersion(conf *DBConf) (version int64, err error) { db, err := OpenDBFromDBConf(conf) if err != nil { return -1, err } defer db.Close() version, err = EnsureDBVersion(conf, db) if err != nil { return -1, err } return version, nil } func GetPreviousDBVersion(dirpath string, version int64) (previous int64, err error) { previous = -1 sawGivenVersion := false filepath.Walk(dirpath, func(name string, info os.FileInfo, walkerr error) error { if !info.IsDir() { if v, e := NumericComponent(name); e == nil { if v > previous && v < version { previous = v } if v == version { sawGivenVersion = true } } } return nil }) if previous == -1 { if sawGivenVersion { // the given version is (likely) valid but we didn't find // anything before it. // 'previous' must reflect that no migrations have been applied. previous = 0 } else { err = ErrNoPreviousVersion } } return } // helper to identify the most recent possible version // within a folder of migration scripts func GetMostRecentDBVersion(dirpath string) (version int64, err error) { version = -1 filepath.Walk(dirpath, func(name string, info os.FileInfo, walkerr error) error { if walkerr != nil { return walkerr } if !info.IsDir() { if v, e := NumericComponent(name); e == nil { if v > version { version = v } } } return nil }) if version == -1 { err = errors.New("no valid version found") } return } func CreateMigration(name, migrationType, dir string, t time.Time) (path string, err error) { if migrationType != "go" && migrationType != "sql" { return "", errors.New("migration type must be 'go' or 'sql'") } timestamp := t.Format("20060102150405") filename := fmt.Sprintf("%v_%v.%v", timestamp, name, migrationType) fpath := filepath.Join(dir, filename) var tmpl *template.Template if migrationType == "sql" { tmpl = sqlMigrationTemplate } else { tmpl = goMigrationTemplate } path, err = writeTemplateToFile(fpath, tmpl, timestamp) return } // Update the version table for the given migration, // and finalize the transaction. func FinalizeMigration(conf *DBConf, txn *sql.Tx, direction bool, v int64) error { // XXX: drop goose_db_version table on some minimum version number? stmt := conf.Driver.Dialect.insertVersionSql() if _, err := txn.Exec(stmt, v, direction); err != nil { txn.Rollback() return err } return txn.Commit() } var goMigrationTemplate = template.Must(template.New("goose.go-migration").Parse(` package main import ( "database/sql" ) // Up is executed when this migration is applied func Up_{{ . }}(txn *sql.Tx) { } // Down is executed when this migration is rolled back func Down_{{ . }}(txn *sql.Tx) { } `)) var sqlMigrationTemplate = template.Must(template.New("goose.sql-migration").Parse(` -- +goose Up -- SQL in section 'Up' is executed when this migration is applied -- +goose Down -- SQL section 'Down' is executed when this migration is rolled back `)) ================================================ FILE: vendor/bitbucket.org/liamstask/goose/lib/goose/migration_go.go ================================================ package goose import ( "bytes" "encoding/gob" "fmt" "io/ioutil" "log" "os" "os/exec" "path/filepath" "text/template" ) type templateData struct { Version int64 Import string Conf string // gob encoded DBConf Direction bool Func string InsertStmt string } func init() { gob.Register(PostgresDialect{}) gob.Register(MySqlDialect{}) gob.Register(Sqlite3Dialect{}) } // // Run a .go migration. // // In order to do this, we copy a modified version of the // original .go migration, and execute it via `go run` along // with a main() of our own creation. // func runGoMigration(conf *DBConf, path string, version int64, direction bool) error { // everything gets written to a temp dir, and zapped afterwards d, e := ioutil.TempDir("", "goose") if e != nil { log.Fatal(e) } defer os.RemoveAll(d) directionStr := "Down" if direction { directionStr = "Up" } var bb bytes.Buffer if err := gob.NewEncoder(&bb).Encode(conf); err != nil { return err } // XXX: there must be a better way of making this byte array // available to the generated code... // but for now, print an array literal of the gob bytes var sb bytes.Buffer sb.WriteString("[]byte{ ") for _, b := range bb.Bytes() { sb.WriteString(fmt.Sprintf("0x%02x, ", b)) } sb.WriteString("}") td := &templateData{ Version: version, Import: conf.Driver.Import, Conf: sb.String(), Direction: direction, Func: fmt.Sprintf("%v_%v", directionStr, version), InsertStmt: conf.Driver.Dialect.insertVersionSql(), } main, e := writeTemplateToFile(filepath.Join(d, "goose_main.go"), goMigrationDriverTemplate, td) if e != nil { log.Fatal(e) } outpath := filepath.Join(d, filepath.Base(path)) if _, e = copyFile(outpath, path); e != nil { log.Fatal(e) } cmd := exec.Command("go", "run", main, outpath) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if e = cmd.Run(); e != nil { log.Fatal("`go run` failed: ", e) } return nil } // // template for the main entry point to a go-based migration. // this gets linked against the substituted versions of the user-supplied // scripts in order to execute a migration via `go run` // var goMigrationDriverTemplate = template.Must(template.New("goose.go-driver").Parse(` package main import ( "log" "bytes" "encoding/gob" _ "{{.Import}}" "bitbucket.org/liamstask/goose/lib/goose" ) func main() { var conf goose.DBConf buf := bytes.NewBuffer({{ .Conf }}) if err := gob.NewDecoder(buf).Decode(&conf); err != nil { log.Fatal("gob.Decode - ", err) } db, err := goose.OpenDBFromDBConf(&conf) if err != nil { log.Fatal("failed to open DB:", err) } defer db.Close() txn, err := db.Begin() if err != nil { log.Fatal("db.Begin:", err) } {{ .Func }}(txn) err = goose.FinalizeMigration(&conf, txn, {{ .Direction }}, {{ .Version }}) if err != nil { log.Fatal("Commit() failed:", err) } } `)) ================================================ FILE: vendor/bitbucket.org/liamstask/goose/lib/goose/migration_sql.go ================================================ package goose import ( "bufio" "bytes" "database/sql" "io" "log" "os" "path/filepath" "strings" ) const sqlCmdPrefix = "-- +goose " // Checks the line to see if the line has a statement-ending semicolon // or if the line contains a double-dash comment. func endsWithSemicolon(line string) bool { prev := "" scanner := bufio.NewScanner(strings.NewReader(line)) scanner.Split(bufio.ScanWords) for scanner.Scan() { word := scanner.Text() if strings.HasPrefix(word, "--") { break } prev = word } return strings.HasSuffix(prev, ";") } // Split the given sql script into individual statements. // // The base case is to simply split on semicolons, as these // naturally terminate a statement. // // However, more complex cases like pl/pgsql can have semicolons // within a statement. For these cases, we provide the explicit annotations // 'StatementBegin' and 'StatementEnd' to allow the script to // tell us to ignore semicolons. func splitSQLStatements(r io.Reader, direction bool) (stmts []string) { var buf bytes.Buffer scanner := bufio.NewScanner(r) // track the count of each section // so we can diagnose scripts with no annotations upSections := 0 downSections := 0 statementEnded := false ignoreSemicolons := false directionIsActive := false for scanner.Scan() { line := scanner.Text() // handle any goose-specific commands if strings.HasPrefix(line, sqlCmdPrefix) { cmd := strings.TrimSpace(line[len(sqlCmdPrefix):]) switch cmd { case "Up": directionIsActive = (direction == true) upSections++ break case "Down": directionIsActive = (direction == false) downSections++ break case "StatementBegin": if directionIsActive { ignoreSemicolons = true } break case "StatementEnd": if directionIsActive { statementEnded = (ignoreSemicolons == true) ignoreSemicolons = false } break } } if !directionIsActive { continue } if _, err := buf.WriteString(line + "\n"); err != nil { log.Fatalf("io err: %v", err) } // Wrap up the two supported cases: 1) basic with semicolon; 2) psql statement // Lines that end with semicolon that are in a statement block // do not conclude statement. if (!ignoreSemicolons && endsWithSemicolon(line)) || statementEnded { statementEnded = false stmts = append(stmts, buf.String()) buf.Reset() } } if err := scanner.Err(); err != nil { log.Fatalf("scanning migration: %v", err) } // diagnose likely migration script errors if ignoreSemicolons { log.Println("WARNING: saw '-- +goose StatementBegin' with no matching '-- +goose StatementEnd'") } if bufferRemaining := strings.TrimSpace(buf.String()); len(bufferRemaining) > 0 { log.Printf("WARNING: Unexpected unfinished SQL query: %s. Missing a semicolon?\n", bufferRemaining) } if upSections == 0 && downSections == 0 { log.Fatalf(`ERROR: no Up/Down annotations found, so no statements were executed. See https://bitbucket.org/liamstask/goose/overview for details.`) } return } // Run a migration specified in raw SQL. // // Sections of the script can be annotated with a special comment, // starting with "-- +goose" to specify whether the section should // be applied during an Up or Down migration // // All statements following an Up or Down directive are grouped together // until another direction directive is found. func runSQLMigration(conf *DBConf, db *sql.DB, scriptFile string, v int64, direction bool) error { txn, err := db.Begin() if err != nil { log.Fatal("db.Begin:", err) } f, err := os.Open(scriptFile) if err != nil { log.Fatal(err) } // find each statement, checking annotations for up/down direction // and execute each of them in the current transaction. // Commits the transaction if successfully applied each statement and // records the version into the version table or returns an error and // rolls back the transaction. for _, query := range splitSQLStatements(f, direction) { if _, err = txn.Exec(query); err != nil { txn.Rollback() log.Fatalf("FAIL %s (%v), quitting migration.", filepath.Base(scriptFile), err) return err } } if err = FinalizeMigration(conf, txn, direction, v); err != nil { log.Fatalf("error finalizing migration %s, quitting. (%v)", filepath.Base(scriptFile), err) } return nil } ================================================ FILE: vendor/bitbucket.org/liamstask/goose/lib/goose/util.go ================================================ package goose import ( "io" "os" "text/template" ) // common routines func writeTemplateToFile(path string, t *template.Template, data interface{}) (string, error) { f, e := os.Create(path) if e != nil { return "", e } defer f.Close() e = t.Execute(f, data) if e != nil { return "", e } return f.Name(), nil } func copyFile(dst, src string) (int64, error) { sf, err := os.Open(src) if err != nil { return 0, err } defer sf.Close() df, err := os.Create(dst) if err != nil { return 0, err } defer df.Close() return io.Copy(df, sf) } ================================================ FILE: vendor/filippo.io/edwards25519/LICENSE ================================================ Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: vendor/filippo.io/edwards25519/README.md ================================================ # filippo.io/edwards25519 ``` import "filippo.io/edwards25519" ``` This library implements the edwards25519 elliptic curve, exposing the necessary APIs to build a wide array of higher-level primitives. Read the docs at [pkg.go.dev/filippo.io/edwards25519](https://pkg.go.dev/filippo.io/edwards25519). The code is originally derived from Adam Langley's internal implementation in the Go standard library, and includes George Tankersley's [performance improvements](https://golang.org/cl/71950). It was then further developed by Henry de Valence for use in ristretto255, and was finally [merged back into the Go standard library](https://golang.org/cl/276272) as of Go 1.17. It now tracks the upstream codebase and extends it with additional functionality. Most users don't need this package, and should instead use `crypto/ed25519` for signatures, `golang.org/x/crypto/curve25519` for Diffie-Hellman, or `github.com/gtank/ristretto255` for prime order group logic. However, for anyone currently using a fork of `crypto/internal/edwards25519`/`crypto/ed25519/internal/edwards25519` or `github.com/agl/edwards25519`, this package should be a safer, faster, and more powerful alternative. Since this package is meant to curb proliferation of edwards25519 implementations in the Go ecosystem, it welcomes requests for new APIs or reviewable performance improvements. ================================================ FILE: vendor/filippo.io/edwards25519/doc.go ================================================ // Copyright (c) 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package edwards25519 implements group logic for the twisted Edwards curve // // -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2 // // This is better known as the Edwards curve equivalent to Curve25519, and is // the curve used by the Ed25519 signature scheme. // // Most users don't need this package, and should instead use crypto/ed25519 for // signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or // github.com/gtank/ristretto255 for prime order group logic. // // However, developers who do need to interact with low-level edwards25519 // operations can use this package, which is an extended version of // crypto/internal/edwards25519 from the standard library repackaged as // an importable module. package edwards25519 ================================================ FILE: vendor/filippo.io/edwards25519/edwards25519.go ================================================ // Copyright (c) 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package edwards25519 import ( "errors" "filippo.io/edwards25519/field" ) // Point types. type projP1xP1 struct { X, Y, Z, T field.Element } type projP2 struct { X, Y, Z field.Element } // Point represents a point on the edwards25519 curve. // // This type works similarly to math/big.Int, and all arguments and receivers // are allowed to alias. // // The zero value is NOT valid, and it may be used only as a receiver. type Point struct { // Make the type not comparable (i.e. used with == or as a map key), as // equivalent points can be represented by different Go values. _ incomparable // The point is internally represented in extended coordinates (X, Y, Z, T) // where x = X/Z, y = Y/Z, and xy = T/Z per https://eprint.iacr.org/2008/522. x, y, z, t field.Element } type incomparable [0]func() func checkInitialized(points ...*Point) { for _, p := range points { if p.x == (field.Element{}) && p.y == (field.Element{}) { panic("edwards25519: use of uninitialized Point") } } } type projCached struct { YplusX, YminusX, Z, T2d field.Element } type affineCached struct { YplusX, YminusX, T2d field.Element } // Constructors. func (v *projP2) Zero() *projP2 { v.X.Zero() v.Y.One() v.Z.One() return v } // identity is the point at infinity. var identity, _ = new(Point).SetBytes([]byte{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) // NewIdentityPoint returns a new Point set to the identity. func NewIdentityPoint() *Point { return new(Point).Set(identity) } // generator is the canonical curve basepoint. See TestGenerator for the // correspondence of this encoding with the values in RFC 8032. var generator, _ = new(Point).SetBytes([]byte{ 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}) // NewGeneratorPoint returns a new Point set to the canonical generator. func NewGeneratorPoint() *Point { return new(Point).Set(generator) } func (v *projCached) Zero() *projCached { v.YplusX.One() v.YminusX.One() v.Z.One() v.T2d.Zero() return v } func (v *affineCached) Zero() *affineCached { v.YplusX.One() v.YminusX.One() v.T2d.Zero() return v } // Assignments. // Set sets v = u, and returns v. func (v *Point) Set(u *Point) *Point { *v = *u return v } // Encoding. // Bytes returns the canonical 32-byte encoding of v, according to RFC 8032, // Section 5.1.2. func (v *Point) Bytes() []byte { // This function is outlined to make the allocations inline in the caller // rather than happen on the heap. var buf [32]byte return v.bytes(&buf) } func (v *Point) bytes(buf *[32]byte) []byte { checkInitialized(v) var zInv, x, y field.Element zInv.Invert(&v.z) // zInv = 1 / Z x.Multiply(&v.x, &zInv) // x = X / Z y.Multiply(&v.y, &zInv) // y = Y / Z out := copyFieldElement(buf, &y) out[31] |= byte(x.IsNegative() << 7) return out } var feOne = new(field.Element).One() // SetBytes sets v = x, where x is a 32-byte encoding of v. If x does not // represent a valid point on the curve, SetBytes returns nil and an error and // the receiver is unchanged. Otherwise, SetBytes returns v. // // Note that SetBytes accepts all non-canonical encodings of valid points. // That is, it follows decoding rules that match most implementations in // the ecosystem rather than RFC 8032. func (v *Point) SetBytes(x []byte) (*Point, error) { // Specifically, the non-canonical encodings that are accepted are // 1) the ones where the field element is not reduced (see the // (*field.Element).SetBytes docs) and // 2) the ones where the x-coordinate is zero and the sign bit is set. // // Read more at https://hdevalence.ca/blog/2020-10-04-its-25519am, // specifically the "Canonical A, R" section. y, err := new(field.Element).SetBytes(x) if err != nil { return nil, errors.New("edwards25519: invalid point encoding length") } // -x² + y² = 1 + dx²y² // x² + dx²y² = x²(dy² + 1) = y² - 1 // x² = (y² - 1) / (dy² + 1) // u = y² - 1 y2 := new(field.Element).Square(y) u := new(field.Element).Subtract(y2, feOne) // v = dy² + 1 vv := new(field.Element).Multiply(y2, d) vv = vv.Add(vv, feOne) // x = +√(u/v) xx, wasSquare := new(field.Element).SqrtRatio(u, vv) if wasSquare == 0 { return nil, errors.New("edwards25519: invalid point encoding") } // Select the negative square root if the sign bit is set. xxNeg := new(field.Element).Negate(xx) xx = xx.Select(xxNeg, xx, int(x[31]>>7)) v.x.Set(xx) v.y.Set(y) v.z.One() v.t.Multiply(xx, y) // xy = T / Z return v, nil } func copyFieldElement(buf *[32]byte, v *field.Element) []byte { copy(buf[:], v.Bytes()) return buf[:] } // Conversions. func (v *projP2) FromP1xP1(p *projP1xP1) *projP2 { v.X.Multiply(&p.X, &p.T) v.Y.Multiply(&p.Y, &p.Z) v.Z.Multiply(&p.Z, &p.T) return v } func (v *projP2) FromP3(p *Point) *projP2 { v.X.Set(&p.x) v.Y.Set(&p.y) v.Z.Set(&p.z) return v } func (v *Point) fromP1xP1(p *projP1xP1) *Point { v.x.Multiply(&p.X, &p.T) v.y.Multiply(&p.Y, &p.Z) v.z.Multiply(&p.Z, &p.T) v.t.Multiply(&p.X, &p.Y) return v } func (v *Point) fromP2(p *projP2) *Point { v.x.Multiply(&p.X, &p.Z) v.y.Multiply(&p.Y, &p.Z) v.z.Square(&p.Z) v.t.Multiply(&p.X, &p.Y) return v } // d is a constant in the curve equation. var d, _ = new(field.Element).SetBytes([]byte{ 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52}) var d2 = new(field.Element).Add(d, d) func (v *projCached) FromP3(p *Point) *projCached { v.YplusX.Add(&p.y, &p.x) v.YminusX.Subtract(&p.y, &p.x) v.Z.Set(&p.z) v.T2d.Multiply(&p.t, d2) return v } func (v *affineCached) FromP3(p *Point) *affineCached { v.YplusX.Add(&p.y, &p.x) v.YminusX.Subtract(&p.y, &p.x) v.T2d.Multiply(&p.t, d2) var invZ field.Element invZ.Invert(&p.z) v.YplusX.Multiply(&v.YplusX, &invZ) v.YminusX.Multiply(&v.YminusX, &invZ) v.T2d.Multiply(&v.T2d, &invZ) return v } // (Re)addition and subtraction. // Add sets v = p + q, and returns v. func (v *Point) Add(p, q *Point) *Point { checkInitialized(p, q) qCached := new(projCached).FromP3(q) result := new(projP1xP1).Add(p, qCached) return v.fromP1xP1(result) } // Subtract sets v = p - q, and returns v. func (v *Point) Subtract(p, q *Point) *Point { checkInitialized(p, q) qCached := new(projCached).FromP3(q) result := new(projP1xP1).Sub(p, qCached) return v.fromP1xP1(result) } func (v *projP1xP1) Add(p *Point, q *projCached) *projP1xP1 { var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element YplusX.Add(&p.y, &p.x) YminusX.Subtract(&p.y, &p.x) PP.Multiply(&YplusX, &q.YplusX) MM.Multiply(&YminusX, &q.YminusX) TT2d.Multiply(&p.t, &q.T2d) ZZ2.Multiply(&p.z, &q.Z) ZZ2.Add(&ZZ2, &ZZ2) v.X.Subtract(&PP, &MM) v.Y.Add(&PP, &MM) v.Z.Add(&ZZ2, &TT2d) v.T.Subtract(&ZZ2, &TT2d) return v } func (v *projP1xP1) Sub(p *Point, q *projCached) *projP1xP1 { var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element YplusX.Add(&p.y, &p.x) YminusX.Subtract(&p.y, &p.x) PP.Multiply(&YplusX, &q.YminusX) // flipped sign MM.Multiply(&YminusX, &q.YplusX) // flipped sign TT2d.Multiply(&p.t, &q.T2d) ZZ2.Multiply(&p.z, &q.Z) ZZ2.Add(&ZZ2, &ZZ2) v.X.Subtract(&PP, &MM) v.Y.Add(&PP, &MM) v.Z.Subtract(&ZZ2, &TT2d) // flipped sign v.T.Add(&ZZ2, &TT2d) // flipped sign return v } func (v *projP1xP1) AddAffine(p *Point, q *affineCached) *projP1xP1 { var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element YplusX.Add(&p.y, &p.x) YminusX.Subtract(&p.y, &p.x) PP.Multiply(&YplusX, &q.YplusX) MM.Multiply(&YminusX, &q.YminusX) TT2d.Multiply(&p.t, &q.T2d) Z2.Add(&p.z, &p.z) v.X.Subtract(&PP, &MM) v.Y.Add(&PP, &MM) v.Z.Add(&Z2, &TT2d) v.T.Subtract(&Z2, &TT2d) return v } func (v *projP1xP1) SubAffine(p *Point, q *affineCached) *projP1xP1 { var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element YplusX.Add(&p.y, &p.x) YminusX.Subtract(&p.y, &p.x) PP.Multiply(&YplusX, &q.YminusX) // flipped sign MM.Multiply(&YminusX, &q.YplusX) // flipped sign TT2d.Multiply(&p.t, &q.T2d) Z2.Add(&p.z, &p.z) v.X.Subtract(&PP, &MM) v.Y.Add(&PP, &MM) v.Z.Subtract(&Z2, &TT2d) // flipped sign v.T.Add(&Z2, &TT2d) // flipped sign return v } // Doubling. func (v *projP1xP1) Double(p *projP2) *projP1xP1 { var XX, YY, ZZ2, XplusYsq field.Element XX.Square(&p.X) YY.Square(&p.Y) ZZ2.Square(&p.Z) ZZ2.Add(&ZZ2, &ZZ2) XplusYsq.Add(&p.X, &p.Y) XplusYsq.Square(&XplusYsq) v.Y.Add(&YY, &XX) v.Z.Subtract(&YY, &XX) v.X.Subtract(&XplusYsq, &v.Y) v.T.Subtract(&ZZ2, &v.Z) return v } // Negation. // Negate sets v = -p, and returns v. func (v *Point) Negate(p *Point) *Point { checkInitialized(p) v.x.Negate(&p.x) v.y.Set(&p.y) v.z.Set(&p.z) v.t.Negate(&p.t) return v } // Equal returns 1 if v is equivalent to u, and 0 otherwise. func (v *Point) Equal(u *Point) int { checkInitialized(v, u) var t1, t2, t3, t4 field.Element t1.Multiply(&v.x, &u.z) t2.Multiply(&u.x, &v.z) t3.Multiply(&v.y, &u.z) t4.Multiply(&u.y, &v.z) return t1.Equal(&t2) & t3.Equal(&t4) } // Constant-time operations // Select sets v to a if cond == 1 and to b if cond == 0. func (v *projCached) Select(a, b *projCached, cond int) *projCached { v.YplusX.Select(&a.YplusX, &b.YplusX, cond) v.YminusX.Select(&a.YminusX, &b.YminusX, cond) v.Z.Select(&a.Z, &b.Z, cond) v.T2d.Select(&a.T2d, &b.T2d, cond) return v } // Select sets v to a if cond == 1 and to b if cond == 0. func (v *affineCached) Select(a, b *affineCached, cond int) *affineCached { v.YplusX.Select(&a.YplusX, &b.YplusX, cond) v.YminusX.Select(&a.YminusX, &b.YminusX, cond) v.T2d.Select(&a.T2d, &b.T2d, cond) return v } // CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0. func (v *projCached) CondNeg(cond int) *projCached { v.YplusX.Swap(&v.YminusX, cond) v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond) return v } // CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0. func (v *affineCached) CondNeg(cond int) *affineCached { v.YplusX.Swap(&v.YminusX, cond) v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond) return v } ================================================ FILE: vendor/filippo.io/edwards25519/extra.go ================================================ // Copyright (c) 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package edwards25519 // This file contains additional functionality that is not included in the // upstream crypto/internal/edwards25519 package. import ( "errors" "filippo.io/edwards25519/field" ) // ExtendedCoordinates returns v in extended coordinates (X:Y:Z:T) where // x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522. func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) { // This function is outlined to make the allocations inline in the caller // rather than happen on the heap. Don't change the style without making // sure it doesn't increase the inliner cost. var e [4]field.Element X, Y, Z, T = v.extendedCoordinates(&e) return } func (v *Point) extendedCoordinates(e *[4]field.Element) (X, Y, Z, T *field.Element) { checkInitialized(v) X = e[0].Set(&v.x) Y = e[1].Set(&v.y) Z = e[2].Set(&v.z) T = e[3].Set(&v.t) return } // SetExtendedCoordinates sets v = (X:Y:Z:T) in extended coordinates where // x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522. // // If the coordinates are invalid or don't represent a valid point on the curve, // SetExtendedCoordinates returns nil and an error and the receiver is // unchanged. Otherwise, SetExtendedCoordinates returns v. func (v *Point) SetExtendedCoordinates(X, Y, Z, T *field.Element) (*Point, error) { if !isOnCurve(X, Y, Z, T) { return nil, errors.New("edwards25519: invalid point coordinates") } v.x.Set(X) v.y.Set(Y) v.z.Set(Z) v.t.Set(T) return v, nil } func isOnCurve(X, Y, Z, T *field.Element) bool { var lhs, rhs field.Element XX := new(field.Element).Square(X) YY := new(field.Element).Square(Y) ZZ := new(field.Element).Square(Z) TT := new(field.Element).Square(T) // -x² + y² = 1 + dx²y² // -(X/Z)² + (Y/Z)² = 1 + d(T/Z)² // -X² + Y² = Z² + dT² lhs.Subtract(YY, XX) rhs.Multiply(d, TT).Add(&rhs, ZZ) if lhs.Equal(&rhs) != 1 { return false } // xy = T/Z // XY/Z² = T/Z // XY = TZ lhs.Multiply(X, Y) rhs.Multiply(T, Z) return lhs.Equal(&rhs) == 1 } // BytesMontgomery converts v to a point on the birationally-equivalent // Curve25519 Montgomery curve, and returns its canonical 32 bytes encoding // according to RFC 7748. // // Note that BytesMontgomery only encodes the u-coordinate, so v and -v encode // to the same value. If v is the identity point, BytesMontgomery returns 32 // zero bytes, analogously to the X25519 function. // // The lack of an inverse operation (such as SetMontgomeryBytes) is deliberate: // while every valid edwards25519 point has a unique u-coordinate Montgomery // encoding, X25519 accepts inputs on the quadratic twist, which don't correspond // to any edwards25519 point, and every other X25519 input corresponds to two // edwards25519 points. func (v *Point) BytesMontgomery() []byte { // This function is outlined to make the allocations inline in the caller // rather than happen on the heap. var buf [32]byte return v.bytesMontgomery(&buf) } func (v *Point) bytesMontgomery(buf *[32]byte) []byte { checkInitialized(v) // RFC 7748, Section 4.1 provides the bilinear map to calculate the // Montgomery u-coordinate // // u = (1 + y) / (1 - y) // // where y = Y / Z. var y, recip, u field.Element y.Multiply(&v.y, y.Invert(&v.z)) // y = Y / Z recip.Invert(recip.Subtract(feOne, &y)) // r = 1/(1 - y) u.Multiply(u.Add(feOne, &y), &recip) // u = (1 + y)*r return copyFieldElement(buf, &u) } // MultByCofactor sets v = 8 * p, and returns v. func (v *Point) MultByCofactor(p *Point) *Point { checkInitialized(p) result := projP1xP1{} pp := (&projP2{}).FromP3(p) result.Double(pp) pp.FromP1xP1(&result) result.Double(pp) pp.FromP1xP1(&result) result.Double(pp) return v.fromP1xP1(&result) } // Given k > 0, set s = s**(2*i). func (s *Scalar) pow2k(k int) { for i := 0; i < k; i++ { s.Multiply(s, s) } } // Invert sets s to the inverse of a nonzero scalar v, and returns s. // // If t is zero, Invert returns zero. func (s *Scalar) Invert(t *Scalar) *Scalar { // Uses a hardcoded sliding window of width 4. var table [8]Scalar var tt Scalar tt.Multiply(t, t) table[0] = *t for i := 0; i < 7; i++ { table[i+1].Multiply(&table[i], &tt) } // Now table = [t**1, t**3, t**5, t**7, t**9, t**11, t**13, t**15] // so t**k = t[k/2] for odd k // To compute the sliding window digits, use the following Sage script: // sage: import itertools // sage: def sliding_window(w,k): // ....: digits = [] // ....: while k > 0: // ....: if k % 2 == 1: // ....: kmod = k % (2**w) // ....: digits.append(kmod) // ....: k = k - kmod // ....: else: // ....: digits.append(0) // ....: k = k // 2 // ....: return digits // Now we can compute s roughly as follows: // sage: s = 1 // sage: for coeff in reversed(sliding_window(4,l-2)): // ....: s = s*s // ....: if coeff > 0 : // ....: s = s*t**coeff // This works on one bit at a time, with many runs of zeros. // The digits can be collapsed into [(count, coeff)] as follows: // sage: [(len(list(group)),d) for d,group in itertools.groupby(sliding_window(4,l-2))] // Entries of the form (k, 0) turn into pow2k(k) // Entries of the form (1, coeff) turn into a squaring and then a table lookup. // We can fold the squaring into the previous pow2k(k) as pow2k(k+1). *s = table[1/2] s.pow2k(127 + 1) s.Multiply(s, &table[1/2]) s.pow2k(4 + 1) s.Multiply(s, &table[9/2]) s.pow2k(3 + 1) s.Multiply(s, &table[11/2]) s.pow2k(3 + 1) s.Multiply(s, &table[13/2]) s.pow2k(3 + 1) s.Multiply(s, &table[15/2]) s.pow2k(4 + 1) s.Multiply(s, &table[7/2]) s.pow2k(4 + 1) s.Multiply(s, &table[15/2]) s.pow2k(3 + 1) s.Multiply(s, &table[5/2]) s.pow2k(3 + 1) s.Multiply(s, &table[1/2]) s.pow2k(4 + 1) s.Multiply(s, &table[15/2]) s.pow2k(4 + 1) s.Multiply(s, &table[15/2]) s.pow2k(4 + 1) s.Multiply(s, &table[7/2]) s.pow2k(3 + 1) s.Multiply(s, &table[3/2]) s.pow2k(4 + 1) s.Multiply(s, &table[11/2]) s.pow2k(5 + 1) s.Multiply(s, &table[11/2]) s.pow2k(9 + 1) s.Multiply(s, &table[9/2]) s.pow2k(3 + 1) s.Multiply(s, &table[3/2]) s.pow2k(4 + 1) s.Multiply(s, &table[3/2]) s.pow2k(4 + 1) s.Multiply(s, &table[3/2]) s.pow2k(4 + 1) s.Multiply(s, &table[9/2]) s.pow2k(3 + 1) s.Multiply(s, &table[7/2]) s.pow2k(3 + 1) s.Multiply(s, &table[3/2]) s.pow2k(3 + 1) s.Multiply(s, &table[13/2]) s.pow2k(3 + 1) s.Multiply(s, &table[7/2]) s.pow2k(4 + 1) s.Multiply(s, &table[9/2]) s.pow2k(3 + 1) s.Multiply(s, &table[15/2]) s.pow2k(4 + 1) s.Multiply(s, &table[11/2]) return s } // MultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v. // // Execution time depends only on the lengths of the two slices, which must match. func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point { if len(scalars) != len(points) { panic("edwards25519: called MultiScalarMult with different size inputs") } checkInitialized(points...) // Proceed as in the single-base case, but share doublings // between each point in the multiscalar equation. // Build lookup tables for each point tables := make([]projLookupTable, len(points)) for i := range tables { tables[i].FromP3(points[i]) } // Compute signed radix-16 digits for each scalar digits := make([][64]int8, len(scalars)) for i := range digits { digits[i] = scalars[i].signedRadix16() } // Unwrap first loop iteration to save computing 16*identity multiple := &projCached{} tmp1 := &projP1xP1{} tmp2 := &projP2{} // Lookup-and-add the appropriate multiple of each input point for j := range tables { tables[j].SelectInto(multiple, digits[j][63]) tmp1.Add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords v.fromP1xP1(tmp1) // update v } tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration for i := 62; i >= 0; i-- { tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords // Lookup-and-add the appropriate multiple of each input point for j := range tables { tables[j].SelectInto(multiple, digits[j][i]) tmp1.Add(v, multiple) // tmp1 = v + x_(j,i)*Q in P1xP1 coords v.fromP1xP1(tmp1) // update v } tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration } return v } // VarTimeMultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v. // // Execution time depends on the inputs. func (v *Point) VarTimeMultiScalarMult(scalars []*Scalar, points []*Point) *Point { if len(scalars) != len(points) { panic("edwards25519: called VarTimeMultiScalarMult with different size inputs") } checkInitialized(points...) // Generalize double-base NAF computation to arbitrary sizes. // Here all the points are dynamic, so we only use the smaller // tables. // Build lookup tables for each point tables := make([]nafLookupTable5, len(points)) for i := range tables { tables[i].FromP3(points[i]) } // Compute a NAF for each scalar nafs := make([][256]int8, len(scalars)) for i := range nafs { nafs[i] = scalars[i].nonAdjacentForm(5) } multiple := &projCached{} tmp1 := &projP1xP1{} tmp2 := &projP2{} tmp2.Zero() // Move from high to low bits, doubling the accumulator // at each iteration and checking whether there is a nonzero // coefficient to look up a multiple of. // // Skip trying to find the first nonzero coefficent, because // searching might be more work than a few extra doublings. for i := 255; i >= 0; i-- { tmp1.Double(tmp2) for j := range nafs { if nafs[j][i] > 0 { v.fromP1xP1(tmp1) tables[j].SelectInto(multiple, nafs[j][i]) tmp1.Add(v, multiple) } else if nafs[j][i] < 0 { v.fromP1xP1(tmp1) tables[j].SelectInto(multiple, -nafs[j][i]) tmp1.Sub(v, multiple) } } tmp2.FromP1xP1(tmp1) } v.fromP2(tmp2) return v } ================================================ FILE: vendor/filippo.io/edwards25519/field/fe.go ================================================ // Copyright (c) 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package field implements fast arithmetic modulo 2^255-19. package field import ( "crypto/subtle" "encoding/binary" "errors" "math/bits" ) // Element represents an element of the field GF(2^255-19). Note that this // is not a cryptographically secure group, and should only be used to interact // with edwards25519.Point coordinates. // // This type works similarly to math/big.Int, and all arguments and receivers // are allowed to alias. // // The zero value is a valid zero element. type Element struct { // An element t represents the integer // t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204 // // Between operations, all limbs are expected to be lower than 2^52. l0 uint64 l1 uint64 l2 uint64 l3 uint64 l4 uint64 } const maskLow51Bits uint64 = (1 << 51) - 1 var feZero = &Element{0, 0, 0, 0, 0} // Zero sets v = 0, and returns v. func (v *Element) Zero() *Element { *v = *feZero return v } var feOne = &Element{1, 0, 0, 0, 0} // One sets v = 1, and returns v. func (v *Element) One() *Element { *v = *feOne return v } // reduce reduces v modulo 2^255 - 19 and returns it. func (v *Element) reduce() *Element { v.carryPropagate() // After the light reduction we now have a field element representation // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19. // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1, // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise. c := (v.l0 + 19) >> 51 c = (v.l1 + c) >> 51 c = (v.l2 + c) >> 51 c = (v.l3 + c) >> 51 c = (v.l4 + c) >> 51 // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's // effectively applying the reduction identity to the carry. v.l0 += 19 * c v.l1 += v.l0 >> 51 v.l0 = v.l0 & maskLow51Bits v.l2 += v.l1 >> 51 v.l1 = v.l1 & maskLow51Bits v.l3 += v.l2 >> 51 v.l2 = v.l2 & maskLow51Bits v.l4 += v.l3 >> 51 v.l3 = v.l3 & maskLow51Bits // no additional carry v.l4 = v.l4 & maskLow51Bits return v } // Add sets v = a + b, and returns v. func (v *Element) Add(a, b *Element) *Element { v.l0 = a.l0 + b.l0 v.l1 = a.l1 + b.l1 v.l2 = a.l2 + b.l2 v.l3 = a.l3 + b.l3 v.l4 = a.l4 + b.l4 // Using the generic implementation here is actually faster than the // assembly. Probably because the body of this function is so simple that // the compiler can figure out better optimizations by inlining the carry // propagation. return v.carryPropagateGeneric() } // Subtract sets v = a - b, and returns v. func (v *Element) Subtract(a, b *Element) *Element { // We first add 2 * p, to guarantee the subtraction won't underflow, and // then subtract b (which can be up to 2^255 + 2^13 * 19). v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0 v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1 v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2 v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3 v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4 return v.carryPropagate() } // Negate sets v = -a, and returns v. func (v *Element) Negate(a *Element) *Element { return v.Subtract(feZero, a) } // Invert sets v = 1/z mod p, and returns v. // // If z == 0, Invert returns v = 0. func (v *Element) Invert(z *Element) *Element { // Inversion is implemented as exponentiation with exponent p − 2. It uses the // same sequence of 255 squarings and 11 multiplications as [Curve25519]. var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element z2.Square(z) // 2 t.Square(&z2) // 4 t.Square(&t) // 8 z9.Multiply(&t, z) // 9 z11.Multiply(&z9, &z2) // 11 t.Square(&z11) // 22 z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0 t.Square(&z2_5_0) // 2^6 - 2^1 for i := 0; i < 4; i++ { t.Square(&t) // 2^10 - 2^5 } z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0 t.Square(&z2_10_0) // 2^11 - 2^1 for i := 0; i < 9; i++ { t.Square(&t) // 2^20 - 2^10 } z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0 t.Square(&z2_20_0) // 2^21 - 2^1 for i := 0; i < 19; i++ { t.Square(&t) // 2^40 - 2^20 } t.Multiply(&t, &z2_20_0) // 2^40 - 2^0 t.Square(&t) // 2^41 - 2^1 for i := 0; i < 9; i++ { t.Square(&t) // 2^50 - 2^10 } z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0 t.Square(&z2_50_0) // 2^51 - 2^1 for i := 0; i < 49; i++ { t.Square(&t) // 2^100 - 2^50 } z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0 t.Square(&z2_100_0) // 2^101 - 2^1 for i := 0; i < 99; i++ { t.Square(&t) // 2^200 - 2^100 } t.Multiply(&t, &z2_100_0) // 2^200 - 2^0 t.Square(&t) // 2^201 - 2^1 for i := 0; i < 49; i++ { t.Square(&t) // 2^250 - 2^50 } t.Multiply(&t, &z2_50_0) // 2^250 - 2^0 t.Square(&t) // 2^251 - 2^1 t.Square(&t) // 2^252 - 2^2 t.Square(&t) // 2^253 - 2^3 t.Square(&t) // 2^254 - 2^4 t.Square(&t) // 2^255 - 2^5 return v.Multiply(&t, &z11) // 2^255 - 21 } // Set sets v = a, and returns v. func (v *Element) Set(a *Element) *Element { *v = *a return v } // SetBytes sets v to x, where x is a 32-byte little-endian encoding. If x is // not of the right length, SetBytes returns nil and an error, and the // receiver is unchanged. // // Consistent with RFC 7748, the most significant bit (the high bit of the // last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1) // are accepted. Note that this is laxer than specified by RFC 8032, but // consistent with most Ed25519 implementations. func (v *Element) SetBytes(x []byte) (*Element, error) { if len(x) != 32 { return nil, errors.New("edwards25519: invalid field element input size") } // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51). v.l0 = binary.LittleEndian.Uint64(x[0:8]) v.l0 &= maskLow51Bits // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51). v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3 v.l1 &= maskLow51Bits // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51). v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6 v.l2 &= maskLow51Bits // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51). v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1 v.l3 &= maskLow51Bits // Bits 204:255 (bytes 24:32, bits 192:256, shift 12, mask 51). // Note: not bytes 25:33, shift 4, to avoid overread. v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12 v.l4 &= maskLow51Bits return v, nil } // Bytes returns the canonical 32-byte little-endian encoding of v. func (v *Element) Bytes() []byte { // This function is outlined to make the allocations inline in the caller // rather than happen on the heap. var out [32]byte return v.bytes(&out) } func (v *Element) bytes(out *[32]byte) []byte { t := *v t.reduce() var buf [8]byte for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} { bitsOffset := i * 51 binary.LittleEndian.PutUint64(buf[:], l<= len(out) { break } out[off] |= bb } } return out[:] } // Equal returns 1 if v and u are equal, and 0 otherwise. func (v *Element) Equal(u *Element) int { sa, sv := u.Bytes(), v.Bytes() return subtle.ConstantTimeCompare(sa, sv) } // mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise. func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) } // Select sets v to a if cond == 1, and to b if cond == 0. func (v *Element) Select(a, b *Element, cond int) *Element { m := mask64Bits(cond) v.l0 = (m & a.l0) | (^m & b.l0) v.l1 = (m & a.l1) | (^m & b.l1) v.l2 = (m & a.l2) | (^m & b.l2) v.l3 = (m & a.l3) | (^m & b.l3) v.l4 = (m & a.l4) | (^m & b.l4) return v } // Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v. func (v *Element) Swap(u *Element, cond int) { m := mask64Bits(cond) t := m & (v.l0 ^ u.l0) v.l0 ^= t u.l0 ^= t t = m & (v.l1 ^ u.l1) v.l1 ^= t u.l1 ^= t t = m & (v.l2 ^ u.l2) v.l2 ^= t u.l2 ^= t t = m & (v.l3 ^ u.l3) v.l3 ^= t u.l3 ^= t t = m & (v.l4 ^ u.l4) v.l4 ^= t u.l4 ^= t } // IsNegative returns 1 if v is negative, and 0 otherwise. func (v *Element) IsNegative() int { return int(v.Bytes()[0] & 1) } // Absolute sets v to |u|, and returns v. func (v *Element) Absolute(u *Element) *Element { return v.Select(new(Element).Negate(u), u, u.IsNegative()) } // Multiply sets v = x * y, and returns v. func (v *Element) Multiply(x, y *Element) *Element { feMul(v, x, y) return v } // Square sets v = x * x, and returns v. func (v *Element) Square(x *Element) *Element { feSquare(v, x) return v } // Mult32 sets v = x * y, and returns v. func (v *Element) Mult32(x *Element, y uint32) *Element { x0lo, x0hi := mul51(x.l0, y) x1lo, x1hi := mul51(x.l1, y) x2lo, x2hi := mul51(x.l2, y) x3lo, x3hi := mul51(x.l3, y) x4lo, x4hi := mul51(x.l4, y) v.l0 = x0lo + 19*x4hi // carried over per the reduction identity v.l1 = x1lo + x0hi v.l2 = x2lo + x1hi v.l3 = x3lo + x2hi v.l4 = x4lo + x3hi // The hi portions are going to be only 32 bits, plus any previous excess, // so we can skip the carry propagation. return v } // mul51 returns lo + hi * 2⁵¹ = a * b. func mul51(a uint64, b uint32) (lo uint64, hi uint64) { mh, ml := bits.Mul64(a, uint64(b)) lo = ml & maskLow51Bits hi = (mh << 13) | (ml >> 51) return } // Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3. func (v *Element) Pow22523(x *Element) *Element { var t0, t1, t2 Element t0.Square(x) // x^2 t1.Square(&t0) // x^4 t1.Square(&t1) // x^8 t1.Multiply(x, &t1) // x^9 t0.Multiply(&t0, &t1) // x^11 t0.Square(&t0) // x^22 t0.Multiply(&t1, &t0) // x^31 t1.Square(&t0) // x^62 for i := 1; i < 5; i++ { // x^992 t1.Square(&t1) } t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1 t1.Square(&t0) // 2^11 - 2 for i := 1; i < 10; i++ { // 2^20 - 2^10 t1.Square(&t1) } t1.Multiply(&t1, &t0) // 2^20 - 1 t2.Square(&t1) // 2^21 - 2 for i := 1; i < 20; i++ { // 2^40 - 2^20 t2.Square(&t2) } t1.Multiply(&t2, &t1) // 2^40 - 1 t1.Square(&t1) // 2^41 - 2 for i := 1; i < 10; i++ { // 2^50 - 2^10 t1.Square(&t1) } t0.Multiply(&t1, &t0) // 2^50 - 1 t1.Square(&t0) // 2^51 - 2 for i := 1; i < 50; i++ { // 2^100 - 2^50 t1.Square(&t1) } t1.Multiply(&t1, &t0) // 2^100 - 1 t2.Square(&t1) // 2^101 - 2 for i := 1; i < 100; i++ { // 2^200 - 2^100 t2.Square(&t2) } t1.Multiply(&t2, &t1) // 2^200 - 1 t1.Square(&t1) // 2^201 - 2 for i := 1; i < 50; i++ { // 2^250 - 2^50 t1.Square(&t1) } t0.Multiply(&t1, &t0) // 2^250 - 1 t0.Square(&t0) // 2^251 - 2 t0.Square(&t0) // 2^252 - 4 return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3) } // sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion. var sqrtM1 = &Element{1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133} // SqrtRatio sets r to the non-negative square root of the ratio of u and v. // // If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio // sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00, // and returns r and 0. func (r *Element) SqrtRatio(u, v *Element) (R *Element, wasSquare int) { t0 := new(Element) // r = (u * v3) * (u * v7)^((p-5)/8) v2 := new(Element).Square(v) uv3 := new(Element).Multiply(u, t0.Multiply(v2, v)) uv7 := new(Element).Multiply(uv3, t0.Square(v2)) rr := new(Element).Multiply(uv3, t0.Pow22523(uv7)) check := new(Element).Multiply(v, t0.Square(rr)) // check = v * r^2 uNeg := new(Element).Negate(u) correctSignSqrt := check.Equal(u) flippedSignSqrt := check.Equal(uNeg) flippedSignSqrtI := check.Equal(t0.Multiply(uNeg, sqrtM1)) rPrime := new(Element).Multiply(rr, sqrtM1) // r_prime = SQRT_M1 * r // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r) rr.Select(rPrime, rr, flippedSignSqrt|flippedSignSqrtI) r.Absolute(rr) // Choose the nonnegative square root. return r, correctSignSqrt | flippedSignSqrt } ================================================ FILE: vendor/filippo.io/edwards25519/field/fe_amd64.go ================================================ // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. //go:build amd64 && gc && !purego // +build amd64,gc,!purego package field // feMul sets out = a * b. It works like feMulGeneric. // //go:noescape func feMul(out *Element, a *Element, b *Element) // feSquare sets out = a * a. It works like feSquareGeneric. // //go:noescape func feSquare(out *Element, a *Element) ================================================ FILE: vendor/filippo.io/edwards25519/field/fe_amd64.s ================================================ // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. //go:build amd64 && gc && !purego // +build amd64,gc,!purego #include "textflag.h" // func feMul(out *Element, a *Element, b *Element) TEXT ·feMul(SB), NOSPLIT, $0-24 MOVQ a+8(FP), CX MOVQ b+16(FP), BX // r0 = a0×b0 MOVQ (CX), AX MULQ (BX) MOVQ AX, DI MOVQ DX, SI // r0 += 19×a1×b4 MOVQ 8(CX), AX IMUL3Q $0x13, AX, AX MULQ 32(BX) ADDQ AX, DI ADCQ DX, SI // r0 += 19×a2×b3 MOVQ 16(CX), AX IMUL3Q $0x13, AX, AX MULQ 24(BX) ADDQ AX, DI ADCQ DX, SI // r0 += 19×a3×b2 MOVQ 24(CX), AX IMUL3Q $0x13, AX, AX MULQ 16(BX) ADDQ AX, DI ADCQ DX, SI // r0 += 19×a4×b1 MOVQ 32(CX), AX IMUL3Q $0x13, AX, AX MULQ 8(BX) ADDQ AX, DI ADCQ DX, SI // r1 = a0×b1 MOVQ (CX), AX MULQ 8(BX) MOVQ AX, R9 MOVQ DX, R8 // r1 += a1×b0 MOVQ 8(CX), AX MULQ (BX) ADDQ AX, R9 ADCQ DX, R8 // r1 += 19×a2×b4 MOVQ 16(CX), AX IMUL3Q $0x13, AX, AX MULQ 32(BX) ADDQ AX, R9 ADCQ DX, R8 // r1 += 19×a3×b3 MOVQ 24(CX), AX IMUL3Q $0x13, AX, AX MULQ 24(BX) ADDQ AX, R9 ADCQ DX, R8 // r1 += 19×a4×b2 MOVQ 32(CX), AX IMUL3Q $0x13, AX, AX MULQ 16(BX) ADDQ AX, R9 ADCQ DX, R8 // r2 = a0×b2 MOVQ (CX), AX MULQ 16(BX) MOVQ AX, R11 MOVQ DX, R10 // r2 += a1×b1 MOVQ 8(CX), AX MULQ 8(BX) ADDQ AX, R11 ADCQ DX, R10 // r2 += a2×b0 MOVQ 16(CX), AX MULQ (BX) ADDQ AX, R11 ADCQ DX, R10 // r2 += 19×a3×b4 MOVQ 24(CX), AX IMUL3Q $0x13, AX, AX MULQ 32(BX) ADDQ AX, R11 ADCQ DX, R10 // r2 += 19×a4×b3 MOVQ 32(CX), AX IMUL3Q $0x13, AX, AX MULQ 24(BX) ADDQ AX, R11 ADCQ DX, R10 // r3 = a0×b3 MOVQ (CX), AX MULQ 24(BX) MOVQ AX, R13 MOVQ DX, R12 // r3 += a1×b2 MOVQ 8(CX), AX MULQ 16(BX) ADDQ AX, R13 ADCQ DX, R12 // r3 += a2×b1 MOVQ 16(CX), AX MULQ 8(BX) ADDQ AX, R13 ADCQ DX, R12 // r3 += a3×b0 MOVQ 24(CX), AX MULQ (BX) ADDQ AX, R13 ADCQ DX, R12 // r3 += 19×a4×b4 MOVQ 32(CX), AX IMUL3Q $0x13, AX, AX MULQ 32(BX) ADDQ AX, R13 ADCQ DX, R12 // r4 = a0×b4 MOVQ (CX), AX MULQ 32(BX) MOVQ AX, R15 MOVQ DX, R14 // r4 += a1×b3 MOVQ 8(CX), AX MULQ 24(BX) ADDQ AX, R15 ADCQ DX, R14 // r4 += a2×b2 MOVQ 16(CX), AX MULQ 16(BX) ADDQ AX, R15 ADCQ DX, R14 // r4 += a3×b1 MOVQ 24(CX), AX MULQ 8(BX) ADDQ AX, R15 ADCQ DX, R14 // r4 += a4×b0 MOVQ 32(CX), AX MULQ (BX) ADDQ AX, R15 ADCQ DX, R14 // First reduction chain MOVQ $0x0007ffffffffffff, AX SHLQ $0x0d, DI, SI SHLQ $0x0d, R9, R8 SHLQ $0x0d, R11, R10 SHLQ $0x0d, R13, R12 SHLQ $0x0d, R15, R14 ANDQ AX, DI IMUL3Q $0x13, R14, R14 ADDQ R14, DI ANDQ AX, R9 ADDQ SI, R9 ANDQ AX, R11 ADDQ R8, R11 ANDQ AX, R13 ADDQ R10, R13 ANDQ AX, R15 ADDQ R12, R15 // Second reduction chain (carryPropagate) MOVQ DI, SI SHRQ $0x33, SI MOVQ R9, R8 SHRQ $0x33, R8 MOVQ R11, R10 SHRQ $0x33, R10 MOVQ R13, R12 SHRQ $0x33, R12 MOVQ R15, R14 SHRQ $0x33, R14 ANDQ AX, DI IMUL3Q $0x13, R14, R14 ADDQ R14, DI ANDQ AX, R9 ADDQ SI, R9 ANDQ AX, R11 ADDQ R8, R11 ANDQ AX, R13 ADDQ R10, R13 ANDQ AX, R15 ADDQ R12, R15 // Store output MOVQ out+0(FP), AX MOVQ DI, (AX) MOVQ R9, 8(AX) MOVQ R11, 16(AX) MOVQ R13, 24(AX) MOVQ R15, 32(AX) RET // func feSquare(out *Element, a *Element) TEXT ·feSquare(SB), NOSPLIT, $0-16 MOVQ a+8(FP), CX // r0 = l0×l0 MOVQ (CX), AX MULQ (CX) MOVQ AX, SI MOVQ DX, BX // r0 += 38×l1×l4 MOVQ 8(CX), AX IMUL3Q $0x26, AX, AX MULQ 32(CX) ADDQ AX, SI ADCQ DX, BX // r0 += 38×l2×l3 MOVQ 16(CX), AX IMUL3Q $0x26, AX, AX MULQ 24(CX) ADDQ AX, SI ADCQ DX, BX // r1 = 2×l0×l1 MOVQ (CX), AX SHLQ $0x01, AX MULQ 8(CX) MOVQ AX, R8 MOVQ DX, DI // r1 += 38×l2×l4 MOVQ 16(CX), AX IMUL3Q $0x26, AX, AX MULQ 32(CX) ADDQ AX, R8 ADCQ DX, DI // r1 += 19×l3×l3 MOVQ 24(CX), AX IMUL3Q $0x13, AX, AX MULQ 24(CX) ADDQ AX, R8 ADCQ DX, DI // r2 = 2×l0×l2 MOVQ (CX), AX SHLQ $0x01, AX MULQ 16(CX) MOVQ AX, R10 MOVQ DX, R9 // r2 += l1×l1 MOVQ 8(CX), AX MULQ 8(CX) ADDQ AX, R10 ADCQ DX, R9 // r2 += 38×l3×l4 MOVQ 24(CX), AX IMUL3Q $0x26, AX, AX MULQ 32(CX) ADDQ AX, R10 ADCQ DX, R9 // r3 = 2×l0×l3 MOVQ (CX), AX SHLQ $0x01, AX MULQ 24(CX) MOVQ AX, R12 MOVQ DX, R11 // r3 += 2×l1×l2 MOVQ 8(CX), AX IMUL3Q $0x02, AX, AX MULQ 16(CX) ADDQ AX, R12 ADCQ DX, R11 // r3 += 19×l4×l4 MOVQ 32(CX), AX IMUL3Q $0x13, AX, AX MULQ 32(CX) ADDQ AX, R12 ADCQ DX, R11 // r4 = 2×l0×l4 MOVQ (CX), AX SHLQ $0x01, AX MULQ 32(CX) MOVQ AX, R14 MOVQ DX, R13 // r4 += 2×l1×l3 MOVQ 8(CX), AX IMUL3Q $0x02, AX, AX MULQ 24(CX) ADDQ AX, R14 ADCQ DX, R13 // r4 += l2×l2 MOVQ 16(CX), AX MULQ 16(CX) ADDQ AX, R14 ADCQ DX, R13 // First reduction chain MOVQ $0x0007ffffffffffff, AX SHLQ $0x0d, SI, BX SHLQ $0x0d, R8, DI SHLQ $0x0d, R10, R9 SHLQ $0x0d, R12, R11 SHLQ $0x0d, R14, R13 ANDQ AX, SI IMUL3Q $0x13, R13, R13 ADDQ R13, SI ANDQ AX, R8 ADDQ BX, R8 ANDQ AX, R10 ADDQ DI, R10 ANDQ AX, R12 ADDQ R9, R12 ANDQ AX, R14 ADDQ R11, R14 // Second reduction chain (carryPropagate) MOVQ SI, BX SHRQ $0x33, BX MOVQ R8, DI SHRQ $0x33, DI MOVQ R10, R9 SHRQ $0x33, R9 MOVQ R12, R11 SHRQ $0x33, R11 MOVQ R14, R13 SHRQ $0x33, R13 ANDQ AX, SI IMUL3Q $0x13, R13, R13 ADDQ R13, SI ANDQ AX, R8 ADDQ BX, R8 ANDQ AX, R10 ADDQ DI, R10 ANDQ AX, R12 ADDQ R9, R12 ANDQ AX, R14 ADDQ R11, R14 // Store output MOVQ out+0(FP), AX MOVQ SI, (AX) MOVQ R8, 8(AX) MOVQ R10, 16(AX) MOVQ R12, 24(AX) MOVQ R14, 32(AX) RET ================================================ FILE: vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go ================================================ // Copyright (c) 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !amd64 || !gc || purego // +build !amd64 !gc purego package field func feMul(v, x, y *Element) { feMulGeneric(v, x, y) } func feSquare(v, x *Element) { feSquareGeneric(v, x) } ================================================ FILE: vendor/filippo.io/edwards25519/field/fe_arm64.go ================================================ // Copyright (c) 2020 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build arm64 && gc && !purego // +build arm64,gc,!purego package field //go:noescape func carryPropagate(v *Element) func (v *Element) carryPropagate() *Element { carryPropagate(v) return v } ================================================ FILE: vendor/filippo.io/edwards25519/field/fe_arm64.s ================================================ // Copyright (c) 2020 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build arm64 && gc && !purego #include "textflag.h" // carryPropagate works exactly like carryPropagateGeneric and uses the // same AND, ADD, and LSR+MADD instructions emitted by the compiler, but // avoids loading R0-R4 twice and uses LDP and STP. // // See https://golang.org/issues/43145 for the main compiler issue. // // func carryPropagate(v *Element) TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8 MOVD v+0(FP), R20 LDP 0(R20), (R0, R1) LDP 16(R20), (R2, R3) MOVD 32(R20), R4 AND $0x7ffffffffffff, R0, R10 AND $0x7ffffffffffff, R1, R11 AND $0x7ffffffffffff, R2, R12 AND $0x7ffffffffffff, R3, R13 AND $0x7ffffffffffff, R4, R14 ADD R0>>51, R11, R11 ADD R1>>51, R12, R12 ADD R2>>51, R13, R13 ADD R3>>51, R14, R14 // R4>>51 * 19 + R10 -> R10 LSR $51, R4, R21 MOVD $19, R22 MADD R22, R10, R21, R10 STP (R10, R11), 0(R20) STP (R12, R13), 16(R20) MOVD R14, 32(R20) RET ================================================ FILE: vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go ================================================ // Copyright (c) 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !arm64 || !gc || purego // +build !arm64 !gc purego package field func (v *Element) carryPropagate() *Element { return v.carryPropagateGeneric() } ================================================ FILE: vendor/filippo.io/edwards25519/field/fe_extra.go ================================================ // Copyright (c) 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package field import "errors" // This file contains additional functionality that is not included in the // upstream crypto/ed25519/edwards25519/field package. // SetWideBytes sets v to x, where x is a 64-byte little-endian encoding, which // is reduced modulo the field order. If x is not of the right length, // SetWideBytes returns nil and an error, and the receiver is unchanged. // // SetWideBytes is not necessary to select a uniformly distributed value, and is // only provided for compatibility: SetBytes can be used instead as the chance // of bias is less than 2⁻²⁵⁰. func (v *Element) SetWideBytes(x []byte) (*Element, error) { if len(x) != 64 { return nil, errors.New("edwards25519: invalid SetWideBytes input size") } // Split the 64 bytes into two elements, and extract the most significant // bit of each, which is ignored by SetBytes. lo, _ := new(Element).SetBytes(x[:32]) loMSB := uint64(x[31] >> 7) hi, _ := new(Element).SetBytes(x[32:]) hiMSB := uint64(x[63] >> 7) // The output we want is // // v = lo + loMSB * 2²⁵⁵ + hi * 2²⁵⁶ + hiMSB * 2⁵¹¹ // // which applying the reduction identity comes out to // // v = lo + loMSB * 19 + hi * 2 * 19 + hiMSB * 2 * 19² // // l0 will be the sum of a 52 bits value (lo.l0), plus a 5 bits value // (loMSB * 19), a 6 bits value (hi.l0 * 2 * 19), and a 10 bits value // (hiMSB * 2 * 19²), so it fits in a uint64. v.l0 = lo.l0 + loMSB*19 + hi.l0*2*19 + hiMSB*2*19*19 v.l1 = lo.l1 + hi.l1*2*19 v.l2 = lo.l2 + hi.l2*2*19 v.l3 = lo.l3 + hi.l3*2*19 v.l4 = lo.l4 + hi.l4*2*19 return v.carryPropagate(), nil } ================================================ FILE: vendor/filippo.io/edwards25519/field/fe_generic.go ================================================ // Copyright (c) 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package field import "math/bits" // uint128 holds a 128-bit number as two 64-bit limbs, for use with the // bits.Mul64 and bits.Add64 intrinsics. type uint128 struct { lo, hi uint64 } // mul64 returns a * b. func mul64(a, b uint64) uint128 { hi, lo := bits.Mul64(a, b) return uint128{lo, hi} } // addMul64 returns v + a * b. func addMul64(v uint128, a, b uint64) uint128 { hi, lo := bits.Mul64(a, b) lo, c := bits.Add64(lo, v.lo, 0) hi, _ = bits.Add64(hi, v.hi, c) return uint128{lo, hi} } // shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits. func shiftRightBy51(a uint128) uint64 { return (a.hi << (64 - 51)) | (a.lo >> 51) } func feMulGeneric(v, a, b *Element) { a0 := a.l0 a1 := a.l1 a2 := a.l2 a3 := a.l3 a4 := a.l4 b0 := b.l0 b1 := b.l1 b2 := b.l2 b3 := b.l3 b4 := b.l4 // Limb multiplication works like pen-and-paper columnar multiplication, but // with 51-bit limbs instead of digits. // // a4 a3 a2 a1 a0 x // b4 b3 b2 b1 b0 = // ------------------------ // a4b0 a3b0 a2b0 a1b0 a0b0 + // a4b1 a3b1 a2b1 a1b1 a0b1 + // a4b2 a3b2 a2b2 a1b2 a0b2 + // a4b3 a3b3 a2b3 a1b3 a0b3 + // a4b4 a3b4 a2b4 a1b4 a0b4 = // ---------------------------------------------- // r8 r7 r6 r5 r4 r3 r2 r1 r0 // // We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to // reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5, // r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc. // // Reduction can be carried out simultaneously to multiplication. For // example, we do not compute r5: whenever the result of a multiplication // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0. // // a4b0 a3b0 a2b0 a1b0 a0b0 + // a3b1 a2b1 a1b1 a0b1 19×a4b1 + // a2b2 a1b2 a0b2 19×a4b2 19×a3b2 + // a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 + // a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 = // -------------------------------------- // r4 r3 r2 r1 r0 // // Finally we add up the columns into wide, overlapping limbs. a1_19 := a1 * 19 a2_19 := a2 * 19 a3_19 := a3 * 19 a4_19 := a4 * 19 // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) r0 := mul64(a0, b0) r0 = addMul64(r0, a1_19, b4) r0 = addMul64(r0, a2_19, b3) r0 = addMul64(r0, a3_19, b2) r0 = addMul64(r0, a4_19, b1) // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2) r1 := mul64(a0, b1) r1 = addMul64(r1, a1, b0) r1 = addMul64(r1, a2_19, b4) r1 = addMul64(r1, a3_19, b3) r1 = addMul64(r1, a4_19, b2) // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3) r2 := mul64(a0, b2) r2 = addMul64(r2, a1, b1) r2 = addMul64(r2, a2, b0) r2 = addMul64(r2, a3_19, b4) r2 = addMul64(r2, a4_19, b3) // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4 r3 := mul64(a0, b3) r3 = addMul64(r3, a1, b2) r3 = addMul64(r3, a2, b1) r3 = addMul64(r3, a3, b0) r3 = addMul64(r3, a4_19, b4) // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 r4 := mul64(a0, b4) r4 = addMul64(r4, a1, b3) r4 = addMul64(r4, a2, b2) r4 = addMul64(r4, a3, b1) r4 = addMul64(r4, a4, b0) // After the multiplication, we need to reduce (carry) the five coefficients // to obtain a result with limbs that are at most slightly larger than 2⁵¹, // to respect the Element invariant. // // Overall, the reduction works the same as carryPropagate, except with // wider inputs: we take the carry for each coefficient by shifting it right // by 51, and add it to the limb above it. The top carry is multiplied by 19 // according to the reduction identity and added to the lowest limb. // // The largest coefficient (r0) will be at most 111 bits, which guarantees // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64. // // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) // r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²) // r0 < (1 + 19 × 4) × 2⁵² × 2⁵² // r0 < 2⁷ × 2⁵² × 2⁵² // r0 < 2¹¹¹ // // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and // allows us to easily apply the reduction identity. // // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 // r4 < 5 × 2⁵² × 2⁵² // r4 < 2¹⁰⁷ // c0 := shiftRightBy51(r0) c1 := shiftRightBy51(r1) c2 := shiftRightBy51(r2) c3 := shiftRightBy51(r3) c4 := shiftRightBy51(r4) rr0 := r0.lo&maskLow51Bits + c4*19 rr1 := r1.lo&maskLow51Bits + c0 rr2 := r2.lo&maskLow51Bits + c1 rr3 := r3.lo&maskLow51Bits + c2 rr4 := r4.lo&maskLow51Bits + c3 // Now all coefficients fit into 64-bit registers but are still too large to // be passed around as an Element. We therefore do one last carry chain, // where the carries will be small enough to fit in the wiggle room above 2⁵¹. *v = Element{rr0, rr1, rr2, rr3, rr4} v.carryPropagate() } func feSquareGeneric(v, a *Element) { l0 := a.l0 l1 := a.l1 l2 := a.l2 l3 := a.l3 l4 := a.l4 // Squaring works precisely like multiplication above, but thanks to its // symmetry we get to group a few terms together. // // l4 l3 l2 l1 l0 x // l4 l3 l2 l1 l0 = // ------------------------ // l4l0 l3l0 l2l0 l1l0 l0l0 + // l4l1 l3l1 l2l1 l1l1 l0l1 + // l4l2 l3l2 l2l2 l1l2 l0l2 + // l4l3 l3l3 l2l3 l1l3 l0l3 + // l4l4 l3l4 l2l4 l1l4 l0l4 = // ---------------------------------------------- // r8 r7 r6 r5 r4 r3 r2 r1 r0 // // l4l0 l3l0 l2l0 l1l0 l0l0 + // l3l1 l2l1 l1l1 l0l1 19×l4l1 + // l2l2 l1l2 l0l2 19×l4l2 19×l3l2 + // l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 + // l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 = // -------------------------------------- // r4 r3 r2 r1 r0 // // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with // only three Mul64 and four Add64, instead of five and eight. l0_2 := l0 * 2 l1_2 := l1 * 2 l1_38 := l1 * 38 l2_38 := l2 * 38 l3_38 := l3 * 38 l3_19 := l3 * 19 l4_19 := l4 * 19 // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3) r0 := mul64(l0, l0) r0 = addMul64(r0, l1_38, l4) r0 = addMul64(r0, l2_38, l3) // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3 r1 := mul64(l0_2, l1) r1 = addMul64(r1, l2_38, l4) r1 = addMul64(r1, l3_19, l3) // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4 r2 := mul64(l0_2, l2) r2 = addMul64(r2, l1, l1) r2 = addMul64(r2, l3_38, l4) // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4 r3 := mul64(l0_2, l3) r3 = addMul64(r3, l1_2, l2) r3 = addMul64(r3, l4_19, l4) // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2 r4 := mul64(l0_2, l4) r4 = addMul64(r4, l1_2, l3) r4 = addMul64(r4, l2, l2) c0 := shiftRightBy51(r0) c1 := shiftRightBy51(r1) c2 := shiftRightBy51(r2) c3 := shiftRightBy51(r3) c4 := shiftRightBy51(r4) rr0 := r0.lo&maskLow51Bits + c4*19 rr1 := r1.lo&maskLow51Bits + c0 rr2 := r2.lo&maskLow51Bits + c1 rr3 := r3.lo&maskLow51Bits + c2 rr4 := r4.lo&maskLow51Bits + c3 *v = Element{rr0, rr1, rr2, rr3, rr4} v.carryPropagate() } // carryPropagateGeneric brings the limbs below 52 bits by applying the reduction // identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. func (v *Element) carryPropagateGeneric() *Element { c0 := v.l0 >> 51 c1 := v.l1 >> 51 c2 := v.l2 >> 51 c3 := v.l3 >> 51 c4 := v.l4 >> 51 // c4 is at most 64 - 51 = 13 bits, so c4*19 is at most 18 bits, and // the final l0 will be at most 52 bits. Similarly for the rest. v.l0 = v.l0&maskLow51Bits + c4*19 v.l1 = v.l1&maskLow51Bits + c0 v.l2 = v.l2&maskLow51Bits + c1 v.l3 = v.l3&maskLow51Bits + c2 v.l4 = v.l4&maskLow51Bits + c3 return v } ================================================ FILE: vendor/filippo.io/edwards25519/scalar.go ================================================ // Copyright (c) 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package edwards25519 import ( "encoding/binary" "errors" ) // A Scalar is an integer modulo // // l = 2^252 + 27742317777372353535851937790883648493 // // which is the prime order of the edwards25519 group. // // This type works similarly to math/big.Int, and all arguments and // receivers are allowed to alias. // // The zero value is a valid zero element. type Scalar struct { // s is the scalar in the Montgomery domain, in the format of the // fiat-crypto implementation. s fiatScalarMontgomeryDomainFieldElement } // The field implementation in scalar_fiat.go is generated by the fiat-crypto // project (https://github.com/mit-plv/fiat-crypto) at version v0.0.9 (23d2dbc) // from a formally verified model. // // fiat-crypto code comes under the following license. // // Copyright (c) 2015-2020 The fiat-crypto Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, // Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // NewScalar returns a new zero Scalar. func NewScalar() *Scalar { return &Scalar{} } // MultiplyAdd sets s = x * y + z mod l, and returns s. It is equivalent to // using Multiply and then Add. func (s *Scalar) MultiplyAdd(x, y, z *Scalar) *Scalar { // Make a copy of z in case it aliases s. zCopy := new(Scalar).Set(z) return s.Multiply(x, y).Add(s, zCopy) } // Add sets s = x + y mod l, and returns s. func (s *Scalar) Add(x, y *Scalar) *Scalar { // s = 1 * x + y mod l fiatScalarAdd(&s.s, &x.s, &y.s) return s } // Subtract sets s = x - y mod l, and returns s. func (s *Scalar) Subtract(x, y *Scalar) *Scalar { // s = -1 * y + x mod l fiatScalarSub(&s.s, &x.s, &y.s) return s } // Negate sets s = -x mod l, and returns s. func (s *Scalar) Negate(x *Scalar) *Scalar { // s = -1 * x + 0 mod l fiatScalarOpp(&s.s, &x.s) return s } // Multiply sets s = x * y mod l, and returns s. func (s *Scalar) Multiply(x, y *Scalar) *Scalar { // s = x * y + 0 mod l fiatScalarMul(&s.s, &x.s, &y.s) return s } // Set sets s = x, and returns s. func (s *Scalar) Set(x *Scalar) *Scalar { *s = *x return s } // SetUniformBytes sets s = x mod l, where x is a 64-byte little-endian integer. // If x is not of the right length, SetUniformBytes returns nil and an error, // and the receiver is unchanged. // // SetUniformBytes can be used to set s to a uniformly distributed value given // 64 uniformly distributed random bytes. func (s *Scalar) SetUniformBytes(x []byte) (*Scalar, error) { if len(x) != 64 { return nil, errors.New("edwards25519: invalid SetUniformBytes input length") } // We have a value x of 512 bits, but our fiatScalarFromBytes function // expects an input lower than l, which is a little over 252 bits. // // Instead of writing a reduction function that operates on wider inputs, we // can interpret x as the sum of three shorter values a, b, and c. // // x = a + b * 2^168 + c * 2^336 mod l // // We then precompute 2^168 and 2^336 modulo l, and perform the reduction // with two multiplications and two additions. s.setShortBytes(x[:21]) t := new(Scalar).setShortBytes(x[21:42]) s.Add(s, t.Multiply(t, scalarTwo168)) t.setShortBytes(x[42:]) s.Add(s, t.Multiply(t, scalarTwo336)) return s, nil } // scalarTwo168 and scalarTwo336 are 2^168 and 2^336 modulo l, encoded as a // fiatScalarMontgomeryDomainFieldElement, which is a little-endian 4-limb value // in the 2^256 Montgomery domain. var scalarTwo168 = &Scalar{s: [4]uint64{0x5b8ab432eac74798, 0x38afddd6de59d5d7, 0xa2c131b399411b7c, 0x6329a7ed9ce5a30}} var scalarTwo336 = &Scalar{s: [4]uint64{0xbd3d108e2b35ecc5, 0x5c3a3718bdf9c90b, 0x63aa97a331b4f2ee, 0x3d217f5be65cb5c}} // setShortBytes sets s = x mod l, where x is a little-endian integer shorter // than 32 bytes. func (s *Scalar) setShortBytes(x []byte) *Scalar { if len(x) >= 32 { panic("edwards25519: internal error: setShortBytes called with a long string") } var buf [32]byte copy(buf[:], x) fiatScalarFromBytes((*[4]uint64)(&s.s), &buf) fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s)) return s } // SetCanonicalBytes sets s = x, where x is a 32-byte little-endian encoding of // s, and returns s. If x is not a canonical encoding of s, SetCanonicalBytes // returns nil and an error, and the receiver is unchanged. func (s *Scalar) SetCanonicalBytes(x []byte) (*Scalar, error) { if len(x) != 32 { return nil, errors.New("invalid scalar length") } if !isReduced(x) { return nil, errors.New("invalid scalar encoding") } fiatScalarFromBytes((*[4]uint64)(&s.s), (*[32]byte)(x)) fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s)) return s, nil } // scalarMinusOneBytes is l - 1 in little endian. var scalarMinusOneBytes = [32]byte{236, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16} // isReduced returns whether the given scalar in 32-byte little endian encoded // form is reduced modulo l. func isReduced(s []byte) bool { if len(s) != 32 { return false } for i := len(s) - 1; i >= 0; i-- { switch { case s[i] > scalarMinusOneBytes[i]: return false case s[i] < scalarMinusOneBytes[i]: return true } } return true } // SetBytesWithClamping applies the buffer pruning described in RFC 8032, // Section 5.1.5 (also known as clamping) and sets s to the result. The input // must be 32 bytes, and it is not modified. If x is not of the right length, // SetBytesWithClamping returns nil and an error, and the receiver is unchanged. // // Note that since Scalar values are always reduced modulo the prime order of // the curve, the resulting value will not preserve any of the cofactor-clearing // properties that clamping is meant to provide. It will however work as // expected as long as it is applied to points on the prime order subgroup, like // in Ed25519. In fact, it is lost to history why RFC 8032 adopted the // irrelevant RFC 7748 clamping, but it is now required for compatibility. func (s *Scalar) SetBytesWithClamping(x []byte) (*Scalar, error) { // The description above omits the purpose of the high bits of the clamping // for brevity, but those are also lost to reductions, and are also // irrelevant to edwards25519 as they protect against a specific // implementation bug that was once observed in a generic Montgomery ladder. if len(x) != 32 { return nil, errors.New("edwards25519: invalid SetBytesWithClamping input length") } // We need to use the wide reduction from SetUniformBytes, since clamping // sets the 2^254 bit, making the value higher than the order. var wideBytes [64]byte copy(wideBytes[:], x[:]) wideBytes[0] &= 248 wideBytes[31] &= 63 wideBytes[31] |= 64 return s.SetUniformBytes(wideBytes[:]) } // Bytes returns the canonical 32-byte little-endian encoding of s. func (s *Scalar) Bytes() []byte { // This function is outlined to make the allocations inline in the caller // rather than happen on the heap. var encoded [32]byte return s.bytes(&encoded) } func (s *Scalar) bytes(out *[32]byte) []byte { var ss fiatScalarNonMontgomeryDomainFieldElement fiatScalarFromMontgomery(&ss, &s.s) fiatScalarToBytes(out, (*[4]uint64)(&ss)) return out[:] } // Equal returns 1 if s and t are equal, and 0 otherwise. func (s *Scalar) Equal(t *Scalar) int { var diff fiatScalarMontgomeryDomainFieldElement fiatScalarSub(&diff, &s.s, &t.s) var nonzero uint64 fiatScalarNonzero(&nonzero, (*[4]uint64)(&diff)) nonzero |= nonzero >> 32 nonzero |= nonzero >> 16 nonzero |= nonzero >> 8 nonzero |= nonzero >> 4 nonzero |= nonzero >> 2 nonzero |= nonzero >> 1 return int(^nonzero) & 1 } // nonAdjacentForm computes a width-w non-adjacent form for this scalar. // // w must be between 2 and 8, or nonAdjacentForm will panic. func (s *Scalar) nonAdjacentForm(w uint) [256]int8 { // This implementation is adapted from the one // in curve25519-dalek and is documented there: // https://github.com/dalek-cryptography/curve25519-dalek/blob/f630041af28e9a405255f98a8a93adca18e4315b/src/scalar.rs#L800-L871 b := s.Bytes() if b[31] > 127 { panic("scalar has high bit set illegally") } if w < 2 { panic("w must be at least 2 by the definition of NAF") } else if w > 8 { panic("NAF digits must fit in int8") } var naf [256]int8 var digits [5]uint64 for i := 0; i < 4; i++ { digits[i] = binary.LittleEndian.Uint64(b[i*8:]) } width := uint64(1 << w) windowMask := uint64(width - 1) pos := uint(0) carry := uint64(0) for pos < 256 { indexU64 := pos / 64 indexBit := pos % 64 var bitBuf uint64 if indexBit < 64-w { // This window's bits are contained in a single u64 bitBuf = digits[indexU64] >> indexBit } else { // Combine the current 64 bits with bits from the next 64 bitBuf = (digits[indexU64] >> indexBit) | (digits[1+indexU64] << (64 - indexBit)) } // Add carry into the current window window := carry + (bitBuf & windowMask) if window&1 == 0 { // If the window value is even, preserve the carry and continue. // Why is the carry preserved? // If carry == 0 and window & 1 == 0, // then the next carry should be 0 // If carry == 1 and window & 1 == 0, // then bit_buf & 1 == 1 so the next carry should be 1 pos += 1 continue } if window < width/2 { carry = 0 naf[pos] = int8(window) } else { carry = 1 naf[pos] = int8(window) - int8(width) } pos += w } return naf } func (s *Scalar) signedRadix16() [64]int8 { b := s.Bytes() if b[31] > 127 { panic("scalar has high bit set illegally") } var digits [64]int8 // Compute unsigned radix-16 digits: for i := 0; i < 32; i++ { digits[2*i] = int8(b[i] & 15) digits[2*i+1] = int8((b[i] >> 4) & 15) } // Recenter coefficients: for i := 0; i < 63; i++ { carry := (digits[i] + 8) >> 4 digits[i] -= carry << 4 digits[i+1] += carry } return digits } ================================================ FILE: vendor/filippo.io/edwards25519/scalar_fiat.go ================================================ // Code generated by Fiat Cryptography. DO NOT EDIT. // // Autogenerated: word_by_word_montgomery --lang Go --cmovznz-by-mul --relax-primitive-carry-to-bitwidth 32,64 --public-function-case camelCase --public-type-case camelCase --private-function-case camelCase --private-type-case camelCase --doc-text-before-function-name '' --doc-newline-before-package-declaration --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --package-name edwards25519 Scalar 64 '2^252 + 27742317777372353535851937790883648493' mul add sub opp nonzero from_montgomery to_montgomery to_bytes from_bytes // // curve description: Scalar // // machine_wordsize = 64 (from "64") // // requested operations: mul, add, sub, opp, nonzero, from_montgomery, to_montgomery, to_bytes, from_bytes // // m = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed (from "2^252 + 27742317777372353535851937790883648493") // // // // NOTE: In addition to the bounds specified above each function, all // // functions synthesized for this Montgomery arithmetic require the // // input to be strictly less than the prime modulus (m), and also // // require the input to be in the unique saturated representation. // // All functions also ensure that these two properties are true of // // return values. // // // // Computed values: // // eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) // // bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) // // twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in // // if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 package edwards25519 import "math/bits" type fiatScalarUint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 type fiatScalarInt1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 // The type fiatScalarMontgomeryDomainFieldElement is a field element in the Montgomery domain. // // Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] type fiatScalarMontgomeryDomainFieldElement [4]uint64 // The type fiatScalarNonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain. // // Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] type fiatScalarNonMontgomeryDomainFieldElement [4]uint64 // fiatScalarCmovznzU64 is a single-word conditional move. // // Postconditions: // // out1 = (if arg1 = 0 then arg2 else arg3) // // Input Bounds: // // arg1: [0x0 ~> 0x1] // arg2: [0x0 ~> 0xffffffffffffffff] // arg3: [0x0 ~> 0xffffffffffffffff] // // Output Bounds: // // out1: [0x0 ~> 0xffffffffffffffff] func fiatScalarCmovznzU64(out1 *uint64, arg1 fiatScalarUint1, arg2 uint64, arg3 uint64) { x1 := (uint64(arg1) * 0xffffffffffffffff) x2 := ((x1 & arg3) | ((^x1) & arg2)) *out1 = x2 } // fiatScalarMul multiplies two field elements in the Montgomery domain. // // Preconditions: // // 0 ≤ eval arg1 < m // 0 ≤ eval arg2 < m // // Postconditions: // // eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m // 0 ≤ eval out1 < m func fiatScalarMul(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) { x1 := arg1[1] x2 := arg1[2] x3 := arg1[3] x4 := arg1[0] var x5 uint64 var x6 uint64 x6, x5 = bits.Mul64(x4, arg2[3]) var x7 uint64 var x8 uint64 x8, x7 = bits.Mul64(x4, arg2[2]) var x9 uint64 var x10 uint64 x10, x9 = bits.Mul64(x4, arg2[1]) var x11 uint64 var x12 uint64 x12, x11 = bits.Mul64(x4, arg2[0]) var x13 uint64 var x14 uint64 x13, x14 = bits.Add64(x12, x9, uint64(0x0)) var x15 uint64 var x16 uint64 x15, x16 = bits.Add64(x10, x7, uint64(fiatScalarUint1(x14))) var x17 uint64 var x18 uint64 x17, x18 = bits.Add64(x8, x5, uint64(fiatScalarUint1(x16))) x19 := (uint64(fiatScalarUint1(x18)) + x6) var x20 uint64 _, x20 = bits.Mul64(x11, 0xd2b51da312547e1b) var x22 uint64 var x23 uint64 x23, x22 = bits.Mul64(x20, 0x1000000000000000) var x24 uint64 var x25 uint64 x25, x24 = bits.Mul64(x20, 0x14def9dea2f79cd6) var x26 uint64 var x27 uint64 x27, x26 = bits.Mul64(x20, 0x5812631a5cf5d3ed) var x28 uint64 var x29 uint64 x28, x29 = bits.Add64(x27, x24, uint64(0x0)) x30 := (uint64(fiatScalarUint1(x29)) + x25) var x32 uint64 _, x32 = bits.Add64(x11, x26, uint64(0x0)) var x33 uint64 var x34 uint64 x33, x34 = bits.Add64(x13, x28, uint64(fiatScalarUint1(x32))) var x35 uint64 var x36 uint64 x35, x36 = bits.Add64(x15, x30, uint64(fiatScalarUint1(x34))) var x37 uint64 var x38 uint64 x37, x38 = bits.Add64(x17, x22, uint64(fiatScalarUint1(x36))) var x39 uint64 var x40 uint64 x39, x40 = bits.Add64(x19, x23, uint64(fiatScalarUint1(x38))) var x41 uint64 var x42 uint64 x42, x41 = bits.Mul64(x1, arg2[3]) var x43 uint64 var x44 uint64 x44, x43 = bits.Mul64(x1, arg2[2]) var x45 uint64 var x46 uint64 x46, x45 = bits.Mul64(x1, arg2[1]) var x47 uint64 var x48 uint64 x48, x47 = bits.Mul64(x1, arg2[0]) var x49 uint64 var x50 uint64 x49, x50 = bits.Add64(x48, x45, uint64(0x0)) var x51 uint64 var x52 uint64 x51, x52 = bits.Add64(x46, x43, uint64(fiatScalarUint1(x50))) var x53 uint64 var x54 uint64 x53, x54 = bits.Add64(x44, x41, uint64(fiatScalarUint1(x52))) x55 := (uint64(fiatScalarUint1(x54)) + x42) var x56 uint64 var x57 uint64 x56, x57 = bits.Add64(x33, x47, uint64(0x0)) var x58 uint64 var x59 uint64 x58, x59 = bits.Add64(x35, x49, uint64(fiatScalarUint1(x57))) var x60 uint64 var x61 uint64 x60, x61 = bits.Add64(x37, x51, uint64(fiatScalarUint1(x59))) var x62 uint64 var x63 uint64 x62, x63 = bits.Add64(x39, x53, uint64(fiatScalarUint1(x61))) var x64 uint64 var x65 uint64 x64, x65 = bits.Add64(uint64(fiatScalarUint1(x40)), x55, uint64(fiatScalarUint1(x63))) var x66 uint64 _, x66 = bits.Mul64(x56, 0xd2b51da312547e1b) var x68 uint64 var x69 uint64 x69, x68 = bits.Mul64(x66, 0x1000000000000000) var x70 uint64 var x71 uint64 x71, x70 = bits.Mul64(x66, 0x14def9dea2f79cd6) var x72 uint64 var x73 uint64 x73, x72 = bits.Mul64(x66, 0x5812631a5cf5d3ed) var x74 uint64 var x75 uint64 x74, x75 = bits.Add64(x73, x70, uint64(0x0)) x76 := (uint64(fiatScalarUint1(x75)) + x71) var x78 uint64 _, x78 = bits.Add64(x56, x72, uint64(0x0)) var x79 uint64 var x80 uint64 x79, x80 = bits.Add64(x58, x74, uint64(fiatScalarUint1(x78))) var x81 uint64 var x82 uint64 x81, x82 = bits.Add64(x60, x76, uint64(fiatScalarUint1(x80))) var x83 uint64 var x84 uint64 x83, x84 = bits.Add64(x62, x68, uint64(fiatScalarUint1(x82))) var x85 uint64 var x86 uint64 x85, x86 = bits.Add64(x64, x69, uint64(fiatScalarUint1(x84))) x87 := (uint64(fiatScalarUint1(x86)) + uint64(fiatScalarUint1(x65))) var x88 uint64 var x89 uint64 x89, x88 = bits.Mul64(x2, arg2[3]) var x90 uint64 var x91 uint64 x91, x90 = bits.Mul64(x2, arg2[2]) var x92 uint64 var x93 uint64 x93, x92 = bits.Mul64(x2, arg2[1]) var x94 uint64 var x95 uint64 x95, x94 = bits.Mul64(x2, arg2[0]) var x96 uint64 var x97 uint64 x96, x97 = bits.Add64(x95, x92, uint64(0x0)) var x98 uint64 var x99 uint64 x98, x99 = bits.Add64(x93, x90, uint64(fiatScalarUint1(x97))) var x100 uint64 var x101 uint64 x100, x101 = bits.Add64(x91, x88, uint64(fiatScalarUint1(x99))) x102 := (uint64(fiatScalarUint1(x101)) + x89) var x103 uint64 var x104 uint64 x103, x104 = bits.Add64(x79, x94, uint64(0x0)) var x105 uint64 var x106 uint64 x105, x106 = bits.Add64(x81, x96, uint64(fiatScalarUint1(x104))) var x107 uint64 var x108 uint64 x107, x108 = bits.Add64(x83, x98, uint64(fiatScalarUint1(x106))) var x109 uint64 var x110 uint64 x109, x110 = bits.Add64(x85, x100, uint64(fiatScalarUint1(x108))) var x111 uint64 var x112 uint64 x111, x112 = bits.Add64(x87, x102, uint64(fiatScalarUint1(x110))) var x113 uint64 _, x113 = bits.Mul64(x103, 0xd2b51da312547e1b) var x115 uint64 var x116 uint64 x116, x115 = bits.Mul64(x113, 0x1000000000000000) var x117 uint64 var x118 uint64 x118, x117 = bits.Mul64(x113, 0x14def9dea2f79cd6) var x119 uint64 var x120 uint64 x120, x119 = bits.Mul64(x113, 0x5812631a5cf5d3ed) var x121 uint64 var x122 uint64 x121, x122 = bits.Add64(x120, x117, uint64(0x0)) x123 := (uint64(fiatScalarUint1(x122)) + x118) var x125 uint64 _, x125 = bits.Add64(x103, x119, uint64(0x0)) var x126 uint64 var x127 uint64 x126, x127 = bits.Add64(x105, x121, uint64(fiatScalarUint1(x125))) var x128 uint64 var x129 uint64 x128, x129 = bits.Add64(x107, x123, uint64(fiatScalarUint1(x127))) var x130 uint64 var x131 uint64 x130, x131 = bits.Add64(x109, x115, uint64(fiatScalarUint1(x129))) var x132 uint64 var x133 uint64 x132, x133 = bits.Add64(x111, x116, uint64(fiatScalarUint1(x131))) x134 := (uint64(fiatScalarUint1(x133)) + uint64(fiatScalarUint1(x112))) var x135 uint64 var x136 uint64 x136, x135 = bits.Mul64(x3, arg2[3]) var x137 uint64 var x138 uint64 x138, x137 = bits.Mul64(x3, arg2[2]) var x139 uint64 var x140 uint64 x140, x139 = bits.Mul64(x3, arg2[1]) var x141 uint64 var x142 uint64 x142, x141 = bits.Mul64(x3, arg2[0]) var x143 uint64 var x144 uint64 x143, x144 = bits.Add64(x142, x139, uint64(0x0)) var x145 uint64 var x146 uint64 x145, x146 = bits.Add64(x140, x137, uint64(fiatScalarUint1(x144))) var x147 uint64 var x148 uint64 x147, x148 = bits.Add64(x138, x135, uint64(fiatScalarUint1(x146))) x149 := (uint64(fiatScalarUint1(x148)) + x136) var x150 uint64 var x151 uint64 x150, x151 = bits.Add64(x126, x141, uint64(0x0)) var x152 uint64 var x153 uint64 x152, x153 = bits.Add64(x128, x143, uint64(fiatScalarUint1(x151))) var x154 uint64 var x155 uint64 x154, x155 = bits.Add64(x130, x145, uint64(fiatScalarUint1(x153))) var x156 uint64 var x157 uint64 x156, x157 = bits.Add64(x132, x147, uint64(fiatScalarUint1(x155))) var x158 uint64 var x159 uint64 x158, x159 = bits.Add64(x134, x149, uint64(fiatScalarUint1(x157))) var x160 uint64 _, x160 = bits.Mul64(x150, 0xd2b51da312547e1b) var x162 uint64 var x163 uint64 x163, x162 = bits.Mul64(x160, 0x1000000000000000) var x164 uint64 var x165 uint64 x165, x164 = bits.Mul64(x160, 0x14def9dea2f79cd6) var x166 uint64 var x167 uint64 x167, x166 = bits.Mul64(x160, 0x5812631a5cf5d3ed) var x168 uint64 var x169 uint64 x168, x169 = bits.Add64(x167, x164, uint64(0x0)) x170 := (uint64(fiatScalarUint1(x169)) + x165) var x172 uint64 _, x172 = bits.Add64(x150, x166, uint64(0x0)) var x173 uint64 var x174 uint64 x173, x174 = bits.Add64(x152, x168, uint64(fiatScalarUint1(x172))) var x175 uint64 var x176 uint64 x175, x176 = bits.Add64(x154, x170, uint64(fiatScalarUint1(x174))) var x177 uint64 var x178 uint64 x177, x178 = bits.Add64(x156, x162, uint64(fiatScalarUint1(x176))) var x179 uint64 var x180 uint64 x179, x180 = bits.Add64(x158, x163, uint64(fiatScalarUint1(x178))) x181 := (uint64(fiatScalarUint1(x180)) + uint64(fiatScalarUint1(x159))) var x182 uint64 var x183 uint64 x182, x183 = bits.Sub64(x173, 0x5812631a5cf5d3ed, uint64(0x0)) var x184 uint64 var x185 uint64 x184, x185 = bits.Sub64(x175, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x183))) var x186 uint64 var x187 uint64 x186, x187 = bits.Sub64(x177, uint64(0x0), uint64(fiatScalarUint1(x185))) var x188 uint64 var x189 uint64 x188, x189 = bits.Sub64(x179, 0x1000000000000000, uint64(fiatScalarUint1(x187))) var x191 uint64 _, x191 = bits.Sub64(x181, uint64(0x0), uint64(fiatScalarUint1(x189))) var x192 uint64 fiatScalarCmovznzU64(&x192, fiatScalarUint1(x191), x182, x173) var x193 uint64 fiatScalarCmovznzU64(&x193, fiatScalarUint1(x191), x184, x175) var x194 uint64 fiatScalarCmovznzU64(&x194, fiatScalarUint1(x191), x186, x177) var x195 uint64 fiatScalarCmovznzU64(&x195, fiatScalarUint1(x191), x188, x179) out1[0] = x192 out1[1] = x193 out1[2] = x194 out1[3] = x195 } // fiatScalarAdd adds two field elements in the Montgomery domain. // // Preconditions: // // 0 ≤ eval arg1 < m // 0 ≤ eval arg2 < m // // Postconditions: // // eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m // 0 ≤ eval out1 < m func fiatScalarAdd(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) { var x1 uint64 var x2 uint64 x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0)) var x3 uint64 var x4 uint64 x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(fiatScalarUint1(x2))) var x5 uint64 var x6 uint64 x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(fiatScalarUint1(x4))) var x7 uint64 var x8 uint64 x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(fiatScalarUint1(x6))) var x9 uint64 var x10 uint64 x9, x10 = bits.Sub64(x1, 0x5812631a5cf5d3ed, uint64(0x0)) var x11 uint64 var x12 uint64 x11, x12 = bits.Sub64(x3, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x10))) var x13 uint64 var x14 uint64 x13, x14 = bits.Sub64(x5, uint64(0x0), uint64(fiatScalarUint1(x12))) var x15 uint64 var x16 uint64 x15, x16 = bits.Sub64(x7, 0x1000000000000000, uint64(fiatScalarUint1(x14))) var x18 uint64 _, x18 = bits.Sub64(uint64(fiatScalarUint1(x8)), uint64(0x0), uint64(fiatScalarUint1(x16))) var x19 uint64 fiatScalarCmovznzU64(&x19, fiatScalarUint1(x18), x9, x1) var x20 uint64 fiatScalarCmovznzU64(&x20, fiatScalarUint1(x18), x11, x3) var x21 uint64 fiatScalarCmovznzU64(&x21, fiatScalarUint1(x18), x13, x5) var x22 uint64 fiatScalarCmovznzU64(&x22, fiatScalarUint1(x18), x15, x7) out1[0] = x19 out1[1] = x20 out1[2] = x21 out1[3] = x22 } // fiatScalarSub subtracts two field elements in the Montgomery domain. // // Preconditions: // // 0 ≤ eval arg1 < m // 0 ≤ eval arg2 < m // // Postconditions: // // eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m // 0 ≤ eval out1 < m func fiatScalarSub(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) { var x1 uint64 var x2 uint64 x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0)) var x3 uint64 var x4 uint64 x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(fiatScalarUint1(x2))) var x5 uint64 var x6 uint64 x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(fiatScalarUint1(x4))) var x7 uint64 var x8 uint64 x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(fiatScalarUint1(x6))) var x9 uint64 fiatScalarCmovznzU64(&x9, fiatScalarUint1(x8), uint64(0x0), 0xffffffffffffffff) var x10 uint64 var x11 uint64 x10, x11 = bits.Add64(x1, (x9 & 0x5812631a5cf5d3ed), uint64(0x0)) var x12 uint64 var x13 uint64 x12, x13 = bits.Add64(x3, (x9 & 0x14def9dea2f79cd6), uint64(fiatScalarUint1(x11))) var x14 uint64 var x15 uint64 x14, x15 = bits.Add64(x5, uint64(0x0), uint64(fiatScalarUint1(x13))) var x16 uint64 x16, _ = bits.Add64(x7, (x9 & 0x1000000000000000), uint64(fiatScalarUint1(x15))) out1[0] = x10 out1[1] = x12 out1[2] = x14 out1[3] = x16 } // fiatScalarOpp negates a field element in the Montgomery domain. // // Preconditions: // // 0 ≤ eval arg1 < m // // Postconditions: // // eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m // 0 ≤ eval out1 < m func fiatScalarOpp(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement) { var x1 uint64 var x2 uint64 x1, x2 = bits.Sub64(uint64(0x0), arg1[0], uint64(0x0)) var x3 uint64 var x4 uint64 x3, x4 = bits.Sub64(uint64(0x0), arg1[1], uint64(fiatScalarUint1(x2))) var x5 uint64 var x6 uint64 x5, x6 = bits.Sub64(uint64(0x0), arg1[2], uint64(fiatScalarUint1(x4))) var x7 uint64 var x8 uint64 x7, x8 = bits.Sub64(uint64(0x0), arg1[3], uint64(fiatScalarUint1(x6))) var x9 uint64 fiatScalarCmovznzU64(&x9, fiatScalarUint1(x8), uint64(0x0), 0xffffffffffffffff) var x10 uint64 var x11 uint64 x10, x11 = bits.Add64(x1, (x9 & 0x5812631a5cf5d3ed), uint64(0x0)) var x12 uint64 var x13 uint64 x12, x13 = bits.Add64(x3, (x9 & 0x14def9dea2f79cd6), uint64(fiatScalarUint1(x11))) var x14 uint64 var x15 uint64 x14, x15 = bits.Add64(x5, uint64(0x0), uint64(fiatScalarUint1(x13))) var x16 uint64 x16, _ = bits.Add64(x7, (x9 & 0x1000000000000000), uint64(fiatScalarUint1(x15))) out1[0] = x10 out1[1] = x12 out1[2] = x14 out1[3] = x16 } // fiatScalarNonzero outputs a single non-zero word if the input is non-zero and zero otherwise. // // Preconditions: // // 0 ≤ eval arg1 < m // // Postconditions: // // out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0 // // Input Bounds: // // arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] // // Output Bounds: // // out1: [0x0 ~> 0xffffffffffffffff] func fiatScalarNonzero(out1 *uint64, arg1 *[4]uint64) { x1 := (arg1[0] | (arg1[1] | (arg1[2] | arg1[3]))) *out1 = x1 } // fiatScalarFromMontgomery translates a field element out of the Montgomery domain. // // Preconditions: // // 0 ≤ eval arg1 < m // // Postconditions: // // eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m // 0 ≤ eval out1 < m func fiatScalarFromMontgomery(out1 *fiatScalarNonMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement) { x1 := arg1[0] var x2 uint64 _, x2 = bits.Mul64(x1, 0xd2b51da312547e1b) var x4 uint64 var x5 uint64 x5, x4 = bits.Mul64(x2, 0x1000000000000000) var x6 uint64 var x7 uint64 x7, x6 = bits.Mul64(x2, 0x14def9dea2f79cd6) var x8 uint64 var x9 uint64 x9, x8 = bits.Mul64(x2, 0x5812631a5cf5d3ed) var x10 uint64 var x11 uint64 x10, x11 = bits.Add64(x9, x6, uint64(0x0)) var x13 uint64 _, x13 = bits.Add64(x1, x8, uint64(0x0)) var x14 uint64 var x15 uint64 x14, x15 = bits.Add64(uint64(0x0), x10, uint64(fiatScalarUint1(x13))) var x16 uint64 var x17 uint64 x16, x17 = bits.Add64(x14, arg1[1], uint64(0x0)) var x18 uint64 _, x18 = bits.Mul64(x16, 0xd2b51da312547e1b) var x20 uint64 var x21 uint64 x21, x20 = bits.Mul64(x18, 0x1000000000000000) var x22 uint64 var x23 uint64 x23, x22 = bits.Mul64(x18, 0x14def9dea2f79cd6) var x24 uint64 var x25 uint64 x25, x24 = bits.Mul64(x18, 0x5812631a5cf5d3ed) var x26 uint64 var x27 uint64 x26, x27 = bits.Add64(x25, x22, uint64(0x0)) var x29 uint64 _, x29 = bits.Add64(x16, x24, uint64(0x0)) var x30 uint64 var x31 uint64 x30, x31 = bits.Add64((uint64(fiatScalarUint1(x17)) + (uint64(fiatScalarUint1(x15)) + (uint64(fiatScalarUint1(x11)) + x7))), x26, uint64(fiatScalarUint1(x29))) var x32 uint64 var x33 uint64 x32, x33 = bits.Add64(x4, (uint64(fiatScalarUint1(x27)) + x23), uint64(fiatScalarUint1(x31))) var x34 uint64 var x35 uint64 x34, x35 = bits.Add64(x5, x20, uint64(fiatScalarUint1(x33))) var x36 uint64 var x37 uint64 x36, x37 = bits.Add64(x30, arg1[2], uint64(0x0)) var x38 uint64 var x39 uint64 x38, x39 = bits.Add64(x32, uint64(0x0), uint64(fiatScalarUint1(x37))) var x40 uint64 var x41 uint64 x40, x41 = bits.Add64(x34, uint64(0x0), uint64(fiatScalarUint1(x39))) var x42 uint64 _, x42 = bits.Mul64(x36, 0xd2b51da312547e1b) var x44 uint64 var x45 uint64 x45, x44 = bits.Mul64(x42, 0x1000000000000000) var x46 uint64 var x47 uint64 x47, x46 = bits.Mul64(x42, 0x14def9dea2f79cd6) var x48 uint64 var x49 uint64 x49, x48 = bits.Mul64(x42, 0x5812631a5cf5d3ed) var x50 uint64 var x51 uint64 x50, x51 = bits.Add64(x49, x46, uint64(0x0)) var x53 uint64 _, x53 = bits.Add64(x36, x48, uint64(0x0)) var x54 uint64 var x55 uint64 x54, x55 = bits.Add64(x38, x50, uint64(fiatScalarUint1(x53))) var x56 uint64 var x57 uint64 x56, x57 = bits.Add64(x40, (uint64(fiatScalarUint1(x51)) + x47), uint64(fiatScalarUint1(x55))) var x58 uint64 var x59 uint64 x58, x59 = bits.Add64((uint64(fiatScalarUint1(x41)) + (uint64(fiatScalarUint1(x35)) + x21)), x44, uint64(fiatScalarUint1(x57))) var x60 uint64 var x61 uint64 x60, x61 = bits.Add64(x54, arg1[3], uint64(0x0)) var x62 uint64 var x63 uint64 x62, x63 = bits.Add64(x56, uint64(0x0), uint64(fiatScalarUint1(x61))) var x64 uint64 var x65 uint64 x64, x65 = bits.Add64(x58, uint64(0x0), uint64(fiatScalarUint1(x63))) var x66 uint64 _, x66 = bits.Mul64(x60, 0xd2b51da312547e1b) var x68 uint64 var x69 uint64 x69, x68 = bits.Mul64(x66, 0x1000000000000000) var x70 uint64 var x71 uint64 x71, x70 = bits.Mul64(x66, 0x14def9dea2f79cd6) var x72 uint64 var x73 uint64 x73, x72 = bits.Mul64(x66, 0x5812631a5cf5d3ed) var x74 uint64 var x75 uint64 x74, x75 = bits.Add64(x73, x70, uint64(0x0)) var x77 uint64 _, x77 = bits.Add64(x60, x72, uint64(0x0)) var x78 uint64 var x79 uint64 x78, x79 = bits.Add64(x62, x74, uint64(fiatScalarUint1(x77))) var x80 uint64 var x81 uint64 x80, x81 = bits.Add64(x64, (uint64(fiatScalarUint1(x75)) + x71), uint64(fiatScalarUint1(x79))) var x82 uint64 var x83 uint64 x82, x83 = bits.Add64((uint64(fiatScalarUint1(x65)) + (uint64(fiatScalarUint1(x59)) + x45)), x68, uint64(fiatScalarUint1(x81))) x84 := (uint64(fiatScalarUint1(x83)) + x69) var x85 uint64 var x86 uint64 x85, x86 = bits.Sub64(x78, 0x5812631a5cf5d3ed, uint64(0x0)) var x87 uint64 var x88 uint64 x87, x88 = bits.Sub64(x80, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x86))) var x89 uint64 var x90 uint64 x89, x90 = bits.Sub64(x82, uint64(0x0), uint64(fiatScalarUint1(x88))) var x91 uint64 var x92 uint64 x91, x92 = bits.Sub64(x84, 0x1000000000000000, uint64(fiatScalarUint1(x90))) var x94 uint64 _, x94 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(fiatScalarUint1(x92))) var x95 uint64 fiatScalarCmovznzU64(&x95, fiatScalarUint1(x94), x85, x78) var x96 uint64 fiatScalarCmovznzU64(&x96, fiatScalarUint1(x94), x87, x80) var x97 uint64 fiatScalarCmovznzU64(&x97, fiatScalarUint1(x94), x89, x82) var x98 uint64 fiatScalarCmovznzU64(&x98, fiatScalarUint1(x94), x91, x84) out1[0] = x95 out1[1] = x96 out1[2] = x97 out1[3] = x98 } // fiatScalarToMontgomery translates a field element into the Montgomery domain. // // Preconditions: // // 0 ≤ eval arg1 < m // // Postconditions: // // eval (from_montgomery out1) mod m = eval arg1 mod m // 0 ≤ eval out1 < m func fiatScalarToMontgomery(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarNonMontgomeryDomainFieldElement) { x1 := arg1[1] x2 := arg1[2] x3 := arg1[3] x4 := arg1[0] var x5 uint64 var x6 uint64 x6, x5 = bits.Mul64(x4, 0x399411b7c309a3d) var x7 uint64 var x8 uint64 x8, x7 = bits.Mul64(x4, 0xceec73d217f5be65) var x9 uint64 var x10 uint64 x10, x9 = bits.Mul64(x4, 0xd00e1ba768859347) var x11 uint64 var x12 uint64 x12, x11 = bits.Mul64(x4, 0xa40611e3449c0f01) var x13 uint64 var x14 uint64 x13, x14 = bits.Add64(x12, x9, uint64(0x0)) var x15 uint64 var x16 uint64 x15, x16 = bits.Add64(x10, x7, uint64(fiatScalarUint1(x14))) var x17 uint64 var x18 uint64 x17, x18 = bits.Add64(x8, x5, uint64(fiatScalarUint1(x16))) var x19 uint64 _, x19 = bits.Mul64(x11, 0xd2b51da312547e1b) var x21 uint64 var x22 uint64 x22, x21 = bits.Mul64(x19, 0x1000000000000000) var x23 uint64 var x24 uint64 x24, x23 = bits.Mul64(x19, 0x14def9dea2f79cd6) var x25 uint64 var x26 uint64 x26, x25 = bits.Mul64(x19, 0x5812631a5cf5d3ed) var x27 uint64 var x28 uint64 x27, x28 = bits.Add64(x26, x23, uint64(0x0)) var x30 uint64 _, x30 = bits.Add64(x11, x25, uint64(0x0)) var x31 uint64 var x32 uint64 x31, x32 = bits.Add64(x13, x27, uint64(fiatScalarUint1(x30))) var x33 uint64 var x34 uint64 x33, x34 = bits.Add64(x15, (uint64(fiatScalarUint1(x28)) + x24), uint64(fiatScalarUint1(x32))) var x35 uint64 var x36 uint64 x35, x36 = bits.Add64(x17, x21, uint64(fiatScalarUint1(x34))) var x37 uint64 var x38 uint64 x38, x37 = bits.Mul64(x1, 0x399411b7c309a3d) var x39 uint64 var x40 uint64 x40, x39 = bits.Mul64(x1, 0xceec73d217f5be65) var x41 uint64 var x42 uint64 x42, x41 = bits.Mul64(x1, 0xd00e1ba768859347) var x43 uint64 var x44 uint64 x44, x43 = bits.Mul64(x1, 0xa40611e3449c0f01) var x45 uint64 var x46 uint64 x45, x46 = bits.Add64(x44, x41, uint64(0x0)) var x47 uint64 var x48 uint64 x47, x48 = bits.Add64(x42, x39, uint64(fiatScalarUint1(x46))) var x49 uint64 var x50 uint64 x49, x50 = bits.Add64(x40, x37, uint64(fiatScalarUint1(x48))) var x51 uint64 var x52 uint64 x51, x52 = bits.Add64(x31, x43, uint64(0x0)) var x53 uint64 var x54 uint64 x53, x54 = bits.Add64(x33, x45, uint64(fiatScalarUint1(x52))) var x55 uint64 var x56 uint64 x55, x56 = bits.Add64(x35, x47, uint64(fiatScalarUint1(x54))) var x57 uint64 var x58 uint64 x57, x58 = bits.Add64(((uint64(fiatScalarUint1(x36)) + (uint64(fiatScalarUint1(x18)) + x6)) + x22), x49, uint64(fiatScalarUint1(x56))) var x59 uint64 _, x59 = bits.Mul64(x51, 0xd2b51da312547e1b) var x61 uint64 var x62 uint64 x62, x61 = bits.Mul64(x59, 0x1000000000000000) var x63 uint64 var x64 uint64 x64, x63 = bits.Mul64(x59, 0x14def9dea2f79cd6) var x65 uint64 var x66 uint64 x66, x65 = bits.Mul64(x59, 0x5812631a5cf5d3ed) var x67 uint64 var x68 uint64 x67, x68 = bits.Add64(x66, x63, uint64(0x0)) var x70 uint64 _, x70 = bits.Add64(x51, x65, uint64(0x0)) var x71 uint64 var x72 uint64 x71, x72 = bits.Add64(x53, x67, uint64(fiatScalarUint1(x70))) var x73 uint64 var x74 uint64 x73, x74 = bits.Add64(x55, (uint64(fiatScalarUint1(x68)) + x64), uint64(fiatScalarUint1(x72))) var x75 uint64 var x76 uint64 x75, x76 = bits.Add64(x57, x61, uint64(fiatScalarUint1(x74))) var x77 uint64 var x78 uint64 x78, x77 = bits.Mul64(x2, 0x399411b7c309a3d) var x79 uint64 var x80 uint64 x80, x79 = bits.Mul64(x2, 0xceec73d217f5be65) var x81 uint64 var x82 uint64 x82, x81 = bits.Mul64(x2, 0xd00e1ba768859347) var x83 uint64 var x84 uint64 x84, x83 = bits.Mul64(x2, 0xa40611e3449c0f01) var x85 uint64 var x86 uint64 x85, x86 = bits.Add64(x84, x81, uint64(0x0)) var x87 uint64 var x88 uint64 x87, x88 = bits.Add64(x82, x79, uint64(fiatScalarUint1(x86))) var x89 uint64 var x90 uint64 x89, x90 = bits.Add64(x80, x77, uint64(fiatScalarUint1(x88))) var x91 uint64 var x92 uint64 x91, x92 = bits.Add64(x71, x83, uint64(0x0)) var x93 uint64 var x94 uint64 x93, x94 = bits.Add64(x73, x85, uint64(fiatScalarUint1(x92))) var x95 uint64 var x96 uint64 x95, x96 = bits.Add64(x75, x87, uint64(fiatScalarUint1(x94))) var x97 uint64 var x98 uint64 x97, x98 = bits.Add64(((uint64(fiatScalarUint1(x76)) + (uint64(fiatScalarUint1(x58)) + (uint64(fiatScalarUint1(x50)) + x38))) + x62), x89, uint64(fiatScalarUint1(x96))) var x99 uint64 _, x99 = bits.Mul64(x91, 0xd2b51da312547e1b) var x101 uint64 var x102 uint64 x102, x101 = bits.Mul64(x99, 0x1000000000000000) var x103 uint64 var x104 uint64 x104, x103 = bits.Mul64(x99, 0x14def9dea2f79cd6) var x105 uint64 var x106 uint64 x106, x105 = bits.Mul64(x99, 0x5812631a5cf5d3ed) var x107 uint64 var x108 uint64 x107, x108 = bits.Add64(x106, x103, uint64(0x0)) var x110 uint64 _, x110 = bits.Add64(x91, x105, uint64(0x0)) var x111 uint64 var x112 uint64 x111, x112 = bits.Add64(x93, x107, uint64(fiatScalarUint1(x110))) var x113 uint64 var x114 uint64 x113, x114 = bits.Add64(x95, (uint64(fiatScalarUint1(x108)) + x104), uint64(fiatScalarUint1(x112))) var x115 uint64 var x116 uint64 x115, x116 = bits.Add64(x97, x101, uint64(fiatScalarUint1(x114))) var x117 uint64 var x118 uint64 x118, x117 = bits.Mul64(x3, 0x399411b7c309a3d) var x119 uint64 var x120 uint64 x120, x119 = bits.Mul64(x3, 0xceec73d217f5be65) var x121 uint64 var x122 uint64 x122, x121 = bits.Mul64(x3, 0xd00e1ba768859347) var x123 uint64 var x124 uint64 x124, x123 = bits.Mul64(x3, 0xa40611e3449c0f01) var x125 uint64 var x126 uint64 x125, x126 = bits.Add64(x124, x121, uint64(0x0)) var x127 uint64 var x128 uint64 x127, x128 = bits.Add64(x122, x119, uint64(fiatScalarUint1(x126))) var x129 uint64 var x130 uint64 x129, x130 = bits.Add64(x120, x117, uint64(fiatScalarUint1(x128))) var x131 uint64 var x132 uint64 x131, x132 = bits.Add64(x111, x123, uint64(0x0)) var x133 uint64 var x134 uint64 x133, x134 = bits.Add64(x113, x125, uint64(fiatScalarUint1(x132))) var x135 uint64 var x136 uint64 x135, x136 = bits.Add64(x115, x127, uint64(fiatScalarUint1(x134))) var x137 uint64 var x138 uint64 x137, x138 = bits.Add64(((uint64(fiatScalarUint1(x116)) + (uint64(fiatScalarUint1(x98)) + (uint64(fiatScalarUint1(x90)) + x78))) + x102), x129, uint64(fiatScalarUint1(x136))) var x139 uint64 _, x139 = bits.Mul64(x131, 0xd2b51da312547e1b) var x141 uint64 var x142 uint64 x142, x141 = bits.Mul64(x139, 0x1000000000000000) var x143 uint64 var x144 uint64 x144, x143 = bits.Mul64(x139, 0x14def9dea2f79cd6) var x145 uint64 var x146 uint64 x146, x145 = bits.Mul64(x139, 0x5812631a5cf5d3ed) var x147 uint64 var x148 uint64 x147, x148 = bits.Add64(x146, x143, uint64(0x0)) var x150 uint64 _, x150 = bits.Add64(x131, x145, uint64(0x0)) var x151 uint64 var x152 uint64 x151, x152 = bits.Add64(x133, x147, uint64(fiatScalarUint1(x150))) var x153 uint64 var x154 uint64 x153, x154 = bits.Add64(x135, (uint64(fiatScalarUint1(x148)) + x144), uint64(fiatScalarUint1(x152))) var x155 uint64 var x156 uint64 x155, x156 = bits.Add64(x137, x141, uint64(fiatScalarUint1(x154))) x157 := ((uint64(fiatScalarUint1(x156)) + (uint64(fiatScalarUint1(x138)) + (uint64(fiatScalarUint1(x130)) + x118))) + x142) var x158 uint64 var x159 uint64 x158, x159 = bits.Sub64(x151, 0x5812631a5cf5d3ed, uint64(0x0)) var x160 uint64 var x161 uint64 x160, x161 = bits.Sub64(x153, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x159))) var x162 uint64 var x163 uint64 x162, x163 = bits.Sub64(x155, uint64(0x0), uint64(fiatScalarUint1(x161))) var x164 uint64 var x165 uint64 x164, x165 = bits.Sub64(x157, 0x1000000000000000, uint64(fiatScalarUint1(x163))) var x167 uint64 _, x167 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(fiatScalarUint1(x165))) var x168 uint64 fiatScalarCmovznzU64(&x168, fiatScalarUint1(x167), x158, x151) var x169 uint64 fiatScalarCmovznzU64(&x169, fiatScalarUint1(x167), x160, x153) var x170 uint64 fiatScalarCmovznzU64(&x170, fiatScalarUint1(x167), x162, x155) var x171 uint64 fiatScalarCmovznzU64(&x171, fiatScalarUint1(x167), x164, x157) out1[0] = x168 out1[1] = x169 out1[2] = x170 out1[3] = x171 } // fiatScalarToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. // // Preconditions: // // 0 ≤ eval arg1 < m // // Postconditions: // // out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31] // // Input Bounds: // // arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1fffffffffffffff]] // // Output Bounds: // // out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1f]] func fiatScalarToBytes(out1 *[32]uint8, arg1 *[4]uint64) { x1 := arg1[3] x2 := arg1[2] x3 := arg1[1] x4 := arg1[0] x5 := (uint8(x4) & 0xff) x6 := (x4 >> 8) x7 := (uint8(x6) & 0xff) x8 := (x6 >> 8) x9 := (uint8(x8) & 0xff) x10 := (x8 >> 8) x11 := (uint8(x10) & 0xff) x12 := (x10 >> 8) x13 := (uint8(x12) & 0xff) x14 := (x12 >> 8) x15 := (uint8(x14) & 0xff) x16 := (x14 >> 8) x17 := (uint8(x16) & 0xff) x18 := uint8((x16 >> 8)) x19 := (uint8(x3) & 0xff) x20 := (x3 >> 8) x21 := (uint8(x20) & 0xff) x22 := (x20 >> 8) x23 := (uint8(x22) & 0xff) x24 := (x22 >> 8) x25 := (uint8(x24) & 0xff) x26 := (x24 >> 8) x27 := (uint8(x26) & 0xff) x28 := (x26 >> 8) x29 := (uint8(x28) & 0xff) x30 := (x28 >> 8) x31 := (uint8(x30) & 0xff) x32 := uint8((x30 >> 8)) x33 := (uint8(x2) & 0xff) x34 := (x2 >> 8) x35 := (uint8(x34) & 0xff) x36 := (x34 >> 8) x37 := (uint8(x36) & 0xff) x38 := (x36 >> 8) x39 := (uint8(x38) & 0xff) x40 := (x38 >> 8) x41 := (uint8(x40) & 0xff) x42 := (x40 >> 8) x43 := (uint8(x42) & 0xff) x44 := (x42 >> 8) x45 := (uint8(x44) & 0xff) x46 := uint8((x44 >> 8)) x47 := (uint8(x1) & 0xff) x48 := (x1 >> 8) x49 := (uint8(x48) & 0xff) x50 := (x48 >> 8) x51 := (uint8(x50) & 0xff) x52 := (x50 >> 8) x53 := (uint8(x52) & 0xff) x54 := (x52 >> 8) x55 := (uint8(x54) & 0xff) x56 := (x54 >> 8) x57 := (uint8(x56) & 0xff) x58 := (x56 >> 8) x59 := (uint8(x58) & 0xff) x60 := uint8((x58 >> 8)) out1[0] = x5 out1[1] = x7 out1[2] = x9 out1[3] = x11 out1[4] = x13 out1[5] = x15 out1[6] = x17 out1[7] = x18 out1[8] = x19 out1[9] = x21 out1[10] = x23 out1[11] = x25 out1[12] = x27 out1[13] = x29 out1[14] = x31 out1[15] = x32 out1[16] = x33 out1[17] = x35 out1[18] = x37 out1[19] = x39 out1[20] = x41 out1[21] = x43 out1[22] = x45 out1[23] = x46 out1[24] = x47 out1[25] = x49 out1[26] = x51 out1[27] = x53 out1[28] = x55 out1[29] = x57 out1[30] = x59 out1[31] = x60 } // fiatScalarFromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order. // // Preconditions: // // 0 ≤ bytes_eval arg1 < m // // Postconditions: // // eval out1 mod m = bytes_eval arg1 mod m // 0 ≤ eval out1 < m // // Input Bounds: // // arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1f]] // // Output Bounds: // // out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1fffffffffffffff]] func fiatScalarFromBytes(out1 *[4]uint64, arg1 *[32]uint8) { x1 := (uint64(arg1[31]) << 56) x2 := (uint64(arg1[30]) << 48) x3 := (uint64(arg1[29]) << 40) x4 := (uint64(arg1[28]) << 32) x5 := (uint64(arg1[27]) << 24) x6 := (uint64(arg1[26]) << 16) x7 := (uint64(arg1[25]) << 8) x8 := arg1[24] x9 := (uint64(arg1[23]) << 56) x10 := (uint64(arg1[22]) << 48) x11 := (uint64(arg1[21]) << 40) x12 := (uint64(arg1[20]) << 32) x13 := (uint64(arg1[19]) << 24) x14 := (uint64(arg1[18]) << 16) x15 := (uint64(arg1[17]) << 8) x16 := arg1[16] x17 := (uint64(arg1[15]) << 56) x18 := (uint64(arg1[14]) << 48) x19 := (uint64(arg1[13]) << 40) x20 := (uint64(arg1[12]) << 32) x21 := (uint64(arg1[11]) << 24) x22 := (uint64(arg1[10]) << 16) x23 := (uint64(arg1[9]) << 8) x24 := arg1[8] x25 := (uint64(arg1[7]) << 56) x26 := (uint64(arg1[6]) << 48) x27 := (uint64(arg1[5]) << 40) x28 := (uint64(arg1[4]) << 32) x29 := (uint64(arg1[3]) << 24) x30 := (uint64(arg1[2]) << 16) x31 := (uint64(arg1[1]) << 8) x32 := arg1[0] x33 := (x31 + uint64(x32)) x34 := (x30 + x33) x35 := (x29 + x34) x36 := (x28 + x35) x37 := (x27 + x36) x38 := (x26 + x37) x39 := (x25 + x38) x40 := (x23 + uint64(x24)) x41 := (x22 + x40) x42 := (x21 + x41) x43 := (x20 + x42) x44 := (x19 + x43) x45 := (x18 + x44) x46 := (x17 + x45) x47 := (x15 + uint64(x16)) x48 := (x14 + x47) x49 := (x13 + x48) x50 := (x12 + x49) x51 := (x11 + x50) x52 := (x10 + x51) x53 := (x9 + x52) x54 := (x7 + uint64(x8)) x55 := (x6 + x54) x56 := (x5 + x55) x57 := (x4 + x56) x58 := (x3 + x57) x59 := (x2 + x58) x60 := (x1 + x59) out1[0] = x39 out1[1] = x46 out1[2] = x53 out1[3] = x60 } ================================================ FILE: vendor/filippo.io/edwards25519/scalarmult.go ================================================ // Copyright (c) 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package edwards25519 import "sync" // basepointTable is a set of 32 affineLookupTables, where table i is generated // from 256i * basepoint. It is precomputed the first time it's used. func basepointTable() *[32]affineLookupTable { basepointTablePrecomp.initOnce.Do(func() { p := NewGeneratorPoint() for i := 0; i < 32; i++ { basepointTablePrecomp.table[i].FromP3(p) for j := 0; j < 8; j++ { p.Add(p, p) } } }) return &basepointTablePrecomp.table } var basepointTablePrecomp struct { table [32]affineLookupTable initOnce sync.Once } // ScalarBaseMult sets v = x * B, where B is the canonical generator, and // returns v. // // The scalar multiplication is done in constant time. func (v *Point) ScalarBaseMult(x *Scalar) *Point { basepointTable := basepointTable() // Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i ) // as described in the Ed25519 paper // // Group even and odd coefficients // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B // + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B // + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B) // // We use a lookup table for each i to get x_i*16^(2*i)*B // and do four doublings to multiply by 16. digits := x.signedRadix16() multiple := &affineCached{} tmp1 := &projP1xP1{} tmp2 := &projP2{} // Accumulate the odd components first v.Set(NewIdentityPoint()) for i := 1; i < 64; i += 2 { basepointTable[i/2].SelectInto(multiple, digits[i]) tmp1.AddAffine(v, multiple) v.fromP1xP1(tmp1) } // Multiply by 16 tmp2.FromP3(v) // tmp2 = v in P2 coords tmp1.Double(tmp2) // tmp1 = 2*v in P1xP1 coords tmp2.FromP1xP1(tmp1) // tmp2 = 2*v in P2 coords tmp1.Double(tmp2) // tmp1 = 4*v in P1xP1 coords tmp2.FromP1xP1(tmp1) // tmp2 = 4*v in P2 coords tmp1.Double(tmp2) // tmp1 = 8*v in P1xP1 coords tmp2.FromP1xP1(tmp1) // tmp2 = 8*v in P2 coords tmp1.Double(tmp2) // tmp1 = 16*v in P1xP1 coords v.fromP1xP1(tmp1) // now v = 16*(odd components) // Accumulate the even components for i := 0; i < 64; i += 2 { basepointTable[i/2].SelectInto(multiple, digits[i]) tmp1.AddAffine(v, multiple) v.fromP1xP1(tmp1) } return v } // ScalarMult sets v = x * q, and returns v. // // The scalar multiplication is done in constant time. func (v *Point) ScalarMult(x *Scalar, q *Point) *Point { checkInitialized(q) var table projLookupTable table.FromP3(q) // Write x = sum(x_i * 16^i) // so x*Q = sum( Q*x_i*16^i ) // = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... ) // <------compute inside out--------- // // We use the lookup table to get the x_i*Q values // and do four doublings to compute 16*Q digits := x.signedRadix16() // Unwrap first loop iteration to save computing 16*identity multiple := &projCached{} tmp1 := &projP1xP1{} tmp2 := &projP2{} table.SelectInto(multiple, digits[63]) v.Set(NewIdentityPoint()) tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords for i := 62; i >= 0; i-- { tmp2.FromP1xP1(tmp1) // tmp2 = (prev) in P2 coords tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords table.SelectInto(multiple, digits[i]) tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords } v.fromP1xP1(tmp1) return v } // basepointNafTable is the nafLookupTable8 for the basepoint. // It is precomputed the first time it's used. func basepointNafTable() *nafLookupTable8 { basepointNafTablePrecomp.initOnce.Do(func() { basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint()) }) return &basepointNafTablePrecomp.table } var basepointNafTablePrecomp struct { table nafLookupTable8 initOnce sync.Once } // VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical // generator, and returns v. // // Execution time depends on the inputs. func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point { checkInitialized(A) // Similarly to the single variable-base approach, we compute // digits and use them with a lookup table. However, because // we are allowed to do variable-time operations, we don't // need constant-time lookups or constant-time digit // computations. // // So we use a non-adjacent form of some width w instead of // radix 16. This is like a binary representation (one digit // for each binary place) but we allow the digits to grow in // magnitude up to 2^{w-1} so that the nonzero digits are as // sparse as possible. Intuitively, this "condenses" the // "mass" of the scalar onto sparse coefficients (meaning // fewer additions). basepointNafTable := basepointNafTable() var aTable nafLookupTable5 aTable.FromP3(A) // Because the basepoint is fixed, we can use a wider NAF // corresponding to a bigger table. aNaf := a.nonAdjacentForm(5) bNaf := b.nonAdjacentForm(8) // Find the first nonzero coefficient. i := 255 for j := i; j >= 0; j-- { if aNaf[j] != 0 || bNaf[j] != 0 { break } } multA := &projCached{} multB := &affineCached{} tmp1 := &projP1xP1{} tmp2 := &projP2{} tmp2.Zero() // Move from high to low bits, doubling the accumulator // at each iteration and checking whether there is a nonzero // coefficient to look up a multiple of. for ; i >= 0; i-- { tmp1.Double(tmp2) // Only update v if we have a nonzero coeff to add in. if aNaf[i] > 0 { v.fromP1xP1(tmp1) aTable.SelectInto(multA, aNaf[i]) tmp1.Add(v, multA) } else if aNaf[i] < 0 { v.fromP1xP1(tmp1) aTable.SelectInto(multA, -aNaf[i]) tmp1.Sub(v, multA) } if bNaf[i] > 0 { v.fromP1xP1(tmp1) basepointNafTable.SelectInto(multB, bNaf[i]) tmp1.AddAffine(v, multB) } else if bNaf[i] < 0 { v.fromP1xP1(tmp1) basepointNafTable.SelectInto(multB, -bNaf[i]) tmp1.SubAffine(v, multB) } tmp2.FromP1xP1(tmp1) } v.fromP2(tmp2) return v } ================================================ FILE: vendor/filippo.io/edwards25519/tables.go ================================================ // Copyright (c) 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package edwards25519 import ( "crypto/subtle" ) // A dynamic lookup table for variable-base, constant-time scalar muls. type projLookupTable struct { points [8]projCached } // A precomputed lookup table for fixed-base, constant-time scalar muls. type affineLookupTable struct { points [8]affineCached } // A dynamic lookup table for variable-base, variable-time scalar muls. type nafLookupTable5 struct { points [8]projCached } // A precomputed lookup table for fixed-base, variable-time scalar muls. type nafLookupTable8 struct { points [64]affineCached } // Constructors. // Builds a lookup table at runtime. Fast. func (v *projLookupTable) FromP3(q *Point) { // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q v.points[0].FromP3(q) tmpP3 := Point{} tmpP1xP1 := projP1xP1{} for i := 0; i < 7; i++ { // Compute (i+1)*Q as Q + i*Q and convert to a projCached // This is needlessly complicated because the API has explicit // receivers instead of creating stack objects and relying on RVO v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i]))) } } // This is not optimised for speed; fixed-base tables should be precomputed. func (v *affineLookupTable) FromP3(q *Point) { // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q v.points[0].FromP3(q) tmpP3 := Point{} tmpP1xP1 := projP1xP1{} for i := 0; i < 7; i++ { // Compute (i+1)*Q as Q + i*Q and convert to affineCached v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i]))) } } // Builds a lookup table at runtime. Fast. func (v *nafLookupTable5) FromP3(q *Point) { // Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q // This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q v.points[0].FromP3(q) q2 := Point{} q2.Add(q, q) tmpP3 := Point{} tmpP1xP1 := projP1xP1{} for i := 0; i < 7; i++ { v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i]))) } } // This is not optimised for speed; fixed-base tables should be precomputed. func (v *nafLookupTable8) FromP3(q *Point) { v.points[0].FromP3(q) q2 := Point{} q2.Add(q, q) tmpP3 := Point{} tmpP1xP1 := projP1xP1{} for i := 0; i < 63; i++ { v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i]))) } } // Selectors. // Set dest to x*Q, where -8 <= x <= 8, in constant time. func (v *projLookupTable) SelectInto(dest *projCached, x int8) { // Compute xabs = |x| xmask := x >> 7 xabs := uint8((x + xmask) ^ xmask) dest.Zero() for j := 1; j <= 8; j++ { // Set dest = j*Q if |x| = j cond := subtle.ConstantTimeByteEq(xabs, uint8(j)) dest.Select(&v.points[j-1], dest, cond) } // Now dest = |x|*Q, conditionally negate to get x*Q dest.CondNeg(int(xmask & 1)) } // Set dest to x*Q, where -8 <= x <= 8, in constant time. func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) { // Compute xabs = |x| xmask := x >> 7 xabs := uint8((x + xmask) ^ xmask) dest.Zero() for j := 1; j <= 8; j++ { // Set dest = j*Q if |x| = j cond := subtle.ConstantTimeByteEq(xabs, uint8(j)) dest.Select(&v.points[j-1], dest, cond) } // Now dest = |x|*Q, conditionally negate to get x*Q dest.CondNeg(int(xmask & 1)) } // Given odd x with 0 < x < 2^4, return x*Q (in variable time). func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) { *dest = v.points[x/2] } // Given odd x with 0 < x < 2^7, return x*Q (in variable time). func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) { *dest = v.points[x/2] } ================================================ FILE: vendor/github.com/beorn7/perks/LICENSE ================================================ Copyright (C) 2013 Blake Mizerany Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: vendor/github.com/beorn7/perks/quantile/exampledata.txt ================================================ 8 5 26 12 5 235 13 6 28 30 3 3 3 3 5 2 33 7 2 4 7 12 14 5 8 3 10 4 5 3 6 6 209 20 3 10 14 3 4 6 8 5 11 7 3 2 3 3 212 5 222 4 10 10 5 6 3 8 3 10 254 220 2 3 5 24 5 4 222 7 3 3 223 8 15 12 14 14 3 2 2 3 13 3 11 4 4 6 5 7 13 5 3 5 2 5 3 5 2 7 15 17 14 3 6 6 3 17 5 4 7 6 4 4 8 6 8 3 9 3 6 3 4 5 3 3 660 4 6 10 3 6 3 2 5 13 2 4 4 10 4 8 4 3 7 9 9 3 10 37 3 13 4 12 3 6 10 8 5 21 2 3 8 3 2 3 3 4 12 2 4 8 8 4 3 2 20 1 6 32 2 11 6 18 3 8 11 3 212 3 4 2 6 7 12 11 3 2 16 10 6 4 6 3 2 7 3 2 2 2 2 5 6 4 3 10 3 4 6 5 3 4 4 5 6 4 3 4 4 5 7 5 5 3 2 7 2 4 12 4 5 6 2 4 4 8 4 15 13 7 16 5 3 23 5 5 7 3 2 9 8 7 5 8 11 4 10 76 4 47 4 3 2 7 4 2 3 37 10 4 2 20 5 4 4 10 10 4 3 7 23 240 7 13 5 5 3 3 2 5 4 2 8 7 19 2 23 8 7 2 5 3 8 3 8 13 5 5 5 2 3 23 4 9 8 4 3 3 5 220 2 3 4 6 14 3 53 6 2 5 18 6 3 219 6 5 2 5 3 6 5 15 4 3 17 3 2 4 7 2 3 3 4 4 3 2 664 6 3 23 5 5 16 5 8 2 4 2 24 12 3 2 3 5 8 3 5 4 3 14 3 5 8 2 3 7 9 4 2 3 6 8 4 3 4 6 5 3 3 6 3 19 4 4 6 3 6 3 5 22 5 4 4 3 8 11 4 9 7 6 13 4 4 4 6 17 9 3 3 3 4 3 221 5 11 3 4 2 12 6 3 5 7 5 7 4 9 7 14 37 19 217 16 3 5 2 2 7 19 7 6 7 4 24 5 11 4 7 7 9 13 3 4 3 6 28 4 4 5 5 2 5 6 4 4 6 10 5 4 3 2 3 3 6 5 5 4 3 2 3 7 4 6 18 16 8 16 4 5 8 6 9 13 1545 6 215 6 5 6 3 45 31 5 2 2 4 3 3 2 5 4 3 5 7 7 4 5 8 5 4 749 2 31 9 11 2 11 5 4 4 7 9 11 4 5 4 7 3 4 6 2 15 3 4 3 4 3 5 2 13 5 5 3 3 23 4 4 5 7 4 13 2 4 3 4 2 6 2 7 3 5 5 3 29 5 4 4 3 10 2 3 79 16 6 6 7 7 3 5 5 7 4 3 7 9 5 6 5 9 6 3 6 4 17 2 10 9 3 6 2 3 21 22 5 11 4 2 17 2 224 2 14 3 4 4 2 4 4 4 4 5 3 4 4 10 2 6 3 3 5 7 2 7 5 6 3 218 2 2 5 2 6 3 5 222 14 6 33 3 2 5 3 3 3 9 5 3 3 2 7 4 3 4 3 5 6 5 26 4 13 9 7 3 221 3 3 4 4 4 4 2 18 5 3 7 9 6 8 3 10 3 11 9 5 4 17 5 5 6 6 3 2 4 12 17 6 7 218 4 2 4 10 3 5 15 3 9 4 3 3 6 29 3 3 4 5 5 3 8 5 6 6 7 5 3 5 3 29 2 31 5 15 24 16 5 207 4 3 3 2 15 4 4 13 5 5 4 6 10 2 7 8 4 6 20 5 3 4 3 12 12 5 17 7 3 3 3 6 10 3 5 25 80 4 9 3 2 11 3 3 2 3 8 7 5 5 19 5 3 3 12 11 2 6 5 5 5 3 3 3 4 209 14 3 2 5 19 4 4 3 4 14 5 6 4 13 9 7 4 7 10 2 9 5 7 2 8 4 6 5 5 222 8 7 12 5 216 3 4 4 6 3 14 8 7 13 4 3 3 3 3 17 5 4 3 33 6 6 33 7 5 3 8 7 5 2 9 4 2 233 24 7 4 8 10 3 4 15 2 16 3 3 13 12 7 5 4 207 4 2 4 27 15 2 5 2 25 6 5 5 6 13 6 18 6 4 12 225 10 7 5 2 2 11 4 14 21 8 10 3 5 4 232 2 5 5 3 7 17 11 6 6 23 4 6 3 5 4 2 17 3 6 5 8 3 2 2 14 9 4 4 2 5 5 3 7 6 12 6 10 3 6 2 2 19 5 4 4 9 2 4 13 3 5 6 3 6 5 4 9 6 3 5 7 3 6 6 4 3 10 6 3 221 3 5 3 6 4 8 5 3 6 4 4 2 54 5 6 11 3 3 4 4 4 3 7 3 11 11 7 10 6 13 223 213 15 231 7 3 7 228 2 3 4 4 5 6 7 4 13 3 4 5 3 6 4 6 7 2 4 3 4 3 3 6 3 7 3 5 18 5 6 8 10 3 3 3 2 4 2 4 4 5 6 6 4 10 13 3 12 5 12 16 8 4 19 11 2 4 5 6 8 5 6 4 18 10 4 2 216 6 6 6 2 4 12 8 3 11 5 6 14 5 3 13 4 5 4 5 3 28 6 3 7 219 3 9 7 3 10 6 3 4 19 5 7 11 6 15 19 4 13 11 3 7 5 10 2 8 11 2 6 4 6 24 6 3 3 3 3 6 18 4 11 4 2 5 10 8 3 9 5 3 4 5 6 2 5 7 4 4 14 6 4 4 5 5 7 2 4 3 7 3 3 6 4 5 4 4 4 3 3 3 3 8 14 2 3 5 3 2 4 5 3 7 3 3 18 3 4 4 5 7 3 3 3 13 5 4 8 211 5 5 3 5 2 5 4 2 655 6 3 5 11 2 5 3 12 9 15 11 5 12 217 2 6 17 3 3 207 5 5 4 5 9 3 2 8 5 4 3 2 5 12 4 14 5 4 2 13 5 8 4 225 4 3 4 5 4 3 3 6 23 9 2 6 7 233 4 4 6 18 3 4 6 3 4 4 2 3 7 4 13 227 4 3 5 4 2 12 9 17 3 7 14 6 4 5 21 4 8 9 2 9 25 16 3 6 4 7 8 5 2 3 5 4 3 3 5 3 3 3 2 3 19 2 4 3 4 2 3 4 4 2 4 3 3 3 2 6 3 17 5 6 4 3 13 5 3 3 3 4 9 4 2 14 12 4 5 24 4 3 37 12 11 21 3 4 3 13 4 2 3 15 4 11 4 4 3 8 3 4 4 12 8 5 3 3 4 2 220 3 5 223 3 3 3 10 3 15 4 241 9 7 3 6 6 23 4 13 7 3 4 7 4 9 3 3 4 10 5 5 1 5 24 2 4 5 5 6 14 3 8 2 3 5 13 13 3 5 2 3 15 3 4 2 10 4 4 4 5 5 3 5 3 4 7 4 27 3 6 4 15 3 5 6 6 5 4 8 3 9 2 6 3 4 3 7 4 18 3 11 3 3 8 9 7 24 3 219 7 10 4 5 9 12 2 5 4 4 4 3 3 19 5 8 16 8 6 22 3 23 3 242 9 4 3 3 5 7 3 3 5 8 3 7 5 14 8 10 3 4 3 7 4 6 7 4 10 4 3 11 3 7 10 3 13 6 8 12 10 5 7 9 3 4 7 7 10 8 30 9 19 4 3 19 15 4 13 3 215 223 4 7 4 8 17 16 3 7 6 5 5 4 12 3 7 4 4 13 4 5 2 5 6 5 6 6 7 10 18 23 9 3 3 6 5 2 4 2 7 3 3 2 5 5 14 10 224 6 3 4 3 7 5 9 3 6 4 2 5 11 4 3 3 2 8 4 7 4 10 7 3 3 18 18 17 3 3 3 4 5 3 3 4 12 7 3 11 13 5 4 7 13 5 4 11 3 12 3 6 4 4 21 4 6 9 5 3 10 8 4 6 4 4 6 5 4 8 6 4 6 4 4 5 9 6 3 4 2 9 3 18 2 4 3 13 3 6 6 8 7 9 3 2 16 3 4 6 3 2 33 22 14 4 9 12 4 5 6 3 23 9 4 3 5 5 3 4 5 3 5 3 10 4 5 5 8 4 4 6 8 5 4 3 4 6 3 3 3 5 9 12 6 5 9 3 5 3 2 2 2 18 3 2 21 2 5 4 6 4 5 10 3 9 3 2 10 7 3 6 6 4 4 8 12 7 3 7 3 3 9 3 4 5 4 4 5 5 10 15 4 4 14 6 227 3 14 5 216 22 5 4 2 2 6 3 4 2 9 9 4 3 28 13 11 4 5 3 3 2 3 3 5 3 4 3 5 23 26 3 4 5 6 4 6 3 5 5 3 4 3 2 2 2 7 14 3 6 7 17 2 2 15 14 16 4 6 7 13 6 4 5 6 16 3 3 28 3 6 15 3 9 2 4 6 3 3 22 4 12 6 7 2 5 4 10 3 16 6 9 2 5 12 7 5 5 5 5 2 11 9 17 4 3 11 7 3 5 15 4 3 4 211 8 7 5 4 7 6 7 6 3 6 5 6 5 3 4 4 26 4 6 10 4 4 3 2 3 3 4 5 9 3 9 4 4 5 5 8 2 4 2 3 8 4 11 19 5 8 6 3 5 6 12 3 2 4 16 12 3 4 4 8 6 5 6 6 219 8 222 6 16 3 13 19 5 4 3 11 6 10 4 7 7 12 5 3 3 5 6 10 3 8 2 5 4 7 2 4 4 2 12 9 6 4 2 40 2 4 10 4 223 4 2 20 6 7 24 5 4 5 2 20 16 6 5 13 2 3 3 19 3 2 4 5 6 7 11 12 5 6 7 7 3 5 3 5 3 14 3 4 4 2 11 1 7 3 9 6 11 12 5 8 6 221 4 2 12 4 3 15 4 5 226 7 218 7 5 4 5 18 4 5 9 4 4 2 9 18 18 9 5 6 6 3 3 7 3 5 4 4 4 12 3 6 31 5 4 7 3 6 5 6 5 11 2 2 11 11 6 7 5 8 7 10 5 23 7 4 3 5 34 2 5 23 7 3 6 8 4 4 4 2 5 3 8 5 4 8 25 2 3 17 8 3 4 8 7 3 15 6 5 7 21 9 5 6 6 5 3 2 3 10 3 6 3 14 7 4 4 8 7 8 2 6 12 4 213 6 5 21 8 2 5 23 3 11 2 3 6 25 2 3 6 7 6 6 4 4 6 3 17 9 7 6 4 3 10 7 2 3 3 3 11 8 3 7 6 4 14 36 3 4 3 3 22 13 21 4 2 7 4 4 17 15 3 7 11 2 4 7 6 209 6 3 2 2 24 4 9 4 3 3 3 29 2 2 4 3 3 5 4 6 3 3 2 4 ================================================ FILE: vendor/github.com/beorn7/perks/quantile/stream.go ================================================ // Package quantile computes approximate quantiles over an unbounded data // stream within low memory and CPU bounds. // // A small amount of accuracy is traded to achieve the above properties. // // Multiple streams can be merged before calling Query to generate a single set // of results. This is meaningful when the streams represent the same type of // data. See Merge and Samples. // // For more detailed information about the algorithm used, see: // // Effective Computation of Biased Quantiles over Data Streams // // http://www.cs.rutgers.edu/~muthu/bquant.pdf package quantile import ( "math" "sort" ) // Sample holds an observed value and meta information for compression. JSON // tags have been added for convenience. type Sample struct { Value float64 `json:",string"` Width float64 `json:",string"` Delta float64 `json:",string"` } // Samples represents a slice of samples. It implements sort.Interface. type Samples []Sample func (a Samples) Len() int { return len(a) } func (a Samples) Less(i, j int) bool { return a[i].Value < a[j].Value } func (a Samples) Swap(i, j int) { a[i], a[j] = a[j], a[i] } type invariant func(s *stream, r float64) float64 // NewLowBiased returns an initialized Stream for low-biased quantiles // (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but // error guarantees can still be given even for the lower ranks of the data // distribution. // // The provided epsilon is a relative error, i.e. the true quantile of a value // returned by a query is guaranteed to be within (1±Epsilon)*Quantile. // // See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error // properties. func NewLowBiased(epsilon float64) *Stream { ƒ := func(s *stream, r float64) float64 { return 2 * epsilon * r } return newStream(ƒ) } // NewHighBiased returns an initialized Stream for high-biased quantiles // (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but // error guarantees can still be given even for the higher ranks of the data // distribution. // // The provided epsilon is a relative error, i.e. the true quantile of a value // returned by a query is guaranteed to be within 1-(1±Epsilon)*(1-Quantile). // // See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error // properties. func NewHighBiased(epsilon float64) *Stream { ƒ := func(s *stream, r float64) float64 { return 2 * epsilon * (s.n - r) } return newStream(ƒ) } // NewTargeted returns an initialized Stream concerned with a particular set of // quantile values that are supplied a priori. Knowing these a priori reduces // space and computation time. The targets map maps the desired quantiles to // their absolute errors, i.e. the true quantile of a value returned by a query // is guaranteed to be within (Quantile±Epsilon). // // See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties. func NewTargeted(targetMap map[float64]float64) *Stream { // Convert map to slice to avoid slow iterations on a map. // ƒ is called on the hot path, so converting the map to a slice // beforehand results in significant CPU savings. targets := targetMapToSlice(targetMap) ƒ := func(s *stream, r float64) float64 { var m = math.MaxFloat64 var f float64 for _, t := range targets { if t.quantile*s.n <= r { f = (2 * t.epsilon * r) / t.quantile } else { f = (2 * t.epsilon * (s.n - r)) / (1 - t.quantile) } if f < m { m = f } } return m } return newStream(ƒ) } type target struct { quantile float64 epsilon float64 } func targetMapToSlice(targetMap map[float64]float64) []target { targets := make([]target, 0, len(targetMap)) for quantile, epsilon := range targetMap { t := target{ quantile: quantile, epsilon: epsilon, } targets = append(targets, t) } return targets } // Stream computes quantiles for a stream of float64s. It is not thread-safe by // design. Take care when using across multiple goroutines. type Stream struct { *stream b Samples sorted bool } func newStream(ƒ invariant) *Stream { x := &stream{ƒ: ƒ} return &Stream{x, make(Samples, 0, 500), true} } // Insert inserts v into the stream. func (s *Stream) Insert(v float64) { s.insert(Sample{Value: v, Width: 1}) } func (s *Stream) insert(sample Sample) { s.b = append(s.b, sample) s.sorted = false if len(s.b) == cap(s.b) { s.flush() } } // Query returns the computed qth percentiles value. If s was created with // NewTargeted, and q is not in the set of quantiles provided a priori, Query // will return an unspecified result. func (s *Stream) Query(q float64) float64 { if !s.flushed() { // Fast path when there hasn't been enough data for a flush; // this also yields better accuracy for small sets of data. l := len(s.b) if l == 0 { return 0 } i := int(math.Ceil(float64(l) * q)) if i > 0 { i -= 1 } s.maybeSort() return s.b[i].Value } s.flush() return s.stream.query(q) } // Merge merges samples into the underlying streams samples. This is handy when // merging multiple streams from separate threads, database shards, etc. // // ATTENTION: This method is broken and does not yield correct results. The // underlying algorithm is not capable of merging streams correctly. func (s *Stream) Merge(samples Samples) { sort.Sort(samples) s.stream.merge(samples) } // Reset reinitializes and clears the list reusing the samples buffer memory. func (s *Stream) Reset() { s.stream.reset() s.b = s.b[:0] } // Samples returns stream samples held by s. func (s *Stream) Samples() Samples { if !s.flushed() { return s.b } s.flush() return s.stream.samples() } // Count returns the total number of samples observed in the stream // since initialization. func (s *Stream) Count() int { return len(s.b) + s.stream.count() } func (s *Stream) flush() { s.maybeSort() s.stream.merge(s.b) s.b = s.b[:0] } func (s *Stream) maybeSort() { if !s.sorted { s.sorted = true sort.Sort(s.b) } } func (s *Stream) flushed() bool { return len(s.stream.l) > 0 } type stream struct { n float64 l []Sample ƒ invariant } func (s *stream) reset() { s.l = s.l[:0] s.n = 0 } func (s *stream) insert(v float64) { s.merge(Samples{{v, 1, 0}}) } func (s *stream) merge(samples Samples) { // TODO(beorn7): This tries to merge not only individual samples, but // whole summaries. The paper doesn't mention merging summaries at // all. Unittests show that the merging is inaccurate. Find out how to // do merges properly. var r float64 i := 0 for _, sample := range samples { for ; i < len(s.l); i++ { c := s.l[i] if c.Value > sample.Value { // Insert at position i. s.l = append(s.l, Sample{}) copy(s.l[i+1:], s.l[i:]) s.l[i] = Sample{ sample.Value, sample.Width, math.Max(sample.Delta, math.Floor(s.ƒ(s, r))-1), // TODO(beorn7): How to calculate delta correctly? } i++ goto inserted } r += c.Width } s.l = append(s.l, Sample{sample.Value, sample.Width, 0}) i++ inserted: s.n += sample.Width r += sample.Width } s.compress() } func (s *stream) count() int { return int(s.n) } func (s *stream) query(q float64) float64 { t := math.Ceil(q * s.n) t += math.Ceil(s.ƒ(s, t) / 2) p := s.l[0] var r float64 for _, c := range s.l[1:] { r += p.Width if r+c.Width+c.Delta > t { return p.Value } p = c } return p.Value } func (s *stream) compress() { if len(s.l) < 2 { return } x := s.l[len(s.l)-1] xi := len(s.l) - 1 r := s.n - 1 - x.Width for i := len(s.l) - 2; i >= 0; i-- { c := s.l[i] if c.Width+x.Width+x.Delta <= s.ƒ(s, r) { x.Width += c.Width s.l[xi] = x // Remove element at i. copy(s.l[i:], s.l[i+1:]) s.l = s.l[:len(s.l)-1] xi -= 1 } else { x = c xi = i } r -= c.Width } } func (s *stream) samples() Samples { samples := make(Samples, len(s.l)) copy(samples, s.l) return samples } ================================================ FILE: vendor/github.com/cespare/xxhash/v2/LICENSE.txt ================================================ Copyright (c) 2016 Caleb Spare MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: vendor/github.com/cespare/xxhash/v2/README.md ================================================ # xxhash [![Go Reference](https://pkg.go.dev/badge/github.com/cespare/xxhash/v2.svg)](https://pkg.go.dev/github.com/cespare/xxhash/v2) [![Test](https://github.com/cespare/xxhash/actions/workflows/test.yml/badge.svg)](https://github.com/cespare/xxhash/actions/workflows/test.yml) xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a high-quality hashing algorithm that is much faster than anything in the Go standard library. This package provides a straightforward API: ``` func Sum64(b []byte) uint64 func Sum64String(s string) uint64 type Digest struct{ ... } func New() *Digest ``` The `Digest` type implements hash.Hash64. Its key methods are: ``` func (*Digest) Write([]byte) (int, error) func (*Digest) WriteString(string) (int, error) func (*Digest) Sum64() uint64 ``` The package is written with optimized pure Go and also contains even faster assembly implementations for amd64 and arm64. If desired, the `purego` build tag opts into using the Go code even on those architectures. [xxHash]: http://cyan4973.github.io/xxHash/ ## Compatibility This package is in a module and the latest code is in version 2 of the module. You need a version of Go with at least "minimal module compatibility" to use github.com/cespare/xxhash/v2: * 1.9.7+ for Go 1.9 * 1.10.3+ for Go 1.10 * Go 1.11 or later I recommend using the latest release of Go. ## Benchmarks Here are some quick benchmarks comparing the pure-Go and assembly implementations of Sum64. | input size | purego | asm | | ---------- | --------- | --------- | | 4 B | 1.3 GB/s | 1.2 GB/s | | 16 B | 2.9 GB/s | 3.5 GB/s | | 100 B | 6.9 GB/s | 8.1 GB/s | | 4 KB | 11.7 GB/s | 16.7 GB/s | | 10 MB | 12.0 GB/s | 17.3 GB/s | These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C CPU using the following commands under Go 1.19.2: ``` benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$') benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$') ``` ## Projects using this package - [InfluxDB](https://github.com/influxdata/influxdb) - [Prometheus](https://github.com/prometheus/prometheus) - [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) - [FreeCache](https://github.com/coocood/freecache) - [FastCache](https://github.com/VictoriaMetrics/fastcache) ================================================ FILE: vendor/github.com/cespare/xxhash/v2/testall.sh ================================================ #!/bin/bash set -eu -o pipefail # Small convenience script for running the tests with various combinations of # arch/tags. This assumes we're running on amd64 and have qemu available. go test ./... go test -tags purego ./... GOARCH=arm64 go test GOARCH=arm64 go test -tags purego ================================================ FILE: vendor/github.com/cespare/xxhash/v2/xxhash.go ================================================ // Package xxhash implements the 64-bit variant of xxHash (XXH64) as described // at http://cyan4973.github.io/xxHash/. package xxhash import ( "encoding/binary" "errors" "math/bits" ) const ( prime1 uint64 = 11400714785074694791 prime2 uint64 = 14029467366897019727 prime3 uint64 = 1609587929392839161 prime4 uint64 = 9650029242287828579 prime5 uint64 = 2870177450012600261 ) // Store the primes in an array as well. // // The consts are used when possible in Go code to avoid MOVs but we need a // contiguous array of the assembly code. var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5} // Digest implements hash.Hash64. type Digest struct { v1 uint64 v2 uint64 v3 uint64 v4 uint64 total uint64 mem [32]byte n int // how much of mem is used } // New creates a new Digest that computes the 64-bit xxHash algorithm. func New() *Digest { var d Digest d.Reset() return &d } // Reset clears the Digest's state so that it can be reused. func (d *Digest) Reset() { d.v1 = primes[0] + prime2 d.v2 = prime2 d.v3 = 0 d.v4 = -primes[0] d.total = 0 d.n = 0 } // Size always returns 8 bytes. func (d *Digest) Size() int { return 8 } // BlockSize always returns 32 bytes. func (d *Digest) BlockSize() int { return 32 } // Write adds more data to d. It always returns len(b), nil. func (d *Digest) Write(b []byte) (n int, err error) { n = len(b) d.total += uint64(n) memleft := d.mem[d.n&(len(d.mem)-1):] if d.n+n < 32 { // This new data doesn't even fill the current block. copy(memleft, b) d.n += n return } if d.n > 0 { // Finish off the partial block. c := copy(memleft, b) d.v1 = round(d.v1, u64(d.mem[0:8])) d.v2 = round(d.v2, u64(d.mem[8:16])) d.v3 = round(d.v3, u64(d.mem[16:24])) d.v4 = round(d.v4, u64(d.mem[24:32])) b = b[c:] d.n = 0 } if len(b) >= 32 { // One or more full blocks left. nw := writeBlocks(d, b) b = b[nw:] } // Store any remaining partial block. copy(d.mem[:], b) d.n = len(b) return } // Sum appends the current hash to b and returns the resulting slice. func (d *Digest) Sum(b []byte) []byte { s := d.Sum64() return append( b, byte(s>>56), byte(s>>48), byte(s>>40), byte(s>>32), byte(s>>24), byte(s>>16), byte(s>>8), byte(s), ) } // Sum64 returns the current hash. func (d *Digest) Sum64() uint64 { var h uint64 if d.total >= 32 { v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4 h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) h = mergeRound(h, v1) h = mergeRound(h, v2) h = mergeRound(h, v3) h = mergeRound(h, v4) } else { h = d.v3 + prime5 } h += d.total b := d.mem[:d.n&(len(d.mem)-1)] for ; len(b) >= 8; b = b[8:] { k1 := round(0, u64(b[:8])) h ^= k1 h = rol27(h)*prime1 + prime4 } if len(b) >= 4 { h ^= uint64(u32(b[:4])) * prime1 h = rol23(h)*prime2 + prime3 b = b[4:] } for ; len(b) > 0; b = b[1:] { h ^= uint64(b[0]) * prime5 h = rol11(h) * prime1 } h ^= h >> 33 h *= prime2 h ^= h >> 29 h *= prime3 h ^= h >> 32 return h } const ( magic = "xxh\x06" marshaledSize = len(magic) + 8*5 + 32 ) // MarshalBinary implements the encoding.BinaryMarshaler interface. func (d *Digest) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize) b = append(b, magic...) b = appendUint64(b, d.v1) b = appendUint64(b, d.v2) b = appendUint64(b, d.v3) b = appendUint64(b, d.v4) b = appendUint64(b, d.total) b = append(b, d.mem[:d.n]...) b = b[:len(b)+len(d.mem)-d.n] return b, nil } // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. func (d *Digest) UnmarshalBinary(b []byte) error { if len(b) < len(magic) || string(b[:len(magic)]) != magic { return errors.New("xxhash: invalid hash state identifier") } if len(b) != marshaledSize { return errors.New("xxhash: invalid hash state size") } b = b[len(magic):] b, d.v1 = consumeUint64(b) b, d.v2 = consumeUint64(b) b, d.v3 = consumeUint64(b) b, d.v4 = consumeUint64(b) b, d.total = consumeUint64(b) copy(d.mem[:], b) d.n = int(d.total % uint64(len(d.mem))) return nil } func appendUint64(b []byte, x uint64) []byte { var a [8]byte binary.LittleEndian.PutUint64(a[:], x) return append(b, a[:]...) } func consumeUint64(b []byte) ([]byte, uint64) { x := u64(b) return b[8:], x } func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) } func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } func round(acc, input uint64) uint64 { acc += input * prime2 acc = rol31(acc) acc *= prime1 return acc } func mergeRound(acc, val uint64) uint64 { val = round(0, val) acc ^= val acc = acc*prime1 + prime4 return acc } func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) } func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) } func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) } func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) } func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) } func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) } func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) } func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) } ================================================ FILE: vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s ================================================ //go:build !appengine && gc && !purego // +build !appengine // +build gc // +build !purego #include "textflag.h" // Registers: #define h AX #define d AX #define p SI // pointer to advance through b #define n DX #define end BX // loop end #define v1 R8 #define v2 R9 #define v3 R10 #define v4 R11 #define x R12 #define prime1 R13 #define prime2 R14 #define prime4 DI #define round(acc, x) \ IMULQ prime2, x \ ADDQ x, acc \ ROLQ $31, acc \ IMULQ prime1, acc // round0 performs the operation x = round(0, x). #define round0(x) \ IMULQ prime2, x \ ROLQ $31, x \ IMULQ prime1, x // mergeRound applies a merge round on the two registers acc and x. // It assumes that prime1, prime2, and prime4 have been loaded. #define mergeRound(acc, x) \ round0(x) \ XORQ x, acc \ IMULQ prime1, acc \ ADDQ prime4, acc // blockLoop processes as many 32-byte blocks as possible, // updating v1, v2, v3, and v4. It assumes that there is at least one block // to process. #define blockLoop() \ loop: \ MOVQ +0(p), x \ round(v1, x) \ MOVQ +8(p), x \ round(v2, x) \ MOVQ +16(p), x \ round(v3, x) \ MOVQ +24(p), x \ round(v4, x) \ ADDQ $32, p \ CMPQ p, end \ JLE loop // func Sum64(b []byte) uint64 TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32 // Load fixed primes. MOVQ ·primes+0(SB), prime1 MOVQ ·primes+8(SB), prime2 MOVQ ·primes+24(SB), prime4 // Load slice. MOVQ b_base+0(FP), p MOVQ b_len+8(FP), n LEAQ (p)(n*1), end // The first loop limit will be len(b)-32. SUBQ $32, end // Check whether we have at least one block. CMPQ n, $32 JLT noBlocks // Set up initial state (v1, v2, v3, v4). MOVQ prime1, v1 ADDQ prime2, v1 MOVQ prime2, v2 XORQ v3, v3 XORQ v4, v4 SUBQ prime1, v4 blockLoop() MOVQ v1, h ROLQ $1, h MOVQ v2, x ROLQ $7, x ADDQ x, h MOVQ v3, x ROLQ $12, x ADDQ x, h MOVQ v4, x ROLQ $18, x ADDQ x, h mergeRound(h, v1) mergeRound(h, v2) mergeRound(h, v3) mergeRound(h, v4) JMP afterBlocks noBlocks: MOVQ ·primes+32(SB), h afterBlocks: ADDQ n, h ADDQ $24, end CMPQ p, end JG try4 loop8: MOVQ (p), x ADDQ $8, p round0(x) XORQ x, h ROLQ $27, h IMULQ prime1, h ADDQ prime4, h CMPQ p, end JLE loop8 try4: ADDQ $4, end CMPQ p, end JG try1 MOVL (p), x ADDQ $4, p IMULQ prime1, x XORQ x, h ROLQ $23, h IMULQ prime2, h ADDQ ·primes+16(SB), h try1: ADDQ $4, end CMPQ p, end JGE finalize loop1: MOVBQZX (p), x ADDQ $1, p IMULQ ·primes+32(SB), x XORQ x, h ROLQ $11, h IMULQ prime1, h CMPQ p, end JL loop1 finalize: MOVQ h, x SHRQ $33, x XORQ x, h IMULQ prime2, h MOVQ h, x SHRQ $29, x XORQ x, h IMULQ ·primes+16(SB), h MOVQ h, x SHRQ $32, x XORQ x, h MOVQ h, ret+24(FP) RET // func writeBlocks(d *Digest, b []byte) int TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 // Load fixed primes needed for round. MOVQ ·primes+0(SB), prime1 MOVQ ·primes+8(SB), prime2 // Load slice. MOVQ b_base+8(FP), p MOVQ b_len+16(FP), n LEAQ (p)(n*1), end SUBQ $32, end // Load vN from d. MOVQ s+0(FP), d MOVQ 0(d), v1 MOVQ 8(d), v2 MOVQ 16(d), v3 MOVQ 24(d), v4 // We don't need to check the loop condition here; this function is // always called with at least one block of data to process. blockLoop() // Copy vN back to d. MOVQ v1, 0(d) MOVQ v2, 8(d) MOVQ v3, 16(d) MOVQ v4, 24(d) // The number of bytes written is p minus the old base pointer. SUBQ b_base+8(FP), p MOVQ p, ret+32(FP) RET ================================================ FILE: vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s ================================================ //go:build !appengine && gc && !purego // +build !appengine // +build gc // +build !purego #include "textflag.h" // Registers: #define digest R1 #define h R2 // return value #define p R3 // input pointer #define n R4 // input length #define nblocks R5 // n / 32 #define prime1 R7 #define prime2 R8 #define prime3 R9 #define prime4 R10 #define prime5 R11 #define v1 R12 #define v2 R13 #define v3 R14 #define v4 R15 #define x1 R20 #define x2 R21 #define x3 R22 #define x4 R23 #define round(acc, x) \ MADD prime2, acc, x, acc \ ROR $64-31, acc \ MUL prime1, acc // round0 performs the operation x = round(0, x). #define round0(x) \ MUL prime2, x \ ROR $64-31, x \ MUL prime1, x #define mergeRound(acc, x) \ round0(x) \ EOR x, acc \ MADD acc, prime4, prime1, acc // blockLoop processes as many 32-byte blocks as possible, // updating v1, v2, v3, and v4. It assumes that n >= 32. #define blockLoop() \ LSR $5, n, nblocks \ PCALIGN $16 \ loop: \ LDP.P 16(p), (x1, x2) \ LDP.P 16(p), (x3, x4) \ round(v1, x1) \ round(v2, x2) \ round(v3, x3) \ round(v4, x4) \ SUB $1, nblocks \ CBNZ nblocks, loop // func Sum64(b []byte) uint64 TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32 LDP b_base+0(FP), (p, n) LDP ·primes+0(SB), (prime1, prime2) LDP ·primes+16(SB), (prime3, prime4) MOVD ·primes+32(SB), prime5 CMP $32, n CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 } BLT afterLoop ADD prime1, prime2, v1 MOVD prime2, v2 MOVD $0, v3 NEG prime1, v4 blockLoop() ROR $64-1, v1, x1 ROR $64-7, v2, x2 ADD x1, x2 ROR $64-12, v3, x3 ROR $64-18, v4, x4 ADD x3, x4 ADD x2, x4, h mergeRound(h, v1) mergeRound(h, v2) mergeRound(h, v3) mergeRound(h, v4) afterLoop: ADD n, h TBZ $4, n, try8 LDP.P 16(p), (x1, x2) round0(x1) // NOTE: here and below, sequencing the EOR after the ROR (using a // rotated register) is worth a small but measurable speedup for small // inputs. ROR $64-27, h EOR x1 @> 64-27, h, h MADD h, prime4, prime1, h round0(x2) ROR $64-27, h EOR x2 @> 64-27, h, h MADD h, prime4, prime1, h try8: TBZ $3, n, try4 MOVD.P 8(p), x1 round0(x1) ROR $64-27, h EOR x1 @> 64-27, h, h MADD h, prime4, prime1, h try4: TBZ $2, n, try2 MOVWU.P 4(p), x2 MUL prime1, x2 ROR $64-23, h EOR x2 @> 64-23, h, h MADD h, prime3, prime2, h try2: TBZ $1, n, try1 MOVHU.P 2(p), x3 AND $255, x3, x1 LSR $8, x3, x2 MUL prime5, x1 ROR $64-11, h EOR x1 @> 64-11, h, h MUL prime1, h MUL prime5, x2 ROR $64-11, h EOR x2 @> 64-11, h, h MUL prime1, h try1: TBZ $0, n, finalize MOVBU (p), x4 MUL prime5, x4 ROR $64-11, h EOR x4 @> 64-11, h, h MUL prime1, h finalize: EOR h >> 33, h MUL prime2, h EOR h >> 29, h MUL prime3, h EOR h >> 32, h MOVD h, ret+24(FP) RET // func writeBlocks(d *Digest, b []byte) int TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 LDP ·primes+0(SB), (prime1, prime2) // Load state. Assume v[1-4] are stored contiguously. MOVD d+0(FP), digest LDP 0(digest), (v1, v2) LDP 16(digest), (v3, v4) LDP b_base+8(FP), (p, n) blockLoop() // Store updated state. STP (v1, v2), 0(digest) STP (v3, v4), 16(digest) BIC $31, n MOVD n, ret+32(FP) RET ================================================ FILE: vendor/github.com/cespare/xxhash/v2/xxhash_asm.go ================================================ //go:build (amd64 || arm64) && !appengine && gc && !purego // +build amd64 arm64 // +build !appengine // +build gc // +build !purego package xxhash // Sum64 computes the 64-bit xxHash digest of b. // //go:noescape func Sum64(b []byte) uint64 //go:noescape func writeBlocks(d *Digest, b []byte) int ================================================ FILE: vendor/github.com/cespare/xxhash/v2/xxhash_other.go ================================================ //go:build (!amd64 && !arm64) || appengine || !gc || purego // +build !amd64,!arm64 appengine !gc purego package xxhash // Sum64 computes the 64-bit xxHash digest of b. func Sum64(b []byte) uint64 { // A simpler version would be // d := New() // d.Write(b) // return d.Sum64() // but this is faster, particularly for small inputs. n := len(b) var h uint64 if n >= 32 { v1 := primes[0] + prime2 v2 := prime2 v3 := uint64(0) v4 := -primes[0] for len(b) >= 32 { v1 = round(v1, u64(b[0:8:len(b)])) v2 = round(v2, u64(b[8:16:len(b)])) v3 = round(v3, u64(b[16:24:len(b)])) v4 = round(v4, u64(b[24:32:len(b)])) b = b[32:len(b):len(b)] } h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) h = mergeRound(h, v1) h = mergeRound(h, v2) h = mergeRound(h, v3) h = mergeRound(h, v4) } else { h = prime5 } h += uint64(n) for ; len(b) >= 8; b = b[8:] { k1 := round(0, u64(b[:8])) h ^= k1 h = rol27(h)*prime1 + prime4 } if len(b) >= 4 { h ^= uint64(u32(b[:4])) * prime1 h = rol23(h)*prime2 + prime3 b = b[4:] } for ; len(b) > 0; b = b[1:] { h ^= uint64(b[0]) * prime5 h = rol11(h) * prime1 } h ^= h >> 33 h *= prime2 h ^= h >> 29 h *= prime3 h ^= h >> 32 return h } func writeBlocks(d *Digest, b []byte) int { v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4 n := len(b) for len(b) >= 32 { v1 = round(v1, u64(b[0:8:len(b)])) v2 = round(v2, u64(b[8:16:len(b)])) v3 = round(v3, u64(b[16:24:len(b)])) v4 = round(v4, u64(b[24:32:len(b)])) b = b[32:len(b):len(b)] } d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4 return n - len(b) } ================================================ FILE: vendor/github.com/cespare/xxhash/v2/xxhash_safe.go ================================================ //go:build appengine // +build appengine // This file contains the safe implementations of otherwise unsafe-using code. package xxhash // Sum64String computes the 64-bit xxHash digest of s. func Sum64String(s string) uint64 { return Sum64([]byte(s)) } // WriteString adds more data to d. It always returns len(s), nil. func (d *Digest) WriteString(s string) (n int, err error) { return d.Write([]byte(s)) } ================================================ FILE: vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go ================================================ //go:build !appengine // +build !appengine // This file encapsulates usage of unsafe. // xxhash_safe.go contains the safe implementations. package xxhash import ( "unsafe" ) // In the future it's possible that compiler optimizations will make these // XxxString functions unnecessary by realizing that calls such as // Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205. // If that happens, even if we keep these functions they can be replaced with // the trivial safe code. // NOTE: The usual way of doing an unsafe string-to-[]byte conversion is: // // var b []byte // bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) // bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data // bh.Len = len(s) // bh.Cap = len(s) // // Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough // weight to this sequence of expressions that any function that uses it will // not be inlined. Instead, the functions below use a different unsafe // conversion designed to minimize the inliner weight and allow both to be // inlined. There is also a test (TestInlining) which verifies that these are // inlined. // // See https://github.com/golang/go/issues/42739 for discussion. // Sum64String computes the 64-bit xxHash digest of s. // It may be faster than Sum64([]byte(s)) by avoiding a copy. func Sum64String(s string) uint64 { b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})) return Sum64(b) } // WriteString adds more data to d. It always returns len(s), nil. // It may be faster than Write([]byte(s)) by avoiding a copy. func (d *Digest) WriteString(s string) (n int, err error) { d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))) // d.Write always returns len(s), nil. // Ignoring the return output and returning these fixed values buys a // savings of 6 in the inliner's cost model. return len(s), nil } // sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout // of the first two words is the same as the layout of a string. type sliceHeader struct { s string cap int } ================================================ FILE: vendor/github.com/cloudflare/backoff/.travis.yml ================================================ sudo: false language: go go: - 1.6 - 1.7 - tip before_script: - go get github.com/GeertJohan/fgt - go get github.com/golang/lint/golint - go get golang.org/x/tools/cmd/goimports - go get honnef.co/go/staticcheck/cmd/staticcheck script: - find . -name \*.go | xargs fgt goimports -l - fgt go vet ./... - fgt golint ./... - fgt staticcheck ./... - go test ./... notifications: email: recipients: - kyle@cloudflare.com ================================================ FILE: vendor/github.com/cloudflare/backoff/LICENSE ================================================ Copyright (c) 2016 CloudFlare Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: vendor/github.com/cloudflare/backoff/README.md ================================================ # backoff ## Go implementation of "Exponential Backoff And Jitter" This package implements the backoff strategy described in the AWS Architecture Blog article ["Exponential Backoff And Jitter"](http://www.awsarchitectureblog.com/2015/03/backoff.html). Essentially, the backoff has an interval `time.Duration`; the *nth* call to backoff will return an a `time.Duration` that is *2 n * interval*. If jitter is enabled (which is the default behaviour), the duration is a random value between 0 and *2 n * interval*. The backoff is configured with a maximum duration that will not be exceeded; e.g., by default, the longest duration returned is `backoff.DefaultMaxDuration`. ## Usage A `Backoff` is initialised with a call to `New`. Using zero values causes it to use `DefaultMaxDuration` and `DefaultInterval` as the maximum duration and interval. ``` package something import "github.com/cloudflare/backoff" func retryable() { b := backoff.New(0, 0) for { err := someOperation() if err == nil { break } log.Printf("error in someOperation: %v", err) <-time.After(b.Duration()) } log.Printf("succeeded after %d tries", b.Tries()+1) b.Reset() } ``` It can also be used to rate limit code that should retry infinitely, but which does not use `Backoff` itself. ``` package something import ( "time" "github.com/cloudflare/backoff" ) func retryable() { b := backoff.New(0, 0) b.SetDecay(30 * time.Second) for { // b will reset if someOperation returns later than // the last call to b.Duration() + 30s. err := someOperation() if err == nil { break } log.Printf("error in someOperation: %v", err) <-time.After(b.Duration()) } } ``` ## Tunables * `NewWithoutJitter` creates a Backoff that doesn't use jitter. The default behaviour is controlled by two variables: * `DefaultInterval` sets the base interval for backoffs created with the zero `time.Duration` value in the `Interval` field. * `DefaultMaxDuration` sets the maximum duration for backoffs created with the zero `time.Duration` value in the `MaxDuration` field. ================================================ FILE: vendor/github.com/cloudflare/backoff/backoff.go ================================================ // Package backoff contains an implementation of an intelligent backoff // strategy. It is based on the approach in the AWS architecture blog // article titled "Exponential Backoff And Jitter", which is found at // http://www.awsarchitectureblog.com/2015/03/backoff.html. // // Essentially, the backoff has an interval `time.Duration`; the nth // call to backoff will return a `time.Duration` that is 2^n * // interval. If jitter is enabled (which is the default behaviour), // the duration is a random value between 0 and 2^n * interval. The // backoff is configured with a maximum duration that will not be // exceeded. // // The `New` function will attempt to use the system's cryptographic // random number generator to seed a Go math/rand random number // source. If this fails, the package will panic on startup. package backoff import ( "crypto/rand" "encoding/binary" "io" "math" mrand "math/rand" "sync" "time" ) var prngMu sync.Mutex var prng *mrand.Rand // DefaultInterval is used when a Backoff is initialised with a // zero-value Interval. var DefaultInterval = 5 * time.Minute // DefaultMaxDuration is maximum amount of time that the backoff will // delay for. var DefaultMaxDuration = 6 * time.Hour // A Backoff contains the information needed to intelligently backoff // and retry operations using an exponential backoff algorithm. It should // be initialised with a call to `New`. // // Only use a Backoff from a single goroutine, it is not safe for concurrent // access. type Backoff struct { // maxDuration is the largest possible duration that can be // returned from a call to Duration. maxDuration time.Duration // interval controls the time step for backing off. interval time.Duration // noJitter controls whether to use the "Full Jitter" // improvement to attempt to smooth out spikes in a high // contention scenario. If noJitter is set to true, no // jitter will be introduced. noJitter bool // decay controls the decay of n. If it is non-zero, n is // reset if more than the last backoff + decay has elapsed since // the last try. decay time.Duration n uint64 lastTry time.Time } // New creates a new backoff with the specified max duration and // interval. Zero values may be used to use the default values. // // Panics if either max or interval is negative. func New(max time.Duration, interval time.Duration) *Backoff { if max < 0 || interval < 0 { panic("backoff: max or interval is negative") } b := &Backoff{ maxDuration: max, interval: interval, } b.setup() return b } // NewWithoutJitter works similarly to New, except that the created // Backoff will not use jitter. func NewWithoutJitter(max time.Duration, interval time.Duration) *Backoff { b := New(max, interval) b.noJitter = true return b } func init() { var buf [8]byte var n int64 _, err := io.ReadFull(rand.Reader, buf[:]) if err != nil { panic(err.Error()) } n = int64(binary.LittleEndian.Uint64(buf[:])) src := mrand.NewSource(n) prng = mrand.New(src) } func (b *Backoff) setup() { if b.interval == 0 { b.interval = DefaultInterval } if b.maxDuration == 0 { b.maxDuration = DefaultMaxDuration } } // Duration returns a time.Duration appropriate for the backoff, // incrementing the attempt counter. func (b *Backoff) Duration() time.Duration { b.setup() b.decayN() t := b.duration(b.n) if b.n < math.MaxUint64 { b.n++ } if !b.noJitter { prngMu.Lock() t = time.Duration(prng.Int63n(int64(t))) prngMu.Unlock() } return t } // requires b to be locked. func (b *Backoff) duration(n uint64) (t time.Duration) { // Saturate pow pow := time.Duration(math.MaxInt64) if n < 63 { pow = 1 << n } t = b.interval * pow if t/pow != b.interval || t > b.maxDuration { t = b.maxDuration } return } // Reset resets the attempt counter of a backoff. // // It should be called when the rate-limited action succeeds. func (b *Backoff) Reset() { b.lastTry = time.Time{} b.n = 0 } // SetDecay sets the duration after which the try counter will be reset. // Panics if decay is smaller than 0. // // The decay only kicks in if at least the last backoff + decay has elapsed // since the last try. func (b *Backoff) SetDecay(decay time.Duration) { if decay < 0 { panic("backoff: decay < 0") } b.decay = decay } // requires b to be locked func (b *Backoff) decayN() { if b.decay == 0 { return } if b.lastTry.IsZero() { b.lastTry = time.Now() return } lastDuration := b.duration(b.n - 1) decayed := time.Since(b.lastTry) > lastDuration+b.decay b.lastTry = time.Now() if !decayed { return } b.n = 0 } ================================================ FILE: vendor/github.com/cloudflare/redoctober/LICENSE.md ================================================ ## Copyright & License This module is licensed under the terms of the BSD license. Copyright (c) 2013-2017, Nicholas Sullivan, Cloudflare Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: vendor/github.com/cloudflare/redoctober/client/client.go ================================================ package client import ( "bytes" "crypto/tls" "crypto/x509" "encoding/json" "errors" "fmt" "io/ioutil" "net/http" "github.com/cloudflare/redoctober/core" ) // RemoteServer represents a remote RedOctober server. type RemoteServer struct { client *http.Client serverAddress string } // NewRemoteServer generates a RemoteServer with the server address and // the root CA the server uses to authenticate itself. func NewRemoteServer(serverAddress, CAFile string) (*RemoteServer, error) { var rootCAs *x509.CertPool // populate a root CA pool from input CAfile // otherwise, use the system's default root CA set if CAFile != "" { rootCAs = x509.NewCertPool() pemBytes, err := ioutil.ReadFile(CAFile) if err != nil { return nil, errors.New("fail to read CA file: " + err.Error()) } ok := rootCAs.AppendCertsFromPEM(pemBytes) if !ok { return nil, errors.New("fail to populate CA root pool") } } tr := &http.Transport{ TLSClientConfig: &tls.Config{RootCAs: rootCAs}, DisableCompression: true, } server := &RemoteServer{ client: &http.Client{Transport: tr}, serverAddress: serverAddress, } return server, nil } // getURL creates URL for a specific path of the RemoteServer func (c *RemoteServer) getURL(path string) string { return fmt.Sprintf("https://%s%s", c.serverAddress, path) } // doAction sends req to the remote server and returns the response func (c *RemoteServer) doAction(action string, req []byte) ([]byte, error) { buf := bytes.NewBuffer(req) url := c.getURL("/" + action) resp, err := c.client.Post(url, "application/json", buf) if err != nil { return nil, err } body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } resp.Body.Close() // Return response body as error if status code != 200 if resp.StatusCode != http.StatusOK { return nil, errors.New(string(body)) } return body, nil } // unmarshalResponseData is a helper function that unmarshal response bytes // into ResponseData object. func unmarshalResponseData(respBytes []byte) (*core.ResponseData, error) { response := new(core.ResponseData) err := json.Unmarshal(respBytes, response) if err != nil { return nil, err } if response.Status != "ok" { return nil, errors.New(response.Status) } return response, nil } func unmarshalOwnersData(respBytes []byte) (*core.OwnersData, error) { response := new(core.OwnersData) err := json.Unmarshal(respBytes, response) if err != nil { return nil, err } if response.Status != "ok" { return nil, errors.New(response.Status) } return response, nil } // Create creates an admin account at the remote server func (c *RemoteServer) Create(req core.CreateRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("create", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // Summary returns the summary reported by the remote server func (c *RemoteServer) Summary(req core.SummaryRequest) (*core.SummaryData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("summary", reqBytes) if err != nil { return nil, err } response := new(core.SummaryData) err = json.Unmarshal(respBytes, response) if err != nil { return nil, err } if response.Status != "ok" { return nil, errors.New(response.Status) } return response, nil } // Delegate issues a delegate request to the remote server func (c *RemoteServer) Delegate(req core.DelegateRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("delegate", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // CreateUser issues a create-user request to the remote server func (c *RemoteServer) CreateUser(req core.CreateUserRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("create-user", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // Purge issues a purge request to the remote server func (c *RemoteServer) Purge(req core.DelegateRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("purge", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // Modify issues a modify request to the remote server func (c *RemoteServer) Modify(req core.ModifyRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("modify", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // Encrypt issues an encrypt request to the remote server func (c *RemoteServer) Encrypt(req core.EncryptRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("encrypt", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // ReEncrypt issues an re-encrypt request to the remote server func (c *RemoteServer) ReEncrypt(req core.ReEncryptRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("re-encrypt", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // Decrypt issues an decrypt request to the remote server func (c *RemoteServer) Decrypt(req core.DecryptRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("decrypt", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // SSHSignWith issues a SSH-sign-with request to the remote server func (c *RemoteServer) SSHSignWith(req core.SSHSignWithRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("ssh-sign-with", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // DecryptIntoData issues an decrypt request to the remote server and extract // the decrypted data from the response func (c *RemoteServer) DecryptIntoData(req core.DecryptRequest) ([]byte, error) { responseData, err := c.Decrypt(req) if err != nil { return nil, err } d := new(core.DecryptWithDelegates) err = json.Unmarshal(responseData.Response, d) if err != nil { return nil, err } return d.Data, nil } // Password issues an password request to the remote server func (c *RemoteServer) Password(req []byte) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("delegate", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // Owners issues an Owners request to the remote server func (c *RemoteServer) Owners(req core.OwnersRequest) (*core.OwnersData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("owners", reqBytes) if err != nil { return nil, err } return unmarshalOwnersData(respBytes) } // Order issues an order request to the remote server func (c *RemoteServer) Order(req core.OrderRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("order", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // OrderOutstanding issues an order outstanding request to the remote server func (c *RemoteServer) OrderOutstanding(req core.OrderOutstandingRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("orderout", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // OrderInfo issues an order info request to the remote server func (c *RemoteServer) OrderInfo(req core.OrderInfoRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("orderinfo", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // OrderCancel issues an order cancel request to the remote server func (c *RemoteServer) OrderCancel(req core.OrderInfoRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("ordercancel", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // Status returns the current delegation persistence state from the remote server. func (c *RemoteServer) Status(req core.StatusRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("status", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // Restore issues a restore request to the server. Note that a restore // request is the same as a delegation request, except that the user // and label lists are ignored. func (c *RemoteServer) Restore(req core.DelegateRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("restore", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } // ResetPersisted issues a persisted delegation reset request, // clearing out any persisted delegations. This must be done by an // admin user. func (c *RemoteServer) ResetPersisted(req core.PurgeRequest) (*core.ResponseData, error) { reqBytes, err := json.Marshal(req) if err != nil { return nil, err } respBytes, err := c.doAction("reset-persisted", reqBytes) if err != nil { return nil, err } return unmarshalResponseData(respBytes) } ================================================ FILE: vendor/github.com/cloudflare/redoctober/config/config.go ================================================ // Package config implements configuration structures for Red // October. package config import ( "encoding/json" "io/ioutil" ) // Server contains the configuration information required to start a // redoctober server. type Server struct { // Addr contains the host:port that the server should listen // on. Addr string `json:"address"` // CAPath contains the path to the TLS CA for client // authentication. This is an optional field. CAPath string `json:"ca_path,omitempty"` // KeyPaths and CertPaths contains a list of paths to TLS key // pairs that should be used to secure connections to the // server. The paths should be comma-separated. KeyPaths string `json:"private_keys"` CertPaths string `json:"certificates"` // Systemd indicates whether systemd socket activation should // be used instead of a normal port listener. Systemd bool `json:"use_systemd,omitempty"` } // UI contains the configuration information for the WWW API. type UI struct { // Root contains the base URL for the UI. Root string `json:"root"` // Static is an optional path for overriding the built in HTML // UI. Static string `json:"static"` } // HipChat contains the settings for Hipchat integration. The ID is // the name that should be used in the startup message. type HipChat struct { Host string `json:"host"` Room string `json:"room"` ID string `json:"id"` APIKey string `json:"api_key"` } // Valid returns true if the HipChat config is ready to be used for // HipChat notifications. func (hc *HipChat) Valid() bool { if hc.APIKey == "" { return false } if hc.Room == "" { return false } if hc.Host == "" { return false } return true } // Metrics contains the configuration for the Prometheus metrics // collector. type Metrics struct { Host string `json:"host"` Port string `json:"port"` } // Reporting contains configuration for error reporting. type Reporting struct { SentryDSN string `json:"sentry_dsn"` } // Delegations contains configuration for persisting delegations. type Delegations struct { // Persist controls whether delegations are persisted or not. Persist bool `json:"persist"` // Policy contains the MSP predicate for delegation // persistence, and users contains the users allowed // to delegate. Policy string `json:"policy"` Users []string `json:"users"` // Mechanism specifies the persistence mechanism to use. Mechanism string `json:"mechanism"` // Location contains location information for the persistence // mechanism, such as a file path or database connection // string. Location string `json:"location"` } // Config contains all the configuration options for a redoctober // instance. type Config struct { Server *Server `json:"server"` UI *UI `json:"ui"` HipChat *HipChat `json:"hipchat"` Metrics *Metrics `json:"metrics"` Reporting *Reporting `json:"reporting"` Delegations *Delegations `json:"delegations"` } // Valid ensures that the config has enough data to start a Red // October process. func (c *Config) Valid() bool { // The RedOctober API relies on TLS for security. if len(c.Server.CertPaths) == 0 || len(c.Server.KeyPaths) == 0 { return false } // The server needs some address to listen on. if c.Server.Addr == "" && !c.Server.Systemd { return false } return true } // New returns a new, empty config. func New() *Config { return &Config{ Server: &Server{}, UI: &UI{}, HipChat: &HipChat{}, Metrics: &Metrics{}, Reporting: &Reporting{}, Delegations: &Delegations{}, } } // Load reads a JSON-encoded config file from disk. func Load(path string) (*Config, error) { cfg := New() in, err := ioutil.ReadFile(path) if err != nil { return nil, err } err = json.Unmarshal(in, cfg) if err != nil { return nil, err } return cfg, nil } ================================================ FILE: vendor/github.com/cloudflare/redoctober/core/core.go ================================================ // Package core handles the main operations of the Red October server. // // Copyright (c) 2013 CloudFlare, Inc. package core import ( "crypto/rand" "encoding/json" "errors" "fmt" "log" "regexp" "strconv" "strings" "time" "github.com/cloudflare/redoctober/config" "github.com/cloudflare/redoctober/cryptor" "github.com/cloudflare/redoctober/hipchat" "github.com/cloudflare/redoctober/keycache" "github.com/cloudflare/redoctober/order" "github.com/cloudflare/redoctober/passvault" "github.com/cloudflare/redoctober/persist" "github.com/cloudflare/redoctober/report" "golang.org/x/crypto/ssh" ) var ( crypt *cryptor.Cryptor records passvault.Records orders order.Orderer ) // Each of these structures corresponds to the JSON expected on the // correspondingly named URI (e.g. the delegate structure maps to the // JSON that should be sent on the /delegate URI and it is handled by // the Delegate function below). type CreateRequest struct { Name string Password string } type SummaryRequest struct { Name string Password string } type PurgeRequest struct { Name string Password string } type DelegateRequest struct { Name string Password string Uses int Time string Slot string Users []string Labels []string } type CreateUserRequest struct { Name string Password string UserType string HipchatName string } type PasswordRequest struct { Name string Password string NewPassword string HipchatName string } type EncryptRequest struct { Name string Password string Minimum int Owners []string LeftOwners []string RightOwners []string Predicate string Data []byte Labels []string Usages []string } type ReEncryptRequest EncryptRequest type DecryptRequest struct { Name string Password string Data []byte } type SSHSignWithRequest struct { Name string Password string Data []byte TBSData []byte } type SSHSignatureWithDelegates struct { SignatureFormat string Signature []byte Secure bool Delegates []string } type OwnersRequest struct { Data []byte } type ModifyRequest struct { Name string Password string ToModify string Command string } type ExportRequest struct { Name string Password string } type OrderRequest struct { Name string Password string Duration string Uses int Users []string EncryptedData []byte Labels []string } type OrderInfoRequest struct { Name string Password string OrderNum string } type OrderOutstandingRequest struct { Name string Password string } type OrderCancelRequest struct { Name string Password string OrderNum string } type StatusRequest struct { Name string Password string } // These structures map the JSON responses that will be sent from the API type ResponseData struct { Status string Response []byte `json:",omitempty"` } type SummaryData struct { Status string State string Live map[string]ActiveUser All map[string]passvault.Summary } type ActiveUser struct { keycache.Usage AltNames map[string]string Admin bool Type string } type DecryptWithDelegates struct { Data []byte Secure bool Delegates []string } type OwnersData struct { Status string Owners []string Labels []string Predicate string } type StatusData struct { Status string } // Helper functions that create JSON responses sent by core func jsonStatusOk() ([]byte, error) { return json.Marshal(ResponseData{Status: "ok"}) } func jsonStatusError(err error) ([]byte, error) { return json.Marshal(ResponseData{Status: err.Error()}) } func jsonSummary() ([]byte, error) { state := crypt.Status() return json.Marshal(SummaryData{Status: "ok", State: state.State, Live: liveSummary(), All: records.GetSummary()}) } func jsonResponse(resp []byte) ([]byte, error) { return json.Marshal(ResponseData{Status: "ok", Response: resp}) } // validateUser checks that the username and password passed in are // correct. If admin is true, the user must be an admin as well. func validateUser(name, password string, admin bool) error { if records.NumRecords() == 0 { return errors.New("Vault is not created yet") } pr, ok := records.GetRecord(name) if !ok { return errors.New("User not present") } if err := pr.ValidatePassword(password); err != nil { return err } if admin && !pr.IsAdmin() { return errors.New("Admin required") } return nil } //Username must start with an alphanumeric character and can include "-" and "_" after the first var validName = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9\_\-]*$`).MatchString // validateName checks that the username and password pass a validation test. func validateName(name, password string) error { if !validName(name) { return errors.New("must start with an alphanumeric character and can include \"-\" or \"_\" after the first character") } if password == "" { return errors.New("Password must be at least one character") } return nil } // liveSummary creates a sanitized version of cryptor.LiveSummary() without any key material func liveSummary() map[string]ActiveUser { currLiveSummary := crypt.LiveSummary() summaryData := make(map[string]ActiveUser) for summaryInfo, activeUser := range currLiveSummary { sanitizedActiveUser := ActiveUser{ Usage: activeUser.Usage, AltNames: activeUser.AltNames, Admin: activeUser.Admin, Type: activeUser.Type, } summaryData[summaryInfo] = sanitizedActiveUser } return summaryData } // Init reads the records from disk from a given path func Init(path string, config *config.Config) error { var err error tags := map[string]string{"function": "core.Init"} defer func() { if err != nil { report.Check(err, tags) log.Printf("core.init failed: %v", err) } else { log.Printf("core.init success: path=%s", path) } }() if records, err = passvault.InitFrom(path); err != nil { err = fmt.Errorf("failed to load password vault %s: %s", path, err) } crypt, err = cryptor.New(&records, nil, config) if err != nil { return err } var hipchatClient hipchat.HipchatClient hc := config.HipChat if hc.Valid() { roomId, err := strconv.Atoi(hc.Room) if err != nil { return errors.New("core.init unable to use hipchat roomId provided") } hipchatClient = hipchat.HipchatClient{ ApiKey: hc.APIKey, RoomId: roomId, HcHost: hc.Host, RoHost: config.UI.Root, } name := hc.ID if name == "" { name = "Red October" } message := name + " has restarted." color := hipchat.GreenBackground status := crypt.Status() if status.State == persist.Inactive { message += " @here: persistence is currently " + status.State + "; the restore admins need to restore the saved delegations." color = hipchat.RedBackground } err = hipchatClient.Notify(message, color) if err != nil { return err } } orders = order.NewOrderer(hipchatClient) return nil } // Create processes a create request. func Create(jsonIn []byte) ([]byte, error) { var s CreateRequest var err error defer func() { if err != nil { log.Printf("core.create failed: user=%s %v", s.Name, err) } else { log.Printf("core.create success: user=%s", s.Name) } }() if err = json.Unmarshal(jsonIn, &s); err != nil { return jsonStatusError(err) } if records.NumRecords() != 0 { err = errors.New("Vault is already created") return jsonStatusError(err) } // Validate the Name and Password as valid if err = validateName(s.Name, s.Password); err != nil { return jsonStatusError(err) } if _, err = records.AddNewRecord(s.Name, s.Password, true, passvault.DefaultRecordType); err != nil { return jsonStatusError(err) } return jsonStatusOk() } // Summary processes a summary request. func Summary(jsonIn []byte) ([]byte, error) { var s SummaryRequest var err error defer func() { if err != nil { log.Printf("core.summary failed: user=%s %v", s.Name, err) } else { log.Printf("core.summary success: user=%s", s.Name) } }() err = crypt.Refresh() if err != nil { return jsonStatusError(err) } if err := json.Unmarshal(jsonIn, &s); err != nil { return jsonStatusError(err) } if records.NumRecords() == 0 { err = errors.New("vault has not been created") return jsonStatusError(err) } if err := validateUser(s.Name, s.Password, false); err != nil { return jsonStatusError(err) } return jsonSummary() } // Purge processes a delegation purge request. func Purge(jsonIn []byte) ([]byte, error) { var s PurgeRequest var err error defer func() { if err != nil { log.Printf("core.purge failed: user=%s %v", s.Name, err) } else { log.Printf("core.purge success: user=%s", s.Name) } }() if err = json.Unmarshal(jsonIn, &s); err != nil { return jsonStatusError(err) } if records.NumRecords() == 0 { err = errors.New("vault has not been created") return jsonStatusError(err) } // Validate the Name and Password as valid and admin if err = validateUser(s.Name, s.Password, true); err != nil { return jsonStatusError(err) } err = crypt.Flush() if err != nil { return jsonStatusError(err) } return jsonStatusOk() } // Delegate processes a delegation request. func Delegate(jsonIn []byte) ([]byte, error) { var s DelegateRequest var err error var tags = map[string]string{"function": "core.Delegate"} defer func() { if err != nil { tags["delegation.name"] = s.Name tags["delegation.uses"] = fmt.Sprintf("%d", s.Uses) tags["delegation.time"] = s.Time tags["delegation.users"] = strings.Join(s.Users, ", ") tags["delegation.labels"] = strings.Join(s.Labels, ", ") log.Printf("core.delegate failed: user=%s %v", s.Name, err) } else { log.Printf("core.delegate success: user=%s uses=%d time=%s users=%v labels=%v", s.Name, s.Uses, s.Time, s.Users, s.Labels) } }() if err = json.Unmarshal(jsonIn, &s); err != nil { return jsonStatusError(err) } if records.NumRecords() == 0 { err = errors.New("Vault is not created yet") return jsonStatusError(err) } // Validate the Name and Password as valid if err = validateName(s.Name, s.Password); err != nil { return jsonStatusError(err) } // Make sure the user we are delegating to exists var invalidUsers []string for _, user := range s.Users { if _, ok := records.GetRecord(user); !ok { invalidUsers = append(invalidUsers, user) } } if len(invalidUsers) != 0 { err = fmt.Errorf("User(s) not present: %s", strings.Join(invalidUsers, ", ")) return jsonStatusError(err) } // Find password record for user and verify that their password // matches. If not found then add a new entry for this user. pr, found := records.GetRecord(s.Name) if found { if err = pr.ValidatePassword(s.Password); err != nil { return jsonStatusError(err) } } else { if pr, err = records.AddNewRecord(s.Name, s.Password, false, passvault.DefaultRecordType); err != nil { return jsonStatusError(err) } } // add signed-in record to active set if err = crypt.Delegate(pr, s.Name, s.Password, s.Users, s.Labels, s.Uses, s.Slot, s.Time); err != nil { return jsonStatusError(err) } // Make sure we capture the number who have already delegated. for _, delegatedUser := range s.Users { if orderKey, found := orders.FindOrder(delegatedUser, s.Labels); found { order := orders.Orders[orderKey] // Don't re-add names to the list of people who have delegated. Instead // just skip them but make sure we count their delegation if len(order.OwnersDelegated) == 0 { order.OwnersDelegated = append(order.OwnersDelegated, s.Name) } else { for _, ownerName := range order.OwnersDelegated { if ownerName == s.Name { continue } order.OwnersDelegated = append(order.OwnersDelegated, s.Name) order.Delegated++ } } orders.Orders[orderKey] = order // Notify the hipchat room that there was a new delegator orders.NotifyDelegation(s.Name, delegatedUser, orderKey, s.Time, s.Labels) } } return jsonStatusOk() } // CreateUser processes a create-user request. func CreateUser(jsonIn []byte) ([]byte, error) { var s CreateUserRequest var err error defer func() { if err != nil { log.Printf("core.create-user failed: user=%s %v", s.Name, err) } else { log.Printf("core.create-user success: user=%s", s.Name) } }() if err = json.Unmarshal(jsonIn, &s); err != nil { return jsonStatusError(err) } // If no UserType if provided use the default one if s.UserType == "" { s.UserType = passvault.DefaultRecordType } if records.NumRecords() == 0 { err = errors.New("Vault is not created yet") return jsonStatusError(err) } // Validate the Name and Password as valid if err = validateName(s.Name, s.Password); err != nil { return jsonStatusError(err) } _, found := records.GetRecord(s.Name) if found { err = errors.New("User with that name already exists") return jsonStatusError(err) } if _, err := records.AddNewRecord(s.Name, s.Password, false, s.UserType); err != nil { return jsonStatusError(err) } if err = records.ChangePassword(s.Name, s.Password, "", s.HipchatName); err != nil { return jsonStatusError(err) } return jsonStatusOk() } // Password processes a password change request. func Password(jsonIn []byte) ([]byte, error) { var err error var s PasswordRequest defer func() { if err != nil { log.Printf("core.password failed: user=%s %v", s.Name, err) } else { log.Printf("core.password success: user=%s", s.Name) } }() if err = json.Unmarshal(jsonIn, &s); err != nil { return jsonStatusError(err) } if records.NumRecords() == 0 { err = errors.New("Vault is not created yet") return jsonStatusError(err) } // add signed-in record to active set err = records.ChangePassword(s.Name, s.Password, s.NewPassword, s.HipchatName) if err != nil { return jsonStatusError(err) } return jsonStatusOk() } // Encrypt processes an encrypt request. func Encrypt(jsonIn []byte) ([]byte, error) { var s EncryptRequest var err error var tags = map[string]string{"function": "core.Encrypt"} defer func() { if err != nil { tags["encrypt.user"] = s.Name tags["encrypt.size"] = fmt.Sprintf("%d", len(s.Data)) report.Check(err, tags) log.Printf("core.encrypt failed: user=%s size=%d %v", s.Name, len(s.Data), err) } else { log.Printf("core.encrypt success: user=%s size=%d", s.Name, len(s.Data)) } }() err = json.Unmarshal(jsonIn, &s) if err != nil { return jsonStatusError(err) } if err = validateUser(s.Name, s.Password, false); err != nil { return jsonStatusError(err) } access := cryptor.AccessStructure{ Minimum: s.Minimum, Names: s.Owners, LeftNames: s.LeftOwners, RightNames: s.RightOwners, Predicate: s.Predicate, } resp, err := crypt.Encrypt(s.Data, s.Labels, s.Usages, access) if err != nil { return jsonStatusError(err) } return jsonResponse(resp) } // ReEncrypt processes an Re-encrypt request. func ReEncrypt(jsonIn []byte) ([]byte, error) { var s ReEncryptRequest var err error defer func() { if err != nil { log.Printf("core.re-encrypt failed: user=%s size=%d %v", s.Name, len(s.Data), err) } else { log.Printf("core.re-encrypt success: user=%s size=%d", s.Name, len(s.Data)) } }() err = json.Unmarshal(jsonIn, &s) if err != nil { return jsonStatusError(err) } if err = validateUser(s.Name, s.Password, false); err != nil { return jsonStatusError(err) } data, _, _, usages, secure, err := crypt.Decrypt(s.Data, s.Name) if err != nil { return jsonStatusError(err) } if !secure { return jsonStatusError(errors.New("decryption's secure bit is false")) } access := cryptor.AccessStructure{ Minimum: s.Minimum, Names: s.Owners, LeftNames: s.LeftOwners, RightNames: s.RightOwners, Predicate: s.Predicate, } resp, err := crypt.Encrypt(data, s.Labels, usages, access) if err != nil { return jsonStatusError(err) } return jsonResponse(resp) } // Decrypt processes a decrypt request. func Decrypt(jsonIn []byte) ([]byte, error) { var s DecryptRequest var err error var tags = map[string]string{"function": "core.Decrypt"} defer func() { if err != nil { tags["decrypt.user"] = s.Name report.Check(err, tags) log.Printf("core.decrypt failed: user=%s %v", s.Name, err) } else { log.Printf("core.decrypt success: user=%s", s.Name) } }() err = json.Unmarshal(jsonIn, &s) if err != nil { return jsonStatusError(err) } err = validateUser(s.Name, s.Password, false) if err != nil { return jsonStatusError(err) } data, allLabels, names, usages, secure, err := crypt.Decrypt(s.Data, s.Name) if err != nil { return jsonStatusError(err) } if len(usages) != 0 { // a file must be marked as usable for "decrypt" before we will decrypt // it for the user. If no usages are provided, we permit decryption foundDecrypt := false for _, usage := range usages { if usage == "decrypt" { foundDecrypt = true break } } if !foundDecrypt { return jsonStatusError(errors.New("cannot decrypt this file")) } } resp := &DecryptWithDelegates{ Data: data, Secure: secure, Delegates: names, } tags["delegates"] = strings.Join(names, ", ") out, err := json.Marshal(resp) if err != nil { return jsonStatusError(err) } // Cleanup any orders that have been fulfilled and notify the room. if orderKey, found := orders.FindOrder(s.Name, allLabels); found { delete(orders.Orders, orderKey) orders.NotifyOrderFulfilled(s.Name, orderKey) } return jsonResponse(out) } // SSHSignWith signs a message with an SSH key func SSHSignWith(jsonIn []byte) ([]byte, error) { var s SSHSignWithRequest var err error var tags = map[string]string{"function": "core.SSHSignWith"} defer func() { if err != nil { tags["ssh-sign-with.user"] = s.Name report.Check(err, tags) log.Printf("core.ssh-sign-with failed: user=%s %v", s.Name, err) } else { log.Printf("core.ssh-sign-with success: user=%s", s.Name) } }() err = json.Unmarshal(jsonIn, &s) if err != nil { return jsonStatusError(err) } err = validateUser(s.Name, s.Password, false) if err != nil { return jsonStatusError(err) } data, allLabels, names, usages, secure, err := crypt.Decrypt(s.Data, s.Name) if err != nil { return jsonStatusError(err) } // a file must be marked as usable for "ssh-sign-with" before we will try to sign with it foundSign := false for _, usage := range usages { if usage == "ssh-sign-with" { foundSign = true break } } if !foundSign { return jsonStatusError(errors.New("cannot sign with this file")) } var signer ssh.Signer // TODO ParsePrivateKeyWithPassphrase signer, err = ssh.ParsePrivateKey(data) if err != nil { return jsonStatusError(err) } var signature *ssh.Signature signature, err = signer.Sign(rand.Reader, s.TBSData) resp := &SSHSignatureWithDelegates{ SignatureFormat: signature.Format, Signature: signature.Blob, Secure: secure, Delegates: names, } tags["delegates"] = strings.Join(names, ", ") out, err := json.Marshal(resp) if err != nil { return jsonStatusError(err) } // Cleanup any orders that have been fulfilled and notify the room. if orderKey, found := orders.FindOrder(s.Name, allLabels); found { delete(orders.Orders, orderKey) orders.NotifyOrderFulfilled(s.Name, orderKey) } return jsonResponse(out) } // Modify processes a modify request. func Modify(jsonIn []byte) ([]byte, error) { var s ModifyRequest var err error defer func() { if err != nil { log.Printf("core.modify failed: user=%s target=%s command=%s %v", s.Name, s.ToModify, s.Command, err) } else { log.Printf("core.modify success: user=%s target=%s command=%s", s.Name, s.ToModify, s.Command) } }() err = json.Unmarshal(jsonIn, &s) if err != nil { return jsonStatusError(err) } if err = validateUser(s.Name, s.Password, true); err != nil { return jsonStatusError(err) } if _, ok := records.GetRecord(s.ToModify); !ok { err = errors.New("core: record to modify missing") return jsonStatusError(err) } if s.Name == s.ToModify { err = errors.New("core: cannot modify own record") return jsonStatusError(err) } switch s.Command { case "delete": err = records.DeleteRecord(s.ToModify) case "revoke": err = records.RevokeRecord(s.ToModify) case "admin": err = records.MakeAdmin(s.ToModify) default: err = fmt.Errorf("core: unknown command '%s' passed to modify", s.Command) return jsonStatusError(err) } if err != nil { return jsonStatusError(err) } return jsonStatusOk() } // Owners processes a owners request. func Owners(jsonIn []byte) ([]byte, error) { var s OwnersRequest var err error defer func() { if err != nil { log.Printf("core.owners failed: size=%d %v", len(s.Data), err) } else { log.Printf("core.owners success: size=%d", len(s.Data)) } }() err = json.Unmarshal(jsonIn, &s) if err != nil { return jsonStatusError(err) } names, labels, predicate, err := crypt.GetOwners(s.Data) if err != nil { return jsonStatusError(err) } return json.Marshal(OwnersData{ Status: "ok", Owners: names, Predicate: predicate, Labels: labels, }) } // Export returns a backed up vault. func Export(jsonIn []byte) ([]byte, error) { var s ExportRequest var err error defer func() { if err != nil { log.Printf("core.export failed: user=%s %v", s.Name, err) } else { log.Printf("core.export success: user=%s", s.Name) } }() err = json.Unmarshal(jsonIn, &s) if err != nil { return jsonStatusError(err) } err = validateUser(s.Name, s.Password, true) if err != nil { return jsonStatusError(err) } out, err := json.Marshal(records) if err != nil { return jsonStatusError(err) } return jsonResponse(out) } // Order will request delegations from other users. func Order(jsonIn []byte) (out []byte, err error) { var o OrderRequest defer func() { if err != nil { log.Printf("core.order failed: user=%s %v", o.Name, err) } else { log.Printf("core.order success: user=%s", o.Name) } }() if err = json.Unmarshal(jsonIn, &o); err != nil { return jsonStatusError(err) } if err := validateUser(o.Name, o.Password, false); err != nil { return jsonStatusError(err) } // Get the owners of the ciphertext. owners, _, _, err := crypt.GetOwners(o.EncryptedData) if err != nil { return jsonStatusError(err) } if o.Duration == "" { err = errors.New("Duration required when placing an order.") return jsonStatusError(err) } if o.Uses == 0 { err = errors.New("Number of required uses necessary when placing an order.") return jsonStatusError(err) } err = crypt.Refresh() if err != nil { return jsonStatusError(err) } orderNum := order.GenerateNum() if len(o.Users) == 0 { err = errors.New("Must specify at least one user per order.") return jsonStatusError(err) } adminsDelegated, numDelegated := crypt.DelegateStatus(o.Users[0], o.Labels, owners) duration, err := time.ParseDuration(o.Duration) if err != nil { return jsonStatusError(err) } currentTime := time.Now() ord := order.CreateOrder(o.Name, orderNum, currentTime, duration, adminsDelegated, owners, o.Users, o.Labels, numDelegated) orders.Orders[orderNum] = ord out, err = json.Marshal(ord) // Get a map to any alternative name we want to notify altOwners := records.GetAltNamesFromName(orders.AlternateName, owners) // Let everyone on hipchat know there is a new order. orders.NotifyNewOrder(o.Duration, orderNum, o.Users, o.Labels, o.Uses, altOwners) if err != nil { return jsonStatusError(err) } return jsonResponse(out) } // OrdersOutstanding will return a list of currently outstanding orders. func OrdersOutstanding(jsonIn []byte) (out []byte, err error) { var o OrderOutstandingRequest defer func() { if err != nil { log.Printf("core.ordersout failed: user=%s %v", o.Name, err) } else { log.Printf("core.ordersout success: user=%s", o.Name) } }() if err = json.Unmarshal(jsonIn, &o); err != nil { return jsonStatusError(err) } if err := validateUser(o.Name, o.Password, false); err != nil { return jsonStatusError(err) } out, err = json.Marshal(orders.Orders) if err != nil { return jsonStatusError(err) } return jsonResponse(out) } // OrderInfo will return a list of currently outstanding order numbers. func OrderInfo(jsonIn []byte) (out []byte, err error) { var o OrderInfoRequest defer func() { if err != nil { log.Printf("core.order failed: user=%s %v", o.Name, err) } else { log.Printf("core.order success: user=%s", o.Name) } }() if err = json.Unmarshal(jsonIn, &o); err != nil { return jsonStatusError(err) } if err := validateUser(o.Name, o.Password, false); err != nil { return jsonStatusError(err) } if ord, ok := orders.Orders[o.OrderNum]; ok { if out, err = json.Marshal(ord); err != nil { return jsonStatusError(err) } else if len(out) == 0 { return jsonStatusError(errors.New("No order with that number")) } return jsonResponse(out) } return jsonStatusError(errors.New("No order with that number")) } // OrderCancel will cancel an order given an order num func OrderCancel(jsonIn []byte) (out []byte, err error) { var o OrderCancelRequest defer func() { if err != nil { log.Printf("core.order failed: user=%s %v", o.Name, err) } else { log.Printf("core.order success: user=%s", o.Name) } }() if err = json.Unmarshal(jsonIn, &o); err != nil { return jsonStatusError(err) } if err := validateUser(o.Name, o.Password, false); err != nil { return jsonStatusError(err) } if ord, ok := orders.Orders[o.OrderNum]; ok { if o.Name == ord.Creator { delete(orders.Orders, o.OrderNum) out = []byte("Successfully removed order") return jsonResponse(out) } } err = errors.New("Invalid Order Number") return jsonStatusError(err) } // Status returns the current delegation persistence state. In the // future, this may return more data. func Status(jsonIn []byte) (out []byte, err error) { var req StatusRequest defer func() { if err != nil { log.Printf("core.status failed: user=%s %v", req.Name, err) } else { log.Printf("core.status success: user=%s", req.Name) } }() if err = json.Unmarshal(jsonIn, &req); err != nil { return jsonStatusError(err) } if err := validateUser(req.Name, req.Password, false); err != nil { return jsonStatusError(err) } st := crypt.Status() resp := &StatusData{Status: st.State} if out, err = json.Marshal(resp); err != nil { return jsonStatusError(err) } return jsonResponse(out) } // Restore attempts a restoration of the persistence store. func Restore(jsonIn []byte) (out []byte, err error) { var req DelegateRequest var tags = map[string]string{"function": "core.Restore"} defer func() { if err != nil { tags["restore.user"] = req.Name report.Check(err, tags) log.Printf("core.restore failed: user=%s %v", req.Name, err) } else { log.Printf("core.restore success: user=%s", req.Name) } }() if err = json.Unmarshal(jsonIn, &req); err != nil { return jsonStatusError(err) } if err := validateUser(req.Name, req.Password, false); err != nil { return jsonStatusError(err) } err = crypt.Restore(req.Name, req.Password, 1, "", req.Time) if err != nil && err != cryptor.ErrRestoreDelegations { return jsonStatusError(err) } st := crypt.Status() resp := &StatusData{Status: st.State} if out, err = json.Marshal(resp); err != nil { return jsonStatusError(err) } return jsonResponse(out) } // ResetPersisted clears the persisted user data from the server. This // request requires an admin. func ResetPersisted(jsonIn []byte) (out []byte, err error) { var req PurgeRequest var tags = map[string]string{"function": "core.ResetPersisted"} defer func() { if err != nil { tags["reset-persisted.user"] = req.Name report.Check(err, tags) log.Printf("core.resetpersisted failed: user=%s %v", req.Name, err) } else { log.Printf("core.resetpersisted success: user=%s", req.Name) } }() if err = json.Unmarshal(jsonIn, &req); err != nil { return jsonStatusError(err) } if err := validateUser(req.Name, req.Password, true); err != nil { return jsonStatusError(err) } st, err := crypt.ResetPersisted() if err != nil { return jsonStatusError(err) } resp := &StatusData{Status: st.State} if out, err = json.Marshal(resp); err != nil { return jsonStatusError(err) } return jsonResponse(out) } ================================================ FILE: vendor/github.com/cloudflare/redoctober/cryptor/cryptor.go ================================================ // Package cryptor encrypts and decrypts files using the Red October // vault and key cache. // // Copyright (c) 2013 CloudFlare, Inc. package cryptor import ( "crypto/aes" "crypto/cipher" "crypto/hmac" "crypto/sha1" "encoding/json" "errors" "log" "sort" "strconv" "strings" "github.com/cloudflare/redoctober/config" "github.com/cloudflare/redoctober/keycache" "github.com/cloudflare/redoctober/msp" "github.com/cloudflare/redoctober/padding" "github.com/cloudflare/redoctober/passvault" "github.com/cloudflare/redoctober/persist" "github.com/cloudflare/redoctober/symcrypt" ) const ( DEFAULT_VERSION = 1 ) type Cryptor struct { records *passvault.Records cache *keycache.Cache persist persist.Store } func New(records *passvault.Records, cache *keycache.Cache, config *config.Config) (*Cryptor, error) { if cache == nil { c := keycache.NewCache() cache = &c } store, err := persist.New(config.Delegations) if err != nil { return nil, err } c := &Cryptor{ records: records, cache: cache, persist: store, } return c, nil } // AccessStructure represents different possible access structures for // encrypted data. If len(Names) > 0, then at least 2 of the users in the list // must be delegated to decrypt. If len(LeftNames) > 0 & len(RightNames) > 0, // then at least one from each list must be delegated (if the same user is in // both, then he can decrypt it alone). If a predicate is present, it must be // satisfied to decrypt. type AccessStructure struct { Minimum int Names []string LeftNames []string RightNames []string Predicate string } // Implements msp.UserDatabase type UserDatabase struct { names *[]string records *passvault.Records cache *keycache.Cache user string labels []string keySet map[string]SingleWrappedKey shareSet map[string][][]byte } func (u UserDatabase) ValidUser(name string) bool { _, ok := u.records.GetRecord(name) return ok } func (u UserDatabase) CanGetShare(name string) bool { _, _, ok1 := u.cache.MatchUser(name, u.user, u.labels) _, ok2 := u.shareSet[name] _, ok3 := u.keySet[name] return ok1 && ok2 && ok3 } func (u UserDatabase) GetShare(name string) ([][]byte, error) { *u.names = append(*u.names, name) return u.cache.DecryptShares( u.shareSet[name], name, u.user, u.labels, u.keySet[name].Key, ) } // MultiWrappedKey is a structure containing a 16-byte key encrypted // once for each of the keys corresponding to the names of the users // in Name in order. type MultiWrappedKey struct { Name []string Key []byte } // SingleWrappedKey is a structure containing a 16-byte key encrypted // by an RSA or EC key. type SingleWrappedKey struct { Key []byte aesKey []byte } // EncryptedData is the format for encrypted data containing all the // keys necessary to decrypt it when delegated. type EncryptedData struct { Version int VaultId int `json:",omitempty"` Labels []string `json:",omitempty"` // Usages list the endpoints which may use this data // If empty, only decryption in permitted Usages []string `json:",omitempty"` Predicate string `json:",omitempty"` KeySet []MultiWrappedKey `json:",omitempty"` KeySetRSA map[string]SingleWrappedKey `json:",omitempty"` ShareSet map[string][][]byte `json:",omitempty"` IV []byte `json:",omitempty"` Data []byte Signature []byte } type pair struct { name string key []byte } type mwkSlice []MultiWrappedKey type swkSlice []pair func (s mwkSlice) Len() int { return len(s) } func (s mwkSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s mwkSlice) Less(i, j int) bool { // Alphabetic order var shorter = i if len(s[i].Name) > len(s[j].Name) { shorter = j } for index := range s[shorter].Name { if s[i].Name[index] != s[j].Name[index] { return s[i].Name[index] < s[j].Name[index] } } return false } func (s swkSlice) Len() int { return len(s) } func (s swkSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s swkSlice) Less(i, j int) bool { return s[i].name < s[j].name } // computeHmac computes the signature of the encrypted data structure // the signature takes into account every element of the EncryptedData // structure, with all keys sorted alphabetically by name func (encrypted *EncryptedData) computeHmac(key []byte) []byte { mac := hmac.New(sha1.New, key) // sort the multi-wrapped keys mwks := mwkSlice(encrypted.KeySet) sort.Sort(mwks) // sort the singly-wrapped keys var swks swkSlice for name, val := range encrypted.KeySetRSA { swks = append(swks, pair{name, val.Key}) } sort.Sort(&swks) // sort the labels and usages sort.Strings(encrypted.Labels) sort.Strings(encrypted.Usages) // start hashing mac.Write([]byte(strconv.Itoa(encrypted.Version))) mac.Write([]byte(strconv.Itoa(encrypted.VaultId))) // hash the multi-wrapped keys for _, mwk := range encrypted.KeySet { for _, name := range mwk.Name { mac.Write([]byte(name)) } mac.Write(mwk.Key) } // hash the single-wrapped keys for index := range swks { mac.Write([]byte(swks[index].name)) mac.Write(swks[index].key) } // hash the IV and data mac.Write(encrypted.IV) mac.Write(encrypted.Data) // hash the labels for _, label := range encrypted.Labels { mac.Write([]byte(label)) } // hash the usages for _, usage := range encrypted.Usages { mac.Write([]byte(usage)) } return mac.Sum(nil) } func (encrypted *EncryptedData) lock(key []byte) (err error) { payload, err := json.Marshal(encrypted) if err != nil { return } mac := hmac.New(sha1.New, key) mac.Write(payload) sig := mac.Sum(nil) *encrypted = EncryptedData{ Version: -1, Data: payload, Signature: sig, } return } func (encrypted *EncryptedData) unlock(key []byte) (err error) { if encrypted.Version != -1 { return } mac := hmac.New(sha1.New, key) mac.Write(encrypted.Data) sig := mac.Sum(nil) if !hmac.Equal(encrypted.Signature, sig) { err = errors.New("Signature mismatch") return } return json.Unmarshal(encrypted.Data, encrypted) } // wrapKey encrypts the clear key according to an access structure. func (encrypted *EncryptedData) wrapKey(records *passvault.Records, clearKey []byte, access AccessStructure) (err error) { generateRandomKey := func(name string) (singleWrappedKey SingleWrappedKey, err error) { rec, ok := records.GetRecord(name) if !ok { err = errors.New("Missing user on disk") return } if singleWrappedKey.aesKey, err = symcrypt.MakeRandom(16); err != nil { return } if singleWrappedKey.Key, err = rec.EncryptKey(singleWrappedKey.aesKey); err != nil { return } return } encryptKey := func(keyNames []string, clearKey []byte) (keyBytes []byte, err error) { keyBytes = make([]byte, 16) copy(keyBytes, clearKey) for _, keyName := range keyNames { var keyCrypt cipher.Block keyCrypt, err = aes.NewCipher(encrypted.KeySetRSA[keyName].aesKey) if err != nil { return } keyCrypt.Encrypt(keyBytes, keyBytes) } return } if len(access.Names) > 0 && access.Minimum > 0 { // Generate a random AES key for each user and RSA/ECIES encrypt it encrypted.KeySetRSA = make(map[string]SingleWrappedKey) for _, name := range access.Names { encrypted.KeySetRSA[name], err = generateRandomKey(name) if err != nil { return err } if access.Minimum == 1 { keyBytes, err := encryptKey([]string{access.Names[0]}, clearKey) if err != nil { return err } encrypted.KeySet = append(encrypted.KeySet, MultiWrappedKey{ Name: []string{access.Names[0]}, Key: keyBytes, }) } } if access.Minimum == 2 { for i := 0; i < len(access.Names); i++ { for j := i + 1; j < len(access.Names); j++ { keyBytes, err := encryptKey([]string{access.Names[j], access.Names[i]}, clearKey) if err != nil { return err } out := MultiWrappedKey{ Name: []string{access.Names[i], access.Names[j]}, Key: keyBytes, } encrypted.KeySet = append(encrypted.KeySet, out) } } } else if access.Minimum > 2 { err = errors.New("Encryption to a list of owners with minimum > 2 is not implemented") return err } } else if len(access.LeftNames) > 0 && len(access.RightNames) > 0 { // Generate a random AES key for each user and RSA/ECIES encrypt it encrypted.KeySetRSA = make(map[string]SingleWrappedKey) for _, name := range access.LeftNames { encrypted.KeySetRSA[name], err = generateRandomKey(name) if err != nil { return err } } for _, name := range access.RightNames { encrypted.KeySetRSA[name], err = generateRandomKey(name) if err != nil { return err } } // encrypt file key with every combination of one left key and one right key encrypted.KeySet = make([]MultiWrappedKey, 0) for _, leftName := range access.LeftNames { for _, rightName := range access.RightNames { if leftName == rightName { continue } keyBytes, err := encryptKey([]string{rightName, leftName}, clearKey) if err != nil { return err } out := MultiWrappedKey{ Name: []string{leftName, rightName}, Key: keyBytes, } encrypted.KeySet = append(encrypted.KeySet, out) } } } else if len(access.Predicate) > 0 { encrypted.KeySetRSA = make(map[string]SingleWrappedKey) sss, err := msp.StringToMSP(access.Predicate) if err != nil { return err } db := UserDatabase{records: records} shareSet, err := sss.DistributeShares(clearKey, &db) if err != nil { return err } for name := range shareSet { encrypted.KeySetRSA[name], err = generateRandomKey(name) if err != nil { return err } crypt, err := aes.NewCipher(encrypted.KeySetRSA[name].aesKey) if err != nil { return err } for i := range shareSet[name] { tmp := make([]byte, 16) crypt.Encrypt(tmp, shareSet[name][i]) shareSet[name][i] = tmp } } encrypted.ShareSet = shareSet encrypted.Predicate = access.Predicate } else { return errors.New("Invalid access structure.") } return nil } // unwrapKey decrypts first key in keys whose encryption keys are in keycache func (encrypted *EncryptedData) unwrapKey(cache *keycache.Cache, user string) (unwrappedKey []byte, names []string, err error) { var ( decryptErr error fullMatch bool = false nameSet = map[string]bool{} ) if len(encrypted.Predicate) == 0 { for _, mwKey := range encrypted.KeySet { // validate the size of the keys if len(mwKey.Key) != 16 { err = errors.New("Invalid Input") } if err != nil { return nil, nil, err } // loop through users to see if they are all delegated fullMatch = true for _, mwName := range mwKey.Name { if valid := cache.Valid(mwName, user, encrypted.Labels); !valid { fullMatch = false break } nameSet[mwName] = true } // if the keys are delegated, decrypt the mwKey with them if fullMatch == true { tmpKeyValue := mwKey.Key for _, mwName := range mwKey.Name { pubEncrypted := encrypted.KeySetRSA[mwName] if tmpKeyValue, decryptErr = cache.DecryptKey(tmpKeyValue, mwName, user, encrypted.Labels, pubEncrypted.Key); decryptErr != nil { break } } unwrappedKey = tmpKeyValue break } } if !fullMatch { err = ErrNotEnoughDelegations return } if decryptErr != nil { err = errors.New("Failed to decrypt with all keys in keyset") return } names = make([]string, 0, len(nameSet)) for name := range nameSet { names = append(names, name) } return } var sss msp.MSP sss, err = msp.StringToMSP(encrypted.Predicate) if err != nil { return nil, nil, err } db := UserDatabase{ names: &names, cache: cache, user: user, labels: encrypted.Labels, keySet: encrypted.KeySetRSA, shareSet: encrypted.ShareSet, } unwrappedKey, err = sss.RecoverSecret(&db) return } // Encrypt encrypts data with the keys associated with names. This // requires a minimum of min keys to decrypt. NOTE: as currently // implemented, the maximum value for min is 2. func (c *Cryptor) Encrypt(in []byte, labels []string, usages []string, access AccessStructure) (resp []byte, err error) { var encrypted EncryptedData encrypted.Version = DEFAULT_VERSION if encrypted.VaultId, err = c.records.GetVaultID(); err != nil { return } // Generate random IV and encryption key encrypted.IV, err = symcrypt.MakeRandom(16) if err != nil { return } clearKey, err := symcrypt.MakeRandom(16) if err != nil { return } err = encrypted.wrapKey(c.records, clearKey, access) if err != nil { return } // encrypt file with clear key aesCrypt, err := aes.NewCipher(clearKey) if err != nil { return } clearFile := padding.AddPadding(in) encryptedFile := make([]byte, len(clearFile)) aesCBC := cipher.NewCBCEncrypter(aesCrypt, encrypted.IV) aesCBC.CryptBlocks(encryptedFile, clearFile) encrypted.Data = encryptedFile encrypted.Labels = labels encrypted.Usages = usages hmacKey, err := c.records.GetHMACKey() if err != nil { return } encrypted.Signature = encrypted.computeHmac(hmacKey) encrypted.lock(hmacKey) return json.Marshal(encrypted) } // Decrypt decrypts a file using the keys in the key cache. func (c *Cryptor) Decrypt(in []byte, user string) (resp []byte, labels, names []string, usages []string, secure bool, err error) { return c.decrypt(c.cache, in, user) } func (c *Cryptor) decrypt(cache *keycache.Cache, in []byte, user string) (resp []byte, labels, names []string, usages []string, secure bool, err error) { // unwrap encrypted file var encrypted EncryptedData if err = json.Unmarshal(in, &encrypted); err != nil { return } if encrypted.Version != DEFAULT_VERSION && encrypted.Version != -1 { return nil, nil, nil, nil, secure, errors.New("Unknown version") } secure = encrypted.Version == -1 hmacKey, err := c.records.GetHMACKey() if err != nil { return } if err = encrypted.unlock(hmacKey); err != nil { return } // make sure file was encrypted with the active vault vaultId, err := c.records.GetVaultID() if err != nil { return } if encrypted.VaultId != vaultId { return nil, nil, nil, nil, secure, errors.New("Wrong vault") } // compute HMAC expectedMAC := encrypted.computeHmac(hmacKey) if !hmac.Equal(encrypted.Signature, expectedMAC) { err = errors.New("Signature mismatch") return } // decrypt file key with delegate keys var unwrappedKey = make([]byte, 16) unwrappedKey, names, err = encrypted.unwrapKey(cache, user) if err != nil { return } aesCrypt, err := aes.NewCipher(unwrappedKey) if err != nil { return } clearData := make([]byte, len(encrypted.Data)) aesCBC := cipher.NewCBCDecrypter(aesCrypt, encrypted.IV) // decrypt contents of file aesCBC.CryptBlocks(clearData, encrypted.Data) resp, err = padding.RemovePadding(clearData) labels = encrypted.Labels usages = encrypted.Usages return } // GetOwners returns the list of users that can delegate their passwords // to decrypt the given encrypted secret. func (c *Cryptor) GetOwners(in []byte) (names, labels []string, predicate string, err error) { // unwrap encrypted file var encrypted EncryptedData if err = json.Unmarshal(in, &encrypted); err != nil { return } if encrypted.Version != DEFAULT_VERSION && encrypted.Version != -1 { err = errors.New("Unknown version") return } hmacKey, err := c.records.GetHMACKey() if err != nil { return } if err = encrypted.unlock(hmacKey); err != nil { return } // make sure file was encrypted with the active vault vaultId, err := c.records.GetVaultID() if err != nil { return } if encrypted.VaultId != vaultId { err = errors.New("Wrong vault") return } // compute HMAC expectedMAC := encrypted.computeHmac(hmacKey) if !hmac.Equal(encrypted.Signature, expectedMAC) { err = errors.New("Signature mismatch") return } addedNames := make(map[string]bool) for _, mwKey := range encrypted.KeySet { // names from the combinatorial method for _, mwName := range mwKey.Name { if !addedNames[mwName] { names = append(names, mwName) addedNames[mwName] = true } } } for name := range encrypted.ShareSet { // names from the secret splitting method if !addedNames[name] { names = append(names, name) addedNames[name] = true } } predicate = encrypted.Predicate labels = encrypted.Labels return } // LiveSummary returns a list of the users currently delegated. func (c *Cryptor) LiveSummary() map[string]keycache.ActiveUser { return c.cache.GetSummary() } // Refresh purges all expired or fully-used delegations in the // crypto's key cache. It returns an error if the delegations // should have been stored, but couldn't be. func (c *Cryptor) Refresh() error { n := c.cache.Refresh() if n != 0 { return c.store() } return nil } // Flush removes all delegations. func (c *Cryptor) Flush() error { if c.cache.Flush() { return c.store() } return nil } // Delegate attempts to decrypt a key for the specified user and add // the key to the key cache. func (c *Cryptor) Delegate(record passvault.PasswordRecord, name, password string, users, labels []string, uses int, slot, durationString string) (err error) { err = c.cache.AddKeyFromRecord(record, name, password, users, labels, uses, slot, durationString) if err != nil { return err } return c.store() } // DelegateStatus will return a list of admins who have delegated to a particular user, for a particular label. // This is useful information to have when determining the status of an order and conveying order progress. func (c *Cryptor) DelegateStatus(name string, labels, admins []string) (adminsDelegated []string, hasDelegated int) { return c.cache.DelegateStatus(name, labels, admins) } // store serialises the key cache, encrypts it, and writes it to disk. func (c *Cryptor) store() error { // If the store isn't currently active, we shouldn't attempt // to persist the store. st := c.persist.Status() if st.State != persist.Active { return nil } cache, err := json.Marshal(c.cache.GetSummary()) if err != nil { return err } access := AccessStructure{ Names: c.persist.Users(), Predicate: c.persist.Policy(), } cache, err = c.Encrypt(cache, persist.Labels, persist.Usages, access) if err != nil { return err } return c.persist.Store(cache) } // ErrRestoreDelegations is a sentinal value returned when more // delegations are needed for the restore to continue. var ErrRestoreDelegations = errors.New("cryptor: need more delegations") // ErrNotEnoughDelegations is a error returned by Decrypt. var ErrNotEnoughDelegations = errors.New("need more delegated keys") // Restore delegates the named user to the persistence key cache. If // enough delegations are present to restore the cache, the current // Red October key cache is replaced with the persisted one. func (c *Cryptor) Restore(name, password string, uses int, slot, durationString string) error { // If the persistence store is already active, don't proceed. if st := c.persist.Status(); st != nil && st.State == persist.Active { return nil } record, ok := c.records.GetRecord(name) if !ok { return errors.New("Missing user on disk") } err := c.persist.Delegate(record, name, password, c.persist.Users(), persist.Labels, uses, slot, durationString) if err != nil { return err } // A failure to decrypt isn't a restore error, it (most often) // just means there aren't enough delegations yet; the // sentinal value ErrRestoreDelegations is returned to // indicate this. However, the error cache, _, _, names, _, err := c.decrypt(c.persist.Cache(), c.persist.Blob(), name) if err != nil { if err == msp.ErrNotEnoughShares { return ErrRestoreDelegations } return err } log.Printf("cryptor.restore success: names=%s", strings.Join(names, ",")) var uk map[string]keycache.ActiveUser err = json.Unmarshal(cache, &uk) if err != nil { return err } rcache := keycache.NewFrom(uk) err = rcache.Restore() if err != nil { return err } c.cache = rcache c.persist.Persist() c.persist.Cache().Flush() return nil } // Status returns the status of the underlying persistence store. func (c *Cryptor) Status() *persist.Status { return c.persist.Status() } // ResetPersisted clears any persisted delegations and returns the // vault to an active delegation state if configured. func (c *Cryptor) ResetPersisted() (*persist.Status, error) { err := c.persist.Purge() return c.persist.Status(), err } ================================================ FILE: vendor/github.com/cloudflare/redoctober/ecdh/ecdh.go ================================================ // Package ecdh encrypts and decrypts data using elliptic curve keys. Data // is encrypted with AES-128-CBC with HMAC-SHA1 message tags using // ECDHE to generate a shared key. The P256 curve is chosen in // keeping with the use of AES-128 for encryption. package ecdh import ( "crypto/aes" "crypto/ecdsa" "crypto/elliptic" "crypto/hmac" "crypto/rand" "crypto/sha1" "crypto/sha256" "errors" "github.com/cloudflare/redoctober/padding" "github.com/cloudflare/redoctober/symcrypt" ) var Curve = elliptic.P256 // Encrypt secures and authenticates its input using the public key // using ECDHE with AES-128-CBC-HMAC-SHA1. func Encrypt(pub *ecdsa.PublicKey, in []byte) (out []byte, err error) { ephemeral, err := ecdsa.GenerateKey(Curve(), rand.Reader) if err != nil { return } x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, ephemeral.D.Bytes()) if x == nil { return nil, errors.New("Failed to generate encryption key") } shared := sha256.Sum256(x.Bytes()) iv, err := symcrypt.MakeRandom(16) if err != nil { return } paddedIn := padding.AddPadding(in) ct, err := symcrypt.EncryptCBC(paddedIn, iv, shared[:16]) if err != nil { return } ephPub := elliptic.Marshal(pub.Curve, ephemeral.PublicKey.X, ephemeral.PublicKey.Y) out = make([]byte, 1+len(ephPub)+16) out[0] = byte(len(ephPub)) copy(out[1:], ephPub) copy(out[1+len(ephPub):], iv) out = append(out, ct...) h := hmac.New(sha1.New, shared[16:]) h.Write(iv) h.Write(ct) out = h.Sum(out) return } // Decrypt authenticates and recovers the original message from // its input using the private key and the ephemeral key included in // the message. func Decrypt(priv *ecdsa.PrivateKey, in []byte) (out []byte, err error) { ephLen := int(in[0]) ephPub := in[1 : 1+ephLen] ct := in[1+ephLen:] if len(ct) < (sha1.Size + aes.BlockSize) { return nil, errors.New("Invalid ciphertext") } x, y := elliptic.Unmarshal(Curve(), ephPub) ok := Curve().IsOnCurve(x, y) // Rejects the identity point too. if x == nil || !ok { return nil, errors.New("Invalid public key") } x, _ = priv.Curve.ScalarMult(x, y, priv.D.Bytes()) if x == nil { return nil, errors.New("Failed to generate encryption key") } shared := sha256.Sum256(x.Bytes()) tagStart := len(ct) - sha1.Size h := hmac.New(sha1.New, shared[16:]) h.Write(ct[:tagStart]) mac := h.Sum(nil) if !hmac.Equal(mac, ct[tagStart:]) { return nil, errors.New("Invalid MAC") } paddedOut, err := symcrypt.DecryptCBC(ct[aes.BlockSize:tagStart], ct[:aes.BlockSize], shared[:16]) if err != nil { return } out, err = padding.RemovePadding(paddedOut) return } ================================================ FILE: vendor/github.com/cloudflare/redoctober/hipchat/hipchat.go ================================================ package hipchat import ( "bytes" "encoding/json" "errors" "fmt" "io/ioutil" "log" "net/http" "net/url" "strconv" ) const ( RedBackground = "red" YellowBackground = "yellow" GreenBackground = "green" GrayBackground = "gray" RandomBackground = "random" PurpleBackground = "purple" ) type HipchatClient struct { RoomId int ApiKey string HcHost string RoHost string } func NewClient() *HipchatClient { return &HipchatClient{} } func (h *HipchatClient) Notify(msg, color string) error { if h.ApiKey == "" { return errors.New("ApiKey unset") } msgBody := map[string]interface{}{ "message": msg, "notify": "true", "color": color, } body, err := json.Marshal(msgBody) if err != nil { return err } roomId := url.QueryEscape(strconv.Itoa(h.RoomId)) hipchatUrl := fmt.Sprintf("https://%s/v2/room/%s/message?auth_token=%s", h.HcHost, roomId, h.ApiKey) req, err := http.NewRequest("POST", hipchatUrl, bytes.NewReader(body)) req.Header.Add("Content-Type", "application/json") Client := http.Client{} resp, err := Client.Do(req) if err != nil { log.Printf("Could not post to hipchat for the reason %s", err.Error()) return err } _, err = ioutil.ReadAll(resp.Body) if err != nil { log.Printf("Could not post to hipchat for the reason %s", err.Error()) return err } return nil } ================================================ FILE: vendor/github.com/cloudflare/redoctober/keycache/keycache.go ================================================ // Package keycache provides the ability to hold active keys in memory // for the Red October server. // // Copyright (c) 2013 CloudFlare, Inc. package keycache import ( "crypto/aes" "crypto/ecdsa" "crypto/rand" "crypto/rsa" "crypto/sha1" "crypto/x509" "errors" "fmt" "log" "strings" "sync" "time" "github.com/cloudflare/redoctober/ecdh" "github.com/cloudflare/redoctober/passvault" ) // DelegateIndex is used to index the map of currently delegated keys. // This is necessary to provide a way for a delegator to provide multiple // delegations. It is also used to avoid the complexity of string parsing // and enforcement of username and slot character requirements. type DelegateIndex struct { Name string Slot string } // Usage holds the permissions of a delegated permission type Usage struct { Uses int // Number of uses delegated Labels []string // File labels allowed to decrypt Users []string // Set of users allows to decrypt Expiry time.Time // Expiration of usage } // ActiveUser holds the information about an actively delegated key. type ActiveUser struct { Usage AltNames map[string]string Admin bool Type string Key []byte rsaKey rsa.PrivateKey eccKey *ecdsa.PrivateKey } // Cache represents the current list of delegated keys in memory type Cache struct { lock *sync.Mutex UserKeys map[DelegateIndex]ActiveUser } // matchesLabel returns true if this usage applies the user and label // an empty array of Users indicates that all users are valid func (usage Usage) matchesLabel(labels []string) bool { // if asset has no labels always match if len(labels) == 0 { return true } for _, validLabel := range usage.Labels { for _, label := range labels { if label == validLabel { return true } } } return false } // matches returns true if this usage applies the user and label // an empty array of Users indicates that all users are valid func (usage Usage) matches(user string, labels []string) bool { if !usage.matchesLabel(labels) { return false } // if usage lists no users, always match if len(usage.Users) == 0 { return true } for _, validUser := range usage.Users { if user == validUser { return true } } return false } // NewCache initalizes a new cache. func NewCache() Cache { return Cache{ UserKeys: make(map[DelegateIndex]ActiveUser), lock: new(sync.Mutex), } } // NewFrom takes the output of GetSummary and returns a new keycache. func NewFrom(summary map[string]ActiveUser) *Cache { cache := &Cache{ UserKeys: make(map[DelegateIndex]ActiveUser), lock: new(sync.Mutex), } for di, user := range summary { diSplit := strings.SplitN(di, "-", 2) index := DelegateIndex{ Name: diSplit[0], } if len(diSplit) == 2 { index.Slot = diSplit[1] } cache.UserKeys[index] = user } return cache } // setUser takes an ActiveUser and adds it to the cache. func (cache *Cache) setUser(in ActiveUser, name, slot string) { cache.lock.Lock() cache.UserKeys[DelegateIndex{Name: name, Slot: slot}] = in cache.lock.Unlock() } // Valid returns true if matching active user is present. func (cache *Cache) Valid(name, user string, labels []string) (present bool) { for d, key := range cache.UserKeys { if d.Name != name { continue } if key.Usage.matches(user, labels) { return true } } return false } // MatchUser returns the matching active user if present // and a boolean to indicate its presence. func (cache *Cache) MatchUser(name, user string, labels []string) (ActiveUser, string, bool) { var key ActiveUser for d, key := range cache.UserKeys { if d.Name != name { continue } if key.Usage.matches(user, labels) { return key, d.Slot, true } } return key, "", false } // useKey decrements the counter on an active key // for decryption or symmetric encryption func (cache *Cache) useKey(name, user, slot string, labels []string) { if val, slot, present := cache.MatchUser(name, user, labels); present { val.Usage.Uses-- if val.Usage.Uses <= 0 { delete(cache.UserKeys, DelegateIndex{name, slot}) } else { cache.setUser(val, name, slot) } } } // GetSummary returns the list of active user keys. func (cache *Cache) GetSummary() map[string]ActiveUser { summaryData := make(map[string]ActiveUser) for d, activeUser := range cache.UserKeys { summaryInfo := d.Name if d.Slot != "" { summaryInfo = fmt.Sprintf("%s-%s", d.Name, d.Slot) } summaryData[summaryInfo] = activeUser } return summaryData } // Flush removes all delegated keys. It returns true if the cache // wasn't empty (i.e. there were active users removed), and false if // the cache was empty. func (cache *Cache) Flush() bool { if len(cache.UserKeys) == 0 { return false } cache.lock.Lock() for d := range cache.UserKeys { delete(cache.UserKeys, d) } cache.lock.Unlock() return true } // Refresh purges all expired keys. It returns the number of // delegations that were removed. func (cache *Cache) Refresh() int { var removed int for d, active := range cache.UserKeys { if active.Usage.Expiry.Before(time.Now()) { log.Println("Record expired", d.Name, d.Slot, active.Usage.Users, active.Usage.Labels, active.Usage.Expiry) removed++ delete(cache.UserKeys, d) } } return removed } // AddKeyFromRecord decrypts a key for a given record and adds it to the cache. func (cache *Cache) AddKeyFromRecord(record passvault.PasswordRecord, name, password string, users, labels []string, uses int, slot, durationString string) (err error) { var current ActiveUser cache.Refresh() // compute exipiration duration, err := time.ParseDuration(durationString) if err != nil { return } current.Usage.Uses = uses current.Usage.Expiry = time.Now().Add(duration) current.Usage.Users = users current.Usage.Labels = labels // get decryption keys switch record.Type { case passvault.RSARecord: current.rsaKey, err = record.GetKeyRSA(password) if err != nil { return } current.Key = x509.MarshalPKCS1PrivateKey(¤t.rsaKey) case passvault.ECCRecord: current.eccKey, err = record.GetKeyECC(password) if err != nil { return } current.Key, err = x509.MarshalECPrivateKey(current.eccKey) default: err = errors.New("Unknown record type") } if err != nil { return } // set types current.Type = record.Type current.Admin = record.Admin // add current to map (overwriting previous for this name) cache.setUser(current, name, slot) return } // DecryptKey decrypts a 16 byte key using the key corresponding to the name parameter // For RSA and EC keys, the cached RSA/EC key is used to decrypt // the pubEncryptedKey which is then used to decrypt the input // buffer. func (cache *Cache) DecryptKey(in []byte, name, user string, labels []string, pubEncryptedKey []byte) (out []byte, err error) { cache.Refresh() decryptKey, slot, ok := cache.MatchUser(name, user, labels) if !ok { return nil, errors.New("Key not delegated") } var aesKey []byte // pick the aesKey to use for decryption switch decryptKey.Type { case passvault.RSARecord: // extract the aes key from the pubEncryptedKey aesKey, err = rsa.DecryptOAEP(sha1.New(), rand.Reader, &decryptKey.rsaKey, pubEncryptedKey, nil) if err != nil { return out, err } case passvault.ECCRecord: // extract the aes key from the pubEncryptedKey aesKey, err = ecdh.Decrypt(decryptKey.eccKey, pubEncryptedKey) if err != nil { return out, err } default: return nil, errors.New("unknown type") } // decrypt aesSession, err := aes.NewCipher(aesKey) if err != nil { return out, err } out = make([]byte, 16) aesSession.Decrypt(out, in) cache.useKey(name, user, slot, labels) return } // DecryptShares decrypts an array of 16 byte shares using the key corresponding // to the name parameter. func (cache *Cache) DecryptShares(in [][]byte, name, user string, labels []string, pubEncryptedKey []byte) (out [][]byte, err error) { cache.Refresh() decryptKey, slot, ok := cache.MatchUser(name, user, labels) if !ok { return nil, errors.New("Key not delegated") } var aesKey []byte // pick the aesKey to use for decryption switch decryptKey.Type { case passvault.RSARecord: // extract the aes key from the pubEncryptedKey aesKey, err = rsa.DecryptOAEP(sha1.New(), rand.Reader, &decryptKey.rsaKey, pubEncryptedKey, nil) if err != nil { return } case passvault.ECCRecord: // extract the aes key from the pubEncryptedKey aesKey, err = ecdh.Decrypt(decryptKey.eccKey, pubEncryptedKey) if err != nil { return } default: return nil, errors.New("unknown type") } // decrypt aesSession, err := aes.NewCipher(aesKey) if err != nil { return } for _, encShare := range in { tmp := make([]byte, 16) aesSession.Decrypt(tmp, encShare) out = append(out, tmp) } cache.useKey(name, user, slot, labels) return } // DelegateStatus will return a list of admins who have delegated to a particular user, for a particular label. // This is useful information to have when determining the status of an order and conveying order progress. func (cache *Cache) DelegateStatus(name string, labels, admins []string) (adminsDelegated []string, hasDelegated int) { // Iterate over the admins of the ciphertext to look for users // who have already delegated the label to the delegatee. for _, admin := range admins { for di, use := range cache.UserKeys { if di.Name != admin { continue } nameFound := false for _, user := range use.Users { if user == name { nameFound = true } } for _, ol := range use.Labels { for _, il := range labels { if ol == il { if nameFound { adminsDelegated = append(adminsDelegated, admin) hasDelegated++ } } } } } } return } // Restore unmarshals the private key stored in the delegator to the // appropriate private structure. func (cache *Cache) Restore() (err error) { for index, uk := range cache.UserKeys { if len(uk.Key) == 0 { return errors.New("keycache: no private key in active user") } rsaPriv, err := x509.ParsePKCS1PrivateKey(uk.Key) if err == nil { uk.rsaKey = *rsaPriv cache.UserKeys[index] = uk continue } ecPriv, err := x509.ParseECPrivateKey(uk.Key) if err == nil { uk.eccKey = ecPriv cache.UserKeys[index] = uk continue } return err } return nil } ================================================ FILE: vendor/github.com/cloudflare/redoctober/msp/README.md ================================================ Monotone Span Programs ====================== - [Introduction](#monotone-span-programs) - [Types of Predicates](#types-of-predicates) - [Documentation](#documentation) - [User Databases](#user-databases) - [Building Predicates](#building-predicates) - [Splitting & Reconstructing Secrets](#splitting--reconstructing-secrets) A *Monotone Span Program* (or *MSP*) is a cryptographic technique for splitting a secret into several *shares* that are then distributed to *parties* or *users*. (Have you heard of [Shamir's Secret Sharing](http://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing)? It's like that.) Unlike Shamir's Secret Sharing, MSPs allow *arbitrary monotone access structures*. An access structure is just a boolean predicate on a set of users that tells us whether or not that set is allowed to recover the secret. A monotone access structure is the same thing, but with the invariant that adding a user to a set will never turn the predicate's output from `true` to `false`--negations or boolean `nots` are disallowed. **Example:** `(Alice or Bob) and Carl` is good, but `(Alice or Bob) and !Carl` is not because excluding people is rude. MSPs are fundamental and powerful primitives. They're well-suited for distributed commitments (DC), verifiable secret sharing (VSS) and multi-party computation (MPC). #### Types of Predicates An MSP itself is a type of predicate and the reader is probably familiar with raw boolean predicates like in the example above, but another important type is a *formatted boolean predicate*. Formatted boolean predicates are isomorphic to all MSPs and therefore all monotone raw boolean predicates. They're built by nesting threshold gates. **Example:** Let `(2, Alice, Bob, Carl)` denote that at least 2 members of the set `{Alice, Bob, Carl}` must be present to recover the secret. Then, `(2, (1, Alice, Bob), Carl)` is the formatted version of `(Alice or Bob) and Carl`. It is possible to convert between different types of predicates (and its one of the fundamental operations of splitting secrets with an MSP), but circuit minimization is a non-trivial and computationally complex problem. The code can do a small amount of compression, but the onus is on the user to design efficiently computable predicates. #### To Do 1. Anonymous secret generation / secret homomorphisms 2. Non-interactive verifiable secret sharing / distributed commitments Documentation ------------- ### User Databases ```go type UserDatabase interface { ValidUser(string) bool // Is this the name of an existing user? CanGetShare(string) bool // Can I get this user's share? GetShare(string) ([][]byte, error) // Retrieves a user's shares. } ``` User databases are an abstraction over the primitive name -> share map that hopefully offer a bit more flexibility in implementing secret sharing schemes. `CanGetShare(name)` should be faster and less binding than `GetShare(name)`. `CanGetShare(name)` may be called a large number of times, but `GetShare(name)` will be called the absolute minimum number of times possible. Depending on the predicate used, a name may be associated to multiple shares of a secret, hence `[][]byte` as opposed to one share (`[]byte`). For test/play purposes there's a cheaty implementation of `UserDatabase` in `msp_test.go` that just wraps the `map[string][][]byte` returned by `DistributeShares(...)` ### Building Predicates ```go type Raw struct { ... } func StringToRaw(string) (Raw, error) { ... } func (r Raw) String() string { .. .} func (r Raw) Formatted() Formatted { ... } type Formatted struct { ... } func StringToFormatted(string) (Formatted, error) func (f Formatted) String() string ``` Building predicates is extremely easy--just write it out in a string and have one of the package methods parse it. Raw predicates take the `&` (logical AND) and `|` (logical OR) operators, but are otherwise the same as discussed above. Formatted predicates are exactly the same as above--just nested threshold gates. ```go r1, _ := msp.StringToRaw("(Alice | Bob) & Carl") r2, _ := msp.StringToRaw("Alice & Bob & Carl") fmt.Printf("%v\n", r1.Formatted()) // (2, (1, Alice, Bob), Carl) fmt.Printf("%v\n", r2.Formatted()) // (3, Alice, Bob, Carl) ``` ### Splitting & Reconstructing Secrets ```go type MSP Formatted func (m MSP) DistributeShares(sec []byte, db *UserDatabase) (map[string][][]byte, error) {} func (m MSP) RecoverSecret(db *UserDatabase) ([]byte, error) {} ``` To switch from predicate-mode to secret-sharing-mode, just cast your formatted predicate into an MSP something like this: ```go predicate := msp.StringToFormatted("(3, Alice, Bob, Carl)") sss := msp.MSP(predicate) ``` Calling `DistributeShares` on it returns a map from a party's name to their set of shares which should be given to that party and integrated into the `UserDatabase` somehow. When you're ready to reconstruct the secret, you call `RecoverSecret`, which does some prodding about and hopefully gives you back what you put in. ================================================ FILE: vendor/github.com/cloudflare/redoctober/msp/formatted.go ================================================ package msp import ( "errors" "fmt" "strconv" "strings" ) type Formatted struct { // Represents threshold gate (also type of condition) Min int Conds []Condition } func StringToFormatted(f string) (out Formatted, err error) { // Automaton. Modification of Dijkstra's Two-Stack Algorithm for parsing // infix notation. Running time linear in the size of the predicate? // // Steps either to the next comma or the next unparenthesis. // ( -> Push new queue onto staging stack // value -> Push onto back of queue at top of staging stack. // ) -> Pop queue off top of staging stack, build threshold gate, // and push gate onto the back of the top queue. // // Staging stack is empty on initialization and should have exactly 1 built // threshold gate at the end of the string. if len(f) == 0 || f[0] != '(' || f[len(f)-1] != ')' { return out, errors.New("Invalid string: Needs to begin and end with parentheses.") } staging := [][]Condition{} indices := make(map[string]int, 0) var nxt string for len(f) > 0 { nxt, f = getNext(f) switch nxt { case "(": staging = append([][]Condition{[]Condition{}}, staging...) case ")": if len(staging) < 1 || len(staging[0]) < 1 { // Check 1 return out, errors.New("Invalid string: Illegal close parenthesis.") } top := staging[0] // Legal because of check 1. staging = staging[1:] var min int minStr, ok := top[0].(Name) // Legal because of check 1. if !ok { return out, errors.New("Invalid string: First argument wasn't a threshold!") } min, err = strconv.Atoi(minStr.string) if err != nil { return } built := Formatted{ Min: min, Conds: []Condition{}, } for _, cond := range top[1:] { built.Conds = append(built.Conds, cond) } if len(staging) == 0 { // Check 2 if len(f) == 0 { return built, nil } return out, errors.New("Invalid string: Can't parse anymore, but there's still data. Too many closing parentheses or too few opening parentheses?") } staging[0] = append(staging[0], built) // Legal because of check 2. default: if len(staging) < 1 { return out, errors.New("Invalid string: Name is not encapsulated!") } if _, there := indices[nxt]; !there { indices[nxt] = 0 } staging[0] = append(staging[0], Name{nxt, indices[nxt]}) // Legal because of check above. indices[nxt]++ } } return out, errors.New("Invalid string: Not finished parsing, but out of data. Too many opening parentheses or too few closing parentheses?") } func getNext(f string) (string, string) { // f -> (next, rest) f = strings.TrimSpace(f) if f[0] == '(' { return f[0:1], f[1:] } nextComma := strings.Index(f, ",") if f[0] == ')' { if nextComma == -1 { return f[0:1], "" } return f[0:1], f[nextComma+1:] } else if nextComma == -1 { return f[0 : len(f)-1], f[len(f)-1:] } nextUnParen := strings.Index(f, ")") if nextComma < nextUnParen { return strings.TrimSpace(f[0:nextComma]), f[nextComma+1:] } return strings.TrimSpace(f[0:nextUnParen]), f[nextUnParen:] } func (f Formatted) String() string { out := fmt.Sprintf("(%v", f.Min) for _, cond := range f.Conds { switch cond := cond.(type) { case Name: out += fmt.Sprintf(", %v", cond.string) case Formatted: out += fmt.Sprintf(", %v", cond.String()) } } return out + ")" } func (f Formatted) Ok(db UserDatabase) bool { // Goes through the smallest number of conditions possible to check if the // threshold gate returns true. Sometimes requires recursing down to check // nested threshold gates. rest := f.Min for _, cond := range f.Conds { if cond.Ok(db) { rest-- } if rest == 0 { return true } } return false } func (f *Formatted) Compress() { if f.Min == len(f.Conds) { // AND Compression: (n, ..., (m, ...), ...) = (n + m, ...) skip := 0 for i, cond := range f.Conds { if skip > 0 { skip-- continue } switch cond := cond.(type) { case Formatted: cond.Compress() f.Conds[i] = cond if cond.Min == len(cond.Conds) { f.Min += cond.Min - 1 f.Conds = append(f.Conds[0:i], append(cond.Conds, f.Conds[i+1:]...)...) skip = len(cond.Conds) - 1 } } } } else if f.Min == 1 { // OR Compression: (1, ..., (1, ...), ...) = (1, ...) skip := 0 for i, cond := range f.Conds { if skip > 0 { skip-- continue } switch cond := cond.(type) { case Formatted: cond.Compress() f.Conds[i] = cond if cond.Min == 1 { f.Conds = append(f.Conds[0:i], append(cond.Conds, f.Conds[i+1:]...)...) skip = len(cond.Conds) - 1 } } } } } ================================================ FILE: vendor/github.com/cloudflare/redoctober/msp/matrix.go ================================================ // Package msp implements matrix operations for elements in GF(2^128). package msp type Row []FieldElem // NewRow returns a row of length s with all zero entries. func NewRow(s int) Row { out := Row(make([]FieldElem, s)) for i := 0; i < s; i++ { out[i] = NewFieldElem() } return out } // AddM adds two vectors. func (e Row) AddM(f Row) { le, lf := e.Size(), f.Size() if le != lf { panic("Can't add rows that are different sizes!") } for i, fI := range f { e[i].AddM(fI) } return } // MulM multiplies the row by a scalar. func (e Row) MulM(f FieldElem) { for i := range e { e[i] = e[i].Mul(f) } } func (e Row) Mul(f FieldElem) Row { out := NewRow(e.Size()) for i := 0; i < e.Size(); i++ { out[i] = e[i].Mul(f) } return out } // DotProduct computes the dot product of two vectors. func (e Row) DotProduct(f Row) FieldElem { if e.Size() != f.Size() { panic("Can't get dot product of rows of different length!") } out := NewFieldElem() for i := 0; i < e.Size(); i++ { out.AddM(e[i].Mul(f[i])) } return out } func (e Row) Size() int { return len(e) } type Matrix []Row // Mul right-multiplies a matrix by a row. func (e Matrix) Mul(f Row) Row { out, in := e.Size() if in != f.Size() { panic("Can't multiply by row that is wrong size!") } res := NewRow(out) for i := 0; i < out; i++ { res[i] = e[i].DotProduct(f) } return res } // Recovery returns the row vector that takes this matrix to the target vector [1 0 0 ... 0]. func (e Matrix) Recovery() (Row, bool) { a, b := e.Size() // aug is the target vector. aug := NewRow(a) aug[0] = One.Dup() // Duplicate e away so we don't mutate it; transpose it at the same time. f := make([]Row, b) for i := range f { f[i] = NewRow(a) } for i := 0; i < a; i++ { for j := 0; j < b; j++ { f[j][i] = e[i][j].Dup() } } for row := range f { if row >= b { // The matrix is tall and thin--we've finished before exhausting all the rows. break } // Find a row with a non-zero entry in the (row)th position candId := -1 for j, fJ := range f[row:] { if !fJ[row].IsZero() { candId = j + row break } } if candId == -1 { // If we can't find one, fail and return our partial work. return aug, false } // Move it to the top f[row], f[candId] = f[candId], f[row] aug[row], aug[candId] = aug[candId], aug[row] // Make the pivot 1. fInv := f[row][row].Invert() f[row].MulM(fInv) aug[row] = aug[row].Mul(fInv) // Cancel out the (row)th position for every row above and below it. for i := range f { if i != row && !f[i][row].IsZero() { c := f[i][row].Dup() f[i].AddM(f[row].Mul(c)) aug[i].AddM(aug[row].Mul(c)) } } } return aug, true } func (e Matrix) Size() (int, int) { return len(e), e[0].Size() } ================================================ FILE: vendor/github.com/cloudflare/redoctober/msp/msp.go ================================================ package msp import ( "container/heap" "crypto/rand" "errors" "fmt" "strings" ) // A UserDatabase is an abstraction over the name -> share map returned by the // secret splitter that allows an application to only decrypt or request shares // when needed, rather than re-build a partial map of known data. type UserDatabase interface { ValidUser(name string) bool CanGetShare(name string) bool GetShare(name string) ([][]byte, error) } type Condition interface { // Represents one condition in a predicate Ok(UserDatabase) bool } type Name struct { // Type of condition string index int } func (n Name) Ok(db UserDatabase) bool { return db.CanGetShare(n.string) } type TraceElem struct { loc int names []string trace []string } type TraceSlice []TraceElem func (ts TraceSlice) Len() int { return len(ts) } func (ts TraceSlice) Swap(i, j int) { ts[i], ts[j] = ts[j], ts[i] } func (ts TraceSlice) Less(i, j int) bool { return len(ts[i].trace) > len(ts[j].trace) } func (ts *TraceSlice) Push(te interface{}) { *ts = append(*ts, te.(TraceElem)) } func (ts *TraceSlice) Pop() interface{} { old := *ts n := len(old) *ts = old[0 : n-1] out := old[n-1] return out } // Compact takes a trace slice and merges all of its fields. // // index: Union of all locations in the slice. // names: Union of all names in the slice. // trace: Union of all the traces in the slice. func (ts TraceSlice) Compact() (index []int, names []string, trace []string) { for _, te := range ts { index = append(index, te.loc) names = append(names, te.names...) trace = append(trace, te.trace...) } // This is a QuickSort related algorithm. It makes all the names in the trace unique so we don't double-count people. // // Invariant: There are no duplicates in trace[0:ptr] // Algorithm: Advance ptr by 1 and enforce the invariant. ptr, cutoff := 0, len(trace) TopLoop: for ptr < cutoff { // Choose the next un-checked element of the slice. for i := 0; i < ptr; i++ { // Compare it to all elements before it. if trace[i] == trace[ptr] { // If we find a duplicate... trace[ptr], trace[cutoff-1] = trace[cutoff-1], trace[ptr] // Push the dup to the end of the surviving slice. cutoff-- // Mark it for removal. continue TopLoop // Because trace[ptr] has been mutated, try to verify the invariant again w/o advancing ptr. } } ptr++ // There are no duplicates; move the ptr forward and start again. } trace = trace[0:cutoff] return } type MSP Formatted func StringToMSP(pred string) (m MSP, err error) { var f Formatted if -1 == strings.Index(pred, ",") { var r Raw r, err = StringToRaw(pred) if err != nil { return } f = r.Formatted() } else { f, err = StringToFormatted(pred) if err != nil { return } } return MSP(f), nil } // DerivePath returns the cheapest way to satisfy the MSP (the one with the minimal number of delegations). // // ok: True if the MSP can be satisfied with current delegations; false if not. // names: The names in the top-level threshold gate that need to be delegated. // locs: The index in the treshold gate for each name. // trace: All names that must be delegated for for this gate to be satisfied. func (m MSP) DerivePath(db UserDatabase) (ok bool, names []string, locs []int, trace []string) { ts := &TraceSlice{} for i, cond := range m.Conds { switch cond := cond.(type) { case Name: if db.CanGetShare(cond.string) { heap.Push(ts, TraceElem{ i, []string{cond.string}, []string{cond.string}, }) } case Formatted: sok, _, _, strace := MSP(cond).DerivePath(db) if sok { heap.Push(ts, TraceElem{i, []string{}, strace}) } } if (*ts).Len() > m.Min { // If we can otherwise satisfy the threshold gate heap.Pop(ts) // Drop the TraceElem with the heaviest trace (the one that requires the most delegations). } } ok = (*ts).Len() >= m.Min locs, names, trace = ts.Compact() return } // DistributeShares takes as input a secret and a user database and returns secret shares according to access structure // described by the MSP. func (m MSP) DistributeShares(sec []byte, db UserDatabase) (map[string][][]byte, error) { out := make(map[string][][]byte) // Generate a Vandermonde matrix. height, width := len(m.Conds), m.Min M := Matrix(make([]Row, height)) for i := 0; i < height; i++ { M[i] = NewRow(width) for j := 0; j < width; j++ { M[i][j][0] = byte(i + 1) M[i][j] = M[i][j].Exp(j) } } // Convert secret vector. s := NewRow(width) s[0] = FieldElem(sec) for i := 1; i < width; i++ { r := NewFieldElem() rand.Read(r) s[i] = FieldElem(r) } // Calculate shares. shares := M.Mul(s) // Distribute the shares. for i, cond := range m.Conds { share := shares[i] switch cond := cond.(type) { case Name: name := cond.string if !db.ValidUser(name) { return nil, fmt.Errorf("Unknown user '%s' in predicate.", name) } out[name] = append(out[name], share) case Formatted: below := MSP(cond) subOut, err := below.DistributeShares(share, db) if err != nil { return out, err } for name, shares := range subOut { out[name] = append(out[name], shares...) } } } return out, nil } // ErrNotEnoughShares is returned if there aren't enough shares to // decrypt the secret. var ErrNotEnoughShares = errors.New("not enough shares to recover") // RecoverSecret takes a user database storing secret shares as input and returns the original secret. func (m MSP) RecoverSecret(db UserDatabase) ([]byte, error) { cache := make(map[string][][]byte, 0) // Caches un-used shares for a user. return m.recoverSecret(db, cache) } func (m MSP) recoverSecret(db UserDatabase, cache map[string][][]byte) ([]byte, error) { var ( index = []int{} // Indexes where given shares were in the matrix. shares = []FieldElem{} // Contains shares that will be used in reconstruction. ) ok, names, locs, _ := m.DerivePath(db) if !ok { return nil, ErrNotEnoughShares } for _, name := range names { if _, cached := cache[name]; !cached { out, err := db.GetShare(name) if err != nil { return nil, err } cache[name] = out } } for _, loc := range locs { gate := m.Conds[loc] index = append(index, loc+1) switch gate := gate.(type) { case Name: if len(cache[gate.string]) <= gate.index { return nil, errors.New("Predicate / database mismatch!") } shares = append(shares, FieldElem(cache[gate.string][gate.index])) case Formatted: share, err := MSP(gate).recoverSecret(db, cache) if err != nil { return nil, err } shares = append(shares, FieldElem(share)) } } // Generate the Vandermonde matrix specific to whichever users' shares we're using. MSub := Matrix(make([]Row, m.Min)) for i := 0; i < m.Min; i++ { MSub[i] = NewRow(m.Min) for j := 0; j < m.Min; j++ { MSub[i][j][0] = byte(index[i]) MSub[i][j] = MSub[i][j].Exp(j) } } // Calculate the reconstruction vector and use it to recover the secret. r, ok := MSub.Recovery() if !ok { return nil, errors.New("Unable to find a reconstruction vector!") } // Compute dot product of the shares vector and the reconstruction vector to // recover the secret. s := Row(shares).DotProduct(r) return []byte(s), nil } ================================================ FILE: vendor/github.com/cloudflare/redoctober/msp/number.go ================================================ // Polynomial fields with coefficients in GF(2) package msp import ( "bytes" ) type FieldElem []byte var ( Modulus FieldElem = []byte{135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // x^128 + x^7 + x^2 + x + 1 ModulusSize int = 16 ModulusBitSize int = 128 Zero FieldElem = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} One FieldElem = []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} ) // NewFieldElem returns a new zero element. func NewFieldElem() FieldElem { return FieldElem(make([]byte, ModulusSize)) } // AddM mutates e into e+f. func (e FieldElem) AddM(f FieldElem) { for i := 0; i < ModulusSize; i++ { e[i] ^= f[i] } } // Add returns e+f. func (e FieldElem) Add(f FieldElem) FieldElem { out := e.Dup() out.AddM(f) return out } // Mul returns e*f. func (e FieldElem) Mul(f FieldElem) FieldElem { out := NewFieldElem() for i := 0; i < ModulusBitSize; i++ { // Foreach bit e_i in e: if e.getCoeff(i) == 1 { // where e_i equals 1: temp := f.Dup() // Multiply f * x^i mod M(x): for j := 0; j < i; j++ { // Multiply f by x mod M(x), i times. carry := temp.shift() if carry { temp[0] ^= Modulus[0] } } out.AddM(temp) // Add f * x^i to the output } } return out } // Exp returns e^i. func (e FieldElem) Exp(i int) FieldElem { out := One.Dup() for j := 0; j < i; j++ { out = out.Mul(e) } return out } // Invert returns the multiplicative inverse of e. func (e FieldElem) Invert() FieldElem { out, temp := e.Dup(), e.Dup() for i := 0; i < 126; i++ { temp = temp.Mul(temp) out = out.Mul(temp) } return out.Mul(out) } // getCoeff returns the ith coefficient of the field element: either 0 or 1. func (e FieldElem) getCoeff(i int) byte { return (e[i/8] >> (uint(i) % 8)) & 1 } // shift multiplies e by 2 and returns true if there was overflow and false if there wasn't. func (e FieldElem) shift() bool { carry := false for i := 0; i < ModulusSize; i++ { nextCarry := e[i] >= 128 e[i] = e[i] << 1 if carry { e[i]++ } carry = nextCarry } return carry } func (e FieldElem) IsZero() bool { return bytes.Compare(e, Zero) == 0 } func (e FieldElem) IsOne() bool { return bytes.Compare(e, One) == 0 } // Dup returns a duplicate of e. func (e FieldElem) Dup() FieldElem { out := FieldElem(make([]byte, ModulusSize)) copy(out, e) return out } ================================================ FILE: vendor/github.com/cloudflare/redoctober/msp/raw.go ================================================ package msp import ( "errors" "strings" ) type NodeType int // Types of node in the binary expression tree. const ( NodeAnd NodeType = iota NodeOr ) func (t NodeType) Type() NodeType { return t } type Layer struct { Conditions []Condition Operators []NodeType } type Raw struct { // Represents one node in the tree. NodeType Left Condition Right Condition } func StringToRaw(r string) (out Raw, err error) { // Automaton. Modification of Dijkstra's Two-Stack Algorithm for parsing // infix notation. Reads one long unbroken expression (several operators and // operands with no parentheses) at a time and parses it into a binary // expression tree (giving AND operators precedence). Running time linear in // the size of the predicate? // // Steps to the next (un)parenthesis. // ( -> Push new queue onto staging stack // value -> Push onto back of queue at top of staging stack. // ) -> Pop queue off top of staging stack, build BET, and push tree // onto the back of the top queue. // // To build the binary expression tree, for each type of operation we iterate // through the (Condition, operator) lists compacting where that operation // occurs into tree nodes. // // Staging stack is empty on initialization and should have exactly 1 node // (the root node) at the end of the string. r = "(" + r + ")" min := func(a, b, c int) int { // Return smallest non-negative argument. if a > b { // Sort {a, b, c} a, b = b, a } if b > c { b, c = c, b } if a > b { a, b = b, a } if a != -1 { return a } else if b != -1 { return b } else { return c } } getNext := func(r string) (string, string) { // r -> (next, rest) r = strings.TrimSpace(r) if r[0] == '(' || r[0] == ')' || r[0] == '&' || r[0] == '|' { return r[0:1], r[1:] } nextOper := min( strings.Index(r, "&"), strings.Index(r, "|"), strings.Index(r, ")"), ) if nextOper == -1 { return r, "" } return strings.TrimSpace(r[0:nextOper]), r[nextOper:] } staging := []Layer{} // Stack of (Condition list, operator list) indices := make(map[string]int, 0) var nxt string for len(r) > 0 { nxt, r = getNext(r) switch nxt { case "(": staging = append([]Layer{Layer{}}, staging...) case ")": if len(staging) < 1 { // Check 1 return out, errors.New("Invalid string: Illegal close parenthesis.") } top := staging[0] // Legal because of check 1. staging = staging[1:] if len(top.Conditions) != (len(top.Operators) + 1) { // Check 2 return out, errors.New("Invalid string: There needs to be an operator (& or |) for every pair of operands.") } for typ := NodeAnd; typ <= NodeOr; typ++ { i := 0 for i < len(top.Operators) { oper := top.Operators[i] // Legal because for loop condition. // Copy left and right out of slice and THEN give a pointer for them! left, right := top.Conditions[i], top.Conditions[i+1] // Legal because of check 2. if oper == typ { built := Raw{typ, left, right} top.Conditions = append( top.Conditions[:i], append([]Condition{built}, top.Conditions[i+2:]...)..., ) top.Operators = append(top.Operators[:i], top.Operators[i+1:]...) // Legal because for loop condition. } else { i++ } } } if len(top.Conditions) != 1 || len(top.Operators) != 0 { // Check 3 return out, errors.New("Invalid string: Couldn't evaluate all of the operators.") } if len(staging) == 0 { // Check 4 if len(r) == 0 { res, ok := top.Conditions[0].(Raw) // Legal because of check 3. if !ok { return out, errors.New("Invalid string: Only one condition was found?") } return res, nil } return out, errors.New("Invalid string: Can't parse anymore, but there's still data. Too many closing parentheses or too few opening parentheses?") } staging[0].Conditions = append(staging[0].Conditions, top.Conditions[0]) // Legal because of checks 3 and 4. case "&": // Legal because first operation is to add an empty layer to the stack. // If the stack is ever empty again, the function tries to return or error. staging[0].Operators = append(staging[0].Operators, NodeAnd) case "|": staging[0].Operators = append(staging[0].Operators, NodeOr) // Legal for same reason as case &. default: if _, there := indices[nxt]; !there { indices[nxt] = 0 } staging[0].Conditions = append(staging[0].Conditions, Name{nxt, indices[nxt]}) // Legal for same reason as case &. indices[nxt]++ } } return out, errors.New("Invalid string: Not finished parsing, but out of data. Too many opening parentheses or too few closing parentheses?") } func (r Raw) String() string { out := "" switch left := r.Left.(type) { case Name: out += left.string case Raw: out += "(" + left.String() + ")" } if r.Type() == NodeAnd { out += " & " } else { out += " | " } switch right := r.Right.(type) { case Name: out += right.string case Raw: out += "(" + right.String() + ")" } return out } func (r Raw) Formatted() (out Formatted) { // Recursively maps a raw predicate to a formatted predicate by mapping AND // gates to (2, A, B) treshold gates and OR gates to (1, A, B) gates. if r.Type() == NodeAnd { out.Min = 2 } else { out.Min = 1 } switch left := r.Left.(type) { case Name: out.Conds = []Condition{left} case Raw: out.Conds = []Condition{left.Formatted()} } switch right := r.Right.(type) { case Name: out.Conds = append(out.Conds, right) case Raw: out.Conds = append(out.Conds, right.Formatted()) } out.Compress() // Small amount of predicate compression. return } func (r Raw) Ok(db UserDatabase) bool { if r.Type() == NodeAnd { return r.Left.Ok(db) && r.Right.Ok(db) } return r.Left.Ok(db) || r.Right.Ok(db) } ================================================ FILE: vendor/github.com/cloudflare/redoctober/order/order.go ================================================ // Package order manages the bookkeeping and utilies required // for users to create an 'order' meaning they have requested // delegations for a certain resource. // // Copyright (c) 2016 CloudFlare, Inc. package order import ( "crypto/rand" "encoding/hex" "fmt" "net/url" "strconv" "time" "github.com/cloudflare/redoctober/hipchat" ) const ( NewOrder = "%s has created an order for the label %s. requesting %d delegations for %s" NewOrderLink = "@%s - https://%s?%s" OrderFulfilled = "%s has had order %s fulfilled." NewDelegation = "%s has delegated the label %s to %s (per order %s) for %s" ) type Order struct { Creator string Users []string Num string TimeRequested time.Time DurationRequested time.Duration Delegated int OwnersDelegated []string Owners []string Labels []string } type OrderIndex struct { OrderFor string OrderId string OrderOwners []string } // Orders represents a mapping of Order IDs to Orders. This structure // is useful for looking up information about individual Orders and // whether or not an order has been fulfilled. Orders that have been // fulfilled will be removed from the structure. type Orderer struct { Orders map[string]Order Hipchat hipchat.HipchatClient AlternateName string } func CreateOrder(name, orderNum string, time time.Time, duration time.Duration, adminsDelegated, contacts, users, labels []string, numDelegated int) (ord Order) { ord.Creator = name ord.Num = orderNum ord.Labels = labels ord.TimeRequested = time ord.DurationRequested = duration ord.OwnersDelegated = adminsDelegated ord.Owners = contacts ord.Delegated = numDelegated ord.Users = users return } func GenerateNum() (num string) { b := make([]byte, 12) rand.Read(b) return hex.EncodeToString(b) } // NewOrder will create a new map of Orders func NewOrderer(hipchatClient hipchat.HipchatClient) (o Orderer) { o.Orders = make(map[string]Order) o.Hipchat = hipchatClient o.AlternateName = "HipchatName" return } // notify is a generic function for using a notifier, but it checks to make // sure that there is a notifier available, since there won't always be. func notify(o *Orderer, msg, color string) { o.Hipchat.Notify(msg, color) } func (o *Orderer) NotifyNewOrder(duration, orderNum string, names, labels []string, uses int, owners map[string]string) { labelList := "" for i, label := range labels { if i == 0 { labelList += label } else { // Never include spaces in something go URI encodes. Go will // add a + to the string, instead of a %20 labelList += "," + label } } nameList := "" for i, name := range names { if i == 0 { nameList += name } else { // Never include spaces in something go URI encodes. Go will // add a + to the string, instead of a %20 nameList += "," + name } } n := fmt.Sprintf(NewOrder, nameList, labelList, uses, duration) notify(o, n, hipchat.RedBackground) for owner, hipchatName := range owners { queryParams := url.Values{ "delegator": {owner}, "label": {labelList}, "duration": {duration}, "uses": {strconv.Itoa(uses)}, "ordernum": {orderNum}, "delegatee": {nameList}, }.Encode() notify(o, fmt.Sprintf(NewOrderLink, hipchatName, o.Hipchat.RoHost, queryParams), hipchat.GreenBackground) } } func (o *Orderer) NotifyDelegation(delegator, delegatee, orderNum, duration string, labels []string) { labelList := "" for i, label := range labels { if i == 0 { labelList += label } else { labelList += ", " + label } } n := fmt.Sprintf(NewDelegation, delegator, labelList, delegatee, orderNum, duration) notify(o, n, hipchat.YellowBackground) } func (o *Orderer) NotifyOrderFulfilled(name, orderNum string) { n := fmt.Sprintf(OrderFulfilled, name, orderNum) notify(o, n, hipchat.PurpleBackground) } func (o *Orderer) FindOrder(user string, labels []string) (string, bool) { for key, order := range o.Orders { foundLabel := false foundUser := false for _, orderUser := range order.Users { if orderUser == user { foundUser = true } } if !foundUser { continue } for _, ol := range order.Labels { foundLabel = false for _, il := range labels { if il == ol { foundLabel = true } } } if !foundLabel { continue } return key, true } return "", false } ================================================ FILE: vendor/github.com/cloudflare/redoctober/padding/padding.go ================================================ // Package padding adds and removes padding for AES-CBC mode. // // Copyright (c) 2013 CloudFlare, Inc. package padding import "errors" // The final byte of a padded []byte indicates the number of padding // bytes that were added. The padding bytes are always NUL bytes and // up to 16 bytes may be added. // // Examples: // // 1. Data to be padded has a length divisible by 16. 16 bytes will be // added where the first 15 are 0x00 and the final byte is 0x10. // // 2. Data to be padded has a length with remainder 15 when divided by // 16. One byte will be added and that byte will be 0x01 (indicating // one byte of padding). // // 3. Data to be padded has a length with remainder 2 when divided by // 16. 14 bytes will be added. The first 13 will be 0x00 and then final // byte will be 0x0e. // // Removing padding is trivial: the number of bytes specified by the // final byte are removed. // RemovePadding removes padding from data that was added with // AddPadding func RemovePadding(b []byte) ([]byte, error) { l := int(b[len(b)-1]) if l > 16 { return nil, errors.New("Padding incorrect") } return b[:len(b)-l], nil } // AddPadding adds padding to a block of data func AddPadding(b []byte) []byte { l := 16 - len(b)%16 padding := make([]byte, l) padding[l-1] = byte(l) return append(b, padding...) } ================================================ FILE: vendor/github.com/cloudflare/redoctober/passvault/passvault.go ================================================ // Package passvault manages the vault containing user records on // disk. It contains usernames and associated passwords which are // stored hashed (with salt) using scrypt. // // Copyright (c) 2013 CloudFlare, Inc. package passvault import ( "bytes" "crypto/aes" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/sha1" "crypto/x509" "encoding/binary" "encoding/json" "errors" "io/ioutil" "math/big" mrand "math/rand" "os" "github.com/cloudflare/redoctober/ecdh" "github.com/cloudflare/redoctober/padding" "github.com/cloudflare/redoctober/symcrypt" "golang.org/x/crypto/scrypt" ) // Constants for record type const ( RSARecord = "RSA" ECCRecord = "ECC" ) var DefaultRecordType = RSARecord // Constants for scrypt const ( KEYLENGTH = 16 // 16-byte output from scrypt N = 16384 // Cost parameter R = 8 // Block size P = 1 // Parallelization factor DEFAULT_VERSION = 1 ) type ECPublicKey struct { Curve *elliptic.CurveParams X, Y *big.Int } // toECDSA takes the internal ECPublicKey and returns an equivalent // an ecdsa.PublicKey func (pk *ECPublicKey) toECDSA() *ecdsa.PublicKey { ecdsaPub := new(ecdsa.PublicKey) ecdsaPub.Curve = pk.Curve ecdsaPub.X = pk.X ecdsaPub.Y = pk.Y return ecdsaPub } // PasswordRecord is the structure used to store password and key // material for a single user name. It is written and read from // storage in JSON format. type PasswordRecord struct { Type string PasswordSalt []byte HashedPassword []byte KeySalt []byte RSAKey struct { RSAExp []byte RSAExpIV []byte RSAPrimeP []byte RSAPrimePIV []byte RSAPrimeQ []byte RSAPrimeQIV []byte RSAPublic rsa.PublicKey } ECKey struct { ECPriv []byte ECPrivIV []byte ECPublic ECPublicKey } AltNames map[string]string Admin bool } // Records is the structure used to read and write a JSON file // containing the contents of a password vault type Records struct { Version int VaultId int HmacKey []byte Passwords map[string]PasswordRecord localPath string // Path of current vault } // Summary is a minmial account summary. type Summary struct { Admin bool Type string } func init() { // seed math.random from crypto.random seedBytes, _ := symcrypt.MakeRandom(8) seedBuf := bytes.NewBuffer(seedBytes) n64, _ := binary.ReadVarint(seedBuf) mrand.Seed(n64) } // hashPassword takes a password and derives a scrypt salted and hashed // version func hashPassword(password string, salt []byte) ([]byte, error) { return scrypt.Key([]byte(password), salt, N, R, P, KEYLENGTH) } // encryptRSARecord takes an RSA private key and encrypts it with // a password key func encryptRSARecord(newRec *PasswordRecord, rsaPriv *rsa.PrivateKey, passKey []byte) (err error) { if newRec.RSAKey.RSAExpIV, err = symcrypt.MakeRandom(16); err != nil { return } paddedExponent := padding.AddPadding(rsaPriv.D.Bytes()) if newRec.RSAKey.RSAExp, err = symcrypt.EncryptCBC(paddedExponent, newRec.RSAKey.RSAExpIV, passKey); err != nil { return } if newRec.RSAKey.RSAPrimePIV, err = symcrypt.MakeRandom(16); err != nil { return } paddedPrimeP := padding.AddPadding(rsaPriv.Primes[0].Bytes()) if newRec.RSAKey.RSAPrimeP, err = symcrypt.EncryptCBC(paddedPrimeP, newRec.RSAKey.RSAPrimePIV, passKey); err != nil { return } if newRec.RSAKey.RSAPrimeQIV, err = symcrypt.MakeRandom(16); err != nil { return } paddedPrimeQ := padding.AddPadding(rsaPriv.Primes[1].Bytes()) newRec.RSAKey.RSAPrimeQ, err = symcrypt.EncryptCBC(paddedPrimeQ, newRec.RSAKey.RSAPrimeQIV, passKey) return } // encryptECCRecord takes an ECDSA private key and encrypts it with // a password key. func encryptECCRecord(newRec *PasswordRecord, ecPriv *ecdsa.PrivateKey, passKey []byte) (err error) { ecX509, err := x509.MarshalECPrivateKey(ecPriv) if err != nil { return } if newRec.ECKey.ECPrivIV, err = symcrypt.MakeRandom(16); err != nil { return } paddedX509 := padding.AddPadding(ecX509) newRec.ECKey.ECPriv, err = symcrypt.EncryptCBC(paddedX509, newRec.ECKey.ECPrivIV, passKey) return } // createPasswordRec creates a new record from a username and password func createPasswordRec(password string, admin bool, userType string) (newRec PasswordRecord, err error) { newRec.Type = userType if newRec.PasswordSalt, err = symcrypt.MakeRandom(16); err != nil { return } if newRec.HashedPassword, err = hashPassword(password, newRec.PasswordSalt); err != nil { return } if newRec.KeySalt, err = symcrypt.MakeRandom(16); err != nil { return } passKey, err := derivePasswordKey(password, newRec.KeySalt) if err != nil { return } newRec.AltNames = make(map[string]string) // generate a key pair switch userType { case RSARecord: var rsaPriv *rsa.PrivateKey rsaPriv, err = rsa.GenerateKey(rand.Reader, 2048) if err != nil { return } // encrypt RSA key with password key if err = encryptRSARecord(&newRec, rsaPriv, passKey); err != nil { return } newRec.RSAKey.RSAPublic = rsaPriv.PublicKey case ECCRecord: var ecPriv *ecdsa.PrivateKey ecPriv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return } // encrypt ECDSA key with password key if err = encryptECCRecord(&newRec, ecPriv, passKey); err != nil { return } newRec.ECKey.ECPublic.Curve = ecPriv.PublicKey.Curve.Params() newRec.ECKey.ECPublic.X = ecPriv.PublicKey.X newRec.ECKey.ECPublic.Y = ecPriv.PublicKey.Y default: err = errors.New("Unknown record type") } newRec.Admin = admin return } // derivePasswordKey generates a key from a password (and salt) using // scrypt func derivePasswordKey(password string, keySalt []byte) ([]byte, error) { return scrypt.Key([]byte(password), keySalt, N, R, P, KEYLENGTH) } // decryptECB decrypts bytes using a key in AES ECB mode. func decryptECB(data, key []byte) (decryptedData []byte, err error) { aesCrypt, err := aes.NewCipher(key) if err != nil { return } decryptedData = make([]byte, len(data)) aesCrypt.Decrypt(decryptedData, data) return } // encryptECB encrypts bytes using a key in AES ECB mode. func encryptECB(data, key []byte) (encryptedData []byte, err error) { aesCrypt, err := aes.NewCipher(key) if err != nil { return } encryptedData = make([]byte, len(data)) aesCrypt.Encrypt(encryptedData, data) return } // InitFrom reads the record from disk and initialize global context. func InitFrom(path string) (records Records, err error) { var jsonDiskRecord []byte if path != "memory" { jsonDiskRecord, err = ioutil.ReadFile(path) // It's OK for the file to be missing, we'll create it later if // anything is added. if err != nil && !os.IsNotExist(err) { return } } // Initialized so that we can determine later if anything was read // from the file. records.Version = 0 if len(jsonDiskRecord) != 0 { if err = json.Unmarshal(jsonDiskRecord, &records); err != nil { return } } err = errors.New("Format error") for k, rec := range records.Passwords { if rec.AltNames == nil { rec.AltNames = make(map[string]string) records.Passwords[k] = rec } if len(rec.PasswordSalt) != 16 { return } if len(rec.HashedPassword) != 16 { return } if len(rec.KeySalt) != 16 { return } if rec.Type == RSARecord { if len(rec.RSAKey.RSAExp) == 0 || len(rec.RSAKey.RSAExp)%16 != 0 { return } if len(rec.RSAKey.RSAPrimeP) == 0 || len(rec.RSAKey.RSAPrimeP)%16 != 0 { return } if len(rec.RSAKey.RSAPrimeQ) == 0 || len(rec.RSAKey.RSAPrimeQ)%16 != 0 { return } if len(rec.RSAKey.RSAExpIV) != 16 { return } if len(rec.RSAKey.RSAPrimePIV) != 16 { return } if len(rec.RSAKey.RSAPrimeQIV) != 16 { return } } if rec.Type == ECCRecord { if len(rec.ECKey.ECPriv) == 0 || len(rec.ECKey.ECPriv)%16 != 0 { return } if len(rec.ECKey.ECPrivIV) != 16 { return } } } // If the Version field is 0 then it indicates that nothing was // read from the file and so it needs to be initialized. if records.Version == 0 { records.Version = DEFAULT_VERSION records.VaultId = int(mrand.Int31()) records.HmacKey, err = symcrypt.MakeRandom(16) if err != nil { return } records.Passwords = make(map[string]PasswordRecord) } records.localPath = path err = nil return } // WriteRecordsToDisk saves the current state of the records to disk. func (records *Records) WriteRecordsToDisk() error { if records.localPath == "memory" { return nil } jsonDiskRecord, err := json.Marshal(records) if err != nil { return err } return ioutil.WriteFile(records.localPath, jsonDiskRecord, 0644) } // AddNewRecord adds a new record for a given username and password. func (records *Records) AddNewRecord(name, password string, admin bool, userType string) (PasswordRecord, error) { pr, err := createPasswordRec(password, admin, userType) if err != nil { return pr, err } records.SetRecord(pr, name) return pr, records.WriteRecordsToDisk() } // ChangePassword changes the password for a given user. func (records *Records) ChangePassword(name, password, newPassword, hipchatName string) (err error) { pr, ok := records.GetRecord(name) if !ok { err = errors.New("Record not present") return } if len(hipchatName) != 0 { pr.AltNames["HipchatName"] = hipchatName } if len(newPassword) == 0 { records.SetRecord(pr, name) return records.WriteRecordsToDisk() } var keySalt []byte if keySalt, err = symcrypt.MakeRandom(16); err != nil { return } newPassKey, err := derivePasswordKey(newPassword, keySalt) if err != nil { return } // decrypt with old password and re-encrypt original key with new password if pr.Type == RSARecord { var rsaKey rsa.PrivateKey rsaKey, err = pr.GetKeyRSA(password) if err != nil { return } // encrypt RSA key with password key err = encryptRSARecord(&pr, &rsaKey, newPassKey) if err != nil { return } } else if pr.Type == ECCRecord { var ecKey *ecdsa.PrivateKey ecKey, err = pr.GetKeyECC(password) if err != nil { return } // encrypt ECDSA key with password key err = encryptECCRecord(&pr, ecKey, newPassKey) if err != nil { return } } else { err = errors.New("Unknown record type") return } // add the password salt and hash if pr.PasswordSalt, err = symcrypt.MakeRandom(16); err != nil { return } if pr.HashedPassword, err = hashPassword(newPassword, pr.PasswordSalt); err != nil { return } pr.KeySalt = keySalt records.SetRecord(pr, name) return records.WriteRecordsToDisk() } // DeleteRecord deletes a given record. func (records *Records) DeleteRecord(name string) error { if _, ok := records.GetRecord(name); ok { delete(records.Passwords, name) return records.WriteRecordsToDisk() } return errors.New("Record missing") } // RevokeRecord removes admin status from a record. func (records *Records) RevokeRecord(name string) error { if rec, ok := records.GetRecord(name); ok { rec.Admin = false records.SetRecord(rec, name) return records.WriteRecordsToDisk() } return errors.New("Record missing") } // MakeAdmin adds admin status to a given record. func (records *Records) MakeAdmin(name string) error { if rec, ok := records.GetRecord(name); ok { rec.Admin = true records.SetRecord(rec, name) return records.WriteRecordsToDisk() } return errors.New("Record missing") } // SetRecord puts a record into the global status. func (records *Records) SetRecord(pr PasswordRecord, name string) { records.Passwords[name] = pr } // GetRecord returns a record given a name. func (records *Records) GetRecord(name string) (PasswordRecord, bool) { dpr, found := records.Passwords[name] return dpr, found } // GetVaultID returns the id of the current vault. func (records *Records) GetVaultID() (id int, err error) { return records.VaultId, nil } // GetHMACKey returns the hmac key of the current vault. func (records *Records) GetHMACKey() (key []byte, err error) { return records.HmacKey, nil } // NumRecords returns the number of records in the vault. func (records *Records) NumRecords() int { return len(records.Passwords) } // GetSummary returns a summary of the records on disk. func (records *Records) GetSummary() (summary map[string]Summary) { summary = make(map[string]Summary) for name, pass := range records.Passwords { summary[name] = Summary{pass.Admin, pass.Type} } return } // IsAdmin returns the admin status of the PasswordRecord. func (pr *PasswordRecord) IsAdmin() bool { return pr.Admin } // GetType returns the type status of the PasswordRecord. func (pr *PasswordRecord) GetType() string { return pr.Type } // EncryptKey encrypts a 16-byte key with the RSA or EC key of the record. func (pr *PasswordRecord) EncryptKey(in []byte) (out []byte, err error) { if pr.Type == RSARecord { return rsa.EncryptOAEP(sha1.New(), rand.Reader, &pr.RSAKey.RSAPublic, in, nil) } else if pr.Type == ECCRecord { return ecdh.Encrypt(pr.ECKey.ECPublic.toECDSA(), in) } else { return nil, errors.New("Invalid function for record type") } } // GetKeyRSAPub returns the RSA public key of the record. func (pr *PasswordRecord) GetKeyRSAPub() (out *rsa.PublicKey, err error) { if pr.Type != RSARecord { return out, errors.New("Invalid function for record type") } return &pr.RSAKey.RSAPublic, err } // GetKeyECCPub returns the ECDSA public key out of the record. func (pr *PasswordRecord) GetKeyECCPub() (out *ecdsa.PublicKey, err error) { if pr.Type != ECCRecord { return out, errors.New("Invalid function for record type") } return pr.ECKey.ECPublic.toECDSA(), err } // GetKeyECC returns the ECDSA private key of the record given the correct password. func (pr *PasswordRecord) GetKeyECC(password string) (key *ecdsa.PrivateKey, err error) { if pr.Type != ECCRecord { return key, errors.New("Invalid function for record type") } if err = pr.ValidatePassword(password); err != nil { return } passKey, err := derivePasswordKey(password, pr.KeySalt) if err != nil { return } x509Padded, err := symcrypt.DecryptCBC(pr.ECKey.ECPriv, pr.ECKey.ECPrivIV, passKey) if err != nil { return } ecX509, err := padding.RemovePadding(x509Padded) if err != nil { return } return x509.ParseECPrivateKey(ecX509) } // GetKeyRSA returns the RSA private key of the record given the correct password. func (pr *PasswordRecord) GetKeyRSA(password string) (key rsa.PrivateKey, err error) { if pr.Type != RSARecord { return key, errors.New("Invalid function for record type") } err = pr.ValidatePassword(password) if err != nil { return } passKey, err := derivePasswordKey(password, pr.KeySalt) if err != nil { return } rsaExponentPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAExp, pr.RSAKey.RSAExpIV, passKey) if err != nil { return } rsaExponent, err := padding.RemovePadding(rsaExponentPadded) if err != nil { return } rsaPrimePPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAPrimeP, pr.RSAKey.RSAPrimePIV, passKey) if err != nil { return } rsaPrimeP, err := padding.RemovePadding(rsaPrimePPadded) if err != nil { return } rsaPrimeQPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAPrimeQ, pr.RSAKey.RSAPrimeQIV, passKey) if err != nil { return } rsaPrimeQ, err := padding.RemovePadding(rsaPrimeQPadded) if err != nil { return } key.PublicKey = pr.RSAKey.RSAPublic key.D = big.NewInt(0).SetBytes(rsaExponent) key.Primes = []*big.Int{big.NewInt(0), big.NewInt(0)} key.Primes[0].SetBytes(rsaPrimeP) key.Primes[1].SetBytes(rsaPrimeQ) err = key.Validate() if err != nil { return } return } func (records *Records) GetAltNameFromName(alt, name string) (altName string, found bool) { if passwordRecord, ok := records.Passwords[name]; ok { if altName, ok := passwordRecord.AltNames[alt]; ok { return altName, true } } return "", false } func (r *Records) GetAltNamesFromName(alt string, names []string) map[string]string { altNames := make(map[string]string) for _, name := range names { altName, found := r.GetAltNameFromName(alt, name) if !found { altName = name } altNames[name] = altName } return altNames } // ValidatePassword returns an error if the password is incorrect. func (pr *PasswordRecord) ValidatePassword(password string) error { h, err := hashPassword(password, pr.PasswordSalt) if err != nil { return err } if bytes.Compare(h, pr.HashedPassword) != 0 { return errors.New("Wrong Password") } return nil } ================================================ FILE: vendor/github.com/cloudflare/redoctober/persist/file.go ================================================ package persist import ( "io/ioutil" "os" "github.com/cloudflare/redoctober/config" "github.com/cloudflare/redoctober/keycache" "github.com/cloudflare/redoctober/passvault" ) // File implements a file-backed persistence store. type File struct { config *config.Delegations cache *keycache.Cache state string blob []byte } // Valid ensures the configuration is valid for a file store. Note // that it won't validate the policy, it will just ensure that one // is present. func (f *File) Valid() bool { if f.config.Persist == false { return false } if f.config.Policy == "" { return false } if len(f.config.Users) == 0 { return false } if f.config.Mechanism != FileMechanism { return false } if f.config.Location == "" { return false } return true } // newFile returns a new file-backed persistence store. func newFile(config *config.Delegations) (Store, error) { cache := keycache.NewCache() file := &File{ config: config, cache: &cache, state: Inactive, } if !file.Valid() { return nil, ErrInvalidConfig } err := file.Load() if err != nil { return nil, err } return file, nil } func (f *File) Blob() []byte { return f.blob } func (f *File) Policy() string { return f.config.Policy } func (f *File) Users() []string { return f.config.Users } func (f *File) Store(blob []byte) error { if f.state == Active { f.blob = blob return ioutil.WriteFile(f.config.Location, blob, 0644) } return nil } func (f *File) Load() error { if fi, err := os.Stat(f.config.Location); err != nil { // If the file doesn't exist, it can be persisted // immediately. if os.IsNotExist(err) { f.state = Active return nil } return err } else if fi.Size() == 0 { f.state = Active return nil } in, err := ioutil.ReadFile(f.config.Location) if err != nil { return err } f.state = Inactive f.blob = in return nil } func (f *File) Persist() { f.state = Active } func (f *File) Cache() *keycache.Cache { return f.cache } func (f *File) Delegate(record passvault.PasswordRecord, name, password string, users, labels []string, uses int, slot, durationString string) error { return f.cache.AddKeyFromRecord(record, name, password, users, labels, uses, slot, durationString) } func (f *File) Status() *Status { return &Status{ State: f.state, Summary: f.cache.GetSummary(), } } func (f *File) Purge() error { f.state = Active f.blob = nil if err := os.Remove(f.config.Location); err != nil { return err } return nil } ================================================ FILE: vendor/github.com/cloudflare/redoctober/persist/null.go ================================================ package persist import ( "errors" "github.com/cloudflare/redoctober/config" "github.com/cloudflare/redoctober/keycache" "github.com/cloudflare/redoctober/passvault" ) // Null is a non-persisting store. It is used when persistence is not // activated. type Null struct { config *config.Delegations } func newNull(config *config.Delegations) (Store, error) { return &Null{config: config}, nil } func (n *Null) Blob() []byte { return nil } func (n *Null) Policy() string { return n.config.Policy } func (n *Null) Users() []string { return n.config.Users } func (n *Null) Store(bs []byte) error { return nil } func (n *Null) Load() error { return nil } func (n *Null) Persist() { return } func (n *Null) Status() *Status { return &Status{ State: Disabled, Summary: nil, } } func (n *Null) Delegate(record passvault.PasswordRecord, name, password string, users, labels []string, uses int, slot, durationString string) error { return errors.New("persist: null store does not support delegations") } func (n *Null) Cache() *keycache.Cache { cache := keycache.NewCache() return &cache } func (n *Null) Purge() error { return nil } ================================================ FILE: vendor/github.com/cloudflare/redoctober/persist/persist.go ================================================ // Package persist implements delegation persistence. It is primarily // concerned with configuration and serialisation; encryption and // decryption is done by the cryptor package. package persist import ( "errors" "github.com/cloudflare/redoctober/config" "github.com/cloudflare/redoctober/keycache" "github.com/cloudflare/redoctober/passvault" ) var defaultStore Store = &File{} // Labels are the labels that the keycache should be encrypted with. var Labels = []string{"restore"} // Usages indicate whether encrypted data can be decrypted or only used for signing var Usages = []string{} const ( // Disabled indicates that the persistence store will never // persist active delegations. Disabled = "disabled" // Inactive indicates that the persistence store requires // more delegations to unlock, and isn't currently persisting // the store. Inactive = "inactive" // Active indicates that the persistence store is // actively persisting delegations. Active = "active" ) // Status contains information on the current status of a persistence // store. type Status struct { State string `json:"state"` Summary map[string]keycache.ActiveUser } // Store is a persistence store interface that handles delegations, // serialising the persistence store, and writing the store to disk. type Store interface { Blob() []byte Policy() string Users() []string Store([]byte) error Load() error Status() *Status // Persist tells the Store to start actively persisting. Persist() Delegate(record passvault.PasswordRecord, name, password string, users, labels []string, uses int, slot, durationString string) error // This is not the main keycache. This is the keycache for // users that can decrypt the store. Cache() *keycache.Cache // Purge clears the persisted keys. Purge() error } // FileMechanism indicates that the persistence mechanism is a file. const FileMechanism = "file" type mechanism func(*config.Delegations) (Store, error) var stores = map[string]mechanism{ "": newNull, FileMechanism: newFile, } // New attempts to create a new persistence store from the // configuration. func New(config *config.Delegations) (Store, error) { if config == nil { return nil, errors.New("persist: nil configuration") } if !config.Persist { return newNull(config) } constructor, ok := stores[config.Mechanism] if !ok { return nil, errors.New("persist: invalid persistence mechanism") } return constructor(config) } // ErrInvalidConfig is returned when the configuration is invalid for // the type of persistence store in use. var ErrInvalidConfig = errors.New("persist: invalid configuration") ================================================ FILE: vendor/github.com/cloudflare/redoctober/report/report.go ================================================ // Package report contains error reporting functions. package report import ( "fmt" "time" "github.com/cloudflare/redoctober/config" "github.com/getsentry/sentry-go" ) // useSentry will be set to true if sentry reporting is valid. var useSentry bool // sentryTags contains additional tags that can be sent to Sentry. func configSentry(cfg *config.Config) { err := sentry.Init(sentry.ClientOptions{ Dsn: cfg.Reporting.SentryDSN, }) if err != nil { fmt.Printf("Sentry initialization failed: %v\n", err) return } useSentry = true var sentryTags = map[string]string{} sentryTags["started_at"] = fmt.Sprintf("%d", time.Now().Unix()) sentryTags["server.systemd"] = fmt.Sprintf("%v", cfg.Server.Systemd) if cfg.Server.Addr != "" { sentryTags["server.address"] = cfg.Server.Addr } sentryTags["metrics.host"] = cfg.Metrics.Host sentryTags["metrics.port"] = cfg.Metrics.Port if cfg.HipChat.ID != "" { sentryTags["hipchat.id"] = cfg.HipChat.ID } sentryTags["persist.enabled"] = fmt.Sprintf("%v", cfg.Delegations.Persist) if cfg.Delegations.Persist { sentryTags["persist.mechanism"] = cfg.Delegations.Mechanism sentryTags["persist.location"] = cfg.Delegations.Location } sentry.ConfigureScope(func(scope *sentry.Scope) { scope.SetTags(sentryTags) }) } func Init(cfg *config.Config) { if cfg.Reporting.SentryDSN != "" { configSentry(cfg) } } // Check will see if err contains an error; if it does, and if // reporting is configured, it will report the error. func Check(err error, tags map[string]string) { if err == nil { return } if tags == nil { tags = map[string]string{} } if useSentry { sentry.ConfigureScope(func(scope *sentry.Scope) { scope.SetTags(tags) }) sentry.CaptureException(err) } } // Recover will wrap the function in a manner that will capture // panics. If error reporting isn't active, it will just panic. This // default behaviour allows the stack trace to be capture in the // system logs and the service management system (e.g. systemd) to // automatically restart the server. func Recover(fn func()) { if useSentry { defer sentry.Recover() } fn() } ================================================ FILE: vendor/github.com/cloudflare/redoctober/symcrypt/symcrypt.go ================================================ // Package symcrypt contains common symmetric encryption functions. package symcrypt import ( "crypto/aes" "crypto/cipher" "crypto/rand" ) // DecryptCBC decrypt bytes using a key and IV with AES in CBC mode. func DecryptCBC(data, iv, key []byte) (decryptedData []byte, err error) { aesCrypt, err := aes.NewCipher(key) if err != nil { return } ivBytes := append([]byte{}, iv...) decryptedData = make([]byte, len(data)) aesCBC := cipher.NewCBCDecrypter(aesCrypt, ivBytes) aesCBC.CryptBlocks(decryptedData, data) return } // EncryptCBC encrypt data using a key and IV with AES in CBC mode. func EncryptCBC(data, iv, key []byte) (encryptedData []byte, err error) { aesCrypt, err := aes.NewCipher(key) if err != nil { return } ivBytes := append([]byte{}, iv...) encryptedData = make([]byte, len(data)) aesCBC := cipher.NewCBCEncrypter(aesCrypt, ivBytes) aesCBC.CryptBlocks(encryptedData, data) return } // MakeRandom is a helper that makes a new buffer full of random data. func MakeRandom(length int) ([]byte, error) { bytes := make([]byte, length) _, err := rand.Read(bytes) return bytes, err } ================================================ FILE: vendor/github.com/getsentry/sentry-go/.craft.yml ================================================ minVersion: '0.9.2' github: owner: getsentry repo: sentry-go preReleaseCommand: bash scripts/craft-pre-release.sh changelogPolicy: simple statusProvider: name: github artifactProvider: name: none targets: - name: github includeNames: /none/ tagPrefix: v - name: registry type: sdk config: canonical: "github:getsentry/sentry-go" ================================================ FILE: vendor/github.com/getsentry/sentry-go/.gitattributes ================================================ # Tell Git to use LF for line endings on all platforms. # Required to have correct test data on Windows. # https://github.com/mvdan/github-actions-golang#caveats # https://github.com/actions/checkout/issues/135#issuecomment-613361104 * text eol=lf ================================================ FILE: vendor/github.com/getsentry/sentry-go/.gitignore ================================================ coverage.txt # Just my personal way of tracking stuff — Kamil FIXME.md TODO.md !NOTES.md ================================================ FILE: vendor/github.com/getsentry/sentry-go/.golangci.yml ================================================ linters: disable-all: true enable: - bodyclose - deadcode - depguard - dogsled - dupl - errcheck - gochecknoinits - goconst - gocritic - gocyclo - godot - gofmt - goimports - golint - gosec - gosimple - govet - ineffassign - interfacer - maligned - misspell - nakedret - prealloc - scopelint - staticcheck - structcheck - typecheck - unconvert - unparam - unused - varcheck - whitespace issues: exclude-rules: - path: _test\.go linters: - prealloc - path: _test\.go text: "G306:" linters: - gosec - path: errors_test\.go linters: - unused - path: http/example_test\.go linters: - errcheck - bodyclose ================================================ FILE: vendor/github.com/getsentry/sentry-go/CHANGELOG.md ================================================ # Changelog ## v0.11.0 - feat(transports): Category-based Rate Limiting ([#354](https://github.com/getsentry/sentry-go/pull/354)) - feat(transports): Report User-Agent identifying SDK ([#357](https://github.com/getsentry/sentry-go/pull/357)) - fix(scope): Include event processors in clone ([#349](https://github.com/getsentry/sentry-go/pull/349)) - Improvements to `go doc` documentation ([#344](https://github.com/getsentry/sentry-go/pull/344), [#350](https://github.com/getsentry/sentry-go/pull/350), [#351](https://github.com/getsentry/sentry-go/pull/351)) - Miscellaneous changes to our testing infrastructure with GitHub Actions ([57123a40](https://github.com/getsentry/sentry-go/commit/57123a409be55f61b1d5a6da93c176c55a399ad0), [#128](https://github.com/getsentry/sentry-go/pull/128), [#338](https://github.com/getsentry/sentry-go/pull/338), [#345](https://github.com/getsentry/sentry-go/pull/345), [#346](https://github.com/getsentry/sentry-go/pull/346), [#352](https://github.com/getsentry/sentry-go/pull/352), [#353](https://github.com/getsentry/sentry-go/pull/353), [#355](https://github.com/getsentry/sentry-go/pull/355)) _NOTE:_ This version drops support for Go 1.13. The currently supported Go versions are the last 3 stable releases: 1.14, 1.15 and 1.16. Users of the tracing functionality (`StartSpan`, etc) should upgrade to this version to benefit from separate rate limits for errors and transactions. There are no breaking changes and upgrading should be a smooth experience for all users. ## v0.10.0 - feat: Debug connection reuse (#323) - fix: Send root span data as `Event.Extra` (#329) - fix: Do not double sample transactions (#328) - fix: Do not override trace context of transactions (#327) - fix: Drain and close API response bodies (#322) - ci: Run tests against Go tip (#319) - ci: Move away from Travis in favor of GitHub Actions (#314) (#321) ## v0.9.0 - feat: Initial tracing and performance monitoring support (#285) - doc: Revamp sentryhttp documentation (#304) - fix: Hub.PopScope never empties the scope stack (#300) - ref: Report Event.Timestamp in local time (#299) - ref: Report Breadcrumb.Timestamp in local time (#299) _NOTE:_ This version introduces support for [Sentry's Performance Monitoring](https://docs.sentry.io/platforms/go/performance/). The new tracing capabilities are beta, and we plan to expand them on future versions. Feedback is welcome, please open new issues on GitHub. The `sentryhttp` package got better API docs, an [updated usage example](https://github.com/getsentry/sentry-go/tree/master/example/http) and support for creating automatic transactions as part of Performance Monitoring. ## v0.8.0 - build: Bump required version of Iris (#296) - fix: avoid unnecessary allocation in Client.processEvent (#293) - doc: Remove deprecation of sentryhttp.HandleFunc (#284) - ref: Update sentryhttp example (#283) - doc: Improve documentation of sentryhttp package (#282) - doc: Clarify SampleRate documentation (#279) - fix: Remove RawStacktrace (#278) - docs: Add example of custom HTTP transport - ci: Test against go1.15, drop go1.12 support (#271) _NOTE:_ This version comes with a few updates. Some examples and documentation have been improved. We've bumped the supported version of the Iris framework to avoid LGPL-licensed modules in the module dependency graph. The `Exception.RawStacktrace` and `Thread.RawStacktrace` fields have been removed to conform to Sentry's ingestion protocol, only `Exception.Stacktrace` and `Thread.Stacktrace` should appear in user code. ## v0.7.0 - feat: Include original error when event cannot be encoded as JSON (#258) - feat: Use Hub from request context when available (#217, #259) - feat: Extract stack frames from golang.org/x/xerrors (#262) - feat: Make Environment Integration preserve existing context data (#261) - feat: Recover and RecoverWithContext with arbitrary types (#268) - feat: Report bad usage of CaptureMessage and CaptureEvent (#269) - feat: Send debug logging to stderr by default (#266) - feat: Several improvements to documentation (#223, #245, #250, #265) - feat: Example of Recover followed by panic (#241, #247) - feat: Add Transactions and Spans (to support OpenTelemetry Sentry Exporter) (#235, #243, #254) - fix: Set either Frame.Filename or Frame.AbsPath (#233) - fix: Clone requestBody to new Scope (#244) - fix: Synchronize access and mutation of Hub.lastEventID (#264) - fix: Avoid repeated syscalls in prepareEvent (#256) - fix: Do not allocate new RNG for every event (#256) - fix: Remove stale replace directive in go.mod (#255) - fix(http): Deprecate HandleFunc, remove duplication (#260) _NOTE:_ This version comes packed with several fixes and improvements and no breaking changes. Notably, there is a change in how the SDK reports file names in stack traces that should resolve any ambiguity when looking at stack traces and using the Suspect Commits feature. We recommend all users to upgrade. ## v0.6.1 - fix: Use NewEvent to init Event struct (#220) _NOTE:_ A change introduced in v0.6.0 with the intent of avoiding allocations made a pattern used in official examples break in certain circumstances (attempting to write to a nil map). This release reverts the change such that maps in the Event struct are always allocated. ## v0.6.0 - feat: Read module dependencies from runtime/debug (#199) - feat: Support chained errors using Unwrap (#206) - feat: Report chain of errors when available (#185) - **[breaking]** fix: Accept http.RoundTripper to customize transport (#205) Before the SDK accepted a concrete value of type `*http.Transport` in `ClientOptions`, now it accepts any value implementing the `http.RoundTripper` interface. Note that `*http.Transport` implements `http.RoundTripper`, so most code bases will continue to work unchanged. Users of custom transport gain the ability to pass in other implementations of `http.RoundTripper` and may be able to simplify their code bases. - fix: Do not panic when scope event processor drops event (#192) - **[breaking]** fix: Use time.Time for timestamps (#191) Users of sentry-go typically do not need to manipulate timestamps manually. For those who do, the field type changed from `int64` to `time.Time`, which should be more convenient to use. The recommended way to get the current time is `time.Now().UTC()`. - fix: Report usage error including stack trace (#189) - feat: Add Exception.ThreadID field (#183) - ci: Test against Go 1.14, drop 1.11 (#170) - feat: Limit reading bytes from request bodies (#168) - **[breaking]** fix: Rename fasthttp integration package sentryhttp => sentryfasthttp The current recommendation is to use a named import, in which case existing code should not require any change: ```go package main import ( "fmt" "github.com/getsentry/sentry-go" sentryfasthttp "github.com/getsentry/sentry-go/fasthttp" "github.com/valyala/fasthttp" ) ``` _NOTE:_ This version includes some new features and a few breaking changes, none of which should pose troubles with upgrading. Most code bases should be able to upgrade without any changes. ## v0.5.1 - fix: Ignore err.Cause() when it is nil (#160) ## v0.5.0 - fix: Synchronize access to HTTPTransport.disabledUntil (#158) - docs: Update Flush documentation (#153) - fix: HTTPTransport.Flush panic and data race (#140) _NOTE:_ This version changes the implementation of the default transport, modifying the behavior of `sentry.Flush`. The previous behavior was to wait until there were no buffered events; new concurrent events kept `Flush` from returning. The new behavior is to wait until the last event prior to the call to `Flush` has been sent or the timeout; new concurrent events have no effect. The new behavior is inline with the [Unified API Guidelines](https://docs.sentry.io/development/sdk-dev/unified-api/). We have updated the documentation and examples to clarify that `Flush` is meant to be called typically only once before program termination, to wait for in-flight events to be sent to Sentry. Calling `Flush` after every event is not recommended, as it introduces unnecessary latency to the surrounding function. Please verify the usage of `sentry.Flush` in your code base. ## v0.4.0 - fix(stacktrace): Correctly report package names (#127) - fix(stacktrace): Do not rely on AbsPath of files (#123) - build: Require github.com/ugorji/go@v1.1.7 (#110) - fix: Correctly store last event id (#99) - fix: Include request body in event payload (#94) - build: Reset go.mod version to 1.11 (#109) - fix: Eliminate data race in modules integration (#105) - feat: Add support for path prefixes in the DSN (#102) - feat: Add HTTPClient option (#86) - feat: Extract correct type and value from top-most error (#85) - feat: Check for broken pipe errors in Gin integration (#82) - fix: Client.CaptureMessage accept nil EventModifier (#72) ## v0.3.1 - feat: Send extra information exposed by the Go runtime (#76) - fix: Handle new lines in module integration (#65) - fix: Make sure that cache is locked when updating for contextifyFramesIntegration - ref: Update Iris integration and example to version 12 - misc: Remove indirect dependencies in order to move them to separate go.mod files ## v0.3.0 - feat: Retry event marshaling without contextual data if the first pass fails - fix: Include `url.Parse` error in `DsnParseError` - fix: Make more `Scope` methods safe for concurrency - fix: Synchronize concurrent access to `Hub.client` - ref: Remove mutex from `Scope` exported API - ref: Remove mutex from `Hub` exported API - ref: Compile regexps for `filterFrames` only once - ref: Change `SampleRate` type to `float64` - doc: `Scope.Clear` not safe for concurrent use - ci: Test sentry-go with `go1.13`, drop `go1.10` _NOTE:_ This version removes some of the internal APIs that landed publicly (namely `Hub/Scope` mutex structs) and may require (but shouldn't) some changes to your code. It's not done through major version update, as we are still in `0.x` stage. ## v0.2.1 - fix: Run `Contextify` integration on `Threads` as well ## v0.2.0 - feat: Add `SetTransaction()` method on the `Scope` - feat: `fasthttp` framework support with `sentryfasthttp` package - fix: Add `RWMutex` locks to internal `Hub` and `Scope` changes ## v0.1.3 - feat: Move frames context reading into `contextifyFramesIntegration` (#28) _NOTE:_ In case of any performance issues due to source contexts IO, you can let us know and turn off the integration in the meantime with: ```go sentry.Init(sentry.ClientOptions{ Integrations: func(integrations []sentry.Integration) []sentry.Integration { var filteredIntegrations []sentry.Integration for _, integration := range integrations { if integration.Name() == "ContextifyFrames" { continue } filteredIntegrations = append(filteredIntegrations, integration) } return filteredIntegrations }, }) ``` ## v0.1.2 - feat: Better source code location resolution and more useful inapp frames (#26) - feat: Use `noopTransport` when no `Dsn` provided (#27) - ref: Allow empty `Dsn` instead of returning an error (#22) - fix: Use `NewScope` instead of literal struct inside a `scope.Clear` call (#24) - fix: Add to `WaitGroup` before the request is put inside a buffer (#25) ## v0.1.1 - fix: Check for initialized `Client` in `AddBreadcrumbs` (#20) - build: Bump version when releasing with Craft (#19) ## v0.1.0 - First stable release! \o/ ## v0.0.1-beta.5 - feat: **[breaking]** Add `NewHTTPTransport` and `NewHTTPSyncTransport` which accepts all transport options - feat: New `HTTPSyncTransport` that blocks after each call - feat: New `Echo` integration - ref: **[breaking]** Remove `BufferSize` option from `ClientOptions` and move it to `HTTPTransport` instead - ref: Export default `HTTPTransport` - ref: Export `net/http` integration handler - ref: Set `Request` instantly in the package handlers, not in `recoverWithSentry` so it can be accessed later on - ci: Add craft config ## v0.0.1-beta.4 - feat: `IgnoreErrors` client option and corresponding integration - ref: Reworked `net/http` integration, wrote better example and complete readme - ref: Reworked `Gin` integration, wrote better example and complete readme - ref: Reworked `Iris` integration, wrote better example and complete readme - ref: Reworked `Negroni` integration, wrote better example and complete readme - ref: Reworked `Martini` integration, wrote better example and complete readme - ref: Remove `Handle()` from frameworks handlers and return it directly from New ## v0.0.1-beta.3 - feat: `Iris` framework support with `sentryiris` package - feat: `Gin` framework support with `sentrygin` package - feat: `Martini` framework support with `sentrymartini` package - feat: `Negroni` framework support with `sentrynegroni` package - feat: Add `Hub.Clone()` for easier frameworks integration - feat: Return `EventID` from `Recovery` methods - feat: Add `NewScope` and `NewEvent` functions and use them in the whole codebase - feat: Add `AddEventProcessor` to the `Client` - fix: Operate on requests body copy instead of the original - ref: Try to read source files from the root directory, based on the filename as well, to make it work on AWS Lambda - ref: Remove `gocertifi` dependence and document how to provide your own certificates - ref: **[breaking]** Remove `Decorate` and `DecorateFunc` methods in favor of `sentryhttp` package - ref: **[breaking]** Allow for integrations to live on the client, by passing client instance in `SetupOnce` method - ref: **[breaking]** Remove `GetIntegration` from the `Hub` - ref: **[breaking]** Remove `GlobalEventProcessors` getter from the public API ## v0.0.1-beta.2 - feat: Add `AttachStacktrace` client option to include stacktrace for messages - feat: Add `BufferSize` client option to configure transport buffer size - feat: Add `SetRequest` method on a `Scope` to control `Request` context data - feat: Add `FromHTTPRequest` for `Request` type for easier extraction - ref: Extract `Request` information more accurately - fix: Attach `ServerName`, `Release`, `Dist`, `Environment` options to the event - fix: Don't log events dropped due to full transport buffer as sent - fix: Don't panic and create an appropriate event when called `CaptureException` or `Recover` with `nil` value ## v0.0.1-beta - Initial release ================================================ FILE: vendor/github.com/getsentry/sentry-go/CONTRIBUTING.md ================================================ # Contributing to sentry-go Hey, thank you if you're reading this, we welcome your contribution! ## Sending a Pull Request Please help us save time when reviewing your PR by following this simple process: 1. Is your PR a simple typo fix? Read no further, **click that green "Create pull request" button**! 2. For more complex PRs that involve behavior changes or new APIs, please consider [opening an **issue**][new-issue] describing the problem you're trying to solve if there's not one already. A PR is often one specific solution to a problem and sometimes talking about the problem unfolds new possible solutions. Remember we will be responsible for maintaining the changes later. 3. Fixing a bug and changing a behavior? Please add automated tests to prevent future regression. 4. Practice writing good commit messages. We have [commit guidelines][commit-guide]. 5. We have [guidelines for PR submitters][pr-guide]. A short summary: - Good PR descriptions are very helpful and most of the time they include **why** something is done and why done in this particular way. Also list other possible solutions that were considered and discarded. - Be your own first reviewer. Make sure your code compiles and passes the existing tests. [new-issue]: https://github.com/getsentry/sentry-go/issues/new/choose [commit-guide]: https://develop.sentry.dev/code-review/#commit-guidelines [pr-guide]: https://develop.sentry.dev/code-review/#guidelines-for-submitters Please also read through our [SDK Development docs](https://develop.sentry.dev/sdk/). It contains information about SDK features, expected payloads and best practices for contributing to Sentry SDKs. ## Community The public-facing channels for support and development of Sentry SDKs can be found on [Discord](https://discord.gg/Ww9hbqr). ## Testing ```console $ go test ``` ### Watch mode Use: https://github.com/cespare/reflex ```console $ reflex -g '*.go' -d "none" -- sh -c 'printf "\n"; go test' ``` ### With data race detection ```console $ go test -race ``` ### Coverage ```console $ go test -race -coverprofile=coverage.txt -covermode=atomic && go tool cover -html coverage.txt ``` ## Linting ```console $ golangci-lint run ``` ## Release 1. Update `CHANGELOG.md` with new version in `vX.X.X` format title and list of changes. The command below can be used to get a list of changes since the last tag, with the format used in `CHANGELOG.md`: ```console $ git log --no-merges --format=%s $(git describe --abbrev=0).. | sed 's/^/- /' ``` 2. Commit with `misc: vX.X.X changelog` commit message and push to `master`. 3. Let [`craft`](https://github.com/getsentry/craft) do the rest: ```console $ craft prepare X.X.X $ craft publish X.X.X ``` ================================================ FILE: vendor/github.com/getsentry/sentry-go/LICENSE ================================================ Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: vendor/github.com/getsentry/sentry-go/MIGRATION.md ================================================ # `raven-go` to `sentry-go` Migration Guide ## Installation raven-go ```go go get github.com/getsentry/raven-go ``` sentry-go ```go go get github.com/getsentry/sentry-go@v0.0.1 ``` ## Configuration raven-go ```go import "github.com/getsentry/raven-go" func main() { raven.SetDSN("___PUBLIC_DSN___") } ``` sentry-go ```go import ( "fmt" "github.com/getsentry/sentry-go" ) func main() { err := sentry.Init(sentry.ClientOptions{ Dsn: "___PUBLIC_DSN___", }) if err != nil { fmt.Printf("Sentry initialization failed: %v\n", err) } } ``` raven-go ```go SetDSN() SetDefaultLoggerName() SetDebug() SetEnvironment() SetRelease() SetSampleRate() SetIgnoreErrors() SetIncludePaths() ``` sentry-go ```go sentry.Init(sentry.ClientOptions{ Dsn: "___PUBLIC_DSN___", DebugWriter: os.Stderr, Debug: true, Environment: "environment", Release: "release", SampleRate: 0.5, // IgnoreErrors: TBD, // IncludePaths: TBD }) ``` Available options: see [Configuration](https://docs.sentry.io/platforms/go/config/) section. ### Providing SSL Certificates By default, TLS uses the host's root CA set. If you don't have `ca-certificates` (which should be your go-to way of fixing the issue of missing certificates) and want to use `gocertifi` instead, you can provide pre-loaded cert files as one of the options to the `sentry.Init` call: ```go package main import ( "log" "github.com/certifi/gocertifi" "github.com/getsentry/sentry-go" ) sentryClientOptions := sentry.ClientOptions{ Dsn: "___PUBLIC_DSN___", } rootCAs, err := gocertifi.CACerts() if err != nil { log.Println("Couldn't load CA Certificates: %v\n", err) } else { sentryClientOptions.CaCerts = rootCAs } sentry.Init(sentryClientOptions) ``` ## Usage ### Capturing Errors raven-go ```go f, err := os.Open("filename.ext") if err != nil { raven.CaptureError(err, nil) } ``` sentry-go ```go f, err := os.Open("filename.ext") if err != nil { sentry.CaptureException(err) } ``` ### Capturing Panics raven-go ```go raven.CapturePanic(func() { // do all of the scary things here }, nil) ``` sentry-go ```go func() { defer sentry.Recover() // do all of the scary things here }() ``` ### Capturing Messages raven-go ```go raven.CaptureMessage("Something bad happened and I would like to know about that") ``` sentry-go ```go sentry.CaptureMessage("Something bad happened and I would like to know about that") ``` ### Capturing Events raven-go ```go packet := &raven.Packet{ Message: "Hand-crafted event", Extra: &raven.Extra{ "runtime.Version": runtime.Version(), "runtime.NumCPU": runtime.NumCPU(), }, } raven.Capture(packet) ``` sentry-go ```go event := &sentry.NewEvent() event.Message = "Hand-crafted event" event.Extra["runtime.Version"] = runtime.Version() event.Extra["runtime.NumCPU"] = runtime.NumCPU() sentry.CaptureEvent(event) ``` ### Additional Data See Context section. ### Event Sampling raven-go ```go raven.SetSampleRate(0.25) ``` sentry-go ```go sentry.Init(sentry.ClientOptions{ SampleRate: 0.25, }) ``` ### Awaiting the response (not recommended) ```go raven.CaptureMessageAndWait("Something bad happened and I would like to know about that") ``` sentry-go ```go sentry.CaptureMessage("Something bad happened and I would like to know about that") if sentry.Flush(time.Second * 2) { // event delivered } else { // timeout reached } ``` ## Context ### Per-event raven-go ```go raven.CaptureError(err, map[string]string{"browser": "Firefox"}, &raven.Http{ Method: "GET", URL: "https://example.com/raven-go" }) ``` sentry-go ```go sentry.WithScope(func(scope *sentry.Scope) { scope.SetTag("browser", "Firefox") scope.SetContext("Request", map[string]string{ "Method": "GET", "URL": "https://example.com/raven-go", }) sentry.CaptureException(err) }) ``` ### Globally #### SetHttpContext raven-go ```go raven.SetHttpContext(&raven.Http{ Method: "GET", URL: "https://example.com/raven-go", }) ``` sentry-go ```go sentry.ConfigureScope(func(scope *sentry.Scope) { scope.SetContext("Request", map[string]string{ "Method": "GET", "URL": "https://example.com/raven-go", }) }) ``` #### SetTagsContext raven-go ```go t := map[string]string{"day": "Friday", "sport": "Weightlifting"} raven.SetTagsContext(map[string]string{"day": "Friday", "sport": "Weightlifting"}) ``` sentry-go ```go sentry.ConfigureScope(func(scope *sentry.Scope) { scope.SetTags(map[string]string{"day": "Friday", "sport": "Weightlifting"}) }) ``` #### SetUserContext raven-go ```go raven.SetUserContext(&raven.User{ ID: "1337", Username: "kamilogorek", Email: "kamil@sentry.io", IP: "127.0.0.1", }) ``` sentry-go ```go sentry.ConfigureScope(func(scope *sentry.Scope) { scope.SetUser(sentry.User{ ID: "1337", Username: "kamilogorek", Email: "kamil@sentry.io", IPAddress: "127.0.0.1", }) }) ``` #### ClearContext raven-go ```go raven.ClearContext() ``` sentry-go ```go sentry.ConfigureScope(func(scope *sentry.Scope) { scope.Clear() }) ``` #### WrapWithExtra raven-go ```go path := "filename.ext" f, err := os.Open(path) if err != nil { err = raven.WrapWithExtra(err, map[string]string{"path": path, "cwd": os.Getwd()} raven.CaptureError(err, nil) } ``` sentry-go ```go // use `sentry.WithScope`, see "Context / Per-event Section" path := "filename.ext" f, err := os.Open(path) if err != nil { sentry.WithScope(func(scope *sentry.Scope) { sentry.SetExtras(map[string]interface{}{"path": path, "cwd": os.Getwd()) sentry.CaptureException(err) }) } ``` ## Integrations ### net/http raven-go ```go mux := http.NewServeMux http.Handle("/", raven.Recoverer(mux)) // or func root(w http.ResponseWriter, r *http.Request) {} http.HandleFunc("/", raven.RecoveryHandler(root)) ``` sentry-go ```go sentryHandler := sentryhttp.New(sentryhttp.Options{ Repanic: false, WaitForDelivery: true, }) mux := http.NewServeMux http.Handle("/", sentryHandler.Handle(mux)) // or func root(w http.ResponseWriter, r *http.Request) {} http.HandleFunc("/", sentryHandler.HandleFunc(root)) ``` ================================================ FILE: vendor/github.com/getsentry/sentry-go/README.md ================================================


# Official Sentry SDK for Go [![Build Status](https://github.com/getsentry/sentry-go/workflows/go-workflow/badge.svg)](https://github.com/getsentry/sentry-go/actions?query=workflow%3Ago-workflow) [![Go Report Card](https://goreportcard.com/badge/github.com/getsentry/sentry-go)](https://goreportcard.com/report/github.com/getsentry/sentry-go) [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) [![GoDoc](https://godoc.org/github.com/getsentry/sentry-go?status.svg)](https://godoc.org/github.com/getsentry/sentry-go) [![go.dev](https://img.shields.io/badge/go.dev-pkg-007d9c.svg?style=flat)](https://pkg.go.dev/github.com/getsentry/sentry-go) `sentry-go` provides a Sentry client implementation for the Go programming language. This is the next line of the Go SDK for [Sentry](https://sentry.io/), intended to replace the `raven-go` package. > Looking for the old `raven-go` SDK documentation? See the Legacy client section [here](https://docs.sentry.io/clients/go/). > If you want to start using sentry-go instead, check out the [migration guide](https://docs.sentry.io/platforms/go/migration/). ## Requirements The only requirement is a Go compiler. We verify this package against the 3 most recent releases of Go. Those are the supported versions. The exact versions are defined in [`GitHub workflow`](.github/workflows/ci.yml). In addition, we run tests against the current master branch of the Go toolchain, though support for this configuration is best-effort. ## Installation `sentry-go` can be installed like any other Go library through `go get`: ```console $ go get github.com/getsentry/sentry-go ``` Or, if you are already using [Go Modules](https://github.com/golang/go/wiki/Modules), you may specify a version number as well: ```console $ go get github.com/getsentry/sentry-go@latest ``` Check out the [list of released versions](https://pkg.go.dev/github.com/getsentry/sentry-go?tab=versions). ## Configuration To use `sentry-go`, you’ll need to import the `sentry-go` package and initialize it with your DSN and other [options](https://pkg.go.dev/github.com/getsentry/sentry-go#ClientOptions). If not specified in the SDK initialization, the [DSN](https://docs.sentry.io/product/sentry-basics/dsn-explainer/), [Release](https://docs.sentry.io/product/releases/) and [Environment](https://docs.sentry.io/product/sentry-basics/environments/) are read from the environment variables `SENTRY_DSN`, `SENTRY_RELEASE` and `SENTRY_ENVIRONMENT`, respectively. More on this in the [Configuration section of the official Sentry Go SDK documentation](https://docs.sentry.io/platforms/go/configuration/). ## Usage The SDK supports reporting errors and tracking application performance. To get started, have a look at one of our [examples](example/): - [Basic error instrumentation](example/basic/main.go) - [Error and tracing for HTTP servers](example/http/main.go) We also provide a [complete API reference](https://pkg.go.dev/github.com/getsentry/sentry-go). For more detailed information about how to get the most out of `sentry-go`, checkout the official documentation: - [Sentry Go SDK documentation](https://docs.sentry.io/platforms/go/) - Guides: - [net/http](https://docs.sentry.io/platforms/go/guides/http/) - [echo](https://docs.sentry.io/platforms/go/guides/echo/) - [fasthttp](https://docs.sentry.io/platforms/go/guides/fasthttp/) - [gin](https://docs.sentry.io/platforms/go/guides/gin/) - [iris](https://docs.sentry.io/platforms/go/guides/iris/) - [martini](https://docs.sentry.io/platforms/go/guides/martini/) - [negroni](https://docs.sentry.io/platforms/go/guides/negroni/) ## Resources - [Bug Tracker](https://github.com/getsentry/sentry-go/issues) - [GitHub Project](https://github.com/getsentry/sentry-go) - [![GoDoc](https://godoc.org/github.com/getsentry/sentry-go?status.svg)](https://godoc.org/github.com/getsentry/sentry-go) - [![go.dev](https://img.shields.io/badge/go.dev-pkg-007d9c.svg?style=flat)](https://pkg.go.dev/github.com/getsentry/sentry-go) - [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/go/) - [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks) - [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) - [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](http://stackoverflow.com/questions/tagged/sentry) - [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) ## License Licensed under [The 2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause), see [`LICENSE`](LICENSE). ## Community Join Sentry's [`#go` channel on Discord](https://discord.gg/Ww9hbqr) to get involved and help us improve the SDK! ================================================ FILE: vendor/github.com/getsentry/sentry-go/client.go ================================================ package sentry import ( "context" "crypto/x509" "errors" "fmt" "io" "io/ioutil" "log" "math/rand" "net/http" "os" "reflect" "sort" "strings" "sync" "time" "github.com/getsentry/sentry-go/internal/debug" ) // maxErrorDepth is the maximum number of errors reported in a chain of errors. // This protects the SDK from an arbitrarily long chain of wrapped errors. // // An additional consideration is that arguably reporting a long chain of errors // is of little use when debugging production errors with Sentry. The Sentry UI // is not optimized for long chains either. The top-level error together with a // stack trace is often the most useful information. const maxErrorDepth = 10 // hostname is the host name reported by the kernel. It is precomputed once to // avoid syscalls when capturing events. // // The error is ignored because retrieving the host name is best-effort. If the // error is non-nil, there is nothing to do other than retrying. We choose not // to retry for now. var hostname, _ = os.Hostname() // lockedRand is a random number generator safe for concurrent use. Its API is // intentionally limited and it is not meant as a full replacement for a // rand.Rand. type lockedRand struct { mu sync.Mutex r *rand.Rand } // Float64 returns a pseudo-random number in [0.0,1.0). func (r *lockedRand) Float64() float64 { r.mu.Lock() defer r.mu.Unlock() return r.r.Float64() } // rng is the internal random number generator. // // We do not use the global functions from math/rand because, while they are // safe for concurrent use, any package in a build could change the seed and // affect the generated numbers, for instance making them deterministic. On the // other hand, the source returned from rand.NewSource is not safe for // concurrent use, so we need to couple its use with a sync.Mutex. var rng = &lockedRand{ r: rand.New(rand.NewSource(time.Now().UnixNano())), } // usageError is used to report to Sentry an SDK usage error. // // It is not exported because it is never returned by any function or method in // the exported API. type usageError struct { error } // Logger is an instance of log.Logger that is use to provide debug information about running Sentry Client // can be enabled by either using Logger.SetOutput directly or with Debug client option. var Logger = log.New(ioutil.Discard, "[Sentry] ", log.LstdFlags) // EventProcessor is a function that processes an event. // Event processors are used to change an event before it is sent to Sentry. type EventProcessor func(event *Event, hint *EventHint) *Event // EventModifier is the interface that wraps the ApplyToEvent method. // // ApplyToEvent changes an event based on external data and/or // an event hint. type EventModifier interface { ApplyToEvent(event *Event, hint *EventHint) *Event } var globalEventProcessors []EventProcessor // AddGlobalEventProcessor adds processor to the global list of event // processors. Global event processors apply to all events. // // AddGlobalEventProcessor is deprecated. Most users will prefer to initialize // the SDK with Init and provide a ClientOptions.BeforeSend function or use // Scope.AddEventProcessor instead. func AddGlobalEventProcessor(processor EventProcessor) { globalEventProcessors = append(globalEventProcessors, processor) } // Integration allows for registering a functions that modify or discard captured events. type Integration interface { Name() string SetupOnce(client *Client) } // ClientOptions that configures a SDK Client. type ClientOptions struct { // The DSN to use. If the DSN is not set, the client is effectively // disabled. Dsn string // In debug mode, the debug information is printed to stdout to help you // understand what sentry is doing. Debug bool // Configures whether SDK should generate and attach stacktraces to pure // capture message calls. AttachStacktrace bool // The sample rate for event submission in the range [0.0, 1.0]. By default, // all events are sent. Thus, as a historical special case, the sample rate // 0.0 is treated as if it was 1.0. To drop all events, set the DSN to the // empty string. SampleRate float64 // The sample rate for sampling traces in the range [0.0, 1.0]. TracesSampleRate float64 // Used to customize the sampling of traces, overrides TracesSampleRate. TracesSampler TracesSampler // List of regexp strings that will be used to match against event's message // and if applicable, caught errors type and value. // If the match is found, then a whole event will be dropped. IgnoreErrors []string // BeforeSend is called before error events are sent to Sentry. // Use it to mutate the event or return nil to discard the event. // See EventProcessor if you need to mutate transactions. BeforeSend func(event *Event, hint *EventHint) *Event // Before breadcrumb add callback. BeforeBreadcrumb func(breadcrumb *Breadcrumb, hint *BreadcrumbHint) *Breadcrumb // Integrations to be installed on the current Client, receives default // integrations. Integrations func([]Integration) []Integration // io.Writer implementation that should be used with the Debug mode. DebugWriter io.Writer // The transport to use. Defaults to HTTPTransport. Transport Transport // The server name to be reported. ServerName string // The release to be sent with events. Release string // The dist to be sent with events. Dist string // The environment to be sent with events. Environment string // Maximum number of breadcrumbs. MaxBreadcrumbs int // An optional pointer to http.Client that will be used with a default // HTTPTransport. Using your own client will make HTTPTransport, HTTPProxy, // HTTPSProxy and CaCerts options ignored. HTTPClient *http.Client // An optional pointer to http.Transport that will be used with a default // HTTPTransport. Using your own transport will make HTTPProxy, HTTPSProxy // and CaCerts options ignored. HTTPTransport http.RoundTripper // An optional HTTP proxy to use. // This will default to the HTTP_PROXY environment variable. HTTPProxy string // An optional HTTPS proxy to use. // This will default to the HTTPS_PROXY environment variable. // HTTPS_PROXY takes precedence over HTTP_PROXY for https requests. HTTPSProxy string // An optional set of SSL certificates to use. CaCerts *x509.CertPool } // Client is the underlying processor that is used by the main API and Hub // instances. It must be created with NewClient. type Client struct { options ClientOptions dsn *Dsn eventProcessors []EventProcessor integrations []Integration // Transport is read-only. Replacing the transport of an existing client is // not supported, create a new client instead. Transport Transport } // NewClient creates and returns an instance of Client configured using // ClientOptions. // // Most users will not create clients directly. Instead, initialize the SDK with // Init and use the package-level functions (for simple programs that run on a // single goroutine) or hub methods (for concurrent programs, for example web // servers). func NewClient(options ClientOptions) (*Client, error) { if options.TracesSampleRate != 0.0 && options.TracesSampler != nil { return nil, errors.New("TracesSampleRate and TracesSampler are mutually exclusive") } if options.Debug { debugWriter := options.DebugWriter if debugWriter == nil { debugWriter = os.Stderr } Logger.SetOutput(debugWriter) } if options.Dsn == "" { options.Dsn = os.Getenv("SENTRY_DSN") } if options.Release == "" { options.Release = os.Getenv("SENTRY_RELEASE") } if options.Environment == "" { options.Environment = os.Getenv("SENTRY_ENVIRONMENT") } // SENTRYGODEBUG is a comma-separated list of key=value pairs (similar // to GODEBUG). It is not a supported feature: recognized debug options // may change any time. // // The intended public is SDK developers. It is orthogonal to // options.Debug, which is also available for SDK users. dbg := strings.Split(os.Getenv("SENTRYGODEBUG"), ",") sort.Strings(dbg) // dbgOpt returns true when the given debug option is enabled, for // example SENTRYGODEBUG=someopt=1. dbgOpt := func(opt string) bool { s := opt + "=1" return dbg[sort.SearchStrings(dbg, s)%len(dbg)] == s } if dbgOpt("httpdump") || dbgOpt("httptrace") { options.HTTPTransport = &debug.Transport{ RoundTripper: http.DefaultTransport, Output: os.Stderr, Dump: dbgOpt("httpdump"), Trace: dbgOpt("httptrace"), } } var dsn *Dsn if options.Dsn != "" { var err error dsn, err = NewDsn(options.Dsn) if err != nil { return nil, err } } client := Client{ options: options, dsn: dsn, } client.setupTransport() client.setupIntegrations() return &client, nil } func (client *Client) setupTransport() { opts := client.options transport := opts.Transport if transport == nil { if opts.Dsn == "" { transport = new(noopTransport) } else { httpTransport := NewHTTPTransport() // When tracing is enabled, use larger buffer to // accommodate more concurrent events. // TODO(tracing): consider using separate buffers per // event type. if opts.TracesSampleRate != 0 || opts.TracesSampler != nil { httpTransport.BufferSize = 1000 } transport = httpTransport } } transport.Configure(opts) client.Transport = transport } func (client *Client) setupIntegrations() { integrations := []Integration{ new(contextifyFramesIntegration), new(environmentIntegration), new(modulesIntegration), new(ignoreErrorsIntegration), } if client.options.Integrations != nil { integrations = client.options.Integrations(integrations) } for _, integration := range integrations { if client.integrationAlreadyInstalled(integration.Name()) { Logger.Printf("Integration %s is already installed\n", integration.Name()) continue } client.integrations = append(client.integrations, integration) integration.SetupOnce(client) Logger.Printf("Integration installed: %s\n", integration.Name()) } } // AddEventProcessor adds an event processor to the client. It must not be // called from concurrent goroutines. Most users will prefer to use // ClientOptions.BeforeSend or Scope.AddEventProcessor instead. // // Note that typical programs have only a single client created by Init and the // client is shared among multiple hubs, one per goroutine, such that adding an // event processor to the client affects all hubs that share the client. func (client *Client) AddEventProcessor(processor EventProcessor) { client.eventProcessors = append(client.eventProcessors, processor) } // Options return ClientOptions for the current Client. func (client Client) Options() ClientOptions { return client.options } // CaptureMessage captures an arbitrary message. func (client *Client) CaptureMessage(message string, hint *EventHint, scope EventModifier) *EventID { event := client.eventFromMessage(message, LevelInfo) return client.CaptureEvent(event, hint, scope) } // CaptureException captures an error. func (client *Client) CaptureException(exception error, hint *EventHint, scope EventModifier) *EventID { event := client.eventFromException(exception, LevelError) return client.CaptureEvent(event, hint, scope) } // CaptureEvent captures an event on the currently active client if any. // // The event must already be assembled. Typically code would instead use // the utility methods like CaptureException. The return value is the // event ID. In case Sentry is disabled or event was dropped, the return value will be nil. func (client *Client) CaptureEvent(event *Event, hint *EventHint, scope EventModifier) *EventID { return client.processEvent(event, hint, scope) } // Recover captures a panic. // Returns EventID if successfully, or nil if there's no error to recover from. func (client *Client) Recover(err interface{}, hint *EventHint, scope EventModifier) *EventID { if err == nil { err = recover() } // Normally we would not pass a nil Context, but RecoverWithContext doesn't // use the Context for communicating deadline nor cancelation. All it does // is store the Context in the EventHint and there nil means the Context is // not available. //nolint: staticcheck return client.RecoverWithContext(nil, err, hint, scope) } // RecoverWithContext captures a panic and passes relevant context object. // Returns EventID if successfully, or nil if there's no error to recover from. func (client *Client) RecoverWithContext( ctx context.Context, err interface{}, hint *EventHint, scope EventModifier, ) *EventID { if err == nil { err = recover() } if err == nil { return nil } if ctx != nil { if hint == nil { hint = &EventHint{} } if hint.Context == nil { hint.Context = ctx } } var event *Event switch err := err.(type) { case error: event = client.eventFromException(err, LevelFatal) case string: event = client.eventFromMessage(err, LevelFatal) default: event = client.eventFromMessage(fmt.Sprintf("%#v", err), LevelFatal) } return client.CaptureEvent(event, hint, scope) } // Flush waits until the underlying Transport sends any buffered events to the // Sentry server, blocking for at most the given timeout. It returns false if // the timeout was reached. In that case, some events may not have been sent. // // Flush should be called before terminating the program to avoid // unintentionally dropping events. // // Do not call Flush indiscriminately after every call to CaptureEvent, // CaptureException or CaptureMessage. Instead, to have the SDK send events over // the network synchronously, configure it to use the HTTPSyncTransport in the // call to Init. func (client *Client) Flush(timeout time.Duration) bool { return client.Transport.Flush(timeout) } func (client *Client) eventFromMessage(message string, level Level) *Event { if message == "" { err := usageError{fmt.Errorf("%s called with empty message", callerFunctionName())} return client.eventFromException(err, level) } event := NewEvent() event.Level = level event.Message = message if client.Options().AttachStacktrace { event.Threads = []Thread{{ Stacktrace: NewStacktrace(), Crashed: false, Current: true, }} } return event } func (client *Client) eventFromException(exception error, level Level) *Event { err := exception if err == nil { err = usageError{fmt.Errorf("%s called with nil error", callerFunctionName())} } event := NewEvent() event.Level = level for i := 0; i < maxErrorDepth && err != nil; i++ { event.Exception = append(event.Exception, Exception{ Value: err.Error(), Type: reflect.TypeOf(err).String(), Stacktrace: ExtractStacktrace(err), }) switch previous := err.(type) { case interface{ Unwrap() error }: err = previous.Unwrap() case interface{ Cause() error }: err = previous.Cause() default: err = nil } } // Add a trace of the current stack to the most recent error in a chain if // it doesn't have a stack trace yet. // We only add to the most recent error to avoid duplication and because the // current stack is most likely unrelated to errors deeper in the chain. if event.Exception[0].Stacktrace == nil { event.Exception[0].Stacktrace = NewStacktrace() } // event.Exception should be sorted such that the most recent error is last. reverse(event.Exception) return event } // reverse reverses the slice a in place. func reverse(a []Exception) { for i := len(a)/2 - 1; i >= 0; i-- { opp := len(a) - 1 - i a[i], a[opp] = a[opp], a[i] } } func (client *Client) processEvent(event *Event, hint *EventHint, scope EventModifier) *EventID { if event == nil { err := usageError{fmt.Errorf("%s called with nil event", callerFunctionName())} return client.CaptureException(err, hint, scope) } options := client.Options() // The default error event sample rate for all SDKs is 1.0 (send all). // // In Go, the zero value (default) for float64 is 0.0, which means that // constructing a client with NewClient(ClientOptions{}), or, equivalently, // initializing the SDK with Init(ClientOptions{}) without an explicit // SampleRate would drop all events. // // To retain the desired default behavior, we exceptionally flip SampleRate // from 0.0 to 1.0 here. Setting the sample rate to 0.0 is not very useful // anyway, and the same end result can be achieved in many other ways like // not initializing the SDK, setting the DSN to the empty string or using an // event processor that always returns nil. // // An alternative API could be such that default options don't need to be // the same as Go's zero values, for example using the Functional Options // pattern. That would either require a breaking change if we want to reuse // the obvious NewClient name, or a new function as an alternative // constructor. if options.SampleRate == 0.0 { options.SampleRate = 1.0 } // Transactions are sampled by options.TracesSampleRate or // options.TracesSampler when they are started. All other events // (errors, messages) are sampled here. if event.Type != transactionType && !sample(options.SampleRate) { Logger.Println("Event dropped due to SampleRate hit.") return nil } if event = client.prepareEvent(event, hint, scope); event == nil { return nil } // As per spec, transactions do not go through BeforeSend. if event.Type != transactionType && options.BeforeSend != nil { if hint == nil { hint = &EventHint{} } if event = options.BeforeSend(event, hint); event == nil { Logger.Println("Event dropped due to BeforeSend callback.") return nil } } client.Transport.SendEvent(event) return &event.EventID } func (client *Client) prepareEvent(event *Event, hint *EventHint, scope EventModifier) *Event { if event.EventID == "" { event.EventID = EventID(uuid()) } if event.Timestamp.IsZero() { event.Timestamp = time.Now() } if event.Level == "" { event.Level = LevelInfo } if event.ServerName == "" { if client.Options().ServerName != "" { event.ServerName = client.Options().ServerName } else { event.ServerName = hostname } } if event.Release == "" && client.Options().Release != "" { event.Release = client.Options().Release } if event.Dist == "" && client.Options().Dist != "" { event.Dist = client.Options().Dist } if event.Environment == "" && client.Options().Environment != "" { event.Environment = client.Options().Environment } event.Platform = "go" event.Sdk = SdkInfo{ Name: "sentry.go", Version: Version, Integrations: client.listIntegrations(), Packages: []SdkPackage{{ Name: "sentry-go", Version: Version, }}, } if scope != nil { event = scope.ApplyToEvent(event, hint) if event == nil { return nil } } for _, processor := range client.eventProcessors { id := event.EventID event = processor(event, hint) if event == nil { Logger.Printf("Event dropped by one of the Client EventProcessors: %s\n", id) return nil } } for _, processor := range globalEventProcessors { id := event.EventID event = processor(event, hint) if event == nil { Logger.Printf("Event dropped by one of the Global EventProcessors: %s\n", id) return nil } } return event } func (client Client) listIntegrations() []string { integrations := make([]string, 0, len(client.integrations)) for _, integration := range client.integrations { integrations = append(integrations, integration.Name()) } sort.Strings(integrations) return integrations } func (client Client) integrationAlreadyInstalled(name string) bool { for _, integration := range client.integrations { if integration.Name() == name { return true } } return false } // sample returns true with the given probability, which must be in the range // [0.0, 1.0]. func sample(probability float64) bool { return rng.Float64() < probability } ================================================ FILE: vendor/github.com/getsentry/sentry-go/doc.go ================================================ /* Package sentry is the official Sentry SDK for Go. Use it to report errors and track application performance through distributed tracing. For more information about Sentry and SDK features please have a look at the documentation site https://docs.sentry.io/platforms/go/. Basic Usage The first step is to initialize the SDK, providing at a minimum the DSN of your Sentry project. This step is accomplished through a call to sentry.Init. func main() { err := sentry.Init(...) ... } A more detailed yet simple example is available at https://github.com/getsentry/sentry-go/blob/master/example/basic/main.go. Error Reporting The Capture* functions report messages and errors to Sentry. sentry.CaptureMessage(...) sentry.CaptureException(...) sentry.CaptureEvent(...) Use similarly named functions in the Hub for concurrent programs like web servers. Performance Monitoring You can use Sentry to monitor your application's performance. More information on the product page https://docs.sentry.io/product/performance/. The StartSpan function creates new spans. span := sentry.StartSpan(ctx, "operation") ... span.Finish() Integrations The SDK has support for several Go frameworks, available as subpackages. Getting Support For paid Sentry.io accounts, head out to https://sentry.io/support. For all users, support channels include: Forum: https://forum.sentry.io Discord: https://discord.gg/Ww9hbqr (#go channel) If you found an issue with the SDK, please report through https://github.com/getsentry/sentry-go/issues/new/choose. For responsibly disclosing a security issue, please follow the steps in https://sentry.io/security/#vulnerability-disclosure. */ package sentry ================================================ FILE: vendor/github.com/getsentry/sentry-go/dsn.go ================================================ package sentry import ( "encoding/json" "fmt" "net/url" "strconv" "strings" "time" ) type scheme string const ( schemeHTTP scheme = "http" schemeHTTPS scheme = "https" ) func (scheme scheme) defaultPort() int { switch scheme { case schemeHTTPS: return 443 case schemeHTTP: return 80 default: return 80 } } // DsnParseError represents an error that occurs if a Sentry // DSN cannot be parsed. type DsnParseError struct { Message string } func (e DsnParseError) Error() string { return "[Sentry] DsnParseError: " + e.Message } // Dsn is used as the remote address source to client transport. type Dsn struct { scheme scheme publicKey string secretKey string host string port int path string projectID int } // NewDsn creates a Dsn by parsing rawURL. Most users will never call this // function directly. It is provided for use in custom Transport // implementations. func NewDsn(rawURL string) (*Dsn, error) { // Parse parsedURL, err := url.Parse(rawURL) if err != nil { return nil, &DsnParseError{fmt.Sprintf("invalid url: %v", err)} } // Scheme var scheme scheme switch parsedURL.Scheme { case "http": scheme = schemeHTTP case "https": scheme = schemeHTTPS default: return nil, &DsnParseError{"invalid scheme"} } // PublicKey publicKey := parsedURL.User.Username() if publicKey == "" { return nil, &DsnParseError{"empty username"} } // SecretKey var secretKey string if parsedSecretKey, ok := parsedURL.User.Password(); ok { secretKey = parsedSecretKey } // Host host := parsedURL.Hostname() if host == "" { return nil, &DsnParseError{"empty host"} } // Port var port int if parsedURL.Port() != "" { parsedPort, err := strconv.Atoi(parsedURL.Port()) if err != nil { return nil, &DsnParseError{"invalid port"} } port = parsedPort } else { port = scheme.defaultPort() } // ProjectID if parsedURL.Path == "" || parsedURL.Path == "/" { return nil, &DsnParseError{"empty project id"} } pathSegments := strings.Split(parsedURL.Path[1:], "/") projectID, err := strconv.Atoi(pathSegments[len(pathSegments)-1]) if err != nil { return nil, &DsnParseError{"invalid project id"} } // Path var path string if len(pathSegments) > 1 { path = "/" + strings.Join(pathSegments[0:len(pathSegments)-1], "/") } return &Dsn{ scheme: scheme, publicKey: publicKey, secretKey: secretKey, host: host, port: port, path: path, projectID: projectID, }, nil } // String formats Dsn struct into a valid string url. func (dsn Dsn) String() string { var url string url += fmt.Sprintf("%s://%s", dsn.scheme, dsn.publicKey) if dsn.secretKey != "" { url += fmt.Sprintf(":%s", dsn.secretKey) } url += fmt.Sprintf("@%s", dsn.host) if dsn.port != dsn.scheme.defaultPort() { url += fmt.Sprintf(":%d", dsn.port) } if dsn.path != "" { url += dsn.path } url += fmt.Sprintf("/%d", dsn.projectID) return url } // StoreAPIURL returns the URL of the store endpoint of the project associated // with the DSN. func (dsn Dsn) StoreAPIURL() *url.URL { return dsn.getAPIURL("store") } // EnvelopeAPIURL returns the URL of the envelope endpoint of the project // associated with the DSN. func (dsn Dsn) EnvelopeAPIURL() *url.URL { return dsn.getAPIURL("envelope") } func (dsn Dsn) getAPIURL(s string) *url.URL { var rawURL string rawURL += fmt.Sprintf("%s://%s", dsn.scheme, dsn.host) if dsn.port != dsn.scheme.defaultPort() { rawURL += fmt.Sprintf(":%d", dsn.port) } if dsn.path != "" { rawURL += dsn.path } rawURL += fmt.Sprintf("/api/%d/%s/", dsn.projectID, s) parsedURL, _ := url.Parse(rawURL) return parsedURL } // RequestHeaders returns all the necessary headers that have to be used in the transport. func (dsn Dsn) RequestHeaders() map[string]string { auth := fmt.Sprintf("Sentry sentry_version=%s, sentry_timestamp=%d, "+ "sentry_client=sentry.go/%s, sentry_key=%s", apiVersion, time.Now().Unix(), Version, dsn.publicKey) if dsn.secretKey != "" { auth = fmt.Sprintf("%s, sentry_secret=%s", auth, dsn.secretKey) } return map[string]string{ "Content-Type": "application/json", "X-Sentry-Auth": auth, } } // MarshalJSON converts the Dsn struct to JSON. func (dsn Dsn) MarshalJSON() ([]byte, error) { return json.Marshal(dsn.String()) } // UnmarshalJSON converts JSON data to the Dsn struct. func (dsn *Dsn) UnmarshalJSON(data []byte) error { var str string _ = json.Unmarshal(data, &str) newDsn, err := NewDsn(str) if err != nil { return err } *dsn = *newDsn return nil } ================================================ FILE: vendor/github.com/getsentry/sentry-go/hub.go ================================================ package sentry import ( "context" "sync" "time" ) type contextKey int // Keys used to store values in a Context. Use with Context.Value to access // values stored by the SDK. const ( // HubContextKey is the key used to store the current Hub. HubContextKey = contextKey(1) // RequestContextKey is the key used to store the current http.Request. RequestContextKey = contextKey(2) ) // defaultMaxBreadcrumbs is the default maximum number of breadcrumbs added to // an event. Can be overwritten with the maxBreadcrumbs option. const defaultMaxBreadcrumbs = 30 // maxBreadcrumbs is the absolute maximum number of breadcrumbs added to an // event. The maxBreadcrumbs option cannot be set higher than this value. const maxBreadcrumbs = 100 // currentHub is the initial Hub with no Client bound and an empty Scope. var currentHub = NewHub(nil, NewScope()) // Hub is the central object that manages scopes and clients. // // This can be used to capture events and manage the scope. // The default hub that is available automatically. // // In most situations developers do not need to interface the hub. Instead // toplevel convenience functions are exposed that will automatically dispatch // to global (CurrentHub) hub. In some situations this might not be // possible in which case it might become necessary to manually work with the // hub. This is for instance the case when working with async code. type Hub struct { mu sync.RWMutex stack *stack lastEventID EventID } type layer struct { // mu protects concurrent reads and writes to client. mu sync.RWMutex client *Client // scope is read-only, not protected by mu. scope *Scope } // Client returns the layer's client. Safe for concurrent use. func (l *layer) Client() *Client { l.mu.RLock() defer l.mu.RUnlock() return l.client } // SetClient sets the layer's client. Safe for concurrent use. func (l *layer) SetClient(c *Client) { l.mu.Lock() defer l.mu.Unlock() l.client = c } type stack []*layer // NewHub returns an instance of a Hub with provided Client and Scope bound. func NewHub(client *Client, scope *Scope) *Hub { hub := Hub{ stack: &stack{{ client: client, scope: scope, }}, } return &hub } // CurrentHub returns an instance of previously initialized Hub stored in the global namespace. func CurrentHub() *Hub { return currentHub } // LastEventID returns an ID of last captured event for the current Hub. func (hub *Hub) LastEventID() EventID { hub.mu.RLock() defer hub.mu.RUnlock() return hub.lastEventID } // stackTop returns the top layer of the hub stack. Valid hubs always have at // least one layer, therefore stackTop always return a non-nil pointer. func (hub *Hub) stackTop() *layer { hub.mu.RLock() defer hub.mu.RUnlock() stack := hub.stack stackLen := len(*stack) top := (*stack)[stackLen-1] return top } // Clone returns a copy of the current Hub with top-most scope and client copied over. func (hub *Hub) Clone() *Hub { top := hub.stackTop() scope := top.scope if scope != nil { scope = scope.Clone() } return NewHub(top.Client(), scope) } // Scope returns top-level Scope of the current Hub or nil if no Scope is bound. func (hub *Hub) Scope() *Scope { top := hub.stackTop() return top.scope } // Client returns top-level Client of the current Hub or nil if no Client is bound. func (hub *Hub) Client() *Client { top := hub.stackTop() return top.Client() } // PushScope pushes a new scope for the current Hub and reuses previously bound Client. func (hub *Hub) PushScope() *Scope { top := hub.stackTop() var scope *Scope if top.scope != nil { scope = top.scope.Clone() } else { scope = NewScope() } hub.mu.Lock() defer hub.mu.Unlock() *hub.stack = append(*hub.stack, &layer{ client: top.Client(), scope: scope, }) return scope } // PopScope drops the most recent scope. // // Calls to PopScope must be coordinated with PushScope. For most cases, using // WithScope should be more convenient. // // Calls to PopScope that do not match previous calls to PushScope are silently // ignored. func (hub *Hub) PopScope() { hub.mu.Lock() defer hub.mu.Unlock() stack := *hub.stack stackLen := len(stack) if stackLen > 1 { // Never pop the last item off the stack, the stack should always have // at least one item. *hub.stack = stack[0 : stackLen-1] } } // BindClient binds a new Client for the current Hub. func (hub *Hub) BindClient(client *Client) { top := hub.stackTop() top.SetClient(client) } // WithScope runs f in an isolated temporary scope. // // It is useful when extra data should be sent with a single capture call, for // instance a different level or tags. // // The scope passed to f starts as a clone of the current scope and can be // freely modified without affecting the current scope. // // It is a shorthand for PushScope followed by PopScope. func (hub *Hub) WithScope(f func(scope *Scope)) { scope := hub.PushScope() defer hub.PopScope() f(scope) } // ConfigureScope runs f in the current scope. // // It is useful to set data that applies to all events that share the current // scope. // // Modifying the scope affects all references to the current scope. // // See also WithScope for making isolated temporary changes. func (hub *Hub) ConfigureScope(f func(scope *Scope)) { scope := hub.Scope() f(scope) } // CaptureEvent calls the method of a same name on currently bound Client instance // passing it a top-level Scope. // Returns EventID if successfully, or nil if there's no Scope or Client available. func (hub *Hub) CaptureEvent(event *Event) *EventID { client, scope := hub.Client(), hub.Scope() if client == nil || scope == nil { return nil } eventID := client.CaptureEvent(event, nil, scope) hub.mu.Lock() defer hub.mu.Unlock() if eventID != nil { hub.lastEventID = *eventID } else { hub.lastEventID = "" } return eventID } // CaptureMessage calls the method of a same name on currently bound Client instance // passing it a top-level Scope. // Returns EventID if successfully, or nil if there's no Scope or Client available. func (hub *Hub) CaptureMessage(message string) *EventID { client, scope := hub.Client(), hub.Scope() if client == nil || scope == nil { return nil } eventID := client.CaptureMessage(message, nil, scope) hub.mu.Lock() defer hub.mu.Unlock() if eventID != nil { hub.lastEventID = *eventID } else { hub.lastEventID = "" } return eventID } // CaptureException calls the method of a same name on currently bound Client instance // passing it a top-level Scope. // Returns EventID if successfully, or nil if there's no Scope or Client available. func (hub *Hub) CaptureException(exception error) *EventID { client, scope := hub.Client(), hub.Scope() if client == nil || scope == nil { return nil } eventID := client.CaptureException(exception, &EventHint{OriginalException: exception}, scope) hub.mu.Lock() defer hub.mu.Unlock() if eventID != nil { hub.lastEventID = *eventID } else { hub.lastEventID = "" } return eventID } // AddBreadcrumb records a new breadcrumb. // // The total number of breadcrumbs that can be recorded are limited by the // configuration on the client. func (hub *Hub) AddBreadcrumb(breadcrumb *Breadcrumb, hint *BreadcrumbHint) { client := hub.Client() // If there's no client, just store it on the scope straight away if client == nil { hub.Scope().AddBreadcrumb(breadcrumb, maxBreadcrumbs) return } options := client.Options() max := defaultMaxBreadcrumbs if options.MaxBreadcrumbs != 0 { max = options.MaxBreadcrumbs } if max < 0 { return } if options.BeforeBreadcrumb != nil { h := &BreadcrumbHint{} if hint != nil { h = hint } if breadcrumb = options.BeforeBreadcrumb(breadcrumb, h); breadcrumb == nil { Logger.Println("breadcrumb dropped due to BeforeBreadcrumb callback.") return } } if max > maxBreadcrumbs { max = maxBreadcrumbs } hub.Scope().AddBreadcrumb(breadcrumb, max) } // Recover calls the method of a same name on currently bound Client instance // passing it a top-level Scope. // Returns EventID if successfully, or nil if there's no Scope or Client available. func (hub *Hub) Recover(err interface{}) *EventID { if err == nil { err = recover() } client, scope := hub.Client(), hub.Scope() if client == nil || scope == nil { return nil } return client.Recover(err, &EventHint{RecoveredException: err}, scope) } // RecoverWithContext calls the method of a same name on currently bound Client instance // passing it a top-level Scope. // Returns EventID if successfully, or nil if there's no Scope or Client available. func (hub *Hub) RecoverWithContext(ctx context.Context, err interface{}) *EventID { if err == nil { err = recover() } client, scope := hub.Client(), hub.Scope() if client == nil || scope == nil { return nil } return client.RecoverWithContext(ctx, err, &EventHint{RecoveredException: err}, scope) } // Flush waits until the underlying Transport sends any buffered events to the // Sentry server, blocking for at most the given timeout. It returns false if // the timeout was reached. In that case, some events may not have been sent. // // Flush should be called before terminating the program to avoid // unintentionally dropping events. // // Do not call Flush indiscriminately after every call to CaptureEvent, // CaptureException or CaptureMessage. Instead, to have the SDK send events over // the network synchronously, configure it to use the HTTPSyncTransport in the // call to Init. func (hub *Hub) Flush(timeout time.Duration) bool { client := hub.Client() if client == nil { return false } return client.Flush(timeout) } // HasHubOnContext checks whether Hub instance is bound to a given Context struct. func HasHubOnContext(ctx context.Context) bool { _, ok := ctx.Value(HubContextKey).(*Hub) return ok } // GetHubFromContext tries to retrieve Hub instance from the given Context struct // or return nil if one is not found. func GetHubFromContext(ctx context.Context) *Hub { if hub, ok := ctx.Value(HubContextKey).(*Hub); ok { return hub } return nil } // hubFromContext returns either a hub stored in the context or the current hub. // The return value is guaranteed to be non-nil, unlike GetHubFromContext. func hubFromContext(ctx context.Context) *Hub { if hub, ok := ctx.Value(HubContextKey).(*Hub); ok { return hub } return currentHub } // SetHubOnContext stores given Hub instance on the Context struct and returns a new Context. func SetHubOnContext(ctx context.Context, hub *Hub) context.Context { return context.WithValue(ctx, HubContextKey, hub) } ================================================ FILE: vendor/github.com/getsentry/sentry-go/integrations.go ================================================ package sentry import ( "fmt" "regexp" "runtime" "runtime/debug" "strings" "sync" ) // ================================ // Modules Integration // ================================ type modulesIntegration struct { once sync.Once modules map[string]string } func (mi *modulesIntegration) Name() string { return "Modules" } func (mi *modulesIntegration) SetupOnce(client *Client) { client.AddEventProcessor(mi.processor) } func (mi *modulesIntegration) processor(event *Event, hint *EventHint) *Event { if len(event.Modules) == 0 { mi.once.Do(func() { info, ok := debug.ReadBuildInfo() if !ok { Logger.Print("The Modules integration is not available in binaries built without module support.") return } mi.modules = extractModules(info) }) } event.Modules = mi.modules return event } func extractModules(info *debug.BuildInfo) map[string]string { modules := map[string]string{ info.Main.Path: info.Main.Version, } for _, dep := range info.Deps { ver := dep.Version if dep.Replace != nil { ver += fmt.Sprintf(" => %s %s", dep.Replace.Path, dep.Replace.Version) } modules[dep.Path] = strings.TrimSuffix(ver, " ") } return modules } // ================================ // Environment Integration // ================================ type environmentIntegration struct{} func (ei *environmentIntegration) Name() string { return "Environment" } func (ei *environmentIntegration) SetupOnce(client *Client) { client.AddEventProcessor(ei.processor) } func (ei *environmentIntegration) processor(event *Event, hint *EventHint) *Event { // Initialize maps as necessary. if event.Contexts == nil { event.Contexts = make(map[string]interface{}) } for _, name := range []string{"device", "os", "runtime"} { if event.Contexts[name] == nil { event.Contexts[name] = make(map[string]interface{}) } } // Set contextual information preserving existing data. For each context, if // the existing value is not of type map[string]interface{}, then no // additional information is added. if deviceContext, ok := event.Contexts["device"].(map[string]interface{}); ok { if _, ok := deviceContext["arch"]; !ok { deviceContext["arch"] = runtime.GOARCH } if _, ok := deviceContext["num_cpu"]; !ok { deviceContext["num_cpu"] = runtime.NumCPU() } } if osContext, ok := event.Contexts["os"].(map[string]interface{}); ok { if _, ok := osContext["name"]; !ok { osContext["name"] = runtime.GOOS } } if runtimeContext, ok := event.Contexts["runtime"].(map[string]interface{}); ok { if _, ok := runtimeContext["name"]; !ok { runtimeContext["name"] = "go" } if _, ok := runtimeContext["version"]; !ok { runtimeContext["version"] = runtime.Version() } if _, ok := runtimeContext["go_numroutines"]; !ok { runtimeContext["go_numroutines"] = runtime.NumGoroutine() } if _, ok := runtimeContext["go_maxprocs"]; !ok { runtimeContext["go_maxprocs"] = runtime.GOMAXPROCS(0) } if _, ok := runtimeContext["go_numcgocalls"]; !ok { runtimeContext["go_numcgocalls"] = runtime.NumCgoCall() } } return event } // ================================ // Ignore Errors Integration // ================================ type ignoreErrorsIntegration struct { ignoreErrors []*regexp.Regexp } func (iei *ignoreErrorsIntegration) Name() string { return "IgnoreErrors" } func (iei *ignoreErrorsIntegration) SetupOnce(client *Client) { iei.ignoreErrors = transformStringsIntoRegexps(client.Options().IgnoreErrors) client.AddEventProcessor(iei.processor) } func (iei *ignoreErrorsIntegration) processor(event *Event, hint *EventHint) *Event { suspects := getIgnoreErrorsSuspects(event) for _, suspect := range suspects { for _, pattern := range iei.ignoreErrors { if pattern.Match([]byte(suspect)) { Logger.Printf("Event dropped due to being matched by `IgnoreErrors` option."+ "| Value matched: %s | Filter used: %s", suspect, pattern) return nil } } } return event } func transformStringsIntoRegexps(strings []string) []*regexp.Regexp { var exprs []*regexp.Regexp for _, s := range strings { r, err := regexp.Compile(s) if err == nil { exprs = append(exprs, r) } } return exprs } func getIgnoreErrorsSuspects(event *Event) []string { suspects := []string{} if event.Message != "" { suspects = append(suspects, event.Message) } for _, ex := range event.Exception { suspects = append(suspects, ex.Type, ex.Value) } return suspects } // ================================ // Contextify Frames Integration // ================================ type contextifyFramesIntegration struct { sr sourceReader contextLines int cachedLocations sync.Map } func (cfi *contextifyFramesIntegration) Name() string { return "ContextifyFrames" } func (cfi *contextifyFramesIntegration) SetupOnce(client *Client) { cfi.sr = newSourceReader() cfi.contextLines = 5 client.AddEventProcessor(cfi.processor) } func (cfi *contextifyFramesIntegration) processor(event *Event, hint *EventHint) *Event { // Range over all exceptions for _, ex := range event.Exception { // If it has no stacktrace, just bail out if ex.Stacktrace == nil { continue } // If it does, it should have frames, so try to contextify them ex.Stacktrace.Frames = cfi.contextify(ex.Stacktrace.Frames) } // Range over all threads for _, th := range event.Threads { // If it has no stacktrace, just bail out if th.Stacktrace == nil { continue } // If it does, it should have frames, so try to contextify them th.Stacktrace.Frames = cfi.contextify(th.Stacktrace.Frames) } return event } func (cfi *contextifyFramesIntegration) contextify(frames []Frame) []Frame { contextifiedFrames := make([]Frame, 0, len(frames)) for _, frame := range frames { if !frame.InApp { contextifiedFrames = append(contextifiedFrames, frame) continue } var path string if cachedPath, ok := cfi.cachedLocations.Load(frame.AbsPath); ok { if p, ok := cachedPath.(string); ok { path = p } } else { // Optimize for happy path here if fileExists(frame.AbsPath) { path = frame.AbsPath } else { path = cfi.findNearbySourceCodeLocation(frame.AbsPath) } } if path == "" { contextifiedFrames = append(contextifiedFrames, frame) continue } lines, contextLine := cfi.sr.readContextLines(path, frame.Lineno, cfi.contextLines) contextifiedFrames = append(contextifiedFrames, cfi.addContextLinesToFrame(frame, lines, contextLine)) } return contextifiedFrames } func (cfi *contextifyFramesIntegration) findNearbySourceCodeLocation(originalPath string) string { trimmedPath := strings.TrimPrefix(originalPath, "/") components := strings.Split(trimmedPath, "/") for len(components) > 0 { components = components[1:] possibleLocation := strings.Join(components, "/") if fileExists(possibleLocation) { cfi.cachedLocations.Store(originalPath, possibleLocation) return possibleLocation } } cfi.cachedLocations.Store(originalPath, "") return "" } func (cfi *contextifyFramesIntegration) addContextLinesToFrame(frame Frame, lines [][]byte, contextLine int) Frame { for i, line := range lines { switch { case i < contextLine: frame.PreContext = append(frame.PreContext, string(line)) case i == contextLine: frame.ContextLine = string(line) default: frame.PostContext = append(frame.PostContext, string(line)) } } return frame } ================================================ FILE: vendor/github.com/getsentry/sentry-go/interfaces.go ================================================ package sentry import ( "context" "encoding/json" "fmt" "net" "net/http" "strings" "time" ) // Protocol Docs (kinda) // https://github.com/getsentry/rust-sentry-types/blob/master/src/protocol/v7.rs // transactionType is the type of a transaction event. const transactionType = "transaction" // Level marks the severity of the event. type Level string // Describes the severity of the event. const ( LevelDebug Level = "debug" LevelInfo Level = "info" LevelWarning Level = "warning" LevelError Level = "error" LevelFatal Level = "fatal" ) // SdkInfo contains all metadata about about the SDK being used. type SdkInfo struct { Name string `json:"name,omitempty"` Version string `json:"version,omitempty"` Integrations []string `json:"integrations,omitempty"` Packages []SdkPackage `json:"packages,omitempty"` } // SdkPackage describes a package that was installed. type SdkPackage struct { Name string `json:"name,omitempty"` Version string `json:"version,omitempty"` } // TODO: This type could be more useful, as map of interface{} is too generic // and requires a lot of type assertions in beforeBreadcrumb calls // plus it could just be map[string]interface{} then. // BreadcrumbHint contains information that can be associated with a Breadcrumb. type BreadcrumbHint map[string]interface{} // Breadcrumb specifies an application event that occurred before a Sentry event. // An event may contain one or more breadcrumbs. type Breadcrumb struct { Type string `json:"type,omitempty"` Category string `json:"category,omitempty"` Message string `json:"message,omitempty"` Data map[string]interface{} `json:"data,omitempty"` Level Level `json:"level,omitempty"` Timestamp time.Time `json:"timestamp"` } // TODO: provide constants for known breadcrumb types. // See https://develop.sentry.dev/sdk/event-payloads/breadcrumbs/#breadcrumb-types. // MarshalJSON converts the Breadcrumb struct to JSON. func (b *Breadcrumb) MarshalJSON() ([]byte, error) { // We want to omit time.Time zero values, otherwise the server will try to // interpret dates too far in the past. However, encoding/json doesn't // support the "omitempty" option for struct types. See // https://golang.org/issues/11939. // // We overcome the limitation and achieve what we want by shadowing fields // and a few type tricks. // breadcrumb aliases Breadcrumb to allow calling json.Marshal without an // infinite loop. It preserves all fields while none of the attached // methods. type breadcrumb Breadcrumb if b.Timestamp.IsZero() { return json.Marshal(struct { // Embed all of the fields of Breadcrumb. *breadcrumb // Timestamp shadows the original Timestamp field and is meant to // remain nil, triggering the omitempty behavior. Timestamp json.RawMessage `json:"timestamp,omitempty"` }{breadcrumb: (*breadcrumb)(b)}) } return json.Marshal((*breadcrumb)(b)) } // User describes the user associated with an Event. If this is used, at least // an ID or an IP address should be provided. type User struct { Email string `json:"email,omitempty"` ID string `json:"id,omitempty"` IPAddress string `json:"ip_address,omitempty"` Username string `json:"username,omitempty"` } // Request contains information on a HTTP request related to the event. type Request struct { URL string `json:"url,omitempty"` Method string `json:"method,omitempty"` Data string `json:"data,omitempty"` QueryString string `json:"query_string,omitempty"` Cookies string `json:"cookies,omitempty"` Headers map[string]string `json:"headers,omitempty"` Env map[string]string `json:"env,omitempty"` } // NewRequest returns a new Sentry Request from the given http.Request. // // NewRequest avoids operations that depend on network access. In particular, it // does not read r.Body. func NewRequest(r *http.Request) *Request { protocol := schemeHTTP if r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https" { protocol = schemeHTTPS } url := fmt.Sprintf("%s://%s%s", protocol, r.Host, r.URL.Path) // We read only the first Cookie header because of the specification: // https://tools.ietf.org/html/rfc6265#section-5.4 // When the user agent generates an HTTP request, the user agent MUST NOT // attach more than one Cookie header field. cookies := r.Header.Get("Cookie") headers := make(map[string]string, len(r.Header)) for k, v := range r.Header { headers[k] = strings.Join(v, ",") } headers["Host"] = r.Host var env map[string]string if addr, port, err := net.SplitHostPort(r.RemoteAddr); err == nil { env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port} } return &Request{ URL: url, Method: r.Method, QueryString: r.URL.RawQuery, Cookies: cookies, Headers: headers, Env: env, } } // Exception specifies an error that occurred. type Exception struct { Type string `json:"type,omitempty"` // used as the main issue title Value string `json:"value,omitempty"` // used as the main issue subtitle Module string `json:"module,omitempty"` ThreadID string `json:"thread_id,omitempty"` Stacktrace *Stacktrace `json:"stacktrace,omitempty"` } // EventID is a hexadecimal string representing a unique uuid4 for an Event. // An EventID must be 32 characters long, lowercase and not have any dashes. type EventID string // Event is the fundamental data structure that is sent to Sentry. type Event struct { Breadcrumbs []*Breadcrumb `json:"breadcrumbs,omitempty"` Contexts map[string]interface{} `json:"contexts,omitempty"` Dist string `json:"dist,omitempty"` Environment string `json:"environment,omitempty"` EventID EventID `json:"event_id,omitempty"` Extra map[string]interface{} `json:"extra,omitempty"` Fingerprint []string `json:"fingerprint,omitempty"` Level Level `json:"level,omitempty"` Message string `json:"message,omitempty"` Platform string `json:"platform,omitempty"` Release string `json:"release,omitempty"` Sdk SdkInfo `json:"sdk,omitempty"` ServerName string `json:"server_name,omitempty"` Threads []Thread `json:"threads,omitempty"` Tags map[string]string `json:"tags,omitempty"` Timestamp time.Time `json:"timestamp"` Transaction string `json:"transaction,omitempty"` User User `json:"user,omitempty"` Logger string `json:"logger,omitempty"` Modules map[string]string `json:"modules,omitempty"` Request *Request `json:"request,omitempty"` Exception []Exception `json:"exception,omitempty"` // The fields below are only relevant for transactions. Type string `json:"type,omitempty"` StartTime time.Time `json:"start_timestamp"` Spans []*Span `json:"spans,omitempty"` } // TODO: Event.Contexts map[string]interface{} => map[string]EventContext, // to prevent accidentally storing T when we mean *T. // For example, the TraceContext must be stored as *TraceContext to pick up the // MarshalJSON method (and avoid copying). // type EventContext interface{ EventContext() } // MarshalJSON converts the Event struct to JSON. func (e *Event) MarshalJSON() ([]byte, error) { // We want to omit time.Time zero values, otherwise the server will try to // interpret dates too far in the past. However, encoding/json doesn't // support the "omitempty" option for struct types. See // https://golang.org/issues/11939. // // We overcome the limitation and achieve what we want by shadowing fields // and a few type tricks. if e.Type == transactionType { return e.transactionMarshalJSON() } return e.defaultMarshalJSON() } func (e *Event) defaultMarshalJSON() ([]byte, error) { // event aliases Event to allow calling json.Marshal without an infinite // loop. It preserves all fields while none of the attached methods. type event Event // errorEvent is like Event with shadowed fields for customizing JSON // marshaling. type errorEvent struct { *event // Timestamp shadows the original Timestamp field. It allows us to // include the timestamp when non-zero and omit it otherwise. Timestamp json.RawMessage `json:"timestamp,omitempty"` // The fields below are not part of error events and only make sense to // be sent for transactions. They shadow the respective fields in Event // and are meant to remain nil, triggering the omitempty behavior. Type json.RawMessage `json:"type,omitempty"` StartTime json.RawMessage `json:"start_timestamp,omitempty"` Spans json.RawMessage `json:"spans,omitempty"` } x := errorEvent{event: (*event)(e)} if !e.Timestamp.IsZero() { b, err := e.Timestamp.MarshalJSON() if err != nil { return nil, err } x.Timestamp = b } return json.Marshal(x) } func (e *Event) transactionMarshalJSON() ([]byte, error) { // event aliases Event to allow calling json.Marshal without an infinite // loop. It preserves all fields while none of the attached methods. type event Event // transactionEvent is like Event with shadowed fields for customizing JSON // marshaling. type transactionEvent struct { *event // The fields below shadow the respective fields in Event. They allow us // to include timestamps when non-zero and omit them otherwise. StartTime json.RawMessage `json:"start_timestamp,omitempty"` Timestamp json.RawMessage `json:"timestamp,omitempty"` } x := transactionEvent{event: (*event)(e)} if !e.Timestamp.IsZero() { b, err := e.Timestamp.MarshalJSON() if err != nil { return nil, err } x.Timestamp = b } if !e.StartTime.IsZero() { b, err := e.StartTime.MarshalJSON() if err != nil { return nil, err } x.StartTime = b } return json.Marshal(x) } // NewEvent creates a new Event. func NewEvent() *Event { event := Event{ Contexts: make(map[string]interface{}), Extra: make(map[string]interface{}), Tags: make(map[string]string), Modules: make(map[string]string), } return &event } // Thread specifies threads that were running at the time of an event. type Thread struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Stacktrace *Stacktrace `json:"stacktrace,omitempty"` Crashed bool `json:"crashed,omitempty"` Current bool `json:"current,omitempty"` } // EventHint contains information that can be associated with an Event. type EventHint struct { Data interface{} EventID string OriginalException error RecoveredException interface{} Context context.Context Request *http.Request Response *http.Response } ================================================ FILE: vendor/github.com/getsentry/sentry-go/internal/crypto/randutil/randutil.go ================================================ package randutil import ( "crypto/rand" "encoding/binary" ) const ( floatMax = 1 << 53 floatMask = floatMax - 1 ) // Float64 returns a cryptographically secure random number in [0.0, 1.0). func Float64() float64 { // The implementation is, in essence: // return float64(rand.Int63n(1<<53)) / (1<<53) b := make([]byte, 8) _, err := rand.Read(b) if err != nil { panic(err) } return float64(binary.LittleEndian.Uint64(b)&floatMask) / floatMax } ================================================ FILE: vendor/github.com/getsentry/sentry-go/internal/debug/transport.go ================================================ package debug import ( "bytes" "fmt" "io" "net/http" "net/http/httptrace" "net/http/httputil" ) // Transport implements http.RoundTripper and can be used to wrap other HTTP // transports for debugging, normally http.DefaultTransport. type Transport struct { http.RoundTripper Output io.Writer // Dump controls whether to dump HTTP request and responses. Dump bool // Trace enables usage of net/http/httptrace. Trace bool } func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { var buf bytes.Buffer if t.Dump { b, err := httputil.DumpRequestOut(req, true) if err != nil { panic(err) } _, err = buf.Write(ensureTrailingNewline(b)) if err != nil { panic(err) } } if t.Trace { trace := &httptrace.ClientTrace{ DNSDone: func(di httptrace.DNSDoneInfo) { fmt.Fprintf(&buf, "* DNS %v → %v\n", req.Host, di.Addrs) }, GotConn: func(ci httptrace.GotConnInfo) { fmt.Fprintf(&buf, "* Connection local=%v remote=%v", ci.Conn.LocalAddr(), ci.Conn.RemoteAddr()) if ci.Reused { fmt.Fprint(&buf, " (reused)") } if ci.WasIdle { fmt.Fprintf(&buf, " (idle %v)", ci.IdleTime) } fmt.Fprintln(&buf) }, } req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) } resp, err := t.RoundTripper.RoundTrip(req) if err != nil { return nil, err } if t.Dump { b, err := httputil.DumpResponse(resp, true) if err != nil { panic(err) } _, err = buf.Write(ensureTrailingNewline(b)) if err != nil { panic(err) } } _, err = io.Copy(t.Output, &buf) if err != nil { panic(err) } return resp, nil } func ensureTrailingNewline(b []byte) []byte { if len(b) > 0 && b[len(b)-1] != '\n' { b = append(b, '\n') } return b } ================================================ FILE: vendor/github.com/getsentry/sentry-go/internal/ratelimit/category.go ================================================ package ratelimit import "strings" // Reference: // https://github.com/getsentry/relay/blob/0424a2e017d193a93918053c90cdae9472d164bf/relay-common/src/constants.rs#L116-L127 // Category classifies supported payload types that can be ingested by Sentry // and, therefore, rate limited. type Category string // Known rate limit categories. As a special case, the CategoryAll applies to // all known payload types. const ( CategoryAll Category = "" CategoryError Category = "error" CategoryTransaction Category = "transaction" ) // knownCategories is the set of currently known categories. Other categories // are ignored for the purpose of rate-limiting. var knownCategories = map[Category]struct{}{ CategoryAll: {}, CategoryError: {}, CategoryTransaction: {}, } // String returns the category formatted for debugging. func (c Category) String() string { switch c { case "": return "CategoryAll" default: var b strings.Builder b.WriteString("Category") for _, w := range strings.Fields(string(c)) { b.WriteString(strings.Title(w)) } return b.String() } } ================================================ FILE: vendor/github.com/getsentry/sentry-go/internal/ratelimit/deadline.go ================================================ package ratelimit import "time" // A Deadline is a time instant when a rate limit expires. type Deadline time.Time // After reports whether the deadline d is after other. func (d Deadline) After(other Deadline) bool { return time.Time(d).After(time.Time(other)) } // Equal reports whether d and e represent the same deadline. func (d Deadline) Equal(e Deadline) bool { return time.Time(d).Equal(time.Time(e)) } // String returns the deadline formatted for debugging. func (d Deadline) String() string { // Like time.Time.String, but without the monotonic clock reading. return time.Time(d).Round(0).String() } ================================================ FILE: vendor/github.com/getsentry/sentry-go/internal/ratelimit/doc.go ================================================ // Package ratelimit provides tools to work with rate limits imposed by Sentry's // data ingestion pipeline. package ratelimit ================================================ FILE: vendor/github.com/getsentry/sentry-go/internal/ratelimit/map.go ================================================ package ratelimit import ( "net/http" "time" ) // Map maps categories to rate limit deadlines. // // A rate limit is in effect for a given category if either the category's // deadline or the deadline for the special CategoryAll has not yet expired. // // Use IsRateLimited to check whether a category is rate-limited. type Map map[Category]Deadline // IsRateLimited returns true if the category is currently rate limited. func (m Map) IsRateLimited(c Category) bool { return m.isRateLimited(c, time.Now()) } func (m Map) isRateLimited(c Category, now time.Time) bool { return m.Deadline(c).After(Deadline(now)) } // Deadline returns the deadline when the rate limit for the given category or // the special CategoryAll expire, whichever is furthest into the future. func (m Map) Deadline(c Category) Deadline { categoryDeadline := m[c] allDeadline := m[CategoryAll] if categoryDeadline.After(allDeadline) { return categoryDeadline } return allDeadline } // Merge merges the other map into m. // // If a category appears in both maps, the deadline that is furthest into the // future is preserved. func (m Map) Merge(other Map) { for c, d := range other { if d.After(m[c]) { m[c] = d } } } // FromResponse returns a rate limit map from an HTTP response. func FromResponse(r *http.Response) Map { return fromResponse(r, time.Now()) } func fromResponse(r *http.Response, now time.Time) Map { s := r.Header.Get("X-Sentry-Rate-Limits") if s != "" { return parseXSentryRateLimits(s, now) } if r.StatusCode == http.StatusTooManyRequests { s := r.Header.Get("Retry-After") deadline, _ := parseRetryAfter(s, now) return Map{CategoryAll: deadline} } return Map{} } ================================================ FILE: vendor/github.com/getsentry/sentry-go/internal/ratelimit/rate_limits.go ================================================ package ratelimit import ( "errors" "math" "strconv" "strings" "time" ) var errInvalidXSRLRetryAfter = errors.New("invalid retry-after value") // parseXSentryRateLimits returns a RateLimits map by parsing an input string in // the format of the X-Sentry-Rate-Limits header. // // Example // // X-Sentry-Rate-Limits: 60:transaction, 2700:default;error;security // // This will rate limit transactions for the next 60 seconds and errors for the // next 2700 seconds. // // Limits for unknown categories are ignored. func parseXSentryRateLimits(s string, now time.Time) Map { // https://github.com/getsentry/relay/blob/0424a2e017d193a93918053c90cdae9472d164bf/relay-server/src/utils/rate_limits.rs#L44-L82 m := make(Map, len(knownCategories)) for _, limit := range strings.Split(s, ",") { limit = strings.TrimSpace(limit) if limit == "" { continue } components := strings.Split(limit, ":") if len(components) == 0 { continue } retryAfter, err := parseXSRLRetryAfter(strings.TrimSpace(components[0]), now) if err != nil { continue } categories := "" if len(components) > 1 { categories = components[1] } for _, category := range strings.Split(categories, ";") { c := Category(strings.ToLower(strings.TrimSpace(category))) if _, ok := knownCategories[c]; !ok { // skip unknown categories, keep m small continue } // always keep the deadline furthest into the future if retryAfter.After(m[c]) { m[c] = retryAfter } } } return m } // parseXSRLRetryAfter parses a string into a retry-after rate limit deadline. // // Valid input is a number, possibly signed and possibly floating-point, // indicating the number of seconds to wait before sending another request. // Negative values are treated as zero. Fractional values are rounded to the // next integer. func parseXSRLRetryAfter(s string, now time.Time) (Deadline, error) { // https://github.com/getsentry/relay/blob/0424a2e017d193a93918053c90cdae9472d164bf/relay-quotas/src/rate_limit.rs#L88-L96 f, err := strconv.ParseFloat(s, 64) if err != nil { return Deadline{}, errInvalidXSRLRetryAfter } d := time.Duration(math.Ceil(math.Max(f, 0.0))) * time.Second if d < 0 { d = 0 } return Deadline(now.Add(d)), nil } ================================================ FILE: vendor/github.com/getsentry/sentry-go/internal/ratelimit/retry_after.go ================================================ package ratelimit import ( "errors" "strconv" "time" ) const defaultRetryAfter = 1 * time.Minute var errInvalidRetryAfter = errors.New("invalid input") // parseRetryAfter parses a string s as in the standard Retry-After HTTP header // and returns a deadline until when requests are rate limited and therefore new // requests should not be sent. The input may be either a date or a non-negative // integer number of seconds. // // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After // // parseRetryAfter always returns a usable deadline, even in case of an error. // // This is the original rate limiting mechanism used by Sentry, superseeded by // the X-Sentry-Rate-Limits response header. func parseRetryAfter(s string, now time.Time) (Deadline, error) { if s == "" { goto invalid } if n, err := strconv.Atoi(s); err == nil { if n < 0 { goto invalid } d := time.Duration(n) * time.Second return Deadline(now.Add(d)), nil } if date, err := time.Parse(time.RFC1123, s); err == nil { return Deadline(date), nil } invalid: return Deadline(now.Add(defaultRetryAfter)), errInvalidRetryAfter } ================================================ FILE: vendor/github.com/getsentry/sentry-go/scope.go ================================================ package sentry import ( "bytes" "io" "net/http" "reflect" "sync" "time" ) // Scope holds contextual data for the current scope. // // The scope is an object that can cloned efficiently and stores data that is // locally relevant to an event. For instance the scope will hold recorded // breadcrumbs and similar information. // // The scope can be interacted with in two ways. First, the scope is routinely // updated with information by functions such as AddBreadcrumb which will modify // the current scope. Second, the current scope can be configured through the // ConfigureScope function or Hub method of the same name. // // The scope is meant to be modified but not inspected directly. When preparing // an event for reporting, the current client adds information from the current // scope into the event. type Scope struct { mu sync.RWMutex breadcrumbs []*Breadcrumb user User tags map[string]string contexts map[string]interface{} extra map[string]interface{} fingerprint []string level Level transaction string request *http.Request // requestBody holds a reference to the original request.Body. requestBody interface { // Bytes returns bytes from the original body, lazily buffered as the // original body is read. Bytes() []byte // Overflow returns true if the body is larger than the maximum buffer // size. Overflow() bool } eventProcessors []EventProcessor } // NewScope creates a new Scope. func NewScope() *Scope { scope := Scope{ breadcrumbs: make([]*Breadcrumb, 0), tags: make(map[string]string), contexts: make(map[string]interface{}), extra: make(map[string]interface{}), fingerprint: make([]string, 0), } return &scope } // AddBreadcrumb adds new breadcrumb to the current scope // and optionally throws the old one if limit is reached. func (scope *Scope) AddBreadcrumb(breadcrumb *Breadcrumb, limit int) { if breadcrumb.Timestamp.IsZero() { breadcrumb.Timestamp = time.Now() } scope.mu.Lock() defer scope.mu.Unlock() breadcrumbs := append(scope.breadcrumbs, breadcrumb) if len(breadcrumbs) > limit { scope.breadcrumbs = breadcrumbs[1 : limit+1] } else { scope.breadcrumbs = breadcrumbs } } // ClearBreadcrumbs clears all breadcrumbs from the current scope. func (scope *Scope) ClearBreadcrumbs() { scope.mu.Lock() defer scope.mu.Unlock() scope.breadcrumbs = []*Breadcrumb{} } // SetUser sets the user for the current scope. func (scope *Scope) SetUser(user User) { scope.mu.Lock() defer scope.mu.Unlock() scope.user = user } // SetRequest sets the request for the current scope. func (scope *Scope) SetRequest(r *http.Request) { scope.mu.Lock() defer scope.mu.Unlock() scope.request = r if r == nil { return } // Don't buffer request body if we know it is oversized. if r.ContentLength > maxRequestBodyBytes { return } // Don't buffer if there is no body. if r.Body == nil || r.Body == http.NoBody { return } buf := &limitedBuffer{Capacity: maxRequestBodyBytes} r.Body = readCloser{ Reader: io.TeeReader(r.Body, buf), Closer: r.Body, } scope.requestBody = buf } // SetRequestBody sets the request body for the current scope. // // This method should only be called when the body bytes are already available // in memory. Typically, the request body is buffered lazily from the // Request.Body from SetRequest. func (scope *Scope) SetRequestBody(b []byte) { scope.mu.Lock() defer scope.mu.Unlock() capacity := maxRequestBodyBytes overflow := false if len(b) > capacity { overflow = true b = b[:capacity] } scope.requestBody = &limitedBuffer{ Capacity: capacity, Buffer: *bytes.NewBuffer(b), overflow: overflow, } } // maxRequestBodyBytes is the default maximum request body size to send to // Sentry. const maxRequestBodyBytes = 10 * 1024 // A limitedBuffer is like a bytes.Buffer, but limited to store at most Capacity // bytes. Any writes past the capacity are silently discarded, similar to // ioutil.Discard. type limitedBuffer struct { Capacity int bytes.Buffer overflow bool } // Write implements io.Writer. func (b *limitedBuffer) Write(p []byte) (n int, err error) { // Silently ignore writes after overflow. if b.overflow { return len(p), nil } left := b.Capacity - b.Len() if left < 0 { left = 0 } if len(p) > left { b.overflow = true p = p[:left] } return b.Buffer.Write(p) } // Overflow returns true if the limitedBuffer discarded bytes written to it. func (b *limitedBuffer) Overflow() bool { return b.overflow } // readCloser combines an io.Reader and an io.Closer to implement io.ReadCloser. type readCloser struct { io.Reader io.Closer } // SetTag adds a tag to the current scope. func (scope *Scope) SetTag(key, value string) { scope.mu.Lock() defer scope.mu.Unlock() scope.tags[key] = value } // SetTags assigns multiple tags to the current scope. func (scope *Scope) SetTags(tags map[string]string) { scope.mu.Lock() defer scope.mu.Unlock() for k, v := range tags { scope.tags[k] = v } } // RemoveTag removes a tag from the current scope. func (scope *Scope) RemoveTag(key string) { scope.mu.Lock() defer scope.mu.Unlock() delete(scope.tags, key) } // SetContext adds a context to the current scope. func (scope *Scope) SetContext(key string, value interface{}) { scope.mu.Lock() defer scope.mu.Unlock() scope.contexts[key] = value } // SetContexts assigns multiple contexts to the current scope. func (scope *Scope) SetContexts(contexts map[string]interface{}) { scope.mu.Lock() defer scope.mu.Unlock() for k, v := range contexts { scope.contexts[k] = v } } // RemoveContext removes a context from the current scope. func (scope *Scope) RemoveContext(key string) { scope.mu.Lock() defer scope.mu.Unlock() delete(scope.contexts, key) } // SetExtra adds an extra to the current scope. func (scope *Scope) SetExtra(key string, value interface{}) { scope.mu.Lock() defer scope.mu.Unlock() scope.extra[key] = value } // SetExtras assigns multiple extras to the current scope. func (scope *Scope) SetExtras(extra map[string]interface{}) { scope.mu.Lock() defer scope.mu.Unlock() for k, v := range extra { scope.extra[k] = v } } // RemoveExtra removes a extra from the current scope. func (scope *Scope) RemoveExtra(key string) { scope.mu.Lock() defer scope.mu.Unlock() delete(scope.extra, key) } // SetFingerprint sets new fingerprint for the current scope. func (scope *Scope) SetFingerprint(fingerprint []string) { scope.mu.Lock() defer scope.mu.Unlock() scope.fingerprint = fingerprint } // SetLevel sets new level for the current scope. func (scope *Scope) SetLevel(level Level) { scope.mu.Lock() defer scope.mu.Unlock() scope.level = level } // SetTransaction sets the transaction name for the current transaction. func (scope *Scope) SetTransaction(name string) { scope.mu.Lock() defer scope.mu.Unlock() scope.transaction = name } // Transaction returns the transaction name for the current transaction. func (scope *Scope) Transaction() (name string) { scope.mu.RLock() defer scope.mu.RUnlock() return scope.transaction } // Clone returns a copy of the current scope with all data copied over. func (scope *Scope) Clone() *Scope { scope.mu.RLock() defer scope.mu.RUnlock() clone := NewScope() clone.user = scope.user clone.breadcrumbs = make([]*Breadcrumb, len(scope.breadcrumbs)) copy(clone.breadcrumbs, scope.breadcrumbs) for key, value := range scope.tags { clone.tags[key] = value } for key, value := range scope.contexts { clone.contexts[key] = value } for key, value := range scope.extra { clone.extra[key] = value } clone.fingerprint = make([]string, len(scope.fingerprint)) copy(clone.fingerprint, scope.fingerprint) clone.level = scope.level clone.transaction = scope.transaction clone.request = scope.request clone.requestBody = scope.requestBody clone.eventProcessors = scope.eventProcessors return clone } // Clear removes the data from the current scope. Not safe for concurrent use. func (scope *Scope) Clear() { *scope = *NewScope() } // AddEventProcessor adds an event processor to the current scope. func (scope *Scope) AddEventProcessor(processor EventProcessor) { scope.mu.Lock() defer scope.mu.Unlock() scope.eventProcessors = append(scope.eventProcessors, processor) } // ApplyToEvent takes the data from the current scope and attaches it to the event. func (scope *Scope) ApplyToEvent(event *Event, hint *EventHint) *Event { scope.mu.RLock() defer scope.mu.RUnlock() if len(scope.breadcrumbs) > 0 { if event.Breadcrumbs == nil { event.Breadcrumbs = []*Breadcrumb{} } event.Breadcrumbs = append(event.Breadcrumbs, scope.breadcrumbs...) } if len(scope.tags) > 0 { if event.Tags == nil { event.Tags = make(map[string]string) } for key, value := range scope.tags { event.Tags[key] = value } } if len(scope.contexts) > 0 { if event.Contexts == nil { event.Contexts = make(map[string]interface{}) } for key, value := range scope.contexts { if key == "trace" && event.Type == transactionType { // Do not override trace context of // transactions, otherwise it breaks the // transaction event representation. // For error events, the trace context is used // to link errors and traces/spans in Sentry. continue } event.Contexts[key] = value } } if len(scope.extra) > 0 { if event.Extra == nil { event.Extra = make(map[string]interface{}) } for key, value := range scope.extra { event.Extra[key] = value } } if (reflect.DeepEqual(event.User, User{})) { event.User = scope.user } if (event.Fingerprint == nil || len(event.Fingerprint) == 0) && len(scope.fingerprint) > 0 { event.Fingerprint = make([]string, len(scope.fingerprint)) copy(event.Fingerprint, scope.fingerprint) } if scope.level != "" { event.Level = scope.level } if scope.transaction != "" { event.Transaction = scope.transaction } if event.Request == nil && scope.request != nil { event.Request = NewRequest(scope.request) // NOTE: The SDK does not attempt to send partial request body data. // // The reason being that Sentry's ingest pipeline and UI are optimized // to show structured data. Additionally, tooling around PII scrubbing // relies on structured data; truncated request bodies would create // invalid payloads that are more prone to leaking PII data. // // Users can still send more data along their events if they want to, // for example using Event.Extra. if scope.requestBody != nil && !scope.requestBody.Overflow() { event.Request.Data = string(scope.requestBody.Bytes()) } } for _, processor := range scope.eventProcessors { id := event.EventID event = processor(event, hint) if event == nil { Logger.Printf("Event dropped by one of the Scope EventProcessors: %s\n", id) return nil } } return event } ================================================ FILE: vendor/github.com/getsentry/sentry-go/sentry.go ================================================ package sentry import ( "context" "time" ) // Version is the version of the SDK. const Version = "0.11.0" // apiVersion is the minimum version of the Sentry API compatible with the // sentry-go SDK. const apiVersion = "7" // userAgent is the User-Agent of outgoing HTTP requests. const userAgent = "sentry-go/" + Version // Init initializes the SDK with options. The returned error is non-nil if // options is invalid, for instance if a malformed DSN is provided. func Init(options ClientOptions) error { hub := CurrentHub() client, err := NewClient(options) if err != nil { return err } hub.BindClient(client) return nil } // AddBreadcrumb records a new breadcrumb. // // The total number of breadcrumbs that can be recorded are limited by the // configuration on the client. func AddBreadcrumb(breadcrumb *Breadcrumb) { hub := CurrentHub() hub.AddBreadcrumb(breadcrumb, nil) } // CaptureMessage captures an arbitrary message. func CaptureMessage(message string) *EventID { hub := CurrentHub() return hub.CaptureMessage(message) } // CaptureException captures an error. func CaptureException(exception error) *EventID { hub := CurrentHub() return hub.CaptureException(exception) } // CaptureEvent captures an event on the currently active client if any. // // The event must already be assembled. Typically code would instead use // the utility methods like CaptureException. The return value is the // event ID. In case Sentry is disabled or event was dropped, the return value will be nil. func CaptureEvent(event *Event) *EventID { hub := CurrentHub() return hub.CaptureEvent(event) } // Recover captures a panic. func Recover() *EventID { if err := recover(); err != nil { hub := CurrentHub() return hub.Recover(err) } return nil } // RecoverWithContext captures a panic and passes relevant context object. func RecoverWithContext(ctx context.Context) *EventID { if err := recover(); err != nil { var hub *Hub if HasHubOnContext(ctx) { hub = GetHubFromContext(ctx) } else { hub = CurrentHub() } return hub.RecoverWithContext(ctx, err) } return nil } // WithScope is a shorthand for CurrentHub().WithScope. func WithScope(f func(scope *Scope)) { hub := CurrentHub() hub.WithScope(f) } // ConfigureScope is a shorthand for CurrentHub().ConfigureScope. func ConfigureScope(f func(scope *Scope)) { hub := CurrentHub() hub.ConfigureScope(f) } // PushScope is a shorthand for CurrentHub().PushScope. func PushScope() { hub := CurrentHub() hub.PushScope() } // PopScope is a shorthand for CurrentHub().PopScope. func PopScope() { hub := CurrentHub() hub.PopScope() } // Flush waits until the underlying Transport sends any buffered events to the // Sentry server, blocking for at most the given timeout. It returns false if // the timeout was reached. In that case, some events may not have been sent. // // Flush should be called before terminating the program to avoid // unintentionally dropping events. // // Do not call Flush indiscriminately after every call to CaptureEvent, // CaptureException or CaptureMessage. Instead, to have the SDK send events over // the network synchronously, configure it to use the HTTPSyncTransport in the // call to Init. func Flush(timeout time.Duration) bool { hub := CurrentHub() return hub.Flush(timeout) } // LastEventID returns an ID of last captured event. func LastEventID() EventID { hub := CurrentHub() return hub.LastEventID() } ================================================ FILE: vendor/github.com/getsentry/sentry-go/sourcereader.go ================================================ package sentry import ( "bytes" "io/ioutil" "sync" ) type sourceReader struct { mu sync.Mutex cache map[string][][]byte } func newSourceReader() sourceReader { return sourceReader{ cache: make(map[string][][]byte), } } func (sr *sourceReader) readContextLines(filename string, line, context int) ([][]byte, int) { sr.mu.Lock() defer sr.mu.Unlock() lines, ok := sr.cache[filename] if !ok { data, err := ioutil.ReadFile(filename) if err != nil { sr.cache[filename] = nil return nil, 0 } lines = bytes.Split(data, []byte{'\n'}) sr.cache[filename] = lines } return sr.calculateContextLines(lines, line, context) } func (sr *sourceReader) calculateContextLines(lines [][]byte, line, context int) ([][]byte, int) { // Stacktrace lines are 1-indexed, slices are 0-indexed line-- // contextLine points to a line that caused an issue itself, in relation to // returned slice. contextLine := context if lines == nil || line >= len(lines) || line < 0 { return nil, 0 } if context < 0 { context = 0 contextLine = 0 } start := line - context if start < 0 { contextLine += start start = 0 } end := line + context + 1 if end > len(lines) { end = len(lines) } return lines[start:end], contextLine } ================================================ FILE: vendor/github.com/getsentry/sentry-go/span_recorder.go ================================================ package sentry import ( "sync" ) // maxSpans limits the number of recorded spans per transaction. The limit is // meant to bound memory usage and prevent too large transaction events that // would be rejected by Sentry. const maxSpans = 1000 // A spanRecorder stores a span tree that makes up a transaction. Safe for // concurrent use. It is okay to add child spans from multiple goroutines. type spanRecorder struct { mu sync.Mutex spans []*Span overflowOnce sync.Once } // record stores a span. The first stored span is assumed to be the root of a // span tree. func (r *spanRecorder) record(s *Span) { r.mu.Lock() defer r.mu.Unlock() if len(r.spans) >= maxSpans { r.overflowOnce.Do(func() { root := r.spans[0] Logger.Printf("Too many spans: dropping spans from transaction with TraceID=%s SpanID=%s limit=%d", root.TraceID, root.SpanID, maxSpans) }) // TODO(tracing): mark the transaction event in some way to // communicate that spans were dropped. return } r.spans = append(r.spans, s) } // root returns the first recorded span. Returns nil if none have been recorded. func (r *spanRecorder) root() *Span { r.mu.Lock() defer r.mu.Unlock() if len(r.spans) == 0 { return nil } return r.spans[0] } // children returns a list of all recorded spans, except the root. Returns nil // if there are no children. func (r *spanRecorder) children() []*Span { r.mu.Lock() defer r.mu.Unlock() if len(r.spans) < 2 { return nil } return r.spans[1:] } ================================================ FILE: vendor/github.com/getsentry/sentry-go/stacktrace.go ================================================ package sentry import ( "go/build" "path/filepath" "reflect" "runtime" "strings" ) const unknown string = "unknown" // The module download is split into two parts: downloading the go.mod and downloading the actual code. // If you have dependencies only needed for tests, then they will show up in your go.mod, // and go get will download their go.mods, but it will not download their code. // The test-only dependencies get downloaded only when you need it, such as the first time you run go test. // // https://github.com/golang/go/issues/26913#issuecomment-411976222 // Stacktrace holds information about the frames of the stack. type Stacktrace struct { Frames []Frame `json:"frames,omitempty"` FramesOmitted []uint `json:"frames_omitted,omitempty"` } // NewStacktrace creates a stacktrace using runtime.Callers. func NewStacktrace() *Stacktrace { pcs := make([]uintptr, 100) n := runtime.Callers(1, pcs) if n == 0 { return nil } frames := extractFrames(pcs[:n]) frames = filterFrames(frames) stacktrace := Stacktrace{ Frames: frames, } return &stacktrace } // TODO: Make it configurable so that anyone can provide their own implementation? // Use of reflection allows us to not have a hard dependency on any given // package, so we don't have to import it. // ExtractStacktrace creates a new Stacktrace based on the given error. func ExtractStacktrace(err error) *Stacktrace { method := extractReflectedStacktraceMethod(err) var pcs []uintptr if method.IsValid() { pcs = extractPcs(method) } else { pcs = extractXErrorsPC(err) } if len(pcs) == 0 { return nil } frames := extractFrames(pcs) frames = filterFrames(frames) stacktrace := Stacktrace{ Frames: frames, } return &stacktrace } func extractReflectedStacktraceMethod(err error) reflect.Value { var method reflect.Value // https://github.com/pingcap/errors methodGetStackTracer := reflect.ValueOf(err).MethodByName("GetStackTracer") // https://github.com/pkg/errors methodStackTrace := reflect.ValueOf(err).MethodByName("StackTrace") // https://github.com/go-errors/errors methodStackFrames := reflect.ValueOf(err).MethodByName("StackFrames") if methodGetStackTracer.IsValid() { stacktracer := methodGetStackTracer.Call(make([]reflect.Value, 0))[0] stacktracerStackTrace := reflect.ValueOf(stacktracer).MethodByName("StackTrace") if stacktracerStackTrace.IsValid() { method = stacktracerStackTrace } } if methodStackTrace.IsValid() { method = methodStackTrace } if methodStackFrames.IsValid() { method = methodStackFrames } return method } func extractPcs(method reflect.Value) []uintptr { var pcs []uintptr stacktrace := method.Call(make([]reflect.Value, 0))[0] if stacktrace.Kind() != reflect.Slice { return nil } for i := 0; i < stacktrace.Len(); i++ { pc := stacktrace.Index(i) if pc.Kind() == reflect.Uintptr { pcs = append(pcs, uintptr(pc.Uint())) continue } if pc.Kind() == reflect.Struct { field := pc.FieldByName("ProgramCounter") if field.IsValid() && field.Kind() == reflect.Uintptr { pcs = append(pcs, uintptr(field.Uint())) continue } } } return pcs } // extractXErrorsPC extracts program counters from error values compatible with // the error types from golang.org/x/xerrors. // // It returns nil if err is not compatible with errors from that package or if // no program counters are stored in err. func extractXErrorsPC(err error) []uintptr { // This implementation uses the reflect package to avoid a hard dependency // on third-party packages. // We don't know if err matches the expected type. For simplicity, instead // of trying to account for all possible ways things can go wrong, some // assumptions are made and if they are violated the code will panic. We // recover from any panic and ignore it, returning nil. //nolint: errcheck defer func() { recover() }() field := reflect.ValueOf(err).Elem().FieldByName("frame") // type Frame struct{ frames [3]uintptr } field = field.FieldByName("frames") field = field.Slice(1, field.Len()) // drop first pc pointing to xerrors.New pc := make([]uintptr, field.Len()) for i := 0; i < field.Len(); i++ { pc[i] = uintptr(field.Index(i).Uint()) } return pc } // Frame represents a function call and it's metadata. Frames are associated // with a Stacktrace. type Frame struct { Function string `json:"function,omitempty"` Symbol string `json:"symbol,omitempty"` Module string `json:"module,omitempty"` Package string `json:"package,omitempty"` Filename string `json:"filename,omitempty"` AbsPath string `json:"abs_path,omitempty"` Lineno int `json:"lineno,omitempty"` Colno int `json:"colno,omitempty"` PreContext []string `json:"pre_context,omitempty"` ContextLine string `json:"context_line,omitempty"` PostContext []string `json:"post_context,omitempty"` InApp bool `json:"in_app,omitempty"` Vars map[string]interface{} `json:"vars,omitempty"` } // NewFrame assembles a stacktrace frame out of runtime.Frame. func NewFrame(f runtime.Frame) Frame { var abspath, relpath string // NOTE: f.File paths historically use forward slash as path separator even // on Windows, though this is not yet documented, see // https://golang.org/issues/3335. In any case, filepath.IsAbs can work with // paths with either slash or backslash on Windows. switch { case f.File == "": relpath = unknown // Leave abspath as the empty string to be omitted when serializing // event as JSON. abspath = "" case filepath.IsAbs(f.File): abspath = f.File // TODO: in the general case, it is not trivial to come up with a // "project relative" path with the data we have in run time. // We shall not use filepath.Base because it creates ambiguous paths and // affects the "Suspect Commits" feature. // For now, leave relpath empty to be omitted when serializing the event // as JSON. Improve this later. relpath = "" default: // f.File is a relative path. This may happen when the binary is built // with the -trimpath flag. relpath = f.File // Omit abspath when serializing the event as JSON. abspath = "" } function := f.Function var pkg string if function != "" { pkg, function = splitQualifiedFunctionName(function) } frame := Frame{ AbsPath: abspath, Filename: relpath, Lineno: f.Line, Module: pkg, Function: function, } frame.InApp = isInAppFrame(frame) return frame } // splitQualifiedFunctionName splits a package path-qualified function name into // package name and function name. Such qualified names are found in // runtime.Frame.Function values. func splitQualifiedFunctionName(name string) (pkg string, fun string) { pkg = packageName(name) fun = strings.TrimPrefix(name, pkg+".") return } func extractFrames(pcs []uintptr) []Frame { var frames []Frame callersFrames := runtime.CallersFrames(pcs) for { callerFrame, more := callersFrames.Next() frames = append([]Frame{ NewFrame(callerFrame), }, frames...) if !more { break } } return frames } // filterFrames filters out stack frames that are not meant to be reported to // Sentry. Those are frames internal to the SDK or Go. func filterFrames(frames []Frame) []Frame { if len(frames) == 0 { return nil } filteredFrames := make([]Frame, 0, len(frames)) for _, frame := range frames { // Skip Go internal frames. if frame.Module == "runtime" || frame.Module == "testing" { continue } // Skip Sentry internal frames, except for frames in _test packages (for // testing). if strings.HasPrefix(frame.Module, "github.com/getsentry/sentry-go") && !strings.HasSuffix(frame.Module, "_test") { continue } filteredFrames = append(filteredFrames, frame) } return filteredFrames } func isInAppFrame(frame Frame) bool { if strings.HasPrefix(frame.AbsPath, build.Default.GOROOT) || strings.Contains(frame.Module, "vendor") || strings.Contains(frame.Module, "third_party") { return false } return true } func callerFunctionName() string { pcs := make([]uintptr, 1) runtime.Callers(3, pcs) callersFrames := runtime.CallersFrames(pcs) callerFrame, _ := callersFrames.Next() return baseName(callerFrame.Function) } // packageName returns the package part of the symbol name, or the empty string // if there is none. // It replicates https://golang.org/pkg/debug/gosym/#Sym.PackageName, avoiding a // dependency on debug/gosym. func packageName(name string) string { // A prefix of "type." and "go." is a compiler-generated symbol that doesn't belong to any package. // See variable reservedimports in cmd/compile/internal/gc/subr.go if strings.HasPrefix(name, "go.") || strings.HasPrefix(name, "type.") { return "" } pathend := strings.LastIndex(name, "/") if pathend < 0 { pathend = 0 } if i := strings.Index(name[pathend:], "."); i != -1 { return name[:pathend+i] } return "" } // baseName returns the symbol name without the package or receiver name. // It replicates https://golang.org/pkg/debug/gosym/#Sym.BaseName, avoiding a // dependency on debug/gosym. func baseName(name string) string { if i := strings.LastIndex(name, "."); i != -1 { return name[i+1:] } return name } ================================================ FILE: vendor/github.com/getsentry/sentry-go/traces_sampler.go ================================================ package sentry import ( "fmt" "github.com/getsentry/sentry-go/internal/crypto/randutil" ) // A TracesSampler makes sampling decisions for spans. // // In addition to the sampling context passed to the Sample method, // implementations may keep and use internal state to make decisions. // // Sampling is one of the last steps when starting a new span, such that the // sampler can inspect most of the state of the span to make a decision. // // Implementations must be safe for concurrent use by multiple goroutines. type TracesSampler interface { Sample(ctx SamplingContext) Sampled } // Implementation note: // // TracesSampler.Sample return type is Sampled (instead of bool or float64), so // that we can compose samplers by letting a sampler return SampledUndefined to // defer the decision to the next sampler. // // For example, a hypothetical InheritFromParentSampler would return // SampledUndefined if there is no parent span in the SamplingContext, deferring // the sampling decision to another sampler, like a UniformSampler. // // var _ TracesSampler = sentry.TracesSamplers{ // sentry.InheritFromParentSampler, // sentry.UniformTracesSampler(0.1), // } // // Another example, we can provide a sampler that returns SampledFalse if the // SamplingContext matches some condition, and SampledUndefined otherwise: // // var _ TracesSampler = sentry.TracesSamplers{ // sentry.IgnoreTransaction(regexp.MustCompile(`^\w+ /(favicon.ico|healthz)`), // sentry.InheritFromParentSampler, // sentry.UniformTracesSampler(0.1), // } // // If after running all samplers the decision is still undefined, the // span/transaction is not sampled. // A SamplingContext is passed to a TracesSampler to determine a sampling // decision. type SamplingContext struct { Span *Span // The current span, always non-nil. Parent *Span // The parent span, may be nil. } // TODO(tracing): possibly expand SamplingContext to include custom / // user-provided data. // // Unlike in other SDKs, the current http.Request is not part of the // SamplingContext to avoid bloating it with possibly unnecessary values that // could confuse people or have negative performance consequences. // // For the request to be provided in a SamplingContext, a request pointer would // most likely need to be stored in the span context and it would open precedent // for more arbitrary data like fasthttp.Request. // // Users wanting to influence the sampling decision based on the request can // still do so, either by updating the transaction directly on their HTTP // handler: // // func(w http.ResponseWriter, r *http.Request) { // transaction := sentry.TransactionFromContext(r.Context()) // if r.Header.Get("X-Custom-Sampling") == "yes" { // transaction.Sampled = sentry.SampledTrue // } else { // transaction.Sampled = sentry.SampledFalse // } // } // // Or by having their own middleware that stores arbitrary data in the request // context (a pointer to the request itself included): // // type myContextKey struct{} // type myContextData struct { // request *http.Request // // ... // } // // func middleware(h http.Handler) http.Handler { // return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // data := &myContextData{ // request: r, // } // ctx := context.WithValue(r.Context(), myContextKey{}, data) // h.ServeHTTP(w, r.WithContext(ctx)) // }) // } // // func main() { // err := sentry.Init(sentry.ClientOptions{ // // A custom TracesSampler can access data from the span's context: // TracesSampler: sentry.TracesSamplerFunc(func(ctx sentry.SamplingContext) bool { // data, ok := ctx.Span.Context().Value(myContextKey{}).(*myContextData) // if !ok { // return false // } // return data.request.URL.Hostname() == "example.com" // }), // }) // // ... // } // // Note, however, that for the middleware to be effective, it would have to run // before sentryhttp's own middleware, meaning the middleware itself is not // instrumented to send panics to Sentry and it is not part of the timed // transaction. // // If neither of those prove to be sufficient, we can consider including a // (possibly nil) *http.Request field to SamplingContext. In that case, the SDK // would need to track the request either in the Scope or the Span.Context. // // Alternatively, add a map-like type or simply a generic interface{} similar to // the CustomSamplingContext type in the Java SDK: // // type SamplingContext struct { // Span *Span // The current span, always non-nil. // Parent *Span // The parent span, may be nil. // CustomData interface{} // } // // func CustomSamplingContext(data interface{}) SpanOption { // return func(s *Span) { // s.customSamplingContext = data // } // } // // func main() { // // ... // span := sentry.StartSpan(ctx, "op", CustomSamplingContext(data)) // // ... // } // The TracesSamplerFunc type is an adapter to allow the use of ordinary // functions as a TracesSampler. type TracesSamplerFunc func(ctx SamplingContext) Sampled var _ TracesSampler = TracesSamplerFunc(nil) func (f TracesSamplerFunc) Sample(ctx SamplingContext) Sampled { return f(ctx) } // UniformTracesSampler is a TracesSampler that samples root spans randomly at a // uniform rate. type UniformTracesSampler float64 var _ TracesSampler = UniformTracesSampler(0) func (s UniformTracesSampler) Sample(ctx SamplingContext) Sampled { if s < 0.0 || s > 1.0 { panic(fmt.Errorf("sampling rate out of range [0.0, 1.0]: %f", s)) } if randutil.Float64() < float64(s) { return SampledTrue } return SampledFalse } // TODO(tracing): implement and export basic TracesSampler implementations: // parent-based, span ID / trace ID based, etc. It should be possible to compose // parent-based with other samplers. ================================================ FILE: vendor/github.com/getsentry/sentry-go/tracing.go ================================================ package sentry import ( "context" "crypto/rand" "encoding/hex" "encoding/json" "fmt" "net/http" "regexp" "strings" "time" ) // A Span is the building block of a Sentry transaction. Spans build up a tree // structure of timed operations. The span tree makes up a transaction event // that is sent to Sentry when the root span is finished. // // Spans must be started with either StartSpan or Span.StartChild. type Span struct { //nolint: maligned // prefer readability over optimal memory layout (see note below *) TraceID TraceID `json:"trace_id"` SpanID SpanID `json:"span_id"` ParentSpanID SpanID `json:"parent_span_id"` Op string `json:"op,omitempty"` Description string `json:"description,omitempty"` Status SpanStatus `json:"status,omitempty"` Tags map[string]string `json:"tags,omitempty"` StartTime time.Time `json:"start_timestamp"` EndTime time.Time `json:"timestamp"` Data map[string]interface{} `json:"data,omitempty"` Sampled Sampled `json:"-"` // ctx is the context where the span was started. Always non-nil. ctx context.Context // parent refers to the immediate local parent span. A remote parent span is // only referenced by setting ParentSpanID. parent *Span // isTransaction is true only for the root span of a local span tree. The // root span is the first span started in a context. Note that a local root // span may have a remote parent belonging to the same trace, therefore // isTransaction depends on ctx and not on parent. isTransaction bool // recorder stores all spans in a transaction. Guaranteed to be non-nil. recorder *spanRecorder } // (*) Note on maligned: // // We prefer readability over optimal memory layout. If we ever decide to // reorder fields, we can use a tool: // // go run honnef.co/go/tools/cmd/structlayout -json . Span | go run honnef.co/go/tools/cmd/structlayout-optimize // // Other structs would deserve reordering as well, for example Event. // TODO: make Span.Tags and Span.Data opaque types (struct{unexported []slice}). // An opaque type allows us to add methods and make it more convenient to use // than maps, because maps require careful nil checks to use properly or rely on // explicit initialization for every span, even when there might be no // tags/data. For Span.Data, must gracefully handle values that cannot be // marshaled into JSON (see transport.go:getRequestBodyFromEvent). // StartSpan starts a new span to describe an operation. The new span will be a // child of the last span stored in ctx, if any. // // One or more options can be used to modify the span properties. Typically one // option as a function literal is enough. Combining multiple options can be // useful to define and reuse specific properties with named functions. // // Caller should call the Finish method on the span to mark its end. Finishing a // root span sends the span and all of its children, recursively, as a // transaction to Sentry. func StartSpan(ctx context.Context, operation string, options ...SpanOption) *Span { parent, hasParent := ctx.Value(spanContextKey{}).(*Span) var span Span span = Span{ // defaults Op: operation, StartTime: time.Now(), ctx: context.WithValue(ctx, spanContextKey{}, &span), parent: parent, isTransaction: !hasParent, } if hasParent { span.TraceID = parent.TraceID } else { // Implementation note: // // While math/rand is ~2x faster than crypto/rand (exact // difference depends on hardware / OS), crypto/rand is probably // fast enough and a safer choice. // // For reference, OpenTelemetry [1] uses crypto/rand to seed // math/rand. AFAICT this approach does not preserve the // properties from crypto/rand that make it suitable for // cryptography. While it might be debatable whether those // properties are important for us here, again, we're taking the // safer path. // // See [2a] & [2b] for a discussion of some of the properties we // obtain by using crypto/rand and [3a] & [3b] for why we avoid // math/rand. // // Because the math/rand seed has only 64 bits (int64), if the // first thing we do after seeding an RNG is to read in a random // TraceID, there are only 2^64 possible values. Compared to // UUID v4 that have 122 random bits, there is a much greater // chance of collision [4a] & [4b]. // // [1]: https://github.com/open-telemetry/opentelemetry-go/blob/958041ddf619a128/sdk/trace/trace.go#L25-L31 // [2a]: https://security.stackexchange.com/q/120352/246345 // [2b]: https://security.stackexchange.com/a/120365/246345 // [3a]: https://github.com/golang/go/issues/11871#issuecomment-126333686 // [3b]: https://github.com/golang/go/issues/11871#issuecomment-126357889 // [4a]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions // [4b]: https://www.wolframalpha.com/input/?i=sqrt%282*2%5E64*ln%281%2F%281-0.5%29%29%29 _, err := rand.Read(span.TraceID[:]) if err != nil { panic(err) } } _, err := rand.Read(span.SpanID[:]) if err != nil { panic(err) } if hasParent { span.ParentSpanID = parent.SpanID } // Apply options to override defaults. for _, option := range options { option(&span) } span.Sampled = span.sample() if hasParent { span.recorder = parent.spanRecorder() } else { span.recorder = &spanRecorder{} } span.recorder.record(&span) // Update scope so that all events include a trace context, allowing // Sentry to correlate errors to transactions/spans. hubFromContext(ctx).Scope().SetContext("trace", span.traceContext()) return &span } // Finish sets the span's end time, unless already set. If the span is the root // of a span tree, Finish sends the span tree to Sentry as a transaction. func (s *Span) Finish() { // TODO(tracing): maybe make Finish run at most once, such that // (incorrectly) calling it twice never double sends to Sentry. if s.EndTime.IsZero() { s.EndTime = monotonicTimeSince(s.StartTime) } if !s.Sampled.Bool() { return } event := s.toEvent() if event == nil { return } // TODO(tracing): add breadcrumbs // (see https://github.com/getsentry/sentry-python/blob/f6f3525f8812f609/sentry_sdk/tracing.py#L372) hub := hubFromContext(s.ctx) if hub.Scope().Transaction() == "" { Logger.Printf("Missing transaction name for span with op = %q", s.Op) } hub.CaptureEvent(event) } // Context returns the context containing the span. func (s *Span) Context() context.Context { return s.ctx } // StartChild starts a new child span. // // The call span.StartChild(operation, options...) is a shortcut for // StartSpan(span.Context(), operation, options...). func (s *Span) StartChild(operation string, options ...SpanOption) *Span { return StartSpan(s.Context(), operation, options...) } // SetTag sets a tag on the span. It is recommended to use SetTag instead of // accessing the tags map directly as SetTag takes care of initializing the map // when necessary. func (s *Span) SetTag(name, value string) { if s.Tags == nil { s.Tags = make(map[string]string) } s.Tags[name] = value } // TODO(tracing): maybe add shortcuts to get/set transaction name. Right now the // transaction name is in the Scope, as it has existed there historically, prior // to tracing. // // See Scope.Transaction() and Scope.SetTransaction(). // // func (s *Span) TransactionName() string // func (s *Span) SetTransactionName(name string) // ToSentryTrace returns the trace propagation value used with the sentry-trace // HTTP header. func (s *Span) ToSentryTrace() string { // TODO(tracing): add instrumentation for outgoing HTTP requests using // ToSentryTrace. var b strings.Builder fmt.Fprintf(&b, "%s-%s", s.TraceID.Hex(), s.SpanID.Hex()) switch s.Sampled { case SampledTrue: b.WriteString("-1") case SampledFalse: b.WriteString("-0") } return b.String() } // sentryTracePattern matches either // // TRACE_ID - SPAN_ID // [[:xdigit:]]{32}-[[:xdigit:]]{16} // // or // // TRACE_ID - SPAN_ID - SAMPLED // [[:xdigit:]]{32}-[[:xdigit:]]{16}-[01] var sentryTracePattern = regexp.MustCompile(`^([[:xdigit:]]{32})-([[:xdigit:]]{16})(?:-([01]))?$`) // updateFromSentryTrace parses a sentry-trace HTTP header (as returned by // ToSentryTrace) and updates fields of the span. If the header cannot be // recognized as valid, the span is left unchanged. func (s *Span) updateFromSentryTrace(header []byte) { m := sentryTracePattern.FindSubmatch(header) if m == nil { // no match return } _, _ = hex.Decode(s.TraceID[:], m[1]) _, _ = hex.Decode(s.ParentSpanID[:], m[2]) if len(m[3]) != 0 { switch m[3][0] { case '0': s.Sampled = SampledFalse case '1': s.Sampled = SampledTrue } } } func (s *Span) MarshalJSON() ([]byte, error) { // span aliases Span to allow calling json.Marshal without an infinite loop. // It preserves all fields while none of the attached methods. type span Span var parentSpanID string if s.ParentSpanID != zeroSpanID { parentSpanID = s.ParentSpanID.String() } return json.Marshal(struct { *span ParentSpanID string `json:"parent_span_id,omitempty"` }{ span: (*span)(s), ParentSpanID: parentSpanID, }) } func (s *Span) sample() Sampled { // https://develop.sentry.dev/sdk/unified-api/tracing/#sampling // #1 explicit sampling decision via StartSpan options. if s.Sampled != SampledUndefined { return s.Sampled } hub := hubFromContext(s.ctx) var clientOptions ClientOptions client := hub.Client() if client != nil { clientOptions = hub.Client().Options() } samplingContext := SamplingContext{Span: s, Parent: s.parent} // Variant for non-transaction spans: they inherit the parent decision. // TracesSampler only runs for the root span. // Note: non-transaction should always have a parent, but we check both // conditions anyway -- the first for semantic meaning, the second to // avoid a nil pointer dereference. if !s.isTransaction && s.parent != nil { return s.parent.Sampled } // #2 use TracesSampler from ClientOptions. sampler := clientOptions.TracesSampler if sampler != nil { return sampler.Sample(samplingContext) } // #3 inherit parent decision. if s.parent != nil { return s.parent.Sampled } // #4 uniform sampling using TracesSampleRate. sampler = UniformTracesSampler(clientOptions.TracesSampleRate) return sampler.Sample(samplingContext) } func (s *Span) toEvent() *Event { if !s.isTransaction { return nil // only transactions can be transformed into events } hub := hubFromContext(s.ctx) children := s.recorder.children() finished := make([]*Span, 0, len(children)) for _, child := range children { if child.EndTime.IsZero() { Logger.Printf("Dropped unfinished span: Op=%q TraceID=%s SpanID=%s", child.Op, child.TraceID, child.SpanID) continue } finished = append(finished, child) } return &Event{ Type: transactionType, Transaction: hub.Scope().Transaction(), Contexts: map[string]interface{}{ "trace": s.traceContext(), }, Tags: s.Tags, Extra: s.Data, Timestamp: s.EndTime, StartTime: s.StartTime, Spans: finished, } } func (s *Span) traceContext() *TraceContext { return &TraceContext{ TraceID: s.TraceID, SpanID: s.SpanID, ParentSpanID: s.ParentSpanID, Op: s.Op, Description: s.Description, Status: s.Status, } } // spanRecorder stores the span tree. Guaranteed to be non-nil. func (s *Span) spanRecorder() *spanRecorder { return s.recorder } // TraceID identifies a trace. type TraceID [16]byte func (id TraceID) Hex() []byte { b := make([]byte, hex.EncodedLen(len(id))) hex.Encode(b, id[:]) return b } func (id TraceID) String() string { return string(id.Hex()) } func (id TraceID) MarshalText() ([]byte, error) { return id.Hex(), nil } // SpanID identifies a span. type SpanID [8]byte func (id SpanID) Hex() []byte { b := make([]byte, hex.EncodedLen(len(id))) hex.Encode(b, id[:]) return b } func (id SpanID) String() string { return string(id.Hex()) } func (id SpanID) MarshalText() ([]byte, error) { return id.Hex(), nil } // Zero values of TraceID and SpanID used for comparisons. var ( zeroTraceID TraceID zeroSpanID SpanID ) // SpanStatus is the status of a span. type SpanStatus uint8 // Implementation note: // // In Relay (ingestion), the SpanStatus type is an enum used as // Annotated when embedded in structs, making it effectively // Option. It means the status is either null or one of the known // string values. // // In Snuba (search), the SpanStatus is stored as an uint8 and defaulted to 2 // ("unknown") when not set. It means that Discover searches for // `transaction.status:unknown` return both transactions/spans with status // `null` or `"unknown"`. Searches for `transaction.status:""` return nothing. // // With that in mind, the Go SDK default is SpanStatusUndefined, which is // null/omitted when serializing to JSON, but integrations may update the status // automatically based on contextual information. const ( SpanStatusUndefined SpanStatus = iota SpanStatusOK SpanStatusCanceled SpanStatusUnknown SpanStatusInvalidArgument SpanStatusDeadlineExceeded SpanStatusNotFound SpanStatusAlreadyExists SpanStatusPermissionDenied SpanStatusResourceExhausted SpanStatusFailedPrecondition SpanStatusAborted SpanStatusOutOfRange SpanStatusUnimplemented SpanStatusInternalError SpanStatusUnavailable SpanStatusDataLoss SpanStatusUnauthenticated maxSpanStatus ) func (ss SpanStatus) String() string { if ss >= maxSpanStatus { return "" } m := [maxSpanStatus]string{ "", "ok", "cancelled", // [sic] "unknown", "invalid_argument", "deadline_exceeded", "not_found", "already_exists", "permission_denied", "resource_exhausted", "failed_precondition", "aborted", "out_of_range", "unimplemented", "internal_error", "unavailable", "data_loss", "unauthenticated", } return m[ss] } func (ss SpanStatus) MarshalJSON() ([]byte, error) { s := ss.String() if s == "" { return []byte("null"), nil } return json.Marshal(s) } // A TraceContext carries information about an ongoing trace and is meant to be // stored in Event.Contexts (as *TraceContext). type TraceContext struct { TraceID TraceID `json:"trace_id"` SpanID SpanID `json:"span_id"` ParentSpanID SpanID `json:"parent_span_id"` Op string `json:"op,omitempty"` Description string `json:"description,omitempty"` Status SpanStatus `json:"status,omitempty"` } func (tc *TraceContext) MarshalJSON() ([]byte, error) { // traceContext aliases TraceContext to allow calling json.Marshal without // an infinite loop. It preserves all fields while none of the attached // methods. type traceContext TraceContext var parentSpanID string if tc.ParentSpanID != zeroSpanID { parentSpanID = tc.ParentSpanID.String() } return json.Marshal(struct { *traceContext ParentSpanID string `json:"parent_span_id,omitempty"` }{ traceContext: (*traceContext)(tc), ParentSpanID: parentSpanID, }) } // Sampled signifies a sampling decision. type Sampled int8 // The possible trace sampling decisions are: SampledFalse, SampledUndefined // (default) and SampledTrue. const ( SampledFalse Sampled = -1 + iota SampledUndefined SampledTrue ) func (s Sampled) String() string { switch s { case SampledFalse: return "SampledFalse" case SampledUndefined: return "SampledUndefined" case SampledTrue: return "SampledTrue" default: return fmt.Sprintf("SampledInvalid(%d)", s) } } // Bool returns true if the sample decision is SampledTrue, false otherwise. func (s Sampled) Bool() bool { return s == SampledTrue } // A SpanOption is a function that can modify the properties of a span. type SpanOption func(s *Span) // The TransactionName option sets the name of the current transaction. // // A span tree has a single transaction name, therefore using this option when // starting a span affects the span tree as a whole, potentially overwriting a // name set previously. func TransactionName(name string) SpanOption { return func(s *Span) { hubFromContext(s.Context()).Scope().SetTransaction(name) } } // ContinueFromRequest returns a span option that updates the span to continue // an existing trace. If it cannot detect an existing trace in the request, the // span will be left unchanged. func ContinueFromRequest(r *http.Request) SpanOption { return func(s *Span) { trace := r.Header.Get("sentry-trace") if trace == "" { return } s.updateFromSentryTrace([]byte(trace)) } } // spanContextKey is used to store span values in contexts. type spanContextKey struct{} // TransactionFromContext returns the root span of the current transaction. It // returns nil if no transaction is tracked in the context. func TransactionFromContext(ctx context.Context) *Span { if span, ok := ctx.Value(spanContextKey{}).(*Span); ok { return span.recorder.root() } return nil } // spanFromContext returns the last span stored in the context or a dummy // non-nil span. // // TODO(tracing): consider exporting this. Without this, users cannot retrieve a // span from a context since spanContextKey is not exported. // // This can be added retroactively, and in the meantime think better whether it // should return nil (like GetHubFromContext), always non-nil (like // HubFromContext), or both: two exported functions. // // Note the equivalence: // // SpanFromContext(ctx).StartChild(...) === StartSpan(ctx, ...) // // So we don't aim spanFromContext at creating spans, but mutating existing // spans that you'd have no access otherwise (because it was created in code you // do not control, for example SDK auto-instrumentation). // // For now we provide TransactionFromContext, which solves the more common case // of setting tags, etc, on the current transaction. func spanFromContext(ctx context.Context) *Span { if span, ok := ctx.Value(spanContextKey{}).(*Span); ok { return span } return nil } ================================================ FILE: vendor/github.com/getsentry/sentry-go/transport.go ================================================ package sentry import ( "bytes" "crypto/tls" "encoding/json" "errors" "fmt" "io" "io/ioutil" "net/http" "net/url" "sync" "time" "github.com/getsentry/sentry-go/internal/ratelimit" ) const defaultBufferSize = 30 const defaultTimeout = time.Second * 30 // maxDrainResponseBytes is the maximum number of bytes that transport // implementations will read from response bodies when draining them. // // Sentry's ingestion API responses are typically short and the SDK doesn't need // the contents of the response body. However, the net/http HTTP client requires // response bodies to be fully drained (and closed) for TCP keep-alive to work. // // maxDrainResponseBytes strikes a balance between reading too much data (if the // server is misbehaving) and reusing TCP connections. const maxDrainResponseBytes = 16 << 10 // Transport is used by the Client to deliver events to remote server. type Transport interface { Flush(timeout time.Duration) bool Configure(options ClientOptions) SendEvent(event *Event) } func getProxyConfig(options ClientOptions) func(*http.Request) (*url.URL, error) { if options.HTTPSProxy != "" { return func(_ *http.Request) (*url.URL, error) { return url.Parse(options.HTTPSProxy) } } else if options.HTTPProxy != "" { return func(_ *http.Request) (*url.URL, error) { return url.Parse(options.HTTPProxy) } } return http.ProxyFromEnvironment } func getTLSConfig(options ClientOptions) *tls.Config { if options.CaCerts != nil { return &tls.Config{ RootCAs: options.CaCerts, } } return nil } func getRequestBodyFromEvent(event *Event) []byte { body, err := json.Marshal(event) if err == nil { return body } msg := fmt.Sprintf("Could not encode original event as JSON. "+ "Succeeded by removing Breadcrumbs, Contexts and Extra. "+ "Please verify the data you attach to the scope. "+ "Error: %s", err) // Try to serialize the event, with all the contextual data that allows for interface{} stripped. event.Breadcrumbs = nil event.Contexts = nil event.Extra = map[string]interface{}{ "info": msg, } body, err = json.Marshal(event) if err == nil { Logger.Println(msg) return body } // This should _only_ happen when Event.Exception[0].Stacktrace.Frames[0].Vars is unserializable // Which won't ever happen, as we don't use it now (although it's the part of public interface accepted by Sentry) // Juuust in case something, somehow goes utterly wrong. Logger.Println("Event couldn't be marshaled, even with stripped contextual data. Skipping delivery. " + "Please notify the SDK owners with possibly broken payload.") return nil } func transactionEnvelopeFromBody(eventID EventID, sentAt time.Time, body json.RawMessage) (*bytes.Buffer, error) { var b bytes.Buffer enc := json.NewEncoder(&b) // envelope header err := enc.Encode(struct { EventID EventID `json:"event_id"` SentAt time.Time `json:"sent_at"` }{ EventID: eventID, SentAt: sentAt, }) if err != nil { return nil, err } // item header err = enc.Encode(struct { Type string `json:"type"` Length int `json:"length"` }{ Type: transactionType, Length: len(body), }) if err != nil { return nil, err } // payload err = enc.Encode(body) if err != nil { return nil, err } return &b, nil } func getRequestFromEvent(event *Event, dsn *Dsn) (r *http.Request, err error) { defer func() { if r != nil { r.Header.Set("User-Agent", userAgent) } }() body := getRequestBodyFromEvent(event) if body == nil { return nil, errors.New("event could not be marshaled") } if event.Type == transactionType { b, err := transactionEnvelopeFromBody(event.EventID, time.Now(), body) if err != nil { return nil, err } return http.NewRequest( http.MethodPost, dsn.EnvelopeAPIURL().String(), b, ) } return http.NewRequest( http.MethodPost, dsn.StoreAPIURL().String(), bytes.NewReader(body), ) } func categoryFor(eventType string) ratelimit.Category { switch eventType { case "": return ratelimit.CategoryError case transactionType: return ratelimit.CategoryTransaction default: return ratelimit.Category(eventType) } } // ================================ // HTTPTransport // ================================ // A batch groups items that are processed sequentially. type batch struct { items chan batchItem started chan struct{} // closed to signal items started to be worked on done chan struct{} // closed to signal completion of all items } type batchItem struct { request *http.Request category ratelimit.Category } // HTTPTransport is the default, non-blocking, implementation of Transport. // // Clients using this transport will enqueue requests in a buffer and return to // the caller before any network communication has happened. Requests are sent // to Sentry sequentially from a background goroutine. type HTTPTransport struct { dsn *Dsn client *http.Client transport http.RoundTripper // buffer is a channel of batches. Calling Flush terminates work on the // current in-flight items and starts a new batch for subsequent events. buffer chan batch start sync.Once // Size of the transport buffer. Defaults to 30. BufferSize int // HTTP Client request timeout. Defaults to 30 seconds. Timeout time.Duration mu sync.RWMutex limits ratelimit.Map } // NewHTTPTransport returns a new pre-configured instance of HTTPTransport. func NewHTTPTransport() *HTTPTransport { transport := HTTPTransport{ BufferSize: defaultBufferSize, Timeout: defaultTimeout, limits: make(ratelimit.Map), } return &transport } // Configure is called by the Client itself, providing it it's own ClientOptions. func (t *HTTPTransport) Configure(options ClientOptions) { dsn, err := NewDsn(options.Dsn) if err != nil { Logger.Printf("%v\n", err) return } t.dsn = dsn // A buffered channel with capacity 1 works like a mutex, ensuring only one // goroutine can access the current batch at a given time. Access is // synchronized by reading from and writing to the channel. t.buffer = make(chan batch, 1) t.buffer <- batch{ items: make(chan batchItem, t.BufferSize), started: make(chan struct{}), done: make(chan struct{}), } if options.HTTPTransport != nil { t.transport = options.HTTPTransport } else { t.transport = &http.Transport{ Proxy: getProxyConfig(options), TLSClientConfig: getTLSConfig(options), } } if options.HTTPClient != nil { t.client = options.HTTPClient } else { t.client = &http.Client{ Transport: t.transport, Timeout: t.Timeout, } } t.start.Do(func() { go t.worker() }) } // SendEvent assembles a new packet out of Event and sends it to remote server. func (t *HTTPTransport) SendEvent(event *Event) { if t.dsn == nil { return } category := categoryFor(event.Type) if t.disabled(category) { return } request, err := getRequestFromEvent(event, t.dsn) if err != nil { return } for headerKey, headerValue := range t.dsn.RequestHeaders() { request.Header.Set(headerKey, headerValue) } // <-t.buffer is equivalent to acquiring a lock to access the current batch. // A few lines below, t.buffer <- b releases the lock. // // The lock must be held during the select block below to guarantee that // b.items is not closed while trying to send to it. Remember that sending // on a closed channel panics. // // Note that the select block takes a bounded amount of CPU time because of // the default case that is executed if sending on b.items would block. That // is, the event is dropped if it cannot be sent immediately to the b.items // channel (used as a queue). b := <-t.buffer select { case b.items <- batchItem{ request: request, category: category, }: var eventType string if event.Type == transactionType { eventType = "transaction" } else { eventType = fmt.Sprintf("%s event", event.Level) } Logger.Printf( "Sending %s [%s] to %s project: %d", eventType, event.EventID, t.dsn.host, t.dsn.projectID, ) default: Logger.Println("Event dropped due to transport buffer being full.") } t.buffer <- b } // Flush waits until any buffered events are sent to the Sentry server, blocking // for at most the given timeout. It returns false if the timeout was reached. // In that case, some events may not have been sent. // // Flush should be called before terminating the program to avoid // unintentionally dropping events. // // Do not call Flush indiscriminately after every call to SendEvent. Instead, to // have the SDK send events over the network synchronously, configure it to use // the HTTPSyncTransport in the call to Init. func (t *HTTPTransport) Flush(timeout time.Duration) bool { toolate := time.After(timeout) // Wait until processing the current batch has started or the timeout. // // We must wait until the worker has seen the current batch, because it is // the only way b.done will be closed. If we do not wait, there is a // possible execution flow in which b.done is never closed, and the only way // out of Flush would be waiting for the timeout, which is undesired. var b batch for { select { case b = <-t.buffer: select { case <-b.started: goto started default: t.buffer <- b } case <-toolate: goto fail } } started: // Signal that there won't be any more items in this batch, so that the // worker inner loop can end. close(b.items) // Start a new batch for subsequent events. t.buffer <- batch{ items: make(chan batchItem, t.BufferSize), started: make(chan struct{}), done: make(chan struct{}), } // Wait until the current batch is done or the timeout. select { case <-b.done: Logger.Println("Buffer flushed successfully.") return true case <-toolate: goto fail } fail: Logger.Println("Buffer flushing reached the timeout.") return false } func (t *HTTPTransport) worker() { for b := range t.buffer { // Signal that processing of the current batch has started. close(b.started) // Return the batch to the buffer so that other goroutines can use it. // Equivalent to releasing a lock. t.buffer <- b // Process all batch items. for item := range b.items { if t.disabled(item.category) { continue } response, err := t.client.Do(item.request) if err != nil { Logger.Printf("There was an issue with sending an event: %v", err) continue } t.mu.Lock() t.limits.Merge(ratelimit.FromResponse(response)) t.mu.Unlock() // Drain body up to a limit and close it, allowing the // transport to reuse TCP connections. _, _ = io.CopyN(ioutil.Discard, response.Body, maxDrainResponseBytes) response.Body.Close() } // Signal that processing of the batch is done. close(b.done) } } func (t *HTTPTransport) disabled(c ratelimit.Category) bool { t.mu.RLock() defer t.mu.RUnlock() disabled := t.limits.IsRateLimited(c) if disabled { Logger.Printf("Too many requests for %q, backing off till: %v", c, t.limits.Deadline(c)) } return disabled } // ================================ // HTTPSyncTransport // ================================ // HTTPSyncTransport is a blocking implementation of Transport. // // Clients using this transport will send requests to Sentry sequentially and // block until a response is returned. // // The blocking behavior is useful in a limited set of use cases. For example, // use it when deploying code to a Function as a Service ("Serverless") // platform, where any work happening in a background goroutine is not // guaranteed to execute. // // For most cases, prefer HTTPTransport. type HTTPSyncTransport struct { dsn *Dsn client *http.Client transport http.RoundTripper mu sync.Mutex limits ratelimit.Map // HTTP Client request timeout. Defaults to 30 seconds. Timeout time.Duration } // NewHTTPSyncTransport returns a new pre-configured instance of HTTPSyncTransport. func NewHTTPSyncTransport() *HTTPSyncTransport { transport := HTTPSyncTransport{ Timeout: defaultTimeout, limits: make(ratelimit.Map), } return &transport } // Configure is called by the Client itself, providing it it's own ClientOptions. func (t *HTTPSyncTransport) Configure(options ClientOptions) { dsn, err := NewDsn(options.Dsn) if err != nil { Logger.Printf("%v\n", err) return } t.dsn = dsn if options.HTTPTransport != nil { t.transport = options.HTTPTransport } else { t.transport = &http.Transport{ Proxy: getProxyConfig(options), TLSClientConfig: getTLSConfig(options), } } if options.HTTPClient != nil { t.client = options.HTTPClient } else { t.client = &http.Client{ Transport: t.transport, Timeout: t.Timeout, } } } // SendEvent assembles a new packet out of Event and sends it to remote server. func (t *HTTPSyncTransport) SendEvent(event *Event) { if t.dsn == nil { return } if t.disabled(categoryFor(event.Type)) { return } request, err := getRequestFromEvent(event, t.dsn) if err != nil { return } for headerKey, headerValue := range t.dsn.RequestHeaders() { request.Header.Set(headerKey, headerValue) } var eventType string if event.Type == transactionType { eventType = "transaction" } else { eventType = fmt.Sprintf("%s event", event.Level) } Logger.Printf( "Sending %s [%s] to %s project: %d", eventType, event.EventID, t.dsn.host, t.dsn.projectID, ) response, err := t.client.Do(request) if err != nil { Logger.Printf("There was an issue with sending an event: %v", err) return } t.mu.Lock() t.limits.Merge(ratelimit.FromResponse(response)) t.mu.Unlock() // Drain body up to a limit and close it, allowing the // transport to reuse TCP connections. _, _ = io.CopyN(ioutil.Discard, response.Body, maxDrainResponseBytes) response.Body.Close() } // Flush is a no-op for HTTPSyncTransport. It always returns true immediately. func (t *HTTPSyncTransport) Flush(_ time.Duration) bool { return true } func (t *HTTPSyncTransport) disabled(c ratelimit.Category) bool { t.mu.Lock() defer t.mu.Unlock() disabled := t.limits.IsRateLimited(c) if disabled { Logger.Printf("Too many requests for %q, backing off till: %v", c, t.limits.Deadline(c)) } return disabled } // ================================ // noopTransport // ================================ // noopTransport is an implementation of Transport interface which drops all the events. // Only used internally when an empty DSN is provided, which effectively disables the SDK. type noopTransport struct{} func (t *noopTransport) Configure(options ClientOptions) { Logger.Println("Sentry client initialized with an empty DSN. Using noopTransport. No events will be delivered.") } func (t *noopTransport) SendEvent(event *Event) { Logger.Println("Event dropped due to noopTransport usage.") } func (t *noopTransport) Flush(_ time.Duration) bool { return true } ================================================ FILE: vendor/github.com/getsentry/sentry-go/util.go ================================================ package sentry import ( "crypto/rand" "encoding/hex" "encoding/json" "fmt" "os" "time" ) func uuid() string { id := make([]byte, 16) // Prefer rand.Read over rand.Reader, see https://go-review.googlesource.com/c/go/+/272326/. _, _ = rand.Read(id) id[6] &= 0x0F // clear version id[6] |= 0x40 // set version to 4 (random uuid) id[8] &= 0x3F // clear variant id[8] |= 0x80 // set to IETF variant return hex.EncodeToString(id) } func fileExists(fileName string) bool { _, err := os.Stat(fileName) return err == nil } // monotonicTimeSince replaces uses of time.Now() to take into account the // monotonic clock reading stored in start, such that duration = end - start is // unaffected by changes in the system wall clock. func monotonicTimeSince(start time.Time) (end time.Time) { return start.Add(time.Since(start)) } //nolint: deadcode, unused func prettyPrint(data interface{}) { dbg, _ := json.MarshalIndent(data, "", " ") fmt.Println(string(dbg)) } ================================================ FILE: vendor/github.com/go-logr/logr/.golangci.yaml ================================================ run: timeout: 1m tests: true linters: disable-all: true enable: - asciicheck - errcheck - forcetypeassert - gocritic - gofmt - goimports - gosimple - govet - ineffassign - misspell - revive - staticcheck - typecheck - unused issues: exclude-use-default: false max-issues-per-linter: 0 max-same-issues: 10 ================================================ FILE: vendor/github.com/go-logr/logr/CHANGELOG.md ================================================ # CHANGELOG ## v1.0.0-rc1 This is the first logged release. Major changes (including breaking changes) have occurred since earlier tags. ================================================ FILE: vendor/github.com/go-logr/logr/CONTRIBUTING.md ================================================ # Contributing Logr is open to pull-requests, provided they fit within the intended scope of the project. Specifically, this library aims to be VERY small and minimalist, with no external dependencies. ## Compatibility This project intends to follow [semantic versioning](http://semver.org) and is very strict about compatibility. Any proposed changes MUST follow those rules. ## Performance As a logging library, logr must be as light-weight as possible. Any proposed code change must include results of running the [benchmark](./benchmark) before and after the change. ================================================ FILE: vendor/github.com/go-logr/logr/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/go-logr/logr/README.md ================================================ # A minimal logging API for Go [![Go Reference](https://pkg.go.dev/badge/github.com/go-logr/logr.svg)](https://pkg.go.dev/github.com/go-logr/logr) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-logr/logr/badge)](https://securityscorecards.dev/viewer/?platform=github.com&org=go-logr&repo=logr) logr offers an(other) opinion on how Go programs and libraries can do logging without becoming coupled to a particular logging implementation. This is not an implementation of logging - it is an API. In fact it is two APIs with two different sets of users. The `Logger` type is intended for application and library authors. It provides a relatively small API which can be used everywhere you want to emit logs. It defers the actual act of writing logs (to files, to stdout, or whatever) to the `LogSink` interface. The `LogSink` interface is intended for logging library implementers. It is a pure interface which can be implemented by logging frameworks to provide the actual logging functionality. This decoupling allows application and library developers to write code in terms of `logr.Logger` (which has very low dependency fan-out) while the implementation of logging is managed "up stack" (e.g. in or near `main()`.) Application developers can then switch out implementations as necessary. Many people assert that libraries should not be logging, and as such efforts like this are pointless. Those people are welcome to convince the authors of the tens-of-thousands of libraries that *DO* write logs that they are all wrong. In the meantime, logr takes a more practical approach. ## Typical usage Somewhere, early in an application's life, it will make a decision about which logging library (implementation) it actually wants to use. Something like: ``` func main() { // ... other setup code ... // Create the "root" logger. We have chosen the "logimpl" implementation, // which takes some initial parameters and returns a logr.Logger. logger := logimpl.New(param1, param2) // ... other setup code ... ``` Most apps will call into other libraries, create structures to govern the flow, etc. The `logr.Logger` object can be passed to these other libraries, stored in structs, or even used as a package-global variable, if needed. For example: ``` app := createTheAppObject(logger) app.Run() ``` Outside of this early setup, no other packages need to know about the choice of implementation. They write logs in terms of the `logr.Logger` that they received: ``` type appObject struct { // ... other fields ... logger logr.Logger // ... other fields ... } func (app *appObject) Run() { app.logger.Info("starting up", "timestamp", time.Now()) // ... app code ... ``` ## Background If the Go standard library had defined an interface for logging, this project probably would not be needed. Alas, here we are. When the Go developers started developing such an interface with [slog](https://github.com/golang/go/issues/56345), they adopted some of the logr design but also left out some parts and changed others: | Feature | logr | slog | |---------|------|------| | High-level API | `Logger` (passed by value) | `Logger` (passed by [pointer](https://github.com/golang/go/issues/59126)) | | Low-level API | `LogSink` | `Handler` | | Stack unwinding | done by `LogSink` | done by `Logger` | | Skipping helper functions | `WithCallDepth`, `WithCallStackHelper` | [not supported by Logger](https://github.com/golang/go/issues/59145) | | Generating a value for logging on demand | `Marshaler` | `LogValuer` | | Log levels | >= 0, higher meaning "less important" | positive and negative, with 0 for "info" and higher meaning "more important" | | Error log entries | always logged, don't have a verbosity level | normal log entries with level >= `LevelError` | | Passing logger via context | `NewContext`, `FromContext` | no API | | Adding a name to a logger | `WithName` | no API | | Modify verbosity of log entries in a call chain | `V` | no API | | Grouping of key/value pairs | not supported | `WithGroup`, `GroupValue` | | Pass context for extracting additional values | no API | API variants like `InfoCtx` | The high-level slog API is explicitly meant to be one of many different APIs that can be layered on top of a shared `slog.Handler`. logr is one such alternative API, with [interoperability](#slog-interoperability) provided by some conversion functions. ### Inspiration Before you consider this package, please read [this blog post by the inimitable Dave Cheney][warning-makes-no-sense]. We really appreciate what he has to say, and it largely aligns with our own experiences. ### Differences from Dave's ideas The main differences are: 1. Dave basically proposes doing away with the notion of a logging API in favor of `fmt.Printf()`. We disagree, especially when you consider things like output locations, timestamps, file and line decorations, and structured logging. This package restricts the logging API to just 2 types of logs: info and error. Info logs are things you want to tell the user which are not errors. Error logs are, well, errors. If your code receives an `error` from a subordinate function call and is logging that `error` *and not returning it*, use error logs. 2. Verbosity-levels on info logs. This gives developers a chance to indicate arbitrary grades of importance for info logs, without assigning names with semantic meaning such as "warning", "trace", and "debug." Superficially this may feel very similar, but the primary difference is the lack of semantics. Because verbosity is a numerical value, it's safe to assume that an app running with higher verbosity means more (and less important) logs will be generated. ## Implementations (non-exhaustive) There are implementations for the following logging libraries: - **a function** (can bridge to non-structured libraries): [funcr](https://github.com/go-logr/logr/tree/master/funcr) - **a testing.T** (for use in Go tests, with JSON-like output): [testr](https://github.com/go-logr/logr/tree/master/testr) - **github.com/google/glog**: [glogr](https://github.com/go-logr/glogr) - **k8s.io/klog** (for Kubernetes): [klogr](https://git.k8s.io/klog/klogr) - **a testing.T** (with klog-like text output): [ktesting](https://git.k8s.io/klog/ktesting) - **go.uber.org/zap**: [zapr](https://github.com/go-logr/zapr) - **log** (the Go standard library logger): [stdr](https://github.com/go-logr/stdr) - **github.com/sirupsen/logrus**: [logrusr](https://github.com/bombsimon/logrusr) - **github.com/wojas/genericr**: [genericr](https://github.com/wojas/genericr) (makes it easy to implement your own backend) - **logfmt** (Heroku style [logging](https://www.brandur.org/logfmt)): [logfmtr](https://github.com/iand/logfmtr) - **github.com/rs/zerolog**: [zerologr](https://github.com/go-logr/zerologr) - **github.com/go-kit/log**: [gokitlogr](https://github.com/tonglil/gokitlogr) (also compatible with github.com/go-kit/kit/log since v0.12.0) - **bytes.Buffer** (writing to a buffer): [bufrlogr](https://github.com/tonglil/buflogr) (useful for ensuring values were logged, like during testing) ## slog interoperability Interoperability goes both ways, using the `logr.Logger` API with a `slog.Handler` and using the `slog.Logger` API with a `logr.LogSink`. `FromSlogHandler` and `ToSlogHandler` convert between a `logr.Logger` and a `slog.Handler`. As usual, `slog.New` can be used to wrap such a `slog.Handler` in the high-level slog API. ### Using a `logr.LogSink` as backend for slog Ideally, a logr sink implementation should support both logr and slog by implementing both the normal logr interface(s) and `SlogSink`. Because of a conflict in the parameters of the common `Enabled` method, it is [not possible to implement both slog.Handler and logr.Sink in the same type](https://github.com/golang/go/issues/59110). If both are supported, log calls can go from the high-level APIs to the backend without the need to convert parameters. `FromSlogHandler` and `ToSlogHandler` can convert back and forth without adding additional wrappers, with one exception: when `Logger.V` was used to adjust the verbosity for a `slog.Handler`, then `ToSlogHandler` has to use a wrapper which adjusts the verbosity for future log calls. Such an implementation should also support values that implement specific interfaces from both packages for logging (`logr.Marshaler`, `slog.LogValuer`, `slog.GroupValue`). logr does not convert those. Not supporting slog has several drawbacks: - Recording source code locations works correctly if the handler gets called through `slog.Logger`, but may be wrong in other cases. That's because a `logr.Sink` does its own stack unwinding instead of using the program counter provided by the high-level API. - slog levels <= 0 can be mapped to logr levels by negating the level without a loss of information. But all slog levels > 0 (e.g. `slog.LevelWarning` as used by `slog.Logger.Warn`) must be mapped to 0 before calling the sink because logr does not support "more important than info" levels. - The slog group concept is supported by prefixing each key in a key/value pair with the group names, separated by a dot. For structured output like JSON it would be better to group the key/value pairs inside an object. - Special slog values and interfaces don't work as expected. - The overhead is likely to be higher. These drawbacks are severe enough that applications using a mixture of slog and logr should switch to a different backend. ### Using a `slog.Handler` as backend for logr Using a plain `slog.Handler` without support for logr works better than the other direction: - All logr verbosity levels can be mapped 1:1 to their corresponding slog level by negating them. - Stack unwinding is done by the `SlogSink` and the resulting program counter is passed to the `slog.Handler`. - Names added via `Logger.WithName` are gathered and recorded in an additional attribute with `logger` as key and the names separated by slash as value. - `Logger.Error` is turned into a log record with `slog.LevelError` as level and an additional attribute with `err` as key, if an error was provided. The main drawback is that `logr.Marshaler` will not be supported. Types should ideally support both `logr.Marshaler` and `slog.Valuer`. If compatibility with logr implementations without slog support is not important, then `slog.Valuer` is sufficient. ### Context support for slog Storing a logger in a `context.Context` is not supported by slog. `NewContextWithSlogLogger` and `FromContextAsSlogLogger` can be used to fill this gap. They store and retrieve a `slog.Logger` pointer under the same context key that is also used by `NewContext` and `FromContext` for `logr.Logger` value. When `NewContextWithSlogLogger` is followed by `FromContext`, the latter will automatically convert the `slog.Logger` to a `logr.Logger`. `FromContextAsSlogLogger` does the same for the other direction. With this approach, binaries which use either slog or logr are as efficient as possible with no unnecessary allocations. This is also why the API stores a `slog.Logger` pointer: when storing a `slog.Handler`, creating a `slog.Logger` on retrieval would need to allocate one. The downside is that switching back and forth needs more allocations. Because logr is the API that is already in use by different packages, in particular Kubernetes, the recommendation is to use the `logr.Logger` API in code which uses contextual logging. An alternative to adding values to a logger and storing that logger in the context is to store the values in the context and to configure a logging backend to extract those values when emitting log entries. This only works when log calls are passed the context, which is not supported by the logr API. With the slog API, it is possible, but not required. https://github.com/veqryn/slog-context is a package for slog which provides additional support code for this approach. It also contains wrappers for the context functions in logr, so developers who prefer to not use the logr APIs directly can use those instead and the resulting code will still be interoperable with logr. ## FAQ ### Conceptual #### Why structured logging? - **Structured logs are more easily queryable**: Since you've got key-value pairs, it's much easier to query your structured logs for particular values by filtering on the contents of a particular key -- think searching request logs for error codes, Kubernetes reconcilers for the name and namespace of the reconciled object, etc. - **Structured logging makes it easier to have cross-referenceable logs**: Similarly to searchability, if you maintain conventions around your keys, it becomes easy to gather all log lines related to a particular concept. - **Structured logs allow better dimensions of filtering**: if you have structure to your logs, you've got more precise control over how much information is logged -- you might choose in a particular configuration to log certain keys but not others, only log lines where a certain key matches a certain value, etc., instead of just having v-levels and names to key off of. - **Structured logs better represent structured data**: sometimes, the data that you want to log is inherently structured (think tuple-link objects.) Structured logs allow you to preserve that structure when outputting. #### Why V-levels? **V-levels give operators an easy way to control the chattiness of log operations**. V-levels provide a way for a given package to distinguish the relative importance or verbosity of a given log message. Then, if a particular logger or package is logging too many messages, the user of the package can simply change the v-levels for that library. #### Why not named levels, like Info/Warning/Error? Read [Dave Cheney's post][warning-makes-no-sense]. Then read [Differences from Dave's ideas](#differences-from-daves-ideas). #### Why not allow format strings, too? **Format strings negate many of the benefits of structured logs**: - They're not easily searchable without resorting to fuzzy searching, regular expressions, etc. - They don't store structured data well, since contents are flattened into a string. - They're not cross-referenceable. - They don't compress easily, since the message is not constant. (Unless you turn positional parameters into key-value pairs with numerical keys, at which point you've gotten key-value logging with meaningless keys.) ### Practical #### Why key-value pairs, and not a map? Key-value pairs are *much* easier to optimize, especially around allocations. Zap (a structured logger that inspired logr's interface) has [performance measurements](https://github.com/uber-go/zap#performance) that show this quite nicely. While the interface ends up being a little less obvious, you get potentially better performance, plus avoid making users type `map[string]string{}` every time they want to log. #### What if my V-levels differ between libraries? That's fine. Control your V-levels on a per-logger basis, and use the `WithName` method to pass different loggers to different libraries. Generally, you should take care to ensure that you have relatively consistent V-levels within a given logger, however, as this makes deciding on what verbosity of logs to request easier. #### But I really want to use a format string! That's not actually a question. Assuming your question is "how do I convert my mental model of logging with format strings to logging with constant messages": 1. Figure out what the error actually is, as you'd write in a TL;DR style, and use that as a message. 2. For every place you'd write a format specifier, look to the word before it, and add that as a key value pair. For instance, consider the following examples (all taken from spots in the Kubernetes codebase): - `klog.V(4).Infof("Client is returning errors: code %v, error %v", responseCode, err)` becomes `logger.Error(err, "client returned an error", "code", responseCode)` - `klog.V(4).Infof("Got a Retry-After %ds response for attempt %d to %v", seconds, retries, url)` becomes `logger.V(4).Info("got a retry-after response when requesting url", "attempt", retries, "after seconds", seconds, "url", url)` If you *really* must use a format string, use it in a key's value, and call `fmt.Sprintf` yourself. For instance: `log.Printf("unable to reflect over type %T")` becomes `logger.Info("unable to reflect over type", "type", fmt.Sprintf("%T"))`. In general though, the cases where this is necessary should be few and far between. #### How do I choose my V-levels? This is basically the only hard constraint: increase V-levels to denote more verbose or more debug-y logs. Otherwise, you can start out with `0` as "you always want to see this", `1` as "common logging that you might *possibly* want to turn off", and `10` as "I would like to performance-test your log collection stack." Then gradually choose levels in between as you need them, working your way down from 10 (for debug and trace style logs) and up from 1 (for chattier info-type logs). For reference, slog pre-defines -4 for debug logs (corresponds to 4 in logr), which matches what is [recommended for Kubernetes](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md#what-method-to-use). #### How do I choose my keys? Keys are fairly flexible, and can hold more or less any string value. For best compatibility with implementations and consistency with existing code in other projects, there are a few conventions you should consider. - Make your keys human-readable. - Constant keys are generally a good idea. - Be consistent across your codebase. - Keys should naturally match parts of the message string. - Use lower case for simple keys and [lowerCamelCase](https://en.wiktionary.org/wiki/lowerCamelCase) for more complex ones. Kubernetes is one example of a project that has [adopted that convention](https://github.com/kubernetes/community/blob/HEAD/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments). While key names are mostly unrestricted (and spaces are acceptable), it's generally a good idea to stick to printable ascii characters, or at least match the general character set of your log lines. #### Why should keys be constant values? The point of structured logging is to make later log processing easier. Your keys are, effectively, the schema of each log message. If you use different keys across instances of the same log line, you will make your structured logs much harder to use. `Sprintf()` is for values, not for keys! #### Why is this not a pure interface? The Logger type is implemented as a struct in order to allow the Go compiler to optimize things like high-V `Info` logs that are not triggered. Not all of these implementations are implemented yet, but this structure was suggested as a way to ensure they *can* be implemented. All of the real work is behind the `LogSink` interface. [warning-makes-no-sense]: http://dave.cheney.net/2015/11/05/lets-talk-about-logging ================================================ FILE: vendor/github.com/go-logr/logr/SECURITY.md ================================================ # Security Policy If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. You may submit the report in the following ways: - send an email to go-logr-security@googlegroups.com - send us a [private vulnerability report](https://github.com/go-logr/logr/security/advisories/new) Please provide the following information in your report: - A description of the vulnerability and its impact - How to reproduce the issue We ask that you give us 90 days to work on a fix before public exposure. ================================================ FILE: vendor/github.com/go-logr/logr/context.go ================================================ /* Copyright 2023 The logr Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package logr // contextKey is how we find Loggers in a context.Context. With Go < 1.21, // the value is always a Logger value. With Go >= 1.21, the value can be a // Logger value or a slog.Logger pointer. type contextKey struct{} // notFoundError exists to carry an IsNotFound method. type notFoundError struct{} func (notFoundError) Error() string { return "no logr.Logger was present" } func (notFoundError) IsNotFound() bool { return true } ================================================ FILE: vendor/github.com/go-logr/logr/context_noslog.go ================================================ //go:build !go1.21 // +build !go1.21 /* Copyright 2019 The logr Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package logr import ( "context" ) // FromContext returns a Logger from ctx or an error if no Logger is found. func FromContext(ctx context.Context) (Logger, error) { if v, ok := ctx.Value(contextKey{}).(Logger); ok { return v, nil } return Logger{}, notFoundError{} } // FromContextOrDiscard returns a Logger from ctx. If no Logger is found, this // returns a Logger that discards all log messages. func FromContextOrDiscard(ctx context.Context) Logger { if v, ok := ctx.Value(contextKey{}).(Logger); ok { return v } return Discard() } // NewContext returns a new Context, derived from ctx, which carries the // provided Logger. func NewContext(ctx context.Context, logger Logger) context.Context { return context.WithValue(ctx, contextKey{}, logger) } ================================================ FILE: vendor/github.com/go-logr/logr/context_slog.go ================================================ //go:build go1.21 // +build go1.21 /* Copyright 2019 The logr Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package logr import ( "context" "fmt" "log/slog" ) // FromContext returns a Logger from ctx or an error if no Logger is found. func FromContext(ctx context.Context) (Logger, error) { v := ctx.Value(contextKey{}) if v == nil { return Logger{}, notFoundError{} } switch v := v.(type) { case Logger: return v, nil case *slog.Logger: return FromSlogHandler(v.Handler()), nil default: // Not reached. panic(fmt.Sprintf("unexpected value type for logr context key: %T", v)) } } // FromContextAsSlogLogger returns a slog.Logger from ctx or nil if no such Logger is found. func FromContextAsSlogLogger(ctx context.Context) *slog.Logger { v := ctx.Value(contextKey{}) if v == nil { return nil } switch v := v.(type) { case Logger: return slog.New(ToSlogHandler(v)) case *slog.Logger: return v default: // Not reached. panic(fmt.Sprintf("unexpected value type for logr context key: %T", v)) } } // FromContextOrDiscard returns a Logger from ctx. If no Logger is found, this // returns a Logger that discards all log messages. func FromContextOrDiscard(ctx context.Context) Logger { if logger, err := FromContext(ctx); err == nil { return logger } return Discard() } // NewContext returns a new Context, derived from ctx, which carries the // provided Logger. func NewContext(ctx context.Context, logger Logger) context.Context { return context.WithValue(ctx, contextKey{}, logger) } // NewContextWithSlogLogger returns a new Context, derived from ctx, which carries the // provided slog.Logger. func NewContextWithSlogLogger(ctx context.Context, logger *slog.Logger) context.Context { return context.WithValue(ctx, contextKey{}, logger) } ================================================ FILE: vendor/github.com/go-logr/logr/discard.go ================================================ /* Copyright 2020 The logr Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package logr // Discard returns a Logger that discards all messages logged to it. It can be // used whenever the caller is not interested in the logs. Logger instances // produced by this function always compare as equal. func Discard() Logger { return New(nil) } ================================================ FILE: vendor/github.com/go-logr/logr/logr.go ================================================ /* Copyright 2019 The logr Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // This design derives from Dave Cheney's blog: // http://dave.cheney.net/2015/11/05/lets-talk-about-logging // Package logr defines a general-purpose logging API and abstract interfaces // to back that API. Packages in the Go ecosystem can depend on this package, // while callers can implement logging with whatever backend is appropriate. // // # Usage // // Logging is done using a Logger instance. Logger is a concrete type with // methods, which defers the actual logging to a LogSink interface. The main // methods of Logger are Info() and Error(). Arguments to Info() and Error() // are key/value pairs rather than printf-style formatted strings, emphasizing // "structured logging". // // With Go's standard log package, we might write: // // log.Printf("setting target value %s", targetValue) // // With logr's structured logging, we'd write: // // logger.Info("setting target", "value", targetValue) // // Errors are much the same. Instead of: // // log.Printf("failed to open the pod bay door for user %s: %v", user, err) // // We'd write: // // logger.Error(err, "failed to open the pod bay door", "user", user) // // Info() and Error() are very similar, but they are separate methods so that // LogSink implementations can choose to do things like attach additional // information (such as stack traces) on calls to Error(). Error() messages are // always logged, regardless of the current verbosity. If there is no error // instance available, passing nil is valid. // // # Verbosity // // Often we want to log information only when the application in "verbose // mode". To write log lines that are more verbose, Logger has a V() method. // The higher the V-level of a log line, the less critical it is considered. // Log-lines with V-levels that are not enabled (as per the LogSink) will not // be written. Level V(0) is the default, and logger.V(0).Info() has the same // meaning as logger.Info(). Negative V-levels have the same meaning as V(0). // Error messages do not have a verbosity level and are always logged. // // Where we might have written: // // if flVerbose >= 2 { // log.Printf("an unusual thing happened") // } // // We can write: // // logger.V(2).Info("an unusual thing happened") // // # Logger Names // // Logger instances can have name strings so that all messages logged through // that instance have additional context. For example, you might want to add // a subsystem name: // // logger.WithName("compactor").Info("started", "time", time.Now()) // // The WithName() method returns a new Logger, which can be passed to // constructors or other functions for further use. Repeated use of WithName() // will accumulate name "segments". These name segments will be joined in some // way by the LogSink implementation. It is strongly recommended that name // segments contain simple identifiers (letters, digits, and hyphen), and do // not contain characters that could muddle the log output or confuse the // joining operation (e.g. whitespace, commas, periods, slashes, brackets, // quotes, etc). // // # Saved Values // // Logger instances can store any number of key/value pairs, which will be // logged alongside all messages logged through that instance. For example, // you might want to create a Logger instance per managed object: // // With the standard log package, we might write: // // log.Printf("decided to set field foo to value %q for object %s/%s", // targetValue, object.Namespace, object.Name) // // With logr we'd write: // // // Elsewhere: set up the logger to log the object name. // obj.logger = mainLogger.WithValues( // "name", obj.name, "namespace", obj.namespace) // // // later on... // obj.logger.Info("setting foo", "value", targetValue) // // # Best Practices // // Logger has very few hard rules, with the goal that LogSink implementations // might have a lot of freedom to differentiate. There are, however, some // things to consider. // // The log message consists of a constant message attached to the log line. // This should generally be a simple description of what's occurring, and should // never be a format string. Variable information can then be attached using // named values. // // Keys are arbitrary strings, but should generally be constant values. Values // may be any Go value, but how the value is formatted is determined by the // LogSink implementation. // // Logger instances are meant to be passed around by value. Code that receives // such a value can call its methods without having to check whether the // instance is ready for use. // // The zero logger (= Logger{}) is identical to Discard() and discards all log // entries. Code that receives a Logger by value can simply call it, the methods // will never crash. For cases where passing a logger is optional, a pointer to Logger // should be used. // // # Key Naming Conventions // // Keys are not strictly required to conform to any specification or regex, but // it is recommended that they: // - be human-readable and meaningful (not auto-generated or simple ordinals) // - be constant (not dependent on input data) // - contain only printable characters // - not contain whitespace or punctuation // - use lower case for simple keys and lowerCamelCase for more complex ones // // These guidelines help ensure that log data is processed properly regardless // of the log implementation. For example, log implementations will try to // output JSON data or will store data for later database (e.g. SQL) queries. // // While users are generally free to use key names of their choice, it's // generally best to avoid using the following keys, as they're frequently used // by implementations: // - "caller": the calling information (file/line) of a particular log line // - "error": the underlying error value in the `Error` method // - "level": the log level // - "logger": the name of the associated logger // - "msg": the log message // - "stacktrace": the stack trace associated with a particular log line or // error (often from the `Error` message) // - "ts": the timestamp for a log line // // Implementations are encouraged to make use of these keys to represent the // above concepts, when necessary (for example, in a pure-JSON output form, it // would be necessary to represent at least message and timestamp as ordinary // named values). // // # Break Glass // // Implementations may choose to give callers access to the underlying // logging implementation. The recommended pattern for this is: // // // Underlier exposes access to the underlying logging implementation. // // Since callers only have a logr.Logger, they have to know which // // implementation is in use, so this interface is less of an abstraction // // and more of way to test type conversion. // type Underlier interface { // GetUnderlying() // } // // Logger grants access to the sink to enable type assertions like this: // // func DoSomethingWithImpl(log logr.Logger) { // if underlier, ok := log.GetSink().(impl.Underlier); ok { // implLogger := underlier.GetUnderlying() // ... // } // } // // Custom `With*` functions can be implemented by copying the complete // Logger struct and replacing the sink in the copy: // // // WithFooBar changes the foobar parameter in the log sink and returns a // // new logger with that modified sink. It does nothing for loggers where // // the sink doesn't support that parameter. // func WithFoobar(log logr.Logger, foobar int) logr.Logger { // if foobarLogSink, ok := log.GetSink().(FoobarSink); ok { // log = log.WithSink(foobarLogSink.WithFooBar(foobar)) // } // return log // } // // Don't use New to construct a new Logger with a LogSink retrieved from an // existing Logger. Source code attribution might not work correctly and // unexported fields in Logger get lost. // // Beware that the same LogSink instance may be shared by different logger // instances. Calling functions that modify the LogSink will affect all of // those. package logr // New returns a new Logger instance. This is primarily used by libraries // implementing LogSink, rather than end users. Passing a nil sink will create // a Logger which discards all log lines. func New(sink LogSink) Logger { logger := Logger{} logger.setSink(sink) if sink != nil { sink.Init(runtimeInfo) } return logger } // setSink stores the sink and updates any related fields. It mutates the // logger and thus is only safe to use for loggers that are not currently being // used concurrently. func (l *Logger) setSink(sink LogSink) { l.sink = sink } // GetSink returns the stored sink. func (l Logger) GetSink() LogSink { return l.sink } // WithSink returns a copy of the logger with the new sink. func (l Logger) WithSink(sink LogSink) Logger { l.setSink(sink) return l } // Logger is an interface to an abstract logging implementation. This is a // concrete type for performance reasons, but all the real work is passed on to // a LogSink. Implementations of LogSink should provide their own constructors // that return Logger, not LogSink. // // The underlying sink can be accessed through GetSink and be modified through // WithSink. This enables the implementation of custom extensions (see "Break // Glass" in the package documentation). Normally the sink should be used only // indirectly. type Logger struct { sink LogSink level int } // Enabled tests whether this Logger is enabled. For example, commandline // flags might be used to set the logging verbosity and disable some info logs. func (l Logger) Enabled() bool { // Some implementations of LogSink look at the caller in Enabled (e.g. // different verbosity levels per package or file), but we only pass one // CallDepth in (via Init). This means that all calls from Logger to the // LogSink's Enabled, Info, and Error methods must have the same number of // frames. In other words, Logger methods can't call other Logger methods // which call these LogSink methods unless we do it the same in all paths. return l.sink != nil && l.sink.Enabled(l.level) } // Info logs a non-error message with the given key/value pairs as context. // // The msg argument should be used to add some constant description to the log // line. The key/value pairs can then be used to add additional variable // information. The key/value pairs must alternate string keys and arbitrary // values. func (l Logger) Info(msg string, keysAndValues ...any) { if l.sink == nil { return } if l.sink.Enabled(l.level) { // see comment in Enabled if withHelper, ok := l.sink.(CallStackHelperLogSink); ok { withHelper.GetCallStackHelper()() } l.sink.Info(l.level, msg, keysAndValues...) } } // Error logs an error, with the given message and key/value pairs as context. // It functions similarly to Info, but may have unique behavior, and should be // preferred for logging errors (see the package documentations for more // information). The log message will always be emitted, regardless of // verbosity level. // // The msg argument should be used to add context to any underlying error, // while the err argument should be used to attach the actual error that // triggered this log line, if present. The err parameter is optional // and nil may be passed instead of an error instance. func (l Logger) Error(err error, msg string, keysAndValues ...any) { if l.sink == nil { return } if withHelper, ok := l.sink.(CallStackHelperLogSink); ok { withHelper.GetCallStackHelper()() } l.sink.Error(err, msg, keysAndValues...) } // V returns a new Logger instance for a specific verbosity level, relative to // this Logger. In other words, V-levels are additive. A higher verbosity // level means a log message is less important. Negative V-levels are treated // as 0. func (l Logger) V(level int) Logger { if l.sink == nil { return l } if level < 0 { level = 0 } l.level += level return l } // GetV returns the verbosity level of the logger. If the logger's LogSink is // nil as in the Discard logger, this will always return 0. func (l Logger) GetV() int { // 0 if l.sink nil because of the if check in V above. return l.level } // WithValues returns a new Logger instance with additional key/value pairs. // See Info for documentation on how key/value pairs work. func (l Logger) WithValues(keysAndValues ...any) Logger { if l.sink == nil { return l } l.setSink(l.sink.WithValues(keysAndValues...)) return l } // WithName returns a new Logger instance with the specified name element added // to the Logger's name. Successive calls with WithName append additional // suffixes to the Logger's name. It's strongly recommended that name segments // contain only letters, digits, and hyphens (see the package documentation for // more information). func (l Logger) WithName(name string) Logger { if l.sink == nil { return l } l.setSink(l.sink.WithName(name)) return l } // WithCallDepth returns a Logger instance that offsets the call stack by the // specified number of frames when logging call site information, if possible. // This is useful for users who have helper functions between the "real" call // site and the actual calls to Logger methods. If depth is 0 the attribution // should be to the direct caller of this function. If depth is 1 the // attribution should skip 1 call frame, and so on. Successive calls to this // are additive. // // If the underlying log implementation supports a WithCallDepth(int) method, // it will be called and the result returned. If the implementation does not // support CallDepthLogSink, the original Logger will be returned. // // To skip one level, WithCallStackHelper() should be used instead of // WithCallDepth(1) because it works with implementions that support the // CallDepthLogSink and/or CallStackHelperLogSink interfaces. func (l Logger) WithCallDepth(depth int) Logger { if l.sink == nil { return l } if withCallDepth, ok := l.sink.(CallDepthLogSink); ok { l.setSink(withCallDepth.WithCallDepth(depth)) } return l } // WithCallStackHelper returns a new Logger instance that skips the direct // caller when logging call site information, if possible. This is useful for // users who have helper functions between the "real" call site and the actual // calls to Logger methods and want to support loggers which depend on marking // each individual helper function, like loggers based on testing.T. // // In addition to using that new logger instance, callers also must call the // returned function. // // If the underlying log implementation supports a WithCallDepth(int) method, // WithCallDepth(1) will be called to produce a new logger. If it supports a // WithCallStackHelper() method, that will be also called. If the // implementation does not support either of these, the original Logger will be // returned. func (l Logger) WithCallStackHelper() (func(), Logger) { if l.sink == nil { return func() {}, l } var helper func() if withCallDepth, ok := l.sink.(CallDepthLogSink); ok { l.setSink(withCallDepth.WithCallDepth(1)) } if withHelper, ok := l.sink.(CallStackHelperLogSink); ok { helper = withHelper.GetCallStackHelper() } else { helper = func() {} } return helper, l } // IsZero returns true if this logger is an uninitialized zero value func (l Logger) IsZero() bool { return l.sink == nil } // RuntimeInfo holds information that the logr "core" library knows which // LogSinks might want to know. type RuntimeInfo struct { // CallDepth is the number of call frames the logr library adds between the // end-user and the LogSink. LogSink implementations which choose to print // the original logging site (e.g. file & line) should climb this many // additional frames to find it. CallDepth int } // runtimeInfo is a static global. It must not be changed at run time. var runtimeInfo = RuntimeInfo{ CallDepth: 1, } // LogSink represents a logging implementation. End-users will generally not // interact with this type. type LogSink interface { // Init receives optional information about the logr library for LogSink // implementations that need it. Init(info RuntimeInfo) // Enabled tests whether this LogSink is enabled at the specified V-level. // For example, commandline flags might be used to set the logging // verbosity and disable some info logs. Enabled(level int) bool // Info logs a non-error message with the given key/value pairs as context. // The level argument is provided for optional logging. This method will // only be called when Enabled(level) is true. See Logger.Info for more // details. Info(level int, msg string, keysAndValues ...any) // Error logs an error, with the given message and key/value pairs as // context. See Logger.Error for more details. Error(err error, msg string, keysAndValues ...any) // WithValues returns a new LogSink with additional key/value pairs. See // Logger.WithValues for more details. WithValues(keysAndValues ...any) LogSink // WithName returns a new LogSink with the specified name appended. See // Logger.WithName for more details. WithName(name string) LogSink } // CallDepthLogSink represents a LogSink that knows how to climb the call stack // to identify the original call site and can offset the depth by a specified // number of frames. This is useful for users who have helper functions // between the "real" call site and the actual calls to Logger methods. // Implementations that log information about the call site (such as file, // function, or line) would otherwise log information about the intermediate // helper functions. // // This is an optional interface and implementations are not required to // support it. type CallDepthLogSink interface { // WithCallDepth returns a LogSink that will offset the call // stack by the specified number of frames when logging call // site information. // // If depth is 0, the LogSink should skip exactly the number // of call frames defined in RuntimeInfo.CallDepth when Info // or Error are called, i.e. the attribution should be to the // direct caller of Logger.Info or Logger.Error. // // If depth is 1 the attribution should skip 1 call frame, and so on. // Successive calls to this are additive. WithCallDepth(depth int) LogSink } // CallStackHelperLogSink represents a LogSink that knows how to climb // the call stack to identify the original call site and can skip // intermediate helper functions if they mark themselves as // helper. Go's testing package uses that approach. // // This is useful for users who have helper functions between the // "real" call site and the actual calls to Logger methods. // Implementations that log information about the call site (such as // file, function, or line) would otherwise log information about the // intermediate helper functions. // // This is an optional interface and implementations are not required // to support it. Implementations that choose to support this must not // simply implement it as WithCallDepth(1), because // Logger.WithCallStackHelper will call both methods if they are // present. This should only be implemented for LogSinks that actually // need it, as with testing.T. type CallStackHelperLogSink interface { // GetCallStackHelper returns a function that must be called // to mark the direct caller as helper function when logging // call site information. GetCallStackHelper() func() } // Marshaler is an optional interface that logged values may choose to // implement. Loggers with structured output, such as JSON, should // log the object return by the MarshalLog method instead of the // original value. type Marshaler interface { // MarshalLog can be used to: // - ensure that structs are not logged as strings when the original // value has a String method: return a different type without a // String method // - select which fields of a complex type should get logged: // return a simpler struct with fewer fields // - log unexported fields: return a different struct // with exported fields // // It may return any value of any type. MarshalLog() any } ================================================ FILE: vendor/github.com/go-logr/logr/sloghandler.go ================================================ //go:build go1.21 // +build go1.21 /* Copyright 2023 The logr Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package logr import ( "context" "log/slog" ) type slogHandler struct { // May be nil, in which case all logs get discarded. sink LogSink // Non-nil if sink is non-nil and implements SlogSink. slogSink SlogSink // groupPrefix collects values from WithGroup calls. It gets added as // prefix to value keys when handling a log record. groupPrefix string // levelBias can be set when constructing the handler to influence the // slog.Level of log records. A positive levelBias reduces the // slog.Level value. slog has no API to influence this value after the // handler got created, so it can only be set indirectly through // Logger.V. levelBias slog.Level } var _ slog.Handler = &slogHandler{} // groupSeparator is used to concatenate WithGroup names and attribute keys. const groupSeparator = "." // GetLevel is used for black box unit testing. func (l *slogHandler) GetLevel() slog.Level { return l.levelBias } func (l *slogHandler) Enabled(_ context.Context, level slog.Level) bool { return l.sink != nil && (level >= slog.LevelError || l.sink.Enabled(l.levelFromSlog(level))) } func (l *slogHandler) Handle(ctx context.Context, record slog.Record) error { if l.slogSink != nil { // Only adjust verbosity level of log entries < slog.LevelError. if record.Level < slog.LevelError { record.Level -= l.levelBias } return l.slogSink.Handle(ctx, record) } // No need to check for nil sink here because Handle will only be called // when Enabled returned true. kvList := make([]any, 0, 2*record.NumAttrs()) record.Attrs(func(attr slog.Attr) bool { kvList = attrToKVs(attr, l.groupPrefix, kvList) return true }) if record.Level >= slog.LevelError { l.sinkWithCallDepth().Error(nil, record.Message, kvList...) } else { level := l.levelFromSlog(record.Level) l.sinkWithCallDepth().Info(level, record.Message, kvList...) } return nil } // sinkWithCallDepth adjusts the stack unwinding so that when Error or Info // are called by Handle, code in slog gets skipped. // // This offset currently (Go 1.21.0) works for calls through // slog.New(ToSlogHandler(...)). There's no guarantee that the call // chain won't change. Wrapping the handler will also break unwinding. It's // still better than not adjusting at all.... // // This cannot be done when constructing the handler because FromSlogHandler needs // access to the original sink without this adjustment. A second copy would // work, but then WithAttrs would have to be called for both of them. func (l *slogHandler) sinkWithCallDepth() LogSink { if sink, ok := l.sink.(CallDepthLogSink); ok { return sink.WithCallDepth(2) } return l.sink } func (l *slogHandler) WithAttrs(attrs []slog.Attr) slog.Handler { if l.sink == nil || len(attrs) == 0 { return l } clone := *l if l.slogSink != nil { clone.slogSink = l.slogSink.WithAttrs(attrs) clone.sink = clone.slogSink } else { kvList := make([]any, 0, 2*len(attrs)) for _, attr := range attrs { kvList = attrToKVs(attr, l.groupPrefix, kvList) } clone.sink = l.sink.WithValues(kvList...) } return &clone } func (l *slogHandler) WithGroup(name string) slog.Handler { if l.sink == nil { return l } if name == "" { // slog says to inline empty groups return l } clone := *l if l.slogSink != nil { clone.slogSink = l.slogSink.WithGroup(name) clone.sink = clone.slogSink } else { clone.groupPrefix = addPrefix(clone.groupPrefix, name) } return &clone } // attrToKVs appends a slog.Attr to a logr-style kvList. It handle slog Groups // and other details of slog. func attrToKVs(attr slog.Attr, groupPrefix string, kvList []any) []any { attrVal := attr.Value.Resolve() if attrVal.Kind() == slog.KindGroup { groupVal := attrVal.Group() grpKVs := make([]any, 0, 2*len(groupVal)) prefix := groupPrefix if attr.Key != "" { prefix = addPrefix(groupPrefix, attr.Key) } for _, attr := range groupVal { grpKVs = attrToKVs(attr, prefix, grpKVs) } kvList = append(kvList, grpKVs...) } else if attr.Key != "" { kvList = append(kvList, addPrefix(groupPrefix, attr.Key), attrVal.Any()) } return kvList } func addPrefix(prefix, name string) string { if prefix == "" { return name } if name == "" { return prefix } return prefix + groupSeparator + name } // levelFromSlog adjusts the level by the logger's verbosity and negates it. // It ensures that the result is >= 0. This is necessary because the result is // passed to a LogSink and that API did not historically document whether // levels could be negative or what that meant. // // Some example usage: // // logrV0 := getMyLogger() // logrV2 := logrV0.V(2) // slogV2 := slog.New(logr.ToSlogHandler(logrV2)) // slogV2.Debug("msg") // =~ logrV2.V(4) =~ logrV0.V(6) // slogV2.Info("msg") // =~ logrV2.V(0) =~ logrV0.V(2) // slogv2.Warn("msg") // =~ logrV2.V(-4) =~ logrV0.V(0) func (l *slogHandler) levelFromSlog(level slog.Level) int { result := -level result += l.levelBias // in case the original Logger had a V level if result < 0 { result = 0 // because LogSink doesn't expect negative V levels } return int(result) } ================================================ FILE: vendor/github.com/go-logr/logr/slogr.go ================================================ //go:build go1.21 // +build go1.21 /* Copyright 2023 The logr Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package logr import ( "context" "log/slog" ) // FromSlogHandler returns a Logger which writes to the slog.Handler. // // The logr verbosity level is mapped to slog levels such that V(0) becomes // slog.LevelInfo and V(4) becomes slog.LevelDebug. func FromSlogHandler(handler slog.Handler) Logger { if handler, ok := handler.(*slogHandler); ok { if handler.sink == nil { return Discard() } return New(handler.sink).V(int(handler.levelBias)) } return New(&slogSink{handler: handler}) } // ToSlogHandler returns a slog.Handler which writes to the same sink as the Logger. // // The returned logger writes all records with level >= slog.LevelError as // error log entries with LogSink.Error, regardless of the verbosity level of // the Logger: // // logger := // slog.New(ToSlogHandler(logger.V(10))).Error(...) -> logSink.Error(...) // // The level of all other records gets reduced by the verbosity // level of the Logger and the result is negated. If it happens // to be negative, then it gets replaced by zero because a LogSink // is not expected to handled negative levels: // // slog.New(ToSlogHandler(logger)).Debug(...) -> logger.GetSink().Info(level=4, ...) // slog.New(ToSlogHandler(logger)).Warning(...) -> logger.GetSink().Info(level=0, ...) // slog.New(ToSlogHandler(logger)).Info(...) -> logger.GetSink().Info(level=0, ...) // slog.New(ToSlogHandler(logger.V(4))).Info(...) -> logger.GetSink().Info(level=4, ...) func ToSlogHandler(logger Logger) slog.Handler { if sink, ok := logger.GetSink().(*slogSink); ok && logger.GetV() == 0 { return sink.handler } handler := &slogHandler{sink: logger.GetSink(), levelBias: slog.Level(logger.GetV())} if slogSink, ok := handler.sink.(SlogSink); ok { handler.slogSink = slogSink } return handler } // SlogSink is an optional interface that a LogSink can implement to support // logging through the slog.Logger or slog.Handler APIs better. It then should // also support special slog values like slog.Group. When used as a // slog.Handler, the advantages are: // // - stack unwinding gets avoided in favor of logging the pre-recorded PC, // as intended by slog // - proper grouping of key/value pairs via WithGroup // - verbosity levels > slog.LevelInfo can be recorded // - less overhead // // Both APIs (Logger and slog.Logger/Handler) then are supported equally // well. Developers can pick whatever API suits them better and/or mix // packages which use either API in the same binary with a common logging // implementation. // // This interface is necessary because the type implementing the LogSink // interface cannot also implement the slog.Handler interface due to the // different prototype of the common Enabled method. // // An implementation could support both interfaces in two different types, but then // additional interfaces would be needed to convert between those types in FromSlogHandler // and ToSlogHandler. type SlogSink interface { LogSink Handle(ctx context.Context, record slog.Record) error WithAttrs(attrs []slog.Attr) SlogSink WithGroup(name string) SlogSink } ================================================ FILE: vendor/github.com/go-logr/logr/slogsink.go ================================================ //go:build go1.21 // +build go1.21 /* Copyright 2023 The logr Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package logr import ( "context" "log/slog" "runtime" "time" ) var ( _ LogSink = &slogSink{} _ CallDepthLogSink = &slogSink{} _ Underlier = &slogSink{} ) // Underlier is implemented by the LogSink returned by NewFromLogHandler. type Underlier interface { // GetUnderlying returns the Handler used by the LogSink. GetUnderlying() slog.Handler } const ( // nameKey is used to log the `WithName` values as an additional attribute. nameKey = "logger" // errKey is used to log the error parameter of Error as an additional attribute. errKey = "err" ) type slogSink struct { callDepth int name string handler slog.Handler } func (l *slogSink) Init(info RuntimeInfo) { l.callDepth = info.CallDepth } func (l *slogSink) GetUnderlying() slog.Handler { return l.handler } func (l *slogSink) WithCallDepth(depth int) LogSink { newLogger := *l newLogger.callDepth += depth return &newLogger } func (l *slogSink) Enabled(level int) bool { return l.handler.Enabled(context.Background(), slog.Level(-level)) } func (l *slogSink) Info(level int, msg string, kvList ...interface{}) { l.log(nil, msg, slog.Level(-level), kvList...) } func (l *slogSink) Error(err error, msg string, kvList ...interface{}) { l.log(err, msg, slog.LevelError, kvList...) } func (l *slogSink) log(err error, msg string, level slog.Level, kvList ...interface{}) { var pcs [1]uintptr // skip runtime.Callers, this function, Info/Error, and all helper functions above that. runtime.Callers(3+l.callDepth, pcs[:]) record := slog.NewRecord(time.Now(), level, msg, pcs[0]) if l.name != "" { record.AddAttrs(slog.String(nameKey, l.name)) } if err != nil { record.AddAttrs(slog.Any(errKey, err)) } record.Add(kvList...) _ = l.handler.Handle(context.Background(), record) } func (l slogSink) WithName(name string) LogSink { if l.name != "" { l.name += "/" } l.name += name return &l } func (l slogSink) WithValues(kvList ...interface{}) LogSink { l.handler = l.handler.WithAttrs(kvListToAttrs(kvList...)) return &l } func kvListToAttrs(kvList ...interface{}) []slog.Attr { // We don't need the record itself, only its Add method. record := slog.NewRecord(time.Time{}, 0, "", 0) record.Add(kvList...) attrs := make([]slog.Attr, 0, record.NumAttrs()) record.Attrs(func(attr slog.Attr) bool { attrs = append(attrs, attr) return true }) return attrs } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/.gitignore ================================================ .DS_Store .DS_Store? ._* .Spotlight-V100 .Trashes Icon? ehthumbs.db Thumbs.db .idea ================================================ FILE: vendor/github.com/go-sql-driver/mysql/AUTHORS ================================================ # This is the official list of Go-MySQL-Driver authors for copyright purposes. # If you are submitting a patch, please add your name or the name of the # organization which holds the copyright to this list in alphabetical order. # Names should be added to this file as # Name # The email address is not required for organizations. # Please keep the list sorted. # Individual Persons Aaron Hopkins Achille Roussel Aidan Alex Snast Alexey Palazhchenko Andrew Reid Animesh Ray Arne Hormann Ariel Mashraki Asta Xie Brian Hendriks Bulat Gaifullin Caine Jette Carlos Nieto Chris Kirkland Chris Moos Craig Wilson Daemonxiao <735462752 at qq.com> Daniel Montoya Daniel Nichter Daniël van Eeden Dave Protasowski DisposaBoy Egor Smolyakov Erwan Martin Evan Elias Evan Shaw Frederick Mayle Gustavo Kristic Gusted Hajime Nakagami Hanno Braun Henri Yandell Hirotaka Yamamoto Huyiguang ICHINOSE Shogo Ilia Cimpoes INADA Naoki Jacek Szwec James Harr Janek Vedock Jason Ng Jean-Yves Pellé Jeff Hodges Jeffrey Charles Jennifer Purevsuren Jerome Meyer Jiajia Zhong Jian Zhen Joshua Prunier Julien Lefevre Julien Schmidt Justin Li Justin Nuß Kamil Dziedzic Kei Kamikawa Kevin Malachowski Kieron Woodhouse Lance Tian Lennart Rudolph Leonardo YongUk Kim Linh Tran Tuan Lion Yang Luca Looz Lucas Liu Lunny Xiao Luke Scott Maciej Zimnoch Michael Woolnough Nathanial Murphy Nicola Peduzzi Oliver Bone Olivier Mengué oscarzhao Paul Bonser Paulius Lozys Peter Schultz Phil Porada Rebecca Chin Reed Allman Richard Wilkes Robert Russell Runrioter Wung Samantha Frank Santhosh Kumar Tekuri Sho Iizuka Sho Ikeda Shuode Li Simon J Mudd Soroush Pour Stan Putrya Stanley Gunawan Steven Hartland Tan Jinhua <312841925 at qq.com> Tetsuro Aoki Thomas Wodarek Tim Ruffles Tom Jenkinson Vladimir Kovpak Vladyslav Zhelezniak Xiangyu Hu Xiaobing Jiang Xiuming Chen Xuehong Chan Zhang Xiang Zhenye Xie Zhixin Wen Ziheng Lyu # Organizations Barracuda Networks, Inc. Counting Ltd. DigitalOcean Inc. Dolthub Inc. dyves labs AG Facebook Inc. GitHub Inc. Google Inc. InfoSum Ltd. Keybase Inc. Microsoft Corp. Multiplay Ltd. Percona LLC PingCAP Inc. Pivotal Inc. Shattered Silicon Ltd. Stripe Inc. Zendesk Inc. ================================================ FILE: vendor/github.com/go-sql-driver/mysql/CHANGELOG.md ================================================ ## Version 1.7.1 (2023-04-25) Changes: - bump actions/checkout@v3 and actions/setup-go@v3 (#1375) - Add go1.20 and mariadb10.11 to the testing matrix (#1403) - Increase default maxAllowedPacket size. (#1411) Bugfixes: - Use SET syntax as specified in the MySQL documentation (#1402) ## Version 1.7 (2022-11-29) Changes: - Drop support of Go 1.12 (#1211) - Refactoring `(*textRows).readRow` in a more clear way (#1230) - util: Reduce boundary check in escape functions. (#1316) - enhancement for mysqlConn handleAuthResult (#1250) New Features: - support Is comparison on MySQLError (#1210) - return unsigned in database type name when necessary (#1238) - Add API to express like a --ssl-mode=PREFERRED MySQL client (#1370) - Add SQLState to MySQLError (#1321) Bugfixes: - Fix parsing 0 year. (#1257) ## Version 1.6 (2021-04-01) Changes: - Migrate the CI service from travis-ci to GitHub Actions (#1176, #1183, #1190) - `NullTime` is deprecated (#960, #1144) - Reduce allocations when building SET command (#1111) - Performance improvement for time formatting (#1118) - Performance improvement for time parsing (#1098, #1113) New Features: - Implement `driver.Validator` interface (#1106, #1174) - Support returning `uint64` from `Valuer` in `ConvertValue` (#1143) - Add `json.RawMessage` for converter and prepared statement (#1059) - Interpolate `json.RawMessage` as `string` (#1058) - Implements `CheckNamedValue` (#1090) Bugfixes: - Stop rounding times (#1121, #1172) - Put zero filler into the SSL handshake packet (#1066) - Fix checking cancelled connections back into the connection pool (#1095) - Fix remove last 0 byte for mysql_old_password when password is empty (#1133) ## Version 1.5 (2020-01-07) Changes: - Dropped support Go 1.9 and lower (#823, #829, #886, #1016, #1017) - Improve buffer handling (#890) - Document potentially insecure TLS configs (#901) - Use a double-buffering scheme to prevent data races (#943) - Pass uint64 values without converting them to string (#838, #955) - Update collations and make utf8mb4 default (#877, #1054) - Make NullTime compatible with sql.NullTime in Go 1.13+ (#995) - Removed CloudSQL support (#993, #1007) - Add Go Module support (#1003) New Features: - Implement support of optional TLS (#900) - Check connection liveness (#934, #964, #997, #1048, #1051, #1052) - Implement Connector Interface (#941, #958, #1020, #1035) Bugfixes: - Mark connections as bad on error during ping (#875) - Mark connections as bad on error during dial (#867) - Fix connection leak caused by rapid context cancellation (#1024) - Mark connections as bad on error during Conn.Prepare (#1030) ## Version 1.4.1 (2018-11-14) Bugfixes: - Fix TIME format for binary columns (#818) - Fix handling of empty auth plugin names (#835) - Fix caching_sha2_password with empty password (#826) - Fix canceled context broke mysqlConn (#862) - Fix OldAuthSwitchRequest support (#870) - Fix Auth Response packet for cleartext password (#887) ## Version 1.4 (2018-06-03) Changes: - Documentation fixes (#530, #535, #567) - Refactoring (#575, #579, #580, #581, #603, #615, #704) - Cache column names (#444) - Sort the DSN parameters in DSNs generated from a config (#637) - Allow native password authentication by default (#644) - Use the default port if it is missing in the DSN (#668) - Removed the `strict` mode (#676) - Do not query `max_allowed_packet` by default (#680) - Dropped support Go 1.6 and lower (#696) - Updated `ConvertValue()` to match the database/sql/driver implementation (#760) - Document the usage of `0000-00-00T00:00:00` as the time.Time zero value (#783) - Improved the compatibility of the authentication system (#807) New Features: - Multi-Results support (#537) - `rejectReadOnly` DSN option (#604) - `context.Context` support (#608, #612, #627, #761) - Transaction isolation level support (#619, #744) - Read-Only transactions support (#618, #634) - `NewConfig` function which initializes a config with default values (#679) - Implemented the `ColumnType` interfaces (#667, #724) - Support for custom string types in `ConvertValue` (#623) - Implemented `NamedValueChecker`, improving support for uint64 with high bit set (#690, #709, #710) - `caching_sha2_password` authentication plugin support (#794, #800, #801, #802) - Implemented `driver.SessionResetter` (#779) - `sha256_password` authentication plugin support (#808) Bugfixes: - Use the DSN hostname as TLS default ServerName if `tls=true` (#564, #718) - Fixed LOAD LOCAL DATA INFILE for empty files (#590) - Removed columns definition cache since it sometimes cached invalid data (#592) - Don't mutate registered TLS configs (#600) - Make RegisterTLSConfig concurrency-safe (#613) - Handle missing auth data in the handshake packet correctly (#646) - Do not retry queries when data was written to avoid data corruption (#302, #736) - Cache the connection pointer for error handling before invalidating it (#678) - Fixed imports for appengine/cloudsql (#700) - Fix sending STMT_LONG_DATA for 0 byte data (#734) - Set correct capacity for []bytes read from length-encoded strings (#766) - Make RegisterDial concurrency-safe (#773) ## Version 1.3 (2016-12-01) Changes: - Go 1.1 is no longer supported - Use decimals fields in MySQL to format time types (#249) - Buffer optimizations (#269) - TLS ServerName defaults to the host (#283) - Refactoring (#400, #410, #437) - Adjusted documentation for second generation CloudSQL (#485) - Documented DSN system var quoting rules (#502) - Made statement.Close() calls idempotent to avoid errors in Go 1.6+ (#512) New Features: - Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249) - Support for returning table alias on Columns() (#289, #359, #382) - Placeholder interpolation, can be activated with the DSN parameter `interpolateParams=true` (#309, #318, #490) - Support for uint64 parameters with high bit set (#332, #345) - Cleartext authentication plugin support (#327) - Exported ParseDSN function and the Config struct (#403, #419, #429) - Read / Write timeouts (#401) - Support for JSON field type (#414) - Support for multi-statements and multi-results (#411, #431) - DSN parameter to set the driver-side max_allowed_packet value manually (#489) - Native password authentication plugin support (#494, #524) Bugfixes: - Fixed handling of queries without columns and rows (#255) - Fixed a panic when SetKeepAlive() failed (#298) - Handle ERR packets while reading rows (#321) - Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349) - Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356) - Actually zero out bytes in handshake response (#378) - Fixed race condition in registering LOAD DATA INFILE handler (#383) - Fixed tests with MySQL 5.7.9+ (#380) - QueryUnescape TLS config names (#397) - Fixed "broken pipe" error by writing to closed socket (#390) - Fixed LOAD LOCAL DATA INFILE buffering (#424) - Fixed parsing of floats into float64 when placeholders are used (#434) - Fixed DSN tests with Go 1.7+ (#459) - Handle ERR packets while waiting for EOF (#473) - Invalidate connection on error while discarding additional results (#513) - Allow terminating packets of length 0 (#516) ## Version 1.2 (2014-06-03) Changes: - We switched back to a "rolling release". `go get` installs the current master branch again - Version v1 of the driver will not be maintained anymore. Go 1.0 is no longer supported by this driver - Exported errors to allow easy checking from application code - Enabled TCP Keepalives on TCP connections - Optimized INFILE handling (better buffer size calculation, lazy init, ...) - The DSN parser also checks for a missing separating slash - Faster binary date / datetime to string formatting - Also exported the MySQLWarning type - mysqlConn.Close returns the first error encountered instead of ignoring all errors - writePacket() automatically writes the packet size to the header - readPacket() uses an iterative approach instead of the recursive approach to merge split packets New Features: - `RegisterDial` allows the usage of a custom dial function to establish the network connection - Setting the connection collation is possible with the `collation` DSN parameter. This parameter should be preferred over the `charset` parameter - Logging of critical errors is configurable with `SetLogger` - Google CloudSQL support Bugfixes: - Allow more than 32 parameters in prepared statements - Various old_password fixes - Fixed TestConcurrent test to pass Go's race detection - Fixed appendLengthEncodedInteger for large numbers - Renamed readLengthEnodedString to readLengthEncodedString and skipLengthEnodedString to skipLengthEncodedString (fixed typo) ## Version 1.1 (2013-11-02) Changes: - Go-MySQL-Driver now requires Go 1.1 - Connections now use the collation `utf8_general_ci` by default. Adding `&charset=UTF8` to the DSN should not be necessary anymore - Made closing rows and connections error tolerant. This allows for example deferring rows.Close() without checking for errors - `[]byte(nil)` is now treated as a NULL value. Before, it was treated like an empty string / `[]byte("")` - DSN parameter values must now be url.QueryEscape'ed. This allows text values to contain special characters, such as '&'. - Use the IO buffer also for writing. This results in zero allocations (by the driver) for most queries - Optimized the buffer for reading - stmt.Query now caches column metadata - New Logo - Changed the copyright header to include all contributors - Improved the LOAD INFILE documentation - The driver struct is now exported to make the driver directly accessible - Refactored the driver tests - Added more benchmarks and moved all to a separate file - Other small refactoring New Features: - Added *old_passwords* support: Required in some cases, but must be enabled by adding `allowOldPasswords=true` to the DSN since it is insecure - Added a `clientFoundRows` parameter: Return the number of matching rows instead of the number of rows changed on UPDATEs - Added TLS/SSL support: Use a TLS/SSL encrypted connection to the server. Custom TLS configs can be registered and used Bugfixes: - Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification - Convert to DB timezone when inserting `time.Time` - Split packets (more than 16MB) are now merged correctly - Fixed false positive `io.EOF` errors when the data was fully read - Avoid panics on reuse of closed connections - Fixed empty string producing false nil values - Fixed sign byte for positive TIME fields ## Version 1.0 (2013-05-14) Initial Release ================================================ FILE: vendor/github.com/go-sql-driver/mysql/LICENSE ================================================ Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: vendor/github.com/go-sql-driver/mysql/README.md ================================================ # Go-MySQL-Driver A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) package ![Go-MySQL-Driver logo](https://raw.github.com/wiki/go-sql-driver/mysql/gomysql_m.png "Golang Gopher holding the MySQL Dolphin") --------------------------------------- * [Features](#features) * [Requirements](#requirements) * [Installation](#installation) * [Usage](#usage) * [DSN (Data Source Name)](#dsn-data-source-name) * [Password](#password) * [Protocol](#protocol) * [Address](#address) * [Parameters](#parameters) * [Examples](#examples) * [Connection pool and timeouts](#connection-pool-and-timeouts) * [context.Context Support](#contextcontext-support) * [ColumnType Support](#columntype-support) * [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support) * [time.Time support](#timetime-support) * [Unicode support](#unicode-support) * [Testing / Development](#testing--development) * [License](#license) --------------------------------------- ## Features * Lightweight and [fast](https://github.com/go-sql-driver/sql-benchmark "golang MySQL-Driver performance") * Native Go implementation. No C-bindings, just pure Go * Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](https://godoc.org/github.com/go-sql-driver/mysql#DialFunc) * Automatic handling of broken connections * Automatic Connection Pooling *(by database/sql package)* * Supports queries larger than 16MB * Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support. * Intelligent `LONG DATA` handling in prepared statements * Secure `LOAD DATA LOCAL INFILE` support with file allowlisting and `io.Reader` support * Optional `time.Time` parsing * Optional placeholder interpolation ## Requirements * Go 1.19 or higher. We aim to support the 3 latest versions of Go. * MySQL (5.7+) and MariaDB (10.3+) are supported. * [TiDB](https://github.com/pingcap/tidb) is supported by PingCAP. * Do not ask questions about TiDB in our issue tracker or forum. * [Document](https://docs.pingcap.com/tidb/v6.1/dev-guide-sample-application-golang) * [Forum](https://ask.pingcap.com/) * go-mysql would work with Percona Server, Google CloudSQL or Sphinx (2.2.3+). * Maintainers won't support them. Do not expect issues are investigated and resolved by maintainers. * Investigate issues yourself and please send a pull request to fix it. --------------------------------------- ## Installation Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell: ```bash go get -u github.com/go-sql-driver/mysql ``` Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`. ## Usage _Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then. Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`: ```go import ( "database/sql" "time" _ "github.com/go-sql-driver/mysql" ) // ... db, err := sql.Open("mysql", "user:password@/dbname") if err != nil { panic(err) } // See "Important settings" section. db.SetConnMaxLifetime(time.Minute * 3) db.SetMaxOpenConns(10) db.SetMaxIdleConns(10) ``` [Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples "Go-MySQL-Driver Examples"). ### Important settings `db.SetConnMaxLifetime()` is required to ensure connections are closed by the driver safely before connection is closed by MySQL server, OS, or other middlewares. Since some middlewares close idle connections by 5 minutes, we recommend timeout shorter than 5 minutes. This setting helps load balancing and changing system variables too. `db.SetMaxOpenConns()` is highly recommended to limit the number of connection used by the application. There is no recommended limit number because it depends on application and MySQL server. `db.SetMaxIdleConns()` is recommended to be set same to `db.SetMaxOpenConns()`. When it is smaller than `SetMaxOpenConns()`, connections can be opened and closed much more frequently than you expect. Idle connections can be closed by the `db.SetConnMaxLifetime()`. If you want to close idle connections more rapidly, you can use `db.SetConnMaxIdleTime()` since Go 1.15. ### DSN (Data Source Name) The Data Source Name has a common format, like e.g. [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php) uses it, but without type-prefix (optional parts marked by squared brackets): ``` [username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN] ``` A DSN in its fullest form: ``` username:password@protocol(address)/dbname?param=value ``` Except for the databasename, all values are optional. So the minimal DSN is: ``` /dbname ``` If you do not want to preselect a database, leave `dbname` empty: ``` / ``` This has the same effect as an empty DSN string: ``` ``` `dbname` is escaped by [PathEscape()](https://pkg.go.dev/net/url#PathEscape) since v1.8.0. If your database name is `dbname/withslash`, it becomes: ``` /dbname%2Fwithslash ``` Alternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mysql#Config.FormatDSN) can be used to create a DSN string by filling a struct. #### Password Passwords can consist of any character. Escaping is **not** necessary. #### Protocol See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available. In general you should use a Unix domain socket if available and TCP otherwise for best performance. #### Address For TCP and UDP networks, addresses have the form `host[:port]`. If `port` is omitted, the default port will be used. If `host` is a literal IPv6 address, it must be enclosed in square brackets. The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form. For Unix domain sockets the address is the absolute path to the MySQL-Server-socket, e.g. `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock`. #### Parameters *Parameters are case-sensitive!* Notice that any of `true`, `TRUE`, `True` or `1` is accepted to stand for a true boolean value. Not surprisingly, false can be specified as any of: `false`, `FALSE`, `False` or `0`. ##### `allowAllFiles` ``` Type: bool Valid Values: true, false Default: false ``` `allowAllFiles=true` disables the file allowlist for `LOAD DATA LOCAL INFILE` and allows *all* files. [*Might be insecure!*](https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-local) ##### `allowCleartextPasswords` ``` Type: bool Valid Values: true, false Default: false ``` `allowCleartextPasswords=true` allows using the [cleartext client side plugin](https://dev.mysql.com/doc/en/cleartext-pluggable-authentication.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network. ##### `allowFallbackToPlaintext` ``` Type: bool Valid Values: true, false Default: false ``` `allowFallbackToPlaintext=true` acts like a `--ssl-mode=PREFERRED` MySQL client as described in [Command Options for Connecting to the Server](https://dev.mysql.com/doc/refman/5.7/en/connection-options.html#option_general_ssl-mode) ##### `allowNativePasswords` ``` Type: bool Valid Values: true, false Default: true ``` `allowNativePasswords=false` disallows the usage of MySQL native password method. ##### `allowOldPasswords` ``` Type: bool Valid Values: true, false Default: false ``` `allowOldPasswords=true` allows the usage of the insecure old password method. This should be avoided, but is necessary in some cases. See also [the old_passwords wiki page](https://github.com/go-sql-driver/mysql/wiki/old_passwords). ##### `charset` ``` Type: string Valid Values: Default: none ``` Sets the charset used for client-server interaction (`"SET NAMES "`). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset fails. This enables for example support for `utf8mb4` ([introduced in MySQL 5.5.3](http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)) with fallback to `utf8` for older servers (`charset=utf8mb4,utf8`). See also [Unicode Support](#unicode-support). ##### `checkConnLiveness` ``` Type: bool Valid Values: true, false Default: true ``` On supported platforms connections retrieved from the connection pool are checked for liveness before using them. If the check fails, the respective connection is marked as bad and the query retried with another connection. `checkConnLiveness=false` disables this liveness check of connections. ##### `collation` ``` Type: string Valid Values: Default: utf8mb4_general_ci ``` Sets the collation used for client-server interaction on connection. In contrast to `charset`, `collation` does not issue additional queries. If the specified collation is unavailable on the target server, the connection will fail. A list of valid charsets for a server is retrievable with `SHOW COLLATION`. The default collation (`utf8mb4_general_ci`) is supported from MySQL 5.5. You should use an older collation (e.g. `utf8_general_ci`) for older MySQL. Collations for charset "ucs2", "utf16", "utf16le", and "utf32" can not be used ([ref](https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset)). See also [Unicode Support](#unicode-support). ##### `clientFoundRows` ``` Type: bool Valid Values: true, false Default: false ``` `clientFoundRows=true` causes an UPDATE to return the number of matching rows instead of the number of rows changed. ##### `columnsWithAlias` ``` Type: bool Valid Values: true, false Default: false ``` When `columnsWithAlias` is true, calls to `sql.Rows.Columns()` will return the table alias and the column name separated by a dot. For example: ``` SELECT u.id FROM users as u ``` will return `u.id` instead of just `id` if `columnsWithAlias=true`. ##### `interpolateParams` ``` Type: bool Valid Values: true, false Default: false ``` If `interpolateParams` is true, placeholders (`?`) in calls to `db.Query()` and `db.Exec()` are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with `interpolateParams=false`. *This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are rejected as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!* ##### `loc` ``` Type: string Valid Values: Default: UTC ``` Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation) for details. Note that this sets the location for time.Time values but does not change MySQL's [time_zone setting](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html). For that see the [time_zone system variable](#system-variables), which can also be set as a DSN parameter. Please keep in mind, that param values must be [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`. ##### `timeTruncate` ``` Type: duration Default: 0 ``` [Truncate time values](https://pkg.go.dev/time#Duration.Truncate) to the specified duration. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. ##### `maxAllowedPacket` ``` Type: decimal number Default: 64*1024*1024 ``` Max packet size allowed in bytes. The default value is 64 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*. ##### `multiStatements` ``` Type: bool Valid Values: true, false Default: false ``` Allow multiple statements in one query. This can be used to bach multiple queries. Use [Rows.NextResultSet()](https://pkg.go.dev/database/sql#Rows.NextResultSet) to get result of the second and subsequent queries. When `multiStatements` is used, `?` parameters must only be used in the first statement. [interpolateParams](#interpolateparams) can be used to avoid this limitation unless prepared statement is used explicitly. It's possible to access the last inserted ID and number of affected rows for multiple statements by using `sql.Conn.Raw()` and the `mysql.Result`. For example: ```go conn, _ := db.Conn(ctx) conn.Raw(func(conn interface{}) error { ex := conn.(driver.Execer) res, err := ex.Exec(` UPDATE point SET x = 1 WHERE y = 2; UPDATE point SET x = 2 WHERE y = 3; `, nil) // Both slices have 2 elements. log.Print(res.(mysql.Result).AllRowsAffected()) log.Print(res.(mysql.Result).AllLastInsertIds()) }) ``` ##### `parseTime` ``` Type: bool Valid Values: true, false Default: false ``` `parseTime=true` changes the output type of `DATE` and `DATETIME` values to `time.Time` instead of `[]byte` / `string` The date or datetime like `0000-00-00 00:00:00` is converted into zero value of `time.Time`. ##### `readTimeout` ``` Type: duration Default: 0 ``` I/O read timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. ##### `rejectReadOnly` ``` Type: bool Valid Values: true, false Default: false ``` `rejectReadOnly=true` causes the driver to reject read-only connections. This is for a possible race condition during an automatic failover, where the mysql client gets connected to a read-only replica after the failover. Note that this should be a fairly rare case, as an automatic failover normally happens when the primary is down, and the race condition shouldn't happen unless it comes back up online as soon as the failover is kicked off. On the other hand, when this happens, a MySQL application can get stuck on a read-only connection until restarted. It is however fairly easy to reproduce, for example, using a manual failover on AWS Aurora's MySQL-compatible cluster. If you are not relying on read-only transactions to reject writes that aren't supposed to happen, setting this on some MySQL providers (such as AWS Aurora) is safer for failovers. Note that ERROR 1290 can be returned for a `read-only` server and this option will cause a retry for that error. However the same error number is used for some other cases. You should ensure your application will never cause an ERROR 1290 except for `read-only` mode when enabling this option. ##### `serverPubKey` ``` Type: string Valid Values: Default: none ``` Server public keys can be registered with [`mysql.RegisterServerPubKey`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterServerPubKey), which can then be used by the assigned name in the DSN. Public keys are used to transmit encrypted data, e.g. for authentication. If the server's public key is known, it should be set manually to avoid expensive and potentially insecure transmissions of the public key from the server to the client each time it is required. ##### `timeout` ``` Type: duration Default: OS default ``` Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. ##### `tls` ``` Type: bool / string Valid Values: true, false, skip-verify, preferred, Default: false ``` `tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side) or use `preferred` to use TLS only when advertised by the server. This is similar to `skip-verify`, but additionally allows a fallback to a connection which is not encrypted. Neither `skip-verify` nor `preferred` add any reliable security. You can use a custom TLS config after registering it with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig). ##### `writeTimeout` ``` Type: duration Default: 0 ``` I/O write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. ##### `connectionAttributes` ``` Type: comma-delimited string of user-defined "key:value" pairs Valid Values: (:,:,...) Default: none ``` [Connection attributes](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-connection-attribute-tables.html) are key-value pairs that application programs can pass to the server at connect time. ##### System Variables Any other parameters are interpreted as system variables: * `=`: `SET =` * `=`: `SET =` * `=%27%27`: `SET =''` Rules: * The values for string variables must be quoted with `'`. * The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed! (which implies values of string variables must be wrapped with `%27`). Examples: * `autocommit=1`: `SET autocommit=1` * [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'` * [`transaction_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_transaction_isolation): `SET transaction_isolation='REPEATABLE-READ'` #### Examples ``` user@unix(/path/to/socket)/dbname ``` ``` root:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local ``` ``` user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true ``` Treat warnings as errors by setting the system variable [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html): ``` user:password@/dbname?sql_mode=TRADITIONAL ``` TCP via IPv6: ``` user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?timeout=90s&collation=utf8mb4_unicode_ci ``` TCP on a remote host, e.g. Amazon RDS: ``` id:password@tcp(your-amazonaws-uri.com:3306)/dbname ``` Google Cloud SQL on App Engine: ``` user:password@unix(/cloudsql/project-id:region-name:instance-name)/dbname ``` TCP using default port (3306) on localhost: ``` user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped ``` Use the default protocol (tcp) and host (localhost:3306): ``` user:password@/dbname ``` No Database preselected: ``` user:password@/ ``` ### Connection pool and timeouts The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively. ## `ColumnType` Support This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported. All Unsigned database type names will be returned `UNSIGNED ` with `INT`, `TINYINT`, `SMALLINT`, `MEDIUMINT`, `BIGINT`. ## `context.Context` Support Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts. See [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details. ### `LOAD DATA LOCAL INFILE` support For this feature you need direct access to the package. Therefore you must change the import path (no `_`): ```go import "github.com/go-sql-driver/mysql" ``` Files must be explicitly allowed by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the allowlist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-local)). To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore. See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details. ### `time.Time` support The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your program. However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical equivalent in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter. **Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes). ### Unicode support Since version 1.5 Go-MySQL-Driver automatically uses the collation ` utf8mb4_general_ci` by default. Other charsets / collations can be set using the [`charset`](#charset) or [`collation`](#collation) DSN parameter. - When only the `charset` is specified, the `SET NAMES ` query is sent and the server's default collation is used. - When both the `charset` and `collation` are specified, the `SET NAMES COLLATE ` query is sent. - When only the `collation` is specified, the collation is specified in the protocol handshake and the `SET NAMES` query is not sent. This can save one roundtrip, but note that the server may ignore the specified collation silently and use the server's default charset/collation instead. See http://dev.mysql.com/doc/refman/8.0/en/charset-unicode.html for more details on MySQL's Unicode support. ## Testing / Development To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details. Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated. If you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls). See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/.github/CONTRIBUTING.md) for details. --------------------------------------- ## License Go-MySQL-Driver is licensed under the [Mozilla Public License Version 2.0](https://raw.github.com/go-sql-driver/mysql/master/LICENSE) Mozilla summarizes the license scope as follows: > MPL: The copyleft applies to any files containing MPLed code. That means: * You can **use** the **unchanged** source code both in private and commercially. * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0). * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**. Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license. You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE). ![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow") ================================================ FILE: vendor/github.com/go-sql-driver/mysql/atomic_bool.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package. // // Copyright 2022 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. //go:build go1.19 // +build go1.19 package mysql import "sync/atomic" /****************************************************************************** * Sync utils * ******************************************************************************/ type atomicBool = atomic.Bool ================================================ FILE: vendor/github.com/go-sql-driver/mysql/atomic_bool_go118.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package. // // Copyright 2022 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. //go:build !go1.19 // +build !go1.19 package mysql import "sync/atomic" /****************************************************************************** * Sync utils * ******************************************************************************/ // atomicBool is an implementation of atomic.Bool for older version of Go. // it is a wrapper around uint32 for usage as a boolean value with // atomic access. type atomicBool struct { _ noCopy value uint32 } // Load returns whether the current boolean value is true func (ab *atomicBool) Load() bool { return atomic.LoadUint32(&ab.value) > 0 } // Store sets the value of the bool regardless of the previous value func (ab *atomicBool) Store(value bool) { if value { atomic.StoreUint32(&ab.value, 1) } else { atomic.StoreUint32(&ab.value, 0) } } // Swap sets the value of the bool and returns the old value. func (ab *atomicBool) Swap(value bool) bool { if value { return atomic.SwapUint32(&ab.value, 1) > 0 } return atomic.SwapUint32(&ab.value, 0) > 0 } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/auth.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "crypto/rand" "crypto/rsa" "crypto/sha1" "crypto/sha256" "crypto/sha512" "crypto/x509" "encoding/pem" "fmt" "sync" "filippo.io/edwards25519" ) // server pub keys registry var ( serverPubKeyLock sync.RWMutex serverPubKeyRegistry map[string]*rsa.PublicKey ) // RegisterServerPubKey registers a server RSA public key which can be used to // send data in a secure manner to the server without receiving the public key // in a potentially insecure way from the server first. // Registered keys can afterwards be used adding serverPubKey= to the DSN. // // Note: The provided rsa.PublicKey instance is exclusively owned by the driver // after registering it and may not be modified. // // data, err := os.ReadFile("mykey.pem") // if err != nil { // log.Fatal(err) // } // // block, _ := pem.Decode(data) // if block == nil || block.Type != "PUBLIC KEY" { // log.Fatal("failed to decode PEM block containing public key") // } // // pub, err := x509.ParsePKIXPublicKey(block.Bytes) // if err != nil { // log.Fatal(err) // } // // if rsaPubKey, ok := pub.(*rsa.PublicKey); ok { // mysql.RegisterServerPubKey("mykey", rsaPubKey) // } else { // log.Fatal("not a RSA public key") // } func RegisterServerPubKey(name string, pubKey *rsa.PublicKey) { serverPubKeyLock.Lock() if serverPubKeyRegistry == nil { serverPubKeyRegistry = make(map[string]*rsa.PublicKey) } serverPubKeyRegistry[name] = pubKey serverPubKeyLock.Unlock() } // DeregisterServerPubKey removes the public key registered with the given name. func DeregisterServerPubKey(name string) { serverPubKeyLock.Lock() if serverPubKeyRegistry != nil { delete(serverPubKeyRegistry, name) } serverPubKeyLock.Unlock() } func getServerPubKey(name string) (pubKey *rsa.PublicKey) { serverPubKeyLock.RLock() if v, ok := serverPubKeyRegistry[name]; ok { pubKey = v } serverPubKeyLock.RUnlock() return } // Hash password using pre 4.1 (old password) method // https://github.com/atcurtis/mariadb/blob/master/mysys/my_rnd.c type myRnd struct { seed1, seed2 uint32 } const myRndMaxVal = 0x3FFFFFFF // Pseudo random number generator func newMyRnd(seed1, seed2 uint32) *myRnd { return &myRnd{ seed1: seed1 % myRndMaxVal, seed2: seed2 % myRndMaxVal, } } // Tested to be equivalent to MariaDB's floating point variant // http://play.golang.org/p/QHvhd4qved // http://play.golang.org/p/RG0q4ElWDx func (r *myRnd) NextByte() byte { r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal return byte(uint64(r.seed1) * 31 / myRndMaxVal) } // Generate binary hash from byte string using insecure pre 4.1 method func pwHash(password []byte) (result [2]uint32) { var add uint32 = 7 var tmp uint32 result[0] = 1345345333 result[1] = 0x12345671 for _, c := range password { // skip spaces and tabs in password if c == ' ' || c == '\t' { continue } tmp = uint32(c) result[0] ^= (((result[0] & 63) + add) * tmp) + (result[0] << 8) result[1] += (result[1] << 8) ^ result[0] add += tmp } // Remove sign bit (1<<31)-1) result[0] &= 0x7FFFFFFF result[1] &= 0x7FFFFFFF return } // Hash password using insecure pre 4.1 method func scrambleOldPassword(scramble []byte, password string) []byte { scramble = scramble[:8] hashPw := pwHash([]byte(password)) hashSc := pwHash(scramble) r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1]) var out [8]byte for i := range out { out[i] = r.NextByte() + 64 } mask := r.NextByte() for i := range out { out[i] ^= mask } return out[:] } // Hash password using 4.1+ method (SHA1) func scramblePassword(scramble []byte, password string) []byte { if len(password) == 0 { return nil } // stage1Hash = SHA1(password) crypt := sha1.New() crypt.Write([]byte(password)) stage1 := crypt.Sum(nil) // scrambleHash = SHA1(scramble + SHA1(stage1Hash)) // inner Hash crypt.Reset() crypt.Write(stage1) hash := crypt.Sum(nil) // outer Hash crypt.Reset() crypt.Write(scramble) crypt.Write(hash) scramble = crypt.Sum(nil) // token = scrambleHash XOR stage1Hash for i := range scramble { scramble[i] ^= stage1[i] } return scramble } // Hash password using MySQL 8+ method (SHA256) func scrambleSHA256Password(scramble []byte, password string) []byte { if len(password) == 0 { return nil } // XOR(SHA256(password), SHA256(SHA256(SHA256(password)), scramble)) crypt := sha256.New() crypt.Write([]byte(password)) message1 := crypt.Sum(nil) crypt.Reset() crypt.Write(message1) message1Hash := crypt.Sum(nil) crypt.Reset() crypt.Write(message1Hash) crypt.Write(scramble) message2 := crypt.Sum(nil) for i := range message1 { message1[i] ^= message2[i] } return message1 } func encryptPassword(password string, seed []byte, pub *rsa.PublicKey) ([]byte, error) { plain := make([]byte, len(password)+1) copy(plain, password) for i := range plain { j := i % len(seed) plain[i] ^= seed[j] } sha1 := sha1.New() return rsa.EncryptOAEP(sha1, rand.Reader, pub, plain, nil) } // authEd25519 does ed25519 authentication used by MariaDB. func authEd25519(scramble []byte, password string) ([]byte, error) { // Derived from https://github.com/MariaDB/server/blob/d8e6bb00888b1f82c031938f4c8ac5d97f6874c3/plugin/auth_ed25519/ref10/sign.c // Code style is from https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:src/crypto/ed25519/ed25519.go;l=207 h := sha512.Sum512([]byte(password)) s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32]) if err != nil { return nil, err } A := (&edwards25519.Point{}).ScalarBaseMult(s) mh := sha512.New() mh.Write(h[32:]) mh.Write(scramble) messageDigest := mh.Sum(nil) r, err := edwards25519.NewScalar().SetUniformBytes(messageDigest) if err != nil { return nil, err } R := (&edwards25519.Point{}).ScalarBaseMult(r) kh := sha512.New() kh.Write(R.Bytes()) kh.Write(A.Bytes()) kh.Write(scramble) hramDigest := kh.Sum(nil) k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest) if err != nil { return nil, err } S := k.MultiplyAdd(k, s, r) return append(R.Bytes(), S.Bytes()...), nil } func (mc *mysqlConn) sendEncryptedPassword(seed []byte, pub *rsa.PublicKey) error { enc, err := encryptPassword(mc.cfg.Passwd, seed, pub) if err != nil { return err } return mc.writeAuthSwitchPacket(enc) } func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) { switch plugin { case "caching_sha2_password": authResp := scrambleSHA256Password(authData, mc.cfg.Passwd) return authResp, nil case "mysql_old_password": if !mc.cfg.AllowOldPasswords { return nil, ErrOldPassword } if len(mc.cfg.Passwd) == 0 { return nil, nil } // Note: there are edge cases where this should work but doesn't; // this is currently "wontfix": // https://github.com/go-sql-driver/mysql/issues/184 authResp := append(scrambleOldPassword(authData[:8], mc.cfg.Passwd), 0) return authResp, nil case "mysql_clear_password": if !mc.cfg.AllowCleartextPasswords { return nil, ErrCleartextPassword } // http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html // http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html return append([]byte(mc.cfg.Passwd), 0), nil case "mysql_native_password": if !mc.cfg.AllowNativePasswords { return nil, ErrNativePassword } // https://dev.mysql.com/doc/internals/en/secure-password-authentication.html // Native password authentication only need and will need 20-byte challenge. authResp := scramblePassword(authData[:20], mc.cfg.Passwd) return authResp, nil case "sha256_password": if len(mc.cfg.Passwd) == 0 { return []byte{0}, nil } // unlike caching_sha2_password, sha256_password does not accept // cleartext password on unix transport. if mc.cfg.TLS != nil { // write cleartext auth packet return append([]byte(mc.cfg.Passwd), 0), nil } pubKey := mc.cfg.pubKey if pubKey == nil { // request public key from server return []byte{1}, nil } // encrypted password enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey) return enc, err case "client_ed25519": if len(authData) != 32 { return nil, ErrMalformPkt } return authEd25519(authData, mc.cfg.Passwd) default: mc.cfg.Logger.Print("unknown auth plugin:", plugin) return nil, ErrUnknownPlugin } } func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error { // Read Result Packet authData, newPlugin, err := mc.readAuthResult() if err != nil { return err } // handle auth plugin switch, if requested if newPlugin != "" { // If CLIENT_PLUGIN_AUTH capability is not supported, no new cipher is // sent and we have to keep using the cipher sent in the init packet. if authData == nil { authData = oldAuthData } else { // copy data from read buffer to owned slice copy(oldAuthData, authData) } plugin = newPlugin authResp, err := mc.auth(authData, plugin) if err != nil { return err } if err = mc.writeAuthSwitchPacket(authResp); err != nil { return err } // Read Result Packet authData, newPlugin, err = mc.readAuthResult() if err != nil { return err } // Do not allow to change the auth plugin more than once if newPlugin != "" { return ErrMalformPkt } } switch plugin { // https://dev.mysql.com/blog-archive/preparing-your-community-connector-for-mysql-8-part-2-sha256/ case "caching_sha2_password": switch len(authData) { case 0: return nil // auth successful case 1: switch authData[0] { case cachingSha2PasswordFastAuthSuccess: if err = mc.resultUnchanged().readResultOK(); err == nil { return nil // auth successful } case cachingSha2PasswordPerformFullAuthentication: if mc.cfg.TLS != nil || mc.cfg.Net == "unix" { // write cleartext auth packet err = mc.writeAuthSwitchPacket(append([]byte(mc.cfg.Passwd), 0)) if err != nil { return err } } else { pubKey := mc.cfg.pubKey if pubKey == nil { // request public key from server data, err := mc.buf.takeSmallBuffer(4 + 1) if err != nil { return err } data[4] = cachingSha2PasswordRequestPublicKey err = mc.writePacket(data) if err != nil { return err } if data, err = mc.readPacket(); err != nil { return err } if data[0] != iAuthMoreData { return fmt.Errorf("unexpected resp from server for caching_sha2_password, perform full authentication") } // parse public key block, rest := pem.Decode(data[1:]) if block == nil { return fmt.Errorf("no pem data found, data: %s", rest) } pkix, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return err } pubKey = pkix.(*rsa.PublicKey) } // send encrypted password err = mc.sendEncryptedPassword(oldAuthData, pubKey) if err != nil { return err } } return mc.resultUnchanged().readResultOK() default: return ErrMalformPkt } default: return ErrMalformPkt } case "sha256_password": switch len(authData) { case 0: return nil // auth successful default: block, _ := pem.Decode(authData) if block == nil { return fmt.Errorf("no Pem data found, data: %s", authData) } pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return err } // send encrypted password err = mc.sendEncryptedPassword(oldAuthData, pub.(*rsa.PublicKey)) if err != nil { return err } return mc.resultUnchanged().readResultOK() } default: return nil // auth successful } return err } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/buffer.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "io" "net" "time" ) const defaultBufSize = 4096 const maxCachedBufSize = 256 * 1024 // A buffer which is used for both reading and writing. // This is possible since communication on each connection is synchronous. // In other words, we can't write and read simultaneously on the same connection. // The buffer is similar to bufio.Reader / Writer but zero-copy-ish // Also highly optimized for this particular use case. // This buffer is backed by two byte slices in a double-buffering scheme type buffer struct { buf []byte // buf is a byte buffer who's length and capacity are equal. nc net.Conn idx int length int timeout time.Duration dbuf [2][]byte // dbuf is an array with the two byte slices that back this buffer flipcnt uint // flipccnt is the current buffer counter for double-buffering } // newBuffer allocates and returns a new buffer. func newBuffer(nc net.Conn) buffer { fg := make([]byte, defaultBufSize) return buffer{ buf: fg, nc: nc, dbuf: [2][]byte{fg, nil}, } } // flip replaces the active buffer with the background buffer // this is a delayed flip that simply increases the buffer counter; // the actual flip will be performed the next time we call `buffer.fill` func (b *buffer) flip() { b.flipcnt += 1 } // fill reads into the buffer until at least _need_ bytes are in it func (b *buffer) fill(need int) error { n := b.length // fill data into its double-buffering target: if we've called // flip on this buffer, we'll be copying to the background buffer, // and then filling it with network data; otherwise we'll just move // the contents of the current buffer to the front before filling it dest := b.dbuf[b.flipcnt&1] // grow buffer if necessary to fit the whole packet. if need > len(dest) { // Round up to the next multiple of the default size dest = make([]byte, ((need/defaultBufSize)+1)*defaultBufSize) // if the allocated buffer is not too large, move it to backing storage // to prevent extra allocations on applications that perform large reads if len(dest) <= maxCachedBufSize { b.dbuf[b.flipcnt&1] = dest } } // if we're filling the fg buffer, move the existing data to the start of it. // if we're filling the bg buffer, copy over the data if n > 0 { copy(dest[:n], b.buf[b.idx:]) } b.buf = dest b.idx = 0 for { if b.timeout > 0 { if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil { return err } } nn, err := b.nc.Read(b.buf[n:]) n += nn switch err { case nil: if n < need { continue } b.length = n return nil case io.EOF: if n >= need { b.length = n return nil } return io.ErrUnexpectedEOF default: return err } } } // returns next N bytes from buffer. // The returned slice is only guaranteed to be valid until the next read func (b *buffer) readNext(need int) ([]byte, error) { if b.length < need { // refill if err := b.fill(need); err != nil { return nil, err } } offset := b.idx b.idx += need b.length -= need return b.buf[offset:b.idx], nil } // takeBuffer returns a buffer with the requested size. // If possible, a slice from the existing buffer is returned. // Otherwise a bigger buffer is made. // Only one buffer (total) can be used at a time. func (b *buffer) takeBuffer(length int) ([]byte, error) { if b.length > 0 { return nil, ErrBusyBuffer } // test (cheap) general case first if length <= cap(b.buf) { return b.buf[:length], nil } if length < maxPacketSize { b.buf = make([]byte, length) return b.buf, nil } // buffer is larger than we want to store. return make([]byte, length), nil } // takeSmallBuffer is shortcut which can be used if length is // known to be smaller than defaultBufSize. // Only one buffer (total) can be used at a time. func (b *buffer) takeSmallBuffer(length int) ([]byte, error) { if b.length > 0 { return nil, ErrBusyBuffer } return b.buf[:length], nil } // takeCompleteBuffer returns the complete existing buffer. // This can be used if the necessary buffer size is unknown. // cap and len of the returned buffer will be equal. // Only one buffer (total) can be used at a time. func (b *buffer) takeCompleteBuffer() ([]byte, error) { if b.length > 0 { return nil, ErrBusyBuffer } return b.buf, nil } // store stores buf, an updated buffer, if its suitable to do so. func (b *buffer) store(buf []byte) error { if b.length > 0 { return ErrBusyBuffer } else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) { b.buf = buf[:cap(buf)] } return nil } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/collations.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2014 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql const defaultCollation = "utf8mb4_general_ci" const binaryCollationID = 63 // A list of available collations mapped to the internal ID. // To update this map use the following MySQL query: // // SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS WHERE ID<256 ORDER BY ID // // Handshake packet have only 1 byte for collation_id. So we can't use collations with ID > 255. // // ucs2, utf16, and utf32 can't be used for connection charset. // https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset // They are commented out to reduce this map. var collations = map[string]byte{ "big5_chinese_ci": 1, "latin2_czech_cs": 2, "dec8_swedish_ci": 3, "cp850_general_ci": 4, "latin1_german1_ci": 5, "hp8_english_ci": 6, "koi8r_general_ci": 7, "latin1_swedish_ci": 8, "latin2_general_ci": 9, "swe7_swedish_ci": 10, "ascii_general_ci": 11, "ujis_japanese_ci": 12, "sjis_japanese_ci": 13, "cp1251_bulgarian_ci": 14, "latin1_danish_ci": 15, "hebrew_general_ci": 16, "tis620_thai_ci": 18, "euckr_korean_ci": 19, "latin7_estonian_cs": 20, "latin2_hungarian_ci": 21, "koi8u_general_ci": 22, "cp1251_ukrainian_ci": 23, "gb2312_chinese_ci": 24, "greek_general_ci": 25, "cp1250_general_ci": 26, "latin2_croatian_ci": 27, "gbk_chinese_ci": 28, "cp1257_lithuanian_ci": 29, "latin5_turkish_ci": 30, "latin1_german2_ci": 31, "armscii8_general_ci": 32, "utf8_general_ci": 33, "cp1250_czech_cs": 34, //"ucs2_general_ci": 35, "cp866_general_ci": 36, "keybcs2_general_ci": 37, "macce_general_ci": 38, "macroman_general_ci": 39, "cp852_general_ci": 40, "latin7_general_ci": 41, "latin7_general_cs": 42, "macce_bin": 43, "cp1250_croatian_ci": 44, "utf8mb4_general_ci": 45, "utf8mb4_bin": 46, "latin1_bin": 47, "latin1_general_ci": 48, "latin1_general_cs": 49, "cp1251_bin": 50, "cp1251_general_ci": 51, "cp1251_general_cs": 52, "macroman_bin": 53, //"utf16_general_ci": 54, //"utf16_bin": 55, //"utf16le_general_ci": 56, "cp1256_general_ci": 57, "cp1257_bin": 58, "cp1257_general_ci": 59, //"utf32_general_ci": 60, //"utf32_bin": 61, //"utf16le_bin": 62, "binary": 63, "armscii8_bin": 64, "ascii_bin": 65, "cp1250_bin": 66, "cp1256_bin": 67, "cp866_bin": 68, "dec8_bin": 69, "greek_bin": 70, "hebrew_bin": 71, "hp8_bin": 72, "keybcs2_bin": 73, "koi8r_bin": 74, "koi8u_bin": 75, "utf8_tolower_ci": 76, "latin2_bin": 77, "latin5_bin": 78, "latin7_bin": 79, "cp850_bin": 80, "cp852_bin": 81, "swe7_bin": 82, "utf8_bin": 83, "big5_bin": 84, "euckr_bin": 85, "gb2312_bin": 86, "gbk_bin": 87, "sjis_bin": 88, "tis620_bin": 89, //"ucs2_bin": 90, "ujis_bin": 91, "geostd8_general_ci": 92, "geostd8_bin": 93, "latin1_spanish_ci": 94, "cp932_japanese_ci": 95, "cp932_bin": 96, "eucjpms_japanese_ci": 97, "eucjpms_bin": 98, "cp1250_polish_ci": 99, //"utf16_unicode_ci": 101, //"utf16_icelandic_ci": 102, //"utf16_latvian_ci": 103, //"utf16_romanian_ci": 104, //"utf16_slovenian_ci": 105, //"utf16_polish_ci": 106, //"utf16_estonian_ci": 107, //"utf16_spanish_ci": 108, //"utf16_swedish_ci": 109, //"utf16_turkish_ci": 110, //"utf16_czech_ci": 111, //"utf16_danish_ci": 112, //"utf16_lithuanian_ci": 113, //"utf16_slovak_ci": 114, //"utf16_spanish2_ci": 115, //"utf16_roman_ci": 116, //"utf16_persian_ci": 117, //"utf16_esperanto_ci": 118, //"utf16_hungarian_ci": 119, //"utf16_sinhala_ci": 120, //"utf16_german2_ci": 121, //"utf16_croatian_ci": 122, //"utf16_unicode_520_ci": 123, //"utf16_vietnamese_ci": 124, //"ucs2_unicode_ci": 128, //"ucs2_icelandic_ci": 129, //"ucs2_latvian_ci": 130, //"ucs2_romanian_ci": 131, //"ucs2_slovenian_ci": 132, //"ucs2_polish_ci": 133, //"ucs2_estonian_ci": 134, //"ucs2_spanish_ci": 135, //"ucs2_swedish_ci": 136, //"ucs2_turkish_ci": 137, //"ucs2_czech_ci": 138, //"ucs2_danish_ci": 139, //"ucs2_lithuanian_ci": 140, //"ucs2_slovak_ci": 141, //"ucs2_spanish2_ci": 142, //"ucs2_roman_ci": 143, //"ucs2_persian_ci": 144, //"ucs2_esperanto_ci": 145, //"ucs2_hungarian_ci": 146, //"ucs2_sinhala_ci": 147, //"ucs2_german2_ci": 148, //"ucs2_croatian_ci": 149, //"ucs2_unicode_520_ci": 150, //"ucs2_vietnamese_ci": 151, //"ucs2_general_mysql500_ci": 159, //"utf32_unicode_ci": 160, //"utf32_icelandic_ci": 161, //"utf32_latvian_ci": 162, //"utf32_romanian_ci": 163, //"utf32_slovenian_ci": 164, //"utf32_polish_ci": 165, //"utf32_estonian_ci": 166, //"utf32_spanish_ci": 167, //"utf32_swedish_ci": 168, //"utf32_turkish_ci": 169, //"utf32_czech_ci": 170, //"utf32_danish_ci": 171, //"utf32_lithuanian_ci": 172, //"utf32_slovak_ci": 173, //"utf32_spanish2_ci": 174, //"utf32_roman_ci": 175, //"utf32_persian_ci": 176, //"utf32_esperanto_ci": 177, //"utf32_hungarian_ci": 178, //"utf32_sinhala_ci": 179, //"utf32_german2_ci": 180, //"utf32_croatian_ci": 181, //"utf32_unicode_520_ci": 182, //"utf32_vietnamese_ci": 183, "utf8_unicode_ci": 192, "utf8_icelandic_ci": 193, "utf8_latvian_ci": 194, "utf8_romanian_ci": 195, "utf8_slovenian_ci": 196, "utf8_polish_ci": 197, "utf8_estonian_ci": 198, "utf8_spanish_ci": 199, "utf8_swedish_ci": 200, "utf8_turkish_ci": 201, "utf8_czech_ci": 202, "utf8_danish_ci": 203, "utf8_lithuanian_ci": 204, "utf8_slovak_ci": 205, "utf8_spanish2_ci": 206, "utf8_roman_ci": 207, "utf8_persian_ci": 208, "utf8_esperanto_ci": 209, "utf8_hungarian_ci": 210, "utf8_sinhala_ci": 211, "utf8_german2_ci": 212, "utf8_croatian_ci": 213, "utf8_unicode_520_ci": 214, "utf8_vietnamese_ci": 215, "utf8_general_mysql500_ci": 223, "utf8mb4_unicode_ci": 224, "utf8mb4_icelandic_ci": 225, "utf8mb4_latvian_ci": 226, "utf8mb4_romanian_ci": 227, "utf8mb4_slovenian_ci": 228, "utf8mb4_polish_ci": 229, "utf8mb4_estonian_ci": 230, "utf8mb4_spanish_ci": 231, "utf8mb4_swedish_ci": 232, "utf8mb4_turkish_ci": 233, "utf8mb4_czech_ci": 234, "utf8mb4_danish_ci": 235, "utf8mb4_lithuanian_ci": 236, "utf8mb4_slovak_ci": 237, "utf8mb4_spanish2_ci": 238, "utf8mb4_roman_ci": 239, "utf8mb4_persian_ci": 240, "utf8mb4_esperanto_ci": 241, "utf8mb4_hungarian_ci": 242, "utf8mb4_sinhala_ci": 243, "utf8mb4_german2_ci": 244, "utf8mb4_croatian_ci": 245, "utf8mb4_unicode_520_ci": 246, "utf8mb4_vietnamese_ci": 247, "gb18030_chinese_ci": 248, "gb18030_bin": 249, "gb18030_unicode_520_ci": 250, "utf8mb4_0900_ai_ci": 255, } // A denylist of collations which is unsafe to interpolate parameters. // These multibyte encodings may contains 0x5c (`\`) in their trailing bytes. var unsafeCollations = map[string]bool{ "big5_chinese_ci": true, "sjis_japanese_ci": true, "gbk_chinese_ci": true, "big5_bin": true, "gb2312_bin": true, "gbk_bin": true, "sjis_bin": true, "cp932_japanese_ci": true, "cp932_bin": true, "gb18030_chinese_ci": true, "gb18030_bin": true, "gb18030_unicode_520_ci": true, } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/conncheck.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2019 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. //go:build linux || darwin || dragonfly || freebsd || netbsd || openbsd || solaris || illumos // +build linux darwin dragonfly freebsd netbsd openbsd solaris illumos package mysql import ( "errors" "io" "net" "syscall" ) var errUnexpectedRead = errors.New("unexpected read from socket") func connCheck(conn net.Conn) error { var sysErr error sysConn, ok := conn.(syscall.Conn) if !ok { return nil } rawConn, err := sysConn.SyscallConn() if err != nil { return err } err = rawConn.Read(func(fd uintptr) bool { var buf [1]byte n, err := syscall.Read(int(fd), buf[:]) switch { case n == 0 && err == nil: sysErr = io.EOF case n > 0: sysErr = errUnexpectedRead case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK: sysErr = nil default: sysErr = err } return true }) if err != nil { return err } return sysErr } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2019 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. //go:build !linux && !darwin && !dragonfly && !freebsd && !netbsd && !openbsd && !solaris && !illumos // +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!illumos package mysql import "net" func connCheck(conn net.Conn) error { return nil } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/connection.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "context" "database/sql" "database/sql/driver" "encoding/json" "io" "net" "strconv" "strings" "time" ) type mysqlConn struct { buf buffer netConn net.Conn rawConn net.Conn // underlying connection when netConn is TLS connection. result mysqlResult // managed by clearResult() and handleOkPacket(). cfg *Config connector *connector maxAllowedPacket int maxWriteSize int writeTimeout time.Duration flags clientFlag status statusFlag sequence uint8 parseTime bool // for context support (Go 1.8+) watching bool watcher chan<- context.Context closech chan struct{} finished chan<- struct{} canceled atomicError // set non-nil if conn is canceled closed atomicBool // set when conn is closed, before closech is closed } // Handles parameters set in DSN after the connection is established func (mc *mysqlConn) handleParams() (err error) { var cmdSet strings.Builder for param, val := range mc.cfg.Params { switch param { // Charset: character_set_connection, character_set_client, character_set_results case "charset": charsets := strings.Split(val, ",") for _, cs := range charsets { // ignore errors here - a charset may not exist if mc.cfg.Collation != "" { err = mc.exec("SET NAMES " + cs + " COLLATE " + mc.cfg.Collation) } else { err = mc.exec("SET NAMES " + cs) } if err == nil { break } } if err != nil { return } // Other system vars accumulated in a single SET command default: if cmdSet.Len() == 0 { // Heuristic: 29 chars for each other key=value to reduce reallocations cmdSet.Grow(4 + len(param) + 3 + len(val) + 30*(len(mc.cfg.Params)-1)) cmdSet.WriteString("SET ") } else { cmdSet.WriteString(", ") } cmdSet.WriteString(param) cmdSet.WriteString(" = ") cmdSet.WriteString(val) } } if cmdSet.Len() > 0 { err = mc.exec(cmdSet.String()) if err != nil { return } } return } func (mc *mysqlConn) markBadConn(err error) error { if mc == nil { return err } if err != errBadConnNoWrite { return err } return driver.ErrBadConn } func (mc *mysqlConn) Begin() (driver.Tx, error) { return mc.begin(false) } func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) { if mc.closed.Load() { mc.cfg.Logger.Print(ErrInvalidConn) return nil, driver.ErrBadConn } var q string if readOnly { q = "START TRANSACTION READ ONLY" } else { q = "START TRANSACTION" } err := mc.exec(q) if err == nil { return &mysqlTx{mc}, err } return nil, mc.markBadConn(err) } func (mc *mysqlConn) Close() (err error) { // Makes Close idempotent if !mc.closed.Load() { err = mc.writeCommandPacket(comQuit) } mc.cleanup() return } // Closes the network connection and unsets internal variables. Do not call this // function after successfully authentication, call Close instead. This function // is called before auth or on auth failure because MySQL will have already // closed the network connection. func (mc *mysqlConn) cleanup() { if mc.closed.Swap(true) { return } // Makes cleanup idempotent close(mc.closech) if mc.netConn == nil { return } if err := mc.netConn.Close(); err != nil { mc.cfg.Logger.Print(err) } mc.clearResult() } func (mc *mysqlConn) error() error { if mc.closed.Load() { if err := mc.canceled.Value(); err != nil { return err } return ErrInvalidConn } return nil } func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { if mc.closed.Load() { mc.cfg.Logger.Print(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command err := mc.writeCommandPacketStr(comStmtPrepare, query) if err != nil { // STMT_PREPARE is safe to retry. So we can return ErrBadConn here. mc.cfg.Logger.Print(err) return nil, driver.ErrBadConn } stmt := &mysqlStmt{ mc: mc, } // Read Result columnCount, err := stmt.readPrepareResultPacket() if err == nil { if stmt.paramCount > 0 { if err = mc.readUntilEOF(); err != nil { return nil, err } } if columnCount > 0 { err = mc.readUntilEOF() } } return stmt, err } func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) { // Number of ? should be same to len(args) if strings.Count(query, "?") != len(args) { return "", driver.ErrSkip } buf, err := mc.buf.takeCompleteBuffer() if err != nil { // can not take the buffer. Something must be wrong with the connection mc.cfg.Logger.Print(err) return "", ErrInvalidConn } buf = buf[:0] argPos := 0 for i := 0; i < len(query); i++ { q := strings.IndexByte(query[i:], '?') if q == -1 { buf = append(buf, query[i:]...) break } buf = append(buf, query[i:i+q]...) i += q arg := args[argPos] argPos++ if arg == nil { buf = append(buf, "NULL"...) continue } switch v := arg.(type) { case int64: buf = strconv.AppendInt(buf, v, 10) case uint64: // Handle uint64 explicitly because our custom ConvertValue emits unsigned values buf = strconv.AppendUint(buf, v, 10) case float64: buf = strconv.AppendFloat(buf, v, 'g', -1, 64) case bool: if v { buf = append(buf, '1') } else { buf = append(buf, '0') } case time.Time: if v.IsZero() { buf = append(buf, "'0000-00-00'"...) } else { buf = append(buf, '\'') buf, err = appendDateTime(buf, v.In(mc.cfg.Loc), mc.cfg.timeTruncate) if err != nil { return "", err } buf = append(buf, '\'') } case json.RawMessage: buf = append(buf, '\'') if mc.status&statusNoBackslashEscapes == 0 { buf = escapeBytesBackslash(buf, v) } else { buf = escapeBytesQuotes(buf, v) } buf = append(buf, '\'') case []byte: if v == nil { buf = append(buf, "NULL"...) } else { buf = append(buf, "_binary'"...) if mc.status&statusNoBackslashEscapes == 0 { buf = escapeBytesBackslash(buf, v) } else { buf = escapeBytesQuotes(buf, v) } buf = append(buf, '\'') } case string: buf = append(buf, '\'') if mc.status&statusNoBackslashEscapes == 0 { buf = escapeStringBackslash(buf, v) } else { buf = escapeStringQuotes(buf, v) } buf = append(buf, '\'') default: return "", driver.ErrSkip } if len(buf)+4 > mc.maxAllowedPacket { return "", driver.ErrSkip } } if argPos != len(args) { return "", driver.ErrSkip } return string(buf), nil } func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { if mc.closed.Load() { mc.cfg.Logger.Print(ErrInvalidConn) return nil, driver.ErrBadConn } if len(args) != 0 { if !mc.cfg.InterpolateParams { return nil, driver.ErrSkip } // try to interpolate the parameters to save extra roundtrips for preparing and closing a statement prepared, err := mc.interpolateParams(query, args) if err != nil { return nil, err } query = prepared } err := mc.exec(query) if err == nil { copied := mc.result return &copied, err } return nil, mc.markBadConn(err) } // Internal function to execute commands func (mc *mysqlConn) exec(query string) error { handleOk := mc.clearResult() // Send command if err := mc.writeCommandPacketStr(comQuery, query); err != nil { return mc.markBadConn(err) } // Read Result resLen, err := handleOk.readResultSetHeaderPacket() if err != nil { return err } if resLen > 0 { // columns if err := mc.readUntilEOF(); err != nil { return err } // rows if err := mc.readUntilEOF(); err != nil { return err } } return handleOk.discardResults() } func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) { return mc.query(query, args) } func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) { handleOk := mc.clearResult() if mc.closed.Load() { mc.cfg.Logger.Print(ErrInvalidConn) return nil, driver.ErrBadConn } if len(args) != 0 { if !mc.cfg.InterpolateParams { return nil, driver.ErrSkip } // try client-side prepare to reduce roundtrip prepared, err := mc.interpolateParams(query, args) if err != nil { return nil, err } query = prepared } // Send command err := mc.writeCommandPacketStr(comQuery, query) if err == nil { // Read Result var resLen int resLen, err = handleOk.readResultSetHeaderPacket() if err == nil { rows := new(textRows) rows.mc = mc if resLen == 0 { rows.rs.done = true switch err := rows.NextResultSet(); err { case nil, io.EOF: return rows, nil default: return nil, err } } // Columns rows.rs.columns, err = mc.readColumns(resLen) return rows, err } } return nil, mc.markBadConn(err) } // Gets the value of the given MySQL System Variable // The returned byte slice is only valid until the next read func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { // Send command handleOk := mc.clearResult() if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil { return nil, err } // Read Result resLen, err := handleOk.readResultSetHeaderPacket() if err == nil { rows := new(textRows) rows.mc = mc rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}} if resLen > 0 { // Columns if err := mc.readUntilEOF(); err != nil { return nil, err } } dest := make([]driver.Value, resLen) if err = rows.readRow(dest); err == nil { return dest[0].([]byte), mc.readUntilEOF() } } return nil, err } // finish is called when the query has canceled. func (mc *mysqlConn) cancel(err error) { mc.canceled.Set(err) mc.cleanup() } // finish is called when the query has succeeded. func (mc *mysqlConn) finish() { if !mc.watching || mc.finished == nil { return } select { case mc.finished <- struct{}{}: mc.watching = false case <-mc.closech: } } // Ping implements driver.Pinger interface func (mc *mysqlConn) Ping(ctx context.Context) (err error) { if mc.closed.Load() { mc.cfg.Logger.Print(ErrInvalidConn) return driver.ErrBadConn } if err = mc.watchCancel(ctx); err != nil { return } defer mc.finish() handleOk := mc.clearResult() if err = mc.writeCommandPacket(comPing); err != nil { return mc.markBadConn(err) } return handleOk.readResultOK() } // BeginTx implements driver.ConnBeginTx interface func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { if mc.closed.Load() { return nil, driver.ErrBadConn } if err := mc.watchCancel(ctx); err != nil { return nil, err } defer mc.finish() if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault { level, err := mapIsolationLevel(opts.Isolation) if err != nil { return nil, err } err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level) if err != nil { return nil, err } } return mc.begin(opts.ReadOnly) } func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { dargs, err := namedValueToValue(args) if err != nil { return nil, err } if err := mc.watchCancel(ctx); err != nil { return nil, err } rows, err := mc.query(query, dargs) if err != nil { mc.finish() return nil, err } rows.finish = mc.finish return rows, err } func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { dargs, err := namedValueToValue(args) if err != nil { return nil, err } if err := mc.watchCancel(ctx); err != nil { return nil, err } defer mc.finish() return mc.Exec(query, dargs) } func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { if err := mc.watchCancel(ctx); err != nil { return nil, err } stmt, err := mc.Prepare(query) mc.finish() if err != nil { return nil, err } select { default: case <-ctx.Done(): stmt.Close() return nil, ctx.Err() } return stmt, nil } func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { dargs, err := namedValueToValue(args) if err != nil { return nil, err } if err := stmt.mc.watchCancel(ctx); err != nil { return nil, err } rows, err := stmt.query(dargs) if err != nil { stmt.mc.finish() return nil, err } rows.finish = stmt.mc.finish return rows, err } func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { dargs, err := namedValueToValue(args) if err != nil { return nil, err } if err := stmt.mc.watchCancel(ctx); err != nil { return nil, err } defer stmt.mc.finish() return stmt.Exec(dargs) } func (mc *mysqlConn) watchCancel(ctx context.Context) error { if mc.watching { // Reach here if canceled, // so the connection is already invalid mc.cleanup() return nil } // When ctx is already cancelled, don't watch it. if err := ctx.Err(); err != nil { return err } // When ctx is not cancellable, don't watch it. if ctx.Done() == nil { return nil } // When watcher is not alive, can't watch it. if mc.watcher == nil { return nil } mc.watching = true mc.watcher <- ctx return nil } func (mc *mysqlConn) startWatcher() { watcher := make(chan context.Context, 1) mc.watcher = watcher finished := make(chan struct{}) mc.finished = finished go func() { for { var ctx context.Context select { case ctx = <-watcher: case <-mc.closech: return } select { case <-ctx.Done(): mc.cancel(ctx.Err()) case <-finished: case <-mc.closech: return } } }() } func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) { nv.Value, err = converter{}.ConvertValue(nv.Value) return } // ResetSession implements driver.SessionResetter. // (From Go 1.10) func (mc *mysqlConn) ResetSession(ctx context.Context) error { if mc.closed.Load() { return driver.ErrBadConn } // Perform a stale connection check. We only perform this check for // the first query on a connection that has been checked out of the // connection pool: a fresh connection from the pool is more likely // to be stale, and it has not performed any previous writes that // could cause data corruption, so it's safe to return ErrBadConn // if the check fails. if mc.cfg.CheckConnLiveness { conn := mc.netConn if mc.rawConn != nil { conn = mc.rawConn } var err error if mc.cfg.ReadTimeout != 0 { err = conn.SetReadDeadline(time.Now().Add(mc.cfg.ReadTimeout)) } if err == nil { err = connCheck(conn) } if err != nil { mc.cfg.Logger.Print("closing bad idle connection: ", err) return driver.ErrBadConn } } return nil } // IsValid implements driver.Validator interface // (From Go 1.15) func (mc *mysqlConn) IsValid() bool { return !mc.closed.Load() } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/connector.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "context" "database/sql/driver" "net" "os" "strconv" "strings" ) type connector struct { cfg *Config // immutable private copy. encodedAttributes string // Encoded connection attributes. } func encodeConnectionAttributes(cfg *Config) string { connAttrsBuf := make([]byte, 0) // default connection attributes connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrClientName) connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrClientNameValue) connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrOS) connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrOSValue) connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPlatform) connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPlatformValue) connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPid) connAttrsBuf = appendLengthEncodedString(connAttrsBuf, strconv.Itoa(os.Getpid())) serverHost, _, _ := net.SplitHostPort(cfg.Addr) if serverHost != "" { connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrServerHost) connAttrsBuf = appendLengthEncodedString(connAttrsBuf, serverHost) } // user-defined connection attributes for _, connAttr := range strings.Split(cfg.ConnectionAttributes, ",") { k, v, found := strings.Cut(connAttr, ":") if !found { continue } connAttrsBuf = appendLengthEncodedString(connAttrsBuf, k) connAttrsBuf = appendLengthEncodedString(connAttrsBuf, v) } return string(connAttrsBuf) } func newConnector(cfg *Config) *connector { encodedAttributes := encodeConnectionAttributes(cfg) return &connector{ cfg: cfg, encodedAttributes: encodedAttributes, } } // Connect implements driver.Connector interface. // Connect returns a connection to the database. func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { var err error // Invoke beforeConnect if present, with a copy of the configuration cfg := c.cfg if c.cfg.beforeConnect != nil { cfg = c.cfg.Clone() err = c.cfg.beforeConnect(ctx, cfg) if err != nil { return nil, err } } // New mysqlConn mc := &mysqlConn{ maxAllowedPacket: maxPacketSize, maxWriteSize: maxPacketSize - 1, closech: make(chan struct{}), cfg: cfg, connector: c, } mc.parseTime = mc.cfg.ParseTime // Connect to Server dialsLock.RLock() dial, ok := dials[mc.cfg.Net] dialsLock.RUnlock() if ok { dctx := ctx if mc.cfg.Timeout > 0 { var cancel context.CancelFunc dctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout) defer cancel() } mc.netConn, err = dial(dctx, mc.cfg.Addr) } else { nd := net.Dialer{Timeout: mc.cfg.Timeout} mc.netConn, err = nd.DialContext(ctx, mc.cfg.Net, mc.cfg.Addr) } if err != nil { return nil, err } // Enable TCP Keepalives on TCP connections if tc, ok := mc.netConn.(*net.TCPConn); ok { if err := tc.SetKeepAlive(true); err != nil { c.cfg.Logger.Print(err) } } // Call startWatcher for context support (From Go 1.8) mc.startWatcher() if err := mc.watchCancel(ctx); err != nil { mc.cleanup() return nil, err } defer mc.finish() mc.buf = newBuffer(mc.netConn) // Set I/O timeouts mc.buf.timeout = mc.cfg.ReadTimeout mc.writeTimeout = mc.cfg.WriteTimeout // Reading Handshake Initialization Packet authData, plugin, err := mc.readHandshakePacket() if err != nil { mc.cleanup() return nil, err } if plugin == "" { plugin = defaultAuthPlugin } // Send Client Authentication Packet authResp, err := mc.auth(authData, plugin) if err != nil { // try the default auth plugin, if using the requested plugin failed c.cfg.Logger.Print("could not use requested auth plugin '"+plugin+"': ", err.Error()) plugin = defaultAuthPlugin authResp, err = mc.auth(authData, plugin) if err != nil { mc.cleanup() return nil, err } } if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil { mc.cleanup() return nil, err } // Handle response to auth packet, switch methods if possible if err = mc.handleAuthResult(authData, plugin); err != nil { // Authentication failed and MySQL has already closed the connection // (https://dev.mysql.com/doc/internals/en/authentication-fails.html). // Do not send COM_QUIT, just cleanup and return the error. mc.cleanup() return nil, err } if mc.cfg.MaxAllowedPacket > 0 { mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket } else { // Get max allowed packet size maxap, err := mc.getSystemVar("max_allowed_packet") if err != nil { mc.Close() return nil, err } mc.maxAllowedPacket = stringToInt(maxap) - 1 } if mc.maxAllowedPacket < maxPacketSize { mc.maxWriteSize = mc.maxAllowedPacket } // Handle DSN Params err = mc.handleParams() if err != nil { mc.Close() return nil, err } return mc, nil } // Driver implements driver.Connector interface. // Driver returns &MySQLDriver{}. func (c *connector) Driver() driver.Driver { return &MySQLDriver{} } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/const.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import "runtime" const ( defaultAuthPlugin = "mysql_native_password" defaultMaxAllowedPacket = 64 << 20 // 64 MiB. See https://github.com/go-sql-driver/mysql/issues/1355 minProtocolVersion = 10 maxPacketSize = 1<<24 - 1 timeFormat = "2006-01-02 15:04:05.999999" // Connection attributes // See https://dev.mysql.com/doc/refman/8.0/en/performance-schema-connection-attribute-tables.html#performance-schema-connection-attributes-available connAttrClientName = "_client_name" connAttrClientNameValue = "Go-MySQL-Driver" connAttrOS = "_os" connAttrOSValue = runtime.GOOS connAttrPlatform = "_platform" connAttrPlatformValue = runtime.GOARCH connAttrPid = "_pid" connAttrServerHost = "_server_host" ) // MySQL constants documentation: // http://dev.mysql.com/doc/internals/en/client-server-protocol.html const ( iOK byte = 0x00 iAuthMoreData byte = 0x01 iLocalInFile byte = 0xfb iEOF byte = 0xfe iERR byte = 0xff ) // https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags type clientFlag uint32 const ( clientLongPassword clientFlag = 1 << iota clientFoundRows clientLongFlag clientConnectWithDB clientNoSchema clientCompress clientODBC clientLocalFiles clientIgnoreSpace clientProtocol41 clientInteractive clientSSL clientIgnoreSIGPIPE clientTransactions clientReserved clientSecureConn clientMultiStatements clientMultiResults clientPSMultiResults clientPluginAuth clientConnectAttrs clientPluginAuthLenEncClientData clientCanHandleExpiredPasswords clientSessionTrack clientDeprecateEOF ) const ( comQuit byte = iota + 1 comInitDB comQuery comFieldList comCreateDB comDropDB comRefresh comShutdown comStatistics comProcessInfo comConnect comProcessKill comDebug comPing comTime comDelayedInsert comChangeUser comBinlogDump comTableDump comConnectOut comRegisterSlave comStmtPrepare comStmtExecute comStmtSendLongData comStmtClose comStmtReset comSetOption comStmtFetch ) // https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType type fieldType byte const ( fieldTypeDecimal fieldType = iota fieldTypeTiny fieldTypeShort fieldTypeLong fieldTypeFloat fieldTypeDouble fieldTypeNULL fieldTypeTimestamp fieldTypeLongLong fieldTypeInt24 fieldTypeDate fieldTypeTime fieldTypeDateTime fieldTypeYear fieldTypeNewDate fieldTypeVarChar fieldTypeBit ) const ( fieldTypeJSON fieldType = iota + 0xf5 fieldTypeNewDecimal fieldTypeEnum fieldTypeSet fieldTypeTinyBLOB fieldTypeMediumBLOB fieldTypeLongBLOB fieldTypeBLOB fieldTypeVarString fieldTypeString fieldTypeGeometry ) type fieldFlag uint16 const ( flagNotNULL fieldFlag = 1 << iota flagPriKey flagUniqueKey flagMultipleKey flagBLOB flagUnsigned flagZeroFill flagBinary flagEnum flagAutoIncrement flagTimestamp flagSet flagUnknown1 flagUnknown2 flagUnknown3 flagUnknown4 ) // http://dev.mysql.com/doc/internals/en/status-flags.html type statusFlag uint16 const ( statusInTrans statusFlag = 1 << iota statusInAutocommit statusReserved // Not in documentation statusMoreResultsExists statusNoGoodIndexUsed statusNoIndexUsed statusCursorExists statusLastRowSent statusDbDropped statusNoBackslashEscapes statusMetadataChanged statusQueryWasSlow statusPsOutParams statusInTransReadonly statusSessionStateChanged ) const ( cachingSha2PasswordRequestPublicKey = 2 cachingSha2PasswordFastAuthSuccess = 3 cachingSha2PasswordPerformFullAuthentication = 4 ) ================================================ FILE: vendor/github.com/go-sql-driver/mysql/driver.go ================================================ // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. // Package mysql provides a MySQL driver for Go's database/sql package. // // The driver should be used via the database/sql package: // // import "database/sql" // import _ "github.com/go-sql-driver/mysql" // // db, err := sql.Open("mysql", "user:password@/dbname") // // See https://github.com/go-sql-driver/mysql#usage for details package mysql import ( "context" "database/sql" "database/sql/driver" "net" "sync" ) // MySQLDriver is exported to make the driver directly accessible. // In general the driver is used via the database/sql package. type MySQLDriver struct{} // DialFunc is a function which can be used to establish the network connection. // Custom dial functions must be registered with RegisterDial // // Deprecated: users should register a DialContextFunc instead type DialFunc func(addr string) (net.Conn, error) // DialContextFunc is a function which can be used to establish the network connection. // Custom dial functions must be registered with RegisterDialContext type DialContextFunc func(ctx context.Context, addr string) (net.Conn, error) var ( dialsLock sync.RWMutex dials map[string]DialContextFunc ) // RegisterDialContext registers a custom dial function. It can then be used by the // network address mynet(addr), where mynet is the registered new network. // The current context for the connection and its address is passed to the dial function. func RegisterDialContext(net string, dial DialContextFunc) { dialsLock.Lock() defer dialsLock.Unlock() if dials == nil { dials = make(map[string]DialContextFunc) } dials[net] = dial } // DeregisterDialContext removes the custom dial function registered with the given net. func DeregisterDialContext(net string) { dialsLock.Lock() defer dialsLock.Unlock() if dials != nil { delete(dials, net) } } // RegisterDial registers a custom dial function. It can then be used by the // network address mynet(addr), where mynet is the registered new network. // addr is passed as a parameter to the dial function. // // Deprecated: users should call RegisterDialContext instead func RegisterDial(network string, dial DialFunc) { RegisterDialContext(network, func(_ context.Context, addr string) (net.Conn, error) { return dial(addr) }) } // Open new Connection. // See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how // the DSN string is formatted func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { cfg, err := ParseDSN(dsn) if err != nil { return nil, err } c := newConnector(cfg) return c.Connect(context.Background()) } // This variable can be replaced with -ldflags like below: // go build "-ldflags=-X github.com/go-sql-driver/mysql.driverName=custom" var driverName = "mysql" func init() { if driverName != "" { sql.Register(driverName, &MySQLDriver{}) } } // NewConnector returns new driver.Connector. func NewConnector(cfg *Config) (driver.Connector, error) { cfg = cfg.Clone() // normalize the contents of cfg so calls to NewConnector have the same // behavior as MySQLDriver.OpenConnector if err := cfg.normalize(); err != nil { return nil, err } return newConnector(cfg), nil } // OpenConnector implements driver.DriverContext. func (d MySQLDriver) OpenConnector(dsn string) (driver.Connector, error) { cfg, err := ParseDSN(dsn) if err != nil { return nil, err } return newConnector(cfg), nil } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/dsn.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "bytes" "context" "crypto/rsa" "crypto/tls" "errors" "fmt" "math/big" "net" "net/url" "sort" "strconv" "strings" "time" ) var ( errInvalidDSNUnescaped = errors.New("invalid DSN: did you forget to escape a param value?") errInvalidDSNAddr = errors.New("invalid DSN: network address not terminated (missing closing brace)") errInvalidDSNNoSlash = errors.New("invalid DSN: missing the slash separating the database name") errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations") ) // Config is a configuration parsed from a DSN string. // If a new Config is created instead of being parsed from a DSN string, // the NewConfig function should be used, which sets default values. type Config struct { // non boolean fields User string // Username Passwd string // Password (requires User) Net string // Network (e.g. "tcp", "tcp6", "unix". default: "tcp") Addr string // Address (default: "127.0.0.1:3306" for "tcp" and "/tmp/mysql.sock" for "unix") DBName string // Database name Params map[string]string // Connection parameters ConnectionAttributes string // Connection Attributes, comma-delimited string of user-defined "key:value" pairs Collation string // Connection collation Loc *time.Location // Location for time.Time values MaxAllowedPacket int // Max packet size allowed ServerPubKey string // Server public key name TLSConfig string // TLS configuration name TLS *tls.Config // TLS configuration, its priority is higher than TLSConfig Timeout time.Duration // Dial timeout ReadTimeout time.Duration // I/O read timeout WriteTimeout time.Duration // I/O write timeout Logger Logger // Logger // boolean fields AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE AllowCleartextPasswords bool // Allows the cleartext client side plugin AllowFallbackToPlaintext bool // Allows fallback to unencrypted connection if server does not support TLS AllowNativePasswords bool // Allows the native password authentication method AllowOldPasswords bool // Allows the old insecure password method CheckConnLiveness bool // Check connections for liveness before using them ClientFoundRows bool // Return number of matching rows instead of rows changed ColumnsWithAlias bool // Prepend table alias to column names InterpolateParams bool // Interpolate placeholders into query string MultiStatements bool // Allow multiple statements in one query ParseTime bool // Parse time values to time.Time RejectReadOnly bool // Reject read-only connections // unexported fields. new options should be come here beforeConnect func(context.Context, *Config) error // Invoked before a connection is established pubKey *rsa.PublicKey // Server public key timeTruncate time.Duration // Truncate time.Time values to the specified duration } // Functional Options Pattern // https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis type Option func(*Config) error // NewConfig creates a new Config and sets default values. func NewConfig() *Config { cfg := &Config{ Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, Logger: defaultLogger, AllowNativePasswords: true, CheckConnLiveness: true, } return cfg } // Apply applies the given options to the Config object. func (c *Config) Apply(opts ...Option) error { for _, opt := range opts { err := opt(c) if err != nil { return err } } return nil } // TimeTruncate sets the time duration to truncate time.Time values in // query parameters. func TimeTruncate(d time.Duration) Option { return func(cfg *Config) error { cfg.timeTruncate = d return nil } } // BeforeConnect sets the function to be invoked before a connection is established. func BeforeConnect(fn func(context.Context, *Config) error) Option { return func(cfg *Config) error { cfg.beforeConnect = fn return nil } } func (cfg *Config) Clone() *Config { cp := *cfg if cp.TLS != nil { cp.TLS = cfg.TLS.Clone() } if len(cp.Params) > 0 { cp.Params = make(map[string]string, len(cfg.Params)) for k, v := range cfg.Params { cp.Params[k] = v } } if cfg.pubKey != nil { cp.pubKey = &rsa.PublicKey{ N: new(big.Int).Set(cfg.pubKey.N), E: cfg.pubKey.E, } } return &cp } func (cfg *Config) normalize() error { if cfg.InterpolateParams && cfg.Collation != "" && unsafeCollations[cfg.Collation] { return errInvalidDSNUnsafeCollation } // Set default network if empty if cfg.Net == "" { cfg.Net = "tcp" } // Set default address if empty if cfg.Addr == "" { switch cfg.Net { case "tcp": cfg.Addr = "127.0.0.1:3306" case "unix": cfg.Addr = "/tmp/mysql.sock" default: return errors.New("default addr for network '" + cfg.Net + "' unknown") } } else if cfg.Net == "tcp" { cfg.Addr = ensureHavePort(cfg.Addr) } if cfg.TLS == nil { switch cfg.TLSConfig { case "false", "": // don't set anything case "true": cfg.TLS = &tls.Config{} case "skip-verify": cfg.TLS = &tls.Config{InsecureSkipVerify: true} case "preferred": cfg.TLS = &tls.Config{InsecureSkipVerify: true} cfg.AllowFallbackToPlaintext = true default: cfg.TLS = getTLSConfigClone(cfg.TLSConfig) if cfg.TLS == nil { return errors.New("invalid value / unknown config name: " + cfg.TLSConfig) } } } if cfg.TLS != nil && cfg.TLS.ServerName == "" && !cfg.TLS.InsecureSkipVerify { host, _, err := net.SplitHostPort(cfg.Addr) if err == nil { cfg.TLS.ServerName = host } } if cfg.ServerPubKey != "" { cfg.pubKey = getServerPubKey(cfg.ServerPubKey) if cfg.pubKey == nil { return errors.New("invalid value / unknown server pub key name: " + cfg.ServerPubKey) } } if cfg.Logger == nil { cfg.Logger = defaultLogger } return nil } func writeDSNParam(buf *bytes.Buffer, hasParam *bool, name, value string) { buf.Grow(1 + len(name) + 1 + len(value)) if !*hasParam { *hasParam = true buf.WriteByte('?') } else { buf.WriteByte('&') } buf.WriteString(name) buf.WriteByte('=') buf.WriteString(value) } // FormatDSN formats the given Config into a DSN string which can be passed to // the driver. // // Note: use [NewConnector] and [database/sql.OpenDB] to open a connection from a [*Config]. func (cfg *Config) FormatDSN() string { var buf bytes.Buffer // [username[:password]@] if len(cfg.User) > 0 { buf.WriteString(cfg.User) if len(cfg.Passwd) > 0 { buf.WriteByte(':') buf.WriteString(cfg.Passwd) } buf.WriteByte('@') } // [protocol[(address)]] if len(cfg.Net) > 0 { buf.WriteString(cfg.Net) if len(cfg.Addr) > 0 { buf.WriteByte('(') buf.WriteString(cfg.Addr) buf.WriteByte(')') } } // /dbname buf.WriteByte('/') buf.WriteString(url.PathEscape(cfg.DBName)) // [?param1=value1&...¶mN=valueN] hasParam := false if cfg.AllowAllFiles { hasParam = true buf.WriteString("?allowAllFiles=true") } if cfg.AllowCleartextPasswords { writeDSNParam(&buf, &hasParam, "allowCleartextPasswords", "true") } if cfg.AllowFallbackToPlaintext { writeDSNParam(&buf, &hasParam, "allowFallbackToPlaintext", "true") } if !cfg.AllowNativePasswords { writeDSNParam(&buf, &hasParam, "allowNativePasswords", "false") } if cfg.AllowOldPasswords { writeDSNParam(&buf, &hasParam, "allowOldPasswords", "true") } if !cfg.CheckConnLiveness { writeDSNParam(&buf, &hasParam, "checkConnLiveness", "false") } if cfg.ClientFoundRows { writeDSNParam(&buf, &hasParam, "clientFoundRows", "true") } if col := cfg.Collation; col != "" { writeDSNParam(&buf, &hasParam, "collation", col) } if cfg.ColumnsWithAlias { writeDSNParam(&buf, &hasParam, "columnsWithAlias", "true") } if cfg.InterpolateParams { writeDSNParam(&buf, &hasParam, "interpolateParams", "true") } if cfg.Loc != time.UTC && cfg.Loc != nil { writeDSNParam(&buf, &hasParam, "loc", url.QueryEscape(cfg.Loc.String())) } if cfg.MultiStatements { writeDSNParam(&buf, &hasParam, "multiStatements", "true") } if cfg.ParseTime { writeDSNParam(&buf, &hasParam, "parseTime", "true") } if cfg.timeTruncate > 0 { writeDSNParam(&buf, &hasParam, "timeTruncate", cfg.timeTruncate.String()) } if cfg.ReadTimeout > 0 { writeDSNParam(&buf, &hasParam, "readTimeout", cfg.ReadTimeout.String()) } if cfg.RejectReadOnly { writeDSNParam(&buf, &hasParam, "rejectReadOnly", "true") } if len(cfg.ServerPubKey) > 0 { writeDSNParam(&buf, &hasParam, "serverPubKey", url.QueryEscape(cfg.ServerPubKey)) } if cfg.Timeout > 0 { writeDSNParam(&buf, &hasParam, "timeout", cfg.Timeout.String()) } if len(cfg.TLSConfig) > 0 { writeDSNParam(&buf, &hasParam, "tls", url.QueryEscape(cfg.TLSConfig)) } if cfg.WriteTimeout > 0 { writeDSNParam(&buf, &hasParam, "writeTimeout", cfg.WriteTimeout.String()) } if cfg.MaxAllowedPacket != defaultMaxAllowedPacket { writeDSNParam(&buf, &hasParam, "maxAllowedPacket", strconv.Itoa(cfg.MaxAllowedPacket)) } // other params if cfg.Params != nil { var params []string for param := range cfg.Params { params = append(params, param) } sort.Strings(params) for _, param := range params { writeDSNParam(&buf, &hasParam, param, url.QueryEscape(cfg.Params[param])) } } return buf.String() } // ParseDSN parses the DSN string to a Config func ParseDSN(dsn string) (cfg *Config, err error) { // New config with some default values cfg = NewConfig() // [user[:password]@][net[(addr)]]/dbname[?param1=value1¶mN=valueN] // Find the last '/' (since the password or the net addr might contain a '/') foundSlash := false for i := len(dsn) - 1; i >= 0; i-- { if dsn[i] == '/' { foundSlash = true var j, k int // left part is empty if i <= 0 if i > 0 { // [username[:password]@][protocol[(address)]] // Find the last '@' in dsn[:i] for j = i; j >= 0; j-- { if dsn[j] == '@' { // username[:password] // Find the first ':' in dsn[:j] for k = 0; k < j; k++ { if dsn[k] == ':' { cfg.Passwd = dsn[k+1 : j] break } } cfg.User = dsn[:k] break } } // [protocol[(address)]] // Find the first '(' in dsn[j+1:i] for k = j + 1; k < i; k++ { if dsn[k] == '(' { // dsn[i-1] must be == ')' if an address is specified if dsn[i-1] != ')' { if strings.ContainsRune(dsn[k+1:i], ')') { return nil, errInvalidDSNUnescaped } return nil, errInvalidDSNAddr } cfg.Addr = dsn[k+1 : i-1] break } } cfg.Net = dsn[j+1 : k] } // dbname[?param1=value1&...¶mN=valueN] // Find the first '?' in dsn[i+1:] for j = i + 1; j < len(dsn); j++ { if dsn[j] == '?' { if err = parseDSNParams(cfg, dsn[j+1:]); err != nil { return } break } } dbname := dsn[i+1 : j] if cfg.DBName, err = url.PathUnescape(dbname); err != nil { return nil, fmt.Errorf("invalid dbname %q: %w", dbname, err) } break } } if !foundSlash && len(dsn) > 0 { return nil, errInvalidDSNNoSlash } if err = cfg.normalize(); err != nil { return nil, err } return } // parseDSNParams parses the DSN "query string" // Values must be url.QueryEscape'ed func parseDSNParams(cfg *Config, params string) (err error) { for _, v := range strings.Split(params, "&") { key, value, found := strings.Cut(v, "=") if !found { continue } // cfg params switch key { // Disable INFILE allowlist / enable all files case "allowAllFiles": var isBool bool cfg.AllowAllFiles, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // Use cleartext authentication mode (MySQL 5.5.10+) case "allowCleartextPasswords": var isBool bool cfg.AllowCleartextPasswords, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // Allow fallback to unencrypted connection if server does not support TLS case "allowFallbackToPlaintext": var isBool bool cfg.AllowFallbackToPlaintext, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // Use native password authentication case "allowNativePasswords": var isBool bool cfg.AllowNativePasswords, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // Use old authentication mode (pre MySQL 4.1) case "allowOldPasswords": var isBool bool cfg.AllowOldPasswords, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // Check connections for Liveness before using them case "checkConnLiveness": var isBool bool cfg.CheckConnLiveness, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // Switch "rowsAffected" mode case "clientFoundRows": var isBool bool cfg.ClientFoundRows, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // Collation case "collation": cfg.Collation = value case "columnsWithAlias": var isBool bool cfg.ColumnsWithAlias, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // Compression case "compress": return errors.New("compression not implemented yet") // Enable client side placeholder substitution case "interpolateParams": var isBool bool cfg.InterpolateParams, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // Time Location case "loc": if value, err = url.QueryUnescape(value); err != nil { return } cfg.Loc, err = time.LoadLocation(value) if err != nil { return } // multiple statements in one query case "multiStatements": var isBool bool cfg.MultiStatements, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // time.Time parsing case "parseTime": var isBool bool cfg.ParseTime, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // time.Time truncation case "timeTruncate": cfg.timeTruncate, err = time.ParseDuration(value) if err != nil { return fmt.Errorf("invalid timeTruncate value: %v, error: %w", value, err) } // I/O read Timeout case "readTimeout": cfg.ReadTimeout, err = time.ParseDuration(value) if err != nil { return } // Reject read-only connections case "rejectReadOnly": var isBool bool cfg.RejectReadOnly, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } // Server public key case "serverPubKey": name, err := url.QueryUnescape(value) if err != nil { return fmt.Errorf("invalid value for server pub key name: %v", err) } cfg.ServerPubKey = name // Strict mode case "strict": panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode") // Dial Timeout case "timeout": cfg.Timeout, err = time.ParseDuration(value) if err != nil { return } // TLS-Encryption case "tls": boolValue, isBool := readBool(value) if isBool { if boolValue { cfg.TLSConfig = "true" } else { cfg.TLSConfig = "false" } } else if vl := strings.ToLower(value); vl == "skip-verify" || vl == "preferred" { cfg.TLSConfig = vl } else { name, err := url.QueryUnescape(value) if err != nil { return fmt.Errorf("invalid value for TLS config name: %v", err) } cfg.TLSConfig = name } // I/O write Timeout case "writeTimeout": cfg.WriteTimeout, err = time.ParseDuration(value) if err != nil { return } case "maxAllowedPacket": cfg.MaxAllowedPacket, err = strconv.Atoi(value) if err != nil { return } // Connection attributes case "connectionAttributes": connectionAttributes, err := url.QueryUnescape(value) if err != nil { return fmt.Errorf("invalid connectionAttributes value: %v", err) } cfg.ConnectionAttributes = connectionAttributes default: // lazy init if cfg.Params == nil { cfg.Params = make(map[string]string) } if cfg.Params[key], err = url.QueryUnescape(value); err != nil { return } } } return } func ensureHavePort(addr string) string { if _, _, err := net.SplitHostPort(addr); err != nil { return net.JoinHostPort(addr, "3306") } return addr } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/errors.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "errors" "fmt" "log" "os" ) // Various errors the driver might return. Can change between driver versions. var ( ErrInvalidConn = errors.New("invalid connection") ErrMalformPkt = errors.New("malformed packet") ErrNoTLS = errors.New("TLS requested but server does not support TLS") ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN") ErrNativePassword = errors.New("this user requires mysql native password authentication") ErrOldPassword = errors.New("this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords") ErrUnknownPlugin = errors.New("this authentication plugin is not supported") ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+") ErrPktSync = errors.New("commands out of sync. You can't run this command now") ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?") ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the `Config.MaxAllowedPacket`") ErrBusyBuffer = errors.New("busy buffer") // errBadConnNoWrite is used for connection errors where nothing was sent to the database yet. // If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn // to trigger a resend. // See https://github.com/go-sql-driver/mysql/pull/302 errBadConnNoWrite = errors.New("bad connection") ) var defaultLogger = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile)) // Logger is used to log critical error messages. type Logger interface { Print(v ...interface{}) } // NopLogger is a nop implementation of the Logger interface. type NopLogger struct{} // Print implements Logger interface. func (nl *NopLogger) Print(_ ...interface{}) {} // SetLogger is used to set the default logger for critical errors. // The initial logger is os.Stderr. func SetLogger(logger Logger) error { if logger == nil { return errors.New("logger is nil") } defaultLogger = logger return nil } // MySQLError is an error type which represents a single MySQL error type MySQLError struct { Number uint16 SQLState [5]byte Message string } func (me *MySQLError) Error() string { if me.SQLState != [5]byte{} { return fmt.Sprintf("Error %d (%s): %s", me.Number, me.SQLState, me.Message) } return fmt.Sprintf("Error %d: %s", me.Number, me.Message) } func (me *MySQLError) Is(err error) bool { if merr, ok := err.(*MySQLError); ok { return merr.Number == me.Number } return false } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/fields.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "database/sql" "reflect" ) func (mf *mysqlField) typeDatabaseName() string { switch mf.fieldType { case fieldTypeBit: return "BIT" case fieldTypeBLOB: if mf.charSet != binaryCollationID { return "TEXT" } return "BLOB" case fieldTypeDate: return "DATE" case fieldTypeDateTime: return "DATETIME" case fieldTypeDecimal: return "DECIMAL" case fieldTypeDouble: return "DOUBLE" case fieldTypeEnum: return "ENUM" case fieldTypeFloat: return "FLOAT" case fieldTypeGeometry: return "GEOMETRY" case fieldTypeInt24: if mf.flags&flagUnsigned != 0 { return "UNSIGNED MEDIUMINT" } return "MEDIUMINT" case fieldTypeJSON: return "JSON" case fieldTypeLong: if mf.flags&flagUnsigned != 0 { return "UNSIGNED INT" } return "INT" case fieldTypeLongBLOB: if mf.charSet != binaryCollationID { return "LONGTEXT" } return "LONGBLOB" case fieldTypeLongLong: if mf.flags&flagUnsigned != 0 { return "UNSIGNED BIGINT" } return "BIGINT" case fieldTypeMediumBLOB: if mf.charSet != binaryCollationID { return "MEDIUMTEXT" } return "MEDIUMBLOB" case fieldTypeNewDate: return "DATE" case fieldTypeNewDecimal: return "DECIMAL" case fieldTypeNULL: return "NULL" case fieldTypeSet: return "SET" case fieldTypeShort: if mf.flags&flagUnsigned != 0 { return "UNSIGNED SMALLINT" } return "SMALLINT" case fieldTypeString: if mf.flags&flagEnum != 0 { return "ENUM" } else if mf.flags&flagSet != 0 { return "SET" } if mf.charSet == binaryCollationID { return "BINARY" } return "CHAR" case fieldTypeTime: return "TIME" case fieldTypeTimestamp: return "TIMESTAMP" case fieldTypeTiny: if mf.flags&flagUnsigned != 0 { return "UNSIGNED TINYINT" } return "TINYINT" case fieldTypeTinyBLOB: if mf.charSet != binaryCollationID { return "TINYTEXT" } return "TINYBLOB" case fieldTypeVarChar: if mf.charSet == binaryCollationID { return "VARBINARY" } return "VARCHAR" case fieldTypeVarString: if mf.charSet == binaryCollationID { return "VARBINARY" } return "VARCHAR" case fieldTypeYear: return "YEAR" default: return "" } } var ( scanTypeFloat32 = reflect.TypeOf(float32(0)) scanTypeFloat64 = reflect.TypeOf(float64(0)) scanTypeInt8 = reflect.TypeOf(int8(0)) scanTypeInt16 = reflect.TypeOf(int16(0)) scanTypeInt32 = reflect.TypeOf(int32(0)) scanTypeInt64 = reflect.TypeOf(int64(0)) scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) scanTypeNullTime = reflect.TypeOf(sql.NullTime{}) scanTypeUint8 = reflect.TypeOf(uint8(0)) scanTypeUint16 = reflect.TypeOf(uint16(0)) scanTypeUint32 = reflect.TypeOf(uint32(0)) scanTypeUint64 = reflect.TypeOf(uint64(0)) scanTypeString = reflect.TypeOf("") scanTypeNullString = reflect.TypeOf(sql.NullString{}) scanTypeBytes = reflect.TypeOf([]byte{}) scanTypeUnknown = reflect.TypeOf(new(interface{})) ) type mysqlField struct { tableName string name string length uint32 flags fieldFlag fieldType fieldType decimals byte charSet uint8 } func (mf *mysqlField) scanType() reflect.Type { switch mf.fieldType { case fieldTypeTiny: if mf.flags&flagNotNULL != 0 { if mf.flags&flagUnsigned != 0 { return scanTypeUint8 } return scanTypeInt8 } return scanTypeNullInt case fieldTypeShort, fieldTypeYear: if mf.flags&flagNotNULL != 0 { if mf.flags&flagUnsigned != 0 { return scanTypeUint16 } return scanTypeInt16 } return scanTypeNullInt case fieldTypeInt24, fieldTypeLong: if mf.flags&flagNotNULL != 0 { if mf.flags&flagUnsigned != 0 { return scanTypeUint32 } return scanTypeInt32 } return scanTypeNullInt case fieldTypeLongLong: if mf.flags&flagNotNULL != 0 { if mf.flags&flagUnsigned != 0 { return scanTypeUint64 } return scanTypeInt64 } return scanTypeNullInt case fieldTypeFloat: if mf.flags&flagNotNULL != 0 { return scanTypeFloat32 } return scanTypeNullFloat case fieldTypeDouble: if mf.flags&flagNotNULL != 0 { return scanTypeFloat64 } return scanTypeNullFloat case fieldTypeBit, fieldTypeTinyBLOB, fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, fieldTypeVarString, fieldTypeString, fieldTypeGeometry: if mf.charSet == binaryCollationID { return scanTypeBytes } fallthrough case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, fieldTypeEnum, fieldTypeSet, fieldTypeJSON, fieldTypeTime: if mf.flags&flagNotNULL != 0 { return scanTypeString } return scanTypeNullString case fieldTypeDate, fieldTypeNewDate, fieldTypeTimestamp, fieldTypeDateTime: // NullTime is always returned for more consistent behavior as it can // handle both cases of parseTime regardless if the field is nullable. return scanTypeNullTime default: return scanTypeUnknown } } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/infile.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "fmt" "io" "os" "strings" "sync" ) var ( fileRegister map[string]bool fileRegisterLock sync.RWMutex readerRegister map[string]func() io.Reader readerRegisterLock sync.RWMutex ) // RegisterLocalFile adds the given file to the file allowlist, // so that it can be used by "LOAD DATA LOCAL INFILE ". // Alternatively you can allow the use of all local files with // the DSN parameter 'allowAllFiles=true' // // filePath := "/home/gopher/data.csv" // mysql.RegisterLocalFile(filePath) // err := db.Exec("LOAD DATA LOCAL INFILE '" + filePath + "' INTO TABLE foo") // if err != nil { // ... func RegisterLocalFile(filePath string) { fileRegisterLock.Lock() // lazy map init if fileRegister == nil { fileRegister = make(map[string]bool) } fileRegister[strings.Trim(filePath, `"`)] = true fileRegisterLock.Unlock() } // DeregisterLocalFile removes the given filepath from the allowlist. func DeregisterLocalFile(filePath string) { fileRegisterLock.Lock() delete(fileRegister, strings.Trim(filePath, `"`)) fileRegisterLock.Unlock() } // RegisterReaderHandler registers a handler function which is used // to receive a io.Reader. // The Reader can be used by "LOAD DATA LOCAL INFILE Reader::". // If the handler returns a io.ReadCloser Close() is called when the // request is finished. // // mysql.RegisterReaderHandler("data", func() io.Reader { // var csvReader io.Reader // Some Reader that returns CSV data // ... // Open Reader here // return csvReader // }) // err := db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE foo") // if err != nil { // ... func RegisterReaderHandler(name string, handler func() io.Reader) { readerRegisterLock.Lock() // lazy map init if readerRegister == nil { readerRegister = make(map[string]func() io.Reader) } readerRegister[name] = handler readerRegisterLock.Unlock() } // DeregisterReaderHandler removes the ReaderHandler function with // the given name from the registry. func DeregisterReaderHandler(name string) { readerRegisterLock.Lock() delete(readerRegister, name) readerRegisterLock.Unlock() } func deferredClose(err *error, closer io.Closer) { closeErr := closer.Close() if *err == nil { *err = closeErr } } const defaultPacketSize = 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP func (mc *okHandler) handleInFileRequest(name string) (err error) { var rdr io.Reader var data []byte packetSize := defaultPacketSize if mc.maxWriteSize < packetSize { packetSize = mc.maxWriteSize } if idx := strings.Index(name, "Reader::"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader // The server might return an an absolute path. See issue #355. name = name[idx+8:] readerRegisterLock.RLock() handler, inMap := readerRegister[name] readerRegisterLock.RUnlock() if inMap { rdr = handler() if rdr != nil { if cl, ok := rdr.(io.Closer); ok { defer deferredClose(&err, cl) } } else { err = fmt.Errorf("reader '%s' is ", name) } } else { err = fmt.Errorf("reader '%s' is not registered", name) } } else { // File name = strings.Trim(name, `"`) fileRegisterLock.RLock() fr := fileRegister[name] fileRegisterLock.RUnlock() if mc.cfg.AllowAllFiles || fr { var file *os.File var fi os.FileInfo if file, err = os.Open(name); err == nil { defer deferredClose(&err, file) // get file size if fi, err = file.Stat(); err == nil { rdr = file if fileSize := int(fi.Size()); fileSize < packetSize { packetSize = fileSize } } } } else { err = fmt.Errorf("local file '%s' is not registered", name) } } // send content packets // if packetSize == 0, the Reader contains no data if err == nil && packetSize > 0 { data := make([]byte, 4+packetSize) var n int for err == nil { n, err = rdr.Read(data[4:]) if n > 0 { if ioErr := mc.conn().writePacket(data[:4+n]); ioErr != nil { return ioErr } } } if err == io.EOF { err = nil } } // send empty packet (termination) if data == nil { data = make([]byte, 4) } if ioErr := mc.conn().writePacket(data[:4]); ioErr != nil { return ioErr } // read OK packet if err == nil { return mc.readResultOK() } mc.conn().readPacket() return err } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/nulltime.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "database/sql" "database/sql/driver" "fmt" "time" ) // NullTime represents a time.Time that may be NULL. // NullTime implements the Scanner interface so // it can be used as a scan destination: // // var nt NullTime // err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt) // ... // if nt.Valid { // // use nt.Time // } else { // // NULL value // } // // # This NullTime implementation is not driver-specific // // Deprecated: NullTime doesn't honor the loc DSN parameter. // NullTime.Scan interprets a time as UTC, not the loc DSN parameter. // Use sql.NullTime instead. type NullTime sql.NullTime // Scan implements the Scanner interface. // The value type must be time.Time or string / []byte (formatted time-string), // otherwise Scan fails. func (nt *NullTime) Scan(value interface{}) (err error) { if value == nil { nt.Time, nt.Valid = time.Time{}, false return } switch v := value.(type) { case time.Time: nt.Time, nt.Valid = v, true return case []byte: nt.Time, err = parseDateTime(v, time.UTC) nt.Valid = (err == nil) return case string: nt.Time, err = parseDateTime([]byte(v), time.UTC) nt.Valid = (err == nil) return } nt.Valid = false return fmt.Errorf("can't convert %T to time.Time", value) } // Value implements the driver Valuer interface. func (nt NullTime) Value() (driver.Value, error) { if !nt.Valid { return nil, nil } return nt.Time, nil } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/packets.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "bytes" "crypto/tls" "database/sql/driver" "encoding/binary" "encoding/json" "fmt" "io" "math" "strconv" "time" ) // Packets documentation: // http://dev.mysql.com/doc/internals/en/client-server-protocol.html // Read packet to buffer 'data' func (mc *mysqlConn) readPacket() ([]byte, error) { var prevData []byte for { // read packet header data, err := mc.buf.readNext(4) if err != nil { if cerr := mc.canceled.Value(); cerr != nil { return nil, cerr } mc.cfg.Logger.Print(err) mc.Close() return nil, ErrInvalidConn } // packet length [24 bit] pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16) // check packet sync [8 bit] if data[3] != mc.sequence { mc.Close() if data[3] > mc.sequence { return nil, ErrPktSyncMul } return nil, ErrPktSync } mc.sequence++ // packets with length 0 terminate a previous packet which is a // multiple of (2^24)-1 bytes long if pktLen == 0 { // there was no previous packet if prevData == nil { mc.cfg.Logger.Print(ErrMalformPkt) mc.Close() return nil, ErrInvalidConn } return prevData, nil } // read packet body [pktLen bytes] data, err = mc.buf.readNext(pktLen) if err != nil { if cerr := mc.canceled.Value(); cerr != nil { return nil, cerr } mc.cfg.Logger.Print(err) mc.Close() return nil, ErrInvalidConn } // return data if this was the last packet if pktLen < maxPacketSize { // zero allocations for non-split packets if prevData == nil { return data, nil } return append(prevData, data...), nil } prevData = append(prevData, data...) } } // Write packet buffer 'data' func (mc *mysqlConn) writePacket(data []byte) error { pktLen := len(data) - 4 if pktLen > mc.maxAllowedPacket { return ErrPktTooLarge } for { var size int if pktLen >= maxPacketSize { data[0] = 0xff data[1] = 0xff data[2] = 0xff size = maxPacketSize } else { data[0] = byte(pktLen) data[1] = byte(pktLen >> 8) data[2] = byte(pktLen >> 16) size = pktLen } data[3] = mc.sequence // Write packet if mc.writeTimeout > 0 { if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil { return err } } n, err := mc.netConn.Write(data[:4+size]) if err == nil && n == 4+size { mc.sequence++ if size != maxPacketSize { return nil } pktLen -= size data = data[size:] continue } // Handle error if err == nil { // n != len(data) mc.cleanup() mc.cfg.Logger.Print(ErrMalformPkt) } else { if cerr := mc.canceled.Value(); cerr != nil { return cerr } if n == 0 && pktLen == len(data)-4 { // only for the first loop iteration when nothing was written yet return errBadConnNoWrite } mc.cleanup() mc.cfg.Logger.Print(err) } return ErrInvalidConn } } /****************************************************************************** * Initialization Process * ******************************************************************************/ // Handshake Initialization Packet // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err error) { data, err = mc.readPacket() if err != nil { // for init we can rewrite this to ErrBadConn for sql.Driver to retry, since // in connection initialization we don't risk retrying non-idempotent actions. if err == ErrInvalidConn { return nil, "", driver.ErrBadConn } return } if data[0] == iERR { return nil, "", mc.handleErrorPacket(data) } // protocol version [1 byte] if data[0] < minProtocolVersion { return nil, "", fmt.Errorf( "unsupported protocol version %d. Version %d or higher is required", data[0], minProtocolVersion, ) } // server version [null terminated string] // connection id [4 bytes] pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + 4 // first part of the password cipher [8 bytes] authData := data[pos : pos+8] // (filler) always 0x00 [1 byte] pos += 8 + 1 // capability flags (lower 2 bytes) [2 bytes] mc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) if mc.flags&clientProtocol41 == 0 { return nil, "", ErrOldProtocol } if mc.flags&clientSSL == 0 && mc.cfg.TLS != nil { if mc.cfg.AllowFallbackToPlaintext { mc.cfg.TLS = nil } else { return nil, "", ErrNoTLS } } pos += 2 if len(data) > pos { // character set [1 byte] // status flags [2 bytes] // capability flags (upper 2 bytes) [2 bytes] // length of auth-plugin-data [1 byte] // reserved (all [00]) [10 bytes] pos += 1 + 2 + 2 + 1 + 10 // second part of the password cipher [minimum 13 bytes], // where len=MAX(13, length of auth-plugin-data - 8) // // The web documentation is ambiguous about the length. However, // according to mysql-5.7/sql/auth/sql_authentication.cc line 538, // the 13th byte is "\0 byte, terminating the second part of // a scramble". So the second part of the password cipher is // a NULL terminated string that's at least 13 bytes with the // last byte being NULL. // // The official Python library uses the fixed length 12 // which seems to work but technically could have a hidden bug. authData = append(authData, data[pos:pos+12]...) pos += 13 // EOF if version (>= 5.5.7 and < 5.5.10) or (>= 5.6.0 and < 5.6.2) // \NUL otherwise if end := bytes.IndexByte(data[pos:], 0x00); end != -1 { plugin = string(data[pos : pos+end]) } else { plugin = string(data[pos:]) } // make a memory safe copy of the cipher slice var b [20]byte copy(b[:], authData) return b[:], plugin, nil } // make a memory safe copy of the cipher slice var b [8]byte copy(b[:], authData) return b[:], plugin, nil } // Client Authentication Packet // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string) error { // Adjust client flags based on server support clientFlags := clientProtocol41 | clientSecureConn | clientLongPassword | clientTransactions | clientLocalFiles | clientPluginAuth | clientMultiResults | clientConnectAttrs | mc.flags&clientLongFlag if mc.cfg.ClientFoundRows { clientFlags |= clientFoundRows } // To enable TLS / SSL if mc.cfg.TLS != nil { clientFlags |= clientSSL } if mc.cfg.MultiStatements { clientFlags |= clientMultiStatements } // encode length of the auth plugin data var authRespLEIBuf [9]byte authRespLen := len(authResp) authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(authRespLen)) if len(authRespLEI) > 1 { // if the length can not be written in 1 byte, it must be written as a // length encoded integer clientFlags |= clientPluginAuthLenEncClientData } pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1 // To specify a db name if n := len(mc.cfg.DBName); n > 0 { clientFlags |= clientConnectWithDB pktLen += n + 1 } // encode length of the connection attributes var connAttrsLEIBuf [9]byte connAttrsLen := len(mc.connector.encodedAttributes) connAttrsLEI := appendLengthEncodedInteger(connAttrsLEIBuf[:0], uint64(connAttrsLen)) pktLen += len(connAttrsLEI) + len(mc.connector.encodedAttributes) // Calculate packet length and get buffer with that size data, err := mc.buf.takeBuffer(pktLen + 4) if err != nil { // cannot take the buffer. Something must be wrong with the connection mc.cfg.Logger.Print(err) return errBadConnNoWrite } // ClientFlags [32 bit] data[4] = byte(clientFlags) data[5] = byte(clientFlags >> 8) data[6] = byte(clientFlags >> 16) data[7] = byte(clientFlags >> 24) // MaxPacketSize [32 bit] (none) data[8] = 0x00 data[9] = 0x00 data[10] = 0x00 data[11] = 0x00 // Collation ID [1 byte] cname := mc.cfg.Collation if cname == "" { cname = defaultCollation } var found bool data[12], found = collations[cname] if !found { // Note possibility for false negatives: // could be triggered although the collation is valid if the // collations map does not contain entries the server supports. return fmt.Errorf("unknown collation: %q", cname) } // Filler [23 bytes] (all 0x00) pos := 13 for ; pos < 13+23; pos++ { data[pos] = 0 } // SSL Connection Request Packet // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest if mc.cfg.TLS != nil { // Send TLS / SSL request packet if err := mc.writePacket(data[:(4+4+1+23)+4]); err != nil { return err } // Switch to TLS tlsConn := tls.Client(mc.netConn, mc.cfg.TLS) if err := tlsConn.Handshake(); err != nil { return err } mc.rawConn = mc.netConn mc.netConn = tlsConn mc.buf.nc = tlsConn } // User [null terminated string] if len(mc.cfg.User) > 0 { pos += copy(data[pos:], mc.cfg.User) } data[pos] = 0x00 pos++ // Auth Data [length encoded integer] pos += copy(data[pos:], authRespLEI) pos += copy(data[pos:], authResp) // Databasename [null terminated string] if len(mc.cfg.DBName) > 0 { pos += copy(data[pos:], mc.cfg.DBName) data[pos] = 0x00 pos++ } pos += copy(data[pos:], plugin) data[pos] = 0x00 pos++ // Connection Attributes pos += copy(data[pos:], connAttrsLEI) pos += copy(data[pos:], []byte(mc.connector.encodedAttributes)) // Send Auth packet return mc.writePacket(data[:pos]) } // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error { pktLen := 4 + len(authData) data, err := mc.buf.takeSmallBuffer(pktLen) if err != nil { // cannot take the buffer. Something must be wrong with the connection mc.cfg.Logger.Print(err) return errBadConnNoWrite } // Add the auth data [EOF] copy(data[4:], authData) return mc.writePacket(data) } /****************************************************************************** * Command Packets * ******************************************************************************/ func (mc *mysqlConn) writeCommandPacket(command byte) error { // Reset Packet Sequence mc.sequence = 0 data, err := mc.buf.takeSmallBuffer(4 + 1) if err != nil { // cannot take the buffer. Something must be wrong with the connection mc.cfg.Logger.Print(err) return errBadConnNoWrite } // Add command byte data[4] = command // Send CMD packet return mc.writePacket(data) } func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error { // Reset Packet Sequence mc.sequence = 0 pktLen := 1 + len(arg) data, err := mc.buf.takeBuffer(pktLen + 4) if err != nil { // cannot take the buffer. Something must be wrong with the connection mc.cfg.Logger.Print(err) return errBadConnNoWrite } // Add command byte data[4] = command // Add arg copy(data[5:], arg) // Send CMD packet return mc.writePacket(data) } func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error { // Reset Packet Sequence mc.sequence = 0 data, err := mc.buf.takeSmallBuffer(4 + 1 + 4) if err != nil { // cannot take the buffer. Something must be wrong with the connection mc.cfg.Logger.Print(err) return errBadConnNoWrite } // Add command byte data[4] = command // Add arg [32 bit] data[5] = byte(arg) data[6] = byte(arg >> 8) data[7] = byte(arg >> 16) data[8] = byte(arg >> 24) // Send CMD packet return mc.writePacket(data) } /****************************************************************************** * Result Packets * ******************************************************************************/ func (mc *mysqlConn) readAuthResult() ([]byte, string, error) { data, err := mc.readPacket() if err != nil { return nil, "", err } // packet indicator switch data[0] { case iOK: // resultUnchanged, since auth happens before any queries or // commands have been executed. return nil, "", mc.resultUnchanged().handleOkPacket(data) case iAuthMoreData: return data[1:], "", err case iEOF: if len(data) == 1 { // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest return nil, "mysql_old_password", nil } pluginEndIndex := bytes.IndexByte(data, 0x00) if pluginEndIndex < 0 { return nil, "", ErrMalformPkt } plugin := string(data[1:pluginEndIndex]) authData := data[pluginEndIndex+1:] return authData, plugin, nil default: // Error otherwise return nil, "", mc.handleErrorPacket(data) } } // Returns error if Packet is not a 'Result OK'-Packet func (mc *okHandler) readResultOK() error { data, err := mc.conn().readPacket() if err != nil { return err } if data[0] == iOK { return mc.handleOkPacket(data) } return mc.conn().handleErrorPacket(data) } // Result Set Header Packet // http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::Resultset func (mc *okHandler) readResultSetHeaderPacket() (int, error) { // handleOkPacket replaces both values; other cases leave the values unchanged. mc.result.affectedRows = append(mc.result.affectedRows, 0) mc.result.insertIds = append(mc.result.insertIds, 0) data, err := mc.conn().readPacket() if err == nil { switch data[0] { case iOK: return 0, mc.handleOkPacket(data) case iERR: return 0, mc.conn().handleErrorPacket(data) case iLocalInFile: return 0, mc.handleInFileRequest(string(data[1:])) } // column count num, _, _ := readLengthEncodedInteger(data) // ignore remaining data in the packet. see #1478. return int(num), nil } return 0, err } // Error Packet // http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-ERR_Packet func (mc *mysqlConn) handleErrorPacket(data []byte) error { if data[0] != iERR { return ErrMalformPkt } // 0xff [1 byte] // Error Number [16 bit uint] errno := binary.LittleEndian.Uint16(data[1:3]) // 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION // 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover) if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly { // Oops; we are connected to a read-only connection, and won't be able // to issue any write statements. Since RejectReadOnly is configured, // we throw away this connection hoping this one would have write // permission. This is specifically for a possible race condition // during failover (e.g. on AWS Aurora). See README.md for more. // // We explicitly close the connection before returning // driver.ErrBadConn to ensure that `database/sql` purges this // connection and initiates a new one for next statement next time. mc.Close() return driver.ErrBadConn } me := &MySQLError{Number: errno} pos := 3 // SQL State [optional: # + 5bytes string] if data[3] == 0x23 { copy(me.SQLState[:], data[4:4+5]) pos = 9 } // Error Message [string] me.Message = string(data[pos:]) return me } func readStatus(b []byte) statusFlag { return statusFlag(b[0]) | statusFlag(b[1])<<8 } // Returns an instance of okHandler for codepaths where mysqlConn.result doesn't // need to be cleared first (e.g. during authentication, or while additional // resultsets are being fetched.) func (mc *mysqlConn) resultUnchanged() *okHandler { return (*okHandler)(mc) } // okHandler represents the state of the connection when mysqlConn.result has // been prepared for processing of OK packets. // // To correctly populate mysqlConn.result (updated by handleOkPacket()), all // callpaths must either: // // 1. first clear it using clearResult(), or // 2. confirm that they don't need to (by calling resultUnchanged()). // // Both return an instance of type *okHandler. type okHandler mysqlConn // Exposes the underlying type's methods. func (mc *okHandler) conn() *mysqlConn { return (*mysqlConn)(mc) } // clearResult clears the connection's stored affectedRows and insertIds // fields. // // It returns a handler that can process OK responses. func (mc *mysqlConn) clearResult() *okHandler { mc.result = mysqlResult{} return (*okHandler)(mc) } // Ok Packet // http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet func (mc *okHandler) handleOkPacket(data []byte) error { var n, m int var affectedRows, insertId uint64 // 0x00 [1 byte] // Affected rows [Length Coded Binary] affectedRows, _, n = readLengthEncodedInteger(data[1:]) // Insert id [Length Coded Binary] insertId, _, m = readLengthEncodedInteger(data[1+n:]) // Update for the current statement result (only used by // readResultSetHeaderPacket). if len(mc.result.affectedRows) > 0 { mc.result.affectedRows[len(mc.result.affectedRows)-1] = int64(affectedRows) } if len(mc.result.insertIds) > 0 { mc.result.insertIds[len(mc.result.insertIds)-1] = int64(insertId) } // server_status [2 bytes] mc.status = readStatus(data[1+n+m : 1+n+m+2]) if mc.status&statusMoreResultsExists != 0 { return nil } // warning count [2 bytes] return nil } // Read Packets as Field Packets until EOF-Packet or an Error appears // http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition41 func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { columns := make([]mysqlField, count) for i := 0; ; i++ { data, err := mc.readPacket() if err != nil { return nil, err } // EOF Packet if data[0] == iEOF && (len(data) == 5 || len(data) == 1) { if i == count { return columns, nil } return nil, fmt.Errorf("column count mismatch n:%d len:%d", count, len(columns)) } // Catalog pos, err := skipLengthEncodedString(data) if err != nil { return nil, err } // Database [len coded string] n, err := skipLengthEncodedString(data[pos:]) if err != nil { return nil, err } pos += n // Table [len coded string] if mc.cfg.ColumnsWithAlias { tableName, _, n, err := readLengthEncodedString(data[pos:]) if err != nil { return nil, err } pos += n columns[i].tableName = string(tableName) } else { n, err = skipLengthEncodedString(data[pos:]) if err != nil { return nil, err } pos += n } // Original table [len coded string] n, err = skipLengthEncodedString(data[pos:]) if err != nil { return nil, err } pos += n // Name [len coded string] name, _, n, err := readLengthEncodedString(data[pos:]) if err != nil { return nil, err } columns[i].name = string(name) pos += n // Original name [len coded string] n, err = skipLengthEncodedString(data[pos:]) if err != nil { return nil, err } pos += n // Filler [uint8] pos++ // Charset [charset, collation uint8] columns[i].charSet = data[pos] pos += 2 // Length [uint32] columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4]) pos += 4 // Field type [uint8] columns[i].fieldType = fieldType(data[pos]) pos++ // Flags [uint16] columns[i].flags = fieldFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) pos += 2 // Decimals [uint8] columns[i].decimals = data[pos] //pos++ // Default value [len coded binary] //if pos < len(data) { // defaultVal, _, err = bytesToLengthCodedBinary(data[pos:]) //} } } // Read Packets as Field Packets until EOF-Packet or an Error appears // http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::ResultsetRow func (rows *textRows) readRow(dest []driver.Value) error { mc := rows.mc if rows.rs.done { return io.EOF } data, err := mc.readPacket() if err != nil { return err } // EOF Packet if data[0] == iEOF && len(data) == 5 { // server_status [2 bytes] rows.mc.status = readStatus(data[3:]) rows.rs.done = true if !rows.HasNextResultSet() { rows.mc = nil } return io.EOF } if data[0] == iERR { rows.mc = nil return mc.handleErrorPacket(data) } // RowSet Packet var ( n int isNull bool pos int = 0 ) for i := range dest { // Read bytes and convert to string var buf []byte buf, isNull, n, err = readLengthEncodedString(data[pos:]) pos += n if err != nil { return err } if isNull { dest[i] = nil continue } switch rows.rs.columns[i].fieldType { case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeDate, fieldTypeNewDate: if mc.parseTime { dest[i], err = parseDateTime(buf, mc.cfg.Loc) } else { dest[i] = buf } case fieldTypeTiny, fieldTypeShort, fieldTypeInt24, fieldTypeYear, fieldTypeLong: dest[i], err = strconv.ParseInt(string(buf), 10, 64) case fieldTypeLongLong: if rows.rs.columns[i].flags&flagUnsigned != 0 { dest[i], err = strconv.ParseUint(string(buf), 10, 64) } else { dest[i], err = strconv.ParseInt(string(buf), 10, 64) } case fieldTypeFloat: var d float64 d, err = strconv.ParseFloat(string(buf), 32) dest[i] = float32(d) case fieldTypeDouble: dest[i], err = strconv.ParseFloat(string(buf), 64) default: dest[i] = buf } if err != nil { return err } } return nil } // Reads Packets until EOF-Packet or an Error appears. Returns count of Packets read func (mc *mysqlConn) readUntilEOF() error { for { data, err := mc.readPacket() if err != nil { return err } switch data[0] { case iERR: return mc.handleErrorPacket(data) case iEOF: if len(data) == 5 { mc.status = readStatus(data[3:]) } return nil } } } /****************************************************************************** * Prepared Statements * ******************************************************************************/ // Prepare Result Packets // http://dev.mysql.com/doc/internals/en/com-stmt-prepare-response.html func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) { data, err := stmt.mc.readPacket() if err == nil { // packet indicator [1 byte] if data[0] != iOK { return 0, stmt.mc.handleErrorPacket(data) } // statement id [4 bytes] stmt.id = binary.LittleEndian.Uint32(data[1:5]) // Column count [16 bit uint] columnCount := binary.LittleEndian.Uint16(data[5:7]) // Param count [16 bit uint] stmt.paramCount = int(binary.LittleEndian.Uint16(data[7:9])) // Reserved [8 bit] // Warning count [16 bit uint] return columnCount, nil } return 0, err } // http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error { maxLen := stmt.mc.maxAllowedPacket - 1 pktLen := maxLen // After the header (bytes 0-3) follows before the data: // 1 byte command // 4 bytes stmtID // 2 bytes paramID const dataOffset = 1 + 4 + 2 // Cannot use the write buffer since // a) the buffer is too small // b) it is in use data := make([]byte, 4+1+4+2+len(arg)) copy(data[4+dataOffset:], arg) for argLen := len(arg); argLen > 0; argLen -= pktLen - dataOffset { if dataOffset+argLen < maxLen { pktLen = dataOffset + argLen } stmt.mc.sequence = 0 // Add command byte [1 byte] data[4] = comStmtSendLongData // Add stmtID [32 bit] data[5] = byte(stmt.id) data[6] = byte(stmt.id >> 8) data[7] = byte(stmt.id >> 16) data[8] = byte(stmt.id >> 24) // Add paramID [16 bit] data[9] = byte(paramID) data[10] = byte(paramID >> 8) // Send CMD packet err := stmt.mc.writePacket(data[:4+pktLen]) if err == nil { data = data[pktLen-dataOffset:] continue } return err } // Reset Packet Sequence stmt.mc.sequence = 0 return nil } // Execute Prepared Statement // http://dev.mysql.com/doc/internals/en/com-stmt-execute.html func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { if len(args) != stmt.paramCount { return fmt.Errorf( "argument count mismatch (got: %d; has: %d)", len(args), stmt.paramCount, ) } const minPktLen = 4 + 1 + 4 + 1 + 4 mc := stmt.mc // Determine threshold dynamically to avoid packet size shortage. longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) if longDataSize < 64 { longDataSize = 64 } // Reset packet-sequence mc.sequence = 0 var data []byte var err error if len(args) == 0 { data, err = mc.buf.takeBuffer(minPktLen) } else { data, err = mc.buf.takeCompleteBuffer() // In this case the len(data) == cap(data) which is used to optimise the flow below. } if err != nil { // cannot take the buffer. Something must be wrong with the connection mc.cfg.Logger.Print(err) return errBadConnNoWrite } // command [1 byte] data[4] = comStmtExecute // statement_id [4 bytes] data[5] = byte(stmt.id) data[6] = byte(stmt.id >> 8) data[7] = byte(stmt.id >> 16) data[8] = byte(stmt.id >> 24) // flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte] data[9] = 0x00 // iteration_count (uint32(1)) [4 bytes] data[10] = 0x01 data[11] = 0x00 data[12] = 0x00 data[13] = 0x00 if len(args) > 0 { pos := minPktLen var nullMask []byte if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= cap(data) { // buffer has to be extended but we don't know by how much so // we depend on append after all data with known sizes fit. // We stop at that because we deal with a lot of columns here // which makes the required allocation size hard to guess. tmp := make([]byte, pos+maskLen+typesLen) copy(tmp[:pos], data[:pos]) data = tmp nullMask = data[pos : pos+maskLen] // No need to clean nullMask as make ensures that. pos += maskLen } else { nullMask = data[pos : pos+maskLen] for i := range nullMask { nullMask[i] = 0 } pos += maskLen } // newParameterBoundFlag 1 [1 byte] data[pos] = 0x01 pos++ // type of each parameter [len(args)*2 bytes] paramTypes := data[pos:] pos += len(args) * 2 // value of each parameter [n bytes] paramValues := data[pos:pos] valuesCap := cap(paramValues) for i, arg := range args { // build NULL-bitmap if arg == nil { nullMask[i/8] |= 1 << (uint(i) & 7) paramTypes[i+i] = byte(fieldTypeNULL) paramTypes[i+i+1] = 0x00 continue } if v, ok := arg.(json.RawMessage); ok { arg = []byte(v) } // cache types and values switch v := arg.(type) { case int64: paramTypes[i+i] = byte(fieldTypeLongLong) paramTypes[i+i+1] = 0x00 if cap(paramValues)-len(paramValues)-8 >= 0 { paramValues = paramValues[:len(paramValues)+8] binary.LittleEndian.PutUint64( paramValues[len(paramValues)-8:], uint64(v), ) } else { paramValues = append(paramValues, uint64ToBytes(uint64(v))..., ) } case uint64: paramTypes[i+i] = byte(fieldTypeLongLong) paramTypes[i+i+1] = 0x80 // type is unsigned if cap(paramValues)-len(paramValues)-8 >= 0 { paramValues = paramValues[:len(paramValues)+8] binary.LittleEndian.PutUint64( paramValues[len(paramValues)-8:], uint64(v), ) } else { paramValues = append(paramValues, uint64ToBytes(uint64(v))..., ) } case float64: paramTypes[i+i] = byte(fieldTypeDouble) paramTypes[i+i+1] = 0x00 if cap(paramValues)-len(paramValues)-8 >= 0 { paramValues = paramValues[:len(paramValues)+8] binary.LittleEndian.PutUint64( paramValues[len(paramValues)-8:], math.Float64bits(v), ) } else { paramValues = append(paramValues, uint64ToBytes(math.Float64bits(v))..., ) } case bool: paramTypes[i+i] = byte(fieldTypeTiny) paramTypes[i+i+1] = 0x00 if v { paramValues = append(paramValues, 0x01) } else { paramValues = append(paramValues, 0x00) } case []byte: // Common case (non-nil value) first if v != nil { paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 if len(v) < longDataSize { paramValues = appendLengthEncodedInteger(paramValues, uint64(len(v)), ) paramValues = append(paramValues, v...) } else { if err := stmt.writeCommandLongData(i, v); err != nil { return err } } continue } // Handle []byte(nil) as a NULL value nullMask[i/8] |= 1 << (uint(i) & 7) paramTypes[i+i] = byte(fieldTypeNULL) paramTypes[i+i+1] = 0x00 case string: paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 if len(v) < longDataSize { paramValues = appendLengthEncodedInteger(paramValues, uint64(len(v)), ) paramValues = append(paramValues, v...) } else { if err := stmt.writeCommandLongData(i, []byte(v)); err != nil { return err } } case time.Time: paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 var a [64]byte var b = a[:0] if v.IsZero() { b = append(b, "0000-00-00"...) } else { b, err = appendDateTime(b, v.In(mc.cfg.Loc), mc.cfg.timeTruncate) if err != nil { return err } } paramValues = appendLengthEncodedInteger(paramValues, uint64(len(b)), ) paramValues = append(paramValues, b...) default: return fmt.Errorf("cannot convert type: %T", arg) } } // Check if param values exceeded the available buffer // In that case we must build the data packet with the new values buffer if valuesCap != cap(paramValues) { data = append(data[:pos], paramValues...) if err = mc.buf.store(data); err != nil { mc.cfg.Logger.Print(err) return errBadConnNoWrite } } pos += len(paramValues) data = data[:pos] } return mc.writePacket(data) } // For each remaining resultset in the stream, discards its rows and updates // mc.affectedRows and mc.insertIds. func (mc *okHandler) discardResults() error { for mc.status&statusMoreResultsExists != 0 { resLen, err := mc.readResultSetHeaderPacket() if err != nil { return err } if resLen > 0 { // columns if err := mc.conn().readUntilEOF(); err != nil { return err } // rows if err := mc.conn().readUntilEOF(); err != nil { return err } } } return nil } // http://dev.mysql.com/doc/internals/en/binary-protocol-resultset-row.html func (rows *binaryRows) readRow(dest []driver.Value) error { data, err := rows.mc.readPacket() if err != nil { return err } // packet indicator [1 byte] if data[0] != iOK { // EOF Packet if data[0] == iEOF && len(data) == 5 { rows.mc.status = readStatus(data[3:]) rows.rs.done = true if !rows.HasNextResultSet() { rows.mc = nil } return io.EOF } mc := rows.mc rows.mc = nil // Error otherwise return mc.handleErrorPacket(data) } // NULL-bitmap, [(column-count + 7 + 2) / 8 bytes] pos := 1 + (len(dest)+7+2)>>3 nullMask := data[1:pos] for i := range dest { // Field is NULL // (byte >> bit-pos) % 2 == 1 if ((nullMask[(i+2)>>3] >> uint((i+2)&7)) & 1) == 1 { dest[i] = nil continue } // Convert to byte-coded string switch rows.rs.columns[i].fieldType { case fieldTypeNULL: dest[i] = nil continue // Numeric Types case fieldTypeTiny: if rows.rs.columns[i].flags&flagUnsigned != 0 { dest[i] = int64(data[pos]) } else { dest[i] = int64(int8(data[pos])) } pos++ continue case fieldTypeShort, fieldTypeYear: if rows.rs.columns[i].flags&flagUnsigned != 0 { dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2])) } else { dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2]))) } pos += 2 continue case fieldTypeInt24, fieldTypeLong: if rows.rs.columns[i].flags&flagUnsigned != 0 { dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4])) } else { dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4]))) } pos += 4 continue case fieldTypeLongLong: if rows.rs.columns[i].flags&flagUnsigned != 0 { val := binary.LittleEndian.Uint64(data[pos : pos+8]) if val > math.MaxInt64 { dest[i] = uint64ToString(val) } else { dest[i] = int64(val) } } else { dest[i] = int64(binary.LittleEndian.Uint64(data[pos : pos+8])) } pos += 8 continue case fieldTypeFloat: dest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4])) pos += 4 continue case fieldTypeDouble: dest[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[pos : pos+8])) pos += 8 continue // Length coded Binary Strings case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON: var isNull bool var n int dest[i], isNull, n, err = readLengthEncodedString(data[pos:]) pos += n if err == nil { if !isNull { continue } else { dest[i] = nil continue } } return err case fieldTypeDate, fieldTypeNewDate, // Date YYYY-MM-DD fieldTypeTime, // Time [-][H]HH:MM:SS[.fractal] fieldTypeTimestamp, fieldTypeDateTime: // Timestamp YYYY-MM-DD HH:MM:SS[.fractal] num, isNull, n := readLengthEncodedInteger(data[pos:]) pos += n switch { case isNull: dest[i] = nil continue case rows.rs.columns[i].fieldType == fieldTypeTime: // database/sql does not support an equivalent to TIME, return a string var dstlen uint8 switch decimals := rows.rs.columns[i].decimals; decimals { case 0x00, 0x1f: dstlen = 8 case 1, 2, 3, 4, 5, 6: dstlen = 8 + 1 + decimals default: return fmt.Errorf( "protocol error, illegal decimals value %d", rows.rs.columns[i].decimals, ) } dest[i], err = formatBinaryTime(data[pos:pos+int(num)], dstlen) case rows.mc.parseTime: dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc) default: var dstlen uint8 if rows.rs.columns[i].fieldType == fieldTypeDate { dstlen = 10 } else { switch decimals := rows.rs.columns[i].decimals; decimals { case 0x00, 0x1f: dstlen = 19 case 1, 2, 3, 4, 5, 6: dstlen = 19 + 1 + decimals default: return fmt.Errorf( "protocol error, illegal decimals value %d", rows.rs.columns[i].decimals, ) } } dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen) } if err == nil { pos += int(num) continue } else { return err } // Please report if this happens! default: return fmt.Errorf("unknown field type %d", rows.rs.columns[i].fieldType) } } return nil } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/result.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import "database/sql/driver" // Result exposes data not available through *connection.Result. // // This is accessible by executing statements using sql.Conn.Raw() and // downcasting the returned result: // // res, err := rawConn.Exec(...) // res.(mysql.Result).AllRowsAffected() type Result interface { driver.Result // AllRowsAffected returns a slice containing the affected rows for each // executed statement. AllRowsAffected() []int64 // AllLastInsertIds returns a slice containing the last inserted ID for each // executed statement. AllLastInsertIds() []int64 } type mysqlResult struct { // One entry in both slices is created for every executed statement result. affectedRows []int64 insertIds []int64 } func (res *mysqlResult) LastInsertId() (int64, error) { return res.insertIds[len(res.insertIds)-1], nil } func (res *mysqlResult) RowsAffected() (int64, error) { return res.affectedRows[len(res.affectedRows)-1], nil } func (res *mysqlResult) AllLastInsertIds() []int64 { return append([]int64{}, res.insertIds...) // defensive copy } func (res *mysqlResult) AllRowsAffected() []int64 { return append([]int64{}, res.affectedRows...) // defensive copy } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/rows.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "database/sql/driver" "io" "math" "reflect" ) type resultSet struct { columns []mysqlField columnNames []string done bool } type mysqlRows struct { mc *mysqlConn rs resultSet finish func() } type binaryRows struct { mysqlRows } type textRows struct { mysqlRows } func (rows *mysqlRows) Columns() []string { if rows.rs.columnNames != nil { return rows.rs.columnNames } columns := make([]string, len(rows.rs.columns)) if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias { for i := range columns { if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 { columns[i] = tableName + "." + rows.rs.columns[i].name } else { columns[i] = rows.rs.columns[i].name } } } else { for i := range columns { columns[i] = rows.rs.columns[i].name } } rows.rs.columnNames = columns return columns } func (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string { return rows.rs.columns[i].typeDatabaseName() } // func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) { // return int64(rows.rs.columns[i].length), true // } func (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) { return rows.rs.columns[i].flags&flagNotNULL == 0, true } func (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) { column := rows.rs.columns[i] decimals := int64(column.decimals) switch column.fieldType { case fieldTypeDecimal, fieldTypeNewDecimal: if decimals > 0 { return int64(column.length) - 2, decimals, true } return int64(column.length) - 1, decimals, true case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime: return decimals, decimals, true case fieldTypeFloat, fieldTypeDouble: if decimals == 0x1f { return math.MaxInt64, math.MaxInt64, true } return math.MaxInt64, decimals, true } return 0, 0, false } func (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type { return rows.rs.columns[i].scanType() } func (rows *mysqlRows) Close() (err error) { if f := rows.finish; f != nil { f() rows.finish = nil } mc := rows.mc if mc == nil { return nil } if err := mc.error(); err != nil { return err } // flip the buffer for this connection if we need to drain it. // note that for a successful query (i.e. one where rows.next() // has been called until it returns false), `rows.mc` will be nil // by the time the user calls `(*Rows).Close`, so we won't reach this // see: https://github.com/golang/go/commit/651ddbdb5056ded455f47f9c494c67b389622a47 mc.buf.flip() // Remove unread packets from stream if !rows.rs.done { err = mc.readUntilEOF() } if err == nil { handleOk := mc.clearResult() if err = handleOk.discardResults(); err != nil { return err } } rows.mc = nil return err } func (rows *mysqlRows) HasNextResultSet() (b bool) { if rows.mc == nil { return false } return rows.mc.status&statusMoreResultsExists != 0 } func (rows *mysqlRows) nextResultSet() (int, error) { if rows.mc == nil { return 0, io.EOF } if err := rows.mc.error(); err != nil { return 0, err } // Remove unread packets from stream if !rows.rs.done { if err := rows.mc.readUntilEOF(); err != nil { return 0, err } rows.rs.done = true } if !rows.HasNextResultSet() { rows.mc = nil return 0, io.EOF } rows.rs = resultSet{} // rows.mc.affectedRows and rows.mc.insertIds accumulate on each call to // nextResultSet. resLen, err := rows.mc.resultUnchanged().readResultSetHeaderPacket() if err != nil { // Clean up about multi-results flag rows.rs.done = true rows.mc.status = rows.mc.status & (^statusMoreResultsExists) } return resLen, err } func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) { for { resLen, err := rows.nextResultSet() if err != nil { return 0, err } if resLen > 0 { return resLen, nil } rows.rs.done = true } } func (rows *binaryRows) NextResultSet() error { resLen, err := rows.nextNotEmptyResultSet() if err != nil { return err } rows.rs.columns, err = rows.mc.readColumns(resLen) return err } func (rows *binaryRows) Next(dest []driver.Value) error { if mc := rows.mc; mc != nil { if err := mc.error(); err != nil { return err } // Fetch next row from stream return rows.readRow(dest) } return io.EOF } func (rows *textRows) NextResultSet() (err error) { resLen, err := rows.nextNotEmptyResultSet() if err != nil { return err } rows.rs.columns, err = rows.mc.readColumns(resLen) return err } func (rows *textRows) Next(dest []driver.Value) error { if mc := rows.mc; mc != nil { if err := mc.error(); err != nil { return err } // Fetch next row from stream return rows.readRow(dest) } return io.EOF } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/statement.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "database/sql/driver" "encoding/json" "fmt" "io" "reflect" ) type mysqlStmt struct { mc *mysqlConn id uint32 paramCount int } func (stmt *mysqlStmt) Close() error { if stmt.mc == nil || stmt.mc.closed.Load() { // driver.Stmt.Close can be called more than once, thus this function // has to be idempotent. // See also Issue #450 and golang/go#16019. //errLog.Print(ErrInvalidConn) return driver.ErrBadConn } err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id) stmt.mc = nil return err } func (stmt *mysqlStmt) NumInput() int { return stmt.paramCount } func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter { return converter{} } func (stmt *mysqlStmt) CheckNamedValue(nv *driver.NamedValue) (err error) { nv.Value, err = converter{}.ConvertValue(nv.Value) return } func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { if stmt.mc.closed.Load() { stmt.mc.cfg.Logger.Print(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command err := stmt.writeExecutePacket(args) if err != nil { return nil, stmt.mc.markBadConn(err) } mc := stmt.mc handleOk := stmt.mc.clearResult() // Read Result resLen, err := handleOk.readResultSetHeaderPacket() if err != nil { return nil, err } if resLen > 0 { // Columns if err = mc.readUntilEOF(); err != nil { return nil, err } // Rows if err := mc.readUntilEOF(); err != nil { return nil, err } } if err := handleOk.discardResults(); err != nil { return nil, err } copied := mc.result return &copied, nil } func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { return stmt.query(args) } func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { if stmt.mc.closed.Load() { stmt.mc.cfg.Logger.Print(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command err := stmt.writeExecutePacket(args) if err != nil { return nil, stmt.mc.markBadConn(err) } mc := stmt.mc // Read Result handleOk := stmt.mc.clearResult() resLen, err := handleOk.readResultSetHeaderPacket() if err != nil { return nil, err } rows := new(binaryRows) if resLen > 0 { rows.mc = mc rows.rs.columns, err = mc.readColumns(resLen) } else { rows.rs.done = true switch err := rows.NextResultSet(); err { case nil, io.EOF: return rows, nil default: return nil, err } } return rows, err } var jsonType = reflect.TypeOf(json.RawMessage{}) type converter struct{} // ConvertValue mirrors the reference/default converter in database/sql/driver // with _one_ exception. We support uint64 with their high bit and the default // implementation does not. This function should be kept in sync with // database/sql/driver defaultConverter.ConvertValue() except for that // deliberate difference. func (c converter) ConvertValue(v interface{}) (driver.Value, error) { if driver.IsValue(v) { return v, nil } if vr, ok := v.(driver.Valuer); ok { sv, err := callValuerValue(vr) if err != nil { return nil, err } if driver.IsValue(sv) { return sv, nil } // A value returned from the Valuer interface can be "a type handled by // a database driver's NamedValueChecker interface" so we should accept // uint64 here as well. if u, ok := sv.(uint64); ok { return u, nil } return nil, fmt.Errorf("non-Value type %T returned from Value", sv) } rv := reflect.ValueOf(v) switch rv.Kind() { case reflect.Ptr: // indirect pointers if rv.IsNil() { return nil, nil } else { return c.ConvertValue(rv.Elem().Interface()) } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return rv.Int(), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return rv.Uint(), nil case reflect.Float32, reflect.Float64: return rv.Float(), nil case reflect.Bool: return rv.Bool(), nil case reflect.Slice: switch t := rv.Type(); { case t == jsonType: return v, nil case t.Elem().Kind() == reflect.Uint8: return rv.Bytes(), nil default: return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, t.Elem().Kind()) } case reflect.String: return rv.String(), nil } return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) } var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() // callValuerValue returns vr.Value(), with one exception: // If vr.Value is an auto-generated method on a pointer type and the // pointer is nil, it would panic at runtime in the panicwrap // method. Treat it like nil instead. // // This is so people can implement driver.Value on value types and // still use nil pointers to those types to mean nil/NULL, just like // string/*string. // // This is an exact copy of the same-named unexported function from the // database/sql package. func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr && rv.IsNil() && rv.Type().Elem().Implements(valuerReflectType) { return nil, nil } return vr.Value() } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/transaction.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql type mysqlTx struct { mc *mysqlConn } func (tx *mysqlTx) Commit() (err error) { if tx.mc == nil || tx.mc.closed.Load() { return ErrInvalidConn } err = tx.mc.exec("COMMIT") tx.mc = nil return } func (tx *mysqlTx) Rollback() (err error) { if tx.mc == nil || tx.mc.closed.Load() { return ErrInvalidConn } err = tx.mc.exec("ROLLBACK") tx.mc = nil return } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/utils.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. package mysql import ( "crypto/tls" "database/sql" "database/sql/driver" "encoding/binary" "errors" "fmt" "io" "strconv" "strings" "sync" "sync/atomic" "time" ) // Registry for custom tls.Configs var ( tlsConfigLock sync.RWMutex tlsConfigRegistry map[string]*tls.Config ) // RegisterTLSConfig registers a custom tls.Config to be used with sql.Open. // Use the key as a value in the DSN where tls=value. // // Note: The provided tls.Config is exclusively owned by the driver after // registering it. // // rootCertPool := x509.NewCertPool() // pem, err := os.ReadFile("/path/ca-cert.pem") // if err != nil { // log.Fatal(err) // } // if ok := rootCertPool.AppendCertsFromPEM(pem); !ok { // log.Fatal("Failed to append PEM.") // } // clientCert := make([]tls.Certificate, 0, 1) // certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem") // if err != nil { // log.Fatal(err) // } // clientCert = append(clientCert, certs) // mysql.RegisterTLSConfig("custom", &tls.Config{ // RootCAs: rootCertPool, // Certificates: clientCert, // }) // db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom") func RegisterTLSConfig(key string, config *tls.Config) error { if _, isBool := readBool(key); isBool || strings.ToLower(key) == "skip-verify" || strings.ToLower(key) == "preferred" { return fmt.Errorf("key '%s' is reserved", key) } tlsConfigLock.Lock() if tlsConfigRegistry == nil { tlsConfigRegistry = make(map[string]*tls.Config) } tlsConfigRegistry[key] = config tlsConfigLock.Unlock() return nil } // DeregisterTLSConfig removes the tls.Config associated with key. func DeregisterTLSConfig(key string) { tlsConfigLock.Lock() if tlsConfigRegistry != nil { delete(tlsConfigRegistry, key) } tlsConfigLock.Unlock() } func getTLSConfigClone(key string) (config *tls.Config) { tlsConfigLock.RLock() if v, ok := tlsConfigRegistry[key]; ok { config = v.Clone() } tlsConfigLock.RUnlock() return } // Returns the bool value of the input. // The 2nd return value indicates if the input was a valid bool value func readBool(input string) (value bool, valid bool) { switch input { case "1", "true", "TRUE", "True": return true, true case "0", "false", "FALSE", "False": return false, true } // Not a valid bool value return } /****************************************************************************** * Time related utils * ******************************************************************************/ func parseDateTime(b []byte, loc *time.Location) (time.Time, error) { const base = "0000-00-00 00:00:00.000000" switch len(b) { case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM" if string(b) == base[:len(b)] { return time.Time{}, nil } year, err := parseByteYear(b) if err != nil { return time.Time{}, err } if b[4] != '-' { return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[4]) } m, err := parseByte2Digits(b[5], b[6]) if err != nil { return time.Time{}, err } month := time.Month(m) if b[7] != '-' { return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[7]) } day, err := parseByte2Digits(b[8], b[9]) if err != nil { return time.Time{}, err } if len(b) == 10 { return time.Date(year, month, day, 0, 0, 0, 0, loc), nil } if b[10] != ' ' { return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[10]) } hour, err := parseByte2Digits(b[11], b[12]) if err != nil { return time.Time{}, err } if b[13] != ':' { return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[13]) } min, err := parseByte2Digits(b[14], b[15]) if err != nil { return time.Time{}, err } if b[16] != ':' { return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[16]) } sec, err := parseByte2Digits(b[17], b[18]) if err != nil { return time.Time{}, err } if len(b) == 19 { return time.Date(year, month, day, hour, min, sec, 0, loc), nil } if b[19] != '.' { return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[19]) } nsec, err := parseByteNanoSec(b[20:]) if err != nil { return time.Time{}, err } return time.Date(year, month, day, hour, min, sec, nsec, loc), nil default: return time.Time{}, fmt.Errorf("invalid time bytes: %s", b) } } func parseByteYear(b []byte) (int, error) { year, n := 0, 1000 for i := 0; i < 4; i++ { v, err := bToi(b[i]) if err != nil { return 0, err } year += v * n n /= 10 } return year, nil } func parseByte2Digits(b1, b2 byte) (int, error) { d1, err := bToi(b1) if err != nil { return 0, err } d2, err := bToi(b2) if err != nil { return 0, err } return d1*10 + d2, nil } func parseByteNanoSec(b []byte) (int, error) { ns, digit := 0, 100000 // max is 6-digits for i := 0; i < len(b); i++ { v, err := bToi(b[i]) if err != nil { return 0, err } ns += v * digit digit /= 10 } // nanoseconds has 10-digits. (needs to scale digits) // 10 - 6 = 4, so we have to multiple 1000. return ns * 1000, nil } func bToi(b byte) (int, error) { if b < '0' || b > '9' { return 0, errors.New("not [0-9]") } return int(b - '0'), nil } func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) { switch num { case 0: return time.Time{}, nil case 4: return time.Date( int(binary.LittleEndian.Uint16(data[:2])), // year time.Month(data[2]), // month int(data[3]), // day 0, 0, 0, 0, loc, ), nil case 7: return time.Date( int(binary.LittleEndian.Uint16(data[:2])), // year time.Month(data[2]), // month int(data[3]), // day int(data[4]), // hour int(data[5]), // minutes int(data[6]), // seconds 0, loc, ), nil case 11: return time.Date( int(binary.LittleEndian.Uint16(data[:2])), // year time.Month(data[2]), // month int(data[3]), // day int(data[4]), // hour int(data[5]), // minutes int(data[6]), // seconds int(binary.LittleEndian.Uint32(data[7:11]))*1000, // nanoseconds loc, ), nil } return nil, fmt.Errorf("invalid DATETIME packet length %d", num) } func appendDateTime(buf []byte, t time.Time, timeTruncate time.Duration) ([]byte, error) { if timeTruncate > 0 { t = t.Truncate(timeTruncate) } year, month, day := t.Date() hour, min, sec := t.Clock() nsec := t.Nanosecond() if year < 1 || year > 9999 { return buf, errors.New("year is not in the range [1, 9999]: " + strconv.Itoa(year)) // use errors.New instead of fmt.Errorf to avoid year escape to heap } year100 := year / 100 year1 := year % 100 var localBuf [len("2006-01-02T15:04:05.999999999")]byte // does not escape localBuf[0], localBuf[1], localBuf[2], localBuf[3] = digits10[year100], digits01[year100], digits10[year1], digits01[year1] localBuf[4] = '-' localBuf[5], localBuf[6] = digits10[month], digits01[month] localBuf[7] = '-' localBuf[8], localBuf[9] = digits10[day], digits01[day] if hour == 0 && min == 0 && sec == 0 && nsec == 0 { return append(buf, localBuf[:10]...), nil } localBuf[10] = ' ' localBuf[11], localBuf[12] = digits10[hour], digits01[hour] localBuf[13] = ':' localBuf[14], localBuf[15] = digits10[min], digits01[min] localBuf[16] = ':' localBuf[17], localBuf[18] = digits10[sec], digits01[sec] if nsec == 0 { return append(buf, localBuf[:19]...), nil } nsec100000000 := nsec / 100000000 nsec1000000 := (nsec / 1000000) % 100 nsec10000 := (nsec / 10000) % 100 nsec100 := (nsec / 100) % 100 nsec1 := nsec % 100 localBuf[19] = '.' // milli second localBuf[20], localBuf[21], localBuf[22] = digits01[nsec100000000], digits10[nsec1000000], digits01[nsec1000000] // micro second localBuf[23], localBuf[24], localBuf[25] = digits10[nsec10000], digits01[nsec10000], digits10[nsec100] // nano second localBuf[26], localBuf[27], localBuf[28] = digits01[nsec100], digits10[nsec1], digits01[nsec1] // trim trailing zeros n := len(localBuf) for n > 0 && localBuf[n-1] == '0' { n-- } return append(buf, localBuf[:n]...), nil } // zeroDateTime is used in formatBinaryDateTime to avoid an allocation // if the DATE or DATETIME has the zero value. // It must never be changed. // The current behavior depends on database/sql copying the result. var zeroDateTime = []byte("0000-00-00 00:00:00.000000") const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999" func appendMicrosecs(dst, src []byte, decimals int) []byte { if decimals <= 0 { return dst } if len(src) == 0 { return append(dst, ".000000"[:decimals+1]...) } microsecs := binary.LittleEndian.Uint32(src[:4]) p1 := byte(microsecs / 10000) microsecs -= 10000 * uint32(p1) p2 := byte(microsecs / 100) microsecs -= 100 * uint32(p2) p3 := byte(microsecs) switch decimals { default: return append(dst, '.', digits10[p1], digits01[p1], digits10[p2], digits01[p2], digits10[p3], digits01[p3], ) case 1: return append(dst, '.', digits10[p1], ) case 2: return append(dst, '.', digits10[p1], digits01[p1], ) case 3: return append(dst, '.', digits10[p1], digits01[p1], digits10[p2], ) case 4: return append(dst, '.', digits10[p1], digits01[p1], digits10[p2], digits01[p2], ) case 5: return append(dst, '.', digits10[p1], digits01[p1], digits10[p2], digits01[p2], digits10[p3], ) } } func formatBinaryDateTime(src []byte, length uint8) (driver.Value, error) { // length expects the deterministic length of the zero value, // negative time and 100+ hours are automatically added if needed if len(src) == 0 { return zeroDateTime[:length], nil } var dst []byte // return value var p1, p2, p3 byte // current digit pair switch length { case 10, 19, 21, 22, 23, 24, 25, 26: default: t := "DATE" if length > 10 { t += "TIME" } return nil, fmt.Errorf("illegal %s length %d", t, length) } switch len(src) { case 4, 7, 11: default: t := "DATE" if length > 10 { t += "TIME" } return nil, fmt.Errorf("illegal %s packet length %d", t, len(src)) } dst = make([]byte, 0, length) // start with the date year := binary.LittleEndian.Uint16(src[:2]) pt := year / 100 p1 = byte(year - 100*uint16(pt)) p2, p3 = src[2], src[3] dst = append(dst, digits10[pt], digits01[pt], digits10[p1], digits01[p1], '-', digits10[p2], digits01[p2], '-', digits10[p3], digits01[p3], ) if length == 10 { return dst, nil } if len(src) == 4 { return append(dst, zeroDateTime[10:length]...), nil } dst = append(dst, ' ') p1 = src[4] // hour src = src[5:] // p1 is 2-digit hour, src is after hour p2, p3 = src[0], src[1] dst = append(dst, digits10[p1], digits01[p1], ':', digits10[p2], digits01[p2], ':', digits10[p3], digits01[p3], ) return appendMicrosecs(dst, src[2:], int(length)-20), nil } func formatBinaryTime(src []byte, length uint8) (driver.Value, error) { // length expects the deterministic length of the zero value, // negative time and 100+ hours are automatically added if needed if len(src) == 0 { return zeroDateTime[11 : 11+length], nil } var dst []byte // return value switch length { case 8, // time (can be up to 10 when negative and 100+ hours) 10, 11, 12, 13, 14, 15: // time with fractional seconds default: return nil, fmt.Errorf("illegal TIME length %d", length) } switch len(src) { case 8, 12: default: return nil, fmt.Errorf("invalid TIME packet length %d", len(src)) } // +2 to enable negative time and 100+ hours dst = make([]byte, 0, length+2) if src[0] == 1 { dst = append(dst, '-') } days := binary.LittleEndian.Uint32(src[1:5]) hours := int64(days)*24 + int64(src[5]) if hours >= 100 { dst = strconv.AppendInt(dst, hours, 10) } else { dst = append(dst, digits10[hours], digits01[hours]) } min, sec := src[6], src[7] dst = append(dst, ':', digits10[min], digits01[min], ':', digits10[sec], digits01[sec], ) return appendMicrosecs(dst, src[8:], int(length)-9), nil } /****************************************************************************** * Convert from and to bytes * ******************************************************************************/ func uint64ToBytes(n uint64) []byte { return []byte{ byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24), byte(n >> 32), byte(n >> 40), byte(n >> 48), byte(n >> 56), } } func uint64ToString(n uint64) []byte { var a [20]byte i := 20 // U+0030 = 0 // ... // U+0039 = 9 var q uint64 for n >= 10 { i-- q = n / 10 a[i] = uint8(n-q*10) + 0x30 n = q } i-- a[i] = uint8(n) + 0x30 return a[i:] } // treats string value as unsigned integer representation func stringToInt(b []byte) int { val := 0 for i := range b { val *= 10 val += int(b[i] - 0x30) } return val } // returns the string read as a bytes slice, whether the value is NULL, // the number of bytes read and an error, in case the string is longer than // the input slice func readLengthEncodedString(b []byte) ([]byte, bool, int, error) { // Get length num, isNull, n := readLengthEncodedInteger(b) if num < 1 { return b[n:n], isNull, n, nil } n += int(num) // Check data length if len(b) >= n { return b[n-int(num) : n : n], false, n, nil } return nil, false, n, io.EOF } // returns the number of bytes skipped and an error, in case the string is // longer than the input slice func skipLengthEncodedString(b []byte) (int, error) { // Get length num, _, n := readLengthEncodedInteger(b) if num < 1 { return n, nil } n += int(num) // Check data length if len(b) >= n { return n, nil } return n, io.EOF } // returns the number read, whether the value is NULL and the number of bytes read func readLengthEncodedInteger(b []byte) (uint64, bool, int) { // See issue #349 if len(b) == 0 { return 0, true, 1 } switch b[0] { // 251: NULL case 0xfb: return 0, true, 1 // 252: value of following 2 case 0xfc: return uint64(b[1]) | uint64(b[2])<<8, false, 3 // 253: value of following 3 case 0xfd: return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16, false, 4 // 254: value of following 8 case 0xfe: return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16 | uint64(b[4])<<24 | uint64(b[5])<<32 | uint64(b[6])<<40 | uint64(b[7])<<48 | uint64(b[8])<<56, false, 9 } // 0-250: value of first byte return uint64(b[0]), false, 1 } // encodes a uint64 value and appends it to the given bytes slice func appendLengthEncodedInteger(b []byte, n uint64) []byte { switch { case n <= 250: return append(b, byte(n)) case n <= 0xffff: return append(b, 0xfc, byte(n), byte(n>>8)) case n <= 0xffffff: return append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16)) } return append(b, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24), byte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56)) } func appendLengthEncodedString(b []byte, s string) []byte { b = appendLengthEncodedInteger(b, uint64(len(s))) return append(b, s...) } // reserveBuffer checks cap(buf) and expand buffer to len(buf) + appendSize. // If cap(buf) is not enough, reallocate new buffer. func reserveBuffer(buf []byte, appendSize int) []byte { newSize := len(buf) + appendSize if cap(buf) < newSize { // Grow buffer exponentially newBuf := make([]byte, len(buf)*2+appendSize) copy(newBuf, buf) buf = newBuf } return buf[:newSize] } // escapeBytesBackslash escapes []byte with backslashes (\) // This escapes the contents of a string (provided as []byte) by adding backslashes before special // characters, and turning others into specific escape sequences, such as // turning newlines into \n and null bytes into \0. // https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L823-L932 func escapeBytesBackslash(buf, v []byte) []byte { pos := len(buf) buf = reserveBuffer(buf, len(v)*2) for _, c := range v { switch c { case '\x00': buf[pos+1] = '0' buf[pos] = '\\' pos += 2 case '\n': buf[pos+1] = 'n' buf[pos] = '\\' pos += 2 case '\r': buf[pos+1] = 'r' buf[pos] = '\\' pos += 2 case '\x1a': buf[pos+1] = 'Z' buf[pos] = '\\' pos += 2 case '\'': buf[pos+1] = '\'' buf[pos] = '\\' pos += 2 case '"': buf[pos+1] = '"' buf[pos] = '\\' pos += 2 case '\\': buf[pos+1] = '\\' buf[pos] = '\\' pos += 2 default: buf[pos] = c pos++ } } return buf[:pos] } // escapeStringBackslash is similar to escapeBytesBackslash but for string. func escapeStringBackslash(buf []byte, v string) []byte { pos := len(buf) buf = reserveBuffer(buf, len(v)*2) for i := 0; i < len(v); i++ { c := v[i] switch c { case '\x00': buf[pos+1] = '0' buf[pos] = '\\' pos += 2 case '\n': buf[pos+1] = 'n' buf[pos] = '\\' pos += 2 case '\r': buf[pos+1] = 'r' buf[pos] = '\\' pos += 2 case '\x1a': buf[pos+1] = 'Z' buf[pos] = '\\' pos += 2 case '\'': buf[pos+1] = '\'' buf[pos] = '\\' pos += 2 case '"': buf[pos+1] = '"' buf[pos] = '\\' pos += 2 case '\\': buf[pos+1] = '\\' buf[pos] = '\\' pos += 2 default: buf[pos] = c pos++ } } return buf[:pos] } // escapeBytesQuotes escapes apostrophes in []byte by doubling them up. // This escapes the contents of a string by doubling up any apostrophes that // it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in // effect on the server. // https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L963-L1038 func escapeBytesQuotes(buf, v []byte) []byte { pos := len(buf) buf = reserveBuffer(buf, len(v)*2) for _, c := range v { if c == '\'' { buf[pos+1] = '\'' buf[pos] = '\'' pos += 2 } else { buf[pos] = c pos++ } } return buf[:pos] } // escapeStringQuotes is similar to escapeBytesQuotes but for string. func escapeStringQuotes(buf []byte, v string) []byte { pos := len(buf) buf = reserveBuffer(buf, len(v)*2) for i := 0; i < len(v); i++ { c := v[i] if c == '\'' { buf[pos+1] = '\'' buf[pos] = '\'' pos += 2 } else { buf[pos] = c pos++ } } return buf[:pos] } /****************************************************************************** * Sync utils * ******************************************************************************/ // noCopy may be embedded into structs which must not be copied // after the first use. // // See https://github.com/golang/go/issues/8005#issuecomment-190753527 // for details. type noCopy struct{} // Lock is a no-op used by -copylocks checker from `go vet`. func (*noCopy) Lock() {} // Unlock is a no-op used by -copylocks checker from `go vet`. // noCopy should implement sync.Locker from Go 1.11 // https://github.com/golang/go/commit/c2eba53e7f80df21d51285879d51ab81bcfbf6bc // https://github.com/golang/go/issues/26165 func (*noCopy) Unlock() {} // atomicError is a wrapper for atomically accessed error values type atomicError struct { _ noCopy value atomic.Value } // Set sets the error value regardless of the previous value. // The value must not be nil func (ae *atomicError) Set(value error) { ae.value.Store(value) } // Value returns the current error value func (ae *atomicError) Value() error { if v := ae.value.Load(); v != nil { // this will panic if the value doesn't implement the error interface return v.(error) } return nil } func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) { dargs := make([]driver.Value, len(named)) for n, param := range named { if len(param.Name) > 0 { // TODO: support the use of Named Parameters #561 return nil, errors.New("mysql: driver does not support the use of Named Parameters") } dargs[n] = param.Value } return dargs, nil } func mapIsolationLevel(level driver.IsolationLevel) (string, error) { switch sql.IsolationLevel(level) { case sql.LevelRepeatableRead: return "REPEATABLE READ", nil case sql.LevelReadCommitted: return "READ COMMITTED", nil case sql.LevelReadUncommitted: return "READ UNCOMMITTED", nil case sql.LevelSerializable: return "SERIALIZABLE", nil default: return "", fmt.Errorf("mysql: unsupported isolation level: %v", level) } } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/.gitignore ================================================ *.iml *.swo *.swp *.tfstate *.tfstate.backup *~ /.idea /certcheck /chainfix /coverage.txt /createtree /crlcheck /ctclient /ct_server /ct_hammer /data /dumpscts /findlog /goshawk /gosmin /gossip_server /preloader /scanlog /sctcheck /sctscan /trillian_log_server /trillian_log_signer /trillian.json ================================================ FILE: vendor/github.com/google/certificate-transparency-go/.golangci.yaml ================================================ run: deadline: 90s skip-dirs: - (^|/)x509($|/) - (^|/)x509util($|/) - (^|/)asn1($|/) linters-settings: gocyclo: min-complexity: 25 depguard: list-type: blacklist packages: - ^golang.org/x/net/context$ - github.com/gogo/protobuf/proto - encoding/asn1 - crypto/x509 issues: exclude-use-default: false exclude: - "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked" ================================================ FILE: vendor/github.com/google/certificate-transparency-go/AUTHORS ================================================ # This is the official list of benchmark authors for copyright purposes. # This file is distinct from the CONTRIBUTORS files. # See the latter for an explanation. # # Names should be added to this file as: # Name or Organization # The email address is not required for organizations. # # Please keep the list sorted. Alex Cohn Comodo CA Limited Ed Maste Fiaz Hossain Google LLC Internet Security Research Group Jeff Trawick Katriel Cohn-Gordon Laël Cellier Mark Schloesser NORDUnet A/S Nicholas Galbreath Oliver Weidner PrimeKey Solutions AB Ruslan Kovalov Venafi, Inc. Vladimir Rutsky Ximin Luo ================================================ FILE: vendor/github.com/google/certificate-transparency-go/CHANGELOG.md ================================================ # CERTIFICATE-TRANSPARENCY-GO Changelog ## HEAD ## v1.1.8 * Recommended Go version for development: 1.21 * Using a different version can lead to presubmits failing due to unexpected diffs. ### Add support for AIX * crypto/x509: add AIX operating system by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1277 ### Monitoring * Distribution metric to monitor the start of get-entries requests by @phbnf in https://github.com/google/certificate-transparency-go/pull/1364 ### Fixes * Use the appropriate HTTP response code for backend timeouts by @robstradling in https://github.com/google/certificate-transparency-go/pull/1313 ### Misc * Move golangci-lint from Cloud Build to GitHub Action by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1230 * Set golangci-lint GH action timeout to 5m by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1231 * Added Slack channel details by @mhutchinson in https://github.com/google/certificate-transparency-go/pull/1246 * Improve fuzzing by @AdamKorcz in https://github.com/google/certificate-transparency-go/pull/1345 ### Dependency update * Bump golang from `20f9ab5` to `5ee1296` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1216 * Bump golang from `20f9ab5` to `5ee1296` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1217 * Bump golang from `20f9ab5` to `5ee1296` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1218 * Bump k8s.io/klog/v2 from 2.100.1 to 2.110.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1219 * Bump golang from `20f9ab5` to `5ee1296` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1220 * Bump golang from `5ee1296` to `5bafbbb` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1221 * Bump golang from `5ee1296` to `5bafbbb` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1222 * Bump golang from `5ee1296` to `5bafbbb` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1223 * Bump golang from `5ee1296` to `5bafbbb` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1224 * Update the minimal image to gcr.io/distroless/base-debian12 by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1148 * Bump jq from 1.6 to 1.7 by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1225 * Bump github.com/spf13/cobra from 1.7.0 to 1.8.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1226 * Bump golang.org/x/time from 0.3.0 to 0.4.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1227 * Bump github.com/mattn/go-sqlite3 from 1.14.17 to 1.14.18 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1228 * Bump github.com/gorilla/mux from 1.8.0 to 1.8.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1229 * Bump golang from 1.21.3-bookworm to 1.21.4-bookworm in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1232 * Bump golang from 1.21.3-bookworm to 1.21.4-bookworm in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1233 * Bump golang from 1.21.3-bookworm to 1.21.4-bookworm in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1234 * Bump golang from 1.21.3-bookworm to 1.21.4-bookworm in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1235 * Bump go-version-input from 1.20.10 to 1.20.11 in govulncheck.yml by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1238 * Bump golang.org/x/net from 0.17.0 to 0.18.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1236 * Bump github/codeql-action from 2.22.5 to 2.22.6 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1240 * Bump github/codeql-action from 2.22.6 to 2.22.7 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1241 * Bump golang from `85aacbe` to `dadce81` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1243 * Bump golang from `85aacbe` to `dadce81` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1242 * Bump golang from `85aacbe` to `dadce81` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1244 * Bump golang from `85aacbe` to `dadce81` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1245 * Bump golang from `dadce81` to `52362e2` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1247 * Bump golang from `dadce81` to `52362e2` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1248 * Bump golang from `dadce81` to `52362e2` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1249 * Bump golang from `dadce81` to `52362e2` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1250 * Bump github/codeql-action from 2.22.7 to 2.22.8 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1251 * Bump golang.org/x/net from 0.18.0 to 0.19.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1252 * Bump golang.org/x/time from 0.4.0 to 0.5.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1254 * Bump alpine from `eece025` to `34871e7` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1256 * Bump alpine from `eece025` to `34871e7` in /trillian/examples/deployment/docker/envsubst by @dependabot in https://github.com/google/certificate-transparency-go/pull/1257 * Bump go-version-input from 1.20.11 to 1.20.12 in govulncheck.yml by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1264 * Bump actions/setup-go from 4.1.0 to 5.0.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1261 * Bump golang from 1.21.4-bookworm to 1.21.5-bookworm in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1259 * Bump golang from 1.21.4-bookworm to 1.21.5-bookworm in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1263 * Bump golang from 1.21.4-bookworm to 1.21.5-bookworm in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1262 * Bump golang from 1.21.4-bookworm to 1.21.5-bookworm in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1260 * Bump go.etcd.io/etcd/v3 from 3.5.10 to 3.5.11 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1266 * Bump github/codeql-action from 2.22.8 to 2.22.9 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1269 * Bump alpine from `34871e7` to `51b6726` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1270 * Bump alpine from 3.18 to 3.19 in /trillian/examples/deployment/docker/envsubst by @dependabot in https://github.com/google/certificate-transparency-go/pull/1271 * Bump golang from `a6b787c` to `2d3b13c` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1272 * Bump golang from `a6b787c` to `2d3b13c` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1273 * Bump golang from `a6b787c` to `2d3b13c` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1274 * Bump golang from `a6b787c` to `2d3b13c` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1275 * Bump github/codeql-action from 2.22.9 to 2.22.10 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1278 * Bump google.golang.org/grpc from 1.59.0 to 1.60.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1279 * Bump github/codeql-action from 2.22.10 to 3.22.11 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1280 * Bump distroless/base-debian12 from `1dfdb5e` to `8a0bb63` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1281 * Bump github.com/google/trillian from 1.5.3 to 1.5.4-0.20240110091238-00ca9abe023d by @mhutchinson in https://github.com/google/certificate-transparency-go/pull/1297 * Bump actions/upload-artifact from 3.1.3 to 4.0.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1282 * Bump github/codeql-action from 3.22.11 to 3.23.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1295 * Bump github.com/mattn/go-sqlite3 from 1.14.18 to 1.14.19 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1283 * Bump golang from 1.21.5-bookworm to 1.21.6-bookworm in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1300 * Bump distroless/base-debian12 from `8a0bb63` to `0a93daa` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1284 * Bump golang from 1.21.5-bookworm to 1.21.6-bookworm in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1299 * Bump golang from 1.21.5-bookworm to 1.21.6-bookworm in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1298 * Bump golang from 1.21.5-bookworm to 1.21.6-bookworm in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1301 * Bump golang from `688ad7f` to `1e8ea75` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1306 * Bump golang from `688ad7f` to `1e8ea75` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1305 * Use trillian release instead of pinned commit by @mhutchinson in https://github.com/google/certificate-transparency-go/pull/1304 * Bump actions/upload-artifact from 4.0.0 to 4.1.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1310 * Bump golang from `1e8ea75` to `cbee5d2` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1312 * Bump golang from `688ad7f` to `cbee5d2` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1308 * Bump golang from `1e8ea75` to `cbee5d2` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1311 * Bump golang.org/x/net from 0.19.0 to 0.20.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1302 * Bump golang from `b651ed8` to `cbee5d2` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1309 * Bump golang from `cbee5d2` to `c4b696f` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1314 * Bump golang from `cbee5d2` to `c4b696f` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1315 * Bump github/codeql-action from 3.23.0 to 3.23.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1317 * Bump golang from `cbee5d2` to `c4b696f` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1316 * Bump golang from `cbee5d2` to `c4b696f` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1318 * Bump k8s.io/klog/v2 from 2.120.0 to 2.120.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1319 * Bump actions/upload-artifact from 4.1.0 to 4.2.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1320 * Bump actions/upload-artifact from 4.2.0 to 4.3.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1321 * Bump golang from `c4b696f` to `d8c365d` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1326 * Bump golang from `c4b696f` to `d8c365d` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1323 * Bump google.golang.org/grpc from 1.60.1 to 1.61.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1324 * Bump golang from `c4b696f` to `d8c365d` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1322 * Bump golang from `c4b696f` to `d8c365d` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1325 * Bump github.com/mattn/go-sqlite3 from 1.14.19 to 1.14.20 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1327 * Bump github/codeql-action from 3.23.1 to 3.23.2 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1328 * Bump alpine from `51b6726` to `c5b1261` in /trillian/examples/deployment/docker/envsubst by @dependabot in https://github.com/google/certificate-transparency-go/pull/1330 * Bump alpine from `51b6726` to `c5b1261` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1329 * Bump go.etcd.io/etcd/v3 from 3.5.11 to 3.5.12 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1332 * Bump github.com/mattn/go-sqlite3 from 1.14.20 to 1.14.21 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1333 * Bump golang from `d8c365d` to `69bfed3` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1335 * Bump golang from `d8c365d` to `69bfed3` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1338 * Bump golang from `d8c365d` to `69bfed3` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1337 * Bump golang from `d8c365d` to `69bfed3` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1336 * Bump golang from `69bfed3` to `3efef61` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1339 * Bump github.com/mattn/go-sqlite3 from 1.14.21 to 1.14.22 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1344 * Bump golang from `69bfed3` to `3efef61` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1341 * Bump golang from `69bfed3` to `3efef61` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1343 * Bump distroless/base-debian12 from `0a93daa` to `f47fa3d` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1340 * Bump golang from `69bfed3` to `3efef61` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1342 * Bump github/codeql-action from 3.23.2 to 3.24.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1346 * Bump actions/upload-artifact from 4.3.0 to 4.3.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1347 * Bump golang from 1.21.6-bookworm to 1.22.0-bookworm in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1350 * Bump golang from 1.21.6-bookworm to 1.22.0-bookworm in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1348 * Bump golang from 1.21.6-bookworm to 1.22.0-bookworm in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1349 * Bump golang from 1.21.6-bookworm to 1.22.0-bookworm in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1351 * Bump golang.org/x/crypto from 0.18.0 to 0.19.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1353 * Bump golangci/golangci-lint-action from 3.7.0 to 4.0.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1354 * Bump golang.org/x/net from 0.20.0 to 0.21.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1352 * Bump distroless/base-debian12 from `f47fa3d` to `2102ce1` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1355 * Bump github/codeql-action from 3.24.0 to 3.24.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1357 * Bump golang from `874c267` to `5a3e169` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1356 * Bump golang from `874c267` to `5a3e169` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1358 * Bump golang from `874c267` to `5a3e169` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1359 * Bump golang from `874c267` to `5a3e169` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1360 * Bump github/codeql-action from 3.24.1 to 3.24.3 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1366 * Bump golang from `5a3e169` to `925fe3f` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1363 * Bump google.golang.org/grpc from 1.61.0 to 1.61.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1362 * Bump golang from `5a3e169` to `925fe3f` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1365 * Bump golang from `5a3e169` to `925fe3f` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1361 * Bump golang from `5a3e169` to `925fe3f` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1367 * Bump golang/govulncheck-action from 1.0.1 to 1.0.2 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1368 * Bump github/codeql-action from 3.24.3 to 3.24.5 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1371 * Bump google.golang.org/grpc from 1.61.1 to 1.62.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1369 * Bump distroless/base-debian12 from `2102ce1` to `5eae9ef` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1372 * Bump distroless/base-debian12 from `5eae9ef` to `f9b0e86` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1375 * Bump golang.org/x/crypto from 0.19.0 to 0.20.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1374 * Bump github.com/prometheus/client_golang from 1.18.0 to 1.19.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1373 * Bump github/codeql-action from 3.24.5 to 3.24.6 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1377 * Bump distroless/base-debian12 from `f9b0e86` to `5eae9ef` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1376 * Bump golang.org/x/net from 0.21.0 to 0.22.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1378 * Bump Go from 1.20 to 1.21 by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1386 * Bump google.golang.org/grpc from 1.62.0 to 1.62.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1380 * Bump golang from 1.22.0-bookworm to 1.22.1-bookworm in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1382 * Bump golang from 1.22.0-bookworm to 1.22.1-bookworm in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1385 * Bump golang from 1.22.0-bookworm to 1.22.1-bookworm in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1384 * Bump golang from 1.22.0-bookworm to 1.22.1-bookworm in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1383 ## v1.1.7 * Recommended Go version for development: 1.20 * This is the version used by the Cloud Build presubmits. Using a different version can lead to presubmits failing due to unexpected diffs. * Bump golangci-lint from 1.51.1 to 1.55.1 (developers should update to this version). ### Add support for WASI port * Add build tags for wasip1 GOOS by @flavio in https://github.com/google/certificate-transparency-go/pull/1089 ### Add support for IBM Z operating system z/OS * Add build tags for zOS by @onlywork1984 in https://github.com/google/certificate-transparency-go/pull/1088 ### Log List * Add support for "is_all_logs" field in loglist3 by @phbnf in https://github.com/google/certificate-transparency-go/pull/1095 ### Documentation * Improve Dockerized Test Deployment documentation by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1179 ### Misc * Escape forward slashes in certificate Subject names when used as user quota id strings by @robstradling in https://github.com/google/certificate-transparency-go/pull/1059 * Search whole chain looking for issuer match by @mhutchinson in https://github.com/google/certificate-transparency-go/pull/1112 * Use proper check per @AGWA instead of buggy check introduced in #1112 by @mhutchinson in https://github.com/google/certificate-transparency-go/pull/1114 * Build the ctfe/ct_server binary without depending on glibc by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1119 * Migrate CTFE Ingress manifest to support GKE version 1.23 by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1086 * Remove Dependabot ignore configuration by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1097 * Add "github-actions" and "docker" Dependabot config by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1101 * Add top level permission in CodeQL workflow by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1102 * Pin Docker image dependencies by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1110 * Remove GO111MODULE from Dockerfile and Cloud Build yaml files by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1113 * Add docker Dependabot config by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1126 * Export is_mirror = 0.0 for non mirror instead of nothing by @phbnf in https://github.com/google/certificate-transparency-go/pull/1133 * Add govulncheck GitHub action by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1145 * Spelling by @jsoref in https://github.com/google/certificate-transparency-go/pull/1144 ### Dependency update * Bump Go from 1.19 to 1.20 by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1146 * Bump golangci-lint from 1.51.1 to 1.55.1 by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1214 * Bump go.etcd.io/etcd/v3 from 3.5.8 to 3.5.9 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1083 * Bump golang.org/x/crypto from 0.8.0 to 0.9.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/108 * Bump github.com/mattn/go-sqlite3 from 1.14.16 to 1.14.17 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1092 * Bump golang.org/x/net from 0.10.0 to 0.11.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1094 * Bump github.com/prometheus/client_golang from 1.15.1 to 1.16.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1098 * Bump google.golang.org/protobuf from 1.30.0 to 1.31.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1099 * Bump golang.org/x/net from 0.11.0 to 0.12.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1108 * Bump actions/checkout from 3.1.0 to 3.5.3 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1103 * Bump github/codeql-action from 2.1.27 to 2.20.3 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1104 * Bump ossf/scorecard-action from 2.0.6 to 2.2.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1105 * Bump actions/upload-artifact from 3.1.0 to 3.1.2 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1106 * Bump github/codeql-action from 2.20.3 to 2.20.4 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1115 * Bump github/codeql-action from 2.20.4 to 2.21.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1117 * Bump golang.org/x/net from 0.12.0 to 0.14.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1124 * Bump github/codeql-action from 2.21.0 to 2.21.2 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1121 * Bump github/codeql-action from 2.21.2 to 2.21.4 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1125 * Bump golang from `fd9306e` to `eb3f9ac` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1127 * Bump alpine from 3.8 to 3.18 in /trillian/examples/deployment/docker/envsubst by @dependabot in https://github.com/google/certificate-transparency-go/pull/1129 * Bump golang from `fd9306e` to `eb3f9ac` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1128 * Bump alpine from `82d1e9d` to `7144f7b` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1130 * Bump golang from `fd9306e` to `eb3f9ac` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1131 * Bump golang from 1.19-alpine to 1.21-alpine in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1132 * Bump actions/checkout from 3.5.3 to 3.6.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1134 * Bump github/codeql-action from 2.21.4 to 2.21.5 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1135 * Bump distroless/base from `73deaaf` to `46c5b9b` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1136 * Bump actions/checkout from 3.6.0 to 4.0.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1137 * Bump golang.org/x/net from 0.14.0 to 0.15.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1139 * Bump github.com/rs/cors from 1.9.0 to 1.10.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1140 * Bump actions/upload-artifact from 3.1.2 to 3.1.3 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1141 * Bump golang from `445f340` to `96634e5` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1142 * Bump github/codeql-action from 2.21.5 to 2.21.6 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1149 * Bump Docker golang base images to 1.21.1 by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1147 * Bump github/codeql-action from 2.21.6 to 2.21.7 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1150 * Bump github/codeql-action from 2.21.7 to 2.21.8 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1152 * Bump golang from `d3114db` to `a0b3bc4` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1155 * Bump golang from `d3114db` to `a0b3bc4` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1157 * Bump golang from `d3114db` to `a0b3bc4` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1156 * Bump golang from `d3114db` to `a0b3bc4` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1158 * Bump golang from `e06b3a4` to `114b9cc` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1159 * Bump golang from `a0b3bc4` to `114b9cc` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1160 * Bump golang from `a0b3bc4` to `114b9cc` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1161 * Bump actions/checkout from 4.0.0 to 4.1.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1162 * Bump golang from `114b9cc` to `9c7ea4a` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1163 * Bump golang from `114b9cc` to `9c7ea4a` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1166 * Bump golang from `114b9cc` to `9c7ea4a` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1165 * Bump golang from `114b9cc` to `9c7ea4a` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1164 * Bump github/codeql-action from 2.21.8 to 2.21.9 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1169 * Bump golang from `9c7ea4a` to `61f84bc` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1168 * Bump github.com/prometheus/client_golang from 1.16.0 to 1.17.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1172 * Bump golang from `9c7ea4a` to `61f84bc` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1170 * Bump github.com/rs/cors from 1.10.0 to 1.10.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1176 * Bump alpine from `7144f7b` to `eece025` in /trillian/examples/deployment/docker/envsubst by @dependabot in https://github.com/google/certificate-transparency-go/pull/1174 * Bump alpine from `7144f7b` to `eece025` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1175 * Bump golang from `9c7ea4a` to `61f84bc` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1171 * Bump golang from `9c7ea4a` to `61f84bc` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1173 * Bump distroless/base from `46c5b9b` to `a35b652` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1177 * Bump golang.org/x/crypto from 0.13.0 to 0.14.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1178 * Bump github/codeql-action from 2.21.9 to 2.22.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1180 * Bump golang from 1.21.1-bookworm to 1.21.2-bookworm in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1181 * Bump golang.org/x/net from 0.15.0 to 0.16.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1184 * Bump golang from 1.21.1-bookworm to 1.21.2-bookworm in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1182 * Bump golang from 1.21.1-bookworm to 1.21.2-bookworm in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1185 * Bump golang from 1.21.1-bookworm to 1.21.2-bookworm in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1183 * Bump github/codeql-action from 2.22.0 to 2.22.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1186 * Bump distroless/base from `a35b652` to `b31a6e0` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1188 * Bump ossf/scorecard-action from 2.2.0 to 2.3.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1187 * Bump github.com/google/go-cmp from 0.5.9 to 0.6.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1189 * Bump golang.org/x/net from 0.16.0 to 0.17.0 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1190 * Bump go-version-input from 1.20.8 to 1.20.10 in govulncheck by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1195 * Bump golang from 1.21.2-bookworm to 1.21.3-bookworm in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1193 * Bump golang from 1.21.2-bookworm to 1.21.3-bookworm in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1191 * Bump golang from 1.21.2-bookworm to 1.21.3-bookworm in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1194 * Bump golang from 1.21.2-bookworm to 1.21.3-bookworm in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1192 * Bump golang from `a94b089` to `8f9a1ec` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1196 * Bump github/codeql-action from 2.22.1 to 2.22.2 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1197 * Bump golang from `a94b089` to `5cc7ddc` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1200 * Bump golang from `a94b089` to `5cc7ddc` in /internal/witness/cmd/witness by @dependabot in https://github.com/google/certificate-transparency-go/pull/1199 * Bump github/codeql-action from 2.22.2 to 2.22.3 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1202 * Bump golang from `5cc7ddc` to `20f9ab5` in /integration by @dependabot in https://github.com/google/certificate-transparency-go/pull/1203 * Bump golang from `a94b089` to `20f9ab5` in /trillian/examples/deployment/docker/ctfe by @dependabot in https://github.com/google/certificate-transparency-go/pull/1198 * Bump golang from `8f9a1ec` to `20f9ab5` in /internal/witness/cmd/feeder by @dependabot in https://github.com/google/certificate-transparency-go/pull/1201 * Bump actions/checkout from 4.1.0 to 4.1.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1204 * Bump github/codeql-action from 2.22.3 to 2.22.4 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1206 * Bump ossf/scorecard-action from 2.3.0 to 2.3.1 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1207 * Bump github/codeql-action from 2.22.4 to 2.22.5 by @dependabot in https://github.com/google/certificate-transparency-go/pull/1209 * Bump multiple Go module dependencies by @roger2hk in https://github.com/google/certificate-transparency-go/pull/1213 ## v1.1.6 ### Dependency update * Bump Trillian to v1.5.2 * Bump Prometheus to v0.43.1 ## v1.1.5 ### Public/Private Key Consistency * #1044: If a public key has been configured for a log, check that it is consistent with the private key. * #1046: Ensure that no two logs in the CTFE configuration use the same private key. ### Cleanup * Remove v2 log list package files. ### Misc * Updated golangci-lint to v1.51.1 (developers should update to this version). * Bump Go version from 1.17 to 1.19. ## v1.1.4 [Published 2022-10-21](https://github.com/google/certificate-transparency-go/releases/tag/v1.1.4) ### Cleanup * Remove log list v1 package and its dependencies. ### Migrillian * #960: Skip consistency check when root is size zero. ### Misc * Update Trillian to [0a389c4](https://github.com/google/trillian/commit/0a389c4bb8d97fb3be8f55d7e5b428cf4304986f) * Migrate loglist dependency from v1 to v3 in ctclient cmd. * Migrate loglist dependency from v1 to v3 in ctutil/loginfo.go * Migrate loglist dependency from v1 to v3 in ctutil/sctscan.go * Migrate loglist dependency from v1 to v3 in trillian/integration/ct_hammer/main.go * Downgrade 429 errors to verbosity 2 ## v1.1.3 [Published 2022-05-14](https://github.com/google/certificate-transparency-go/releases/tag/v1.1.3) ### Integration * Breaking change to API for `integration.HammerCTLog`: * Added `ctx` as first argument, and terminate loop if it becomes cancelled ### JSONClient * PostAndParseWithRetry now does backoff-and-retry upon receiving HTTP 429. ### Cleanup * `WithBalancerName` is deprecated and removed, using the recommended way. * `ctfe.PEMCertPool` type has been moved to `x509util.PEMCertPool` to reduce dependencies (#903). ### Misc * updated golangci-lint to v1.46.1 (developers should update to this version) * update `google.golang.org/grpc` to v1.46.0 * `ctclient` tool now uses Cobra for better CLI experience (#901). * #800: Remove dependency from `ratelimit`. * #927: Add read-only mode to CTFE config. ## v1.1.2 [Published 2021-09-21](https://github.com/google/certificate-transparency-go/releases/tag/v1.1.2) ### CTFE * Removed the `-by_range` flag. ### Updated dependencies * Trillian from v1.3.11 to v1.4.0 * protobuf to v2 ## v1.1.1 [Published 2020-10-06](https://github.com/google/certificate-transparency-go/releases/tag/v1.1.1) ### Tools #### CT Hammer Added a flag (--strict_sth_consistency_size) which when set to true enforces the current behaviour of only request consistency proofs between tree sizes for which the hammer has seen valid STHs. When setting this flag to false, if no two usable STHs are available the hammer will attempt to request a consistency proof between the latest STH it's seen and a random smaller (but > 0) tree size. ### CTFE #### Caching The CTFE now includes a Cache-Control header in responses containing purely immutable data, e.g. those for get-entries and get-proof-by-hash. This allows clients and proxies to cache these responses for up to 24 hours. #### EKU Filtering > :warning: **It is not yet recommended to enable this option in a production CT Log!** CTFE now supports filtering logging submissions by leaf certificate EKU. This is enabled by adding an extKeyUsage list to a log's stanza in the config file. The format is a list of strings corresponding to the supported golang x509 EKUs: |Config string | Extended Key Usage | |----------------------------|----------------------------------------| |`Any` | ExtKeyUsageAny | |`ServerAuth` | ExtKeyUsageServerAuth | |`ClientAuth` | ExtKeyUsageClientAuth | |`CodeSigning` | ExtKeyUsageCodeSigning | |`EmailProtection` | ExtKeyUsageEmailProtection | |`IPSECEndSystem` | ExtKeyUsageIPSECEndSystem | |`IPSECTunnel` | ExtKeyUsageIPSECTunnel | |`IPSECUser` | ExtKeyUsageIPSECUser | |`TimeStamping` | ExtKeyUsageTimeStamping | |`OCSPSigning` | ExtKeyUsageOCSPSigning | |`MicrosoftServerGatedCrypto`| ExtKeyUsageMicrosoftServerGatedCrypto | |`NetscapeServerGatedCrypto` | ExtKeyUsageNetscapeServerGatedCrypto | When an extKeyUsage list is specified, the CT Log will reject logging submissions for leaf certificates that do not contain an EKU present in this list. When enabled, EKU filtering is only performed at the leaf level (i.e. there is no 'nested' EKU filtering performed). If no list is specified, or the list contains an `Any` entry, no EKU filtering will be performed. #### GetEntries Calls to `get-entries` which are at (or above) the maximum permitted number of entries whose `start` parameter does not fall on a multiple of the maximum permitted number of entries, will have their responses truncated such that subsequent requests will align with this boundary. This is intended to coerce callers of `get-entries` into all using the same `start` and `end` parameters and thereby increase the cacheability of these requests. e.g.:
Old behaviour:
             1         2         3
             0         0         0
Entries>-----|---------|---------|----...
Client A -------|---------|----------|...
Client B --|--------|---------|-------...
           ^        ^         ^
           `--------`---------`---- requests

With coercion (max batch = 10 entries):
             1         2         3
             0         0         0
Entries>-----|---------|---------|----...
Client A ----X---------|---------|...
Client B --|-X---------|---------|-------...
             ^
             `-- Requests truncated
This behaviour can be disabled by setting the `--align_getentries` flag to false. #### Flags The `ct_server` binary changed the default of these flags: - `by_range` - Now defaults to `true` The `ct_server` binary added the following flags: - `align_getentries` - See GetEntries section above for details Added `backend` flag to `migrillian`, which now replaces the deprecated "backend" feature of Migrillian configs. #### FixedBackendResolver Replaced This was previously used in situations where a comma separated list of backends was provided in the `rpcBackend` flag rather than a single value. It has been replaced by equivalent functionality using a newer gRPC API. However this support was only intended for use in integration tests. In production we recommend the use of etcd or a gRPC load balancer. ### LogList Log list tools updated to use the correct v2 URL (from v2_beta previously). ### Libraries #### x509 fork Merged upstream Go 1.13 and Go 1.14 changes (with the exception of https://github.com/golang/go/commit/14521198679e, to allow old certs using a malformed root still to be logged). #### asn1 fork Merged upstream Go 1.14 changes. #### ctutil Added VerifySCTWithVerifier() to verify SCTs using a given ct.SignatureVerifier. ### Configuration Files Configuration files that previously had to be text-encoded Protobuf messages can now alternatively be binary-encoded instead. ### JSONClient - `PostAndParseWithRetry` error logging now includes log URI in messages. ### Minimal Gossip Example All the code for this, except for the x509ext package, has been moved over to the [trillian-examples](https://github.com/google/trillian-examples) repository. This keeps the code together and removes a circular dependency between the two repositories. The package layout and structure remains the same so updating should just mean changing any relevant import paths. ### Dependencies A circular dependency on the [monologue](https://github.com/google/monologue) repository has been removed. A circular dependency on the [trillian-examples](https://github.com/google/trillian-examples) repository has been removed. The version of trillian in use has been updated to 1.3.11. This has required various other dependency updates including gRPC and protobuf. This code now uses the v2 proto API. The Travis tests now expect the 3.11.4 version of protoc. The version of etcd in use has been switched to the one from `go.etcd.io`. Most of the above changes are to align versions more closely with the ones used in the trillian repository. ## v1.1.0 Published 2019-11-14 15:00:00 +0000 UTC ### CTFE The `reject_expired` and `reject_unexpired` configuration fields for the CTFE have been changed so that their behaviour reflects their name: - `reject_expired` only rejects expired certificates (i.e. it now allows not-yet-valid certificates). - `reject_unexpired` only allows expired certificates (i.e. it now rejects not-yet-valid certificates). A `reject_extensions` configuration field for the CTFE was added, this allows submissions to be rejected if they contain an extension with any of the specified OIDs. A `frozen_sth` configuration field for the CTFE was added. This STH will be served permanently. It must be signed by the log's private key. A `/healthz` URL has been added which responds with HTTP 200 OK and the string "ok" when the server is up. #### Flags The `ct_server` binary has these new flags: - `mask_internal_errors` - Removes error strings from HTTP 500 responses (Internal Server Error) Removed default values for `--metrics_endpoint` and `--log_rpc_server` flags. This makes it easier to get the documented "unset" behaviour. #### Metrics The CTFE exports these new metrics: - `is_mirror` - set to 1 for mirror logs (copies of logs hosted elsewhere) - `frozen_sth_timestamp` - time of the frozen Signed Tree Head in milliseconds since the epoch #### Kubernetes Updated prometheus-to-sd to v0.5.2. A dedicated node pool is no longer required by the Kubernetes manifests. ### Log Lists A new package has been created for parsing, searching and creating JSON log lists compatible with the [v2 schema](http://www.gstatic.com/ct/log_list/v2_beta/log_list_schema.json): `github.com/google/certificate-transparency-go/loglist2`. ### Docker Images Our Docker images have been updated to use Go 1.11 and [Distroless base images](https://github.com/GoogleContainerTools/distroless). The CTFE Docker image now sets `ENTRYPOINT`. ### Utilities / Libraries #### jsonclient The `jsonclient` package now copes with empty HTTP responses. The user-agent header it sends can now be specified. #### x509 and asn1 forks Merged upstream changes from Go 1.12 into the `asn1` and `x509` packages. Added a "lax" tag to `asn1` that applies recursively and makes some checks more relaxed: - parsePrintableString() copes with invalid PrintableString contents, e.g. use of tagPrintableString when the string data is really ISO8859-1. - checkInteger() allows integers that are not minimally encoded (and so are not correct DER). - OIDs are allowed to be empty. The following `x509` functions will now return `x509.NonFatalErrors` if ASN.1 parsing fails in strict mode but succeeds in lax mode. Previously, they only attempted strict mode parsing. - `x509.ParseTBSCertificate()` - `x509.ParseCertificate()` - `x509.ParseCertificates()` The `x509` package will now treat a negative RSA modulus as a non-fatal error. The `x509` package now supports RSASES-OAEP and Ed25519 keys. #### ctclient The `ctclient` tool now defaults to using [all_logs_list.json](https://www.gstatic.com/ct/log_list/all_logs_list.json) instead of [log_list.json](https://www.gstatic.com/ct/log_list/log_list.json). This can be overridden using the `--log_list` flag. It can now perform inclusion checks on pre-certificates. It has these new commands: - `bisect` - Finds a log entry given a timestamp. It has these new flags: - `--chain` - Displays the entire certificate chain - `--dns_server` - The DNS server to direct queries to (system resolver by default) - `--skip_https_verify` - Skips verification of the HTTPS connection - `--timestamp` - Timestamp to use for `bisect` and `inclusion` commands (for `inclusion`, only if --leaf_hash is not used) It now accepts hex or base64-encoded strings for the `--tree_hash`, `--prev_hash` and `--leaf_hash` flags. #### certcheck The `certcheck` tool has these new flags: - `--check_time` - Check current validity of certificate (replaces `--timecheck`) - `--check_name` - Check validity of certificate name - `--check_eku` - Check validity of EKU nesting - `--check_path_len` - Check validity of path length constraint - `--check_name_constraint` - Check name constraints - `--check_unknown_critical_exts` - Check for unknown critical extensions (replaces `--ignore_unknown_critical_exts`) - `--strict` - Set non-zero exit code for non-fatal errors in parsing #### sctcheck The `sctcheck` tool has these new flags: - `--check_inclusion` - Checks that the SCT was honoured (i.e. the corresponding certificate was included in the issuing CT log) #### ct_hammer The `ct_hammer` tool has these new flags: - `--duplicate_chance` - Allows setting the probability of the hammer sending a duplicate submission. ## v1.0.21 - CTFE Logging / Path Options. Mirroring. RPKI. Non Fatal X.509 error improvements Published 2018-08-20 10:11:04 +0000 UTC ### CTFE `CTFE` no longer prints certificate chains as long byte strings in messages when handler errors occur. This was obscuring the reason for the failure and wasn't particularly useful. `CTFE` now has a global log URL path prefix flag and a configuration proto for a log specific path. The latter should help for various migration strategies if existing C++ server logs are going to be converted to run on the new code. ### Mirroring More progress has been made on log mirroring. We believe that it's now at the point where testing can begin. ### Utilities / Libraries The `certcheck` and `ct_hammer` utilities have received more enhancements. `x509` and `x509util` now support Subject Information Access and additional extensions for [RPKI / RFC 3779](https://www.ietf.org/rfc/rfc3779.txt). `scanner` / `fixchain` and some other command line utilities now have better handling of non-fatal errors. Commit [3629d6846518309d22c16fee15d1007262a459d2](https://api.github.com/repos/google/certificate-transparency-go/commits/3629d6846518309d22c16fee15d1007262a459d2) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.21) ## v1.0.20 - Minimal Gossip / Go 1.11 Fix / Utility Improvements Published 2018-07-05 09:21:34 +0000 UTC Enhancements have been made to various utilities including `scanner`, `sctcheck`, `loglist` and `x509util`. The `allow_verification_with_non_compliant_keys` flag has been removed from `signatures.go`. An implementation of Gossip has been added. See the `gossip/minimal` package for more information. An X.509 compatibility issue for Go 1.11 has been fixed. This should be backwards compatible with 1.10. Commit [37a384cd035e722ea46e55029093e26687138edf](https://api.github.com/repos/google/certificate-transparency-go/commits/37a384cd035e722ea46e55029093e26687138edf) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.20) ## v1.0.19 - CTFE User Quota Published 2018-06-01 13:51:52 +0000 UTC CTFE now supports Trillian Log's explicit quota API; quota can be requested based on the remote user's IP, as well as per-issuing certificate in submitted chains. Commit [8736a411b4ff214ea20687e46c2b67d66ebd83fc](https://api.github.com/repos/google/certificate-transparency-go/commits/8736a411b4ff214ea20687e46c2b67d66ebd83fc) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.19) ## v1.0.18 - Adding Migration Tool / Client Additions / K8 Config Published 2018-06-01 14:28:20 +0000 UTC Work on a log migration tool (Migrillian) is in progress. This is not yet ready for production use but will provide features for mirroring and migrating logs. The `RequestLog` API allows for logging of SCTs when they are issued by CTFE. The CT Go client now supports `GetEntryAndProof`. Utilities have been switched over to use the `glog` package. Commit [77abf2dac5410a62c04ac1c662c6d0fa54afc2dc](https://api.github.com/repos/google/certificate-transparency-go/commits/77abf2dac5410a62c04ac1c662c6d0fa54afc2dc) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.18) ## v1.0.17 - Merkle verification / Tracing / Demo script / CORS Published 2018-06-01 14:25:16 +0000 UTC Now uses Merkle Tree verification from Trillian. The CT server now supports CORS. Request tracing added using OpenCensus. For GCE / K8 it just requires the flag to be enabled to export traces to Stackdriver. Other environments may differ. A demo script was added that goes through setting up a simple deployment suitable for development / demo purposes. This may be useful for those new to the project. Commit [3c3d22ce946447d047a03228ebb4a41e3e4eb15b](https://api.github.com/repos/google/certificate-transparency-go/commits/3c3d22ce946447d047a03228ebb4a41e3e4eb15b) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.17) ## v1.0.16 - Lifecycle test / Go 1.10.1 Published 2018-06-01 14:22:23 +0000 UTC An integration test was added that goes through a create / drain queue / freeze lifecycle for a log. Changes to `x509` were merged from Go 1.10.1. Commit [a72423d09b410b80673fd1135ba1022d04bac6cd](https://api.github.com/repos/google/certificate-transparency-go/commits/a72423d09b410b80673fd1135ba1022d04bac6cd) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.16) ## v1.0.15 - More control of verification, grpclb, stackdriver metrics Published 2018-06-01 14:20:32 +0000 UTC Facilities were added to the `x509` package to control whether verification checks are applied. Log server requests are now balanced using `gRPClb`. For Kubernetes, metrics can be published to Stackdriver monitoring. Commit [684d6eee6092774e54d301ccad0ed61bc8d010c1](https://api.github.com/repos/google/certificate-transparency-go/commits/684d6eee6092774e54d301ccad0ed61bc8d010c1) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.15) ## v1.0.14 - SQLite Removed, LeafHashForLeaf Published 2018-06-01 14:15:37 +0000 UTC Support for SQLite was removed. This motivation was ongoing test flakiness caused by multi-user access. This database may work for an embedded scenario but is not suitable for use in a server environment. A `LeafHashForLeaf` client API was added and is now used by the CT client and integration tests. Commit [698cd6a661196db4b2e71437422178ffe8705006](https://api.github.com/repos/google/certificate-transparency-go/commits/698cd6a661196db4b2e71437422178ffe8705006) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.14) ## v1.0.13 - Crypto changes, util updates, sync with trillian repo, loglist verification Published 2018-06-01 14:15:21 +0000 UTC Some of our custom crypto package that were wrapping calls to the standard package have been removed and the base features used directly. Updates were made to GCE ingress and health checks. The log list utility can verify signatures. Commit [480c3654a70c5383b9543ec784203030aedbd3a5](https://api.github.com/repos/google/certificate-transparency-go/commits/480c3654a70c5383b9543ec784203030aedbd3a5) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.13) ## v1.0.12 - Client / util updates & CTFE fixes Published 2018-06-01 14:13:42 +0000 UTC The CT client can now use a JSON loglist to find logs. CTFE had a fix applied for preissued precerts. A DNS client was added and CT client was extended to support DNS retrieval. Commit [74c06c95e0b304a050a1c33764c8a01d653a16e3](https://api.github.com/repos/google/certificate-transparency-go/commits/74c06c95e0b304a050a1c33764c8a01d653a16e3) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.12) ## v1.0.11 - Kubernetes CI / Integration fixes Published 2018-06-01 14:12:18 +0000 UTC Updates to Kubernetes configs, mostly related to running a CI instance. Commit [0856acca7e0ab7f082ae83a1fbb5d21160962efc](https://api.github.com/repos/google/certificate-transparency-go/commits/0856acca7e0ab7f082ae83a1fbb5d21160962efc) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.11) ## v1.0.10 - More scanner, x509, utility and client fixes. CTFE updates Published 2018-06-01 14:09:47 +0000 UTC The CT client was using the wrong protobuffer library package. To guard against this in future a check has been added to our lint config. The `x509` and `asn1` packages have had upstream fixes applied from Go 1.10rc1. Commit [1bec4527572c443752ad4f2830bef88be0533236](https://api.github.com/repos/google/certificate-transparency-go/commits/1bec4527572c443752ad4f2830bef88be0533236) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.10) ## v1.0.9 - Scanner, x509, utility and client fixes Published 2018-06-01 14:11:13 +0000 UTC The `scanner` utility now displays throughput stats. Build instructions and README files were updated. The `certcheck` utility can be told to ignore unknown critical X.509 extensions. Commit [c06833528d04a94eed0c775104d1107bab9ae17c](https://api.github.com/repos/google/certificate-transparency-go/commits/c06833528d04a94eed0c775104d1107bab9ae17c) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.9) ## v1.0.8 - Client fixes, align with trillian repo Published 2018-06-01 14:06:44 +0000 UTC Commit [e8b02c60f294b503dbb67de0868143f5d4935e56](https://api.github.com/repos/google/certificate-transparency-go/commits/e8b02c60f294b503dbb67de0868143f5d4935e56) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.8) ## v1.0.7 - CTFE fixes Published 2018-06-01 14:06:13 +0000 UTC An issue was fixed with CTFE signature caching. In an unlikely set of circumstances this could lead to log mis-operation. While the chances of this are small, we recommend that versions prior to this one are not deployed. Commit [52c0590bd3b4b80c5497005b0f47e10557425eeb](https://api.github.com/repos/google/certificate-transparency-go/commits/52c0590bd3b4b80c5497005b0f47e10557425eeb) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.7) ## v1.0.6 - crlcheck improvements / other fixes Published 2018-06-01 14:04:22 +0000 UTC The `crlcheck` utility has had several fixes and enhancements. Additionally the `hammer` now supports temporal logs. Commit [3955e4a00c42e83ff17ce25003976159c5d0f0f9](https://api.github.com/repos/google/certificate-transparency-go/commits/3955e4a00c42e83ff17ce25003976159c5d0f0f9) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.6) ## v1.0.5 - X509 and asn1 fixes Published 2018-06-01 14:02:58 +0000 UTC This release is mostly fixes to the `x509` and `asn1` packages. Some command line utilities were also updated. Commit [ae40d07cce12f1227c6e658e61c9dddb7646f97b](https://api.github.com/repos/google/certificate-transparency-go/commits/ae40d07cce12f1227c6e658e61c9dddb7646f97b) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.5) ## v1.0.4 - Multi log backend configs Published 2018-06-01 14:02:07 +0000 UTC Support was added to allow CTFE to use multiple backends, each serving a distinct set of logs. It allows for e.g. regional backend deployment with common frontend servers. Commit [62023ed90b41fa40854957b5dec7d9d73594723f](https://api.github.com/repos/google/certificate-transparency-go/commits/62023ed90b41fa40854957b5dec7d9d73594723f) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.4) ## v1.0.3 - Hammer updates, use standard context Published 2018-06-01 14:01:11 +0000 UTC After the Go 1.9 migration references to anything other than the standard `context` package have been removed. This is the only one that should be used from now on. Commit [b28beed8b9aceacc705e0ff4a11d435a310e3d97](https://api.github.com/repos/google/certificate-transparency-go/commits/b28beed8b9aceacc705e0ff4a11d435a310e3d97) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.3) ## v1.0.2 - Go 1.9 Published 2018-06-01 14:00:00 +0000 UTC Go 1.9 is now required to build the code. Commit [3aed33d672ee43f04b1e8a00b25ca3e2e2e74309](https://api.github.com/repos/google/certificate-transparency-go/commits/3aed33d672ee43f04b1e8a00b25ca3e2e2e74309) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.2) ## v1.0.1 - Hammer and client improvements Published 2018-06-01 13:59:29 +0000 UTC Commit [c28796cc21776667fb05d6300e32d9517be96515](https://api.github.com/repos/google/certificate-transparency-go/commits/c28796cc21776667fb05d6300e32d9517be96515) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.1) ## v1.0 - First Trillian CT Release Published 2018-06-01 13:59:00 +0000 UTC This is the point that corresponds to the 1.0 release in the trillian repo. Commit [abb79e468b6f3bbd48d1ab0c9e68febf80d52c4d](https://api.github.com/repos/google/certificate-transparency-go/commits/abb79e468b6f3bbd48d1ab0c9e68febf80d52c4d) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0) ================================================ FILE: vendor/github.com/google/certificate-transparency-go/CODEOWNERS ================================================ * @google/certificate-transparency ================================================ FILE: vendor/github.com/google/certificate-transparency-go/CONTRIBUTING.md ================================================ # How to contribute # We'd love to accept your patches and contributions to this project. There are a just a few small guidelines you need to follow. ## Contributor License Agreement ## Contributions to any Google project must be accompanied by a Contributor License Agreement. This is not a copyright **assignment**, it simply gives Google permission to use and redistribute your contributions as part of the project. * If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA][]. * If you work for a company that wants to allow you to contribute your work, then you'll need to sign a [corporate CLA][]. You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. [individual CLA]: https://developers.google.com/open-source/cla/individual [corporate CLA]: https://developers.google.com/open-source/cla/corporate Once your CLA is submitted (or if you already submitted one for another Google project), make a commit adding yourself to the [AUTHORS][] and [CONTRIBUTORS][] files. This commit can be part of your first [pull request][]. [AUTHORS]: AUTHORS [CONTRIBUTORS]: CONTRIBUTORS ## Submitting a patch ## 1. It's generally best to start by opening a new issue describing the bug or feature you're intending to fix. Even if you think it's relatively minor, it's helpful to know what people are working on. Mention in the initial issue that you are planning to work on that bug or feature so that it can be assigned to you. 1. Follow the normal process of [forking][] the project, and setup a new branch to work in. It's important that each group of changes be done in separate branches in order to ensure that a pull request only includes the commits related to that bug or feature. 1. Do your best to have [well-formed commit messages][] for each change. This provides consistency throughout the project, and ensures that commit messages are able to be formatted properly by various git tools. 1. Finally, push the commits to your fork and submit a [pull request][]. [forking]: https://help.github.com/articles/fork-a-repo [well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html [pull request]: https://help.github.com/articles/creating-a-pull-request ================================================ FILE: vendor/github.com/google/certificate-transparency-go/CONTRIBUTORS ================================================ # People who have agreed to one of the CLAs and can contribute patches. # The AUTHORS file lists the copyright holders; this file # lists people. For example, Google employees are listed here # but not in AUTHORS, because Google holds the copyright. # # Names should be added to this file only after verifying that # the individual or the individual's organization has agreed to # the appropriate Contributor License Agreement, found here: # # https://developers.google.com/open-source/cla/individual # https://developers.google.com/open-source/cla/corporate # # The agreement for individuals can be filled out on the web. # # When adding J Random Contributor's name to this file, # either J's name or J's organization's name should be # added to the AUTHORS file, depending on whether the # individual or corporate CLA was used. # # Names should be added to this file as: # Name # # Please keep the list sorted. Adam Eijdenberg Al Cutter Alex Cohn Ben Laurie Chris Kennelly David Drysdale Deyan Bektchiev Ed Maste Emilia Kasper Eran Messeri Fiaz Hossain Gary Belvin Jeff Trawick Joe Tsai Kat Joyce Katriel Cohn-Gordon Kiril Nikolov Konrad Kraszewski Laël Cellier Linus Nordberg Mark Schloesser Nicholas Galbreath Oliver Weidner Pascal Leroy Paul Hadfield Paul Lietar Pavel Kalinnikov Pierre Phaneuf Rob Percival Rob Stradling Roger Ng Roland Shoemaker Ruslan Kovalov Samuel Lidén Borell Tatiana Merkulova Vladimir Rutsky Ximin Luo ================================================ FILE: vendor/github.com/google/certificate-transparency-go/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/google/certificate-transparency-go/PULL_REQUEST_TEMPLATE.md ================================================ ### Checklist - [ ] I have updated the [CHANGELOG](CHANGELOG.md). - Adjust the draft version number according to [semantic versioning](https://semver.org/) rules. - [ ] I have updated [documentation](docs/) accordingly. ================================================ FILE: vendor/github.com/google/certificate-transparency-go/README.md ================================================ # Certificate Transparency: Go Code [![Go Report Card](https://goreportcard.com/badge/github.com/google/certificate-transparency-go)](https://goreportcard.com/report/github.com/google/certificate-transparency-go) [![GoDoc](https://godoc.org/github.com/google/certificate-transparency-go?status.svg)](https://godoc.org/github.com/google/certificate-transparency-go) ![CodeQL workflow](https://github.com/google/certificate-transparency-go/actions/workflows/codeql.yml/badge.svg) This repository holds Go code related to [Certificate Transparency](https://www.certificate-transparency.org/) (CT). The repository requires Go version 1.21. - [Repository Structure](#repository-structure) - [Trillian CT Personality](#trillian-ct-personality) - [Working on the Code](#working-on-the-code) - [Running Codebase Checks](#running-codebase-checks) - [Rebuilding Generated Code](#rebuilding-generated-code) ## Support - Slack: https://transparency-dev.slack.com/ ([invitation](https://join.slack.com/t/transparency-dev/shared_invite/zt-27pkqo21d-okUFhur7YZ0rFoJVIOPznQ)) ## Repository Structure The main parts of the repository are: - Encoding libraries: - `asn1/` and `x509/` are forks of the upstream Go `encoding/asn1` and `crypto/x509` libraries. We maintain separate forks of these packages because CT is intended to act as an observatory of certificates across the ecosystem; as such, we need to be able to process somewhat-malformed certificates that the stricter upstream code would (correctly) reject. Our `x509` fork also includes code for working with the [pre-certificates defined in RFC 6962](https://tools.ietf.org/html/rfc6962#section-3.1). - `tls` holds a library for processing TLS-encoded data as described in [RFC 5246](https://tools.ietf.org/html/rfc5246). - `x509util/` provides additional utilities for dealing with `x509.Certificate`s. - CT client libraries: - The top-level `ct` package (in `.`) holds types and utilities for working with CT data structures defined in [RFC 6962](https://tools.ietf.org/html/rfc6962). - `client/` and `jsonclient/` hold libraries that allow access to CT Logs via HTTP entrypoints described in [section 4 of RFC 6962](https://tools.ietf.org/html/rfc6962#section-4). - `dnsclient/` has a library that allows access to CT Logs over [DNS](https://github.com/google/certificate-transparency-rfcs/blob/master/dns/draft-ct-over-dns.md). - `scanner/` holds a library for scanning the entire contents of an existing CT Log. - CT Personality for [Trillian](https://github.com/google/trillian): - `trillian/` holds code that allows a Certificate Transparency Log to be run using a Trillian Log as its back-end -- see [below](#trillian-ct-personality). - Command line tools: - `./client/ctclient` allows interaction with a CT Log. - `./ctutil/sctcheck` allows SCTs (signed certificate timestamps) from a CT Log to be verified. - `./scanner/scanlog` allows an existing CT Log to be scanned for certificates of interest; please be polite when running this tool against a Log. - `./x509util/certcheck` allows display and verification of certificates - `./x509util/crlcheck` allows display and verification of certificate revocation lists (CRLs). - Other libraries related to CT: - `ctutil/` holds utility functions for validating and verifying CT data structures. - `loglist3/` has a library for reading [v3 JSON lists of CT Logs](https://groups.google.com/a/chromium.org/g/ct-policy/c/IdbrdAcDQto/m/i5KPyzYwBAAJ). ## Trillian CT Personality The `trillian/` subdirectory holds code and scripts for running a CT Log based on the [Trillian](https://github.com/google/trillian) general transparency Log, and is [documented separately](trillian/README.md). ## Working on the Code Developers who want to make changes to the codebase need some additional dependencies and tools, described in the following sections. ### Running Codebase Checks The [`scripts/presubmit.sh`](scripts/presubmit.sh) script runs various tools and tests over the codebase; please ensure this script passes before sending pull requests for review. ```bash # Install golangci-lint go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.1 # Run code generation, build, test and linters ./scripts/presubmit.sh # Run build, test and linters but skip code generation ./scripts/presubmit.sh --no-generate # Or just run the linters alone: golangci-lint run ``` ### Rebuilding Generated Code Some of the CT Go code is autogenerated from other files: - [Protocol buffer](https://developers.google.com/protocol-buffers/) message definitions are converted to `.pb.go` implementations. - A mock implementation of the Trillian gRPC API (in `trillian/mockclient`) is created with [GoMock](https://github.com/golang/mock). Re-generating mock or protobuffer files is only needed if you're changing the original files; if you do, you'll need to install the prerequisites: - tools written in `go` can be installed with a single run of `go install` (courtesy of [`tools.go`](./tools/tools.go) and `go.mod`). - `protoc` tool: you'll need [version 3.20.1](https://github.com/protocolbuffers/protobuf/releases/tag/v3.20.1) installed, and `PATH` updated to include its `bin/` directory. With tools installed, run the following: ```bash go generate -x ./... # hunts for //go:generate comments and runs them ``` ================================================ FILE: vendor/github.com/google/certificate-transparency-go/asn1/README.md ================================================ # Important Notice This is a fork of the `encoding/asn1` Go package. The original source can be found on [GitHub](https://github.com/golang/go). Be careful about making local modifications to this code as it will make maintenance harder in future. ================================================ FILE: vendor/github.com/google/certificate-transparency-go/asn1/asn1.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package asn1 implements parsing of DER-encoded ASN.1 data structures, // as defined in ITU-T Rec X.690. // // See also “A Layman's Guide to a Subset of ASN.1, BER, and DER,” // http://luca.ntop.org/Teaching/Appunti/asn1.html. // // This is a fork of the Go standard library ASN.1 implementation // (encoding/asn1), with the aim of relaxing checks for various things // that are common errors present in many X.509 certificates in the // wild. // // Main differences: // - Extra "lax" tag that recursively applies and relaxes some strict // checks: // - parsePrintableString() copes with invalid PrintableString contents, // e.g. use of tagPrintableString when the string data is really // ISO8859-1. // - checkInteger() allows integers that are not minimally encoded (and // so are not correct DER). // - parseObjectIdentifier() allows zero-length OIDs. // - Better diagnostics on which particular field causes errors. package asn1 // ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc // are different encoding formats for those objects. Here, we'll be dealing // with DER, the Distinguished Encoding Rules. DER is used in X.509 because // it's fast to parse and, unlike BER, has a unique encoding for every object. // When calculating hashes over objects, it's important that the resulting // bytes be the same at both ends and DER removes this margin of error. // // ASN.1 is very complex and this package doesn't attempt to implement // everything by any means. import ( "errors" "fmt" "math" "math/big" "reflect" "strconv" "time" "unicode/utf16" "unicode/utf8" ) // A StructuralError suggests that the ASN.1 data is valid, but the Go type // which is receiving it doesn't match. type StructuralError struct { Msg string Field string } func (e StructuralError) Error() string { var prefix string if e.Field != "" { prefix = e.Field + ": " } return "asn1: structure error: " + prefix + e.Msg } // A SyntaxError suggests that the ASN.1 data is invalid. type SyntaxError struct { Msg string Field string } func (e SyntaxError) Error() string { var prefix string if e.Field != "" { prefix = e.Field + ": " } return "asn1: syntax error: " + prefix + e.Msg } // We start by dealing with each of the primitive types in turn. // BOOLEAN func parseBool(bytes []byte, fieldName string) (ret bool, err error) { if len(bytes) != 1 { err = SyntaxError{"invalid boolean", fieldName} return } // DER demands that "If the encoding represents the boolean value TRUE, // its single contents octet shall have all eight bits set to one." // Thus only 0 and 255 are valid encoded values. switch bytes[0] { case 0: ret = false case 0xff: ret = true default: err = SyntaxError{"invalid boolean", fieldName} } return } // INTEGER // checkInteger returns nil if the given bytes are a valid DER-encoded // INTEGER and an error otherwise. func checkInteger(bytes []byte, lax bool, fieldName string) error { if len(bytes) == 0 { return StructuralError{"empty integer", fieldName} } if len(bytes) == 1 { return nil } if lax { return nil } if (bytes[0] == 0 && bytes[1]&0x80 == 0) || (bytes[0] == 0xff && bytes[1]&0x80 == 0x80) { return StructuralError{"integer not minimally-encoded", fieldName} } return nil } // parseInt64 treats the given bytes as a big-endian, signed integer and // returns the result. func parseInt64(bytes []byte, lax bool, fieldName string) (ret int64, err error) { err = checkInteger(bytes, lax, fieldName) if err != nil { return } if len(bytes) > 8 { // We'll overflow an int64 in this case. err = StructuralError{"integer too large", fieldName} return } for bytesRead := 0; bytesRead < len(bytes); bytesRead++ { ret <<= 8 ret |= int64(bytes[bytesRead]) } // Shift up and down in order to sign extend the result. ret <<= 64 - uint8(len(bytes))*8 ret >>= 64 - uint8(len(bytes))*8 return } // parseInt treats the given bytes as a big-endian, signed integer and returns // the result. func parseInt32(bytes []byte, lax bool, fieldName string) (int32, error) { if err := checkInteger(bytes, lax, fieldName); err != nil { return 0, err } ret64, err := parseInt64(bytes, lax, fieldName) if err != nil { return 0, err } if ret64 != int64(int32(ret64)) { return 0, StructuralError{"integer too large", fieldName} } return int32(ret64), nil } var bigOne = big.NewInt(1) // parseBigInt treats the given bytes as a big-endian, signed integer and returns // the result. func parseBigInt(bytes []byte, lax bool, fieldName string) (*big.Int, error) { if err := checkInteger(bytes, lax, fieldName); err != nil { return nil, err } ret := new(big.Int) if len(bytes) > 0 && bytes[0]&0x80 == 0x80 { // This is a negative number. notBytes := make([]byte, len(bytes)) for i := range notBytes { notBytes[i] = ^bytes[i] } ret.SetBytes(notBytes) ret.Add(ret, bigOne) ret.Neg(ret) return ret, nil } ret.SetBytes(bytes) return ret, nil } // BIT STRING // BitString is the structure to use when you want an ASN.1 BIT STRING type. A // bit string is padded up to the nearest byte in memory and the number of // valid bits is recorded. Padding bits will be zero. type BitString struct { Bytes []byte // bits packed into bytes. BitLength int // length in bits. } // At returns the bit at the given index. If the index is out of range it // returns false. func (b BitString) At(i int) int { if i < 0 || i >= b.BitLength { return 0 } x := i / 8 y := 7 - uint(i%8) return int(b.Bytes[x]>>y) & 1 } // RightAlign returns a slice where the padding bits are at the beginning. The // slice may share memory with the BitString. func (b BitString) RightAlign() []byte { shift := uint(8 - (b.BitLength % 8)) if shift == 8 || len(b.Bytes) == 0 { return b.Bytes } a := make([]byte, len(b.Bytes)) a[0] = b.Bytes[0] >> shift for i := 1; i < len(b.Bytes); i++ { a[i] = b.Bytes[i-1] << (8 - shift) a[i] |= b.Bytes[i] >> shift } return a } // parseBitString parses an ASN.1 bit string from the given byte slice and returns it. func parseBitString(bytes []byte, fieldName string) (ret BitString, err error) { if len(bytes) == 0 { err = SyntaxError{"zero length BIT STRING", fieldName} return } paddingBits := int(bytes[0]) if paddingBits > 7 || len(bytes) == 1 && paddingBits > 0 || bytes[len(bytes)-1]&((1< 0 { s += "." } s += strconv.Itoa(v) } return s } // parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and // returns it. An object identifier is a sequence of variable length integers // that are assigned in a hierarchy. func parseObjectIdentifier(bytes []byte, lax bool, fieldName string) (s ObjectIdentifier, err error) { if len(bytes) == 0 { if lax { return ObjectIdentifier{}, nil } err = SyntaxError{"zero length OBJECT IDENTIFIER", fieldName} return } // In the worst case, we get two elements from the first byte (which is // encoded differently) and then every varint is a single byte long. s = make([]int, len(bytes)+1) // The first varint is 40*value1 + value2: // According to this packing, value1 can take the values 0, 1 and 2 only. // When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2, // then there are no restrictions on value2. v, offset, err := parseBase128Int(bytes, 0, fieldName) if err != nil { return } if v < 80 { s[0] = v / 40 s[1] = v % 40 } else { s[0] = 2 s[1] = v - 80 } i := 2 for ; offset < len(bytes); i++ { v, offset, err = parseBase128Int(bytes, offset, fieldName) if err != nil { return } s[i] = v } s = s[0:i] return } // ENUMERATED // An Enumerated is represented as a plain int. type Enumerated int // FLAG // A Flag accepts any data and is set to true if present. type Flag bool // parseBase128Int parses a base-128 encoded int from the given offset in the // given byte slice. It returns the value and the new offset. func parseBase128Int(bytes []byte, initOffset int, fieldName string) (ret, offset int, err error) { offset = initOffset var ret64 int64 for shifted := 0; offset < len(bytes); shifted++ { // 5 * 7 bits per byte == 35 bits of data // Thus the representation is either non-minimal or too large for an int32 if shifted == 5 { err = StructuralError{"base 128 integer too large", fieldName} return } ret64 <<= 7 b := bytes[offset] ret64 |= int64(b & 0x7f) offset++ if b&0x80 == 0 { ret = int(ret64) // Ensure that the returned value fits in an int on all platforms if ret64 > math.MaxInt32 { err = StructuralError{"base 128 integer too large", fieldName} } return } } err = SyntaxError{"truncated base 128 integer", fieldName} return } // UTCTime func parseUTCTime(bytes []byte) (ret time.Time, err error) { s := string(bytes) formatStr := "0601021504Z0700" ret, err = time.Parse(formatStr, s) if err != nil { formatStr = "060102150405Z0700" ret, err = time.Parse(formatStr, s) } if err != nil { return } if serialized := ret.Format(formatStr); serialized != s { err = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", s, serialized) return } if ret.Year() >= 2050 { // UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 ret = ret.AddDate(-100, 0, 0) } return } // parseGeneralizedTime parses the GeneralizedTime from the given byte slice // and returns the resulting time. func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) { const formatStr = "20060102150405Z0700" s := string(bytes) if ret, err = time.Parse(formatStr, s); err != nil { return } if serialized := ret.Format(formatStr); serialized != s { err = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", s, serialized) } return } // NumericString // parseNumericString parses an ASN.1 NumericString from the given byte array // and returns it. func parseNumericString(bytes []byte, fieldName string) (ret string, err error) { for _, b := range bytes { if !isNumeric(b) { return "", SyntaxError{"NumericString contains invalid character", fieldName} } } return string(bytes), nil } // isNumeric reports whether the given b is in the ASN.1 NumericString set. func isNumeric(b byte) bool { return '0' <= b && b <= '9' || b == ' ' } // PrintableString // parsePrintableString parses an ASN.1 PrintableString from the given byte // array and returns it. func parsePrintableString(bytes []byte, lax bool, fieldName string) (ret string, err error) { for _, b := range bytes { if !isPrintable(b, allowAsterisk, allowAmpersand) { if !lax { err = SyntaxError{"PrintableString contains invalid character", fieldName} } else { // Might be an ISO8859-1 string stuffed in, check if it // would be valid and assume that's what's happened if so, // otherwise try T.61, failing that give up and just assign // the bytes switch { case couldBeISO8859_1(bytes): ret, err = iso8859_1ToUTF8(bytes), nil case couldBeT61(bytes): ret, err = parseT61String(bytes) default: err = SyntaxError{"PrintableString contains invalid character, couldn't determine correct String type", fieldName} } } return } } ret = string(bytes) return } type asteriskFlag bool type ampersandFlag bool const ( allowAsterisk asteriskFlag = true rejectAsterisk asteriskFlag = false allowAmpersand ampersandFlag = true rejectAmpersand ampersandFlag = false ) // isPrintable reports whether the given b is in the ASN.1 PrintableString set. // If asterisk is allowAsterisk then '*' is also allowed, reflecting existing // practice. If ampersand is allowAmpersand then '&' is allowed as well. func isPrintable(b byte, asterisk asteriskFlag, ampersand ampersandFlag) bool { return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' || '0' <= b && b <= '9' || '\'' <= b && b <= ')' || '+' <= b && b <= '/' || b == ' ' || b == ':' || b == '=' || b == '?' || // This is technically not allowed in a PrintableString. // However, x509 certificates with wildcard strings don't // always use the correct string type so we permit it. (bool(asterisk) && b == '*') || // This is not technically allowed either. However, not // only is it relatively common, but there are also a // handful of CA certificates that contain it. At least // one of which will not expire until 2027. (bool(ampersand) && b == '&') } // IA5String // parseIA5String parses an ASN.1 IA5String (ASCII string) from the given // byte slice and returns it. func parseIA5String(bytes []byte, fieldName string) (ret string, err error) { for _, b := range bytes { if b >= utf8.RuneSelf { err = SyntaxError{"IA5String contains invalid character", fieldName} return } } ret = string(bytes) return } // T61String // parseT61String parses an ASN.1 T61String (8-bit clean string) from the given // byte slice and returns it. func parseT61String(bytes []byte) (ret string, err error) { return string(bytes), nil } // UTF8String // parseUTF8String parses an ASN.1 UTF8String (raw UTF-8) from the given byte // array and returns it. func parseUTF8String(bytes []byte) (ret string, err error) { if !utf8.Valid(bytes) { return "", errors.New("asn1: invalid UTF-8 string") } return string(bytes), nil } // BMPString // parseBMPString parses an ASN.1 BMPString (Basic Multilingual Plane of // ISO/IEC/ITU 10646-1) from the given byte slice and returns it. func parseBMPString(bmpString []byte) (string, error) { if len(bmpString)%2 != 0 { return "", errors.New("pkcs12: odd-length BMP string") } // Strip terminator if present. if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 { bmpString = bmpString[:l-2] } s := make([]uint16, 0, len(bmpString)/2) for len(bmpString) > 0 { s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1])) bmpString = bmpString[2:] } return string(utf16.Decode(s)), nil } // A RawValue represents an undecoded ASN.1 object. type RawValue struct { Class, Tag int IsCompound bool Bytes []byte FullBytes []byte // includes the tag and length } // RawContent is used to signal that the undecoded, DER data needs to be // preserved for a struct. To use it, the first field of the struct must have // this type. It's an error for any of the other fields to have this type. type RawContent []byte // Tagging // parseTagAndLength parses an ASN.1 tag and length pair from the given offset // into a byte slice. It returns the parsed data and the new offset. SET and // SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we // don't distinguish between ordered and unordered objects in this code. func parseTagAndLength(bytes []byte, initOffset int, fieldName string) (ret tagAndLength, offset int, err error) { offset = initOffset // parseTagAndLength should not be called without at least a single // byte to read. Thus this check is for robustness: if offset >= len(bytes) { err = errors.New("asn1: internal error in parseTagAndLength") return } b := bytes[offset] offset++ ret.class = int(b >> 6) ret.isCompound = b&0x20 == 0x20 ret.tag = int(b & 0x1f) // If the bottom five bits are set, then the tag number is actually base 128 // encoded afterwards if ret.tag == 0x1f { ret.tag, offset, err = parseBase128Int(bytes, offset, fieldName) if err != nil { return } // Tags should be encoded in minimal form. if ret.tag < 0x1f { err = SyntaxError{"non-minimal tag", fieldName} return } } if offset >= len(bytes) { err = SyntaxError{"truncated tag or length", fieldName} return } b = bytes[offset] offset++ if b&0x80 == 0 { // The length is encoded in the bottom 7 bits. ret.length = int(b & 0x7f) } else { // Bottom 7 bits give the number of length bytes to follow. numBytes := int(b & 0x7f) if numBytes == 0 { err = SyntaxError{"indefinite length found (not DER)", fieldName} return } ret.length = 0 for i := 0; i < numBytes; i++ { if offset >= len(bytes) { err = SyntaxError{"truncated tag or length", fieldName} return } b = bytes[offset] offset++ if ret.length >= 1<<23 { // We can't shift ret.length up without // overflowing. err = StructuralError{"length too large", fieldName} return } ret.length <<= 8 ret.length |= int(b) if ret.length == 0 { // DER requires that lengths be minimal. err = StructuralError{"superfluous leading zeros in length", fieldName} return } } // Short lengths must be encoded in short form. if ret.length < 0x80 { err = StructuralError{"non-minimal length", fieldName} return } } return } // parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse // a number of ASN.1 values from the given byte slice and returns them as a // slice of Go values of the given type. func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type, lax bool, fieldName string) (ret reflect.Value, err error) { matchAny, expectedTag, compoundType, ok := getUniversalType(elemType) if !ok { err = StructuralError{"unknown Go type for slice", fieldName} return } // First we iterate over the input and count the number of elements, // checking that the types are correct in each case. numElements := 0 for offset := 0; offset < len(bytes); { var t tagAndLength t, offset, err = parseTagAndLength(bytes, offset, fieldName) if err != nil { return } switch t.tag { case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString, TagBMPString: // We pretend that various other string types are // PRINTABLE STRINGs so that a sequence of them can be // parsed into a []string. t.tag = TagPrintableString case TagGeneralizedTime, TagUTCTime: // Likewise, both time types are treated the same. t.tag = TagUTCTime } if !matchAny && (t.class != ClassUniversal || t.isCompound != compoundType || t.tag != expectedTag) { err = StructuralError{fmt.Sprintf("sequence tag mismatch (got:%+v, want:0/%d/%t)", t, expectedTag, compoundType), fieldName} return } if invalidLength(offset, t.length, len(bytes)) { err = SyntaxError{"truncated sequence", fieldName} return } offset += t.length numElements++ } ret = reflect.MakeSlice(sliceType, numElements, numElements) params := fieldParameters{lax: lax} offset := 0 for i := 0; i < numElements; i++ { offset, err = parseField(ret.Index(i), bytes, offset, params) if err != nil { return } } return } var ( bitStringType = reflect.TypeOf(BitString{}) objectIdentifierType = reflect.TypeOf(ObjectIdentifier{}) enumeratedType = reflect.TypeOf(Enumerated(0)) flagType = reflect.TypeOf(Flag(false)) timeType = reflect.TypeOf(time.Time{}) rawValueType = reflect.TypeOf(RawValue{}) rawContentsType = reflect.TypeOf(RawContent(nil)) bigIntType = reflect.TypeOf(new(big.Int)) ) // invalidLength reports whether offset + length > sliceLength, or if the // addition would overflow. func invalidLength(offset, length, sliceLength int) bool { return offset+length < offset || offset+length > sliceLength } // Tests whether the data in |bytes| would be a valid ISO8859-1 string. // Clearly, a sequence of bytes comprised solely of valid ISO8859-1 // codepoints does not imply that the encoding MUST be ISO8859-1, rather that // you would not encounter an error trying to interpret the data as such. func couldBeISO8859_1(bytes []byte) bool { for _, b := range bytes { if b < 0x20 || (b >= 0x7F && b < 0xA0) { return false } } return true } // Checks whether the data in |bytes| would be a valid T.61 string. // Clearly, a sequence of bytes comprised solely of valid T.61 // codepoints does not imply that the encoding MUST be T.61, rather that // you would not encounter an error trying to interpret the data as such. func couldBeT61(bytes []byte) bool { for _, b := range bytes { switch b { case 0x00: // Since we're guessing at (incorrect) encodings for a // PrintableString, we'll err on the side of caution and disallow // strings with a NUL in them, don't want to re-create a PayPal NUL // situation in monitors. fallthrough case 0x23, 0x24, 0x5C, 0x5E, 0x60, 0x7B, 0x7D, 0x7E, 0xA5, 0xA6, 0xAC, 0xAD, 0xAE, 0xAF, 0xB9, 0xBA, 0xC0, 0xC9, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDE, 0xDF, 0xE5, 0xFF: // These are all invalid code points in T.61, so it can't be a T.61 string. return false } } return true } // Converts the data in |bytes| to the equivalent UTF-8 string. func iso8859_1ToUTF8(bytes []byte) string { buf := make([]rune, len(bytes)) for i, b := range bytes { buf[i] = rune(b) } return string(buf) } // parseField is the main parsing function. Given a byte slice and an offset // into the array, it will try to parse a suitable ASN.1 value out and store it // in the given Value. func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err error) { offset = initOffset fieldType := v.Type() // If we have run out of data, it may be that there are optional elements at the end. if offset == len(bytes) { if !setDefaultValue(v, params) { err = SyntaxError{"sequence truncated", params.name} } return } // Deal with the ANY type. if ifaceType := fieldType; ifaceType.Kind() == reflect.Interface && ifaceType.NumMethod() == 0 { var t tagAndLength t, offset, err = parseTagAndLength(bytes, offset, params.name) if err != nil { return } if invalidLength(offset, t.length, len(bytes)) { err = SyntaxError{"data truncated", params.name} return } var result interface{} if !t.isCompound && t.class == ClassUniversal { innerBytes := bytes[offset : offset+t.length] switch t.tag { case TagPrintableString: result, err = parsePrintableString(innerBytes, params.lax, params.name) case TagNumericString: result, err = parseNumericString(innerBytes, params.name) case TagIA5String: result, err = parseIA5String(innerBytes, params.name) case TagT61String: result, err = parseT61String(innerBytes) case TagUTF8String: result, err = parseUTF8String(innerBytes) case TagInteger: result, err = parseInt64(innerBytes, params.lax, params.name) case TagBitString: result, err = parseBitString(innerBytes, params.name) case TagOID: result, err = parseObjectIdentifier(innerBytes, params.lax, params.name) case TagUTCTime: result, err = parseUTCTime(innerBytes) case TagGeneralizedTime: result, err = parseGeneralizedTime(innerBytes) case TagOctetString: result = innerBytes case TagBMPString: result, err = parseBMPString(innerBytes) default: // If we don't know how to handle the type, we just leave Value as nil. } } offset += t.length if err != nil { return } if result != nil { v.Set(reflect.ValueOf(result)) } return } t, offset, err := parseTagAndLength(bytes, offset, params.name) if err != nil { return } if params.explicit { expectedClass := ClassContextSpecific if params.application { expectedClass = ClassApplication } if offset == len(bytes) { err = StructuralError{"explicit tag has no child", params.name} return } if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) { if fieldType == rawValueType { // The inner element should not be parsed for RawValues. } else if t.length > 0 { t, offset, err = parseTagAndLength(bytes, offset, params.name) if err != nil { return } } else { if fieldType != flagType { err = StructuralError{"zero length explicit tag was not an asn1.Flag", params.name} return } v.SetBool(true) return } } else { // The tags didn't match, it might be an optional element. ok := setDefaultValue(v, params) if ok { offset = initOffset } else { err = StructuralError{"explicitly tagged member didn't match", params.name} } return } } matchAny, universalTag, compoundType, ok1 := getUniversalType(fieldType) if !ok1 { err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType), params.name} return } // Special case for strings: all the ASN.1 string types map to the Go // type string. getUniversalType returns the tag for PrintableString // when it sees a string, so if we see a different string type on the // wire, we change the universal type to match. if universalTag == TagPrintableString { if t.class == ClassUniversal { switch t.tag { case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString, TagBMPString: universalTag = t.tag } } else if params.stringType != 0 { universalTag = params.stringType } } // Special case for time: UTCTime and GeneralizedTime both map to the // Go type time.Time. if universalTag == TagUTCTime && t.tag == TagGeneralizedTime && t.class == ClassUniversal { universalTag = TagGeneralizedTime } if params.set { universalTag = TagSet } matchAnyClassAndTag := matchAny expectedClass := ClassUniversal expectedTag := universalTag if !params.explicit && params.tag != nil { expectedClass = ClassContextSpecific expectedTag = *params.tag matchAnyClassAndTag = false } if !params.explicit && params.application && params.tag != nil { expectedClass = ClassApplication expectedTag = *params.tag matchAnyClassAndTag = false } if !params.explicit && params.private && params.tag != nil { expectedClass = ClassPrivate expectedTag = *params.tag matchAnyClassAndTag = false } // We have unwrapped any explicit tagging at this point. if !matchAnyClassAndTag && (t.class != expectedClass || t.tag != expectedTag) || (!matchAny && t.isCompound != compoundType) { // Tags don't match. Again, it could be an optional element. ok := setDefaultValue(v, params) if ok { offset = initOffset } else { err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset), params.name} } return } if invalidLength(offset, t.length, len(bytes)) { err = SyntaxError{"data truncated", params.name} return } innerBytes := bytes[offset : offset+t.length] offset += t.length // We deal with the structures defined in this package first. switch fieldType { case rawValueType: result := RawValue{t.class, t.tag, t.isCompound, innerBytes, bytes[initOffset:offset]} v.Set(reflect.ValueOf(result)) return case objectIdentifierType: newSlice, err1 := parseObjectIdentifier(innerBytes, params.lax, params.name) v.Set(reflect.MakeSlice(v.Type(), len(newSlice), len(newSlice))) if err1 == nil { reflect.Copy(v, reflect.ValueOf(newSlice)) } err = err1 return case bitStringType: bs, err1 := parseBitString(innerBytes, params.name) if err1 == nil { v.Set(reflect.ValueOf(bs)) } err = err1 return case timeType: var time time.Time var err1 error if universalTag == TagUTCTime { time, err1 = parseUTCTime(innerBytes) } else { time, err1 = parseGeneralizedTime(innerBytes) } if err1 == nil { v.Set(reflect.ValueOf(time)) } err = err1 return case enumeratedType: parsedInt, err1 := parseInt32(innerBytes, params.lax, params.name) if err1 == nil { v.SetInt(int64(parsedInt)) } err = err1 return case flagType: v.SetBool(true) return case bigIntType: parsedInt, err1 := parseBigInt(innerBytes, params.lax, params.name) if err1 == nil { v.Set(reflect.ValueOf(parsedInt)) } err = err1 return } switch val := v; val.Kind() { case reflect.Bool: parsedBool, err1 := parseBool(innerBytes, params.name) if err1 == nil { val.SetBool(parsedBool) } err = err1 return case reflect.Int, reflect.Int32, reflect.Int64: if val.Type().Size() == 4 { parsedInt, err1 := parseInt32(innerBytes, params.lax, params.name) if err1 == nil { val.SetInt(int64(parsedInt)) } err = err1 } else { parsedInt, err1 := parseInt64(innerBytes, params.lax, params.name) if err1 == nil { val.SetInt(parsedInt) } err = err1 } return // TODO(dfc) Add support for the remaining integer types case reflect.Struct: structType := fieldType for i := 0; i < structType.NumField(); i++ { if structType.Field(i).PkgPath != "" { err = StructuralError{"struct contains unexported fields", structType.Field(i).Name} return } } if structType.NumField() > 0 && structType.Field(0).Type == rawContentsType { bytes := bytes[initOffset:offset] val.Field(0).Set(reflect.ValueOf(RawContent(bytes))) } innerOffset := 0 for i := 0; i < structType.NumField(); i++ { field := structType.Field(i) if i == 0 && field.Type == rawContentsType { continue } innerParams := parseFieldParameters(field.Tag.Get("asn1")) innerParams.name = field.Name innerParams.lax = params.lax innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, innerParams) if err != nil { return } } // We allow extra bytes at the end of the SEQUENCE because // adding elements to the end has been used in X.509 as the // version numbers have increased. return case reflect.Slice: sliceType := fieldType if sliceType.Elem().Kind() == reflect.Uint8 { val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes))) reflect.Copy(val, reflect.ValueOf(innerBytes)) return } newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem(), params.lax, params.name) if err1 == nil { val.Set(newSlice) } err = err1 return case reflect.String: var v string switch universalTag { case TagPrintableString: v, err = parsePrintableString(innerBytes, params.lax, params.name) case TagNumericString: v, err = parseNumericString(innerBytes, params.name) case TagIA5String: v, err = parseIA5String(innerBytes, params.name) case TagT61String: v, err = parseT61String(innerBytes) case TagUTF8String: v, err = parseUTF8String(innerBytes) case TagGeneralString: // GeneralString is specified in ISO-2022/ECMA-35, // A brief review suggests that it includes structures // that allow the encoding to change midstring and // such. We give up and pass it as an 8-bit string. v, err = parseT61String(innerBytes) case TagBMPString: v, err = parseBMPString(innerBytes) default: err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag), params.name} } if err == nil { val.SetString(v) } return } err = StructuralError{"unsupported: " + v.Type().String(), params.name} return } // canHaveDefaultValue reports whether k is a Kind that we will set a default // value for. (A signed integer, essentially.) func canHaveDefaultValue(k reflect.Kind) bool { switch k { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return true } return false } // setDefaultValue is used to install a default value, from a tag string, into // a Value. It is successful if the field was optional, even if a default value // wasn't provided or it failed to install it into the Value. func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { if !params.optional { return } ok = true if params.defaultValue == nil { return } if canHaveDefaultValue(v.Kind()) { v.SetInt(*params.defaultValue) } return } // Unmarshal parses the DER-encoded ASN.1 data structure b // and uses the reflect package to fill in an arbitrary value pointed at by val. // Because Unmarshal uses the reflect package, the structs // being written to must use upper case field names. // // An ASN.1 INTEGER can be written to an int, int32, int64, // or *big.Int (from the math/big package). // If the encoded value does not fit in the Go type, // Unmarshal returns a parse error. // // An ASN.1 BIT STRING can be written to a BitString. // // An ASN.1 OCTET STRING can be written to a []byte. // // An ASN.1 OBJECT IDENTIFIER can be written to an // ObjectIdentifier. // // An ASN.1 ENUMERATED can be written to an Enumerated. // // An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a time.Time. // // An ASN.1 PrintableString, IA5String, or NumericString can be written to a string. // // Any of the above ASN.1 values can be written to an interface{}. // The value stored in the interface has the corresponding Go type. // For integers, that type is int64. // // An ASN.1 SEQUENCE OF x or SET OF x can be written // to a slice if an x can be written to the slice's element type. // // An ASN.1 SEQUENCE or SET can be written to a struct // if each of the elements in the sequence can be // written to the corresponding element in the struct. // // The following tags on struct fields have special meaning to Unmarshal: // // application specifies that an APPLICATION tag is used // private specifies that a PRIVATE tag is used // default:x sets the default value for optional integer fields (only used if optional is also present) // explicit specifies that an additional, explicit tag wraps the implicit one // optional marks the field as ASN.1 OPTIONAL // set causes a SET, rather than a SEQUENCE type to be expected // tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC // lax relax strict encoding checks for this field, and for any fields within it // // If the type of the first field of a structure is RawContent then the raw // ASN1 contents of the struct will be stored in it. // // If the type name of a slice element ends with "SET" then it's treated as if // the "set" tag was set on it. This can be used with nested slices where a // struct tag cannot be given. // // Other ASN.1 types are not supported; if it encounters them, // Unmarshal returns a parse error. func Unmarshal(b []byte, val interface{}) (rest []byte, err error) { return UnmarshalWithParams(b, val, "") } // UnmarshalWithParams allows field parameters to be specified for the // top-level element. The form of the params is the same as the field tags. func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err error) { v := reflect.ValueOf(val).Elem() offset, err := parseField(v, b, 0, parseFieldParameters(params)) if err != nil { return nil, err } return b[offset:], nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/asn1/common.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package asn1 import ( "reflect" "strconv" "strings" ) // ASN.1 objects have metadata preceding them: // the tag: the type of the object // a flag denoting if this object is compound or not // the class type: the namespace of the tag // the length of the object, in bytes // Here are some standard tags and classes // ASN.1 tags represent the type of the following object. const ( TagBoolean = 1 TagInteger = 2 TagBitString = 3 TagOctetString = 4 TagNull = 5 TagOID = 6 TagEnum = 10 TagUTF8String = 12 TagSequence = 16 TagSet = 17 TagNumericString = 18 TagPrintableString = 19 TagT61String = 20 TagIA5String = 22 TagUTCTime = 23 TagGeneralizedTime = 24 TagGeneralString = 27 TagBMPString = 30 ) // ASN.1 class types represent the namespace of the tag. const ( ClassUniversal = 0 ClassApplication = 1 ClassContextSpecific = 2 ClassPrivate = 3 ) type tagAndLength struct { class, tag, length int isCompound bool } // ASN.1 has IMPLICIT and EXPLICIT tags, which can be translated as "instead // of" and "in addition to". When not specified, every primitive type has a // default tag in the UNIVERSAL class. // // For example: a BIT STRING is tagged [UNIVERSAL 3] by default (although ASN.1 // doesn't actually have a UNIVERSAL keyword). However, by saying [IMPLICIT // CONTEXT-SPECIFIC 42], that means that the tag is replaced by another. // // On the other hand, if it said [EXPLICIT CONTEXT-SPECIFIC 10], then an // /additional/ tag would wrap the default tag. This explicit tag will have the // compound flag set. // // (This is used in order to remove ambiguity with optional elements.) // // You can layer EXPLICIT and IMPLICIT tags to an arbitrary depth, however we // don't support that here. We support a single layer of EXPLICIT or IMPLICIT // tagging with tag strings on the fields of a structure. // fieldParameters is the parsed representation of tag string from a structure field. type fieldParameters struct { optional bool // true iff the field is OPTIONAL explicit bool // true iff an EXPLICIT tag is in use. application bool // true iff an APPLICATION tag is in use. private bool // true iff a PRIVATE tag is in use. defaultValue *int64 // a default value for INTEGER typed fields (maybe nil). tag *int // the EXPLICIT or IMPLICIT tag (maybe nil). stringType int // the string tag to use when marshaling. timeType int // the time tag to use when marshaling. set bool // true iff this should be encoded as a SET omitEmpty bool // true iff this should be omitted if empty when marshaling. lax bool // true iff unmarshalling should skip some error checks name string // name of field for better diagnostics // Invariants: // if explicit is set, tag is non-nil. } // Given a tag string with the format specified in the package comment, // parseFieldParameters will parse it into a fieldParameters structure, // ignoring unknown parts of the string. func parseFieldParameters(str string) (ret fieldParameters) { for _, part := range strings.Split(str, ",") { switch { case part == "optional": ret.optional = true case part == "explicit": ret.explicit = true if ret.tag == nil { ret.tag = new(int) } case part == "generalized": ret.timeType = TagGeneralizedTime case part == "utc": ret.timeType = TagUTCTime case part == "ia5": ret.stringType = TagIA5String case part == "printable": ret.stringType = TagPrintableString case part == "numeric": ret.stringType = TagNumericString case part == "utf8": ret.stringType = TagUTF8String case strings.HasPrefix(part, "default:"): i, err := strconv.ParseInt(part[8:], 10, 64) if err == nil { ret.defaultValue = new(int64) *ret.defaultValue = i } case strings.HasPrefix(part, "tag:"): i, err := strconv.Atoi(part[4:]) if err == nil { ret.tag = new(int) *ret.tag = i } case part == "set": ret.set = true case part == "application": ret.application = true if ret.tag == nil { ret.tag = new(int) } case part == "private": ret.private = true if ret.tag == nil { ret.tag = new(int) } case part == "omitempty": ret.omitEmpty = true case part == "lax": ret.lax = true } } return } // Given a reflected Go type, getUniversalType returns the default tag number // and expected compound flag. func getUniversalType(t reflect.Type) (matchAny bool, tagNumber int, isCompound, ok bool) { switch t { case rawValueType: return true, -1, false, true case objectIdentifierType: return false, TagOID, false, true case bitStringType: return false, TagBitString, false, true case timeType: return false, TagUTCTime, false, true case enumeratedType: return false, TagEnum, false, true case bigIntType: return false, TagInteger, false, true } switch t.Kind() { case reflect.Bool: return false, TagBoolean, false, true case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return false, TagInteger, false, true case reflect.Struct: return false, TagSequence, true, true case reflect.Slice: if t.Elem().Kind() == reflect.Uint8 { return false, TagOctetString, false, true } if strings.HasSuffix(t.Name(), "SET") { return false, TagSet, true, true } return false, TagSequence, true, true case reflect.String: return false, TagPrintableString, false, true } return false, 0, false, false } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/asn1/marshal.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package asn1 import ( "errors" "fmt" "math/big" "reflect" "time" "unicode/utf8" ) var ( byte00Encoder encoder = byteEncoder(0x00) byteFFEncoder encoder = byteEncoder(0xff) ) // encoder represents an ASN.1 element that is waiting to be marshaled. type encoder interface { // Len returns the number of bytes needed to marshal this element. Len() int // Encode encodes this element by writing Len() bytes to dst. Encode(dst []byte) } type byteEncoder byte func (c byteEncoder) Len() int { return 1 } func (c byteEncoder) Encode(dst []byte) { dst[0] = byte(c) } type bytesEncoder []byte func (b bytesEncoder) Len() int { return len(b) } func (b bytesEncoder) Encode(dst []byte) { if copy(dst, b) != len(b) { panic("internal error") } } type stringEncoder string func (s stringEncoder) Len() int { return len(s) } func (s stringEncoder) Encode(dst []byte) { if copy(dst, s) != len(s) { panic("internal error") } } type multiEncoder []encoder func (m multiEncoder) Len() int { var size int for _, e := range m { size += e.Len() } return size } func (m multiEncoder) Encode(dst []byte) { var off int for _, e := range m { e.Encode(dst[off:]) off += e.Len() } } type taggedEncoder struct { // scratch contains temporary space for encoding the tag and length of // an element in order to avoid extra allocations. scratch [8]byte tag encoder body encoder } func (t *taggedEncoder) Len() int { return t.tag.Len() + t.body.Len() } func (t *taggedEncoder) Encode(dst []byte) { t.tag.Encode(dst) t.body.Encode(dst[t.tag.Len():]) } type int64Encoder int64 func (i int64Encoder) Len() int { n := 1 for i > 127 { n++ i >>= 8 } for i < -128 { n++ i >>= 8 } return n } func (i int64Encoder) Encode(dst []byte) { n := i.Len() for j := 0; j < n; j++ { dst[j] = byte(i >> uint((n-1-j)*8)) } } func base128IntLength(n int64) int { if n == 0 { return 1 } l := 0 for i := n; i > 0; i >>= 7 { l++ } return l } func appendBase128Int(dst []byte, n int64) []byte { l := base128IntLength(n) for i := l - 1; i >= 0; i-- { o := byte(n >> uint(i*7)) o &= 0x7f if i != 0 { o |= 0x80 } dst = append(dst, o) } return dst } func makeBigInt(n *big.Int, fieldName string) (encoder, error) { if n == nil { return nil, StructuralError{"empty integer", fieldName} } if n.Sign() < 0 { // A negative number has to be converted to two's-complement // form. So we'll invert and subtract 1. If the // most-significant-bit isn't set then we'll need to pad the // beginning with 0xff in order to keep the number negative. nMinus1 := new(big.Int).Neg(n) nMinus1.Sub(nMinus1, bigOne) bytes := nMinus1.Bytes() for i := range bytes { bytes[i] ^= 0xff } if len(bytes) == 0 || bytes[0]&0x80 == 0 { return multiEncoder([]encoder{byteFFEncoder, bytesEncoder(bytes)}), nil } return bytesEncoder(bytes), nil } else if n.Sign() == 0 { // Zero is written as a single 0 zero rather than no bytes. return byte00Encoder, nil } else { bytes := n.Bytes() if len(bytes) > 0 && bytes[0]&0x80 != 0 { // We'll have to pad this with 0x00 in order to stop it // looking like a negative number. return multiEncoder([]encoder{byte00Encoder, bytesEncoder(bytes)}), nil } return bytesEncoder(bytes), nil } } func appendLength(dst []byte, i int) []byte { n := lengthLength(i) for ; n > 0; n-- { dst = append(dst, byte(i>>uint((n-1)*8))) } return dst } func lengthLength(i int) (numBytes int) { numBytes = 1 for i > 255 { numBytes++ i >>= 8 } return } func appendTagAndLength(dst []byte, t tagAndLength) []byte { b := uint8(t.class) << 6 if t.isCompound { b |= 0x20 } if t.tag >= 31 { b |= 0x1f dst = append(dst, b) dst = appendBase128Int(dst, int64(t.tag)) } else { b |= uint8(t.tag) dst = append(dst, b) } if t.length >= 128 { l := lengthLength(t.length) dst = append(dst, 0x80|byte(l)) dst = appendLength(dst, t.length) } else { dst = append(dst, byte(t.length)) } return dst } type bitStringEncoder BitString func (b bitStringEncoder) Len() int { return len(b.Bytes) + 1 } func (b bitStringEncoder) Encode(dst []byte) { dst[0] = byte((8 - b.BitLength%8) % 8) if copy(dst[1:], b.Bytes) != len(b.Bytes) { panic("internal error") } } type oidEncoder []int func (oid oidEncoder) Len() int { l := base128IntLength(int64(oid[0]*40 + oid[1])) for i := 2; i < len(oid); i++ { l += base128IntLength(int64(oid[i])) } return l } func (oid oidEncoder) Encode(dst []byte) { dst = appendBase128Int(dst[:0], int64(oid[0]*40+oid[1])) for i := 2; i < len(oid); i++ { dst = appendBase128Int(dst, int64(oid[i])) } } func makeObjectIdentifier(oid []int, fieldName string) (e encoder, err error) { if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) { return nil, StructuralError{"invalid object identifier", fieldName} } return oidEncoder(oid), nil } func makePrintableString(s, fieldName string) (e encoder, err error) { for i := 0; i < len(s); i++ { // The asterisk is often used in PrintableString, even though // it is invalid. If a PrintableString was specifically // requested then the asterisk is permitted by this code. // Ampersand is allowed in parsing due a handful of CA // certificates, however when making new certificates // it is rejected. if !isPrintable(s[i], allowAsterisk, rejectAmpersand) { return nil, StructuralError{"PrintableString contains invalid character", fieldName} } } return stringEncoder(s), nil } func makeIA5String(s, fieldName string) (e encoder, err error) { for i := 0; i < len(s); i++ { if s[i] > 127 { return nil, StructuralError{"IA5String contains invalid character", fieldName} } } return stringEncoder(s), nil } func makeNumericString(s string, fieldName string) (e encoder, err error) { for i := 0; i < len(s); i++ { if !isNumeric(s[i]) { return nil, StructuralError{"NumericString contains invalid character", fieldName} } } return stringEncoder(s), nil } func makeUTF8String(s string) encoder { return stringEncoder(s) } func appendTwoDigits(dst []byte, v int) []byte { return append(dst, byte('0'+(v/10)%10), byte('0'+v%10)) } func appendFourDigits(dst []byte, v int) []byte { var bytes [4]byte for i := range bytes { bytes[3-i] = '0' + byte(v%10) v /= 10 } return append(dst, bytes[:]...) } func outsideUTCRange(t time.Time) bool { year := t.Year() return year < 1950 || year >= 2050 } func makeUTCTime(t time.Time, fieldName string) (e encoder, err error) { dst := make([]byte, 0, 18) dst, err = appendUTCTime(dst, t, fieldName) if err != nil { return nil, err } return bytesEncoder(dst), nil } func makeGeneralizedTime(t time.Time, fieldName string) (e encoder, err error) { dst := make([]byte, 0, 20) dst, err = appendGeneralizedTime(dst, t, fieldName) if err != nil { return nil, err } return bytesEncoder(dst), nil } func appendUTCTime(dst []byte, t time.Time, fieldName string) (ret []byte, err error) { year := t.Year() switch { case 1950 <= year && year < 2000: dst = appendTwoDigits(dst, year-1900) case 2000 <= year && year < 2050: dst = appendTwoDigits(dst, year-2000) default: return nil, StructuralError{"cannot represent time as UTCTime", fieldName} } return appendTimeCommon(dst, t), nil } func appendGeneralizedTime(dst []byte, t time.Time, fieldName string) (ret []byte, err error) { year := t.Year() if year < 0 || year > 9999 { return nil, StructuralError{"cannot represent time as GeneralizedTime", fieldName} } dst = appendFourDigits(dst, year) return appendTimeCommon(dst, t), nil } func appendTimeCommon(dst []byte, t time.Time) []byte { _, month, day := t.Date() dst = appendTwoDigits(dst, int(month)) dst = appendTwoDigits(dst, day) hour, min, sec := t.Clock() dst = appendTwoDigits(dst, hour) dst = appendTwoDigits(dst, min) dst = appendTwoDigits(dst, sec) _, offset := t.Zone() switch { case offset/60 == 0: return append(dst, 'Z') case offset > 0: dst = append(dst, '+') case offset < 0: dst = append(dst, '-') } offsetMinutes := offset / 60 if offsetMinutes < 0 { offsetMinutes = -offsetMinutes } dst = appendTwoDigits(dst, offsetMinutes/60) dst = appendTwoDigits(dst, offsetMinutes%60) return dst } func stripTagAndLength(in []byte) []byte { _, offset, err := parseTagAndLength(in, 0, "") if err != nil { return in } return in[offset:] } func makeBody(value reflect.Value, params fieldParameters) (e encoder, err error) { switch value.Type() { case flagType: return bytesEncoder(nil), nil case timeType: t := value.Interface().(time.Time) if params.timeType == TagGeneralizedTime || outsideUTCRange(t) { return makeGeneralizedTime(t, params.name) } return makeUTCTime(t, params.name) case bitStringType: return bitStringEncoder(value.Interface().(BitString)), nil case objectIdentifierType: return makeObjectIdentifier(value.Interface().(ObjectIdentifier), params.name) case bigIntType: return makeBigInt(value.Interface().(*big.Int), params.name) } switch v := value; v.Kind() { case reflect.Bool: if v.Bool() { return byteFFEncoder, nil } return byte00Encoder, nil case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return int64Encoder(v.Int()), nil case reflect.Struct: t := v.Type() for i := 0; i < t.NumField(); i++ { if t.Field(i).PkgPath != "" { return nil, StructuralError{"struct contains unexported fields", t.Field(i).Name} } } startingField := 0 n := t.NumField() if n == 0 { return bytesEncoder(nil), nil } // If the first element of the structure is a non-empty // RawContents, then we don't bother serializing the rest. if t.Field(0).Type == rawContentsType { s := v.Field(0) if s.Len() > 0 { bytes := s.Bytes() /* The RawContents will contain the tag and * length fields but we'll also be writing * those ourselves, so we strip them out of * bytes */ return bytesEncoder(stripTagAndLength(bytes)), nil } startingField = 1 } switch n1 := n - startingField; n1 { case 0: return bytesEncoder(nil), nil case 1: return makeField(v.Field(startingField), parseFieldParameters(t.Field(startingField).Tag.Get("asn1"))) default: m := make([]encoder, n1) for i := 0; i < n1; i++ { m[i], err = makeField(v.Field(i+startingField), parseFieldParameters(t.Field(i+startingField).Tag.Get("asn1"))) if err != nil { return nil, err } } return multiEncoder(m), nil } case reflect.Slice: sliceType := v.Type() if sliceType.Elem().Kind() == reflect.Uint8 { return bytesEncoder(v.Bytes()), nil } var fp fieldParameters switch l := v.Len(); l { case 0: return bytesEncoder(nil), nil case 1: return makeField(v.Index(0), fp) default: m := make([]encoder, l) for i := 0; i < l; i++ { m[i], err = makeField(v.Index(i), fp) if err != nil { return nil, err } } return multiEncoder(m), nil } case reflect.String: switch params.stringType { case TagIA5String: return makeIA5String(v.String(), params.name) case TagPrintableString: return makePrintableString(v.String(), params.name) case TagNumericString: return makeNumericString(v.String(), params.name) default: return makeUTF8String(v.String()), nil } } return nil, StructuralError{"unknown Go type", params.name} } func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) { if !v.IsValid() { return nil, fmt.Errorf("asn1: cannot marshal nil value") } // If the field is an interface{} then recurse into it. if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 { return makeField(v.Elem(), params) } if v.Kind() == reflect.Slice && v.Len() == 0 && params.omitEmpty { return bytesEncoder(nil), nil } if params.optional && params.defaultValue != nil && canHaveDefaultValue(v.Kind()) { defaultValue := reflect.New(v.Type()).Elem() defaultValue.SetInt(*params.defaultValue) if reflect.DeepEqual(v.Interface(), defaultValue.Interface()) { return bytesEncoder(nil), nil } } // If no default value is given then the zero value for the type is // assumed to be the default value. This isn't obviously the correct // behavior, but it's what Go has traditionally done. if params.optional && params.defaultValue == nil { if reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) { return bytesEncoder(nil), nil } } if v.Type() == rawValueType { rv := v.Interface().(RawValue) if len(rv.FullBytes) != 0 { return bytesEncoder(rv.FullBytes), nil } t := new(taggedEncoder) t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})) t.body = bytesEncoder(rv.Bytes) return t, nil } matchAny, tag, isCompound, ok := getUniversalType(v.Type()) if !ok || matchAny { return nil, StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type()), params.name} } if params.timeType != 0 && tag != TagUTCTime { return nil, StructuralError{"explicit time type given to non-time member", params.name} } if params.stringType != 0 && tag != TagPrintableString { return nil, StructuralError{"explicit string type given to non-string member", params.name} } switch tag { case TagPrintableString: if params.stringType == 0 { // This is a string without an explicit string type. We'll use // a PrintableString if the character set in the string is // sufficiently limited, otherwise we'll use a UTF8String. for _, r := range v.String() { if r >= utf8.RuneSelf || !isPrintable(byte(r), rejectAsterisk, rejectAmpersand) { if !utf8.ValidString(v.String()) { return nil, errors.New("asn1: string not valid UTF-8") } tag = TagUTF8String break } } } else { tag = params.stringType } case TagUTCTime: if params.timeType == TagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) { tag = TagGeneralizedTime } } if params.set { if tag != TagSequence { return nil, StructuralError{"non sequence tagged as set", params.name} } tag = TagSet } t := new(taggedEncoder) t.body, err = makeBody(v, params) if err != nil { return nil, err } bodyLen := t.body.Len() class := ClassUniversal if params.tag != nil { if params.application { class = ClassApplication } else if params.private { class = ClassPrivate } else { class = ClassContextSpecific } if params.explicit { t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{ClassUniversal, tag, bodyLen, isCompound})) tt := new(taggedEncoder) tt.body = t tt.tag = bytesEncoder(appendTagAndLength(tt.scratch[:0], tagAndLength{ class: class, tag: *params.tag, length: bodyLen + t.tag.Len(), isCompound: true, })) return tt, nil } // implicit tag. tag = *params.tag } t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound})) return t, nil } // Marshal returns the ASN.1 encoding of val. // // In addition to the struct tags recognised by Unmarshal, the following can be // used: // // ia5: causes strings to be marshaled as ASN.1, IA5String values // omitempty: causes empty slices to be skipped // printable: causes strings to be marshaled as ASN.1, PrintableString values // utf8: causes strings to be marshaled as ASN.1, UTF8String values // utc: causes time.Time to be marshaled as ASN.1, UTCTime values // generalized: causes time.Time to be marshaled as ASN.1, GeneralizedTime values func Marshal(val interface{}) ([]byte, error) { return MarshalWithParams(val, "") } // MarshalWithParams allows field parameters to be specified for the // top-level element. The form of the params is the same as the field tags. func MarshalWithParams(val interface{}, params string) ([]byte, error) { e, err := makeField(reflect.ValueOf(val), parseFieldParameters(params)) if err != nil { return nil, err } b := make([]byte, e.Len()) e.Encode(b) return b, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/client/configpb/multilog.pb.go ================================================ // Copyright 2017 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 // protoc v3.20.1 // source: client/configpb/multilog.proto package configpb import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // TemporalLogConfig is a set of LogShardConfig messages, whose // time limits should be contiguous. type TemporalLogConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Shard []*LogShardConfig `protobuf:"bytes,1,rep,name=shard,proto3" json:"shard,omitempty"` } func (x *TemporalLogConfig) Reset() { *x = TemporalLogConfig{} if protoimpl.UnsafeEnabled { mi := &file_client_configpb_multilog_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *TemporalLogConfig) String() string { return protoimpl.X.MessageStringOf(x) } func (*TemporalLogConfig) ProtoMessage() {} func (x *TemporalLogConfig) ProtoReflect() protoreflect.Message { mi := &file_client_configpb_multilog_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use TemporalLogConfig.ProtoReflect.Descriptor instead. func (*TemporalLogConfig) Descriptor() ([]byte, []int) { return file_client_configpb_multilog_proto_rawDescGZIP(), []int{0} } func (x *TemporalLogConfig) GetShard() []*LogShardConfig { if x != nil { return x.Shard } return nil } // LogShardConfig describes the acceptable date range for a single shard of a temporal // log. type LogShardConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"` // The log's public key in DER-encoded PKIX form. PublicKeyDer []byte `protobuf:"bytes,2,opt,name=public_key_der,json=publicKeyDer,proto3" json:"public_key_der,omitempty"` // not_after_start defines the start of the range of acceptable NotAfter // values, inclusive. // Leaving this unset implies no lower bound to the range. NotAfterStart *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=not_after_start,json=notAfterStart,proto3" json:"not_after_start,omitempty"` // not_after_limit defines the end of the range of acceptable NotAfter values, // exclusive. // Leaving this unset implies no upper bound to the range. NotAfterLimit *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=not_after_limit,json=notAfterLimit,proto3" json:"not_after_limit,omitempty"` } func (x *LogShardConfig) Reset() { *x = LogShardConfig{} if protoimpl.UnsafeEnabled { mi := &file_client_configpb_multilog_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *LogShardConfig) String() string { return protoimpl.X.MessageStringOf(x) } func (*LogShardConfig) ProtoMessage() {} func (x *LogShardConfig) ProtoReflect() protoreflect.Message { mi := &file_client_configpb_multilog_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use LogShardConfig.ProtoReflect.Descriptor instead. func (*LogShardConfig) Descriptor() ([]byte, []int) { return file_client_configpb_multilog_proto_rawDescGZIP(), []int{1} } func (x *LogShardConfig) GetUri() string { if x != nil { return x.Uri } return "" } func (x *LogShardConfig) GetPublicKeyDer() []byte { if x != nil { return x.PublicKeyDer } return nil } func (x *LogShardConfig) GetNotAfterStart() *timestamppb.Timestamp { if x != nil { return x.NotAfterStart } return nil } func (x *LogShardConfig) GetNotAfterLimit() *timestamppb.Timestamp { if x != nil { return x.NotAfterLimit } return nil } var File_client_configpb_multilog_proto protoreflect.FileDescriptor var file_client_configpb_multilog_proto_rawDesc = []byte{ 0x0a, 0x1e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, 0x62, 0x2f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, 0x62, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x43, 0x0a, 0x11, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x67, 0x53, 0x68, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x22, 0xd0, 0x01, 0x0a, 0x0e, 0x4c, 0x6f, 0x67, 0x53, 0x68, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x6e, 0x6f, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x42, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x6e, 0x6f, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x6c, 0x6f, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_client_configpb_multilog_proto_rawDescOnce sync.Once file_client_configpb_multilog_proto_rawDescData = file_client_configpb_multilog_proto_rawDesc ) func file_client_configpb_multilog_proto_rawDescGZIP() []byte { file_client_configpb_multilog_proto_rawDescOnce.Do(func() { file_client_configpb_multilog_proto_rawDescData = protoimpl.X.CompressGZIP(file_client_configpb_multilog_proto_rawDescData) }) return file_client_configpb_multilog_proto_rawDescData } var file_client_configpb_multilog_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_client_configpb_multilog_proto_goTypes = []interface{}{ (*TemporalLogConfig)(nil), // 0: configpb.TemporalLogConfig (*LogShardConfig)(nil), // 1: configpb.LogShardConfig (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp } var file_client_configpb_multilog_proto_depIdxs = []int32{ 1, // 0: configpb.TemporalLogConfig.shard:type_name -> configpb.LogShardConfig 2, // 1: configpb.LogShardConfig.not_after_start:type_name -> google.protobuf.Timestamp 2, // 2: configpb.LogShardConfig.not_after_limit:type_name -> google.protobuf.Timestamp 3, // [3:3] is the sub-list for method output_type 3, // [3:3] is the sub-list for method input_type 3, // [3:3] is the sub-list for extension type_name 3, // [3:3] is the sub-list for extension extendee 0, // [0:3] is the sub-list for field type_name } func init() { file_client_configpb_multilog_proto_init() } func file_client_configpb_multilog_proto_init() { if File_client_configpb_multilog_proto != nil { return } if !protoimpl.UnsafeEnabled { file_client_configpb_multilog_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TemporalLogConfig); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_client_configpb_multilog_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*LogShardConfig); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_client_configpb_multilog_proto_rawDesc, NumEnums: 0, NumMessages: 2, NumExtensions: 0, NumServices: 0, }, GoTypes: file_client_configpb_multilog_proto_goTypes, DependencyIndexes: file_client_configpb_multilog_proto_depIdxs, MessageInfos: file_client_configpb_multilog_proto_msgTypes, }.Build() File_client_configpb_multilog_proto = out.File file_client_configpb_multilog_proto_rawDesc = nil file_client_configpb_multilog_proto_goTypes = nil file_client_configpb_multilog_proto_depIdxs = nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/client/configpb/multilog.proto ================================================ // Copyright 2017 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. syntax = "proto3"; package configpb; option go_package = "github.com/google/certificate-transparency-go/client/multilog/configpb"; import "google/protobuf/timestamp.proto"; // TemporalLogConfig is a set of LogShardConfig messages, whose // time limits should be contiguous. message TemporalLogConfig { repeated LogShardConfig shard = 1; } // LogShardConfig describes the acceptable date range for a single shard of a temporal // log. message LogShardConfig { string uri = 1; // The log's public key in DER-encoded PKIX form. bytes public_key_der = 2; // not_after_start defines the start of the range of acceptable NotAfter // values, inclusive. // Leaving this unset implies no lower bound to the range. google.protobuf.Timestamp not_after_start = 3; // not_after_limit defines the end of the range of acceptable NotAfter values, // exclusive. // Leaving this unset implies no upper bound to the range. google.protobuf.Timestamp not_after_limit = 4; } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/client/getentries.go ================================================ // Copyright 2016 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package client import ( "context" "errors" "strconv" ct "github.com/google/certificate-transparency-go" "github.com/google/certificate-transparency-go/x509" ) // GetRawEntries exposes the /ct/v1/get-entries result with only the JSON parsing done. func (c *LogClient) GetRawEntries(ctx context.Context, start, end int64) (*ct.GetEntriesResponse, error) { if end < 0 { return nil, errors.New("end should be >= 0") } if end < start { return nil, errors.New("start should be <= end") } params := map[string]string{ "start": strconv.FormatInt(start, 10), "end": strconv.FormatInt(end, 10), } var resp ct.GetEntriesResponse if _, _, err := c.GetAndParse(ctx, ct.GetEntriesPath, params, &resp); err != nil { return nil, err } return &resp, nil } // GetEntries attempts to retrieve the entries in the sequence [start, end] from the CT log server // (RFC6962 s4.6) as parsed [pre-]certificates for convenience, held in a slice of ct.LogEntry structures. // However, this does mean that any certificate parsing failures will cause a failure of the whole // retrieval operation; for more robust retrieval of parsed certificates, use GetRawEntries() and invoke // ct.LogEntryFromLeaf() on each individual entry. func (c *LogClient) GetEntries(ctx context.Context, start, end int64) ([]ct.LogEntry, error) { resp, err := c.GetRawEntries(ctx, start, end) if err != nil { return nil, err } entries := make([]ct.LogEntry, len(resp.Entries)) for i, entry := range resp.Entries { index := start + int64(i) logEntry, err := ct.LogEntryFromLeaf(index, &entry) if x509.IsFatal(err) { return nil, err } entries[i] = *logEntry } return entries, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/client/logclient.go ================================================ // Copyright 2014 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package client is a CT log client implementation and contains types and code // for interacting with RFC6962-compliant CT Log instances. // See http://tools.ietf.org/html/rfc6962 for details package client import ( "context" "encoding/base64" "fmt" "net/http" "strconv" ct "github.com/google/certificate-transparency-go" "github.com/google/certificate-transparency-go/jsonclient" "github.com/google/certificate-transparency-go/tls" ) // LogClient represents a client for a given CT Log instance type LogClient struct { jsonclient.JSONClient } // CheckLogClient is an interface that allows (just) checking of various log contents. type CheckLogClient interface { BaseURI() string GetSTH(context.Context) (*ct.SignedTreeHead, error) GetSTHConsistency(ctx context.Context, first, second uint64) ([][]byte, error) GetProofByHash(ctx context.Context, hash []byte, treeSize uint64) (*ct.GetProofByHashResponse, error) } // New constructs a new LogClient instance. // |uri| is the base URI of the CT log instance to interact with, e.g. // https://ct.googleapis.com/pilot // |hc| is the underlying client to be used for HTTP requests to the CT log. // |opts| can be used to provide a custom logger interface and a public key // for signature verification. func New(uri string, hc *http.Client, opts jsonclient.Options) (*LogClient, error) { logClient, err := jsonclient.New(uri, hc, opts) if err != nil { return nil, err } return &LogClient{*logClient}, err } // RspError represents a server error including HTTP information. type RspError = jsonclient.RspError // Attempts to add |chain| to the log, using the api end-point specified by // |path|. If provided context expires before submission is complete an // error will be returned. func (c *LogClient) addChainWithRetry(ctx context.Context, ctype ct.LogEntryType, path string, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) { var resp ct.AddChainResponse var req ct.AddChainRequest for _, link := range chain { req.Chain = append(req.Chain, link.Data) } httpRsp, body, err := c.PostAndParseWithRetry(ctx, path, &req, &resp) if err != nil { return nil, err } var ds ct.DigitallySigned if rest, err := tls.Unmarshal(resp.Signature, &ds); err != nil { return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body} } else if len(rest) > 0 { return nil, RspError{ Err: fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest)), StatusCode: httpRsp.StatusCode, Body: body, } } exts, err := base64.StdEncoding.DecodeString(resp.Extensions) if err != nil { return nil, RspError{ Err: fmt.Errorf("invalid base64 data in Extensions (%q): %v", resp.Extensions, err), StatusCode: httpRsp.StatusCode, Body: body, } } var logID ct.LogID copy(logID.KeyID[:], resp.ID) sct := &ct.SignedCertificateTimestamp{ SCTVersion: resp.SCTVersion, LogID: logID, Timestamp: resp.Timestamp, Extensions: ct.CTExtensions(exts), Signature: ds, } if err := c.VerifySCTSignature(*sct, ctype, chain); err != nil { return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body} } return sct, nil } // AddChain adds the (DER represented) X509 |chain| to the log. func (c *LogClient) AddChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) { return c.addChainWithRetry(ctx, ct.X509LogEntryType, ct.AddChainPath, chain) } // AddPreChain adds the (DER represented) Precertificate |chain| to the log. func (c *LogClient) AddPreChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) { return c.addChainWithRetry(ctx, ct.PrecertLogEntryType, ct.AddPreChainPath, chain) } // GetSTH retrieves the current STH from the log. // Returns a populated SignedTreeHead, or a non-nil error (which may be of type // RspError if a raw http.Response is available). func (c *LogClient) GetSTH(ctx context.Context) (*ct.SignedTreeHead, error) { var resp ct.GetSTHResponse httpRsp, body, err := c.GetAndParse(ctx, ct.GetSTHPath, nil, &resp) if err != nil { return nil, err } sth, err := resp.ToSignedTreeHead() if err != nil { return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body} } if err := c.VerifySTHSignature(*sth); err != nil { return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body} } return sth, nil } // VerifySTHSignature checks the signature in sth, returning any error encountered or nil if verification is // successful. func (c *LogClient) VerifySTHSignature(sth ct.SignedTreeHead) error { if c.Verifier == nil { // Can't verify signatures without a verifier return nil } return c.Verifier.VerifySTHSignature(sth) } // VerifySCTSignature checks the signature in sct for the given LogEntryType, with associated certificate chain. func (c *LogClient) VerifySCTSignature(sct ct.SignedCertificateTimestamp, ctype ct.LogEntryType, certData []ct.ASN1Cert) error { if c.Verifier == nil { // Can't verify signatures without a verifier return nil } leaf, err := ct.MerkleTreeLeafFromRawChain(certData, ctype, sct.Timestamp) if err != nil { return fmt.Errorf("failed to build MerkleTreeLeaf: %v", err) } entry := ct.LogEntry{Leaf: *leaf} return c.Verifier.VerifySCTSignature(sct, entry) } // GetSTHConsistency retrieves the consistency proof between two snapshots. func (c *LogClient) GetSTHConsistency(ctx context.Context, first, second uint64) ([][]byte, error) { base10 := 10 params := map[string]string{ "first": strconv.FormatUint(first, base10), "second": strconv.FormatUint(second, base10), } var resp ct.GetSTHConsistencyResponse if _, _, err := c.GetAndParse(ctx, ct.GetSTHConsistencyPath, params, &resp); err != nil { return nil, err } return resp.Consistency, nil } // GetProofByHash returns an audit path for the hash of an SCT. func (c *LogClient) GetProofByHash(ctx context.Context, hash []byte, treeSize uint64) (*ct.GetProofByHashResponse, error) { b64Hash := base64.StdEncoding.EncodeToString(hash) base10 := 10 params := map[string]string{ "tree_size": strconv.FormatUint(treeSize, base10), "hash": b64Hash, } var resp ct.GetProofByHashResponse if _, _, err := c.GetAndParse(ctx, ct.GetProofByHashPath, params, &resp); err != nil { return nil, err } return &resp, nil } // GetAcceptedRoots retrieves the set of acceptable root certificates for a log. func (c *LogClient) GetAcceptedRoots(ctx context.Context) ([]ct.ASN1Cert, error) { var resp ct.GetRootsResponse httpRsp, body, err := c.GetAndParse(ctx, ct.GetRootsPath, nil, &resp) if err != nil { return nil, err } var roots []ct.ASN1Cert for _, cert64 := range resp.Certificates { cert, err := base64.StdEncoding.DecodeString(cert64) if err != nil { return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body} } roots = append(roots, ct.ASN1Cert{Data: cert}) } return roots, nil } // GetEntryAndProof returns a log entry and audit path for the index of a leaf. func (c *LogClient) GetEntryAndProof(ctx context.Context, index, treeSize uint64) (*ct.GetEntryAndProofResponse, error) { base10 := 10 params := map[string]string{ "leaf_index": strconv.FormatUint(index, base10), "tree_size": strconv.FormatUint(treeSize, base10), } var resp ct.GetEntryAndProofResponse if _, _, err := c.GetAndParse(ctx, ct.GetEntryAndProofPath, params, &resp); err != nil { return nil, err } return &resp, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/client/multilog.go ================================================ // Copyright 2017 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package client import ( "context" "crypto/sha256" "errors" "fmt" "net/http" "os" "time" ct "github.com/google/certificate-transparency-go" "github.com/google/certificate-transparency-go/client/configpb" "github.com/google/certificate-transparency-go/jsonclient" "github.com/google/certificate-transparency-go/x509" "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" ) type interval struct { lower *time.Time // nil => no lower bound upper *time.Time // nil => no upper bound } // TemporalLogConfigFromFile creates a TemporalLogConfig object from the given // filename, which should contain text-protobuf encoded configuration data. func TemporalLogConfigFromFile(filename string) (*configpb.TemporalLogConfig, error) { if len(filename) == 0 { return nil, errors.New("log config filename empty") } cfgBytes, err := os.ReadFile(filename) if err != nil { return nil, fmt.Errorf("failed to read log config: %v", err) } var cfg configpb.TemporalLogConfig if txtErr := prototext.Unmarshal(cfgBytes, &cfg); txtErr != nil { if binErr := proto.Unmarshal(cfgBytes, &cfg); binErr != nil { return nil, fmt.Errorf("failed to parse TemporalLogConfig from %q as text protobuf (%v) or binary protobuf (%v)", filename, txtErr, binErr) } } if len(cfg.Shard) == 0 { return nil, errors.New("empty log config found") } return &cfg, nil } // AddLogClient is an interface that allows adding certificates and pre-certificates to a log. // Both LogClient and TemporalLogClient implement this interface, which allows users to // commonize code for adding certs to normal/temporal logs. type AddLogClient interface { AddChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) AddPreChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) GetAcceptedRoots(ctx context.Context) ([]ct.ASN1Cert, error) } // TemporalLogClient allows [pre-]certificates to be uploaded to a temporal log. type TemporalLogClient struct { Clients []*LogClient intervals []interval } // NewTemporalLogClient builds a new client for interacting with a temporal log. // The provided config should be contiguous and chronological. func NewTemporalLogClient(cfg *configpb.TemporalLogConfig, hc *http.Client) (*TemporalLogClient, error) { if len(cfg.GetShard()) == 0 { return nil, errors.New("empty config") } overall, err := shardInterval(cfg.Shard[0]) if err != nil { return nil, fmt.Errorf("cfg.Shard[0] invalid: %v", err) } intervals := make([]interval, 0, len(cfg.Shard)) intervals = append(intervals, overall) for i := 1; i < len(cfg.Shard); i++ { interval, err := shardInterval(cfg.Shard[i]) if err != nil { return nil, fmt.Errorf("cfg.Shard[%d] invalid: %v", i, err) } if overall.upper == nil { return nil, fmt.Errorf("cfg.Shard[%d] extends an interval with no upper bound", i) } if interval.lower == nil { return nil, fmt.Errorf("cfg.Shard[%d] has no lower bound but extends an interval", i) } if !interval.lower.Equal(*overall.upper) { return nil, fmt.Errorf("cfg.Shard[%d] starts at %v but previous interval ended at %v", i, interval.lower, overall.upper) } overall.upper = interval.upper intervals = append(intervals, interval) } clients := make([]*LogClient, 0, len(cfg.Shard)) for i, shard := range cfg.Shard { opts := jsonclient.Options{UserAgent: "ct-go-multilog/1.0"} opts.PublicKeyDER = shard.GetPublicKeyDer() c, err := New(shard.Uri, hc, opts) if err != nil { return nil, fmt.Errorf("failed to create client for cfg.Shard[%d]: %v", i, err) } clients = append(clients, c) } tlc := TemporalLogClient{ Clients: clients, intervals: intervals, } return &tlc, nil } // GetAcceptedRoots retrieves the set of acceptable root certificates for all // of the shards of a temporal log (i.e. the union). func (tlc *TemporalLogClient) GetAcceptedRoots(ctx context.Context) ([]ct.ASN1Cert, error) { type result struct { roots []ct.ASN1Cert err error } results := make(chan result, len(tlc.Clients)) for _, c := range tlc.Clients { go func(c *LogClient) { var r result r.roots, r.err = c.GetAcceptedRoots(ctx) results <- r }(c) } var allRoots []ct.ASN1Cert seen := make(map[[sha256.Size]byte]bool) for range tlc.Clients { r := <-results if r.err != nil { return nil, r.err } for _, root := range r.roots { h := sha256.Sum256(root.Data) if seen[h] { continue } seen[h] = true allRoots = append(allRoots, root) } } return allRoots, nil } // AddChain adds the (DER represented) X509 chain to the appropriate log. func (tlc *TemporalLogClient) AddChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) { return tlc.addChain(ctx, ct.X509LogEntryType, ct.AddChainPath, chain) } // AddPreChain adds the (DER represented) Precertificate chain to the appropriate log. func (tlc *TemporalLogClient) AddPreChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) { return tlc.addChain(ctx, ct.PrecertLogEntryType, ct.AddPreChainPath, chain) } func (tlc *TemporalLogClient) addChain(ctx context.Context, ctype ct.LogEntryType, path string, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) { // Parse the first entry in the chain if len(chain) == 0 { return nil, errors.New("missing chain") } cert, err := x509.ParseCertificate(chain[0].Data) if err != nil { return nil, fmt.Errorf("failed to parse initial chain entry: %v", err) } cidx, err := tlc.IndexByDate(cert.NotAfter) if err != nil { return nil, fmt.Errorf("failed to find log to process cert: %v", err) } return tlc.Clients[cidx].addChainWithRetry(ctx, ctype, path, chain) } // IndexByDate returns the index of the Clients entry that is appropriate for the given // date. func (tlc *TemporalLogClient) IndexByDate(when time.Time) (int, error) { for i, interval := range tlc.intervals { if (interval.lower != nil) && when.Before(*interval.lower) { continue } if (interval.upper != nil) && !when.Before(*interval.upper) { continue } return i, nil } return -1, fmt.Errorf("no log found encompassing date %v", when) } func shardInterval(cfg *configpb.LogShardConfig) (interval, error) { var interval interval if cfg.NotAfterStart != nil { if err := cfg.NotAfterStart.CheckValid(); err != nil { return interval, fmt.Errorf("failed to parse NotAfterStart: %v", err) } t := cfg.NotAfterStart.AsTime() interval.lower = &t } if cfg.NotAfterLimit != nil { if err := cfg.NotAfterLimit.CheckValid(); err != nil { return interval, fmt.Errorf("failed to parse NotAfterLimit: %v", err) } t := cfg.NotAfterLimit.AsTime() interval.upper = &t } if interval.lower != nil && interval.upper != nil && !(*interval.lower).Before(*interval.upper) { return interval, errors.New("inverted interval") } return interval, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/cloudbuild.yaml ================================================ ############################################################################# ## The top section of this file is identical in the 3 cloudbuild.*yaml files. ## Make sure any edits you make here are copied over to the other files too ## if appropriate. ## ## TODO(al): consider if it's possible to merge these 3 files and control via ## substitutions. ############################################################################# timeout: 1200s options: machineType: N1_HIGHCPU_32 volumes: - name: go-modules path: /go env: - GOPROXY=https://proxy.golang.org - PROJECT_ROOT=github.com/google/certificate-transparency-go - GOPATH=/go substitutions: _CLUSTER_NAME: trillian-opensource-ci _MASTER_ZONE: us-central1-a # Cloud Build logs sent to GCS bucket logsBucket: 'gs://trillian-cloudbuild-logs' steps: # First build a "ct_testbase" docker image which contains most of the tools we need for the later steps: - name: 'gcr.io/cloud-builders/docker' entrypoint: 'bash' args: ['-c', 'docker pull gcr.io/$PROJECT_ID/ct_testbase:latest || exit 0'] - name: 'gcr.io/cloud-builders/docker' args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/ct_testbase:latest', '--cache-from', 'gcr.io/$PROJECT_ID/ct_testbase:latest', '-f', './integration/Dockerfile', '.' ] # prepare spins up an ephemeral trillian instance for testing use. - name: gcr.io/$PROJECT_ID/ct_testbase entrypoint: 'bash' id: 'prepare' args: - '-exc' - | # Use latest versions of Trillian docker images built by the Trillian CI cloudbuilders. docker pull gcr.io/$PROJECT_ID/log_server:latest docker tag gcr.io/$PROJECT_ID/log_server:latest deployment_trillian-log-server docker pull gcr.io/$PROJECT_ID/log_signer:latest docker tag gcr.io/$PROJECT_ID/log_signer:latest deployment_trillian-log-signer # Bring up an ephemeral trillian instance using the docker-compose config in the Trillian repo: export TRILLIAN_LOCATION="$$(go list -f '{{.Dir}}' github.com/google/trillian)" # We need to fix up Trillian's docker-compose to connect to the CloudBuild network to that tests can use it: echo -e "networks:\n default:\n external:\n name: cloudbuild" >> $${TRILLIAN_LOCATION}/examples/deployment/docker-compose.yml docker-compose -f $${TRILLIAN_LOCATION}/examples/deployment/docker-compose.yml pull mysql trillian-log-server trillian-log-signer docker-compose -f $${TRILLIAN_LOCATION}/examples/deployment/docker-compose.yml up -d mysql trillian-log-server trillian-log-signer # Install proto related bits and block on Trillian being ready - name: gcr.io/$PROJECT_ID/ct_testbase id: 'ci-ready' entrypoint: 'bash' args: - '-ec' - | go install \ github.com/golang/protobuf/proto \ github.com/golang/protobuf/protoc-gen-go \ github.com/golang/mock/mockgen \ go.etcd.io/etcd/v3 go.etcd.io/etcd/etcdctl/v3 \ github.com/fullstorydev/grpcurl/cmd/grpcurl # Generate all protoc and mockgen files go generate -run="protoc" ./... go generate -run="mockgen" ./... # Cache all the modules we'll need too go mod download go test ./... # Wait for trillian logserver to be up until nc -z deployment_trillian-log-server_1 8090; do echo .; sleep 5; done waitFor: ['prepare'] # Run the presubmit tests - name: gcr.io/$PROJECT_ID/ct_testbase id: 'default_test' env: - 'GOFLAGS=' - 'PRESUBMIT_OPTS=--no-linters --no-generate' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'race_detection' env: - 'GOFLAGS=-race' - 'PRESUBMIT_OPTS=--no-linters --no-generate' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'etcd_with_coverage' env: - 'GOFLAGS=' - 'PRESUBMIT_OPTS=--no-linters --no-generate --coverage' - 'WITH_ETCD=true' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'etcd_with_race' env: - 'GOFLAGS=-race' - 'PRESUBMIT_OPTS=--no-linters --no-generate' - 'WITH_ETCD=true' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'with_pkcs11_and_race' env: - 'GOFLAGS=-race --tags=pkcs11' - 'PRESUBMIT_OPTS=--no-linters --no-generate' - 'WITH_PKCS11=true' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] # Collect and submit codecoverage reports - name: 'gcr.io/cloud-builders/curl' id: 'codecov.io' entrypoint: bash args: ['-c', 'bash <(curl -s https://codecov.io/bash)'] env: - 'VCS_COMMIT_ID=$COMMIT_SHA' - 'VCS_BRANCH_NAME=$BRANCH_NAME' - 'VCS_PULL_REQUEST=$_PR_NUMBER' - 'CI_BUILD_ID=$BUILD_ID' - 'CODECOV_TOKEN=$_CODECOV_TOKEN' # _CODECOV_TOKEN is specified in the cloud build trigger waitFor: ['etcd_with_coverage'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'ci_complete' entrypoint: /bin/true waitFor: ['codecov.io', 'default_test', 'race_detection', 'etcd_with_coverage', 'etcd_with_race', 'with_pkcs11_and_race'] ############################################################################ ## End of replicated section. ## Below are deployment specific steps for the CD env. ############################################################################ - id: build_ctfe name: gcr.io/cloud-builders/docker args: - build - --file=trillian/examples/deployment/docker/ctfe/Dockerfile - --tag=gcr.io/${PROJECT_ID}/ctfe:${COMMIT_SHA} - --cache-from=gcr.io/${PROJECT_ID}/ctfe - . waitFor: [-] - id: build_envsubst name: gcr.io/cloud-builders/docker args: - build - trillian/examples/deployment/docker/envsubst - -t - envsubst waitFor: ['ci_complete'] - id: envsubst_kubernetes_configs name: envsubst args: - trillian/examples/deployment/kubernetes/ctfe-deployment.yaml - trillian/examples/deployment/kubernetes/ctfe-service.yaml - trillian/examples/deployment/kubernetes/ctfe-ingress.yaml env: - PROJECT_ID=${PROJECT_ID} - IMAGE_TAG=${COMMIT_SHA} waitFor: - build_envsubst - id: update_kubernetes_configs_dryrun name: gcr.io/cloud-builders/kubectl args: - apply - --dry-run=server - -f=trillian/examples/deployment/kubernetes/ctfe-deployment.yaml - -f=trillian/examples/deployment/kubernetes/ctfe-service.yaml - -f=trillian/examples/deployment/kubernetes/ctfe-ingress.yaml env: - CLOUDSDK_COMPUTE_ZONE=${_MASTER_ZONE} - CLOUDSDK_CONTAINER_CLUSTER=${_CLUSTER_NAME} waitFor: - envsubst_kubernetes_configs - build_ctfe images: - gcr.io/${PROJECT_ID}/ctfe:${COMMIT_SHA} - gcr.io/${PROJECT_ID}/ct_testbase:latest ================================================ FILE: vendor/github.com/google/certificate-transparency-go/cloudbuild_master.yaml ================================================ ############################################################################# ## The top section of this file is identical in the 3 cloudbuild.*yaml files. ## Make sure any edits you make here are copied over to the other files too ## if appropriate. ## ## TODO(al): consider if it's possible to merge these 3 files and control via ## substitutions. ############################################################################# timeout: 1200s options: machineType: N1_HIGHCPU_32 volumes: - name: go-modules path: /go env: - GOPROXY=https://proxy.golang.org - PROJECT_ROOT=github.com/google/certificate-transparency-go - GOPATH=/go substitutions: _CLUSTER_NAME: trillian-opensource-ci _MASTER_ZONE: us-central1-a # Cloud Build logs sent to GCS bucket logsBucket: 'gs://trillian-cloudbuild-logs' steps: # First build a "ct_testbase" docker image which contains most of the tools we need for the later steps: - name: 'gcr.io/cloud-builders/docker' entrypoint: 'bash' args: ['-c', 'docker pull gcr.io/$PROJECT_ID/ct_testbase:latest || exit 0'] - name: 'gcr.io/cloud-builders/docker' args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/ct_testbase:latest', '--cache-from', 'gcr.io/$PROJECT_ID/ct_testbase:latest', '-f', './integration/Dockerfile', '.' ] # prepare spins up an ephemeral trillian instance for testing use. - name: gcr.io/$PROJECT_ID/ct_testbase entrypoint: 'bash' id: 'prepare' args: - '-exc' - | # Use latest versions of Trillian docker images built by the Trillian CI cloudbuilders. docker pull gcr.io/$PROJECT_ID/log_server:latest docker tag gcr.io/$PROJECT_ID/log_server:latest deployment_trillian-log-server docker pull gcr.io/$PROJECT_ID/log_signer:latest docker tag gcr.io/$PROJECT_ID/log_signer:latest deployment_trillian-log-signer # Bring up an ephemeral trillian instance using the docker-compose config in the Trillian repo: export TRILLIAN_LOCATION="$$(go list -f '{{.Dir}}' github.com/google/trillian)" # We need to fix up Trillian's docker-compose to connect to the CloudBuild network to that tests can use it: echo -e "networks:\n default:\n external:\n name: cloudbuild" >> $${TRILLIAN_LOCATION}/examples/deployment/docker-compose.yml docker-compose -f $${TRILLIAN_LOCATION}/examples/deployment/docker-compose.yml pull mysql trillian-log-server trillian-log-signer docker-compose -f $${TRILLIAN_LOCATION}/examples/deployment/docker-compose.yml up -d mysql trillian-log-server trillian-log-signer # Install proto related bits and block on Trillian being ready - name: gcr.io/$PROJECT_ID/ct_testbase id: 'ci-ready' entrypoint: 'bash' args: - '-ec' - | go install \ github.com/golang/protobuf/proto \ github.com/golang/protobuf/protoc-gen-go \ github.com/golang/mock/mockgen \ go.etcd.io/etcd/v3 go.etcd.io/etcd/etcdctl/v3 \ github.com/fullstorydev/grpcurl/cmd/grpcurl # Generate all protoc and mockgen files go generate -run="protoc" ./... go generate -run="mockgen" ./... # Cache all the modules we'll need too go mod download go test ./... # Wait for trillian logserver to be up until nc -z deployment_trillian-log-server_1 8090; do echo .; sleep 5; done waitFor: ['prepare'] # Run the presubmit tests - name: gcr.io/$PROJECT_ID/ct_testbase id: 'default_test' env: - 'GOFLAGS=' - 'PRESUBMIT_OPTS=--no-linters --no-generate' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'race_detection' env: - 'GOFLAGS=-race' - 'PRESUBMIT_OPTS=--no-linters --no-generate' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'etcd_with_coverage' env: - 'GOFLAGS=' - 'PRESUBMIT_OPTS=--no-linters --no-generate --coverage' - 'WITH_ETCD=true' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'etcd_with_race' env: - 'GOFLAGS=-race' - 'PRESUBMIT_OPTS=--no-linters --no-generate' - 'WITH_ETCD=true' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'with_pkcs11_and_race' env: - 'GOFLAGS=-race --tags=pkcs11' - 'PRESUBMIT_OPTS=--no-linters --no-generate' - 'WITH_PKCS11=true' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] # Collect and submit codecoverage reports - name: 'gcr.io/cloud-builders/curl' id: 'codecov.io' entrypoint: bash args: ['-c', 'bash <(curl -s https://codecov.io/bash)'] env: - 'VCS_COMMIT_ID=$COMMIT_SHA' - 'VCS_BRANCH_NAME=$BRANCH_NAME' - 'VCS_PULL_REQUEST=$_PR_NUMBER' - 'CI_BUILD_ID=$BUILD_ID' - 'CODECOV_TOKEN=$_CODECOV_TOKEN' # _CODECOV_TOKEN is specified in the cloud build trigger waitFor: ['etcd_with_coverage'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'ci_complete' entrypoint: /bin/true waitFor: ['codecov.io', 'default_test', 'race_detection', 'etcd_with_coverage', 'etcd_with_race', 'with_pkcs11_and_race'] ############################################################################ ## End of replicated section. ## Below are deployment specific steps for the CD env. ############################################################################ - id: build_ctfe name: gcr.io/cloud-builders/docker args: - build - --file=trillian/examples/deployment/docker/ctfe/Dockerfile - --tag=gcr.io/${PROJECT_ID}/ctfe:${COMMIT_SHA} - --cache-from=gcr.io/${PROJECT_ID}/ctfe - . waitFor: ["-"] - id: push_ctfe name: gcr.io/cloud-builders/docker args: - push - gcr.io/${PROJECT_ID}/ctfe:${COMMIT_SHA} waitFor: - build_ctfe - id: tag_latest_ctfe name: gcr.io/cloud-builders/gcloud args: - container - images - add-tag - gcr.io/${PROJECT_ID}/ctfe:${COMMIT_SHA} - gcr.io/${PROJECT_ID}/ctfe:latest waitFor: - push_ctfe - id: build_envsubst name: gcr.io/cloud-builders/docker args: - build - trillian/examples/deployment/docker/envsubst - -t - envsubst waitFor: ["-"] - id: envsubst_kubernetes_configs name: envsubst args: - trillian/examples/deployment/kubernetes/ctfe-deployment.yaml - trillian/examples/deployment/kubernetes/ctfe-service.yaml - trillian/examples/deployment/kubernetes/ctfe-ingress.yaml env: - PROJECT_ID=${PROJECT_ID} - IMAGE_TAG=${COMMIT_SHA} waitFor: - build_envsubst - id: update_kubernetes_configs name: gcr.io/cloud-builders/kubectl args: - apply - -f=trillian/examples/deployment/kubernetes/ctfe-deployment.yaml - -f=trillian/examples/deployment/kubernetes/ctfe-service.yaml - -f=trillian/examples/deployment/kubernetes/ctfe-ingress.yaml env: - CLOUDSDK_COMPUTE_ZONE=${_MASTER_ZONE} - CLOUDSDK_CONTAINER_CLUSTER=${_CLUSTER_NAME} waitFor: - envsubst_kubernetes_configs - push_ctfe images: - gcr.io/${PROJECT_ID}/ctfe:${COMMIT_SHA} - gcr.io/${PROJECT_ID}/ct_testbase:latest ================================================ FILE: vendor/github.com/google/certificate-transparency-go/cloudbuild_tag.yaml ================================================ ############################################################################# ## The top section of this file is identical in the 3 cloudbuild.*yaml files. ## Make sure any edits you make here are copied over to the other files too ## if appropriate. ## ## TODO(al): consider if it's possible to merge these 3 files and control via ## substitutions. ############################################################################# timeout: 1200s options: machineType: N1_HIGHCPU_32 volumes: - name: go-modules path: /go env: - GOPROXY=https://proxy.golang.org - PROJECT_ROOT=github.com/google/certificate-transparency-go - GOPATH=/go substitutions: _CLUSTER_NAME: trillian-opensource-ci _MASTER_ZONE: us-central1-a # Cloud Build logs sent to GCS bucket logsBucket: 'gs://trillian-cloudbuild-logs' steps: # First build a "ct_testbase" docker image which contains most of the tools we need for the later steps: - name: 'gcr.io/cloud-builders/docker' entrypoint: 'bash' args: ['-c', 'docker pull gcr.io/$PROJECT_ID/ct_testbase:latest || exit 0'] - name: 'gcr.io/cloud-builders/docker' args: [ 'build', '-t', 'gcr.io/$PROJECT_ID/ct_testbase:latest', '--cache-from', 'gcr.io/$PROJECT_ID/ct_testbase:latest', '-f', './integration/Dockerfile', '.' ] # prepare spins up an ephemeral trillian instance for testing use. - name: gcr.io/$PROJECT_ID/ct_testbase entrypoint: 'bash' id: 'prepare' args: - '-exc' - | # Use latest versions of Trillian docker images built by the Trillian CI cloudbuilders. docker pull gcr.io/$PROJECT_ID/log_server:latest docker tag gcr.io/$PROJECT_ID/log_server:latest deployment_trillian-log-server docker pull gcr.io/$PROJECT_ID/log_signer:latest docker tag gcr.io/$PROJECT_ID/log_signer:latest deployment_trillian-log-signer # Bring up an ephemeral trillian instance using the docker-compose config in the Trillian repo: export TRILLIAN_LOCATION="$$(go list -f '{{.Dir}}' github.com/google/trillian)" # We need to fix up Trillian's docker-compose to connect to the CloudBuild network to that tests can use it: echo -e "networks:\n default:\n external:\n name: cloudbuild" >> $${TRILLIAN_LOCATION}/examples/deployment/docker-compose.yml docker-compose -f $${TRILLIAN_LOCATION}/examples/deployment/docker-compose.yml pull mysql trillian-log-server trillian-log-signer docker-compose -f $${TRILLIAN_LOCATION}/examples/deployment/docker-compose.yml up -d mysql trillian-log-server trillian-log-signer # Install proto related bits and block on Trillian being ready - name: gcr.io/$PROJECT_ID/ct_testbase id: 'ci-ready' entrypoint: 'bash' args: - '-ec' - | go install \ github.com/golang/protobuf/proto \ github.com/golang/protobuf/protoc-gen-go \ github.com/golang/mock/mockgen \ go.etcd.io/etcd/v3 go.etcd.io/etcd/etcdctl/v3 \ github.com/fullstorydev/grpcurl/cmd/grpcurl # Generate all protoc and mockgen files go generate -run="protoc" ./... go generate -run="mockgen" ./... # Cache all the modules we'll need too go mod download go test ./... # Wait for trillian logserver to be up until nc -z deployment_trillian-log-server_1 8090; do echo .; sleep 5; done waitFor: ['prepare'] # Run the presubmit tests - name: gcr.io/$PROJECT_ID/ct_testbase id: 'default_test' env: - 'GOFLAGS=' - 'PRESUBMIT_OPTS=--no-linters --no-generate' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'race_detection' env: - 'GOFLAGS=-race' - 'PRESUBMIT_OPTS=--no-linters' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'etcd_with_coverage' env: - 'GOFLAGS=' - 'PRESUBMIT_OPTS=--no-linters --coverage' - 'WITH_ETCD=true' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'etcd_with_race' env: - 'GOFLAGS=-race' - 'PRESUBMIT_OPTS=--no-linters' - 'WITH_ETCD=true' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'with_pkcs11_and_race' env: - 'GOFLAGS=-race --tags=pkcs11' - 'PRESUBMIT_OPTS=--no-linters' - 'WITH_PKCS11=true' - 'TRILLIAN_LOG_SERVERS=deployment_trillian-log-server_1:8090' - 'TRILLIAN_LOG_SERVER_1=deployment_trillian-log-server_1:8090' waitFor: ['ci-ready'] # Collect and submit codecoverage reports - name: 'gcr.io/cloud-builders/curl' id: 'codecov.io' entrypoint: bash args: ['-c', 'bash <(curl -s https://codecov.io/bash)'] env: - 'VCS_COMMIT_ID=$COMMIT_SHA' - 'VCS_BRANCH_NAME=$BRANCH_NAME' - 'VCS_PULL_REQUEST=$_PR_NUMBER' - 'CI_BUILD_ID=$BUILD_ID' - 'CODECOV_TOKEN=$_CODECOV_TOKEN' # _CODECOV_TOKEN is specified in the cloud build trigger waitFor: ['etcd_with_coverage'] - name: gcr.io/$PROJECT_ID/ct_testbase id: 'ci_complete' entrypoint: /bin/true waitFor: ['codecov.io', 'default_test', 'race_detection', 'etcd_with_coverage', 'etcd_with_race', 'with_pkcs11_and_race'] ############################################################################ ## End of replicated section. ## Below are deployment specific steps for the CD env. ############################################################################ - id: build_ctfe name: gcr.io/cloud-builders/docker args: - build - --file=trillian/examples/deployment/docker/ctfe/Dockerfile - --tag=gcr.io/${PROJECT_ID}/ctfe:${TAG_NAME} - --cache-from=gcr.io/${PROJECT_ID}/ctfe - . images: - gcr.io/${PROJECT_ID}/ctfe:${TAG_NAME} - gcr.io/${PROJECT_ID}/ct_testbase:latest ================================================ FILE: vendor/github.com/google/certificate-transparency-go/codecov.yml ================================================ # Customizations to codecov for c-t-go repo. This will be merged into # the team / default codecov yaml file. # # Validate changes with: # curl --data-binary @codecov.yml https://codecov.io/validate # Exclude code that's for testing, demos or utilities that aren't really # part of production releases. ignore: - "**/mock_*.go" - "**/testonly" - "trillian/integration" coverage: status: project: default: # Allow 1% coverage drop without complaining, to avoid being too noisy. threshold: 1% ================================================ FILE: vendor/github.com/google/certificate-transparency-go/jsonclient/backoff.go ================================================ // Copyright 2017 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jsonclient import ( "sync" "time" ) type backoff struct { mu sync.RWMutex multiplier uint notBefore time.Time } const ( // maximum backoff is 2^(maxMultiplier-1) = 128 seconds maxMultiplier = 8 ) func (b *backoff) set(override *time.Duration) time.Duration { b.mu.Lock() defer b.mu.Unlock() if b.notBefore.After(time.Now()) { if override != nil { // If existing backoff is set but override would be longer than // it then set it to that. notBefore := time.Now().Add(*override) if notBefore.After(b.notBefore) { b.notBefore = notBefore } } return time.Until(b.notBefore) } var wait time.Duration if override != nil { wait = *override } else { if b.multiplier < maxMultiplier { b.multiplier++ } wait = time.Second * time.Duration(1<<(b.multiplier-1)) } b.notBefore = time.Now().Add(wait) return wait } func (b *backoff) decreaseMultiplier() { b.mu.Lock() defer b.mu.Unlock() if b.multiplier > 0 { b.multiplier-- } } func (b *backoff) until() time.Time { b.mu.RLock() defer b.mu.RUnlock() return b.notBefore } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/jsonclient/client.go ================================================ // Copyright 2016 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package jsonclient provides a simple client for fetching and parsing // JSON CT structures from a log. package jsonclient import ( "bytes" "context" "crypto" "encoding/json" "errors" "fmt" "io" "log" "math/rand" "net/http" "net/url" "strconv" "strings" "time" ct "github.com/google/certificate-transparency-go" "github.com/google/certificate-transparency-go/x509" "golang.org/x/net/context/ctxhttp" "k8s.io/klog/v2" ) const maxJitter = 250 * time.Millisecond type backoffer interface { // set adjusts/increases the current backoff interval (typically on retryable failure); // if the optional parameter is provided, this will be used as the interval if it is greater // than the currently set interval. Returns the current wait period so that it can be // logged along with any error message. set(*time.Duration) time.Duration // decreaseMultiplier reduces the current backoff multiplier, typically on success. decreaseMultiplier() // until returns the time until which the client should wait before making a request, // it may be in the past in which case it should be ignored. until() time.Time } // JSONClient provides common functionality for interacting with a JSON server // that uses cryptographic signatures. type JSONClient struct { uri string // the base URI of the server. e.g. https://ct.googleapis/pilot httpClient *http.Client // used to interact with the server via HTTP Verifier *ct.SignatureVerifier // nil for no verification (e.g. no public key available) logger Logger // interface to use for logging warnings and errors backoff backoffer // object used to store and calculate backoff information userAgent string // If set, this is sent as the UserAgent header. } // Logger is a simple logging interface used to log internal errors and warnings type Logger interface { // Printf formats and logs a message Printf(string, ...interface{}) } // Options are the options for creating a new JSONClient. type Options struct { // Interface to use for logging warnings and errors, if nil the // standard library log package will be used. Logger Logger // PEM format public key to use for signature verification. PublicKey string // DER format public key to use for signature verification. PublicKeyDER []byte // UserAgent, if set, will be sent as the User-Agent header with each request. UserAgent string } // ParsePublicKey parses and returns the public key contained in opts. // If both opts.PublicKey and opts.PublicKeyDER are set, PublicKeyDER is used. // If neither is set, nil will be returned. func (opts *Options) ParsePublicKey() (crypto.PublicKey, error) { if len(opts.PublicKeyDER) > 0 { return x509.ParsePKIXPublicKey(opts.PublicKeyDER) } if opts.PublicKey != "" { pubkey, _ /* keyhash */, rest, err := ct.PublicKeyFromPEM([]byte(opts.PublicKey)) if err != nil { return nil, err } if len(rest) > 0 { return nil, errors.New("extra data found after PEM key decoded") } return pubkey, nil } return nil, nil } type basicLogger struct{} func (bl *basicLogger) Printf(msg string, args ...interface{}) { log.Printf(msg, args...) } // RspError represents an error that occurred when processing a response from a server, // and also includes key details from the http.Response that triggered the error. type RspError struct { Err error StatusCode int Body []byte } // Error formats the RspError instance, focusing on the error. func (e RspError) Error() string { return e.Err.Error() } // New constructs a new JSONClient instance, for the given base URI, using the // given http.Client object (if provided) and the Options object. // If opts does not specify a public key, signatures will not be verified. func New(uri string, hc *http.Client, opts Options) (*JSONClient, error) { pubkey, err := opts.ParsePublicKey() if err != nil { return nil, fmt.Errorf("invalid public key: %v", err) } var verifier *ct.SignatureVerifier if pubkey != nil { var err error verifier, err = ct.NewSignatureVerifier(pubkey) if err != nil { return nil, err } } if hc == nil { hc = new(http.Client) } logger := opts.Logger if logger == nil { logger = &basicLogger{} } return &JSONClient{ uri: strings.TrimRight(uri, "/"), httpClient: hc, Verifier: verifier, logger: logger, backoff: &backoff{}, userAgent: opts.UserAgent, }, nil } // BaseURI returns the base URI that the JSONClient makes queries to. func (c *JSONClient) BaseURI() string { return c.uri } // GetAndParse makes a HTTP GET call to the given path, and attempts to parse // the response as a JSON representation of the rsp structure. Returns the // http.Response, the body of the response, and an error (which may be of // type RspError if the HTTP response was available). func (c *JSONClient) GetAndParse(ctx context.Context, path string, params map[string]string, rsp interface{}) (*http.Response, []byte, error) { if ctx == nil { return nil, nil, errors.New("context.Context required") } // Build a GET request with URL-encoded parameters. vals := url.Values{} for k, v := range params { vals.Add(k, v) } fullURI := fmt.Sprintf("%s%s?%s", c.uri, path, vals.Encode()) klog.V(2).Infof("GET %s", fullURI) httpReq, err := http.NewRequest(http.MethodGet, fullURI, nil) if err != nil { return nil, nil, err } if len(c.userAgent) != 0 { httpReq.Header.Set("User-Agent", c.userAgent) } httpRsp, err := ctxhttp.Do(ctx, c.httpClient, httpReq) if err != nil { return nil, nil, err } // Read everything now so http.Client can reuse the connection. body, err := io.ReadAll(httpRsp.Body) httpRsp.Body.Close() if err != nil { return nil, nil, RspError{Err: fmt.Errorf("failed to read response body: %v", err), StatusCode: httpRsp.StatusCode, Body: body} } if httpRsp.StatusCode != http.StatusOK { return nil, nil, RspError{Err: fmt.Errorf("got HTTP Status %q", httpRsp.Status), StatusCode: httpRsp.StatusCode, Body: body} } if err := json.NewDecoder(bytes.NewReader(body)).Decode(rsp); err != nil { return nil, nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body} } return httpRsp, body, nil } // PostAndParse makes a HTTP POST call to the given path, including the request // parameters, and attempts to parse the response as a JSON representation of // the rsp structure. Returns the http.Response, the body of the response, and // an error (which may be of type RspError if the HTTP response was available). func (c *JSONClient) PostAndParse(ctx context.Context, path string, req, rsp interface{}) (*http.Response, []byte, error) { if ctx == nil { return nil, nil, errors.New("context.Context required") } // Build a POST request with JSON body. postBody, err := json.Marshal(req) if err != nil { return nil, nil, err } fullURI := fmt.Sprintf("%s%s", c.uri, path) klog.V(2).Infof("POST %s", fullURI) httpReq, err := http.NewRequest(http.MethodPost, fullURI, bytes.NewReader(postBody)) if err != nil { return nil, nil, err } if len(c.userAgent) != 0 { httpReq.Header.Set("User-Agent", c.userAgent) } httpReq.Header.Set("Content-Type", "application/json") httpRsp, err := ctxhttp.Do(ctx, c.httpClient, httpReq) // Read all of the body, if there is one, so that the http.Client can do Keep-Alive. var body []byte if httpRsp != nil { body, err = io.ReadAll(httpRsp.Body) httpRsp.Body.Close() } if err != nil { if httpRsp != nil { return nil, nil, RspError{StatusCode: httpRsp.StatusCode, Body: body, Err: err} } return nil, nil, err } if httpRsp.StatusCode == http.StatusOK { if err = json.Unmarshal(body, &rsp); err != nil { return nil, nil, RspError{StatusCode: httpRsp.StatusCode, Body: body, Err: err} } } return httpRsp, body, nil } // waitForBackoff blocks until the defined backoff interval or context has expired, if the returned // not before time is in the past it returns immediately. func (c *JSONClient) waitForBackoff(ctx context.Context) error { dur := time.Until(c.backoff.until().Add(time.Millisecond * time.Duration(rand.Intn(int(maxJitter.Seconds()*1000))))) if dur < 0 { dur = 0 } backoffTimer := time.NewTimer(dur) select { case <-ctx.Done(): return ctx.Err() case <-backoffTimer.C: } return nil } // PostAndParseWithRetry makes a HTTP POST call, but retries (with backoff) on // retryable errors; the caller should set a deadline on the provided context // to prevent infinite retries. Return values are as for PostAndParse. func (c *JSONClient) PostAndParseWithRetry(ctx context.Context, path string, req, rsp interface{}) (*http.Response, []byte, error) { if ctx == nil { return nil, nil, errors.New("context.Context required") } for { httpRsp, body, err := c.PostAndParse(ctx, path, req, rsp) if err != nil { // Don't retry context errors. if err == context.Canceled || err == context.DeadlineExceeded { return nil, nil, err } wait := c.backoff.set(nil) c.logger.Printf("Request to %s failed, backing-off %s: %s", c.uri, wait, err) } else { switch { case httpRsp.StatusCode == http.StatusOK: return httpRsp, body, nil case httpRsp.StatusCode == http.StatusRequestTimeout: // Request timeout, retry immediately c.logger.Printf("Request to %s timed out, retrying immediately", c.uri) case httpRsp.StatusCode == http.StatusServiceUnavailable: fallthrough case httpRsp.StatusCode == http.StatusTooManyRequests: var backoff *time.Duration // Retry-After may be either a number of seconds as a int or a RFC 1123 // date string (RFC 7231 Section 7.1.3) if retryAfter := httpRsp.Header.Get("Retry-After"); retryAfter != "" { if seconds, err := strconv.Atoi(retryAfter); err == nil { b := time.Duration(seconds) * time.Second backoff = &b } else if date, err := time.Parse(time.RFC1123, retryAfter); err == nil { b := time.Until(date) backoff = &b } } wait := c.backoff.set(backoff) c.logger.Printf("Request to %s failed, backing-off for %s: got HTTP status %s", c.uri, wait, httpRsp.Status) default: return nil, nil, RspError{ StatusCode: httpRsp.StatusCode, Body: body, Err: fmt.Errorf("got HTTP status %q", httpRsp.Status)} } } if err := c.waitForBackoff(ctx); err != nil { return nil, nil, err } } } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/proto_gen.go ================================================ // Copyright 2021 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ct // We do the protoc generation here (rather than in the individual directories) // in order to work around the newly-enforced rule that all protobuf file "names" // must be unique. // See https://developers.google.com/protocol-buffers/docs/proto#packages and // https://github.com/golang/protobuf/issues/1122 //go:generate sh -c "protoc -I=. -I$(go list -f '{{ .Dir }}' github.com/google/trillian) -I$(go list -f '{{ .Dir }}' github.com/google/certificate-transparency-go) --go_out=paths=source_relative:. trillian/ctfe/configpb/config.proto" //go:generate sh -c "protoc -I=. -I$(go list -f '{{ .Dir }}' github.com/google/trillian) -I$(go list -f '{{ .Dir }}' github.com/google/certificate-transparency-go) --go_out=paths=source_relative:. trillian/migrillian/configpb/config.proto" //go:generate sh -c "protoc -I=. -I$(go list -f '{{ .Dir }}' github.com/google/certificate-transparency-go) --go_out=paths=source_relative:. client/configpb/multilog.proto" ================================================ FILE: vendor/github.com/google/certificate-transparency-go/serialization.go ================================================ // Copyright 2015 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ct import ( "crypto" "crypto/sha256" "fmt" "time" "github.com/google/certificate-transparency-go/tls" "github.com/google/certificate-transparency-go/x509" ) // SerializeSCTSignatureInput serializes the passed in sct and log entry into // the correct format for signing. func SerializeSCTSignatureInput(sct SignedCertificateTimestamp, entry LogEntry) ([]byte, error) { switch sct.SCTVersion { case V1: input := CertificateTimestamp{ SCTVersion: sct.SCTVersion, SignatureType: CertificateTimestampSignatureType, Timestamp: sct.Timestamp, EntryType: entry.Leaf.TimestampedEntry.EntryType, Extensions: sct.Extensions, } switch entry.Leaf.TimestampedEntry.EntryType { case X509LogEntryType: input.X509Entry = entry.Leaf.TimestampedEntry.X509Entry case PrecertLogEntryType: input.PrecertEntry = &PreCert{ IssuerKeyHash: entry.Leaf.TimestampedEntry.PrecertEntry.IssuerKeyHash, TBSCertificate: entry.Leaf.TimestampedEntry.PrecertEntry.TBSCertificate, } default: return nil, fmt.Errorf("unsupported entry type %s", entry.Leaf.TimestampedEntry.EntryType) } return tls.Marshal(input) default: return nil, fmt.Errorf("unknown SCT version %d", sct.SCTVersion) } } // SerializeSTHSignatureInput serializes the passed in STH into the correct // format for signing. func SerializeSTHSignatureInput(sth SignedTreeHead) ([]byte, error) { switch sth.Version { case V1: if len(sth.SHA256RootHash) != crypto.SHA256.Size() { return nil, fmt.Errorf("invalid TreeHash length, got %d expected %d", len(sth.SHA256RootHash), crypto.SHA256.Size()) } input := TreeHeadSignature{ Version: sth.Version, SignatureType: TreeHashSignatureType, Timestamp: sth.Timestamp, TreeSize: sth.TreeSize, SHA256RootHash: sth.SHA256RootHash, } return tls.Marshal(input) default: return nil, fmt.Errorf("unsupported STH version %d", sth.Version) } } // CreateX509MerkleTreeLeaf generates a MerkleTreeLeaf for an X509 cert func CreateX509MerkleTreeLeaf(cert ASN1Cert, timestamp uint64) *MerkleTreeLeaf { return &MerkleTreeLeaf{ Version: V1, LeafType: TimestampedEntryLeafType, TimestampedEntry: &TimestampedEntry{ Timestamp: timestamp, EntryType: X509LogEntryType, X509Entry: &cert, }, } } // MerkleTreeLeafFromRawChain generates a MerkleTreeLeaf from a chain (in DER-encoded form) and timestamp. func MerkleTreeLeafFromRawChain(rawChain []ASN1Cert, etype LogEntryType, timestamp uint64) (*MerkleTreeLeaf, error) { // Need at most 3 of the chain count := 3 if count > len(rawChain) { count = len(rawChain) } chain := make([]*x509.Certificate, count) for i := range chain { cert, err := x509.ParseCertificate(rawChain[i].Data) if x509.IsFatal(err) { return nil, fmt.Errorf("failed to parse chain[%d] cert: %v", i, err) } chain[i] = cert } return MerkleTreeLeafFromChain(chain, etype, timestamp) } // MerkleTreeLeafFromChain generates a MerkleTreeLeaf from a chain and timestamp. func MerkleTreeLeafFromChain(chain []*x509.Certificate, etype LogEntryType, timestamp uint64) (*MerkleTreeLeaf, error) { leaf := MerkleTreeLeaf{ Version: V1, LeafType: TimestampedEntryLeafType, TimestampedEntry: &TimestampedEntry{ EntryType: etype, Timestamp: timestamp, }, } if etype == X509LogEntryType { leaf.TimestampedEntry.X509Entry = &ASN1Cert{Data: chain[0].Raw} return &leaf, nil } if etype != PrecertLogEntryType { return nil, fmt.Errorf("unknown LogEntryType %d", etype) } // Pre-certs are more complicated. First, parse the leaf pre-cert and its // putative issuer. if len(chain) < 2 { return nil, fmt.Errorf("no issuer cert available for precert leaf building") } issuer := chain[1] cert := chain[0] var preIssuer *x509.Certificate if IsPreIssuer(issuer) { // Replace the cert's issuance information with details from the pre-issuer. preIssuer = issuer // The issuer of the pre-cert is not going to be the issuer of the final // cert. Change to use the final issuer's key hash. if len(chain) < 3 { return nil, fmt.Errorf("no issuer cert available for pre-issuer") } issuer = chain[2] } // Next, post-process the DER-encoded TBSCertificate, to remove the CT poison // extension and possibly update the issuer field. defangedTBS, err := x509.BuildPrecertTBS(cert.RawTBSCertificate, preIssuer) if err != nil { return nil, fmt.Errorf("failed to remove poison extension: %v", err) } leaf.TimestampedEntry.EntryType = PrecertLogEntryType leaf.TimestampedEntry.PrecertEntry = &PreCert{ IssuerKeyHash: sha256.Sum256(issuer.RawSubjectPublicKeyInfo), TBSCertificate: defangedTBS, } return &leaf, nil } // MerkleTreeLeafForEmbeddedSCT generates a MerkleTreeLeaf from a chain and an // SCT timestamp, where the leaf certificate at chain[0] is a certificate that // contains embedded SCTs. It is assumed that the timestamp provided is from // one of the SCTs embedded within the leaf certificate. func MerkleTreeLeafForEmbeddedSCT(chain []*x509.Certificate, timestamp uint64) (*MerkleTreeLeaf, error) { // For building the leaf for a certificate and SCT where the SCT is embedded // in the certificate, we need to build the original precertificate TBS // data. First, parse the leaf cert and its issuer. if len(chain) < 2 { return nil, fmt.Errorf("no issuer cert available for precert leaf building") } issuer := chain[1] cert := chain[0] // Next, post-process the DER-encoded TBSCertificate, to remove the SCTList // extension. tbs, err := x509.RemoveSCTList(cert.RawTBSCertificate) if err != nil { return nil, fmt.Errorf("failed to remove SCT List extension: %v", err) } return &MerkleTreeLeaf{ Version: V1, LeafType: TimestampedEntryLeafType, TimestampedEntry: &TimestampedEntry{ EntryType: PrecertLogEntryType, Timestamp: timestamp, PrecertEntry: &PreCert{ IssuerKeyHash: sha256.Sum256(issuer.RawSubjectPublicKeyInfo), TBSCertificate: tbs, }, }, }, nil } // LeafHashForLeaf returns the leaf hash for a Merkle tree leaf. func LeafHashForLeaf(leaf *MerkleTreeLeaf) ([sha256.Size]byte, error) { leafData, err := tls.Marshal(*leaf) if err != nil { return [sha256.Size]byte{}, fmt.Errorf("failed to tls-encode MerkleTreeLeaf: %s", err) } data := append([]byte{TreeLeafPrefix}, leafData...) leafHash := sha256.Sum256(data) return leafHash, nil } // IsPreIssuer indicates whether a certificate is a pre-cert issuer with the specific // certificate transparency extended key usage. func IsPreIssuer(issuer *x509.Certificate) bool { for _, eku := range issuer.ExtKeyUsage { if eku == x509.ExtKeyUsageCertificateTransparency { return true } } return false } // RawLogEntryFromLeaf converts a LeafEntry object (which has the raw leaf data // after JSON parsing) into a RawLogEntry object (i.e. a TLS-parsed structure). func RawLogEntryFromLeaf(index int64, entry *LeafEntry) (*RawLogEntry, error) { ret := RawLogEntry{Index: index} if rest, err := tls.Unmarshal(entry.LeafInput, &ret.Leaf); err != nil { return nil, fmt.Errorf("failed to unmarshal MerkleTreeLeaf: %v", err) } else if len(rest) > 0 { return nil, fmt.Errorf("MerkleTreeLeaf: trailing data %d bytes", len(rest)) } switch eType := ret.Leaf.TimestampedEntry.EntryType; eType { case X509LogEntryType: var certChain CertificateChain if rest, err := tls.Unmarshal(entry.ExtraData, &certChain); err != nil { return nil, fmt.Errorf("failed to unmarshal CertificateChain: %v", err) } else if len(rest) > 0 { return nil, fmt.Errorf("CertificateChain: trailing data %d bytes", len(rest)) } ret.Cert = *ret.Leaf.TimestampedEntry.X509Entry ret.Chain = certChain.Entries case PrecertLogEntryType: var precertChain PrecertChainEntry if rest, err := tls.Unmarshal(entry.ExtraData, &precertChain); err != nil { return nil, fmt.Errorf("failed to unmarshal PrecertChainEntry: %v", err) } else if len(rest) > 0 { return nil, fmt.Errorf("PrecertChainEntry: trailing data %d bytes", len(rest)) } ret.Cert = precertChain.PreCertificate ret.Chain = precertChain.CertificateChain default: // TODO(pavelkalinnikov): Section 4.6 of RFC6962 implies that unknown types // are not errors. We should revisit how we process this case. return nil, fmt.Errorf("unknown entry type: %v", eType) } return &ret, nil } // ToLogEntry converts RawLogEntry to a LogEntry, which includes an x509-parsed // (pre-)certificate. // // Note that this function may return a valid LogEntry object and a non-nil // error value, when the error indicates a non-fatal parsing error. func (rle *RawLogEntry) ToLogEntry() (*LogEntry, error) { var err error entry := LogEntry{Index: rle.Index, Leaf: rle.Leaf, Chain: rle.Chain} switch eType := rle.Leaf.TimestampedEntry.EntryType; eType { case X509LogEntryType: entry.X509Cert, err = rle.Leaf.X509Certificate() if x509.IsFatal(err) { return nil, fmt.Errorf("failed to parse certificate: %v", err) } case PrecertLogEntryType: var tbsCert *x509.Certificate tbsCert, err = rle.Leaf.Precertificate() if x509.IsFatal(err) { return nil, fmt.Errorf("failed to parse precertificate: %v", err) } entry.Precert = &Precertificate{ Submitted: rle.Cert, IssuerKeyHash: rle.Leaf.TimestampedEntry.PrecertEntry.IssuerKeyHash, TBSCertificate: tbsCert, } default: return nil, fmt.Errorf("unknown entry type: %v", eType) } // err may be non-nil for a non-fatal error. return &entry, err } // LogEntryFromLeaf converts a LeafEntry object (which has the raw leaf data // after JSON parsing) into a LogEntry object (which includes x509.Certificate // objects, after TLS and ASN.1 parsing). // // Note that this function may return a valid LogEntry object and a non-nil // error value, when the error indicates a non-fatal parsing error. func LogEntryFromLeaf(index int64, leaf *LeafEntry) (*LogEntry, error) { rle, err := RawLogEntryFromLeaf(index, leaf) if err != nil { return nil, err } return rle.ToLogEntry() } // TimestampToTime converts a timestamp in the style of RFC 6962 (milliseconds // since UNIX epoch) to a Go Time. func TimestampToTime(ts uint64) time.Time { secs := int64(ts / 1000) msecs := int64(ts % 1000) return time.Unix(secs, msecs*1000000) } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/signatures.go ================================================ // Copyright 2015 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ct import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" "crypto/sha256" "encoding/base64" "encoding/pem" "fmt" "log" "github.com/google/certificate-transparency-go/tls" "github.com/google/certificate-transparency-go/x509" ) // AllowVerificationWithNonCompliantKeys may be set to true in order to allow // SignatureVerifier to use keys which are technically non-compliant with // RFC6962. var AllowVerificationWithNonCompliantKeys = false // PublicKeyFromPEM parses a PEM formatted block and returns the public key contained within and any remaining unread bytes, or an error. func PublicKeyFromPEM(b []byte) (crypto.PublicKey, SHA256Hash, []byte, error) { p, rest := pem.Decode(b) if p == nil { return nil, [sha256.Size]byte{}, rest, fmt.Errorf("no PEM block found in %s", string(b)) } k, err := x509.ParsePKIXPublicKey(p.Bytes) return k, sha256.Sum256(p.Bytes), rest, err } // PublicKeyFromB64 parses a base64-encoded public key. func PublicKeyFromB64(b64PubKey string) (crypto.PublicKey, error) { der, err := base64.StdEncoding.DecodeString(b64PubKey) if err != nil { return nil, fmt.Errorf("error decoding public key: %s", err) } return x509.ParsePKIXPublicKey(der) } // SignatureVerifier can verify signatures on SCTs and STHs type SignatureVerifier struct { PubKey crypto.PublicKey } // NewSignatureVerifier creates a new SignatureVerifier using the passed in PublicKey. func NewSignatureVerifier(pk crypto.PublicKey) (*SignatureVerifier, error) { switch pkType := pk.(type) { case *rsa.PublicKey: if pkType.N.BitLen() < 2048 { e := fmt.Errorf("public key is RSA with < 2048 bits (size:%d)", pkType.N.BitLen()) if !AllowVerificationWithNonCompliantKeys { return nil, e } log.Printf("WARNING: %v", e) } case *ecdsa.PublicKey: params := *(pkType.Params()) if params != *elliptic.P256().Params() { e := fmt.Errorf("public is ECDSA, but not on the P256 curve") if !AllowVerificationWithNonCompliantKeys { return nil, e } log.Printf("WARNING: %v", e) } default: return nil, fmt.Errorf("unsupported public key type %v", pkType) } return &SignatureVerifier{PubKey: pk}, nil } // VerifySignature verifies the given signature sig matches the data. func (s SignatureVerifier) VerifySignature(data []byte, sig tls.DigitallySigned) error { return tls.VerifySignature(s.PubKey, data, sig) } // VerifySCTSignature verifies that the SCT's signature is valid for the given LogEntry. func (s SignatureVerifier) VerifySCTSignature(sct SignedCertificateTimestamp, entry LogEntry) error { sctData, err := SerializeSCTSignatureInput(sct, entry) if err != nil { return err } return s.VerifySignature(sctData, tls.DigitallySigned(sct.Signature)) } // VerifySTHSignature verifies that the STH's signature is valid. func (s SignatureVerifier) VerifySTHSignature(sth SignedTreeHead) error { sthData, err := SerializeSTHSignatureInput(sth) if err != nil { return err } return s.VerifySignature(sthData, tls.DigitallySigned(sth.TreeHeadSignature)) } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/tls/signature.go ================================================ // Copyright 2016 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package tls import ( "crypto" "crypto/dsa" //nolint:staticcheck "crypto/ecdsa" _ "crypto/md5" // For registration side-effect "crypto/rand" "crypto/rsa" _ "crypto/sha1" // For registration side-effect _ "crypto/sha256" // For registration side-effect _ "crypto/sha512" // For registration side-effect "errors" "fmt" "log" "math/big" "github.com/google/certificate-transparency-go/asn1" ) type dsaSig struct { R, S *big.Int } func generateHash(algo HashAlgorithm, data []byte) ([]byte, crypto.Hash, error) { var hashType crypto.Hash switch algo { case MD5: hashType = crypto.MD5 case SHA1: hashType = crypto.SHA1 case SHA224: hashType = crypto.SHA224 case SHA256: hashType = crypto.SHA256 case SHA384: hashType = crypto.SHA384 case SHA512: hashType = crypto.SHA512 default: return nil, hashType, fmt.Errorf("unsupported Algorithm.Hash in signature: %v", algo) } hasher := hashType.New() if _, err := hasher.Write(data); err != nil { return nil, hashType, fmt.Errorf("failed to write to hasher: %v", err) } return hasher.Sum([]byte{}), hashType, nil } // VerifySignature verifies that the passed in signature over data was created by the given PublicKey. func VerifySignature(pubKey crypto.PublicKey, data []byte, sig DigitallySigned) error { hash, hashType, err := generateHash(sig.Algorithm.Hash, data) if err != nil { return err } switch sig.Algorithm.Signature { case RSA: rsaKey, ok := pubKey.(*rsa.PublicKey) if !ok { return fmt.Errorf("cannot verify RSA signature with %T key", pubKey) } if err := rsa.VerifyPKCS1v15(rsaKey, hashType, hash, sig.Signature); err != nil { return fmt.Errorf("failed to verify rsa signature: %v", err) } case DSA: dsaKey, ok := pubKey.(*dsa.PublicKey) if !ok { return fmt.Errorf("cannot verify DSA signature with %T key", pubKey) } var dsaSig dsaSig rest, err := asn1.Unmarshal(sig.Signature, &dsaSig) if err != nil { return fmt.Errorf("failed to unmarshal DSA signature: %v", err) } if len(rest) != 0 { log.Printf("Garbage following signature %q", rest) } if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 { return errors.New("DSA signature contained zero or negative values") } if !dsa.Verify(dsaKey, hash, dsaSig.R, dsaSig.S) { return errors.New("failed to verify DSA signature") } case ECDSA: ecdsaKey, ok := pubKey.(*ecdsa.PublicKey) if !ok { return fmt.Errorf("cannot verify ECDSA signature with %T key", pubKey) } var ecdsaSig dsaSig rest, err := asn1.Unmarshal(sig.Signature, &ecdsaSig) if err != nil { return fmt.Errorf("failed to unmarshal ECDSA signature: %v", err) } if len(rest) != 0 { log.Printf("Garbage following signature %q", rest) } if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { return errors.New("ECDSA signature contained zero or negative values") } if !ecdsa.Verify(ecdsaKey, hash, ecdsaSig.R, ecdsaSig.S) { return errors.New("failed to verify ECDSA signature") } default: return fmt.Errorf("unsupported Algorithm.Signature in signature: %v", sig.Algorithm.Hash) } return nil } // CreateSignature builds a signature over the given data using the specified hash algorithm and private key. func CreateSignature(privKey crypto.PrivateKey, hashAlgo HashAlgorithm, data []byte) (DigitallySigned, error) { var sig DigitallySigned sig.Algorithm.Hash = hashAlgo hash, hashType, err := generateHash(sig.Algorithm.Hash, data) if err != nil { return sig, err } switch privKey := privKey.(type) { case rsa.PrivateKey: sig.Algorithm.Signature = RSA sig.Signature, err = rsa.SignPKCS1v15(rand.Reader, &privKey, hashType, hash) return sig, err case ecdsa.PrivateKey: sig.Algorithm.Signature = ECDSA var ecdsaSig dsaSig ecdsaSig.R, ecdsaSig.S, err = ecdsa.Sign(rand.Reader, &privKey, hash) if err != nil { return sig, err } sig.Signature, err = asn1.Marshal(ecdsaSig) return sig, err default: return sig, fmt.Errorf("unsupported private key type %T", privKey) } } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/tls/tls.go ================================================ // Copyright 2016 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package tls implements functionality for dealing with TLS-encoded data, // as defined in RFC 5246. This includes parsing and generation of TLS-encoded // data, together with utility functions for dealing with the DigitallySigned // TLS type. package tls import ( "bytes" "encoding/binary" "fmt" "reflect" "strconv" "strings" ) // This file holds utility functions for TLS encoding/decoding data // as per RFC 5246 section 4. // A structuralError suggests that the TLS data is valid, but the Go type // which is receiving it doesn't match. type structuralError struct { field string msg string } func (e structuralError) Error() string { var prefix string if e.field != "" { prefix = e.field + ": " } return "tls: structure error: " + prefix + e.msg } // A syntaxError suggests that the TLS data is invalid. type syntaxError struct { field string msg string } func (e syntaxError) Error() string { var prefix string if e.field != "" { prefix = e.field + ": " } return "tls: syntax error: " + prefix + e.msg } // Uint24 is an unsigned 3-byte integer. type Uint24 uint32 // Enum is an unsigned integer. type Enum uint64 var ( uint8Type = reflect.TypeOf(uint8(0)) uint16Type = reflect.TypeOf(uint16(0)) uint24Type = reflect.TypeOf(Uint24(0)) uint32Type = reflect.TypeOf(uint32(0)) uint64Type = reflect.TypeOf(uint64(0)) enumType = reflect.TypeOf(Enum(0)) ) // Unmarshal parses the TLS-encoded data in b and uses the reflect package to // fill in an arbitrary value pointed at by val. Because Unmarshal uses the // reflect package, the structs being written to must use exported fields // (upper case names). // // The mappings between TLS types and Go types is as follows; some fields // must have tags (to indicate their encoded size). // // TLS Go Required Tags // opaque byte / uint8 // uint8 byte / uint8 // uint16 uint16 // uint24 tls.Uint24 // uint32 uint32 // uint64 uint64 // enum tls.Enum size:S or maxval:N // Type []Type minlen:N,maxlen:M // opaque[N] [N]byte / [N]uint8 // uint8[N] [N]byte / [N]uint8 // struct { } struct { } // select(T) { // case e1: Type *T selector:Field,val:e1 // } // // TLS variants (RFC 5246 s4.6.1) are only supported when the value of the // associated enumeration type is available earlier in the same enclosing // struct, and each possible variant is marked with a selector tag (to // indicate which field selects the variants) and a val tag (to indicate // what value of the selector picks this particular field). // // For example, a TLS structure: // // enum { e1(1), e2(2) } EnumType; // struct { // EnumType sel; // select(sel) { // case e1: uint16 // case e2: uint32 // } data; // } VariantItem; // // would have a corresponding Go type: // // type VariantItem struct { // Sel tls.Enum `tls:"maxval:2"` // Data16 *uint16 `tls:"selector:Sel,val:1"` // Data32 *uint32 `tls:"selector:Sel,val:2"` // } // // TLS fixed-length vectors of types other than opaque or uint8 are not supported. // // For TLS variable-length vectors that are themselves used in other vectors, // create a single-field structure to represent the inner type. For example, for: // // opaque InnerType<1..65535>; // struct { // InnerType inners<1,65535>; // } Something; // // convert to: // // type InnerType struct { // Val []byte `tls:"minlen:1,maxlen:65535"` // } // type Something struct { // Inners []InnerType `tls:"minlen:1,maxlen:65535"` // } // // If the encoded value does not fit in the Go type, Unmarshal returns a parse error. func Unmarshal(b []byte, val interface{}) ([]byte, error) { return UnmarshalWithParams(b, val, "") } // UnmarshalWithParams allows field parameters to be specified for the // top-level element. The form of the params is the same as the field tags. func UnmarshalWithParams(b []byte, val interface{}, params string) ([]byte, error) { info, err := fieldTagToFieldInfo(params, "") if err != nil { return nil, err } // The passed in interface{} is a pointer (to allow the value to be written // to); extract the pointed-to object as a reflect.Value, so parseField // can do various introspection things. v := reflect.ValueOf(val).Elem() offset, err := parseField(v, b, 0, info) if err != nil { return nil, err } return b[offset:], nil } // Return the number of bytes needed to encode values up to (and including) x. func byteCount(x uint64) uint { switch { case x < 0x100: return 1 case x < 0x10000: return 2 case x < 0x1000000: return 3 case x < 0x100000000: return 4 case x < 0x10000000000: return 5 case x < 0x1000000000000: return 6 case x < 0x100000000000000: return 7 default: return 8 } } type fieldInfo struct { count uint // Number of bytes countSet bool minlen uint64 // Only relevant for slices maxlen uint64 // Only relevant for slices selector string // Only relevant for select sub-values val uint64 // Only relevant for select sub-values name string // Used for better error messages } func (i *fieldInfo) fieldName() string { if i == nil { return "" } return i.name } // Given a tag string, return a fieldInfo describing the field. func fieldTagToFieldInfo(str string, name string) (*fieldInfo, error) { var info *fieldInfo // Iterate over clauses in the tag, ignoring any that don't parse properly. for _, part := range strings.Split(str, ",") { switch { case strings.HasPrefix(part, "maxval:"): if v, err := strconv.ParseUint(part[7:], 10, 64); err == nil { info = &fieldInfo{count: byteCount(v), countSet: true} } case strings.HasPrefix(part, "size:"): if sz, err := strconv.ParseUint(part[5:], 10, 32); err == nil { info = &fieldInfo{count: uint(sz), countSet: true} } case strings.HasPrefix(part, "maxlen:"): v, err := strconv.ParseUint(part[7:], 10, 64) if err != nil { continue } if info == nil { info = &fieldInfo{} } info.count = byteCount(v) info.countSet = true info.maxlen = v case strings.HasPrefix(part, "minlen:"): v, err := strconv.ParseUint(part[7:], 10, 64) if err != nil { continue } if info == nil { info = &fieldInfo{} } info.minlen = v case strings.HasPrefix(part, "selector:"): if info == nil { info = &fieldInfo{} } info.selector = part[9:] case strings.HasPrefix(part, "val:"): v, err := strconv.ParseUint(part[4:], 10, 64) if err != nil { continue } if info == nil { info = &fieldInfo{} } info.val = v } } if info != nil { info.name = name if info.selector == "" { if info.count < 1 { return nil, structuralError{name, "field of unknown size in " + str} } else if info.count > 8 { return nil, structuralError{name, "specified size too large in " + str} } else if info.minlen > info.maxlen { return nil, structuralError{name, "specified length range inverted in " + str} } else if info.val > 0 { return nil, structuralError{name, "specified selector value but not field in " + str} } } } else if name != "" { info = &fieldInfo{name: name} } return info, nil } // Check that a value fits into a field described by a fieldInfo structure. func (i fieldInfo) check(val uint64, fldName string) error { if val >= (1 << (8 * i.count)) { return structuralError{fldName, fmt.Sprintf("value %d too large for size", val)} } if i.maxlen != 0 { if val < i.minlen { return structuralError{fldName, fmt.Sprintf("value %d too small for minimum %d", val, i.minlen)} } if val > i.maxlen { return structuralError{fldName, fmt.Sprintf("value %d too large for maximum %d", val, i.maxlen)} } } return nil } // readVarUint reads an big-endian unsigned integer of the given size in // bytes. func readVarUint(data []byte, info *fieldInfo) (uint64, error) { if info == nil || !info.countSet { return 0, structuralError{info.fieldName(), "no field size information available"} } if len(data) < int(info.count) { return 0, syntaxError{info.fieldName(), "truncated variable-length integer"} } var result uint64 for i := uint(0); i < info.count; i++ { result = (result << 8) | uint64(data[i]) } if err := info.check(result, info.name); err != nil { return 0, err } return result, nil } // parseField is the main parsing function. Given a byte slice and an offset // (in bytes) into the data, it will try to parse a suitable ASN.1 value out // and store it in the given Value. func parseField(v reflect.Value, data []byte, initOffset int, info *fieldInfo) (int, error) { offset := initOffset rest := data[offset:] fieldType := v.Type() // First look for known fixed types. switch fieldType { case uint8Type: if len(rest) < 1 { return offset, syntaxError{info.fieldName(), "truncated uint8"} } v.SetUint(uint64(rest[0])) offset++ return offset, nil case uint16Type: if len(rest) < 2 { return offset, syntaxError{info.fieldName(), "truncated uint16"} } v.SetUint(uint64(binary.BigEndian.Uint16(rest))) offset += 2 return offset, nil case uint24Type: if len(rest) < 3 { return offset, syntaxError{info.fieldName(), "truncated uint24"} } v.SetUint(uint64(data[0])<<16 | uint64(data[1])<<8 | uint64(data[2])) offset += 3 return offset, nil case uint32Type: if len(rest) < 4 { return offset, syntaxError{info.fieldName(), "truncated uint32"} } v.SetUint(uint64(binary.BigEndian.Uint32(rest))) offset += 4 return offset, nil case uint64Type: if len(rest) < 8 { return offset, syntaxError{info.fieldName(), "truncated uint64"} } v.SetUint(uint64(binary.BigEndian.Uint64(rest))) offset += 8 return offset, nil } // Now deal with user-defined types. switch v.Kind() { case enumType.Kind(): // Assume that anything of the same kind as Enum is an Enum, so that // users can alias types of their own to Enum. val, err := readVarUint(rest, info) if err != nil { return offset, err } v.SetUint(val) offset += int(info.count) return offset, nil case reflect.Struct: structType := fieldType // TLS includes a select(Enum) {..} construct, where the value of an enum // indicates which variant field is present (like a C union). We require // that the enum value be an earlier field in the same structure (the selector), // and that each of the possible variant destination fields be pointers. // So the Go mapping looks like: // type variantType struct { // Which tls.Enum `tls:"size:1"` // this is the selector // Val1 *type1 `tls:"selector:Which,val:1"` // this is a destination // Val2 *type2 `tls:"selector:Which,val:1"` // this is a destination // } // To deal with this, we track any enum-like fields and their values... enums := make(map[string]uint64) // .. and we track which selector names we've seen (in the destination field tags), // and whether a destination for that selector has been chosen. selectorSeen := make(map[string]bool) for i := 0; i < structType.NumField(); i++ { // Find information about this field. tag := structType.Field(i).Tag.Get("tls") fieldInfo, err := fieldTagToFieldInfo(tag, structType.Field(i).Name) if err != nil { return offset, err } destination := v.Field(i) if fieldInfo.selector != "" { // This is a possible select(Enum) destination, so first check that the referenced // selector field has already been seen earlier in the struct. choice, ok := enums[fieldInfo.selector] if !ok { return offset, structuralError{fieldInfo.name, "selector not seen: " + fieldInfo.selector} } if structType.Field(i).Type.Kind() != reflect.Ptr { return offset, structuralError{fieldInfo.name, "choice field not a pointer type"} } // Is this the first mention of the selector field name? If so, remember it. seen, ok := selectorSeen[fieldInfo.selector] if !ok { selectorSeen[fieldInfo.selector] = false } if choice != fieldInfo.val { // This destination field was not the chosen one, so make it nil (we checked // it was a pointer above). v.Field(i).Set(reflect.Zero(structType.Field(i).Type)) continue } if seen { // We already saw a different destination field receive the value for this // selector value, which indicates a badly annotated structure. return offset, structuralError{fieldInfo.name, "duplicate selector value for " + fieldInfo.selector} } selectorSeen[fieldInfo.selector] = true // Make an object of the pointed-to type and parse into that. v.Field(i).Set(reflect.New(structType.Field(i).Type.Elem())) destination = v.Field(i).Elem() } offset, err = parseField(destination, data, offset, fieldInfo) if err != nil { return offset, err } // Remember any possible tls.Enum values encountered in case they are selectors. if structType.Field(i).Type.Kind() == enumType.Kind() { enums[structType.Field(i).Name] = v.Field(i).Uint() } } // Now we have seen all fields in the structure, check that all select(Enum) {..} selector // fields found a destination to put their data in. for selector, seen := range selectorSeen { if !seen { return offset, syntaxError{info.fieldName(), selector + ": unhandled value for selector"} } } return offset, nil case reflect.Array: datalen := v.Len() if datalen > len(rest) { return offset, syntaxError{info.fieldName(), "truncated array"} } inner := rest[:datalen] offset += datalen if fieldType.Elem().Kind() != reflect.Uint8 { // Only byte/uint8 arrays are supported return offset, structuralError{info.fieldName(), "unsupported array type: " + v.Type().String()} } reflect.Copy(v, reflect.ValueOf(inner)) return offset, nil case reflect.Slice: sliceType := fieldType // Slices represent variable-length vectors, which are prefixed by a length field. // The fieldInfo indicates the size of that length field. varlen, err := readVarUint(rest, info) if err != nil { return offset, err } datalen := int(varlen) offset += int(info.count) rest = rest[info.count:] if datalen > len(rest) { return offset, syntaxError{info.fieldName(), "truncated slice"} } inner := rest[:datalen] offset += datalen if fieldType.Elem().Kind() == reflect.Uint8 { // Fast version for []byte v.Set(reflect.MakeSlice(sliceType, datalen, datalen)) reflect.Copy(v, reflect.ValueOf(inner)) return offset, nil } v.Set(reflect.MakeSlice(sliceType, 0, datalen)) single := reflect.New(sliceType.Elem()) for innerOffset := 0; innerOffset < len(inner); { var err error innerOffset, err = parseField(single.Elem(), inner, innerOffset, nil) if err != nil { return offset, err } v.Set(reflect.Append(v, single.Elem())) } return offset, nil default: return offset, structuralError{info.fieldName(), fmt.Sprintf("unsupported type: %s of kind %s", fieldType, v.Kind())} } } // Marshal returns the TLS encoding of val. func Marshal(val interface{}) ([]byte, error) { return MarshalWithParams(val, "") } // MarshalWithParams returns the TLS encoding of val, and allows field // parameters to be specified for the top-level element. The form // of the params is the same as the field tags. func MarshalWithParams(val interface{}, params string) ([]byte, error) { info, err := fieldTagToFieldInfo(params, "") if err != nil { return nil, err } var out bytes.Buffer v := reflect.ValueOf(val) if err := marshalField(&out, v, info); err != nil { return nil, err } return out.Bytes(), err } func marshalField(out *bytes.Buffer, v reflect.Value, info *fieldInfo) error { var prefix string if info != nil && len(info.name) > 0 { prefix = info.name + ": " } fieldType := v.Type() // First look for known fixed types. switch fieldType { case uint8Type: out.WriteByte(byte(v.Uint())) return nil case uint16Type: scratch := make([]byte, 2) binary.BigEndian.PutUint16(scratch, uint16(v.Uint())) out.Write(scratch) return nil case uint24Type: i := v.Uint() if i > 0xffffff { return structuralError{info.fieldName(), fmt.Sprintf("uint24 overflow %d", i)} } scratch := make([]byte, 4) binary.BigEndian.PutUint32(scratch, uint32(i)) out.Write(scratch[1:]) return nil case uint32Type: scratch := make([]byte, 4) binary.BigEndian.PutUint32(scratch, uint32(v.Uint())) out.Write(scratch) return nil case uint64Type: scratch := make([]byte, 8) binary.BigEndian.PutUint64(scratch, uint64(v.Uint())) out.Write(scratch) return nil } // Now deal with user-defined types. switch v.Kind() { case enumType.Kind(): i := v.Uint() if info == nil { return structuralError{info.fieldName(), "enum field tag missing"} } if err := info.check(i, prefix); err != nil { return err } scratch := make([]byte, 8) binary.BigEndian.PutUint64(scratch, uint64(i)) out.Write(scratch[(8 - info.count):]) return nil case reflect.Struct: structType := fieldType enums := make(map[string]uint64) // Values of any Enum fields // The comment parseField() describes the mapping of the TLS select(Enum) {..} construct; // here we have selector and source (rather than destination) fields. // Track which selector names we've seen (in the source field tags), and whether a source // value for that selector has been processed. selectorSeen := make(map[string]bool) for i := 0; i < structType.NumField(); i++ { // Find information about this field. tag := structType.Field(i).Tag.Get("tls") fieldInfo, err := fieldTagToFieldInfo(tag, structType.Field(i).Name) if err != nil { return err } source := v.Field(i) if fieldInfo.selector != "" { // This field is a possible source for a select(Enum) {..}. First check // the selector field name has been seen. choice, ok := enums[fieldInfo.selector] if !ok { return structuralError{fieldInfo.name, "selector not seen: " + fieldInfo.selector} } if structType.Field(i).Type.Kind() != reflect.Ptr { return structuralError{fieldInfo.name, "choice field not a pointer type"} } // Is this the first mention of the selector field name? If so, remember it. seen, ok := selectorSeen[fieldInfo.selector] if !ok { selectorSeen[fieldInfo.selector] = false } if choice != fieldInfo.val { // This source was not chosen; police that it should be nil. if v.Field(i).Pointer() != uintptr(0) { return structuralError{fieldInfo.name, "unchosen field is non-nil"} } continue } if seen { // We already saw a different source field generate the value for this // selector value, which indicates a badly annotated structure. return structuralError{fieldInfo.name, "duplicate selector value for " + fieldInfo.selector} } selectorSeen[fieldInfo.selector] = true if v.Field(i).Pointer() == uintptr(0) { return structuralError{fieldInfo.name, "chosen field is nil"} } // Marshal from the pointed-to source object. source = v.Field(i).Elem() } var fieldData bytes.Buffer if err := marshalField(&fieldData, source, fieldInfo); err != nil { return err } out.Write(fieldData.Bytes()) // Remember any tls.Enum values encountered in case they are selectors. if structType.Field(i).Type.Kind() == enumType.Kind() { enums[structType.Field(i).Name] = v.Field(i).Uint() } } // Now we have seen all fields in the structure, check that all select(Enum) {..} selector // fields found a source field to get their data from. for selector, seen := range selectorSeen { if !seen { return syntaxError{info.fieldName(), selector + ": unhandled value for selector"} } } return nil case reflect.Array: datalen := v.Len() arrayType := fieldType if arrayType.Elem().Kind() != reflect.Uint8 { // Only byte/uint8 arrays are supported return structuralError{info.fieldName(), "unsupported array type"} } bytes := make([]byte, datalen) for i := 0; i < datalen; i++ { bytes[i] = uint8(v.Index(i).Uint()) } _, err := out.Write(bytes) return err case reflect.Slice: if info == nil { return structuralError{info.fieldName(), "slice field tag missing"} } sliceType := fieldType if sliceType.Elem().Kind() == reflect.Uint8 { // Fast version for []byte: first write the length as info.count bytes. datalen := v.Len() scratch := make([]byte, 8) binary.BigEndian.PutUint64(scratch, uint64(datalen)) out.Write(scratch[(8 - info.count):]) if err := info.check(uint64(datalen), prefix); err != nil { return err } // Then just write the data. bytes := make([]byte, datalen) for i := 0; i < datalen; i++ { bytes[i] = uint8(v.Index(i).Uint()) } _, err := out.Write(bytes) return err } // General version: use a separate Buffer to write the slice entries into. var innerBuf bytes.Buffer for i := 0; i < v.Len(); i++ { if err := marshalField(&innerBuf, v.Index(i), nil); err != nil { return err } } // Now insert (and check) the size. size := uint64(innerBuf.Len()) if err := info.check(size, prefix); err != nil { return err } scratch := make([]byte, 8) binary.BigEndian.PutUint64(scratch, size) out.Write(scratch[(8 - info.count):]) // Then copy the data. _, err := out.Write(innerBuf.Bytes()) return err default: return structuralError{info.fieldName(), fmt.Sprintf("unsupported type: %s of kind %s", fieldType, v.Kind())} } } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/tls/types.go ================================================ // Copyright 2016 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package tls import ( "crypto" "crypto/dsa" //nolint:staticcheck "crypto/ecdsa" "crypto/rsa" "fmt" ) // DigitallySigned gives information about a signature, including the algorithm used // and the signature value. Defined in RFC 5246 s4.7. type DigitallySigned struct { Algorithm SignatureAndHashAlgorithm Signature []byte `tls:"minlen:0,maxlen:65535"` } func (d DigitallySigned) String() string { return fmt.Sprintf("Signature: HashAlgo=%v SignAlgo=%v Value=%x", d.Algorithm.Hash, d.Algorithm.Signature, d.Signature) } // SignatureAndHashAlgorithm gives information about the algorithms used for a // signature. Defined in RFC 5246 s7.4.1.4.1. type SignatureAndHashAlgorithm struct { Hash HashAlgorithm `tls:"maxval:255"` Signature SignatureAlgorithm `tls:"maxval:255"` } // HashAlgorithm enum from RFC 5246 s7.4.1.4.1. type HashAlgorithm Enum // HashAlgorithm constants from RFC 5246 s7.4.1.4.1. const ( None HashAlgorithm = 0 MD5 HashAlgorithm = 1 SHA1 HashAlgorithm = 2 SHA224 HashAlgorithm = 3 SHA256 HashAlgorithm = 4 SHA384 HashAlgorithm = 5 SHA512 HashAlgorithm = 6 ) func (h HashAlgorithm) String() string { switch h { case None: return "None" case MD5: return "MD5" case SHA1: return "SHA1" case SHA224: return "SHA224" case SHA256: return "SHA256" case SHA384: return "SHA384" case SHA512: return "SHA512" default: return fmt.Sprintf("UNKNOWN(%d)", h) } } // SignatureAlgorithm enum from RFC 5246 s7.4.1.4.1. type SignatureAlgorithm Enum // SignatureAlgorithm constants from RFC 5246 s7.4.1.4.1. const ( Anonymous SignatureAlgorithm = 0 RSA SignatureAlgorithm = 1 DSA SignatureAlgorithm = 2 ECDSA SignatureAlgorithm = 3 ) func (s SignatureAlgorithm) String() string { switch s { case Anonymous: return "Anonymous" case RSA: return "RSA" case DSA: return "DSA" case ECDSA: return "ECDSA" default: return fmt.Sprintf("UNKNOWN(%d)", s) } } // SignatureAlgorithmFromPubKey returns the algorithm used for this public key. // ECDSA, RSA, and DSA keys are supported. Other key types will return Anonymous. func SignatureAlgorithmFromPubKey(k crypto.PublicKey) SignatureAlgorithm { switch k.(type) { case *ecdsa.PublicKey: return ECDSA case *rsa.PublicKey: return RSA case *dsa.PublicKey: return DSA default: return Anonymous } } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/types.go ================================================ // Copyright 2015 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package ct holds core types and utilities for Certificate Transparency. package ct import ( "crypto/sha256" "encoding/base64" "encoding/json" "fmt" "github.com/google/certificate-transparency-go/tls" "github.com/google/certificate-transparency-go/x509" ) /////////////////////////////////////////////////////////////////////////////// // The following structures represent those outlined in RFC6962; any section // numbers mentioned refer to that RFC. /////////////////////////////////////////////////////////////////////////////// // LogEntryType represents the LogEntryType enum from section 3.1: // // enum { x509_entry(0), precert_entry(1), (65535) } LogEntryType; type LogEntryType tls.Enum // tls:"maxval:65535" // LogEntryType constants from section 3.1. const ( X509LogEntryType LogEntryType = 0 PrecertLogEntryType LogEntryType = 1 ) func (e LogEntryType) String() string { switch e { case X509LogEntryType: return "X509LogEntryType" case PrecertLogEntryType: return "PrecertLogEntryType" default: return fmt.Sprintf("UnknownEntryType(%d)", e) } } // RFC6962 section 2.1 requires a prefix byte on hash inputs for second preimage resistance. const ( TreeLeafPrefix = byte(0x00) TreeNodePrefix = byte(0x01) ) // MerkleLeafType represents the MerkleLeafType enum from section 3.4: // // enum { timestamped_entry(0), (255) } MerkleLeafType; type MerkleLeafType tls.Enum // tls:"maxval:255" // TimestampedEntryLeafType is the only defined MerkleLeafType constant from section 3.4. const TimestampedEntryLeafType MerkleLeafType = 0 // Entry type for an SCT func (m MerkleLeafType) String() string { switch m { case TimestampedEntryLeafType: return "TimestampedEntryLeafType" default: return fmt.Sprintf("UnknownLeafType(%d)", m) } } // Version represents the Version enum from section 3.2: // // enum { v1(0), (255) } Version; type Version tls.Enum // tls:"maxval:255" // CT Version constants from section 3.2. const ( V1 Version = 0 ) func (v Version) String() string { switch v { case V1: return "V1" default: return fmt.Sprintf("UnknownVersion(%d)", v) } } // SignatureType differentiates STH signatures from SCT signatures, see section 3.2. // // enum { certificate_timestamp(0), tree_hash(1), (255) } SignatureType; type SignatureType tls.Enum // tls:"maxval:255" // SignatureType constants from section 3.2. const ( CertificateTimestampSignatureType SignatureType = 0 TreeHashSignatureType SignatureType = 1 ) func (st SignatureType) String() string { switch st { case CertificateTimestampSignatureType: return "CertificateTimestamp" case TreeHashSignatureType: return "TreeHash" default: return fmt.Sprintf("UnknownSignatureType(%d)", st) } } // ASN1Cert type for holding the raw DER bytes of an ASN.1 Certificate // (section 3.1). type ASN1Cert struct { Data []byte `tls:"minlen:1,maxlen:16777215"` } // LogID holds the hash of the Log's public key (section 3.2). // TODO(pphaneuf): Users should be migrated to the one in the logid package. type LogID struct { KeyID [sha256.Size]byte } // PreCert represents a Precertificate (section 3.2). type PreCert struct { IssuerKeyHash [sha256.Size]byte TBSCertificate []byte `tls:"minlen:1,maxlen:16777215"` // DER-encoded TBSCertificate } // CTExtensions is a representation of the raw bytes of any CtExtension // structure (see section 3.2). // nolint: revive type CTExtensions []byte // tls:"minlen:0,maxlen:65535"` // MerkleTreeNode represents an internal node in the CT tree. type MerkleTreeNode []byte // ConsistencyProof represents a CT consistency proof (see sections 2.1.2 and // 4.4). type ConsistencyProof []MerkleTreeNode // AuditPath represents a CT inclusion proof (see sections 2.1.1 and 4.5). type AuditPath []MerkleTreeNode // LeafInput represents a serialized MerkleTreeLeaf structure. type LeafInput []byte // DigitallySigned is a local alias for tls.DigitallySigned so that we can // attach a MarshalJSON method. type DigitallySigned tls.DigitallySigned // FromBase64String populates the DigitallySigned structure from the base64 data passed in. // Returns an error if the base64 data is invalid. func (d *DigitallySigned) FromBase64String(b64 string) error { raw, err := base64.StdEncoding.DecodeString(b64) if err != nil { return fmt.Errorf("failed to unbase64 DigitallySigned: %v", err) } var ds tls.DigitallySigned if rest, err := tls.Unmarshal(raw, &ds); err != nil { return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err) } else if len(rest) > 0 { return fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest)) } *d = DigitallySigned(ds) return nil } // Base64String returns the base64 representation of the DigitallySigned struct. func (d DigitallySigned) Base64String() (string, error) { b, err := tls.Marshal(d) if err != nil { return "", err } return base64.StdEncoding.EncodeToString(b), nil } // MarshalJSON implements the json.Marshaller interface. func (d DigitallySigned) MarshalJSON() ([]byte, error) { b64, err := d.Base64String() if err != nil { return []byte{}, err } return []byte(`"` + b64 + `"`), nil } // UnmarshalJSON implements the json.Unmarshaler interface. func (d *DigitallySigned) UnmarshalJSON(b []byte) error { var content string if err := json.Unmarshal(b, &content); err != nil { return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err) } return d.FromBase64String(content) } // RawLogEntry represents the (TLS-parsed) contents of an entry in a CT log. type RawLogEntry struct { // Index is a position of the entry in the log. Index int64 // Leaf is a parsed Merkle leaf hash input. Leaf MerkleTreeLeaf // Cert is: // - A certificate if Leaf.TimestampedEntry.EntryType is X509LogEntryType. // - A precertificate if Leaf.TimestampedEntry.EntryType is // PrecertLogEntryType, in the form of a DER-encoded Certificate as // originally added (which includes the poison extension and a signature // generated over the pre-cert by the pre-cert issuer). // - Empty otherwise. Cert ASN1Cert // Chain is the issuing certificate chain starting with the issuer of Cert, // or an empty slice if Cert is empty. Chain []ASN1Cert } // LogEntry represents the (parsed) contents of an entry in a CT log. This is described // in section 3.1, but note that this structure does *not* match the TLS structure // defined there (the TLS structure is never used directly in RFC6962). type LogEntry struct { Index int64 Leaf MerkleTreeLeaf // Exactly one of the following three fields should be non-empty. X509Cert *x509.Certificate // Parsed X.509 certificate Precert *Precertificate // Extracted precertificate JSONData []byte // Chain holds the issuing certificate chain, starting with the // issuer of the leaf certificate / pre-certificate. Chain []ASN1Cert } // PrecertChainEntry holds an precertificate together with a validation chain // for it; see section 3.1. type PrecertChainEntry struct { PreCertificate ASN1Cert `tls:"minlen:1,maxlen:16777215"` CertificateChain []ASN1Cert `tls:"minlen:0,maxlen:16777215"` } // CertificateChain holds a chain of certificates, as returned as extra data // for get-entries (section 4.6). type CertificateChain struct { Entries []ASN1Cert `tls:"minlen:0,maxlen:16777215"` } // JSONDataEntry holds arbitrary data. type JSONDataEntry struct { Data []byte `tls:"minlen:0,maxlen:1677215"` } // SHA256Hash represents the output from the SHA256 hash function. type SHA256Hash [sha256.Size]byte // FromBase64String populates the SHA256 struct with the contents of the base64 data passed in. func (s *SHA256Hash) FromBase64String(b64 string) error { bs, err := base64.StdEncoding.DecodeString(b64) if err != nil { return fmt.Errorf("failed to unbase64 LogID: %v", err) } if len(bs) != sha256.Size { return fmt.Errorf("invalid SHA256 length, expected 32 but got %d", len(bs)) } copy(s[:], bs) return nil } // Base64String returns the base64 representation of this SHA256Hash. func (s SHA256Hash) Base64String() string { return base64.StdEncoding.EncodeToString(s[:]) } // MarshalJSON implements the json.Marshaller interface for SHA256Hash. func (s SHA256Hash) MarshalJSON() ([]byte, error) { return []byte(`"` + s.Base64String() + `"`), nil } // UnmarshalJSON implements the json.Unmarshaller interface. func (s *SHA256Hash) UnmarshalJSON(b []byte) error { var content string if err := json.Unmarshal(b, &content); err != nil { return fmt.Errorf("failed to unmarshal SHA256Hash: %v", err) } return s.FromBase64String(content) } // SignedTreeHead represents the structure returned by the get-sth CT method // after base64 decoding; see sections 3.5 and 4.3. type SignedTreeHead struct { Version Version `json:"sth_version"` // The version of the protocol to which the STH conforms TreeSize uint64 `json:"tree_size"` // The number of entries in the new tree Timestamp uint64 `json:"timestamp"` // The time at which the STH was created SHA256RootHash SHA256Hash `json:"sha256_root_hash"` // The root hash of the log's Merkle tree TreeHeadSignature DigitallySigned `json:"tree_head_signature"` // Log's signature over a TLS-encoded TreeHeadSignature LogID SHA256Hash `json:"log_id"` // The SHA256 hash of the log's public key } func (s SignedTreeHead) String() string { sigStr, err := s.TreeHeadSignature.Base64String() if err != nil { sigStr = tls.DigitallySigned(s.TreeHeadSignature).String() } // If the LogID field in the SignedTreeHead is empty, don't include it in // the string. var logIDStr string if id, empty := s.LogID, (SHA256Hash{}); id != empty { logIDStr = fmt.Sprintf("LogID:%s, ", id.Base64String()) } return fmt.Sprintf("{%sTreeSize:%d, Timestamp:%d, SHA256RootHash:%q, TreeHeadSignature:%q}", logIDStr, s.TreeSize, s.Timestamp, s.SHA256RootHash.Base64String(), sigStr) } // TreeHeadSignature holds the data over which the signature in an STH is // generated; see section 3.5 type TreeHeadSignature struct { Version Version `tls:"maxval:255"` SignatureType SignatureType `tls:"maxval:255"` // == TreeHashSignatureType Timestamp uint64 TreeSize uint64 SHA256RootHash SHA256Hash } // SignedCertificateTimestamp represents the structure returned by the // add-chain and add-pre-chain methods after base64 decoding; see sections // 3.2, 4.1 and 4.2. type SignedCertificateTimestamp struct { SCTVersion Version `tls:"maxval:255"` LogID LogID Timestamp uint64 Extensions CTExtensions `tls:"minlen:0,maxlen:65535"` Signature DigitallySigned // Signature over TLS-encoded CertificateTimestamp } // CertificateTimestamp is the collection of data that the signature in an // SCT is over; see section 3.2. type CertificateTimestamp struct { SCTVersion Version `tls:"maxval:255"` SignatureType SignatureType `tls:"maxval:255"` Timestamp uint64 EntryType LogEntryType `tls:"maxval:65535"` X509Entry *ASN1Cert `tls:"selector:EntryType,val:0"` PrecertEntry *PreCert `tls:"selector:EntryType,val:1"` JSONEntry *JSONDataEntry `tls:"selector:EntryType,val:32768"` Extensions CTExtensions `tls:"minlen:0,maxlen:65535"` } func (s SignedCertificateTimestamp) String() string { return fmt.Sprintf("{Version:%d LogId:%s Timestamp:%d Extensions:'%s' Signature:%v}", s.SCTVersion, base64.StdEncoding.EncodeToString(s.LogID.KeyID[:]), s.Timestamp, s.Extensions, s.Signature) } // TimestampedEntry is part of the MerkleTreeLeaf structure; see section 3.4. type TimestampedEntry struct { Timestamp uint64 EntryType LogEntryType `tls:"maxval:65535"` X509Entry *ASN1Cert `tls:"selector:EntryType,val:0"` PrecertEntry *PreCert `tls:"selector:EntryType,val:1"` JSONEntry *JSONDataEntry `tls:"selector:EntryType,val:32768"` Extensions CTExtensions `tls:"minlen:0,maxlen:65535"` } // MerkleTreeLeaf represents the deserialized structure of the hash input for the // leaves of a log's Merkle tree; see section 3.4. type MerkleTreeLeaf struct { Version Version `tls:"maxval:255"` LeafType MerkleLeafType `tls:"maxval:255"` TimestampedEntry *TimestampedEntry `tls:"selector:LeafType,val:0"` } // Precertificate represents the parsed CT Precertificate structure. type Precertificate struct { // DER-encoded pre-certificate as originally added, which includes a // poison extension and a signature generated over the pre-cert by // the pre-cert issuer (which might differ from the issuer of the final // cert, see RFC6962 s3.1). Submitted ASN1Cert // SHA256 hash of the issuing key IssuerKeyHash [sha256.Size]byte // Parsed TBSCertificate structure, held in an x509.Certificate for convenience. TBSCertificate *x509.Certificate } // X509Certificate returns the X.509 Certificate contained within the // MerkleTreeLeaf. func (m *MerkleTreeLeaf) X509Certificate() (*x509.Certificate, error) { if m.TimestampedEntry.EntryType != X509LogEntryType { return nil, fmt.Errorf("cannot call X509Certificate on a MerkleTreeLeaf that is not an X509 entry") } return x509.ParseCertificate(m.TimestampedEntry.X509Entry.Data) } // Precertificate returns the X.509 Precertificate contained within the MerkleTreeLeaf. // // The returned precertificate is embedded in an x509.Certificate, but is in the // form stored internally in the log rather than the original submitted form // (i.e. it does not include the poison extension and any changes to reflect the // final certificate's issuer have been made; see x509.BuildPrecertTBS). func (m *MerkleTreeLeaf) Precertificate() (*x509.Certificate, error) { if m.TimestampedEntry.EntryType != PrecertLogEntryType { return nil, fmt.Errorf("cannot call Precertificate on a MerkleTreeLeaf that is not a precert entry") } return x509.ParseTBSCertificate(m.TimestampedEntry.PrecertEntry.TBSCertificate) } // APIEndpoint is a string that represents one of the Certificate Transparency // Log API endpoints. type APIEndpoint string // Certificate Transparency Log API endpoints; see section 4. // WARNING: Should match the URI paths without the "/ct/v1/" prefix. If // changing these constants, may need to change those too. const ( AddChainStr APIEndpoint = "add-chain" AddPreChainStr APIEndpoint = "add-pre-chain" GetSTHStr APIEndpoint = "get-sth" GetEntriesStr APIEndpoint = "get-entries" GetProofByHashStr APIEndpoint = "get-proof-by-hash" GetSTHConsistencyStr APIEndpoint = "get-sth-consistency" GetRootsStr APIEndpoint = "get-roots" GetEntryAndProofStr APIEndpoint = "get-entry-and-proof" ) // URI paths for Log requests; see section 4. // WARNING: Should match the API endpoints, with the "/ct/v1/" prefix. If // changing these constants, may need to change those too. const ( AddChainPath = "/ct/v1/add-chain" AddPreChainPath = "/ct/v1/add-pre-chain" GetSTHPath = "/ct/v1/get-sth" GetEntriesPath = "/ct/v1/get-entries" GetProofByHashPath = "/ct/v1/get-proof-by-hash" GetSTHConsistencyPath = "/ct/v1/get-sth-consistency" GetRootsPath = "/ct/v1/get-roots" GetEntryAndProofPath = "/ct/v1/get-entry-and-proof" AddJSONPath = "/ct/v1/add-json" // Experimental addition ) // AddChainRequest represents the JSON request body sent to the add-chain and // add-pre-chain POST methods from sections 4.1 and 4.2. type AddChainRequest struct { Chain [][]byte `json:"chain"` } // AddChainResponse represents the JSON response to the add-chain and // add-pre-chain POST methods. // An SCT represents a Log's promise to integrate a [pre-]certificate into the // log within a defined period of time. type AddChainResponse struct { SCTVersion Version `json:"sct_version"` // SCT structure version ID []byte `json:"id"` // Log ID Timestamp uint64 `json:"timestamp"` // Timestamp of issuance Extensions string `json:"extensions"` // Holder for any CT extensions Signature []byte `json:"signature"` // Log signature for this SCT } // ToSignedCertificateTimestamp creates a SignedCertificateTimestamp from the // AddChainResponse. func (r *AddChainResponse) ToSignedCertificateTimestamp() (*SignedCertificateTimestamp, error) { sct := SignedCertificateTimestamp{ SCTVersion: r.SCTVersion, Timestamp: r.Timestamp, } if len(r.ID) != sha256.Size { return nil, fmt.Errorf("id is invalid length, expected %d got %d", sha256.Size, len(r.ID)) } copy(sct.LogID.KeyID[:], r.ID) exts, err := base64.StdEncoding.DecodeString(r.Extensions) if err != nil { return nil, fmt.Errorf("invalid base64 data in Extensions (%q): %v", r.Extensions, err) } sct.Extensions = CTExtensions(exts) var ds DigitallySigned if rest, err := tls.Unmarshal(r.Signature, &ds); err != nil { return nil, fmt.Errorf("tls.Unmarshal(): %s", err) } else if len(rest) > 0 { return nil, fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest)) } sct.Signature = ds return &sct, nil } // AddJSONRequest represents the JSON request body sent to the add-json POST method. // The corresponding response re-uses AddChainResponse. // This is an experimental addition not covered by RFC6962. type AddJSONRequest struct { Data interface{} `json:"data"` } // GetSTHResponse represents the JSON response to the get-sth GET method from section 4.3. type GetSTHResponse struct { TreeSize uint64 `json:"tree_size"` // Number of certs in the current tree Timestamp uint64 `json:"timestamp"` // Time that the tree was created SHA256RootHash []byte `json:"sha256_root_hash"` // Root hash of the tree TreeHeadSignature []byte `json:"tree_head_signature"` // Log signature for this STH } // ToSignedTreeHead creates a SignedTreeHead from the GetSTHResponse. func (r *GetSTHResponse) ToSignedTreeHead() (*SignedTreeHead, error) { sth := SignedTreeHead{ TreeSize: r.TreeSize, Timestamp: r.Timestamp, } if len(r.SHA256RootHash) != sha256.Size { return nil, fmt.Errorf("sha256_root_hash is invalid length, expected %d got %d", sha256.Size, len(r.SHA256RootHash)) } copy(sth.SHA256RootHash[:], r.SHA256RootHash) var ds DigitallySigned if rest, err := tls.Unmarshal(r.TreeHeadSignature, &ds); err != nil { return nil, fmt.Errorf("tls.Unmarshal(): %s", err) } else if len(rest) > 0 { return nil, fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest)) } sth.TreeHeadSignature = ds return &sth, nil } // GetSTHConsistencyResponse represents the JSON response to the get-sth-consistency // GET method from section 4.4. (The corresponding GET request has parameters 'first' and // 'second'.) type GetSTHConsistencyResponse struct { Consistency [][]byte `json:"consistency"` } // GetProofByHashResponse represents the JSON response to the get-proof-by-hash GET // method from section 4.5. (The corresponding GET request has parameters 'hash' // and 'tree_size'.) type GetProofByHashResponse struct { LeafIndex int64 `json:"leaf_index"` // The 0-based index of the end entity corresponding to the "hash" parameter. AuditPath [][]byte `json:"audit_path"` // An array of base64-encoded Merkle Tree nodes proving the inclusion of the chosen certificate. } // LeafEntry represents a leaf in the Log's Merkle tree, as returned by the get-entries // GET method from section 4.6. type LeafEntry struct { // LeafInput is a TLS-encoded MerkleTreeLeaf LeafInput []byte `json:"leaf_input"` // ExtraData holds (unsigned) extra data, normally the cert validation chain. ExtraData []byte `json:"extra_data"` } // GetEntriesResponse represents the JSON response to the get-entries GET method // from section 4.6. type GetEntriesResponse struct { Entries []LeafEntry `json:"entries"` // the list of returned entries } // GetRootsResponse represents the JSON response to the get-roots GET method from section 4.7. type GetRootsResponse struct { Certificates []string `json:"certificates"` } // GetEntryAndProofResponse represents the JSON response to the get-entry-and-proof // GET method from section 4.8. (The corresponding GET request has parameters 'leaf_index' // and 'tree_size'.) type GetEntryAndProofResponse struct { LeafInput []byte `json:"leaf_input"` // the entry itself ExtraData []byte `json:"extra_data"` // any chain provided when the entry was added to the log AuditPath [][]byte `json:"audit_path"` // the corresponding proof } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/README.md ================================================ # Important Notice This is a fork of the `crypto/x509` Go package. The original source can be found on [GitHub](https://github.com/golang/go). Be careful about making local modifications to this code as it will make maintenance harder in future. ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/cert_pool.go ================================================ // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import ( "encoding/pem" "errors" "runtime" ) // CertPool is a set of certificates. type CertPool struct { bySubjectKeyId map[string][]int byName map[string][]int certs []*Certificate } // NewCertPool returns a new, empty CertPool. func NewCertPool() *CertPool { return &CertPool{ bySubjectKeyId: make(map[string][]int), byName: make(map[string][]int), } } func (s *CertPool) copy() *CertPool { p := &CertPool{ bySubjectKeyId: make(map[string][]int, len(s.bySubjectKeyId)), byName: make(map[string][]int, len(s.byName)), certs: make([]*Certificate, len(s.certs)), } for k, v := range s.bySubjectKeyId { indexes := make([]int, len(v)) copy(indexes, v) p.bySubjectKeyId[k] = indexes } for k, v := range s.byName { indexes := make([]int, len(v)) copy(indexes, v) p.byName[k] = indexes } copy(p.certs, s.certs) return p } // SystemCertPool returns a copy of the system cert pool. // // Any mutations to the returned pool are not written to disk and do // not affect any other pool returned by SystemCertPool. // // New changes in the system cert pool might not be reflected // in subsequent calls. func SystemCertPool() (*CertPool, error) { if runtime.GOOS == "windows" { // Issue 16736, 18609: return nil, errors.New("crypto/x509: system root pool is not available on Windows") } if sysRoots := systemRootsPool(); sysRoots != nil { return sysRoots.copy(), nil } return loadSystemRoots() } // findPotentialParents returns the indexes of certificates in s which might // have signed cert. The caller must not modify the returned slice. func (s *CertPool) findPotentialParents(cert *Certificate) []int { if s == nil { return nil } var candidates []int if len(cert.AuthorityKeyId) > 0 { candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)] } if len(candidates) == 0 { candidates = s.byName[string(cert.RawIssuer)] } return candidates } func (s *CertPool) contains(cert *Certificate) bool { if s == nil { return false } candidates := s.byName[string(cert.RawSubject)] for _, c := range candidates { if s.certs[c].Equal(cert) { return true } } return false } // AddCert adds a certificate to a pool. func (s *CertPool) AddCert(cert *Certificate) { if cert == nil { panic("adding nil Certificate to CertPool") } // Check that the certificate isn't being added twice. if s.contains(cert) { return } n := len(s.certs) s.certs = append(s.certs, cert) if len(cert.SubjectKeyId) > 0 { keyId := string(cert.SubjectKeyId) s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n) } name := string(cert.RawSubject) s.byName[name] = append(s.byName[name], n) } // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates. // It appends any certificates found to s and reports whether any certificates // were successfully parsed. // // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set // of root CAs in a format suitable for this function. func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) { for len(pemCerts) > 0 { var block *pem.Block block, pemCerts = pem.Decode(pemCerts) if block == nil { break } if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { continue } cert, err := ParseCertificate(block.Bytes) if IsFatal(err) { continue } s.AddCert(cert) ok = true } return } // Subjects returns a list of the DER-encoded subjects of // all of the certificates in the pool. func (s *CertPool) Subjects() [][]byte { res := make([][]byte, len(s.certs)) for i, c := range s.certs { res[i] = c.RawSubject } return res } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/curves.go ================================================ // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import ( "crypto/elliptic" "math/big" "sync" ) // This file holds ECC curves that are not supported by the main Go crypto/elliptic // library, but which have been observed in certificates in the wild. var initonce sync.Once var p192r1 *elliptic.CurveParams func initAllCurves() { initSECP192R1() } func initSECP192R1() { // See SEC-2, section 2.2.2 p192r1 = &elliptic.CurveParams{Name: "P-192"} p192r1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16) p192r1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", 16) p192r1.B, _ = new(big.Int).SetString("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", 16) p192r1.Gx, _ = new(big.Int).SetString("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", 16) p192r1.Gy, _ = new(big.Int).SetString("07192B95FFC8DA78631011ED6B24CDD573F977A11E794811", 16) p192r1.BitSize = 192 } func secp192r1() elliptic.Curve { initonce.Do(initAllCurves) return p192r1 } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/error.go ================================================ package x509 import ( "bytes" "fmt" "strconv" "strings" ) // Error implements the error interface and describes a single error in an X.509 certificate or CRL. type Error struct { ID ErrorID Category ErrCategory Summary string Field string SpecRef string SpecText string // Fatal indicates that parsing has been aborted. Fatal bool } func (err Error) Error() string { var msg bytes.Buffer if err.ID != ErrInvalidID { if err.Fatal { msg.WriteRune('E') } else { msg.WriteRune('W') } msg.WriteString(fmt.Sprintf("%03d: ", err.ID)) } msg.WriteString(err.Summary) return msg.String() } // VerboseError creates a more verbose error string, including spec details. func (err Error) VerboseError() string { var msg bytes.Buffer msg.WriteString(err.Error()) if len(err.Field) > 0 || err.Category != UnknownCategory || len(err.SpecRef) > 0 || len(err.SpecText) > 0 { msg.WriteString(" (") needSep := false if len(err.Field) > 0 { msg.WriteString(err.Field) needSep = true } if err.Category != UnknownCategory { if needSep { msg.WriteString(": ") } msg.WriteString(err.Category.String()) needSep = true } if len(err.SpecRef) > 0 { if needSep { msg.WriteString(": ") } msg.WriteString(err.SpecRef) needSep = true } if len(err.SpecText) > 0 { if needSep { if len(err.SpecRef) > 0 { msg.WriteString(", ") } else { msg.WriteString(": ") } } msg.WriteString("'") msg.WriteString(err.SpecText) msg.WriteString("'") } msg.WriteString(")") } return msg.String() } // ErrCategory indicates the category of an x509.Error. type ErrCategory int // ErrCategory values. const ( UnknownCategory ErrCategory = iota // Errors in ASN.1 encoding InvalidASN1Encoding InvalidASN1Content InvalidASN1DER // Errors in ASN.1 relative to schema InvalidValueRange InvalidASN1Type UnexpectedAdditionalData // Errors in X.509 PoorlyFormedCertificate // Fails a SHOULD clause MalformedCertificate // Fails a MUST clause PoorlyFormedCRL // Fails a SHOULD clause MalformedCRL // Fails a MUST clause // Errors relative to CA/Browser Forum guidelines BaselineRequirementsFailure EVRequirementsFailure // Other errors InsecureAlgorithm UnrecognizedValue ) func (category ErrCategory) String() string { switch category { case InvalidASN1Encoding: return "Invalid ASN.1 encoding" case InvalidASN1Content: return "Invalid ASN.1 content" case InvalidASN1DER: return "Invalid ASN.1 distinguished encoding" case InvalidValueRange: return "Invalid value for range given in schema" case InvalidASN1Type: return "Invalid ASN.1 type for schema" case UnexpectedAdditionalData: return "Unexpected additional data present" case PoorlyFormedCertificate: return "Certificate does not comply with SHOULD clause in spec" case MalformedCertificate: return "Certificate does not comply with MUST clause in spec" case PoorlyFormedCRL: return "Certificate Revocation List does not comply with SHOULD clause in spec" case MalformedCRL: return "Certificate Revocation List does not comply with MUST clause in spec" case BaselineRequirementsFailure: return "Certificate does not comply with CA/BF baseline requirements" case EVRequirementsFailure: return "Certificate does not comply with CA/BF EV requirements" case InsecureAlgorithm: return "Certificate uses an insecure algorithm" case UnrecognizedValue: return "Certificate uses an unrecognized value" default: return fmt.Sprintf("Unknown (%d)", category) } } // ErrorID is an identifier for an x509.Error, to allow filtering. type ErrorID int // Errors implements the error interface and holds a collection of errors found in a certificate or CRL. type Errors struct { Errs []Error } // Error converts to a string. func (e *Errors) Error() string { return e.combineErrors(Error.Error) } // VerboseError creates a more verbose error string, including spec details. func (e *Errors) VerboseError() string { return e.combineErrors(Error.VerboseError) } // Fatal indicates whether e includes a fatal error func (e *Errors) Fatal() bool { return (e.FirstFatal() != nil) } // Empty indicates whether e has no errors. func (e *Errors) Empty() bool { if e == nil { return true } return len(e.Errs) == 0 } // FirstFatal returns the first fatal error in e, or nil // if there is no fatal error. func (e *Errors) FirstFatal() error { if e == nil { return nil } for _, err := range e.Errs { if err.Fatal { return err } } return nil } // AddID adds the Error identified by the given id to an x509.Errors. func (e *Errors) AddID(id ErrorID, args ...interface{}) { e.Errs = append(e.Errs, NewError(id, args...)) } func (e Errors) combineErrors(errfn func(Error) string) string { if len(e.Errs) == 0 { return "" } if len(e.Errs) == 1 { return errfn((e.Errs)[0]) } var msg bytes.Buffer msg.WriteString("Errors:") for _, err := range e.Errs { msg.WriteString("\n ") msg.WriteString(errfn(err)) } return msg.String() } // Filter creates a new Errors object with any entries from the filtered // list of IDs removed. func (e Errors) Filter(filtered []ErrorID) Errors { var results Errors eloop: for _, v := range e.Errs { for _, f := range filtered { if v.ID == f { break eloop } } results.Errs = append(results.Errs, v) } return results } // ErrorFilter builds a list of error IDs (suitable for use with Errors.Filter) from a comma-separated string. func ErrorFilter(ignore string) []ErrorID { var ids []ErrorID filters := strings.Split(ignore, ",") for _, f := range filters { v, err := strconv.Atoi(f) if err != nil { continue } ids = append(ids, ErrorID(v)) } return ids } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/errors.go ================================================ package x509 import "fmt" // To preserve error IDs, only append to this list, never insert. const ( ErrInvalidID ErrorID = iota ErrInvalidCertList ErrTrailingCertList ErrUnexpectedlyCriticalCertListExtension ErrUnexpectedlyNonCriticalCertListExtension ErrInvalidCertListAuthKeyID ErrTrailingCertListAuthKeyID ErrInvalidCertListIssuerAltName ErrInvalidCertListCRLNumber ErrTrailingCertListCRLNumber ErrNegativeCertListCRLNumber ErrInvalidCertListDeltaCRL ErrTrailingCertListDeltaCRL ErrNegativeCertListDeltaCRL ErrInvalidCertListIssuingDP ErrTrailingCertListIssuingDP ErrCertListIssuingDPMultipleTypes ErrCertListIssuingDPInvalidFullName ErrInvalidCertListFreshestCRL ErrInvalidCertListAuthInfoAccess ErrTrailingCertListAuthInfoAccess ErrUnhandledCriticalCertListExtension ErrUnexpectedlyCriticalRevokedCertExtension ErrUnexpectedlyNonCriticalRevokedCertExtension ErrInvalidRevocationReason ErrTrailingRevocationReason ErrInvalidRevocationInvalidityDate ErrTrailingRevocationInvalidityDate ErrInvalidRevocationIssuer ErrUnhandledCriticalRevokedCertExtension ErrMaxID ) // idToError gives a template x509.Error for each defined ErrorID; where the Summary // field may hold format specifiers that take field parameters. var idToError map[ErrorID]Error var errorInfo = []Error{ { ID: ErrInvalidCertList, Summary: "x509: failed to parse CertificateList: %v", Field: "CertificateList", SpecRef: "RFC 5280 s5.1", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrTrailingCertList, Summary: "x509: trailing data after CertificateList", Field: "CertificateList", SpecRef: "RFC 5280 s5.1", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrUnexpectedlyCriticalCertListExtension, Summary: "x509: certificate list extension %v marked critical but expected to be non-critical", Field: "tbsCertList.crlExtensions.*.critical", SpecRef: "RFC 5280 s5.2", Category: MalformedCRL, }, { ID: ErrUnexpectedlyNonCriticalCertListExtension, Summary: "x509: certificate list extension %v marked non-critical but expected to be critical", Field: "tbsCertList.crlExtensions.*.critical", SpecRef: "RFC 5280 s5.2", Category: MalformedCRL, }, { ID: ErrInvalidCertListAuthKeyID, Summary: "x509: failed to unmarshal certificate-list authority key-id: %v", Field: "tbsCertList.crlExtensions.*.AuthorityKeyIdentifier", SpecRef: "RFC 5280 s5.2.1", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrTrailingCertListAuthKeyID, Summary: "x509: trailing data after certificate list auth key ID", Field: "tbsCertList.crlExtensions.*.AuthorityKeyIdentifier", SpecRef: "RFC 5280 s5.2.1", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrInvalidCertListIssuerAltName, Summary: "x509: failed to parse CRL issuer alt name: %v", Field: "tbsCertList.crlExtensions.*.IssuerAltName", SpecRef: "RFC 5280 s5.2.2", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrInvalidCertListCRLNumber, Summary: "x509: failed to unmarshal certificate-list crl-number: %v", Field: "tbsCertList.crlExtensions.*.CRLNumber", SpecRef: "RFC 5280 s5.2.3", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrTrailingCertListCRLNumber, Summary: "x509: trailing data after certificate list crl-number", Field: "tbsCertList.crlExtensions.*.CRLNumber", SpecRef: "RFC 5280 s5.2.3", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrNegativeCertListCRLNumber, Summary: "x509: negative certificate list crl-number: %d", Field: "tbsCertList.crlExtensions.*.CRLNumber", SpecRef: "RFC 5280 s5.2.3", Category: MalformedCRL, Fatal: true, }, { ID: ErrInvalidCertListDeltaCRL, Summary: "x509: failed to unmarshal certificate-list delta-crl: %v", Field: "tbsCertList.crlExtensions.*.BaseCRLNumber", SpecRef: "RFC 5280 s5.2.4", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrTrailingCertListDeltaCRL, Summary: "x509: trailing data after certificate list delta-crl", Field: "tbsCertList.crlExtensions.*.BaseCRLNumber", SpecRef: "RFC 5280 s5.2.4", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrNegativeCertListDeltaCRL, Summary: "x509: negative certificate list base-crl-number: %d", Field: "tbsCertList.crlExtensions.*.BaseCRLNumber", SpecRef: "RFC 5280 s5.2.4", Category: MalformedCRL, Fatal: true, }, { ID: ErrInvalidCertListIssuingDP, Summary: "x509: failed to unmarshal certificate list issuing distribution point: %v", Field: "tbsCertList.crlExtensions.*.IssuingDistributionPoint", SpecRef: "RFC 5280 s5.2.5", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrTrailingCertListIssuingDP, Summary: "x509: trailing data after certificate list issuing distribution point", Field: "tbsCertList.crlExtensions.*.IssuingDistributionPoint", SpecRef: "RFC 5280 s5.2.5", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrCertListIssuingDPMultipleTypes, Summary: "x509: multiple cert types set in issuing-distribution-point: user:%v CA:%v attr:%v", Field: "tbsCertList.crlExtensions.*.IssuingDistributionPoint", SpecRef: "RFC 5280 s5.2.5", SpecText: "at most one of onlyContainsUserCerts, onlyContainsCACerts, and onlyContainsAttributeCerts may be set to TRUE.", Category: MalformedCRL, Fatal: true, }, { ID: ErrCertListIssuingDPInvalidFullName, Summary: "x509: failed to parse CRL issuing-distribution-point fullName: %v", Field: "tbsCertList.crlExtensions.*.IssuingDistributionPoint.distributionPoint", SpecRef: "RFC 5280 s5.2.5", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrInvalidCertListFreshestCRL, Summary: "x509: failed to unmarshal certificate list freshestCRL: %v", Field: "tbsCertList.crlExtensions.*.FreshestCRL", SpecRef: "RFC 5280 s5.2.6", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrInvalidCertListAuthInfoAccess, Summary: "x509: failed to unmarshal certificate list authority info access: %v", Field: "tbsCertList.crlExtensions.*.AuthorityInfoAccess", SpecRef: "RFC 5280 s5.2.7", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrTrailingCertListAuthInfoAccess, Summary: "x509: trailing data after certificate list authority info access", Field: "tbsCertList.crlExtensions.*.AuthorityInfoAccess", SpecRef: "RFC 5280 s5.2.7", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrUnhandledCriticalCertListExtension, Summary: "x509: unhandled critical extension in certificate list: %v", Field: "tbsCertList.revokedCertificates.crlExtensions.*", SpecRef: "RFC 5280 s5.2", SpecText: "If a CRL contains a critical extension that the application cannot process, then the application MUST NOT use that CRL to determine the status of certificates.", Category: MalformedCRL, Fatal: true, }, { ID: ErrUnexpectedlyCriticalRevokedCertExtension, Summary: "x509: revoked certificate extension %v marked critical but expected to be non-critical", Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.critical", SpecRef: "RFC 5280 s5.3", Category: MalformedCRL, }, { ID: ErrUnexpectedlyNonCriticalRevokedCertExtension, Summary: "x509: revoked certificate extension %v marked non-critical but expected to be critical", Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.critical", SpecRef: "RFC 5280 s5.3", Category: MalformedCRL, }, { ID: ErrInvalidRevocationReason, Summary: "x509: failed to parse revocation reason: %v", Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.CRLReason", SpecRef: "RFC 5280 s5.3.1", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrTrailingRevocationReason, Summary: "x509: trailing data after revoked certificate reason", Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.CRLReason", SpecRef: "RFC 5280 s5.3.1", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrInvalidRevocationInvalidityDate, Summary: "x509: failed to parse revoked certificate invalidity date: %v", Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.InvalidityDate", SpecRef: "RFC 5280 s5.3.2", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrTrailingRevocationInvalidityDate, Summary: "x509: trailing data after revoked certificate invalidity date", Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.InvalidityDate", SpecRef: "RFC 5280 s5.3.2", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrInvalidRevocationIssuer, Summary: "x509: failed to parse revocation issuer %v", Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.CertificateIssuer", SpecRef: "RFC 5280 s5.3.3", Category: InvalidASN1Content, Fatal: true, }, { ID: ErrUnhandledCriticalRevokedCertExtension, Summary: "x509: unhandled critical extension in revoked certificate: %v", Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*", SpecRef: "RFC 5280 s5.3", SpecText: "If a CRL contains a critical CRL entry extension that the application cannot process, then the application MUST NOT use that CRL to determine the status of any certificates.", Category: MalformedCRL, Fatal: true, }, } func init() { idToError = make(map[ErrorID]Error, len(errorInfo)) for _, info := range errorInfo { idToError[info.ID] = info } } // NewError builds a new x509.Error based on the template for the given id. func NewError(id ErrorID, args ...interface{}) Error { var err Error if id >= ErrMaxID { err.ID = id err.Summary = fmt.Sprintf("Unknown error ID %v: args %+v", id, args) err.Fatal = true } else { err = idToError[id] err.Summary = fmt.Sprintf(err.Summary, args...) } return err } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/names.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import ( "fmt" "net" "github.com/google/certificate-transparency-go/asn1" "github.com/google/certificate-transparency-go/x509/pkix" ) const ( // GeneralName tag values from RFC 5280, 4.2.1.6 tagOtherName = 0 tagRFC822Name = 1 tagDNSName = 2 tagX400Address = 3 tagDirectoryName = 4 tagEDIPartyName = 5 tagURI = 6 tagIPAddress = 7 tagRegisteredID = 8 ) // OtherName describes a name related to a certificate which is not in one // of the standard name formats. RFC 5280, 4.2.1.6: // // OtherName ::= SEQUENCE { // type-id OBJECT IDENTIFIER, // value [0] EXPLICIT ANY DEFINED BY type-id } type OtherName struct { TypeID asn1.ObjectIdentifier Value asn1.RawValue } // GeneralNames holds a collection of names related to a certificate. type GeneralNames struct { DNSNames []string EmailAddresses []string DirectoryNames []pkix.Name URIs []string IPNets []net.IPNet RegisteredIDs []asn1.ObjectIdentifier OtherNames []OtherName } // Len returns the total number of names in a GeneralNames object. func (gn GeneralNames) Len() int { return (len(gn.DNSNames) + len(gn.EmailAddresses) + len(gn.DirectoryNames) + len(gn.URIs) + len(gn.IPNets) + len(gn.RegisteredIDs) + len(gn.OtherNames)) } // Empty indicates whether a GeneralNames object is empty. func (gn GeneralNames) Empty() bool { return gn.Len() == 0 } func parseGeneralNames(value []byte, gname *GeneralNames) error { // RFC 5280, 4.2.1.6 // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName // // GeneralName ::= CHOICE { // otherName [0] OtherName, // rfc822Name [1] IA5String, // dNSName [2] IA5String, // x400Address [3] ORAddress, // directoryName [4] Name, // ediPartyName [5] EDIPartyName, // uniformResourceIdentifier [6] IA5String, // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } var seq asn1.RawValue var rest []byte if rest, err := asn1.Unmarshal(value, &seq); err != nil { return fmt.Errorf("x509: failed to parse GeneralNames: %v", err) } else if len(rest) != 0 { return fmt.Errorf("x509: trailing data after GeneralNames") } if !seq.IsCompound || seq.Tag != asn1.TagSequence || seq.Class != asn1.ClassUniversal { return fmt.Errorf("x509: failed to parse GeneralNames sequence, tag %+v", seq) } rest = seq.Bytes for len(rest) > 0 { var err error rest, err = parseGeneralName(rest, gname, false) if err != nil { return fmt.Errorf("x509: failed to parse GeneralName: %v", err) } } return nil } func parseGeneralName(data []byte, gname *GeneralNames, withMask bool) ([]byte, error) { var v asn1.RawValue var rest []byte var err error rest, err = asn1.Unmarshal(data, &v) if err != nil { return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames: %v", err) } switch v.Tag { case tagOtherName: if !v.IsCompound { return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.otherName: not compound") } var other OtherName v.FullBytes = append([]byte{}, v.FullBytes...) v.FullBytes[0] = asn1.TagSequence | 0x20 _, err = asn1.Unmarshal(v.FullBytes, &other) if err != nil { return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.otherName: %v", err) } gname.OtherNames = append(gname.OtherNames, other) case tagRFC822Name: gname.EmailAddresses = append(gname.EmailAddresses, string(v.Bytes)) case tagDNSName: dns := string(v.Bytes) gname.DNSNames = append(gname.DNSNames, dns) case tagDirectoryName: var rdnSeq pkix.RDNSequence if _, err := asn1.Unmarshal(v.Bytes, &rdnSeq); err != nil { return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.directoryName: %v", err) } var dirName pkix.Name dirName.FillFromRDNSequence(&rdnSeq) gname.DirectoryNames = append(gname.DirectoryNames, dirName) case tagURI: gname.URIs = append(gname.URIs, string(v.Bytes)) case tagIPAddress: vlen := len(v.Bytes) if withMask { switch vlen { case (2 * net.IPv4len), (2 * net.IPv6len): ipNet := net.IPNet{IP: v.Bytes[0 : vlen/2], Mask: v.Bytes[vlen/2:]} gname.IPNets = append(gname.IPNets, ipNet) default: return nil, fmt.Errorf("x509: invalid IP/mask length %d in GeneralNames.iPAddress", vlen) } } else { switch vlen { case net.IPv4len, net.IPv6len: ipNet := net.IPNet{IP: v.Bytes} gname.IPNets = append(gname.IPNets, ipNet) default: return nil, fmt.Errorf("x509: invalid IP length %d in GeneralNames.iPAddress", vlen) } } case tagRegisteredID: var oid asn1.ObjectIdentifier v.FullBytes = append([]byte{}, v.FullBytes...) v.FullBytes[0] = asn1.TagOID _, err = asn1.Unmarshal(v.FullBytes, &oid) if err != nil { return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.registeredID: %v", err) } gname.RegisteredIDs = append(gname.RegisteredIDs, oid) default: return nil, fmt.Errorf("x509: failed to unmarshal GeneralName: unknown tag %d", v.Tag) } return rest, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/pem_decrypt.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 // RFC 1423 describes the encryption of PEM blocks. The algorithm used to // generate a key from the password was derived by looking at the OpenSSL // implementation. import ( "crypto/aes" "crypto/cipher" "crypto/des" "crypto/md5" "encoding/hex" "encoding/pem" "errors" "io" "strings" ) type PEMCipher int // Possible values for the EncryptPEMBlock encryption algorithm. const ( _ PEMCipher = iota PEMCipherDES PEMCipher3DES PEMCipherAES128 PEMCipherAES192 PEMCipherAES256 ) // rfc1423Algo holds a method for enciphering a PEM block. type rfc1423Algo struct { cipher PEMCipher name string cipherFunc func(key []byte) (cipher.Block, error) keySize int blockSize int } // rfc1423Algos holds a slice of the possible ways to encrypt a PEM // block. The ivSize numbers were taken from the OpenSSL source. var rfc1423Algos = []rfc1423Algo{{ cipher: PEMCipherDES, name: "DES-CBC", cipherFunc: des.NewCipher, keySize: 8, blockSize: des.BlockSize, }, { cipher: PEMCipher3DES, name: "DES-EDE3-CBC", cipherFunc: des.NewTripleDESCipher, keySize: 24, blockSize: des.BlockSize, }, { cipher: PEMCipherAES128, name: "AES-128-CBC", cipherFunc: aes.NewCipher, keySize: 16, blockSize: aes.BlockSize, }, { cipher: PEMCipherAES192, name: "AES-192-CBC", cipherFunc: aes.NewCipher, keySize: 24, blockSize: aes.BlockSize, }, { cipher: PEMCipherAES256, name: "AES-256-CBC", cipherFunc: aes.NewCipher, keySize: 32, blockSize: aes.BlockSize, }, } // deriveKey uses a key derivation function to stretch the password into a key // with the number of bits our cipher requires. This algorithm was derived from // the OpenSSL source. func (c rfc1423Algo) deriveKey(password, salt []byte) []byte { hash := md5.New() out := make([]byte, c.keySize) var digest []byte for i := 0; i < len(out); i += len(digest) { hash.Reset() hash.Write(digest) hash.Write(password) hash.Write(salt) digest = hash.Sum(digest[:0]) copy(out[i:], digest) } return out } // IsEncryptedPEMBlock returns if the PEM block is password encrypted. func IsEncryptedPEMBlock(b *pem.Block) bool { _, ok := b.Headers["DEK-Info"] return ok } // IncorrectPasswordError is returned when an incorrect password is detected. var IncorrectPasswordError = errors.New("x509: decryption password incorrect") // DecryptPEMBlock takes a password encrypted PEM block and the password used to // encrypt it and returns a slice of decrypted DER encoded bytes. It inspects // the DEK-Info header to determine the algorithm used for decryption. If no // DEK-Info header is present, an error is returned. If an incorrect password // is detected an IncorrectPasswordError is returned. Because of deficiencies // in the encrypted-PEM format, it's not always possible to detect an incorrect // password. In these cases no error will be returned but the decrypted DER // bytes will be random noise. func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) { dek, ok := b.Headers["DEK-Info"] if !ok { return nil, errors.New("x509: no DEK-Info header in block") } idx := strings.Index(dek, ",") if idx == -1 { return nil, errors.New("x509: malformed DEK-Info header") } mode, hexIV := dek[:idx], dek[idx+1:] ciph := cipherByName(mode) if ciph == nil { return nil, errors.New("x509: unknown encryption mode") } iv, err := hex.DecodeString(hexIV) if err != nil { return nil, err } if len(iv) != ciph.blockSize { return nil, errors.New("x509: incorrect IV size") } // Based on the OpenSSL implementation. The salt is the first 8 bytes // of the initialization vector. key := ciph.deriveKey(password, iv[:8]) block, err := ciph.cipherFunc(key) if err != nil { return nil, err } if len(b.Bytes)%block.BlockSize() != 0 { return nil, errors.New("x509: encrypted PEM data is not a multiple of the block size") } data := make([]byte, len(b.Bytes)) dec := cipher.NewCBCDecrypter(block, iv) dec.CryptBlocks(data, b.Bytes) // Blocks are padded using a scheme where the last n bytes of padding are all // equal to n. It can pad from 1 to blocksize bytes inclusive. See RFC 1423. // For example: // [x y z 2 2] // [x y 7 7 7 7 7 7 7] // If we detect a bad padding, we assume it is an invalid password. dlen := len(data) if dlen == 0 || dlen%ciph.blockSize != 0 { return nil, errors.New("x509: invalid padding") } last := int(data[dlen-1]) if dlen < last { return nil, IncorrectPasswordError } if last == 0 || last > ciph.blockSize { return nil, IncorrectPasswordError } for _, val := range data[dlen-last:] { if int(val) != last { return nil, IncorrectPasswordError } } return data[:dlen-last], nil } // EncryptPEMBlock returns a PEM block of the specified type holding the // given DER-encoded data encrypted with the specified algorithm and // password. func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, alg PEMCipher) (*pem.Block, error) { ciph := cipherByKey(alg) if ciph == nil { return nil, errors.New("x509: unknown encryption mode") } iv := make([]byte, ciph.blockSize) if _, err := io.ReadFull(rand, iv); err != nil { return nil, errors.New("x509: cannot generate IV: " + err.Error()) } // The salt is the first 8 bytes of the initialization vector, // matching the key derivation in DecryptPEMBlock. key := ciph.deriveKey(password, iv[:8]) block, err := ciph.cipherFunc(key) if err != nil { return nil, err } enc := cipher.NewCBCEncrypter(block, iv) pad := ciph.blockSize - len(data)%ciph.blockSize encrypted := make([]byte, len(data), len(data)+pad) // We could save this copy by encrypting all the whole blocks in // the data separately, but it doesn't seem worth the additional // code. copy(encrypted, data) // See RFC 1423, Section 1.1. for i := 0; i < pad; i++ { encrypted = append(encrypted, byte(pad)) } enc.CryptBlocks(encrypted, encrypted) return &pem.Block{ Type: blockType, Headers: map[string]string{ "Proc-Type": "4,ENCRYPTED", "DEK-Info": ciph.name + "," + hex.EncodeToString(iv), }, Bytes: encrypted, }, nil } func cipherByName(name string) *rfc1423Algo { for i := range rfc1423Algos { alg := &rfc1423Algos[i] if alg.name == name { return alg } } return nil } func cipherByKey(key PEMCipher) *rfc1423Algo { for i := range rfc1423Algos { alg := &rfc1423Algos[i] if alg.cipher == key { return alg } } return nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/pkcs1.go ================================================ // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import ( "crypto/rsa" "errors" "math/big" "github.com/google/certificate-transparency-go/asn1" ) // pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key. type pkcs1PrivateKey struct { Version int N *big.Int E int D *big.Int P *big.Int Q *big.Int // We ignore these values, if present, because rsa will calculate them. Dp *big.Int `asn1:"optional"` Dq *big.Int `asn1:"optional"` Qinv *big.Int `asn1:"optional"` AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"` } type pkcs1AdditionalRSAPrime struct { Prime *big.Int // We ignore these values because rsa will calculate them. Exp *big.Int Coeff *big.Int } // pkcs1PublicKey reflects the ASN.1 structure of a PKCS#1 public key. type pkcs1PublicKey struct { N *big.Int E int } // ParsePKCS1PrivateKey parses an RSA private key in PKCS#1, ASN.1 DER form. // // This kind of key is commonly encoded in PEM blocks of type "RSA PRIVATE KEY". func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) { var priv pkcs1PrivateKey rest, err := asn1.Unmarshal(der, &priv) if len(rest) > 0 { return nil, asn1.SyntaxError{Msg: "trailing data"} } if err != nil { if _, err := asn1.Unmarshal(der, &ecPrivateKey{}); err == nil { return nil, errors.New("x509: failed to parse private key (use ParseECPrivateKey instead for this key format)") } if _, err := asn1.Unmarshal(der, &pkcs8{}); err == nil { return nil, errors.New("x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)") } return nil, err } if priv.Version > 1 { return nil, errors.New("x509: unsupported private key version") } if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 { return nil, errors.New("x509: private key contains zero or negative value") } key := new(rsa.PrivateKey) key.PublicKey = rsa.PublicKey{ E: priv.E, N: priv.N, } key.D = priv.D key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes)) key.Primes[0] = priv.P key.Primes[1] = priv.Q for i, a := range priv.AdditionalPrimes { if a.Prime.Sign() <= 0 { return nil, errors.New("x509: private key contains zero or negative prime") } key.Primes[i+2] = a.Prime // We ignore the other two values because rsa will calculate // them as needed. } err = key.Validate() if err != nil { return nil, err } key.Precompute() return key, nil } // MarshalPKCS1PrivateKey converts an RSA private key to PKCS#1, ASN.1 DER form. // // This kind of key is commonly encoded in PEM blocks of type "RSA PRIVATE KEY". // For a more flexible key format which is not RSA specific, use // MarshalPKCS8PrivateKey. func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { key.Precompute() version := 0 if len(key.Primes) > 2 { version = 1 } priv := pkcs1PrivateKey{ Version: version, N: key.N, E: key.PublicKey.E, D: key.D, P: key.Primes[0], Q: key.Primes[1], Dp: key.Precomputed.Dp, Dq: key.Precomputed.Dq, Qinv: key.Precomputed.Qinv, } priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues)) for i, values := range key.Precomputed.CRTValues { priv.AdditionalPrimes[i].Prime = key.Primes[2+i] priv.AdditionalPrimes[i].Exp = values.Exp priv.AdditionalPrimes[i].Coeff = values.Coeff } b, _ := asn1.Marshal(priv) return b } // ParsePKCS1PublicKey parses an RSA public key in PKCS#1, ASN.1 DER form. // // This kind of key is commonly encoded in PEM blocks of type "RSA PUBLIC KEY". func ParsePKCS1PublicKey(der []byte) (*rsa.PublicKey, error) { var pub pkcs1PublicKey rest, err := asn1.Unmarshal(der, &pub) if err != nil { if _, err := asn1.Unmarshal(der, &publicKeyInfo{}); err == nil { return nil, errors.New("x509: failed to parse public key (use ParsePKIXPublicKey instead for this key format)") } return nil, err } if len(rest) > 0 { return nil, asn1.SyntaxError{Msg: "trailing data"} } if pub.N.Sign() <= 0 || pub.E <= 0 { return nil, errors.New("x509: public key contains zero or negative value") } if pub.E > 1<<31-1 { return nil, errors.New("x509: public key contains large public exponent") } return &rsa.PublicKey{ E: pub.E, N: pub.N, }, nil } // MarshalPKCS1PublicKey converts an RSA public key to PKCS#1, ASN.1 DER form. // // This kind of key is commonly encoded in PEM blocks of type "RSA PUBLIC KEY". func MarshalPKCS1PublicKey(key *rsa.PublicKey) []byte { derBytes, _ := asn1.Marshal(pkcs1PublicKey{ N: key.N, E: key.E, }) return derBytes } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/pkcs8.go ================================================ // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import ( "crypto/ecdsa" "crypto/rsa" "errors" "fmt" "github.com/google/certificate-transparency-go/asn1" "github.com/google/certificate-transparency-go/x509/pkix" // TODO(robpercival): change this to crypto/ed25519 when Go 1.13 is min version "golang.org/x/crypto/ed25519" ) // pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn // and RFC 5208. type pkcs8 struct { Version int Algo pkix.AlgorithmIdentifier PrivateKey []byte // optional attributes omitted. } // ParsePKCS8PrivateKey parses an unencrypted private key in PKCS#8, ASN.1 DER form. // // It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, or a ed25519.PrivateKey. // More types might be supported in the future. // // This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY". func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { var privKey pkcs8 if _, err := asn1.Unmarshal(der, &privKey); err != nil { if _, err := asn1.Unmarshal(der, &ecPrivateKey{}); err == nil { return nil, errors.New("x509: failed to parse private key (use ParseECPrivateKey instead for this key format)") } if _, err := asn1.Unmarshal(der, &pkcs1PrivateKey{}); err == nil { return nil, errors.New("x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)") } return nil, err } switch { case privKey.Algo.Algorithm.Equal(OIDPublicKeyRSA): key, err = ParsePKCS1PrivateKey(privKey.PrivateKey) if err != nil { return nil, errors.New("x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error()) } return key, nil case privKey.Algo.Algorithm.Equal(OIDPublicKeyECDSA): bytes := privKey.Algo.Parameters.FullBytes namedCurveOID := new(asn1.ObjectIdentifier) if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil { namedCurveOID = nil } key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey) if err != nil { return nil, errors.New("x509: failed to parse EC private key embedded in PKCS#8: " + err.Error()) } return key, nil case privKey.Algo.Algorithm.Equal(OIDPublicKeyEd25519): if l := len(privKey.Algo.Parameters.FullBytes); l != 0 { return nil, errors.New("x509: invalid Ed25519 private key parameters") } var curvePrivateKey []byte if _, err := asn1.Unmarshal(privKey.PrivateKey, &curvePrivateKey); err != nil { return nil, fmt.Errorf("x509: invalid Ed25519 private key: %v", err) } if l := len(curvePrivateKey); l != ed25519.SeedSize { return nil, fmt.Errorf("x509: invalid Ed25519 private key length: %d", l) } return ed25519.NewKeyFromSeed(curvePrivateKey), nil default: return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm) } } // MarshalPKCS8PrivateKey converts a private key to PKCS#8, ASN.1 DER form. // // The following key types are currently supported: *rsa.PrivateKey, *ecdsa.PrivateKey // and ed25519.PrivateKey. Unsupported key types result in an error. // // This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY". func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) { var privKey pkcs8 switch k := key.(type) { case *rsa.PrivateKey: privKey.Algo = pkix.AlgorithmIdentifier{ Algorithm: OIDPublicKeyRSA, Parameters: asn1.NullRawValue, } privKey.PrivateKey = MarshalPKCS1PrivateKey(k) case *ecdsa.PrivateKey: oid, ok := OIDFromNamedCurve(k.Curve) if !ok { return nil, errors.New("x509: unknown curve while marshaling to PKCS#8") } oidBytes, err := asn1.Marshal(oid) if err != nil { return nil, errors.New("x509: failed to marshal curve OID: " + err.Error()) } privKey.Algo = pkix.AlgorithmIdentifier{ Algorithm: OIDPublicKeyECDSA, Parameters: asn1.RawValue{ FullBytes: oidBytes, }, } if privKey.PrivateKey, err = marshalECPrivateKeyWithOID(k, nil); err != nil { return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error()) } case ed25519.PrivateKey: privKey.Algo = pkix.AlgorithmIdentifier{ Algorithm: OIDPublicKeyEd25519, } curvePrivateKey, err := asn1.Marshal(k.Seed()) if err != nil { return nil, fmt.Errorf("x509: failed to marshal private key: %v", err) } privKey.PrivateKey = curvePrivateKey default: return nil, fmt.Errorf("x509: unknown key type while marshaling PKCS#8: %T", key) } return asn1.Marshal(privKey) } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/pkix/pkix.go ================================================ // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package pkix contains shared, low level structures used for ASN.1 parsing // and serialization of X.509 certificates, CRL and OCSP. package pkix import ( "encoding/hex" "fmt" "math/big" "time" "github.com/google/certificate-transparency-go/asn1" ) // AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC // 5280, section 4.1.1.2. type AlgorithmIdentifier struct { Algorithm asn1.ObjectIdentifier Parameters asn1.RawValue `asn1:"optional"` } type RDNSequence []RelativeDistinguishedNameSET var attributeTypeNames = map[string]string{ "2.5.4.6": "C", "2.5.4.10": "O", "2.5.4.11": "OU", "2.5.4.3": "CN", "2.5.4.5": "SERIALNUMBER", "2.5.4.7": "L", "2.5.4.8": "ST", "2.5.4.9": "STREET", "2.5.4.17": "POSTALCODE", } // String returns a string representation of the sequence r, // roughly following the RFC 2253 Distinguished Names syntax. func (r RDNSequence) String() string { s := "" for i := 0; i < len(r); i++ { rdn := r[len(r)-1-i] if i > 0 { s += "," } for j, tv := range rdn { if j > 0 { s += "+" } oidString := tv.Type.String() typeName, ok := attributeTypeNames[oidString] if !ok { derBytes, err := asn1.Marshal(tv.Value) if err == nil { s += oidString + "=#" + hex.EncodeToString(derBytes) continue // No value escaping necessary. } typeName = oidString } valueString := fmt.Sprint(tv.Value) escaped := make([]rune, 0, len(valueString)) for k, c := range valueString { escape := false switch c { case ',', '+', '"', '\\', '<', '>', ';': escape = true case ' ': escape = k == 0 || k == len(valueString)-1 case '#': escape = k == 0 } if escape { escaped = append(escaped, '\\', c) } else { escaped = append(escaped, c) } } s += typeName + "=" + string(escaped) } } return s } type RelativeDistinguishedNameSET []AttributeTypeAndValue // AttributeTypeAndValue mirrors the ASN.1 structure of the same name in // RFC 5280, Section 4.1.2.4. type AttributeTypeAndValue struct { Type asn1.ObjectIdentifier Value interface{} } // AttributeTypeAndValueSET represents a set of ASN.1 sequences of // AttributeTypeAndValue sequences from RFC 2986 (PKCS #10). type AttributeTypeAndValueSET struct { Type asn1.ObjectIdentifier Value [][]AttributeTypeAndValue `asn1:"set"` } // Extension represents the ASN.1 structure of the same name. See RFC // 5280, section 4.2. type Extension struct { Id asn1.ObjectIdentifier Critical bool `asn1:"optional"` Value []byte } // Name represents an X.509 distinguished name. This only includes the common // elements of a DN. When parsing, all elements are stored in Names and // non-standard elements can be extracted from there. When marshaling, elements // in ExtraNames are appended and override other values with the same OID. type Name struct { Country, Organization, OrganizationalUnit []string Locality, Province []string StreetAddress, PostalCode []string SerialNumber, CommonName string Names []AttributeTypeAndValue ExtraNames []AttributeTypeAndValue } func (n *Name) FillFromRDNSequence(rdns *RDNSequence) { for _, rdn := range *rdns { if len(rdn) == 0 { continue } for _, atv := range rdn { n.Names = append(n.Names, atv) value, ok := atv.Value.(string) if !ok { continue } t := atv.Type if len(t) == 4 && t[0] == OIDAttribute[0] && t[1] == OIDAttribute[1] && t[2] == OIDAttribute[2] { switch t[3] { case OIDCommonName[3]: n.CommonName = value case OIDSerialNumber[3]: n.SerialNumber = value case OIDCountry[3]: n.Country = append(n.Country, value) case OIDLocality[3]: n.Locality = append(n.Locality, value) case OIDProvince[3]: n.Province = append(n.Province, value) case OIDStreetAddress[3]: n.StreetAddress = append(n.StreetAddress, value) case OIDOrganization[3]: n.Organization = append(n.Organization, value) case OIDOrganizationalUnit[3]: n.OrganizationalUnit = append(n.OrganizationalUnit, value) case OIDPostalCode[3]: n.PostalCode = append(n.PostalCode, value) } } } } } var ( OIDAttribute = asn1.ObjectIdentifier{2, 5, 4} OIDCountry = asn1.ObjectIdentifier{2, 5, 4, 6} OIDOrganization = asn1.ObjectIdentifier{2, 5, 4, 10} OIDOrganizationalUnit = asn1.ObjectIdentifier{2, 5, 4, 11} OIDCommonName = asn1.ObjectIdentifier{2, 5, 4, 3} OIDSerialNumber = asn1.ObjectIdentifier{2, 5, 4, 5} OIDLocality = asn1.ObjectIdentifier{2, 5, 4, 7} OIDProvince = asn1.ObjectIdentifier{2, 5, 4, 8} OIDStreetAddress = asn1.ObjectIdentifier{2, 5, 4, 9} OIDPostalCode = asn1.ObjectIdentifier{2, 5, 4, 17} OIDPseudonym = asn1.ObjectIdentifier{2, 5, 4, 65} OIDTitle = asn1.ObjectIdentifier{2, 5, 4, 12} OIDDnQualifier = asn1.ObjectIdentifier{2, 5, 4, 46} OIDName = asn1.ObjectIdentifier{2, 5, 4, 41} OIDSurname = asn1.ObjectIdentifier{2, 5, 4, 4} OIDGivenName = asn1.ObjectIdentifier{2, 5, 4, 42} OIDInitials = asn1.ObjectIdentifier{2, 5, 4, 43} OIDGenerationQualifier = asn1.ObjectIdentifier{2, 5, 4, 44} ) // appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence // and returns the new value. The relativeDistinguishedNameSET contains an // attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and // search for AttributeTypeAndValue. func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence { if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) { return in } s := make([]AttributeTypeAndValue, len(values)) for i, value := range values { s[i].Type = oid s[i].Value = value } return append(in, s) } func (n Name) ToRDNSequence() (ret RDNSequence) { ret = n.appendRDNs(ret, n.Country, OIDCountry) ret = n.appendRDNs(ret, n.Province, OIDProvince) ret = n.appendRDNs(ret, n.Locality, OIDLocality) ret = n.appendRDNs(ret, n.StreetAddress, OIDStreetAddress) ret = n.appendRDNs(ret, n.PostalCode, OIDPostalCode) ret = n.appendRDNs(ret, n.Organization, OIDOrganization) ret = n.appendRDNs(ret, n.OrganizationalUnit, OIDOrganizationalUnit) if len(n.CommonName) > 0 { ret = n.appendRDNs(ret, []string{n.CommonName}, OIDCommonName) } if len(n.SerialNumber) > 0 { ret = n.appendRDNs(ret, []string{n.SerialNumber}, OIDSerialNumber) } for _, atv := range n.ExtraNames { ret = append(ret, []AttributeTypeAndValue{atv}) } return ret } // String returns the string form of n, roughly following // the RFC 2253 Distinguished Names syntax. func (n Name) String() string { return n.ToRDNSequence().String() } // oidInAttributeTypeAndValue reports whether a type with the given OID exists // in atv. func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool { for _, a := range atv { if a.Type.Equal(oid) { return true } } return false } // CertificateList represents the ASN.1 structure of the same name. See RFC // 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the // signature. type CertificateList struct { TBSCertList TBSCertificateList SignatureAlgorithm AlgorithmIdentifier SignatureValue asn1.BitString } // HasExpired reports whether certList should have been updated by now. func (certList *CertificateList) HasExpired(now time.Time) bool { return !now.Before(certList.TBSCertList.NextUpdate) } // TBSCertificateList represents the ASN.1 structure TBSCertList. See RFC // 5280, section 5.1. type TBSCertificateList struct { Raw asn1.RawContent Version int `asn1:"optional,default:0"` Signature AlgorithmIdentifier Issuer RDNSequence ThisUpdate time.Time NextUpdate time.Time `asn1:"optional"` RevokedCertificates []RevokedCertificate `asn1:"optional"` Extensions []Extension `asn1:"tag:0,optional,explicit"` } // RevokedCertificate represents the unnamed ASN.1 structure that makes up the // revokedCertificates member of the TBSCertList structure. See RFC // 5280, section 5.1. type RevokedCertificate struct { SerialNumber *big.Int RevocationTime time.Time Extensions []Extension `asn1:"optional"` } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/ptr_sysptr_windows.go ================================================ // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build go1.11 // +build go1.11 package x509 import ( "syscall" "unsafe" ) // For Go versions >= 1.11, the ExtraPolicyPara field in // syscall.CertChainPolicyPara is of type syscall.Pointer. See: // https://github.com/golang/go/commit/4869ec00e87ef func convertToPolicyParaType(p unsafe.Pointer) syscall.Pointer { return (syscall.Pointer)(p) } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/ptr_uint_windows.go ================================================ // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !go1.11 // +build !go1.11 package x509 import "unsafe" // For Go versions before 1.11, the ExtraPolicyPara field in // syscall.CertChainPolicyPara was of type uintptr. See: // https://github.com/golang/go/commit/4869ec00e87ef func convertToPolicyParaType(p unsafe.Pointer) uintptr { return uintptr(p) } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/revoked.go ================================================ // Copyright 2017 Google LLC. All Rights Reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import ( "bytes" "encoding/pem" "time" "github.com/google/certificate-transparency-go/asn1" "github.com/google/certificate-transparency-go/x509/pkix" ) // OID values for CRL extensions (TBSCertList.Extensions), RFC 5280 s5.2. var ( OIDExtensionCRLNumber = asn1.ObjectIdentifier{2, 5, 29, 20} OIDExtensionDeltaCRLIndicator = asn1.ObjectIdentifier{2, 5, 29, 27} OIDExtensionIssuingDistributionPoint = asn1.ObjectIdentifier{2, 5, 29, 28} ) // OID values for CRL entry extensions (RevokedCertificate.Extensions), RFC 5280 s5.3 var ( OIDExtensionCRLReasons = asn1.ObjectIdentifier{2, 5, 29, 21} OIDExtensionInvalidityDate = asn1.ObjectIdentifier{2, 5, 29, 24} OIDExtensionCertificateIssuer = asn1.ObjectIdentifier{2, 5, 29, 29} ) // RevocationReasonCode represents the reason for a certificate revocation; see RFC 5280 s5.3.1. type RevocationReasonCode asn1.Enumerated // RevocationReasonCode values. var ( Unspecified = RevocationReasonCode(0) KeyCompromise = RevocationReasonCode(1) CACompromise = RevocationReasonCode(2) AffiliationChanged = RevocationReasonCode(3) Superseded = RevocationReasonCode(4) CessationOfOperation = RevocationReasonCode(5) CertificateHold = RevocationReasonCode(6) RemoveFromCRL = RevocationReasonCode(8) PrivilegeWithdrawn = RevocationReasonCode(9) AACompromise = RevocationReasonCode(10) ) // ReasonFlag holds a bitmask of applicable revocation reasons, from RFC 5280 s4.2.1.13 type ReasonFlag int // ReasonFlag values. const ( UnusedFlag ReasonFlag = 1 << iota KeyCompromiseFlag CACompromiseFlag AffiliationChangedFlag SupersededFlag CessationOfOperationFlag CertificateHoldFlag PrivilegeWithdrawnFlag AACompromiseFlag ) // CertificateList represents the ASN.1 structure of the same name from RFC 5280, s5.1. // It has the same content as pkix.CertificateList, but the contents include parsed versions // of any extensions. type CertificateList struct { Raw asn1.RawContent TBSCertList TBSCertList SignatureAlgorithm pkix.AlgorithmIdentifier SignatureValue asn1.BitString } // ExpiredAt reports whether now is past the expiry time of certList. func (certList *CertificateList) ExpiredAt(now time.Time) bool { return now.After(certList.TBSCertList.NextUpdate) } // Indication of whether extensions need to be critical or non-critical. Extensions that // can be either are omitted from the map. var listExtCritical = map[string]bool{ // From RFC 5280... OIDExtensionAuthorityKeyId.String(): false, // s5.2.1 OIDExtensionIssuerAltName.String(): false, // s5.2.2 OIDExtensionCRLNumber.String(): false, // s5.2.3 OIDExtensionDeltaCRLIndicator.String(): true, // s5.2.4 OIDExtensionIssuingDistributionPoint.String(): true, // s5.2.5 OIDExtensionFreshestCRL.String(): false, // s5.2.6 OIDExtensionAuthorityInfoAccess.String(): false, // s5.2.7 } var certExtCritical = map[string]bool{ // From RFC 5280... OIDExtensionCRLReasons.String(): false, // s5.3.1 OIDExtensionInvalidityDate.String(): false, // s5.3.2 OIDExtensionCertificateIssuer.String(): true, // s5.3.3 } // IssuingDistributionPoint represents the ASN.1 structure of the same // name type IssuingDistributionPoint struct { DistributionPoint distributionPointName `asn1:"optional,tag:0"` OnlyContainsUserCerts bool `asn1:"optional,tag:1"` OnlyContainsCACerts bool `asn1:"optional,tag:2"` OnlySomeReasons asn1.BitString `asn1:"optional,tag:3"` IndirectCRL bool `asn1:"optional,tag:4"` OnlyContainsAttributeCerts bool `asn1:"optional,tag:5"` } // TBSCertList represents the ASN.1 structure of the same name from RFC // 5280, section 5.1. It has the same content as pkix.TBSCertificateList // but the extensions are included in a parsed format. type TBSCertList struct { Raw asn1.RawContent Version int Signature pkix.AlgorithmIdentifier Issuer pkix.RDNSequence ThisUpdate time.Time NextUpdate time.Time RevokedCertificates []*RevokedCertificate Extensions []pkix.Extension // Cracked out extensions: AuthorityKeyID []byte IssuerAltNames GeneralNames CRLNumber int BaseCRLNumber int // -1 if no delta CRL present IssuingDistributionPoint IssuingDistributionPoint IssuingDPFullNames GeneralNames FreshestCRLDistributionPoint []string OCSPServer []string IssuingCertificateURL []string } // ParseCertificateList parses a CertificateList (e.g. a CRL) from the given // bytes. It's often the case that PEM encoded CRLs will appear where they // should be DER encoded, so this function will transparently handle PEM // encoding as long as there isn't any leading garbage. func ParseCertificateList(clBytes []byte) (*CertificateList, error) { if bytes.HasPrefix(clBytes, pemCRLPrefix) { block, _ := pem.Decode(clBytes) if block != nil && block.Type == pemType { clBytes = block.Bytes } } return ParseCertificateListDER(clBytes) } // ParseCertificateListDER parses a DER encoded CertificateList from the given bytes. // For non-fatal errors, this function returns both an error and a CertificateList // object. func ParseCertificateListDER(derBytes []byte) (*CertificateList, error) { var errs Errors // First parse the DER into the pkix structures. pkixList := new(pkix.CertificateList) if rest, err := asn1.Unmarshal(derBytes, pkixList); err != nil { errs.AddID(ErrInvalidCertList, err) return nil, &errs } else if len(rest) != 0 { errs.AddID(ErrTrailingCertList) return nil, &errs } // Transcribe the revoked certs but crack out extensions. revokedCerts := make([]*RevokedCertificate, len(pkixList.TBSCertList.RevokedCertificates)) for i, pkixRevoked := range pkixList.TBSCertList.RevokedCertificates { revokedCerts[i] = parseRevokedCertificate(pkixRevoked, &errs) if revokedCerts[i] == nil { return nil, &errs } } certList := CertificateList{ Raw: derBytes, TBSCertList: TBSCertList{ Raw: pkixList.TBSCertList.Raw, Version: pkixList.TBSCertList.Version, Signature: pkixList.TBSCertList.Signature, Issuer: pkixList.TBSCertList.Issuer, ThisUpdate: pkixList.TBSCertList.ThisUpdate, NextUpdate: pkixList.TBSCertList.NextUpdate, RevokedCertificates: revokedCerts, Extensions: pkixList.TBSCertList.Extensions, CRLNumber: -1, BaseCRLNumber: -1, }, SignatureAlgorithm: pkixList.SignatureAlgorithm, SignatureValue: pkixList.SignatureValue, } // Now crack out extensions. for _, e := range certList.TBSCertList.Extensions { if expectCritical, present := listExtCritical[e.Id.String()]; present { if e.Critical && !expectCritical { errs.AddID(ErrUnexpectedlyCriticalCertListExtension, e.Id) } else if !e.Critical && expectCritical { errs.AddID(ErrUnexpectedlyNonCriticalCertListExtension, e.Id) } } switch { case e.Id.Equal(OIDExtensionAuthorityKeyId): // RFC 5280 s5.2.1 var a authKeyId if rest, err := asn1.Unmarshal(e.Value, &a); err != nil { errs.AddID(ErrInvalidCertListAuthKeyID, err) } else if len(rest) != 0 { errs.AddID(ErrTrailingCertListAuthKeyID) } certList.TBSCertList.AuthorityKeyID = a.Id case e.Id.Equal(OIDExtensionIssuerAltName): // RFC 5280 s5.2.2 if err := parseGeneralNames(e.Value, &certList.TBSCertList.IssuerAltNames); err != nil { errs.AddID(ErrInvalidCertListIssuerAltName, err) } case e.Id.Equal(OIDExtensionCRLNumber): // RFC 5280 s5.2.3 if rest, err := asn1.Unmarshal(e.Value, &certList.TBSCertList.CRLNumber); err != nil { errs.AddID(ErrInvalidCertListCRLNumber, err) } else if len(rest) != 0 { errs.AddID(ErrTrailingCertListCRLNumber) } if certList.TBSCertList.CRLNumber < 0 { errs.AddID(ErrNegativeCertListCRLNumber, certList.TBSCertList.CRLNumber) } case e.Id.Equal(OIDExtensionDeltaCRLIndicator): // RFC 5280 s5.2.4 if rest, err := asn1.Unmarshal(e.Value, &certList.TBSCertList.BaseCRLNumber); err != nil { errs.AddID(ErrInvalidCertListDeltaCRL, err) } else if len(rest) != 0 { errs.AddID(ErrTrailingCertListDeltaCRL) } if certList.TBSCertList.BaseCRLNumber < 0 { errs.AddID(ErrNegativeCertListDeltaCRL, certList.TBSCertList.BaseCRLNumber) } case e.Id.Equal(OIDExtensionIssuingDistributionPoint): parseIssuingDistributionPoint(e.Value, &certList.TBSCertList.IssuingDistributionPoint, &certList.TBSCertList.IssuingDPFullNames, &errs) case e.Id.Equal(OIDExtensionFreshestCRL): // RFC 5280 s5.2.6 if err := parseDistributionPoints(e.Value, &certList.TBSCertList.FreshestCRLDistributionPoint); err != nil { errs.AddID(ErrInvalidCertListFreshestCRL, err) return nil, err } case e.Id.Equal(OIDExtensionAuthorityInfoAccess): // RFC 5280 s5.2.7 var aia []accessDescription if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil { errs.AddID(ErrInvalidCertListAuthInfoAccess, err) } else if len(rest) != 0 { errs.AddID(ErrTrailingCertListAuthInfoAccess) } for _, v := range aia { // GeneralName: uniformResourceIdentifier [6] IA5String if v.Location.Tag != tagURI { continue } switch { case v.Method.Equal(OIDAuthorityInfoAccessOCSP): certList.TBSCertList.OCSPServer = append(certList.TBSCertList.OCSPServer, string(v.Location.Bytes)) case v.Method.Equal(OIDAuthorityInfoAccessIssuers): certList.TBSCertList.IssuingCertificateURL = append(certList.TBSCertList.IssuingCertificateURL, string(v.Location.Bytes)) } // TODO(drysdale): cope with more possibilities } default: if e.Critical { errs.AddID(ErrUnhandledCriticalCertListExtension, e.Id) } } } if errs.Fatal() { return nil, &errs } if errs.Empty() { return &certList, nil } return &certList, &errs } func parseIssuingDistributionPoint(data []byte, idp *IssuingDistributionPoint, name *GeneralNames, errs *Errors) { // RFC 5280 s5.2.5 if rest, err := asn1.Unmarshal(data, idp); err != nil { errs.AddID(ErrInvalidCertListIssuingDP, err) } else if len(rest) != 0 { errs.AddID(ErrTrailingCertListIssuingDP) } typeCount := 0 if idp.OnlyContainsUserCerts { typeCount++ } if idp.OnlyContainsCACerts { typeCount++ } if idp.OnlyContainsAttributeCerts { typeCount++ } if typeCount > 1 { errs.AddID(ErrCertListIssuingDPMultipleTypes, idp.OnlyContainsUserCerts, idp.OnlyContainsCACerts, idp.OnlyContainsAttributeCerts) } for _, fn := range idp.DistributionPoint.FullName { if _, err := parseGeneralName(fn.FullBytes, name, false); err != nil { errs.AddID(ErrCertListIssuingDPInvalidFullName, err) } } } // RevokedCertificate represents the unnamed ASN.1 structure that makes up the // revokedCertificates member of the TBSCertList structure from RFC 5280, s5.1. // It has the same content as pkix.RevokedCertificate but the extensions are // included in a parsed format. type RevokedCertificate struct { pkix.RevokedCertificate // Cracked out extensions: RevocationReason RevocationReasonCode InvalidityDate time.Time Issuer GeneralNames } func parseRevokedCertificate(pkixRevoked pkix.RevokedCertificate, errs *Errors) *RevokedCertificate { result := RevokedCertificate{RevokedCertificate: pkixRevoked} for _, e := range pkixRevoked.Extensions { if expectCritical, present := certExtCritical[e.Id.String()]; present { if e.Critical && !expectCritical { errs.AddID(ErrUnexpectedlyCriticalRevokedCertExtension, e.Id) } else if !e.Critical && expectCritical { errs.AddID(ErrUnexpectedlyNonCriticalRevokedCertExtension, e.Id) } } switch { case e.Id.Equal(OIDExtensionCRLReasons): // RFC 5280, s5.3.1 var reason asn1.Enumerated if rest, err := asn1.Unmarshal(e.Value, &reason); err != nil { errs.AddID(ErrInvalidRevocationReason, err) } else if len(rest) != 0 { errs.AddID(ErrTrailingRevocationReason) } result.RevocationReason = RevocationReasonCode(reason) case e.Id.Equal(OIDExtensionInvalidityDate): // RFC 5280, s5.3.2 if rest, err := asn1.Unmarshal(e.Value, &result.InvalidityDate); err != nil { errs.AddID(ErrInvalidRevocationInvalidityDate, err) } else if len(rest) != 0 { errs.AddID(ErrTrailingRevocationInvalidityDate) } case e.Id.Equal(OIDExtensionCertificateIssuer): // RFC 5280, s5.3.3 if err := parseGeneralNames(e.Value, &result.Issuer); err != nil { errs.AddID(ErrInvalidRevocationIssuer, err) } default: if e.Critical { errs.AddID(ErrUnhandledCriticalRevokedCertExtension, e.Id) } } } return &result } // CheckCertificateListSignature checks that the signature in crl is from c. func (c *Certificate) CheckCertificateListSignature(crl *CertificateList) error { algo := SignatureAlgorithmFromAI(crl.SignatureAlgorithm) return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign()) } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import "sync" var ( once sync.Once systemRoots *CertPool systemRootsErr error ) func systemRootsPool() *CertPool { once.Do(initSystemRoots) return systemRoots } func initSystemRoots() { systemRoots, systemRootsErr = loadSystemRoots() if systemRootsErr != nil { systemRoots = nil } } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_aix.go ================================================ // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 // Possible certificate files; stop after finding one. var certFiles = []string{ "/var/ssl/certs/ca-bundle.crt", } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_bsd.go ================================================ // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build dragonfly || freebsd || netbsd || openbsd // +build dragonfly freebsd netbsd openbsd package x509 // Possible certificate files; stop after finding one. var certFiles = []string{ "/usr/local/etc/ssl/cert.pem", // FreeBSD "/etc/ssl/cert.pem", // OpenBSD "/usr/local/share/certs/ca-root-nss.crt", // DragonFly "/etc/openssl/certs/ca-certificates.crt", // NetBSD } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_cgo_darwin.go ================================================ // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build cgo && !arm && !arm64 && !ios // +build cgo,!arm,!arm64,!ios package x509 /* #cgo CFLAGS: -mmacosx-version-min=10.10 -D__MAC_OS_X_VERSION_MAX_ALLOWED=101300 #cgo LDFLAGS: -framework CoreFoundation -framework Security #include #include #include #include static Boolean isSSLPolicy(SecPolicyRef policyRef) { if (!policyRef) { return false; } CFDictionaryRef properties = SecPolicyCopyProperties(policyRef); if (properties == NULL) { return false; } Boolean isSSL = false; CFTypeRef value = NULL; if (CFDictionaryGetValueIfPresent(properties, kSecPolicyOid, (const void **)&value)) { isSSL = CFEqual(value, kSecPolicyAppleSSL); } CFRelease(properties); return isSSL; } // sslTrustSettingsResult obtains the final kSecTrustSettingsResult value // for a certificate in the user or admin domain, combining usage constraints // for the SSL SecTrustSettingsPolicy, ignoring SecTrustSettingsKeyUsage and // kSecTrustSettingsAllowedError. // https://developer.apple.com/documentation/security/1400261-sectrustsettingscopytrustsetting static SInt32 sslTrustSettingsResult(SecCertificateRef cert) { CFArrayRef trustSettings = NULL; OSStatus err = SecTrustSettingsCopyTrustSettings(cert, kSecTrustSettingsDomainUser, &trustSettings); // According to Apple's SecTrustServer.c, "user trust settings overrule admin trust settings", // but the rules of the override are unclear. Let's assume admin trust settings are applicable // if and only if user trust settings fail to load or are NULL. if (err != errSecSuccess || trustSettings == NULL) { if (trustSettings != NULL) CFRelease(trustSettings); err = SecTrustSettingsCopyTrustSettings(cert, kSecTrustSettingsDomainAdmin, &trustSettings); } // > no trust settings [...] means "this certificate must be verified to a known trusted certificate” // (Should this cause a fallback from user to admin domain? It's unclear.) if (err != errSecSuccess || trustSettings == NULL) { if (trustSettings != NULL) CFRelease(trustSettings); return kSecTrustSettingsResultUnspecified; } // > An empty trust settings array means "always trust this certificate” with an // > overall trust setting for the certificate of kSecTrustSettingsResultTrustRoot. if (CFArrayGetCount(trustSettings) == 0) { CFRelease(trustSettings); return kSecTrustSettingsResultTrustRoot; } // kSecTrustSettingsResult is defined as CFSTR("kSecTrustSettingsResult"), // but the Go linker's internal linking mode can't handle CFSTR relocations. // Create our own dynamic string instead and release it below. CFStringRef _kSecTrustSettingsResult = CFStringCreateWithCString( NULL, "kSecTrustSettingsResult", kCFStringEncodingUTF8); CFStringRef _kSecTrustSettingsPolicy = CFStringCreateWithCString( NULL, "kSecTrustSettingsPolicy", kCFStringEncodingUTF8); CFStringRef _kSecTrustSettingsPolicyString = CFStringCreateWithCString( NULL, "kSecTrustSettingsPolicyString", kCFStringEncodingUTF8); CFIndex m; SInt32 result = 0; for (m = 0; m < CFArrayGetCount(trustSettings); m++) { CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, m); // First, check if this trust setting is constrained to a non-SSL policy. SecPolicyRef policyRef; if (CFDictionaryGetValueIfPresent(tSetting, _kSecTrustSettingsPolicy, (const void**)&policyRef)) { if (!isSSLPolicy(policyRef)) { continue; } } if (CFDictionaryContainsKey(tSetting, _kSecTrustSettingsPolicyString)) { // Restricted to a hostname, not a root. continue; } CFNumberRef cfNum; if (CFDictionaryGetValueIfPresent(tSetting, _kSecTrustSettingsResult, (const void**)&cfNum)) { CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result); } else { // > If this key is not present, a default value of // > kSecTrustSettingsResultTrustRoot is assumed. result = kSecTrustSettingsResultTrustRoot; } // If multiple dictionaries match, we are supposed to "OR" them, // the semantics of which are not clear. Since TrustRoot and TrustAsRoot // are mutually exclusive, Deny should probably override, and Invalid and // Unspecified be overridden, approximate this by stopping at the first // TrustRoot, TrustAsRoot or Deny. if (result == kSecTrustSettingsResultTrustRoot) { break; } else if (result == kSecTrustSettingsResultTrustAsRoot) { break; } else if (result == kSecTrustSettingsResultDeny) { break; } } // If trust settings are present, but none of them match the policy... // the docs don't tell us what to do. // // "Trust settings for a given use apply if any of the dictionaries in the // certificate’s trust settings array satisfies the specified use." suggests // that it's as if there were no trust settings at all, so we should probably // fallback to the admin trust settings. TODO. if (result == 0) { result = kSecTrustSettingsResultUnspecified; } CFRelease(_kSecTrustSettingsPolicy); CFRelease(_kSecTrustSettingsPolicyString); CFRelease(_kSecTrustSettingsResult); CFRelease(trustSettings); return result; } // isRootCertificate reports whether Subject and Issuer match. static Boolean isRootCertificate(SecCertificateRef cert, CFErrorRef *errRef) { CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, errRef); if (*errRef != NULL) { return false; } CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, errRef); if (*errRef != NULL) { CFRelease(subjectName); return false; } Boolean equal = CFEqual(subjectName, issuerName); CFRelease(subjectName); CFRelease(issuerName); return equal; } // CopyPEMRootsCTX509 fetches the system's list of trusted X.509 root certificates // for the kSecTrustSettingsPolicy SSL. // // On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root // certificates of the system. On failure, the function returns -1. // Additionally, it fills untrustedPemRoots with certs that must be removed from pemRoots. // // Note: The CFDataRef returned in pemRoots and untrustedPemRoots must // be released (using CFRelease) after we've consumed its content. static int CopyPEMRootsCTX509(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots, bool debugDarwinRoots) { int i; if (debugDarwinRoots) { fprintf(stderr, "crypto/x509: kSecTrustSettingsResultInvalid = %d\n", kSecTrustSettingsResultInvalid); fprintf(stderr, "crypto/x509: kSecTrustSettingsResultTrustRoot = %d\n", kSecTrustSettingsResultTrustRoot); fprintf(stderr, "crypto/x509: kSecTrustSettingsResultTrustAsRoot = %d\n", kSecTrustSettingsResultTrustAsRoot); fprintf(stderr, "crypto/x509: kSecTrustSettingsResultDeny = %d\n", kSecTrustSettingsResultDeny); fprintf(stderr, "crypto/x509: kSecTrustSettingsResultUnspecified = %d\n", kSecTrustSettingsResultUnspecified); } // Get certificates from all domains, not just System, this lets // the user add CAs to their "login" keychain, and Admins to add // to the "System" keychain SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem, kSecTrustSettingsDomainAdmin, kSecTrustSettingsDomainUser }; int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain); if (pemRoots == NULL || untrustedPemRoots == NULL) { return -1; } CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0); CFMutableDataRef combinedUntrustedData = CFDataCreateMutable(kCFAllocatorDefault, 0); for (i = 0; i < numDomains; i++) { int j; CFArrayRef certs = NULL; OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs); if (err != noErr) { continue; } CFIndex numCerts = CFArrayGetCount(certs); for (j = 0; j < numCerts; j++) { SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j); if (cert == NULL) { continue; } SInt32 result; if (domains[i] == kSecTrustSettingsDomainSystem) { // Certs found in the system domain are always trusted. If the user // configures "Never Trust" on such a cert, it will also be found in the // admin or user domain, causing it to be added to untrustedPemRoots. The // Go code will then clean this up. result = kSecTrustSettingsResultTrustRoot; } else { result = sslTrustSettingsResult(cert); if (debugDarwinRoots) { CFErrorRef errRef = NULL; CFStringRef summary = SecCertificateCopyShortDescription(NULL, cert, &errRef); if (errRef != NULL) { fprintf(stderr, "crypto/x509: SecCertificateCopyShortDescription failed\n"); CFRelease(errRef); continue; } CFIndex length = CFStringGetLength(summary); CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; char *buffer = malloc(maxSize); if (CFStringGetCString(summary, buffer, maxSize, kCFStringEncodingUTF8)) { fprintf(stderr, "crypto/x509: %s returned %d\n", buffer, (int)result); } free(buffer); CFRelease(summary); } } CFMutableDataRef appendTo; // > Note the distinction between the results kSecTrustSettingsResultTrustRoot // > and kSecTrustSettingsResultTrustAsRoot: The former can only be applied to // > root (self-signed) certificates; the latter can only be applied to // > non-root certificates. if (result == kSecTrustSettingsResultTrustRoot) { CFErrorRef errRef = NULL; if (!isRootCertificate(cert, &errRef) || errRef != NULL) { if (errRef != NULL) CFRelease(errRef); continue; } appendTo = combinedData; } else if (result == kSecTrustSettingsResultTrustAsRoot) { CFErrorRef errRef = NULL; if (isRootCertificate(cert, &errRef) || errRef != NULL) { if (errRef != NULL) CFRelease(errRef); continue; } appendTo = combinedData; } else if (result == kSecTrustSettingsResultDeny) { appendTo = combinedUntrustedData; } else if (result == kSecTrustSettingsResultUnspecified) { // Certificates with unspecified trust should probably be added to a pool of // intermediates for chain building, or checked for transitive trust and // added to the root pool (which is an imprecise approximation because it // cuts chains short) but we don't support either at the moment. TODO. continue; } else { continue; } CFDataRef data = NULL; err = SecItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); if (err != noErr) { continue; } if (data != NULL) { CFDataAppendBytes(appendTo, CFDataGetBytePtr(data), CFDataGetLength(data)); CFRelease(data); } } CFRelease(certs); } *pemRoots = combinedData; *untrustedPemRoots = combinedUntrustedData; return 0; } */ import "C" import ( "errors" "unsafe" ) func loadSystemRoots() (*CertPool, error) { var data, untrustedData C.CFDataRef err := C.CopyPEMRootsCTX509(&data, &untrustedData, C.bool(debugDarwinRoots)) if err == -1 { return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo") } defer C.CFRelease(C.CFTypeRef(data)) defer C.CFRelease(C.CFTypeRef(untrustedData)) buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data))) roots := NewCertPool() roots.AppendCertsFromPEM(buf) if C.CFDataGetLength(untrustedData) == 0 { return roots, nil } buf = C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(untrustedData)), C.int(C.CFDataGetLength(untrustedData))) untrustedRoots := NewCertPool() untrustedRoots.AppendCertsFromPEM(buf) trustedRoots := NewCertPool() for _, c := range roots.certs { if !untrustedRoots.contains(c) { trustedRoots.AddCert(c) } } return trustedRoots, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_darwin.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go package x509 import ( "bufio" "bytes" "crypto/sha1" "encoding/pem" "fmt" "io" "os" "os/exec" "os/user" "path/filepath" "strings" "sync" ) var debugDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1") func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { return nil, nil } // This code is only used when compiling without cgo. // It is here, instead of root_nocgo_darwin.go, so that tests can check it // even if the tests are run with cgo enabled. // The linker will not include these unused functions in binaries built with cgo enabled. // execSecurityRoots finds the macOS list of trusted root certificates // using only command-line tools. This is our fallback path when cgo isn't available. // // The strategy is as follows: // // 1. Run "security trust-settings-export" and "security // trust-settings-export -d" to discover the set of certs with some // user-tweaked trust policy. We're too lazy to parse the XML // (Issue 26830) to understand what the trust // policy actually is. We just learn that there is _some_ policy. // // 2. Run "security find-certificate" to dump the list of system root // CAs in PEM format. // // 3. For each dumped cert, conditionally verify it with "security // verify-cert" if that cert was in the set discovered in Step 1. // Without the Step 1 optimization, running "security verify-cert" // 150-200 times takes 3.5 seconds. With the optimization, the // whole process takes about 180 milliseconds with 1 untrusted root // CA. (Compared to 110ms in the cgo path) func execSecurityRoots() (*CertPool, error) { hasPolicy, err := getCertsWithTrustPolicy() if err != nil { return nil, err } if debugDarwinRoots { fmt.Fprintf(os.Stderr, "crypto/x509: %d certs have a trust policy\n", len(hasPolicy)) } keychains := []string{"/Library/Keychains/System.keychain"} // Note that this results in trusting roots from $HOME/... (the environment // variable), which might not be expected. u, err := user.Current() if err != nil { if debugDarwinRoots { fmt.Fprintf(os.Stderr, "crypto/x509: can't get user home directory: %v\n", err) } } else { keychains = append(keychains, filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain"), // Fresh installs of Sierra use a slightly different path for the login keychain filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain-db"), ) } type rootCandidate struct { c *Certificate system bool } var ( mu sync.Mutex roots = NewCertPool() numVerified int // number of execs of 'security verify-cert', for debug stats wg sync.WaitGroup verifyCh = make(chan rootCandidate) ) // Using 4 goroutines to pipe into verify-cert seems to be // about the best we can do. The verify-cert binary seems to // just RPC to another server with coarse locking anyway, so // running 16 at a time for instance doesn't help at all. Due // to the "if hasPolicy" check below, though, we will rarely // (or never) call verify-cert on stock macOS systems, though. // The hope is that we only call verify-cert when the user has // tweaked their trust policy. These 4 goroutines are only // defensive in the pathological case of many trust edits. for i := 0; i < 4; i++ { wg.Add(1) go func() { defer wg.Done() for cert := range verifyCh { sha1CapHex := fmt.Sprintf("%X", sha1.Sum(cert.c.Raw)) var valid bool verifyChecks := 0 if hasPolicy[sha1CapHex] { verifyChecks++ valid = verifyCertWithSystem(cert.c) } else { // Certificates not in SystemRootCertificates without user // or admin trust settings are not trusted. valid = cert.system } mu.Lock() numVerified += verifyChecks if valid { roots.AddCert(cert.c) } mu.Unlock() } }() } err = forEachCertInKeychains(keychains, func(cert *Certificate) { verifyCh <- rootCandidate{c: cert, system: false} }) if err != nil { close(verifyCh) return nil, err } err = forEachCertInKeychains([]string{ "/System/Library/Keychains/SystemRootCertificates.keychain", }, func(cert *Certificate) { verifyCh <- rootCandidate{c: cert, system: true} }) if err != nil { close(verifyCh) return nil, err } close(verifyCh) wg.Wait() if debugDarwinRoots { fmt.Fprintf(os.Stderr, "crypto/x509: ran security verify-cert %d times\n", numVerified) } return roots, nil } func forEachCertInKeychains(paths []string, f func(*Certificate)) error { args := append([]string{"find-certificate", "-a", "-p"}, paths...) cmd := exec.Command("/usr/bin/security", args...) data, err := cmd.Output() if err != nil { return err } for len(data) > 0 { var block *pem.Block block, data = pem.Decode(data) if block == nil { break } if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { continue } cert, err := ParseCertificate(block.Bytes) if err != nil { continue } f(cert) } return nil } func verifyCertWithSystem(cert *Certificate) bool { data := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: cert.Raw, }) f, err := os.CreateTemp("", "cert") if err != nil { fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err) return false } defer os.Remove(f.Name()) if _, err := f.Write(data); err != nil { fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err) return false } if err := f.Close(); err != nil { fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err) return false } cmd := exec.Command("/usr/bin/security", "verify-cert", "-p", "ssl", "-c", f.Name(), "-l", "-L") var stderr bytes.Buffer if debugDarwinRoots { cmd.Stderr = &stderr } if err := cmd.Run(); err != nil { if debugDarwinRoots { fmt.Fprintf(os.Stderr, "crypto/x509: verify-cert rejected %s: %q\n", cert.Subject, bytes.TrimSpace(stderr.Bytes())) } return false } if debugDarwinRoots { fmt.Fprintf(os.Stderr, "crypto/x509: verify-cert approved %s\n", cert.Subject) } return true } // getCertsWithTrustPolicy returns the set of certs that have a // possibly-altered trust policy. The keys of the map are capitalized // sha1 hex of the raw cert. // They are the certs that should be checked against `security // verify-cert` to see whether the user altered the default trust // settings. This code is only used for cgo-disabled builds. func getCertsWithTrustPolicy() (map[string]bool, error) { set := map[string]bool{} td, err := os.MkdirTemp("", "x509trustpolicy") if err != nil { return nil, err } defer os.RemoveAll(td) run := func(file string, args ...string) error { file = filepath.Join(td, file) args = append(args, file) cmd := exec.Command("/usr/bin/security", args...) var stderr bytes.Buffer cmd.Stderr = &stderr if err := cmd.Run(); err != nil { // If there are no trust settings, the // `security trust-settings-export` command // fails with: // exit status 1, SecTrustSettingsCreateExternalRepresentation: No Trust Settings were found. // Rather than match on English substrings that are probably // localized on macOS, just interpret any failure to mean that // there are no trust settings. if debugDarwinRoots { fmt.Fprintf(os.Stderr, "crypto/x509: exec %q: %v, %s\n", cmd.Args, err, stderr.Bytes()) } return nil } f, err := os.Open(file) if err != nil { return err } defer f.Close() // Gather all the runs of 40 capitalized hex characters. br := bufio.NewReader(f) var hexBuf bytes.Buffer for { b, err := br.ReadByte() isHex := ('A' <= b && b <= 'F') || ('0' <= b && b <= '9') if isHex { hexBuf.WriteByte(b) } else { if hexBuf.Len() == 40 { set[hexBuf.String()] = true } hexBuf.Reset() } if err == io.EOF { break } if err != nil { return err } } return nil } if err := run("user", "trust-settings-export"); err != nil { return nil, fmt.Errorf("dump-trust-settings (user): %v", err) } if err := run("admin", "trust-settings-export", "-d"); err != nil { return nil, fmt.Errorf("dump-trust-settings (admin): %v", err) } return set, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_darwin_armx.go ================================================ // Code generated by root_darwin_arm_gen --output root_darwin_armx.go; DO NOT EDIT. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build cgo && darwin && (arm || arm64 || ios) // +build cgo // +build darwin // +build arm arm64 ios package x509 func loadSystemRoots() (*CertPool, error) { p := NewCertPool() p.AppendCertsFromPEM([]byte(systemRootsPEM)) return p, nil } const systemRootsPEM = ` -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe 3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX 4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ 51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC +Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X 7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz 43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFVTCCBD2gAwIBAgIEO/OB0DANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJj aDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQDEw1BZG1pbi1Sb290LUNB MB4XDTAxMTExNTA4NTEwN1oXDTIxMTExMDA3NTEwN1owbDELMAkGA1UEBhMCY2gx DjAMBgNVBAoTBWFkbWluMREwDwYDVQQLEwhTZXJ2aWNlczEiMCAGA1UECxMZQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdGllczEWMBQGA1UEAxMNQWRtaW4tUm9vdC1DQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMvgr0QUIv5qF0nyXZ3PXAJi C4C5Wr+oVTN7oxIkXkxvO0GJToM9n7OVJjSmzBL0zJ2HXj0MDRcvhSY+KiZZc6Go vDvr5Ua481l7ILFeQAFtumeza+vvxeL5Nd0Maga2miiacLNAKXbAcUYRa0Ov5VZB ++YcOYNNt/aisWbJqA2y8He+NsEgJzK5zNdayvYXQTZN+7tVgWOck16Da3+4FXdy fH1NCWtZlebtMKtERtkVAaVbiWW24CjZKAiVfggjsiLo3yVMPGj3budLx5D9hEEm vlyDOtcjebca+AcZglppWMX/iHIrx7740y0zd6cWEqiLIcZCrnpkr/KzwO135GkC AwEAAaOCAf0wggH5MA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIASBkTCBjjCBiwYI YIV0AREDAQAwfzArBggrBgEFBQcCAjAfGh1UaGlzIGlzIHRoZSBBZG1pbi1Sb290 LUNBIENQUzBQBggrBgEFBQcCARZEaHR0cDovL3d3dy5pbmZvcm1hdGlrLmFkbWlu LmNoL1BLSS9saW5rcy9DUFNfMl8xNl83NTZfMV8xN18zXzFfMC5wZGYwfwYDVR0f BHgwdjB0oHKgcKRuMGwxFjAUBgNVBAMTDUFkbWluLVJvb3QtQ0ExIjAgBgNVBAsT GUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxETAPBgNVBAsTCFNlcnZpY2VzMQ4w DAYDVQQKEwVhZG1pbjELMAkGA1UEBhMCY2gwHQYDVR0OBBYEFIKf+iNzIPGXi7JM Tb5CxX9mzWToMIGZBgNVHSMEgZEwgY6AFIKf+iNzIPGXi7JMTb5CxX9mzWTooXCk bjBsMQswCQYDVQQGEwJjaDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZp Y2VzMSIwIAYDVQQLExlDZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQD Ew1BZG1pbi1Sb290LUNBggQ784HQMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B AQUFAAOCAQEAeE96XCYRpy6umkPKXDWCRn7INo96ZrWpMggcDORuofHIwdTkgOeM vWOxDN/yuT7CC3FAaUajbPRbDw0hRMcqKz0aC8CgwcyIyhw/rFK29mfNTG3EviP9 QSsEbnelFnjpm1wjz4EaBiFjatwpUbI6+Zv3XbEt9QQXBn+c6DeFLe4xvC4B+MTr a440xTk59pSYux8OHhEvqIwHCkiijGqZhTS3KmGFeBopaR+dJVBRBMoXwzk4B3Hn 0Zib1dEYFZa84vPJZyvxCbLOnPRDJgH6V2uQqbG+6DXVaf/wORVOvF/wzzv0viM/ RWbEtJZdvo8N3sdtCULzifnxP/V0T9+4ZQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp 6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D 0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ +jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S 5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B 8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc 0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e KeC2uAloGRwYQw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIIGDCCBgCgAwIBAgIGAT8vMXfmMA0GCSqGSIb3DQEBCwUAMIIBCjELMAkGA1UE BhMCRVMxEjAQBgNVBAgMCUJhcmNlbG9uYTFYMFYGA1UEBwxPQmFyY2Vsb25hIChz ZWUgY3VycmVudCBhZGRyZXNzIGF0IGh0dHA6Ly93d3cuYW5mLmVzL2VzL2FkZHJl c3MtZGlyZWNjaW9uLmh0bWwgKTEnMCUGA1UECgweQU5GIEF1dG9yaWRhZCBkZSBD ZXJ0aWZpY2FjaW9uMRcwFQYDVQQLDA5BTkYgQ2xhc2UgMSBDQTEaMBgGCSqGSIb3 DQEJARYLaW5mb0BhbmYuZXMxEjAQBgNVBAUTCUc2MzI4NzUxMDEbMBkGA1UEAwwS QU5GIEdsb2JhbCBSb290IENBMB4XDTEzMDYxMDE3NDUzOFoXDTMzMDYwNTE3NDUz OFowggEKMQswCQYDVQQGEwJFUzESMBAGA1UECAwJQmFyY2Vsb25hMVgwVgYDVQQH DE9CYXJjZWxvbmEgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgaHR0cDovL3d3dy5h bmYuZXMvZXMvYWRkcmVzcy1kaXJlY2Npb24uaHRtbCApMScwJQYDVQQKDB5BTkYg QXV0b3JpZGFkIGRlIENlcnRpZmljYWNpb24xFzAVBgNVBAsMDkFORiBDbGFzZSAx IENBMRowGAYJKoZIhvcNAQkBFgtpbmZvQGFuZi5lczESMBAGA1UEBRMJRzYzMjg3 NTEwMRswGQYDVQQDDBJBTkYgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDHPi9xy4wynbcUbWjorVUgQKeUAVh937J7P37XmsfH ZLOBZKIIlhhCtRwnDlg7x+BUvtJOTkIbEGMujDygUQ2s3HDYr5I41hTyM2Pl0cq2 EuSGEbPIHb3dEX8NAguFexM0jqNjrreN3hM2/+TOkAxSdDJP2aMurlySC5zwl47K ZLHtcVrkZnkDa0o5iN24hJT4vBDT4t2q9khQ+qb1D8KgCOb02r1PxWXu3vfd6Ha2 mkdB97iGuEh5gO2n4yOmFS5goFlVA2UdPbbhJsb8oKVKDd+YdCKGQDCkQyG4AjmC YiNm3UPG/qtftTH5cWri67DlLtm6fyUFOMmO6NSh0RtR745pL8GyWJUanyq/Q4bF HQB21E+WtTsCaqjGaoFcrBunMypmCd+jUZXl27TYENRFbrwNdAh7m2UztcIyb+Sg VJFyfvVsBQNvnp7GPimVxXZNc4VpxEXObRuPWQN1oZN/90PcZVqTia/SHzEyTryL ckhiLG3jZiaFZ7pTZ5I9wti9Pn+4kOHvE3Y/4nEnUo4mTxPX9pOlinF+VCiybtV2 u1KSlc+YaIM7VmuyndDZCJRXm3v0/qTE7t5A5fArZl9lvibigMbWB8fpD+c1GpGH Eo8NRY0lkaM+DkIqQoaziIsz3IKJrfdKaq9bQMSlIfameKBZ8fNYTBZrH9KZAIhz YwIDAQABo4IBfjCCAXowHQYDVR0OBBYEFIf6nt9SdnXsSUogb1twlo+d77sXMB8G A1UdIwQYMBaAFIf6nt9SdnXsSUogb1twlo+d77sXMA8GA1UdEwEB/wQFMAMBAf8w DgYDVR0PAQH/BAQDAgEGMIIBFQYDVR0RBIIBDDCCAQiCEWh0dHA6Ly93d3cuYW5m LmVzgQtpbmZvQGFuZi5lc6SB5TCB4jE0MDIGA1UECQwrR3JhbiBWaWEgZGUgbGVz IENvcnRzIENhdGFsYW5lcy4gOTk2LiAwODAxODESMBAGA1UEBwwJQmFyY2Vsb25h MScwJQYDVQQKDB5BTkYgQXV0b3JpZGFkIGRlIENlcnRpZmljYWNpb24xEjAQBgNV BAUTCUc2MzI4NzUxMDFZMFcGA1UECwxQSW5zY3JpdGEgZW4gZWwgTWluaXN0ZXJp byBkZWwgSW50ZXJpb3IgZGUgRXNwYcOxYSBjb24gZWwgbnVtZXJvIG5hY2lvbmFs IDE3MS40NDMwDQYJKoZIhvcNAQELBQADggIBAIgR9tFTZ9BCYg+HViMxOfF0MHN2 Pe/eC128ARdS+GH8A4thtbqiH/SOYbWofO/0zssHhNKa5iQEj45lCAb8BANpWJMD nWkPr6jq2+50a6d0MMgSS2l1rvjSF+3nIrEuicshHXSTi3q/vBLKr7uGKMVFaM68 XAropIwk6ndlA0JseARSPsbetv7ALESMIZAxlHV1TcctYHd0bB3c/Jz+PLszJQqs Cg/kBPo2D111OXZkIY8W/fJuG9veR783khAK2gUnC0zLLCNsYzEbdGt8zUmBsAsM cGxqGm6B6vDXd65OxWqw13xdq/24+5R8Ng1PF9tvfjZkUFBF30CxjWur7P90WiKI G7IGfr6BE1NgXlhEQQu4F+HizB1ypEPzGWltecXQ4yOzO+H0WfFTjLTYX6VSveyW DQV18ixF8M4tHP/SwNE+yyv2b2JJ3/3RpxjtFlLk+opJ574x0gD/dMJuWTH0JqVY 3PbRfE1jIxFpk164Qz/Xp7H7w7f6xh+tQCkBs3PUYmnGIZcPwq44Q6JHlCNsKx4K hxfggTvRCk4w79cUID45c2qDsRCqTPoOo/cbOpcfVhbH9LdMORpmuLwNogRZEUSE fWpqR9q+0kcQf4zGSWIURIyDrogdpDgoHDxktqgMgc+qA4ZE2WQl1D8hmev53A46 lUSrWUiWfDXtK3ux -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIIAeDltYNno+AwDQYJKoZIhvcNAQEMBQAwZzEbMBkGA1UE AwwSQXBwbGUgUm9vdCBDQSAtIEcyMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMw HhcNMTQwNDMwMTgxMDA5WhcNMzkwNDMwMTgxMDA5WjBnMRswGQYDVQQDDBJBcHBs ZSBSb290IENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgREkhI2imKScUcx+xuM23+TfvgHN6s XuI2pyT5f1BrTM65MFQn5bPW7SXmMLYFN14UIhHF6Kob0vuy0gmVOKTvKkmMXT5x ZgM4+xb1hYjkWpIMBDLyyED7Ul+f9sDx47pFoFDVEovy3d6RhiPw9bZyLgHaC/Yu OQhfGaFjQQscp5TBhsRTL3b2CtcM0YM/GlMZ81fVJ3/8E7j4ko380yhDPLVoACVd J2LT3VXdRCCQgzWTxb+4Gftr49wIQuavbfqeQMpOhYV4SbHXw8EwOTKrfl+q04tv ny0aIWhwZ7Oj8ZhBbZF8+NfbqOdfIRqMM78xdLe40fTgIvS/cjTf94FNcX1RoeKz 8NMoFnNvzcytN31O661A4T+B/fc9Cj6i8b0xlilZ3MIZgIxbdMYs0xBTJh0UT8TU gWY8h2czJxQI6bR3hDRSj4n4aJgXv8O7qhOTH11UL6jHfPsNFL4VPSQ08prcdUFm IrQB1guvkJ4M6mL4m1k8COKWNORj3rw31OsMiANDC1CvoDTdUE0V+1ok2Az6DGOe HwOx4e7hqkP0ZmUoNwIx7wHHHtHMn23KVDpA287PT0aLSmWaasZobNfMmRtHsHLD d4/E92GcdB/O/WuhwpyUgquUoue9G7q5cDmVF8Up8zlYNPXEpMZ7YLlmQ1A/bmH8 DvmGqmAMQ0uVAgMBAAGjQjBAMB0GA1UdDgQWBBTEmRNsGAPCe8CjoA1/coB6HHcm jTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwF AAOCAgEAUabz4vS4PZO/Lc4Pu1vhVRROTtHlznldgX/+tvCHM/jvlOV+3Gp5pxy+ 8JS3ptEwnMgNCnWefZKVfhidfsJxaXwU6s+DDuQUQp50DhDNqxq6EWGBeNjxtUVA eKuowM77fWM3aPbn+6/Gw0vsHzYmE1SGlHKy6gLti23kDKaQwFd1z4xCfVzmMX3z ybKSaUYOiPjjLUKyOKimGY3xn83uamW8GrAlvacp/fQ+onVJv57byfenHmOZ4VxG /5IFjPoeIPmGlFYl5bRXOJ3riGQUIUkhOb9iZqmxospvPyFgxYnURTbImHy99v6Z SYA7LNKmp4gDBDEZt7Y6YUX6yfIjyGNzv1aJMbDZfGKnexWoiIqrOEDCzBL/FePw N983csvMmOa/orz6JopxVtfnJBtIRD6e/J/JzBrsQzwBvDR4yGn1xuZW7AYJNpDr FEobXsmII9oDMJELuDY++ee1KG++P+w8j2Ud5cAeh6Squpj9kuNsJnfdBrRkBof0 Tta6SqoWqPQFZ2aWuuJVecMsXUmPgEkrihLHdoBR37q9ZV0+N0djMenl9MU/S60E inpxLK8JQzcPqOMyT/RFtm2XNuyE9QoB6he7hY1Ck3DDUOUUi78/w0EP3SIEIwiK um1xRKtzCTrJ+VKACd+66eYWyi4uTLLT3OUEVLLUNIAytbwPF+E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwS QXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcN MTQwNDMwMTgxOTA2WhcNMzkwNDMwMTgxOTA2WjBnMRswGQYDVQQDDBJBcHBsZSBS b290IENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9y aXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzB2MBAGByqGSM49 AgEGBSuBBAAiA2IABJjpLz1AcqTtkyJygRMc3RCV8cWjTnHcFBbZDuWmBSp3ZHtf TjjTuxxEtX/1H7YyYl3J6YRbTzBPEVoA/VhYDKX1DyxNB0cTddqXl5dvMVztK517 IDvYuVTZXpmkOlEKMaNCMEAwHQYDVR0OBBYEFLuw3qFYM4iapIqZ3r6966/ayySr MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gA MGUCMQCD6cHEFl4aXTQY2e3v9GwOAEZLuN+yRhHFD/3meoyhpmvOwgPUnPWTxnS4 at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM 6BgD56KyKA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0 MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+ +FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1 XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3 R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93 d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0 YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7 R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX UKqK1drk/NAJBzewdXUh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFujCCBKKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhjELMAkGA1UEBhMCVVMx HTAbBgNVBAoTFEFwcGxlIENvbXB1dGVyLCBJbmMuMS0wKwYDVQQLEyRBcHBsZSBD b21wdXRlciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIEFwcGxlIFJv b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA1MDIxMDAwMTgxNFoXDTI1MDIx MDAwMTgxNFowgYYxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBcHBsZSBDb21wdXRl ciwgSW5jLjEtMCsGA1UECxMkQXBwbGUgQ29tcHV0ZXIgQ2VydGlmaWNhdGUgQXV0 aG9yaXR5MSkwJwYDVQQDEyBBcHBsZSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOSRqQkfkdseR1DrBe1e eYQt6zaiV0xV7IsZid75S2z1B6siMALoGD74UAnTf0GomPnRymacJGsR0KO75Bsq wx+VnnoMpEeLW9QWNzPLxA9NzhRp0ckZcvVdDtV/X5vyJQO6VY9NXQ3xZDUjFUsV WR2zlPf2nJ7PULrBWFBnjwi0IPfLrCwgb3C2PwEwjLdDzw+dPfMrSSgayP7OtbkO 2V4c1ss9tTqt9A8OAJILsSEWLnTVPA3bYharo3GSR1NVwa8vQbP4++NwzeajTEV+ H0xrUJZBicR0YgsQg0GHM4qBsTBY7FoEMoxos48d3mVz/2deZbxJ2HafMxRloXeU yS0CAwEAAaOCAi8wggIrMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ MB0GA1UdDgQWBBQr0GlHlHYJ/vRrjS5ApvdHTX8IXjAfBgNVHSMEGDAWgBQr0GlH lHYJ/vRrjS5ApvdHTX8IXjCCASkGA1UdIASCASAwggEcMIIBGAYJKoZIhvdjZAUB MIIBCTBBBggrBgEFBQcCARY1aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmlj YXRlYXV0aG9yaXR5L3Rlcm1zLmh0bWwwgcMGCCsGAQUFBwICMIG2GoGzUmVsaWFu Y2Ugb24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2Nl cHRhbmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5k IGNvbmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRp ZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wRAYDVR0fBD0wOzA5oDegNYYz aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L3Jvb3Qu Y3JsMFUGCCsGAQUFBwEBBEkwRzBFBggrBgEFBQcwAoY5aHR0cHM6Ly93d3cuYXBw bGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L2Nhc2lnbmVycy5odG1sMA0GCSqG SIb3DQEBBQUAA4IBAQCd2i0oWC99dgS5BNM+zrdmY06PL9T+S61yvaM5xlJNBZhS 9YlRASR5vhoy9+VEi0tEBzmC1lrKtCBe2a4VXR2MHTK/ODFiSF3H4ZCx+CRA+F9Y m1FdV53B5f88zHIhbsTp6aF31ywXJsM/65roCwO66bNKcuszCVut5mIxauivL9Wv Hld2j383LS4CXN1jyfJxuCZA3xWNdUQ/eb3mHZnhQyw+rW++uaT+DjUZUWOxw961 kj5ReAFziqQjyqSI8R5cH0EWLX6VCqrpiUGYGxrdyyC/R14MJsVVNU3GMIuZZxTH CR+6R8faAQmHJEKVvRNgGQrv6n8Obs3BREM6StXj -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgILMTI1MzcyODI4MjgwDQYJKoZIhvcNAQELBQAwWDELMAkG A1UEBhMCSlAxHDAaBgNVBAoTE0phcGFuZXNlIEdvdmVybm1lbnQxDTALBgNVBAsT BEdQS0kxHDAaBgNVBAMTE0FwcGxpY2F0aW9uQ0EyIFJvb3QwHhcNMTMwMzEyMTUw MDAwWhcNMzMwMzEyMTUwMDAwWjBYMQswCQYDVQQGEwJKUDEcMBoGA1UEChMTSmFw YW5lc2UgR292ZXJubWVudDENMAsGA1UECxMER1BLSTEcMBoGA1UEAxMTQXBwbGlj YXRpb25DQTIgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKaq rSVl1gAR1uh6dqr05rRL88zDUrSNrKZPtZJxb0a11a2LEiIXJc5F6BR6hZrkIxCo +rFnUOVtR+BqiRPjrq418fRCxQX3TZd+PCj8sCaRHoweOBqW3FhEl2LjMsjRFUFN dZh4vqtoqV7tR76kuo6hApfek3SZbWe0BSXulMjtqqS6MmxCEeu+yxcGkOGThchk KM4fR8fAXWDudjbcMztR63vPctgPeKgZggiQPhqYjY60zxU2pm7dt+JNQCBT2XYq 0HisifBPizJtROouurCp64ndt295D6uBbrjmiykLWa+2SQ1RLKn9nShjZrhwlXOa 2Po7M7xCQhsyrLEy+z0CAwEAAaOBwTCBvjAdBgNVHQ4EFgQUVqesqgIdsqw9kA6g by5Bxnbne9owDgYDVR0PAQH/BAQDAgEGMHwGA1UdEQR1MHOkcTBvMQswCQYDVQQG EwJKUDEYMBYGA1UECgwP5pel5pys5Zu95pS/5bqcMRswGQYDVQQLDBLmlL/lupzo qo3oqLzln7rnm6QxKTAnBgNVBAMMIOOCouODl+ODquOCseODvOOCt+ODp+ODs0NB MiBSb290MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH+aCXWs B9FydC53VzDCBJzUgKaD56WgG5/+q/OAvdVKo6GPtkxgEefK4WCB10jBIFmlYTKL nZ6X02aD2mUuWD7b5S+lzYxzplG+WCigeVxpL0PfY7KJR8q73rk0EWOgDiUX5Yf0 HbCwpc9BqHTG6FPVQvSCLVMJEWgmcZR1E02qdog8dLHW40xPYsNJTE5t8XB+w3+m Bcx4m+mB26jIx1ye/JKSLaaX8ji1bnOVDMA/zqaUMLX6BbfeniCq/BNkyYq6ZO/i Y+TYmK5rtT6mVbgzPixy+ywRAPtbFi+E0hOe+gXFwctyTiLdhMpLvNIthhoEdlkf SUJiOxMfFui61/0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ 4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF 6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF 661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS 3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF 3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIJmzCCB4OgAwIBAgIBATANBgkqhkiG9w0BAQwFADCCAR4xPjA8BgNVBAMTNUF1 dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s YW5vMQswCQYDVQQGEwJWRTEQMA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlz dHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0 aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBlcmludGVuZGVuY2lh IGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUwIwYJ KoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyMjE4MDgy MVoXDTMwMTIxNzIzNTk1OVowggEeMT4wPAYDVQQDEzVBdXRvcmlkYWQgZGUgQ2Vy dGlmaWNhY2lvbiBSYWl6IGRlbCBFc3RhZG8gVmVuZXpvbGFubzELMAkGA1UEBhMC VkUxEDAOBgNVBAcTB0NhcmFjYXMxGTAXBgNVBAgTEERpc3RyaXRvIENhcGl0YWwx NjA0BgNVBAoTLVNpc3RlbWEgTmFjaW9uYWwgZGUgQ2VydGlmaWNhY2lvbiBFbGVj dHJvbmljYTFDMEEGA1UECxM6U3VwZXJpbnRlbmRlbmNpYSBkZSBTZXJ2aWNpb3Mg ZGUgQ2VydGlmaWNhY2lvbiBFbGVjdHJvbmljYTElMCMGCSqGSIb3DQEJARYWYWNy YWl6QHN1c2NlcnRlLmdvYi52ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBAME77xNS8ZlW47RsBeEaaRZhJoZ4rw785UAFCuPZOAVMqNS1wMYqzy95q6Gk UO81ER/ugiQX/KMcq/4HBn83fwdYWxPZfwBfK7BP2p/JsFgzYeFP0BXOLmvoJIzl Jb6FW+1MPwGBjuaZGFImWZsSmGUclb51mRYMZETh9/J5CLThR1exStxHQptwSzra zNFpkQY/zmj7+YZNA9yDoroVFv6sybYOZ7OxNDo7zkSLo45I7gMwtxqWZ8VkJZkC 8+p0dX6mkhUT0QAV64Zc9HsZiH/oLhEkXjhrgZ28cF73MXIqLx1fyM4kPH1yOJi/ R72nMwL7D+Sd6mZgI035TxuHXc2/uOwXfKrrTjaJDz8Jp6DdessOkxIgkKXRjP+F K3ze3n4NUIRGhGRtyvEjK95/2g02t6PeYiYVGur6ruS49n0RAaSS0/LJb6XzaAAe 0mmO2evnEqxIKwy2mZRNPfAVW1l3wCnWiUwryBU6OsbFcFFrQm+00wOicXvOTHBM aiCVAVZTb9RSLyi+LJ1llzJZO3pq3IRiiBj38Nooo+2ZNbMEciSgmig7YXaUcmud SVQvLSL+Yw+SqawyezwZuASbp7d/0rutQ59d81zlbMt3J7yB567rT2IqIydQ8qBW k+fmXzghX+/FidYsh/aK+zZ7Wy68kKHuzEw1Vqkat5DGs+VzAgMBAAGjggLeMIIC 2jASBgNVHRMBAf8ECDAGAQH/AgECMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52 ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMB0GA1UdDgQWBBStuyIdxuDS Aaj9dlBSk+2YwU2u0zCCAVAGA1UdIwSCAUcwggFDgBStuyIdxuDSAaj9dlBSk+2Y wU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRpZmlj YWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAw DgYDVQQHEwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYD VQQKEy1TaXN0ZW1hIE5hY2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25p Y2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5kZW5jaWEgZGUgU2VydmljaW9zIGRlIENl cnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG9w0BCQEWFmFjcmFpekBz dXNjZXJ0ZS5nb2IudmWCAQEwDgYDVR0PAQH/BAQDAgEGMDcGA1UdEQQwMC6CD3N1 c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMFQGA1Ud HwRNMEswJKAioCCGHmhodHA6Ly93d3cuc3VzY2VydGUuZ29iLnZlL2xjcjAjoCGg H4YdbGRhcDovL2FjcmFpei5zdXNjZXJ0ZS5nb2IudmUwNwYIKwYBBQUHAQEEKzAp MCcGCCsGAQUFBzABhhtoaHRwOi8vb2NzcC5zdXNjZXJ0ZS5nb2IudmUwQAYDVR0g BDkwNzA1BgVghl4BAjAsMCoGCCsGAQUFBwIBFh5odHRwOi8vd3d3LnN1c2NlcnRl LmdvYi52ZS9kcGMwDQYJKoZIhvcNAQEMBQADggIBAK4qy/zmZ9zBwfW3yOYtLcBT Oy4szJyPz7/RhNH3bPVH7HbDTGpi6JZ4YXdXMBeJE5qBF4a590Kgj8Rlnltt+Rbo OFQOU1UDqKuTdBsA//Zry5899fmn8jBUkg4nh09jhHHbLlaUScdz704Zz2+UVg7i s/r3Legxap60KzmdrmTAE9VKte1TQRgavQwVX5/2mO/J+SCas//UngI+h8SyOucq mjudYEgBrZaodUsagUfn/+AzFNrGLy+al+5nZeHb8JnCfLHWS0M9ZyhgoeO/czyn 99+5G93VWNv4zfc4KiavHZKrkn8F9pg0ycIZh+OwPT/RE2zq4gTazBMlP3ACIe/p olkNaOEa8KvgzW96sjBZpMW49zFmyINYkcj+uaNCJrVGsXgdBmkuRGJNWFZ9r0cG woIaxViFBypsz045r1ESfYPlfDOavBhZ/giR/Xocm9CHkPRY2BApMMR0DUCyGETg Ql+L3kfdTKzuDjUp2DM9FqysQmaM81YDZufWkMhlZPfHwC7KbNougoLroa5Umeos bqAXWmk46SwIdWRPLLqbUpDTKooynZKpSYIkkotdgJoVZUUCY+RCO8jsVPEU6ece SxztNUm5UOta1OJPMwSAKRHOo3ilVb9c6lAixDdvV8MeNbqe6asM1mpCHWbJ/0rg 5Ls9Cxx8hracyp0ev7b0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIIKv++n6Lw6YcwDQYJKoZIhvcNAQEFBQAwKDELMAkGA1UE BhMCQkUxGTAXBgNVBAMTEEJlbGdpdW0gUm9vdCBDQTIwHhcNMDcxMDA0MTAwMDAw WhcNMjExMjE1MDgwMDAwWjAoMQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1 bSBSb290IENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZzQh6S /3UPi790hqc/7bIYLS2X+an7mEoj39WN4IzGMhwWLQdC1i22bi+n9fzGhYJdld61 IgDMqFNAn68KNaJ6x+HK92AQZw6nUHMXU5WfIp8MXW+2QbyM69odRr2nlL/zGsvU +40OHjPIltfsjFPekx40HopQcSZYtF3CiInaYNKJIT/e1wEYNm7hLHADBGXvmAYr XR5i3FVr/mZkIV/4L+HXmymvb82fqgxG0YjFnaKVn6w/Fa7yYd/vw2uaItgscf1Y HewApDgglVrH1Tdjuk+bqv5WRi5j2Qsj1Yr6tSPwiRuhFA0m2kHwOI8w7QUmecFL TqG4flVSOmlGhHUCAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4CQEBMC4wLAYIKwYBBQUHAgEWIGh0dHA6 Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSFiuv0xbu+DlkD lN7WgAEV4xCcOTARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUhYrr9MW7 vg5ZA5Te1oABFeMQnDkwDQYJKoZIhvcNAQEFBQADggEBAFHYhd27V2/MoGy1oyCc UwnzSgEMdL8rs5qauhjyC4isHLMzr87lEwEnkoRYmhC598wUkmt0FoqW6FHvv/pK JaeJtmMrXZRY0c8RcrYeuTlBFk0pvDVTC9rejg7NqZV3JcqUWumyaa7YwBO+mPyW nIR/VRPmPIfjvCCkpDZoa01gZhz5v6yAlGYuuUGK02XThIAC71AdXkbc98m6tTR8 KvPG2F9fVJ3bTc0R5/0UAoNmXsimABKgX77OFP67H6dh96tK8QYUn8pJQsKpvO2F sauBQeYNxUJpU4c5nUwfAA4+Bw11V0SoU7Q2dmSZ3G7rPUZuFF1eR1ONeE3gJ7uO hXY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr 6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN 9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h 9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo +fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h 3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX 0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c /3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D 34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv 033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq 4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQy MDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjEw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy3QRk D2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/o OI7bm+V8u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3A fQ+lekLZWnDZv6fXARz2m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJe IgpFy4QxTaz+29FHuvlglzmxZcfe+5nkCiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8n oc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTaYVKvJrT1cU/J19IG32PK /yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6vpmumwKj rckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD 3AjLLhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE 7cderVC6xkGbrPAXZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkC yC2fg69naQanMVXVz0tv/wQFx1isXxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLd qvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ04IwDQYJKoZI hvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaA SfX8MPWbTx9BLxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXo HqJPYNcHKfyyo6SdbhWSVhlMCrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpB emOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5GfbVSUZP/3oNn6z4eGBrxEWi1CXYBmC AMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85YmLLW1AL14FABZyb 7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKSds+x DzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvk F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka +elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q 130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG 9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4 Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0 aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N 8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K /OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu 7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC 28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6 lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB 0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09 5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q 619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn 2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG 5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0 BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb 5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ 0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ 8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do 0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ 44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN 9u6wWk5JRFRYX0KD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs 6GAqm4VKQPNriiTsBhYscw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn 0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n 3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P 5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi DrW5viSP -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 /ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp 7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN 5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe /v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ 5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR 5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s +12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 +HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF 5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ d0jQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq 7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p 26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi 1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu tGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDQzCCAiugAwIBAgIQX/h7KCtU3I1CoxW1aMmt/zANBgkqhkiG9w0BAQUFADA1 MRYwFAYDVQQKEw1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENB IDIwNDgwHhcNMDQwNTE0MjAxNzEyWhcNMjkwNTE0MjAyNTQyWjA1MRYwFAYDVQQK Ew1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENBIDIwNDgwggEg MA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQCwmrmrp68Kd6ficba0ZmKUeIhH xmJVhEAyv8CrLqUccda8bnuoqrpu0hWISEWdovyD0My5jOAmaHBKeN8hF570YQXJ FcjPFto1YYmUQ6iEqDGYeJu5Tm8sUxJszR2tKyS7McQr/4NEb7Y9JHcJ6r8qqB9q VvYgDxFUl4F1pyXOWWqCZe+36ufijXWLbvLdT6ZeYpzPEApk0E5tzivMW/VgpSdH jWn0f84bcN5wGyDWbs2mAag8EtKpP6BrXruOIIt6keO1aO6g58QBdKhTCytKmg9l Eg6CTY5j/e/rmxrbU6YTYK/CfdfHbBcl1HP7R2RQgYCUTOG/rksc35LtLgXfAgED o1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJ/PI FR5umgIJFq0roIlgX9p7L6owEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEF BQADggEBAJ2dhISjQal8dwy3U8pORFBi71R803UXHOjgxkhLtv5MOhmBVrBW7hmW Yqpao2TB9k5UM8Z3/sUcuuVdJcr18JOagxEu5sv4dEX+5wW4q+ffy0vhN4TauYuX cB7w4ovXsNgOnbFp1iqRe6lJT37mjpXYgyc81WhJDtSd9i7rp77rMKSsH0T8lasz Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4 CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 l7+ijrRU -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgIQKTZHquOKrIZKI1byyrdhrzANBgkqhkiG9w0BAQUFADBO MQswCQYDVQQGEwJ1czEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQ0wCwYDVQQL EwRGQkNBMRYwFAYDVQQDEw1Db21tb24gUG9saWN5MB4XDTA3MTAxNTE1NTgwMFoX DTI3MTAxNTE2MDgwMFowTjELMAkGA1UEBhMCdXMxGDAWBgNVBAoTD1UuUy4gR292 ZXJubWVudDENMAsGA1UECxMERkJDQTEWMBQGA1UEAxMNQ29tbW9uIFBvbGljeTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJeNvTMn5K1b+3i9L0dHbsd4 6ZOcpN7JHP0vGzk4rEcXwH53KQA7Ax9oD81Npe53uCxiazH2+nIJfTApBnznfKM9 hBiKHa4skqgf6F5PjY7rPxr4nApnnbBnTfAu0DDew5SwoM8uCjR/VAnTNr2kSVdS c+md/uRIeUYbW40y5KVIZPMiDZKdCBW/YDyD90ciJSKtKXG3d+8XyaK2lF7IMJCk FEhcVlcLQUwF1CpMP64Sm1kRdXAHImktLNMxzJJ+zM2kfpRHqpwJCPZLr1LoakCR xVW9QLHIbVeGlRfmH3O+Ry4+i0wXubklHKVSFzYIWcBCvgortFZRPBtVyYyQd+sC AwEAAaN7MHkwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFC9Yl9ipBZilVh/72at17wI8NjTHMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJ KwYBBAGCNxUCBBYEFHa3YJbdFFYprHWF03BjwbxHhhyLMA0GCSqGSIb3DQEBBQUA A4IBAQBgrvNIFkBypgiIybxHLCRLXaCRc+1leJDwZ5B6pb8KrbYq+Zln34PFdx80 CTj5fp5B4Ehg/uKqXYeI6oj9XEWyyWrafaStsU+/HA2fHprA1RRzOCuKeEBuMPdi 4c2Z/FFpZ2wR3bgQo2jeJqVW/TZsN5hs++58PGxrcD/3SDcJjwtCga1GRrgLgwb0 Gzigf0/NC++DiYeXHIowZ9z9VKEDfgHLhUyxCynDvux84T8PCVI8L6eaSP436REG WOE2QYrEtr+O3c5Ks7wawM36GpnScZv6z7zyxFSjiDV2zBssRm8MtNHDYXaSdBHq S4CNHIkRi+xb/xfJSPzn4AYR4oRe -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI 2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp +2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW /zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB ZQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR 6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC 9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV /erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z +pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB /wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM 4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV 2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl 0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB NVOFBkpdn627G190 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0 MRMwEQYDVQQDEwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQG EwJJTDAeFw0wNDAzMjQxMTMyMThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMT CkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNpZ24xCzAJBgNVBAYTAklMMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49qROR+WCf4C9DklBKK 8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTyP2Q2 98CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb 2CEJKHxNGGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxC ejVb7Us6eva1jsz/D3zkYDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7Kpi Xd3DTKaCQeQzC6zJMw9kglcq/QytNuEMrkvF7zuZ2SOzW120V+x0cAwqTwIDAQAB o4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2Zl ZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0PAQH/BAQD AgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRL AZs+VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWd foPPbrxHbvUanlR2QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0M cXS6hMTXcpuEfDhOZAYnKuGntewImbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq 8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb/627HOkthIDYIb6FUtnUdLlp hbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VGzT2ouvDzuFYk Res3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U AGegcQCCSA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGATCCA+mgAwIBAgIRAI9hcRW6eVgXjH0ROqzW264wDQYJKoZIhvcNAQELBQAw RTEfMB0GA1UEAxMWQ29tU2lnbiBHbG9iYWwgUm9vdCBDQTEVMBMGA1UEChMMQ29t U2lnbiBMdGQuMQswCQYDVQQGEwJJTDAeFw0xMTA3MTgxMDI0NTRaFw0zNjA3MTYx MDI0NTVaMEUxHzAdBgNVBAMTFkNvbVNpZ24gR2xvYmFsIFJvb3QgQ0ExFTATBgNV BAoTDENvbVNpZ24gTHRkLjELMAkGA1UEBhMCSUwwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCyKClzKh3rm6n1nvigmV/VU1D4hSwYW2ro3VqpzpPo0Ph3 3LguqjXd5juDwN4mpxTpD99d7Xu5X6KGTlMVtfN+bTbA4t3x7DU0Zqn0BE5XuOgs 3GLH41Vmr5wox1bShVpM+IsjcN4E/hMnDtt/Bkb5s33xCG+ohz5dlq0gA9qfr/g4 O9lkHZXTCeYrmVzd/il4x79CqNvGkdL3um+OKYl8rg1dPtD8UsytMaDgBAopKR+W igc16QJzCbvcinlETlrzP/Ny76BWPnAQgaYBULax/Q5thVU+N3sEOKp6uviTdD+X O6i96gARU4H0xxPFI75PK/YdHrHjfjQevXl4J37FJfPMSHAbgPBhHC+qn/014DOx 46fEGXcdw2BFeIIIwbj2GH70VyJWmuk/xLMCHHpJ/nIF8w25BQtkPpkwESL6esaU b1CyB4Vgjyf16/0nRiCAKAyC/DY/Yh+rDWtXK8c6QkXD2XamrVJo43DVNFqGZzbf 5bsUXqiVDOz71AxqqK+p4ek9374xPNMJ2rB5MLPAPycwI0bUuLHhLy6nAIFHLhut TNI+6Y/soYpi5JSaEjcY7pxI8WIkUAzr2r+6UoT0vAdyOt7nt1y8844a7szo/aKf woziHl2O1w6ZXUC30K+ptXVaOiW79pBDcbLZ9ZdbONhS7Ea3iH4HJNwktrBJLQID AQABo4HrMIHoMA8GA1UdEwEB/wQFMAMBAf8wgYQGA1UdHwR9MHswPKA6oDiGNmh0 dHA6Ly9mZWRpci5jb21zaWduLmNvLmlsL2NybC9jb21zaWduZ2xvYmFscm9vdGNh LmNybDA7oDmgN4Y1aHR0cDovL2NybDEuY29tc2lnbi5jby5pbC9jcmwvY29tc2ln bmdsb2JhbHJvb3RjYS5jcmwwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBQCRZPY DUhirGm6rgZbPvuqJpFQsTAfBgNVHSMEGDAWgBQCRZPYDUhirGm6rgZbPvuqJpFQ sTANBgkqhkiG9w0BAQsFAAOCAgEAk1V5V9701xsfy4mfX+tP9Ln5e9h3N+QMwUfj kr+k3e8iXOqADjTpUHeBkEee5tJq09ZLp/43F5tZ2eHdYq2ZEX7iWHCnOQet6Yw9 SU1TahsrGDA6JJD9sdPFnNZooGsU1520e0zNB0dNWwxrWAmu4RsBxvEpWCJbvzQL dOfyX85RWwli81OiVMBc5XvJ1mxsIIqli45oRynKtsWP7E+b0ISJ1n+XFLdQo/Nm WA/5sDfT0F5YPzWdZymudMbXitimxC+n4oQE4mbQ4Zm718Iwg3pP9gMMcSc7Qc1J kJHPH9O7gVubkKHuSYj9T3Ym6c6egL1pb4pz/uT7cT26Fiopc/jdqbe2EAfoJZkv hlp/zdzOoXTWjiKNA5zmgWnZn943FuE9KMRyKtyi/ezJXCh8ypnqLIKxeFfZl69C BwJsPXUTuqj8Fic0s3aZmmr7C4jXycP+Q8V+akMEIoHAxcd960b4wVWKqOcI/kZS Q0cYqWOY1LNjznRt9lweWEfwDBL3FhrHOmD4++1N3FkkM4W+Q1b2WOL24clDMj+i 2n9Iw0lc1llHMSMvA5D0vpsXZpOgcCVahfXczQKi9wQ3oZyonJeWx4/rXdMtagAB VBYGFuMEUEQtybI+eIbnp5peO2WAAblQI4eTy/jMVowe5tfMEXovV3sz9ULgmGb3 DscLP1I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu MQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwx GzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjEL MAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGtWhf HZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs49oh gHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sW v+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ue Mv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr 9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt 6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7 MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNl Y3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58 ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkq hkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7p iL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtC dsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAmlaxMDPWL kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp /hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y Johw1+qRzT65ysCQblrGXnRl11z+o+I= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp 3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl 6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I 0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv 6pZjamVFkpUBtA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI 2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx 1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV 5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY 1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 sycX -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t 9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd +SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N 0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie 4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 /YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDOzCCAiOgAwIBAgIRANAeRlAAACmMAAAAAgAAAAIwDQYJKoZIhvcNAQEFBQAw PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD Ew5EU1QgUm9vdCBDQSBYNDAeFw0wMDA5MTMwNjIyNTBaFw0yMDA5MTMwNjIyNTBa MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEXMBUGA1UE AxMORFNUIFJvb3QgQ0EgWDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCthX3OFEYY8gSeIYur0O4ypOT68HnDrjLfIutL5PZHRwQGjzCPb9PFo/ihboJ8 RvfGhBAqpQCo47zwYEhpWm1jB+L/OE/dBBiyn98krfU2NiBKSom2J58RBeAwHGEy cO+lewyjVvbDDLUy4CheY059vfMjPAftCRXjqSZIolQb9FdPcAoa90mFwB7rKniE J7vppdrUScSS0+eBrHSUPLdvwyn4RGp+lSwbWYcbg5EpSpE0GRJdchic0YDjvIoC YHpe7Rkj93PYRTQyU4bhC88ck8tMqbvRYqMRqR+vobbkrj5LLCOQCHV5WEoxWh+0 E2SpIFe7RkV++MmpIAc0h1tZAgMBAAGjMjAwMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFPCD6nPIP1ubWzdf9UyPWvf0hki9MA0GCSqGSIb3DQEBBQUAA4IBAQCE G85wl5eEWd7adH6XW/ikGN5salvpq/Fix6yVTzE6CrhlP5LBdkf6kx1bSPL18M45 g0rw2zA/MWOhJ3+S6U+BE0zPGCuu8YQaZibR7snm3HiHUaZNMu5c8D0x0bcMxDjY AVVcHCoNiL53Q4PLW27nbY6wwG0ffFKmgV3blxrYWfuUDgGpyPwHwkfVFvz9qjaV mf12VJffL6W8omBPtgteb6UaT/k1oJ7YI0ldGf+ngpVbRhD+LC3cUtT6GO/BEPZu 8YTV/hbiDH5v3khVqMIeKT6o8IuXGG7F6a6vKwP1F1FwTXf4UC/ivhme7vdUH7B/ Vv4AEbT8dNfEeFxrkDbh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c 77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 +GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE5zCCA8+gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCQ0Ex EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoTFEVj aG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNlcnZp Y2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMjAeFw0wNTEwMDYxMDQ5MTNa Fw0zMDEwMDcxMDQ5MTNaMIGNMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJp bzEQMA4GA1UEBxMHVG9yb250bzEdMBsGA1UEChMURWNob3dvcnggQ29ycG9yYXRp b24xHzAdBgNVBAsTFkNlcnRpZmljYXRpb24gU2VydmljZXMxGjAYBgNVBAMTEUVj aG93b3J4IFJvb3QgQ0EyMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA utU/5BkV15UBf+s+JQruKQxr77s3rjp/RpOtmhHILIiO5gsEWP8MMrfrVEiidjI6 Qh6ans0KAWc2Dw0/j4qKAQzOSyAZgjcdypNTBZ7muv212DA2Pu41rXqwMrlBrVi/ KTghfdLlNRu6JrC5y8HarrnRFSKF1Thbzz921kLDRoCi+FVs5eVuK5LvIfkhNAqA byrTgO3T9zfZgk8upmEkANPDL1+8y7dGPB/d6lk0I5mv8PESKX02TlvwgRSIiTHR k8++iOPLBWlGp7ZfqTEXkPUZhgrQQvxcrwCUo6mk8TqgxCDP5FgPoHFiPLef5szP ZLBJDWp7GLyE1PmkQI6WiwIBA6OCAVAwggFMMA8GA1UdEwEB/wQFMAMBAf8wCwYD VR0PBAQDAgEGMB0GA1UdDgQWBBQ74YEboKs/OyGC1eISrq5QqxSlEzCBugYDVR0j BIGyMIGvgBQ74YEboKs/OyGC1eISrq5QqxSlE6GBk6SBkDCBjTELMAkGA1UEBhMC Q0ExEDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoT FEVjaG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMoIBADBQBgNVHSAESTBH MEUGCysGAQQB+REKAQMBMDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuZWNob3dv cnguY29tL2NhL3Jvb3QyL2Nwcy5wZGYwDQYJKoZIhvcNAQEFBQADggEBAG+nrPi/ 0RpfEzrj02C6JGPUar4nbjIhcY6N7DWNeqBoUulBSIH/PYGNHYx7/lnJefiixPGE 7TQ5xPgElxb9bK8zoAApO7U33OubqZ7M7DlHnFeCoOoIAZnG1kuwKwD5CXKB2a74 HzcqNnFW0IsBFCYqrVh/rQgJOzDA8POGbH0DeD0xjwBBooAolkKT+7ZItJF1Pb56 QpDL9G+16F7GkmnKlAIYT3QTS3yFGYChnJcd+6txUPhKi9sSOOmAIaKHnkH9Scz+ A2cSi4A3wUYXVatuVNHpRb2lygfH3SuCX9MU8Ure3zBlSU1LALtMqI4JmcQmQpIq zIzvO2jHyu9PQqo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE 1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v 1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi 94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP 9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m 0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH 4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy vUxFnmG6v4SBkgPR0ml8xQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH 4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er fF6adulZkMV8gzURZVE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS /jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D hNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYDCCA0igAwIBAgICATAwDQYJKoZIhvcNAQELBQAwWTELMAkGA1UEBhMCVVMx GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UE AxMYRmVkZXJhbCBDb21tb24gUG9saWN5IENBMB4XDTEwMTIwMTE2NDUyN1oXDTMw MTIwMTE2NDUyN1owWTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu bWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UEAxMYRmVkZXJhbCBDb21tb24gUG9s aWN5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2HX7NRY0WkG/ Wq9cMAQUHK14RLXqJup1YcfNNnn4fNi9KVFmWSHjeavUeL6wLbCh1bI1FiPQzB6+ Duir3MPJ1hLXp3JoGDG4FyKyPn66CG3G/dFYLGmgA/Aqo/Y/ISU937cyxY4nsyOl 4FKzXZbpsLjFxZ+7xaBugkC7xScFNknWJidpDDSPzyd6KgqjQV+NHQOGgxXgVcHF mCye7Bpy3EjBPvmE0oSCwRvDdDa3ucc2Mnr4MrbQNq4iGDGMUHMhnv6DOzCIJOPp wX7e7ZjHH5IQip9bYi+dpLzVhW86/clTpyBLqtsgqyFOHQ1O5piF5asRR12dP8Qj wOMUBm7+nQIDAQABo4IBMDCCASwwDwYDVR0TAQH/BAUwAwEB/zCB6QYIKwYBBQUH AQsEgdwwgdkwPwYIKwYBBQUHMAWGM2h0dHA6Ly9odHRwLmZwa2kuZ292L2ZjcGNh L2NhQ2VydHNJc3N1ZWRCeWZjcGNhLnA3YzCBlQYIKwYBBQUHMAWGgYhsZGFwOi8v bGRhcC5mcGtpLmdvdi9jbj1GZWRlcmFsJTIwQ29tbW9uJTIwUG9saWN5JTIwQ0Es b3U9RlBLSSxvPVUuUy4lMjBHb3Zlcm5tZW50LGM9VVM/Y0FDZXJ0aWZpY2F0ZTti aW5hcnksY3Jvc3NDZXJ0aWZpY2F0ZVBhaXI7YmluYXJ5MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUrQx6dVzl85jEeZgOrCj9l/TnAvwwDQYJKoZIhvcNAQELBQAD ggEBAI9z2uF/gLGH9uwsz9GEYx728Yi3mvIRte9UrYpuGDco71wb5O9Qt2wmGCMi TR0mRyDpCZzicGJxqxHPkYnos/UqoEfAFMtOQsHdDA4b8Idb7OV316rgVNdF9IU+ 7LQd3nyKf1tNnJaK0KIyn9psMQz4pO9+c+iR3Ah6cFqgr2KBWfgAdKLI3VTKQVZH venAT+0g3eOlCd+uKML80cgX2BLHb94u6b2akfI8WpQukSKAiaGMWMyDeiYZdQKl Dn0KJnNR6obLB6jI/WNaNZvSr79PMUjBhHDbNXuaGQ/lj/RqDG8z2esccKIN47lQ A2EC/0rskqTcLe4qNJMHtyznGI8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU 1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV 5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz rD6ogRLQy7rQkgu2npaqBA+K -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz +uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn 5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G spki4cErx5z481+oghLrGREt -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl 4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r 6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs ewv4n4Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc 8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg 515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO xwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG 3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO 291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH WD9f -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h /t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf ReYNnyicsbkqWletNw+vHX/bvZ8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH /PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu 9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo 2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI 4uJEvlz36hz1 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFSzCCAzOgAwIBAgIRALZLiAfiI+7IXBKtpg4GofIwDQYJKoZIhvcNAQELBQAw PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eTAeFw0xMjA5MjgwODU4NTFaFw0zNzEyMzExNTU5NTla MD8xCzAJBgNVBAYTAlRXMTAwLgYDVQQKDCdHb3Zlcm5tZW50IFJvb3QgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQC2/5c8gb4BWCQnr44BK9ZykjAyG1+bfNTUf+ihYHMwVxAA+lCWJP5Q5ow6ldFX eYTVZ1MMKoI+GFy4MCYa1l7GLbIEUQ7v3wxjR+vEEghRK5lxXtVpe+FdyXcdIOxW juVhYC386RyA3/pqg7sFtR4jEpyCygrzFB0g5AaPQySZn7YKk1pzGxY5vgW28Yyl ZJKPBeRcdvc5w88tvQ7Yy6gOMZvJRg9nU0MEj8iyyIOAX7ryD6uBNaIgIZfOD4k0 eA/PH07p+4woPN405+2f0mb1xcoxeNLOUNFggmOd4Ez3B66DNJ1JSUPUfr0t4urH cWWACOQ2nnlwCjyHKenkkpTqBpIpJ3jmrdc96QoLXvTg1oadLXLLi2RW5vSueKWg OTNYPNyoj420ai39iHPplVBzBN8RiD5C1gJ0+yzEb7xs1uCAb9GGpTJXA9ZN9E4K mSJ2fkpAgvjJ5E7LUy3Hsbbi08J1J265DnGyNPy/HE7CPfg26QrMWJqhGIZO4uGq s3NZbl6dtMIIr69c/aQCb/+4DbvVq9dunxpPkUDwH0ZVbaCSw4nNt7H/HLPLo5wK 4/7NqrwB7N1UypHdTxOHpPaY7/1J1lcqPKZc9mA3v9g+fk5oKiMyOr5u5CI9ByTP isubXVGzMNJxbc5Gim18SjNE2hIvNkvy6fFRCW3bapcOFwIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBTVZx3gnHosnMvFmOcdByYqhux0zTAOBgNV HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAJA75cJTQijq9TFOjj2Rnk0J 89ixUuZPrAwxIbvx6pnMg/y2KOTshAcOD06Xu29oRo8OURWV+Do7H1+CDgxxDryR T64zLiNB9CZrTxOH+nj2LsIPkQWXqmrBap+8hJ4IKifd2ocXhuGzyl3tOKkpboTe Rmv8JxlQpRJ6jH1i/NrnzLyfSa8GuCcn8on3Fj0Y5r3e9YwSkZ/jBI3+BxQaWqw5 ghvxOBnhY+OvbLamURfr+kvriyL2l/4QOl+UoEtTcT9a4RD4co+WgN2NApgAYT2N vC2xR8zaXeEgp4wxXPHj2rkKhkfIoT0Hozymc26Uke1uJDr5yTDRB6iBfSZ9fYTf hsmL5a4NHr6JSFEVg5iWL0rrczTXdM3Jb9DCuiv2mv6Z3WAUjhv5nDk8f0OJU+jl wqu+Iq0nOJt3KLejY2OngeepaUXrjnhWzAWEx/uttjB8YwWfLYwkf0uLkvw4Hp+g pVezbp3YZLhwmmBScMip0P/GnO0QYV7Ngw5u6E0CQUridgR51lQ/ipgyFKDdLZzn uoJxo4ZVKZnSKdt1OvfbQ/+2W/u3fjWAjg1srnm3Ni2XUqGwB5wH5Ss2zQOXlL0t DjQG/MAWifw3VOTWzz0TBPKR2ck2Lj7FWtClTILD/y58Jnb38/1FoqVuVa4uzM8s iTTa9g3nkagQ6hed8vbs -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD 75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp 5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p 6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI l7WdmplNsDz4SgCbZN2fOUvRJ9e4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi AmvZWg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFHjCCBAagAwIBAgIEAKA3oDANBgkqhkiG9w0BAQsFADCBtzELMAkGA1UEBhMC Q1oxOjA4BgNVBAMMMUkuQ0EgLSBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHksIDA5LzIwMDkxLTArBgNVBAoMJFBydm7DrSBjZXJ0aWZpa2HEjW7DrSBh dXRvcml0YSwgYS5zLjE9MDsGA1UECww0SS5DQSAtIEFjY3JlZGl0ZWQgUHJvdmlk ZXIgb2YgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlczAeFw0wOTA5MDEwMDAwMDBaFw0x OTA5MDEwMDAwMDBaMIG3MQswCQYDVQQGEwJDWjE6MDgGA1UEAwwxSS5DQSAtIFF1 YWxpZmllZCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSwgMDkvMjAwOTEtMCsGA1UE CgwkUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRhLCBhLnMuMT0wOwYDVQQL DDRJLkNBIC0gQWNjcmVkaXRlZCBQcm92aWRlciBvZiBDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtTaEy0KC8M9l 4lSaWHMs4+sVV1LwzyJYiIQNeCrv1HHm/YpGIdY/Z640ceankjQvIX7m23BK4OSC 6KO8kZYA3zopOz6GFCOKV2PvLukbc+c2imF6kLHEv6qNA8WxhPbR3xKwlHDwB2yh Wzo7V3QVgDRG83sugqQntKYC3LnlTGbJpNP+Az72gpO9AHUn/IBhFk4ksc8lYS2L 9GCy9CsmdKSBP78p9w8Lx7vDLqkDgt1/zBrcUWmSSb7AE/BPEeMryQV1IdI6nlGn BhWkXOYf6GSdayJw86btuxC7viDKNrbp44HjQRaSxnp6O3eto1x4DfiYdw/YbJFe 7EjkxSQBywIDAQABo4IBLjCCASowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwgecGA1UdIASB3zCB3DCB2QYEVR0gADCB0DCBzQYIKwYBBQUHAgIwgcAa gb1UZW50byBjZXJ0aWZpa2F0IGplIHZ5ZGFuIGpha28ga3ZhbGlmaWtvdmFueSBz eXN0ZW1vdnkgY2VydGlmaWthdCBwb2RsZSB6YWtvbmEgYy4gMjI3LzIwMDAgU2Iu IHYgcGxhdG5lbSB6bmVuaS9UaGlzIGlzIHF1YWxpZmllZCBzeXN0ZW0gY2VydGlm aWNhdGUgYWNjb3JkaW5nIHRvIEN6ZWNoIEFjdCBOby4gMjI3LzIwMDAgQ29sbC4w HQYDVR0OBBYEFHnL0CPpOmdwkXRP01Hi4CD94Sj7MA0GCSqGSIb3DQEBCwUAA4IB AQB9laU214hYaBHPZftbDS/2dIGLWdmdSbj1OZbJ8LIPBMxYjPoEMqzAR74tw96T i6aWRa5WdOWaS6I/qibEKFZhJAVXX5mkx2ewGFLJ+0Go+eTxnjLOnhVF2V2s+57b m8c8j6/bS6Ij6DspcHEYpfjjh64hE2r0aSpZDjGzKFM6YpqsCJN8qYe2X1qmGMLQ wvNdjG+nPzCJOOuUEypIWt555ZDLXqS5F7ZjBjlfyDZjEfS2Es9Idok8alf563Mi 9/o+Ba46wMYOkk3P1IlU0RqCajdbliioACKDztAqubONU1guZVzV8tuMASVzbJeL /GAB7ECTwe1RuKrLYtglMKI9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT 3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU +ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH 6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 +wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG 4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A 7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF /YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R 3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy 9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ 2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 +bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv 8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXzCCA0egAwIBAgIBATANBgkqhkiG9w0BAQUFADCB0DELMAkGA1UEBhMCRVMx SDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMuVml0 b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwgTWVk aXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6MRMw EQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5wZS5j b20wHhcNMDMwMTMwMjMwMDAwWhcNMTgwMTMwMjMwMDAwWjCB0DELMAkGA1UEBhMC RVMxSDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMu Vml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwg TWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6 MRMwEQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5w ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1btoCXXhp3xIW D+Bxl8nUCxkyiazWfpt0e68t+Qt9+lZjKZSdEw2Omj4qvr+ovRmDXO3iWpWVOWDl 3JHJjAzFCe8ZEBNDH+QNYwZHmPBaMYFOYFdbAFVHWvys152C308hcFJ6xWWGmjvl 2eMiEl9P2nR2LWue368DCu+ak7j3gjAXaCOdP1a7Bfr+RW3X2SC5R4Xyp8iHlL5J PHJD/WBkLrezwzQPdACw8m9EG7q9kUwlNpL32mROujS3ZkT6mQTzJieLiE3X04s0 uIUqVkk5MhjcHFf7al0N5CzjtTcnXYJKN2Z9EDVskk4olAdGi46eSoZXbjUOP5gk Ej6wVZAXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MB0GA1UdDgQWBBTqVk/sPIOhFIh4gbIrBSLAB0FbQjANBgkqhkiG9w0BAQUFAAOC AQEAYp7mEzzhw6o5Hf5+T5kcI+t4BJyiIWy7vHlLs/G8dLYXO81aN/Mzg928eMTR TxxYZL8dd9uwsJ50TVfX6L0R4Dyw6wikh3fHRrat9ufXi63j5K91Ysr7aXqnF38d iAgHYkrwC3kuxHBb9C0KBz6h8Q45/KCyN7d37wWAq38yyhPDlaOvyoE6bdUuK5hT m5EYA5JmPyrhQ1moDOyueWBAjxzMEMj+OAY1H90cLv6wszsqerxRrdTOHBdv7MjB EIpvEEQkXUxVXAzFuuT6m2t91Lfnwfl/IvljHaVC7DlyyhRYHD6D4Rx+4QKp4tWL vpw6LkI+gKNJ/YdMCsRZQzEEFA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8DCCA9igAwIBAgIPBuhGJy8fCo/RhFzjafbVMA0GCSqGSIb3DQEBBQUAMDgx CzAJBgNVBAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXpl bnBlLmNvbTAeFw0wNzEyMTMxMzA4MjdaFw0zNzEyMTMwODI3MjVaMDgxCzAJBgNV BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXplbnBlLmNv bTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMnTesoPHqynhugWZWqx whtFMnGV2f4QW8yv56V5AY+Jw8ryVXH3d753lPNypCxE2J6SmxQ6oeckkAoKVo7F 2CaU4dlI4S0+2gpy3aOZFdqBoof0e24md4lYrdbrDLJBenNubdt6eEHpCIgSfocu ZhFjbFT7PJ1ywLwu/8K33Q124zrX97RovqL144FuwUZvXY3gTcZUVYkaMzEKsVe5 o4qYw+w7NMWVQWl+dcI8IMVhulFHoCCQk6GQS/NOfIVFVJrRBSZBsLVNHTO+xAPI JXzBcNs79AktVCdIrC/hxKw+yMuSTFM5NyPs0wH54AlETU1kwOENWocivK0bo/4m tRXzp/yEGensoYi0RGmEg/OJ0XQGqcwL1sLeJ4VQJsoXuMl6h1YsGgEebL4TrRCs tST1OJGh1kva8bvS3ke18byB9llrzxlT6Y0Vy0rLqW9E5RtBz+GGp8rQap+8TI0G M1qiheWQNaBiXBZO8OOi+gMatCxxs1gs3nsL2xoP694hHwZ3BgOwye+Z/MC5TwuG KP7Suerj2qXDR2kS4Nvw9hmL7Xtw1wLW7YcYKCwEJEx35EiKGsY7mtQPyvp10gFA Wo15v4vPS8+qFsGV5K1Mij4XkdSxYuWC5YAEpAN+jb/af6IPl08M0w3719Hlcn4c yHf/W5oPt64FRuXxqBbsR6QXAgMBAAGjgfYwgfMwgbAGA1UdEQSBqDCBpYEPaW5m b0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBB MDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEG A1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEw IFZpdG9yaWEtR2FzdGVpejAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUHRxlDqjyJXu0kc/ksbHmvVV0bAUwDQYJKoZIhvcNAQEFBQAD ggIBAMeBRm8hGE+gBe/n1bqXUKJg7aWSFBpSm/nxiEqg3Hh10dUflU7F57dp5iL0 +CmoKom+z892j+Mxc50m0xwbRxYpB2iEitL7sRskPtKYGCwkjq/2e+pEFhsqxPqg l+nqbFik73WrAGLRne0TNtsiC7bw0fRue0aHwp28vb5CO7dz0JoqPLRbEhYArxk5 ja2DUBzIgU+9Ag89njWW7u/kwgN8KRwCfr00J16vU9adF79XbOnQgxCvv11N75B7 XSus7Op9ACYXzAJcY9cZGKfsK8eKPlgOiofmg59OsjQerFQJTx0CCzl+gQgVuaBp E8gyK+OtbBPWg50jLbJtooiGfqgNASYJQNntKE6MkyQP2/EeTXp6WuKlWPHcj1+Z ggwuz7LdmMySlD/5CbOlliVbN/UShUHiGUzGigjB3Bh6Dx4/glmimj4/+eAJn/3B kUtdyXvWton83x18hqrNA/ILUpLxYm9/h+qrdslsUMIZgq+qHfUgKGgu1fxkN0/P pUTEvnK0jHS0bKf68r10OEMr3q/53NjgnZ/cPcqlY0S/kqJPTIAcuxrDmkoEVU3K 7iYLHL8CxWTTnn7S05EcS6L1HOUXHA0MUqORH5zwIe0ClG+poEnK6EOMxPQ02nwi o8ZmPrgbBYhdurz3vOXcFD2nhqi2WVIhA16L4wTtSyoeo09Q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDczCCAlugAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN MAsGA1UECgwES0lTQTEuMCwGA1UECwwlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkgQ2VudHJhbDEWMBQGA1UEAwwNS0lTQSBSb290Q0EgMTAeFw0wNTA4MjQw ODA1NDZaFw0yNTA4MjQwODA1NDZaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKDARL SVNBMS4wLAYDVQQLDCVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 cmFsMRYwFAYDVQQDDA1LSVNBIFJvb3RDQSAxMIIBIDANBgkqhkiG9w0BAQEFAAOC AQ0AMIIBCAKCAQEAvATk+hM58DSWIGtsaLv623f/J/es7C/n/fB/bW+MKs0lCVsk 9KFo/CjsySXirO3eyDOE9bClCTqnsUdIxcxPjHmc+QZXfd3uOPbPFLKc6tPAXXdi 8EcNuRpAU1xkcK8IWsD3z3X5bI1kKB4g/rcbGdNaZoNy4rCbvdMlFQ0yb2Q3lIVG yHK+d9VuHygvx2nt54OJM1jT3qC/QOhDUO7cTWu8peqmyGGO9cNkrwYV3CmLP3WM vHFE2/yttRcdbYmDz8Yzvb9Fov4Kn6MRXw+5H5wawkbMnChmn3AmPC7fqoD+jMUE CSVPzZNHPDfqAmeS/vwiJFys0izgXAEzisEZ2wIBA6MyMDAwHQYDVR0OBBYEFL+2 J9gDWnZlTGEBQVYx5Yt7OtnMMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF BQADggEBABOvUQveimpb5poKyLGQSk6hAp3MiNKrZr097LuxQpVqslxa/6FjZJap aBV/JV6K+KRzwYCKhQoOUugy50X4TmWAkZl0Q+VFnUkq8JSV3enhMNITbslOsXfl BM+tWh6UCVrXPAgcrnrpFDLBRa3SJkhyrKhB2vAhhzle3/xk/2F0KpzZm4tfwjeT 2KM3LzuTa7IbB6d/CVDv0zq+IWuKkDsnSlFOa56ch534eJAx7REnxqhZvvwYC/uO fi5C4e3nCSG9uRPFVmf0JqZCQ5BEVLRxm3bkGhKsGigA35vB1fjbXKP4krG9tNT5 UNkAAk/bg9ART6RCVmE6fhMy04Qfybo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 +rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c 2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C +C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH /nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg 4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ /L7fCg0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX 1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P 99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh 4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc 3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz 8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l 7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE +V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp +ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og /zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y 4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza 8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR /xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP 0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf 3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl 8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB 4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd 8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A 4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd +LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B 4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK 4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK SnQ2+Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa /FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO 0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj 7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS 8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ 3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy 1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt 5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s 3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu 8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ 3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS /ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH 1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u 2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc 7uzXLg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp 5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy 5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv 6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen 5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL +63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR 9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az 5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh /WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw 0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq 4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR 1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM 94B7IWcnMFk= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf 8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN +lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA 1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg 8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk 6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn 0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN sSi6 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1 OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/ Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM 0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9 Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K 2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl 6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK 9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ 9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst 0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK 1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ 8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm fyWl8kgAwKQB2j8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo 19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e 3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 MBr1mmz0DlP5OlvRHA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBk MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg Q0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2MjUwNzM4MTRaMGQxCzAJBgNVBAYT AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvEr jw0DzpPMLgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r 0rk0X2s682Q2zsKwzxNoysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f 2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJwDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVP ACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpHWrumnf2U5NGKpV+GY3aF y6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1aSgJA/MTA tukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL 6yxSNLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0 uPoTXGiTOmekl9AbmbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrAL acywlKinh/LTSlDcX3KwFnUey7QYYpqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velh k6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3qPyZ7iVNTA6z00yPhOgpD/0Q VAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw FDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqh b97iEoHF8TwuMA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4R fbgZPnm3qKhyN2abGu2sEzsOv2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv /2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ82YqZh6NM4OKb3xuqFp1mrjX2lhI REeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLzo9v/tdhZsnPdTSpx srpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcsa0vv aGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciAT woCqISxxOQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99n Bjx8Oto0QuFmtEYE3saWmA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5W t6NlUe07qxS/TFED6F+KBZvuim6c779o+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N 8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TCrvJcwhbtkj6EPnNgiLx2 9CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX5OfNeOI5 wSsSnqaeG8XmDtkx2Q== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAw ZzELMAkGA1UEBhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdp dGFsIENlcnRpZmljYXRlIFNlcnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290 IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcNMzEwNjI1MDg0NTA4WjBnMQswCQYD VQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2Vy dGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYgQ0Eg MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7Bx UglgRCgzo3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD 1ycfMQ4jFrclyxy0uYAyXhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPH oCE2G3pXKSinLr9xJZDzRINpUKTk4RtiGZQJo/PDvO/0vezbE53PnUgJUmfANykR HvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8LiqG12W0OfvrSdsyaGOx9/ 5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaHZa0zKcQv idm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHL OdAGalNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaC NYGu+HuB5ur+rPQam3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f 46Fq9mDU5zXNysRojddxyNMkM3OxbPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCB UWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDixzgHcgplwLa7JSnaFp6LNYth 7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/BAQDAgGGMB0G A1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWB bj2ITY1x0kbBbkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6x XCX5145v9Ydkn+0UjrgEjihLj6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98T PLr+flaYC/NUn81ETm484T4VvwYmneTwkLbUwp4wLh/vx3rEUMfqe9pQy3omywC0 Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7XwgiG/W9mR4U9s70 WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH59yL Gn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm 7JFe3VE/23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4S nr8PyQUQ3nqjsTzyP6WqJ3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VN vBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyAHmBR3NdUIR7KYndP+tiPsys6DXhyyWhB WkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/giuMod89a2GQ+fYWVq6nTI fI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuWl8PVP3wb I+2ksx0WckNLIOFZfsLorSa/ovc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c 6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn 8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a 77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFejCCA2KgAwIBAgIJAN7E8kTzHab8MA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJDAiBgNVBAMTG1N3aXNzU2ln biBHb2xkIFJvb3QgQ0EgLSBHMzAeFw0wOTA4MDQxMzMxNDdaFw0zNzA4MDQxMzMx NDdaMEoxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJDAiBgNV BAMTG1N3aXNzU2lnbiBHb2xkIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEB BQADggIPADCCAgoCggIBAMPon8hlWp1nG8FFl7S0h0NbYWCAnvJ/XvlnRN1E+qu1 q3f/KhlMzm/Ej0Gf4OLNcuDR1FJhQQkKvwpw++CDaWEpytsimlul5t0XlbBvhI46 PmRaQfsbWPz9Kz6ypOasyYK8zvaV+Jd37Sb2WK6eJ+IPg+zFNljIe8/Vh6GphxoT Z2EBbaZpnOKQ8StoZfPosHz8gj3erdgKAAlEeROc8P5udXvCvLNZAQt8xdUt8L// bVfSSYHrtLNQrFv5CxUVjGn/ozkB7fzc3CeXjnuL1Wqm1uAdX80Bkeb1Ipi6LgkY OG8TqIHS+yE35y20YueBkLDGeVm3Z3X+vo87+jbsr63ST3Q2AeVXqyMEzEpel89+ xu+MzJUjaY3LOMcZ9taKABQeND1v2gwLw7qX/BFLUmE+vzNnUxC/eBsJwke6Hq9Y 9XWBf71W8etW19lpDAfpNzGwEhwy71bZvnorfL3TPbxqM006PFAQhyfHegpnU9t/ gJvoniP6+Qg6i6GONFpIM19k05eGBxl9iJTOKnzFat+vvKmfzTqmurtU+X+P388O WsStmryzOndzg0yTPJBotXxQlRHIgl6UcdBBGPvJxmXszom2ziKzEVs/4J0+Gxho DaoDoWdZv2udvPjyZS+aQTpF2F7QNmxvOx5jtI6YTBPbIQ6fe+3qoKpxw+ujoNIl AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBRclwZGNKvfMMV8xQ1VcWYwtWCPnjAfBgNVHSMEGDAWgBRclwZGNKvfMMV8 xQ1VcWYwtWCPnjANBgkqhkiG9w0BAQsFAAOCAgEAd0tN3uqFSqssJ9ZFx/FfIMFb YO0Hy6Iz3DbPx5TxBsfV2s/NrYQ+/xJIf0HopWZXMMQd5KcaLy1Cwe9Gc7LV9Vr9 Dnpr0sgxow1IlldlY1UYwPzkisyYhlurDIonN/ojaFlcJtehwcK5Tiz/KV7mlAu+ zXJPleiP9ve4Pl7Oz54RyawDKUiKqbamNLmsQP/EtnM3scd/qVHbSypHX0AkB4gG tySz+3/3sIsz+r8jdaNc/qplGsK+8X2BdwOBsY3XlQ16PEKYt4+pfVDh31IGmqBS VHiDB2FSCTdeipynxlHRXGPRhNzC29L6Wxg2fWa81CiXL3WWHIQHrIuOUxG+JCGq Z/LBrYic07B4Z3j101gDIApdIPG152XMDiDj1d/mLxkrhWjBBCbPj+0FU6HdBw7r QSbHtKksW+NpPWbAYhvAqobAN8MxBIZwOb5rXyFAQaB/5dkPOEtwX0n4hbgrLqof k0FD+PuydDwfS1dbt9RRoZJKzr4Qou7YFCJ7uUG9jemIqdGPAxpg/z+HiaCZJyJm sD5onnKIUTidEz5FbQXlRrVz7UOGsRQKHrzaDb8eJFxmjw6+of3G62m8Q3nXA3b5 3IeZuJjEzX9tEPkQvixC/pwpTYNrCr21jsRIiv0hB6aAfR+b6au9gmFECnEnX22b kJ6u/zYks2gD1pWMa3M= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ 6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl +zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgTCCA2mgAwIBAgIIIj+pFyDegZQwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEoMCYGA1UEAxMfU3dpc3NTaWdu IFBsYXRpbnVtIFJvb3QgQ0EgLSBHMzAeFw0wOTA4MDQxMzM0MDRaFw0zNzA4MDQx MzM0MDRaME4xCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxKDAm BgNVBAMTH1N3aXNzU2lnbiBQbGF0aW51bSBSb290IENBIC0gRzMwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCUoO8TG59EIBvNxaoiu9nyUj56Wlh35o2h K8ncpPPksxOUAGKbHPJDUEOBfq8wNkmsGIkMGEW4PsdUbePYmllriholqba1Dbd9 I/BffagHqfc+hi7IAU3c5jbtHeU3B2kSS+OD0QQcJPAfcHHnGe1zSG6VKxW2VuYC 31bpm/rqpu7gwsO64MzGyHvXbzqVmzqPvlss0qmgOD7WiOGxYhOO3KswZ82oaqZj K4Kwy8c9Tu1y9n2rMk5lAusPmXT4HBoojA5FAJMsFJ9txxue9orce3jjtJRHHU0F bYR6kFSynot1woDfhzk/n/tIVAeNoCn1+WBfWnLou5ugQuAIADSjFTwT49YaawKy lCGjnUG8KmtOMzumlDj8PccrM7MuKwZ0rJsQb8VORfddoVYDLA1fer0e3h13kGva pS2KTOnfQfTnS+x9lUKfTKkJD0OIPz2T5yv0ekjaaMTdEoAxGl0kVCamJCGzTK3a Fwg2AlfGnIZwyXXJnnxh2HjmuegUafkcECgSXUt1ULo80GdwVVVWS/s9HNjbeU2X 37ie2xcs1TUHuFCp9473Vv96Z0NPINnKZtY4YEvulDHWDaJIm/80aZTGNfWWiO+q ZsyBputMU/8ydKe2nZhXtLomqfEzM2J+OrADEVf/3G8RI60+xgrQzFS3LcKTHeXC pozH2O9T9wIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUVio/kFj0F1oUstcIG4VbVGpUGigwHwYDVR0jBBgwFoAUVio/ kFj0F1oUstcIG4VbVGpUGigwDQYJKoZIhvcNAQELBQADggIBAGztiudDqHknm7jP hz5kOBiMEUKShjfgWMMb7gQu94TsgxBoDH94LZzCl442ThbYDuprSK1Pnl0NzA2p PhiFfsxomTk11tifhsEy+01lsyIUS8iFZtoX/3GRrJxWV95xLFZCv/jNDvCi0//S IhX70HgKfuGwWs6ON9upnueVz2PyLA3S+m/zyNX7ALf3NWcQ03tS7BAy+L/dXsmm gqTxsL8dLt0l5L1N8DWpkQFH+BAClFvrPusNutUdYyylLqvn4x6j7kuqX7FmAbSC WvlGS8fx+N8svv113ZY4mjc6bqXmMhVus5DAOYp0pZWgvg0uiXnNKVaOw15XUcQF bwRVj4HpTL1ZRssqvE3JHfLGTwXkyAQN925P2sM6nNLC9enGJHoUPhxCMKgCRTGp /FCp3NyGOA9bkz9/CE5qDSc6EHlWwxW4PgaG9tlwZ691eoviWMzGdU8yVcVsFAko O/KV5GreLCgHraB9Byjd1Fqj6aZ8E4yZC1J429nR3z5aQ3Z/RmBTws3ndkd8Vc20 OWQQW5VLNV1EgyTV4C4kDMGAbmkAgAZ3CmaCEAxRbzeJV9vzTOW4ue4jZpdgt1Ld 2Zb7uoo7oE3OXvBETJDMIU8bOphrjjGD+YMIUssZwTVr7qEVW4g/bazyNJJTpjAq E9fmhqhd2ULSx52peovL3+6iMcLl -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH 6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ 2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFfjCCA2agAwIBAgIJAKqIsFoLsXabMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJjAkBgNVBAMTHVN3aXNzU2ln biBTaWx2ZXIgUm9vdCBDQSAtIEczMB4XDTA5MDgwNDEzMTkxNFoXDTM3MDgwNDEz MTkxNFowTDELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEmMCQG A1UEAxMdU3dpc3NTaWduIFNpbHZlciBSb290IENBIC0gRzMwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQC+h5sF5nF8Um9t7Dep6bPczF9/01DqIZsE8D2/ vo7JpRQWMhDPmfzscK1INmckDBcy1inlSjmxN+umeAxsbxnKTvdR2hro+iE4bJWc L9aLzDsCm78mmxFFtrg0Wh2mVEhSyJ14cc5ISsyneIPcaKtmHncH0zYYCNfUbWD4 8HnTMzYJkmO3BJr1p5baRa90GvyC46hbDjo/UleYfrycjMHAslrfxH7+DKZUdoN+ ut3nKvRKNk+HZS6lujmNWWEp89OOJHCMU5sRpUcHsnUFXA2E2UTZzckmRFduAn2V AdSrJIbuPXD7V/qwKRTQnfLFl8sJyvHyPefYS5bpiC+eR1GKVGWYSNIS5FR3DAfm vluc8d0Dfo2E/L7JYtX8yTroibVfwgVSYfCcPuwuTYxykY7IQ8GiKF71gCTc4i+H O1MA5cvwsnyNeRmgiM14+MWKWnflBqzdSt7mcG6+r771sasOCLDboD+Uxb4Subx7 J3m1MildrsUgI5IDe1Q5sIkiVG0S48N46jpA/aSTrOktiDzbpkdmTN/YF+0W3hrW 10Fmvx2A8aTgZBEpXgwnBWLr5cQEYtHEnwxqVdZYOJxmD537q1SAmZzsSdaCn9pF 1j9TBgO3/R/shn104KS06DK2qgcj+O8kQZ5jMHj0VN2O8Fo4jhJ/eMdvAlYhM864 uK1pVQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd BgNVHQ4EFgQUoYxFkwoSYwunV18ySn3hIee3PmYwHwYDVR0jBBgwFoAUoYxFkwoS YwunV18ySn3hIee3PmYwDQYJKoZIhvcNAQELBQADggIBAIeuYW1IOCrGHNxKLoR4 ScAjKkW4NU3RBfq5BTPEZL3brVQWKrA+DVoo2qYagHMMxEFvr7g0tnfUW44dC4tG kES1s+5JGInBSzSzhzV0op5FZ+1FcWa2uaElc9fCrIj70h2na9rAWubYWWQ0l2Ug MTMDT86tCZ6u6cI+GHW0MyUSuwXsULpxQOK93ohGBSGEi6MrHuswMIm/EfVcRPiR i0tZRQswDcoMT29jvgT+we3gh/7IzVa/5dyOetTWKU6A26ubP45lByL3RM2WHy3H 9Qm2mHD/ONxQFRGEO3+p8NgkVMgXjCsTSdaZf0XRD46/aXI3Uwf05q79Wz55uQbN uIF4tE2g0DW65K7/00m8Ne1jxrP846thWgW2C+T/qSq+31ROwktcaNqjMqLJTVcY UzRZPGaZ1zwCeKdMcdC/2/HEPOcB5gTyRPZIJjAzybEBGesC8cwh+joCMBedyF+A P90lrAKb4xfevcqSFNJSgVPm6vwwZzKpYvaTFxUHMV4PG2n19Km3fC2z7YREMkco BzuGaUWpxzaWkHJ02BKmcyPRTrm2ejrEKaFQBhG52fQmbmIIEiAW8AFXF9QFNmeX 61H5/zMkDAUPVr/vPRxSjoreaQ9aH/DVAzFEs5LG6nWorrvHYAOImP/HBIRSkIbh tJOpUC/o69I2rDBgp9ADE7UK -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICqDCCAi2gAwIBAgIQIW4zpcvTiKRvKQe0JzzE2DAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAxIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAATXZrUb266zYO5G6ohjdTsqlG3zXxL24w+etgoUU0hS yNw6s8tIICYSTvqJhNTfkeQpfSgB2dsYQ2mhH7XThhbcx39nI9/fMTGDAzVwsUu3 yBe7UcvclBfb6gk7dhLeqrWjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRlwI0l9Qy6l3eQP54u4Fr1ztXh5DAKBggqhkjOPQQD AwNpADBmAjEApa7jRlP4mDbjIvouKEkN7jB+M/PsP3FezFWJeJmssv3cHFwzjim5 axfIEWi13IMHAjEAnMhE2mnCNsNUGRCFAtqdR+9B52wmnQk9922Q0QVEL7C8g5No 8gxFSTm/mQQc0xCg -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9jCCAt6gAwIBAgIQJDJ18h0v0gkz97RqytDzmDANBgkqhkiG9w0BAQsFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAx IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHOddJZKmZgiJM6kXZBxbje/SD 6Jlz+muxNuCad6BAwoGNAcfMjL2Pffd543pMA03Z+/2HOCgs3ZqLVAjbZ/sbjP4o ki++t7JIp4Gh2F6Iw8w5QEFa0dzl2hCfL9oBTf0uRnz5LicKaTfukaMbasxEvxvH w9QRslBglwm9LiL1QYRmn81ApqkAgMEflZKf3vNI79sdd2H8f9/ulqRy0LY+/3gn r8uSFWkI22MQ4uaXrG7crPaizh5HmbmJtxLmodTNWRFnw2+F2EJOKL5ZVVkElauP N4C/DfD8HzpkMViBeNfiNfYgPym4jxZuPkjctUwH4fIa6n4KedaovetdhitNAgMB AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBQzQejIORIVk0jyljIuWvXalF9TYDANBgkqhkiG9w0BAQsFAAOCAQEAFeNzV7EX tl9JaUSm9l56Z6zS3nVJq/4lVcc6yUQVEG6/MWvL2QeTfxyFYwDjMhLgzMv7OWyP 4lPiPEAz2aSMR+atWPuJr+PehilWNCxFuBL6RIluLRQlKCQBZdbqUqwFblYSCT3Q dPTXvQbKqDqNVkL6jXI+dPEDct+HG14OelWWLDi3mIXNTTNEyZSPWjEwN0ujOhKz 5zbRIWhLLTjmU64cJVYIVgNnhJ3Gw84kYsdMNs+wBkS39V8C3dlU6S+QTnrIToNA DJqXPDe/v+z28LSFdyjBC8hnghAXOKK3Buqbvzr46SMHv3TgmDgVVXjucgBcGaP0 0jPg/73RVDkpDw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICqDCCAi2gAwIBAgIQNBdlEkA7t1aALYDLeVWmHjAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAyIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAATR2UqOTA2ESlG6fO/TzPo6mrWnYxM9AeBJPvrBR8mS szrX/m+c95o6D/UOCgrDP8jnEhSO1dVtmCyzcTIK6yq99tdqIAtnRZzSsr9TImYJ XdsR8/EFM1ij4rjPfM2Cm72jQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBQ9MvM6qQyQhPmijGkGYVQvh3L+BTAKBggqhkjOPQQD AwNpADBmAjEAyKapr0F/tckRQhZoaUxcuCcYtpjxwH+QbYfTjEYX8D5P/OqwCMR6 S7wIL8fip29lAjEA1lnehs5fDspU1cbQFQ78i5Ry1I4AWFPPfrFLDeVQhuuea9// KabYR9mglhjb8kWz -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID9jCCAt6gAwIBAgIQZIKe/DcedF38l/+XyLH/QTANBgkqhkiG9w0BAQsFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAy IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNzOkFyGOFyz9AYxe9GPo15gRn V2WYKaRPyVyPDzTS+NqoE2KquB5QZ3iwFkygOakVeq7t0qLA8JA3KRgmXOgNPLZs ST/B4NzZS7YUGQum05bh1gnjGSYc+R9lS/kaQxwAg9bQqkmi1NvmYji6UBRDbfkx +FYW2TgCkc/rbN27OU6Z4TBnRfHU8I3D3/7yOAchfQBeVkSz5GC9kSucq1sEcg+y KNlyqwUgQiWpWwNqIBDMMfAr2jUs0Pual07wgksr2F82owstr2MNHSV/oW5cYqGN KD6h/Bwg+AEvulWaEbAZ0shQeWsOagXXqgQ2sqPy4V93p3ec5R7c6d9qwWVdAgMB AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW BBSHjCCVyJhK0daABkqQNETfHE2/sDANBgkqhkiG9w0BAQsFAAOCAQEAgY6ypWaW tyGltu9vI1pf24HFQqV4wWn99DzX+VxrcHIa/FqXTQCAiIiCisNxDY7FiZss7Y0L 0nJU9X3UXENX6fOupQIR9nYrgVfdfdp0MP1UR/bgFm6mtApI5ud1Bw8pGTnOefS2 bMVfmdUfS/rfbSw8DVSAcPCIC4DPxmiiuB1w2XaM/O6lyc+tHc+ZJVdaYkXLFmu9 Sc2lo4xpeSWuuExsi0BmSxY/zwIa3eFsawdhanYVKZl/G92IgMG/tY9zxaaWI4Sm KIYkM2oBLldzJbZev4/mHWGoQClnHYebHX+bn5nNMdZUvmK7OaxoEkiRIKXLsd3+ b/xa5IJVWa8xqQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICpzCCAi2gAwIBAgIQTHm1miicdjFk9YlE0JEC3jAKBggqhkjOPQQDAzCBlDEL MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD bGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g RzQwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UEBhMC VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAzIFB1 YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAARXz+qzOU0/oSHgbi84csaHl/OFC0fnD1HI0fSZm8pZ Zf9M+eoLtyXV0vbsMS0yYhLXdoan+jjJZdT+c+KEOfhMSWIT3brViKBfPchPsD+P oVAR5JNGrcNfy/GkapVW6MCjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBQknbzScfcdwiW+IvGJpSwVOzQeXjAKBggqhkjOPQQD AwNoADBlAjEAuWZoZdsF0Dh9DvPIdWG40CjEsUozUVj78jwQyK5HeHbKZiQXhj5Q Vm6lLZmIuL0kAjAD6qfnqDzqnWLGX1TamPR3vU+PGJyRXEdrQE0QHbPhicoLIsga xcX+i93B3294n5E= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF9jCCA96gAwIBAgIQZWNxhdNvRcaPfzH5CYeSgjANBgkqhkiG9w0BAQwFADCB lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl YyBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzYwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAz IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggIi MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC3DrL6TbyachX7d1vb/UMPywv3 YC6zK34Mu1PyzE5l8xm7/zUd99Opu0Attd141Kb5N+qFBXttt+YTSwZ8+3ZjjyAd LTgrBIXy6LDRX01KIclq2JTqHgJQpqqQB6BHIepm+QSg5oPwxPVeluInTWHDs8GM IrZmoQDRVin77cF/JMo9+lqUsITDx7pDHP1kDvEo+0dZ8ibhMblE+avd+76+LDfj rAsY0/wBovGkCjWCR0yrvYpe3xOF/CDMSFmvr0FvyyPNypOn3dVfyGQ7/wEDoApP LW49hL6vyDKyUymQFfewBZoKPPa5BpDJpeFdoDuw/qi2v/WJKFckOiGGceTciotB VeweMCRZ0cBZuHivqlp03iWAMJjtMERvIXAc2xJTDtamKGaTLB/MTzwbgcW59nhv 0DI6CHLbaw5GF4WU87zvvPekXo7p6bVk5bdLRRIsTDe3YEMKTXEGAJQmNXQfu3o5 XE475rgD4seTi4QsJUlF3X8jlGAfy+nN9quX92Hn+39igcjcCjBcGHzmzu/Hbh6H fLPpysh7avRo/IOlDFa0urKNSgrHl5fFiDAVPRAIVBVycmczM/R8t84AJ1NlziTx WmTnNi/yLgLCl99y6AIeoPc9tftoYAP6M6nmEm0G4amoXU48/tnnAGWsthlNe4N/ NEfq4RhtsYsceavnnQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUOXEIAD7eyIbnkP/k/SEPziQZFvYwDQYJKoZIhvcN AQEMBQADggIBAFBriE1gSM5a4yLOZ3yEp80c/ekMA4w2rwqHDmquV64B0Da78v25 c8FftaiuTKL6ScsHRhY2vePIVzh+OOS/JTNgxtw3nGO7XpgeGrKC8K6mdxGAREeh KcXwszrOmPC47NMOgAZ3IzBM/3lkYyJbd5NDS3Wz2ztuO0rd8ciutTeKlYg6EGhw OLlbcH7VQ8n8X0/l5ns27vAg7UdXEyYQXhQGDXt2B8LGLRb0rqdsD7yID08sAraj 1yLmmUc12I2lT4ESOhF9s8wLdfMecKMbA+r6mujmLjY5zJnOOj8Mt674Q5mwk25v qtkPajGRu5zTtCj7g0x6c4JQZ9IOrO1gxbJdNZjPh34eWR0kvFa62qRa2MzmvB4Q jxuMjvPB27e+1LBbZY8WaPNWxSoZFk0PuGWHbSSDuGLc4EdhGoh7zk5//dzGDVqa pPO1TPbdMaboHREhMzAEYX0c4D5PjT+1ixIAWn2poQDUg+twuxj4pNIcgS23CBHI Jnu21OUPA0Zy1CVAHr5JXW2T8VyyO3VUaTqg7kwiuqya4gitRWMFSlI1dsQ09V4H Mq3cfCbRW4+t5OaqG3Wf61206MCpFXxOSgdy30bJ1JGSdVaw4e43NmUoxRXIK3bM bW8Zg/T92hXiQeczeUaDV/nxpbZt07zXU+fucW14qZen7iCcGRVyFT0E -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDcTCCAlmgAwIBAgIVAOYJ/nrqAGiM4CS07SAbH+9StETRMA0GCSqGSIb3DQEB BQUAMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGlj emVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIgUk9PVCBDQTAeFw0xMTEyMDYx MTEwNTdaFw0zMTEyMDYxMTEwNTdaMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIg Uk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxHL49ZMTml 6g3wpYwrvQKkvc0Kc6oJ5sxfgmp1qZfluwbv88BdocHSiXlY8NzrVYzuWBp7J/9K ULMAoWoTIzOQ6C9TNm4YbA9A1jdX1wYNL5Akylf8W5L/I4BXhT9KnlI6x+a7BVAm nr/Ttl+utT/Asms2fRfEsF2vZPMxH4UFqOAhFjxTkmJWf2Cu4nvRQJHcttB+cEAo ag/hERt/+tzo4URz6x6r19toYmxx4FjjBkUhWQw1X21re//Hof2+0YgiwYT84zLb eqDqCOMOXxvH480yGDkh/QoazWX3U75HQExT/iJlwnu7I1V6HXztKIwCBjsxffbH 3jOshCJtywcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFFOSo33/gnbwM9TrkmdHYTMbaDsqMA0GCSqGSIb3DQEBBQUA A4IBAQA5UFWd5EL/pBviIMm1zD2JLUCpp0mJG7JkwznIOzawhGmFFaxGoxAhQBEg haP+E0KR66oAwVC6xe32QUVSHfWqWndzbODzLB8yj7WAR0cDM45ZngSBPBuFE3Wu GLJX9g100ETfIX+4YBR/4NR/uvTnpnd9ete7Whl0ZfY94yuu4xQqB5QFv+P7IXXV lTOjkjuGXEcyQAjQzbFaT9vIABSbeCXWBbjvOXukJy6WgAiclzGNSYprre8Ryydd fmjW9HIGwsIO03EldivvqEYL1Hv1w/Pur+6FUEOaL68PEIUovfgwIB2BAw+vZDuw cH0mX548PojGyg434cDjkSXa3mHF -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi 1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP BSeOE6Fuwg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN 8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ 1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT 91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p TpPDpFQUWw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ /jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs 81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG 9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA 2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu MdRAGmI0Nj81Aa6sY6A= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta 3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk 6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 /qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 jVaMaA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIGHDCCBASgAwIBAgIES45gAzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJE SzESMBAGA1UEChMJVFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQ cmltYXJ5IENBMB4XDTEwMDMwMzEyNDEzNFoXDTM3MTIwMzEzMTEzNFowRTELMAkG A1UEBhMCREsxEjAQBgNVBAoTCVRSVVNUMjQwODEiMCAGA1UEAxMZVFJVU1QyNDA4 IE9DRVMgUHJpbWFyeSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB AJlJodr3U1Fa+v8HnyACHV81/wLevLS0KUk58VIABl6Wfs3LLNoj5soVAZv4LBi5 gs7E8CZ9w0F2CopW8vzM8i5HLKE4eedPdnaFqHiBZ0q5aaaQArW+qKJx1rT/AaXt alMB63/yvJcYlXS2lpexk5H/zDBUXeEQyvfmK+slAySWT6wKxIPDwVapauFY9QaG +VBhCa5jBstWS7A5gQfEvYqn6csZ3jW472kW6OFNz6ftBcTwufomGJBMkonf4ZLr 6t0AdRi9jflBPz3MNNRGxyjIuAmFqGocYFA/OODBRjvSHB2DygqQ8k+9tlpvzMRr kU7jq3RKL+83G1dJ3/LTjCLz4ryEMIC/OJ/gNZfE0qXddpPtzflIPtUFVffXdbFV 1t6XZFhJ+wBHQCpJobq/BjqLWUA86upsDbfwnePtmIPRCemeXkY0qabC+2Qmd2Fe xyZphwTyMnbqy6FG1tB65dYf3mOqStmLa3RcHn9+2dwNfUkh0tjO2FXD7drWcU0O I9DW8oAypiPhm/QCjMU6j6t+0pzqJ/S0tdAo+BeiXK5hwk6aR+sRb608QfBbRAs3 U/q8jSPByenggac2BtTN6cl+AA1Mfcgl8iXWNFVGegzd/VS9vINClJCe3FNVoUnR YCKkj+x0fqxvBLopOkJkmuZw/yhgMxljUi2qYYGn90OzAgMBAAGjggESMIIBDjAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHSAECjAIMAYGBFUd IAAwgZcGA1UdHwSBjzCBjDAsoCqgKIYmaHR0cDovL2NybC5vY2VzLnRydXN0MjQw OC5jb20vb2Nlcy5jcmwwXKBaoFikVjBUMQswCQYDVQQGEwJESzESMBAGA1UEChMJ VFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQcmltYXJ5IENBMQ0w CwYDVQQDEwRDUkwxMB8GA1UdIwQYMBaAFPZt+LFIs0FDAduGROUYBbdezAY3MB0G A1UdDgQWBBT2bfixSLNBQwHbhkTlGAW3XswGNzANBgkqhkiG9w0BAQsFAAOCAgEA VPAQGrT7dIjD3/sIbQW86f9CBPu0c7JKN6oUoRUtKqgJ2KCdcB5ANhCoyznHpu3m /dUfVUI5hc31CaPgZyY37hch1q4/c9INcELGZVE/FWfehkH+acpdNr7j8UoRZlkN 15b/0UUBfGeiiJG/ugo4llfoPrp8bUmXEGggK3wyqIPcJatPtHwlb6ympfC2b/Ld v/0IdIOzIOm+A89Q0utx+1cOBq72OHy8gpGb6MfncVFMoL2fjP652Ypgtr8qN9Ka /XOazktiIf+2Pzp7hLi92hRc9QMYexrV/nnFSQoWdU8TqULFUoZ3zTEC3F/g2yj+ FhbrgXHGo5/A4O74X+lpbY2XV47aSuw+DzcPt/EhMj2of7SA55WSgbjPMbmNX0rb oenSIte2HRFW5Tr2W+qqkc/StixgkKdyzGLoFx/xeTWdJkZKwyjqge2wJqws2upY EiThhC497+/mTiSuXd69eVUwKyqYp9SD2rTtNmF6TCghRM/dNsJOl+osxDVGcwvt WIVFF/Onlu5fu1NHXdqNEfzldKDUvCfii3L2iATTZyHwU9CALE+2eIA+PIaLgnM1 1oCfUnYBkQurTrihvzz9PryCVkLxiqRmBVvUz+D4N5G/wvvKDS6t6cPCS+hqM482 cbBsn0R9fFLO4El62S9eH1tqOzO20OAOK65yJIsOpSE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA 0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN ZetX2fNXlrtIzYE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF 10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz 0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc 46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm 4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL 1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh 15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW 6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy KwbQBM0= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx 3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2 ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0 aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/ BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM 7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs yZyQ2uypQjyttgI= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOc UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xS S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg SGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4XDTA3MTIyNTE4Mzcx OVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxla3Ry b25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMC VFIxDzANBgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDE sGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7F ni4gKGMpIEFyYWzEsWsgMjAwNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9NYvDdE3ePYakqtdTyuTFY KTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQvKUmi8wUG +7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveG HtyaKhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6P IzdezKKqdfcYbwnTrqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M 733WB2+Y8a+xwXrXgTW4qhe04MsCAwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHk Yb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G CSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/sPx+EnWVUXKgW AkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5 mxRZNTZPz/OOXl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsa XRik7r4EW5nVcV9VZWRi1aKbBFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZ qxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAKpoRq0Tl9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIBCDANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJDTjER MA8GA1UEChMIVW5pVHJ1c3QxGDAWBgNVBAMTD1VDQSBHbG9iYWwgUm9vdDAeFw0w ODAxMDEwMDAwMDBaFw0zNzEyMzEwMDAwMDBaMDoxCzAJBgNVBAYTAkNOMREwDwYD VQQKEwhVbmlUcnVzdDEYMBYGA1UEAxMPVUNBIEdsb2JhbCBSb290MIICIjANBgkq hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2rPlBlA/9nP3xDK/RqUlYjOHsGj+p9+I A2N9Apb964fJ7uIIu527u+RBj8cwiQ9tJMAEbBSUgU2gDXRm8/CFr/hkGd656YGT 0CiFmUdCSiw8OCdKzP/5bBnXtfPvm65bNAbXj6ITBpyKhELVs6OQaG2BkO5NhOxM cE4t3iQ5zhkAQ5N4+QiGHUPR9HK8BcBn+sBR0smFBySuOR56zUHSNqth6iur8CBV mTxtLRwuLnWW2HKX4AzKaXPudSsVCeCObbvaE/9GqOgADKwHLx25urnRoPeZnnRc GQVmMc8+KlL+b5/zub35wYH1N9ouTIElXfbZlJrTNYsgKDdfUet9Ysepk9H50DTL qScmLCiQkjtVY7cXDlRzq6987DqrcDOsIfsiJrOGrCOp139tywgg8q9A9f9ER3Hd J90TKKHqdjn5EKCgTUCkJ7JZFStsLSS3JGN490MYeg9NEePorIdCjedYcaSrbqLA l3y74xNLytu7awj5abQEctXDRrl36v+6++nwOgw19o8PrgaEFt2UVdTvyie3AzzF HCYq9TyopZWbhvGKiWf4xwxmse1Bv4KmAGg6IjTuHuvlb4l0T2qqaqhXZ1LUIGHB zlPL/SR/XybfoQhplqCe/klD4tPq2sTxiDEhbhzhzfN1DiBEFsx9c3Q1RSw7gdQg 7LYJjD5IskkCAwEAAaOBojCBnzALBgNVHQ8EBAMCAQYwDAYDVR0TBAUwAwEB/zBj BgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcD BAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUHAwgGCCsGAQUF BwMJMB0GA1UdDgQWBBTZw9P4gJJnzF3SOqLXcaK0xDiALTANBgkqhkiG9w0BAQUF AAOCAgEA0Ih5ygiq9ws0oE4Jwul+NUiJcIQjL1HDKy9e21NrW3UIKlS6Mg7VxnGF sZdJgPaE0PC6t3GUyHlrpsVE6EKirSUtVy/m1jEp+hmJVCl+t35HNmktbjK81HXa QnO4TuWDQHOyXd/URHOmYgvbqm4FjMh/Rk85hZCdvBtUKayl1/7lWFZXbSyZoUkh 1WHGjGHhdSTBAd0tGzbDLxLMC9Z4i3WA6UG5iLHKPKkWxk4V43I29tSgQYWvimVw TbVEEFDs7d9t5tnGwBLxSzovc+k8qe4bqi81pZufTcU0hF8mFGmzI7GJchT46U1R IgP/SobEHOh7eQrbRyWBfvw0hKxZuFhD5D1DCVR0wtD92e9uWfdyYJl2b/Unp7uD pEqB7CmB9HdL4UISVdSGKhK28FWbAS7d9qjjGcPORy/AeGEYWsdl/J1GW1fcfA67 loMQfFUYCQSu0feLKj6g5lDWMDbX54s4U+xJRODPpN/xU3uLWrb2EZBL1nXz/gLz Ka/wI3J9FO2pXd96gZ6bkiL8HvgBRUGXx2sBYb4zaPKgZYRmvOAqpGjTcezHCN6j w8k2SjTxF+KAryAhk5Qe5hXTVGLxtTgv48y5ZwSpuuXu+RBuyy5+E6+SFP7zJ3N7 OPxzbbm5iPZujAv1/P8JDrMtXnt145Ik4ubhWD5LKAN1axibRww= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAmygAwIBAgIBCTANBgkqhkiG9w0BAQUFADAzMQswCQYDVQQGEwJDTjER MA8GA1UEChMIVW5pVHJ1c3QxETAPBgNVBAMTCFVDQSBSb290MB4XDTA0MDEwMTAw MDAwMFoXDTI5MTIzMTAwMDAwMFowMzELMAkGA1UEBhMCQ04xETAPBgNVBAoTCFVu aVRydXN0MREwDwYDVQQDEwhVQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBALNdB8qGJn1r4vs4CQ7MgsJqGgCiFV/W6dQBt1YDAVmP9ThpJHbC XivF9iu/r/tB/Q9a/KvXg3BNMJjRnrJ2u5LWu+kQKGkoNkTo8SzXWHwk1n8COvCB a2FgP/Qz3m3l6ihST/ypHWN8C7rqrsRoRuTej8GnsrZYWm0dLNmMOreIy4XU9+gD Xv2yTVDo1h//rgI/i0+WITyb1yXJHT/7mLFZ5PCpO6+zzYUs4mBGzG+OoOvwNMXx QhhgrhLtRnUc5dipllq+3lrWeGeWW5N3UPJuG96WUUqm1ktDdSFmjXfsAoR2XEQQ th1hbOSjIH23jboPkXXHjd+8AmCoKai9PUMCAwEAAaOBojCBnzALBgNVHQ8EBAMC AQYwDAYDVR0TBAUwAwEB/zBjBgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIG CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcD BwYIKwYBBQUHAwgGCCsGAQUFBwMJMB0GA1UdDgQWBBTbHzXza0z/QjFkm827Wh4d SBC37jANBgkqhkiG9w0BAQUFAAOCAQEAOGy3iPGt+lg3dNHocN6cJ1nL5BXXoMNg 14iABMUwTD3UGusGXllH5rxmy+AI/Og17GJ9ysDawXiv5UZv+4mCI4/211NmVaDe JRI7cTYWVRJ2+z34VFsxugAG+H1V5ad2g6pcSpemKijfvcZsCyOVjjN/Hl5AHxNU LJzltQ7dFyiuawHTUin1Ih+QOfTcYmjwPIZH7LgFRbu3DJaUxmfLI3HQjnQi1kHr A6i26r7EARK1s11AdgYg1GS4KUYGis4fk5oQ7vuqWrTcL9Ury/bXBYSYBZELhPc9 +tb5evosFeo2gkO3t7jj83EB7UNDogVFwygFBzXjAaU4HoDU18PZ3g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B 3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT 79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs 8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG jjxDah2nGN59PRbxYvnKkKj9 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK 4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv 2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9 hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM 1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws 6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50 aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u 7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0 xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn 0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM //bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t 3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3 dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo 5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+ pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU 4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5 81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO 8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u 7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te 2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC 4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF 9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN /BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz 4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 7M2CYfE45k+XmCpajQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h 2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq 299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd 7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw ++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt 398znM/jra6O1I7mT1GvFpLgXPYHDw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID+TCCAuGgAwIBAgIQW1fXqEywr9nTb0ugMbTW4jANBgkqhkiG9w0BAQUFADB5 MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xKjAoBgNVBAMTIVZpc2EgSW5m b3JtYXRpb24gRGVsaXZlcnkgUm9vdCBDQTAeFw0wNTA2MjcxNzQyNDJaFw0yNTA2 MjkxNzQyNDJaMHkxCzAJBgNVBAYTAlVTMQ0wCwYDVQQKEwRWSVNBMS8wLQYDVQQL EyZWaXNhIEludGVybmF0aW9uYWwgU2VydmljZSBBc3NvY2lhdGlvbjEqMCgGA1UE AxMhVmlzYSBJbmZvcm1hdGlvbiBEZWxpdmVyeSBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyREA4R/QkkfpLx0cYjga/EhIPZpchH0MZsRZ FfP6C2ITtf/Wc+MtgD4yTK0yoiXvni3d+aCtEgK3GDvkdgYrgF76ROJFZwUQjQ9l x42gRT05DbXvWFoy7dTglCZ9z/Tt2Cnktv9oxKgmkeHY/CyfpCBg1S8xth2JlGMR 0ug/GMO5zANuegZOv438p5Lt5So+du2Gl+RMFQqEPwqN5uJSqAe0VtmB4gWdQ8on Bj2ZAM2R73QW7UW0Igt2vA4JaSiNtaAG/Y/58VXWHGgbq7rDtNK1R30X0kJV0rGA ib3RSwB3LpG7bOjbIucV5mQgJoVjoA1e05w6g1x/KmNTmOGRVwIDAQABo30wezAP BgNVHRMBAf8EBTADAQH/MDkGA1UdIAQyMDAwLgYFZ4EDAgEwJTAVBggrBgEFBQcC ARYJMS4yLjMuNC41MAwGCCsGAQUFBwICMAAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud DgQWBBRPitp2/2d3I5qmgH1924h1hfeBejANBgkqhkiG9w0BAQUFAAOCAQEACUW1 QdUHdDJydgDPmYt+telnG/Su+DPaf1cregzlN43bJaJosMP7NwjoJY/H2He4XLWb 5rXEkl+xH1UyUwF7mtaUoxbGxEvt8hPZSTB4da2mzXgwKvXuHyzF5Qjy1hOB0/pS WaF9ARpVKJJ7TOJQdGKBsF2Ty4fSCLqZLgfxbqwMsd9sysXI3rDXjIhekqvbgeLz PqZr+pfgFhwCCLSMQWl5Ll3u7Qk9wR094DZ6jj6+JCVCRUS3HyabH4OlM0Vc2K+j INsF/64Or7GNtRf9HYEJvrPxHINxl3JVwhYj4ASeaO4KwhVbwtw94Tc/XrGcexDo c5lC3rAi4/UZqweYCw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEGjCCAwKgAwIBAgIDAYagMA0GCSqGSIb3DQEBBQUAMIGjMQswCQYDVQQGEwJG STEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0ZXJpa2Vz a3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBTZXJ2aWNl czEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJLIEdvdi4g Um9vdCBDQTAeFw0wMjEyMTgxMzUzMDBaFw0yMzEyMTgxMzUxMDhaMIGjMQswCQYD VQQGEwJGSTEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0 ZXJpa2Vza3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBT ZXJ2aWNlczEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJL IEdvdi4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCF FdrIAzfQo0Y3bBseljDCWoUSZyPyu5/nioFgJ/gTqTy894aqqvTzJSm0/nWuHoGG igWyHWWyOOi0zCia+xc28ZPVec7Bg4shT8MNrUHfeJ1I4x9CRPw8bSEga60ihCRC jxdNwlAfZM0tOSJWiP2yY51U2kJpwMhP1xjiPshphJQ9LIDGfM6911Mf64i5psu7 hVfvV3ZdDIvTXhJBnyHAOfQmbQj6OLOhd7HuFtjQaNq0mKWgZUZKa41+qk1guPjI DfxxPu45h4G02fhukO4/DmHXHSto5i7hQkQmeCxY8n0Wf2HASSQqiYe2XS8pGfim 545SnkFLWg6quMJmQlMCAwEAAaNVMFMwDwYDVR0TAQH/BAUwAwEB/zARBglghkgB hvhCAQEEBAMCAAcwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBTb6eGb0tEkC/yr 46Bn6q6cS3f0sDANBgkqhkiG9w0BAQUFAAOCAQEArX1ID1QRnljurw2bEi8hpM2b uoRH5sklVSPj3xhYKizbXvfNVPVRJHtiZ+GxH0mvNNDrsczZog1Sf0JLiGCXzyVy t08pLWKfT6HAVVdWDsRol5EfnGTCKTIB6dTI2riBmCguGMcs/OubUpbf9MiQGS0j 8/G7cdqehSO9Gu8u5Hp5t8OdhkktY7ktdM9lDzJmid87Ie4pbzlj2RXBbvbfgD5Q eBmK3QOjFKU3p7UsfLYRh+cF8ry23tT/l4EohP7+bEaFEEGfTXWMB9SZZ291im/k UJL2mdUQuMSpe/cXjUu/15WfCdxEDx4yw8DP03kN5Mc7h/CQNIghYkmSBAQfvA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ O+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- ` ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_js.go ================================================ // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build js && wasm // +build js,wasm package x509 // Possible certificate files; stop after finding one. var certFiles = []string{} func loadSystemRoots() (*CertPool, error) { return NewCertPool(), nil } func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { return nil, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_linux.go ================================================ // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 // Possible certificate files; stop after finding one. var certFiles = []string{ "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6 "/etc/ssl/ca-bundle.pem", // OpenSUSE "/etc/pki/tls/cacert.pem", // OpenELEC "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7 "/etc/ssl/cert.pem", // Alpine Linux } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_nocgo_darwin.go ================================================ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !cgo // +build !cgo package x509 func loadSystemRoots() (*CertPool, error) { return execSecurityRoots() } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_plan9.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build plan9 // +build plan9 package x509 import ( "os" ) // Possible certificate files; stop after finding one. var certFiles = []string{ "/sys/lib/tls/ca.pem", } func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { return nil, nil } func loadSystemRoots() (*CertPool, error) { roots := NewCertPool() var bestErr error for _, file := range certFiles { data, err := os.ReadFile(file) if err == nil { roots.AppendCertsFromPEM(data) return roots, nil } if bestErr == nil || (os.IsNotExist(bestErr) && !os.IsNotExist(err)) { bestErr = err } } if bestErr == nil { return roots, nil } return nil, bestErr } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_solaris.go ================================================ // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 // Possible certificate files; stop after finding one. var certFiles = []string{ "/etc/certs/ca-certificates.crt", // Solaris 11.2+ "/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS "/etc/ssl/cacert.pem", // OmniOS } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_unix.go ================================================ // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build aix || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos // +build aix dragonfly freebsd linux netbsd openbsd solaris zos package x509 import ( "os" ) // Possible directories with certificate files; stop after successfully // reading at least one file from a directory. var certDirectories = []string{ "/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139 "/system/etc/security/cacerts", // Android "/usr/local/share/certs", // FreeBSD "/etc/pki/tls/certs", // Fedora/RHEL "/etc/openssl/certs", // NetBSD "/var/ssl/certs", // AIX } const ( // certFileEnv is the environment variable which identifies where to locate // the SSL certificate file. If set this overrides the system default. certFileEnv = "SSL_CERT_FILE" // certDirEnv is the environment variable which identifies which directory // to check for SSL certificate files. If set this overrides the system default. certDirEnv = "SSL_CERT_DIR" ) func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { return nil, nil } func loadSystemRoots() (*CertPool, error) { roots := NewCertPool() files := certFiles if f := os.Getenv(certFileEnv); f != "" { files = []string{f} } var firstErr error for _, file := range files { data, err := os.ReadFile(file) if err == nil { roots.AppendCertsFromPEM(data) break } if firstErr == nil && !os.IsNotExist(err) { firstErr = err } } dirs := certDirectories if d := os.Getenv(certDirEnv); d != "" { dirs = []string{d} } for _, directory := range dirs { fis, err := os.ReadDir(directory) if err != nil { if firstErr == nil && !os.IsNotExist(err) { firstErr = err } continue } rootsAdded := false for _, fi := range fis { data, err := os.ReadFile(directory + "/" + fi.Name()) if err == nil && roots.AppendCertsFromPEM(data) { rootsAdded = true } } if rootsAdded { return roots, nil } } if len(roots.certs) > 0 || firstErr == nil { return roots, nil } return nil, firstErr } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_wasip1.go ================================================ // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build wasip1 // +build wasip1 package x509 // Possible certificate files; stop after finding one. var certFiles = []string{} func loadSystemRoots() (*CertPool, error) { return NewCertPool(), nil } func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { return nil, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_windows.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import ( "errors" "syscall" "unsafe" ) // Creates a new *syscall.CertContext representing the leaf certificate in an in-memory // certificate store containing itself and all of the intermediate certificates specified // in the opts.Intermediates CertPool. // // A pointer to the in-memory store is available in the returned CertContext's Store field. // The store is automatically freed when the CertContext is freed using // syscall.CertFreeCertificateContext. func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertContext, error) { var storeCtx *syscall.CertContext leafCtx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &leaf.Raw[0], uint32(len(leaf.Raw))) if err != nil { return nil, err } defer syscall.CertFreeCertificateContext(leafCtx) handle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0) if err != nil { return nil, err } defer syscall.CertCloseStore(handle, 0) err = syscall.CertAddCertificateContextToStore(handle, leafCtx, syscall.CERT_STORE_ADD_ALWAYS, &storeCtx) if err != nil { return nil, err } if opts.Intermediates != nil { for _, intermediate := range opts.Intermediates.certs { ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw))) if err != nil { return nil, err } err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil) syscall.CertFreeCertificateContext(ctx) if err != nil { return nil, err } } } return storeCtx, nil } // extractSimpleChain extracts the final certificate chain from a CertSimpleChain. func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error) { if simpleChain == nil || count == 0 { return nil, errors.New("x509: invalid simple chain") } simpleChains := (*[1 << 20]*syscall.CertSimpleChain)(unsafe.Pointer(simpleChain))[:count:count] lastChain := simpleChains[count-1] elements := (*[1 << 20]*syscall.CertChainElement)(unsafe.Pointer(lastChain.Elements))[:lastChain.NumElements:lastChain.NumElements] for i := 0; i < int(lastChain.NumElements); i++ { // Copy the buf, since ParseCertificate does not create its own copy. cert := elements[i].CertContext encodedCert := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:cert.Length:cert.Length] buf := make([]byte, cert.Length) copy(buf, encodedCert) parsedCert, err := ParseCertificate(buf) if err != nil { return nil, err } chain = append(chain, parsedCert) } return chain, nil } // checkChainTrustStatus checks the trust status of the certificate chain, translating // any errors it finds into Go errors in the process. func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error { if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR { status := chainCtx.TrustStatus.ErrorStatus switch status { case syscall.CERT_TRUST_IS_NOT_TIME_VALID: return CertificateInvalidError{c, Expired, ""} default: return UnknownAuthorityError{c, nil, nil} } } return nil } // checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for // use as a certificate chain for a SSL/TLS server. func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error { servernamep, err := syscall.UTF16PtrFromString(opts.DNSName) if err != nil { return err } sslPara := &syscall.SSLExtraCertChainPolicyPara{ AuthType: syscall.AUTHTYPE_SERVER, ServerName: servernamep, } sslPara.Size = uint32(unsafe.Sizeof(*sslPara)) para := &syscall.CertChainPolicyPara{ ExtraPolicyPara: convertToPolicyParaType(unsafe.Pointer(sslPara)), } para.Size = uint32(unsafe.Sizeof(*para)) status := syscall.CertChainPolicyStatus{} err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status) if err != nil { return err } // TODO(mkrautz): use the lChainIndex and lElementIndex fields // of the CertChainPolicyStatus to provide proper context, instead // using c. if status.Error != 0 { switch status.Error { case syscall.CERT_E_EXPIRED: return CertificateInvalidError{c, Expired, ""} case syscall.CERT_E_CN_NO_MATCH: return HostnameError{c, opts.DNSName} case syscall.CERT_E_UNTRUSTEDROOT: return UnknownAuthorityError{c, nil, nil} default: return UnknownAuthorityError{c, nil, nil} } } return nil } // systemVerify is like Verify, except that it uses CryptoAPI calls // to build certificate chains and verify them. func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { hasDNSName := opts != nil && len(opts.DNSName) > 0 storeCtx, err := createStoreContext(c, opts) if err != nil { return nil, err } defer syscall.CertFreeCertificateContext(storeCtx) para := new(syscall.CertChainPara) para.Size = uint32(unsafe.Sizeof(*para)) // If there's a DNSName set in opts, assume we're verifying // a certificate from a TLS server. if hasDNSName { oids := []*byte{ &syscall.OID_PKIX_KP_SERVER_AUTH[0], // Both IE and Chrome allow certificates with // Server Gated Crypto as well. Some certificates // in the wild require them. &syscall.OID_SERVER_GATED_CRYPTO[0], &syscall.OID_SGC_NETSCAPE[0], } para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR para.RequestedUsage.Usage.Length = uint32(len(oids)) para.RequestedUsage.Usage.UsageIdentifiers = &oids[0] } else { para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_AND para.RequestedUsage.Usage.Length = 0 para.RequestedUsage.Usage.UsageIdentifiers = nil } var verifyTime *syscall.Filetime if opts != nil && !opts.CurrentTime.IsZero() { ft := syscall.NsecToFiletime(opts.CurrentTime.UnixNano()) verifyTime = &ft } // CertGetCertificateChain will traverse Windows's root stores // in an attempt to build a verified certificate chain. Once // it has found a verified chain, it stops. MSDN docs on // CERT_CHAIN_CONTEXT: // // When a CERT_CHAIN_CONTEXT is built, the first simple chain // begins with an end certificate and ends with a self-signed // certificate. If that self-signed certificate is not a root // or otherwise trusted certificate, an attempt is made to // build a new chain. CTLs are used to create the new chain // beginning with the self-signed certificate from the original // chain as the end certificate of the new chain. This process // continues building additional simple chains until the first // self-signed certificate is a trusted certificate or until // an additional simple chain cannot be built. // // The result is that we'll only get a single trusted chain to // return to our caller. var chainCtx *syscall.CertChainContext err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, 0, 0, &chainCtx) if err != nil { return nil, err } defer syscall.CertFreeCertificateChain(chainCtx) err = checkChainTrustStatus(c, chainCtx) if err != nil { return nil, err } if hasDNSName { err = checkChainSSLServerPolicy(c, chainCtx, opts) if err != nil { return nil, err } } chain, err := extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount)) if err != nil { return nil, err } if len(chain) < 1 { return nil, errors.New("x509: internal error: system verifier returned an empty chain") } // Mitigate CVE-2020-0601, where the Windows system verifier might be // tricked into using custom curve parameters for a trusted root, by // double-checking all ECDSA signatures. If the system was tricked into // using spoofed parameters, the signature will be invalid for the correct // ones we parsed. (We don't support custom curves ourselves.) for i, parent := range chain[1:] { if parent.PublicKeyAlgorithm != ECDSA { continue } if err := parent.CheckSignature(chain[i].SignatureAlgorithm, chain[i].RawTBSCertificate, chain[i].Signature); err != nil { return nil, err } } return [][]*Certificate{chain}, nil } func loadSystemRoots() (*CertPool, error) { // TODO: restore this functionality on Windows. We tried to do // it in Go 1.8 but had to revert it. See Issue 18609. // Returning (nil, nil) was the old behavior, prior to CL 30578. // The if statement here avoids vet complaining about // unreachable code below. if true { return nil, nil } const CRYPT_E_NOT_FOUND = 0x80092004 store, err := syscall.CertOpenSystemStore(0, syscall.StringToUTF16Ptr("ROOT")) if err != nil { return nil, err } defer syscall.CertCloseStore(store, 0) roots := NewCertPool() var cert *syscall.CertContext for { cert, err = syscall.CertEnumCertificatesInStore(store, cert) if err != nil { if errno, ok := err.(syscall.Errno); ok { if errno == CRYPT_E_NOT_FOUND { break } } return nil, err } if cert == nil { break } // Copy the buf, since ParseCertificate does not create its own copy. buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:cert.Length:cert.Length] buf2 := make([]byte, cert.Length) copy(buf2, buf) if c, err := ParseCertificate(buf2); err == nil { roots.AddCert(c) } } return roots, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/root_zos.go ================================================ // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build zos // +build zos package x509 // Possible certificate files; stop after finding one. var certFiles = []string{ "/etc/cacert.pem", // IBM zOS default } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/rpki.go ================================================ // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import ( "bytes" "encoding/binary" "errors" "fmt" "github.com/google/certificate-transparency-go/asn1" ) // IPAddressPrefix describes an IP address prefix as an ASN.1 bit string, // where the BitLength field holds the prefix length. type IPAddressPrefix asn1.BitString // IPAddressRange describes an (inclusive) IP address range. type IPAddressRange struct { Min IPAddressPrefix Max IPAddressPrefix } // Most relevant values for AFI from: // http://www.iana.org/assignments/address-family-numbers. const ( IPv4AddressFamilyIndicator = uint16(1) IPv6AddressFamilyIndicator = uint16(2) ) // IPAddressFamilyBlocks describes a set of ranges of IP addresses. type IPAddressFamilyBlocks struct { // AFI holds an address family indicator from // http://www.iana.org/assignments/address-family-numbers. AFI uint16 // SAFI holds a subsequent address family indicator from // http://www.iana.org/assignments/safi-namespace. SAFI byte // InheritFromIssuer indicates that the set of addresses should // be taken from the issuer's certificate. InheritFromIssuer bool // AddressPrefixes holds prefixes if InheritFromIssuer is false. AddressPrefixes []IPAddressPrefix // AddressRanges holds ranges if InheritFromIssuer is false. AddressRanges []IPAddressRange } // Internal types for asn1 unmarshalling. type ipAddressFamily struct { AddressFamily []byte // 2-byte AFI plus optional 1 byte SAFI Choice asn1.RawValue } // Internally, use raw asn1.BitString rather than the IPAddressPrefix // type alias (so that asn1.Unmarshal() decodes properly). type ipAddressRange struct { Min asn1.BitString Max asn1.BitString } func parseRPKIAddrBlocks(data []byte, nfe *NonFatalErrors) []*IPAddressFamilyBlocks { // RFC 3779 2.2.3 // IPAddrBlocks ::= SEQUENCE OF IPAddressFamily // // IPAddressFamily ::= SEQUENCE { -- AFI & optional SAFI -- // addressFamily OCTET STRING (SIZE (2..3)), // ipAddressChoice IPAddressChoice } // // IPAddressChoice ::= CHOICE { // inherit NULL, -- inherit from issuer -- // addressesOrRanges SEQUENCE OF IPAddressOrRange } // // IPAddressOrRange ::= CHOICE { // addressPrefix IPAddress, // addressRange IPAddressRange } // // IPAddressRange ::= SEQUENCE { // min IPAddress, // max IPAddress } // // IPAddress ::= BIT STRING var addrBlocks []ipAddressFamily if rest, err := asn1.Unmarshal(data, &addrBlocks); err != nil { nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ipAddrBlocks extension: %v", err)) return nil } else if len(rest) != 0 { nfe.AddError(errors.New("trailing data after ipAddrBlocks extension")) return nil } var results []*IPAddressFamilyBlocks for i, block := range addrBlocks { var fam IPAddressFamilyBlocks if l := len(block.AddressFamily); l < 2 || l > 3 { nfe.AddError(fmt.Errorf("invalid address family length (%d) for ipAddrBlock.addressFamily", l)) continue } fam.AFI = binary.BigEndian.Uint16(block.AddressFamily[0:2]) if len(block.AddressFamily) > 2 { fam.SAFI = block.AddressFamily[2] } // IPAddressChoice is an ASN.1 CHOICE where the chosen alternative is indicated by (implicit) // tagging of the alternatives -- here, either NULL or SEQUENCE OF. if bytes.Equal(block.Choice.FullBytes, asn1.NullBytes) { fam.InheritFromIssuer = true results = append(results, &fam) continue } var addrRanges []asn1.RawValue if _, err := asn1.Unmarshal(block.Choice.FullBytes, &addrRanges); err != nil { nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ipAddrBlocks[%d].ipAddressChoice.addressesOrRanges: %v", i, err)) continue } for j, ar := range addrRanges { // Each IPAddressOrRange is a CHOICE where the alternatives have distinct (implicit) // tags -- here, either BIT STRING or SEQUENCE. switch ar.Tag { case asn1.TagBitString: // BIT STRING for single prefix IPAddress var val asn1.BitString if _, err := asn1.Unmarshal(ar.FullBytes, &val); err != nil { nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ipAddrBlocks[%d].ipAddressChoice.addressesOrRanges[%d].addressPrefix: %v", i, j, err)) continue } fam.AddressPrefixes = append(fam.AddressPrefixes, IPAddressPrefix(val)) case asn1.TagSequence: var val ipAddressRange if _, err := asn1.Unmarshal(ar.FullBytes, &val); err != nil { nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ipAddrBlocks[%d].ipAddressChoice.addressesOrRanges[%d].addressRange: %v", i, j, err)) continue } fam.AddressRanges = append(fam.AddressRanges, IPAddressRange{Min: IPAddressPrefix(val.Min), Max: IPAddressPrefix(val.Max)}) default: nfe.AddError(fmt.Errorf("unexpected ASN.1 type in ipAddrBlocks[%d].ipAddressChoice.addressesOrRanges[%d]: %+v", i, j, ar)) } } results = append(results, &fam) } return results } // ASIDRange describes an inclusive range of AS Identifiers (AS numbers or routing // domain identifiers). type ASIDRange struct { Min int Max int } // ASIdentifiers describes a collection of AS Identifiers (AS numbers or routing // domain identifiers). type ASIdentifiers struct { // InheritFromIssuer indicates that the set of AS identifiers should // be taken from the issuer's certificate. InheritFromIssuer bool // ASIDs holds AS identifiers if InheritFromIssuer is false. ASIDs []int // ASIDs holds AS identifier ranges (inclusive) if InheritFromIssuer is false. ASIDRanges []ASIDRange } type asIdentifiers struct { ASNum asn1.RawValue `asn1:"optional,tag:0"` RDI asn1.RawValue `asn1:"optional,tag:1"` } func parseASIDChoice(val asn1.RawValue, nfe *NonFatalErrors) *ASIdentifiers { // RFC 3779 2.3.2 // ASIdentifierChoice ::= CHOICE { // inherit NULL, -- inherit from issuer -- // asIdsOrRanges SEQUENCE OF ASIdOrRange } // ASIdOrRange ::= CHOICE { // id ASId, // range ASRange } // ASRange ::= SEQUENCE { // min ASId, // max ASId } // ASId ::= INTEGER if len(val.FullBytes) == 0 { // OPTIONAL return nil } // ASIdentifierChoice is an ASN.1 CHOICE where the chosen alternative is indicated by (implicit) // tagging of the alternatives -- here, either NULL or SEQUENCE OF. if bytes.Equal(val.Bytes, asn1.NullBytes) { return &ASIdentifiers{InheritFromIssuer: true} } var ids []asn1.RawValue if rest, err := asn1.Unmarshal(val.Bytes, &ids); err != nil { nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ASIdentifiers.asIdsOrRanges: %v", err)) return nil } else if len(rest) != 0 { nfe.AddError(errors.New("trailing data after ASIdentifiers.asIdsOrRanges")) return nil } var asID ASIdentifiers for i, id := range ids { // Each ASIdOrRange is a CHOICE where the alternatives have distinct (implicit) // tags -- here, either INTEGER or SEQUENCE. switch id.Tag { case asn1.TagInteger: var val int if _, err := asn1.Unmarshal(id.FullBytes, &val); err != nil { nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ASIdentifiers.asIdsOrRanges[%d].id: %v", i, err)) continue } asID.ASIDs = append(asID.ASIDs, val) case asn1.TagSequence: var val ASIDRange if _, err := asn1.Unmarshal(id.FullBytes, &val); err != nil { nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ASIdentifiers.asIdsOrRanges[%d].range: %v", i, err)) continue } asID.ASIDRanges = append(asID.ASIDRanges, val) default: nfe.AddError(fmt.Errorf("unexpected value in ASIdentifiers.asIdsOrRanges[%d]: %+v", i, id)) } } return &asID } func parseRPKIASIdentifiers(data []byte, nfe *NonFatalErrors) (*ASIdentifiers, *ASIdentifiers) { // RFC 3779 2.3.2 // ASIdentifiers ::= SEQUENCE { // asnum [0] EXPLICIT ASIdentifierChoice OPTIONAL, // rdi [1] EXPLICIT ASIdentifierChoice OPTIONAL} var asIDs asIdentifiers if rest, err := asn1.Unmarshal(data, &asIDs); err != nil { nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ASIdentifiers extension: %v", err)) return nil, nil } else if len(rest) != 0 { nfe.AddError(errors.New("trailing data after ASIdentifiers extension")) return nil, nil } return parseASIDChoice(asIDs.ASNum, nfe), parseASIDChoice(asIDs.RDI, nfe) } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/sec1.go ================================================ // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import ( "crypto/ecdsa" "crypto/elliptic" "errors" "fmt" "math/big" "github.com/google/certificate-transparency-go/asn1" ) const ecPrivKeyVersion = 1 // ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure. // References: // // RFC 5915 // SEC1 - http://www.secg.org/sec1-v2.pdf // // Per RFC 5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in // most cases it is not. type ecPrivateKey struct { Version int PrivateKey []byte NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"` } // ParseECPrivateKey parses an EC private key in SEC 1, ASN.1 DER form. // // This kind of key is commonly encoded in PEM blocks of type "EC PRIVATE KEY". func ParseECPrivateKey(der []byte) (*ecdsa.PrivateKey, error) { return parseECPrivateKey(nil, der) } // MarshalECPrivateKey converts an EC private key to SEC 1, ASN.1 DER form. // // This kind of key is commonly encoded in PEM blocks of type "EC PRIVATE KEY". // For a more flexible key format which is not EC specific, use // MarshalPKCS8PrivateKey. func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) { oid, ok := OIDFromNamedCurve(key.Curve) if !ok { return nil, errors.New("x509: unknown elliptic curve") } return marshalECPrivateKeyWithOID(key, oid) } // marshalECPrivateKey marshals an EC private key into ASN.1, DER format and // sets the curve ID to the given OID, or omits it if OID is nil. func marshalECPrivateKeyWithOID(key *ecdsa.PrivateKey, oid asn1.ObjectIdentifier) ([]byte, error) { privateKeyBytes := key.D.Bytes() paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8) copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes) return asn1.Marshal(ecPrivateKey{ Version: 1, PrivateKey: paddedPrivateKey, NamedCurveOID: oid, PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}, }) } // parseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure. // The OID for the named curve may be provided from another source (such as // the PKCS8 container) - if it is provided then use this instead of the OID // that may exist in the EC private key structure. func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *ecdsa.PrivateKey, err error) { var privKey ecPrivateKey if _, err := asn1.Unmarshal(der, &privKey); err != nil { if _, err := asn1.Unmarshal(der, &pkcs8{}); err == nil { return nil, errors.New("x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)") } if _, err := asn1.Unmarshal(der, &pkcs1PrivateKey{}); err == nil { return nil, errors.New("x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)") } return nil, errors.New("x509: failed to parse EC private key: " + err.Error()) } if privKey.Version != ecPrivKeyVersion { return nil, fmt.Errorf("x509: unknown EC private key version %d", privKey.Version) } var nfe NonFatalErrors var curve elliptic.Curve if namedCurveOID != nil { curve = namedCurveFromOID(*namedCurveOID, &nfe) } else { curve = namedCurveFromOID(privKey.NamedCurveOID, &nfe) } if curve == nil { return nil, errors.New("x509: unknown elliptic curve") } k := new(big.Int).SetBytes(privKey.PrivateKey) curveOrder := curve.Params().N if k.Cmp(curveOrder) >= 0 { return nil, errors.New("x509: invalid elliptic curve private key value") } priv := new(ecdsa.PrivateKey) priv.Curve = curve priv.D = k privateKey := make([]byte, (curveOrder.BitLen()+7)/8) // Some private keys have leading zero padding. This is invalid // according to [SEC1], but this code will ignore it. for len(privKey.PrivateKey) > len(privateKey) { if privKey.PrivateKey[0] != 0 { return nil, errors.New("x509: invalid private key length") } privKey.PrivateKey = privKey.PrivateKey[1:] } // Some private keys remove all leading zeros, this is also invalid // according to [SEC1] but since OpenSSL used to do this, we ignore // this too. copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey) priv.X, priv.Y = curve.ScalarBaseMult(privateKey) return priv, nil } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/test-dir.crt ================================================ -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIJAL8a/lsnspOqMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz dHMxETAPBgNVBAMMCHRlc3QtZGlyMB4XDTE3MDIwMTIzNTAyN1oXDTI3MDEzMDIz NTAyN1owTDELMAkGA1UEBhMCVUsxEzARBgNVBAgMClRlc3QtU3RhdGUxFTATBgNV BAoMDEdvbGFuZyBUZXN0czERMA8GA1UEAwwIdGVzdC1kaXIwggIiMA0GCSqGSIb3 DQEBAQUAA4ICDwAwggIKAoICAQDzBoi43Yn30KN13PKFHu8LA4UmgCRToTukLItM WK2Je45grs/axg9n3YJOXC6hmsyrkOnyBcx1xVNgSrOAll7fSjtChRIX72Xrloxu XewtWVIrijqz6oylbvEmbRT3O8uynu5rF82Pmdiy8oiSfdywjKuPnE0hjV1ZSCql MYcXqA+f0JFD8kMv4pbtxjGH8f2DkYQz+hHXLrJH4/MEYdVMQXoz/GDzLyOkrXBN hpMaBBqg1p0P+tRdfLXuliNzA9vbZylzpF1YZ0gvsr0S5Y6LVtv7QIRygRuLY4kF k+UYuFq8NrV8TykS7FVnO3tf4XcYZ7r2KV5FjYSrJtNNo85BV5c3xMD3fJ2XcOWk +oD1ATdgAM3aKmSOxNtNItKKxBe1mkqDH41NbWx7xMad78gDznyeT0tjEOltN2bM uXU1R/jgR/vq5Ec0AhXJyL/ziIcmuV2fSl/ZxT4ARD+16tgPiIx+welTf0v27/JY adlfkkL5XsPRrbSguISrj7JeaO/gjG3KnDVHcZvYBpDfHqRhCgrosfe26TZcTXx2 cRxOfvBjMz1zJAg+esuUzSkerreyRhzD7RpeZTwi6sxvx82MhYMbA3w1LtgdABio 9JRqZy3xqsIbNv7N46WO/qXL1UMRKb1UyHeW8g8btboz+B4zv1U0Nj+9qxPBbQui dgL9LQIDAQABo1AwTjAdBgNVHQ4EFgQUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwHwYD VR0jBBgwFoAUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwDAYDVR0TBAUwAwEB/zANBgkq hkiG9w0BAQsFAAOCAgEAvEVnUYsIOt87rggmLPqEueynkuQ+562M8EDHSQl82zbe xDCxeg3DvPgKb+RvaUdt1362z/szK10SoeMgx6+EQLoV9LiVqXwNqeYfixrhrdw3 ppAhYYhymdkbUQCEMHypmXP1vPhAz4o8Bs+eES1M+zO6ErBiD7SqkmBElT+GixJC 6epC9ZQFs+dw3lPlbiZSsGE85sqc3VAs0/JgpL/pb1/Eg4s0FUhZD2C2uWdSyZGc g0/v3aXJCp4j/9VoNhI1WXz3M45nysZIL5OQgXymLqJElQa1pZ3Wa4i/nidvT4AT Xlxc/qijM8set/nOqp7hVd5J0uG6qdwLRILUddZ6OpXd7ZNi1EXg+Bpc7ehzGsDt 3UFGzYXDjxYnK2frQfjLS8stOQIqSrGthW6x0fdkVx0y8BByvd5J6+JmZl4UZfzA m99VxXSt4B9x6BvnY7ktzcFDOjtuLc4B/7yg9fv1eQuStA4cHGGAttsCg1X/Kx8W PvkkeH0UWDZ9vhH9K36703z89da6MWF+bz92B0+4HoOmlVaXRkvblsNaynJnL0LC Ayry7QBxuh5cMnDdRwJB3AVJIiJ1GVpb7aGvBOnx+s2lwRv9HWtghb+cbwwktx1M JHyBf3GZNSWTpKY7cD8V+NnBv3UuioOVVo+XAU4LF/bYUjdRpxWADJizNtZrtFo= -----END CERTIFICATE----- ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/test-file.crt ================================================ -----BEGIN CERTIFICATE----- MIIFbTCCA1WgAwIBAgIJAN338vEmMtLsMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz dHMxEjAQBgNVBAMMCXRlc3QtZmlsZTAeFw0xNzAyMDEyMzUyMDhaFw0yNzAxMzAy MzUyMDhaME0xCzAJBgNVBAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYD VQQKDAxHb2xhbmcgVGVzdHMxEjAQBgNVBAMMCXRlc3QtZmlsZTCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAPMGiLjdiffQo3Xc8oUe7wsDhSaAJFOhO6Qs i0xYrYl7jmCuz9rGD2fdgk5cLqGazKuQ6fIFzHXFU2BKs4CWXt9KO0KFEhfvZeuW jG5d7C1ZUiuKOrPqjKVu8SZtFPc7y7Ke7msXzY+Z2LLyiJJ93LCMq4+cTSGNXVlI KqUxhxeoD5/QkUPyQy/ilu3GMYfx/YORhDP6Edcuskfj8wRh1UxBejP8YPMvI6St cE2GkxoEGqDWnQ/61F18te6WI3MD29tnKXOkXVhnSC+yvRLljotW2/tAhHKBG4tj iQWT5Ri4Wrw2tXxPKRLsVWc7e1/hdxhnuvYpXkWNhKsm002jzkFXlzfEwPd8nZdw 5aT6gPUBN2AAzdoqZI7E200i0orEF7WaSoMfjU1tbHvExp3vyAPOfJ5PS2MQ6W03 Zsy5dTVH+OBH++rkRzQCFcnIv/OIhya5XZ9KX9nFPgBEP7Xq2A+IjH7B6VN/S/bv 8lhp2V+SQvlew9GttKC4hKuPsl5o7+CMbcqcNUdxm9gGkN8epGEKCuix97bpNlxN fHZxHE5+8GMzPXMkCD56y5TNKR6ut7JGHMPtGl5lPCLqzG/HzYyFgxsDfDUu2B0A GKj0lGpnLfGqwhs2/s3jpY7+pcvVQxEpvVTId5byDxu1ujP4HjO/VTQ2P72rE8Ft C6J2Av0tAgMBAAGjUDBOMB0GA1UdDgQWBBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAf BgNVHSMEGDAWgBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAMBgNVHRMEBTADAQH/MA0G CSqGSIb3DQEBCwUAA4ICAQB3sCntCcQwhMgRPPyvOCMyTcQ/Iv+cpfxz2Ck14nlx AkEAH2CH0ov5GWTt07/ur3aa5x+SAKi0J3wTD1cdiw4U/6Uin6jWGKKxvoo4IaeK SbM8w/6eKx6UbmHx7PA/eRABY9tTlpdPCVgw7/o3WDr03QM+IAtatzvaCPPczake pbdLwmBZB/v8V+6jUajy6jOgdSH0PyffGnt7MWgDETmNC6p/Xigp5eh+C8Fb4NGT xgHES5PBC+sruWp4u22bJGDKTvYNdZHsnw/CaKQWNsQqwisxa3/8N5v+PCff/pxl r05pE3PdHn9JrCl4iWdVlgtiI9BoPtQyDfa/OEFaScE8KYR8LxaAgdgp3zYncWls BpwQ6Y/A2wIkhlD9eEp5Ib2hz7isXOs9UwjdriKqrBXqcIAE5M+YIk3+KAQKxAtd 4YsK3CSJ010uphr12YKqlScj4vuKFjuOtd5RyyMIxUG3lrrhAu2AzCeKCLdVgA8+ 75FrYMApUdvcjp4uzbBoED4XRQlx9kdFHVbYgmE/+yddBYJM8u4YlgAL0hW2/D8p z9JWIfxVmjJnBnXaKGBuiUyZ864A3PJndP6EMMo7TzS2CDnfCYuJjvI0KvDjFNmc rQA04+qfMSEz3nmKhbbZu4eYLzlADhfH8tT4GMtXf71WLA5AUHGf2Y4+HIHTsmHG vQ== -----END CERTIFICATE----- ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/verify.go ================================================ // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package x509 import ( "bytes" "errors" "fmt" "net" "net/url" "os" "reflect" "runtime" "strings" "time" "unicode/utf8" ) // ignoreCN disables interpreting Common Name as a hostname. See issue 24151. var ignoreCN = strings.Contains(os.Getenv("GODEBUG"), "x509ignoreCN=1") type InvalidReason int const ( // NotAuthorizedToSign results when a certificate is signed by another // which isn't marked as a CA certificate. NotAuthorizedToSign InvalidReason = iota // Expired results when a certificate has expired, based on the time // given in the VerifyOptions. Expired // CANotAuthorizedForThisName results when an intermediate or root // certificate has a name constraint which doesn't permit a DNS or // other name (including IP address) in the leaf certificate. CANotAuthorizedForThisName // TooManyIntermediates results when a path length constraint is // violated. TooManyIntermediates // IncompatibleUsage results when the certificate's key usage indicates // that it may only be used for a different purpose. IncompatibleUsage // NameMismatch results when the subject name of a parent certificate // does not match the issuer name in the child. NameMismatch // NameConstraintsWithoutSANs results when a leaf certificate doesn't // contain a Subject Alternative Name extension, but a CA certificate // contains name constraints, and the Common Name can be interpreted as // a hostname. // // You can avoid this error by setting the experimental GODEBUG environment // variable to "x509ignoreCN=1", disabling Common Name matching entirely. // This behavior might become the default in the future. NameConstraintsWithoutSANs // UnconstrainedName results when a CA certificate contains permitted // name constraints, but leaf certificate contains a name of an // unsupported or unconstrained type. UnconstrainedName // TooManyConstraints results when the number of comparison operations // needed to check a certificate exceeds the limit set by // VerifyOptions.MaxConstraintComparisions. This limit exists to // prevent pathological certificates can consuming excessive amounts of // CPU time to verify. TooManyConstraints // CANotAuthorizedForExtKeyUsage results when an intermediate or root // certificate does not permit a requested extended key usage. CANotAuthorizedForExtKeyUsage ) // CertificateInvalidError results when an odd error occurs. Users of this // library probably want to handle all these errors uniformly. type CertificateInvalidError struct { Cert *Certificate Reason InvalidReason Detail string } func (e CertificateInvalidError) Error() string { switch e.Reason { case NotAuthorizedToSign: return "x509: certificate is not authorized to sign other certificates" case Expired: return "x509: certificate has expired or is not yet valid: " + e.Detail case CANotAuthorizedForThisName: return "x509: a root or intermediate certificate is not authorized to sign for this name: " + e.Detail case CANotAuthorizedForExtKeyUsage: return "x509: a root or intermediate certificate is not authorized for an extended key usage: " + e.Detail case TooManyIntermediates: return "x509: too many intermediates for path length constraint" case IncompatibleUsage: return "x509: certificate specifies an incompatible key usage" case NameMismatch: return "x509: issuer name does not match subject from issuing certificate" case NameConstraintsWithoutSANs: return "x509: issuer has name constraints but leaf doesn't have a SAN extension" case UnconstrainedName: return "x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + e.Detail } return "x509: unknown error" } // HostnameError results when the set of authorized names doesn't match the // requested name. type HostnameError struct { Certificate *Certificate Host string } func (h HostnameError) Error() string { c := h.Certificate if !c.hasSANExtension() && !validHostname(c.Subject.CommonName) && matchHostnames(toLowerCaseASCII(c.Subject.CommonName), toLowerCaseASCII(h.Host)) { // This would have validated, if it weren't for the validHostname check on Common Name. return "x509: Common Name is not a valid hostname: " + c.Subject.CommonName } var valid string if ip := net.ParseIP(h.Host); ip != nil { // Trying to validate an IP if len(c.IPAddresses) == 0 { return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs" } for _, san := range c.IPAddresses { if len(valid) > 0 { valid += ", " } valid += san.String() } } else { if c.commonNameAsHostname() { valid = c.Subject.CommonName } else { valid = strings.Join(c.DNSNames, ", ") } } if len(valid) == 0 { return "x509: certificate is not valid for any names, but wanted to match " + h.Host } return "x509: certificate is valid for " + valid + ", not " + h.Host } // UnknownAuthorityError results when the certificate issuer is unknown type UnknownAuthorityError struct { Cert *Certificate // hintErr contains an error that may be helpful in determining why an // authority wasn't found. hintErr error // hintCert contains a possible authority certificate that was rejected // because of the error in hintErr. hintCert *Certificate } func (e UnknownAuthorityError) Error() string { s := "x509: certificate signed by unknown authority" if e.hintErr != nil { certName := e.hintCert.Subject.CommonName if len(certName) == 0 { if len(e.hintCert.Subject.Organization) > 0 { certName = e.hintCert.Subject.Organization[0] } else { certName = "serial:" + e.hintCert.SerialNumber.String() } } s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName) } return s } // SystemRootsError results when we fail to load the system root certificates. type SystemRootsError struct { Err error } func (se SystemRootsError) Error() string { msg := "x509: failed to load system roots and no roots provided" if se.Err != nil { return msg + "; " + se.Err.Error() } return msg } // errNotParsed is returned when a certificate without ASN.1 contents is // verified. Platform-specific verification needs the ASN.1 contents. var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate") // VerifyOptions contains parameters for Certificate.Verify. It's a structure // because other PKIX verification APIs have ended up needing many options. type VerifyOptions struct { DNSName string Intermediates *CertPool Roots *CertPool // if nil, the system roots are used CurrentTime time.Time // if zero, the current time is used // Options to disable various verification checks. DisableTimeChecks bool DisableCriticalExtensionChecks bool DisableNameChecks bool DisableEKUChecks bool DisablePathLenChecks bool DisableNameConstraintChecks bool // KeyUsage specifies which Extended Key Usage values are acceptable. A leaf // certificate is accepted if it contains any of the listed values. An empty // list means ExtKeyUsageServerAuth. To accept any key usage, include // ExtKeyUsageAny. // // Certificate chains are required to nest these extended key usage values. // (This matches the Windows CryptoAPI behavior, but not the spec.) KeyUsages []ExtKeyUsage // MaxConstraintComparisions is the maximum number of comparisons to // perform when checking a given certificate's name constraints. If // zero, a sensible default is used. This limit prevents pathological // certificates from consuming excessive amounts of CPU time when // validating. MaxConstraintComparisions int } const ( leafCertificate = iota intermediateCertificate rootCertificate ) // rfc2821Mailbox represents a “mailbox” (which is an email address to most // people) by breaking it into the “local” (i.e. before the '@') and “domain” // parts. type rfc2821Mailbox struct { local, domain string } // parseRFC2821Mailbox parses an email address into local and domain parts, // based on the ABNF for a “Mailbox” from RFC 2821. According to RFC 5280, // Section 4.2.1.6 that's correct for an rfc822Name from a certificate: “The // format of an rfc822Name is a "Mailbox" as defined in RFC 2821, Section 4.1.2”. func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) { if len(in) == 0 { return mailbox, false } localPartBytes := make([]byte, 0, len(in)/2) if in[0] == '"' { // Quoted-string = DQUOTE *qcontent DQUOTE // non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127 // qcontent = qtext / quoted-pair // qtext = non-whitespace-control / // %d33 / %d35-91 / %d93-126 // quoted-pair = ("\" text) / obs-qp // text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text // // (Names beginning with “obs-” are the obsolete syntax from RFC 2822, // Section 4. Since it has been 16 years, we no longer accept that.) in = in[1:] QuotedString: for { if len(in) == 0 { return mailbox, false } c := in[0] in = in[1:] switch { case c == '"': break QuotedString case c == '\\': // quoted-pair if len(in) == 0 { return mailbox, false } if in[0] == 11 || in[0] == 12 || (1 <= in[0] && in[0] <= 9) || (14 <= in[0] && in[0] <= 127) { localPartBytes = append(localPartBytes, in[0]) in = in[1:] } else { return mailbox, false } case c == 11 || c == 12 || // Space (char 32) is not allowed based on the // BNF, but RFC 3696 gives an example that // assumes that it is. Several “verified” // errata continue to argue about this point. // We choose to accept it. c == 32 || c == 33 || c == 127 || (1 <= c && c <= 8) || (14 <= c && c <= 31) || (35 <= c && c <= 91) || (93 <= c && c <= 126): // qtext localPartBytes = append(localPartBytes, c) default: return mailbox, false } } } else { // Atom ("." Atom)* NextChar: for len(in) > 0 { // atext from RFC 2822, Section 3.2.4 c := in[0] switch { case c == '\\': // Examples given in RFC 3696 suggest that // escaped characters can appear outside of a // quoted string. Several “verified” errata // continue to argue the point. We choose to // accept it. in = in[1:] if len(in) == 0 { return mailbox, false } fallthrough case ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\'' || c == '*' || c == '+' || c == '-' || c == '/' || c == '=' || c == '?' || c == '^' || c == '_' || c == '`' || c == '{' || c == '|' || c == '}' || c == '~' || c == '.': localPartBytes = append(localPartBytes, in[0]) in = in[1:] default: break NextChar } } if len(localPartBytes) == 0 { return mailbox, false } // From RFC 3696, Section 3: // “period (".") may also appear, but may not be used to start // or end the local part, nor may two or more consecutive // periods appear.” twoDots := []byte{'.', '.'} if localPartBytes[0] == '.' || localPartBytes[len(localPartBytes)-1] == '.' || bytes.Contains(localPartBytes, twoDots) { return mailbox, false } } if len(in) == 0 || in[0] != '@' { return mailbox, false } in = in[1:] // The RFC species a format for domains, but that's known to be // violated in practice so we accept that anything after an '@' is the // domain part. if _, ok := domainToReverseLabels(in); !ok { return mailbox, false } mailbox.local = string(localPartBytes) mailbox.domain = in return mailbox, true } // domainToReverseLabels converts a textual domain name like foo.example.com to // the list of labels in reverse order, e.g. ["com", "example", "foo"]. func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { for len(domain) > 0 { if i := strings.LastIndexByte(domain, '.'); i == -1 { reverseLabels = append(reverseLabels, domain) domain = "" } else { reverseLabels = append(reverseLabels, domain[i+1:]) domain = domain[:i] } } if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 { // An empty label at the end indicates an absolute value. return nil, false } for _, label := range reverseLabels { if len(label) == 0 { // Empty labels are otherwise invalid. return nil, false } for _, c := range label { if c < 33 || c > 126 { // Invalid character. return nil, false } } } return reverseLabels, true } func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) { // If the constraint contains an @, then it specifies an exact mailbox // name. if strings.Contains(constraint, "@") { constraintMailbox, ok := parseRFC2821Mailbox(constraint) if !ok { return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint) } return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil } // Otherwise the constraint is like a DNS constraint of the domain part // of the mailbox. return matchDomainConstraint(mailbox.domain, constraint) } func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { // From RFC 5280, Section 4.2.1.10: // “a uniformResourceIdentifier that does not include an authority // component with a host name specified as a fully qualified domain // name (e.g., if the URI either does not include an authority // component or includes an authority component in which the host name // is specified as an IP address), then the application MUST reject the // certificate.” host := uri.Host if len(host) == 0 { return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String()) } if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") { var err error host, _, err = net.SplitHostPort(uri.Host) if err != nil { return false, err } } if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") || net.ParseIP(host) != nil { return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) } return matchDomainConstraint(host, constraint) } func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { if len(ip) != len(constraint.IP) { return false, nil } for i := range ip { if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask { return false, nil } } return true, nil } func matchDomainConstraint(domain, constraint string) (bool, error) { // The meaning of zero length constraints is not specified, but this // code follows NSS and accepts them as matching everything. if len(constraint) == 0 { return true, nil } domainLabels, ok := domainToReverseLabels(domain) if !ok { return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain) } // RFC 5280 says that a leading period in a domain name means that at // least one label must be prepended, but only for URI and email // constraints, not DNS constraints. The code also supports that // behaviour for DNS constraints. mustHaveSubdomains := false if constraint[0] == '.' { mustHaveSubdomains = true constraint = constraint[1:] } constraintLabels, ok := domainToReverseLabels(constraint) if !ok { return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint) } if len(domainLabels) < len(constraintLabels) || (mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) { return false, nil } for i, constraintLabel := range constraintLabels { if !strings.EqualFold(constraintLabel, domainLabels[i]) { return false, nil } } return true, nil } // checkNameConstraints checks that c permits a child certificate to claim the // given name, of type nameType. The argument parsedName contains the parsed // form of name, suitable for passing to the match function. The total number // of comparisons is tracked in the given count and should not exceed the given // limit. func (c *Certificate) checkNameConstraints(count *int, maxConstraintComparisons int, nameType string, name string, parsedName interface{}, match func(parsedName, constraint interface{}) (match bool, err error), permitted, excluded interface{}) error { excludedValue := reflect.ValueOf(excluded) *count += excludedValue.Len() if *count > maxConstraintComparisons { return CertificateInvalidError{c, TooManyConstraints, ""} } for i := 0; i < excludedValue.Len(); i++ { constraint := excludedValue.Index(i).Interface() match, err := match(parsedName, constraint) if err != nil { return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} } if match { return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", nameType, name, constraint)} } } permittedValue := reflect.ValueOf(permitted) *count += permittedValue.Len() if *count > maxConstraintComparisons { return CertificateInvalidError{c, TooManyConstraints, ""} } ok := true for i := 0; i < permittedValue.Len(); i++ { constraint := permittedValue.Index(i).Interface() var err error if ok, err = match(parsedName, constraint); err != nil { return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} } if ok { break } } if !ok { return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", nameType, name)} } return nil } // isValid performs validity checks on c given that it is a candidate to append // to the chain in currentChain. func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error { if !opts.DisableCriticalExtensionChecks && len(c.UnhandledCriticalExtensions) > 0 { return UnhandledCriticalExtension{ID: c.UnhandledCriticalExtensions[0]} } if !opts.DisableNameChecks && len(currentChain) > 0 { child := currentChain[len(currentChain)-1] if !bytes.Equal(child.RawIssuer, c.RawSubject) { return CertificateInvalidError{c, NameMismatch, ""} } } if !opts.DisableTimeChecks { now := opts.CurrentTime if now.IsZero() { now = time.Now() } if now.Before(c.NotBefore) { return CertificateInvalidError{ Cert: c, Reason: Expired, Detail: fmt.Sprintf("current time %s is before %s", now.Format(time.RFC3339), c.NotBefore.Format(time.RFC3339)), } } else if now.After(c.NotAfter) { return CertificateInvalidError{ Cert: c, Reason: Expired, Detail: fmt.Sprintf("current time %s is after %s", now.Format(time.RFC3339), c.NotAfter.Format(time.RFC3339)), } } } maxConstraintComparisons := opts.MaxConstraintComparisions if maxConstraintComparisons == 0 { maxConstraintComparisons = 250000 } comparisonCount := 0 var leaf *Certificate if certType == intermediateCertificate || certType == rootCertificate { if len(currentChain) == 0 { return errors.New("x509: internal error: empty chain when appending CA cert") } leaf = currentChain[0] } checkNameConstraints := !opts.DisableNameConstraintChecks && (certType == intermediateCertificate || certType == rootCertificate) && c.hasNameConstraints() if checkNameConstraints && leaf.commonNameAsHostname() { // This is the deprecated, legacy case of depending on the commonName as // a hostname. We don't enforce name constraints against the CN, but // VerifyHostname will look for hostnames in there if there are no SANs. // In order to ensure VerifyHostname will not accept an unchecked name, // return an error here. return CertificateInvalidError{c, NameConstraintsWithoutSANs, ""} } else if checkNameConstraints && leaf.hasSANExtension() { err := forEachSAN(leaf.getSANExtension(), func(tag int, data []byte) error { switch tag { case nameTypeEmail: name := string(data) mailbox, ok := parseRFC2821Mailbox(name) if !ok { return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox) } if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox, func(parsedName, constraint interface{}) (bool, error) { return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string)) }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil { return err } case nameTypeDNS: name := string(data) if _, ok := domainToReverseLabels(name); !ok { return fmt.Errorf("x509: cannot parse dnsName %q", name) } if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name, func(parsedName, constraint interface{}) (bool, error) { return matchDomainConstraint(parsedName.(string), constraint.(string)) }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil { return err } case nameTypeURI: name := string(data) uri, err := url.Parse(name) if err != nil { return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name) } if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri, func(parsedName, constraint interface{}) (bool, error) { return matchURIConstraint(parsedName.(*url.URL), constraint.(string)) }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil { return err } case nameTypeIP: ip := net.IP(data) if l := len(ip); l != net.IPv4len && l != net.IPv6len { return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data) } if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip, func(parsedName, constraint interface{}) (bool, error) { return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet)) }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil { return err } default: // Unknown SAN types are ignored. } return nil }) if err != nil { return err } } // KeyUsage status flags are ignored. From Engineering Security, Peter // Gutmann: A European government CA marked its signing certificates as // being valid for encryption only, but no-one noticed. Another // European CA marked its signature keys as not being valid for // signatures. A different CA marked its own trusted root certificate // as being invalid for certificate signing. Another national CA // distributed a certificate to be used to encrypt data for the // country’s tax authority that was marked as only being usable for // digital signatures but not for encryption. Yet another CA reversed // the order of the bit flags in the keyUsage due to confusion over // encoding endianness, essentially setting a random keyUsage in // certificates that it issued. Another CA created a self-invalidating // certificate by adding a certificate policy statement stipulating // that the certificate had to be used strictly as specified in the // keyUsage, and a keyUsage containing a flag indicating that the RSA // encryption key could only be used for Diffie-Hellman key agreement. if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) { return CertificateInvalidError{c, NotAuthorizedToSign, ""} } if !opts.DisablePathLenChecks && c.BasicConstraintsValid && c.MaxPathLen >= 0 { numIntermediates := len(currentChain) - 1 if numIntermediates > c.MaxPathLen { return CertificateInvalidError{c, TooManyIntermediates, ""} } } return nil } // Verify attempts to verify c by building one or more chains from c to a // certificate in opts.Roots, using certificates in opts.Intermediates if // needed. If successful, it returns one or more chains where the first // element of the chain is c and the last element is from opts.Roots. // // If opts.Roots is nil and system roots are unavailable the returned error // will be of type SystemRootsError. // // Name constraints in the intermediates will be applied to all names claimed // in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim // example.com if an intermediate doesn't permit it, even if example.com is not // the name being validated. Note that DirectoryName constraints are not // supported. // // Extended Key Usage values are enforced down a chain, so an intermediate or // root that enumerates EKUs prevents a leaf from asserting an EKU not in that // list. // // WARNING: this function doesn't do any revocation checking. func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) { // Platform-specific verification needs the ASN.1 contents so // this makes the behavior consistent across platforms. if len(c.Raw) == 0 { return nil, errNotParsed } if opts.Intermediates != nil { for _, intermediate := range opts.Intermediates.certs { if len(intermediate.Raw) == 0 { return nil, errNotParsed } } } // Use Windows's own verification and chain building. if opts.Roots == nil && runtime.GOOS == "windows" { return c.systemVerify(&opts) } if opts.Roots == nil { opts.Roots = systemRootsPool() if opts.Roots == nil { return nil, SystemRootsError{systemRootsErr} } } err = c.isValid(leafCertificate, nil, &opts) if err != nil { return } if len(opts.DNSName) > 0 { err = c.VerifyHostname(opts.DNSName) if err != nil { return } } var candidateChains [][]*Certificate if opts.Roots.contains(c) { candidateChains = append(candidateChains, []*Certificate{c}) } else { if candidateChains, err = c.buildChains(nil, []*Certificate{c}, nil, &opts); err != nil { return nil, err } } keyUsages := opts.KeyUsages if len(keyUsages) == 0 { keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} } // If any key usage is acceptable then we're done. for _, usage := range keyUsages { if usage == ExtKeyUsageAny { return candidateChains, nil } } for _, candidate := range candidateChains { if opts.DisableEKUChecks || checkChainForKeyUsage(candidate, keyUsages) { chains = append(chains, candidate) } } if len(chains) == 0 { return nil, CertificateInvalidError{c, IncompatibleUsage, ""} } return chains, nil } func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate { n := make([]*Certificate, len(chain)+1) copy(n, chain) n[len(chain)] = cert return n } // maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls // that an invocation of buildChains will (tranistively) make. Most chains are // less than 15 certificates long, so this leaves space for multiple chains and // for failed checks due to different intermediates having the same Subject. const maxChainSignatureChecks = 100 func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) { var ( hintErr error hintCert *Certificate ) considerCandidate := func(certType int, candidate *Certificate) { for _, cert := range currentChain { if cert.Equal(candidate) { return } } if sigChecks == nil { sigChecks = new(int) } *sigChecks++ if *sigChecks > maxChainSignatureChecks { err = errors.New("x509: signature check attempts limit reached while verifying certificate chain") return } if err := c.CheckSignatureFrom(candidate); err != nil { if hintErr == nil { hintErr = err hintCert = candidate } return } err = candidate.isValid(certType, currentChain, opts) if err != nil { return } switch certType { case rootCertificate: chains = append(chains, appendToFreshChain(currentChain, candidate)) case intermediateCertificate: if cache == nil { cache = make(map[*Certificate][][]*Certificate) } childChains, ok := cache[candidate] if !ok { childChains, err = candidate.buildChains(cache, appendToFreshChain(currentChain, candidate), sigChecks, opts) cache[candidate] = childChains } chains = append(chains, childChains...) } } for _, rootNum := range opts.Roots.findPotentialParents(c) { considerCandidate(rootCertificate, opts.Roots.certs[rootNum]) } for _, intermediateNum := range opts.Intermediates.findPotentialParents(c) { considerCandidate(intermediateCertificate, opts.Intermediates.certs[intermediateNum]) } if len(chains) > 0 { err = nil } if len(chains) == 0 && err == nil { err = UnknownAuthorityError{c, hintErr, hintCert} } return } // validHostname reports whether host is a valid hostname that can be matched or // matched against according to RFC 6125 2.2, with some leniency to accommodate // legacy values. func validHostname(host string) bool { host = strings.TrimSuffix(host, ".") if len(host) == 0 { return false } for i, part := range strings.Split(host, ".") { if part == "" { // Empty label. return false } if i == 0 && part == "*" { // Only allow full left-most wildcards, as those are the only ones // we match, and matching literal '*' characters is probably never // the expected behavior. continue } for j, c := range part { if 'a' <= c && c <= 'z' { continue } if '0' <= c && c <= '9' { continue } if 'A' <= c && c <= 'Z' { continue } if c == '-' && j != 0 { continue } if c == '_' || c == ':' { // Not valid characters in hostnames, but commonly // found in deployments outside the WebPKI. continue } return false } } return true } // commonNameAsHostname reports whether the Common Name field should be // considered the hostname that the certificate is valid for. This is a legacy // behavior, disabled if the Subject Alt Name extension is present. // // It applies the strict validHostname check to the Common Name field, so that // certificates without SANs can still be validated against CAs with name // constraints if there is no risk the CN would be matched as a hostname. // See NameConstraintsWithoutSANs and issue 24151. func (c *Certificate) commonNameAsHostname() bool { return !ignoreCN && !c.hasSANExtension() && validHostname(c.Subject.CommonName) } func matchHostnames(pattern, host string) bool { host = strings.TrimSuffix(host, ".") pattern = strings.TrimSuffix(pattern, ".") if len(pattern) == 0 || len(host) == 0 { return false } patternParts := strings.Split(pattern, ".") hostParts := strings.Split(host, ".") if len(patternParts) != len(hostParts) { return false } for i, patternPart := range patternParts { if i == 0 && patternPart == "*" { continue } if patternPart != hostParts[i] { return false } } return true } // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use // an explicitly ASCII function to avoid any sharp corners resulting from // performing Unicode operations on DNS labels. func toLowerCaseASCII(in string) string { // If the string is already lower-case then there's nothing to do. isAlreadyLowerCase := true for _, c := range in { if c == utf8.RuneError { // If we get a UTF-8 error then there might be // upper-case ASCII bytes in the invalid sequence. isAlreadyLowerCase = false break } if 'A' <= c && c <= 'Z' { isAlreadyLowerCase = false break } } if isAlreadyLowerCase { return in } out := []byte(in) for i, c := range out { if 'A' <= c && c <= 'Z' { out[i] += 'a' - 'A' } } return string(out) } // VerifyHostname returns nil if c is a valid certificate for the named host. // Otherwise it returns an error describing the mismatch. func (c *Certificate) VerifyHostname(h string) error { // IP addresses may be written in [ ]. candidateIP := h if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' { candidateIP = h[1 : len(h)-1] } if ip := net.ParseIP(candidateIP); ip != nil { // We only match IP addresses against IP SANs. // See RFC 6125, Appendix B.2. for _, candidate := range c.IPAddresses { if ip.Equal(candidate) { return nil } } return HostnameError{c, candidateIP} } lowered := toLowerCaseASCII(h) if c.commonNameAsHostname() { if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) { return nil } } else { for _, match := range c.DNSNames { if matchHostnames(toLowerCaseASCII(match), lowered) { return nil } } } return HostnameError{c, h} } func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool { usages := make([]ExtKeyUsage, len(keyUsages)) copy(usages, keyUsages) if len(chain) == 0 { return false } usagesRemaining := len(usages) // We walk down the list and cross out any usages that aren't supported // by each certificate. If we cross out all the usages, then the chain // is unacceptable. NextCert: for i := len(chain) - 1; i >= 0; i-- { cert := chain[i] if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 { // The certificate doesn't have any extended key usage specified. continue } for _, usage := range cert.ExtKeyUsage { if usage == ExtKeyUsageAny { // The certificate is explicitly good for any usage. continue NextCert } } const invalidUsage ExtKeyUsage = -1 NextRequestedUsage: for i, requestedUsage := range usages { if requestedUsage == invalidUsage { continue } for _, usage := range cert.ExtKeyUsage { if requestedUsage == usage { continue NextRequestedUsage } else if requestedUsage == ExtKeyUsageServerAuth && (usage == ExtKeyUsageNetscapeServerGatedCrypto || usage == ExtKeyUsageMicrosoftServerGatedCrypto) { // In order to support COMODO // certificate chains, we have to // accept Netscape or Microsoft SGC // usages as equal to ServerAuth. continue NextRequestedUsage } } usages[i] = invalidUsage usagesRemaining-- if usagesRemaining == 0 { return false } } } return true } ================================================ FILE: vendor/github.com/google/certificate-transparency-go/x509/x509.go ================================================ // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package x509 parses X.509-encoded keys and certificates. // // On UNIX systems the environment variables SSL_CERT_FILE and SSL_CERT_DIR // can be used to override the system default locations for the SSL certificate // file and SSL certificate files directory, respectively. // // This is a fork of the Go library crypto/x509 package, primarily adapted for // use with Certificate Transparency. Main areas of difference are: // // - Life as a fork: // - Rename OS-specific cgo code so it doesn't clash with main Go library. // - Use local library imports (asn1, pkix) throughout. // - Add version-specific wrappers for Go version-incompatible code (in // ptr_*_windows.go). // - Laxer certificate parsing: // - Add options to disable various validation checks (times, EKUs etc). // - Use NonFatalErrors type for some errors and continue parsing; this // can be checked with IsFatal(err). // - Support for short bitlength ECDSA curves (in curves.go). // - Certificate Transparency specific function: // - Parsing and marshaling of SCTList extension. // - RemoveSCTList() function for rebuilding CT leaf entry. // - Pre-certificate processing (RemoveCTPoison(), BuildPrecertTBS(), // ParseTBSCertificate(), IsPrecertificate()). // - Revocation list processing: // - Detailed CRL parsing (in revoked.go) // - Detailed error recording mechanism (in error.go, errors.go) // - Factor out parseDistributionPoints() for reuse. // - Factor out and generalize GeneralNames parsing (in names.go) // - Fix CRL commenting. // - RPKI support: // - Support for SubjectInfoAccess extension // - Support for RFC3779 extensions (in rpki.go) // - RSAES-OAEP support: // - Support for parsing RSASES-OAEP public keys from certificates // - Ed25519 support: // - Support for parsing and marshaling Ed25519 keys // - General improvements: // - Export and use OID values throughout. // - Export OIDFromNamedCurve(). // - Export SignatureAlgorithmFromAI(). // - Add OID value to UnhandledCriticalExtension error. // - Minor typo/lint fixes. package x509 import ( "bytes" "crypto" "crypto/dsa" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" _ "crypto/sha1" _ "crypto/sha256" _ "crypto/sha512" "encoding/pem" "errors" "fmt" "io" "math/big" "net" "net/url" "strconv" "strings" "time" "unicode/utf8" "golang.org/x/crypto/cryptobyte" cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" "golang.org/x/crypto/ed25519" "github.com/google/certificate-transparency-go/asn1" "github.com/google/certificate-transparency-go/tls" "github.com/google/certificate-transparency-go/x509/pkix" ) // pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo // in RFC 3280. type pkixPublicKey struct { Algo pkix.AlgorithmIdentifier BitString asn1.BitString } // ParsePKIXPublicKey parses a public key in PKIX, ASN.1 DER form. // // It returns a *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, or // ed25519.PublicKey. More types might be supported in the future. // // This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) { var pki publicKeyInfo if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after ASN.1 of public-key") } algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm) if algo == UnknownPublicKeyAlgorithm { return nil, errors.New("x509: unknown public key algorithm") } var nfe NonFatalErrors pub, err = parsePublicKey(algo, &pki, &nfe) if err != nil { return pub, err } // Treat non-fatal errors as fatal for this entrypoint. if len(nfe.Errors) > 0 { return nil, nfe.Errors[0] } return pub, nil } func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) { switch pub := pub.(type) { case *rsa.PublicKey: publicKeyBytes, err = asn1.Marshal(pkcs1PublicKey{ N: pub.N, E: pub.E, }) if err != nil { return nil, pkix.AlgorithmIdentifier{}, err } publicKeyAlgorithm.Algorithm = OIDPublicKeyRSA // This is a NULL parameters value which is required by // RFC 3279, Section 2.3.1. publicKeyAlgorithm.Parameters = asn1.NullRawValue case *ecdsa.PublicKey: publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) oid, ok := OIDFromNamedCurve(pub.Curve) if !ok { return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve") } publicKeyAlgorithm.Algorithm = OIDPublicKeyECDSA var paramBytes []byte paramBytes, err = asn1.Marshal(oid) if err != nil { return } publicKeyAlgorithm.Parameters.FullBytes = paramBytes case ed25519.PublicKey: publicKeyBytes = pub publicKeyAlgorithm.Algorithm = OIDPublicKeyEd25519 default: return nil, pkix.AlgorithmIdentifier{}, fmt.Errorf("x509: unsupported public key type: %T", pub) } return publicKeyBytes, publicKeyAlgorithm, nil } // MarshalPKIXPublicKey converts a public key to PKIX, ASN.1 DER form. // // The following key types are currently supported: *rsa.PublicKey, *ecdsa.PublicKey // and ed25519.PublicKey. Unsupported key types result in an error. // // This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) { var publicKeyBytes []byte var publicKeyAlgorithm pkix.AlgorithmIdentifier var err error if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil { return nil, err } pkix := pkixPublicKey{ Algo: publicKeyAlgorithm, BitString: asn1.BitString{ Bytes: publicKeyBytes, BitLength: 8 * len(publicKeyBytes), }, } ret, _ := asn1.Marshal(pkix) return ret, nil } // These structures reflect the ASN.1 structure of X.509 certificates.: type certificate struct { Raw asn1.RawContent TBSCertificate tbsCertificate SignatureAlgorithm pkix.AlgorithmIdentifier SignatureValue asn1.BitString } type tbsCertificate struct { Raw asn1.RawContent Version int `asn1:"optional,explicit,default:0,tag:0"` SerialNumber *big.Int SignatureAlgorithm pkix.AlgorithmIdentifier Issuer asn1.RawValue Validity validity Subject asn1.RawValue PublicKey publicKeyInfo UniqueId asn1.BitString `asn1:"optional,tag:1"` SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"` Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"` } // RFC 4055, 4.1 // The current ASN.1 parser does not support non-integer defaults so // the 'default:' tags here do nothing. type rsaesoaepAlgorithmParameters struct { HashFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:0,default:sha1Identifier"` MaskgenFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:1,default:mgf1SHA1Identifier"` PSourceFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:2,default:pSpecifiedEmptyIdentifier"` } type dsaAlgorithmParameters struct { P, Q, G *big.Int } type dsaSignature struct { R, S *big.Int } type ecdsaSignature dsaSignature type validity struct { NotBefore, NotAfter time.Time } type publicKeyInfo struct { Raw asn1.RawContent Algorithm pkix.AlgorithmIdentifier PublicKey asn1.BitString } // RFC 5280, 4.2.1.1 type authKeyId struct { Id []byte `asn1:"optional,tag:0"` } // SignatureAlgorithm indicates the algorithm used to sign a certificate. type SignatureAlgorithm int // SignatureAlgorithm values: const ( UnknownSignatureAlgorithm SignatureAlgorithm = iota MD2WithRSA MD5WithRSA SHA1WithRSA SHA256WithRSA SHA384WithRSA SHA512WithRSA DSAWithSHA1 DSAWithSHA256 ECDSAWithSHA1 ECDSAWithSHA256 ECDSAWithSHA384 ECDSAWithSHA512 SHA256WithRSAPSS SHA384WithRSAPSS SHA512WithRSAPSS PureEd25519 ) // RFC 4055, 6. Basic object identifiers var oidpSpecified = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 9} // These are the default parameters for an RSAES-OAEP pubkey. // The current ASN.1 parser does not support non-integer defaults so // these currently do nothing. var ( sha1Identifier = pkix.AlgorithmIdentifier{ Algorithm: oidSHA1, Parameters: asn1.NullRawValue, } mgf1SHA1Identifier = pkix.AlgorithmIdentifier{ Algorithm: oidMGF1, // RFC 4055, 2.1 sha1Identifier Parameters: asn1.RawValue{ Class: asn1.ClassUniversal, Tag: asn1.TagSequence, IsCompound: false, Bytes: []byte{6, 5, 43, 14, 3, 2, 26, 5, 0}, FullBytes: []byte{16, 9, 6, 5, 43, 14, 3, 2, 26, 5, 0}}, } pSpecifiedEmptyIdentifier = pkix.AlgorithmIdentifier{ Algorithm: oidpSpecified, // RFC 4055, 4.1 nullOctetString Parameters: asn1.RawValue{ Class: asn1.ClassUniversal, Tag: asn1.TagOctetString, IsCompound: false, Bytes: []byte{}, FullBytes: []byte{4, 0}}, } ) func (algo SignatureAlgorithm) isRSAPSS() bool { switch algo { case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS: return true default: return false } } func (algo SignatureAlgorithm) String() string { for _, details := range signatureAlgorithmDetails { if details.algo == algo { return details.name } } return strconv.Itoa(int(algo)) } // PublicKeyAlgorithm indicates the algorithm used for a certificate's public key. type PublicKeyAlgorithm int // PublicKeyAlgorithm values: const ( UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota RSA DSA ECDSA Ed25519 RSAESOAEP ) var publicKeyAlgoName = [...]string{ RSA: "RSA", DSA: "DSA", ECDSA: "ECDSA", Ed25519: "Ed25519", RSAESOAEP: "RSAESOAEP", } func (algo PublicKeyAlgorithm) String() string { if 0 < algo && int(algo) < len(publicKeyAlgoName) { return publicKeyAlgoName[algo] } return strconv.Itoa(int(algo)) } // OIDs for signature algorithms // // pkcs-1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } // // // RFC 3279 2.2.1 RSA Signature Algorithms // // md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 } // // md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } // // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } // // dsaWithSha1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } // // RFC 3279 2.2.3 ECDSA Signature Algorithm // // ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-x962(10045) // signatures(4) ecdsa-with-SHA1(1)} // // // RFC 4055 5 PKCS #1 Version 1.5 // // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } // // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } // // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } // // // RFC 5758 3.1 DSA Signature Algorithms // // dsaWithSha256 OBJECT IDENTIFIER ::= { // joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101) // csor(3) algorithms(4) id-dsa-with-sha2(3) 2} // // RFC 5758 3.2 ECDSA Signature Algorithm // // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } // // ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } // // ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } // // // RFC 8410 3 Curve25519 and Curve448 Algorithm Identifiers // // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } var ( oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} oidSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26} oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8} // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA // but it's specified by ISO. Microsoft's makecert.exe has been known // to produce certificates with this OID. oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} ) var signatureAlgorithmDetails = []struct { algo SignatureAlgorithm name string oid asn1.ObjectIdentifier pubKeyAlgo PublicKeyAlgorithm hash crypto.Hash }{ {MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */}, {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, RSA, crypto.MD5}, {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, RSA, crypto.SHA1}, {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1}, {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, RSA, crypto.SHA256}, {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, RSA, crypto.SHA384}, {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, RSA, crypto.SHA512}, {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA256}, {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA384}, {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA512}, {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, DSA, crypto.SHA1}, {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, DSA, crypto.SHA256}, {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1}, {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256}, {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384}, {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512}, {PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */}, } // pssParameters reflects the parameters in an AlgorithmIdentifier that // specifies RSA PSS. See RFC 3447, Appendix A.2.3. type pssParameters struct { // The following three fields are not marked as // optional because the default values specify SHA-1, // which is no longer suitable for use in signatures. Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"` MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"` SaltLength int `asn1:"explicit,tag:2"` TrailerField int `asn1:"optional,explicit,tag:3,default:1"` } // rsaPSSParameters returns an asn1.RawValue suitable for use as the Parameters // in an AlgorithmIdentifier that specifies RSA PSS. func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue { var hashOID asn1.ObjectIdentifier switch hashFunc { case crypto.SHA256: hashOID = oidSHA256 case crypto.SHA384: hashOID = oidSHA384 case crypto.SHA512: hashOID = oidSHA512 } params := pssParameters{ Hash: pkix.AlgorithmIdentifier{ Algorithm: hashOID, Parameters: asn1.NullRawValue, }, MGF: pkix.AlgorithmIdentifier{ Algorithm: oidMGF1, }, SaltLength: hashFunc.Size(), TrailerField: 1, } mgf1Params := pkix.AlgorithmIdentifier{ Algorithm: hashOID, Parameters: asn1.NullRawValue, } var err error params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params) if err != nil { panic(err) } serialized, err := asn1.Marshal(params) if err != nil { panic(err) } return asn1.RawValue{FullBytes: serialized} } // SignatureAlgorithmFromAI converts an PKIX algorithm identifier to the // equivalent local constant. func SignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm { if ai.Algorithm.Equal(oidSignatureEd25519) { // RFC 8410, Section 3 // > For all of the OIDs, the parameters MUST be absent. if len(ai.Parameters.FullBytes) != 0 { return UnknownSignatureAlgorithm } } if !ai.Algorithm.Equal(oidSignatureRSAPSS) { for _, details := range signatureAlgorithmDetails { if ai.Algorithm.Equal(details.oid) { return details.algo } } return UnknownSignatureAlgorithm } // RSA PSS is special because it encodes important parameters // in the Parameters. var params pssParameters if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil { return UnknownSignatureAlgorithm } var mgf1HashFunc pkix.AlgorithmIdentifier if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil { return UnknownSignatureAlgorithm } // PSS is greatly overburdened with options. This code forces them into // three buckets by requiring that the MGF1 hash function always match the // message hash function (as recommended in RFC 3447, Section 8.1), that the // salt length matches the hash length, and that the trailer field has the // default value. if (len(params.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes)) || !params.MGF.Algorithm.Equal(oidMGF1) || !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || (len(mgf1HashFunc.Parameters.FullBytes) != 0 && !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes)) || params.TrailerField != 1 { return UnknownSignatureAlgorithm } switch { case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32: return SHA256WithRSAPSS case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48: return SHA384WithRSAPSS case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64: return SHA512WithRSAPSS } return UnknownSignatureAlgorithm } // RFC 3279, 2.3 Public Key Algorithms // // pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) // // rsadsi(113549) pkcs(1) 1 } // // rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 } // // id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) // // x9-57(10040) x9cm(4) 1 } // // # RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters // // id-ecPublicKey OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } var ( OIDPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} OIDPublicKeyRSAESOAEP = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 7} OIDPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} OIDPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} OIDPublicKeyRSAObsolete = asn1.ObjectIdentifier{2, 5, 8, 1, 1} OIDPublicKeyEd25519 = oidSignatureEd25519 ) func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm { switch { case oid.Equal(OIDPublicKeyRSA): return RSA case oid.Equal(OIDPublicKeyDSA): return DSA case oid.Equal(OIDPublicKeyECDSA): return ECDSA case oid.Equal(OIDPublicKeyRSAESOAEP): return RSAESOAEP case oid.Equal(OIDPublicKeyEd25519): return Ed25519 } return UnknownPublicKeyAlgorithm } // RFC 5480, 2.1.1.1. Named Curve // // secp224r1 OBJECT IDENTIFIER ::= { // iso(1) identified-organization(3) certicom(132) curve(0) 33 } // // secp256r1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) // prime(1) 7 } // // secp384r1 OBJECT IDENTIFIER ::= { // iso(1) identified-organization(3) certicom(132) curve(0) 34 } // // secp521r1 OBJECT IDENTIFIER ::= { // iso(1) identified-organization(3) certicom(132) curve(0) 35 } // // secp192r1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) // prime(1) 1 } // // NB: secp256r1 is equivalent to prime256v1, // secp192r1 is equivalent to ansix9p192r and prime192v1 var ( OIDNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} OIDNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} OIDNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} OIDNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} OIDNamedCurveP192 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 1} ) func namedCurveFromOID(oid asn1.ObjectIdentifier, nfe *NonFatalErrors) elliptic.Curve { switch { case oid.Equal(OIDNamedCurveP224): return elliptic.P224() case oid.Equal(OIDNamedCurveP256): return elliptic.P256() case oid.Equal(OIDNamedCurveP384): return elliptic.P384() case oid.Equal(OIDNamedCurveP521): return elliptic.P521() case oid.Equal(OIDNamedCurveP192): nfe.AddError(errors.New("insecure curve (secp192r1) specified")) return secp192r1() } return nil } // OIDFromNamedCurve returns the OID used to specify the use of the given // elliptic curve. func OIDFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { switch curve { case elliptic.P224(): return OIDNamedCurveP224, true case elliptic.P256(): return OIDNamedCurveP256, true case elliptic.P384(): return OIDNamedCurveP384, true case elliptic.P521(): return OIDNamedCurveP521, true case secp192r1(): return OIDNamedCurveP192, true } return nil, false } // KeyUsage represents the set of actions that are valid for a given key. It's // a bitmap of the KeyUsage* constants. type KeyUsage int // KeyUsage values: const ( KeyUsageDigitalSignature KeyUsage = 1 << iota KeyUsageContentCommitment KeyUsageKeyEncipherment KeyUsageDataEncipherment KeyUsageKeyAgreement KeyUsageCertSign KeyUsageCRLSign KeyUsageEncipherOnly KeyUsageDecipherOnly ) // RFC 5280, 4.2.1.12 Extended Key Usage // // anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } // // id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } // // id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } // id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } // id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } // id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } // id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } var ( oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22} oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1} // RFC 6962 s3.1 oidExtKeyUsageCertificateTransparency = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 4} ) // ExtKeyUsage represents an extended set of actions that are valid for a given key. // Each of the ExtKeyUsage* constants define a unique action. type ExtKeyUsage int // ExtKeyUsage values: const ( ExtKeyUsageAny ExtKeyUsage = iota ExtKeyUsageServerAuth ExtKeyUsageClientAuth ExtKeyUsageCodeSigning ExtKeyUsageEmailProtection ExtKeyUsageIPSECEndSystem ExtKeyUsageIPSECTunnel ExtKeyUsageIPSECUser ExtKeyUsageTimeStamping ExtKeyUsageOCSPSigning ExtKeyUsageMicrosoftServerGatedCrypto ExtKeyUsageNetscapeServerGatedCrypto ExtKeyUsageMicrosoftCommercialCodeSigning ExtKeyUsageMicrosoftKernelCodeSigning ExtKeyUsageCertificateTransparency ) // extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID. var extKeyUsageOIDs = []struct { extKeyUsage ExtKeyUsage oid asn1.ObjectIdentifier }{ {ExtKeyUsageAny, oidExtKeyUsageAny}, {ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth}, {ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth}, {ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning}, {ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection}, {ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem}, {ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel}, {ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser}, {ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping}, {ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning}, {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto}, {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto}, {ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning}, {ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning}, {ExtKeyUsageCertificateTransparency, oidExtKeyUsageCertificateTransparency}, } func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) { for _, pair := range extKeyUsageOIDs { if oid.Equal(pair.oid) { return pair.extKeyUsage, true } } return } func oidFromExtKeyUsage(eku ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) { for _, pair := range extKeyUsageOIDs { if eku == pair.extKeyUsage { return pair.oid, true } } return } // SerializedSCT represents a single TLS-encoded signed certificate timestamp, from RFC6962 s3.3. type SerializedSCT struct { Val []byte `tls:"minlen:1,maxlen:65535"` } // SignedCertificateTimestampList is a list of signed certificate timestamps, from RFC6962 s3.3. type SignedCertificateTimestampList struct { SCTList []SerializedSCT `tls:"minlen:1,maxlen:65335"` } // A Certificate represents an X.509 certificate. type Certificate struct { Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature). RawTBSCertificate []byte // Certificate part of raw ASN.1 DER content. RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo. RawSubject []byte // DER encoded Subject RawIssuer []byte // DER encoded Issuer Signature []byte SignatureAlgorithm SignatureAlgorithm PublicKeyAlgorithm PublicKeyAlgorithm PublicKey interface{} Version int SerialNumber *big.Int Issuer pkix.Name Subject pkix.Name NotBefore, NotAfter time.Time // Validity bounds. KeyUsage KeyUsage // Extensions contains raw X.509 extensions. When parsing certificates, // this can be used to extract non-critical extensions that are not // parsed by this package. When marshaling certificates, the Extensions // field is ignored, see ExtraExtensions. Extensions []pkix.Extension // ExtraExtensions contains extensions to be copied, raw, into any // marshaled certificates. Values override any extensions that would // otherwise be produced based on the other fields. The ExtraExtensions // field is not populated when parsing certificates, see Extensions. ExtraExtensions []pkix.Extension // UnhandledCriticalExtensions contains a list of extension IDs that // were not (fully) processed when parsing. Verify will fail if this // slice is non-empty, unless verification is delegated to an OS // library which understands all the critical extensions. // // Users can access these extensions using Extensions and can remove // elements from this slice if they believe that they have been // handled. UnhandledCriticalExtensions []asn1.ObjectIdentifier ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages. UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package. // BasicConstraintsValid indicates whether IsCA, MaxPathLen, // and MaxPathLenZero are valid. BasicConstraintsValid bool IsCA bool // MaxPathLen and MaxPathLenZero indicate the presence and // value of the BasicConstraints' "pathLenConstraint". // // When parsing a certificate, a positive non-zero MaxPathLen // means that the field was specified, -1 means it was unset, // and MaxPathLenZero being true mean that the field was // explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false // should be treated equivalent to -1 (unset). // // When generating a certificate, an unset pathLenConstraint // can be requested with either MaxPathLen == -1 or using the // zero value for both MaxPathLen and MaxPathLenZero. MaxPathLen int // MaxPathLenZero indicates that BasicConstraintsValid==true // and MaxPathLen==0 should be interpreted as an actual // maximum path length of zero. Otherwise, that combination is // interpreted as MaxPathLen not being set. MaxPathLenZero bool SubjectKeyId []byte AuthorityKeyId []byte // RFC 5280, 4.2.2.1 (Authority Information Access) OCSPServer []string IssuingCertificateURL []string // Subject Information Access SubjectTimestamps []string SubjectCARepositories []string // Subject Alternate Name values. (Note that these values may not be valid // if invalid values were contained within a parsed certificate. For // example, an element of DNSNames may not be a valid DNS domain name.) DNSNames []string EmailAddresses []string IPAddresses []net.IP URIs []*url.URL // Name constraints PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical. PermittedDNSDomains []string ExcludedDNSDomains []string PermittedIPRanges []*net.IPNet ExcludedIPRanges []*net.IPNet PermittedEmailAddresses []string ExcludedEmailAddresses []string PermittedURIDomains []string ExcludedURIDomains []string // CRL Distribution Points CRLDistributionPoints []string PolicyIdentifiers []asn1.ObjectIdentifier RPKIAddressRanges []*IPAddressFamilyBlocks RPKIASNumbers, RPKIRoutingDomainIDs *ASIdentifiers // Certificate Transparency SCT extension contents; this is a TLS-encoded // SignedCertificateTimestampList (RFC 6962 s3.3). RawSCT []byte SCTList SignedCertificateTimestampList } // ErrUnsupportedAlgorithm results from attempting to perform an operation that // involves algorithms that are not currently implemented. var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented") // InsecureAlgorithmError results when the signature algorithm for a certificate // is known to be insecure. type InsecureAlgorithmError SignatureAlgorithm func (e InsecureAlgorithmError) Error() string { return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e)) } // ConstraintViolationError results when a requested usage is not permitted by // a certificate. For example: checking a signature when the public key isn't a // certificate signing key. type ConstraintViolationError struct{} func (ConstraintViolationError) Error() string { return "x509: invalid signature: parent certificate cannot sign this kind of certificate" } // Equal indicates whether two Certificate objects are equal (by comparing their // DER-encoded values). func (c *Certificate) Equal(other *Certificate) bool { if c == nil || other == nil { return c == other } return bytes.Equal(c.Raw, other.Raw) } // IsPrecertificate checks whether the certificate is a precertificate, by // checking for the presence of the CT Poison extension. func (c *Certificate) IsPrecertificate() bool { if c == nil { return false } for _, ext := range c.Extensions { if ext.Id.Equal(OIDExtensionCTPoison) { return true } } return false } func (c *Certificate) hasSANExtension() bool { return oidInExtensions(OIDExtensionSubjectAltName, c.Extensions) } // Entrust have a broken root certificate (CN=Entrust.net Certification // Authority (2048)) which isn't marked as a CA certificate and is thus invalid // according to PKIX. // We recognise this certificate by its SubjectPublicKeyInfo and exempt it // from the Basic Constraints requirement. // See http://www.entrust.net/knowledge-base/technote.cfm?tn=7869 // // TODO(agl): remove this hack once their reissued root is sufficiently // widespread. var entrustBrokenSPKI = []byte{ 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x97, 0xa3, 0x2d, 0x3c, 0x9e, 0xde, 0x05, 0xda, 0x13, 0xc2, 0x11, 0x8d, 0x9d, 0x8e, 0xe3, 0x7f, 0xc7, 0x4b, 0x7e, 0x5a, 0x9f, 0xb3, 0xff, 0x62, 0xab, 0x73, 0xc8, 0x28, 0x6b, 0xba, 0x10, 0x64, 0x82, 0x87, 0x13, 0xcd, 0x57, 0x18, 0xff, 0x28, 0xce, 0xc0, 0xe6, 0x0e, 0x06, 0x91, 0x50, 0x29, 0x83, 0xd1, 0xf2, 0xc3, 0x2a, 0xdb, 0xd8, 0xdb, 0x4e, 0x04, 0xcc, 0x00, 0xeb, 0x8b, 0xb6, 0x96, 0xdc, 0xbc, 0xaa, 0xfa, 0x52, 0x77, 0x04, 0xc1, 0xdb, 0x19, 0xe4, 0xae, 0x9c, 0xfd, 0x3c, 0x8b, 0x03, 0xef, 0x4d, 0xbc, 0x1a, 0x03, 0x65, 0xf9, 0xc1, 0xb1, 0x3f, 0x72, 0x86, 0xf2, 0x38, 0xaa, 0x19, 0xae, 0x10, 0x88, 0x78, 0x28, 0xda, 0x75, 0xc3, 0x3d, 0x02, 0x82, 0x02, 0x9c, 0xb9, 0xc1, 0x65, 0x77, 0x76, 0x24, 0x4c, 0x98, 0xf7, 0x6d, 0x31, 0x38, 0xfb, 0xdb, 0xfe, 0xdb, 0x37, 0x02, 0x76, 0xa1, 0x18, 0x97, 0xa6, 0xcc, 0xde, 0x20, 0x09, 0x49, 0x36, 0x24, 0x69, 0x42, 0xf6, 0xe4, 0x37, 0x62, 0xf1, 0x59, 0x6d, 0xa9, 0x3c, 0xed, 0x34, 0x9c, 0xa3, 0x8e, 0xdb, 0xdc, 0x3a, 0xd7, 0xf7, 0x0a, 0x6f, 0xef, 0x2e, 0xd8, 0xd5, 0x93, 0x5a, 0x7a, 0xed, 0x08, 0x49, 0x68, 0xe2, 0x41, 0xe3, 0x5a, 0x90, 0xc1, 0x86, 0x55, 0xfc, 0x51, 0x43, 0x9d, 0xe0, 0xb2, 0xc4, 0x67, 0xb4, 0xcb, 0x32, 0x31, 0x25, 0xf0, 0x54, 0x9f, 0x4b, 0xd1, 0x6f, 0xdb, 0xd4, 0xdd, 0xfc, 0xaf, 0x5e, 0x6c, 0x78, 0x90, 0x95, 0xde, 0xca, 0x3a, 0x48, 0xb9, 0x79, 0x3c, 0x9b, 0x19, 0xd6, 0x75, 0x05, 0xa0, 0xf9, 0x88, 0xd7, 0xc1, 0xe8, 0xa5, 0x09, 0xe4, 0x1a, 0x15, 0xdc, 0x87, 0x23, 0xaa, 0xb2, 0x75, 0x8c, 0x63, 0x25, 0x87, 0xd8, 0xf8, 0x3d, 0xa6, 0xc2, 0xcc, 0x66, 0xff, 0xa5, 0x66, 0x68, 0x55, 0x02, 0x03, 0x01, 0x00, 0x01, } // CheckSignatureFrom verifies that the signature on c is a valid signature // from parent. func (c *Certificate) CheckSignatureFrom(parent *Certificate) error { // RFC 5280, 4.2.1.9: // "If the basic constraints extension is not present in a version 3 // certificate, or the extension is present but the cA boolean is not // asserted, then the certified public key MUST NOT be used to verify // certificate signatures." // (except for Entrust, see comment above entrustBrokenSPKI) if (parent.Version == 3 && !parent.BasicConstraintsValid || parent.BasicConstraintsValid && !parent.IsCA) && !bytes.Equal(c.RawSubjectPublicKeyInfo, entrustBrokenSPKI) { return ConstraintViolationError{} } if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 { return ConstraintViolationError{} } if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm { return ErrUnsupportedAlgorithm } // TODO(agl): don't ignore the path length constraint. return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature) } // CheckSignature verifies that signature is a valid signature over signed from // c's public key. func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error { return checkSignature(algo, signed, signature, c.PublicKey) } func (c *Certificate) hasNameConstraints() bool { return oidInExtensions(OIDExtensionNameConstraints, c.Extensions) } func (c *Certificate) getSANExtension() []byte { for _, e := range c.Extensions { if e.Id.Equal(OIDExtensionSubjectAltName) { return e.Value } } return nil } func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm, pubKey interface{}) error { return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey) } // CheckSignature verifies that signature is a valid signature over signed from // a crypto.PublicKey. func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) { var hashType crypto.Hash var pubKeyAlgo PublicKeyAlgorithm for _, details := range signatureAlgorithmDetails { if details.algo == algo { hashType = details.hash pubKeyAlgo = details.pubKeyAlgo } } switch hashType { case crypto.Hash(0): if pubKeyAlgo != Ed25519 { return ErrUnsupportedAlgorithm } case crypto.MD5: return InsecureAlgorithmError(algo) default: if !hashType.Available() { return ErrUnsupportedAlgorithm } h := hashType.New() h.Write(signed) signed = h.Sum(nil) } switch pub := publicKey.(type) { case *rsa.PublicKey: if pubKeyAlgo != RSA { return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) } if algo.isRSAPSS() { return rsa.VerifyPSS(pub, hashType, signed, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}) } else { return rsa.VerifyPKCS1v15(pub, hashType, signed, signature) } case *dsa.PublicKey: if pubKeyAlgo != DSA { return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) } dsaSig := new(dsaSignature) if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil { return err } else if len(rest) != 0 { return errors.New("x509: trailing data after DSA signature") } if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 { return errors.New("x509: DSA signature contained zero or negative values") } // According to FIPS 186-3, section 4.6, the hash must be truncated if it is longer // than the key length, but crypto/dsa doesn't do it automatically. if maxHashLen := pub.Q.BitLen() / 8; maxHashLen < len(signed) { signed = signed[:maxHashLen] } if !dsa.Verify(pub, signed, dsaSig.R, dsaSig.S) { return errors.New("x509: DSA verification failure") } return case *ecdsa.PublicKey: if pubKeyAlgo != ECDSA { return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) } ecdsaSig := new(ecdsaSignature) if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil { return err } else if len(rest) != 0 { return errors.New("x509: trailing data after ECDSA signature") } if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { return errors.New("x509: ECDSA signature contained zero or negative values") } if !ecdsa.Verify(pub, signed, ecdsaSig.R, ecdsaSig.S) { return errors.New("x509: ECDSA verification failure") } return case ed25519.PublicKey: if pubKeyAlgo != Ed25519 { return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) } if !ed25519.Verify(pub, signed, signature) { return errors.New("x509: Ed25519 verification failure") } return } return ErrUnsupportedAlgorithm } // CheckCRLSignature checks that the signature in crl is from c. func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error { algo := SignatureAlgorithmFromAI(crl.SignatureAlgorithm) return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign()) } // UnhandledCriticalExtension results when the certificate contains an extension // that is marked as critical but which is not handled by this library. type UnhandledCriticalExtension struct { ID asn1.ObjectIdentifier } func (h UnhandledCriticalExtension) Error() string { return fmt.Sprintf("x509: unhandled critical extension (%v)", h.ID) } // removeExtension takes a DER-encoded TBSCertificate, removes the extension // specified by oid (preserving the order of other extensions), and returns the // result still as a DER-encoded TBSCertificate. This function will fail if // there is not exactly 1 extension of the type specified by the oid present. func removeExtension(tbsData []byte, oid asn1.ObjectIdentifier) ([]byte, error) { var tbs tbsCertificate rest, err := asn1.Unmarshal(tbsData, &tbs) if err != nil { return nil, fmt.Errorf("failed to parse TBSCertificate: %v", err) } else if rLen := len(rest); rLen > 0 { return nil, fmt.Errorf("trailing data (%d bytes) after TBSCertificate", rLen) } extAt := -1 for i, ext := range tbs.Extensions { if ext.Id.Equal(oid) { if extAt != -1 { return nil, errors.New("multiple extensions of specified type present") } extAt = i } } if extAt == -1 { return nil, errors.New("no extension of specified type present") } tbs.Extensions = append(tbs.Extensions[:extAt], tbs.Extensions[extAt+1:]...) // Clear out the asn1.RawContent so the re-marshal operation sees the // updated structure (rather than just copying the out-of-date DER data). tbs.Raw = nil data, err := asn1.Marshal(tbs) if err != nil { return nil, fmt.Errorf("failed to re-marshal TBSCertificate: %v", err) } return data, nil } // RemoveSCTList takes a DER-encoded TBSCertificate and removes the CT SCT // extension that contains the SCT list (preserving the order of other // extensions), and returns the result still as a DER-encoded TBSCertificate. // This function will fail if there is not exactly 1 CT SCT extension present. func RemoveSCTList(tbsData []byte) ([]byte, error) { return removeExtension(tbsData, OIDExtensionCTSCT) } // RemoveCTPoison takes a DER-encoded TBSCertificate and removes the CT poison // extension (preserving the order of other extensions), and returns the result // still as a DER-encoded TBSCertificate. This function will fail if there is // not exactly 1 CT poison extension present. func RemoveCTPoison(tbsData []byte) ([]byte, error) { return BuildPrecertTBS(tbsData, nil) } // BuildPrecertTBS builds a Certificate Transparency pre-certificate (RFC 6962 // s3.1) from the given DER-encoded TBSCertificate, returning a DER-encoded // TBSCertificate. // // This function removes the CT poison extension (there must be exactly 1 of // these), preserving the order of other extensions. // // If preIssuer is provided, this should be a special intermediate certificate // that was used to sign the precert (indicated by having the special // CertificateTransparency extended key usage). In this case, the issuance // information of the pre-cert is updated to reflect the next issuer in the // chain, i.e. the issuer of this special intermediate: // - The precert's Issuer is changed to the Issuer of the intermediate // - The precert's AuthorityKeyId is changed to the AuthorityKeyId of the // intermediate. func BuildPrecertTBS(tbsData []byte, preIssuer *Certificate) ([]byte, error) { data, err := removeExtension(tbsData, OIDExtensionCTPoison) if err != nil { return nil, err } var tbs tbsCertificate rest, err := asn1.Unmarshal(data, &tbs) if err != nil { return nil, fmt.Errorf("failed to parse TBSCertificate: %v", err) } else if rLen := len(rest); rLen > 0 { return nil, fmt.Errorf("trailing data (%d bytes) after TBSCertificate", rLen) } if preIssuer != nil { // Update the precert's Issuer field. Use the RawIssuer rather than the // parsed Issuer to avoid any chance of ASN.1 differences (e.g. switching // from UTF8String to PrintableString). tbs.Issuer.FullBytes = preIssuer.RawIssuer // Also need to update the cert's AuthorityKeyID extension // to that of the preIssuer. var issuerKeyID []byte for _, ext := range preIssuer.Extensions { if ext.Id.Equal(OIDExtensionAuthorityKeyId) { issuerKeyID = ext.Value break } } // Check the preIssuer has the CT EKU. seenCTEKU := false for _, eku := range preIssuer.ExtKeyUsage { if eku == ExtKeyUsageCertificateTransparency { seenCTEKU = true break } } if !seenCTEKU { return nil, fmt.Errorf("issuer does not have CertificateTransparency extended key usage") } keyAt := -1 for i, ext := range tbs.Extensions { if ext.Id.Equal(OIDExtensionAuthorityKeyId) { keyAt = i break } } if keyAt >= 0 { // PreCert has an auth-key-id; replace it with the value from the preIssuer if issuerKeyID != nil { tbs.Extensions[keyAt].Value = issuerKeyID } else { tbs.Extensions = append(tbs.Extensions[:keyAt], tbs.Extensions[keyAt+1:]...) } } else if issuerKeyID != nil { // PreCert did not have an auth-key-id, but the preIssuer does, so add it at the end. authKeyIDExt := pkix.Extension{ Id: OIDExtensionAuthorityKeyId, Critical: false, Value: issuerKeyID, } tbs.Extensions = append(tbs.Extensions, authKeyIDExt) } // Clear out the asn1.RawContent so the re-marshal operation sees the // updated structure (rather than just copying the out-of-date DER data). tbs.Raw = nil } data, err = asn1.Marshal(tbs) if err != nil { return nil, fmt.Errorf("failed to re-marshal TBSCertificate: %v", err) } return data, nil } type basicConstraints struct { IsCA bool `asn1:"optional"` MaxPathLen int `asn1:"optional,default:-1"` } // RFC 5280, 4.2.1.4 type policyInformation struct { Policy asn1.ObjectIdentifier // policyQualifiers omitted } const ( nameTypeEmail = 1 nameTypeDNS = 2 nameTypeURI = 6 nameTypeIP = 7 ) // RFC 5280, 4.2.2.1 type accessDescription struct { Method asn1.ObjectIdentifier Location asn1.RawValue } // RFC 5280, 4.2.1.14 type distributionPoint struct { DistributionPoint distributionPointName `asn1:"optional,tag:0"` Reason asn1.BitString `asn1:"optional,tag:1"` CRLIssuer asn1.RawValue `asn1:"optional,tag:2"` } type distributionPointName struct { FullName []asn1.RawValue `asn1:"optional,tag:0"` RelativeName pkix.RDNSequence `asn1:"optional,tag:1"` } func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo, nfe *NonFatalErrors) (interface{}, error) { asn1Data := keyData.PublicKey.RightAlign() switch algo { case RSA, RSAESOAEP: // RSA public keys must have a NULL in the parameters. // See RFC 3279, Section 2.3.1. if algo == RSA && !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) { nfe.AddError(errors.New("x509: RSA key missing NULL parameters")) } if algo == RSAESOAEP { // We only parse the parameters to ensure it is a valid encoding, we throw out the actual values paramsData := keyData.Algorithm.Parameters.FullBytes params := new(rsaesoaepAlgorithmParameters) params.HashFunc = sha1Identifier params.MaskgenFunc = mgf1SHA1Identifier params.PSourceFunc = pSpecifiedEmptyIdentifier rest, err := asn1.Unmarshal(paramsData, params) if err != nil { return nil, err } if len(rest) != 0 { return nil, errors.New("x509: trailing data after RSAES-OAEP parameters") } } p := new(pkcs1PublicKey) rest, err := asn1.Unmarshal(asn1Data, p) if err != nil { var laxErr error rest, laxErr = asn1.UnmarshalWithParams(asn1Data, p, "lax") if laxErr != nil { return nil, laxErr } nfe.AddError(err) } if len(rest) != 0 { return nil, errors.New("x509: trailing data after RSA public key") } if p.N.Sign() <= 0 { nfe.AddError(errors.New("x509: RSA modulus is not a positive number")) } if p.E <= 0 { return nil, errors.New("x509: RSA public exponent is not a positive number") } // TODO(dkarch): Update to return the parameters once crypto/x509 has come up with permanent solution (https://github.com/golang/go/issues/30416) pub := &rsa.PublicKey{ E: p.E, N: p.N, } return pub, nil case DSA: var p *big.Int rest, err := asn1.Unmarshal(asn1Data, &p) if err != nil { var laxErr error rest, laxErr = asn1.UnmarshalWithParams(asn1Data, &p, "lax") if laxErr != nil { return nil, laxErr } nfe.AddError(err) } if len(rest) != 0 { return nil, errors.New("x509: trailing data after DSA public key") } paramsData := keyData.Algorithm.Parameters.FullBytes params := new(dsaAlgorithmParameters) rest, err = asn1.Unmarshal(paramsData, params) if err != nil { return nil, err } if len(rest) != 0 { return nil, errors.New("x509: trailing data after DSA parameters") } if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 { return nil, errors.New("x509: zero or negative DSA parameter") } pub := &dsa.PublicKey{ Parameters: dsa.Parameters{ P: params.P, Q: params.Q, G: params.G, }, Y: p, } return pub, nil case ECDSA: paramsData := keyData.Algorithm.Parameters.FullBytes namedCurveOID := new(asn1.ObjectIdentifier) rest, err := asn1.Unmarshal(paramsData, namedCurveOID) if err != nil { return nil, errors.New("x509: failed to parse ECDSA parameters as named curve") } if len(rest) != 0 { return nil, errors.New("x509: trailing data after ECDSA parameters") } namedCurve := namedCurveFromOID(*namedCurveOID, nfe) if namedCurve == nil { return nil, fmt.Errorf("x509: unsupported elliptic curve %v", namedCurveOID) } x, y := elliptic.Unmarshal(namedCurve, asn1Data) if x == nil { return nil, errors.New("x509: failed to unmarshal elliptic curve point") } pub := &ecdsa.PublicKey{ Curve: namedCurve, X: x, Y: y, } return pub, nil case Ed25519: return ed25519.PublicKey(asn1Data), nil default: return nil, nil } } // NonFatalErrors is an error type which can hold a number of other errors. // It's used to collect a range of non-fatal errors which occur while parsing // a certificate, that way we can still match on certs which technically are // invalid. type NonFatalErrors struct { Errors []error } // AddError adds an error to the list of errors contained by NonFatalErrors. func (e *NonFatalErrors) AddError(err error) { e.Errors = append(e.Errors, err) } // Returns a string consisting of the values of Error() from all of the errors // contained in |e| func (e NonFatalErrors) Error() string { r := "NonFatalErrors: " for _, err := range e.Errors { r += err.Error() + "; " } return r } // HasError returns true if |e| contains at least one error func (e *NonFatalErrors) HasError() bool { if e == nil { return false } return len(e.Errors) > 0 } // Append combines the contents of two NonFatalErrors instances. func (e *NonFatalErrors) Append(more *NonFatalErrors) *NonFatalErrors { if e == nil { return more } if more == nil { return e } combined := NonFatalErrors{Errors: make([]error, 0, len(e.Errors)+len(more.Errors))} combined.Errors = append(combined.Errors, e.Errors...) combined.Errors = append(combined.Errors, more.Errors...) return &combined } // IsFatal indicates whether an error is fatal. func IsFatal(err error) bool { if err == nil { return false } if _, ok := err.(NonFatalErrors); ok { return false } if errs, ok := err.(*Errors); ok { return errs.Fatal() } return true } func parseDistributionPoints(data []byte, crldp *[]string) error { // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint // // DistributionPoint ::= SEQUENCE { // distributionPoint [0] DistributionPointName OPTIONAL, // reasons [1] ReasonFlags OPTIONAL, // cRLIssuer [2] GeneralNames OPTIONAL } // // DistributionPointName ::= CHOICE { // fullName [0] GeneralNames, // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } var cdp []distributionPoint if rest, err := asn1.Unmarshal(data, &cdp); err != nil { return err } else if len(rest) != 0 { return errors.New("x509: trailing data after X.509 CRL distribution point") } for _, dp := range cdp { // Per RFC 5280, 4.2.1.13, one of distributionPoint or cRLIssuer may be empty. if len(dp.DistributionPoint.FullName) == 0 { continue } for _, fullName := range dp.DistributionPoint.FullName { if fullName.Tag == 6 { *crldp = append(*crldp, string(fullName.Bytes)) } } } return nil } func forEachSAN(extension []byte, callback func(tag int, data []byte) error) error { // RFC 5280, 4.2.1.6 // SubjectAltName ::= GeneralNames // // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName // // GeneralName ::= CHOICE { // otherName [0] OtherName, // rfc822Name [1] IA5String, // dNSName [2] IA5String, // x400Address [3] ORAddress, // directoryName [4] Name, // ediPartyName [5] EDIPartyName, // uniformResourceIdentifier [6] IA5String, // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } var seq asn1.RawValue rest, err := asn1.Unmarshal(extension, &seq) if err != nil { return err } else if len(rest) != 0 { return errors.New("x509: trailing data after X.509 extension") } if !seq.IsCompound || seq.Tag != asn1.TagSequence || seq.Class != asn1.ClassUniversal { return asn1.StructuralError{Msg: "bad SAN sequence"} } rest = seq.Bytes for len(rest) > 0 { var v asn1.RawValue rest, err = asn1.Unmarshal(rest, &v) if err != nil { return err } if err := callback(v.Tag, v.Bytes); err != nil { return err } } return nil } func parseSANExtension(value []byte, nfe *NonFatalErrors) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) { err = forEachSAN(value, func(tag int, data []byte) error { switch tag { case nameTypeEmail: emailAddresses = append(emailAddresses, string(data)) case nameTypeDNS: dnsNames = append(dnsNames, string(data)) case nameTypeURI: uri, err := url.Parse(string(data)) if err != nil { return fmt.Errorf("x509: cannot parse URI %q: %s", string(data), err) } if len(uri.Host) > 0 { if _, ok := domainToReverseLabels(uri.Host); !ok { return fmt.Errorf("x509: cannot parse URI %q: invalid domain", string(data)) } } uris = append(uris, uri) case nameTypeIP: switch len(data) { case net.IPv4len, net.IPv6len: ipAddresses = append(ipAddresses, data) default: nfe.AddError(errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data)))) } } return nil }) return } // isValidIPMask reports whether mask consists of zero or more 1 bits, followed by zero bits. func isValidIPMask(mask []byte) bool { seenZero := false for _, b := range mask { if seenZero { if b != 0 { return false } continue } switch b { case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe: seenZero = true case 0xff: default: return false } } return true } func parseNameConstraintsExtension(out *Certificate, e pkix.Extension, nfe *NonFatalErrors) (unhandled bool, err error) { // RFC 5280, 4.2.1.10 // NameConstraints ::= SEQUENCE { // permittedSubtrees [0] GeneralSubtrees OPTIONAL, // excludedSubtrees [1] GeneralSubtrees OPTIONAL } // // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree // // GeneralSubtree ::= SEQUENCE { // base GeneralName, // minimum [0] BaseDistance DEFAULT 0, // maximum [1] BaseDistance OPTIONAL } // // BaseDistance ::= INTEGER (0..MAX) outer := cryptobyte.String(e.Value) var toplevel, permitted, excluded cryptobyte.String var havePermitted, haveExcluded bool if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) || !outer.Empty() || !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) || !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) || !toplevel.Empty() { return false, errors.New("x509: invalid NameConstraints extension") } if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 { // From RFC 5280, Section 4.2.1.10: // “either the permittedSubtrees field // or the excludedSubtrees MUST be // present” return false, errors.New("x509: empty name constraints extension") } getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) { for !subtrees.Empty() { var seq, value cryptobyte.String var tag cryptobyte_asn1.Tag if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) || !seq.ReadAnyASN1(&value, &tag) { return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension") } var ( dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific() emailTag = cryptobyte_asn1.Tag(1).ContextSpecific() ipTag = cryptobyte_asn1.Tag(7).ContextSpecific() uriTag = cryptobyte_asn1.Tag(6).ContextSpecific() ) switch tag { case dnsTag: domain := string(value) if err := isIA5String(domain); err != nil { return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) } trimmedDomain := domain if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { // constraints can have a leading // period to exclude the domain // itself, but that's not valid in a // normal domain name. trimmedDomain = trimmedDomain[1:] } if _, ok := domainToReverseLabels(trimmedDomain); !ok { nfe.AddError(fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)) } dnsNames = append(dnsNames, domain) case ipTag: l := len(value) var ip, mask []byte switch l { case 8: ip = value[:4] mask = value[4:] case 32: ip = value[:16] mask = value[16:] default: return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l) } if !isValidIPMask(mask) { return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask) } ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)}) case emailTag: constraint := string(value) if err := isIA5String(constraint); err != nil { return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) } // If the constraint contains an @ then // it specifies an exact mailbox name. if strings.Contains(constraint, "@") { if _, ok := parseRFC2821Mailbox(constraint); !ok { nfe.AddError(fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)) } } else { // Otherwise it's a domain name. domain := constraint if len(domain) > 0 && domain[0] == '.' { domain = domain[1:] } if _, ok := domainToReverseLabels(domain); !ok { nfe.AddError(fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)) } } emails = append(emails, constraint) case uriTag: domain := string(value) if err := isIA5String(domain); err != nil { return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) } if net.ParseIP(domain) != nil { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain) } trimmedDomain := domain if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { // constraints can have a leading // period to exclude the domain itself, // but that's not valid in a normal // domain name. trimmedDomain = trimmedDomain[1:] } if _, ok := domainToReverseLabels(trimmedDomain); !ok { nfe.AddError(fmt.Errorf("x509: failed to parse URI constraint %q", domain)) } uriDomains = append(uriDomains, domain) default: unhandled = true } } return dnsNames, ips, emails, uriDomains, nil } if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil { return false, err } if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil { return false, err } out.PermittedDNSDomainsCritical = e.Critical return unhandled, nil } func parseCertificate(in *certificate) (*Certificate, error) { var nfe NonFatalErrors out := new(Certificate) out.Raw = in.Raw out.RawTBSCertificate = in.TBSCertificate.Raw out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw out.RawSubject = in.TBSCertificate.Subject.FullBytes out.RawIssuer = in.TBSCertificate.Issuer.FullBytes out.Signature = in.SignatureValue.RightAlign() out.SignatureAlgorithm = SignatureAlgorithmFromAI(in.TBSCertificate.SignatureAlgorithm) out.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm) var err error out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey, &nfe) if err != nil { return nil, err } out.Version = in.TBSCertificate.Version + 1 out.SerialNumber = in.TBSCertificate.SerialNumber var issuer, subject pkix.RDNSequence if rest, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil { var laxErr error rest, laxErr = asn1.UnmarshalWithParams(in.TBSCertificate.Subject.FullBytes, &subject, "lax") if laxErr != nil { return nil, laxErr } nfe.AddError(err) } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 subject") } if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil { var laxErr error rest, laxErr = asn1.UnmarshalWithParams(in.TBSCertificate.Issuer.FullBytes, &issuer, "lax") if laxErr != nil { return nil, laxErr } nfe.AddError(err) } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 subject") } out.Issuer.FillFromRDNSequence(&issuer) out.Subject.FillFromRDNSequence(&subject) out.NotBefore = in.TBSCertificate.Validity.NotBefore out.NotAfter = in.TBSCertificate.Validity.NotAfter for _, e := range in.TBSCertificate.Extensions { out.Extensions = append(out.Extensions, e) unhandled := false if len(e.Id) == 4 && e.Id[0] == OIDExtensionArc[0] && e.Id[1] == OIDExtensionArc[1] && e.Id[2] == OIDExtensionArc[2] { switch e.Id[3] { case OIDExtensionKeyUsage[3]: // RFC 5280, 4.2.1.3 var usageBits asn1.BitString if rest, err := asn1.Unmarshal(e.Value, &usageBits); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 KeyUsage") } var usage int for i := 0; i < 9; i++ { if usageBits.At(i) != 0 { usage |= 1 << uint(i) } } out.KeyUsage = KeyUsage(usage) case OIDExtensionBasicConstraints[3]: // RFC 5280, 4.2.1.9 var constraints basicConstraints if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 BasicConstraints") } out.BasicConstraintsValid = true out.IsCA = constraints.IsCA out.MaxPathLen = constraints.MaxPathLen out.MaxPathLenZero = out.MaxPathLen == 0 // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285) case OIDExtensionSubjectAltName[3]: out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value, &nfe) if err != nil { return nil, err } if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 { // If we didn't parse anything then we do the critical check, below. unhandled = true } case OIDExtensionNameConstraints[3]: unhandled, err = parseNameConstraintsExtension(out, e, &nfe) if err != nil { return nil, err } case OIDExtensionCRLDistributionPoints[3]: // RFC 5280, 4.2.1.13 if err := parseDistributionPoints(e.Value, &out.CRLDistributionPoints); err != nil { return nil, err } case OIDExtensionAuthorityKeyId[3]: // RFC 5280, 4.2.1.1 var a authKeyId if rest, err := asn1.Unmarshal(e.Value, &a); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 authority key-id") } out.AuthorityKeyId = a.Id case OIDExtensionExtendedKeyUsage[3]: // RFC 5280, 4.2.1.12. Extended Key Usage // id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } // // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId // // KeyPurposeId ::= OBJECT IDENTIFIER var keyUsage []asn1.ObjectIdentifier if len(e.Value) == 0 { nfe.AddError(errors.New("x509: empty ExtendedKeyUsage")) } else { rest, err := asn1.Unmarshal(e.Value, &keyUsage) if err != nil { var laxErr error rest, laxErr = asn1.UnmarshalWithParams(e.Value, &keyUsage, "lax") if laxErr != nil { return nil, laxErr } nfe.AddError(err) } if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage") } } for _, u := range keyUsage { if extKeyUsage, ok := extKeyUsageFromOID(u); ok { out.ExtKeyUsage = append(out.ExtKeyUsage, extKeyUsage) } else { out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u) } } case OIDExtensionSubjectKeyId[3]: // RFC 5280, 4.2.1.2 var keyid []byte if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 key-id") } out.SubjectKeyId = keyid case OIDExtensionCertificatePolicies[3]: // RFC 5280 4.2.1.4: Certificate Policies var policies []policyInformation if rest, err := asn1.Unmarshal(e.Value, &policies); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 certificate policies") } out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies)) for i, policy := range policies { out.PolicyIdentifiers[i] = policy.Policy } default: // Unknown extensions are recorded if critical. unhandled = true } } else if e.Id.Equal(OIDExtensionAuthorityInfoAccess) { // RFC 5280 4.2.2.1: Authority Information Access var aia []accessDescription if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 authority information") } if len(aia) == 0 { nfe.AddError(errors.New("x509: empty AuthorityInfoAccess extension")) } for _, v := range aia { // GeneralName: uniformResourceIdentifier [6] IA5String if v.Location.Tag != 6 { continue } if v.Method.Equal(OIDAuthorityInfoAccessOCSP) { out.OCSPServer = append(out.OCSPServer, string(v.Location.Bytes)) } else if v.Method.Equal(OIDAuthorityInfoAccessIssuers) { out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes)) } } } else if e.Id.Equal(OIDExtensionSubjectInfoAccess) { // RFC 5280 4.2.2.2: Subject Information Access var sia []accessDescription if rest, err := asn1.Unmarshal(e.Value, &sia); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 subject information") } if len(sia) == 0 { nfe.AddError(errors.New("x509: empty SubjectInfoAccess extension")) } for _, v := range sia { // TODO(drysdale): cope with non-URI types of GeneralName // GeneralName: uniformResourceIdentifier [6] IA5String if v.Location.Tag != 6 { continue } if v.Method.Equal(OIDSubjectInfoAccessTimestamp) { out.SubjectTimestamps = append(out.SubjectTimestamps, string(v.Location.Bytes)) } else if v.Method.Equal(OIDSubjectInfoAccessCARepo) { out.SubjectCARepositories = append(out.SubjectCARepositories, string(v.Location.Bytes)) } } } else if e.Id.Equal(OIDExtensionIPPrefixList) { out.RPKIAddressRanges = parseRPKIAddrBlocks(e.Value, &nfe) } else if e.Id.Equal(OIDExtensionASList) { out.RPKIASNumbers, out.RPKIRoutingDomainIDs = parseRPKIASIdentifiers(e.Value, &nfe) } else if e.Id.Equal(OIDExtensionCTSCT) { if rest, err := asn1.Unmarshal(e.Value, &out.RawSCT); err != nil { nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal SCT list extension: %v", err)) } else if len(rest) != 0 { nfe.AddError(errors.New("trailing data after ASN1-encoded SCT list")) } else { if rest, err := tls.Unmarshal(out.RawSCT, &out.SCTList); err != nil { nfe.AddError(fmt.Errorf("failed to tls.Unmarshal SCT list: %v", err)) } else if len(rest) != 0 { nfe.AddError(errors.New("trailing data after TLS-encoded SCT list")) } } } else { // Unknown extensions are recorded if critical. unhandled = true } if e.Critical && unhandled { out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id) } } if nfe.HasError() { return out, nfe } return out, nil } // ParseTBSCertificate parses a single TBSCertificate from the given ASN.1 DER data. // The parsed data is returned in a Certificate struct for ease of access. func ParseTBSCertificate(asn1Data []byte) (*Certificate, error) { var tbsCert tbsCertificate var nfe NonFatalErrors rest, err := asn1.Unmarshal(asn1Data, &tbsCert) if err != nil { var laxErr error rest, laxErr = asn1.UnmarshalWithParams(asn1Data, &tbsCert, "lax") if laxErr != nil { return nil, laxErr } nfe.AddError(err) } if len(rest) > 0 { return nil, asn1.SyntaxError{Msg: "trailing data"} } ret, err := parseCertificate(&certificate{ Raw: tbsCert.Raw, TBSCertificate: tbsCert}) if err != nil { errs, ok := err.(NonFatalErrors) if !ok { return nil, err } nfe.Errors = append(nfe.Errors, errs.Errors...) } if nfe.HasError() { return ret, nfe } return ret, nil } // ParseCertificate parses a single certificate from the given ASN.1 DER data. // This function can return both a Certificate and an error (in which case the // error will be of type NonFatalErrors). func ParseCertificate(asn1Data []byte) (*Certificate, error) { var cert certificate var nfe NonFatalErrors rest, err := asn1.Unmarshal(asn1Data, &cert) if err != nil { var laxErr error rest, laxErr = asn1.UnmarshalWithParams(asn1Data, &cert, "lax") if laxErr != nil { return nil, laxErr } nfe.AddError(err) } if len(rest) > 0 { return nil, asn1.SyntaxError{Msg: "trailing data"} } ret, err := parseCertificate(&cert) if err != nil { errs, ok := err.(NonFatalErrors) if !ok { return nil, err } nfe.Errors = append(nfe.Errors, errs.Errors...) } if nfe.HasError() { return ret, nfe } return ret, nil } // ParseCertificates parses one or more certificates from the given ASN.1 DER // data. The certificates must be concatenated with no intermediate padding. // This function can return both a slice of Certificate and an error (in which // case the error will be of type NonFatalErrors). func ParseCertificates(asn1Data []byte) ([]*Certificate, error) { var v []*certificate var nfe NonFatalErrors for len(asn1Data) > 0 { cert := new(certificate) var err error asn1Data, err = asn1.Unmarshal(asn1Data, cert) if err != nil { var laxErr error asn1Data, laxErr = asn1.UnmarshalWithParams(asn1Data, &cert, "lax") if laxErr != nil { return nil, laxErr } nfe.AddError(err) } v = append(v, cert) } ret := make([]*Certificate, len(v)) for i, ci := range v { cert, err := parseCertificate(ci) if err != nil { errs, ok := err.(NonFatalErrors) if !ok { return nil, err } nfe.Errors = append(nfe.Errors, errs.Errors...) } ret[i] = cert } if nfe.HasError() { return ret, nfe } return ret, nil } func reverseBitsInAByte(in byte) byte { b1 := in>>4 | in<<4 b2 := b1>>2&0x33 | b1<<2&0xcc b3 := b2>>1&0x55 | b2<<1&0xaa return b3 } // asn1BitLength returns the bit-length of bitString by considering the // most-significant bit in a byte to be the "first" bit. This convention // matches ASN.1, but differs from almost everything else. func asn1BitLength(bitString []byte) int { bitLen := len(bitString) * 8 for i := range bitString { b := bitString[len(bitString)-i-1] for bit := uint(0); bit < 8; bit++ { if (b>>bit)&1 == 1 { return bitLen } bitLen-- } } return 0 } // OID values for standard extensions from RFC 5280. var ( OIDExtensionArc = asn1.ObjectIdentifier{2, 5, 29} // id-ce RFC5280 s4.2.1 OIDExtensionSubjectKeyId = asn1.ObjectIdentifier{2, 5, 29, 14} OIDExtensionKeyUsage = asn1.ObjectIdentifier{2, 5, 29, 15} OIDExtensionExtendedKeyUsage = asn1.ObjectIdentifier{2, 5, 29, 37} OIDExtensionAuthorityKeyId = asn1.ObjectIdentifier{2, 5, 29, 35} OIDExtensionBasicConstraints = asn1.ObjectIdentifier{2, 5, 29, 19} OIDExtensionSubjectAltName = asn1.ObjectIdentifier{2, 5, 29, 17} OIDExtensionCertificatePolicies = asn1.ObjectIdentifier{2, 5, 29, 32} OIDExtensionNameConstraints = asn1.ObjectIdentifier{2, 5, 29, 30} OIDExtensionCRLDistributionPoints = asn1.ObjectIdentifier{2, 5, 29, 31} OIDExtensionIssuerAltName = asn1.ObjectIdentifier{2, 5, 29, 18} OIDExtensionSubjectDirectoryAttributes = asn1.ObjectIdentifier{2, 5, 29, 9} OIDExtensionInhibitAnyPolicy = asn1.ObjectIdentifier{2, 5, 29, 54} OIDExtensionPolicyConstraints = asn1.ObjectIdentifier{2, 5, 29, 36} OIDExtensionPolicyMappings = asn1.ObjectIdentifier{2, 5, 29, 33} OIDExtensionFreshestCRL = asn1.ObjectIdentifier{2, 5, 29, 46} OIDExtensionAuthorityInfoAccess = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 1} OIDExtensionSubjectInfoAccess = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 11} // OIDExtensionCTPoison is defined in RFC 6962 s3.1. OIDExtensionCTPoison = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3} // OIDExtensionCTSCT is defined in RFC 6962 s3.3. OIDExtensionCTSCT = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2} // OIDExtensionIPPrefixList is defined in RFC 3779 s2. OIDExtensionIPPrefixList = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 7} // OIDExtensionASList is defined in RFC 3779 s3. OIDExtensionASList = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 8} ) var ( OIDAuthorityInfoAccessOCSP = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1} OIDAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2} OIDSubjectInfoAccessTimestamp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 3} OIDSubjectInfoAccessCARepo = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 5} OIDAnyPolicy = asn1.ObjectIdentifier{2, 5, 29, 32, 0} ) // oidInExtensions reports whether an extension with the given oid exists in // extensions. func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool { for _, e := range extensions { if e.Id.Equal(oid) { return true } } return false } // marshalSANs marshals a list of addresses into a the contents of an X.509 // SubjectAlternativeName extension. func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL) (derBytes []byte, err error) { var rawValues []asn1.RawValue for _, name := range dnsNames { rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeDNS, Class: asn1.ClassContextSpecific, Bytes: []byte(name)}) } for _, email := range emailAddresses { rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeEmail, Class: asn1.ClassContextSpecific, Bytes: []byte(email)}) } for _, rawIP := range ipAddresses { // If possible, we always want to encode IPv4 addresses in 4 bytes. ip := rawIP.To4() if ip == nil { ip = rawIP } rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeIP, Class: asn1.ClassContextSpecific, Bytes: ip}) } for _, uri := range uris { rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: asn1.ClassContextSpecific, Bytes: []byte(uri.String())}) } return asn1.Marshal(rawValues) } func isIA5String(s string) error { for _, r := range s { if r >= utf8.RuneSelf { return fmt.Errorf("x509: %q cannot be encoded as an IA5String", s) } } return nil } func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte) (ret []pkix.Extension, err error) { ret = make([]pkix.Extension, 12 /* maximum number of elements. */) n := 0 if template.KeyUsage != 0 && !oidInExtensions(OIDExtensionKeyUsage, template.ExtraExtensions) { ret[n].Id = OIDExtensionKeyUsage ret[n].Critical = true var a [2]byte a[0] = reverseBitsInAByte(byte(template.KeyUsage)) a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8)) l := 1 if a[1] != 0 { l = 2 } bitString := a[:l] ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)}) if err != nil { return } n++ } if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) && !oidInExtensions(OIDExtensionExtendedKeyUsage, template.ExtraExtensions) { ret[n].Id = OIDExtensionExtendedKeyUsage var oids []asn1.ObjectIdentifier for _, u := range template.ExtKeyUsage { if oid, ok := oidFromExtKeyUsage(u); ok { oids = append(oids, oid) } else { panic("internal error") } } oids = append(oids, template.UnknownExtKeyUsage...) ret[n].Value, err = asn1.Marshal(oids) if err != nil { return } n++ } if template.BasicConstraintsValid && !oidInExtensions(OIDExtensionBasicConstraints, template.ExtraExtensions) { // Leaving MaxPathLen as zero indicates that no maximum path // length is desired, unless MaxPathLenZero is set. A value of // -1 causes encoding/asn1 to omit the value as desired. maxPathLen := template.MaxPathLen if maxPathLen == 0 && !template.MaxPathLenZero { maxPathLen = -1 } ret[n].Id = OIDExtensionBasicConstraints ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, maxPathLen}) ret[n].Critical = true if err != nil { return } n++ } if len(template.SubjectKeyId) > 0 && !oidInExtensions(OIDExtensionSubjectKeyId, template.ExtraExtensions) { ret[n].Id = OIDExtensionSubjectKeyId ret[n].Value, err = asn1.Marshal(template.SubjectKeyId) if err != nil { return } n++ } if len(authorityKeyId) > 0 && !oidInExtensions(OIDExtensionAuthorityKeyId, template.ExtraExtensions) { ret[n].Id = OIDExtensionAuthorityKeyId ret[n].Value, err = asn1.Marshal(authKeyId{authorityKeyId}) if err != nil { return } n++ } if (len(template.OCSPServer) > 0 || len(template.IssuingCertificateURL) > 0) && !oidInExtensions(OIDExtensionAuthorityInfoAccess, template.ExtraExtensions) { ret[n].Id = OIDExtensionAuthorityInfoAccess var aiaValues []accessDescription for _, name := range template.OCSPServer { aiaValues = append(aiaValues, accessDescription{ Method: OIDAuthorityInfoAccessOCSP, Location: asn1.RawValue{Tag: 6, Class: asn1.ClassContextSpecific, Bytes: []byte(name)}, }) } for _, name := range template.IssuingCertificateURL { aiaValues = append(aiaValues, accessDescription{ Method: OIDAuthorityInfoAccessIssuers, Location: asn1.RawValue{Tag: 6, Class: asn1.ClassContextSpecific, Bytes: []byte(name)}, }) } ret[n].Value, err = asn1.Marshal(aiaValues) if err != nil { return } n++ } if len(template.SubjectTimestamps) > 0 || len(template.SubjectCARepositories) > 0 && !oidInExtensions(OIDExtensionSubjectInfoAccess, template.ExtraExtensions) { ret[n].Id = OIDExtensionSubjectInfoAccess var siaValues []accessDescription for _, ts := range template.SubjectTimestamps { siaValues = append(siaValues, accessDescription{ Method: OIDSubjectInfoAccessTimestamp, Location: asn1.RawValue{Tag: 6, Class: asn1.ClassContextSpecific, Bytes: []byte(ts)}, }) } for _, repo := range template.SubjectCARepositories { siaValues = append(siaValues, accessDescription{ Method: OIDSubjectInfoAccessCARepo, Location: asn1.RawValue{Tag: 6, Class: asn1.ClassContextSpecific, Bytes: []byte(repo)}, }) } ret[n].Value, err = asn1.Marshal(siaValues) if err != nil { return } n++ } if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) && !oidInExtensions(OIDExtensionSubjectAltName, template.ExtraExtensions) { ret[n].Id = OIDExtensionSubjectAltName // From RFC 5280, Section 4.2.1.6: // “If the subject field contains an empty sequence ... then // subjectAltName extension ... is marked as critical” ret[n].Critical = subjectIsEmpty ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs) if err != nil { return } n++ } if len(template.PolicyIdentifiers) > 0 && !oidInExtensions(OIDExtensionCertificatePolicies, template.ExtraExtensions) { ret[n].Id = OIDExtensionCertificatePolicies policies := make([]policyInformation, len(template.PolicyIdentifiers)) for i, policy := range template.PolicyIdentifiers { policies[i].Policy = policy } ret[n].Value, err = asn1.Marshal(policies) if err != nil { return } n++ } if (len(template.PermittedDNSDomains) > 0 || len(template.ExcludedDNSDomains) > 0 || len(template.PermittedIPRanges) > 0 || len(template.ExcludedIPRanges) > 0 || len(template.PermittedEmailAddresses) > 0 || len(template.ExcludedEmailAddresses) > 0 || len(template.PermittedURIDomains) > 0 || len(template.ExcludedURIDomains) > 0) && !oidInExtensions(OIDExtensionNameConstraints, template.ExtraExtensions) { ret[n].Id = OIDExtensionNameConstraints ret[n].Critical = template.PermittedDNSDomainsCritical ipAndMask := func(ipNet *net.IPNet) []byte { maskedIP := ipNet.IP.Mask(ipNet.Mask) ipAndMask := make([]byte, 0, len(maskedIP)+len(ipNet.Mask)) ipAndMask = append(ipAndMask, maskedIP...) ipAndMask = append(ipAndMask, ipNet.Mask...) return ipAndMask } serialiseConstraints := func(dns []string, ips []*net.IPNet, emails []string, uriDomains []string) (der []byte, err error) { var b cryptobyte.Builder for _, name := range dns { if err = isIA5String(name); err != nil { return nil, err } b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { b.AddASN1(cryptobyte_asn1.Tag(2).ContextSpecific(), func(b *cryptobyte.Builder) { b.AddBytes([]byte(name)) }) }) } for _, ipNet := range ips { b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { b.AddASN1(cryptobyte_asn1.Tag(7).ContextSpecific(), func(b *cryptobyte.Builder) { b.AddBytes(ipAndMask(ipNet)) }) }) } for _, email := range emails { if err = isIA5String(email); err != nil { return nil, err } b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific(), func(b *cryptobyte.Builder) { b.AddBytes([]byte(email)) }) }) } for _, uriDomain := range uriDomains { if err = isIA5String(uriDomain); err != nil { return nil, err } b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { b.AddASN1(cryptobyte_asn1.Tag(6).ContextSpecific(), func(b *cryptobyte.Builder) { b.AddBytes([]byte(uriDomain)) }) }) } return b.Bytes() } permitted, err := serialiseConstraints(template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains) if err != nil { return nil, err } excluded, err := serialiseConstraints(template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains) if err != nil { return nil, err } var b cryptobyte.Builder b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { if len(permitted) > 0 { b.AddASN1(cryptobyte_asn1.Tag(0).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) { b.AddBytes(permitted) }) } if len(excluded) > 0 { b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) { b.AddBytes(excluded) }) } }) ret[n].Value, err = b.Bytes() if err != nil { return nil, err } n++ } if len(template.CRLDistributionPoints) > 0 && !oidInExtensions(OIDExtensionCRLDistributionPoints, template.ExtraExtensions) { ret[n].Id = OIDExtensionCRLDistributionPoints var crlDp []distributionPoint for _, name := range template.CRLDistributionPoints { dp := distributionPoint{ DistributionPoint: distributionPointName{ FullName: []asn1.RawValue{ {Tag: 6, Class: asn1.ClassContextSpecific, Bytes: []byte(name)}, }, }, } crlDp = append(crlDp, dp) } ret[n].Value, err = asn1.Marshal(crlDp) if err != nil { return } n++ } if (len(template.RawSCT) > 0 || len(template.SCTList.SCTList) > 0) && !oidInExtensions(OIDExtensionCTSCT, template.ExtraExtensions) { rawSCT := template.RawSCT if len(template.SCTList.SCTList) > 0 { rawSCT, err = tls.Marshal(template.SCTList) if err != nil { return } } ret[n].Id = OIDExtensionCTSCT ret[n].Value, err = asn1.Marshal(rawSCT) if err != nil { return } n++ } // Adding another extension here? Remember to update the maximum number // of elements in the make() at the top of the function and the list of // template fields used in CreateCertificate documentation. return append(ret[:n], template.ExtraExtensions...), nil } func subjectBytes(cert *Certificate) ([]byte, error) { if len(cert.RawSubject) > 0 { return cert.RawSubject, nil } return asn1.Marshal(cert.Subject.ToRDNSequence()) } // signingParamsForPublicKey returns the parameters to use for signing with // priv. If requestedSigAlgo is not zero then it overrides the default // signature algorithm. func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) { var pubType PublicKeyAlgorithm switch pub := pub.(type) { case *rsa.PublicKey: pubType = RSA hashFunc = crypto.SHA256 sigAlgo.Algorithm = oidSignatureSHA256WithRSA sigAlgo.Parameters = asn1.NullRawValue case *ecdsa.PublicKey: pubType = ECDSA switch pub.Curve { case elliptic.P224(), elliptic.P256(): hashFunc = crypto.SHA256 sigAlgo.Algorithm = oidSignatureECDSAWithSHA256 case elliptic.P384(): hashFunc = crypto.SHA384 sigAlgo.Algorithm = oidSignatureECDSAWithSHA384 case elliptic.P521(): hashFunc = crypto.SHA512 sigAlgo.Algorithm = oidSignatureECDSAWithSHA512 default: err = errors.New("x509: unknown elliptic curve") } case ed25519.PublicKey: pubType = Ed25519 sigAlgo.Algorithm = oidSignatureEd25519 default: err = errors.New("x509: only RSA, ECDSA and Ed25519 keys supported") } if err != nil { return } if requestedSigAlgo == 0 { return } found := false for _, details := range signatureAlgorithmDetails { if details.algo == requestedSigAlgo { if details.pubKeyAlgo != pubType { err = errors.New("x509: requested SignatureAlgorithm does not match private key type") return } sigAlgo.Algorithm, hashFunc = details.oid, details.hash if hashFunc == 0 && pubType != Ed25519 { err = errors.New("x509: cannot sign with hash function requested") return } if requestedSigAlgo.isRSAPSS() { sigAlgo.Parameters = rsaPSSParameters(hashFunc) } found = true break } } if !found { err = errors.New("x509: unknown SignatureAlgorithm") } return } // emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is // just an empty SEQUENCE. var emptyASN1Subject = []byte{0x30, 0} // CreateCertificate creates a new X.509v3 certificate based on a template. // The following members of template are used: // - SerialNumber // - Subject // - NotBefore, NotAfter // - SignatureAlgorithm // - For extensions: // - KeyUsage // - ExtKeyUsage, UnknownExtKeyUsage // - BasicConstraintsValid, IsCA, MaxPathLen, MaxPathLenZero // - SubjectKeyId // - AuthorityKeyId // - OCSPServer, IssuingCertificateURL // - SubjectTimestamps, SubjectCARepositories // - DNSNames, EmailAddresses, IPAddresses, URIs // - PolicyIdentifiers // - ExcludedDNSDomains, ExcludedIPRanges, ExcludedEmailAddresses, ExcludedURIDomains, PermittedDNSDomainsCritical, // PermittedDNSDomains, PermittedIPRanges, PermittedEmailAddresses, PermittedURIDomains // - CRLDistributionPoints // - RawSCT, SCTList // - ExtraExtensions // // The certificate is signed by parent. If parent is equal to template then the // certificate is self-signed. The parameter pub is the public key of the // signee and priv is the private key of the signer. // // The returned slice is the certificate in DER encoding. // // The currently supported key types are *rsa.PublicKey, *ecdsa.PublicKey and // ed25519.PublicKey. pub must be a supported key type, and priv must be a // crypto.Signer with a supported public key. // // The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any, // unless the resulting certificate is self-signed. Otherwise the value from // template will be used. func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) { key, ok := priv.(crypto.Signer) if !ok { return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } if template.SerialNumber == nil { return nil, errors.New("x509: no SerialNumber given") } hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) if err != nil { return nil, err } publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub) if err != nil { return nil, err } asn1Issuer, err := subjectBytes(parent) if err != nil { return } asn1Subject, err := subjectBytes(template) if err != nil { return } authorityKeyId := template.AuthorityKeyId if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 { authorityKeyId = parent.SubjectKeyId } extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId) if err != nil { return } encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes} c := tbsCertificate{ Version: 2, SerialNumber: template.SerialNumber, SignatureAlgorithm: signatureAlgorithm, Issuer: asn1.RawValue{FullBytes: asn1Issuer}, Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()}, Subject: asn1.RawValue{FullBytes: asn1Subject}, PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}, Extensions: extensions, } tbsCertContents, err := asn1.Marshal(c) if err != nil { return } c.Raw = tbsCertContents signed := tbsCertContents if hashFunc != 0 { h := hashFunc.New() h.Write(signed) signed = h.Sum(nil) } var signerOpts crypto.SignerOpts = hashFunc if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() { signerOpts = &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc, } } var signature []byte signature, err = key.Sign(rand, signed, signerOpts) if err != nil { return } return asn1.Marshal(certificate{ nil, c, signatureAlgorithm, asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } // pemCRLPrefix is the magic string that indicates that we have a PEM encoded // CRL. var pemCRLPrefix = []byte("-----BEGIN X509 CRL") // pemType is the type of a PEM encoded CRL. var pemType = "X509 CRL" // ParseCRL parses a CRL from the given bytes. It's often the case that PEM // encoded CRLs will appear where they should be DER encoded, so this function // will transparently handle PEM encoding as long as there isn't any leading // garbage. func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) { if bytes.HasPrefix(crlBytes, pemCRLPrefix) { block, _ := pem.Decode(crlBytes) if block != nil && block.Type == pemType { crlBytes = block.Bytes } } return ParseDERCRL(crlBytes) } // ParseDERCRL parses a DER encoded CRL from the given bytes. func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) { certList := new(pkix.CertificateList) if rest, err := asn1.Unmarshal(derBytes, certList); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after CRL") } return certList, nil } // CreateCRL returns a DER encoded CRL, signed by this Certificate, that // contains the given list of revoked certificates. func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { key, ok := priv.(crypto.Signer) if !ok { return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0) if err != nil { return nil, err } // Force revocation times to UTC per RFC 5280. revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts)) for i, rc := range revokedCerts { rc.RevocationTime = rc.RevocationTime.UTC() revokedCertsUTC[i] = rc } tbsCertList := pkix.TBSCertificateList{ Version: 1, Signature: signatureAlgorithm, Issuer: c.Subject.ToRDNSequence(), ThisUpdate: now.UTC(), NextUpdate: expiry.UTC(), RevokedCertificates: revokedCertsUTC, } // Authority Key Id if len(c.SubjectKeyId) > 0 { var aki pkix.Extension aki.Id = OIDExtensionAuthorityKeyId aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId}) if err != nil { return } tbsCertList.Extensions = append(tbsCertList.Extensions, aki) } tbsCertListContents, err := asn1.Marshal(tbsCertList) if err != nil { return } signed := tbsCertListContents if hashFunc != 0 { h := hashFunc.New() h.Write(signed) signed = h.Sum(nil) } var signature []byte signature, err = key.Sign(rand, signed, hashFunc) if err != nil { return } return asn1.Marshal(pkix.CertificateList{ TBSCertList: tbsCertList, SignatureAlgorithm: signatureAlgorithm, SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } // CertificateRequest represents a PKCS #10, certificate signature request. type CertificateRequest struct { Raw []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature). RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content. RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo. RawSubject []byte // DER encoded Subject. Version int Signature []byte SignatureAlgorithm SignatureAlgorithm PublicKeyAlgorithm PublicKeyAlgorithm PublicKey interface{} Subject pkix.Name // Attributes contains the CSR attributes that can parse as // pkix.AttributeTypeAndValueSET. // // Deprecated: Use Extensions and ExtraExtensions instead for parsing and // generating the requestedExtensions attribute. Attributes []pkix.AttributeTypeAndValueSET // Extensions contains all requested extensions, in raw form. When parsing // CSRs, this can be used to extract extensions that are not parsed by this // package. Extensions []pkix.Extension // ExtraExtensions contains extensions to be copied, raw, into any CSR // marshaled by CreateCertificateRequest. Values override any extensions // that would otherwise be produced based on the other fields but are // overridden by any extensions specified in Attributes. // // The ExtraExtensions field is not populated by ParseCertificateRequest, // see Extensions instead. ExtraExtensions []pkix.Extension // Subject Alternate Name values. DNSNames []string EmailAddresses []string IPAddresses []net.IP URIs []*url.URL } // These structures reflect the ASN.1 structure of X.509 certificate // signature requests (see RFC 2986): type tbsCertificateRequest struct { Raw asn1.RawContent Version int Subject asn1.RawValue PublicKey publicKeyInfo RawAttributes []asn1.RawValue `asn1:"tag:0"` } type certificateRequest struct { Raw asn1.RawContent TBSCSR tbsCertificateRequest SignatureAlgorithm pkix.AlgorithmIdentifier SignatureValue asn1.BitString } // oidExtensionRequest is a PKCS#9 OBJECT IDENTIFIER that indicates requested // extensions in a CSR. var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} // newRawAttributes converts AttributeTypeAndValueSETs from a template // CertificateRequest's Attributes into tbsCertificateRequest RawAttributes. func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) { var rawAttributes []asn1.RawValue b, err := asn1.Marshal(attributes) if err != nil { return nil, err } rest, err := asn1.Unmarshal(b, &rawAttributes) if err != nil { return nil, err } if len(rest) != 0 { return nil, errors.New("x509: failed to unmarshal raw CSR Attributes") } return rawAttributes, nil } // parseRawAttributes Unmarshals RawAttributes into AttributeTypeAndValueSETs. func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET { var attributes []pkix.AttributeTypeAndValueSET for _, rawAttr := range rawAttributes { var attr pkix.AttributeTypeAndValueSET rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr) // Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET // (i.e.: challengePassword or unstructuredName). if err == nil && len(rest) == 0 { attributes = append(attributes, attr) } } return attributes } // parseCSRExtensions parses the attributes from a CSR and extracts any // requested extensions. func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) { // pkcs10Attribute reflects the Attribute structure from RFC 2986, Section 4.1. type pkcs10Attribute struct { Id asn1.ObjectIdentifier Values []asn1.RawValue `asn1:"set"` } var ret []pkix.Extension for _, rawAttr := range rawAttributes { var attr pkcs10Attribute if rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr); err != nil || len(rest) != 0 || len(attr.Values) == 0 { // Ignore attributes that don't parse. continue } if !attr.Id.Equal(oidExtensionRequest) { continue } var extensions []pkix.Extension if _, err := asn1.Unmarshal(attr.Values[0].FullBytes, &extensions); err != nil { return nil, err } ret = append(ret, extensions...) } return ret, nil } // CreateCertificateRequest creates a new certificate request based on a // template. The following members of template are used: // // - SignatureAlgorithm // - Subject // - DNSNames // - EmailAddresses // - IPAddresses // - URIs // - ExtraExtensions // - Attributes (deprecated) // // priv is the private key to sign the CSR with, and the corresponding public // key will be included in the CSR. It must implement crypto.Signer and its // Public() method must return a *rsa.PublicKey or a *ecdsa.PublicKey or a // ed25519.PublicKey. (A *rsa.PrivateKey, *ecdsa.PrivateKey or // ed25519.PrivateKey satisfies this.) // // The returned slice is the certificate request in DER encoding. func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) { key, ok := priv.(crypto.Signer) if !ok { return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } var hashFunc crypto.Hash var sigAlgo pkix.AlgorithmIdentifier hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) if err != nil { return nil, err } var publicKeyBytes []byte var publicKeyAlgorithm pkix.AlgorithmIdentifier publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public()) if err != nil { return nil, err } var extensions []pkix.Extension if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) && !oidInExtensions(OIDExtensionSubjectAltName, template.ExtraExtensions) { sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs) if err != nil { return nil, err } extensions = append(extensions, pkix.Extension{ Id: OIDExtensionSubjectAltName, Value: sanBytes, }) } extensions = append(extensions, template.ExtraExtensions...) // Make a copy of template.Attributes because we may alter it below. attributes := make([]pkix.AttributeTypeAndValueSET, 0, len(template.Attributes)) for _, attr := range template.Attributes { values := make([][]pkix.AttributeTypeAndValue, len(attr.Value)) copy(values, attr.Value) attributes = append(attributes, pkix.AttributeTypeAndValueSET{ Type: attr.Type, Value: values, }) } extensionsAppended := false if len(extensions) > 0 { // Append the extensions to an existing attribute if possible. for _, atvSet := range attributes { if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 { continue } // specifiedExtensions contains all the extensions that we // found specified via template.Attributes. specifiedExtensions := make(map[string]bool) for _, atvs := range atvSet.Value { for _, atv := range atvs { specifiedExtensions[atv.Type.String()] = true } } newValue := make([]pkix.AttributeTypeAndValue, 0, len(atvSet.Value[0])+len(extensions)) newValue = append(newValue, atvSet.Value[0]...) for _, e := range extensions { if specifiedExtensions[e.Id.String()] { // Attributes already contained a value for // this extension and it takes priority. continue } newValue = append(newValue, pkix.AttributeTypeAndValue{ // There is no place for the critical // flag in an AttributeTypeAndValue. Type: e.Id, Value: e.Value, }) } atvSet.Value[0] = newValue extensionsAppended = true break } } rawAttributes, err := newRawAttributes(attributes) if err != nil { return } // If not included in attributes, add a new attribute for the // extensions. if len(extensions) > 0 && !extensionsAppended { attr := struct { Type asn1.ObjectIdentifier Value [][]pkix.Extension `asn1:"set"` }{ Type: oidExtensionRequest, Value: [][]pkix.Extension{extensions}, } b, err := asn1.Marshal(attr) if err != nil { return nil, errors.New("x509: failed to serialise extensions attribute: " + err.Error()) } var rawValue asn1.RawValue if _, err := asn1.Unmarshal(b, &rawValue); err != nil { return nil, err } rawAttributes = append(rawAttributes, rawValue) } asn1Subject := template.RawSubject if len(asn1Subject) == 0 { asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence()) if err != nil { return nil, err } } tbsCSR := tbsCertificateRequest{ Version: 0, // PKCS #10, RFC 2986 Subject: asn1.RawValue{FullBytes: asn1Subject}, PublicKey: publicKeyInfo{ Algorithm: publicKeyAlgorithm, PublicKey: asn1.BitString{ Bytes: publicKeyBytes, BitLength: len(publicKeyBytes) * 8, }, }, RawAttributes: rawAttributes, } tbsCSRContents, err := asn1.Marshal(tbsCSR) if err != nil { return } tbsCSR.Raw = tbsCSRContents signed := tbsCSRContents if hashFunc != 0 { h := hashFunc.New() h.Write(signed) signed = h.Sum(nil) } var signature []byte signature, err = key.Sign(rand, signed, hashFunc) if err != nil { return } return asn1.Marshal(certificateRequest{ TBSCSR: tbsCSR, SignatureAlgorithm: sigAlgo, SignatureValue: asn1.BitString{ Bytes: signature, BitLength: len(signature) * 8, }, }) } // ParseCertificateRequest parses a single certificate request from the // given ASN.1 DER data. func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) { var csr certificateRequest rest, err := asn1.Unmarshal(asn1Data, &csr) if err != nil { return nil, err } else if len(rest) != 0 { return nil, asn1.SyntaxError{Msg: "trailing data"} } return parseCertificateRequest(&csr) } func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) { out := &CertificateRequest{ Raw: in.Raw, RawTBSCertificateRequest: in.TBSCSR.Raw, RawSubjectPublicKeyInfo: in.TBSCSR.PublicKey.Raw, RawSubject: in.TBSCSR.Subject.FullBytes, Signature: in.SignatureValue.RightAlign(), SignatureAlgorithm: SignatureAlgorithmFromAI(in.SignatureAlgorithm), PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm), Version: in.TBSCSR.Version, Attributes: parseRawAttributes(in.TBSCSR.RawAttributes), } var err error var nfe NonFatalErrors out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCSR.PublicKey, &nfe) if err != nil { return nil, err } // Treat non-fatal errors as fatal here. if len(nfe.Errors) > 0 { return nil, nfe.Errors[0] } var subject pkix.RDNSequence if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 Subject") } out.Subject.FillFromRDNSequence(&subject) if out.Extensions, err = parseCSRExtensions(in.TBSCSR.RawAttributes); err != nil { return nil, err } for _, extension := range out.Extensions { if extension.Id.Equal(OIDExtensionSubjectAltName) { out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(extension.Value, &nfe) if err != nil { return nil, err } } } return out, nil } // CheckSignature reports whether the signature on c is valid. func (c *CertificateRequest) CheckSignature() error { return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey) } ================================================ FILE: vendor/github.com/jmhodges/clock/.travis.yml ================================================ language: go go: - 1.3 - 1.4 - 1.5 sudo: false ================================================ FILE: vendor/github.com/jmhodges/clock/LICENSE ================================================ The MIT License (MIT) Copyright © 2014 Jeff Hodges Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: vendor/github.com/jmhodges/clock/README.md ================================================ clock ==== [![GoDoc](https://img.shields.io/badge/pkg.go.dev-doc-blue)](http://pkg.go.dev/github.com/jmhodges/clock) Package clock provides an abstraction for system time that enables testing of time-sensitive code. Where you'd use `time.Now`, instead use `clk.Now` where `clk` is an instance of `clock.Clock`. When running your code in production, pass it a `Clock` given by `clock.Default()` and when you're running it in your tests, pass it an instance of `Clock` from `NewFake()`. When you do that, you can use `FakeClock`'s `Add` and `Set` methods to control how time behaves in your tests. That makes the tests you'll write more reliable while also expanding the space of problems you can test. This code intentionally does not attempt to provide an abstraction over `time.Ticker` and `time.Timer` because Go does not have the runtime or API hooks available to do so reliably. See https://github.com/golang/go/issues/8869 As with any use of `time`, be sure to test `Time` equality with `time.Time#Equal`, not `==`. For API documentation, see the [godoc](http://godoc.org/github.com/jmhodges/clock). ================================================ FILE: vendor/github.com/jmhodges/clock/clock.go ================================================ // Package clock provides an abstraction for system time that enables testing of // time-sensitive code. // // Where you'd use time.Now, instead use clk.Now where clk is an instance of // Clock. // // When running your code in production, pass it a Clock given by // clock.Default() and when you're running it in your tests, pass it an instance // of Clock from NewFake(). // // When you do that, you can use FakeClock's Add and Set methods to control how // time behaves in your tests. That makes the tests you'll write more reliable // while also expanding the space of problems you can test. // // This code intentionally does not attempt to provide an abstraction over // time.Ticker and time.Timer because Go does not have the runtime or API hooks // available to do so reliably. See https://github.com/golang/go/issues/8869 package clock import ( "sort" "sync" "time" ) // Some in-use reflection-heavy systems, like facebookgo/inject, fail when given // a value type like sysClock{}. Since it's hidden by an interface, this has // surprised users. We fixed that by making systemClock a &sysClock. var systemClock Clock = &sysClock{} // New returns a Clock that matches the actual system time. func New() Clock { // This is a method instead of a public var to prevent folks from // "making things work" by writing to the var instead of passing // in a Clock. return systemClock } // Deprecated: Default is just an alias for New but less memorable. func Default() Clock { return systemClock } // Clock is an abstraction over system time. New instances of it can // be made with Default and NewFake. type Clock interface { // Now returns the Clock's current view of the time. Mutating the // returned Time will not mutate the clock's time. Now() time.Time // Sleep causes the current goroutine to sleep for the given duration. Sleep(time.Duration) // After returns a channel that fires after the given duration. After(time.Duration) <-chan time.Time // Since is a short hand for Now().Sub(t). Since(time.Time) time.Duration // NewTimer makes a Timer based on this clock's time. Using Timers and // negative durations in the Clock or Timer API is undefined behavior and // may be changed. NewTimer(time.Duration) *Timer } type sysClock struct{} func (s *sysClock) Now() time.Time { return time.Now() } func (s *sysClock) Sleep(d time.Duration) { time.Sleep(d) } func (s *sysClock) After(d time.Duration) <-chan time.Time { return time.After(d) } func (s *sysClock) Since(t time.Time) time.Duration { return time.Since(t) } func (s *sysClock) NewTimer(d time.Duration) *Timer { tt := time.NewTimer(d) return &Timer{C: tt.C, timer: tt} } // NewFake returns a FakeClock to be used in tests that need to // manipulate time. Its initial value is always the unix epoch in the // UTC timezone. The FakeClock returned is thread-safe. func NewFake() FakeClock { // We're explicit about this time construction to avoid early user // questions about why the time object doesn't have a Location by // default. return &fake{t: time.Unix(0, 0).UTC()} } // FakeClock is a Clock with additional controls. The return value of // Now return can be modified with Add. Use NewFake to get a // thread-safe FakeClock implementation. type FakeClock interface { Clock // Adjust the time that will be returned by Now. Add(d time.Duration) // Set the Clock's time to exactly the time given. Set(t time.Time) } // To prevent mistakes with the API, we hide this behind NewFake. It's // easy forget to create a pointer to a fake since time.Time (and // sync.Mutex) are also simple values. The code will appear to work // but the clock's time will never be adjusted. type fake struct { sync.RWMutex t time.Time sends sortedSends } func (f *fake) Now() time.Time { f.RLock() defer f.RUnlock() return f.t } func (f *fake) Sleep(d time.Duration) { if d < 0 { // time.Sleep just returns immediately. Do the same. return } f.Add(d) } func (f *fake) After(d time.Duration) <-chan time.Time { return f.NewTimer(d).C } func (f *fake) Since(t time.Time) time.Duration { return f.Now().Sub(t) } func (f *fake) NewTimer(d time.Duration) *Timer { f.Lock() defer f.Unlock() ch := make(chan time.Time, 1) tt := f.t.Add(d) ft := &fakeTimer{c: ch, clk: f, active: true} t := &Timer{ C: ch, fakeTimer: ft, } s := f.addSend(tt, ft) ft.sends = []*send{s} return t } func (f *fake) Add(d time.Duration) { f.Lock() defer f.Unlock() f.t = f.t.Add(d) f.sendTimes() } func (f *fake) Set(t time.Time) { f.Lock() defer f.Unlock() f.t = t f.sendTimes() } // Only to be called while the fake's lock is held func (f *fake) sendTimes() { newSends := make(sortedSends, 0) for _, s := range f.sends { if !s.active || !s.ft.active { continue } if s.target.Equal(f.t) || s.target.Before(f.t) { s.ft.active = false s.active = false // The select is to drop second sends from resets without a user // receiving from ft.c. select { case s.ft.c <- s.target: default: } } if s.active { newSends = append(newSends, s) } } f.sends = newSends } // Only to be called while the fake's lock is held func (f *fake) addSend(target time.Time, ft *fakeTimer) *send { s := &send{target: target, ft: ft, active: true} f.sends = append(f.sends, s) // This will be a small enough slice to be fast. Can be replaced with a more // complicated container if someone is making many timers. sort.Sort(f.sends) return s } // send is a struct that represents a scheduled send of a time.Time to its // fakeTimer's channel. They are actually sent when the relevant fake's time // goes equal or past their target time, as long as the relevant fakeTimer has // not been Reset or Stop'ed. When a Timer is Reset, the old sends are // deactivated and will be removed from the clocks list on the next attempt to // send. type send struct { target time.Time active bool ft *fakeTimer } type sortedSends []*send func (s sortedSends) Len() int { return len(s) } func (s sortedSends) Less(i, j int) bool { return s[i].target.Before(s[j].target) } func (s sortedSends) Swap(i, j int) { s[i], s[j] = s[j], s[i] } ================================================ FILE: vendor/github.com/jmhodges/clock/timer.go ================================================ package clock import "time" type Timer struct { C <-chan time.Time timer *time.Timer fakeTimer *fakeTimer } func (t *Timer) Reset(d time.Duration) bool { if t.timer != nil { return t.timer.Reset(d) } return t.fakeTimer.Reset(d) } func (t *Timer) Stop() bool { if t.timer != nil { return t.timer.Stop() } return t.fakeTimer.Stop() } type fakeTimer struct { // c is the same chan as C in the Timer that contains this fakeTimer c chan<- time.Time // clk is kept so we can maintain just one lock and to add and attempt to // send the times made by this timer during Resets and Stops clk *fake // active is true until the fakeTimer's send is attempted or it has been // stopped active bool // sends is where we store all the sends made by this timer so we can // deactivate the old ones when Reset or Stop is called. sends []*send } func (ft *fakeTimer) Reset(d time.Duration) bool { ft.clk.Lock() defer ft.clk.Unlock() target := ft.clk.t.Add(d) active := ft.active ft.active = true for _, s := range ft.sends { s.active = false } s := ft.clk.addSend(target, ft) ft.sends = []*send{s} ft.clk.sendTimes() return active } func (ft *fakeTimer) Stop() bool { ft.clk.Lock() defer ft.clk.Unlock() active := ft.active ft.active = false for _, s := range ft.sends { s.active = false } ft.sends = nil ft.clk.sendTimes() return active } ================================================ FILE: vendor/github.com/jmoiron/sqlx/.gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test .idea # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe tags environ ================================================ FILE: vendor/github.com/jmoiron/sqlx/.travis.yml ================================================ # vim: ft=yaml sw=2 ts=2 language: go # enable database services services: - mysql - postgresql # create test database before_install: - mysql -e 'CREATE DATABASE IF NOT EXISTS sqlxtest;' - psql -c 'create database sqlxtest;' -U postgres - go get github.com/mattn/goveralls - export SQLX_MYSQL_DSN="travis:@/sqlxtest?parseTime=true" - export SQLX_POSTGRES_DSN="postgres://postgres:@localhost/sqlxtest?sslmode=disable" - export SQLX_SQLITE_DSN="$HOME/sqlxtest.db" # go versions to test go: - "1.15.x" - "1.16.x" # run tests w/ coverage script: - travis_retry $GOPATH/bin/goveralls -service=travis-ci ================================================ FILE: vendor/github.com/jmoiron/sqlx/LICENSE ================================================ Copyright (c) 2013, Jason Moiron Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: vendor/github.com/jmoiron/sqlx/README.md ================================================ # sqlx [![Build Status](https://travis-ci.org/jmoiron/sqlx.svg?branch=master)](https://travis-ci.org/jmoiron/sqlx) [![Coverage Status](https://coveralls.io/repos/github/jmoiron/sqlx/badge.svg?branch=master)](https://coveralls.io/github/jmoiron/sqlx?branch=master) [![Godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/jmoiron/sqlx) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/jmoiron/sqlx/master/LICENSE) sqlx is a library which provides a set of extensions on go's standard `database/sql` library. The sqlx versions of `sql.DB`, `sql.TX`, `sql.Stmt`, et al. all leave the underlying interfaces untouched, so that their interfaces are a superset on the standard ones. This makes it relatively painless to integrate existing codebases using database/sql with sqlx. Major additional concepts are: * Marshal rows into structs (with embedded struct support), maps, and slices * Named parameter support including prepared statements * `Get` and `Select` to go quickly from query to struct/slice In addition to the [godoc API documentation](http://godoc.org/github.com/jmoiron/sqlx), there is also some [user documentation](http://jmoiron.github.io/sqlx/) that explains how to use `database/sql` along with sqlx. ## Recent Changes 1.3.0: * `sqlx.DB.Connx(context.Context) *sqlx.Conn` * `sqlx.BindDriver(driverName, bindType)` * support for `[]map[string]interface{}` to do "batch" insertions * allocation & perf improvements for `sqlx.In` DB.Connx returns an `sqlx.Conn`, which is an `sql.Conn`-alike consistent with sqlx's wrapping of other types. `BindDriver` allows users to control the bindvars that sqlx will use for drivers, and add new drivers at runtime. This results in a very slight performance hit when resolving the driver into a bind type (~40ns per call), but it allows users to specify what bindtype their driver uses even when sqlx has not been updated to know about it by default. ### Backwards Compatibility Compatibility with the most recent two versions of Go is a requirement for any new changes. Compatibility beyond that is not guaranteed. Versioning is done with Go modules. Breaking changes (eg. removing deprecated API) will get major version number bumps. ## install go get github.com/jmoiron/sqlx ## issues Row headers can be ambiguous (`SELECT 1 AS a, 2 AS a`), and the result of `Columns()` does not fully qualify column names in queries like: ```sql SELECT a.id, a.name, b.id, b.name FROM foos AS a JOIN foos AS b ON a.parent = b.id; ``` making a struct or map destination ambiguous. Use `AS` in your queries to give columns distinct names, `rows.Scan` to scan them manually, or `SliceScan` to get a slice of results. ## usage Below is an example which shows some common use cases for sqlx. Check [sqlx_test.go](https://github.com/jmoiron/sqlx/blob/master/sqlx_test.go) for more usage. ```go package main import ( "database/sql" "fmt" "log" _ "github.com/lib/pq" "github.com/jmoiron/sqlx" ) var schema = ` CREATE TABLE person ( first_name text, last_name text, email text ); CREATE TABLE place ( country text, city text NULL, telcode integer )` type Person struct { FirstName string `db:"first_name"` LastName string `db:"last_name"` Email string } type Place struct { Country string City sql.NullString TelCode int } func main() { // this Pings the database trying to connect // use sqlx.Open() for sql.Open() semantics db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable") if err != nil { log.Fatalln(err) } // exec the schema or fail; multi-statement Exec behavior varies between // database drivers; pq will exec them all, sqlite3 won't, ymmv db.MustExec(schema) tx := db.MustBegin() tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "Jason", "Moiron", "jmoiron@jmoiron.net") tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "John", "Doe", "johndoeDNE@gmail.net") tx.MustExec("INSERT INTO place (country, city, telcode) VALUES ($1, $2, $3)", "United States", "New York", "1") tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Hong Kong", "852") tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Singapore", "65") // Named queries can use structs, so if you have an existing struct (i.e. person := &Person{}) that you have populated, you can pass it in as &person tx.NamedExec("INSERT INTO person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)", &Person{"Jane", "Citizen", "jane.citzen@example.com"}) tx.Commit() // Query the database, storing results in a []Person (wrapped in []interface{}) people := []Person{} db.Select(&people, "SELECT * FROM person ORDER BY first_name ASC") jason, john := people[0], people[1] fmt.Printf("%#v\n%#v", jason, john) // Person{FirstName:"Jason", LastName:"Moiron", Email:"jmoiron@jmoiron.net"} // Person{FirstName:"John", LastName:"Doe", Email:"johndoeDNE@gmail.net"} // You can also get a single result, a la QueryRow jason = Person{} err = db.Get(&jason, "SELECT * FROM person WHERE first_name=$1", "Jason") fmt.Printf("%#v\n", jason) // Person{FirstName:"Jason", LastName:"Moiron", Email:"jmoiron@jmoiron.net"} // if you have null fields and use SELECT *, you must use sql.Null* in your struct places := []Place{} err = db.Select(&places, "SELECT * FROM place ORDER BY telcode ASC") if err != nil { fmt.Println(err) return } usa, singsing, honkers := places[0], places[1], places[2] fmt.Printf("%#v\n%#v\n%#v\n", usa, singsing, honkers) // Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1} // Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65} // Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852} // Loop through rows using only one struct place := Place{} rows, err := db.Queryx("SELECT * FROM place") for rows.Next() { err := rows.StructScan(&place) if err != nil { log.Fatalln(err) } fmt.Printf("%#v\n", place) } // Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1} // Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852} // Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65} // Named queries, using `:name` as the bindvar. Automatic bindvar support // which takes into account the dbtype based on the driverName on sqlx.Open/Connect _, err = db.NamedExec(`INSERT INTO person (first_name,last_name,email) VALUES (:first,:last,:email)`, map[string]interface{}{ "first": "Bin", "last": "Smuth", "email": "bensmith@allblacks.nz", }) // Selects Mr. Smith from the database rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:fn`, map[string]interface{}{"fn": "Bin"}) // Named queries can also use structs. Their bind names follow the same rules // as the name -> db mapping, so struct fields are lowercased and the `db` tag // is taken into consideration. rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:first_name`, jason) // batch insert // batch insert with structs personStructs := []Person{ {FirstName: "Ardie", LastName: "Savea", Email: "asavea@ab.co.nz"}, {FirstName: "Sonny Bill", LastName: "Williams", Email: "sbw@ab.co.nz"}, {FirstName: "Ngani", LastName: "Laumape", Email: "nlaumape@ab.co.nz"}, } _, err = db.NamedExec(`INSERT INTO person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)`, personStructs) // batch insert with maps personMaps := []map[string]interface{}{ {"first_name": "Ardie", "last_name": "Savea", "email": "asavea@ab.co.nz"}, {"first_name": "Sonny Bill", "last_name": "Williams", "email": "sbw@ab.co.nz"}, {"first_name": "Ngani", "last_name": "Laumape", "email": "nlaumape@ab.co.nz"}, } _, err = db.NamedExec(`INSERT INTO person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)`, personMaps) } ``` ================================================ FILE: vendor/github.com/jmoiron/sqlx/bind.go ================================================ package sqlx import ( "bytes" "database/sql/driver" "errors" "reflect" "strconv" "strings" "sync" "github.com/jmoiron/sqlx/reflectx" ) // Bindvar types supported by Rebind, BindMap and BindStruct. const ( UNKNOWN = iota QUESTION DOLLAR NAMED AT ) var defaultBinds = map[int][]string{ DOLLAR: []string{"postgres", "pgx", "pq-timeouts", "cloudsqlpostgres", "ql", "nrpostgres", "cockroach"}, QUESTION: []string{"mysql", "sqlite3", "nrmysql", "nrsqlite3"}, NAMED: []string{"oci8", "ora", "goracle", "godror"}, AT: []string{"sqlserver"}, } var binds sync.Map func init() { for bind, drivers := range defaultBinds { for _, driver := range drivers { BindDriver(driver, bind) } } } // BindType returns the bindtype for a given database given a drivername. func BindType(driverName string) int { itype, ok := binds.Load(driverName) if !ok { return UNKNOWN } return itype.(int) } // BindDriver sets the BindType for driverName to bindType. func BindDriver(driverName string, bindType int) { binds.Store(driverName, bindType) } // FIXME: this should be able to be tolerant of escaped ?'s in queries without // losing much speed, and should be to avoid confusion. // Rebind a query from the default bindtype (QUESTION) to the target bindtype. func Rebind(bindType int, query string) string { switch bindType { case QUESTION, UNKNOWN: return query } // Add space enough for 10 params before we have to allocate rqb := make([]byte, 0, len(query)+10) var i, j int for i = strings.Index(query, "?"); i != -1; i = strings.Index(query, "?") { rqb = append(rqb, query[:i]...) switch bindType { case DOLLAR: rqb = append(rqb, '$') case NAMED: rqb = append(rqb, ':', 'a', 'r', 'g') case AT: rqb = append(rqb, '@', 'p') } j++ rqb = strconv.AppendInt(rqb, int64(j), 10) query = query[i+1:] } return string(append(rqb, query...)) } // Experimental implementation of Rebind which uses a bytes.Buffer. The code is // much simpler and should be more resistant to odd unicode, but it is twice as // slow. Kept here for benchmarking purposes and to possibly replace Rebind if // problems arise with its somewhat naive handling of unicode. func rebindBuff(bindType int, query string) string { if bindType != DOLLAR { return query } b := make([]byte, 0, len(query)) rqb := bytes.NewBuffer(b) j := 1 for _, r := range query { if r == '?' { rqb.WriteRune('$') rqb.WriteString(strconv.Itoa(j)) j++ } else { rqb.WriteRune(r) } } return rqb.String() } func asSliceForIn(i interface{}) (v reflect.Value, ok bool) { if i == nil { return reflect.Value{}, false } v = reflect.ValueOf(i) t := reflectx.Deref(v.Type()) // Only expand slices if t.Kind() != reflect.Slice { return reflect.Value{}, false } // []byte is a driver.Value type so it should not be expanded if t == reflect.TypeOf([]byte{}) { return reflect.Value{}, false } return v, true } // In expands slice values in args, returning the modified query string // and a new arg list that can be executed by a database. The `query` should // use the `?` bindVar. The return value uses the `?` bindVar. func In(query string, args ...interface{}) (string, []interface{}, error) { // argMeta stores reflect.Value and length for slices and // the value itself for non-slice arguments type argMeta struct { v reflect.Value i interface{} length int } var flatArgsCount int var anySlices bool var stackMeta [32]argMeta var meta []argMeta if len(args) <= len(stackMeta) { meta = stackMeta[:len(args)] } else { meta = make([]argMeta, len(args)) } for i, arg := range args { if a, ok := arg.(driver.Valuer); ok { var err error arg, err = a.Value() if err != nil { return "", nil, err } } if v, ok := asSliceForIn(arg); ok { meta[i].length = v.Len() meta[i].v = v anySlices = true flatArgsCount += meta[i].length if meta[i].length == 0 { return "", nil, errors.New("empty slice passed to 'in' query") } } else { meta[i].i = arg flatArgsCount++ } } // don't do any parsing if there aren't any slices; note that this means // some errors that we might have caught below will not be returned. if !anySlices { return query, args, nil } newArgs := make([]interface{}, 0, flatArgsCount) var buf strings.Builder buf.Grow(len(query) + len(", ?")*flatArgsCount) var arg, offset int for i := strings.IndexByte(query[offset:], '?'); i != -1; i = strings.IndexByte(query[offset:], '?') { if arg >= len(meta) { // if an argument wasn't passed, lets return an error; this is // not actually how database/sql Exec/Query works, but since we are // creating an argument list programmatically, we want to be able // to catch these programmer errors earlier. return "", nil, errors.New("number of bindVars exceeds arguments") } argMeta := meta[arg] arg++ // not a slice, continue. // our questionmark will either be written before the next expansion // of a slice or after the loop when writing the rest of the query if argMeta.length == 0 { offset = offset + i + 1 newArgs = append(newArgs, argMeta.i) continue } // write everything up to and including our ? character buf.WriteString(query[:offset+i+1]) for si := 1; si < argMeta.length; si++ { buf.WriteString(", ?") } newArgs = appendReflectSlice(newArgs, argMeta.v, argMeta.length) // slice the query and reset the offset. this avoids some bookkeeping for // the write after the loop query = query[offset+i+1:] offset = 0 } buf.WriteString(query) if arg < len(meta) { return "", nil, errors.New("number of bindVars less than number arguments") } return buf.String(), newArgs, nil } func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interface{} { switch val := v.Interface().(type) { case []interface{}: args = append(args, val...) case []int: for i := range val { args = append(args, val[i]) } case []string: for i := range val { args = append(args, val[i]) } default: for si := 0; si < vlen; si++ { args = append(args, v.Index(si).Interface()) } } return args } ================================================ FILE: vendor/github.com/jmoiron/sqlx/doc.go ================================================ // Package sqlx provides general purpose extensions to database/sql. // // It is intended to seamlessly wrap database/sql and provide convenience // methods which are useful in the development of database driven applications. // None of the underlying database/sql methods are changed. Instead all extended // behavior is implemented through new methods defined on wrapper types. // // Additions include scanning into structs, named query support, rebinding // queries for different drivers, convenient shorthands for common error handling // and more. // package sqlx ================================================ FILE: vendor/github.com/jmoiron/sqlx/named.go ================================================ package sqlx // Named Query Support // // * BindMap - bind query bindvars to map/struct args // * NamedExec, NamedQuery - named query w/ struct or map // * NamedStmt - a pre-compiled named query which is a prepared statement // // Internal Interfaces: // // * compileNamedQuery - rebind a named query, returning a query and list of names // * bindArgs, bindMapArgs, bindAnyArgs - given a list of names, return an arglist // import ( "bytes" "database/sql" "errors" "fmt" "reflect" "regexp" "strconv" "unicode" "github.com/jmoiron/sqlx/reflectx" ) // NamedStmt is a prepared statement that executes named queries. Prepare it // how you would execute a NamedQuery, but pass in a struct or map when executing. type NamedStmt struct { Params []string QueryString string Stmt *Stmt } // Close closes the named statement. func (n *NamedStmt) Close() error { return n.Stmt.Close() } // Exec executes a named statement using the struct passed. // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) Exec(arg interface{}) (sql.Result, error) { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return *new(sql.Result), err } return n.Stmt.Exec(args...) } // Query executes a named statement using the struct argument, returning rows. // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) Query(arg interface{}) (*sql.Rows, error) { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return nil, err } return n.Stmt.Query(args...) } // QueryRow executes a named statement against the database. Because sqlx cannot // create a *sql.Row with an error condition pre-set for binding errors, sqlx // returns a *sqlx.Row instead. // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) QueryRow(arg interface{}) *Row { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return &Row{err: err} } return n.Stmt.QueryRowx(args...) } // MustExec execs a NamedStmt, panicing on error // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) MustExec(arg interface{}) sql.Result { res, err := n.Exec(arg) if err != nil { panic(err) } return res } // Queryx using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) Queryx(arg interface{}) (*Rows, error) { r, err := n.Query(arg) if err != nil { return nil, err } return &Rows{Rows: r, Mapper: n.Stmt.Mapper, unsafe: isUnsafe(n)}, err } // QueryRowx this NamedStmt. Because of limitations with QueryRow, this is // an alias for QueryRow. // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) QueryRowx(arg interface{}) *Row { return n.QueryRow(arg) } // Select using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) Select(dest interface{}, arg interface{}) error { rows, err := n.Queryx(arg) if err != nil { return err } // if something happens here, we want to make sure the rows are Closed defer rows.Close() return scanAll(rows, dest, false) } // Get using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) Get(dest interface{}, arg interface{}) error { r := n.QueryRowx(arg) return r.scanAny(dest, false) } // Unsafe creates an unsafe version of the NamedStmt func (n *NamedStmt) Unsafe() *NamedStmt { r := &NamedStmt{Params: n.Params, Stmt: n.Stmt, QueryString: n.QueryString} r.Stmt.unsafe = true return r } // A union interface of preparer and binder, required to be able to prepare // named statements (as the bindtype must be determined). type namedPreparer interface { Preparer binder } func prepareNamed(p namedPreparer, query string) (*NamedStmt, error) { bindType := BindType(p.DriverName()) q, args, err := compileNamedQuery([]byte(query), bindType) if err != nil { return nil, err } stmt, err := Preparex(p, q) if err != nil { return nil, err } return &NamedStmt{ QueryString: q, Params: args, Stmt: stmt, }, nil } // convertMapStringInterface attempts to convert v to map[string]interface{}. // Unlike v.(map[string]interface{}), this function works on named types that // are convertible to map[string]interface{} as well. func convertMapStringInterface(v interface{}) (map[string]interface{}, bool) { var m map[string]interface{} mtype := reflect.TypeOf(m) t := reflect.TypeOf(v) if !t.ConvertibleTo(mtype) { return nil, false } return reflect.ValueOf(v).Convert(mtype).Interface().(map[string]interface{}), true } func bindAnyArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) { if maparg, ok := convertMapStringInterface(arg); ok { return bindMapArgs(names, maparg) } return bindArgs(names, arg, m) } // private interface to generate a list of interfaces from a given struct // type, given a list of names to pull out of the struct. Used by public // BindStruct interface. func bindArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) { arglist := make([]interface{}, 0, len(names)) // grab the indirected value of arg v := reflect.ValueOf(arg) for v = reflect.ValueOf(arg); v.Kind() == reflect.Ptr; { v = v.Elem() } err := m.TraversalsByNameFunc(v.Type(), names, func(i int, t []int) error { if len(t) == 0 { return fmt.Errorf("could not find name %s in %#v", names[i], arg) } val := reflectx.FieldByIndexesReadOnly(v, t) arglist = append(arglist, val.Interface()) return nil }) return arglist, err } // like bindArgs, but for maps. func bindMapArgs(names []string, arg map[string]interface{}) ([]interface{}, error) { arglist := make([]interface{}, 0, len(names)) for _, name := range names { val, ok := arg[name] if !ok { return arglist, fmt.Errorf("could not find name %s in %#v", name, arg) } arglist = append(arglist, val) } return arglist, nil } // bindStruct binds a named parameter query with fields from a struct argument. // The rules for binding field names to parameter names follow the same // conventions as for StructScan, including obeying the `db` struct tags. func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) { bound, names, err := compileNamedQuery([]byte(query), bindType) if err != nil { return "", []interface{}{}, err } arglist, err := bindAnyArgs(names, arg, m) if err != nil { return "", []interface{}{}, err } return bound, arglist, nil } var valuesReg = regexp.MustCompile(`\)\s*(?i)VALUES\s*\(`) func findMatchingClosingBracketIndex(s string) int { count := 0 for i, ch := range s { if ch == '(' { count++ } if ch == ')' { count-- if count == 0 { return i } } } return 0 } func fixBound(bound string, loop int) string { loc := valuesReg.FindStringIndex(bound) // defensive guard when "VALUES (...)" not found if len(loc) < 2 { return bound } openingBracketIndex := loc[1] - 1 index := findMatchingClosingBracketIndex(bound[openingBracketIndex:]) // defensive guard. must have closing bracket if index == 0 { return bound } closingBracketIndex := openingBracketIndex + index + 1 var buffer bytes.Buffer buffer.WriteString(bound[0:closingBracketIndex]) for i := 0; i < loop-1; i++ { buffer.WriteString(",") buffer.WriteString(bound[openingBracketIndex:closingBracketIndex]) } buffer.WriteString(bound[closingBracketIndex:]) return buffer.String() } // bindArray binds a named parameter query with fields from an array or slice of // structs argument. func bindArray(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) { // do the initial binding with QUESTION; if bindType is not question, // we can rebind it at the end. bound, names, err := compileNamedQuery([]byte(query), QUESTION) if err != nil { return "", []interface{}{}, err } arrayValue := reflect.ValueOf(arg) arrayLen := arrayValue.Len() if arrayLen == 0 { return "", []interface{}{}, fmt.Errorf("length of array is 0: %#v", arg) } var arglist = make([]interface{}, 0, len(names)*arrayLen) for i := 0; i < arrayLen; i++ { elemArglist, err := bindAnyArgs(names, arrayValue.Index(i).Interface(), m) if err != nil { return "", []interface{}{}, err } arglist = append(arglist, elemArglist...) } if arrayLen > 1 { bound = fixBound(bound, arrayLen) } // adjust binding type if we weren't on question if bindType != QUESTION { bound = Rebind(bindType, bound) } return bound, arglist, nil } // bindMap binds a named parameter query with a map of arguments. func bindMap(bindType int, query string, args map[string]interface{}) (string, []interface{}, error) { bound, names, err := compileNamedQuery([]byte(query), bindType) if err != nil { return "", []interface{}{}, err } arglist, err := bindMapArgs(names, args) return bound, arglist, err } // -- Compilation of Named Queries // Allow digits and letters in bind params; additionally runes are // checked against underscores, meaning that bind params can have be // alphanumeric with underscores. Mind the difference between unicode // digits and numbers, where '5' is a digit but '五' is not. var allowedBindRunes = []*unicode.RangeTable{unicode.Letter, unicode.Digit} // FIXME: this function isn't safe for unicode named params, as a failing test // can testify. This is not a regression but a failure of the original code // as well. It should be modified to range over runes in a string rather than // bytes, even though this is less convenient and slower. Hopefully the // addition of the prepared NamedStmt (which will only do this once) will make // up for the slightly slower ad-hoc NamedExec/NamedQuery. // compile a NamedQuery into an unbound query (using the '?' bindvar) and // a list of names. func compileNamedQuery(qs []byte, bindType int) (query string, names []string, err error) { names = make([]string, 0, 10) rebound := make([]byte, 0, len(qs)) inName := false last := len(qs) - 1 currentVar := 1 name := make([]byte, 0, 10) for i, b := range qs { // a ':' while we're in a name is an error if b == ':' { // if this is the second ':' in a '::' escape sequence, append a ':' if inName && i > 0 && qs[i-1] == ':' { rebound = append(rebound, ':') inName = false continue } else if inName { err = errors.New("unexpected `:` while reading named param at " + strconv.Itoa(i)) return query, names, err } inName = true name = []byte{} } else if inName && i > 0 && b == '=' && len(name) == 0 { rebound = append(rebound, ':', '=') inName = false continue // if we're in a name, and this is an allowed character, continue } else if inName && (unicode.IsOneOf(allowedBindRunes, rune(b)) || b == '_' || b == '.') && i != last { // append the byte to the name if we are in a name and not on the last byte name = append(name, b) // if we're in a name and it's not an allowed character, the name is done } else if inName { inName = false // if this is the final byte of the string and it is part of the name, then // make sure to add it to the name if i == last && unicode.IsOneOf(allowedBindRunes, rune(b)) { name = append(name, b) } // add the string representation to the names list names = append(names, string(name)) // add a proper bindvar for the bindType switch bindType { // oracle only supports named type bind vars even for positional case NAMED: rebound = append(rebound, ':') rebound = append(rebound, name...) case QUESTION, UNKNOWN: rebound = append(rebound, '?') case DOLLAR: rebound = append(rebound, '$') for _, b := range strconv.Itoa(currentVar) { rebound = append(rebound, byte(b)) } currentVar++ case AT: rebound = append(rebound, '@', 'p') for _, b := range strconv.Itoa(currentVar) { rebound = append(rebound, byte(b)) } currentVar++ } // add this byte to string unless it was not part of the name if i != last { rebound = append(rebound, b) } else if !unicode.IsOneOf(allowedBindRunes, rune(b)) { rebound = append(rebound, b) } } else { // this is a normal byte and should just go onto the rebound query rebound = append(rebound, b) } } return string(rebound), names, err } // BindNamed binds a struct or a map to a query with named parameters. // DEPRECATED: use sqlx.Named` instead of this, it may be removed in future. func BindNamed(bindType int, query string, arg interface{}) (string, []interface{}, error) { return bindNamedMapper(bindType, query, arg, mapper()) } // Named takes a query using named parameters and an argument and // returns a new query with a list of args that can be executed by // a database. The return value uses the `?` bindvar. func Named(query string, arg interface{}) (string, []interface{}, error) { return bindNamedMapper(QUESTION, query, arg, mapper()) } func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) { t := reflect.TypeOf(arg) k := t.Kind() switch { case k == reflect.Map && t.Key().Kind() == reflect.String: m, ok := convertMapStringInterface(arg) if !ok { return "", nil, fmt.Errorf("sqlx.bindNamedMapper: unsupported map type: %T", arg) } return bindMap(bindType, query, m) case k == reflect.Array || k == reflect.Slice: return bindArray(bindType, query, arg, m) default: return bindStruct(bindType, query, arg, m) } } // NamedQuery binds a named query and then runs Query on the result using the // provided Ext (sqlx.Tx, sqlx.Db). It works with both structs and with // map[string]interface{} types. func NamedQuery(e Ext, query string, arg interface{}) (*Rows, error) { q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e)) if err != nil { return nil, err } return e.Queryx(q, args...) } // NamedExec uses BindStruct to get a query executable by the driver and // then runs Exec on the result. Returns an error from the binding // or the query execution itself. func NamedExec(e Ext, query string, arg interface{}) (sql.Result, error) { q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e)) if err != nil { return nil, err } return e.Exec(q, args...) } ================================================ FILE: vendor/github.com/jmoiron/sqlx/named_context.go ================================================ // +build go1.8 package sqlx import ( "context" "database/sql" ) // A union interface of contextPreparer and binder, required to be able to // prepare named statements with context (as the bindtype must be determined). type namedPreparerContext interface { PreparerContext binder } func prepareNamedContext(ctx context.Context, p namedPreparerContext, query string) (*NamedStmt, error) { bindType := BindType(p.DriverName()) q, args, err := compileNamedQuery([]byte(query), bindType) if err != nil { return nil, err } stmt, err := PreparexContext(ctx, p, q) if err != nil { return nil, err } return &NamedStmt{ QueryString: q, Params: args, Stmt: stmt, }, nil } // ExecContext executes a named statement using the struct passed. // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) ExecContext(ctx context.Context, arg interface{}) (sql.Result, error) { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return *new(sql.Result), err } return n.Stmt.ExecContext(ctx, args...) } // QueryContext executes a named statement using the struct argument, returning rows. // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) QueryContext(ctx context.Context, arg interface{}) (*sql.Rows, error) { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return nil, err } return n.Stmt.QueryContext(ctx, args...) } // QueryRowContext executes a named statement against the database. Because sqlx cannot // create a *sql.Row with an error condition pre-set for binding errors, sqlx // returns a *sqlx.Row instead. // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) QueryRowContext(ctx context.Context, arg interface{}) *Row { args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper) if err != nil { return &Row{err: err} } return n.Stmt.QueryRowxContext(ctx, args...) } // MustExecContext execs a NamedStmt, panicing on error // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) MustExecContext(ctx context.Context, arg interface{}) sql.Result { res, err := n.ExecContext(ctx, arg) if err != nil { panic(err) } return res } // QueryxContext using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) QueryxContext(ctx context.Context, arg interface{}) (*Rows, error) { r, err := n.QueryContext(ctx, arg) if err != nil { return nil, err } return &Rows{Rows: r, Mapper: n.Stmt.Mapper, unsafe: isUnsafe(n)}, err } // QueryRowxContext this NamedStmt. Because of limitations with QueryRow, this is // an alias for QueryRow. // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) QueryRowxContext(ctx context.Context, arg interface{}) *Row { return n.QueryRowContext(ctx, arg) } // SelectContext using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) SelectContext(ctx context.Context, dest interface{}, arg interface{}) error { rows, err := n.QueryxContext(ctx, arg) if err != nil { return err } // if something happens here, we want to make sure the rows are Closed defer rows.Close() return scanAll(rows, dest, false) } // GetContext using this NamedStmt // Any named placeholder parameters are replaced with fields from arg. func (n *NamedStmt) GetContext(ctx context.Context, dest interface{}, arg interface{}) error { r := n.QueryRowxContext(ctx, arg) return r.scanAny(dest, false) } // NamedQueryContext binds a named query and then runs Query on the result using the // provided Ext (sqlx.Tx, sqlx.Db). It works with both structs and with // map[string]interface{} types. func NamedQueryContext(ctx context.Context, e ExtContext, query string, arg interface{}) (*Rows, error) { q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e)) if err != nil { return nil, err } return e.QueryxContext(ctx, q, args...) } // NamedExecContext uses BindStruct to get a query executable by the driver and // then runs Exec on the result. Returns an error from the binding // or the query execution itself. func NamedExecContext(ctx context.Context, e ExtContext, query string, arg interface{}) (sql.Result, error) { q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e)) if err != nil { return nil, err } return e.ExecContext(ctx, q, args...) } ================================================ FILE: vendor/github.com/jmoiron/sqlx/reflectx/README.md ================================================ # reflectx The sqlx package has special reflect needs. In particular, it needs to: * be able to map a name to a field * understand embedded structs * understand mapping names to fields by a particular tag * user specified name -> field mapping functions These behaviors mimic the behaviors by the standard library marshallers and also the behavior of standard Go accessors. The first two are amply taken care of by `Reflect.Value.FieldByName`, and the third is addressed by `Reflect.Value.FieldByNameFunc`, but these don't quite understand struct tags in the ways that are vital to most marshallers, and they are slow. This reflectx package extends reflect to achieve these goals. ================================================ FILE: vendor/github.com/jmoiron/sqlx/reflectx/reflect.go ================================================ // Package reflectx implements extensions to the standard reflect lib suitable // for implementing marshalling and unmarshalling packages. The main Mapper type // allows for Go-compatible named attribute access, including accessing embedded // struct attributes and the ability to use functions and struct tags to // customize field names. // package reflectx import ( "reflect" "runtime" "strings" "sync" ) // A FieldInfo is metadata for a struct field. type FieldInfo struct { Index []int Path string Field reflect.StructField Zero reflect.Value Name string Options map[string]string Embedded bool Children []*FieldInfo Parent *FieldInfo } // A StructMap is an index of field metadata for a struct. type StructMap struct { Tree *FieldInfo Index []*FieldInfo Paths map[string]*FieldInfo Names map[string]*FieldInfo } // GetByPath returns a *FieldInfo for a given string path. func (f StructMap) GetByPath(path string) *FieldInfo { return f.Paths[path] } // GetByTraversal returns a *FieldInfo for a given integer path. It is // analogous to reflect.FieldByIndex, but using the cached traversal // rather than re-executing the reflect machinery each time. func (f StructMap) GetByTraversal(index []int) *FieldInfo { if len(index) == 0 { return nil } tree := f.Tree for _, i := range index { if i >= len(tree.Children) || tree.Children[i] == nil { return nil } tree = tree.Children[i] } return tree } // Mapper is a general purpose mapper of names to struct fields. A Mapper // behaves like most marshallers in the standard library, obeying a field tag // for name mapping but also providing a basic transform function. type Mapper struct { cache map[reflect.Type]*StructMap tagName string tagMapFunc func(string) string mapFunc func(string) string mutex sync.Mutex } // NewMapper returns a new mapper using the tagName as its struct field tag. // If tagName is the empty string, it is ignored. func NewMapper(tagName string) *Mapper { return &Mapper{ cache: make(map[reflect.Type]*StructMap), tagName: tagName, } } // NewMapperTagFunc returns a new mapper which contains a mapper for field names // AND a mapper for tag values. This is useful for tags like json which can // have values like "name,omitempty". func NewMapperTagFunc(tagName string, mapFunc, tagMapFunc func(string) string) *Mapper { return &Mapper{ cache: make(map[reflect.Type]*StructMap), tagName: tagName, mapFunc: mapFunc, tagMapFunc: tagMapFunc, } } // NewMapperFunc returns a new mapper which optionally obeys a field tag and // a struct field name mapper func given by f. Tags will take precedence, but // for any other field, the mapped name will be f(field.Name) func NewMapperFunc(tagName string, f func(string) string) *Mapper { return &Mapper{ cache: make(map[reflect.Type]*StructMap), tagName: tagName, mapFunc: f, } } // TypeMap returns a mapping of field strings to int slices representing // the traversal down the struct to reach the field. func (m *Mapper) TypeMap(t reflect.Type) *StructMap { m.mutex.Lock() mapping, ok := m.cache[t] if !ok { mapping = getMapping(t, m.tagName, m.mapFunc, m.tagMapFunc) m.cache[t] = mapping } m.mutex.Unlock() return mapping } // FieldMap returns the mapper's mapping of field names to reflect values. Panics // if v's Kind is not Struct, or v is not Indirectable to a struct kind. func (m *Mapper) FieldMap(v reflect.Value) map[string]reflect.Value { v = reflect.Indirect(v) mustBe(v, reflect.Struct) r := map[string]reflect.Value{} tm := m.TypeMap(v.Type()) for tagName, fi := range tm.Names { r[tagName] = FieldByIndexes(v, fi.Index) } return r } // FieldByName returns a field by its mapped name as a reflect.Value. // Panics if v's Kind is not Struct or v is not Indirectable to a struct Kind. // Returns zero Value if the name is not found. func (m *Mapper) FieldByName(v reflect.Value, name string) reflect.Value { v = reflect.Indirect(v) mustBe(v, reflect.Struct) tm := m.TypeMap(v.Type()) fi, ok := tm.Names[name] if !ok { return v } return FieldByIndexes(v, fi.Index) } // FieldsByName returns a slice of values corresponding to the slice of names // for the value. Panics if v's Kind is not Struct or v is not Indirectable // to a struct Kind. Returns zero Value for each name not found. func (m *Mapper) FieldsByName(v reflect.Value, names []string) []reflect.Value { v = reflect.Indirect(v) mustBe(v, reflect.Struct) tm := m.TypeMap(v.Type()) vals := make([]reflect.Value, 0, len(names)) for _, name := range names { fi, ok := tm.Names[name] if !ok { vals = append(vals, *new(reflect.Value)) } else { vals = append(vals, FieldByIndexes(v, fi.Index)) } } return vals } // TraversalsByName returns a slice of int slices which represent the struct // traversals for each mapped name. Panics if t is not a struct or Indirectable // to a struct. Returns empty int slice for each name not found. func (m *Mapper) TraversalsByName(t reflect.Type, names []string) [][]int { r := make([][]int, 0, len(names)) m.TraversalsByNameFunc(t, names, func(_ int, i []int) error { if i == nil { r = append(r, []int{}) } else { r = append(r, i) } return nil }) return r } // TraversalsByNameFunc traverses the mapped names and calls fn with the index of // each name and the struct traversal represented by that name. Panics if t is not // a struct or Indirectable to a struct. Returns the first error returned by fn or nil. func (m *Mapper) TraversalsByNameFunc(t reflect.Type, names []string, fn func(int, []int) error) error { t = Deref(t) mustBe(t, reflect.Struct) tm := m.TypeMap(t) for i, name := range names { fi, ok := tm.Names[name] if !ok { if err := fn(i, nil); err != nil { return err } } else { if err := fn(i, fi.Index); err != nil { return err } } } return nil } // FieldByIndexes returns a value for the field given by the struct traversal // for the given value. func FieldByIndexes(v reflect.Value, indexes []int) reflect.Value { for _, i := range indexes { v = reflect.Indirect(v).Field(i) // if this is a pointer and it's nil, allocate a new value and set it if v.Kind() == reflect.Ptr && v.IsNil() { alloc := reflect.New(Deref(v.Type())) v.Set(alloc) } if v.Kind() == reflect.Map && v.IsNil() { v.Set(reflect.MakeMap(v.Type())) } } return v } // FieldByIndexesReadOnly returns a value for a particular struct traversal, // but is not concerned with allocating nil pointers because the value is // going to be used for reading and not setting. func FieldByIndexesReadOnly(v reflect.Value, indexes []int) reflect.Value { for _, i := range indexes { v = reflect.Indirect(v).Field(i) } return v } // Deref is Indirect for reflect.Types func Deref(t reflect.Type) reflect.Type { if t.Kind() == reflect.Ptr { t = t.Elem() } return t } // -- helpers & utilities -- type kinder interface { Kind() reflect.Kind } // mustBe checks a value against a kind, panicing with a reflect.ValueError // if the kind isn't that which is required. func mustBe(v kinder, expected reflect.Kind) { if k := v.Kind(); k != expected { panic(&reflect.ValueError{Method: methodName(), Kind: k}) } } // methodName returns the caller of the function calling methodName func methodName() string { pc, _, _, _ := runtime.Caller(2) f := runtime.FuncForPC(pc) if f == nil { return "unknown method" } return f.Name() } type typeQueue struct { t reflect.Type fi *FieldInfo pp string // Parent path } // A copying append that creates a new slice each time. func apnd(is []int, i int) []int { x := make([]int, len(is)+1) copy(x, is) x[len(x)-1] = i return x } type mapf func(string) string // parseName parses the tag and the target name for the given field using // the tagName (eg 'json' for `json:"foo"` tags), mapFunc for mapping the // field's name to a target name, and tagMapFunc for mapping the tag to // a target name. func parseName(field reflect.StructField, tagName string, mapFunc, tagMapFunc mapf) (tag, fieldName string) { // first, set the fieldName to the field's name fieldName = field.Name // if a mapFunc is set, use that to override the fieldName if mapFunc != nil { fieldName = mapFunc(fieldName) } // if there's no tag to look for, return the field name if tagName == "" { return "", fieldName } // if this tag is not set using the normal convention in the tag, // then return the fieldname.. this check is done because according // to the reflect documentation: // If the tag does not have the conventional format, // the value returned by Get is unspecified. // which doesn't sound great. if !strings.Contains(string(field.Tag), tagName+":") { return "", fieldName } // at this point we're fairly sure that we have a tag, so lets pull it out tag = field.Tag.Get(tagName) // if we have a mapper function, call it on the whole tag // XXX: this is a change from the old version, which pulled out the name // before the tagMapFunc could be run, but I think this is the right way if tagMapFunc != nil { tag = tagMapFunc(tag) } // finally, split the options from the name parts := strings.Split(tag, ",") fieldName = parts[0] return tag, fieldName } // parseOptions parses options out of a tag string, skipping the name func parseOptions(tag string) map[string]string { parts := strings.Split(tag, ",") options := make(map[string]string, len(parts)) if len(parts) > 1 { for _, opt := range parts[1:] { // short circuit potentially expensive split op if strings.Contains(opt, "=") { kv := strings.Split(opt, "=") options[kv[0]] = kv[1] continue } options[opt] = "" } } return options } // getMapping returns a mapping for the t type, using the tagName, mapFunc and // tagMapFunc to determine the canonical names of fields. func getMapping(t reflect.Type, tagName string, mapFunc, tagMapFunc mapf) *StructMap { m := []*FieldInfo{} root := &FieldInfo{} queue := []typeQueue{} queue = append(queue, typeQueue{Deref(t), root, ""}) QueueLoop: for len(queue) != 0 { // pop the first item off of the queue tq := queue[0] queue = queue[1:] // ignore recursive field for p := tq.fi.Parent; p != nil; p = p.Parent { if tq.fi.Field.Type == p.Field.Type { continue QueueLoop } } nChildren := 0 if tq.t.Kind() == reflect.Struct { nChildren = tq.t.NumField() } tq.fi.Children = make([]*FieldInfo, nChildren) // iterate through all of its fields for fieldPos := 0; fieldPos < nChildren; fieldPos++ { f := tq.t.Field(fieldPos) // parse the tag and the target name using the mapping options for this field tag, name := parseName(f, tagName, mapFunc, tagMapFunc) // if the name is "-", disabled via a tag, skip it if name == "-" { continue } fi := FieldInfo{ Field: f, Name: name, Zero: reflect.New(f.Type).Elem(), Options: parseOptions(tag), } // if the path is empty this path is just the name if tq.pp == "" { fi.Path = fi.Name } else { fi.Path = tq.pp + "." + fi.Name } // skip unexported fields if len(f.PkgPath) != 0 && !f.Anonymous { continue } // bfs search of anonymous embedded structs if f.Anonymous { pp := tq.pp if tag != "" { pp = fi.Path } fi.Embedded = true fi.Index = apnd(tq.fi.Index, fieldPos) nChildren := 0 ft := Deref(f.Type) if ft.Kind() == reflect.Struct { nChildren = ft.NumField() } fi.Children = make([]*FieldInfo, nChildren) queue = append(queue, typeQueue{Deref(f.Type), &fi, pp}) } else if fi.Zero.Kind() == reflect.Struct || (fi.Zero.Kind() == reflect.Ptr && fi.Zero.Type().Elem().Kind() == reflect.Struct) { fi.Index = apnd(tq.fi.Index, fieldPos) fi.Children = make([]*FieldInfo, Deref(f.Type).NumField()) queue = append(queue, typeQueue{Deref(f.Type), &fi, fi.Path}) } fi.Index = apnd(tq.fi.Index, fieldPos) fi.Parent = tq.fi tq.fi.Children[fieldPos] = &fi m = append(m, &fi) } } flds := &StructMap{Index: m, Tree: root, Paths: map[string]*FieldInfo{}, Names: map[string]*FieldInfo{}} for _, fi := range flds.Index { // check if nothing has already been pushed with the same path // sometimes you can choose to override a type using embedded struct fld, ok := flds.Paths[fi.Path] if !ok || fld.Embedded { flds.Paths[fi.Path] = fi if fi.Name != "" && !fi.Embedded { flds.Names[fi.Path] = fi } } } return flds } ================================================ FILE: vendor/github.com/jmoiron/sqlx/sqlx.go ================================================ package sqlx import ( "database/sql" "database/sql/driver" "errors" "fmt" "io/ioutil" "path/filepath" "reflect" "strings" "sync" "github.com/jmoiron/sqlx/reflectx" ) // Although the NameMapper is convenient, in practice it should not // be relied on except for application code. If you are writing a library // that uses sqlx, you should be aware that the name mappings you expect // can be overridden by your user's application. // NameMapper is used to map column names to struct field names. By default, // it uses strings.ToLower to lowercase struct field names. It can be set // to whatever you want, but it is encouraged to be set before sqlx is used // as name-to-field mappings are cached after first use on a type. var NameMapper = strings.ToLower var origMapper = reflect.ValueOf(NameMapper) // Rather than creating on init, this is created when necessary so that // importers have time to customize the NameMapper. var mpr *reflectx.Mapper // mprMu protects mpr. var mprMu sync.Mutex // mapper returns a valid mapper using the configured NameMapper func. func mapper() *reflectx.Mapper { mprMu.Lock() defer mprMu.Unlock() if mpr == nil { mpr = reflectx.NewMapperFunc("db", NameMapper) } else if origMapper != reflect.ValueOf(NameMapper) { // if NameMapper has changed, create a new mapper mpr = reflectx.NewMapperFunc("db", NameMapper) origMapper = reflect.ValueOf(NameMapper) } return mpr } // isScannable takes the reflect.Type and the actual dest value and returns // whether or not it's Scannable. Something is scannable if: // * it is not a struct // * it implements sql.Scanner // * it has no exported fields func isScannable(t reflect.Type) bool { if reflect.PtrTo(t).Implements(_scannerInterface) { return true } if t.Kind() != reflect.Struct { return true } // it's not important that we use the right mapper for this particular object, // we're only concerned on how many exported fields this struct has return len(mapper().TypeMap(t).Index) == 0 } // ColScanner is an interface used by MapScan and SliceScan type ColScanner interface { Columns() ([]string, error) Scan(dest ...interface{}) error Err() error } // Queryer is an interface used by Get and Select type Queryer interface { Query(query string, args ...interface{}) (*sql.Rows, error) Queryx(query string, args ...interface{}) (*Rows, error) QueryRowx(query string, args ...interface{}) *Row } // Execer is an interface used by MustExec and LoadFile type Execer interface { Exec(query string, args ...interface{}) (sql.Result, error) } // Binder is an interface for something which can bind queries (Tx, DB) type binder interface { DriverName() string Rebind(string) string BindNamed(string, interface{}) (string, []interface{}, error) } // Ext is a union interface which can bind, query, and exec, used by // NamedQuery and NamedExec. type Ext interface { binder Queryer Execer } // Preparer is an interface used by Preparex. type Preparer interface { Prepare(query string) (*sql.Stmt, error) } // determine if any of our extensions are unsafe func isUnsafe(i interface{}) bool { switch v := i.(type) { case Row: return v.unsafe case *Row: return v.unsafe case Rows: return v.unsafe case *Rows: return v.unsafe case NamedStmt: return v.Stmt.unsafe case *NamedStmt: return v.Stmt.unsafe case Stmt: return v.unsafe case *Stmt: return v.unsafe case qStmt: return v.unsafe case *qStmt: return v.unsafe case DB: return v.unsafe case *DB: return v.unsafe case Tx: return v.unsafe case *Tx: return v.unsafe case sql.Rows, *sql.Rows: return false default: return false } } func mapperFor(i interface{}) *reflectx.Mapper { switch i := i.(type) { case DB: return i.Mapper case *DB: return i.Mapper case Tx: return i.Mapper case *Tx: return i.Mapper default: return mapper() } } var _scannerInterface = reflect.TypeOf((*sql.Scanner)(nil)).Elem() var _valuerInterface = reflect.TypeOf((*driver.Valuer)(nil)).Elem() // Row is a reimplementation of sql.Row in order to gain access to the underlying // sql.Rows.Columns() data, necessary for StructScan. type Row struct { err error unsafe bool rows *sql.Rows Mapper *reflectx.Mapper } // Scan is a fixed implementation of sql.Row.Scan, which does not discard the // underlying error from the internal rows object if it exists. func (r *Row) Scan(dest ...interface{}) error { if r.err != nil { return r.err } // TODO(bradfitz): for now we need to defensively clone all // []byte that the driver returned (not permitting // *RawBytes in Rows.Scan), since we're about to close // the Rows in our defer, when we return from this function. // the contract with the driver.Next(...) interface is that it // can return slices into read-only temporary memory that's // only valid until the next Scan/Close. But the TODO is that // for a lot of drivers, this copy will be unnecessary. We // should provide an optional interface for drivers to // implement to say, "don't worry, the []bytes that I return // from Next will not be modified again." (for instance, if // they were obtained from the network anyway) But for now we // don't care. defer r.rows.Close() for _, dp := range dest { if _, ok := dp.(*sql.RawBytes); ok { return errors.New("sql: RawBytes isn't allowed on Row.Scan") } } if !r.rows.Next() { if err := r.rows.Err(); err != nil { return err } return sql.ErrNoRows } err := r.rows.Scan(dest...) if err != nil { return err } // Make sure the query can be processed to completion with no errors. if err := r.rows.Close(); err != nil { return err } return nil } // Columns returns the underlying sql.Rows.Columns(), or the deferred error usually // returned by Row.Scan() func (r *Row) Columns() ([]string, error) { if r.err != nil { return []string{}, r.err } return r.rows.Columns() } // ColumnTypes returns the underlying sql.Rows.ColumnTypes(), or the deferred error func (r *Row) ColumnTypes() ([]*sql.ColumnType, error) { if r.err != nil { return []*sql.ColumnType{}, r.err } return r.rows.ColumnTypes() } // Err returns the error encountered while scanning. func (r *Row) Err() error { return r.err } // DB is a wrapper around sql.DB which keeps track of the driverName upon Open, // used mostly to automatically bind named queries using the right bindvars. type DB struct { *sql.DB driverName string unsafe bool Mapper *reflectx.Mapper } // NewDb returns a new sqlx DB wrapper for a pre-existing *sql.DB. The // driverName of the original database is required for named query support. func NewDb(db *sql.DB, driverName string) *DB { return &DB{DB: db, driverName: driverName, Mapper: mapper()} } // DriverName returns the driverName passed to the Open function for this DB. func (db *DB) DriverName() string { return db.driverName } // Open is the same as sql.Open, but returns an *sqlx.DB instead. func Open(driverName, dataSourceName string) (*DB, error) { db, err := sql.Open(driverName, dataSourceName) if err != nil { return nil, err } return &DB{DB: db, driverName: driverName, Mapper: mapper()}, err } // MustOpen is the same as sql.Open, but returns an *sqlx.DB instead and panics on error. func MustOpen(driverName, dataSourceName string) *DB { db, err := Open(driverName, dataSourceName) if err != nil { panic(err) } return db } // MapperFunc sets a new mapper for this db using the default sqlx struct tag // and the provided mapper function. func (db *DB) MapperFunc(mf func(string) string) { db.Mapper = reflectx.NewMapperFunc("db", mf) } // Rebind transforms a query from QUESTION to the DB driver's bindvar type. func (db *DB) Rebind(query string) string { return Rebind(BindType(db.driverName), query) } // Unsafe returns a version of DB which will silently succeed to scan when // columns in the SQL result have no fields in the destination struct. // sqlx.Stmt and sqlx.Tx which are created from this DB will inherit its // safety behavior. func (db *DB) Unsafe() *DB { return &DB{DB: db.DB, driverName: db.driverName, unsafe: true, Mapper: db.Mapper} } // BindNamed binds a query using the DB driver's bindvar type. func (db *DB) BindNamed(query string, arg interface{}) (string, []interface{}, error) { return bindNamedMapper(BindType(db.driverName), query, arg, db.Mapper) } // NamedQuery using this DB. // Any named placeholder parameters are replaced with fields from arg. func (db *DB) NamedQuery(query string, arg interface{}) (*Rows, error) { return NamedQuery(db, query, arg) } // NamedExec using this DB. // Any named placeholder parameters are replaced with fields from arg. func (db *DB) NamedExec(query string, arg interface{}) (sql.Result, error) { return NamedExec(db, query, arg) } // Select using this DB. // Any placeholder parameters are replaced with supplied args. func (db *DB) Select(dest interface{}, query string, args ...interface{}) error { return Select(db, dest, query, args...) } // Get using this DB. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. func (db *DB) Get(dest interface{}, query string, args ...interface{}) error { return Get(db, dest, query, args...) } // MustBegin starts a transaction, and panics on error. Returns an *sqlx.Tx instead // of an *sql.Tx. func (db *DB) MustBegin() *Tx { tx, err := db.Beginx() if err != nil { panic(err) } return tx } // Beginx begins a transaction and returns an *sqlx.Tx instead of an *sql.Tx. func (db *DB) Beginx() (*Tx, error) { tx, err := db.DB.Begin() if err != nil { return nil, err } return &Tx{Tx: tx, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, err } // Queryx queries the database and returns an *sqlx.Rows. // Any placeholder parameters are replaced with supplied args. func (db *DB) Queryx(query string, args ...interface{}) (*Rows, error) { r, err := db.DB.Query(query, args...) if err != nil { return nil, err } return &Rows{Rows: r, unsafe: db.unsafe, Mapper: db.Mapper}, err } // QueryRowx queries the database and returns an *sqlx.Row. // Any placeholder parameters are replaced with supplied args. func (db *DB) QueryRowx(query string, args ...interface{}) *Row { rows, err := db.DB.Query(query, args...) return &Row{rows: rows, err: err, unsafe: db.unsafe, Mapper: db.Mapper} } // MustExec (panic) runs MustExec using this database. // Any placeholder parameters are replaced with supplied args. func (db *DB) MustExec(query string, args ...interface{}) sql.Result { return MustExec(db, query, args...) } // Preparex returns an sqlx.Stmt instead of a sql.Stmt func (db *DB) Preparex(query string) (*Stmt, error) { return Preparex(db, query) } // PrepareNamed returns an sqlx.NamedStmt func (db *DB) PrepareNamed(query string) (*NamedStmt, error) { return prepareNamed(db, query) } // Conn is a wrapper around sql.Conn with extra functionality type Conn struct { *sql.Conn driverName string unsafe bool Mapper *reflectx.Mapper } // Tx is an sqlx wrapper around sql.Tx with extra functionality type Tx struct { *sql.Tx driverName string unsafe bool Mapper *reflectx.Mapper } // DriverName returns the driverName used by the DB which began this transaction. func (tx *Tx) DriverName() string { return tx.driverName } // Rebind a query within a transaction's bindvar type. func (tx *Tx) Rebind(query string) string { return Rebind(BindType(tx.driverName), query) } // Unsafe returns a version of Tx which will silently succeed to scan when // columns in the SQL result have no fields in the destination struct. func (tx *Tx) Unsafe() *Tx { return &Tx{Tx: tx.Tx, driverName: tx.driverName, unsafe: true, Mapper: tx.Mapper} } // BindNamed binds a query within a transaction's bindvar type. func (tx *Tx) BindNamed(query string, arg interface{}) (string, []interface{}, error) { return bindNamedMapper(BindType(tx.driverName), query, arg, tx.Mapper) } // NamedQuery within a transaction. // Any named placeholder parameters are replaced with fields from arg. func (tx *Tx) NamedQuery(query string, arg interface{}) (*Rows, error) { return NamedQuery(tx, query, arg) } // NamedExec a named query within a transaction. // Any named placeholder parameters are replaced with fields from arg. func (tx *Tx) NamedExec(query string, arg interface{}) (sql.Result, error) { return NamedExec(tx, query, arg) } // Select within a transaction. // Any placeholder parameters are replaced with supplied args. func (tx *Tx) Select(dest interface{}, query string, args ...interface{}) error { return Select(tx, dest, query, args...) } // Queryx within a transaction. // Any placeholder parameters are replaced with supplied args. func (tx *Tx) Queryx(query string, args ...interface{}) (*Rows, error) { r, err := tx.Tx.Query(query, args...) if err != nil { return nil, err } return &Rows{Rows: r, unsafe: tx.unsafe, Mapper: tx.Mapper}, err } // QueryRowx within a transaction. // Any placeholder parameters are replaced with supplied args. func (tx *Tx) QueryRowx(query string, args ...interface{}) *Row { rows, err := tx.Tx.Query(query, args...) return &Row{rows: rows, err: err, unsafe: tx.unsafe, Mapper: tx.Mapper} } // Get within a transaction. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. func (tx *Tx) Get(dest interface{}, query string, args ...interface{}) error { return Get(tx, dest, query, args...) } // MustExec runs MustExec within a transaction. // Any placeholder parameters are replaced with supplied args. func (tx *Tx) MustExec(query string, args ...interface{}) sql.Result { return MustExec(tx, query, args...) } // Preparex a statement within a transaction. func (tx *Tx) Preparex(query string) (*Stmt, error) { return Preparex(tx, query) } // Stmtx returns a version of the prepared statement which runs within a transaction. Provided // stmt can be either *sql.Stmt or *sqlx.Stmt. func (tx *Tx) Stmtx(stmt interface{}) *Stmt { var s *sql.Stmt switch v := stmt.(type) { case Stmt: s = v.Stmt case *Stmt: s = v.Stmt case *sql.Stmt: s = v default: panic(fmt.Sprintf("non-statement type %v passed to Stmtx", reflect.ValueOf(stmt).Type())) } return &Stmt{Stmt: tx.Stmt(s), Mapper: tx.Mapper} } // NamedStmt returns a version of the prepared statement which runs within a transaction. func (tx *Tx) NamedStmt(stmt *NamedStmt) *NamedStmt { return &NamedStmt{ QueryString: stmt.QueryString, Params: stmt.Params, Stmt: tx.Stmtx(stmt.Stmt), } } // PrepareNamed returns an sqlx.NamedStmt func (tx *Tx) PrepareNamed(query string) (*NamedStmt, error) { return prepareNamed(tx, query) } // Stmt is an sqlx wrapper around sql.Stmt with extra functionality type Stmt struct { *sql.Stmt unsafe bool Mapper *reflectx.Mapper } // Unsafe returns a version of Stmt which will silently succeed to scan when // columns in the SQL result have no fields in the destination struct. func (s *Stmt) Unsafe() *Stmt { return &Stmt{Stmt: s.Stmt, unsafe: true, Mapper: s.Mapper} } // Select using the prepared statement. // Any placeholder parameters are replaced with supplied args. func (s *Stmt) Select(dest interface{}, args ...interface{}) error { return Select(&qStmt{s}, dest, "", args...) } // Get using the prepared statement. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. func (s *Stmt) Get(dest interface{}, args ...interface{}) error { return Get(&qStmt{s}, dest, "", args...) } // MustExec (panic) using this statement. Note that the query portion of the error // output will be blank, as Stmt does not expose its query. // Any placeholder parameters are replaced with supplied args. func (s *Stmt) MustExec(args ...interface{}) sql.Result { return MustExec(&qStmt{s}, "", args...) } // QueryRowx using this statement. // Any placeholder parameters are replaced with supplied args. func (s *Stmt) QueryRowx(args ...interface{}) *Row { qs := &qStmt{s} return qs.QueryRowx("", args...) } // Queryx using this statement. // Any placeholder parameters are replaced with supplied args. func (s *Stmt) Queryx(args ...interface{}) (*Rows, error) { qs := &qStmt{s} return qs.Queryx("", args...) } // qStmt is an unexposed wrapper which lets you use a Stmt as a Queryer & Execer by // implementing those interfaces and ignoring the `query` argument. type qStmt struct{ *Stmt } func (q *qStmt) Query(query string, args ...interface{}) (*sql.Rows, error) { return q.Stmt.Query(args...) } func (q *qStmt) Queryx(query string, args ...interface{}) (*Rows, error) { r, err := q.Stmt.Query(args...) if err != nil { return nil, err } return &Rows{Rows: r, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}, err } func (q *qStmt) QueryRowx(query string, args ...interface{}) *Row { rows, err := q.Stmt.Query(args...) return &Row{rows: rows, err: err, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper} } func (q *qStmt) Exec(query string, args ...interface{}) (sql.Result, error) { return q.Stmt.Exec(args...) } // Rows is a wrapper around sql.Rows which caches costly reflect operations // during a looped StructScan type Rows struct { *sql.Rows unsafe bool Mapper *reflectx.Mapper // these fields cache memory use for a rows during iteration w/ structScan started bool fields [][]int values []interface{} } // SliceScan using this Rows. func (r *Rows) SliceScan() ([]interface{}, error) { return SliceScan(r) } // MapScan using this Rows. func (r *Rows) MapScan(dest map[string]interface{}) error { return MapScan(r, dest) } // StructScan is like sql.Rows.Scan, but scans a single Row into a single Struct. // Use this and iterate over Rows manually when the memory load of Select() might be // prohibitive. *Rows.StructScan caches the reflect work of matching up column // positions to fields to avoid that overhead per scan, which means it is not safe // to run StructScan on the same Rows instance with different struct types. func (r *Rows) StructScan(dest interface{}) error { v := reflect.ValueOf(dest) if v.Kind() != reflect.Ptr { return errors.New("must pass a pointer, not a value, to StructScan destination") } v = v.Elem() if !r.started { columns, err := r.Columns() if err != nil { return err } m := r.Mapper r.fields = m.TraversalsByName(v.Type(), columns) // if we are not unsafe and are missing fields, return an error if f, err := missingFields(r.fields); err != nil && !r.unsafe { return fmt.Errorf("missing destination name %s in %T", columns[f], dest) } r.values = make([]interface{}, len(columns)) r.started = true } err := fieldsByTraversal(v, r.fields, r.values, true) if err != nil { return err } // scan into the struct field pointers and append to our results err = r.Scan(r.values...) if err != nil { return err } return r.Err() } // Connect to a database and verify with a ping. func Connect(driverName, dataSourceName string) (*DB, error) { db, err := Open(driverName, dataSourceName) if err != nil { return nil, err } err = db.Ping() if err != nil { db.Close() return nil, err } return db, nil } // MustConnect connects to a database and panics on error. func MustConnect(driverName, dataSourceName string) *DB { db, err := Connect(driverName, dataSourceName) if err != nil { panic(err) } return db } // Preparex prepares a statement. func Preparex(p Preparer, query string) (*Stmt, error) { s, err := p.Prepare(query) if err != nil { return nil, err } return &Stmt{Stmt: s, unsafe: isUnsafe(p), Mapper: mapperFor(p)}, err } // Select executes a query using the provided Queryer, and StructScans each row // into dest, which must be a slice. If the slice elements are scannable, then // the result set must have only one column. Otherwise, StructScan is used. // The *sql.Rows are closed automatically. // Any placeholder parameters are replaced with supplied args. func Select(q Queryer, dest interface{}, query string, args ...interface{}) error { rows, err := q.Queryx(query, args...) if err != nil { return err } // if something happens here, we want to make sure the rows are Closed defer rows.Close() return scanAll(rows, dest, false) } // Get does a QueryRow using the provided Queryer, and scans the resulting row // to dest. If dest is scannable, the result must only have one column. Otherwise, // StructScan is used. Get will return sql.ErrNoRows like row.Scan would. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. func Get(q Queryer, dest interface{}, query string, args ...interface{}) error { r := q.QueryRowx(query, args...) return r.scanAny(dest, false) } // LoadFile exec's every statement in a file (as a single call to Exec). // LoadFile may return a nil *sql.Result if errors are encountered locating or // reading the file at path. LoadFile reads the entire file into memory, so it // is not suitable for loading large data dumps, but can be useful for initializing // schemas or loading indexes. // // FIXME: this does not really work with multi-statement files for mattn/go-sqlite3 // or the go-mysql-driver/mysql drivers; pq seems to be an exception here. Detecting // this by requiring something with DriverName() and then attempting to split the // queries will be difficult to get right, and its current driver-specific behavior // is deemed at least not complex in its incorrectness. func LoadFile(e Execer, path string) (*sql.Result, error) { realpath, err := filepath.Abs(path) if err != nil { return nil, err } contents, err := ioutil.ReadFile(realpath) if err != nil { return nil, err } res, err := e.Exec(string(contents)) return &res, err } // MustExec execs the query using e and panics if there was an error. // Any placeholder parameters are replaced with supplied args. func MustExec(e Execer, query string, args ...interface{}) sql.Result { res, err := e.Exec(query, args...) if err != nil { panic(err) } return res } // SliceScan using this Rows. func (r *Row) SliceScan() ([]interface{}, error) { return SliceScan(r) } // MapScan using this Rows. func (r *Row) MapScan(dest map[string]interface{}) error { return MapScan(r, dest) } func (r *Row) scanAny(dest interface{}, structOnly bool) error { if r.err != nil { return r.err } if r.rows == nil { r.err = sql.ErrNoRows return r.err } defer r.rows.Close() v := reflect.ValueOf(dest) if v.Kind() != reflect.Ptr { return errors.New("must pass a pointer, not a value, to StructScan destination") } if v.IsNil() { return errors.New("nil pointer passed to StructScan destination") } base := reflectx.Deref(v.Type()) scannable := isScannable(base) if structOnly && scannable { return structOnlyError(base) } columns, err := r.Columns() if err != nil { return err } if scannable && len(columns) > 1 { return fmt.Errorf("scannable dest type %s with >1 columns (%d) in result", base.Kind(), len(columns)) } if scannable { return r.Scan(dest) } m := r.Mapper fields := m.TraversalsByName(v.Type(), columns) // if we are not unsafe and are missing fields, return an error if f, err := missingFields(fields); err != nil && !r.unsafe { return fmt.Errorf("missing destination name %s in %T", columns[f], dest) } values := make([]interface{}, len(columns)) err = fieldsByTraversal(v, fields, values, true) if err != nil { return err } // scan into the struct field pointers and append to our results return r.Scan(values...) } // StructScan a single Row into dest. func (r *Row) StructScan(dest interface{}) error { return r.scanAny(dest, true) } // SliceScan a row, returning a []interface{} with values similar to MapScan. // This function is primarily intended for use where the number of columns // is not known. Because you can pass an []interface{} directly to Scan, // it's recommended that you do that as it will not have to allocate new // slices per row. func SliceScan(r ColScanner) ([]interface{}, error) { // ignore r.started, since we needn't use reflect for anything. columns, err := r.Columns() if err != nil { return []interface{}{}, err } values := make([]interface{}, len(columns)) for i := range values { values[i] = new(interface{}) } err = r.Scan(values...) if err != nil { return values, err } for i := range columns { values[i] = *(values[i].(*interface{})) } return values, r.Err() } // MapScan scans a single Row into the dest map[string]interface{}. // Use this to get results for SQL that might not be under your control // (for instance, if you're building an interface for an SQL server that // executes SQL from input). Please do not use this as a primary interface! // This will modify the map sent to it in place, so reuse the same map with // care. Columns which occur more than once in the result will overwrite // each other! func MapScan(r ColScanner, dest map[string]interface{}) error { // ignore r.started, since we needn't use reflect for anything. columns, err := r.Columns() if err != nil { return err } values := make([]interface{}, len(columns)) for i := range values { values[i] = new(interface{}) } err = r.Scan(values...) if err != nil { return err } for i, column := range columns { dest[column] = *(values[i].(*interface{})) } return r.Err() } type rowsi interface { Close() error Columns() ([]string, error) Err() error Next() bool Scan(...interface{}) error } // structOnlyError returns an error appropriate for type when a non-scannable // struct is expected but something else is given func structOnlyError(t reflect.Type) error { isStruct := t.Kind() == reflect.Struct isScanner := reflect.PtrTo(t).Implements(_scannerInterface) if !isStruct { return fmt.Errorf("expected %s but got %s", reflect.Struct, t.Kind()) } if isScanner { return fmt.Errorf("structscan expects a struct dest but the provided struct type %s implements scanner", t.Name()) } return fmt.Errorf("expected a struct, but struct %s has no exported fields", t.Name()) } // scanAll scans all rows into a destination, which must be a slice of any // type. It resets the slice length to zero before appending each element to // the slice. If the destination slice type is a Struct, then StructScan will // be used on each row. If the destination is some other kind of base type, // then each row must only have one column which can scan into that type. This // allows you to do something like: // // rows, _ := db.Query("select id from people;") // var ids []int // scanAll(rows, &ids, false) // // and ids will be a list of the id results. I realize that this is a desirable // interface to expose to users, but for now it will only be exposed via changes // to `Get` and `Select`. The reason that this has been implemented like this is // this is the only way to not duplicate reflect work in the new API while // maintaining backwards compatibility. func scanAll(rows rowsi, dest interface{}, structOnly bool) error { var v, vp reflect.Value value := reflect.ValueOf(dest) // json.Unmarshal returns errors for these if value.Kind() != reflect.Ptr { return errors.New("must pass a pointer, not a value, to StructScan destination") } if value.IsNil() { return errors.New("nil pointer passed to StructScan destination") } direct := reflect.Indirect(value) slice, err := baseType(value.Type(), reflect.Slice) if err != nil { return err } direct.SetLen(0) isPtr := slice.Elem().Kind() == reflect.Ptr base := reflectx.Deref(slice.Elem()) scannable := isScannable(base) if structOnly && scannable { return structOnlyError(base) } columns, err := rows.Columns() if err != nil { return err } // if it's a base type make sure it only has 1 column; if not return an error if scannable && len(columns) > 1 { return fmt.Errorf("non-struct dest type %s with >1 columns (%d)", base.Kind(), len(columns)) } if !scannable { var values []interface{} var m *reflectx.Mapper switch rows.(type) { case *Rows: m = rows.(*Rows).Mapper default: m = mapper() } fields := m.TraversalsByName(base, columns) // if we are not unsafe and are missing fields, return an error if f, err := missingFields(fields); err != nil && !isUnsafe(rows) { return fmt.Errorf("missing destination name %s in %T", columns[f], dest) } values = make([]interface{}, len(columns)) for rows.Next() { // create a new struct type (which returns PtrTo) and indirect it vp = reflect.New(base) v = reflect.Indirect(vp) err = fieldsByTraversal(v, fields, values, true) if err != nil { return err } // scan into the struct field pointers and append to our results err = rows.Scan(values...) if err != nil { return err } if isPtr { direct.Set(reflect.Append(direct, vp)) } else { direct.Set(reflect.Append(direct, v)) } } } else { for rows.Next() { vp = reflect.New(base) err = rows.Scan(vp.Interface()) if err != nil { return err } // append if isPtr { direct.Set(reflect.Append(direct, vp)) } else { direct.Set(reflect.Append(direct, reflect.Indirect(vp))) } } } return rows.Err() } // FIXME: StructScan was the very first bit of API in sqlx, and now unfortunately // it doesn't really feel like it's named properly. There is an incongruency // between this and the way that StructScan (which might better be ScanStruct // anyway) works on a rows object. // StructScan all rows from an sql.Rows or an sqlx.Rows into the dest slice. // StructScan will scan in the entire rows result, so if you do not want to // allocate structs for the entire result, use Queryx and see sqlx.Rows.StructScan. // If rows is sqlx.Rows, it will use its mapper, otherwise it will use the default. func StructScan(rows rowsi, dest interface{}) error { return scanAll(rows, dest, true) } // reflect helpers func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) { t = reflectx.Deref(t) if t.Kind() != expected { return nil, fmt.Errorf("expected %s but got %s", expected, t.Kind()) } return t, nil } // fieldsByName fills a values interface with fields from the passed value based // on the traversals in int. If ptrs is true, return addresses instead of values. // We write this instead of using FieldsByName to save allocations and map lookups // when iterating over many rows. Empty traversals will get an interface pointer. // Because of the necessity of requesting ptrs or values, it's considered a bit too // specialized for inclusion in reflectx itself. func fieldsByTraversal(v reflect.Value, traversals [][]int, values []interface{}, ptrs bool) error { v = reflect.Indirect(v) if v.Kind() != reflect.Struct { return errors.New("argument not a struct") } for i, traversal := range traversals { if len(traversal) == 0 { values[i] = new(interface{}) continue } f := reflectx.FieldByIndexes(v, traversal) if ptrs { values[i] = f.Addr().Interface() } else { values[i] = f.Interface() } } return nil } func missingFields(transversals [][]int) (field int, err error) { for i, t := range transversals { if len(t) == 0 { return i, errors.New("missing field") } } return 0, nil } ================================================ FILE: vendor/github.com/jmoiron/sqlx/sqlx_context.go ================================================ // +build go1.8 package sqlx import ( "context" "database/sql" "fmt" "io/ioutil" "path/filepath" "reflect" ) // ConnectContext to a database and verify with a ping. func ConnectContext(ctx context.Context, driverName, dataSourceName string) (*DB, error) { db, err := Open(driverName, dataSourceName) if err != nil { return db, err } err = db.PingContext(ctx) return db, err } // QueryerContext is an interface used by GetContext and SelectContext type QueryerContext interface { QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row } // PreparerContext is an interface used by PreparexContext. type PreparerContext interface { PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) } // ExecerContext is an interface used by MustExecContext and LoadFileContext type ExecerContext interface { ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) } // ExtContext is a union interface which can bind, query, and exec, with Context // used by NamedQueryContext and NamedExecContext. type ExtContext interface { binder QueryerContext ExecerContext } // SelectContext executes a query using the provided Queryer, and StructScans // each row into dest, which must be a slice. If the slice elements are // scannable, then the result set must have only one column. Otherwise, // StructScan is used. The *sql.Rows are closed automatically. // Any placeholder parameters are replaced with supplied args. func SelectContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error { rows, err := q.QueryxContext(ctx, query, args...) if err != nil { return err } // if something happens here, we want to make sure the rows are Closed defer rows.Close() return scanAll(rows, dest, false) } // PreparexContext prepares a statement. // // The provided context is used for the preparation of the statement, not for // the execution of the statement. func PreparexContext(ctx context.Context, p PreparerContext, query string) (*Stmt, error) { s, err := p.PrepareContext(ctx, query) if err != nil { return nil, err } return &Stmt{Stmt: s, unsafe: isUnsafe(p), Mapper: mapperFor(p)}, err } // GetContext does a QueryRow using the provided Queryer, and scans the // resulting row to dest. If dest is scannable, the result must only have one // column. Otherwise, StructScan is used. Get will return sql.ErrNoRows like // row.Scan would. Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. func GetContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error { r := q.QueryRowxContext(ctx, query, args...) return r.scanAny(dest, false) } // LoadFileContext exec's every statement in a file (as a single call to Exec). // LoadFileContext may return a nil *sql.Result if errors are encountered // locating or reading the file at path. LoadFile reads the entire file into // memory, so it is not suitable for loading large data dumps, but can be useful // for initializing schemas or loading indexes. // // FIXME: this does not really work with multi-statement files for mattn/go-sqlite3 // or the go-mysql-driver/mysql drivers; pq seems to be an exception here. Detecting // this by requiring something with DriverName() and then attempting to split the // queries will be difficult to get right, and its current driver-specific behavior // is deemed at least not complex in its incorrectness. func LoadFileContext(ctx context.Context, e ExecerContext, path string) (*sql.Result, error) { realpath, err := filepath.Abs(path) if err != nil { return nil, err } contents, err := ioutil.ReadFile(realpath) if err != nil { return nil, err } res, err := e.ExecContext(ctx, string(contents)) return &res, err } // MustExecContext execs the query using e and panics if there was an error. // Any placeholder parameters are replaced with supplied args. func MustExecContext(ctx context.Context, e ExecerContext, query string, args ...interface{}) sql.Result { res, err := e.ExecContext(ctx, query, args...) if err != nil { panic(err) } return res } // PrepareNamedContext returns an sqlx.NamedStmt func (db *DB) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) { return prepareNamedContext(ctx, db, query) } // NamedQueryContext using this DB. // Any named placeholder parameters are replaced with fields from arg. func (db *DB) NamedQueryContext(ctx context.Context, query string, arg interface{}) (*Rows, error) { return NamedQueryContext(ctx, db, query, arg) } // NamedExecContext using this DB. // Any named placeholder parameters are replaced with fields from arg. func (db *DB) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) { return NamedExecContext(ctx, db, query, arg) } // SelectContext using this DB. // Any placeholder parameters are replaced with supplied args. func (db *DB) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { return SelectContext(ctx, db, dest, query, args...) } // GetContext using this DB. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. func (db *DB) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { return GetContext(ctx, db, dest, query, args...) } // PreparexContext returns an sqlx.Stmt instead of a sql.Stmt. // // The provided context is used for the preparation of the statement, not for // the execution of the statement. func (db *DB) PreparexContext(ctx context.Context, query string) (*Stmt, error) { return PreparexContext(ctx, db, query) } // QueryxContext queries the database and returns an *sqlx.Rows. // Any placeholder parameters are replaced with supplied args. func (db *DB) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { r, err := db.DB.QueryContext(ctx, query, args...) if err != nil { return nil, err } return &Rows{Rows: r, unsafe: db.unsafe, Mapper: db.Mapper}, err } // QueryRowxContext queries the database and returns an *sqlx.Row. // Any placeholder parameters are replaced with supplied args. func (db *DB) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row { rows, err := db.DB.QueryContext(ctx, query, args...) return &Row{rows: rows, err: err, unsafe: db.unsafe, Mapper: db.Mapper} } // MustBeginTx starts a transaction, and panics on error. Returns an *sqlx.Tx instead // of an *sql.Tx. // // The provided context is used until the transaction is committed or rolled // back. If the context is canceled, the sql package will roll back the // transaction. Tx.Commit will return an error if the context provided to // MustBeginContext is canceled. func (db *DB) MustBeginTx(ctx context.Context, opts *sql.TxOptions) *Tx { tx, err := db.BeginTxx(ctx, opts) if err != nil { panic(err) } return tx } // MustExecContext (panic) runs MustExec using this database. // Any placeholder parameters are replaced with supplied args. func (db *DB) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result { return MustExecContext(ctx, db, query, args...) } // BeginTxx begins a transaction and returns an *sqlx.Tx instead of an // *sql.Tx. // // The provided context is used until the transaction is committed or rolled // back. If the context is canceled, the sql package will roll back the // transaction. Tx.Commit will return an error if the context provided to // BeginxContext is canceled. func (db *DB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { tx, err := db.DB.BeginTx(ctx, opts) if err != nil { return nil, err } return &Tx{Tx: tx, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, err } // Connx returns an *sqlx.Conn instead of an *sql.Conn. func (db *DB) Connx(ctx context.Context) (*Conn, error) { conn, err := db.DB.Conn(ctx) if err != nil { return nil, err } return &Conn{Conn: conn, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, nil } // BeginTxx begins a transaction and returns an *sqlx.Tx instead of an // *sql.Tx. // // The provided context is used until the transaction is committed or rolled // back. If the context is canceled, the sql package will roll back the // transaction. Tx.Commit will return an error if the context provided to // BeginxContext is canceled. func (c *Conn) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { tx, err := c.Conn.BeginTx(ctx, opts) if err != nil { return nil, err } return &Tx{Tx: tx, driverName: c.driverName, unsafe: c.unsafe, Mapper: c.Mapper}, err } // SelectContext using this Conn. // Any placeholder parameters are replaced with supplied args. func (c *Conn) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { return SelectContext(ctx, c, dest, query, args...) } // GetContext using this Conn. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. func (c *Conn) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { return GetContext(ctx, c, dest, query, args...) } // PreparexContext returns an sqlx.Stmt instead of a sql.Stmt. // // The provided context is used for the preparation of the statement, not for // the execution of the statement. func (c *Conn) PreparexContext(ctx context.Context, query string) (*Stmt, error) { return PreparexContext(ctx, c, query) } // QueryxContext queries the database and returns an *sqlx.Rows. // Any placeholder parameters are replaced with supplied args. func (c *Conn) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { r, err := c.Conn.QueryContext(ctx, query, args...) if err != nil { return nil, err } return &Rows{Rows: r, unsafe: c.unsafe, Mapper: c.Mapper}, err } // QueryRowxContext queries the database and returns an *sqlx.Row. // Any placeholder parameters are replaced with supplied args. func (c *Conn) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row { rows, err := c.Conn.QueryContext(ctx, query, args...) return &Row{rows: rows, err: err, unsafe: c.unsafe, Mapper: c.Mapper} } // Rebind a query within a Conn's bindvar type. func (c *Conn) Rebind(query string) string { return Rebind(BindType(c.driverName), query) } // StmtxContext returns a version of the prepared statement which runs within a // transaction. Provided stmt can be either *sql.Stmt or *sqlx.Stmt. func (tx *Tx) StmtxContext(ctx context.Context, stmt interface{}) *Stmt { var s *sql.Stmt switch v := stmt.(type) { case Stmt: s = v.Stmt case *Stmt: s = v.Stmt case *sql.Stmt: s = v default: panic(fmt.Sprintf("non-statement type %v passed to Stmtx", reflect.ValueOf(stmt).Type())) } return &Stmt{Stmt: tx.StmtContext(ctx, s), Mapper: tx.Mapper} } // NamedStmtContext returns a version of the prepared statement which runs // within a transaction. func (tx *Tx) NamedStmtContext(ctx context.Context, stmt *NamedStmt) *NamedStmt { return &NamedStmt{ QueryString: stmt.QueryString, Params: stmt.Params, Stmt: tx.StmtxContext(ctx, stmt.Stmt), } } // PreparexContext returns an sqlx.Stmt instead of a sql.Stmt. // // The provided context is used for the preparation of the statement, not for // the execution of the statement. func (tx *Tx) PreparexContext(ctx context.Context, query string) (*Stmt, error) { return PreparexContext(ctx, tx, query) } // PrepareNamedContext returns an sqlx.NamedStmt func (tx *Tx) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) { return prepareNamedContext(ctx, tx, query) } // MustExecContext runs MustExecContext within a transaction. // Any placeholder parameters are replaced with supplied args. func (tx *Tx) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result { return MustExecContext(ctx, tx, query, args...) } // QueryxContext within a transaction and context. // Any placeholder parameters are replaced with supplied args. func (tx *Tx) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { r, err := tx.Tx.QueryContext(ctx, query, args...) if err != nil { return nil, err } return &Rows{Rows: r, unsafe: tx.unsafe, Mapper: tx.Mapper}, err } // SelectContext within a transaction and context. // Any placeholder parameters are replaced with supplied args. func (tx *Tx) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { return SelectContext(ctx, tx, dest, query, args...) } // GetContext within a transaction and context. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. func (tx *Tx) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { return GetContext(ctx, tx, dest, query, args...) } // QueryRowxContext within a transaction and context. // Any placeholder parameters are replaced with supplied args. func (tx *Tx) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row { rows, err := tx.Tx.QueryContext(ctx, query, args...) return &Row{rows: rows, err: err, unsafe: tx.unsafe, Mapper: tx.Mapper} } // NamedExecContext using this Tx. // Any named placeholder parameters are replaced with fields from arg. func (tx *Tx) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) { return NamedExecContext(ctx, tx, query, arg) } // SelectContext using the prepared statement. // Any placeholder parameters are replaced with supplied args. func (s *Stmt) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error { return SelectContext(ctx, &qStmt{s}, dest, "", args...) } // GetContext using the prepared statement. // Any placeholder parameters are replaced with supplied args. // An error is returned if the result set is empty. func (s *Stmt) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error { return GetContext(ctx, &qStmt{s}, dest, "", args...) } // MustExecContext (panic) using this statement. Note that the query portion of // the error output will be blank, as Stmt does not expose its query. // Any placeholder parameters are replaced with supplied args. func (s *Stmt) MustExecContext(ctx context.Context, args ...interface{}) sql.Result { return MustExecContext(ctx, &qStmt{s}, "", args...) } // QueryRowxContext using this statement. // Any placeholder parameters are replaced with supplied args. func (s *Stmt) QueryRowxContext(ctx context.Context, args ...interface{}) *Row { qs := &qStmt{s} return qs.QueryRowxContext(ctx, "", args...) } // QueryxContext using this statement. // Any placeholder parameters are replaced with supplied args. func (s *Stmt) QueryxContext(ctx context.Context, args ...interface{}) (*Rows, error) { qs := &qStmt{s} return qs.QueryxContext(ctx, "", args...) } func (q *qStmt) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { return q.Stmt.QueryContext(ctx, args...) } func (q *qStmt) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) { r, err := q.Stmt.QueryContext(ctx, args...) if err != nil { return nil, err } return &Rows{Rows: r, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}, err } func (q *qStmt) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row { rows, err := q.Stmt.QueryContext(ctx, args...) return &Row{rows: rows, err: err, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper} } func (q *qStmt) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { return q.Stmt.ExecContext(ctx, args...) } ================================================ FILE: vendor/github.com/jmoiron/sqlx/types/README.md ================================================ # types The types package provides some useful types which implement the `sql.Scanner` and `driver.Valuer` interfaces, suitable for use as scan and value targets with database/sql. ================================================ FILE: vendor/github.com/jmoiron/sqlx/types/types.go ================================================ package types import ( "bytes" "compress/gzip" "database/sql/driver" "encoding/json" "errors" "io/ioutil" ) // GzippedText is a []byte which transparently gzips data being submitted to // a database and ungzips data being Scanned from a database. type GzippedText []byte // Value implements the driver.Valuer interface, gzipping the raw value of // this GzippedText. func (g GzippedText) Value() (driver.Value, error) { b := make([]byte, 0, len(g)) buf := bytes.NewBuffer(b) w := gzip.NewWriter(buf) w.Write(g) w.Close() return buf.Bytes(), nil } // Scan implements the sql.Scanner interface, ungzipping the value coming off // the wire and storing the raw result in the GzippedText. func (g *GzippedText) Scan(src interface{}) error { var source []byte switch src := src.(type) { case string: source = []byte(src) case []byte: source = src default: return errors.New("Incompatible type for GzippedText") } reader, err := gzip.NewReader(bytes.NewReader(source)) if err != nil { return err } defer reader.Close() b, err := ioutil.ReadAll(reader) if err != nil { return err } *g = GzippedText(b) return nil } // JSONText is a json.RawMessage, which is a []byte underneath. // Value() validates the json format in the source, and returns an error if // the json is not valid. Scan does no validation. JSONText additionally // implements `Unmarshal`, which unmarshals the json within to an interface{} type JSONText json.RawMessage var emptyJSON = JSONText("{}") // MarshalJSON returns the *j as the JSON encoding of j. func (j JSONText) MarshalJSON() ([]byte, error) { if len(j) == 0 { return emptyJSON, nil } return j, nil } // UnmarshalJSON sets *j to a copy of data func (j *JSONText) UnmarshalJSON(data []byte) error { if j == nil { return errors.New("JSONText: UnmarshalJSON on nil pointer") } *j = append((*j)[0:0], data...) return nil } // Value returns j as a value. This does a validating unmarshal into another // RawMessage. If j is invalid json, it returns an error. func (j JSONText) Value() (driver.Value, error) { var m json.RawMessage var err = j.Unmarshal(&m) if err != nil { return []byte{}, err } return []byte(j), nil } // Scan stores the src in *j. No validation is done. func (j *JSONText) Scan(src interface{}) error { var source []byte switch t := src.(type) { case string: source = []byte(t) case []byte: if len(t) == 0 { source = emptyJSON } else { source = t } case nil: *j = emptyJSON default: return errors.New("Incompatible type for JSONText") } *j = append((*j)[0:0], source...) return nil } // Unmarshal unmarshal's the json in j to v, as in json.Unmarshal. func (j *JSONText) Unmarshal(v interface{}) error { if len(*j) == 0 { *j = emptyJSON } return json.Unmarshal([]byte(*j), v) } // String supports pretty printing for JSONText types. func (j JSONText) String() string { return string(j) } // NullJSONText represents a JSONText that may be null. // NullJSONText implements the scanner interface so // it can be used as a scan destination, similar to NullString. type NullJSONText struct { JSONText Valid bool // Valid is true if JSONText is not NULL } // Scan implements the Scanner interface. func (n *NullJSONText) Scan(value interface{}) error { if value == nil { n.JSONText, n.Valid = emptyJSON, false return nil } n.Valid = true return n.JSONText.Scan(value) } // Value implements the driver Valuer interface. func (n NullJSONText) Value() (driver.Value, error) { if !n.Valid { return nil, nil } return n.JSONText.Value() } // BitBool is an implementation of a bool for the MySQL type BIT(1). // This type allows you to avoid wasting an entire byte for MySQL's boolean type TINYINT. type BitBool bool // Value implements the driver.Valuer interface, // and turns the BitBool into a bitfield (BIT(1)) for MySQL storage. func (b BitBool) Value() (driver.Value, error) { if b { return []byte{1}, nil } return []byte{0}, nil } // Scan implements the sql.Scanner interface, // and turns the bitfield incoming from MySQL into a BitBool func (b *BitBool) Scan(src interface{}) error { v, ok := src.([]byte) if !ok { return errors.New("bad []byte type assertion") } *b = v[0] == 1 return nil } ================================================ FILE: vendor/github.com/kisielk/sqlstruct/.gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe ================================================ FILE: vendor/github.com/kisielk/sqlstruct/.travis.yml ================================================ arch: - amd64 - ppc64le language: go go: - 1.2 - tip jobs: exclude: - go: 1.2 arch: ppc64le - go: 1.2 arch: amd64 ================================================ FILE: vendor/github.com/kisielk/sqlstruct/LICENSE ================================================ Copyright 2012 Kamil Kisiel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: vendor/github.com/kisielk/sqlstruct/README.md ================================================ sqlstruct ========= sqlstruct provides some convenience functions for using structs with go's database/sql package Documentation can be found at http://godoc.org/github.com/kisielk/sqlstruct ================================================ FILE: vendor/github.com/kisielk/sqlstruct/sqlstruct.go ================================================ // Copyright 2012 Kamil Kisiel. All rights reserved. // Use of this source code is governed by the MIT // license which can be found in the LICENSE file. /* Package sqlstruct provides some convenience functions for using structs with the Go standard library's database/sql package. The package matches struct field names to SQL query column names. A field can also specify a matching column with "sql" tag, if it's different from field name. Unexported fields or fields marked with `sql:"-"` are ignored, just like with "encoding/json" package. For example: type T struct { F1 string F2 string `sql:"field2"` F3 string `sql:"-"` } rows, err := db.Query(fmt.Sprintf("SELECT %s FROM tablename", sqlstruct.Columns(T{}))) ... for rows.Next() { var t T err = sqlstruct.Scan(&t, rows) ... } err = rows.Err() // get any errors encountered during iteration Aliased tables in a SQL statement may be scanned into a specific structure identified by the same alias, using the ColumnsAliased and ScanAliased functions: type User struct { Id int `sql:"id"` Username string `sql:"username"` Email string `sql:"address"` Name string `sql:"name"` HomeAddress *Address `sql:"-"` } type Address struct { Id int `sql:"id"` City string `sql:"city"` Street string `sql:"address"` } ... var user User var address Address sql := ` SELECT %s, %s FROM users AS u INNER JOIN address AS a ON a.id = u.address_id WHERE u.username = ? ` sql = fmt.Sprintf(sql, sqlstruct.ColumnsAliased(*user, "u"), sqlstruct.ColumnsAliased(*address, "a")) rows, err := db.Query(sql, "gedi") if err != nil { log.Fatal(err) } defer rows.Close() if rows.Next() { err = sqlstruct.ScanAliased(&user, rows, "u") if err != nil { log.Fatal(err) } err = sqlstruct.ScanAliased(&address, rows, "a") if err != nil { log.Fatal(err) } user.HomeAddress = address } fmt.Printf("%+v", *user) // output: "{Id:1 Username:gedi Email:gediminas.morkevicius@gmail.com Name:Gedas HomeAddress:0xc21001f570}" fmt.Printf("%+v", *user.HomeAddress) // output: "{Id:2 City:Vilnius Street:Plento 34}" */ package sqlstruct import ( "bytes" "database/sql" "fmt" "reflect" "sort" "strings" "sync" ) // NameMapper is the function used to convert struct fields which do not have sql tags // into database column names. // // The default mapper converts field names to lower case. If instead you would prefer // field names converted to snake case, simply assign sqlstruct.ToSnakeCase to the variable: // // sqlstruct.NameMapper = sqlstruct.ToSnakeCase // // Alternatively for a custom mapping, any func(string) string can be used instead. var NameMapper func(string) string = strings.ToLower // A cache of fieldInfos to save reflecting every time. Inspried by encoding/xml var finfos map[reflect.Type]fieldInfo var finfoLock sync.RWMutex // TagName is the name of the tag to use on struct fields var TagName = "sql" // fieldInfo is a mapping of field tag values to their indices type fieldInfo map[string][]int func init() { finfos = make(map[reflect.Type]fieldInfo) } // Rows defines the interface of types that are scannable with the Scan function. // It is implemented by the sql.Rows type from the standard library type Rows interface { Scan(...interface{}) error Columns() ([]string, error) } // getFieldInfo creates a fieldInfo for the provided type. Fields that are not tagged // with the "sql" tag and unexported fields are not included. func getFieldInfo(typ reflect.Type) fieldInfo { finfoLock.RLock() finfo, ok := finfos[typ] finfoLock.RUnlock() if ok { return finfo } finfo = make(fieldInfo) n := typ.NumField() for i := 0; i < n; i++ { f := typ.Field(i) tag := f.Tag.Get(TagName) // Skip unexported fields or fields marked with "-" if f.PkgPath != "" || tag == "-" { continue } // Handle embedded structs if f.Anonymous && f.Type.Kind() == reflect.Struct { for k, v := range getFieldInfo(f.Type) { finfo[k] = append([]int{i}, v...) } continue } // Use field name for untagged fields if tag == "" { tag = f.Name } tag = NameMapper(tag) finfo[tag] = []int{i} } finfoLock.Lock() finfos[typ] = finfo finfoLock.Unlock() return finfo } // Scan scans the next row from rows in to a struct pointed to by dest. The struct type // should have exported fields tagged with the "sql" tag. Columns from row which are not // mapped to any struct fields are ignored. Struct fields which have no matching column // in the result set are left unchanged. func Scan(dest interface{}, rows Rows) error { return doScan(dest, rows, "") } // ScanAliased works like scan, except that it expects the results in the query to be // prefixed by the given alias. // // For example, if scanning to a field named "name" with an alias of "user" it will // expect to find the result in a column named "user_name". // // See ColumnAliased for a convenient way to generate these queries. func ScanAliased(dest interface{}, rows Rows, alias string) error { return doScan(dest, rows, alias) } // Columns returns a string containing a sorted, comma-separated list of column names as // defined by the type s. s must be a struct that has exported fields tagged with the "sql" tag. func Columns(s interface{}) string { return strings.Join(cols(s), ", ") } // ColumnsAliased works like Columns except it prefixes the resulting column name with the // given alias. // // For each field in the given struct it will generate a statement like: // alias.field AS alias_field // // It is intended to be used in conjunction with the ScanAliased function. func ColumnsAliased(s interface{}, alias string) string { names := cols(s) aliased := make([]string, 0, len(names)) for _, n := range names { aliased = append(aliased, alias+"."+n+" AS "+alias+"_"+n) } return strings.Join(aliased, ", ") } func cols(s interface{}) []string { v := reflect.ValueOf(s) fields := getFieldInfo(v.Type()) names := make([]string, 0, len(fields)) for f := range fields { names = append(names, f) } sort.Strings(names) return names } func doScan(dest interface{}, rows Rows, alias string) error { destv := reflect.ValueOf(dest) typ := destv.Type() if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Struct { panic(fmt.Errorf("dest must be pointer to struct; got %T", destv)) } fieldInfo := getFieldInfo(typ.Elem()) elem := destv.Elem() var values []interface{} cols, err := rows.Columns() if err != nil { return err } for _, name := range cols { if len(alias) > 0 { name = strings.Replace(name, alias+"_", "", 1) } idx, ok := fieldInfo[strings.ToLower(name)] var v interface{} if !ok { // There is no field mapped to this column so we discard it v = &sql.RawBytes{} } else { v = elem.FieldByIndex(idx).Addr().Interface() } values = append(values, v) } return rows.Scan(values...) } // ToSnakeCase converts a string to snake case, words separated with underscores. // It's intended to be used with NameMapper to map struct field names to snake case database fields. func ToSnakeCase(src string) string { thisUpper := false prevUpper := false buf := bytes.NewBufferString("") for i, v := range src { if v >= 'A' && v <= 'Z' { thisUpper = true } else { thisUpper = false } if i > 0 && thisUpper && !prevUpper { buf.WriteRune('_') } prevUpper = thisUpper buf.WriteRune(v) } return strings.ToLower(buf.String()) } ================================================ FILE: vendor/github.com/kylelemons/go-gypsy/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/kylelemons/go-gypsy/yaml/config.go ================================================ // Copyright 2013 Google, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package yaml import ( "bytes" "fmt" "os" "strconv" "strings" ) // A File represents the top-level YAML node found in a file. It is intended // for use as a configuration file. type File struct { Root Node // TODO(kevlar): Add a cache? } // ReadFile reads a YAML configuration file from the given filename. func ReadFile(filename string) (*File, error) { fin, err := os.Open(filename) if err != nil { return nil, err } defer fin.Close() f := new(File) f.Root, err = Parse(fin) if err != nil { return nil, err } return f, nil } // Config reads a YAML configuration from a static string. If an error is // found, it will panic. This is a utility function and is intended for use in // initializers. func Config(yamlconf string) *File { var err error buf := bytes.NewBufferString(yamlconf) f := new(File) f.Root, err = Parse(buf) if err != nil { panic(err) } return f } // ConfigFile reads a YAML configuration file from the given filename and // panics if an error is found. This is a utility function and is intended for // use in initializers. func ConfigFile(filename string) *File { f, err := ReadFile(filename) if err != nil { panic(err) } return f } // Get retrieves a scalar from the file specified by a string of the same // format as that expected by Child. If the final node is not a Scalar, Get // will return an error. func (f *File) Get(spec string) (string, error) { node, err := Child(f.Root, spec) if err != nil { return "", err } if node == nil { return "", &NodeNotFound{ Full: spec, Spec: spec, } } scalar, ok := node.(Scalar) if !ok { return "", &NodeTypeMismatch{ Full: spec, Spec: spec, Token: "$", Expected: "yaml.Scalar", Node: node, } } return scalar.String(), nil } func (f *File) GetInt(spec string) (int64, error) { s, err := f.Get(spec) if err != nil { return 0, err } i, err := strconv.ParseInt(s, 10, 64) if err != nil { return 0, err } return i, nil } func (f *File) GetBool(spec string) (bool, error) { s, err := f.Get(spec) if err != nil { return false, err } b, err := strconv.ParseBool(s) if err != nil { return false, err } return b, nil } // Count retrieves a the number of elements in the specified list from the file // using the same format as that expected by Child. If the final node is not a // List, Count will return an error. func (f *File) Count(spec string) (int, error) { node, err := Child(f.Root, spec) if err != nil { return -1, err } if node == nil { return -1, &NodeNotFound{ Full: spec, Spec: spec, } } lst, ok := node.(List) if !ok { return -1, &NodeTypeMismatch{ Full: spec, Spec: spec, Token: "$", Expected: "yaml.List", Node: node, } } return lst.Len(), nil } // Require retrieves a scalar from the file specified by a string of the same // format as that expected by Child. If the final node is not a Scalar, String // will panic. This is a convenience function for use in initializers. func (f *File) Require(spec string) string { str, err := f.Get(spec) if err != nil { panic(err) } return str } // Child retrieves a child node from the specified node as follows: // .mapkey - Get the key 'mapkey' of the Node, which must be a Map // [idx] - Choose the index from the current Node, which must be a List // // The above selectors may be applied recursively, and each successive selector // applies to the result of the previous selector. For convenience, a "." is // implied as the first character if the first character is not a "." or "[". // The node tree is walked from the given node, considering each token of the // above format. If a node along the evaluation path is not found, an error is // returned. If a node is not the proper type, an error is returned. If the // final node is not a Scalar, an error is returned. func Child(root Node, spec string) (Node, error) { if len(spec) == 0 { return root, nil } if first := spec[0]; first != '.' && first != '[' { spec = "." + spec } var recur func(Node, string, string) (Node, error) recur = func(n Node, last, s string) (Node, error) { if len(s) == 0 { return n, nil } if n == nil { return nil, &NodeNotFound{ Full: spec, Spec: last, } } // Extract the next token delim := 1 + strings.IndexAny(s[1:], ".[") if delim <= 0 { delim = len(s) } tok := s[:delim] remain := s[delim:] switch s[0] { case '[': s, ok := n.(List) if !ok { return nil, &NodeTypeMismatch{ Node: n, Expected: "yaml.List", Full: spec, Spec: last, Token: tok, } } if tok[0] == '[' && tok[len(tok)-1] == ']' { if num, err := strconv.Atoi(tok[1 : len(tok)-1]); err == nil { if num >= 0 && num < len(s) { return recur(s[num], last+tok, remain) } } } return nil, &NodeNotFound{ Full: spec, Spec: last + tok, } default: m, ok := n.(Map) if !ok { return nil, &NodeTypeMismatch{ Node: n, Expected: "yaml.Map", Full: spec, Spec: last, Token: tok, } } n, ok = m[tok[1:]] if !ok { return nil, &NodeNotFound{ Full: spec, Spec: last + tok, } } return recur(n, last+tok, remain) } } return recur(root, "", spec) } type NodeNotFound struct { Full string Spec string } func (e *NodeNotFound) Error() string { return fmt.Sprintf("yaml: %s: %q not found", e.Full, e.Spec) } type NodeTypeMismatch struct { Full string Spec string Token string Node Node Expected string } func (e *NodeTypeMismatch) Error() string { return fmt.Sprintf("yaml: %s: type mismatch: %q is %T, want %s (at %q)", e.Full, e.Spec, e.Node, e.Expected, e.Token) } ================================================ FILE: vendor/github.com/kylelemons/go-gypsy/yaml/doc.go ================================================ // Copyright 2013 Google, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Gypsy is a simplified YAML parser written in Go. It is intended to be used as // a simple configuration file, and as such does not support a lot of the more // nuanced syntaxes allowed in full-fledged YAML. YAML does not allow indent with // tabs, and GYPSY does not ever consider a tab to be a space character. It is // recommended that your editor be configured to convert tabs to spaces when // editing Gypsy config files. // // Gypsy understands the following to be a list: // // - one // - two // - three // // This is parsed as a `yaml.List`, and can be retrieved from the // `yaml.Node.List()` method. In this case, each element of the `yaml.List` would // be a `yaml.Scalar` whose value can be retrieved with the `yaml.Scalar.String()` // method. // // Gypsy understands the following to be a mapping: // // key: value // foo: bar // running: away // // A mapping is an unordered list of `key:value` pairs. All whitespace after the // colon is stripped from the value and is used for alignment purposes during // export. If the value is not a list or a map, everything after the first // non-space character until the end of the line is used as the `yaml.Scalar` // value. // // Gypsy allows arbitrary nesting of maps inside lists, lists inside of maps, and // maps and/or lists nested inside of themselves. // // A map inside of a list: // // - name: John Smith // age: 42 // - name: Jane Smith // age: 45 // // A list inside of a map: // // schools: // - Meadow Glen // - Forest Creek // - Shady Grove // libraries: // - Joseph Hollingsworth Memorial // - Andrew Keriman Memorial // // A list of lists: // // - - one // - two // - three // - - un // - deux // - trois // - - ichi // - ni // - san // // A map of maps: // // google: // company: Google, Inc. // ticker: GOOG // url: http://google.com/ // yahoo: // company: Yahoo, Inc. // ticker: YHOO // url: http://yahoo.com/ // // In the case of a map of maps, all sub-keys must be on subsequent lines and // indented equally. It is allowable for the first key/value to be on the same // line if there is more than one key/value pair, but this is not recommended. // // Values can also be expressed in long form (leading whitespace of the first line // is removed from it and all subsequent lines). In the normal (baz) case, // newlines are treated as spaces, all indentation is removed. In the folded case // (bar), newlines are treated as spaces, except pairs of newlines (e.g. a blank // line) are treated as a single newline, only the indentation level of the first // line is removed, and newlines at the end of indented lines are preserved. In // the verbatim (foo) case, only the indent at the level of the first line is // stripped. The example: // // foo: | // lorem ipsum dolor // sit amet // bar: > // lorem ipsum // // dolor // // sit amet // baz: // lorem ipsum // dolor sit amet // // The YAML subset understood by Gypsy can be expressed (loosely) in the following // grammar (not including comments): // // OBJECT = MAPPING | SEQUENCE | SCALAR . // SHORT-OBJECT = SHORT-MAPPING | SHORT-SEQUENCE | SHORT-SCALAR . // EOL = '\n' // // MAPPING = { LONG-MAPPING | SHORT-MAPPING } . // SEQUENCE = { LONG-SEQUENCE | SHORT-SEQUENCE } . // SCALAR = { LONG-SCALAR | SHORT-SCALAR } . // // LONG-MAPPING = { INDENT KEY ':' OBJECT EOL } . // SHORT-MAPPING = '{' KEY ':' SHORT-OBJECT { ',' KEY ':' SHORT-OBJECT } '}' EOL . // // LONG-SEQUENCE = { INDENT '-' OBJECT EOL } EOL . // SHORT-SEQUENCE = '[' SHORT-OBJECT { ',' SHORT-OBJECT } ']' EOL . // // LONG-SCALAR = ( '|' | '>' | ) EOL { INDENT SHORT-SCALAR EOL } // SHORT-SCALAR = { alpha | digit | punct | ' ' | '\t' } . // // KEY = { alpha | digit } // INDENT = { ' ' } // // Any line where the first non-space character is a sharp sign (#) is a comment. // It will be ignored. // Only full-line comments are allowed. package yaml // BUG(kevlar): Multi-line strings are currently not supported. ================================================ FILE: vendor/github.com/kylelemons/go-gypsy/yaml/parser.go ================================================ // Copyright 2013 Google, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package yaml import ( "bufio" "bytes" "errors" "fmt" "io" "strings" ) // Parse returns a root-level Node parsed from the lines read from r. In // general, this will be done for you by one of the File constructors. func Parse(r io.Reader) (node Node, err error) { lb := &lineBuffer{ Reader: bufio.NewReader(r), } defer func() { if r := recover(); r != nil { switch r := r.(type) { case error: err = r case string: err = errors.New(r) default: err = fmt.Errorf("%v", r) } } }() node = parseNode(lb, 0, nil) return } // Supporting types and constants const ( typUnknown = iota typSequence typMapping typScalar ) var typNames = []string{ "Unknown", "Sequence", "Mapping", "Scalar", } type lineReader interface { Next(minIndent int) *indentedLine } type indentedLine struct { lineno int indent int line []byte } func (line *indentedLine) String() string { return fmt.Sprintf("%2d: %s%s", line.indent, strings.Repeat(" ", 0*line.indent), string(line.line)) } func parseNode(r lineReader, ind int, initial Node) (node Node) { first := true node = initial // read lines for { line := r.Next(ind) if line == nil { break } if len(line.line) == 0 { continue } if first { ind = line.indent first = false } types := []int{} pieces := []string{} var inlineValue func([]byte) inlineValue = func(partial []byte) { // TODO(kevlar): This can be a for loop now vtyp, brk := getType(partial) begin, end := partial[:brk], partial[brk:] if vtyp == typMapping { end = end[1:] } end = bytes.TrimLeft(end, " ") switch vtyp { case typScalar: types = append(types, typScalar) pieces = append(pieces, string(end)) return case typMapping: types = append(types, typMapping) pieces = append(pieces, strings.TrimSpace(string(begin))) trimmed := bytes.TrimSpace(end) if len(trimmed) == 1 && trimmed[0] == '|' { text := "" for { l := r.Next(1) if l == nil { break } s := string(l.line) s = strings.TrimSpace(s) if len(s) == 0 { break } text = text + "\n" + s } types = append(types, typScalar) pieces = append(pieces, string(text)) return } inlineValue(end) case typSequence: types = append(types, typSequence) pieces = append(pieces, "-") inlineValue(end) } } inlineValue(line.line) var prev Node // Nest inlines for len(types) > 0 { last := len(types) - 1 typ, piece := types[last], pieces[last] var current Node if last == 0 { current = node } //child := parseNode(r, line.indent+1, typUnknown) // TODO allow scalar only // Add to current node switch typ { case typScalar: // last will be == nil if _, ok := current.(Scalar); current != nil && !ok { panic("cannot append scalar to non-scalar node") } if current != nil { current = Scalar(piece) + " " + current.(Scalar) break } current = Scalar(piece) case typMapping: var mapNode Map var ok bool var child Node // Get the current map, if there is one if mapNode, ok = current.(Map); current != nil && !ok { _ = current.(Map) // panic } else if current == nil { mapNode = make(Map) } if _, inlineMap := prev.(Scalar); inlineMap && last > 0 { current = Map{ piece: prev, } break } child = parseNode(r, line.indent+1, prev) mapNode[piece] = child current = mapNode case typSequence: var listNode List var ok bool var child Node // Get the current list, if there is one if listNode, ok = current.(List); current != nil && !ok { _ = current.(List) // panic } else if current == nil { listNode = make(List, 0) } if _, inlineList := prev.(Scalar); inlineList && last > 0 { current = List{ prev, } break } child = parseNode(r, line.indent+1, prev) listNode = append(listNode, child) current = listNode } if last < 0 { last = 0 } types = types[:last] pieces = pieces[:last] prev = current } node = prev } return } func getType(line []byte) (typ, split int) { if len(line) == 0 { return } if line[0] == '-' { typ = typSequence split = 1 return } typ = typScalar if line[0] == ' ' || line[0] == '"' { return } // the first character is real // need to iterate past the first word // things like "foo:" and "foo :" are mappings // everything else is a scalar idx := bytes.IndexAny(line, " \":") if idx < 0 { return } if line[idx] == '"' { return } if line[idx] == ':' { typ = typMapping split = idx } else if line[idx] == ' ' { // we have a space // need to see if its all spaces until a : for i := idx; i < len(line); i++ { switch ch := line[i]; ch { case ' ': continue case ':': // only split on colons followed by a space if i+1 < len(line) && line[i+1] != ' ' { continue } typ = typMapping split = i break default: break } } } if typ == typMapping && split+1 < len(line) && line[split+1] != ' ' { typ = typScalar split = 0 } return } // lineReader implementations type lineBuffer struct { *bufio.Reader readLines int pending *indentedLine } func (lb *lineBuffer) Next(min int) (next *indentedLine) { if lb.pending == nil { var ( read []byte more bool err error ) l := new(indentedLine) l.lineno = lb.readLines more = true for more { read, more, err = lb.ReadLine() if err != nil { if err == io.EOF { return nil } panic(err) } l.line = append(l.line, read...) } lb.readLines++ for _, ch := range l.line { switch ch { case ' ': l.indent += 1 continue default: } break } l.line = l.line[l.indent:] // Ignore blank lines and comments. if len(l.line) == 0 || l.line[0] == '#' { return lb.Next(min) } lb.pending = l } next = lb.pending if next.indent < min { return nil } lb.pending = nil return } type lineSlice []*indentedLine func (ls *lineSlice) Next(min int) (next *indentedLine) { if len(*ls) == 0 { return nil } next = (*ls)[0] if next.indent < min { return nil } *ls = (*ls)[1:] return } func (ls *lineSlice) Push(line *indentedLine) { *ls = append(*ls, line) } ================================================ FILE: vendor/github.com/kylelemons/go-gypsy/yaml/types.go ================================================ // Copyright 2013 Google, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package yaml import ( "bytes" "fmt" "io" "sort" "strings" ) // A Node is a YAML Node which can be a Map, List or Scalar. type Node interface { write(io.Writer, int, int) } // A Map is a YAML Mapping which maps Strings to Nodes. type Map map[string]Node // Key returns the value associeted with the key in the map. func (node Map) Key(key string) Node { return node[key] } func (node Map) write(out io.Writer, firstind, nextind int) { indent := bytes.Repeat([]byte{' '}, nextind) ind := firstind width := 0 scalarkeys := []string{} objectkeys := []string{} for key, value := range node { if _, ok := value.(Scalar); ok { if swid := len(key); swid > width { width = swid } scalarkeys = append(scalarkeys, key) continue } objectkeys = append(objectkeys, key) } sort.Strings(scalarkeys) sort.Strings(objectkeys) for _, key := range scalarkeys { value := node[key].(Scalar) out.Write(indent[:ind]) fmt.Fprintf(out, "%-*s %s\n", width+1, key+":", string(value)) ind = nextind } for _, key := range objectkeys { out.Write(indent[:ind]) if node[key] == nil { fmt.Fprintf(out, "%s: \n", key) continue } fmt.Fprintf(out, "%s:\n", key) ind = nextind node[key].write(out, ind+2, ind+2) } } // A List is a YAML Sequence of Nodes. type List []Node // Get the number of items in the List. func (node List) Len() int { return len(node) } // Get the idx'th item from the List. func (node List) Item(idx int) Node { if idx >= 0 && idx < len(node) { return node[idx] } return nil } func (node List) write(out io.Writer, firstind, nextind int) { indent := bytes.Repeat([]byte{' '}, nextind) ind := firstind for _, value := range node { out.Write(indent[:ind]) fmt.Fprint(out, "- ") ind = nextind value.write(out, 0, ind+2) } } // A Scalar is a YAML Scalar. type Scalar string // String returns the string represented by this Scalar. func (node Scalar) String() string { return string(node) } func (node Scalar) write(out io.Writer, ind, _ int) { fmt.Fprintf(out, "%s%s\n", strings.Repeat(" ", ind), string(node)) } // Render returns a string of the node as a YAML document. Note that // Scalars will have a newline appended if they are rendered directly. func Render(node Node) string { buf := bytes.NewBuffer(nil) node.write(buf, 0, 0) return buf.String() } ================================================ FILE: vendor/github.com/lib/pq/.gitignore ================================================ .db *.test *~ *.swp .idea .vscode ================================================ FILE: vendor/github.com/lib/pq/LICENSE.md ================================================ Copyright (c) 2011-2013, 'pq' Contributors Portions Copyright (C) 2011 Blake Mizerany Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: vendor/github.com/lib/pq/README.md ================================================ # pq - A pure Go postgres driver for Go's database/sql package [![GoDoc](https://godoc.org/github.com/lib/pq?status.svg)](https://pkg.go.dev/github.com/lib/pq?tab=doc) ## Install go get github.com/lib/pq ## Features * SSL * Handles bad connections for `database/sql` * Scan `time.Time` correctly (i.e. `timestamp[tz]`, `time[tz]`, `date`) * Scan binary blobs correctly (i.e. `bytea`) * Package for `hstore` support * COPY FROM support * pq.ParseURL for converting urls to connection strings for sql.Open. * Many libpq compatible environment variables * Unix socket support * Notifications: `LISTEN`/`NOTIFY` * pgpass support * GSS (Kerberos) auth ## Tests `go test` is used for testing. See [TESTS.md](TESTS.md) for more details. ## Status This package is currently in maintenance mode, which means: 1. It generally does not accept new features. 2. It does accept bug fixes and version compatability changes provided by the community. 3. Maintainers usually do not resolve reported issues. 4. Community members are encouraged to help each other with reported issues. For users that require new features or reliable resolution of reported bugs, we recommend using [pgx](https://github.com/jackc/pgx) which is under active development. ================================================ FILE: vendor/github.com/lib/pq/TESTS.md ================================================ # Tests ## Running Tests `go test` is used for testing. A running PostgreSQL server is required, with the ability to log in. The database to connect to test with is "pqgotest," on "localhost" but these can be overridden using [environment variables](https://www.postgresql.org/docs/9.3/static/libpq-envars.html). Example: PGHOST=/run/postgresql go test ## Benchmarks A benchmark suite can be run as part of the tests: go test -bench . ## Example setup (Docker) Run a postgres container: ``` docker run --expose 5432:5432 postgres ``` Run tests: ``` PGHOST=localhost PGPORT=5432 PGUSER=postgres PGSSLMODE=disable PGDATABASE=postgres go test ``` ================================================ FILE: vendor/github.com/lib/pq/array.go ================================================ package pq import ( "bytes" "database/sql" "database/sql/driver" "encoding/hex" "fmt" "reflect" "strconv" "strings" ) var typeByteSlice = reflect.TypeOf([]byte{}) var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem() var typeSQLScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem() // Array returns the optimal driver.Valuer and sql.Scanner for an array or // slice of any dimension. // // For example: // db.Query(`SELECT * FROM t WHERE id = ANY($1)`, pq.Array([]int{235, 401})) // // var x []sql.NullInt64 // db.QueryRow(`SELECT ARRAY[235, 401]`).Scan(pq.Array(&x)) // // Scanning multi-dimensional arrays is not supported. Arrays where the lower // bound is not one (such as `[0:0]={1}') are not supported. func Array(a interface{}) interface { driver.Valuer sql.Scanner } { switch a := a.(type) { case []bool: return (*BoolArray)(&a) case []float64: return (*Float64Array)(&a) case []float32: return (*Float32Array)(&a) case []int64: return (*Int64Array)(&a) case []int32: return (*Int32Array)(&a) case []string: return (*StringArray)(&a) case [][]byte: return (*ByteaArray)(&a) case *[]bool: return (*BoolArray)(a) case *[]float64: return (*Float64Array)(a) case *[]float32: return (*Float32Array)(a) case *[]int64: return (*Int64Array)(a) case *[]int32: return (*Int32Array)(a) case *[]string: return (*StringArray)(a) case *[][]byte: return (*ByteaArray)(a) } return GenericArray{a} } // ArrayDelimiter may be optionally implemented by driver.Valuer or sql.Scanner // to override the array delimiter used by GenericArray. type ArrayDelimiter interface { // ArrayDelimiter returns the delimiter character(s) for this element's type. ArrayDelimiter() string } // BoolArray represents a one-dimensional array of the PostgreSQL boolean type. type BoolArray []bool // Scan implements the sql.Scanner interface. func (a *BoolArray) Scan(src interface{}) error { switch src := src.(type) { case []byte: return a.scanBytes(src) case string: return a.scanBytes([]byte(src)) case nil: *a = nil return nil } return fmt.Errorf("pq: cannot convert %T to BoolArray", src) } func (a *BoolArray) scanBytes(src []byte) error { elems, err := scanLinearArray(src, []byte{','}, "BoolArray") if err != nil { return err } if *a != nil && len(elems) == 0 { *a = (*a)[:0] } else { b := make(BoolArray, len(elems)) for i, v := range elems { if len(v) != 1 { return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v) } switch v[0] { case 't': b[i] = true case 'f': b[i] = false default: return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v) } } *a = b } return nil } // Value implements the driver.Valuer interface. func (a BoolArray) Value() (driver.Value, error) { if a == nil { return nil, nil } if n := len(a); n > 0 { // There will be exactly two curly brackets, N bytes of values, // and N-1 bytes of delimiters. b := make([]byte, 1+2*n) for i := 0; i < n; i++ { b[2*i] = ',' if a[i] { b[1+2*i] = 't' } else { b[1+2*i] = 'f' } } b[0] = '{' b[2*n] = '}' return string(b), nil } return "{}", nil } // ByteaArray represents a one-dimensional array of the PostgreSQL bytea type. type ByteaArray [][]byte // Scan implements the sql.Scanner interface. func (a *ByteaArray) Scan(src interface{}) error { switch src := src.(type) { case []byte: return a.scanBytes(src) case string: return a.scanBytes([]byte(src)) case nil: *a = nil return nil } return fmt.Errorf("pq: cannot convert %T to ByteaArray", src) } func (a *ByteaArray) scanBytes(src []byte) error { elems, err := scanLinearArray(src, []byte{','}, "ByteaArray") if err != nil { return err } if *a != nil && len(elems) == 0 { *a = (*a)[:0] } else { b := make(ByteaArray, len(elems)) for i, v := range elems { b[i], err = parseBytea(v) if err != nil { return fmt.Errorf("could not parse bytea array index %d: %s", i, err.Error()) } } *a = b } return nil } // Value implements the driver.Valuer interface. It uses the "hex" format which // is only supported on PostgreSQL 9.0 or newer. func (a ByteaArray) Value() (driver.Value, error) { if a == nil { return nil, nil } if n := len(a); n > 0 { // There will be at least two curly brackets, 2*N bytes of quotes, // 3*N bytes of hex formatting, and N-1 bytes of delimiters. size := 1 + 6*n for _, x := range a { size += hex.EncodedLen(len(x)) } b := make([]byte, size) for i, s := 0, b; i < n; i++ { o := copy(s, `,"\\x`) o += hex.Encode(s[o:], a[i]) s[o] = '"' s = s[o+1:] } b[0] = '{' b[size-1] = '}' return string(b), nil } return "{}", nil } // Float64Array represents a one-dimensional array of the PostgreSQL double // precision type. type Float64Array []float64 // Scan implements the sql.Scanner interface. func (a *Float64Array) Scan(src interface{}) error { switch src := src.(type) { case []byte: return a.scanBytes(src) case string: return a.scanBytes([]byte(src)) case nil: *a = nil return nil } return fmt.Errorf("pq: cannot convert %T to Float64Array", src) } func (a *Float64Array) scanBytes(src []byte) error { elems, err := scanLinearArray(src, []byte{','}, "Float64Array") if err != nil { return err } if *a != nil && len(elems) == 0 { *a = (*a)[:0] } else { b := make(Float64Array, len(elems)) for i, v := range elems { if b[i], err = strconv.ParseFloat(string(v), 64); err != nil { return fmt.Errorf("pq: parsing array element index %d: %v", i, err) } } *a = b } return nil } // Value implements the driver.Valuer interface. func (a Float64Array) Value() (driver.Value, error) { if a == nil { return nil, nil } if n := len(a); n > 0 { // There will be at least two curly brackets, N bytes of values, // and N-1 bytes of delimiters. b := make([]byte, 1, 1+2*n) b[0] = '{' b = strconv.AppendFloat(b, a[0], 'f', -1, 64) for i := 1; i < n; i++ { b = append(b, ',') b = strconv.AppendFloat(b, a[i], 'f', -1, 64) } return string(append(b, '}')), nil } return "{}", nil } // Float32Array represents a one-dimensional array of the PostgreSQL double // precision type. type Float32Array []float32 // Scan implements the sql.Scanner interface. func (a *Float32Array) Scan(src interface{}) error { switch src := src.(type) { case []byte: return a.scanBytes(src) case string: return a.scanBytes([]byte(src)) case nil: *a = nil return nil } return fmt.Errorf("pq: cannot convert %T to Float32Array", src) } func (a *Float32Array) scanBytes(src []byte) error { elems, err := scanLinearArray(src, []byte{','}, "Float32Array") if err != nil { return err } if *a != nil && len(elems) == 0 { *a = (*a)[:0] } else { b := make(Float32Array, len(elems)) for i, v := range elems { var x float64 if x, err = strconv.ParseFloat(string(v), 32); err != nil { return fmt.Errorf("pq: parsing array element index %d: %v", i, err) } b[i] = float32(x) } *a = b } return nil } // Value implements the driver.Valuer interface. func (a Float32Array) Value() (driver.Value, error) { if a == nil { return nil, nil } if n := len(a); n > 0 { // There will be at least two curly brackets, N bytes of values, // and N-1 bytes of delimiters. b := make([]byte, 1, 1+2*n) b[0] = '{' b = strconv.AppendFloat(b, float64(a[0]), 'f', -1, 32) for i := 1; i < n; i++ { b = append(b, ',') b = strconv.AppendFloat(b, float64(a[i]), 'f', -1, 32) } return string(append(b, '}')), nil } return "{}", nil } // GenericArray implements the driver.Valuer and sql.Scanner interfaces for // an array or slice of any dimension. type GenericArray struct{ A interface{} } func (GenericArray) evaluateDestination(rt reflect.Type) (reflect.Type, func([]byte, reflect.Value) error, string) { var assign func([]byte, reflect.Value) error var del = "," // TODO calculate the assign function for other types // TODO repeat this section on the element type of arrays or slices (multidimensional) { if reflect.PtrTo(rt).Implements(typeSQLScanner) { // dest is always addressable because it is an element of a slice. assign = func(src []byte, dest reflect.Value) (err error) { ss := dest.Addr().Interface().(sql.Scanner) if src == nil { err = ss.Scan(nil) } else { err = ss.Scan(src) } return } goto FoundType } assign = func([]byte, reflect.Value) error { return fmt.Errorf("pq: scanning to %s is not implemented; only sql.Scanner", rt) } } FoundType: if ad, ok := reflect.Zero(rt).Interface().(ArrayDelimiter); ok { del = ad.ArrayDelimiter() } return rt, assign, del } // Scan implements the sql.Scanner interface. func (a GenericArray) Scan(src interface{}) error { dpv := reflect.ValueOf(a.A) switch { case dpv.Kind() != reflect.Ptr: return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A) case dpv.IsNil(): return fmt.Errorf("pq: destination %T is nil", a.A) } dv := dpv.Elem() switch dv.Kind() { case reflect.Slice: case reflect.Array: default: return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A) } switch src := src.(type) { case []byte: return a.scanBytes(src, dv) case string: return a.scanBytes([]byte(src), dv) case nil: if dv.Kind() == reflect.Slice { dv.Set(reflect.Zero(dv.Type())) return nil } } return fmt.Errorf("pq: cannot convert %T to %s", src, dv.Type()) } func (a GenericArray) scanBytes(src []byte, dv reflect.Value) error { dtype, assign, del := a.evaluateDestination(dv.Type().Elem()) dims, elems, err := parseArray(src, []byte(del)) if err != nil { return err } // TODO allow multidimensional if len(dims) > 1 { return fmt.Errorf("pq: scanning from multidimensional ARRAY%s is not implemented", strings.Replace(fmt.Sprint(dims), " ", "][", -1)) } // Treat a zero-dimensional array like an array with a single dimension of zero. if len(dims) == 0 { dims = append(dims, 0) } for i, rt := 0, dv.Type(); i < len(dims); i, rt = i+1, rt.Elem() { switch rt.Kind() { case reflect.Slice: case reflect.Array: if rt.Len() != dims[i] { return fmt.Errorf("pq: cannot convert ARRAY%s to %s", strings.Replace(fmt.Sprint(dims), " ", "][", -1), dv.Type()) } default: // TODO handle multidimensional } } values := reflect.MakeSlice(reflect.SliceOf(dtype), len(elems), len(elems)) for i, e := range elems { if err := assign(e, values.Index(i)); err != nil { return fmt.Errorf("pq: parsing array element index %d: %v", i, err) } } // TODO handle multidimensional switch dv.Kind() { case reflect.Slice: dv.Set(values.Slice(0, dims[0])) case reflect.Array: for i := 0; i < dims[0]; i++ { dv.Index(i).Set(values.Index(i)) } } return nil } // Value implements the driver.Valuer interface. func (a GenericArray) Value() (driver.Value, error) { if a.A == nil { return nil, nil } rv := reflect.ValueOf(a.A) switch rv.Kind() { case reflect.Slice: if rv.IsNil() { return nil, nil } case reflect.Array: default: return nil, fmt.Errorf("pq: Unable to convert %T to array", a.A) } if n := rv.Len(); n > 0 { // There will be at least two curly brackets, N bytes of values, // and N-1 bytes of delimiters. b := make([]byte, 0, 1+2*n) b, _, err := appendArray(b, rv, n) return string(b), err } return "{}", nil } // Int64Array represents a one-dimensional array of the PostgreSQL integer types. type Int64Array []int64 // Scan implements the sql.Scanner interface. func (a *Int64Array) Scan(src interface{}) error { switch src := src.(type) { case []byte: return a.scanBytes(src) case string: return a.scanBytes([]byte(src)) case nil: *a = nil return nil } return fmt.Errorf("pq: cannot convert %T to Int64Array", src) } func (a *Int64Array) scanBytes(src []byte) error { elems, err := scanLinearArray(src, []byte{','}, "Int64Array") if err != nil { return err } if *a != nil && len(elems) == 0 { *a = (*a)[:0] } else { b := make(Int64Array, len(elems)) for i, v := range elems { if b[i], err = strconv.ParseInt(string(v), 10, 64); err != nil { return fmt.Errorf("pq: parsing array element index %d: %v", i, err) } } *a = b } return nil } // Value implements the driver.Valuer interface. func (a Int64Array) Value() (driver.Value, error) { if a == nil { return nil, nil } if n := len(a); n > 0 { // There will be at least two curly brackets, N bytes of values, // and N-1 bytes of delimiters. b := make([]byte, 1, 1+2*n) b[0] = '{' b = strconv.AppendInt(b, a[0], 10) for i := 1; i < n; i++ { b = append(b, ',') b = strconv.AppendInt(b, a[i], 10) } return string(append(b, '}')), nil } return "{}", nil } // Int32Array represents a one-dimensional array of the PostgreSQL integer types. type Int32Array []int32 // Scan implements the sql.Scanner interface. func (a *Int32Array) Scan(src interface{}) error { switch src := src.(type) { case []byte: return a.scanBytes(src) case string: return a.scanBytes([]byte(src)) case nil: *a = nil return nil } return fmt.Errorf("pq: cannot convert %T to Int32Array", src) } func (a *Int32Array) scanBytes(src []byte) error { elems, err := scanLinearArray(src, []byte{','}, "Int32Array") if err != nil { return err } if *a != nil && len(elems) == 0 { *a = (*a)[:0] } else { b := make(Int32Array, len(elems)) for i, v := range elems { x, err := strconv.ParseInt(string(v), 10, 32) if err != nil { return fmt.Errorf("pq: parsing array element index %d: %v", i, err) } b[i] = int32(x) } *a = b } return nil } // Value implements the driver.Valuer interface. func (a Int32Array) Value() (driver.Value, error) { if a == nil { return nil, nil } if n := len(a); n > 0 { // There will be at least two curly brackets, N bytes of values, // and N-1 bytes of delimiters. b := make([]byte, 1, 1+2*n) b[0] = '{' b = strconv.AppendInt(b, int64(a[0]), 10) for i := 1; i < n; i++ { b = append(b, ',') b = strconv.AppendInt(b, int64(a[i]), 10) } return string(append(b, '}')), nil } return "{}", nil } // StringArray represents a one-dimensional array of the PostgreSQL character types. type StringArray []string // Scan implements the sql.Scanner interface. func (a *StringArray) Scan(src interface{}) error { switch src := src.(type) { case []byte: return a.scanBytes(src) case string: return a.scanBytes([]byte(src)) case nil: *a = nil return nil } return fmt.Errorf("pq: cannot convert %T to StringArray", src) } func (a *StringArray) scanBytes(src []byte) error { elems, err := scanLinearArray(src, []byte{','}, "StringArray") if err != nil { return err } if *a != nil && len(elems) == 0 { *a = (*a)[:0] } else { b := make(StringArray, len(elems)) for i, v := range elems { if b[i] = string(v); v == nil { return fmt.Errorf("pq: parsing array element index %d: cannot convert nil to string", i) } } *a = b } return nil } // Value implements the driver.Valuer interface. func (a StringArray) Value() (driver.Value, error) { if a == nil { return nil, nil } if n := len(a); n > 0 { // There will be at least two curly brackets, 2*N bytes of quotes, // and N-1 bytes of delimiters. b := make([]byte, 1, 1+3*n) b[0] = '{' b = appendArrayQuotedBytes(b, []byte(a[0])) for i := 1; i < n; i++ { b = append(b, ',') b = appendArrayQuotedBytes(b, []byte(a[i])) } return string(append(b, '}')), nil } return "{}", nil } // appendArray appends rv to the buffer, returning the extended buffer and // the delimiter used between elements. // // It panics when n <= 0 or rv's Kind is not reflect.Array nor reflect.Slice. func appendArray(b []byte, rv reflect.Value, n int) ([]byte, string, error) { var del string var err error b = append(b, '{') if b, del, err = appendArrayElement(b, rv.Index(0)); err != nil { return b, del, err } for i := 1; i < n; i++ { b = append(b, del...) if b, del, err = appendArrayElement(b, rv.Index(i)); err != nil { return b, del, err } } return append(b, '}'), del, nil } // appendArrayElement appends rv to the buffer, returning the extended buffer // and the delimiter to use before the next element. // // When rv's Kind is neither reflect.Array nor reflect.Slice, it is converted // using driver.DefaultParameterConverter and the resulting []byte or string // is double-quoted. // // See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO func appendArrayElement(b []byte, rv reflect.Value) ([]byte, string, error) { if k := rv.Kind(); k == reflect.Array || k == reflect.Slice { if t := rv.Type(); t != typeByteSlice && !t.Implements(typeDriverValuer) { if n := rv.Len(); n > 0 { return appendArray(b, rv, n) } return b, "", nil } } var del = "," var err error var iv interface{} = rv.Interface() if ad, ok := iv.(ArrayDelimiter); ok { del = ad.ArrayDelimiter() } if iv, err = driver.DefaultParameterConverter.ConvertValue(iv); err != nil { return b, del, err } switch v := iv.(type) { case nil: return append(b, "NULL"...), del, nil case []byte: return appendArrayQuotedBytes(b, v), del, nil case string: return appendArrayQuotedBytes(b, []byte(v)), del, nil } b, err = appendValue(b, iv) return b, del, err } func appendArrayQuotedBytes(b, v []byte) []byte { b = append(b, '"') for { i := bytes.IndexAny(v, `"\`) if i < 0 { b = append(b, v...) break } if i > 0 { b = append(b, v[:i]...) } b = append(b, '\\', v[i]) v = v[i+1:] } return append(b, '"') } func appendValue(b []byte, v driver.Value) ([]byte, error) { return append(b, encode(nil, v, 0)...), nil } // parseArray extracts the dimensions and elements of an array represented in // text format. Only representations emitted by the backend are supported. // Notably, whitespace around brackets and delimiters is significant, and NULL // is case-sensitive. // // See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO func parseArray(src, del []byte) (dims []int, elems [][]byte, err error) { var depth, i int if len(src) < 1 || src[0] != '{' { return nil, nil, fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '{', 0) } Open: for i < len(src) { switch src[i] { case '{': depth++ i++ case '}': elems = make([][]byte, 0) goto Close default: break Open } } dims = make([]int, i) Element: for i < len(src) { switch src[i] { case '{': if depth == len(dims) { break Element } depth++ dims[depth-1] = 0 i++ case '"': var elem = []byte{} var escape bool for i++; i < len(src); i++ { if escape { elem = append(elem, src[i]) escape = false } else { switch src[i] { default: elem = append(elem, src[i]) case '\\': escape = true case '"': elems = append(elems, elem) i++ break Element } } } default: for start := i; i < len(src); i++ { if bytes.HasPrefix(src[i:], del) || src[i] == '}' { elem := src[start:i] if len(elem) == 0 { return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) } if bytes.Equal(elem, []byte("NULL")) { elem = nil } elems = append(elems, elem) break Element } } } } for i < len(src) { if bytes.HasPrefix(src[i:], del) && depth > 0 { dims[depth-1]++ i += len(del) goto Element } else if src[i] == '}' && depth > 0 { dims[depth-1]++ depth-- i++ } else { return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) } } Close: for i < len(src) { if src[i] == '}' && depth > 0 { depth-- i++ } else { return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) } } if depth > 0 { err = fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '}', i) } if err == nil { for _, d := range dims { if (len(elems) % d) != 0 { err = fmt.Errorf("pq: multidimensional arrays must have elements with matching dimensions") } } } return } func scanLinearArray(src, del []byte, typ string) (elems [][]byte, err error) { dims, elems, err := parseArray(src, del) if err != nil { return nil, err } if len(dims) > 1 { return nil, fmt.Errorf("pq: cannot convert ARRAY%s to %s", strings.Replace(fmt.Sprint(dims), " ", "][", -1), typ) } return elems, err } ================================================ FILE: vendor/github.com/lib/pq/buf.go ================================================ package pq import ( "bytes" "encoding/binary" "github.com/lib/pq/oid" ) type readBuf []byte func (b *readBuf) int32() (n int) { n = int(int32(binary.BigEndian.Uint32(*b))) *b = (*b)[4:] return } func (b *readBuf) oid() (n oid.Oid) { n = oid.Oid(binary.BigEndian.Uint32(*b)) *b = (*b)[4:] return } // N.B: this is actually an unsigned 16-bit integer, unlike int32 func (b *readBuf) int16() (n int) { n = int(binary.BigEndian.Uint16(*b)) *b = (*b)[2:] return } func (b *readBuf) string() string { i := bytes.IndexByte(*b, 0) if i < 0 { errorf("invalid message format; expected string terminator") } s := (*b)[:i] *b = (*b)[i+1:] return string(s) } func (b *readBuf) next(n int) (v []byte) { v = (*b)[:n] *b = (*b)[n:] return } func (b *readBuf) byte() byte { return b.next(1)[0] } type writeBuf struct { buf []byte pos int } func (b *writeBuf) int32(n int) { x := make([]byte, 4) binary.BigEndian.PutUint32(x, uint32(n)) b.buf = append(b.buf, x...) } func (b *writeBuf) int16(n int) { x := make([]byte, 2) binary.BigEndian.PutUint16(x, uint16(n)) b.buf = append(b.buf, x...) } func (b *writeBuf) string(s string) { b.buf = append(append(b.buf, s...), '\000') } func (b *writeBuf) byte(c byte) { b.buf = append(b.buf, c) } func (b *writeBuf) bytes(v []byte) { b.buf = append(b.buf, v...) } func (b *writeBuf) wrap() []byte { p := b.buf[b.pos:] binary.BigEndian.PutUint32(p, uint32(len(p))) return b.buf } func (b *writeBuf) next(c byte) { p := b.buf[b.pos:] binary.BigEndian.PutUint32(p, uint32(len(p))) b.pos = len(b.buf) + 1 b.buf = append(b.buf, c, 0, 0, 0, 0) } ================================================ FILE: vendor/github.com/lib/pq/conn.go ================================================ package pq import ( "bufio" "bytes" "context" "crypto/md5" "crypto/sha256" "database/sql" "database/sql/driver" "encoding/binary" "errors" "fmt" "io" "net" "os" "os/user" "path" "path/filepath" "strconv" "strings" "sync" "time" "unicode" "github.com/lib/pq/oid" "github.com/lib/pq/scram" ) // Common error types var ( ErrNotSupported = errors.New("pq: Unsupported command") ErrInFailedTransaction = errors.New("pq: Could not complete operation in a failed transaction") ErrSSLNotSupported = errors.New("pq: SSL is not enabled on the server") ErrSSLKeyUnknownOwnership = errors.New("pq: Could not get owner information for private key, may not be properly protected") ErrSSLKeyHasWorldPermissions = errors.New("pq: Private key has world access. Permissions should be u=rw,g=r (0640) if owned by root, or u=rw (0600), or less") ErrCouldNotDetectUsername = errors.New("pq: Could not detect default username. Please provide one explicitly") errUnexpectedReady = errors.New("unexpected ReadyForQuery") errNoRowsAffected = errors.New("no RowsAffected available after the empty statement") errNoLastInsertID = errors.New("no LastInsertId available after the empty statement") ) // Compile time validation that our types implement the expected interfaces var ( _ driver.Driver = Driver{} ) // Driver is the Postgres database driver. type Driver struct{} // Open opens a new connection to the database. name is a connection string. // Most users should only use it through database/sql package from the standard // library. func (d Driver) Open(name string) (driver.Conn, error) { return Open(name) } func init() { sql.Register("postgres", &Driver{}) } type parameterStatus struct { // server version in the same format as server_version_num, or 0 if // unavailable serverVersion int // the current location based on the TimeZone value of the session, if // available currentLocation *time.Location } type transactionStatus byte const ( txnStatusIdle transactionStatus = 'I' txnStatusIdleInTransaction transactionStatus = 'T' txnStatusInFailedTransaction transactionStatus = 'E' ) func (s transactionStatus) String() string { switch s { case txnStatusIdle: return "idle" case txnStatusIdleInTransaction: return "idle in transaction" case txnStatusInFailedTransaction: return "in a failed transaction" default: errorf("unknown transactionStatus %d", s) } panic("not reached") } // Dialer is the dialer interface. It can be used to obtain more control over // how pq creates network connections. type Dialer interface { Dial(network, address string) (net.Conn, error) DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) } // DialerContext is the context-aware dialer interface. type DialerContext interface { DialContext(ctx context.Context, network, address string) (net.Conn, error) } type defaultDialer struct { d net.Dialer } func (d defaultDialer) Dial(network, address string) (net.Conn, error) { return d.d.Dial(network, address) } func (d defaultDialer) DialTimeout( network, address string, timeout time.Duration, ) (net.Conn, error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return d.DialContext(ctx, network, address) } func (d defaultDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { return d.d.DialContext(ctx, network, address) } type conn struct { c net.Conn buf *bufio.Reader namei int scratch [512]byte txnStatus transactionStatus txnFinish func() // Save connection arguments to use during CancelRequest. dialer Dialer opts values // Cancellation key data for use with CancelRequest messages. processID int secretKey int parameterStatus parameterStatus saveMessageType byte saveMessageBuffer []byte // If an error is set, this connection is bad and all public-facing // functions should return the appropriate error by calling get() // (ErrBadConn) or getForNext(). err syncErr // If set, this connection should never use the binary format when // receiving query results from prepared statements. Only provided for // debugging. disablePreparedBinaryResult bool // Whether to always send []byte parameters over as binary. Enables single // round-trip mode for non-prepared Query calls. binaryParameters bool // If true this connection is in the middle of a COPY inCopy bool // If not nil, notices will be synchronously sent here noticeHandler func(*Error) // If not nil, notifications will be synchronously sent here notificationHandler func(*Notification) // GSSAPI context gss GSS } type syncErr struct { err error sync.Mutex } // Return ErrBadConn if connection is bad. func (e *syncErr) get() error { e.Lock() defer e.Unlock() if e.err != nil { return driver.ErrBadConn } return nil } // Return the error set on the connection. Currently only used by rows.Next. func (e *syncErr) getForNext() error { e.Lock() defer e.Unlock() return e.err } // Set error, only if it isn't set yet. func (e *syncErr) set(err error) { if err == nil { panic("attempt to set nil err") } e.Lock() defer e.Unlock() if e.err == nil { e.err = err } } // Handle driver-side settings in parsed connection string. func (cn *conn) handleDriverSettings(o values) (err error) { boolSetting := func(key string, val *bool) error { if value, ok := o[key]; ok { if value == "yes" { *val = true } else if value == "no" { *val = false } else { return fmt.Errorf("unrecognized value %q for %s", value, key) } } return nil } err = boolSetting("disable_prepared_binary_result", &cn.disablePreparedBinaryResult) if err != nil { return err } return boolSetting("binary_parameters", &cn.binaryParameters) } func (cn *conn) handlePgpass(o values) { // if a password was supplied, do not process .pgpass if _, ok := o["password"]; ok { return } filename := os.Getenv("PGPASSFILE") if filename == "" { // XXX this code doesn't work on Windows where the default filename is // XXX %APPDATA%\postgresql\pgpass.conf // Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470 userHome := os.Getenv("HOME") if userHome == "" { user, err := user.Current() if err != nil { return } userHome = user.HomeDir } filename = filepath.Join(userHome, ".pgpass") } fileinfo, err := os.Stat(filename) if err != nil { return } mode := fileinfo.Mode() if mode&(0x77) != 0 { // XXX should warn about incorrect .pgpass permissions as psql does return } file, err := os.Open(filename) if err != nil { return } defer file.Close() scanner := bufio.NewScanner(io.Reader(file)) // From: https://github.com/tg/pgpass/blob/master/reader.go for scanner.Scan() { if scanText(scanner.Text(), o) { break } } } // GetFields is a helper function for scanText. func getFields(s string) []string { fs := make([]string, 0, 5) f := make([]rune, 0, len(s)) var esc bool for _, c := range s { switch { case esc: f = append(f, c) esc = false case c == '\\': esc = true case c == ':': fs = append(fs, string(f)) f = f[:0] default: f = append(f, c) } } return append(fs, string(f)) } // ScanText assists HandlePgpass in it's objective. func scanText(line string, o values) bool { hostname := o["host"] ntw, _ := network(o) port := o["port"] db := o["dbname"] username := o["user"] if len(line) == 0 || line[0] == '#' { return false } split := getFields(line) if len(split) != 5 { return false } if (split[0] == "*" || split[0] == hostname || (split[0] == "localhost" && (hostname == "" || ntw == "unix"))) && (split[1] == "*" || split[1] == port) && (split[2] == "*" || split[2] == db) && (split[3] == "*" || split[3] == username) { o["password"] = split[4] return true } return false } func (cn *conn) writeBuf(b byte) *writeBuf { cn.scratch[0] = b return &writeBuf{ buf: cn.scratch[:5], pos: 1, } } // Open opens a new connection to the database. dsn is a connection string. // Most users should only use it through database/sql package from the standard // library. func Open(dsn string) (_ driver.Conn, err error) { return DialOpen(defaultDialer{}, dsn) } // DialOpen opens a new connection to the database using a dialer. func DialOpen(d Dialer, dsn string) (_ driver.Conn, err error) { c, err := NewConnector(dsn) if err != nil { return nil, err } c.Dialer(d) return c.open(context.Background()) } func (c *Connector) open(ctx context.Context) (cn *conn, err error) { // Handle any panics during connection initialization. Note that we // specifically do *not* want to use errRecover(), as that would turn any // connection errors into ErrBadConns, hiding the real error message from // the user. defer errRecoverNoErrBadConn(&err) // Create a new values map (copy). This makes it so maps in different // connections do not reference the same underlying data structure, so it // is safe for multiple connections to concurrently write to their opts. o := make(values) for k, v := range c.opts { o[k] = v } cn = &conn{ opts: o, dialer: c.dialer, } err = cn.handleDriverSettings(o) if err != nil { return nil, err } cn.handlePgpass(o) cn.c, err = dial(ctx, c.dialer, o) if err != nil { return nil, err } err = cn.ssl(o) if err != nil { if cn.c != nil { cn.c.Close() } return nil, err } // cn.startup panics on error. Make sure we don't leak cn.c. panicking := true defer func() { if panicking { cn.c.Close() } }() cn.buf = bufio.NewReader(cn.c) cn.startup(o) // reset the deadline, in case one was set (see dial) if timeout, ok := o["connect_timeout"]; ok && timeout != "0" { err = cn.c.SetDeadline(time.Time{}) } panicking = false return cn, err } func dial(ctx context.Context, d Dialer, o values) (net.Conn, error) { network, address := network(o) // Zero or not specified means wait indefinitely. if timeout, ok := o["connect_timeout"]; ok && timeout != "0" { seconds, err := strconv.ParseInt(timeout, 10, 0) if err != nil { return nil, fmt.Errorf("invalid value for parameter connect_timeout: %s", err) } duration := time.Duration(seconds) * time.Second // connect_timeout should apply to the entire connection establishment // procedure, so we both use a timeout for the TCP connection // establishment and set a deadline for doing the initial handshake. // The deadline is then reset after startup() is done. deadline := time.Now().Add(duration) var conn net.Conn if dctx, ok := d.(DialerContext); ok { ctx, cancel := context.WithTimeout(ctx, duration) defer cancel() conn, err = dctx.DialContext(ctx, network, address) } else { conn, err = d.DialTimeout(network, address, duration) } if err != nil { return nil, err } err = conn.SetDeadline(deadline) return conn, err } if dctx, ok := d.(DialerContext); ok { return dctx.DialContext(ctx, network, address) } return d.Dial(network, address) } func network(o values) (string, string) { host := o["host"] if strings.HasPrefix(host, "/") { sockPath := path.Join(host, ".s.PGSQL."+o["port"]) return "unix", sockPath } return "tcp", net.JoinHostPort(host, o["port"]) } type values map[string]string // scanner implements a tokenizer for libpq-style option strings. type scanner struct { s []rune i int } // newScanner returns a new scanner initialized with the option string s. func newScanner(s string) *scanner { return &scanner{[]rune(s), 0} } // Next returns the next rune. // It returns 0, false if the end of the text has been reached. func (s *scanner) Next() (rune, bool) { if s.i >= len(s.s) { return 0, false } r := s.s[s.i] s.i++ return r, true } // SkipSpaces returns the next non-whitespace rune. // It returns 0, false if the end of the text has been reached. func (s *scanner) SkipSpaces() (rune, bool) { r, ok := s.Next() for unicode.IsSpace(r) && ok { r, ok = s.Next() } return r, ok } // parseOpts parses the options from name and adds them to the values. // // The parsing code is based on conninfo_parse from libpq's fe-connect.c func parseOpts(name string, o values) error { s := newScanner(name) for { var ( keyRunes, valRunes []rune r rune ok bool ) if r, ok = s.SkipSpaces(); !ok { break } // Scan the key for !unicode.IsSpace(r) && r != '=' { keyRunes = append(keyRunes, r) if r, ok = s.Next(); !ok { break } } // Skip any whitespace if we're not at the = yet if r != '=' { r, ok = s.SkipSpaces() } // The current character should be = if r != '=' || !ok { return fmt.Errorf(`missing "=" after %q in connection info string"`, string(keyRunes)) } // Skip any whitespace after the = if r, ok = s.SkipSpaces(); !ok { // If we reach the end here, the last value is just an empty string as per libpq. o[string(keyRunes)] = "" break } if r != '\'' { for !unicode.IsSpace(r) { if r == '\\' { if r, ok = s.Next(); !ok { return fmt.Errorf(`missing character after backslash`) } } valRunes = append(valRunes, r) if r, ok = s.Next(); !ok { break } } } else { quote: for { if r, ok = s.Next(); !ok { return fmt.Errorf(`unterminated quoted string literal in connection string`) } switch r { case '\'': break quote case '\\': r, _ = s.Next() fallthrough default: valRunes = append(valRunes, r) } } } o[string(keyRunes)] = string(valRunes) } return nil } func (cn *conn) isInTransaction() bool { return cn.txnStatus == txnStatusIdleInTransaction || cn.txnStatus == txnStatusInFailedTransaction } func (cn *conn) checkIsInTransaction(intxn bool) { if cn.isInTransaction() != intxn { cn.err.set(driver.ErrBadConn) errorf("unexpected transaction status %v", cn.txnStatus) } } func (cn *conn) Begin() (_ driver.Tx, err error) { return cn.begin("") } func (cn *conn) begin(mode string) (_ driver.Tx, err error) { if err := cn.err.get(); err != nil { return nil, err } defer cn.errRecover(&err) cn.checkIsInTransaction(false) _, commandTag, err := cn.simpleExec("BEGIN" + mode) if err != nil { return nil, err } if commandTag != "BEGIN" { cn.err.set(driver.ErrBadConn) return nil, fmt.Errorf("unexpected command tag %s", commandTag) } if cn.txnStatus != txnStatusIdleInTransaction { cn.err.set(driver.ErrBadConn) return nil, fmt.Errorf("unexpected transaction status %v", cn.txnStatus) } return cn, nil } func (cn *conn) closeTxn() { if finish := cn.txnFinish; finish != nil { finish() } } func (cn *conn) Commit() (err error) { defer cn.closeTxn() if err := cn.err.get(); err != nil { return err } defer cn.errRecover(&err) cn.checkIsInTransaction(true) // We don't want the client to think that everything is okay if it tries // to commit a failed transaction. However, no matter what we return, // database/sql will release this connection back into the free connection // pool so we have to abort the current transaction here. Note that you // would get the same behaviour if you issued a COMMIT in a failed // transaction, so it's also the least surprising thing to do here. if cn.txnStatus == txnStatusInFailedTransaction { if err := cn.rollback(); err != nil { return err } return ErrInFailedTransaction } _, commandTag, err := cn.simpleExec("COMMIT") if err != nil { if cn.isInTransaction() { cn.err.set(driver.ErrBadConn) } return err } if commandTag != "COMMIT" { cn.err.set(driver.ErrBadConn) return fmt.Errorf("unexpected command tag %s", commandTag) } cn.checkIsInTransaction(false) return nil } func (cn *conn) Rollback() (err error) { defer cn.closeTxn() if err := cn.err.get(); err != nil { return err } defer cn.errRecover(&err) return cn.rollback() } func (cn *conn) rollback() (err error) { cn.checkIsInTransaction(true) _, commandTag, err := cn.simpleExec("ROLLBACK") if err != nil { if cn.isInTransaction() { cn.err.set(driver.ErrBadConn) } return err } if commandTag != "ROLLBACK" { return fmt.Errorf("unexpected command tag %s", commandTag) } cn.checkIsInTransaction(false) return nil } func (cn *conn) gname() string { cn.namei++ return strconv.FormatInt(int64(cn.namei), 10) } func (cn *conn) simpleExec(q string) (res driver.Result, commandTag string, err error) { b := cn.writeBuf('Q') b.string(q) cn.send(b) for { t, r := cn.recv1() switch t { case 'C': res, commandTag = cn.parseComplete(r.string()) case 'Z': cn.processReadyForQuery(r) if res == nil && err == nil { err = errUnexpectedReady } // done return case 'E': err = parseError(r) case 'I': res = emptyRows case 'T', 'D': // ignore any results default: cn.err.set(driver.ErrBadConn) errorf("unknown response for simple query: %q", t) } } } func (cn *conn) simpleQuery(q string) (res *rows, err error) { defer cn.errRecover(&err) b := cn.writeBuf('Q') b.string(q) cn.send(b) for { t, r := cn.recv1() switch t { case 'C', 'I': // We allow queries which don't return any results through Query as // well as Exec. We still have to give database/sql a rows object // the user can close, though, to avoid connections from being // leaked. A "rows" with done=true works fine for that purpose. if err != nil { cn.err.set(driver.ErrBadConn) errorf("unexpected message %q in simple query execution", t) } if res == nil { res = &rows{ cn: cn, } } // Set the result and tag to the last command complete if there wasn't a // query already run. Although queries usually return from here and cede // control to Next, a query with zero results does not. if t == 'C' { res.result, res.tag = cn.parseComplete(r.string()) if res.colNames != nil { return } } res.done = true case 'Z': cn.processReadyForQuery(r) // done return case 'E': res = nil err = parseError(r) case 'D': if res == nil { cn.err.set(driver.ErrBadConn) errorf("unexpected DataRow in simple query execution") } // the query didn't fail; kick off to Next cn.saveMessage(t, r) return case 'T': // res might be non-nil here if we received a previous // CommandComplete, but that's fine; just overwrite it res = &rows{cn: cn} res.rowsHeader = parsePortalRowDescribe(r) // To work around a bug in QueryRow in Go 1.2 and earlier, wait // until the first DataRow has been received. default: cn.err.set(driver.ErrBadConn) errorf("unknown response for simple query: %q", t) } } } type noRows struct{} var emptyRows noRows var _ driver.Result = noRows{} func (noRows) LastInsertId() (int64, error) { return 0, errNoLastInsertID } func (noRows) RowsAffected() (int64, error) { return 0, errNoRowsAffected } // Decides which column formats to use for a prepared statement. The input is // an array of type oids, one element per result column. func decideColumnFormats( colTyps []fieldDesc, forceText bool, ) (colFmts []format, colFmtData []byte) { if len(colTyps) == 0 { return nil, colFmtDataAllText } colFmts = make([]format, len(colTyps)) if forceText { return colFmts, colFmtDataAllText } allBinary := true allText := true for i, t := range colTyps { switch t.OID { // This is the list of types to use binary mode for when receiving them // through a prepared statement. If a type appears in this list, it // must also be implemented in binaryDecode in encode.go. case oid.T_bytea: fallthrough case oid.T_int8: fallthrough case oid.T_int4: fallthrough case oid.T_int2: fallthrough case oid.T_uuid: colFmts[i] = formatBinary allText = false default: allBinary = false } } if allBinary { return colFmts, colFmtDataAllBinary } else if allText { return colFmts, colFmtDataAllText } else { colFmtData = make([]byte, 2+len(colFmts)*2) binary.BigEndian.PutUint16(colFmtData, uint16(len(colFmts))) for i, v := range colFmts { binary.BigEndian.PutUint16(colFmtData[2+i*2:], uint16(v)) } return colFmts, colFmtData } } func (cn *conn) prepareTo(q, stmtName string) *stmt { st := &stmt{cn: cn, name: stmtName} b := cn.writeBuf('P') b.string(st.name) b.string(q) b.int16(0) b.next('D') b.byte('S') b.string(st.name) b.next('S') cn.send(b) cn.readParseResponse() st.paramTyps, st.colNames, st.colTyps = cn.readStatementDescribeResponse() st.colFmts, st.colFmtData = decideColumnFormats(st.colTyps, cn.disablePreparedBinaryResult) cn.readReadyForQuery() return st } func (cn *conn) Prepare(q string) (_ driver.Stmt, err error) { if err := cn.err.get(); err != nil { return nil, err } defer cn.errRecover(&err) if len(q) >= 4 && strings.EqualFold(q[:4], "COPY") { s, err := cn.prepareCopyIn(q) if err == nil { cn.inCopy = true } return s, err } return cn.prepareTo(q, cn.gname()), nil } func (cn *conn) Close() (err error) { // Skip cn.bad return here because we always want to close a connection. defer cn.errRecover(&err) // Ensure that cn.c.Close is always run. Since error handling is done with // panics and cn.errRecover, the Close must be in a defer. defer func() { cerr := cn.c.Close() if err == nil { err = cerr } }() // Don't go through send(); ListenerConn relies on us not scribbling on the // scratch buffer of this connection. return cn.sendSimpleMessage('X') } // Implement the "Queryer" interface func (cn *conn) Query(query string, args []driver.Value) (driver.Rows, error) { return cn.query(query, args) } func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) { if err := cn.err.get(); err != nil { return nil, err } if cn.inCopy { return nil, errCopyInProgress } defer cn.errRecover(&err) // Check to see if we can use the "simpleQuery" interface, which is // *much* faster than going through prepare/exec if len(args) == 0 { return cn.simpleQuery(query) } if cn.binaryParameters { cn.sendBinaryModeQuery(query, args) cn.readParseResponse() cn.readBindResponse() rows := &rows{cn: cn} rows.rowsHeader = cn.readPortalDescribeResponse() cn.postExecuteWorkaround() return rows, nil } st := cn.prepareTo(query, "") st.exec(args) return &rows{ cn: cn, rowsHeader: st.rowsHeader, }, nil } // Implement the optional "Execer" interface for one-shot queries func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err error) { if err := cn.err.get(); err != nil { return nil, err } defer cn.errRecover(&err) // Check to see if we can use the "simpleExec" interface, which is // *much* faster than going through prepare/exec if len(args) == 0 { // ignore commandTag, our caller doesn't care r, _, err := cn.simpleExec(query) return r, err } if cn.binaryParameters { cn.sendBinaryModeQuery(query, args) cn.readParseResponse() cn.readBindResponse() cn.readPortalDescribeResponse() cn.postExecuteWorkaround() res, _, err = cn.readExecuteResponse("Execute") return res, err } // Use the unnamed statement to defer planning until bind // time, or else value-based selectivity estimates cannot be // used. st := cn.prepareTo(query, "") r, err := st.Exec(args) if err != nil { panic(err) } return r, err } type safeRetryError struct { Err error } func (se *safeRetryError) Error() string { return se.Err.Error() } func (cn *conn) send(m *writeBuf) { n, err := cn.c.Write(m.wrap()) if err != nil { if n == 0 { err = &safeRetryError{Err: err} } panic(err) } } func (cn *conn) sendStartupPacket(m *writeBuf) error { _, err := cn.c.Write((m.wrap())[1:]) return err } // Send a message of type typ to the server on the other end of cn. The // message should have no payload. This method does not use the scratch // buffer. func (cn *conn) sendSimpleMessage(typ byte) (err error) { _, err = cn.c.Write([]byte{typ, '\x00', '\x00', '\x00', '\x04'}) return err } // saveMessage memorizes a message and its buffer in the conn struct. // recvMessage will then return these values on the next call to it. This // method is useful in cases where you have to see what the next message is // going to be (e.g. to see whether it's an error or not) but you can't handle // the message yourself. func (cn *conn) saveMessage(typ byte, buf *readBuf) { if cn.saveMessageType != 0 { cn.err.set(driver.ErrBadConn) errorf("unexpected saveMessageType %d", cn.saveMessageType) } cn.saveMessageType = typ cn.saveMessageBuffer = *buf } // recvMessage receives any message from the backend, or returns an error if // a problem occurred while reading the message. func (cn *conn) recvMessage(r *readBuf) (byte, error) { // workaround for a QueryRow bug, see exec if cn.saveMessageType != 0 { t := cn.saveMessageType *r = cn.saveMessageBuffer cn.saveMessageType = 0 cn.saveMessageBuffer = nil return t, nil } x := cn.scratch[:5] _, err := io.ReadFull(cn.buf, x) if err != nil { return 0, err } // read the type and length of the message that follows t := x[0] n := int(binary.BigEndian.Uint32(x[1:])) - 4 var y []byte if n <= len(cn.scratch) { y = cn.scratch[:n] } else { y = make([]byte, n) } _, err = io.ReadFull(cn.buf, y) if err != nil { return 0, err } *r = y return t, nil } // recv receives a message from the backend, but if an error happened while // reading the message or the received message was an ErrorResponse, it panics. // NoticeResponses are ignored. This function should generally be used only // during the startup sequence. func (cn *conn) recv() (t byte, r *readBuf) { for { var err error r = &readBuf{} t, err = cn.recvMessage(r) if err != nil { panic(err) } switch t { case 'E': panic(parseError(r)) case 'N': if n := cn.noticeHandler; n != nil { n(parseError(r)) } case 'A': if n := cn.notificationHandler; n != nil { n(recvNotification(r)) } default: return } } } // recv1Buf is exactly equivalent to recv1, except it uses a buffer supplied by // the caller to avoid an allocation. func (cn *conn) recv1Buf(r *readBuf) byte { for { t, err := cn.recvMessage(r) if err != nil { panic(err) } switch t { case 'A': if n := cn.notificationHandler; n != nil { n(recvNotification(r)) } case 'N': if n := cn.noticeHandler; n != nil { n(parseError(r)) } case 'S': cn.processParameterStatus(r) default: return t } } } // recv1 receives a message from the backend, panicking if an error occurs // while attempting to read it. All asynchronous messages are ignored, with // the exception of ErrorResponse. func (cn *conn) recv1() (t byte, r *readBuf) { r = &readBuf{} t = cn.recv1Buf(r) return t, r } func (cn *conn) ssl(o values) error { upgrade, err := ssl(o) if err != nil { return err } if upgrade == nil { // Nothing to do return nil } w := cn.writeBuf(0) w.int32(80877103) if err = cn.sendStartupPacket(w); err != nil { return err } b := cn.scratch[:1] _, err = io.ReadFull(cn.c, b) if err != nil { return err } if b[0] != 'S' { return ErrSSLNotSupported } cn.c, err = upgrade(cn.c) return err } // isDriverSetting returns true iff a setting is purely for configuring the // driver's options and should not be sent to the server in the connection // startup packet. func isDriverSetting(key string) bool { switch key { case "host", "port": return true case "password": return true case "sslmode", "sslcert", "sslkey", "sslrootcert", "sslinline", "sslsni": return true case "fallback_application_name": return true case "connect_timeout": return true case "disable_prepared_binary_result": return true case "binary_parameters": return true case "krbsrvname": return true case "krbspn": return true default: return false } } func (cn *conn) startup(o values) { w := cn.writeBuf(0) w.int32(196608) // Send the backend the name of the database we want to connect to, and the // user we want to connect as. Additionally, we send over any run-time // parameters potentially included in the connection string. If the server // doesn't recognize any of them, it will reply with an error. for k, v := range o { if isDriverSetting(k) { // skip options which can't be run-time parameters continue } // The protocol requires us to supply the database name as "database" // instead of "dbname". if k == "dbname" { k = "database" } w.string(k) w.string(v) } w.string("") if err := cn.sendStartupPacket(w); err != nil { panic(err) } for { t, r := cn.recv() switch t { case 'K': cn.processBackendKeyData(r) case 'S': cn.processParameterStatus(r) case 'R': cn.auth(r, o) case 'Z': cn.processReadyForQuery(r) return default: errorf("unknown response for startup: %q", t) } } } func (cn *conn) auth(r *readBuf, o values) { switch code := r.int32(); code { case 0: // OK case 3: w := cn.writeBuf('p') w.string(o["password"]) cn.send(w) t, r := cn.recv() if t != 'R' { errorf("unexpected password response: %q", t) } if r.int32() != 0 { errorf("unexpected authentication response: %q", t) } case 5: s := string(r.next(4)) w := cn.writeBuf('p') w.string("md5" + md5s(md5s(o["password"]+o["user"])+s)) cn.send(w) t, r := cn.recv() if t != 'R' { errorf("unexpected password response: %q", t) } if r.int32() != 0 { errorf("unexpected authentication response: %q", t) } case 7: // GSSAPI, startup if newGss == nil { errorf("kerberos error: no GSSAPI provider registered (import github.com/lib/pq/auth/kerberos if you need Kerberos support)") } cli, err := newGss() if err != nil { errorf("kerberos error: %s", err.Error()) } var token []byte if spn, ok := o["krbspn"]; ok { // Use the supplied SPN if provided.. token, err = cli.GetInitTokenFromSpn(spn) } else { // Allow the kerberos service name to be overridden service := "postgres" if val, ok := o["krbsrvname"]; ok { service = val } token, err = cli.GetInitToken(o["host"], service) } if err != nil { errorf("failed to get Kerberos ticket: %q", err) } w := cn.writeBuf('p') w.bytes(token) cn.send(w) // Store for GSSAPI continue message cn.gss = cli case 8: // GSSAPI continue if cn.gss == nil { errorf("GSSAPI protocol error") } b := []byte(*r) done, tokOut, err := cn.gss.Continue(b) if err == nil && !done { w := cn.writeBuf('p') w.bytes(tokOut) cn.send(w) } // Errors fall through and read the more detailed message // from the server.. case 10: sc := scram.NewClient(sha256.New, o["user"], o["password"]) sc.Step(nil) if sc.Err() != nil { errorf("SCRAM-SHA-256 error: %s", sc.Err().Error()) } scOut := sc.Out() w := cn.writeBuf('p') w.string("SCRAM-SHA-256") w.int32(len(scOut)) w.bytes(scOut) cn.send(w) t, r := cn.recv() if t != 'R' { errorf("unexpected password response: %q", t) } if r.int32() != 11 { errorf("unexpected authentication response: %q", t) } nextStep := r.next(len(*r)) sc.Step(nextStep) if sc.Err() != nil { errorf("SCRAM-SHA-256 error: %s", sc.Err().Error()) } scOut = sc.Out() w = cn.writeBuf('p') w.bytes(scOut) cn.send(w) t, r = cn.recv() if t != 'R' { errorf("unexpected password response: %q", t) } if r.int32() != 12 { errorf("unexpected authentication response: %q", t) } nextStep = r.next(len(*r)) sc.Step(nextStep) if sc.Err() != nil { errorf("SCRAM-SHA-256 error: %s", sc.Err().Error()) } default: errorf("unknown authentication response: %d", code) } } type format int const formatText format = 0 const formatBinary format = 1 // One result-column format code with the value 1 (i.e. all binary). var colFmtDataAllBinary = []byte{0, 1, 0, 1} // No result-column format codes (i.e. all text). var colFmtDataAllText = []byte{0, 0} type stmt struct { cn *conn name string rowsHeader colFmtData []byte paramTyps []oid.Oid closed bool } func (st *stmt) Close() (err error) { if st.closed { return nil } if err := st.cn.err.get(); err != nil { return err } defer st.cn.errRecover(&err) w := st.cn.writeBuf('C') w.byte('S') w.string(st.name) st.cn.send(w) st.cn.send(st.cn.writeBuf('S')) t, _ := st.cn.recv1() if t != '3' { st.cn.err.set(driver.ErrBadConn) errorf("unexpected close response: %q", t) } st.closed = true t, r := st.cn.recv1() if t != 'Z' { st.cn.err.set(driver.ErrBadConn) errorf("expected ready for query, but got: %q", t) } st.cn.processReadyForQuery(r) return nil } func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) { return st.query(v) } func (st *stmt) query(v []driver.Value) (r *rows, err error) { if err := st.cn.err.get(); err != nil { return nil, err } defer st.cn.errRecover(&err) st.exec(v) return &rows{ cn: st.cn, rowsHeader: st.rowsHeader, }, nil } func (st *stmt) Exec(v []driver.Value) (res driver.Result, err error) { if err := st.cn.err.get(); err != nil { return nil, err } defer st.cn.errRecover(&err) st.exec(v) res, _, err = st.cn.readExecuteResponse("simple query") return res, err } func (st *stmt) exec(v []driver.Value) { if len(v) >= 65536 { errorf("got %d parameters but PostgreSQL only supports 65535 parameters", len(v)) } if len(v) != len(st.paramTyps) { errorf("got %d parameters but the statement requires %d", len(v), len(st.paramTyps)) } cn := st.cn w := cn.writeBuf('B') w.byte(0) // unnamed portal w.string(st.name) if cn.binaryParameters { cn.sendBinaryParameters(w, v) } else { w.int16(0) w.int16(len(v)) for i, x := range v { if x == nil { w.int32(-1) } else { b := encode(&cn.parameterStatus, x, st.paramTyps[i]) w.int32(len(b)) w.bytes(b) } } } w.bytes(st.colFmtData) w.next('E') w.byte(0) w.int32(0) w.next('S') cn.send(w) cn.readBindResponse() cn.postExecuteWorkaround() } func (st *stmt) NumInput() int { return len(st.paramTyps) } // parseComplete parses the "command tag" from a CommandComplete message, and // returns the number of rows affected (if applicable) and a string // identifying only the command that was executed, e.g. "ALTER TABLE". If the // command tag could not be parsed, parseComplete panics. func (cn *conn) parseComplete(commandTag string) (driver.Result, string) { commandsWithAffectedRows := []string{ "SELECT ", // INSERT is handled below "UPDATE ", "DELETE ", "FETCH ", "MOVE ", "COPY ", } var affectedRows *string for _, tag := range commandsWithAffectedRows { if strings.HasPrefix(commandTag, tag) { t := commandTag[len(tag):] affectedRows = &t commandTag = tag[:len(tag)-1] break } } // INSERT also includes the oid of the inserted row in its command tag. // Oids in user tables are deprecated, and the oid is only returned when // exactly one row is inserted, so it's unlikely to be of value to any // real-world application and we can ignore it. if affectedRows == nil && strings.HasPrefix(commandTag, "INSERT ") { parts := strings.Split(commandTag, " ") if len(parts) != 3 { cn.err.set(driver.ErrBadConn) errorf("unexpected INSERT command tag %s", commandTag) } affectedRows = &parts[len(parts)-1] commandTag = "INSERT" } // There should be no affected rows attached to the tag, just return it if affectedRows == nil { return driver.RowsAffected(0), commandTag } n, err := strconv.ParseInt(*affectedRows, 10, 64) if err != nil { cn.err.set(driver.ErrBadConn) errorf("could not parse commandTag: %s", err) } return driver.RowsAffected(n), commandTag } type rowsHeader struct { colNames []string colTyps []fieldDesc colFmts []format } type rows struct { cn *conn finish func() rowsHeader done bool rb readBuf result driver.Result tag string next *rowsHeader } func (rs *rows) Close() error { if finish := rs.finish; finish != nil { defer finish() } // no need to look at cn.bad as Next() will for { err := rs.Next(nil) switch err { case nil: case io.EOF: // rs.Next can return io.EOF on both 'Z' (ready for query) and 'T' (row // description, used with HasNextResultSet). We need to fetch messages until // we hit a 'Z', which is done by waiting for done to be set. if rs.done { return nil } default: return err } } } func (rs *rows) Columns() []string { return rs.colNames } func (rs *rows) Result() driver.Result { if rs.result == nil { return emptyRows } return rs.result } func (rs *rows) Tag() string { return rs.tag } func (rs *rows) Next(dest []driver.Value) (err error) { if rs.done { return io.EOF } conn := rs.cn if err := conn.err.getForNext(); err != nil { return err } defer conn.errRecover(&err) for { t := conn.recv1Buf(&rs.rb) switch t { case 'E': err = parseError(&rs.rb) case 'C', 'I': if t == 'C' { rs.result, rs.tag = conn.parseComplete(rs.rb.string()) } continue case 'Z': conn.processReadyForQuery(&rs.rb) rs.done = true if err != nil { return err } return io.EOF case 'D': n := rs.rb.int16() if err != nil { conn.err.set(driver.ErrBadConn) errorf("unexpected DataRow after error %s", err) } if n < len(dest) { dest = dest[:n] } for i := range dest { l := rs.rb.int32() if l == -1 { dest[i] = nil continue } dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i].OID, rs.colFmts[i]) } return case 'T': next := parsePortalRowDescribe(&rs.rb) rs.next = &next return io.EOF default: errorf("unexpected message after execute: %q", t) } } } func (rs *rows) HasNextResultSet() bool { hasNext := rs.next != nil && !rs.done return hasNext } func (rs *rows) NextResultSet() error { if rs.next == nil { return io.EOF } rs.rowsHeader = *rs.next rs.next = nil return nil } // QuoteIdentifier quotes an "identifier" (e.g. a table or a column name) to be // used as part of an SQL statement. For example: // // tblname := "my_table" // data := "my_data" // quoted := pq.QuoteIdentifier(tblname) // err := db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", quoted), data) // // Any double quotes in name will be escaped. The quoted identifier will be // case sensitive when used in a query. If the input string contains a zero // byte, the result will be truncated immediately before it. func QuoteIdentifier(name string) string { end := strings.IndexRune(name, 0) if end > -1 { name = name[:end] } return `"` + strings.Replace(name, `"`, `""`, -1) + `"` } // BufferQuoteIdentifier satisfies the same purpose as QuoteIdentifier, but backed by a // byte buffer. func BufferQuoteIdentifier(name string, buffer *bytes.Buffer) { end := strings.IndexRune(name, 0) if end > -1 { name = name[:end] } buffer.WriteRune('"') buffer.WriteString(strings.Replace(name, `"`, `""`, -1)) buffer.WriteRune('"') } // QuoteLiteral quotes a 'literal' (e.g. a parameter, often used to pass literal // to DDL and other statements that do not accept parameters) to be used as part // of an SQL statement. For example: // // exp_date := pq.QuoteLiteral("2023-01-05 15:00:00Z") // err := db.Exec(fmt.Sprintf("CREATE ROLE my_user VALID UNTIL %s", exp_date)) // // Any single quotes in name will be escaped. Any backslashes (i.e. "\") will be // replaced by two backslashes (i.e. "\\") and the C-style escape identifier // that PostgreSQL provides ('E') will be prepended to the string. func QuoteLiteral(literal string) string { // This follows the PostgreSQL internal algorithm for handling quoted literals // from libpq, which can be found in the "PQEscapeStringInternal" function, // which is found in the libpq/fe-exec.c source file: // https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/interfaces/libpq/fe-exec.c // // substitute any single-quotes (') with two single-quotes ('') literal = strings.Replace(literal, `'`, `''`, -1) // determine if the string has any backslashes (\) in it. // if it does, replace any backslashes (\) with two backslashes (\\) // then, we need to wrap the entire string with a PostgreSQL // C-style escape. Per how "PQEscapeStringInternal" handles this case, we // also add a space before the "E" if strings.Contains(literal, `\`) { literal = strings.Replace(literal, `\`, `\\`, -1) literal = ` E'` + literal + `'` } else { // otherwise, we can just wrap the literal with a pair of single quotes literal = `'` + literal + `'` } return literal } func md5s(s string) string { h := md5.New() h.Write([]byte(s)) return fmt.Sprintf("%x", h.Sum(nil)) } func (cn *conn) sendBinaryParameters(b *writeBuf, args []driver.Value) { // Do one pass over the parameters to see if we're going to send any of // them over in binary. If we are, create a paramFormats array at the // same time. var paramFormats []int for i, x := range args { _, ok := x.([]byte) if ok { if paramFormats == nil { paramFormats = make([]int, len(args)) } paramFormats[i] = 1 } } if paramFormats == nil { b.int16(0) } else { b.int16(len(paramFormats)) for _, x := range paramFormats { b.int16(x) } } b.int16(len(args)) for _, x := range args { if x == nil { b.int32(-1) } else { datum := binaryEncode(&cn.parameterStatus, x) b.int32(len(datum)) b.bytes(datum) } } } func (cn *conn) sendBinaryModeQuery(query string, args []driver.Value) { if len(args) >= 65536 { errorf("got %d parameters but PostgreSQL only supports 65535 parameters", len(args)) } b := cn.writeBuf('P') b.byte(0) // unnamed statement b.string(query) b.int16(0) b.next('B') b.int16(0) // unnamed portal and statement cn.sendBinaryParameters(b, args) b.bytes(colFmtDataAllText) b.next('D') b.byte('P') b.byte(0) // unnamed portal b.next('E') b.byte(0) b.int32(0) b.next('S') cn.send(b) } func (cn *conn) processParameterStatus(r *readBuf) { var err error param := r.string() switch param { case "server_version": var major1 int var major2 int _, err = fmt.Sscanf(r.string(), "%d.%d", &major1, &major2) if err == nil { cn.parameterStatus.serverVersion = major1*10000 + major2*100 } case "TimeZone": cn.parameterStatus.currentLocation, err = time.LoadLocation(r.string()) if err != nil { cn.parameterStatus.currentLocation = nil } default: // ignore } } func (cn *conn) processReadyForQuery(r *readBuf) { cn.txnStatus = transactionStatus(r.byte()) } func (cn *conn) readReadyForQuery() { t, r := cn.recv1() switch t { case 'Z': cn.processReadyForQuery(r) return default: cn.err.set(driver.ErrBadConn) errorf("unexpected message %q; expected ReadyForQuery", t) } } func (cn *conn) processBackendKeyData(r *readBuf) { cn.processID = r.int32() cn.secretKey = r.int32() } func (cn *conn) readParseResponse() { t, r := cn.recv1() switch t { case '1': return case 'E': err := parseError(r) cn.readReadyForQuery() panic(err) default: cn.err.set(driver.ErrBadConn) errorf("unexpected Parse response %q", t) } } func (cn *conn) readStatementDescribeResponse() ( paramTyps []oid.Oid, colNames []string, colTyps []fieldDesc, ) { for { t, r := cn.recv1() switch t { case 't': nparams := r.int16() paramTyps = make([]oid.Oid, nparams) for i := range paramTyps { paramTyps[i] = r.oid() } case 'n': return paramTyps, nil, nil case 'T': colNames, colTyps = parseStatementRowDescribe(r) return paramTyps, colNames, colTyps case 'E': err := parseError(r) cn.readReadyForQuery() panic(err) default: cn.err.set(driver.ErrBadConn) errorf("unexpected Describe statement response %q", t) } } } func (cn *conn) readPortalDescribeResponse() rowsHeader { t, r := cn.recv1() switch t { case 'T': return parsePortalRowDescribe(r) case 'n': return rowsHeader{} case 'E': err := parseError(r) cn.readReadyForQuery() panic(err) default: cn.err.set(driver.ErrBadConn) errorf("unexpected Describe response %q", t) } panic("not reached") } func (cn *conn) readBindResponse() { t, r := cn.recv1() switch t { case '2': return case 'E': err := parseError(r) cn.readReadyForQuery() panic(err) default: cn.err.set(driver.ErrBadConn) errorf("unexpected Bind response %q", t) } } func (cn *conn) postExecuteWorkaround() { // Work around a bug in sql.DB.QueryRow: in Go 1.2 and earlier it ignores // any errors from rows.Next, which masks errors that happened during the // execution of the query. To avoid the problem in common cases, we wait // here for one more message from the database. If it's not an error the // query will likely succeed (or perhaps has already, if it's a // CommandComplete), so we push the message into the conn struct; recv1 // will return it as the next message for rows.Next or rows.Close. // However, if it's an error, we wait until ReadyForQuery and then return // the error to our caller. for { t, r := cn.recv1() switch t { case 'E': err := parseError(r) cn.readReadyForQuery() panic(err) case 'C', 'D', 'I': // the query didn't fail, but we can't process this message cn.saveMessage(t, r) return default: cn.err.set(driver.ErrBadConn) errorf("unexpected message during extended query execution: %q", t) } } } // Only for Exec(), since we ignore the returned data func (cn *conn) readExecuteResponse( protocolState string, ) (res driver.Result, commandTag string, err error) { for { t, r := cn.recv1() switch t { case 'C': if err != nil { cn.err.set(driver.ErrBadConn) errorf("unexpected CommandComplete after error %s", err) } res, commandTag = cn.parseComplete(r.string()) case 'Z': cn.processReadyForQuery(r) if res == nil && err == nil { err = errUnexpectedReady } return res, commandTag, err case 'E': err = parseError(r) case 'T', 'D', 'I': if err != nil { cn.err.set(driver.ErrBadConn) errorf("unexpected %q after error %s", t, err) } if t == 'I' { res = emptyRows } // ignore any results default: cn.err.set(driver.ErrBadConn) errorf("unknown %s response: %q", protocolState, t) } } } func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []fieldDesc) { n := r.int16() colNames = make([]string, n) colTyps = make([]fieldDesc, n) for i := range colNames { colNames[i] = r.string() r.next(6) colTyps[i].OID = r.oid() colTyps[i].Len = r.int16() colTyps[i].Mod = r.int32() // format code not known when describing a statement; always 0 r.next(2) } return } func parsePortalRowDescribe(r *readBuf) rowsHeader { n := r.int16() colNames := make([]string, n) colFmts := make([]format, n) colTyps := make([]fieldDesc, n) for i := range colNames { colNames[i] = r.string() r.next(6) colTyps[i].OID = r.oid() colTyps[i].Len = r.int16() colTyps[i].Mod = r.int32() colFmts[i] = format(r.int16()) } return rowsHeader{ colNames: colNames, colFmts: colFmts, colTyps: colTyps, } } // parseEnviron tries to mimic some of libpq's environment handling // // To ease testing, it does not directly reference os.Environ, but is // designed to accept its output. // // Environment-set connection information is intended to have a higher // precedence than a library default but lower than any explicitly // passed information (such as in the URL or connection string). func parseEnviron(env []string) (out map[string]string) { out = make(map[string]string) for _, v := range env { parts := strings.SplitN(v, "=", 2) accrue := func(keyname string) { out[keyname] = parts[1] } unsupported := func() { panic(fmt.Sprintf("setting %v not supported", parts[0])) } // The order of these is the same as is seen in the // PostgreSQL 9.1 manual. Unsupported but well-defined // keys cause a panic; these should be unset prior to // execution. Options which pq expects to be set to a // certain value are allowed, but must be set to that // value if present (they can, of course, be absent). switch parts[0] { case "PGHOST": accrue("host") case "PGHOSTADDR": unsupported() case "PGPORT": accrue("port") case "PGDATABASE": accrue("dbname") case "PGUSER": accrue("user") case "PGPASSWORD": accrue("password") case "PGSERVICE", "PGSERVICEFILE", "PGREALM": unsupported() case "PGOPTIONS": accrue("options") case "PGAPPNAME": accrue("application_name") case "PGSSLMODE": accrue("sslmode") case "PGSSLCERT": accrue("sslcert") case "PGSSLKEY": accrue("sslkey") case "PGSSLROOTCERT": accrue("sslrootcert") case "PGSSLSNI": accrue("sslsni") case "PGREQUIRESSL", "PGSSLCRL": unsupported() case "PGREQUIREPEER": unsupported() case "PGKRBSRVNAME", "PGGSSLIB": unsupported() case "PGCONNECT_TIMEOUT": accrue("connect_timeout") case "PGCLIENTENCODING": accrue("client_encoding") case "PGDATESTYLE": accrue("datestyle") case "PGTZ": accrue("timezone") case "PGGEQO": accrue("geqo") case "PGSYSCONFDIR", "PGLOCALEDIR": unsupported() } } return out } // isUTF8 returns whether name is a fuzzy variation of the string "UTF-8". func isUTF8(name string) bool { // Recognize all sorts of silly things as "UTF-8", like Postgres does s := strings.Map(alnumLowerASCII, name) return s == "utf8" || s == "unicode" } func alnumLowerASCII(ch rune) rune { if 'A' <= ch && ch <= 'Z' { return ch + ('a' - 'A') } if 'a' <= ch && ch <= 'z' || '0' <= ch && ch <= '9' { return ch } return -1 // discard } // The database/sql/driver package says: // All Conn implementations should implement the following interfaces: Pinger, SessionResetter, and Validator. var _ driver.Pinger = &conn{} var _ driver.SessionResetter = &conn{} func (cn *conn) ResetSession(ctx context.Context) error { // Ensure bad connections are reported: From database/sql/driver: // If a connection is never returned to the connection pool but immediately reused, then // ResetSession is called prior to reuse but IsValid is not called. return cn.err.get() } func (cn *conn) IsValid() bool { return cn.err.get() == nil } ================================================ FILE: vendor/github.com/lib/pq/conn_go115.go ================================================ //go:build go1.15 // +build go1.15 package pq import "database/sql/driver" var _ driver.Validator = &conn{} ================================================ FILE: vendor/github.com/lib/pq/conn_go18.go ================================================ package pq import ( "context" "database/sql" "database/sql/driver" "fmt" "io" "io/ioutil" "time" ) const ( watchCancelDialContextTimeout = time.Second * 10 ) // Implement the "QueryerContext" interface func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { list := make([]driver.Value, len(args)) for i, nv := range args { list[i] = nv.Value } finish := cn.watchCancel(ctx) r, err := cn.query(query, list) if err != nil { if finish != nil { finish() } return nil, err } r.finish = finish return r, nil } // Implement the "ExecerContext" interface func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { list := make([]driver.Value, len(args)) for i, nv := range args { list[i] = nv.Value } if finish := cn.watchCancel(ctx); finish != nil { defer finish() } return cn.Exec(query, list) } // Implement the "ConnPrepareContext" interface func (cn *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { if finish := cn.watchCancel(ctx); finish != nil { defer finish() } return cn.Prepare(query) } // Implement the "ConnBeginTx" interface func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { var mode string switch sql.IsolationLevel(opts.Isolation) { case sql.LevelDefault: // Don't touch mode: use the server's default case sql.LevelReadUncommitted: mode = " ISOLATION LEVEL READ UNCOMMITTED" case sql.LevelReadCommitted: mode = " ISOLATION LEVEL READ COMMITTED" case sql.LevelRepeatableRead: mode = " ISOLATION LEVEL REPEATABLE READ" case sql.LevelSerializable: mode = " ISOLATION LEVEL SERIALIZABLE" default: return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation) } if opts.ReadOnly { mode += " READ ONLY" } else { mode += " READ WRITE" } tx, err := cn.begin(mode) if err != nil { return nil, err } cn.txnFinish = cn.watchCancel(ctx) return tx, nil } func (cn *conn) Ping(ctx context.Context) error { if finish := cn.watchCancel(ctx); finish != nil { defer finish() } rows, err := cn.simpleQuery(";") if err != nil { return driver.ErrBadConn // https://golang.org/pkg/database/sql/driver/#Pinger } rows.Close() return nil } func (cn *conn) watchCancel(ctx context.Context) func() { if done := ctx.Done(); done != nil { finished := make(chan struct{}, 1) go func() { select { case <-done: select { case finished <- struct{}{}: default: // We raced with the finish func, let the next query handle this with the // context. return } // Set the connection state to bad so it does not get reused. cn.err.set(ctx.Err()) // At this point the function level context is canceled, // so it must not be used for the additional network // request to cancel the query. // Create a new context to pass into the dial. ctxCancel, cancel := context.WithTimeout(context.Background(), watchCancelDialContextTimeout) defer cancel() _ = cn.cancel(ctxCancel) case <-finished: } }() return func() { select { case <-finished: cn.err.set(ctx.Err()) cn.Close() case finished <- struct{}{}: } } } return nil } func (cn *conn) cancel(ctx context.Context) error { // Create a new values map (copy). This makes sure the connection created // in this method cannot write to the same underlying data, which could // cause a concurrent map write panic. This is necessary because cancel // is called from a goroutine in watchCancel. o := make(values) for k, v := range cn.opts { o[k] = v } c, err := dial(ctx, cn.dialer, o) if err != nil { return err } defer c.Close() { can := conn{ c: c, } err = can.ssl(o) if err != nil { return err } w := can.writeBuf(0) w.int32(80877102) // cancel request code w.int32(cn.processID) w.int32(cn.secretKey) if err := can.sendStartupPacket(w); err != nil { return err } } // Read until EOF to ensure that the server received the cancel. { _, err := io.Copy(ioutil.Discard, c) return err } } // Implement the "StmtQueryContext" interface func (st *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { list := make([]driver.Value, len(args)) for i, nv := range args { list[i] = nv.Value } finish := st.watchCancel(ctx) r, err := st.query(list) if err != nil { if finish != nil { finish() } return nil, err } r.finish = finish return r, nil } // Implement the "StmtExecContext" interface func (st *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { list := make([]driver.Value, len(args)) for i, nv := range args { list[i] = nv.Value } if finish := st.watchCancel(ctx); finish != nil { defer finish() } return st.Exec(list) } // watchCancel is implemented on stmt in order to not mark the parent conn as bad func (st *stmt) watchCancel(ctx context.Context) func() { if done := ctx.Done(); done != nil { finished := make(chan struct{}) go func() { select { case <-done: // At this point the function level context is canceled, // so it must not be used for the additional network // request to cancel the query. // Create a new context to pass into the dial. ctxCancel, cancel := context.WithTimeout(context.Background(), watchCancelDialContextTimeout) defer cancel() _ = st.cancel(ctxCancel) finished <- struct{}{} case <-finished: } }() return func() { select { case <-finished: case finished <- struct{}{}: } } } return nil } func (st *stmt) cancel(ctx context.Context) error { return st.cn.cancel(ctx) } ================================================ FILE: vendor/github.com/lib/pq/connector.go ================================================ package pq import ( "context" "database/sql/driver" "errors" "fmt" "os" "strings" ) // Connector represents a fixed configuration for the pq driver with a given // name. Connector satisfies the database/sql/driver Connector interface and // can be used to create any number of DB Conn's via the database/sql OpenDB // function. // // See https://golang.org/pkg/database/sql/driver/#Connector. // See https://golang.org/pkg/database/sql/#OpenDB. type Connector struct { opts values dialer Dialer } // Connect returns a connection to the database using the fixed configuration // of this Connector. Context is not used. func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) { return c.open(ctx) } // Dialer allows change the dialer used to open connections. func (c *Connector) Dialer(dialer Dialer) { c.dialer = dialer } // Driver returns the underlying driver of this Connector. func (c *Connector) Driver() driver.Driver { return &Driver{} } // NewConnector returns a connector for the pq driver in a fixed configuration // with the given dsn. The returned connector can be used to create any number // of equivalent Conn's. The returned connector is intended to be used with // database/sql.OpenDB. // // See https://golang.org/pkg/database/sql/driver/#Connector. // See https://golang.org/pkg/database/sql/#OpenDB. func NewConnector(dsn string) (*Connector, error) { var err error o := make(values) // A number of defaults are applied here, in this order: // // * Very low precedence defaults applied in every situation // * Environment variables // * Explicitly passed connection information o["host"] = "localhost" o["port"] = "5432" // N.B.: Extra float digits should be set to 3, but that breaks // Postgres 8.4 and older, where the max is 2. o["extra_float_digits"] = "2" for k, v := range parseEnviron(os.Environ()) { o[k] = v } if strings.HasPrefix(dsn, "postgres://") || strings.HasPrefix(dsn, "postgresql://") { dsn, err = ParseURL(dsn) if err != nil { return nil, err } } if err := parseOpts(dsn, o); err != nil { return nil, err } // Use the "fallback" application name if necessary if fallback, ok := o["fallback_application_name"]; ok { if _, ok := o["application_name"]; !ok { o["application_name"] = fallback } } // We can't work with any client_encoding other than UTF-8 currently. // However, we have historically allowed the user to set it to UTF-8 // explicitly, and there's no reason to break such programs, so allow that. // Note that the "options" setting could also set client_encoding, but // parsing its value is not worth it. Instead, we always explicitly send // client_encoding as a separate run-time parameter, which should override // anything set in options. if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) { return nil, errors.New("client_encoding must be absent or 'UTF8'") } o["client_encoding"] = "UTF8" // DateStyle needs a similar treatment. if datestyle, ok := o["datestyle"]; ok { if datestyle != "ISO, MDY" { return nil, fmt.Errorf("setting datestyle must be absent or %v; got %v", "ISO, MDY", datestyle) } } else { o["datestyle"] = "ISO, MDY" } // If a user is not provided by any other means, the last // resort is to use the current operating system provided user // name. if _, ok := o["user"]; !ok { u, err := userCurrent() if err != nil { return nil, err } o["user"] = u } // SSL is not necessary or supported over UNIX domain sockets if network, _ := network(o); network == "unix" { o["sslmode"] = "disable" } return &Connector{opts: o, dialer: defaultDialer{}}, nil } ================================================ FILE: vendor/github.com/lib/pq/copy.go ================================================ package pq import ( "bytes" "context" "database/sql/driver" "encoding/binary" "errors" "fmt" "sync" ) var ( errCopyInClosed = errors.New("pq: copyin statement has already been closed") errBinaryCopyNotSupported = errors.New("pq: only text format supported for COPY") errCopyToNotSupported = errors.New("pq: COPY TO is not supported") errCopyNotSupportedOutsideTxn = errors.New("pq: COPY is only allowed inside a transaction") errCopyInProgress = errors.New("pq: COPY in progress") ) // CopyIn creates a COPY FROM statement which can be prepared with // Tx.Prepare(). The target table should be visible in search_path. func CopyIn(table string, columns ...string) string { buffer := bytes.NewBufferString("COPY ") BufferQuoteIdentifier(table, buffer) buffer.WriteString(" (") makeStmt(buffer, columns...) return buffer.String() } // MakeStmt makes the stmt string for CopyIn and CopyInSchema. func makeStmt(buffer *bytes.Buffer, columns ...string) { //s := bytes.NewBufferString() for i, col := range columns { if i != 0 { buffer.WriteString(", ") } BufferQuoteIdentifier(col, buffer) } buffer.WriteString(") FROM STDIN") } // CopyInSchema creates a COPY FROM statement which can be prepared with // Tx.Prepare(). func CopyInSchema(schema, table string, columns ...string) string { buffer := bytes.NewBufferString("COPY ") BufferQuoteIdentifier(schema, buffer) buffer.WriteRune('.') BufferQuoteIdentifier(table, buffer) buffer.WriteString(" (") makeStmt(buffer, columns...) return buffer.String() } type copyin struct { cn *conn buffer []byte rowData chan []byte done chan bool closed bool mu struct { sync.Mutex err error driver.Result } } const ciBufferSize = 64 * 1024 // flush buffer before the buffer is filled up and needs reallocation const ciBufferFlushSize = 63 * 1024 func (cn *conn) prepareCopyIn(q string) (_ driver.Stmt, err error) { if !cn.isInTransaction() { return nil, errCopyNotSupportedOutsideTxn } ci := ©in{ cn: cn, buffer: make([]byte, 0, ciBufferSize), rowData: make(chan []byte), done: make(chan bool, 1), } // add CopyData identifier + 4 bytes for message length ci.buffer = append(ci.buffer, 'd', 0, 0, 0, 0) b := cn.writeBuf('Q') b.string(q) cn.send(b) awaitCopyInResponse: for { t, r := cn.recv1() switch t { case 'G': if r.byte() != 0 { err = errBinaryCopyNotSupported break awaitCopyInResponse } go ci.resploop() return ci, nil case 'H': err = errCopyToNotSupported break awaitCopyInResponse case 'E': err = parseError(r) case 'Z': if err == nil { ci.setBad(driver.ErrBadConn) errorf("unexpected ReadyForQuery in response to COPY") } cn.processReadyForQuery(r) return nil, err default: ci.setBad(driver.ErrBadConn) errorf("unknown response for copy query: %q", t) } } // something went wrong, abort COPY before we return b = cn.writeBuf('f') b.string(err.Error()) cn.send(b) for { t, r := cn.recv1() switch t { case 'c', 'C', 'E': case 'Z': // correctly aborted, we're done cn.processReadyForQuery(r) return nil, err default: ci.setBad(driver.ErrBadConn) errorf("unknown response for CopyFail: %q", t) } } } func (ci *copyin) flush(buf []byte) { // set message length (without message identifier) binary.BigEndian.PutUint32(buf[1:], uint32(len(buf)-1)) _, err := ci.cn.c.Write(buf) if err != nil { panic(err) } } func (ci *copyin) resploop() { for { var r readBuf t, err := ci.cn.recvMessage(&r) if err != nil { ci.setBad(driver.ErrBadConn) ci.setError(err) ci.done <- true return } switch t { case 'C': // complete res, _ := ci.cn.parseComplete(r.string()) ci.setResult(res) case 'N': if n := ci.cn.noticeHandler; n != nil { n(parseError(&r)) } case 'Z': ci.cn.processReadyForQuery(&r) ci.done <- true return case 'E': err := parseError(&r) ci.setError(err) default: ci.setBad(driver.ErrBadConn) ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t)) ci.done <- true return } } } func (ci *copyin) setBad(err error) { ci.cn.err.set(err) } func (ci *copyin) getBad() error { return ci.cn.err.get() } func (ci *copyin) err() error { ci.mu.Lock() err := ci.mu.err ci.mu.Unlock() return err } // setError() sets ci.err if one has not been set already. Caller must not be // holding ci.Mutex. func (ci *copyin) setError(err error) { ci.mu.Lock() if ci.mu.err == nil { ci.mu.err = err } ci.mu.Unlock() } func (ci *copyin) setResult(result driver.Result) { ci.mu.Lock() ci.mu.Result = result ci.mu.Unlock() } func (ci *copyin) getResult() driver.Result { ci.mu.Lock() result := ci.mu.Result ci.mu.Unlock() if result == nil { return driver.RowsAffected(0) } return result } func (ci *copyin) NumInput() int { return -1 } func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) { return nil, ErrNotSupported } // Exec inserts values into the COPY stream. The insert is asynchronous // and Exec can return errors from previous Exec calls to the same // COPY stmt. // // You need to call Exec(nil) to sync the COPY stream and to get any // errors from pending data, since Stmt.Close() doesn't return errors // to the user. func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) { if ci.closed { return nil, errCopyInClosed } if err := ci.getBad(); err != nil { return nil, err } defer ci.cn.errRecover(&err) if err := ci.err(); err != nil { return nil, err } if len(v) == 0 { if err := ci.Close(); err != nil { return driver.RowsAffected(0), err } return ci.getResult(), nil } numValues := len(v) for i, value := range v { ci.buffer = appendEncodedText(&ci.cn.parameterStatus, ci.buffer, value) if i < numValues-1 { ci.buffer = append(ci.buffer, '\t') } } ci.buffer = append(ci.buffer, '\n') if len(ci.buffer) > ciBufferFlushSize { ci.flush(ci.buffer) // reset buffer, keep bytes for message identifier and length ci.buffer = ci.buffer[:5] } return driver.RowsAffected(0), nil } // CopyData inserts a raw string into the COPY stream. The insert is // asynchronous and CopyData can return errors from previous CopyData calls to // the same COPY stmt. // // You need to call Exec(nil) to sync the COPY stream and to get any // errors from pending data, since Stmt.Close() doesn't return errors // to the user. func (ci *copyin) CopyData(ctx context.Context, line string) (r driver.Result, err error) { if ci.closed { return nil, errCopyInClosed } if finish := ci.cn.watchCancel(ctx); finish != nil { defer finish() } if err := ci.getBad(); err != nil { return nil, err } defer ci.cn.errRecover(&err) if err := ci.err(); err != nil { return nil, err } ci.buffer = append(ci.buffer, []byte(line)...) ci.buffer = append(ci.buffer, '\n') if len(ci.buffer) > ciBufferFlushSize { ci.flush(ci.buffer) // reset buffer, keep bytes for message identifier and length ci.buffer = ci.buffer[:5] } return driver.RowsAffected(0), nil } func (ci *copyin) Close() (err error) { if ci.closed { // Don't do anything, we're already closed return nil } ci.closed = true if err := ci.getBad(); err != nil { return err } defer ci.cn.errRecover(&err) if len(ci.buffer) > 0 { ci.flush(ci.buffer) } // Avoid touching the scratch buffer as resploop could be using it. err = ci.cn.sendSimpleMessage('c') if err != nil { return err } <-ci.done ci.cn.inCopy = false if err := ci.err(); err != nil { return err } return nil } ================================================ FILE: vendor/github.com/lib/pq/doc.go ================================================ /* Package pq is a pure Go Postgres driver for the database/sql package. In most cases clients will use the database/sql package instead of using this package directly. For example: import ( "database/sql" _ "github.com/lib/pq" ) func main() { connStr := "user=pqgotest dbname=pqgotest sslmode=verify-full" db, err := sql.Open("postgres", connStr) if err != nil { log.Fatal(err) } age := 21 rows, err := db.Query("SELECT name FROM users WHERE age = $1", age) … } You can also connect to a database using a URL. For example: connStr := "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full" db, err := sql.Open("postgres", connStr) Connection String Parameters Similarly to libpq, when establishing a connection using pq you are expected to supply a connection string containing zero or more parameters. A subset of the connection parameters supported by libpq are also supported by pq. Additionally, pq also lets you specify run-time parameters (such as search_path or work_mem) directly in the connection string. This is different from libpq, which does not allow run-time parameters in the connection string, instead requiring you to supply them in the options parameter. For compatibility with libpq, the following special connection parameters are supported: * dbname - The name of the database to connect to * user - The user to sign in as * password - The user's password * host - The host to connect to. Values that start with / are for unix domain sockets. (default is localhost) * port - The port to bind to. (default is 5432) * sslmode - Whether or not to use SSL (default is require, this is not the default for libpq) * fallback_application_name - An application_name to fall back to if one isn't provided. * connect_timeout - Maximum wait for connection, in seconds. Zero or not specified means wait indefinitely. * sslcert - Cert file location. The file must contain PEM encoded data. * sslkey - Key file location. The file must contain PEM encoded data. * sslrootcert - The location of the root certificate file. The file must contain PEM encoded data. Valid values for sslmode are: * disable - No SSL * require - Always SSL (skip verification) * verify-ca - Always SSL (verify that the certificate presented by the server was signed by a trusted CA) * verify-full - Always SSL (verify that the certification presented by the server was signed by a trusted CA and the server host name matches the one in the certificate) See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING for more information about connection string parameters. Use single quotes for values that contain whitespace: "user=pqgotest password='with spaces'" A backslash will escape the next character in values: "user=space\ man password='it\'s valid'" Note that the connection parameter client_encoding (which sets the text encoding for the connection) may be set but must be "UTF8", matching with the same rules as Postgres. It is an error to provide any other value. In addition to the parameters listed above, any run-time parameter that can be set at backend start time can be set in the connection string. For more information, see http://www.postgresql.org/docs/current/static/runtime-config.html. Most environment variables as specified at http://www.postgresql.org/docs/current/static/libpq-envars.html supported by libpq are also supported by pq. If any of the environment variables not supported by pq are set, pq will panic during connection establishment. Environment variables have a lower precedence than explicitly provided connection parameters. The pgpass mechanism as described in http://www.postgresql.org/docs/current/static/libpq-pgpass.html is supported, but on Windows PGPASSFILE must be specified explicitly. Queries database/sql does not dictate any specific format for parameter markers in query strings, and pq uses the Postgres-native ordinal markers, as shown above. The same marker can be reused for the same parameter: rows, err := db.Query(`SELECT name FROM users WHERE favorite_fruit = $1 OR age BETWEEN $2 AND $2 + 3`, "orange", 64) pq does not support the LastInsertId() method of the Result type in database/sql. To return the identifier of an INSERT (or UPDATE or DELETE), use the Postgres RETURNING clause with a standard Query or QueryRow call: var userid int err := db.QueryRow(`INSERT INTO users(name, favorite_fruit, age) VALUES('beatrice', 'starfruit', 93) RETURNING id`).Scan(&userid) For more details on RETURNING, see the Postgres documentation: http://www.postgresql.org/docs/current/static/sql-insert.html http://www.postgresql.org/docs/current/static/sql-update.html http://www.postgresql.org/docs/current/static/sql-delete.html For additional instructions on querying see the documentation for the database/sql package. Data Types Parameters pass through driver.DefaultParameterConverter before they are handled by this package. When the binary_parameters connection option is enabled, []byte values are sent directly to the backend as data in binary format. This package returns the following types for values from the PostgreSQL backend: - integer types smallint, integer, and bigint are returned as int64 - floating-point types real and double precision are returned as float64 - character types char, varchar, and text are returned as string - temporal types date, time, timetz, timestamp, and timestamptz are returned as time.Time - the boolean type is returned as bool - the bytea type is returned as []byte All other types are returned directly from the backend as []byte values in text format. Errors pq may return errors of type *pq.Error which can be interrogated for error details: if err, ok := err.(*pq.Error); ok { fmt.Println("pq error:", err.Code.Name()) } See the pq.Error type for details. Bulk imports You can perform bulk imports by preparing a statement returned by pq.CopyIn (or pq.CopyInSchema) in an explicit transaction (sql.Tx). The returned statement handle can then be repeatedly "executed" to copy data into the target table. After all data has been processed you should call Exec() once with no arguments to flush all buffered data. Any call to Exec() might return an error which should be handled appropriately, but because of the internal buffering an error returned by Exec() might not be related to the data passed in the call that failed. CopyIn uses COPY FROM internally. It is not possible to COPY outside of an explicit transaction in pq. Usage example: txn, err := db.Begin() if err != nil { log.Fatal(err) } stmt, err := txn.Prepare(pq.CopyIn("users", "name", "age")) if err != nil { log.Fatal(err) } for _, user := range users { _, err = stmt.Exec(user.Name, int64(user.Age)) if err != nil { log.Fatal(err) } } _, err = stmt.Exec() if err != nil { log.Fatal(err) } err = stmt.Close() if err != nil { log.Fatal(err) } err = txn.Commit() if err != nil { log.Fatal(err) } Notifications PostgreSQL supports a simple publish/subscribe model over database connections. See http://www.postgresql.org/docs/current/static/sql-notify.html for more information about the general mechanism. To start listening for notifications, you first have to open a new connection to the database by calling NewListener. This connection can not be used for anything other than LISTEN / NOTIFY. Calling Listen will open a "notification channel"; once a notification channel is open, a notification generated on that channel will effect a send on the Listener.Notify channel. A notification channel will remain open until Unlisten is called, though connection loss might result in some notifications being lost. To solve this problem, Listener sends a nil pointer over the Notify channel any time the connection is re-established following a connection loss. The application can get information about the state of the underlying connection by setting an event callback in the call to NewListener. A single Listener can safely be used from concurrent goroutines, which means that there is often no need to create more than one Listener in your application. However, a Listener is always connected to a single database, so you will need to create a new Listener instance for every database you want to receive notifications in. The channel name in both Listen and Unlisten is case sensitive, and can contain any characters legal in an identifier (see http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS for more information). Note that the channel name will be truncated to 63 bytes by the PostgreSQL server. You can find a complete, working example of Listener usage at https://godoc.org/github.com/lib/pq/example/listen. Kerberos Support If you need support for Kerberos authentication, add the following to your main package: import "github.com/lib/pq/auth/kerberos" func init() { pq.RegisterGSSProvider(func() (pq.Gss, error) { return kerberos.NewGSS() }) } This package is in a separate module so that users who don't need Kerberos don't have to download unnecessary dependencies. When imported, additional connection string parameters are supported: * krbsrvname - GSS (Kerberos) service name when constructing the SPN (default is `postgres`). This will be combined with the host to form the full SPN: `krbsrvname/host`. * krbspn - GSS (Kerberos) SPN. This takes priority over `krbsrvname` if present. */ package pq ================================================ FILE: vendor/github.com/lib/pq/encode.go ================================================ package pq import ( "bytes" "database/sql/driver" "encoding/binary" "encoding/hex" "errors" "fmt" "math" "regexp" "strconv" "strings" "sync" "time" "github.com/lib/pq/oid" ) var time2400Regex = regexp.MustCompile(`^(24:00(?::00(?:\.0+)?)?)(?:[Z+-].*)?$`) func binaryEncode(parameterStatus *parameterStatus, x interface{}) []byte { switch v := x.(type) { case []byte: return v default: return encode(parameterStatus, x, oid.T_unknown) } } func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) []byte { switch v := x.(type) { case int64: return strconv.AppendInt(nil, v, 10) case float64: return strconv.AppendFloat(nil, v, 'f', -1, 64) case []byte: if pgtypOid == oid.T_bytea { return encodeBytea(parameterStatus.serverVersion, v) } return v case string: if pgtypOid == oid.T_bytea { return encodeBytea(parameterStatus.serverVersion, []byte(v)) } return []byte(v) case bool: return strconv.AppendBool(nil, v) case time.Time: return formatTs(v) default: errorf("encode: unknown type for %T", v) } panic("not reached") } func decode(parameterStatus *parameterStatus, s []byte, typ oid.Oid, f format) interface{} { switch f { case formatBinary: return binaryDecode(parameterStatus, s, typ) case formatText: return textDecode(parameterStatus, s, typ) default: panic("not reached") } } func binaryDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} { switch typ { case oid.T_bytea: return s case oid.T_int8: return int64(binary.BigEndian.Uint64(s)) case oid.T_int4: return int64(int32(binary.BigEndian.Uint32(s))) case oid.T_int2: return int64(int16(binary.BigEndian.Uint16(s))) case oid.T_uuid: b, err := decodeUUIDBinary(s) if err != nil { panic(err) } return b default: errorf("don't know how to decode binary parameter of type %d", uint32(typ)) } panic("not reached") } func textDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} { switch typ { case oid.T_char, oid.T_varchar, oid.T_text: return string(s) case oid.T_bytea: b, err := parseBytea(s) if err != nil { errorf("%s", err) } return b case oid.T_timestamptz: return parseTs(parameterStatus.currentLocation, string(s)) case oid.T_timestamp, oid.T_date: return parseTs(nil, string(s)) case oid.T_time: return mustParse("15:04:05", typ, s) case oid.T_timetz: return mustParse("15:04:05-07", typ, s) case oid.T_bool: return s[0] == 't' case oid.T_int8, oid.T_int4, oid.T_int2: i, err := strconv.ParseInt(string(s), 10, 64) if err != nil { errorf("%s", err) } return i case oid.T_float4, oid.T_float8: // We always use 64 bit parsing, regardless of whether the input text is for // a float4 or float8, because clients expect float64s for all float datatypes // and returning a 32-bit parsed float64 produces lossy results. f, err := strconv.ParseFloat(string(s), 64) if err != nil { errorf("%s", err) } return f } return s } // appendEncodedText encodes item in text format as required by COPY // and appends to buf func appendEncodedText(parameterStatus *parameterStatus, buf []byte, x interface{}) []byte { switch v := x.(type) { case int64: return strconv.AppendInt(buf, v, 10) case float64: return strconv.AppendFloat(buf, v, 'f', -1, 64) case []byte: encodedBytea := encodeBytea(parameterStatus.serverVersion, v) return appendEscapedText(buf, string(encodedBytea)) case string: return appendEscapedText(buf, v) case bool: return strconv.AppendBool(buf, v) case time.Time: return append(buf, formatTs(v)...) case nil: return append(buf, "\\N"...) default: errorf("encode: unknown type for %T", v) } panic("not reached") } func appendEscapedText(buf []byte, text string) []byte { escapeNeeded := false startPos := 0 var c byte // check if we need to escape for i := 0; i < len(text); i++ { c = text[i] if c == '\\' || c == '\n' || c == '\r' || c == '\t' { escapeNeeded = true startPos = i break } } if !escapeNeeded { return append(buf, text...) } // copy till first char to escape, iterate the rest result := append(buf, text[:startPos]...) for i := startPos; i < len(text); i++ { c = text[i] switch c { case '\\': result = append(result, '\\', '\\') case '\n': result = append(result, '\\', 'n') case '\r': result = append(result, '\\', 'r') case '\t': result = append(result, '\\', 't') default: result = append(result, c) } } return result } func mustParse(f string, typ oid.Oid, s []byte) time.Time { str := string(s) // Check for a minute and second offset in the timezone. if typ == oid.T_timestamptz || typ == oid.T_timetz { for i := 3; i <= 6; i += 3 { if str[len(str)-i] == ':' { f += ":00" continue } break } } // Special case for 24:00 time. // Unfortunately, golang does not parse 24:00 as a proper time. // In this case, we want to try "round to the next day", to differentiate. // As such, we find if the 24:00 time matches at the beginning; if so, // we default it back to 00:00 but add a day later. var is2400Time bool switch typ { case oid.T_timetz, oid.T_time: if matches := time2400Regex.FindStringSubmatch(str); matches != nil { // Concatenate timezone information at the back. str = "00:00:00" + str[len(matches[1]):] is2400Time = true } } t, err := time.Parse(f, str) if err != nil { errorf("decode: %s", err) } if is2400Time { t = t.Add(24 * time.Hour) } return t } var errInvalidTimestamp = errors.New("invalid timestamp") type timestampParser struct { err error } func (p *timestampParser) expect(str string, char byte, pos int) { if p.err != nil { return } if pos+1 > len(str) { p.err = errInvalidTimestamp return } if c := str[pos]; c != char && p.err == nil { p.err = fmt.Errorf("expected '%v' at position %v; got '%v'", char, pos, c) } } func (p *timestampParser) mustAtoi(str string, begin int, end int) int { if p.err != nil { return 0 } if begin < 0 || end < 0 || begin > end || end > len(str) { p.err = errInvalidTimestamp return 0 } result, err := strconv.Atoi(str[begin:end]) if err != nil { if p.err == nil { p.err = fmt.Errorf("expected number; got '%v'", str) } return 0 } return result } // The location cache caches the time zones typically used by the client. type locationCache struct { cache map[int]*time.Location lock sync.Mutex } // All connections share the same list of timezones. Benchmarking shows that // about 5% speed could be gained by putting the cache in the connection and // losing the mutex, at the cost of a small amount of memory and a somewhat // significant increase in code complexity. var globalLocationCache = newLocationCache() func newLocationCache() *locationCache { return &locationCache{cache: make(map[int]*time.Location)} } // Returns the cached timezone for the specified offset, creating and caching // it if necessary. func (c *locationCache) getLocation(offset int) *time.Location { c.lock.Lock() defer c.lock.Unlock() location, ok := c.cache[offset] if !ok { location = time.FixedZone("", offset) c.cache[offset] = location } return location } var infinityTsEnabled = false var infinityTsNegative time.Time var infinityTsPositive time.Time const ( infinityTsEnabledAlready = "pq: infinity timestamp enabled already" infinityTsNegativeMustBeSmaller = "pq: infinity timestamp: negative value must be smaller (before) than positive" ) // EnableInfinityTs controls the handling of Postgres' "-infinity" and // "infinity" "timestamp"s. // // If EnableInfinityTs is not called, "-infinity" and "infinity" will return // []byte("-infinity") and []byte("infinity") respectively, and potentially // cause error "sql: Scan error on column index 0: unsupported driver -> Scan // pair: []uint8 -> *time.Time", when scanning into a time.Time value. // // Once EnableInfinityTs has been called, all connections created using this // driver will decode Postgres' "-infinity" and "infinity" for "timestamp", // "timestamp with time zone" and "date" types to the predefined minimum and // maximum times, respectively. When encoding time.Time values, any time which // equals or precedes the predefined minimum time will be encoded to // "-infinity". Any values at or past the maximum time will similarly be // encoded to "infinity". // // If EnableInfinityTs is called with negative >= positive, it will panic. // Calling EnableInfinityTs after a connection has been established results in // undefined behavior. If EnableInfinityTs is called more than once, it will // panic. func EnableInfinityTs(negative time.Time, positive time.Time) { if infinityTsEnabled { panic(infinityTsEnabledAlready) } if !negative.Before(positive) { panic(infinityTsNegativeMustBeSmaller) } infinityTsEnabled = true infinityTsNegative = negative infinityTsPositive = positive } /* * Testing might want to toggle infinityTsEnabled */ func disableInfinityTs() { infinityTsEnabled = false } // This is a time function specific to the Postgres default DateStyle // setting ("ISO, MDY"), the only one we currently support. This // accounts for the discrepancies between the parsing available with // time.Parse and the Postgres date formatting quirks. func parseTs(currentLocation *time.Location, str string) interface{} { switch str { case "-infinity": if infinityTsEnabled { return infinityTsNegative } return []byte(str) case "infinity": if infinityTsEnabled { return infinityTsPositive } return []byte(str) } t, err := ParseTimestamp(currentLocation, str) if err != nil { panic(err) } return t } // ParseTimestamp parses Postgres' text format. It returns a time.Time in // currentLocation iff that time's offset agrees with the offset sent from the // Postgres server. Otherwise, ParseTimestamp returns a time.Time with the // fixed offset offset provided by the Postgres server. func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, error) { p := timestampParser{} monSep := strings.IndexRune(str, '-') // this is Gregorian year, not ISO Year // In Gregorian system, the year 1 BC is followed by AD 1 year := p.mustAtoi(str, 0, monSep) daySep := monSep + 3 month := p.mustAtoi(str, monSep+1, daySep) p.expect(str, '-', daySep) timeSep := daySep + 3 day := p.mustAtoi(str, daySep+1, timeSep) minLen := monSep + len("01-01") + 1 isBC := strings.HasSuffix(str, " BC") if isBC { minLen += 3 } var hour, minute, second int if len(str) > minLen { p.expect(str, ' ', timeSep) minSep := timeSep + 3 p.expect(str, ':', minSep) hour = p.mustAtoi(str, timeSep+1, minSep) secSep := minSep + 3 p.expect(str, ':', secSep) minute = p.mustAtoi(str, minSep+1, secSep) secEnd := secSep + 3 second = p.mustAtoi(str, secSep+1, secEnd) } remainderIdx := monSep + len("01-01 00:00:00") + 1 // Three optional (but ordered) sections follow: the // fractional seconds, the time zone offset, and the BC // designation. We set them up here and adjust the other // offsets if the preceding sections exist. nanoSec := 0 tzOff := 0 if remainderIdx < len(str) && str[remainderIdx] == '.' { fracStart := remainderIdx + 1 fracOff := strings.IndexAny(str[fracStart:], "-+Z ") if fracOff < 0 { fracOff = len(str) - fracStart } fracSec := p.mustAtoi(str, fracStart, fracStart+fracOff) nanoSec = fracSec * (1000000000 / int(math.Pow(10, float64(fracOff)))) remainderIdx += fracOff + 1 } if tzStart := remainderIdx; tzStart < len(str) && (str[tzStart] == '-' || str[tzStart] == '+') { // time zone separator is always '-' or '+' or 'Z' (UTC is +00) var tzSign int switch c := str[tzStart]; c { case '-': tzSign = -1 case '+': tzSign = +1 default: return time.Time{}, fmt.Errorf("expected '-' or '+' at position %v; got %v", tzStart, c) } tzHours := p.mustAtoi(str, tzStart+1, tzStart+3) remainderIdx += 3 var tzMin, tzSec int if remainderIdx < len(str) && str[remainderIdx] == ':' { tzMin = p.mustAtoi(str, remainderIdx+1, remainderIdx+3) remainderIdx += 3 } if remainderIdx < len(str) && str[remainderIdx] == ':' { tzSec = p.mustAtoi(str, remainderIdx+1, remainderIdx+3) remainderIdx += 3 } tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec) } else if tzStart < len(str) && str[tzStart] == 'Z' { // time zone Z separator indicates UTC is +00 remainderIdx += 1 } var isoYear int if isBC { isoYear = 1 - year remainderIdx += 3 } else { isoYear = year } if remainderIdx < len(str) { return time.Time{}, fmt.Errorf("expected end of input, got %v", str[remainderIdx:]) } t := time.Date(isoYear, time.Month(month), day, hour, minute, second, nanoSec, globalLocationCache.getLocation(tzOff)) if currentLocation != nil { // Set the location of the returned Time based on the session's // TimeZone value, but only if the local time zone database agrees with // the remote database on the offset. lt := t.In(currentLocation) _, newOff := lt.Zone() if newOff == tzOff { t = lt } } return t, p.err } // formatTs formats t into a format postgres understands. func formatTs(t time.Time) []byte { if infinityTsEnabled { // t <= -infinity : ! (t > -infinity) if !t.After(infinityTsNegative) { return []byte("-infinity") } // t >= infinity : ! (!t < infinity) if !t.Before(infinityTsPositive) { return []byte("infinity") } } return FormatTimestamp(t) } // FormatTimestamp formats t into Postgres' text format for timestamps. func FormatTimestamp(t time.Time) []byte { // Need to send dates before 0001 A.D. with " BC" suffix, instead of the // minus sign preferred by Go. // Beware, "0000" in ISO is "1 BC", "-0001" is "2 BC" and so on bc := false if t.Year() <= 0 { // flip year sign, and add 1, e.g: "0" will be "1", and "-10" will be "11" t = t.AddDate((-t.Year())*2+1, 0, 0) bc = true } b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00")) _, offset := t.Zone() offset %= 60 if offset != 0 { // RFC3339Nano already printed the minus sign if offset < 0 { offset = -offset } b = append(b, ':') if offset < 10 { b = append(b, '0') } b = strconv.AppendInt(b, int64(offset), 10) } if bc { b = append(b, " BC"...) } return b } // Parse a bytea value received from the server. Both "hex" and the legacy // "escape" format are supported. func parseBytea(s []byte) (result []byte, err error) { if len(s) >= 2 && bytes.Equal(s[:2], []byte("\\x")) { // bytea_output = hex s = s[2:] // trim off leading "\\x" result = make([]byte, hex.DecodedLen(len(s))) _, err := hex.Decode(result, s) if err != nil { return nil, err } } else { // bytea_output = escape for len(s) > 0 { if s[0] == '\\' { // escaped '\\' if len(s) >= 2 && s[1] == '\\' { result = append(result, '\\') s = s[2:] continue } // '\\' followed by an octal number if len(s) < 4 { return nil, fmt.Errorf("invalid bytea sequence %v", s) } r, err := strconv.ParseUint(string(s[1:4]), 8, 8) if err != nil { return nil, fmt.Errorf("could not parse bytea value: %s", err.Error()) } result = append(result, byte(r)) s = s[4:] } else { // We hit an unescaped, raw byte. Try to read in as many as // possible in one go. i := bytes.IndexByte(s, '\\') if i == -1 { result = append(result, s...) break } result = append(result, s[:i]...) s = s[i:] } } } return result, nil } func encodeBytea(serverVersion int, v []byte) (result []byte) { if serverVersion >= 90000 { // Use the hex format if we know that the server supports it result = make([]byte, 2+hex.EncodedLen(len(v))) result[0] = '\\' result[1] = 'x' hex.Encode(result[2:], v) } else { // .. or resort to "escape" for _, b := range v { if b == '\\' { result = append(result, '\\', '\\') } else if b < 0x20 || b > 0x7e { result = append(result, []byte(fmt.Sprintf("\\%03o", b))...) } else { result = append(result, b) } } } return result } // NullTime represents a time.Time that may be null. NullTime implements the // sql.Scanner interface so it can be used as a scan destination, similar to // sql.NullString. type NullTime struct { Time time.Time Valid bool // Valid is true if Time is not NULL } // Scan implements the Scanner interface. func (nt *NullTime) Scan(value interface{}) error { nt.Time, nt.Valid = value.(time.Time) return nil } // Value implements the driver Valuer interface. func (nt NullTime) Value() (driver.Value, error) { if !nt.Valid { return nil, nil } return nt.Time, nil } ================================================ FILE: vendor/github.com/lib/pq/error.go ================================================ package pq import ( "database/sql/driver" "fmt" "io" "net" "runtime" ) // Error severities const ( Efatal = "FATAL" Epanic = "PANIC" Ewarning = "WARNING" Enotice = "NOTICE" Edebug = "DEBUG" Einfo = "INFO" Elog = "LOG" ) // Error represents an error communicating with the server. // // See http://www.postgresql.org/docs/current/static/protocol-error-fields.html for details of the fields type Error struct { Severity string Code ErrorCode Message string Detail string Hint string Position string InternalPosition string InternalQuery string Where string Schema string Table string Column string DataTypeName string Constraint string File string Line string Routine string } // ErrorCode is a five-character error code. type ErrorCode string // Name returns a more human friendly rendering of the error code, namely the // "condition name". // // See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for // details. func (ec ErrorCode) Name() string { return errorCodeNames[ec] } // ErrorClass is only the class part of an error code. type ErrorClass string // Name returns the condition name of an error class. It is equivalent to the // condition name of the "standard" error code (i.e. the one having the last // three characters "000"). func (ec ErrorClass) Name() string { return errorCodeNames[ErrorCode(ec+"000")] } // Class returns the error class, e.g. "28". // // See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for // details. func (ec ErrorCode) Class() ErrorClass { return ErrorClass(ec[0:2]) } // errorCodeNames is a mapping between the five-character error codes and the // human readable "condition names". It is derived from the list at // http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html var errorCodeNames = map[ErrorCode]string{ // Class 00 - Successful Completion "00000": "successful_completion", // Class 01 - Warning "01000": "warning", "0100C": "dynamic_result_sets_returned", "01008": "implicit_zero_bit_padding", "01003": "null_value_eliminated_in_set_function", "01007": "privilege_not_granted", "01006": "privilege_not_revoked", "01004": "string_data_right_truncation", "01P01": "deprecated_feature", // Class 02 - No Data (this is also a warning class per the SQL standard) "02000": "no_data", "02001": "no_additional_dynamic_result_sets_returned", // Class 03 - SQL Statement Not Yet Complete "03000": "sql_statement_not_yet_complete", // Class 08 - Connection Exception "08000": "connection_exception", "08003": "connection_does_not_exist", "08006": "connection_failure", "08001": "sqlclient_unable_to_establish_sqlconnection", "08004": "sqlserver_rejected_establishment_of_sqlconnection", "08007": "transaction_resolution_unknown", "08P01": "protocol_violation", // Class 09 - Triggered Action Exception "09000": "triggered_action_exception", // Class 0A - Feature Not Supported "0A000": "feature_not_supported", // Class 0B - Invalid Transaction Initiation "0B000": "invalid_transaction_initiation", // Class 0F - Locator Exception "0F000": "locator_exception", "0F001": "invalid_locator_specification", // Class 0L - Invalid Grantor "0L000": "invalid_grantor", "0LP01": "invalid_grant_operation", // Class 0P - Invalid Role Specification "0P000": "invalid_role_specification", // Class 0Z - Diagnostics Exception "0Z000": "diagnostics_exception", "0Z002": "stacked_diagnostics_accessed_without_active_handler", // Class 20 - Case Not Found "20000": "case_not_found", // Class 21 - Cardinality Violation "21000": "cardinality_violation", // Class 22 - Data Exception "22000": "data_exception", "2202E": "array_subscript_error", "22021": "character_not_in_repertoire", "22008": "datetime_field_overflow", "22012": "division_by_zero", "22005": "error_in_assignment", "2200B": "escape_character_conflict", "22022": "indicator_overflow", "22015": "interval_field_overflow", "2201E": "invalid_argument_for_logarithm", "22014": "invalid_argument_for_ntile_function", "22016": "invalid_argument_for_nth_value_function", "2201F": "invalid_argument_for_power_function", "2201G": "invalid_argument_for_width_bucket_function", "22018": "invalid_character_value_for_cast", "22007": "invalid_datetime_format", "22019": "invalid_escape_character", "2200D": "invalid_escape_octet", "22025": "invalid_escape_sequence", "22P06": "nonstandard_use_of_escape_character", "22010": "invalid_indicator_parameter_value", "22023": "invalid_parameter_value", "2201B": "invalid_regular_expression", "2201W": "invalid_row_count_in_limit_clause", "2201X": "invalid_row_count_in_result_offset_clause", "22009": "invalid_time_zone_displacement_value", "2200C": "invalid_use_of_escape_character", "2200G": "most_specific_type_mismatch", "22004": "null_value_not_allowed", "22002": "null_value_no_indicator_parameter", "22003": "numeric_value_out_of_range", "2200H": "sequence_generator_limit_exceeded", "22026": "string_data_length_mismatch", "22001": "string_data_right_truncation", "22011": "substring_error", "22027": "trim_error", "22024": "unterminated_c_string", "2200F": "zero_length_character_string", "22P01": "floating_point_exception", "22P02": "invalid_text_representation", "22P03": "invalid_binary_representation", "22P04": "bad_copy_file_format", "22P05": "untranslatable_character", "2200L": "not_an_xml_document", "2200M": "invalid_xml_document", "2200N": "invalid_xml_content", "2200S": "invalid_xml_comment", "2200T": "invalid_xml_processing_instruction", // Class 23 - Integrity Constraint Violation "23000": "integrity_constraint_violation", "23001": "restrict_violation", "23502": "not_null_violation", "23503": "foreign_key_violation", "23505": "unique_violation", "23514": "check_violation", "23P01": "exclusion_violation", // Class 24 - Invalid Cursor State "24000": "invalid_cursor_state", // Class 25 - Invalid Transaction State "25000": "invalid_transaction_state", "25001": "active_sql_transaction", "25002": "branch_transaction_already_active", "25008": "held_cursor_requires_same_isolation_level", "25003": "inappropriate_access_mode_for_branch_transaction", "25004": "inappropriate_isolation_level_for_branch_transaction", "25005": "no_active_sql_transaction_for_branch_transaction", "25006": "read_only_sql_transaction", "25007": "schema_and_data_statement_mixing_not_supported", "25P01": "no_active_sql_transaction", "25P02": "in_failed_sql_transaction", // Class 26 - Invalid SQL Statement Name "26000": "invalid_sql_statement_name", // Class 27 - Triggered Data Change Violation "27000": "triggered_data_change_violation", // Class 28 - Invalid Authorization Specification "28000": "invalid_authorization_specification", "28P01": "invalid_password", // Class 2B - Dependent Privilege Descriptors Still Exist "2B000": "dependent_privilege_descriptors_still_exist", "2BP01": "dependent_objects_still_exist", // Class 2D - Invalid Transaction Termination "2D000": "invalid_transaction_termination", // Class 2F - SQL Routine Exception "2F000": "sql_routine_exception", "2F005": "function_executed_no_return_statement", "2F002": "modifying_sql_data_not_permitted", "2F003": "prohibited_sql_statement_attempted", "2F004": "reading_sql_data_not_permitted", // Class 34 - Invalid Cursor Name "34000": "invalid_cursor_name", // Class 38 - External Routine Exception "38000": "external_routine_exception", "38001": "containing_sql_not_permitted", "38002": "modifying_sql_data_not_permitted", "38003": "prohibited_sql_statement_attempted", "38004": "reading_sql_data_not_permitted", // Class 39 - External Routine Invocation Exception "39000": "external_routine_invocation_exception", "39001": "invalid_sqlstate_returned", "39004": "null_value_not_allowed", "39P01": "trigger_protocol_violated", "39P02": "srf_protocol_violated", // Class 3B - Savepoint Exception "3B000": "savepoint_exception", "3B001": "invalid_savepoint_specification", // Class 3D - Invalid Catalog Name "3D000": "invalid_catalog_name", // Class 3F - Invalid Schema Name "3F000": "invalid_schema_name", // Class 40 - Transaction Rollback "40000": "transaction_rollback", "40002": "transaction_integrity_constraint_violation", "40001": "serialization_failure", "40003": "statement_completion_unknown", "40P01": "deadlock_detected", // Class 42 - Syntax Error or Access Rule Violation "42000": "syntax_error_or_access_rule_violation", "42601": "syntax_error", "42501": "insufficient_privilege", "42846": "cannot_coerce", "42803": "grouping_error", "42P20": "windowing_error", "42P19": "invalid_recursion", "42830": "invalid_foreign_key", "42602": "invalid_name", "42622": "name_too_long", "42939": "reserved_name", "42804": "datatype_mismatch", "42P18": "indeterminate_datatype", "42P21": "collation_mismatch", "42P22": "indeterminate_collation", "42809": "wrong_object_type", "42703": "undefined_column", "42883": "undefined_function", "42P01": "undefined_table", "42P02": "undefined_parameter", "42704": "undefined_object", "42701": "duplicate_column", "42P03": "duplicate_cursor", "42P04": "duplicate_database", "42723": "duplicate_function", "42P05": "duplicate_prepared_statement", "42P06": "duplicate_schema", "42P07": "duplicate_table", "42712": "duplicate_alias", "42710": "duplicate_object", "42702": "ambiguous_column", "42725": "ambiguous_function", "42P08": "ambiguous_parameter", "42P09": "ambiguous_alias", "42P10": "invalid_column_reference", "42611": "invalid_column_definition", "42P11": "invalid_cursor_definition", "42P12": "invalid_database_definition", "42P13": "invalid_function_definition", "42P14": "invalid_prepared_statement_definition", "42P15": "invalid_schema_definition", "42P16": "invalid_table_definition", "42P17": "invalid_object_definition", // Class 44 - WITH CHECK OPTION Violation "44000": "with_check_option_violation", // Class 53 - Insufficient Resources "53000": "insufficient_resources", "53100": "disk_full", "53200": "out_of_memory", "53300": "too_many_connections", "53400": "configuration_limit_exceeded", // Class 54 - Program Limit Exceeded "54000": "program_limit_exceeded", "54001": "statement_too_complex", "54011": "too_many_columns", "54023": "too_many_arguments", // Class 55 - Object Not In Prerequisite State "55000": "object_not_in_prerequisite_state", "55006": "object_in_use", "55P02": "cant_change_runtime_param", "55P03": "lock_not_available", // Class 57 - Operator Intervention "57000": "operator_intervention", "57014": "query_canceled", "57P01": "admin_shutdown", "57P02": "crash_shutdown", "57P03": "cannot_connect_now", "57P04": "database_dropped", // Class 58 - System Error (errors external to PostgreSQL itself) "58000": "system_error", "58030": "io_error", "58P01": "undefined_file", "58P02": "duplicate_file", // Class F0 - Configuration File Error "F0000": "config_file_error", "F0001": "lock_file_exists", // Class HV - Foreign Data Wrapper Error (SQL/MED) "HV000": "fdw_error", "HV005": "fdw_column_name_not_found", "HV002": "fdw_dynamic_parameter_value_needed", "HV010": "fdw_function_sequence_error", "HV021": "fdw_inconsistent_descriptor_information", "HV024": "fdw_invalid_attribute_value", "HV007": "fdw_invalid_column_name", "HV008": "fdw_invalid_column_number", "HV004": "fdw_invalid_data_type", "HV006": "fdw_invalid_data_type_descriptors", "HV091": "fdw_invalid_descriptor_field_identifier", "HV00B": "fdw_invalid_handle", "HV00C": "fdw_invalid_option_index", "HV00D": "fdw_invalid_option_name", "HV090": "fdw_invalid_string_length_or_buffer_length", "HV00A": "fdw_invalid_string_format", "HV009": "fdw_invalid_use_of_null_pointer", "HV014": "fdw_too_many_handles", "HV001": "fdw_out_of_memory", "HV00P": "fdw_no_schemas", "HV00J": "fdw_option_name_not_found", "HV00K": "fdw_reply_handle", "HV00Q": "fdw_schema_not_found", "HV00R": "fdw_table_not_found", "HV00L": "fdw_unable_to_create_execution", "HV00M": "fdw_unable_to_create_reply", "HV00N": "fdw_unable_to_establish_connection", // Class P0 - PL/pgSQL Error "P0000": "plpgsql_error", "P0001": "raise_exception", "P0002": "no_data_found", "P0003": "too_many_rows", // Class XX - Internal Error "XX000": "internal_error", "XX001": "data_corrupted", "XX002": "index_corrupted", } func parseError(r *readBuf) *Error { err := new(Error) for t := r.byte(); t != 0; t = r.byte() { msg := r.string() switch t { case 'S': err.Severity = msg case 'C': err.Code = ErrorCode(msg) case 'M': err.Message = msg case 'D': err.Detail = msg case 'H': err.Hint = msg case 'P': err.Position = msg case 'p': err.InternalPosition = msg case 'q': err.InternalQuery = msg case 'W': err.Where = msg case 's': err.Schema = msg case 't': err.Table = msg case 'c': err.Column = msg case 'd': err.DataTypeName = msg case 'n': err.Constraint = msg case 'F': err.File = msg case 'L': err.Line = msg case 'R': err.Routine = msg } } return err } // Fatal returns true if the Error Severity is fatal. func (err *Error) Fatal() bool { return err.Severity == Efatal } // SQLState returns the SQLState of the error. func (err *Error) SQLState() string { return string(err.Code) } // Get implements the legacy PGError interface. New code should use the fields // of the Error struct directly. func (err *Error) Get(k byte) (v string) { switch k { case 'S': return err.Severity case 'C': return string(err.Code) case 'M': return err.Message case 'D': return err.Detail case 'H': return err.Hint case 'P': return err.Position case 'p': return err.InternalPosition case 'q': return err.InternalQuery case 'W': return err.Where case 's': return err.Schema case 't': return err.Table case 'c': return err.Column case 'd': return err.DataTypeName case 'n': return err.Constraint case 'F': return err.File case 'L': return err.Line case 'R': return err.Routine } return "" } func (err *Error) Error() string { return "pq: " + err.Message } // PGError is an interface used by previous versions of pq. It is provided // only to support legacy code. New code should use the Error type. type PGError interface { Error() string Fatal() bool Get(k byte) (v string) } func errorf(s string, args ...interface{}) { panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))) } // TODO(ainar-g) Rename to errorf after removing panics. func fmterrorf(s string, args ...interface{}) error { return fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)) } func errRecoverNoErrBadConn(err *error) { e := recover() if e == nil { // Do nothing return } var ok bool *err, ok = e.(error) if !ok { *err = fmt.Errorf("pq: unexpected error: %#v", e) } } func (cn *conn) errRecover(err *error) { e := recover() switch v := e.(type) { case nil: // Do nothing case runtime.Error: cn.err.set(driver.ErrBadConn) panic(v) case *Error: if v.Fatal() { *err = driver.ErrBadConn } else { *err = v } case *net.OpError: cn.err.set(driver.ErrBadConn) *err = v case *safeRetryError: cn.err.set(driver.ErrBadConn) *err = driver.ErrBadConn case error: if v == io.EOF || v.Error() == "remote error: handshake failure" { *err = driver.ErrBadConn } else { *err = v } default: cn.err.set(driver.ErrBadConn) panic(fmt.Sprintf("unknown error: %#v", e)) } // Any time we return ErrBadConn, we need to remember it since *Tx doesn't // mark the connection bad in database/sql. if *err == driver.ErrBadConn { cn.err.set(driver.ErrBadConn) } } ================================================ FILE: vendor/github.com/lib/pq/krb.go ================================================ package pq // NewGSSFunc creates a GSS authentication provider, for use with // RegisterGSSProvider. type NewGSSFunc func() (GSS, error) var newGss NewGSSFunc // RegisterGSSProvider registers a GSS authentication provider. For example, if // you need to use Kerberos to authenticate with your server, add this to your // main package: // // import "github.com/lib/pq/auth/kerberos" // // func init() { // pq.RegisterGSSProvider(func() (pq.GSS, error) { return kerberos.NewGSS() }) // } func RegisterGSSProvider(newGssArg NewGSSFunc) { newGss = newGssArg } // GSS provides GSSAPI authentication (e.g., Kerberos). type GSS interface { GetInitToken(host string, service string) ([]byte, error) GetInitTokenFromSpn(spn string) ([]byte, error) Continue(inToken []byte) (done bool, outToken []byte, err error) } ================================================ FILE: vendor/github.com/lib/pq/notice.go ================================================ //go:build go1.10 // +build go1.10 package pq import ( "context" "database/sql/driver" ) // NoticeHandler returns the notice handler on the given connection, if any. A // runtime panic occurs if c is not a pq connection. This is rarely used // directly, use ConnectorNoticeHandler and ConnectorWithNoticeHandler instead. func NoticeHandler(c driver.Conn) func(*Error) { return c.(*conn).noticeHandler } // SetNoticeHandler sets the given notice handler on the given connection. A // runtime panic occurs if c is not a pq connection. A nil handler may be used // to unset it. This is rarely used directly, use ConnectorNoticeHandler and // ConnectorWithNoticeHandler instead. // // Note: Notice handlers are executed synchronously by pq meaning commands // won't continue to be processed until the handler returns. func SetNoticeHandler(c driver.Conn, handler func(*Error)) { c.(*conn).noticeHandler = handler } // NoticeHandlerConnector wraps a regular connector and sets a notice handler // on it. type NoticeHandlerConnector struct { driver.Connector noticeHandler func(*Error) } // Connect calls the underlying connector's connect method and then sets the // notice handler. func (n *NoticeHandlerConnector) Connect(ctx context.Context) (driver.Conn, error) { c, err := n.Connector.Connect(ctx) if err == nil { SetNoticeHandler(c, n.noticeHandler) } return c, err } // ConnectorNoticeHandler returns the currently set notice handler, if any. If // the given connector is not a result of ConnectorWithNoticeHandler, nil is // returned. func ConnectorNoticeHandler(c driver.Connector) func(*Error) { if c, ok := c.(*NoticeHandlerConnector); ok { return c.noticeHandler } return nil } // ConnectorWithNoticeHandler creates or sets the given handler for the given // connector. If the given connector is a result of calling this function // previously, it is simply set on the given connector and returned. Otherwise, // this returns a new connector wrapping the given one and setting the notice // handler. A nil notice handler may be used to unset it. // // The returned connector is intended to be used with database/sql.OpenDB. // // Note: Notice handlers are executed synchronously by pq meaning commands // won't continue to be processed until the handler returns. func ConnectorWithNoticeHandler(c driver.Connector, handler func(*Error)) *NoticeHandlerConnector { if c, ok := c.(*NoticeHandlerConnector); ok { c.noticeHandler = handler return c } return &NoticeHandlerConnector{Connector: c, noticeHandler: handler} } ================================================ FILE: vendor/github.com/lib/pq/notify.go ================================================ package pq // Package pq is a pure Go Postgres driver for the database/sql package. // This module contains support for Postgres LISTEN/NOTIFY. import ( "context" "database/sql/driver" "errors" "fmt" "sync" "sync/atomic" "time" ) // Notification represents a single notification from the database. type Notification struct { // Process ID (PID) of the notifying postgres backend. BePid int // Name of the channel the notification was sent on. Channel string // Payload, or the empty string if unspecified. Extra string } func recvNotification(r *readBuf) *Notification { bePid := r.int32() channel := r.string() extra := r.string() return &Notification{bePid, channel, extra} } // SetNotificationHandler sets the given notification handler on the given // connection. A runtime panic occurs if c is not a pq connection. A nil handler // may be used to unset it. // // Note: Notification handlers are executed synchronously by pq meaning commands // won't continue to be processed until the handler returns. func SetNotificationHandler(c driver.Conn, handler func(*Notification)) { c.(*conn).notificationHandler = handler } // NotificationHandlerConnector wraps a regular connector and sets a notification handler // on it. type NotificationHandlerConnector struct { driver.Connector notificationHandler func(*Notification) } // Connect calls the underlying connector's connect method and then sets the // notification handler. func (n *NotificationHandlerConnector) Connect(ctx context.Context) (driver.Conn, error) { c, err := n.Connector.Connect(ctx) if err == nil { SetNotificationHandler(c, n.notificationHandler) } return c, err } // ConnectorNotificationHandler returns the currently set notification handler, if any. If // the given connector is not a result of ConnectorWithNotificationHandler, nil is // returned. func ConnectorNotificationHandler(c driver.Connector) func(*Notification) { if c, ok := c.(*NotificationHandlerConnector); ok { return c.notificationHandler } return nil } // ConnectorWithNotificationHandler creates or sets the given handler for the given // connector. If the given connector is a result of calling this function // previously, it is simply set on the given connector and returned. Otherwise, // this returns a new connector wrapping the given one and setting the notification // handler. A nil notification handler may be used to unset it. // // The returned connector is intended to be used with database/sql.OpenDB. // // Note: Notification handlers are executed synchronously by pq meaning commands // won't continue to be processed until the handler returns. func ConnectorWithNotificationHandler(c driver.Connector, handler func(*Notification)) *NotificationHandlerConnector { if c, ok := c.(*NotificationHandlerConnector); ok { c.notificationHandler = handler return c } return &NotificationHandlerConnector{Connector: c, notificationHandler: handler} } const ( connStateIdle int32 = iota connStateExpectResponse connStateExpectReadyForQuery ) type message struct { typ byte err error } var errListenerConnClosed = errors.New("pq: ListenerConn has been closed") // ListenerConn is a low-level interface for waiting for notifications. You // should use Listener instead. type ListenerConn struct { // guards cn and err connectionLock sync.Mutex cn *conn err error connState int32 // the sending goroutine will be holding this lock senderLock sync.Mutex notificationChan chan<- *Notification replyChan chan message } // NewListenerConn creates a new ListenerConn. Use NewListener instead. func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) { return newDialListenerConn(defaultDialer{}, name, notificationChan) } func newDialListenerConn(d Dialer, name string, c chan<- *Notification) (*ListenerConn, error) { cn, err := DialOpen(d, name) if err != nil { return nil, err } l := &ListenerConn{ cn: cn.(*conn), notificationChan: c, connState: connStateIdle, replyChan: make(chan message, 2), } go l.listenerConnMain() return l, nil } // We can only allow one goroutine at a time to be running a query on the // connection for various reasons, so the goroutine sending on the connection // must be holding senderLock. // // Returns an error if an unrecoverable error has occurred and the ListenerConn // should be abandoned. func (l *ListenerConn) acquireSenderLock() error { // we must acquire senderLock first to avoid deadlocks; see ExecSimpleQuery l.senderLock.Lock() l.connectionLock.Lock() err := l.err l.connectionLock.Unlock() if err != nil { l.senderLock.Unlock() return err } return nil } func (l *ListenerConn) releaseSenderLock() { l.senderLock.Unlock() } // setState advances the protocol state to newState. Returns false if moving // to that state from the current state is not allowed. func (l *ListenerConn) setState(newState int32) bool { var expectedState int32 switch newState { case connStateIdle: expectedState = connStateExpectReadyForQuery case connStateExpectResponse: expectedState = connStateIdle case connStateExpectReadyForQuery: expectedState = connStateExpectResponse default: panic(fmt.Sprintf("unexpected listenerConnState %d", newState)) } return atomic.CompareAndSwapInt32(&l.connState, expectedState, newState) } // Main logic is here: receive messages from the postgres backend, forward // notifications and query replies and keep the internal state in sync with the // protocol state. Returns when the connection has been lost, is about to go // away or should be discarded because we couldn't agree on the state with the // server backend. func (l *ListenerConn) listenerConnLoop() (err error) { defer errRecoverNoErrBadConn(&err) r := &readBuf{} for { t, err := l.cn.recvMessage(r) if err != nil { return err } switch t { case 'A': // recvNotification copies all the data so we don't need to worry // about the scratch buffer being overwritten. l.notificationChan <- recvNotification(r) case 'T', 'D': // only used by tests; ignore case 'E': // We might receive an ErrorResponse even when not in a query; it // is expected that the server will close the connection after // that, but we should make sure that the error we display is the // one from the stray ErrorResponse, not io.ErrUnexpectedEOF. if !l.setState(connStateExpectReadyForQuery) { return parseError(r) } l.replyChan <- message{t, parseError(r)} case 'C', 'I': if !l.setState(connStateExpectReadyForQuery) { // protocol out of sync return fmt.Errorf("unexpected CommandComplete") } // ExecSimpleQuery doesn't need to know about this message case 'Z': if !l.setState(connStateIdle) { // protocol out of sync return fmt.Errorf("unexpected ReadyForQuery") } l.replyChan <- message{t, nil} case 'S': // ignore case 'N': if n := l.cn.noticeHandler; n != nil { n(parseError(r)) } default: return fmt.Errorf("unexpected message %q from server in listenerConnLoop", t) } } } // This is the main routine for the goroutine receiving on the database // connection. Most of the main logic is in listenerConnLoop. func (l *ListenerConn) listenerConnMain() { err := l.listenerConnLoop() // listenerConnLoop terminated; we're done, but we still have to clean up. // Make sure nobody tries to start any new queries by making sure the err // pointer is set. It is important that we do not overwrite its value; a // connection could be closed by either this goroutine or one sending on // the connection -- whoever closes the connection is assumed to have the // more meaningful error message (as the other one will probably get // net.errClosed), so that goroutine sets the error we expose while the // other error is discarded. If the connection is lost while two // goroutines are operating on the socket, it probably doesn't matter which // error we expose so we don't try to do anything more complex. l.connectionLock.Lock() if l.err == nil { l.err = err } l.cn.Close() l.connectionLock.Unlock() // There might be a query in-flight; make sure nobody's waiting for a // response to it, since there's not going to be one. close(l.replyChan) // let the listener know we're done close(l.notificationChan) // this ListenerConn is done } // Listen sends a LISTEN query to the server. See ExecSimpleQuery. func (l *ListenerConn) Listen(channel string) (bool, error) { return l.ExecSimpleQuery("LISTEN " + QuoteIdentifier(channel)) } // Unlisten sends an UNLISTEN query to the server. See ExecSimpleQuery. func (l *ListenerConn) Unlisten(channel string) (bool, error) { return l.ExecSimpleQuery("UNLISTEN " + QuoteIdentifier(channel)) } // UnlistenAll sends an `UNLISTEN *` query to the server. See ExecSimpleQuery. func (l *ListenerConn) UnlistenAll() (bool, error) { return l.ExecSimpleQuery("UNLISTEN *") } // Ping the remote server to make sure it's alive. Non-nil error means the // connection has failed and should be abandoned. func (l *ListenerConn) Ping() error { sent, err := l.ExecSimpleQuery("") if !sent { return err } if err != nil { // shouldn't happen panic(err) } return nil } // Attempt to send a query on the connection. Returns an error if sending the // query failed, and the caller should initiate closure of this connection. // The caller must be holding senderLock (see acquireSenderLock and // releaseSenderLock). func (l *ListenerConn) sendSimpleQuery(q string) (err error) { defer errRecoverNoErrBadConn(&err) // must set connection state before sending the query if !l.setState(connStateExpectResponse) { panic("two queries running at the same time") } // Can't use l.cn.writeBuf here because it uses the scratch buffer which // might get overwritten by listenerConnLoop. b := &writeBuf{ buf: []byte("Q\x00\x00\x00\x00"), pos: 1, } b.string(q) l.cn.send(b) return nil } // ExecSimpleQuery executes a "simple query" (i.e. one with no bindable // parameters) on the connection. The possible return values are: // 1) "executed" is true; the query was executed to completion on the // database server. If the query failed, err will be set to the error // returned by the database, otherwise err will be nil. // 2) If "executed" is false, the query could not be executed on the remote // server. err will be non-nil. // // After a call to ExecSimpleQuery has returned an executed=false value, the // connection has either been closed or will be closed shortly thereafter, and // all subsequently executed queries will return an error. func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) { if err = l.acquireSenderLock(); err != nil { return false, err } defer l.releaseSenderLock() err = l.sendSimpleQuery(q) if err != nil { // We can't know what state the protocol is in, so we need to abandon // this connection. l.connectionLock.Lock() // Set the error pointer if it hasn't been set already; see // listenerConnMain. if l.err == nil { l.err = err } l.connectionLock.Unlock() l.cn.c.Close() return false, err } // now we just wait for a reply.. for { m, ok := <-l.replyChan if !ok { // We lost the connection to server, don't bother waiting for a // a response. err should have been set already. l.connectionLock.Lock() err := l.err l.connectionLock.Unlock() return false, err } switch m.typ { case 'Z': // sanity check if m.err != nil { panic("m.err != nil") } // done; err might or might not be set return true, err case 'E': // sanity check if m.err == nil { panic("m.err == nil") } // server responded with an error; ReadyForQuery to follow err = m.err default: return false, fmt.Errorf("unknown response for simple query: %q", m.typ) } } } // Close closes the connection. func (l *ListenerConn) Close() error { l.connectionLock.Lock() if l.err != nil { l.connectionLock.Unlock() return errListenerConnClosed } l.err = errListenerConnClosed l.connectionLock.Unlock() // We can't send anything on the connection without holding senderLock. // Simply close the net.Conn to wake up everyone operating on it. return l.cn.c.Close() } // Err returns the reason the connection was closed. It is not safe to call // this function until l.Notify has been closed. func (l *ListenerConn) Err() error { return l.err } var errListenerClosed = errors.New("pq: Listener has been closed") // ErrChannelAlreadyOpen is returned from Listen when a channel is already // open. var ErrChannelAlreadyOpen = errors.New("pq: channel is already open") // ErrChannelNotOpen is returned from Unlisten when a channel is not open. var ErrChannelNotOpen = errors.New("pq: channel is not open") // ListenerEventType is an enumeration of listener event types. type ListenerEventType int const ( // ListenerEventConnected is emitted only when the database connection // has been initially initialized. The err argument of the callback // will always be nil. ListenerEventConnected ListenerEventType = iota // ListenerEventDisconnected is emitted after a database connection has // been lost, either because of an error or because Close has been // called. The err argument will be set to the reason the database // connection was lost. ListenerEventDisconnected // ListenerEventReconnected is emitted after a database connection has // been re-established after connection loss. The err argument of the // callback will always be nil. After this event has been emitted, a // nil pq.Notification is sent on the Listener.Notify channel. ListenerEventReconnected // ListenerEventConnectionAttemptFailed is emitted after a connection // to the database was attempted, but failed. The err argument will be // set to an error describing why the connection attempt did not // succeed. ListenerEventConnectionAttemptFailed ) // EventCallbackType is the event callback type. See also ListenerEventType // constants' documentation. type EventCallbackType func(event ListenerEventType, err error) // Listener provides an interface for listening to notifications from a // PostgreSQL database. For general usage information, see section // "Notifications". // // Listener can safely be used from concurrently running goroutines. type Listener struct { // Channel for receiving notifications from the database. In some cases a // nil value will be sent. See section "Notifications" above. Notify chan *Notification name string minReconnectInterval time.Duration maxReconnectInterval time.Duration dialer Dialer eventCallback EventCallbackType lock sync.Mutex isClosed bool reconnectCond *sync.Cond cn *ListenerConn connNotificationChan <-chan *Notification channels map[string]struct{} } // NewListener creates a new database connection dedicated to LISTEN / NOTIFY. // // name should be set to a connection string to be used to establish the // database connection (see section "Connection String Parameters" above). // // minReconnectInterval controls the duration to wait before trying to // re-establish the database connection after connection loss. After each // consecutive failure this interval is doubled, until maxReconnectInterval is // reached. Successfully completing the connection establishment procedure // resets the interval back to minReconnectInterval. // // The last parameter eventCallback can be set to a function which will be // called by the Listener when the state of the underlying database connection // changes. This callback will be called by the goroutine which dispatches the // notifications over the Notify channel, so you should try to avoid doing // potentially time-consuming operations from the callback. func NewListener(name string, minReconnectInterval time.Duration, maxReconnectInterval time.Duration, eventCallback EventCallbackType) *Listener { return NewDialListener(defaultDialer{}, name, minReconnectInterval, maxReconnectInterval, eventCallback) } // NewDialListener is like NewListener but it takes a Dialer. func NewDialListener(d Dialer, name string, minReconnectInterval time.Duration, maxReconnectInterval time.Duration, eventCallback EventCallbackType) *Listener { l := &Listener{ name: name, minReconnectInterval: minReconnectInterval, maxReconnectInterval: maxReconnectInterval, dialer: d, eventCallback: eventCallback, channels: make(map[string]struct{}), Notify: make(chan *Notification, 32), } l.reconnectCond = sync.NewCond(&l.lock) go l.listenerMain() return l } // NotificationChannel returns the notification channel for this listener. // This is the same channel as Notify, and will not be recreated during the // life time of the Listener. func (l *Listener) NotificationChannel() <-chan *Notification { return l.Notify } // Listen starts listening for notifications on a channel. Calls to this // function will block until an acknowledgement has been received from the // server. Note that Listener automatically re-establishes the connection // after connection loss, so this function may block indefinitely if the // connection can not be re-established. // // Listen will only fail in three conditions: // 1) The channel is already open. The returned error will be // ErrChannelAlreadyOpen. // 2) The query was executed on the remote server, but PostgreSQL returned an // error message in response to the query. The returned error will be a // pq.Error containing the information the server supplied. // 3) Close is called on the Listener before the request could be completed. // // The channel name is case-sensitive. func (l *Listener) Listen(channel string) error { l.lock.Lock() defer l.lock.Unlock() if l.isClosed { return errListenerClosed } // The server allows you to issue a LISTEN on a channel which is already // open, but it seems useful to be able to detect this case to spot for // mistakes in application logic. If the application genuinely does't // care, it can check the exported error and ignore it. _, exists := l.channels[channel] if exists { return ErrChannelAlreadyOpen } if l.cn != nil { // If gotResponse is true but error is set, the query was executed on // the remote server, but resulted in an error. This should be // relatively rare, so it's fine if we just pass the error to our // caller. However, if gotResponse is false, we could not complete the // query on the remote server and our underlying connection is about // to go away, so we only add relname to l.channels, and wait for // resync() to take care of the rest. gotResponse, err := l.cn.Listen(channel) if gotResponse && err != nil { return err } } l.channels[channel] = struct{}{} for l.cn == nil { l.reconnectCond.Wait() // we let go of the mutex for a while if l.isClosed { return errListenerClosed } } return nil } // Unlisten removes a channel from the Listener's channel list. Returns // ErrChannelNotOpen if the Listener is not listening on the specified channel. // Returns immediately with no error if there is no connection. Note that you // might still get notifications for this channel even after Unlisten has // returned. // // The channel name is case-sensitive. func (l *Listener) Unlisten(channel string) error { l.lock.Lock() defer l.lock.Unlock() if l.isClosed { return errListenerClosed } // Similarly to LISTEN, this is not an error in Postgres, but it seems // useful to distinguish from the normal conditions. _, exists := l.channels[channel] if !exists { return ErrChannelNotOpen } if l.cn != nil { // Similarly to Listen (see comment in that function), the caller // should only be bothered with an error if it came from the backend as // a response to our query. gotResponse, err := l.cn.Unlisten(channel) if gotResponse && err != nil { return err } } // Don't bother waiting for resync if there's no connection. delete(l.channels, channel) return nil } // UnlistenAll removes all channels from the Listener's channel list. Returns // immediately with no error if there is no connection. Note that you might // still get notifications for any of the deleted channels even after // UnlistenAll has returned. func (l *Listener) UnlistenAll() error { l.lock.Lock() defer l.lock.Unlock() if l.isClosed { return errListenerClosed } if l.cn != nil { // Similarly to Listen (see comment in that function), the caller // should only be bothered with an error if it came from the backend as // a response to our query. gotResponse, err := l.cn.UnlistenAll() if gotResponse && err != nil { return err } } // Don't bother waiting for resync if there's no connection. l.channels = make(map[string]struct{}) return nil } // Ping the remote server to make sure it's alive. Non-nil return value means // that there is no active connection. func (l *Listener) Ping() error { l.lock.Lock() defer l.lock.Unlock() if l.isClosed { return errListenerClosed } if l.cn == nil { return errors.New("no connection") } return l.cn.Ping() } // Clean up after losing the server connection. Returns l.cn.Err(), which // should have the reason the connection was lost. func (l *Listener) disconnectCleanup() error { l.lock.Lock() defer l.lock.Unlock() // sanity check; can't look at Err() until the channel has been closed select { case _, ok := <-l.connNotificationChan: if ok { panic("connNotificationChan not closed") } default: panic("connNotificationChan not closed") } err := l.cn.Err() l.cn.Close() l.cn = nil return err } // Synchronize the list of channels we want to be listening on with the server // after the connection has been established. func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notification) error { doneChan := make(chan error) go func(notificationChan <-chan *Notification) { for channel := range l.channels { // If we got a response, return that error to our caller as it's // going to be more descriptive than cn.Err(). gotResponse, err := cn.Listen(channel) if gotResponse && err != nil { doneChan <- err return } // If we couldn't reach the server, wait for notificationChan to // close and then return the error message from the connection, as // per ListenerConn's interface. if err != nil { for range notificationChan { } doneChan <- cn.Err() return } } doneChan <- nil }(notificationChan) // Ignore notifications while synchronization is going on to avoid // deadlocks. We have to send a nil notification over Notify anyway as // we can't possibly know which notifications (if any) were lost while // the connection was down, so there's no reason to try and process // these messages at all. for { select { case _, ok := <-notificationChan: if !ok { notificationChan = nil } case err := <-doneChan: return err } } } // caller should NOT be holding l.lock func (l *Listener) closed() bool { l.lock.Lock() defer l.lock.Unlock() return l.isClosed } func (l *Listener) connect() error { notificationChan := make(chan *Notification, 32) cn, err := newDialListenerConn(l.dialer, l.name, notificationChan) if err != nil { return err } l.lock.Lock() defer l.lock.Unlock() err = l.resync(cn, notificationChan) if err != nil { cn.Close() return err } l.cn = cn l.connNotificationChan = notificationChan l.reconnectCond.Broadcast() return nil } // Close disconnects the Listener from the database and shuts it down. // Subsequent calls to its methods will return an error. Close returns an // error if the connection has already been closed. func (l *Listener) Close() error { l.lock.Lock() defer l.lock.Unlock() if l.isClosed { return errListenerClosed } if l.cn != nil { l.cn.Close() } l.isClosed = true // Unblock calls to Listen() l.reconnectCond.Broadcast() return nil } func (l *Listener) emitEvent(event ListenerEventType, err error) { if l.eventCallback != nil { l.eventCallback(event, err) } } // Main logic here: maintain a connection to the server when possible, wait // for notifications and emit events. func (l *Listener) listenerConnLoop() { var nextReconnect time.Time reconnectInterval := l.minReconnectInterval for { for { err := l.connect() if err == nil { break } if l.closed() { return } l.emitEvent(ListenerEventConnectionAttemptFailed, err) time.Sleep(reconnectInterval) reconnectInterval *= 2 if reconnectInterval > l.maxReconnectInterval { reconnectInterval = l.maxReconnectInterval } } if nextReconnect.IsZero() { l.emitEvent(ListenerEventConnected, nil) } else { l.emitEvent(ListenerEventReconnected, nil) l.Notify <- nil } reconnectInterval = l.minReconnectInterval nextReconnect = time.Now().Add(reconnectInterval) for { notification, ok := <-l.connNotificationChan if !ok { // lost connection, loop again break } l.Notify <- notification } err := l.disconnectCleanup() if l.closed() { return } l.emitEvent(ListenerEventDisconnected, err) time.Sleep(time.Until(nextReconnect)) } } func (l *Listener) listenerMain() { l.listenerConnLoop() close(l.Notify) } ================================================ FILE: vendor/github.com/lib/pq/oid/doc.go ================================================ // Package oid contains OID constants // as defined by the Postgres server. package oid // Oid is a Postgres Object ID. type Oid uint32 ================================================ FILE: vendor/github.com/lib/pq/oid/types.go ================================================ // Code generated by gen.go. DO NOT EDIT. package oid const ( T_bool Oid = 16 T_bytea Oid = 17 T_char Oid = 18 T_name Oid = 19 T_int8 Oid = 20 T_int2 Oid = 21 T_int2vector Oid = 22 T_int4 Oid = 23 T_regproc Oid = 24 T_text Oid = 25 T_oid Oid = 26 T_tid Oid = 27 T_xid Oid = 28 T_cid Oid = 29 T_oidvector Oid = 30 T_pg_ddl_command Oid = 32 T_pg_type Oid = 71 T_pg_attribute Oid = 75 T_pg_proc Oid = 81 T_pg_class Oid = 83 T_json Oid = 114 T_xml Oid = 142 T__xml Oid = 143 T_pg_node_tree Oid = 194 T__json Oid = 199 T_smgr Oid = 210 T_index_am_handler Oid = 325 T_point Oid = 600 T_lseg Oid = 601 T_path Oid = 602 T_box Oid = 603 T_polygon Oid = 604 T_line Oid = 628 T__line Oid = 629 T_cidr Oid = 650 T__cidr Oid = 651 T_float4 Oid = 700 T_float8 Oid = 701 T_abstime Oid = 702 T_reltime Oid = 703 T_tinterval Oid = 704 T_unknown Oid = 705 T_circle Oid = 718 T__circle Oid = 719 T_money Oid = 790 T__money Oid = 791 T_macaddr Oid = 829 T_inet Oid = 869 T__bool Oid = 1000 T__bytea Oid = 1001 T__char Oid = 1002 T__name Oid = 1003 T__int2 Oid = 1005 T__int2vector Oid = 1006 T__int4 Oid = 1007 T__regproc Oid = 1008 T__text Oid = 1009 T__tid Oid = 1010 T__xid Oid = 1011 T__cid Oid = 1012 T__oidvector Oid = 1013 T__bpchar Oid = 1014 T__varchar Oid = 1015 T__int8 Oid = 1016 T__point Oid = 1017 T__lseg Oid = 1018 T__path Oid = 1019 T__box Oid = 1020 T__float4 Oid = 1021 T__float8 Oid = 1022 T__abstime Oid = 1023 T__reltime Oid = 1024 T__tinterval Oid = 1025 T__polygon Oid = 1027 T__oid Oid = 1028 T_aclitem Oid = 1033 T__aclitem Oid = 1034 T__macaddr Oid = 1040 T__inet Oid = 1041 T_bpchar Oid = 1042 T_varchar Oid = 1043 T_date Oid = 1082 T_time Oid = 1083 T_timestamp Oid = 1114 T__timestamp Oid = 1115 T__date Oid = 1182 T__time Oid = 1183 T_timestamptz Oid = 1184 T__timestamptz Oid = 1185 T_interval Oid = 1186 T__interval Oid = 1187 T__numeric Oid = 1231 T_pg_database Oid = 1248 T__cstring Oid = 1263 T_timetz Oid = 1266 T__timetz Oid = 1270 T_bit Oid = 1560 T__bit Oid = 1561 T_varbit Oid = 1562 T__varbit Oid = 1563 T_numeric Oid = 1700 T_refcursor Oid = 1790 T__refcursor Oid = 2201 T_regprocedure Oid = 2202 T_regoper Oid = 2203 T_regoperator Oid = 2204 T_regclass Oid = 2205 T_regtype Oid = 2206 T__regprocedure Oid = 2207 T__regoper Oid = 2208 T__regoperator Oid = 2209 T__regclass Oid = 2210 T__regtype Oid = 2211 T_record Oid = 2249 T_cstring Oid = 2275 T_any Oid = 2276 T_anyarray Oid = 2277 T_void Oid = 2278 T_trigger Oid = 2279 T_language_handler Oid = 2280 T_internal Oid = 2281 T_opaque Oid = 2282 T_anyelement Oid = 2283 T__record Oid = 2287 T_anynonarray Oid = 2776 T_pg_authid Oid = 2842 T_pg_auth_members Oid = 2843 T__txid_snapshot Oid = 2949 T_uuid Oid = 2950 T__uuid Oid = 2951 T_txid_snapshot Oid = 2970 T_fdw_handler Oid = 3115 T_pg_lsn Oid = 3220 T__pg_lsn Oid = 3221 T_tsm_handler Oid = 3310 T_anyenum Oid = 3500 T_tsvector Oid = 3614 T_tsquery Oid = 3615 T_gtsvector Oid = 3642 T__tsvector Oid = 3643 T__gtsvector Oid = 3644 T__tsquery Oid = 3645 T_regconfig Oid = 3734 T__regconfig Oid = 3735 T_regdictionary Oid = 3769 T__regdictionary Oid = 3770 T_jsonb Oid = 3802 T__jsonb Oid = 3807 T_anyrange Oid = 3831 T_event_trigger Oid = 3838 T_int4range Oid = 3904 T__int4range Oid = 3905 T_numrange Oid = 3906 T__numrange Oid = 3907 T_tsrange Oid = 3908 T__tsrange Oid = 3909 T_tstzrange Oid = 3910 T__tstzrange Oid = 3911 T_daterange Oid = 3912 T__daterange Oid = 3913 T_int8range Oid = 3926 T__int8range Oid = 3927 T_pg_shseclabel Oid = 4066 T_regnamespace Oid = 4089 T__regnamespace Oid = 4090 T_regrole Oid = 4096 T__regrole Oid = 4097 ) var TypeName = map[Oid]string{ T_bool: "BOOL", T_bytea: "BYTEA", T_char: "CHAR", T_name: "NAME", T_int8: "INT8", T_int2: "INT2", T_int2vector: "INT2VECTOR", T_int4: "INT4", T_regproc: "REGPROC", T_text: "TEXT", T_oid: "OID", T_tid: "TID", T_xid: "XID", T_cid: "CID", T_oidvector: "OIDVECTOR", T_pg_ddl_command: "PG_DDL_COMMAND", T_pg_type: "PG_TYPE", T_pg_attribute: "PG_ATTRIBUTE", T_pg_proc: "PG_PROC", T_pg_class: "PG_CLASS", T_json: "JSON", T_xml: "XML", T__xml: "_XML", T_pg_node_tree: "PG_NODE_TREE", T__json: "_JSON", T_smgr: "SMGR", T_index_am_handler: "INDEX_AM_HANDLER", T_point: "POINT", T_lseg: "LSEG", T_path: "PATH", T_box: "BOX", T_polygon: "POLYGON", T_line: "LINE", T__line: "_LINE", T_cidr: "CIDR", T__cidr: "_CIDR", T_float4: "FLOAT4", T_float8: "FLOAT8", T_abstime: "ABSTIME", T_reltime: "RELTIME", T_tinterval: "TINTERVAL", T_unknown: "UNKNOWN", T_circle: "CIRCLE", T__circle: "_CIRCLE", T_money: "MONEY", T__money: "_MONEY", T_macaddr: "MACADDR", T_inet: "INET", T__bool: "_BOOL", T__bytea: "_BYTEA", T__char: "_CHAR", T__name: "_NAME", T__int2: "_INT2", T__int2vector: "_INT2VECTOR", T__int4: "_INT4", T__regproc: "_REGPROC", T__text: "_TEXT", T__tid: "_TID", T__xid: "_XID", T__cid: "_CID", T__oidvector: "_OIDVECTOR", T__bpchar: "_BPCHAR", T__varchar: "_VARCHAR", T__int8: "_INT8", T__point: "_POINT", T__lseg: "_LSEG", T__path: "_PATH", T__box: "_BOX", T__float4: "_FLOAT4", T__float8: "_FLOAT8", T__abstime: "_ABSTIME", T__reltime: "_RELTIME", T__tinterval: "_TINTERVAL", T__polygon: "_POLYGON", T__oid: "_OID", T_aclitem: "ACLITEM", T__aclitem: "_ACLITEM", T__macaddr: "_MACADDR", T__inet: "_INET", T_bpchar: "BPCHAR", T_varchar: "VARCHAR", T_date: "DATE", T_time: "TIME", T_timestamp: "TIMESTAMP", T__timestamp: "_TIMESTAMP", T__date: "_DATE", T__time: "_TIME", T_timestamptz: "TIMESTAMPTZ", T__timestamptz: "_TIMESTAMPTZ", T_interval: "INTERVAL", T__interval: "_INTERVAL", T__numeric: "_NUMERIC", T_pg_database: "PG_DATABASE", T__cstring: "_CSTRING", T_timetz: "TIMETZ", T__timetz: "_TIMETZ", T_bit: "BIT", T__bit: "_BIT", T_varbit: "VARBIT", T__varbit: "_VARBIT", T_numeric: "NUMERIC", T_refcursor: "REFCURSOR", T__refcursor: "_REFCURSOR", T_regprocedure: "REGPROCEDURE", T_regoper: "REGOPER", T_regoperator: "REGOPERATOR", T_regclass: "REGCLASS", T_regtype: "REGTYPE", T__regprocedure: "_REGPROCEDURE", T__regoper: "_REGOPER", T__regoperator: "_REGOPERATOR", T__regclass: "_REGCLASS", T__regtype: "_REGTYPE", T_record: "RECORD", T_cstring: "CSTRING", T_any: "ANY", T_anyarray: "ANYARRAY", T_void: "VOID", T_trigger: "TRIGGER", T_language_handler: "LANGUAGE_HANDLER", T_internal: "INTERNAL", T_opaque: "OPAQUE", T_anyelement: "ANYELEMENT", T__record: "_RECORD", T_anynonarray: "ANYNONARRAY", T_pg_authid: "PG_AUTHID", T_pg_auth_members: "PG_AUTH_MEMBERS", T__txid_snapshot: "_TXID_SNAPSHOT", T_uuid: "UUID", T__uuid: "_UUID", T_txid_snapshot: "TXID_SNAPSHOT", T_fdw_handler: "FDW_HANDLER", T_pg_lsn: "PG_LSN", T__pg_lsn: "_PG_LSN", T_tsm_handler: "TSM_HANDLER", T_anyenum: "ANYENUM", T_tsvector: "TSVECTOR", T_tsquery: "TSQUERY", T_gtsvector: "GTSVECTOR", T__tsvector: "_TSVECTOR", T__gtsvector: "_GTSVECTOR", T__tsquery: "_TSQUERY", T_regconfig: "REGCONFIG", T__regconfig: "_REGCONFIG", T_regdictionary: "REGDICTIONARY", T__regdictionary: "_REGDICTIONARY", T_jsonb: "JSONB", T__jsonb: "_JSONB", T_anyrange: "ANYRANGE", T_event_trigger: "EVENT_TRIGGER", T_int4range: "INT4RANGE", T__int4range: "_INT4RANGE", T_numrange: "NUMRANGE", T__numrange: "_NUMRANGE", T_tsrange: "TSRANGE", T__tsrange: "_TSRANGE", T_tstzrange: "TSTZRANGE", T__tstzrange: "_TSTZRANGE", T_daterange: "DATERANGE", T__daterange: "_DATERANGE", T_int8range: "INT8RANGE", T__int8range: "_INT8RANGE", T_pg_shseclabel: "PG_SHSECLABEL", T_regnamespace: "REGNAMESPACE", T__regnamespace: "_REGNAMESPACE", T_regrole: "REGROLE", T__regrole: "_REGROLE", } ================================================ FILE: vendor/github.com/lib/pq/rows.go ================================================ package pq import ( "math" "reflect" "time" "github.com/lib/pq/oid" ) const headerSize = 4 type fieldDesc struct { // The object ID of the data type. OID oid.Oid // The data type size (see pg_type.typlen). // Note that negative values denote variable-width types. Len int // The type modifier (see pg_attribute.atttypmod). // The meaning of the modifier is type-specific. Mod int } func (fd fieldDesc) Type() reflect.Type { switch fd.OID { case oid.T_int8: return reflect.TypeOf(int64(0)) case oid.T_int4: return reflect.TypeOf(int32(0)) case oid.T_int2: return reflect.TypeOf(int16(0)) case oid.T_varchar, oid.T_text: return reflect.TypeOf("") case oid.T_bool: return reflect.TypeOf(false) case oid.T_date, oid.T_time, oid.T_timetz, oid.T_timestamp, oid.T_timestamptz: return reflect.TypeOf(time.Time{}) case oid.T_bytea: return reflect.TypeOf([]byte(nil)) default: return reflect.TypeOf(new(interface{})).Elem() } } func (fd fieldDesc) Name() string { return oid.TypeName[fd.OID] } func (fd fieldDesc) Length() (length int64, ok bool) { switch fd.OID { case oid.T_text, oid.T_bytea: return math.MaxInt64, true case oid.T_varchar, oid.T_bpchar: return int64(fd.Mod - headerSize), true default: return 0, false } } func (fd fieldDesc) PrecisionScale() (precision, scale int64, ok bool) { switch fd.OID { case oid.T_numeric, oid.T__numeric: mod := fd.Mod - headerSize precision = int64((mod >> 16) & 0xffff) scale = int64(mod & 0xffff) return precision, scale, true default: return 0, 0, false } } // ColumnTypeScanType returns the value type that can be used to scan types into. func (rs *rows) ColumnTypeScanType(index int) reflect.Type { return rs.colTyps[index].Type() } // ColumnTypeDatabaseTypeName return the database system type name. func (rs *rows) ColumnTypeDatabaseTypeName(index int) string { return rs.colTyps[index].Name() } // ColumnTypeLength returns the length of the column type if the column is a // variable length type. If the column is not a variable length type ok // should return false. func (rs *rows) ColumnTypeLength(index int) (length int64, ok bool) { return rs.colTyps[index].Length() } // ColumnTypePrecisionScale should return the precision and scale for decimal // types. If not applicable, ok should be false. func (rs *rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { return rs.colTyps[index].PrecisionScale() } ================================================ FILE: vendor/github.com/lib/pq/scram/scram.go ================================================ // Copyright (c) 2014 - Gustavo Niemeyer // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Package scram implements a SCRAM-{SHA-1,etc} client per RFC5802. // // http://tools.ietf.org/html/rfc5802 // package scram import ( "bytes" "crypto/hmac" "crypto/rand" "encoding/base64" "fmt" "hash" "strconv" "strings" ) // Client implements a SCRAM-* client (SCRAM-SHA-1, SCRAM-SHA-256, etc). // // A Client may be used within a SASL conversation with logic resembling: // // var in []byte // var client = scram.NewClient(sha1.New, user, pass) // for client.Step(in) { // out := client.Out() // // send out to server // in := serverOut // } // if client.Err() != nil { // // auth failed // } // type Client struct { newHash func() hash.Hash user string pass string step int out bytes.Buffer err error clientNonce []byte serverNonce []byte saltedPass []byte authMsg bytes.Buffer } // NewClient returns a new SCRAM-* client with the provided hash algorithm. // // For SCRAM-SHA-256, for example, use: // // client := scram.NewClient(sha256.New, user, pass) // func NewClient(newHash func() hash.Hash, user, pass string) *Client { c := &Client{ newHash: newHash, user: user, pass: pass, } c.out.Grow(256) c.authMsg.Grow(256) return c } // Out returns the data to be sent to the server in the current step. func (c *Client) Out() []byte { if c.out.Len() == 0 { return nil } return c.out.Bytes() } // Err returns the error that occurred, or nil if there were no errors. func (c *Client) Err() error { return c.err } // SetNonce sets the client nonce to the provided value. // If not set, the nonce is generated automatically out of crypto/rand on the first step. func (c *Client) SetNonce(nonce []byte) { c.clientNonce = nonce } var escaper = strings.NewReplacer("=", "=3D", ",", "=2C") // Step processes the incoming data from the server and makes the // next round of data for the server available via Client.Out. // Step returns false if there are no errors and more data is // still expected. func (c *Client) Step(in []byte) bool { c.out.Reset() if c.step > 2 || c.err != nil { return false } c.step++ switch c.step { case 1: c.err = c.step1(in) case 2: c.err = c.step2(in) case 3: c.err = c.step3(in) } return c.step > 2 || c.err != nil } func (c *Client) step1(in []byte) error { if len(c.clientNonce) == 0 { const nonceLen = 16 buf := make([]byte, nonceLen+b64.EncodedLen(nonceLen)) if _, err := rand.Read(buf[:nonceLen]); err != nil { return fmt.Errorf("cannot read random SCRAM-SHA-256 nonce from operating system: %v", err) } c.clientNonce = buf[nonceLen:] b64.Encode(c.clientNonce, buf[:nonceLen]) } c.authMsg.WriteString("n=") escaper.WriteString(&c.authMsg, c.user) c.authMsg.WriteString(",r=") c.authMsg.Write(c.clientNonce) c.out.WriteString("n,,") c.out.Write(c.authMsg.Bytes()) return nil } var b64 = base64.StdEncoding func (c *Client) step2(in []byte) error { c.authMsg.WriteByte(',') c.authMsg.Write(in) fields := bytes.Split(in, []byte(",")) if len(fields) != 3 { return fmt.Errorf("expected 3 fields in first SCRAM-SHA-256 server message, got %d: %q", len(fields), in) } if !bytes.HasPrefix(fields[0], []byte("r=")) || len(fields[0]) < 2 { return fmt.Errorf("server sent an invalid SCRAM-SHA-256 nonce: %q", fields[0]) } if !bytes.HasPrefix(fields[1], []byte("s=")) || len(fields[1]) < 6 { return fmt.Errorf("server sent an invalid SCRAM-SHA-256 salt: %q", fields[1]) } if !bytes.HasPrefix(fields[2], []byte("i=")) || len(fields[2]) < 6 { return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2]) } c.serverNonce = fields[0][2:] if !bytes.HasPrefix(c.serverNonce, c.clientNonce) { return fmt.Errorf("server SCRAM-SHA-256 nonce is not prefixed by client nonce: got %q, want %q+\"...\"", c.serverNonce, c.clientNonce) } salt := make([]byte, b64.DecodedLen(len(fields[1][2:]))) n, err := b64.Decode(salt, fields[1][2:]) if err != nil { return fmt.Errorf("cannot decode SCRAM-SHA-256 salt sent by server: %q", fields[1]) } salt = salt[:n] iterCount, err := strconv.Atoi(string(fields[2][2:])) if err != nil { return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2]) } c.saltPassword(salt, iterCount) c.authMsg.WriteString(",c=biws,r=") c.authMsg.Write(c.serverNonce) c.out.WriteString("c=biws,r=") c.out.Write(c.serverNonce) c.out.WriteString(",p=") c.out.Write(c.clientProof()) return nil } func (c *Client) step3(in []byte) error { var isv, ise bool var fields = bytes.Split(in, []byte(",")) if len(fields) == 1 { isv = bytes.HasPrefix(fields[0], []byte("v=")) ise = bytes.HasPrefix(fields[0], []byte("e=")) } if ise { return fmt.Errorf("SCRAM-SHA-256 authentication error: %s", fields[0][2:]) } else if !isv { return fmt.Errorf("unsupported SCRAM-SHA-256 final message from server: %q", in) } if !bytes.Equal(c.serverSignature(), fields[0][2:]) { return fmt.Errorf("cannot authenticate SCRAM-SHA-256 server signature: %q", fields[0][2:]) } return nil } func (c *Client) saltPassword(salt []byte, iterCount int) { mac := hmac.New(c.newHash, []byte(c.pass)) mac.Write(salt) mac.Write([]byte{0, 0, 0, 1}) ui := mac.Sum(nil) hi := make([]byte, len(ui)) copy(hi, ui) for i := 1; i < iterCount; i++ { mac.Reset() mac.Write(ui) mac.Sum(ui[:0]) for j, b := range ui { hi[j] ^= b } } c.saltedPass = hi } func (c *Client) clientProof() []byte { mac := hmac.New(c.newHash, c.saltedPass) mac.Write([]byte("Client Key")) clientKey := mac.Sum(nil) hash := c.newHash() hash.Write(clientKey) storedKey := hash.Sum(nil) mac = hmac.New(c.newHash, storedKey) mac.Write(c.authMsg.Bytes()) clientProof := mac.Sum(nil) for i, b := range clientKey { clientProof[i] ^= b } clientProof64 := make([]byte, b64.EncodedLen(len(clientProof))) b64.Encode(clientProof64, clientProof) return clientProof64 } func (c *Client) serverSignature() []byte { mac := hmac.New(c.newHash, c.saltedPass) mac.Write([]byte("Server Key")) serverKey := mac.Sum(nil) mac = hmac.New(c.newHash, serverKey) mac.Write(c.authMsg.Bytes()) serverSignature := mac.Sum(nil) encoded := make([]byte, b64.EncodedLen(len(serverSignature))) b64.Encode(encoded, serverSignature) return encoded } ================================================ FILE: vendor/github.com/lib/pq/ssl.go ================================================ package pq import ( "crypto/tls" "crypto/x509" "io/ioutil" "net" "os" "os/user" "path/filepath" "strings" ) // ssl generates a function to upgrade a net.Conn based on the "sslmode" and // related settings. The function is nil when no upgrade should take place. func ssl(o values) (func(net.Conn) (net.Conn, error), error) { verifyCaOnly := false tlsConf := tls.Config{} switch mode := o["sslmode"]; mode { // "require" is the default. case "", "require": // We must skip TLS's own verification since it requires full // verification since Go 1.3. tlsConf.InsecureSkipVerify = true // From http://www.postgresql.org/docs/current/static/libpq-ssl.html: // // Note: For backwards compatibility with earlier versions of // PostgreSQL, if a root CA file exists, the behavior of // sslmode=require will be the same as that of verify-ca, meaning the // server certificate is validated against the CA. Relying on this // behavior is discouraged, and applications that need certificate // validation should always use verify-ca or verify-full. if sslrootcert, ok := o["sslrootcert"]; ok { if _, err := os.Stat(sslrootcert); err == nil { verifyCaOnly = true } else { delete(o, "sslrootcert") } } case "verify-ca": // We must skip TLS's own verification since it requires full // verification since Go 1.3. tlsConf.InsecureSkipVerify = true verifyCaOnly = true case "verify-full": tlsConf.ServerName = o["host"] case "disable": return nil, nil default: return nil, fmterrorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode) } // Set Server Name Indication (SNI), if enabled by connection parameters. // By default SNI is on, any value which is not starting with "1" disables // SNI -- that is the same check vanilla libpq uses. if sslsni := o["sslsni"]; sslsni == "" || strings.HasPrefix(sslsni, "1") { // RFC 6066 asks to not set SNI if the host is a literal IP address (IPv4 // or IPv6). This check is coded already crypto.tls.hostnameInSNI, so // just always set ServerName here and let crypto/tls do the filtering. tlsConf.ServerName = o["host"] } err := sslClientCertificates(&tlsConf, o) if err != nil { return nil, err } err = sslCertificateAuthority(&tlsConf, o) if err != nil { return nil, err } // Accept renegotiation requests initiated by the backend. // // Renegotiation was deprecated then removed from PostgreSQL 9.5, but // the default configuration of older versions has it enabled. Redshift // also initiates renegotiations and cannot be reconfigured. tlsConf.Renegotiation = tls.RenegotiateFreelyAsClient return func(conn net.Conn) (net.Conn, error) { client := tls.Client(conn, &tlsConf) if verifyCaOnly { err := sslVerifyCertificateAuthority(client, &tlsConf) if err != nil { return nil, err } } return client, nil }, nil } // sslClientCertificates adds the certificate specified in the "sslcert" and // "sslkey" settings, or if they aren't set, from the .postgresql directory // in the user's home directory. The configured files must exist and have // the correct permissions. func sslClientCertificates(tlsConf *tls.Config, o values) error { sslinline := o["sslinline"] if sslinline == "true" { cert, err := tls.X509KeyPair([]byte(o["sslcert"]), []byte(o["sslkey"])) if err != nil { return err } tlsConf.Certificates = []tls.Certificate{cert} return nil } // user.Current() might fail when cross-compiling. We have to ignore the // error and continue without home directory defaults, since we wouldn't // know from where to load them. user, _ := user.Current() // In libpq, the client certificate is only loaded if the setting is not blank. // // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1036-L1037 sslcert := o["sslcert"] if len(sslcert) == 0 && user != nil { sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt") } // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045 if len(sslcert) == 0 { return nil } // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054 if _, err := os.Stat(sslcert); os.IsNotExist(err) { return nil } else if err != nil { return err } // In libpq, the ssl key is only loaded if the setting is not blank. // // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1123-L1222 sslkey := o["sslkey"] if len(sslkey) == 0 && user != nil { sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key") } if len(sslkey) > 0 { if err := sslKeyPermissions(sslkey); err != nil { return err } } cert, err := tls.LoadX509KeyPair(sslcert, sslkey) if err != nil { return err } tlsConf.Certificates = []tls.Certificate{cert} return nil } // sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting. func sslCertificateAuthority(tlsConf *tls.Config, o values) error { // In libpq, the root certificate is only loaded if the setting is not blank. // // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951 if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 { tlsConf.RootCAs = x509.NewCertPool() sslinline := o["sslinline"] var cert []byte if sslinline == "true" { cert = []byte(sslrootcert) } else { var err error cert, err = ioutil.ReadFile(sslrootcert) if err != nil { return err } } if !tlsConf.RootCAs.AppendCertsFromPEM(cert) { return fmterrorf("couldn't parse pem in sslrootcert") } } return nil } // sslVerifyCertificateAuthority carries out a TLS handshake to the server and // verifies the presented certificate against the CA, i.e. the one specified in // sslrootcert or the system CA if sslrootcert was not specified. func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) error { err := client.Handshake() if err != nil { return err } certs := client.ConnectionState().PeerCertificates opts := x509.VerifyOptions{ DNSName: client.ConnectionState().ServerName, Intermediates: x509.NewCertPool(), Roots: tlsConf.RootCAs, } for i, cert := range certs { if i == 0 { continue } opts.Intermediates.AddCert(cert) } _, err = certs[0].Verify(opts) return err } ================================================ FILE: vendor/github.com/lib/pq/ssl_permissions.go ================================================ //go:build !windows // +build !windows package pq import ( "errors" "os" "syscall" ) const ( rootUserID = uint32(0) // The maximum permissions that a private key file owned by a regular user // is allowed to have. This translates to u=rw. maxUserOwnedKeyPermissions os.FileMode = 0600 // The maximum permissions that a private key file owned by root is allowed // to have. This translates to u=rw,g=r. maxRootOwnedKeyPermissions os.FileMode = 0640 ) var ( errSSLKeyHasUnacceptableUserPermissions = errors.New("permissions for files not owned by root should be u=rw (0600) or less") errSSLKeyHasUnacceptableRootPermissions = errors.New("permissions for root owned files should be u=rw,g=r (0640) or less") ) // sslKeyPermissions checks the permissions on user-supplied ssl key files. // The key file should have very little access. // // libpq does not check key file permissions on Windows. func sslKeyPermissions(sslkey string) error { info, err := os.Stat(sslkey) if err != nil { return err } err = hasCorrectPermissions(info) // return ErrSSLKeyHasWorldPermissions for backwards compatability with // existing code. if err == errSSLKeyHasUnacceptableUserPermissions || err == errSSLKeyHasUnacceptableRootPermissions { err = ErrSSLKeyHasWorldPermissions } return err } // hasCorrectPermissions checks the file info (and the unix-specific stat_t // output) to verify that the permissions on the file are correct. // // If the file is owned by the same user the process is running as, // the file should only have 0600 (u=rw). If the file is owned by root, // and the group matches the group that the process is running in, the // permissions cannot be more than 0640 (u=rw,g=r). The file should // never have world permissions. // // Returns an error when the permission check fails. func hasCorrectPermissions(info os.FileInfo) error { // if file's permission matches 0600, allow access. userPermissionMask := (os.FileMode(0777) ^ maxUserOwnedKeyPermissions) // regardless of if we're running as root or not, 0600 is acceptable, // so we return if we match the regular user permission mask. if info.Mode().Perm()&userPermissionMask == 0 { return nil } // We need to pull the Unix file information to get the file's owner. // If we can't access it, there's some sort of operating system level error // and we should fail rather than attempting to use faulty information. sysInfo := info.Sys() if sysInfo == nil { return ErrSSLKeyUnknownOwnership } unixStat, ok := sysInfo.(*syscall.Stat_t) if !ok { return ErrSSLKeyUnknownOwnership } // if the file is owned by root, we allow 0640 (u=rw,g=r) to match what // Postgres does. if unixStat.Uid == rootUserID { rootPermissionMask := (os.FileMode(0777) ^ maxRootOwnedKeyPermissions) if info.Mode().Perm()&rootPermissionMask != 0 { return errSSLKeyHasUnacceptableRootPermissions } return nil } return errSSLKeyHasUnacceptableUserPermissions } ================================================ FILE: vendor/github.com/lib/pq/ssl_windows.go ================================================ //go:build windows // +build windows package pq // sslKeyPermissions checks the permissions on user-supplied ssl key files. // The key file should have very little access. // // libpq does not check key file permissions on Windows. func sslKeyPermissions(string) error { return nil } ================================================ FILE: vendor/github.com/lib/pq/url.go ================================================ package pq import ( "fmt" "net" nurl "net/url" "sort" "strings" ) // ParseURL no longer needs to be used by clients of this library since supplying a URL as a // connection string to sql.Open() is now supported: // // sql.Open("postgres", "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full") // // It remains exported here for backwards-compatibility. // // ParseURL converts a url to a connection string for driver.Open. // Example: // // "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full" // // converts to: // // "user=bob password=secret host=1.2.3.4 port=5432 dbname=mydb sslmode=verify-full" // // A minimal example: // // "postgres://" // // This will be blank, causing driver.Open to use all of the defaults func ParseURL(url string) (string, error) { u, err := nurl.Parse(url) if err != nil { return "", err } if u.Scheme != "postgres" && u.Scheme != "postgresql" { return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) } var kvs []string escaper := strings.NewReplacer(`'`, `\'`, `\`, `\\`) accrue := func(k, v string) { if v != "" { kvs = append(kvs, k+"='"+escaper.Replace(v)+"'") } } if u.User != nil { v := u.User.Username() accrue("user", v) v, _ = u.User.Password() accrue("password", v) } if host, port, err := net.SplitHostPort(u.Host); err != nil { accrue("host", u.Host) } else { accrue("host", host) accrue("port", port) } if u.Path != "" { accrue("dbname", u.Path[1:]) } q := u.Query() for k := range q { accrue(k, q.Get(k)) } sort.Strings(kvs) // Makes testing easier (not a performance concern) return strings.Join(kvs, " "), nil } ================================================ FILE: vendor/github.com/lib/pq/user_other.go ================================================ // Package pq is a pure Go Postgres driver for the database/sql package. //go:build js || android || hurd || zos // +build js android hurd zos package pq func userCurrent() (string, error) { return "", ErrCouldNotDetectUsername } ================================================ FILE: vendor/github.com/lib/pq/user_posix.go ================================================ // Package pq is a pure Go Postgres driver for the database/sql package. //go:build aix || darwin || dragonfly || freebsd || (linux && !android) || nacl || netbsd || openbsd || plan9 || solaris || rumprun || illumos // +build aix darwin dragonfly freebsd linux,!android nacl netbsd openbsd plan9 solaris rumprun illumos package pq import ( "os" "os/user" ) func userCurrent() (string, error) { u, err := user.Current() if err == nil { return u.Username, nil } name := os.Getenv("USER") if name != "" { return name, nil } return "", ErrCouldNotDetectUsername } ================================================ FILE: vendor/github.com/lib/pq/user_windows.go ================================================ // Package pq is a pure Go Postgres driver for the database/sql package. package pq import ( "path/filepath" "syscall" ) // Perform Windows user name lookup identically to libpq. // // The PostgreSQL code makes use of the legacy Win32 function // GetUserName, and that function has not been imported into stock Go. // GetUserNameEx is available though, the difference being that a // wider range of names are available. To get the output to be the // same as GetUserName, only the base (or last) component of the // result is returned. func userCurrent() (string, error) { pw_name := make([]uint16, 128) pwname_size := uint32(len(pw_name)) - 1 err := syscall.GetUserNameEx(syscall.NameSamCompatible, &pw_name[0], &pwname_size) if err != nil { return "", ErrCouldNotDetectUsername } s := syscall.UTF16ToString(pw_name) u := filepath.Base(s) return u, nil } ================================================ FILE: vendor/github.com/lib/pq/uuid.go ================================================ package pq import ( "encoding/hex" "fmt" ) // decodeUUIDBinary interprets the binary format of a uuid, returning it in text format. func decodeUUIDBinary(src []byte) ([]byte, error) { if len(src) != 16 { return nil, fmt.Errorf("pq: unable to decode uuid; bad length: %d", len(src)) } dst := make([]byte, 36) dst[8], dst[13], dst[18], dst[23] = '-', '-', '-', '-' hex.Encode(dst[0:], src[0:4]) hex.Encode(dst[9:], src[4:6]) hex.Encode(dst[14:], src[6:8]) hex.Encode(dst[19:], src[8:10]) hex.Encode(dst[24:], src[10:16]) return dst, nil } ================================================ FILE: vendor/github.com/mattn/go-sqlite3/.codecov.yml ================================================ coverage: status: project: off patch: off ================================================ FILE: vendor/github.com/mattn/go-sqlite3/.gitignore ================================================ *.db *.exe *.dll *.o # VSCode .vscode # Exclude from upgrade upgrade/*.c upgrade/*.h # Exclude upgrade binary upgrade/upgrade ================================================ FILE: vendor/github.com/mattn/go-sqlite3/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Yasuhiro Matsumoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: vendor/github.com/mattn/go-sqlite3/README.md ================================================ go-sqlite3 ========== [![Go Reference](https://pkg.go.dev/badge/github.com/mattn/go-sqlite3.svg)](https://pkg.go.dev/github.com/mattn/go-sqlite3) [![GitHub Actions](https://github.com/mattn/go-sqlite3/workflows/Go/badge.svg)](https://github.com/mattn/go-sqlite3/actions?query=workflow%3AGo) [![Financial Contributors on Open Collective](https://opencollective.com/mattn-go-sqlite3/all/badge.svg?label=financial+contributors)](https://opencollective.com/mattn-go-sqlite3) [![codecov](https://codecov.io/gh/mattn/go-sqlite3/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-sqlite3) [![Go Report Card](https://goreportcard.com/badge/github.com/mattn/go-sqlite3)](https://goreportcard.com/report/github.com/mattn/go-sqlite3) Latest stable version is v1.14 or later, not v2. ~~**NOTE:** The increase to v2 was an accident. There were no major changes or features.~~ # Description A sqlite3 driver that conforms to the built-in database/sql interface. Supported Golang version: See [.github/workflows/go.yaml](./.github/workflows/go.yaml). This package follows the official [Golang Release Policy](https://golang.org/doc/devel/release.html#policy). ### Overview - [go-sqlite3](#go-sqlite3) - [Description](#description) - [Overview](#overview) - [Installation](#installation) - [API Reference](#api-reference) - [Connection String](#connection-string) - [DSN Examples](#dsn-examples) - [Features](#features) - [Usage](#usage) - [Feature / Extension List](#feature--extension-list) - [Compilation](#compilation) - [Android](#android) - [ARM](#arm) - [Cross Compile](#cross-compile) - [Google Cloud Platform](#google-cloud-platform) - [Linux](#linux) - [Alpine](#alpine) - [Fedora](#fedora) - [Ubuntu](#ubuntu) - [macOS](#mac-osx) - [Windows](#windows) - [Errors](#errors) - [User Authentication](#user-authentication) - [Compile](#compile) - [Usage](#usage-1) - [Create protected database](#create-protected-database) - [Password Encoding](#password-encoding) - [Available Encoders](#available-encoders) - [Restrictions](#restrictions) - [Support](#support) - [User Management](#user-management) - [SQL](#sql) - [Examples](#examples) - [*SQLiteConn](#sqliteconn) - [Attached database](#attached-database) - [Extensions](#extensions) - [Spatialite](#spatialite) - [FAQ](#faq) - [License](#license) - [Author](#author) # Installation This package can be installed with the `go get` command: go get github.com/mattn/go-sqlite3 _go-sqlite3_ is *cgo* package. If you want to build your app using go-sqlite3, you need gcc. However, after you have built and installed _go-sqlite3_ with `go install github.com/mattn/go-sqlite3` (which requires gcc), you can build your app without relying on gcc in future. ***Important: because this is a `CGO` enabled package, you are required to set the environment variable `CGO_ENABLED=1` and have a `gcc` compiler present within your path.*** # API Reference API documentation can be found [here](http://godoc.org/github.com/mattn/go-sqlite3). Examples can be found under the [examples](./_example) directory. # Connection String When creating a new SQLite database or connection to an existing one, with the file name additional options can be given. This is also known as a DSN (Data Source Name) string. Options are append after the filename of the SQLite database. The database filename and options are separated by an `?` (Question Mark). Options should be URL-encoded (see [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)). This also applies when using an in-memory database instead of a file. Options can be given using the following format: `KEYWORD=VALUE` and multiple options can be combined with the `&` ampersand. This library supports DSN options of SQLite itself and provides additional options. Boolean values can be one of: * `0` `no` `false` `off` * `1` `yes` `true` `on` | Name | Key | Value(s) | Description | |------|-----|----------|-------------| | UA - Create | `_auth` | - | Create User Authentication, for more information see [User Authentication](#user-authentication) | | UA - Username | `_auth_user` | `string` | Username for User Authentication, for more information see [User Authentication](#user-authentication) | | UA - Password | `_auth_pass` | `string` | Password for User Authentication, for more information see [User Authentication](#user-authentication) | | UA - Crypt | `_auth_crypt` |
  • SHA1
  • SSHA1
  • SHA256
  • SSHA256
  • SHA384
  • SSHA384
  • SHA512
  • SSHA512
| Password encoder to use for User Authentication, for more information see [User Authentication](#user-authentication) | | UA - Salt | `_auth_salt` | `string` | Salt to use if the configure password encoder requires a salt, for User Authentication, for more information see [User Authentication](#user-authentication) | | Auto Vacuum | `_auto_vacuum` \| `_vacuum` |
  • `0` \| `none`
  • `1` \| `full`
  • `2` \| `incremental`
| For more information see [PRAGMA auto_vacuum](https://www.sqlite.org/pragma.html#pragma_auto_vacuum) | | Busy Timeout | `_busy_timeout` \| `_timeout` | `int` | Specify value for sqlite3_busy_timeout. For more information see [PRAGMA busy_timeout](https://www.sqlite.org/pragma.html#pragma_busy_timeout) | | Case Sensitive LIKE | `_case_sensitive_like` \| `_cslike` | `boolean` | For more information see [PRAGMA case_sensitive_like](https://www.sqlite.org/pragma.html#pragma_case_sensitive_like) | | Defer Foreign Keys | `_defer_foreign_keys` \| `_defer_fk` | `boolean` | For more information see [PRAGMA defer_foreign_keys](https://www.sqlite.org/pragma.html#pragma_defer_foreign_keys) | | Foreign Keys | `_foreign_keys` \| `_fk` | `boolean` | For more information see [PRAGMA foreign_keys](https://www.sqlite.org/pragma.html#pragma_foreign_keys) | | Ignore CHECK Constraints | `_ignore_check_constraints` | `boolean` | For more information see [PRAGMA ignore_check_constraints](https://www.sqlite.org/pragma.html#pragma_ignore_check_constraints) | | Immutable | `immutable` | `boolean` | For more information see [Immutable](https://www.sqlite.org/c3ref/open.html) | | Journal Mode | `_journal_mode` \| `_journal` |
  • DELETE
  • TRUNCATE
  • PERSIST
  • MEMORY
  • WAL
  • OFF
| For more information see [PRAGMA journal_mode](https://www.sqlite.org/pragma.html#pragma_journal_mode) | | Locking Mode | `_locking_mode` \| `_locking` |
  • NORMAL
  • EXCLUSIVE
| For more information see [PRAGMA locking_mode](https://www.sqlite.org/pragma.html#pragma_locking_mode) | | Mode | `mode` |
  • ro
  • rw
  • rwc
  • memory
| Access Mode of the database. For more information see [SQLite Open](https://www.sqlite.org/c3ref/open.html) | | Mutex Locking | `_mutex` |
  • no
  • full
| Specify mutex mode. | | Query Only | `_query_only` | `boolean` | For more information see [PRAGMA query_only](https://www.sqlite.org/pragma.html#pragma_query_only) | | Recursive Triggers | `_recursive_triggers` \| `_rt` | `boolean` | For more information see [PRAGMA recursive_triggers](https://www.sqlite.org/pragma.html#pragma_recursive_triggers) | | Secure Delete | `_secure_delete` | `boolean` \| `FAST` | For more information see [PRAGMA secure_delete](https://www.sqlite.org/pragma.html#pragma_secure_delete) | | Shared-Cache Mode | `cache` |
  • shared
  • private
| Set cache mode for more information see [sqlite.org](https://www.sqlite.org/sharedcache.html) | | Synchronous | `_synchronous` \| `_sync` |
  • 0 \| OFF
  • 1 \| NORMAL
  • 2 \| FULL
  • 3 \| EXTRA
| For more information see [PRAGMA synchronous](https://www.sqlite.org/pragma.html#pragma_synchronous) | | Time Zone Location | `_loc` | auto | Specify location of time format. | | Transaction Lock | `_txlock` |
  • immediate
  • deferred
  • exclusive
| Specify locking behavior for transactions. | | Writable Schema | `_writable_schema` | `Boolean` | When this pragma is on, the SQLITE_MASTER tables in which database can be changed using ordinary UPDATE, INSERT, and DELETE statements. Warning: misuse of this pragma can easily result in a corrupt database file. | | Cache Size | `_cache_size` | `int` | Maximum cache size; default is 2000K (2M). See [PRAGMA cache_size](https://sqlite.org/pragma.html#pragma_cache_size) | ## DSN Examples ``` file:test.db?cache=shared&mode=memory ``` # Features This package allows additional configuration of features available within SQLite3 to be enabled or disabled by golang build constraints also known as build `tags`. Click [here](https://golang.org/pkg/go/build/#hdr-Build_Constraints) for more information about build tags / constraints. ### Usage If you wish to build this library with additional extensions / features, use the following command: ```bash go build -tags "" ``` For available features, see the extension list. When using multiple build tags, all the different tags should be space delimited. Example: ```bash go build -tags "icu json1 fts5 secure_delete" ``` ### Feature / Extension List | Extension | Build Tag | Description | |-----------|-----------|-------------| | Additional Statistics | sqlite_stat4 | This option adds additional logic to the ANALYZE command and to the query planner that can help SQLite to chose a better query plan under certain situations. The ANALYZE command is enhanced to collect histogram data from all columns of every index and store that data in the sqlite_stat4 table.

The query planner will then use the histogram data to help it make better index choices. The downside of this compile-time option is that it violates the query planner stability guarantee making it more difficult to ensure consistent performance in mass-produced applications.

SQLITE_ENABLE_STAT4 is an enhancement of SQLITE_ENABLE_STAT3. STAT3 only recorded histogram data for the left-most column of each index whereas the STAT4 enhancement records histogram data from all columns of each index.

The SQLITE_ENABLE_STAT3 compile-time option is a no-op and is ignored if the SQLITE_ENABLE_STAT4 compile-time option is used | | Allow URI Authority | sqlite_allow_uri_authority | URI filenames normally throws an error if the authority section is not either empty or "localhost".

However, if SQLite is compiled with the SQLITE_ALLOW_URI_AUTHORITY compile-time option, then the URI is converted into a Uniform Naming Convention (UNC) filename and passed down to the underlying operating system that way | | App Armor | sqlite_app_armor | When defined, this C-preprocessor macro activates extra code that attempts to detect misuse of the SQLite API, such as passing in NULL pointers to required parameters or using objects after they have been destroyed.

App Armor is not available under `Windows`. | | Disable Load Extensions | sqlite_omit_load_extension | Loading of external extensions is enabled by default.

To disable extension loading add the build tag `sqlite_omit_load_extension`. | | Enable Serialization with `libsqlite3` | sqlite_serialize | Serialization and deserialization of a SQLite database is available by default, unless the build tag `libsqlite3` is set.

To enable this functionality even if `libsqlite3` is set, add the build tag `sqlite_serialize`. | | Foreign Keys | sqlite_foreign_keys | This macro determines whether enforcement of foreign key constraints is enabled or disabled by default for new database connections.

Each database connection can always turn enforcement of foreign key constraints on and off and run-time using the foreign_keys pragma.

Enforcement of foreign key constraints is normally off by default, but if this compile-time parameter is set to 1, enforcement of foreign key constraints will be on by default | | Full Auto Vacuum | sqlite_vacuum_full | Set the default auto vacuum to full | | Incremental Auto Vacuum | sqlite_vacuum_incr | Set the default auto vacuum to incremental | | Full Text Search Engine | sqlite_fts5 | When this option is defined in the amalgamation, versions 5 of the full-text search engine (fts5) is added to the build automatically | | International Components for Unicode | sqlite_icu | This option causes the International Components for Unicode or "ICU" extension to SQLite to be added to the build | | Introspect PRAGMAS | sqlite_introspect | This option adds some extra PRAGMA statements.
  • PRAGMA function_list
  • PRAGMA module_list
  • PRAGMA pragma_list
| | JSON SQL Functions | sqlite_json | When this option is defined in the amalgamation, the JSON SQL functions are added to the build automatically | | Math Functions | sqlite_math_functions | This compile-time option enables built-in scalar math functions. For more information see [Built-In Mathematical SQL Functions](https://www.sqlite.org/lang_mathfunc.html) | | OS Trace | sqlite_os_trace | This option enables OSTRACE() debug logging. This can be verbose and should not be used in production. | | Pre Update Hook | sqlite_preupdate_hook | Registers a callback function that is invoked prior to each INSERT, UPDATE, and DELETE operation on a database table. | | Secure Delete | sqlite_secure_delete | This compile-time option changes the default setting of the secure_delete pragma.

When this option is not used, secure_delete defaults to off. When this option is present, secure_delete defaults to on.

The secure_delete setting causes deleted content to be overwritten with zeros. There is a small performance penalty since additional I/O must occur.

On the other hand, secure_delete can prevent fragments of sensitive information from lingering in unused parts of the database file after it has been deleted. See the documentation on the secure_delete pragma for additional information | | Secure Delete (FAST) | sqlite_secure_delete_fast | For more information see [PRAGMA secure_delete](https://www.sqlite.org/pragma.html#pragma_secure_delete) | | Tracing / Debug | sqlite_trace | Activate trace functions | | User Authentication | sqlite_userauth | SQLite User Authentication see [User Authentication](#user-authentication) for more information. | | Virtual Tables | sqlite_vtable | SQLite Virtual Tables see [SQLite Official VTABLE Documentation](https://www.sqlite.org/vtab.html) for more information, and a [full example here](https://github.com/mattn/go-sqlite3/tree/master/_example/vtable) | # Compilation This package requires the `CGO_ENABLED=1` environment variable if not set by default, and the presence of the `gcc` compiler. If you need to add additional CFLAGS or LDFLAGS to the build command, and do not want to modify this package, then this can be achieved by using the `CGO_CFLAGS` and `CGO_LDFLAGS` environment variables. ## Android This package can be compiled for android. Compile with: ```bash go build -tags "android" ``` For more information see [#201](https://github.com/mattn/go-sqlite3/issues/201) # ARM To compile for `ARM` use the following environment: ```bash env CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ \ CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 \ go build -v ``` Additional information: - [#242](https://github.com/mattn/go-sqlite3/issues/242) - [#504](https://github.com/mattn/go-sqlite3/issues/504) # Cross Compile This library can be cross-compiled. In some cases you are required to the `CC` environment variable with the cross compiler. ## Cross Compiling from macOS The simplest way to cross compile from macOS is to use [xgo](https://github.com/karalabe/xgo). Steps: - Install [musl-cross](https://github.com/FiloSottile/homebrew-musl-cross) (`brew install FiloSottile/musl-cross/musl-cross`). - Run `CC=x86_64-linux-musl-gcc CXX=x86_64-linux-musl-g++ GOARCH=amd64 GOOS=linux CGO_ENABLED=1 go build -ldflags "-linkmode external -extldflags -static"`. Please refer to the project's [README](https://github.com/FiloSottile/homebrew-musl-cross#readme) for further information. # Google Cloud Platform Building on GCP is not possible because Google Cloud Platform does not allow `gcc` to be executed. Please work only with compiled final binaries. ## Linux To compile this package on Linux, you must install the development tools for your linux distribution. To compile under linux use the build tag `linux`. ```bash go build -tags "linux" ``` If you wish to link directly to libsqlite3 then you can use the `libsqlite3` build tag. ``` go build -tags "libsqlite3 linux" ``` ### Alpine When building in an `alpine` container run the following command before building: ``` apk add --update gcc musl-dev ``` ### Fedora ```bash sudo yum groupinstall "Development Tools" "Development Libraries" ``` ### Ubuntu ```bash sudo apt-get install build-essential ``` ## macOS macOS should have all the tools present to compile this package. If not, install XCode to add all the developers tools. Required dependency: ```bash brew install sqlite3 ``` For macOS, there is an additional package to install which is required if you wish to build the `icu` extension. This additional package can be installed with `homebrew`: ```bash brew upgrade icu4c ``` To compile for macOS on x86: ```bash go build -tags "darwin amd64" ``` To compile for macOS on ARM chips: ```bash go build -tags "darwin arm64" ``` If you wish to link directly to libsqlite3, use the `libsqlite3` build tag: ``` # x86 go build -tags "libsqlite3 darwin amd64" # ARM go build -tags "libsqlite3 darwin arm64" ``` Additional information: - [#206](https://github.com/mattn/go-sqlite3/issues/206) - [#404](https://github.com/mattn/go-sqlite3/issues/404) ## Windows To compile this package on Windows, you must have the `gcc` compiler installed. 1) Install a Windows `gcc` toolchain. 2) Add the `bin` folder to the Windows path, if the installer did not do this by default. 3) Open a terminal for the TDM-GCC toolchain, which can be found in the Windows Start menu. 4) Navigate to your project folder and run the `go build ...` command for this package. For example the TDM-GCC Toolchain can be found [here](https://jmeubank.github.io/tdm-gcc/). ## Errors - Compile error: `can not be used when making a shared object; recompile with -fPIC` When receiving a compile time error referencing recompile with `-FPIC` then you are probably using a hardend system. You can compile the library on a hardend system with the following command. ```bash go build -ldflags '-extldflags=-fno-PIC' ``` More details see [#120](https://github.com/mattn/go-sqlite3/issues/120) - Can't build go-sqlite3 on windows 64bit. > Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit. > See: [#27](https://github.com/mattn/go-sqlite3/issues/27) - `go get github.com/mattn/go-sqlite3` throws compilation error. `gcc` throws: `internal compiler error` Remove the download repository from your disk and try re-install with: ```bash go install github.com/mattn/go-sqlite3 ``` # User Authentication This package supports the SQLite User Authentication module. ## Compile To use the User authentication module, the package has to be compiled with the tag `sqlite_userauth`. See [Features](#features). ## Usage ### Create protected database To create a database protected by user authentication, provide the following argument to the connection string `_auth`. This will enable user authentication within the database. This option however requires two additional arguments: - `_auth_user` - `_auth_pass` When `_auth` is present in the connection string user authentication will be enabled and the provided user will be created as an `admin` user. After initial creation, the parameter `_auth` has no effect anymore and can be omitted from the connection string. Example connection strings: Create an user authentication database with user `admin` and password `admin`: `file:test.s3db?_auth&_auth_user=admin&_auth_pass=admin` Create an user authentication database with user `admin` and password `admin` and use `SHA1` for the password encoding: `file:test.s3db?_auth&_auth_user=admin&_auth_pass=admin&_auth_crypt=sha1` ### Password Encoding The passwords within the user authentication module of SQLite are encoded with the SQLite function `sqlite_cryp`. This function uses a ceasar-cypher which is quite insecure. This library provides several additional password encoders which can be configured through the connection string. The password cypher can be configured with the key `_auth_crypt`. And if the configured password encoder also requires an salt this can be configured with `_auth_salt`. #### Available Encoders - SHA1 - SSHA1 (Salted SHA1) - SHA256 - SSHA256 (salted SHA256) - SHA384 - SSHA384 (salted SHA384) - SHA512 - SSHA512 (salted SHA512) ### Restrictions Operations on the database regarding user management can only be preformed by an administrator user. ### Support The user authentication supports two kinds of users: - administrators - regular users ### User Management User management can be done by directly using the `*SQLiteConn` or by SQL. #### SQL The following sql functions are available for user management: | Function | Arguments | Description | |----------|-----------|-------------| | `authenticate` | username `string`, password `string` | Will authenticate an user, this is done by the connection; and should not be used manually. | | `auth_user_add` | username `string`, password `string`, admin `int` | This function will add an user to the database.
if the database is not protected by user authentication it will enable it. Argument `admin` is an integer identifying if the added user should be an administrator. Only Administrators can add administrators. | | `auth_user_change` | username `string`, password `string`, admin `int` | Function to modify an user. Users can change their own password, but only an administrator can change the administrator flag. | | `authUserDelete` | username `string` | Delete an user from the database. Can only be used by an administrator. The current logged in administrator cannot be deleted. This is to make sure their is always an administrator remaining. | These functions will return an integer: - 0 (SQLITE_OK) - 23 (SQLITE_AUTH) Failed to perform due to authentication or insufficient privileges ##### Examples ```sql // Autheticate user // Create Admin User SELECT auth_user_add('admin2', 'admin2', 1); // Change password for user SELECT auth_user_change('user', 'userpassword', 0); // Delete user SELECT user_delete('user'); ``` #### *SQLiteConn The following functions are available for User authentication from the `*SQLiteConn`: | Function | Description | |----------|-------------| | `Authenticate(username, password string) error` | Authenticate user | | `AuthUserAdd(username, password string, admin bool) error` | Add user | | `AuthUserChange(username, password string, admin bool) error` | Modify user | | `AuthUserDelete(username string) error` | Delete user | ### Attached database When using attached databases, SQLite will use the authentication from the `main` database for the attached database(s). # Extensions If you want your own extension to be listed here, or you want to add a reference to an extension; please submit an Issue for this. ## Spatialite Spatialite is available as an extension to SQLite, and can be used in combination with this repository. For an example, see [shaxbee/go-spatialite](https://github.com/shaxbee/go-spatialite). ## extension-functions.c from SQLite3 Contrib extension-functions.c is available as an extension to SQLite, and provides the following functions: - Math: acos, asin, atan, atn2, atan2, acosh, asinh, atanh, difference, degrees, radians, cos, sin, tan, cot, cosh, sinh, tanh, coth, exp, log, log10, power, sign, sqrt, square, ceil, floor, pi. - String: replicate, charindex, leftstr, rightstr, ltrim, rtrim, trim, replace, reverse, proper, padl, padr, padc, strfilter. - Aggregate: stdev, variance, mode, median, lower_quartile, upper_quartile For an example, see [dinedal/go-sqlite3-extension-functions](https://github.com/dinedal/go-sqlite3-extension-functions). # FAQ - Getting insert error while query is opened. > You can pass some arguments into the connection string, for example, a URI. > See: [#39](https://github.com/mattn/go-sqlite3/issues/39) - Do you want to cross compile? mingw on Linux or Mac? > See: [#106](https://github.com/mattn/go-sqlite3/issues/106) > See also: http://www.limitlessfx.com/cross-compile-golang-app-for-windows-from-linux.html - Want to get time.Time with current locale Use `_loc=auto` in SQLite3 filename schema like `file:foo.db?_loc=auto`. - Can I use this in multiple routines concurrently? Yes for readonly. But not for writable. See [#50](https://github.com/mattn/go-sqlite3/issues/50), [#51](https://github.com/mattn/go-sqlite3/issues/51), [#209](https://github.com/mattn/go-sqlite3/issues/209), [#274](https://github.com/mattn/go-sqlite3/issues/274). - Why I'm getting `no such table` error? Why is it racy if I use a `sql.Open("sqlite3", ":memory:")` database? Each connection to `":memory:"` opens a brand new in-memory sql database, so if the stdlib's sql engine happens to open another connection and you've only specified `":memory:"`, that connection will see a brand new database. A workaround is to use `"file::memory:?cache=shared"` (or `"file:foobar?mode=memory&cache=shared"`). Every connection to this string will point to the same in-memory database. Note that if the last database connection in the pool closes, the in-memory database is deleted. Make sure the [max idle connection limit](https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns) is > 0, and the [connection lifetime](https://golang.org/pkg/database/sql/#DB.SetConnMaxLifetime) is infinite. For more information see: * [#204](https://github.com/mattn/go-sqlite3/issues/204) * [#511](https://github.com/mattn/go-sqlite3/issues/511) * https://www.sqlite.org/sharedcache.html#shared_cache_and_in_memory_databases * https://www.sqlite.org/inmemorydb.html#sharedmemdb - Reading from database with large amount of goroutines fails on OSX. OS X limits OS-wide to not have more than 1000 files open simultaneously by default. For more information, see [#289](https://github.com/mattn/go-sqlite3/issues/289) - Trying to execute a `.` (dot) command throws an error. Error: `Error: near ".": syntax error` Dot command are part of SQLite3 CLI, not of this library. You need to implement the feature or call the sqlite3 cli. More information see [#305](https://github.com/mattn/go-sqlite3/issues/305). - Error: `database is locked` When you get a database is locked, please use the following options. Add to DSN: `cache=shared` Example: ```go db, err := sql.Open("sqlite3", "file:locked.sqlite?cache=shared") ``` Next, please set the database connections of the SQL package to 1: ```go db.SetMaxOpenConns(1) ``` For more information, see [#209](https://github.com/mattn/go-sqlite3/issues/209). ## Contributors ### Code Contributors This project exists thanks to all the people who [[contribute](CONTRIBUTING.md)]. ### Financial Contributors Become a financial contributor and help us sustain our community. [[Contribute here](https://opencollective.com/mattn-go-sqlite3/contribute)]. #### Individuals #### Organizations Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/mattn-go-sqlite3/contribute)] # License MIT: http://mattn.mit-license.org/2018 sqlite3-binding.c, sqlite3-binding.h, sqlite3ext.h The -binding suffix was added to avoid build failures under gccgo. In this repository, those files are an amalgamation of code that was copied from SQLite3. The license of that code is the same as the license of SQLite3. # Author Yasuhiro Matsumoto (a.k.a mattn) G.J.R. Timmer ================================================ FILE: vendor/github.com/mattn/go-sqlite3/backup.go ================================================ // Copyright (C) 2019 Yasuhiro Matsumoto . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. package sqlite3 /* #ifndef USE_LIBSQLITE3 #include "sqlite3-binding.h" #else #include #endif #include */ import "C" import ( "runtime" "unsafe" ) // SQLiteBackup implement interface of Backup. type SQLiteBackup struct { b *C.sqlite3_backup } // Backup make backup from src to dest. func (destConn *SQLiteConn) Backup(dest string, srcConn *SQLiteConn, src string) (*SQLiteBackup, error) { destptr := C.CString(dest) defer C.free(unsafe.Pointer(destptr)) srcptr := C.CString(src) defer C.free(unsafe.Pointer(srcptr)) if b := C.sqlite3_backup_init(destConn.db, destptr, srcConn.db, srcptr); b != nil { bb := &SQLiteBackup{b: b} runtime.SetFinalizer(bb, (*SQLiteBackup).Finish) return bb, nil } return nil, destConn.lastError() } // Step to backs up for one step. Calls the underlying `sqlite3_backup_step` // function. This function returns a boolean indicating if the backup is done // and an error signalling any other error. Done is returned if the underlying // C function returns SQLITE_DONE (Code 101) func (b *SQLiteBackup) Step(p int) (bool, error) { ret := C.sqlite3_backup_step(b.b, C.int(p)) if ret == C.SQLITE_DONE { return true, nil } else if ret != 0 && ret != C.SQLITE_LOCKED && ret != C.SQLITE_BUSY { return false, Error{Code: ErrNo(ret)} } return false, nil } // Remaining return whether have the rest for backup. func (b *SQLiteBackup) Remaining() int { return int(C.sqlite3_backup_remaining(b.b)) } // PageCount return count of pages. func (b *SQLiteBackup) PageCount() int { return int(C.sqlite3_backup_pagecount(b.b)) } // Finish close backup. func (b *SQLiteBackup) Finish() error { return b.Close() } // Close close backup. func (b *SQLiteBackup) Close() error { ret := C.sqlite3_backup_finish(b.b) // sqlite3_backup_finish() never fails, it just returns the // error code from previous operations, so clean up before // checking and returning an error b.b = nil runtime.SetFinalizer(b, nil) if ret != 0 { return Error{Code: ErrNo(ret)} } return nil } ================================================ FILE: vendor/github.com/mattn/go-sqlite3/callback.go ================================================ // Copyright (C) 2019 Yasuhiro Matsumoto . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. package sqlite3 // You can't export a Go function to C and have definitions in the C // preamble in the same file, so we have to have callbackTrampoline in // its own file. Because we need a separate file anyway, the support // code for SQLite custom functions is in here. /* #ifndef USE_LIBSQLITE3 #include "sqlite3-binding.h" #else #include #endif #include void _sqlite3_result_text(sqlite3_context* ctx, const char* s); void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l); */ import "C" import ( "errors" "fmt" "math" "reflect" "sync" "unsafe" ) //export callbackTrampoline func callbackTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value) { args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc] fi := lookupHandle(C.sqlite3_user_data(ctx)).(*functionInfo) fi.Call(ctx, args) } //export stepTrampoline func stepTrampoline(ctx *C.sqlite3_context, argc C.int, argv **C.sqlite3_value) { args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:int(argc):int(argc)] ai := lookupHandle(C.sqlite3_user_data(ctx)).(*aggInfo) ai.Step(ctx, args) } //export doneTrampoline func doneTrampoline(ctx *C.sqlite3_context) { ai := lookupHandle(C.sqlite3_user_data(ctx)).(*aggInfo) ai.Done(ctx) } //export compareTrampoline func compareTrampoline(handlePtr unsafe.Pointer, la C.int, a *C.char, lb C.int, b *C.char) C.int { cmp := lookupHandle(handlePtr).(func(string, string) int) return C.int(cmp(C.GoStringN(a, la), C.GoStringN(b, lb))) } //export commitHookTrampoline func commitHookTrampoline(handle unsafe.Pointer) int { callback := lookupHandle(handle).(func() int) return callback() } //export rollbackHookTrampoline func rollbackHookTrampoline(handle unsafe.Pointer) { callback := lookupHandle(handle).(func()) callback() } //export updateHookTrampoline func updateHookTrampoline(handle unsafe.Pointer, op int, db *C.char, table *C.char, rowid int64) { callback := lookupHandle(handle).(func(int, string, string, int64)) callback(op, C.GoString(db), C.GoString(table), rowid) } //export authorizerTrampoline func authorizerTrampoline(handle unsafe.Pointer, op int, arg1 *C.char, arg2 *C.char, arg3 *C.char) int { callback := lookupHandle(handle).(func(int, string, string, string) int) return callback(op, C.GoString(arg1), C.GoString(arg2), C.GoString(arg3)) } //export preUpdateHookTrampoline func preUpdateHookTrampoline(handle unsafe.Pointer, dbHandle uintptr, op int, db *C.char, table *C.char, oldrowid int64, newrowid int64) { hval := lookupHandleVal(handle) data := SQLitePreUpdateData{ Conn: hval.db, Op: op, DatabaseName: C.GoString(db), TableName: C.GoString(table), OldRowID: oldrowid, NewRowID: newrowid, } callback := hval.val.(func(SQLitePreUpdateData)) callback(data) } // Use handles to avoid passing Go pointers to C. type handleVal struct { db *SQLiteConn val any } var handleLock sync.Mutex var handleVals = make(map[unsafe.Pointer]handleVal) func newHandle(db *SQLiteConn, v any) unsafe.Pointer { handleLock.Lock() defer handleLock.Unlock() val := handleVal{db: db, val: v} var p unsafe.Pointer = C.malloc(C.size_t(1)) if p == nil { panic("can't allocate 'cgo-pointer hack index pointer': ptr == nil") } handleVals[p] = val return p } func lookupHandleVal(handle unsafe.Pointer) handleVal { handleLock.Lock() defer handleLock.Unlock() return handleVals[handle] } func lookupHandle(handle unsafe.Pointer) any { return lookupHandleVal(handle).val } func deleteHandles(db *SQLiteConn) { handleLock.Lock() defer handleLock.Unlock() for handle, val := range handleVals { if val.db == db { delete(handleVals, handle) C.free(handle) } } } // This is only here so that tests can refer to it. type callbackArgRaw C.sqlite3_value type callbackArgConverter func(*C.sqlite3_value) (reflect.Value, error) type callbackArgCast struct { f callbackArgConverter typ reflect.Type } func (c callbackArgCast) Run(v *C.sqlite3_value) (reflect.Value, error) { val, err := c.f(v) if err != nil { return reflect.Value{}, err } if !val.Type().ConvertibleTo(c.typ) { return reflect.Value{}, fmt.Errorf("cannot convert %s to %s", val.Type(), c.typ) } return val.Convert(c.typ), nil } func callbackArgInt64(v *C.sqlite3_value) (reflect.Value, error) { if C.sqlite3_value_type(v) != C.SQLITE_INTEGER { return reflect.Value{}, fmt.Errorf("argument must be an INTEGER") } return reflect.ValueOf(int64(C.sqlite3_value_int64(v))), nil } func callbackArgBool(v *C.sqlite3_value) (reflect.Value, error) { if C.sqlite3_value_type(v) != C.SQLITE_INTEGER { return reflect.Value{}, fmt.Errorf("argument must be an INTEGER") } i := int64(C.sqlite3_value_int64(v)) val := false if i != 0 { val = true } return reflect.ValueOf(val), nil } func callbackArgFloat64(v *C.sqlite3_value) (reflect.Value, error) { if C.sqlite3_value_type(v) != C.SQLITE_FLOAT { return reflect.Value{}, fmt.Errorf("argument must be a FLOAT") } return reflect.ValueOf(float64(C.sqlite3_value_double(v))), nil } func callbackArgBytes(v *C.sqlite3_value) (reflect.Value, error) { switch C.sqlite3_value_type(v) { case C.SQLITE_BLOB: l := C.sqlite3_value_bytes(v) p := C.sqlite3_value_blob(v) return reflect.ValueOf(C.GoBytes(p, l)), nil case C.SQLITE_TEXT: l := C.sqlite3_value_bytes(v) c := unsafe.Pointer(C.sqlite3_value_text(v)) return reflect.ValueOf(C.GoBytes(c, l)), nil default: return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT") } } func callbackArgString(v *C.sqlite3_value) (reflect.Value, error) { switch C.sqlite3_value_type(v) { case C.SQLITE_BLOB: l := C.sqlite3_value_bytes(v) p := (*C.char)(C.sqlite3_value_blob(v)) return reflect.ValueOf(C.GoStringN(p, l)), nil case C.SQLITE_TEXT: c := (*C.char)(unsafe.Pointer(C.sqlite3_value_text(v))) return reflect.ValueOf(C.GoString(c)), nil default: return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT") } } func callbackArgGeneric(v *C.sqlite3_value) (reflect.Value, error) { switch C.sqlite3_value_type(v) { case C.SQLITE_INTEGER: return callbackArgInt64(v) case C.SQLITE_FLOAT: return callbackArgFloat64(v) case C.SQLITE_TEXT: return callbackArgString(v) case C.SQLITE_BLOB: return callbackArgBytes(v) case C.SQLITE_NULL: // Interpret NULL as a nil byte slice. var ret []byte return reflect.ValueOf(ret), nil default: panic("unreachable") } } func callbackArg(typ reflect.Type) (callbackArgConverter, error) { switch typ.Kind() { case reflect.Interface: if typ.NumMethod() != 0 { return nil, errors.New("the only supported interface type is any") } return callbackArgGeneric, nil case reflect.Slice: if typ.Elem().Kind() != reflect.Uint8 { return nil, errors.New("the only supported slice type is []byte") } return callbackArgBytes, nil case reflect.String: return callbackArgString, nil case reflect.Bool: return callbackArgBool, nil case reflect.Int64: return callbackArgInt64, nil case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint: c := callbackArgCast{callbackArgInt64, typ} return c.Run, nil case reflect.Float64: return callbackArgFloat64, nil case reflect.Float32: c := callbackArgCast{callbackArgFloat64, typ} return c.Run, nil default: return nil, fmt.Errorf("don't know how to convert to %s", typ) } } func callbackConvertArgs(argv []*C.sqlite3_value, converters []callbackArgConverter, variadic callbackArgConverter) ([]reflect.Value, error) { var args []reflect.Value if len(argv) < len(converters) { return nil, fmt.Errorf("function requires at least %d arguments", len(converters)) } for i, arg := range argv[:len(converters)] { v, err := converters[i](arg) if err != nil { return nil, err } args = append(args, v) } if variadic != nil { for _, arg := range argv[len(converters):] { v, err := variadic(arg) if err != nil { return nil, err } args = append(args, v) } } return args, nil } type callbackRetConverter func(*C.sqlite3_context, reflect.Value) error func callbackRetInteger(ctx *C.sqlite3_context, v reflect.Value) error { switch v.Type().Kind() { case reflect.Int64: case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint: v = v.Convert(reflect.TypeOf(int64(0))) case reflect.Bool: b := v.Interface().(bool) if b { v = reflect.ValueOf(int64(1)) } else { v = reflect.ValueOf(int64(0)) } default: return fmt.Errorf("cannot convert %s to INTEGER", v.Type()) } C.sqlite3_result_int64(ctx, C.sqlite3_int64(v.Interface().(int64))) return nil } func callbackRetFloat(ctx *C.sqlite3_context, v reflect.Value) error { switch v.Type().Kind() { case reflect.Float64: case reflect.Float32: v = v.Convert(reflect.TypeOf(float64(0))) default: return fmt.Errorf("cannot convert %s to FLOAT", v.Type()) } C.sqlite3_result_double(ctx, C.double(v.Interface().(float64))) return nil } func callbackRetBlob(ctx *C.sqlite3_context, v reflect.Value) error { if v.Type().Kind() != reflect.Slice || v.Type().Elem().Kind() != reflect.Uint8 { return fmt.Errorf("cannot convert %s to BLOB", v.Type()) } i := v.Interface() if i == nil || len(i.([]byte)) == 0 { C.sqlite3_result_null(ctx) } else { bs := i.([]byte) C._sqlite3_result_blob(ctx, unsafe.Pointer(&bs[0]), C.int(len(bs))) } return nil } func callbackRetText(ctx *C.sqlite3_context, v reflect.Value) error { if v.Type().Kind() != reflect.String { return fmt.Errorf("cannot convert %s to TEXT", v.Type()) } C._sqlite3_result_text(ctx, C.CString(v.Interface().(string))) return nil } func callbackRetNil(ctx *C.sqlite3_context, v reflect.Value) error { return nil } func callbackRetGeneric(ctx *C.sqlite3_context, v reflect.Value) error { if v.IsNil() { C.sqlite3_result_null(ctx) return nil } cb, err := callbackRet(v.Elem().Type()) if err != nil { return err } return cb(ctx, v.Elem()) } func callbackRet(typ reflect.Type) (callbackRetConverter, error) { switch typ.Kind() { case reflect.Interface: errorInterface := reflect.TypeOf((*error)(nil)).Elem() if typ.Implements(errorInterface) { return callbackRetNil, nil } if typ.NumMethod() == 0 { return callbackRetGeneric, nil } fallthrough case reflect.Slice: if typ.Elem().Kind() != reflect.Uint8 { return nil, errors.New("the only supported slice type is []byte") } return callbackRetBlob, nil case reflect.String: return callbackRetText, nil case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint: return callbackRetInteger, nil case reflect.Float32, reflect.Float64: return callbackRetFloat, nil default: return nil, fmt.Errorf("don't know how to convert to %s", typ) } } func callbackError(ctx *C.sqlite3_context, err error) { cstr := C.CString(err.Error()) defer C.free(unsafe.Pointer(cstr)) C.sqlite3_result_error(ctx, cstr, C.int(-1)) } // Test support code. Tests are not allowed to import "C", so we can't // declare any functions that use C.sqlite3_value. func callbackSyntheticForTests(v reflect.Value, err error) callbackArgConverter { return func(*C.sqlite3_value) (reflect.Value, error) { return v, err } } ================================================ FILE: vendor/github.com/mattn/go-sqlite3/convert.go ================================================ // Extracted from Go database/sql source code // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Type conversions for Scan. package sqlite3 import ( "database/sql" "database/sql/driver" "errors" "fmt" "reflect" "strconv" "time" ) var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error // convertAssign copies to dest the value in src, converting it if possible. // An error is returned if the copy would result in loss of information. // dest should be a pointer type. func convertAssign(dest, src any) error { // Common cases, without reflect. switch s := src.(type) { case string: switch d := dest.(type) { case *string: if d == nil { return errNilPtr } *d = s return nil case *[]byte: if d == nil { return errNilPtr } *d = []byte(s) return nil case *sql.RawBytes: if d == nil { return errNilPtr } *d = append((*d)[:0], s...) return nil } case []byte: switch d := dest.(type) { case *string: if d == nil { return errNilPtr } *d = string(s) return nil case *any: if d == nil { return errNilPtr } *d = cloneBytes(s) return nil case *[]byte: if d == nil { return errNilPtr } *d = cloneBytes(s) return nil case *sql.RawBytes: if d == nil { return errNilPtr } *d = s return nil } case time.Time: switch d := dest.(type) { case *time.Time: *d = s return nil case *string: *d = s.Format(time.RFC3339Nano) return nil case *[]byte: if d == nil { return errNilPtr } *d = []byte(s.Format(time.RFC3339Nano)) return nil case *sql.RawBytes: if d == nil { return errNilPtr } *d = s.AppendFormat((*d)[:0], time.RFC3339Nano) return nil } case nil: switch d := dest.(type) { case *any: if d == nil { return errNilPtr } *d = nil return nil case *[]byte: if d == nil { return errNilPtr } *d = nil return nil case *sql.RawBytes: if d == nil { return errNilPtr } *d = nil return nil } } var sv reflect.Value switch d := dest.(type) { case *string: sv = reflect.ValueOf(src) switch sv.Kind() { case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64: *d = asString(src) return nil } case *[]byte: sv = reflect.ValueOf(src) if b, ok := asBytes(nil, sv); ok { *d = b return nil } case *sql.RawBytes: sv = reflect.ValueOf(src) if b, ok := asBytes([]byte(*d)[:0], sv); ok { *d = sql.RawBytes(b) return nil } case *bool: bv, err := driver.Bool.ConvertValue(src) if err == nil { *d = bv.(bool) } return err case *any: *d = src return nil } if scanner, ok := dest.(sql.Scanner); ok { return scanner.Scan(src) } dpv := reflect.ValueOf(dest) if dpv.Kind() != reflect.Ptr { return errors.New("destination not a pointer") } if dpv.IsNil() { return errNilPtr } if !sv.IsValid() { sv = reflect.ValueOf(src) } dv := reflect.Indirect(dpv) if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { switch b := src.(type) { case []byte: dv.Set(reflect.ValueOf(cloneBytes(b))) default: dv.Set(sv) } return nil } if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { dv.Set(sv.Convert(dv.Type())) return nil } // The following conversions use a string value as an intermediate representation // to convert between various numeric types. // // This also allows scanning into user defined types such as "type Int int64". // For symmetry, also check for string destination types. switch dv.Kind() { case reflect.Ptr: if src == nil { dv.Set(reflect.Zero(dv.Type())) return nil } dv.Set(reflect.New(dv.Type().Elem())) return convertAssign(dv.Interface(), src) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: s := asString(src) i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) if err != nil { err = strconvErr(err) return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) } dv.SetInt(i64) return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: s := asString(src) u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) if err != nil { err = strconvErr(err) return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) } dv.SetUint(u64) return nil case reflect.Float32, reflect.Float64: s := asString(src) f64, err := strconv.ParseFloat(s, dv.Type().Bits()) if err != nil { err = strconvErr(err) return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) } dv.SetFloat(f64) return nil case reflect.String: switch v := src.(type) { case string: dv.SetString(v) return nil case []byte: dv.SetString(string(v)) return nil } } return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) } func strconvErr(err error) error { if ne, ok := err.(*strconv.NumError); ok { return ne.Err } return err } func cloneBytes(b []byte) []byte { if b == nil { return nil } c := make([]byte, len(b)) copy(c, b) return c } func asString(src any) string { switch v := src.(type) { case string: return v case []byte: return string(v) } rv := reflect.ValueOf(src) switch rv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return strconv.FormatInt(rv.Int(), 10) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return strconv.FormatUint(rv.Uint(), 10) case reflect.Float64: return strconv.FormatFloat(rv.Float(), 'g', -1, 64) case reflect.Float32: return strconv.FormatFloat(rv.Float(), 'g', -1, 32) case reflect.Bool: return strconv.FormatBool(rv.Bool()) } return fmt.Sprintf("%v", src) } func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { switch rv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return strconv.AppendInt(buf, rv.Int(), 10), true case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return strconv.AppendUint(buf, rv.Uint(), 10), true case reflect.Float32: return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true case reflect.Float64: return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true case reflect.Bool: return strconv.AppendBool(buf, rv.Bool()), true case reflect.String: s := rv.String() return append(buf, s...), true } return } ================================================ FILE: vendor/github.com/mattn/go-sqlite3/doc.go ================================================ /* Package sqlite3 provides interface to SQLite3 databases. This works as a driver for database/sql. Installation go get github.com/mattn/go-sqlite3 # Supported Types Currently, go-sqlite3 supports the following data types. +------------------------------+ |go | sqlite3 | |----------|-------------------| |nil | null | |int | integer | |int64 | integer | |float64 | float | |bool | integer | |[]byte | blob | |string | text | |time.Time | timestamp/datetime| +------------------------------+ # SQLite3 Extension You can write your own extension module for sqlite3. For example, below is an extension for a Regexp matcher operation. #include #include #include #include SQLITE_EXTENSION_INIT1 static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) { if (argc >= 2) { const char *target = (const char *)sqlite3_value_text(argv[1]); const char *pattern = (const char *)sqlite3_value_text(argv[0]); const char* errstr = NULL; int erroff = 0; int vec[500]; int n, rc; pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL); rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500); if (rc <= 0) { sqlite3_result_error(context, errstr, 0); return; } sqlite3_result_int(context, 1); } } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) { SQLITE_EXTENSION_INIT2(api); return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, (void*)db, regexp_func, NULL, NULL); } It needs to be built as a so/dll shared library. And you need to register the extension module like below. sql.Register("sqlite3_with_extensions", &sqlite3.SQLiteDriver{ Extensions: []string{ "sqlite3_mod_regexp", }, }) Then, you can use this extension. rows, err := db.Query("select text from mytable where name regexp '^golang'") # Connection Hook You can hook and inject your code when the connection is established by setting ConnectHook to get the SQLiteConn. sql.Register("sqlite3_with_hook_example", &sqlite3.SQLiteDriver{ ConnectHook: func(conn *sqlite3.SQLiteConn) error { sqlite3conn = append(sqlite3conn, conn) return nil }, }) You can also use database/sql.Conn.Raw (Go >= 1.13): conn, err := db.Conn(context.Background()) // if err != nil { ... } defer conn.Close() err = conn.Raw(func (driverConn any) error { sqliteConn := driverConn.(*sqlite3.SQLiteConn) // ... use sqliteConn }) // if err != nil { ... } # Go SQlite3 Extensions If you want to register Go functions as SQLite extension functions you can make a custom driver by calling RegisterFunction from ConnectHook. regex = func(re, s string) (bool, error) { return regexp.MatchString(re, s) } sql.Register("sqlite3_extended", &sqlite3.SQLiteDriver{ ConnectHook: func(conn *sqlite3.SQLiteConn) error { return conn.RegisterFunc("regexp", regex, true) }, }) You can then use the custom driver by passing its name to sql.Open. var i int conn, err := sql.Open("sqlite3_extended", "./foo.db") if err != nil { panic(err) } err = db.QueryRow(`SELECT regexp("foo.*", "seafood")`).Scan(&i) if err != nil { panic(err) } See the documentation of RegisterFunc for more details. */ package sqlite3 ================================================ FILE: vendor/github.com/mattn/go-sqlite3/error.go ================================================ // Copyright (C) 2019 Yasuhiro Matsumoto . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. package sqlite3 /* #ifndef USE_LIBSQLITE3 #include "sqlite3-binding.h" #else #include #endif */ import "C" import "syscall" // ErrNo inherit errno. type ErrNo int // ErrNoMask is mask code. const ErrNoMask C.int = 0xff // ErrNoExtended is extended errno. type ErrNoExtended int // Error implement sqlite error code. type Error struct { Code ErrNo /* The error code returned by SQLite */ ExtendedCode ErrNoExtended /* The extended error code returned by SQLite */ SystemErrno syscall.Errno /* The system errno returned by the OS through SQLite, if applicable */ err string /* The error string returned by sqlite3_errmsg(), this usually contains more specific details. */ } // result codes from http://www.sqlite.org/c3ref/c_abort.html var ( ErrError = ErrNo(1) /* SQL error or missing database */ ErrInternal = ErrNo(2) /* Internal logic error in SQLite */ ErrPerm = ErrNo(3) /* Access permission denied */ ErrAbort = ErrNo(4) /* Callback routine requested an abort */ ErrBusy = ErrNo(5) /* The database file is locked */ ErrLocked = ErrNo(6) /* A table in the database is locked */ ErrNomem = ErrNo(7) /* A malloc() failed */ ErrReadonly = ErrNo(8) /* Attempt to write a readonly database */ ErrInterrupt = ErrNo(9) /* Operation terminated by sqlite3_interrupt() */ ErrIoErr = ErrNo(10) /* Some kind of disk I/O error occurred */ ErrCorrupt = ErrNo(11) /* The database disk image is malformed */ ErrNotFound = ErrNo(12) /* Unknown opcode in sqlite3_file_control() */ ErrFull = ErrNo(13) /* Insertion failed because database is full */ ErrCantOpen = ErrNo(14) /* Unable to open the database file */ ErrProtocol = ErrNo(15) /* Database lock protocol error */ ErrEmpty = ErrNo(16) /* Database is empty */ ErrSchema = ErrNo(17) /* The database schema changed */ ErrTooBig = ErrNo(18) /* String or BLOB exceeds size limit */ ErrConstraint = ErrNo(19) /* Abort due to constraint violation */ ErrMismatch = ErrNo(20) /* Data type mismatch */ ErrMisuse = ErrNo(21) /* Library used incorrectly */ ErrNoLFS = ErrNo(22) /* Uses OS features not supported on host */ ErrAuth = ErrNo(23) /* Authorization denied */ ErrFormat = ErrNo(24) /* Auxiliary database format error */ ErrRange = ErrNo(25) /* 2nd parameter to sqlite3_bind out of range */ ErrNotADB = ErrNo(26) /* File opened that is not a database file */ ErrNotice = ErrNo(27) /* Notifications from sqlite3_log() */ ErrWarning = ErrNo(28) /* Warnings from sqlite3_log() */ ) // Error return error message from errno. func (err ErrNo) Error() string { return Error{Code: err}.Error() } // Extend return extended errno. func (err ErrNo) Extend(by int) ErrNoExtended { return ErrNoExtended(int(err) | (by << 8)) } // Error return error message that is extended code. func (err ErrNoExtended) Error() string { return Error{Code: ErrNo(C.int(err) & ErrNoMask), ExtendedCode: err}.Error() } func (err Error) Error() string { var str string if err.err != "" { str = err.err } else { str = C.GoString(C.sqlite3_errstr(C.int(err.Code))) } if err.SystemErrno != 0 { str += ": " + err.SystemErrno.Error() } return str } // result codes from http://www.sqlite.org/c3ref/c_abort_rollback.html var ( ErrIoErrRead = ErrIoErr.Extend(1) ErrIoErrShortRead = ErrIoErr.Extend(2) ErrIoErrWrite = ErrIoErr.Extend(3) ErrIoErrFsync = ErrIoErr.Extend(4) ErrIoErrDirFsync = ErrIoErr.Extend(5) ErrIoErrTruncate = ErrIoErr.Extend(6) ErrIoErrFstat = ErrIoErr.Extend(7) ErrIoErrUnlock = ErrIoErr.Extend(8) ErrIoErrRDlock = ErrIoErr.Extend(9) ErrIoErrDelete = ErrIoErr.Extend(10) ErrIoErrBlocked = ErrIoErr.Extend(11) ErrIoErrNoMem = ErrIoErr.Extend(12) ErrIoErrAccess = ErrIoErr.Extend(13) ErrIoErrCheckReservedLock = ErrIoErr.Extend(14) ErrIoErrLock = ErrIoErr.Extend(15) ErrIoErrClose = ErrIoErr.Extend(16) ErrIoErrDirClose = ErrIoErr.Extend(17) ErrIoErrSHMOpen = ErrIoErr.Extend(18) ErrIoErrSHMSize = ErrIoErr.Extend(19) ErrIoErrSHMLock = ErrIoErr.Extend(20) ErrIoErrSHMMap = ErrIoErr.Extend(21) ErrIoErrSeek = ErrIoErr.Extend(22) ErrIoErrDeleteNoent = ErrIoErr.Extend(23) ErrIoErrMMap = ErrIoErr.Extend(24) ErrIoErrGetTempPath = ErrIoErr.Extend(25) ErrIoErrConvPath = ErrIoErr.Extend(26) ErrLockedSharedCache = ErrLocked.Extend(1) ErrBusyRecovery = ErrBusy.Extend(1) ErrBusySnapshot = ErrBusy.Extend(2) ErrCantOpenNoTempDir = ErrCantOpen.Extend(1) ErrCantOpenIsDir = ErrCantOpen.Extend(2) ErrCantOpenFullPath = ErrCantOpen.Extend(3) ErrCantOpenConvPath = ErrCantOpen.Extend(4) ErrCorruptVTab = ErrCorrupt.Extend(1) ErrReadonlyRecovery = ErrReadonly.Extend(1) ErrReadonlyCantLock = ErrReadonly.Extend(2) ErrReadonlyRollback = ErrReadonly.Extend(3) ErrReadonlyDbMoved = ErrReadonly.Extend(4) ErrAbortRollback = ErrAbort.Extend(2) ErrConstraintCheck = ErrConstraint.Extend(1) ErrConstraintCommitHook = ErrConstraint.Extend(2) ErrConstraintForeignKey = ErrConstraint.Extend(3) ErrConstraintFunction = ErrConstraint.Extend(4) ErrConstraintNotNull = ErrConstraint.Extend(5) ErrConstraintPrimaryKey = ErrConstraint.Extend(6) ErrConstraintTrigger = ErrConstraint.Extend(7) ErrConstraintUnique = ErrConstraint.Extend(8) ErrConstraintVTab = ErrConstraint.Extend(9) ErrConstraintRowID = ErrConstraint.Extend(10) ErrNoticeRecoverWAL = ErrNotice.Extend(1) ErrNoticeRecoverRollback = ErrNotice.Extend(2) ErrWarningAutoIndex = ErrWarning.Extend(1) ) ================================================ FILE: vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c ================================================ #ifndef USE_LIBSQLITE3 /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite ** version 3.45.1. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements ** of 5% or more are commonly seen when SQLite is compiled as a single ** translation unit. ** ** This file is all you need to compile SQLite. To use SQLite in other ** programs, you need this file and the "sqlite3.h" header file that defines ** the programming interface to the SQLite library. (If you do not have ** the "sqlite3.h" header file at hand, you will find a copy embedded within ** the text of this file. Search for "Begin file sqlite3.h" to find the start ** of the embedded sqlite3.h header file.) Additional code files may be needed ** if you want a wrapper to interface SQLite with your choice of programming ** language. The code for the "sqlite3" command-line shell is also in a ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in ** e876e51a0ed5c5b3126f52e532044363a014. */ #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 #ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static #endif /************** Begin file sqliteInt.h ***************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** */ #ifndef SQLITEINT_H #define SQLITEINT_H /* Special Comments: ** ** Some comments have special meaning to the tools that measure test ** coverage: ** ** NO_TEST - The branches on this line are not ** measured by branch coverage. This is ** used on lines of code that actually ** implement parts of coverage testing. ** ** OPTIMIZATION-IF-TRUE - This branch is allowed to always be false ** and the correct answer is still obtained, ** though perhaps more slowly. ** ** OPTIMIZATION-IF-FALSE - This branch is allowed to always be true ** and the correct answer is still obtained, ** though perhaps more slowly. ** ** PREVENTS-HARMLESS-OVERREAD - This branch prevents a buffer overread ** that would be harmless and undetectable ** if it did occur. ** ** In all cases, the special comment must be enclosed in the usual ** slash-asterisk...asterisk-slash comment marks, with no spaces between the ** asterisks and the comment text. */ /* ** Make sure the Tcl calling convention macro is defined. This macro is ** only used by test code and Tcl integration code. */ #ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI #endif /* ** Include the header file used to customize the compiler options for MSVC. ** This should be done first so that it can successfully prevent spurious ** compiler warnings due to subsequent content in this file and other files ** that are included by this file. */ /************** Include msvc.h in the middle of sqliteInt.h ******************/ /************** Begin file msvc.h ********************************************/ /* ** 2015 January 12 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to MSVC. */ #ifndef SQLITE_MSVC_H #define SQLITE_MSVC_H #if defined(_MSC_VER) #pragma warning(disable : 4054) #pragma warning(disable : 4055) #pragma warning(disable : 4100) #pragma warning(disable : 4127) #pragma warning(disable : 4130) #pragma warning(disable : 4152) #pragma warning(disable : 4189) #pragma warning(disable : 4206) #pragma warning(disable : 4210) #pragma warning(disable : 4232) #pragma warning(disable : 4244) #pragma warning(disable : 4305) #pragma warning(disable : 4306) #pragma warning(disable : 4702) #pragma warning(disable : 4706) #endif /* defined(_MSC_VER) */ #if defined(_MSC_VER) && !defined(_WIN64) #undef SQLITE_4_BYTE_ALIGNED_MALLOC #define SQLITE_4_BYTE_ALIGNED_MALLOC #endif /* defined(_MSC_VER) && !defined(_WIN64) */ #if !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800 #define HAVE_LOG2 0 #endif /* !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800 */ #endif /* SQLITE_MSVC_H */ /************** End of msvc.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /* ** Special setup for VxWorks */ /************** Include vxworks.h in the middle of sqliteInt.h ***************/ /************** Begin file vxworks.h *****************************************/ /* ** 2015-03-02 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to Wind River's VxWorks */ #if defined(__RTP__) || defined(_WRS_KERNEL) /* This is VxWorks. Set up things specially for that OS */ #include #include /* amalgamator: dontcache */ #define OS_VXWORKS 1 #define SQLITE_OS_OTHER 0 #define SQLITE_HOMEGROWN_RECURSIVE_MUTEX 1 #define SQLITE_OMIT_LOAD_EXTENSION 1 #define SQLITE_ENABLE_LOCKING_STYLE 0 #define HAVE_UTIME 1 #else /* This is not VxWorks. */ #define OS_VXWORKS 0 #define HAVE_FCHOWN 1 #define HAVE_READLINK 1 #define HAVE_LSTAT 1 #endif /* defined(_WRS_KERNEL) */ /************** End of vxworks.h *********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /* ** These #defines should enable >2GB file support on POSIX if the ** underlying operating system supports it. If the OS lacks ** large file support, or if the OS is windows, these should be no-ops. ** ** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any ** system #includes. Hence, this block of code must be the very first ** code in all source files. ** ** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch ** on the compiler command line. This is necessary if you are compiling ** on a recent machine (ex: Red Hat 7.2) but you want your code to work ** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2 ** without this option, LFS is enable. But LFS does not exist in the kernel ** in Red Hat 6.0, so the code won't work. Hence, for maximum binary ** portability you should omit LFS. ** ** The previous paragraph was written in 2005. (This paragraph is written ** on 2008-11-28.) These days, all Linux kernels support large files, so ** you should probably leave LFS enabled. But some embedded platforms might ** lack LFS in which case the SQLITE_DISABLE_LFS macro might still be useful. ** ** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later. */ #ifndef SQLITE_DISABLE_LFS # define _LARGE_FILE 1 # ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 # endif # define _LARGEFILE_SOURCE 1 #endif /* The GCC_VERSION and MSVC_VERSION macros are used to ** conditionally include optimizations for each of these compilers. A ** value of 0 means that compiler is not being used. The ** SQLITE_DISABLE_INTRINSIC macro means do not use any compiler-specific ** optimizations, and hence set all compiler macros to 0 ** ** There was once also a CLANG_VERSION macro. However, we learn that the ** version numbers in clang are for "marketing" only and are inconsistent ** and unreliable. Fortunately, all versions of clang also recognize the ** gcc version numbers and have reasonable settings for gcc version numbers, ** so the GCC_VERSION macro will be set to a correct non-zero value even ** when compiling with clang. */ #if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) #else # define GCC_VERSION 0 #endif #if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) # define MSVC_VERSION _MSC_VER #else # define MSVC_VERSION 0 #endif /* ** Some C99 functions in "math.h" are only present for MSVC when its version ** is associated with Visual Studio 2013 or higher. */ #ifndef SQLITE_HAVE_C99_MATH_FUNCS # if MSVC_VERSION==0 || MSVC_VERSION>=1800 # define SQLITE_HAVE_C99_MATH_FUNCS (1) # else # define SQLITE_HAVE_C99_MATH_FUNCS (0) # endif #endif /* Needed for various definitions... */ #if defined(__GNUC__) && !defined(_GNU_SOURCE) # define _GNU_SOURCE #endif #if defined(__OpenBSD__) && !defined(_BSD_SOURCE) # define _BSD_SOURCE #endif /* ** Macro to disable warnings about missing "break" at the end of a "case". */ #if GCC_VERSION>=7000000 # define deliberate_fall_through __attribute__((fallthrough)); #else # define deliberate_fall_through #endif /* ** For MinGW, check to see if we can include the header file containing its ** version information, among other things. Normally, this internal MinGW ** header file would [only] be included automatically by other MinGW header ** files; however, the contained version information is now required by this ** header file to work around binary compatibility issues (see below) and ** this is the only known way to reliably obtain it. This entire #if block ** would be completely unnecessary if there was any other way of detecting ** MinGW via their preprocessor (e.g. if they customized their GCC to define ** some MinGW-specific macros). When compiling for MinGW, either the ** _HAVE_MINGW_H or _HAVE__MINGW_H (note the extra underscore) macro must be ** defined; otherwise, detection of conditions specific to MinGW will be ** disabled. */ #if defined(_HAVE_MINGW_H) # include "mingw.h" #elif defined(_HAVE__MINGW_H) # include "_mingw.h" #endif /* ** For MinGW version 4.x (and higher), check to see if the _USE_32BIT_TIME_T ** define is required to maintain binary compatibility with the MSVC runtime ** library in use (e.g. for Windows XP). */ #if !defined(_USE_32BIT_TIME_T) && !defined(_USE_64BIT_TIME_T) && \ defined(_WIN32) && !defined(_WIN64) && \ defined(__MINGW_MAJOR_VERSION) && __MINGW_MAJOR_VERSION >= 4 && \ defined(__MSVCRT__) # define _USE_32BIT_TIME_T #endif /* Optionally #include a user-defined header, whereby compilation options ** may be set prior to where they take effect, but after platform setup. ** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include ** file. */ #ifdef SQLITE_CUSTOM_INCLUDE # define INC_STRINGIFY_(f) #f # define INC_STRINGIFY(f) INC_STRINGIFY_(f) # include INC_STRINGIFY(SQLITE_CUSTOM_INCLUDE) #endif /* The public SQLite interface. The _FILE_OFFSET_BITS macro must appear ** first in QNX. Also, the _USE_32BIT_TIME_T macro must appear first for ** MinGW. */ /************** Include sqlite3.h in the middle of sqliteInt.h ***************/ /************** Begin file sqlite3.h *****************************************/ /* ** 2001-09-15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the SQLite library ** presents to client programs. If a C-function, structure, datatype, ** or constant definition does not appear in this file, then it is ** not a published API of SQLite, is subject to change without ** notice, and should not be referenced by programs that use SQLite. ** ** Some of the definitions that are in this file are marked as ** "experimental". Experimental interfaces are normally new ** features recently added to SQLite. We do not anticipate changes ** to experimental interfaces but reserve the right to make minor changes ** if experience from use "in the wild" suggest such changes are prudent. ** ** The official C-language API documentation for SQLite is derived ** from comments in this file. This file is the authoritative source ** on how SQLite interfaces are supposed to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. */ #ifndef SQLITE3_H #define SQLITE3_H #include /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. */ #if 0 extern "C" { #endif /* ** Facilitate override of interface linkage and calling conventions. ** Be aware that these macros may not be used within this particular ** translation of the amalgamation and its associated header file. ** ** The SQLITE_EXTERN and SQLITE_API macros are used to instruct the ** compiler that the target identifier should have external linkage. ** ** The SQLITE_CDECL macro is used to set the calling convention for ** public functions that accept a variable number of arguments. ** ** The SQLITE_APICALL macro is used to set the calling convention for ** public functions that accept a fixed number of arguments. ** ** The SQLITE_STDCALL macro is no longer used and is now deprecated. ** ** The SQLITE_CALLBACK macro is used to set the calling convention for ** function pointers. ** ** The SQLITE_SYSAPI macro is used to set the calling convention for ** functions provided by the operating system. ** ** Currently, the SQLITE_CDECL, SQLITE_APICALL, SQLITE_CALLBACK, and ** SQLITE_SYSAPI macros are used only when building for environments ** that require non-default calling conventions. */ #ifndef SQLITE_EXTERN # define SQLITE_EXTERN extern #endif #ifndef SQLITE_API # define SQLITE_API #endif #ifndef SQLITE_CDECL # define SQLITE_CDECL #endif #ifndef SQLITE_APICALL # define SQLITE_APICALL #endif #ifndef SQLITE_STDCALL # define SQLITE_STDCALL SQLITE_APICALL #endif #ifndef SQLITE_CALLBACK # define SQLITE_CALLBACK #endif #ifndef SQLITE_SYSAPI # define SQLITE_SYSAPI #endif /* ** These no-op macros are used in front of interfaces to mark those ** interfaces as either deprecated or experimental. New applications ** should not use deprecated interfaces - they are supported for backwards ** compatibility only. Application writers should be aware that ** experimental interfaces are subject to change in point releases. ** ** These macros used to resolve to various kinds of compiler magic that ** would generate warning messages when they were used. But that ** compiler magic ended up generating such a flurry of bug reports ** that we have taken it all out and gone back to using simple ** noop macros. */ #define SQLITE_DEPRECATED #define SQLITE_EXPERIMENTAL /* ** Ensure these symbols were not defined by some previous header file. */ #ifdef SQLITE_VERSION # undef SQLITE_VERSION #endif #ifdef SQLITE_VERSION_NUMBER # undef SQLITE_VERSION_NUMBER #endif /* ** CAPI3REF: Compile-Time Library Version Numbers ** ** ^(The [SQLITE_VERSION] C preprocessor macro in the sqlite3.h header ** evaluates to a string literal that is the SQLite version in the ** format "X.Y.Z" where X is the major version number (always 3 for ** SQLite3) and Y is the minor version number and Z is the release number.)^ ** ^(The [SQLITE_VERSION_NUMBER] C preprocessor macro resolves to an integer ** with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same ** numbers used in [SQLITE_VERSION].)^ ** The SQLITE_VERSION_NUMBER for any given release of SQLite will also ** be larger than the release from which it is derived. Either Y will ** be held constant and Z will be incremented or else Y will be incremented ** and Z will be reset to zero. ** ** Since [version 3.6.18] ([dateof:3.6.18]), ** SQLite source code has been stored in the ** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID ** string contains the date and time of the check-in (UTC) and a SHA1 ** or SHA3-256 hash of the entire source tree. If the source code has ** been edited in any way since it was last checked in, then the last ** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.45.1" #define SQLITE_VERSION_NUMBER 3045001 #define SQLITE_SOURCE_ID "2024-01-30 16:01:20 e876e51a0ed5c5b3126f52e532044363a014bc594cfefa87ffb5b82257cc467a" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros ** but are associated with the library instead of the header file. ^(Cautious ** programmers might include assert() statements in their application to ** verify that values returned by these interfaces match the macros in ** the header, and thus ensure that the application is ** compiled with matching library and header files. ** **
** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
** 
)^ ** ** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] ** macro. ^The sqlite3_libversion() function returns a pointer to the ** to the sqlite3_version[] string constant. The sqlite3_libversion() ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to ** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns ** a pointer to a string constant whose value is the same as the ** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built ** using an edited copy of [the amalgamation], then the last four characters ** of the hash might be different from [SQLITE_SOURCE_ID].)^ ** ** See also: [sqlite_version()] and [sqlite_source_id()]. */ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; SQLITE_API const char *sqlite3_libversion(void); SQLITE_API const char *sqlite3_sourceid(void); SQLITE_API int sqlite3_libversion_number(void); /* ** CAPI3REF: Run-Time Library Compilation Options Diagnostics ** ** ^The sqlite3_compileoption_used() function returns 0 or 1 ** indicating whether the specified option was defined at ** compile time. ^The SQLITE_ prefix may be omitted from the ** option name passed to sqlite3_compileoption_used(). ** ** ^The sqlite3_compileoption_get() function allows iterating ** over the list of options that were defined at compile time by ** returning the N-th compile time option string. ^If N is out of range, ** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_ ** prefix is omitted from any strings returned by ** sqlite3_compileoption_get(). ** ** ^Support for the diagnostic functions sqlite3_compileoption_used() ** and sqlite3_compileoption_get() may be omitted by specifying the ** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time. ** ** See also: SQL functions [sqlite_compileoption_used()] and ** [sqlite_compileoption_get()] and the [compile_options pragma]. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_API int sqlite3_compileoption_used(const char *zOptName); SQLITE_API const char *sqlite3_compileoption_get(int N); #else # define sqlite3_compileoption_used(X) 0 # define sqlite3_compileoption_get(X) ((void*)0) #endif /* ** CAPI3REF: Test To See If The Library Is Threadsafe ** ** ^The sqlite3_threadsafe() function returns zero if and only if ** SQLite was compiled with mutexing code omitted due to the ** [SQLITE_THREADSAFE] compile-time option being set to 0. ** ** SQLite can be compiled with or without mutexes. When ** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes ** are enabled and SQLite is threadsafe. When the ** [SQLITE_THREADSAFE] macro is 0, ** the mutexes are omitted. Without the mutexes, it is not safe ** to use SQLite concurrently from more than one thread. ** ** Enabling mutexes incurs a measurable performance penalty. ** So if speed is of utmost importance, it makes sense to disable ** the mutexes. But for maximum safety, mutexes should be enabled. ** ^The default behavior is for mutexes to be enabled. ** ** This interface can be used by an application to make sure that the ** version of SQLite that it is linking against was compiled with ** the desired setting of the [SQLITE_THREADSAFE] macro. ** ** This interface only reports on the compile-time mutex setting ** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with ** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but ** can be fully or partially disabled using a call to [sqlite3_config()] ** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD], ** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the ** sqlite3_threadsafe() function shows only the compile-time setting of ** thread safety, not any run-time changes to that setting made by ** sqlite3_config(). In other words, the return value from sqlite3_threadsafe() ** is unchanged by calls to sqlite3_config().)^ ** ** See the [threading mode] documentation for additional information. */ SQLITE_API int sqlite3_threadsafe(void); /* ** CAPI3REF: Database Connection Handle ** KEYWORDS: {database connection} {database connections} ** ** Each open SQLite database is represented by a pointer to an instance of ** the opaque structure named "sqlite3". It is useful to think of an sqlite3 ** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and ** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()] ** and [sqlite3_close_v2()] are its destructors. There are many other ** interfaces (such as ** [sqlite3_prepare_v2()], [sqlite3_create_function()], and ** [sqlite3_busy_timeout()] to name but three) that are methods on an ** sqlite3 object. */ typedef struct sqlite3 sqlite3; /* ** CAPI3REF: 64-Bit Integer Types ** KEYWORDS: sqlite_int64 sqlite_uint64 ** ** Because there is no cross-platform way to specify 64-bit integer types ** SQLite includes typedefs for 64-bit signed and unsigned integers. ** ** The sqlite3_int64 and sqlite3_uint64 are the preferred type definitions. ** The sqlite_int64 and sqlite_uint64 types are supported for backwards ** compatibility only. ** ** ^The sqlite3_int64 and sqlite_int64 types can store integer values ** between -9223372036854775808 and +9223372036854775807 inclusive. ^The ** sqlite3_uint64 and sqlite_uint64 types can store integer values ** between 0 and +18446744073709551615 inclusive. */ #ifdef SQLITE_INT64_TYPE typedef SQLITE_INT64_TYPE sqlite_int64; # ifdef SQLITE_UINT64_TYPE typedef SQLITE_UINT64_TYPE sqlite_uint64; # else typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; # endif #elif defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 sqlite_int64; typedef unsigned __int64 sqlite_uint64; #else typedef long long int sqlite_int64; typedef unsigned long long int sqlite_uint64; #endif typedef sqlite_int64 sqlite3_int64; typedef sqlite_uint64 sqlite3_uint64; /* ** If compiling for a processor that lacks floating point support, ** substitute integer for floating-point. */ #ifdef SQLITE_OMIT_FLOATING_POINT # define double sqlite3_int64 #endif /* ** CAPI3REF: Closing A Database Connection ** DESTRUCTOR: sqlite3 ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. ** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if ** the [sqlite3] object is successfully destroyed and all associated ** resources are deallocated. ** ** Ideally, applications should [sqlite3_finalize | finalize] all ** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated ** with the [sqlite3] object prior to attempting to close the object. ** ^If the database connection is associated with unfinalized prepared ** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then ** sqlite3_close() will leave the database connection open and return ** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared ** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups, ** it returns [SQLITE_OK] regardless, but instead of deallocating the database ** connection immediately, it marks the database connection as an unusable ** "zombie" and makes arrangements to automatically deallocate the database ** connection after all prepared statements are finalized, all BLOB handles ** are closed, and all backups have finished. The sqlite3_close_v2() interface ** is intended for use with host languages that are garbage collected, and ** where the order in which destructors are called is arbitrary. ** ** ^If an [sqlite3] object is destroyed while a transaction is open, ** the transaction is automatically rolled back. ** ** The C parameter to [sqlite3_close(C)] and [sqlite3_close_v2(C)] ** must be either a NULL ** pointer or an [sqlite3] object pointer obtained ** from [sqlite3_open()], [sqlite3_open16()], or ** [sqlite3_open_v2()], and not previously closed. ** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer ** argument is a harmless no-op. */ SQLITE_API int sqlite3_close(sqlite3*); SQLITE_API int sqlite3_close_v2(sqlite3*); /* ** The type for a callback function. ** This is legacy and deprecated. It is included for historical ** compatibility and is not documented. */ typedef int (*sqlite3_callback)(void*,int,char**, char**); /* ** CAPI3REF: One-Step Query Execution Interface ** METHOD: sqlite3 ** ** The sqlite3_exec() interface is a convenience wrapper around ** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], ** that allows an application to run multiple statements of SQL ** without having to use a lot of C code. ** ** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, ** semicolon-separate SQL statements passed into its 2nd argument, ** in the context of the [database connection] passed in as its 1st ** argument. ^If the callback function of the 3rd argument to ** sqlite3_exec() is not NULL, then it is invoked for each result row ** coming out of the evaluated SQL statements. ^The 4th argument to ** sqlite3_exec() is relayed through to the 1st argument of each ** callback invocation. ^If the callback pointer to sqlite3_exec() ** is NULL, then no callback is ever invoked and result rows are ** ignored. ** ** ^If an error occurs while evaluating the SQL statements passed into ** sqlite3_exec(), then execution of the current statement stops and ** subsequent statements are skipped. ^If the 5th parameter to sqlite3_exec() ** is not NULL then any error message is written into memory obtained ** from [sqlite3_malloc()] and passed back through the 5th parameter. ** To avoid memory leaks, the application should invoke [sqlite3_free()] ** on error message strings returned through the 5th parameter of ** sqlite3_exec() after the error message string is no longer needed. ** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors ** occur, then sqlite3_exec() sets the pointer in its 5th parameter to ** NULL before returning. ** ** ^If an sqlite3_exec() callback returns non-zero, the sqlite3_exec() ** routine returns SQLITE_ABORT without invoking the callback again and ** without running any subsequent SQL statements. ** ** ^The 2nd argument to the sqlite3_exec() callback function is the ** number of columns in the result. ^The 3rd argument to the sqlite3_exec() ** callback is an array of pointers to strings obtained as if from ** [sqlite3_column_text()], one for each column. ^If an element of a ** result row is NULL then the corresponding string pointer for the ** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the ** sqlite3_exec() callback is an array of pointers to strings where each ** entry represents the name of corresponding result column as obtained ** from [sqlite3_column_name()]. ** ** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer ** to an empty string, or a pointer that contains only whitespace and/or ** SQL comments, then no SQL statements are evaluated and the database ** is not changed. ** ** Restrictions: ** **
    **
  • The application must ensure that the 1st parameter to sqlite3_exec() ** is a valid and open [database connection]. **
  • The application must not close the [database connection] specified by ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. **
  • The application must not modify the SQL statement text passed into ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. **
*/ SQLITE_API int sqlite3_exec( sqlite3*, /* An open database */ const char *sql, /* SQL to be evaluated */ int (*callback)(void*,int,char**,char**), /* Callback function */ void *, /* 1st argument to callback */ char **errmsg /* Error msg written here */ ); /* ** CAPI3REF: Result Codes ** KEYWORDS: {result code definitions} ** ** Many SQLite functions return an integer result code from the set shown ** here in order to indicate success or failure. ** ** New error codes may be added in future versions of SQLite. ** ** See also: [extended result code definitions] */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ #define SQLITE_ERROR 1 /* Generic error */ #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ #define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */ #define SQLITE_BUSY 5 /* The database file is locked */ #define SQLITE_LOCKED 6 /* A table in the database is locked */ #define SQLITE_NOMEM 7 /* A malloc() failed */ #define SQLITE_READONLY 8 /* Attempt to write a readonly database */ #define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ #define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ #define SQLITE_CORRUPT 11 /* The database disk image is malformed */ #define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ #define SQLITE_EMPTY 16 /* Internal use only */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ #define SQLITE_MISMATCH 20 /* Data type mismatch */ #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ #define SQLITE_FORMAT 24 /* Not used */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ /* end-of-error-codes */ /* ** CAPI3REF: Extended Result Codes ** KEYWORDS: {extended result code definitions} ** ** In its default configuration, SQLite API routines return one of 30 integer ** [result codes]. However, experience has shown that many of ** these result codes are too coarse-grained. They do not provide as ** much information about problems as programmers might like. In an effort to ** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8] ** and later) include ** support for additional result codes that provide more detailed information ** about errors. These [extended result codes] are enabled or disabled ** on a per database connection basis using the ** [sqlite3_extended_result_codes()] API. Or, the extended code for ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) #define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) #define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) #define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) #define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) #define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) #define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8)) #define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8)) #define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8)) #define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) #define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8)) #define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8)) #define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8)) #define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8)) #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) #define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) #define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */ #define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8)) #define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) #define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8)) #define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) #define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) #define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) #define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) #define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) #define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) #define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) #define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. ** ** Only those flags marked as "Ok for sqlite3_open_v2()" may be ** used as the third argument to the [sqlite3_open_v2()] interface. ** The other flags have historically been ignored by sqlite3_open_v2(), ** though future versions of SQLite might change so that an error is ** raised if any of the disallowed bits are passed into sqlite3_open_v2(). ** Applications should not depend on the historical behavior. ** ** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into ** [sqlite3_open_v2()] does *not* cause the underlying database file ** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into ** [sqlite3_open_v2()] has historically be a no-op and might become an ** error in future versions of SQLite. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ #define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_MEMORY 0x00000080 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ #define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ #define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */ #define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ #define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */ /* Reserved: 0x00F00000 */ /* Legacy compatibility: */ #define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ /* ** CAPI3REF: Device Characteristics ** ** The xDeviceCharacteristics method of the [sqlite3_io_methods] ** object returns an integer which is a vector of these ** bit values expressing I/O characteristics of the mass storage ** device that holds the file that the [sqlite3_io_methods] ** refers to. ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values ** mean that writes of blocks that are nnn bytes in size and ** are aligned to an address which is an integer multiple of ** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means ** that when data is appended to a file, the data is appended ** first then the size of the file is extended, never the other ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that ** information is written to disk in the same order as calls ** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that ** after reboot following a crash or power loss, the only bytes in a ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are ** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN ** flag indicates that a file cannot be deleted when open. The ** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on ** read-only media and cannot be changed even by processes with ** elevated privileges. ** ** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying ** filesystem supports doing multiple write operations atomically when those ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 #define SQLITE_IOCAP_ATOMIC1K 0x00000004 #define SQLITE_IOCAP_ATOMIC2K 0x00000008 #define SQLITE_IOCAP_ATOMIC4K 0x00000010 #define SQLITE_IOCAP_ATOMIC8K 0x00000020 #define SQLITE_IOCAP_ATOMIC16K 0x00000040 #define SQLITE_IOCAP_ATOMIC32K 0x00000080 #define SQLITE_IOCAP_ATOMIC64K 0x00000100 #define SQLITE_IOCAP_SAFE_APPEND 0x00000200 #define SQLITE_IOCAP_SEQUENTIAL 0x00000400 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods ** of an [sqlite3_io_methods] object. These values are ordered from ** lest restrictive to most restrictive. ** ** The argument to xLock() is always SHARED or higher. The argument to ** xUnlock is either SHARED or NONE. */ #define SQLITE_LOCK_NONE 0 /* xUnlock() only */ #define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */ #define SQLITE_LOCK_RESERVED 2 /* xLock() only */ #define SQLITE_LOCK_PENDING 3 /* xLock() only */ #define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */ /* ** CAPI3REF: Synchronization Type Flags ** ** When SQLite invokes the xSync() method of an ** [sqlite3_io_methods] object it uses a combination of ** these integer values as the second argument. ** ** When the SQLITE_SYNC_DATAONLY flag is used, it means that the ** sync operation only needs to flush data to mass storage. Inode ** information need not be flushed. If the lower four bits of the flag ** equal SQLITE_SYNC_NORMAL, that means to use normal fsync() semantics. ** If the lower four bits equal SQLITE_SYNC_FULL, that means ** to use Mac OS X style fullsync instead of fsync(). ** ** Do not confuse the SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags ** with the [PRAGMA synchronous]=NORMAL and [PRAGMA synchronous]=FULL ** settings. The [synchronous pragma] determines when calls to the ** xSync VFS method occur and applies uniformly across all platforms. ** The SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags determine how ** energetic or rigorous or forceful the sync operations are and ** only make a difference on Mac OSX for the default SQLite code. ** (Third-party VFS implementations might also make the distinction ** between SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL, but among the ** operating systems natively supported by SQLite, only Mac OSX ** cares about the difference.) */ #define SQLITE_SYNC_NORMAL 0x00002 #define SQLITE_SYNC_FULL 0x00003 #define SQLITE_SYNC_DATAONLY 0x00010 /* ** CAPI3REF: OS Interface Open File Handle ** ** An [sqlite3_file] object represents an open file in the ** [sqlite3_vfs | OS interface layer]. Individual OS interface ** implementations will ** want to subclass this object by appending additional fields ** for their own use. The pMethods entry is a pointer to an ** [sqlite3_io_methods] object that defines methods for performing ** I/O operations on the open file. */ typedef struct sqlite3_file sqlite3_file; struct sqlite3_file { const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ }; /* ** CAPI3REF: OS Interface File Virtual Methods Object ** ** Every file opened by the [sqlite3_vfs.xOpen] method populates an ** [sqlite3_file] object (or, more commonly, a subclass of the ** [sqlite3_file] object) with a pointer to an instance of this object. ** This object defines the methods used to perform various operations ** against the open file represented by the [sqlite3_file] object. ** ** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method ** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The ** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] ** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element ** to NULL. ** ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). ** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] ** flag may be ORed in to indicate that only the data of the file ** and not its inode needs to be synced. ** ** The integer values to xLock() and xUnlock() are one of **
    **
  • [SQLITE_LOCK_NONE], **
  • [SQLITE_LOCK_SHARED], **
  • [SQLITE_LOCK_RESERVED], **
  • [SQLITE_LOCK_PENDING], or **
  • [SQLITE_LOCK_EXCLUSIVE]. **
** xLock() upgrades the database file lock. In other words, xLock() moves the ** database file lock in the direction NONE toward EXCLUSIVE. The argument to ** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never ** SQLITE_LOCK_NONE. If the database file lock is already at or above the ** requested lock, then the call to xLock() is a no-op. ** xUnlock() downgrades the database file lock to either SHARED or NONE. * If the lock is already at or below the requested lock state, then the call ** to xUnlock() is a no-op. ** The xCheckReservedLock() method checks whether any database connection, ** either in this process or in some other process, is holding a RESERVED, ** PENDING, or EXCLUSIVE lock on the file. It returns true ** if such a lock exists and false otherwise. ** ** The xFileControl() method is a generic interface that allows custom ** VFS implementations to directly control an open file using the ** [sqlite3_file_control()] interface. The second "op" argument is an ** integer opcode. The third argument is a generic pointer intended to ** point to a structure that may contain arguments or space in which to ** write return values. Potential uses for xFileControl() might be ** functions to enable blocking locks with timeouts, to change the ** locking strategy (for example to use dot-file locks), to inquire ** about the status of a lock, or to break stale locks. The SQLite ** core reserves all opcodes less than 100 for its own use. ** A [file control opcodes | list of opcodes] less than 100 is available. ** Applications that define a custom xFileControl method should use opcodes ** greater than 100 to avoid conflicts. VFS implementations should ** return [SQLITE_NOTFOUND] for file control opcodes that they do not ** recognize. ** ** The xSectorSize() method returns the sector size of the ** device that underlies the file. The sector size is the ** minimum write that can be performed without disturbing ** other bytes in the file. The xDeviceCharacteristics() ** method returns a bit vector describing behaviors of the ** underlying device: ** **
    **
  • [SQLITE_IOCAP_ATOMIC] **
  • [SQLITE_IOCAP_ATOMIC512] **
  • [SQLITE_IOCAP_ATOMIC1K] **
  • [SQLITE_IOCAP_ATOMIC2K] **
  • [SQLITE_IOCAP_ATOMIC4K] **
  • [SQLITE_IOCAP_ATOMIC8K] **
  • [SQLITE_IOCAP_ATOMIC16K] **
  • [SQLITE_IOCAP_ATOMIC32K] **
  • [SQLITE_IOCAP_ATOMIC64K] **
  • [SQLITE_IOCAP_SAFE_APPEND] **
  • [SQLITE_IOCAP_SEQUENTIAL] **
  • [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN] **
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] **
  • [SQLITE_IOCAP_IMMUTABLE] **
  • [SQLITE_IOCAP_BATCH_ATOMIC] **
** ** The SQLITE_IOCAP_ATOMIC property means that all writes of ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values ** mean that writes of blocks that are nnn bytes in size and ** are aligned to an address which is an integer multiple of ** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means ** that when data is appended to a file, the data is appended ** first then the size of the file is extended, never the other ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that ** information is written to disk in the same order as calls ** to xWrite(). ** ** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill ** in the unread portions of the buffer with zeros. A VFS that ** fails to zero-fill short reads might seem to work. However, ** failure to zero-fill short reads will eventually lead to ** database corruption. */ typedef struct sqlite3_io_methods sqlite3_io_methods; struct sqlite3_io_methods { int iVersion; int (*xClose)(sqlite3_file*); int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); int (*xSync)(sqlite3_file*, int flags); int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); int (*xLock)(sqlite3_file*, int); int (*xUnlock)(sqlite3_file*, int); int (*xCheckReservedLock)(sqlite3_file*, int *pResOut); int (*xFileControl)(sqlite3_file*, int op, void *pArg); int (*xSectorSize)(sqlite3_file*); int (*xDeviceCharacteristics)(sqlite3_file*); /* Methods above are valid for version 1 */ int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); void (*xShmBarrier)(sqlite3_file*); int (*xShmUnmap)(sqlite3_file*, int deleteFlag); /* Methods above are valid for version 2 */ int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); /* Methods above are valid for version 3 */ /* Additional methods may be added in future releases */ }; /* ** CAPI3REF: Standard File Control Opcodes ** KEYWORDS: {file control opcodes} {file control opcode} ** ** These integer constants are opcodes for the xFileControl method ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] ** interface. ** **
    **
  • [[SQLITE_FCNTL_LOCKSTATE]] ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. ** This capability is only available if SQLite is compiled with [SQLITE_DEBUG]. ** **
  • [[SQLITE_FCNTL_SIZE_HINT]] ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS ** layer a hint of how large the database file will grow to be during the ** current transaction. This hint is not guaranteed to be accurate but it ** is often close. The underlying VFS might choose to preallocate database ** file space based on this hint in order to help writes to the database ** file run faster. ** **
  • [[SQLITE_FCNTL_SIZE_LIMIT]] ** The [SQLITE_FCNTL_SIZE_LIMIT] opcode is used by in-memory VFS that ** implements [sqlite3_deserialize()] to set an upper bound on the size ** of the in-memory database. The argument is a pointer to a [sqlite3_int64]. ** If the integer pointed to is negative, then it is filled in with the ** current limit. Otherwise the limit is set to the larger of the value ** of the integer pointed to and the current database size. The integer ** pointed to is set to the new limit. ** **
  • [[SQLITE_FCNTL_CHUNK_SIZE]] ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS ** extends and truncates the database file in chunks of a size specified ** by the user. The fourth argument to [sqlite3_file_control()] should ** point to an integer (type int) containing the new chunk-size to use ** for the nominated database. Allocating database file space in large ** chunks (say 1MB at a time), may reduce file-system fragmentation and ** improve performance on some systems. ** **
  • [[SQLITE_FCNTL_FILE_POINTER]] ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer ** to the [sqlite3_file] object associated with a particular database ** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER]. ** **
  • [[SQLITE_FCNTL_JOURNAL_POINTER]] ** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer ** to the [sqlite3_file] object associated with the journal file (either ** the [rollback journal] or the [write-ahead log]) for a particular database ** connection. See also [SQLITE_FCNTL_FILE_POINTER]. ** **
  • [[SQLITE_FCNTL_SYNC_OMITTED]] ** No longer in use. ** **
  • [[SQLITE_FCNTL_SYNC]] ** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and ** sent to the VFS immediately before the xSync method is invoked on a ** database file descriptor. Or, if the xSync method is not invoked ** because the user has configured SQLite with ** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place ** of the xSync method. In most cases, the pointer argument passed with ** this file-control is NULL. However, if the database file is being synced ** as part of a multi-database commit, the argument points to a nul-terminated ** string containing the transactions super-journal file name. VFSes that ** do not need this signal should silently ignore this opcode. Applications ** should not call [sqlite3_file_control()] with this opcode as doing so may ** disrupt the operation of the specialized VFSes that do require it. ** **
  • [[SQLITE_FCNTL_COMMIT_PHASETWO]] ** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite ** and sent to the VFS after a transaction has been committed immediately ** but before the database is unlocked. VFSes that do not need this signal ** should silently ignore this opcode. Applications should not call ** [sqlite3_file_control()] with this opcode as doing so may disrupt the ** operation of the specialized VFSes that do require it. ** **
  • [[SQLITE_FCNTL_WIN32_AV_RETRY]] ** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic ** retry counts and intervals for certain disk I/O operations for the ** windows [VFS] in order to provide robustness in the presence of ** anti-virus programs. By default, the windows VFS will retry file read, ** file write, and file delete operations up to 10 times, with a delay ** of 25 milliseconds before the first retry and with the delay increasing ** by an additional 25 milliseconds with each subsequent retry. This ** opcode allows these two values (10 retries and 25 milliseconds of delay) ** to be adjusted. The values are changed for all database connections ** within the same process. The argument is a pointer to an array of two ** integers where the first integer is the new retry count and the second ** integer is the delay. If either integer is negative, then the setting ** is not changed but instead the prior value of that setting is written ** into the array entry, allowing the current retry settings to be ** interrogated. The zDbName parameter is ignored. ** **
  • [[SQLITE_FCNTL_PERSIST_WAL]] ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary ** write ahead log ([WAL file]) and shared memory ** files used for transaction control ** are automatically deleted when the latest connection to the database ** closes. Setting persistent WAL mode causes those files to persist after ** close. Persisting the files is useful when other processes that do not ** have write permission on the directory containing the database file want ** to read the database file, as the WAL and shared memory files must exist ** in order for the database to be readable. The fourth parameter to ** [sqlite3_file_control()] for this opcode should be a pointer to an integer. ** That integer is 0 to disable persistent WAL mode or 1 to enable persistent ** WAL mode. If the integer is -1, then it is overwritten with the current ** WAL persistence setting. ** **
  • [[SQLITE_FCNTL_POWERSAFE_OVERWRITE]] ** ^The [SQLITE_FCNTL_POWERSAFE_OVERWRITE] opcode is used to set or query the ** persistent "powersafe-overwrite" or "PSOW" setting. The PSOW setting ** determines the [SQLITE_IOCAP_POWERSAFE_OVERWRITE] bit of the ** xDeviceCharacteristics methods. The fourth parameter to ** [sqlite3_file_control()] for this opcode should be a pointer to an integer. ** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage ** mode. If the integer is -1, then it is overwritten with the current ** zero-damage mode setting. ** **
  • [[SQLITE_FCNTL_OVERWRITE]] ** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening ** a write transaction to indicate that, unless it is rolled back for some ** reason, the entire database file will be overwritten by the current ** transaction. This is used by VACUUM operations. ** **
  • [[SQLITE_FCNTL_VFSNAME]] ** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of ** all [VFSes] in the VFS stack. The names are of all VFS shims and the ** final bottom-level VFS are written into memory obtained from ** [sqlite3_malloc()] and the result is stored in the char* variable ** that the fourth parameter of [sqlite3_file_control()] points to. ** The caller is responsible for freeing the memory when done. As with ** all file-control actions, there is no guarantee that this will actually ** do anything. Callers should initialize the char* variable to a NULL ** pointer in case this file-control is not implemented. This file-control ** is intended for diagnostic use only. ** **
  • [[SQLITE_FCNTL_VFS_POINTER]] ** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level ** [VFSes] currently in use. ^(The argument X in ** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be ** of type "[sqlite3_vfs] **". This opcodes will set *X ** to a pointer to the top-level VFS.)^ ** ^When there are multiple VFS shims in the stack, this opcode finds the ** upper-most shim only. ** **
  • [[SQLITE_FCNTL_PRAGMA]] ** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] ** file control is sent to the open [sqlite3_file] object corresponding ** to the database file to which the pragma statement refers. ^The argument ** to the [SQLITE_FCNTL_PRAGMA] file control is an array of ** pointers to strings (char**) in which the second element of the array ** is the name of the pragma and the third element is the argument to the ** pragma or NULL if the pragma has no argument. ^The handler for an ** [SQLITE_FCNTL_PRAGMA] file control can optionally make the first element ** of the char** argument point to a string obtained from [sqlite3_mprintf()] ** or the equivalent and that string will become the result of the pragma or ** the error message if the pragma fails. ^If the ** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] ** file control returns [SQLITE_OK], then the parser assumes that the ** VFS has handled the PRAGMA itself and the parser generates a no-op ** prepared statement if result string is NULL, or that returns a copy ** of the result string if the string is non-NULL. ** ^If the [SQLITE_FCNTL_PRAGMA] file control returns ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means ** that the VFS encountered an error while handling the [PRAGMA] and the ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] ** file control occurs at the beginning of pragma statement analysis and so ** it is able to override built-in [PRAGMA] statements. ** **
  • [[SQLITE_FCNTL_BUSYHANDLER]] ** ^The [SQLITE_FCNTL_BUSYHANDLER] ** file-control may be invoked by SQLite on the database file handle ** shortly after it is opened in order to provide a custom VFS with access ** to the connection's busy-handler callback. The argument is of type (void**) ** - an array of two (void *) values. The first (void *) actually points ** to a function of type (int (*)(void *)). In order to invoke the connection's ** busy-handler, this function should be invoked with the second (void *) in ** the array as the only argument. If it returns non-zero, then the operation ** should be retried. If it returns zero, the custom VFS should abandon the ** current operation. ** **
  • [[SQLITE_FCNTL_TEMPFILENAME]] ** ^Applications can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control ** to have SQLite generate a ** temporary filename using the same algorithm that is followed to generate ** temporary filenames for TEMP tables and other internal uses. The ** argument should be a char** which will be filled with the filename ** written into memory obtained from [sqlite3_malloc()]. The caller should ** invoke [sqlite3_free()] on the result to avoid a memory leak. ** **
  • [[SQLITE_FCNTL_MMAP_SIZE]] ** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the ** maximum number of bytes that will be used for memory-mapped I/O. ** The argument is a pointer to a value of type sqlite3_int64 that ** is an advisory maximum number of bytes in the file to memory map. The ** pointer is overwritten with the old value. The limit is not changed if ** the value originally pointed to is negative, and so the current limit ** can be queried by passing in a pointer to a negative number. This ** file-control is used internally to implement [PRAGMA mmap_size]. ** **
  • [[SQLITE_FCNTL_TRACE]] ** The [SQLITE_FCNTL_TRACE] file control provides advisory information ** to the VFS about what the higher layers of the SQLite stack are doing. ** This file control is used by some VFS activity tracing [shims]. ** The argument is a zero-terminated string. Higher layers in the ** SQLite stack may generate instances of this file control if ** the [SQLITE_USE_FCNTL_TRACE] compile-time option is enabled. ** **
  • [[SQLITE_FCNTL_HAS_MOVED]] ** The [SQLITE_FCNTL_HAS_MOVED] file control interprets its argument as a ** pointer to an integer and it writes a boolean into that integer depending ** on whether or not the file has been renamed, moved, or deleted since it ** was first opened. ** **
  • [[SQLITE_FCNTL_WIN32_GET_HANDLE]] ** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the ** underlying native file handle associated with a file handle. This file ** control interprets its argument as a pointer to a native file handle and ** writes the resulting value there. ** **
  • [[SQLITE_FCNTL_WIN32_SET_HANDLE]] ** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This ** opcode causes the xFileControl method to swap the file handle with the one ** pointed to by the pArg argument. This capability is used during testing ** and only needs to be supported when SQLITE_TEST is defined. ** **
  • [[SQLITE_FCNTL_WAL_BLOCK]] ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might ** be advantageous to block on the next WAL lock if the lock is not immediately ** available. The WAL subsystem issues this signal during rare ** circumstances in order to fix a problem with priority inversion. ** Applications should not use this file-control. ** **
  • [[SQLITE_FCNTL_ZIPVFS]] ** The [SQLITE_FCNTL_ZIPVFS] opcode is implemented by zipvfs only. All other ** VFS should return SQLITE_NOTFOUND for this opcode. ** **
  • [[SQLITE_FCNTL_RBU]] ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by ** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for ** this opcode. ** **
  • [[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]] ** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then ** the file descriptor is placed in "batch write mode", which ** means all subsequent write operations will be deferred and done ** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems ** that do not support batch atomic writes will return SQLITE_NOTFOUND. ** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to ** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or ** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make ** no VFS interface calls on the same [sqlite3_file] file descriptor ** except for calls to the xWrite method and the xFileControl method ** with [SQLITE_FCNTL_SIZE_HINT]. ** **
  • [[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]] ** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write ** operations since the previous successful call to ** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically. ** This file control returns [SQLITE_OK] if and only if the writes were ** all performed successfully and have been committed to persistent storage. ** ^Regardless of whether or not it is successful, this file control takes ** the file descriptor out of batch write mode so that all subsequent ** write operations are independent. ** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without ** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** **
  • [[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]] ** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write ** operations since the previous successful call to ** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back. ** ^This file control takes the file descriptor out of batch write mode ** so that all subsequent write operations are independent. ** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without ** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** **
  • [[SQLITE_FCNTL_LOCK_TIMEOUT]] ** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS ** to block for up to M milliseconds before failing when attempting to ** obtain a file lock using the xLock or xShmLock methods of the VFS. ** The parameter is a pointer to a 32-bit signed integer that contains ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** **
  • [[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. ** The "data version" for the pager is written into the pointer. The ** "data version" changes whenever any change occurs to the corresponding ** database file, either through SQL statements on the same database ** connection or through transactions committed by separate database ** connections possibly in other processes. The [sqlite3_total_changes()] ** interface can be used to find if any database on the connection has changed, ** but that interface responds to changes on TEMP as well as MAIN and does ** not provide a mechanism to detect changes to MAIN only. Also, the ** [sqlite3_total_changes()] interface responds to internal changes only and ** omits changes made by other database connections. The ** [PRAGMA data_version] command provides a mechanism to detect changes to ** a single attached database that occur due to other database connections, ** but omits changes implemented by the database connection on which it is ** called. This file control is the only mechanism to detect changes that ** happen either internally or externally and that are associated with ** a particular attached database. ** **
  • [[SQLITE_FCNTL_CKPT_START]] ** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint ** in wal mode before the client starts to copy pages from the wal ** file to the database file. ** **
  • [[SQLITE_FCNTL_CKPT_DONE]] ** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint ** in wal mode after the client has finished copying pages from the wal ** file to the database file, but before the *-shm file is updated to ** record the fact that the pages have been checkpointed. ** **
  • [[SQLITE_FCNTL_EXTERNAL_READER]] ** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect ** whether or not there is a database client in another process with a wal-mode ** transaction open on the database or not. It is only available on unix.The ** (void*) argument passed with this file-control should be a pointer to a ** value of type (int). The integer value is set to 1 if the database is a wal ** mode database and there exists at least one client in another process that ** currently has an SQL transaction open on the database. It is set to 0 if ** the database is not a wal-mode db, or if there is no such connection in any ** other process. This opcode cannot be used to detect transactions opened ** by clients within the current process, only within other processes. ** **
  • [[SQLITE_FCNTL_CKSM_FILE]] ** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the ** [checksum VFS shim] only. ** **
  • [[SQLITE_FCNTL_RESET_CACHE]] ** If there is currently no transaction open on the database, and the ** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control ** purges the contents of the in-memory page cache. If there is an open ** transaction, or if the db is a temp-db, this opcode is a no-op, not an error. **
*/ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 #define SQLITE_FCNTL_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_WIN32_AV_RETRY 9 #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_BUSYHANDLER 15 #define SQLITE_FCNTL_TEMPFILENAME 16 #define SQLITE_FCNTL_MMAP_SIZE 18 #define SQLITE_FCNTL_TRACE 19 #define SQLITE_FCNTL_HAS_MOVED 20 #define SQLITE_FCNTL_SYNC 21 #define SQLITE_FCNTL_COMMIT_PHASETWO 22 #define SQLITE_FCNTL_WIN32_SET_HANDLE 23 #define SQLITE_FCNTL_WAL_BLOCK 24 #define SQLITE_FCNTL_ZIPVFS 25 #define SQLITE_FCNTL_RBU 26 #define SQLITE_FCNTL_VFS_POINTER 27 #define SQLITE_FCNTL_JOURNAL_POINTER 28 #define SQLITE_FCNTL_WIN32_GET_HANDLE 29 #define SQLITE_FCNTL_PDB 30 #define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 #define SQLITE_FCNTL_LOCK_TIMEOUT 34 #define SQLITE_FCNTL_DATA_VERSION 35 #define SQLITE_FCNTL_SIZE_LIMIT 36 #define SQLITE_FCNTL_CKPT_DONE 37 #define SQLITE_FCNTL_RESERVE_BYTES 38 #define SQLITE_FCNTL_CKPT_START 39 #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only ** deals with pointers to the [sqlite3_mutex] object. ** ** Mutexes are created using [sqlite3_mutex_alloc()]. */ typedef struct sqlite3_mutex sqlite3_mutex; /* ** CAPI3REF: Loadable Extension Thunk ** ** A pointer to the opaque sqlite3_api_routines structure is passed as ** the third parameter to entry points of [loadable extensions]. This ** structure must be typedefed in order to work around compiler warnings ** on some platforms. */ typedef struct sqlite3_api_routines sqlite3_api_routines; /* ** CAPI3REF: File Name ** ** Type [sqlite3_filename] is used by SQLite to pass filenames to the ** xOpen method of a [VFS]. It may be cast to (const char*) and treated ** as a normal, nul-terminated, UTF-8 buffer containing the filename, but ** may also be passed to special APIs such as: ** **
    **
  • sqlite3_filename_database() **
  • sqlite3_filename_journal() **
  • sqlite3_filename_wal() **
  • sqlite3_uri_parameter() **
  • sqlite3_uri_boolean() **
  • sqlite3_uri_int64() **
  • sqlite3_uri_key() **
*/ typedef const char *sqlite3_filename; /* ** CAPI3REF: OS Interface Object ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" ** in the name of the object stands for "virtual file system". See ** the [VFS | VFS documentation] for further information. ** ** The VFS interface is sometimes extended by adding new methods onto ** the end. Each time such an extension occurs, the iVersion field ** is incremented. The iVersion value started out as 1 in ** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2 ** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased ** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6]. Additional fields ** may be appended to the sqlite3_vfs object and the iVersion value ** may increase again in future versions of SQLite. ** Note that due to an oversight, the structure ** of the sqlite3_vfs object changed in the transition from ** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0] ** and yet the iVersion field was not increased. ** ** The szOsFile field is the size of the subclassed [sqlite3_file] ** structure used by this VFS. mxPathname is the maximum length of ** a pathname in this VFS. ** ** Registered sqlite3_vfs objects are kept on a linked list formed by ** the pNext pointer. The [sqlite3_vfs_register()] ** and [sqlite3_vfs_unregister()] interfaces manage this list ** in a thread-safe way. The [sqlite3_vfs_find()] interface ** searches the list. Neither the application code nor the VFS ** implementation should use the pNext pointer. ** ** The pNext field is the only field in the sqlite3_vfs ** structure that SQLite will ever modify. SQLite will only access ** or modify this field while holding a particular static mutex. ** The application should never modify anything within the sqlite3_vfs ** object once the object has been registered. ** ** The zName field holds the name of the VFS module. The name must ** be unique across all VFS modules. ** ** [[sqlite3_vfs.xOpen]] ** ^SQLite guarantees that the zFilename parameter to xOpen ** is either a NULL pointer or string obtained ** from xFullPathname() with an optional suffix added. ** ^If a suffix is added to the zFilename parameter, it will ** consist of a single "-" character followed by no more than ** 11 alphanumeric and/or "-" characters. ** ^SQLite further guarantees that ** the string will be valid and unchanged until xClose() is ** called. Because of the previous sentence, ** the [sqlite3_file] can safely store a pointer to the ** filename if it needs to remember the filename for some reason. ** If the zFilename parameter to xOpen is a NULL pointer then xOpen ** must invent its own temporary name for the file. ^Whenever the ** xFilename parameter is NULL it will also be the case that the ** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE]. ** ** The flags argument to xOpen() includes all bits set in ** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()] ** or [sqlite3_open16()] is used, then flags includes at least ** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. ** If xOpen() opens a file read-only then it sets *pOutFlags to ** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set. ** ** ^(SQLite will also add one of the following flags to the xOpen() ** call, depending on the object being opened: ** **
    **
  • [SQLITE_OPEN_MAIN_DB] **
  • [SQLITE_OPEN_MAIN_JOURNAL] **
  • [SQLITE_OPEN_TEMP_DB] **
  • [SQLITE_OPEN_TEMP_JOURNAL] **
  • [SQLITE_OPEN_TRANSIENT_DB] **
  • [SQLITE_OPEN_SUBJOURNAL] **
  • [SQLITE_OPEN_SUPER_JOURNAL] **
  • [SQLITE_OPEN_WAL] **
)^ ** ** The file I/O implementation can use the object type flags to ** change the way it deals with files. For example, an application ** that does not care about crash recovery or rollback might make ** the open of a journal file a no-op. Writes to this journal would ** also be no-ops, and any attempt to read the journal would return ** SQLITE_IOERR. Or the implementation might recognize that a database ** file will be doing page-aligned sector reads and writes in a random ** order and set up its I/O subsystem accordingly. ** ** SQLite might also add one of the following flags to the xOpen method: ** **
    **
  • [SQLITE_OPEN_DELETEONCLOSE] **
  • [SQLITE_OPEN_EXCLUSIVE] **
** ** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be ** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE] ** will be set for TEMP databases and their journals, transient ** databases, and subjournals. ** ** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction ** with the [SQLITE_OPEN_CREATE] flag, which are both directly ** analogous to the O_EXCL and O_CREAT flags of the POSIX open() ** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the ** SQLITE_OPEN_CREATE, is used to indicate that file should always ** be created, and that it is an error if it already exists. ** It is not used to indicate the file should be opened ** for exclusive access. ** ** ^At least szOsFile bytes of memory are allocated by SQLite ** to hold the [sqlite3_file] structure passed as the third ** argument to xOpen. The xOpen method does not have to ** allocate the structure; it should just fill it in. Note that ** the xOpen method must set the sqlite3_file.pMethods to either ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods ** element will be valid after xOpen returns regardless of the success ** or failure of the xOpen call. ** ** [[sqlite3_vfs.xAccess]] ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] ** to test whether a file is at least readable. The SQLITE_ACCESS_READ ** flag is never actually used and is not implemented in the built-in ** VFSes of SQLite. The file is named by the second argument and can be a ** directory. The xAccess method returns [SQLITE_OK] on success or some ** non-zero error code if there is an I/O error or if the name of ** the file given in the second argument is illegal. If SQLITE_OK ** is returned, then non-zero or zero is written into *pResOut to indicate ** whether or not the file is accessible. ** ** ^SQLite will always allocate at least mxPathname+1 bytes for the ** output buffer xFullPathname. The exact size of the output buffer ** is also passed as a parameter to both methods. If the output buffer ** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is ** handled as a fatal error by SQLite, vfs implementations should endeavor ** to prevent this by setting mxPathname to a sufficiently large value. ** ** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64() ** interfaces are not strictly a part of the filesystem, but they are ** included in the VFS structure for completeness. ** The xRandomness() function attempts to return nBytes bytes ** of good-quality randomness into zOut. The return value is ** the actual number of bytes of randomness obtained. ** The xSleep() method causes the calling thread to sleep for at ** least the number of microseconds given. ^The xCurrentTime() ** method returns a Julian Day Number for the current date and time as ** a floating point value. ** ^The xCurrentTimeInt64() method returns, as an integer, the Julian ** Day Number multiplied by 86400000 (the number of milliseconds in ** a 24-hour day). ** ^SQLite will use the xCurrentTimeInt64() method to get the current ** date and time if that method is available (if iVersion is 2 or ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. ** ** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces ** are not used by the SQLite core. These optional interfaces are provided ** by some VFSes to facilitate testing of the VFS code. By overriding ** system calls with functions under its control, a test program can ** simulate faults and error conditions that would otherwise be difficult ** or impossible to induce. The set of system calls that can be overridden ** varies from one VFS to another, and from one version of the same VFS to the ** next. Applications that use these interfaces must be prepared for any ** or all of these interfaces to be NULL or for their behavior to change ** from one release to the next. Applications must not attempt to access ** any of these methods if the iVersion of the VFS is less than 3. */ typedef struct sqlite3_vfs sqlite3_vfs; typedef void (*sqlite3_syscall_ptr)(void); struct sqlite3_vfs { int iVersion; /* Structure version number (currently 3) */ int szOsFile; /* Size of subclassed sqlite3_file */ int mxPathname; /* Maximum file pathname length */ sqlite3_vfs *pNext; /* Next registered VFS */ const char *zName; /* Name of this virtual file system */ void *pAppData; /* Pointer to application-specific data */ int (*xOpen)(sqlite3_vfs*, sqlite3_filename zName, sqlite3_file*, int flags, int *pOutFlags); int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); void (*xDlClose)(sqlite3_vfs*, void*); int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); int (*xSleep)(sqlite3_vfs*, int microseconds); int (*xCurrentTime)(sqlite3_vfs*, double*); int (*xGetLastError)(sqlite3_vfs*, int, char *); /* ** The methods above are in version 1 of the sqlite_vfs object ** definition. Those that follow are added in version 2 or later */ int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); /* ** The methods above are in versions 1 and 2 of the sqlite_vfs object. ** Those below are for version 3 and greater. */ int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); /* ** The methods above are in versions 1 through 3 of the sqlite_vfs object. ** New fields may be appended in future versions. The iVersion ** value will increment whenever this happens. */ }; /* ** CAPI3REF: Flags for the xAccess VFS method ** ** These integer constants can be used as the third parameter to ** the xAccess method of an [sqlite3_vfs] object. They determine ** what kind of permissions the xAccess method is looking for. ** With SQLITE_ACCESS_EXISTS, the xAccess method ** simply checks whether the file exists. ** With SQLITE_ACCESS_READWRITE, the xAccess method ** checks whether the named directory is both readable and writable ** (in other words, if files can be added, removed, and renamed within ** the directory). ** The SQLITE_ACCESS_READWRITE constant is currently used only by the ** [temp_store_directory pragma], though this could change in a future ** release of SQLite. ** With SQLITE_ACCESS_READ, the xAccess method ** checks whether the file is readable. The SQLITE_ACCESS_READ constant is ** currently unused, though it might be used in a future release of ** SQLite. */ #define SQLITE_ACCESS_EXISTS 0 #define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */ #define SQLITE_ACCESS_READ 2 /* Unused */ /* ** CAPI3REF: Flags for the xShmLock VFS method ** ** These integer constants define the various locking operations ** allowed by the xShmLock method of [sqlite3_io_methods]. The ** following are the only legal combinations of flags to the ** xShmLock method: ** **
    **
  • SQLITE_SHM_LOCK | SQLITE_SHM_SHARED **
  • SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE **
  • SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED **
  • SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE **
** ** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as ** was given on the corresponding lock. ** ** The xShmLock method can transition between unlocked and SHARED or ** between unlocked and EXCLUSIVE. It cannot transition between SHARED ** and EXCLUSIVE. */ #define SQLITE_SHM_UNLOCK 1 #define SQLITE_SHM_LOCK 2 #define SQLITE_SHM_SHARED 4 #define SQLITE_SHM_EXCLUSIVE 8 /* ** CAPI3REF: Maximum xShmLock index ** ** The xShmLock method on [sqlite3_io_methods] may use values ** between 0 and this upper bound as its "offset" argument. ** The SQLite core will never attempt to acquire or release a ** lock outside of this range */ #define SQLITE_SHM_NLOCK 8 /* ** CAPI3REF: Initialize The SQLite Library ** ** ^The sqlite3_initialize() routine initializes the ** SQLite library. ^The sqlite3_shutdown() routine ** deallocates any resources that were allocated by sqlite3_initialize(). ** These routines are designed to aid in process initialization and ** shutdown on embedded systems. Workstation applications using ** SQLite normally do not need to invoke either of these routines. ** ** A call to sqlite3_initialize() is an "effective" call if it is ** the first time sqlite3_initialize() is invoked during the lifetime of ** the process, or if it is the first time sqlite3_initialize() is invoked ** following a call to sqlite3_shutdown(). ^(Only an effective call ** of sqlite3_initialize() does any initialization. All other calls ** are harmless no-ops.)^ ** ** A call to sqlite3_shutdown() is an "effective" call if it is the first ** call to sqlite3_shutdown() since the last sqlite3_initialize(). ^(Only ** an effective call to sqlite3_shutdown() does any deinitialization. ** All other valid calls to sqlite3_shutdown() are harmless no-ops.)^ ** ** The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown() ** is not. The sqlite3_shutdown() interface must only be called from a ** single thread. All open [database connections] must be closed and all ** other SQLite resources must be deallocated prior to invoking ** sqlite3_shutdown(). ** ** Among other things, ^sqlite3_initialize() will invoke ** sqlite3_os_init(). Similarly, ^sqlite3_shutdown() ** will invoke sqlite3_os_end(). ** ** ^The sqlite3_initialize() routine returns [SQLITE_OK] on success. ** ^If for some reason, sqlite3_initialize() is unable to initialize ** the library (perhaps it is unable to allocate a needed resource such ** as a mutex) it returns an [error code] other than [SQLITE_OK]. ** ** ^The sqlite3_initialize() routine is called internally by many other ** SQLite interfaces so that an application usually does not need to ** invoke sqlite3_initialize() directly. For example, [sqlite3_open()] ** calls sqlite3_initialize() so the SQLite library will be automatically ** initialized when [sqlite3_open()] is called if it has not be initialized ** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT] ** compile-time option, then the automatic calls to sqlite3_initialize() ** are omitted and the application must call sqlite3_initialize() directly ** prior to using any other SQLite interface. For maximum portability, ** it is recommended that applications always invoke sqlite3_initialize() ** directly prior to using any other SQLite interface. Future releases ** of SQLite may require this. In other words, the behavior exhibited ** when SQLite is compiled with [SQLITE_OMIT_AUTOINIT] might become the ** default behavior in some future release of SQLite. ** ** The sqlite3_os_init() routine does operating-system specific ** initialization of the SQLite library. The sqlite3_os_end() ** routine undoes the effect of sqlite3_os_init(). Typical tasks ** performed by these routines include allocation or deallocation ** of static resources, initialization of global variables, ** setting up a default [sqlite3_vfs] module, or setting up ** a default configuration using [sqlite3_config()]. ** ** The application should never invoke either sqlite3_os_init() ** or sqlite3_os_end() directly. The application should only invoke ** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init() ** interface is called automatically by sqlite3_initialize() and ** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate ** implementations for sqlite3_os_init() and sqlite3_os_end() ** are built into SQLite when it is compiled for Unix, Windows, or OS/2. ** When [custom builds | built for other platforms] ** (using the [SQLITE_OS_OTHER=1] compile-time ** option) the application must supply a suitable implementation for ** sqlite3_os_init() and sqlite3_os_end(). An application-supplied ** implementation of sqlite3_os_init() or sqlite3_os_end() ** must return [SQLITE_OK] on success and some other [error code] upon ** failure. */ SQLITE_API int sqlite3_initialize(void); SQLITE_API int sqlite3_shutdown(void); SQLITE_API int sqlite3_os_init(void); SQLITE_API int sqlite3_os_end(void); /* ** CAPI3REF: Configuring The SQLite Library ** ** The sqlite3_config() interface is used to make global configuration ** changes to SQLite in order to tune SQLite to the specific needs of ** the application. The default configuration is recommended for most ** applications and so this routine is usually not necessary. It is ** provided to support rare applications with unusual needs. ** ** The sqlite3_config() interface is not threadsafe. The application ** must ensure that no other SQLite interfaces are invoked by other ** threads while sqlite3_config() is running. ** ** The first argument to sqlite3_config() is an integer ** [configuration option] that determines ** what property of SQLite is to be configured. Subsequent arguments ** vary depending on the [configuration option] ** in the first argument. ** ** For most configuration options, the sqlite3_config() interface ** may only be invoked prior to library initialization using ** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. ** The exceptional configuration options that may be invoked at any time ** are called "anytime configuration options". ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before ** [sqlite3_shutdown()] with a first argument that is not an anytime ** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. ** ^If the option is unknown or SQLite is unable to set the option ** then this routine returns a non-zero [error code]. */ SQLITE_API int sqlite3_config(int, ...); /* ** CAPI3REF: Configure database connections ** METHOD: sqlite3 ** ** The sqlite3_db_config() interface is used to make configuration ** changes to a [database connection]. The interface is similar to ** [sqlite3_config()] except that the changes apply to a single ** [database connection] (specified in the first argument). ** ** The second argument to sqlite3_db_config(D,V,...) is the ** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code ** that indicates what aspect of the [database connection] is being configured. ** Subsequent arguments vary depending on the configuration verb. ** ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if ** the call is considered successful. */ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); /* ** CAPI3REF: Memory Allocation Routines ** ** An instance of this object defines the interface between SQLite ** and low-level memory allocation routines. ** ** This object is used in only one place in the SQLite interface. ** A pointer to an instance of this object is the argument to ** [sqlite3_config()] when the configuration option is ** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. ** By creating an instance of this object ** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC]) ** during configuration, an application can specify an alternative ** memory allocation subsystem for SQLite to use for all of its ** dynamic memory needs. ** ** Note that SQLite comes with several [built-in memory allocators] ** that are perfectly adequate for the overwhelming majority of applications ** and that this object is only useful to a tiny minority of applications ** with specialized memory allocation requirements. This object is ** also used during testing of SQLite in order to specify an alternative ** memory allocator that simulates memory out-of-memory conditions in ** order to verify that SQLite recovers gracefully from such ** conditions. ** ** The xMalloc, xRealloc, and xFree methods must work like the ** malloc(), realloc() and free() functions from the standard C library. ** ^SQLite guarantees that the second argument to ** xRealloc is always a value returned by a prior call to xRoundup. ** ** xSize should return the allocated size of a memory allocation ** previously obtained from xMalloc or xRealloc. The allocated size ** is always at least as big as the requested size but may be larger. ** ** The xRoundup method returns what would be the allocated size of ** a memory allocation given a particular requested size. Most memory ** allocators round up memory allocations at least to the next multiple ** of 8. Some allocators round up to a larger multiple or to a power of 2. ** Every memory allocation request coming in through [sqlite3_malloc()] ** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, ** that causes the corresponding memory allocation to fail. ** ** The xInit method initializes the memory allocator. For example, ** it might allocate any required mutexes or initialize internal data ** structures. The xShutdown method is invoked (indirectly) by ** [sqlite3_shutdown()] and should deallocate any resources acquired ** by xInit. The pAppData pointer is used as the only parameter to ** xInit and xShutdown. ** ** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes ** the xInit method, so the xInit method need not be threadsafe. The ** xShutdown method is only called from [sqlite3_shutdown()] so it does ** not need to be threadsafe either. For all other methods, SQLite ** holds the [SQLITE_MUTEX_STATIC_MEM] mutex as long as the ** [SQLITE_CONFIG_MEMSTATUS] configuration option is turned on (which ** it is by default) and so the methods are automatically serialized. ** However, if [SQLITE_CONFIG_MEMSTATUS] is disabled, then the other ** methods must be threadsafe or else make their own arrangements for ** serialization. ** ** SQLite will never invoke xInit() more than once without an intervening ** call to xShutdown(). */ typedef struct sqlite3_mem_methods sqlite3_mem_methods; struct sqlite3_mem_methods { void *(*xMalloc)(int); /* Memory allocation function */ void (*xFree)(void*); /* Free a prior allocation */ void *(*xRealloc)(void*,int); /* Resize an allocation */ int (*xSize)(void*); /* Return the size of an allocation */ int (*xRoundup)(int); /* Round up request size to allocation size */ int (*xInit)(void*); /* Initialize the memory allocator */ void (*xShutdown)(void*); /* Deinitialize the memory allocator */ void *pAppData; /* Argument to xInit() and xShutdown() */ }; /* ** CAPI3REF: Configuration Options ** KEYWORDS: {configuration option} ** ** These constants are the available integer configuration options that ** can be passed as the first argument to the [sqlite3_config()] interface. ** ** Most of the configuration options for sqlite3_config() ** will only work if invoked prior to [sqlite3_initialize()] or after ** [sqlite3_shutdown()]. The few exceptions to this rule are called ** "anytime configuration options". ** ^Calling [sqlite3_config()] with a first argument that is not an ** anytime configuration option in between calls to [sqlite3_initialize()] and ** [sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE. ** ** The set of anytime configuration options can change (by insertions ** and/or deletions) from one release of SQLite to the next. ** As of SQLite version 3.42.0, the complete set of anytime configuration ** options is: **
    **
  • SQLITE_CONFIG_LOG **
  • SQLITE_CONFIG_PCACHE_HDRSZ **
** ** New configuration options may be added in future releases of SQLite. ** Existing configuration options might be discontinued. Applications ** should check the return code from [sqlite3_config()] to make sure that ** the call worked. The [sqlite3_config()] interface will return a ** non-zero [error code] if a discontinued or unsupported configuration option ** is invoked. ** **
** [[SQLITE_CONFIG_SINGLETHREAD]]
SQLITE_CONFIG_SINGLETHREAD
**
There are no arguments to this option. ^This option sets the ** [threading mode] to Single-thread. In other words, it disables ** all mutexing and puts SQLite into a mode where it can only be used ** by a single thread. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to change the [threading mode] from its default ** value of Single-thread and so [sqlite3_config()] will return ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD ** configuration option.
** ** [[SQLITE_CONFIG_MULTITHREAD]]
SQLITE_CONFIG_MULTITHREAD
**
There are no arguments to this option. ^This option sets the ** [threading mode] to Multi-thread. In other words, it disables ** mutexing on [database connection] and [prepared statement] objects. ** The application is responsible for serializing access to ** [database connections] and [prepared statements]. But other mutexes ** are enabled so that SQLite will be safe to use in a multi-threaded ** environment as long as no two threads attempt to use the same ** [database connection] at the same time. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to set the Multi-thread [threading mode] and ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_MULTITHREAD configuration option.
** ** [[SQLITE_CONFIG_SERIALIZED]]
SQLITE_CONFIG_SERIALIZED
**
There are no arguments to this option. ^This option sets the ** [threading mode] to Serialized. In other words, this option enables ** all mutexes including the recursive ** mutexes on [database connection] and [prepared statement] objects. ** In this mode (which is the default when SQLite is compiled with ** [SQLITE_THREADSAFE=1]) the SQLite library will itself serialize access ** to [database connections] and [prepared statements] so that the ** application is free to use the same [database connection] or the ** same [prepared statement] in different threads at the same time. ** ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to set the Serialized [threading mode] and ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_SERIALIZED configuration option.
** ** [[SQLITE_CONFIG_MALLOC]]
SQLITE_CONFIG_MALLOC
**
^(The SQLITE_CONFIG_MALLOC option takes a single argument which is ** a pointer to an instance of the [sqlite3_mem_methods] structure. ** The argument specifies ** alternative low-level memory allocation routines to be used in place of ** the memory allocation routines built into SQLite.)^ ^SQLite makes ** its own private copy of the content of the [sqlite3_mem_methods] structure ** before the [sqlite3_config()] call returns.
** ** [[SQLITE_CONFIG_GETMALLOC]]
SQLITE_CONFIG_GETMALLOC
**
^(The SQLITE_CONFIG_GETMALLOC option takes a single argument which ** is a pointer to an instance of the [sqlite3_mem_methods] structure. ** The [sqlite3_mem_methods] ** structure is filled with the currently defined memory allocation routines.)^ ** This option can be used to overload the default memory allocation ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example.
** ** [[SQLITE_CONFIG_SMALL_MALLOC]]
SQLITE_CONFIG_SMALL_MALLOC
**
^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of ** type int, interpreted as a boolean, which if true provides a hint to ** SQLite that it should avoid large memory allocations if possible. ** SQLite will run faster if it is free to make large memory allocations, ** but some application might prefer to run slower in exchange for ** guarantees about memory fragmentation that are possible if large ** allocations are avoided. This hint is normally off. **
** ** [[SQLITE_CONFIG_MEMSTATUS]]
SQLITE_CONFIG_MEMSTATUS
**
^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, ** interpreted as a boolean, which enables or disables the collection of ** memory allocation statistics. ^(When memory allocation statistics are ** disabled, the following SQLite interfaces become non-operational: **
    **
  • [sqlite3_hard_heap_limit64()] **
  • [sqlite3_memory_used()] **
  • [sqlite3_memory_highwater()] **
  • [sqlite3_soft_heap_limit64()] **
  • [sqlite3_status64()] **
)^ ** ^Memory allocation statistics are enabled by default unless SQLite is ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory ** allocation statistics are disabled by default. **
** ** [[SQLITE_CONFIG_SCRATCH]]
SQLITE_CONFIG_SCRATCH
**
The SQLITE_CONFIG_SCRATCH option is no longer used. **
** ** [[SQLITE_CONFIG_PAGECACHE]]
SQLITE_CONFIG_PAGECACHE
**
^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool ** that SQLite can use for the database page cache with the default page ** cache implementation. ** This configuration option is a no-op if an application-defined page ** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]. ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to ** 8-byte aligned memory (pMem), the size of each page cache line (sz), ** and the number of cache lines (N). ** The sz argument should be the size of the largest database page ** (a power of two between 512 and 65536) plus some extra bytes for each ** page header. ^The number of extra bytes needed by the page header ** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ]. ** ^It is harmless, apart from the wasted memory, ** for the sz parameter to be larger than necessary. The pMem ** argument must be either a NULL pointer or a pointer to an 8-byte ** aligned block of memory of at least sz*N bytes, otherwise ** subsequent behavior is undefined. ** ^When pMem is not NULL, SQLite will strive to use the memory provided ** to satisfy page cache needs, falling back to [sqlite3_malloc()] if ** a page cache line is larger than sz bytes or if all of the pMem buffer ** is exhausted. ** ^If pMem is NULL and N is non-zero, then each database connection ** does an initial bulk allocation for page cache memory ** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or ** of -1024*N bytes if N is negative, . ^If additional ** page cache memory is needed beyond what is provided by the initial ** allocation, then SQLite goes to [sqlite3_malloc()] separately for each ** additional cache line.
** ** [[SQLITE_CONFIG_HEAP]]
SQLITE_CONFIG_HEAP
**
^The SQLITE_CONFIG_HEAP option specifies a static memory buffer ** that SQLite will use for all of its dynamic memory allocation needs ** beyond those provided for by [SQLITE_CONFIG_PAGECACHE]. ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns ** [SQLITE_ERROR] if invoked otherwise. ** ^There are three arguments to SQLITE_CONFIG_HEAP: ** An 8-byte aligned pointer to the memory, ** the number of bytes in the memory buffer, and the minimum allocation size. ** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts ** to using its default memory allocator (the system malloc() implementation), ** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the ** memory pointer is not NULL then the alternative memory ** allocator is engaged to handle all of SQLites memory allocation needs. ** The first pointer (the memory pointer) must be aligned to an 8-byte ** boundary or subsequent behavior of SQLite will be undefined. ** The minimum allocation size is capped at 2**12. Reasonable values ** for the minimum allocation size are 2**5 through 2**8.
** ** [[SQLITE_CONFIG_MUTEX]]
SQLITE_CONFIG_MUTEX
**
^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a ** pointer to an instance of the [sqlite3_mutex_methods] structure. ** The argument specifies alternative low-level mutex routines to be used ** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of ** the content of the [sqlite3_mutex_methods] structure before the call to ** [sqlite3_config()] returns. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** the entire mutexing subsystem is omitted from the build and hence calls to ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will ** return [SQLITE_ERROR].
** ** [[SQLITE_CONFIG_GETMUTEX]]
SQLITE_CONFIG_GETMUTEX
**
^(The SQLITE_CONFIG_GETMUTEX option takes a single argument which ** is a pointer to an instance of the [sqlite3_mutex_methods] structure. The ** [sqlite3_mutex_methods] ** structure is filled with the currently defined mutex routines.)^ ** This option can be used to overload the default mutex allocation ** routines with a wrapper used to track mutex usage for performance ** profiling or testing, for example. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** the entire mutexing subsystem is omitted from the build and hence calls to ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will ** return [SQLITE_ERROR].
** ** [[SQLITE_CONFIG_LOOKASIDE]]
SQLITE_CONFIG_LOOKASIDE
**
^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine ** the default size of lookaside memory on each [database connection]. ** The first argument is the ** size of each lookaside buffer slot and the second is the number of ** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE ** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] ** option to [sqlite3_db_config()] can be used to change the lookaside ** configuration on individual connections.)^
** ** [[SQLITE_CONFIG_PCACHE2]]
SQLITE_CONFIG_PCACHE2
**
^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is ** a pointer to an [sqlite3_pcache_methods2] object. This object specifies ** the interface to a custom page cache implementation.)^ ** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.
** ** [[SQLITE_CONFIG_GETPCACHE2]]
SQLITE_CONFIG_GETPCACHE2
**
^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which ** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of ** the current page cache implementation into that object.)^
** ** [[SQLITE_CONFIG_LOG]]
SQLITE_CONFIG_LOG
**
The SQLITE_CONFIG_LOG option is used to configure the SQLite ** global [error log]. ** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a ** function with a call signature of void(*)(void*,int,const char*), ** and a pointer to void. ^If the function pointer is not NULL, it is ** invoked by [sqlite3_log()] to process each logging event. ^If the ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. ** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is ** passed through as the first parameter to the application-defined logger ** function whenever that function is invoked. ^The second parameter to ** the logger function is a copy of the first parameter to the corresponding ** [sqlite3_log()] call and is intended to be a [result code] or an ** [extended result code]. ^The third parameter passed to the logger is ** log message after formatting via [sqlite3_snprintf()]. ** The SQLite logging interface is not reentrant; the logger function ** supplied by the application must not invoke any SQLite interface. ** In a multi-threaded application, the application-defined logger ** function must be threadsafe.
** ** [[SQLITE_CONFIG_URI]]
SQLITE_CONFIG_URI **
^(The SQLITE_CONFIG_URI option takes a single argument of type int. ** If non-zero, then URI handling is globally enabled. If the parameter is zero, ** then URI handling is globally disabled.)^ ^If URI handling is globally ** enabled, all filenames passed to [sqlite3_open()], [sqlite3_open_v2()], ** [sqlite3_open16()] or ** specified as part of [ATTACH] commands are interpreted as URIs, regardless ** of whether or not the [SQLITE_OPEN_URI] flag is set when the database ** connection is opened. ^If it is globally disabled, filenames are ** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the ** database connection is opened. ^(By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** [SQLITE_USE_URI] symbol defined.)^ ** ** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]]
SQLITE_CONFIG_COVERING_INDEX_SCAN **
^The SQLITE_CONFIG_COVERING_INDEX_SCAN option takes a single integer ** argument which is interpreted as a boolean in order to enable or disable ** the use of covering indices for full table scans in the query optimizer. ** ^The default setting is determined ** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on" ** if that compile-time option is omitted. ** The ability to disable the use of covering indices for full table scans ** is because some incorrectly coded legacy applications might malfunction ** when the optimization is enabled. Providing the ability to ** disable the optimization allows the older, buggy application code to work ** without change even with newer versions of SQLite. ** ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] **
SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE **
These options are obsolete and should not be used by new code. ** They are retained for backwards compatibility but are now no-ops. **
** ** [[SQLITE_CONFIG_SQLLOG]] **
SQLITE_CONFIG_SQLLOG **
This option is only available if sqlite is compiled with the ** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should ** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int). ** The second should be of type (void*). The callback is invoked by the library ** in three separate circumstances, identified by the value passed as the ** fourth parameter. If the fourth parameter is 0, then the database connection ** passed as the second argument has just been opened. The third argument ** points to a buffer containing the name of the main database file. If the ** fourth parameter is 1, then the SQL statement that the third parameter ** points to has just been executed. Or, if the fourth parameter is 2, then ** the connection being passed as the second parameter is being closed. The ** third parameter is passed NULL In this case. An example of using this ** configuration option can be seen in the "test_sqllog.c" source file in ** the canonical SQLite source tree.
** ** [[SQLITE_CONFIG_MMAP_SIZE]] **
SQLITE_CONFIG_MMAP_SIZE **
^SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values ** that are the default mmap size limit (the default setting for ** [PRAGMA mmap_size]) and the maximum allowed mmap size limit. ** ^The default setting can be overridden by each database connection using ** either the [PRAGMA mmap_size] command, or by using the ** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size ** will be silently truncated if necessary so that it does not exceed the ** compile-time maximum mmap size set by the ** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^ ** ^If either argument to this option is negative, then that argument is ** changed to its compile-time default. ** ** [[SQLITE_CONFIG_WIN32_HEAPSIZE]] **
SQLITE_CONFIG_WIN32_HEAPSIZE **
^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is ** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro ** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value ** that specifies the maximum size of the created heap. ** ** [[SQLITE_CONFIG_PCACHE_HDRSZ]] **
SQLITE_CONFIG_PCACHE_HDRSZ **
^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which ** is a pointer to an integer and writes into that integer the number of extra ** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE]. ** The amount of extra space required can change depending on the compiler, ** target platform, and SQLite version. ** ** [[SQLITE_CONFIG_PMASZ]] **
SQLITE_CONFIG_PMASZ **
^The SQLITE_CONFIG_PMASZ option takes a single parameter which ** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded ** sorter to that integer. The default minimum PMA Size is set by the ** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched ** to help with sort operations when multithreaded sorting ** is enabled (using the [PRAGMA threads] command) and the amount of content ** to be sorted exceeds the page size times the minimum of the ** [PRAGMA cache_size] setting and this value. ** ** [[SQLITE_CONFIG_STMTJRNL_SPILL]] **
SQLITE_CONFIG_STMTJRNL_SPILL **
^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which ** becomes the [statement journal] spill-to-disk threshold. ** [Statement journals] are held in memory until their size (in bytes) ** exceeds this threshold, at which point they are written to disk. ** Or if the threshold is -1, statement journals are always held ** exclusively in memory. ** Since many statement journals never become large, setting the spill ** threshold to a value such as 64KiB can greatly reduce the amount of ** I/O required to support statement rollback. ** The default value for this setting is controlled by the ** [SQLITE_STMTJRNL_SPILL] compile-time option. ** ** [[SQLITE_CONFIG_SORTERREF_SIZE]] **
SQLITE_CONFIG_SORTERREF_SIZE **
The SQLITE_CONFIG_SORTERREF_SIZE option accepts a single parameter ** of type (int) - the new value of the sorter-reference size threshold. ** Usually, when SQLite uses an external sort to order records according ** to an ORDER BY clause, all fields required by the caller are present in the ** sorted records. However, if SQLite determines based on the declared type ** of a table column that its values are likely to be very large - larger ** than the configured sorter-reference size threshold - then a reference ** is stored in each sorted record and the required column values loaded ** from the database as records are returned in sorted order. The default ** value for this option is to never use this optimization. Specifying a ** negative value for this option restores the default behavior. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. ** ** [[SQLITE_CONFIG_MEMDB_MAXSIZE]] **
SQLITE_CONFIG_MEMDB_MAXSIZE **
The SQLITE_CONFIG_MEMDB_MAXSIZE option accepts a single parameter ** [sqlite3_int64] parameter which is the default maximum size for an in-memory ** database created using [sqlite3_deserialize()]. This default maximum ** size can be adjusted up or down for individual databases using the ** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this ** configuration setting is never used, then the default maximum is determined ** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that ** compile-time option is not set, then the default maximum is 1073741824. **
*/ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ #define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ #define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ #define SQLITE_CONFIG_PCACHE 14 /* no-op */ #define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that ** can be passed as the second argument to the [sqlite3_db_config()] interface. ** ** New configuration options may be added in future releases of SQLite. ** Existing configuration options might be discontinued. Applications ** should check the return code from [sqlite3_db_config()] to make sure that ** the call worked. ^The [sqlite3_db_config()] interface will return a ** non-zero [error code] if a discontinued or unsupported configuration option ** is invoked. ** **
** [[SQLITE_DBCONFIG_LOOKASIDE]] **
SQLITE_DBCONFIG_LOOKASIDE
**
^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. ** ^The first argument (the third parameter to [sqlite3_db_config()] is a ** pointer to a memory buffer to use for lookaside memory. ** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb ** may be NULL in which case SQLite will allocate the ** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the ** size of each lookaside buffer slot. ^The third argument is the number of ** slots. The size of the buffer in the first argument must be greater than ** or equal to the product of the second and third arguments. The buffer ** must be aligned to an 8-byte boundary. ^If the second argument to ** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally ** rounded down to the next smaller multiple of 8. ^(The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words ** when the "current value" returned by ** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^
** ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **
SQLITE_DBCONFIG_ENABLE_FKEY
**
^This option is used to enable or disable the enforcement of ** [foreign key constraints]. There should be two additional arguments. ** The first argument is an integer which is 0 to disable FK enforcement, ** positive to enable FK enforcement or negative to leave FK enforcement ** unchanged. The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether FK enforcement is off or on ** following this call. The second parameter may be a NULL pointer, in ** which case the FK enforcement setting is not reported back.
** ** [[SQLITE_DBCONFIG_ENABLE_TRIGGER]] **
SQLITE_DBCONFIG_ENABLE_TRIGGER
**
^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable triggers, ** positive to enable triggers or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether triggers are disabled or enabled ** following this call. The second parameter may be a NULL pointer, in ** which case the trigger setting is not reported back. ** **

Originally this option disabled all triggers. ^(However, since ** SQLite version 3.35.0, TEMP triggers are still allowed even if ** this option is off. So, in other words, this option now only disables ** triggers in the main database schema or in the schemas of ATTACH-ed ** databases.)^

** ** [[SQLITE_DBCONFIG_ENABLE_VIEW]] **
SQLITE_DBCONFIG_ENABLE_VIEW
**
^This option is used to enable or disable [CREATE VIEW | views]. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable views, ** positive to enable views or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether views are disabled or enabled ** following this call. The second parameter may be a NULL pointer, in ** which case the view setting is not reported back. ** **

Originally this option disabled all views. ^(However, since ** SQLite version 3.35.0, TEMP views are still allowed even if ** this option is off. So, in other words, this option now only disables ** views in the main database schema or in the schemas of ATTACH-ed ** databases.)^

** ** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] **
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
**
^This option is used to enable or disable the ** [fts3_tokenizer()] function which is part of the ** [FTS3] full-text search engine extension. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable fts3_tokenizer() or ** positive to enable fts3_tokenizer() or negative to leave the setting ** unchanged. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled ** following this call. The second parameter may be a NULL pointer, in ** which case the new setting is not reported back.
** ** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]] **
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
**
^This option is used to enable or disable the [sqlite3_load_extension()] ** interface independently of the [load_extension()] SQL function. ** The [sqlite3_enable_load_extension()] API enables or disables both the ** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. ** There should be two additional arguments. ** When the first argument to this interface is 1, then only the C-API is ** enabled and the SQL function remains disabled. If the first argument to ** this interface is 0, then both the C-API and the SQL function are disabled. ** If the first argument is -1, then no changes are made to state of either the ** C-API or the SQL function. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface ** is disabled or enabled following this call. The second parameter may ** be a NULL pointer, in which case the new setting is not reported back. **
** ** [[SQLITE_DBCONFIG_MAINDBNAME]]
SQLITE_DBCONFIG_MAINDBNAME
**
^This option is used to change the name of the "main" database ** schema. ^The sole argument is a pointer to a constant UTF8 string ** which will become the new schema name in place of "main". ^SQLite ** does not make a copy of the new main schema name string, so the application ** must ensure that the argument passed into this DBCONFIG option is unchanged ** until after the database connection closes. **
** ** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
**
Usually, when a database in wal mode is closed or detached from a ** database handle, SQLite checks if this will mean that there are now no ** connections at all to the database. If so, it performs a checkpoint ** operation before closing the connection. This option may be used to ** override this behavior. The first parameter passed to this operation ** is an integer - positive to disable checkpoints-on-close, or zero (the ** default) to enable them, and negative to leave the setting unchanged. ** The second parameter is a pointer to an integer ** into which is written 0 or 1 to indicate whether checkpoints-on-close ** have been disabled - 0 if they are not disabled, 1 if they are. **
** ** [[SQLITE_DBCONFIG_ENABLE_QPSG]]
SQLITE_DBCONFIG_ENABLE_QPSG
**
^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates ** the [query planner stability guarantee] (QPSG). When the QPSG is active, ** a single SQL query statement will always use the same algorithm regardless ** of values of [bound parameters].)^ The QPSG disables some query optimizations ** that look at the values of bound parameters, which can make some queries ** slower. But the QPSG has the advantage of more predictable behavior. With ** the QPSG active, SQLite will always use the same query plan in the field as ** was used during testing in the lab. ** The first argument to this setting is an integer which is 0 to disable ** the QPSG, positive to enable QPSG, or negative to leave the setting ** unchanged. The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether the QPSG is disabled or enabled ** following this call. **
** ** [[SQLITE_DBCONFIG_TRIGGER_EQP]]
SQLITE_DBCONFIG_TRIGGER_EQP
**
By default, the output of EXPLAIN QUERY PLAN commands does not ** include output for any operations performed by trigger programs. This ** option is used to set or clear (the default) a flag that governs this ** behavior. The first parameter passed to this operation is an integer - ** positive to enable output for trigger programs, or zero to disable it, ** or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which is written ** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if ** it is not disabled, 1 if it is. **
** ** [[SQLITE_DBCONFIG_RESET_DATABASE]]
SQLITE_DBCONFIG_RESET_DATABASE
**
Set the SQLITE_DBCONFIG_RESET_DATABASE flag and then run ** [VACUUM] in order to reset a database back to an empty database ** with no schema and no content. The following process works even for ** a badly corrupted database file: **
    **
  1. If the database connection is newly opened, make sure it has read the ** database schema by preparing then discarding some query against the ** database, or calling sqlite3_table_column_metadata(), ignoring any ** errors. This step is only necessary if the application desires to keep ** the database in WAL mode after the reset if it was in WAL mode before ** the reset. **
  2. sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); **
  3. [sqlite3_exec](db, "[VACUUM]", 0, 0, 0); **
  4. sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); **
** Because resetting a database is destructive and irreversible, the ** process requires the use of this obscure API and multiple steps to ** help ensure that it does not happen by accident. Because this ** feature must be capable of resetting corrupt databases, and ** shutting down virtual tables may require access to that corrupt ** storage, the library must abandon any installed virtual tables ** without calling their xDestroy() methods. ** ** [[SQLITE_DBCONFIG_DEFENSIVE]]
SQLITE_DBCONFIG_DEFENSIVE
**
The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the ** "defensive" flag for a database connection. When the defensive ** flag is enabled, language features that allow ordinary SQL to ** deliberately corrupt the database file are disabled. The disabled ** features include but are not limited to the following: **
    **
  • The [PRAGMA writable_schema=ON] statement. **
  • The [PRAGMA journal_mode=OFF] statement. **
  • The [PRAGMA schema_version=N] statement. **
  • Writes to the [sqlite_dbpage] virtual table. **
  • Direct writes to [shadow tables]. **
**
** ** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]]
SQLITE_DBCONFIG_WRITABLE_SCHEMA
**
The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the ** "writable_schema" flag. This has the same effect and is logically equivalent ** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF]. ** The first argument to this setting is an integer which is 0 to disable ** the writable_schema, positive to enable writable_schema, or negative to ** leave the setting unchanged. The second parameter is a pointer to an ** integer into which is written 0 or 1 to indicate whether the writable_schema ** is enabled or disabled following this call. **
** ** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] **
SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
**
The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates ** the legacy behavior of the [ALTER TABLE RENAME] command such it ** behaves as it did prior to [version 3.24.0] (2018-06-04). See the ** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for ** additional information. This feature can also be turned on and off ** using the [PRAGMA legacy_alter_table] statement. **
** ** [[SQLITE_DBCONFIG_DQS_DML]] **
SQLITE_DBCONFIG_DQS_DML
**
The SQLITE_DBCONFIG_DQS_DML option activates or deactivates ** the legacy [double-quoted string literal] misfeature for DML statements ** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The ** default value of this setting is determined by the [-DSQLITE_DQS] ** compile-time option. **
** ** [[SQLITE_DBCONFIG_DQS_DDL]] **
SQLITE_DBCONFIG_DQS_DDL
**
The SQLITE_DBCONFIG_DQS option activates or deactivates ** the legacy [double-quoted string literal] misfeature for DDL statements, ** such as CREATE TABLE and CREATE INDEX. The ** default value of this setting is determined by the [-DSQLITE_DQS] ** compile-time option. **
** ** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]] **
SQLITE_DBCONFIG_TRUSTED_SCHEMA
**
The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to ** assume that database schemas are untainted by malicious content. ** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite ** takes additional defensive steps to protect the application from harm ** including: **
    **
  • Prohibit the use of SQL functions inside triggers, views, ** CHECK constraints, DEFAULT clauses, expression indexes, ** partial indexes, or generated columns ** unless those functions are tagged with [SQLITE_INNOCUOUS]. **
  • Prohibit the use of virtual tables inside of triggers or views ** unless those virtual tables are tagged with [SQLITE_VTAB_INNOCUOUS]. **
** This setting defaults to "on" for legacy compatibility, however ** all applications are advised to turn it off if possible. This setting ** can also be controlled using the [PRAGMA trusted_schema] statement. **
** ** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]] **
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
**
The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates ** the legacy file format flag. When activated, this flag causes all newly ** created database file to have a schema format version number (the 4-byte ** integer found at offset 44 into the database header) of 1. This in turn ** means that the resulting database file will be readable and writable by ** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting, ** newly created databases are generally not understandable by SQLite versions ** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there ** is now scarcely any need to generate database files that are compatible ** all the way back to version 3.0.0, and so this setting is of little ** practical use, but is provided so that SQLite can continue to claim the ** ability to generate new database files that are compatible with version ** 3.0.0. **

Note that when the SQLITE_DBCONFIG_LEGACY_FILE_FORMAT setting is on, ** the [VACUUM] command will fail with an obscure error when attempting to ** process a table with generated columns and a descending index. This is ** not considered a bug since SQLite versions 3.3.0 and earlier do not support ** either generated columns or descending indexes. **

** ** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]] **
SQLITE_DBCONFIG_STMT_SCANSTATUS
**
The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in ** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears ** a flag that enables collection of the sqlite3_stmt_scanstatus_v2() ** statistics. For statistics to be collected, the flag must be set on ** the database handle both when the SQL statement is prepared and when it ** is stepped. The flag is set (collection of statistics is enabled) ** by default. This option takes two arguments: an integer and a pointer to ** an integer.. The first argument is 1, 0, or -1 to enable, disable, or ** leave unchanged the statement scanstatus option. If the second argument ** is not NULL, then the value of the statement scanstatus setting after ** processing the first argument is written into the integer that the second ** argument points to. **
** ** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]] **
SQLITE_DBCONFIG_REVERSE_SCANORDER
**
The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order ** in which tables and indexes are scanned so that the scans start at the end ** and work toward the beginning rather than starting at the beginning and ** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the ** same as setting [PRAGMA reverse_unordered_selects]. This option takes ** two arguments which are an integer and a pointer to an integer. The first ** argument is 1, 0, or -1 to enable, disable, or leave unchanged the ** reverse scan order flag, respectively. If the second argument is not NULL, ** then 0 or 1 is written into the integer that the second argument points to ** depending on if the reverse scan order flag is set after processing the ** first argument. **
** **
*/ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ #define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ #define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ #define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ #define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ #define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ #define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */ #define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */ #define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ #define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */ #define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */ #define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes ** METHOD: sqlite3 ** ** ^The sqlite3_extended_result_codes() routine enables or disables the ** [extended result codes] feature of SQLite. ^The extended result ** codes are disabled by default for historical compatibility. */ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); /* ** CAPI3REF: Last Insert Rowid ** METHOD: sqlite3 ** ** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables) ** has a unique 64-bit signed ** integer key called the [ROWID | "rowid"]. ^The rowid is always available ** as an undeclared column named ROWID, OID, or _ROWID_ as long as those ** names are not also used by explicitly declared columns. ^If ** the table has a column of type [INTEGER PRIMARY KEY] then that column ** is another alias for the rowid. ** ** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of ** the most recent successful [INSERT] into a rowid table or [virtual table] ** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not ** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred ** on the database connection D, then sqlite3_last_insert_rowid(D) returns ** zero. ** ** As well as being set automatically as rows are inserted into database ** tables, the value returned by this function may be set explicitly by ** [sqlite3_set_last_insert_rowid()] ** ** Some virtual table implementations may INSERT rows into rowid tables as ** part of committing a transaction (e.g. to flush data accumulated in memory ** to disk). In this case subsequent calls to this function return the rowid ** associated with these internal INSERT operations, which leads to ** unintuitive results. Virtual table implementations that do write to rowid ** tables in this way can avoid this problem by restoring the original ** rowid value using [sqlite3_set_last_insert_rowid()] before returning ** control to the user. ** ** ^(If an [INSERT] occurs within a trigger then this routine will ** return the [rowid] of the inserted row as long as the trigger is ** running. Once the trigger program ends, the value returned ** by this routine reverts to what it was before the trigger was fired.)^ ** ** ^An [INSERT] that fails due to a constraint violation is not a ** successful [INSERT] and does not change the value returned by this ** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, ** and INSERT OR ABORT make no changes to the return value of this ** routine when their insertion fails. ^(When INSERT OR REPLACE ** encounters a constraint violation, it does not fail. The ** INSERT continues to completion after deleting rows that caused ** the constraint problem so INSERT OR REPLACE will always change ** the return value of this interface.)^ ** ** ^For the purposes of this routine, an [INSERT] is considered to ** be successful even if it is subsequently rolled back. ** ** This function is accessible to SQL statements via the ** [last_insert_rowid() SQL function]. ** ** If a separate thread performs a new [INSERT] on the same ** database connection while the [sqlite3_last_insert_rowid()] ** function is running and thus changes the last insert [rowid], ** then the value returned by [sqlite3_last_insert_rowid()] is ** unpredictable and might not equal either the old or the new ** last insert [rowid]. */ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); /* ** CAPI3REF: Set the Last Insert Rowid value. ** METHOD: sqlite3 ** ** The sqlite3_set_last_insert_rowid(D, R) method allows the application to ** set the value returned by calling sqlite3_last_insert_rowid(D) to R ** without inserting a row into the database. */ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); /* ** CAPI3REF: Count The Number Of Rows Modified ** METHOD: sqlite3 ** ** ^These functions return the number of rows modified, inserted or ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. ** The two functions are identical except for the type of the return value ** and that if the number of rows modified by the most recent INSERT, UPDATE ** or DELETE is greater than the maximum value supported by type "int", then ** the return value of sqlite3_changes() is undefined. ^Executing any other ** type of SQL statement does not modify the value returned by these functions. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], ** [foreign key actions] or [REPLACE] constraint resolution are not counted. ** ** Changes to a view that are intercepted by ** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value ** returned by sqlite3_changes() immediately after an INSERT, UPDATE or ** DELETE statement run on a view is always zero. Only changes made to real ** tables are counted. ** ** Things are more complicated if the sqlite3_changes() function is ** executed while a trigger program is running. This may happen if the ** program uses the [changes() SQL function], or if some other callback ** function invokes sqlite3_changes() directly. Essentially: ** **
    **
  • ^(Before entering a trigger program the value returned by ** sqlite3_changes() function is saved. After the trigger program ** has finished, the original value is restored.)^ ** **
  • ^(Within a trigger program each INSERT, UPDATE and DELETE ** statement sets the value returned by sqlite3_changes() ** upon completion as normal. Of course, this value will not include ** any changes performed by sub-triggers, as the sqlite3_changes() ** value will be saved and restored after each sub-trigger has run.)^ **
** ** ^This means that if the changes() SQL function (or similar) is used ** by the first INSERT, UPDATE or DELETE statement within a trigger, it ** returns the value as set when the calling statement began executing. ** ^If it is used by the second or subsequent such statement within a trigger ** program, the value returned reflects the number of rows modified by the ** previous INSERT, UPDATE or DELETE statement within the same trigger. ** ** If a separate thread makes changes on the same database connection ** while [sqlite3_changes()] is running then the value returned ** is unpredictable and not meaningful. ** ** See also: **
    **
  • the [sqlite3_total_changes()] interface **
  • the [count_changes pragma] **
  • the [changes() SQL function] **
  • the [data_version pragma] **
*/ SQLITE_API int sqlite3_changes(sqlite3*); SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** METHOD: sqlite3 ** ** ^These functions return the total number of rows inserted, modified or ** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed ** since the database connection was opened, including those executed as ** part of trigger programs. The two functions are identical except for the ** type of the return value and that if the number of rows modified by the ** connection exceeds the maximum value supported by type "int", then ** the return value of sqlite3_total_changes() is undefined. ^Executing ** any other type of SQL statement does not affect the value returned by ** sqlite3_total_changes(). ** ** ^Changes made as part of [foreign key actions] are included in the ** count, but those made as part of REPLACE constraint resolution are ** not. ^Changes to a view that are intercepted by INSTEAD OF triggers ** are not counted. ** ** The [sqlite3_total_changes(D)] interface only reports the number ** of rows that changed due to SQL statement run against database ** connection D. Any changes by other database connections are ignored. ** To detect changes against a database file from other database ** connections use the [PRAGMA data_version] command or the ** [SQLITE_FCNTL_DATA_VERSION] [file control]. ** ** If a separate thread makes changes on the same database connection ** while [sqlite3_total_changes()] is running then the value ** returned is unpredictable and not meaningful. ** ** See also: **
    **
  • the [sqlite3_changes()] interface **
  • the [count_changes pragma] **
  • the [changes() SQL function] **
  • the [data_version pragma] **
  • the [SQLITE_FCNTL_DATA_VERSION] [file control] **
*/ SQLITE_API int sqlite3_total_changes(sqlite3*); SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query ** METHOD: sqlite3 ** ** ^This function causes any pending database operation to abort and ** return at its earliest opportunity. This routine is typically ** called in response to a user action such as pressing "Cancel" ** or Ctrl-C where the user wants a long query operation to halt ** immediately. ** ** ^It is safe to call this routine from a thread different from the ** thread that is currently running the database operation. But it ** is not safe to call this routine with a [database connection] that ** is closed or might close before sqlite3_interrupt() returns. ** ** ^If an SQL operation is very nearly finished at the time when ** sqlite3_interrupt() is called, then it might not have an opportunity ** to be interrupted and might continue to completion. ** ** ^An SQL operation that is interrupted will return [SQLITE_INTERRUPT]. ** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE ** that is inside an explicit transaction, then the entire transaction ** will be rolled back automatically. ** ** ^The sqlite3_interrupt(D) call is in effect until all currently running ** SQL statements on [database connection] D complete. ^Any new SQL statements ** that are started after the sqlite3_interrupt() call and before the ** running statement count reaches zero are interrupted as if they had been ** running prior to the sqlite3_interrupt() call. ^New SQL statements ** that are started after the running statement count reaches zero are ** not effected by the sqlite3_interrupt(). ** ^A call to sqlite3_interrupt(D) that occurs when there are no running ** SQL statements is a no-op and has no effect on SQL statements ** that are started after the sqlite3_interrupt() call returns. ** ** ^The [sqlite3_is_interrupted(D)] interface can be used to determine whether ** or not an interrupt is currently in effect for [database connection] D. ** It returns 1 if an interrupt is currently in effect, or 0 otherwise. */ SQLITE_API void sqlite3_interrupt(sqlite3*); SQLITE_API int sqlite3_is_interrupted(sqlite3*); /* ** CAPI3REF: Determine If An SQL Statement Is Complete ** ** These routines are useful during command-line input to determine if the ** currently entered text seems to form a complete SQL statement or ** if additional input is needed before sending the text into ** SQLite for parsing. ^These routines return 1 if the input string ** appears to be a complete SQL statement. ^A statement is judged to be ** complete if it ends with a semicolon token and is not a prefix of a ** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within ** string literals or quoted identifier names or comments are not ** independent tokens (they are part of the token in which they are ** embedded) and thus do not count as a statement terminator. ^Whitespace ** and comments that follow the final semicolon are ignored. ** ** ^These routines return 0 if the statement is incomplete. ^If a ** memory allocation fails, then SQLITE_NOMEM is returned. ** ** ^These routines do not parse the SQL statements thus ** will not detect syntactically incorrect SQL. ** ** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior ** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked ** automatically by sqlite3_complete16(). If that initialization fails, ** then the return value from sqlite3_complete16() will be non-zero ** regardless of whether or not the input SQL is complete.)^ ** ** The input to [sqlite3_complete()] must be a zero-terminated ** UTF-8 string. ** ** The input to [sqlite3_complete16()] must be a zero-terminated ** UTF-16 string in native byte order. */ SQLITE_API int sqlite3_complete(const char *sql); SQLITE_API int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors ** KEYWORDS: {busy-handler callback} {busy handler} ** METHOD: sqlite3 ** ** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X ** that might be invoked with argument P whenever ** an attempt is made to access a database table associated with ** [database connection] D when another thread ** or process has the table locked. ** The sqlite3_busy_handler() interface is used to implement ** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout]. ** ** ^If the busy callback is NULL, then [SQLITE_BUSY] ** is returned immediately upon encountering the lock. ^If the busy callback ** is not NULL, then the callback might be invoked with two arguments. ** ** ^The first argument to the busy handler is a copy of the void* pointer which ** is the third argument to sqlite3_busy_handler(). ^The second argument to ** the busy handler callback is the number of times that the busy handler has ** been invoked previously for the same locking event. ^If the ** busy callback returns 0, then no additional attempts are made to ** access the database and [SQLITE_BUSY] is returned ** to the application. ** ^If the callback returns non-zero, then another attempt ** is made to access the database and the cycle repeats. ** ** The presence of a busy handler does not guarantee that it will be invoked ** when there is lock contention. ^If SQLite determines that invoking the busy ** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] ** to the application instead of invoking the ** busy handler. ** Consider a scenario where one process is holding a read lock that ** it is trying to promote to a reserved lock and ** a second process is holding a reserved lock that it is trying ** to promote to an exclusive lock. The first process cannot proceed ** because it is blocked by the second and the second process cannot ** proceed because it is blocked by the first. If both processes ** invoke the busy handlers, neither will make any progress. Therefore, ** SQLite returns [SQLITE_BUSY] for the first process, hoping that this ** will induce the first process to release its read lock and allow ** the second process to proceed. ** ** ^The default busy callback is NULL. ** ** ^(There can only be a single busy handler defined for each ** [database connection]. Setting a new busy handler clears any ** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] ** or evaluating [PRAGMA busy_timeout=N] will change the ** busy handler and thus clear any previously set busy handler. ** ** The busy callback should not take any actions which modify the ** database connection that invoked the busy handler. In other words, ** the busy handler is not reentrant. Any such actions ** result in undefined behavior. ** ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); /* ** CAPI3REF: Set A Busy Timeout ** METHOD: sqlite3 ** ** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps ** for a specified amount of time when a table is locked. ^The handler ** will sleep multiple times until at least "ms" milliseconds of sleeping ** have accumulated. ^After at least "ms" milliseconds of sleeping, ** the handler returns 0 which causes [sqlite3_step()] to return ** [SQLITE_BUSY]. ** ** ^Calling this routine with an argument less than or equal to zero ** turns off all busy handlers. ** ** ^(There can only be a single busy handler for a particular ** [database connection] at any given moment. If another busy handler ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ ** ** See also: [PRAGMA busy_timeout] */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 ** ** This is a legacy interface that is preserved for backwards compatibility. ** Use of this interface is not recommended. ** ** Definition: A result table is memory data structure created by the ** [sqlite3_get_table()] interface. A result table records the ** complete query results from one or more queries. ** ** The table conceptually has a number of rows and columns. But ** these numbers are not part of the result table itself. These ** numbers are obtained separately. Let N be the number of rows ** and M be the number of columns. ** ** A result table is an array of pointers to zero-terminated UTF-8 strings. ** There are (N+1)*M elements in the array. The first M pointers point ** to zero-terminated strings that contain the names of the columns. ** The remaining entries all point to query results. NULL values result ** in NULL pointers. All other values are in their UTF-8 zero-terminated ** string representation as returned by [sqlite3_column_text()]. ** ** A result table might consist of one or more memory allocations. ** It is not safe to pass a result table directly to [sqlite3_free()]. ** A result table should be deallocated using [sqlite3_free_table()]. ** ** ^(As an example of the result table format, suppose a query result ** is as follows: ** **
**        Name        | Age
**        -----------------------
**        Alice       | 43
**        Bob         | 28
**        Cindy       | 21
** 
** ** There are two columns (M==2) and three rows (N==3). Thus the ** result table has 8 entries. Suppose the result table is stored ** in an array named azResult. Then azResult holds this content: ** **
**        azResult[0] = "Name";
**        azResult[1] = "Age";
**        azResult[2] = "Alice";
**        azResult[3] = "43";
**        azResult[4] = "Bob";
**        azResult[5] = "28";
**        azResult[6] = "Cindy";
**        azResult[7] = "21";
** 
)^ ** ** ^The sqlite3_get_table() function evaluates one or more ** semicolon-separated SQL statements in the zero-terminated UTF-8 ** string of its 2nd parameter and returns a result table to the ** pointer given in its 3rd parameter. ** ** After the application has finished with the result from sqlite3_get_table(), ** it must pass the result table pointer to sqlite3_free_table() in order to ** release the memory that was malloced. Because of the way the ** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling ** function must not try to call [sqlite3_free()] directly. Only ** [sqlite3_free_table()] is able to release the memory properly and safely. ** ** The sqlite3_get_table() interface is implemented as a wrapper around ** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access ** to any internal data structures of SQLite. It uses only the public ** interface defined here. As a consequence, errors that occur in the ** wrapper layer outside of the internal [sqlite3_exec()] call are not ** reflected in subsequent calls to [sqlite3_errcode()] or ** [sqlite3_errmsg()]. */ SQLITE_API int sqlite3_get_table( sqlite3 *db, /* An open database */ const char *zSql, /* SQL to be evaluated */ char ***pazResult, /* Results of the query */ int *pnRow, /* Number of result rows written here */ int *pnColumn, /* Number of result columns written here */ char **pzErrmsg /* Error msg written here */ ); SQLITE_API void sqlite3_free_table(char **result); /* ** CAPI3REF: Formatted String Printing Functions ** ** These routines are work-alikes of the "printf()" family of functions ** from the standard C library. ** These routines understand most of the common formatting options from ** the standard library printf() ** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]). ** See the [built-in printf()] documentation for details. ** ** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their ** results into memory obtained from [sqlite3_malloc64()]. ** The strings returned by these two routines should be ** released by [sqlite3_free()]. ^Both routines return a ** NULL pointer if [sqlite3_malloc64()] is unable to allocate enough ** memory to hold the resulting string. ** ** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from ** the standard C library. The result is written into the ** buffer supplied as the second parameter whose size is given by ** the first parameter. Note that the order of the ** first two parameters is reversed from snprintf().)^ This is an ** historical accident that cannot be fixed without breaking ** backwards compatibility. ^(Note also that sqlite3_snprintf() ** returns a pointer to its buffer instead of the number of ** characters actually written into the buffer.)^ We admit that ** the number of characters written would be a more useful return ** value but we cannot change the implementation of sqlite3_snprintf() ** now without breaking compatibility. ** ** ^As long as the buffer size is greater than zero, sqlite3_snprintf() ** guarantees that the buffer is always zero-terminated. ^The first ** parameter "n" is the total size of the buffer, including space for ** the zero terminator. So the longest string that can be completely ** written will be n-1 characters. ** ** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf(). ** ** See also: [built-in printf()], [printf() SQL function] */ SQLITE_API char *sqlite3_mprintf(const char*,...); SQLITE_API char *sqlite3_vmprintf(const char*, va_list); SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...); SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); /* ** CAPI3REF: Memory Allocation Subsystem ** ** The SQLite core uses these three routines for all of its own ** internal memory allocation needs. "Core" in the previous sentence ** does not include operating-system specific [VFS] implementation. The ** Windows VFS uses native malloc() and free() for some operations. ** ** ^The sqlite3_malloc() routine returns a pointer to a block ** of memory at least N bytes in length, where N is the parameter. ** ^If sqlite3_malloc() is unable to obtain sufficient free ** memory, it returns a NULL pointer. ^If the parameter N to ** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns ** a NULL pointer. ** ** ^The sqlite3_malloc64(N) routine works just like ** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead ** of a signed 32-bit integer. ** ** ^Calling sqlite3_free() with a pointer previously returned ** by sqlite3_malloc() or sqlite3_realloc() releases that memory so ** that it might be reused. ^The sqlite3_free() routine is ** a no-op if is called with a NULL pointer. Passing a NULL pointer ** to sqlite3_free() is harmless. After being freed, memory ** should neither be read nor written. Even reading previously freed ** memory might result in a segmentation fault or other severe error. ** Memory corruption, a segmentation fault, or other severe error ** might result if sqlite3_free() is called with a non-NULL pointer that ** was not obtained from sqlite3_malloc() or sqlite3_realloc(). ** ** ^The sqlite3_realloc(X,N) interface attempts to resize a ** prior memory allocation X to be at least N bytes. ** ^If the X parameter to sqlite3_realloc(X,N) ** is a NULL pointer then its behavior is identical to calling ** sqlite3_malloc(N). ** ^If the N parameter to sqlite3_realloc(X,N) is zero or ** negative then the behavior is exactly the same as calling ** sqlite3_free(X). ** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation ** of at least N bytes in size or NULL if insufficient memory is available. ** ^If M is the size of the prior allocation, then min(N,M) bytes ** of the prior allocation are copied into the beginning of buffer returned ** by sqlite3_realloc(X,N) and the prior allocation is freed. ** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the ** prior allocation is not freed. ** ** ^The sqlite3_realloc64(X,N) interfaces works the same as ** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead ** of a 32-bit signed integer. ** ** ^If X is a memory allocation previously obtained from sqlite3_malloc(), ** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then ** sqlite3_msize(X) returns the size of that memory allocation in bytes. ** ^The value returned by sqlite3_msize(X) might be larger than the number ** of bytes requested when X was allocated. ^If X is a NULL pointer then ** sqlite3_msize(X) returns zero. If X points to something that is not ** the beginning of memory allocation, or if it points to a formerly ** valid memory allocation that has now been freed, then the behavior ** of sqlite3_msize(X) is undefined and possibly harmful. ** ** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(), ** sqlite3_malloc64(), and sqlite3_realloc64() ** is always aligned to at least an 8 byte boundary, or to a ** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time ** option is used. ** ** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] ** must be either NULL or else pointers obtained from a prior ** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have ** not yet been released. ** ** The application must not read or write any part of ** a block of memory after it has been released using ** [sqlite3_free()] or [sqlite3_realloc()]. */ SQLITE_API void *sqlite3_malloc(int); SQLITE_API void *sqlite3_malloc64(sqlite3_uint64); SQLITE_API void *sqlite3_realloc(void*, int); SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64); SQLITE_API void sqlite3_free(void*); SQLITE_API sqlite3_uint64 sqlite3_msize(void*); /* ** CAPI3REF: Memory Allocator Statistics ** ** SQLite provides these two interfaces for reporting on the status ** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()] ** routines, which form the built-in memory allocation subsystem. ** ** ^The [sqlite3_memory_used()] routine returns the number of bytes ** of memory currently outstanding (malloced but not freed). ** ^The [sqlite3_memory_highwater()] routine returns the maximum ** value of [sqlite3_memory_used()] since the high-water mark ** was last reset. ^The values returned by [sqlite3_memory_used()] and ** [sqlite3_memory_highwater()] include any overhead ** added by SQLite in its implementation of [sqlite3_malloc()], ** but not overhead added by the any underlying system library ** routines that [sqlite3_malloc()] may call. ** ** ^The memory high-water mark is reset to the current value of ** [sqlite3_memory_used()] if and only if the parameter to ** [sqlite3_memory_highwater()] is true. ^The value returned ** by [sqlite3_memory_highwater(1)] is the high-water mark ** prior to the reset. */ SQLITE_API sqlite3_int64 sqlite3_memory_used(void); SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); /* ** CAPI3REF: Pseudo-Random Number Generator ** ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to ** select random [ROWID | ROWIDs] when inserting new records into a table that ** already uses the largest possible [ROWID]. The PRNG is also used for ** the built-in random() and randomblob() SQL functions. This interface allows ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. ** ^The P parameter can be a NULL pointer. ** ** ^If this routine has not been previously called or if the previous ** call had N less than one or a NULL pointer for P, then the PRNG is ** seeded using randomness obtained from the xRandomness method of ** the default [sqlite3_vfs] object. ** ^If the previous call to this routine had an N of 1 or more and a ** non-NULL P then the pseudo-randomness is generated ** internally and without recourse to the [sqlite3_vfs] xRandomness ** method. */ SQLITE_API void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks ** METHOD: sqlite3 ** KEYWORDS: {authorizer callback} ** ** ^This routine registers an authorizer callback with a particular ** [database connection], supplied in the first argument. ** ^The authorizer callback is invoked as SQL statements are being compiled ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], ** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()], ** and [sqlite3_prepare16_v3()]. ^At various ** points during the compilation process, as logic is being created ** to perform various actions, the authorizer callback is invoked to ** see if those actions are allowed. ^The authorizer callback should ** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the ** specific action but allow the SQL statement to continue to be ** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be ** rejected with an error. ^If the authorizer callback returns ** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY] ** then the [sqlite3_prepare_v2()] or equivalent call that triggered ** the authorizer will fail with an error message. ** ** When the callback returns [SQLITE_OK], that means the operation ** requested is ok. ^When the callback returns [SQLITE_DENY], the ** [sqlite3_prepare_v2()] or equivalent call that triggered the ** authorizer will fail with an error message explaining that ** access is denied. ** ** ^The first parameter to the authorizer callback is a copy of the third ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter ** to the callback is an integer [SQLITE_COPY | action code] that specifies ** the particular action to be authorized. ^The third through sixth parameters ** to the callback are either NULL pointers or zero-terminated strings ** that contain additional details about the action to be authorized. ** Applications must always be prepared to encounter a NULL pointer in any ** of the third through the sixth parameters of the authorization callback. ** ** ^If the action code is [SQLITE_READ] ** and the callback returns [SQLITE_IGNORE] then the ** [prepared statement] statement is constructed to substitute ** a NULL value in place of the table column that would have ** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] ** return can be used to deny an untrusted user access to individual ** columns of a table. ** ^When a table is referenced by a [SELECT] but no column values are ** extracted from that table (for example in a query like ** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback ** is invoked once for that table with a column name that is an empty string. ** ^If the action code is [SQLITE_DELETE] and the callback returns ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the ** [truncate optimization] is disabled and all rows are deleted individually. ** ** An authorizer is used when [sqlite3_prepare | preparing] ** SQL statements from an untrusted source, to ensure that the SQL statements ** do not try to access data they are not allowed to see, or that they do not ** try to execute malicious statements that damage the database. For ** example, an application may allow a user to enter arbitrary ** SQL queries for evaluation by a database. But the application does ** not want the user to be able to make arbitrary changes to the ** database. An authorizer could then be put in place while the ** user-entered SQL is being [sqlite3_prepare | prepared] that ** disallows everything except [SELECT] statements. ** ** Applications that need to process SQL from untrusted sources ** might also consider lowering resource limits using [sqlite3_limit()] ** and limiting database size using the [max_page_count] [PRAGMA] ** in addition to using an authorizer. ** ** ^(Only a single authorizer can be in place on a database connection ** at a time. Each call to sqlite3_set_authorizer overrides the ** previous call.)^ ^Disable the authorizer by installing a NULL callback. ** The authorizer is disabled by default. ** ** The authorizer callback must not do anything that will modify ** the database connection that invoked the authorizer callback. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** ** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the ** statement might be re-prepared during [sqlite3_step()] due to a ** schema change. Hence, the application should ensure that the ** correct authorizer callback remains in place during the [sqlite3_step()]. ** ** ^Note that the authorizer callback is invoked only during ** [sqlite3_prepare()] or its variants. Authorization is not ** performed during statement evaluation in [sqlite3_step()], unless ** as stated in the previous paragraph, sqlite3_step() invokes ** sqlite3_prepare_v2() to reprepare a statement after a schema change. */ SQLITE_API int sqlite3_set_authorizer( sqlite3*, int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pUserData ); /* ** CAPI3REF: Authorizer Return Codes ** ** The [sqlite3_set_authorizer | authorizer callback function] must ** return either [SQLITE_OK] or one of these two constants in order ** to signal SQLite whether or not the action is permitted. See the ** [sqlite3_set_authorizer | authorizer documentation] for additional ** information. ** ** Note that SQLITE_IGNORE is also used as a [conflict resolution mode] ** returned from the [sqlite3_vtab_on_conflict()] interface. */ #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ /* ** CAPI3REF: Authorizer Action Codes ** ** The [sqlite3_set_authorizer()] interface registers a callback function ** that is invoked to authorize certain SQL statement actions. The ** second parameter to the callback is an integer code that specifies ** what action is being authorized. These are the integer action codes that ** the authorizer callback may be passed. ** ** These action code values signify what kind of operation is to be ** authorized. The 3rd and 4th parameters to the authorization ** callback function will be parameters or NULL depending on which of these ** codes is used as the second parameter. ^(The 5th parameter to the ** authorizer callback is the name of the database ("main", "temp", ** etc.) if applicable.)^ ^The 6th parameter to the authorizer callback ** is the name of the inner-most trigger or view that is responsible for ** the access attempt or NULL if this access attempt is directly from ** top-level SQL code. */ /******************************************* 3rd ************ 4th ***********/ #define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ #define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ #define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ #define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ #define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ #define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ #define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ #define SQLITE_CREATE_VIEW 8 /* View Name NULL */ #define SQLITE_DELETE 9 /* Table Name NULL */ #define SQLITE_DROP_INDEX 10 /* Index Name Table Name */ #define SQLITE_DROP_TABLE 11 /* Table Name NULL */ #define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */ #define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */ #define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */ #define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */ #define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */ #define SQLITE_DROP_VIEW 17 /* View Name NULL */ #define SQLITE_INSERT 18 /* Table Name NULL */ #define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */ #define SQLITE_READ 20 /* Table Name Column Name */ #define SQLITE_SELECT 21 /* NULL NULL */ #define SQLITE_TRANSACTION 22 /* Operation NULL */ #define SQLITE_UPDATE 23 /* Table Name Column Name */ #define SQLITE_ATTACH 24 /* Filename NULL */ #define SQLITE_DETACH 25 /* Database Name NULL */ #define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ #define SQLITE_REINDEX 27 /* Index Name NULL */ #define SQLITE_ANALYZE 28 /* Table Name NULL */ #define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ #define SQLITE_FUNCTION 31 /* NULL Function Name */ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ #define SQLITE_COPY 0 /* No longer used */ #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* ** CAPI3REF: Tracing And Profiling Functions ** METHOD: sqlite3 ** ** These routines are deprecated. Use the [sqlite3_trace_v2()] interface ** instead of the routines described here. ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** ** ^The callback function registered by sqlite3_trace() is invoked at ** various times when an SQL statement is being run by [sqlite3_step()]. ** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the ** SQL statement text as the statement first begins executing. ** ^(Additional sqlite3_trace() callbacks might occur ** as each triggered subprogram is entered. The callbacks for triggers ** contain a UTF-8 SQL comment that identifies the trigger.)^ ** ** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit ** the length of [bound parameter] expansion in the output of sqlite3_trace(). ** ** ^The callback function registered by sqlite3_profile() is invoked ** as each SQL statement finishes. ^The profile callback contains ** the original statement text and an estimate of wall-clock time ** of how long that statement took to run. ^The profile callback ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite ** might provide greater resolution on the profiler callback. Invoking ** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the ** profile callback. */ SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, void(*xProfile)(void*,const char*,sqlite3_uint64), void*); /* ** CAPI3REF: SQL Trace Event Codes ** KEYWORDS: SQLITE_TRACE ** ** These constants identify classes of events that can be monitored ** using the [sqlite3_trace_v2()] tracing logic. The M argument ** to [sqlite3_trace_v2(D,M,X,P)] is an OR-ed combination of one or more of ** the following constants. ^The first argument to the trace callback ** is one of the following constants. ** ** New tracing constants may be added in future releases. ** ** ^A trace callback has four arguments: xCallback(T,C,P,X). ** ^The T argument is one of the integer type codes above. ** ^The C argument is a copy of the context pointer passed in as the ** fourth argument to [sqlite3_trace_v2()]. ** The P and X arguments are pointers whose meanings depend on T. ** **
** [[SQLITE_TRACE_STMT]]
SQLITE_TRACE_STMT
**
^An SQLITE_TRACE_STMT callback is invoked when a prepared statement ** first begins running and possibly at other times during the ** execution of the prepared statement, such as at the start of each ** trigger subprogram. ^The P argument is a pointer to the ** [prepared statement]. ^The X argument is a pointer to a string which ** is the unexpanded SQL text of the prepared statement or an SQL comment ** that indicates the invocation of a trigger. ^The callback can compute ** the same text that would have been returned by the legacy [sqlite3_trace()] ** interface by using the X argument when X begins with "--" and invoking ** [sqlite3_expanded_sql(P)] otherwise. ** ** [[SQLITE_TRACE_PROFILE]]
SQLITE_TRACE_PROFILE
**
^An SQLITE_TRACE_PROFILE callback provides approximately the same ** information as is provided by the [sqlite3_profile()] callback. ** ^The P argument is a pointer to the [prepared statement] and the ** X argument points to a 64-bit integer which is approximately ** the number of nanoseconds that the prepared statement took to run. ** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. ** ** [[SQLITE_TRACE_ROW]]
SQLITE_TRACE_ROW
**
^An SQLITE_TRACE_ROW callback is invoked whenever a prepared ** statement generates a single row of result. ** ^The P argument is a pointer to the [prepared statement] and the ** X argument is unused. ** ** [[SQLITE_TRACE_CLOSE]]
SQLITE_TRACE_CLOSE
**
^An SQLITE_TRACE_CLOSE callback is invoked when a database ** connection closes. ** ^The P argument is a pointer to the [database connection] object ** and the X argument is unused. **
*/ #define SQLITE_TRACE_STMT 0x01 #define SQLITE_TRACE_PROFILE 0x02 #define SQLITE_TRACE_ROW 0x04 #define SQLITE_TRACE_CLOSE 0x08 /* ** CAPI3REF: SQL Trace Hook ** METHOD: sqlite3 ** ** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback ** function X against [database connection] D, using property mask M ** and context pointer P. ^If the X callback is ** NULL or if the M mask is zero, then tracing is disabled. The ** M argument should be the bitwise OR-ed combination of ** zero or more [SQLITE_TRACE] constants. ** ** ^Each call to either sqlite3_trace(D,X,P) or sqlite3_trace_v2(D,M,X,P) ** overrides (cancels) all prior calls to sqlite3_trace(D,X,P) or ** sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each ** database connection may have at most one trace callback. ** ** ^The X callback is invoked whenever any of the events identified by ** mask M occur. ^The integer return value from the callback is currently ** ignored, though this may change in future releases. Callback ** implementations should return zero to ensure future compatibility. ** ** ^A trace callback is invoked with four arguments: callback(T,C,P,X). ** ^The T argument is one of the [SQLITE_TRACE] ** constants to indicate why the callback was invoked. ** ^The C argument is a copy of the context pointer. ** The P and X arguments are pointers whose meanings depend on T. ** ** The sqlite3_trace_v2() interface is intended to replace the legacy ** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which ** are deprecated. */ SQLITE_API int sqlite3_trace_v2( sqlite3*, unsigned uMask, int(*xCallback)(unsigned,void*,void*,void*), void *pCtx ); /* ** CAPI3REF: Query Progress Callbacks ** METHOD: sqlite3 ** ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to ** [sqlite3_step()] and [sqlite3_prepare()] and similar for ** database connection D. An example use for this ** interface is to keep a GUI updated during a large query. ** ** ^The parameter P is passed through as the only parameter to the ** callback function X. ^The parameter N is the approximate number of ** [virtual machine instructions] that are evaluated between successive ** invocations of the callback X. ^If N is less than one then the progress ** handler is disabled. ** ** ^Only a single progress handler may be defined at one time per ** [database connection]; setting a new progress handler cancels the ** old one. ^Setting parameter X to NULL disables the progress handler. ** ^The progress handler is also disabled by setting N to a value less ** than 1. ** ** ^If the progress callback returns non-zero, the operation is ** interrupted. This feature can be used to implement a ** "Cancel" button on a GUI progress dialog box. ** ** The progress handler callback must not do anything that will modify ** the database connection that invoked the progress handler. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** ** The progress handler callback would originally only be invoked from the ** bytecode engine. It still might be invoked during [sqlite3_prepare()] ** and similar because those routines might force a reparse of the schema ** which involves running the bytecode engine. However, beginning with ** SQLite version 3.41.0, the progress handler callback might also be ** invoked directly from [sqlite3_prepare()] while analyzing and generating ** code for complex queries. */ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); /* ** CAPI3REF: Opening A New Database Connection ** CONSTRUCTOR: sqlite3 ** ** ^These routines open an SQLite database file as specified by the ** filename argument. ^The filename argument is interpreted as UTF-8 for ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte ** order for sqlite3_open16(). ^(A [database connection] handle is usually ** returned in *ppDb, even if an error occurs. The only exception is that ** if SQLite is unable to allocate memory to hold the [sqlite3] object, ** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] ** object.)^ ^(If the database is opened (and/or created) successfully, then ** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The ** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain ** an English language description of the error following a failure of any ** of the sqlite3_open() routines. ** ** ^The default encoding will be UTF-8 for databases created using ** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases ** created using sqlite3_open16() will be UTF-16 in the native byte order. ** ** Whether or not an error occurs when it is opened, resources ** associated with the [database connection] handle should be released by ** passing it to [sqlite3_close()] when it is no longer required. ** ** The sqlite3_open_v2() interface works like sqlite3_open() ** except that it accepts two additional parameters for additional control ** over the new database connection. ^(The flags parameter to ** sqlite3_open_v2() must include, at a minimum, one of the following ** three flag combinations:)^ ** **
** ^(
[SQLITE_OPEN_READONLY]
**
The database is opened in read-only mode. If the database does ** not already exist, an error is returned.
)^ ** ** ^(
[SQLITE_OPEN_READWRITE]
**
The database is opened for reading and writing if possible, or ** reading only if the file is write protected by the operating ** system. In either case the database must already exist, otherwise ** an error is returned. For historical reasons, if opening in ** read-write mode fails due to OS-level permissions, an attempt is ** made to open it in read-only mode. [sqlite3_db_readonly()] can be ** used to determine whether the database is actually ** read-write.
)^ ** ** ^(
[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
**
The database is opened for reading and writing, and is created if ** it does not already exist. This is the behavior that is always used for ** sqlite3_open() and sqlite3_open16().
)^ **
** ** In addition to the required flags, the following optional flags are ** also supported: ** **
** ^(
[SQLITE_OPEN_URI]
**
The filename can be interpreted as a URI if this flag is set.
)^ ** ** ^(
[SQLITE_OPEN_MEMORY]
**
The database will be opened as an in-memory database. The database ** is named by the "filename" argument for the purposes of cache-sharing, ** if shared cache mode is enabled, but the "filename" is otherwise ignored. **
)^ ** ** ^(
[SQLITE_OPEN_NOMUTEX]
**
The new database connection will use the "multi-thread" ** [threading mode].)^ This means that separate threads are allowed ** to use SQLite at the same time, as long as each thread is using ** a different [database connection]. ** ** ^(
[SQLITE_OPEN_FULLMUTEX]
**
The new database connection will use the "serialized" ** [threading mode].)^ This means the multiple threads can safely ** attempt to use the same database connection at the same time. ** (Mutexes will block any actual concurrency, but in this mode ** there is no harm in trying.) ** ** ^(
[SQLITE_OPEN_SHAREDCACHE]
**
The database is opened [shared cache] enabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** The [use of shared cache mode is discouraged] and hence shared cache ** capabilities may be omitted from many builds of SQLite. In such cases, ** this option is a no-op. ** ** ^(
[SQLITE_OPEN_PRIVATECACHE]
**
The database is opened [shared cache] disabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** ** [[OPEN_EXRESCODE]] ^(
[SQLITE_OPEN_EXRESCODE]
**
The database connection comes up in "extended result code mode". ** In other words, the database behaves has if ** [sqlite3_extended_result_codes(db,1)] where called on the database ** connection as soon as the connection is created. In addition to setting ** the extended result code mode, this flag also causes [sqlite3_open_v2()] ** to return an extended result code.
** ** [[OPEN_NOFOLLOW]] ^(
[SQLITE_OPEN_NOFOLLOW]
**
The database filename is not allowed to contain a symbolic link
**
)^ ** ** If the 3rd parameter to sqlite3_open_v2() is not one of the ** required combinations shown above optionally combined with other ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] ** then the behavior is undefined. Historic versions of SQLite ** have silently ignored surplus bits in the flags parameter to ** sqlite3_open_v2(), however that behavior might not be carried through ** into future versions of SQLite and so applications should not rely ** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op ** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause ** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE ** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not ** by sqlite3_open_v2(). ** ** ^The fourth parameter to sqlite3_open_v2() is the name of the ** [sqlite3_vfs] object that defines the operating system interface that ** the new database connection should use. ^If the fourth parameter is ** a NULL pointer then the default [sqlite3_vfs] object is used. ** ** ^If the filename is ":memory:", then a private, temporary in-memory database ** is created for the connection. ^This in-memory database will vanish when ** the database connection is closed. Future versions of SQLite might ** make use of additional special filenames that begin with the ":" character. ** It is recommended that when a database filename actually does begin with ** a ":" character you should prefix the filename with a pathname such as ** "./" to avoid ambiguity. ** ** ^If the filename is an empty string, then a private, temporary ** on-disk database will be created. ^This private database will be ** automatically deleted as soon as the database connection is closed. ** ** [[URI filenames in sqlite3_open()]]

URI Filenames

** ** ^If [URI filename] interpretation is enabled, and the filename argument ** begins with "file:", then the filename is interpreted as a URI. ^URI ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is ** set in the third argument to sqlite3_open_v2(), or if it has ** been enabled globally using the [SQLITE_CONFIG_URI] option with the ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. ** URI filename interpretation is turned off ** by default, but future releases of SQLite might enable URI filename ** interpretation by default. See "[URI filenames]" for additional ** information. ** ** URI filenames are parsed according to RFC 3986. ^If the URI contains an ** authority, then it must be either an empty string or the string ** "localhost". ^If the authority is not an empty string or "localhost", an ** error is returned to the caller. ^The fragment component of a URI, if ** present, is ignored. ** ** ^SQLite uses the path component of the URI as the name of the disk file ** which contains the database. ^If the path begins with a '/' character, ** then it is interpreted as an absolute path. ^If the path does not begin ** with a '/' (meaning that the authority section is omitted from the URI) ** then the path is interpreted as a relative path. ** ^(On windows, the first component of an absolute path ** is a drive specification (e.g. "C:").)^ ** ** [[core URI query parameters]] ** The query component of a URI may contain parameters that are interpreted ** either by SQLite itself, or by a [VFS | custom VFS implementation]. ** SQLite and its built-in [VFSes] interpret the ** following query parameters: ** **
    **
  • vfs: ^The "vfs" parameter may be used to specify the name of ** a VFS object that provides the operating system interface that should ** be used to access the database file on disk. ^If this option is set to ** an empty string the default VFS object is used. ^Specifying an unknown ** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is ** present, then the VFS specified by the option takes precedence over ** the value passed as the fourth parameter to sqlite3_open_v2(). ** **
  • mode: ^(The mode parameter may be set to either "ro", "rw", ** "rwc", or "memory". Attempting to set it to any other value is ** an error)^. ** ^If "ro" is specified, then the database is opened for read-only ** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the ** third argument to sqlite3_open_v2(). ^If the mode option is set to ** "rw", then the database is opened for read-write (but not create) ** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had ** been set. ^Value "rwc" is equivalent to setting both ** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If the mode option is ** set to "memory" then a pure [in-memory database] that never reads ** or writes from disk is used. ^It is an error to specify a value for ** the mode parameter that is less restrictive than that specified by ** the flags passed in the third parameter to sqlite3_open_v2(). ** **
  • cache: ^The cache parameter may be set to either "shared" or ** "private". ^Setting it to "shared" is equivalent to setting the ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** **
  • psow: ^The psow parameter indicates whether or not the ** [powersafe overwrite] property does or does not apply to the ** storage media on which the database file resides. ** **
  • nolock: ^The nolock parameter is a boolean query parameter ** which if set disables file locking in rollback journal modes. This ** is useful for accessing a database on a filesystem that does not ** support locking. Caution: Database corruption might result if two ** or more processes write to the same database and any one of those ** processes uses nolock=1. ** **
  • immutable: ^The immutable parameter is a boolean query ** parameter that indicates that the database file is stored on ** read-only media. ^When immutable is set, SQLite assumes that the ** database file cannot be changed, even by a process with higher ** privilege, and so the database is opened read-only and all locking ** and change detection is disabled. Caution: Setting the immutable ** property on a database file that does in fact change can result ** in incorrect query results and/or [SQLITE_CORRUPT] errors. ** See also: [SQLITE_IOCAP_IMMUTABLE]. ** **
** ** ^Specifying an unknown parameter in the query component of a URI is not an ** error. Future versions of SQLite might understand additional query ** parameters. See "[query parameters with special meaning to SQLite]" for ** additional information. ** ** [[URI filename examples]]

URI filename examples

** ** **
URI filenames Results **
file:data.db ** Open the file "data.db" in the current directory. **
file:/home/fred/data.db
** file:///home/fred/data.db
** file://localhost/home/fred/data.db
** Open the database file "/home/fred/data.db". **
file://darkstar/home/fred/data.db ** An error. "darkstar" is not a recognized authority. **
** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db ** Windows only: Open the file "data.db" on fred's desktop on drive ** C:. Note that the %20 escaping in this example is not strictly ** necessary - space characters can be used literally ** in URI filenames. **
file:data.db?mode=ro&cache=private ** Open file "data.db" in the current directory for read-only access. ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. **
file:/home/fred/data.db?vfs=unix-dotfile ** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" ** that uses dot-files in place of posix advisory locking. **
file:data.db?mode=readonly ** An error. "readonly" is not a valid option for the "mode" parameter. ** Use "ro" instead: "file:data.db?mode=ro". **
** ** ^URI hexadecimal escape sequences (%HH) are supported within the path and ** query components of a URI. A hexadecimal escape sequence consists of a ** percent sign - "%" - followed by exactly two hexadecimal digits ** specifying an octet value. ^Before the path or query components of a ** URI filename are interpreted, they are encoded using UTF-8 and all ** hexadecimal escape sequences replaced by a single byte containing the ** corresponding octet. If this process generates an invalid UTF-8 encoding, ** the results are undefined. ** ** Note to Windows users: The encoding used for the filename argument ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever ** codepage is currently defined. Filenames containing international ** characters must be converted to UTF-8 prior to passing them into ** sqlite3_open() or sqlite3_open_v2(). ** ** Note to Windows Runtime users: The temporary directory must be set ** prior to calling sqlite3_open() or sqlite3_open_v2(). Otherwise, various ** features that require the use of temporary files may fail. ** ** See also: [sqlite3_temp_directory] */ SQLITE_API int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); SQLITE_API int sqlite3_open16( const void *filename, /* Database filename (UTF-16) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); SQLITE_API int sqlite3_open_v2( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb, /* OUT: SQLite db handle */ int flags, /* Flags */ const char *zVfs /* Name of VFS module to use */ ); /* ** CAPI3REF: Obtain Values For URI Parameters ** ** These are utility routines, useful to [VFS|custom VFS implementations], ** that check if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** ** The first parameter to these interfaces (hereafter referred to ** as F) must be one of: **
    **
  • A database filename pointer created by the SQLite core and ** passed into the xOpen() method of a VFS implementation, or **
  • A filename obtained from [sqlite3_db_filename()], or **
  • A new filename constructed using [sqlite3_create_filename()]. **
** If the F parameter is not one of the above, then the behavior is ** undefined and probably undesirable. Older versions of SQLite were ** more tolerant of invalid F parameters than newer versions. ** ** If F is a suitable filename (as described in the previous paragraph) ** and if P is the name of the query parameter, then ** sqlite3_uri_parameter(F,P) returns the value of the P ** parameter if it exists or a NULL pointer if P does not appear as a ** query parameter on F. If P is a query parameter of F and it ** has no explicit value, then sqlite3_uri_parameter(F,P) returns ** a pointer to an empty string. ** ** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean ** parameter and returns true (1) or false (0) according to the value ** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the ** value of query parameter P is one of "yes", "true", or "on" in any ** case or if the value begins with a non-zero number. The ** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of ** query parameter P is one of "no", "false", or "off" in any case or ** if the value begins with a numeric zero. If P is not a query ** parameter on F or if the value of P does not match any of the ** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). ** ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a ** 64-bit signed integer and returns that integer, or D if P does not ** exist. If the value of P is something other than an integer, then ** zero is returned. ** ** The sqlite3_uri_key(F,N) returns a pointer to the name (not ** the value) of the N-th query parameter for filename F, or a NULL ** pointer if N is less than zero or greater than the number of query ** parameters minus 1. The N value is zero-based so N should be 0 to obtain ** the name of the first query parameter, 1 for the second parameter, and ** so forth. ** ** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and ** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and ** is not a database file pathname pointer that the SQLite core passed ** into the xOpen VFS method, then the behavior of this routine is undefined ** and probably undesirable. ** ** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F ** parameter can also be the name of a rollback journal file or WAL file ** in addition to the main database file. Prior to version 3.31.0, these ** routines would only work if F was the name of the main database file. ** When the F parameter is the name of the rollback journal or WAL file, ** it has access to all the same query parameters as were found on the ** main database file. ** ** See the [URI filename] documentation for additional information. */ SQLITE_API const char *sqlite3_uri_parameter(sqlite3_filename z, const char *zParam); SQLITE_API int sqlite3_uri_boolean(sqlite3_filename z, const char *zParam, int bDefault); SQLITE_API sqlite3_int64 sqlite3_uri_int64(sqlite3_filename, const char*, sqlite3_int64); SQLITE_API const char *sqlite3_uri_key(sqlite3_filename z, int N); /* ** CAPI3REF: Translate filenames ** ** These routines are available to [VFS|custom VFS implementations] for ** translating filenames between the main database file, the journal file, ** and the WAL file. ** ** If F is the name of an sqlite database file, journal file, or WAL file ** passed by the SQLite core into the VFS, then sqlite3_filename_database(F) ** returns the name of the corresponding database file. ** ** If F is the name of an sqlite database file, journal file, or WAL file ** passed by the SQLite core into the VFS, or if F is a database filename ** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F) ** returns the name of the corresponding rollback journal file. ** ** If F is the name of an sqlite database file, journal file, or WAL file ** that was passed by the SQLite core into the VFS, or if F is a database ** filename obtained from [sqlite3_db_filename()], then ** sqlite3_filename_wal(F) returns the name of the corresponding ** WAL file. ** ** In all of the above, if F is not the name of a database, journal or WAL ** filename passed into the VFS from the SQLite core and F is not the ** return value from [sqlite3_db_filename()], then the result is ** undefined and is likely a memory access violation. */ SQLITE_API const char *sqlite3_filename_database(sqlite3_filename); SQLITE_API const char *sqlite3_filename_journal(sqlite3_filename); SQLITE_API const char *sqlite3_filename_wal(sqlite3_filename); /* ** CAPI3REF: Database File Corresponding To A Journal ** ** ^If X is the name of a rollback or WAL-mode journal file that is ** passed into the xOpen method of [sqlite3_vfs], then ** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file] ** object that represents the main database file. ** ** This routine is intended for use in custom [VFS] implementations ** only. It is not a general-purpose interface. ** The argument sqlite3_file_object(X) must be a filename pointer that ** has been passed into [sqlite3_vfs].xOpen method where the ** flags parameter to xOpen contains one of the bits ** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use ** of this routine results in undefined and probably undesirable ** behavior. */ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); /* ** CAPI3REF: Create and Destroy VFS Filenames ** ** These interfaces are provided for use by [VFS shim] implementations and ** are not useful outside of that context. ** ** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of ** database filename D with corresponding journal file J and WAL file W and ** with N URI parameters key/values pairs in the array P. The result from ** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that ** is safe to pass to routines like: **
    **
  • [sqlite3_uri_parameter()], **
  • [sqlite3_uri_boolean()], **
  • [sqlite3_uri_int64()], **
  • [sqlite3_uri_key()], **
  • [sqlite3_filename_database()], **
  • [sqlite3_filename_journal()], or **
  • [sqlite3_filename_wal()]. **
** If a memory allocation error occurs, sqlite3_create_filename() might ** return a NULL pointer. The memory obtained from sqlite3_create_filename(X) ** must be released by a corresponding call to sqlite3_free_filename(Y). ** ** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array ** of 2*N pointers to strings. Each pair of pointers in this array corresponds ** to a key and value for a query parameter. The P parameter may be a NULL ** pointer if N is zero. None of the 2*N pointers in the P array may be ** NULL pointers and key pointers should not be empty strings. ** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may ** be NULL pointers, though they can be empty strings. ** ** The sqlite3_free_filename(Y) routine releases a memory allocation ** previously obtained from sqlite3_create_filename(). Invoking ** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op. ** ** If the Y parameter to sqlite3_free_filename(Y) is anything other ** than a NULL pointer or a pointer previously acquired from ** sqlite3_create_filename(), then bad things such as heap ** corruption or segfaults may occur. The value Y should not be ** used again after sqlite3_free_filename(Y) has been called. This means ** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y, ** then the corresponding [sqlite3_module.xClose() method should also be ** invoked prior to calling sqlite3_free_filename(Y). */ SQLITE_API sqlite3_filename sqlite3_create_filename( const char *zDatabase, const char *zJournal, const char *zWal, int nParam, const char **azParam ); SQLITE_API void sqlite3_free_filename(sqlite3_filename); /* ** CAPI3REF: Error Codes And Messages ** METHOD: sqlite3 ** ** ^If the most recent sqlite3_* API call associated with ** [database connection] D failed, then the sqlite3_errcode(D) interface ** returns the numeric [result code] or [extended result code] for that ** API call. ** ^The sqlite3_extended_errcode() ** interface is the same except that it always returns the ** [extended result code] even when extended result codes are ** disabled. ** ** The values returned by sqlite3_errcode() and/or ** sqlite3_extended_errcode() might change with each API call. ** Except, there are some interfaces that are guaranteed to never ** change the value of the error code. The error-code preserving ** interfaces include the following: ** **
    **
  • sqlite3_errcode() **
  • sqlite3_extended_errcode() **
  • sqlite3_errmsg() **
  • sqlite3_errmsg16() **
  • sqlite3_error_offset() **
** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively, ** or NULL if no error message is available. ** (See how SQLite handles [invalid UTF] for exceptions to this rule.) ** ^(Memory to hold the error message string is managed internally. ** The application does not need to worry about freeing the result. ** However, the error string might be overwritten or deallocated by ** subsequent calls to other SQLite interface functions.)^ ** ** ^The sqlite3_errstr(E) interface returns the English-language text ** that describes the [result code] E, as UTF-8, or NULL if E is not an ** result code for which a text error message is available. ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. ** ** ^If the most recent error references a specific token in the input ** SQL, the sqlite3_error_offset() interface returns the byte offset ** of the start of that token. ^The byte offset returned by ** sqlite3_error_offset() assumes that the input SQL is UTF8. ** ^If the most recent error does not reference a specific token in the input ** SQL, then the sqlite3_error_offset() function returns -1. ** ** When the serialized [threading mode] is in use, it might be the ** case that a second error occurs on a separate thread in between ** the time of the first error and the call to these interfaces. ** When that happens, the second error will be reported since these ** interfaces always report the most recent result. To avoid ** this, each thread can obtain exclusive use of the [database connection] D ** by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning ** to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after ** all calls to the interfaces listed here are completed. ** ** If an interface fails with SQLITE_MISUSE, that means the interface ** was invoked incorrectly by the application. In that case, the ** error code and message may or may not be set. */ SQLITE_API int sqlite3_errcode(sqlite3 *db); SQLITE_API int sqlite3_extended_errcode(sqlite3 *db); SQLITE_API const char *sqlite3_errmsg(sqlite3*); SQLITE_API const void *sqlite3_errmsg16(sqlite3*); SQLITE_API const char *sqlite3_errstr(int); SQLITE_API int sqlite3_error_offset(sqlite3 *db); /* ** CAPI3REF: Prepared Statement Object ** KEYWORDS: {prepared statement} {prepared statements} ** ** An instance of this object represents a single SQL statement that ** has been compiled into binary form and is ready to be evaluated. ** ** Think of each SQL statement as a separate computer program. The ** original SQL text is source code. A prepared statement object ** is the compiled object code. All SQL must be converted into a ** prepared statement before it can be run. ** ** The life-cycle of a prepared statement object usually goes like this: ** **
    **
  1. Create the prepared statement object using [sqlite3_prepare_v2()]. **
  2. Bind values to [parameters] using the sqlite3_bind_*() ** interfaces. **
  3. Run the SQL by calling [sqlite3_step()] one or more times. **
  4. Reset the prepared statement using [sqlite3_reset()] then go back ** to step 2. Do this zero or more times. **
  5. Destroy the object using [sqlite3_finalize()]. **
*/ typedef struct sqlite3_stmt sqlite3_stmt; /* ** CAPI3REF: Run-time Limits ** METHOD: sqlite3 ** ** ^(This interface allows the size of various constructs to be limited ** on a connection by connection basis. The first parameter is the ** [database connection] whose limit is to be set or queried. The ** second parameter is one of the [limit categories] that define a ** class of constructs to be size limited. The third parameter is the ** new limit for that construct.)^ ** ** ^If the new limit is a negative number, the limit is unchanged. ** ^(For each limit category SQLITE_LIMIT_NAME there is a ** [limits | hard upper bound] ** set at compile-time by a C preprocessor macro called ** [limits | SQLITE_MAX_NAME]. ** (The "_LIMIT_" in the name is changed to "_MAX_".))^ ** ^Attempts to increase a limit above its hard upper bound are ** silently truncated to the hard upper bound. ** ** ^Regardless of whether or not the limit was changed, the ** [sqlite3_limit()] interface returns the prior value of the limit. ** ^Hence, to find the current value of a limit without changing it, ** simply invoke this interface with the third parameter set to -1. ** ** Run-time limits are intended for use in applications that manage ** both their own internal database and also databases that are controlled ** by untrusted external sources. An example application might be a ** web browser that has its own databases for storing history and ** separate databases controlled by JavaScript applications downloaded ** off the Internet. The internal databases can be given the ** large, default limits. Databases managed by external sources can ** be given much smaller limits designed to prevent a denial of service ** attack. Developers might also want to use the [sqlite3_set_authorizer()] ** interface to further control untrusted SQL. The size of the database ** created by an untrusted script can be contained using the ** [max_page_count] [PRAGMA]. ** ** New run-time limit categories may be added in future releases. */ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); /* ** CAPI3REF: Run-Time Limit Categories ** KEYWORDS: {limit category} {*limit categories} ** ** These constants define various performance limits ** that can be lowered at run-time using [sqlite3_limit()]. ** The synopsis of the meanings of the various limits is shown below. ** Additional information is available at [limits | Limits in SQLite]. ** **
** [[SQLITE_LIMIT_LENGTH]] ^(
SQLITE_LIMIT_LENGTH
**
The maximum size of any string or BLOB or table row, in bytes.
)^ ** ** [[SQLITE_LIMIT_SQL_LENGTH]] ^(
SQLITE_LIMIT_SQL_LENGTH
**
The maximum length of an SQL statement, in bytes.
)^ ** ** [[SQLITE_LIMIT_COLUMN]] ^(
SQLITE_LIMIT_COLUMN
**
The maximum number of columns in a table definition or in the ** result set of a [SELECT] or the maximum number of columns in an index ** or in an ORDER BY or GROUP BY clause.
)^ ** ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
SQLITE_LIMIT_EXPR_DEPTH
**
The maximum depth of the parse tree on any expression.
)^ ** ** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
SQLITE_LIMIT_COMPOUND_SELECT
**
The maximum number of terms in a compound SELECT statement.
)^ ** ** [[SQLITE_LIMIT_VDBE_OP]] ^(
SQLITE_LIMIT_VDBE_OP
**
The maximum number of instructions in a virtual machine program ** used to implement an SQL statement. If [sqlite3_prepare_v2()] or ** the equivalent tries to allocate space for more than this many opcodes ** in a single prepared statement, an SQLITE_NOMEM error is returned.
)^ ** ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(
SQLITE_LIMIT_FUNCTION_ARG
**
The maximum number of arguments on a function.
)^ ** ** [[SQLITE_LIMIT_ATTACHED]] ^(
SQLITE_LIMIT_ATTACHED
**
The maximum number of [ATTACH | attached databases].)^
** ** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] ** ^(
SQLITE_LIMIT_LIKE_PATTERN_LENGTH
**
The maximum length of the pattern argument to the [LIKE] or ** [GLOB] operators.
)^ ** ** [[SQLITE_LIMIT_VARIABLE_NUMBER]] ** ^(
SQLITE_LIMIT_VARIABLE_NUMBER
**
The maximum index number of any [parameter] in an SQL statement.)^ ** ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
SQLITE_LIMIT_TRIGGER_DEPTH
**
The maximum depth of recursion for triggers.
)^ ** ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
SQLITE_LIMIT_WORKER_THREADS
**
The maximum number of auxiliary worker threads that a single ** [prepared statement] may start.
)^ **
*/ #define SQLITE_LIMIT_LENGTH 0 #define SQLITE_LIMIT_SQL_LENGTH 1 #define SQLITE_LIMIT_COLUMN 2 #define SQLITE_LIMIT_EXPR_DEPTH 3 #define SQLITE_LIMIT_COMPOUND_SELECT 4 #define SQLITE_LIMIT_VDBE_OP 5 #define SQLITE_LIMIT_FUNCTION_ARG 6 #define SQLITE_LIMIT_ATTACHED 7 #define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 /* ** CAPI3REF: Prepare Flags ** ** These constants define various flags that can be passed into ** "prepFlags" parameter of the [sqlite3_prepare_v3()] and ** [sqlite3_prepare16_v3()] interfaces. ** ** New flags may be added in future releases of SQLite. ** **
** [[SQLITE_PREPARE_PERSISTENT]] ^(
SQLITE_PREPARE_PERSISTENT
**
The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner ** that the prepared statement will be retained for a long time and ** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()] ** and [sqlite3_prepare16_v3()] assume that the prepared statement will ** be used just once or at most a few times and then destroyed using ** [sqlite3_finalize()] relatively soon. The current implementation acts ** on this hint by avoiding the use of [lookaside memory] so as not to ** deplete the limited store of lookaside memory. Future versions of ** SQLite may act on this hint differently. ** ** [[SQLITE_PREPARE_NORMALIZE]]
SQLITE_PREPARE_NORMALIZE
**
The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used ** to be required for any prepared statement that wanted to use the ** [sqlite3_normalized_sql()] interface. However, the ** [sqlite3_normalized_sql()] interface is now available to all ** prepared statements, regardless of whether or not they use this ** flag. ** ** [[SQLITE_PREPARE_NO_VTAB]]
SQLITE_PREPARE_NO_VTAB
**
The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler ** to return an error (error code SQLITE_ERROR) if the statement uses ** any virtual tables. **
*/ #define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_NORMALIZE 0x02 #define SQLITE_PREPARE_NO_VTAB 0x04 /* ** CAPI3REF: Compiling An SQL Statement ** KEYWORDS: {SQL statement compiler} ** METHOD: sqlite3 ** CONSTRUCTOR: sqlite3_stmt ** ** To execute an SQL statement, it must first be compiled into a byte-code ** program using one of these routines. Or, in other words, these routines ** are constructors for the [prepared statement] object. ** ** The preferred routine to use is [sqlite3_prepare_v2()]. The ** [sqlite3_prepare()] interface is legacy and should be avoided. ** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used ** for special purposes. ** ** The use of the UTF-8 interfaces is preferred, as SQLite currently ** does all parsing using UTF-8. The UTF-16 interfaces are provided ** as a convenience. The UTF-16 interfaces work by converting the ** input text into UTF-8, then invoking the corresponding UTF-8 interface. ** ** The first argument, "db", is a [database connection] obtained from a ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or ** [sqlite3_open16()]. The database connection must not have been closed. ** ** The second argument, "zSql", is the statement to be compiled, encoded ** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(), ** and sqlite3_prepare_v3() ** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(), ** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the ** first zero terminator. ^If nByte is positive, then it is the ** number of bytes read from zSql. ^If nByte is zero, then no prepared ** statement is generated. ** If the caller knows that the supplied string is nul-terminated, then ** there is a small performance advantage to passing an nByte parameter that ** is the number of bytes in the input string including ** the nul-terminator. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only ** compile the first statement in zSql, so *pzTail is left pointing to ** what remains uncompiled. ** ** ^*ppStmt is left pointing to a compiled [prepared statement] that can be ** executed using [sqlite3_step()]. ^If there is an error, *ppStmt is set ** to NULL. ^If the input text contains no SQL (if the input is an empty ** string or a comment) then *ppStmt is set to NULL. ** The calling procedure is responsible for deleting the compiled ** SQL statement using [sqlite3_finalize()] after it has finished with it. ** ppStmt may not be NULL. ** ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; ** otherwise an [error code] is returned. ** ** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(), ** and sqlite3_prepare16_v3() interfaces are recommended for all new programs. ** The older interfaces (sqlite3_prepare() and sqlite3_prepare16()) ** are retained for backwards compatibility, but their use is discouraged. ** ^In the "vX" interfaces, the prepared statement ** that is returned (the [sqlite3_stmt] object) contains a copy of the ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: ** **
    **
  1. ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it ** always used to do, [sqlite3_step()] will automatically recompile the SQL ** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY] ** retries will occur before sqlite3_step() gives up and returns an error. **
  2. ** **
  3. ** ^When an error occurs, [sqlite3_step()] will return one of the detailed ** [error codes] or [extended error codes]. ^The legacy behavior was that ** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code ** and the application would have to make a second call to [sqlite3_reset()] ** in order to find the underlying cause of the problem. With the "v2" prepare ** interfaces, the underlying reason for the error is returned immediately. **
  4. ** **
  5. ** ^If the specific value bound to a [parameter | host parameter] in the ** WHERE clause might influence the choice of query plan for a statement, ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of a WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled. **
  6. **
** **

^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having ** the extra prepFlags parameter, which is a bit array consisting of zero or ** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The ** sqlite3_prepare_v2() interface works exactly the same as ** sqlite3_prepare_v3() with a zero prepFlags parameter. */ SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare_v2( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare_v3( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare16( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare16_v2( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare16_v3( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); /* ** CAPI3REF: Retrieving Statement SQL ** METHOD: sqlite3_stmt ** ** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 ** SQL text used to create [prepared statement] P if P was ** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], ** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. ** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8 ** string containing the normalized SQL text of prepared statement P. The ** semantics used to normalize a SQL statement are unspecified and subject ** to change. At a minimum, literal values will be replaced with suitable ** placeholders. ** ** ^(For example, if a prepared statement is created using the SQL ** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 ** and parameter :xyz is unbound, then sqlite3_sql() will return ** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() ** will return "SELECT 2345,NULL".)^ ** ** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory ** is available to hold the result, or if the result would exceed the ** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. ** ** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** ** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) ** are managed by SQLite and are automatically freed when the prepared ** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, ** is obtained from [sqlite3_malloc()] and must be freed by the application ** by passing it to [sqlite3_free()]. ** ** ^The sqlite3_normalized_sql() interface is only available if ** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined. */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); #ifdef SQLITE_ENABLE_NORMALIZE SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); #endif /* ** CAPI3REF: Determine If An SQL Statement Writes The Database ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if ** and only if the [prepared statement] X makes no direct changes to ** the content of the database file. ** ** Note that [application-defined SQL functions] or ** [virtual tables] might change the database indirectly as a side effect. ** ^(For example, if an application defines a function "eval()" that ** calls [sqlite3_exec()], then the following SQL statement would ** change the database file through side-effects: ** **

**    SELECT eval('DELETE FROM t1') FROM t2;
** 
** ** But because the [SELECT] statement does not change the database file ** directly, sqlite3_stmt_readonly() would still return true.)^ ** ** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK], ** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true, ** since the statements themselves do not actually modify the database but ** rather they control the timing of when other statements modify the ** database. ^The [ATTACH] and [DETACH] statements also cause ** sqlite3_stmt_readonly() to return true since, while those statements ** change the configuration of a database connection, they do not make ** changes to the content of the database files on disk. ** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since ** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and ** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so ** sqlite3_stmt_readonly() returns false for those commands. ** ** ^This routine returns false if there is any possibility that the ** statement might change the database file. ^A false return does ** not guarantee that the statement will change the database file. ** ^For example, an UPDATE statement might have a WHERE clause that ** makes it a no-op, but the sqlite3_stmt_readonly() result would still ** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a ** read-only no-op if the table already exists, but ** sqlite3_stmt_readonly() still returns false for such a statement. ** ** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN] ** statement, then sqlite3_stmt_readonly(X) returns the same value as ** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted. */ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); /* ** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the ** prepared statement S is an EXPLAIN statement, or 2 if the ** statement S is an EXPLAIN QUERY PLAN. ** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is ** an ordinary statement or a NULL pointer. */ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); /* ** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement ** METHOD: sqlite3_stmt ** ** The sqlite3_stmt_explain(S,E) interface changes the EXPLAIN ** setting for [prepared statement] S. If E is zero, then S becomes ** a normal prepared statement. If E is 1, then S behaves as if ** its SQL text began with "[EXPLAIN]". If E is 2, then S behaves as if ** its SQL text began with "[EXPLAIN QUERY PLAN]". ** ** Calling sqlite3_stmt_explain(S,E) might cause S to be reprepared. ** SQLite tries to avoid a reprepare, but a reprepare might be necessary ** on the first transition into EXPLAIN or EXPLAIN QUERY PLAN mode. ** ** Because of the potential need to reprepare, a call to ** sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be ** reprepared because it was created using [sqlite3_prepare()] instead of ** the newer [sqlite3_prepare_v2()] or [sqlite3_prepare_v3()] interfaces and ** hence has no saved SQL text with which to reprepare. ** ** Changing the explain setting for a prepared statement does not change ** the original SQL text for the statement. Hence, if the SQL text originally ** began with EXPLAIN or EXPLAIN QUERY PLAN, but sqlite3_stmt_explain(S,0) ** is called to convert the statement into an ordinary statement, the EXPLAIN ** or EXPLAIN QUERY PLAN keywords will still appear in the sqlite3_sql(S) ** output, even though the statement now acts like a normal SQL statement. ** ** This routine returns SQLITE_OK if the explain mode is successfully ** changed, or an error code if the explain mode could not be changed. ** The explain mode cannot be changed while a statement is active. ** Hence, it is good practice to call [sqlite3_reset(S)] ** immediately prior to calling sqlite3_stmt_explain(S,E). */ SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode); /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the ** [prepared statement] S has been stepped at least once using ** [sqlite3_step(S)] but has neither run to completion (returned ** [SQLITE_DONE] from [sqlite3_step(S)]) nor ** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S) ** interface returns false if S is a NULL pointer. If S is not a ** NULL pointer and is not a pointer to a valid [prepared statement] ** object, then the behavior is undefined and probably undesirable. ** ** This interface can be used in combination [sqlite3_next_stmt()] ** to locate all prepared statements associated with a database ** connection that are in need of being reset. This can be used, ** for example, in diagnostic routines to search for prepared ** statements that are holding a transaction open. */ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); /* ** CAPI3REF: Dynamically Typed Value Object ** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value} ** ** SQLite uses the sqlite3_value object to represent all values ** that can be stored in a database table. SQLite uses dynamic typing ** for the values it stores. ^Values stored in sqlite3_value objects ** can be integers, floating point values, strings, BLOBs, or NULL. ** ** An sqlite3_value object may be either "protected" or "unprotected". ** Some interfaces require a protected sqlite3_value. Other interfaces ** will accept either a protected or an unprotected sqlite3_value. ** Every interface that accepts sqlite3_value arguments specifies ** whether or not it requires a protected sqlite3_value. The ** [sqlite3_value_dup()] interface can be used to construct a new ** protected sqlite3_value from an unprotected sqlite3_value. ** ** The terms "protected" and "unprotected" refer to whether or not ** a mutex is held. An internal mutex is held for a protected ** sqlite3_value object but no mutex is held for an unprotected ** sqlite3_value object. If SQLite is compiled to be single-threaded ** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) ** or if SQLite is run in one of reduced mutex modes ** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD] ** then there is no distinction between protected and unprotected ** sqlite3_value objects and they can be used interchangeably. However, ** for maximum code portability it is recommended that applications ** still make the distinction between protected and unprotected ** sqlite3_value objects even when not strictly required. ** ** ^The sqlite3_value objects that are passed as parameters into the ** implementation of [application-defined SQL functions] are protected. ** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()] ** are protected. ** ^The sqlite3_value object returned by ** [sqlite3_column_value()] is unprotected. ** Unprotected sqlite3_value objects may only be used as arguments ** to [sqlite3_result_value()], [sqlite3_bind_value()], and ** [sqlite3_value_dup()]. ** The [sqlite3_value_blob | sqlite3_value_type()] family of ** interfaces require protected sqlite3_value objects. */ typedef struct sqlite3_value sqlite3_value; /* ** CAPI3REF: SQL Function Context Object ** ** The context in which an SQL function executes is stored in an ** sqlite3_context object. ^A pointer to an sqlite3_context object ** is always first parameter to [application-defined SQL functions]. ** The application-defined SQL function implementation will pass this ** pointer through into calls to [sqlite3_result_int | sqlite3_result()], ** [sqlite3_aggregate_context()], [sqlite3_user_data()], ** [sqlite3_context_db_handle()], [sqlite3_get_auxdata()], ** and/or [sqlite3_set_auxdata()]. */ typedef struct sqlite3_context sqlite3_context; /* ** CAPI3REF: Binding Values To Prepared Statements ** KEYWORDS: {host parameter} {host parameters} {host parameter name} ** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding} ** METHOD: sqlite3_stmt ** ** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, ** literals may be replaced by a [parameter] that matches one of following ** templates: ** **
    **
  • ? **
  • ?NNN **
  • :VVV **
  • @VVV **
  • $VVV **
** ** In the templates above, NNN represents an integer literal, ** and VVV represents an alphanumeric identifier.)^ ^The values of these ** parameters (also called "host parameter names" or "SQL parameters") ** can be set using the sqlite3_bind_*() routines defined here. ** ** ^The first argument to the sqlite3_bind_*() routines is always ** a pointer to the [sqlite3_stmt] object returned from ** [sqlite3_prepare_v2()] or its variants. ** ** ^The second argument is the index of the SQL parameter to be set. ** ^The leftmost SQL parameter has an index of 1. ^When the same named ** SQL parameter is used more than once, second and subsequent ** occurrences have the same index as the first occurrence. ** ^The index for named parameters can be looked up using the ** [sqlite3_bind_parameter_index()] API if desired. ^The index ** for "?NNN" parameters is the value of NNN. ** ^The NNN value must be between 1 and the [sqlite3_limit()] ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766). ** ** ^The third argument is the value to bind to the parameter. ** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() ** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter ** is ignored and the end result is the same as sqlite3_bind_null(). ** ^If the third parameter to sqlite3_bind_text() is not NULL, then ** it should be a pointer to well-formed UTF8 text. ** ^If the third parameter to sqlite3_bind_text16() is not NULL, then ** it should be a pointer to well-formed UTF16 text. ** ^If the third parameter to sqlite3_bind_text64() is not NULL, then ** it should be a pointer to a well-formed unicode string that is ** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 ** otherwise. ** ** [[byte-order determination rules]] ^The byte-order of ** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) ** found in first character, which is removed, or in the absence of a BOM ** the byte order is the native byte order of the host ** machine for sqlite3_bind_text16() or the byte order specified in ** the 6th parameter for sqlite3_bind_text64().)^ ** ^If UTF16 input text contains invalid unicode ** characters, then SQLite might change those invalid characters ** into the unicode replacement character: U+FFFD. ** ** ^(In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the ** number of bytes in the value, not the number of characters.)^ ** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() ** is negative, then the length of the string is ** the number of bytes up to the first zero terminator. ** If the fourth parameter to sqlite3_bind_blob() is negative, then ** the behavior is undefined. ** If a non-negative fourth parameter is provided to sqlite3_bind_text() ** or sqlite3_bind_text16() or sqlite3_bind_text64() then ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL ** terminated. If any NUL characters occurs at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** ** ^The fifth argument to the BLOB and string binding interfaces controls ** or indicates the lifetime of the object referenced by the third parameter. ** These three options exist: ** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished ** with it may be passed. ^It is called to dispose of the BLOB or string even ** if the call to the bind API fails, except the destructor is not called if ** the third parameter is a NULL pointer or the fourth parameter is negative. ** ^ (2) The special constant, [SQLITE_STATIC], may be passed to indicate that ** the application remains responsible for disposing of the object. ^In this ** case, the object and the provided pointer to it must remain valid until ** either the prepared statement is finalized or the same SQL parameter is ** bound to something else, whichever occurs sooner. ** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the ** object is to be copied prior to the return from sqlite3_bind_*(). ^The ** object and pointer to it must remain valid until then. ^SQLite will then ** manage the lifetime of its private copy. ** ** ^The sixth argument to sqlite3_bind_text64() must be one of ** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] ** to specify the encoding of the text in the third parameter. If ** the sixth argument to sqlite3_bind_text64() is not one of the ** allowed values shown above, or if the text encoding is different ** from the encoding specified by the sixth parameter, then the behavior ** is undefined. ** ** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that ** is filled with zeroes. ^A zeroblob uses a fixed amount of memory ** (just an integer to hold its size) while it is being processed. ** Zeroblobs are intended to serve as placeholders for BLOBs whose ** content is later written using ** [sqlite3_blob_open | incremental BLOB I/O] routines. ** ^A negative value for the zeroblob results in a zero-length BLOB. ** ** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in ** [prepared statement] S to have an SQL value of NULL, but to also be ** associated with the pointer P of type T. ^D is either a NULL pointer or ** a pointer to a destructor function for P. ^SQLite will invoke the ** destructor D with a single argument of P when it is finished using ** P. The T parameter should be a static string, preferably a string ** literal. The sqlite3_bind_pointer() routine is part of the ** [pointer passing interface] added for SQLite 3.20.0. ** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which ** [sqlite3_step()] has been called more recently than [sqlite3_reset()], ** then the call will return [SQLITE_MISUSE]. If any sqlite3_bind_() ** routine is passed a [prepared statement] that has been finalized, the ** result is undefined and probably harmful. ** ** ^Bindings are not cleared by the [sqlite3_reset()] routine. ** ^Unbound parameters are interpreted as NULL. ** ** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an ** [error code] if anything goes wrong. ** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB ** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or ** [SQLITE_MAX_LENGTH]. ** ^[SQLITE_RANGE] is returned if the parameter ** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. ** ** See also: [sqlite3_bind_parameter_count()], ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. */ SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, void(*)(void*)); SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void(*)(void*), unsigned char encoding); SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); /* ** CAPI3REF: Number Of SQL Parameters ** METHOD: sqlite3_stmt ** ** ^This routine can be used to find the number of [SQL parameters] ** in a [prepared statement]. SQL parameters are tokens of the ** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as ** placeholders for values that are [sqlite3_bind_blob | bound] ** to the parameters at a later time. ** ** ^(This routine actually returns the index of the largest (rightmost) ** parameter. For all forms except ?NNN, this will correspond to the ** number of unique parameters. If parameters of the ?NNN form are used, ** there may be gaps in the list.)^ ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_name()], and ** [sqlite3_bind_parameter_index()]. */ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); /* ** CAPI3REF: Name Of A Host Parameter ** METHOD: sqlite3_stmt ** ** ^The sqlite3_bind_parameter_name(P,N) interface returns ** the name of the N-th [SQL parameter] in the [prepared statement] P. ** ^(SQL parameters of the form "?NNN" or ":AAA" or "@AAA" or "$AAA" ** have a name which is the string "?NNN" or ":AAA" or "@AAA" or "$AAA" ** respectively. ** In other words, the initial ":" or "$" or "@" or "?" ** is included as part of the name.)^ ** ^Parameters of the form "?" without a following integer have no name ** and are referred to as "nameless" or "anonymous parameters". ** ** ^The first host parameter has an index of 1, not 0. ** ** ^If the value N is out of range or if the N-th parameter is ** nameless, then NULL is returned. ^The returned string is ** always in UTF-8 encoding even if the named parameter was ** originally specified as UTF-16 in [sqlite3_prepare16()], ** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and ** [sqlite3_bind_parameter_index()]. */ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); /* ** CAPI3REF: Index Of A Parameter With A Given Name ** METHOD: sqlite3_stmt ** ** ^Return the index of an SQL parameter given its name. ^The ** index value returned is suitable for use as the second ** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero ** is returned if no matching parameter is found. ^The parameter ** name must be given in UTF-8 even if the original statement ** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or ** [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and ** [sqlite3_bind_parameter_name()]. */ SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); /* ** CAPI3REF: Reset All Bindings On A Prepared Statement ** METHOD: sqlite3_stmt ** ** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset ** the [sqlite3_bind_blob | bindings] on a [prepared statement]. ** ^Use this routine to reset all host parameters to NULL. */ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); /* ** CAPI3REF: Number Of Columns In A Result Set ** METHOD: sqlite3_stmt ** ** ^Return the number of columns in the result set returned by the ** [prepared statement]. ^If this routine returns 0, that means the ** [prepared statement] returns no data (for example an [UPDATE]). ** ^However, just because this routine returns a positive number does not ** mean that one or more rows of data will be returned. ^A SELECT statement ** will always have a positive sqlite3_column_count() but depending on the ** WHERE clause constraints and the table content, it might return no rows. ** ** See also: [sqlite3_data_count()] */ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Column Names In A Result Set ** METHOD: sqlite3_stmt ** ** ^These routines return the name assigned to a particular column ** in the result set of a [SELECT] statement. ^The sqlite3_column_name() ** interface returns a pointer to a zero-terminated UTF-8 string ** and sqlite3_column_name16() returns a pointer to a zero-terminated ** UTF-16 string. ^The first parameter is the [prepared statement] ** that implements the [SELECT] statement. ^The second parameter is the ** column number. ^The leftmost column is number 0. ** ** ^The returned string pointer is valid until either the [prepared statement] ** is destroyed by [sqlite3_finalize()] or until the statement is automatically ** reprepared by the first call to [sqlite3_step()] for a particular run ** or until the next call to ** sqlite3_column_name() or sqlite3_column_name16() on the same column. ** ** ^If sqlite3_malloc() fails during the processing of either routine ** (for example during a conversion from UTF-8 to UTF-16) then a ** NULL pointer is returned. ** ** ^The name of a result column is the value of the "AS" clause for ** that column, if there is an AS clause. If there is no AS clause ** then the name of the column is unspecified and may change from ** one release of SQLite to the next. */ SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N); SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); /* ** CAPI3REF: Source Of Data In A Query Result ** METHOD: sqlite3_stmt ** ** ^These routines provide a means to determine the database, table, and ** table column that is the origin of a particular result column in ** [SELECT] statement. ** ^The name of the database or table or column can be returned as ** either a UTF-8 or UTF-16 string. ^The _database_ routines return ** the database name, the _table_ routines return the table name, and ** the origin_ routines return the column name. ** ^The returned string is valid until the [prepared statement] is destroyed ** using [sqlite3_finalize()] or until the statement is automatically ** reprepared by the first call to [sqlite3_step()] for a particular run ** or until the same information is requested ** again in a different encoding. ** ** ^The names returned are the original un-aliased names of the ** database, table, and column. ** ** ^The first argument to these interfaces is a [prepared statement]. ** ^These functions return information about the Nth result column returned by ** the statement, where N is the second function argument. ** ^The left-most column is column 0 for these routines. ** ** ^If the Nth column returned by the statement is an expression or ** subquery and is not a column value, then all of these functions return ** NULL. ^These routines might also return NULL if a memory allocation error ** occurs. ^Otherwise, they return the name of the attached database, table, ** or column that query result column was extracted from. ** ** ^As with all other SQLite APIs, those whose names end with "16" return ** UTF-16 encoded strings and the other functions return UTF-8. ** ** ^These APIs are only available if the library was compiled with the ** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol. ** ** If two or more threads call one or more ** [sqlite3_column_database_name | column metadata interfaces] ** for the same [prepared statement] and result column ** at the same time then the results are undefined. */ SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int); SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int); SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int); SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int); SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int); SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); /* ** CAPI3REF: Declared Datatype Of A Query Result ** METHOD: sqlite3_stmt ** ** ^(The first parameter is a [prepared statement]. ** If this statement is a [SELECT] statement and the Nth column of the ** returned result set of that [SELECT] is a table column (not an ** expression or subquery) then the declared type of the table ** column is returned.)^ ^If the Nth column of the result set is an ** expression or subquery, then a NULL pointer is returned. ** ^The returned string is always UTF-8 encoded. ** ** ^(For example, given the database schema: ** ** CREATE TABLE t1(c1 VARIANT); ** ** and the following statement to be compiled: ** ** SELECT c1 + 1, c1 FROM t1; ** ** this routine would return the string "VARIANT" for the second result ** column (i==1), and a NULL pointer for the first result column (i==0).)^ ** ** ^SQLite uses dynamic run-time typing. ^So just because a column ** is declared to contain a particular type does not mean that the ** data stored in that column is of the declared type. SQLite is ** strongly typed, but the typing is dynamic not static. ^Type ** is associated with individual values, not with the containers ** used to hold those values. */ SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int); SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); /* ** CAPI3REF: Evaluate An SQL Statement ** METHOD: sqlite3_stmt ** ** After a [prepared statement] has been prepared using any of ** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()], ** or [sqlite3_prepare16_v3()] or one of the legacy ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function ** must be called one or more times to evaluate the statement. ** ** The details of the behavior of the sqlite3_step() interface depend ** on whether the statement was prepared using the newer "vX" interfaces ** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()], ** [sqlite3_prepare16_v2()] or the older legacy ** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the ** new "vX" interface is recommended for new applications but the legacy ** interface will continue to be supported. ** ** ^In the legacy interface, the return value will be either [SQLITE_BUSY], ** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE]. ** ^With the "v2" interface, any of the other [result codes] or ** [extended result codes] might be returned as well. ** ** ^[SQLITE_BUSY] means that the database engine was unable to acquire the ** database locks it needs to do its job. ^If the statement is a [COMMIT] ** or occurs outside of an explicit transaction, then you can retry the ** statement. If the statement is not a [COMMIT] and occurs within an ** explicit transaction then you should rollback the transaction before ** continuing. ** ** ^[SQLITE_DONE] means that the statement has finished executing ** successfully. sqlite3_step() should not be called again on this virtual ** machine without first calling [sqlite3_reset()] to reset the virtual ** machine back to its initial state. ** ** ^If the SQL statement being executed returns any data, then [SQLITE_ROW] ** is returned each time a new row of data is ready for processing by the ** caller. The values may be accessed using the [column access functions]. ** sqlite3_step() is called again to retrieve the next row of data. ** ** ^[SQLITE_ERROR] means that a run-time error (such as a constraint ** violation) has occurred. sqlite3_step() should not be called again on ** the VM. More information may be found by calling [sqlite3_errmsg()]. ** ^With the legacy interface, a more specific error code (for example, ** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) ** can be obtained by calling [sqlite3_reset()] on the ** [prepared statement]. ^In the "v2" interface, ** the more specific error code is returned directly by sqlite3_step(). ** ** [SQLITE_MISUSE] means that the this routine was called inappropriately. ** Perhaps it was called on a [prepared statement] that has ** already been [sqlite3_finalize | finalized] or on one that had ** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could ** be the case that the same database connection is being used by two or ** more threads at the same moment in time. ** ** For all versions of SQLite up to and including 3.6.23.1, a call to ** [sqlite3_reset()] was required after sqlite3_step() returned anything ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from ** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], ** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility ** break because any application that ever receives an SQLITE_MISUSE error ** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option ** can be used to restore the legacy behavior. ** ** Goofy Interface Alert: In the legacy interface, the sqlite3_step() ** API always returns a generic error code, [SQLITE_ERROR], following any ** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call ** [sqlite3_reset()] or [sqlite3_finalize()] in order to find one of the ** specific [error codes] that better describes the error. ** We admit that this is a goofy design. The problem has been fixed ** with the "v2" interface. If you prepare all of your SQL statements ** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()] ** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, ** then the more specific [error codes] are returned directly ** by sqlite3_step(). The use of the "vX" interfaces is recommended. */ SQLITE_API int sqlite3_step(sqlite3_stmt*); /* ** CAPI3REF: Number of columns in a result set ** METHOD: sqlite3_stmt ** ** ^The sqlite3_data_count(P) interface returns the number of columns in the ** current row of the result set of [prepared statement] P. ** ^If prepared statement P does not have results ready to return ** (via calls to the [sqlite3_column_int | sqlite3_column()] family of ** interfaces) then sqlite3_data_count(P) returns 0. ** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. ** ^The sqlite3_data_count(P) routine returns 0 if the previous call to ** [sqlite3_step](P) returned [SQLITE_DONE]. ^The sqlite3_data_count(P) ** will return non-zero if previous call to [sqlite3_step](P) returned ** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum] ** where it always returns zero since each step of that multi-step ** pragma returns 0 columns of data. ** ** See also: [sqlite3_column_count()] */ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Fundamental Datatypes ** KEYWORDS: SQLITE_TEXT ** ** ^(Every value in SQLite has one of five fundamental datatypes: ** **
    **
  • 64-bit signed integer **
  • 64-bit IEEE floating point number **
  • string **
  • BLOB **
  • NULL **
)^ ** ** These constants are codes for each of those types. ** ** Note that the SQLITE_TEXT constant was also used in SQLite version 2 ** for a completely different meaning. Software that links against both ** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT, not ** SQLITE_TEXT. */ #define SQLITE_INTEGER 1 #define SQLITE_FLOAT 2 #define SQLITE_BLOB 4 #define SQLITE_NULL 5 #ifdef SQLITE_TEXT # undef SQLITE_TEXT #else # define SQLITE_TEXT 3 #endif #define SQLITE3_TEXT 3 /* ** CAPI3REF: Result Values From A Query ** KEYWORDS: {column access functions} ** METHOD: sqlite3_stmt ** ** Summary: **
**
sqlite3_column_blobBLOB result **
sqlite3_column_doubleREAL result **
sqlite3_column_int32-bit INTEGER result **
sqlite3_column_int6464-bit INTEGER result **
sqlite3_column_textUTF-8 TEXT result **
sqlite3_column_text16UTF-16 TEXT result **
sqlite3_column_valueThe result as an ** [sqlite3_value|unprotected sqlite3_value] object. **
    **
sqlite3_column_bytesSize of a BLOB ** or a UTF-8 TEXT result in bytes **
sqlite3_column_bytes16   ** →  Size of UTF-16 ** TEXT in bytes **
sqlite3_column_typeDefault ** datatype of the result **
** ** Details: ** ** ^These routines return information about a single column of the current ** result row of a query. ^In every case the first argument is a pointer ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] ** that was returned from [sqlite3_prepare_v2()] or one of its variants) ** and the second argument is the index of the column for which information ** should be returned. ^The leftmost column of the result set has the index 0. ** ^The number of columns in the result can be determined using ** [sqlite3_column_count()]. ** ** If the SQL statement does not currently point to a valid row, or if the ** column index is out of range, the result is undefined. ** These routines may only be called when the most recent call to ** [sqlite3_step()] has returned [SQLITE_ROW] and neither ** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently. ** If any of these routines are called after [sqlite3_reset()] or ** [sqlite3_finalize()] or after [sqlite3_step()] has returned ** something other than [SQLITE_ROW], the results are undefined. ** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()] ** are called from a different thread while any of these routines ** are pending, then the results are undefined. ** ** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16) ** each return the value of a result column in a specific data format. If ** the result column is not initially in the requested format (for example, ** if the query returns an integer but the sqlite3_column_text() interface ** is used to extract the value) then an automatic type conversion is performed. ** ** ^The sqlite3_column_type() routine returns the ** [SQLITE_INTEGER | datatype code] for the initial data type ** of the result column. ^The returned value is one of [SQLITE_INTEGER], ** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. ** The return value of sqlite3_column_type() can be used to decide which ** of the first six interface should be used to extract the column value. ** The value returned by sqlite3_column_type() is only meaningful if no ** automatic type conversions have occurred for the value in question. ** After a type conversion, the result of calling sqlite3_column_type() ** is undefined, though harmless. Future ** versions of SQLite may change the behavior of sqlite3_column_type() ** following a type conversion. ** ** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes() ** or sqlite3_column_bytes16() interfaces can be used to determine the size ** of that BLOB or string. ** ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() ** routine returns the number of bytes in that BLOB or string. ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts ** the string to UTF-8 and then returns the number of bytes. ** ^If the result is a numeric value then sqlite3_column_bytes() uses ** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns ** the number of bytes in that string. ** ^If the result is NULL, then sqlite3_column_bytes() returns zero. ** ** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16() ** routine returns the number of bytes in that BLOB or string. ** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts ** the string to UTF-16 and then returns the number of bytes. ** ^If the result is a numeric value then sqlite3_column_bytes16() uses ** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns ** the number of bytes in that string. ** ^If the result is NULL, then sqlite3_column_bytes16() returns zero. ** ** ^The values returned by [sqlite3_column_bytes()] and ** [sqlite3_column_bytes16()] do not include the zero terminators at the end ** of the string. ^For clarity: the values returned by ** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of ** bytes in the string, not the number of characters. ** ** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(), ** even empty strings, are always zero-terminated. ^The return ** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. ** ** ^Strings returned by sqlite3_column_text16() always have the endianness ** which is native to the platform, regardless of the text encoding set ** for the database. ** ** Warning: ^The object returned by [sqlite3_column_value()] is an ** [unprotected sqlite3_value] object. In a multithreaded environment, ** an unprotected sqlite3_value object may only be used safely with ** [sqlite3_bind_value()] and [sqlite3_result_value()]. ** If the [unprotected sqlite3_value] object returned by ** [sqlite3_column_value()] is used in any other way, including calls ** to routines like [sqlite3_value_int()], [sqlite3_value_text()], ** or [sqlite3_value_bytes()], the behavior is not threadsafe. ** Hence, the sqlite3_column_value() interface ** is normally only useful within the implementation of ** [application-defined SQL functions] or [virtual tables], not within ** top-level application code. ** ** These routines may attempt to convert the datatype of the result. ** ^For example, if the internal representation is FLOAT and a text result ** is requested, [sqlite3_snprintf()] is used internally to perform the ** conversion automatically. ^(The following table details the conversions ** that are applied: ** **
** **
Internal
Type
Requested
Type
Conversion ** **
NULL INTEGER Result is 0 **
NULL FLOAT Result is 0.0 **
NULL TEXT Result is a NULL pointer **
NULL BLOB Result is a NULL pointer **
INTEGER FLOAT Convert from integer to float **
INTEGER TEXT ASCII rendering of the integer **
INTEGER BLOB Same as INTEGER->TEXT **
FLOAT INTEGER [CAST] to INTEGER **
FLOAT TEXT ASCII rendering of the float **
FLOAT BLOB [CAST] to BLOB **
TEXT INTEGER [CAST] to INTEGER **
TEXT FLOAT [CAST] to REAL **
TEXT BLOB No change **
BLOB INTEGER [CAST] to INTEGER **
BLOB FLOAT [CAST] to REAL **
BLOB TEXT [CAST] to TEXT, ensure zero terminator **
**
)^ ** ** Note that when type conversions occur, pointers returned by prior ** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or ** sqlite3_column_text16() may be invalidated. ** Type conversions and pointer invalidations might occur ** in the following cases: ** **
    **
  • The initial content is a BLOB and sqlite3_column_text() or ** sqlite3_column_text16() is called. A zero-terminator might ** need to be added to the string.
  • **
  • The initial content is UTF-8 text and sqlite3_column_bytes16() or ** sqlite3_column_text16() is called. The content must be converted ** to UTF-16.
  • **
  • The initial content is UTF-16 text and sqlite3_column_bytes() or ** sqlite3_column_text() is called. The content must be converted ** to UTF-8.
  • **
** ** ^Conversions between UTF-16be and UTF-16le are always done in place and do ** not invalidate a prior pointer, though of course the content of the buffer ** that the prior pointer references will have been modified. Other kinds ** of conversion are done in place when it is possible, but sometimes they ** are not possible and in those cases prior pointers are invalidated. ** ** The safest policy is to invoke these routines ** in one of the following ways: ** **
    **
  • sqlite3_column_text() followed by sqlite3_column_bytes()
  • **
  • sqlite3_column_blob() followed by sqlite3_column_bytes()
  • **
  • sqlite3_column_text16() followed by sqlite3_column_bytes16()
  • **
** ** In other words, you should call sqlite3_column_text(), ** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result ** into the desired format, then invoke sqlite3_column_bytes() or ** sqlite3_column_bytes16() to find the size of the result. Do not mix calls ** to sqlite3_column_text() or sqlite3_column_blob() with calls to ** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() ** with calls to sqlite3_column_bytes(). ** ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings ** and BLOBs is freed automatically. Do not pass the pointers returned ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** ** As long as the input parameters are correct, these routines will only ** fail if an out-of-memory error occurs during a format conversion. ** Only the following subset of interfaces are subject to out-of-memory ** errors: ** **
    **
  • sqlite3_column_blob() **
  • sqlite3_column_text() **
  • sqlite3_column_text16() **
  • sqlite3_column_bytes() **
  • sqlite3_column_bytes16() **
** ** If an out-of-memory error occurs, then the return value from these ** routines is the same as if the column had contained an SQL NULL value. ** Valid SQL NULL returns can be distinguished from out-of-memory errors ** by invoking the [sqlite3_errcode()] immediately after the suspect ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. */ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); /* ** CAPI3REF: Destroy A Prepared Statement Object ** DESTRUCTOR: sqlite3_stmt ** ** ^The sqlite3_finalize() function is called to delete a [prepared statement]. ** ^If the most recent evaluation of the statement encountered no errors ** or if the statement is never been evaluated, then sqlite3_finalize() returns ** SQLITE_OK. ^If the most recent evaluation of statement S failed, then ** sqlite3_finalize(S) returns the appropriate [error code] or ** [extended error code]. ** ** ^The sqlite3_finalize(S) routine can be called at any point during ** the life cycle of [prepared statement] S: ** before statement S is ever evaluated, after ** one or more calls to [sqlite3_reset()], or after any call ** to [sqlite3_step()] regardless of whether or not the statement has ** completed execution. ** ** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op. ** ** The application must finalize every [prepared statement] in order to avoid ** resource leaks. It is a grievous error for the application to try to use ** a prepared statement after it has been finalized. Any use of a prepared ** statement after it has been finalized can result in undefined and ** undesirable behavior such as segfaults and heap corruption. */ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); /* ** CAPI3REF: Reset A Prepared Statement Object ** METHOD: sqlite3_stmt ** ** The sqlite3_reset() function is called to reset a [prepared statement] ** object back to its initial state, ready to be re-executed. ** ^Any SQL statement variables that had values bound to them using ** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values. ** Use [sqlite3_clear_bindings()] to reset the bindings. ** ** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S ** back to the beginning of its program. ** ** ^The return code from [sqlite3_reset(S)] indicates whether or not ** the previous evaluation of prepared statement S completed successfully. ** ^If [sqlite3_step(S)] has never before been called on S or if ** [sqlite3_step(S)] has not been called since the previous call ** to [sqlite3_reset(S)], then [sqlite3_reset(S)] will return ** [SQLITE_OK]. ** ** ^If the most recent call to [sqlite3_step(S)] for the ** [prepared statement] S indicated an error, then ** [sqlite3_reset(S)] returns an appropriate [error code]. ** ^The [sqlite3_reset(S)] interface might also return an [error code] ** if there were no prior errors but the process of resetting ** the prepared statement caused a new error. ^For example, if an ** [INSERT] statement with a [RETURNING] clause is only stepped one time, ** that one call to [sqlite3_step(S)] might return SQLITE_ROW but ** the overall statement might still fail and the [sqlite3_reset(S)] call ** might return SQLITE_BUSY if locking constraints prevent the ** database change from committing. Therefore, it is important that ** applications check the return code from [sqlite3_reset(S)] even if ** no prior call to [sqlite3_step(S)] indicated a problem. ** ** ^The [sqlite3_reset(S)] interface does not change the values ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. */ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); /* ** CAPI3REF: Create Or Redefine SQL Functions ** KEYWORDS: {function creation routines} ** METHOD: sqlite3 ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior ** of existing SQL functions or aggregates. The only differences between ** the three "sqlite3_create_function*" routines are the text encoding ** expected for the second parameter (the name of the function being ** created) and the presence or absence of a destructor callback for ** the application data pointer. Function sqlite3_create_window_function() ** is similar, but allows the user to supply the extra callback functions ** needed by [aggregate window functions]. ** ** ^The first parameter is the [database connection] to which the SQL ** function is to be added. ^If an application uses more than one database ** connection then application-defined SQL functions must be added ** to each database connection separately. ** ** ^The second parameter is the name of the SQL function to be created or ** redefined. ^The length of the name is limited to 255 bytes in a UTF-8 ** representation, exclusive of the zero-terminator. ^Note that the name ** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. ** ^Any attempt to create a function with a longer name ** will result in [SQLITE_MISUSE] being returned. ** ** ^The third parameter (nArg) ** is the number of arguments that the SQL function or ** aggregate takes. ^If this parameter is -1, then the SQL function or ** aggregate may take any number of arguments between 0 and the limit ** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third ** parameter is less than -1 or greater than 127 then the behavior is ** undefined. ** ** ^The fourth parameter, eTextRep, specifies what ** [SQLITE_UTF8 | text encoding] this SQL function prefers for ** its parameters. The application should set this parameter to ** [SQLITE_UTF16LE] if the function implementation invokes ** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the ** implementation invokes [sqlite3_value_text16be()] on an input, or ** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8] ** otherwise. ^The same SQL function may be registered multiple times using ** different preferred text encodings, with different implementations for ** each encoding. ** ^When multiple implementations of the same function are available, SQLite ** will pick the one that involves the least amount of data conversion. ** ** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC] ** to signal that the function will always return the same result given ** the same inputs within a single SQL statement. Most SQL functions are ** deterministic. The built-in [random()] SQL function is an example of a ** function that is not deterministic. The SQLite query planner is able to ** perform additional optimizations on deterministic functions, so use ** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. ** ** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY] ** flag, which if present prevents the function from being invoked from ** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions, ** index expressions, or the WHERE clause of partial indexes. ** ** For best security, the [SQLITE_DIRECTONLY] flag is recommended for ** all application-defined SQL functions that do not need to be ** used inside of triggers, view, CHECK constraints, or other elements of ** the database schema. This flags is especially recommended for SQL ** functions that have side effects or reveal internal application state. ** Without this flag, an attacker might be able to modify the schema of ** a database file to include invocations of the function with parameters ** chosen by the attacker, which the application will then execute when ** the database file is opened and read. ** ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** ** ^The sixth, seventh and eighth parameters passed to the three ** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or ** aggregate. ^A scalar SQL function requires an implementation of the xFunc ** callback only; NULL pointers must be passed as the xStep and xFinal ** parameters. ^An aggregate SQL function requires an implementation of xStep ** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing ** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue ** and xInverse) passed to sqlite3_create_window_function are pointers to ** C-language callbacks that implement the new function. xStep and xFinal ** must both be non-NULL. xValue and xInverse may either both be NULL, in ** which case a regular aggregate function is created, or must both be ** non-NULL, in which case the new function may be used as either an aggregate ** or aggregate window function. More details regarding the implementation ** of aggregate window functions are ** [user-defined window functions|available here]. ** ** ^(If the final parameter to sqlite3_create_function_v2() or ** sqlite3_create_window_function() is not NULL, then it is destructor for ** the application data pointer. The destructor is invoked when the function ** is deleted, either by being overloaded or when the database connection ** closes.)^ ^The destructor is also invoked if the call to ** sqlite3_create_function_v2() fails. ^When the destructor callback is ** invoked, it is passed a single argument which is a copy of the application ** data pointer which was the fifth parameter to sqlite3_create_function_v2(). ** ** ^It is permitted to register multiple implementations of the same ** functions with the same name but with either differing numbers of ** arguments or differing preferred text encodings. ^SQLite will use ** the implementation that most closely matches the way in which the ** SQL function is used. ^A function implementation with a non-negative ** nArg parameter is a better match than a function implementation with ** a negative nArg. ^A function where the preferred text encoding ** matches the database encoding is a better ** match than a function where the encoding is different. ** ^A function where the encoding difference is between UTF16le and UTF16be ** is a closer match than a function where the encoding difference is ** between UTF8 and UTF16. ** ** ^Built-in functions may be overloaded by new application-defined functions. ** ** ^An application-defined function is permitted to call other ** SQLite interfaces. However, such calls must not ** close the database connection nor finalize or reset the prepared ** statement in which the function is running. */ SQLITE_API int sqlite3_create_function( sqlite3 *db, const char *zFunctionName, int nArg, int eTextRep, void *pApp, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); SQLITE_API int sqlite3_create_function16( sqlite3 *db, const void *zFunctionName, int nArg, int eTextRep, void *pApp, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); SQLITE_API int sqlite3_create_function_v2( sqlite3 *db, const char *zFunctionName, int nArg, int eTextRep, void *pApp, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*) ); SQLITE_API int sqlite3_create_window_function( sqlite3 *db, const char *zFunctionName, int nArg, int eTextRep, void *pApp, void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInverse)(sqlite3_context*,int,sqlite3_value**), void(*xDestroy)(void*) ); /* ** CAPI3REF: Text Encodings ** ** These constant define integer codes that represent the various ** text encodings supported by SQLite. */ #define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ #define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ #define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */ #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* Deprecated */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ /* ** CAPI3REF: Function Flags ** ** These constants may be ORed together with the ** [SQLITE_UTF8 | preferred text encoding] as the fourth argument ** to [sqlite3_create_function()], [sqlite3_create_function16()], or ** [sqlite3_create_function_v2()]. ** **
** [[SQLITE_DETERMINISTIC]]
SQLITE_DETERMINISTIC
** The SQLITE_DETERMINISTIC flag means that the new function always gives ** the same output when the input parameters are the same. ** The [abs|abs() function] is deterministic, for example, but ** [randomblob|randomblob()] is not. Functions must ** be deterministic in order to be used in certain contexts such as ** with the WHERE clause of [partial indexes] or in [generated columns]. ** SQLite might also optimize deterministic functions by factoring them ** out of inner loops. **
** ** [[SQLITE_DIRECTONLY]]
SQLITE_DIRECTONLY
** The SQLITE_DIRECTONLY flag means that the function may only be invoked ** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in ** schema structures such as [CHECK constraints], [DEFAULT clauses], ** [expression indexes], [partial indexes], or [generated columns]. **

** The SQLITE_DIRECTONLY flag is recommended for any ** [application-defined SQL function] ** that has side-effects or that could potentially leak sensitive information. ** This will prevent attacks in which an application is tricked ** into using a database file that has had its schema surreptitiously ** modified to invoke the application-defined function in ways that are ** harmful. **

** Some people say it is good practice to set SQLITE_DIRECTONLY on all ** [application-defined SQL functions], regardless of whether or not they ** are security sensitive, as doing so prevents those functions from being used ** inside of the database schema, and thus ensures that the database ** can be inspected and modified using generic tools (such as the [CLI]) ** that do not have access to the application-defined functions. **

** ** [[SQLITE_INNOCUOUS]]
SQLITE_INNOCUOUS
** The SQLITE_INNOCUOUS flag means that the function is unlikely ** to cause problems even if misused. An innocuous function should have ** no side effects and should not depend on any values other than its ** input parameters. The [abs|abs() function] is an example of an ** innocuous function. ** The [load_extension() SQL function] is not innocuous because of its ** side effects. **

SQLITE_INNOCUOUS is similar to SQLITE_DETERMINISTIC, but is not ** exactly the same. The [random|random() function] is an example of a ** function that is innocuous but not deterministic. **

Some heightened security settings ** ([SQLITE_DBCONFIG_TRUSTED_SCHEMA] and [PRAGMA trusted_schema=OFF]) ** disable the use of SQL functions inside views and triggers and in ** schema structures such as [CHECK constraints], [DEFAULT clauses], ** [expression indexes], [partial indexes], and [generated columns] unless ** the function is tagged with SQLITE_INNOCUOUS. Most built-in functions ** are innocuous. Developers are advised to avoid using the ** SQLITE_INNOCUOUS flag for application-defined functions unless the ** function has been carefully audited and found to be free of potentially ** security-adverse side-effects and information-leaks. **

** ** [[SQLITE_SUBTYPE]]
SQLITE_SUBTYPE
** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. ** This flag instructs SQLite to omit some corner-case optimizations that ** might disrupt the operation of the [sqlite3_value_subtype()] function, ** causing it to return zero rather than the correct subtype(). ** SQL functions that invokes [sqlite3_value_subtype()] should have this ** property. If the SQLITE_SUBTYPE property is omitted, then the return ** value from [sqlite3_value_subtype()] might sometimes be zero even though ** a non-zero subtype was specified by the function argument expression. ** ** [[SQLITE_RESULT_SUBTYPE]]
SQLITE_RESULT_SUBTYPE
** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call ** [sqlite3_result_subtype()] to cause a sub-type to be associated with its ** result. ** Every function that invokes [sqlite3_result_subtype()] should have this ** property. If it does not, then the call to [sqlite3_result_subtype()] ** might become a no-op if the function is used as term in an ** [expression index]. On the other hand, SQL functions that never invoke ** [sqlite3_result_subtype()] should avoid setting this property, as the ** purpose of this property is to disable certain optimizations that are ** incompatible with subtypes. **
**
*/ #define SQLITE_DETERMINISTIC 0x000000800 #define SQLITE_DIRECTONLY 0x000080000 #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 #define SQLITE_RESULT_SUBTYPE 0x001000000 /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** ** These functions are [deprecated]. In order to maintain ** backwards compatibility with older code, these functions continue ** to be supported. However, new applications should avoid ** the use of these functions. To encourage programmers to avoid ** these functions, we will not explain what they do. */ #ifndef SQLITE_OMIT_DEPRECATED SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), void*,sqlite3_int64); #endif /* ** CAPI3REF: Obtaining SQL Values ** METHOD: sqlite3_value ** ** Summary: **
**
sqlite3_value_blobBLOB value **
sqlite3_value_doubleREAL value **
sqlite3_value_int32-bit INTEGER value **
sqlite3_value_int6464-bit INTEGER value **
sqlite3_value_pointerPointer value **
sqlite3_value_textUTF-8 TEXT value **
sqlite3_value_text16UTF-16 TEXT value in ** the native byteorder **
sqlite3_value_text16beUTF-16be TEXT value **
sqlite3_value_text16leUTF-16le TEXT value **
    **
sqlite3_value_bytesSize of a BLOB ** or a UTF-8 TEXT in bytes **
sqlite3_value_bytes16   ** →  Size of UTF-16 ** TEXT in bytes **
sqlite3_value_typeDefault ** datatype of the value **
sqlite3_value_numeric_type   ** →  Best numeric datatype of the value **
sqlite3_value_nochange   ** →  True if the column is unchanged in an UPDATE ** against a virtual table. **
sqlite3_value_frombind   ** →  True if value originated from a [bound parameter] **
** ** Details: ** ** These routines extract type, size, and content information from ** [protected sqlite3_value] objects. Protected sqlite3_value objects ** are used to pass parameter information into the functions that ** implement [application-defined SQL functions] and [virtual tables]. ** ** These routines work only with [protected sqlite3_value] objects. ** Any attempt to use these routines on an [unprotected sqlite3_value] ** is not threadsafe. ** ** ^These routines work just like the corresponding [column access functions] ** except that these routines take a single [protected sqlite3_value] object ** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. ** ** ^The sqlite3_value_text16() interface extracts a UTF-16 string ** in the native byte-order of the host machine. ^The ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces ** extract UTF-16 strings as big-endian and little-endian respectively. ** ** ^If [sqlite3_value] object V was initialized ** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)] ** and if X and Y are strings that compare equal according to strcmp(X,Y), ** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise, ** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() ** routine is part of the [pointer passing interface] added for SQLite 3.20.0. ** ** ^(The sqlite3_value_type(V) interface returns the ** [SQLITE_INTEGER | datatype code] for the initial datatype of the ** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER], ** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ ** Other interfaces might change the datatype for an sqlite3_value object. ** For example, if the datatype is initially SQLITE_INTEGER and ** sqlite3_value_text(V) is called to extract a text value for that ** integer, then subsequent calls to sqlite3_value_type(V) might return ** SQLITE_TEXT. Whether or not a persistent internal datatype conversion ** occurs is undefined and may change from one release of SQLite to the next. ** ** ^(The sqlite3_value_numeric_type() interface attempts to apply ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If ** such a conversion is possible without loss of information (in other ** words, if the value is a string that looks like a number) ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** ** ^Within the [xUpdate] method of a [virtual table], the ** sqlite3_value_nochange(X) interface returns true if and only if ** the column corresponding to X is unchanged by the UPDATE operation ** that the xUpdate method call was invoked to implement and if ** and the prior [xColumn] method call that was invoked to extracted ** the value for that column returned without setting a result (probably ** because it queried [sqlite3_vtab_nochange()] and found that the column ** was unchanging). ^Within an [xUpdate] method, any value for which ** sqlite3_value_nochange(X) is true will in all other respects appear ** to be a NULL value. If sqlite3_value_nochange(X) is invoked anywhere other ** than within an [xUpdate] method call for an UPDATE statement, then ** the return value is arbitrary and meaningless. ** ** ^The sqlite3_value_frombind(X) interface returns non-zero if the ** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] ** interfaces. ^If X comes from an SQL literal value, or a table column, ** or an expression, then sqlite3_value_frombind(X) returns zero. ** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to ** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], ** or [sqlite3_value_text16()]. ** ** These routines must be called from the same thread as ** the SQL function that supplied the [sqlite3_value*] parameters. ** ** As long as the input parameter is correct, these routines can only ** fail if an out-of-memory error occurs during a format conversion. ** Only the following subset of interfaces are subject to out-of-memory ** errors: ** **
    **
  • sqlite3_value_blob() **
  • sqlite3_value_text() **
  • sqlite3_value_text16() **
  • sqlite3_value_text16le() **
  • sqlite3_value_text16be() **
  • sqlite3_value_bytes() **
  • sqlite3_value_bytes16() **
** ** If an out-of-memory error occurs, then the return value from these ** routines is the same as if the column had contained an SQL NULL value. ** Valid SQL NULL returns can be distinguished from out-of-memory errors ** by invoking the [sqlite3_errcode()] immediately after the suspect ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); SQLITE_API int sqlite3_value_int(sqlite3_value*); SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*); SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); SQLITE_API int sqlite3_value_bytes(sqlite3_value*); SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Report the internal text encoding state of an sqlite3_value object ** METHOD: sqlite3_value ** ** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8], ** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current text encoding ** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) ** returns something other than SQLITE_TEXT, then the return value from ** sqlite3_value_encoding(X) is meaningless. ^Calls to ** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)], ** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or ** [sqlite3_value_bytes16(X)] might change the encoding of the value X and ** thus change the return from subsequent calls to sqlite3_value_encoding(X). ** ** This routine is intended for used by applications that test and validate ** the SQLite implementation. This routine is inquiring about the opaque ** internal state of an [sqlite3_value] object. Ordinary applications should ** not need to know what the internal state of an sqlite3_value object is and ** hence should not need to use this interface. */ SQLITE_API int sqlite3_value_encoding(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values ** METHOD: sqlite3_value ** ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. ** ** Every [application-defined SQL function] that invoke this interface ** should include the [SQLITE_SUBTYPE] property in the text ** encoding argument when the function is [sqlite3_create_function|registered]. ** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() ** might return zero instead of the upstream subtype in some corner cases. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); /* ** CAPI3REF: Copy And Free SQL Values ** METHOD: sqlite3_value ** ** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value] ** object D and returns a pointer to that copy. ^The [sqlite3_value] returned ** is a [protected sqlite3_value] object even if the input is not. ** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a ** memory allocation fails. ^If V is a [pointer value], then the result ** of sqlite3_value_dup(V) is a NULL value. ** ** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object ** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer ** then sqlite3_value_free(V) is a harmless no-op. */ SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*); SQLITE_API void sqlite3_value_free(sqlite3_value*); /* ** CAPI3REF: Obtain Aggregate Function Context ** METHOD: sqlite3_context ** ** Implementations of aggregate SQL functions use this ** routine to allocate memory for storing their state. ** ** ^The first time the sqlite3_aggregate_context(C,N) routine is called ** for a particular aggregate function, SQLite allocates ** N bytes of memory, zeroes out that memory, and returns a pointer ** to the new memory. ^On second and subsequent calls to ** sqlite3_aggregate_context() for the same aggregate function instance, ** the same buffer is returned. Sqlite3_aggregate_context() is normally ** called once for each invocation of the xStep callback and then one ** last time when the xFinal callback is invoked. ^(When no rows match ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer ** when first called if N is less than or equal to zero or if a memory ** allocation error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** determined by the N parameter on first successful call. Changing the ** value of N in any subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ Within the xFinal callback, it is customary to set ** N=0 in calls to sqlite3_aggregate_context(C,N) so that no ** pointless memory allocations occur. ** ** ^SQLite automatically frees the memory allocated by ** sqlite3_aggregate_context() when the aggregate query concludes. ** ** The first parameter must be a copy of the ** [sqlite3_context | SQL function context] that is the first parameter ** to the xStep or xFinal callback routine that implements the aggregate ** function. ** ** This routine must be called from the same thread in which ** the aggregate SQL function is running. */ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); /* ** CAPI3REF: User Data For Functions ** METHOD: sqlite3_context ** ** ^The sqlite3_user_data() interface returns a copy of ** the pointer that was the pUserData parameter (the 5th parameter) ** of the [sqlite3_create_function()] ** and [sqlite3_create_function16()] routines that originally ** registered the application defined function. ** ** This routine must be called from the same thread in which ** the application-defined function is running. */ SQLITE_API void *sqlite3_user_data(sqlite3_context*); /* ** CAPI3REF: Database Connection For Functions ** METHOD: sqlite3_context ** ** ^The sqlite3_context_db_handle() interface returns a copy of ** the pointer to the [database connection] (the 1st parameter) ** of the [sqlite3_create_function()] ** and [sqlite3_create_function16()] routines that originally ** registered the application defined function. */ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /* ** CAPI3REF: Function Auxiliary Data ** METHOD: sqlite3_context ** ** These functions may be used by (non-aggregate) SQL functions to ** associate auxiliary data with argument values. If the same argument ** value is passed to multiple invocations of the same SQL function during ** query execution, under some circumstances the associated auxiliary data ** might be preserved. An example of where this might be useful is in a ** regular-expression matching function. The compiled version of the regular ** expression can be stored as auxiliary data associated with the pattern string. ** Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** ** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data ** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument ** value to the application-defined function. ^N is zero for the left-most ** function argument. ^If there is no auxiliary data ** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the ** N-th argument of the application-defined function. ^Subsequent ** calls to sqlite3_get_auxdata(C,N) return P from the most recent ** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or ** NULL if the auxiliary data has been discarded. ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, ** SQLite will invoke the destructor function X with parameter P exactly ** once, when the auxiliary data is discarded. ** SQLite is free to discard the auxiliary data at any time, including:
    **
  • ^(when the corresponding function parameter changes)^, or **
  • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** SQL statement)^, or **
  • ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or **
  • ^(during the original sqlite3_set_auxdata() call when a memory ** allocation error occurs.)^ **
  • ^(during the original sqlite3_set_auxdata() call if the function ** is evaluated during query planning instead of during query execution, ** as sometimes happens with [SQLITE_ENABLE_STAT4].)^
** ** Note the last two bullets in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the ** function implementation should not make any use of P after ** sqlite3_set_auxdata() has been called. Furthermore, a call to ** sqlite3_get_auxdata() that occurs immediately after a corresponding call ** to sqlite3_set_auxdata() might still return NULL if an out-of-memory ** condition occurred during the sqlite3_set_auxdata() call or if the ** function is being evaluated during query planning rather than during ** query execution. ** ** ^(In practice, auxiliary data is preserved between function calls for ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** ** The value of the N parameter to these interfaces should be non-negative. ** Future enhancements may make use of negative N values to define new ** kinds of function caching behavior. ** ** These routines must be called from the same thread in which ** the SQL function is running. ** ** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()]. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); /* ** CAPI3REF: Database Connection Client Data ** METHOD: sqlite3 ** ** These functions are used to associate one or more named pointers ** with a [database connection]. ** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P ** to be attached to [database connection] D using name N. Subsequent ** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P ** or a NULL pointer if there were no prior calls to ** sqlite3_set_clientdata() with the same values of D and N. ** Names are compared using strcmp() and are thus case sensitive. ** ** If P and X are both non-NULL, then the destructor X is invoked with ** argument P on the first of the following occurrences: **
    **
  • An out-of-memory error occurs during the call to ** sqlite3_set_clientdata() which attempts to register pointer P. **
  • A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made ** with the same D and N parameters. **
  • The database connection closes. SQLite does not make any guarantees ** about the order in which destructors are called, only that all ** destructors will be called exactly once at some point during the ** database connection closing process. **
** ** SQLite does not do anything with client data other than invoke ** destructors on the client data at the appropriate time. The intended ** use for client data is to provide a mechanism for wrapper libraries ** to store additional information about an SQLite database connection. ** ** There is no limit (other than available memory) on the number of different ** client data pointers (with different names) that can be attached to a ** single database connection. However, the implementation is optimized ** for the case of having only one or two different client data names. ** Applications and wrapper libraries are discouraged from using more than ** one client data name each. ** ** There is no way to enumerate the client data pointers ** associated with a database connection. The N parameter can be thought ** of as a secret key such that only code that knows the secret key is able ** to access the associated data. ** ** Security Warning: These interfaces should not be exposed in scripting ** languages or in other circumstances where it might be possible for an ** an attacker to invoke them. Any agent that can invoke these interfaces ** can probably also take control of the process. ** ** Database connection client data is only available for SQLite ** version 3.44.0 ([dateof:3.44.0]) and later. ** ** See also: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()]. */ SQLITE_API void *sqlite3_get_clientdata(sqlite3*,const char*); SQLITE_API int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*)); /* ** CAPI3REF: Constants Defining Special Destructor Behavior ** ** These are special values for the destructor that is passed in as the ** final argument to routines like [sqlite3_result_blob()]. ^If the destructor ** argument is SQLITE_STATIC, it means that the content pointer is constant ** and will never change. It does not need to be destroyed. ^The ** SQLITE_TRANSIENT value means that the content will likely change in ** the near future and that SQLite should make its own private copy of ** the content before returning. ** ** The typedef is necessary to work around problems in certain ** C++ compilers. */ typedef void (*sqlite3_destructor_type)(void*); #define SQLITE_STATIC ((sqlite3_destructor_type)0) #define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) /* ** CAPI3REF: Setting The Result Of An SQL Function ** METHOD: sqlite3_context ** ** These routines are used by the xFunc or xFinal callbacks that ** implement SQL functions and aggregates. See ** [sqlite3_create_function()] and [sqlite3_create_function16()] ** for additional information. ** ** These functions work very much like the [parameter binding] family of ** functions used to bind values to host parameters in prepared statements. ** Refer to the [SQL parameter] documentation for additional information. ** ** ^The sqlite3_result_blob() interface sets the result from ** an application-defined function to be the BLOB whose content is pointed ** to by the second parameter and which is N bytes long where N is the ** third parameter. ** ** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N) ** interfaces set the result of the application-defined function to be ** a BLOB containing all zero bytes and N bytes in size. ** ** ^The sqlite3_result_double() interface sets the result from ** an application-defined function to be a floating point value specified ** by its 2nd argument. ** ** ^The sqlite3_result_error() and sqlite3_result_error16() functions ** cause the implemented SQL function to throw an exception. ** ^SQLite uses the string pointed to by the ** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() ** as the text of an error message. ^SQLite interprets the error ** message string from sqlite3_result_error() as UTF-8. ^SQLite ** interprets the string from sqlite3_result_error16() as UTF-16 using ** the same [byte-order determination rules] as [sqlite3_bind_text16()]. ** ^If the third parameter to sqlite3_result_error() ** or sqlite3_result_error16() is negative then SQLite takes as the error ** message all text up through the first zero character. ** ^If the third parameter to sqlite3_result_error() or ** sqlite3_result_error16() is non-negative then SQLite takes that many ** bytes (not characters) from the 2nd parameter as the error message. ** ^The sqlite3_result_error() and sqlite3_result_error16() ** routines make a private copy of the error message text before ** they return. Hence, the calling function can deallocate or ** modify the text after they return without harm. ** ^The sqlite3_result_error_code() function changes the error code ** returned by SQLite as a result of an error in a function. ^By default, ** the error code is SQLITE_ERROR. ^A subsequent call to sqlite3_result_error() ** or sqlite3_result_error16() resets the error code to SQLITE_ERROR. ** ** ^The sqlite3_result_error_toobig() interface causes SQLite to throw an ** error indicating that a string or BLOB is too long to represent. ** ** ^The sqlite3_result_error_nomem() interface causes SQLite to throw an ** error indicating that a memory allocation failed. ** ** ^The sqlite3_result_int() interface sets the return value ** of the application-defined function to be the 32-bit signed integer ** value given in the 2nd argument. ** ^The sqlite3_result_int64() interface sets the return value ** of the application-defined function to be the 64-bit signed integer ** value given in the 2nd argument. ** ** ^The sqlite3_result_null() interface sets the return value ** of the application-defined function to be NULL. ** ** ^The sqlite3_result_text(), sqlite3_result_text16(), ** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. ** ^The sqlite3_result_text64() interface sets the return value of an ** application-defined function to be a text string in an encoding ** specified by the fifth (and last) parameter, which must be one ** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces ** other than sqlite3_result_text64() is negative, then SQLite computes ** the string length itself by searching the 2nd parameter for the first ** zero character. ** ^If the 3rd parameter to the sqlite3_result_text* interfaces ** is non-negative, then as many bytes (not characters) of the text ** pointed to by the 2nd parameter are taken as the application-defined ** function result. If the 3rd parameter is non-negative, then it ** must be the byte offset into the string where the NUL terminator would ** appear if the string where NUL terminated. If any NUL characters occur ** in the string at a byte offset that is less than the value of the 3rd ** parameter, then the resulting string will contain embedded NULs and the ** result of expressions operating on strings with embedded NULs is undefined. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that ** function as the destructor on the text or BLOB result when it has ** finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces or to ** sqlite3_result_blob is the special constant SQLITE_STATIC, then SQLite ** assumes that the text or BLOB result is in constant space and does not ** copy the content of the parameter nor call a destructor on the content ** when it has finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT ** then SQLite makes a copy of the result into space obtained ** from [sqlite3_malloc()] before it returns. ** ** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and ** sqlite3_result_text16be() routines, and for sqlite3_result_text64() ** when the encoding is not UTF8, if the input UTF16 begins with a ** byte-order mark (BOM, U+FEFF) then the BOM is removed from the ** string and the rest of the string is interpreted according to the ** byte-order specified by the BOM. ^The byte-order specified by ** the BOM at the beginning of the text overrides the byte-order ** specified by the interface procedure. ^So, for example, if ** sqlite3_result_text16le() is invoked with text that begins ** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the ** first two bytes of input are skipped and the remaining input ** is interpreted as UTF16BE text. ** ** ^For UTF16 input text to the sqlite3_result_text16(), ** sqlite3_result_text16be(), sqlite3_result_text16le(), and ** sqlite3_result_text64() routines, if the text contains invalid ** UTF16 characters, the invalid characters might be converted ** into the unicode replacement character, U+FFFD. ** ** ^The sqlite3_result_value() interface sets the result of ** the application-defined function to be a copy of the ** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The ** sqlite3_result_value() interface makes a copy of the [sqlite3_value] ** so that the [sqlite3_value] specified in the parameter may change or ** be deallocated after sqlite3_result_value() returns without harm. ** ^A [protected sqlite3_value] object may always be used where an ** [unprotected sqlite3_value] object is required, so either ** kind of [sqlite3_value] object can be used with this interface. ** ** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an ** SQL NULL value, just like [sqlite3_result_null(C)], except that it ** also associates the host-language pointer P or type T with that ** NULL value such that the pointer can be retrieved within an ** [application-defined SQL function] using [sqlite3_value_pointer()]. ** ^If the D parameter is not NULL, then it is a pointer to a destructor ** for the P parameter. ^SQLite invokes D with P as its only argument ** when SQLite is finished with P. The T parameter should be a static ** string and preferably a string literal. The sqlite3_result_pointer() ** routine is part of the [pointer passing interface] added for SQLite 3.20.0. ** ** If these routines are called from within the different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. */ SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*, sqlite3_uint64,void(*)(void*)); SQLITE_API void sqlite3_result_double(sqlite3_context*, double); SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*); SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*); SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int); SQLITE_API void sqlite3_result_int(sqlite3_context*, int); SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, void(*)(void*), unsigned char encoding); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*)); SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); /* ** CAPI3REF: Setting The Subtype Of An SQL Function ** METHOD: sqlite3_context ** ** The sqlite3_result_subtype(C,T) function causes the subtype of ** the result from the [application-defined SQL function] with ** [sqlite3_context] C to be the value T. Only the lower 8 bits ** of the subtype T are preserved in current versions of SQLite; ** higher order bits are discarded. ** The number of subtype bytes preserved by SQLite might increase ** in future releases of SQLite. ** ** Every [application-defined SQL function] that invokes this interface ** should include the [SQLITE_RESULT_SUBTYPE] property in its ** text encoding argument when the SQL function is ** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE] ** property is omitted from the function that invokes sqlite3_result_subtype(), ** then in some cases the sqlite3_result_subtype() might fail to set ** the result subtype. ** ** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any ** SQL function that invokes the sqlite3_result_subtype() interface ** and that does not have the SQLITE_RESULT_SUBTYPE property will raise ** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1 ** by default. */ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); /* ** CAPI3REF: Define New Collating Sequences ** METHOD: sqlite3 ** ** ^These functions add, remove, or modify a [collation] associated ** with the [database connection] specified as the first argument. ** ** ^The name of the collation is a UTF-8 string ** for sqlite3_create_collation() and sqlite3_create_collation_v2() ** and a UTF-16 string in native byte order for sqlite3_create_collation16(). ** ^Collation names that compare equal according to [sqlite3_strnicmp()] are ** considered to be the same name. ** ** ^(The third argument (eTextRep) must be one of the constants: **
    **
  • [SQLITE_UTF8], **
  • [SQLITE_UTF16LE], **
  • [SQLITE_UTF16BE], **
  • [SQLITE_UTF16], or **
  • [SQLITE_UTF16_ALIGNED]. **
)^ ** ^The eTextRep argument determines the encoding of strings passed ** to the collating function callback, xCompare. ** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep ** force strings to be UTF16 with native byte order. ** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin ** on an even byte address. ** ** ^The fourth argument, pArg, is an application data pointer that is passed ** through as the first argument to the collating function callback. ** ** ^The fifth argument, xCompare, is a pointer to the collating function. ** ^Multiple collating functions can be registered using the same name but ** with different eTextRep parameters and SQLite will use whichever ** function requires the least amount of data transformation. ** ^If the xCompare argument is NULL then the collating function is ** deleted. ^When all collating functions having the same name are deleted, ** that collation is no longer usable. ** ** ^The collating function callback is invoked with a copy of the pArg ** application data pointer and with two strings in the encoding specified ** by the eTextRep argument. The two integer parameters to the collating ** function callback are the length of the two strings, in bytes. The collating ** function must return an integer that is negative, zero, or positive ** if the first string is less than, equal to, or greater than the second, ** respectively. A collating function must always return the same answer ** given the same inputs. If two or more collating functions are registered ** to the same collation name (using different eTextRep values) then all ** must give an equivalent answer when invoked with equivalent strings. ** The collating function must obey the following properties for all ** strings A, B, and C: ** **
    **
  1. If A==B then B==A. **
  2. If A==B and B==C then A==C. **
  3. If A<B THEN B>A. **
  4. If A<B and B<C then A<C. **
** ** If a collating function fails any of the above constraints and that ** collating function is registered and used, then the behavior of SQLite ** is undefined. ** ** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation() ** with the addition that the xDestroy callback is invoked on pArg when ** the collating function is deleted. ** ^Collating functions are deleted when they are overridden by later ** calls to the collation creation functions or when the ** [database connection] is closed using [sqlite3_close()]. ** ** ^The xDestroy callback is not called if the ** sqlite3_create_collation_v2() function fails. Applications that invoke ** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should ** check the return code and dispose of the application data pointer ** themselves rather than expecting SQLite to deal with it for them. ** This is different from every other SQLite interface. The inconsistency ** is unfortunate but cannot be changed without breaking backwards ** compatibility. ** ** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. */ SQLITE_API int sqlite3_create_collation( sqlite3*, const char *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); SQLITE_API int sqlite3_create_collation_v2( sqlite3*, const char *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*), void(*xDestroy)(void*) ); SQLITE_API int sqlite3_create_collation16( sqlite3*, const void *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); /* ** CAPI3REF: Collation Needed Callbacks ** METHOD: sqlite3 ** ** ^To avoid having to register all collation sequences before a database ** can be used, a single callback function may be registered with the ** [database connection] to be invoked whenever an undefined collation ** sequence is required. ** ** ^If the function is registered using the sqlite3_collation_needed() API, ** then it is passed the names of undefined collation sequences as strings ** encoded in UTF-8. ^If sqlite3_collation_needed16() is used, ** the names are passed as UTF-16 in machine native byte order. ** ^A call to either function replaces the existing collation-needed callback. ** ** ^(When the callback is invoked, the first argument passed is a copy ** of the second argument to sqlite3_collation_needed() or ** sqlite3_collation_needed16(). The second argument is the database ** connection. The third argument is one of [SQLITE_UTF8], [SQLITE_UTF16BE], ** or [SQLITE_UTF16LE], indicating the most desirable form of the collation ** sequence function required. The fourth parameter is the name of the ** required collation sequence.)^ ** ** The callback function should register the desired collation using ** [sqlite3_create_collation()], [sqlite3_create_collation16()], or ** [sqlite3_create_collation_v2()]. */ SQLITE_API int sqlite3_collation_needed( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const char*) ); SQLITE_API int sqlite3_collation_needed16( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const void*) ); #ifdef SQLITE_ENABLE_CEROD /* ** Specify the activation key for a CEROD database. Unless ** activated, none of the CEROD routines will work. */ SQLITE_API void sqlite3_activate_cerod( const char *zPassPhrase /* Activation phrase */ ); #endif /* ** CAPI3REF: Suspend Execution For A Short Time ** ** The sqlite3_sleep() function causes the current thread to suspend execution ** for at least a number of milliseconds specified in its parameter. ** ** If the operating system does not support sleep requests with ** millisecond time resolution, then the time will be rounded up to ** the nearest second. The number of milliseconds of sleep actually ** requested from the operating system is returned. ** ** ^SQLite implements this interface by calling the xSleep() ** method of the default [sqlite3_vfs] object. If the xSleep() method ** of the default VFS is not implemented correctly, or not implemented at ** all, then the behavior of sqlite3_sleep() may deviate from the description ** in the previous paragraphs. ** ** If a negative argument is passed to sqlite3_sleep() the results vary by ** VFS and operating system. Some system treat a negative argument as an ** instruction to sleep forever. Others understand it to mean do not sleep ** at all. ^In SQLite version 3.42.0 and later, a negative ** argument passed into sqlite3_sleep() is changed to zero before it is relayed ** down into the xSleep method of the VFS. */ SQLITE_API int sqlite3_sleep(int); /* ** CAPI3REF: Name Of The Folder Holding Temporary Files ** ** ^(If this global variable is made to point to a string which is ** the name of a folder (a.k.a. directory), then all temporary files ** created by SQLite when using a built-in [sqlite3_vfs | VFS] ** will be placed in that directory.)^ ^If this variable ** is a NULL pointer, then SQLite performs a search for an appropriate ** temporary file directory. ** ** Applications are strongly discouraged from using this global variable. ** It is required to set a temporary folder on Windows Runtime (WinRT). ** But for all other platforms, it is highly recommended that applications ** neither read nor write this variable. This global variable is a relic ** that exists for backwards compatibility of legacy applications and should ** be avoided in new projects. ** ** It is not safe to read or modify this variable in more than one ** thread at a time. It is not safe to read or modify this variable ** if a [database connection] is being used at the same time in a separate ** thread. ** It is intended that this variable be set once ** as part of process initialization and before any SQLite interface ** routines have been called and that this variable remain unchanged ** thereafter. ** ** ^The [temp_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [temp_store_directory pragma] always assumes that any string ** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be ** made NULL or made to point to memory obtained from [sqlite3_malloc] ** or else the use of the [temp_store_directory pragma] should be avoided. ** Except when requested by the [temp_store_directory pragma], SQLite ** does not free the memory that sqlite3_temp_directory points to. If ** the application wants that memory to be freed, it must do ** so itself, taking care to only do so after all [database connection] ** objects have been destroyed. ** ** Note to Windows Runtime users: The temporary directory must be set ** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various ** features that require the use of temporary files may fail. Here is an ** example of how to do this using C++ with the Windows Runtime: ** **
** LPCWSTR zPath = Windows::Storage::ApplicationData::Current->
**       TemporaryFolder->Path->Data();
** char zPathBuf[MAX_PATH + 1];
** memset(zPathBuf, 0, sizeof(zPathBuf));
** WideCharToMultiByte(CP_UTF8, 0, zPath, -1, zPathBuf, sizeof(zPathBuf),
**       NULL, NULL);
** sqlite3_temp_directory = sqlite3_mprintf("%s", zPathBuf);
** 
*/ SQLITE_API char *sqlite3_temp_directory; /* ** CAPI3REF: Name Of The Folder Holding Database Files ** ** ^(If this global variable is made to point to a string which is ** the name of a folder (a.k.a. directory), then all database files ** specified with a relative pathname and created or accessed by ** SQLite when using a built-in windows [sqlite3_vfs | VFS] will be assumed ** to be relative to that directory.)^ ^If this variable is a NULL ** pointer, then SQLite assumes that all database files specified ** with a relative pathname are relative to the current directory ** for the process. Only the windows VFS makes use of this global ** variable; it is ignored by the unix VFS. ** ** Changing the value of this variable while a database connection is ** open can result in a corrupt database. ** ** It is not safe to read or modify this variable in more than one ** thread at a time. It is not safe to read or modify this variable ** if a [database connection] is being used at the same time in a separate ** thread. ** It is intended that this variable be set once ** as part of process initialization and before any SQLite interface ** routines have been called and that this variable remain unchanged ** thereafter. ** ** ^The [data_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [data_store_directory pragma] always assumes that any string ** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be ** made NULL or made to point to memory obtained from [sqlite3_malloc] ** or else the use of the [data_store_directory pragma] should be avoided. */ SQLITE_API char *sqlite3_data_directory; /* ** CAPI3REF: Win32 Specific Interface ** ** These interfaces are available only on Windows. The ** [sqlite3_win32_set_directory] interface is used to set the value associated ** with the [sqlite3_temp_directory] or [sqlite3_data_directory] variable, to ** zValue, depending on the value of the type parameter. The zValue parameter ** should be NULL to cause the previous value to be freed via [sqlite3_free]; ** a non-NULL value will be copied into memory obtained from [sqlite3_malloc] ** prior to being used. The [sqlite3_win32_set_directory] interface returns ** [SQLITE_OK] to indicate success, [SQLITE_ERROR] if the type is unsupported, ** or [SQLITE_NOMEM] if memory could not be allocated. The value of the ** [sqlite3_data_directory] variable is intended to act as a replacement for ** the current directory on the sub-platforms of Win32 where that concept is ** not present, e.g. WinRT and UWP. The [sqlite3_win32_set_directory8] and ** [sqlite3_win32_set_directory16] interfaces behave exactly the same as the ** sqlite3_win32_set_directory interface except the string parameter must be ** UTF-8 or UTF-16, respectively. */ SQLITE_API int sqlite3_win32_set_directory( unsigned long type, /* Identifier for directory being set or reset */ void *zValue /* New value for directory being set or reset */ ); SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char *zValue); SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zValue); /* ** CAPI3REF: Win32 Directory Types ** ** These macros are only available on Windows. They define the allowed values ** for the type argument to the [sqlite3_win32_set_directory] interface. */ #define SQLITE_WIN32_DATA_DIRECTORY_TYPE 1 #define SQLITE_WIN32_TEMP_DIRECTORY_TYPE 2 /* ** CAPI3REF: Test For Auto-Commit Mode ** KEYWORDS: {autocommit mode} ** METHOD: sqlite3 ** ** ^The sqlite3_get_autocommit() interface returns non-zero or ** zero if the given database connection is or is not in autocommit mode, ** respectively. ^Autocommit mode is on by default. ** ^Autocommit mode is disabled by a [BEGIN] statement. ** ^Autocommit mode is re-enabled by a [COMMIT] or [ROLLBACK]. ** ** If certain kinds of errors occur on a statement within a multi-statement ** transaction (errors including [SQLITE_FULL], [SQLITE_IOERR], ** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the ** transaction might be rolled back automatically. The only way to ** find out whether SQLite automatically rolled back the transaction after ** an error is to use this function. ** ** If another thread changes the autocommit status of the database ** connection while this routine is running, then the return value ** is undefined. */ SQLITE_API int sqlite3_get_autocommit(sqlite3*); /* ** CAPI3REF: Find The Database Handle Of A Prepared Statement ** METHOD: sqlite3_stmt ** ** ^The sqlite3_db_handle interface returns the [database connection] handle ** to which a [prepared statement] belongs. ^The [database connection] ** returned by sqlite3_db_handle is the same [database connection] ** that was the first argument ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to ** create the statement in the first place. */ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); /* ** CAPI3REF: Return The Schema Name For A Database Connection ** METHOD: sqlite3 ** ** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name ** for the N-th database on database connection D, or a NULL pointer of N is ** out of range. An N value of 0 means the main database file. An N of 1 is ** the "temp" schema. Larger values of N correspond to various ATTACH-ed ** databases. ** ** Space to hold the string that is returned by sqlite3_db_name() is managed ** by SQLite itself. The string might be deallocated by any operation that ** changes the schema, including [ATTACH] or [DETACH] or calls to ** [sqlite3_serialize()] or [sqlite3_deserialize()], even operations that ** occur on a different thread. Applications that need to ** remember the string long-term should make their own copy. Applications that ** are accessing the same database connection simultaneously on multiple ** threads should mutex-protect calls to this API and should make their own ** private copy of the result prior to releasing the mutex. */ SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N); /* ** CAPI3REF: Return The Filename For A Database Connection ** METHOD: sqlite3 ** ** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename ** associated with database N of connection D. ** ^If there is no attached database N on the database ** connection D, or if database N is a temporary or in-memory database, then ** this function will return either a NULL pointer or an empty string. ** ** ^The string value returned by this routine is owned and managed by ** the database connection. ^The value will be valid until the database N ** is [DETACH]-ed or until the database connection closes. ** ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. ** ** If the filename pointer returned by this routine is not NULL, then it ** can be used as the filename input parameter to these routines: **
    **
  • [sqlite3_uri_parameter()] **
  • [sqlite3_uri_boolean()] **
  • [sqlite3_uri_int64()] **
  • [sqlite3_filename_database()] **
  • [sqlite3_filename_journal()] **
  • [sqlite3_filename_wal()] **
*/ SQLITE_API sqlite3_filename sqlite3_db_filename(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Determine if a database is read-only ** METHOD: sqlite3 ** ** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N ** of connection D is read-only, 0 if it is read/write, or -1 if N is not ** the name of a database on connection D. */ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Determine the transaction state of a database ** METHOD: sqlite3 ** ** ^The sqlite3_txn_state(D,S) interface returns the current ** [transaction state] of schema S in database connection D. ^If S is NULL, ** then the highest transaction state of any schema on database connection D ** is returned. Transaction states are (in order of lowest to highest): **
    **
  1. SQLITE_TXN_NONE **
  2. SQLITE_TXN_READ **
  3. SQLITE_TXN_WRITE **
** ^If the S argument to sqlite3_txn_state(D,S) is not the name of ** a valid schema, then -1 is returned. */ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); /* ** CAPI3REF: Allowed return values from sqlite3_txn_state() ** KEYWORDS: {transaction state} ** ** These constants define the current transaction state of a database file. ** ^The [sqlite3_txn_state(D,S)] interface returns one of these ** constants in order to describe the transaction state of schema S ** in [database connection] D. ** **
** [[SQLITE_TXN_NONE]]
SQLITE_TXN_NONE
**
The SQLITE_TXN_NONE state means that no transaction is currently ** pending.
** ** [[SQLITE_TXN_READ]]
SQLITE_TXN_READ
**
The SQLITE_TXN_READ state means that the database is currently ** in a read transaction. Content has been read from the database file ** but nothing in the database file has changed. The transaction state ** will advanced to SQLITE_TXN_WRITE if any changes occur and there are ** no other conflicting concurrent write transactions. The transaction ** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or ** [COMMIT].
** ** [[SQLITE_TXN_WRITE]]
SQLITE_TXN_WRITE
**
The SQLITE_TXN_WRITE state means that the database is currently ** in a write transaction. Content has been written to the database file ** but has not yet committed. The transaction state will change to ** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
*/ #define SQLITE_TXN_NONE 0 #define SQLITE_TXN_READ 1 #define SQLITE_TXN_WRITE 2 /* ** CAPI3REF: Find the next prepared statement ** METHOD: sqlite3 ** ** ^This interface returns a pointer to the next [prepared statement] after ** pStmt associated with the [database connection] pDb. ^If pStmt is NULL ** then this interface returns a pointer to the first prepared statement ** associated with the database connection pDb. ^If no prepared statement ** satisfies the conditions of this routine, it returns NULL. ** ** The [database connection] pointer D in a call to ** [sqlite3_next_stmt(D,S)] must refer to an open database ** connection and in particular must not be a NULL pointer. */ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); /* ** CAPI3REF: Commit And Rollback Notification Callbacks ** METHOD: sqlite3 ** ** ^The sqlite3_commit_hook() interface registers a callback ** function to be invoked whenever a transaction is [COMMIT | committed]. ** ^Any callback set by a previous call to sqlite3_commit_hook() ** for the same database connection is overridden. ** ^The sqlite3_rollback_hook() interface registers a callback ** function to be invoked whenever a transaction is [ROLLBACK | rolled back]. ** ^Any callback set by a previous call to sqlite3_rollback_hook() ** for the same database connection is overridden. ** ^The pArg argument is passed through to the callback. ** ^If the callback on a commit hook function returns non-zero, ** then the commit is converted into a rollback. ** ** ^The sqlite3_commit_hook(D,C,P) and sqlite3_rollback_hook(D,C,P) functions ** return the P argument from the previous call of the same function ** on the same [database connection] D, or NULL for ** the first call for each function on D. ** ** The commit and rollback hook callbacks are not reentrant. ** The callback implementation must not do anything that will modify ** the database connection that invoked the callback. Any actions ** to modify the database connection must be deferred until after the ** completion of the [sqlite3_step()] call that triggered the commit ** or rollback hook in the first place. ** Note that running any other SQL statements, including SELECT statements, ** or merely calling [sqlite3_prepare_v2()] and [sqlite3_step()] will modify ** the database connections for the meaning of "modify" in this paragraph. ** ** ^Registering a NULL function disables the callback. ** ** ^When the commit hook callback routine returns zero, the [COMMIT] ** operation is allowed to continue normally. ^If the commit hook ** returns non-zero, then the [COMMIT] is converted into a [ROLLBACK]. ** ^The rollback hook is invoked on a rollback that results from a commit ** hook returning non-zero, just as it would be with any other rollback. ** ** ^For the purposes of this API, a transaction is said to have been ** rolled back if an explicit "ROLLBACK" statement is executed, or ** an error or constraint causes an implicit rollback to occur. ** ^The rollback callback is not invoked if a transaction is ** automatically rolled back because the database connection is closed. ** ** See also the [sqlite3_update_hook()] interface. */ SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Autovacuum Compaction Amount Callback ** METHOD: sqlite3 ** ** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback ** function C that is invoked prior to each autovacuum of the database ** file. ^The callback is passed a copy of the generic data pointer (P), ** the schema-name of the attached database that is being autovacuumed, ** the size of the database file in pages, the number of free pages, ** and the number of bytes per page, respectively. The callback should ** return the number of free pages that should be removed by the ** autovacuum. ^If the callback returns zero, then no autovacuum happens. ** ^If the value returned is greater than or equal to the number of ** free pages, then a complete autovacuum happens. ** **

^If there are multiple ATTACH-ed database files that are being ** modified as part of a transaction commit, then the autovacuum pages ** callback is invoked separately for each file. ** **

The callback is not reentrant. The callback function should ** not attempt to invoke any other SQLite interface. If it does, bad ** things may happen, including segmentation faults and corrupt database ** files. The callback function should be a simple function that ** does some arithmetic on its input parameters and returns a result. ** ** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional ** destructor for the P parameter. ^If X is not NULL, then X(P) is ** invoked whenever the database connection closes or when the callback ** is overwritten by another invocation of sqlite3_autovacuum_pages(). ** **

^There is only one autovacuum pages callback per database connection. ** ^Each call to the sqlite3_autovacuum_pages() interface overrides all ** previous invocations for that database connection. ^If the callback ** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, ** then the autovacuum steps callback is canceled. The return value ** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might ** be some other error code if something goes wrong. The current ** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other ** return codes might be added in future releases. ** **

If no autovacuum pages callback is specified (the usual case) or ** a NULL pointer is provided for the callback, ** then the default behavior is to vacuum all free pages. So, in other ** words, the default behavior is the same as if the callback function ** were something like this: ** **

**     unsigned int demonstration_autovac_pages_callback(
**       void *pClientData,
**       const char *zSchema,
**       unsigned int nDbPage,
**       unsigned int nFreePage,
**       unsigned int nBytePerPage
**     ){
**       return nFreePage;
**     }
** 
*/ SQLITE_API int sqlite3_autovacuum_pages( sqlite3 *db, unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), void*, void(*)(void*) ); /* ** CAPI3REF: Data Change Notification Callbacks ** METHOD: sqlite3 ** ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument ** to be invoked whenever a row is updated, inserted or deleted in ** a [rowid table]. ** ^Any callback set by a previous call to this function ** for the same database connection is overridden. ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], ** or [SQLITE_UPDATE], depending on the operation that caused the callback ** to be invoked. ** ^The third and fourth arguments to the callback contain pointers to the ** database and table name containing the affected row. ** ^The final callback parameter is the [rowid] of the row. ** ^In the case of an update, this is the [rowid] after the update takes place. ** ** ^(The update hook is not invoked when internal system tables are ** modified (i.e. sqlite_sequence).)^ ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. ** ** ^In the current implementation, the update hook ** is not invoked when conflicting rows are deleted because of an ** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook ** invoked when rows are deleted using the [truncate optimization]. ** The exceptions defined in this paragraph might change in a future ** release of SQLite. ** ** The update hook implementation must not do anything that will modify ** the database connection that invoked the update hook. Any actions ** to modify the database connection must be deferred until after the ** completion of the [sqlite3_step()] call that triggered the update hook. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** ** ^The sqlite3_update_hook(D,C,P) function ** returns the P argument from the previous call ** on the same [database connection] D, or NULL for ** the first call on D. ** ** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()], ** and [sqlite3_preupdate_hook()] interfaces. */ SQLITE_API void *sqlite3_update_hook( sqlite3*, void(*)(void *,int ,char const *,char const *,sqlite3_int64), void* ); /* ** CAPI3REF: Enable Or Disable Shared Pager Cache ** ** ^(This routine enables or disables the sharing of the database cache ** and schema data structures between [database connection | connections] ** to the same database. Sharing is enabled if the argument is true ** and disabled if the argument is false.)^ ** ** This interface is omitted if SQLite is compiled with ** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE] ** compile-time option is recommended because the ** [use of shared cache mode is discouraged]. ** ** ^Cache sharing is enabled and disabled for an entire process. ** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). ** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent ** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. ** Existing database connections continue to use the sharing mode ** that was in effect at the time they were opened.)^ ** ** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled ** successfully. An [error code] is returned otherwise.)^ ** ** ^Shared cache is disabled by default. It is recommended that it stay ** that way. In other words, do not use this routine. This interface ** continues to be provided for historical compatibility, but its use is ** discouraged. Any use of shared cache is discouraged. If shared cache ** must be used, it is recommended that shared cache only be enabled for ** individual database connections using the [sqlite3_open_v2()] interface ** with the [SQLITE_OPEN_SHAREDCACHE] flag. ** ** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0 ** and will always return SQLITE_MISUSE. On those systems, ** shared cache mode should be enabled per-database connection via ** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE]. ** ** This interface is threadsafe on processors where writing a ** 32-bit integer is atomic. ** ** See Also: [SQLite Shared-Cache Mode] */ SQLITE_API int sqlite3_enable_shared_cache(int); /* ** CAPI3REF: Attempt To Free Heap Memory ** ** ^The sqlite3_release_memory() interface attempts to free N bytes ** of heap memory by deallocating non-essential memory allocations ** held by the database library. Memory used to cache database ** pages to improve performance is an example of non-essential memory. ** ^sqlite3_release_memory() returns the number of bytes actually freed, ** which might be more or less than the amount requested. ** ^The sqlite3_release_memory() routine is a no-op returning zero ** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT]. ** ** See also: [sqlite3_db_release_memory()] */ SQLITE_API int sqlite3_release_memory(int); /* ** CAPI3REF: Free Memory Used By A Database Connection ** METHOD: sqlite3 ** ** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap ** memory as possible from database connection D. Unlike the ** [sqlite3_release_memory()] interface, this interface is in effect even ** when the [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is ** omitted. ** ** See also: [sqlite3_release_memory()] */ SQLITE_API int sqlite3_db_release_memory(sqlite3*); /* ** CAPI3REF: Impose A Limit On Heap Size ** ** These interfaces impose limits on the amount of heap memory that will be ** by all database connections within a single process. ** ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the ** soft limit on the amount of heap memory that may be allocated by SQLite. ** ^SQLite strives to keep heap memory utilization below the soft heap ** limit by reducing the number of pages held in the page cache ** as heap memory usages approaches the limit. ** ^The soft heap limit is "soft" because even though SQLite strives to stay ** below the limit, it will exceed the limit rather than generate ** an [SQLITE_NOMEM] error. In other words, the soft heap limit ** is advisory only. ** ** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of ** N bytes on the amount of memory that will be allocated. ^The ** sqlite3_hard_heap_limit64(N) interface is similar to ** sqlite3_soft_heap_limit64(N) except that memory allocations will fail ** when the hard heap limit is reached. ** ** ^The return value from both sqlite3_soft_heap_limit64() and ** sqlite3_hard_heap_limit64() is the size of ** the heap limit prior to the call, or negative in the case of an ** error. ^If the argument N is negative ** then no change is made to the heap limit. Hence, the current ** size of heap limits can be determined by invoking ** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). ** ** ^Setting the heap limits to zero disables the heap limiter mechanism. ** ** ^The soft heap limit may not be greater than the hard heap limit. ** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) ** is invoked with a value of N that is greater than the hard heap limit, ** the soft heap limit is set to the value of the hard heap limit. ** ^The soft heap limit is automatically enabled whenever the hard heap ** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and ** the soft heap limit is outside the range of 1..N, then the soft heap ** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the ** hard heap limit is enabled makes the soft heap limit equal to the ** hard heap limit. ** ** The memory allocation limits can also be adjusted using ** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit]. ** ** ^(The heap limits are not enforced in the current implementation ** if one or more of following conditions are true: ** **
    **
  • The limit value is set to zero. **
  • Memory accounting is disabled using a combination of the ** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and ** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. **
  • An alternative page cache implementation is specified using ** [sqlite3_config]([SQLITE_CONFIG_PCACHE2],...). **
  • The page cache allocates from its own memory pool supplied ** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than ** from the heap. **
)^ ** ** The circumstances under which SQLite will enforce the heap limits may ** changes in future releases of SQLite. */ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N); /* ** CAPI3REF: Deprecated Soft Heap Limit Interface ** DEPRECATED ** ** This is a deprecated version of the [sqlite3_soft_heap_limit64()] ** interface. This routine is provided for historical compatibility ** only. All new applications should use the ** [sqlite3_soft_heap_limit64()] interface rather than this one. */ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); /* ** CAPI3REF: Extract Metadata About A Column Of A Table ** METHOD: sqlite3 ** ** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns ** information about column C of table T in database D ** on [database connection] X.)^ ^The sqlite3_table_column_metadata() ** interface returns SQLITE_OK and fills in the non-NULL pointers in ** the final five arguments with appropriate values if the specified ** column exists. ^The sqlite3_table_column_metadata() interface returns ** SQLITE_ERROR if the specified column does not exist. ** ^If the column-name parameter to sqlite3_table_column_metadata() is a ** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it ** does not. If the table name parameter T in a call to ** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is ** undefined behavior. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^(The second parameter is either the name of the database ** (i.e. "main", "temp", or an attached database) containing the specified ** table or NULL.)^ ^If it is NULL, then all attached databases are searched ** for the table using the same algorithm used by the database engine to ** resolve unqualified table references. ** ** ^The third and fourth parameters to this function are the table and column ** name of the desired column, respectively. ** ** ^Metadata is returned by writing to the memory locations passed as the 5th ** and subsequent parameters to this function. ^Any of these arguments may be ** NULL, in which case the corresponding element of metadata is omitted. ** ** ^(
** **
Parameter Output
Type
Description ** **
5th const char* Data type **
6th const char* Name of default collation sequence **
7th int True if column has a NOT NULL constraint **
8th int True if column is part of the PRIMARY KEY **
9th int True if column is [AUTOINCREMENT] **
**
)^ ** ** ^The memory pointed to by the character pointers returned for the ** declaration type and collation sequence is valid until the next ** call to any SQLite API function. ** ** ^If the specified table is actually a view, an [error code] is returned. ** ** ^If the specified column is "rowid", "oid" or "_rowid_" and the table ** is not a [WITHOUT ROWID] table and an ** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output ** parameters are set for the explicitly declared column. ^(If there is no ** [INTEGER PRIMARY KEY] column, then the outputs ** for the [rowid] are set as follows: ** **
**     data type: "INTEGER"
**     collation sequence: "BINARY"
**     not null: 0
**     primary key: 1
**     auto increment: 0
** 
)^ ** ** ^This function causes all database schemas to be read from disk and ** parsed, if that has not already been done, and returns an error if ** any errors are encountered while loading the schema. */ SQLITE_API int sqlite3_table_column_metadata( sqlite3 *db, /* Connection handle */ const char *zDbName, /* Database name or NULL */ const char *zTableName, /* Table name */ const char *zColumnName, /* Column name */ char const **pzDataType, /* OUTPUT: Declared data type */ char const **pzCollSeq, /* OUTPUT: Collation sequence name */ int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ int *pPrimaryKey, /* OUTPUT: True if column part of PK */ int *pAutoinc /* OUTPUT: True if column is auto-increment */ ); /* ** CAPI3REF: Load An Extension ** METHOD: sqlite3 ** ** ^This interface loads an SQLite extension library from the named file. ** ** ^The sqlite3_load_extension() interface attempts to load an ** [SQLite extension] library contained in the file zFile. If ** the file cannot be loaded directly, attempts are made to load ** with various operating-system specific extensions added. ** So for example, if "samplelib" cannot be loaded, then names like ** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might ** be tried also. ** ** ^The entry point is zProc. ** ^(zProc may be 0, in which case SQLite will try to come up with an ** entry point name on its own. It first tries "sqlite3_extension_init". ** If that does not work, it constructs a name "sqlite3_X_init" where the ** X is consists of the lower-case equivalent of all ASCII alphabetic ** characters in the filename from the last "/" to the first following ** "." and omitting any initial "lib".)^ ** ^The sqlite3_load_extension() interface returns ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** ^If an error occurs and pzErrMsg is not 0, then the ** [sqlite3_load_extension()] interface shall attempt to ** fill *pzErrMsg with error message text stored in memory ** obtained from [sqlite3_malloc()]. The calling function ** should free this memory by calling [sqlite3_free()]. ** ** ^Extension loading must be enabled using ** [sqlite3_enable_load_extension()] or ** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL) ** prior to calling this API, ** otherwise an error will be returned. ** ** Security warning: It is recommended that the ** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this ** interface. The use of the [sqlite3_enable_load_extension()] interface ** should be avoided. This will keep the SQL function [load_extension()] ** disabled and prevent SQL injections from giving attackers ** access to extension loading capabilities. ** ** See also the [load_extension() SQL function]. */ SQLITE_API int sqlite3_load_extension( sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Derived from zFile if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ); /* ** CAPI3REF: Enable Or Disable Extension Loading ** METHOD: sqlite3 ** ** ^So as not to open security holes in older applications that are ** unprepared to deal with [extension loading], and as a means of disabling ** [extension loading] while evaluating user-entered SQL, the following API ** is provided to turn the [sqlite3_load_extension()] mechanism on and off. ** ** ^Extension loading is off by default. ** ^Call the sqlite3_enable_load_extension() routine with onoff==1 ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. ** ** ^This interface enables or disables both the C-API ** [sqlite3_load_extension()] and the SQL function [load_extension()]. ** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) ** to enable or disable only the C-API.)^ ** ** Security warning: It is recommended that extension loading ** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method ** rather than this interface, so the [load_extension()] SQL function ** remains disabled. This will prevent SQL injections from giving attackers ** access to extension loading capabilities. */ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); /* ** CAPI3REF: Automatically Load Statically Linked Extensions ** ** ^This interface causes the xEntryPoint() function to be invoked for ** each new [database connection] that is created. The idea here is that ** xEntryPoint() is the entry point for a statically linked [SQLite extension] ** that is to be automatically loaded into all new database connections. ** ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three ** arguments and expects an integer result as if the signature of the ** entry point where as follows: ** **
**    int xEntryPoint(
**      sqlite3 *db,
**      const char **pzErrMsg,
**      const struct sqlite3_api_routines *pThunk
**    );
** 
)^ ** ** If the xEntryPoint routine encounters an error, it should make *pzErrMsg ** point to an appropriate error message (obtained from [sqlite3_mprintf()]) ** and return an appropriate [error code]. ^SQLite ensures that *pzErrMsg ** is NULL before calling the xEntryPoint(). ^SQLite will invoke ** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns. ^If any ** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()], ** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail. ** ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already ** on the list of automatic extensions is a harmless no-op. ^No entry point ** will be called more than once for each database connection that is opened. ** ** See also: [sqlite3_reset_auto_extension()] ** and [sqlite3_cancel_auto_extension()] */ SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void)); /* ** CAPI3REF: Cancel Automatic Extension Loading ** ** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the ** initialization routine X that was registered using a prior call to ** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)] ** routine returns 1 if initialization routine X was successfully ** unregistered and it returns 0 if X was not on the list of initialization ** routines. */ SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void)); /* ** CAPI3REF: Reset Automatic Extension Loading ** ** ^This interface disables all automatic extensions previously ** registered using [sqlite3_auto_extension()]. */ SQLITE_API void sqlite3_reset_auto_extension(void); /* ** Structures used by the virtual table interface */ typedef struct sqlite3_vtab sqlite3_vtab; typedef struct sqlite3_index_info sqlite3_index_info; typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; typedef struct sqlite3_module sqlite3_module; /* ** CAPI3REF: Virtual Table Object ** KEYWORDS: sqlite3_module {virtual table module} ** ** This structure, sometimes called a "virtual table module", ** defines the implementation of a [virtual table]. ** This structure consists mostly of methods for the module. ** ** ^A virtual table module is created by filling in a persistent ** instance of this structure and passing a pointer to that instance ** to [sqlite3_create_module()] or [sqlite3_create_module_v2()]. ** ^The registration remains valid until it is replaced by a different ** module or until the [database connection] closes. The content ** of this structure must not change while it is registered with ** any database connection. */ struct sqlite3_module { int iVersion; int (*xCreate)(sqlite3*, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char**); int (*xConnect)(sqlite3*, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char**); int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); int (*xDisconnect)(sqlite3_vtab *pVTab); int (*xDestroy)(sqlite3_vtab *pVTab); int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); int (*xClose)(sqlite3_vtab_cursor*); int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, sqlite3_value **argv); int (*xNext)(sqlite3_vtab_cursor*); int (*xEof)(sqlite3_vtab_cursor*); int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); int (*xBegin)(sqlite3_vtab *pVTab); int (*xSync)(sqlite3_vtab *pVTab); int (*xCommit)(sqlite3_vtab *pVTab); int (*xRollback)(sqlite3_vtab *pVTab); int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg); int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); /* The methods above are in version 1 of the sqlite_module object. Those ** below are for version 2 and greater. */ int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); /* The methods above are in versions 1 and 2 of the sqlite_module object. ** Those below are for version 3 and greater. */ int (*xShadowName)(const char*); /* The methods above are in versions 1 through 3 of the sqlite_module object. ** Those below are for version 4 and greater. */ int (*xIntegrity)(sqlite3_vtab *pVTab, const char *zSchema, const char *zTabName, int mFlags, char **pzErr); }; /* ** CAPI3REF: Virtual Table Indexing Information ** KEYWORDS: sqlite3_index_info ** ** The sqlite3_index_info structure and its substructures is used as part ** of the [virtual table] interface to ** pass information into and receive the reply from the [xBestIndex] ** method of a [virtual table module]. The fields under **Inputs** are the ** inputs to xBestIndex and are read-only. xBestIndex inserts its ** results into the **Outputs** fields. ** ** ^(The aConstraint[] array records WHERE clause constraints of the form: ** **
column OP expr
** ** where OP is =, <, <=, >, or >=.)^ ^(The particular operator is ** stored in aConstraint[].op using one of the ** [SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_ values].)^ ** ^(The index of the column is stored in ** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the ** expr on the right-hand side can be evaluated (and thus the constraint ** is usable) and false if it cannot.)^ ** ** ^The optimizer automatically inverts terms of the form "expr OP column" ** and makes other simplifications to the WHERE clause in an attempt to ** get as many WHERE clause terms into the form shown above as possible. ** ^The aConstraint[] array only reports WHERE clause terms that are ** relevant to the particular virtual table being queried. ** ** ^Information about the ORDER BY clause is stored in aOrderBy[]. ** ^Each term of aOrderBy records a column of the ORDER BY clause. ** ** The colUsed field indicates which columns of the virtual table may be ** required by the current scan. Virtual table columns are numbered from ** zero in the order in which they appear within the CREATE TABLE statement ** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62), ** the corresponding bit is set within the colUsed mask if the column may be ** required by SQLite. If the table has at least 64 columns and any column ** to the right of the first 63 is required, then bit 63 of colUsed is also ** set. In other words, column iCol may be required if the expression ** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to ** non-zero. ** ** The [xBestIndex] method must fill aConstraintUsage[] with information ** about what parameters to pass to xFilter. ^If argvIndex>0 then ** the right-hand side of the corresponding aConstraint[] is evaluated ** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit ** is true, then the constraint is assumed to be fully handled by the ** virtual table and might not be checked again by the byte code.)^ ^(The ** aConstraintUsage[].omit flag is an optimization hint. When the omit flag ** is left in its default setting of false, the constraint will always be ** checked separately in byte code. If the omit flag is change to true, then ** the constraint may or may not be checked in byte code. In other words, ** when the omit flag is true there is no guarantee that the constraint will ** not be checked again using byte code.)^ ** ** ^The idxNum and idxStr values are recorded and passed into the ** [xFilter] method. ** ^[sqlite3_free()] is used to free idxStr if and only if ** needToFreeIdxStr is true. ** ** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in ** the correct order to satisfy the ORDER BY clause so that no separate ** sorting step is required. ** ** ^The estimatedCost value is an estimate of the cost of a particular ** strategy. A cost of N indicates that the cost of the strategy is similar ** to a linear scan of an SQLite table with N rows. A cost of log(N) ** indicates that the expense of the operation is similar to that of a ** binary search on a unique indexed field of an SQLite table with N rows. ** ** ^The estimatedRows value is an estimate of the number of rows that ** will be returned by the strategy. ** ** The xBestIndex method may optionally populate the idxFlags field with a ** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - ** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite ** assumes that the strategy may visit at most one row. ** ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then ** SQLite also assumes that if a call to the xUpdate() method is made as ** part of the same statement to delete or update a virtual table row and the ** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback ** any database changes. In other words, if the xUpdate() returns ** SQLITE_CONSTRAINT, the database contents must be exactly as they were ** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not ** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by ** the xUpdate method are automatically rolled back by SQLite. ** ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info ** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). ** If a virtual table extension is ** used with an SQLite version earlier than 3.8.2, the results of attempting ** to read or write the estimatedRows field are undefined (but are likely ** to include crashing the application). The estimatedRows field should ** therefore only be used if [sqlite3_libversion_number()] returns a ** value greater than or equal to 3008002. Similarly, the idxFlags field ** was added for [version 3.9.0] ([dateof:3.9.0]). ** It may therefore only be used if ** sqlite3_libversion_number() returns a value greater than or equal to ** 3009000. */ struct sqlite3_index_info { /* Inputs */ int nConstraint; /* Number of entries in aConstraint */ struct sqlite3_index_constraint { int iColumn; /* Column constrained. -1 for ROWID */ unsigned char op; /* Constraint operator */ unsigned char usable; /* True if this constraint is usable */ int iTermOffset; /* Used internally - xBestIndex should ignore */ } *aConstraint; /* Table of WHERE clause constraints */ int nOrderBy; /* Number of terms in the ORDER BY clause */ struct sqlite3_index_orderby { int iColumn; /* Column number */ unsigned char desc; /* True for DESC. False for ASC. */ } *aOrderBy; /* The ORDER BY clause */ /* Outputs */ struct sqlite3_index_constraint_usage { int argvIndex; /* if >0, constraint is part of argv to xFilter */ unsigned char omit; /* Do not code a test for this constraint */ } *aConstraintUsage; int idxNum; /* Number used to identify the index */ char *idxStr; /* String, possibly obtained from sqlite3_malloc */ int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ int orderByConsumed; /* True if output is already ordered */ double estimatedCost; /* Estimated cost of using this index */ /* Fields below are only available in SQLite 3.8.2 and later */ sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ /* Fields below are only available in SQLite 3.9.0 and later */ int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */ /* Fields below are only available in SQLite 3.10.0 and later */ sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */ }; /* ** CAPI3REF: Virtual Table Scan Flags ** ** Virtual table implementations are allowed to set the ** [sqlite3_index_info].idxFlags field to some combination of ** these bits. */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes ** ** These macros define the allowed values for the ** [sqlite3_index_info].aConstraint[].op field. Each value represents ** an operator that is part of a constraint term in the WHERE clause of ** a query that uses a [virtual table]. ** ** ^The left-hand operand of the operator is given by the corresponding ** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand ** operand is the rowid. ** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET ** operators have no left-hand operand, and so for those operators the ** corresponding aConstraint[].iColumn is meaningless and should not be ** used. ** ** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through ** value 255 are reserved to represent functions that are overloaded ** by the [xFindFunction|xFindFunction method] of the virtual table ** implementation. ** ** The right-hand operands for each constraint might be accessible using ** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand ** operand is only available if it appears as a single constant literal ** in the input SQL. If the right-hand operand is another column or an ** expression (even a constant expression) or a parameter, then the ** sqlite3_vtab_rhs_value() probably will not be able to extract it. ** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and ** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand ** and hence calls to sqlite3_vtab_rhs_value() for those operators will ** always return SQLITE_NOTFOUND. ** ** The collating sequence to be used for comparison can be found using ** the [sqlite3_vtab_collation()] interface. For most real-world virtual ** tables, the collating sequence of constraints does not matter (for example ** because the constraints are numeric) and so the sqlite3_vtab_collation() ** interface is not commonly needed. */ #define SQLITE_INDEX_CONSTRAINT_EQ 2 #define SQLITE_INDEX_CONSTRAINT_GT 4 #define SQLITE_INDEX_CONSTRAINT_LE 8 #define SQLITE_INDEX_CONSTRAINT_LT 16 #define SQLITE_INDEX_CONSTRAINT_GE 32 #define SQLITE_INDEX_CONSTRAINT_MATCH 64 #define SQLITE_INDEX_CONSTRAINT_LIKE 65 #define SQLITE_INDEX_CONSTRAINT_GLOB 66 #define SQLITE_INDEX_CONSTRAINT_REGEXP 67 #define SQLITE_INDEX_CONSTRAINT_NE 68 #define SQLITE_INDEX_CONSTRAINT_ISNOT 69 #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 #define SQLITE_INDEX_CONSTRAINT_ISNULL 71 #define SQLITE_INDEX_CONSTRAINT_IS 72 #define SQLITE_INDEX_CONSTRAINT_LIMIT 73 #define SQLITE_INDEX_CONSTRAINT_OFFSET 74 #define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 /* ** CAPI3REF: Register A Virtual Table Implementation ** METHOD: sqlite3 ** ** ^These routines are used to register a new [virtual table module] name. ** ^Module names must be registered before ** creating a new [virtual table] using the module and before using a ** preexisting [virtual table] for the module. ** ** ^The module name is registered on the [database connection] specified ** by the first parameter. ^The name of the module is given by the ** second parameter. ^The third parameter is a pointer to ** the implementation of the [virtual table module]. ^The fourth ** parameter is an arbitrary client data pointer that is passed through ** into the [xCreate] and [xConnect] methods of the virtual table module ** when a new virtual table is be being created or reinitialized. ** ** ^The sqlite3_create_module_v2() interface has a fifth parameter which ** is a pointer to a destructor for the pClientData. ^SQLite will ** invoke the destructor function (if it is not NULL) when SQLite ** no longer needs the pClientData pointer. ^The destructor will also ** be invoked if the call to sqlite3_create_module_v2() fails. ** ^The sqlite3_create_module() ** interface is equivalent to sqlite3_create_module_v2() with a NULL ** destructor. ** ** ^If the third parameter (the pointer to the sqlite3_module object) is ** NULL then no new module is created and any existing modules with the ** same name are dropped. ** ** See also: [sqlite3_drop_modules()] */ SQLITE_API int sqlite3_create_module( sqlite3 *db, /* SQLite connection to register module with */ const char *zName, /* Name of the module */ const sqlite3_module *p, /* Methods for the module */ void *pClientData /* Client data for xCreate/xConnect */ ); SQLITE_API int sqlite3_create_module_v2( sqlite3 *db, /* SQLite connection to register module with */ const char *zName, /* Name of the module */ const sqlite3_module *p, /* Methods for the module */ void *pClientData, /* Client data for xCreate/xConnect */ void(*xDestroy)(void*) /* Module destructor function */ ); /* ** CAPI3REF: Remove Unnecessary Virtual Table Implementations ** METHOD: sqlite3 ** ** ^The sqlite3_drop_modules(D,L) interface removes all virtual ** table modules from database connection D except those named on list L. ** The L parameter must be either NULL or a pointer to an array of pointers ** to strings where the array is terminated by a single NULL pointer. ** ^If the L parameter is NULL, then all virtual table modules are removed. ** ** See also: [sqlite3_create_module()] */ SQLITE_API int sqlite3_drop_modules( sqlite3 *db, /* Remove modules from this connection */ const char **azKeep /* Except, do not remove the ones named here */ ); /* ** CAPI3REF: Virtual Table Instance Object ** KEYWORDS: sqlite3_vtab ** ** Every [virtual table module] implementation uses a subclass ** of this object to describe a particular instance ** of the [virtual table]. Each subclass will ** be tailored to the specific needs of the module implementation. ** The purpose of this superclass is to define certain fields that are ** common to all module implementations. ** ** ^Virtual tables methods can set an error message by assigning a ** string obtained from [sqlite3_mprintf()] to zErrMsg. The method should ** take care that any prior string is freed by a call to [sqlite3_free()] ** prior to assigning a new string to zErrMsg. ^After the error message ** is delivered up to the client application, the string will be automatically ** freed by sqlite3_free() and the zErrMsg field will be zeroed. */ struct sqlite3_vtab { const sqlite3_module *pModule; /* The module for this virtual table */ int nRef; /* Number of open cursors */ char *zErrMsg; /* Error message from sqlite3_mprintf() */ /* Virtual table implementations will typically add additional fields */ }; /* ** CAPI3REF: Virtual Table Cursor Object ** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor} ** ** Every [virtual table module] implementation uses a subclass of the ** following structure to describe cursors that point into the ** [virtual table] and are used ** to loop through the virtual table. Cursors are created using the ** [sqlite3_module.xOpen | xOpen] method of the module and are destroyed ** by the [sqlite3_module.xClose | xClose] method. Cursors are used ** by the [xFilter], [xNext], [xEof], [xColumn], and [xRowid] methods ** of the module. Each module implementation will define ** the content of a cursor structure to suit its own needs. ** ** This superclass exists in order to define fields of the cursor that ** are common to all implementations. */ struct sqlite3_vtab_cursor { sqlite3_vtab *pVtab; /* Virtual table of this cursor */ /* Virtual table implementations will typically add additional fields */ }; /* ** CAPI3REF: Declare The Schema Of A Virtual Table ** ** ^The [xCreate] and [xConnect] methods of a ** [virtual table module] call this interface ** to declare the format (the names and datatypes of the columns) of ** the virtual tables they implement. */ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL); /* ** CAPI3REF: Overload A Function For A Virtual Table ** METHOD: sqlite3 ** ** ^(Virtual tables can provide alternative implementations of functions ** using the [xFindFunction] method of the [virtual table module]. ** But global versions of those functions ** must exist in order to be overloaded.)^ ** ** ^(This API makes sure a global version of a function with a particular ** name and number of parameters exists. If no such function exists ** before this API is called, a new function is created.)^ ^The implementation ** of the new function always causes an exception to be thrown. So ** the new function is not good for anything by itself. Its only ** purpose is to be a placeholder function that can be overloaded ** by a [virtual table]. */ SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); /* ** CAPI3REF: A Handle To An Open BLOB ** KEYWORDS: {BLOB handle} {BLOB handles} ** ** An instance of this object represents an open BLOB on which ** [sqlite3_blob_open | incremental BLOB I/O] can be performed. ** ^Objects of this type are created by [sqlite3_blob_open()] ** and destroyed by [sqlite3_blob_close()]. ** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces ** can be used to read or write small subsections of the BLOB. ** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes. */ typedef struct sqlite3_blob sqlite3_blob; /* ** CAPI3REF: Open A BLOB For Incremental I/O ** METHOD: sqlite3 ** CONSTRUCTOR: sqlite3_blob ** ** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located ** in row iRow, column zColumn, table zTable in database zDb; ** in other words, the same BLOB that would be selected by: ** **
**     SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
** 
)^ ** ** ^(Parameter zDb is not the filename that contains the database, but ** rather the symbolic name of the database. For attached databases, this is ** the name that appears after the AS keyword in the [ATTACH] statement. ** For the main database file, the database name is "main". For TEMP ** tables, the database name is "temp".)^ ** ** ^If the flags parameter is non-zero, then the BLOB is opened for read ** and write access. ^If the flags parameter is zero, the BLOB is opened for ** read-only access. ** ** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored ** in *ppBlob. Otherwise an [error code] is returned and, unless the error ** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided ** the API is not misused, it is always safe to call [sqlite3_blob_close()] ** on *ppBlob after this function it returns. ** ** This function fails with SQLITE_ERROR if any of the following are true: **
    **
  • ^(Database zDb does not exist)^, **
  • ^(Table zTable does not exist within database zDb)^, **
  • ^(Table zTable is a WITHOUT ROWID table)^, **
  • ^(Column zColumn does not exist)^, **
  • ^(Row iRow is not present in the table)^, **
  • ^(The specified column of row iRow contains a value that is not ** a TEXT or BLOB value)^, **
  • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE ** constraint and the blob is being opened for read/write access)^, **
  • ^([foreign key constraints | Foreign key constraints] are enabled, ** column zColumn is part of a [child key] definition and the blob is ** being opened for read/write access)^. **
** ** ^Unless it returns SQLITE_MISUSE, this function sets the ** [database connection] error code and message accessible via ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** ** A BLOB referenced by sqlite3_blob_open() may be read using the ** [sqlite3_blob_read()] interface and modified by using ** [sqlite3_blob_write()]. The [BLOB handle] can be moved to a ** different row of the same table using the [sqlite3_blob_reopen()] ** interface. However, the column, table, or database of a [BLOB handle] ** cannot be changed after the [BLOB handle] is opened. ** ** ^(If the row that a BLOB handle points to is modified by an ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects ** then the BLOB handle is marked as "expired". ** This is true if any column of the row is changed, even a column ** other than the one the BLOB handle is open on.)^ ** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for ** an expired BLOB handle fail with a return code of [SQLITE_ABORT]. ** ^(Changes written into a BLOB prior to the BLOB expiring are not ** rolled back by the expiration of the BLOB. Such changes will eventually ** commit if the transaction continues to completion.)^ ** ** ^Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. ^The size of a blob may not be changed by this ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces ** and the built-in [zeroblob] SQL function may be used to create a ** zero-filled blob to read or write using the incremental-blob interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually ** be released by a call to [sqlite3_blob_close()]. ** ** See also: [sqlite3_blob_close()], ** [sqlite3_blob_reopen()], [sqlite3_blob_read()], ** [sqlite3_blob_bytes()], [sqlite3_blob_write()]. */ SQLITE_API int sqlite3_blob_open( sqlite3*, const char *zDb, const char *zTable, const char *zColumn, sqlite3_int64 iRow, int flags, sqlite3_blob **ppBlob ); /* ** CAPI3REF: Move a BLOB Handle to a New Row ** METHOD: sqlite3_blob ** ** ^This function is used to move an existing [BLOB handle] so that it points ** to a different row of the same database table. ^The new row is identified ** by the rowid value passed as the second argument. Only the row can be ** changed. ^The database, table and column on which the blob handle is open ** remain the same. Moving an existing [BLOB handle] to a new row is ** faster than closing the existing handle and opening a new one. ** ** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] - ** it must exist and there must be either a blob or text value stored in ** the nominated column.)^ ^If the new row is not present in the table, or if ** it does not contain a blob or text value, or if another error occurs, an ** SQLite error code is returned and the blob handle is considered aborted. ** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or ** [sqlite3_blob_reopen()] on an aborted blob handle immediately return ** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle ** always returns zero. ** ** ^This function sets the database handle error code and message. */ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); /* ** CAPI3REF: Close A BLOB Handle ** DESTRUCTOR: sqlite3_blob ** ** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed ** unconditionally. Even if this routine returns an error code, the ** handle is still closed.)^ ** ** ^If the blob handle being closed was opened for read-write access, and if ** the database is in auto-commit mode and there are no other open read-write ** blob handles or active write statements, the current transaction is ** committed. ^If an error occurs while committing the transaction, an error ** code is returned and the transaction rolled back. ** ** Calling this function with an argument that is not a NULL pointer or an ** open blob handle results in undefined behavior. ^Calling this routine ** with a null pointer (such as would be returned by a failed call to ** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function ** is passed a valid open blob handle, the values returned by the ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. */ SQLITE_API int sqlite3_blob_close(sqlite3_blob *); /* ** CAPI3REF: Return The Size Of An Open BLOB ** METHOD: sqlite3_blob ** ** ^Returns the size in bytes of the BLOB accessible via the ** successfully opened [BLOB handle] in its only argument. ^The ** incremental blob I/O routines can only read or overwriting existing ** blob content; they cannot change the size of a blob. ** ** This routine only works on a [BLOB handle] which has been created ** by a prior successful call to [sqlite3_blob_open()] and which has not ** been closed by [sqlite3_blob_close()]. Passing any other pointer in ** to this routine results in undefined and probably undesirable behavior. */ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *); /* ** CAPI3REF: Read Data From A BLOB Incrementally ** METHOD: sqlite3_blob ** ** ^(This function is used to read data from an open [BLOB handle] into a ** caller-supplied buffer. N bytes of data are copied into buffer Z ** from the open BLOB, starting at offset iOffset.)^ ** ** ^If offset iOffset is less than N bytes from the end of the BLOB, ** [SQLITE_ERROR] is returned and no data is read. ^If N or iOffset is ** less than zero, [SQLITE_ERROR] is returned and no data is read. ** ^The size of the blob (and hence the maximum value of N+iOffset) ** can be determined using the [sqlite3_blob_bytes()] interface. ** ** ^An attempt to read from an expired [BLOB handle] fails with an ** error code of [SQLITE_ABORT]. ** ** ^(On success, sqlite3_blob_read() returns SQLITE_OK. ** Otherwise, an [error code] or an [extended error code] is returned.)^ ** ** This routine only works on a [BLOB handle] which has been created ** by a prior successful call to [sqlite3_blob_open()] and which has not ** been closed by [sqlite3_blob_close()]. Passing any other pointer in ** to this routine results in undefined and probably undesirable behavior. ** ** See also: [sqlite3_blob_write()]. */ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); /* ** CAPI3REF: Write Data Into A BLOB Incrementally ** METHOD: sqlite3_blob ** ** ^(This function is used to write data into an open [BLOB handle] from a ** caller-supplied buffer. N bytes of data are copied from the buffer Z ** into the open BLOB, starting at offset iOffset.)^ ** ** ^(On success, sqlite3_blob_write() returns SQLITE_OK. ** Otherwise, an [error code] or an [extended error code] is returned.)^ ** ^Unless SQLITE_MISUSE is returned, this function sets the ** [database connection] error code and message accessible via ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** ** ^If the [BLOB handle] passed as the first argument was not opened for ** writing (the flags parameter to [sqlite3_blob_open()] was zero), ** this function returns [SQLITE_READONLY]. ** ** This function may only modify the contents of the BLOB; it is ** not possible to increase the size of a BLOB using this API. ** ^If offset iOffset is less than N bytes from the end of the BLOB, ** [SQLITE_ERROR] is returned and no data is written. The size of the ** BLOB (and hence the maximum value of N+iOffset) can be determined ** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less ** than zero [SQLITE_ERROR] is returned and no data is written. ** ** ^An attempt to write to an expired [BLOB handle] fails with an ** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred ** before the [BLOB handle] expired are not rolled back by the ** expiration of the handle, though of course those changes might ** have been overwritten by the statement that expired the BLOB handle ** or by other independent statements. ** ** This routine only works on a [BLOB handle] which has been created ** by a prior successful call to [sqlite3_blob_open()] and which has not ** been closed by [sqlite3_blob_close()]. Passing any other pointer in ** to this routine results in undefined and probably undesirable behavior. ** ** See also: [sqlite3_blob_read()]. */ SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); /* ** CAPI3REF: Virtual File System Objects ** ** A virtual filesystem (VFS) is an [sqlite3_vfs] object ** that SQLite uses to interact ** with the underlying operating system. Most SQLite builds come with a ** single default VFS that is appropriate for the host computer. ** New VFSes can be registered and existing VFSes can be unregistered. ** The following interfaces are provided. ** ** ^The sqlite3_vfs_find() interface returns a pointer to a VFS given its name. ** ^Names are case sensitive. ** ^Names are zero-terminated UTF-8 strings. ** ^If there is no match, a NULL pointer is returned. ** ^If zVfsName is NULL then the default VFS is returned. ** ** ^New VFSes are registered with sqlite3_vfs_register(). ** ^Each new VFS becomes the default VFS if the makeDflt flag is set. ** ^The same VFS can be registered multiple times without injury. ** ^To make an existing VFS into the default VFS, register it again ** with the makeDflt flag set. If two different VFSes with the ** same name are registered, the behavior is undefined. If a ** VFS is registered with a name that is NULL or an empty string, ** then the behavior is undefined. ** ** ^Unregister a VFS with the sqlite3_vfs_unregister() interface. ** ^(If the default VFS is unregistered, another VFS is chosen as ** the default. The choice for the new VFS is arbitrary.)^ */ SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); /* ** CAPI3REF: Mutexes ** ** The SQLite core uses these routines for thread ** synchronization. Though they are intended for internal ** use by SQLite, code that links against SQLite is ** permitted to use any of these routines. ** ** The SQLite source code contains multiple implementations ** of these mutex routines. An appropriate implementation ** is selected automatically at compile-time. The following ** implementations are available in the SQLite core: ** **
    **
  • SQLITE_MUTEX_PTHREADS **
  • SQLITE_MUTEX_W32 **
  • SQLITE_MUTEX_NOOP **
** ** The SQLITE_MUTEX_NOOP implementation is a set of routines ** that does no real locking and is appropriate for use in ** a single-threaded application. The SQLITE_MUTEX_PTHREADS and ** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix ** and Windows. ** ** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor ** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex ** implementation is included with the library. In this case the ** application must supply a custom mutex implementation using the ** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function ** before calling sqlite3_initialize() or any other public sqlite3_ ** function that calls sqlite3_initialize(). ** ** ^The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() ** routine returns NULL if it is unable to allocate the requested ** mutex. The argument to sqlite3_mutex_alloc() must one of these ** integer constants: ** **
    **
  • SQLITE_MUTEX_FAST **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MAIN **
  • SQLITE_MUTEX_STATIC_MEM **
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU **
  • SQLITE_MUTEX_STATIC_PMEM **
  • SQLITE_MUTEX_STATIC_APP1 **
  • SQLITE_MUTEX_STATIC_APP2 **
  • SQLITE_MUTEX_STATIC_APP3 **
  • SQLITE_MUTEX_STATIC_VFS1 **
  • SQLITE_MUTEX_STATIC_VFS2 **
  • SQLITE_MUTEX_STATIC_VFS3 **
** ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) ** cause sqlite3_mutex_alloc() to create ** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does ** not want to. SQLite will only request a recursive mutex in ** cases where it really needs one. If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other ** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return ** a pointer to a static preexisting mutex. ^Nine static mutexes are ** used by the current version of SQLite. Future versions of SQLite ** may add additional static mutexes. Static mutexes are for internal ** use by SQLite only. Applications that use SQLite mutexes should ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or ** SQLITE_MUTEX_RECURSIVE. ** ** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() ** returns a different mutex on every call. ^For the static ** mutex types, the same mutex is returned on every call that has ** the same type number. ** ** ^The sqlite3_mutex_free() routine deallocates a previously ** allocated dynamic mutex. Attempting to deallocate a static ** mutex results in undefined behavior. ** ** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt ** to enter a mutex. ^If another thread is already within the mutex, ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return ** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK] ** upon successful entry. ^(Mutexes created using ** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread. ** In such cases, the ** mutex must be exited an equal number of times before another thread ** can enter.)^ If the same thread tries to enter any mutex other ** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. ** ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() ** will always return SQLITE_BUSY. In most cases the SQLite core only uses ** sqlite3_mutex_try() as an optimization, so this is acceptable ** behavior. The exceptions are unix builds that set the ** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working ** sqlite3_mutex_try() is required.)^ ** ** ^The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. The behavior ** is undefined if the mutex is not currently entered by the ** calling thread or is not currently allocated. ** ** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), ** sqlite3_mutex_leave(), or sqlite3_mutex_free() is a NULL pointer, ** then any of the four routines behaves as a no-op. ** ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. */ SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int); SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*); SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*); SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*); SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); /* ** CAPI3REF: Mutex Methods Object ** ** An instance of this structure defines the low-level routines ** used to allocate and use mutexes. ** ** Usually, the default mutex implementations provided by SQLite are ** sufficient, however the application has the option of substituting a custom ** implementation for specialized deployments or systems for which SQLite ** does not provide a suitable implementation. In this case, the application ** creates and populates an instance of this structure to pass ** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option. ** Additionally, an instance of this structure can be used as an ** output variable when querying the system for the current mutex ** implementation, using the [SQLITE_CONFIG_GETMUTEX] option. ** ** ^The xMutexInit method defined by this structure is invoked as ** part of system initialization by the sqlite3_initialize() function. ** ^The xMutexInit routine is called by SQLite exactly once for each ** effective call to [sqlite3_initialize()]. ** ** ^The xMutexEnd method defined by this structure is invoked as ** part of system shutdown by the sqlite3_shutdown() function. The ** implementation of this method is expected to release all outstanding ** resources obtained by the mutex methods implementation, especially ** those obtained by the xMutexInit method. ^The xMutexEnd() ** interface is invoked exactly once for each call to [sqlite3_shutdown()]. ** ** ^(The remaining seven methods defined by this structure (xMutexAlloc, ** xMutexFree, xMutexEnter, xMutexTry, xMutexLeave, xMutexHeld and ** xMutexNotheld) implement the following interfaces (respectively): ** **
    **
  • [sqlite3_mutex_alloc()]
  • **
  • [sqlite3_mutex_free()]
  • **
  • [sqlite3_mutex_enter()]
  • **
  • [sqlite3_mutex_try()]
  • **
  • [sqlite3_mutex_leave()]
  • **
  • [sqlite3_mutex_held()]
  • **
  • [sqlite3_mutex_notheld()]
  • **
)^ ** ** The only difference is that the public sqlite3_XXX functions enumerated ** above silently ignore any invocations that pass a NULL pointer instead ** of a valid mutex handle. The implementations of the methods defined ** by this structure are not required to handle this case. The results ** of passing a NULL pointer instead of a valid mutex handle are undefined ** (i.e. it is acceptable to provide an implementation that segfaults if ** it is passed a NULL pointer). ** ** The xMutexInit() method must be threadsafe. It must be harmless to ** invoke xMutexInit() multiple times within the same process and without ** intervening calls to xMutexEnd(). Second and subsequent calls to ** xMutexInit() must be no-ops. ** ** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()] ** and its associates). Similarly, xMutexAlloc() must not use SQLite memory ** allocation for a static mutex. ^However xMutexAlloc() may use SQLite ** memory allocation for a fast or recursive mutex. ** ** ^SQLite will invoke the xMutexEnd() method when [sqlite3_shutdown()] is ** called, but only if the prior call to xMutexInit returned SQLITE_OK. ** If xMutexInit fails in any way, it is expected to clean up after itself ** prior to returning. */ typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; struct sqlite3_mutex_methods { int (*xMutexInit)(void); int (*xMutexEnd)(void); sqlite3_mutex *(*xMutexAlloc)(int); void (*xMutexFree)(sqlite3_mutex *); void (*xMutexEnter)(sqlite3_mutex *); int (*xMutexTry)(sqlite3_mutex *); void (*xMutexLeave)(sqlite3_mutex *); int (*xMutexHeld)(sqlite3_mutex *); int (*xMutexNotheld)(sqlite3_mutex *); }; /* ** CAPI3REF: Mutex Verification Routines ** ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines ** are intended for use inside assert() statements. The SQLite core ** never uses these routines except inside an assert() and applications ** are advised to follow the lead of the core. The SQLite core only ** provides implementations for these routines when it is compiled ** with the SQLITE_DEBUG flag. External mutex implementations ** are only required to provide these routines if SQLITE_DEBUG is ** defined and if NDEBUG is not defined. ** ** These routines should return true if the mutex in their argument ** is held or not held, respectively, by the calling thread. ** ** The implementation is not required to provide versions of these ** routines that actually work. If the implementation does not provide working ** versions of these routines, it should at least provide stubs that always ** return true so that one does not get spurious assertion failures. ** ** If the argument to sqlite3_mutex_held() is a NULL pointer then ** the routine should return 1. This seems counter-intuitive since ** clearly the mutex cannot be held if it does not exist. But ** the reason the mutex does not exist is because the build is not ** using mutexes. And we do not want the assert() containing the ** call to sqlite3_mutex_held() to fail, so a non-zero return is ** the appropriate thing to do. The sqlite3_mutex_notheld() ** interface should also return 1 when given a NULL pointer. */ #ifndef NDEBUG SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); #endif /* ** CAPI3REF: Mutex Types ** ** The [sqlite3_mutex_alloc()] interface takes a single argument ** which is one of these integer constants. ** ** The set of static mutexes may change from one SQLite release to the ** next. Applications that override the built-in mutex logic must be ** prepared to accommodate additional static mutexes. */ #define SQLITE_MUTEX_FAST 0 #define SQLITE_MUTEX_RECURSIVE 1 #define SQLITE_MUTEX_STATIC_MAIN 2 #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ #define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */ #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ #define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ #define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ #define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ #define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */ #define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */ #define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */ /* Legacy compatibility: */ #define SQLITE_MUTEX_STATIC_MASTER 2 /* ** CAPI3REF: Retrieve the mutex for a database connection ** METHOD: sqlite3 ** ** ^This interface returns a pointer the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. ** ^If the [threading mode] is Single-thread or Multi-thread then this ** routine returns a NULL pointer. */ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); /* ** CAPI3REF: Low-Level Control Of Database Files ** METHOD: sqlite3 ** KEYWORDS: {file control} ** ** ^The [sqlite3_file_control()] interface makes a direct call to the ** xFileControl method for the [sqlite3_io_methods] object associated ** with a particular database identified by the second argument. ^The ** name of the database is "main" for the main database or "temp" for the ** TEMP database, or the name that appears after the AS keyword for ** databases that are added using the [ATTACH] SQL command. ** ^A NULL pointer can be used in place of "main" to refer to the ** main database file. ** ^The third and fourth parameters to this routine ** are passed directly through to the second and third parameters of ** the xFileControl method. ^The return value of the xFileControl ** method becomes the return value of this routine. ** ** A few opcodes for [sqlite3_file_control()] are handled directly ** by the SQLite core and never invoke the ** sqlite3_io_methods.xFileControl method. ** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes ** a pointer to the underlying [sqlite3_file] object to be written into ** the space pointed to by the 4th parameter. The ** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns ** the [sqlite3_file] object associated with the journal file instead of ** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns ** a pointer to the underlying [sqlite3_vfs] object for the file. ** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter ** from the pager. ** ** ^If the second parameter (zDbName) does not match the name of any ** open database file, then SQLITE_ERROR is returned. ^This error ** code is not remembered and will not be recalled by [sqlite3_errcode()] ** or [sqlite3_errmsg()]. The underlying xFileControl method might ** also return SQLITE_ERROR. There is no way to distinguish between ** an incorrect zDbName and an SQLITE_ERROR return from the underlying ** xFileControl method. ** ** See also: [file control opcodes] */ SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); /* ** CAPI3REF: Testing Interface ** ** ^The sqlite3_test_control() interface is used to read out internal ** state of SQLite and to inject faults into SQLite for testing ** purposes. ^The first parameter is an operation code that determines ** the number, meaning, and operation of all subsequent parameters. ** ** This interface is not for use by applications. It exists solely ** for verifying the correct operation of the SQLite library. Depending ** on how the SQLite library is compiled, this interface might not exist. ** ** The details of the operation codes, their meanings, the parameters ** they take, and what they do are all subject to change without notice. ** Unlike most of the SQLite API, this function is not guaranteed to ** operate consistently from one release to the next. */ SQLITE_API int sqlite3_test_control(int op, ...); /* ** CAPI3REF: Testing Interface Operation Codes ** ** These constants are the valid operation code parameters used ** as the first argument to [sqlite3_test_control()]. ** ** These parameters and their meanings are subject to change ** without notice. These values are for testing purposes only. ** Applications should not use any of these parameters or the ** [sqlite3_test_control()] interface. */ #define SQLITE_TESTCTRL_FIRST 5 #define SQLITE_TESTCTRL_PRNG_SAVE 5 #define SQLITE_TESTCTRL_PRNG_RESTORE 6 #define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */ #define SQLITE_TESTCTRL_FK_NO_ACTION 7 #define SQLITE_TESTCTRL_BITVEC_TEST 8 #define SQLITE_TESTCTRL_FAULT_INSTALL 9 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 #define SQLITE_TESTCTRL_PENDING_BYTE 11 #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ #define SQLITE_TESTCTRL_JSON_SELFCHECK 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_IMPOSTER 25 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26 #define SQLITE_TESTCTRL_RESULT_INTREAL 27 #define SQLITE_TESTCTRL_PRNG_SEED 28 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 #define SQLITE_TESTCTRL_SEEK_COUNT 30 #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking ** ** These routines provide access to the set of SQL language keywords ** recognized by SQLite. Applications can uses these routines to determine ** whether or not a specific identifier needs to be escaped (for example, ** by enclosing in double-quotes) so as not to confuse the parser. ** ** The sqlite3_keyword_count() interface returns the number of distinct ** keywords understood by SQLite. ** ** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and ** makes *Z point to that keyword expressed as UTF8 and writes the number ** of bytes in the keyword into *L. The string that *Z points to is not ** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns ** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z ** or L are NULL or invalid pointers then calls to ** sqlite3_keyword_name(N,Z,L) result in undefined behavior. ** ** The sqlite3_keyword_check(Z,L) interface checks to see whether or not ** the L-byte UTF8 identifier that Z points to is a keyword, returning non-zero ** if it is and zero if not. ** ** The parser used by SQLite is forgiving. It is often possible to use ** a keyword as an identifier as long as such use does not result in a ** parsing ambiguity. For example, the statement ** "CREATE TABLE BEGIN(REPLACE,PRAGMA,END);" is accepted by SQLite, and ** creates a new table named "BEGIN" with three columns named ** "REPLACE", "PRAGMA", and "END". Nevertheless, best practice is to avoid ** using keywords as identifiers. Common techniques used to avoid keyword ** name collisions include: **
    **
  • Put all identifier names inside double-quotes. This is the official ** SQL way to escape identifier names. **
  • Put identifier names inside [...]. This is not standard SQL, ** but it is what SQL Server does and so lots of programmers use this ** technique. **
  • Begin every identifier with the letter "Z" as no SQL keywords start ** with "Z". **
  • Include a digit somewhere in every identifier name. **
** ** Note that the number of keywords understood by SQLite can depend on ** compile-time options. For example, "VACUUM" is not a keyword if ** SQLite is compiled with the [-DSQLITE_OMIT_VACUUM] option. Also, ** new keywords may be added to future releases of SQLite. */ SQLITE_API int sqlite3_keyword_count(void); SQLITE_API int sqlite3_keyword_name(int,const char**,int*); SQLITE_API int sqlite3_keyword_check(const char*,int); /* ** CAPI3REF: Dynamic String Object ** KEYWORDS: {dynamic string} ** ** An instance of the sqlite3_str object contains a dynamically-sized ** string under construction. ** ** The lifecycle of an sqlite3_str object is as follows: **
    **
  1. ^The sqlite3_str object is created using [sqlite3_str_new()]. **
  2. ^Text is appended to the sqlite3_str object using various ** methods, such as [sqlite3_str_appendf()]. **
  3. ^The sqlite3_str object is destroyed and the string it created ** is returned using the [sqlite3_str_finish()] interface. **
*/ typedef struct sqlite3_str sqlite3_str; /* ** CAPI3REF: Create A New Dynamic String Object ** CONSTRUCTOR: sqlite3_str ** ** ^The [sqlite3_str_new(D)] interface allocates and initializes ** a new [sqlite3_str] object. To avoid memory leaks, the object returned by ** [sqlite3_str_new()] must be freed by a subsequent call to ** [sqlite3_str_finish(X)]. ** ** ^The [sqlite3_str_new(D)] interface always returns a pointer to a ** valid [sqlite3_str] object, though in the event of an out-of-memory ** error the returned object might be a special singleton that will ** silently reject new text, always return SQLITE_NOMEM from ** [sqlite3_str_errcode()], always return 0 for ** [sqlite3_str_length()], and always return NULL from ** [sqlite3_str_finish(X)]. It is always safe to use the value ** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter ** to any of the other [sqlite3_str] methods. ** ** The D parameter to [sqlite3_str_new(D)] may be NULL. If the ** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum ** length of the string contained in the [sqlite3_str] object will be ** the value set for [sqlite3_limit](D,[SQLITE_LIMIT_LENGTH]) instead ** of [SQLITE_MAX_LENGTH]. */ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); /* ** CAPI3REF: Finalize A Dynamic String ** DESTRUCTOR: sqlite3_str ** ** ^The [sqlite3_str_finish(X)] interface destroys the sqlite3_str object X ** and returns a pointer to a memory buffer obtained from [sqlite3_malloc64()] ** that contains the constructed string. The calling application should ** pass the returned value to [sqlite3_free()] to avoid a memory leak. ** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any ** errors were encountered during construction of the string. ^The ** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the ** string in [sqlite3_str] object X is zero bytes long. */ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); /* ** CAPI3REF: Add Content To A Dynamic String ** METHOD: sqlite3_str ** ** These interfaces add content to an sqlite3_str object previously obtained ** from [sqlite3_str_new()]. ** ** ^The [sqlite3_str_appendf(X,F,...)] and ** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] ** functionality of SQLite to append formatted text onto the end of ** [sqlite3_str] object X. ** ** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S ** onto the end of the [sqlite3_str] object X. N must be non-negative. ** S must contain at least N non-zero bytes of content. To append a ** zero-terminated string in its entirety, use the [sqlite3_str_appendall()] ** method instead. ** ** ^The [sqlite3_str_appendall(X,S)] method appends the complete content of ** zero-terminated string S onto the end of [sqlite3_str] object X. ** ** ^The [sqlite3_str_appendchar(X,N,C)] method appends N copies of the ** single-byte character C onto the end of [sqlite3_str] object X. ** ^This method can be used, for example, to add whitespace indentation. ** ** ^The [sqlite3_str_reset(X)] method resets the string under construction ** inside [sqlite3_str] object X back to zero bytes in length. ** ** These methods do not return a result code. ^If an error occurs, that fact ** is recorded in the [sqlite3_str] object and can be recovered by a ** subsequent call to [sqlite3_str_errcode(X)]. */ SQLITE_API void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...); SQLITE_API void sqlite3_str_vappendf(sqlite3_str*, const char *zFormat, va_list); SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); SQLITE_API void sqlite3_str_reset(sqlite3_str*); /* ** CAPI3REF: Status Of A Dynamic String ** METHOD: sqlite3_str ** ** These interfaces return the current status of an [sqlite3_str] object. ** ** ^If any prior errors have occurred while constructing the dynamic string ** in sqlite3_str X, then the [sqlite3_str_errcode(X)] method will return ** an appropriate error code. ^The [sqlite3_str_errcode(X)] method returns ** [SQLITE_NOMEM] following any out-of-memory error, or ** [SQLITE_TOOBIG] if the size of the dynamic string exceeds ** [SQLITE_MAX_LENGTH], or [SQLITE_OK] if there have been no errors. ** ** ^The [sqlite3_str_length(X)] method returns the current length, in bytes, ** of the dynamic string under construction in [sqlite3_str] object X. ** ^The length returned by [sqlite3_str_length(X)] does not include the ** zero-termination byte. ** ** ^The [sqlite3_str_value(X)] method returns a pointer to the current ** content of the dynamic string under construction in X. The value ** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X ** and might be freed or altered by any subsequent method on the same ** [sqlite3_str] object. Applications must not used the pointer returned ** [sqlite3_str_value(X)] after any subsequent method call on the same ** object. ^Applications may change the content of the string returned ** by [sqlite3_str_value(X)] as long as they do not write into any bytes ** outside the range of 0 to [sqlite3_str_length(X)] and do not read or ** write any byte after any subsequent sqlite3_str method call. */ SQLITE_API int sqlite3_str_errcode(sqlite3_str*); SQLITE_API int sqlite3_str_length(sqlite3_str*); SQLITE_API char *sqlite3_str_value(sqlite3_str*); /* ** CAPI3REF: SQLite Runtime Status ** ** ^These interfaces are used to retrieve runtime status information ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for ** the specific parameter to measure. ^(Recognized integer codes ** are of the form [status parameters | SQLITE_STATUS_...].)^ ** ^The current value of the parameter is returned into *pCurrent. ** ^The highest recorded value is returned in *pHighwater. ^If the ** resetFlag is true, then the highest record value is reset after ** *pHighwater is written. ^(Some parameters do not record the highest ** value. For those parameters ** nothing is written into *pHighwater and the resetFlag is ignored.)^ ** ^(Other parameters record only the highwater mark and not the current ** value. For these latter parameters nothing is written into *pCurrent.)^ ** ** ^The sqlite3_status() and sqlite3_status64() routines return ** SQLITE_OK on success and a non-zero [error code] on failure. ** ** If either the current value or the highwater mark is too large to ** be represented by a 32-bit integer, then the values returned by ** sqlite3_status() are undefined. ** ** See also: [sqlite3_db_status()] */ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); SQLITE_API int sqlite3_status64( int op, sqlite3_int64 *pCurrent, sqlite3_int64 *pHighwater, int resetFlag ); /* ** CAPI3REF: Status Parameters ** KEYWORDS: {status parameters} ** ** These integer constants designate various run-time status parameters ** that can be returned by [sqlite3_status()]. ** **
** [[SQLITE_STATUS_MEMORY_USED]] ^(
SQLITE_STATUS_MEMORY_USED
**
This parameter is the current amount of memory checked out ** using [sqlite3_malloc()], either directly or indirectly. The ** figure includes calls made to [sqlite3_malloc()] by the application ** and internal memory usage by the SQLite library. Auxiliary page-cache ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in ** this parameter. The amount returned is the sum of the allocation ** sizes as reported by the xSize method in [sqlite3_mem_methods].
)^ ** ** [[SQLITE_STATUS_MALLOC_SIZE]] ^(
SQLITE_STATUS_MALLOC_SIZE
**
This parameter records the largest memory allocation request ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their ** internal equivalents). Only the value returned in the ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
)^ ** ** [[SQLITE_STATUS_MALLOC_COUNT]] ^(
SQLITE_STATUS_MALLOC_COUNT
**
This parameter records the number of separate memory allocations ** currently checked out.
)^ ** ** [[SQLITE_STATUS_PAGECACHE_USED]] ^(
SQLITE_STATUS_PAGECACHE_USED
**
This parameter returns the number of pages used out of the ** [pagecache memory allocator] that was configured using ** [SQLITE_CONFIG_PAGECACHE]. The ** value returned is in pages, not in bytes.
)^ ** ** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] ** ^(
SQLITE_STATUS_PAGECACHE_OVERFLOW
**
This parameter returns the number of bytes of page cache ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] ** buffer and where forced to overflow to [sqlite3_malloc()]. The ** returned value includes allocations that overflowed because they ** where too large (they were larger than the "sz" parameter to ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because ** no space was left in the page cache.
)^ ** ** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(
SQLITE_STATUS_PAGECACHE_SIZE
**
This parameter records the largest memory allocation request ** handed to the [pagecache memory allocator]. Only the value returned in the ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
)^ ** ** [[SQLITE_STATUS_SCRATCH_USED]]
SQLITE_STATUS_SCRATCH_USED
**
No longer used.
** ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(
SQLITE_STATUS_SCRATCH_OVERFLOW
**
No longer used.
** ** [[SQLITE_STATUS_SCRATCH_SIZE]]
SQLITE_STATUS_SCRATCH_SIZE
**
No longer used.
** ** [[SQLITE_STATUS_PARSER_STACK]] ^(
SQLITE_STATUS_PARSER_STACK
**
The *pHighwater parameter records the deepest parser stack. ** The *pCurrent value is undefined. The *pHighwater value is only ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].
)^ **
** ** New status parameters may be added from time to time. */ #define SQLITE_STATUS_MEMORY_USED 0 #define SQLITE_STATUS_PAGECACHE_USED 1 #define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 #define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */ #define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */ #define SQLITE_STATUS_MALLOC_SIZE 5 #define SQLITE_STATUS_PARSER_STACK 6 #define SQLITE_STATUS_PAGECACHE_SIZE 7 #define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */ #define SQLITE_STATUS_MALLOC_COUNT 9 /* ** CAPI3REF: Database Connection Status ** METHOD: sqlite3 ** ** ^This interface is used to retrieve runtime status information ** about a single [database connection]. ^The first argument is the ** database connection object to be interrogated. ^The second argument ** is an integer constant, taken from the set of ** [SQLITE_DBSTATUS options], that ** determines the parameter to interrogate. The set of ** [SQLITE_DBSTATUS options] is likely ** to grow in future releases of SQLite. ** ** ^The current value of the requested parameter is written into *pCur ** and the highest instantaneous value is written into *pHiwtr. ^If ** the resetFlg is true, then the highest instantaneous value is ** reset back down to the current value. ** ** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a ** non-zero [error code] on failure. ** ** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. */ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); /* ** CAPI3REF: Status Parameters for database connections ** KEYWORDS: {SQLITE_DBSTATUS options} ** ** These constants are the available integer "verbs" that can be passed as ** the second argument to the [sqlite3_db_status()] interface. ** ** New verbs may be added in future releases of SQLite. Existing verbs ** might be discontinued. Applications should check the return code from ** [sqlite3_db_status()] to make sure that the call worked. ** The [sqlite3_db_status()] interface will return a non-zero error code ** if a discontinued or unsupported verb is invoked. ** **
** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(
SQLITE_DBSTATUS_LOOKASIDE_USED
**
This parameter returns the number of lookaside memory slots currently ** checked out.
)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
SQLITE_DBSTATUS_LOOKASIDE_HIT
**
This parameter returns the number of malloc attempts that were ** satisfied using lookaside memory. Only the high-water value is meaningful; ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] ** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
**
This parameter returns the number malloc attempts that might have ** been satisfied using lookaside memory but failed due to the amount of ** memory requested being larger than the lookaside slot size. ** Only the high-water value is meaningful; ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] ** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
**
This parameter returns the number malloc attempts that might have ** been satisfied using lookaside memory but failed due to all lookaside ** memory already being in use. ** Only the high-water value is meaningful; ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
SQLITE_DBSTATUS_CACHE_USED
**
This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** ** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] ** ^(
SQLITE_DBSTATUS_CACHE_USED_SHARED
**
This parameter is similar to DBSTATUS_CACHE_USED, except that if a ** pager cache is shared between two or more connections the bytes of heap ** memory used by that pager cache is divided evenly between the attached ** connections.)^ In other words, if none of the pager caches associated ** with the database connection are shared, this request returns the same ** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are ** shared, the value returned by this call will be smaller than that returned ** by DBSTATUS_CACHE_USED. ^The highwater mark associated with ** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. ** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
SQLITE_DBSTATUS_SCHEMA_USED
**
This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the ** schema memory is shared with other database connections due to ** [shared cache mode] being enabled. ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. ** ** [[SQLITE_DBSTATUS_STMT_USED]] ^(
SQLITE_DBSTATUS_STMT_USED
**
This parameter returns the approximate number of bytes of heap ** and lookaside memory used by all prepared statements associated with ** the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. **
** ** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(
SQLITE_DBSTATUS_CACHE_HIT
**
This parameter returns the number of pager cache hits that have ** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT ** is always 0. **
** ** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(
SQLITE_DBSTATUS_CACHE_MISS
**
This parameter returns the number of pager cache misses that have ** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS ** is always 0. **
** ** [[SQLITE_DBSTATUS_CACHE_WRITE]] ^(
SQLITE_DBSTATUS_CACHE_WRITE
**
This parameter returns the number of dirty cache entries that have ** been written to disk. Specifically, the number of pages written to the ** wal file in wal mode databases, or the number of pages written to the ** database file in rollback mode databases. Any pages written as part of ** transaction rollback or database recovery operations are not included. ** If an IO or other error occurs while writing a page to disk, the effect ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. **
** ** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(
SQLITE_DBSTATUS_CACHE_SPILL
**
This parameter returns the number of dirty cache entries that have ** been written to disk in the middle of a transaction due to the page ** cache overflowing. Transactions are more efficient if they are written ** to disk all at once. When pages spill mid-transaction, that introduces ** additional overhead. This parameter can be used help identify ** inefficiencies that can be resolved by increasing the cache size. **
** ** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(
SQLITE_DBSTATUS_DEFERRED_FKS
**
This parameter returns zero for the current value if and only if ** all foreign key constraints (deferred or immediate) have been ** resolved.)^ ^The highwater mark is always 0. **
**
*/ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_CACHE_USED 1 #define SQLITE_DBSTATUS_SCHEMA_USED 2 #define SQLITE_DBSTATUS_STMT_USED 3 #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_DEFERRED_FKS 10 #define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 #define SQLITE_DBSTATUS_CACHE_SPILL 12 #define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */ /* ** CAPI3REF: Prepared Statement Status ** METHOD: sqlite3_stmt ** ** ^(Each prepared statement maintains various ** [SQLITE_STMTSTATUS counters] that measure the number ** of times it has performed specific operations.)^ These counters can ** be used to monitor the performance characteristics of the prepared ** statements. For example, if the number of table steps greatly exceeds ** the number of table searches or result rows, that would tend to indicate ** that the prepared statement is using a full table scan rather than ** an index. ** ** ^(This interface is used to retrieve and reset counter values from ** a [prepared statement]. The first argument is the prepared statement ** object to be interrogated. The second argument ** is an integer code for a specific [SQLITE_STMTSTATUS counter] ** to be interrogated.)^ ** ^The current value of the requested counter is returned. ** ^If the resetFlg is true, then the counter is reset to zero after this ** interface call returns. ** ** See also: [sqlite3_status()] and [sqlite3_db_status()]. */ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); /* ** CAPI3REF: Status Parameters for prepared statements ** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} ** ** These preprocessor macros define integer codes that name counter ** values associated with the [sqlite3_stmt_status()] interface. ** The meanings of the various counters are as follows: ** **
** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]]
SQLITE_STMTSTATUS_FULLSCAN_STEP
**
^This is the number of times that SQLite has stepped forward in ** a table as part of a full table scan. Large numbers for this counter ** may indicate opportunities for performance improvement through ** careful use of indices.
** ** [[SQLITE_STMTSTATUS_SORT]]
SQLITE_STMTSTATUS_SORT
**
^This is the number of sort operations that have occurred. ** A non-zero value in this counter may indicate an opportunity to ** improvement performance through careful use of indices.
** ** [[SQLITE_STMTSTATUS_AUTOINDEX]]
SQLITE_STMTSTATUS_AUTOINDEX
**
^This is the number of rows inserted into transient indices that ** were created automatically in order to help joins run faster. ** A non-zero value in this counter may indicate an opportunity to ** improvement performance by adding permanent indices that do not ** need to be reinitialized each time the statement is run.
** ** [[SQLITE_STMTSTATUS_VM_STEP]]
SQLITE_STMTSTATUS_VM_STEP
**
^This is the number of virtual machine operations executed ** by the prepared statement if that number is less than or equal ** to 2147483647. The number of virtual machine operations can be ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 ** then the value returned by this statement status code is undefined. ** ** [[SQLITE_STMTSTATUS_REPREPARE]]
SQLITE_STMTSTATUS_REPREPARE
**
^This is the number of times that the prepare statement has been ** automatically regenerated due to schema changes or changes to ** [bound parameters] that might affect the query plan. ** ** [[SQLITE_STMTSTATUS_RUN]]
SQLITE_STMTSTATUS_RUN
**
^This is the number of times that the prepared statement has ** been run. A single "run" for the purposes of this counter is one ** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. ** The counter is incremented on the first [sqlite3_step()] call of each ** cycle. ** ** [[SQLITE_STMTSTATUS_FILTER_MISS]] ** [[SQLITE_STMTSTATUS_FILTER HIT]] **
SQLITE_STMTSTATUS_FILTER_HIT
** SQLITE_STMTSTATUS_FILTER_MISS
**
^SQLITE_STMTSTATUS_FILTER_HIT is the number of times that a join ** step was bypassed because a Bloom filter returned not-found. The ** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of ** times that the Bloom filter returned a find, and thus the join step ** had to be processed as normal. ** ** [[SQLITE_STMTSTATUS_MEMUSED]]
SQLITE_STMTSTATUS_MEMUSED
**
^This is the approximate number of bytes of heap memory ** used to store the prepared statement. ^This value is not actually ** a counter, and so the resetFlg parameter to sqlite3_stmt_status() ** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED. **
**
*/ #define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 #define SQLITE_STMTSTATUS_VM_STEP 4 #define SQLITE_STMTSTATUS_REPREPARE 5 #define SQLITE_STMTSTATUS_RUN 6 #define SQLITE_STMTSTATUS_FILTER_MISS 7 #define SQLITE_STMTSTATUS_FILTER_HIT 8 #define SQLITE_STMTSTATUS_MEMUSED 99 /* ** CAPI3REF: Custom Page Cache Object ** ** The sqlite3_pcache type is opaque. It is implemented by ** the pluggable module. The SQLite core has no knowledge of ** its size or internal structure and never deals with the ** sqlite3_pcache object except by holding and passing pointers ** to the object. ** ** See [sqlite3_pcache_methods2] for additional information. */ typedef struct sqlite3_pcache sqlite3_pcache; /* ** CAPI3REF: Custom Page Cache Object ** ** The sqlite3_pcache_page object represents a single page in the ** page cache. The page cache will allocate instances of this ** object. Various methods of the page cache use pointers to instances ** of this object as parameters or as their return value. ** ** See [sqlite3_pcache_methods2] for additional information. */ typedef struct sqlite3_pcache_page sqlite3_pcache_page; struct sqlite3_pcache_page { void *pBuf; /* The content of the page */ void *pExtra; /* Extra information associated with the page */ }; /* ** CAPI3REF: Application Defined Page Cache. ** KEYWORDS: {page cache} ** ** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can ** register an alternative page cache implementation by passing in an ** instance of the sqlite3_pcache_methods2 structure.)^ ** In many applications, most of the heap memory allocated by ** SQLite is used for the page cache. ** By implementing a ** custom page cache using this API, an application can better control ** the amount of memory consumed by SQLite, the way in which ** that memory is allocated and released, and the policies used to ** determine exactly which parts of a database file are cached and for ** how long. ** ** The alternative page cache mechanism is an ** extreme measure that is only needed by the most demanding applications. ** The built-in page cache is recommended for most uses. ** ** ^(The contents of the sqlite3_pcache_methods2 structure are copied to an ** internal buffer by SQLite within the call to [sqlite3_config]. Hence ** the application may discard the parameter after the call to ** [sqlite3_config()] returns.)^ ** ** [[the xInit() page cache method]] ** ^(The xInit() method is called once for each effective ** call to [sqlite3_initialize()])^ ** (usually only once during the lifetime of the process). ^(The xInit() ** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^ ** The intent of the xInit() method is to set up global data structures ** required by the custom page cache implementation. ** ^(If the xInit() method is NULL, then the ** built-in default page cache is used instead of the application defined ** page cache.)^ ** ** [[the xShutdown() page cache method]] ** ^The xShutdown() method is called by [sqlite3_shutdown()]. ** It can be used to clean up ** any outstanding resources before process shutdown, if required. ** ^The xShutdown() method may be NULL. ** ** ^SQLite automatically serializes calls to the xInit method, ** so the xInit method need not be threadsafe. ^The ** xShutdown method is only called from [sqlite3_shutdown()] so it does ** not need to be threadsafe either. All other methods must be threadsafe ** in multithreaded applications. ** ** ^SQLite will never invoke xInit() more than once without an intervening ** call to xShutdown(). ** ** [[the xCreate() page cache methods]] ** ^SQLite invokes the xCreate() method to construct a new cache instance. ** SQLite will typically create one cache instance for each open database file, ** though this is not guaranteed. ^The ** first parameter, szPage, is the size in bytes of the pages that must ** be allocated by the cache. ^szPage will always a power of two. ^The ** second parameter szExtra is a number of bytes of extra storage ** associated with each page cache entry. ^The szExtra parameter will ** a number less than 250. SQLite will use the ** extra szExtra bytes on each page to store metadata about the underlying ** database page on disk. The value passed into szExtra depends ** on the SQLite version, the target platform, and how SQLite was compiled. ** ^The third argument to xCreate(), bPurgeable, is true if the cache being ** created will be used to cache database pages of a file stored on disk, or ** false if it is used for an in-memory database. The cache implementation ** does not have to do anything special based with the value of bPurgeable; ** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will ** never invoke xUnpin() except to deliberately delete a page. ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to ** false will always have the "discard" flag set to true. ** ^Hence, a cache created with bPurgeable false will ** never contain any unpinned pages. ** ** [[the xCachesize() page cache method]] ** ^(The xCachesize() method may be called at any time by SQLite to set the ** suggested maximum cache-size (number of pages stored by) the cache ** instance passed as the first argument. This is the value configured using ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable ** parameter, the implementation is not required to do anything with this ** value; it is advisory only. ** ** [[the xPagecount() page cache methods]] ** The xPagecount() method must return the number of pages currently ** stored in the cache, both pinned and unpinned. ** ** [[the xFetch() page cache methods]] ** The xFetch() method locates a page in the cache and returns a pointer to ** an sqlite3_pcache_page object associated with that page, or a NULL pointer. ** The pBuf element of the returned sqlite3_pcache_page object will be a ** pointer to a buffer of szPage bytes used to store the content of a ** single database page. The pExtra element of sqlite3_pcache_page will be ** a pointer to the szExtra bytes of extra storage that SQLite has requested ** for each entry in the page cache. ** ** The page to be fetched is determined by the key. ^The minimum key value ** is 1. After it has been retrieved using xFetch, the page is considered ** to be "pinned". ** ** If the requested page is already in the page cache, then the page cache ** implementation must return a pointer to the page buffer with its content ** intact. If the requested page is not already in the cache, then the ** cache implementation should use the value of the createFlag ** parameter to help it determined what action to take: ** ** **
createFlag Behavior when page is not already in cache **
0 Do not allocate a new page. Return NULL. **
1 Allocate a new page if it easy and convenient to do so. ** Otherwise return NULL. **
2 Make every effort to allocate a new page. Only return ** NULL if allocating a new page is effectively impossible. **
** ** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite ** will only use a createFlag of 2 after a prior call with a createFlag of 1 ** failed.)^ In between the xFetch() calls, SQLite may ** attempt to unpin one or more cache pages by spilling the content of ** pinned pages to disk and synching the operating system disk cache. ** ** [[the xUnpin() page cache method]] ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page ** as its second argument. If the third parameter, discard, is non-zero, ** then the page must be evicted from the cache. ** ^If the discard parameter is ** zero, then the page may be discarded or retained at the discretion of ** page cache implementation. ^The page cache implementation ** may choose to evict unpinned pages at any time. ** ** The cache must not perform any reference counting. A single ** call to xUnpin() unpins the page regardless of the number of prior calls ** to xFetch(). ** ** [[the xRekey() page cache methods]] ** The xRekey() method is used to change the key value associated with the ** page passed as the second argument. If the cache ** previously contains an entry associated with newKey, it must be ** discarded. ^Any prior cache entry associated with newKey is guaranteed not ** to be pinned. ** ** When SQLite calls the xTruncate() method, the cache must discard all ** existing cache entries with page numbers (keys) greater than or equal ** to the value of the iLimit parameter passed to xTruncate(). If any ** of these pages are pinned, they are implicitly unpinned, meaning that ** they can be safely discarded. ** ** [[the xDestroy() page cache method]] ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). ** All resources associated with the specified cache should be freed. ^After ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] ** handle invalid, and will not use it with any other sqlite3_pcache_methods2 ** functions. ** ** [[the xShrink() page cache method]] ** ^SQLite invokes the xShrink() method when it wants the page cache to ** free up as much of heap memory as possible. The page cache implementation ** is not obligated to free any memory, but well-behaved implementations should ** do their best. */ typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2; struct sqlite3_pcache_methods2 { int iVersion; void *pArg; int (*xInit)(void*); void (*xShutdown)(void*); sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable); void (*xCachesize)(sqlite3_pcache*, int nCachesize); int (*xPagecount)(sqlite3_pcache*); sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, unsigned oldKey, unsigned newKey); void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); void (*xDestroy)(sqlite3_pcache*); void (*xShrink)(sqlite3_pcache*); }; /* ** This is the obsolete pcache_methods object that has now been replaced ** by sqlite3_pcache_methods2. This object is not used by SQLite. It is ** retained in the header file for backwards compatibility only. */ typedef struct sqlite3_pcache_methods sqlite3_pcache_methods; struct sqlite3_pcache_methods { void *pArg; int (*xInit)(void*); void (*xShutdown)(void*); sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable); void (*xCachesize)(sqlite3_pcache*, int nCachesize); int (*xPagecount)(sqlite3_pcache*); void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); void (*xUnpin)(sqlite3_pcache*, void*, int discard); void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey); void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); void (*xDestroy)(sqlite3_pcache*); }; /* ** CAPI3REF: Online Backup Object ** ** The sqlite3_backup object records state information about an ongoing ** online backup operation. ^The sqlite3_backup object is created by ** a call to [sqlite3_backup_init()] and is destroyed by a call to ** [sqlite3_backup_finish()]. ** ** See Also: [Using the SQLite Online Backup API] */ typedef struct sqlite3_backup sqlite3_backup; /* ** CAPI3REF: Online Backup API. ** ** The backup API copies the content of one database into another. ** It is useful either for creating backups of databases or ** for copying in-memory databases to or from persistent files. ** ** See Also: [Using the SQLite Online Backup API] ** ** ^SQLite holds a write transaction open on the destination database file ** for the duration of the backup operation. ** ^The source database is read-locked only while it is being read; ** it is not locked continuously for the entire backup operation. ** ^Thus, the backup may be performed on a live source database without ** preventing other database connections from ** reading or writing to the source database while the backup is underway. ** ** ^(To perform a backup operation: **
    **
  1. sqlite3_backup_init() is called once to initialize the ** backup, **
  2. sqlite3_backup_step() is called one or more times to transfer ** the data between the two databases, and finally **
  3. sqlite3_backup_finish() is called to release all resources ** associated with the backup operation. **
)^ ** There should be exactly one call to sqlite3_backup_finish() for each ** successful call to sqlite3_backup_init(). ** ** [[sqlite3_backup_init()]] sqlite3_backup_init() ** ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the ** [database connection] associated with the destination database ** and the database name, respectively. ** ^The database name is "main" for the main database, "temp" for the ** temporary database, or the name specified after the AS keyword in ** an [ATTACH] statement for an attached database. ** ^The S and M arguments passed to ** sqlite3_backup_init(D,N,S,M) identify the [database connection] ** and database name of the source database, respectively. ** ^The source and destination [database connections] (parameters S and D) ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with ** an error. ** ** ^A call to sqlite3_backup_init() will fail, returning NULL, if ** there is already a read or read-write transaction open on the ** destination database. ** ** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is ** returned and an error code and error message are stored in the ** destination [database connection] D. ** ^The error code and message for the failed call to sqlite3_backup_init() ** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or ** [sqlite3_errmsg16()] functions. ** ^A successful call to sqlite3_backup_init() returns a pointer to an ** [sqlite3_backup] object. ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and ** sqlite3_backup_finish() functions to perform the specified backup ** operation. ** ** [[sqlite3_backup_step()]] sqlite3_backup_step() ** ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between ** the source and destination databases specified by [sqlite3_backup] object B. ** ^If N is negative, all remaining source pages are copied. ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there ** are still more pages to be copied, then the function returns [SQLITE_OK]. ** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages ** from source to destination, then it returns [SQLITE_DONE]. ** ^If an error occurs while running sqlite3_backup_step(B,N), ** then an [error code] is returned. ^As well as [SQLITE_OK] and ** [SQLITE_DONE], a call to sqlite3_backup_step() may return [SQLITE_READONLY], ** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an ** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code. ** ** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if **
    **
  1. the destination database was opened read-only, or **
  2. the destination database is using write-ahead-log journaling ** and the destination and source page sizes differ, or **
  3. the destination database is an in-memory database and the ** destination and source page sizes differ. **
)^ ** ** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then ** the [sqlite3_busy_handler | busy-handler function] ** is invoked (if one is specified). ^If the ** busy-handler returns non-zero before the lock is available, then ** [SQLITE_BUSY] is returned to the caller. ^In this case the call to ** sqlite3_backup_step() can be retried later. ^If the source ** [database connection] ** is being used to write to the source database when sqlite3_backup_step() ** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this ** case the call to sqlite3_backup_step() can be retried later on. ^(If ** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or ** [SQLITE_READONLY] is returned, then ** there is no point in retrying the call to sqlite3_backup_step(). These ** errors are considered fatal.)^ The application must accept ** that the backup operation has failed and pass the backup operation handle ** to the sqlite3_backup_finish() to release associated resources. ** ** ^The first call to sqlite3_backup_step() obtains an exclusive lock ** on the destination file. ^The exclusive lock is not released until either ** sqlite3_backup_finish() is called or the backup operation is complete ** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to ** sqlite3_backup_step() obtains a [shared lock] on the source database that ** lasts for the duration of the sqlite3_backup_step() call. ** ^Because the source database is not locked between calls to ** sqlite3_backup_step(), the source database may be modified mid-way ** through the backup process. ^If the source database is modified by an ** external process or via a database connection other than the one being ** used by the backup operation, then the backup will be automatically ** restarted by the next call to sqlite3_backup_step(). ^If the source ** database is modified by the using the same database connection as is used ** by the backup operation, then the backup database is automatically ** updated at the same time. ** ** [[sqlite3_backup_finish()]] sqlite3_backup_finish() ** ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the ** application wishes to abandon the backup operation, the application ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). ** ^The sqlite3_backup_finish() interfaces releases all ** resources associated with the [sqlite3_backup] object. ** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any ** active write-transaction on the destination database is rolled back. ** The [sqlite3_backup] object is invalid ** and may not be used following a call to sqlite3_backup_finish(). ** ** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no ** sqlite3_backup_step() errors occurred, regardless or whether or not ** sqlite3_backup_step() completed. ** ^If an out-of-memory condition or IO error occurred during any prior ** sqlite3_backup_step() call on the same [sqlite3_backup] object, then ** sqlite3_backup_finish() returns the corresponding [error code]. ** ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() ** is not a permanent error and does not affect the return value of ** sqlite3_backup_finish(). ** ** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]] ** sqlite3_backup_remaining() and sqlite3_backup_pagecount() ** ** ^The sqlite3_backup_remaining() routine returns the number of pages still ** to be backed up at the conclusion of the most recent sqlite3_backup_step(). ** ^The sqlite3_backup_pagecount() routine returns the total number of pages ** in the source database at the conclusion of the most recent ** sqlite3_backup_step(). ** ^(The values returned by these functions are only updated by ** sqlite3_backup_step(). If the source database is modified in a way that ** changes the size of the source database or the number of pages remaining, ** those changes are not reflected in the output of sqlite3_backup_pagecount() ** and sqlite3_backup_remaining() until after the next ** sqlite3_backup_step().)^ ** ** Concurrent Usage of Database Handles ** ** ^The source [database connection] may be used by the application for other ** purposes while a backup operation is underway or being initialized. ** ^If SQLite is compiled and configured to support threadsafe database ** connections, then the source database connection may be used concurrently ** from within other threads. ** ** However, the application must guarantee that the destination ** [database connection] is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). SQLite does not currently check to see ** if the application incorrectly accesses the destination [database connection] ** and so no error code is reported, but the operations may malfunction ** nevertheless. Use of the destination database connection while a ** backup is in progress might also cause a mutex deadlock. ** ** If running in [shared cache mode], the application must ** guarantee that the shared cache used by the destination database ** is not accessed while the backup is running. In practice this means ** that the application must guarantee that the disk file being ** backed up to is not accessed by any connection within the process, ** not just the specific connection that was passed to sqlite3_backup_init(). ** ** The [sqlite3_backup] object itself is partially threadsafe. Multiple ** threads may safely make multiple concurrent calls to sqlite3_backup_step(). ** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount() ** APIs are not strictly speaking threadsafe. If they are invoked at the ** same time as another thread is invoking sqlite3_backup_step() it is ** possible that they return invalid values. */ SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /* Destination database handle */ const char *zDestName, /* Destination database name */ sqlite3 *pSource, /* Source database handle */ const char *zSourceName /* Source database name */ ); SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage); SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p); SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p); SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); /* ** CAPI3REF: Unlock Notification ** METHOD: sqlite3 ** ** ^When running in shared-cache mode, a database operation may fail with ** an [SQLITE_LOCKED] error if the required locks on the shared-cache or ** individual tables within the shared-cache cannot be obtained. See ** [SQLite Shared-Cache Mode] for a description of shared-cache locking. ** ^This API may be used to register a callback that SQLite will invoke ** when the connection currently holding the required lock relinquishes it. ** ^This API is only available if the library was compiled with the ** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined. ** ** See Also: [Using the SQLite Unlock Notification Feature]. ** ** ^Shared-cache locks are released when a database connection concludes ** its current transaction, either by committing it or rolling it back. ** ** ^When a connection (known as the blocked connection) fails to obtain a ** shared-cache lock and SQLITE_LOCKED is returned to the caller, the ** identity of the database connection (the blocking connection) that ** has locked the required resource is stored internally. ^After an ** application receives an SQLITE_LOCKED error, it may call the ** sqlite3_unlock_notify() method with the blocked connection handle as ** the first argument to register for a callback that will be invoked ** when the blocking connections current transaction is concluded. ^The ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] ** call that concludes the blocking connection's transaction. ** ** ^(If sqlite3_unlock_notify() is called in a multi-threaded application, ** there is a chance that the blocking connection will have already ** concluded its transaction by the time sqlite3_unlock_notify() is invoked. ** If this happens, then the specified callback is invoked immediately, ** from within the call to sqlite3_unlock_notify().)^ ** ** ^If the blocked connection is attempting to obtain a write-lock on a ** shared-cache table, and more than one other connection currently holds ** a read-lock on the same table, then SQLite arbitrarily selects one of ** the other connections to use as the blocking connection. ** ** ^(There may be at most one unlock-notify callback registered by a ** blocked connection. If sqlite3_unlock_notify() is called when the ** blocked connection already has a registered unlock-notify callback, ** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is ** called with a NULL pointer as its second argument, then any existing ** unlock-notify callback is canceled. ^The blocked connections ** unlock-notify callback may also be canceled by closing the blocked ** connection using [sqlite3_close()]. ** ** The unlock-notify callback is not reentrant. If an application invokes ** any sqlite3_xxx API functions from within an unlock-notify callback, a ** crash or deadlock may be the result. ** ** ^Unless deadlock is detected (see below), sqlite3_unlock_notify() always ** returns SQLITE_OK. ** ** Callback Invocation Details ** ** When an unlock-notify callback is registered, the application provides a ** single void* pointer that is passed to the callback when it is invoked. ** However, the signature of the callback function allows SQLite to pass ** it an array of void* context pointers. The first argument passed to ** an unlock-notify callback is a pointer to an array of void* pointers, ** and the second is the number of entries in the array. ** ** When a blocking connection's transaction is concluded, there may be ** more than one blocked connection that has registered for an unlock-notify ** callback. ^If two or more such blocked connections have specified the ** same callback function, then instead of invoking the callback function ** multiple times, it is invoked once with the set of void* context pointers ** specified by the blocked connections bundled together into an array. ** This gives the application an opportunity to prioritize any actions ** related to the set of unblocked database connections. ** ** Deadlock Detection ** ** Assuming that after registering for an unlock-notify callback a ** database waits for the callback to be issued before taking any further ** action (a reasonable assumption), then using this API may cause the ** application to deadlock. For example, if connection X is waiting for ** connection Y's transaction to be concluded, and similarly connection ** Y is waiting on connection X's transaction, then neither connection ** will proceed and the system may remain deadlocked indefinitely. ** ** To avoid this scenario, the sqlite3_unlock_notify() performs deadlock ** detection. ^If a given call to sqlite3_unlock_notify() would put the ** system in a deadlocked state, then SQLITE_LOCKED is returned and no ** unlock-notify callback is registered. The system is said to be in ** a deadlocked state if connection A has registered for an unlock-notify ** callback on the conclusion of connection B's transaction, and connection ** B has itself registered for an unlock-notify callback when connection ** A's transaction is concluded. ^Indirect deadlock is also detected, so ** the system is also considered to be deadlocked if connection B has ** registered for an unlock-notify callback on the conclusion of connection ** C's transaction, where connection C is waiting on connection A. ^Any ** number of levels of indirection are allowed. ** ** The "DROP TABLE" Exception ** ** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost ** always appropriate to call sqlite3_unlock_notify(). There is however, ** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement, ** SQLite checks if there are any currently executing SELECT statements ** that belong to the same connection. If there are, SQLITE_LOCKED is ** returned. In this case there is no "blocking connection", so invoking ** sqlite3_unlock_notify() results in the unlock-notify callback being ** invoked immediately. If the application then re-attempts the "DROP TABLE" ** or "DROP INDEX" query, an infinite loop might be the result. ** ** One way around this problem is to check the extended error code returned ** by an sqlite3_step() call. ^(If there is a blocking connection, then the ** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in ** the special "DROP TABLE/INDEX" case, the extended error code is just ** SQLITE_LOCKED.)^ */ SQLITE_API int sqlite3_unlock_notify( sqlite3 *pBlocked, /* Waiting connection */ void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** CAPI3REF: String Comparison ** ** ^The [sqlite3_stricmp()] and [sqlite3_strnicmp()] APIs allow applications ** and extensions to compare the contents of two buffers containing UTF-8 ** strings in a case-independent fashion, using the same definition of "case ** independence" that SQLite uses internally when comparing identifiers. */ SQLITE_API int sqlite3_stricmp(const char *, const char *); SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); /* ** CAPI3REF: String Globbing * ** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if ** string X matches the [GLOB] pattern P. ** ^The definition of [GLOB] pattern matching used in ** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the ** SQL dialect understood by SQLite. ^The [sqlite3_strglob(P,X)] function ** is case sensitive. ** ** Note that this routine returns zero on a match and non-zero if the strings ** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. ** ** See also: [sqlite3_strlike()]. */ SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr); /* ** CAPI3REF: String LIKE Matching * ** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if ** string X matches the [LIKE] pattern P with escape character E. ** ^The definition of [LIKE] pattern matching used in ** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E" ** operator in the SQL dialect understood by SQLite. ^For "X LIKE P" without ** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0. ** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case ** insensitive - equivalent upper and lower case ASCII characters match ** one another. ** ** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though ** only ASCII characters are case folded. ** ** Note that this routine returns zero on a match and non-zero if the strings ** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. ** ** See also: [sqlite3_strglob()]. */ SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc); /* ** CAPI3REF: Error Logging Interface ** ** ^The [sqlite3_log()] interface writes a message into the [error log] ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. ** ^If logging is enabled, the zFormat string and subsequent arguments are ** used with [sqlite3_snprintf()] to generate the final output string. ** ** The sqlite3_log() interface is intended for use by extensions such as ** virtual tables, collating functions, and SQL functions. While there is ** nothing to prevent an application from calling sqlite3_log(), doing so ** is considered bad form. ** ** The zFormat string must not be NULL. ** ** To avoid deadlocks and other threading problems, the sqlite3_log() routine ** will not use dynamically allocated memory. The log message is stored in ** a fixed-length buffer on the stack. If the log message is longer than ** a few hundred characters, it will be truncated to the length of the ** buffer. */ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); /* ** CAPI3REF: Write-Ahead Log Commit Hook ** METHOD: sqlite3 ** ** ^The [sqlite3_wal_hook()] function is used to register a callback that ** is invoked each time data is committed to a database in wal mode. ** ** ^(The callback is invoked by SQLite after the commit has taken place and ** the associated write-lock on the database released)^, so the implementation ** may read, write or [checkpoint] the database as required. ** ** ^The first parameter passed to the callback function when it is invoked ** is a copy of the third parameter passed to sqlite3_wal_hook() when ** registering the callback. ^The second is a copy of the database handle. ** ^The third parameter is the name of the database that was written to - ** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter ** is the number of pages currently in the write-ahead log file, ** including those that were just committed. ** ** The callback function should normally return [SQLITE_OK]. ^If an error ** code is returned, that error will propagate back up through the ** SQLite code base to cause the statement that provoked the callback ** to report an error, though the commit will have still occurred. If the ** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value ** that does not correspond to any valid SQLite error code, the results ** are undefined. ** ** A single database handle may have at most a single write-ahead log callback ** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any ** previously registered write-ahead log callback. ^The return value is ** a copy of the third parameter from the previous call, if any, or 0. ** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will ** overwrite any prior [sqlite3_wal_hook()] settings. */ SQLITE_API void *sqlite3_wal_hook( sqlite3*, int(*)(void *,sqlite3*,const char*,int), void* ); /* ** CAPI3REF: Configure an auto-checkpoint ** METHOD: sqlite3 ** ** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around ** [sqlite3_wal_hook()] that causes any database on [database connection] D ** to automatically [checkpoint] ** after committing a transaction if there are N or ** more frames in the [write-ahead log] file. ^Passing zero or ** a negative value as the nFrame parameter disables automatic ** checkpoints entirely. ** ** ^The callback registered by this function replaces any existing callback ** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback ** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism ** configured by this function. ** ** ^The [wal_autocheckpoint pragma] can be used to invoke this interface ** from SQL. ** ** ^Checkpoints initiated by this mechanism are ** [sqlite3_wal_checkpoint_v2|PASSIVE]. ** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] ** pages. The use of this interface ** is only necessary if the default setting is found to be suboptimal ** for a particular application. */ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /* ** CAPI3REF: Checkpoint a database ** METHOD: sqlite3 ** ** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to ** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^ ** ** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the ** [write-ahead log] for database X on [database connection] D to be ** transferred into the database file and for the write-ahead log to ** be reset. See the [checkpointing] documentation for addition ** information. ** ** This interface used to be the only way to cause a checkpoint to ** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()] ** interface was added. This interface is retained for backwards ** compatibility and as a convenience for applications that need to manually ** start a callback but which do not need the full power (and corresponding ** complication) of [sqlite3_wal_checkpoint_v2()]. */ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Checkpoint a database ** METHOD: sqlite3 ** ** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint ** operation on database X of [database connection] D in mode M. Status ** information is written back into integers pointed to by L and C.)^ ** ^(The M parameter must be a valid [checkpoint mode]:)^ ** **
**
SQLITE_CHECKPOINT_PASSIVE
** ^Checkpoint as many frames as possible without waiting for any database ** readers or writers to finish, then sync the database file if all frames ** in the log were checkpointed. ^The [busy-handler callback] ** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode. ** ^On the other hand, passive mode might leave the checkpoint unfinished ** if there are concurrent readers or writers. ** **
SQLITE_CHECKPOINT_FULL
** ^This mode blocks (it invokes the ** [sqlite3_busy_handler|busy-handler callback]) until there is no ** database writer and all readers are reading from the most recent database ** snapshot. ^It then checkpoints all frames in the log file and syncs the ** database file. ^This mode blocks new database writers while it is pending, ** but new database readers are allowed to continue unimpeded. ** **
SQLITE_CHECKPOINT_RESTART
** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition ** that after checkpointing the log file it blocks (calls the ** [busy-handler callback]) ** until all readers are reading from the database file only. ^This ensures ** that the next writer will restart the log file from the beginning. ** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new ** database writer attempts while it is pending, but does not impede readers. ** **
SQLITE_CHECKPOINT_TRUNCATE
** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the ** addition that it also truncates the log file to zero bytes just prior ** to a successful return. **
** ** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in ** the log file or to -1 if the checkpoint could not run because ** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not ** NULL,then *pnCkpt is set to the total number of checkpointed frames in the ** log file (including any that were already checkpointed before the function ** was called) or to -1 if the checkpoint could not run due to an error or ** because the database is not in WAL mode. ^Note that upon successful ** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been ** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero. ** ** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If ** any other process is running a checkpoint operation at the same time, the ** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a ** busy-handler configured, it will not be invoked in this case. ** ** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the ** exclusive "writer" lock on the database file. ^If the writer lock cannot be ** obtained immediately, and a busy-handler is configured, it is invoked and ** the writer lock retried until either the busy-handler returns 0 or the lock ** is successfully obtained. ^The busy-handler is also invoked while waiting for ** database readers as described above. ^If the busy-handler returns 0 before ** the writer lock is obtained or while waiting for database readers, the ** checkpoint operation proceeds from that point in the same way as ** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible ** without blocking any further. ^SQLITE_BUSY is returned in this case. ** ** ^If parameter zDb is NULL or points to a zero length string, then the ** specified operation is attempted on all WAL databases [attached] to ** [database connection] db. In this case the ** values written to output parameters *pnLog and *pnCkpt are undefined. ^If ** an SQLITE_BUSY error is encountered when processing one or more of the ** attached WAL databases, the operation is still attempted on any remaining ** attached databases and SQLITE_BUSY is returned at the end. ^If any other ** error occurs while processing an attached database, processing is abandoned ** and the error code is returned to the caller immediately. ^If no error ** (SQLITE_BUSY or otherwise) is encountered while processing the attached ** databases, SQLITE_OK is returned. ** ** ^If database zDb is the name of an attached database that is not in WAL ** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If ** zDb is not NULL (or a zero length string) and is not the name of any ** attached database, SQLITE_ERROR is returned to the caller. ** ** ^Unless it returns SQLITE_MISUSE, ** the sqlite3_wal_checkpoint_v2() interface ** sets the error information that is queried by ** [sqlite3_errcode()] and [sqlite3_errmsg()]. ** ** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface ** from SQL. */ SQLITE_API int sqlite3_wal_checkpoint_v2( sqlite3 *db, /* Database handle */ const char *zDb, /* Name of attached database (or NULL) */ int eMode, /* SQLITE_CHECKPOINT_* value */ int *pnLog, /* OUT: Size of WAL log in frames */ int *pnCkpt /* OUT: Total number of frames checkpointed */ ); /* ** CAPI3REF: Checkpoint Mode Values ** KEYWORDS: {checkpoint mode} ** ** These constants define all valid values for the "checkpoint mode" passed ** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface. ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ #define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ #define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ #define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */ #define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */ /* ** CAPI3REF: Virtual Table Interface Configuration ** ** This function may be called by either the [xConnect] or [xCreate] method ** of a [virtual table] implementation to configure ** various facets of the virtual table interface. ** ** If this interface is invoked outside the context of an xConnect or ** xCreate virtual table method then the behavior is undefined. ** ** In the call sqlite3_vtab_config(D,C,...) the D parameter is the ** [database connection] in which the virtual table is being created and ** which is passed in as the first argument to the [xConnect] or [xCreate] ** method that is invoking sqlite3_vtab_config(). The C parameter is one ** of the [virtual table configuration options]. The presence and meaning ** of parameters after C depend on which [virtual table configuration option] ** is used. */ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Virtual Table Configuration Options ** KEYWORDS: {virtual table configuration options} ** KEYWORDS: {virtual table configuration option} ** ** These macros define the various options to the ** [sqlite3_vtab_config()] interface that [virtual table] implementations ** can use to customize and optimize their behavior. ** **
** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]] **
SQLITE_VTAB_CONSTRAINT_SUPPORT
**
Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, ** where X is an integer. If X is zero, then the [virtual table] whose ** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not ** support constraints. In this configuration (which is the default) if ** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire ** statement is rolled back as if [ON CONFLICT | OR ABORT] had been ** specified as part of the users SQL statement, regardless of the actual ** ON CONFLICT mode specified. ** ** If X is non-zero, then the virtual table implementation guarantees ** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before ** any modifications to internal or persistent data structures have been made. ** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite ** is able to roll back a statement or database transaction, and abandon ** or continue processing the current SQL statement as appropriate. ** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns ** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode ** had been ABORT. ** ** Virtual table implementations that are required to handle OR REPLACE ** must do so within the [xUpdate] method. If a call to the ** [sqlite3_vtab_on_conflict()] function indicates that the current ON ** CONFLICT policy is REPLACE, the virtual table implementation should ** silently replace the appropriate rows within the xUpdate callback and ** return SQLITE_OK. Or, if this is not possible, it may return ** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT ** constraint handling. **
** ** [[SQLITE_VTAB_DIRECTONLY]]
SQLITE_VTAB_DIRECTONLY
**
Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the ** the [xConnect] or [xCreate] methods of a [virtual table] implementation ** prohibits that virtual table from being used from within triggers and ** views. **
** ** [[SQLITE_VTAB_INNOCUOUS]]
SQLITE_VTAB_INNOCUOUS
**
Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the ** the [xConnect] or [xCreate] methods of a [virtual table] implementation ** identify that virtual table as being safe to use from within triggers ** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the ** virtual table can do no serious harm even if it is controlled by a ** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS ** flag unless absolutely necessary. **
** ** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]
SQLITE_VTAB_USES_ALL_SCHEMAS
**
Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the ** the [xConnect] or [xCreate] methods of a [virtual table] implementation ** instruct the query planner to begin at least a read transaction on ** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the ** virtual table is used. **
**
*/ #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 #define SQLITE_VTAB_INNOCUOUS 2 #define SQLITE_VTAB_DIRECTONLY 3 #define SQLITE_VTAB_USES_ALL_SCHEMAS 4 /* ** CAPI3REF: Determine The Virtual Table Conflict Policy ** ** This function may only be called from within a call to the [xUpdate] method ** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The ** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], ** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode ** of the SQL statement that triggered the call to the [xUpdate] method of the ** [virtual table]. */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE ** ** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] ** method of a [virtual table], then it might return true if the ** column is being fetched as part of an UPDATE operation during which the ** column value will not change. The virtual table implementation can use ** this hint as permission to substitute a return value that is less ** expensive to compute and that the corresponding ** [xUpdate] method understands as a "no-change" value. ** ** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that ** the column is not changed by the UPDATE statement, then the xColumn ** method can optionally return without setting a result, without calling ** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. ** In that case, [sqlite3_value_nochange(X)] will return true for the ** same column in the [xUpdate] method. ** ** The sqlite3_vtab_nochange() routine is an optimization. Virtual table ** implementations should continue to give a correct answer even if the ** sqlite3_vtab_nochange() interface were to always return false. In the ** current implementation, the sqlite3_vtab_nochange() interface does always ** returns false for the enhanced [UPDATE FROM] statement. */ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); /* ** CAPI3REF: Determine The Collation For a Virtual Table Constraint ** METHOD: sqlite3_index_info ** ** This function may only be called from within a call to the [xBestIndex] ** method of a [virtual table]. This function returns a pointer to a string ** that is the name of the appropriate collation sequence to use for text ** comparisons on the constraint identified by its arguments. ** ** The first argument must be the pointer to the [sqlite3_index_info] object ** that is the first parameter to the xBestIndex() method. The second argument ** must be an index into the aConstraint[] array belonging to the ** sqlite3_index_info structure passed to xBestIndex. ** ** Important: ** The first parameter must be the same pointer that is passed into the ** xBestMethod() method. The first parameter may not be a pointer to a ** different [sqlite3_index_info] object, even an exact copy. ** ** The return value is computed as follows: ** **
    **
  1. If the constraint comes from a WHERE clause expression that contains ** a [COLLATE operator], then the name of the collation specified by ** that COLLATE operator is returned. **

  2. If there is no COLLATE operator, but the column that is the subject ** of the constraint specifies an alternative collating sequence via ** a [COLLATE clause] on the column definition within the CREATE TABLE ** statement that was passed into [sqlite3_declare_vtab()], then the ** name of that alternative collating sequence is returned. **

  3. Otherwise, "BINARY" is returned. **

*/ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); /* ** CAPI3REF: Determine if a virtual table query is DISTINCT ** METHOD: sqlite3_index_info ** ** This API may only be used from within an [xBestIndex|xBestIndex method] ** of a [virtual table] implementation. The result of calling this ** interface from outside of xBestIndex() is undefined and probably harmful. ** ** ^The sqlite3_vtab_distinct() interface returns an integer between 0 and ** 3. The integer returned by sqlite3_vtab_distinct() ** gives the virtual table additional information about how the query ** planner wants the output to be ordered. As long as the virtual table ** can meet the ordering requirements of the query planner, it may set ** the "orderByConsumed" flag. ** **
  1. ** ^If the sqlite3_vtab_distinct() interface returns 0, that means ** that the query planner needs the virtual table to return all rows in the ** sort order defined by the "nOrderBy" and "aOrderBy" fields of the ** [sqlite3_index_info] object. This is the default expectation. If the ** virtual table outputs all rows in sorted order, then it is always safe for ** the xBestIndex method to set the "orderByConsumed" flag, regardless of ** the return value from sqlite3_vtab_distinct(). **

  2. ** ^(If the sqlite3_vtab_distinct() interface returns 1, that means ** that the query planner does not need the rows to be returned in sorted order ** as long as all rows with the same values in all columns identified by the ** "aOrderBy" field are adjacent.)^ This mode is used when the query planner ** is doing a GROUP BY. **

  3. ** ^(If the sqlite3_vtab_distinct() interface returns 2, that means ** that the query planner does not need the rows returned in any particular ** order, as long as rows with the same values in all "aOrderBy" columns ** are adjacent.)^ ^(Furthermore, only a single row for each particular ** combination of values in the columns identified by the "aOrderBy" field ** needs to be returned.)^ ^It is always ok for two or more rows with the same ** values in all "aOrderBy" columns to be returned, as long as all such rows ** are adjacent. ^The virtual table may, if it chooses, omit extra rows ** that have the same value for all columns identified by "aOrderBy". ** ^However omitting the extra rows is optional. ** This mode is used for a DISTINCT query. **

  4. ** ^(If the sqlite3_vtab_distinct() interface returns 3, that means ** that the query planner needs only distinct rows but it does need the ** rows to be sorted.)^ ^The virtual table implementation is free to omit ** rows that are identical in all aOrderBy columns, if it wants to, but ** it is not required to omit any rows. This mode is used for queries ** that have both DISTINCT and ORDER BY clauses. **

** ** ^For the purposes of comparing virtual table output values to see if the ** values are same value for sorting purposes, two NULL values are considered ** to be the same. In other words, the comparison operator is "IS" ** (or "IS NOT DISTINCT FROM") and not "==". ** ** If a virtual table implementation is unable to meet the requirements ** specified above, then it must not set the "orderByConsumed" flag in the ** [sqlite3_index_info] object or an incorrect answer may result. ** ** ^A virtual table implementation is always free to return rows in any order ** it wants, as long as the "orderByConsumed" flag is not set. ^When the ** the "orderByConsumed" flag is unset, the query planner will add extra ** [bytecode] to ensure that the final results returned by the SQL query are ** ordered correctly. The use of the "orderByConsumed" flag and the ** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful ** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed" ** flag might help queries against a virtual table to run faster. Being ** overly aggressive and setting the "orderByConsumed" flag when it is not ** valid to do so, on the other hand, might cause SQLite to return incorrect ** results. */ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*); /* ** CAPI3REF: Identify and handle IN constraints in xBestIndex ** ** This interface may only be used from within an ** [xBestIndex|xBestIndex() method] of a [virtual table] implementation. ** The result of invoking this interface from any other context is ** undefined and probably harmful. ** ** ^(A constraint on a virtual table of the form ** "[IN operator|column IN (...)]" is ** communicated to the xBestIndex method as a ** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use ** this constraint, it must set the corresponding ** aConstraintUsage[].argvIndex to a positive integer. ^(Then, under ** the usual mode of handling IN operators, SQLite generates [bytecode] ** that invokes the [xFilter|xFilter() method] once for each value ** on the right-hand side of the IN operator.)^ Thus the virtual table ** only sees a single value from the right-hand side of the IN operator ** at a time. ** ** In some cases, however, it would be advantageous for the virtual ** table to see all values on the right-hand of the IN operator all at ** once. The sqlite3_vtab_in() interfaces facilitates this in two ways: ** **
    **
  1. ** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero) ** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint ** is an [IN operator] that can be processed all at once. ^In other words, ** sqlite3_vtab_in() with -1 in the third argument is a mechanism ** by which the virtual table can ask SQLite if all-at-once processing ** of the IN operator is even possible. ** **

  2. ** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates ** to SQLite that the virtual table does or does not want to process ** the IN operator all-at-once, respectively. ^Thus when the third ** parameter (F) is non-negative, this interface is the mechanism by ** which the virtual table tells SQLite how it wants to process the ** IN operator. **

** ** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times ** within the same xBestIndex method call. ^For any given P,N pair, ** the return value from sqlite3_vtab_in(P,N,F) will always be the same ** within the same xBestIndex call. ^If the interface returns true ** (non-zero), that means that the constraint is an IN operator ** that can be processed all-at-once. ^If the constraint is not an IN ** operator or cannot be processed all-at-once, then the interface returns ** false. ** ** ^(All-at-once processing of the IN operator is selected if both of the ** following conditions are met: ** **
    **
  1. The P->aConstraintUsage[N].argvIndex value is set to a positive ** integer. This is how the virtual table tells SQLite that it wants to ** use the N-th constraint. ** **

  2. The last call to sqlite3_vtab_in(P,N,F) for which F was ** non-negative had F>=1. **

)^ ** ** ^If either or both of the conditions above are false, then SQLite uses ** the traditional one-at-a-time processing strategy for the IN constraint. ** ^If both conditions are true, then the argvIndex-th parameter to the ** xFilter method will be an [sqlite3_value] that appears to be NULL, ** but which can be passed to [sqlite3_vtab_in_first()] and ** [sqlite3_vtab_in_next()] to find all values on the right-hand side ** of the IN constraint. */ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); /* ** CAPI3REF: Find all elements on the right-hand side of an IN constraint. ** ** These interfaces are only useful from within the ** [xFilter|xFilter() method] of a [virtual table] implementation. ** The result of invoking these interfaces from any other context ** is undefined and probably harmful. ** ** The X parameter in a call to sqlite3_vtab_in_first(X,P) or ** sqlite3_vtab_in_next(X,P) should be one of the parameters to the ** xFilter method which invokes these routines, and specifically ** a parameter that was previously selected for all-at-once IN constraint ** processing use the [sqlite3_vtab_in()] interface in the ** [xBestIndex|xBestIndex method]. ^(If the X parameter is not ** an xFilter argument that was selected for all-at-once IN constraint ** processing, then these routines return [SQLITE_ERROR].)^ ** ** ^(Use these routines to access all values on the right-hand side ** of the IN constraint using code like the following: ** **
**    for(rc=sqlite3_vtab_in_first(pList, &pVal);
**        rc==SQLITE_OK && pVal;
**        rc=sqlite3_vtab_in_next(pList, &pVal)
**    ){
**      // do something with pVal
**    }
**    if( rc!=SQLITE_OK ){
**      // an error has occurred
**    }
** 
)^ ** ** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P) ** routines return SQLITE_OK and set *P to point to the first or next value ** on the RHS of the IN constraint. ^If there are no more values on the ** right hand side of the IN constraint, then *P is set to NULL and these ** routines return [SQLITE_DONE]. ^The return value might be ** some other value, such as SQLITE_NOMEM, in the event of a malfunction. ** ** The *ppOut values returned by these routines are only valid until the ** next call to either of these routines or until the end of the xFilter ** method from which these routines were called. If the virtual table ** implementation needs to retain the *ppOut values for longer, it must make ** copies. The *ppOut values are [protected sqlite3_value|protected]. */ SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut); SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut); /* ** CAPI3REF: Constraint values in xBestIndex() ** METHOD: sqlite3_index_info ** ** This API may only be used from within the [xBestIndex|xBestIndex method] ** of a [virtual table] implementation. The result of calling this interface ** from outside of an xBestIndex method are undefined and probably harmful. ** ** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within ** the [xBestIndex] method of a [virtual table] implementation, with P being ** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and ** J being a 0-based index into P->aConstraint[], then this routine ** attempts to set *V to the value of the right-hand operand of ** that constraint if the right-hand operand is known. ^If the ** right-hand operand is not known, then *V is set to a NULL pointer. ** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if ** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V) ** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th ** constraint is not available. ^The sqlite3_vtab_rhs_value() interface ** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if ** something goes wrong. ** ** The sqlite3_vtab_rhs_value() interface is usually only successful if ** the right-hand operand of a constraint is a literal value in the original ** SQL statement. If the right-hand operand is an expression or a reference ** to some other column or a [host parameter], then sqlite3_vtab_rhs_value() ** will probably return [SQLITE_NOTFOUND]. ** ** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and ** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such ** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^ ** ** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value ** and remains valid for the duration of the xBestIndex method call. ** ^When xBestIndex returns, the sqlite3_value object returned by ** sqlite3_vtab_rhs_value() is automatically deallocated. ** ** The "_rhs_" in the name of this routine is an abbreviation for ** "Right-Hand Side". */ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal); /* ** CAPI3REF: Conflict resolution modes ** KEYWORDS: {conflict resolution mode} ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to ** inform a [virtual table] implementation what the [ON CONFLICT] mode ** is for the SQL statement being evaluated. ** ** Note that the [SQLITE_IGNORE] constant is also used as a potential ** return value from the [sqlite3_set_authorizer()] callback and that ** [SQLITE_ABORT] is also a [result code]. */ #define SQLITE_ROLLBACK 1 /* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ #define SQLITE_FAIL 3 /* #define SQLITE_ABORT 4 // Also an error code */ #define SQLITE_REPLACE 5 /* ** CAPI3REF: Prepared Statement Scan Status Opcodes ** KEYWORDS: {scanstatus options} ** ** The following constants can be used for the T parameter to the ** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a ** different metric for sqlite3_stmt_scanstatus() to return. ** ** When the value returned to V is a string, space to hold that string is ** managed by the prepared statement S and will be automatically freed when ** S is finalized. ** ** Not all values are available for all query elements. When a value is ** not available, the output variable is set to -1 if the value is numeric, ** or to NULL if it is a string (SQLITE_SCANSTAT_NAME). ** **
** [[SQLITE_SCANSTAT_NLOOP]]
SQLITE_SCANSTAT_NLOOP
**
^The [sqlite3_int64] variable pointed to by the V parameter will be ** set to the total number of times that the X-th loop has run.
** ** [[SQLITE_SCANSTAT_NVISIT]]
SQLITE_SCANSTAT_NVISIT
**
^The [sqlite3_int64] variable pointed to by the V parameter will be set ** to the total number of rows examined by all iterations of the X-th loop.
** ** [[SQLITE_SCANSTAT_EST]]
SQLITE_SCANSTAT_EST
**
^The "double" variable pointed to by the V parameter will be set to the ** query planner's estimate for the average number of rows output from each ** iteration of the X-th loop. If the query planner's estimates was accurate, ** then this value will approximate the quotient NVISIT/NLOOP and the ** product of this value for all prior loops with the same SELECTID will ** be the NLOOP value for the current loop. ** ** [[SQLITE_SCANSTAT_NAME]]
SQLITE_SCANSTAT_NAME
**
^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the name of the index or table ** used for the X-th loop. ** ** [[SQLITE_SCANSTAT_EXPLAIN]]
SQLITE_SCANSTAT_EXPLAIN
**
^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] ** description for the X-th loop. ** ** [[SQLITE_SCANSTAT_SELECTID]]
SQLITE_SCANSTAT_SELECTID
**
^The "int" variable pointed to by the V parameter will be set to the ** id for the X-th query plan element. The id value is unique within the ** statement. The select-id is the same value as is output in the first ** column of an [EXPLAIN QUERY PLAN] query. ** ** [[SQLITE_SCANSTAT_PARENTID]]
SQLITE_SCANSTAT_PARENTID
**
The "int" variable pointed to by the V parameter will be set to the ** the id of the parent of the current query element, if applicable, or ** to zero if the query element has no parent. This is the same value as ** returned in the second column of an [EXPLAIN QUERY PLAN] query. ** ** [[SQLITE_SCANSTAT_NCYCLE]]
SQLITE_SCANSTAT_NCYCLE
**
The sqlite3_int64 output value is set to the number of cycles, ** according to the processor time-stamp counter, that elapsed while the ** query element was being processed. This value is not available for ** all query elements - if it is unavailable the output variable is ** set to -1. **
*/ #define SQLITE_SCANSTAT_NLOOP 0 #define SQLITE_SCANSTAT_NVISIT 1 #define SQLITE_SCANSTAT_EST 2 #define SQLITE_SCANSTAT_NAME 3 #define SQLITE_SCANSTAT_EXPLAIN 4 #define SQLITE_SCANSTAT_SELECTID 5 #define SQLITE_SCANSTAT_PARENTID 6 #define SQLITE_SCANSTAT_NCYCLE 7 /* ** CAPI3REF: Prepared Statement Scan Status ** METHOD: sqlite3_stmt ** ** These interfaces return information about the predicted and measured ** performance for pStmt. Advanced applications can use this ** interface to compare the predicted and the measured performance and ** issue warnings and/or rerun [ANALYZE] if discrepancies are found. ** ** Since this interface is expected to be rarely used, it is only ** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS] ** compile-time option. ** ** The "iScanStatusOp" parameter determines which status information to return. ** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior ** of this interface is undefined. ^The requested measurement is written into ** a variable pointed to by the "pOut" parameter. ** ** The "flags" parameter must be passed a mask of flags. At present only ** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX ** is specified, then status information is available for all elements ** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If ** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements ** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of ** the EXPLAIN QUERY PLAN output) are available. Invoking API ** sqlite3_stmt_scanstatus() is equivalent to calling ** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter. ** ** Parameter "idx" identifies the specific query element to retrieve statistics ** for. Query elements are numbered starting from zero. A value of -1 may be ** to query for statistics regarding the entire query. ^If idx is out of range ** - less than -1 or greater than or equal to the total number of query ** elements used to implement the statement - a non-zero value is returned and ** the variable that pOut points to is unchanged. ** ** See also: [sqlite3_stmt_scanstatus_reset()] */ SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ int idx, /* Index of loop to report on */ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ void *pOut /* Result written here */ ); SQLITE_API int sqlite3_stmt_scanstatus_v2( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ int idx, /* Index of loop to report on */ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ int flags, /* Mask of flags defined below */ void *pOut /* Result written here */ ); /* ** CAPI3REF: Prepared Statement Scan Status ** KEYWORDS: {scan status flags} */ #define SQLITE_SCANSTAT_COMPLEX 0x0001 /* ** CAPI3REF: Zero Scan-Status Counters ** METHOD: sqlite3_stmt ** ** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. ** ** This API is only available if the library is built with pre-processor ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. */ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction ** METHOD: sqlite3 ** ** ^If a write-transaction is open on [database connection] D when the ** [sqlite3_db_cacheflush(D)] interface invoked, any dirty ** pages in the pager-cache that are not currently in use are written out ** to disk. A dirty page may be in use if a database cursor created by an ** active SQL statement is reading from it, or if it is page 1 of a database ** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)] ** interface flushes caches for all schemas - "main", "temp", and ** any [attached] databases. ** ** ^If this function needs to obtain extra database locks before dirty pages ** can be flushed to disk, it does so. ^If those locks cannot be obtained ** immediately and there is a busy-handler callback configured, it is invoked ** in the usual manner. ^If the required lock still cannot be obtained, then ** the database is skipped and an attempt made to flush any dirty pages ** belonging to the next (if any) database. ^If any databases are skipped ** because locks cannot be obtained, but no other error occurs, this ** function returns SQLITE_BUSY. ** ** ^If any other error occurs while flushing dirty pages to disk (for ** example an IO error or out-of-memory condition), then processing is ** abandoned and an SQLite [error code] is returned to the caller immediately. ** ** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK. ** ** ^This function does not set the database handle error code or message ** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions. */ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); /* ** CAPI3REF: The pre-update hook. ** METHOD: sqlite3 ** ** ^These interfaces are only available if SQLite is compiled using the ** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. ** ** ^The [sqlite3_preupdate_hook()] interface registers a callback function ** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation ** on a database table. ** ^At most one preupdate hook may be registered at a time on a single ** [database connection]; each call to [sqlite3_preupdate_hook()] overrides ** the previous setting. ** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()] ** with a NULL pointer as the second parameter. ** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as ** the first parameter to callbacks. ** ** ^The preupdate hook only fires for changes to real database tables; the ** preupdate hook is not invoked for changes to [virtual tables] or to ** system tables like sqlite_sequence or sqlite_stat1. ** ** ^The second parameter to the preupdate callback is a pointer to ** the [database connection] that registered the preupdate hook. ** ^The third parameter to the preupdate callback is one of the constants ** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the ** kind of update operation that is about to occur. ** ^(The fourth parameter to the preupdate callback is the name of the ** database within the database connection that is being modified. This ** will be "main" for the main database or "temp" for TEMP tables or ** the name given after the AS keyword in the [ATTACH] statement for attached ** databases.)^ ** ^The fifth parameter to the preupdate callback is the name of the ** table that is being modified. ** ** For an UPDATE or DELETE operation on a [rowid table], the sixth ** parameter passed to the preupdate callback is the initial [rowid] of the ** row being modified or deleted. For an INSERT operation on a rowid table, ** or any operation on a WITHOUT ROWID table, the value of the sixth ** parameter is undefined. For an INSERT or UPDATE on a rowid table the ** seventh parameter is the final rowid value of the row being inserted ** or updated. The value of the seventh parameter passed to the callback ** function is not defined for operations on WITHOUT ROWID tables, or for ** DELETE operations on rowid tables. ** ** ^The sqlite3_preupdate_hook(D,C,P) function returns the P argument from ** the previous call on the same [database connection] D, or NULL for ** the first call on D. ** ** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces ** provide additional information about a preupdate event. These routines ** may only be called from within a preupdate callback. Invoking any of ** these routines from outside of a preupdate callback or with a ** [database connection] pointer that is different from the one supplied ** to the preupdate callback results in undefined and probably undesirable ** behavior. ** ** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns ** in the row that is being inserted, updated, or deleted. ** ** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to ** a [protected sqlite3_value] that contains the value of the Nth column of ** the table row before it is updated. The N parameter must be between 0 ** and one less than the number of columns or the behavior will be ** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE ** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the ** behavior is undefined. The [sqlite3_value] that P points to ** will be destroyed when the preupdate callback returns. ** ** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to ** a [protected sqlite3_value] that contains the value of the Nth column of ** the table row after it is updated. The N parameter must be between 0 ** and one less than the number of columns or the behavior will be ** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE ** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the ** behavior is undefined. The [sqlite3_value] that P points to ** will be destroyed when the preupdate callback returns. ** ** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate ** callback was invoked as a result of a direct insert, update, or delete ** operation; or 1 for inserts, updates, or deletes invoked by top-level ** triggers; or 2 for changes resulting from triggers called by top-level ** triggers; and so forth. ** ** When the [sqlite3_blob_write()] API is used to update a blob column, ** the pre-update hook is invoked with SQLITE_DELETE. This is because the ** in this case the new values are not available. In this case, when a ** callback made with op==SQLITE_DELETE is actually a write using the ** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns ** the index of the column being written. In other cases, where the ** pre-update hook is being invoked for some other reason, including a ** regular DELETE, sqlite3_preupdate_blobwrite() returns -1. ** ** See also: [sqlite3_update_hook()] */ #if defined(SQLITE_ENABLE_PREUPDATE_HOOK) SQLITE_API void *sqlite3_preupdate_hook( sqlite3 *db, void(*xPreUpdate)( void *pCtx, /* Copy of third arg to preupdate_hook() */ sqlite3 *db, /* Database handle */ int op, /* SQLITE_UPDATE, DELETE or INSERT */ char const *zDb, /* Database name */ char const *zName, /* Table name */ sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ ), void* ); SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); SQLITE_API int sqlite3_preupdate_count(sqlite3 *); SQLITE_API int sqlite3_preupdate_depth(sqlite3 *); SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *); #endif /* ** CAPI3REF: Low-level system error code ** METHOD: sqlite3 ** ** ^Attempt to return the underlying operating system error code or error ** number that caused the most recent I/O error or failure to open a file. ** The return value is OS-dependent. For example, on unix systems, after ** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be ** called to get back the underlying "errno" that caused the problem, such ** as ENOSPC, EAUTH, EISDIR, and so forth. */ SQLITE_API int sqlite3_system_errno(sqlite3*); /* ** CAPI3REF: Database Snapshot ** KEYWORDS: {snapshot} {sqlite3_snapshot} ** ** An instance of the snapshot object records the state of a [WAL mode] ** database for some specific point in history. ** ** In [WAL mode], multiple [database connections] that are open on the ** same database file can each be reading a different historical version ** of the database file. When a [database connection] begins a read ** transaction, that connection sees an unchanging copy of the database ** as it existed for the point in time when the transaction first started. ** Subsequent changes to the database from other connections are not seen ** by the reader until a new read transaction is started. ** ** The sqlite3_snapshot object records state information about an historical ** version of the database file so that it is possible to later open a new read ** transaction that sees that historical version of the database rather than ** the most recent version. */ typedef struct sqlite3_snapshot { unsigned char hidden[48]; } sqlite3_snapshot; /* ** CAPI3REF: Record A Database Snapshot ** CONSTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a ** new [sqlite3_snapshot] object that records the current state of ** schema S in database connection D. ^On success, the ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. ** If there is not already a read-transaction open on schema S when ** this function is called, one is opened automatically. ** ** The following must be true for this function to succeed. If any of ** the following statements are false when sqlite3_snapshot_get() is ** called, SQLITE_ERROR is returned. The final value of *P is undefined ** in this case. ** **
    **
  • The database handle must not be in [autocommit mode]. ** **
  • Schema S of [database connection] D must be a [WAL mode] database. ** **
  • There must not be a write transaction open on schema S of database ** connection D. ** **
  • One or more transactions must have been written to the current wal ** file since it was created on disk (by any connection). This means ** that a snapshot cannot be taken on a wal mode database with no wal ** file immediately after it is first opened. At least one transaction ** must be written to it first. **
** ** This function may also return SQLITE_NOMEM. If it is called with the ** database handle in autocommit mode but fails for some other reason, ** whether or not a read transaction is opened on schema S is undefined. ** ** The [sqlite3_snapshot] object returned from a successful call to ** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()] ** to avoid a memory leak. ** ** The [sqlite3_snapshot_get()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( sqlite3 *db, const char *zSchema, sqlite3_snapshot **ppSnapshot ); /* ** CAPI3REF: Start a read transaction on an historical snapshot ** METHOD: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read ** transaction or upgrades an existing one for schema S of ** [database connection] D such that the read transaction refers to ** historical [snapshot] P, rather than the most recent change to the ** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK ** on success or an appropriate [error code] if it fails. ** ** ^In order to succeed, the database connection must not be in ** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there ** is already a read transaction open on schema S, then the database handle ** must have no active statements (SELECT statements that have been passed ** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()). ** SQLITE_ERROR is returned if either of these conditions is violated, or ** if schema S does not exist, or if the snapshot object is invalid. ** ** ^A call to sqlite3_snapshot_open() will fail to open if the specified ** snapshot has been overwritten by a [checkpoint]. In this case ** SQLITE_ERROR_SNAPSHOT is returned. ** ** If there is already a read transaction open when this function is ** invoked, then the same read transaction remains open (on the same ** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT ** is returned. If another error code - for example SQLITE_PROTOCOL or an ** SQLITE_IOERR error code - is returned, then the final state of the ** read transaction is undefined. If SQLITE_OK is returned, then the ** read transaction is now open on database snapshot P. ** ** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the ** database connection D does not know that the database file for ** schema S is in [WAL mode]. A database connection might not know ** that the database file is in [WAL mode] if there has been no prior ** I/O on that database connection, or if the database entered [WAL mode] ** after the most recent I/O on the database connection.)^ ** (Hint: Run "[PRAGMA application_id]" against a newly opened ** database connection in order to make it ready to use snapshots.) ** ** The [sqlite3_snapshot_open()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( sqlite3 *db, const char *zSchema, sqlite3_snapshot *pSnapshot ); /* ** CAPI3REF: Destroy a snapshot ** DESTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P. ** The application must eventually free every [sqlite3_snapshot] object ** using this routine to avoid a memory leak. ** ** The [sqlite3_snapshot_free()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); /* ** CAPI3REF: Compare the ages of two snapshot handles. ** METHOD: sqlite3_snapshot ** ** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages ** of two valid snapshot handles. ** ** If the two snapshot handles are not associated with the same database ** file, the result of the comparison is undefined. ** ** Additionally, the result of the comparison is only valid if both of the ** snapshot handles were obtained by calling sqlite3_snapshot_get() since the ** last time the wal file was deleted. The wal file is deleted when the ** database is changed back to rollback mode or when the number of database ** clients drops to zero. If either snapshot handle was obtained before the ** wal file was last deleted, the value returned by this function ** is undefined. ** ** Otherwise, this API returns a negative value if P1 refers to an older ** snapshot than P2, zero if the two handles refer to the same database ** snapshot, and a positive value if P1 is a newer snapshot than P2. ** ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( sqlite3_snapshot *p1, sqlite3_snapshot *p2 ); /* ** CAPI3REF: Recover snapshots from a wal file ** METHOD: sqlite3_snapshot ** ** If a [WAL file] remains on disk after all database connections close ** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control] ** or because the last process to have the database opened exited without ** calling [sqlite3_close()]) and a new connection is subsequently opened ** on that database and [WAL file], the [sqlite3_snapshot_open()] interface ** will only be able to open the last transaction added to the WAL file ** even though the WAL file contains other valid transactions. ** ** This function attempts to scan the WAL file associated with database zDb ** of database handle db and make all valid snapshots available to ** sqlite3_snapshot_open(). It is an error if there is already a read ** transaction open on the database, or if the database is not a WAL mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. ** ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Serialize a database ** ** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory ** that is a serialization of the S database on [database connection] D. ** If P is not a NULL pointer, then the size of the database in bytes ** is written into *P. ** ** For an ordinary on-disk database file, the serialization is just a ** copy of the disk file. For an in-memory database or a "TEMP" database, ** the serialization is the same sequence of bytes which would be written ** to disk if that database where backed up to disk. ** ** The usual case is that sqlite3_serialize() copies the serialization of ** the database into memory obtained from [sqlite3_malloc64()] and returns ** a pointer to that memory. The caller is responsible for freeing the ** returned value to avoid a memory leak. However, if the F argument ** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations ** are made, and the sqlite3_serialize() function will return a pointer ** to the contiguous memory representation of the database that SQLite ** is currently using for that database, or NULL if the no such contiguous ** memory representation of the database exists. A contiguous memory ** representation of the database will usually only exist if there has ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same ** values of D and S. ** The size of the database is written into *P even if the ** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** ** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set, ** the returned buffer content will remain accessible and unchanged ** until either the next write operation on the connection or when ** the connection is closed, and applications must not modify the ** buffer. If the bit had been clear, the returned buffer will not ** be accessed by SQLite after the call. ** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** allocation error occurs. ** ** This interface is omitted if SQLite is compiled with the ** [SQLITE_OMIT_DESERIALIZE] option. */ SQLITE_API unsigned char *sqlite3_serialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */ sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */ unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */ ); /* ** CAPI3REF: Flags for sqlite3_serialize ** ** Zero or more of the following constants can be OR-ed together for ** the F argument to [sqlite3_serialize(D,S,P,F)]. ** ** SQLITE_SERIALIZE_NOCOPY means that [sqlite3_serialize()] will return ** a pointer to contiguous in-memory database that it is currently using, ** without making a copy of the database. If SQLite is not currently using ** a contiguous in-memory database, then this option causes ** [sqlite3_serialize()] to return a NULL pointer. SQLite will only be ** using a contiguous in-memory database if it has been initialized by a ** prior call to [sqlite3_deserialize()]. */ #define SQLITE_SERIALIZE_NOCOPY 0x001 /* Do no memory allocations */ /* ** CAPI3REF: Deserialize a database ** ** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the ** [database connection] D to disconnect from database S and then ** reopen S as an in-memory database based on the serialization contained ** in P. The serialized database P is N bytes in size. M is the size of ** the buffer P, which might be larger than N. If M is larger than N, and ** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is ** permitted to add content to the in-memory database as long as the total ** size does not exceed M bytes. ** ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will ** invoke sqlite3_free() on the serialization buffer when the database ** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then ** SQLite will try to increase the buffer size using sqlite3_realloc64() ** if writes on the database cause it to grow larger than M bytes. ** ** Applications must not modify the buffer P or invalidate it before ** the database connection D is closed. ** ** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. ** ** It is not possible to deserialized into the TEMP database. If the ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the ** function returns SQLITE_ERROR. ** ** The deserialized database should not be in [WAL mode]. If the database ** is in WAL mode, then any attempt to use the database file will result ** in an [SQLITE_CANTOPEN] error. The application can set the ** [file format version numbers] (bytes 18 and 19) of the input database P ** to 0x01 prior to invoking sqlite3_deserialize(D,S,P,N,M,F) to force the ** database file into rollback mode and work around this limitation. ** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. ** ** This interface is omitted if SQLite is compiled with the ** [SQLITE_OMIT_DESERIALIZE] option. */ SQLITE_API int sqlite3_deserialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to reopen with the deserialization */ unsigned char *pData, /* The serialized database content */ sqlite3_int64 szDb, /* Number bytes in the deserialization */ sqlite3_int64 szBuf, /* Total size of buffer pData[] */ unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ ); /* ** CAPI3REF: Flags for sqlite3_deserialize() ** ** The following are allowed values for 6th argument (the F argument) to ** the [sqlite3_deserialize(D,S,P,N,M,F)] interface. ** ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization ** in the P argument is held in memory obtained from [sqlite3_malloc64()] ** and that SQLite should take ownership of this memory and automatically ** free it when it has finished using it. Without this flag, the caller ** is responsible for freeing any dynamically allocated memory. ** ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to ** grow the size of the database using calls to [sqlite3_realloc64()]. This ** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. ** Without this flag, the deserialized database cannot increase in size beyond ** the number of bytes specified by the M parameter. ** ** The SQLITE_DESERIALIZE_READONLY flag means that the deserialized database ** should be treated as read-only. */ #define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */ #define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */ #define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */ /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #if defined(__wasi__) # undef SQLITE_WASI # define SQLITE_WASI 1 # undef SQLITE_OMIT_WAL # define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */ # ifndef SQLITE_OMIT_LOAD_EXTENSION # define SQLITE_OMIT_LOAD_EXTENSION # endif # ifndef SQLITE_THREADSAFE # define SQLITE_THREADSAFE 0 # endif #endif #if 0 } /* End of the 'extern "C"' block */ #endif #endif /* SQLITE3_H */ /******** Begin file sqlite3rtree.h *********/ /* ** 2010 August 30 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* */ #ifndef _SQLITE3RTREE_H_ #define _SQLITE3RTREE_H_ #if 0 extern "C" { #endif typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; /* The double-precision datatype used by RTree depends on the ** SQLITE_RTREE_INT_ONLY compile-time option. */ #ifdef SQLITE_RTREE_INT_ONLY typedef sqlite3_int64 sqlite3_rtree_dbl; #else typedef double sqlite3_rtree_dbl; #endif /* ** Register a geometry callback named zGeom that can be used as part of an ** R-Tree geometry query as follows: ** ** SELECT ... FROM WHERE MATCH $zGeom(... params ...) */ SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), void *pContext ); /* ** A pointer to a structure of the following type is passed as the first ** argument to callbacks registered using rtree_geometry_callback(). */ struct sqlite3_rtree_geometry { void *pContext; /* Copy of pContext passed to s_r_g_c() */ int nParam; /* Size of array aParam[] */ sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ void *pUser; /* Callback implementation user data */ void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ }; /* ** Register a 2nd-generation geometry callback named zScore that can be ** used as part of an R-Tree geometry query as follows: ** ** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) */ SQLITE_API int sqlite3_rtree_query_callback( sqlite3 *db, const char *zQueryFunc, int (*xQueryFunc)(sqlite3_rtree_query_info*), void *pContext, void (*xDestructor)(void*) ); /* ** A pointer to a structure of the following type is passed as the ** argument to scored geometry callback registered using ** sqlite3_rtree_query_callback(). ** ** Note that the first 5 fields of this structure are identical to ** sqlite3_rtree_geometry. This structure is a subclass of ** sqlite3_rtree_geometry. */ struct sqlite3_rtree_query_info { void *pContext; /* pContext from when function registered */ int nParam; /* Number of function parameters */ sqlite3_rtree_dbl *aParam; /* value of function parameters */ void *pUser; /* callback can use this, if desired */ void (*xDelUser)(void*); /* function to free pUser */ sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ unsigned int *anQueue; /* Number of pending entries in the queue */ int nCoord; /* Number of coordinates */ int iLevel; /* Level of current node or entry */ int mxLevel; /* The largest iLevel value in the tree */ sqlite3_int64 iRowid; /* Rowid for current entry */ sqlite3_rtree_dbl rParentScore; /* Score of parent node */ int eParentWithin; /* Visibility of parent node */ int eWithin; /* OUT: Visibility */ sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ /* The following fields are only available in 3.8.11 and later */ sqlite3_value **apSqlParam; /* Original SQL values of parameters */ }; /* ** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin. */ #define NOT_WITHIN 0 /* Object completely outside of query region */ #define PARTLY_WITHIN 1 /* Object partially overlaps query region */ #define FULLY_WITHIN 2 /* Object fully contained within query region */ #if 0 } /* end of the 'extern "C"' block */ #endif #endif /* ifndef _SQLITE3RTREE_H_ */ /******** End of sqlite3rtree.h *********/ /******** Begin file sqlite3session.h *********/ #if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) #define __SQLITESESSION_H_ 1 /* ** Make sure we can call this stuff from C++. */ #if 0 extern "C" { #endif /* ** CAPI3REF: Session Object Handle ** ** An instance of this object is a [session] that can be used to ** record changes to a database. */ typedef struct sqlite3_session sqlite3_session; /* ** CAPI3REF: Changeset Iterator Handle ** ** An instance of this object acts as a cursor for iterating ** over the elements of a [changeset] or [patchset]. */ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; /* ** CAPI3REF: Create A New Session Object ** CONSTRUCTOR: sqlite3_session ** ** Create a new session object attached to database handle db. If successful, ** a pointer to the new object is written to *ppSession and SQLITE_OK is ** returned. If an error occurs, *ppSession is set to NULL and an SQLite ** error code (e.g. SQLITE_NOMEM) is returned. ** ** It is possible to create multiple session objects attached to a single ** database handle. ** ** Session objects created using this function should be deleted using the ** [sqlite3session_delete()] function before the database handle that they ** are attached to is itself closed. If the database handle is closed before ** the session object is deleted, then the results of calling any session ** module function, including [sqlite3session_delete()] on the session object ** are undefined. ** ** Because the session module uses the [sqlite3_preupdate_hook()] API, it ** is not possible for an application to register a pre-update hook on a ** database handle that has one or more session objects attached. Nor is ** it possible to create a session object attached to a database handle for ** which a pre-update hook is already defined. The results of attempting ** either of these things are undefined. ** ** The session object will be used to create changesets for tables in ** database zDb, where zDb is either "main", or "temp", or the name of an ** attached database. It is not an error if database zDb is not attached ** to the database when the session object is created. */ SQLITE_API int sqlite3session_create( sqlite3 *db, /* Database handle */ const char *zDb, /* Name of db (e.g. "main") */ sqlite3_session **ppSession /* OUT: New session object */ ); /* ** CAPI3REF: Delete A Session Object ** DESTRUCTOR: sqlite3_session ** ** Delete a session object previously allocated using ** [sqlite3session_create()]. Once a session object has been deleted, the ** results of attempting to use pSession with any other session module ** function are undefined. ** ** Session objects must be deleted before the database handle to which they ** are attached is closed. Refer to the documentation for ** [sqlite3session_create()] for details. */ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); /* ** CAPI3REF: Configure a Session Object ** METHOD: sqlite3_session ** ** This method is used to configure a session object after it has been ** created. At present the only valid values for the second parameter are ** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID]. ** */ SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); /* ** CAPI3REF: Options for sqlite3session_object_config ** ** The following values may passed as the the 2nd parameter to ** sqlite3session_object_config(). ** **
SQLITE_SESSION_OBJCONFIG_SIZE
** This option is used to set, clear or query the flag that enables ** the [sqlite3session_changeset_size()] API. Because it imposes some ** computational overhead, this API is disabled by default. Argument ** pArg must point to a value of type (int). If the value is initially ** 0, then the sqlite3session_changeset_size() API is disabled. If it ** is greater than 0, then the same API is enabled. Or, if the initial ** value is less than zero, no change is made. In all cases the (int) ** variable is set to 1 if the sqlite3session_changeset_size() API is ** enabled following the current call, or 0 otherwise. ** ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after ** the first table has been attached to the session object. ** **
SQLITE_SESSION_OBJCONFIG_ROWID
** This option is used to set, clear or query the flag that enables ** collection of data for tables with no explicit PRIMARY KEY. ** ** Normally, tables with no explicit PRIMARY KEY are simply ignored ** by the sessions module. However, if this flag is set, it behaves ** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted ** as their leftmost columns. ** ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after ** the first table has been attached to the session object. */ #define SQLITE_SESSION_OBJCONFIG_SIZE 1 #define SQLITE_SESSION_OBJCONFIG_ROWID 2 /* ** CAPI3REF: Enable Or Disable A Session Object ** METHOD: sqlite3_session ** ** Enable or disable the recording of changes by a session object. When ** enabled, a session object records changes made to the database. When ** disabled - it does not. A newly created session object is enabled. ** Refer to the documentation for [sqlite3session_changeset()] for further ** details regarding how enabling and disabling a session object affects ** the eventual changesets. ** ** Passing zero to this function disables the session. Passing a value ** greater than zero enables it. Passing a value less than zero is a ** no-op, and may be used to query the current state of the session. ** ** The return value indicates the final state of the session object: 0 if ** the session is disabled, or 1 if it is enabled. */ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); /* ** CAPI3REF: Set Or Clear the Indirect Change Flag ** METHOD: sqlite3_session ** ** Each change recorded by a session object is marked as either direct or ** indirect. A change is marked as indirect if either: ** **
    **
  • The session object "indirect" flag is set when the change is ** made, or **
  • The change is made by an SQL trigger or foreign key action ** instead of directly as a result of a users SQL statement. **
** ** If a single row is affected by more than one operation within a session, ** then the change is considered indirect if all operations meet the criteria ** for an indirect change above, or direct otherwise. ** ** This function is used to set, clear or query the session object indirect ** flag. If the second argument passed to this function is zero, then the ** indirect flag is cleared. If it is greater than zero, the indirect flag ** is set. Passing a value less than zero does not modify the current value ** of the indirect flag, and may be used to query the current state of the ** indirect flag for the specified session object. ** ** The return value indicates the final state of the indirect flag: 0 if ** it is clear, or 1 if it is set. */ SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect); /* ** CAPI3REF: Attach A Table To A Session Object ** METHOD: sqlite3_session ** ** If argument zTab is not NULL, then it is the name of a table to attach ** to the session object passed as the first argument. All subsequent changes ** made to the table while the session object is enabled will be recorded. See ** documentation for [sqlite3session_changeset()] for further details. ** ** Or, if argument zTab is NULL, then changes are recorded for all tables ** in the database. If additional tables are added to the database (by ** executing "CREATE TABLE" statements) after this call is made, changes for ** the new tables are also recorded. ** ** Changes can only be recorded for tables that have a PRIMARY KEY explicitly ** defined as part of their CREATE TABLE statement. It does not matter if the ** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY ** KEY may consist of a single column, or may be a composite key. ** ** It is not an error if the named table does not exist in the database. Nor ** is it an error if the named table does not have a PRIMARY KEY. However, ** no changes will be recorded in either of these scenarios. ** ** Changes are not recorded for individual rows that have NULL values stored ** in one or more of their PRIMARY KEY columns. ** ** SQLITE_OK is returned if the call completes without error. Or, if an error ** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. ** **

Special sqlite_stat1 Handling

** ** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to ** some of the rules above. In SQLite, the schema of sqlite_stat1 is: **
**        CREATE TABLE sqlite_stat1(tbl,idx,stat)
**  
** ** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are ** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes ** are recorded for rows for which (idx IS NULL) is true. However, for such ** rows a zero-length blob (SQL value X'') is stored in the changeset or ** patchset instead of a NULL value. This allows such changesets to be ** manipulated by legacy implementations of sqlite3changeset_invert(), ** concat() and similar. ** ** The sqlite3changeset_apply() function automatically converts the ** zero-length blob back to a NULL value when updating the sqlite_stat1 ** table. However, if the application calls sqlite3changeset_new(), ** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset ** iterator directly (including on a changeset iterator passed to a ** conflict-handler callback) then the X'' value is returned. The application ** must translate X'' to NULL itself if required. ** ** Legacy (older than 3.22.0) versions of the sessions module cannot capture ** changes made to the sqlite_stat1 table. Legacy versions of the ** sqlite3changeset_apply() function silently ignore any modifications to the ** sqlite_stat1 table that are part of a changeset or patchset. */ SQLITE_API int sqlite3session_attach( sqlite3_session *pSession, /* Session object */ const char *zTab /* Table name */ ); /* ** CAPI3REF: Set a table filter on a Session Object. ** METHOD: sqlite3_session ** ** The second argument (xFilter) is the "filter callback". For changes to rows ** in tables that are not attached to the Session object, the filter is called ** to determine whether changes to the table's rows should be tracked or not. ** If xFilter returns 0, changes are not tracked. Note that once a table is ** attached, xFilter will not be called again. */ SQLITE_API void sqlite3session_table_filter( sqlite3_session *pSession, /* Session object */ int(*xFilter)( void *pCtx, /* Copy of third arg to _filter_table() */ const char *zTab /* Table name */ ), void *pCtx /* First argument passed to xFilter */ ); /* ** CAPI3REF: Generate A Changeset From A Session Object ** METHOD: sqlite3_session ** ** Obtain a changeset containing changes to the tables attached to the ** session object passed as the first argument. If successful, ** set *ppChangeset to point to a buffer containing the changeset ** and *pnChangeset to the size of the changeset in bytes before returning ** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to ** zero and return an SQLite error code. ** ** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes, ** each representing a change to a single row of an attached table. An INSERT ** change contains the values of each field of a new database row. A DELETE ** contains the original values of each field of a deleted database row. An ** UPDATE change contains the original values of each field of an updated ** database row along with the updated values for each updated non-primary-key ** column. It is not possible for an UPDATE change to represent a change that ** modifies the values of primary key columns. If such a change is made, it ** is represented in a changeset as a DELETE followed by an INSERT. ** ** Changes are not recorded for rows that have NULL values stored in one or ** more of their PRIMARY KEY columns. If such a row is inserted or deleted, ** no corresponding change is present in the changesets returned by this ** function. If an existing row with one or more NULL values stored in ** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL, ** only an INSERT is appears in the changeset. Similarly, if an existing row ** with non-NULL PRIMARY KEY values is updated so that one or more of its ** PRIMARY KEY columns are set to NULL, the resulting changeset contains a ** DELETE change only. ** ** The contents of a changeset may be traversed using an iterator created ** using the [sqlite3changeset_start()] API. A changeset may be applied to ** a database with a compatible schema using the [sqlite3changeset_apply()] ** API. ** ** Within a changeset generated by this function, all changes related to a ** single table are grouped together. In other words, when iterating through ** a changeset or when applying a changeset to a database, all changes related ** to a single table are processed before moving on to the next table. Tables ** are sorted in the same order in which they were attached (or auto-attached) ** to the sqlite3_session object. The order in which the changes related to ** a single table are stored is undefined. ** ** Following a successful call to this function, it is the responsibility of ** the caller to eventually free the buffer that *ppChangeset points to using ** [sqlite3_free()]. ** **

Changeset Generation

** ** Once a table has been attached to a session object, the session object ** records the primary key values of all new rows inserted into the table. ** It also records the original primary key and other column values of any ** deleted or updated rows. For each unique primary key value, data is only ** recorded once - the first time a row with said primary key is inserted, ** updated or deleted in the lifetime of the session. ** ** There is one exception to the previous paragraph: when a row is inserted, ** updated or deleted, if one or more of its primary key columns contain a ** NULL value, no record of the change is made. ** ** The session object therefore accumulates two types of records - those ** that consist of primary key values only (created when the user inserts ** a new record) and those that consist of the primary key values and the ** original values of other table columns (created when the users deletes ** or updates a record). ** ** When this function is called, the requested changeset is created using ** both the accumulated records and the current contents of the database ** file. Specifically: ** **
    **
  • For each record generated by an insert, the database is queried ** for a row with a matching primary key. If one is found, an INSERT ** change is added to the changeset. If no such row is found, no change ** is added to the changeset. ** **
  • For each record generated by an update or delete, the database is ** queried for a row with a matching primary key. If such a row is ** found and one or more of the non-primary key fields have been ** modified from their original values, an UPDATE change is added to ** the changeset. Or, if no such row is found in the table, a DELETE ** change is added to the changeset. If there is a row with a matching ** primary key in the database, but all fields contain their original ** values, no change is added to the changeset. **
** ** This means, amongst other things, that if a row is inserted and then later ** deleted while a session object is active, neither the insert nor the delete ** will be present in the changeset. Or if a row is deleted and then later a ** row with the same primary key values inserted while a session object is ** active, the resulting changeset will contain an UPDATE change instead of ** a DELETE and an INSERT. ** ** When a session object is disabled (see the [sqlite3session_enable()] API), ** it does not accumulate records when rows are inserted, updated or deleted. ** This may appear to have some counter-intuitive effects if a single row ** is written to more than once during a session. For example, if a row ** is inserted while a session object is enabled, then later deleted while ** the same session object is disabled, no INSERT record will appear in the ** changeset, even though the delete took place while the session was disabled. ** Or, if one field of a row is updated while a session is disabled, and ** another field of the same row is updated while the session is enabled, the ** resulting changeset will contain an UPDATE change that updates both fields. */ SQLITE_API int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ); /* ** CAPI3REF: Return An Upper-limit For The Size Of The Changeset ** METHOD: sqlite3_session ** ** By default, this function always returns 0. For it to return ** a useful result, the sqlite3_session object must have been configured ** to enable this API using sqlite3session_object_config() with the ** SQLITE_SESSION_OBJCONFIG_SIZE verb. ** ** When enabled, this function returns an upper limit, in bytes, for the size ** of the changeset that might be produced if sqlite3session_changeset() were ** called. The final changeset size might be equal to or smaller than the ** size in bytes returned by this function. */ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession); /* ** CAPI3REF: Load The Difference Between Tables Into A Session ** METHOD: sqlite3_session ** ** If it is not already attached to the session object passed as the first ** argument, this function attaches table zTbl in the same manner as the ** [sqlite3session_attach()] function. If zTbl does not exist, or if it ** does not have a primary key, this function is a no-op (but does not return ** an error). ** ** Argument zFromDb must be the name of a database ("main", "temp" etc.) ** attached to the same database handle as the session object that contains ** a table compatible with the table attached to the session by this function. ** A table is considered compatible if it: ** **
    **
  • Has the same name, **
  • Has the same set of columns declared in the same order, and **
  • Has the same PRIMARY KEY definition. **
** ** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables ** are compatible but do not have any PRIMARY KEY columns, it is not an error ** but no changes are added to the session object. As with other session ** APIs, tables without PRIMARY KEYs are simply ignored. ** ** This function adds a set of changes to the session object that could be ** used to update the table in database zFrom (call this the "from-table") ** so that its content is the same as the table attached to the session ** object (call this the "to-table"). Specifically: ** **
    **
  • For each row (primary key) that exists in the to-table but not in ** the from-table, an INSERT record is added to the session object. ** **
  • For each row (primary key) that exists in the to-table but not in ** the from-table, a DELETE record is added to the session object. ** **
  • For each row (primary key) that exists in both tables, but features ** different non-PK values in each, an UPDATE record is added to the ** session. **
** ** To clarify, if this function is called and then a changeset constructed ** using [sqlite3session_changeset()], then after applying that changeset to ** database zFrom the contents of the two compatible tables would be ** identical. ** ** It an error if database zFrom does not exist or does not contain the ** required compatible table. ** ** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg ** may be set to point to a buffer containing an English language error ** message. It is the responsibility of the caller to free this buffer using ** sqlite3_free(). */ SQLITE_API int sqlite3session_diff( sqlite3_session *pSession, const char *zFromDb, const char *zTbl, char **pzErrMsg ); /* ** CAPI3REF: Generate A Patchset From A Session Object ** METHOD: sqlite3_session ** ** The differences between a patchset and a changeset are that: ** **
    **
  • DELETE records consist of the primary key fields only. The ** original values of other fields are omitted. **
  • The original values of any modified fields are omitted from ** UPDATE records. **
** ** A patchset blob may be used with up to date versions of all ** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), ** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly, ** attempting to use a patchset blob with old versions of the ** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. ** ** Because the non-primary key "old.*" fields are omitted, no ** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset ** is passed to the sqlite3changeset_apply() API. Other conflict types work ** in the same way as for changesets. ** ** Changes within a patchset are ordered in the same way as for changesets ** generated by the sqlite3session_changeset() function (i.e. all changes for ** a single table are grouped together, tables appear in the order in which ** they were attached to the session object). */ SQLITE_API int sqlite3session_patchset( sqlite3_session *pSession, /* Session object */ int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */ void **ppPatchset /* OUT: Buffer containing patchset */ ); /* ** CAPI3REF: Test if a changeset has recorded any changes. ** ** Return non-zero if no changes to attached tables have been recorded by ** the session object passed as the first argument. Otherwise, if one or ** more changes have been recorded, return zero. ** ** Even if this function returns zero, it is possible that calling ** [sqlite3session_changeset()] on the session handle may still return a ** changeset that contains no changes. This can happen when a row in ** an attached table is modified and then later on the original values ** are restored. However, if this function returns non-zero, then it is ** guaranteed that a call to sqlite3session_changeset() will return a ** changeset containing zero changes. */ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); /* ** CAPI3REF: Query for the amount of heap memory used by a session object. ** ** This API returns the total amount of heap memory in bytes currently ** used by the session object passed as the only argument. */ SQLITE_API sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession); /* ** CAPI3REF: Create An Iterator To Traverse A Changeset ** CONSTRUCTOR: sqlite3_changeset_iter ** ** Create an iterator used to iterate through the contents of a changeset. ** If successful, *pp is set to point to the iterator handle and SQLITE_OK ** is returned. Otherwise, if an error occurs, *pp is set to zero and an ** SQLite error code is returned. ** ** The following functions can be used to advance and query a changeset ** iterator created by this function: ** **
    **
  • [sqlite3changeset_next()] **
  • [sqlite3changeset_op()] **
  • [sqlite3changeset_new()] **
  • [sqlite3changeset_old()] **
** ** It is the responsibility of the caller to eventually destroy the iterator ** by passing it to [sqlite3changeset_finalize()]. The buffer containing the ** changeset (pChangeset) must remain valid until after the iterator is ** destroyed. ** ** Assuming the changeset blob was created by one of the ** [sqlite3session_changeset()], [sqlite3changeset_concat()] or ** [sqlite3changeset_invert()] functions, all changes within the changeset ** that apply to a single table are grouped together. This means that when ** an application iterates through a changeset using an iterator created by ** this function, all changes that relate to a single table are visited ** consecutively. There is no chance that the iterator will visit a change ** the applies to table X, then one for table Y, and then later on visit ** another change for table X. ** ** The behavior of sqlite3changeset_start_v2() and its streaming equivalent ** may be modified by passing a combination of ** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. ** ** Note that the sqlite3changeset_start_v2() API is still experimental ** and therefore subject to change. */ SQLITE_API int sqlite3changeset_start( sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); SQLITE_API int sqlite3changeset_start_v2( sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset, /* Pointer to blob containing changeset */ int flags /* SESSION_CHANGESETSTART_* flags */ ); /* ** CAPI3REF: Flags for sqlite3changeset_start_v2 ** ** The following flags may passed via the 4th parameter to ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: ** **
SQLITE_CHANGESETAPPLY_INVERT
** Invert the changeset while iterating through it. This is equivalent to ** inverting a changeset using sqlite3changeset_invert() before applying it. ** It is an error to specify this flag with a patchset. */ #define SQLITE_CHANGESETSTART_INVERT 0x0002 /* ** CAPI3REF: Advance A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** This function may only be used with iterators created by the function ** [sqlite3changeset_start()]. If it is called on an iterator passed to ** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE ** is returned and the call has no effect. ** ** Immediately after an iterator is created by sqlite3changeset_start(), it ** does not point to any change in the changeset. Assuming the changeset ** is not empty, the first call to this function advances the iterator to ** point to the first change in the changeset. Each subsequent call advances ** the iterator to point to the next change in the changeset (if any). If ** no error occurs and the iterator points to a valid change after a call ** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. ** Otherwise, if all changes in the changeset have already been visited, ** SQLITE_DONE is returned. ** ** If an error occurs, an SQLite error code is returned. Possible error ** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or ** SQLITE_NOMEM. */ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); /* ** CAPI3REF: Obtain The Current Operation From A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this ** is not the case, this function returns [SQLITE_MISUSE]. ** ** Arguments pOp, pnCol and pzTab may not be NULL. Upon return, three ** outputs are set through these pointers: ** ** *pOp is set to one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], ** depending on the type of change that the iterator currently points to; ** ** *pnCol is set to the number of columns in the table affected by the change; and ** ** *pzTab is set to point to a nul-terminated utf-8 encoded string containing ** the name of the table affected by the current change. The buffer remains ** valid until either sqlite3changeset_next() is called on the iterator ** or until the conflict-handler function returns. ** ** If pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change ** is an indirect change, or false (0) otherwise. See the documentation for ** [sqlite3session_indirect()] for a description of direct and indirect ** changes. ** ** If no error occurs, SQLITE_OK is returned. If an error does occur, an ** SQLite error code is returned. The values of the output variables may not ** be trusted in this case. */ SQLITE_API int sqlite3changeset_op( sqlite3_changeset_iter *pIter, /* Iterator object */ const char **pzTab, /* OUT: Pointer to table name */ int *pnCol, /* OUT: Number of columns in table */ int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ int *pbIndirect /* OUT: True for an 'indirect' change */ ); /* ** CAPI3REF: Obtain The Primary Key Definition Of A Table ** METHOD: sqlite3_changeset_iter ** ** For each modified table, a changeset includes the following: ** **
    **
  • The number of columns in the table, and **
  • Which of those columns make up the tables PRIMARY KEY. **
** ** This function is used to find which columns comprise the PRIMARY KEY of ** the table modified by the change that iterator pIter currently points to. ** If successful, *pabPK is set to point to an array of nCol entries, where ** nCol is the number of columns in the table. Elements of *pabPK are set to ** 0x01 if the corresponding column is part of the tables primary key, or ** 0x00 if it is not. ** ** If argument pnCol is not NULL, then *pnCol is set to the number of columns ** in the table. ** ** If this function is called when the iterator does not point to a valid ** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise, ** SQLITE_OK is returned and the output variables populated as described ** above. */ SQLITE_API int sqlite3changeset_pk( sqlite3_changeset_iter *pIter, /* Iterator object */ unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ int *pnCol /* OUT: Number of entries in output array */ ); /* ** CAPI3REF: Obtain old.* Values From A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. ** Furthermore, it may only be called if the type of change that the iterator ** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, ** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. ** ** Argument iVal must be greater than or equal to 0, and less than the number ** of columns in the table affected by the current change. Otherwise, ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. ** ** If successful, this function sets *ppValue to point to a protected ** sqlite3_value object containing the iVal'th value from the vector of ** original row values stored as part of the UPDATE or DELETE change and ** returns SQLITE_OK. The name of the function comes from the fact that this ** is similar to the "old.*" columns available to update or delete triggers. ** ** If some other error occurs (e.g. an OOM condition), an SQLite error code ** is returned and *ppValue is set to NULL. */ SQLITE_API int sqlite3changeset_old( sqlite3_changeset_iter *pIter, /* Changeset iterator */ int iVal, /* Column number */ sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ ); /* ** CAPI3REF: Obtain new.* Values From A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. ** Furthermore, it may only be called if the type of change that the iterator ** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, ** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. ** ** Argument iVal must be greater than or equal to 0, and less than the number ** of columns in the table affected by the current change. Otherwise, ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. ** ** If successful, this function sets *ppValue to point to a protected ** sqlite3_value object containing the iVal'th value from the vector of ** new row values stored as part of the UPDATE or INSERT change and ** returns SQLITE_OK. If the change is an UPDATE and does not include ** a new value for the requested column, *ppValue is set to NULL and ** SQLITE_OK returned. The name of the function comes from the fact that ** this is similar to the "new.*" columns available to update or delete ** triggers. ** ** If some other error occurs (e.g. an OOM condition), an SQLite error code ** is returned and *ppValue is set to NULL. */ SQLITE_API int sqlite3changeset_new( sqlite3_changeset_iter *pIter, /* Changeset iterator */ int iVal, /* Column number */ sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ ); /* ** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** This function should only be used with iterator objects passed to a ** conflict-handler callback by [sqlite3changeset_apply()] with either ** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function ** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue ** is set to NULL. ** ** Argument iVal must be greater than or equal to 0, and less than the number ** of columns in the table affected by the current change. Otherwise, ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. ** ** If successful, this function sets *ppValue to point to a protected ** sqlite3_value object containing the iVal'th value from the ** "conflicting row" associated with the current conflict-handler callback ** and returns SQLITE_OK. ** ** If some other error occurs (e.g. an OOM condition), an SQLite error code ** is returned and *ppValue is set to NULL. */ SQLITE_API int sqlite3changeset_conflict( sqlite3_changeset_iter *pIter, /* Changeset iterator */ int iVal, /* Column number */ sqlite3_value **ppValue /* OUT: Value from conflicting row */ ); /* ** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations ** METHOD: sqlite3_changeset_iter ** ** This function may only be called with an iterator passed to an ** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case ** it sets the output variable to the total number of known foreign key ** violations in the destination database and returns SQLITE_OK. ** ** In all other cases this function returns SQLITE_MISUSE. */ SQLITE_API int sqlite3changeset_fk_conflicts( sqlite3_changeset_iter *pIter, /* Changeset iterator */ int *pnOut /* OUT: Number of FK violations */ ); /* ** CAPI3REF: Finalize A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** This function is used to finalize an iterator allocated with ** [sqlite3changeset_start()]. ** ** This function should only be called on iterators created using the ** [sqlite3changeset_start()] function. If an application calls this ** function with an iterator passed to a conflict-handler by ** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the ** call has no effect. ** ** If an error was encountered within a call to an sqlite3changeset_xxx() ** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an ** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding ** to that error is returned by this function. Otherwise, SQLITE_OK is ** returned. This is to allow the following pattern (pseudo-code): ** **
**   sqlite3changeset_start();
**   while( SQLITE_ROW==sqlite3changeset_next() ){
**     // Do something with change.
**   }
**   rc = sqlite3changeset_finalize();
**   if( rc!=SQLITE_OK ){
**     // An error has occurred
**   }
** 
*/ SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); /* ** CAPI3REF: Invert A Changeset ** ** This function is used to "invert" a changeset object. Applying an inverted ** changeset to a database reverses the effects of applying the uninverted ** changeset. Specifically: ** **
    **
  • Each DELETE change is changed to an INSERT, and **
  • Each INSERT change is changed to a DELETE, and **
  • For each UPDATE change, the old.* and new.* values are exchanged. **
** ** This function does not change the order in which changes appear within ** the changeset. It merely reverses the sense of each individual change. ** ** If successful, a pointer to a buffer containing the inverted changeset ** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and ** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are ** zeroed and an SQLite error code returned. ** ** It is the responsibility of the caller to eventually call sqlite3_free() ** on the *ppOut pointer to free the buffer allocation following a successful ** call to this function. ** ** WARNING/TODO: This function currently assumes that the input is a valid ** changeset. If it is not, the results are undefined. */ SQLITE_API int sqlite3changeset_invert( int nIn, const void *pIn, /* Input changeset */ int *pnOut, void **ppOut /* OUT: Inverse of input */ ); /* ** CAPI3REF: Concatenate Two Changeset Objects ** ** This function is used to concatenate two changesets, A and B, into a ** single changeset. The result is a changeset equivalent to applying ** changeset A followed by changeset B. ** ** This function combines the two input changesets using an ** sqlite3_changegroup object. Calling it produces similar results as the ** following code fragment: ** **
**   sqlite3_changegroup *pGrp;
**   rc = sqlite3_changegroup_new(&pGrp);
**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
**   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
**   if( rc==SQLITE_OK ){
**     rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
**   }else{
**     *ppOut = 0;
**     *pnOut = 0;
**   }
** 
** ** Refer to the sqlite3_changegroup documentation below for details. */ SQLITE_API int sqlite3changeset_concat( int nA, /* Number of bytes in buffer pA */ void *pA, /* Pointer to buffer containing changeset A */ int nB, /* Number of bytes in buffer pB */ void *pB, /* Pointer to buffer containing changeset B */ int *pnOut, /* OUT: Number of bytes in output changeset */ void **ppOut /* OUT: Buffer containing output changeset */ ); /* ** CAPI3REF: Upgrade the Schema of a Changeset/Patchset */ SQLITE_API int sqlite3changeset_upgrade( sqlite3 *db, const char *zDb, int nIn, const void *pIn, /* Input changeset */ int *pnOut, void **ppOut /* OUT: Inverse of input */ ); /* ** CAPI3REF: Changegroup Handle ** ** A changegroup is an object used to combine two or more ** [changesets] or [patchsets] */ typedef struct sqlite3_changegroup sqlite3_changegroup; /* ** CAPI3REF: Create A New Changegroup Object ** CONSTRUCTOR: sqlite3_changegroup ** ** An sqlite3_changegroup object is used to combine two or more changesets ** (or patchsets) into a single changeset (or patchset). A single changegroup ** object may combine changesets or patchsets, but not both. The output is ** always in the same format as the input. ** ** If successful, this function returns SQLITE_OK and populates (*pp) with ** a pointer to a new sqlite3_changegroup object before returning. The caller ** should eventually free the returned object using a call to ** sqlite3changegroup_delete(). If an error occurs, an SQLite error code ** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL. ** ** The usual usage pattern for an sqlite3_changegroup object is as follows: ** **
    **
  • It is created using a call to sqlite3changegroup_new(). ** **
  • Zero or more changesets (or patchsets) are added to the object ** by calling sqlite3changegroup_add(). ** **
  • The result of combining all input changesets together is obtained ** by the application via a call to sqlite3changegroup_output(). ** **
  • The object is deleted using a call to sqlite3changegroup_delete(). **
** ** Any number of calls to add() and output() may be made between the calls to ** new() and delete(), and in any order. ** ** As well as the regular sqlite3changegroup_add() and ** sqlite3changegroup_output() functions, also available are the streaming ** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). */ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); /* ** CAPI3REF: Add a Schema to a Changegroup ** METHOD: sqlite3_changegroup_schema ** ** This method may be used to optionally enforce the rule that the changesets ** added to the changegroup handle must match the schema of database zDb ** ("main", "temp", or the name of an attached database). If ** sqlite3changegroup_add() is called to add a changeset that is not compatible ** with the configured schema, SQLITE_SCHEMA is returned and the changegroup ** object is left in an undefined state. ** ** A changeset schema is considered compatible with the database schema in ** the same way as for sqlite3changeset_apply(). Specifically, for each ** table in the changeset, there exists a database table with: ** **
    **
  • The name identified by the changeset, and **
  • at least as many columns as recorded in the changeset, and **
  • the primary key columns in the same position as recorded in ** the changeset. **
** ** The output of the changegroup object always has the same schema as the ** database nominated using this function. In cases where changesets passed ** to sqlite3changegroup_add() have fewer columns than the corresponding table ** in the database schema, these are filled in using the default column ** values from the database schema. This makes it possible to combined ** changesets that have different numbers of columns for a single table ** within a changegroup, provided that they are otherwise compatible. */ SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb); /* ** CAPI3REF: Add A Changeset To A Changegroup ** METHOD: sqlite3_changegroup ** ** Add all changes within the changeset (or patchset) in buffer pData (size ** nData bytes) to the changegroup. ** ** If the buffer contains a patchset, then all prior calls to this function ** on the same changegroup object must also have specified patchsets. Or, if ** the buffer contains a changeset, so must have the earlier calls to this ** function. Otherwise, SQLITE_ERROR is returned and no changes are added ** to the changegroup. ** ** Rows within the changeset and changegroup are identified by the values in ** their PRIMARY KEY columns. A change in the changeset is considered to ** apply to the same row as a change already present in the changegroup if ** the two rows have the same primary key. ** ** Changes to rows that do not already appear in the changegroup are ** simply copied into it. Or, if both the new changeset and the changegroup ** contain changes that apply to a single row, the final contents of the ** changegroup depends on the type of each change, as follows: ** ** ** ** **
Existing Change New Change Output Change **
INSERT INSERT ** The new change is ignored. This case does not occur if the new ** changeset was recorded immediately after the changesets already ** added to the changegroup. **
INSERT UPDATE ** The INSERT change remains in the changegroup. The values in the ** INSERT change are modified as if the row was inserted by the ** existing change and then updated according to the new change. **
INSERT DELETE ** The existing INSERT is removed from the changegroup. The DELETE is ** not added. **
UPDATE INSERT ** The new change is ignored. This case does not occur if the new ** changeset was recorded immediately after the changesets already ** added to the changegroup. **
UPDATE UPDATE ** The existing UPDATE remains within the changegroup. It is amended ** so that the accompanying values are as if the row was updated once ** by the existing change and then again by the new change. **
UPDATE DELETE ** The existing UPDATE is replaced by the new DELETE within the ** changegroup. **
DELETE INSERT ** If one or more of the column values in the row inserted by the ** new change differ from those in the row deleted by the existing ** change, the existing DELETE is replaced by an UPDATE within the ** changegroup. Otherwise, if the inserted row is exactly the same ** as the deleted row, the existing DELETE is simply discarded. **
DELETE UPDATE ** The new change is ignored. This case does not occur if the new ** changeset was recorded immediately after the changesets already ** added to the changegroup. **
DELETE DELETE ** The new change is ignored. This case does not occur if the new ** changeset was recorded immediately after the changesets already ** added to the changegroup. **
** ** If the new changeset contains changes to a table that is already present ** in the changegroup, then the number of columns and the position of the ** primary key columns for the table must be consistent. If this is not the ** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup ** object has been configured with a database schema using the ** sqlite3changegroup_schema() API, then it is possible to combine changesets ** with different numbers of columns for a single table, provided that ** they are otherwise compatible. ** ** If the input changeset appears to be corrupt and the corruption is ** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition ** occurs during processing, this function returns SQLITE_NOMEM. ** ** In all cases, if an error occurs the state of the final contents of the ** changegroup is undefined. If no error occurs, SQLITE_OK is returned. */ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); /* ** CAPI3REF: Obtain A Composite Changeset From A Changegroup ** METHOD: sqlite3_changegroup ** ** Obtain a buffer containing a changeset (or patchset) representing the ** current contents of the changegroup. If the inputs to the changegroup ** were themselves changesets, the output is a changeset. Or, if the ** inputs were patchsets, the output is also a patchset. ** ** As with the output of the sqlite3session_changeset() and ** sqlite3session_patchset() functions, all changes related to a single ** table are grouped together in the output of this function. Tables appear ** in the same order as for the very first changeset added to the changegroup. ** If the second or subsequent changesets added to the changegroup contain ** changes for tables that do not appear in the first changeset, they are ** appended onto the end of the output changeset, again in the order in ** which they are first encountered. ** ** If an error occurs, an SQLite error code is returned and the output ** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK ** is returned and the output variables are set to the size of and a ** pointer to the output buffer, respectively. In this case it is the ** responsibility of the caller to eventually free the buffer using a ** call to sqlite3_free(). */ SQLITE_API int sqlite3changegroup_output( sqlite3_changegroup*, int *pnData, /* OUT: Size of output buffer in bytes */ void **ppData /* OUT: Pointer to output buffer */ ); /* ** CAPI3REF: Delete A Changegroup Object ** DESTRUCTOR: sqlite3_changegroup */ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); /* ** CAPI3REF: Apply A Changeset To A Database ** ** Apply a changeset or patchset to a database. These functions attempt to ** update the "main" database attached to handle db with the changes found in ** the changeset passed via the second and third arguments. ** ** The fourth argument (xFilter) passed to these functions is the "filter ** callback". If it is not NULL, then for each table affected by at least one ** change in the changeset, the filter callback is invoked with ** the table name as the second argument, and a copy of the context pointer ** passed as the sixth argument as the first. If the "filter callback" ** returns zero, then no attempt is made to apply any changes to the table. ** Otherwise, if the return value is non-zero or the xFilter argument to ** is NULL, all changes related to the table are attempted. ** ** For each table that is not excluded by the filter callback, this function ** tests that the target database contains a compatible table. A table is ** considered compatible if all of the following are true: ** **
    **
  • The table has the same name as the name recorded in the ** changeset, and **
  • The table has at least as many columns as recorded in the ** changeset, and **
  • The table has primary key columns in the same position as ** recorded in the changeset. **
** ** If there is no compatible table, it is not an error, but none of the ** changes associated with the table are applied. A warning message is issued ** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most ** one such warning is issued for each table in the changeset. ** ** For each change for which there is a compatible table, an attempt is made ** to modify the table contents according to the UPDATE, INSERT or DELETE ** change. If a change cannot be applied cleanly, the conflict handler ** function passed as the fifth argument to sqlite3changeset_apply() may be ** invoked. A description of exactly when the conflict handler is invoked for ** each type of change is below. ** ** Unlike the xFilter argument, xConflict may not be passed NULL. The results ** of passing anything other than a valid function pointer as the xConflict ** argument are undefined. ** ** Each time the conflict handler function is invoked, it must return one ** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or ** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned ** if the second argument passed to the conflict handler is either ** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler ** returns an illegal value, any changes already made are rolled back and ** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different ** actions are taken by sqlite3changeset_apply() depending on the value ** returned by each invocation of the conflict-handler function. Refer to ** the documentation for the three ** [SQLITE_CHANGESET_OMIT|available return values] for details. ** **
**
DELETE Changes
** For each DELETE change, the function checks if the target database ** contains a row with the same primary key value (or values) as the ** original row values stored in the changeset. If it does, and the values ** stored in all non-primary key columns also match the values stored in ** the changeset the row is deleted from the target database. ** ** If a row with matching primary key values is found, but one or more of ** the non-primary key fields contains a value different from the original ** row value stored in the changeset, the conflict-handler function is ** invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the ** database table has more columns than are recorded in the changeset, ** only the values of those non-primary key fields are compared against ** the current database contents - any trailing database table columns ** are ignored. ** ** If no row with matching primary key values is found in the database, ** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] ** passed as the second argument. ** ** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT ** (which can only happen if a foreign key constraint is violated), the ** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT] ** passed as the second argument. This includes the case where the DELETE ** operation is attempted because an earlier call to the conflict handler ** function returned [SQLITE_CHANGESET_REPLACE]. ** **
INSERT Changes
** For each INSERT change, an attempt is made to insert the new row into ** the database. If the changeset row contains fewer fields than the ** database table, the trailing fields are populated with their default ** values. ** ** If the attempt to insert the row fails because the database already ** contains a row with the same primary key values, the conflict handler ** function is invoked with the second argument set to ** [SQLITE_CHANGESET_CONFLICT]. ** ** If the attempt to insert the row fails because of some other constraint ** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is ** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT]. ** This includes the case where the INSERT operation is re-attempted because ** an earlier call to the conflict handler function returned ** [SQLITE_CHANGESET_REPLACE]. ** **
UPDATE Changes
** For each UPDATE change, the function checks if the target database ** contains a row with the same primary key value (or values) as the ** original row values stored in the changeset. If it does, and the values ** stored in all modified non-primary key columns also match the values ** stored in the changeset the row is updated within the target database. ** ** If a row with matching primary key values is found, but one or more of ** the modified non-primary key fields contains a value different from an ** original row value stored in the changeset, the conflict-handler function ** is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since ** UPDATE changes only contain values for non-primary key fields that are ** to be modified, only those fields need to match the original values to ** avoid the SQLITE_CHANGESET_DATA conflict-handler callback. ** ** If no row with matching primary key values is found in the database, ** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] ** passed as the second argument. ** ** If the UPDATE operation is attempted, but SQLite returns ** SQLITE_CONSTRAINT, the conflict-handler function is invoked with ** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument. ** This includes the case where the UPDATE operation is attempted after ** an earlier call to the conflict handler function returned ** [SQLITE_CHANGESET_REPLACE]. **
** ** It is safe to execute SQL statements, including those that write to the ** table that the callback related to, from within the xConflict callback. ** This can be used to further customize the application's conflict ** resolution strategy. ** ** All changes made by these functions are enclosed in a savepoint transaction. ** If any other error (aside from a constraint failure when attempting to ** write to the target database) occurs, then the savepoint transaction is ** rolled back, restoring the target database to its original state, and an ** SQLite error code returned. ** ** If the output parameters (ppRebase) and (pnRebase) are non-NULL and ** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2() ** may set (*ppRebase) to point to a "rebase" that may be used with the ** sqlite3_rebaser APIs buffer before returning. In this case (*pnRebase) ** is set to the size of the buffer in bytes. It is the responsibility of the ** caller to eventually free any such buffer using sqlite3_free(). The buffer ** is only allocated and populated if one or more conflicts were encountered ** while applying the patchset. See comments surrounding the sqlite3_rebaser ** APIs for further details. ** ** The behavior of sqlite3changeset_apply_v2() and its streaming equivalent ** may be modified by passing a combination of ** [SQLITE_CHANGESETAPPLY_NOSAVEPOINT | supported flags] as the 9th parameter. ** ** Note that the sqlite3changeset_apply_v2() API is still experimental ** and therefore subject to change. */ SQLITE_API int sqlite3changeset_apply( sqlite3 *db, /* Apply change to "main" db of this handle */ int nChangeset, /* Size of changeset in bytes */ void *pChangeset, /* Changeset blob */ int(*xFilter)( void *pCtx, /* Copy of sixth arg to _apply() */ const char *zTab /* Table name */ ), int(*xConflict)( void *pCtx, /* Copy of sixth arg to _apply() */ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ sqlite3_changeset_iter *p /* Handle describing change and conflict */ ), void *pCtx /* First argument passed to xConflict */ ); SQLITE_API int sqlite3changeset_apply_v2( sqlite3 *db, /* Apply change to "main" db of this handle */ int nChangeset, /* Size of changeset in bytes */ void *pChangeset, /* Changeset blob */ int(*xFilter)( void *pCtx, /* Copy of sixth arg to _apply() */ const char *zTab /* Table name */ ), int(*xConflict)( void *pCtx, /* Copy of sixth arg to _apply() */ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ sqlite3_changeset_iter *p /* Handle describing change and conflict */ ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, /* OUT: Rebase data */ int flags /* SESSION_CHANGESETAPPLY_* flags */ ); /* ** CAPI3REF: Flags for sqlite3changeset_apply_v2 ** ** The following flags may passed via the 9th parameter to ** [sqlite3changeset_apply_v2] and [sqlite3changeset_apply_v2_strm]: ** **
**
SQLITE_CHANGESETAPPLY_NOSAVEPOINT
** Usually, the sessions module encloses all operations performed by ** a single call to apply_v2() or apply_v2_strm() in a [SAVEPOINT]. The ** SAVEPOINT is committed if the changeset or patchset is successfully ** applied, or rolled back if an error occurs. Specifying this flag ** causes the sessions module to omit this savepoint. In this case, if the ** caller has an open transaction or savepoint when apply_v2() is called, ** it may revert the partially applied changeset by rolling it back. ** **
SQLITE_CHANGESETAPPLY_INVERT
** Invert the changeset before applying it. This is equivalent to inverting ** a changeset using sqlite3changeset_invert() before applying it. It is ** an error to specify this flag with a patchset. ** **
SQLITE_CHANGESETAPPLY_IGNORENOOP
** Do not invoke the conflict handler callback for any changes that ** would not actually modify the database even if they were applied. ** Specifically, this means that the conflict handler is not invoked ** for: **
    **
  • a delete change if the row being deleted cannot be found, **
  • an update change if the modified fields are already set to ** their new values in the conflicting row, or **
  • an insert change if all fields of the conflicting row match ** the row being inserted. **
** **
SQLITE_CHANGESETAPPLY_FKNOACTION
** If this flag it set, then all foreign key constraints in the target ** database behave as if they were declared with "ON UPDATE NO ACTION ON ** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL ** or SET DEFAULT. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 #define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 #define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008 /* ** CAPI3REF: Constants Passed To The Conflict Handler ** ** Values that may be passed as the second argument to a conflict-handler. ** **
**
SQLITE_CHANGESET_DATA
** The conflict handler is invoked with CHANGESET_DATA as the second argument ** when processing a DELETE or UPDATE change if a row with the required ** PRIMARY KEY fields is present in the database, but one or more other ** (non primary-key) fields modified by the update do not contain the ** expected "before" values. ** ** The conflicting row, in this case, is the database row with the matching ** primary key. ** **
SQLITE_CHANGESET_NOTFOUND
** The conflict handler is invoked with CHANGESET_NOTFOUND as the second ** argument when processing a DELETE or UPDATE change if a row with the ** required PRIMARY KEY fields is not present in the database. ** ** There is no conflicting row in this case. The results of invoking the ** sqlite3changeset_conflict() API are undefined. ** **
SQLITE_CHANGESET_CONFLICT
** CHANGESET_CONFLICT is passed as the second argument to the conflict ** handler while processing an INSERT change if the operation would result ** in duplicate primary key values. ** ** The conflicting row in this case is the database row with the matching ** primary key. ** **
SQLITE_CHANGESET_FOREIGN_KEY
** If foreign key handling is enabled, and applying a changeset leaves the ** database in a state containing foreign key violations, the conflict ** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument ** exactly once before the changeset is committed. If the conflict handler ** returns CHANGESET_OMIT, the changes, including those that caused the ** foreign key constraint violation, are committed. Or, if it returns ** CHANGESET_ABORT, the changeset is rolled back. ** ** No current or conflicting row information is provided. The only function ** it is possible to call on the supplied sqlite3_changeset_iter handle ** is sqlite3changeset_fk_conflicts(). ** **
SQLITE_CHANGESET_CONSTRAINT
** If any other constraint violation occurs while applying a change (i.e. ** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is ** invoked with CHANGESET_CONSTRAINT as the second argument. ** ** There is no conflicting row in this case. The results of invoking the ** sqlite3changeset_conflict() API are undefined. ** **
*/ #define SQLITE_CHANGESET_DATA 1 #define SQLITE_CHANGESET_NOTFOUND 2 #define SQLITE_CHANGESET_CONFLICT 3 #define SQLITE_CHANGESET_CONSTRAINT 4 #define SQLITE_CHANGESET_FOREIGN_KEY 5 /* ** CAPI3REF: Constants Returned By The Conflict Handler ** ** A conflict handler callback must return one of the following three values. ** **
**
SQLITE_CHANGESET_OMIT
** If a conflict handler returns this value no special action is taken. The ** change that caused the conflict is not applied. The session module ** continues to the next change in the changeset. ** **
SQLITE_CHANGESET_REPLACE
** This value may only be returned if the second argument to the conflict ** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this ** is not the case, any changes applied so far are rolled back and the ** call to sqlite3changeset_apply() returns SQLITE_MISUSE. ** ** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict ** handler, then the conflicting row is either updated or deleted, depending ** on the type of change. ** ** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict ** handler, then the conflicting row is removed from the database and a ** second attempt to apply the change is made. If this second attempt fails, ** the original row is restored to the database before continuing. ** **
SQLITE_CHANGESET_ABORT
** If this value is returned, any changes applied so far are rolled back ** and the call to sqlite3changeset_apply() returns SQLITE_ABORT. **
*/ #define SQLITE_CHANGESET_OMIT 0 #define SQLITE_CHANGESET_REPLACE 1 #define SQLITE_CHANGESET_ABORT 2 /* ** CAPI3REF: Rebasing changesets ** EXPERIMENTAL ** ** Suppose there is a site hosting a database in state S0. And that ** modifications are made that move that database to state S1 and a ** changeset recorded (the "local" changeset). Then, a changeset based ** on S0 is received from another site (the "remote" changeset) and ** applied to the database. The database is then in state ** (S1+"remote"), where the exact state depends on any conflict ** resolution decisions (OMIT or REPLACE) made while applying "remote". ** Rebasing a changeset is to update it to take those conflict ** resolution decisions into account, so that the same conflicts ** do not have to be resolved elsewhere in the network. ** ** For example, if both the local and remote changesets contain an ** INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)": ** ** local: INSERT INTO t1 VALUES(1, 'v1'); ** remote: INSERT INTO t1 VALUES(1, 'v2'); ** ** and the conflict resolution is REPLACE, then the INSERT change is ** removed from the local changeset (it was overridden). Or, if the ** conflict resolution was "OMIT", then the local changeset is modified ** to instead contain: ** ** UPDATE t1 SET b = 'v2' WHERE a=1; ** ** Changes within the local changeset are rebased as follows: ** **
**
Local INSERT
** This may only conflict with a remote INSERT. If the conflict ** resolution was OMIT, then add an UPDATE change to the rebased ** changeset. Or, if the conflict resolution was REPLACE, add ** nothing to the rebased changeset. ** **
Local DELETE
** This may conflict with a remote UPDATE or DELETE. In both cases the ** only possible resolution is OMIT. If the remote operation was a ** DELETE, then add no change to the rebased changeset. If the remote ** operation was an UPDATE, then the old.* fields of change are updated ** to reflect the new.* values in the UPDATE. ** **
Local UPDATE
** This may conflict with a remote UPDATE or DELETE. If it conflicts ** with a DELETE, and the conflict resolution was OMIT, then the update ** is changed into an INSERT. Any undefined values in the new.* record ** from the update change are filled in using the old.* values from ** the conflicting DELETE. Or, if the conflict resolution was REPLACE, ** the UPDATE change is simply omitted from the rebased changeset. ** ** If conflict is with a remote UPDATE and the resolution is OMIT, then ** the old.* values are rebased using the new.* values in the remote ** change. Or, if the resolution is REPLACE, then the change is copied ** into the rebased changeset with updates to columns also updated by ** the conflicting remote UPDATE removed. If this means no columns would ** be updated, the change is omitted. **
** ** A local change may be rebased against multiple remote changes ** simultaneously. If a single key is modified by multiple remote ** changesets, they are combined as follows before the local changeset ** is rebased: ** **
    **
  • If there has been one or more REPLACE resolutions on a ** key, it is rebased according to a REPLACE. ** **
  • If there have been no REPLACE resolutions on a key, then ** the local changeset is rebased according to the most recent ** of the OMIT resolutions. **
** ** Note that conflict resolutions from multiple remote changesets are ** combined on a per-field basis, not per-row. This means that in the ** case of multiple remote UPDATE operations, some fields of a single ** local change may be rebased for REPLACE while others are rebased for ** OMIT. ** ** In order to rebase a local changeset, the remote changeset must first ** be applied to the local database using sqlite3changeset_apply_v2() and ** the buffer of rebase information captured. Then: ** **
    **
  1. An sqlite3_rebaser object is created by calling ** sqlite3rebaser_create(). **
  2. The new object is configured with the rebase buffer obtained from ** sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure(). ** If the local changeset is to be rebased against multiple remote ** changesets, then sqlite3rebaser_configure() should be called ** multiple times, in the same order that the multiple ** sqlite3changeset_apply_v2() calls were made. **
  3. Each local changeset is rebased by calling sqlite3rebaser_rebase(). **
  4. The sqlite3_rebaser object is deleted by calling ** sqlite3rebaser_delete(). **
*/ typedef struct sqlite3_rebaser sqlite3_rebaser; /* ** CAPI3REF: Create a changeset rebaser object. ** EXPERIMENTAL ** ** Allocate a new changeset rebaser object. If successful, set (*ppNew) to ** point to the new object and return SQLITE_OK. Otherwise, if an error ** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew) ** to NULL. */ SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew); /* ** CAPI3REF: Configure a changeset rebaser object. ** EXPERIMENTAL ** ** Configure the changeset rebaser object to rebase changesets according ** to the conflict resolutions described by buffer pRebase (size nRebase ** bytes), which must have been obtained from a previous call to ** sqlite3changeset_apply_v2(). */ SQLITE_API int sqlite3rebaser_configure( sqlite3_rebaser*, int nRebase, const void *pRebase ); /* ** CAPI3REF: Rebase a changeset ** EXPERIMENTAL ** ** Argument pIn must point to a buffer containing a changeset nIn bytes ** in size. This function allocates and populates a buffer with a copy ** of the changeset rebased according to the configuration of the ** rebaser object passed as the first argument. If successful, (*ppOut) ** is set to point to the new buffer containing the rebased changeset and ** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the ** responsibility of the caller to eventually free the new buffer using ** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut) ** are set to zero and an SQLite error code returned. */ SQLITE_API int sqlite3rebaser_rebase( sqlite3_rebaser*, int nIn, const void *pIn, int *pnOut, void **ppOut ); /* ** CAPI3REF: Delete a changeset rebaser object. ** EXPERIMENTAL ** ** Delete the changeset rebaser object and all associated resources. There ** should be one call to this function for each successful invocation ** of sqlite3rebaser_create(). */ SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p); /* ** CAPI3REF: Streaming Versions of API functions. ** ** The six streaming API xxx_strm() functions serve similar purposes to the ** corresponding non-streaming API functions: ** ** ** **
Streaming functionNon-streaming equivalent
sqlite3changeset_apply_strm[sqlite3changeset_apply] **
sqlite3changeset_apply_strm_v2[sqlite3changeset_apply_v2] **
sqlite3changeset_concat_strm[sqlite3changeset_concat] **
sqlite3changeset_invert_strm[sqlite3changeset_invert] **
sqlite3changeset_start_strm[sqlite3changeset_start] **
sqlite3session_changeset_strm[sqlite3session_changeset] **
sqlite3session_patchset_strm[sqlite3session_patchset] **
** ** Non-streaming functions that accept changesets (or patchsets) as input ** require that the entire changeset be stored in a single buffer in memory. ** Similarly, those that return a changeset or patchset do so by returning ** a pointer to a single large buffer allocated using sqlite3_malloc(). ** Normally this is convenient. However, if an application running in a ** low-memory environment is required to handle very large changesets, the ** large contiguous memory allocations required can become onerous. ** ** In order to avoid this problem, instead of a single large buffer, input ** is passed to a streaming API functions by way of a callback function that ** the sessions module invokes to incrementally request input data as it is ** required. In all cases, a pair of API function parameters such as ** **
**        int nChangeset,
**        void *pChangeset,
**  
** ** Is replaced by: ** **
**        int (*xInput)(void *pIn, void *pData, int *pnData),
**        void *pIn,
**  
** ** Each time the xInput callback is invoked by the sessions module, the first ** argument passed is a copy of the supplied pIn context pointer. The second ** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no ** error occurs the xInput method should copy up to (*pnData) bytes of data ** into the buffer and set (*pnData) to the actual number of bytes copied ** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) ** should be set to zero to indicate this. Or, if an error occurs, an SQLite ** error code should be returned. In all cases, if an xInput callback returns ** an error, all processing is abandoned and the streaming API function ** returns a copy of the error code to the caller. ** ** In the case of sqlite3changeset_start_strm(), the xInput callback may be ** invoked by the sessions module at any point during the lifetime of the ** iterator. If such an xInput callback returns an error, the iterator enters ** an error state, whereby all subsequent calls to iterator functions ** immediately fail with the same error code as returned by xInput. ** ** Similarly, streaming API functions that return changesets (or patchsets) ** return them in chunks by way of a callback function instead of via a ** pointer to a single large buffer. In this case, a pair of parameters such ** as: ** **
**        int *pnChangeset,
**        void **ppChangeset,
**  
** ** Is replaced by: ** **
**        int (*xOutput)(void *pOut, const void *pData, int nData),
**        void *pOut
**  
** ** The xOutput callback is invoked zero or more times to return data to ** the application. The first parameter passed to each call is a copy of the ** pOut pointer supplied by the application. The second parameter, pData, ** points to a buffer nData bytes in size containing the chunk of output ** data being returned. If the xOutput callback successfully processes the ** supplied data, it should return SQLITE_OK to indicate success. Otherwise, ** it should return some other SQLite error code. In this case processing ** is immediately abandoned and the streaming API function returns a copy ** of the xOutput error code to the application. ** ** The sessions module never invokes an xOutput callback with the third ** parameter set to a value less than or equal to zero. Other than this, ** no guarantees are made as to the size of the chunks of data returned. */ SQLITE_API int sqlite3changeset_apply_strm( sqlite3 *db, /* Apply change to "main" db of this handle */ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ void *pIn, /* First arg for xInput */ int(*xFilter)( void *pCtx, /* Copy of sixth arg to _apply() */ const char *zTab /* Table name */ ), int(*xConflict)( void *pCtx, /* Copy of sixth arg to _apply() */ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ sqlite3_changeset_iter *p /* Handle describing change and conflict */ ), void *pCtx /* First argument passed to xConflict */ ); SQLITE_API int sqlite3changeset_apply_v2_strm( sqlite3 *db, /* Apply change to "main" db of this handle */ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ void *pIn, /* First arg for xInput */ int(*xFilter)( void *pCtx, /* Copy of sixth arg to _apply() */ const char *zTab /* Table name */ ), int(*xConflict)( void *pCtx, /* Copy of sixth arg to _apply() */ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ sqlite3_changeset_iter *p /* Handle describing change and conflict */ ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, int flags ); SQLITE_API int sqlite3changeset_concat_strm( int (*xInputA)(void *pIn, void *pData, int *pnData), void *pInA, int (*xInputB)(void *pIn, void *pData, int *pnData), void *pInB, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); SQLITE_API int sqlite3changeset_invert_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); SQLITE_API int sqlite3changeset_start_strm( sqlite3_changeset_iter **pp, int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); SQLITE_API int sqlite3changeset_start_v2_strm( sqlite3_changeset_iter **pp, int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int flags ); SQLITE_API int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); SQLITE_API int sqlite3session_patchset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); SQLITE_API int sqlite3rebaser_rebase_strm( sqlite3_rebaser *pRebaser, int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); /* ** CAPI3REF: Configure global parameters ** ** The sqlite3session_config() interface is used to make global configuration ** changes to the sessions module in order to tune it to the specific needs ** of the application. ** ** The sqlite3session_config() interface is not threadsafe. If it is invoked ** while any other thread is inside any other sessions method then the ** results are undefined. Furthermore, if it is invoked after any sessions ** related objects have been created, the results are also undefined. ** ** The first argument to the sqlite3session_config() function must be one ** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The ** interpretation of the (void*) value passed as the second parameter and ** the effect of calling this function depends on the value of the first ** parameter. ** **
**
SQLITE_SESSION_CONFIG_STRMSIZE
** By default, the sessions module streaming interfaces attempt to input ** and output data in approximately 1 KiB chunks. This operand may be used ** to set and query the value of this configuration setting. The pointer ** passed as the second argument must point to a value of type (int). ** If this value is greater than 0, it is used as the new streaming data ** chunk size for both input and output. Before returning, the (int) value ** pointed to by pArg is set to the final value of the streaming interface ** chunk size. **
** ** This function returns SQLITE_OK if successful, or an SQLite error code ** otherwise. */ SQLITE_API int sqlite3session_config(int op, void *pArg); /* ** CAPI3REF: Values for sqlite3session_config(). */ #define SQLITE_SESSION_CONFIG_STRMSIZE 1 /* ** Make sure we can call this stuff from C++. */ #if 0 } #endif #endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */ /******** End of sqlite3session.h *********/ /******** Begin file fts5.h *********/ /* ** 2014 May 31 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** Interfaces to extend FTS5. Using the interfaces defined in this file, ** FTS5 may be extended with: ** ** * custom tokenizers, and ** * custom auxiliary functions. */ #ifndef _FTS5_H #define _FTS5_H #if 0 extern "C" { #endif /************************************************************************* ** CUSTOM AUXILIARY FUNCTIONS ** ** Virtual table implementations may overload SQL functions by implementing ** the sqlite3_module.xFindFunction() method. */ typedef struct Fts5ExtensionApi Fts5ExtensionApi; typedef struct Fts5Context Fts5Context; typedef struct Fts5PhraseIter Fts5PhraseIter; typedef void (*fts5_extension_function)( const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ Fts5Context *pFts, /* First arg to pass to pApi functions */ sqlite3_context *pCtx, /* Context for returning result/error */ int nVal, /* Number of values in apVal[] array */ sqlite3_value **apVal /* Array of trailing arguments */ ); struct Fts5PhraseIter { const unsigned char *a; const unsigned char *b; }; /* ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): ** Return a copy of the context pointer the extension function was ** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken ** to the total number of tokens in the FTS5 table. Or, if iCol is ** non-negative but less than the number of columns in the table, return ** the total number of tokens in column iCol, considering all rows in ** the FTS5 table. ** ** If parameter iCol is greater than or equal to the number of columns ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. ** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** ** xColumnCount(pFts): ** Return the number of columns in the table. ** ** xColumnSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken ** to the total number of tokens in the current row. Or, if iCol is ** non-negative but less than the number of columns in the table, set ** *pnToken to the number of tokens in column iCol of the current row. ** ** If parameter iCol is greater than or equal to the number of columns ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. ** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** ** This function may be quite inefficient if used with an FTS5 table ** created with the "columnsize=0" option. ** ** xColumnText: ** If parameter iCol is less than zero, or greater than or equal to the ** number of columns in the table, SQLITE_RANGE is returned. ** ** Otherwise, this function attempts to retrieve the text of column iCol of ** the current document. If successful, (*pz) is set to point to a buffer ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, ** if an error occurs, an SQLite error code is returned and the final values ** of (*pz) and (*pn) are undefined. ** ** xPhraseCount: ** Returns the number of phrases in the current query expression. ** ** xPhraseSize: ** If parameter iCol is less than zero, or greater than or equal to the ** number of phrases in the current query, as returned by xPhraseCount, ** 0 is returned. Otherwise, this function returns the number of tokens in ** phrase iPhrase of the query. Phrases are numbered starting from zero. ** ** xInstCount: ** Set *pnInst to the total number of occurrences of all phrases within ** the query within the current row. Return SQLITE_OK if successful, or ** an error code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. If the FTS5 table is created ** with either "detail=none" or "detail=column" and "content=" option ** (i.e. if it is a contentless table), then this API always returns 0. ** ** xInst: ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value ** output by xInstCount(). If iIdx is less than zero or greater than ** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. ** ** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the ** first token of the phrase. SQLITE_OK is returned if successful, or an ** error code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. ** ** xRowid: ** Returns the rowid of the current row. ** ** xTokenize: ** Tokenize text using the tokenizer belonging to the FTS5 table. ** ** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback): ** This API function is used to query the FTS table for phrase iPhrase ** of the current query. Specifically, a query equivalent to: ** ** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid ** ** with $p set to a phrase equivalent to the phrase iPhrase of the ** current query is executed. Any column filter that applies to ** phrase iPhrase of the current query is included in $p. For each ** row visited, the callback function passed as the fourth argument ** is invoked. The context and API objects passed to the callback ** function may be used to access the properties of each matched row. ** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** ** If parameter iPhrase is less than zero, or greater than or equal to ** the number of phrases in the query, as returned by xPhraseCount(), ** this function returns SQLITE_RANGE. ** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. ** Otherwise, the error code is propagated upwards. ** ** If the query runs to completion without incident, SQLITE_OK is returned. ** Or, if some error occurs before the query completes or is aborted by ** the callback, an SQLite error code is returned. ** ** ** xSetAuxdata(pFts5, pAux, xDelete) ** ** Save the pointer passed as the second argument as the extension function's ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of ** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for ** each FTS query (MATCH expression). If the extension function is invoked ** more than once for a single FTS query, then all invocations share a ** single auxiliary data context. ** ** If there is already an auxiliary data pointer when this function is ** invoked, then it is replaced by the new pointer. If an xDelete callback ** was specified along with the original pointer, it is invoked at this ** point. ** ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** ** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. ** ** ** xGetAuxdata(pFts5, bClear) ** ** Returns the current auxiliary data pointer for the fts5 extension ** function. See the xSetAuxdata() method for details. ** ** If the bClear argument is non-zero, then the auxiliary data is cleared ** (set to NULL) before this function returns. In this case the xDelete, ** if any, is not invoked. ** ** ** xRowCount(pFts5, pnRow) ** ** This function is used to retrieve the total number of rows in the table. ** In other words, the same value that would be returned by: ** ** SELECT count(*) FROM ftstable; ** ** xPhraseFirst() ** This function is used, along with type Fts5PhraseIter and the xPhraseNext ** method, to iterate through all instances of a single query phrase within ** the current row. This is the same information as is accessible via the ** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient ** to use, this API may be faster under some circumstances. To iterate ** through instances of phrase iPhrase, use the following code: ** ** Fts5PhraseIter iter; ** int iCol, iOff; ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); ** iCol>=0; ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) ** ){ ** // An instance of phrase iPhrase at offset iOff of column iCol ** } ** ** The Fts5PhraseIter structure is defined above. Applications should not ** modify this structure directly - it should only be used as shown above ** with the xPhraseFirst() and xPhraseNext() API methods (and by ** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. If the FTS5 table is created ** with either "detail=none" or "detail=column" and "content=" option ** (i.e. if it is a contentless table), then this API always iterates ** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** ** xPhraseNext() ** See xPhraseFirst above. ** ** xPhraseFirstColumn() ** This function and xPhraseNextColumn() are similar to the xPhraseFirst() ** and xPhraseNext() APIs described above. The difference is that instead ** of iterating through all instances of a phrase in the current row, these ** APIs are used to iterate through the set of columns in the current row ** that contain one or more instances of a specified phrase. For example: ** ** Fts5PhraseIter iter; ** int iCol; ** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); ** iCol>=0; ** pApi->xPhraseNextColumn(pFts, &iter, &iCol) ** ){ ** // Column iCol contains at least one instance of phrase iPhrase ** } ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" option. If the FTS5 table is created with either ** "detail=none" "content=" option (i.e. if it is a contentless table), ** then this API always iterates through an empty set (all calls to ** xPhraseFirstColumn() set iCol to -1). ** ** The information accessed using this API and its companion ** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext ** (or xInst/xInstCount). The chief advantage of this API is that it is ** significantly more efficient than those alternatives when used with ** "detail=column" tables. ** ** xPhraseNextColumn() ** See xPhraseFirstColumn above. ** ** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken) ** This is used to access token iToken of phrase iPhrase of the current ** query. Before returning, output parameter *ppToken is set to point ** to a buffer containing the requested token, and *pnToken to the ** size of this buffer in bytes. ** ** If iPhrase or iToken are less than zero, or if iPhrase is greater than ** or equal to the number of phrases in the query as reported by ** xPhraseCount(), or if iToken is equal to or greater than the number of ** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken are both zeroed. ** ** The output text is not a copy of the query text that specified the ** token. It is the output of the tokenizer module. For tokendata=1 ** tables, this includes any embedded 0x00 and trailing data. ** ** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken) ** This is used to access token iToken of phrase hit iIdx within the ** current row. If iIdx is less than zero or greater than or equal to the ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, ** output variable (*ppToken) is set to point to a buffer containing the ** matching document token, and (*pnToken) to the size of that buffer in ** bytes. This API is not available if the specified token matches a ** prefix query term. In that case both output variables are always set ** to 0. ** ** The output text is not a copy of the document text that was tokenized. ** It is the output of the tokenizer module. For tokendata=1 tables, this ** includes any embedded 0x00 and trailing data. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. */ struct Fts5ExtensionApi { int iVersion; /* Currently always set to 3 */ void *(*xUserData)(Fts5Context*); int (*xColumnCount)(Fts5Context*); int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); int (*xTokenize)(Fts5Context*, const char *pText, int nText, /* Text to tokenize */ void *pCtx, /* Context passed to xToken() */ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ ); int (*xPhraseCount)(Fts5Context*); int (*xPhraseSize)(Fts5Context*, int iPhrase); int (*xInstCount)(Fts5Context*, int *pnInst); int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff); sqlite3_int64 (*xRowid)(Fts5Context*); int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn); int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken); int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData, int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) ); int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); void *(*xGetAuxdata)(Fts5Context*, int bClear); int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); /* Below this point are iVersion>=3 only */ int (*xQueryToken)(Fts5Context*, int iPhrase, int iToken, const char **ppToken, int *pnToken ); int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); }; /* ** CUSTOM AUXILIARY FUNCTIONS *************************************************************************/ /************************************************************************* ** CUSTOM TOKENIZERS ** ** Applications may also register custom tokenizer types. A tokenizer ** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** ** xCreate: ** This function is used to allocate and initialize a tokenizer instance. ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) ** pointer provided by the application when the fts5_tokenizer object ** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used ** to create the FTS5 table. ** ** The final argument is an output variable. If successful, (*ppOut) ** should be set to point to the new tokenizer handle and SQLITE_OK ** returned. If an error occurs, some value other than SQLITE_OK should ** be returned. In this case, fts5 assumes that the final value of *ppOut ** is undefined. ** ** xDelete: ** This function is invoked to delete a tokenizer handle previously ** allocated using xCreate(). Fts5 guarantees that this function will ** be invoked exactly once for each successful call to xCreate(). ** ** xTokenize: ** This function is expected to tokenize the nText byte string indicated ** by argument pText. pText may or may not be nul-terminated. The first ** argument passed to this function is a pointer to an Fts5Tokenizer object ** returned by an earlier call to xCreate(). ** ** The second argument indicates the reason that FTS5 is requesting ** tokenization of the supplied text. This is always one of the following ** four values: ** **
  • FTS5_TOKENIZE_DOCUMENT - A document is being inserted into ** or removed from the FTS table. The tokenizer is being invoked to ** determine the set of tokens to add to (or delete from) the ** FTS index. ** **
  • FTS5_TOKENIZE_QUERY - A MATCH query is being executed ** against the FTS index. The tokenizer is being called to tokenize ** a bareword or quoted string specified as part of the query. ** **
  • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as ** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is ** followed by a "*" character, indicating that the last token ** returned by the tokenizer will be treated as a token prefix. ** **
  • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to ** satisfy an fts5_api.xTokenize() request made by an auxiliary ** function. Or an fts5_api.xColumnSize() request made by the same ** on a columnsize=0 database. **
** ** For each token in the input string, the supplied callback xToken() must ** be invoked. The first argument to it should be a copy of the pointer ** passed as the second argument to xTokenize(). The third and fourth ** arguments are a pointer to a buffer containing the token text, and the ** size of the token in bytes. The 4th and 5th arguments are the byte offsets ** of the first byte of and first byte immediately following the text from ** which the token is derived within the input. ** ** The second argument passed to the xToken() callback ("tflags") should ** normally be set to 0. The exception is if the tokenizer supports ** synonyms. In this case see the discussion below for details. ** ** FTS5 assumes the xToken() callback is invoked for each token in the ** order that they occur within the input text. ** ** If an xToken() callback returns any value other than SQLITE_OK, then ** the tokenization should be abandoned and the xTokenize() method should ** immediately return a copy of the xToken() return value. Or, if the ** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally, ** if an error occurs with the xTokenize() implementation itself, it ** may abandon the tokenization and return any error code other than ** SQLITE_OK or SQLITE_DONE. ** ** SYNONYM SUPPORT ** ** Custom tokenizers may also support synonyms. Consider a case in which a ** user wishes to query for a phrase such as "first place". Using the ** built-in tokenizers, the FTS5 query 'first + place' will match instances ** of "first place" within the document set, but not alternative forms ** such as "1st place". In some applications, it would be better to match ** all instances of "first place" or "1st place" regardless of which form ** the user specified in the MATCH query text. ** ** There are several ways to approach this in FTS5: ** **
  1. By mapping all synonyms to a single token. In this case, using ** the above example, this means that the tokenizer returns the ** same token for inputs "first" and "1st". Say that token is in ** fact "first", so that when the user inserts the document "I won ** 1st place" entries are added to the index for tokens "i", "won", ** "first" and "place". If the user then queries for '1st + place', ** the tokenizer substitutes "first" for "1st" and the query works ** as expected. ** **
  2. By querying the index for all synonyms of each query term ** separately. In this case, when tokenizing query text, the ** tokenizer may provide multiple synonyms for a single term ** within the document. FTS5 then queries the index for each ** synonym individually. For example, faced with the query: ** ** ** ... MATCH 'first place' ** ** the tokenizer offers both "1st" and "first" as synonyms for the ** first token in the MATCH query and FTS5 effectively runs a query ** similar to: ** ** ** ... MATCH '(first OR 1st) place' ** ** except that, for the purposes of auxiliary functions, the query ** still appears to contain just two phrases - "(first OR 1st)" ** being treated as a single phrase. ** **
  3. By adding multiple synonyms for a single term to the FTS index. ** Using this method, when tokenizing document text, the tokenizer ** provides multiple synonyms for each token. So that when a ** document such as "I won first place" is tokenized, entries are ** added to the FTS index for "i", "won", "first", "1st" and ** "place". ** ** This way, even if the tokenizer does not provide synonyms ** when tokenizing query text (it should not - to do so would be ** inefficient), it doesn't matter if the user queries for ** 'first + place' or '1st + place', as there are entries in the ** FTS index corresponding to both forms of the first token. **
** ** Whether it is parsing document or query text, any call to xToken that ** specifies a tflags argument with the FTS5_TOKEN_COLOCATED bit ** is considered to supply a synonym for the previous token. For example, ** when parsing the document "I won first place", a tokenizer that supports ** synonyms would call xToken() 5 times, as follows: ** ** ** xToken(pCtx, 0, "i", 1, 0, 1); ** xToken(pCtx, 0, "won", 3, 2, 5); ** xToken(pCtx, 0, "first", 5, 6, 11); ** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11); ** xToken(pCtx, 0, "place", 5, 12, 17); ** ** ** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time ** xToken() is called. Multiple synonyms may be specified for a single token ** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. ** There is no limit to the number of synonyms that may be provided for a ** single token. ** ** In many cases, method (1) above is the best approach. It does not add ** extra data to the FTS index or require FTS5 to query for multiple terms, ** so it is efficient in terms of disk space and query speed. However, it ** does not support prefix queries very well. If, as suggested above, the ** token "first" is substituted for "1st" by the tokenizer, then the query: ** ** ** ... MATCH '1s*' ** ** will not match documents that contain the token "1st" (as the tokenizer ** will probably not map "1s" to any prefix of "first"). ** ** For full prefix support, method (3) may be preferred. In this case, ** because the index contains entries for both "first" and "1st", prefix ** queries such as 'fi*' or '1s*' will match correctly. However, because ** extra entries are added to the FTS index, this method uses more space ** within the database. ** ** Method (2) offers a midpoint between (1) and (3). Using this method, ** a query such as '1s*' will match documents that contain the literal ** token "1st", but not "first" (assuming the tokenizer is not able to ** provide synonyms for prefixes). However, a non-prefix query like '1st' ** will match against "1st" and "first". This method does not require ** extra disk space, as no extra entries are added to the FTS index. ** On the other hand, it may require more CPU cycles to run MATCH queries, ** as separate queries of the FTS index are required for each synonym. ** ** When using methods (2) or (3), it is important that the tokenizer only ** provide synonyms when tokenizing document text (method (3)) or query ** text (method (2)), not both. Doing so will not cause any errors, but is ** inefficient. */ typedef struct Fts5Tokenizer Fts5Tokenizer; typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); void (*xDelete)(Fts5Tokenizer*); int (*xTokenize)(Fts5Tokenizer*, void *pCtx, int flags, /* Mask of FTS5_TOKENIZE_* flags */ const char *pText, int nText, int (*xToken)( void *pCtx, /* Copy of 2nd argument to xTokenize() */ int tflags, /* Mask of FTS5_TOKEN_* flags */ const char *pToken, /* Pointer to buffer containing token */ int nToken, /* Size of token in bytes */ int iStart, /* Byte offset of token within input text */ int iEnd /* Byte offset of end of token within input text */ ) ); }; /* Flags that may be passed as the third argument to xTokenize() */ #define FTS5_TOKENIZE_QUERY 0x0001 #define FTS5_TOKENIZE_PREFIX 0x0002 #define FTS5_TOKENIZE_DOCUMENT 0x0004 #define FTS5_TOKENIZE_AUX 0x0008 /* Flags that may be passed by the tokenizer implementation back to FTS5 ** as the third argument to the supplied xToken callback. */ #define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */ /* ** END OF CUSTOM TOKENIZERS *************************************************************************/ /************************************************************************* ** FTS5 EXTENSION REGISTRATION API */ typedef struct fts5_api fts5_api; struct fts5_api { int iVersion; /* Currently always set to 2 */ /* Create a new tokenizer */ int (*xCreateTokenizer)( fts5_api *pApi, const char *zName, void *pUserData, fts5_tokenizer *pTokenizer, void (*xDestroy)(void*) ); /* Find an existing tokenizer */ int (*xFindTokenizer)( fts5_api *pApi, const char *zName, void **ppUserData, fts5_tokenizer *pTokenizer ); /* Create a new auxiliary function */ int (*xCreateFunction)( fts5_api *pApi, const char *zName, void *pUserData, fts5_extension_function xFunction, void (*xDestroy)(void*) ); }; /* ** END OF REGISTRATION API *************************************************************************/ #if 0 } /* end of the 'extern "C"' block */ #endif #endif /* _FTS5_H */ /******** End of fts5.h *********/ /************** End of sqlite3.h *********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /* ** Reuse the STATIC_LRU for mutex access to sqlite3_temp_directory. */ #define SQLITE_MUTEX_STATIC_TEMPDIR SQLITE_MUTEX_STATIC_VFS1 /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ #if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) #include "sqlite_cfg.h" #define SQLITECONFIG_H 1 #endif /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/ /************** Begin file sqliteLimit.h *************************************/ /* ** 2007 May 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file defines various limits of what SQLite can process. */ /* ** The maximum length of a TEXT or BLOB in bytes. This also ** limits the size of a row in a table or index. ** ** The hard limit is the ability of a 32-bit signed integer ** to count the size: 2^31-1 or 2147483647. */ #ifndef SQLITE_MAX_LENGTH # define SQLITE_MAX_LENGTH 1000000000 #endif /* ** This is the maximum number of ** ** * Columns in a table ** * Columns in an index ** * Columns in a view ** * Terms in the SET clause of an UPDATE statement ** * Terms in the result set of a SELECT statement ** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement. ** * Terms in the VALUES clause of an INSERT statement ** ** The hard upper limit here is 32676. Most database people will ** tell you that in a well-normalized database, you usually should ** not have more than a dozen or so columns in any table. And if ** that is the case, there is no point in having more than a few ** dozen values in any of the other situations described above. */ #ifndef SQLITE_MAX_COLUMN # define SQLITE_MAX_COLUMN 2000 #endif /* ** The maximum length of a single SQL statement in bytes. ** ** It used to be the case that setting this value to zero would ** turn the limit off. That is no longer true. It is not possible ** to turn this limit off. */ #ifndef SQLITE_MAX_SQL_LENGTH # define SQLITE_MAX_SQL_LENGTH 1000000000 #endif /* ** The maximum depth of an expression tree. This is limited to ** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might ** want to place more severe limits on the complexity of an ** expression. A value of 0 means that there is no limit. */ #ifndef SQLITE_MAX_EXPR_DEPTH # define SQLITE_MAX_EXPR_DEPTH 1000 #endif /* ** The maximum number of terms in a compound SELECT statement. ** The code generator for compound SELECT statements does one ** level of recursion for each term. A stack overflow can result ** if the number of terms is too large. In practice, most SQL ** never has more than 3 or 4 terms. Use a value of 0 to disable ** any limit on the number of terms in a compound SELECT. */ #ifndef SQLITE_MAX_COMPOUND_SELECT # define SQLITE_MAX_COMPOUND_SELECT 500 #endif /* ** The maximum number of opcodes in a VDBE program. ** Not currently enforced. */ #ifndef SQLITE_MAX_VDBE_OP # define SQLITE_MAX_VDBE_OP 250000000 #endif /* ** The maximum number of arguments to an SQL function. */ #ifndef SQLITE_MAX_FUNCTION_ARG # define SQLITE_MAX_FUNCTION_ARG 127 #endif /* ** The suggested maximum number of in-memory pages to use for ** the main database table and for temporary tables. ** ** IMPLEMENTATION-OF: R-30185-15359 The default suggested cache size is -2000, ** which means the cache size is limited to 2048000 bytes of memory. ** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be ** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options. */ #ifndef SQLITE_DEFAULT_CACHE_SIZE # define SQLITE_DEFAULT_CACHE_SIZE -2000 #endif /* ** The default number of frames to accumulate in the log file before ** checkpointing the database in WAL mode. */ #ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT # define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000 #endif /* ** The maximum number of attached databases. This must be between 0 ** and 125. The upper bound of 125 is because the attached databases are ** counted using a signed 8-bit integer which has a maximum value of 127 ** and we have to allow 2 extra counts for the "main" and "temp" databases. */ #ifndef SQLITE_MAX_ATTACHED # define SQLITE_MAX_ATTACHED 10 #endif /* ** The maximum value of a ?nnn wildcard that the parser will accept. ** If the value exceeds 32767 then extra space is required for the Expr ** structure. But otherwise, we believe that the number can be as large ** as a signed 32-bit integer can hold. */ #ifndef SQLITE_MAX_VARIABLE_NUMBER # define SQLITE_MAX_VARIABLE_NUMBER 32766 #endif /* Maximum page size. The upper bound on this value is 65536. This a limit ** imposed by the use of 16-bit offsets within each page. ** ** Earlier versions of SQLite allowed the user to change this value at ** compile time. This is no longer permitted, on the grounds that it creates ** a library that is technically incompatible with an SQLite library ** compiled with a different limit. If a process operating on a database ** with a page-size of 65536 bytes crashes, then an instance of SQLite ** compiled with the default page-size limit will not be able to rollback ** the aborted transaction. This could lead to database corruption. */ #ifdef SQLITE_MAX_PAGE_SIZE # undef SQLITE_MAX_PAGE_SIZE #endif #define SQLITE_MAX_PAGE_SIZE 65536 /* ** The default size of a database page. */ #ifndef SQLITE_DEFAULT_PAGE_SIZE # define SQLITE_DEFAULT_PAGE_SIZE 4096 #endif #if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE # undef SQLITE_DEFAULT_PAGE_SIZE # define SQLITE_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE #endif /* ** Ordinarily, if no value is explicitly provided, SQLite creates databases ** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain ** device characteristics (sector-size and atomic write() support), ** SQLite may choose a larger value. This constant is the maximum value ** SQLite will choose on its own. */ #ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE # define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192 #endif #if SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE # undef SQLITE_MAX_DEFAULT_PAGE_SIZE # define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE #endif /* ** Maximum number of pages in one database file. ** ** This is really just the default value for the max_page_count pragma. ** This value can be lowered (or raised) at run-time using that the ** max_page_count macro. */ #ifndef SQLITE_MAX_PAGE_COUNT # define SQLITE_MAX_PAGE_COUNT 0xfffffffe /* 4294967294 */ #endif /* ** Maximum length (in bytes) of the pattern in a LIKE or GLOB ** operator. */ #ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH # define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 #endif /* ** Maximum depth of recursion for triggers. ** ** A value of 1 means that a trigger program will not be able to itself ** fire any triggers. A value of 0 means that no trigger programs at all ** may be executed. */ #ifndef SQLITE_MAX_TRIGGER_DEPTH # define SQLITE_MAX_TRIGGER_DEPTH 1000 #endif /************** End of sqliteLimit.h *****************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /* Disable nuisance warnings on Borland compilers */ #if defined(__BORLANDC__) #pragma warn -rch /* unreachable code */ #pragma warn -ccc /* Condition is always true or false */ #pragma warn -aus /* Assigned value is never used */ #pragma warn -csu /* Comparing signed and unsigned */ #pragma warn -spa /* Suspicious pointer arithmetic */ #endif /* ** A few places in the code require atomic load/store of aligned ** integer values. */ #ifndef __has_extension # define __has_extension(x) 0 /* compatibility with non-clang compilers */ #endif #if GCC_VERSION>=4007000 || __has_extension(c_atomic) # define SQLITE_ATOMIC_INTRINSICS 1 # define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED) # define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED) #else # define SQLITE_ATOMIC_INTRINSICS 0 # define AtomicLoad(PTR) (*(PTR)) # define AtomicStore(PTR,VAL) (*(PTR) = (VAL)) #endif /* ** Include standard header files as necessary */ #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif /* ** The following macros are used to cast pointers to integers and ** integers to pointers. The way you do this varies from one compiler ** to the next, so we have developed the following set of #if statements ** to generate appropriate macros for a wide range of compilers. ** ** The correct "ANSI" way to do this is to use the intptr_t type. ** Unfortunately, that typedef is not available on all compilers, or ** if it is available, it requires an #include of specific headers ** that vary from one machine to the next. ** ** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on ** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)). ** So we have to define the macros in different ways depending on the ** compiler. */ #if defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */ # define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X)) #elif defined(__PTRDIFF_TYPE__) /* This case should work for GCC */ # define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X)) #elif !defined(__GNUC__) /* Works for compilers other than LLVM */ # define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X]) # define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0)) #else /* Generates a warning - but it always works */ # define SQLITE_INT_TO_PTR(X) ((void*)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(X)) #endif /* ** Macros to hint to the compiler that a function should or should not be ** inlined. */ #if defined(__GNUC__) # define SQLITE_NOINLINE __attribute__((noinline)) # define SQLITE_INLINE __attribute__((always_inline)) inline #elif defined(_MSC_VER) && _MSC_VER>=1310 # define SQLITE_NOINLINE __declspec(noinline) # define SQLITE_INLINE __forceinline #else # define SQLITE_NOINLINE # define SQLITE_INLINE #endif #if defined(SQLITE_COVERAGE_TEST) || defined(__STRICT_ANSI__) # undef SQLITE_INLINE # define SQLITE_INLINE #endif /* ** Make sure that the compiler intrinsics we desire are enabled when ** compiling with an appropriate version of MSVC unless prevented by ** the SQLITE_DISABLE_INTRINSIC define. */ #if !defined(SQLITE_DISABLE_INTRINSIC) # if defined(_MSC_VER) && _MSC_VER>=1400 # if !defined(_WIN32_WCE) # include # pragma intrinsic(_byteswap_ushort) # pragma intrinsic(_byteswap_ulong) # pragma intrinsic(_byteswap_uint64) # pragma intrinsic(_ReadWriteBarrier) # else # include # endif # endif #endif /* ** Enable SQLITE_USE_SEH by default on MSVC builds. Only omit ** SEH support if the -DSQLITE_OMIT_SEH option is given. */ #if defined(_MSC_VER) && !defined(SQLITE_OMIT_SEH) # define SQLITE_USE_SEH 1 #else # undef SQLITE_USE_SEH #endif /* ** Enable SQLITE_DIRECT_OVERFLOW_READ, unless the build explicitly ** disables it using -DSQLITE_DIRECT_OVERFLOW_READ=0 */ #if defined(SQLITE_DIRECT_OVERFLOW_READ) && SQLITE_DIRECT_OVERFLOW_READ+1==1 /* Disable if -DSQLITE_DIRECT_OVERFLOW_READ=0 */ # undef SQLITE_DIRECT_OVERFLOW_READ #else /* In all other cases, enable */ # define SQLITE_DIRECT_OVERFLOW_READ 1 #endif /* ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. ** 0 means mutexes are permanently disable and the library is never ** threadsafe. 1 means the library is serialized which is the highest ** level of threadsafety. 2 means the library is multithreaded - multiple ** threads can use SQLite as long as no two threads try to use the same ** database connection at the same time. ** ** Older versions of SQLite used an optional THREADSAFE macro. ** We support that for legacy. ** ** To ensure that the correct value of "THREADSAFE" is reported when querying ** for compile-time options at runtime (e.g. "PRAGMA compile_options"), this ** logic is partially replicated in ctime.c. If it is updated here, it should ** also be updated there. */ #if !defined(SQLITE_THREADSAFE) # if defined(THREADSAFE) # define SQLITE_THREADSAFE THREADSAFE # else # define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */ # endif #endif /* ** Powersafe overwrite is on by default. But can be turned off using ** the -DSQLITE_POWERSAFE_OVERWRITE=0 command-line option. */ #ifndef SQLITE_POWERSAFE_OVERWRITE # define SQLITE_POWERSAFE_OVERWRITE 1 #endif /* ** EVIDENCE-OF: R-25715-37072 Memory allocation statistics are enabled by ** default unless SQLite is compiled with SQLITE_DEFAULT_MEMSTATUS=0 in ** which case memory allocation statistics are disabled by default. */ #if !defined(SQLITE_DEFAULT_MEMSTATUS) # define SQLITE_DEFAULT_MEMSTATUS 1 #endif /* ** Exactly one of the following macros must be defined in order to ** specify which memory allocation subsystem to use. ** ** SQLITE_SYSTEM_MALLOC // Use normal system malloc() ** SQLITE_WIN32_MALLOC // Use Win32 native heap API ** SQLITE_ZERO_MALLOC // Use a stub allocator that always fails ** SQLITE_MEMDEBUG // Debugging version of system malloc() ** ** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the ** assert() macro is enabled, each call into the Win32 native heap subsystem ** will cause HeapValidate to be called. If heap validation should fail, an ** assertion will be triggered. ** ** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as ** the default. */ #if defined(SQLITE_SYSTEM_MALLOC) \ + defined(SQLITE_WIN32_MALLOC) \ + defined(SQLITE_ZERO_MALLOC) \ + defined(SQLITE_MEMDEBUG)>1 # error "Two or more of the following compile-time configuration options\ are defined but at most one is allowed:\ SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG,\ SQLITE_ZERO_MALLOC" #endif #if defined(SQLITE_SYSTEM_MALLOC) \ + defined(SQLITE_WIN32_MALLOC) \ + defined(SQLITE_ZERO_MALLOC) \ + defined(SQLITE_MEMDEBUG)==0 # define SQLITE_SYSTEM_MALLOC 1 #endif /* ** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the ** sizes of memory allocations below this value where possible. */ #if !defined(SQLITE_MALLOC_SOFT_LIMIT) # define SQLITE_MALLOC_SOFT_LIMIT 1024 #endif /* ** We need to define _XOPEN_SOURCE as follows in order to enable ** recursive mutexes on most Unix systems and fchmod() on OpenBSD. ** But _XOPEN_SOURCE define causes problems for Mac OS X, so omit ** it. */ #if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) # define _XOPEN_SOURCE 600 #endif /* ** NDEBUG and SQLITE_DEBUG are opposites. It should always be true that ** defined(NDEBUG)==!defined(SQLITE_DEBUG). If this is not currently true, ** make it true by defining or undefining NDEBUG. ** ** Setting NDEBUG makes the code smaller and faster by disabling the ** assert() statements in the code. So we want the default action ** to be for NDEBUG to be set and NDEBUG to be undefined only if SQLITE_DEBUG ** is set. Thus NDEBUG becomes an opt-in rather than an opt-out ** feature. */ #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif #if defined(NDEBUG) && defined(SQLITE_DEBUG) # undef NDEBUG #endif /* ** Enable SQLITE_ENABLE_EXPLAIN_COMMENTS if SQLITE_DEBUG is turned on. */ #if !defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) && defined(SQLITE_DEBUG) # define SQLITE_ENABLE_EXPLAIN_COMMENTS 1 #endif /* ** The testcase() macro is used to aid in coverage testing. When ** doing coverage testing, the condition inside the argument to ** testcase() must be evaluated both true and false in order to ** get full branch coverage. The testcase() macro is inserted ** to help ensure adequate test coverage in places where simple ** condition/decision coverage is inadequate. For example, testcase() ** can be used to make sure boundary values are tested. For ** bitmask tests, testcase() can be used to make sure each bit ** is significant and used at least once. On switch statements ** where multiple cases go to the same block of code, testcase() ** can insure that all cases are evaluated. */ #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) # ifndef SQLITE_AMALGAMATION extern unsigned int sqlite3CoverageCounter; # endif # define testcase(X) if( X ){ sqlite3CoverageCounter += (unsigned)__LINE__; } #else # define testcase(X) #endif /* ** The TESTONLY macro is used to enclose variable declarations or ** other bits of code that are needed to support the arguments ** within testcase() and assert() macros. */ #if !defined(NDEBUG) || defined(SQLITE_COVERAGE_TEST) # define TESTONLY(X) X #else # define TESTONLY(X) #endif /* ** Sometimes we need a small amount of code such as a variable initialization ** to setup for a later assert() statement. We do not want this code to ** appear when assert() is disabled. The following macro is therefore ** used to contain that setup code. The "VVA" acronym stands for ** "Verification, Validation, and Accreditation". In other words, the ** code within VVA_ONLY() will only run during verification processes. */ #ifndef NDEBUG # define VVA_ONLY(X) X #else # define VVA_ONLY(X) #endif /* ** Disable ALWAYS() and NEVER() (make them pass-throughs) for coverage ** and mutation testing */ #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 #endif /* ** The ALWAYS and NEVER macros surround boolean expressions which ** are intended to always be true or false, respectively. Such ** expressions could be omitted from the code completely. But they ** are included in a few cases in order to enhance the resilience ** of SQLite to unexpected behavior - to make the code "self-healing" ** or "ductile" rather than being "brittle" and crashing at the first ** hint of unplanned behavior. ** ** In other words, ALWAYS and NEVER are added for defensive code. ** ** When doing coverage testing ALWAYS and NEVER are hard-coded to ** be true and false so that the unreachable code they specify will ** not be counted as untested code. */ #if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) # define NEVER(X) (X) #endif /* ** Some conditionals are optimizations only. In other words, if the ** conditionals are replaced with a constant 1 (true) or 0 (false) then ** the correct answer is still obtained, though perhaps not as quickly. ** ** The following macros mark these optimizations conditionals. */ #if defined(SQLITE_MUTATION_TEST) # define OK_IF_ALWAYS_TRUE(X) (1) # define OK_IF_ALWAYS_FALSE(X) (0) #else # define OK_IF_ALWAYS_TRUE(X) (X) # define OK_IF_ALWAYS_FALSE(X) (X) #endif /* ** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is ** defined. We need to defend against those failures when testing with ** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches ** during a normal build. The following macro can be used to disable tests ** that are always false except when SQLITE_TEST_REALLOC_STRESS is set. */ #if defined(SQLITE_TEST_REALLOC_STRESS) # define ONLY_IF_REALLOC_STRESS(X) (X) #elif !defined(NDEBUG) # define ONLY_IF_REALLOC_STRESS(X) ((X)?(assert(0),1):0) #else # define ONLY_IF_REALLOC_STRESS(X) (0) #endif /* ** Declarations used for tracing the operating system interfaces. */ #if defined(SQLITE_FORCE_OS_TRACE) || defined(SQLITE_TEST) || \ (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) extern int sqlite3OSTrace; # define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X # define SQLITE_HAVE_OS_TRACE #else # define OSTRACE(X) # undef SQLITE_HAVE_OS_TRACE #endif /* ** Is the sqlite3ErrName() function needed in the build? Currently, ** it is needed by "mutex_w32.c" (when debugging), "os_win.c" (when ** OSTRACE is enabled), and by several "test*.c" files (which are ** compiled using SQLITE_TEST). */ #if defined(SQLITE_HAVE_OS_TRACE) || defined(SQLITE_TEST) || \ (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) # define SQLITE_NEED_ERR_NAME #else # undef SQLITE_NEED_ERR_NAME #endif /* ** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_OMIT_EXPLAIN # undef SQLITE_ENABLE_EXPLAIN_COMMENTS #endif /* ** SQLITE_OMIT_VIRTUALTABLE implies SQLITE_OMIT_ALTERTABLE */ #if defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_ALTERTABLE) # define SQLITE_OMIT_ALTERTABLE #endif /* ** Return true (non-zero) if the input is an integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() ** macros to verify that we have tested SQLite for large-file support. */ #define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0) /* ** The macro unlikely() is a hint that surrounds a boolean ** expression that is usually false. Macro likely() surrounds ** a boolean expression that is usually true. These hints could, ** in theory, be used by the compiler to generate better code, but ** currently they are just comments for human readers. */ #define likely(X) (X) #define unlikely(X) (X) /************** Include hash.h in the middle of sqliteInt.h ******************/ /************** Begin file hash.h ********************************************/ /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the header file for the generic hash-table implementation ** used in SQLite. */ #ifndef SQLITE_HASH_H #define SQLITE_HASH_H /* Forward declarations of structures. */ typedef struct Hash Hash; typedef struct HashElem HashElem; /* A complete hash table is an instance of the following structure. ** The internals of this structure are intended to be opaque -- client ** code should not attempt to access or modify the fields of this structure ** directly. Change this structure only by using the routines below. ** However, some of the "procedures" and "functions" for modifying and ** accessing this structure are really macros, so we can't really make ** this structure opaque. ** ** All elements of the hash table are on a single doubly-linked list. ** Hash.first points to the head of this list. ** ** There are Hash.htsize buckets. Each bucket points to a spot in ** the global doubly-linked list. The contents of the bucket are the ** element pointed to plus the next _ht.count-1 elements in the list. ** ** Hash.htsize and Hash.ht may be zero. In that case lookup is done ** by a linear search of the global list. For small tables, the ** Hash.ht table is never allocated because if there are few elements ** in the table, it is faster to do a linear search than to manage ** the hash table. */ struct Hash { unsigned int htsize; /* Number of buckets in the hash table */ unsigned int count; /* Number of entries in this table */ HashElem *first; /* The first element of the array */ struct _ht { /* the hash table */ unsigned int count; /* Number of entries with this hash */ HashElem *chain; /* Pointer to first entry with this hash */ } *ht; }; /* Each element in the hash table is an instance of the following ** structure. All elements are stored on a single doubly-linked list. ** ** Again, this structure is intended to be opaque, but it can't really ** be opaque because it is used by macros. */ struct HashElem { HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ const char *pKey; /* Key associated with this element */ }; /* ** Access routines. To delete, insert a NULL pointer. */ SQLITE_PRIVATE void sqlite3HashInit(Hash*); SQLITE_PRIVATE void *sqlite3HashInsert(Hash*, const char *pKey, void *pData); SQLITE_PRIVATE void *sqlite3HashFind(const Hash*, const char *pKey); SQLITE_PRIVATE void sqlite3HashClear(Hash*); /* ** Macros for looping over all elements of a hash table. The idiom is ** like this: ** ** Hash h; ** HashElem *p; ** ... ** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){ ** SomeStructure *pData = sqliteHashData(p); ** // do something with pData ** } */ #define sqliteHashFirst(H) ((H)->first) #define sqliteHashNext(E) ((E)->next) #define sqliteHashData(E) ((E)->data) /* #define sqliteHashKey(E) ((E)->pKey) // NOT USED */ /* #define sqliteHashKeysize(E) ((E)->nKey) // NOT USED */ /* ** Number of entries in a hash table */ #define sqliteHashCount(H) ((H)->count) #endif /* SQLITE_HASH_H */ /************** End of hash.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include parse.h in the middle of sqliteInt.h *****************/ /************** Begin file parse.h *******************************************/ #define TK_SEMI 1 #define TK_EXPLAIN 2 #define TK_QUERY 3 #define TK_PLAN 4 #define TK_BEGIN 5 #define TK_TRANSACTION 6 #define TK_DEFERRED 7 #define TK_IMMEDIATE 8 #define TK_EXCLUSIVE 9 #define TK_COMMIT 10 #define TK_END 11 #define TK_ROLLBACK 12 #define TK_SAVEPOINT 13 #define TK_RELEASE 14 #define TK_TO 15 #define TK_TABLE 16 #define TK_CREATE 17 #define TK_IF 18 #define TK_NOT 19 #define TK_EXISTS 20 #define TK_TEMP 21 #define TK_LP 22 #define TK_RP 23 #define TK_AS 24 #define TK_COMMA 25 #define TK_WITHOUT 26 #define TK_ABORT 27 #define TK_ACTION 28 #define TK_AFTER 29 #define TK_ANALYZE 30 #define TK_ASC 31 #define TK_ATTACH 32 #define TK_BEFORE 33 #define TK_BY 34 #define TK_CASCADE 35 #define TK_CAST 36 #define TK_CONFLICT 37 #define TK_DATABASE 38 #define TK_DESC 39 #define TK_DETACH 40 #define TK_EACH 41 #define TK_FAIL 42 #define TK_OR 43 #define TK_AND 44 #define TK_IS 45 #define TK_MATCH 46 #define TK_LIKE_KW 47 #define TK_BETWEEN 48 #define TK_IN 49 #define TK_ISNULL 50 #define TK_NOTNULL 51 #define TK_NE 52 #define TK_EQ 53 #define TK_GT 54 #define TK_LE 55 #define TK_LT 56 #define TK_GE 57 #define TK_ESCAPE 58 #define TK_ID 59 #define TK_COLUMNKW 60 #define TK_DO 61 #define TK_FOR 62 #define TK_IGNORE 63 #define TK_INITIALLY 64 #define TK_INSTEAD 65 #define TK_NO 66 #define TK_KEY 67 #define TK_OF 68 #define TK_OFFSET 69 #define TK_PRAGMA 70 #define TK_RAISE 71 #define TK_RECURSIVE 72 #define TK_REPLACE 73 #define TK_RESTRICT 74 #define TK_ROW 75 #define TK_ROWS 76 #define TK_TRIGGER 77 #define TK_VACUUM 78 #define TK_VIEW 79 #define TK_VIRTUAL 80 #define TK_WITH 81 #define TK_NULLS 82 #define TK_FIRST 83 #define TK_LAST 84 #define TK_CURRENT 85 #define TK_FOLLOWING 86 #define TK_PARTITION 87 #define TK_PRECEDING 88 #define TK_RANGE 89 #define TK_UNBOUNDED 90 #define TK_EXCLUDE 91 #define TK_GROUPS 92 #define TK_OTHERS 93 #define TK_TIES 94 #define TK_GENERATED 95 #define TK_ALWAYS 96 #define TK_MATERIALIZED 97 #define TK_REINDEX 98 #define TK_RENAME 99 #define TK_CTIME_KW 100 #define TK_ANY 101 #define TK_BITAND 102 #define TK_BITOR 103 #define TK_LSHIFT 104 #define TK_RSHIFT 105 #define TK_PLUS 106 #define TK_MINUS 107 #define TK_STAR 108 #define TK_SLASH 109 #define TK_REM 110 #define TK_CONCAT 111 #define TK_PTR 112 #define TK_COLLATE 113 #define TK_BITNOT 114 #define TK_ON 115 #define TK_INDEXED 116 #define TK_STRING 117 #define TK_JOIN_KW 118 #define TK_CONSTRAINT 119 #define TK_DEFAULT 120 #define TK_NULL 121 #define TK_PRIMARY 122 #define TK_UNIQUE 123 #define TK_CHECK 124 #define TK_REFERENCES 125 #define TK_AUTOINCR 126 #define TK_INSERT 127 #define TK_DELETE 128 #define TK_UPDATE 129 #define TK_SET 130 #define TK_DEFERRABLE 131 #define TK_FOREIGN 132 #define TK_DROP 133 #define TK_UNION 134 #define TK_ALL 135 #define TK_EXCEPT 136 #define TK_INTERSECT 137 #define TK_SELECT 138 #define TK_VALUES 139 #define TK_DISTINCT 140 #define TK_DOT 141 #define TK_FROM 142 #define TK_JOIN 143 #define TK_USING 144 #define TK_ORDER 145 #define TK_GROUP 146 #define TK_HAVING 147 #define TK_LIMIT 148 #define TK_WHERE 149 #define TK_RETURNING 150 #define TK_INTO 151 #define TK_NOTHING 152 #define TK_FLOAT 153 #define TK_BLOB 154 #define TK_INTEGER 155 #define TK_VARIABLE 156 #define TK_CASE 157 #define TK_WHEN 158 #define TK_THEN 159 #define TK_ELSE 160 #define TK_INDEX 161 #define TK_ALTER 162 #define TK_ADD 163 #define TK_WINDOW 164 #define TK_OVER 165 #define TK_FILTER 166 #define TK_COLUMN 167 #define TK_AGG_FUNCTION 168 #define TK_AGG_COLUMN 169 #define TK_TRUEFALSE 170 #define TK_ISNOT 171 #define TK_FUNCTION 172 #define TK_UMINUS 173 #define TK_UPLUS 174 #define TK_TRUTH 175 #define TK_REGISTER 176 #define TK_VECTOR 177 #define TK_SELECT_COLUMN 178 #define TK_IF_NULL_ROW 179 #define TK_ASTERISK 180 #define TK_SPAN 181 #define TK_ERROR 182 #define TK_SPACE 183 #define TK_ILLEGAL 184 /************** End of parse.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ #include #include #include #include #include /* ** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY. ** This allows better measurements of where memcpy() is used when running ** cachegrind. But this macro version of memcpy() is very slow so it ** should not be used in production. This is a performance measurement ** hack only. */ #ifdef SQLITE_INLINE_MEMCPY # define memcpy(D,S,N) {char*xxd=(char*)(D);const char*xxs=(const char*)(S);\ int xxn=(N);while(xxn-->0)*(xxd++)=*(xxs++);} #endif /* ** If compiling for a processor that lacks floating point support, ** substitute integer for floating-point */ #ifdef SQLITE_OMIT_FLOATING_POINT # define double sqlite_int64 # define float sqlite_int64 # define LONGDOUBLE_TYPE sqlite_int64 # ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50) # endif # define SQLITE_OMIT_DATETIME_FUNCS 1 # define SQLITE_OMIT_TRACE 1 # undef SQLITE_MIXED_ENDIAN_64BIT_FLOAT # undef SQLITE_HAVE_ISNAN #endif #ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (1e99) #endif /* ** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0 ** afterward. Having this macro allows us to cause the C compiler ** to omit code used by TEMP tables without messy #ifndef statements. */ #ifdef SQLITE_OMIT_TEMPDB #define OMIT_TEMPDB 1 #else #define OMIT_TEMPDB 0 #endif /* ** The "file format" number is an integer that is incremented whenever ** the VDBE-level file format changes. The following macros define the ** the default file format for new databases and the maximum file format ** that the library can read. */ #define SQLITE_MAX_FILE_FORMAT 4 #ifndef SQLITE_DEFAULT_FILE_FORMAT # define SQLITE_DEFAULT_FILE_FORMAT 4 #endif /* ** Determine whether triggers are recursive by default. This can be ** changed at run-time using a pragma. */ #ifndef SQLITE_DEFAULT_RECURSIVE_TRIGGERS # define SQLITE_DEFAULT_RECURSIVE_TRIGGERS 0 #endif /* ** Provide a default value for SQLITE_TEMP_STORE in case it is not specified ** on the command-line */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 #endif /* ** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if ** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it ** to zero. */ #if SQLITE_TEMP_STORE==3 || SQLITE_THREADSAFE==0 # undef SQLITE_MAX_WORKER_THREADS # define SQLITE_MAX_WORKER_THREADS 0 #endif #ifndef SQLITE_MAX_WORKER_THREADS # define SQLITE_MAX_WORKER_THREADS 8 #endif #ifndef SQLITE_DEFAULT_WORKER_THREADS # define SQLITE_DEFAULT_WORKER_THREADS 0 #endif #if SQLITE_DEFAULT_WORKER_THREADS>SQLITE_MAX_WORKER_THREADS # undef SQLITE_MAX_WORKER_THREADS # define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS #endif /* ** The default initial allocation for the pagecache when using separate ** pagecaches for each database connection. A positive number is the ** number of pages. A negative number N translations means that a buffer ** of -1024*N bytes is allocated and used for as many pages as it will hold. ** ** The default value of "20" was chosen to minimize the run-time of the ** speedtest1 test program with options: --shrink-memory --reprepare */ #ifndef SQLITE_DEFAULT_PCACHE_INITSZ # define SQLITE_DEFAULT_PCACHE_INITSZ 20 #endif /* ** Default value for the SQLITE_CONFIG_SORTERREF_SIZE option. */ #ifndef SQLITE_DEFAULT_SORTERREF_SIZE # define SQLITE_DEFAULT_SORTERREF_SIZE 0x7fffffff #endif /* ** The compile-time options SQLITE_MMAP_READWRITE and ** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another. ** You must choose one or the other (or neither) but not both. */ #if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) #error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE #endif /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. */ #ifndef offsetof #define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD)) #endif /* ** Macros to compute minimum and maximum of two numbers. */ #ifndef MIN # define MIN(A,B) ((A)<(B)?(A):(B)) #endif #ifndef MAX # define MAX(A,B) ((A)>(B)?(A):(B)) #endif /* ** Swap two objects of type TYPE. */ #define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} /* ** Check to see if this machine uses EBCDIC. (Yes, believe it or ** not, there are still machines out there that use EBCDIC.) */ #if 'A' == '\301' # define SQLITE_EBCDIC 1 #else # define SQLITE_ASCII 1 #endif /* ** Integers of known sizes. These typedefs might change for architectures ** where the sizes very. Preprocessor macros are available so that the ** types can be conveniently redefined at compile-type. Like this: ** ** cc '-DUINTPTR_TYPE=long long int' ... */ #ifndef UINT32_TYPE # ifdef HAVE_UINT32_T # define UINT32_TYPE uint32_t # else # define UINT32_TYPE unsigned int # endif #endif #ifndef UINT16_TYPE # ifdef HAVE_UINT16_T # define UINT16_TYPE uint16_t # else # define UINT16_TYPE unsigned short int # endif #endif #ifndef INT16_TYPE # ifdef HAVE_INT16_T # define INT16_TYPE int16_t # else # define INT16_TYPE short int # endif #endif #ifndef UINT8_TYPE # ifdef HAVE_UINT8_T # define UINT8_TYPE uint8_t # else # define UINT8_TYPE unsigned char # endif #endif #ifndef INT8_TYPE # ifdef HAVE_INT8_T # define INT8_TYPE int8_t # else # define INT8_TYPE signed char # endif #endif #ifndef LONGDOUBLE_TYPE # define LONGDOUBLE_TYPE long double #endif typedef sqlite_int64 i64; /* 8-byte signed integer */ typedef sqlite_uint64 u64; /* 8-byte unsigned integer */ typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ typedef INT16_TYPE i16; /* 2-byte signed integer */ typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ typedef INT8_TYPE i8; /* 1-byte signed integer */ /* ** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value ** that can be stored in a u32 without loss of data. The value ** is 0x00000000ffffffff. But because of quirks of some compilers, we ** have to specify the value in the less intuitive manner shown: */ #define SQLITE_MAX_U32 ((((u64)1)<<32)-1) /* ** The datatype used to store estimates of the number of rows in a ** table or index. */ typedef u64 tRowcnt; /* ** Estimated quantities used for query planning are stored as 16-bit ** logarithms. For quantity X, the value stored is 10*log2(X). This ** gives a possible range of values of approximately 1.0e986 to 1e-986. ** But the allowed values are "grainy". Not every value is representable. ** For example, quantities 16 and 17 are both represented by a LogEst ** of 40. However, since LogEst quantities are suppose to be estimates, ** not exact values, this imprecision is not a problem. ** ** "LogEst" is short for "Logarithmic Estimate". ** ** Examples: ** 1 -> 0 20 -> 43 10000 -> 132 ** 2 -> 10 25 -> 46 25000 -> 146 ** 3 -> 16 100 -> 66 1000000 -> 199 ** 4 -> 20 1000 -> 99 1048576 -> 200 ** 10 -> 33 1024 -> 100 4294967296 -> 320 ** ** The LogEst can be negative to indicate fractional values. ** Examples: ** ** 0.5 -> -10 0.1 -> -33 0.0625 -> -40 */ typedef INT16_TYPE LogEst; /* ** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer */ #ifndef SQLITE_PTRSIZE # if defined(__SIZEOF_POINTER__) # define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(_M_ARM) || defined(__arm__) || defined(__x86) || \ (defined(__APPLE__) && defined(__POWERPC__)) || \ (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else # define SQLITE_PTRSIZE 8 # endif #endif /* The uptr type is an unsigned integer large enough to hold a pointer */ #if defined(HAVE_STDINT_H) typedef uintptr_t uptr; #elif SQLITE_PTRSIZE==4 typedef u32 uptr; #else typedef u64 uptr; #endif /* ** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to ** something between S (inclusive) and E (exclusive). ** ** In other words, S is a buffer and E is a pointer to the first byte after ** the end of buffer S. This macro returns true if P points to something ** contained within the buffer S. */ #define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E))) /* ** P is one byte past the end of a large buffer. Return true if a span of bytes ** between S..E crosses the end of that buffer. In other words, return true ** if the sub-buffer S..E-1 overflows the buffer whose last byte is P-1. ** ** S is the start of the span. E is one byte past the end of end of span. ** ** P ** |-----------------| FALSE ** |-------| ** S E ** ** P ** |-----------------| ** |-------| TRUE ** S E ** ** P ** |-----------------| ** |-------| FALSE ** S E */ #define SQLITE_OVERFLOW(P,S,E) (((uptr)(S)<(uptr)(P))&&((uptr)(E)>(uptr)(P))) /* ** Macros to determine whether the machine is big or little endian, ** and whether or not that determination is run-time or compile-time. ** ** For best performance, an attempt is made to guess at the byte-order ** using C-preprocessor macros. If that is unsuccessful, or if ** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined ** at run-time. ** ** If you are building SQLite on some obscure platform for which the ** following ifdef magic does not work, you can always include either: ** ** -DSQLITE_BYTEORDER=1234 ** ** or ** ** -DSQLITE_BYTEORDER=4321 ** ** to cause the build to work for little-endian or big-endian processors, ** respectively. */ #ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */ # if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ # define SQLITE_BYTEORDER 4321 # elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ # define SQLITE_BYTEORDER 1234 # elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1 # define SQLITE_BYTEORDER 4321 # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64) # define SQLITE_BYTEORDER 1234 # elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__) # define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 # endif #endif #if SQLITE_BYTEORDER==4321 # define SQLITE_BIGENDIAN 1 # define SQLITE_LITTLEENDIAN 0 # define SQLITE_UTF16NATIVE SQLITE_UTF16BE #elif SQLITE_BYTEORDER==1234 # define SQLITE_BIGENDIAN 0 # define SQLITE_LITTLEENDIAN 1 # define SQLITE_UTF16NATIVE SQLITE_UTF16LE #else # ifdef SQLITE_AMALGAMATION const int sqlite3one = 1; # else extern const int sqlite3one; # endif # define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0) # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1) # define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) #endif /* ** Constants for the largest and smallest possible 64-bit signed integers. ** These macros are designed to work correctly on both 32-bit and 64-bit ** compilers. */ #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) /* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. ** ** ROUND8() always does the rounding, for any argument. ** ** ROUND8P() assumes that the argument is already an integer number of ** pointers in size, and so it is a no-op on systems where the pointer ** size is 8. */ #define ROUND8(x) (((x)+7)&~7) #if SQLITE_PTRSIZE==8 # define ROUND8P(x) (x) #else # define ROUND8P(x) (((x)+7)&~7) #endif /* ** Round down to the nearest multiple of 8 */ #define ROUNDDOWN8(x) ((x)&~7) /* ** Assert that the pointer X is aligned to an 8-byte boundary. This ** macro is used only within assert() to verify that the code gets ** all alignment restrictions correct. ** ** Except, if SQLITE_4_BYTE_ALIGNED_MALLOC is defined, then the ** underlying malloc() implementation might return us 4-byte aligned ** pointers. In that case, only verify 4-byte alignment. */ #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0) #else # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) #endif /* ** Disable MMAP on platforms where it is known to not work */ #if defined(__OpenBSD__) || defined(__QNXNTO__) # undef SQLITE_MAX_MMAP_SIZE # define SQLITE_MAX_MMAP_SIZE 0 #endif /* ** Default maximum size of memory used by memory-mapped I/O in the VFS */ #ifdef __APPLE__ # include #endif #ifndef SQLITE_MAX_MMAP_SIZE # if defined(__linux__) \ || defined(_WIN32) \ || (defined(__APPLE__) && defined(__MACH__)) \ || defined(__sun) \ || defined(__FreeBSD__) \ || defined(__DragonFly__) # define SQLITE_MAX_MMAP_SIZE 0x7fff0000 /* 2147418112 */ # else # define SQLITE_MAX_MMAP_SIZE 0 # endif #endif /* ** The default MMAP_SIZE is zero on all platforms. Or, even if a larger ** default MMAP_SIZE is specified at compile-time, make sure that it does ** not exceed the maximum mmap size. */ #ifndef SQLITE_DEFAULT_MMAP_SIZE # define SQLITE_DEFAULT_MMAP_SIZE 0 #endif #if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE # undef SQLITE_DEFAULT_MMAP_SIZE # define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE #endif /* ** TREETRACE_ENABLED will be either 1 or 0 depending on whether or not ** the Abstract Syntax Tree tracing logic is turned on. */ #if !defined(SQLITE_AMALGAMATION) SQLITE_PRIVATE u32 sqlite3TreeTrace; #endif #if defined(SQLITE_DEBUG) \ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE) \ || defined(SQLITE_ENABLE_TREETRACE)) # define TREETRACE_ENABLED 1 # define TREETRACE(K,P,S,X) \ if(sqlite3TreeTrace&(K)) \ sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\ sqlite3DebugPrintf X #else # define TREETRACE(K,P,S,X) # define TREETRACE_ENABLED 0 #endif /* TREETRACE flag meanings: ** ** 0x00000001 Beginning and end of SELECT processing ** 0x00000002 WHERE clause processing ** 0x00000004 Query flattener ** 0x00000008 Result-set wildcard expansion ** 0x00000010 Query name resolution ** 0x00000020 Aggregate analysis ** 0x00000040 Window functions ** 0x00000080 Generated column names ** 0x00000100 Move HAVING terms into WHERE ** 0x00000200 Count-of-view optimization ** 0x00000400 Compound SELECT processing ** 0x00000800 Drop superfluous ORDER BY ** 0x00001000 LEFT JOIN simplifies to JOIN ** 0x00002000 Constant propagation ** 0x00004000 Push-down optimization ** 0x00008000 After all FROM-clause analysis ** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing ** 0x00020000 Transform DISTINCT into GROUP BY ** 0x00040000 SELECT tree dump after all code has been generated */ /* ** Macros for "wheretrace" */ SQLITE_PRIVATE u32 sqlite3WhereTrace; #if defined(SQLITE_DEBUG) \ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) # define WHERETRACE(K,X) if(sqlite3WhereTrace&(K)) sqlite3DebugPrintf X # define WHERETRACE_ENABLED 1 #else # define WHERETRACE(K,X) #endif /* ** Bits for the sqlite3WhereTrace mask: ** ** (---any--) Top-level block structure ** 0x-------F High-level debug messages ** 0x----FFF- More detail ** 0xFFFF---- Low-level debug messages ** ** 0x00000001 Code generation ** 0x00000002 Solver ** 0x00000004 Solver costs ** 0x00000008 WhereLoop inserts ** ** 0x00000010 Display sqlite3_index_info xBestIndex calls ** 0x00000020 Range an equality scan metrics ** 0x00000040 IN operator decisions ** 0x00000080 WhereLoop cost adjustements ** 0x00000100 ** 0x00000200 Covering index decisions ** 0x00000400 OR optimization ** 0x00000800 Index scanner ** 0x00001000 More details associated with code generation ** 0x00002000 ** 0x00004000 Show all WHERE terms at key points ** 0x00008000 Show the full SELECT statement at key places ** ** 0x00010000 Show more detail when printing WHERE terms ** 0x00020000 Show WHERE terms returned from whereScanNext() */ /* ** An instance of the following structure is used to store the busy-handler ** callback for a given sqlite handle. ** ** The sqlite.busyHandler member of the sqlite struct contains the busy ** callback for the database handle. Each pager opened via the sqlite ** handle is passed a pointer to sqlite.busyHandler. The busy-handler ** callback is currently invoked only from within pager.c. */ typedef struct BusyHandler BusyHandler; struct BusyHandler { int (*xBusyHandler)(void *,int); /* The busy callback */ void *pBusyArg; /* First arg to busy callback */ int nBusy; /* Incremented with each busy call */ }; /* ** Name of table that holds the database schema. ** ** The PREFERRED names are used wherever possible. But LEGACY is also ** used for backwards compatibility. ** ** 1. Queries can use either the PREFERRED or the LEGACY names ** 2. The sqlite3_set_authorizer() callback uses the LEGACY name ** 3. The PRAGMA table_list statement uses the PREFERRED name ** ** The LEGACY names are stored in the internal symbol hash table ** in support of (2). Names are translated using sqlite3PreferredTableName() ** for (3). The sqlite3FindTable() function takes care of translating ** names for (1). ** ** Note that "sqlite_temp_schema" can also be called "temp.sqlite_schema". */ #define LEGACY_SCHEMA_TABLE "sqlite_master" #define LEGACY_TEMP_SCHEMA_TABLE "sqlite_temp_master" #define PREFERRED_SCHEMA_TABLE "sqlite_schema" #define PREFERRED_TEMP_SCHEMA_TABLE "sqlite_temp_schema" /* ** The root-page of the schema table. */ #define SCHEMA_ROOT 1 /* ** The name of the schema table. The name is different for TEMP. */ #define SCHEMA_TABLE(x) \ ((!OMIT_TEMPDB)&&(x==1)?LEGACY_TEMP_SCHEMA_TABLE:LEGACY_SCHEMA_TABLE) /* ** A convenience macro that returns the number of elements in ** an array. */ #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) /* ** Determine if the argument is a power of two */ #define IsPowerOfTwo(X) (((X)&((X)-1))==0) /* ** The following value as a destructor means to use sqlite3DbFree(). ** The sqlite3DbFree() routine requires two parameters instead of the ** one parameter that destructors normally want. So we have to introduce ** this magic value that the code knows to handle differently. Any ** pointer will work here as long as it is distinct from SQLITE_STATIC ** and SQLITE_TRANSIENT. */ #define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomClear) /* ** When SQLITE_OMIT_WSD is defined, it means that the target platform does ** not support Writable Static Data (WSD) such as global and static variables. ** All variables must either be on the stack or dynamically allocated from ** the heap. When WSD is unsupported, the variable declarations scattered ** throughout the SQLite code must become constants instead. The SQLITE_WSD ** macro is used for this purpose. And instead of referencing the variable ** directly, we use its constant as a key to lookup the run-time allocated ** buffer that holds real variable. The constant is also the initializer ** for the run-time allocated buffer. ** ** In the usual case where WSD is supported, the SQLITE_WSD and GLOBAL ** macros become no-ops and have zero performance impact. */ #ifdef SQLITE_OMIT_WSD #define SQLITE_WSD const #define GLOBAL(t,v) (*(t*)sqlite3_wsd_find((void*)&(v), sizeof(v))) #define sqlite3GlobalConfig GLOBAL(struct Sqlite3Config, sqlite3Config) SQLITE_API int sqlite3_wsd_init(int N, int J); SQLITE_API void *sqlite3_wsd_find(void *K, int L); #else #define SQLITE_WSD #define GLOBAL(t,v) v #define sqlite3GlobalConfig sqlite3Config #endif /* ** The following macros are used to suppress compiler warnings and to ** make it clear to human readers when a function parameter is deliberately ** left unused within the body of a function. This usually happens when ** a function is called via a function pointer. For example the ** implementation of an SQL aggregate step callback may not use the ** parameter indicating the number of arguments passed to the aggregate, ** if it knows that this is enforced elsewhere. ** ** When a function parameter is not used at all within the body of a function, ** it is generally named "NotUsed" or "NotUsed2" to make things even clearer. ** However, these macros may also be used to suppress warnings related to ** parameters that may or may not be used depending on compilation options. ** For example those parameters only used in assert() statements. In these ** cases the parameters are named as per the usual conventions. */ #define UNUSED_PARAMETER(x) (void)(x) #define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y) /* ** Forward references to structures */ typedef struct AggInfo AggInfo; typedef struct AuthContext AuthContext; typedef struct AutoincInfo AutoincInfo; typedef struct Bitvec Bitvec; typedef struct CollSeq CollSeq; typedef struct Column Column; typedef struct Cte Cte; typedef struct CteUse CteUse; typedef struct Db Db; typedef struct DbClientData DbClientData; typedef struct DbFixer DbFixer; typedef struct Schema Schema; typedef struct Expr Expr; typedef struct ExprList ExprList; typedef struct FKey FKey; typedef struct FpDecode FpDecode; typedef struct FuncDestructor FuncDestructor; typedef struct FuncDef FuncDef; typedef struct FuncDefHash FuncDefHash; typedef struct IdList IdList; typedef struct Index Index; typedef struct IndexedExpr IndexedExpr; typedef struct IndexSample IndexSample; typedef struct KeyClass KeyClass; typedef struct KeyInfo KeyInfo; typedef struct Lookaside Lookaside; typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; typedef struct OnOrUsing OnOrUsing; typedef struct Parse Parse; typedef struct ParseCleanup ParseCleanup; typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; typedef struct RCStr RCStr; typedef struct RenameToken RenameToken; typedef struct Returning Returning; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; typedef struct SrcItem SrcItem; typedef struct SrcList SrcList; typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; typedef struct TreeView TreeView; typedef struct Trigger Trigger; typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; typedef struct UnpackedRecord UnpackedRecord; typedef struct Upsert Upsert; typedef struct VTable VTable; typedef struct VtabCtx VtabCtx; typedef struct Walker Walker; typedef struct WhereInfo WhereInfo; typedef struct Window Window; typedef struct With With; /* ** The bitmask datatype defined below is used for various optimizations. ** ** Changing this from a 64-bit to a 32-bit type limits the number of ** tables in a join to 32 instead of 64. But it also reduces the size ** of the library by 738 bytes on ix86. */ #ifdef SQLITE_BITMASK_TYPE typedef SQLITE_BITMASK_TYPE Bitmask; #else typedef u64 Bitmask; #endif /* ** The number of bits in a Bitmask. "BMS" means "BitMask Size". */ #define BMS ((int)(sizeof(Bitmask)*8)) /* ** A bit in a Bitmask */ #define MASKBIT(n) (((Bitmask)1)<<(n)) #define MASKBIT64(n) (((u64)1)<<(n)) #define MASKBIT32(n) (((unsigned int)1)<<(n)) #define SMASKBIT32(n) ((n)<=31?((unsigned int)1)<<(n):0) #define ALLBITS ((Bitmask)-1) #define TOPBIT (((Bitmask)1)<<(BMS-1)) /* A VList object records a mapping between parameters/variables/wildcards ** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer ** variable number associated with that parameter. See the format description ** on the sqlite3VListAdd() routine for more information. A VList is really ** just an array of integers. */ typedef int VList; /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque ** pointer types (i.e. FuncDef) defined above. */ /************** Include os.h in the middle of sqliteInt.h ********************/ /************** Begin file os.h **********************************************/ /* ** 2001 September 16 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This header file (together with is companion C source-code file ** "os.c") attempt to abstract the underlying operating system so that ** the SQLite library will work on both POSIX and windows systems. ** ** This header file is #include-ed by sqliteInt.h and thus ends up ** being included by every source file. */ #ifndef _SQLITE_OS_H_ #define _SQLITE_OS_H_ /* ** Attempt to automatically detect the operating system and setup the ** necessary pre-processor macros for it. */ /************** Include os_setup.h in the middle of os.h *********************/ /************** Begin file os_setup.h ****************************************/ /* ** 2013 November 25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains pre-processor directives related to operating system ** detection and/or setup. */ #ifndef SQLITE_OS_SETUP_H #define SQLITE_OS_SETUP_H /* ** Figure out if we are dealing with Unix, Windows, or some other operating ** system. ** ** After the following block of preprocess macros, all of ** ** SQLITE_OS_KV ** SQLITE_OS_OTHER ** SQLITE_OS_UNIX ** SQLITE_OS_WIN ** ** will defined to either 1 or 0. One of them will be 1. The others will be 0. ** If none of the macros are initially defined, then select either ** SQLITE_OS_UNIX or SQLITE_OS_WIN depending on the target platform. ** ** If SQLITE_OS_OTHER=1 is specified at compile-time, then the application ** must provide its own VFS implementation together with sqlite3_os_init() ** and sqlite3_os_end() routines. */ #if !defined(SQLITE_OS_KV) && !defined(SQLITE_OS_OTHER) && \ !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_WIN) # if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \ defined(__MINGW32__) || defined(__BORLANDC__) # define SQLITE_OS_WIN 1 # define SQLITE_OS_UNIX 0 # else # define SQLITE_OS_WIN 0 # define SQLITE_OS_UNIX 1 # endif #endif #if SQLITE_OS_OTHER+1>1 # undef SQLITE_OS_KV # define SQLITE_OS_KV 0 # undef SQLITE_OS_UNIX # define SQLITE_OS_UNIX 0 # undef SQLITE_OS_WIN # define SQLITE_OS_WIN 0 #endif #if SQLITE_OS_KV+1>1 # undef SQLITE_OS_OTHER # define SQLITE_OS_OTHER 0 # undef SQLITE_OS_UNIX # define SQLITE_OS_UNIX 0 # undef SQLITE_OS_WIN # define SQLITE_OS_WIN 0 # define SQLITE_OMIT_LOAD_EXTENSION 1 # define SQLITE_OMIT_WAL 1 # define SQLITE_OMIT_DEPRECATED 1 # undef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 3 /* Always use memory for temporary storage */ # define SQLITE_DQS 0 # define SQLITE_OMIT_SHARED_CACHE 1 # define SQLITE_OMIT_AUTOINIT 1 #endif #if SQLITE_OS_UNIX+1>1 # undef SQLITE_OS_KV # define SQLITE_OS_KV 0 # undef SQLITE_OS_OTHER # define SQLITE_OS_OTHER 0 # undef SQLITE_OS_WIN # define SQLITE_OS_WIN 0 #endif #if SQLITE_OS_WIN+1>1 # undef SQLITE_OS_KV # define SQLITE_OS_KV 0 # undef SQLITE_OS_OTHER # define SQLITE_OS_OTHER 0 # undef SQLITE_OS_UNIX # define SQLITE_OS_UNIX 0 #endif #endif /* SQLITE_OS_SETUP_H */ /************** End of os_setup.h ********************************************/ /************** Continuing where we left off in os.h *************************/ /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ #ifndef SET_FULLSYNC # define SET_FULLSYNC(x,y) #endif /* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h */ #ifndef SQLITE_MAX_PATHLEN # define SQLITE_MAX_PATHLEN FILENAME_MAX #endif /* Maximum number of symlinks that will be resolved while trying to ** expand a filename in xFullPathname() in the VFS. */ #ifndef SQLITE_MAX_SYMLINK # define SQLITE_MAX_SYMLINK 200 #endif /* ** The default size of a disk sector */ #ifndef SQLITE_DEFAULT_SECTOR_SIZE # define SQLITE_DEFAULT_SECTOR_SIZE 4096 #endif /* ** Temporary files are named starting with this prefix followed by 16 random ** alphanumeric characters, and no file extension. They are stored in the ** OS's standard temporary file directory, and are deleted prior to exit. ** If sqlite is being embedded in another program, you may wish to change the ** prefix to reflect your program's name, so that if your program exits ** prematurely, old temporary files can be easily identified. This can be done ** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line. ** ** 2006-10-31: The default prefix used to be "sqlite_". But then ** Mcafee started using SQLite in their anti-virus product and it ** started putting files with the "sqlite" name in the c:/temp folder. ** This annoyed many windows users. Those users would then do a ** Google search for "sqlite", find the telephone numbers of the ** developers and call to wake them up at night and complain. ** For this reason, the default name prefix is changed to be "sqlite" ** spelled backwards. So the temp files are still identified, but ** anybody smart enough to figure out the code is also likely smart ** enough to know that calling the developer will not help get rid ** of the file. */ #ifndef SQLITE_TEMP_FILE_PREFIX # define SQLITE_TEMP_FILE_PREFIX "etilqs_" #endif /* ** The following values may be passed as the second argument to ** sqlite3OsLock(). The various locks exhibit the following semantics: ** ** SHARED: Any number of processes may hold a SHARED lock simultaneously. ** RESERVED: A single process may hold a RESERVED lock on a file at ** any time. Other processes may hold and obtain new SHARED locks. ** PENDING: A single process may hold a PENDING lock on a file at ** any one time. Existing SHARED locks may persist, but no new ** SHARED locks may be obtained by other processes. ** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks. ** ** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a ** process that requests an EXCLUSIVE lock may actually obtain a PENDING ** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to ** sqlite3OsLock(). */ #define NO_LOCK 0 #define SHARED_LOCK 1 #define RESERVED_LOCK 2 #define PENDING_LOCK 3 #define EXCLUSIVE_LOCK 4 /* ** File Locking Notes: (Mostly about windows but also some info for Unix) ** ** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because ** those functions are not available. So we use only LockFile() and ** UnlockFile(). ** ** LockFile() prevents not just writing but also reading by other processes. ** A SHARED_LOCK is obtained by locking a single randomly-chosen ** byte out of a specific range of bytes. The lock byte is obtained at ** random so two separate readers can probably access the file at the ** same time, unless they are unlucky and choose the same lock byte. ** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range. ** There can only be one writer. A RESERVED_LOCK is obtained by locking ** a single byte of the file that is designated as the reserved lock byte. ** A PENDING_LOCK is obtained by locking a designated byte different from ** the RESERVED_LOCK byte. ** ** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available, ** which means we can use reader/writer locks. When reader/writer locks ** are used, the lock is placed on the same range of bytes that is used ** for probabilistic locking in Win95/98/ME. Hence, the locking scheme ** will support two or more Win95 readers or two or more WinNT readers. ** But a single Win95 reader will lock out all WinNT readers and a single ** WinNT reader will lock out all other Win95 readers. ** ** The following #defines specify the range of bytes used for locking. ** SHARED_SIZE is the number of bytes available in the pool from which ** a random byte is selected for a shared lock. The pool of bytes for ** shared locks begins at SHARED_FIRST. ** ** The same locking strategy and ** byte ranges are used for Unix. This leaves open the possibility of having ** clients on win95, winNT, and unix all talking to the same shared file ** and all locking correctly. To do so would require that samba (or whatever ** tool is being used for file sharing) implements locks correctly between ** windows and unix. I'm guessing that isn't likely to happen, but by ** using the same locking range we are at least open to the possibility. ** ** Locking in windows is manditory. For this reason, we cannot store ** actual data in the bytes used for locking. The pager never allocates ** the pages involved in locking therefore. SHARED_SIZE is selected so ** that all locks will fit on a single page even at the minimum page size. ** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE ** is set high so that we don't have to allocate an unused page except ** for very large databases. But one should test the page skipping logic ** by setting PENDING_BYTE low and running the entire regression suite. ** ** Changing the value of PENDING_BYTE results in a subtly incompatible ** file format. Depending on how it is changed, you might not notice ** the incompatibility right away, even running a full regression test. ** The default location of PENDING_BYTE is the first byte past the ** 1GB boundary. ** */ #ifdef SQLITE_OMIT_WSD # define PENDING_BYTE (0x40000000) #else # define PENDING_BYTE sqlite3PendingByte #endif #define RESERVED_BYTE (PENDING_BYTE+1) #define SHARED_FIRST (PENDING_BYTE+2) #define SHARED_SIZE 510 /* ** Wrapper around OS specific sqlite3_os_init() function. */ SQLITE_PRIVATE int sqlite3OsInit(void); /* ** Functions for accessing sqlite3_file methods */ SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*); SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset); SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size); SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int); SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize); SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int); SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int); SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut); SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*); SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*); #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id); #ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int); SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int); #endif /* SQLITE_OMIT_WAL */ SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **); SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *); /* ** Functions for accessing sqlite3_vfs methods */ SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int); SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut); SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *); #ifndef SQLITE_OMIT_LOAD_EXTENSION SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *); SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *); SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void); SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *); #endif /* SQLITE_OMIT_LOAD_EXTENSION */ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *); SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int); SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*); SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*); /* ** Convenience functions for opening and closing files using ** sqlite3_malloc() to obtain space for the file-handle structure. */ SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*); SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *); #endif /* _SQLITE_OS_H_ */ /************** End of os.h **************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include pager.h in the middle of sqliteInt.h *****************/ /************** Begin file pager.h *******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. */ #ifndef SQLITE_PAGER_H #define SQLITE_PAGER_H /* ** Default maximum size for persistent journal files. A negative ** value means no limit. This value may be overridden using the ** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit". */ #ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1 #endif /* ** The type used to represent a page number. The first page in a file ** is called page 1. 0 is used to represent "not a page". */ typedef u32 Pgno; /* ** Each open file is managed by a separate instance of the "Pager" structure. */ typedef struct Pager Pager; /* ** Handle type for pages. */ typedef struct PgHdr DbPage; /* ** Page number PAGER_SJ_PGNO is never used in an SQLite database (it is ** reserved for working around a windows/posix incompatibility). It is ** used in the journal to signify that the remainder of the journal file ** is devoted to storing a super-journal name - there are no more pages to ** roll back. See comments for function writeSuperJournal() in pager.c ** for details. */ #define PAGER_SJ_PGNO_COMPUTED(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) #define PAGER_SJ_PGNO(x) ((x)->lckPgno) /* ** Allowed values for the flags parameter to sqlite3PagerOpen(). ** ** NOTE: These values must match the corresponding BTREE_ values in btree.h. */ #define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ #define PAGER_MEMORY 0x0002 /* In-memory database */ /* ** Valid values for the second argument to sqlite3PagerLockingMode(). */ #define PAGER_LOCKINGMODE_QUERY -1 #define PAGER_LOCKINGMODE_NORMAL 0 #define PAGER_LOCKINGMODE_EXCLUSIVE 1 /* ** Numeric constants that encode the journalmode. ** ** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY) ** are exposed in the API via the "PRAGMA journal_mode" command and ** therefore cannot be changed without a compatibility break. */ #define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */ #define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */ #define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */ #define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ #define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */ #define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ #define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ /* ** Flags that make up the mask passed to sqlite3PagerGet(). */ #define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */ #define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */ /* ** Flags for sqlite3PagerSetFlags() ** ** Value constraints (enforced via assert()): ** PAGER_FULLFSYNC == SQLITE_FullFSync ** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync ** PAGER_CACHE_SPILL == SQLITE_CacheSpill */ #define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */ #define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */ #define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */ #define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */ #define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */ #define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */ #define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */ #define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */ #define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */ /* ** The remainder of this file contains the declarations of the functions ** that make up the Pager sub-system API. See source code comments for ** a detailed description of each routine. */ /* Open and close a Pager connection. */ SQLITE_PRIVATE int sqlite3PagerOpen( sqlite3_vfs*, Pager **ppPager, const char*, int, int, int, void(*)(DbPage*) ); SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*); SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno); SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int); SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64); SQLITE_PRIVATE void sqlite3PagerShrink(Pager*); SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned); SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int); SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int); SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*); SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*); SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64); SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*); SQLITE_PRIVATE int sqlite3PagerFlush(Pager*); /* Functions used to obtain and release page references. */ SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); SQLITE_PRIVATE void sqlite3PagerRef(DbPage*); SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*); SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*); SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*); /* Operations on page references. */ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*); SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*); SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int); SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*); SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *); SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *); /* Functions used to manage pager transactions and savepoints. */ SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*); SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int); SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int); SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*); SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper); SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*); SQLITE_PRIVATE int sqlite3PagerRollback(Pager*); SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n); SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager); #ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*); SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*); # ifdef SQLITE_ENABLE_SNAPSHOT SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot); SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot); SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot); SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager); # endif #endif #if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT) SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager*, int); SQLITE_PRIVATE void sqlite3PagerWalDb(Pager*, sqlite3*); #else # define sqlite3PagerWalWriteLock(y,z) SQLITE_OK # define sqlite3PagerWalDb(x,y) #endif #ifdef SQLITE_DIRECT_OVERFLOW_READ SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno); #endif #ifdef SQLITE_ENABLE_ZIPVFS SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager); #endif /* Functions used to query pager state and configuration. */ SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*); SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*); #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*); #endif SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*); SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager*, int); SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*); SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*); SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, u64*); SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*); SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16); /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*); #endif #ifdef SQLITE_TEST SQLITE_PRIVATE int *sqlite3PagerStats(Pager*); SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); void disable_simulated_io_errors(void); void enable_simulated_io_errors(void); #else # define disable_simulated_io_errors() # define enable_simulated_io_errors() #endif #if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL) SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager*); #endif #endif /* SQLITE_PAGER_H */ /************** End of pager.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include btree.h in the middle of sqliteInt.h *****************/ /************** Begin file btree.h *******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. */ #ifndef SQLITE_BTREE_H #define SQLITE_BTREE_H /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. */ #define SQLITE_N_BTREE_META 16 /* ** If defined as non-zero, auto-vacuum is enabled by default. Otherwise ** it must be turned on for each database using "PRAGMA auto_vacuum = 1". */ #ifndef SQLITE_DEFAULT_AUTOVACUUM #define SQLITE_DEFAULT_AUTOVACUUM 0 #endif #define BTREE_AUTOVACUUM_NONE 0 /* Do not do auto-vacuum */ #define BTREE_AUTOVACUUM_FULL 1 /* Do full auto-vacuum */ #define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */ /* ** Forward declarations of structure */ typedef struct Btree Btree; typedef struct BtCursor BtCursor; typedef struct BtShared BtShared; typedef struct BtreePayload BtreePayload; SQLITE_PRIVATE int sqlite3BtreeOpen( sqlite3_vfs *pVfs, /* VFS to use with this b-tree */ const char *zFilename, /* Name of database file to open */ sqlite3 *db, /* Associated database connection */ Btree **ppBtree, /* Return open Btree* here */ int flags, /* Flags */ int vfsFlags /* Flags passed through to VFS open */ ); /* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the ** following values. ** ** NOTE: These values must match the corresponding PAGER_ values in ** pager.h. */ #define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ #define BTREE_MEMORY 2 /* This is an in-memory DB */ #define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */ SQLITE_PRIVATE int sqlite3BtreeClose(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree*,int); #if SQLITE_MAX_MMAP_SIZE>0 SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); #endif SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned); SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*); SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree*,Pgno); SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree*); SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree*); SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p); SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int); SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *); SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int,int*); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char*); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int); SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*); SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int); SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags); SQLITE_PRIVATE int sqlite3BtreeTxnState(Btree*); SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*); SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree); #ifndef SQLITE_OMIT_SHARED_CACHE SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock); #endif /* Savepoints are named, nestable SQL transactions mostly implemented */ /* in vdbe.c and pager.c See https://sqlite.org/lang_savepoint.html */ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *, int, int); /* "Checkpoint" only refers to WAL. See https://sqlite.org/wal.html#ckpt */ #ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *); SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *); SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *); SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *); /* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR ** of the flags shown below. ** ** Every SQLite table must have either BTREE_INTKEY or BTREE_BLOBKEY set. ** With BTREE_INTKEY, the table key is a 64-bit integer and arbitrary data ** is stored in the leaves. (BTREE_INTKEY is used for SQL tables.) With ** BTREE_BLOBKEY, the key is an arbitrary BLOB and no content is stored ** anywhere - the key is the content. (BTREE_BLOBKEY is used for SQL ** indices.) */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, i64*); SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree*, int, int); SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p); /* ** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta ** should be one of the following values. The integer values are assigned ** to constants so that the offset of the corresponding field in an ** SQLite database header may be found using the following formula: ** ** offset = 36 + (idx * 4) ** ** For example, the free-page-count field is located at byte offset 36 of ** the database file header. The incr-vacuum-flag field is located at ** byte offset 64 (== 36+4*7). ** ** The BTREE_DATA_VERSION value is not really a value stored in the header. ** It is a read-only number computed by the pager. But we merge it with ** the header value access routines since its access pattern is the same. ** Call it a "virtual meta value". */ #define BTREE_FREE_PAGE_COUNT 0 #define BTREE_SCHEMA_VERSION 1 #define BTREE_FILE_FORMAT 2 #define BTREE_DEFAULT_CACHE_SIZE 3 #define BTREE_LARGEST_ROOT_PAGE 4 #define BTREE_TEXT_ENCODING 5 #define BTREE_USER_VERSION 6 #define BTREE_INCR_VACUUM 7 #define BTREE_APPLICATION_ID 8 #define BTREE_DATA_VERSION 15 /* A virtual meta-value */ /* ** Kinds of hints that can be passed into the sqlite3BtreeCursorHint() ** interface. ** ** BTREE_HINT_RANGE (arguments: Expr*, Mem*) ** ** The first argument is an Expr* (which is guaranteed to be constant for ** the lifetime of the cursor) that defines constraints on which rows ** might be fetched with this cursor. The Expr* tree may contain ** TK_REGISTER nodes that refer to values stored in the array of registers ** passed as the second parameter. In other words, if Expr.op==TK_REGISTER ** then the value of the node is the value in Mem[pExpr.iTable]. Any ** TK_COLUMN node in the expression tree refers to the Expr.iColumn-th ** column of the b-tree of the cursor. The Expr tree will not contain ** any function calls nor subqueries nor references to b-trees other than ** the cursor being hinted. ** ** The design of the _RANGE hint is aid b-tree implementations that try ** to prefetch content from remote machines - to provide those ** implementations with limits on what needs to be prefetched and thereby ** reduce network bandwidth. ** ** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by ** standard SQLite. The other hints are provided for extensions that use ** the SQLite parser and code generator but substitute their own storage ** engine. */ #define BTREE_HINT_RANGE 0 /* Range constraints on queries */ /* ** Values that may be OR'd together to form the argument to the ** BTREE_HINT_FLAGS hint for sqlite3BtreeCursorHint(): ** ** The BTREE_BULKLOAD flag is set on index cursors when the index is going ** to be filled with content that is already in sorted order. ** ** The BTREE_SEEK_EQ flag is set on cursors that will get OP_SeekGE or ** OP_SeekLE opcodes for a range search, but where the range of entries ** selected will all have the same key. In other words, the cursor will ** be used only for equality key searches. ** */ #define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */ #define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */ /* ** Flags passed as the third argument to sqlite3BtreeCursor(). ** ** For read-only cursors the wrFlag argument is always zero. For read-write ** cursors it may be set to either (BTREE_WRCSR|BTREE_FORDELETE) or just ** (BTREE_WRCSR). If the BTREE_FORDELETE bit is set, then the cursor will ** only be used by SQLite for the following: ** ** * to seek to and then delete specific entries, and/or ** ** * to read values that will be used to create keys that other ** BTREE_FORDELETE cursors will seek to and delete. ** ** The BTREE_FORDELETE flag is an optimization hint. It is not used by ** by this, the native b-tree engine of SQLite, but it is available to ** alternative storage engines that might be substituted in place of this ** b-tree system. For alternative storage engines in which a delete of ** the main table row automatically deletes corresponding index rows, ** the FORDELETE flag hint allows those alternative storage engines to ** skip a lot of work. Namely: FORDELETE cursors may treat all SEEK ** and DELETE operations as no-ops, and any READ operation against a ** FORDELETE cursor may return a null row: 0x01 0x00. */ #define BTREE_WRCSR 0x00000004 /* read-write cursor */ #define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */ SQLITE_PRIVATE int sqlite3BtreeCursor( Btree*, /* BTree containing table to open */ Pgno iTable, /* Index of root page */ int wrFlag, /* 1 for writing. 0 for read-only */ struct KeyInfo*, /* First argument to compare function */ BtCursor *pCursor /* Space to write cursor structure */ ); SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void); SQLITE_PRIVATE int sqlite3BtreeCursorSize(void); SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); #ifdef SQLITE_ENABLE_CURSOR_HINTS SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...); #endif SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeTableMoveto( BtCursor*, i64 intKey, int bias, int *pRes ); SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( BtCursor*, UnpackedRecord *pUnKey, int *pRes ); SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*); SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags); /* Allowed flags for sqlite3BtreeDelete() and sqlite3BtreeInsert() */ #define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */ #define BTREE_AUXDELETE 0x04 /* not the primary delete operation */ #define BTREE_APPEND 0x08 /* Insert is likely an append */ #define BTREE_PREFORMAT 0x80 /* Inserted data is a preformated cell */ /* An instance of the BtreePayload object describes the content of a single ** entry in either an index or table btree. ** ** Index btrees (used for indexes and also WITHOUT ROWID tables) contain ** an arbitrary key and no data. These btrees have pKey,nKey set to the ** key and the pData,nData,nZero fields are uninitialized. The aMem,nMem ** fields give an array of Mem objects that are a decomposition of the key. ** The nMem field might be zero, indicating that no decomposition is available. ** ** Table btrees (used for rowid tables) contain an integer rowid used as ** the key and passed in the nKey field. The pKey field is zero. ** pData,nData hold the content of the new entry. nZero extra zero bytes ** are appended to the end of the content when constructing the entry. ** The aMem,nMem fields are uninitialized for table btrees. ** ** Field usage summary: ** ** Table BTrees Index Btrees ** ** pKey always NULL encoded key ** nKey the ROWID length of pKey ** pData data not used ** aMem not used decomposed key value ** nMem not used entries in aMem ** nData length of pData not used ** nZero extra zeros after pData not used ** ** This object is used to pass information into sqlite3BtreeInsert(). The ** same information used to be passed as five separate parameters. But placing ** the information into this object helps to keep the interface more ** organized and understandable, and it also helps the resulting code to ** run a little faster by using fewer registers for parameter passing. */ struct BtreePayload { const void *pKey; /* Key content for indexes. NULL for tables */ sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */ const void *pData; /* Data for tables. */ sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */ u16 nMem; /* Number of aMem[] value. Might be zero */ int nData; /* Size of pData. 0 if none. */ int nZero; /* Extra zero data appended after pData,nData */ }; SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int flags, int seekResult); SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags); SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags); SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor*); SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*); SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*); SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( sqlite3 *db, /* Database connection that is running the check */ Btree *p, /* The btree to be checked */ Pgno *aRoot, /* An array of root pages numbers for individual trees */ int nRoot, /* Number of entries in aRoot[] */ int mxErr, /* Stop reporting errors after this many */ int *pnErr, /* OUT: Write number of errors seen to this variable */ char **pzOut /* OUT: Write the error message string here */ ); SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*); #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *); #endif SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *); SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask); SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt); SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void); #ifdef SQLITE_DEBUG SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree*); #else # define sqlite3BtreeSeekCount(X) 0 #endif #ifndef NDEBUG SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*); #endif SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*); #ifdef SQLITE_TEST SQLITE_PRIVATE int sqlite3BtreeCursorInfo(BtCursor*, int*, int); SQLITE_PRIVATE void sqlite3BtreeCursorList(Btree*); #endif #ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64); SQLITE_PRIVATE void sqlite3BtreeClearCache(Btree*); /* ** If we are not using shared cache, then there is no need to ** use mutexes to access the BtShared structures. So make the ** Enter and Leave procedures no-ops. */ #ifndef SQLITE_OMIT_SHARED_CACHE SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*); SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*); SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*); SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree*); #else # define sqlite3BtreeEnter(X) # define sqlite3BtreeEnterAll(X) # define sqlite3BtreeSharable(X) 0 # define sqlite3BtreeEnterCursor(X) # define sqlite3BtreeConnectionCount(X) 1 #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*); SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*); #ifndef NDEBUG /* These routines are used inside assert() statements only. */ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree*); SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*); SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); #endif #else # define sqlite3BtreeLeave(X) # define sqlite3BtreeLeaveCursor(X) # define sqlite3BtreeLeaveAll(X) # define sqlite3BtreeHoldsMutex(X) 1 # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif #endif /* SQLITE_BTREE_H */ /************** End of btree.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include vdbe.h in the middle of sqliteInt.h ******************/ /************** Begin file vdbe.h ********************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. */ #ifndef SQLITE_VDBE_H #define SQLITE_VDBE_H /* #include */ /* ** A single VDBE is an opaque structure named "Vdbe". Only routines ** in the source file sqliteVdbe.c are allowed to see the insides ** of this structure. */ typedef struct Vdbe Vdbe; /* ** The names of the following types declared in vdbeInt.h are required ** for the VdbeOp definition. */ typedef struct sqlite3_value Mem; typedef struct SubProgram SubProgram; /* ** A single instruction of the virtual machine has an opcode ** and as many as three operands. The instruction is recorded ** as an instance of the following structure: */ struct VdbeOp { u8 opcode; /* What operation to perform */ signed char p4type; /* One of the P4_xxx constants for p4 */ u16 p5; /* Fifth parameter is an unsigned 16-bit integer */ int p1; /* First operand */ int p2; /* Second parameter (often the jump destination) */ int p3; /* The third parameter */ union p4union { /* fourth parameter */ int i; /* Integer value if p4type==P4_INT32 */ void *p; /* Generic pointer */ char *z; /* Pointer to data for string (char array) types */ i64 *pI64; /* Used when p4type is P4_INT64 */ double *pReal; /* Used when p4type is P4_REAL */ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ u32 *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ Table *pTab; /* Used when p4type is P4_TABLE */ #ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */ #endif #ifdef SQLITE_VDBE_COVERAGE u32 iSrcLine; /* Source-code line that generated this opcode ** with flags in the upper 8 bits */ #endif #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE) u64 nExec; u64 nCycle; #endif }; typedef struct VdbeOp VdbeOp; /* ** A sub-routine used to implement a trigger program. */ struct SubProgram { VdbeOp *aOp; /* Array of opcodes for sub-program */ int nOp; /* Elements in aOp[] */ int nMem; /* Number of memory cells required */ int nCsr; /* Number of cursors required */ u8 *aOnce; /* Array of OP_Once flags */ void *token; /* id that may be used to recursive triggers */ SubProgram *pNext; /* Next sub-program already visited */ }; /* ** A smaller version of VdbeOp used for the VdbeAddOpList() function because ** it takes up less space. */ struct VdbeOpList { u8 opcode; /* What operation to perform */ signed char p1; /* First operand */ signed char p2; /* Second parameter (often the jump destination) */ signed char p3; /* Third parameter */ }; typedef struct VdbeOpList VdbeOpList; /* ** Allowed values of VdbeOp.p4type */ #define P4_NOTUSED 0 /* The P4 parameter is not used */ #define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ #define P4_STATIC (-1) /* Pointer to a static string */ #define P4_COLLSEQ (-2) /* P4 is a pointer to a CollSeq structure */ #define P4_INT32 (-3) /* P4 is a 32-bit signed integer */ #define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */ #define P4_TABLE (-5) /* P4 is a pointer to a Table structure */ /* Above do not own any resources. Must free those below */ #define P4_FREE_IF_LE (-6) #define P4_DYNAMIC (-6) /* Pointer to memory from sqliteMalloc() */ #define P4_FUNCDEF (-7) /* P4 is a pointer to a FuncDef structure */ #define P4_KEYINFO (-8) /* P4 is a pointer to a KeyInfo structure */ #define P4_EXPR (-9) /* P4 is a pointer to an Expr tree */ #define P4_MEM (-10) /* P4 is a pointer to a Mem* structure */ #define P4_VTAB (-11) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */ #define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */ #define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 #define P5_ConstraintUnique 2 #define P5_ConstraintCheck 3 #define P5_ConstraintFK 4 /* ** The Vdbe.aColName array contains 5n Mem structures, where n is the ** number of columns of data returned by the statement. */ #define COLNAME_NAME 0 #define COLNAME_DECLTYPE 1 #define COLNAME_DATABASE 2 #define COLNAME_TABLE 3 #define COLNAME_COLUMN 4 #ifdef SQLITE_ENABLE_COLUMN_METADATA # define COLNAME_N 5 /* Number of COLNAME_xxx symbols */ #else # ifdef SQLITE_OMIT_DECLTYPE # define COLNAME_N 1 /* Store only the name */ # else # define COLNAME_N 2 /* Store the name and decltype */ # endif #endif /* ** The following macro converts a label returned by sqlite3VdbeMakeLabel() ** into an index into the Parse.aLabel[] array that contains the resolved ** address of that label. */ #define ADDR(X) (~(X)) /* ** The makefile scans the vdbe.c source file and creates the "opcodes.h" ** header file that defines a number for each opcode used by the VDBE. */ /************** Include opcodes.h in the middle of vdbe.h ********************/ /************** Begin file opcodes.h *****************************************/ /* Automatically generated. Do not edit */ /* See the tool/mkopcodeh.tcl script for details */ #define OP_Savepoint 0 #define OP_AutoCommit 1 #define OP_Transaction 2 #define OP_Checkpoint 3 #define OP_JournalMode 4 #define OP_Vacuum 5 #define OP_VFilter 6 /* jump, synopsis: iplan=r[P3] zplan='P4' */ #define OP_VUpdate 7 /* synopsis: data=r[P3@P2] */ #define OP_Init 8 /* jump, synopsis: Start at P2 */ #define OP_Goto 9 /* jump */ #define OP_Gosub 10 /* jump */ #define OP_InitCoroutine 11 /* jump */ #define OP_Yield 12 /* jump */ #define OP_MustBeInt 13 /* jump */ #define OP_Jump 14 /* jump */ #define OP_Once 15 /* jump */ #define OP_If 16 /* jump */ #define OP_IfNot 17 /* jump */ #define OP_IsType 18 /* jump, synopsis: if typeof(P1.P3) in P5 goto P2 */ #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ #define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ #define OP_SeekLT 21 /* jump, synopsis: key=r[P3@P4] */ #define OP_SeekLE 22 /* jump, synopsis: key=r[P3@P4] */ #define OP_SeekGE 23 /* jump, synopsis: key=r[P3@P4] */ #define OP_SeekGT 24 /* jump, synopsis: key=r[P3@P4] */ #define OP_IfNotOpen 25 /* jump, synopsis: if( !csr[P1] ) goto P2 */ #define OP_IfNoHope 26 /* jump, synopsis: key=r[P3@P4] */ #define OP_NoConflict 27 /* jump, synopsis: key=r[P3@P4] */ #define OP_NotFound 28 /* jump, synopsis: key=r[P3@P4] */ #define OP_Found 29 /* jump, synopsis: key=r[P3@P4] */ #define OP_SeekRowid 30 /* jump, synopsis: intkey=r[P3] */ #define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */ #define OP_Last 32 /* jump */ #define OP_IfSmaller 33 /* jump */ #define OP_SorterSort 34 /* jump */ #define OP_Sort 35 /* jump */ #define OP_Rewind 36 /* jump */ #define OP_SorterNext 37 /* jump */ #define OP_Prev 38 /* jump */ #define OP_Next 39 /* jump */ #define OP_IdxLE 40 /* jump, synopsis: key=r[P3@P4] */ #define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */ #define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */ #define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ #define OP_IdxGE 45 /* jump, synopsis: key=r[P3@P4] */ #define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */ #define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ #define OP_Program 48 /* jump */ #define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ #define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ #define OP_Eq 53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */ #define OP_Gt 54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */ #define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */ #define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ #define OP_ElseEq 58 /* jump, same as TK_ESCAPE */ #define OP_IfPos 59 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ #define OP_IfNotZero 60 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ #define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */ #define OP_IncrVacuum 62 /* jump */ #define OP_VNext 63 /* jump */ #define OP_Filter 64 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ #define OP_PureFunc 65 /* synopsis: r[P3]=func(r[P2@NP]) */ #define OP_Function 66 /* synopsis: r[P3]=func(r[P2@NP]) */ #define OP_Return 67 #define OP_EndCoroutine 68 #define OP_HaltIfNull 69 /* synopsis: if r[P3]=null halt */ #define OP_Halt 70 #define OP_Integer 71 /* synopsis: r[P2]=P1 */ #define OP_Int64 72 /* synopsis: r[P2]=P4 */ #define OP_String 73 /* synopsis: r[P2]='P4' (len=P1) */ #define OP_BeginSubrtn 74 /* synopsis: r[P2]=NULL */ #define OP_Null 75 /* synopsis: r[P2..P3]=NULL */ #define OP_SoftNull 76 /* synopsis: r[P1]=NULL */ #define OP_Blob 77 /* synopsis: r[P2]=P4 (len=P1) */ #define OP_Variable 78 /* synopsis: r[P2]=parameter(P1,P4) */ #define OP_Move 79 /* synopsis: r[P2@P3]=r[P1@P3] */ #define OP_Copy 80 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ #define OP_SCopy 81 /* synopsis: r[P2]=r[P1] */ #define OP_IntCopy 82 /* synopsis: r[P2]=r[P1] */ #define OP_FkCheck 83 #define OP_ResultRow 84 /* synopsis: output=r[P1@P2] */ #define OP_CollSeq 85 #define OP_AddImm 86 /* synopsis: r[P1]=r[P1]+P2 */ #define OP_RealAffinity 87 #define OP_Cast 88 /* synopsis: affinity(r[P1]) */ #define OP_Permutation 89 #define OP_Compare 90 /* synopsis: r[P1@P3] <-> r[P2@P3] */ #define OP_IsTrue 91 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ #define OP_ZeroOrNull 92 /* synopsis: r[P2] = 0 OR NULL */ #define OP_Offset 93 /* synopsis: r[P3] = sqlite_offset(P1) */ #define OP_Column 94 /* synopsis: r[P3]=PX cursor P1 column P2 */ #define OP_TypeCheck 95 /* synopsis: typecheck(r[P1@P2]) */ #define OP_Affinity 96 /* synopsis: affinity(r[P1@P2]) */ #define OP_MakeRecord 97 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ #define OP_Count 98 /* synopsis: r[P2]=count() */ #define OP_ReadCookie 99 #define OP_SetCookie 100 #define OP_ReopenIdx 101 /* synopsis: root=P2 iDb=P3 */ #define OP_BitAnd 102 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 103 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 104 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ #define OP_Add 106 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ #define OP_Subtract 107 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ #define OP_Multiply 108 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ #define OP_Divide 109 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ #define OP_Remainder 110 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ #define OP_Concat 111 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ #define OP_OpenRead 112 /* synopsis: root=P2 iDb=P3 */ #define OP_OpenWrite 113 /* synopsis: root=P2 iDb=P3 */ #define OP_BitNot 114 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ #define OP_OpenDup 115 #define OP_OpenAutoindex 116 /* synopsis: nColumn=P2 */ #define OP_String8 117 /* same as TK_STRING, synopsis: r[P2]='P4' */ #define OP_OpenEphemeral 118 /* synopsis: nColumn=P2 */ #define OP_SorterOpen 119 #define OP_SequenceTest 120 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ #define OP_OpenPseudo 121 /* synopsis: P3 columns in r[P2] */ #define OP_Close 122 #define OP_ColumnsUsed 123 #define OP_SeekScan 124 /* synopsis: Scan-ahead up to P1 rows */ #define OP_SeekHit 125 /* synopsis: set P2<=seekHit<=P3 */ #define OP_Sequence 126 /* synopsis: r[P2]=cursor[P1].ctr++ */ #define OP_NewRowid 127 /* synopsis: r[P2]=rowid */ #define OP_Insert 128 /* synopsis: intkey=r[P3] data=r[P2] */ #define OP_RowCell 129 #define OP_Delete 130 #define OP_ResetCount 131 #define OP_SorterCompare 132 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ #define OP_SorterData 133 /* synopsis: r[P2]=data */ #define OP_RowData 134 /* synopsis: r[P2]=data */ #define OP_Rowid 135 /* synopsis: r[P2]=PX rowid of P1 */ #define OP_NullRow 136 #define OP_SeekEnd 137 #define OP_IdxInsert 138 /* synopsis: key=r[P2] */ #define OP_SorterInsert 139 /* synopsis: key=r[P2] */ #define OP_IdxDelete 140 /* synopsis: key=r[P2@P3] */ #define OP_DeferredSeek 141 /* synopsis: Move P3 to P1.rowid if needed */ #define OP_IdxRowid 142 /* synopsis: r[P2]=rowid */ #define OP_FinishSeek 143 #define OP_Destroy 144 #define OP_Clear 145 #define OP_ResetSorter 146 #define OP_CreateBtree 147 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ #define OP_SqlExec 148 #define OP_ParseSchema 149 #define OP_LoadAnalysis 150 #define OP_DropTable 151 #define OP_DropIndex 152 #define OP_Real 153 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ #define OP_DropTrigger 154 #define OP_IntegrityCk 155 #define OP_RowSetAdd 156 /* synopsis: rowset(P1)=r[P2] */ #define OP_Param 157 #define OP_FkCounter 158 /* synopsis: fkctr[P1]+=P2 */ #define OP_MemMax 159 /* synopsis: r[P1]=max(r[P1],r[P2]) */ #define OP_OffsetLimit 160 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ #define OP_AggInverse 161 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ #define OP_AggStep 162 /* synopsis: accum=r[P3] step(r[P2@P5]) */ #define OP_AggStep1 163 /* synopsis: accum=r[P3] step(r[P2@P5]) */ #define OP_AggValue 164 /* synopsis: r[P3]=value N=P2 */ #define OP_AggFinal 165 /* synopsis: accum=r[P1] N=P2 */ #define OP_Expire 166 #define OP_CursorLock 167 #define OP_CursorUnlock 168 #define OP_TableLock 169 /* synopsis: iDb=P1 root=P2 write=P3 */ #define OP_VBegin 170 #define OP_VCreate 171 #define OP_VDestroy 172 #define OP_VOpen 173 #define OP_VCheck 174 #define OP_VInitIn 175 /* synopsis: r[P2]=ValueList(P1,P3) */ #define OP_VColumn 176 /* synopsis: r[P3]=vcolumn(P2) */ #define OP_VRename 177 #define OP_Pagecount 178 #define OP_MaxPgcnt 179 #define OP_ClrSubtype 180 /* synopsis: r[P1].subtype = 0 */ #define OP_GetSubtype 181 /* synopsis: r[P2] = r[P1].subtype */ #define OP_SetSubtype 182 /* synopsis: r[P2].subtype = r[P1] */ #define OP_FilterAdd 183 /* synopsis: filter(P1) += key(P3@P4) */ #define OP_Trace 184 #define OP_CursorHint 185 #define OP_ReleaseReg 186 /* synopsis: release r[P1@P2] mask P3 */ #define OP_Noop 187 #define OP_Explain 188 #define OP_Abortable 189 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c ** are encoded into bitvectors as follows: */ #define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */ #define OPFLG_IN1 0x02 /* in1: P1 is an input */ #define OPFLG_IN2 0x04 /* in2: P2 is an input */ #define OPFLG_IN3 0x08 /* in3: P3 is an input */ #define OPFLG_OUT2 0x10 /* out2: P2 is an output */ #define OPFLG_OUT3 0x20 /* out3: P3 is an output */ #define OPFLG_NCYCLE 0x40 /* ncycle:Cycles count against P1 */ #define OPFLG_INITIALIZER {\ /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x41, 0x00,\ /* 8 */ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01,\ /* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x49, 0x49, 0x49,\ /* 24 */ 0x49, 0x01, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,\ /* 32 */ 0x41, 0x01, 0x41, 0x41, 0x41, 0x01, 0x41, 0x41,\ /* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x23, 0x0b,\ /* 48 */ 0x01, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ /* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x41,\ /* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\ /* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\ /* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\ /* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40, 0x00,\ /* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x26, 0x26,\ /* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ /* 112 */ 0x40, 0x00, 0x12, 0x40, 0x40, 0x10, 0x40, 0x00,\ /* 120 */ 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x10,\ /* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50,\ /* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\ /* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ /* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\ /* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\ /* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\ /* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} /* The resolve3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum ** JUMP opcode the better, so the mkopcodeh.tcl script that ** generated this include file strives to group all JUMP opcodes ** together near the beginning of the list. */ #define SQLITE_MX_JUMP_OPCODE 64 /* Maximum JUMP opcode */ /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ /* ** Additional non-public SQLITE_PREPARE_* flags */ #define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */ #define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */ /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*); SQLITE_PRIVATE Parse *sqlite3VdbeParser(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int); SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe*,int,const char*); SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...); SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall(Parse*,int,int,int,int,const FuncDef*,int); SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe*,int); #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N); SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p); #else # define sqlite3VdbeVerifyNoMallocRequired(A,B) # define sqlite3VdbeVerifyNoResultRow(A) #endif #if defined(SQLITE_DEBUG) SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int); SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn(Vdbe*,int,int,int); #else # define sqlite3VdbeVerifyAbortable(A,B) # define sqlite3VdbeNoJumpsOutsideSubrtn(A,B,C,D) #endif SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno); #ifndef SQLITE_OMIT_EXPLAIN SQLITE_PRIVATE int sqlite3VdbeExplain(Parse*,u8,const char*,...); SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse*); SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse*); # define ExplainQueryPlan(P) sqlite3VdbeExplain P # ifdef SQLITE_ENABLE_STMT_SCANSTATUS # define ExplainQueryPlan2(V,P) (V = sqlite3VdbeExplain P) # else # define ExplainQueryPlan2(V,P) ExplainQueryPlan(P) # endif # define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P) # define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P) #else # define ExplainQueryPlan(P) # define ExplainQueryPlan2(V,P) # define ExplainQueryPlanPop(P) # define ExplainQueryPlanParent(P) 0 # define sqlite3ExplainBreakpoint(A,B) /*no-op*/ #endif #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char*,const char*); #else # define sqlite3ExplainBreakpoint(A,B) /*no-op*/ #endif SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16); SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8); SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3); SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5); SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe*, int); SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr); SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr); SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(Parse*,int addr, int n, u32 mask, int); #else # define sqlite3VdbeReleaseRegisters(P,A,N,M,F) #endif SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type); SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetLastOp(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*); SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*); SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int); SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *, int); #endif SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*); SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*); SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, u8); #ifdef SQLITE_ENABLE_NORMALIZE SQLITE_PRIVATE void sqlite3VdbeAddDblquoteStr(sqlite3*,Vdbe*,const char*); SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString(Vdbe*,const char*); #endif SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*); SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int); #ifndef SQLITE_OMIT_TRACE SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); SQLITE_PRIVATE int sqlite3BlobCompare(const Mem*, const Mem*); SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int); SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*); typedef int (*RecordCompare)(int,const void*,UnpackedRecord*); SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); SQLITE_PRIVATE int sqlite3VdbeHasSubProgram(Vdbe*); SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); #ifdef SQLITE_ENABLE_BYTECODE_VTAB SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*); #endif /* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on ** each VDBE opcode. ** ** Use the SQLITE_ENABLE_MODULE_COMMENTS macro to see some extra no-op ** comments in VDBE programs that show key decision points in the code ** generator. */ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe*, const char*, ...); # define VdbeComment(X) sqlite3VdbeComment X SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...); # define VdbeNoopComment(X) sqlite3VdbeNoopComment X # ifdef SQLITE_ENABLE_MODULE_COMMENTS # define VdbeModuleComment(X) sqlite3VdbeNoopComment X # else # define VdbeModuleComment(X) # endif #else # define VdbeComment(X) # define VdbeNoopComment(X) # define VdbeModuleComment(X) #endif /* ** The VdbeCoverage macros are used to set a coverage testing point ** for VDBE branch instructions. The coverage testing points are line ** numbers in the sqlite3.c source file. VDBE branch coverage testing ** only works with an amalgamation build. That's ok since a VDBE branch ** coverage build designed for testing the test suite only. No application ** should ever ship with VDBE branch coverage measuring turned on. ** ** VdbeCoverage(v) // Mark the previously coded instruction ** // as a branch ** ** VdbeCoverageIf(v, conditional) // Mark previous if conditional true ** ** VdbeCoverageAlwaysTaken(v) // Previous branch is always taken ** ** VdbeCoverageNeverTaken(v) // Previous branch is never taken ** ** VdbeCoverageNeverNull(v) // Previous three-way branch is only ** // taken on the first two ways. The ** // NULL option is not possible ** ** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested ** // in distinguishing equal and not-equal. ** ** Every VDBE branch operation must be tagged with one of the macros above. ** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and ** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch() ** routine in vdbe.c, alerting the developer to the missed tag. ** ** During testing, the test application will invoke ** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback ** routine that is invoked as each bytecode branch is taken. The callback ** contains the sqlite3.c source line number of the VdbeCoverage macro and ** flags to indicate whether or not the branch was taken. The test application ** is responsible for keeping track of this and reporting byte-code branches ** that are never taken. ** ** See the VdbeBranchTaken() macro and vdbeTakeBranch() function in the ** vdbe.c source file for additional information. */ #ifdef SQLITE_VDBE_COVERAGE SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int); # define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__) # define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__) # define VdbeCoverageAlwaysTaken(v) \ sqlite3VdbeSetLineNumber(v,__LINE__|0x5000000); # define VdbeCoverageNeverTaken(v) \ sqlite3VdbeSetLineNumber(v,__LINE__|0x6000000); # define VdbeCoverageNeverNull(v) \ sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000); # define VdbeCoverageNeverNullIf(v,x) \ if(x)sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000); # define VdbeCoverageEqNe(v) \ sqlite3VdbeSetLineNumber(v,__LINE__|0x8000000); # define VDBE_OFFSET_LINENO(x) (__LINE__+x) #else # define VdbeCoverage(v) # define VdbeCoverageIf(v,x) # define VdbeCoverageAlwaysTaken(v) # define VdbeCoverageNeverTaken(v) # define VdbeCoverageNeverNull(v) # define VdbeCoverageNeverNullIf(v,x) # define VdbeCoverageEqNe(v) # define VDBE_OFFSET_LINENO(x) 0 #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); SQLITE_PRIVATE void sqlite3VdbeScanStatusRange(Vdbe*, int, int, int); SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(Vdbe*, int, int, int); #else # define sqlite3VdbeScanStatus(a,b,c,d,e,f) # define sqlite3VdbeScanStatusRange(a,b,c,d) # define sqlite3VdbeScanStatusCounters(a,b,c,d) #endif #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*); #endif #if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr); #endif #endif /* SQLITE_VDBE_H */ /************** End of vdbe.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include pcache.h in the middle of sqliteInt.h ****************/ /************** Begin file pcache.h ******************************************/ /* ** 2008 August 05 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. */ #ifndef _PCACHE_H_ typedef struct PgHdr PgHdr; typedef struct PCache PCache; /* ** Every page in the cache is controlled by an instance of the following ** structure. */ struct PgHdr { sqlite3_pcache_page *pPage; /* Pcache object page handle */ void *pData; /* Page data */ void *pExtra; /* Extra content */ PCache *pCache; /* PRIVATE: Cache that owns this page */ PgHdr *pDirty; /* Transient list of dirty sorted by pgno */ Pager *pPager; /* The pager this page is part of */ Pgno pgno; /* Page number for this page */ #ifdef SQLITE_CHECK_PAGES u32 pageHash; /* Hash of page content */ #endif u16 flags; /* PGHDR flags defined below */ /********************************************************************** ** Elements above, except pCache, are public. All that follow are ** private to pcache.c and should not be accessed by other modules. ** pCache is grouped with the public elements for efficiency. */ i64 nRef; /* Number of users of this page */ PgHdr *pDirtyNext; /* Next element in list of dirty pages */ PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */ /* NB: pDirtyNext and pDirtyPrev are undefined if the ** PgHdr object is not dirty */ }; /* Bit values for PgHdr.flags */ #define PGHDR_CLEAN 0x001 /* Page not on the PCache.pDirty list */ #define PGHDR_DIRTY 0x002 /* Page is on the PCache.pDirty list */ #define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */ #define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before ** writing this page to the database */ #define PGHDR_DONT_WRITE 0x010 /* Do not write content to disk */ #define PGHDR_MMAP 0x020 /* This is an mmap page object */ #define PGHDR_WAL_APPEND 0x040 /* Appended to wal file */ /* Initialize and shutdown the page cache subsystem */ SQLITE_PRIVATE int sqlite3PcacheInitialize(void); SQLITE_PRIVATE void sqlite3PcacheShutdown(void); /* Page cache buffer management: ** These routines implement SQLITE_CONFIG_PAGECACHE. */ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *, int sz, int n); /* Create a new pager cache. ** Under memory stress, invoke xStress to try to make pages clean. ** Only clean and unpinned pages can be reclaimed. */ SQLITE_PRIVATE int sqlite3PcacheOpen( int szPage, /* Size of every page */ int szExtra, /* Extra space associated with each page */ int bPurgeable, /* True if pages are on backing store */ int (*xStress)(void*, PgHdr*), /* Call to try to make pages clean */ void *pStress, /* Argument to xStress */ PCache *pToInit /* Preallocated space for the PCache */ ); /* Modify the page-size after the cache has been created. */ SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *, int); /* Return the size in bytes of a PCache object. Used to preallocate ** storage space. */ SQLITE_PRIVATE int sqlite3PcacheSize(void); /* One release per successful fetch. Page is pinned until released. ** Reference counted. */ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(PCache*, Pgno, int createFlag); SQLITE_PRIVATE int sqlite3PcacheFetchStress(PCache*, Pgno, sqlite3_pcache_page**); SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(PCache*, Pgno, sqlite3_pcache_page *pPage); SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr*); SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache */ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr*); /* Make sure page is marked dirty */ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr*); /* Mark a single page as clean */ SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */ SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache*); /* Change a page number. Used by incr-vacuum. */ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr*, Pgno); /* Remove all pages with pgno>x. Reset the cache if x==0 */ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache*, Pgno x); /* Get a list of all dirty pages in the cache, sorted by page number */ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache*); /* Reset and close the cache object */ SQLITE_PRIVATE void sqlite3PcacheClose(PCache*); /* Clear flags from pages of the page cache */ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *); /* Discard the contents of the cache */ SQLITE_PRIVATE void sqlite3PcacheClear(PCache*); /* Return the total number of outstanding page references */ SQLITE_PRIVATE i64 sqlite3PcacheRefCount(PCache*); /* Increment the reference count of an existing page */ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr*); SQLITE_PRIVATE i64 sqlite3PcachePageRefcount(PgHdr*); /* Return the total number of pages stored in the cache */ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*); #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* Iterate through all dirty pages currently stored in the cache. This ** interface is only available if SQLITE_CHECK_PAGES is defined when the ** library is built. */ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)); #endif #if defined(SQLITE_DEBUG) /* Check invariants on a PgHdr object */ SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr*); #endif /* Set and get the suggested cache-size for the specified pager-cache. ** ** If no global maximum is configured, then the system attempts to limit ** the total number of pages cached by purgeable pager-caches to the sum ** of the suggested cache-sizes. */ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *, int); #ifdef SQLITE_TEST SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *); #endif /* Set or get the suggested spill-size for the specified pager-cache. ** ** The spill-size is the minimum number of pages in cache before the cache ** will attempt to spill dirty pages by calling xStress. */ SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *, int); /* Free up as much memory as possible from the page cache */ SQLITE_PRIVATE void sqlite3PcacheShrink(PCache*); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* Try to return memory used by the pcache module to the main memory heap */ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int); #endif #ifdef SQLITE_TEST SQLITE_PRIVATE void sqlite3PcacheStats(int*,int*,int*,int*); #endif SQLITE_PRIVATE void sqlite3PCacheSetDefault(void); /* Return the header size */ SQLITE_PRIVATE int sqlite3HeaderSizePcache(void); SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void); /* Number of dirty pages as a percentage of the configured cache size */ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); #ifdef SQLITE_DIRECT_OVERFLOW_READ SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache); #endif #endif /* _PCACHE_H_ */ /************** End of pcache.h **********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include mutex.h in the middle of sqliteInt.h *****************/ /************** Begin file mutex.h *******************************************/ /* ** 2007 August 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains the common header for all mutex implementations. ** The sqliteInt.h header #includes this file so that it is available ** to all source files. We break it out in an effort to keep the code ** better organized. ** ** NOTE: source files should *not* #include this header file directly. ** Source files should #include the sqliteInt.h file and let that file ** include this one indirectly. */ /* ** Figure out what version of the code to use. The choices are ** ** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The ** mutexes implementation cannot be overridden ** at start-time. ** ** SQLITE_MUTEX_NOOP For single-threaded applications. No ** mutual exclusion is provided. But this ** implementation can be overridden at ** start-time. ** ** SQLITE_MUTEX_PTHREADS For multi-threaded applications on Unix. ** ** SQLITE_MUTEX_W32 For multi-threaded applications on Win32. */ #if !SQLITE_THREADSAFE # define SQLITE_MUTEX_OMIT #endif #if SQLITE_THREADSAFE && !defined(SQLITE_MUTEX_NOOP) # if SQLITE_OS_UNIX # define SQLITE_MUTEX_PTHREADS # elif SQLITE_OS_WIN # define SQLITE_MUTEX_W32 # else # define SQLITE_MUTEX_NOOP # endif #endif #ifdef SQLITE_MUTEX_OMIT /* ** If this is a no-op implementation, implement everything as macros. */ #define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8) #define sqlite3_mutex_free(X) #define sqlite3_mutex_enter(X) #define sqlite3_mutex_try(X) SQLITE_OK #define sqlite3_mutex_leave(X) #define sqlite3_mutex_held(X) ((void)(X),1) #define sqlite3_mutex_notheld(X) ((void)(X),1) #define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) #define sqlite3MutexInit() SQLITE_OK #define sqlite3MutexEnd() #define MUTEX_LOGIC(X) #else #define MUTEX_LOGIC(X) X SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); #endif /* defined(SQLITE_MUTEX_OMIT) */ /************** End of mutex.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /* The SQLITE_EXTRA_DURABLE compile-time option used to set the default ** synchronous setting to EXTRA. It is no longer supported. */ #ifdef SQLITE_EXTRA_DURABLE # warning Use SQLITE_DEFAULT_SYNCHRONOUS=3 instead of SQLITE_EXTRA_DURABLE # define SQLITE_DEFAULT_SYNCHRONOUS 3 #endif /* ** Default synchronous levels. ** ** Note that (for historical reasons) the PAGER_SYNCHRONOUS_* macros differ ** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1. ** ** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS ** OFF 1 0 ** NORMAL 2 1 ** FULL 3 2 ** EXTRA 4 3 ** ** The "PRAGMA synchronous" statement also uses the zero-based numbers. ** In other words, the zero-based numbers are used for all external interfaces ** and the one-based values are used internally. */ #ifndef SQLITE_DEFAULT_SYNCHRONOUS # define SQLITE_DEFAULT_SYNCHRONOUS 2 #endif #ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS # define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS #endif /* ** Each database file to be accessed by the system is an instance ** of the following structure. There are normally two of these structures ** in the sqlite.aDb[] array. aDb[0] is the main database file and ** aDb[1] is the database file used to hold temporary tables. Additional ** databases may be attached. */ struct Db { char *zDbSName; /* Name of this database. (schema name, not filename) */ Btree *pBt; /* The B*Tree structure for this database file */ u8 safety_level; /* How aggressive at syncing data to disk */ u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */ Schema *pSchema; /* Pointer to database schema (possibly shared) */ }; /* ** An instance of the following structure stores a database schema. ** ** Most Schema objects are associated with a Btree. The exception is ** the Schema for the TEMP database (sqlite3.aDb[1]) which is free-standing. ** In shared cache mode, a single Schema object can be shared by multiple ** Btrees that refer to the same underlying BtShared object. ** ** Schema objects are automatically deallocated when the last Btree that ** references them is destroyed. The TEMP Schema is manually freed by ** sqlite3_close(). * ** A thread must be holding a mutex on the corresponding Btree in order ** to access Schema content. This implies that the thread must also be ** holding a mutex on the sqlite3 connection pointer that owns the Btree. ** For a TEMP Schema, only the connection mutex is required. */ struct Schema { int schema_cookie; /* Database schema version number for this file */ int iGeneration; /* Generation counter. Incremented with each change */ Hash tblHash; /* All tables indexed by name */ Hash idxHash; /* All (named) indices indexed by name */ Hash trigHash; /* All triggers indexed by name */ Hash fkeyHash; /* All foreign keys by referenced table name */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ u16 schemaFlags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ }; /* ** These macros can be used to test, set, or clear bits in the ** Db.pSchema->flags field. */ #define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P)) #define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))!=0) #define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags|=(P) #define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags&=~(P) /* ** Allowed values for the DB.pSchema->flags field. ** ** The DB_SchemaLoaded flag is set after the database schema has been ** read into internal hash tables. ** ** DB_UnresetViews means that one or more views have column names that ** have been filled out. If the schema changes, these column names might ** changes and so the view will need to be reset. */ #define DB_SchemaLoaded 0x0001 /* The schema has been loaded */ #define DB_UnresetViews 0x0002 /* Some views have defined column names */ #define DB_ResetWanted 0x0008 /* Reset the schema when nSchemaLock==0 */ /* ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ #define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1) /* ** Lookaside malloc is a set of fixed-size buffers that can be used ** to satisfy small transient memory allocation requests for objects ** associated with a particular database connection. The use of ** lookaside malloc provides a significant performance enhancement ** (approx 10%) by avoiding numerous malloc/free requests while parsing ** SQL statements. ** ** The Lookaside structure holds configuration information about the ** lookaside malloc subsystem. Each available memory allocation in ** the lookaside subsystem is stored on a linked list of LookasideSlot ** objects. ** ** Lookaside allocations are only allowed for objects that are associated ** with a particular database connection. Hence, schema information cannot ** be stored in lookaside because in shared cache mode the schema information ** is shared by multiple database connections. Therefore, while parsing ** schema information, the Lookaside.bEnabled flag is cleared so that ** lookaside allocations are not used to construct the schema objects. ** ** New lookaside allocations are only allowed if bDisable==0. When ** bDisable is greater than zero, sz is set to zero which effectively ** disables lookaside without adding a new test for the bDisable flag ** in a performance-critical path. sz should be set by to szTrue whenever ** bDisable changes back to zero. ** ** Lookaside buffers are initially held on the pInit list. As they are ** used and freed, they are added back to the pFree list. New allocations ** come off of pFree first, then pInit as a fallback. This dual-list ** allows use to compute a high-water mark - the maximum number of allocations ** outstanding at any point in the past - by subtracting the number of ** allocations on the pInit list from the total number of allocations. ** ** Enhancement on 2019-12-12: Two-size-lookaside ** The default lookaside configuration is 100 slots of 1200 bytes each. ** The larger slot sizes are important for performance, but they waste ** a lot of space, as most lookaside allocations are less than 128 bytes. ** The two-size-lookaside enhancement breaks up the lookaside allocation ** into two pools: One of 128-byte slots and the other of the default size ** (1200-byte) slots. Allocations are filled from the small-pool first, ** failing over to the full-size pool if that does not work. Thus more ** lookaside slots are available while also using less memory. ** This enhancement can be omitted by compiling with ** SQLITE_OMIT_TWOSIZE_LOOKASIDE. */ struct Lookaside { u32 bDisable; /* Only operate the lookaside when zero */ u16 sz; /* Size of each buffer in bytes */ u16 szTrue; /* True value of sz, even if disabled */ u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */ u32 nSlot; /* Number of lookaside slots allocated */ u32 anStat[3]; /* 0: hits. 1: size misses. 2: full misses */ LookasideSlot *pInit; /* List of buffers not previously used */ LookasideSlot *pFree; /* List of available buffers */ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE LookasideSlot *pSmallInit; /* List of small buffers not previously used */ LookasideSlot *pSmallFree; /* List of available small buffers */ void *pMiddle; /* First byte past end of full-size buffers and ** the first byte of LOOKASIDE_SMALL buffers */ #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ void *pStart; /* First byte of available memory space */ void *pEnd; /* First byte past end of available space */ void *pTrueEnd; /* True value of pEnd, when db->pnBytesFreed!=0 */ }; struct LookasideSlot { LookasideSlot *pNext; /* Next buffer in the list of free buffers */ }; #define DisableLookaside db->lookaside.bDisable++;db->lookaside.sz=0 #define EnableLookaside db->lookaside.bDisable--;\ db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue /* Size of the smaller allocations in two-size lookaside */ #ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE # define LOOKASIDE_SMALL 0 #else # define LOOKASIDE_SMALL 128 #endif /* ** A hash table for built-in function definitions. (Application-defined ** functions use a regular table table from hash.h.) ** ** Hash each FuncDef structure into one of the FuncDefHash.a[] slots. ** Collisions are on the FuncDef.u.pHash chain. Use the SQLITE_FUNC_HASH() ** macro to compute a hash on the function name. */ #define SQLITE_FUNC_HASH_SZ 23 struct FuncDefHash { FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */ }; #define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ) #ifdef SQLITE_USER_AUTHENTICATION /* ** Information held in the "sqlite3" database connection object and used ** to manage user authentication. */ typedef struct sqlite3_userauth sqlite3_userauth; struct sqlite3_userauth { u8 authLevel; /* Current authentication level */ int nAuthPW; /* Size of the zAuthPW in bytes */ char *zAuthPW; /* Password used to authenticate */ char *zAuthUser; /* User name used to authenticate */ }; /* Allowed values for sqlite3_userauth.authLevel */ #define UAUTH_Unknown 0 /* Authentication not yet checked */ #define UAUTH_Fail 1 /* User authentication failed */ #define UAUTH_User 2 /* Authenticated as a normal user */ #define UAUTH_Admin 3 /* Authenticated as an administrator */ /* Functions used only by user authorization logic */ SQLITE_PRIVATE int sqlite3UserAuthTable(const char*); SQLITE_PRIVATE int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*); SQLITE_PRIVATE void sqlite3UserAuthInit(sqlite3*); SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); #endif /* SQLITE_USER_AUTHENTICATION */ /* ** typedef for the authorization callback function. */ #ifdef SQLITE_USER_AUTHENTICATION typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, const char*, const char*); #else typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, const char*); #endif #ifndef SQLITE_OMIT_DEPRECATED /* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing ** in the style of sqlite3_trace() */ #define SQLITE_TRACE_LEGACY 0x40 /* Use the legacy xTrace */ #define SQLITE_TRACE_XPROFILE 0x80 /* Use the legacy xProfile */ #else #define SQLITE_TRACE_LEGACY 0 #define SQLITE_TRACE_XPROFILE 0 #endif /* SQLITE_OMIT_DEPRECATED */ #define SQLITE_TRACE_NONLEGACY_MASK 0x0f /* Normal flags */ /* ** Maximum number of sqlite3.aDb[] entries. This is the number of attached ** databases plus 2 for "main" and "temp". */ #define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2) /* ** Each database connection is an instance of the following structure. */ struct sqlite3 { sqlite3_vfs *pVfs; /* OS Interface */ struct Vdbe *pVdbe; /* List of active virtual machines */ CollSeq *pDfltColl; /* BINARY collseq for the database encoding */ sqlite3_mutex *mutex; /* Connection mutex */ Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ u32 mDbFlags; /* flags recording internal state */ u64 flags; /* flags settable by pragmas. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 szMmap; /* Default mmap_size setting */ u32 nSchemaLock; /* Do not reset the schema when non-zero */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errByteOffset; /* Byte offset of error in SQL statement */ int errMask; /* & result codes with this before returning */ int iSysErrno; /* Errno value from last system error */ u32 dbOptFlags; /* Flags to enable/disable optimizations */ u8 enc; /* Text encoding */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ u8 bBenignMalloc; /* Do not require OOMs if true */ u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ u8 suppressErr; /* Do not issue error messages if true */ u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ u8 mTrace; /* zero or more SQLITE_TRACE flags */ u8 noSharedCache; /* True if no shared-cache backends */ u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ u8 eOpenState; /* Current condition of the connection */ int nextPagesize; /* Pagesize after VACUUM if >0 */ i64 nChange; /* Value returned by sqlite3_changes() */ i64 nTotalChange; /* Value returned by sqlite3_total_changes() */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ struct sqlite3InitInfo { /* Information used during initialization */ Pgno newTnum; /* Rootpage of table being initialized */ u8 iDb; /* Which db file is being initialized */ u8 busy; /* TRUE if currently initializing */ unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */ unsigned imposterTable : 1; /* Building an imposter table */ unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */ const char **azInit; /* "type", "name", and "tbl_name" columns */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ int nVdbeWrite; /* Number of active VDBEs that read and write */ int nVdbeExec; /* Number of nested calls to VdbeExec() */ int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ union { void (*xLegacy)(void*,const char*); /* mTrace==SQLITE_TRACE_LEGACY */ int (*xV2)(u32,void*,void*,void*); /* All other mTrace values */ } trace; void *pTraceArg; /* Argument to the trace function */ #ifndef SQLITE_OMIT_DEPRECATED void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ #endif void *pCommitArg; /* Argument to xCommitCallback() */ int (*xCommitCallback)(void*); /* Invoked at every commit. */ void *pRollbackArg; /* Argument to xRollbackCallback() */ void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); void *pAutovacPagesArg; /* Client argument to autovac_pages */ void (*xAutovacDestr)(void*); /* Destructor for pAutovacPAgesArg */ unsigned int (*xAutovacPages)(void*,const char*,u32,u32,u32); Parse *pParse; /* Current parse */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */ void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64 ); PreUpdate *pPreUpdate; /* Context for active pre-update callback */ #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifndef SQLITE_OMIT_WAL int (*xWalCallback)(void *, sqlite3 *, const char *, int); void *pWalArg; #endif void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); void *pCollNeededArg; sqlite3_value *pErr; /* Most recent error message */ union { volatile int isInterrupted; /* True if sqlite3_interrupt has been called */ double notUsed1; /* Spacer */ } u1; Lookaside lookaside; /* Lookaside malloc configuration */ #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth; /* Access authorization function */ void *pAuthArg; /* 1st argument to the access auth function */ #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ unsigned nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE int nVTrans; /* Allocated size of aVTrans */ Hash aModule; /* populated by sqlite3_create_module() */ VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ VTable **aVTrans; /* Virtual tables with open transactions */ VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ #endif Hash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ int nAnalysisLimit; /* Number of index rows to ANALYZE */ int busyTimeout; /* Busy handler timeout, in msec */ int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ DbClientData *pDbData; /* sqlite3_set_clientdata() content */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MAIN ** mutex, not by sqlite3.mutex. They are used by code in notify.c. ** ** When X.pUnlockConnection==Y, that means that X is waiting for Y to ** unlock so that it can proceed. ** ** When X.pBlockingConnection==Y, that means that something that X tried ** tried to do recently failed with an SQLITE_LOCKED error due to locks ** held by Y. */ sqlite3 *pBlockingConnection; /* Connection that caused SQLITE_LOCKED */ sqlite3 *pUnlockConnection; /* Connection to watch for unlock */ void *pUnlockArg; /* Argument to xUnlockNotify */ void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif #ifdef SQLITE_USER_AUTHENTICATION sqlite3_userauth auth; /* User authentication information */ #endif }; /* ** A macro to discover the encoding of a database. */ #define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) #define ENC(db) ((db)->enc) /* ** A u64 constant where the lower 32 bits are all zeros. Only the ** upper 32 bits are included in the argument. Necessary because some ** C-compilers still do not accept LL integer literals. */ #define HI(X) ((u64)(X)<<32) /* ** Possible values for the sqlite3.flags. ** ** Value constraints (enforced via assert()): ** SQLITE_FullFSync == PAGER_FULLFSYNC ** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC ** SQLITE_CacheSpill == PAGER_CACHE_SPILL */ #define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_SCHEMA */ #define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */ #define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */ #define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */ #define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */ #define SQLITE_CacheSpill 0x00000020 /* OK to spill pager cache */ #define SQLITE_ShortColNames 0x00000040 /* Show short columns names */ #define SQLITE_TrustedSchema 0x00000080 /* Allow unsafe functions and ** vtabs in the schema definition */ #define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */ /* result set is empty */ #define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */ #define SQLITE_StmtScanStatus 0x00000400 /* Enable stmt_scanstats() counters */ #define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */ #define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */ #define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */ #define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */ #define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */ #define SQLITE_LoadExtension 0x00010000 /* Enable load_extension */ #define SQLITE_LoadExtFunc 0x00020000 /* Enable load_extension() SQL func */ #define SQLITE_EnableTrigger 0x00040000 /* True to enable triggers */ #define SQLITE_DeferFKs 0x00080000 /* Defer all FK constraints */ #define SQLITE_QueryOnly 0x00100000 /* Disable database changes */ #define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */ #define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */ #define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/ #define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */ #define SQLITE_ResetDatabase 0x02000000 /* Reset the database */ #define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */ #define SQLITE_NoSchemaError 0x08000000 /* Do not report schema parse errors*/ #define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */ #define SQLITE_DqsDDL 0x20000000 /* dbl-quoted strings allowed in DDL*/ #define SQLITE_DqsDML 0x40000000 /* dbl-quoted strings allowed in DML*/ #define SQLITE_EnableView 0x80000000 /* Enable the use of views */ #define SQLITE_CountRows HI(0x00001) /* Count rows changed by INSERT, */ /* DELETE, or UPDATE and return */ /* the count using a callback. */ #define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */ #define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */ #define SQLITE_FkNoAction HI(0x00008) /* Treat all FK as NO ACTION */ /* Flags used only if debugging */ #ifdef SQLITE_DEBUG #define SQLITE_SqlTrace HI(0x0100000) /* Debug print SQL as it executes */ #define SQLITE_VdbeListing HI(0x0200000) /* Debug listings of VDBE progs */ #define SQLITE_VdbeTrace HI(0x0400000) /* True to trace VDBE execution */ #define SQLITE_VdbeAddopTrace HI(0x0800000) /* Trace sqlite3VdbeAddOp() calls */ #define SQLITE_VdbeEQP HI(0x1000000) /* Debug EXPLAIN QUERY PLAN */ #define SQLITE_ParserTrace HI(0x2000000) /* PRAGMA parser_trace=ON */ #endif /* ** Allowed values for sqlite3.mDbFlags */ #define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */ #define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */ #define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */ #define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */ #define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */ #define DBFLAG_InternalFunc 0x0020 /* Allow use of internal functions */ #define DBFLAG_EncodingFixed 0x0040 /* No longer possible to change enc. */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x00000001 /* Query flattening */ #define SQLITE_WindowFunc 0x00000002 /* Use xInverse for window functions */ #define SQLITE_GroupByOrder 0x00000004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x00000008 /* Constant factoring */ #define SQLITE_DistinctOpt 0x00000010 /* DISTINCT using indexes */ #define SQLITE_CoverIdxScan 0x00000020 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x00000040 /* ORDER BY of joins via index */ #define SQLITE_Transitive 0x00000080 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x00000100 /* Omit unused tables in joins */ #define SQLITE_CountOfView 0x00000200 /* The count-of-view optimization */ #define SQLITE_CursorHints 0x00000400 /* Add OP_CursorHint opcodes */ #define SQLITE_Stat4 0x00000800 /* Use STAT4 data */ /* TH3 expects this value ^^^^^^^^^^ to be 0x0000800. Don't change it */ #define SQLITE_PushDown 0x00001000 /* The push-down optimization */ #define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */ #define SQLITE_SkipScan 0x00004000 /* Skip-scans */ #define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */ #define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */ #define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */ #define SQLITE_OmitOrderBy 0x00040000 /* Omit pointless ORDER BY */ /* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */ #define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */ #define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */ #define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */ #define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */ #define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */ /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */ #define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */ #define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */ #define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */ #define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) #define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) /* ** Return true if it OK to factor constant expressions into the initialization ** code. The argument is a Parse object for the code generator. */ #define ConstFactorOk(P) ((P)->okConstFactor) /* Possible values for the sqlite3.eOpenState field. ** The numbers are randomly selected such that a minimum of three bits must ** change to convert any number to another or to zero */ #define SQLITE_STATE_OPEN 0x76 /* Database is open */ #define SQLITE_STATE_CLOSED 0xce /* Database is closed */ #define SQLITE_STATE_SICK 0xba /* Error and awaiting close */ #define SQLITE_STATE_BUSY 0x6d /* Database currently in use */ #define SQLITE_STATE_ERROR 0xd5 /* An SQLITE_MISUSE error occurred */ #define SQLITE_STATE_ZOMBIE 0xa7 /* Close with last statement close */ /* ** Each SQL function is defined by an instance of the following ** structure. For global built-in functions (ex: substr(), max(), count()) ** a pointer to this structure is held in the sqlite3BuiltinFunctions object. ** For per-connection application-defined functions, a pointer to this ** structure is held in the db->aHash hash table. ** ** The u.pHash field is used by the global built-ins. The u.pDestructor ** field is used by per-connection app-def functions. */ struct FuncDef { i8 nArg; /* Number of arguments. -1 means unlimited */ u32 funcFlags; /* Some combination of SQLITE_FUNC_* */ void *pUserData; /* User data parameter */ FuncDef *pNext; /* Next function with same name */ void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */ void (*xFinalize)(sqlite3_context*); /* Agg finalizer */ void (*xValue)(sqlite3_context*); /* Current agg value */ void (*xInverse)(sqlite3_context*,int,sqlite3_value**); /* inverse agg-step */ const char *zName; /* SQL name of the function. */ union { FuncDef *pHash; /* Next with a different name but the same hash */ FuncDestructor *pDestructor; /* Reference counted destructor function */ } u; /* pHash if SQLITE_FUNC_BUILTIN, pDestructor otherwise */ }; /* ** This structure encapsulates a user-function destructor callback (as ** configured using create_function_v2()) and a reference counter. When ** create_function_v2() is called to create a function with a destructor, ** a single object of this type is allocated. FuncDestructor.nRef is set to ** the number of FuncDef objects created (either 1 or 3, depending on whether ** or not the specified encoding is SQLITE_ANY). The FuncDef.pDestructor ** member of each of the new FuncDef objects is set to point to the allocated ** FuncDestructor. ** ** Thereafter, when one of the FuncDef objects is deleted, the reference ** count on this object is decremented. When it reaches 0, the destructor ** is invoked and the FuncDestructor structure freed. */ struct FuncDestructor { int nRef; void (*xDestroy)(void *); void *pUserData; }; /* ** Possible values for FuncDef.flags. Note that the _LENGTH and _TYPEOF ** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. And ** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC. There ** are assert() statements in the code to verify this. ** ** Value constraints (enforced via assert()): ** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg ** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd ** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG ** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG ** SQLITE_FUNC_BYTELEN == OPFLAG_BYTELENARG ** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API ** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API ** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS -- opposite meanings!!! ** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API ** ** Note that even though SQLITE_FUNC_UNSAFE and SQLITE_INNOCUOUS have the ** same bit value, their meanings are inverted. SQLITE_FUNC_UNSAFE is ** used internally and if set means that the function has side effects. ** SQLITE_INNOCUOUS is used by application code and means "not unsafe". ** See multiple instances of tag-20230109-1. */ #define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */ #define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */ #define SQLITE_FUNC_CASE 0x0008 /* Case-sensitive LIKE-type function */ #define SQLITE_FUNC_EPHEM 0x0010 /* Ephemeral. Delete with VDBE */ #define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/ #define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */ #define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */ #define SQLITE_FUNC_BYTELEN 0x00c0 /* Built-in octet_length() function */ #define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */ /* 0x0200 -- available for reuse */ #define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */ #define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */ #define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ #define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a ** single query - might change over time */ #define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */ #define SQLITE_FUNC_RUNONLY 0x8000 /* Cannot be used by valueFromFunction */ #define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ #define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ #define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */ /* SQLITE_SUBTYPE 0x00100000 // Consumer of subtypes */ #define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */ #define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */ #define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */ /* SQLITE_RESULT_SUBTYPE 0x01000000 // Generator of subtypes */ #define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */ /* Identifier numbers for each in-line function */ #define INLINEFUNC_coalesce 0 #define INLINEFUNC_implies_nonnull_row 1 #define INLINEFUNC_expr_implies_expr 2 #define INLINEFUNC_expr_compare 3 #define INLINEFUNC_affinity 4 #define INLINEFUNC_iif 5 #define INLINEFUNC_sqlite_offset 6 #define INLINEFUNC_unlikely 99 /* Default case */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are ** used to create the initializers for the FuncDef structures. ** ** FUNCTION(zName, nArg, iArg, bNC, xFunc) ** Used to create a scalar function definition of a function zName ** implemented by C function xFunc that accepts nArg arguments. The ** value passed as iArg is cast to a (void*) and made available ** as the user-data (sqlite3_user_data()) for the function. If ** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set. ** ** VFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag. ** ** SFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and ** adds the SQLITE_DIRECTONLY flag. ** ** INLINE_FUNC(zName, nArg, iFuncId, mFlags) ** zName is the name of a function that is implemented by in-line ** byte code rather than by the usual callbacks. The iFuncId ** parameter determines the function id. The mFlags parameter is ** optional SQLITE_FUNC_ flags for this function. ** ** TEST_FUNC(zName, nArg, iFuncId, mFlags) ** zName is the name of a test-only function implemented by in-line ** byte code rather than by the usual callbacks. The iFuncId ** parameter determines the function id. The mFlags parameter is ** optional SQLITE_FUNC_ flags for this function. ** ** DFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and ** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions ** and functions like sqlite_version() that can change, but not during ** a single query. The iArg is ignored. The user-data is always set ** to a NULL pointer. The bNC parameter is not used. ** ** MFUNCTION(zName, nArg, xPtr, xFunc) ** For math-library functions. xPtr is an arbitrary pointer. ** ** PURE_DATE(zName, nArg, iArg, bNC, xFunc) ** Used for "pure" date/time functions, this macro is like DFUNCTION ** except that it does set the SQLITE_FUNC_CONSTANT flags. iArg is ** ignored and the user-data for these functions is set to an ** arbitrary non-NULL pointer. The bNC parameter is not used. ** ** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal) ** Used to create an aggregate function definition implemented by ** the C functions xStep and xFinal. The first four parameters ** are interpreted in the same way as the first 4 parameters to ** FUNCTION(). ** ** WAGGREGATE(zName, nArg, iArg, xStep, xFinal, xValue, xInverse) ** Used to create an aggregate function definition implemented by ** the C functions xStep and xFinal. The first four parameters ** are interpreted in the same way as the first 4 parameters to ** FUNCTION(). ** ** LIKEFUNC(zName, nArg, pArg, flags) ** Used to create a scalar function definition of a function zName ** that accepts nArg arguments and is implemented by a call to C ** function likeFunc. Argument pArg is cast to a (void *) and made ** available as the function user-data (sqlite3_user_data()). The ** FuncDef.flags variable is set to the value passed as the flags ** parameter. */ #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define MFUNCTION(zName, nArg, xPtr, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } #define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, bJsonB, iArg, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\ SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\ ((bRS)*SQLITE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \ SQLITE_INT_TO_PTR(iArg|((bJsonB)*JSON_BLOB)),0,xFunc,0, 0, 0, #zName, {0} } #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } #define TEST_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \ SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ 0, 0, xFunc, 0, 0, 0, #zName, {0} } #define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ (void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} } #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ pArg, 0, xFunc, 0, 0, 0, #zName, } #define LIKEFUNC(zName, nArg, arg, flags) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} } #define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}} #define INTERNAL_FUNCTION(zName, nArg, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ 0, 0, xFunc, 0, 0, 0, #zName, {0} } /* ** All current savepoints are stored in a linked list starting at ** sqlite3.pSavepoint. The first element in the list is the most recently ** opened savepoint. Savepoints are added to the list by the vdbe ** OP_Savepoint instruction. */ struct Savepoint { char *zName; /* Savepoint name (nul-terminated) */ i64 nDeferredCons; /* Number of deferred fk violations */ i64 nDeferredImmCons; /* Number of deferred imm fk. */ Savepoint *pNext; /* Parent savepoint (if any) */ }; /* ** The following are used as the second parameter to sqlite3Savepoint(), ** and as the P1 argument to the OP_Savepoint instruction. */ #define SAVEPOINT_BEGIN 0 #define SAVEPOINT_RELEASE 1 #define SAVEPOINT_ROLLBACK 2 /* ** Each SQLite module (virtual table definition) is defined by an ** instance of the following structure, stored in the sqlite3.aModule ** hash table. */ struct Module { const sqlite3_module *pModule; /* Callback pointers */ const char *zName; /* Name passed to create_module() */ int nRefModule; /* Number of pointers to this object */ void *pAux; /* pAux passed to create_module() */ void (*xDestroy)(void *); /* Module destructor function */ Table *pEpoTab; /* Eponymous table for this module */ }; /* ** Information about each column of an SQL table is held in an instance ** of the Column structure, in the Table.aCol[] array. ** ** Definitions: ** ** "table column index" This is the index of the column in the ** Table.aCol[] array, and also the index of ** the column in the original CREATE TABLE stmt. ** ** "storage column index" This is the index of the column in the ** record BLOB generated by the OP_MakeRecord ** opcode. The storage column index is less than ** or equal to the table column index. It is ** equal if and only if there are no VIRTUAL ** columns to the left. ** ** Notes on zCnName: ** The zCnName field stores the name of the column, the datatype of the ** column, and the collating sequence for the column, in that order, all in ** a single allocation. Each string is 0x00 terminated. The datatype ** is only included if the COLFLAG_HASTYPE bit of colFlags is set and the ** collating sequence name is only included if the COLFLAG_HASCOLL bit is ** set. */ struct Column { char *zCnName; /* Name of this column */ unsigned notNull :4; /* An OE_ code for handling a NOT NULL constraint */ unsigned eCType :4; /* One of the standard types */ char affinity; /* One of the SQLITE_AFF_... values */ u8 szEst; /* Est size of value in this column. sizeof(INT)==1 */ u8 hName; /* Column name hash for faster lookup */ u16 iDflt; /* 1-based index of DEFAULT. 0 means "none" */ u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */ }; /* Allowed values for Column.eCType. ** ** Values must match entries in the global constant arrays ** sqlite3StdTypeLen[] and sqlite3StdType[]. Each value is one more ** than the offset into these arrays for the corresponding name. ** Adjust the SQLITE_N_STDTYPE value if adding or removing entries. */ #define COLTYPE_CUSTOM 0 /* Type appended to zName */ #define COLTYPE_ANY 1 #define COLTYPE_BLOB 2 #define COLTYPE_INT 3 #define COLTYPE_INTEGER 4 #define COLTYPE_REAL 5 #define COLTYPE_TEXT 6 #define SQLITE_N_STDTYPE 6 /* Number of standard types */ /* Allowed values for Column.colFlags. ** ** Constraints: ** TF_HasVirtual == COLFLAG_VIRTUAL ** TF_HasStored == COLFLAG_STORED ** TF_HasHidden == COLFLAG_HIDDEN */ #define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ #define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ #define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ #define COLFLAG_UNIQUE 0x0008 /* Column def contains "UNIQUE" or "PK" */ #define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */ #define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */ #define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ #define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */ #define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */ #define COLFLAG_HASCOLL 0x0200 /* Has collating sequence name in zCnName */ #define COLFLAG_NOEXPAND 0x0400 /* Omit this column when expanding "*" */ #define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */ #define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */ /* ** A "Collating Sequence" is defined by an instance of the following ** structure. Conceptually, a collating sequence consists of a name and ** a comparison routine that defines the order of that sequence. ** ** If CollSeq.xCmp is NULL, it means that the ** collating sequence is undefined. Indices built on an undefined ** collating sequence may not be read or written. */ struct CollSeq { char *zName; /* Name of the collating sequence, UTF-8 encoded */ u8 enc; /* Text encoding handled by xCmp() */ void *pUser; /* First argument to xCmp() */ int (*xCmp)(void*,int, const void*, int, const void*); void (*xDel)(void*); /* Destructor for pUser */ }; /* ** A sort order can be either ASC or DESC. */ #define SQLITE_SO_ASC 0 /* Sort in ascending order */ #define SQLITE_SO_DESC 1 /* Sort in ascending order */ #define SQLITE_SO_UNDEFINED -1 /* No sort order specified */ /* ** Column affinity types. ** ** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and ** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve ** the speed a little by numbering the values consecutively. ** ** But rather than start with 0 or 1, we begin with 'A'. That way, ** when multiple affinity types are concatenated into a string and ** used as the P4 operand, they will be more readable. ** ** Note also that the numeric types are grouped together so that testing ** for a numeric type is a single comparison. And the BLOB type is first. */ #define SQLITE_AFF_NONE 0x40 /* '@' */ #define SQLITE_AFF_BLOB 0x41 /* 'A' */ #define SQLITE_AFF_TEXT 0x42 /* 'B' */ #define SQLITE_AFF_NUMERIC 0x43 /* 'C' */ #define SQLITE_AFF_INTEGER 0x44 /* 'D' */ #define SQLITE_AFF_REAL 0x45 /* 'E' */ #define SQLITE_AFF_FLEXNUM 0x46 /* 'F' */ #define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) /* ** The SQLITE_AFF_MASK values masks off the significant bits of an ** affinity value. */ #define SQLITE_AFF_MASK 0x47 /* ** Additional bit values that can be ORed with an affinity without ** changing the affinity. ** ** The SQLITE_NOTNULL flag is a combination of NULLEQ and JUMPIFNULL. ** It causes an assert() to fire if either operand to a comparison ** operator is NULL. It is added to certain comparison operators to ** prove that the operands are always NOT NULL. */ #define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ #define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */ /* ** An object of this type is created for each virtual table present in ** the database schema. ** ** If the database schema is shared, then there is one instance of this ** structure for each database connection (sqlite3*) that uses the shared ** schema. This is because each database connection requires its own unique ** instance of the sqlite3_vtab* handle used to access the virtual table ** implementation. sqlite3_vtab* handles can not be shared between ** database connections, even when the rest of the in-memory database ** schema is shared, as the implementation often stores the database ** connection handle passed to it via the xConnect() or xCreate() method ** during initialization internally. This database connection handle may ** then be used by the virtual table implementation to access real tables ** within the database. So that they appear as part of the callers ** transaction, these accesses need to be made via the same database ** connection as that used to execute SQL operations on the virtual table. ** ** All VTable objects that correspond to a single table in a shared ** database schema are initially stored in a linked-list pointed to by ** the Table.pVTable member variable of the corresponding Table object. ** When an sqlite3_prepare() operation is required to access the virtual ** table, it searches the list for the VTable that corresponds to the ** database connection doing the preparing so as to use the correct ** sqlite3_vtab* handle in the compiled query. ** ** When an in-memory Table object is deleted (for example when the ** schema is being reloaded for some reason), the VTable objects are not ** deleted and the sqlite3_vtab* handles are not xDisconnect()ed ** immediately. Instead, they are moved from the Table.pVTable list to ** another linked list headed by the sqlite3.pDisconnect member of the ** corresponding sqlite3 structure. They are then deleted/xDisconnected ** next time a statement is prepared using said sqlite3*. This is done ** to avoid deadlock issues involving multiple sqlite3.mutex mutexes. ** Refer to comments above function sqlite3VtabUnlockList() for an ** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect ** list without holding the corresponding sqlite3.mutex mutex. ** ** The memory for objects of this type is always allocated by ** sqlite3DbMalloc(), using the connection handle stored in VTable.db as ** the first argument. */ struct VTable { sqlite3 *db; /* Database connection associated with this table */ Module *pMod; /* Pointer to module implementation */ sqlite3_vtab *pVtab; /* Pointer to vtab instance */ int nRef; /* Number of pointers to this structure */ u8 bConstraint; /* True if constraints are supported */ u8 bAllSchemas; /* True if might use any attached schema */ u8 eVtabRisk; /* Riskiness of allowing hacker access */ int iSavepoint; /* Depth of the SAVEPOINT stack */ VTable *pNext; /* Next in linked list (see above) */ }; /* Allowed values for VTable.eVtabRisk */ #define SQLITE_VTABRISK_Low 0 #define SQLITE_VTABRISK_Normal 1 #define SQLITE_VTABRISK_High 2 /* ** The schema for each SQL table, virtual table, and view is represented ** in memory by an instance of the following structure. */ struct Table { char *zName; /* Name of the table or view */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ char *zColAff; /* String defining the affinity of each column */ ExprList *pCheck; /* All CHECK constraints */ /* ... also used as column name list in a VIEW */ Pgno tnum; /* Root BTree page for this table */ u32 nTabRef; /* Number of pointers to this Table */ u32 tabFlags; /* Mask of TF_* values */ i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */ i16 nCol; /* Number of columns in this table */ i16 nNVCol; /* Number of columns that are not VIRTUAL */ LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ #ifdef SQLITE_ENABLE_COSTMULT LogEst costMult; /* Cost multiplier for using this table */ #endif u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ u8 eTabType; /* 0: normal, 1: virtual, 2: view */ union { struct { /* Used by ordinary tables: */ int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ FKey *pFKey; /* Linked list of all foreign keys in this table */ ExprList *pDfltList; /* DEFAULT clauses on various columns. ** Or the AS clause for generated columns. */ } tab; struct { /* Used by views: */ Select *pSelect; /* View definition */ } view; struct { /* Used by virtual tables only: */ int nArg; /* Number of arguments to the module */ char **azArg; /* 0: module 1: schema 2: vtab name 3...: args */ VTable *p; /* List of VTable objects. */ } vtab; } u; Trigger *pTrigger; /* List of triggers on this object */ Schema *pSchema; /* Schema that contains this table */ }; /* ** Allowed values for Table.tabFlags. ** ** TF_OOOHidden applies to tables or view that have hidden columns that are ** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING ** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden, ** the TF_OOOHidden attribute would apply in this case. Such tables require ** special handling during INSERT processing. The "OOO" means "Out Of Order". ** ** Constraints: ** ** TF_HasVirtual == COLFLAG_VIRTUAL ** TF_HasStored == COLFLAG_STORED ** TF_HasHidden == COLFLAG_HIDDEN */ #define TF_Readonly 0x00000001 /* Read-only system table */ #define TF_HasHidden 0x00000002 /* Has one or more hidden columns */ #define TF_HasPrimaryKey 0x00000004 /* Table has a primary key */ #define TF_Autoincrement 0x00000008 /* Integer primary key is autoincrement */ #define TF_HasStat1 0x00000010 /* nRowLogEst set from sqlite_stat1 */ #define TF_HasVirtual 0x00000020 /* Has one or more VIRTUAL columns */ #define TF_HasStored 0x00000040 /* Has one or more STORED columns */ #define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */ #define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */ #define TF_StatsUsed 0x00000100 /* Query planner decisions affected by ** Index.aiRowLogEst[] values */ #define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */ #define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */ #define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */ #define TF_Shadow 0x00001000 /* True for a shadow table */ #define TF_HasStat4 0x00002000 /* STAT4 info available for this table */ #define TF_Ephemeral 0x00004000 /* An ephemeral table */ #define TF_Eponymous 0x00008000 /* An eponymous virtual table */ #define TF_Strict 0x00010000 /* STRICT mode */ /* ** Allowed values for Table.eTabType */ #define TABTYP_NORM 0 /* Ordinary table */ #define TABTYP_VTAB 1 /* Virtual table */ #define TABTYP_VIEW 2 /* A view */ #define IsView(X) ((X)->eTabType==TABTYP_VIEW) #define IsOrdinaryTable(X) ((X)->eTabType==TABTYP_NORM) /* ** Test to see whether or not a table is a virtual table. This is ** done as a macro so that it will be optimized out when virtual ** table support is omitted from the build. */ #ifndef SQLITE_OMIT_VIRTUALTABLE # define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB) # define ExprIsVtab(X) \ ((X)->op==TK_COLUMN && (X)->y.pTab->eTabType==TABTYP_VTAB) #else # define IsVirtual(X) 0 # define ExprIsVtab(X) 0 #endif /* ** Macros to determine if a column is hidden. IsOrdinaryHiddenColumn() ** only works for non-virtual tables (ordinary tables and views) and is ** always false unless SQLITE_ENABLE_HIDDEN_COLUMNS is defined. The ** IsHiddenColumn() macro is general purpose. */ #if defined(SQLITE_ENABLE_HIDDEN_COLUMNS) # define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0) # define IsOrdinaryHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0) #elif !defined(SQLITE_OMIT_VIRTUALTABLE) # define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0) # define IsOrdinaryHiddenColumn(X) 0 #else # define IsHiddenColumn(X) 0 # define IsOrdinaryHiddenColumn(X) 0 #endif /* Does the table have a rowid */ #define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0) #define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0) /* ** Each foreign key constraint is an instance of the following structure. ** ** A foreign key is associated with two tables. The "from" table is ** the table that contains the REFERENCES clause that creates the foreign ** key. The "to" table is the table that is named in the REFERENCES clause. ** Consider this example: ** ** CREATE TABLE ex1( ** a INTEGER PRIMARY KEY, ** b INTEGER CONSTRAINT fk1 REFERENCES ex2(x) ** ); ** ** For foreign key "fk1", the from-table is "ex1" and the to-table is "ex2". ** Equivalent names: ** ** from-table == child-table ** to-table == parent-table ** ** Each REFERENCES clause generates an instance of the following structure ** which is attached to the from-table. The to-table need not exist when ** the from-table is created. The existence of the to-table is not checked. ** ** The list of all parents for child Table X is held at X.pFKey. ** ** A list of all children for a table named Z (which might not even exist) ** is held in Schema.fkeyHash with a hash key of Z. */ struct FKey { Table *pFrom; /* Table containing the REFERENCES clause (aka: Child) */ FKey *pNextFrom; /* Next FKey with the same in pFrom. Next parent of pFrom */ char *zTo; /* Name of table that the key points to (aka: Parent) */ FKey *pNextTo; /* Next with the same zTo. Next child of zTo. */ FKey *pPrevTo; /* Previous with the same zTo */ int nCol; /* Number of columns in this key */ /* EV: R-30323-21917 */ u8 isDeferred; /* True if constraint checking is deferred till COMMIT */ u8 aAction[2]; /* ON DELETE and ON UPDATE actions, respectively */ Trigger *apTrigger[2];/* Triggers for aAction[] actions */ struct sColMap { /* Mapping of columns in pFrom to columns in zTo */ int iFrom; /* Index of column in pFrom */ char *zCol; /* Name of column in zTo. If NULL use PRIMARY KEY */ } aCol[1]; /* One entry for each of nCol columns */ }; /* ** SQLite supports many different ways to resolve a constraint ** error. ROLLBACK processing means that a constraint violation ** causes the operation in process to fail and for the current transaction ** to be rolled back. ABORT processing means the operation in process ** fails and any prior changes from that one operation are backed out, ** but the transaction is not rolled back. FAIL processing means that ** the operation in progress stops and returns an error code. But prior ** changes due to the same operation are not backed out and no rollback ** occurs. IGNORE means that the particular row that caused the constraint ** error is not inserted or updated. Processing continues and no error ** is returned. REPLACE means that preexisting database rows that caused ** a UNIQUE constraint violation are removed so that the new insert or ** update can proceed. Processing continues and no error is reported. ** UPDATE applies to insert operations only and means that the insert ** is omitted and the DO UPDATE clause of an upsert is run instead. ** ** RESTRICT, SETNULL, SETDFLT, and CASCADE actions apply only to foreign keys. ** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the ** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign ** key is set to NULL. SETDFLT means that the foreign key is set ** to its default value. CASCADE means that a DELETE or UPDATE of the ** referenced table row is propagated into the row that holds the ** foreign key. ** ** The OE_Default value is a place holder that means to use whatever ** conflict resolution algorithm is required from context. ** ** The following symbolic values are used to record which type ** of conflict resolution action to take. */ #define OE_None 0 /* There is no constraint to check */ #define OE_Rollback 1 /* Fail the operation and rollback the transaction */ #define OE_Abort 2 /* Back out changes but do no rollback transaction */ #define OE_Fail 3 /* Stop the operation but leave all prior changes */ #define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */ #define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */ #define OE_Update 6 /* Process as a DO UPDATE in an upsert */ #define OE_Restrict 7 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */ #define OE_SetNull 8 /* Set the foreign key value to NULL */ #define OE_SetDflt 9 /* Set the foreign key value to its default */ #define OE_Cascade 10 /* Cascade the changes */ #define OE_Default 11 /* Do whatever the default action is */ /* ** An instance of the following structure is passed as the first ** argument to sqlite3VdbeKeyCompare and is used to control the ** comparison of the two index keys. ** ** Note that aSortOrder[] and aColl[] have nField+1 slots. There ** are nField slots for the columns of an index then one extra slot ** for the rowid at the end. */ struct KeyInfo { u32 nRef; /* Number of references to this KeyInfo object */ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */ u16 nKeyField; /* Number of key columns in the index */ u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ u8 *aSortFlags; /* Sort order for each column. */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ }; /* ** Allowed bit values for entries in the KeyInfo.aSortFlags[] array. */ #define KEYINFO_ORDER_DESC 0x01 /* DESC sort order */ #define KEYINFO_ORDER_BIGNULL 0x02 /* NULL is larger than any other value */ /* ** This object holds a record which has been parsed out into individual ** fields, for the purposes of doing a comparison. ** ** A record is an object that contains one or more fields of data. ** Records are used to store the content of a table row and to store ** the key of an index. A blob encoding of a record is created by ** the OP_MakeRecord opcode of the VDBE and is disassembled by the ** OP_Column opcode. ** ** An instance of this object serves as a "key" for doing a search on ** an index b+tree. The goal of the search is to find the entry that ** is closed to the key described by this object. This object might hold ** just a prefix of the key. The number of fields is given by ** pKeyInfo->nField. ** ** The r1 and r2 fields are the values to return if this key is less than ** or greater than a key in the btree, respectively. These are normally ** -1 and +1 respectively, but might be inverted to +1 and -1 if the b-tree ** is in DESC order. ** ** The key comparison functions actually return default_rc when they find ** an equals comparison. default_rc can be -1, 0, or +1. If there are ** multiple entries in the b-tree with the same key (when only looking ** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to ** cause the search to find the last match, or +1 to cause the search to ** find the first match. ** ** The key comparison functions will set eqSeen to true if they ever ** get and equal results when comparing this structure to a b-tree record. ** When default_rc!=0, the search might end up on the record immediately ** before the first match or immediately after the last match. The ** eqSeen field will indicate whether or not an exact match exists in the ** b-tree. */ struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ Mem *aMem; /* Values */ union { char *z; /* Cache of aMem[0].z for vdbeRecordCompareString() */ i64 i; /* Cache of aMem[0].u.i for vdbeRecordCompareInt() */ } u; int n; /* Cache of aMem[0].n used by vdbeRecordCompareString() */ u16 nField; /* Number of entries in apMem[] */ i8 default_rc; /* Comparison result if keys are equal */ u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */ i8 r1; /* Value to return if (lhs < rhs) */ i8 r2; /* Value to return if (lhs > rhs) */ u8 eqSeen; /* True if an equality comparison has been seen */ }; /* ** Each SQL index is represented in memory by an ** instance of the following structure. ** ** The columns of the table that are to be indexed are described ** by the aiColumn[] field of this structure. For example, suppose ** we have the following table and index: ** ** CREATE TABLE Ex1(c1 int, c2 int, c3 text); ** CREATE INDEX Ex2 ON Ex1(c3,c1); ** ** In the Table structure describing Ex1, nCol==3 because there are ** three columns in the table. In the Index structure describing ** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed. ** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the ** first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. ** The second column to be indexed (c1) has an index of 0 in ** Ex1.aCol[], hence Ex2.aiColumn[1]==0. ** ** The Index.onError field determines whether or not the indexed columns ** must be unique and what to do if they are not. When Index.onError=OE_None, ** it means this is not a unique index. Otherwise it is a unique index ** and the value of Index.onError indicates which conflict resolution ** algorithm to employ when an attempt is made to insert a non-unique ** element. ** ** The colNotIdxed bitmask is used in combination with SrcItem.colUsed ** for a fast test to see if an index can serve as a covering index. ** colNotIdxed has a 1 bit for every column of the original table that ** is *not* available in the index. Thus the expression ** "colUsed & colNotIdxed" will be non-zero if the index is not a ** covering index. The most significant bit of of colNotIdxed will always ** be true (note-20221022-a). If a column beyond the 63rd column of the ** table is used, the "colUsed & colNotIdxed" test will always be non-zero ** and we have to assume either that the index is not covering, or use ** an alternative (slower) algorithm to determine whether or not ** the index is covering. ** ** While parsing a CREATE TABLE or CREATE INDEX statement in order to ** generate VDBE code (as opposed to parsing one read from an sqlite_schema ** table as part of parsing an existing database schema), transient instances ** of this structure may be created. In this case the Index.tnum variable is ** used to store the address of a VDBE instruction, not a database page ** number (it cannot - the database page is not allocated until the VDBE ** program is executed). See convertToWithoutRowidTable() for details. */ struct Index { char *zName; /* Name of this index */ i16 *aiColumn; /* Which columns are used by this index. 1st is 0 */ LogEst *aiRowLogEst; /* From ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ Schema *pSchema; /* Schema containing this index */ u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ const char **azColl; /* Array of collation sequence names for index */ Expr *pPartIdxWhere; /* WHERE clause for partial indices */ ExprList *aColExpr; /* Column expressions */ Pgno tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ u16 nColumn; /* Number of columns stored in the index */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ unsigned isCovering:1; /* True if this is a covering index */ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */ unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ unsigned bHasExpr:1; /* Index contains an expression, either a literal ** expression, or a reference to a VIRTUAL column */ #ifdef SQLITE_ENABLE_STAT4 int nSample; /* Number of elements in aSample[] */ int mxSample; /* Number of slots allocated to aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */ tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */ #endif Bitmask colNotIdxed; /* Unindexed columns in pTab */ }; /* ** Allowed values for Index.idxType */ #define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ #define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */ #define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */ #define SQLITE_IDXTYPE_IPK 3 /* INTEGER PRIMARY KEY index */ /* Return true if index X is a PRIMARY KEY index */ #define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) /* Return true if index X is a UNIQUE index */ #define IsUniqueIndex(X) ((X)->onError!=OE_None) /* The Index.aiColumn[] values are normally positive integer. But ** there are some negative values that have special meaning: */ #define XN_ROWID (-1) /* Indexed column is the rowid */ #define XN_EXPR (-2) /* Indexed column is an expression */ /* ** Each sample stored in the sqlite_stat4 table is represented in memory ** using a structure of this type. See documentation at the top of the ** analyze.c source file for additional information. */ struct IndexSample { void *p; /* Pointer to sampled record */ int n; /* Size of record in bytes */ tRowcnt *anEq; /* Est. number of rows where the key equals this sample */ tRowcnt *anLt; /* Est. number of rows where key is less than this sample */ tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */ }; /* ** Possible values to use within the flags argument to sqlite3GetToken(). */ #define SQLITE_TOKEN_QUOTED 0x1 /* Token is a quoted identifier. */ #define SQLITE_TOKEN_KEYWORD 0x2 /* Token is a keyword. */ /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. ** ** The memory that "z" points to is owned by other objects. Take care ** that the owner of the "z" string does not deallocate the string before ** the Token goes out of scope! Very often, the "z" points to some place ** in the middle of the Parse.zSql text. But it might also point to a ** static string. */ struct Token { const char *z; /* Text of the token. Not NULL-terminated! */ unsigned int n; /* Number of characters in this token */ }; /* ** An instance of this structure contains information needed to generate ** code for a SELECT that contains aggregate functions. ** ** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a ** pointer to this structure. The Expr.iAgg field is the index in ** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate ** code for that node. ** ** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the ** original Select structure that describes the SELECT statement. These ** fields do not need to be freed when deallocating the AggInfo structure. */ struct AggInfo { u8 directMode; /* Direct rendering mode means take data directly ** from source tables rather than from accumulators */ u8 useSortingIdx; /* In direct mode, reference the sorting index rather ** than the source table */ u16 nSortingColumn; /* Number of columns in the sorting index */ int sortingIdx; /* Cursor number of the sorting index */ int sortingIdxPTab; /* Cursor number of pseudo-table */ int iFirstReg; /* First register in range for aCol[] and aFunc[] */ ExprList *pGroupBy; /* The group by clause */ struct AggInfo_col { /* For each column used in source tables */ Table *pTab; /* Source table */ Expr *pCExpr; /* The original expression */ int iTable; /* Cursor number of the source table */ i16 iColumn; /* Column number within the source table */ i16 iSorterColumn; /* Column number in the sorting index */ } *aCol; int nColumn; /* Number of used entries in aCol[] */ int nAccumulator; /* Number of columns that show through to the output. ** Additional columns are used only as parameters to ** aggregate functions */ struct AggInfo_func { /* For each aggregate function */ Expr *pFExpr; /* Expression encoding the function */ FuncDef *pFunc; /* The aggregate function implementation */ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ int iDistAddr; /* Address of OP_OpenEphemeral */ int iOBTab; /* Ephemeral table to implement ORDER BY */ u8 bOBPayload; /* iOBTab has payload columns separate from key */ u8 bOBUnique; /* Enforce uniqueness on iOBTab keys */ u8 bUseSubtype; /* Transfer subtype info through sorter */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ u32 selId; /* Select to which this AggInfo belongs */ #ifdef SQLITE_DEBUG Select *pSelect; /* SELECT statement that this AggInfo supports */ #endif }; /* ** Macros to compute aCol[] and aFunc[] register numbers. ** ** These macros should not be used prior to the call to ** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg. ** The assert()s that are part of this macro verify that constraint. */ #define AggInfoColumnReg(A,I) (assert((A)->iFirstReg),(A)->iFirstReg+(I)) #define AggInfoFuncReg(A,I) \ (assert((A)->iFirstReg),(A)->iFirstReg+(A)->nColumn+(I)) /* ** The datatype ynVar is a signed integer, either 16-bit or 32-bit. ** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater ** than 32767 we have to make it 32-bit. 16-bit is preferred because ** it uses less memory in the Expr object, which is a big memory user ** in systems with lots of prepared statements. And few applications ** need more than about 10 or 20 variables. But some extreme users want ** to have prepared statements with over 32766 variables, and for them ** the option is available (at compile-time). */ #if SQLITE_MAX_VARIABLE_NUMBER<32767 typedef i16 ynVar; #else typedef int ynVar; #endif /* ** Each node of an expression in the parse tree is an instance ** of this structure. ** ** Expr.op is the opcode. The integer parser token codes are reused ** as opcodes here. For example, the parser defines TK_GE to be an integer ** code representing the ">=" operator. This same integer code is reused ** to represent the greater-than-or-equal-to operator in the expression ** tree. ** ** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, ** or TK_STRING), then Expr.u.zToken contains the text of the SQL literal. If ** the expression is a variable (TK_VARIABLE), then Expr.u.zToken contains the ** variable name. Finally, if the expression is an SQL function (TK_FUNCTION), ** then Expr.u.zToken contains the name of the function. ** ** Expr.pRight and Expr.pLeft are the left and right subexpressions of a ** binary operator. Either or both may be NULL. ** ** Expr.x.pList is a list of arguments if the expression is an SQL function, ** a CASE expression or an IN expression of the form " IN (, ...)". ** Expr.x.pSelect is used if the expression is a sub-select or an expression of ** the form " IN (SELECT ...)". If the EP_xIsSelect bit is set in the ** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is ** valid. ** ** An expression of the form ID or ID.ID refers to a column in a table. ** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is ** the integer cursor number of a VDBE cursor pointing to that table and ** Expr.iColumn is the column number for the specific column. If the ** expression is used as a result in an aggregate SELECT, then the ** value is also stored in the Expr.iAgg column in the aggregate so that ** it can be accessed after all aggregates are computed. ** ** If the expression is an unbound variable marker (a question mark ** character '?' in the original SQL) then the Expr.iTable holds the index ** number for that variable. ** ** If the expression is a subquery then Expr.iColumn holds an integer ** register number containing the result of the subquery. If the ** subquery gives a constant result, then iTable is -1. If the subquery ** gives a different answer at different times during statement processing ** then iTable is the address of a subroutine that computes the subquery. ** ** If the Expr is of type OP_Column, and the table it is selecting from ** is a disk table or the "old.*" pseudo-table, then pTab points to the ** corresponding table definition. ** ** ALLOCATION NOTES: ** ** Expr objects can use a lot of memory space in database schema. To ** help reduce memory requirements, sometimes an Expr object will be ** truncated. And to reduce the number of memory allocations, sometimes ** two or more Expr objects will be stored in a single memory allocation, ** together with Expr.u.zToken strings. ** ** If the EP_Reduced and EP_TokenOnly flags are set when ** an Expr object is truncated. When EP_Reduced is set, then all ** the child Expr objects in the Expr.pLeft and Expr.pRight subtrees ** are contained within the same memory allocation. Note, however, that ** the subtrees in Expr.x.pList or Expr.x.pSelect are always separately ** allocated, regardless of whether or not EP_Reduced is set. */ struct Expr { u8 op; /* Operation performed by this node */ char affExpr; /* affinity, or RAISE type */ u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth ** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */ #ifdef SQLITE_DEBUG u8 vvaFlags; /* Verification flags. */ #endif u32 flags; /* Various flags. EP_* See below */ union { char *zToken; /* Token value. Zero terminated and dequoted */ int iValue; /* Non-negative integer value if EP_IntValue */ } u; /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no ** space is allocated for the fields below this point. An attempt to ** access them will result in a segfault or malfunction. *********************************************************************/ Expr *pLeft; /* Left subnode */ Expr *pRight; /* Right subnode */ union { ExprList *pList; /* op = IN, EXISTS, SELECT, CASE, FUNCTION, BETWEEN */ Select *pSelect; /* EP_xIsSelect and op = IN, EXISTS, SELECT */ } x; /* If the EP_Reduced flag is set in the Expr.flags mask, then no ** space is allocated for the fields below this point. An attempt to ** access them will result in a segfault or malfunction. *********************************************************************/ #if SQLITE_MAX_EXPR_DEPTH>0 int nHeight; /* Height of the tree headed by this node */ #endif int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old ** EP_Unlikely: 134217728 times likelihood ** TK_IN: ephemeral table holding RHS ** TK_SELECT_COLUMN: Number of columns on the LHS ** TK_SELECT: 1st register of result vector */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ union { int iJoin; /* If EP_OuterON or EP_InnerON, the right table */ int iOfst; /* else: start of token from start of statement */ } w; AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ union { Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL ** for a column of an index on an expression */ Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */ struct { /* TK_IN, TK_SELECT, and TK_EXISTS */ int iAddr; /* Subroutine entry address */ int regReturn; /* Register used to hold return address */ } sub; } y; }; /* The following are the meanings of bits in the Expr.flags field. ** Value restrictions: ** ** EP_Agg == NC_HasAgg == SF_HasAgg ** EP_Win == NC_HasWin */ #define EP_OuterON 0x000001 /* Originates in ON/USING clause of outer join */ #define EP_InnerON 0x000002 /* Originates in ON/USING of an inner join */ #define EP_Distinct 0x000004 /* Aggregate function with DISTINCT keyword */ #define EP_HasFunc 0x000008 /* Contains one or more functions of any kind */ #define EP_Agg 0x000010 /* Contains one or more aggregate functions */ #define EP_FixedCol 0x000020 /* TK_Column with a known fixed value */ #define EP_VarSelect 0x000040 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000080 /* token.z was originally in "..." */ #define EP_InfixFunc 0x000100 /* True for an infix function: LIKE, GLOB, etc */ #define EP_Collate 0x000200 /* Tree contains a TK_COLLATE operator */ #define EP_Commuted 0x000400 /* Comparison operator has been commuted */ #define EP_IntValue 0x000800 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x001000 /* x.pSelect is valid (otherwise x.pList is) */ #define EP_Skip 0x002000 /* Operator does not contribute to affinity */ #define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_Win 0x008000 /* Contains window functions */ #define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ #define EP_FullSize 0x020000 /* Expr structure must remain full sized */ #define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */ #define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */ #define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ #define EP_CanBeNull 0x200000 /* Can be null despite NOT NULL constraint */ #define EP_Subquery 0x400000 /* Tree contains a TK_SELECT operator */ #define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ #define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */ #define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */ #define EP_Quoted 0x4000000 /* TK_ID was originally quoted */ #define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */ #define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */ #define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */ #define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */ /* 0x80000000 // Available */ /* The EP_Propagate mask is a set of properties that automatically propagate ** upwards into parent nodes. */ #define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc) /* Macros can be used to test, set, or clear bits in the ** Expr.flags field. */ #define ExprHasProperty(E,P) (((E)->flags&(P))!=0) #define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) #define ExprSetProperty(E,P) (E)->flags|=(P) #define ExprClearProperty(E,P) (E)->flags&=~(P) #define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue) #define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse) #define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0) /* Macros used to ensure that the correct members of unions are accessed ** in Expr. */ #define ExprUseUToken(E) (((E)->flags&EP_IntValue)==0) #define ExprUseUValue(E) (((E)->flags&EP_IntValue)!=0) #define ExprUseWOfst(E) (((E)->flags&(EP_InnerON|EP_OuterON))==0) #define ExprUseWJoin(E) (((E)->flags&(EP_InnerON|EP_OuterON))!=0) #define ExprUseXList(E) (((E)->flags&EP_xIsSelect)==0) #define ExprUseXSelect(E) (((E)->flags&EP_xIsSelect)!=0) #define ExprUseYTab(E) (((E)->flags&(EP_WinFunc|EP_Subrtn))==0) #define ExprUseYWin(E) (((E)->flags&EP_WinFunc)!=0) #define ExprUseYSub(E) (((E)->flags&EP_Subrtn)!=0) /* Flags for use with Expr.vvaFlags */ #define EP_NoReduce 0x01 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Immutable 0x02 /* Do not change this Expr node */ /* The ExprSetVVAProperty() macro is used for Verification, Validation, ** and Accreditation only. It works like ExprSetProperty() during VVA ** processes but is a no-op for delivery. */ #ifdef SQLITE_DEBUG # define ExprSetVVAProperty(E,P) (E)->vvaFlags|=(P) # define ExprHasVVAProperty(E,P) (((E)->vvaFlags&(P))!=0) # define ExprClearVVAProperties(E) (E)->vvaFlags = 0 #else # define ExprSetVVAProperty(E,P) # define ExprHasVVAProperty(E,P) 0 # define ExprClearVVAProperties(E) #endif /* ** Macros to determine the number of bytes required by a normal Expr ** struct, an Expr struct with the EP_Reduced flag set in Expr.flags ** and an Expr struct with the EP_TokenOnly flag set. */ #define EXPR_FULLSIZE sizeof(Expr) /* Full size */ #define EXPR_REDUCEDSIZE offsetof(Expr,iTable) /* Common features */ #define EXPR_TOKENONLYSIZE offsetof(Expr,pLeft) /* Fewer features */ /* ** Flags passed to the sqlite3ExprDup() function. See the header comment ** above sqlite3ExprDup() for details. */ #define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */ /* ** True if the expression passed as an argument was a function with ** an OVER() clause (a window function). */ #ifdef SQLITE_OMIT_WINDOWFUNC # define IsWindowFunc(p) 0 #else # define IsWindowFunc(p) ( \ ExprHasProperty((p), EP_WinFunc) && p->y.pWin->eFrmType!=TK_FILTER \ ) #endif /* ** A list of expressions. Each expression may optionally have a ** name. An expr/name combination can be used in several ways, such ** as the list of "expr AS ID" fields following a "SELECT" or in the ** list of "ID = expr" items in an UPDATE. A list of expressions can ** also be used as the argument to a function, in which case the a.zName ** field is not used. ** ** In order to try to keep memory usage down, the Expr.a.zEName field ** is used for multiple purposes: ** ** eEName Usage ** ---------- ------------------------- ** ENAME_NAME (1) the AS of result set column ** (2) COLUMN= of an UPDATE ** ** ENAME_TAB DB.TABLE.NAME used to resolve names ** of subqueries ** ** ENAME_SPAN Text of the original result set ** expression. */ struct ExprList { int nExpr; /* Number of expressions on the list */ int nAlloc; /* Number of a[] slots allocated */ struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The parse tree for this expression */ char *zEName; /* Token associated with this expression */ struct { u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */ unsigned eEName :2; /* Meaning of zEName */ unsigned done :1; /* Indicates when processing is finished */ unsigned reusable :1; /* Constant expression is reusable */ unsigned bSorterRef :1; /* Defer evaluation until after sorting */ unsigned bNulls :1; /* True if explicit "NULLS FIRST/LAST" */ unsigned bUsed :1; /* This column used in a SF_NestedFrom subquery */ unsigned bUsingTerm:1; /* Term from the USING clause of a NestedFrom */ unsigned bNoExpand: 1; /* Term is an auxiliary in NestedFrom and should ** not be expanded by "*" in parent queries */ } fg; union { struct { /* Used by any ExprList other than Parse.pConsExpr */ u16 iOrderByCol; /* For ORDER BY, column number in result set */ u16 iAlias; /* Index into Parse.aAlias[] for zName */ } x; int iConstExprReg; /* Register in which Expr value is cached. Used only ** by Parse.pConstExpr */ } u; } a[1]; /* One slot for each expression in the list */ }; /* ** Allowed values for Expr.a.eEName */ #define ENAME_NAME 0 /* The AS clause of a result set */ #define ENAME_SPAN 1 /* Complete text of the result set expression */ #define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */ #define ENAME_ROWID 3 /* "DB.TABLE._rowid_" for * expansion of rowid */ /* ** An instance of this structure can hold a simple list of identifiers, ** such as the list "a,b,c" in the following statements: ** ** INSERT INTO t(a,b,c) VALUES ...; ** CREATE INDEX idx ON t(a,b,c); ** CREATE TRIGGER trig BEFORE UPDATE ON t(a,b,c) ...; ** ** The IdList.a.idx field is used when the IdList represents the list of ** column names after a table name in an INSERT statement. In the statement ** ** INSERT INTO t(a,b,c) ... ** ** If "a" is the k-th column of table "t", then IdList.a[0].idx==k. */ struct IdList { int nId; /* Number of identifiers on the list */ u8 eU4; /* Which element of a.u4 is valid */ struct IdList_item { char *zName; /* Name of the identifier */ union { int idx; /* Index in some Table.aCol[] of a column named zName */ Expr *pExpr; /* Expr to implement a USING variable -- NOT USED */ } u4; } a[1]; }; /* ** Allowed values for IdList.eType, which determines which value of the a.u4 ** is valid. */ #define EU4_NONE 0 /* Does not use IdList.a.u4 */ #define EU4_IDX 1 /* Uses IdList.a.u4.idx */ #define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */ /* ** The SrcItem object represents a single term in the FROM clause of a query. ** The SrcList object is mostly an array of SrcItems. ** ** The jointype starts out showing the join type between the current table ** and the next table on the list. The parser builds the list this way. ** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each ** jointype expresses the join between the table and the previous table. ** ** In the colUsed field, the high-order bit (bit 63) is set if the table ** contains more than 63 columns and the 64-th or later column is used. ** ** Union member validity: ** ** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc ** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy ** u2.pIBIndex fg.isIndexedBy && !fg.isCte ** u2.pCteUse fg.isCte && !fg.isIndexedBy */ struct SrcItem { Schema *pSchema; /* Schema to which this item is fixed */ char *zDatabase; /* Name of database holding this table */ char *zName; /* Name of the table */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ int regResult; /* Registers holding results of a co-routine */ struct { u8 jointype; /* Type of join between this table and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned isMaterialized:1; /* This is a materialized view */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ unsigned fromDDL :1; /* Comes from sqlite_schema */ unsigned isCte :1; /* This is a CTE */ unsigned notCte :1; /* This item may not match a CTE */ unsigned isUsing :1; /* u3.pUsing is valid */ unsigned isOn :1; /* u3.pOn was once valid and non-NULL */ unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */ unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */ } fg; int iCursor; /* The VDBE cursor number used to access this table */ union { Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */ IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */ } u3; Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */ union { char *zIndexedBy; /* Identifier from "INDEXED BY " clause */ ExprList *pFuncArg; /* Arguments to table-valued-function */ } u1; union { Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */ } u2; }; /* ** The OnOrUsing object represents either an ON clause or a USING clause. ** It can never be both at the same time, but it can be neither. */ struct OnOrUsing { Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ }; /* ** This object represents one or more tables that are the source of ** content for an SQL statement. For example, a single SrcList object ** is used to hold the FROM clause of a SELECT statement. SrcList also ** represents the target tables for DELETE, INSERT, and UPDATE statements. ** */ struct SrcList { int nSrc; /* Number of tables or subqueries in the FROM clause */ u32 nAlloc; /* Number of entries allocated in a[] below */ SrcItem a[1]; /* One entry for each identifier on the list */ }; /* ** Permitted values of the SrcList.a.jointype field */ #define JT_INNER 0x01 /* Any kind of inner or cross join */ #define JT_CROSS 0x02 /* Explicit use of the CROSS keyword */ #define JT_NATURAL 0x04 /* True for a "natural" join */ #define JT_LEFT 0x08 /* Left outer join */ #define JT_RIGHT 0x10 /* Right outer join */ #define JT_OUTER 0x20 /* The "OUTER" keyword is present */ #define JT_LTORJ 0x40 /* One of the LEFT operands of a RIGHT JOIN ** Mnemonic: Left Table Of Right Join */ #define JT_ERROR 0x80 /* unknown or unsupported join type */ /* ** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin() ** and the WhereInfo.wctrlFlags member. ** ** Value constraints (enforced via assert()): ** WHERE_USE_LIMIT == SF_FixedLimit */ #define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */ #define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */ #define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */ #define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ #define WHERE_ONEPASS_MULTIROW 0x0008 /* ONEPASS is ok with multiple rows */ #define WHERE_DUPLICATES_OK 0x0010 /* Ok to return a row more than once */ #define WHERE_OR_SUBCLAUSE 0x0020 /* Processing a sub-WHERE as part of ** the OR optimization */ #define WHERE_GROUPBY 0x0040 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */ #define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ #define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */ #define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ #define WHERE_RIGHT_JOIN 0x1000 /* Processing a RIGHT JOIN */ /* 0x2000 not currently used */ #define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ /* 0x8000 not currently used */ /* Allowed return values from sqlite3WhereIsDistinct() */ #define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ #define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */ #define WHERE_DISTINCT_ORDERED 2 /* All duplicates are adjacent */ #define WHERE_DISTINCT_UNORDERED 3 /* Duplicates are scattered */ /* ** A NameContext defines a context in which to resolve table and column ** names. The context consists of a list of tables (the pSrcList) field and ** a list of named expression (pEList). The named expression list may ** be NULL. The pSrc corresponds to the FROM clause of a SELECT or ** to the table being operated on by INSERT, UPDATE, or DELETE. The ** pEList corresponds to the result set of a SELECT and is NULL for ** other statements. ** ** NameContexts can be nested. When resolving names, the inner-most ** context is searched first. If no match is found, the next outer ** context is checked. If there is still no match, the next context ** is checked. This process continues until either a match is found ** or all contexts are check. When a match is found, the nRef member of ** the context containing the match is incremented. ** ** Each subquery gets a new NameContext. The pNext field points to the ** NameContext in the parent query. Thus the process of scanning the ** NameContext list corresponds to searching through successively outer ** subqueries looking for a match. */ struct NameContext { Parse *pParse; /* The parser */ SrcList *pSrcList; /* One or more tables used to resolve names */ union { ExprList *pEList; /* Optional list of result-set columns */ AggInfo *pAggInfo; /* Information about aggregates at this level */ Upsert *pUpsert; /* ON CONFLICT clause information from an upsert */ int iBaseReg; /* For TK_REGISTER when parsing RETURNING */ } uNC; NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ int nNcErr; /* Number of errors encountered while resolving names */ int ncFlags; /* Zero or more NC_* flags defined below */ u32 nNestedSelect; /* Number of nested selects using this NC */ Select *pWinSelect; /* SELECT statement for any window functions */ }; /* ** Allowed values for the NameContext, ncFlags field. ** ** Value constraints (all checked via assert()): ** NC_HasAgg == SF_HasAgg == EP_Agg ** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX ** NC_OrderAgg == SF_OrderByReqd == SQLITE_FUNC_ANYORDER ** NC_HasWin == EP_Win ** */ #define NC_AllowAgg 0x000001 /* Aggregate functions are allowed here */ #define NC_PartIdx 0x000002 /* True if resolving a partial index WHERE */ #define NC_IsCheck 0x000004 /* True if resolving a CHECK constraint */ #define NC_GenCol 0x000008 /* True for a GENERATED ALWAYS AS clause */ #define NC_HasAgg 0x000010 /* One or more aggregate functions seen */ #define NC_IdxExpr 0x000020 /* True if resolving columns of CREATE INDEX */ #define NC_SelfRef 0x00002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */ #define NC_Subquery 0x000040 /* A subquery has been seen */ #define NC_UEList 0x000080 /* True if uNC.pEList is used */ #define NC_UAggInfo 0x000100 /* True if uNC.pAggInfo is used */ #define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */ #define NC_UBaseReg 0x000400 /* True if uNC.iBaseReg is used */ #define NC_MinMaxAgg 0x001000 /* min/max aggregates seen. See note above */ #define NC_Complex 0x002000 /* True if a function or subquery seen */ #define NC_AllowWin 0x004000 /* Window functions are allowed here */ #define NC_HasWin 0x008000 /* One or more window functions seen */ #define NC_IsDDL 0x010000 /* Resolving names in a CREATE statement */ #define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */ #define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */ #define NC_NoSelect 0x080000 /* Do not descend into sub-selects */ #define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */ /* ** An instance of the following object describes a single ON CONFLICT ** clause in an upsert. ** ** The pUpsertTarget field is only set if the ON CONFLICT clause includes ** conflict-target clause. (In "ON CONFLICT(a,b)" the "(a,b)" is the ** conflict-target clause.) The pUpsertTargetWhere is the optional ** WHERE clause used to identify partial unique indexes. ** ** pUpsertSet is the list of column=expr terms of the UPDATE statement. ** The pUpsertSet field is NULL for a ON CONFLICT DO NOTHING. The ** pUpsertWhere is the WHERE clause for the UPDATE and is NULL if the ** WHERE clause is omitted. */ struct Upsert { ExprList *pUpsertTarget; /* Optional description of conflict target */ Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */ ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */ Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */ Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */ u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */ /* Above this point is the parse tree for the ON CONFLICT clauses. ** The next group of fields stores intermediate data. */ void *pToFree; /* Free memory when deleting the Upsert object */ /* All fields above are owned by the Upsert object and must be freed ** when the Upsert is destroyed. The fields below are used to transfer ** information from the INSERT processing down into the UPDATE processing ** while generating code. The fields below are owned by the INSERT ** statement and will be freed by INSERT processing. */ Index *pUpsertIdx; /* UNIQUE constraint specified by pUpsertTarget */ SrcList *pUpsertSrc; /* Table to be updated */ int regData; /* First register holding array of VALUES */ int iDataCur; /* Index of the data cursor */ int iIdxCur; /* Index of the first index cursor */ }; /* ** An instance of the following structure contains all information ** needed to generate code for a single SELECT statement. ** ** See the header comment on the computeLimitRegisters() routine for a ** detailed description of the meaning of the iLimit and iOffset fields. ** ** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes. ** These addresses must be stored so that we can go back and fill in ** the P4_KEYINFO and P2 parameters later. Neither the KeyInfo nor ** the number of columns in P2 can be computed at the same time ** as the OP_OpenEphm instruction is coded because not ** enough information about the compound query is known at that point. ** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences ** for the result set. The KeyInfo for addrOpenEphm[2] contains collating ** sequences for the ORDER BY clause. */ struct Select { u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ LogEst nSelectRow; /* Estimated number of result rows */ u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ u32 selId; /* Unique identifier number for this SELECT */ int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ ExprList *pEList; /* The fields of the result */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ Expr *pHaving; /* The HAVING clause */ ExprList *pOrderBy; /* The ORDER BY clause */ Select *pPrior; /* Prior select in a compound select statement */ Select *pNext; /* Next select to the left in a compound */ Expr *pLimit; /* LIMIT expression. NULL means not used. */ With *pWith; /* WITH clause attached to this select. Or NULL. */ #ifndef SQLITE_OMIT_WINDOWFUNC Window *pWin; /* List of window functions */ Window *pWinDefn; /* List of named window definitions */ #endif }; /* ** Allowed values for Select.selFlags. The "SF" prefix stands for ** "Select Flag". ** ** Value constraints (all checked via assert()) ** SF_HasAgg == NC_HasAgg ** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX ** SF_OrderByReqd == NC_OrderAgg == SQLITE_FUNC_ANYORDER ** SF_FixedLimit == WHERE_USE_LIMIT */ #define SF_Distinct 0x0000001 /* Output should be DISTINCT */ #define SF_All 0x0000002 /* Includes the ALL keyword */ #define SF_Resolved 0x0000004 /* Identifiers have been resolved */ #define SF_Aggregate 0x0000008 /* Contains agg functions or a GROUP BY */ #define SF_HasAgg 0x0000010 /* Contains aggregate functions */ #define SF_UsesEphemeral 0x0000020 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0000040 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0000080 /* FROM subqueries have Table metadata */ #define SF_Compound 0x0000100 /* Part of a compound query */ #define SF_Values 0x0000200 /* Synthesized from VALUES clause */ #define SF_MultiValue 0x0000400 /* Single VALUES term with multiple rows */ #define SF_NestedFrom 0x0000800 /* Part of a parenthesized FROM clause */ #define SF_MinMaxAgg 0x0001000 /* Aggregate containing min() or max() */ #define SF_Recursive 0x0002000 /* The recursive part of a recursive CTE */ #define SF_FixedLimit 0x0004000 /* nSelectRow set by a constant LIMIT */ #define SF_MaybeConvert 0x0008000 /* Need convertCompoundSelectToSubquery() */ #define SF_Converted 0x0010000 /* By convertCompoundSelectToSubquery() */ #define SF_IncludeHidden 0x0020000 /* Include hidden columns in output */ #define SF_ComplexResult 0x0040000 /* Result contains subquery or function */ #define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */ #define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */ #define SF_View 0x0200000 /* SELECT statement is a view */ #define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ #define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */ #define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */ #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */ #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */ #define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */ /* True if S exists and has SF_NestedFrom */ #define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0) /* ** The results of a SELECT can be distributed in several ways, as defined ** by one of the following macros. The "SRT" prefix means "SELECT Result ** Type". ** ** SRT_Union Store results as a key in a temporary index ** identified by pDest->iSDParm. ** ** SRT_Except Remove results from the temporary index pDest->iSDParm. ** ** SRT_Exists Store a 1 in memory cell pDest->iSDParm if the result ** set is not empty. ** ** SRT_Discard Throw the results away. This is used by SELECT ** statements within triggers whose only purpose is ** the side-effects of functions. ** ** SRT_Output Generate a row of output (using the OP_ResultRow ** opcode) for each row in the result set. ** ** SRT_Mem Only valid if the result is a single column. ** Store the first column of the first result row ** in register pDest->iSDParm then abandon the rest ** of the query. This destination implies "LIMIT 1". ** ** SRT_Set The result must be a single column. Store each ** row of result as the key in table pDest->iSDParm. ** Apply the affinity pDest->affSdst before storing ** results. Used to implement "IN (SELECT ...)". ** ** SRT_EphemTab Create an temporary table pDest->iSDParm and store ** the result there. The cursor is left open after ** returning. This is like SRT_Table except that ** this destination uses OP_OpenEphemeral to create ** the table first. ** ** SRT_Coroutine Generate a co-routine that returns a new row of ** results each time it is invoked. The entry point ** of the co-routine is stored in register pDest->iSDParm ** and the result row is stored in pDest->nDest registers ** starting with pDest->iSdst. ** ** SRT_Table Store results in temporary table pDest->iSDParm. ** SRT_Fifo This is like SRT_EphemTab except that the table ** is assumed to already be open. SRT_Fifo has ** the additional property of being able to ignore ** the ORDER BY clause. ** ** SRT_DistFifo Store results in a temporary table pDest->iSDParm. ** But also use temporary table pDest->iSDParm+1 as ** a record of all prior results and ignore any duplicate ** rows. Name means: "Distinct Fifo". ** ** SRT_Queue Store results in priority queue pDest->iSDParm (really ** an index). Append a sequence number so that all entries ** are distinct. ** ** SRT_DistQueue Store results in priority queue pDest->iSDParm only if ** the same record has never been stored before. The ** index at pDest->iSDParm+1 hold all prior stores. ** ** SRT_Upfrom Store results in the temporary table already opened by ** pDest->iSDParm. If (pDest->iSDParm<0), then the temp ** table is an intkey table - in this case the first ** column returned by the SELECT is used as the integer ** key. If (pDest->iSDParm>0), then the table is an index ** table. (pDest->iSDParm) is the number of key columns in ** each index record in this case. */ #define SRT_Union 1 /* Store result as keys in an index */ #define SRT_Except 2 /* Remove result from a UNION index */ #define SRT_Exists 3 /* Store 1 if the result is not empty */ #define SRT_Discard 4 /* Do not save the results anywhere */ #define SRT_DistFifo 5 /* Like SRT_Fifo, but unique results only */ #define SRT_DistQueue 6 /* Like SRT_Queue, but unique results only */ /* The DISTINCT clause is ignored for all of the above. Not that ** IgnorableDistinct() implies IgnorableOrderby() */ #define IgnorableDistinct(X) ((X->eDest)<=SRT_DistQueue) #define SRT_Queue 7 /* Store result in an queue */ #define SRT_Fifo 8 /* Store result as data with an automatic rowid */ /* The ORDER BY clause is ignored for all of the above */ #define IgnorableOrderby(X) ((X->eDest)<=SRT_Fifo) #define SRT_Output 9 /* Output each row of result */ #define SRT_Mem 10 /* Store result in a memory cell */ #define SRT_Set 11 /* Store results as keys in an index */ #define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */ #define SRT_Coroutine 13 /* Generate a single row of result */ #define SRT_Table 14 /* Store result as data with an automatic rowid */ #define SRT_Upfrom 15 /* Store result as data with rowid */ /* ** An instance of this object describes where to put of the results of ** a SELECT statement. */ struct SelectDest { u8 eDest; /* How to dispose of the results. One of SRT_* above. */ int iSDParm; /* A parameter used by the eDest disposal method */ int iSDParm2; /* A second parameter for the eDest disposal method */ int iSdst; /* Base register where results are written */ int nSdst; /* Number of registers allocated */ char *zAffSdst; /* Affinity used for SRT_Set */ ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */ }; /* ** During code generation of statements that do inserts into AUTOINCREMENT ** tables, the following information is attached to the Table.u.autoInc.p ** pointer of each autoincrement table to record some side information that ** the code generator needs. We have to keep per-table autoincrement ** information in case inserts are done within triggers. Triggers do not ** normally coordinate their activities, but we do need to coordinate the ** loading and saving of autoincrement information. */ struct AutoincInfo { AutoincInfo *pNext; /* Next info block in a list of them all */ Table *pTab; /* Table this info block refers to */ int iDb; /* Index in sqlite3.aDb[] of database holding pTab */ int regCtr; /* Memory register holding the rowid counter */ }; /* ** At least one instance of the following structure is created for each ** trigger that may be fired while parsing an INSERT, UPDATE or DELETE ** statement. All such objects are stored in the linked list headed at ** Parse.pTriggerPrg and deleted once statement compilation has been ** completed. ** ** A Vdbe sub-program that implements the body and WHEN clause of trigger ** TriggerPrg.pTrigger, assuming a default ON CONFLICT clause of ** TriggerPrg.orconf, is stored in the TriggerPrg.pProgram variable. ** The Parse.pTriggerPrg list never contains two entries with the same ** values for both pTrigger and orconf. ** ** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns ** accessed (or set to 0 for triggers fired as a result of INSERT ** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to ** a mask of new.* columns used by the program. */ struct TriggerPrg { Trigger *pTrigger; /* Trigger this program was coded from */ TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */ SubProgram *pProgram; /* Program implementing pTrigger/orconf */ int orconf; /* Default ON CONFLICT policy */ u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */ }; /* ** The yDbMask datatype for the bitmask of all attached databases. */ #if SQLITE_MAX_ATTACHED>30 typedef unsigned char yDbMask[(SQLITE_MAX_ATTACHED+9)/8]; # define DbMaskTest(M,I) (((M)[(I)/8]&(1<<((I)&7)))!=0) # define DbMaskZero(M) memset((M),0,sizeof(M)) # define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7)) # define DbMaskAllZero(M) sqlite3DbMaskAllZero(M) # define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0) #else typedef unsigned int yDbMask; # define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0) # define DbMaskZero(M) ((M)=0) # define DbMaskSet(M,I) ((M)|=(((yDbMask)1)<<(I))) # define DbMaskAllZero(M) ((M)==0) # define DbMaskNonZero(M) ((M)!=0) #endif /* ** For each index X that has as one of its arguments either an expression ** or the name of a virtual generated column, and if X is in scope such that ** the value of the expression can simply be read from the index, then ** there is an instance of this object on the Parse.pIdxExpr list. ** ** During code generation, while generating code to evaluate expressions, ** this list is consulted and if a matching expression is found, the value ** is read from the index rather than being recomputed. */ struct IndexedExpr { Expr *pExpr; /* The expression contained in the index */ int iDataCur; /* The data cursor associated with the index */ int iIdxCur; /* The index cursor */ int iIdxCol; /* The index column that contains value of pExpr */ u8 bMaybeNullRow; /* True if we need an OP_IfNullRow check */ u8 aff; /* Affinity of the pExpr expression */ IndexedExpr *pIENext; /* Next in a list of all indexed expressions */ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS const char *zIdxName; /* Name of index, used only for bytecode comments */ #endif }; /* ** An instance of the ParseCleanup object specifies an operation that ** should be performed after parsing to deallocation resources obtained ** during the parse and which are no longer needed. */ struct ParseCleanup { ParseCleanup *pNext; /* Next cleanup task */ void *pPtr; /* Pointer to object to deallocate */ void (*xCleanup)(sqlite3*,void*); /* Deallocation routine */ }; /* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to ** carry around information that is global to the entire parse. ** ** The structure is divided into two parts. When the parser and code ** generate call themselves recursively, the first part of the structure ** is constant but the second part is reset at the beginning and end of ** each recursion. ** ** The nTableLock and aTableLock variables are only used if the shared-cache ** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are ** used to store the set of table-locks required by the statement being ** compiled. Function sqlite3TableLock() is used to add entries to the ** list. */ struct Parse { sqlite3 *db; /* The main database structure */ char *zErrMsg; /* An error message */ Vdbe *pVdbe; /* An engine for executing database bytecode */ int rc; /* Return code from execution */ u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif #ifdef SQLITE_DEBUG u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */ #endif int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ int iSelfTab; /* Table associated with an index on expr, or negative ** of the base register during check-constraint eval */ int nLabel; /* The *negative* of the number of labels used */ int nLabelAlloc; /* Number of slots in aLabel */ int *aLabel; /* Space to hold the labels */ ExprList *pConstExpr;/* Constant expressions */ IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */ IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */ Token constraintName;/* Name of the constraint currently being parsed */ yDbMask writeMask; /* Start a write transaction on these databases */ yDbMask cookieMask; /* Bitmask of schema verified databases */ int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ int nMaxArg; /* Max args passed to user function by sub-program */ int nSelect; /* Number of SELECT stmts. Counter for Select.selId */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */ #endif #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ #endif AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ union { int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ Returning *pReturning; /* The RETURNING clause */ } u1; u32 oldmask; /* Mask of old.* columns referenced */ u32 newmask; /* Mask of new.* columns referenced */ LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ u8 bReturning; /* Coding a RETURNING trigger */ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ u8 disableTriggers; /* True to disable triggers */ /************************************************************************** ** Fields above must be initialized to zero. The fields that follow, ** down to the beginning of the recursive section, do not need to be ** initialized as they will be set before being used. The boundary is ** determined by offsetof(Parse,aTempReg). **************************************************************************/ int aTempReg[8]; /* Holding area for temporary registers */ Parse *pOuterParse; /* Outer Parse object when nested */ Token sNameToken; /* Token with unqualified schema object name */ /************************************************************************ ** Above is constant between recursions. Below is reset before and after ** each recursion. The boundary between these two regions is determined ** using offsetof(Parse,sLastToken) so the sLastToken field must be the ** first field in the recursive region. ************************************************************************/ Token sLastToken; /* The last token parsed */ ynVar nVar; /* Number of '?' variables seen in the SQL so far */ u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ u8 explain; /* True if the EXPLAIN flag is found on the query */ u8 eParseMode; /* PARSE_MODE_XXX constant */ #ifndef SQLITE_OMIT_VIRTUALTABLE int nVtabLock; /* Number of virtual tables to lock */ #endif int nHeight; /* Expression tree height of current sub-select */ #ifndef SQLITE_OMIT_EXPLAIN int addrExplain; /* Address of current OP_Explain opcode */ #endif VList *pVList; /* Mapping between variable names and numbers */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ Index *pNewIndex; /* An index being constructed by CREATE INDEX. ** Also used to hold redundant UNIQUE constraints ** during a RENAME COLUMN */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ #ifndef SQLITE_OMIT_VIRTUALTABLE Token sArg; /* Complete text of a module argument */ Table **apVtabLock; /* Pointer to virtual tables needing locking */ #endif With *pWith; /* Current WITH clause, or NULL */ #ifndef SQLITE_OMIT_ALTERTABLE RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */ #endif }; /* Allowed values for Parse.eParseMode */ #define PARSE_MODE_NORMAL 0 #define PARSE_MODE_DECLARE_VTAB 1 #define PARSE_MODE_RENAME 2 #define PARSE_MODE_UNMAP 3 /* ** Sizes and pointers of various parts of the Parse object. */ #define PARSE_HDR(X) (((char*)(X))+offsetof(Parse,zErrMsg)) #define PARSE_HDR_SZ (offsetof(Parse,aTempReg)-offsetof(Parse,zErrMsg)) /* Recursive part w/o aColCache*/ #define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */ #define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */ #define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */ /* ** Return true if currently inside an sqlite3_declare_vtab() call. */ #ifdef SQLITE_OMIT_VIRTUALTABLE #define IN_DECLARE_VTAB 0 #else #define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB) #endif #if defined(SQLITE_OMIT_ALTERTABLE) #define IN_RENAME_OBJECT 0 #else #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME) #endif #if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE) #define IN_SPECIAL_PARSE 0 #else #define IN_SPECIAL_PARSE (pParse->eParseMode!=PARSE_MODE_NORMAL) #endif /* ** An instance of the following structure can be declared on a stack and used ** to save the Parse.zAuthContext value so that it can be restored later. */ struct AuthContext { const char *zAuthContext; /* Put saved Parse.zAuthContext here */ Parse *pParse; /* The Parse structure */ }; /* ** Bitfield flags for P5 value in various opcodes. ** ** Value constraints (enforced via assert()): ** OPFLAG_LENGTHARG == SQLITE_FUNC_LENGTH ** OPFLAG_TYPEOFARG == SQLITE_FUNC_TYPEOF ** OPFLAG_BULKCSR == BTREE_BULKLOAD ** OPFLAG_SEEKEQ == BTREE_SEEK_EQ ** OPFLAG_FORDELETE == BTREE_FORDELETE ** OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION ** OPFLAG_AUXDELETE == BTREE_AUXDELETE */ #define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */ /* Also used in P2 (not P5) of OP_Delete */ #define OPFLAG_NOCHNG 0x01 /* OP_VColumn nochange for UPDATE */ #define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ #define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ #define OPFLAG_APPEND 0x08 /* This is likely to be an append */ #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ #define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */ #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ #define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ #define OPFLAG_BYTELENARG 0xc0 /* OP_Column only for octet_length() */ #define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ #define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */ #define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */ #define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */ #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ #define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */ #define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */ #define OPFLAG_NOCHNG_MAGIC 0x6d /* OP_MakeRecord: serialtype 10 is ok */ #define OPFLAG_PREFORMAT 0x80 /* OP_Insert uses preformatted cell */ /* ** Each trigger present in the database schema is stored as an instance of ** struct Trigger. ** ** Pointers to instances of struct Trigger are stored in two ways. ** 1. In the "trigHash" hash table (part of the sqlite3* that represents the ** database). This allows Trigger structures to be retrieved by name. ** 2. All triggers associated with a single table form a linked list, using the ** pNext member of struct Trigger. A pointer to the first element of the ** linked list is stored as the "pTrigger" member of the associated ** struct Table. ** ** The "step_list" member points to the first element of a linked list ** containing the SQL statements specified as the trigger program. */ struct Trigger { char *zName; /* The name of the trigger */ char *table; /* The table or view to which the trigger applies */ u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */ u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ u8 bReturning; /* This trigger implements a RETURNING clause */ Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */ IdList *pColumns; /* If this is an UPDATE OF trigger, the is stored here */ Schema *pSchema; /* Schema containing the trigger */ Schema *pTabSchema; /* Schema containing the table */ TriggerStep *step_list; /* Link list of trigger program steps */ Trigger *pNext; /* Next trigger associated with the table */ }; /* ** A trigger is either a BEFORE or an AFTER trigger. The following constants ** determine which. ** ** If there are multiple triggers, you might of some BEFORE and some AFTER. ** In that cases, the constants below can be ORed together. */ #define TRIGGER_BEFORE 1 #define TRIGGER_AFTER 2 /* ** An instance of struct TriggerStep is used to store a single SQL statement ** that is a part of a trigger-program. ** ** Instances of struct TriggerStep are stored in a singly linked list (linked ** using the "pNext" member) referenced by the "step_list" member of the ** associated struct Trigger instance. The first element of the linked list is ** the first step of the trigger-program. ** ** The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or ** "SELECT" statement. The meanings of the other members is determined by the ** value of "op" as follows: ** ** (op == TK_INSERT) ** orconf -> stores the ON CONFLICT algorithm ** pSelect -> The content to be inserted - either a SELECT statement or ** a VALUES clause. ** zTarget -> Dequoted name of the table to insert into. ** pIdList -> If this is an INSERT INTO ... () VALUES ... ** statement, then this stores the column-names to be ** inserted into. ** pUpsert -> The ON CONFLICT clauses for an Upsert ** ** (op == TK_DELETE) ** zTarget -> Dequoted name of the table to delete from. ** pWhere -> The WHERE clause of the DELETE statement if one is specified. ** Otherwise NULL. ** ** (op == TK_UPDATE) ** zTarget -> Dequoted name of the table to update. ** pWhere -> The WHERE clause of the UPDATE statement if one is specified. ** Otherwise NULL. ** pExprList -> A list of the columns to update and the expressions to update ** them to. See sqlite3Update() documentation of "pChanges" ** argument. ** ** (op == TK_SELECT) ** pSelect -> The SELECT statement ** ** (op == TK_RETURNING) ** pExprList -> The list of expressions that follow the RETURNING keyword. ** */ struct TriggerStep { u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT, ** or TK_RETURNING */ u8 orconf; /* OE_Rollback etc. */ Trigger *pTrig; /* The trigger that this step is a part of */ Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */ char *zTarget; /* Target table for DELETE, UPDATE, INSERT */ SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */ Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ ExprList *pExprList; /* SET clause for UPDATE, or RETURNING clause */ IdList *pIdList; /* Column names for INSERT */ Upsert *pUpsert; /* Upsert clauses on an INSERT */ char *zSpan; /* Original SQL text of this command */ TriggerStep *pNext; /* Next in the link-list */ TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */ }; /* ** Information about a RETURNING clause */ struct Returning { Parse *pParse; /* The parse that includes the RETURNING clause */ ExprList *pReturnEL; /* List of expressions to return */ Trigger retTrig; /* The transient trigger that implements RETURNING */ TriggerStep retTStep; /* The trigger step */ int iRetCur; /* Transient table holding RETURNING results */ int nRetCol; /* Number of in pReturnEL after expansion */ int iRetReg; /* Register array for holding a row of RETURNING */ char zName[40]; /* Name of trigger: "sqlite_returning_%p" */ }; /* ** An objected used to accumulate the text of a string where we ** do not necessarily know how big the string will be in the end. */ struct sqlite3_str { sqlite3 *db; /* Optional database for lookaside. Can be NULL */ char *zText; /* The string collected so far */ u32 nAlloc; /* Amount of space allocated in zText */ u32 mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */ u32 nChar; /* Length of the string so far */ u8 accError; /* SQLITE_NOMEM or SQLITE_TOOBIG */ u8 printfFlags; /* SQLITE_PRINTF flags below */ }; #define SQLITE_PRINTF_INTERNAL 0x01 /* Internal-use-only converters allowed */ #define SQLITE_PRINTF_SQLFUNC 0x02 /* SQL function arguments to VXPrintf */ #define SQLITE_PRINTF_MALLOCED 0x04 /* True if xText is allocated space */ #define isMalloced(X) (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0) /* ** The following object is the header for an "RCStr" or "reference-counted ** string". An RCStr is passed around and used like any other char* ** that has been dynamically allocated. The important interface ** differences: ** ** 1. RCStr strings are reference counted. They are deallocated ** when the reference count reaches zero. ** ** 2. Use sqlite3RCStrUnref() to free an RCStr string rather than ** sqlite3_free() ** ** 3. Make a (read-only) copy of a read-only RCStr string using ** sqlite3RCStrRef(). ** ** "String" is in the name, but an RCStr object can also be used to hold ** binary data. */ struct RCStr { u64 nRCRef; /* Number of references */ /* Total structure size should be a multiple of 8 bytes for alignment */ }; /* ** A pointer to this structure is used to communicate information ** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback. */ typedef struct { sqlite3 *db; /* The database being initialized */ char **pzErrMsg; /* Error message stored here */ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ int rc; /* Result code stored here */ u32 mInitFlags; /* Flags controlling error messages */ u32 nInitRow; /* Number of rows processed */ Pgno mxPage; /* Maximum page number. 0 for no limit. */ } InitData; /* ** Allowed values for mInitFlags */ #define INITFLAG_AlterMask 0x0003 /* Types of ALTER */ #define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */ #define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */ #define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */ /* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled ** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning ** parameters are for temporary use during development, to help find ** optimal values for parameters in the query planner. The should not ** be used on trunk check-ins. They are a temporary mechanism available ** for transient development builds only. ** ** Tuning parameters are numbered starting with 1. */ #define SQLITE_NTUNE 6 /* Should be zero for all trunk check-ins */ #ifdef SQLITE_DEBUG # define Tuning(X) (sqlite3Config.aTune[(X)-1]) #else # define Tuning(X) 0 #endif /* ** Structure containing global configuration data for the SQLite library. ** ** This structure also contains some state information. */ struct Sqlite3Config { int bMemstat; /* True to enable memory status */ u8 bCoreMutex; /* True to enable core mutexing */ u8 bFullMutex; /* True to enable full mutexing */ u8 bOpenUri; /* True to interpret filenames as URIs */ u8 bUseCis; /* Use covering indices for full-scans */ u8 bSmallMalloc; /* Avoid large memory allocations if true */ u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */ u8 bUseLongDouble; /* Make use of long double */ #ifdef SQLITE_DEBUG u8 bJsonSelfcheck; /* Double-check JSON parsing */ #endif int mxStrlen; /* Maximum string length */ int neverCorrupt; /* Database is always well-formed */ int szLookaside; /* Default lookaside buffer size */ int nLookaside; /* Default lookaside buffer count */ int nStmtSpill; /* Stmt-journal spill-to-disk threshold */ sqlite3_mem_methods m; /* Low-level memory allocation interface */ sqlite3_mutex_methods mutex; /* Low-level mutex interface */ sqlite3_pcache_methods2 pcache2; /* Low-level page-cache interface */ void *pHeap; /* Heap storage space */ int nHeap; /* Size of pHeap[] */ int mnReq, mxReq; /* Min and max heap requests sizes */ sqlite3_int64 szMmap; /* mmap() space per open file */ sqlite3_int64 mxMmap; /* Maximum value for szMmap */ void *pPage; /* Page cache memory */ int szPage; /* Size of each page in pPage[] */ int nPage; /* Number of pages in pPage[] */ int mxParserStack; /* maximum depth of the parser stack */ int sharedCacheEnabled; /* true if shared-cache mode enabled */ u32 szPma; /* Maximum Sorter PMA size */ /* The above might be initialized to non-zero. The following need to always ** initially be zero, however. */ int isInit; /* True after initialization has finished */ int inProgress; /* True while initialization in progress */ int isMutexInit; /* True after mutexes are initialized */ int isMallocInit; /* True after malloc is initialized */ int isPCacheInit; /* True after malloc is initialized */ int nRefInitMutex; /* Number of users of pInitMutex */ sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ void (*xLog)(void*,int,const char*); /* Function for logging */ void *pLogArg; /* First argument to xLog() */ #ifdef SQLITE_ENABLE_SQLLOG void(*xSqllog)(void*,sqlite3*,const char*, int); void *pSqllogArg; #endif #ifdef SQLITE_VDBE_COVERAGE /* The following callback (if not NULL) is invoked on every VDBE branch ** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE. */ void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif #ifndef SQLITE_OMIT_DESERIALIZE sqlite3_int64 mxMemdbSize; /* Default max memdb size */ #endif #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif int bLocaltimeFault; /* True to fail localtime() calls */ int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */ int iOnceResetThreshold; /* When to reset OP_Once counters */ u32 szSorterRef; /* Min size in bytes to use sorter-refs */ unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */ /* vvvv--- must be last ---vvv */ #ifdef SQLITE_DEBUG sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */ #endif }; /* ** This macro is used inside of assert() statements to indicate that ** the assert is only valid on a well-formed database. Instead of: ** ** assert( X ); ** ** One writes: ** ** assert( X || CORRUPT_DB ); ** ** CORRUPT_DB is true during normal operation. CORRUPT_DB does not indicate ** that the database is definitely corrupt, only that it might be corrupt. ** For most test cases, CORRUPT_DB is set to false using a special ** sqlite3_test_control(). This enables assert() statements to prove ** things that are always true for well-formed databases. */ #define CORRUPT_DB (sqlite3Config.neverCorrupt==0) /* ** Context pointer passed down through the tree-walk. */ struct Walker { Parse *pParse; /* Parser context. */ int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */ int walkerDepth; /* Number of subqueries */ u16 eCode; /* A small processing code */ u16 mWFlags; /* Use-dependent flags */ union { /* Extra data for callback */ NameContext *pNC; /* Naming context */ int n; /* A counter */ int iCur; /* A cursor number */ SrcList *pSrcList; /* FROM clause */ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */ int *aiCol; /* array of column indexes */ struct IdxCover *pIdxCover; /* Check for index coverage */ ExprList *pGroupBy; /* GROUP BY clause */ Select *pSelect; /* HAVING to WHERE clause ctx */ struct WindowRewrite *pRewrite; /* Window rewrite context */ struct WhereConst *pConst; /* WHERE clause constants */ struct RenameCtx *pRename; /* RENAME COLUMN context */ struct Table *pTab; /* Table of generated column */ struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */ SrcItem *pSrcItem; /* A single FROM clause item */ DbFixer *pFix; /* See sqlite3FixSelect() */ Mem *aMem; /* See sqlite3BtreeCursorHint() */ } u; }; /* ** The following structure contains information used by the sqliteFix... ** routines as they walk the parse tree to make database references ** explicit. */ struct DbFixer { Parse *pParse; /* The parsing context. Error messages written here */ Walker w; /* Walker object */ Schema *pSchema; /* Fix items to this schema */ u8 bTemp; /* True for TEMP schema entries */ const char *zDb; /* Make sure all objects are contained in this database */ const char *zType; /* Type of the container - used for error messages */ const Token *pName; /* Name of the container - used for error messages */ }; /* Forward declarations */ SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*); SQLITE_PRIVATE int sqlite3WalkExprNN(Walker*, Expr*); SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*); SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*); SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*); SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*); SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*); SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*); SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*); SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker*,Select*); SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker*,Select*); SQLITE_PRIVATE void sqlite3WalkWinDefnDummyCallback(Walker*,Select*); #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*); #endif #ifndef SQLITE_OMIT_CTE SQLITE_PRIVATE void sqlite3SelectPopWith(Walker*, Select*); #else # define sqlite3SelectPopWith 0 #endif /* ** Return code from the parse-tree walking primitives and their ** callbacks. */ #define WRC_Continue 0 /* Continue down into children */ #define WRC_Prune 1 /* Omit children but continue walking siblings */ #define WRC_Abort 2 /* Abandon the tree walk */ /* ** A single common table expression */ struct Cte { char *zName; /* Name of this CTE */ ExprList *pCols; /* List of explicit column names, or NULL */ Select *pSelect; /* The definition of this CTE */ const char *zCteErr; /* Error message for circular references */ CteUse *pUse; /* Usage information for this CTE */ u8 eM10d; /* The MATERIALIZED flag */ }; /* ** Allowed values for the materialized flag (eM10d): */ #define M10d_Yes 0 /* AS MATERIALIZED */ #define M10d_Any 1 /* Not specified. Query planner's choice */ #define M10d_No 2 /* AS NOT MATERIALIZED */ /* ** An instance of the With object represents a WITH clause containing ** one or more CTEs (common table expressions). */ struct With { int nCte; /* Number of CTEs in the WITH clause */ int bView; /* Belongs to the outermost Select of a view */ With *pOuter; /* Containing WITH clause, or NULL */ Cte a[1]; /* For each CTE in the WITH clause.... */ }; /* ** The Cte object is not guaranteed to persist for the entire duration ** of code generation. (The query flattener or other parser tree ** edits might delete it.) The following object records information ** about each Common Table Expression that must be preserved for the ** duration of the parse. ** ** The CteUse objects are freed using sqlite3ParserAddCleanup() rather ** than sqlite3SelectDelete(), which is what enables them to persist ** until the end of code generation. */ struct CteUse { int nUse; /* Number of users of this CTE */ int addrM9e; /* Start of subroutine to compute materialization */ int regRtn; /* Return address register for addrM9e subroutine */ int iCur; /* Ephemeral table holding the materialization */ LogEst nRowEst; /* Estimated number of rows in the table */ u8 eM10d; /* The MATERIALIZED flag */ }; /* Client data associated with sqlite3_set_clientdata() and ** sqlite3_get_clientdata(). */ struct DbClientData { DbClientData *pNext; /* Next in a linked list */ void *pData; /* The data */ void (*xDestructor)(void*); /* Destructor. Might be NULL */ char zName[1]; /* Name of this client data. MUST BE LAST */ }; #ifdef SQLITE_DEBUG /* ** An instance of the TreeView object is used for printing the content of ** data structures on sqlite3DebugPrintf() using a tree-like view. */ struct TreeView { int iLevel; /* Which level of the tree we are on */ u8 bLine[100]; /* Draw vertical in column i if bLine[i] is true */ }; #endif /* SQLITE_DEBUG */ /* ** This object is used in various ways, most (but not all) related to window ** functions. ** ** (1) A single instance of this structure is attached to the ** the Expr.y.pWin field for each window function in an expression tree. ** This object holds the information contained in the OVER clause, ** plus additional fields used during code generation. ** ** (2) All window functions in a single SELECT form a linked-list ** attached to Select.pWin. The Window.pFunc and Window.pExpr ** fields point back to the expression that is the window function. ** ** (3) The terms of the WINDOW clause of a SELECT are instances of this ** object on a linked list attached to Select.pWinDefn. ** ** (4) For an aggregate function with a FILTER clause, an instance ** of this object is stored in Expr.y.pWin with eFrmType set to ** TK_FILTER. In this case the only field used is Window.pFilter. ** ** The uses (1) and (2) are really the same Window object that just happens ** to be accessible in two different ways. Use case (3) are separate objects. */ struct Window { char *zName; /* Name of window (may be NULL) */ char *zBase; /* Name of base window for chaining (may be NULL) */ ExprList *pPartition; /* PARTITION BY clause */ ExprList *pOrderBy; /* ORDER BY clause */ u8 eFrmType; /* TK_RANGE, TK_GROUPS, TK_ROWS, or 0 */ u8 eStart; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ u8 eEnd; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ u8 bImplicitFrame; /* True if frame was implicitly specified */ u8 eExclude; /* TK_NO, TK_CURRENT, TK_TIES, TK_GROUP, or 0 */ Expr *pStart; /* Expression for " PRECEDING" */ Expr *pEnd; /* Expression for " FOLLOWING" */ Window **ppThis; /* Pointer to this object in Select.pWin list */ Window *pNextWin; /* Next window function belonging to this SELECT */ Expr *pFilter; /* The FILTER expression */ FuncDef *pWFunc; /* The function */ int iEphCsr; /* Partition buffer or Peer buffer */ int regAccum; /* Accumulator */ int regResult; /* Interim result */ int csrApp; /* Function cursor (used by min/max) */ int regApp; /* Function register (also used by min/max) */ int regPart; /* Array of registers for PARTITION BY values */ Expr *pOwner; /* Expression object this window is attached to */ int nBufferCol; /* Number of columns in buffer table */ int iArgCol; /* Offset of first argument for this function */ int regOne; /* Register containing constant value 1 */ int regStartRowid; int regEndRowid; u8 bExprArgs; /* Defer evaluation of window function arguments ** due to the SQLITE_SUBTYPE flag */ }; #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*); SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window*); SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p); SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*); SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin); SQLITE_PRIVATE int sqlite3WindowCompare(const Parse*, const Window*, const Window*, int); SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Select*); SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*); SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*); SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p); SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p); SQLITE_PRIVATE void sqlite3WindowFunctions(void); SQLITE_PRIVATE void sqlite3WindowChain(Parse*, Window*, Window*); SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprList*, Token*); #else # define sqlite3WindowDelete(a,b) # define sqlite3WindowFunctions() # define sqlite3WindowAttach(a,b,c) #endif /* ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. */ #define SQLITE_SKIP_UTF8(zIn) { \ if( (*(zIn++))>=0xc0 ){ \ while( (*zIn & 0xc0)==0x80 ){ zIn++; } \ } \ } /* ** The SQLITE_*_BKPT macros are substitutes for the error codes with ** the same name but without the _BKPT suffix. These macros invoke ** routines that report the line-number on which the error originated ** using sqlite3_log(). The routines also provide a convenient place ** to set a debugger breakpoint. */ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType); SQLITE_PRIVATE int sqlite3CorruptError(int); SQLITE_PRIVATE int sqlite3MisuseError(int); SQLITE_PRIVATE int sqlite3CantopenError(int); #define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__) #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3NomemError(int); SQLITE_PRIVATE int sqlite3IoerrnomemError(int); # define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__) # define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__) #else # define SQLITE_NOMEM_BKPT SQLITE_NOMEM # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); # define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) #else # define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) #endif /* ** FTS3 and FTS4 both require virtual table support */ #if defined(SQLITE_OMIT_VIRTUALTABLE) # undef SQLITE_ENABLE_FTS3 # undef SQLITE_ENABLE_FTS4 #endif /* ** FTS4 is really an extension for FTS3. It is enabled using the ** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also call ** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3. */ #if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3) # define SQLITE_ENABLE_FTS3 1 #endif /* ** The ctype.h header is needed for non-ASCII systems. It is also ** needed by FTS3 when FTS3 is included in the amalgamation. */ #if !defined(SQLITE_ASCII) || \ (defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_AMALGAMATION)) # include #endif /* ** The following macros mimic the standard library functions toupper(), ** isspace(), isalnum(), isdigit() and isxdigit(), respectively. The ** sqlite versions only work for ASCII characters, regardless of locale. */ #ifdef SQLITE_ASCII # define sqlite3Toupper(x) ((x)&~(sqlite3CtypeMap[(unsigned char)(x)]&0x20)) # define sqlite3Isspace(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x01) # define sqlite3Isalnum(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x06) # define sqlite3Isalpha(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x02) # define sqlite3Isdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x04) # define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08) # define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)]) # define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80) # define sqlite3JsonId1(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x42) # define sqlite3JsonId2(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x46) #else # define sqlite3Toupper(x) toupper((unsigned char)(x)) # define sqlite3Isspace(x) isspace((unsigned char)(x)) # define sqlite3Isalnum(x) isalnum((unsigned char)(x)) # define sqlite3Isalpha(x) isalpha((unsigned char)(x)) # define sqlite3Isdigit(x) isdigit((unsigned char)(x)) # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) # define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`') # define sqlite3JsonId1(x) (sqlite3IsIdChar(x)&&(x)<'0') # define sqlite3JsonId2(x) sqlite3IsIdChar(x) #endif SQLITE_PRIVATE int sqlite3IsIdChar(u8); /* ** Internal function prototypes */ SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*); SQLITE_PRIVATE int sqlite3Strlen30(const char*); #define sqlite3Strlen30NN(C) (strlen(C)&0x3fffffff) SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*); #define sqlite3StrNICmp sqlite3_strnicmp SQLITE_PRIVATE int sqlite3MallocInit(void); SQLITE_PRIVATE void sqlite3MallocEnd(void); SQLITE_PRIVATE void *sqlite3Malloc(u64); SQLITE_PRIVATE void *sqlite3MallocZero(u64); SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, u64); SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64); SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3*, u64); SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*); SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64); SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3*,const char*,const char*); SQLITE_PRIVATE void *sqlite3Realloc(void*, u64); SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64); SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*); SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*); SQLITE_PRIVATE void sqlite3DbNNFreeNN(sqlite3*, void*); SQLITE_PRIVATE int sqlite3MallocSize(const void*); SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, const void*); SQLITE_PRIVATE void *sqlite3PageMalloc(int); SQLITE_PRIVATE void sqlite3PageFree(void*); SQLITE_PRIVATE void sqlite3MemSetDefault(void); #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void)); #endif SQLITE_PRIVATE int sqlite3HeapNearlyFull(void); /* ** On systems with ample stack space and that support alloca(), make ** use of alloca() to obtain space for large automatic objects. By default, ** obtain space from malloc(). ** ** The alloca() routine never returns NULL. This will cause code paths ** that deal with sqlite3StackAlloc() failures to be unreachable. */ #ifdef SQLITE_USE_ALLOCA # define sqlite3StackAllocRaw(D,N) alloca(N) # define sqlite3StackAllocRawNN(D,N) alloca(N) # define sqlite3StackFree(D,P) # define sqlite3StackFreeNN(D,P) #else # define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N) # define sqlite3StackAllocRawNN(D,N) sqlite3DbMallocRawNN(D,N) # define sqlite3StackFree(D,P) sqlite3DbFree(D,P) # define sqlite3StackFreeNN(D,P) sqlite3DbFreeNN(D,P) #endif /* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they ** are, disable MEMSYS3 */ #ifdef SQLITE_ENABLE_MEMSYS5 SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); #undef SQLITE_ENABLE_MEMSYS3 #endif #ifdef SQLITE_ENABLE_MEMSYS3 SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); #endif #ifndef SQLITE_MUTEX_OMIT SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void); SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void); SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int); SQLITE_PRIVATE int sqlite3MutexInit(void); SQLITE_PRIVATE int sqlite3MutexEnd(void); #endif #if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP) SQLITE_PRIVATE void sqlite3MemoryBarrier(void); #else # define sqlite3MemoryBarrier() #endif SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int); SQLITE_PRIVATE void sqlite3StatusUp(int, int); SQLITE_PRIVATE void sqlite3StatusDown(int, int); SQLITE_PRIVATE void sqlite3StatusHighwater(int, int); SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*); /* Access to mutexes used by sqlite3_status() */ SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void); SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void); #if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT) SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*); #else # define sqlite3MutexWarnOnContention(x) #endif #ifndef SQLITE_OMIT_FLOATING_POINT # define EXP754 (((u64)0x7ff)<<52) # define MAN754 ((((u64)1)<<52)-1) # define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0) SQLITE_PRIVATE int sqlite3IsNaN(double); #else # define IsNaN(X) 0 # define sqlite3IsNaN(X) 0 #endif /* ** An instance of the following structure holds information about SQL ** functions arguments that are the parameters to the printf() function. */ struct PrintfArguments { int nArg; /* Total number of arguments */ int nUsed; /* Number of arguments used so far */ sqlite3_value **apArg; /* The argument values */ }; /* ** An instance of this object receives the decoding of a floating point ** value into an approximate decimal representation. */ struct FpDecode { char sign; /* '+' or '-' */ char isSpecial; /* 1: Infinity 2: NaN */ int n; /* Significant digits in the decode */ int iDP; /* Location of the decimal point */ char *z; /* Start of significant digits */ char zBuf[24]; /* Storage for significant digits */ }; SQLITE_PRIVATE void sqlite3FpDecode(FpDecode*,double,int,int); SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...); SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list); #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) SQLITE_PRIVATE void sqlite3DebugPrintf(const char*, ...); #endif #if defined(SQLITE_TEST) SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*); #endif #if defined(SQLITE_DEBUG) SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView*, const char *zFormat, ...); SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); SQLITE_PRIVATE void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*); SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); SQLITE_PRIVATE void sqlite3TreeViewBareIdList(TreeView*, const IdList*, const char*); SQLITE_PRIVATE void sqlite3TreeViewIdList(TreeView*, const IdList*, u8, const char*); SQLITE_PRIVATE void sqlite3TreeViewColumnList(TreeView*, const Column*, int, u8); SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView*, const SrcList*); SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8); SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8); SQLITE_PRIVATE void sqlite3TreeViewUpsert(TreeView*, const Upsert*, u8); #if TREETRACE_ENABLED SQLITE_PRIVATE void sqlite3TreeViewDelete(const With*, const SrcList*, const Expr*, const ExprList*,const Expr*, const Trigger*); SQLITE_PRIVATE void sqlite3TreeViewInsert(const With*, const SrcList*, const IdList*, const Select*, const ExprList*, int, const Upsert*, const Trigger*); SQLITE_PRIVATE void sqlite3TreeViewUpdate(const With*, const SrcList*, const ExprList*, const Expr*, int, const ExprList*, const Expr*, const Upsert*, const Trigger*); #endif #ifndef SQLITE_OMIT_TRIGGER SQLITE_PRIVATE void sqlite3TreeViewTriggerStep(TreeView*, const TriggerStep*, u8, u8); SQLITE_PRIVATE void sqlite3TreeViewTrigger(TreeView*, const Trigger*, u8, u8); #endif #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView*, const Window*, u8); SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8); #endif SQLITE_PRIVATE void sqlite3ShowExpr(const Expr*); SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList*); SQLITE_PRIVATE void sqlite3ShowIdList(const IdList*); SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList*); SQLITE_PRIVATE void sqlite3ShowSelect(const Select*); SQLITE_PRIVATE void sqlite3ShowWith(const With*); SQLITE_PRIVATE void sqlite3ShowUpsert(const Upsert*); #ifndef SQLITE_OMIT_TRIGGER SQLITE_PRIVATE void sqlite3ShowTriggerStep(const TriggerStep*); SQLITE_PRIVATE void sqlite3ShowTriggerStepList(const TriggerStep*); SQLITE_PRIVATE void sqlite3ShowTrigger(const Trigger*); SQLITE_PRIVATE void sqlite3ShowTriggerList(const Trigger*); #endif #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE void sqlite3ShowWindow(const Window*); SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window*); #endif #endif SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*); SQLITE_PRIVATE void sqlite3ProgressCheck(Parse*); SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...); SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3*,int); SQLITE_PRIVATE void sqlite3Dequote(char*); SQLITE_PRIVATE void sqlite3DequoteExpr(Expr*); SQLITE_PRIVATE void sqlite3DequoteToken(Token*); SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*); SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int); SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*); SQLITE_PRIVATE void sqlite3FinishCoding(Parse*); SQLITE_PRIVATE int sqlite3GetTempReg(Parse*); SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int); SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int); SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int); SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*); SQLITE_PRIVATE void sqlite3TouchRegister(Parse*,int); #if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG) SQLITE_PRIVATE int sqlite3FirstAvailableRegister(Parse*,int); #endif #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int); #endif SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*); SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*); SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int); SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy(Parse*,Expr*,ExprList*); SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse*,Expr*); SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*); SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); SQLITE_PRIVATE void sqlite3ExprDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse*, Expr*); SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse*, int, ExprList*); SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int); SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int); SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*); SQLITE_PRIVATE void sqlite3ExprListDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*); SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*); SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**); SQLITE_PRIVATE int sqlite3InitOne(sqlite3*, int, char**, u32); SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); #ifndef SQLITE_OMIT_VIRTUALTABLE SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName); #endif SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*); SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int); SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*); SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*); SQLITE_PRIVATE void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*); SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table*,Column*); SQLITE_PRIVATE void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl); SQLITE_PRIVATE const char *sqlite3ColumnColl(Column*); SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*); SQLITE_PRIVATE void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char); SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int); SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*); SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index*, i16); #ifdef SQLITE_OMIT_GENERATED_COLUMNS # define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */ # define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */ #else SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table*, i16); SQLITE_PRIVATE i16 sqlite3StorageColumnToTable(Table*, i16); #endif SQLITE_PRIVATE void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); #if SQLITE_ENABLE_HIDDEN_COLUMNS SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table*, Column*); #else # define sqlite3ColumnPropertiesFromName(T,C) /* no-op */ #endif SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token,Token); SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int); SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*); SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*); SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*); SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*); SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*); SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); #define sqlite3CodecQueryParameters(A,B,C) 0 SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); #ifdef SQLITE_UNTESTABLE # define sqlite3FaultSim(X) SQLITE_OK #else SQLITE_PRIVATE int sqlite3FaultSim(int); #endif SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32); SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32); SQLITE_PRIVATE int sqlite3BitvecTestNotNull(Bitvec*, u32); SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32); SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*); SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*); SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*); #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*); #endif SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*); SQLITE_PRIVATE void sqlite3RowSetDelete(void*); SQLITE_PRIVATE void sqlite3RowSetClear(void*); SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64); SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64); SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*); SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int); #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*); #else # define sqlite3ViewGetColumnNames(A,B) 0 #endif #if SQLITE_MAX_ATTACHED>30 SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask); #endif SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int); SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); SQLITE_PRIVATE void sqlite3DeleteTableGeneric(sqlite3*, void*); SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3*, Index*); #ifndef SQLITE_OMIT_AUTOINCREMENT SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); #else # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) #endif SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*); #ifndef SQLITE_OMIT_GENERATED_COLUMNS SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns(Parse*, int, Table*); #endif SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*); SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int); SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2); SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*); SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, SrcItem *); SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(Parse*,SrcList*); SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*); SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*); SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*); SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, Trigger*); SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); #endif SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe*,int,const char*); SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*); SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*, Upsert*); SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*, ExprList*,Select*,u16,int); SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo*); SQLITE_PRIVATE void sqlite3WhereMinMaxOptEarlyOut(Vdbe*,WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*); #define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */ #define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */ #define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */ SQLITE_PRIVATE int sqlite3WhereUsesDeferredSeek(WhereInfo*); SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int); #ifndef SQLITE_OMIT_GENERATED_COLUMNS SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int); #endif SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ #define SQLITE_ECEL_OMITREF 0x08 /* Omit if ExprList.u.x.iOrderByCol */ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int); SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int); SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*); #define LOCATE_VIEW 0x01 #define LOCATE_NOERR 0x02 SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); SQLITE_PRIVATE const char *sqlite3PreferredTableName(const char*); SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,SrcItem *); SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*,Expr*); SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*); SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, const Token*); SQLITE_PRIVATE int sqlite3ExprCompare(const Parse*,const Expr*,const Expr*, int); SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*,Expr*,int); SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList*,const ExprList*, int); SQLITE_PRIVATE int sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int); SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int,int); SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse*, Expr*, SrcList*); SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3PrngSaveState(void); SQLITE_PRIVATE void sqlite3PrngRestoreState(void); #endif SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int); SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); SQLITE_PRIVATE void sqlite3EndTransaction(Parse*,int); SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*); SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*); SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char*); SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr*); SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8); SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int); SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int); #ifdef SQLITE_ENABLE_CURSOR_HINTS SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*); #endif SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); SQLITE_PRIVATE int sqlite3IsRowid(const char*); SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab); SQLITE_PRIVATE void sqlite3GenerateRowDelete( Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int); SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int); SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn(Expr*,int*,int); SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, u8,u8,int,int*,int*,Upsert*); #ifdef SQLITE_ENABLE_NULL_TRIM SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe*,Table*); #else # define sqlite3SetMakeRecordP5(A,B) #endif SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*); SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int); SQLITE_PRIVATE void sqlite3MultiWrite(Parse*); SQLITE_PRIVATE void sqlite3MayAbort(Parse*); SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8); SQLITE_PRIVATE void sqlite3UniqueConstraint(Parse*, int, Index*); SQLITE_PRIVATE void sqlite3RowidConstraint(Parse*, int, Table*); SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,const Expr*,int); SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,const ExprList*,int); SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,const SrcList*,int); SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,const IdList*); SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int); SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*); SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*); SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void); SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3*); #endif SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*); SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*); SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int); SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p); #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int); #endif #ifndef SQLITE_OMIT_TRIGGER SQLITE_PRIVATE void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*, Expr*,int, int); SQLITE_PRIVATE void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*); SQLITE_PRIVATE void sqlite3DropTrigger(Parse*, SrcList*, int); SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse*, Trigger*); SQLITE_PRIVATE Trigger *sqlite3TriggersExist(Parse *, Table*, int, ExprList*, int *pMask); SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *, Table *); SQLITE_PRIVATE void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, int, Table *, int, int, int); SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int); void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*, const char*,const char*); SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*, Select*,u8,Upsert*, const char*,const char*); SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,SrcList*,ExprList*, Expr*, u8, const char*,const char*); SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*, const char*,const char*); SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3*, Trigger*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int); SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*); # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) # define sqlite3IsToplevel(p) ((p)->pToplevel==0) #else # define sqlite3TriggersExist(B,C,D,E,F) 0 # define sqlite3DeleteTrigger(A,B) # define sqlite3DropTriggerPtr(A,B) # define sqlite3UnlinkAndDeleteTrigger(A,B,C) # define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) # define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F) # define sqlite3TriggerList(X, Y) 0 # define sqlite3ParseToplevel(p) p # define sqlite3IsToplevel(p) 1 # define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0 # define sqlite3TriggerStepSrc(A,B) 0 #endif SQLITE_PRIVATE int sqlite3JoinType(Parse*, Token*, Token*, Token*); SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol); SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem*,int); SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr*,int,u32); SQLITE_PRIVATE void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse*, int); #ifndef SQLITE_OMIT_AUTHORIZATION SQLITE_PRIVATE void sqlite3AuthRead(Parse*,Expr*,Schema*,SrcList*); SQLITE_PRIVATE int sqlite3AuthCheck(Parse*,int, const char*, const char*, const char*); SQLITE_PRIVATE void sqlite3AuthContextPush(Parse*, AuthContext*, const char*); SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext*); SQLITE_PRIVATE int sqlite3AuthReadCol(Parse*, const char *, const char *, int); #else # define sqlite3AuthRead(a,b,c,d) # define sqlite3AuthCheck(a,b,c,d,e) SQLITE_OK # define sqlite3AuthContextPush(a,b,c) # define sqlite3AuthContextPop(a) ((void)(a)) #endif SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName); SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*); SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*); SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*); SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*); SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64); SQLITE_PRIVATE i64 sqlite3RealToI64(double); SQLITE_PRIVATE int sqlite3Int64ToText(i64,char*); SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*); SQLITE_PRIVATE int sqlite3Atoi(const char*); #ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); #endif SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); SQLITE_PRIVATE int sqlite3Utf8ReadLimited(const u8*, int, u32*); SQLITE_PRIVATE LogEst sqlite3LogEst(u64); SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst); SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double); SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst); SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int); SQLITE_PRIVATE const char *sqlite3VListNumToName(VList*,int); SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int); /* ** Routines to read and write variable-length integers. These used to ** be defined locally, but now we use the varint routines in the util.c ** file. */ SQLITE_PRIVATE int sqlite3PutVarint(unsigned char*, u64); SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *, u64 *); SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *, u32 *); SQLITE_PRIVATE int sqlite3VarintLen(u64 v); /* ** The common case is for a varint to be a single byte. They following ** macros handle the common case without a procedure call, but then call ** the procedure for larger varints. */ #define getVarint32(A,B) \ (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B))) #define getVarint32NR(A,B) \ B=(u32)*(A);if(B>=0x80)sqlite3GetVarint32((A),(u32*)&(B)) #define putVarint32(A,B) \ (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\ sqlite3PutVarint((A),(B))) #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*); SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3*,const Table*); SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int); SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2); SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity); SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table*,int); SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr); SQLITE_PRIVATE int sqlite3ExprDataType(const Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*); SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); SQLITE_PRIVATE void sqlite3Error(sqlite3*,int); SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3*); SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int); SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); SQLITE_PRIVATE u8 sqlite3HexToInt(int h); SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); #if defined(SQLITE_NEED_ERR_NAME) SQLITE_PRIVATE const char *sqlite3ErrName(int); #endif #ifndef SQLITE_OMIT_DESERIALIZE SQLITE_PRIVATE int sqlite3MemdbInit(void); SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs*); #else # define sqlite3IsMemdb(X) 0 #endif SQLITE_PRIVATE const char *sqlite3ErrStr(int); SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*); SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8); SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr); SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr); SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*); SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(const Parse *pParse, Expr*, const Token*, int); SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(const Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*); SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*); SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*); SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, i64); SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64); SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64); SQLITE_PRIVATE int sqlite3AbsInt32(int); #ifdef SQLITE_ENABLE_8_3_NAMES SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*); #else # define sqlite3FileSuffix3(X,Y) #endif SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8); SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); SQLITE_PRIVATE int sqlite3ValueIsOfClass(const sqlite3_value*, void(*)(void*)); SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*); SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context*); #endif SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); #ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); #endif SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, const Expr *, u8, u8, sqlite3_value **); SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[]; SQLITE_PRIVATE const char sqlite3StrBINARY[]; SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[]; SQLITE_PRIVATE const char sqlite3StdTypeAffinity[]; SQLITE_PRIVATE const char *sqlite3StdType[]; SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[]; SQLITE_PRIVATE const unsigned char *sqlite3aLTb; SQLITE_PRIVATE const unsigned char *sqlite3aEQb; SQLITE_PRIVATE const unsigned char *sqlite3aGTb; SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[]; SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config; SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; #ifndef SQLITE_OMIT_WSD SQLITE_PRIVATE int sqlite3PendingByte; #endif #endif /* SQLITE_AMALGAMATION */ #ifdef VDBE_PROFILE SQLITE_PRIVATE sqlite3_uint64 sqlite3NProfileCnt; #endif SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, Pgno, Pgno); SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*); SQLITE_PRIVATE void sqlite3AlterFunctions(void); SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *); SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int); SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr*); SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*); SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, SrcItem*); SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); SQLITE_PRIVATE int sqlite3MatchEName( const struct ExprList_item*, const char*, const char*, const char*, int* ); SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr*); SQLITE_PRIVATE u8 sqlite3StrIHash(const char*); SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*); SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*); SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); SQLITE_PRIVATE int sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int); SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *); SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse*, SrcList*, const Token*); SQLITE_PRIVATE const void *sqlite3RenameTokenMap(Parse*, const void*, const Token*); SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, const void *pTo, const void *pFrom); SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*); SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*); SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*); SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*); SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*); SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*); SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *); SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB); SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*); SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*); SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3*, int); SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); SQLITE_PRIVATE void sqlite3SchemaClear(void *); SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *, Btree *); SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *); SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int); SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo*); SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo*); SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int); SQLITE_PRIVATE const char *sqlite3SelectOpName(int); SQLITE_PRIVATE int sqlite3HasExplicitNulls(Parse*, ExprList*); #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*); #endif SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*), void (*)(sqlite3_context*), void (*)(sqlite3_context*,int,sqlite3_value **), FuncDestructor *pDestructor ); SQLITE_PRIVATE void sqlite3NoopDestructor(void*); SQLITE_PRIVATE void *sqlite3OomFault(sqlite3*); SQLITE_PRIVATE void sqlite3OomClear(sqlite3*); SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int); SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *); SQLITE_PRIVATE char *sqlite3RCStrRef(char*); SQLITE_PRIVATE void sqlite3RCStrUnref(void*); SQLITE_PRIVATE char *sqlite3RCStrNew(u64); SQLITE_PRIVATE char *sqlite3RCStrResize(char*,u64); SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, i64); SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*); SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum*, u8); SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*); SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int); SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); SQLITE_PRIVATE void sqlite3RecordErrorByteOffset(sqlite3*,const char*); SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3*,const Expr*); SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *); SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *); #ifndef SQLITE_OMIT_SUBQUERY SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse*, Expr*); #else # define sqlite3ExprCheckIN(x,y) SQLITE_OK #endif #ifdef SQLITE_ENABLE_STAT4 SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue( Parse*,Index*,UnpackedRecord**,Expr*,int,int,int*); SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**); SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord*); SQLITE_PRIVATE int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**); SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3*, Index*, int); #endif /* ** The interface to the LEMON-generated parser */ #ifndef SQLITE_AMALGAMATION SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64), Parse*); SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*)); #endif SQLITE_PRIVATE void sqlite3Parser(void*, int, Token); SQLITE_PRIVATE int sqlite3ParserFallback(int); #ifdef YYTRACKMAXSTACKDEPTH SQLITE_PRIVATE int sqlite3ParserStackPeak(void*); #endif SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3*); #ifndef SQLITE_OMIT_LOAD_EXTENSION SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3*); #else # define sqlite3CloseExtensions(X) #endif #ifndef SQLITE_OMIT_SHARED_CACHE SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, Pgno, u8, const char *); #else #define sqlite3TableLock(v,w,x,y,z) #endif #ifdef SQLITE_TEST SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*); #endif #ifdef SQLITE_OMIT_VIRTUALTABLE # define sqlite3VtabClear(D,T) # define sqlite3VtabSync(X,Y) SQLITE_OK # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) # define sqlite3VtabInSync(db) 0 # define sqlite3VtabLock(X) # define sqlite3VtabUnlock(X) # define sqlite3VtabModuleUnref(D,X) # define sqlite3VtabUnlockList(X) # define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK # define sqlite3GetVTable(X,Y) ((VTable*)0) #else SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table*); SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p); SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, Vdbe*); SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db); SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db); SQLITE_PRIVATE void sqlite3VtabLock(VTable *); SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *); SQLITE_PRIVATE void sqlite3VtabModuleUnref(sqlite3*,Module*); SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*); SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int); SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*); SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*); SQLITE_PRIVATE Module *sqlite3VtabCreateModule( sqlite3*, const char*, const sqlite3_module*, void*, void(*)(void*) ); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db); #ifndef SQLITE_OMIT_VIRTUALTABLE SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName); SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*); SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3*, Table*); #else # define sqlite3ShadowTableName(A,B) 0 # define sqlite3IsShadowTableOf(A,B,C) 0 # define sqlite3MarkAllShadowTablesOf(A,B) #endif SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*); SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*); SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*); SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int); SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*); SQLITE_PRIVATE void sqlite3VtabArgInit(Parse*); SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse*, Token*); SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse*, Table*); SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *); SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *); SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(Parse*); SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); SQLITE_PRIVATE void sqlite3ParseObjectInit(Parse*,sqlite3*); SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse*); SQLITE_PRIVATE void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*); #ifdef SQLITE_ENABLE_NORMALIZE SQLITE_PRIVATE char *sqlite3Normalize(Vdbe*, const char*); #endif SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*); SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse*,const Expr*); SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, const Expr*, const Expr*); SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*); SQLITE_PRIVATE const char *sqlite3JournalModename(int); #ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int, int, int*, int*); SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); #endif #ifndef SQLITE_OMIT_CTE SQLITE_PRIVATE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8); SQLITE_PRIVATE void sqlite3CteDelete(sqlite3*,Cte*); SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Cte*); SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*); SQLITE_PRIVATE void sqlite3WithDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8); #else # define sqlite3CteNew(P,T,E,S) ((void*)0) # define sqlite3CteDelete(D,C) # define sqlite3CteWithAdd(P,W,C) ((void*)0) # define sqlite3WithDelete(x,y) # define sqlite3WithPush(x,y,z) ((void*)0) #endif #ifndef SQLITE_OMIT_UPSERT SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*); SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*); SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*); SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*); SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int); SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert*,Index*); SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert*); #else #define sqlite3UpsertNew(u,v,w,x,y,z) ((Upsert*)0) #define sqlite3UpsertDelete(x,y) #define sqlite3UpsertDup(x,y) ((Upsert*)0) #define sqlite3UpsertOfIndex(x,y) ((Upsert*)0) #define sqlite3UpsertNextIsIPK(x) 0 #endif /* Declarations for functions in fkey.c. All of these are replaced by ** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign ** key functionality is available. If OMIT_TRIGGER is defined but ** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In ** this case foreign keys are parsed, but no other functionality is ** provided (enforcement of FK constraints requires the triggers sub-system). */ #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) SQLITE_PRIVATE void sqlite3FkCheck(Parse*, Table*, int, int, int*, int); SQLITE_PRIVATE void sqlite3FkDropTable(Parse*, SrcList *, Table*); SQLITE_PRIVATE void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int); SQLITE_PRIVATE int sqlite3FkRequired(Parse*, Table*, int*, int); SQLITE_PRIVATE u32 sqlite3FkOldmask(Parse*, Table*); SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *); SQLITE_PRIVATE void sqlite3FkClearTriggerCache(sqlite3*,int); #else #define sqlite3FkActions(a,b,c,d,e,f) #define sqlite3FkCheck(a,b,c,d,e,f) #define sqlite3FkDropTable(a,b,c) #define sqlite3FkOldmask(a,b) 0 #define sqlite3FkRequired(a,b,c,d) 0 #define sqlite3FkReferences(a) 0 #define sqlite3FkClearTriggerCache(a,b) #endif #ifndef SQLITE_OMIT_FOREIGN_KEY SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *, Table*); SQLITE_PRIVATE int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**); #else #define sqlite3FkDelete(a,b) #define sqlite3FkLocateIndex(a,b,c,d,e) #endif /* ** Available fault injectors. Should be numbered beginning with 0. */ #define SQLITE_FAULTINJECTOR_MALLOC 0 #define SQLITE_FAULTINJECTOR_COUNT 1 /* ** The interface to the code in fault.c used for identifying "benign" ** malloc failures. This is only present if SQLITE_UNTESTABLE ** is not defined. */ #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void); SQLITE_PRIVATE void sqlite3EndBenignMalloc(void); #else #define sqlite3BeginBenignMalloc() #define sqlite3EndBenignMalloc() #endif /* ** Allowed return values from sqlite3FindInIndex() */ #define IN_INDEX_ROWID 1 /* Search the rowid of the table */ #define IN_INDEX_EPH 2 /* Search an ephemeral b-tree */ #define IN_INDEX_INDEX_ASC 3 /* Existing index ASCENDING */ #define IN_INDEX_INDEX_DESC 4 /* Existing index DESCENDING */ #define IN_INDEX_NOOP 5 /* No table available. Use comparisons */ /* ** Allowed flags for the 3rd parameter to sqlite3FindInIndex(). */ #define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ #define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ #define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*); SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *); #if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *); #endif SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p); SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *); SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); #if SQLITE_MAX_EXPR_DEPTH>0 SQLITE_PRIVATE int sqlite3SelectExprHeight(const Select *); SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int); #else #define sqlite3SelectExprHeight(x) 0 #define sqlite3ExprCheckHeight(x,y) #endif SQLITE_PRIVATE void sqlite3ExprSetErrorOffset(Expr*,int); SQLITE_PRIVATE u32 sqlite3Get4byte(const u8*); SQLITE_PRIVATE void sqlite3Put4byte(u8*, u32); #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_PRIVATE void sqlite3ConnectionBlocked(sqlite3 *, sqlite3 *); SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db); SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db); #else #define sqlite3ConnectionBlocked(x,y) #define sqlite3ConnectionUnlocked(x) #define sqlite3ConnectionClosed(x) #endif #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *); #endif #if defined(YYCOVERAGE) SQLITE_PRIVATE int sqlite3ParserCoverage(FILE*); #endif /* ** If the SQLITE_ENABLE IOTRACE exists then the global variable ** sqlite3IoTrace is a pointer to a printf-like routine used to ** print I/O tracing messages. */ #ifdef SQLITE_ENABLE_IOTRACE # define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; } SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe*); SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...); #else # define IOTRACE(A) # define sqlite3VdbeIOTraceSql(X) #endif /* ** These routines are available for the mem2.c debugging memory allocator ** only. They are used to verify that different "types" of memory ** allocations are properly tracked by the system. ** ** sqlite3MemdebugSetType() sets the "type" of an allocation to one of ** the MEMTYPE_* macros defined below. The type must be a bitmask with ** a single bit set. ** ** sqlite3MemdebugHasType() returns true if any of the bits in its second ** argument match the type set by the previous sqlite3MemdebugSetType(). ** sqlite3MemdebugHasType() is intended for use inside assert() statements. ** ** sqlite3MemdebugNoType() returns true if none of the bits in its second ** argument match the type set by the previous sqlite3MemdebugSetType(). ** ** Perhaps the most important point is the difference between MEMTYPE_HEAP ** and MEMTYPE_LOOKASIDE. If an allocation is MEMTYPE_LOOKASIDE, that means ** it might have been allocated by lookaside, except the allocation was ** too large or lookaside was already full. It is important to verify ** that allocations that might have been satisfied by lookaside are not ** passed back to non-lookaside free() routines. Asserts such as the ** example above are placed on the non-lookaside free() routines to verify ** this constraint. ** ** All of this is no-op for a production build. It only comes into ** play when the SQLITE_MEMDEBUG compile-time option is used. */ #ifdef SQLITE_MEMDEBUG SQLITE_PRIVATE void sqlite3MemdebugSetType(void*,u8); SQLITE_PRIVATE int sqlite3MemdebugHasType(const void*,u8); SQLITE_PRIVATE int sqlite3MemdebugNoType(const void*,u8); #else # define sqlite3MemdebugSetType(X,Y) /* no-op */ # define sqlite3MemdebugHasType(X,Y) 1 # define sqlite3MemdebugNoType(X,Y) 1 #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ #define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */ #define MEMTYPE_PCACHE 0x04 /* Page cache allocations */ /* ** Threading interface */ #if SQLITE_MAX_WORKER_THREADS>0 SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*); SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**); #endif #if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST) SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*); #endif #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST) SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*); #endif SQLITE_PRIVATE int sqlite3ExprVectorSize(const Expr *pExpr); SQLITE_PRIVATE int sqlite3ExprIsVector(const Expr *pExpr); SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int); SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int); SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt); #endif #if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) SQLITE_PRIVATE int sqlite3KvvfsInit(void); #endif #if defined(VDBE_PROFILE) \ || defined(SQLITE_PERFORMANCE_TRACE) \ || defined(SQLITE_ENABLE_STMT_SCANSTATUS) SQLITE_PRIVATE sqlite3_uint64 sqlite3Hwtime(void); #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS # define IS_STMT_SCANSTATUS(db) (db->flags & SQLITE_StmtScanStatus) #else # define IS_STMT_SCANSTATUS(db) 0 #endif #endif /* SQLITEINT_H */ /************** End of sqliteInt.h *******************************************/ /************** Begin file os_common.h ***************************************/ /* ** 2004 May 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains macros and a little bit of code that is common to ** all of the platform-specific files (os_*.c) and is #included into those ** files. ** ** This file should be #included by the os_*.c files only. It is not a ** general purpose header file. */ #ifndef _OS_COMMON_H_ #define _OS_COMMON_H_ /* ** At least two bugs have slipped in because we changed the MEMORY_DEBUG ** macro to SQLITE_DEBUG and some older makefiles have not yet made the ** switch. The following code should catch this problem at compile-time. */ #ifdef MEMORY_DEBUG # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif /* ** Macros for performance tracing. Normally turned off. Only works ** on i486 hardware. */ #ifdef SQLITE_PERFORMANCE_TRACE static sqlite_uint64 g_start; static sqlite_uint64 g_elapsed; #define TIMER_START g_start=sqlite3Hwtime() #define TIMER_END g_elapsed=sqlite3Hwtime()-g_start #define TIMER_ELAPSED g_elapsed #else #define TIMER_START #define TIMER_END #define TIMER_ELAPSED ((sqlite_uint64)0) #endif /* ** If we compile with the SQLITE_TEST macro set, then the following block ** of code will give us the ability to simulate a disk I/O error. This ** is used for testing the I/O recovery logic. */ #if defined(SQLITE_TEST) SQLITE_API extern int sqlite3_io_error_hit; SQLITE_API extern int sqlite3_io_error_hardhit; SQLITE_API extern int sqlite3_io_error_pending; SQLITE_API extern int sqlite3_io_error_persist; SQLITE_API extern int sqlite3_io_error_benign; SQLITE_API extern int sqlite3_diskfull_pending; SQLITE_API extern int sqlite3_diskfull; #define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) #define SimulateIOError(CODE) \ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ || sqlite3_io_error_pending-- == 1 ) \ { local_ioerr(); CODE; } static void local_ioerr(){ IOTRACE(("IOERR\n")); sqlite3_io_error_hit++; if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; } #define SimulateDiskfullError(CODE) \ if( sqlite3_diskfull_pending ){ \ if( sqlite3_diskfull_pending == 1 ){ \ local_ioerr(); \ sqlite3_diskfull = 1; \ sqlite3_io_error_hit = 1; \ CODE; \ }else{ \ sqlite3_diskfull_pending--; \ } \ } #else #define SimulateIOErrorBenign(X) #define SimulateIOError(A) #define SimulateDiskfullError(A) #endif /* defined(SQLITE_TEST) */ /* ** When testing, keep a count of the number of open files. */ #if defined(SQLITE_TEST) SQLITE_API extern int sqlite3_open_file_count; #define OpenCounter(X) sqlite3_open_file_count+=(X) #else #define OpenCounter(X) #endif /* defined(SQLITE_TEST) */ #endif /* !defined(_OS_COMMON_H_) */ /************** End of os_common.h *******************************************/ /************** Begin file ctime.c *******************************************/ /* DO NOT EDIT! ** This file is automatically generated by the script in the canonical ** SQLite source tree at tool/mkctimec.tcl. ** ** To modify this header, edit any of the various lists in that script ** which specify categories of generated conditionals in this file. */ /* ** 2010 February 23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file implements routines used to report what compile-time options ** SQLite was built with. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ #if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) /* #include "sqlite_cfg.h" */ #define SQLITECONFIG_H 1 #endif /* These macros are provided to "stringify" the value of the define ** for those options in which the value is meaningful. */ #define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) /* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This ** option requires a separate macro because legal values contain a single ** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */ #define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2 #define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt) /* #include "sqliteInt.h" */ /* ** An array of names of all compile-time options. This array should ** be sorted A-Z. ** ** This array looks large, but in a typical installation actually uses ** only a handful of compile-time options, so most times this array is usually ** rather short and uses little memory space. */ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_32BIT_ROWID "32BIT_ROWID", #endif #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC "4_BYTE_ALIGNED_MALLOC", #endif #ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN # if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1 "ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN), # endif #endif #ifdef SQLITE_ALLOW_URI_AUTHORITY "ALLOW_URI_AUTHORITY", #endif #ifdef SQLITE_ATOMIC_INTRINSICS "ATOMIC_INTRINSICS=" CTIMEOPT_VAL(SQLITE_ATOMIC_INTRINSICS), #endif #ifdef SQLITE_BITMASK_TYPE "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), #endif #ifdef SQLITE_BUG_COMPATIBLE_20160819 "BUG_COMPATIBLE_20160819", #endif #ifdef SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif #ifdef SQLITE_CHECK_PAGES "CHECK_PAGES", #endif #if defined(__clang__) && defined(__clang_major__) "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "." CTIMEOPT_VAL(__clang_minor__) "." CTIMEOPT_VAL(__clang_patchlevel__), #elif defined(_MSC_VER) "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER), #elif defined(__GNUC__) && defined(__VERSION__) "COMPILER=gcc-" __VERSION__, #endif #ifdef SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif #ifdef SQLITE_DEBUG "DEBUG", #endif #ifdef SQLITE_DEFAULT_AUTOMATIC_INDEX "DEFAULT_AUTOMATIC_INDEX", #endif #ifdef SQLITE_DEFAULT_AUTOVACUUM "DEFAULT_AUTOVACUUM", #endif #ifdef SQLITE_DEFAULT_CACHE_SIZE "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE), #endif #ifdef SQLITE_DEFAULT_CKPTFULLFSYNC "DEFAULT_CKPTFULLFSYNC", #endif #ifdef SQLITE_DEFAULT_FILE_FORMAT "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT), #endif #ifdef SQLITE_DEFAULT_FILE_PERMISSIONS "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS), #endif #ifdef SQLITE_DEFAULT_FOREIGN_KEYS "DEFAULT_FOREIGN_KEYS", #endif #ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT), #endif #ifdef SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #ifdef SQLITE_DEFAULT_LOOKASIDE "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE), #endif #ifdef SQLITE_DEFAULT_MEMSTATUS # if SQLITE_DEFAULT_MEMSTATUS != 1 "DEFAULT_MEMSTATUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_MEMSTATUS), # endif #endif #ifdef SQLITE_DEFAULT_MMAP_SIZE "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), #endif #ifdef SQLITE_DEFAULT_PAGE_SIZE "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE), #endif #ifdef SQLITE_DEFAULT_PCACHE_INITSZ "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ), #endif #ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS), #endif #ifdef SQLITE_DEFAULT_RECURSIVE_TRIGGERS "DEFAULT_RECURSIVE_TRIGGERS", #endif #ifdef SQLITE_DEFAULT_ROWEST "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST), #endif #ifdef SQLITE_DEFAULT_SECTOR_SIZE "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE), #endif #ifdef SQLITE_DEFAULT_SYNCHRONOUS "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS), #endif #ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT), #endif #ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS), #endif #ifdef SQLITE_DEFAULT_WORKER_THREADS "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS), #endif #ifdef SQLITE_DIRECT_OVERFLOW_READ "DIRECT_OVERFLOW_READ", #endif #ifdef SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif #ifdef SQLITE_DISABLE_FTS3_UNICODE "DISABLE_FTS3_UNICODE", #endif #ifdef SQLITE_DISABLE_FTS4_DEFERRED "DISABLE_FTS4_DEFERRED", #endif #ifdef SQLITE_DISABLE_INTRINSIC "DISABLE_INTRINSIC", #endif #ifdef SQLITE_DISABLE_LFS "DISABLE_LFS", #endif #ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS "DISABLE_PAGECACHE_OVERFLOW_STATS", #endif #ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT "DISABLE_SKIPAHEAD_DISTINCT", #endif #ifdef SQLITE_DQS "DQS=" CTIMEOPT_VAL(SQLITE_DQS), #endif #ifdef SQLITE_ENABLE_8_3_NAMES "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), #endif #ifdef SQLITE_ENABLE_API_ARMOR "ENABLE_API_ARMOR", #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE "ENABLE_ATOMIC_WRITE", #endif #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE "ENABLE_BATCH_ATOMIC_WRITE", #endif #ifdef SQLITE_ENABLE_BYTECODE_VTAB "ENABLE_BYTECODE_VTAB", #endif #ifdef SQLITE_ENABLE_CEROD "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), #endif #ifdef SQLITE_ENABLE_COLUMN_METADATA "ENABLE_COLUMN_METADATA", #endif #ifdef SQLITE_ENABLE_COLUMN_USED_MASK "ENABLE_COLUMN_USED_MASK", #endif #ifdef SQLITE_ENABLE_COSTMULT "ENABLE_COSTMULT", #endif #ifdef SQLITE_ENABLE_CURSOR_HINTS "ENABLE_CURSOR_HINTS", #endif #ifdef SQLITE_ENABLE_DBPAGE_VTAB "ENABLE_DBPAGE_VTAB", #endif #ifdef SQLITE_ENABLE_DBSTAT_VTAB "ENABLE_DBSTAT_VTAB", #endif #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT "ENABLE_EXPENSIVE_ASSERT", #endif #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS "ENABLE_EXPLAIN_COMMENTS", #endif #ifdef SQLITE_ENABLE_FTS3 "ENABLE_FTS3", #endif #ifdef SQLITE_ENABLE_FTS3_PARENTHESIS "ENABLE_FTS3_PARENTHESIS", #endif #ifdef SQLITE_ENABLE_FTS3_TOKENIZER "ENABLE_FTS3_TOKENIZER", #endif #ifdef SQLITE_ENABLE_FTS4 "ENABLE_FTS4", #endif #ifdef SQLITE_ENABLE_FTS5 "ENABLE_FTS5", #endif #ifdef SQLITE_ENABLE_GEOPOLY "ENABLE_GEOPOLY", #endif #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS "ENABLE_HIDDEN_COLUMNS", #endif #ifdef SQLITE_ENABLE_ICU "ENABLE_ICU", #endif #ifdef SQLITE_ENABLE_IOTRACE "ENABLE_IOTRACE", #endif #ifdef SQLITE_ENABLE_LOAD_EXTENSION "ENABLE_LOAD_EXTENSION", #endif #ifdef SQLITE_ENABLE_LOCKING_STYLE "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), #endif #ifdef SQLITE_ENABLE_MATH_FUNCTIONS "ENABLE_MATH_FUNCTIONS", #endif #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT "ENABLE_MEMORY_MANAGEMENT", #endif #ifdef SQLITE_ENABLE_MEMSYS3 "ENABLE_MEMSYS3", #endif #ifdef SQLITE_ENABLE_MEMSYS5 "ENABLE_MEMSYS5", #endif #ifdef SQLITE_ENABLE_MULTIPLEX "ENABLE_MULTIPLEX", #endif #ifdef SQLITE_ENABLE_NORMALIZE "ENABLE_NORMALIZE", #endif #ifdef SQLITE_ENABLE_NULL_TRIM "ENABLE_NULL_TRIM", #endif #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC "ENABLE_OFFSET_SQL_FUNC", #endif #ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif #ifdef SQLITE_ENABLE_PREUPDATE_HOOK "ENABLE_PREUPDATE_HOOK", #endif #ifdef SQLITE_ENABLE_QPSG "ENABLE_QPSG", #endif #ifdef SQLITE_ENABLE_RBU "ENABLE_RBU", #endif #ifdef SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif #ifdef SQLITE_ENABLE_SESSION "ENABLE_SESSION", #endif #ifdef SQLITE_ENABLE_SNAPSHOT "ENABLE_SNAPSHOT", #endif #ifdef SQLITE_ENABLE_SORTER_REFERENCES "ENABLE_SORTER_REFERENCES", #endif #ifdef SQLITE_ENABLE_SQLLOG "ENABLE_SQLLOG", #endif #ifdef SQLITE_ENABLE_STAT4 "ENABLE_STAT4", #endif #ifdef SQLITE_ENABLE_STMTVTAB "ENABLE_STMTVTAB", #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS "ENABLE_STMT_SCANSTATUS", #endif #ifdef SQLITE_ENABLE_TREETRACE "ENABLE_TREETRACE", #endif #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION "ENABLE_UNKNOWN_SQL_FUNCTION", #endif #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY "ENABLE_UNLOCK_NOTIFY", #endif #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT "ENABLE_UPDATE_DELETE_LIMIT", #endif #ifdef SQLITE_ENABLE_URI_00_ERROR "ENABLE_URI_00_ERROR", #endif #ifdef SQLITE_ENABLE_VFSTRACE "ENABLE_VFSTRACE", #endif #ifdef SQLITE_ENABLE_WHERETRACE "ENABLE_WHERETRACE", #endif #ifdef SQLITE_ENABLE_ZIPVFS "ENABLE_ZIPVFS", #endif #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS "EXPLAIN_ESTIMATED_ROWS", #endif #ifdef SQLITE_EXTRA_AUTOEXT "EXTRA_AUTOEXT=" CTIMEOPT_VAL(SQLITE_EXTRA_AUTOEXT), #endif #ifdef SQLITE_EXTRA_IFNULLROW "EXTRA_IFNULLROW", #endif #ifdef SQLITE_EXTRA_INIT "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), #endif #ifdef SQLITE_EXTRA_SHUTDOWN "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), #endif #ifdef SQLITE_FTS3_MAX_EXPR_DEPTH "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), #endif #ifdef SQLITE_FTS5_ENABLE_TEST_MI "FTS5_ENABLE_TEST_MI", #endif #ifdef SQLITE_FTS5_NO_WITHOUT_ROWID "FTS5_NO_WITHOUT_ROWID", #endif #if HAVE_ISNAN || SQLITE_HAVE_ISNAN "HAVE_ISNAN", #endif #ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX # if SQLITE_HOMEGROWN_RECURSIVE_MUTEX != 1 "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), # endif #endif #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS "IGNORE_AFP_LOCK_ERRORS", #endif #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS "IGNORE_FLOCK_LOCK_ERRORS", #endif #ifdef SQLITE_INLINE_MEMCPY "INLINE_MEMCPY", #endif #ifdef SQLITE_INT64_TYPE "INT64_TYPE", #endif #ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX), #endif #ifdef SQLITE_LEGACY_JSON_VALID "LEGACY_JSON_VALID", #endif #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS "LIKE_DOESNT_MATCH_BLOBS", #endif #ifdef SQLITE_LOCK_TRACE "LOCK_TRACE", #endif #ifdef SQLITE_LOG_CACHE_SPILL "LOG_CACHE_SPILL", #endif #ifdef SQLITE_MALLOC_SOFT_LIMIT "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT), #endif #ifdef SQLITE_MAX_ATTACHED "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED), #endif #ifdef SQLITE_MAX_COLUMN "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN), #endif #ifdef SQLITE_MAX_COMPOUND_SELECT "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT), #endif #ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE), #endif #ifdef SQLITE_MAX_EXPR_DEPTH "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH), #endif #ifdef SQLITE_MAX_FUNCTION_ARG "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG), #endif #ifdef SQLITE_MAX_LENGTH "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH), #endif #ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH), #endif #ifdef SQLITE_MAX_MEMORY "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY), #endif #ifdef SQLITE_MAX_MMAP_SIZE "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE), #endif #ifdef SQLITE_MAX_MMAP_SIZE_ "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_), #endif #ifdef SQLITE_MAX_PAGE_COUNT "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT), #endif #ifdef SQLITE_MAX_PAGE_SIZE "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE), #endif #ifdef SQLITE_MAX_SCHEMA_RETRY "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), #endif #ifdef SQLITE_MAX_SQL_LENGTH "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH), #endif #ifdef SQLITE_MAX_TRIGGER_DEPTH "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH), #endif #ifdef SQLITE_MAX_VARIABLE_NUMBER "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER), #endif #ifdef SQLITE_MAX_VDBE_OP "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP), #endif #ifdef SQLITE_MAX_WORKER_THREADS "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS), #endif #ifdef SQLITE_MEMDEBUG "MEMDEBUG", #endif #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT "MIXED_ENDIAN_64BIT_FLOAT", #endif #ifdef SQLITE_MMAP_READWRITE "MMAP_READWRITE", #endif #ifdef SQLITE_MUTEX_NOOP "MUTEX_NOOP", #endif #ifdef SQLITE_MUTEX_OMIT "MUTEX_OMIT", #endif #ifdef SQLITE_MUTEX_PTHREADS "MUTEX_PTHREADS", #endif #ifdef SQLITE_MUTEX_W32 "MUTEX_W32", #endif #ifdef SQLITE_NEED_ERR_NAME "NEED_ERR_NAME", #endif #ifdef SQLITE_NO_SYNC "NO_SYNC", #endif #ifdef SQLITE_OMIT_ALTERTABLE "OMIT_ALTERTABLE", #endif #ifdef SQLITE_OMIT_ANALYZE "OMIT_ANALYZE", #endif #ifdef SQLITE_OMIT_ATTACH "OMIT_ATTACH", #endif #ifdef SQLITE_OMIT_AUTHORIZATION "OMIT_AUTHORIZATION", #endif #ifdef SQLITE_OMIT_AUTOINCREMENT "OMIT_AUTOINCREMENT", #endif #ifdef SQLITE_OMIT_AUTOINIT "OMIT_AUTOINIT", #endif #ifdef SQLITE_OMIT_AUTOMATIC_INDEX "OMIT_AUTOMATIC_INDEX", #endif #ifdef SQLITE_OMIT_AUTORESET "OMIT_AUTORESET", #endif #ifdef SQLITE_OMIT_AUTOVACUUM "OMIT_AUTOVACUUM", #endif #ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION "OMIT_BETWEEN_OPTIMIZATION", #endif #ifdef SQLITE_OMIT_BLOB_LITERAL "OMIT_BLOB_LITERAL", #endif #ifdef SQLITE_OMIT_CAST "OMIT_CAST", #endif #ifdef SQLITE_OMIT_CHECK "OMIT_CHECK", #endif #ifdef SQLITE_OMIT_COMPLETE "OMIT_COMPLETE", #endif #ifdef SQLITE_OMIT_COMPOUND_SELECT "OMIT_COMPOUND_SELECT", #endif #ifdef SQLITE_OMIT_CONFLICT_CLAUSE "OMIT_CONFLICT_CLAUSE", #endif #ifdef SQLITE_OMIT_CTE "OMIT_CTE", #endif #if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT) "OMIT_DATETIME_FUNCS", #endif #ifdef SQLITE_OMIT_DECLTYPE "OMIT_DECLTYPE", #endif #ifdef SQLITE_OMIT_DEPRECATED "OMIT_DEPRECATED", #endif #ifdef SQLITE_OMIT_DESERIALIZE "OMIT_DESERIALIZE", #endif #ifdef SQLITE_OMIT_DISKIO "OMIT_DISKIO", #endif #ifdef SQLITE_OMIT_EXPLAIN "OMIT_EXPLAIN", #endif #ifdef SQLITE_OMIT_FLAG_PRAGMAS "OMIT_FLAG_PRAGMAS", #endif #ifdef SQLITE_OMIT_FLOATING_POINT "OMIT_FLOATING_POINT", #endif #ifdef SQLITE_OMIT_FOREIGN_KEY "OMIT_FOREIGN_KEY", #endif #ifdef SQLITE_OMIT_GET_TABLE "OMIT_GET_TABLE", #endif #ifdef SQLITE_OMIT_HEX_INTEGER "OMIT_HEX_INTEGER", #endif #ifdef SQLITE_OMIT_INCRBLOB "OMIT_INCRBLOB", #endif #ifdef SQLITE_OMIT_INTEGRITY_CHECK "OMIT_INTEGRITY_CHECK", #endif #ifdef SQLITE_OMIT_INTROSPECTION_PRAGMAS "OMIT_INTROSPECTION_PRAGMAS", #endif #ifdef SQLITE_OMIT_JSON "OMIT_JSON", #endif #ifdef SQLITE_OMIT_LIKE_OPTIMIZATION "OMIT_LIKE_OPTIMIZATION", #endif #ifdef SQLITE_OMIT_LOAD_EXTENSION "OMIT_LOAD_EXTENSION", #endif #ifdef SQLITE_OMIT_LOCALTIME "OMIT_LOCALTIME", #endif #ifdef SQLITE_OMIT_LOOKASIDE "OMIT_LOOKASIDE", #endif #ifdef SQLITE_OMIT_MEMORYDB "OMIT_MEMORYDB", #endif #ifdef SQLITE_OMIT_OR_OPTIMIZATION "OMIT_OR_OPTIMIZATION", #endif #ifdef SQLITE_OMIT_PAGER_PRAGMAS "OMIT_PAGER_PRAGMAS", #endif #ifdef SQLITE_OMIT_PARSER_TRACE "OMIT_PARSER_TRACE", #endif #ifdef SQLITE_OMIT_POPEN "OMIT_POPEN", #endif #ifdef SQLITE_OMIT_PRAGMA "OMIT_PRAGMA", #endif #ifdef SQLITE_OMIT_PROGRESS_CALLBACK "OMIT_PROGRESS_CALLBACK", #endif #ifdef SQLITE_OMIT_QUICKBALANCE "OMIT_QUICKBALANCE", #endif #ifdef SQLITE_OMIT_REINDEX "OMIT_REINDEX", #endif #ifdef SQLITE_OMIT_SCHEMA_PRAGMAS "OMIT_SCHEMA_PRAGMAS", #endif #ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS "OMIT_SCHEMA_VERSION_PRAGMAS", #endif #ifdef SQLITE_OMIT_SEH "OMIT_SEH", #endif #ifdef SQLITE_OMIT_SHARED_CACHE "OMIT_SHARED_CACHE", #endif #ifdef SQLITE_OMIT_SHUTDOWN_DIRECTORIES "OMIT_SHUTDOWN_DIRECTORIES", #endif #ifdef SQLITE_OMIT_SUBQUERY "OMIT_SUBQUERY", #endif #ifdef SQLITE_OMIT_TCL_VARIABLE "OMIT_TCL_VARIABLE", #endif #ifdef SQLITE_OMIT_TEMPDB "OMIT_TEMPDB", #endif #ifdef SQLITE_OMIT_TEST_CONTROL "OMIT_TEST_CONTROL", #endif #ifdef SQLITE_OMIT_TRACE # if SQLITE_OMIT_TRACE != 1 "OMIT_TRACE=" CTIMEOPT_VAL(SQLITE_OMIT_TRACE), # endif #endif #ifdef SQLITE_OMIT_TRIGGER "OMIT_TRIGGER", #endif #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION "OMIT_TRUNCATE_OPTIMIZATION", #endif #ifdef SQLITE_OMIT_UTF16 "OMIT_UTF16", #endif #ifdef SQLITE_OMIT_VACUUM "OMIT_VACUUM", #endif #ifdef SQLITE_OMIT_VIEW "OMIT_VIEW", #endif #ifdef SQLITE_OMIT_VIRTUALTABLE "OMIT_VIRTUALTABLE", #endif #ifdef SQLITE_OMIT_WAL "OMIT_WAL", #endif #ifdef SQLITE_OMIT_WSD "OMIT_WSD", #endif #ifdef SQLITE_OMIT_XFER_OPT "OMIT_XFER_OPT", #endif #ifdef SQLITE_PERFORMANCE_TRACE "PERFORMANCE_TRACE", #endif #ifdef SQLITE_POWERSAFE_OVERWRITE # if SQLITE_POWERSAFE_OVERWRITE != 1 "POWERSAFE_OVERWRITE=" CTIMEOPT_VAL(SQLITE_POWERSAFE_OVERWRITE), # endif #endif #ifdef SQLITE_PREFER_PROXY_LOCKING "PREFER_PROXY_LOCKING", #endif #ifdef SQLITE_PROXY_DEBUG "PROXY_DEBUG", #endif #ifdef SQLITE_REVERSE_UNORDERED_SELECTS "REVERSE_UNORDERED_SELECTS", #endif #ifdef SQLITE_RTREE_INT_ONLY "RTREE_INT_ONLY", #endif #ifdef SQLITE_SECURE_DELETE "SECURE_DELETE", #endif #ifdef SQLITE_SMALL_STACK "SMALL_STACK", #endif #ifdef SQLITE_SORTER_PMASZ "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ), #endif #ifdef SQLITE_SOUNDEX "SOUNDEX", #endif #ifdef SQLITE_STAT4_SAMPLES "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES), #endif #ifdef SQLITE_STMTJRNL_SPILL "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), #endif #ifdef SQLITE_SUBSTR_COMPATIBILITY "SUBSTR_COMPATIBILITY", #endif #if (!defined(SQLITE_WIN32_MALLOC) \ && !defined(SQLITE_ZERO_MALLOC) \ && !defined(SQLITE_MEMDEBUG) \ ) || defined(SQLITE_SYSTEM_MALLOC) "SYSTEM_MALLOC", #endif #ifdef SQLITE_TCL "TCL", #endif #ifdef SQLITE_TEMP_STORE "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), #endif #ifdef SQLITE_TEST "TEST", #endif #if defined(SQLITE_THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), #elif defined(THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE), #else "THREADSAFE=1", #endif #ifdef SQLITE_UNLINK_AFTER_CLOSE "UNLINK_AFTER_CLOSE", #endif #ifdef SQLITE_UNTESTABLE "UNTESTABLE", #endif #ifdef SQLITE_USER_AUTHENTICATION "USER_AUTHENTICATION", #endif #ifdef SQLITE_USE_ALLOCA "USE_ALLOCA", #endif #ifdef SQLITE_USE_FCNTL_TRACE "USE_FCNTL_TRACE", #endif #ifdef SQLITE_USE_URI "USE_URI", #endif #ifdef SQLITE_VDBE_COVERAGE "VDBE_COVERAGE", #endif #ifdef SQLITE_WIN32_MALLOC "WIN32_MALLOC", #endif #ifdef SQLITE_ZERO_MALLOC "ZERO_MALLOC", #endif } ; SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){ *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]); return (const char**)sqlite3azCompileOpt; } #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ /************** End of ctime.c ***********************************************/ /************** Begin file global.c ******************************************/ /* ** 2008 June 13 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains definitions of global variables and constants. */ /* #include "sqliteInt.h" */ /* An array to map all upper-case characters into their corresponding ** lower-case character. ** ** SQLite only considers US-ASCII (or EBCDIC) characters. We do not ** handle case conversions for the UTF character set since the tables ** involved are nearly as big or bigger than SQLite itself. */ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = { #ifdef SQLITE_ASCII 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107, 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, 252,253,254,255, #endif #ifdef SQLITE_EBCDIC 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */ 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */ 160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */ 192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */ 208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */ 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */ #endif /* All of the upper-to-lower conversion data is above. The following ** 18 integers are completely unrelated. They are appended to the ** sqlite3UpperToLower[] array to avoid UBSAN warnings. Here's what is ** going on: ** ** The SQL comparison operators (<>, =, >, <=, <, and >=) are implemented ** by invoking sqlite3MemCompare(A,B) which compares values A and B and ** returns negative, zero, or positive if A is less then, equal to, or ** greater than B, respectively. Then the true false results is found by ** consulting sqlite3aLTb[opcode], sqlite3aEQb[opcode], or ** sqlite3aGTb[opcode] depending on whether the result of compare(A,B) ** is negative, zero, or positive, where opcode is the specific opcode. ** The only works because the comparison opcodes are consecutive and in ** this order: NE EQ GT LE LT GE. Various assert()s throughout the code ** ensure that is the case. ** ** These elements must be appended to another array. Otherwise the ** index (here shown as [256-OP_Ne]) would be out-of-bounds and thus ** be undefined behavior. That's goofy, but the C-standards people thought ** it was a good idea, so here we are. */ /* NE EQ GT LE LT GE */ 1, 0, 0, 1, 1, 0, /* aLTb[]: Use when compare(A,B) less than zero */ 0, 1, 0, 1, 0, 1, /* aEQb[]: Use when compare(A,B) equals zero */ 1, 0, 1, 0, 0, 1 /* aGTb[]: Use when compare(A,B) greater than zero*/ }; SQLITE_PRIVATE const unsigned char *sqlite3aLTb = &sqlite3UpperToLower[256-OP_Ne]; SQLITE_PRIVATE const unsigned char *sqlite3aEQb = &sqlite3UpperToLower[256+6-OP_Ne]; SQLITE_PRIVATE const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP_Ne]; /* ** The following 256 byte lookup table is used to support SQLites built-in ** equivalents to the following standard library functions: ** ** isspace() 0x01 ** isalpha() 0x02 ** isdigit() 0x04 ** isalnum() 0x06 ** isxdigit() 0x08 ** toupper() 0x20 ** SQLite identifier character 0x40 $, _, or non-ascii ** Quote character 0x80 ** ** Bit 0x20 is set if the mapped character requires translation to upper ** case. i.e. if the character is a lower-case ASCII character. ** If x is a lower-case ASCII character, then its upper-case equivalent ** is (x - 0x20). Therefore toupper() can be implemented as: ** ** (x & ~(map[x]&0x20)) ** ** The equivalent of tolower() is implemented using the sqlite3UpperToLower[] ** array. tolower() is used more often than toupper() by SQLite. ** ** Bit 0x40 is set if the character is non-alphanumeric and can be used in an ** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any ** non-ASCII UTF character. Hence the test for whether or not a character is ** part of an identifier is 0x46. */ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */ 0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */ 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */ 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */ 0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */ 0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */ 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 98..9f ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a0..a7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ }; /* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards ** compatibility for legacy applications, the URI filename capability is ** disabled by default. ** ** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled ** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options. ** ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** SQLITE_USE_URI symbol defined. */ #ifndef SQLITE_USE_URI # define SQLITE_USE_URI 0 #endif /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the ** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if ** that compile-time option is omitted. */ #if !defined(SQLITE_ALLOW_COVERING_INDEX_SCAN) # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 #else # if !SQLITE_ALLOW_COVERING_INDEX_SCAN # error "Compile-time disabling of covering index scan using the\ -DSQLITE_ALLOW_COVERING_INDEX_SCAN=0 option is deprecated.\ Contact SQLite developers if this is a problem for you, and\ delete this #error macro to continue with your build." # endif #endif /* The minimum PMA size is set to this value multiplied by the database ** page size in bytes. */ #ifndef SQLITE_SORTER_PMASZ # define SQLITE_SORTER_PMASZ 250 #endif /* Statement journals spill to disk when their size exceeds the following ** threshold (in bytes). 0 means that statement journals are created and ** written to disk immediately (the default behavior for SQLite versions ** before 3.12.0). -1 means always keep the entire statement journal in ** memory. (The statement journal is also always held entirely in memory ** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this ** setting.) */ #ifndef SQLITE_STMTJRNL_SPILL # define SQLITE_STMTJRNL_SPILL (64*1024) #endif /* ** The default lookaside-configuration, the format "SZ,N". SZ is the ** number of bytes in each lookaside slot (should be a multiple of 8) ** and N is the number of slots. The lookaside-configuration can be ** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE) ** or at run-time for an individual database connection using ** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE); ** ** With the two-size-lookaside enhancement, less lookaside is required. ** The default configuration of 1200,40 actually provides 30 1200-byte slots ** and 93 128-byte slots, which is more lookaside than is available ** using the older 1200,100 configuration without two-size-lookaside. */ #ifndef SQLITE_DEFAULT_LOOKASIDE # ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE # define SQLITE_DEFAULT_LOOKASIDE 1200,100 /* 120KB of memory */ # else # define SQLITE_DEFAULT_LOOKASIDE 1200,40 /* 48KB of memory */ # endif #endif /* The default maximum size of an in-memory database created using ** sqlite3_deserialize() */ #ifndef SQLITE_MEMDB_DEFAULT_MAXSIZE # define SQLITE_MEMDB_DEFAULT_MAXSIZE 1073741824 #endif /* ** The following singleton contains the global configuration for ** the SQLite library. */ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */ 1, /* bCoreMutex */ SQLITE_THREADSAFE==1, /* bFullMutex */ SQLITE_USE_URI, /* bOpenUri */ SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ 0, /* bSmallMalloc */ 1, /* bExtraSchemaChecks */ sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */ #ifdef SQLITE_DEBUG 0, /* bJsonSelfcheck */ #endif 0x7ffffffe, /* mxStrlen */ 0, /* neverCorrupt */ SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */ SQLITE_STMTJRNL_SPILL, /* nStmtSpill */ {0,0,0,0,0,0,0,0}, /* m */ {0,0,0,0,0,0,0,0,0}, /* mutex */ {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */ (void*)0, /* pHeap */ 0, /* nHeap */ 0, 0, /* mnHeap, mxHeap */ SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */ SQLITE_MAX_MMAP_SIZE, /* mxMmap */ (void*)0, /* pPage */ 0, /* szPage */ SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */ 0, /* mxParserStack */ 0, /* sharedCacheEnabled */ SQLITE_SORTER_PMASZ, /* szPma */ /* All the rest should always be initialized to zero */ 0, /* isInit */ 0, /* inProgress */ 0, /* isMutexInit */ 0, /* isMallocInit */ 0, /* isPCacheInit */ 0, /* nRefInitMutex */ 0, /* pInitMutex */ 0, /* xLog */ 0, /* pLogArg */ #ifdef SQLITE_ENABLE_SQLLOG 0, /* xSqllog */ 0, /* pSqllogArg */ #endif #ifdef SQLITE_VDBE_COVERAGE 0, /* xVdbeBranch */ 0, /* pVbeBranchArg */ #endif #ifndef SQLITE_OMIT_DESERIALIZE SQLITE_MEMDB_DEFAULT_MAXSIZE, /* mxMemdbSize */ #endif #ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ #endif 0, /* bLocaltimeFault */ 0, /* xAltLocaltime */ 0x7ffffffe, /* iOnceResetThreshold */ SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ 0, /* iPrngSeed */ #ifdef SQLITE_DEBUG {0,0,0,0,0,0}, /* aTune */ #endif }; /* ** Hash table for global functions - functions common to all ** database connections. After initialization, this table is ** read-only. */ SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) /* ** Counter used for coverage testing. Does not come into play for ** release builds. ** ** Access to this global variable is not mutex protected. This might ** result in TSAN warnings. But as the variable does not exist in ** release builds, that should not be a concern. */ SQLITE_PRIVATE unsigned int sqlite3CoverageCounter; #endif /* SQLITE_COVERAGE_TEST || SQLITE_DEBUG */ #ifdef VDBE_PROFILE /* ** The following performance counter can be used in place of ** sqlite3Hwtime() for profiling. This is a no-op on standard builds. */ SQLITE_PRIVATE sqlite3_uint64 sqlite3NProfileCnt = 0; #endif /* ** The value of the "pending" byte must be 0x40000000 (1 byte past the ** 1-gibabyte boundary) in a compatible database. SQLite never uses ** the database page that contains the pending byte. It never attempts ** to read or write that page. The pending byte page is set aside ** for use by the VFS layers as space for managing file locks. ** ** During testing, it is often desirable to move the pending byte to ** a different position in the file. This allows code that has to ** deal with the pending byte to run on files that are much smaller ** than 1 GiB. The sqlite3_test_control() interface can be used to ** move the pending byte. ** ** IMPORTANT: Changing the pending byte to any value other than ** 0x40000000 results in an incompatible database file format! ** Changing the pending byte during operation will result in undefined ** and incorrect behavior. */ #ifndef SQLITE_OMIT_WSD SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000; #endif /* ** Tracing flags set by SQLITE_TESTCTRL_TRACEFLAGS. */ SQLITE_PRIVATE u32 sqlite3TreeTrace = 0; SQLITE_PRIVATE u32 sqlite3WhereTrace = 0; /* #include "opcodes.h" */ /* ** Properties of opcodes. The OPFLG_INITIALIZER macro is ** created by mkopcodeh.awk during compilation. Data is obtained ** from the comments following the "case OP_xxxx:" statements in ** the vdbe.c file. */ SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER; /* ** Name of the default collating sequence */ SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY"; /* ** Standard typenames. These names must match the COLTYPE_* definitions. ** Adjust the SQLITE_N_STDTYPE value if adding or removing entries. ** ** sqlite3StdType[] The actual names of the datatypes. ** ** sqlite3StdTypeLen[] The length (in bytes) of each entry ** in sqlite3StdType[]. ** ** sqlite3StdTypeAffinity[] The affinity associated with each entry ** in sqlite3StdType[]. */ SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 }; SQLITE_PRIVATE const char sqlite3StdTypeAffinity[] = { SQLITE_AFF_NUMERIC, SQLITE_AFF_BLOB, SQLITE_AFF_INTEGER, SQLITE_AFF_INTEGER, SQLITE_AFF_REAL, SQLITE_AFF_TEXT }; SQLITE_PRIVATE const char *sqlite3StdType[] = { "ANY", "BLOB", "INT", "INTEGER", "REAL", "TEXT" }; /************** End of global.c **********************************************/ /************** Begin file status.c ******************************************/ /* ** 2008 June 18 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This module implements the sqlite3_status() interface and related ** functionality. */ /* #include "sqliteInt.h" */ /************** Include vdbeInt.h in the middle of status.c ******************/ /************** Begin file vdbeInt.h *****************************************/ /* ** 2003 September 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the header file for information that is private to the ** VDBE. This information used to all be at the top of the single ** source code file "vdbe.c". When that file became too big (over ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. */ #ifndef SQLITE_VDBEINT_H #define SQLITE_VDBEINT_H /* ** The maximum number of times that a statement will try to reparse ** itself before giving up and returning SQLITE_SCHEMA. */ #ifndef SQLITE_MAX_SCHEMA_RETRY # define SQLITE_MAX_SCHEMA_RETRY 50 #endif /* ** VDBE_DISPLAY_P4 is true or false depending on whether or not the ** "explain" P4 display logic is enabled. */ #if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \ || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) \ || defined(SQLITE_ENABLE_BYTECODE_VTAB) # define VDBE_DISPLAY_P4 1 #else # define VDBE_DISPLAY_P4 0 #endif /* ** SQL is translated into a sequence of instructions to be ** executed by a virtual machine. Each instruction is an instance ** of the following structure. */ typedef struct VdbeOp Op; /* ** Boolean values */ typedef unsigned Bool; /* Opaque type used by code in vdbesort.c */ typedef struct VdbeSorter VdbeSorter; /* Elements of the linked list at Vdbe.pAuxData */ typedef struct AuxData AuxData; /* A cache of large TEXT or BLOB values in a VdbeCursor */ typedef struct VdbeTxtBlbCache VdbeTxtBlbCache; /* Types of VDBE cursors */ #define CURTYPE_BTREE 0 #define CURTYPE_SORTER 1 #define CURTYPE_VTAB 2 #define CURTYPE_PSEUDO 3 /* ** A VdbeCursor is an superclass (a wrapper) for various cursor objects: ** ** * A b-tree cursor ** - In the main database or in an ephemeral database ** - On either an index or a table ** * A sorter ** * A virtual table ** * A one-row "pseudotable" stored in a single register */ typedef struct VdbeCursor VdbeCursor; struct VdbeCursor { u8 eCurType; /* One of the CURTYPE_* values above */ i8 iDb; /* Index of cursor database in db->aDb[] */ u8 nullRow; /* True if pointing to a row with no data */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ u8 isTable; /* True for rowid tables. False for indexes */ #ifdef SQLITE_DEBUG u8 seekOp; /* Most recent seek operation on this cursor */ u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */ #endif Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */ Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */ Bool noReuse:1; /* OpenEphemeral may not reuse this cursor */ Bool colCache:1; /* pCache pointer is initialized and non-NULL */ u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */ union { /* pBtx for isEphermeral. pAltMap otherwise */ Btree *pBtx; /* Separate file holding temporary table */ u32 *aAltMap; /* Mapping from table to index column numbers */ } ub; i64 seqCount; /* Sequence counter */ /* Cached OP_Column parse information is only valid if cacheStatus matches ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of ** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that ** the cache is out of date. */ u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0 ** if there have been no prior seeks on the cursor. */ /* seekResult does not distinguish between "no seeks have ever occurred ** on this cursor" and "the most recent seek was an exact match". ** For CURTYPE_PSEUDO, seekResult is the register holding the record */ /* When a new VdbeCursor is allocated, only the fields above are zeroed. ** The fields that follow are uninitialized, and must be individually ** initialized prior to first use. */ VdbeCursor *pAltCursor; /* Associated index cursor from which to read */ union { BtCursor *pCursor; /* CURTYPE_BTREE or _PSEUDO. Btree cursor */ sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */ VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */ } uc; KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ u32 iHdrOffset; /* Offset to next unparsed byte of the header */ Pgno pgnoRoot; /* Root page of the open btree cursor */ i16 nField; /* Number of fields in the header */ u16 nHdrParsed; /* Number of header fields parsed so far */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ u32 *aOffset; /* Pointer to aType[nField] */ const u8 *aRow; /* Data for the current row, if all on one page */ u32 payloadSize; /* Total number of bytes in the record */ u32 szRow; /* Byte available in aRow */ #ifdef SQLITE_ENABLE_COLUMN_USED_MASK u64 maskUsed; /* Mask of columns used by this cursor */ #endif VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */ /* 2*nField extra array elements allocated for aType[], beyond the one ** static element declared in the structure. nField total array slots for ** aType[] and nField+1 array slots for aOffset[] */ u32 aType[1]; /* Type values record decode. MUST BE LAST */ }; /* Return true if P is a null-only cursor */ #define IsNullCursor(P) \ ((P)->eCurType==CURTYPE_PSEUDO && (P)->nullRow && (P)->seekResult==0) /* ** A value for VdbeCursor.cacheStatus that means the cache is always invalid. */ #define CACHE_STALE 0 /* ** Large TEXT or BLOB values can be slow to load, so we want to avoid ** loading them more than once. For that reason, large TEXT and BLOB values ** can be stored in a cache defined by this object, and attached to the ** VdbeCursor using the pCache field. */ struct VdbeTxtBlbCache { char *pCValue; /* A RCStr buffer to hold the value */ i64 iOffset; /* File offset of the row being cached */ int iCol; /* Column for which the cache is valid */ u32 cacheStatus; /* Vdbe.cacheCtr value */ u32 colCacheCtr; /* Column cache counter */ }; /* ** When a sub-program is executed (OP_Program), a structure of this type ** is allocated to store the current value of the program counter, as ** well as the current memory cell array and various other frame specific ** values stored in the Vdbe struct. When the sub-program is finished, ** these values are copied back to the Vdbe from the VdbeFrame structure, ** restoring the state of the VM to as it was before the sub-program ** began executing. ** ** The memory for a VdbeFrame object is allocated and managed by a memory ** cell in the parent (calling) frame. When the memory cell is deleted or ** overwritten, the VdbeFrame object is not freed immediately. Instead, it ** is linked into the Vdbe.pDelFrame list. The contents of the Vdbe.pDelFrame ** list is deleted when the VM is reset in VdbeHalt(). The reason for doing ** this instead of deleting the VdbeFrame immediately is to avoid recursive ** calls to sqlite3VdbeMemRelease() when the memory cells belonging to the ** child frame are released. ** ** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is ** set to NULL if the currently executing frame is the main program. */ typedef struct VdbeFrame VdbeFrame; struct VdbeFrame { Vdbe *v; /* VM this frame belongs to */ VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */ Op *aOp; /* Program instructions for parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ u8 *aOnce; /* Bitmask used by OP_Once */ void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ AuxData *pAuxData; /* Linked list of auxdata allocations */ #if SQLITE_DEBUG u32 iFrameMagic; /* magic number for sanity checking */ #endif int nCursor; /* Number of entries in apCsr */ int pc; /* Program Counter in parent (calling) frame */ int nOp; /* Size of aOp array */ int nMem; /* Number of entries in aMem */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ i64 nChange; /* Statement changes (Vdbe.nChange) */ i64 nDbChange; /* Value of db->nChange */ }; /* Magic number for sanity checking on VdbeFrame objects */ #define SQLITE_FRAME_MAGIC 0x879fb71e /* ** Return a pointer to the array of registers allocated for use ** by a VdbeFrame. */ #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) /* ** Internally, the vdbe manipulates nearly all SQL values as Mem ** structures. Each Mem struct may cache multiple representations (string, ** integer etc.) of the same value. */ struct sqlite3_value { union MemValue { double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ } u; char *z; /* String or BLOB value */ int n; /* Number of characters in string value, excluding '\0' */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ u8 eSubtype; /* Subtype for this value */ /* ShallowCopy only needs to copy the information above */ sqlite3 *db; /* The associated database connection */ int szMalloc; /* Size of the zMalloc allocation */ u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */ char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ u16 mScopyFlags; /* flags value immediately after the shallow copy */ #endif }; /* ** Size of struct Mem not including the Mem.zMalloc member or anything that ** follows. */ #define MEMCELLSIZE offsetof(Mem,db) /* One or more of the following flags are set to indicate the ** representations of the value stored in the Mem struct. ** ** * MEM_Null An SQL NULL value ** ** * MEM_Null|MEM_Zero An SQL NULL with the virtual table ** UPDATE no-change flag set ** ** * MEM_Null|MEM_Term| An SQL NULL, but also contains a ** MEM_Subtype pointer accessible using ** sqlite3_value_pointer(). ** ** * MEM_Null|MEM_Cleared Special SQL NULL that compares non-equal ** to other NULLs even using the IS operator. ** ** * MEM_Str A string, stored in Mem.z with ** length Mem.n. Zero-terminated if ** MEM_Term is set. This flag is ** incompatible with MEM_Blob and ** MEM_Null, but can appear with MEM_Int, ** MEM_Real, and MEM_IntReal. ** ** * MEM_Blob A blob, stored in Mem.z length Mem.n. ** Incompatible with MEM_Str, MEM_Null, ** MEM_Int, MEM_Real, and MEM_IntReal. ** ** * MEM_Blob|MEM_Zero A blob in Mem.z of length Mem.n plus ** MEM.u.i extra 0x00 bytes at the end. ** ** * MEM_Int Integer stored in Mem.u.i. ** ** * MEM_Real Real stored in Mem.u.r. ** ** * MEM_IntReal Real stored as an integer in Mem.u.i. ** ** If the MEM_Null flag is set, then the value is an SQL NULL value. ** For a pointer type created using sqlite3_bind_pointer() or ** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set. ** ** If the MEM_Str flag is set then Mem.z points at a string representation. ** Usually this is encoded in the same unicode encoding as the main ** database (see below for exceptions). If the MEM_Term flag is also ** set, then the string is nul terminated. The MEM_Int and MEM_Real ** flags may coexist with the MEM_Str flag. */ #define MEM_Undefined 0x0000 /* Value is undefined */ #define MEM_Null 0x0001 /* Value is NULL (or a pointer) */ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_IntReal 0x0020 /* MEM_Int that stringifies like MEM_Real */ #define MEM_AffMask 0x003f /* Mask of affinity bits */ /* Extra bits that modify the meanings of the core datatypes above */ #define MEM_FromBind 0x0040 /* Value originates from sqlite3_bind() */ /* 0x0080 // Available */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ #define MEM_Term 0x0200 /* String in Mem.z is zero terminated */ #define MEM_Zero 0x0400 /* Mem.i contains count of 0s appended to blob */ #define MEM_Subtype 0x0800 /* Mem.eSubtype is valid */ #define MEM_TypeMask 0x0dbf /* Mask of type bits */ /* Bits that determine the storage for Mem.z for a string or blob or ** aggregate accumulator. */ #define MEM_Dyn 0x1000 /* Need to call Mem.xDel() on Mem.z */ #define MEM_Static 0x2000 /* Mem.z points to a static string */ #define MEM_Ephem 0x4000 /* Mem.z points to an ephemeral string */ #define MEM_Agg 0x8000 /* Mem.z points to an agg function context */ /* Return TRUE if Mem X contains dynamically allocated content - anything ** that needs to be deallocated to avoid a leak. */ #define VdbeMemDynamic(X) \ (((X)->flags&(MEM_Agg|MEM_Dyn))!=0) /* ** Clear any existing type flags from a Mem and replace them with f */ #define MemSetTypeFlag(p, f) \ ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f) /* ** True if Mem X is a NULL-nochng type. */ #define MemNullNochng(X) \ (((X)->flags&MEM_TypeMask)==(MEM_Null|MEM_Zero) \ && (X)->n==0 && (X)->u.nZero==0) /* ** Return true if a memory cell has been initialized and is valid. ** is for use inside assert() statements only. ** ** A Memory cell is initialized if at least one of the ** MEM_Null, MEM_Str, MEM_Int, MEM_Real, MEM_Blob, or MEM_IntReal bits ** is set. It is "undefined" if all those bits are zero. */ #ifdef SQLITE_DEBUG #define memIsValid(M) ((M)->flags & MEM_AffMask)!=0 #endif /* ** Each auxiliary data pointer stored by a user defined function ** implementation calling sqlite3_set_auxdata() is stored in an instance ** of this structure. All such structures associated with a single VM ** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed ** when the VM is halted (if not before). */ struct AuxData { int iAuxOp; /* Instruction number of OP_Function opcode */ int iAuxArg; /* Index of function argument. */ void *pAux; /* Aux data pointer */ void (*xDeleteAux)(void*); /* Destructor for the aux data */ AuxData *pNextAux; /* Next element in list */ }; /* ** The "context" argument for an installable function. A pointer to an ** instance of this structure is the first argument to the routines used ** implement the SQL functions. ** ** There is a typedef for this structure in sqlite.h. So all routines, ** even the public interface to SQLite, can use a pointer to this structure. ** But this file is the only place where the internal details of this ** structure are known. ** ** This structure is defined inside of vdbeInt.h because it uses substructures ** (Mem) which are only defined there. */ struct sqlite3_context { Mem *pOut; /* The return value is stored here */ FuncDef *pFunc; /* Pointer to function information */ Mem *pMem; /* Memory cell used to store aggregate context */ Vdbe *pVdbe; /* The VM that owns this context */ int iOp; /* Instruction number of OP_Function */ int isError; /* Error code returned by the function. */ u8 enc; /* Encoding to use for results */ u8 skipFlag; /* Skip accumulator loading if true */ u8 argc; /* Number of arguments */ sqlite3_value *argv[1]; /* Argument set */ }; /* A bitfield type for use inside of structures. Always follow with :N where ** N is the number of bits. */ typedef unsigned bft; /* Bit Field Type */ /* The ScanStatus object holds a single value for the ** sqlite3_stmt_scanstatus() interface. ** ** aAddrRange[]: ** This array is used by ScanStatus elements associated with EQP ** notes that make an SQLITE_SCANSTAT_NCYCLE value available. It is ** an array of up to 3 ranges of VM addresses for which the Vdbe.anCycle[] ** values should be summed to calculate the NCYCLE value. Each pair of ** integer addresses is a start and end address (both inclusive) for a range ** instructions. A start value of 0 indicates an empty range. */ typedef struct ScanStatus ScanStatus; struct ScanStatus { int addrExplain; /* OP_Explain for loop */ int aAddrRange[6]; int addrLoop; /* Address of "loops" counter */ int addrVisit; /* Address of "rows visited" counter */ int iSelectID; /* The "Select-ID" for this loop */ LogEst nEst; /* Estimated output rows per loop */ char *zName; /* Name of table or index */ }; /* The DblquoteStr object holds the text of a double-quoted ** string for a prepared statement. A linked list of these objects ** is constructed during statement parsing and is held on Vdbe.pDblStr. ** When computing a normalized SQL statement for an SQL statement, that ** list is consulted for each double-quoted identifier to see if the ** identifier should really be a string literal. */ typedef struct DblquoteStr DblquoteStr; struct DblquoteStr { DblquoteStr *pNextStr; /* Next string literal in the list */ char z[8]; /* Dequoted value for the string */ }; /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare() ** is really a pointer to an instance of this structure. */ struct Vdbe { sqlite3 *db; /* The database connection that owns this statement */ Vdbe **ppVPrev,*pVNext; /* Linked list of VDBEs with the same Vdbe.db */ Parse *pParse; /* Parsing context used to create this Vdbe */ ynVar nVar; /* Number of entries in aVar[] */ int nMem; /* Number of memory locations currently allocated */ int nCursor; /* Number of slots in apCsr[] */ u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ i64 nChange; /* Number of db changes made since last reset */ int iStatement; /* Statement number (or 0 if has no opened stmt) */ i64 iCurrentTime; /* Value of julianday('now') for this statement */ i64 nFkConstraint; /* Number of imm. FK constraints this VM */ i64 nStmtDefCons; /* Number of def. constraints when stmt started */ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ Mem *aMem; /* The memory locations */ Mem **apArg; /* Arguments to currently executing user function */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ Mem *aVar; /* Values for the OP_Variable opcode. */ /* When allocating a new Vdbe object, all of the fields below should be ** initialized to zero or NULL */ Op *aOp; /* Space to hold the virtual machine's program */ int nOp; /* Number of instructions in the program */ int nOpAlloc; /* Slots allocated for aOp[] */ Mem *aColName; /* Column names to return */ Mem *pResultRow; /* Current output row */ char *zErrMsg; /* Error message written here */ VList *pVList; /* Name of variables */ #ifndef SQLITE_OMIT_TRACE i64 startTime; /* Time when query started - used for profiling */ #endif #ifdef SQLITE_DEBUG int rcApp; /* errcode set by sqlite3_result_error_code() */ u32 nWrite; /* Number of write operations that have occurred */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u16 nResAlloc; /* Column slots allocated to aColName[] */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 eVdbeState; /* On of the VDBE_*_STATE values */ bft expired:2; /* 1: recompile VM immediately 2: when convenient */ bft explain:2; /* 0: normal, 1: EXPLAIN, 2: EXPLAIN QUERY PLAN */ bft changeCntOn:1; /* True to update the change-counter */ bft usesStmtJournal:1; /* True if uses a statement journal */ bft readOnly:1; /* True for statements that do not write */ bft bIsReader:1; /* True for statements that read */ bft haveEqpOps:1; /* Bytecode supports EXPLAIN QUERY PLAN */ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ yDbMask lockMask; /* Subset of btreeMask that requires a lock */ u32 aCounter[9]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ #ifdef SQLITE_ENABLE_NORMALIZE char *zNormSql; /* Normalization of the associated SQL statement */ DblquoteStr *pDblStr; /* List of double-quoted string literals */ #endif void *pFree; /* Free this when deleting the vdbe */ VdbeFrame *pFrame; /* Parent frame */ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ int nFrame; /* Number of frames in pFrame list */ u32 expmask; /* Binding to these vars invalidates VM */ SubProgram *pProgram; /* Linked list of all sub-programs used by VM */ AuxData *pAuxData; /* Linked list of auxdata allocations */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int nScan; /* Entries in aScan[] */ ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ #endif }; /* ** The following are allowed values for Vdbe.eVdbeState */ #define VDBE_INIT_STATE 0 /* Prepared statement under construction */ #define VDBE_READY_STATE 1 /* Ready to run but not yet started */ #define VDBE_RUN_STATE 2 /* Run in progress */ #define VDBE_HALT_STATE 3 /* Finished. Need reset() or finalize() */ /* ** Structure used to store the context required by the ** sqlite3_preupdate_*() API functions. */ struct PreUpdate { Vdbe *v; VdbeCursor *pCsr; /* Cursor to read old values from */ int op; /* One of SQLITE_INSERT, UPDATE, DELETE */ u8 *aRecord; /* old.* database record */ KeyInfo keyinfo; UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */ UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */ int iNewReg; /* Register for new.* values */ int iBlobWrite; /* Value returned by preupdate_blobwrite() */ i64 iKey1; /* First key value passed to hook */ i64 iKey2; /* Second key value passed to hook */ Mem *aNew; /* Array of new.* values */ Table *pTab; /* Schema object being updated */ Index *pPk; /* PK index if pTab is WITHOUT ROWID */ }; /* ** An instance of this object is used to pass an vector of values into ** OP_VFilter, the xFilter method of a virtual table. The vector is the ** set of values on the right-hand side of an IN constraint. ** ** The value as passed into xFilter is an sqlite3_value with a "pointer" ** type, such as is generated by sqlite3_result_pointer() and read by ** sqlite3_value_pointer. Such values have MEM_Term|MEM_Subtype|MEM_Null ** and a subtype of 'p'. The sqlite3_vtab_in_first() and _next() interfaces ** know how to use this object to step through all the values in the ** right operand of the IN constraint. */ typedef struct ValueList ValueList; struct ValueList { BtCursor *pCsr; /* An ephemeral table holding all values */ sqlite3_value *pOut; /* Register to hold each decoded output value */ }; /* Size of content associated with serial types that fit into a ** single-byte varint. */ #ifndef SQLITE_AMALGAMATION SQLITE_PRIVATE const u8 sqlite3SmallTypeSizes[]; #endif /* ** Function prototypes */ SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...); SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); SQLITE_PRIVATE void sqlite3VdbeFreeCursorNN(Vdbe*,VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeHandleMovedCursor(VdbeCursor *p); SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*); SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*); SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32); SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8); #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT SQLITE_PRIVATE u64 sqlite3FloatSwap(u64 in); # define swapMixedEndianFloat(X) X = sqlite3FloatSwap(X) #else # define swapMixedEndianFloat(X) #endif SQLITE_PRIVATE void sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*); SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*); SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*); #if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB) SQLITE_PRIVATE int sqlite3VdbeNextOpcode(Vdbe*,Mem*,int,int*,int*,Op**); SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3*,Op*); #endif #if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) SQLITE_PRIVATE char *sqlite3VdbeDisplayComment(sqlite3*,const Op*,const char*); #endif #if !defined(SQLITE_OMIT_EXPLAIN) SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*); #endif SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int); SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem*, const Mem*); SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, i64, u8, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64); #ifdef SQLITE_OMIT_FLOATING_POINT # define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64 #else SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double); #endif SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*); #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int); #else SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem*,int); #endif #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*); #endif SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*); SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8); SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double); SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem*); SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*); SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*); SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem*, int ifNull); SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem*,u8,u8); SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*); SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset(BtCursor*,u32,Mem*); SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); SQLITE_PRIVATE void sqlite3VdbeMemReleaseMalloc(Mem*p); SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*); #endif #if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB) SQLITE_PRIVATE const char *sqlite3OpcodeName(int); #endif SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3VdbeFrameIsValid(VdbeFrame*); #endif SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int,int); #endif SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); SQLITE_PRIVATE void sqlite3VdbeValueListFree(void*); #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*); SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe*); #else # define sqlite3VdbeIncrWriteCounter(V,C) # define sqlite3VdbeAssertAbortable(V) #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*); #else # define sqlite3VdbeEnter(X) #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*); #else # define sqlite3VdbeLeave(X) #endif #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*); SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem*); #endif #ifndef SQLITE_OMIT_FOREIGN_KEY SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int); #else # define sqlite3VdbeCheckFk(p,i) 0 #endif #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr); #endif #ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8); SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem); #endif #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *); #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) #else #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK #define ExpandBlob(P) SQLITE_OK #endif #endif /* !defined(SQLITE_VDBEINT_H) */ /************** End of vdbeInt.h *********************************************/ /************** Continuing where we left off in status.c *********************/ /* ** Variables in which to record status information. */ #if SQLITE_PTRSIZE>4 typedef sqlite3_int64 sqlite3StatValueType; #else typedef u32 sqlite3StatValueType; #endif typedef struct sqlite3StatType sqlite3StatType; static SQLITE_WSD struct sqlite3StatType { sqlite3StatValueType nowValue[10]; /* Current value */ sqlite3StatValueType mxValue[10]; /* Maximum value */ } sqlite3Stat = { {0,}, {0,} }; /* ** Elements of sqlite3Stat[] are protected by either the memory allocator ** mutex, or by the pcache1 mutex. The following array determines which. */ static const char statMutex[] = { 0, /* SQLITE_STATUS_MEMORY_USED */ 1, /* SQLITE_STATUS_PAGECACHE_USED */ 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */ 0, /* SQLITE_STATUS_SCRATCH_USED */ 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */ 0, /* SQLITE_STATUS_MALLOC_SIZE */ 0, /* SQLITE_STATUS_PARSER_STACK */ 1, /* SQLITE_STATUS_PAGECACHE_SIZE */ 0, /* SQLITE_STATUS_SCRATCH_SIZE */ 0, /* SQLITE_STATUS_MALLOC_COUNT */ }; /* The "wsdStat" macro will resolve to the status information ** state vector. If writable static data is unsupported on the target, ** we have to locate the state vector at run-time. In the more common ** case where writable static data is supported, wsdStat can refer directly ** to the "sqlite3Stat" state vector declared above. */ #ifdef SQLITE_OMIT_WSD # define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat) # define wsdStat x[0] #else # define wsdStatInit # define wsdStat sqlite3Stat #endif /* ** Return the current value of a status parameter. The caller must ** be holding the appropriate mutex. */ SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int op){ wsdStatInit; assert( op>=0 && op=0 && op=0 && op=0 && opwsdStat.mxValue[op] ){ wsdStat.mxValue[op] = wsdStat.nowValue[op]; } } SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){ wsdStatInit; assert( N>=0 ); assert( op>=0 && op=0 && op=0 ); newValue = (sqlite3StatValueType)X; assert( op>=0 && op=0 && opwsdStat.mxValue[op] ){ wsdStat.mxValue[op] = newValue; } } /* ** Query status information. */ SQLITE_API int sqlite3_status64( int op, sqlite3_int64 *pCurrent, sqlite3_int64 *pHighwater, int resetFlag ){ sqlite3_mutex *pMutex; wsdStatInit; if( op<0 || op>=ArraySize(wsdStat.nowValue) ){ return SQLITE_MISUSE_BKPT; } #ifdef SQLITE_ENABLE_API_ARMOR if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; #endif pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex(); sqlite3_mutex_enter(pMutex); *pCurrent = wsdStat.nowValue[op]; *pHighwater = wsdStat.mxValue[op]; if( resetFlag ){ wsdStat.mxValue[op] = wsdStat.nowValue[op]; } sqlite3_mutex_leave(pMutex); (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */ return SQLITE_OK; } SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ sqlite3_int64 iCur = 0, iHwtr = 0; int rc; #ifdef SQLITE_ENABLE_API_ARMOR if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; #endif rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag); if( rc==0 ){ *pCurrent = (int)iCur; *pHighwater = (int)iHwtr; } return rc; } /* ** Return the number of LookasideSlot elements on the linked list */ static u32 countLookasideSlots(LookasideSlot *p){ u32 cnt = 0; while( p ){ p = p->pNext; cnt++; } return cnt; } /* ** Count the number of slots of lookaside memory that are outstanding */ SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){ u32 nInit = countLookasideSlots(db->lookaside.pInit); u32 nFree = countLookasideSlots(db->lookaside.pFree); #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE nInit += countLookasideSlots(db->lookaside.pSmallInit); nFree += countLookasideSlots(db->lookaside.pSmallFree); #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit; return db->lookaside.nSlot - (nInit+nFree); } /* ** Query status information for a single database connection */ SQLITE_API int sqlite3_db_status( sqlite3 *db, /* The database connection whose status is desired */ int op, /* Status verb */ int *pCurrent, /* Write current value here */ int *pHighwater, /* Write high-water mark here */ int resetFlag /* Reset high-water mark if true */ ){ int rc = SQLITE_OK; /* Return code */ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); switch( op ){ case SQLITE_DBSTATUS_LOOKASIDE_USED: { *pCurrent = sqlite3LookasideUsed(db, pHighwater); if( resetFlag ){ LookasideSlot *p = db->lookaside.pFree; if( p ){ while( p->pNext ) p = p->pNext; p->pNext = db->lookaside.pInit; db->lookaside.pInit = db->lookaside.pFree; db->lookaside.pFree = 0; } #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE p = db->lookaside.pSmallFree; if( p ){ while( p->pNext ) p = p->pNext; p->pNext = db->lookaside.pSmallInit; db->lookaside.pSmallInit = db->lookaside.pSmallFree; db->lookaside.pSmallFree = 0; } #endif } break; } case SQLITE_DBSTATUS_LOOKASIDE_HIT: case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE: case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: { testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT ); testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE ); testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL ); assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 ); assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 ); *pCurrent = 0; *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT]; if( resetFlag ){ db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0; } break; } /* ** Return an approximation for the amount of memory currently used ** by all pagers associated with the given database connection. The ** highwater mark is meaningless and is returned as zero. */ case SQLITE_DBSTATUS_CACHE_USED_SHARED: case SQLITE_DBSTATUS_CACHE_USED: { int totalUsed = 0; int i; sqlite3BtreeEnterAll(db); for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ Pager *pPager = sqlite3BtreePager(pBt); int nByte = sqlite3PagerMemUsed(pPager); if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){ nByte = nByte / sqlite3BtreeConnectionCount(pBt); } totalUsed += nByte; } } sqlite3BtreeLeaveAll(db); *pCurrent = totalUsed; *pHighwater = 0; break; } /* ** *pCurrent gets an accurate estimate of the amount of memory used ** to store the schema for all databases (main, temp, and any ATTACHed ** databases. *pHighwater is set to zero. */ case SQLITE_DBSTATUS_SCHEMA_USED: { int i; /* Used to iterate through schemas */ int nByte = 0; /* Used to accumulate return value */ sqlite3BtreeEnterAll(db); db->pnBytesFreed = &nByte; assert( db->lookaside.pEnd==db->lookaside.pTrueEnd ); db->lookaside.pEnd = db->lookaside.pStart; for(i=0; inDb; i++){ Schema *pSchema = db->aDb[i].pSchema; if( ALWAYS(pSchema!=0) ){ HashElem *p; nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( pSchema->tblHash.count + pSchema->trigHash.count + pSchema->idxHash.count + pSchema->fkeyHash.count ); nByte += sqlite3_msize(pSchema->tblHash.ht); nByte += sqlite3_msize(pSchema->trigHash.ht); nByte += sqlite3_msize(pSchema->idxHash.ht); nByte += sqlite3_msize(pSchema->fkeyHash.ht); for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); } for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); } } } db->pnBytesFreed = 0; db->lookaside.pEnd = db->lookaside.pTrueEnd; sqlite3BtreeLeaveAll(db); *pHighwater = 0; *pCurrent = nByte; break; } /* ** *pCurrent gets an accurate estimate of the amount of memory used ** to store all prepared statements. ** *pHighwater is set to zero. */ case SQLITE_DBSTATUS_STMT_USED: { struct Vdbe *pVdbe; /* Used to iterate through VMs */ int nByte = 0; /* Used to accumulate return value */ db->pnBytesFreed = &nByte; assert( db->lookaside.pEnd==db->lookaside.pTrueEnd ); db->lookaside.pEnd = db->lookaside.pStart; for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pVNext){ sqlite3VdbeDelete(pVdbe); } db->lookaside.pEnd = db->lookaside.pTrueEnd; db->pnBytesFreed = 0; *pHighwater = 0; /* IMP: R-64479-57858 */ *pCurrent = nByte; break; } /* ** Set *pCurrent to the total cache hits or misses encountered by all ** pagers the database handle is connected to. *pHighwater is always set ** to zero. */ case SQLITE_DBSTATUS_CACHE_SPILL: op = SQLITE_DBSTATUS_CACHE_WRITE+1; /* no break */ deliberate_fall_through case SQLITE_DBSTATUS_CACHE_HIT: case SQLITE_DBSTATUS_CACHE_MISS: case SQLITE_DBSTATUS_CACHE_WRITE:{ int i; u64 nRet = 0; assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); for(i=0; inDb; i++){ if( db->aDb[i].pBt ){ Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt); sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); } } *pHighwater = 0; /* IMP: R-42420-56072 */ /* IMP: R-54100-20147 */ /* IMP: R-29431-39229 */ *pCurrent = (int)nRet & 0x7fffffff; break; } /* Set *pCurrent to non-zero if there are unresolved deferred foreign ** key constraints. Set *pCurrent to zero if all foreign key constraints ** have been satisfied. The *pHighwater is always set to zero. */ case SQLITE_DBSTATUS_DEFERRED_FKS: { *pHighwater = 0; /* IMP: R-11967-56545 */ *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; break; } default: { rc = SQLITE_ERROR; } } sqlite3_mutex_leave(db->mutex); return rc; } /************** End of status.c **********************************************/ /************** Begin file date.c ********************************************/ /* ** 2003 October 31 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement date and time ** functions for SQLite. ** ** There is only one exported symbol in this file - the function ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** ** SQLite processes all times and dates as julian day numbers. The ** dates and times are stored as the number of days since noon ** in Greenwich on November 24, 4714 B.C. according to the Gregorian ** calendar system. ** ** 1970-01-01 00:00:00 is JD 2440587.5 ** 2000-01-01 00:00:00 is JD 2451544.5 ** ** This implementation requires years to be expressed as a 4-digit number ** which means that only dates between 0000-01-01 and 9999-12-31 can ** be represented, even though julian day numbers allow a much wider ** range of dates. ** ** The Gregorian calendar system is used for all dates and times, ** even those that predate the Gregorian calendar. Historians usually ** use the julian calendar for dates prior to 1582-10-15 and for some ** dates afterwards, depending on locale. Beware of this difference. ** ** The conversion algorithms are implemented based on descriptions ** in the following text: ** ** Jean Meeus ** Astronomical Algorithms, 2nd Edition, 1998 ** ISBN 0-943396-61-1 ** Willmann-Bell, Inc ** Richmond, Virginia (USA) */ /* #include "sqliteInt.h" */ /* #include */ /* #include */ #include #ifndef SQLITE_OMIT_DATETIME_FUNCS /* ** The MSVC CRT on Windows CE may not have a localtime() function. ** So declare a substitute. The substitute function itself is ** defined in "os_win.c". */ #if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \ (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API) struct tm *__cdecl localtime(const time_t *); #endif /* ** A structure for holding a single date and time. */ typedef struct DateTime DateTime; struct DateTime { sqlite3_int64 iJD; /* The julian day number times 86400000 */ int Y, M, D; /* Year, month, and day */ int h, m; /* Hour and minutes */ int tz; /* Timezone offset in minutes */ double s; /* Seconds */ char validJD; /* True (1) if iJD is valid */ char rawS; /* Raw numeric value stored in s */ char validYMD; /* True (1) if Y,M,D are valid */ char validHMS; /* True (1) if h,m,s are valid */ char validTZ; /* True (1) if tz is valid */ char tzSet; /* Timezone was set explicitly */ char isError; /* An overflow has occurred */ char useSubsec; /* Display subsecond precision */ }; /* ** Convert zDate into one or more integers according to the conversion ** specifier zFormat. ** ** zFormat[] contains 4 characters for each integer converted, except for ** the last integer which is specified by three characters. The meaning ** of a four-character format specifiers ABCD is: ** ** A: number of digits to convert. Always "2" or "4". ** B: minimum value. Always "0" or "1". ** C: maximum value, decoded as: ** a: 12 ** b: 14 ** c: 24 ** d: 31 ** e: 59 ** f: 9999 ** D: the separator character, or \000 to indicate this is the ** last number to convert. ** ** Example: To translate an ISO-8601 date YYYY-MM-DD, the format would ** be "40f-21a-20c". The "40f-" indicates the 4-digit year followed by "-". ** The "21a-" indicates the 2-digit month followed by "-". The "20c" indicates ** the 2-digit day which is the last integer in the set. ** ** The function returns the number of successful conversions. */ static int getDigits(const char *zDate, const char *zFormat, ...){ /* The aMx[] array translates the 3rd character of each format ** spec into a max size: a b c d e f */ static const u16 aMx[] = { 12, 14, 24, 31, 59, 14712 }; va_list ap; int cnt = 0; char nextC; va_start(ap, zFormat); do{ char N = zFormat[0] - '0'; char min = zFormat[1] - '0'; int val = 0; u16 max; assert( zFormat[2]>='a' && zFormat[2]<='f' ); max = aMx[zFormat[2] - 'a']; nextC = zFormat[3]; val = 0; while( N-- ){ if( !sqlite3Isdigit(*zDate) ){ goto end_getDigits; } val = val*10 + *zDate - '0'; zDate++; } if( val<(int)min || val>(int)max || (nextC!=0 && nextC!=*zDate) ){ goto end_getDigits; } *va_arg(ap,int*) = val; zDate++; cnt++; zFormat += 4; }while( nextC ); end_getDigits: va_end(ap); return cnt; } /* ** Parse a timezone extension on the end of a date-time. ** The extension is of the form: ** ** (+/-)HH:MM ** ** Or the "zulu" notation: ** ** Z ** ** If the parse is successful, write the number of minutes ** of change in p->tz and return 0. If a parser error occurs, ** return non-zero. ** ** A missing specifier is not considered an error. */ static int parseTimezone(const char *zDate, DateTime *p){ int sgn = 0; int nHr, nMn; int c; while( sqlite3Isspace(*zDate) ){ zDate++; } p->tz = 0; c = *zDate; if( c=='-' ){ sgn = -1; }else if( c=='+' ){ sgn = +1; }else if( c=='Z' || c=='z' ){ zDate++; goto zulu_time; }else{ return c!=0; } zDate++; if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){ return 1; } zDate += 5; p->tz = sgn*(nMn + nHr*60); zulu_time: while( sqlite3Isspace(*zDate) ){ zDate++; } p->tzSet = 1; return *zDate!=0; } /* ** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF. ** The HH, MM, and SS must each be exactly 2 digits. The ** fractional seconds FFFF can be one or more digits. ** ** Return 1 if there is a parsing error and 0 on success. */ static int parseHhMmSs(const char *zDate, DateTime *p){ int h, m, s; double ms = 0.0; if( getDigits(zDate, "20c:20e", &h, &m)!=2 ){ return 1; } zDate += 5; if( *zDate==':' ){ zDate++; if( getDigits(zDate, "20e", &s)!=1 ){ return 1; } zDate += 2; if( *zDate=='.' && sqlite3Isdigit(zDate[1]) ){ double rScale = 1.0; zDate++; while( sqlite3Isdigit(*zDate) ){ ms = ms*10.0 + *zDate - '0'; rScale *= 10.0; zDate++; } ms /= rScale; } }else{ s = 0; } p->validJD = 0; p->rawS = 0; p->validHMS = 1; p->h = h; p->m = m; p->s = s + ms; if( parseTimezone(zDate, p) ) return 1; p->validTZ = (p->tz!=0)?1:0; return 0; } /* ** Put the DateTime object into its error state. */ static void datetimeError(DateTime *p){ memset(p, 0, sizeof(*p)); p->isError = 1; } /* ** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume ** that the YYYY-MM-DD is according to the Gregorian calendar. ** ** Reference: Meeus page 61 */ static void computeJD(DateTime *p){ int Y, M, D, A, B, X1, X2; if( p->validJD ) return; if( p->validYMD ){ Y = p->Y; M = p->M; D = p->D; }else{ Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */ M = 1; D = 1; } if( Y<-4713 || Y>9999 || p->rawS ){ datetimeError(p); return; } if( M<=2 ){ Y--; M += 12; } A = Y/100; B = 2 - A + (A/4); X1 = 36525*(Y+4716)/100; X2 = 306001*(M+1)/10000; p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000); p->validJD = 1; if( p->validHMS ){ p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5); if( p->validTZ ){ p->iJD -= p->tz*60000; p->validYMD = 0; p->validHMS = 0; p->validTZ = 0; } } } /* ** Parse dates of the form ** ** YYYY-MM-DD HH:MM:SS.FFF ** YYYY-MM-DD HH:MM:SS ** YYYY-MM-DD HH:MM ** YYYY-MM-DD ** ** Write the result into the DateTime structure and return 0 ** on success and 1 if the input string is not a well-formed ** date. */ static int parseYyyyMmDd(const char *zDate, DateTime *p){ int Y, M, D, neg; if( zDate[0]=='-' ){ zDate++; neg = 1; }else{ neg = 0; } if( getDigits(zDate, "40f-21a-21d", &Y, &M, &D)!=3 ){ return 1; } zDate += 10; while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; } if( parseHhMmSs(zDate, p)==0 ){ /* We got the time */ }else if( *zDate==0 ){ p->validHMS = 0; }else{ return 1; } p->validJD = 0; p->validYMD = 1; p->Y = neg ? -Y : Y; p->M = M; p->D = D; if( p->validTZ ){ computeJD(p); } return 0; } /* ** Set the time to the current time reported by the VFS. ** ** Return the number of errors. */ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ p->iJD = sqlite3StmtCurrentTime(context); if( p->iJD>0 ){ p->validJD = 1; return 0; }else{ return 1; } } /* ** Input "r" is a numeric quantity which might be a julian day number, ** or the number of seconds since 1970. If the value if r is within ** range of a julian day number, install it as such and set validJD. ** If the value is a valid unix timestamp, put it in p->s and set p->rawS. */ static void setRawDateNumber(DateTime *p, double r){ p->s = r; p->rawS = 1; if( r>=0.0 && r<5373484.5 ){ p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5); p->validJD = 1; } } /* ** Attempt to parse the given string into a julian day number. Return ** the number of errors. ** ** The following are acceptable forms for the input string: ** ** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM ** DDDD.DD ** now ** ** In the first form, the +/-HH:MM is always optional. The fractional ** seconds extension (the ".FFF") is optional. The seconds portion ** (":SS.FFF") is option. The year and date can be omitted as long ** as there is a time string. The time string can be omitted as long ** as there is a year and date. */ static int parseDateOrTime( sqlite3_context *context, const char *zDate, DateTime *p ){ double r; if( parseYyyyMmDd(zDate,p)==0 ){ return 0; }else if( parseHhMmSs(zDate, p)==0 ){ return 0; }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){ setRawDateNumber(p, r); return 0; }else if( (sqlite3StrICmp(zDate,"subsec")==0 || sqlite3StrICmp(zDate,"subsecond")==0) && sqlite3NotPureFunc(context) ){ p->useSubsec = 1; return setDateTimeToCurrent(context, p); } return 1; } /* The julian day number for 9999-12-31 23:59:59.999 is 5373484.4999999. ** Multiplying this by 86400000 gives 464269060799999 as the maximum value ** for DateTime.iJD. ** ** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with ** such a large integer literal, so we have to encode it. */ #define INT_464269060799999 ((((i64)0x1a640)<<32)|0x1072fdff) /* ** Return TRUE if the given julian day number is within range. ** ** The input is the JulianDay times 86400000. */ static int validJulianDay(sqlite3_int64 iJD){ return iJD>=0 && iJD<=INT_464269060799999; } /* ** Compute the Year, Month, and Day from the julian day number. */ static void computeYMD(DateTime *p){ int Z, A, B, C, D, E, X1; if( p->validYMD ) return; if( !p->validJD ){ p->Y = 2000; p->M = 1; p->D = 1; }else if( !validJulianDay(p->iJD) ){ datetimeError(p); return; }else{ Z = (int)((p->iJD + 43200000)/86400000); A = (int)((Z - 1867216.25)/36524.25); A = Z + 1 + A - (A/4); B = A + 1524; C = (int)((B - 122.1)/365.25); D = (36525*(C&32767))/100; E = (int)((B-D)/30.6001); X1 = (int)(30.6001*E); p->D = B - D - X1; p->M = E<14 ? E-1 : E-13; p->Y = p->M>2 ? C - 4716 : C - 4715; } p->validYMD = 1; } /* ** Compute the Hour, Minute, and Seconds from the julian day number. */ static void computeHMS(DateTime *p){ int day_ms, day_min; /* milliseconds, minutes into the day */ if( p->validHMS ) return; computeJD(p); day_ms = (int)((p->iJD + 43200000) % 86400000); p->s = (day_ms % 60000)/1000.0; day_min = day_ms/60000; p->m = day_min % 60; p->h = day_min / 60; p->rawS = 0; p->validHMS = 1; } /* ** Compute both YMD and HMS */ static void computeYMD_HMS(DateTime *p){ computeYMD(p); computeHMS(p); } /* ** Clear the YMD and HMS and the TZ */ static void clearYMD_HMS_TZ(DateTime *p){ p->validYMD = 0; p->validHMS = 0; p->validTZ = 0; } #ifndef SQLITE_OMIT_LOCALTIME /* ** On recent Windows platforms, the localtime_s() function is available ** as part of the "Secure CRT". It is essentially equivalent to ** localtime_r() available under most POSIX platforms, except that the ** order of the parameters is reversed. ** ** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx. ** ** If the user has not indicated to use localtime_r() or localtime_s() ** already, check for an MSVC build environment that provides ** localtime_s(). */ #if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \ && defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE) #undef HAVE_LOCALTIME_S #define HAVE_LOCALTIME_S 1 #endif /* ** The following routine implements the rough equivalent of localtime_r() ** using whatever operating-system specific localtime facility that ** is available. This routine returns 0 on success and ** non-zero on any kind of error. ** ** If the sqlite3GlobalConfig.bLocaltimeFault variable is non-zero then this ** routine will always fail. If bLocaltimeFault is nonzero and ** sqlite3GlobalConfig.xAltLocaltime is not NULL, then xAltLocaltime() is ** invoked in place of the OS-defined localtime() function. ** ** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C ** library function localtime_r() is used to assist in the calculation of ** local time. */ static int osLocaltime(time_t *t, struct tm *pTm){ int rc; #if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S struct tm *pX; #if SQLITE_THREADSAFE>0 sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif sqlite3_mutex_enter(mutex); pX = localtime(t); #ifndef SQLITE_UNTESTABLE if( sqlite3GlobalConfig.bLocaltimeFault ){ if( sqlite3GlobalConfig.xAltLocaltime!=0 && 0==sqlite3GlobalConfig.xAltLocaltime((const void*)t,(void*)pTm) ){ pX = pTm; }else{ pX = 0; } } #endif if( pX ) *pTm = *pX; #if SQLITE_THREADSAFE>0 sqlite3_mutex_leave(mutex); #endif rc = pX==0; #else #ifndef SQLITE_UNTESTABLE if( sqlite3GlobalConfig.bLocaltimeFault ){ if( sqlite3GlobalConfig.xAltLocaltime!=0 ){ return sqlite3GlobalConfig.xAltLocaltime((const void*)t,(void*)pTm); }else{ return 1; } } #endif #if HAVE_LOCALTIME_R rc = localtime_r(t, pTm)==0; #else rc = localtime_s(pTm, t); #endif /* HAVE_LOCALTIME_R */ #endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */ return rc; } #endif /* SQLITE_OMIT_LOCALTIME */ #ifndef SQLITE_OMIT_LOCALTIME /* ** Assuming the input DateTime is UTC, move it to its localtime equivalent. */ static int toLocaltime( DateTime *p, /* Date at which to calculate offset */ sqlite3_context *pCtx /* Write error here if one occurs */ ){ time_t t; struct tm sLocal; int iYearDiff; /* Initialize the contents of sLocal to avoid a compiler warning. */ memset(&sLocal, 0, sizeof(sLocal)); computeJD(p); if( p->iJD<2108667600*(i64)100000 /* 1970-01-01 */ || p->iJD>2130141456*(i64)100000 /* 2038-01-18 */ ){ /* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only ** works for years between 1970 and 2037. For dates outside this range, ** SQLite attempts to map the year into an equivalent year within this ** range, do the calculation, then map the year back. */ DateTime x = *p; computeYMD_HMS(&x); iYearDiff = (2000 + x.Y%4) - x.Y; x.Y += iYearDiff; x.validJD = 0; computeJD(&x); t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); }else{ iYearDiff = 0; t = (time_t)(p->iJD/1000 - 21086676*(i64)10000); } if( osLocaltime(&t, &sLocal) ){ sqlite3_result_error(pCtx, "local time unavailable", -1); return SQLITE_ERROR; } p->Y = sLocal.tm_year + 1900 - iYearDiff; p->M = sLocal.tm_mon + 1; p->D = sLocal.tm_mday; p->h = sLocal.tm_hour; p->m = sLocal.tm_min; p->s = sLocal.tm_sec + (p->iJD%1000)*0.001; p->validYMD = 1; p->validHMS = 1; p->validJD = 0; p->rawS = 0; p->validTZ = 0; p->isError = 0; return SQLITE_OK; } #endif /* SQLITE_OMIT_LOCALTIME */ /* ** The following table defines various date transformations of the form ** ** 'NNN days' ** ** Where NNN is an arbitrary floating-point number and "days" can be one ** of several units of time. */ static const struct { u8 nName; /* Length of the name */ char zName[7]; /* Name of the transformation */ float rLimit; /* Maximum NNN value for this transform */ float rXform; /* Constant used for this transform */ } aXformType[] = { { 6, "second", 4.6427e+14, 1.0 }, { 6, "minute", 7.7379e+12, 60.0 }, { 4, "hour", 1.2897e+11, 3600.0 }, { 3, "day", 5373485.0, 86400.0 }, { 5, "month", 176546.0, 2592000.0 }, { 4, "year", 14713.0, 31536000.0 }, }; /* ** If the DateTime p is raw number, try to figure out if it is ** a julian day number of a unix timestamp. Set the p value ** appropriately. */ static void autoAdjustDate(DateTime *p){ if( !p->rawS || p->validJD ){ p->rawS = 0; }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */ && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */ ){ double r = p->s*1000.0 + 210866760000000.0; clearYMD_HMS_TZ(p); p->iJD = (sqlite3_int64)(r + 0.5); p->validJD = 1; p->rawS = 0; } } /* ** Process a modifier to a date-time stamp. The modifiers are ** as follows: ** ** NNN days ** NNN hours ** NNN minutes ** NNN.NNNN seconds ** NNN months ** NNN years ** start of month ** start of year ** start of week ** start of day ** weekday N ** unixepoch ** localtime ** utc ** ** Return 0 on success and 1 if there is any kind of error. If the error ** is in a system call (i.e. localtime()), then an error message is written ** to context pCtx. If the error is an unrecognized modifier, no error is ** written to pCtx. */ static int parseModifier( sqlite3_context *pCtx, /* Function context */ const char *z, /* The text of the modifier */ int n, /* Length of zMod in bytes */ DateTime *p, /* The date/time value to be modified */ int idx /* Parameter index of the modifier */ ){ int rc = 1; double r; switch(sqlite3UpperToLower[(u8)z[0]] ){ case 'a': { /* ** auto ** ** If rawS is available, then interpret as a julian day number, or ** a unix timestamp, depending on its magnitude. */ if( sqlite3_stricmp(z, "auto")==0 ){ if( idx>1 ) return 1; /* IMP: R-33611-57934 */ autoAdjustDate(p); rc = 0; } break; } case 'j': { /* ** julianday ** ** Always interpret the prior number as a julian-day value. If this ** is not the first modifier, or if the prior argument is not a numeric ** value in the allowed range of julian day numbers understood by ** SQLite (0..5373484.5) then the result will be NULL. */ if( sqlite3_stricmp(z, "julianday")==0 ){ if( idx>1 ) return 1; /* IMP: R-31176-64601 */ if( p->validJD && p->rawS ){ rc = 0; p->rawS = 0; } } break; } #ifndef SQLITE_OMIT_LOCALTIME case 'l': { /* localtime ** ** Assuming the current time value is UTC (a.k.a. GMT), shift it to ** show local time. */ if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){ rc = toLocaltime(p, pCtx); } break; } #endif case 'u': { /* ** unixepoch ** ** Treat the current value of p->s as the number of ** seconds since 1970. Convert to a real julian day number. */ if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){ if( idx>1 ) return 1; /* IMP: R-49255-55373 */ r = p->s*1000.0 + 210866760000000.0; if( r>=0.0 && r<464269060800000.0 ){ clearYMD_HMS_TZ(p); p->iJD = (sqlite3_int64)(r + 0.5); p->validJD = 1; p->rawS = 0; rc = 0; } } #ifndef SQLITE_OMIT_LOCALTIME else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ if( p->tzSet==0 ){ i64 iOrigJD; /* Original localtime */ i64 iGuess; /* Guess at the corresponding utc time */ int cnt = 0; /* Safety to prevent infinite loop */ i64 iErr; /* Guess is off by this much */ computeJD(p); iGuess = iOrigJD = p->iJD; iErr = 0; do{ DateTime new; memset(&new, 0, sizeof(new)); iGuess -= iErr; new.iJD = iGuess; new.validJD = 1; rc = toLocaltime(&new, pCtx); if( rc ) return rc; computeJD(&new); iErr = new.iJD - iOrigJD; }while( iErr && cnt++<3 ); memset(p, 0, sizeof(*p)); p->iJD = iGuess; p->validJD = 1; p->tzSet = 1; } rc = SQLITE_OK; } #endif break; } case 'w': { /* ** weekday N ** ** Move the date to the same time on the next occurrence of ** weekday N where 0==Sunday, 1==Monday, and so forth. If the ** date is already on the appropriate weekday, this is a no-op. */ if( sqlite3_strnicmp(z, "weekday ", 8)==0 && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0 && r>=0.0 && r<7.0 && (n=(int)r)==r ){ sqlite3_int64 Z; computeYMD_HMS(p); p->validTZ = 0; p->validJD = 0; computeJD(p); Z = ((p->iJD + 129600000)/86400000) % 7; if( Z>n ) Z -= 7; p->iJD += (n - Z)*86400000; clearYMD_HMS_TZ(p); rc = 0; } break; } case 's': { /* ** start of TTTTT ** ** Move the date backwards to the beginning of the current day, ** or month or year. ** ** subsecond ** subsec ** ** Show subsecond precision in the output of datetime() and ** unixepoch() and strftime('%s'). */ if( sqlite3_strnicmp(z, "start of ", 9)!=0 ){ if( sqlite3_stricmp(z, "subsec")==0 || sqlite3_stricmp(z, "subsecond")==0 ){ p->useSubsec = 1; rc = 0; } break; } if( !p->validJD && !p->validYMD && !p->validHMS ) break; z += 9; computeYMD(p); p->validHMS = 1; p->h = p->m = 0; p->s = 0.0; p->rawS = 0; p->validTZ = 0; p->validJD = 0; if( sqlite3_stricmp(z,"month")==0 ){ p->D = 1; rc = 0; }else if( sqlite3_stricmp(z,"year")==0 ){ p->M = 1; p->D = 1; rc = 0; }else if( sqlite3_stricmp(z,"day")==0 ){ rc = 0; } break; } case '+': case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { double rRounder; int i; int Y,M,D,h,m,x; const char *z2 = z; char z0 = z[0]; for(n=1; z[n]; n++){ if( z[n]==':' ) break; if( sqlite3Isspace(z[n]) ) break; if( z[n]=='-' ){ if( n==5 && getDigits(&z[1], "40f", &Y)==1 ) break; if( n==6 && getDigits(&z[1], "50f", &Y)==1 ) break; } } if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){ assert( rc==1 ); break; } if( z[n]=='-' ){ /* A modifier of the form (+|-)YYYY-MM-DD adds or subtracts the ** specified number of years, months, and days. MM is limited to ** the range 0-11 and DD is limited to 0-30. */ if( z0!='+' && z0!='-' ) break; /* Must start with +/- */ if( n==5 ){ if( getDigits(&z[1], "40f-20a-20d", &Y, &M, &D)!=3 ) break; }else{ assert( n==6 ); if( getDigits(&z[1], "50f-20a-20d", &Y, &M, &D)!=3 ) break; z++; } if( M>=12 ) break; /* M range 0..11 */ if( D>=31 ) break; /* D range 0..30 */ computeYMD_HMS(p); p->validJD = 0; if( z0=='-' ){ p->Y -= Y; p->M -= M; D = -D; }else{ p->Y += Y; p->M += M; } x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; p->Y += x; p->M -= x*12; computeJD(p); p->validHMS = 0; p->validYMD = 0; p->iJD += (i64)D*86400000; if( z[11]==0 ){ rc = 0; break; } if( sqlite3Isspace(z[11]) && getDigits(&z[12], "20c:20e", &h, &m)==2 ){ z2 = &z[12]; n = 2; }else{ break; } } if( z2[n]==':' ){ /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the ** specified number of hours, minutes, seconds, and fractional seconds ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be ** omitted. */ DateTime tx; sqlite3_int64 day; if( !sqlite3Isdigit(*z2) ) z2++; memset(&tx, 0, sizeof(tx)); if( parseHhMmSs(z2, &tx) ) break; computeJD(&tx); tx.iJD -= 43200000; day = tx.iJD/86400000; tx.iJD -= day*86400000; if( z0=='-' ) tx.iJD = -tx.iJD; computeJD(p); clearYMD_HMS_TZ(p); p->iJD += tx.iJD; rc = 0; break; } /* If control reaches this point, it means the transformation is ** one of the forms like "+NNN days". */ z += n; while( sqlite3Isspace(*z) ) z++; n = sqlite3Strlen30(z); if( n>10 || n<3 ) break; if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--; computeJD(p); assert( rc==1 ); rRounder = r<0 ? -0.5 : +0.5; for(i=0; i-aXformType[i].rLimit && rM += (int)r; x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; p->Y += x; p->M -= x*12; p->validJD = 0; r -= (int)r; break; } case 5: { /* Special processing to add years */ int y = (int)r; assert( strcmp(aXformType[i].zName,"year")==0 ); computeYMD_HMS(p); p->Y += y; p->validJD = 0; r -= (int)r; break; } } computeJD(p); p->iJD += (sqlite3_int64)(r*1000.0*aXformType[i].rXform + rRounder); rc = 0; break; } } clearYMD_HMS_TZ(p); break; } default: { break; } } return rc; } /* ** Process time function arguments. argv[0] is a date-time stamp. ** argv[1] and following are modifiers. Parse them all and write ** the resulting time into the DateTime structure p. Return 0 ** on success and 1 if there are any errors. ** ** If there are zero parameters (if even argv[0] is undefined) ** then assume a default value of "now" for argv[0]. */ static int isDate( sqlite3_context *context, int argc, sqlite3_value **argv, DateTime *p ){ int i, n; const unsigned char *z; int eType; memset(p, 0, sizeof(*p)); if( argc==0 ){ if( !sqlite3NotPureFunc(context) ) return 1; return setDateTimeToCurrent(context, p); } if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT || eType==SQLITE_INTEGER ){ setRawDateNumber(p, sqlite3_value_double(argv[0])); }else{ z = sqlite3_value_text(argv[0]); if( !z || parseDateOrTime(context, (char*)z, p) ){ return 1; } } for(i=1; iisError || !validJulianDay(p->iJD) ) return 1; if( argc==1 && p->validYMD && p->D>28 ){ /* Make sure a YYYY-MM-DD is normalized. ** Example: 2023-02-31 -> 2023-03-03 */ assert( p->validJD ); p->validYMD = 0; } return 0; } /* ** The following routines implement the various date and time functions ** of SQLite. */ /* ** julianday( TIMESTRING, MOD, MOD, ...) ** ** Return the julian day number of the date specified in the arguments */ static void juliandayFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ computeJD(&x); sqlite3_result_double(context, x.iJD/86400000.0); } } /* ** unixepoch( TIMESTRING, MOD, MOD, ...) ** ** Return the number of seconds (including fractional seconds) since ** the unix epoch of 1970-01-01 00:00:00 GMT. */ static void unixepochFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ computeJD(&x); if( x.useSubsec ){ sqlite3_result_double(context, (x.iJD - 21086676*(i64)10000000)/1000.0); }else{ sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000); } } } /* ** datetime( TIMESTRING, MOD, MOD, ...) ** ** Return YYYY-MM-DD HH:MM:SS */ static void datetimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ int Y, s, n; char zBuf[32]; computeYMD_HMS(&x); Y = x.Y; if( Y<0 ) Y = -Y; zBuf[1] = '0' + (Y/1000)%10; zBuf[2] = '0' + (Y/100)%10; zBuf[3] = '0' + (Y/10)%10; zBuf[4] = '0' + (Y)%10; zBuf[5] = '-'; zBuf[6] = '0' + (x.M/10)%10; zBuf[7] = '0' + (x.M)%10; zBuf[8] = '-'; zBuf[9] = '0' + (x.D/10)%10; zBuf[10] = '0' + (x.D)%10; zBuf[11] = ' '; zBuf[12] = '0' + (x.h/10)%10; zBuf[13] = '0' + (x.h)%10; zBuf[14] = ':'; zBuf[15] = '0' + (x.m/10)%10; zBuf[16] = '0' + (x.m)%10; zBuf[17] = ':'; if( x.useSubsec ){ s = (int)(1000.0*x.s + 0.5); zBuf[18] = '0' + (s/10000)%10; zBuf[19] = '0' + (s/1000)%10; zBuf[20] = '.'; zBuf[21] = '0' + (s/100)%10; zBuf[22] = '0' + (s/10)%10; zBuf[23] = '0' + (s)%10; zBuf[24] = 0; n = 24; }else{ s = (int)x.s; zBuf[18] = '0' + (s/10)%10; zBuf[19] = '0' + (s)%10; zBuf[20] = 0; n = 20; } if( x.Y<0 ){ zBuf[0] = '-'; sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT); }else{ sqlite3_result_text(context, &zBuf[1], n-1, SQLITE_TRANSIENT); } } } /* ** time( TIMESTRING, MOD, MOD, ...) ** ** Return HH:MM:SS */ static void timeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ int s, n; char zBuf[16]; computeHMS(&x); zBuf[0] = '0' + (x.h/10)%10; zBuf[1] = '0' + (x.h)%10; zBuf[2] = ':'; zBuf[3] = '0' + (x.m/10)%10; zBuf[4] = '0' + (x.m)%10; zBuf[5] = ':'; if( x.useSubsec ){ s = (int)(1000.0*x.s + 0.5); zBuf[6] = '0' + (s/10000)%10; zBuf[7] = '0' + (s/1000)%10; zBuf[8] = '.'; zBuf[9] = '0' + (s/100)%10; zBuf[10] = '0' + (s/10)%10; zBuf[11] = '0' + (s)%10; zBuf[12] = 0; n = 12; }else{ s = (int)x.s; zBuf[6] = '0' + (s/10)%10; zBuf[7] = '0' + (s)%10; zBuf[8] = 0; n = 8; } sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT); } } /* ** date( TIMESTRING, MOD, MOD, ...) ** ** Return YYYY-MM-DD */ static void dateFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ int Y; char zBuf[16]; computeYMD(&x); Y = x.Y; if( Y<0 ) Y = -Y; zBuf[1] = '0' + (Y/1000)%10; zBuf[2] = '0' + (Y/100)%10; zBuf[3] = '0' + (Y/10)%10; zBuf[4] = '0' + (Y)%10; zBuf[5] = '-'; zBuf[6] = '0' + (x.M/10)%10; zBuf[7] = '0' + (x.M)%10; zBuf[8] = '-'; zBuf[9] = '0' + (x.D/10)%10; zBuf[10] = '0' + (x.D)%10; zBuf[11] = 0; if( x.Y<0 ){ zBuf[0] = '-'; sqlite3_result_text(context, zBuf, 11, SQLITE_TRANSIENT); }else{ sqlite3_result_text(context, &zBuf[1], 10, SQLITE_TRANSIENT); } } } /* ** strftime( FORMAT, TIMESTRING, MOD, MOD, ...) ** ** Return a string described by FORMAT. Conversions as follows: ** ** %d day of month ** %f ** fractional seconds SS.SSS ** %H hour 00-24 ** %j day of year 000-366 ** %J ** julian day number ** %m month 01-12 ** %M minute 00-59 ** %s seconds since 1970-01-01 ** %S seconds 00-59 ** %w day of week 0-6 Sunday==0 ** %W week of year 00-53 ** %Y year 0000-9999 ** %% % */ static void strftimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; size_t i,j; sqlite3 *db; const char *zFmt; sqlite3_str sRes; if( argc==0 ) return; zFmt = (const char*)sqlite3_value_text(argv[0]); if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; db = sqlite3_context_db_handle(context); sqlite3StrAccumInit(&sRes, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); computeJD(&x); computeYMD_HMS(&x); for(i=j=0; zFmt[i]; i++){ char cf; if( zFmt[i]!='%' ) continue; if( j59.999 ) s = 59.999; sqlite3_str_appendf(&sRes, "%06.3f", s); break; } case 'F': { sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D); break; } case 'H': case 'k': { sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h); break; } case 'I': /* Fall thru */ case 'l': { int h = x.h; if( h>12 ) h -= 12; if( h==0 ) h = 12; sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h); break; } case 'W': /* Fall thru */ case 'j': { int nDay; /* Number of days since 1st day of year */ DateTime y = x; y.validJD = 0; y.M = 1; y.D = 1; computeJD(&y); nDay = (int)((x.iJD-y.iJD+43200000)/86400000); if( cf=='W' ){ int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ wd = (int)(((x.iJD+43200000)/86400000)%7); sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7); }else{ sqlite3_str_appendf(&sRes,"%03d",nDay+1); } break; } case 'J': { sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0); break; } case 'm': { sqlite3_str_appendf(&sRes,"%02d",x.M); break; } case 'M': { sqlite3_str_appendf(&sRes,"%02d",x.m); break; } case 'p': /* Fall thru */ case 'P': { if( x.h>=12 ){ sqlite3_str_append(&sRes, cf=='p' ? "PM" : "pm", 2); }else{ sqlite3_str_append(&sRes, cf=='p' ? "AM" : "am", 2); } break; } case 'R': { sqlite3_str_appendf(&sRes, "%02d:%02d", x.h, x.m); break; } case 's': { if( x.useSubsec ){ sqlite3_str_appendf(&sRes,"%.3f", (x.iJD - 21086676*(i64)10000000)/1000.0); }else{ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); sqlite3_str_appendf(&sRes,"%lld",iS); } break; } case 'S': { sqlite3_str_appendf(&sRes,"%02d",(int)x.s); break; } case 'T': { sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s); break; } case 'u': /* Fall thru */ case 'w': { char c = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; if( c=='0' && cf=='u' ) c = '7'; sqlite3_str_appendchar(&sRes, 1, c); break; } case 'Y': { sqlite3_str_appendf(&sRes,"%04d",x.Y); break; } case '%': { sqlite3_str_appendchar(&sRes, 1, '%'); break; } default: { sqlite3_str_reset(&sRes); return; } } } if( j=d2.iJD ){ sign = '+'; Y = d1.Y - d2.Y; if( Y ){ d2.Y = d1.Y; d2.validJD = 0; computeJD(&d2); } M = d1.M - d2.M; if( M<0 ){ Y--; M += 12; } if( M!=0 ){ d2.M = d1.M; d2.validJD = 0; computeJD(&d2); } while( d1.iJDd2.iJD ){ M--; if( M<0 ){ M = 11; Y--; } d2.M++; if( d2.M>12 ){ d2.M = 1; d2.Y++; } d2.validJD = 0; computeJD(&d2); } d1.iJD = d2.iJD - d1.iJD; d1.iJD += (u64)1486995408 * (u64)100000; } d1.validYMD = 0; d1.validHMS = 0; d1.validTZ = 0; computeYMD_HMS(&d1); sqlite3StrAccumInit(&sRes, 0, 0, 0, 100); sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f", sign, Y, M, d1.D-1, d1.h, d1.m, d1.s); sqlite3ResultStrAccum(context, &sRes); } /* ** current_timestamp() ** ** This function returns the same value as datetime('now'). */ static void ctimestampFunc( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ UNUSED_PARAMETER2(NotUsed, NotUsed2); datetimeFunc(context, 0, 0); } #endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */ #ifdef SQLITE_OMIT_DATETIME_FUNCS /* ** If the library is compiled to omit the full-scale date and time ** handling (to get a smaller binary), the following minimal version ** of the functions current_time(), current_date() and current_timestamp() ** are included instead. This is to support column declarations that ** include "DEFAULT CURRENT_TIME" etc. ** ** This function uses the C-library functions time(), gmtime() ** and strftime(). The format string to pass to strftime() is supplied ** as the user-data for the function. */ static void currentTimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ time_t t; char *zFormat = (char *)sqlite3_user_data(context); sqlite3_int64 iT; struct tm *pTm; struct tm sNow; char zBuf[20]; UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); iT = sqlite3StmtCurrentTime(context); if( iT<=0 ) return; t = iT/1000 - 10000*(sqlite3_int64)21086676; #if HAVE_GMTIME_R pTm = gmtime_r(&t, &sNow); #else sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)); pTm = gmtime(&t); if( pTm ) memcpy(&sNow, pTm, sizeof(sNow)); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)); #endif if( pTm ){ strftime(zBuf, 20, zFormat, &sNow); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } #endif /* ** This function registered all of the above C functions as SQL ** functions. This should be the only routine in this file with ** external linkage. */ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){ static FuncDef aDateTimeFuncs[] = { #ifndef SQLITE_OMIT_DATETIME_FUNCS PURE_DATE(julianday, -1, 0, 0, juliandayFunc ), PURE_DATE(unixepoch, -1, 0, 0, unixepochFunc ), PURE_DATE(date, -1, 0, 0, dateFunc ), PURE_DATE(time, -1, 0, 0, timeFunc ), PURE_DATE(datetime, -1, 0, 0, datetimeFunc ), PURE_DATE(strftime, -1, 0, 0, strftimeFunc ), PURE_DATE(timediff, 2, 0, 0, timediffFunc ), DFUNCTION(current_time, 0, 0, 0, ctimeFunc ), DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), DFUNCTION(current_date, 0, 0, 0, cdateFunc ), #else STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc), STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc), STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc), #endif }; sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs)); } /************** End of date.c ************************************************/ /************** Begin file os.c **********************************************/ /* ** 2005 November 29 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains OS interface code that is common to all ** architectures. */ /* #include "sqliteInt.h" */ /* ** If we compile with the SQLITE_TEST macro set, then the following block ** of code will give us the ability to simulate a disk I/O error. This ** is used for testing the I/O recovery logic. */ #if defined(SQLITE_TEST) SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */ SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */ SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */ SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */ SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */ SQLITE_API int sqlite3_diskfull_pending = 0; SQLITE_API int sqlite3_diskfull = 0; #endif /* defined(SQLITE_TEST) */ /* ** When testing, also keep a count of the number of open files. */ #if defined(SQLITE_TEST) SQLITE_API int sqlite3_open_file_count = 0; #endif /* defined(SQLITE_TEST) */ /* ** The default SQLite sqlite3_vfs implementations do not allocate ** memory (actually, os_unix.c allocates a small amount of memory ** from within OsOpen()), but some third-party implementations may. ** So we test the effects of a malloc() failing and the sqlite3OsXXX() ** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro. ** ** The following functions are instrumented for malloc() failure ** testing: ** ** sqlite3OsRead() ** sqlite3OsWrite() ** sqlite3OsSync() ** sqlite3OsFileSize() ** sqlite3OsLock() ** sqlite3OsCheckReservedLock() ** sqlite3OsFileControl() ** sqlite3OsShmMap() ** sqlite3OsOpen() ** sqlite3OsDelete() ** sqlite3OsAccess() ** sqlite3OsFullPathname() ** */ #if defined(SQLITE_TEST) SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1; #define DO_OS_MALLOC_TEST(x) \ if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3JournalIsInMemory(x))) { \ void *pTstAlloc = sqlite3Malloc(10); \ if (!pTstAlloc) return SQLITE_IOERR_NOMEM_BKPT; \ sqlite3_free(pTstAlloc); \ } #else #define DO_OS_MALLOC_TEST(x) #endif /* ** The following routines are convenience wrappers around methods ** of the sqlite3_file object. This is mostly just syntactic sugar. All ** of this would be completely automatic if SQLite were coded using ** C++ instead of plain old C. */ SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file *pId){ if( pId->pMethods ){ pId->pMethods->xClose(pId); pId->pMethods = 0; } } SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){ DO_OS_MALLOC_TEST(id); return id->pMethods->xRead(id, pBuf, amt, offset); } SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){ DO_OS_MALLOC_TEST(id); return id->pMethods->xWrite(id, pBuf, amt, offset); } SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){ return id->pMethods->xTruncate(id, size); } SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){ DO_OS_MALLOC_TEST(id); return flags ? id->pMethods->xSync(id, flags) : SQLITE_OK; } SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ DO_OS_MALLOC_TEST(id); return id->pMethods->xFileSize(id, pSize); } SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){ DO_OS_MALLOC_TEST(id); assert( lockType>=SQLITE_LOCK_SHARED && lockType<=SQLITE_LOCK_EXCLUSIVE ); return id->pMethods->xLock(id, lockType); } SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){ assert( lockType==SQLITE_LOCK_NONE || lockType==SQLITE_LOCK_SHARED ); return id->pMethods->xUnlock(id, lockType); } SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){ DO_OS_MALLOC_TEST(id); return id->pMethods->xCheckReservedLock(id, pResOut); } /* ** Use sqlite3OsFileControl() when we are doing something that might fail ** and we need to know about the failures. Use sqlite3OsFileControlHint() ** when simply tossing information over the wall to the VFS and we do not ** really care if the VFS receives and understands the information since it ** is only a hint and can be safely ignored. The sqlite3OsFileControlHint() ** routine has no return value since the return value would be meaningless. */ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ if( id->pMethods==0 ) return SQLITE_NOTFOUND; #ifdef SQLITE_TEST if( op!=SQLITE_FCNTL_COMMIT_PHASETWO && op!=SQLITE_FCNTL_LOCK_TIMEOUT && op!=SQLITE_FCNTL_CKPT_DONE && op!=SQLITE_FCNTL_CKPT_START ){ /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite ** is using a regular VFS, it is called after the corresponding ** transaction has been committed. Injecting a fault at this point ** confuses the test scripts - the COMMIT command returns SQLITE_NOMEM ** but the transaction is committed anyway. ** ** The core must call OsFileControl() though, not OsFileControlHint(), ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably ** means the commit really has failed and an error should be returned ** to the user. ** ** The CKPT_DONE and CKPT_START file-controls are write-only signals ** to the cksumvfs. Their return code is meaningless and is ignored ** by the SQLite core, so there is no point in simulating OOMs for them. */ DO_OS_MALLOC_TEST(id); } #endif return id->pMethods->xFileControl(id, op, pArg); } SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){ if( id->pMethods ) (void)id->pMethods->xFileControl(id, op, pArg); } SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){ int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); } SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ if( NEVER(id->pMethods==0) ) return 0; return id->pMethods->xDeviceCharacteristics(id); } #ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){ return id->pMethods->xShmLock(id, offset, n, flags); } SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){ id->pMethods->xShmBarrier(id); } SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int deleteFlag){ return id->pMethods->xShmUnmap(id, deleteFlag); } SQLITE_PRIVATE int sqlite3OsShmMap( sqlite3_file *id, /* Database file handle */ int iPage, int pgsz, int bExtend, /* True to extend file if necessary */ void volatile **pp /* OUT: Pointer to mapping */ ){ DO_OS_MALLOC_TEST(id); return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); } #endif /* SQLITE_OMIT_WAL */ #if SQLITE_MAX_MMAP_SIZE>0 /* The real implementation of xFetch and xUnfetch */ SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ DO_OS_MALLOC_TEST(id); return id->pMethods->xFetch(id, iOff, iAmt, pp); } SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ return id->pMethods->xUnfetch(id, iOff, p); } #else /* No-op stubs to use when memory-mapped I/O is disabled */ SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ *pp = 0; return SQLITE_OK; } SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ return SQLITE_OK; } #endif /* ** The next group of routines are convenience wrappers around the ** VFS methods. */ SQLITE_PRIVATE int sqlite3OsOpen( sqlite3_vfs *pVfs, const char *zPath, sqlite3_file *pFile, int flags, int *pFlagsOut ){ int rc; DO_OS_MALLOC_TEST(0); /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example, ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before ** reaching the VFS. */ assert( zPath || (flags & SQLITE_OPEN_EXCLUSIVE) ); rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut); assert( rc==SQLITE_OK || pFile->pMethods==0 ); return rc; } SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ DO_OS_MALLOC_TEST(0); assert( dirSync==0 || dirSync==1 ); return pVfs->xDelete!=0 ? pVfs->xDelete(pVfs, zPath, dirSync) : SQLITE_OK; } SQLITE_PRIVATE int sqlite3OsAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ DO_OS_MALLOC_TEST(0); return pVfs->xAccess(pVfs, zPath, flags, pResOut); } SQLITE_PRIVATE int sqlite3OsFullPathname( sqlite3_vfs *pVfs, const char *zPath, int nPathOut, char *zPathOut ){ DO_OS_MALLOC_TEST(0); zPathOut[0] = 0; return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut); } #ifndef SQLITE_OMIT_LOAD_EXTENSION SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ assert( zPath!=0 ); assert( strlen(zPath)<=SQLITE_MAX_PATHLEN ); /* tag-20210611-1 */ return pVfs->xDlOpen(pVfs, zPath); } SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ pVfs->xDlError(pVfs, nByte, zBufOut); } SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){ return pVfs->xDlSym(pVfs, pHdle, zSym); } SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){ pVfs->xDlClose(pVfs, pHandle); } #endif /* SQLITE_OMIT_LOAD_EXTENSION */ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ if( sqlite3Config.iPrngSeed ){ memset(zBufOut, 0, nByte); if( ALWAYS(nByte>(signed)sizeof(unsigned)) ) nByte = sizeof(unsigned int); memcpy(zBufOut, &sqlite3Config.iPrngSeed, nByte); return SQLITE_OK; }else{ return pVfs->xRandomness(pVfs, nByte, zBufOut); } } SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){ return pVfs->xSleep(pVfs, nMicro); } SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs *pVfs){ return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0; } SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){ int rc; /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64() ** method to get the current date and time if that method is available ** (if iVersion is 2 or greater and the function pointer is not NULL) and ** will fall back to xCurrentTime() if xCurrentTimeInt64() is ** unavailable. */ if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){ rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut); }else{ double r; rc = pVfs->xCurrentTime(pVfs, &r); *pTimeOut = (sqlite3_int64)(r*86400000.0); } return rc; } SQLITE_PRIVATE int sqlite3OsOpenMalloc( sqlite3_vfs *pVfs, const char *zFile, sqlite3_file **ppFile, int flags, int *pOutFlags ){ int rc; sqlite3_file *pFile; pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile); if( pFile ){ rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); if( rc!=SQLITE_OK ){ sqlite3_free(pFile); *ppFile = 0; }else{ *ppFile = pFile; } }else{ *ppFile = 0; rc = SQLITE_NOMEM_BKPT; } assert( *ppFile!=0 || rc!=SQLITE_OK ); return rc; } SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){ assert( pFile ); sqlite3OsClose(pFile); sqlite3_free(pFile); } /* ** This function is a wrapper around the OS specific implementation of ** sqlite3_os_init(). The purpose of the wrapper is to provide the ** ability to simulate a malloc failure, so that the handling of an ** error in sqlite3_os_init() by the upper layers can be tested. */ SQLITE_PRIVATE int sqlite3OsInit(void){ void *p = sqlite3_malloc(10); if( p==0 ) return SQLITE_NOMEM_BKPT; sqlite3_free(p); return sqlite3_os_init(); } /* ** The list of all registered VFS implementations. */ static sqlite3_vfs * SQLITE_WSD vfsList = 0; #define vfsList GLOBAL(sqlite3_vfs *, vfsList) /* ** Locate a VFS by name. If no name is given, simply return the ** first VFS on the list. */ SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){ sqlite3_vfs *pVfs = 0; #if SQLITE_THREADSAFE sqlite3_mutex *mutex; #endif #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return 0; #endif #if SQLITE_THREADSAFE mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif sqlite3_mutex_enter(mutex); for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){ if( zVfs==0 ) break; if( strcmp(zVfs, pVfs->zName)==0 ) break; } sqlite3_mutex_leave(mutex); return pVfs; } /* ** Unlink a VFS from the linked list */ static void vfsUnlink(sqlite3_vfs *pVfs){ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) ); if( pVfs==0 ){ /* No-op */ }else if( vfsList==pVfs ){ vfsList = pVfs->pNext; }else if( vfsList ){ sqlite3_vfs *p = vfsList; while( p->pNext && p->pNext!=pVfs ){ p = p->pNext; } if( p->pNext==pVfs ){ p->pNext = pVfs->pNext; } } } /* ** Register a VFS with the system. It is harmless to register the same ** VFS multiple times. The new VFS becomes the default if makeDflt is ** true. */ SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ MUTEX_LOGIC(sqlite3_mutex *mutex;) #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return rc; #endif #ifdef SQLITE_ENABLE_API_ARMOR if( pVfs==0 ) return SQLITE_MISUSE_BKPT; #endif MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); if( makeDflt || vfsList==0 ){ pVfs->pNext = vfsList; vfsList = pVfs; }else{ pVfs->pNext = vfsList->pNext; vfsList->pNext = pVfs; } assert(vfsList); sqlite3_mutex_leave(mutex); return SQLITE_OK; } /* ** Unregister a VFS so that it is no longer accessible. */ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ MUTEX_LOGIC(sqlite3_mutex *mutex;) #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return rc; #endif MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); sqlite3_mutex_leave(mutex); return SQLITE_OK; } /************** End of os.c **************************************************/ /************** Begin file fault.c *******************************************/ /* ** 2008 Jan 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code to support the concept of "benign" ** malloc failures (when the xMalloc() or xRealloc() method of the ** sqlite3_mem_methods structure fails to allocate a block of memory ** and returns 0). ** ** Most malloc failures are non-benign. After they occur, SQLite ** abandons the current operation and returns an error code (usually ** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily ** fatal. For example, if a malloc fails while resizing a hash table, this ** is completely recoverable simply by not carrying out the resize. The ** hash table will continue to function normally. So a malloc failure ** during a hash table resize is a benign fault. */ /* #include "sqliteInt.h" */ #ifndef SQLITE_UNTESTABLE /* ** Global variables. */ typedef struct BenignMallocHooks BenignMallocHooks; static SQLITE_WSD struct BenignMallocHooks { void (*xBenignBegin)(void); void (*xBenignEnd)(void); } sqlite3Hooks = { 0, 0 }; /* The "wsdHooks" macro will resolve to the appropriate BenignMallocHooks ** structure. If writable static data is unsupported on the target, ** we have to locate the state vector at run-time. In the more common ** case where writable static data is supported, wsdHooks can refer directly ** to the "sqlite3Hooks" state vector declared above. */ #ifdef SQLITE_OMIT_WSD # define wsdHooksInit \ BenignMallocHooks *x = &GLOBAL(BenignMallocHooks,sqlite3Hooks) # define wsdHooks x[0] #else # define wsdHooksInit # define wsdHooks sqlite3Hooks #endif /* ** Register hooks to call when sqlite3BeginBenignMalloc() and ** sqlite3EndBenignMalloc() are called, respectively. */ SQLITE_PRIVATE void sqlite3BenignMallocHooks( void (*xBenignBegin)(void), void (*xBenignEnd)(void) ){ wsdHooksInit; wsdHooks.xBenignBegin = xBenignBegin; wsdHooks.xBenignEnd = xBenignEnd; } /* ** This (sqlite3EndBenignMalloc()) is called by SQLite code to indicate that ** subsequent malloc failures are benign. A call to sqlite3EndBenignMalloc() ** indicates that subsequent malloc failures are non-benign. */ SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void){ wsdHooksInit; if( wsdHooks.xBenignBegin ){ wsdHooks.xBenignBegin(); } } SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){ wsdHooksInit; if( wsdHooks.xBenignEnd ){ wsdHooks.xBenignEnd(); } } #endif /* #ifndef SQLITE_UNTESTABLE */ /************** End of fault.c ***********************************************/ /************** Begin file mem0.c ********************************************/ /* ** 2008 October 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains a no-op memory allocation drivers for use when ** SQLITE_ZERO_MALLOC is defined. The allocation drivers implemented ** here always fail. SQLite will not operate with these drivers. These ** are merely placeholders. Real drivers must be substituted using ** sqlite3_config() before SQLite will operate. */ /* #include "sqliteInt.h" */ /* ** This version of the memory allocator is the default. It is ** used when no other memory allocator is specified using compile-time ** macros. */ #ifdef SQLITE_ZERO_MALLOC /* ** No-op versions of all memory allocation routines */ static void *sqlite3MemMalloc(int nByte){ return 0; } static void sqlite3MemFree(void *pPrior){ return; } static void *sqlite3MemRealloc(void *pPrior, int nByte){ return 0; } static int sqlite3MemSize(void *pPrior){ return 0; } static int sqlite3MemRoundup(int n){ return n; } static int sqlite3MemInit(void *NotUsed){ return SQLITE_OK; } static void sqlite3MemShutdown(void *NotUsed){ return; } /* ** This routine is the only routine in this file with external linkage. ** ** Populate the low-level memory allocation function pointers in ** sqlite3GlobalConfig.m with pointers to the routines in this file. */ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ static const sqlite3_mem_methods defaultMethods = { sqlite3MemMalloc, sqlite3MemFree, sqlite3MemRealloc, sqlite3MemSize, sqlite3MemRoundup, sqlite3MemInit, sqlite3MemShutdown, 0 }; sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); } #endif /* SQLITE_ZERO_MALLOC */ /************** End of mem0.c ************************************************/ /************** Begin file mem1.c ********************************************/ /* ** 2007 August 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains low-level memory allocation drivers for when ** SQLite will use the standard C-library malloc/realloc/free interface ** to obtain the memory it needs. ** ** This file contains implementations of the low-level memory allocation ** routines specified in the sqlite3_mem_methods object. The content of ** this file is only used if SQLITE_SYSTEM_MALLOC is defined. The ** SQLITE_SYSTEM_MALLOC macro is defined automatically if neither the ** SQLITE_MEMDEBUG nor the SQLITE_WIN32_MALLOC macros are defined. The ** default configuration is to use memory allocation routines in this ** file. ** ** C-preprocessor macro summary: ** ** HAVE_MALLOC_USABLE_SIZE The configure script sets this symbol if ** the malloc_usable_size() interface exists ** on the target platform. Or, this symbol ** can be set manually, if desired. ** If an equivalent interface exists by ** a different name, using a separate -D ** option to rename it. ** ** SQLITE_WITHOUT_ZONEMALLOC Some older macs lack support for the zone ** memory allocator. Set this symbol to enable ** building on older macs. ** ** SQLITE_WITHOUT_MSIZE Set this symbol to disable the use of ** _msize() on windows systems. This might ** be necessary when compiling for Delphi, ** for example. */ /* #include "sqliteInt.h" */ /* ** This version of the memory allocator is the default. It is ** used when no other memory allocator is specified using compile-time ** macros. */ #ifdef SQLITE_SYSTEM_MALLOC #if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) /* ** Use the zone allocator available on apple products unless the ** SQLITE_WITHOUT_ZONEMALLOC symbol is defined. */ #include #include #ifdef SQLITE_MIGHT_BE_SINGLE_CORE #include #endif /* SQLITE_MIGHT_BE_SINGLE_CORE */ static malloc_zone_t* _sqliteZone_; #define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x)) #define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x)); #define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y)) #define SQLITE_MALLOCSIZE(x) \ (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x)) #else /* if not __APPLE__ */ /* ** Use standard C library malloc and free on non-Apple systems. ** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined. */ #define SQLITE_MALLOC(x) malloc(x) #define SQLITE_FREE(x) free(x) #define SQLITE_REALLOC(x,y) realloc((x),(y)) /* ** The malloc.h header file is needed for malloc_usable_size() function ** on some systems (e.g. Linux). */ #if HAVE_MALLOC_H && HAVE_MALLOC_USABLE_SIZE # define SQLITE_USE_MALLOC_H 1 # define SQLITE_USE_MALLOC_USABLE_SIZE 1 /* ** The MSVCRT has malloc_usable_size(), but it is called _msize(). The ** use of _msize() is automatic, but can be disabled by compiling with ** -DSQLITE_WITHOUT_MSIZE. Using the _msize() function also requires ** the malloc.h header file. */ #elif defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE) # define SQLITE_USE_MALLOC_H # define SQLITE_USE_MSIZE #endif /* ** Include the malloc.h header file, if necessary. Also set define macro ** SQLITE_MALLOCSIZE to the appropriate function name, which is _msize() ** for MSVC and malloc_usable_size() for most other systems (e.g. Linux). ** The memory size function can always be overridden manually by defining ** the macro SQLITE_MALLOCSIZE to the desired function name. */ #if defined(SQLITE_USE_MALLOC_H) # include # if defined(SQLITE_USE_MALLOC_USABLE_SIZE) # if !defined(SQLITE_MALLOCSIZE) # define SQLITE_MALLOCSIZE(x) malloc_usable_size(x) # endif # elif defined(SQLITE_USE_MSIZE) # if !defined(SQLITE_MALLOCSIZE) # define SQLITE_MALLOCSIZE _msize # endif # endif #endif /* defined(SQLITE_USE_MALLOC_H) */ #endif /* __APPLE__ or not __APPLE__ */ /* ** Like malloc(), but remember the size of the allocation ** so that we can find it later using sqlite3MemSize(). ** ** For this low-level routine, we are guaranteed that nByte>0 because ** cases of nByte<=0 will be intercepted and dealt with by higher level ** routines. */ static void *sqlite3MemMalloc(int nByte){ #ifdef SQLITE_MALLOCSIZE void *p; testcase( ROUND8(nByte)==nByte ); p = SQLITE_MALLOC( nByte ); if( p==0 ){ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); } return p; #else sqlite3_int64 *p; assert( nByte>0 ); testcase( ROUND8(nByte)!=nByte ); p = SQLITE_MALLOC( nByte+8 ); if( p ){ p[0] = nByte; p++; }else{ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); } return (void *)p; #endif } /* ** Like free() but works for allocations obtained from sqlite3MemMalloc() ** or sqlite3MemRealloc(). ** ** For this low-level routine, we already know that pPrior!=0 since ** cases where pPrior==0 will have been intercepted and dealt with ** by higher-level routines. */ static void sqlite3MemFree(void *pPrior){ #ifdef SQLITE_MALLOCSIZE SQLITE_FREE(pPrior); #else sqlite3_int64 *p = (sqlite3_int64*)pPrior; assert( pPrior!=0 ); p--; SQLITE_FREE(p); #endif } /* ** Report the allocated size of a prior return from xMalloc() ** or xRealloc(). */ static int sqlite3MemSize(void *pPrior){ #ifdef SQLITE_MALLOCSIZE assert( pPrior!=0 ); return (int)SQLITE_MALLOCSIZE(pPrior); #else sqlite3_int64 *p; assert( pPrior!=0 ); p = (sqlite3_int64*)pPrior; p--; return (int)p[0]; #endif } /* ** Like realloc(). Resize an allocation previously obtained from ** sqlite3MemMalloc(). ** ** For this low-level interface, we know that pPrior!=0. Cases where ** pPrior==0 while have been intercepted by higher-level routine and ** redirected to xMalloc. Similarly, we know that nByte>0 because ** cases where nByte<=0 will have been intercepted by higher-level ** routines and redirected to xFree. */ static void *sqlite3MemRealloc(void *pPrior, int nByte){ #ifdef SQLITE_MALLOCSIZE void *p = SQLITE_REALLOC(pPrior, nByte); if( p==0 ){ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed memory resize %u to %u bytes", SQLITE_MALLOCSIZE(pPrior), nByte); } return p; #else sqlite3_int64 *p = (sqlite3_int64*)pPrior; assert( pPrior!=0 && nByte>0 ); assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */ p--; p = SQLITE_REALLOC(p, nByte+8 ); if( p ){ p[0] = nByte; p++; }else{ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed memory resize %u to %u bytes", sqlite3MemSize(pPrior), nByte); } return (void*)p; #endif } /* ** Round up a request size to the next valid allocation size. */ static int sqlite3MemRoundup(int n){ return ROUND8(n); } /* ** Initialize this module. */ static int sqlite3MemInit(void *NotUsed){ #if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) int cpuCount; size_t len; if( _sqliteZone_ ){ return SQLITE_OK; } len = sizeof(cpuCount); /* One usually wants to use hw.activecpu for MT decisions, but not here */ sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0); if( cpuCount>1 ){ /* defer MT decisions to system malloc */ _sqliteZone_ = malloc_default_zone(); }else{ /* only 1 core, use our own zone to contention over global locks, ** e.g. we have our own dedicated locks */ _sqliteZone_ = malloc_create_zone(4096, 0); malloc_set_zone_name(_sqliteZone_, "Sqlite_Heap"); } #endif /* defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) */ UNUSED_PARAMETER(NotUsed); return SQLITE_OK; } /* ** Deinitialize this module. */ static void sqlite3MemShutdown(void *NotUsed){ UNUSED_PARAMETER(NotUsed); return; } /* ** This routine is the only routine in this file with external linkage. ** ** Populate the low-level memory allocation function pointers in ** sqlite3GlobalConfig.m with pointers to the routines in this file. */ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ static const sqlite3_mem_methods defaultMethods = { sqlite3MemMalloc, sqlite3MemFree, sqlite3MemRealloc, sqlite3MemSize, sqlite3MemRoundup, sqlite3MemInit, sqlite3MemShutdown, 0 }; sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); } #endif /* SQLITE_SYSTEM_MALLOC */ /************** End of mem1.c ************************************************/ /************** Begin file mem2.c ********************************************/ /* ** 2007 August 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains low-level memory allocation drivers for when ** SQLite will use the standard C-library malloc/realloc/free interface ** to obtain the memory it needs while adding lots of additional debugging ** information to each allocation in order to help detect and fix memory ** leaks and memory usage errors. ** ** This file contains implementations of the low-level memory allocation ** routines specified in the sqlite3_mem_methods object. */ /* #include "sqliteInt.h" */ /* ** This version of the memory allocator is used only if the ** SQLITE_MEMDEBUG macro is defined */ #ifdef SQLITE_MEMDEBUG /* ** The backtrace functionality is only available with GLIBC */ #ifdef __GLIBC__ extern int backtrace(void**,int); extern void backtrace_symbols_fd(void*const*,int,int); #else # define backtrace(A,B) 1 # define backtrace_symbols_fd(A,B,C) #endif /* #include */ /* ** Each memory allocation looks like this: ** ** ------------------------------------------------------------------------ ** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard | ** ------------------------------------------------------------------------ ** ** The application code sees only a pointer to the allocation. We have ** to back up from the allocation pointer to find the MemBlockHdr. The ** MemBlockHdr tells us the size of the allocation and the number of ** backtrace pointers. There is also a guard word at the end of the ** MemBlockHdr. */ struct MemBlockHdr { i64 iSize; /* Size of this allocation */ struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */ char nBacktrace; /* Number of backtraces on this alloc */ char nBacktraceSlots; /* Available backtrace slots */ u8 nTitle; /* Bytes of title; includes '\0' */ u8 eType; /* Allocation type code */ int iForeGuard; /* Guard word for sanity */ }; /* ** Guard words */ #define FOREGUARD 0x80F5E153 #define REARGUARD 0xE4676B53 /* ** Number of malloc size increments to track. */ #define NCSIZE 1000 /* ** All of the static variables used by this module are collected ** into a single structure named "mem". This is to keep the ** static variables organized and to reduce namespace pollution ** when this module is combined with other in the amalgamation. */ static struct { /* ** Mutex to control access to the memory allocation subsystem. */ sqlite3_mutex *mutex; /* ** Head and tail of a linked list of all outstanding allocations */ struct MemBlockHdr *pFirst; struct MemBlockHdr *pLast; /* ** The number of levels of backtrace to save in new allocations. */ int nBacktrace; void (*xBacktrace)(int, int, void **); /* ** Title text to insert in front of each block */ int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ char zTitle[100]; /* The title text */ /* ** sqlite3MallocDisallow() increments the following counter. ** sqlite3MallocAllow() decrements it. */ int disallow; /* Do not allow memory allocation */ /* ** Gather statistics on the sizes of memory allocations. ** nAlloc[i] is the number of allocation attempts of i*8 ** bytes. i==NCSIZE is the number of allocation attempts for ** sizes more than NCSIZE*8 bytes. */ int nAlloc[NCSIZE]; /* Total number of allocations */ int nCurrent[NCSIZE]; /* Current number of allocations */ int mxCurrent[NCSIZE]; /* Highwater mark for nCurrent */ } mem; /* ** Adjust memory usage statistics */ static void adjustStats(int iSize, int increment){ int i = ROUND8(iSize)/8; if( i>NCSIZE-1 ){ i = NCSIZE - 1; } if( increment>0 ){ mem.nAlloc[i]++; mem.nCurrent[i]++; if( mem.nCurrent[i]>mem.mxCurrent[i] ){ mem.mxCurrent[i] = mem.nCurrent[i]; } }else{ mem.nCurrent[i]--; assert( mem.nCurrent[i]>=0 ); } } /* ** Given an allocation, find the MemBlockHdr for that allocation. ** ** This routine checks the guards at either end of the allocation and ** if they are incorrect it asserts. */ static struct MemBlockHdr *sqlite3MemsysGetHeader(const void *pAllocation){ struct MemBlockHdr *p; int *pInt; u8 *pU8; int nReserve; p = (struct MemBlockHdr*)pAllocation; p--; assert( p->iForeGuard==(int)FOREGUARD ); nReserve = ROUND8(p->iSize); pInt = (int*)pAllocation; pU8 = (u8*)pAllocation; assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD ); /* This checks any of the "extra" bytes allocated due ** to rounding up to an 8 byte boundary to ensure ** they haven't been overwritten. */ while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 ); return p; } /* ** Return the number of bytes currently allocated at address p. */ static int sqlite3MemSize(void *p){ struct MemBlockHdr *pHdr; if( !p ){ return 0; } pHdr = sqlite3MemsysGetHeader(p); return (int)pHdr->iSize; } /* ** Initialize the memory allocation subsystem. */ static int sqlite3MemInit(void *NotUsed){ UNUSED_PARAMETER(NotUsed); assert( (sizeof(struct MemBlockHdr)&7) == 0 ); if( !sqlite3GlobalConfig.bMemstat ){ /* If memory status is enabled, then the malloc.c wrapper will already ** hold the STATIC_MEM mutex when the routines here are invoked. */ mem.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); } return SQLITE_OK; } /* ** Deinitialize the memory allocation subsystem. */ static void sqlite3MemShutdown(void *NotUsed){ UNUSED_PARAMETER(NotUsed); mem.mutex = 0; } /* ** Round up a request size to the next valid allocation size. */ static int sqlite3MemRoundup(int n){ return ROUND8(n); } /* ** Fill a buffer with pseudo-random bytes. This is used to preset ** the content of a new memory allocation to unpredictable values and ** to clear the content of a freed allocation to unpredictable values. */ static void randomFill(char *pBuf, int nByte){ unsigned int x, y, r; x = SQLITE_PTR_TO_INT(pBuf); y = nByte | 1; while( nByte >= 4 ){ x = (x>>1) ^ (-(int)(x&1) & 0xd0000001); y = y*1103515245 + 12345; r = x ^ y; *(int*)pBuf = r; pBuf += 4; nByte -= 4; } while( nByte-- > 0 ){ x = (x>>1) ^ (-(int)(x&1) & 0xd0000001); y = y*1103515245 + 12345; r = x ^ y; *(pBuf++) = r & 0xff; } } /* ** Allocate nByte bytes of memory. */ static void *sqlite3MemMalloc(int nByte){ struct MemBlockHdr *pHdr; void **pBt; char *z; int *pInt; void *p = 0; int totalSize; int nReserve; sqlite3_mutex_enter(mem.mutex); assert( mem.disallow==0 ); nReserve = ROUND8(nByte); totalSize = nReserve + sizeof(*pHdr) + sizeof(int) + mem.nBacktrace*sizeof(void*) + mem.nTitle; p = malloc(totalSize); if( p ){ z = p; pBt = (void**)&z[mem.nTitle]; pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace]; pHdr->pNext = 0; pHdr->pPrev = mem.pLast; if( mem.pLast ){ mem.pLast->pNext = pHdr; }else{ mem.pFirst = pHdr; } mem.pLast = pHdr; pHdr->iForeGuard = FOREGUARD; pHdr->eType = MEMTYPE_HEAP; pHdr->nBacktraceSlots = mem.nBacktrace; pHdr->nTitle = mem.nTitle; if( mem.nBacktrace ){ void *aAddr[40]; pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1; memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*)); assert(pBt[0]); if( mem.xBacktrace ){ mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]); } }else{ pHdr->nBacktrace = 0; } if( mem.nTitle ){ memcpy(z, mem.zTitle, mem.nTitle); } pHdr->iSize = nByte; adjustStats(nByte, +1); pInt = (int*)&pHdr[1]; pInt[nReserve/sizeof(int)] = REARGUARD; randomFill((char*)pInt, nByte); memset(((char*)pInt)+nByte, 0x65, nReserve-nByte); p = (void*)pInt; } sqlite3_mutex_leave(mem.mutex); return p; } /* ** Free memory. */ static void sqlite3MemFree(void *pPrior){ struct MemBlockHdr *pHdr; void **pBt; char *z; assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0 || mem.mutex!=0 ); pHdr = sqlite3MemsysGetHeader(pPrior); pBt = (void**)pHdr; pBt -= pHdr->nBacktraceSlots; sqlite3_mutex_enter(mem.mutex); if( pHdr->pPrev ){ assert( pHdr->pPrev->pNext==pHdr ); pHdr->pPrev->pNext = pHdr->pNext; }else{ assert( mem.pFirst==pHdr ); mem.pFirst = pHdr->pNext; } if( pHdr->pNext ){ assert( pHdr->pNext->pPrev==pHdr ); pHdr->pNext->pPrev = pHdr->pPrev; }else{ assert( mem.pLast==pHdr ); mem.pLast = pHdr->pPrev; } z = (char*)pBt; z -= pHdr->nTitle; adjustStats((int)pHdr->iSize, -1); randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) + (int)pHdr->iSize + sizeof(int) + pHdr->nTitle); free(z); sqlite3_mutex_leave(mem.mutex); } /* ** Change the size of an existing memory allocation. ** ** For this debugging implementation, we *always* make a copy of the ** allocation into a new place in memory. In this way, if the ** higher level code is using pointer to the old allocation, it is ** much more likely to break and we are much more liking to find ** the error. */ static void *sqlite3MemRealloc(void *pPrior, int nByte){ struct MemBlockHdr *pOldHdr; void *pNew; assert( mem.disallow==0 ); assert( (nByte & 7)==0 ); /* EV: R-46199-30249 */ pOldHdr = sqlite3MemsysGetHeader(pPrior); pNew = sqlite3MemMalloc(nByte); if( pNew ){ memcpy(pNew, pPrior, (int)(nByteiSize ? nByte : pOldHdr->iSize)); if( nByte>pOldHdr->iSize ){ randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - (int)pOldHdr->iSize); } sqlite3MemFree(pPrior); } return pNew; } /* ** Populate the low-level memory allocation function pointers in ** sqlite3GlobalConfig.m with pointers to the routines in this file. */ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ static const sqlite3_mem_methods defaultMethods = { sqlite3MemMalloc, sqlite3MemFree, sqlite3MemRealloc, sqlite3MemSize, sqlite3MemRoundup, sqlite3MemInit, sqlite3MemShutdown, 0 }; sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); } /* ** Set the "type" of an allocation. */ SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); pHdr->eType = eType; } } /* ** Return TRUE if the mask of type in eType matches the type of the ** allocation p. Also return true if p==NULL. ** ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** ** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); */ SQLITE_PRIVATE int sqlite3MemdebugHasType(const void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ if( (pHdr->eType&eType)==0 ){ rc = 0; } } return rc; } /* ** Return TRUE if the mask of type in eType matches no bits of the type of the ** allocation p. Also return true if p==NULL. ** ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** ** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); */ SQLITE_PRIVATE int sqlite3MemdebugNoType(const void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ if( (pHdr->eType&eType)!=0 ){ rc = 0; } } return rc; } /* ** Set the number of backtrace levels kept for each allocation. ** A value of zero turns off backtracing. The number is always rounded ** up to a multiple of 2. */ SQLITE_PRIVATE void sqlite3MemdebugBacktrace(int depth){ if( depth<0 ){ depth = 0; } if( depth>20 ){ depth = 20; } depth = (depth+1)&0xfe; mem.nBacktrace = depth; } SQLITE_PRIVATE void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){ mem.xBacktrace = xBacktrace; } /* ** Set the title string for subsequent allocations. */ SQLITE_PRIVATE void sqlite3MemdebugSettitle(const char *zTitle){ unsigned int n = sqlite3Strlen30(zTitle) + 1; sqlite3_mutex_enter(mem.mutex); if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1; memcpy(mem.zTitle, zTitle, n); mem.zTitle[n] = 0; mem.nTitle = ROUND8(n); sqlite3_mutex_leave(mem.mutex); } SQLITE_PRIVATE void sqlite3MemdebugSync(){ struct MemBlockHdr *pHdr; for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ void **pBt = (void**)pHdr; pBt -= pHdr->nBacktraceSlots; mem.xBacktrace((int)pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]); } } /* ** Open the file indicated and write a log of all unfreed memory ** allocations into that log. */ SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){ FILE *out; struct MemBlockHdr *pHdr; void **pBt; int i; out = fopen(zFilename, "w"); if( out==0 ){ fprintf(stderr, "** Unable to output memory debug output log: %s **\n", zFilename); return; } for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ char *z = (char*)pHdr; z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle; fprintf(out, "**** %lld bytes at %p from %s ****\n", pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???"); if( pHdr->nBacktrace ){ fflush(out); pBt = (void**)pHdr; pBt -= pHdr->nBacktraceSlots; backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out)); fprintf(out, "\n"); } } fprintf(out, "COUNTS:\n"); for(i=0; i=1 ); size = mem3.aPool[i-1].u.hdr.size4x/4; assert( size==mem3.aPool[i+size-1].u.hdr.prevSize ); assert( size>=2 ); if( size <= MX_SMALL ){ memsys3UnlinkFromList(i, &mem3.aiSmall[size-2]); }else{ hash = size % N_HASH; memsys3UnlinkFromList(i, &mem3.aiHash[hash]); } } /* ** Link the chunk at mem3.aPool[i] so that is on the list rooted ** at *pRoot. */ static void memsys3LinkIntoList(u32 i, u32 *pRoot){ assert( sqlite3_mutex_held(mem3.mutex) ); mem3.aPool[i].u.list.next = *pRoot; mem3.aPool[i].u.list.prev = 0; if( *pRoot ){ mem3.aPool[*pRoot].u.list.prev = i; } *pRoot = i; } /* ** Link the chunk at index i into either the appropriate ** small chunk list, or into the large chunk hash table. */ static void memsys3Link(u32 i){ u32 size, hash; assert( sqlite3_mutex_held(mem3.mutex) ); assert( i>=1 ); assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 ); size = mem3.aPool[i-1].u.hdr.size4x/4; assert( size==mem3.aPool[i+size-1].u.hdr.prevSize ); assert( size>=2 ); if( size <= MX_SMALL ){ memsys3LinkIntoList(i, &mem3.aiSmall[size-2]); }else{ hash = size % N_HASH; memsys3LinkIntoList(i, &mem3.aiHash[hash]); } } /* ** If the STATIC_MEM mutex is not already held, obtain it now. The mutex ** will already be held (obtained by code in malloc.c) if ** sqlite3GlobalConfig.bMemStat is true. */ static void memsys3Enter(void){ if( sqlite3GlobalConfig.bMemstat==0 && mem3.mutex==0 ){ mem3.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); } sqlite3_mutex_enter(mem3.mutex); } static void memsys3Leave(void){ sqlite3_mutex_leave(mem3.mutex); } /* ** Called when we are unable to satisfy an allocation of nBytes. */ static void memsys3OutOfMemory(int nByte){ if( !mem3.alarmBusy ){ mem3.alarmBusy = 1; assert( sqlite3_mutex_held(mem3.mutex) ); sqlite3_mutex_leave(mem3.mutex); sqlite3_release_memory(nByte); sqlite3_mutex_enter(mem3.mutex); mem3.alarmBusy = 0; } } /* ** Chunk i is a free chunk that has been unlinked. Adjust its ** size parameters for check-out and return a pointer to the ** user portion of the chunk. */ static void *memsys3Checkout(u32 i, u32 nBlock){ u32 x; assert( sqlite3_mutex_held(mem3.mutex) ); assert( i>=1 ); assert( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ); assert( mem3.aPool[i+nBlock-1].u.hdr.prevSize==nBlock ); x = mem3.aPool[i-1].u.hdr.size4x; mem3.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2); mem3.aPool[i+nBlock-1].u.hdr.prevSize = nBlock; mem3.aPool[i+nBlock-1].u.hdr.size4x |= 2; return &mem3.aPool[i]; } /* ** Carve a piece off of the end of the mem3.iKeyBlk free chunk. ** Return a pointer to the new allocation. Or, if the key chunk ** is not large enough, return 0. */ static void *memsys3FromKeyBlk(u32 nBlock){ assert( sqlite3_mutex_held(mem3.mutex) ); assert( mem3.szKeyBlk>=nBlock ); if( nBlock>=mem3.szKeyBlk-1 ){ /* Use the entire key chunk */ void *p = memsys3Checkout(mem3.iKeyBlk, mem3.szKeyBlk); mem3.iKeyBlk = 0; mem3.szKeyBlk = 0; mem3.mnKeyBlk = 0; return p; }else{ /* Split the key block. Return the tail. */ u32 newi, x; newi = mem3.iKeyBlk + mem3.szKeyBlk - nBlock; assert( newi > mem3.iKeyBlk+1 ); mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = nBlock; mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x |= 2; mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1; mem3.szKeyBlk -= nBlock; mem3.aPool[newi-1].u.hdr.prevSize = mem3.szKeyBlk; x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2; mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x; if( mem3.szKeyBlk < mem3.mnKeyBlk ){ mem3.mnKeyBlk = mem3.szKeyBlk; } return (void*)&mem3.aPool[newi]; } } /* ** *pRoot is the head of a list of free chunks of the same size ** or same size hash. In other words, *pRoot is an entry in either ** mem3.aiSmall[] or mem3.aiHash[]. ** ** This routine examines all entries on the given list and tries ** to coalesce each entries with adjacent free chunks. ** ** If it sees a chunk that is larger than mem3.iKeyBlk, it replaces ** the current mem3.iKeyBlk with the new larger chunk. In order for ** this mem3.iKeyBlk replacement to work, the key chunk must be ** linked into the hash tables. That is not the normal state of ** affairs, of course. The calling routine must link the key ** chunk before invoking this routine, then must unlink the (possibly ** changed) key chunk once this routine has finished. */ static void memsys3Merge(u32 *pRoot){ u32 iNext, prev, size, i, x; assert( sqlite3_mutex_held(mem3.mutex) ); for(i=*pRoot; i>0; i=iNext){ iNext = mem3.aPool[i].u.list.next; size = mem3.aPool[i-1].u.hdr.size4x; assert( (size&1)==0 ); if( (size&2)==0 ){ memsys3UnlinkFromList(i, pRoot); assert( i > mem3.aPool[i-1].u.hdr.prevSize ); prev = i - mem3.aPool[i-1].u.hdr.prevSize; if( prev==iNext ){ iNext = mem3.aPool[prev].u.list.next; } memsys3Unlink(prev); size = i + size/4 - prev; x = mem3.aPool[prev-1].u.hdr.size4x & 2; mem3.aPool[prev-1].u.hdr.size4x = size*4 | x; mem3.aPool[prev+size-1].u.hdr.prevSize = size; memsys3Link(prev); i = prev; }else{ size /= 4; } if( size>mem3.szKeyBlk ){ mem3.iKeyBlk = i; mem3.szKeyBlk = size; } } } /* ** Return a block of memory of at least nBytes in size. ** Return NULL if unable. ** ** This function assumes that the necessary mutexes, if any, are ** already held by the caller. Hence "Unsafe". */ static void *memsys3MallocUnsafe(int nByte){ u32 i; u32 nBlock; u32 toFree; assert( sqlite3_mutex_held(mem3.mutex) ); assert( sizeof(Mem3Block)==8 ); if( nByte<=12 ){ nBlock = 2; }else{ nBlock = (nByte + 11)/8; } assert( nBlock>=2 ); /* STEP 1: ** Look for an entry of the correct size in either the small ** chunk table or in the large chunk hash table. This is ** successful most of the time (about 9 times out of 10). */ if( nBlock <= MX_SMALL ){ i = mem3.aiSmall[nBlock-2]; if( i>0 ){ memsys3UnlinkFromList(i, &mem3.aiSmall[nBlock-2]); return memsys3Checkout(i, nBlock); } }else{ int hash = nBlock % N_HASH; for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next){ if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ){ memsys3UnlinkFromList(i, &mem3.aiHash[hash]); return memsys3Checkout(i, nBlock); } } } /* STEP 2: ** Try to satisfy the allocation by carving a piece off of the end ** of the key chunk. This step usually works if step 1 fails. */ if( mem3.szKeyBlk>=nBlock ){ return memsys3FromKeyBlk(nBlock); } /* STEP 3: ** Loop through the entire memory pool. Coalesce adjacent free ** chunks. Recompute the key chunk as the largest free chunk. ** Then try again to satisfy the allocation by carving a piece off ** of the end of the key chunk. This step happens very ** rarely (we hope!) */ for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){ memsys3OutOfMemory(toFree); if( mem3.iKeyBlk ){ memsys3Link(mem3.iKeyBlk); mem3.iKeyBlk = 0; mem3.szKeyBlk = 0; } for(i=0; i=nBlock ){ return memsys3FromKeyBlk(nBlock); } } } /* If none of the above worked, then we fail. */ return 0; } /* ** Free an outstanding memory allocation. ** ** This function assumes that the necessary mutexes, if any, are ** already held by the caller. Hence "Unsafe". */ static void memsys3FreeUnsafe(void *pOld){ Mem3Block *p = (Mem3Block*)pOld; int i; u32 size, x; assert( sqlite3_mutex_held(mem3.mutex) ); assert( p>mem3.aPool && p<&mem3.aPool[mem3.nPool] ); i = p - mem3.aPool; assert( (mem3.aPool[i-1].u.hdr.size4x&1)==1 ); size = mem3.aPool[i-1].u.hdr.size4x/4; assert( i+size<=mem3.nPool+1 ); mem3.aPool[i-1].u.hdr.size4x &= ~1; mem3.aPool[i+size-1].u.hdr.prevSize = size; mem3.aPool[i+size-1].u.hdr.size4x &= ~2; memsys3Link(i); /* Try to expand the key using the newly freed chunk */ if( mem3.iKeyBlk ){ while( (mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x&2)==0 ){ size = mem3.aPool[mem3.iKeyBlk-1].u.hdr.prevSize; mem3.iKeyBlk -= size; mem3.szKeyBlk += size; memsys3Unlink(mem3.iKeyBlk); x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2; mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x; mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk; } x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2; while( (mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x&1)==0 ){ memsys3Unlink(mem3.iKeyBlk+mem3.szKeyBlk); mem3.szKeyBlk += mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x/4; mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x; mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk; } } } /* ** Return the size of an outstanding allocation, in bytes. The ** size returned omits the 8-byte header overhead. This only ** works for chunks that are currently checked out. */ static int memsys3Size(void *p){ Mem3Block *pBlock; assert( p!=0 ); pBlock = (Mem3Block*)p; assert( (pBlock[-1].u.hdr.size4x&1)!=0 ); return (pBlock[-1].u.hdr.size4x&~3)*2 - 4; } /* ** Round up a request size to the next valid allocation size. */ static int memsys3Roundup(int n){ if( n<=12 ){ return 12; }else{ return ((n+11)&~7) - 4; } } /* ** Allocate nBytes of memory. */ static void *memsys3Malloc(int nBytes){ sqlite3_int64 *p; assert( nBytes>0 ); /* malloc.c filters out 0 byte requests */ memsys3Enter(); p = memsys3MallocUnsafe(nBytes); memsys3Leave(); return (void*)p; } /* ** Free memory. */ static void memsys3Free(void *pPrior){ assert( pPrior ); memsys3Enter(); memsys3FreeUnsafe(pPrior); memsys3Leave(); } /* ** Change the size of an existing memory allocation */ static void *memsys3Realloc(void *pPrior, int nBytes){ int nOld; void *p; if( pPrior==0 ){ return sqlite3_malloc(nBytes); } if( nBytes<=0 ){ sqlite3_free(pPrior); return 0; } nOld = memsys3Size(pPrior); if( nBytes<=nOld && nBytes>=nOld-128 ){ return pPrior; } memsys3Enter(); p = memsys3MallocUnsafe(nBytes); if( p ){ if( nOld>1)!=(size&1) ){ fprintf(out, "%p tail checkout bit is incorrect\n", &mem3.aPool[i]); assert( 0 ); break; } if( size&1 ){ fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8); }else{ fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8, i==mem3.iKeyBlk ? " **key**" : ""); } } for(i=0; i0; j=mem3.aPool[j].u.list.next){ fprintf(out, " %p(%d)", &mem3.aPool[j], (mem3.aPool[j-1].u.hdr.size4x/4)*8-8); } fprintf(out, "\n"); } for(i=0; i0; j=mem3.aPool[j].u.list.next){ fprintf(out, " %p(%d)", &mem3.aPool[j], (mem3.aPool[j-1].u.hdr.size4x/4)*8-8); } fprintf(out, "\n"); } fprintf(out, "key=%d\n", mem3.iKeyBlk); fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szKeyBlk*8); fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnKeyBlk*8); sqlite3_mutex_leave(mem3.mutex); if( out==stdout ){ fflush(stdout); }else{ fclose(out); } #else UNUSED_PARAMETER(zFilename); #endif } /* ** This routine is the only routine in this file with external ** linkage. ** ** Populate the low-level memory allocation function pointers in ** sqlite3GlobalConfig.m with pointers to the routines in this file. The ** arguments specify the block of memory to manage. ** ** This routine is only called by sqlite3_config(), and therefore ** is not required to be threadsafe (it is not). */ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){ static const sqlite3_mem_methods mempoolMethods = { memsys3Malloc, memsys3Free, memsys3Realloc, memsys3Size, memsys3Roundup, memsys3Init, memsys3Shutdown, 0 }; return &mempoolMethods; } #endif /* SQLITE_ENABLE_MEMSYS3 */ /************** End of mem3.c ************************************************/ /************** Begin file mem5.c ********************************************/ /* ** 2007 October 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** ** This version of the memory allocation subsystem omits all ** use of malloc(). The application gives SQLite a block of memory ** before calling sqlite3_initialize() from which allocations ** are made and returned by the xMalloc() and xRealloc() ** implementations. Once sqlite3_initialize() has been called, ** the amount of memory available to SQLite is fixed and cannot ** be changed. ** ** This version of the memory allocation subsystem is included ** in the build only if SQLITE_ENABLE_MEMSYS5 is defined. ** ** This memory allocator uses the following algorithm: ** ** 1. All memory allocation sizes are rounded up to a power of 2. ** ** 2. If two adjacent free blocks are the halves of a larger block, ** then the two blocks are coalesced into the single larger block. ** ** 3. New memory is allocated from the first available free block. ** ** This algorithm is described in: J. M. Robson. "Bounds for Some Functions ** Concerning Dynamic Storage Allocation". Journal of the Association for ** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499. ** ** Let n be the size of the largest allocation divided by the minimum ** allocation size (after rounding all sizes up to a power of 2.) Let M ** be the maximum amount of memory ever outstanding at one time. Let ** N be the total amount of memory available for allocation. Robson ** proved that this memory allocator will never breakdown due to ** fragmentation as long as the following constraint holds: ** ** N >= M*(1 + log2(n)/2) - n + 1 ** ** The sqlite3_status() logic tracks the maximum values of n and M so ** that an application can, at any time, verify this constraint. */ /* #include "sqliteInt.h" */ /* ** This version of the memory allocator is used only when ** SQLITE_ENABLE_MEMSYS5 is defined. */ #ifdef SQLITE_ENABLE_MEMSYS5 /* ** A minimum allocation is an instance of the following structure. ** Larger allocations are an array of these structures where the ** size of the array is a power of 2. ** ** The size of this object must be a power of two. That fact is ** verified in memsys5Init(). */ typedef struct Mem5Link Mem5Link; struct Mem5Link { int next; /* Index of next free chunk */ int prev; /* Index of previous free chunk */ }; /* ** Maximum size of any allocation is ((1<=0 && i=0 && iLogsize<=LOGMAX ); assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize ); next = MEM5LINK(i)->next; prev = MEM5LINK(i)->prev; if( prev<0 ){ mem5.aiFreelist[iLogsize] = next; }else{ MEM5LINK(prev)->next = next; } if( next>=0 ){ MEM5LINK(next)->prev = prev; } } /* ** Link the chunk at mem5.aPool[i] so that is on the iLogsize ** free list. */ static void memsys5Link(int i, int iLogsize){ int x; assert( sqlite3_mutex_held(mem5.mutex) ); assert( i>=0 && i=0 && iLogsize<=LOGMAX ); assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize ); x = MEM5LINK(i)->next = mem5.aiFreelist[iLogsize]; MEM5LINK(i)->prev = -1; if( x>=0 ){ assert( xprev = i; } mem5.aiFreelist[iLogsize] = i; } /* ** Obtain or release the mutex needed to access global data structures. */ static void memsys5Enter(void){ sqlite3_mutex_enter(mem5.mutex); } static void memsys5Leave(void){ sqlite3_mutex_leave(mem5.mutex); } /* ** Return the size of an outstanding allocation, in bytes. ** This only works for chunks that are currently checked out. */ static int memsys5Size(void *p){ int iSize, i; assert( p!=0 ); i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom); assert( i>=0 && i0 ); /* No more than 1GiB per allocation */ if( nByte > 0x40000000 ) return 0; #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* Keep track of the maximum allocation request. Even unfulfilled ** requests are counted */ if( (u32)nByte>mem5.maxRequest ){ mem5.maxRequest = nByte; } #endif /* Round nByte up to the next valid power of two */ for(iFullSz=mem5.szAtom,iLogsize=0; iFullSzLOGMAX ){ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte); return 0; } i = mem5.aiFreelist[iBin]; memsys5Unlink(i, iBin); while( iBin>iLogsize ){ int newSize; iBin--; newSize = 1 << iBin; mem5.aCtrl[i+newSize] = CTRL_FREE | iBin; memsys5Link(i+newSize, iBin); } mem5.aCtrl[i] = iLogsize; #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* Update allocator performance statistics. */ mem5.nAlloc++; mem5.totalAlloc += iFullSz; mem5.totalExcess += iFullSz - nByte; mem5.currentCount++; mem5.currentOut += iFullSz; if( mem5.maxCount=0 && iBlock0 ); assert( mem5.currentOut>=(size*mem5.szAtom) ); mem5.currentCount--; mem5.currentOut -= size*mem5.szAtom; assert( mem5.currentOut>0 || mem5.currentCount==0 ); assert( mem5.currentCount>0 || mem5.currentOut==0 ); #endif mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize; while( ALWAYS(iLogsize>iLogsize) & 1 ){ iBuddy = iBlock - size; assert( iBuddy>=0 ); }else{ iBuddy = iBlock + size; if( iBuddy>=mem5.nBlock ) break; } if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break; memsys5Unlink(iBuddy, iLogsize); iLogsize++; if( iBuddy0 ){ memsys5Enter(); p = memsys5MallocUnsafe(nBytes); memsys5Leave(); } return (void*)p; } /* ** Free memory. ** ** The outer layer memory allocator prevents this routine from ** being called with pPrior==0. */ static void memsys5Free(void *pPrior){ assert( pPrior!=0 ); memsys5Enter(); memsys5FreeUnsafe(pPrior); memsys5Leave(); } /* ** Change the size of an existing memory allocation. ** ** The outer layer memory allocator prevents this routine from ** being called with pPrior==0. ** ** nBytes is always a value obtained from a prior call to ** memsys5Round(). Hence nBytes is always a non-negative power ** of two. If nBytes==0 that means that an oversize allocation ** (an allocation larger than 0x40000000) was requested and this ** routine should return 0 without freeing pPrior. */ static void *memsys5Realloc(void *pPrior, int nBytes){ int nOld; void *p; assert( pPrior!=0 ); assert( (nBytes&(nBytes-1))==0 ); /* EV: R-46199-30249 */ assert( nBytes>=0 ); if( nBytes==0 ){ return 0; } nOld = memsys5Size(pPrior); if( nBytes<=nOld ){ return pPrior; } p = memsys5Malloc(nBytes); if( p ){ memcpy(p, pPrior, nOld); memsys5Free(pPrior); } return p; } /* ** Round up a request size to the next valid allocation size. If ** the allocation is too large to be handled by this allocation system, ** return 0. ** ** All allocations must be a power of two and must be expressed by a ** 32-bit signed integer. Hence the largest allocation is 0x40000000 ** or 1073741824 bytes. */ static int memsys5Roundup(int n){ int iFullSz; if( n<=mem5.szAtom*2 ){ if( n<=mem5.szAtom ) return mem5.szAtom; return mem5.szAtom*2; } if( n>0x10000000 ){ if( n>0x40000000 ) return 0; if( n>0x20000000 ) return 0x40000000; return 0x20000000; } for(iFullSz=mem5.szAtom*8; iFullSz=(i64)n ) return iFullSz/2; return iFullSz; } /* ** Return the ceiling of the logarithm base 2 of iValue. ** ** Examples: memsys5Log(1) -> 0 ** memsys5Log(2) -> 1 ** memsys5Log(4) -> 2 ** memsys5Log(5) -> 3 ** memsys5Log(8) -> 3 ** memsys5Log(9) -> 4 */ static int memsys5Log(int iValue){ int iLog; for(iLog=0; (iLog<(int)((sizeof(int)*8)-1)) && (1<mem5.szAtom ){ mem5.szAtom = mem5.szAtom << 1; } mem5.nBlock = (nByte / (mem5.szAtom+sizeof(u8))); mem5.zPool = zByte; mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.szAtom]; for(ii=0; ii<=LOGMAX; ii++){ mem5.aiFreelist[ii] = -1; } iOffset = 0; for(ii=LOGMAX; ii>=0; ii--){ int nAlloc = (1<mem5.nBlock); } /* If a mutex is required for normal operation, allocate one */ if( sqlite3GlobalConfig.bMemstat==0 ){ mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); } return SQLITE_OK; } /* ** Deinitialize this module. */ static void memsys5Shutdown(void *NotUsed){ UNUSED_PARAMETER(NotUsed); mem5.mutex = 0; return; } #ifdef SQLITE_TEST /* ** Open the file indicated and write a log of all unfreed memory ** allocations into that log. */ SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){ FILE *out; int i, j, n; int nMinLog; if( zFilename==0 || zFilename[0]==0 ){ out = stdout; }else{ out = fopen(zFilename, "w"); if( out==0 ){ fprintf(stderr, "** Unable to output memory debug output log: %s **\n", zFilename); return; } } memsys5Enter(); nMinLog = memsys5Log(mem5.szAtom); for(i=0; i<=LOGMAX && i+nMinLog<32; i++){ for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){} fprintf(out, "freelist items of size %d: %d\n", mem5.szAtom << i, n); } fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc); fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc); fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess); fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut); fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount); fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut); fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount); fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest); memsys5Leave(); if( out==stdout ){ fflush(stdout); }else{ fclose(out); } } #endif /* ** This routine is the only routine in this file with external ** linkage. It returns a pointer to a static sqlite3_mem_methods ** struct populated with the memsys5 methods. */ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){ static const sqlite3_mem_methods memsys5Methods = { memsys5Malloc, memsys5Free, memsys5Realloc, memsys5Size, memsys5Roundup, memsys5Init, memsys5Shutdown, 0 }; return &memsys5Methods; } #endif /* SQLITE_ENABLE_MEMSYS5 */ /************** End of mem5.c ************************************************/ /************** Begin file mutex.c *******************************************/ /* ** 2007 August 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement mutexes. ** ** This file contains code that is common across all mutex implementations. */ /* #include "sqliteInt.h" */ #if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT) /* ** For debugging purposes, record when the mutex subsystem is initialized ** and uninitialized so that we can assert() if there is an attempt to ** allocate a mutex while the system is uninitialized. */ static SQLITE_WSD int mutexIsInit = 0; #endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */ #ifndef SQLITE_MUTEX_OMIT #ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS /* ** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains ** the implementation of a wrapper around the system default mutex ** implementation (sqlite3DefaultMutex()). ** ** Most calls are passed directly through to the underlying default ** mutex implementation. Except, if a mutex is configured by calling ** sqlite3MutexWarnOnContention() on it, then if contention is ever ** encountered within xMutexEnter() a warning is emitted via sqlite3_log(). ** ** This type of mutex is used as the database handle mutex when testing ** apps that usually use SQLITE_CONFIG_MULTITHREAD mode. */ /* ** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS ** is defined. Variable CheckMutex.mutex is a pointer to the real mutex ** allocated by the system mutex implementation. Variable iType is usually set ** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST ** or one of the static mutex identifiers. Or, if this is a recursive mutex ** that has been configured using sqlite3MutexWarnOnContention(), it is ** set to SQLITE_MUTEX_WARNONCONTENTION. */ typedef struct CheckMutex CheckMutex; struct CheckMutex { int iType; sqlite3_mutex *mutex; }; #define SQLITE_MUTEX_WARNONCONTENTION (-1) /* ** Pointer to real mutex methods object used by the CheckMutex ** implementation. Set by checkMutexInit(). */ static SQLITE_WSD const sqlite3_mutex_methods *pGlobalMutexMethods; #ifdef SQLITE_DEBUG static int checkMutexHeld(sqlite3_mutex *p){ return pGlobalMutexMethods->xMutexHeld(((CheckMutex*)p)->mutex); } static int checkMutexNotheld(sqlite3_mutex *p){ return pGlobalMutexMethods->xMutexNotheld(((CheckMutex*)p)->mutex); } #endif /* ** Initialize and deinitialize the mutex subsystem. */ static int checkMutexInit(void){ pGlobalMutexMethods = sqlite3DefaultMutex(); return SQLITE_OK; } static int checkMutexEnd(void){ pGlobalMutexMethods = 0; return SQLITE_OK; } /* ** Allocate a mutex. */ static sqlite3_mutex *checkMutexAlloc(int iType){ static CheckMutex staticMutexes[] = { {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}, {10, 0}, {11, 0}, {12, 0}, {13, 0} }; CheckMutex *p = 0; assert( SQLITE_MUTEX_RECURSIVE==1 && SQLITE_MUTEX_FAST==0 ); if( iType<2 ){ p = sqlite3MallocZero(sizeof(CheckMutex)); if( p==0 ) return 0; p->iType = iType; }else{ #ifdef SQLITE_ENABLE_API_ARMOR if( iType-2>=ArraySize(staticMutexes) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif p = &staticMutexes[iType-2]; } if( p->mutex==0 ){ p->mutex = pGlobalMutexMethods->xMutexAlloc(iType); if( p->mutex==0 ){ if( iType<2 ){ sqlite3_free(p); } p = 0; } } return (sqlite3_mutex*)p; } /* ** Free a mutex. */ static void checkMutexFree(sqlite3_mutex *p){ assert( SQLITE_MUTEX_RECURSIVE<2 ); assert( SQLITE_MUTEX_FAST<2 ); assert( SQLITE_MUTEX_WARNONCONTENTION<2 ); #ifdef SQLITE_ENABLE_API_ARMOR if( ((CheckMutex*)p)->iType<2 ) #endif { CheckMutex *pCheck = (CheckMutex*)p; pGlobalMutexMethods->xMutexFree(pCheck->mutex); sqlite3_free(pCheck); } #ifdef SQLITE_ENABLE_API_ARMOR else{ (void)SQLITE_MISUSE_BKPT; } #endif } /* ** Enter the mutex. */ static void checkMutexEnter(sqlite3_mutex *p){ CheckMutex *pCheck = (CheckMutex*)p; if( pCheck->iType==SQLITE_MUTEX_WARNONCONTENTION ){ if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){ return; } sqlite3_log(SQLITE_MISUSE, "illegal multi-threaded access to database connection" ); } pGlobalMutexMethods->xMutexEnter(pCheck->mutex); } /* ** Enter the mutex (do not block). */ static int checkMutexTry(sqlite3_mutex *p){ CheckMutex *pCheck = (CheckMutex*)p; return pGlobalMutexMethods->xMutexTry(pCheck->mutex); } /* ** Leave the mutex. */ static void checkMutexLeave(sqlite3_mutex *p){ CheckMutex *pCheck = (CheckMutex*)p; pGlobalMutexMethods->xMutexLeave(pCheck->mutex); } sqlite3_mutex_methods const *multiThreadedCheckMutex(void){ static const sqlite3_mutex_methods sMutex = { checkMutexInit, checkMutexEnd, checkMutexAlloc, checkMutexFree, checkMutexEnter, checkMutexTry, checkMutexLeave, #ifdef SQLITE_DEBUG checkMutexHeld, checkMutexNotheld #else 0, 0 #endif }; return &sMutex; } /* ** Mark the SQLITE_MUTEX_RECURSIVE mutex passed as the only argument as ** one on which there should be no contention. */ SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex *p){ if( sqlite3GlobalConfig.mutex.xMutexAlloc==checkMutexAlloc ){ CheckMutex *pCheck = (CheckMutex*)p; assert( pCheck->iType==SQLITE_MUTEX_RECURSIVE ); pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION; } } #endif /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */ /* ** Initialize the mutex system. */ SQLITE_PRIVATE int sqlite3MutexInit(void){ int rc = SQLITE_OK; if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){ /* If the xMutexAlloc method has not been set, then the user did not ** install a mutex implementation via sqlite3_config() prior to ** sqlite3_initialize() being called. This block copies pointers to ** the default implementation into the sqlite3GlobalConfig structure. */ sqlite3_mutex_methods const *pFrom; sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex; if( sqlite3GlobalConfig.bCoreMutex ){ #ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS pFrom = multiThreadedCheckMutex(); #else pFrom = sqlite3DefaultMutex(); #endif }else{ pFrom = sqlite3NoopMutex(); } pTo->xMutexInit = pFrom->xMutexInit; pTo->xMutexEnd = pFrom->xMutexEnd; pTo->xMutexFree = pFrom->xMutexFree; pTo->xMutexEnter = pFrom->xMutexEnter; pTo->xMutexTry = pFrom->xMutexTry; pTo->xMutexLeave = pFrom->xMutexLeave; pTo->xMutexHeld = pFrom->xMutexHeld; pTo->xMutexNotheld = pFrom->xMutexNotheld; sqlite3MemoryBarrier(); pTo->xMutexAlloc = pFrom->xMutexAlloc; } assert( sqlite3GlobalConfig.mutex.xMutexInit ); rc = sqlite3GlobalConfig.mutex.xMutexInit(); #ifdef SQLITE_DEBUG GLOBAL(int, mutexIsInit) = 1; #endif sqlite3MemoryBarrier(); return rc; } /* ** Shutdown the mutex system. This call frees resources allocated by ** sqlite3MutexInit(). */ SQLITE_PRIVATE int sqlite3MutexEnd(void){ int rc = SQLITE_OK; if( sqlite3GlobalConfig.mutex.xMutexEnd ){ rc = sqlite3GlobalConfig.mutex.xMutexEnd(); } #ifdef SQLITE_DEBUG GLOBAL(int, mutexIsInit) = 0; #endif return rc; } /* ** Retrieve a pointer to a static mutex or allocate a new dynamic one. */ SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){ #ifndef SQLITE_OMIT_AUTOINIT if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0; if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0; #endif assert( sqlite3GlobalConfig.mutex.xMutexAlloc ); return sqlite3GlobalConfig.mutex.xMutexAlloc(id); } SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){ if( !sqlite3GlobalConfig.bCoreMutex ){ return 0; } assert( GLOBAL(int, mutexIsInit) ); assert( sqlite3GlobalConfig.mutex.xMutexAlloc ); return sqlite3GlobalConfig.mutex.xMutexAlloc(id); } /* ** Free a dynamic mutex. */ SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){ if( p ){ assert( sqlite3GlobalConfig.mutex.xMutexFree ); sqlite3GlobalConfig.mutex.xMutexFree(p); } } /* ** Obtain the mutex p. If some other thread already has the mutex, block ** until it can be obtained. */ SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){ if( p ){ assert( sqlite3GlobalConfig.mutex.xMutexEnter ); sqlite3GlobalConfig.mutex.xMutexEnter(p); } } /* ** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another ** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY. */ SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){ int rc = SQLITE_OK; if( p ){ assert( sqlite3GlobalConfig.mutex.xMutexTry ); return sqlite3GlobalConfig.mutex.xMutexTry(p); } return rc; } /* ** The sqlite3_mutex_leave() routine exits a mutex that was previously ** entered by the same thread. The behavior is undefined if the mutex ** is not currently entered. If a NULL pointer is passed as an argument ** this function is a no-op. */ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){ if( p ){ assert( sqlite3GlobalConfig.mutex.xMutexLeave ); sqlite3GlobalConfig.mutex.xMutexLeave(p); } } #ifndef NDEBUG /* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use inside assert() statements. */ SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){ assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld ); return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p); } SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld ); return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p); } #endif #endif /* !defined(SQLITE_MUTEX_OMIT) */ /************** End of mutex.c ***********************************************/ /************** Begin file mutex_noop.c **************************************/ /* ** 2008 October 07 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement mutexes. ** ** This implementation in this file does not provide any mutual ** exclusion and is thus suitable for use only in applications ** that use SQLite in a single thread. The routines defined ** here are place-holders. Applications can substitute working ** mutex routines at start-time using the ** ** sqlite3_config(SQLITE_CONFIG_MUTEX,...) ** ** interface. ** ** If compiled with SQLITE_DEBUG, then additional logic is inserted ** that does error checking on mutexes to make sure they are being ** called correctly. */ /* #include "sqliteInt.h" */ #ifndef SQLITE_MUTEX_OMIT #ifndef SQLITE_DEBUG /* ** Stub routines for all mutex methods. ** ** This routines provide no mutual exclusion or error checking. */ static int noopMutexInit(void){ return SQLITE_OK; } static int noopMutexEnd(void){ return SQLITE_OK; } static sqlite3_mutex *noopMutexAlloc(int id){ UNUSED_PARAMETER(id); return (sqlite3_mutex*)8; } static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } static int noopMutexTry(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return SQLITE_OK; } static void noopMutexLeave(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){ static const sqlite3_mutex_methods sMutex = { noopMutexInit, noopMutexEnd, noopMutexAlloc, noopMutexFree, noopMutexEnter, noopMutexTry, noopMutexLeave, 0, 0, }; return &sMutex; } #endif /* !SQLITE_DEBUG */ #ifdef SQLITE_DEBUG /* ** In this implementation, error checking is provided for testing ** and debugging purposes. The mutexes still do not provide any ** mutual exclusion. */ /* ** The mutex object */ typedef struct sqlite3_debug_mutex { int id; /* The mutex type */ int cnt; /* Number of entries without a matching leave */ } sqlite3_debug_mutex; /* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use inside assert() statements. */ static int debugMutexHeld(sqlite3_mutex *pX){ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; return p==0 || p->cnt>0; } static int debugMutexNotheld(sqlite3_mutex *pX){ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; return p==0 || p->cnt==0; } /* ** Initialize and deinitialize the mutex subsystem. */ static int debugMutexInit(void){ return SQLITE_OK; } static int debugMutexEnd(void){ return SQLITE_OK; } /* ** The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. If it returns NULL ** that means that a mutex could not be allocated. */ static sqlite3_mutex *debugMutexAlloc(int id){ static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_VFS3 - 1]; sqlite3_debug_mutex *pNew = 0; switch( id ){ case SQLITE_MUTEX_FAST: case SQLITE_MUTEX_RECURSIVE: { pNew = sqlite3Malloc(sizeof(*pNew)); if( pNew ){ pNew->id = id; pNew->cnt = 0; } break; } default: { #ifdef SQLITE_ENABLE_API_ARMOR if( id-2<0 || id-2>=ArraySize(aStatic) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif pNew = &aStatic[id-2]; pNew->id = id; break; } } return (sqlite3_mutex*)pNew; } /* ** This routine deallocates a previously allocated mutex. */ static void debugMutexFree(sqlite3_mutex *pX){ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; assert( p->cnt==0 ); if( p->id==SQLITE_MUTEX_RECURSIVE || p->id==SQLITE_MUTEX_FAST ){ sqlite3_free(p); }else{ #ifdef SQLITE_ENABLE_API_ARMOR (void)SQLITE_MISUSE_BKPT; #endif } } /* ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt ** to enter a mutex. If another thread is already within the mutex, ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can ** be entered multiple times by the same thread. In such cases the, ** mutex must be exited an equal number of times before another thread ** can enter. If the same thread tries to enter any other kind of mutex ** more than once, the behavior is undefined. */ static void debugMutexEnter(sqlite3_mutex *pX){ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) ); p->cnt++; } static int debugMutexTry(sqlite3_mutex *pX){ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) ); p->cnt++; return SQLITE_OK; } /* ** The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. The behavior ** is undefined if the mutex is not currently entered or ** is not currently allocated. SQLite will never do either. */ static void debugMutexLeave(sqlite3_mutex *pX){ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; assert( debugMutexHeld(pX) ); p->cnt--; assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) ); } SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){ static const sqlite3_mutex_methods sMutex = { debugMutexInit, debugMutexEnd, debugMutexAlloc, debugMutexFree, debugMutexEnter, debugMutexTry, debugMutexLeave, debugMutexHeld, debugMutexNotheld }; return &sMutex; } #endif /* SQLITE_DEBUG */ /* ** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation ** is used regardless of the run-time threadsafety setting. */ #ifdef SQLITE_MUTEX_NOOP SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ return sqlite3NoopMutex(); } #endif /* defined(SQLITE_MUTEX_NOOP) */ #endif /* !defined(SQLITE_MUTEX_OMIT) */ /************** End of mutex_noop.c ******************************************/ /************** Begin file mutex_unix.c **************************************/ /* ** 2007 August 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement mutexes for pthreads */ /* #include "sqliteInt.h" */ /* ** The code in this file is only used if we are compiling threadsafe ** under unix with pthreads. ** ** Note that this implementation requires a version of pthreads that ** supports recursive mutexes. */ #ifdef SQLITE_MUTEX_PTHREADS #include /* ** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields ** are necessary under two conditions: (1) Debug builds and (2) using ** home-grown mutexes. Encapsulate these conditions into a single #define. */ #if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX) # define SQLITE_MUTEX_NREF 1 #else # define SQLITE_MUTEX_NREF 0 #endif /* ** Each recursive mutex is an instance of the following structure. */ struct sqlite3_mutex { pthread_mutex_t mutex; /* Mutex controlling the lock */ #if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) int id; /* Mutex type */ #endif #if SQLITE_MUTEX_NREF volatile int nRef; /* Number of entrances */ volatile pthread_t owner; /* Thread that is within this mutex */ int trace; /* True to trace changes */ #endif }; #if SQLITE_MUTEX_NREF # define SQLITE3_MUTEX_INITIALIZER(id) \ {PTHREAD_MUTEX_INITIALIZER,id,0,(pthread_t)0,0} #elif defined(SQLITE_ENABLE_API_ARMOR) # define SQLITE3_MUTEX_INITIALIZER(id) { PTHREAD_MUTEX_INITIALIZER, id } #else #define SQLITE3_MUTEX_INITIALIZER(id) { PTHREAD_MUTEX_INITIALIZER } #endif /* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use only inside assert() statements. On some platforms, ** there might be race conditions that can cause these routines to ** deliver incorrect results. In particular, if pthread_equal() is ** not an atomic operation, then these routines might delivery ** incorrect results. On most platforms, pthread_equal() is a ** comparison of two integers and is therefore atomic. But we are ** told that HPUX is not such a platform. If so, then these routines ** will not always work correctly on HPUX. ** ** On those platforms where pthread_equal() is not atomic, SQLite ** should be compiled without -DSQLITE_DEBUG and with -DNDEBUG to ** make sure no assert() statements are evaluated and hence these ** routines are never called. */ #if !defined(NDEBUG) || defined(SQLITE_DEBUG) static int pthreadMutexHeld(sqlite3_mutex *p){ return (p->nRef!=0 && pthread_equal(p->owner, pthread_self())); } static int pthreadMutexNotheld(sqlite3_mutex *p){ return p->nRef==0 || pthread_equal(p->owner, pthread_self())==0; } #endif /* ** Try to provide a memory barrier operation, needed for initialization ** and also for the implementation of xShmBarrier in the VFS in cases ** where SQLite is compiled without mutexes. */ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ #if defined(SQLITE_MEMORY_BARRIER) SQLITE_MEMORY_BARRIER; #elif defined(__GNUC__) && GCC_VERSION>=4001000 __sync_synchronize(); #endif } /* ** Initialize and deinitialize the mutex subsystem. */ static int pthreadMutexInit(void){ return SQLITE_OK; } static int pthreadMutexEnd(void){ return SQLITE_OK; } /* ** The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. If it returns NULL ** that means that a mutex could not be allocated. SQLite ** will unwind its stack and return an error. The argument ** to sqlite3_mutex_alloc() is one of these integer constants: ** **
    **
  • SQLITE_MUTEX_FAST **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MAIN **
  • SQLITE_MUTEX_STATIC_MEM **
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU **
  • SQLITE_MUTEX_STATIC_PMEM **
  • SQLITE_MUTEX_STATIC_APP1 **
  • SQLITE_MUTEX_STATIC_APP2 **
  • SQLITE_MUTEX_STATIC_APP3 **
  • SQLITE_MUTEX_STATIC_VFS1 **
  • SQLITE_MUTEX_STATIC_VFS2 **
  • SQLITE_MUTEX_STATIC_VFS3 **
** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does ** not want to. But SQLite will only request a recursive mutex in ** cases where it really needs one. If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** The other allowed parameters to sqlite3_mutex_alloc() each return ** a pointer to a static preexisting mutex. Six static mutexes are ** used by the current version of SQLite. Future versions of SQLite ** may add additional static mutexes. Static mutexes are for internal ** use by SQLite only. Applications that use SQLite mutexes should ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or ** SQLITE_MUTEX_RECURSIVE. ** ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() ** returns a different mutex on every call. But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. */ static sqlite3_mutex *pthreadMutexAlloc(int iType){ static sqlite3_mutex staticMutexes[] = { SQLITE3_MUTEX_INITIALIZER(2), SQLITE3_MUTEX_INITIALIZER(3), SQLITE3_MUTEX_INITIALIZER(4), SQLITE3_MUTEX_INITIALIZER(5), SQLITE3_MUTEX_INITIALIZER(6), SQLITE3_MUTEX_INITIALIZER(7), SQLITE3_MUTEX_INITIALIZER(8), SQLITE3_MUTEX_INITIALIZER(9), SQLITE3_MUTEX_INITIALIZER(10), SQLITE3_MUTEX_INITIALIZER(11), SQLITE3_MUTEX_INITIALIZER(12), SQLITE3_MUTEX_INITIALIZER(13) }; sqlite3_mutex *p; switch( iType ){ case SQLITE_MUTEX_RECURSIVE: { p = sqlite3MallocZero( sizeof(*p) ); if( p ){ #ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX /* If recursive mutexes are not available, we will have to ** build our own. See below. */ pthread_mutex_init(&p->mutex, 0); #else /* Use a recursive mutex if it is available */ pthread_mutexattr_t recursiveAttr; pthread_mutexattr_init(&recursiveAttr); pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&p->mutex, &recursiveAttr); pthread_mutexattr_destroy(&recursiveAttr); #endif #if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) p->id = SQLITE_MUTEX_RECURSIVE; #endif } break; } case SQLITE_MUTEX_FAST: { p = sqlite3MallocZero( sizeof(*p) ); if( p ){ pthread_mutex_init(&p->mutex, 0); #if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) p->id = SQLITE_MUTEX_FAST; #endif } break; } default: { #ifdef SQLITE_ENABLE_API_ARMOR if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif p = &staticMutexes[iType-2]; break; } } #if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) assert( p==0 || p->id==iType ); #endif return p; } /* ** This routine deallocates a previously ** allocated mutex. SQLite is careful to deallocate every ** mutex that it allocates. */ static void pthreadMutexFree(sqlite3_mutex *p){ assert( p->nRef==0 ); #ifdef SQLITE_ENABLE_API_ARMOR if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ) #endif { pthread_mutex_destroy(&p->mutex); sqlite3_free(p); } #ifdef SQLITE_ENABLE_API_ARMOR else{ (void)SQLITE_MISUSE_BKPT; } #endif } /* ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt ** to enter a mutex. If another thread is already within the mutex, ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can ** be entered multiple times by the same thread. In such cases the, ** mutex must be exited an equal number of times before another thread ** can enter. If the same thread tries to enter any other kind of mutex ** more than once, the behavior is undefined. */ static void pthreadMutexEnter(sqlite3_mutex *p){ assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) ); #ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX /* If recursive mutexes are not available, then we have to grow ** our own. This implementation assumes that pthread_equal() ** is atomic - that it cannot be deceived into thinking self ** and p->owner are equal if p->owner changes between two values ** that are not equal to self while the comparison is taking place. ** This implementation also assumes a coherent cache - that ** separate processes cannot read different values from the same ** address at the same time. If either of these two conditions ** are not met, then the mutexes will fail and problems will result. */ { pthread_t self = pthread_self(); if( p->nRef>0 && pthread_equal(p->owner, self) ){ p->nRef++; }else{ pthread_mutex_lock(&p->mutex); assert( p->nRef==0 ); p->owner = self; p->nRef = 1; } } #else /* Use the built-in recursive mutexes if they are available. */ pthread_mutex_lock(&p->mutex); #if SQLITE_MUTEX_NREF assert( p->nRef>0 || p->owner==0 ); p->owner = pthread_self(); p->nRef++; #endif #endif #ifdef SQLITE_DEBUG if( p->trace ){ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); } #endif } static int pthreadMutexTry(sqlite3_mutex *p){ int rc; assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) ); #ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX /* If recursive mutexes are not available, then we have to grow ** our own. This implementation assumes that pthread_equal() ** is atomic - that it cannot be deceived into thinking self ** and p->owner are equal if p->owner changes between two values ** that are not equal to self while the comparison is taking place. ** This implementation also assumes a coherent cache - that ** separate processes cannot read different values from the same ** address at the same time. If either of these two conditions ** are not met, then the mutexes will fail and problems will result. */ { pthread_t self = pthread_self(); if( p->nRef>0 && pthread_equal(p->owner, self) ){ p->nRef++; rc = SQLITE_OK; }else if( pthread_mutex_trylock(&p->mutex)==0 ){ assert( p->nRef==0 ); p->owner = self; p->nRef = 1; rc = SQLITE_OK; }else{ rc = SQLITE_BUSY; } } #else /* Use the built-in recursive mutexes if they are available. */ if( pthread_mutex_trylock(&p->mutex)==0 ){ #if SQLITE_MUTEX_NREF p->owner = pthread_self(); p->nRef++; #endif rc = SQLITE_OK; }else{ rc = SQLITE_BUSY; } #endif #ifdef SQLITE_DEBUG if( rc==SQLITE_OK && p->trace ){ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); } #endif return rc; } /* ** The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. The behavior ** is undefined if the mutex is not currently entered or ** is not currently allocated. SQLite will never do either. */ static void pthreadMutexLeave(sqlite3_mutex *p){ assert( pthreadMutexHeld(p) ); #if SQLITE_MUTEX_NREF p->nRef--; if( p->nRef==0 ) p->owner = 0; #endif assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); #ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX if( p->nRef==0 ){ pthread_mutex_unlock(&p->mutex); } #else pthread_mutex_unlock(&p->mutex); #endif #ifdef SQLITE_DEBUG if( p->trace ){ printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); } #endif } SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ static const sqlite3_mutex_methods sMutex = { pthreadMutexInit, pthreadMutexEnd, pthreadMutexAlloc, pthreadMutexFree, pthreadMutexEnter, pthreadMutexTry, pthreadMutexLeave, #ifdef SQLITE_DEBUG pthreadMutexHeld, pthreadMutexNotheld #else 0, 0 #endif }; return &sMutex; } #endif /* SQLITE_MUTEX_PTHREADS */ /************** End of mutex_unix.c ******************************************/ /************** Begin file mutex_w32.c ***************************************/ /* ** 2007 August 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement mutexes for Win32. */ /* #include "sqliteInt.h" */ #if SQLITE_OS_WIN /* ** Include code that is common to all os_*.c files */ /* #include "os_common.h" */ /* ** Include the header file for the Windows VFS. */ /************** Include os_win.h in the middle of mutex_w32.c ****************/ /************** Begin file os_win.h ******************************************/ /* ** 2013 November 25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to Windows. */ #ifndef SQLITE_OS_WIN_H #define SQLITE_OS_WIN_H /* ** Include the primary Windows SDK header file. */ #include "windows.h" #ifdef __CYGWIN__ # include # include /* amalgamator: dontcache */ #endif /* ** Determine if we are dealing with Windows NT. ** ** We ought to be able to determine if we are compiling for Windows 9x or ** Windows NT using the _WIN32_WINNT macro as follows: ** ** #if defined(_WIN32_WINNT) ** # define SQLITE_OS_WINNT 1 ** #else ** # define SQLITE_OS_WINNT 0 ** #endif ** ** However, Visual Studio 2005 does not set _WIN32_WINNT by default, as ** it ought to, so the above test does not work. We'll just assume that ** everything is Windows NT unless the programmer explicitly says otherwise ** by setting SQLITE_OS_WINNT to 0. */ #if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) # define SQLITE_OS_WINNT 1 #endif /* ** Determine if we are dealing with Windows CE - which has a much reduced ** API. */ #if defined(_WIN32_WCE) # define SQLITE_OS_WINCE 1 #else # define SQLITE_OS_WINCE 0 #endif /* ** Determine if we are dealing with WinRT, which provides only a subset of ** the full Win32 API. */ #if !defined(SQLITE_OS_WINRT) # define SQLITE_OS_WINRT 0 #endif /* ** For WinCE, some API function parameters do not appear to be declared as ** volatile. */ #if SQLITE_OS_WINCE # define SQLITE_WIN32_VOLATILE #else # define SQLITE_WIN32_VOLATILE volatile #endif /* ** For some Windows sub-platforms, the _beginthreadex() / _endthreadex() ** functions are not available (e.g. those not using MSVC, Cygwin, etc). */ #if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ SQLITE_THREADSAFE>0 && !defined(__CYGWIN__) # define SQLITE_OS_WIN_THREADS 1 #else # define SQLITE_OS_WIN_THREADS 0 #endif #endif /* SQLITE_OS_WIN_H */ /************** End of os_win.h **********************************************/ /************** Continuing where we left off in mutex_w32.c ******************/ #endif /* ** The code in this file is only used if we are compiling multithreaded ** on a Win32 system. */ #ifdef SQLITE_MUTEX_W32 /* ** Each recursive mutex is an instance of the following structure. */ struct sqlite3_mutex { CRITICAL_SECTION mutex; /* Mutex controlling the lock */ int id; /* Mutex type */ #ifdef SQLITE_DEBUG volatile int nRef; /* Number of entrances */ volatile DWORD owner; /* Thread holding this mutex */ volatile LONG trace; /* True to trace changes */ #endif }; /* ** These are the initializer values used when declaring a "static" mutex ** on Win32. It should be noted that all mutexes require initialization ** on the Win32 platform. */ #define SQLITE_W32_MUTEX_INITIALIZER { 0 } #ifdef SQLITE_DEBUG #define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id, \ 0L, (DWORD)0, 0 } #else #define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id } #endif #ifdef SQLITE_DEBUG /* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use only inside assert() statements. */ static int winMutexHeld(sqlite3_mutex *p){ return p->nRef!=0 && p->owner==GetCurrentThreadId(); } static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){ return p->nRef==0 || p->owner!=tid; } static int winMutexNotheld(sqlite3_mutex *p){ DWORD tid = GetCurrentThreadId(); return winMutexNotheld2(p, tid); } #endif /* ** Try to provide a memory barrier operation, needed for initialization ** and also for the xShmBarrier method of the VFS in cases when SQLite is ** compiled without mutexes (SQLITE_THREADSAFE=0). */ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ #if defined(SQLITE_MEMORY_BARRIER) SQLITE_MEMORY_BARRIER; #elif defined(__GNUC__) __sync_synchronize(); #elif MSVC_VERSION>=1400 _ReadWriteBarrier(); #elif defined(MemoryBarrier) MemoryBarrier(); #endif } /* ** Initialize and deinitialize the mutex subsystem. */ static sqlite3_mutex winMutex_staticMutexes[] = { SQLITE3_MUTEX_INITIALIZER(2), SQLITE3_MUTEX_INITIALIZER(3), SQLITE3_MUTEX_INITIALIZER(4), SQLITE3_MUTEX_INITIALIZER(5), SQLITE3_MUTEX_INITIALIZER(6), SQLITE3_MUTEX_INITIALIZER(7), SQLITE3_MUTEX_INITIALIZER(8), SQLITE3_MUTEX_INITIALIZER(9), SQLITE3_MUTEX_INITIALIZER(10), SQLITE3_MUTEX_INITIALIZER(11), SQLITE3_MUTEX_INITIALIZER(12), SQLITE3_MUTEX_INITIALIZER(13) }; static int winMutex_isInit = 0; static int winMutex_isNt = -1; /* <0 means "need to query" */ /* As the winMutexInit() and winMutexEnd() functions are called as part ** of the sqlite3_initialize() and sqlite3_shutdown() processing, the ** "interlocked" magic used here is probably not strictly necessary. */ static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0; SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ static int winMutexInit(void){ /* The first to increment to 1 does actual initialization */ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ int i; for(i=0; i **
  • SQLITE_MUTEX_FAST **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MAIN **
  • SQLITE_MUTEX_STATIC_MEM **
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU **
  • SQLITE_MUTEX_STATIC_PMEM **
  • SQLITE_MUTEX_STATIC_APP1 **
  • SQLITE_MUTEX_STATIC_APP2 **
  • SQLITE_MUTEX_STATIC_APP3 **
  • SQLITE_MUTEX_STATIC_VFS1 **
  • SQLITE_MUTEX_STATIC_VFS2 **
  • SQLITE_MUTEX_STATIC_VFS3 ** ** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does ** not want to. But SQLite will only request a recursive mutex in ** cases where it really needs one. If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** The other allowed parameters to sqlite3_mutex_alloc() each return ** a pointer to a static preexisting mutex. Six static mutexes are ** used by the current version of SQLite. Future versions of SQLite ** may add additional static mutexes. Static mutexes are for internal ** use by SQLite only. Applications that use SQLite mutexes should ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or ** SQLITE_MUTEX_RECURSIVE. ** ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() ** returns a different mutex on every call. But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. */ static sqlite3_mutex *winMutexAlloc(int iType){ sqlite3_mutex *p; switch( iType ){ case SQLITE_MUTEX_FAST: case SQLITE_MUTEX_RECURSIVE: { p = sqlite3MallocZero( sizeof(*p) ); if( p ){ p->id = iType; #ifdef SQLITE_DEBUG #ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC p->trace = 1; #endif #endif #if SQLITE_OS_WINRT InitializeCriticalSectionEx(&p->mutex, 0, 0); #else InitializeCriticalSection(&p->mutex); #endif } break; } default: { #ifdef SQLITE_ENABLE_API_ARMOR if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif p = &winMutex_staticMutexes[iType-2]; #ifdef SQLITE_DEBUG #ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC InterlockedCompareExchange(&p->trace, 1, 0); #endif #endif break; } } assert( p==0 || p->id==iType ); return p; } /* ** This routine deallocates a previously ** allocated mutex. SQLite is careful to deallocate every ** mutex that it allocates. */ static void winMutexFree(sqlite3_mutex *p){ assert( p ); assert( p->nRef==0 && p->owner==0 ); if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){ DeleteCriticalSection(&p->mutex); sqlite3_free(p); }else{ #ifdef SQLITE_ENABLE_API_ARMOR (void)SQLITE_MISUSE_BKPT; #endif } } /* ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt ** to enter a mutex. If another thread is already within the mutex, ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can ** be entered multiple times by the same thread. In such cases the, ** mutex must be exited an equal number of times before another thread ** can enter. If the same thread tries to enter any other kind of mutex ** more than once, the behavior is undefined. */ static void winMutexEnter(sqlite3_mutex *p){ #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) DWORD tid = GetCurrentThreadId(); #endif #ifdef SQLITE_DEBUG assert( p ); assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); #else assert( p ); #endif assert( winMutex_isInit==1 ); EnterCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG assert( p->nRef>0 || p->owner==0 ); p->owner = tid; p->nRef++; if( p->trace ){ OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n", tid, p->id, p, p->trace, p->nRef)); } #endif } static int winMutexTry(sqlite3_mutex *p){ #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) DWORD tid = GetCurrentThreadId(); #endif int rc = SQLITE_BUSY; assert( p ); assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); /* ** The sqlite3_mutex_try() routine is very rarely used, and when it ** is used it is merely an optimization. So it is OK for it to always ** fail. ** ** The TryEnterCriticalSection() interface is only available on WinNT. ** And some windows compilers complain if you try to use it without ** first doing some #defines that prevent SQLite from building on Win98. ** For that reason, we will omit this optimization for now. See ** ticket #2685. */ #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 assert( winMutex_isInit==1 ); assert( winMutex_isNt>=-1 && winMutex_isNt<=1 ); if( winMutex_isNt<0 ){ winMutex_isNt = sqlite3_win32_is_nt(); } assert( winMutex_isNt==0 || winMutex_isNt==1 ); if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){ #ifdef SQLITE_DEBUG p->owner = tid; p->nRef++; #endif rc = SQLITE_OK; } #else UNUSED_PARAMETER(p); #endif #ifdef SQLITE_DEBUG if( p->trace ){ OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n", tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); } #endif return rc; } /* ** The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. The behavior ** is undefined if the mutex is not currently entered or ** is not currently allocated. SQLite will never do either. */ static void winMutexLeave(sqlite3_mutex *p){ #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) DWORD tid = GetCurrentThreadId(); #endif assert( p ); #ifdef SQLITE_DEBUG assert( p->nRef>0 ); assert( p->owner==tid ); p->nRef--; if( p->nRef==0 ) p->owner = 0; assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); #endif assert( winMutex_isInit==1 ); LeaveCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG if( p->trace ){ OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n", tid, p->id, p, p->trace, p->nRef)); } #endif } SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ static const sqlite3_mutex_methods sMutex = { winMutexInit, winMutexEnd, winMutexAlloc, winMutexFree, winMutexEnter, winMutexTry, winMutexLeave, #ifdef SQLITE_DEBUG winMutexHeld, winMutexNotheld #else 0, 0 #endif }; return &sMutex; } #endif /* SQLITE_MUTEX_W32 */ /************** End of mutex_w32.c *******************************************/ /************** Begin file malloc.c ******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** Memory allocation functions used throughout sqlite. */ /* #include "sqliteInt.h" */ /* #include */ /* ** Attempt to release up to n bytes of non-essential memory currently ** held by SQLite. An example of non-essential memory is memory used to ** cache database pages that are not currently in use. */ SQLITE_API int sqlite3_release_memory(int n){ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT return sqlite3PcacheReleaseMemory(n); #else /* IMPLEMENTATION-OF: R-34391-24921 The sqlite3_release_memory() routine ** is a no-op returning zero if SQLite is not compiled with ** SQLITE_ENABLE_MEMORY_MANAGEMENT. */ UNUSED_PARAMETER(n); return 0; #endif } /* ** Default value of the hard heap limit. 0 means "no limit". */ #ifndef SQLITE_MAX_MEMORY # define SQLITE_MAX_MEMORY 0 #endif /* ** State information local to the memory allocation subsystem. */ static SQLITE_WSD struct Mem0Global { sqlite3_mutex *mutex; /* Mutex to serialize access */ sqlite3_int64 alarmThreshold; /* The soft heap limit */ sqlite3_int64 hardLimit; /* The hard upper bound on memory */ /* ** True if heap is nearly "full" where "full" is defined by the ** sqlite3_soft_heap_limit() setting. */ int nearlyFull; } mem0 = { 0, SQLITE_MAX_MEMORY, SQLITE_MAX_MEMORY, 0 }; #define mem0 GLOBAL(struct Mem0Global, mem0) /* ** Return the memory allocator mutex. sqlite3_status() needs it. */ SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){ return mem0.mutex; } #ifndef SQLITE_OMIT_DEPRECATED /* ** Deprecated external interface. It used to set an alarm callback ** that was invoked when memory usage grew too large. Now it is a ** no-op. */ SQLITE_API int sqlite3_memory_alarm( void(*xCallback)(void *pArg, sqlite3_int64 used,int N), void *pArg, sqlite3_int64 iThreshold ){ (void)xCallback; (void)pArg; (void)iThreshold; return SQLITE_OK; } #endif /* ** Set the soft heap-size limit for the library. An argument of ** zero disables the limit. A negative argument is a no-op used to ** obtain the return value. ** ** The return value is the value of the heap limit just before this ** interface was called. ** ** If the hard heap limit is enabled, then the soft heap limit cannot ** be disabled nor raised above the hard heap limit. */ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){ sqlite3_int64 priorLimit; sqlite3_int64 excess; sqlite3_int64 nUsed; #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return -1; #endif sqlite3_mutex_enter(mem0.mutex); priorLimit = mem0.alarmThreshold; if( n<0 ){ sqlite3_mutex_leave(mem0.mutex); return priorLimit; } if( mem0.hardLimit>0 && (n>mem0.hardLimit || n==0) ){ n = mem0.hardLimit; } mem0.alarmThreshold = n; nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); AtomicStore(&mem0.nearlyFull, n>0 && n<=nUsed); sqlite3_mutex_leave(mem0.mutex); excess = sqlite3_memory_used() - n; if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff)); return priorLimit; } SQLITE_API void sqlite3_soft_heap_limit(int n){ if( n<0 ) n = 0; sqlite3_soft_heap_limit64(n); } /* ** Set the hard heap-size limit for the library. An argument of zero ** disables the hard heap limit. A negative argument is a no-op used ** to obtain the return value without affecting the hard heap limit. ** ** The return value is the value of the hard heap limit just prior to ** calling this interface. ** ** Setting the hard heap limit will also activate the soft heap limit ** and constrain the soft heap limit to be no more than the hard heap ** limit. */ SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 n){ sqlite3_int64 priorLimit; #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return -1; #endif sqlite3_mutex_enter(mem0.mutex); priorLimit = mem0.hardLimit; if( n>=0 ){ mem0.hardLimit = n; if( n0 ); /* In Firefox (circa 2017-02-08), xRoundup() is remapped to an internal ** implementation of malloc_good_size(), which must be called in debug ** mode and specifically when the DMD "Dark Matter Detector" is enabled ** or else a crash results. Hence, do not attempt to optimize out the ** following xRoundup() call. */ nFull = sqlite3GlobalConfig.m.xRoundup(n); sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n); if( mem0.alarmThreshold>0 ){ sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed >= mem0.alarmThreshold - nFull ){ AtomicStore(&mem0.nearlyFull, 1); sqlite3MallocAlarm(nFull); if( mem0.hardLimit ){ nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed >= mem0.hardLimit - nFull ){ *pp = 0; return; } } }else{ AtomicStore(&mem0.nearlyFull, 0); } } p = sqlite3GlobalConfig.m.xMalloc(nFull); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( p==0 && mem0.alarmThreshold>0 ){ sqlite3MallocAlarm(nFull); p = sqlite3GlobalConfig.m.xMalloc(nFull); } #endif if( p ){ nFull = sqlite3MallocSize(p); sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull); sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1); } *pp = p; } /* ** Maximum size of any single memory allocation. ** ** This is not a limit on the total amount of memory used. This is ** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc(). ** ** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391 ** This provides a 256-byte safety margin for defense against 32-bit ** signed integer overflow bugs when computing memory allocation sizes. ** Paranoid applications might want to reduce the maximum allocation size ** further for an even larger safety margin. 0x3fffffff or 0x0fffffff ** or even smaller would be reasonable upper bounds on the size of a memory ** allocations for most applications. */ #ifndef SQLITE_MAX_ALLOCATION_SIZE # define SQLITE_MAX_ALLOCATION_SIZE 2147483391 #endif #if SQLITE_MAX_ALLOCATION_SIZE>2147483391 # error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391 #endif /* ** Allocate memory. This routine is like sqlite3_malloc() except that it ** assumes the memory subsystem has already been initialized. */ SQLITE_PRIVATE void *sqlite3Malloc(u64 n){ void *p; if( n==0 || n>SQLITE_MAX_ALLOCATION_SIZE ){ p = 0; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); mallocWithAlarm((int)n, &p); sqlite3_mutex_leave(mem0.mutex); }else{ p = sqlite3GlobalConfig.m.xMalloc((int)n); } assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-11148-40995 */ return p; } /* ** This version of the memory allocation is for use by the application. ** First make sure the memory subsystem is initialized, then do the ** allocation. */ SQLITE_API void *sqlite3_malloc(int n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return n<=0 ? 0 : sqlite3Malloc(n); } SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return sqlite3Malloc(n); } /* ** TRUE if p is a lookaside memory allocation from db */ #ifndef SQLITE_OMIT_LOOKASIDE static int isLookaside(sqlite3 *db, const void *p){ return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pTrueEnd); } #else #define isLookaside(A,B) 0 #endif /* ** Return the size of a memory allocation previously obtained from ** sqlite3Malloc() or sqlite3_malloc(). */ SQLITE_PRIVATE int sqlite3MallocSize(const void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return sqlite3GlobalConfig.m.xSize((void*)p); } static int lookasideMallocSize(sqlite3 *db, const void *p){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE return plookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL; #else return db->lookaside.szTrue; #endif } SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, const void *p){ assert( p!=0 ); #ifdef SQLITE_DEBUG if( db==0 ){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); }else if( !isLookaside(db,p) ){ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); } #endif if( db ){ if( ((uptr)p)<(uptr)(db->lookaside.pTrueEnd) ){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){ assert( sqlite3_mutex_held(db->mutex) ); return LOOKASIDE_SMALL; } #endif if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){ assert( sqlite3_mutex_held(db->mutex) ); return db->lookaside.szTrue; } } } return sqlite3GlobalConfig.m.xSize((void*)p); } SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return p ? sqlite3GlobalConfig.m.xSize(p) : 0; } /* ** Free memory previously obtained from sqlite3Malloc(). */ SQLITE_API void sqlite3_free(void *p){ if( p==0 ) return; /* IMP: R-49053-54554 */ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, sqlite3MallocSize(p)); sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1); sqlite3GlobalConfig.m.xFree(p); sqlite3_mutex_leave(mem0.mutex); }else{ sqlite3GlobalConfig.m.xFree(p); } } /* ** Add the size of memory allocation "p" to the count in ** *db->pnBytesFreed. */ static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){ *db->pnBytesFreed += sqlite3DbMallocSize(db,p); } /* ** Free memory that might be associated with a particular database ** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op. ** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL. */ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); assert( p!=0 ); if( db ){ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){ LookasideSlot *pBuf = (LookasideSlot*)p; assert( db->pnBytesFreed==0 ); #ifdef SQLITE_DEBUG memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */ #endif pBuf->pNext = db->lookaside.pSmallFree; db->lookaside.pSmallFree = pBuf; return; } #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){ LookasideSlot *pBuf = (LookasideSlot*)p; assert( db->pnBytesFreed==0 ); #ifdef SQLITE_DEBUG memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */ #endif pBuf->pNext = db->lookaside.pFree; db->lookaside.pFree = pBuf; return; } } if( db->pnBytesFreed ){ measureAllocationSize(db, p); return; } } assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); } SQLITE_PRIVATE void sqlite3DbNNFreeNN(sqlite3 *db, void *p){ assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); assert( p!=0 ); if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){ LookasideSlot *pBuf = (LookasideSlot*)p; assert( db->pnBytesFreed==0 ); #ifdef SQLITE_DEBUG memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */ #endif pBuf->pNext = db->lookaside.pSmallFree; db->lookaside.pSmallFree = pBuf; return; } #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){ LookasideSlot *pBuf = (LookasideSlot*)p; assert( db->pnBytesFreed==0 ); #ifdef SQLITE_DEBUG memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */ #endif pBuf->pNext = db->lookaside.pFree; db->lookaside.pFree = pBuf; return; } } if( db->pnBytesFreed ){ measureAllocationSize(db, p); return; } assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); } SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); if( p ) sqlite3DbFreeNN(db, p); } /* ** Change the size of an existing memory allocation */ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ int nOld, nNew, nDiff; void *pNew; assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); assert( sqlite3MemdebugNoType(pOld, (u8)~MEMTYPE_HEAP) ); if( pOld==0 ){ return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */ } if( nBytes==0 ){ sqlite3_free(pOld); /* IMP: R-26507-47431 */ return 0; } if( nBytes>=0x7fffff00 ){ /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */ return 0; } nOld = sqlite3MallocSize(pOld); /* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second ** argument to xRealloc is always a value returned by a prior call to ** xRoundup. */ nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes); if( nOld==nNew ){ pNew = pOld; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_int64 nUsed; sqlite3_mutex_enter(mem0.mutex); sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); nDiff = nNew - nOld; if( nDiff>0 && (nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){ sqlite3_mutex_leave(mem0.mutex); return 0; } } pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( pNew==0 && mem0.alarmThreshold>0 ){ sqlite3MallocAlarm((int)nBytes); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } #endif if( pNew ){ nNew = sqlite3MallocSize(pNew); sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld); } sqlite3_mutex_leave(mem0.mutex); }else{ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-11148-40995 */ return pNew; } /* ** The public interface to sqlite3Realloc. Make sure that the memory ** subsystem is initialized prior to invoking sqliteRealloc. */ SQLITE_API void *sqlite3_realloc(void *pOld, int n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif if( n<0 ) n = 0; /* IMP: R-26507-47431 */ return sqlite3Realloc(pOld, n); } SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return sqlite3Realloc(pOld, n); } /* ** Allocate and zero memory. */ SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){ void *p = sqlite3Malloc(n); if( p ){ memset(p, 0, (size_t)n); } return p; } /* ** Allocate and zero memory. If the allocation fails, make ** the mallocFailed flag in the connection pointer. */ SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){ void *p; testcase( db==0 ); p = sqlite3DbMallocRaw(db, n); if( p ) memset(p, 0, (size_t)n); return p; } /* Finish the work of sqlite3DbMallocRawNN for the unusual and ** slower case when the allocation cannot be fulfilled using lookaside. */ static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){ void *p; assert( db!=0 ); p = sqlite3Malloc(n); if( !p ) sqlite3OomFault(db); sqlite3MemdebugSetType(p, (db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); return p; } /* ** Allocate memory, either lookaside (if possible) or heap. ** If the allocation fails, set the mallocFailed flag in ** the connection pointer. ** ** If db!=0 and db->mallocFailed is true (indicating a prior malloc ** failure on the same database connection) then always return 0. ** Hence for a particular database connection, once malloc starts ** failing, it fails consistently until mallocFailed is reset. ** This is an important assumption. There are many places in the ** code that do things like this: ** ** int *a = (int*)sqlite3DbMallocRaw(db, 100); ** int *b = (int*)sqlite3DbMallocRaw(db, 200); ** if( b ) a[10] = 9; ** ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed ** that all prior mallocs (ex: "a") worked too. ** ** The sqlite3MallocRawNN() variant guarantees that the "db" parameter is ** not a NULL pointer. */ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){ void *p; if( db ) return sqlite3DbMallocRawNN(db, n); p = sqlite3Malloc(n); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); return p; } SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){ #ifndef SQLITE_OMIT_LOOKASIDE LookasideSlot *pBuf; assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); assert( db->pnBytesFreed==0 ); if( n>db->lookaside.sz ){ if( !db->lookaside.bDisable ){ db->lookaside.anStat[1]++; }else if( db->mallocFailed ){ return 0; } return dbMallocRawFinish(db, n); } #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( n<=LOOKASIDE_SMALL ){ if( (pBuf = db->lookaside.pSmallFree)!=0 ){ db->lookaside.pSmallFree = pBuf->pNext; db->lookaside.anStat[0]++; return (void*)pBuf; }else if( (pBuf = db->lookaside.pSmallInit)!=0 ){ db->lookaside.pSmallInit = pBuf->pNext; db->lookaside.anStat[0]++; return (void*)pBuf; } } #endif if( (pBuf = db->lookaside.pFree)!=0 ){ db->lookaside.pFree = pBuf->pNext; db->lookaside.anStat[0]++; return (void*)pBuf; }else if( (pBuf = db->lookaside.pInit)!=0 ){ db->lookaside.pInit = pBuf->pNext; db->lookaside.anStat[0]++; return (void*)pBuf; }else{ db->lookaside.anStat[2]++; } #else assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); assert( db->pnBytesFreed==0 ); if( db->mallocFailed ){ return 0; } #endif return dbMallocRawFinish(db, n); } /* Forward declaration */ static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n); /* ** Resize the block of memory pointed to by p to n bytes. If the ** resize fails, set the mallocFailed flag in the connection object. */ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ assert( db!=0 ); if( p==0 ) return sqlite3DbMallocRawNN(db, n); assert( sqlite3_mutex_held(db->mutex) ); if( ((uptr)p)<(uptr)db->lookaside.pEnd ){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( ((uptr)p)>=(uptr)db->lookaside.pMiddle ){ if( n<=LOOKASIDE_SMALL ) return p; }else #endif if( ((uptr)p)>=(uptr)db->lookaside.pStart ){ if( n<=db->lookaside.szTrue ) return p; } } return dbReallocFinish(db, p, n); } static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){ void *pNew = 0; assert( db!=0 ); assert( p!=0 ); if( db->mallocFailed==0 ){ if( isLookaside(db, p) ){ pNew = sqlite3DbMallocRawNN(db, n); if( pNew ){ memcpy(pNew, p, lookasideMallocSize(db, p)); sqlite3DbFree(db, p); } }else{ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); pNew = sqlite3Realloc(p, n); if( !pNew ){ sqlite3OomFault(db); } sqlite3MemdebugSetType(pNew, (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); } } return pNew; } /* ** Attempt to reallocate p. If the reallocation fails, then free p ** and set the mallocFailed flag in the database connection. */ SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){ void *pNew; pNew = sqlite3DbRealloc(db, p, n); if( !pNew ){ sqlite3DbFree(db, p); } return pNew; } /* ** Make a copy of a string in memory obtained from sqliteMalloc(). These ** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This ** is because when memory debugging is turned on, these two functions are ** called via macros that record the current file and line number in the ** ThreadData structure. */ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){ char *zNew; size_t n; if( z==0 ){ return 0; } n = strlen(z) + 1; zNew = sqlite3DbMallocRaw(db, n); if( zNew ){ memcpy(zNew, z, n); } return zNew; } SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ char *zNew; assert( db!=0 ); assert( z!=0 || n==0 ); assert( (n&0x7fffffff)==n ); zNew = z ? sqlite3DbMallocRawNN(db, n+1) : 0; if( zNew ){ memcpy(zNew, z, (size_t)n); zNew[n] = 0; } return zNew; } /* ** The text between zStart and zEnd represents a phrase within a larger ** SQL statement. Make a copy of this phrase in space obtained form ** sqlite3DbMalloc(). Omit leading and trailing whitespace. */ SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){ int n; #ifdef SQLITE_DEBUG /* Because of the way the parser works, the span is guaranteed to contain ** at least one non-space character */ for(n=0; sqlite3Isspace(zStart[n]); n++){ assert( &zStart[n]mallocFailed, and also ** temporarily disable the lookaside memory allocator and interrupt ** any running VDBEs. ** ** Always return a NULL pointer so that this routine can be invoked using ** ** return sqlite3OomFault(db); ** ** and thereby avoid unnecessary stack frame allocations for the overwhelmingly ** common case where no OOM occurs. */ SQLITE_PRIVATE void *sqlite3OomFault(sqlite3 *db){ if( db->mallocFailed==0 && db->bBenignMalloc==0 ){ db->mallocFailed = 1; if( db->nVdbeExec>0 ){ AtomicStore(&db->u1.isInterrupted, 1); } DisableLookaside; if( db->pParse ){ Parse *pParse; sqlite3ErrorMsg(db->pParse, "out of memory"); db->pParse->rc = SQLITE_NOMEM_BKPT; for(pParse=db->pParse->pOuterParse; pParse; pParse = pParse->pOuterParse){ pParse->nErr++; pParse->rc = SQLITE_NOMEM; } } } return 0; } /* ** This routine reactivates the memory allocator and clears the ** db->mallocFailed flag as necessary. ** ** The memory allocator is not restarted if there are running ** VDBEs. */ SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){ if( db->mallocFailed && db->nVdbeExec==0 ){ db->mallocFailed = 0; AtomicStore(&db->u1.isInterrupted, 0); assert( db->lookaside.bDisable>0 ); EnableLookaside; } } /* ** Take actions at the end of an API call to deal with error codes. */ static SQLITE_NOINLINE int apiHandleError(sqlite3 *db, int rc){ if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomClear(db); sqlite3Error(db, SQLITE_NOMEM); return SQLITE_NOMEM_BKPT; } return rc & db->errMask; } /* ** This function must be called before exiting any API function (i.e. ** returning control to the user) that has called sqlite3_malloc or ** sqlite3_realloc. ** ** The returned value is normally a copy of the second argument to this ** function. However, if a malloc() failure has occurred since the previous ** invocation SQLITE_NOMEM is returned instead. ** ** If an OOM as occurred, then the connection error-code (the value ** returned by sqlite3_errcode()) is set to SQLITE_NOMEM. */ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ /* If the db handle must hold the connection handle mutex here. ** Otherwise the read (and possible write) of db->mallocFailed ** is unsafe, as is the call to sqlite3Error(). */ assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); if( db->mallocFailed || rc ){ return apiHandleError(db, rc); } return 0; } /************** End of malloc.c **********************************************/ /************** Begin file printf.c ******************************************/ /* ** The "printf" code that follows dates from the 1980's. It is in ** the public domain. ** ************************************************************************** ** ** This file contains code for a set of "printf"-like routines. These ** routines format strings much like the printf() from the standard C ** library, though the implementation here has enhancements to support ** SQLite. */ /* #include "sqliteInt.h" */ /* ** Conversion types fall into various categories as defined by the ** following enumeration. */ #define etRADIX 0 /* non-decimal integer types. %x %o */ #define etFLOAT 1 /* Floating point. %f */ #define etEXP 2 /* Exponentional notation. %e and %E */ #define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */ #define etSIZE 4 /* Return number of characters processed so far. %n */ #define etSTRING 5 /* Strings. %s */ #define etDYNSTRING 6 /* Dynamically allocated strings. %z */ #define etPERCENT 7 /* Percent symbol. %% */ #define etCHARX 8 /* Characters. %c */ /* The rest are extensions, not normally found in printf() */ #define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */ #define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', NULL pointers replaced by SQL NULL. %Q */ #define etTOKEN 11 /* a pointer to a Token structure */ #define etSRCITEM 12 /* a pointer to a SrcItem */ #define etPOINTER 13 /* The %p conversion */ #define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ #define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ #define etDECIMAL 16 /* %d or %u, but not %x, %o */ #define etINVALID 17 /* Any unrecognized conversion type */ /* ** An "etByte" is an 8-bit unsigned value. */ typedef unsigned char etByte; /* ** Each builtin conversion character (ex: the 'd' in "%d") is described ** by an instance of the following structure */ typedef struct et_info { /* Information about each format field */ char fmttype; /* The format field code letter */ etByte base; /* The base for radix conversion */ etByte flags; /* One or more of FLAG_ constants below */ etByte type; /* Conversion paradigm */ etByte charset; /* Offset into aDigits[] of the digits string */ etByte prefix; /* Offset into aPrefix[] of the prefix string */ } et_info; /* ** Allowed values for et_info.flags */ #define FLAG_SIGNED 1 /* True if the value to convert is signed */ #define FLAG_STRING 4 /* Allow infinite precision */ /* ** The following table is searched linearly, so it is good to put the ** most frequently used conversion types first. */ static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; static const char aPrefix[] = "-x0\000X0"; static const et_info fmtinfo[] = { { 'd', 10, 1, etDECIMAL, 0, 0 }, { 's', 0, 4, etSTRING, 0, 0 }, { 'g', 0, 1, etGENERIC, 30, 0 }, { 'z', 0, 4, etDYNSTRING, 0, 0 }, { 'q', 0, 4, etSQLESCAPE, 0, 0 }, { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, { 'c', 0, 0, etCHARX, 0, 0 }, { 'o', 8, 0, etRADIX, 0, 2 }, { 'u', 10, 0, etDECIMAL, 0, 0 }, { 'x', 16, 0, etRADIX, 16, 1 }, { 'X', 16, 0, etRADIX, 0, 4 }, #ifndef SQLITE_OMIT_FLOATING_POINT { 'f', 0, 1, etFLOAT, 0, 0 }, { 'e', 0, 1, etEXP, 30, 0 }, { 'E', 0, 1, etEXP, 14, 0 }, { 'G', 0, 1, etGENERIC, 14, 0 }, #endif { 'i', 10, 1, etDECIMAL, 0, 0 }, { 'n', 0, 0, etSIZE, 0, 0 }, { '%', 0, 0, etPERCENT, 0, 0 }, { 'p', 16, 0, etPOINTER, 0, 1 }, /* All the rest are undocumented and are for internal use only */ { 'T', 0, 0, etTOKEN, 0, 0 }, { 'S', 0, 0, etSRCITEM, 0, 0 }, { 'r', 10, 1, etORDINAL, 0, 0 }, }; /* Notes: ** ** %S Takes a pointer to SrcItem. Shows name or database.name ** %!S Like %S but prefer the zName over the zAlias */ /* ** Set the StrAccum object to an error mode. */ SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum *p, u8 eError){ assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); p->accError = eError; if( p->mxAlloc ) sqlite3_str_reset(p); if( eError==SQLITE_TOOBIG ) sqlite3ErrorToParser(p->db, eError); } /* ** Extra argument values from a PrintfArguments object */ static sqlite3_int64 getIntArg(PrintfArguments *p){ if( p->nArg<=p->nUsed ) return 0; return sqlite3_value_int64(p->apArg[p->nUsed++]); } static double getDoubleArg(PrintfArguments *p){ if( p->nArg<=p->nUsed ) return 0.0; return sqlite3_value_double(p->apArg[p->nUsed++]); } static char *getTextArg(PrintfArguments *p){ if( p->nArg<=p->nUsed ) return 0; return (char*)sqlite3_value_text(p->apArg[p->nUsed++]); } /* ** Allocate memory for a temporary buffer needed for printf rendering. ** ** If the requested size of the temp buffer is larger than the size ** of the output buffer in pAccum, then cause an SQLITE_TOOBIG error. ** Do the size check before the memory allocation to prevent rogue ** SQL from requesting large allocations using the precision or width ** field of the printf() function. */ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){ char *z; if( pAccum->accError ) return 0; if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){ sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG); return 0; } z = sqlite3DbMallocRaw(pAccum->db, n); if( z==0 ){ sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM); } return z; } /* ** On machines with a small stack size, you can redefine the ** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired. */ #ifndef SQLITE_PRINT_BUF_SIZE # define SQLITE_PRINT_BUF_SIZE 70 #endif #define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ /* ** Hard limit on the precision of floating-point conversions. */ #ifndef SQLITE_PRINTF_PRECISION_LIMIT # define SQLITE_FP_PRECISION_LIMIT 100000000 #endif /* ** Render a string given by "fmt" into the StrAccum object. */ SQLITE_API void sqlite3_str_vappendf( sqlite3_str *pAccum, /* Accumulate results here */ const char *fmt, /* Format string */ va_list ap /* arguments */ ){ int c; /* Next character in the format string */ char *bufpt; /* Pointer to the conversion buffer */ int precision; /* Precision of the current field */ int length; /* Length of the field */ int idx; /* A general purpose loop counter */ int width; /* Width of the current field */ etByte flag_leftjustify; /* True if "-" flag is present */ etByte flag_prefix; /* '+' or ' ' or 0 for prefix */ etByte flag_alternateform; /* True if "#" flag is present */ etByte flag_altform2; /* True if "!" flag is present */ etByte flag_zeropad; /* True if field width constant starts with zero */ etByte flag_long; /* 1 for the "l" flag, 2 for "ll", 0 by default */ etByte done; /* Loop termination flag */ etByte cThousand; /* Thousands separator for %d and %u */ etByte xtype = etINVALID; /* Conversion paradigm */ u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ sqlite_uint64 longvalue; /* Value for integer types */ double realvalue; /* Value for real types */ const et_info *infop; /* Pointer to the appropriate info structure */ char *zOut; /* Rendering buffer */ int nOut; /* Size of the rendering buffer */ char *zExtra = 0; /* Malloced memory used by some conversion */ int exp, e2; /* exponent of real numbers */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */ char buf[etBUFSIZE]; /* Conversion buffer */ /* pAccum never starts out with an empty buffer that was obtained from ** malloc(). This precondition is required by the mprintf("%z...") ** optimization. */ assert( pAccum->nChar>0 || (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 ); bufpt = 0; if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){ pArgList = va_arg(ap, PrintfArguments*); bArgList = 1; }else{ bArgList = 0; } for(; (c=(*fmt))!=0; ++fmt){ if( c!='%' ){ bufpt = (char *)fmt; #if HAVE_STRCHRNUL fmt = strchrnul(fmt, '%'); #else do{ fmt++; }while( *fmt && *fmt != '%' ); #endif sqlite3_str_append(pAccum, bufpt, (int)(fmt - bufpt)); if( *fmt==0 ) break; } if( (c=(*++fmt))==0 ){ sqlite3_str_append(pAccum, "%", 1); break; } /* Find out what flags are present */ flag_leftjustify = flag_prefix = cThousand = flag_alternateform = flag_altform2 = flag_zeropad = 0; done = 0; width = 0; flag_long = 0; precision = -1; do{ switch( c ){ case '-': flag_leftjustify = 1; break; case '+': flag_prefix = '+'; break; case ' ': flag_prefix = ' '; break; case '#': flag_alternateform = 1; break; case '!': flag_altform2 = 1; break; case '0': flag_zeropad = 1; break; case ',': cThousand = ','; break; default: done = 1; break; case 'l': { flag_long = 1; c = *++fmt; if( c=='l' ){ c = *++fmt; flag_long = 2; } done = 1; break; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { unsigned wx = c - '0'; while( (c = *++fmt)>='0' && c<='9' ){ wx = wx*10 + c - '0'; } testcase( wx>0x7fffffff ); width = wx & 0x7fffffff; #ifdef SQLITE_PRINTF_PRECISION_LIMIT if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ width = SQLITE_PRINTF_PRECISION_LIMIT; } #endif if( c!='.' && c!='l' ){ done = 1; }else{ fmt--; } break; } case '*': { if( bArgList ){ width = (int)getIntArg(pArgList); }else{ width = va_arg(ap,int); } if( width<0 ){ flag_leftjustify = 1; width = width >= -2147483647 ? -width : 0; } #ifdef SQLITE_PRINTF_PRECISION_LIMIT if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ width = SQLITE_PRINTF_PRECISION_LIMIT; } #endif if( (c = fmt[1])!='.' && c!='l' ){ c = *++fmt; done = 1; } break; } case '.': { c = *++fmt; if( c=='*' ){ if( bArgList ){ precision = (int)getIntArg(pArgList); }else{ precision = va_arg(ap,int); } if( precision<0 ){ precision = precision >= -2147483647 ? -precision : -1; } c = *++fmt; }else{ unsigned px = 0; while( c>='0' && c<='9' ){ px = px*10 + c - '0'; c = *++fmt; } testcase( px>0x7fffffff ); precision = px & 0x7fffffff; } #ifdef SQLITE_PRINTF_PRECISION_LIMIT if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){ precision = SQLITE_PRINTF_PRECISION_LIMIT; } #endif if( c=='l' ){ --fmt; }else{ done = 1; } break; } } }while( !done && (c=(*++fmt))!=0 ); /* Fetch the info entry for the field */ infop = &fmtinfo[0]; xtype = etINVALID; for(idx=0; idxtype; break; } } /* ** At this point, variables are initialized as follows: ** ** flag_alternateform TRUE if a '#' is present. ** flag_altform2 TRUE if a '!' is present. ** flag_prefix '+' or ' ' or zero ** flag_leftjustify TRUE if a '-' is present or if the ** field width was negative. ** flag_zeropad TRUE if the width began with 0. ** flag_long 1 for "l", 2 for "ll" ** width The specified field width. This is ** always non-negative. Zero is the default. ** precision The specified precision. The default ** is -1. ** xtype The class of the conversion. ** infop Pointer to the appropriate info struct. */ assert( width>=0 ); assert( precision>=(-1) ); switch( xtype ){ case etPOINTER: flag_long = sizeof(char*)==sizeof(i64) ? 2 : sizeof(char*)==sizeof(long int) ? 1 : 0; /* no break */ deliberate_fall_through case etORDINAL: case etRADIX: cThousand = 0; /* no break */ deliberate_fall_through case etDECIMAL: if( infop->flags & FLAG_SIGNED ){ i64 v; if( bArgList ){ v = getIntArg(pArgList); }else if( flag_long ){ if( flag_long==2 ){ v = va_arg(ap,i64) ; }else{ v = va_arg(ap,long int); } }else{ v = va_arg(ap,int); } if( v<0 ){ testcase( v==SMALLEST_INT64 ); testcase( v==(-1) ); longvalue = ~v; longvalue++; prefix = '-'; }else{ longvalue = v; prefix = flag_prefix; } }else{ if( bArgList ){ longvalue = (u64)getIntArg(pArgList); }else if( flag_long ){ if( flag_long==2 ){ longvalue = va_arg(ap,u64); }else{ longvalue = va_arg(ap,unsigned long int); } }else{ longvalue = va_arg(ap,unsigned int); } prefix = 0; } if( longvalue==0 ) flag_alternateform = 0; if( flag_zeropad && precision=4 || (longvalue/10)%10==1 ){ x = 0; } *(--bufpt) = zOrd[x*2+1]; *(--bufpt) = zOrd[x*2]; } { const char *cset = &aDigits[infop->charset]; u8 base = infop->base; do{ /* Convert to ascii */ *(--bufpt) = cset[longvalue%base]; longvalue = longvalue/base; }while( longvalue>0 ); } length = (int)(&zOut[nOut-1]-bufpt); while( precision>length ){ *(--bufpt) = '0'; /* Zero pad */ length++; } if( cThousand ){ int nn = (length - 1)/3; /* Number of "," to insert */ int ix = (length - 1)%3 + 1; bufpt -= nn; for(idx=0; nn>0; idx++){ bufpt[idx] = bufpt[idx+nn]; ix--; if( ix==0 ){ bufpt[++idx] = cThousand; nn--; ix = 3; } } } if( prefix ) *(--bufpt) = prefix; /* Add sign */ if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ const char *pre; char x; pre = &aPrefix[infop->prefix]; for(; (x=(*pre))!=0; pre++) *(--bufpt) = x; } length = (int)(&zOut[nOut-1]-bufpt); break; case etFLOAT: case etEXP: case etGENERIC: { FpDecode s; int iRound; int j; if( bArgList ){ realvalue = getDoubleArg(pArgList); }else{ realvalue = va_arg(ap,double); } if( precision<0 ) precision = 6; /* Set default precision */ #ifdef SQLITE_FP_PRECISION_LIMIT if( precision>SQLITE_FP_PRECISION_LIMIT ){ precision = SQLITE_FP_PRECISION_LIMIT; } #endif if( xtype==etFLOAT ){ iRound = -precision; }else if( xtype==etGENERIC ){ iRound = precision; }else{ iRound = precision+1; } sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16); if( s.isSpecial ){ if( s.isSpecial==2 ){ bufpt = flag_zeropad ? "null" : "NaN"; length = sqlite3Strlen30(bufpt); break; }else if( flag_zeropad ){ s.z[0] = '9'; s.iDP = 1000; s.n = 1; }else{ memcpy(buf, "-Inf", 5); bufpt = buf; if( s.sign=='-' ){ /* no-op */ }else if( flag_prefix ){ buf[0] = flag_prefix; }else{ bufpt++; } length = sqlite3Strlen30(bufpt); break; } } if( s.sign=='-' ){ prefix = '-'; }else{ prefix = flag_prefix; } exp = s.iDP-1; if( xtype==etGENERIC && precision>0 ) precision--; /* ** If the field type is etGENERIC, then convert to either etEXP ** or etFLOAT, as appropriate. */ if( xtype==etGENERIC ){ flag_rtz = !flag_alternateform; if( exp<-4 || exp>precision ){ xtype = etEXP; }else{ precision = precision - exp; xtype = etFLOAT; } }else{ flag_rtz = flag_altform2; } if( xtype==etEXP ){ e2 = 0; }else{ e2 = s.iDP - 1; } bufpt = buf; { i64 szBufNeeded; /* Size of a temporary buffer needed */ szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15; if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3; if( szBufNeeded > etBUFSIZE ){ bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded); if( bufpt==0 ) return; } } zOut = bufpt; flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2; /* The sign in front of the number */ if( prefix ){ *(bufpt++) = prefix; } /* Digits prior to the decimal point */ j = 0; if( e2<0 ){ *(bufpt++) = '0'; }else{ for(; e2>=0; e2--){ *(bufpt++) = j1 ) *(bufpt++) = ','; } } /* The decimal point */ if( flag_dp ){ *(bufpt++) = '.'; } /* "0" digits after the decimal point but before the first ** significant digit of the number */ for(e2++; e2<0 && precision>0; precision--, e2++){ *(bufpt++) = '0'; } /* Significant digits after the decimal point */ while( (precision--)>0 ){ *(bufpt++) = jzOut ); if( bufpt[-1]=='.' ){ if( flag_altform2 ){ *(bufpt++) = '0'; }else{ *(--bufpt) = 0; } } } /* Add the "eNNN" suffix */ if( xtype==etEXP ){ exp = s.iDP - 1; *(bufpt++) = aDigits[infop->charset]; if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; }else{ *(bufpt++) = '+'; } if( exp>=100 ){ *(bufpt++) = (char)((exp/100)+'0'); /* 100's digit */ exp %= 100; } *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */ *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */ } *bufpt = 0; /* The converted number is in buf[] and zero terminated. Output it. ** Note that the number is in the usual order, not reversed as with ** integer conversions. */ length = (int)(bufpt-zOut); bufpt = zOut; /* Special case: Add leading zeros if the flag_zeropad flag is ** set and we are not left justified */ if( flag_zeropad && !flag_leftjustify && length < width){ int i; int nPad = width - length; for(i=width; i>=nPad; i--){ bufpt[i] = bufpt[i-nPad]; } i = prefix!=0; while( nPad-- ) bufpt[i++] = '0'; length = width; } break; } case etSIZE: if( !bArgList ){ *(va_arg(ap,int*)) = pAccum->nChar; } length = width = 0; break; case etPERCENT: buf[0] = '%'; bufpt = buf; length = 1; break; case etCHARX: if( bArgList ){ bufpt = getTextArg(pArgList); length = 1; if( bufpt ){ buf[0] = c = *(bufpt++); if( (c&0xc0)==0xc0 ){ while( length<4 && (bufpt[0]&0xc0)==0x80 ){ buf[length++] = *(bufpt++); } } }else{ buf[0] = 0; } }else{ unsigned int ch = va_arg(ap,unsigned int); if( ch<0x00080 ){ buf[0] = ch & 0xff; length = 1; }else if( ch<0x00800 ){ buf[0] = 0xc0 + (u8)((ch>>6)&0x1f); buf[1] = 0x80 + (u8)(ch & 0x3f); length = 2; }else if( ch<0x10000 ){ buf[0] = 0xe0 + (u8)((ch>>12)&0x0f); buf[1] = 0x80 + (u8)((ch>>6) & 0x3f); buf[2] = 0x80 + (u8)(ch & 0x3f); length = 3; }else{ buf[0] = 0xf0 + (u8)((ch>>18) & 0x07); buf[1] = 0x80 + (u8)((ch>>12) & 0x3f); buf[2] = 0x80 + (u8)((ch>>6) & 0x3f); buf[3] = 0x80 + (u8)(ch & 0x3f); length = 4; } } if( precision>1 ){ i64 nPrior = 1; width -= precision-1; if( width>1 && !flag_leftjustify ){ sqlite3_str_appendchar(pAccum, width-1, ' '); width = 0; } sqlite3_str_append(pAccum, buf, length); precision--; while( precision > 1 ){ i64 nCopyBytes; if( nPrior > precision-1 ) nPrior = precision - 1; nCopyBytes = length*nPrior; if( nCopyBytes + pAccum->nChar >= pAccum->nAlloc ){ sqlite3StrAccumEnlarge(pAccum, nCopyBytes); } if( pAccum->accError ) break; sqlite3_str_append(pAccum, &pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes); precision -= nPrior; nPrior *= 2; } } bufpt = buf; flag_altform2 = 1; goto adjust_width_for_utf8; case etSTRING: case etDYNSTRING: if( bArgList ){ bufpt = getTextArg(pArgList); xtype = etSTRING; }else{ bufpt = va_arg(ap,char*); } if( bufpt==0 ){ bufpt = ""; }else if( xtype==etDYNSTRING ){ if( pAccum->nChar==0 && pAccum->mxAlloc && width==0 && precision<0 && pAccum->accError==0 ){ /* Special optimization for sqlite3_mprintf("%z..."): ** Extend an existing memory allocation rather than creating ** a new one. */ assert( (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 ); pAccum->zText = bufpt; pAccum->nAlloc = sqlite3DbMallocSize(pAccum->db, bufpt); pAccum->nChar = 0x7fffffff & (int)strlen(bufpt); pAccum->printfFlags |= SQLITE_PRINTF_MALLOCED; length = 0; break; } zExtra = bufpt; } if( precision>=0 ){ if( flag_altform2 ){ /* Set length to the number of bytes needed in order to display ** precision characters */ unsigned char *z = (unsigned char*)bufpt; while( precision-- > 0 && z[0] ){ SQLITE_SKIP_UTF8(z); } length = (int)(z - (unsigned char*)bufpt); }else{ for(length=0; length0 ){ /* Adjust width to account for extra bytes in UTF-8 characters */ int ii = length - 1; while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; } break; case etSQLESCAPE: /* %q: Escape ' characters */ case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */ case etSQLESCAPE3: { /* %w: Escape " characters */ i64 i, j, k, n; int needQuote, isnull; char ch; char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ char *escarg; if( bArgList ){ escarg = getTextArg(pArgList); }else{ escarg = va_arg(ap,char*); } isnull = escarg==0; if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); /* For %q, %Q, and %w, the precision is the number of bytes (or ** characters if the ! flags is present) to use from the input. ** Because of the extra quoting characters inserted, the number ** of output characters may be larger than the precision. */ k = precision; for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){ if( ch==q ) n++; if( flag_altform2 && (ch&0xc0)==0xc0 ){ while( (escarg[i+1]&0xc0)==0x80 ){ i++; } } } needQuote = !isnull && xtype==etSQLESCAPE2; n += i + 3; if( n>etBUFSIZE ){ bufpt = zExtra = printfTempBuf(pAccum, n); if( bufpt==0 ) return; }else{ bufpt = buf; } j = 0; if( needQuote ) bufpt[j++] = q; k = i; for(i=0; iprintfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; if( flag_alternateform ){ /* %#T means an Expr pointer that uses Expr.u.zToken */ Expr *pExpr = va_arg(ap,Expr*); if( ALWAYS(pExpr) && ALWAYS(!ExprHasProperty(pExpr,EP_IntValue)) ){ sqlite3_str_appendall(pAccum, (const char*)pExpr->u.zToken); sqlite3RecordErrorOffsetOfExpr(pAccum->db, pExpr); } }else{ /* %T means a Token pointer */ Token *pToken = va_arg(ap, Token*); assert( bArgList==0 ); if( pToken && pToken->n ){ sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n); sqlite3RecordErrorByteOffset(pAccum->db, pToken->z); } } length = width = 0; break; } case etSRCITEM: { SrcItem *pItem; if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; pItem = va_arg(ap, SrcItem*); assert( bArgList==0 ); if( pItem->zAlias && !flag_altform2 ){ sqlite3_str_appendall(pAccum, pItem->zAlias); }else if( pItem->zName ){ if( pItem->zDatabase ){ sqlite3_str_appendall(pAccum, pItem->zDatabase); sqlite3_str_append(pAccum, ".", 1); } sqlite3_str_appendall(pAccum, pItem->zName); }else if( pItem->zAlias ){ sqlite3_str_appendall(pAccum, pItem->zAlias); }else{ Select *pSel = pItem->pSelect; assert( pSel!=0 ); if( pSel->selFlags & SF_NestedFrom ){ sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId); }else{ sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId); } } length = width = 0; break; } default: { assert( xtype==etINVALID ); return; } }/* End switch over the format type */ /* ** The text of the conversion is pointed to by "bufpt" and is ** "length" characters long. The field width is "width". Do ** the output. Both length and width are in bytes, not characters, ** at this point. If the "!" flag was present on string conversions ** indicating that width and precision should be expressed in characters, ** then the values have been translated prior to reaching this point. */ width -= length; if( width>0 ){ if( !flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' '); sqlite3_str_append(pAccum, bufpt, length); if( flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' '); }else{ sqlite3_str_append(pAccum, bufpt, length); } if( zExtra ){ sqlite3DbFree(pAccum->db, zExtra); zExtra = 0; } }/* End for loop over the format string */ } /* End of function */ /* ** The z string points to the first character of a token that is ** associated with an error. If db does not already have an error ** byte offset recorded, try to compute the error byte offset for ** z and set the error byte offset in db. */ SQLITE_PRIVATE void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){ const Parse *pParse; const char *zText; const char *zEnd; assert( z!=0 ); if( NEVER(db==0) ) return; if( db->errByteOffset!=(-2) ) return; pParse = db->pParse; if( NEVER(pParse==0) ) return; zText =pParse->zTail; if( NEVER(zText==0) ) return; zEnd = &zText[strlen(zText)]; if( SQLITE_WITHIN(z,zText,zEnd) ){ db->errByteOffset = (int)(z-zText); } } /* ** If pExpr has a byte offset for the start of a token, record that as ** as the error offset. */ SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){ while( pExpr && (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0) ){ pExpr = pExpr->pLeft; } if( pExpr==0 ) return; db->errByteOffset = pExpr->w.iOfst; } /* ** Enlarge the memory allocation on a StrAccum object so that it is ** able to accept at least N more bytes of text. ** ** Return the number of bytes of text that StrAccum is able to accept ** after the attempted enlargement. The value returned might be zero. */ SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){ char *zNew; assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */ if( p->accError ){ testcase(p->accError==SQLITE_TOOBIG); testcase(p->accError==SQLITE_NOMEM); return 0; } if( p->mxAlloc==0 ){ sqlite3StrAccumSetError(p, SQLITE_TOOBIG); return p->nAlloc - p->nChar - 1; }else{ char *zOld = isMalloced(p) ? p->zText : 0; i64 szNew = p->nChar + N + 1; if( szNew+p->nChar<=p->mxAlloc ){ /* Force exponential buffer size growth as long as it does not overflow, ** to avoid having to call this routine too often */ szNew += p->nChar; } if( szNew > p->mxAlloc ){ sqlite3_str_reset(p); sqlite3StrAccumSetError(p, SQLITE_TOOBIG); return 0; }else{ p->nAlloc = (int)szNew; } if( p->db ){ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); }else{ zNew = sqlite3Realloc(zOld, p->nAlloc); } if( zNew ){ assert( p->zText!=0 || p->nChar==0 ); if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); p->zText = zNew; p->nAlloc = sqlite3DbMallocSize(p->db, zNew); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ sqlite3_str_reset(p); sqlite3StrAccumSetError(p, SQLITE_NOMEM); return 0; } } assert( N>=0 && N<=0x7fffffff ); return (int)N; } /* ** Append N copies of character c to the given string buffer. */ SQLITE_API void sqlite3_str_appendchar(sqlite3_str *p, int N, char c){ testcase( p->nChar + (i64)N > 0x7fffffff ); if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){ return; } while( (N--)>0 ) p->zText[p->nChar++] = c; } /* ** The StrAccum "p" is not large enough to accept N new bytes of z[]. ** So enlarge if first, then do the append. ** ** This is a helper routine to sqlite3_str_append() that does special-case ** work (enlarging the buffer) using tail recursion, so that the ** sqlite3_str_append() routine can use fast calling semantics. */ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ N = sqlite3StrAccumEnlarge(p, N); if( N>0 ){ memcpy(&p->zText[p->nChar], z, N); p->nChar += N; } } /* ** Append N bytes of text from z to the StrAccum object. Increase the ** size of the memory allocation for StrAccum if necessary. */ SQLITE_API void sqlite3_str_append(sqlite3_str *p, const char *z, int N){ assert( z!=0 || N==0 ); assert( p->zText!=0 || p->nChar==0 || p->accError ); assert( N>=0 ); assert( p->accError==0 || p->nAlloc==0 || p->mxAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ enlargeAndAppend(p,z,N); }else if( N ){ assert( p->zText ); p->nChar += N; memcpy(&p->zText[p->nChar-N], z, N); } } /* ** Append the complete text of zero-terminated string z[] to the p string. */ SQLITE_API void sqlite3_str_appendall(sqlite3_str *p, const char *z){ sqlite3_str_append(p, z, sqlite3Strlen30(z)); } /* ** Finish off a string by making sure it is zero-terminated. ** Return a pointer to the resulting string. Return a NULL ** pointer if any kind of error was encountered. */ static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){ char *zText; assert( p->mxAlloc>0 && !isMalloced(p) ); zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); if( zText ){ memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ sqlite3StrAccumSetError(p, SQLITE_NOMEM); } p->zText = zText; return zText; } SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){ if( p->zText ){ p->zText[p->nChar] = 0; if( p->mxAlloc>0 && !isMalloced(p) ){ return strAccumFinishRealloc(p); } } return p->zText; } /* ** Use the content of the StrAccum passed as the second argument ** as the result of an SQL function. */ SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){ if( p->accError ){ sqlite3_result_error_code(pCtx, p->accError); sqlite3_str_reset(p); }else if( isMalloced(p) ){ sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC); }else{ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); sqlite3_str_reset(p); } } /* ** This singleton is an sqlite3_str object that is returned if ** sqlite3_malloc() fails to provide space for a real one. This ** sqlite3_str object accepts no new text and always returns ** an SQLITE_NOMEM error. */ static sqlite3_str sqlite3OomStr = { 0, 0, 0, 0, 0, SQLITE_NOMEM, 0 }; /* Finalize a string created using sqlite3_str_new(). */ SQLITE_API char *sqlite3_str_finish(sqlite3_str *p){ char *z; if( p!=0 && p!=&sqlite3OomStr ){ z = sqlite3StrAccumFinish(p); sqlite3_free(p); }else{ z = 0; } return z; } /* Return any error code associated with p */ SQLITE_API int sqlite3_str_errcode(sqlite3_str *p){ return p ? p->accError : SQLITE_NOMEM; } /* Return the current length of p in bytes */ SQLITE_API int sqlite3_str_length(sqlite3_str *p){ return p ? p->nChar : 0; } /* Return the current value for p */ SQLITE_API char *sqlite3_str_value(sqlite3_str *p){ if( p==0 || p->nChar==0 ) return 0; p->zText[p->nChar] = 0; return p->zText; } /* ** Reset an StrAccum string. Reclaim all malloced memory. */ SQLITE_API void sqlite3_str_reset(StrAccum *p){ if( isMalloced(p) ){ sqlite3DbFree(p->db, p->zText); p->printfFlags &= ~SQLITE_PRINTF_MALLOCED; } p->nAlloc = 0; p->nChar = 0; p->zText = 0; } /* ** Initialize a string accumulator. ** ** p: The accumulator to be initialized. ** db: Pointer to a database connection. May be NULL. Lookaside ** memory is used if not NULL. db->mallocFailed is set appropriately ** when not NULL. ** zBase: An initial buffer. May be NULL in which case the initial buffer ** is malloced. ** n: Size of zBase in bytes. If total space requirements never exceed ** n then no memory allocations ever occur. ** mx: Maximum number of bytes to accumulate. If mx==0 then no memory ** allocations will ever occur. */ SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){ p->zText = zBase; p->db = db; p->nAlloc = n; p->mxAlloc = mx; p->nChar = 0; p->accError = 0; p->printfFlags = 0; } /* Allocate and initialize a new dynamic string object */ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3 *db){ sqlite3_str *p = sqlite3_malloc64(sizeof(*p)); if( p ){ sqlite3StrAccumInit(p, 0, 0, 0, db ? db->aLimit[SQLITE_LIMIT_LENGTH] : SQLITE_MAX_LENGTH); }else{ p = &sqlite3OomStr; } return p; } /* ** Print into memory obtained from sqliteMalloc(). Use the internal ** %-conversion extensions. */ SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){ char *z; char zBase[SQLITE_PRINT_BUF_SIZE]; StrAccum acc; assert( db!=0 ); sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); acc.printfFlags = SQLITE_PRINTF_INTERNAL; sqlite3_str_vappendf(&acc, zFormat, ap); z = sqlite3StrAccumFinish(&acc); if( acc.accError==SQLITE_NOMEM ){ sqlite3OomFault(db); } return z; } /* ** Print into memory obtained from sqliteMalloc(). Use the internal ** %-conversion extensions. */ SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){ va_list ap; char *z; va_start(ap, zFormat); z = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); return z; } /* ** Print into memory obtained from sqlite3_malloc(). Omit the internal ** %-conversion extensions. */ SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){ char *z; char zBase[SQLITE_PRINT_BUF_SIZE]; StrAccum acc; #ifdef SQLITE_ENABLE_API_ARMOR if( zFormat==0 ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); sqlite3_str_vappendf(&acc, zFormat, ap); z = sqlite3StrAccumFinish(&acc); return z; } /* ** Print into memory obtained from sqlite3_malloc()(). Omit the internal ** %-conversion extensions. */ SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){ va_list ap; char *z; #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif va_start(ap, zFormat); z = sqlite3_vmprintf(zFormat, ap); va_end(ap); return z; } /* ** sqlite3_snprintf() works like snprintf() except that it ignores the ** current locale settings. This is important for SQLite because we ** are not able to use a "," as the decimal point in place of "." as ** specified by some locales. ** ** Oops: The first two arguments of sqlite3_snprintf() are backwards ** from the snprintf() standard. Unfortunately, it is too late to change ** this without breaking compatibility, so we just have to live with the ** mistake. ** ** sqlite3_vsnprintf() is the varargs version. */ SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){ StrAccum acc; if( n<=0 ) return zBuf; #ifdef SQLITE_ENABLE_API_ARMOR if( zBuf==0 || zFormat==0 ) { (void)SQLITE_MISUSE_BKPT; if( zBuf ) zBuf[0] = 0; return zBuf; } #endif sqlite3StrAccumInit(&acc, 0, zBuf, n, 0); sqlite3_str_vappendf(&acc, zFormat, ap); zBuf[acc.nChar] = 0; return zBuf; } SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ StrAccum acc; va_list ap; if( n<=0 ) return zBuf; #ifdef SQLITE_ENABLE_API_ARMOR if( zBuf==0 || zFormat==0 ) { (void)SQLITE_MISUSE_BKPT; if( zBuf ) zBuf[0] = 0; return zBuf; } #endif sqlite3StrAccumInit(&acc, 0, zBuf, n, 0); va_start(ap,zFormat); sqlite3_str_vappendf(&acc, zFormat, ap); va_end(ap); zBuf[acc.nChar] = 0; return zBuf; } /* ** This is the routine that actually formats the sqlite3_log() message. ** We house it in a separate routine from sqlite3_log() to avoid using ** stack space on small-stack systems when logging is disabled. ** ** sqlite3_log() must render into a static buffer. It cannot dynamically ** allocate memory because it might be called while the memory allocator ** mutex is held. ** ** sqlite3_str_vappendf() might ask for *temporary* memory allocations for ** certain format characters (%q) or for very large precisions or widths. ** Care must be taken that any sqlite3_log() calls that occur while the ** memory mutex is held do not use these mechanisms. */ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ StrAccum acc; /* String accumulator */ char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); sqlite3_str_vappendf(&acc, zFormat, ap); sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, sqlite3StrAccumFinish(&acc)); } /* ** Format and write a message to the log if logging is enabled. */ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){ va_list ap; /* Vararg list */ if( sqlite3GlobalConfig.xLog ){ va_start(ap, zFormat); renderLogMsg(iErrCode, zFormat, ap); va_end(ap); } } #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) /* ** A version of printf() that understands %lld. Used for debugging. ** The printf() built into some versions of windows does not understand %lld ** and segfaults if you give it a long long int. */ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){ va_list ap; StrAccum acc; char zBuf[SQLITE_PRINT_BUF_SIZE*10]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); va_start(ap,zFormat); sqlite3_str_vappendf(&acc, zFormat, ap); va_end(ap); sqlite3StrAccumFinish(&acc); #ifdef SQLITE_OS_TRACE_PROC { extern void SQLITE_OS_TRACE_PROC(const char *zBuf, int nBuf); SQLITE_OS_TRACE_PROC(zBuf, sizeof(zBuf)); } #else fprintf(stdout,"%s", zBuf); fflush(stdout); #endif } #endif /* ** variable-argument wrapper around sqlite3_str_vappendf(). The bFlags argument ** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats. */ SQLITE_API void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){ va_list ap; va_start(ap,zFormat); sqlite3_str_vappendf(p, zFormat, ap); va_end(ap); } /***************************************************************************** ** Reference counted string/blob storage *****************************************************************************/ /* ** Increase the reference count of the string by one. ** ** The input parameter is returned. */ SQLITE_PRIVATE char *sqlite3RCStrRef(char *z){ RCStr *p = (RCStr*)z; assert( p!=0 ); p--; p->nRCRef++; return z; } /* ** Decrease the reference count by one. Free the string when the ** reference count reaches zero. */ SQLITE_PRIVATE void sqlite3RCStrUnref(void *z){ RCStr *p = (RCStr*)z; assert( p!=0 ); p--; assert( p->nRCRef>0 ); if( p->nRCRef>=2 ){ p->nRCRef--; }else{ sqlite3_free(p); } } /* ** Create a new string that is capable of holding N bytes of text, not counting ** the zero byte at the end. The string is uninitialized. ** ** The reference count is initially 1. Call sqlite3RCStrUnref() to free the ** newly allocated string. ** ** This routine returns 0 on an OOM. */ SQLITE_PRIVATE char *sqlite3RCStrNew(u64 N){ RCStr *p = sqlite3_malloc64( N + sizeof(*p) + 1 ); if( p==0 ) return 0; p->nRCRef = 1; return (char*)&p[1]; } /* ** Change the size of the string so that it is able to hold N bytes. ** The string might be reallocated, so return the new allocation. */ SQLITE_PRIVATE char *sqlite3RCStrResize(char *z, u64 N){ RCStr *p = (RCStr*)z; RCStr *pNew; assert( p!=0 ); p--; assert( p->nRCRef==1 ); pNew = sqlite3_realloc64(p, N+sizeof(RCStr)+1); if( pNew==0 ){ sqlite3_free(p); return 0; }else{ return (char*)&pNew[1]; } } /************** End of printf.c **********************************************/ /************** Begin file treeview.c ****************************************/ /* ** 2015-06-08 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains C code to implement the TreeView debugging routines. ** These routines print a parse tree to standard output for debugging and ** analysis. ** ** The interfaces in this file is only available when compiling ** with SQLITE_DEBUG. */ /* #include "sqliteInt.h" */ #ifdef SQLITE_DEBUG /* ** Add a new subitem to the tree. The moreToFollow flag indicates that this ** is not the last item in the tree. */ static void sqlite3TreeViewPush(TreeView **pp, u8 moreToFollow){ TreeView *p = *pp; if( p==0 ){ *pp = p = sqlite3_malloc64( sizeof(*p) ); if( p==0 ) return; memset(p, 0, sizeof(*p)); }else{ p->iLevel++; } assert( moreToFollow==0 || moreToFollow==1 ); if( p->iLevel<(int)sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow; } /* ** Finished with one layer of the tree */ static void sqlite3TreeViewPop(TreeView **pp){ TreeView *p = *pp; if( p==0 ) return; p->iLevel--; if( p->iLevel<0 ){ sqlite3_free(p); *pp = 0; } } /* ** Generate a single line of output for the tree, with a prefix that contains ** all the appropriate tree lines */ SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ va_list ap; int i; StrAccum acc; char zBuf[1000]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); if( p ){ for(i=0; iiLevel && i<(int)sizeof(p->bLine)-1; i++){ sqlite3_str_append(&acc, p->bLine[i] ? "| " : " ", 4); } sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); } if( zFormat!=0 ){ va_start(ap, zFormat); sqlite3_str_vappendf(&acc, zFormat, ap); va_end(ap); assert( acc.nChar>0 || acc.accError ); sqlite3_str_append(&acc, "\n", 1); } sqlite3StrAccumFinish(&acc); fprintf(stdout,"%s", zBuf); fflush(stdout); } /* ** Shorthand for starting a new tree item that consists of a single label */ static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){ sqlite3TreeViewPush(&p, moreFollows); sqlite3TreeViewLine(p, "%s", zLabel); } /* ** Show a list of Column objects in tree format. */ SQLITE_PRIVATE void sqlite3TreeViewColumnList( TreeView *pView, const Column *aCol, int nCol, u8 moreToFollow ){ int i; sqlite3TreeViewPush(&pView, moreToFollow); sqlite3TreeViewLine(pView, "COLUMNS"); for(i=0; inCte==0 ) return; if( pWith->pOuter ){ sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter); }else{ sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith); } if( pWith->nCte>0 ){ sqlite3TreeViewPush(&pView, moreToFollow); for(i=0; inCte; i++){ StrAccum x; char zLine[1000]; const struct Cte *pCte = &pWith->a[i]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); sqlite3_str_appendf(&x, "%s", pCte->zName); if( pCte->pCols && pCte->pCols->nExpr>0 ){ char cSep = '('; int j; for(j=0; jpCols->nExpr; j++){ sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zEName); cSep = ','; } sqlite3_str_appendf(&x, ")"); } if( pCte->eM10d!=M10d_Any ){ sqlite3_str_appendf(&x, " %sMATERIALIZED", pCte->eM10d==M10d_No ? "NOT " : ""); } if( pCte->pUse ){ sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse, pCte->pUse->nUse); } sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, inCte-1); sqlite3TreeViewSelect(pView, pCte->pSelect, 0); sqlite3TreeViewPop(&pView); } sqlite3TreeViewPop(&pView); } } /* ** Generate a human-readable description of a SrcList object. */ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ int i; if( pSrc==0 ) return; for(i=0; inSrc; i++){ const SrcItem *pItem = &pSrc->a[i]; StrAccum x; int n = 0; char zLine[1000]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); x.printfFlags |= SQLITE_PRINTF_INTERNAL; sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem); if( pItem->pTab ){ sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx", pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed); } if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){ sqlite3_str_appendf(&x, " FULL-OUTER-JOIN"); }else if( pItem->fg.jointype & JT_LEFT ){ sqlite3_str_appendf(&x, " LEFT-JOIN"); }else if( pItem->fg.jointype & JT_RIGHT ){ sqlite3_str_appendf(&x, " RIGHT-JOIN"); }else if( pItem->fg.jointype & JT_CROSS ){ sqlite3_str_appendf(&x, " CROSS-JOIN"); } if( pItem->fg.jointype & JT_LTORJ ){ sqlite3_str_appendf(&x, " LTORJ"); } if( pItem->fg.fromDDL ){ sqlite3_str_appendf(&x, " DDL"); } if( pItem->fg.isCte ){ sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse); } if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){ sqlite3_str_appendf(&x, " ON"); } if( pItem->fg.isTabFunc ) sqlite3_str_appendf(&x, " isTabFunc"); if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated"); if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized"); if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine"); if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte"); if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom"); sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, inSrc-1); n = 0; if( pItem->pSelect ) n++; if( pItem->fg.isTabFunc ) n++; if( pItem->fg.isUsing ) n++; if( pItem->fg.isUsing ){ sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING"); } if( pItem->pSelect ){ if( pItem->pTab ){ Table *pTab = pItem->pTab; sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1); } assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0); } if( pItem->fg.isTabFunc ){ sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); } sqlite3TreeViewPop(&pView); } } /* ** Generate a human-readable description of a Select object. */ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ int n = 0; int cnt = 0; if( p==0 ){ sqlite3TreeViewLine(pView, "nil-SELECT"); return; } sqlite3TreeViewPush(&pView, moreToFollow); if( p->pWith ){ sqlite3TreeViewWith(pView, p->pWith, 1); cnt = 1; sqlite3TreeViewPush(&pView, 1); } do{ if( p->selFlags & SF_WhereBegin ){ sqlite3TreeViewLine(pView, "sqlite3WhereBegin()"); }else{ sqlite3TreeViewLine(pView, "SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p->selId, p, p->selFlags, (int)p->nSelectRow ); } if( cnt++ ) sqlite3TreeViewPop(&pView); if( p->pPrior ){ n = 1000; }else{ n = 0; if( p->pSrc && p->pSrc->nSrc ) n++; if( p->pWhere ) n++; if( p->pGroupBy ) n++; if( p->pHaving ) n++; if( p->pOrderBy ) n++; if( p->pLimit ) n++; #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWin ) n++; if( p->pWinDefn ) n++; #endif } if( p->pEList ){ sqlite3TreeViewExprList(pView, p->pEList, n>0, "result-set"); } n--; #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWin ){ Window *pX; sqlite3TreeViewPush(&pView, (n--)>0); sqlite3TreeViewLine(pView, "window-functions"); for(pX=p->pWin; pX; pX=pX->pNextWin){ sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0); } sqlite3TreeViewPop(&pView); } #endif if( p->pSrc && p->pSrc->nSrc ){ sqlite3TreeViewPush(&pView, (n--)>0); sqlite3TreeViewLine(pView, "FROM"); sqlite3TreeViewSrcList(pView, p->pSrc); sqlite3TreeViewPop(&pView); } if( p->pWhere ){ sqlite3TreeViewItem(pView, "WHERE", (n--)>0); sqlite3TreeViewExpr(pView, p->pWhere, 0); sqlite3TreeViewPop(&pView); } if( p->pGroupBy ){ sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); } if( p->pHaving ){ sqlite3TreeViewItem(pView, "HAVING", (n--)>0); sqlite3TreeViewExpr(pView, p->pHaving, 0); sqlite3TreeViewPop(&pView); } #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWinDefn ){ Window *pX; sqlite3TreeViewItem(pView, "WINDOW", (n--)>0); for(pX=p->pWinDefn; pX; pX=pX->pNextWin){ sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0); } sqlite3TreeViewPop(&pView); } #endif if( p->pOrderBy ){ sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); } if( p->pLimit ){ sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0); if( p->pLimit->pRight ){ sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0); sqlite3TreeViewPop(&pView); } sqlite3TreeViewPop(&pView); } if( p->pPrior ){ const char *zOp = "UNION"; switch( p->op ){ case TK_ALL: zOp = "UNION ALL"; break; case TK_INTERSECT: zOp = "INTERSECT"; break; case TK_EXCEPT: zOp = "EXCEPT"; break; } sqlite3TreeViewItem(pView, zOp, 1); } p = p->pPrior; }while( p!=0 ); sqlite3TreeViewPop(&pView); } #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Generate a description of starting or stopping bounds */ SQLITE_PRIVATE void sqlite3TreeViewBound( TreeView *pView, /* View context */ u8 eBound, /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */ Expr *pExpr, /* Value for PRECEDING or FOLLOWING */ u8 moreToFollow /* True if more to follow */ ){ switch( eBound ){ case TK_UNBOUNDED: { sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow); sqlite3TreeViewPop(&pView); break; } case TK_CURRENT: { sqlite3TreeViewItem(pView, "CURRENT", moreToFollow); sqlite3TreeViewPop(&pView); break; } case TK_PRECEDING: { sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow); sqlite3TreeViewExpr(pView, pExpr, 0); sqlite3TreeViewPop(&pView); break; } case TK_FOLLOWING: { sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow); sqlite3TreeViewExpr(pView, pExpr, 0); sqlite3TreeViewPop(&pView); break; } } } #endif /* SQLITE_OMIT_WINDOWFUNC */ #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Generate a human-readable explanation for a Window object */ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){ int nElement = 0; if( pWin==0 ) return; if( pWin->pFilter ){ sqlite3TreeViewItem(pView, "FILTER", 1); sqlite3TreeViewExpr(pView, pWin->pFilter, 0); sqlite3TreeViewPop(&pView); if( pWin->eFrmType==TK_FILTER ) return; } sqlite3TreeViewPush(&pView, more); if( pWin->zName ){ sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin); }else{ sqlite3TreeViewLine(pView, "OVER (%p)", pWin); } if( pWin->zBase ) nElement++; if( pWin->pOrderBy ) nElement++; if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ) nElement++; if( pWin->eExclude ) nElement++; if( pWin->zBase ){ sqlite3TreeViewPush(&pView, (--nElement)>0); sqlite3TreeViewLine(pView, "window: %s", pWin->zBase); sqlite3TreeViewPop(&pView); } if( pWin->pPartition ){ sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY"); } if( pWin->pOrderBy ){ sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY"); } if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ){ char zBuf[30]; const char *zFrmType = "ROWS"; if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE"; if( pWin->eFrmType==TK_GROUPS ) zFrmType = "GROUPS"; sqlite3_snprintf(sizeof(zBuf),zBuf,"%s%s",zFrmType, pWin->bImplicitFrame ? " (implied)" : ""); sqlite3TreeViewItem(pView, zBuf, (--nElement)>0); sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1); sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0); sqlite3TreeViewPop(&pView); } if( pWin->eExclude ){ char zBuf[30]; const char *zExclude; switch( pWin->eExclude ){ case TK_NO: zExclude = "NO OTHERS"; break; case TK_CURRENT: zExclude = "CURRENT ROW"; break; case TK_GROUP: zExclude = "GROUP"; break; case TK_TIES: zExclude = "TIES"; break; default: sqlite3_snprintf(sizeof(zBuf),zBuf,"invalid(%d)", pWin->eExclude); zExclude = zBuf; break; } sqlite3TreeViewPush(&pView, 0); sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude); sqlite3TreeViewPop(&pView); } sqlite3TreeViewPop(&pView); } #endif /* SQLITE_OMIT_WINDOWFUNC */ #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Generate a human-readable explanation for a Window Function object */ SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){ if( pWin==0 ) return; sqlite3TreeViewPush(&pView, more); sqlite3TreeViewLine(pView, "WINFUNC %s(%d)", pWin->pWFunc->zName, pWin->pWFunc->nArg); sqlite3TreeViewWindow(pView, pWin, 0); sqlite3TreeViewPop(&pView); } #endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** Generate a human-readable explanation of an expression tree. */ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ char zFlgs[200]; sqlite3TreeViewPush(&pView, moreToFollow); if( pExpr==0 ){ sqlite3TreeViewLine(pView, "nil"); sqlite3TreeViewPop(&pView); return; } if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags || pExpr->pAggInfo ){ StrAccum x; sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0); sqlite3_str_appendf(&x, " fg.af=%x.%c", pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n'); if( ExprHasProperty(pExpr, EP_OuterON) ){ sqlite3_str_appendf(&x, " outer.iJoin=%d", pExpr->w.iJoin); } if( ExprHasProperty(pExpr, EP_InnerON) ){ sqlite3_str_appendf(&x, " inner.iJoin=%d", pExpr->w.iJoin); } if( ExprHasProperty(pExpr, EP_FromDDL) ){ sqlite3_str_appendf(&x, " DDL"); } if( ExprHasVVAProperty(pExpr, EP_Immutable) ){ sqlite3_str_appendf(&x, " IMMUTABLE"); } if( pExpr->pAggInfo!=0 ){ sqlite3_str_appendf(&x, " agg-column[%d]", pExpr->iAgg); } sqlite3StrAccumFinish(&x); }else{ zFlgs[0] = 0; } switch( pExpr->op ){ case TK_AGG_COLUMN: { sqlite3TreeViewLine(pView, "AGG{%d:%d}%s", pExpr->iTable, pExpr->iColumn, zFlgs); break; } case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ char zOp2[16]; if( pExpr->op2 ){ sqlite3_snprintf(sizeof(zOp2),zOp2," op2=0x%02x",pExpr->op2); }else{ zOp2[0] = 0; } sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s", pExpr->iColumn, zFlgs, zOp2); }else{ assert( ExprUseYTab(pExpr) ); sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s", pExpr->iTable, pExpr->iColumn, pExpr->y.pTab, zFlgs); } if( ExprHasProperty(pExpr, EP_FixedCol) ){ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } break; } case TK_INTEGER: { if( pExpr->flags & EP_IntValue ){ sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); }else{ sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); } break; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_STRING: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; } case TK_NULL: { sqlite3TreeViewLine(pView,"NULL"); break; } case TK_TRUEFALSE: { sqlite3TreeViewLine(pView,"%s%s", sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE", zFlgs); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_VARIABLE: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", pExpr->u.zToken, pExpr->iColumn); break; } case TK_REGISTER: { sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); break; } case TK_ID: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } #endif /* SQLITE_OMIT_CAST */ case TK_LT: zBinOp = "LT"; break; case TK_LE: zBinOp = "LE"; break; case TK_GT: zBinOp = "GT"; break; case TK_GE: zBinOp = "GE"; break; case TK_NE: zBinOp = "NE"; break; case TK_EQ: zBinOp = "EQ"; break; case TK_IS: zBinOp = "IS"; break; case TK_ISNOT: zBinOp = "ISNOT"; break; case TK_AND: zBinOp = "AND"; break; case TK_OR: zBinOp = "OR"; break; case TK_PLUS: zBinOp = "ADD"; break; case TK_STAR: zBinOp = "MUL"; break; case TK_MINUS: zBinOp = "SUB"; break; case TK_REM: zBinOp = "REM"; break; case TK_BITAND: zBinOp = "BITAND"; break; case TK_BITOR: zBinOp = "BITOR"; break; case TK_SLASH: zBinOp = "DIV"; break; case TK_LSHIFT: zBinOp = "LSHIFT"; break; case TK_RSHIFT: zBinOp = "RSHIFT"; break; case TK_CONCAT: zBinOp = "CONCAT"; break; case TK_DOT: zBinOp = "DOT"; break; case TK_LIMIT: zBinOp = "LIMIT"; break; case TK_UMINUS: zUniOp = "UMINUS"; break; case TK_UPLUS: zUniOp = "UPLUS"; break; case TK_BITNOT: zUniOp = "BITNOT"; break; case TK_NOT: zUniOp = "NOT"; break; case TK_ISNULL: zUniOp = "ISNULL"; break; case TK_NOTNULL: zUniOp = "NOTNULL"; break; case TK_TRUTH: { int x; const char *azOp[] = { "IS-FALSE", "IS-TRUE", "IS-NOT-FALSE", "IS-NOT-TRUE" }; assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); assert( pExpr->pRight ); assert( sqlite3ExprSkipCollateAndLikely(pExpr->pRight)->op == TK_TRUEFALSE ); x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); zUniOp = azOp[x]; break; } case TK_SPAN: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } case TK_COLLATE: { /* COLLATE operators without the EP_Collate flag are intended to ** emulate collation associated with a table column. These show ** up in the treeview output as "SOFT-COLLATE". Explicit COLLATE ** operators that appear in the original SQL always have the ** EP_Collate bit set and appear in treeview output as just "COLLATE" */ assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "%sCOLLATE %Q%s", !ExprHasProperty(pExpr, EP_Collate) ? "SOFT-" : "", pExpr->u.zToken, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } case TK_AGG_FUNCTION: case TK_FUNCTION: { ExprList *pFarg; /* List of function arguments */ Window *pWin; if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; pWin = 0; }else{ assert( ExprUseXList(pExpr) ); pFarg = pExpr->x.pList; #ifndef SQLITE_OMIT_WINDOWFUNC pWin = IsWindowFunc(pExpr) ? pExpr->y.pWin : 0; #else pWin = 0; #endif } assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->op==TK_AGG_FUNCTION ){ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p", pExpr->op2, pExpr->u.zToken, zFlgs, pExpr->pAggInfo ? pExpr->pAggInfo->selId : 0, pExpr->iAgg, pExpr->pAggInfo); }else if( pExpr->op2!=0 ){ const char *zOp2; char zBuf[8]; sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x",pExpr->op2); zOp2 = zBuf; if( pExpr->op2==NC_IsCheck ) zOp2 = "NC_IsCheck"; if( pExpr->op2==NC_IdxExpr ) zOp2 = "NC_IdxExpr"; if( pExpr->op2==NC_PartIdx ) zOp2 = "NC_PartIdx"; if( pExpr->op2==NC_GenCol ) zOp2 = "NC_GenCol"; sqlite3TreeViewLine(pView, "FUNCTION %Q%s op2=%s", pExpr->u.zToken, zFlgs, zOp2); }else{ sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs); } if( pFarg ){ sqlite3TreeViewExprList(pView, pFarg, pWin!=0 || pExpr->pLeft, 0); if( pExpr->pLeft ){ Expr *pOB = pExpr->pLeft; assert( pOB->op==TK_ORDER ); assert( ExprUseXList(pOB) ); sqlite3TreeViewExprList(pView, pOB->x.pList, pWin!=0, "ORDERBY"); } } #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ sqlite3TreeViewWindow(pView, pWin, 0); } #endif break; } case TK_ORDER: { sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, "ORDERBY"); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { assert( ExprUseXSelect(pExpr) ); sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { assert( ExprUseXSelect(pExpr) ); sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_IN: { sqlite3_str *pStr = sqlite3_str_new(0); char *z; sqlite3_str_appendf(pStr, "IN flags=0x%x", pExpr->flags); if( pExpr->iTable ) sqlite3_str_appendf(pStr, " iTable=%d",pExpr->iTable); if( ExprHasProperty(pExpr, EP_Subrtn) ){ sqlite3_str_appendf(pStr, " subrtn(%d,%d)", pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); } z = sqlite3_str_finish(pStr); sqlite3TreeViewLine(pView, z); sqlite3_free(z); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); if( ExprUseXSelect(pExpr) ){ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); }else{ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); } break; } #endif /* SQLITE_OMIT_SUBQUERY */ /* ** x BETWEEN y AND z ** ** This is equivalent to ** ** x>=y AND x<=z ** ** X is stored in pExpr->pLeft. ** Y is stored in pExpr->pList->a[0].pExpr. ** Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN: { const Expr *pX, *pY, *pZ; pX = pExpr->pLeft; assert( ExprUseXList(pExpr) ); assert( pExpr->x.pList->nExpr==2 ); pY = pExpr->x.pList->a[0].pExpr; pZ = pExpr->x.pList->a[1].pExpr; sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs); sqlite3TreeViewExpr(pView, pX, 1); sqlite3TreeViewExpr(pView, pY, 1); sqlite3TreeViewExpr(pView, pZ, 0); break; } case TK_TRIGGER: { /* If the opcode is TK_TRIGGER, then the expression is a reference ** to a column in the new.* or old.* pseudo-tables available to ** trigger programs. In this case Expr.iTable is set to 1 for the ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn ** is set to the column of the pseudo-table to read, or to -1 to ** read the rowid field. */ sqlite3TreeViewLine(pView, "%s(%d)", pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); break; } case TK_CASE: { sqlite3TreeViewLine(pView, "CASE"); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); assert( ExprUseXList(pExpr) ); sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { const char *zType = "unk"; switch( pExpr->affExpr ){ case OE_Rollback: zType = "rollback"; break; case OE_Abort: zType = "abort"; break; case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } #endif case TK_MATCH: { sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s", pExpr->iTable, pExpr->iColumn, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pRight, 0); break; } case TK_VECTOR: { char *z = sqlite3_mprintf("VECTOR%s",zFlgs); assert( ExprUseXList(pExpr) ); sqlite3TreeViewBareExprList(pView, pExpr->x.pList, z); sqlite3_free(z); break; } case TK_SELECT_COLUMN: { sqlite3TreeViewLine(pView, "SELECT-COLUMN %d of [0..%d]%s", pExpr->iColumn, pExpr->iTable-1, pExpr->pRight==pExpr->pLeft ? " (SELECT-owner)" : ""); assert( ExprUseXSelect(pExpr->pLeft) ); sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0); break; } case TK_IF_NULL_ROW: { sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } case TK_ERROR: { Expr tmp; sqlite3TreeViewLine(pView, "ERROR"); tmp = *pExpr; tmp.op = pExpr->op2; sqlite3TreeViewExpr(pView, &tmp, 0); break; } case TK_ROW: { if( pExpr->iColumn<=0 ){ sqlite3TreeViewLine(pView, "First FROM table rowid"); }else{ sqlite3TreeViewLine(pView, "First FROM table column %d", pExpr->iColumn-1); } break; } default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break; } } if( zBinOp ){ sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); sqlite3TreeViewExpr(pView, pExpr->pRight, 0); }else if( zUniOp ){ sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } sqlite3TreeViewPop(&pView); } /* ** Generate a human-readable explanation of an expression list. */ SQLITE_PRIVATE void sqlite3TreeViewBareExprList( TreeView *pView, const ExprList *pList, const char *zLabel ){ if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; if( pList==0 ){ sqlite3TreeViewLine(pView, "%s (empty)", zLabel); }else{ int i; sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; inExpr; i++){ int j = pList->a[i].u.x.iOrderByCol; char *zName = pList->a[i].zEName; int moreToFollow = inExpr - 1; if( j || zName ){ sqlite3TreeViewPush(&pView, moreToFollow); moreToFollow = 0; sqlite3TreeViewLine(pView, 0); if( zName ){ switch( pList->a[i].fg.eEName ){ default: fprintf(stdout, "AS %s ", zName); break; case ENAME_TAB: fprintf(stdout, "TABLE-ALIAS-NAME(\"%s\") ", zName); if( pList->a[i].fg.bUsed ) fprintf(stdout, "(used) "); if( pList->a[i].fg.bUsingTerm ) fprintf(stdout, "(USING-term) "); if( pList->a[i].fg.bNoExpand ) fprintf(stdout, "(NoExpand) "); break; case ENAME_SPAN: fprintf(stdout, "SPAN(\"%s\") ", zName); break; } } if( j ){ fprintf(stdout, "iOrderByCol=%d", j); } fprintf(stdout, "\n"); fflush(stdout); } sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow); if( j || zName ){ sqlite3TreeViewPop(&pView); } } } } SQLITE_PRIVATE void sqlite3TreeViewExprList( TreeView *pView, const ExprList *pList, u8 moreToFollow, const char *zLabel ){ sqlite3TreeViewPush(&pView, moreToFollow); sqlite3TreeViewBareExprList(pView, pList, zLabel); sqlite3TreeViewPop(&pView); } /* ** Generate a human-readable explanation of an id-list. */ SQLITE_PRIVATE void sqlite3TreeViewBareIdList( TreeView *pView, const IdList *pList, const char *zLabel ){ if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; if( pList==0 ){ sqlite3TreeViewLine(pView, "%s (empty)", zLabel); }else{ int i; sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; inId; i++){ char *zName = pList->a[i].zName; int moreToFollow = inId - 1; if( zName==0 ) zName = "(null)"; sqlite3TreeViewPush(&pView, moreToFollow); sqlite3TreeViewLine(pView, 0); if( pList->eU4==EU4_NONE ){ fprintf(stdout, "%s\n", zName); }else if( pList->eU4==EU4_IDX ){ fprintf(stdout, "%s (%d)\n", zName, pList->a[i].u4.idx); }else{ assert( pList->eU4==EU4_EXPR ); if( pList->a[i].u4.pExpr==0 ){ fprintf(stdout, "%s (pExpr=NULL)\n", zName); }else{ fprintf(stdout, "%s\n", zName); sqlite3TreeViewPush(&pView, inId-1); sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0); sqlite3TreeViewPop(&pView); } } sqlite3TreeViewPop(&pView); } } } SQLITE_PRIVATE void sqlite3TreeViewIdList( TreeView *pView, const IdList *pList, u8 moreToFollow, const char *zLabel ){ sqlite3TreeViewPush(&pView, moreToFollow); sqlite3TreeViewBareIdList(pView, pList, zLabel); sqlite3TreeViewPop(&pView); } /* ** Generate a human-readable explanation of a list of Upsert objects */ SQLITE_PRIVATE void sqlite3TreeViewUpsert( TreeView *pView, const Upsert *pUpsert, u8 moreToFollow ){ if( pUpsert==0 ) return; sqlite3TreeViewPush(&pView, moreToFollow); while( pUpsert ){ int n; sqlite3TreeViewPush(&pView, pUpsert->pNextUpsert!=0 || moreToFollow); sqlite3TreeViewLine(pView, "ON CONFLICT DO %s", pUpsert->isDoUpdate ? "UPDATE" : "NOTHING"); n = (pUpsert->pUpsertSet!=0) + (pUpsert->pUpsertWhere!=0); sqlite3TreeViewExprList(pView, pUpsert->pUpsertTarget, (n--)>0, "TARGET"); sqlite3TreeViewExprList(pView, pUpsert->pUpsertSet, (n--)>0, "SET"); if( pUpsert->pUpsertWhere ){ sqlite3TreeViewItem(pView, "WHERE", (n--)>0); sqlite3TreeViewExpr(pView, pUpsert->pUpsertWhere, 0); sqlite3TreeViewPop(&pView); } sqlite3TreeViewPop(&pView); pUpsert = pUpsert->pNextUpsert; } sqlite3TreeViewPop(&pView); } #if TREETRACE_ENABLED /* ** Generate a human-readable diagram of the data structure that go ** into generating an DELETE statement. */ SQLITE_PRIVATE void sqlite3TreeViewDelete( const With *pWith, const SrcList *pTabList, const Expr *pWhere, const ExprList *pOrderBy, const Expr *pLimit, const Trigger *pTrigger ){ int n = 0; TreeView *pView = 0; sqlite3TreeViewPush(&pView, 0); sqlite3TreeViewLine(pView, "DELETE"); if( pWith ) n++; if( pTabList ) n++; if( pWhere ) n++; if( pOrderBy ) n++; if( pLimit ) n++; if( pTrigger ) n++; if( pWith ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewWith(pView, pWith, 0); sqlite3TreeViewPop(&pView); } if( pTabList ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewLine(pView, "FROM"); sqlite3TreeViewSrcList(pView, pTabList); sqlite3TreeViewPop(&pView); } if( pWhere ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewLine(pView, "WHERE"); sqlite3TreeViewExpr(pView, pWhere, 0); sqlite3TreeViewPop(&pView); } if( pOrderBy ){ sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY"); } if( pLimit ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewLine(pView, "LIMIT"); sqlite3TreeViewExpr(pView, pLimit, 0); sqlite3TreeViewPop(&pView); } if( pTrigger ){ sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1); } sqlite3TreeViewPop(&pView); } #endif /* TREETRACE_ENABLED */ #if TREETRACE_ENABLED /* ** Generate a human-readable diagram of the data structure that go ** into generating an INSERT statement. */ SQLITE_PRIVATE void sqlite3TreeViewInsert( const With *pWith, const SrcList *pTabList, const IdList *pColumnList, const Select *pSelect, const ExprList *pExprList, int onError, const Upsert *pUpsert, const Trigger *pTrigger ){ TreeView *pView = 0; int n = 0; const char *zLabel = "INSERT"; switch( onError ){ case OE_Replace: zLabel = "REPLACE"; break; case OE_Ignore: zLabel = "INSERT OR IGNORE"; break; case OE_Rollback: zLabel = "INSERT OR ROLLBACK"; break; case OE_Abort: zLabel = "INSERT OR ABORT"; break; case OE_Fail: zLabel = "INSERT OR FAIL"; break; } sqlite3TreeViewPush(&pView, 0); sqlite3TreeViewLine(pView, zLabel); if( pWith ) n++; if( pTabList ) n++; if( pColumnList ) n++; if( pSelect ) n++; if( pExprList ) n++; if( pUpsert ) n++; if( pTrigger ) n++; if( pWith ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewWith(pView, pWith, 0); sqlite3TreeViewPop(&pView); } if( pTabList ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewLine(pView, "INTO"); sqlite3TreeViewSrcList(pView, pTabList); sqlite3TreeViewPop(&pView); } if( pColumnList ){ sqlite3TreeViewIdList(pView, pColumnList, (--n)>0, "COLUMNS"); } if( pSelect ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewLine(pView, "DATA-SOURCE"); sqlite3TreeViewSelect(pView, pSelect, 0); sqlite3TreeViewPop(&pView); } if( pExprList ){ sqlite3TreeViewExprList(pView, pExprList, (--n)>0, "VALUES"); } if( pUpsert ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewLine(pView, "UPSERT"); sqlite3TreeViewUpsert(pView, pUpsert, 0); sqlite3TreeViewPop(&pView); } if( pTrigger ){ sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1); } sqlite3TreeViewPop(&pView); } #endif /* TREETRACE_ENABLED */ #if TREETRACE_ENABLED /* ** Generate a human-readable diagram of the data structure that go ** into generating an UPDATE statement. */ SQLITE_PRIVATE void sqlite3TreeViewUpdate( const With *pWith, const SrcList *pTabList, const ExprList *pChanges, const Expr *pWhere, int onError, const ExprList *pOrderBy, const Expr *pLimit, const Upsert *pUpsert, const Trigger *pTrigger ){ int n = 0; TreeView *pView = 0; const char *zLabel = "UPDATE"; switch( onError ){ case OE_Replace: zLabel = "UPDATE OR REPLACE"; break; case OE_Ignore: zLabel = "UPDATE OR IGNORE"; break; case OE_Rollback: zLabel = "UPDATE OR ROLLBACK"; break; case OE_Abort: zLabel = "UPDATE OR ABORT"; break; case OE_Fail: zLabel = "UPDATE OR FAIL"; break; } sqlite3TreeViewPush(&pView, 0); sqlite3TreeViewLine(pView, zLabel); if( pWith ) n++; if( pTabList ) n++; if( pChanges ) n++; if( pWhere ) n++; if( pOrderBy ) n++; if( pLimit ) n++; if( pUpsert ) n++; if( pTrigger ) n++; if( pWith ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewWith(pView, pWith, 0); sqlite3TreeViewPop(&pView); } if( pTabList ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewLine(pView, "FROM"); sqlite3TreeViewSrcList(pView, pTabList); sqlite3TreeViewPop(&pView); } if( pChanges ){ sqlite3TreeViewExprList(pView, pChanges, (--n)>0, "SET"); } if( pWhere ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewLine(pView, "WHERE"); sqlite3TreeViewExpr(pView, pWhere, 0); sqlite3TreeViewPop(&pView); } if( pOrderBy ){ sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY"); } if( pLimit ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewLine(pView, "LIMIT"); sqlite3TreeViewExpr(pView, pLimit, 0); sqlite3TreeViewPop(&pView); } if( pUpsert ){ sqlite3TreeViewPush(&pView, (--n)>0); sqlite3TreeViewLine(pView, "UPSERT"); sqlite3TreeViewUpsert(pView, pUpsert, 0); sqlite3TreeViewPop(&pView); } if( pTrigger ){ sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1); } sqlite3TreeViewPop(&pView); } #endif /* TREETRACE_ENABLED */ #ifndef SQLITE_OMIT_TRIGGER /* ** Show a human-readable graph of a TriggerStep */ SQLITE_PRIVATE void sqlite3TreeViewTriggerStep( TreeView *pView, const TriggerStep *pStep, u8 moreToFollow, u8 showFullList ){ int cnt = 0; if( pStep==0 ) return; sqlite3TreeViewPush(&pView, moreToFollow || (showFullList && pStep->pNext!=0)); do{ if( cnt++ && pStep->pNext==0 ){ sqlite3TreeViewPop(&pView); sqlite3TreeViewPush(&pView, 0); } sqlite3TreeViewLine(pView, "%s", pStep->zSpan ? pStep->zSpan : "RETURNING"); }while( showFullList && (pStep = pStep->pNext)!=0 ); sqlite3TreeViewPop(&pView); } /* ** Show a human-readable graph of a Trigger */ SQLITE_PRIVATE void sqlite3TreeViewTrigger( TreeView *pView, const Trigger *pTrigger, u8 moreToFollow, u8 showFullList ){ int cnt = 0; if( pTrigger==0 ) return; sqlite3TreeViewPush(&pView, moreToFollow || (showFullList && pTrigger->pNext!=0)); do{ if( cnt++ && pTrigger->pNext==0 ){ sqlite3TreeViewPop(&pView); sqlite3TreeViewPush(&pView, 0); } sqlite3TreeViewLine(pView, "TRIGGER %s", pTrigger->zName); sqlite3TreeViewPush(&pView, 0); sqlite3TreeViewTriggerStep(pView, pTrigger->step_list, 0, 1); sqlite3TreeViewPop(&pView); }while( showFullList && (pTrigger = pTrigger->pNext)!=0 ); sqlite3TreeViewPop(&pView); } #endif /* SQLITE_OMIT_TRIGGER */ /* ** These simplified versions of the tree-view routines omit unnecessary ** parameters. These variants are intended to be used from a symbolic ** debugger, such as "gdb", during interactive debugging sessions. ** ** This routines are given external linkage so that they will always be ** accessible to the debugging, and to avoid warnings about unused ** functions. But these routines only exist in debugging builds, so they ** do not contaminate the interface. */ SQLITE_PRIVATE void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); } SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);} SQLITE_PRIVATE void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); } SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); } SQLITE_PRIVATE void sqlite3ShowSelect(const Select *p){ sqlite3TreeViewSelect(0,p,0); } SQLITE_PRIVATE void sqlite3ShowWith(const With *p){ sqlite3TreeViewWith(0,p,0); } SQLITE_PRIVATE void sqlite3ShowUpsert(const Upsert *p){ sqlite3TreeViewUpsert(0,p,0); } #ifndef SQLITE_OMIT_TRIGGER SQLITE_PRIVATE void sqlite3ShowTriggerStep(const TriggerStep *p){ sqlite3TreeViewTriggerStep(0,p,0,0); } SQLITE_PRIVATE void sqlite3ShowTriggerStepList(const TriggerStep *p){ sqlite3TreeViewTriggerStep(0,p,0,1); } SQLITE_PRIVATE void sqlite3ShowTrigger(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,0); } SQLITE_PRIVATE void sqlite3ShowTriggerList(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,1);} #endif #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE void sqlite3ShowWindow(const Window *p){ sqlite3TreeViewWindow(0,p,0); } SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window *p){ sqlite3TreeViewWinFunc(0,p,0); } #endif #endif /* SQLITE_DEBUG */ /************** End of treeview.c ********************************************/ /************** Begin file random.c ******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code to implement a pseudo-random number ** generator (PRNG) for SQLite. ** ** Random numbers are used by some of the database backends in order ** to generate random integer keys for tables or random filenames. */ /* #include "sqliteInt.h" */ /* All threads share a single random number generator. ** This structure is the current state of the generator. */ static SQLITE_WSD struct sqlite3PrngType { u32 s[16]; /* 64 bytes of chacha20 state */ u8 out[64]; /* Output bytes */ u8 n; /* Output bytes remaining */ } sqlite3Prng; /* The RFC-7539 ChaCha20 block function */ #define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) #define QR(a, b, c, d) ( \ a += b, d ^= a, d = ROTL(d,16), \ c += d, b ^= c, b = ROTL(b,12), \ a += b, d ^= a, d = ROTL(d, 8), \ c += d, b ^= c, b = ROTL(b, 7)) static void chacha_block(u32 *out, const u32 *in){ int i; u32 x[16]; memcpy(x, in, 64); for(i=0; i<10; i++){ QR(x[0], x[4], x[ 8], x[12]); QR(x[1], x[5], x[ 9], x[13]); QR(x[2], x[6], x[10], x[14]); QR(x[3], x[7], x[11], x[15]); QR(x[0], x[5], x[10], x[15]); QR(x[1], x[6], x[11], x[12]); QR(x[2], x[7], x[ 8], x[13]); QR(x[3], x[4], x[ 9], x[14]); } for(i=0; i<16; i++) out[i] = x[i]+in[i]; } /* ** Return N random bytes. */ SQLITE_API void sqlite3_randomness(int N, void *pBuf){ unsigned char *zBuf = pBuf; /* The "wsdPrng" macro will resolve to the pseudo-random number generator ** state vector. If writable static data is unsupported on the target, ** we have to locate the state vector at run-time. In the more common ** case where writable static data is supported, wsdPrng can refer directly ** to the "sqlite3Prng" state vector declared above. */ #ifdef SQLITE_OMIT_WSD struct sqlite3PrngType *p = &GLOBAL(struct sqlite3PrngType, sqlite3Prng); # define wsdPrng p[0] #else # define wsdPrng sqlite3Prng #endif #if SQLITE_THREADSAFE sqlite3_mutex *mutex; #endif #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return; #endif #if SQLITE_THREADSAFE mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); #endif sqlite3_mutex_enter(mutex); if( N<=0 || pBuf==0 ){ wsdPrng.s[0] = 0; sqlite3_mutex_leave(mutex); return; } /* Initialize the state of the random number generator once, ** the first time this routine is called. */ if( wsdPrng.s[0]==0 ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); static const u32 chacha20_init[] = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; memcpy(&wsdPrng.s[0], chacha20_init, 16); if( NEVER(pVfs==0) ){ memset(&wsdPrng.s[4], 0, 44); }else{ sqlite3OsRandomness(pVfs, 44, (char*)&wsdPrng.s[4]); } wsdPrng.s[15] = wsdPrng.s[12]; wsdPrng.s[12] = 0; wsdPrng.n = 0; } assert( N>0 ); while( 1 /* exit by break */ ){ if( N<=wsdPrng.n ){ memcpy(zBuf, &wsdPrng.out[wsdPrng.n-N], N); wsdPrng.n -= N; break; } if( wsdPrng.n>0 ){ memcpy(zBuf, wsdPrng.out, wsdPrng.n); N -= wsdPrng.n; zBuf += wsdPrng.n; } wsdPrng.s[12]++; chacha_block((u32*)wsdPrng.out, wsdPrng.s); wsdPrng.n = 64; } sqlite3_mutex_leave(mutex); } #ifndef SQLITE_UNTESTABLE /* ** For testing purposes, we sometimes want to preserve the state of ** PRNG and restore the PRNG to its saved state at a later time, or ** to reset the PRNG to its initial state. These routines accomplish ** those tasks. ** ** The sqlite3_test_control() interface calls these routines to ** control the PRNG. */ static SQLITE_WSD struct sqlite3PrngType sqlite3SavedPrng; SQLITE_PRIVATE void sqlite3PrngSaveState(void){ memcpy( &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng), &GLOBAL(struct sqlite3PrngType, sqlite3Prng), sizeof(sqlite3Prng) ); } SQLITE_PRIVATE void sqlite3PrngRestoreState(void){ memcpy( &GLOBAL(struct sqlite3PrngType, sqlite3Prng), &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng), sizeof(sqlite3Prng) ); } #endif /* SQLITE_UNTESTABLE */ /************** End of random.c **********************************************/ /************** Begin file threads.c *****************************************/ /* ** 2012 July 21 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file presents a simple cross-platform threading interface for ** use internally by SQLite. ** ** A "thread" can be created using sqlite3ThreadCreate(). This thread ** runs independently of its creator until it is joined using ** sqlite3ThreadJoin(), at which point it terminates. ** ** Threads do not have to be real. It could be that the work of the ** "thread" is done by the main thread at either the sqlite3ThreadCreate() ** or sqlite3ThreadJoin() call. This is, in fact, what happens in ** single threaded systems. Nothing in SQLite requires multiple threads. ** This interface exists so that applications that want to take advantage ** of multiple cores can do so, while also allowing applications to stay ** single-threaded if desired. */ /* #include "sqliteInt.h" */ #if SQLITE_OS_WIN /* # include "os_win.h" */ #endif #if SQLITE_MAX_WORKER_THREADS>0 /********************************* Unix Pthreads ****************************/ #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ /* #include */ /* A running thread */ struct SQLiteThread { pthread_t tid; /* Thread ID */ int done; /* Set to true when thread finishes */ void *pOut; /* Result returned by the thread */ void *(*xTask)(void*); /* The thread routine */ void *pIn; /* Argument to the thread */ }; /* Create a new thread */ SQLITE_PRIVATE int sqlite3ThreadCreate( SQLiteThread **ppThread, /* OUT: Write the thread object here */ void *(*xTask)(void*), /* Routine to run in a separate thread */ void *pIn /* Argument passed into xTask() */ ){ SQLiteThread *p; int rc; assert( ppThread!=0 ); assert( xTask!=0 ); /* This routine is never used in single-threaded mode */ assert( sqlite3GlobalConfig.bCoreMutex!=0 ); *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); if( p==0 ) return SQLITE_NOMEM_BKPT; memset(p, 0, sizeof(*p)); p->xTask = xTask; p->pIn = pIn; /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a ** function that returns SQLITE_ERROR when passed the argument 200, that ** forces worker threads to run sequentially and deterministically ** for testing purposes. */ if( sqlite3FaultSim(200) ){ rc = 1; }else{ rc = pthread_create(&p->tid, 0, xTask, pIn); } if( rc ){ p->done = 1; p->pOut = xTask(pIn); } *ppThread = p; return SQLITE_OK; } /* Get the results of the thread */ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ int rc; assert( ppOut!=0 ); if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; if( p->done ){ *ppOut = p->pOut; rc = SQLITE_OK; }else{ rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK; } sqlite3_free(p); return rc; } #endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */ /******************************** End Unix Pthreads *************************/ /********************************* Win32 Threads ****************************/ #if SQLITE_OS_WIN_THREADS #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ #include /* A running thread */ struct SQLiteThread { void *tid; /* The thread handle */ unsigned id; /* The thread identifier */ void *(*xTask)(void*); /* The routine to run as a thread */ void *pIn; /* Argument to xTask */ void *pResult; /* Result of xTask */ }; /* Thread procedure Win32 compatibility shim */ static unsigned __stdcall sqlite3ThreadProc( void *pArg /* IN: Pointer to the SQLiteThread structure */ ){ SQLiteThread *p = (SQLiteThread *)pArg; assert( p!=0 ); #if 0 /* ** This assert appears to trigger spuriously on certain ** versions of Windows, possibly due to _beginthreadex() ** and/or CreateThread() not fully setting their thread ** ID parameter before starting the thread. */ assert( p->id==GetCurrentThreadId() ); #endif assert( p->xTask!=0 ); p->pResult = p->xTask(p->pIn); _endthreadex(0); return 0; /* NOT REACHED */ } /* Create a new thread */ SQLITE_PRIVATE int sqlite3ThreadCreate( SQLiteThread **ppThread, /* OUT: Write the thread object here */ void *(*xTask)(void*), /* Routine to run in a separate thread */ void *pIn /* Argument passed into xTask() */ ){ SQLiteThread *p; assert( ppThread!=0 ); assert( xTask!=0 ); *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); if( p==0 ) return SQLITE_NOMEM_BKPT; /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a ** function that returns SQLITE_ERROR when passed the argument 200, that ** forces worker threads to run sequentially and deterministically ** (via the sqlite3FaultSim() term of the conditional) for testing ** purposes. */ if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){ memset(p, 0, sizeof(*p)); }else{ p->xTask = xTask; p->pIn = pIn; p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id); if( p->tid==0 ){ memset(p, 0, sizeof(*p)); } } if( p->xTask==0 ){ p->id = GetCurrentThreadId(); p->pResult = xTask(pIn); } *ppThread = p; return SQLITE_OK; } SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */ /* Get the results of the thread */ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ DWORD rc; BOOL bRc; assert( ppOut!=0 ); if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; if( p->xTask==0 ){ /* assert( p->id==GetCurrentThreadId() ); */ rc = WAIT_OBJECT_0; assert( p->tid==0 ); }else{ assert( p->id!=0 && p->id!=GetCurrentThreadId() ); rc = sqlite3Win32Wait((HANDLE)p->tid); assert( rc!=WAIT_IO_COMPLETION ); bRc = CloseHandle((HANDLE)p->tid); assert( bRc ); } if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; sqlite3_free(p); return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; } #endif /* SQLITE_OS_WIN_THREADS */ /******************************** End Win32 Threads *************************/ /********************************* Single-Threaded **************************/ #ifndef SQLITE_THREADS_IMPLEMENTED /* ** This implementation does not actually create a new thread. It does the ** work of the thread in the main thread, when either the thread is created ** or when it is joined */ /* A running thread */ struct SQLiteThread { void *(*xTask)(void*); /* The routine to run as a thread */ void *pIn; /* Argument to xTask */ void *pResult; /* Result of xTask */ }; /* Create a new thread */ SQLITE_PRIVATE int sqlite3ThreadCreate( SQLiteThread **ppThread, /* OUT: Write the thread object here */ void *(*xTask)(void*), /* Routine to run in a separate thread */ void *pIn /* Argument passed into xTask() */ ){ SQLiteThread *p; assert( ppThread!=0 ); assert( xTask!=0 ); *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); if( p==0 ) return SQLITE_NOMEM_BKPT; if( (SQLITE_PTR_TO_INT(p)/17)&1 ){ p->xTask = xTask; p->pIn = pIn; }else{ p->xTask = 0; p->pResult = xTask(pIn); } *ppThread = p; return SQLITE_OK; } /* Get the results of the thread */ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ assert( ppOut!=0 ); if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; if( p->xTask ){ *ppOut = p->xTask(p->pIn); }else{ *ppOut = p->pResult; } sqlite3_free(p); #if defined(SQLITE_TEST) { void *pTstAlloc = sqlite3Malloc(10); if (!pTstAlloc) return SQLITE_NOMEM_BKPT; sqlite3_free(pTstAlloc); } #endif return SQLITE_OK; } #endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */ /****************************** End Single-Threaded *************************/ #endif /* SQLITE_MAX_WORKER_THREADS>0 */ /************** End of threads.c *********************************************/ /************** Begin file utf.c *********************************************/ /* ** 2004 April 13 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used to translate between UTF-8, ** UTF-16, UTF-16BE, and UTF-16LE. ** ** Notes on UTF-8: ** ** Byte-0 Byte-1 Byte-2 Byte-3 Value ** 0xxxxxxx 00000000 00000000 0xxxxxxx ** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx ** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx ** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx ** ** ** Notes on UTF-16: (with wwww+1==uuuuu) ** ** Word-0 Word-1 Value ** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx ** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx ** ** ** BOM or Byte Order Mark: ** 0xff 0xfe little-endian utf-16 follows ** 0xfe 0xff big-endian utf-16 follows ** */ /* #include "sqliteInt.h" */ /* #include */ /* #include "vdbeInt.h" */ #if !defined(SQLITE_AMALGAMATION) && SQLITE_BYTEORDER==0 /* ** The following constant value is used by the SQLITE_BIGENDIAN and ** SQLITE_LITTLEENDIAN macros. */ SQLITE_PRIVATE const int sqlite3one = 1; #endif /* SQLITE_AMALGAMATION && SQLITE_BYTEORDER==0 */ /* ** This lookup table is used to help decode the first byte of ** a multi-byte UTF8 character. */ static const unsigned char sqlite3Utf8Trans1[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, }; #define WRITE_UTF8(zOut, c) { \ if( c<0x00080 ){ \ *zOut++ = (u8)(c&0xFF); \ } \ else if( c<0x00800 ){ \ *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); \ *zOut++ = 0x80 + (u8)(c & 0x3F); \ } \ else if( c<0x10000 ){ \ *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ *zOut++ = 0x80 + (u8)(c & 0x3F); \ }else{ \ *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \ *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ *zOut++ = 0x80 + (u8)(c & 0x3F); \ } \ } #define WRITE_UTF16LE(zOut, c) { \ if( c<=0xFFFF ){ \ *zOut++ = (u8)(c&0x00FF); \ *zOut++ = (u8)((c>>8)&0x00FF); \ }else{ \ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \ *zOut++ = (u8)(c&0x00FF); \ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \ } \ } #define WRITE_UTF16BE(zOut, c) { \ if( c<=0xFFFF ){ \ *zOut++ = (u8)((c>>8)&0x00FF); \ *zOut++ = (u8)(c&0x00FF); \ }else{ \ *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \ *zOut++ = (u8)(c&0x00FF); \ } \ } /* ** Translate a single UTF-8 character. Return the unicode value. ** ** During translation, assume that the byte that zTerm points ** is a 0x00. ** ** Write a pointer to the next unread byte back into *pzNext. ** ** Notes On Invalid UTF-8: ** ** * This routine never allows a 7-bit character (0x00 through 0x7f) to ** be encoded as a multi-byte character. Any multi-byte character that ** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd. ** ** * This routine never allows a UTF16 surrogate value to be encoded. ** If a multi-byte character attempts to encode a value between ** 0xd800 and 0xe000 then it is rendered as 0xfffd. ** ** * Bytes in the range of 0x80 through 0xbf which occur as the first ** byte of a character are interpreted as single-byte characters ** and rendered as themselves even though they are technically ** invalid characters. ** ** * This routine accepts over-length UTF8 encodings ** for unicode values 0x80 and greater. It does not change over-length ** encodings to 0xfffd as some systems recommend. */ #define READ_UTF8(zIn, zTerm, c) \ c = *(zIn++); \ if( c>=0xc0 ){ \ c = sqlite3Utf8Trans1[c-0xc0]; \ while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ c = (c<<6) + (0x3f & *(zIn++)); \ } \ if( c<0x80 \ || (c&0xFFFFF800)==0xD800 \ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ } SQLITE_PRIVATE u32 sqlite3Utf8Read( const unsigned char **pz /* Pointer to string from which to read char */ ){ unsigned int c; /* Same as READ_UTF8() above but without the zTerm parameter. ** For this routine, we assume the UTF8 string is always zero-terminated. */ c = *((*pz)++); if( c>=0xc0 ){ c = sqlite3Utf8Trans1[c-0xc0]; while( (*(*pz) & 0xc0)==0x80 ){ c = (c<<6) + (0x3f & *((*pz)++)); } if( c<0x80 || (c&0xFFFFF800)==0xD800 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } } return c; } /* ** Read a single UTF8 character out of buffer z[], but reading no ** more than n characters from the buffer. z[] is not zero-terminated. ** ** Return the number of bytes used to construct the character. ** ** Invalid UTF8 might generate a strange result. No effort is made ** to detect invalid UTF8. ** ** At most 4 bytes will be read out of z[]. The return value will always ** be between 1 and 4. */ SQLITE_PRIVATE int sqlite3Utf8ReadLimited( const u8 *z, int n, u32 *piOut ){ u32 c; int i = 1; assert( n>0 ); c = z[0]; if( c>=0xc0 ){ c = sqlite3Utf8Trans1[c-0xc0]; if( n>4 ) n = 4; while( idb==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( pMem->flags&MEM_Str ); assert( pMem->enc!=desiredEnc ); assert( pMem->enc!=0 ); assert( pMem->n>=0 ); #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) { StrAccum acc; char zBuf[1000]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); sqlite3VdbeMemPrettyPrint(pMem, &acc); fprintf(stderr, "INPUT: %s\n", sqlite3StrAccumFinish(&acc)); } #endif /* If the translation is between UTF-16 little and big endian, then ** all that is required is to swap the byte order. This case is handled ** differently from the others. */ if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){ u8 temp; int rc; rc = sqlite3VdbeMemMakeWriteable(pMem); if( rc!=SQLITE_OK ){ assert( rc==SQLITE_NOMEM ); return SQLITE_NOMEM_BKPT; } zIn = (u8*)pMem->z; zTerm = &zIn[pMem->n&~1]; while( zInenc = desiredEnc; goto translate_out; } /* Set len to the maximum number of bytes required in the output buffer. */ if( desiredEnc==SQLITE_UTF8 ){ /* When converting from UTF-16, the maximum growth results from ** translating a 2-byte character to a 4-byte UTF-8 character. ** A single byte is required for the output string ** nul-terminator. */ pMem->n &= ~1; len = 2 * (sqlite3_int64)pMem->n + 1; }else{ /* When converting from UTF-8 to UTF-16 the maximum growth is caused ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16 ** character. Two bytes are required in the output buffer for the ** nul-terminator. */ len = 2 * (sqlite3_int64)pMem->n + 2; } /* Set zIn to point at the start of the input buffer and zTerm to point 1 ** byte past the end. ** ** Variable zOut is set to point at the output buffer, space obtained ** from sqlite3_malloc(). */ zIn = (u8*)pMem->z; zTerm = &zIn[pMem->n]; zOut = sqlite3DbMallocRaw(pMem->db, len); if( !zOut ){ return SQLITE_NOMEM_BKPT; } z = zOut; if( pMem->enc==SQLITE_UTF8 ){ if( desiredEnc==SQLITE_UTF16LE ){ /* UTF-8 -> UTF-16 Little-endian */ while( zIn UTF-16 Big-endian */ while( zInn = (int)(z - zOut); *z++ = 0; }else{ assert( desiredEnc==SQLITE_UTF8 ); if( pMem->enc==SQLITE_UTF16LE ){ /* UTF-16 Little-endian -> UTF-8 */ while( zIn=0xd800 && c<0xe000 ){ #ifdef SQLITE_REPLACE_INVALID_UTF if( c>=0xdc00 || zIn>=zTerm ){ c = 0xfffd; }else{ int c2 = *(zIn++); c2 += (*(zIn++))<<8; if( c2<0xdc00 || c2>=0xe000 ){ zIn -= 2; c = 0xfffd; }else{ c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000; } } #else if( zIn UTF-8 */ while( zIn=0xd800 && c<0xe000 ){ #ifdef SQLITE_REPLACE_INVALID_UTF if( c>=0xdc00 || zIn>=zTerm ){ c = 0xfffd; }else{ int c2 = (*(zIn++))<<8; c2 += *(zIn++); if( c2<0xdc00 || c2>=0xe000 ){ zIn -= 2; c = 0xfffd; }else{ c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000; } } #else if( zInn = (int)(z - zOut); } *z = 0; assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); c = MEM_Str|MEM_Term|(pMem->flags&(MEM_AffMask|MEM_Subtype)); sqlite3VdbeMemRelease(pMem); pMem->flags = c; pMem->enc = desiredEnc; pMem->z = (char*)zOut; pMem->zMalloc = pMem->z; pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->z); translate_out: #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) { StrAccum acc; char zBuf[1000]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); sqlite3VdbeMemPrettyPrint(pMem, &acc); fprintf(stderr, "OUTPUT: %s\n", sqlite3StrAccumFinish(&acc)); } #endif return SQLITE_OK; } #endif /* SQLITE_OMIT_UTF16 */ #ifndef SQLITE_OMIT_UTF16 /* ** This routine checks for a byte-order mark at the beginning of the ** UTF-16 string stored in *pMem. If one is present, it is removed and ** the encoding of the Mem adjusted. This routine does not do any ** byte-swapping, it just sets Mem.enc appropriately. ** ** The allocation (static, dynamic etc.) and encoding of the Mem may be ** changed by this function. */ SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){ int rc = SQLITE_OK; u8 bom = 0; assert( pMem->n>=0 ); if( pMem->n>1 ){ u8 b1 = *(u8 *)pMem->z; u8 b2 = *(((u8 *)pMem->z) + 1); if( b1==0xFE && b2==0xFF ){ bom = SQLITE_UTF16BE; } if( b1==0xFF && b2==0xFE ){ bom = SQLITE_UTF16LE; } } if( bom ){ rc = sqlite3VdbeMemMakeWriteable(pMem); if( rc==SQLITE_OK ){ pMem->n -= 2; memmove(pMem->z, &pMem->z[2], pMem->n); pMem->z[pMem->n] = '\0'; pMem->z[pMem->n+1] = '\0'; pMem->flags |= MEM_Term; pMem->enc = bom; } } return rc; } #endif /* SQLITE_OMIT_UTF16 */ /* ** pZ is a UTF-8 encoded unicode string. If nByte is less than zero, ** return the number of unicode characters in pZ up to (but not including) ** the first 0x00 byte. If nByte is not less than zero, return the ** number of unicode characters in the first nByte of pZ (or up to ** the first 0x00, whichever comes first). */ SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){ int r = 0; const u8 *z = (const u8*)zIn; const u8 *zTerm; if( nByte>=0 ){ zTerm = &z[nByte]; }else{ zTerm = (const u8*)(-1); } assert( z<=zTerm ); while( *z!=0 && zmallocFailed ){ sqlite3VdbeMemRelease(&m); m.z = 0; } assert( (m.flags & MEM_Term)!=0 || db->mallocFailed ); assert( (m.flags & MEM_Str)!=0 || db->mallocFailed ); assert( m.z || db->mallocFailed ); return m.z; } /* ** zIn is a UTF-16 encoded unicode string at least nChar characters long. ** Return the number of bytes in the first nChar unicode characters ** in pZ. nChar must be non-negative. */ SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){ int c; unsigned char const *z = zIn; int n = 0; if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++; while( n=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2; n++; } return (int)(z-(unsigned char const *)zIn) - (SQLITE_UTF16NATIVE==SQLITE_UTF16LE); } #if defined(SQLITE_TEST) /* ** This routine is called from the TCL test function "translate_selftest". ** It checks that the primitives for serializing and deserializing ** characters in each encoding are inverses of each other. */ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){ unsigned int i, t; unsigned char zBuf[20]; unsigned char *z; int n; unsigned int c; for(i=0; i<0x00110000; i++){ z = zBuf; WRITE_UTF8(z, i); n = (int)(z-zBuf); assert( n>0 && n<=4 ); z[0] = 0; z = zBuf; c = sqlite3Utf8Read((const u8**)&z); t = i; if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD; if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD; assert( c==t ); assert( (z-zBuf)==n ); } } #endif /* SQLITE_TEST */ #endif /* SQLITE_OMIT_UTF16 */ /************** End of utf.c *************************************************/ /************** Begin file util.c ********************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** */ /* #include "sqliteInt.h" */ /* #include */ #ifndef SQLITE_OMIT_FLOATING_POINT #include #endif /* ** Calls to sqlite3FaultSim() are used to simulate a failure during testing, ** or to bypass normal error detection during testing in order to let ** execute proceed further downstream. ** ** In deployment, sqlite3FaultSim() *always* return SQLITE_OK (0). The ** sqlite3FaultSim() function only returns non-zero during testing. ** ** During testing, if the test harness has set a fault-sim callback using ** a call to sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL), then ** each call to sqlite3FaultSim() is relayed to that application-supplied ** callback and the integer return value form the application-supplied ** callback is returned by sqlite3FaultSim(). ** ** The integer argument to sqlite3FaultSim() is a code to identify which ** sqlite3FaultSim() instance is being invoked. Each call to sqlite3FaultSim() ** should have a unique code. To prevent legacy testing applications from ** breaking, the codes should not be changed or reused. */ #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback; return xCallback ? xCallback(iTest) : SQLITE_OK; } #endif #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Return true if the floating point value is Not a Number (NaN). ** ** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN. ** Otherwise, we have our own implementation that works on most systems. */ SQLITE_PRIVATE int sqlite3IsNaN(double x){ int rc; /* The value return */ #if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN u64 y; memcpy(&y,&x,sizeof(y)); rc = IsNaN(y); #else rc = isnan(x); #endif /* HAVE_ISNAN */ testcase( rc ); return rc; } #endif /* SQLITE_OMIT_FLOATING_POINT */ /* ** Compute a string length that is limited to what can be stored in ** lower 30 bits of a 32-bit signed integer. ** ** The value returned will never be negative. Nor will it ever be greater ** than the actual length of the string. For very long strings (greater ** than 1GiB) the value returned might be less than the true string length. */ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){ if( z==0 ) return 0; return 0x3fffffff & (int)strlen(z); } /* ** Return the declared type of a column. Or return zDflt if the column ** has no declared type. ** ** The column type is an extra string stored after the zero-terminator on ** the column name if and only if the COLFLAG_HASTYPE flag is set. */ SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){ if( pCol->colFlags & COLFLAG_HASTYPE ){ return pCol->zCnName + strlen(pCol->zCnName) + 1; }else if( pCol->eCType ){ assert( pCol->eCType<=SQLITE_N_STDTYPE ); return (char*)sqlite3StdType[pCol->eCType-1]; }else{ return zDflt; } } /* ** Helper function for sqlite3Error() - called rarely. Broken out into ** a separate routine to avoid unnecessary register saves on entry to ** sqlite3Error(). */ static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){ if( db->pErr ) sqlite3ValueSetNull(db->pErr); sqlite3SystemError(db, err_code); } /* ** Set the current error code to err_code and clear any prior error message. ** Also set iSysErrno (by calling sqlite3System) if the err_code indicates ** that would be appropriate. */ SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){ assert( db!=0 ); db->errCode = err_code; if( err_code || db->pErr ){ sqlite3ErrorFinish(db, err_code); }else{ db->errByteOffset = -1; } } /* ** The equivalent of sqlite3Error(db, SQLITE_OK). Clear the error state ** and error message. */ SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3 *db){ assert( db!=0 ); db->errCode = SQLITE_OK; db->errByteOffset = -1; if( db->pErr ) sqlite3ValueSetNull(db->pErr); } /* ** Load the sqlite3.iSysErrno field if that is an appropriate thing ** to do based on the SQLite error code in rc. */ SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){ if( rc==SQLITE_IOERR_NOMEM ) return; #if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL) if( rc==SQLITE_IOERR_IN_PAGE ){ int ii; int iErr; sqlite3BtreeEnterAll(db); for(ii=0; iinDb; ii++){ if( db->aDb[ii].pBt ){ iErr = sqlite3PagerWalSystemErrno(sqlite3BtreePager(db->aDb[ii].pBt)); if( iErr ){ db->iSysErrno = iErr; } } } sqlite3BtreeLeaveAll(db); return; } #endif rc &= 0xff; if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){ db->iSysErrno = sqlite3OsGetLastError(db->pVfs); } } /* ** Set the most recent error code and error string for the sqlite ** handle "db". The error code is set to "err_code". ** ** If it is not NULL, string zFormat specifies the format of the ** error string. zFormat and any string tokens that follow it are ** assumed to be encoded in UTF-8. ** ** To clear the most recent error for sqlite handle "db", sqlite3Error ** should be called with err_code set to SQLITE_OK and zFormat set ** to NULL. */ SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){ assert( db!=0 ); db->errCode = err_code; sqlite3SystemError(db, err_code); if( zFormat==0 ){ sqlite3Error(db, err_code); }else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){ char *z; va_list ap; va_start(ap, zFormat); z = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC); } } /* ** Check for interrupts and invoke progress callback. */ SQLITE_PRIVATE void sqlite3ProgressCheck(Parse *p){ sqlite3 *db = p->db; if( AtomicLoad(&db->u1.isInterrupted) ){ p->nErr++; p->rc = SQLITE_INTERRUPT; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( db->xProgress ){ if( p->rc==SQLITE_INTERRUPT ){ p->nProgressSteps = 0; }else if( (++p->nProgressSteps)>=db->nProgressOps ){ if( db->xProgress(db->pProgressArg) ){ p->nErr++; p->rc = SQLITE_INTERRUPT; } p->nProgressSteps = 0; } } #endif } /* ** Add an error message to pParse->zErrMsg and increment pParse->nErr. ** ** This function should be used to report any error that occurs while ** compiling an SQL statement (i.e. within sqlite3_prepare()). The ** last thing the sqlite3_prepare() function does is copy the error ** stored by this function into the database handle using sqlite3Error(). ** Functions sqlite3Error() or sqlite3ErrorWithMsg() should be used ** during statement execution (sqlite3_step() etc.). */ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ char *zMsg; va_list ap; sqlite3 *db = pParse->db; assert( db!=0 ); assert( db->pParse==pParse || db->pParse->pToplevel==pParse ); db->errByteOffset = -2; va_start(ap, zFormat); zMsg = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); if( db->errByteOffset<-1 ) db->errByteOffset = -1; if( db->suppressErr ){ sqlite3DbFree(db, zMsg); if( db->mallocFailed ){ pParse->nErr++; pParse->rc = SQLITE_NOMEM; } }else{ pParse->nErr++; sqlite3DbFree(db, pParse->zErrMsg); pParse->zErrMsg = zMsg; pParse->rc = SQLITE_ERROR; pParse->pWith = 0; } } /* ** If database connection db is currently parsing SQL, then transfer ** error code errCode to that parser if the parser has not already ** encountered some other kind of error. */ SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3 *db, int errCode){ Parse *pParse; if( db==0 || (pParse = db->pParse)==0 ) return errCode; pParse->rc = errCode; pParse->nErr++; return errCode; } /* ** Convert an SQL-style quoted string into a normal string by removing ** the quote characters. The conversion is done in-place. If the ** input does not begin with a quote character, then this routine ** is a no-op. ** ** The input string must be zero-terminated. A new zero-terminator ** is added to the dequoted string. ** ** The return value is -1 if no dequoting occurs or the length of the ** dequoted string, exclusive of the zero terminator, if dequoting does ** occur. ** ** 2002-02-14: This routine is extended to remove MS-Access style ** brackets from around identifiers. For example: "[a-b-c]" becomes ** "a-b-c". */ SQLITE_PRIVATE void sqlite3Dequote(char *z){ char quote; int i, j; if( z==0 ) return; quote = z[0]; if( !sqlite3Isquote(quote) ) return; if( quote=='[' ) quote = ']'; for(i=1, j=0;; i++){ assert( z[i] ); if( z[i]==quote ){ if( z[i+1]==quote ){ z[j++] = quote; i++; }else{ break; } }else{ z[j++] = z[i]; } } z[j] = 0; } SQLITE_PRIVATE void sqlite3DequoteExpr(Expr *p){ assert( !ExprHasProperty(p, EP_IntValue) ); assert( sqlite3Isquote(p->u.zToken[0]) ); p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted; sqlite3Dequote(p->u.zToken); } /* ** If the input token p is quoted, try to adjust the token to remove ** the quotes. This is not always possible: ** ** "abc" -> abc ** "ab""cd" -> (not possible because of the interior "") ** ** Remove the quotes if possible. This is a optimization. The overall ** system should still return the correct answer even if this routine ** is always a no-op. */ SQLITE_PRIVATE void sqlite3DequoteToken(Token *p){ unsigned int i; if( p->n<2 ) return; if( !sqlite3Isquote(p->z[0]) ) return; for(i=1; in-1; i++){ if( sqlite3Isquote(p->z[i]) ) return; } p->n -= 2; p->z++; } /* ** Generate a Token object from a string */ SQLITE_PRIVATE void sqlite3TokenInit(Token *p, char *z){ p->z = z; p->n = sqlite3Strlen30(z); } /* Convenient short-hand */ #define UpperToLower sqlite3UpperToLower /* ** Some systems have stricmp(). Others have strcasecmp(). Because ** there is no consistency, we will define our own. ** ** IMPLEMENTATION-OF: R-30243-02494 The sqlite3_stricmp() and ** sqlite3_strnicmp() APIs allow applications and extensions to compare ** the contents of two buffers containing UTF-8 strings in a ** case-independent fashion, using the same definition of "case ** independence" that SQLite uses internally when comparing identifiers. */ SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){ if( zLeft==0 ){ return zRight ? -1 : 0; }else if( zRight==0 ){ return 1; } return sqlite3StrICmp(zLeft, zRight); } SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){ unsigned char *a, *b; int c, x; a = (unsigned char *)zLeft; b = (unsigned char *)zRight; for(;;){ c = *a; x = *b; if( c==x ){ if( c==0 ) break; }else{ c = (int)UpperToLower[c] - (int)UpperToLower[x]; if( c ) break; } a++; b++; } return c; } SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ register unsigned char *a, *b; if( zLeft==0 ){ return zRight ? -1 : 0; }else if( zRight==0 ){ return 1; } a = (unsigned char *)zLeft; b = (unsigned char *)zRight; while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; } /* ** Compute an 8-bit hash on a string that is insensitive to case differences */ SQLITE_PRIVATE u8 sqlite3StrIHash(const char *z){ u8 h = 0; if( z==0 ) return 0; while( z[0] ){ h += UpperToLower[(unsigned char)z[0]]; z++; } return h; } /* Double-Double multiplication. (x[0],x[1]) *= (y,yy) ** ** Reference: ** T. J. Dekker, "A Floating-Point Technique for Extending the ** Available Precision". 1971-07-26. */ static void dekkerMul2(volatile double *x, double y, double yy){ /* ** The "volatile" keywords on parameter x[] and on local variables ** below are needed force intermediate results to be truncated to ** binary64 rather than be carried around in an extended-precision ** format. The truncation is necessary for the Dekker algorithm to ** work. Intel x86 floating point might omit the truncation without ** the use of volatile. */ volatile double tx, ty, p, q, c, cc; double hx, hy; u64 m; memcpy(&m, (void*)&x[0], 8); m &= 0xfffffffffc000000LL; memcpy(&hx, &m, 8); tx = x[0] - hx; memcpy(&m, &y, 8); m &= 0xfffffffffc000000LL; memcpy(&hy, &m, 8); ty = y - hy; p = hx*hy; q = hx*ty + tx*hy; c = p+q; cc = p - c + q + tx*ty; cc = x[0]*yy + x[1]*y + cc; x[0] = c + cc; x[1] = c - x[0]; x[1] += cc; } /* ** The string z[] is an text representation of a real number. ** Convert this string to a double and write it into *pResult. ** ** The string z[] is length bytes in length (bytes, not characters) and ** uses the encoding enc. The string is not necessarily zero-terminated. ** ** Return TRUE if the result is a valid real number (or integer) and FALSE ** if the string is empty or contains extraneous text. More specifically ** return ** 1 => The input string is a pure integer ** 2 or more => The input has a decimal point or eNNN clause ** 0 or less => The input string is not a valid number ** -1 => Not a valid number, but has a valid prefix which ** includes a decimal point and/or an eNNN clause ** ** Valid numbers are in one of these formats: ** ** [+-]digits[E[+-]digits] ** [+-]digits.[digits][E[+-]digits] ** [+-].digits[E[+-]digits] ** ** Leading and trailing whitespace is ignored for the purpose of determining ** validity. ** ** If some prefix of the input string is a valid number, this routine ** returns FALSE but it still converts the prefix and writes the result ** into *pResult. */ #if defined(_MSC_VER) #pragma warning(disable : 4756) #endif SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ #ifndef SQLITE_OMIT_FLOATING_POINT int incr; const char *zEnd; /* sign * significand * (10 ^ (esign * exponent)) */ int sign = 1; /* sign of significand */ u64 s = 0; /* significand */ int d = 0; /* adjust exponent for shifting decimal point */ int esign = 1; /* sign of exponent */ int e = 0; /* exponent */ int eValid = 1; /* True exponent is either not used or is well-formed */ int nDigit = 0; /* Number of digits processed */ int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ if( length==0 ) return 0; if( enc==SQLITE_UTF8 ){ incr = 1; zEnd = z + length; }else{ int i; incr = 2; length &= ~1; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); testcase( enc==SQLITE_UTF16LE ); testcase( enc==SQLITE_UTF16BE ); for(i=3-enc; i=zEnd ) return 0; /* get sign of significand */ if( *z=='-' ){ sign = -1; z+=incr; }else if( *z=='+' ){ z+=incr; } /* copy max significant digits to significand */ while( z=((LARGEST_UINT64-9)/10) ){ /* skip non-significant significand digits ** (increase exponent by d to shift decimal left) */ while( z=zEnd ) goto do_atof_calc; /* if decimal point is present */ if( *z=='.' ){ z+=incr; eType++; /* copy digits from after decimal to significand ** (decrease exponent by d to shift decimal right) */ while( z=zEnd ) goto do_atof_calc; /* if exponent is present */ if( *z=='e' || *z=='E' ){ z+=incr; eValid = 0; eType++; /* This branch is needed to avoid a (harmless) buffer overread. The ** special comment alerts the mutation tester that the correct answer ** is obtained even if the branch is omitted */ if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/ /* get sign of exponent */ if( *z=='-' ){ esign = -1; z+=incr; }else if( *z=='+' ){ z+=incr; } /* copy digits to exponent */ while( z0 && s<(LARGEST_UINT64/10) ){ s *= 10; e--; } while( e<0 && (s%10)==0 ){ s /= 10; e++; } if( e==0 ){ *pResult = s; }else if( sqlite3Config.bUseLongDouble ){ LONGDOUBLE_TYPE r = (LONGDOUBLE_TYPE)s; if( e>0 ){ while( e>=100 ){ e-=100; r *= 1.0e+100L; } while( e>=10 ){ e-=10; r *= 1.0e+10L; } while( e>=1 ){ e-=1; r *= 1.0e+01L; } }else{ while( e<=-100 ){ e+=100; r *= 1.0e-100L; } while( e<=-10 ){ e+=10; r *= 1.0e-10L; } while( e<=-1 ){ e+=1; r *= 1.0e-01L; } } assert( r>=0.0 ); if( r>+1.7976931348623157081452742373e+308L ){ #ifdef INFINITY *pResult = +INFINITY; #else *pResult = 1.0e308*10.0; #endif }else{ *pResult = (double)r; } }else{ double rr[2]; u64 s2; rr[0] = (double)s; s2 = (u64)rr[0]; rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); if( e>0 ){ while( e>=100 ){ e -= 100; dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); } while( e>=10 ){ e -= 10; dekkerMul2(rr, 1.0e+10, 0.0); } while( e>=1 ){ e -= 1; dekkerMul2(rr, 1.0e+01, 0.0); } }else{ while( e<=-100 ){ e += 100; dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); } while( e<=-10 ){ e += 10; dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); } while( e<=-1 ){ e += 1; dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); } } *pResult = rr[0]+rr[1]; if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300; } if( sign<0 ) *pResult = -*pResult; assert( !sqlite3IsNaN(*pResult) ); atof_return: /* return true if number and no extra non-whitespace characters after */ if( z==zEnd && nDigit>0 && eValid && eType>0 ){ return eType; }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){ return -1; }else{ return 0; } #else return !sqlite3Atoi64(z, pResult, length, enc); #endif /* SQLITE_OMIT_FLOATING_POINT */ } #if defined(_MSC_VER) #pragma warning(default : 4756) #endif /* ** Render an signed 64-bit integer as text. Store the result in zOut[] and ** return the length of the string that was stored, in bytes. The value ** returned does not include the zero terminator at the end of the output ** string. ** ** The caller must ensure that zOut[] is at least 21 bytes in size. */ SQLITE_PRIVATE int sqlite3Int64ToText(i64 v, char *zOut){ int i; u64 x; char zTemp[22]; if( v<0 ){ x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v; }else{ x = v; } i = sizeof(zTemp)-2; zTemp[sizeof(zTemp)-1] = 0; while( 1 /*exit-by-break*/ ){ zTemp[i] = (x%10) + '0'; x = x/10; if( x==0 ) break; i--; }; if( v<0 ) zTemp[--i] = '-'; memcpy(zOut, &zTemp[i], sizeof(zTemp)-i); return sizeof(zTemp)-1-i; } /* ** Compare the 19-character string zNum against the text representation ** value 2^63: 9223372036854775808. Return negative, zero, or positive ** if zNum is less than, equal to, or greater than the string. ** Note that zNum must contain exactly 19 characters. ** ** Unlike memcmp() this routine is guaranteed to return the difference ** in the values of the last digit if the only difference is in the ** last digit. So, for example, ** ** compare2pow63("9223372036854775800", 1) ** ** will return -8. */ static int compare2pow63(const char *zNum, int incr){ int c = 0; int i; /* 012345678901234567 */ const char *pow63 = "922337203685477580"; for(i=0; c==0 && i<18; i++){ c = (zNum[i*incr]-pow63[i])*10; } if( c==0 ){ c = zNum[18*incr] - '8'; testcase( c==(-1) ); testcase( c==0 ); testcase( c==(+1) ); } return c; } /* ** Convert zNum to a 64-bit signed integer. zNum must be decimal. This ** routine does *not* accept hexadecimal notation. ** ** Returns: ** ** -1 Not even a prefix of the input text looks like an integer ** 0 Successful transformation. Fits in a 64-bit signed integer. ** 1 Excess non-space text after the integer value ** 2 Integer too large for a 64-bit signed integer or is malformed ** 3 Special case of 9223372036854775808 ** ** length is the number of bytes in the string (bytes, not characters). ** The string is not necessarily zero-terminated. The encoding is ** given by enc. */ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ int incr; u64 u = 0; int neg = 0; /* assume positive */ int i; int c = 0; int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ int rc; /* Baseline return code */ const char *zStart; const char *zEnd = zNum + length; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); if( enc==SQLITE_UTF8 ){ incr = 1; }else{ incr = 2; length &= ~1; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); for(i=3-enc; i='0' && c<='9'; i+=incr){ u = u*10 + c - '0'; } testcase( i==18*incr ); testcase( i==19*incr ); testcase( i==20*incr ); if( u>LARGEST_INT64 ){ /* This test and assignment is needed only to suppress UB warnings ** from clang and -fsanitize=undefined. This test and assignment make ** the code a little larger and slower, and no harm comes from omitting ** them, but we must appease the undefined-behavior pharisees. */ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; }else if( neg ){ *pNum = -(i64)u; }else{ *pNum = (i64)u; } rc = 0; if( i==0 && zStart==zNum ){ /* No digits */ rc = -1; }else if( nonNum ){ /* UTF16 with high-order bytes non-zero */ rc = 1; }else if( &zNum[i]19*incr ? 1 : compare2pow63(zNum, incr); if( c<0 ){ /* zNum is less than 9223372036854775808 so it fits */ assert( u<=LARGEST_INT64 ); return rc; }else{ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; if( c>0 ){ /* zNum is greater than 9223372036854775808 so it overflows */ return 2; }else{ /* zNum is exactly 9223372036854775808. Fits if negative. The ** special case 2 overflow if positive */ assert( u-1==LARGEST_INT64 ); return neg ? rc : 3; } } } } /* ** Transform a UTF-8 integer literal, in either decimal or hexadecimal, ** into a 64-bit signed integer. This routine accepts hexadecimal literals, ** whereas sqlite3Atoi64() does not. ** ** Returns: ** ** 0 Successful transformation. Fits in a 64-bit signed integer. ** 1 Excess text after the integer value ** 2 Integer too large for a 64-bit signed integer or is malformed ** 3 Special case of 9223372036854775808 */ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ #ifndef SQLITE_OMIT_HEX_INTEGER if( z[0]=='0' && (z[1]=='x' || z[1]=='X') ){ u64 u = 0; int i, k; for(i=2; z[i]=='0'; i++){} for(k=i; sqlite3Isxdigit(z[k]); k++){ u = u*16 + sqlite3HexToInt(z[k]); } memcpy(pOut, &u, 8); if( k-i>16 ) return 2; if( z[k]!=0 ) return 1; return 0; }else #endif /* SQLITE_OMIT_HEX_INTEGER */ { int n = (int)(0x3fffffff&strspn(z,"+- \n\t0123456789")); if( z[n] ) n++; return sqlite3Atoi64(z, pOut, n, SQLITE_UTF8); } } /* ** If zNum represents an integer that will fit in 32-bits, then set ** *pValue to that integer and return true. Otherwise return false. ** ** This routine accepts both decimal and hexadecimal notation for integers. ** ** Any non-numeric characters that following zNum are ignored. ** This is different from sqlite3Atoi64() which requires the ** input number to be zero-terminated. */ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){ sqlite_int64 v = 0; int i, c; int neg = 0; if( zNum[0]=='-' ){ neg = 1; zNum++; }else if( zNum[0]=='+' ){ zNum++; } #ifndef SQLITE_OMIT_HEX_INTEGER else if( zNum[0]=='0' && (zNum[1]=='x' || zNum[1]=='X') && sqlite3Isxdigit(zNum[2]) ){ u32 u = 0; zNum += 2; while( zNum[0]=='0' ) zNum++; for(i=0; i<8 && sqlite3Isxdigit(zNum[i]); i++){ u = u*16 + sqlite3HexToInt(zNum[i]); } if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){ memcpy(pValue, &u, 4); return 1; }else{ return 0; } } #endif if( !sqlite3Isdigit(zNum[0]) ) return 0; while( zNum[0]=='0' ) zNum++; for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ v = v*10 + c; } /* The longest decimal representation of a 32 bit integer is 10 digits: ** ** 1234567890 ** 2^31 -> 2147483648 */ testcase( i==10 ); if( i>10 ){ return 0; } testcase( v-neg==2147483647 ); if( v-neg>2147483647 ){ return 0; } if( neg ){ v = -v; } *pValue = (int)v; return 1; } /* ** Return a 32-bit integer value extracted from a string. If the ** string is not an integer, just return 0. */ SQLITE_PRIVATE int sqlite3Atoi(const char *z){ int x = 0; sqlite3GetInt32(z, &x); return x; } /* ** Decode a floating-point value into an approximate decimal ** representation. ** ** Round the decimal representation to n significant digits if ** n is positive. Or round to -n signficant digits after the ** decimal point if n is negative. No rounding is performed if ** n is zero. ** ** The significant digits of the decimal representation are ** stored in p->z[] which is a often (but not always) a pointer ** into the middle of p->zBuf[]. There are p->n significant digits. ** The p->z[] array is *not* zero-terminated. */ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ int i; u64 v; int e, exp = 0; p->isSpecial = 0; p->z = p->zBuf; /* Convert negative numbers to positive. Deal with Infinity, 0.0, and ** NaN. */ if( r<0.0 ){ p->sign = '-'; r = -r; }else if( r==0.0 ){ p->sign = '+'; p->n = 1; p->iDP = 1; p->z = "0"; return; }else{ p->sign = '+'; } memcpy(&v,&r,8); e = v>>52; if( (e&0x7ff)==0x7ff ){ p->isSpecial = 1 + (v!=0x7ff0000000000000LL); p->n = 0; p->iDP = 0; return; } /* Multiply r by powers of ten until it lands somewhere in between ** 1.0e+19 and 1.0e+17. */ if( sqlite3Config.bUseLongDouble ){ LONGDOUBLE_TYPE rr = r; if( rr>=1.0e+19 ){ while( rr>=1.0e+119L ){ exp+=100; rr *= 1.0e-100L; } while( rr>=1.0e+29L ){ exp+=10; rr *= 1.0e-10L; } while( rr>=1.0e+19L ){ exp++; rr *= 1.0e-1L; } }else{ while( rr<1.0e-97L ){ exp-=100; rr *= 1.0e+100L; } while( rr<1.0e+07L ){ exp-=10; rr *= 1.0e+10L; } while( rr<1.0e+17L ){ exp--; rr *= 1.0e+1L; } } v = (u64)rr; }else{ /* If high-precision floating point is not available using "long double", ** then use Dekker-style double-double computation to increase the ** precision. ** ** The error terms on constants like 1.0e+100 computed using the ** decimal extension, for example as follows: ** ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100))); */ double rr[2]; rr[0] = r; rr[1] = 0.0; if( rr[0]>9.223372036854774784e+18 ){ while( rr[0]>9.223372036854774784e+118 ){ exp += 100; dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); } while( rr[0]>9.223372036854774784e+28 ){ exp += 10; dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); } while( rr[0]>9.223372036854774784e+18 ){ exp += 1; dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); } }else{ while( rr[0]<9.223372036854774784e-83 ){ exp -= 100; dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); } while( rr[0]<9.223372036854774784e+07 ){ exp -= 10; dekkerMul2(rr, 1.0e+10, 0.0); } while( rr[0]<9.22337203685477478e+17 ){ exp -= 1; dekkerMul2(rr, 1.0e+01, 0.0); } } v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1]; } /* Extract significant digits. */ i = sizeof(p->zBuf)-1; assert( v>0 ); while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; } assert( i>=0 && izBuf)-1 ); p->n = sizeof(p->zBuf) - 1 - i; assert( p->n>0 ); assert( p->nzBuf) ); p->iDP = p->n + exp; if( iRound<0 ){ iRound = p->iDP - iRound; if( iRound==0 && p->zBuf[i+1]>='5' ){ iRound = 1; p->zBuf[i--] = '0'; p->n++; p->iDP++; } } if( iRound>0 && (iRoundn || p->n>mxRound) ){ char *z = &p->zBuf[i+1]; if( iRound>mxRound ) iRound = mxRound; p->n = iRound; if( z[iRound]>='5' ){ int j = iRound-1; while( 1 /*exit-by-break*/ ){ z[j]++; if( z[j]<='9' ) break; z[j] = '0'; if( j==0 ){ p->z[i--] = '1'; p->n++; p->iDP++; break; }else{ j--; } } } } p->z = &p->zBuf[i+1]; assert( i+p->n < sizeof(p->zBuf) ); while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; } } /* ** Try to convert z into an unsigned 32-bit integer. Return true on ** success and false if there is an error. ** ** Only decimal notation is accepted. */ SQLITE_PRIVATE int sqlite3GetUInt32(const char *z, u32 *pI){ u64 v = 0; int i; for(i=0; sqlite3Isdigit(z[i]); i++){ v = v*10 + z[i] - '0'; if( v>4294967296LL ){ *pI = 0; return 0; } } if( i==0 || z[i]!=0 ){ *pI = 0; return 0; } *pI = (u32)v; return 1; } /* ** The variable-length integer encoding is as follows: ** ** KEY: ** A = 0xxxxxxx 7 bits of data and one flag bit ** B = 1xxxxxxx 7 bits of data and one flag bit ** C = xxxxxxxx 8 bits of data ** ** 7 bits - A ** 14 bits - BA ** 21 bits - BBA ** 28 bits - BBBA ** 35 bits - BBBBA ** 42 bits - BBBBBA ** 49 bits - BBBBBBA ** 56 bits - BBBBBBBA ** 64 bits - BBBBBBBBC */ /* ** Write a 64-bit variable-length integer to memory starting at p[0]. ** The length of data write will be between 1 and 9 bytes. The number ** of bytes written is returned. ** ** A variable-length integer consists of the lower 7 bits of each byte ** for all bytes that have the 8th bit set and one byte with the 8th ** bit clear. Except, if we get to the 9th byte, it stores the full ** 8 bits and is the last byte. */ static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){ int i, j, n; u8 buf[10]; if( v & (((u64)0xff000000)<<32) ){ p[8] = (u8)v; v >>= 8; for(i=7; i>=0; i--){ p[i] = (u8)((v & 0x7f) | 0x80); v >>= 7; } return 9; } n = 0; do{ buf[n++] = (u8)((v & 0x7f) | 0x80); v >>= 7; }while( v!=0 ); buf[0] &= 0x7f; assert( n<=9 ); for(i=0, j=n-1; j>=0; j--, i++){ p[i] = buf[j]; } return n; } SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){ if( v<=0x7f ){ p[0] = v&0x7f; return 1; } if( v<=0x3fff ){ p[0] = ((v>>7)&0x7f)|0x80; p[1] = v&0x7f; return 2; } return putVarint64(p,v); } /* ** Bitmasks used by sqlite3GetVarint(). These precomputed constants ** are defined here rather than simply putting the constant expressions ** inline in order to work around bugs in the RVT compiler. ** ** SLOT_2_0 A mask for (0x7f<<14) | 0x7f ** ** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0 */ #define SLOT_2_0 0x001fc07f #define SLOT_4_2_0 0xf01fc07f /* ** Read a 64-bit variable-length integer from memory starting at p[0]. ** Return the number of bytes read. The value is stored in *v. */ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ u32 a,b,s; if( ((signed char*)p)[0]>=0 ){ *v = *p; return 1; } if( ((signed char*)p)[1]>=0 ){ *v = ((u32)(p[0]&0x7f)<<7) | p[1]; return 2; } /* Verify that constants are precomputed correctly */ assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); a = ((u32)p[0])<<14; b = p[1]; p += 2; a |= *p; /* a: p0<<14 | p2 (unmasked) */ if (!(a&0x80)) { a &= SLOT_2_0; b &= 0x7f; b = b<<7; a |= b; *v = a; return 3; } /* CSE1 from below */ a &= SLOT_2_0; p++; b = b<<14; b |= *p; /* b: p1<<14 | p3 (unmasked) */ if (!(b&0x80)) { b &= SLOT_2_0; /* moved CSE1 up */ /* a &= (0x7f<<14)|(0x7f); */ a = a<<7; a |= b; *v = a; return 4; } /* a: p0<<14 | p2 (masked) */ /* b: p1<<14 | p3 (unmasked) */ /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ /* moved CSE1 up */ /* a &= (0x7f<<14)|(0x7f); */ b &= SLOT_2_0; s = a; /* s: p0<<14 | p2 (masked) */ p++; a = a<<14; a |= *p; /* a: p0<<28 | p2<<14 | p4 (unmasked) */ if (!(a&0x80)) { /* we can skip these cause they were (effectively) done above ** while calculating s */ /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ /* b &= (0x7f<<14)|(0x7f); */ b = b<<7; a |= b; s = s>>18; *v = ((u64)s)<<32 | a; return 5; } /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ s = s<<7; s |= b; /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ p++; b = b<<14; b |= *p; /* b: p1<<28 | p3<<14 | p5 (unmasked) */ if (!(b&0x80)) { /* we can skip this cause it was (effectively) done above in calc'ing s */ /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ a &= SLOT_2_0; a = a<<7; a |= b; s = s>>18; *v = ((u64)s)<<32 | a; return 6; } p++; a = a<<14; a |= *p; /* a: p2<<28 | p4<<14 | p6 (unmasked) */ if (!(a&0x80)) { a &= SLOT_4_2_0; b &= SLOT_2_0; b = b<<7; a |= b; s = s>>11; *v = ((u64)s)<<32 | a; return 7; } /* CSE2 from below */ a &= SLOT_2_0; p++; b = b<<14; b |= *p; /* b: p3<<28 | p5<<14 | p7 (unmasked) */ if (!(b&0x80)) { b &= SLOT_4_2_0; /* moved CSE2 up */ /* a &= (0x7f<<14)|(0x7f); */ a = a<<7; a |= b; s = s>>4; *v = ((u64)s)<<32 | a; return 8; } p++; a = a<<15; a |= *p; /* a: p4<<29 | p6<<15 | p8 (unmasked) */ /* moved CSE2 up */ /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */ b &= SLOT_2_0; b = b<<8; a |= b; s = s<<4; b = p[-4]; b &= 0x7f; b = b>>3; s |= b; *v = ((u64)s)<<32 | a; return 9; } /* ** Read a 32-bit variable-length integer from memory starting at p[0]. ** Return the number of bytes read. The value is stored in *v. ** ** If the varint stored in p[0] is larger than can fit in a 32-bit unsigned ** integer, then set *v to 0xffffffff. ** ** A MACRO version, getVarint32, is provided which inlines the ** single-byte case. All code should use the MACRO version as ** this function assumes the single-byte case has already been handled. */ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){ u64 v64; u8 n; /* Assume that the single-byte case has already been handled by ** the getVarint32() macro */ assert( (p[0] & 0x80)!=0 ); if( (p[1] & 0x80)==0 ){ /* This is the two-byte case */ *v = ((p[0]&0x7f)<<7) | p[1]; return 2; } if( (p[2] & 0x80)==0 ){ /* This is the three-byte case */ *v = ((p[0]&0x7f)<<14) | ((p[1]&0x7f)<<7) | p[2]; return 3; } /* four or more bytes */ n = sqlite3GetVarint(p, &v64); assert( n>3 && n<=9 ); if( (v64 & SQLITE_MAX_U32)!=v64 ){ *v = 0xffffffff; }else{ *v = (u32)v64; } return n; } /* ** Return the number of bytes that will be needed to store the given ** 64-bit integer. */ SQLITE_PRIVATE int sqlite3VarintLen(u64 v){ int i; for(i=1; (v >>= 7)!=0; i++){ assert( i<10 ); } return i; } /* ** Read or write a four-byte big-endian integer value. */ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){ #if SQLITE_BYTEORDER==4321 u32 x; memcpy(&x,p,4); return x; #elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 u32 x; memcpy(&x,p,4); return __builtin_bswap32(x); #elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 u32 x; memcpy(&x,p,4); return _byteswap_ulong(x); #else testcase( p[0]&0x80 ); return ((unsigned)p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; #endif } SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){ #if SQLITE_BYTEORDER==4321 memcpy(p,&v,4); #elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 u32 x = __builtin_bswap32(v); memcpy(p,&x,4); #elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 u32 x = _byteswap_ulong(v); memcpy(p,&x,4); #else p[0] = (u8)(v>>24); p[1] = (u8)(v>>16); p[2] = (u8)(v>>8); p[3] = (u8)v; #endif } /* ** Translate a single byte of Hex into an integer. ** This routine only works if h really is a valid hexadecimal ** character: 0..9a..fA..F */ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); #ifdef SQLITE_ASCII h += 9*(1&(h>>6)); #endif #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); #endif return (u8)(h & 0xf); } #if !defined(SQLITE_OMIT_BLOB_LITERAL) /* ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary ** value. Return a pointer to its binary value. Space to hold the ** binary value has been obtained from malloc and must be freed by ** the calling routine. */ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ char *zBlob; int i; zBlob = (char *)sqlite3DbMallocRawNN(db, n/2 + 1); n--; if( zBlob ){ for(i=0; ieOpenState; if( eOpenState!=SQLITE_STATE_OPEN ){ if( sqlite3SafetyCheckSickOrOk(db) ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("unopened"); } return 0; }else{ return 1; } } SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ u8 eOpenState; eOpenState = db->eOpenState; if( eOpenState!=SQLITE_STATE_SICK && eOpenState!=SQLITE_STATE_OPEN && eOpenState!=SQLITE_STATE_BUSY ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("invalid"); return 0; }else{ return 1; } } /* ** Attempt to add, subtract, or multiply the 64-bit signed value iB against ** the other 64-bit signed integer at *pA and store the result in *pA. ** Return 0 on success. Or if the operation would have resulted in an ** overflow, leave *pA unchanged and return 1. */ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){ #if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) return __builtin_add_overflow(*pA, iB, pA); #else i64 iA = *pA; testcase( iA==0 ); testcase( iA==1 ); testcase( iB==-1 ); testcase( iB==0 ); if( iB>=0 ){ testcase( iA>0 && LARGEST_INT64 - iA == iB ); testcase( iA>0 && LARGEST_INT64 - iA == iB - 1 ); if( iA>0 && LARGEST_INT64 - iA < iB ) return 1; }else{ testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 1 ); testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 2 ); if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1; } *pA += iB; return 0; #endif } SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ #if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) return __builtin_sub_overflow(*pA, iB, pA); #else testcase( iB==SMALLEST_INT64+1 ); if( iB==SMALLEST_INT64 ){ testcase( (*pA)==(-1) ); testcase( (*pA)==0 ); if( (*pA)>=0 ) return 1; *pA -= iB; return 0; }else{ return sqlite3AddInt64(pA, -iB); } #endif } SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ #if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) return __builtin_mul_overflow(*pA, iB, pA); #else i64 iA = *pA; if( iB>0 ){ if( iA>LARGEST_INT64/iB ) return 1; if( iA0 ){ if( iBLARGEST_INT64/-iB ) return 1; } } *pA = iA*iB; return 0; #endif } /* ** Compute the absolute value of a 32-bit signed integer, of possible. Or ** if the integer has a value of -2147483648, return +2147483647 */ SQLITE_PRIVATE int sqlite3AbsInt32(int x){ if( x>=0 ) return x; if( x==(int)0x80000000 ) return 0x7fffffff; return -x; } #ifdef SQLITE_ENABLE_8_3_NAMES /* ** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database ** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and ** if filename in z[] has a suffix (a.k.a. "extension") that is longer than ** three characters, then shorten the suffix on z[] to be the last three ** characters of the original suffix. ** ** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always ** do the suffix shortening regardless of URI parameter. ** ** Examples: ** ** test.db-journal => test.nal ** test.db-wal => test.wal ** test.db-shm => test.shm ** test.db-mj7f3319fa => test.9fa */ SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ #if SQLITE_ENABLE_8_3_NAMES<2 if( sqlite3_uri_boolean(zBaseFilename, "8_3_names", 0) ) #endif { int i, sz; sz = sqlite3Strlen30(z); for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4); } } #endif /* ** Find (an approximate) sum of two LogEst values. This computation is ** not a simple "+" operator because LogEst is stored as a logarithmic ** value. ** */ SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst a, LogEst b){ static const unsigned char x[] = { 10, 10, /* 0,1 */ 9, 9, /* 2,3 */ 8, 8, /* 4,5 */ 7, 7, 7, /* 6,7,8 */ 6, 6, 6, /* 9,10,11 */ 5, 5, 5, /* 12-14 */ 4, 4, 4, 4, /* 15-18 */ 3, 3, 3, 3, 3, 3, /* 19-24 */ 2, 2, 2, 2, 2, 2, 2, /* 25-31 */ }; if( a>=b ){ if( a>b+49 ) return a; if( a>b+31 ) return a+1; return a+x[a-b]; }else{ if( b>a+49 ) return b; if( b>a+31 ) return b+1; return b+x[b-a]; } } /* ** Convert an integer into a LogEst. In other words, compute an ** approximation for 10*log2(x). */ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){ static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; LogEst y = 40; if( x<8 ){ if( x<2 ) return 0; while( x<8 ){ y -= 10; x <<= 1; } }else{ #if GCC_VERSION>=5004000 int i = 60 - __builtin_clzll(x); y += i*10; x >>= i; #else while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/ while( x>15 ){ y += 10; x >>= 1; } #endif } return a[x&7] + y - 10; } /* ** Convert a double into a LogEst ** In other words, compute an approximation for 10*log2(x). */ SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){ u64 a; LogEst e; assert( sizeof(x)==8 && sizeof(a)==8 ); if( x<=1 ) return 0; if( x<=2000000000 ) return sqlite3LogEst((u64)x); memcpy(&a, &x, 8); e = (a>>52) - 1022; return e*10; } /* ** Convert a LogEst into an integer. */ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){ u64 n; n = x%10; x /= 10; if( n>=5 ) n -= 2; else if( n>=1 ) n -= 1; if( x>60 ) return (u64)LARGEST_INT64; return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x); } /* ** Add a new name/number pair to a VList. This might require that the ** VList object be reallocated, so return the new VList. If an OOM ** error occurs, the original VList returned and the ** db->mallocFailed flag is set. ** ** A VList is really just an array of integers. To destroy a VList, ** simply pass it to sqlite3DbFree(). ** ** The first integer is the number of integers allocated for the whole ** VList. The second integer is the number of integers actually used. ** Each name/number pair is encoded by subsequent groups of 3 or more ** integers. ** ** Each name/number pair starts with two integers which are the numeric ** value for the pair and the size of the name/number pair, respectively. ** The text name overlays one or more following integers. The text name ** is always zero-terminated. ** ** Conceptually: ** ** struct VList { ** int nAlloc; // Number of allocated slots ** int nUsed; // Number of used slots ** struct VListEntry { ** int iValue; // Value for this entry ** int nSlot; // Slots used by this entry ** // ... variable name goes here ** } a[0]; ** } ** ** During code generation, pointers to the variable names within the ** VList are taken. When that happens, nAlloc is set to zero as an ** indication that the VList may never again be enlarged, since the ** accompanying realloc() would invalidate the pointers. */ SQLITE_PRIVATE VList *sqlite3VListAdd( sqlite3 *db, /* The database connection used for malloc() */ VList *pIn, /* The input VList. Might be NULL */ const char *zName, /* Name of symbol to add */ int nName, /* Bytes of text in zName */ int iVal /* Value to associate with zName */ ){ int nInt; /* number of sizeof(int) objects needed for zName */ char *z; /* Pointer to where zName will be stored */ int i; /* Index in pIn[] where zName is stored */ nInt = nName/4 + 3; assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */ if( pIn==0 || pIn[1]+nInt > pIn[0] ){ /* Enlarge the allocation */ sqlite3_int64 nAlloc = (pIn ? 2*(sqlite3_int64)pIn[0] : 10) + nInt; VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int)); if( pOut==0 ) return pIn; if( pIn==0 ) pOut[1] = 2; pIn = pOut; pIn[0] = nAlloc; } i = pIn[1]; pIn[i] = iVal; pIn[i+1] = nInt; z = (char*)&pIn[i+2]; pIn[1] = i+nInt; assert( pIn[1]<=pIn[0] ); memcpy(z, zName, nName); z[nName] = 0; return pIn; } /* ** Return a pointer to the name of a variable in the given VList that ** has the value iVal. Or return a NULL if there is no such variable in ** the list */ SQLITE_PRIVATE const char *sqlite3VListNumToName(VList *pIn, int iVal){ int i, mx; if( pIn==0 ) return 0; mx = pIn[1]; i = 2; do{ if( pIn[i]==iVal ) return (char*)&pIn[i+2]; i += pIn[i+1]; }while( i */ /* Turn bulk memory into a hash table object by initializing the ** fields of the Hash structure. ** ** "pNew" is a pointer to the hash table that is to be initialized. */ SQLITE_PRIVATE void sqlite3HashInit(Hash *pNew){ assert( pNew!=0 ); pNew->first = 0; pNew->count = 0; pNew->htsize = 0; pNew->ht = 0; } /* Remove all entries from a hash table. Reclaim all memory. ** Call this routine to delete a hash table or to reset a hash table ** to the empty state. */ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){ HashElem *elem; /* For looping over all elements of the table */ assert( pH!=0 ); elem = pH->first; pH->first = 0; sqlite3_free(pH->ht); pH->ht = 0; pH->htsize = 0; while( elem ){ HashElem *next_elem = elem->next; sqlite3_free(elem); elem = next_elem; } pH->count = 0; } /* ** The hashing function. */ static unsigned int strHash(const char *z){ unsigned int h = 0; unsigned char c; while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/ /* Knuth multiplicative hashing. (Sorting & Searching, p. 510). ** 0x9e3779b1 is 2654435761 which is the closest prime number to ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */ h += sqlite3UpperToLower[c]; h *= 0x9e3779b1; } return h; } /* Link pNew element into the hash table pH. If pEntry!=0 then also ** insert pNew into the pEntry hash bucket. */ static void insertElement( Hash *pH, /* The complete hash table */ struct _ht *pEntry, /* The entry into which pNew is inserted */ HashElem *pNew /* The element to be inserted */ ){ HashElem *pHead; /* First element already in pEntry */ if( pEntry ){ pHead = pEntry->count ? pEntry->chain : 0; pEntry->count++; pEntry->chain = pNew; }else{ pHead = 0; } if( pHead ){ pNew->next = pHead; pNew->prev = pHead->prev; if( pHead->prev ){ pHead->prev->next = pNew; } else { pH->first = pNew; } pHead->prev = pNew; }else{ pNew->next = pH->first; if( pH->first ){ pH->first->prev = pNew; } pNew->prev = 0; pH->first = pNew; } } /* Resize the hash table so that it contains "new_size" buckets. ** ** The hash table might fail to resize if sqlite3_malloc() fails or ** if the new size is the same as the prior size. ** Return TRUE if the resize occurs and false if not. */ static int rehash(Hash *pH, unsigned int new_size){ struct _ht *new_ht; /* The new hash table */ HashElem *elem, *next_elem; /* For looping over existing elements */ #if SQLITE_MALLOC_SOFT_LIMIT>0 if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){ new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht); } if( new_size==pH->htsize ) return 0; #endif /* The inability to allocates space for a larger hash table is ** a performance hit but it is not a fatal error. So mark the ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of ** sqlite3MallocZero() to make the allocation, as sqlite3MallocZero() ** only zeroes the requested number of bytes whereas this module will ** use the actual amount of space allocated for the hash table (which ** may be larger than the requested amount). */ sqlite3BeginBenignMalloc(); new_ht = (struct _ht *)sqlite3Malloc( new_size*sizeof(struct _ht) ); sqlite3EndBenignMalloc(); if( new_ht==0 ) return 0; sqlite3_free(pH->ht); pH->ht = new_ht; pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht); memset(new_ht, 0, new_size*sizeof(struct _ht)); for(elem=pH->first, pH->first=0; elem; elem = next_elem){ unsigned int h = strHash(elem->pKey) % new_size; next_elem = elem->next; insertElement(pH, &new_ht[h], elem); } return 1; } /* This function (for internal use only) locates an element in an ** hash table that matches the given key. If no element is found, ** a pointer to a static null element with HashElem.data==0 is returned. ** If pH is not NULL, then the hash for this key is written to *pH. */ static HashElem *findElementWithHash( const Hash *pH, /* The pH to be searched */ const char *pKey, /* The key we are searching for */ unsigned int *pHash /* Write the hash value here */ ){ HashElem *elem; /* Used to loop thru the element list */ unsigned int count; /* Number of elements left to test */ unsigned int h; /* The computed hash */ static HashElem nullElement = { 0, 0, 0, 0 }; if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/ struct _ht *pEntry; h = strHash(pKey) % pH->htsize; pEntry = &pH->ht[h]; elem = pEntry->chain; count = pEntry->count; }else{ h = 0; elem = pH->first; count = pH->count; } if( pHash ) *pHash = h; while( count ){ assert( elem!=0 ); if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ return elem; } elem = elem->next; count--; } return &nullElement; } /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. */ static void removeElementGivenHash( Hash *pH, /* The pH containing "elem" */ HashElem* elem, /* The element to be removed from the pH */ unsigned int h /* Hash value for the element */ ){ struct _ht *pEntry; if( elem->prev ){ elem->prev->next = elem->next; }else{ pH->first = elem->next; } if( elem->next ){ elem->next->prev = elem->prev; } if( pH->ht ){ pEntry = &pH->ht[h]; if( pEntry->chain==elem ){ pEntry->chain = elem->next; } assert( pEntry->count>0 ); pEntry->count--; } sqlite3_free( elem ); pH->count--; if( pH->count==0 ){ assert( pH->first==0 ); assert( pH->count==0 ); sqlite3HashClear(pH); } } /* Attempt to locate an element of the hash table pH with a key ** that matches pKey. Return the data for this element if it is ** found, or NULL if there is no match. */ SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){ assert( pH!=0 ); assert( pKey!=0 ); return findElementWithHash(pH, pKey, 0)->data; } /* Insert an element into the hash table pH. The key is pKey ** and the data is "data". ** ** If no element exists with a matching key, then a new ** element is created and NULL is returned. ** ** If another element already exists with the same key, then the ** new data replaces the old data and the old data is returned. ** The key is not copied in this instance. If a malloc fails, then ** the new data is returned and the hash table is unchanged. ** ** If the "data" parameter to this function is NULL, then the ** element corresponding to "key" is removed from the hash table. */ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ unsigned int h; /* the hash of the key modulo hash table size */ HashElem *elem; /* Used to loop thru the element list */ HashElem *new_elem; /* New element added to the pH */ assert( pH!=0 ); assert( pKey!=0 ); elem = findElementWithHash(pH,pKey,&h); if( elem->data ){ void *old_data = elem->data; if( data==0 ){ removeElementGivenHash(pH,elem,h); }else{ elem->data = data; elem->pKey = pKey; } return old_data; } if( data==0 ) return 0; new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) ); if( new_elem==0 ) return data; new_elem->pKey = pKey; new_elem->data = data; pH->count++; if( pH->count>=10 && pH->count > 2*pH->htsize ){ if( rehash(pH, pH->count*2) ){ assert( pH->htsize>0 ); h = strHash(pKey) % pH->htsize; } } insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem); return 0; } /************** End of hash.c ************************************************/ /************** Begin file opcodes.c *****************************************/ /* Automatically generated. Do not edit */ /* See the tool/mkopcodec.tcl script for details. */ #if !defined(SQLITE_OMIT_EXPLAIN) \ || defined(VDBE_PROFILE) \ || defined(SQLITE_DEBUG) #if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) || defined(SQLITE_DEBUG) # define OpHelp(X) "\0" X #else # define OpHelp(X) #endif SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ static const char *const azName[] = { /* 0 */ "Savepoint" OpHelp(""), /* 1 */ "AutoCommit" OpHelp(""), /* 2 */ "Transaction" OpHelp(""), /* 3 */ "Checkpoint" OpHelp(""), /* 4 */ "JournalMode" OpHelp(""), /* 5 */ "Vacuum" OpHelp(""), /* 6 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), /* 7 */ "VUpdate" OpHelp("data=r[P3@P2]"), /* 8 */ "Init" OpHelp("Start at P2"), /* 9 */ "Goto" OpHelp(""), /* 10 */ "Gosub" OpHelp(""), /* 11 */ "InitCoroutine" OpHelp(""), /* 12 */ "Yield" OpHelp(""), /* 13 */ "MustBeInt" OpHelp(""), /* 14 */ "Jump" OpHelp(""), /* 15 */ "Once" OpHelp(""), /* 16 */ "If" OpHelp(""), /* 17 */ "IfNot" OpHelp(""), /* 18 */ "IsType" OpHelp("if typeof(P1.P3) in P5 goto P2"), /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), /* 20 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), /* 21 */ "SeekLT" OpHelp("key=r[P3@P4]"), /* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"), /* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"), /* 24 */ "SeekGT" OpHelp("key=r[P3@P4]"), /* 25 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"), /* 26 */ "IfNoHope" OpHelp("key=r[P3@P4]"), /* 27 */ "NoConflict" OpHelp("key=r[P3@P4]"), /* 28 */ "NotFound" OpHelp("key=r[P3@P4]"), /* 29 */ "Found" OpHelp("key=r[P3@P4]"), /* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"), /* 31 */ "NotExists" OpHelp("intkey=r[P3]"), /* 32 */ "Last" OpHelp(""), /* 33 */ "IfSmaller" OpHelp(""), /* 34 */ "SorterSort" OpHelp(""), /* 35 */ "Sort" OpHelp(""), /* 36 */ "Rewind" OpHelp(""), /* 37 */ "SorterNext" OpHelp(""), /* 38 */ "Prev" OpHelp(""), /* 39 */ "Next" OpHelp(""), /* 40 */ "IdxLE" OpHelp("key=r[P3@P4]"), /* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"), /* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"), /* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), /* 45 */ "IdxGE" OpHelp("key=r[P3@P4]"), /* 46 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), /* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), /* 48 */ "Program" OpHelp(""), /* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), /* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), /* 53 */ "Eq" OpHelp("IF r[P3]==r[P1]"), /* 54 */ "Gt" OpHelp("IF r[P3]>r[P1]"), /* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"), /* 56 */ "Lt" OpHelp("IF r[P3]=r[P1]"), /* 58 */ "ElseEq" OpHelp(""), /* 59 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), /* 60 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), /* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), /* 62 */ "IncrVacuum" OpHelp(""), /* 63 */ "VNext" OpHelp(""), /* 64 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), /* 65 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), /* 66 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), /* 67 */ "Return" OpHelp(""), /* 68 */ "EndCoroutine" OpHelp(""), /* 69 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), /* 70 */ "Halt" OpHelp(""), /* 71 */ "Integer" OpHelp("r[P2]=P1"), /* 72 */ "Int64" OpHelp("r[P2]=P4"), /* 73 */ "String" OpHelp("r[P2]='P4' (len=P1)"), /* 74 */ "BeginSubrtn" OpHelp("r[P2]=NULL"), /* 75 */ "Null" OpHelp("r[P2..P3]=NULL"), /* 76 */ "SoftNull" OpHelp("r[P1]=NULL"), /* 77 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), /* 79 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), /* 80 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), /* 81 */ "SCopy" OpHelp("r[P2]=r[P1]"), /* 82 */ "IntCopy" OpHelp("r[P2]=r[P1]"), /* 83 */ "FkCheck" OpHelp(""), /* 84 */ "ResultRow" OpHelp("output=r[P1@P2]"), /* 85 */ "CollSeq" OpHelp(""), /* 86 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), /* 87 */ "RealAffinity" OpHelp(""), /* 88 */ "Cast" OpHelp("affinity(r[P1])"), /* 89 */ "Permutation" OpHelp(""), /* 90 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), /* 91 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), /* 92 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"), /* 93 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), /* 94 */ "Column" OpHelp("r[P3]=PX cursor P1 column P2"), /* 95 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"), /* 96 */ "Affinity" OpHelp("affinity(r[P1@P2])"), /* 97 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), /* 98 */ "Count" OpHelp("r[P2]=count()"), /* 99 */ "ReadCookie" OpHelp(""), /* 100 */ "SetCookie" OpHelp(""), /* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), /* 102 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 103 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 104 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), /* 106 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), /* 107 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), /* 108 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), /* 109 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), /* 110 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), /* 111 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), /* 112 */ "OpenRead" OpHelp("root=P2 iDb=P3"), /* 113 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), /* 114 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), /* 115 */ "OpenDup" OpHelp(""), /* 116 */ "OpenAutoindex" OpHelp("nColumn=P2"), /* 117 */ "String8" OpHelp("r[P2]='P4'"), /* 118 */ "OpenEphemeral" OpHelp("nColumn=P2"), /* 119 */ "SorterOpen" OpHelp(""), /* 120 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), /* 121 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), /* 122 */ "Close" OpHelp(""), /* 123 */ "ColumnsUsed" OpHelp(""), /* 124 */ "SeekScan" OpHelp("Scan-ahead up to P1 rows"), /* 125 */ "SeekHit" OpHelp("set P2<=seekHit<=P3"), /* 126 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), /* 127 */ "NewRowid" OpHelp("r[P2]=rowid"), /* 128 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), /* 129 */ "RowCell" OpHelp(""), /* 130 */ "Delete" OpHelp(""), /* 131 */ "ResetCount" OpHelp(""), /* 132 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), /* 133 */ "SorterData" OpHelp("r[P2]=data"), /* 134 */ "RowData" OpHelp("r[P2]=data"), /* 135 */ "Rowid" OpHelp("r[P2]=PX rowid of P1"), /* 136 */ "NullRow" OpHelp(""), /* 137 */ "SeekEnd" OpHelp(""), /* 138 */ "IdxInsert" OpHelp("key=r[P2]"), /* 139 */ "SorterInsert" OpHelp("key=r[P2]"), /* 140 */ "IdxDelete" OpHelp("key=r[P2@P3]"), /* 141 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), /* 142 */ "IdxRowid" OpHelp("r[P2]=rowid"), /* 143 */ "FinishSeek" OpHelp(""), /* 144 */ "Destroy" OpHelp(""), /* 145 */ "Clear" OpHelp(""), /* 146 */ "ResetSorter" OpHelp(""), /* 147 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), /* 148 */ "SqlExec" OpHelp(""), /* 149 */ "ParseSchema" OpHelp(""), /* 150 */ "LoadAnalysis" OpHelp(""), /* 151 */ "DropTable" OpHelp(""), /* 152 */ "DropIndex" OpHelp(""), /* 153 */ "Real" OpHelp("r[P2]=P4"), /* 154 */ "DropTrigger" OpHelp(""), /* 155 */ "IntegrityCk" OpHelp(""), /* 156 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), /* 157 */ "Param" OpHelp(""), /* 158 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), /* 159 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), /* 160 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), /* 161 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), /* 162 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), /* 163 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), /* 164 */ "AggValue" OpHelp("r[P3]=value N=P2"), /* 165 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), /* 166 */ "Expire" OpHelp(""), /* 167 */ "CursorLock" OpHelp(""), /* 168 */ "CursorUnlock" OpHelp(""), /* 169 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), /* 170 */ "VBegin" OpHelp(""), /* 171 */ "VCreate" OpHelp(""), /* 172 */ "VDestroy" OpHelp(""), /* 173 */ "VOpen" OpHelp(""), /* 174 */ "VCheck" OpHelp(""), /* 175 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), /* 176 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), /* 177 */ "VRename" OpHelp(""), /* 178 */ "Pagecount" OpHelp(""), /* 179 */ "MaxPgcnt" OpHelp(""), /* 180 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), /* 181 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"), /* 182 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"), /* 183 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), /* 184 */ "Trace" OpHelp(""), /* 185 */ "CursorHint" OpHelp(""), /* 186 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), /* 187 */ "Noop" OpHelp(""), /* 188 */ "Explain" OpHelp(""), /* 189 */ "Abortable" OpHelp(""), }; return azName[i]; } #endif /************** End of opcodes.c *********************************************/ /************** Begin file os_kv.c *******************************************/ /* ** 2022-09-06 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains an experimental VFS layer that operates on a ** Key/Value storage engine where both keys and values must be pure ** text. */ /* #include */ #if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)) /***************************************************************************** ** Debugging logic */ /* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */ #if 0 #define SQLITE_KV_TRACE(X) printf X #else #define SQLITE_KV_TRACE(X) #endif /* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */ #if 0 #define SQLITE_KV_LOG(X) printf X #else #define SQLITE_KV_LOG(X) #endif /* ** Forward declaration of objects used by this VFS implementation */ typedef struct KVVfsFile KVVfsFile; /* A single open file. There are only two files represented by this ** VFS - the database and the rollback journal. */ struct KVVfsFile { sqlite3_file base; /* IO methods */ const char *zClass; /* Storage class */ int isJournal; /* True if this is a journal file */ unsigned int nJrnl; /* Space allocated for aJrnl[] */ char *aJrnl; /* Journal content */ int szPage; /* Last known page size */ sqlite3_int64 szDb; /* Database file size. -1 means unknown */ char *aData; /* Buffer to hold page data */ }; #define SQLITE_KVOS_SZ 133073 /* ** Methods for KVVfsFile */ static int kvvfsClose(sqlite3_file*); static int kvvfsReadDb(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); static int kvvfsReadJrnl(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); static int kvvfsWriteDb(sqlite3_file*,const void*,int iAmt, sqlite3_int64); static int kvvfsWriteJrnl(sqlite3_file*,const void*,int iAmt, sqlite3_int64); static int kvvfsTruncateDb(sqlite3_file*, sqlite3_int64 size); static int kvvfsTruncateJrnl(sqlite3_file*, sqlite3_int64 size); static int kvvfsSyncDb(sqlite3_file*, int flags); static int kvvfsSyncJrnl(sqlite3_file*, int flags); static int kvvfsFileSizeDb(sqlite3_file*, sqlite3_int64 *pSize); static int kvvfsFileSizeJrnl(sqlite3_file*, sqlite3_int64 *pSize); static int kvvfsLock(sqlite3_file*, int); static int kvvfsUnlock(sqlite3_file*, int); static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut); static int kvvfsFileControlDb(sqlite3_file*, int op, void *pArg); static int kvvfsFileControlJrnl(sqlite3_file*, int op, void *pArg); static int kvvfsSectorSize(sqlite3_file*); static int kvvfsDeviceCharacteristics(sqlite3_file*); /* ** Methods for sqlite3_vfs */ static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir); static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *); static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename); static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut); static int kvvfsSleep(sqlite3_vfs*, int microseconds); static int kvvfsCurrentTime(sqlite3_vfs*, double*); static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); static sqlite3_vfs sqlite3OsKvvfsObject = { 1, /* iVersion */ sizeof(KVVfsFile), /* szOsFile */ 1024, /* mxPathname */ 0, /* pNext */ "kvvfs", /* zName */ 0, /* pAppData */ kvvfsOpen, /* xOpen */ kvvfsDelete, /* xDelete */ kvvfsAccess, /* xAccess */ kvvfsFullPathname, /* xFullPathname */ kvvfsDlOpen, /* xDlOpen */ 0, /* xDlError */ 0, /* xDlSym */ 0, /* xDlClose */ kvvfsRandomness, /* xRandomness */ kvvfsSleep, /* xSleep */ kvvfsCurrentTime, /* xCurrentTime */ 0, /* xGetLastError */ kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */ }; /* Methods for sqlite3_file objects referencing a database file */ static sqlite3_io_methods kvvfs_db_io_methods = { 1, /* iVersion */ kvvfsClose, /* xClose */ kvvfsReadDb, /* xRead */ kvvfsWriteDb, /* xWrite */ kvvfsTruncateDb, /* xTruncate */ kvvfsSyncDb, /* xSync */ kvvfsFileSizeDb, /* xFileSize */ kvvfsLock, /* xLock */ kvvfsUnlock, /* xUnlock */ kvvfsCheckReservedLock, /* xCheckReservedLock */ kvvfsFileControlDb, /* xFileControl */ kvvfsSectorSize, /* xSectorSize */ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */ 0, /* xShmMap */ 0, /* xShmLock */ 0, /* xShmBarrier */ 0, /* xShmUnmap */ 0, /* xFetch */ 0 /* xUnfetch */ }; /* Methods for sqlite3_file objects referencing a rollback journal */ static sqlite3_io_methods kvvfs_jrnl_io_methods = { 1, /* iVersion */ kvvfsClose, /* xClose */ kvvfsReadJrnl, /* xRead */ kvvfsWriteJrnl, /* xWrite */ kvvfsTruncateJrnl, /* xTruncate */ kvvfsSyncJrnl, /* xSync */ kvvfsFileSizeJrnl, /* xFileSize */ kvvfsLock, /* xLock */ kvvfsUnlock, /* xUnlock */ kvvfsCheckReservedLock, /* xCheckReservedLock */ kvvfsFileControlJrnl, /* xFileControl */ kvvfsSectorSize, /* xSectorSize */ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */ 0, /* xShmMap */ 0, /* xShmLock */ 0, /* xShmBarrier */ 0, /* xShmUnmap */ 0, /* xFetch */ 0 /* xUnfetch */ }; /****** Storage subsystem **************************************************/ #include #include #include /* Forward declarations for the low-level storage engine */ static int kvstorageWrite(const char*, const char *zKey, const char *zData); static int kvstorageDelete(const char*, const char *zKey); static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf); #define KVSTORAGE_KEY_SZ 32 /* Expand the key name with an appropriate prefix and put the result ** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least ** KVSTORAGE_KEY_SZ bytes. */ static void kvstorageMakeKey( const char *zClass, const char *zKeyIn, char *zKeyOut ){ sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn); } /* Write content into a key. zClass is the particular namespace of the ** underlying key/value store to use - either "local" or "session". ** ** Both zKey and zData are zero-terminated pure text strings. ** ** Return the number of errors. */ static int kvstorageWrite( const char *zClass, const char *zKey, const char *zData ){ FILE *fd; char zXKey[KVSTORAGE_KEY_SZ]; kvstorageMakeKey(zClass, zKey, zXKey); fd = fopen(zXKey, "wb"); if( fd ){ SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey, (int)strlen(zData), zData, strlen(zData)>50 ? "..." : "")); fputs(zData, fd); fclose(fd); return 0; }else{ return 1; } } /* Delete a key (with its corresponding data) from the key/value ** namespace given by zClass. If the key does not previously exist, ** this routine is a no-op. */ static int kvstorageDelete(const char *zClass, const char *zKey){ char zXKey[KVSTORAGE_KEY_SZ]; kvstorageMakeKey(zClass, zKey, zXKey); unlink(zXKey); SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey)); return 0; } /* Read the value associated with a zKey from the key/value namespace given ** by zClass and put the text data associated with that key in the first ** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large ** enough to hold it all. The value put into zBuf must always be zero ** terminated, even if it gets truncated because nBuf is not large enough. ** ** Return the total number of bytes in the data, without truncation, and ** not counting the final zero terminator. Return -1 if the key does ** not exist. ** ** If nBuf<=0 then this routine simply returns the size of the data without ** actually reading it. */ static int kvstorageRead( const char *zClass, const char *zKey, char *zBuf, int nBuf ){ FILE *fd; struct stat buf; char zXKey[KVSTORAGE_KEY_SZ]; kvstorageMakeKey(zClass, zKey, zXKey); if( access(zXKey, R_OK)!=0 || stat(zXKey, &buf)!=0 || !S_ISREG(buf.st_mode) ){ SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey)); return -1; } if( nBuf<=0 ){ return (int)buf.st_size; }else if( nBuf==1 ){ zBuf[0] = 0; SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey, (int)buf.st_size)); return (int)buf.st_size; } if( nBuf > buf.st_size + 1 ){ nBuf = buf.st_size + 1; } fd = fopen(zXKey, "rb"); if( fd==0 ){ SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey)); return -1; }else{ sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd); fclose(fd); zBuf[n] = 0; SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey, n, zBuf, n>50 ? "..." : "")); return (int)n; } } /* ** An internal level of indirection which enables us to replace the ** kvvfs i/o methods with JavaScript implementations in WASM builds. ** Maintenance reminder: if this struct changes in any way, the JSON ** rendering of its structure must be updated in ** sqlite3_wasm_enum_json(). There are no binary compatibility ** concerns, so it does not need an iVersion member. This file is ** necessarily always compiled together with sqlite3_wasm_enum_json(), ** and JS code dynamically creates the mapping of members based on ** that JSON description. */ typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods; struct sqlite3_kvvfs_methods { int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf); int (*xWrite)(const char *zClass, const char *zKey, const char *zData); int (*xDelete)(const char *zClass, const char *zKey); const int nKeySize; }; /* ** This object holds the kvvfs I/O methods which may be swapped out ** for JavaScript-side implementations in WASM builds. In such builds ** it cannot be const, but in native builds it should be so that ** the compiler can hopefully optimize this level of indirection out. ** That said, kvvfs is intended primarily for use in WASM builds. ** ** Note that this is not explicitly flagged as static because the ** amalgamation build will tag it with SQLITE_PRIVATE. */ #ifndef SQLITE_WASM const #endif SQLITE_PRIVATE sqlite3_kvvfs_methods sqlite3KvvfsMethods = { kvstorageRead, kvstorageWrite, kvstorageDelete, KVSTORAGE_KEY_SZ }; /****** Utility subroutines ************************************************/ /* ** Encode binary into the text encoded used to persist on disk. ** The output text is stored in aOut[], which must be at least ** nData+1 bytes in length. ** ** Return the actual length of the encoded text, not counting the ** zero terminator at the end. ** ** Encoding format ** --------------- ** ** * Non-zero bytes are encoded as upper-case hexadecimal ** ** * A sequence of one or more zero-bytes that are not at the ** beginning of the buffer are encoded as a little-endian ** base-26 number using a..z. "a" means 0. "b" means 1, ** "z" means 25. "ab" means 26. "ac" means 52. And so forth. ** ** * Because there is no overlap between the encoding characters ** of hexadecimal and base-26 numbers, it is always clear where ** one stops and the next begins. */ static int kvvfsEncode(const char *aData, int nData, char *aOut){ int i, j; const unsigned char *a = (const unsigned char*)aData; for(i=j=0; i>4]; aOut[j++] = "0123456789ABCDEF"[c&0xf]; }else{ /* A sequence of 1 or more zeros is stored as a little-endian ** base-26 number using a..z as the digits. So one zero is "b". ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb", ** and so forth. */ int k; for(k=1; i+k0 ){ aOut[j++] = 'a'+(k%26); k /= 26; } } } aOut[j] = 0; return j; } static const signed char kvvfsHexValue[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; /* ** Decode the text encoding back to binary. The binary content is ** written into pOut, which must be at least nOut bytes in length. ** ** The return value is the number of bytes actually written into aOut[]. */ static int kvvfsDecode(const char *a, char *aOut, int nOut){ int i, j; int c; const unsigned char *aIn = (const unsigned char*)a; i = 0; j = 0; while( 1 ){ c = kvvfsHexValue[aIn[i]]; if( c<0 ){ int n = 0; int mult = 1; c = aIn[i]; if( c==0 ) break; while( c>='a' && c<='z' ){ n += (c - 'a')*mult; mult *= 26; c = aIn[++i]; } if( j+n>nOut ) return -1; memset(&aOut[j], 0, n); j += n; if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */ }else{ aOut[j] = c<<4; c = kvvfsHexValue[aIn[++i]]; if( c<0 ) break; aOut[j++] += c; i++; } } return j; } /* ** Decode a complete journal file. Allocate space in pFile->aJrnl ** and store the decoding there. Or leave pFile->aJrnl set to NULL ** if an error is encountered. ** ** The first few characters of the text encoding will be a little-endian ** base-26 number (digits a..z) that is the total number of bytes ** in the decoded journal file image. This base-26 number is followed ** by a single space, then the encoding of the journal. The space ** separator is required to act as a terminator for the base-26 number. */ static void kvvfsDecodeJournal( KVVfsFile *pFile, /* Store decoding in pFile->aJrnl */ const char *zTxt, /* Text encoding. Zero-terminated */ int nTxt /* Bytes in zTxt, excluding zero terminator */ ){ unsigned int n = 0; int c, i, mult; i = 0; mult = 1; while( (c = zTxt[i++])>='a' && c<='z' ){ n += (zTxt[i] - 'a')*mult; mult *= 26; } sqlite3_free(pFile->aJrnl); pFile->aJrnl = sqlite3_malloc64( n ); if( pFile->aJrnl==0 ){ pFile->nJrnl = 0; return; } pFile->nJrnl = n; n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl); if( nnJrnl ){ sqlite3_free(pFile->aJrnl); pFile->aJrnl = 0; pFile->nJrnl = 0; } } /* ** Read or write the "sz" element, containing the database file size. */ static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){ char zData[50]; zData[0] = 0; sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1); return strtoll(zData, 0, 0); } static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){ char zData[50]; sqlite3_snprintf(sizeof(zData), zData, "%lld", sz); return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData); } /****** sqlite3_io_methods methods ******************************************/ /* ** Close an kvvfs-file. */ static int kvvfsClose(sqlite3_file *pProtoFile){ KVVfsFile *pFile = (KVVfsFile *)pProtoFile; SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass, pFile->isJournal ? "journal" : "db")); sqlite3_free(pFile->aJrnl); sqlite3_free(pFile->aData); return SQLITE_OK; } /* ** Read from the -journal file. */ static int kvvfsReadJrnl( sqlite3_file *pProtoFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ KVVfsFile *pFile = (KVVfsFile*)pProtoFile; assert( pFile->isJournal ); SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); if( pFile->aJrnl==0 ){ int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0); char *aTxt; if( szTxt<=4 ){ return SQLITE_IOERR; } aTxt = sqlite3_malloc64( szTxt+1 ); if( aTxt==0 ) return SQLITE_NOMEM; kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1); kvvfsDecodeJournal(pFile, aTxt, szTxt); sqlite3_free(aTxt); if( pFile->aJrnl==0 ) return SQLITE_IOERR; } if( iOfst+iAmt>pFile->nJrnl ){ return SQLITE_IOERR_SHORT_READ; } memcpy(zBuf, pFile->aJrnl+iOfst, iAmt); return SQLITE_OK; } /* ** Read from the database file. */ static int kvvfsReadDb( sqlite3_file *pProtoFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ KVVfsFile *pFile = (KVVfsFile*)pProtoFile; unsigned int pgno; int got, n; char zKey[30]; char *aData = pFile->aData; assert( iOfst>=0 ); assert( iAmt>=0 ); SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); if( iOfst+iAmt>=512 ){ if( (iOfst % iAmt)!=0 ){ return SQLITE_IOERR_READ; } if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){ return SQLITE_IOERR_READ; } pFile->szPage = iAmt; pgno = 1 + iOfst/iAmt; }else{ pgno = 1; } sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey, aData, SQLITE_KVOS_SZ-1); if( got<0 ){ n = 0; }else{ aData[got] = 0; if( iOfst+iAmt<512 ){ int k = iOfst+iAmt; aData[k*2] = 0; n = kvvfsDecode(aData, &aData[2000], SQLITE_KVOS_SZ-2000); if( n>=iOfst+iAmt ){ memcpy(zBuf, &aData[2000+iOfst], iAmt); n = iAmt; }else{ n = 0; } }else{ n = kvvfsDecode(aData, zBuf, iAmt); } } if( nzClass, iAmt, iOfst)); if( iEnd>=0x10000000 ) return SQLITE_FULL; if( pFile->aJrnl==0 || pFile->nJrnlaJrnl, iEnd); if( aNew==0 ){ return SQLITE_IOERR_NOMEM; } pFile->aJrnl = aNew; if( pFile->nJrnlaJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl); } pFile->nJrnl = iEnd; } memcpy(pFile->aJrnl+iOfst, zBuf, iAmt); return SQLITE_OK; } /* ** Write into the database file. */ static int kvvfsWriteDb( sqlite3_file *pProtoFile, const void *zBuf, int iAmt, sqlite_int64 iOfst ){ KVVfsFile *pFile = (KVVfsFile*)pProtoFile; unsigned int pgno; char zKey[30]; char *aData = pFile->aData; SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); assert( iAmt>=512 && iAmt<=65536 ); assert( (iAmt & (iAmt-1))==0 ); assert( pFile->szPage<0 || pFile->szPage==iAmt ); pFile->szPage = iAmt; pgno = 1 + iOfst/iAmt; sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); kvvfsEncode(zBuf, iAmt, aData); if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){ return SQLITE_IOERR; } if( iOfst+iAmt > pFile->szDb ){ pFile->szDb = iOfst + iAmt; } return SQLITE_OK; } /* ** Truncate an kvvfs-file. */ static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){ KVVfsFile *pFile = (KVVfsFile *)pProtoFile; SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size)); assert( size==0 ); sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl"); sqlite3_free(pFile->aJrnl); pFile->aJrnl = 0; pFile->nJrnl = 0; return SQLITE_OK; } static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){ KVVfsFile *pFile = (KVVfsFile *)pProtoFile; if( pFile->szDb>size && pFile->szPage>0 && (size % pFile->szPage)==0 ){ char zKey[50]; unsigned int pgno, pgnoMax; SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size)); pgno = 1 + size/pFile->szPage; pgnoMax = 2 + pFile->szDb/pFile->szPage; while( pgno<=pgnoMax ){ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey); pgno++; } pFile->szDb = size; return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK; } return SQLITE_IOERR; } /* ** Sync an kvvfs-file. */ static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){ int i, n; KVVfsFile *pFile = (KVVfsFile *)pProtoFile; char *zOut; SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass)); if( pFile->nJrnl<=0 ){ return kvvfsTruncateJrnl(pProtoFile, 0); } zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 ); if( zOut==0 ){ return SQLITE_IOERR_NOMEM; } n = pFile->nJrnl; i = 0; do{ zOut[i++] = 'a' + (n%26); n /= 26; }while( n>0 ); zOut[i++] = ' '; kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]); i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut); sqlite3_free(zOut); return i ? SQLITE_IOERR : SQLITE_OK; } static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){ return SQLITE_OK; } /* ** Return the current file-size of an kvvfs-file. */ static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){ KVVfsFile *pFile = (KVVfsFile *)pProtoFile; SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass)); *pSize = pFile->nJrnl; return SQLITE_OK; } static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){ KVVfsFile *pFile = (KVVfsFile *)pProtoFile; SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass)); if( pFile->szDb>=0 ){ *pSize = pFile->szDb; }else{ *pSize = kvvfsReadFileSize(pFile); } return SQLITE_OK; } /* ** Lock an kvvfs-file. */ static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){ KVVfsFile *pFile = (KVVfsFile *)pProtoFile; assert( !pFile->isJournal ); SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock)); if( eLock!=SQLITE_LOCK_NONE ){ pFile->szDb = kvvfsReadFileSize(pFile); } return SQLITE_OK; } /* ** Unlock an kvvfs-file. */ static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){ KVVfsFile *pFile = (KVVfsFile *)pProtoFile; assert( !pFile->isJournal ); SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock)); if( eLock==SQLITE_LOCK_NONE ){ pFile->szDb = -1; } return SQLITE_OK; } /* ** Check if another file-handle holds a RESERVED lock on an kvvfs-file. */ static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){ SQLITE_KV_LOG(("xCheckReservedLock\n")); *pResOut = 0; return SQLITE_OK; } /* ** File control method. For custom operations on an kvvfs-file. */ static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){ SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op)); return SQLITE_NOTFOUND; } static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){ SQLITE_KV_LOG(("xFileControl(%d) on database\n", op)); if( op==SQLITE_FCNTL_SYNC ){ KVVfsFile *pFile = (KVVfsFile *)pProtoFile; int rc = SQLITE_OK; SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass)); if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){ rc = SQLITE_IOERR; } return rc; } return SQLITE_NOTFOUND; } /* ** Return the sector-size in bytes for an kvvfs-file. */ static int kvvfsSectorSize(sqlite3_file *pFile){ return 512; } /* ** Return the device characteristic flags supported by an kvvfs-file. */ static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){ return 0; } /****** sqlite3_vfs methods *************************************************/ /* ** Open an kvvfs file handle. */ static int kvvfsOpen( sqlite3_vfs *pProtoVfs, const char *zName, sqlite3_file *pProtoFile, int flags, int *pOutFlags ){ KVVfsFile *pFile = (KVVfsFile*)pProtoFile; if( zName==0 ) zName = ""; SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName)); if( strcmp(zName, "local")==0 || strcmp(zName, "session")==0 ){ pFile->isJournal = 0; pFile->base.pMethods = &kvvfs_db_io_methods; }else if( strcmp(zName, "local-journal")==0 || strcmp(zName, "session-journal")==0 ){ pFile->isJournal = 1; pFile->base.pMethods = &kvvfs_jrnl_io_methods; }else{ return SQLITE_CANTOPEN; } if( zName[0]=='s' ){ pFile->zClass = "session"; }else{ pFile->zClass = "local"; } pFile->aData = sqlite3_malloc64(SQLITE_KVOS_SZ); if( pFile->aData==0 ){ return SQLITE_NOMEM; } pFile->aJrnl = 0; pFile->nJrnl = 0; pFile->szPage = -1; pFile->szDb = -1; return SQLITE_OK; } /* ** Delete the file located at zPath. If the dirSync argument is true, ** ensure the file-system modifications are synced to disk before ** returning. */ static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ if( strcmp(zPath, "local-journal")==0 ){ sqlite3KvvfsMethods.xDelete("local", "jrnl"); }else if( strcmp(zPath, "session-journal")==0 ){ sqlite3KvvfsMethods.xDelete("session", "jrnl"); } return SQLITE_OK; } /* ** Test for access permissions. Return true if the requested permission ** is available, or false otherwise. */ static int kvvfsAccess( sqlite3_vfs *pProtoVfs, const char *zPath, int flags, int *pResOut ){ SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath)); if( strcmp(zPath, "local-journal")==0 ){ *pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0; }else if( strcmp(zPath, "session-journal")==0 ){ *pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0; }else if( strcmp(zPath, "local")==0 ){ *pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0; }else if( strcmp(zPath, "session")==0 ){ *pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0; }else { *pResOut = 0; } SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut)); return SQLITE_OK; } /* ** Populate buffer zOut with the full canonical pathname corresponding ** to the pathname in zPath. zOut is guaranteed to point to a buffer ** of at least (INST_MAX_PATHNAME+1) bytes. */ static int kvvfsFullPathname( sqlite3_vfs *pVfs, const char *zPath, int nOut, char *zOut ){ size_t nPath; #ifdef SQLITE_OS_KV_ALWAYS_LOCAL zPath = "local"; #endif nPath = strlen(zPath); SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath)); if( nOut static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; struct timeval sNow; (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */ *pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; return SQLITE_OK; } #endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */ #if SQLITE_OS_KV /* ** This routine is called initialize the KV-vfs as the default VFS. */ SQLITE_API int sqlite3_os_init(void){ return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1); } SQLITE_API int sqlite3_os_end(void){ return SQLITE_OK; } #endif /* SQLITE_OS_KV */ #if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) SQLITE_PRIVATE int sqlite3KvvfsInit(void){ return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0); } #endif /************** End of os_kv.c ***********************************************/ /************** Begin file os_unix.c *****************************************/ /* ** 2004 May 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains the VFS implementation for unix-like operating systems ** include Linux, MacOSX, *BSD, QNX, VxWorks, AIX, HPUX, and others. ** ** There are actually several different VFS implementations in this file. ** The differences are in the way that file locking is done. The default ** implementation uses Posix Advisory Locks. Alternative implementations ** use flock(), dot-files, various proprietary locking schemas, or simply ** skip locking all together. ** ** This source file is organized into divisions where the logic for various ** subfunctions is contained within the appropriate division. PLEASE ** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed ** in the correct division and should be clearly labelled. ** ** The layout of divisions is as follows: ** ** * General-purpose declarations and utility functions. ** * Unique file ID logic used by VxWorks. ** * Various locking primitive implementations (all except proxy locking): ** + for Posix Advisory Locks ** + for no-op locks ** + for dot-file locks ** + for flock() locking ** + for named semaphore locks (VxWorks only) ** + for AFP filesystem locks (MacOSX only) ** * sqlite3_file methods not associated with locking. ** * Definitions of sqlite3_io_methods objects for all locking ** methods plus "finder" functions for each locking method. ** * sqlite3_vfs method implementations. ** * Locking primitives for the proxy uber-locking-method. (MacOSX only) ** * Definitions of sqlite3_vfs objects for all locking methods ** plus implementations of sqlite3_os_init() and sqlite3_os_end(). */ /* #include "sqliteInt.h" */ #if SQLITE_OS_UNIX /* This file is used on unix only */ /* ** There are various methods for file locking used for concurrency ** control: ** ** 1. POSIX locking (the default), ** 2. No locking, ** 3. Dot-file locking, ** 4. flock() locking, ** 5. AFP locking (OSX only), ** 6. Named POSIX semaphores (VXWorks only), ** 7. proxy locking. (OSX only) ** ** Styles 4, 5, and 7 are only available of SQLITE_ENABLE_LOCKING_STYLE ** is defined to 1. The SQLITE_ENABLE_LOCKING_STYLE also enables automatic ** selection of the appropriate locking style based on the filesystem ** where the database is located. */ #if !defined(SQLITE_ENABLE_LOCKING_STYLE) # if defined(__APPLE__) # define SQLITE_ENABLE_LOCKING_STYLE 1 # else # define SQLITE_ENABLE_LOCKING_STYLE 0 # endif #endif /* Use pread() and pwrite() if they are available */ #if defined(__APPLE__) || defined(__linux__) # define HAVE_PREAD 1 # define HAVE_PWRITE 1 #endif #if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64) # undef USE_PREAD # define USE_PREAD64 1 #elif defined(HAVE_PREAD) && defined(HAVE_PWRITE) # undef USE_PREAD64 # define USE_PREAD 1 #endif /* ** standard include files. */ #include /* amalgamator: keep */ #include /* amalgamator: keep */ #include #include #include /* amalgamator: keep */ /* #include */ #include /* amalgamator: keep */ #include #if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \ && !defined(SQLITE_WASI) # include #endif #if SQLITE_ENABLE_LOCKING_STYLE /* # include */ # include # include #endif /* SQLITE_ENABLE_LOCKING_STYLE */ /* ** Try to determine if gethostuuid() is available based on standard ** macros. This might sometimes compute the wrong value for some ** obscure platforms. For those cases, simply compile with one of ** the following: ** ** -DHAVE_GETHOSTUUID=0 ** -DHAVE_GETHOSTUUID=1 ** ** None if this matters except when building on Apple products with ** -DSQLITE_ENABLE_LOCKING_STYLE. */ #ifndef HAVE_GETHOSTUUID # define HAVE_GETHOSTUUID 0 # if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \ (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000)) # if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \ && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))\ && (!defined(TARGET_OS_MACCATALYST) || (TARGET_OS_MACCATALYST==0)) # undef HAVE_GETHOSTUUID # define HAVE_GETHOSTUUID 1 # else # warning "gethostuuid() is disabled." # endif # endif #endif #if OS_VXWORKS /* # include */ # include # include #endif /* OS_VXWORKS */ #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE # include #endif #ifdef HAVE_UTIME # include #endif /* ** Allowed values of unixFile.fsFlags */ #define SQLITE_FSFLAGS_IS_MSDOS 0x1 /* ** If we are to be thread-safe, include the pthreads header. */ #if SQLITE_THREADSAFE /* # include */ #endif /* ** Default permissions when creating a new file */ #ifndef SQLITE_DEFAULT_FILE_PERMISSIONS # define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 #endif /* ** Default permissions when creating auto proxy dir */ #ifndef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS # define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755 #endif /* ** Maximum supported path-length. */ #define MAX_PATHNAME 512 /* ** Maximum supported symbolic links */ #define SQLITE_MAX_SYMLINKS 100 /* ** Remove and stub certain info for WASI (WebAssembly System ** Interface) builds. */ #ifdef SQLITE_WASI # undef HAVE_FCHMOD # undef HAVE_FCHOWN # undef HAVE_MREMAP # define HAVE_MREMAP 0 # ifndef SQLITE_DEFAULT_UNIX_VFS # define SQLITE_DEFAULT_UNIX_VFS "unix-dotfile" /* ^^^ should SQLITE_DEFAULT_UNIX_VFS be "unix-none"? */ # endif # ifndef F_RDLCK # define F_RDLCK 0 # define F_WRLCK 1 # define F_UNLCK 2 # if __LONG_MAX == 0x7fffffffL # define F_GETLK 12 # define F_SETLK 13 # define F_SETLKW 14 # else # define F_GETLK 5 # define F_SETLK 6 # define F_SETLKW 7 # endif # endif #else /* !SQLITE_WASI */ # ifndef HAVE_FCHMOD # define HAVE_FCHMOD # endif #endif /* SQLITE_WASI */ #ifdef SQLITE_WASI # define osGetpid(X) (pid_t)1 #else /* Always cast the getpid() return type for compatibility with ** kernel modules in VxWorks. */ # define osGetpid(X) (pid_t)getpid() #endif /* ** Only set the lastErrno if the error code is a real error and not ** a normal expected return code of SQLITE_BUSY or SQLITE_OK */ #define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY)) /* Forward references */ typedef struct unixShm unixShm; /* Connection shared memory */ typedef struct unixShmNode unixShmNode; /* Shared memory instance */ typedef struct unixInodeInfo unixInodeInfo; /* An i-node */ typedef struct UnixUnusedFd UnixUnusedFd; /* An unused file descriptor */ /* ** Sometimes, after a file handle is closed by SQLite, the file descriptor ** cannot be closed immediately. In these cases, instances of the following ** structure are used to store the file descriptor while waiting for an ** opportunity to either close or reuse it. */ struct UnixUnusedFd { int fd; /* File descriptor to close */ int flags; /* Flags this file descriptor was opened with */ UnixUnusedFd *pNext; /* Next unused file descriptor on same file */ }; /* ** The unixFile structure is subclass of sqlite3_file specific to the unix ** VFS implementations. */ typedef struct unixFile unixFile; struct unixFile { sqlite3_io_methods const *pMethod; /* Always the first entry */ sqlite3_vfs *pVfs; /* The VFS that created this unixFile */ unixInodeInfo *pInode; /* Info about locks on this inode */ int h; /* The file descriptor */ unsigned char eFileLock; /* The type of lock held on this fd */ unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ int lastErrno; /* The unix errno from last I/O error */ void *lockingContext; /* Locking style specific state */ UnixUnusedFd *pPreallocatedUnused; /* Pre-allocated UnixUnusedFd */ const char *zPath; /* Name of the file */ unixShm *pShm; /* Shared memory segment information */ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ #if SQLITE_MAX_MMAP_SIZE>0 int nFetchOut; /* Number of outstanding xFetch refs */ sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */ sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ void *pMapRegion; /* Memory mapped region */ #endif int sectorSize; /* Device sector size */ int deviceCharacteristics; /* Precomputed device characteristics */ #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif #if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__) unsigned fsFlags; /* cached details from statfs() */ #endif #ifdef SQLITE_ENABLE_SETLK_TIMEOUT unsigned iBusyTimeout; /* Wait this many millisec on locks */ #endif #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID */ #endif #ifdef SQLITE_DEBUG /* The next group of variables are used to track whether or not the ** transaction counter in bytes 24-27 of database files are updated ** whenever any part of the database changes. An assertion fault will ** occur if a file is updated without also updating the transaction ** counter. This test is made to avoid new problems similar to the ** one described by ticket #3584. */ unsigned char transCntrChng; /* True if the transaction counter changed */ unsigned char dbUpdate; /* True if any part of database file changed */ unsigned char inNormalWrite; /* True if in a normal write operation */ #endif #ifdef SQLITE_TEST /* In test mode, increase the size of this structure a bit so that ** it is larger than the struct CrashFile defined in test6.c. */ char aPadding[32]; #endif }; /* This variable holds the process id (pid) from when the xRandomness() ** method was called. If xOpen() is called from a different process id, ** indicating that a fork() has occurred, the PRNG will be reset. */ static pid_t randomnessPid = 0; /* ** Allowed values for the unixFile.ctrlFlags bitmask: */ #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ #define UNIXFILE_RDONLY 0x02 /* Connection is read only */ #define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ #ifndef SQLITE_DISABLE_DIRSYNC # define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */ #else # define UNIXFILE_DIRSYNC 0x00 #endif #define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ #define UNIXFILE_DELETE 0x20 /* Delete on close */ #define UNIXFILE_URI 0x40 /* Filename might have query parameters */ #define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ /* ** Include code that is common to all os_*.c files */ /* #include "os_common.h" */ /* ** Define various macros that are missing from some systems. */ #ifndef O_LARGEFILE # define O_LARGEFILE 0 #endif #ifdef SQLITE_DISABLE_LFS # undef O_LARGEFILE # define O_LARGEFILE 0 #endif #ifndef O_NOFOLLOW # define O_NOFOLLOW 0 #endif #ifndef O_BINARY # define O_BINARY 0 #endif /* ** The threadid macro resolves to the thread-id or to 0. Used for ** testing and debugging only. */ #if SQLITE_THREADSAFE #define threadid pthread_self() #else #define threadid 0 #endif /* ** HAVE_MREMAP defaults to true on Linux and false everywhere else. */ #if !defined(HAVE_MREMAP) # if defined(__linux__) && defined(_GNU_SOURCE) # define HAVE_MREMAP 1 # else # define HAVE_MREMAP 0 # endif #endif /* ** Explicitly call the 64-bit version of lseek() on Android. Otherwise, lseek() ** is the 32-bit version, even if _FILE_OFFSET_BITS=64 is defined. */ #ifdef __ANDROID__ # define lseek lseek64 #endif #ifdef __linux__ /* ** Linux-specific IOCTL magic numbers used for controlling F2FS */ #define F2FS_IOCTL_MAGIC 0xf5 #define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) #define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) #define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) #define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) #define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32) #define F2FS_FEATURE_ATOMIC_WRITE 0x0004 #endif /* __linux__ */ /* ** Different Unix systems declare open() in different ways. Same use ** open(const char*,int,mode_t). Others use open(const char*,int,...). ** The difference is important when using a pointer to the function. ** ** The safest way to deal with the problem is to always use this wrapper ** which always has the same well-defined interface. */ static int posixOpen(const char *zFile, int flags, int mode){ return open(zFile, flags, mode); } /* Forward reference */ static int openDirectory(const char*, int*); static int unixGetpagesize(void); /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during ** testing and sandboxing. The following array holds the names and pointers ** to all overrideable system calls. */ static struct unix_syscall { const char *zName; /* Name of the system call */ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ sqlite3_syscall_ptr pDefault; /* Default value */ } aSyscall[] = { { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) { "close", (sqlite3_syscall_ptr)close, 0 }, #define osClose ((int(*)(int))aSyscall[1].pCurrent) { "access", (sqlite3_syscall_ptr)access, 0 }, #define osAccess ((int(*)(const char*,int))aSyscall[2].pCurrent) { "getcwd", (sqlite3_syscall_ptr)getcwd, 0 }, #define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent) { "stat", (sqlite3_syscall_ptr)stat, 0 }, #define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent) /* ** The DJGPP compiler environment looks mostly like Unix, but it ** lacks the fcntl() system call. So redefine fcntl() to be something ** that always succeeds. This means that locking does not occur under ** DJGPP. But it is DOS - what did you expect? */ #ifdef __DJGPP__ { "fstat", 0, 0 }, #define osFstat(a,b,c) 0 #else { "fstat", (sqlite3_syscall_ptr)fstat, 0 }, #define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent) #endif { "ftruncate", (sqlite3_syscall_ptr)ftruncate, 0 }, #define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent) { "fcntl", (sqlite3_syscall_ptr)fcntl, 0 }, #define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent) { "read", (sqlite3_syscall_ptr)read, 0 }, #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) #if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE { "pread", (sqlite3_syscall_ptr)pread, 0 }, #else { "pread", (sqlite3_syscall_ptr)0, 0 }, #endif #define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent) #if defined(USE_PREAD64) { "pread64", (sqlite3_syscall_ptr)pread64, 0 }, #else { "pread64", (sqlite3_syscall_ptr)0, 0 }, #endif #define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent) { "write", (sqlite3_syscall_ptr)write, 0 }, #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) #if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, #else { "pwrite", (sqlite3_syscall_ptr)0, 0 }, #endif #define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ aSyscall[12].pCurrent) #if defined(USE_PREAD64) { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 }, #else { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, #endif #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\ aSyscall[13].pCurrent) #if defined(HAVE_FCHMOD) { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, #else { "fchmod", (sqlite3_syscall_ptr)0, 0 }, #endif #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, #else { "fallocate", (sqlite3_syscall_ptr)0, 0 }, #endif #define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent) { "unlink", (sqlite3_syscall_ptr)unlink, 0 }, #define osUnlink ((int(*)(const char*))aSyscall[16].pCurrent) { "openDirectory", (sqlite3_syscall_ptr)openDirectory, 0 }, #define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent) { "mkdir", (sqlite3_syscall_ptr)mkdir, 0 }, #define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent) { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 }, #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent) #if defined(HAVE_FCHOWN) { "fchown", (sqlite3_syscall_ptr)fchown, 0 }, #else { "fchown", (sqlite3_syscall_ptr)0, 0 }, #endif #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) #if defined(HAVE_FCHOWN) { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 }, #else { "geteuid", (sqlite3_syscall_ptr)0, 0 }, #endif #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) #if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \ && !defined(SQLITE_WASI) { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, #else { "mmap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent) #if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \ && !defined(SQLITE_WASI) { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, #else { "munmap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMunmap ((int(*)(void*,size_t))aSyscall[23].pCurrent) #if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "mremap", (sqlite3_syscall_ptr)mremap, 0 }, #else { "mremap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent) #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 }, #else { "getpagesize", (sqlite3_syscall_ptr)0, 0 }, #endif #define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent) #if defined(HAVE_READLINK) { "readlink", (sqlite3_syscall_ptr)readlink, 0 }, #else { "readlink", (sqlite3_syscall_ptr)0, 0 }, #endif #define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent) #if defined(HAVE_LSTAT) { "lstat", (sqlite3_syscall_ptr)lstat, 0 }, #else { "lstat", (sqlite3_syscall_ptr)0, 0 }, #endif #define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) # ifdef __ANDROID__ { "ioctl", (sqlite3_syscall_ptr)(int(*)(int, int, ...))ioctl, 0 }, #define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent) # else { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 }, #define osIoctl ((int(*)(int,unsigned long,...))aSyscall[28].pCurrent) # endif #else { "ioctl", (sqlite3_syscall_ptr)0, 0 }, #endif }; /* End of the overrideable system calls */ /* ** On some systems, calls to fchown() will trigger a message in a security ** log if they come from non-root processes. So avoid calling fchown() if ** we are not running as root. */ static int robustFchown(int fd, uid_t uid, gid_t gid){ #if defined(HAVE_FCHOWN) return osGeteuid() ? 0 : osFchown(fd,uid,gid); #else return 0; #endif } /* ** This is the xSetSystemCall() method of sqlite3_vfs for all of the ** "unix" VFSes. Return SQLITE_OK upon successfully updating the ** system call pointer, or SQLITE_NOTFOUND if there is no configurable ** system call named zName. */ static int unixSetSystemCall( sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */ const char *zName, /* Name of system call to override */ sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */ ){ unsigned int i; int rc = SQLITE_NOTFOUND; UNUSED_PARAMETER(pNotUsed); if( zName==0 ){ /* If no zName is given, restore all system calls to their default ** settings and return NULL */ rc = SQLITE_OK; for(i=0; i=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break; if( (f & (O_EXCL|O_CREAT))==(O_EXCL|O_CREAT) ){ (void)osUnlink(z); } osClose(fd); sqlite3_log(SQLITE_WARNING, "attempt to open \"%s\" as file descriptor %d", z, fd); fd = -1; if( osOpen("/dev/null", O_RDONLY, m)<0 ) break; } if( fd>=0 ){ if( m!=0 ){ struct stat statbuf; if( osFstat(fd, &statbuf)==0 && statbuf.st_size==0 && (statbuf.st_mode&0777)!=m ){ osFchmod(fd, m); } } #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); #endif } return fd; } /* ** Helper functions to obtain and relinquish the global mutex. The ** global mutex is used to protect the unixInodeInfo and ** vxworksFileId objects used by this file, all of which may be ** shared by multiple threads. ** ** Function unixMutexHeld() is used to assert() that the global mutex ** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** unixEnterMutex() ** assert( unixMutexHeld() ); ** unixEnterLeave() ** ** To prevent deadlock, the global unixBigLock must must be acquired ** before the unixInodeInfo.pLockMutex mutex, if both are held. It is ** OK to get the pLockMutex without holding unixBigLock first, but if ** that happens, the unixBigLock mutex must not be acquired until after ** pLockMutex is released. ** ** OK: enter(unixBigLock), enter(pLockInfo) ** OK: enter(unixBigLock) ** OK: enter(pLockInfo) ** ERROR: enter(pLockInfo), enter(unixBigLock) */ static sqlite3_mutex *unixBigLock = 0; static void unixEnterMutex(void){ assert( sqlite3_mutex_notheld(unixBigLock) ); /* Not a recursive mutex */ sqlite3_mutex_enter(unixBigLock); } static void unixLeaveMutex(void){ assert( sqlite3_mutex_held(unixBigLock) ); sqlite3_mutex_leave(unixBigLock); } #ifdef SQLITE_DEBUG static int unixMutexHeld(void) { return sqlite3_mutex_held(unixBigLock); } #endif #ifdef SQLITE_HAVE_OS_TRACE /* ** Helper function for printing out trace information from debugging ** binaries. This returns the string representation of the supplied ** integer lock-type. */ static const char *azFileLock(int eFileLock){ switch( eFileLock ){ case NO_LOCK: return "NONE"; case SHARED_LOCK: return "SHARED"; case RESERVED_LOCK: return "RESERVED"; case PENDING_LOCK: return "PENDING"; case EXCLUSIVE_LOCK: return "EXCLUSIVE"; } return "ERROR"; } #endif #ifdef SQLITE_LOCK_TRACE /* ** Print out information about all locking operations. ** ** This routine is used for troubleshooting locks on multithreaded ** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE ** command-line option on the compiler. This code is normally ** turned off. */ static int lockTrace(int fd, int op, struct flock *p){ char *zOpName, *zType; int s; int savedErrno; if( op==F_GETLK ){ zOpName = "GETLK"; }else if( op==F_SETLK ){ zOpName = "SETLK"; }else{ s = osFcntl(fd, op, p); sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s); return s; } if( p->l_type==F_RDLCK ){ zType = "RDLCK"; }else if( p->l_type==F_WRLCK ){ zType = "WRLCK"; }else if( p->l_type==F_UNLCK ){ zType = "UNLCK"; }else{ assert( 0 ); } assert( p->l_whence==SEEK_SET ); s = osFcntl(fd, op, p); savedErrno = errno; sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n", threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len, (int)p->l_pid, s); if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ struct flock l2; l2 = *p; osFcntl(fd, F_GETLK, &l2); if( l2.l_type==F_RDLCK ){ zType = "RDLCK"; }else if( l2.l_type==F_WRLCK ){ zType = "WRLCK"; }else if( l2.l_type==F_UNLCK ){ zType = "UNLCK"; }else{ assert( 0 ); } sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n", zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid); } errno = savedErrno; return s; } #undef osFcntl #define osFcntl lockTrace #endif /* SQLITE_LOCK_TRACE */ /* ** Retry ftruncate() calls that fail due to EINTR ** ** All calls to ftruncate() within this file should be made through ** this wrapper. On the Android platform, bypassing the logic below ** could lead to a corrupt database. */ static int robust_ftruncate(int h, sqlite3_int64 sz){ int rc; #ifdef __ANDROID__ /* On Android, ftruncate() always uses 32-bit offsets, even if ** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to ** truncate a file to any size larger than 2GiB. Silently ignore any ** such attempts. */ if( sz>(sqlite3_int64)0x7FFFFFFF ){ rc = SQLITE_OK; }else #endif do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR ); return rc; } /* ** This routine translates a standard POSIX errno code into something ** useful to the clients of the sqlite3 functions. Specifically, it is ** intended to translate a variety of "try again" errors into SQLITE_BUSY ** and a variety of "please close the file descriptor NOW" errors into ** SQLITE_IOERR ** ** Errors during initialization of locks, or file system support for locks, ** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately. */ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { assert( (sqliteIOErr == SQLITE_IOERR_LOCK) || (sqliteIOErr == SQLITE_IOERR_UNLOCK) || (sqliteIOErr == SQLITE_IOERR_RDLOCK) || (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ); switch (posixError) { case EACCES: case EAGAIN: case ETIMEDOUT: case EBUSY: case EINTR: case ENOLCK: /* random NFS retry error, unless during file system support * introspection, in which it actually means what it says */ return SQLITE_BUSY; case EPERM: return SQLITE_PERM; default: return sqliteIOErr; } } /****************************************************************************** ****************** Begin Unique File ID Utility Used By VxWorks *************** ** ** On most versions of unix, we can get a unique ID for a file by concatenating ** the device number and the inode number. But this does not work on VxWorks. ** On VxWorks, a unique file id must be based on the canonical filename. ** ** A pointer to an instance of the following structure can be used as a ** unique file ID in VxWorks. Each instance of this structure contains ** a copy of the canonical filename. There is also a reference count. ** The structure is reclaimed when the number of pointers to it drops to ** zero. ** ** There are never very many files open at one time and lookups are not ** a performance-critical path, so it is sufficient to put these ** structures on a linked list. */ struct vxworksFileId { struct vxworksFileId *pNext; /* Next in a list of them all */ int nRef; /* Number of references to this one */ int nName; /* Length of the zCanonicalName[] string */ char *zCanonicalName; /* Canonical filename */ }; #if OS_VXWORKS /* ** All unique filenames are held on a linked list headed by this ** variable: */ static struct vxworksFileId *vxworksFileList = 0; /* ** Simplify a filename into its canonical form ** by making the following changes: ** ** * removing any trailing and duplicate / ** * convert /./ into just / ** * convert /A/../ where A is any simple name into just / ** ** Changes are made in-place. Return the new name length. ** ** The original filename is in z[0..n-1]. Return the number of ** characters in the simplified name. */ static int vxworksSimplifyName(char *z, int n){ int i, j; while( n>1 && z[n-1]=='/' ){ n--; } for(i=j=0; i0 && z[j-1]!='/' ){ j--; } if( j>0 ){ j--; } i += 2; continue; } } z[j++] = z[i]; } z[j] = 0; return j; } /* ** Find a unique file ID for the given absolute pathname. Return ** a pointer to the vxworksFileId object. This pointer is the unique ** file ID. ** ** The nRef field of the vxworksFileId object is incremented before ** the object is returned. A new vxworksFileId object is created ** and added to the global list if necessary. ** ** If a memory allocation error occurs, return NULL. */ static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){ struct vxworksFileId *pNew; /* search key and new file ID */ struct vxworksFileId *pCandidate; /* For looping over existing file IDs */ int n; /* Length of zAbsoluteName string */ assert( zAbsoluteName[0]=='/' ); n = (int)strlen(zAbsoluteName); pNew = sqlite3_malloc64( sizeof(*pNew) + (n+1) ); if( pNew==0 ) return 0; pNew->zCanonicalName = (char*)&pNew[1]; memcpy(pNew->zCanonicalName, zAbsoluteName, n+1); n = vxworksSimplifyName(pNew->zCanonicalName, n); /* Search for an existing entry that matching the canonical name. ** If found, increment the reference count and return a pointer to ** the existing file ID. */ unixEnterMutex(); for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){ if( pCandidate->nName==n && memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0 ){ sqlite3_free(pNew); pCandidate->nRef++; unixLeaveMutex(); return pCandidate; } } /* No match was found. We will make a new file ID */ pNew->nRef = 1; pNew->nName = n; pNew->pNext = vxworksFileList; vxworksFileList = pNew; unixLeaveMutex(); return pNew; } /* ** Decrement the reference count on a vxworksFileId object. Free ** the object when the reference count reaches zero. */ static void vxworksReleaseFileId(struct vxworksFileId *pId){ unixEnterMutex(); assert( pId->nRef>0 ); pId->nRef--; if( pId->nRef==0 ){ struct vxworksFileId **pp; for(pp=&vxworksFileList; *pp && *pp!=pId; pp = &((*pp)->pNext)){} assert( *pp==pId ); *pp = pId->pNext; sqlite3_free(pId); } unixLeaveMutex(); } #endif /* OS_VXWORKS */ /*************** End of Unique File ID Utility Used By VxWorks **************** ******************************************************************************/ /****************************************************************************** *************************** Posix Advisory Locking **************************** ** ** POSIX advisory locks are broken by design. ANSI STD 1003.1 (1996) ** section 6.5.2.2 lines 483 through 490 specify that when a process ** sets or clears a lock, that operation overrides any prior locks set ** by the same process. It does not explicitly say so, but this implies ** that it overrides locks set by the same process using a different ** file descriptor. Consider this test case: ** ** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644); ** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644); ** ** Suppose ./file1 and ./file2 are really the same file (because ** one is a hard or symbolic link to the other) then if you set ** an exclusive lock on fd1, then try to get an exclusive lock ** on fd2, it works. I would have expected the second lock to ** fail since there was already a lock on the file due to fd1. ** But not so. Since both locks came from the same process, the ** second overrides the first, even though they were on different ** file descriptors opened on different file names. ** ** This means that we cannot use POSIX locks to synchronize file access ** among competing threads of the same process. POSIX locks will work fine ** to synchronize access for threads in separate processes, but not ** threads within the same process. ** ** To work around the problem, SQLite has to manage file locks internally ** on its own. Whenever a new database is opened, we have to find the ** specific inode of the database file (the inode is determined by the ** st_dev and st_ino fields of the stat structure that fstat() fills in) ** and check for locks already existing on that inode. When locks are ** created or removed, we have to look at our own internal record of the ** locks to see if another thread has previously set a lock on that same ** inode. ** ** (Aside: The use of inode numbers as unique IDs does not work on VxWorks. ** For VxWorks, we have to use the alternative unique ID system based on ** canonical filename and implemented in the previous division.) ** ** The sqlite3_file structure for POSIX is no longer just an integer file ** descriptor. It is now a structure that holds the integer file ** descriptor and a pointer to a structure that describes the internal ** locks on the corresponding inode. There is one locking structure ** per inode, so if the same inode is opened twice, both unixFile structures ** point to the same locking structure. The locking structure keeps ** a reference count (so we will know when to delete it) and a "cnt" ** field that tells us its internal lock status. cnt==0 means the ** file is unlocked. cnt==-1 means the file has an exclusive lock. ** cnt>0 means there are cnt shared locks on the file. ** ** Any attempt to lock or unlock a file first checks the locking ** structure. The fcntl() system call is only invoked to set a ** POSIX lock if the internal lock structure transitions between ** a locked and an unlocked state. ** ** But wait: there are yet more problems with POSIX advisory locks. ** ** If you close a file descriptor that points to a file that has locks, ** all locks on that file that are owned by the current process are ** released. To work around this problem, each unixInodeInfo object ** maintains a count of the number of pending locks on the inode. ** When an attempt is made to close an unixFile, if there are ** other unixFile open on the same inode that are holding locks, the call ** to close() the file descriptor is deferred until all of the locks clear. ** The unixInodeInfo structure keeps a list of file descriptors that need to ** be closed and that list is walked (and cleared) when the last lock ** clears. ** ** Yet another problem: LinuxThreads do not play well with posix locks. ** ** Many older versions of linux use the LinuxThreads library which is ** not posix compliant. Under LinuxThreads, a lock created by thread ** A cannot be modified or overridden by a different thread B. ** Only thread A can modify the lock. Locking behavior is correct ** if the application uses the newer Native Posix Thread Library (NPTL) ** on linux - with NPTL a lock created by thread A can override locks ** in thread B. But there is no way to know at compile-time which ** threading library is being used. So there is no way to know at ** compile-time whether or not thread A can override locks on thread B. ** One has to do a run-time check to discover the behavior of the ** current process. ** ** SQLite used to support LinuxThreads. But support for LinuxThreads ** was dropped beginning with version 3.7.0. SQLite will still work with ** LinuxThreads provided that (1) there is no more than one connection ** per database file in the same process and (2) database connections ** do not move across threads. */ /* ** An instance of the following structure serves as the key used ** to locate a particular unixInodeInfo object. */ struct unixFileId { dev_t dev; /* Device number */ #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID for vxworks. */ #else /* We are told that some versions of Android contain a bug that ** sizes ino_t at only 32-bits instead of 64-bits. (See ** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c) ** To work around this, always allocate 64-bits for the inode number. ** On small machines that only have 32-bit inodes, this wastes 4 bytes, ** but that should not be a big deal. */ /* WAS: ino_t ino; */ u64 ino; /* Inode number */ #endif }; /* ** An instance of the following structure is allocated for each open ** inode. ** ** A single inode can have multiple file descriptors, so each unixFile ** structure contains a pointer to an instance of this object and this ** object keeps a count of the number of unixFile pointing to it. ** ** Mutex rules: ** ** (1) Only the pLockMutex mutex must be held in order to read or write ** any of the locking fields: ** nShared, nLock, eFileLock, bProcessLock, pUnused ** ** (2) When nRef>0, then the following fields are unchanging and can ** be read (but not written) without holding any mutex: ** fileId, pLockMutex ** ** (3) With the exceptions above, all the fields may only be read ** or written while holding the global unixBigLock mutex. ** ** Deadlock prevention: The global unixBigLock mutex may not ** be acquired while holding the pLockMutex mutex. If both unixBigLock ** and pLockMutex are needed, then unixBigLock must be acquired first. */ struct unixInodeInfo { struct unixFileId fileId; /* The lookup key */ sqlite3_mutex *pLockMutex; /* Hold this mutex for... */ int nShared; /* Number of SHARED locks held */ int nLock; /* Number of outstanding file locks */ unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ unsigned char bProcessLock; /* An exclusive process lock is held */ UnixUnusedFd *pUnused; /* Unused file descriptors to close */ int nRef; /* Number of pointers to this structure */ unixShmNode *pShmNode; /* Shared memory associated with this inode */ unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ unixInodeInfo *pPrev; /* .... doubly linked */ #if SQLITE_ENABLE_LOCKING_STYLE unsigned long long sharedByte; /* for AFP simulated shared lock */ #endif #if OS_VXWORKS sem_t *pSem; /* Named POSIX semaphore */ char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */ #endif }; /* ** A lists of all unixInodeInfo objects. ** ** Must hold unixBigLock in order to read or write this variable. */ static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */ #ifdef SQLITE_DEBUG /* ** True if the inode mutex (on the unixFile.pFileMutex field) is held, or not. ** This routine is used only within assert() to help verify correct mutex ** usage. */ int unixFileMutexHeld(unixFile *pFile){ assert( pFile->pInode ); return sqlite3_mutex_held(pFile->pInode->pLockMutex); } int unixFileMutexNotheld(unixFile *pFile){ assert( pFile->pInode ); return sqlite3_mutex_notheld(pFile->pInode->pLockMutex); } #endif /* ** ** This function - unixLogErrorAtLine(), is only ever called via the macro ** unixLogError(). ** ** It is invoked after an error occurs in an OS function and errno has been ** set. It logs a message using sqlite3_log() containing the current value of ** errno and, if possible, the human-readable equivalent from strerror() or ** strerror_r(). ** ** The first argument passed to the macro should be the error code that ** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). ** The two subsequent arguments should be the name of the OS function that ** failed (e.g. "unlink", "open") and the associated file-system path, ** if any. */ #define unixLogError(a,b,c) unixLogErrorAtLine(a,b,c,__LINE__) static int unixLogErrorAtLine( int errcode, /* SQLite error code */ const char *zFunc, /* Name of OS function that failed */ const char *zPath, /* File path associated with error */ int iLine /* Source line number where error occurred */ ){ char *zErr; /* Message from strerror() or equivalent */ int iErrno = errno; /* Saved syscall error number */ /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use ** the strerror() function to obtain the human-readable error message ** equivalent to errno. Otherwise, use strerror_r(). */ #if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R) char aErr[80]; memset(aErr, 0, sizeof(aErr)); zErr = aErr; /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined, ** assume that the system provides the GNU version of strerror_r() that ** returns a pointer to a buffer containing the error message. That pointer ** may point to aErr[], or it may point to some static storage somewhere. ** Otherwise, assume that the system provides the POSIX version of ** strerror_r(), which always writes an error message into aErr[]. ** ** If the code incorrectly assumes that it is the POSIX version that is ** available, the error message will often be an empty string. Not a ** huge problem. Incorrectly concluding that the GNU version is available ** could lead to a segfault though. */ #if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU) zErr = # endif strerror_r(iErrno, aErr, sizeof(aErr)-1); #elif SQLITE_THREADSAFE /* This is a threadsafe build, but strerror_r() is not available. */ zErr = ""; #else /* Non-threadsafe build, use strerror(). */ zErr = strerror(iErrno); #endif if( zPath==0 ) zPath = ""; sqlite3_log(errcode, "os_unix.c:%d: (%d) %s(%s) - %s", iLine, iErrno, zFunc, zPath, zErr ); return errcode; } /* ** Close a file descriptor. ** ** We assume that close() almost always works, since it is only in a ** very sick application or on a very sick platform that it might fail. ** If it does fail, simply leak the file descriptor, but do log the ** error. ** ** Note that it is not safe to retry close() after EINTR since the ** file descriptor might have already been reused by another thread. ** So we don't even try to recover from an EINTR. Just log the error ** and move on. */ static void robust_close(unixFile *pFile, int h, int lineno){ if( osClose(h) ){ unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close", pFile ? pFile->zPath : 0, lineno); } } /* ** Set the pFile->lastErrno. Do this in a subroutine as that provides ** a convenient place to set a breakpoint. */ static void storeLastErrno(unixFile *pFile, int error){ pFile->lastErrno = error; } /* ** Close all file descriptors accumulated in the unixInodeInfo->pUnused list. */ static void closePendingFds(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; UnixUnusedFd *p; UnixUnusedFd *pNext; assert( unixFileMutexHeld(pFile) ); for(p=pInode->pUnused; p; p=pNext){ pNext = p->pNext; robust_close(pFile, p->fd, __LINE__); sqlite3_free(p); } pInode->pUnused = 0; } /* ** Release a unixInodeInfo structure previously allocated by findInodeInfo(). ** ** The global mutex must be held when this routine is called, but the mutex ** on the inode being deleted must NOT be held. */ static void releaseInodeInfo(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); assert( unixFileMutexNotheld(pFile) ); if( ALWAYS(pInode) ){ pInode->nRef--; if( pInode->nRef==0 ){ assert( pInode->pShmNode==0 ); sqlite3_mutex_enter(pInode->pLockMutex); closePendingFds(pFile); sqlite3_mutex_leave(pInode->pLockMutex); if( pInode->pPrev ){ assert( pInode->pPrev->pNext==pInode ); pInode->pPrev->pNext = pInode->pNext; }else{ assert( inodeList==pInode ); inodeList = pInode->pNext; } if( pInode->pNext ){ assert( pInode->pNext->pPrev==pInode ); pInode->pNext->pPrev = pInode->pPrev; } sqlite3_mutex_free(pInode->pLockMutex); sqlite3_free(pInode); } } } /* ** Given a file descriptor, locate the unixInodeInfo object that ** describes that file descriptor. Create a new one if necessary. The ** return value might be uninitialized if an error occurs. ** ** The global mutex must held when calling this routine. ** ** Return an appropriate error code. */ static int findInodeInfo( unixFile *pFile, /* Unix file with file desc used in the key */ unixInodeInfo **ppInode /* Return the unixInodeInfo object here */ ){ int rc; /* System call return code */ int fd; /* The file descriptor for pFile */ struct unixFileId fileId; /* Lookup key for the unixInodeInfo */ struct stat statbuf; /* Low-level file information */ unixInodeInfo *pInode = 0; /* Candidate unixInodeInfo object */ assert( unixMutexHeld() ); /* Get low-level information about the file that we can used to ** create a unique name for the file. */ fd = pFile->h; rc = osFstat(fd, &statbuf); if( rc!=0 ){ storeLastErrno(pFile, errno); #if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS) if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; #endif return SQLITE_IOERR; } #ifdef __APPLE__ /* On OS X on an msdos filesystem, the inode number is reported ** incorrectly for zero-size files. See ticket #3260. To work ** around this problem (we consider it a bug in OS X, not SQLite) ** we always increase the file size to 1 by writing a single byte ** prior to accessing the inode number. The one byte written is ** an ASCII 'S' character which also happens to be the first byte ** in the header of every SQLite database. In this way, if there ** is a race condition such that another thread has already populated ** the first page of the database, no damage is done. */ if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){ do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); if( rc!=1 ){ storeLastErrno(pFile, errno); return SQLITE_IOERR; } rc = osFstat(fd, &statbuf); if( rc!=0 ){ storeLastErrno(pFile, errno); return SQLITE_IOERR; } } #endif memset(&fileId, 0, sizeof(fileId)); fileId.dev = statbuf.st_dev; #if OS_VXWORKS fileId.pId = pFile->pId; #else fileId.ino = (u64)statbuf.st_ino; #endif assert( unixMutexHeld() ); pInode = inodeList; while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){ pInode = pInode->pNext; } if( pInode==0 ){ pInode = sqlite3_malloc64( sizeof(*pInode) ); if( pInode==0 ){ return SQLITE_NOMEM_BKPT; } memset(pInode, 0, sizeof(*pInode)); memcpy(&pInode->fileId, &fileId, sizeof(fileId)); if( sqlite3GlobalConfig.bCoreMutex ){ pInode->pLockMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( pInode->pLockMutex==0 ){ sqlite3_free(pInode); return SQLITE_NOMEM_BKPT; } } pInode->nRef = 1; assert( unixMutexHeld() ); pInode->pNext = inodeList; pInode->pPrev = 0; if( inodeList ) inodeList->pPrev = pInode; inodeList = pInode; }else{ pInode->nRef++; } *ppInode = pInode; return SQLITE_OK; } /* ** Return TRUE if pFile has been renamed or unlinked since it was first opened. */ static int fileHasMoved(unixFile *pFile){ #if OS_VXWORKS return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId; #else struct stat buf; return pFile->pInode!=0 && (osStat(pFile->zPath, &buf)!=0 || (u64)buf.st_ino!=pFile->pInode->fileId.ino); #endif } /* ** Check a unixFile that is a database. Verify the following: ** ** (1) There is exactly one hard link on the file ** (2) The file is not a symbolic link ** (3) The file has not been renamed or unlinked ** ** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right. */ static void verifyDbFile(unixFile *pFile){ struct stat buf; int rc; /* These verifications occurs for the main database only */ if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return; rc = osFstat(pFile->h, &buf); if( rc!=0 ){ sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath); return; } if( buf.st_nlink==0 ){ sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath); return; } if( buf.st_nlink>1 ){ sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath); return; } if( fileHasMoved(pFile) ){ sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath); return; } } /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); assert( pFile->eFileLock<=SHARED_LOCK ); sqlite3_mutex_enter(pFile->pInode->pLockMutex); /* Check if a thread in this process holds such a lock */ if( pFile->pInode->eFileLock>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ #ifndef __DJGPP__ if( !reserved && !pFile->pInode->bProcessLock ){ struct flock lock; lock.l_whence = SEEK_SET; lock.l_start = RESERVED_BYTE; lock.l_len = 1; lock.l_type = F_WRLCK; if( osFcntl(pFile->h, F_GETLK, &lock) ){ rc = SQLITE_IOERR_CHECKRESERVEDLOCK; storeLastErrno(pFile, errno); } else if( lock.l_type!=F_UNLCK ){ reserved = 1; } } #endif sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* Forward declaration*/ static int unixSleep(sqlite3_vfs*,int); /* ** Set a posix-advisory-lock. ** ** There are two versions of this routine. If compiled with ** SQLITE_ENABLE_SETLK_TIMEOUT then the routine has an extra parameter ** which is a pointer to a unixFile. If the unixFile->iBusyTimeout ** value is set, then it is the number of milliseconds to wait before ** failing the lock. The iBusyTimeout value is always reset back to ** zero on each call. ** ** If SQLITE_ENABLE_SETLK_TIMEOUT is not defined, then do a non-blocking ** attempt to set the lock. */ #ifndef SQLITE_ENABLE_SETLK_TIMEOUT # define osSetPosixAdvisoryLock(h,x,t) osFcntl(h,F_SETLK,x) #else static int osSetPosixAdvisoryLock( int h, /* The file descriptor on which to take the lock */ struct flock *pLock, /* The description of the lock */ unixFile *pFile /* Structure holding timeout value */ ){ int tm = pFile->iBusyTimeout; int rc = osFcntl(h,F_SETLK,pLock); while( rc<0 && tm>0 ){ /* On systems that support some kind of blocking file lock with a timeout, ** make appropriate changes here to invoke that blocking file lock. On ** generic posix, however, there is no such API. So we simply try the ** lock once every millisecond until either the timeout expires, or until ** the lock is obtained. */ unixSleep(0,1000); rc = osFcntl(h,F_SETLK,pLock); tm--; } return rc; } #endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ /* ** Attempt to set a system-lock on the file pFile. The lock is ** described by pLock. ** ** If the pFile was opened read/write from unix-excl, then the only lock ** ever obtained is an exclusive lock, and it is obtained exactly once ** the first time any lock is attempted. All subsequent system locking ** operations become no-ops. Locking operations still happen internally, ** in order to coordinate access between separate database connections ** within this process, but all of that is handled in memory and the ** operating system does not participate. ** ** This function is a pass-through to fcntl(F_SETLK) if pFile is using ** any VFS other than "unix-excl" or if pFile is opened on "unix-excl" ** and is read-only. ** ** Zero is returned if the call completes successfully, or -1 if a call ** to fcntl() fails. In this case, errno is set appropriately (by fcntl()). */ static int unixFileLock(unixFile *pFile, struct flock *pLock){ int rc; unixInodeInfo *pInode = pFile->pInode; assert( pInode!=0 ); assert( sqlite3_mutex_held(pInode->pLockMutex) ); if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){ if( pInode->bProcessLock==0 ){ struct flock lock; assert( pInode->nLock==0 ); lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; lock.l_type = F_WRLCK; rc = osSetPosixAdvisoryLock(pFile->h, &lock, pFile); if( rc<0 ) return rc; pInode->bProcessLock = 1; pInode->nLock++; }else{ rc = 0; } }else{ rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile); } return rc; } /* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK ** (3) PENDING_LOCK ** (4) EXCLUSIVE_LOCK ** ** Sometimes when requesting one lock state, additional lock states ** are inserted in between. The locking might fail on one of the later ** transitions leaving the lock state different from what it started but ** still short of its goal. The following chart shows the allowed ** transitions and the inserted intermediate states: ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED ** SHARED -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ static int unixLock(sqlite3_file *id, int eFileLock){ /* The following describes the implementation of the various locks and ** lock transitions in terms of the POSIX advisory shared and exclusive ** lock primitives (called read-locks and write-locks below, to avoid ** confusion with SQLite lock names). The algorithms are complicated ** slightly in order to be compatible with Windows95 systems simultaneously ** accessing the same database file, in case that is ever required. ** ** Symbols defined in os.h identify the 'pending byte' and the 'reserved ** byte', each single bytes at well known offsets, and the 'shared byte ** range', a range of 510 bytes at a well known offset. ** ** To obtain a SHARED lock, a read-lock is obtained on the 'pending ** byte'. If this is successful, 'shared byte range' is read-locked ** and the lock on the 'pending byte' released. (Legacy note: When ** SQLite was first developed, Windows95 systems were still very common, ** and Windows95 lacks a shared-lock capability. So on Windows95, a ** single randomly selected by from the 'shared byte range' is locked. ** Windows95 is now pretty much extinct, but this work-around for the ** lack of shared-locks on Windows95 lives on, for backwards ** compatibility.) ** ** A process may only obtain a RESERVED lock after it has a SHARED lock. ** A RESERVED lock is implemented by grabbing a write-lock on the ** 'reserved byte'. ** ** An EXCLUSIVE lock may only be requested after either a SHARED or ** RESERVED lock is held. An EXCLUSIVE lock is implemented by obtaining ** a write-lock on the entire 'shared byte range'. Since all other locks ** require a read-lock on one of the bytes within this range, this ensures ** that no other locks are held on the database. ** ** If a process that holds a RESERVED lock requests an EXCLUSIVE, then ** a PENDING lock is obtained first. A PENDING lock is implemented by ** obtaining a write-lock on the 'pending byte'. This ensures that no new ** SHARED locks can be obtained, but existing SHARED locks are allowed to ** persist. If the call to this function fails to obtain the EXCLUSIVE ** lock in this case, it holds the PENDING lock instead. The client may ** then re-attempt the EXCLUSIVE lock later on, after existing SHARED ** locks have cleared. */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode; struct flock lock; int tErrno = 0; assert( pFile ); OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, azFileLock(eFileLock), azFileLock(pFile->eFileLock), azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared, osGetpid(0))); /* If there is already a lock of this type or more restrictive on the ** unixFile, do nothing. Don't use the end_lock: exit path, as ** unixEnterMutex() hasn't been called yet. */ if( pFile->eFileLock>=eFileLock ){ OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h, azFileLock(eFileLock))); return SQLITE_OK; } /* Make sure the locking sequence is correct. ** (1) We never move from unlocked to anything higher than shared lock. ** (2) SQLite never explicitly requests a pending lock. ** (3) A shared lock is always held when a reserve lock is requested. */ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); assert( eFileLock!=PENDING_LOCK ); assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); /* This mutex is needed because pFile->pInode is shared across threads */ pInode = pFile->pInode; sqlite3_mutex_enter(pInode->pLockMutex); /* If some thread using this PID has a lock via a different unixFile* ** handle that precludes the requested lock, return BUSY. */ if( (pFile->eFileLock!=pInode->eFileLock && (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ){ rc = SQLITE_BUSY; goto end_lock; } /* If a SHARED lock is requested, and some thread using this PID already ** has a SHARED or RESERVED lock, then increment reference counts and ** return SQLITE_OK. */ if( eFileLock==SHARED_LOCK && (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){ assert( eFileLock==SHARED_LOCK ); assert( pFile->eFileLock==0 ); assert( pInode->nShared>0 ); pFile->eFileLock = SHARED_LOCK; pInode->nShared++; pInode->nLock++; goto end_lock; } /* A PENDING lock is needed before acquiring a SHARED lock and before ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will ** be released. */ lock.l_len = 1L; lock.l_whence = SEEK_SET; if( eFileLock==SHARED_LOCK || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock==RESERVED_LOCK) ){ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK); lock.l_start = PENDING_BYTE; if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( rc!=SQLITE_BUSY ){ storeLastErrno(pFile, tErrno); } goto end_lock; }else if( eFileLock==EXCLUSIVE_LOCK ){ pFile->eFileLock = PENDING_LOCK; pInode->eFileLock = PENDING_LOCK; } } /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ if( eFileLock==SHARED_LOCK ){ assert( pInode->nShared==0 ); assert( pInode->eFileLock==0 ); assert( rc==SQLITE_OK ); /* Now get the read-lock */ lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); } /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; lock.l_type = F_UNLCK; if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){ /* This could happen with a network mount */ tErrno = errno; rc = SQLITE_IOERR_UNLOCK; } if( rc ){ if( rc!=SQLITE_BUSY ){ storeLastErrno(pFile, tErrno); } goto end_lock; }else{ pFile->eFileLock = SHARED_LOCK; pInode->nLock++; pInode->nShared = 1; } }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file ** already. */ assert( 0!=pFile->eFileLock ); lock.l_type = F_WRLCK; assert( eFileLock==RESERVED_LOCK || eFileLock==EXCLUSIVE_LOCK ); if( eFileLock==RESERVED_LOCK ){ lock.l_start = RESERVED_BYTE; lock.l_len = 1L; }else{ lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; } if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( rc!=SQLITE_BUSY ){ storeLastErrno(pFile, tErrno); } } } #ifdef SQLITE_DEBUG /* Set up the transaction-counter change checking flags when ** transitioning from a SHARED to a RESERVED lock. The change ** from SHARED to RESERVED marks the beginning of a normal ** write operation (not a hot journal rollback). */ if( rc==SQLITE_OK && pFile->eFileLock<=SHARED_LOCK && eFileLock==RESERVED_LOCK ){ pFile->transCntrChng = 0; pFile->dbUpdate = 0; pFile->inNormalWrite = 1; } #endif if( rc==SQLITE_OK ){ pFile->eFileLock = eFileLock; pInode->eFileLock = eFileLock; } end_lock: sqlite3_mutex_leave(pInode->pLockMutex); OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); return rc; } /* ** Add the file descriptor used by file handle pFile to the corresponding ** pUnused list. */ static void setPendingFd(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; UnixUnusedFd *p = pFile->pPreallocatedUnused; assert( unixFileMutexHeld(pFile) ); p->pNext = pInode->pUnused; pInode->pUnused = p; pFile->h = -1; pFile->pPreallocatedUnused = 0; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. ** ** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED ** the byte range is divided into 2 parts and the first part is unlocked then ** set to a read lock, then the other part is simply unlocked. This works ** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to ** remove the write lock on a region when a read lock is set. */ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode; struct flock lock; int rc = SQLITE_OK; assert( pFile ); OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock, pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } pInode = pFile->pInode; sqlite3_mutex_enter(pInode->pLockMutex); assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); #ifdef SQLITE_DEBUG /* When reducing a lock such that other processes can start ** reading the database file again, make sure that the ** transaction counter was updated if any part of the database ** file changed. If the transaction counter is not updated, ** other connections to the same file might not realize that ** the file has changed and hence might not know to flush their ** cache. The use of a stale cache can lead to database corruption. */ pFile->inNormalWrite = 0; #endif /* downgrading to a shared lock on NFS involves clearing the write lock ** before establishing the readlock - to avoid a race condition we downgrade ** the lock in 2 blocks, so that part of the range will be covered by a ** write lock until the rest is covered by a read lock: ** 1: [WWWWW] ** 2: [....W] ** 3: [RRRRW] ** 4: [RRRR.] */ if( eFileLock==SHARED_LOCK ){ #if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE (void)handleNFSUnlock; assert( handleNFSUnlock==0 ); #endif #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE if( handleNFSUnlock ){ int tErrno; /* Error code from system call errors */ off_t divSize = SHARED_SIZE - 1; lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = divSize; if( unixFileLock(pFile, &lock)==(-1) ){ tErrno = errno; rc = SQLITE_IOERR_UNLOCK; storeLastErrno(pFile, tErrno); goto end_unlock; } lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = divSize; if( unixFileLock(pFile, &lock)==(-1) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); if( IS_LOCK_ERROR(rc) ){ storeLastErrno(pFile, tErrno); } goto end_unlock; } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST+divSize; lock.l_len = SHARED_SIZE-divSize; if( unixFileLock(pFile, &lock)==(-1) ){ tErrno = errno; rc = SQLITE_IOERR_UNLOCK; storeLastErrno(pFile, tErrno); goto end_unlock; } }else #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ { lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; if( unixFileLock(pFile, &lock) ){ /* In theory, the call to unixFileLock() cannot fail because another ** process is holding an incompatible lock. If it does, this ** indicates that the other process is not following the locking ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning ** SQLITE_BUSY would confuse the upper layer (in practice it causes ** an assert to fail). */ rc = SQLITE_IOERR_RDLOCK; storeLastErrno(pFile, errno); goto end_unlock; } } } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); if( unixFileLock(pFile, &lock)==0 ){ pInode->eFileLock = SHARED_LOCK; }else{ rc = SQLITE_IOERR_UNLOCK; storeLastErrno(pFile, errno); goto end_unlock; } } if( eFileLock==NO_LOCK ){ /* Decrement the shared lock counter. Release the lock using an ** OS call only when all threads in this same process have released ** the lock. */ pInode->nShared--; if( pInode->nShared==0 ){ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; if( unixFileLock(pFile, &lock)==0 ){ pInode->eFileLock = NO_LOCK; }else{ rc = SQLITE_IOERR_UNLOCK; storeLastErrno(pFile, errno); pInode->eFileLock = NO_LOCK; pFile->eFileLock = NO_LOCK; } } /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. */ pInode->nLock--; assert( pInode->nLock>=0 ); if( pInode->nLock==0 ) closePendingFds(pFile); } end_unlock: sqlite3_mutex_leave(pInode->pLockMutex); if( rc==SQLITE_OK ){ pFile->eFileLock = eFileLock; } return rc; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int unixUnlock(sqlite3_file *id, int eFileLock){ #if SQLITE_MAX_MMAP_SIZE>0 assert( eFileLock==SHARED_LOCK || ((unixFile *)id)->nFetchOut==0 ); #endif return posixUnlock(id, eFileLock, 0); } #if SQLITE_MAX_MMAP_SIZE>0 static int unixMapfile(unixFile *pFd, i64 nByte); static void unixUnmapfile(unixFile *pFd); #endif /* ** This function performs the parts of the "close file" operation ** common to all locking schemes. It closes the directory and file ** handles, if they are valid, and sets all fields of the unixFile ** structure to 0. ** ** It is *not* necessary to hold the mutex when this routine is called, ** even on VxWorks. A mutex will be acquired on VxWorks by the ** vxworksReleaseFileId() routine. */ static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; #if SQLITE_MAX_MMAP_SIZE>0 unixUnmapfile(pFile); #endif if( pFile->h>=0 ){ robust_close(pFile, pFile->h, __LINE__); pFile->h = -1; } #if OS_VXWORKS if( pFile->pId ){ if( pFile->ctrlFlags & UNIXFILE_DELETE ){ osUnlink(pFile->pId->zCanonicalName); } vxworksReleaseFileId(pFile->pId); pFile->pId = 0; } #endif #ifdef SQLITE_UNLINK_AFTER_CLOSE if( pFile->ctrlFlags & UNIXFILE_DELETE ){ osUnlink(pFile->zPath); sqlite3_free(*(char**)&pFile->zPath); pFile->zPath = 0; } #endif OSTRACE(("CLOSE %-3d\n", pFile->h)); OpenCounter(-1); sqlite3_free(pFile->pPreallocatedUnused); memset(pFile, 0, sizeof(unixFile)); return SQLITE_OK; } /* ** Close a file. */ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; unixFile *pFile = (unixFile *)id; unixInodeInfo *pInode = pFile->pInode; assert( pInode!=0 ); verifyDbFile(pFile); unixUnlock(id, NO_LOCK); assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); /* unixFile.pInode is always valid here. Otherwise, a different close ** routine (e.g. nolockClose()) would be called instead. */ assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); sqlite3_mutex_enter(pInode->pLockMutex); if( pInode->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pInode->pUnused list. It will be automatically closed ** when the last lock is cleared. */ setPendingFd(pFile); } sqlite3_mutex_leave(pInode->pLockMutex); releaseInodeInfo(pFile); assert( pFile->pShm==0 ); rc = closeUnixFile(id); unixLeaveMutex(); return rc; } /************** End of the posix advisory lock implementation ***************** ******************************************************************************/ /****************************************************************************** ****************************** No-op Locking ********************************** ** ** Of the various locking implementations available, this is by far the ** simplest: locking is ignored. No attempt is made to lock the database ** file for reading or writing. ** ** This locking mode is appropriate for use on read-only databases ** (ex: databases that are burned into CD-ROM, for example.) It can ** also be used if the application employs some external mechanism to ** prevent simultaneous access of the same database by two or more ** database connections. But there is a serious risk of database ** corruption if this locking mode is used in situations where multiple ** database connections are accessing the same database file at the same ** time and one or more of those connections are writing. */ static int nolockCheckReservedLock(sqlite3_file *NotUsed, int *pResOut){ UNUSED_PARAMETER(NotUsed); *pResOut = 0; return SQLITE_OK; } static int nolockLock(sqlite3_file *NotUsed, int NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); return SQLITE_OK; } static int nolockUnlock(sqlite3_file *NotUsed, int NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); return SQLITE_OK; } /* ** Close the file. */ static int nolockClose(sqlite3_file *id) { return closeUnixFile(id); } /******************* End of the no-op lock implementation ********************* ******************************************************************************/ /****************************************************************************** ************************* Begin dot-file Locking ****************************** ** ** The dotfile locking implementation uses the existence of separate lock ** files (really a directory) to control access to the database. This works ** on just about every filesystem imaginable. But there are serious downsides: ** ** (1) There is zero concurrency. A single reader blocks all other ** connections from reading or writing the database. ** ** (2) An application crash or power loss can leave stale lock files ** sitting around that need to be cleared manually. ** ** Nevertheless, a dotlock is an appropriate locking mode for use if no ** other locking strategy is available. ** ** Dotfile locking works by creating a subdirectory in the same directory as ** the database and with the same name but with a ".lock" extension added. ** The existence of a lock directory implies an EXCLUSIVE lock. All other ** lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE. */ /* ** The file suffix added to the data base filename in order to create the ** lock directory. */ #define DOTLOCK_SUFFIX ".lock" /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. ** ** In dotfile locking, either a lock exists or it does not. So in this ** variation of CheckReservedLock(), *pResOut is set to true if any lock ** is held on the file and false if the file is unlocked. */ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) { int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); reserved = osAccess((const char*)pFile->lockingContext, 0)==0; OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK ** (3) PENDING_LOCK ** (4) EXCLUSIVE_LOCK ** ** Sometimes when requesting one lock state, additional lock states ** are inserted in between. The locking might fail on one of the later ** transitions leaving the lock state different from what it started but ** still short of its goal. The following chart shows the allowed ** transitions and the inserted intermediate states: ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED ** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. ** ** With dotfile locking, we really only support state (4): EXCLUSIVE. ** But we track the other locking levels internally. */ static int dotlockLock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; char *zLockFile = (char *)pFile->lockingContext; int rc = SQLITE_OK; /* If we have any lock, then the lock file already exists. All we have ** to do is adjust our internal record of the lock level. */ if( pFile->eFileLock > NO_LOCK ){ pFile->eFileLock = eFileLock; /* Always update the timestamp on the old file */ #ifdef HAVE_UTIME utime(zLockFile, NULL); #else utimes(zLockFile, NULL); #endif return SQLITE_OK; } /* grab an exclusive lock */ rc = osMkdir(zLockFile, 0777); if( rc<0 ){ /* failed to open/create the lock directory */ int tErrno = errno; if( EEXIST == tErrno ){ rc = SQLITE_BUSY; } else { rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( rc!=SQLITE_BUSY ){ storeLastErrno(pFile, tErrno); } } return rc; } /* got it, set the type and return ok */ pFile->eFileLock = eFileLock; return rc; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. ** ** When the locking level reaches NO_LOCK, delete the lock file. */ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; char *zLockFile = (char *)pFile->lockingContext; int rc; assert( pFile ); OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock, pFile->eFileLock, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); /* no-op if possible */ if( pFile->eFileLock==eFileLock ){ return SQLITE_OK; } /* To downgrade to shared, simply update our internal notion of the ** lock state. No need to mess with the file on disk. */ if( eFileLock==SHARED_LOCK ){ pFile->eFileLock = SHARED_LOCK; return SQLITE_OK; } /* To fully unlock the database, delete the lock file */ assert( eFileLock==NO_LOCK ); rc = osRmdir(zLockFile); if( rc<0 ){ int tErrno = errno; if( tErrno==ENOENT ){ rc = SQLITE_OK; }else{ rc = SQLITE_IOERR_UNLOCK; storeLastErrno(pFile, tErrno); } return rc; } pFile->eFileLock = NO_LOCK; return SQLITE_OK; } /* ** Close a file. Make sure the lock has been released before closing. */ static int dotlockClose(sqlite3_file *id) { unixFile *pFile = (unixFile*)id; assert( id!=0 ); dotlockUnlock(id, NO_LOCK); sqlite3_free(pFile->lockingContext); return closeUnixFile(id); } /****************** End of the dot-file lock implementation ******************* ******************************************************************************/ /****************************************************************************** ************************** Begin flock Locking ******************************** ** ** Use the flock() system call to do file locking. ** ** flock() locking is like dot-file locking in that the various ** fine-grain locking levels supported by SQLite are collapsed into ** a single exclusive lock. In other words, SHARED, RESERVED, and ** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite ** still works when you do this, but concurrency is reduced since ** only a single process can be reading the database at a time. ** ** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off */ #if SQLITE_ENABLE_LOCKING_STYLE /* ** Retry flock() calls that fail with EINTR */ #ifdef EINTR static int robust_flock(int fd, int op){ int rc; do{ rc = flock(fd,op); }while( rc<0 && errno==EINTR ); return rc; } #else # define robust_flock(a,b) flock(a,b) #endif /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); /* Check if a thread in this process holds such a lock */ if( pFile->eFileLock>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ if( !reserved ){ /* attempt to get the lock */ int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB); if( !lrc ){ /* got the lock, unlock it */ lrc = robust_flock(pFile->h, LOCK_UN); if ( lrc ) { int tErrno = errno; /* unlock failed with an error */ lrc = SQLITE_IOERR_UNLOCK; storeLastErrno(pFile, tErrno); rc = lrc; } } else { int tErrno = errno; reserved = 1; /* someone else might have it reserved */ lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(lrc) ){ storeLastErrno(pFile, tErrno); rc = lrc; } } } OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved)); #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS if( (rc & 0xff) == SQLITE_IOERR ){ rc = SQLITE_OK; reserved=1; } #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ *pResOut = reserved; return rc; } /* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK ** (3) PENDING_LOCK ** (4) EXCLUSIVE_LOCK ** ** Sometimes when requesting one lock state, additional lock states ** are inserted in between. The locking might fail on one of the later ** transitions leaving the lock state different from what it started but ** still short of its goal. The following chart shows the allowed ** transitions and the inserted intermediate states: ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED ** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** ** flock() only really support EXCLUSIVE locks. We track intermediate ** lock states in the sqlite3_file structure, but all locks SHARED or ** above are really EXCLUSIVE locks and exclude all other processes from ** access the file. ** ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ static int flockLock(sqlite3_file *id, int eFileLock) { int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; assert( pFile ); /* if we already have a lock, it is exclusive. ** Just adjust level and punt on outta here. */ if (pFile->eFileLock > NO_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } /* grab an exclusive lock */ if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) { int tErrno = errno; /* didn't get, must be busy */ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(rc) ){ storeLastErrno(pFile, tErrno); } } else { /* got it, set the type and return ok */ pFile->eFileLock = eFileLock; } OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS if( (rc & 0xff) == SQLITE_IOERR ){ rc = SQLITE_BUSY; } #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ return rc; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int flockUnlock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; assert( pFile ); OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock, pFile->eFileLock, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); /* no-op if possible */ if( pFile->eFileLock==eFileLock ){ return SQLITE_OK; } /* shared can just be set because we always have an exclusive */ if (eFileLock==SHARED_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } /* no, really, unlock. */ if( robust_flock(pFile->h, LOCK_UN) ){ #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS return SQLITE_OK; #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ return SQLITE_IOERR_UNLOCK; }else{ pFile->eFileLock = NO_LOCK; return SQLITE_OK; } } /* ** Close a file. */ static int flockClose(sqlite3_file *id) { assert( id!=0 ); flockUnlock(id, NO_LOCK); return closeUnixFile(id); } #endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */ /******************* End of the flock lock implementation ********************* ******************************************************************************/ /****************************************************************************** ************************ Begin Named Semaphore Locking ************************ ** ** Named semaphore locking is only supported on VxWorks. ** ** Semaphore locking is like dot-lock and flock in that it really only ** supports EXCLUSIVE locking. Only a single process can read or write ** the database file at a time. This reduces potential concurrency, but ** makes the lock implementation much easier. */ #if OS_VXWORKS /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) { int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); /* Check if a thread in this process holds such a lock */ if( pFile->eFileLock>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ if( !reserved ){ sem_t *pSem = pFile->pInode->pSem; if( sem_trywait(pSem)==-1 ){ int tErrno = errno; if( EAGAIN != tErrno ){ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK); storeLastErrno(pFile, tErrno); } else { /* someone else has the lock when we are in NO_LOCK */ reserved = (pFile->eFileLock < SHARED_LOCK); } }else{ /* we could have it if we want it */ sem_post(pSem); } } OSTRACE(("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK ** (3) PENDING_LOCK ** (4) EXCLUSIVE_LOCK ** ** Sometimes when requesting one lock state, additional lock states ** are inserted in between. The locking might fail on one of the later ** transitions leaving the lock state different from what it started but ** still short of its goal. The following chart shows the allowed ** transitions and the inserted intermediate states: ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED ** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** ** Semaphore locks only really support EXCLUSIVE locks. We track intermediate ** lock states in the sqlite3_file structure, but all locks SHARED or ** above are really EXCLUSIVE locks and exclude all other processes from ** access the file. ** ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ static int semXLock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; sem_t *pSem = pFile->pInode->pSem; int rc = SQLITE_OK; /* if we already have a lock, it is exclusive. ** Just adjust level and punt on outta here. */ if (pFile->eFileLock > NO_LOCK) { pFile->eFileLock = eFileLock; rc = SQLITE_OK; goto sem_end_lock; } /* lock semaphore now but bail out when already locked. */ if( sem_trywait(pSem)==-1 ){ rc = SQLITE_BUSY; goto sem_end_lock; } /* got it, set the type and return ok */ pFile->eFileLock = eFileLock; sem_end_lock: return rc; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int semXUnlock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; sem_t *pSem = pFile->pInode->pSem; assert( pFile ); assert( pSem ); OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock, pFile->eFileLock, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); /* no-op if possible */ if( pFile->eFileLock==eFileLock ){ return SQLITE_OK; } /* shared can just be set because we always have an exclusive */ if (eFileLock==SHARED_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } /* no, really unlock. */ if ( sem_post(pSem)==-1 ) { int rc, tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(rc) ){ storeLastErrno(pFile, tErrno); } return rc; } pFile->eFileLock = NO_LOCK; return SQLITE_OK; } /* ** Close a file. */ static int semXClose(sqlite3_file *id) { if( id ){ unixFile *pFile = (unixFile*)id; semXUnlock(id, NO_LOCK); assert( pFile ); assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); releaseInodeInfo(pFile); unixLeaveMutex(); closeUnixFile(id); } return SQLITE_OK; } #endif /* OS_VXWORKS */ /* ** Named semaphore locking is only available on VxWorks. ** *************** End of the named semaphore lock implementation **************** ******************************************************************************/ /****************************************************************************** *************************** Begin AFP Locking ********************************* ** ** AFP is the Apple Filing Protocol. AFP is a network filesystem found ** on Apple Macintosh computers - both OS9 and OSX. ** ** Third-party implementations of AFP are available. But this code here ** only works on OSX. */ #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE /* ** The afpLockingContext structure contains all afp lock specific state */ typedef struct afpLockingContext afpLockingContext; struct afpLockingContext { int reserved; const char *dbPath; /* Name of the open file */ }; struct ByteRangeLockPB2 { unsigned long long offset; /* offset to first byte to lock */ unsigned long long length; /* nbr of bytes to lock */ unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */ unsigned char unLockFlag; /* 1 = unlock, 0 = lock */ unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */ int fd; /* file desc to assoc this lock with */ }; #define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2) /* ** This is a utility for setting or clearing a bit-range lock on an ** AFP filesystem. ** ** Return SQLITE_OK on success, SQLITE_BUSY on failure. */ static int afpSetLock( const char *path, /* Name of the file to be locked or unlocked */ unixFile *pFile, /* Open file descriptor on path */ unsigned long long offset, /* First byte to be locked */ unsigned long long length, /* Number of bytes to lock */ int setLockFlag /* True to set lock. False to clear lock */ ){ struct ByteRangeLockPB2 pb; int err; pb.unLockFlag = setLockFlag ? 0 : 1; pb.startEndFlag = 0; pb.offset = offset; pb.length = length; pb.fd = pFile->h; OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n", (setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""), offset, length)); err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0); if ( err==-1 ) { int rc; int tErrno = errno; OSTRACE(("AFPSETLOCK failed to fsctl() '%s' %d %s\n", path, tErrno, strerror(tErrno))); #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS rc = SQLITE_BUSY; #else rc = sqliteErrorFromPosixError(tErrno, setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK); #endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */ if( IS_LOCK_ERROR(rc) ){ storeLastErrno(pFile, tErrno); } return rc; } else { return SQLITE_OK; } } /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; afpLockingContext *context; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); context = (afpLockingContext *) pFile->lockingContext; if( context->reserved ){ *pResOut = 1; return SQLITE_OK; } sqlite3_mutex_enter(pFile->pInode->pLockMutex); /* Check if a thread in this process holds such a lock */ if( pFile->pInode->eFileLock>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ if( !reserved ){ /* lock the RESERVED byte */ int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); if( SQLITE_OK==lrc ){ /* if we succeeded in taking the reserved lock, unlock it to restore ** the original state */ lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0); } else { /* if we failed to get the lock then someone else must have it */ reserved = 1; } if( IS_LOCK_ERROR(lrc) ){ rc=lrc; } } sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK ** (3) PENDING_LOCK ** (4) EXCLUSIVE_LOCK ** ** Sometimes when requesting one lock state, additional lock states ** are inserted in between. The locking might fail on one of the later ** transitions leaving the lock state different from what it started but ** still short of its goal. The following chart shows the allowed ** transitions and the inserted intermediate states: ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED ** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ static int afpLock(sqlite3_file *id, int eFileLock){ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode = pFile->pInode; afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; assert( pFile ); OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h, azFileLock(eFileLock), azFileLock(pFile->eFileLock), azFileLock(pInode->eFileLock), pInode->nShared , osGetpid(0))); /* If there is already a lock of this type or more restrictive on the ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as ** unixEnterMutex() hasn't been called yet. */ if( pFile->eFileLock>=eFileLock ){ OSTRACE(("LOCK %d %s ok (already held) (afp)\n", pFile->h, azFileLock(eFileLock))); return SQLITE_OK; } /* Make sure the locking sequence is correct ** (1) We never move from unlocked to anything higher than shared lock. ** (2) SQLite never explicitly requests a pending lock. ** (3) A shared lock is always held when a reserve lock is requested. */ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); assert( eFileLock!=PENDING_LOCK ); assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); /* This mutex is needed because pFile->pInode is shared across threads */ pInode = pFile->pInode; sqlite3_mutex_enter(pInode->pLockMutex); /* If some thread using this PID has a lock via a different unixFile* ** handle that precludes the requested lock, return BUSY. */ if( (pFile->eFileLock!=pInode->eFileLock && (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ){ rc = SQLITE_BUSY; goto afp_end_lock; } /* If a SHARED lock is requested, and some thread using this PID already ** has a SHARED or RESERVED lock, then increment reference counts and ** return SQLITE_OK. */ if( eFileLock==SHARED_LOCK && (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){ assert( eFileLock==SHARED_LOCK ); assert( pFile->eFileLock==0 ); assert( pInode->nShared>0 ); pFile->eFileLock = SHARED_LOCK; pInode->nShared++; pInode->nLock++; goto afp_end_lock; } /* A PENDING lock is needed before acquiring a SHARED lock and before ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will ** be released. */ if( eFileLock==SHARED_LOCK || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLockdbPath, pFile, PENDING_BYTE, 1, 1); if (failed) { rc = failed; goto afp_end_lock; } } /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ if( eFileLock==SHARED_LOCK ){ int lrc1, lrc2, lrc1Errno = 0; long lk, mask; assert( pInode->nShared==0 ); assert( pInode->eFileLock==0 ); mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff; /* Now get the read-lock SHARED_LOCK */ /* note that the quality of the randomness doesn't matter that much */ lk = random(); pInode->sharedByte = (lk & mask)%(SHARED_SIZE - 1); lrc1 = afpSetLock(context->dbPath, pFile, SHARED_FIRST+pInode->sharedByte, 1, 1); if( IS_LOCK_ERROR(lrc1) ){ lrc1Errno = pFile->lastErrno; } /* Drop the temporary PENDING lock */ lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); if( IS_LOCK_ERROR(lrc1) ) { storeLastErrno(pFile, lrc1Errno); rc = lrc1; goto afp_end_lock; } else if( IS_LOCK_ERROR(lrc2) ){ rc = lrc2; goto afp_end_lock; } else if( lrc1 != SQLITE_OK ) { rc = lrc1; } else { pFile->eFileLock = SHARED_LOCK; pInode->nLock++; pInode->nShared = 1; } }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file ** already. */ int failed = 0; assert( 0!=pFile->eFileLock ); if (eFileLock >= RESERVED_LOCK && pFile->eFileLock < RESERVED_LOCK) { /* Acquire a RESERVED lock */ failed = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); if( !failed ){ context->reserved = 1; } } if (!failed && eFileLock == EXCLUSIVE_LOCK) { /* Acquire an EXCLUSIVE lock */ /* Remove the shared lock before trying the range. we'll need to ** reestablish the shared lock if we can't get the afpUnlock */ if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST + pInode->sharedByte, 1, 0)) ){ int failed2 = SQLITE_OK; /* now attempt to get the exclusive lock range */ failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 1); if( failed && (failed2 = afpSetLock(context->dbPath, pFile, SHARED_FIRST + pInode->sharedByte, 1, 1)) ){ /* Can't reestablish the shared lock. Sqlite can't deal, this is ** a critical I/O error */ rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 : SQLITE_IOERR_LOCK; goto afp_end_lock; } }else{ rc = failed; } } if( failed ){ rc = failed; } } if( rc==SQLITE_OK ){ pFile->eFileLock = eFileLock; pInode->eFileLock = eFileLock; }else if( eFileLock==EXCLUSIVE_LOCK ){ pFile->eFileLock = PENDING_LOCK; pInode->eFileLock = PENDING_LOCK; } afp_end_lock: sqlite3_mutex_leave(pInode->pLockMutex); OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); return rc; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int afpUnlock(sqlite3_file *id, int eFileLock) { int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode; afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; int skipShared = 0; assert( pFile ); OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock, pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } pInode = pFile->pInode; sqlite3_mutex_enter(pInode->pLockMutex); assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); #ifdef SQLITE_DEBUG /* When reducing a lock such that other processes can start ** reading the database file again, make sure that the ** transaction counter was updated if any part of the database ** file changed. If the transaction counter is not updated, ** other connections to the same file might not realize that ** the file has changed and hence might not know to flush their ** cache. The use of a stale cache can lead to database corruption. */ assert( pFile->inNormalWrite==0 || pFile->dbUpdate==0 || pFile->transCntrChng==1 ); pFile->inNormalWrite = 0; #endif if( pFile->eFileLock==EXCLUSIVE_LOCK ){ rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0); if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){ /* only re-establish the shared lock if necessary */ int sharedLockByte = SHARED_FIRST+pInode->sharedByte; rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 1); } else { skipShared = 1; } } if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){ rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); } if( rc==SQLITE_OK && pFile->eFileLock>=RESERVED_LOCK && context->reserved ){ rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0); if( !rc ){ context->reserved = 0; } } if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){ pInode->eFileLock = SHARED_LOCK; } } if( rc==SQLITE_OK && eFileLock==NO_LOCK ){ /* Decrement the shared lock counter. Release the lock using an ** OS call only when all threads in this same process have released ** the lock. */ unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte; pInode->nShared--; if( pInode->nShared==0 ){ if( !skipShared ){ rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0); } if( !rc ){ pInode->eFileLock = NO_LOCK; pFile->eFileLock = NO_LOCK; } } if( rc==SQLITE_OK ){ pInode->nLock--; assert( pInode->nLock>=0 ); if( pInode->nLock==0 ) closePendingFds(pFile); } } sqlite3_mutex_leave(pInode->pLockMutex); if( rc==SQLITE_OK ){ pFile->eFileLock = eFileLock; } return rc; } /* ** Close a file & cleanup AFP specific locking context */ static int afpClose(sqlite3_file *id) { int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; assert( id!=0 ); afpUnlock(id, NO_LOCK); assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); if( pFile->pInode ){ unixInodeInfo *pInode = pFile->pInode; sqlite3_mutex_enter(pInode->pLockMutex); if( pInode->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pInode->aPending. It will be automatically closed when ** the last lock is cleared. */ setPendingFd(pFile); } sqlite3_mutex_leave(pInode->pLockMutex); } releaseInodeInfo(pFile); sqlite3_free(pFile->lockingContext); rc = closeUnixFile(id); unixLeaveMutex(); return rc; } #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ /* ** The code above is the AFP lock implementation. The code is specific ** to MacOSX and does not work on other unix platforms. No alternative ** is available. If you don't compile for a mac, then the "unix-afp" ** VFS is not available. ** ********************* End of the AFP lock implementation ********************** ******************************************************************************/ /****************************************************************************** *************************** Begin NFS Locking ********************************/ #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int nfsUnlock(sqlite3_file *id, int eFileLock){ return posixUnlock(id, eFileLock, 1); } #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ /* ** The code above is the NFS lock implementation. The code is specific ** to MacOSX and does not work on other unix platforms. No alternative ** is available. ** ********************* End of the NFS lock implementation ********************** ******************************************************************************/ /****************************************************************************** **************** Non-locking sqlite3_file methods ***************************** ** ** The next division contains implementations for all methods of the ** sqlite3_file object other than the locking methods. The locking ** methods were defined in divisions above (one locking method per ** division). Those methods that are common to all locking modes ** are gather together into this division. */ /* ** Seek to the offset passed as the second argument, then read cnt ** bytes into pBuf. Return the number of bytes actually read. ** ** To avoid stomping the errno value on a failed read the lastErrno value ** is set before returning. */ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ int got; int prior = 0; #if (!defined(USE_PREAD) && !defined(USE_PREAD64)) i64 newOffset; #endif TIMER_START; assert( cnt==(cnt&0x1ffff) ); assert( id->h>2 ); do{ #if defined(USE_PREAD) got = osPread(id->h, pBuf, cnt, offset); SimulateIOError( got = -1 ); #elif defined(USE_PREAD64) got = osPread64(id->h, pBuf, cnt, offset); SimulateIOError( got = -1 ); #else newOffset = lseek(id->h, offset, SEEK_SET); SimulateIOError( newOffset = -1 ); if( newOffset<0 ){ storeLastErrno((unixFile*)id, errno); return -1; } got = osRead(id->h, pBuf, cnt); #endif if( got==cnt ) break; if( got<0 ){ if( errno==EINTR ){ got = 1; continue; } prior = 0; storeLastErrno((unixFile*)id, errno); break; }else if( got>0 ){ cnt -= got; offset += got; prior += got; pBuf = (void*)(got + (char*)pBuf); } }while( got>0 ); TIMER_END; OSTRACE(("READ %-3d %5d %7lld %llu\n", id->h, got+prior, offset-prior, TIMER_ELAPSED)); return got+prior; } /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ static int unixRead( sqlite3_file *id, void *pBuf, int amt, sqlite3_int64 offset ){ unixFile *pFile = (unixFile *)id; int got; assert( id ); assert( offset>=0 ); assert( amt>0 ); /* If this is a database file (not a journal, super-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif #if SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this read request as possible by transferring ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt); return SQLITE_OK; }else{ int nCopy = pFile->mmapSize - offset; memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy); pBuf = &((u8 *)pBuf)[nCopy]; amt -= nCopy; offset += nCopy; } } #endif got = seekAndRead(pFile, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ /* pFile->lastErrno has been set by seekAndRead(). ** Usually we return SQLITE_IOERR_READ here, though for some ** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The ** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT ** prior to returning to the application by the sqlite3ApiExit() ** routine. */ switch( pFile->lastErrno ){ case ERANGE: case EIO: #ifdef ENXIO case ENXIO: #endif #ifdef EDEVERR case EDEVERR: #endif return SQLITE_IOERR_CORRUPTFS; } return SQLITE_IOERR_READ; }else{ storeLastErrno(pFile, 0); /* not a system error */ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[got], 0, amt-got); return SQLITE_IOERR_SHORT_READ; } } /* ** Attempt to seek the file-descriptor passed as the first argument to ** absolute offset iOff, then attempt to write nBuf bytes of data from ** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise, ** return the actual number of bytes written (which may be less than ** nBuf). */ static int seekAndWriteFd( int fd, /* File descriptor to write to */ i64 iOff, /* File offset to begin writing at */ const void *pBuf, /* Copy data from this buffer to the file */ int nBuf, /* Size of buffer pBuf in bytes */ int *piErrno /* OUT: Error number if error occurs */ ){ int rc = 0; /* Value returned by system call */ assert( nBuf==(nBuf&0x1ffff) ); assert( fd>2 ); assert( piErrno!=0 ); nBuf &= 0x1ffff; TIMER_START; #if defined(USE_PREAD) do{ rc = (int)osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR ); #elif defined(USE_PREAD64) do{ rc = (int)osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR); #else do{ i64 iSeek = lseek(fd, iOff, SEEK_SET); SimulateIOError( iSeek = -1 ); if( iSeek<0 ){ rc = -1; break; } rc = osWrite(fd, pBuf, nBuf); }while( rc<0 && errno==EINTR ); #endif TIMER_END; OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED)); if( rc<0 ) *piErrno = errno; return rc; } /* ** Seek to the offset in id->offset then read cnt bytes into pBuf. ** Return the number of bytes actually read. Update the offset. ** ** To avoid stomping the errno value on a failed write the lastErrno value ** is set before returning. */ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno); } /* ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ static int unixWrite( sqlite3_file *id, const void *pBuf, int amt, sqlite3_int64 offset ){ unixFile *pFile = (unixFile*)id; int wrote = 0; assert( id ); assert( amt>0 ); /* If this is a database file (not a journal, super-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif #ifdef SQLITE_DEBUG /* If we are doing a normal write to a database file (as opposed to ** doing a hot-journal rollback or a write to some file other than a ** normal database file) then record the fact that the database ** has changed. If the transaction counter is modified, record that ** fact too. */ if( pFile->inNormalWrite ){ pFile->dbUpdate = 1; /* The database has been modified */ if( offset<=24 && offset+amt>=27 ){ int rc; char oldCntr[4]; SimulateIOErrorBenign(1); rc = seekAndRead(pFile, 24, oldCntr, 4); SimulateIOErrorBenign(0); if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){ pFile->transCntrChng = 1; /* The transaction counter has changed */ } } } #endif #if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this write request as possible by transferring ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt); return SQLITE_OK; }else{ int nCopy = pFile->mmapSize - offset; memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy); pBuf = &((u8 *)pBuf)[nCopy]; amt -= nCopy; offset += nCopy; } } #endif while( (wrote = seekAndWrite(pFile, offset, pBuf, amt))0 ){ amt -= wrote; offset += wrote; pBuf = &((char*)pBuf)[wrote]; } SimulateIOError(( wrote=(-1), amt=1 )); SimulateDiskfullError(( wrote=0, amt=1 )); if( amt>wrote ){ if( wrote<0 && pFile->lastErrno!=ENOSPC ){ /* lastErrno set by seekAndWrite */ return SQLITE_IOERR_WRITE; }else{ storeLastErrno(pFile, 0); /* not a system error */ return SQLITE_FULL; } } return SQLITE_OK; } #ifdef SQLITE_TEST /* ** Count the number of fullsyncs and normal syncs. This is used to test ** that syncs and fullsyncs are occurring at the right times. */ SQLITE_API int sqlite3_sync_count = 0; SQLITE_API int sqlite3_fullsync_count = 0; #endif /* ** We do not trust systems to provide a working fdatasync(). Some do. ** Others do no. To be safe, we will stick with the (slightly slower) ** fsync(). If you know that your system does support fdatasync() correctly, ** then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC */ #if !defined(fdatasync) && !HAVE_FDATASYNC # define fdatasync fsync #endif /* ** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not ** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently ** only available on Mac OS X. But that could change. */ #ifdef F_FULLFSYNC # define HAVE_FULLFSYNC 1 #else # define HAVE_FULLFSYNC 0 #endif /* ** The fsync() system call does not work as advertised on many ** unix systems. The following procedure is an attempt to make ** it work better. ** ** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful ** for testing when we want to run through the test suite quickly. ** You are strongly advised *not* to deploy with SQLITE_NO_SYNC ** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash ** or power failure will likely corrupt the database file. ** ** SQLite sets the dataOnly flag if the size of the file is unchanged. ** The idea behind dataOnly is that it should only write the file content ** to disk, not the inode. We only set dataOnly if the file size is ** unchanged since the file size is part of the inode. However, ** Ted Ts'o tells us that fdatasync() will also write the inode if the ** file size has changed. The only real difference between fdatasync() ** and fsync(), Ted tells us, is that fdatasync() will not flush the ** inode if the mtime or owner or other inode attributes have changed. ** We only care about the file size, not the other file attributes, so ** as far as SQLite is concerned, an fdatasync() is always adequate. ** So, we always use fdatasync() if it is available, regardless of ** the value of the dataOnly flag. */ static int full_fsync(int fd, int fullSync, int dataOnly){ int rc; /* The following "ifdef/elif/else/" block has the same structure as ** the one below. It is replicated here solely to avoid cluttering ** up the real code with the UNUSED_PARAMETER() macros. */ #ifdef SQLITE_NO_SYNC UNUSED_PARAMETER(fd); UNUSED_PARAMETER(fullSync); UNUSED_PARAMETER(dataOnly); #elif HAVE_FULLFSYNC UNUSED_PARAMETER(dataOnly); #else UNUSED_PARAMETER(fullSync); UNUSED_PARAMETER(dataOnly); #endif /* Record the number of times that we do a normal fsync() and ** FULLSYNC. This is used during testing to verify that this procedure ** gets called with the correct arguments. */ #ifdef SQLITE_TEST if( fullSync ) sqlite3_fullsync_count++; sqlite3_sync_count++; #endif /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a ** no-op. But go ahead and call fstat() to validate the file ** descriptor as we need a method to provoke a failure during ** coverage testing. */ #ifdef SQLITE_NO_SYNC { struct stat buf; rc = osFstat(fd, &buf); } #elif HAVE_FULLFSYNC if( fullSync ){ rc = osFcntl(fd, F_FULLFSYNC, 0); }else{ rc = 1; } /* If the FULLFSYNC failed, fall back to attempting an fsync(). ** It shouldn't be possible for fullfsync to fail on the local ** file system (on OSX), so failure indicates that FULLFSYNC ** isn't supported for this file system. So, attempt an fsync ** and (for now) ignore the overhead of a superfluous fcntl call. ** It'd be better to detect fullfsync support once and avoid ** the fcntl call every time sync is called. */ if( rc ) rc = fsync(fd); #elif defined(__APPLE__) /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly ** so currently we default to the macro that redefines fdatasync to fsync */ rc = fsync(fd); #else rc = fdatasync(fd); #if OS_VXWORKS if( rc==-1 && errno==ENOTSUP ){ rc = fsync(fd); } #endif /* OS_VXWORKS */ #endif /* ifdef SQLITE_NO_SYNC elif HAVE_FULLFSYNC */ if( OS_VXWORKS && rc!= -1 ){ rc = 0; } return rc; } /* ** Open a file descriptor to the directory containing file zFilename. ** If successful, *pFd is set to the opened file descriptor and ** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM ** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined ** value. ** ** The directory file descriptor is used for only one thing - to ** fsync() a directory to make sure file creation and deletion events ** are flushed to disk. Such fsyncs are not needed on newer ** journaling filesystems, but are required on older filesystems. ** ** This routine can be overridden using the xSetSysCall interface. ** The ability to override this routine was added in support of the ** chromium sandbox. Opening a directory is a security risk (we are ** told) so making it overrideable allows the chromium sandbox to ** replace this routine with a harmless no-op. To make this routine ** a no-op, replace it with a stub that returns SQLITE_OK but leaves ** *pFd set to a negative number. ** ** If SQLITE_OK is returned, the caller is responsible for closing ** the file descriptor *pFd using close(). */ static int openDirectory(const char *zFilename, int *pFd){ int ii; int fd = -1; char zDirname[MAX_PATHNAME+1]; sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); for(ii=(int)strlen(zDirname); ii>0 && zDirname[ii]!='/'; ii--); if( ii>0 ){ zDirname[ii] = '\0'; }else{ if( zDirname[0]!='/' ) zDirname[0] = '.'; zDirname[1] = 0; } fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); if( fd>=0 ){ OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); } *pFd = fd; if( fd>=0 ) return SQLITE_OK; return unixLogError(SQLITE_CANTOPEN_BKPT, "openDirectory", zDirname); } /* ** Make sure all writes to a particular file are committed to disk. ** ** If dataOnly==0 then both the file itself and its metadata (file ** size, access time, etc) are synced. If dataOnly!=0 then only the ** file data is synced. ** ** Under Unix, also make sure that the directory entry for the file ** has been created by fsync-ing the directory that contains the file. ** If we do not do this and we encounter a power failure, the directory ** entry for the journal might not exist after we reboot. The next ** SQLite to access the file will not know that the journal exists (because ** the directory entry for the journal was never created) and the transaction ** will not roll back - possibly leading to database corruption. */ static int unixSync(sqlite3_file *id, int flags){ int rc; unixFile *pFile = (unixFile*)id; int isDataOnly = (flags&SQLITE_SYNC_DATAONLY); int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL; /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ assert((flags&0x0F)==SQLITE_SYNC_NORMAL || (flags&0x0F)==SQLITE_SYNC_FULL ); /* Unix cannot, but some systems may return SQLITE_FULL from here. This ** line is to test that doing so does not cause any problems. */ SimulateDiskfullError( return SQLITE_FULL ); assert( pFile ); OSTRACE(("SYNC %-3d\n", pFile->h)); rc = full_fsync(pFile->h, isFullsync, isDataOnly); SimulateIOError( rc=1 ); if( rc ){ storeLastErrno(pFile, errno); return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath); } /* Also fsync the directory containing the file if the DIRSYNC flag ** is set. This is a one-time occurrence. Many systems (examples: AIX) ** are unable to fsync a directory, so ignore errors on the fsync. */ if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){ int dirfd; OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath, HAVE_FULLFSYNC, isFullsync)); rc = osOpenDirectory(pFile->zPath, &dirfd); if( rc==SQLITE_OK ){ full_fsync(dirfd, 0, 0); robust_close(pFile, dirfd, __LINE__); }else{ assert( rc==SQLITE_CANTOPEN ); rc = SQLITE_OK; } pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC; } return rc; } /* ** Truncate an open file to a specified size */ static int unixTruncate(sqlite3_file *id, i64 nByte){ unixFile *pFile = (unixFile *)id; int rc; assert( pFile ); SimulateIOError( return SQLITE_IOERR_TRUNCATE ); /* If the user has configured a chunk-size for this file, truncate the ** file so that it consists of an integer number of chunks (i.e. the ** actual file size after the operation may be larger than the requested ** size). */ if( pFile->szChunk>0 ){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } rc = robust_ftruncate(pFile->h, nByte); if( rc ){ storeLastErrno(pFile, errno); return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); }else{ #ifdef SQLITE_DEBUG /* If we are doing a normal write to a database file (as opposed to ** doing a hot-journal rollback or a write to some file other than a ** normal database file) and we truncate the file to zero length, ** that effectively updates the change counter. This might happen ** when restoring a database using the backup API from a zero-length ** source. */ if( pFile->inNormalWrite && nByte==0 ){ pFile->transCntrChng = 1; } #endif #if SQLITE_MAX_MMAP_SIZE>0 /* If the file was just truncated to a size smaller than the currently ** mapped region, reduce the effective mapping size as well. SQLite will ** use read() and write() to access data beyond this point from now on. */ if( nBytemmapSize ){ pFile->mmapSize = nByte; } #endif return SQLITE_OK; } } /* ** Determine the current size of a file in bytes */ static int unixFileSize(sqlite3_file *id, i64 *pSize){ int rc; struct stat buf; assert( id ); rc = osFstat(((unixFile*)id)->h, &buf); SimulateIOError( rc=1 ); if( rc!=0 ){ storeLastErrno((unixFile*)id, errno); return SQLITE_IOERR_FSTAT; } *pSize = buf.st_size; /* When opening a zero-size database, the findInodeInfo() procedure ** writes a single byte into that file in order to work around a bug ** in the OS-X msdos filesystem. In order to avoid problems with upper ** layers, we need to report this file size as zero even though it is ** really 1. Ticket #3260. */ if( *pSize==1 ) *pSize = 0; return SQLITE_OK; } #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) /* ** Handler for proxy-locking file-control verbs. Defined below in the ** proxying locking division. */ static int proxyFileControl(sqlite3_file*,int,void*); #endif /* ** This function is called to handle the SQLITE_FCNTL_SIZE_HINT ** file-control operation. Enlarge the database to nBytes in size ** (rounded up to the next chunk-size). If the database is already ** nBytes or larger, this routine is a no-op. */ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ if( pFile->szChunk>0 ){ i64 nSize; /* Required file size */ struct stat buf; /* Used to hold return values of fstat() */ if( osFstat(pFile->h, &buf) ){ return SQLITE_IOERR_FSTAT; } nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk; if( nSize>(i64)buf.st_size ){ #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE /* The code below is handling the return value of osFallocate() ** correctly. posix_fallocate() is defined to "returns zero on success, ** or an error number on failure". See the manpage for details. */ int err; do{ err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); }while( err==EINTR ); if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE; #else /* If the OS does not have posix_fallocate(), fake it. Write a ** single byte to the last byte in each block that falls entirely ** within the extended region. Then, if required, a single byte ** at offset (nSize-1), to set the size of the file correctly. ** This is a similar technique to that used by glibc on systems ** that do not have a real fallocate() call. */ int nBlk = buf.st_blksize; /* File-system block size */ int nWrite = 0; /* Number of bytes written by seekAndWrite */ i64 iWrite; /* Next offset to write to */ iWrite = (buf.st_size/nBlk)*nBlk + nBlk - 1; assert( iWrite>=buf.st_size ); assert( ((iWrite+1)%nBlk)==0 ); for(/*no-op*/; iWrite=nSize ) iWrite = nSize - 1; nWrite = seekAndWrite(pFile, iWrite, "", 1); if( nWrite!=1 ) return SQLITE_IOERR_WRITE; } #endif } } #if SQLITE_MAX_MMAP_SIZE>0 if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){ int rc; if( pFile->szChunk<=0 ){ if( robust_ftruncate(pFile->h, nByte) ){ storeLastErrno(pFile, errno); return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); } } rc = unixMapfile(pFile, nByte); return rc; } #endif return SQLITE_OK; } /* ** If *pArg is initially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ** ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. */ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){ if( *pArg<0 ){ *pArg = (pFile->ctrlFlags & mask)!=0; }else if( (*pArg)==0 ){ pFile->ctrlFlags &= ~mask; }else{ pFile->ctrlFlags |= mask; } } /* Forward declaration */ static int unixGetTempname(int nBuf, char *zBuf); #ifndef SQLITE_OMIT_WAL static int unixFcntlExternalReader(unixFile*, int*); #endif /* ** Information and control of an open file handle. */ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ unixFile *pFile = (unixFile*)id; switch( op ){ #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE); return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK; } case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE); return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK; } case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE); return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK; } #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->eFileLock; return SQLITE_OK; } case SQLITE_FCNTL_LAST_ERRNO: { *(int*)pArg = pFile->lastErrno; return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { pFile->szChunk = *(int *)pArg; return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { int rc; SimulateIOErrorBenign(1); rc = fcntlSizeHint(pFile, *(i64 *)pArg); SimulateIOErrorBenign(0); return rc; } case SQLITE_FCNTL_PERSIST_WAL: { unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg); return SQLITE_OK; } case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { unixModeBit(pFile, UNIXFILE_PSOW, (int*)pArg); return SQLITE_OK; } case SQLITE_FCNTL_VFSNAME: { *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName); return SQLITE_OK; } case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = sqlite3_malloc64( pFile->pVfs->mxPathname ); if( zTFile ){ unixGetTempname(pFile->pVfs->mxPathname, zTFile); *(char**)pArg = zTFile; } return SQLITE_OK; } case SQLITE_FCNTL_HAS_MOVED: { *(int*)pArg = fileHasMoved(pFile); return SQLITE_OK; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT case SQLITE_FCNTL_LOCK_TIMEOUT: { int iOld = pFile->iBusyTimeout; #if SQLITE_ENABLE_SETLK_TIMEOUT==1 pFile->iBusyTimeout = *(int*)pArg; #elif SQLITE_ENABLE_SETLK_TIMEOUT==2 pFile->iBusyTimeout = !!(*(int*)pArg); #else # error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2" #endif *(int*)pArg = iOld; return SQLITE_OK; } #endif #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; int rc = SQLITE_OK; if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } /* The value of newLimit may be eventually cast to (size_t) and passed ** to mmap(). Restrict its value to 2GB if (size_t) is not at least a ** 64-bit type. */ if( newLimit>0 && sizeof(size_t)<8 ){ newLimit = (newLimit & 0x7FFFFFFF); } *(i64*)pArg = pFile->mmapSizeMax; if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ pFile->mmapSizeMax = newLimit; if( pFile->mmapSize>0 ){ unixUnmapfile(pFile); rc = unixMapfile(pFile, -1); } } return rc; } #endif #ifdef SQLITE_DEBUG /* The pager calls this method to signal that it has done ** a rollback and that the database is therefore unchanged and ** it hence it is OK for the transaction change counter to be ** unchanged. */ case SQLITE_FCNTL_DB_UNCHANGED: { ((unixFile*)id)->dbUpdate = 0; return SQLITE_OK; } #endif #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) case SQLITE_FCNTL_SET_LOCKPROXYFILE: case SQLITE_FCNTL_GET_LOCKPROXYFILE: { return proxyFileControl(id,op,pArg); } #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ case SQLITE_FCNTL_EXTERNAL_READER: { #ifndef SQLITE_OMIT_WAL return unixFcntlExternalReader((unixFile*)id, (int*)pArg); #else *(int*)pArg = 0; return SQLITE_OK; #endif } } return SQLITE_NOTFOUND; } /* ** If pFd->sectorSize is non-zero when this function is called, it is a ** no-op. Otherwise, the values of pFd->sectorSize and ** pFd->deviceCharacteristics are set according to the file-system ** characteristics. ** ** There are two versions of this function. One for QNX and one for all ** other systems. */ #ifndef __QNXNTO__ static void setDeviceCharacteristics(unixFile *pFd){ assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 ); if( pFd->sectorSize==0 ){ #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) int res; u32 f = 0; /* Check for support for F2FS atomic batch writes. */ res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f); if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){ pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC; } #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ /* Set the POWERSAFE_OVERWRITE flag if requested. */ if( pFd->ctrlFlags & UNIXFILE_PSOW ){ pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; } pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; } } #else #include #include static void setDeviceCharacteristics(unixFile *pFile){ if( pFile->sectorSize == 0 ){ struct statvfs fsInfo; /* Set defaults for non-supported filesystems */ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; pFile->deviceCharacteristics = 0; if( fstatvfs(pFile->h, &fsInfo) == -1 ) { return; } if( !strcmp(fsInfo.f_basetype, "tmp") ) { pFile->sectorSize = fsInfo.f_bsize; pFile->deviceCharacteristics = SQLITE_IOCAP_ATOMIC4K | /* All ram filesystem writes are atomic */ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until ** the write succeeds */ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind ** so it is ordered */ 0; }else if( strstr(fsInfo.f_basetype, "etfs") ){ pFile->sectorSize = fsInfo.f_bsize; pFile->deviceCharacteristics = /* etfs cluster size writes are atomic */ (pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) | SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until ** the write succeeds */ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind ** so it is ordered */ 0; }else if( !strcmp(fsInfo.f_basetype, "qnx6") ){ pFile->sectorSize = fsInfo.f_bsize; pFile->deviceCharacteristics = SQLITE_IOCAP_ATOMIC | /* All filesystem writes are atomic */ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until ** the write succeeds */ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind ** so it is ordered */ 0; }else if( !strcmp(fsInfo.f_basetype, "qnx4") ){ pFile->sectorSize = fsInfo.f_bsize; pFile->deviceCharacteristics = /* full bitset of atomics from max sector size and smaller */ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind ** so it is ordered */ 0; }else if( strstr(fsInfo.f_basetype, "dos") ){ pFile->sectorSize = fsInfo.f_bsize; pFile->deviceCharacteristics = /* full bitset of atomics from max sector size and smaller */ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind ** so it is ordered */ 0; }else{ pFile->deviceCharacteristics = SQLITE_IOCAP_ATOMIC512 | /* blocks are atomic */ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until ** the write succeeds */ 0; } } /* Last chance verification. If the sector size isn't a multiple of 512 ** then it isn't valid.*/ if( pFile->sectorSize % 512 != 0 ){ pFile->deviceCharacteristics = 0; pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; } } #endif /* ** Return the sector size in bytes of the underlying block device for ** the specified file. This is almost always 512 bytes, but may be ** larger for some devices. ** ** SQLite code assumes this function cannot fail. It also assumes that ** if two files are created in the same file-system directory (i.e. ** a database and its journal file) that the sector size will be the ** same for both. */ static int unixSectorSize(sqlite3_file *id){ unixFile *pFd = (unixFile*)id; setDeviceCharacteristics(pFd); return pFd->sectorSize; } /* ** Return the device characteristics for the file. ** ** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default. ** However, that choice is controversial since technically the underlying ** file system does not always provide powersafe overwrites. (In other ** words, after a power-loss event, parts of the file that were never ** written might end up being altered.) However, non-PSOW behavior is very, ** very rare. And asserting PSOW makes a large reduction in the amount ** of required I/O for journaling, since a lot of padding is eliminated. ** Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control ** available to turn it off and URI query parameter available to turn it off. */ static int unixDeviceCharacteristics(sqlite3_file *id){ unixFile *pFd = (unixFile*)id; setDeviceCharacteristics(pFd); return pFd->deviceCharacteristics; } #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 /* ** Return the system page size. ** ** This function should not be called directly by other code in this file. ** Instead, it should be called via macro osGetpagesize(). */ static int unixGetpagesize(void){ #if OS_VXWORKS return 1024; #elif defined(_BSD_SOURCE) return getpagesize(); #else return (int)sysconf(_SC_PAGESIZE); #endif } #endif /* !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 */ #ifndef SQLITE_OMIT_WAL /* ** Object used to represent an shared memory buffer. ** ** When multiple threads all reference the same wal-index, each thread ** has its own unixShm object, but they all point to a single instance ** of this unixShmNode object. In other words, each wal-index is opened ** only once per process. ** ** Each unixShmNode object is connected to a single unixInodeInfo object. ** We could coalesce this object into unixInodeInfo, but that would mean ** every open file that does not use shared memory (in other words, most ** open files) would have to carry around this extra information. So ** the unixInodeInfo object contains a pointer to this unixShmNode object ** and the unixShmNode object is created only when needed. ** ** unixMutexHeld() must be true when creating or destroying ** this object or while reading or writing the following fields: ** ** nRef ** ** The following fields are read-only after the object is created: ** ** hShm ** zFilename ** ** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and ** unixMutexHeld() is true when reading or writing any other field ** in this structure. ** ** aLock[SQLITE_SHM_NLOCK]: ** This array records the various locks held by clients on each of the ** SQLITE_SHM_NLOCK slots. If the aLock[] entry is set to 0, then no ** locks are held by the process on this slot. If it is set to -1, then ** some client holds an EXCLUSIVE lock on the locking slot. If the aLock[] ** value is set to a positive value, then it is the number of shared ** locks currently held on the slot. ** ** aMutex[SQLITE_SHM_NLOCK]: ** Normally, when SQLITE_ENABLE_SETLK_TIMEOUT is not defined, mutex ** pShmMutex is used to protect the aLock[] array and the right to ** call fcntl() on unixShmNode.hShm to obtain or release locks. ** ** If SQLITE_ENABLE_SETLK_TIMEOUT is defined though, we use an array ** of mutexes - one for each locking slot. To read or write locking ** slot aLock[iSlot], the caller must hold the corresponding mutex ** aMutex[iSlot]. Similarly, to call fcntl() to obtain or release a ** lock corresponding to slot iSlot, mutex aMutex[iSlot] must be held. */ struct unixShmNode { unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */ sqlite3_mutex *pShmMutex; /* Mutex to access this object */ char *zFilename; /* Name of the mmapped file */ int hShm; /* Open file descriptor */ int szRegion; /* Size of shared-memory regions */ u16 nRegion; /* Size of array apRegion */ u8 isReadonly; /* True if read-only */ u8 isUnlocked; /* True if no DMS lock held */ char **apRegion; /* Array of mapped shared-memory regions */ int nRef; /* Number of unixShm objects pointing to this */ unixShm *pFirst; /* All unixShm objects pointing to this */ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK]; #endif int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ #ifdef SQLITE_DEBUG u8 nextShmId; /* Next available unixShm.id value */ #endif }; /* ** Structure used internally by this VFS to record the state of an ** open shared memory connection. ** ** The following fields are initialized when this object is created and ** are read-only thereafter: ** ** unixShm.pShmNode ** unixShm.id ** ** All other fields are read/write. The unixShm.pShmNode->pShmMutex must ** be held while accessing any read/write fields. */ struct unixShm { unixShmNode *pShmNode; /* The underlying unixShmNode object */ unixShm *pNext; /* Next unixShm with the same unixShmNode */ u8 hasMutex; /* True if holding the unixShmNode->pShmMutex */ u8 id; /* Id of this connection within its unixShmNode */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ }; /* ** Constants used for locking */ #define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ /* ** Use F_GETLK to check whether or not there are any readers with open ** wal-mode transactions in other processes on database file pFile. If ** no error occurs, return SQLITE_OK and set (*piOut) to 1 if there are ** such transactions, or 0 otherwise. If an error occurs, return an ** SQLite error code. The final value of *piOut is undefined in this ** case. */ static int unixFcntlExternalReader(unixFile *pFile, int *piOut){ int rc = SQLITE_OK; *piOut = 0; if( pFile->pShm){ unixShmNode *pShmNode = pFile->pShm->pShmNode; struct flock f; memset(&f, 0, sizeof(f)); f.l_type = F_WRLCK; f.l_whence = SEEK_SET; f.l_start = UNIX_SHM_BASE + 3; f.l_len = SQLITE_SHM_NLOCK - 3; sqlite3_mutex_enter(pShmNode->pShmMutex); if( osFcntl(pShmNode->hShm, F_GETLK, &f)<0 ){ rc = SQLITE_IOERR_LOCK; }else{ *piOut = (f.l_type!=F_UNLCK); } sqlite3_mutex_leave(pShmNode->pShmMutex); } return rc; } /* ** Apply posix advisory locks for all bytes from ofst through ofst+n-1. ** ** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking ** otherwise. */ static int unixShmSystemLock( unixFile *pFile, /* Open connection to the WAL file */ int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */ int ofst, /* First byte of the locking range */ int n /* Number of bytes to lock */ ){ unixShmNode *pShmNode; /* Apply locks to this open shared-memory segment */ struct flock f; /* The posix advisory locking structure */ int rc = SQLITE_OK; /* Result code form fcntl() */ pShmNode = pFile->pInode->pShmNode; /* Assert that the parameters are within expected range and that the ** correct mutex or mutexes are held. */ assert( pShmNode->nRef>=0 ); assert( (ofst==UNIX_SHM_DMS && n==1) || (ofst>=UNIX_SHM_BASE && ofst+n<=(UNIX_SHM_BASE+SQLITE_SHM_NLOCK)) ); if( ofst==UNIX_SHM_DMS ){ assert( pShmNode->nRef>0 || unixMutexHeld() ); assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); }else{ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT int ii; for(ii=ofst-UNIX_SHM_BASE; iiaMutex[ii]) ); } #else assert( sqlite3_mutex_held(pShmNode->pShmMutex) ); assert( pShmNode->nRef>0 ); #endif } /* Shared locks never span more than one byte */ assert( n==1 || lockType!=F_RDLCK ); /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) ); if( pShmNode->hShm>=0 ){ int res; /* Initialize the locking parameters */ f.l_type = lockType; f.l_whence = SEEK_SET; f.l_start = ofst; f.l_len = n; res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile); if( res==-1 ){ #if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && SQLITE_ENABLE_SETLK_TIMEOUT==1 rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY); #else rc = SQLITE_BUSY; #endif } } /* Do debug tracing */ #ifdef SQLITE_DEBUG OSTRACE(("SHM-LOCK ")); if( rc==SQLITE_OK ){ if( lockType==F_UNLCK ){ OSTRACE(("unlock %d..%d ok\n", ofst, ofst+n-1)); }else if( lockType==F_RDLCK ){ OSTRACE(("read-lock %d..%d ok\n", ofst, ofst+n-1)); }else{ assert( lockType==F_WRLCK ); OSTRACE(("write-lock %d..%d ok\n", ofst, ofst+n-1)); } }else{ if( lockType==F_UNLCK ){ OSTRACE(("unlock %d..%d failed\n", ofst, ofst+n-1)); }else if( lockType==F_RDLCK ){ OSTRACE(("read-lock %d..%d failed\n", ofst, ofst+n-1)); }else{ assert( lockType==F_WRLCK ); OSTRACE(("write-lock %d..%d failed\n", ofst, ofst+n-1)); } } #endif return rc; } /* ** Return the minimum number of 32KB shm regions that should be mapped at ** a time, assuming that each mapping must be an integer multiple of the ** current system page-size. ** ** Usually, this is 1. The exception seems to be systems that are configured ** to use 64KB pages - in this case each mapping must cover at least two ** shm regions. */ static int unixShmRegionPerMap(void){ int shmsz = 32*1024; /* SHM region size */ int pgsz = osGetpagesize(); /* System page size */ assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */ if( pgszpInode->pShmNode; assert( unixMutexHeld() ); if( p && ALWAYS(p->nRef==0) ){ int nShmPerMap = unixShmRegionPerMap(); int i; assert( p->pInode==pFd->pInode ); sqlite3_mutex_free(p->pShmMutex); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT for(i=0; iaMutex[i]); } #endif for(i=0; inRegion; i+=nShmPerMap){ if( p->hShm>=0 ){ osMunmap(p->apRegion[i], p->szRegion); }else{ sqlite3_free(p->apRegion[i]); } } sqlite3_free(p->apRegion); if( p->hShm>=0 ){ robust_close(pFd, p->hShm, __LINE__); p->hShm = -1; } p->pInode->pShmNode = 0; sqlite3_free(p); } } /* ** The DMS lock has not yet been taken on shm file pShmNode. Attempt to ** take it now. Return SQLITE_OK if successful, or an SQLite error ** code otherwise. ** ** If the DMS cannot be locked because this is a readonly_shm=1 ** connection and no other process already holds a lock, return ** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1. */ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ struct flock lock; int rc = SQLITE_OK; /* Use F_GETLK to determine the locks other processes are holding ** on the DMS byte. If it indicates that another process is holding ** a SHARED lock, then this process may also take a SHARED lock ** and proceed with opening the *-shm file. ** ** Or, if no other process is holding any lock, then this process ** is the first to open it. In this case take an EXCLUSIVE lock on the ** DMS byte and truncate the *-shm file to zero bytes in size. Then ** downgrade to a SHARED lock on the DMS byte. ** ** If another process is holding an EXCLUSIVE lock on the DMS byte, ** return SQLITE_BUSY to the caller (it will try again). An earlier ** version of this code attempted the SHARED lock at this point. But ** this introduced a subtle race condition: if the process holding ** EXCLUSIVE failed just before truncating the *-shm file, then this ** process might open and use the *-shm file without truncating it. ** And if the *-shm file has been corrupted by a power failure or ** system crash, the database itself may also become corrupt. */ lock.l_whence = SEEK_SET; lock.l_start = UNIX_SHM_DMS; lock.l_len = 1; lock.l_type = F_WRLCK; if( osFcntl(pShmNode->hShm, F_GETLK, &lock)!=0 ) { rc = SQLITE_IOERR_LOCK; }else if( lock.l_type==F_UNLCK ){ if( pShmNode->isReadonly ){ pShmNode->isUnlocked = 1; rc = SQLITE_READONLY_CANTINIT; }else{ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* Do not use a blocking lock here. If the lock cannot be obtained ** immediately, it means some other connection is truncating the ** *-shm file. And after it has done so, it will not release its ** lock, but only downgrade it to a shared lock. So no point in ** blocking here. The call below to obtain the shared DMS lock may ** use a blocking lock. */ int iSaveTimeout = pDbFd->iBusyTimeout; pDbFd->iBusyTimeout = 0; #endif rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT pDbFd->iBusyTimeout = iSaveTimeout; #endif /* The first connection to attach must truncate the -shm file. We ** truncate to 3 bytes (an arbitrary small number, less than the ** -shm header size) rather than 0 as a system debugging aid, to ** help detect if a -shm file truncation is legitimate or is the work ** or a rogue process. */ if( rc==SQLITE_OK && robust_ftruncate(pShmNode->hShm, 3) ){ rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename); } } }else if( lock.l_type==F_WRLCK ){ rc = SQLITE_BUSY; } if( rc==SQLITE_OK ){ assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK ); rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); } return rc; } /* ** Open a shared-memory area associated with open database file pDbFd. ** This particular implementation uses mmapped files. ** ** The file used to implement shared-memory is in the same directory ** as the open database file and has the same name as the open database ** file with the "-shm" suffix added. For example, if the database file ** is "/home/user1/config.db" then the file that is created and mmapped ** for shared memory will be called "/home/user1/config.db-shm". ** ** Another approach to is to use files in /dev/shm or /dev/tmp or an ** some other tmpfs mount. But if a file in a different directory ** from the database file is used, then differing access permissions ** or a chroot() might cause two different processes on the same ** database to end up using different files for shared memory - ** meaning that their memory would not really be shared - resulting ** in database corruption. Nevertheless, this tmpfs file usage ** can be enabled at compile-time using -DSQLITE_SHM_DIRECTORY="/dev/shm" ** or the equivalent. The use of the SQLITE_SHM_DIRECTORY compile-time ** option results in an incompatible build of SQLite; builds of SQLite ** that with differing SQLITE_SHM_DIRECTORY settings attempt to use the ** same database file at the same time, database corruption will likely ** result. The SQLITE_SHM_DIRECTORY compile-time option is considered ** "unsupported" and may go away in a future SQLite release. ** ** When opening a new shared-memory file, if no other instances of that ** file are currently open, in this process or in other processes, then ** the file must be truncated to zero length or have its header cleared. ** ** If the original database file (pDbFd) is using the "unix-excl" VFS ** that means that an exclusive lock is held on the database file and ** that no other processes are able to read or write the database. In ** that case, we do not really need shared memory. No shared memory ** file is created. The shared memory will be simulated with heap memory. */ static int unixOpenSharedMemory(unixFile *pDbFd){ struct unixShm *p = 0; /* The connection to be opened */ struct unixShmNode *pShmNode; /* The underlying mmapped file */ int rc = SQLITE_OK; /* Result code */ unixInodeInfo *pInode; /* The inode of fd */ char *zShm; /* Name of the file used for SHM */ int nShmFilename; /* Size of the SHM filename in bytes */ /* Allocate space for the new unixShm object. */ p = sqlite3_malloc64( sizeof(*p) ); if( p==0 ) return SQLITE_NOMEM_BKPT; memset(p, 0, sizeof(*p)); assert( pDbFd->pShm==0 ); /* Check to see if a unixShmNode object already exists. Reuse an existing ** one if present. Create a new one if necessary. */ assert( unixFileMutexNotheld(pDbFd) ); unixEnterMutex(); pInode = pDbFd->pInode; pShmNode = pInode->pShmNode; if( pShmNode==0 ){ struct stat sStat; /* fstat() info for database file */ #ifndef SQLITE_SHM_DIRECTORY const char *zBasePath = pDbFd->zPath; #endif /* Call fstat() to figure out the permissions on the database file. If ** a new *-shm file is created, an attempt will be made to create it ** with the same permissions. */ if( osFstat(pDbFd->h, &sStat) ){ rc = SQLITE_IOERR_FSTAT; goto shm_open_err; } #ifdef SQLITE_SHM_DIRECTORY nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31; #else nShmFilename = 6 + (int)strlen(zBasePath); #endif pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename ); if( pShmNode==0 ){ rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename); zShm = pShmNode->zFilename = (char*)&pShmNode[1]; #ifdef SQLITE_SHM_DIRECTORY sqlite3_snprintf(nShmFilename, zShm, SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x", (u32)sStat.st_ino, (u32)sStat.st_dev); #else sqlite3_snprintf(nShmFilename, zShm, "%s-shm", zBasePath); sqlite3FileSuffix3(pDbFd->zPath, zShm); #endif pShmNode->hShm = -1; pDbFd->pInode->pShmNode = pShmNode; pShmNode->pInode = pDbFd->pInode; if( sqlite3GlobalConfig.bCoreMutex ){ pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( pShmNode->pShmMutex==0 ){ rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT { int ii; for(ii=0; iiaMutex[ii] = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( pShmNode->aMutex[ii]==0 ){ rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } } } #endif } if( pInode->bProcessLock==0 ){ if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW, (sStat.st_mode&0777)); } if( pShmNode->hShm<0 ){ pShmNode->hShm = robust_open(zShm, O_RDONLY|O_NOFOLLOW, (sStat.st_mode&0777)); if( pShmNode->hShm<0 ){ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm); goto shm_open_err; } pShmNode->isReadonly = 1; } /* If this process is running as root, make sure that the SHM file ** is owned by the same user that owns the original database. Otherwise, ** the original owner will not be able to connect. */ robustFchown(pShmNode->hShm, sStat.st_uid, sStat.st_gid); rc = unixLockSharedMemory(pDbFd, pShmNode); if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err; } } /* Make the new connection a child of the unixShmNode */ p->pShmNode = pShmNode; #ifdef SQLITE_DEBUG p->id = pShmNode->nextShmId++; #endif pShmNode->nRef++; pDbFd->pShm = p; unixLeaveMutex(); /* The reference count on pShmNode has already been incremented under ** the cover of the unixEnterMutex() mutex and the pointer from the ** new (struct unixShm) object to the pShmNode has been set. All that is ** left to do is to link the new object into the linked list starting ** at pShmNode->pFirst. This must be done while holding the ** pShmNode->pShmMutex. */ sqlite3_mutex_enter(pShmNode->pShmMutex); p->pNext = pShmNode->pFirst; pShmNode->pFirst = p; sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; /* Jump here on any error */ shm_open_err: unixShmPurge(pDbFd); /* This call frees pShmNode if required */ sqlite3_free(p); unixLeaveMutex(); return rc; } /* ** This function is called to obtain a pointer to region iRegion of the ** shared-memory associated with the database file fd. Shared-memory regions ** are numbered starting from zero. Each shared-memory region is szRegion ** bytes in size. ** ** If an error occurs, an error code is returned and *pp is set to NULL. ** ** Otherwise, if the bExtend parameter is 0 and the requested shared-memory ** region has not been allocated (by any client, including one running in a ** separate process), then *pp is set to NULL and SQLITE_OK returned. If ** bExtend is non-zero and the requested shared-memory region has not yet ** been allocated, it is allocated by this function. ** ** If the shared-memory region has already been allocated or is allocated by ** this call as described above, then it is mapped into this processes ** address space (if it is not already), *pp is set to point to the mapped ** memory and SQLITE_OK returned. */ static int unixShmMap( sqlite3_file *fd, /* Handle open on database file */ int iRegion, /* Region to retrieve */ int szRegion, /* Size of regions */ int bExtend, /* True to extend file if necessary */ void volatile **pp /* OUT: Mapped memory */ ){ unixFile *pDbFd = (unixFile*)fd; unixShm *p; unixShmNode *pShmNode; int rc = SQLITE_OK; int nShmPerMap = unixShmRegionPerMap(); int nReqRegion; /* If the shared-memory file has not yet been opened, open it now. */ if( pDbFd->pShm==0 ){ rc = unixOpenSharedMemory(pDbFd); if( rc!=SQLITE_OK ) return rc; } p = pDbFd->pShm; pShmNode = p->pShmNode; sqlite3_mutex_enter(pShmNode->pShmMutex); if( pShmNode->isUnlocked ){ rc = unixLockSharedMemory(pDbFd, pShmNode); if( rc!=SQLITE_OK ) goto shmpage_out; pShmNode->isUnlocked = 0; } assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); assert( pShmNode->pInode==pDbFd->pInode ); assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); /* Minimum number of regions required to be mapped. */ nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; if( pShmNode->nRegionszRegion = szRegion; if( pShmNode->hShm>=0 ){ /* The requested region is not mapped into this processes address space. ** Check to see if it has been allocated (i.e. if the wal-index file is ** large enough to contain the requested region). */ if( osFstat(pShmNode->hShm, &sStat) ){ rc = SQLITE_IOERR_SHMSIZE; goto shmpage_out; } if( sStat.st_sizehShm, iPg*pgsz + pgsz-1,"",1,&x)!=1 ){ const char *zFile = pShmNode->zFilename; rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile); goto shmpage_out; } } } } } /* Map the requested memory region into this processes address space. */ apNew = (char **)sqlite3_realloc( pShmNode->apRegion, nReqRegion*sizeof(char *) ); if( !apNew ){ rc = SQLITE_IOERR_NOMEM_BKPT; goto shmpage_out; } pShmNode->apRegion = apNew; while( pShmNode->nRegionhShm>=0 ){ pMem = osMmap(0, nMap, pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, MAP_SHARED, pShmNode->hShm, szRegion*(i64)pShmNode->nRegion ); if( pMem==MAP_FAILED ){ rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); goto shmpage_out; } }else{ pMem = sqlite3_malloc64(nMap); if( pMem==0 ){ rc = SQLITE_NOMEM_BKPT; goto shmpage_out; } memset(pMem, 0, nMap); } for(i=0; iapRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i]; } pShmNode->nRegion += nShmPerMap; } } shmpage_out: if( pShmNode->nRegion>iRegion ){ *pp = pShmNode->apRegion[iRegion]; }else{ *pp = 0; } if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; } /* ** Check that the pShmNode->aLock[] array comports with the locking bitmasks ** held by each client. Return true if it does, or false otherwise. This ** is to be used in an assert(). e.g. ** ** assert( assertLockingArrayOk(pShmNode) ); */ #ifdef SQLITE_DEBUG static int assertLockingArrayOk(unixShmNode *pShmNode){ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT return 1; #else unixShm *pX; int aLock[SQLITE_SHM_NLOCK]; memset(aLock, 0, sizeof(aLock)); for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ int i; for(i=0; iexclMask & (1<sharedMask & (1<=0 ); aLock[i]++; } } } assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) ); return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0); #endif } #endif /* ** Change the lock state for a shared-memory segment. ** ** Note that the relationship between SHARED and EXCLUSIVE locks is a little ** different here than in posix. In xShmLock(), one can go from unlocked ** to shared and back or from unlocked to exclusive and back. But one may ** not go from shared to exclusive or from exclusive to shared. */ static int unixShmLock( sqlite3_file *fd, /* Database file holding the shared memory */ int ofst, /* First lock to acquire or release */ int n, /* Number of locks to acquire or release */ int flags /* What to do with the lock */ ){ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ unixShm *p; /* The shared memory being locked */ unixShmNode *pShmNode; /* The underlying file iNode */ int rc = SQLITE_OK; /* Result code */ u16 mask = (1<<(ofst+n)) - (1<pShm; if( p==0 ) return SQLITE_IOERR_SHMLOCK; pShmNode = p->pShmNode; if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; aLock = pShmNode->aLock; assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); assert( n>=1 ); assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); /* Check that, if this to be a blocking lock, no locks that occur later ** in the following list than the lock being obtained are already held: ** ** 1. Checkpointer lock (ofst==1). ** 2. Write lock (ofst==0). ** 3. Read locks (ofst>=3 && ofstexclMask|p->sharedMask); assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( (ofst!=2) /* not RECOVER */ && (ofst!=1 || lockMask==0 || lockMask==2) && (ofst!=0 || lockMask<3) && (ofst<3 || lockMask<(1<exclMask & mask) ); if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask)) || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask)) || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)) ){ /* Take the required mutexes. In SETLK_TIMEOUT mode (blocking locks), if ** this is an attempt on an exclusive lock use sqlite3_mutex_try(). If any ** other thread is holding this mutex, then it is either holding or about ** to hold a lock exclusive to the one being requested, and we may ** therefore return SQLITE_BUSY to the caller. ** ** Doing this prevents some deadlock scenarios. For example, thread 1 may ** be a checkpointer blocked waiting on the WRITER lock. And thread 2 ** may be a normal SQL client upgrading to a write transaction. In this ** case thread 2 does a non-blocking request for the WRITER lock. But - ** if it were to use sqlite3_mutex_enter() then it would effectively ** become a (doomed) blocking request, as thread 2 would block until thread ** 1 obtained WRITER and released the mutex. Since thread 2 already holds ** a lock on a read-locking slot at this point, this breaks the ** anti-deadlock rules (see above). */ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT int iMutex; for(iMutex=ofst; iMutexaMutex[iMutex]); if( rc!=SQLITE_OK ) goto leave_shmnode_mutexes; }else{ sqlite3_mutex_enter(pShmNode->aMutex[iMutex]); } } #else sqlite3_mutex_enter(pShmNode->pShmMutex); #endif if( ALWAYS(rc==SQLITE_OK) ){ if( flags & SQLITE_SHM_UNLOCK ){ /* Case (a) - unlock. */ int bUnlock = 1; assert( (p->exclMask & p->sharedMask)==0 ); assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask ); assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask ); /* If this is a SHARED lock being unlocked, it is possible that other ** clients within this process are holding the same SHARED lock. In ** this case, set bUnlock to 0 so that the posix lock is not removed ** from the file-descriptor below. */ if( flags & SQLITE_SHM_SHARED ){ assert( n==1 ); assert( aLock[ofst]>=1 ); if( aLock[ofst]>1 ){ bUnlock = 0; aLock[ofst]--; p->sharedMask &= ~mask; } } if( bUnlock ){ rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); if( rc==SQLITE_OK ){ memset(&aLock[ofst], 0, sizeof(int)*n); p->sharedMask &= ~mask; p->exclMask &= ~mask; } } }else if( flags & SQLITE_SHM_SHARED ){ /* Case (b) - a shared lock. */ if( aLock[ofst]<0 ){ /* An exclusive lock is held by some other connection. BUSY. */ rc = SQLITE_BUSY; }else if( aLock[ofst]==0 ){ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); } /* Get the local shared locks */ if( rc==SQLITE_OK ){ p->sharedMask |= mask; aLock[ofst]++; } }else{ /* Case (c) - an exclusive lock. */ int ii; assert( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) ); assert( (p->sharedMask & mask)==0 ); assert( (p->exclMask & mask)==0 ); /* Make sure no sibling connections hold locks that will block this ** lock. If any do, return SQLITE_BUSY right away. */ for(ii=ofst; iiexclMask |= mask; for(ii=ofst; ii=ofst; iMutex--){ sqlite3_mutex_leave(pShmNode->aMutex[iMutex]); } #else sqlite3_mutex_leave(pShmNode->pShmMutex); #endif } OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", p->id, osGetpid(0), p->sharedMask, p->exclMask)); return rc; } /* ** Implement a memory barrier or memory fence on shared memory. ** ** All loads and stores begun before the barrier must complete before ** any load or store begun after the barrier. */ static void unixShmBarrier( sqlite3_file *fd /* Database file holding the shared memory */ ){ UNUSED_PARAMETER(fd); sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ assert( fd->pMethods->xLock==nolockLock || unixFileMutexNotheld((unixFile*)fd) ); unixEnterMutex(); /* Also mutex, for redundancy */ unixLeaveMutex(); } /* ** Close a connection to shared-memory. Delete the underlying ** storage if deleteFlag is true. ** ** If there is no shared memory associated with the connection then this ** routine is a harmless no-op. */ static int unixShmUnmap( sqlite3_file *fd, /* The underlying database file */ int deleteFlag /* Delete shared-memory if true */ ){ unixShm *p; /* The connection to be closed */ unixShmNode *pShmNode; /* The underlying shared-memory file */ unixShm **pp; /* For looping over sibling connections */ unixFile *pDbFd; /* The underlying database file */ pDbFd = (unixFile*)fd; p = pDbFd->pShm; if( p==0 ) return SQLITE_OK; pShmNode = p->pShmNode; assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); /* Remove connection p from the set of connections associated ** with pShmNode */ sqlite3_mutex_enter(pShmNode->pShmMutex); for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} *pp = p->pNext; /* Free the connection p */ sqlite3_free(p); pDbFd->pShm = 0; sqlite3_mutex_leave(pShmNode->pShmMutex); /* If pShmNode->nRef has reached 0, then close the underlying ** shared-memory file, too */ assert( unixFileMutexNotheld(pDbFd) ); unixEnterMutex(); assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ if( deleteFlag && pShmNode->hShm>=0 ){ osUnlink(pShmNode->zFilename); } unixShmPurge(pDbFd); } unixLeaveMutex(); return SQLITE_OK; } #else # define unixShmMap 0 # define unixShmLock 0 # define unixShmBarrier 0 # define unixShmUnmap 0 #endif /* #ifndef SQLITE_OMIT_WAL */ #if SQLITE_MAX_MMAP_SIZE>0 /* ** If it is currently memory mapped, unmap file pFd. */ static void unixUnmapfile(unixFile *pFd){ assert( pFd->nFetchOut==0 ); if( pFd->pMapRegion ){ osMunmap(pFd->pMapRegion, pFd->mmapSizeActual); pFd->pMapRegion = 0; pFd->mmapSize = 0; pFd->mmapSizeActual = 0; } } /* ** Attempt to set the size of the memory mapping maintained by file ** descriptor pFd to nNew bytes. Any existing mapping is discarded. ** ** If successful, this function sets the following variables: ** ** unixFile.pMapRegion ** unixFile.mmapSize ** unixFile.mmapSizeActual ** ** If unsuccessful, an error message is logged via sqlite3_log() and ** the three variables above are zeroed. In this case SQLite should ** continue accessing the database using the xRead() and xWrite() ** methods. */ static void unixRemapfile( unixFile *pFd, /* File descriptor object */ i64 nNew /* Required mapping size */ ){ const char *zErr = "mmap"; int h = pFd->h; /* File descriptor open on db file */ u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */ i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */ u8 *pNew = 0; /* Location of new mapping */ int flags = PROT_READ; /* Flags to pass to mmap() */ assert( pFd->nFetchOut==0 ); assert( nNew>pFd->mmapSize ); assert( nNew<=pFd->mmapSizeMax ); assert( nNew>0 ); assert( pFd->mmapSizeActual>=pFd->mmapSize ); assert( MAP_FAILED!=0 ); #ifdef SQLITE_MMAP_READWRITE if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; #endif if( pOrig ){ #if HAVE_MREMAP i64 nReuse = pFd->mmapSize; #else const int szSyspage = osGetpagesize(); i64 nReuse = (pFd->mmapSize & ~(szSyspage-1)); #endif u8 *pReq = &pOrig[nReuse]; /* Unmap any pages of the existing mapping that cannot be reused. */ if( nReuse!=nOrig ){ osMunmap(pReq, nOrig-nReuse); } #if HAVE_MREMAP pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE); zErr = "mremap"; #else pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse); if( pNew!=MAP_FAILED ){ if( pNew!=pReq ){ osMunmap(pNew, nNew - nReuse); pNew = 0; }else{ pNew = pOrig; } } #endif /* The attempt to extend the existing mapping failed. Free it. */ if( pNew==MAP_FAILED || pNew==0 ){ osMunmap(pOrig, nReuse); } } /* If pNew is still NULL, try to create an entirely new mapping. */ if( pNew==0 ){ pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0); } if( pNew==MAP_FAILED ){ pNew = 0; nNew = 0; unixLogError(SQLITE_OK, zErr, pFd->zPath); /* If the mmap() above failed, assume that all subsequent mmap() calls ** will probably fail too. Fall back to using xRead/xWrite exclusively ** in this case. */ pFd->mmapSizeMax = 0; } pFd->pMapRegion = (void *)pNew; pFd->mmapSize = pFd->mmapSizeActual = nNew; } /* ** Memory map or remap the file opened by file-descriptor pFd (if the file ** is already mapped, the existing mapping is replaced by the new). Or, if ** there already exists a mapping for this file, and there are still ** outstanding xFetch() references to it, this function is a no-op. ** ** If parameter nByte is non-negative, then it is the requested size of ** the mapping to create. Otherwise, if nByte is less than zero, then the ** requested size is the size of the file on disk. The actual size of the ** created mapping is either the requested size or the value configured ** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller. ** ** SQLITE_OK is returned if no error occurs (even if the mapping is not ** recreated as a result of outstanding references) or an SQLite error ** code otherwise. */ static int unixMapfile(unixFile *pFd, i64 nMap){ assert( nMap>=0 || pFd->nFetchOut==0 ); assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) ); if( pFd->nFetchOut>0 ) return SQLITE_OK; if( nMap<0 ){ struct stat statbuf; /* Low-level file information */ if( osFstat(pFd->h, &statbuf) ){ return SQLITE_IOERR_FSTAT; } nMap = statbuf.st_size; } if( nMap>pFd->mmapSizeMax ){ nMap = pFd->mmapSizeMax; } assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) ); if( nMap!=pFd->mmapSize ){ unixRemapfile(pFd, nMap); } return SQLITE_OK; } #endif /* SQLITE_MAX_MMAP_SIZE>0 */ /* ** If possible, return a pointer to a mapping of file fd starting at offset ** iOff. The mapping must be valid for at least nAmt bytes. ** ** If such a pointer can be obtained, store it in *pp and return SQLITE_OK. ** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK. ** Finally, if an error does occur, return an SQLite error code. The final ** value of *pp is undefined in this case. ** ** If this function does return a pointer, the caller must eventually ** release the reference by calling unixUnfetch(). */ static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ #if SQLITE_MAX_MMAP_SIZE>0 unixFile *pFd = (unixFile *)fd; /* The underlying database file */ #endif *pp = 0; #if SQLITE_MAX_MMAP_SIZE>0 if( pFd->mmapSizeMax>0 ){ /* Ensure that there is always at least a 256 byte buffer of addressable ** memory following the returned page. If the database is corrupt, ** SQLite may overread the page slightly (in practice only a few bytes, ** but 256 is safe, round, number). */ const int nEofBuffer = 256; if( pFd->pMapRegion==0 ){ int rc = unixMapfile(pFd, -1); if( rc!=SQLITE_OK ) return rc; } if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){ *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; } } #endif return SQLITE_OK; } /* ** If the third argument is non-NULL, then this function releases a ** reference obtained by an earlier call to unixFetch(). The second ** argument passed to this function must be the same as the corresponding ** argument that was passed to the unixFetch() invocation. ** ** Or, if the third argument is NULL, then this function is being called ** to inform the VFS layer that, according to POSIX, any existing mapping ** may now be invalid and should be unmapped. */ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ #if SQLITE_MAX_MMAP_SIZE>0 unixFile *pFd = (unixFile *)fd; /* The underlying database file */ UNUSED_PARAMETER(iOff); /* If p==0 (unmap the entire file) then there must be no outstanding ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), ** then there must be at least one outstanding. */ assert( (p==0)==(pFd->nFetchOut==0) ); /* If p!=0, it must match the iOff value. */ assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] ); if( p ){ pFd->nFetchOut--; }else{ unixUnmapfile(pFd); } assert( pFd->nFetchOut>=0 ); #else UNUSED_PARAMETER(fd); UNUSED_PARAMETER(p); UNUSED_PARAMETER(iOff); #endif return SQLITE_OK; } /* ** Here ends the implementation of all sqlite3_file methods. ** ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ /* ** This division contains definitions of sqlite3_io_methods objects that ** implement various file locking strategies. It also contains definitions ** of "finder" functions. A finder-function is used to locate the appropriate ** sqlite3_io_methods object for a particular database file. The pAppData ** field of the sqlite3_vfs VFS objects are initialized to be pointers to ** the correct finder-function for that VFS. ** ** Most finder functions return a pointer to a fixed sqlite3_io_methods ** object. The only interesting finder-function is autolockIoFinder, which ** looks at the filesystem type and tries to guess the best locking ** strategy from that. ** ** For finder-function F, two objects are created: ** ** (1) The real finder-function named "FImpt()". ** ** (2) A constant pointer to this function named just "F". ** ** ** A pointer to the F pointer is used as the pAppData value for VFS ** objects. We have to do this instead of letting pAppData point ** directly at the finder-function since C90 rules prevent a void* ** from be cast into a function pointer. ** ** ** Each instance of this macro generates two objects: ** ** * A constant sqlite3_io_methods object call METHOD that has locking ** methods CLOSE, LOCK, UNLOCK, CKRESLOCK. ** ** * An I/O method finder function called FINDER that returns a pointer ** to the METHOD object in the previous bullet. */ #define IOMETHODS(FINDER,METHOD,VERSION,CLOSE,LOCK,UNLOCK,CKLOCK,SHMMAP) \ static const sqlite3_io_methods METHOD = { \ VERSION, /* iVersion */ \ CLOSE, /* xClose */ \ unixRead, /* xRead */ \ unixWrite, /* xWrite */ \ unixTruncate, /* xTruncate */ \ unixSync, /* xSync */ \ unixFileSize, /* xFileSize */ \ LOCK, /* xLock */ \ UNLOCK, /* xUnlock */ \ CKLOCK, /* xCheckReservedLock */ \ unixFileControl, /* xFileControl */ \ unixSectorSize, /* xSectorSize */ \ unixDeviceCharacteristics, /* xDeviceCapabilities */ \ SHMMAP, /* xShmMap */ \ unixShmLock, /* xShmLock */ \ unixShmBarrier, /* xShmBarrier */ \ unixShmUnmap, /* xShmUnmap */ \ unixFetch, /* xFetch */ \ unixUnfetch, /* xUnfetch */ \ }; \ static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \ UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \ return &METHOD; \ } \ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \ = FINDER##Impl; /* ** Here are all of the sqlite3_io_methods objects for each of the ** locking strategies. Functions that return pointers to these methods ** are also created. */ IOMETHODS( posixIoFinder, /* Finder function name */ posixIoMethods, /* sqlite3_io_methods object name */ 3, /* shared memory and mmap are enabled */ unixClose, /* xClose method */ unixLock, /* xLock method */ unixUnlock, /* xUnlock method */ unixCheckReservedLock, /* xCheckReservedLock method */ unixShmMap /* xShmMap method */ ) IOMETHODS( nolockIoFinder, /* Finder function name */ nolockIoMethods, /* sqlite3_io_methods object name */ 3, /* shared memory and mmap are enabled */ nolockClose, /* xClose method */ nolockLock, /* xLock method */ nolockUnlock, /* xUnlock method */ nolockCheckReservedLock, /* xCheckReservedLock method */ 0 /* xShmMap method */ ) IOMETHODS( dotlockIoFinder, /* Finder function name */ dotlockIoMethods, /* sqlite3_io_methods object name */ 1, /* shared memory is disabled */ dotlockClose, /* xClose method */ dotlockLock, /* xLock method */ dotlockUnlock, /* xUnlock method */ dotlockCheckReservedLock, /* xCheckReservedLock method */ 0 /* xShmMap method */ ) #if SQLITE_ENABLE_LOCKING_STYLE IOMETHODS( flockIoFinder, /* Finder function name */ flockIoMethods, /* sqlite3_io_methods object name */ 1, /* shared memory is disabled */ flockClose, /* xClose method */ flockLock, /* xLock method */ flockUnlock, /* xUnlock method */ flockCheckReservedLock, /* xCheckReservedLock method */ 0 /* xShmMap method */ ) #endif #if OS_VXWORKS IOMETHODS( semIoFinder, /* Finder function name */ semIoMethods, /* sqlite3_io_methods object name */ 1, /* shared memory is disabled */ semXClose, /* xClose method */ semXLock, /* xLock method */ semXUnlock, /* xUnlock method */ semXCheckReservedLock, /* xCheckReservedLock method */ 0 /* xShmMap method */ ) #endif #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE IOMETHODS( afpIoFinder, /* Finder function name */ afpIoMethods, /* sqlite3_io_methods object name */ 1, /* shared memory is disabled */ afpClose, /* xClose method */ afpLock, /* xLock method */ afpUnlock, /* xUnlock method */ afpCheckReservedLock, /* xCheckReservedLock method */ 0 /* xShmMap method */ ) #endif /* ** The proxy locking method is a "super-method" in the sense that it ** opens secondary file descriptors for the conch and lock files and ** it uses proxy, dot-file, AFP, and flock() locking methods on those ** secondary files. For this reason, the division that implements ** proxy locking is located much further down in the file. But we need ** to go ahead and define the sqlite3_io_methods and finder function ** for proxy locking here. So we forward declare the I/O methods. */ #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE static int proxyClose(sqlite3_file*); static int proxyLock(sqlite3_file*, int); static int proxyUnlock(sqlite3_file*, int); static int proxyCheckReservedLock(sqlite3_file*, int*); IOMETHODS( proxyIoFinder, /* Finder function name */ proxyIoMethods, /* sqlite3_io_methods object name */ 1, /* shared memory is disabled */ proxyClose, /* xClose method */ proxyLock, /* xLock method */ proxyUnlock, /* xUnlock method */ proxyCheckReservedLock, /* xCheckReservedLock method */ 0 /* xShmMap method */ ) #endif /* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */ #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE IOMETHODS( nfsIoFinder, /* Finder function name */ nfsIoMethods, /* sqlite3_io_methods object name */ 1, /* shared memory is disabled */ unixClose, /* xClose method */ unixLock, /* xLock method */ nfsUnlock, /* xUnlock method */ unixCheckReservedLock, /* xCheckReservedLock method */ 0 /* xShmMap method */ ) #endif #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE /* ** This "finder" function attempts to determine the best locking strategy ** for the database file "filePath". It then returns the sqlite3_io_methods ** object that implements that strategy. ** ** This is for MacOSX only. */ static const sqlite3_io_methods *autolockIoFinderImpl( const char *filePath, /* name of the database file */ unixFile *pNew /* open file object for the database file */ ){ static const struct Mapping { const char *zFilesystem; /* Filesystem type name */ const sqlite3_io_methods *pMethods; /* Appropriate locking method */ } aMap[] = { { "hfs", &posixIoMethods }, { "ufs", &posixIoMethods }, { "afpfs", &afpIoMethods }, { "smbfs", &afpIoMethods }, { "webdav", &nolockIoMethods }, { 0, 0 } }; int i; struct statfs fsInfo; struct flock lockInfo; if( !filePath ){ /* If filePath==NULL that means we are dealing with a transient file ** that does not need to be locked. */ return &nolockIoMethods; } if( statfs(filePath, &fsInfo) != -1 ){ if( fsInfo.f_flags & MNT_RDONLY ){ return &nolockIoMethods; } for(i=0; aMap[i].zFilesystem; i++){ if( strcmp(fsInfo.f_fstypename, aMap[i].zFilesystem)==0 ){ return aMap[i].pMethods; } } } /* Default case. Handles, amongst others, "nfs". ** Test byte-range lock using fcntl(). If the call succeeds, ** assume that the file-system supports POSIX style locks. */ lockInfo.l_len = 1; lockInfo.l_start = 0; lockInfo.l_whence = SEEK_SET; lockInfo.l_type = F_RDLCK; if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) { if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){ return &nfsIoMethods; } else { return &posixIoMethods; } }else{ return &dotlockIoMethods; } } static const sqlite3_io_methods *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ #if OS_VXWORKS /* ** This "finder" function for VxWorks checks to see if posix advisory ** locking works. If it does, then that is what is used. If it does not ** work, then fallback to named semaphore locking. */ static const sqlite3_io_methods *vxworksIoFinderImpl( const char *filePath, /* name of the database file */ unixFile *pNew /* the open file object */ ){ struct flock lockInfo; if( !filePath ){ /* If filePath==NULL that means we are dealing with a transient file ** that does not need to be locked. */ return &nolockIoMethods; } /* Test if fcntl() is supported and use POSIX style locks. ** Otherwise fall back to the named semaphore method. */ lockInfo.l_len = 1; lockInfo.l_start = 0; lockInfo.l_whence = SEEK_SET; lockInfo.l_type = F_RDLCK; if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) { return &posixIoMethods; }else{ return &semIoMethods; } } static const sqlite3_io_methods *(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl; #endif /* OS_VXWORKS */ /* ** An abstract type for a pointer to an IO method finder function: */ typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); /**************************************************************************** **************************** sqlite3_vfs methods **************************** ** ** This division contains the implementation of methods on the ** sqlite3_vfs object. */ /* ** Initialize the contents of the unixFile structure pointed to by pId. */ static int fillInUnixFile( sqlite3_vfs *pVfs, /* Pointer to vfs object */ int h, /* Open file descriptor of file being opened */ sqlite3_file *pId, /* Write to the unixFile structure here */ const char *zFilename, /* Name of the file being opened */ int ctrlFlags /* Zero or more UNIXFILE_* values */ ){ const sqlite3_io_methods *pLockingStyle; unixFile *pNew = (unixFile *)pId; int rc = SQLITE_OK; assert( pNew->pInode==NULL ); /* No locking occurs in temporary files */ assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); OSTRACE(("OPEN %-3d %s\n", h, zFilename)); pNew->h = h; pNew->pVfs = pVfs; pNew->zPath = zFilename; pNew->ctrlFlags = (u8)ctrlFlags; #if SQLITE_MAX_MMAP_SIZE>0 pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap; #endif if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pNew->ctrlFlags |= UNIXFILE_PSOW; } if( strcmp(pVfs->zName,"unix-excl")==0 ){ pNew->ctrlFlags |= UNIXFILE_EXCL; } #if OS_VXWORKS pNew->pId = vxworksFindFileId(zFilename); if( pNew->pId==0 ){ ctrlFlags |= UNIXFILE_NOLOCK; rc = SQLITE_NOMEM_BKPT; } #endif if( ctrlFlags & UNIXFILE_NOLOCK ){ pLockingStyle = &nolockIoMethods; }else{ pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew); #if SQLITE_ENABLE_LOCKING_STYLE /* Cache zFilename in the locking context (AFP and dotlock override) for ** proxyLock activation is possible (remote proxy is based on db name) ** zFilename remains valid until file is closed, to support */ pNew->lockingContext = (void*)zFilename; #endif } if( pLockingStyle == &posixIoMethods #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE || pLockingStyle == &nfsIoMethods #endif ){ unixEnterMutex(); rc = findInodeInfo(pNew, &pNew->pInode); if( rc!=SQLITE_OK ){ /* If an error occurred in findInodeInfo(), close the file descriptor ** immediately, before releasing the mutex. findInodeInfo() may fail ** in two scenarios: ** ** (a) A call to fstat() failed. ** (b) A malloc failed. ** ** Scenario (b) may only occur if the process is holding no other ** file descriptors open on the same file. If there were other file ** descriptors on this file, then no malloc would be required by ** findInodeInfo(). If this is the case, it is quite safe to close ** handle h - as it is guaranteed that no posix locks will be released ** by doing so. ** ** If scenario (a) caused the error then things are not so safe. The ** implicit assumption here is that if fstat() fails, things are in ** such bad shape that dropping a lock or two doesn't matter much. */ robust_close(pNew, h, __LINE__); h = -1; } unixLeaveMutex(); } #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) else if( pLockingStyle == &afpIoMethods ){ /* AFP locking uses the file path so it needs to be included in ** the afpLockingContext. */ afpLockingContext *pCtx; pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) ); if( pCtx==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ /* NB: zFilename exists and remains valid until the file is closed ** according to requirement F11141. So we do not need to make a ** copy of the filename. */ pCtx->dbPath = zFilename; pCtx->reserved = 0; srandomdev(); unixEnterMutex(); rc = findInodeInfo(pNew, &pNew->pInode); if( rc!=SQLITE_OK ){ sqlite3_free(pNew->lockingContext); robust_close(pNew, h, __LINE__); h = -1; } unixLeaveMutex(); } } #endif else if( pLockingStyle == &dotlockIoMethods ){ /* Dotfile locking uses the file path so it needs to be included in ** the dotlockLockingContext */ char *zLockFile; int nFilename; assert( zFilename!=0 ); nFilename = (int)strlen(zFilename) + 6; zLockFile = (char *)sqlite3_malloc64(nFilename); if( zLockFile==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename); } pNew->lockingContext = zLockFile; } #if OS_VXWORKS else if( pLockingStyle == &semIoMethods ){ /* Named semaphore locking uses the file path so it needs to be ** included in the semLockingContext */ unixEnterMutex(); rc = findInodeInfo(pNew, &pNew->pInode); if( (rc==SQLITE_OK) && (pNew->pInode->pSem==NULL) ){ char *zSemName = pNew->pInode->aSemName; int n; sqlite3_snprintf(MAX_PATHNAME, zSemName, "/%s.sem", pNew->pId->zCanonicalName); for( n=1; zSemName[n]; n++ ) if( zSemName[n]=='/' ) zSemName[n] = '_'; pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1); if( pNew->pInode->pSem == SEM_FAILED ){ rc = SQLITE_NOMEM_BKPT; pNew->pInode->aSemName[0] = '\0'; } } unixLeaveMutex(); } #endif storeLastErrno(pNew, 0); #if OS_VXWORKS if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); h = -1; osUnlink(zFilename); pNew->ctrlFlags |= UNIXFILE_DELETE; } #endif if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); }else{ pId->pMethods = pLockingStyle; OpenCounter(+1); verifyDbFile(pNew); } return rc; } /* ** Directories to consider for temp files. */ static const char *azTempDirs[] = { 0, 0, "/var/tmp", "/usr/tmp", "/tmp", "." }; /* ** Initialize first two members of azTempDirs[] array. */ static void unixTempFileInit(void){ azTempDirs[0] = getenv("SQLITE_TMPDIR"); azTempDirs[1] = getenv("TMPDIR"); } /* ** Return the name of a directory in which to put temporary files. ** If no suitable temporary file directory can be found, return NULL. */ static const char *unixTempFileDir(void){ unsigned int i = 0; struct stat buf; const char *zDir = sqlite3_temp_directory; while(1){ if( zDir!=0 && osStat(zDir, &buf)==0 && S_ISDIR(buf.st_mode) && osAccess(zDir, 03)==0 ){ return zDir; } if( i>=sizeof(azTempDirs)/sizeof(azTempDirs[0]) ) break; zDir = azTempDirs[i++]; } return 0; } /* ** Create a temporary file name in zBuf. zBuf must be allocated ** by the calling process and must be big enough to hold at least ** pVfs->mxPathname bytes. */ static int unixGetTempname(int nBuf, char *zBuf){ const char *zDir; int iLimit = 0; int rc = SQLITE_OK; /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. */ zBuf[0] = 0; SimulateIOError( return SQLITE_IOERR ); sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); zDir = unixTempFileDir(); if( zDir==0 ){ rc = SQLITE_IOERR_GETTEMPPATH; }else{ do{ u64 r; sqlite3_randomness(sizeof(r), &r); assert( nBuf>2 ); zBuf[nBuf-2] = 0; sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c", zDir, r, 0); if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ){ rc = SQLITE_ERROR; break; } }while( osAccess(zBuf,0)==0 ); } sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); return rc; } #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) /* ** Routine to transform a unixFile into a proxy-locking unixFile. ** Implementation in the proxy-lock division, but used by unixOpen() ** if SQLITE_PREFER_PROXY_LOCKING is defined. */ static int proxyTransformUnixFile(unixFile*, const char*); #endif /* ** Search for an unused file descriptor that was opened on the database ** file (not a journal or super-journal file) identified by pathname ** zPath with SQLITE_OPEN_XXX flags matching those passed as the second ** argument to this function. ** ** Such a file descriptor may exist if a database connection was closed ** but the associated file descriptor could not be closed because some ** other file descriptor open on the same file is holding a file-lock. ** Refer to comments in the unixClose() function and the lengthy comment ** describing "Posix Advisory Locking" at the start of this file for ** further details. Also, ticket #4018. ** ** If a suitable file descriptor is found, then it is returned. If no ** such file descriptor is located, -1 is returned. */ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ UnixUnusedFd *pUnused = 0; /* Do not search for an unused file descriptor on vxworks. Not because ** vxworks would not benefit from the change (it might, we're not sure), ** but because no way to test it is currently available. It is better ** not to risk breaking vxworks support for the sake of such an obscure ** feature. */ #if !OS_VXWORKS struct stat sStat; /* Results of stat() call */ unixEnterMutex(); /* A stat() call may fail for various reasons. If this happens, it is ** almost certain that an open() call on the same path will also fail. ** For this reason, if an error occurs in the stat() call here, it is ** ignored and -1 is returned. The caller will try to open a new file ** descriptor on the same path, fail, and return an error to SQLite. ** ** Even if a subsequent open() call does succeed, the consequences of ** not searching for a reusable file descriptor are not dire. */ if( inodeList!=0 && 0==osStat(zPath, &sStat) ){ unixInodeInfo *pInode; pInode = inodeList; while( pInode && (pInode->fileId.dev!=sStat.st_dev || pInode->fileId.ino!=(u64)sStat.st_ino) ){ pInode = pInode->pNext; } if( pInode ){ UnixUnusedFd **pp; assert( sqlite3_mutex_notheld(pInode->pLockMutex) ); sqlite3_mutex_enter(pInode->pLockMutex); flags &= (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE); for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); pUnused = *pp; if( pUnused ){ *pp = pUnused->pNext; } sqlite3_mutex_leave(pInode->pLockMutex); } } unixLeaveMutex(); #endif /* if !OS_VXWORKS */ return pUnused; } /* ** Find the mode, uid and gid of file zFile. */ static int getFileMode( const char *zFile, /* File name */ mode_t *pMode, /* OUT: Permissions of zFile */ uid_t *pUid, /* OUT: uid of zFile. */ gid_t *pGid /* OUT: gid of zFile. */ ){ struct stat sStat; /* Output of stat() on database file */ int rc = SQLITE_OK; if( 0==osStat(zFile, &sStat) ){ *pMode = sStat.st_mode & 0777; *pUid = sStat.st_uid; *pGid = sStat.st_gid; }else{ rc = SQLITE_IOERR_FSTAT; } return rc; } /* ** This function is called by unixOpen() to determine the unix permissions ** to create new files with. If no error occurs, then SQLITE_OK is returned ** and a value suitable for passing as the third argument to open(2) is ** written to *pMode. If an IO error occurs, an SQLite error code is ** returned and the value of *pMode is not modified. ** ** In most cases, this routine sets *pMode to 0, which will become ** an indication to robust_open() to create the file using ** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask. ** But if the file being opened is a WAL or regular journal file, then ** this function queries the file-system for the permissions on the ** corresponding database file and sets *pMode to this value. Whenever ** possible, WAL and journal files are created using the same permissions ** as the associated database file. ** ** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the ** original filename is unavailable. But 8_3_NAMES is only used for ** FAT filesystems and permissions do not matter there, so just use ** the default permissions. In 8_3_NAMES mode, leave *pMode set to zero. */ static int findCreateFileMode( const char *zPath, /* Path of file (possibly) being created */ int flags, /* Flags passed as 4th argument to xOpen() */ mode_t *pMode, /* OUT: Permissions to open file with */ uid_t *pUid, /* OUT: uid to set on the file */ gid_t *pGid /* OUT: gid to set on the file */ ){ int rc = SQLITE_OK; /* Return Code */ *pMode = 0; *pUid = 0; *pGid = 0; if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ char zDb[MAX_PATHNAME+1]; /* Database file path */ int nDb; /* Number of valid bytes in zDb */ /* zPath is a path to a WAL or journal file. The following block derives ** the path to the associated database file from zPath. This block handles ** the following naming conventions: ** ** "-journal" ** "-wal" ** "-journalNN" ** "-walNN" ** ** where NN is a decimal number. The NN naming schemes are ** used by the test_multiplex.c module. ** ** In normal operation, the journal file name will always contain ** a '-' character. However in 8+3 filename mode, or if a corrupt ** rollback journal specifies a super-journal with a goofy name, then ** the '-' might be missing or the '-' might be the first character in ** the filename. In that case, just return SQLITE_OK with *pMode==0. */ nDb = sqlite3Strlen30(zPath) - 1; while( nDb>0 && zPath[nDb]!='.' ){ if( zPath[nDb]=='-' ){ memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; rc = getFileMode(zDb, pMode, pUid, pGid); break; } nDb--; } }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ *pMode = 0600; }else if( flags & SQLITE_OPEN_URI ){ /* If this is a main database file and the file was opened using a URI ** filename, check for the "modeof" parameter. If present, interpret ** its value as a filename and try to copy the mode, uid and gid from ** that file. */ const char *z = sqlite3_uri_parameter(zPath, "modeof"); if( z ){ rc = getFileMode(z, pMode, pUid, pGid); } } return rc; } /* ** Open the file zPath. ** ** Previously, the SQLite OS layer used three functions in place of this ** one: ** ** sqlite3OsOpenReadWrite(); ** sqlite3OsOpenReadOnly(); ** sqlite3OsOpenExclusive(); ** ** These calls correspond to the following combinations of flags: ** ** ReadWrite() -> (READWRITE | CREATE) ** ReadOnly() -> (READONLY) ** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE) ** ** The old OpenExclusive() accepted a boolean argument - "delFlag". If ** true, the file was configured to be automatically deleted when the ** file handle closed. To achieve the same effect using this new ** interface, add the DELETEONCLOSE flag to those specified above for ** OpenExclusive(). */ static int unixOpen( sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */ const char *zPath, /* Pathname of file to be opened */ sqlite3_file *pFile, /* The file descriptor to be filled in */ int flags, /* Input flags to control the opening */ int *pOutFlags /* Output flags returned to SQLite core */ ){ unixFile *p = (unixFile *)pFile; int fd = -1; /* File descriptor returned by open() */ int openFlags = 0; /* Flags to pass to open() */ int eType = flags&0x0FFF00; /* Type of file to open */ int noLock; /* True to omit locking primitives */ int rc = SQLITE_OK; /* Function Return Code */ int ctrlFlags = 0; /* UNIXFILE_* flags */ int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isCreate = (flags & SQLITE_OPEN_CREATE); int isReadonly = (flags & SQLITE_OPEN_READONLY); int isReadWrite = (flags & SQLITE_OPEN_READWRITE); #if SQLITE_ENABLE_LOCKING_STYLE int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY); #endif #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE struct statfs fsInfo; #endif /* If creating a super- or main-file journal, this function will open ** a file-descriptor on the directory too. The first time unixSync() ** is called the directory file descriptor will be fsync()ed and close()d. */ int isNewJrnl = (isCreate && ( eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_WAL )); /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. */ char zTmpname[MAX_PATHNAME+2]; const char *zName = zPath; /* Check the following statements are true: ** ** (a) Exactly one of the READWRITE and READONLY flags must be set, and ** (b) if CREATE is set, then READWRITE must also be set, and ** (c) if EXCLUSIVE is set, then CREATE must also be set. ** (d) if DELETEONCLOSE is set, then CREATE must also be set. */ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); assert(isCreate==0 || isReadWrite); assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); /* The main DB, main journal, WAL file and super-journal are never ** automatically deleted. Nor are they ever temporary files. */ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); /* Assert that the upper layer has set one of the "file-type" flags. */ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); /* Detect a pid change and reset the PRNG. There is a race condition ** here such that two or more threads all trying to open databases at ** the same instant might all reset the PRNG. But multiple resets ** are harmless. */ if( randomnessPid!=osGetpid(0) ){ randomnessPid = osGetpid(0); sqlite3_randomness(0,0); } memset(p, 0, sizeof(unixFile)); #ifdef SQLITE_ASSERT_NO_FILES /* Applications that never read or write a persistent disk files */ assert( zName==0 ); #endif if( eType==SQLITE_OPEN_MAIN_DB ){ UnixUnusedFd *pUnused; pUnused = findReusableFd(zName, flags); if( pUnused ){ fd = pUnused->fd; }else{ pUnused = sqlite3_malloc64(sizeof(*pUnused)); if( !pUnused ){ return SQLITE_NOMEM_BKPT; } } p->pPreallocatedUnused = pUnused; /* Database filenames are double-zero terminated if they are not ** URIs with parameters. Hence, they can always be passed into ** sqlite3_uri_parameter(). */ assert( (flags & SQLITE_OPEN_URI) || zName[strlen(zName)+1]==0 ); }else if( !zName ){ /* If zName is NULL, the upper layer is requesting a temp file. */ assert(isDelete && !isNewJrnl); rc = unixGetTempname(pVfs->mxPathname, zTmpname); if( rc!=SQLITE_OK ){ return rc; } zName = zTmpname; /* Generated temporary filenames are always double-zero terminated ** for use by sqlite3_uri_parameter(). */ assert( zName[strlen(zName)+1]==0 ); } /* Determine the value of the flags parameter passed to POSIX function ** open(). These must be calculated even if open() is not called, as ** they may be stored as part of the file handle and used by the ** 'conch file' locking functions later on. */ if( isReadonly ) openFlags |= O_RDONLY; if( isReadWrite ) openFlags |= O_RDWR; if( isCreate ) openFlags |= O_CREAT; if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW); openFlags |= (O_LARGEFILE|O_BINARY|O_NOFOLLOW); if( fd<0 ){ mode_t openMode; /* Permissions to create file with */ uid_t uid; /* Userid for the file */ gid_t gid; /* Groupid for the file */ rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid); if( rc!=SQLITE_OK ){ assert( !p->pPreallocatedUnused ); assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL ); return rc; } fd = robust_open(zName, openFlags, openMode); OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags)); assert( !isExclusive || (openFlags & O_CREAT)!=0 ); if( fd<0 ){ if( isNewJrnl && errno==EACCES && osAccess(zName, F_OK) ){ /* If unable to create a journal because the directory is not ** writable, change the error code to indicate that. */ rc = SQLITE_READONLY_DIRECTORY; }else if( errno!=EISDIR && isReadWrite ){ /* Failed to open the file for read/write access. Try read-only. */ flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); openFlags &= ~(O_RDWR|O_CREAT); flags |= SQLITE_OPEN_READONLY; openFlags |= O_RDONLY; isReadonly = 1; fd = robust_open(zName, openFlags, openMode); } } if( fd<0 ){ int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); if( rc==SQLITE_OK ) rc = rc2; goto open_finished; } /* The owner of the rollback journal or WAL file should always be the ** same as the owner of the database file. Try to ensure that this is ** the case. The chown() system call will be a no-op if the current ** process lacks root privileges, be we should at least try. Without ** this step, if a root process opens a database file, it can leave ** behinds a journal/WAL that is owned by root and hence make the ** database inaccessible to unprivileged processes. ** ** If openMode==0, then that means uid and gid are not set correctly ** (probably because SQLite is configured to use 8+3 filename mode) and ** in that case we do not want to attempt the chown(). */ if( openMode && (flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL))!=0 ){ robustFchown(fd, uid, gid); } } assert( fd>=0 ); if( pOutFlags ){ *pOutFlags = flags; } if( p->pPreallocatedUnused ){ p->pPreallocatedUnused->fd = fd; p->pPreallocatedUnused->flags = flags & (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE); } if( isDelete ){ #if OS_VXWORKS zPath = zName; #elif defined(SQLITE_UNLINK_AFTER_CLOSE) zPath = sqlite3_mprintf("%s", zName); if( zPath==0 ){ robust_close(p, fd, __LINE__); return SQLITE_NOMEM_BKPT; } #else osUnlink(zName); #endif } #if SQLITE_ENABLE_LOCKING_STYLE else{ p->openFlags = openFlags; } #endif #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE if( fstatfs(fd, &fsInfo) == -1 ){ storeLastErrno(p, errno); robust_close(p, fd, __LINE__); return SQLITE_IOERR_ACCESS; } if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; } if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) { ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; } #endif /* Set up appropriate ctrlFlags */ if( isDelete ) ctrlFlags |= UNIXFILE_DELETE; if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY; noLock = eType!=SQLITE_OPEN_MAIN_DB; if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK; if( isNewJrnl ) ctrlFlags |= UNIXFILE_DIRSYNC; if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI; #if SQLITE_ENABLE_LOCKING_STYLE #if SQLITE_PREFER_PROXY_LOCKING isAutoProxy = 1; #endif if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){ char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING"); int useProxy = 0; /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means ** never use proxy, NULL means use proxy for non-local files only. */ if( envforce!=NULL ){ useProxy = atoi(envforce)>0; }else{ useProxy = !(fsInfo.f_flags&MNT_LOCAL); } if( useProxy ){ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); if( rc==SQLITE_OK ){ rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); if( rc!=SQLITE_OK ){ /* Use unixClose to clean up the resources added in fillInUnixFile ** and clear all the structure's references. Specifically, ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op */ unixClose(pFile); return rc; } } goto open_finished; } } #endif assert( zPath==0 || zPath[0]=='/' || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL ); rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); open_finished: if( rc!=SQLITE_OK ){ sqlite3_free(p->pPreallocatedUnused); } return rc; } /* ** Delete the file at zPath. If the dirSync argument is true, fsync() ** the directory after deleting the file. */ static int unixDelete( sqlite3_vfs *NotUsed, /* VFS containing this as the xDelete method */ const char *zPath, /* Name of file to be deleted */ int dirSync /* If true, fsync() directory after deleting file */ ){ int rc = SQLITE_OK; UNUSED_PARAMETER(NotUsed); SimulateIOError(return SQLITE_IOERR_DELETE); if( osUnlink(zPath)==(-1) ){ if( errno==ENOENT #if OS_VXWORKS || osAccess(zPath,0)!=0 #endif ){ rc = SQLITE_IOERR_DELETE_NOENT; }else{ rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); } return rc; } #ifndef SQLITE_DISABLE_DIRSYNC if( (dirSync & 1)!=0 ){ int fd; rc = osOpenDirectory(zPath, &fd); if( rc==SQLITE_OK ){ if( full_fsync(fd,0,0) ){ rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); } robust_close(0, fd, __LINE__); }else{ assert( rc==SQLITE_CANTOPEN ); rc = SQLITE_OK; } } #endif return rc; } /* ** Test the existence of or access permissions of file zPath. The ** test performed depends on the value of flags: ** ** SQLITE_ACCESS_EXISTS: Return 1 if the file exists ** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable. ** SQLITE_ACCESS_READONLY: Return 1 if the file is readable. ** ** Otherwise return 0. */ static int unixAccess( sqlite3_vfs *NotUsed, /* The VFS containing this xAccess method */ const char *zPath, /* Path of the file to examine */ int flags, /* What do we want to learn about the zPath file? */ int *pResOut /* Write result boolean here */ ){ UNUSED_PARAMETER(NotUsed); SimulateIOError( return SQLITE_IOERR_ACCESS; ); assert( pResOut!=0 ); /* The spec says there are three possible values for flags. But only ** two of them are actually used */ assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE ); if( flags==SQLITE_ACCESS_EXISTS ){ struct stat buf; *pResOut = 0==osStat(zPath, &buf) && (!S_ISREG(buf.st_mode) || buf.st_size>0); }else{ *pResOut = osAccess(zPath, W_OK|R_OK)==0; } return SQLITE_OK; } /* ** A pathname under construction */ typedef struct DbPath DbPath; struct DbPath { int rc; /* Non-zero following any error */ int nSymlink; /* Number of symlinks resolved */ char *zOut; /* Write the pathname here */ int nOut; /* Bytes of space available to zOut[] */ int nUsed; /* Bytes of zOut[] currently being used */ }; /* Forward reference */ static void appendAllPathElements(DbPath*,const char*); /* ** Append a single path element to the DbPath under construction */ static void appendOnePathElement( DbPath *pPath, /* Path under construction, to which to append zName */ const char *zName, /* Name to append to pPath. Not zero-terminated */ int nName /* Number of significant bytes in zName */ ){ assert( nName>0 ); assert( zName!=0 ); if( zName[0]=='.' ){ if( nName==1 ) return; if( zName[1]=='.' && nName==2 ){ if( pPath->nUsed>1 ){ assert( pPath->zOut[0]=='/' ); while( pPath->zOut[--pPath->nUsed]!='/' ){} } return; } } if( pPath->nUsed + nName + 2 >= pPath->nOut ){ pPath->rc = SQLITE_ERROR; return; } pPath->zOut[pPath->nUsed++] = '/'; memcpy(&pPath->zOut[pPath->nUsed], zName, nName); pPath->nUsed += nName; #if defined(HAVE_READLINK) && defined(HAVE_LSTAT) if( pPath->rc==SQLITE_OK ){ const char *zIn; struct stat buf; pPath->zOut[pPath->nUsed] = 0; zIn = pPath->zOut; if( osLstat(zIn, &buf)!=0 ){ if( errno!=ENOENT ){ pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); } }else if( S_ISLNK(buf.st_mode) ){ ssize_t got; char zLnk[SQLITE_MAX_PATHLEN+2]; if( pPath->nSymlink++ > SQLITE_MAX_SYMLINK ){ pPath->rc = SQLITE_CANTOPEN_BKPT; return; } got = osReadlink(zIn, zLnk, sizeof(zLnk)-2); if( got<=0 || got>=(ssize_t)sizeof(zLnk)-2 ){ pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); return; } zLnk[got] = 0; if( zLnk[0]=='/' ){ pPath->nUsed = 0; }else{ pPath->nUsed -= nName + 1; } appendAllPathElements(pPath, zLnk); } } #endif } /* ** Append all path elements in zPath to the DbPath under construction. */ static void appendAllPathElements( DbPath *pPath, /* Path under construction, to which to append zName */ const char *zPath /* Path to append to pPath. Is zero-terminated */ ){ int i = 0; int j = 0; do{ while( zPath[i] && zPath[i]!='/' ){ i++; } if( i>j ){ appendOnePathElement(pPath, &zPath[j], i-j); } j = i+1; }while( zPath[i++] ); } /* ** Turn a relative pathname into a full pathname. The relative path ** is stored as a nul-terminated string in the buffer pointed to by ** zPath. ** ** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes ** (in this case, MAX_PATHNAME bytes). The full-path is written to ** this buffer before returning. */ static int unixFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zPath, /* Possibly relative input path */ int nOut, /* Size of output buffer in bytes */ char *zOut /* Output buffer */ ){ DbPath path; UNUSED_PARAMETER(pVfs); path.rc = 0; path.nUsed = 0; path.nSymlink = 0; path.nOut = nOut; path.zOut = zOut; if( zPath[0]!='/' ){ char zPwd[SQLITE_MAX_PATHLEN+2]; if( osGetcwd(zPwd, sizeof(zPwd)-2)==0 ){ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); } appendAllPathElements(&path, zPwd); } appendAllPathElements(&path, zPath); zOut[path.nUsed] = 0; if( path.rc || path.nUsed<2 ) return SQLITE_CANTOPEN_BKPT; if( path.nSymlink ) return SQLITE_OK_SYMLINK; return SQLITE_OK; } #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Interfaces for opening a shared library, finding entry points ** within the shared library, and closing the shared library. */ #include static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){ UNUSED_PARAMETER(NotUsed); return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL); } /* ** SQLite calls this function immediately after a call to unixDlSym() or ** unixDlOpen() fails (returns a null pointer). If a more detailed error ** message is available, it is written to zBufOut. If no error message ** is available, zBufOut is left unmodified and SQLite uses a default ** error message. */ static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){ const char *zErr; UNUSED_PARAMETER(NotUsed); unixEnterMutex(); zErr = dlerror(); if( zErr ){ sqlite3_snprintf(nBuf, zBufOut, "%s", zErr); } unixLeaveMutex(); } static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){ /* ** GCC with -pedantic-errors says that C90 does not allow a void* to be ** cast into a pointer to a function. And yet the library dlsym() routine ** returns a void* which is really a pointer to a function. So how do we ** use dlsym() with -pedantic-errors? ** ** Variable x below is defined to be a pointer to a function taking ** parameters void* and const char* and returning a pointer to a function. ** We initialize x by assigning it a pointer to the dlsym() function. ** (That assignment requires a cast.) Then we call the function that ** x points to. ** ** This work-around is unlikely to work correctly on any system where ** you really cannot cast a function pointer into void*. But then, on the ** other hand, dlsym() will not work on such a system either, so we have ** not really lost anything. */ void (*(*x)(void*,const char*))(void); UNUSED_PARAMETER(NotUsed); x = (void(*(*)(void*,const char*))(void))dlsym; return (*x)(p, zSym); } static void unixDlClose(sqlite3_vfs *NotUsed, void *pHandle){ UNUSED_PARAMETER(NotUsed); dlclose(pHandle); } #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ #define unixDlOpen 0 #define unixDlError 0 #define unixDlSym 0 #define unixDlClose 0 #endif /* ** Write nBuf bytes of random data to the supplied buffer zBuf. */ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){ UNUSED_PARAMETER(NotUsed); assert((size_t)nBuf>=(sizeof(time_t)+sizeof(int))); /* We have to initialize zBuf to prevent valgrind from reporting ** errors. The reports issued by valgrind are incorrect - we would ** prefer that the randomness be increased by making use of the ** uninitialized space in zBuf - but valgrind errors tend to worry ** some users. Rather than argue, it seems easier just to initialize ** the whole array and silence valgrind, even if that means less randomness ** in the random seed. ** ** When testing, initializing zBuf[] to zero is all we do. That means ** that we always use the same random number sequence. This makes the ** tests repeatable. */ memset(zBuf, 0, nBuf); randomnessPid = osGetpid(0); #if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) { int fd, got; fd = robust_open("/dev/urandom", O_RDONLY, 0); if( fd<0 ){ time_t t; time(&t); memcpy(zBuf, &t, sizeof(t)); memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid)); assert( sizeof(t)+sizeof(randomnessPid)<=(size_t)nBuf ); nBuf = sizeof(t) + sizeof(randomnessPid); }else{ do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR ); robust_close(0, fd, __LINE__); } } #endif return nBuf; } /* ** Sleep for a little while. Return the amount of time slept. ** The argument is the number of microseconds we want to sleep. ** The return value is the number of microseconds of sleep actually ** requested from the underlying operating system, a number which ** might be greater than or equal to the argument, but not less ** than the argument. */ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ #if !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP+0 struct timespec sp; sp.tv_sec = microseconds / 1000000; sp.tv_nsec = (microseconds % 1000000) * 1000; /* Almost all modern unix systems support nanosleep(). But if you are ** compiling for one of the rare exceptions, you can use ** -DHAVE_NANOSLEEP=0 (perhaps in conjuction with -DHAVE_USLEEP if ** usleep() is available) in order to bypass the use of nanosleep() */ nanosleep(&sp, NULL); UNUSED_PARAMETER(NotUsed); return microseconds; #elif defined(HAVE_USLEEP) && HAVE_USLEEP if( microseconds>=1000000 ) sleep(microseconds/1000000); if( microseconds%1000000 ) usleep(microseconds%1000000); UNUSED_PARAMETER(NotUsed); return microseconds; #else int seconds = (microseconds+999999)/1000000; sleep(seconds); UNUSED_PARAMETER(NotUsed); return seconds*1000000; #endif } /* ** The following variable, if set to a non-zero value, is interpreted as ** the number of seconds since 1970 and is used to set the result of ** sqlite3OsCurrentTime() during testing. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ #endif /* ** Find the current time (in Universal Coordinated Time). Write into *piNow ** the current time and date as a Julian Day number times 86_400_000. In ** other words, write into *piNow the number of milliseconds since the Julian ** epoch of noon in Greenwich on November 24, 4714 B.C according to the ** proleptic Gregorian calendar. ** ** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date ** cannot be found. */ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; int rc = SQLITE_OK; #if defined(NO_GETTOD) time_t t; time(&t); *piNow = ((sqlite3_int64)t)*1000 + unixEpoch; #elif OS_VXWORKS struct timespec sNow; clock_gettime(CLOCK_REALTIME, &sNow); *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000; #else struct timeval sNow; (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; #endif #ifdef SQLITE_TEST if( sqlite3_current_time ){ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch; } #endif UNUSED_PARAMETER(NotUsed); return rc; } #ifndef SQLITE_OMIT_DEPRECATED /* ** Find the current time (in Universal Coordinated Time). Write the ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){ sqlite3_int64 i = 0; int rc; UNUSED_PARAMETER(NotUsed); rc = unixCurrentTimeInt64(0, &i); *prNow = i/86400000.0; return rc; } #else # define unixCurrentTime 0 #endif /* ** The xGetLastError() method is designed to return a better ** low-level error message when operating-system problems come up ** during SQLite operation. Only the integer return code is currently ** used. */ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ UNUSED_PARAMETER(NotUsed); UNUSED_PARAMETER(NotUsed2); UNUSED_PARAMETER(NotUsed3); return errno; } /* ************************ End of sqlite3_vfs methods *************************** ******************************************************************************/ /****************************************************************************** ************************** Begin Proxy Locking ******************************** ** ** Proxy locking is a "uber-locking-method" in this sense: It uses the ** other locking methods on secondary lock files. Proxy locking is a ** meta-layer over top of the primitive locking implemented above. For ** this reason, the division that implements of proxy locking is deferred ** until late in the file (here) after all of the other I/O methods have ** been defined - so that the primitive locking methods are available ** as services to help with the implementation of proxy locking. ** **** ** ** The default locking schemes in SQLite use byte-range locks on the ** database file to coordinate safe, concurrent access by multiple readers ** and writers [http://sqlite.org/lockingv3.html]. The five file locking ** states (UNLOCKED, PENDING, SHARED, RESERVED, EXCLUSIVE) are implemented ** as POSIX read & write locks over fixed set of locations (via fsctl), ** on AFP and SMB only exclusive byte-range locks are available via fsctl ** with _IOWR('z', 23, struct ByteRangeLockPB2) to track the same 5 states. ** To simulate a F_RDLCK on the shared range, on AFP a randomly selected ** address in the shared range is taken for a SHARED lock, the entire ** shared range is taken for an EXCLUSIVE lock): ** ** PENDING_BYTE 0x40000000 ** RESERVED_BYTE 0x40000001 ** SHARED_RANGE 0x40000002 -> 0x40000200 ** ** This works well on the local file system, but shows a nearly 100x ** slowdown in read performance on AFP because the AFP client disables ** the read cache when byte-range locks are present. Enabling the read ** cache exposes a cache coherency problem that is present on all OS X ** supported network file systems. NFS and AFP both observe the ** close-to-open semantics for ensuring cache coherency ** [http://nfs.sourceforge.net/#faq_a8], which does not effectively ** address the requirements for concurrent database access by multiple ** readers and writers ** [http://www.nabble.com/SQLite-on-NFS-cache-coherency-td15655701.html]. ** ** To address the performance and cache coherency issues, proxy file locking ** changes the way database access is controlled by limiting access to a ** single host at a time and moving file locks off of the database file ** and onto a proxy file on the local file system. ** ** ** Using proxy locks ** ----------------- ** ** C APIs ** ** sqlite3_file_control(db, dbname, SQLITE_FCNTL_SET_LOCKPROXYFILE, ** | ":auto:"); ** sqlite3_file_control(db, dbname, SQLITE_FCNTL_GET_LOCKPROXYFILE, ** &); ** ** ** SQL pragmas ** ** PRAGMA [database.]lock_proxy_file= | :auto: ** PRAGMA [database.]lock_proxy_file ** ** Specifying ":auto:" means that if there is a conch file with a matching ** host ID in it, the proxy path in the conch file will be used, otherwise ** a proxy path based on the user's temp dir ** (via confstr(_CS_DARWIN_USER_TEMP_DIR,...)) will be used and the ** actual proxy file name is generated from the name and path of the ** database file. For example: ** ** For database path "/Users/me/foo.db" ** The lock path will be "/sqliteplocks/_Users_me_foo.db:auto:") ** ** Once a lock proxy is configured for a database connection, it can not ** be removed, however it may be switched to a different proxy path via ** the above APIs (assuming the conch file is not being held by another ** connection or process). ** ** ** How proxy locking works ** ----------------------- ** ** Proxy file locking relies primarily on two new supporting files: ** ** * conch file to limit access to the database file to a single host ** at a time ** ** * proxy file to act as a proxy for the advisory locks normally ** taken on the database ** ** The conch file - to use a proxy file, sqlite must first "hold the conch" ** by taking an sqlite-style shared lock on the conch file, reading the ** contents and comparing the host's unique host ID (see below) and lock ** proxy path against the values stored in the conch. The conch file is ** stored in the same directory as the database file and the file name ** is patterned after the database file name as ".-conch". ** If the conch file does not exist, or its contents do not match the ** host ID and/or proxy path, then the lock is escalated to an exclusive ** lock and the conch file contents is updated with the host ID and proxy ** path and the lock is downgraded to a shared lock again. If the conch ** is held by another process (with a shared lock), the exclusive lock ** will fail and SQLITE_BUSY is returned. ** ** The proxy file - a single-byte file used for all advisory file locks ** normally taken on the database file. This allows for safe sharing ** of the database file for multiple readers and writers on the same ** host (the conch ensures that they all use the same local lock file). ** ** Requesting the lock proxy does not immediately take the conch, it is ** only taken when the first request to lock database file is made. ** This matches the semantics of the traditional locking behavior, where ** opening a connection to a database file does not take a lock on it. ** The shared lock and an open file descriptor are maintained until ** the connection to the database is closed. ** ** The proxy file and the lock file are never deleted so they only need ** to be created the first time they are used. ** ** Configuration options ** --------------------- ** ** SQLITE_PREFER_PROXY_LOCKING ** ** Database files accessed on non-local file systems are ** automatically configured for proxy locking, lock files are ** named automatically using the same logic as ** PRAGMA lock_proxy_file=":auto:" ** ** SQLITE_PROXY_DEBUG ** ** Enables the logging of error messages during host id file ** retrieval and creation ** ** LOCKPROXYDIR ** ** Overrides the default directory used for lock proxy files that ** are named automatically via the ":auto:" setting ** ** SQLITE_DEFAULT_PROXYDIR_PERMISSIONS ** ** Permissions to use when creating a directory for storing the ** lock proxy files, only used when LOCKPROXYDIR is not set. ** ** ** As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING, ** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will ** force proxy locking to be used for every database file opened, and 0 ** will force automatic proxy locking to be disabled for all database ** files (explicitly calling the SQLITE_FCNTL_SET_LOCKPROXYFILE pragma or ** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING). */ /* ** Proxy locking is only available on MacOSX */ #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE /* ** The proxyLockingContext has the path and file structures for the remote ** and local proxy files in it */ typedef struct proxyLockingContext proxyLockingContext; struct proxyLockingContext { unixFile *conchFile; /* Open conch file */ char *conchFilePath; /* Name of the conch file */ unixFile *lockProxy; /* Open proxy lock file */ char *lockProxyPath; /* Name of the proxy lock file */ char *dbPath; /* Name of the open file */ int conchHeld; /* 1 if the conch is held, -1 if lockless */ int nFails; /* Number of conch taking failures */ void *oldLockingContext; /* Original lockingcontext to restore on close */ sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */ }; /* ** The proxy lock file path for the database at dbPath is written into lPath, ** which must point to valid, writable memory large enough for a maxLen length ** file path. */ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ int len; int dbLen; int i; #ifdef LOCKPROXYDIR len = strlcpy(lPath, LOCKPROXYDIR, maxLen); #else # ifdef _CS_DARWIN_USER_TEMP_DIR { if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", lPath, errno, osGetpid(0))); return SQLITE_IOERR_LOCK; } len = strlcat(lPath, "sqliteplocks", maxLen); } # else len = strlcpy(lPath, "/tmp/", maxLen); # endif #endif if( lPath[len-1]!='/' ){ len = strlcat(lPath, "/", maxLen); } /* transform the db path to a unique cache name */ dbLen = (int)strlen(dbPath); for( i=0; i 0) ){ /* only mkdir if leaf dir != "." or "/" or ".." */ if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/') || (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){ buf[i]='\0'; if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ int err=errno; if( err!=EEXIST ) { OSTRACE(("CREATELOCKPATH FAILED creating %s, " "'%s' proxy lock path=%s pid=%d\n", buf, strerror(err), lockPath, osGetpid(0))); return err; } } } start=i+1; } buf[i] = lockPath[i]; } OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n",lockPath,osGetpid(0))); return 0; } /* ** Create a new VFS file descriptor (stored in memory obtained from ** sqlite3_malloc) and open the file named "path" in the file descriptor. ** ** The caller is responsible not only for closing the file descriptor ** but also for freeing the memory associated with the file descriptor. */ static int proxyCreateUnixFile( const char *path, /* path for the new unixFile */ unixFile **ppFile, /* unixFile created and returned by ref */ int islockfile /* if non zero missing dirs will be created */ ) { int fd = -1; unixFile *pNew; int rc = SQLITE_OK; int openFlags = O_RDWR | O_CREAT | O_NOFOLLOW; sqlite3_vfs dummyVfs; int terrno = 0; UnixUnusedFd *pUnused = NULL; /* 1. first try to open/create the file ** 2. if that fails, and this is a lock file (not-conch), try creating ** the parent directories and then try again. ** 3. if that fails, try to open the file read-only ** otherwise return BUSY (if lock file) or CANTOPEN for the conch file */ pUnused = findReusableFd(path, openFlags); if( pUnused ){ fd = pUnused->fd; }else{ pUnused = sqlite3_malloc64(sizeof(*pUnused)); if( !pUnused ){ return SQLITE_NOMEM_BKPT; } } if( fd<0 ){ fd = robust_open(path, openFlags, 0); terrno = errno; if( fd<0 && errno==ENOENT && islockfile ){ if( proxyCreateLockPath(path) == SQLITE_OK ){ fd = robust_open(path, openFlags, 0); } } } if( fd<0 ){ openFlags = O_RDONLY | O_NOFOLLOW; fd = robust_open(path, openFlags, 0); terrno = errno; } if( fd<0 ){ if( islockfile ){ return SQLITE_BUSY; } switch (terrno) { case EACCES: return SQLITE_PERM; case EIO: return SQLITE_IOERR_LOCK; /* even though it is the conch */ default: return SQLITE_CANTOPEN_BKPT; } } pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew)); if( pNew==NULL ){ rc = SQLITE_NOMEM_BKPT; goto end_create_proxy; } memset(pNew, 0, sizeof(unixFile)); pNew->openFlags = openFlags; memset(&dummyVfs, 0, sizeof(dummyVfs)); dummyVfs.pAppData = (void*)&autolockIoFinder; dummyVfs.zName = "dummy"; pUnused->fd = fd; pUnused->flags = openFlags; pNew->pPreallocatedUnused = pUnused; rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0); if( rc==SQLITE_OK ){ *ppFile = pNew; return SQLITE_OK; } end_create_proxy: robust_close(pNew, fd, __LINE__); sqlite3_free(pNew); sqlite3_free(pUnused); return rc; } #ifdef SQLITE_TEST /* simulate multiple hosts by creating unique hostid file paths */ SQLITE_API int sqlite3_hostid_num = 0; #endif #define PROXY_HOSTIDLEN 16 /* conch file host id length */ #if HAVE_GETHOSTUUID /* Not always defined in the headers as it ought to be */ extern int gethostuuid(uuid_t id, const struct timespec *wait); #endif /* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN ** bytes of writable memory. */ static int proxyGetHostID(unsigned char *pHostID, int *pError){ assert(PROXY_HOSTIDLEN == sizeof(uuid_t)); memset(pHostID, 0, PROXY_HOSTIDLEN); #if HAVE_GETHOSTUUID { struct timespec timeout = {1, 0}; /* 1 sec timeout */ if( gethostuuid(pHostID, &timeout) ){ int err = errno; if( pError ){ *pError = err; } return SQLITE_IOERR; } } #else UNUSED_PARAMETER(pError); #endif #ifdef SQLITE_TEST /* simulate multiple hosts by creating unique hostid file paths */ if( sqlite3_hostid_num != 0){ pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF)); } #endif return SQLITE_OK; } /* The conch file contains the header, host id and lock file path */ #define PROXY_CONCHVERSION 2 /* 1-byte header, 16-byte host id, path */ #define PROXY_HEADERLEN 1 /* conch file header length */ #define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN) #define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN) /* ** Takes an open conch file, copies the contents to a new path and then moves ** it back. The newly created file's file descriptor is assigned to the ** conch file structure and finally the original conch file descriptor is ** closed. Returns zero if successful. */ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *conchFile = pCtx->conchFile; char tPath[MAXPATHLEN]; char buf[PROXY_MAXCONCHLEN]; char *cPath = pCtx->conchFilePath; size_t readLen = 0; size_t pathLen = 0; char errmsg[64] = ""; int fd = -1; int rc = -1; UNUSED_PARAMETER(myHostID); /* create a new path by replace the trailing '-conch' with '-break' */ pathLen = strlcpy(tPath, cPath, MAXPATHLEN); if( pathLen>MAXPATHLEN || pathLen<6 || (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){ sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen); goto end_breaklock; } /* read the conch content */ readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0); if( readLenh, __LINE__); conchFile->h = fd; conchFile->openFlags = O_RDWR | O_CREAT; end_breaklock: if( rc ){ if( fd>=0 ){ osUnlink(tPath); robust_close(pFile, fd, __LINE__); } fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg); } return rc; } /* Take the requested lock on the conch file and break a stale lock if the ** host id matches. */ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *conchFile = pCtx->conchFile; int rc = SQLITE_OK; int nTries = 0; struct timespec conchModTime; memset(&conchModTime, 0, sizeof(conchModTime)); do { rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); nTries ++; if( rc==SQLITE_BUSY ){ /* If the lock failed (busy): * 1st try: get the mod time of the conch, wait 0.5s and try again. * 2nd try: fail if the mod time changed or host id is different, wait * 10 sec and try again * 3rd try: break the lock unless the mod time has changed. */ struct stat buf; if( osFstat(conchFile->h, &buf) ){ storeLastErrno(pFile, errno); return SQLITE_IOERR_LOCK; } if( nTries==1 ){ conchModTime = buf.st_mtimespec; unixSleep(0,500000); /* wait 0.5 sec and try the lock again*/ continue; } assert( nTries>1 ); if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){ return SQLITE_BUSY; } if( nTries==2 ){ char tBuf[PROXY_MAXCONCHLEN]; int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); if( len<0 ){ storeLastErrno(pFile, errno); return SQLITE_IOERR_LOCK; } if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){ /* don't break the lock if the host id doesn't match */ if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){ return SQLITE_BUSY; } }else{ /* don't break the lock on short read or a version mismatch */ return SQLITE_BUSY; } unixSleep(0,10000000); /* wait 10 sec and try the lock again */ continue; } assert( nTries==3 ); if( 0==proxyBreakConchLock(pFile, myHostID) ){ rc = SQLITE_OK; if( lockType==EXCLUSIVE_LOCK ){ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK); } if( !rc ){ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); } } } } while( rc==SQLITE_BUSY && nTries<3 ); return rc; } /* Takes the conch by taking a shared lock and read the contents conch, if ** lockPath is non-NULL, the host ID and lock file path must match. A NULL ** lockPath means that the lockPath in the conch file will be used if the ** host IDs match, or a new lock path will be generated automatically ** and written to the conch file. */ static int proxyTakeConch(unixFile *pFile){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; if( pCtx->conchHeld!=0 ){ return SQLITE_OK; }else{ unixFile *conchFile = pCtx->conchFile; uuid_t myHostID; int pError = 0; char readBuf[PROXY_MAXCONCHLEN]; char lockPath[MAXPATHLEN]; char *tempLockPath = NULL; int rc = SQLITE_OK; int createConch = 0; int hostIdMatch = 0; int readLen = 0; int tryOldLockPath = 0; int forceNewLockPath = 0; OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h, (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), osGetpid(0))); rc = proxyGetHostID(myHostID, &pError); if( (rc&0xff)==SQLITE_IOERR ){ storeLastErrno(pFile, pError); goto end_takeconch; } rc = proxyConchLock(pFile, myHostID, SHARED_LOCK); if( rc!=SQLITE_OK ){ goto end_takeconch; } /* read the existing conch file */ readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN); if( readLen<0 ){ /* I/O error: lastErrno set by seekAndRead */ storeLastErrno(pFile, conchFile->lastErrno); rc = SQLITE_IOERR_READ; goto end_takeconch; }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || readBuf[0]!=(char)PROXY_CONCHVERSION ){ /* a short read or version format mismatch means we need to create a new ** conch file. */ createConch = 1; } /* if the host id matches and the lock path already exists in the conch ** we'll try to use the path there, if we can't open that path, we'll ** retry with a new auto-generated path */ do { /* in case we need to try again for an :auto: named lock file */ if( !createConch && !forceNewLockPath ){ hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN); /* if the conch has data compare the contents */ if( !pCtx->lockProxyPath ){ /* for auto-named local lock file, just check the host ID and we'll ** use the local lock file path that's already in there */ if( hostIdMatch ){ size_t pathLen = (readLen - PROXY_PATHINDEX); if( pathLen>=MAXPATHLEN ){ pathLen=MAXPATHLEN-1; } memcpy(lockPath, &readBuf[PROXY_PATHINDEX], pathLen); lockPath[pathLen] = 0; tempLockPath = lockPath; tryOldLockPath = 1; /* create a copy of the lock path if the conch is taken */ goto end_takeconch; } }else if( hostIdMatch && !strncmp(pCtx->lockProxyPath, &readBuf[PROXY_PATHINDEX], readLen-PROXY_PATHINDEX) ){ /* conch host and lock path match */ goto end_takeconch; } } /* if the conch isn't writable and doesn't match, we can't take it */ if( (conchFile->openFlags&O_RDWR) == 0 ){ rc = SQLITE_BUSY; goto end_takeconch; } /* either the conch didn't match or we need to create a new one */ if( !pCtx->lockProxyPath ){ proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN); tempLockPath = lockPath; /* create a copy of the lock path _only_ if the conch is taken */ } /* update conch with host and path (this will fail if other process ** has a shared lock already), if the host id matches, use the big ** stick. */ futimes(conchFile->h, NULL); if( hostIdMatch && !createConch ){ if( conchFile->pInode && conchFile->pInode->nShared>1 ){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; } else { rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK); } }else{ rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK); } if( rc==SQLITE_OK ){ char writeBuffer[PROXY_MAXCONCHLEN]; int writeSize = 0; writeBuffer[0] = (char)PROXY_CONCHVERSION; memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN); if( pCtx->lockProxyPath!=NULL ){ strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, MAXPATHLEN); }else{ strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN); } writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]); robust_ftruncate(conchFile->h, writeSize); rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0); full_fsync(conchFile->h,0,0); /* If we created a new conch file (not just updated the contents of a ** valid conch file), try to match the permissions of the database */ if( rc==SQLITE_OK && createConch ){ struct stat buf; int err = osFstat(pFile->h, &buf); if( err==0 ){ mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH); /* try to match the database file R/W permissions, ignore failure */ #ifndef SQLITE_PROXY_DEBUG osFchmod(conchFile->h, cmode); #else do{ rc = osFchmod(conchFile->h, cmode); }while( rc==(-1) && errno==EINTR ); if( rc!=0 ){ int code = errno; fprintf(stderr, "fchmod %o FAILED with %d %s\n", cmode, code, strerror(code)); } else { fprintf(stderr, "fchmod %o SUCCEDED\n",cmode); } }else{ int code = errno; fprintf(stderr, "STAT FAILED[%d] with %d %s\n", err, code, strerror(code)); #endif } } } conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK); end_takeconch: OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h)); if( rc==SQLITE_OK && pFile->openFlags ){ int fd; if( pFile->h>=0 ){ robust_close(pFile, pFile->h, __LINE__); } pFile->h = -1; fd = robust_open(pCtx->dbPath, pFile->openFlags, 0); OSTRACE(("TRANSPROXY: OPEN %d\n", fd)); if( fd>=0 ){ pFile->h = fd; }else{ rc=SQLITE_CANTOPEN_BKPT; /* SQLITE_BUSY? proxyTakeConch called during locking */ } } if( rc==SQLITE_OK && !pCtx->lockProxy ){ char *path = tempLockPath ? tempLockPath : pCtx->lockProxyPath; rc = proxyCreateUnixFile(path, &pCtx->lockProxy, 1); if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && tryOldLockPath ){ /* we couldn't create the proxy lock file with the old lock file path ** so try again via auto-naming */ forceNewLockPath = 1; tryOldLockPath = 0; continue; /* go back to the do {} while start point, try again */ } } if( rc==SQLITE_OK ){ /* Need to make a copy of path if we extracted the value ** from the conch file or the path was allocated on the stack */ if( tempLockPath ){ pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath); if( !pCtx->lockProxyPath ){ rc = SQLITE_NOMEM_BKPT; } } } if( rc==SQLITE_OK ){ pCtx->conchHeld = 1; if( pCtx->lockProxy->pMethod == &afpIoMethods ){ afpLockingContext *afpCtx; afpCtx = (afpLockingContext *)pCtx->lockProxy->lockingContext; afpCtx->dbPath = pCtx->lockProxyPath; } } else { conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); } OSTRACE(("TAKECONCH %d %s\n", conchFile->h, rc==SQLITE_OK?"ok":"failed")); return rc; } while (1); /* in case we need to retry the :auto: lock file - ** we should never get here except via the 'continue' call. */ } } /* ** If pFile holds a lock on a conch file, then release that lock. */ static int proxyReleaseConch(unixFile *pFile){ int rc = SQLITE_OK; /* Subroutine return code */ proxyLockingContext *pCtx; /* The locking context for the proxy lock */ unixFile *conchFile; /* Name of the conch file */ pCtx = (proxyLockingContext *)pFile->lockingContext; conchFile = pCtx->conchFile; OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h, (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), osGetpid(0))); if( pCtx->conchHeld>0 ){ rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); } pCtx->conchHeld = 0; OSTRACE(("RELEASECONCH %d %s\n", conchFile->h, (rc==SQLITE_OK ? "ok" : "failed"))); return rc; } /* ** Given the name of a database file, compute the name of its conch file. ** Store the conch filename in memory obtained from sqlite3_malloc64(). ** Make *pConchPath point to the new name. Return SQLITE_OK on success ** or SQLITE_NOMEM if unable to obtain memory. ** ** The caller is responsible for ensuring that the allocated memory ** space is eventually freed. ** ** *pConchPath is set to NULL if a memory allocation error occurs. */ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){ int i; /* Loop counter */ int len = (int)strlen(dbPath); /* Length of database filename - dbPath */ char *conchPath; /* buffer in which to construct conch name */ /* Allocate space for the conch filename and initialize the name to ** the name of the original database file. */ *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8); if( conchPath==0 ){ return SQLITE_NOMEM_BKPT; } memcpy(conchPath, dbPath, len+1); /* now insert a "." before the last / character */ for( i=(len-1); i>=0; i-- ){ if( conchPath[i]=='/' ){ i++; break; } } conchPath[i]='.'; while ( ilockingContext; char *oldPath = pCtx->lockProxyPath; int rc = SQLITE_OK; if( pFile->eFileLock!=NO_LOCK ){ return SQLITE_BUSY; } /* nothing to do if the path is NULL, :auto: or matches the existing path */ if( !path || path[0]=='\0' || !strcmp(path, ":auto:") || (oldPath && !strncmp(oldPath, path, MAXPATHLEN)) ){ return SQLITE_OK; }else{ unixFile *lockProxy = pCtx->lockProxy; pCtx->lockProxy=NULL; pCtx->conchHeld = 0; if( lockProxy!=NULL ){ rc=lockProxy->pMethod->xClose((sqlite3_file *)lockProxy); if( rc ) return rc; sqlite3_free(lockProxy); } sqlite3_free(oldPath); pCtx->lockProxyPath = sqlite3DbStrDup(0, path); } return rc; } /* ** pFile is a file that has been opened by a prior xOpen call. dbPath ** is a string buffer at least MAXPATHLEN+1 characters in size. ** ** This routine find the filename associated with pFile and writes it ** int dbPath. */ static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){ #if defined(__APPLE__) if( pFile->pMethod == &afpIoMethods ){ /* afp style keeps a reference to the db path in the filePath field ** of the struct */ assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, MAXPATHLEN); } else #endif if( pFile->pMethod == &dotlockIoMethods ){ /* dot lock style uses the locking context to store the dot lock ** file path */ int len = strlen((char *)pFile->lockingContext) - strlen(DOTLOCK_SUFFIX); memcpy(dbPath, (char *)pFile->lockingContext, len + 1); }else{ /* all other styles use the locking context to store the db file path */ assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); strlcpy(dbPath, (char *)pFile->lockingContext, MAXPATHLEN); } return SQLITE_OK; } /* ** Takes an already filled in unix file and alters it so all file locking ** will be performed on the local proxy lock file. The following fields ** are preserved in the locking context so that they can be restored and ** the unix structure properly cleaned up at close time: ** ->lockingContext ** ->pMethod */ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { proxyLockingContext *pCtx; char dbPath[MAXPATHLEN+1]; /* Name of the database file */ char *lockPath=NULL; int rc = SQLITE_OK; if( pFile->eFileLock!=NO_LOCK ){ return SQLITE_BUSY; } proxyGetDbPathForUnixFile(pFile, dbPath); if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ){ lockPath=NULL; }else{ lockPath=(char *)path; } OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h, (lockPath ? lockPath : ":auto:"), osGetpid(0))); pCtx = sqlite3_malloc64( sizeof(*pCtx) ); if( pCtx==0 ){ return SQLITE_NOMEM_BKPT; } memset(pCtx, 0, sizeof(*pCtx)); rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath); if( rc==SQLITE_OK ){ rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile, 0); if( rc==SQLITE_CANTOPEN && ((pFile->openFlags&O_RDWR) == 0) ){ /* if (a) the open flags are not O_RDWR, (b) the conch isn't there, and ** (c) the file system is read-only, then enable no-locking access. ** Ugh, since O_RDONLY==0x0000 we test for !O_RDWR since unixOpen asserts ** that openFlags will have only one of O_RDONLY or O_RDWR. */ struct statfs fsInfo; struct stat conchInfo; int goLockless = 0; if( osStat(pCtx->conchFilePath, &conchInfo) == -1 ) { int err = errno; if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){ goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY; } } if( goLockless ){ pCtx->conchHeld = -1; /* read only FS/ lockless */ rc = SQLITE_OK; } } } if( rc==SQLITE_OK && lockPath ){ pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath); } if( rc==SQLITE_OK ){ pCtx->dbPath = sqlite3DbStrDup(0, dbPath); if( pCtx->dbPath==NULL ){ rc = SQLITE_NOMEM_BKPT; } } if( rc==SQLITE_OK ){ /* all memory is allocated, proxys are created and assigned, ** switch the locking context and pMethod then return. */ pCtx->oldLockingContext = pFile->lockingContext; pFile->lockingContext = pCtx; pCtx->pOldMethod = pFile->pMethod; pFile->pMethod = &proxyIoMethods; }else{ if( pCtx->conchFile ){ pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile); sqlite3_free(pCtx->conchFile); } sqlite3DbFree(0, pCtx->lockProxyPath); sqlite3_free(pCtx->conchFilePath); sqlite3_free(pCtx); } OSTRACE(("TRANSPROXY %d %s\n", pFile->h, (rc==SQLITE_OK ? "ok" : "failed"))); return rc; } /* ** This routine handles sqlite3_file_control() calls that are specific ** to proxy locking. */ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){ switch( op ){ case SQLITE_FCNTL_GET_LOCKPROXYFILE: { unixFile *pFile = (unixFile*)id; if( pFile->pMethod == &proxyIoMethods ){ proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; proxyTakeConch(pFile); if( pCtx->lockProxyPath ){ *(const char **)pArg = pCtx->lockProxyPath; }else{ *(const char **)pArg = ":auto: (not held)"; } } else { *(const char **)pArg = NULL; } return SQLITE_OK; } case SQLITE_FCNTL_SET_LOCKPROXYFILE: { unixFile *pFile = (unixFile*)id; int rc = SQLITE_OK; int isProxyStyle = (pFile->pMethod == &proxyIoMethods); if( pArg==NULL || (const char *)pArg==0 ){ if( isProxyStyle ){ /* turn off proxy locking - not supported. If support is added for ** switching proxy locking mode off then it will need to fail if ** the journal mode is WAL mode. */ rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/; }else{ /* turn off proxy locking - already off - NOOP */ rc = SQLITE_OK; } }else{ const char *proxyPath = (const char *)pArg; if( isProxyStyle ){ proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; if( !strcmp(pArg, ":auto:") || (pCtx->lockProxyPath && !strncmp(pCtx->lockProxyPath, proxyPath, MAXPATHLEN)) ){ rc = SQLITE_OK; }else{ rc = switchLockProxyPath(pFile, proxyPath); } }else{ /* turn on proxy file locking */ rc = proxyTransformUnixFile(pFile, proxyPath); } } return rc; } default: { assert( 0 ); /* The call assures that only valid opcodes are sent */ } } /*NOTREACHED*/ assert(0); return SQLITE_ERROR; } /* ** Within this division (the proxying locking implementation) the procedures ** above this point are all utilities. The lock-related methods of the ** proxy-locking sqlite3_io_method object follow. */ /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int proxyCheckReservedLock(sqlite3_file *id, int *pResOut) { unixFile *pFile = (unixFile*)id; int rc = proxyTakeConch(pFile); if( rc==SQLITE_OK ){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; if( pCtx->conchHeld>0 ){ unixFile *proxy = pCtx->lockProxy; return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut); }else{ /* conchHeld < 0 is lockless */ pResOut=0; } } return rc; } /* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK ** (3) PENDING_LOCK ** (4) EXCLUSIVE_LOCK ** ** Sometimes when requesting one lock state, additional lock states ** are inserted in between. The locking might fail on one of the later ** transitions leaving the lock state different from what it started but ** still short of its goal. The following chart shows the allowed ** transitions and the inserted intermediate states: ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED ** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ static int proxyLock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; int rc = proxyTakeConch(pFile); if( rc==SQLITE_OK ){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; if( pCtx->conchHeld>0 ){ unixFile *proxy = pCtx->lockProxy; rc = proxy->pMethod->xLock((sqlite3_file*)proxy, eFileLock); pFile->eFileLock = proxy->eFileLock; }else{ /* conchHeld < 0 is lockless */ } } return rc; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int proxyUnlock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; int rc = proxyTakeConch(pFile); if( rc==SQLITE_OK ){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; if( pCtx->conchHeld>0 ){ unixFile *proxy = pCtx->lockProxy; rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, eFileLock); pFile->eFileLock = proxy->eFileLock; }else{ /* conchHeld < 0 is lockless */ } } return rc; } /* ** Close a file that uses proxy locks. */ static int proxyClose(sqlite3_file *id) { if( ALWAYS(id) ){ unixFile *pFile = (unixFile*)id; proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *lockProxy = pCtx->lockProxy; unixFile *conchFile = pCtx->conchFile; int rc = SQLITE_OK; if( lockProxy ){ rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK); if( rc ) return rc; rc = lockProxy->pMethod->xClose((sqlite3_file*)lockProxy); if( rc ) return rc; sqlite3_free(lockProxy); pCtx->lockProxy = 0; } if( conchFile ){ if( pCtx->conchHeld ){ rc = proxyReleaseConch(pFile); if( rc ) return rc; } rc = conchFile->pMethod->xClose((sqlite3_file*)conchFile); if( rc ) return rc; sqlite3_free(conchFile); } sqlite3DbFree(0, pCtx->lockProxyPath); sqlite3_free(pCtx->conchFilePath); sqlite3DbFree(0, pCtx->dbPath); /* restore the original locking context and pMethod then close it */ pFile->lockingContext = pCtx->oldLockingContext; pFile->pMethod = pCtx->pOldMethod; sqlite3_free(pCtx); return pFile->pMethod->xClose(id); } return SQLITE_OK; } #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ /* ** The proxy locking style is intended for use with AFP filesystems. ** And since AFP is only supported on MacOSX, the proxy locking is also ** restricted to MacOSX. ** ** ******************* End of the proxy lock implementation ********************** ******************************************************************************/ /* ** Initialize the operating system interface. ** ** This routine registers all VFS implementations for unix-like operating ** systems. This routine, and the sqlite3_os_end() routine that follows, ** should be the only routines in this file that are visible from other ** files. ** ** This routine is called once during SQLite initialization and by a ** single thread. The memory allocation and mutex subsystems have not ** necessarily been initialized when this routine is called, and so they ** should not be used. */ SQLITE_API int sqlite3_os_init(void){ /* ** The following macro defines an initializer for an sqlite3_vfs object. ** The name of the VFS is NAME. The pAppData is a pointer to a pointer ** to the "finder" function. (pAppData is a pointer to a pointer because ** silly C90 rules prohibit a void* from being cast to a function pointer ** and so we have to go through the intermediate pointer to avoid problems ** when compiling with -pedantic-errors on GCC.) ** ** The FINDER parameter to this macro is the name of the pointer to the ** finder-function. The finder-function returns a pointer to the ** sqlite_io_methods object that implements the desired locking ** behaviors. See the division above that contains the IOMETHODS ** macro for addition information on finder-functions. ** ** Most finders simply return a pointer to a fixed sqlite3_io_methods ** object. But the "autolockIoFinder" available on MacOSX does a little ** more than that; it looks at the filesystem type that hosts the ** database file and tries to choose an locking method appropriate for ** that filesystem time. */ #define UNIXVFS(VFSNAME, FINDER) { \ 3, /* iVersion */ \ sizeof(unixFile), /* szOsFile */ \ MAX_PATHNAME, /* mxPathname */ \ 0, /* pNext */ \ VFSNAME, /* zName */ \ (void*)&FINDER, /* pAppData */ \ unixOpen, /* xOpen */ \ unixDelete, /* xDelete */ \ unixAccess, /* xAccess */ \ unixFullPathname, /* xFullPathname */ \ unixDlOpen, /* xDlOpen */ \ unixDlError, /* xDlError */ \ unixDlSym, /* xDlSym */ \ unixDlClose, /* xDlClose */ \ unixRandomness, /* xRandomness */ \ unixSleep, /* xSleep */ \ unixCurrentTime, /* xCurrentTime */ \ unixGetLastError, /* xGetLastError */ \ unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \ unixSetSystemCall, /* xSetSystemCall */ \ unixGetSystemCall, /* xGetSystemCall */ \ unixNextSystemCall, /* xNextSystemCall */ \ } /* ** All default VFSes for unix are contained in the following array. ** ** Note that the sqlite3_vfs.pNext field of the VFS object is modified ** by the SQLite core when the VFS is registered. So the following ** array cannot be const. */ static sqlite3_vfs aVfs[] = { #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) UNIXVFS("unix", autolockIoFinder ), #elif OS_VXWORKS UNIXVFS("unix", vxworksIoFinder ), #else UNIXVFS("unix", posixIoFinder ), #endif UNIXVFS("unix-none", nolockIoFinder ), UNIXVFS("unix-dotfile", dotlockIoFinder ), UNIXVFS("unix-excl", posixIoFinder ), #if OS_VXWORKS UNIXVFS("unix-namedsem", semIoFinder ), #endif #if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS UNIXVFS("unix-posix", posixIoFinder ), #endif #if SQLITE_ENABLE_LOCKING_STYLE UNIXVFS("unix-flock", flockIoFinder ), #endif #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) UNIXVFS("unix-afp", afpIoFinder ), UNIXVFS("unix-nfs", nfsIoFinder ), UNIXVFS("unix-proxy", proxyIoFinder ), #endif }; unsigned int i; /* Loop counter */ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==29 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ #ifdef SQLITE_DEFAULT_UNIX_VFS sqlite3_vfs_register(&aVfs[i], 0==strcmp(aVfs[i].zName,SQLITE_DEFAULT_UNIX_VFS)); #else sqlite3_vfs_register(&aVfs[i], i==0); #endif } #ifdef SQLITE_OS_KV_OPTIONAL sqlite3KvvfsInit(); #endif unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); #ifndef SQLITE_OMIT_WAL /* Validate lock assumptions */ assert( SQLITE_SHM_NLOCK==8 ); /* Number of available locks */ assert( UNIX_SHM_BASE==120 ); /* Start of locking area */ /* Locks: ** WRITE UNIX_SHM_BASE 120 ** CKPT UNIX_SHM_BASE+1 121 ** RECOVER UNIX_SHM_BASE+2 122 ** READ-0 UNIX_SHM_BASE+3 123 ** READ-1 UNIX_SHM_BASE+4 124 ** READ-2 UNIX_SHM_BASE+5 125 ** READ-3 UNIX_SHM_BASE+6 126 ** READ-4 UNIX_SHM_BASE+7 127 ** DMS UNIX_SHM_BASE+8 128 */ assert( UNIX_SHM_DMS==128 ); /* Byte offset of the deadman-switch */ #endif /* Initialize temp file dir array. */ unixTempFileInit(); return SQLITE_OK; } /* ** Shutdown the operating system interface. ** ** Some operating systems might need to do some cleanup in this routine, ** to release dynamically allocated objects. But not on unix. ** This routine is a no-op for unix. */ SQLITE_API int sqlite3_os_end(void){ unixBigLock = 0; return SQLITE_OK; } #endif /* SQLITE_OS_UNIX */ /************** End of os_unix.c *********************************************/ /************** Begin file os_win.c ******************************************/ /* ** 2004 May 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to Windows. */ /* #include "sqliteInt.h" */ #if SQLITE_OS_WIN /* This file is used for Windows only */ /* ** Include code that is common to all os_*.c files */ /* #include "os_common.h" */ /* ** Include the header file for the Windows VFS. */ /* #include "os_win.h" */ /* ** Compiling and using WAL mode requires several APIs that are only ** available in Windows platforms based on the NT kernel. */ #if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL) # error "WAL mode requires support from the Windows NT kernel, compile\ with SQLITE_OMIT_WAL." #endif #if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0 # error "Memory mapped files require support from the Windows NT kernel,\ compile with SQLITE_MAX_MMAP_SIZE=0." #endif /* ** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions ** based on the sub-platform)? */ #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(SQLITE_WIN32_NO_ANSI) # define SQLITE_WIN32_HAS_ANSI #endif /* ** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions ** based on the sub-platform)? */ #if (SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT) && \ !defined(SQLITE_WIN32_NO_WIDE) # define SQLITE_WIN32_HAS_WIDE #endif /* ** Make sure at least one set of Win32 APIs is available. */ #if !defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_WIN32_HAS_WIDE) # error "At least one of SQLITE_WIN32_HAS_ANSI and SQLITE_WIN32_HAS_WIDE\ must be defined." #endif /* ** Define the required Windows SDK version constants if they are not ** already available. */ #ifndef NTDDI_WIN8 # define NTDDI_WIN8 0x06020000 #endif #ifndef NTDDI_WINBLUE # define NTDDI_WINBLUE 0x06030000 #endif #ifndef NTDDI_WINTHRESHOLD # define NTDDI_WINTHRESHOLD 0x06040000 #endif /* ** Check to see if the GetVersionEx[AW] functions are deprecated on the ** target system. GetVersionEx was first deprecated in Win8.1. */ #ifndef SQLITE_WIN32_GETVERSIONEX # if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE # define SQLITE_WIN32_GETVERSIONEX 0 /* GetVersionEx() is deprecated */ # else # define SQLITE_WIN32_GETVERSIONEX 1 /* GetVersionEx() is current */ # endif #endif /* ** Check to see if the CreateFileMappingA function is supported on the ** target system. It is unavailable when using "mincore.lib" on Win10. ** When compiling for Windows 10, always assume "mincore.lib" is in use. */ #ifndef SQLITE_WIN32_CREATEFILEMAPPINGA # if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINTHRESHOLD # define SQLITE_WIN32_CREATEFILEMAPPINGA 0 # else # define SQLITE_WIN32_CREATEFILEMAPPINGA 1 # endif #endif /* ** This constant should already be defined (in the "WinDef.h" SDK file). */ #ifndef MAX_PATH # define MAX_PATH (260) #endif /* ** Maximum pathname length (in chars) for Win32. This should normally be ** MAX_PATH. */ #ifndef SQLITE_WIN32_MAX_PATH_CHARS # define SQLITE_WIN32_MAX_PATH_CHARS (MAX_PATH) #endif /* ** This constant should already be defined (in the "WinNT.h" SDK file). */ #ifndef UNICODE_STRING_MAX_CHARS # define UNICODE_STRING_MAX_CHARS (32767) #endif /* ** Maximum pathname length (in chars) for WinNT. This should normally be ** UNICODE_STRING_MAX_CHARS. */ #ifndef SQLITE_WINNT_MAX_PATH_CHARS # define SQLITE_WINNT_MAX_PATH_CHARS (UNICODE_STRING_MAX_CHARS) #endif /* ** Maximum pathname length (in bytes) for Win32. The MAX_PATH macro is in ** characters, so we allocate 4 bytes per character assuming worst-case of ** 4-bytes-per-character for UTF8. */ #ifndef SQLITE_WIN32_MAX_PATH_BYTES # define SQLITE_WIN32_MAX_PATH_BYTES (SQLITE_WIN32_MAX_PATH_CHARS*4) #endif /* ** Maximum pathname length (in bytes) for WinNT. This should normally be ** UNICODE_STRING_MAX_CHARS * sizeof(WCHAR). */ #ifndef SQLITE_WINNT_MAX_PATH_BYTES # define SQLITE_WINNT_MAX_PATH_BYTES \ (sizeof(WCHAR) * SQLITE_WINNT_MAX_PATH_CHARS) #endif /* ** Maximum error message length (in chars) for WinRT. */ #ifndef SQLITE_WIN32_MAX_ERRMSG_CHARS # define SQLITE_WIN32_MAX_ERRMSG_CHARS (1024) #endif /* ** Returns non-zero if the character should be treated as a directory ** separator. */ #ifndef winIsDirSep # define winIsDirSep(a) (((a) == '/') || ((a) == '\\')) #endif /* ** This macro is used when a local variable is set to a value that is ** [sometimes] not used by the code (e.g. via conditional compilation). */ #ifndef UNUSED_VARIABLE_VALUE # define UNUSED_VARIABLE_VALUE(x) (void)(x) #endif /* ** Returns the character that should be used as the directory separator. */ #ifndef winGetDirSep # define winGetDirSep() '\\' #endif /* ** Do we need to manually define the Win32 file mapping APIs for use with WAL ** mode or memory mapped files (e.g. these APIs are available in the Windows ** CE SDK; however, they are not present in the header file)? */ #if SQLITE_WIN32_FILEMAPPING_API && \ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) /* ** Two of the file mapping APIs are different under WinRT. Figure out which ** set we need. */ #if SQLITE_OS_WINRT WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \ LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR); WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T); #else #if defined(SQLITE_WIN32_HAS_ANSI) WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \ DWORD, DWORD, DWORD, LPCSTR); #endif /* defined(SQLITE_WIN32_HAS_ANSI) */ #if defined(SQLITE_WIN32_HAS_WIDE) WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \ DWORD, DWORD, DWORD, LPCWSTR); #endif /* defined(SQLITE_WIN32_HAS_WIDE) */ WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); #endif /* SQLITE_OS_WINRT */ /* ** These file mapping APIs are common to both Win32 and WinRT. */ WINBASEAPI BOOL WINAPI FlushViewOfFile(LPCVOID, SIZE_T); WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); #endif /* SQLITE_WIN32_FILEMAPPING_API */ /* ** Some Microsoft compilers lack this definition. */ #ifndef INVALID_FILE_ATTRIBUTES # define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif #ifndef FILE_FLAG_MASK # define FILE_FLAG_MASK (0xFF3C0000) #endif #ifndef FILE_ATTRIBUTE_MASK # define FILE_ATTRIBUTE_MASK (0x0003FFF7) #endif #ifndef SQLITE_OMIT_WAL /* Forward references to structures used for WAL */ typedef struct winShm winShm; /* A connection to shared-memory */ typedef struct winShmNode winShmNode; /* A region of shared-memory */ #endif /* ** WinCE lacks native support for file locking so we have to fake it ** with some code of our own. */ #if SQLITE_OS_WINCE typedef struct winceLock { int nReaders; /* Number of reader locks obtained */ BOOL bPending; /* Indicates a pending lock has been obtained */ BOOL bReserved; /* Indicates a reserved lock has been obtained */ BOOL bExclusive; /* Indicates an exclusive lock has been obtained */ } winceLock; #endif /* ** The winFile structure is a subclass of sqlite3_file* specific to the win32 ** portability layer. */ typedef struct winFile winFile; struct winFile { const sqlite3_io_methods *pMethod; /*** Must be first ***/ sqlite3_vfs *pVfs; /* The VFS used to open this file */ HANDLE h; /* Handle for accessing the file */ u8 locktype; /* Type of lock currently held on this file */ short sharedLockByte; /* Randomly chosen byte used as a shared lock */ u8 ctrlFlags; /* Flags. See WINFILE_* below */ DWORD lastErrno; /* The Windows errno from the last I/O error */ #ifndef SQLITE_OMIT_WAL winShm *pShm; /* Instance of shared memory on this file */ #endif const char *zPath; /* Full pathname of this file */ int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ #if SQLITE_OS_WINCE LPWSTR zDeleteOnClose; /* Name of file to delete when closing */ HANDLE hMutex; /* Mutex used to control access to shared lock */ HANDLE hShared; /* Shared memory segment used for locking */ winceLock local; /* Locks obtained by this instance of winFile */ winceLock *shared; /* Global shared lock memory for the file */ #endif #if SQLITE_MAX_MMAP_SIZE>0 int nFetchOut; /* Number of outstanding xFetch references */ HANDLE hMap; /* Handle for accessing memory mapping */ void *pMapRegion; /* Area memory mapped */ sqlite3_int64 mmapSize; /* Size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif }; /* ** The winVfsAppData structure is used for the pAppData member for all of the ** Win32 VFS variants. */ typedef struct winVfsAppData winVfsAppData; struct winVfsAppData { const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */ void *pAppData; /* The extra pAppData, if any. */ BOOL bNoLock; /* Non-zero if locking is disabled. */ }; /* ** Allowed values for winFile.ctrlFlags */ #define WINFILE_RDONLY 0x02 /* Connection is read only */ #define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ #define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ /* * The size of the buffer used by sqlite3_win32_write_debug(). */ #ifndef SQLITE_WIN32_DBG_BUF_SIZE # define SQLITE_WIN32_DBG_BUF_SIZE ((int)(4096-sizeof(DWORD))) #endif /* * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the * various Win32 API heap functions instead of our own. */ #ifdef SQLITE_WIN32_MALLOC /* * If this is non-zero, an isolated heap will be created by the native Win32 * allocator subsystem; otherwise, the default process heap will be used. This * setting has no effect when compiling for WinRT. By default, this is enabled * and an isolated heap will be created to store all allocated data. * ****************************************************************************** * WARNING: It is important to note that when this setting is non-zero and the * winMemShutdown function is called (e.g. by the sqlite3_shutdown * function), all data that was allocated using the isolated heap will * be freed immediately and any attempt to access any of that freed * data will almost certainly result in an immediate access violation. ****************************************************************************** */ #ifndef SQLITE_WIN32_HEAP_CREATE # define SQLITE_WIN32_HEAP_CREATE (TRUE) #endif /* * This is the maximum possible initial size of the Win32-specific heap, in * bytes. */ #ifndef SQLITE_WIN32_HEAP_MAX_INIT_SIZE # define SQLITE_WIN32_HEAP_MAX_INIT_SIZE (4294967295U) #endif /* * This is the extra space for the initial size of the Win32-specific heap, * in bytes. This value may be zero. */ #ifndef SQLITE_WIN32_HEAP_INIT_EXTRA # define SQLITE_WIN32_HEAP_INIT_EXTRA (4194304) #endif /* * Calculate the maximum legal cache size, in pages, based on the maximum * possible initial heap size and the default page size, setting aside the * needed extra space. */ #ifndef SQLITE_WIN32_MAX_CACHE_SIZE # define SQLITE_WIN32_MAX_CACHE_SIZE (((SQLITE_WIN32_HEAP_MAX_INIT_SIZE) - \ (SQLITE_WIN32_HEAP_INIT_EXTRA)) / \ (SQLITE_DEFAULT_PAGE_SIZE)) #endif /* * This is cache size used in the calculation of the initial size of the * Win32-specific heap. It cannot be negative. */ #ifndef SQLITE_WIN32_CACHE_SIZE # if SQLITE_DEFAULT_CACHE_SIZE>=0 # define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE) # else # define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE)) # endif #endif /* * Make sure that the calculated cache size, in pages, cannot cause the * initial size of the Win32-specific heap to exceed the maximum amount * of memory that can be specified in the call to HeapCreate. */ #if SQLITE_WIN32_CACHE_SIZE>SQLITE_WIN32_MAX_CACHE_SIZE # undef SQLITE_WIN32_CACHE_SIZE # define SQLITE_WIN32_CACHE_SIZE (2000) #endif /* * The initial size of the Win32-specific heap. This value may be zero. */ #ifndef SQLITE_WIN32_HEAP_INIT_SIZE # define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \ (SQLITE_DEFAULT_PAGE_SIZE) + \ (SQLITE_WIN32_HEAP_INIT_EXTRA)) #endif /* * The maximum size of the Win32-specific heap. This value may be zero. */ #ifndef SQLITE_WIN32_HEAP_MAX_SIZE # define SQLITE_WIN32_HEAP_MAX_SIZE (0) #endif /* * The extra flags to use in calls to the Win32 heap APIs. This value may be * zero for the default behavior. */ #ifndef SQLITE_WIN32_HEAP_FLAGS # define SQLITE_WIN32_HEAP_FLAGS (0) #endif /* ** The winMemData structure stores information required by the Win32-specific ** sqlite3_mem_methods implementation. */ typedef struct winMemData winMemData; struct winMemData { #ifndef NDEBUG u32 magic1; /* Magic number to detect structure corruption. */ #endif HANDLE hHeap; /* The handle to our heap. */ BOOL bOwned; /* Do we own the heap (i.e. destroy it on shutdown)? */ #ifndef NDEBUG u32 magic2; /* Magic number to detect structure corruption. */ #endif }; #ifndef NDEBUG #define WINMEM_MAGIC1 0x42b2830b #define WINMEM_MAGIC2 0xbd4d7cf4 #endif static struct winMemData win_mem_data = { #ifndef NDEBUG WINMEM_MAGIC1, #endif NULL, FALSE #ifndef NDEBUG ,WINMEM_MAGIC2 #endif }; #ifndef NDEBUG #define winMemAssertMagic1() assert( win_mem_data.magic1==WINMEM_MAGIC1 ) #define winMemAssertMagic2() assert( win_mem_data.magic2==WINMEM_MAGIC2 ) #define winMemAssertMagic() winMemAssertMagic1(); winMemAssertMagic2(); #else #define winMemAssertMagic() #endif #define winMemGetDataPtr() &win_mem_data #define winMemGetHeap() win_mem_data.hHeap #define winMemGetOwned() win_mem_data.bOwned static void *winMemMalloc(int nBytes); static void winMemFree(void *pPrior); static void *winMemRealloc(void *pPrior, int nBytes); static int winMemSize(void *p); static int winMemRoundup(int n); static int winMemInit(void *pAppData); static void winMemShutdown(void *pAppData); SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void); #endif /* SQLITE_WIN32_MALLOC */ /* ** The following variable is (normally) set once and never changes ** thereafter. It records whether the operating system is Win9x ** or WinNT. ** ** 0: Operating system unknown. ** 1: Operating system is Win9x. ** 2: Operating system is WinNT. ** ** In order to facilitate testing on a WinNT system, the test fixture ** can manually set this value to 1 to emulate Win98 behavior. */ #ifdef SQLITE_TEST SQLITE_API LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; #else static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; #endif #ifndef SYSCALL # define SYSCALL sqlite3_syscall_ptr #endif /* ** This function is not available on Windows CE or WinRT. */ #if SQLITE_OS_WINCE || SQLITE_OS_WINRT # define osAreFileApisANSI() 1 #endif /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during ** testing and sandboxing. The following array holds the names and pointers ** to all overrideable system calls. */ static struct win_syscall { const char *zName; /* Name of the system call */ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ sqlite3_syscall_ptr pDefault; /* Default value */ } aSyscall[] = { #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 }, #else { "AreFileApisANSI", (SYSCALL)0, 0 }, #endif #ifndef osAreFileApisANSI #define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent) #endif #if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) { "CharLowerW", (SYSCALL)CharLowerW, 0 }, #else { "CharLowerW", (SYSCALL)0, 0 }, #endif #define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent) #if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) { "CharUpperW", (SYSCALL)CharUpperW, 0 }, #else { "CharUpperW", (SYSCALL)0, 0 }, #endif #define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent) { "CloseHandle", (SYSCALL)CloseHandle, 0 }, #define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "CreateFileA", (SYSCALL)CreateFileA, 0 }, #else { "CreateFileA", (SYSCALL)0, 0 }, #endif #define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent) #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "CreateFileW", (SYSCALL)CreateFileW, 0 }, #else { "CreateFileW", (SYSCALL)0, 0 }, #endif #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \ SQLITE_WIN32_CREATEFILEMAPPINGA { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 }, #else { "CreateFileMappingA", (SYSCALL)0, 0 }, #endif #define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent) #if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, #else { "CreateFileMappingW", (SYSCALL)0, 0 }, #endif #define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent) #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "CreateMutexW", (SYSCALL)CreateMutexW, 0 }, #else { "CreateMutexW", (SYSCALL)0, 0 }, #endif #define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \ LPCWSTR))aSyscall[8].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "DeleteFileA", (SYSCALL)DeleteFileA, 0 }, #else { "DeleteFileA", (SYSCALL)0, 0 }, #endif #define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) { "DeleteFileW", (SYSCALL)DeleteFileW, 0 }, #else { "DeleteFileW", (SYSCALL)0, 0 }, #endif #define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent) #if SQLITE_OS_WINCE { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 }, #else { "FileTimeToLocalFileTime", (SYSCALL)0, 0 }, #endif #define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \ LPFILETIME))aSyscall[11].pCurrent) #if SQLITE_OS_WINCE { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 }, #else { "FileTimeToSystemTime", (SYSCALL)0, 0 }, #endif #define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \ LPSYSTEMTIME))aSyscall[12].pCurrent) { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 }, #define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "FormatMessageA", (SYSCALL)FormatMessageA, 0 }, #else { "FormatMessageA", (SYSCALL)0, 0 }, #endif #define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \ DWORD,va_list*))aSyscall[14].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) { "FormatMessageW", (SYSCALL)FormatMessageW, 0 }, #else { "FormatMessageW", (SYSCALL)0, 0 }, #endif #define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \ DWORD,va_list*))aSyscall[15].pCurrent) #if !defined(SQLITE_OMIT_LOAD_EXTENSION) { "FreeLibrary", (SYSCALL)FreeLibrary, 0 }, #else { "FreeLibrary", (SYSCALL)0, 0 }, #endif #define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent) { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 }, #define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent) #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI) { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 }, #else { "GetDiskFreeSpaceA", (SYSCALL)0, 0 }, #endif #define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \ LPDWORD))aSyscall[18].pCurrent) #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 }, #else { "GetDiskFreeSpaceW", (SYSCALL)0, 0 }, #endif #define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \ LPDWORD))aSyscall[19].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 }, #else { "GetFileAttributesA", (SYSCALL)0, 0 }, #endif #define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent) #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 }, #else { "GetFileAttributesW", (SYSCALL)0, 0 }, #endif #define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 }, #else { "GetFileAttributesExW", (SYSCALL)0, 0 }, #endif #define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \ LPVOID))aSyscall[22].pCurrent) #if !SQLITE_OS_WINRT { "GetFileSize", (SYSCALL)GetFileSize, 0 }, #else { "GetFileSize", (SYSCALL)0, 0 }, #endif #define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent) #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI) { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 }, #else { "GetFullPathNameA", (SYSCALL)0, 0 }, #endif #define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \ LPSTR*))aSyscall[24].pCurrent) #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 }, #else { "GetFullPathNameW", (SYSCALL)0, 0 }, #endif #define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \ LPWSTR*))aSyscall[25].pCurrent) { "GetLastError", (SYSCALL)GetLastError, 0 }, #define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent) #if !defined(SQLITE_OMIT_LOAD_EXTENSION) #if SQLITE_OS_WINCE /* The GetProcAddressA() routine is only available on Windows CE. */ { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 }, #else /* All other Windows platforms expect GetProcAddress() to take ** an ANSI string regardless of the _UNICODE setting */ { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 }, #endif #else { "GetProcAddressA", (SYSCALL)0, 0 }, #endif #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \ LPCSTR))aSyscall[27].pCurrent) #if !SQLITE_OS_WINRT { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 }, #else { "GetSystemInfo", (SYSCALL)0, 0 }, #endif #define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent) { "GetSystemTime", (SYSCALL)GetSystemTime, 0 }, #define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent) #if !SQLITE_OS_WINCE { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 }, #else { "GetSystemTimeAsFileTime", (SYSCALL)0, 0 }, #endif #define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \ LPFILETIME))aSyscall[30].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "GetTempPathA", (SYSCALL)GetTempPathA, 0 }, #else { "GetTempPathA", (SYSCALL)0, 0 }, #endif #define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent) #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "GetTempPathW", (SYSCALL)GetTempPathW, 0 }, #else { "GetTempPathW", (SYSCALL)0, 0 }, #endif #define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent) #if !SQLITE_OS_WINRT { "GetTickCount", (SYSCALL)GetTickCount, 0 }, #else { "GetTickCount", (SYSCALL)0, 0 }, #endif #define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_GETVERSIONEX { "GetVersionExA", (SYSCALL)GetVersionExA, 0 }, #else { "GetVersionExA", (SYSCALL)0, 0 }, #endif #define osGetVersionExA ((BOOL(WINAPI*)( \ LPOSVERSIONINFOA))aSyscall[34].pCurrent) #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ SQLITE_WIN32_GETVERSIONEX { "GetVersionExW", (SYSCALL)GetVersionExW, 0 }, #else { "GetVersionExW", (SYSCALL)0, 0 }, #endif #define osGetVersionExW ((BOOL(WINAPI*)( \ LPOSVERSIONINFOW))aSyscall[35].pCurrent) { "HeapAlloc", (SYSCALL)HeapAlloc, 0 }, #define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \ SIZE_T))aSyscall[36].pCurrent) #if !SQLITE_OS_WINRT { "HeapCreate", (SYSCALL)HeapCreate, 0 }, #else { "HeapCreate", (SYSCALL)0, 0 }, #endif #define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \ SIZE_T))aSyscall[37].pCurrent) #if !SQLITE_OS_WINRT { "HeapDestroy", (SYSCALL)HeapDestroy, 0 }, #else { "HeapDestroy", (SYSCALL)0, 0 }, #endif #define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[38].pCurrent) { "HeapFree", (SYSCALL)HeapFree, 0 }, #define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[39].pCurrent) { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 }, #define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \ SIZE_T))aSyscall[40].pCurrent) { "HeapSize", (SYSCALL)HeapSize, 0 }, #define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \ LPCVOID))aSyscall[41].pCurrent) #if !SQLITE_OS_WINRT { "HeapValidate", (SYSCALL)HeapValidate, 0 }, #else { "HeapValidate", (SYSCALL)0, 0 }, #endif #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \ LPCVOID))aSyscall[42].pCurrent) #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT { "HeapCompact", (SYSCALL)HeapCompact, 0 }, #else { "HeapCompact", (SYSCALL)0, 0 }, #endif #define osHeapCompact ((UINT(WINAPI*)(HANDLE,DWORD))aSyscall[43].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION) { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 }, #else { "LoadLibraryA", (SYSCALL)0, 0 }, #endif #define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[44].pCurrent) #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ !defined(SQLITE_OMIT_LOAD_EXTENSION) { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 }, #else { "LoadLibraryW", (SYSCALL)0, 0 }, #endif #define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[45].pCurrent) #if !SQLITE_OS_WINRT { "LocalFree", (SYSCALL)LocalFree, 0 }, #else { "LocalFree", (SYSCALL)0, 0 }, #endif #define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[46].pCurrent) #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT { "LockFile", (SYSCALL)LockFile, 0 }, #else { "LockFile", (SYSCALL)0, 0 }, #endif #ifndef osLockFile #define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ DWORD))aSyscall[47].pCurrent) #endif #if !SQLITE_OS_WINCE { "LockFileEx", (SYSCALL)LockFileEx, 0 }, #else { "LockFileEx", (SYSCALL)0, 0 }, #endif #ifndef osLockFileEx #define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \ LPOVERLAPPED))aSyscall[48].pCurrent) #endif #if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, #else { "MapViewOfFile", (SYSCALL)0, 0 }, #endif #define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ SIZE_T))aSyscall[49].pCurrent) { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 }, #define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \ int))aSyscall[50].pCurrent) { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 }, #define osQueryPerformanceCounter ((BOOL(WINAPI*)( \ LARGE_INTEGER*))aSyscall[51].pCurrent) { "ReadFile", (SYSCALL)ReadFile, 0 }, #define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \ LPOVERLAPPED))aSyscall[52].pCurrent) { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 }, #define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[53].pCurrent) #if !SQLITE_OS_WINRT { "SetFilePointer", (SYSCALL)SetFilePointer, 0 }, #else { "SetFilePointer", (SYSCALL)0, 0 }, #endif #define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \ DWORD))aSyscall[54].pCurrent) #if !SQLITE_OS_WINRT { "Sleep", (SYSCALL)Sleep, 0 }, #else { "Sleep", (SYSCALL)0, 0 }, #endif #define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[55].pCurrent) { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 }, #define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \ LPFILETIME))aSyscall[56].pCurrent) #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT { "UnlockFile", (SYSCALL)UnlockFile, 0 }, #else { "UnlockFile", (SYSCALL)0, 0 }, #endif #ifndef osUnlockFile #define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ DWORD))aSyscall[57].pCurrent) #endif #if !SQLITE_OS_WINCE { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 }, #else { "UnlockFileEx", (SYSCALL)0, 0 }, #endif #define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ LPOVERLAPPED))aSyscall[58].pCurrent) #if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 }, #else { "UnmapViewOfFile", (SYSCALL)0, 0 }, #endif #define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[59].pCurrent) { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 }, #define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \ LPCSTR,LPBOOL))aSyscall[60].pCurrent) { "WriteFile", (SYSCALL)WriteFile, 0 }, #define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \ LPOVERLAPPED))aSyscall[61].pCurrent) #if SQLITE_OS_WINRT { "CreateEventExW", (SYSCALL)CreateEventExW, 0 }, #else { "CreateEventExW", (SYSCALL)0, 0 }, #endif #define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \ DWORD,DWORD))aSyscall[62].pCurrent) #if !SQLITE_OS_WINRT { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, #else { "WaitForSingleObject", (SYSCALL)0, 0 }, #endif #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ DWORD))aSyscall[63].pCurrent) #if !SQLITE_OS_WINCE { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, #else { "WaitForSingleObjectEx", (SYSCALL)0, 0 }, #endif #define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ BOOL))aSyscall[64].pCurrent) #if SQLITE_OS_WINRT { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, #else { "SetFilePointerEx", (SYSCALL)0, 0 }, #endif #define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \ PLARGE_INTEGER,DWORD))aSyscall[65].pCurrent) #if SQLITE_OS_WINRT { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 }, #else { "GetFileInformationByHandleEx", (SYSCALL)0, 0 }, #endif #define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \ FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent) #if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, #else { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, #endif #define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \ SIZE_T))aSyscall[67].pCurrent) #if SQLITE_OS_WINRT { "CreateFile2", (SYSCALL)CreateFile2, 0 }, #else { "CreateFile2", (SYSCALL)0, 0 }, #endif #define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \ LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[68].pCurrent) #if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION) { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 }, #else { "LoadPackagedLibrary", (SYSCALL)0, 0 }, #endif #define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \ DWORD))aSyscall[69].pCurrent) #if SQLITE_OS_WINRT { "GetTickCount64", (SYSCALL)GetTickCount64, 0 }, #else { "GetTickCount64", (SYSCALL)0, 0 }, #endif #define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[70].pCurrent) #if SQLITE_OS_WINRT { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 }, #else { "GetNativeSystemInfo", (SYSCALL)0, 0 }, #endif #define osGetNativeSystemInfo ((VOID(WINAPI*)( \ LPSYSTEM_INFO))aSyscall[71].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 }, #else { "OutputDebugStringA", (SYSCALL)0, 0 }, #endif #define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[72].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 }, #else { "OutputDebugStringW", (SYSCALL)0, 0 }, #endif #define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[73].pCurrent) { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 }, #define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent) #if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 }, #else { "CreateFileMappingFromApp", (SYSCALL)0, 0 }, #endif #define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent) /* ** NOTE: On some sub-platforms, the InterlockedCompareExchange "function" ** is really just a macro that uses a compiler intrinsic (e.g. x64). ** So do not try to make this is into a redefinable interface. */ #if defined(InterlockedCompareExchange) { "InterlockedCompareExchange", (SYSCALL)0, 0 }, #define osInterlockedCompareExchange InterlockedCompareExchange #else { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, #define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \ SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent) #endif /* defined(InterlockedCompareExchange) */ #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID { "UuidCreate", (SYSCALL)UuidCreate, 0 }, #else { "UuidCreate", (SYSCALL)0, 0 }, #endif #define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent) #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 }, #else { "UuidCreateSequential", (SYSCALL)0, 0 }, #endif #define osUuidCreateSequential \ ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent) #if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0 { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 }, #else { "FlushViewOfFile", (SYSCALL)0, 0 }, #endif #define osFlushViewOfFile \ ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent) }; /* End of the overrideable system calls */ /* ** This is the xSetSystemCall() method of sqlite3_vfs for all of the ** "win32" VFSes. Return SQLITE_OK upon successfully updating the ** system call pointer, or SQLITE_NOTFOUND if there is no configurable ** system call named zName. */ static int winSetSystemCall( sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */ const char *zName, /* Name of system call to override */ sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */ ){ unsigned int i; int rc = SQLITE_NOTFOUND; UNUSED_PARAMETER(pNotUsed); if( zName==0 ){ /* If no zName is given, restore all system calls to their default ** settings and return NULL */ rc = SQLITE_OK; for(i=0; i0 ){ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); memcpy(zDbgBuf, zBuf, nMin); osOutputDebugStringA(zDbgBuf); }else{ osOutputDebugStringA(zBuf); } #elif defined(SQLITE_WIN32_HAS_WIDE) memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); if ( osMultiByteToWideChar( osAreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, zBuf, nMin, (LPWSTR)zDbgBuf, SQLITE_WIN32_DBG_BUF_SIZE/sizeof(WCHAR))<=0 ){ return; } osOutputDebugStringW((LPCWSTR)zDbgBuf); #else if( nMin>0 ){ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); memcpy(zDbgBuf, zBuf, nMin); fprintf(stderr, "%s", zDbgBuf); }else{ fprintf(stderr, "%s", zBuf); } #endif } /* ** The following routine suspends the current thread for at least ms ** milliseconds. This is equivalent to the Win32 Sleep() interface. */ #if SQLITE_OS_WINRT static HANDLE sleepObj = NULL; #endif SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){ #if SQLITE_OS_WINRT if ( sleepObj==NULL ){ sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE); } assert( sleepObj!=NULL ); osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE); #else osSleep(milliseconds); #endif } #if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ SQLITE_THREADSAFE>0 SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ DWORD rc; while( (rc = osWaitForSingleObjectEx(hObject, INFINITE, TRUE))==WAIT_IO_COMPLETION ){} return rc; } #endif /* ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, ** or WinCE. Return false (zero) for Win95, Win98, or WinME. ** ** Here is an interesting observation: Win95, Win98, and WinME lack ** the LockFileEx() API. But we can still statically link against that ** API as long as we don't call it when running Win95/98/ME. A call to ** this routine is used to determine if the host is Win95/98/ME or ** WinNT/2K/XP so that we will know whether or not we can safely call ** the LockFileEx() API. */ #if !SQLITE_WIN32_GETVERSIONEX # define osIsNT() (1) #elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI) # define osIsNT() (1) #elif !defined(SQLITE_WIN32_HAS_WIDE) # define osIsNT() (0) #else # define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt()) #endif /* ** This function determines if the machine is running a version of Windows ** based on the NT kernel. */ SQLITE_API int sqlite3_win32_is_nt(void){ #if SQLITE_OS_WINRT /* ** NOTE: The WinRT sub-platform is always assumed to be based on the NT ** kernel. */ return 1; #elif SQLITE_WIN32_GETVERSIONEX if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ #if defined(SQLITE_WIN32_HAS_ANSI) OSVERSIONINFOA sInfo; sInfo.dwOSVersionInfoSize = sizeof(sInfo); osGetVersionExA(&sInfo); osInterlockedCompareExchange(&sqlite3_os_type, (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); #elif defined(SQLITE_WIN32_HAS_WIDE) OSVERSIONINFOW sInfo; sInfo.dwOSVersionInfoSize = sizeof(sInfo); osGetVersionExW(&sInfo); osInterlockedCompareExchange(&sqlite3_os_type, (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); #endif } return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; #elif SQLITE_TEST return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; #else /* ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are ** deprecated are always assumed to be based on the NT kernel. */ return 1; #endif } #ifdef SQLITE_WIN32_MALLOC /* ** Allocate nBytes of memory. */ static void *winMemMalloc(int nBytes){ HANDLE hHeap; void *p; winMemAssertMagic(); hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif assert( nBytes>=0 ); p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); if( !p ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%lu), heap=%p", nBytes, osGetLastError(), (void*)hHeap); } return p; } /* ** Free memory. */ static void winMemFree(void *pPrior){ HANDLE hHeap; winMemAssertMagic(); hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); #endif if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */ if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%lu), heap=%p", pPrior, osGetLastError(), (void*)hHeap); } } /* ** Change the size of an existing memory allocation */ static void *winMemRealloc(void *pPrior, int nBytes){ HANDLE hHeap; void *p; winMemAssertMagic(); hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); #endif assert( nBytes>=0 ); if( !pPrior ){ p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); }else{ p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes); } if( !p ){ sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%lu), heap=%p", pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(), (void*)hHeap); } return p; } /* ** Return the size of an outstanding allocation, in bytes. */ static int winMemSize(void *p){ HANDLE hHeap; SIZE_T n; winMemAssertMagic(); hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, p) ); #endif if( !p ) return 0; n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p); if( n==(SIZE_T)-1 ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%lu), heap=%p", p, osGetLastError(), (void*)hHeap); return 0; } return (int)n; } /* ** Round up a request size to the next valid allocation size. */ static int winMemRoundup(int n){ return n; } /* ** Initialize this module. */ static int winMemInit(void *pAppData){ winMemData *pWinMemData = (winMemData *)pAppData; if( !pWinMemData ) return SQLITE_ERROR; assert( pWinMemData->magic1==WINMEM_MAGIC1 ); assert( pWinMemData->magic2==WINMEM_MAGIC2 ); #if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE if( !pWinMemData->hHeap ){ DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE; DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap; if( dwMaximumSize==0 ){ dwMaximumSize = SQLITE_WIN32_HEAP_MAX_SIZE; }else if( dwInitialSize>dwMaximumSize ){ dwInitialSize = dwMaximumSize; } pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS, dwInitialSize, dwMaximumSize); if( !pWinMemData->hHeap ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu", osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize, dwMaximumSize); return SQLITE_NOMEM_BKPT; } pWinMemData->bOwned = TRUE; assert( pWinMemData->bOwned ); } #else pWinMemData->hHeap = osGetProcessHeap(); if( !pWinMemData->hHeap ){ sqlite3_log(SQLITE_NOMEM, "failed to GetProcessHeap (%lu)", osGetLastError()); return SQLITE_NOMEM_BKPT; } pWinMemData->bOwned = FALSE; assert( !pWinMemData->bOwned ); #endif assert( pWinMemData->hHeap!=0 ); assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif return SQLITE_OK; } /* ** Deinitialize this module. */ static void winMemShutdown(void *pAppData){ winMemData *pWinMemData = (winMemData *)pAppData; if( !pWinMemData ) return; assert( pWinMemData->magic1==WINMEM_MAGIC1 ); assert( pWinMemData->magic2==WINMEM_MAGIC2 ); if( pWinMemData->hHeap ){ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif if( pWinMemData->bOwned ){ if( !osHeapDestroy(pWinMemData->hHeap) ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%lu), heap=%p", osGetLastError(), (void*)pWinMemData->hHeap); } pWinMemData->bOwned = FALSE; } pWinMemData->hHeap = NULL; } } /* ** Populate the low-level memory allocation function pointers in ** sqlite3GlobalConfig.m with pointers to the routines in this file. The ** arguments specify the block of memory to manage. ** ** This routine is only called by sqlite3_config(), and therefore ** is not required to be threadsafe (it is not). */ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void){ static const sqlite3_mem_methods winMemMethods = { winMemMalloc, winMemFree, winMemRealloc, winMemSize, winMemRoundup, winMemInit, winMemShutdown, &win_mem_data }; return &winMemMethods; } SQLITE_PRIVATE void sqlite3MemSetDefault(void){ sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32()); } #endif /* SQLITE_WIN32_MALLOC */ /* ** Convert a UTF-8 string to Microsoft Unicode. ** ** Space to hold the returned string is obtained from sqlite3_malloc(). */ static LPWSTR winUtf8ToUnicode(const char *zText){ int nChar; LPWSTR zWideText; nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0); if( nChar==0 ){ return 0; } zWideText = sqlite3MallocZero( nChar*sizeof(WCHAR) ); if( zWideText==0 ){ return 0; } nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText, nChar); if( nChar==0 ){ sqlite3_free(zWideText); zWideText = 0; } return zWideText; } /* ** Convert a Microsoft Unicode string to UTF-8. ** ** Space to hold the returned string is obtained from sqlite3_malloc(). */ static char *winUnicodeToUtf8(LPCWSTR zWideText){ int nByte; char *zText; nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0); if( nByte == 0 ){ return 0; } zText = sqlite3MallocZero( nByte ); if( zText==0 ){ return 0; } nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte, 0, 0); if( nByte == 0 ){ sqlite3_free(zText); zText = 0; } return zText; } /* ** Convert an ANSI string to Microsoft Unicode, using the ANSI or OEM ** code page. ** ** Space to hold the returned string is obtained from sqlite3_malloc(). */ static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){ int nByte; LPWSTR zMbcsText; int codepage = useAnsi ? CP_ACP : CP_OEMCP; nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL, 0)*sizeof(WCHAR); if( nByte==0 ){ return 0; } zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) ); if( zMbcsText==0 ){ return 0; } nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText, nByte); if( nByte==0 ){ sqlite3_free(zMbcsText); zMbcsText = 0; } return zMbcsText; } /* ** Convert a Microsoft Unicode string to a multi-byte character string, ** using the ANSI or OEM code page. ** ** Space to hold the returned string is obtained from sqlite3_malloc(). */ static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){ int nByte; char *zText; int codepage = useAnsi ? CP_ACP : CP_OEMCP; nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, 0, 0, 0, 0); if( nByte == 0 ){ return 0; } zText = sqlite3MallocZero( nByte ); if( zText==0 ){ return 0; } nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, zText, nByte, 0, 0); if( nByte == 0 ){ sqlite3_free(zText); zText = 0; } return zText; } /* ** Convert a multi-byte character string to UTF-8. ** ** Space to hold the returned string is obtained from sqlite3_malloc(). */ static char *winMbcsToUtf8(const char *zText, int useAnsi){ char *zTextUtf8; LPWSTR zTmpWide; zTmpWide = winMbcsToUnicode(zText, useAnsi); if( zTmpWide==0 ){ return 0; } zTextUtf8 = winUnicodeToUtf8(zTmpWide); sqlite3_free(zTmpWide); return zTextUtf8; } /* ** Convert a UTF-8 string to a multi-byte character string. ** ** Space to hold the returned string is obtained from sqlite3_malloc(). */ static char *winUtf8ToMbcs(const char *zText, int useAnsi){ char *zTextMbcs; LPWSTR zTmpWide; zTmpWide = winUtf8ToUnicode(zText); if( zTmpWide==0 ){ return 0; } zTextMbcs = winUnicodeToMbcs(zTmpWide, useAnsi); sqlite3_free(zTmpWide); return zTextMbcs; } /* ** This is a public wrapper for the winUtf8ToUnicode() function. */ SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText){ #ifdef SQLITE_ENABLE_API_ARMOR if( !zText ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return winUtf8ToUnicode(zText); } /* ** This is a public wrapper for the winUnicodeToUtf8() function. */ SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){ #ifdef SQLITE_ENABLE_API_ARMOR if( !zWideText ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return winUnicodeToUtf8(zWideText); } /* ** This is a public wrapper for the winMbcsToUtf8() function. */ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){ #ifdef SQLITE_ENABLE_API_ARMOR if( !zText ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return winMbcsToUtf8(zText, osAreFileApisANSI()); } /* ** This is a public wrapper for the winMbcsToUtf8() function. */ SQLITE_API char *sqlite3_win32_mbcs_to_utf8_v2(const char *zText, int useAnsi){ #ifdef SQLITE_ENABLE_API_ARMOR if( !zText ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return winMbcsToUtf8(zText, useAnsi); } /* ** This is a public wrapper for the winUtf8ToMbcs() function. */ SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zText){ #ifdef SQLITE_ENABLE_API_ARMOR if( !zText ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return winUtf8ToMbcs(zText, osAreFileApisANSI()); } /* ** This is a public wrapper for the winUtf8ToMbcs() function. */ SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){ #ifdef SQLITE_ENABLE_API_ARMOR if( !zText ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return winUtf8ToMbcs(zText, useAnsi); } /* ** This function is the same as sqlite3_win32_set_directory (below); however, ** it accepts a UTF-8 string. */ SQLITE_API int sqlite3_win32_set_directory8( unsigned long type, /* Identifier for directory being set or reset */ const char *zValue /* New value for directory being set or reset */ ){ char **ppDirectory = 0; int rc; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ) return rc; #endif sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){ ppDirectory = &sqlite3_data_directory; }else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){ ppDirectory = &sqlite3_temp_directory; } assert( !ppDirectory || type==SQLITE_WIN32_DATA_DIRECTORY_TYPE || type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ); assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) ); if( ppDirectory ){ char *zCopy = 0; if( zValue && zValue[0] ){ zCopy = sqlite3_mprintf("%s", zValue); if ( zCopy==0 ){ rc = SQLITE_NOMEM_BKPT; goto set_directory8_done; } } sqlite3_free(*ppDirectory); *ppDirectory = zCopy; rc = SQLITE_OK; }else{ rc = SQLITE_ERROR; } set_directory8_done: sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); return rc; } /* ** This function is the same as sqlite3_win32_set_directory (below); however, ** it accepts a UTF-16 string. */ SQLITE_API int sqlite3_win32_set_directory16( unsigned long type, /* Identifier for directory being set or reset */ const void *zValue /* New value for directory being set or reset */ ){ int rc; char *zUtf8 = 0; if( zValue ){ zUtf8 = sqlite3_win32_unicode_to_utf8(zValue); if( zUtf8==0 ) return SQLITE_NOMEM_BKPT; } rc = sqlite3_win32_set_directory8(type, zUtf8); if( zUtf8 ) sqlite3_free(zUtf8); return rc; } /* ** This function sets the data directory or the temporary directory based on ** the provided arguments. The type argument must be 1 in order to set the ** data directory or 2 in order to set the temporary directory. The zValue ** argument is the name of the directory to use. The return value will be ** SQLITE_OK if successful. */ SQLITE_API int sqlite3_win32_set_directory( unsigned long type, /* Identifier for directory being set or reset */ void *zValue /* New value for directory being set or reset */ ){ return sqlite3_win32_set_directory16(type, zValue); } /* ** The return value of winGetLastErrorMsg ** is zero if the error message fits in the buffer, or non-zero ** otherwise (if the message was truncated). */ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ /* FormatMessage returns 0 on failure. Otherwise it ** returns the number of TCHARs written to the output ** buffer, excluding the terminating null char. */ DWORD dwLen = 0; char *zOut = 0; if( osIsNT() ){ #if SQLITE_OS_WINRT WCHAR zTempWide[SQLITE_WIN32_MAX_ERRMSG_CHARS+1]; dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastErrno, 0, zTempWide, SQLITE_WIN32_MAX_ERRMSG_CHARS, 0); #else LPWSTR zTempWide = NULL; dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastErrno, 0, (LPWSTR) &zTempWide, 0, 0); #endif if( dwLen > 0 ){ /* allocate a buffer and convert to UTF8 */ sqlite3BeginBenignMalloc(); zOut = winUnicodeToUtf8(zTempWide); sqlite3EndBenignMalloc(); #if !SQLITE_OS_WINRT /* free the system buffer allocated by FormatMessage */ osLocalFree(zTempWide); #endif } } #ifdef SQLITE_WIN32_HAS_ANSI else{ char *zTemp = NULL; dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastErrno, 0, (LPSTR) &zTemp, 0, 0); if( dwLen > 0 ){ /* allocate a buffer and convert to UTF8 */ sqlite3BeginBenignMalloc(); zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI()); sqlite3EndBenignMalloc(); /* free the system buffer allocated by FormatMessage */ osLocalFree(zTemp); } } #endif if( 0 == dwLen ){ sqlite3_snprintf(nBuf, zBuf, "OsError 0x%lx (%lu)", lastErrno, lastErrno); }else{ /* copy a maximum of nBuf chars to output buffer */ sqlite3_snprintf(nBuf, zBuf, "%s", zOut); /* free the UTF8 buffer */ sqlite3_free(zOut); } return 0; } /* ** ** This function - winLogErrorAtLine() - is only ever called via the macro ** winLogError(). ** ** This routine is invoked after an error occurs in an OS function. ** It logs a message using sqlite3_log() containing the current value of ** error code and, if possible, the human-readable equivalent from ** FormatMessage. ** ** The first argument passed to the macro should be the error code that ** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). ** The two subsequent arguments should be the name of the OS function that ** failed and the associated file-system path, if any. */ #define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__) static int winLogErrorAtLine( int errcode, /* SQLite error code */ DWORD lastErrno, /* Win32 last error */ const char *zFunc, /* Name of OS function that failed */ const char *zPath, /* File path associated with error */ int iLine /* Source line number where error occurred */ ){ char zMsg[500]; /* Human readable error text */ int i; /* Loop counter */ zMsg[0] = 0; winGetLastErrorMsg(lastErrno, sizeof(zMsg), zMsg); assert( errcode!=SQLITE_OK ); if( zPath==0 ) zPath = ""; for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){} zMsg[i] = 0; sqlite3_log(errcode, "os_win.c:%d: (%lu) %s(%s) - %s", iLine, lastErrno, zFunc, zPath, zMsg ); return errcode; } /* ** The number of times that a ReadFile(), WriteFile(), and DeleteFile() ** will be retried following a locking error - probably caused by ** antivirus software. Also the initial delay before the first retry. ** The delay increases linearly with each retry. */ #ifndef SQLITE_WIN32_IOERR_RETRY # define SQLITE_WIN32_IOERR_RETRY 10 #endif #ifndef SQLITE_WIN32_IOERR_RETRY_DELAY # define SQLITE_WIN32_IOERR_RETRY_DELAY 25 #endif static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY; static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY; /* ** The "winIoerrCanRetry1" macro is used to determine if a particular I/O ** error code obtained via GetLastError() is eligible to be retried. It ** must accept the error code DWORD as its only argument and should return ** non-zero if the error code is transient in nature and the operation ** responsible for generating the original error might succeed upon being ** retried. The argument to this macro should be a variable. ** ** Additionally, a macro named "winIoerrCanRetry2" may be defined. If it ** is defined, it will be consulted only when the macro "winIoerrCanRetry1" ** returns zero. The "winIoerrCanRetry2" macro is completely optional and ** may be used to include additional error codes in the set that should ** result in the failing I/O operation being retried by the caller. If ** defined, the "winIoerrCanRetry2" macro must exhibit external semantics ** identical to those of the "winIoerrCanRetry1" macro. */ #if !defined(winIoerrCanRetry1) #define winIoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \ ((a)==ERROR_SHARING_VIOLATION) || \ ((a)==ERROR_LOCK_VIOLATION) || \ ((a)==ERROR_DEV_NOT_EXIST) || \ ((a)==ERROR_NETNAME_DELETED) || \ ((a)==ERROR_SEM_TIMEOUT) || \ ((a)==ERROR_NETWORK_UNREACHABLE)) #endif /* ** If a ReadFile() or WriteFile() error occurs, invoke this routine ** to see if it should be retried. Return TRUE to retry. Return FALSE ** to give up with an error. */ static int winRetryIoerr(int *pnRetry, DWORD *pError){ DWORD e = osGetLastError(); if( *pnRetry>=winIoerrRetry ){ if( pError ){ *pError = e; } return 0; } if( winIoerrCanRetry1(e) ){ sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); ++*pnRetry; return 1; } #if defined(winIoerrCanRetry2) else if( winIoerrCanRetry2(e) ){ sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); ++*pnRetry; return 1; } #endif if( pError ){ *pError = e; } return 0; } /* ** Log a I/O error retry episode. */ static void winLogIoerr(int nRetry, int lineno){ if( nRetry ){ sqlite3_log(SQLITE_NOTICE, "delayed %dms for lock/sharing conflict at line %d", winIoerrRetryDelay*nRetry*(nRetry+1)/2, lineno ); } } /* ** This #if does not rely on the SQLITE_OS_WINCE define because the ** corresponding section in "date.c" cannot use it. */ #if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \ (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API) /* ** The MSVC CRT on Windows CE may not have a localtime() function. ** So define a substitute. */ /* # include */ struct tm *__cdecl localtime(const time_t *t) { static struct tm y; FILETIME uTm, lTm; SYSTEMTIME pTm; sqlite3_int64 t64; t64 = *t; t64 = (t64 + 11644473600)*10000000; uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF); uTm.dwHighDateTime= (DWORD)(t64 >> 32); osFileTimeToLocalFileTime(&uTm,&lTm); osFileTimeToSystemTime(&lTm,&pTm); y.tm_year = pTm.wYear - 1900; y.tm_mon = pTm.wMonth - 1; y.tm_wday = pTm.wDayOfWeek; y.tm_mday = pTm.wDay; y.tm_hour = pTm.wHour; y.tm_min = pTm.wMinute; y.tm_sec = pTm.wSecond; return &y; } #endif #if SQLITE_OS_WINCE /************************************************************************* ** This section contains code for WinCE only. */ #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)] /* ** Acquire a lock on the handle h */ static void winceMutexAcquire(HANDLE h){ DWORD dwErr; do { dwErr = osWaitForSingleObject(h, INFINITE); } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED); } /* ** Release a lock acquired by winceMutexAcquire() */ #define winceMutexRelease(h) ReleaseMutex(h) /* ** Create the mutex and shared memory used for locking in the file ** descriptor pFile */ static int winceCreateLock(const char *zFilename, winFile *pFile){ LPWSTR zTok; LPWSTR zName; DWORD lastErrno; BOOL bLogged = FALSE; BOOL bInit = TRUE; zName = winUtf8ToUnicode(zFilename); if( zName==0 ){ /* out of memory */ return SQLITE_IOERR_NOMEM_BKPT; } /* Initialize the local lockdata */ memset(&pFile->local, 0, sizeof(pFile->local)); /* Replace the backslashes from the filename and lowercase it ** to derive a mutex name. */ zTok = osCharLowerW(zName); for (;*zTok;zTok++){ if (*zTok == '\\') *zTok = '_'; } /* Create/open the named mutex */ pFile->hMutex = osCreateMutexW(NULL, FALSE, zName); if (!pFile->hMutex){ pFile->lastErrno = osGetLastError(); sqlite3_free(zName); return winLogError(SQLITE_IOERR, pFile->lastErrno, "winceCreateLock1", zFilename); } /* Acquire the mutex before continuing */ winceMutexAcquire(pFile->hMutex); /* Since the names of named mutexes, semaphores, file mappings etc are ** case-sensitive, take advantage of that by uppercasing the mutex name ** and using that as the shared filemapping name. */ osCharUpperW(zName); pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(winceLock), zName); /* Set a flag that indicates we're the first to create the memory so it ** must be zero-initialized */ lastErrno = osGetLastError(); if (lastErrno == ERROR_ALREADY_EXISTS){ bInit = FALSE; } sqlite3_free(zName); /* If we succeeded in making the shared memory handle, map it. */ if( pFile->hShared ){ pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); /* If mapping failed, close the shared memory handle and erase it */ if( !pFile->shared ){ pFile->lastErrno = osGetLastError(); winLogError(SQLITE_IOERR, pFile->lastErrno, "winceCreateLock2", zFilename); bLogged = TRUE; osCloseHandle(pFile->hShared); pFile->hShared = NULL; } } /* If shared memory could not be created, then close the mutex and fail */ if( pFile->hShared==NULL ){ if( !bLogged ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR, pFile->lastErrno, "winceCreateLock3", zFilename); bLogged = TRUE; } winceMutexRelease(pFile->hMutex); osCloseHandle(pFile->hMutex); pFile->hMutex = NULL; return SQLITE_IOERR; } /* Initialize the shared memory if we're supposed to */ if( bInit ){ memset(pFile->shared, 0, sizeof(winceLock)); } winceMutexRelease(pFile->hMutex); return SQLITE_OK; } /* ** Destroy the part of winFile that deals with wince locks */ static void winceDestroyLock(winFile *pFile){ if (pFile->hMutex){ /* Acquire the mutex */ winceMutexAcquire(pFile->hMutex); /* The following blocks should probably assert in debug mode, but they are to cleanup in case any locks remained open */ if (pFile->local.nReaders){ pFile->shared->nReaders --; } if (pFile->local.bReserved){ pFile->shared->bReserved = FALSE; } if (pFile->local.bPending){ pFile->shared->bPending = FALSE; } if (pFile->local.bExclusive){ pFile->shared->bExclusive = FALSE; } /* De-reference and close our copy of the shared memory handle */ osUnmapViewOfFile(pFile->shared); osCloseHandle(pFile->hShared); /* Done with the mutex */ winceMutexRelease(pFile->hMutex); osCloseHandle(pFile->hMutex); pFile->hMutex = NULL; } } /* ** An implementation of the LockFile() API of Windows for CE */ static BOOL winceLockFile( LPHANDLE phFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh ){ winFile *pFile = HANDLE_TO_WINFILE(phFile); BOOL bReturn = FALSE; UNUSED_PARAMETER(dwFileOffsetHigh); UNUSED_PARAMETER(nNumberOfBytesToLockHigh); if (!pFile->hMutex) return TRUE; winceMutexAcquire(pFile->hMutex); /* Wanting an exclusive lock? */ if (dwFileOffsetLow == (DWORD)SHARED_FIRST && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){ if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){ pFile->shared->bExclusive = TRUE; pFile->local.bExclusive = TRUE; bReturn = TRUE; } } /* Want a read-only lock? */ else if (dwFileOffsetLow == (DWORD)SHARED_FIRST && nNumberOfBytesToLockLow == 1){ if (pFile->shared->bExclusive == 0){ pFile->local.nReaders ++; if (pFile->local.nReaders == 1){ pFile->shared->nReaders ++; } bReturn = TRUE; } } /* Want a pending lock? */ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){ /* If no pending lock has been acquired, then acquire it */ if (pFile->shared->bPending == 0) { pFile->shared->bPending = TRUE; pFile->local.bPending = TRUE; bReturn = TRUE; } } /* Want a reserved lock? */ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){ if (pFile->shared->bReserved == 0) { pFile->shared->bReserved = TRUE; pFile->local.bReserved = TRUE; bReturn = TRUE; } } winceMutexRelease(pFile->hMutex); return bReturn; } /* ** An implementation of the UnlockFile API of Windows for CE */ static BOOL winceUnlockFile( LPHANDLE phFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh ){ winFile *pFile = HANDLE_TO_WINFILE(phFile); BOOL bReturn = FALSE; UNUSED_PARAMETER(dwFileOffsetHigh); UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh); if (!pFile->hMutex) return TRUE; winceMutexAcquire(pFile->hMutex); /* Releasing a reader lock or an exclusive lock */ if (dwFileOffsetLow == (DWORD)SHARED_FIRST){ /* Did we have an exclusive lock? */ if (pFile->local.bExclusive){ assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE); pFile->local.bExclusive = FALSE; pFile->shared->bExclusive = FALSE; bReturn = TRUE; } /* Did we just have a reader lock? */ else if (pFile->local.nReaders){ assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1); pFile->local.nReaders --; if (pFile->local.nReaders == 0) { pFile->shared->nReaders --; } bReturn = TRUE; } } /* Releasing a pending lock */ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){ if (pFile->local.bPending){ pFile->local.bPending = FALSE; pFile->shared->bPending = FALSE; bReturn = TRUE; } } /* Releasing a reserved lock */ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){ if (pFile->local.bReserved) { pFile->local.bReserved = FALSE; pFile->shared->bReserved = FALSE; bReturn = TRUE; } } winceMutexRelease(pFile->hMutex); return bReturn; } /* ** End of the special code for wince *****************************************************************************/ #endif /* SQLITE_OS_WINCE */ /* ** Lock a file region. */ static BOOL winLockFile( LPHANDLE phFile, DWORD flags, DWORD offsetLow, DWORD offsetHigh, DWORD numBytesLow, DWORD numBytesHigh ){ #if SQLITE_OS_WINCE /* ** NOTE: Windows CE is handled differently here due its lack of the Win32 ** API LockFile. */ return winceLockFile(phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); #else if( osIsNT() ){ OVERLAPPED ovlp; memset(&ovlp, 0, sizeof(OVERLAPPED)); ovlp.Offset = offsetLow; ovlp.OffsetHigh = offsetHigh; return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp); }else{ return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); } #endif } /* ** Unlock a file region. */ static BOOL winUnlockFile( LPHANDLE phFile, DWORD offsetLow, DWORD offsetHigh, DWORD numBytesLow, DWORD numBytesHigh ){ #if SQLITE_OS_WINCE /* ** NOTE: Windows CE is handled differently here due its lack of the Win32 ** API UnlockFile. */ return winceUnlockFile(phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); #else if( osIsNT() ){ OVERLAPPED ovlp; memset(&ovlp, 0, sizeof(OVERLAPPED)); ovlp.Offset = offsetLow; ovlp.OffsetHigh = offsetHigh; return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp); }else{ return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); } #endif } /***************************************************************************** ** The next group of routines implement the I/O methods specified ** by the sqlite3_io_methods object. ******************************************************************************/ /* ** Some Microsoft compilers lack this definition. */ #ifndef INVALID_SET_FILE_POINTER # define INVALID_SET_FILE_POINTER ((DWORD)-1) #endif /* ** Move the current position of the file handle passed as the first ** argument to offset iOffset within the file. If successful, return 0. ** Otherwise, set pFile->lastErrno and return non-zero. */ static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ #if !SQLITE_OS_WINRT LONG upperBits; /* Most sig. 32 bits of new offset */ LONG lowerBits; /* Least sig. 32 bits of new offset */ DWORD dwRet; /* Value returned by SetFilePointer() */ DWORD lastErrno; /* Value returned by GetLastError() */ OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset)); upperBits = (LONG)((iOffset>>32) & 0x7fffffff); lowerBits = (LONG)(iOffset & 0xffffffff); /* API oddity: If successful, SetFilePointer() returns a dword ** containing the lower 32-bits of the new file-offset. Or, if it fails, ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine ** whether an error has actually occurred, it is also necessary to call ** GetLastError(). */ dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); if( (dwRet==INVALID_SET_FILE_POINTER && ((lastErrno = osGetLastError())!=NO_ERROR)) ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, "winSeekFile", pFile->zPath); OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); return 1; } OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); return 0; #else /* ** Same as above, except that this implementation works for WinRT. */ LARGE_INTEGER x; /* The new offset */ BOOL bRet; /* Value returned by SetFilePointerEx() */ x.QuadPart = iOffset; bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN); if(!bRet){ pFile->lastErrno = osGetLastError(); winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, "winSeekFile", pFile->zPath); OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); return 1; } OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); return 0; #endif } #if SQLITE_MAX_MMAP_SIZE>0 /* Forward references to VFS helper methods used for memory mapped files */ static int winMapfile(winFile*, sqlite3_int64); static int winUnmapfile(winFile*); #endif /* ** Close a file. ** ** It is reported that an attempt to close a handle might sometimes ** fail. This is a very unreasonable result, but Windows is notorious ** for being unreasonable so I do not doubt that it might happen. If ** the close fails, we pause for 100 milliseconds and try again. As ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before ** giving up and returning an error. */ #define MX_CLOSE_ATTEMPT 3 static int winClose(sqlite3_file *id){ int rc, cnt = 0; winFile *pFile = (winFile*)id; assert( id!=0 ); #ifndef SQLITE_OMIT_WAL assert( pFile->pShm==0 ); #endif assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE ); OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n", osGetCurrentProcessId(), pFile, pFile->h)); #if SQLITE_MAX_MMAP_SIZE>0 winUnmapfile(pFile); #endif do{ rc = osCloseHandle(pFile->h); /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); #if SQLITE_OS_WINCE #define WINCE_DELETION_ATTEMPTS 3 { winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData; if( pAppData==NULL || !pAppData->bNoLock ){ winceDestroyLock(pFile); } } if( pFile->zDeleteOnClose ){ int cnt = 0; while( osDeleteFileW(pFile->zDeleteOnClose)==0 && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff && cnt++ < WINCE_DELETION_ATTEMPTS ){ sqlite3_win32_sleep(100); /* Wait a little before trying again */ } sqlite3_free(pFile->zDeleteOnClose); } #endif if( rc ){ pFile->h = NULL; } OpenCounter(-1); OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n", osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed")); return rc ? SQLITE_OK : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(), "winClose", pFile->zPath); } /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ static int winRead( sqlite3_file *id, /* File to read from */ void *pBuf, /* Write content into this buffer */ int amt, /* Number of bytes to read */ sqlite3_int64 offset /* Begin reading at this offset */ ){ #if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) OVERLAPPED overlapped; /* The offset for ReadFile. */ #endif winFile *pFile = (winFile*)id; /* file handle */ DWORD nRead; /* Number of bytes actually read from file */ int nRetry = 0; /* Number of retrys */ assert( id!=0 ); assert( amt>0 ); assert( offset>=0 ); SimulateIOError(return SQLITE_IOERR_READ); OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, " "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, pFile->h, pBuf, amt, offset, pFile->locktype)); #if SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this read request as possible by transferring ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt); OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; }else{ int nCopy = (int)(pFile->mmapSize - offset); memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy); pBuf = &((u8 *)pBuf)[nCopy]; amt -= nCopy; offset += nCopy; } } #endif #if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) if( winSeekFile(pFile, offset) ){ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n", osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_FULL; } while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ #else memset(&overlapped, 0, sizeof(OVERLAPPED)); overlapped.Offset = (LONG)(offset & 0xffffffff); overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); while( !osReadFile(pFile->h, pBuf, amt, &nRead, &overlapped) && osGetLastError()!=ERROR_HANDLE_EOF ){ #endif DWORD lastErrno; if( winRetryIoerr(&nRetry, &lastErrno) ) continue; pFile->lastErrno = lastErrno; OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n", osGetCurrentProcessId(), pFile, pFile->h)); return winLogError(SQLITE_IOERR_READ, pFile->lastErrno, "winRead", pFile->zPath); } winLogIoerr(nRetry, __LINE__); if( nRead<(DWORD)amt ){ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[nRead], 0, amt-nRead); OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n", osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_IOERR_SHORT_READ; } OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; } /* ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ static int winWrite( sqlite3_file *id, /* File to write into */ const void *pBuf, /* The bytes to be written */ int amt, /* Number of bytes to write */ sqlite3_int64 offset /* Offset into the file to begin writing at */ ){ int rc = 0; /* True if error has occurred, else false */ winFile *pFile = (winFile*)id; /* File handle */ int nRetry = 0; /* Number of retries */ assert( amt>0 ); assert( pFile ); SimulateIOError(return SQLITE_IOERR_WRITE); SimulateDiskfullError(return SQLITE_FULL); OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, " "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, pFile->h, pBuf, amt, offset, pFile->locktype)); #if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this write request as possible by transferring ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt); OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; }else{ int nCopy = (int)(pFile->mmapSize - offset); memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy); pBuf = &((u8 *)pBuf)[nCopy]; amt -= nCopy; offset += nCopy; } } #endif #if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) rc = winSeekFile(pFile, offset); if( rc==0 ){ #else { #endif #if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) OVERLAPPED overlapped; /* The offset for WriteFile. */ #endif u8 *aRem = (u8 *)pBuf; /* Data yet to be written */ int nRem = amt; /* Number of bytes yet to be written */ DWORD nWrite; /* Bytes written by each WriteFile() call */ DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */ #if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) memset(&overlapped, 0, sizeof(OVERLAPPED)); overlapped.Offset = (LONG)(offset & 0xffffffff); overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); #endif while( nRem>0 ){ #if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){ #else if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){ #endif if( winRetryIoerr(&nRetry, &lastErrno) ) continue; break; } assert( nWrite==0 || nWrite<=(DWORD)nRem ); if( nWrite==0 || nWrite>(DWORD)nRem ){ lastErrno = osGetLastError(); break; } #if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) offset += nWrite; overlapped.Offset = (LONG)(offset & 0xffffffff); overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); #endif aRem += nWrite; nRem -= nWrite; } if( nRem>0 ){ pFile->lastErrno = lastErrno; rc = 1; } } if( rc ){ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ) || ( pFile->lastErrno==ERROR_DISK_FULL )){ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n", osGetCurrentProcessId(), pFile, pFile->h)); return winLogError(SQLITE_FULL, pFile->lastErrno, "winWrite1", pFile->zPath); } OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n", osGetCurrentProcessId(), pFile, pFile->h)); return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno, "winWrite2", pFile->zPath); }else{ winLogIoerr(nRetry, __LINE__); } OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; } /* ** Truncate an open file to a specified size */ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ winFile *pFile = (winFile*)id; /* File handle object */ int rc = SQLITE_OK; /* Return code for this function */ DWORD lastErrno; #if SQLITE_MAX_MMAP_SIZE>0 sqlite3_int64 oldMmapSize; if( pFile->nFetchOut>0 ){ /* File truncation is a no-op if there are outstanding memory mapped ** pages. This is because truncating the file means temporarily unmapping ** the file, and that might delete memory out from under existing cursors. ** ** This can result in incremental vacuum not truncating the file, ** if there is an active read cursor when the incremental vacuum occurs. ** No real harm comes of this - the database file is not corrupted, ** though some folks might complain that the file is bigger than it ** needs to be. ** ** The only feasible work-around is to defer the truncation until after ** all references to memory-mapped content are closed. That is doable, ** but involves adding a few branches in the common write code path which ** could slow down normal operations slightly. Hence, we have decided for ** now to simply make transactions a no-op if there are pending reads. We ** can maybe revisit this decision in the future. */ return SQLITE_OK; } #endif assert( pFile ); SimulateIOError(return SQLITE_IOERR_TRUNCATE); OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype)); /* If the user has configured a chunk-size for this file, truncate the ** file so that it consists of an integer number of chunks (i.e. the ** actual file size after the operation may be larger than the requested ** size). */ if( pFile->szChunk>0 ){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } #if SQLITE_MAX_MMAP_SIZE>0 if( pFile->pMapRegion ){ oldMmapSize = pFile->mmapSize; }else{ oldMmapSize = 0; } winUnmapfile(pFile); #endif /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ if( winSeekFile(pFile, nByte) ){ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, "winTruncate1", pFile->zPath); }else if( 0==osSetEndOfFile(pFile->h) && ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){ pFile->lastErrno = lastErrno; rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, "winTruncate2", pFile->zPath); } #if SQLITE_MAX_MMAP_SIZE>0 if( rc==SQLITE_OK && oldMmapSize>0 ){ if( oldMmapSize>nByte ){ winMapfile(pFile, -1); }else{ winMapfile(pFile, oldMmapSize); } } #endif OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n", osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc))); return rc; } #ifdef SQLITE_TEST /* ** Count the number of fullsyncs and normal syncs. This is used to test ** that syncs and fullsyncs are occurring at the right times. */ SQLITE_API int sqlite3_sync_count = 0; SQLITE_API int sqlite3_fullsync_count = 0; #endif /* ** Make sure all writes to a particular file are committed to disk. */ static int winSync(sqlite3_file *id, int flags){ #ifndef SQLITE_NO_SYNC /* ** Used only when SQLITE_NO_SYNC is not defined. */ BOOL rc; #endif #if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \ defined(SQLITE_HAVE_OS_TRACE) /* ** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or ** OSTRACE() macros. */ winFile *pFile = (winFile*)id; #else UNUSED_PARAMETER(id); #endif assert( pFile ); /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ assert((flags&0x0F)==SQLITE_SYNC_NORMAL || (flags&0x0F)==SQLITE_SYNC_FULL ); /* Unix cannot, but some systems may return SQLITE_FULL from here. This ** line is to test that doing so does not cause any problems. */ SimulateDiskfullError( return SQLITE_FULL ); OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n", osGetCurrentProcessId(), pFile, pFile->h, flags, pFile->locktype)); #ifndef SQLITE_TEST UNUSED_PARAMETER(flags); #else if( (flags&0x0F)==SQLITE_SYNC_FULL ){ sqlite3_fullsync_count++; } sqlite3_sync_count++; #endif /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a ** no-op */ #ifdef SQLITE_NO_SYNC OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; #else #if SQLITE_MAX_MMAP_SIZE>0 if( pFile->pMapRegion ){ if( osFlushViewOfFile(pFile->pMapRegion, 0) ){ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, " "rc=SQLITE_OK\n", osGetCurrentProcessId(), pFile, pFile->pMapRegion)); }else{ pFile->lastErrno = osGetLastError(); OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, " "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile, pFile->pMapRegion)); return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, "winSync1", pFile->zPath); } } #endif rc = osFlushFileBuffers(pFile->h); SimulateIOError( rc=FALSE ); if( rc ){ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), pFile, pFile->h)); return SQLITE_OK; }else{ pFile->lastErrno = osGetLastError(); OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n", osGetCurrentProcessId(), pFile, pFile->h)); return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno, "winSync2", pFile->zPath); } #endif } /* ** Determine the current size of a file in bytes */ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ winFile *pFile = (winFile*)id; int rc = SQLITE_OK; assert( id!=0 ); assert( pSize!=0 ); SimulateIOError(return SQLITE_IOERR_FSTAT); OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize)); #if SQLITE_OS_WINRT { FILE_STANDARD_INFO info; if( osGetFileInformationByHandleEx(pFile->h, FileStandardInfo, &info, sizeof(info)) ){ *pSize = info.EndOfFile.QuadPart; }else{ pFile->lastErrno = osGetLastError(); rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, "winFileSize", pFile->zPath); } } #else { DWORD upperBits; DWORD lowerBits; DWORD lastErrno; lowerBits = osGetFileSize(pFile->h, &upperBits); *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; if( (lowerBits == INVALID_FILE_SIZE) && ((lastErrno = osGetLastError())!=NO_ERROR) ){ pFile->lastErrno = lastErrno; rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, "winFileSize", pFile->zPath); } } #endif OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n", pFile->h, pSize, *pSize, sqlite3ErrName(rc))); return rc; } /* ** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. */ #ifndef LOCKFILE_FAIL_IMMEDIATELY # define LOCKFILE_FAIL_IMMEDIATELY 1 #endif #ifndef LOCKFILE_EXCLUSIVE_LOCK # define LOCKFILE_EXCLUSIVE_LOCK 2 #endif /* ** Historically, SQLite has used both the LockFile and LockFileEx functions. ** When the LockFile function was used, it was always expected to fail ** immediately if the lock could not be obtained. Also, it always expected to ** obtain an exclusive lock. These flags are used with the LockFileEx function ** and reflect those expectations; therefore, they should not be changed. */ #ifndef SQLITE_LOCKFILE_FLAGS # define SQLITE_LOCKFILE_FLAGS (LOCKFILE_FAIL_IMMEDIATELY | \ LOCKFILE_EXCLUSIVE_LOCK) #endif /* ** Currently, SQLite never calls the LockFileEx function without wanting the ** call to fail immediately if the lock cannot be obtained. */ #ifndef SQLITE_LOCKFILEEX_FLAGS # define SQLITE_LOCKFILEEX_FLAGS (LOCKFILE_FAIL_IMMEDIATELY) #endif /* ** Acquire a reader lock. ** Different API routines are called depending on whether or not this ** is Win9x or WinNT. */ static int winGetReadLock(winFile *pFile){ int res; OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); if( osIsNT() ){ #if SQLITE_OS_WINCE /* ** NOTE: Windows CE is handled differently here due its lack of the Win32 ** API LockFileEx. */ res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0); #else res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0, SHARED_SIZE, 0); #endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ int lk; sqlite3_randomness(sizeof(lk), &lk); pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1)); res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } #endif if( res == 0 ){ pFile->lastErrno = osGetLastError(); /* No need to log a failure to lock */ } OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res)); return res; } /* ** Undo a readlock */ static int winUnlockReadLock(winFile *pFile){ int res; DWORD lastErrno; OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); if( osIsNT() ){ res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); } #ifdef SQLITE_WIN32_HAS_ANSI else{ res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } #endif if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, "winUnlockReadLock", pFile->zPath); } OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res)); return res; } /* ** Lock the file with the lock specified by parameter locktype - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK ** (3) PENDING_LOCK ** (4) EXCLUSIVE_LOCK ** ** Sometimes when requesting one lock state, additional lock states ** are inserted in between. The locking might fail on one of the later ** transitions leaving the lock state different from what it started but ** still short of its goal. The following chart shows the allowed ** transitions and the inserted intermediate states: ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED ** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** ** This routine will only increase a lock. The winUnlock() routine ** erases all locks at once and returns us immediately to locking level 0. ** It is not possible to lower the locking level one step at a time. You ** must go straight to locking level 0. */ static int winLock(sqlite3_file *id, int locktype){ int rc = SQLITE_OK; /* Return code from subroutines */ int res = 1; /* Result of a Windows lock call */ int newLocktype; /* Set pFile->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ winFile *pFile = (winFile*)id; DWORD lastErrno = NO_ERROR; assert( id!=0 ); OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n", pFile->h, pFile->locktype, pFile->sharedLockByte, locktype)); /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ if( pFile->locktype>=locktype ){ OSTRACE(("LOCK-HELD file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } /* Do not allow any kind of write-lock on a read-only database */ if( (pFile->ctrlFlags & WINFILE_RDONLY)!=0 && locktype>=RESERVED_LOCK ){ return SQLITE_IOERR_LOCK; } /* Make sure the locking sequence is correct */ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of ** the PENDING_LOCK byte is temporary. */ newLocktype = pFile->locktype; if( pFile->locktype==NO_LOCK || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK) ){ int cnt = 3; while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, PENDING_BYTE, 0, 1, 0))==0 ){ /* Try 3 times to get the pending lock. This is needed to work ** around problems caused by indexing and/or anti-virus software on ** Windows systems. ** If you are using this code as a model for alternative VFSes, do not ** copy this retry logic. It is a hack intended for Windows only. */ lastErrno = osGetLastError(); OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n", pFile->h, cnt, res)); if( lastErrno==ERROR_INVALID_HANDLE ){ pFile->lastErrno = lastErrno; rc = SQLITE_IOERR_LOCK; OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n", pFile->h, cnt, sqlite3ErrName(rc))); return rc; } if( cnt ) sqlite3_win32_sleep(1); } gotPendingLock = res; if( !res ){ lastErrno = osGetLastError(); } } /* Acquire a shared lock */ if( locktype==SHARED_LOCK && res ){ assert( pFile->locktype==NO_LOCK ); res = winGetReadLock(pFile); if( res ){ newLocktype = SHARED_LOCK; }else{ lastErrno = osGetLastError(); } } /* Acquire a RESERVED lock */ if( locktype==RESERVED_LOCK && res ){ assert( pFile->locktype==SHARED_LOCK ); res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0); if( res ){ newLocktype = RESERVED_LOCK; }else{ lastErrno = osGetLastError(); } } /* Acquire a PENDING lock */ if( locktype==EXCLUSIVE_LOCK && res ){ newLocktype = PENDING_LOCK; gotPendingLock = 0; } /* Acquire an EXCLUSIVE lock */ if( locktype==EXCLUSIVE_LOCK && res ){ assert( pFile->locktype>=SHARED_LOCK ); (void)winUnlockReadLock(pFile); res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0, SHARED_SIZE, 0); if( res ){ newLocktype = EXCLUSIVE_LOCK; }else{ lastErrno = osGetLastError(); winGetReadLock(pFile); } } /* If we are holding a PENDING lock that ought to be released, then ** release it now. */ if( gotPendingLock && locktype==SHARED_LOCK ){ winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); } /* Update the state of the lock has held in the file descriptor then ** return the appropriate result code. */ if( res ){ rc = SQLITE_OK; }else{ pFile->lastErrno = lastErrno; rc = SQLITE_BUSY; OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n", pFile->h, locktype, newLocktype)); } pFile->locktype = (u8)newLocktype; OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n", pFile->h, pFile->locktype, sqlite3ErrName(rc))); return rc; } /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return ** non-zero, otherwise zero. */ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){ int res; winFile *pFile = (winFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut)); assert( id!=0 ); if( pFile->locktype>=RESERVED_LOCK ){ res = 1; OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res)); }else{ res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE,0,1,0); if( res ){ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); } res = !res; OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res)); } *pResOut = res; OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", pFile->h, pResOut, *pResOut)); return SQLITE_OK; } /* ** Lower the locking level on file descriptor id to locktype. locktype ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. ** ** It is not possible for this routine to fail if the second argument ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine ** might return SQLITE_IOERR; */ static int winUnlock(sqlite3_file *id, int locktype){ int type; winFile *pFile = (winFile*)id; int rc = SQLITE_OK; assert( pFile!=0 ); assert( locktype<=SHARED_LOCK ); OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n", pFile->h, pFile->locktype, pFile->sharedLockByte, locktype)); type = pFile->locktype; if( type>=EXCLUSIVE_LOCK ){ winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(), "winUnlock", pFile->zPath); } } if( type>=RESERVED_LOCK ){ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); } if( locktype==NO_LOCK && type>=SHARED_LOCK ){ winUnlockReadLock(pFile); } if( type>=PENDING_LOCK ){ winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); } pFile->locktype = (u8)locktype; OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n", pFile->h, pFile->locktype, sqlite3ErrName(rc))); return rc; } /****************************************************************************** ****************************** No-op Locking ********************************** ** ** Of the various locking implementations available, this is by far the ** simplest: locking is ignored. No attempt is made to lock the database ** file for reading or writing. ** ** This locking mode is appropriate for use on read-only databases ** (ex: databases that are burned into CD-ROM, for example.) It can ** also be used if the application employs some external mechanism to ** prevent simultaneous access of the same database by two or more ** database connections. But there is a serious risk of database ** corruption if this locking mode is used in situations where multiple ** database connections are accessing the same database file at the same ** time and one or more of those connections are writing. */ static int winNolockLock(sqlite3_file *id, int locktype){ UNUSED_PARAMETER(id); UNUSED_PARAMETER(locktype); return SQLITE_OK; } static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){ UNUSED_PARAMETER(id); UNUSED_PARAMETER(pResOut); return SQLITE_OK; } static int winNolockUnlock(sqlite3_file *id, int locktype){ UNUSED_PARAMETER(id); UNUSED_PARAMETER(locktype); return SQLITE_OK; } /******************* End of the no-op lock implementation ********************* ******************************************************************************/ /* ** If *pArg is initially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ** ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. */ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){ if( *pArg<0 ){ *pArg = (pFile->ctrlFlags & mask)!=0; }else if( (*pArg)==0 ){ pFile->ctrlFlags &= ~mask; }else{ pFile->ctrlFlags |= mask; } } /* Forward references to VFS helper methods used for temporary files */ static int winGetTempname(sqlite3_vfs *, char **); static int winIsDir(const void *); static BOOL winIsLongPathPrefix(const char *); static BOOL winIsDriveLetterAndColon(const char *); /* ** Control and query of the open file handle. */ static int winFileControl(sqlite3_file *id, int op, void *pArg){ winFile *pFile = (winFile*)id; OSTRACE(("FCNTL file=%p, op=%d, pArg=%p\n", pFile->h, op, pArg)); switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->locktype; OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_LAST_ERRNO: { *(int*)pArg = (int)pFile->lastErrno; OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { pFile->szChunk = *(int *)pArg; OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { if( pFile->szChunk>0 ){ sqlite3_int64 oldSz; int rc = winFileSize(id, &oldSz); if( rc==SQLITE_OK ){ sqlite3_int64 newSz = *(sqlite3_int64*)pArg; if( newSz>oldSz ){ SimulateIOErrorBenign(1); rc = winTruncate(id, newSz); SimulateIOErrorBenign(0); } } OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); return rc; } OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_PERSIST_WAL: { winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg); OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { winModeBit(pFile, WINFILE_PSOW, (int*)pArg); OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_VFSNAME: { *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName); OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_WIN32_AV_RETRY: { int *a = (int*)pArg; if( a[0]>0 ){ winIoerrRetry = a[0]; }else{ a[0] = winIoerrRetry; } if( a[1]>0 ){ winIoerrRetryDelay = a[1]; }else{ a[1] = winIoerrRetryDelay; } OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_WIN32_GET_HANDLE: { LPHANDLE phFile = (LPHANDLE)pArg; *phFile = pFile->h; OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } #ifdef SQLITE_TEST case SQLITE_FCNTL_WIN32_SET_HANDLE: { LPHANDLE phFile = (LPHANDLE)pArg; HANDLE hOldFile = pFile->h; pFile->h = *phFile; *phFile = hOldFile; OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n", hOldFile, pFile->h)); return SQLITE_OK; } #endif case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = 0; int rc = winGetTempname(pFile->pVfs, &zTFile); if( rc==SQLITE_OK ){ *(char**)pArg = zTFile; } OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); return rc; } #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; int rc = SQLITE_OK; if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } /* The value of newLimit may be eventually cast to (SIZE_T) and passed ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at ** least a 64-bit type. */ if( newLimit>0 && sizeof(SIZE_T)<8 ){ newLimit = (newLimit & 0x7FFFFFFF); } *(i64*)pArg = pFile->mmapSizeMax; if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ pFile->mmapSizeMax = newLimit; if( pFile->mmapSize>0 ){ winUnmapfile(pFile); rc = winMapfile(pFile, -1); } } OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); return rc; } #endif } OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h)); return SQLITE_NOTFOUND; } /* ** Return the sector size in bytes of the underlying block device for ** the specified file. This is almost always 512 bytes, but may be ** larger for some devices. ** ** SQLite code assumes this function cannot fail. It also assumes that ** if two files are created in the same file-system directory (i.e. ** a database and its journal file) that the sector size will be the ** same for both. */ static int winSectorSize(sqlite3_file *id){ (void)id; return SQLITE_DEFAULT_SECTOR_SIZE; } /* ** Return a vector of device characteristics. */ static int winDeviceCharacteristics(sqlite3_file *id){ winFile *p = (winFile*)id; return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0); } /* ** Windows will only let you create file view mappings ** on allocation size granularity boundaries. ** During sqlite3_os_init() we do a GetSystemInfo() ** to get the granularity size. */ static SYSTEM_INFO winSysInfo; #ifndef SQLITE_OMIT_WAL /* ** Helper functions to obtain and relinquish the global mutex. The ** global mutex is used to protect the winLockInfo objects used by ** this file, all of which may be shared by multiple threads. ** ** Function winShmMutexHeld() is used to assert() that the global mutex ** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** winShmEnterMutex() ** assert( winShmMutexHeld() ); ** winShmLeaveMutex() */ static sqlite3_mutex *winBigLock = 0; static void winShmEnterMutex(void){ sqlite3_mutex_enter(winBigLock); } static void winShmLeaveMutex(void){ sqlite3_mutex_leave(winBigLock); } #ifndef NDEBUG static int winShmMutexHeld(void) { return sqlite3_mutex_held(winBigLock); } #endif /* ** Object used to represent a single file opened and mmapped to provide ** shared memory. When multiple threads all reference the same ** log-summary, each thread has its own winFile object, but they all ** point to a single instance of this object. In other words, each ** log-summary is opened only once per process. ** ** winShmMutexHeld() must be true when creating or destroying ** this object or while reading or writing the following fields: ** ** nRef ** pNext ** ** The following fields are read-only after the object is created: ** ** fid ** zFilename ** ** Either winShmNode.mutex must be held or winShmNode.nRef==0 and ** winShmMutexHeld() is true when reading or writing any other field ** in this structure. ** */ struct winShmNode { sqlite3_mutex *mutex; /* Mutex to access this object */ char *zFilename; /* Name of the file */ winFile hFile; /* File handle from winOpen */ int szRegion; /* Size of shared-memory regions */ int nRegion; /* Size of array apRegion */ u8 isReadonly; /* True if read-only */ u8 isUnlocked; /* True if no DMS lock held */ struct ShmRegion { HANDLE hMap; /* File handle from CreateFileMapping */ void *pMap; } *aRegion; DWORD lastErrno; /* The Windows errno from the last I/O error */ int nRef; /* Number of winShm objects pointing to this */ winShm *pFirst; /* All winShm objects pointing to this */ winShmNode *pNext; /* Next in list of all winShmNode objects */ #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) u8 nextShmId; /* Next available winShm.id value */ #endif }; /* ** A global array of all winShmNode objects. ** ** The winShmMutexHeld() must be true while reading or writing this list. */ static winShmNode *winShmNodeList = 0; /* ** Structure used internally by this VFS to record the state of an ** open shared memory connection. ** ** The following fields are initialized when this object is created and ** are read-only thereafter: ** ** winShm.pShmNode ** winShm.id ** ** All other fields are read/write. The winShm.pShmNode->mutex must be held ** while accessing any read/write fields. */ struct winShm { winShmNode *pShmNode; /* The underlying winShmNode object */ winShm *pNext; /* Next winShm with the same winShmNode */ u8 hasMutex; /* True if holding the winShmNode mutex */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) u8 id; /* Id of this connection with its winShmNode */ #endif }; /* ** Constants used for locking */ #define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ /* ** Apply advisory locks for all n bytes beginning at ofst. */ #define WINSHM_UNLCK 1 #define WINSHM_RDLCK 2 #define WINSHM_WRLCK 3 static int winShmSystemLock( winShmNode *pFile, /* Apply locks to this open shared-memory segment */ int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */ int ofst, /* Offset to first byte to be locked/unlocked */ int nByte /* Number of bytes to lock or unlock */ ){ int rc = 0; /* Result code form Lock/UnlockFileEx() */ /* Access to the winShmNode object is serialized by the caller */ assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) ); OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n", pFile->hFile.h, lockType, ofst, nByte)); /* Release/Acquire the system-level lock */ if( lockType==WINSHM_UNLCK ){ rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); }else{ /* Initialize the locking parameters */ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); } if( rc!= 0 ){ rc = SQLITE_OK; }else{ pFile->lastErrno = osGetLastError(); rc = SQLITE_BUSY; } OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n", pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" : "winLockFile", pFile->lastErrno, sqlite3ErrName(rc))); return rc; } /* Forward references to VFS methods */ static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*); static int winDelete(sqlite3_vfs *,const char*,int); /* ** Purge the winShmNodeList list of all entries with winShmNode.nRef==0. ** ** This is not a VFS shared-memory method; it is a utility function called ** by VFS shared-memory methods. */ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ winShmNode **pp; winShmNode *p; assert( winShmMutexHeld() ); OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n", osGetCurrentProcessId(), deleteFlag)); pp = &winShmNodeList; while( (p = *pp)!=0 ){ if( p->nRef==0 ){ int i; if( p->mutex ){ sqlite3_mutex_free(p->mutex); } for(i=0; inRegion; i++){ BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap); OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n", osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); UNUSED_VARIABLE_VALUE(bRc); bRc = osCloseHandle(p->aRegion[i].hMap); OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n", osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); UNUSED_VARIABLE_VALUE(bRc); } if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){ SimulateIOErrorBenign(1); winClose((sqlite3_file *)&p->hFile); SimulateIOErrorBenign(0); } if( deleteFlag ){ SimulateIOErrorBenign(1); sqlite3BeginBenignMalloc(); winDelete(pVfs, p->zFilename, 0); sqlite3EndBenignMalloc(); SimulateIOErrorBenign(0); } *pp = p->pNext; sqlite3_free(p->aRegion); sqlite3_free(p); }else{ pp = &p->pNext; } } } /* ** The DMS lock has not yet been taken on shm file pShmNode. Attempt to ** take it now. Return SQLITE_OK if successful, or an SQLite error ** code otherwise. ** ** If the DMS cannot be locked because this is a readonly_shm=1 ** connection and no other process already holds a lock, return ** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1. */ static int winLockSharedMemory(winShmNode *pShmNode){ int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1); if( rc==SQLITE_OK ){ if( pShmNode->isReadonly ){ pShmNode->isUnlocked = 1; winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); return SQLITE_READONLY_CANTINIT; }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){ winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), "winLockSharedMemory", pShmNode->zFilename); } } if( rc==SQLITE_OK ){ winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); } return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); } /* ** Open the shared-memory area associated with database file pDbFd. ** ** When opening a new shared-memory file, if no other instances of that ** file are currently open, in this process or in other processes, then ** the file must be truncated to zero length or have its header cleared. */ static int winOpenSharedMemory(winFile *pDbFd){ struct winShm *p; /* The connection to be opened */ winShmNode *pShmNode = 0; /* The underlying mmapped file */ int rc = SQLITE_OK; /* Result code */ winShmNode *pNew; /* Newly allocated winShmNode */ int nName; /* Size of zName in bytes */ assert( pDbFd->pShm==0 ); /* Not previously opened */ /* Allocate space for the new sqlite3_shm object. Also speculatively ** allocate space for a new winShmNode and filename. */ p = sqlite3MallocZero( sizeof(*p) ); if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT; nName = sqlite3Strlen30(pDbFd->zPath); pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 ); if( pNew==0 ){ sqlite3_free(p); return SQLITE_IOERR_NOMEM_BKPT; } pNew->zFilename = (char*)&pNew[1]; sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); /* Look to see if there is an existing winShmNode that can be used. ** If no matching winShmNode currently exists, create a new one. */ winShmEnterMutex(); for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){ /* TBD need to come up with better match here. Perhaps ** use FILE_ID_BOTH_DIR_INFO Structure. */ if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break; } if( pShmNode ){ sqlite3_free(pNew); }else{ int inFlags = SQLITE_OPEN_WAL; int outFlags = 0; pShmNode = pNew; pNew = 0; ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE; pShmNode->pNext = winShmNodeList; winShmNodeList = pShmNode; if( sqlite3GlobalConfig.bCoreMutex ){ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( pShmNode->mutex==0 ){ rc = SQLITE_IOERR_NOMEM_BKPT; goto shm_open_err; } } if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; }else{ inFlags |= SQLITE_OPEN_READONLY; } rc = winOpen(pDbFd->pVfs, pShmNode->zFilename, (sqlite3_file*)&pShmNode->hFile, inFlags, &outFlags); if( rc!=SQLITE_OK ){ rc = winLogError(rc, osGetLastError(), "winOpenShm", pShmNode->zFilename); goto shm_open_err; } if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1; rc = winLockSharedMemory(pShmNode); if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err; } /* Make the new connection a child of the winShmNode */ p->pShmNode = pShmNode; #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) p->id = pShmNode->nextShmId++; #endif pShmNode->nRef++; pDbFd->pShm = p; winShmLeaveMutex(); /* The reference count on pShmNode has already been incremented under ** the cover of the winShmEnterMutex() mutex and the pointer from the ** new (struct winShm) object to the pShmNode has been set. All that is ** left to do is to link the new object into the linked list starting ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex ** mutex. */ sqlite3_mutex_enter(pShmNode->mutex); p->pNext = pShmNode->pFirst; pShmNode->pFirst = p; sqlite3_mutex_leave(pShmNode->mutex); return rc; /* Jump here on any error */ shm_open_err: winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */ sqlite3_free(p); sqlite3_free(pNew); winShmLeaveMutex(); return rc; } /* ** Close a connection to shared-memory. Delete the underlying ** storage if deleteFlag is true. */ static int winShmUnmap( sqlite3_file *fd, /* Database holding shared memory */ int deleteFlag /* Delete after closing if true */ ){ winFile *pDbFd; /* Database holding shared-memory */ winShm *p; /* The connection to be closed */ winShmNode *pShmNode; /* The underlying shared-memory file */ winShm **pp; /* For looping over sibling connections */ pDbFd = (winFile*)fd; p = pDbFd->pShm; if( p==0 ) return SQLITE_OK; pShmNode = p->pShmNode; /* Remove connection p from the set of connections associated ** with pShmNode */ sqlite3_mutex_enter(pShmNode->mutex); for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} *pp = p->pNext; /* Free the connection p */ sqlite3_free(p); pDbFd->pShm = 0; sqlite3_mutex_leave(pShmNode->mutex); /* If pShmNode->nRef has reached 0, then close the underlying ** shared-memory file, too */ winShmEnterMutex(); assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ winShmPurge(pDbFd->pVfs, deleteFlag); } winShmLeaveMutex(); return SQLITE_OK; } /* ** Change the lock state for a shared-memory segment. */ static int winShmLock( sqlite3_file *fd, /* Database file holding the shared memory */ int ofst, /* First lock to acquire or release */ int n, /* Number of locks to acquire or release */ int flags /* What to do with the lock */ ){ winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */ winShm *p = pDbFd->pShm; /* The shared memory being locked */ winShm *pX; /* For looping over all siblings */ winShmNode *pShmNode; int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ if( p==0 ) return SQLITE_IOERR_SHMLOCK; pShmNode = p->pShmNode; if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); assert( n>=1 ); assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); mask = (u16)((1U<<(ofst+n)) - (1U<1 || mask==(1<mutex); if( flags & SQLITE_SHM_UNLOCK ){ u16 allMask = 0; /* Mask of locks held by siblings */ /* See if any siblings hold this same lock */ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ if( pX==p ) continue; assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); allMask |= pX->sharedMask; } /* Unlock the system-level locks */ if( (mask & allMask)==0 ){ rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n); }else{ rc = SQLITE_OK; } /* Undo the local locks */ if( rc==SQLITE_OK ){ p->exclMask &= ~mask; p->sharedMask &= ~mask; } }else if( flags & SQLITE_SHM_SHARED ){ u16 allShared = 0; /* Union of locks held by connections other than "p" */ /* Find out which shared locks are already held by sibling connections. ** If any sibling already holds an exclusive lock, go ahead and return ** SQLITE_BUSY. */ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ if( (pX->exclMask & mask)!=0 ){ rc = SQLITE_BUSY; break; } allShared |= pX->sharedMask; } /* Get shared locks at the system level, if necessary */ if( rc==SQLITE_OK ){ if( (allShared & mask)==0 ){ rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n); }else{ rc = SQLITE_OK; } } /* Get the local shared locks */ if( rc==SQLITE_OK ){ p->sharedMask |= mask; } }else{ /* Make sure no sibling connections hold locks that will block this ** lock. If any do, return SQLITE_BUSY right away. */ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ rc = SQLITE_BUSY; break; } } /* Get the exclusive locks at the system level. Then if successful ** also mark the local connection as being locked. */ if( rc==SQLITE_OK ){ rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n); if( rc==SQLITE_OK ){ assert( (p->sharedMask & mask)==0 ); p->exclMask |= mask; } } } sqlite3_mutex_leave(pShmNode->mutex); OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n", osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask, sqlite3ErrName(rc))); return rc; } /* ** Implement a memory barrier or memory fence on shared memory. ** ** All loads and stores begun before the barrier must complete before ** any load or store begun after the barrier. */ static void winShmBarrier( sqlite3_file *fd /* Database holding the shared memory */ ){ UNUSED_PARAMETER(fd); sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ winShmEnterMutex(); /* Also mutex, for redundancy */ winShmLeaveMutex(); } /* ** This function is called to obtain a pointer to region iRegion of the ** shared-memory associated with the database file fd. Shared-memory regions ** are numbered starting from zero. Each shared-memory region is szRegion ** bytes in size. ** ** If an error occurs, an error code is returned and *pp is set to NULL. ** ** Otherwise, if the isWrite parameter is 0 and the requested shared-memory ** region has not been allocated (by any client, including one running in a ** separate process), then *pp is set to NULL and SQLITE_OK returned. If ** isWrite is non-zero and the requested shared-memory region has not yet ** been allocated, it is allocated by this function. ** ** If the shared-memory region has already been allocated or is allocated by ** this call as described above, then it is mapped into this processes ** address space (if it is not already), *pp is set to point to the mapped ** memory and SQLITE_OK returned. */ static int winShmMap( sqlite3_file *fd, /* Handle open on database file */ int iRegion, /* Region to retrieve */ int szRegion, /* Size of regions */ int isWrite, /* True to extend file if necessary */ void volatile **pp /* OUT: Mapped memory */ ){ winFile *pDbFd = (winFile*)fd; winShm *pShm = pDbFd->pShm; winShmNode *pShmNode; DWORD protect = PAGE_READWRITE; DWORD flags = FILE_MAP_WRITE | FILE_MAP_READ; int rc = SQLITE_OK; if( !pShm ){ rc = winOpenSharedMemory(pDbFd); if( rc!=SQLITE_OK ) return rc; pShm = pDbFd->pShm; assert( pShm!=0 ); } pShmNode = pShm->pShmNode; sqlite3_mutex_enter(pShmNode->mutex); if( pShmNode->isUnlocked ){ rc = winLockSharedMemory(pShmNode); if( rc!=SQLITE_OK ) goto shmpage_out; pShmNode->isUnlocked = 0; } assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); if( pShmNode->nRegion<=iRegion ){ struct ShmRegion *apNew; /* New aRegion[] array */ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */ sqlite3_int64 sz; /* Current size of wal-index file */ pShmNode->szRegion = szRegion; /* The requested region is not mapped into this processes address space. ** Check to see if it has been allocated (i.e. if the wal-index file is ** large enough to contain the requested region). */ rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz); if( rc!=SQLITE_OK ){ rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(), "winShmMap1", pDbFd->zPath); goto shmpage_out; } if( szhFile, nByte); if( rc!=SQLITE_OK ){ rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(), "winShmMap2", pDbFd->zPath); goto shmpage_out; } } /* Map the requested memory region into this processes address space. */ apNew = (struct ShmRegion *)sqlite3_realloc64( pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0]) ); if( !apNew ){ rc = SQLITE_IOERR_NOMEM_BKPT; goto shmpage_out; } pShmNode->aRegion = apNew; if( pShmNode->isReadonly ){ protect = PAGE_READONLY; flags = FILE_MAP_READ; } while( pShmNode->nRegion<=iRegion ){ HANDLE hMap = NULL; /* file-mapping handle */ void *pMap = 0; /* Mapped memory region */ #if SQLITE_OS_WINRT hMap = osCreateFileMappingFromApp(pShmNode->hFile.h, NULL, protect, nByte, NULL ); #elif defined(SQLITE_WIN32_HAS_WIDE) hMap = osCreateFileMappingW(pShmNode->hFile.h, NULL, protect, 0, nByte, NULL ); #elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA hMap = osCreateFileMappingA(pShmNode->hFile.h, NULL, protect, 0, nByte, NULL ); #endif OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, nByte, hMap ? "ok" : "failed")); if( hMap ){ int iOffset = pShmNode->nRegion*szRegion; int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; #if SQLITE_OS_WINRT pMap = osMapViewOfFileFromApp(hMap, flags, iOffset - iOffsetShift, szRegion + iOffsetShift ); #else pMap = osMapViewOfFile(hMap, flags, 0, iOffset - iOffsetShift, szRegion + iOffsetShift ); #endif OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion, pMap ? "ok" : "failed")); } if( !pMap ){ pShmNode->lastErrno = osGetLastError(); rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno, "winShmMap3", pDbFd->zPath); if( hMap ) osCloseHandle(hMap); goto shmpage_out; } pShmNode->aRegion[pShmNode->nRegion].pMap = pMap; pShmNode->aRegion[pShmNode->nRegion].hMap = hMap; pShmNode->nRegion++; } } shmpage_out: if( pShmNode->nRegion>iRegion ){ int iOffset = iRegion*szRegion; int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; char *p = (char *)pShmNode->aRegion[iRegion].pMap; *pp = (void *)&p[iOffsetShift]; }else{ *pp = 0; } if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; sqlite3_mutex_leave(pShmNode->mutex); return rc; } #else # define winShmMap 0 # define winShmLock 0 # define winShmBarrier 0 # define winShmUnmap 0 #endif /* #ifndef SQLITE_OMIT_WAL */ /* ** Cleans up the mapped region of the specified file, if any. */ #if SQLITE_MAX_MMAP_SIZE>0 static int winUnmapfile(winFile *pFile){ assert( pFile!=0 ); OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, " "mmapSize=%lld, mmapSizeMax=%lld\n", osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion, pFile->mmapSize, pFile->mmapSizeMax)); if( pFile->pMapRegion ){ if( !osUnmapViewOfFile(pFile->pMapRegion) ){ pFile->lastErrno = osGetLastError(); OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, pMapRegion=%p, " "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile, pFile->pMapRegion)); return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, "winUnmapfile1", pFile->zPath); } pFile->pMapRegion = 0; pFile->mmapSize = 0; } if( pFile->hMap!=NULL ){ if( !osCloseHandle(pFile->hMap) ){ pFile->lastErrno = osGetLastError(); OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile, pFile->hMap)); return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, "winUnmapfile2", pFile->zPath); } pFile->hMap = NULL; } OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), pFile)); return SQLITE_OK; } /* ** Memory map or remap the file opened by file-descriptor pFd (if the file ** is already mapped, the existing mapping is replaced by the new). Or, if ** there already exists a mapping for this file, and there are still ** outstanding xFetch() references to it, this function is a no-op. ** ** If parameter nByte is non-negative, then it is the requested size of ** the mapping to create. Otherwise, if nByte is less than zero, then the ** requested size is the size of the file on disk. The actual size of the ** created mapping is either the requested size or the value configured ** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller. ** ** SQLITE_OK is returned if no error occurs (even if the mapping is not ** recreated as a result of outstanding references) or an SQLite error ** code otherwise. */ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ sqlite3_int64 nMap = nByte; int rc; assert( nMap>=0 || pFd->nFetchOut==0 ); OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n", osGetCurrentProcessId(), pFd, nByte)); if( pFd->nFetchOut>0 ) return SQLITE_OK; if( nMap<0 ){ rc = winFileSize((sqlite3_file*)pFd, &nMap); if( rc ){ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_IOERR_FSTAT\n", osGetCurrentProcessId(), pFd)); return SQLITE_IOERR_FSTAT; } } if( nMap>pFd->mmapSizeMax ){ nMap = pFd->mmapSizeMax; } nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1); if( nMap==0 && pFd->mmapSize>0 ){ winUnmapfile(pFd); } if( nMap!=pFd->mmapSize ){ void *pNew = 0; DWORD protect = PAGE_READONLY; DWORD flags = FILE_MAP_READ; winUnmapfile(pFd); #ifdef SQLITE_MMAP_READWRITE if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){ protect = PAGE_READWRITE; flags |= FILE_MAP_WRITE; } #endif #if SQLITE_OS_WINRT pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL); #elif defined(SQLITE_WIN32_HAS_WIDE) pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect, (DWORD)((nMap>>32) & 0xffffffff), (DWORD)(nMap & 0xffffffff), NULL); #elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect, (DWORD)((nMap>>32) & 0xffffffff), (DWORD)(nMap & 0xffffffff), NULL); #endif if( pFd->hMap==NULL ){ pFd->lastErrno = osGetLastError(); rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno, "winMapfile1", pFd->zPath); /* Log the error, but continue normal operation using xRead/xWrite */ OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=%s\n", osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); return SQLITE_OK; } assert( (nMap % winSysInfo.dwPageSize)==0 ); assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff ); #if SQLITE_OS_WINRT pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap); #else pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap); #endif if( pNew==NULL ){ osCloseHandle(pFd->hMap); pFd->hMap = NULL; pFd->lastErrno = osGetLastError(); rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno, "winMapfile2", pFd->zPath); /* Log the error, but continue normal operation using xRead/xWrite */ OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=%s\n", osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); return SQLITE_OK; } pFd->pMapRegion = pNew; pFd->mmapSize = nMap; } OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), pFd)); return SQLITE_OK; } #endif /* SQLITE_MAX_MMAP_SIZE>0 */ /* ** If possible, return a pointer to a mapping of file fd starting at offset ** iOff. The mapping must be valid for at least nAmt bytes. ** ** If such a pointer can be obtained, store it in *pp and return SQLITE_OK. ** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK. ** Finally, if an error does occur, return an SQLite error code. The final ** value of *pp is undefined in this case. ** ** If this function does return a pointer, the caller must eventually ** release the reference by calling winUnfetch(). */ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ #if SQLITE_MAX_MMAP_SIZE>0 winFile *pFd = (winFile*)fd; /* The underlying database file */ #endif *pp = 0; OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n", osGetCurrentProcessId(), fd, iOff, nAmt, pp)); #if SQLITE_MAX_MMAP_SIZE>0 if( pFd->mmapSizeMax>0 ){ /* Ensure that there is always at least a 256 byte buffer of addressable ** memory following the returned page. If the database is corrupt, ** SQLite may overread the page slightly (in practice only a few bytes, ** but 256 is safe, round, number). */ const int nEofBuffer = 256; if( pFd->pMapRegion==0 ){ int rc = winMapfile(pFd, -1); if( rc!=SQLITE_OK ){ OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n", osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); return rc; } } if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){ assert( pFd->pMapRegion!=0 ); *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; } } #endif OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), fd, pp, *pp)); return SQLITE_OK; } /* ** If the third argument is non-NULL, then this function releases a ** reference obtained by an earlier call to winFetch(). The second ** argument passed to this function must be the same as the corresponding ** argument that was passed to the winFetch() invocation. ** ** Or, if the third argument is NULL, then this function is being called ** to inform the VFS layer that, according to POSIX, any existing mapping ** may now be invalid and should be unmapped. */ static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){ #if SQLITE_MAX_MMAP_SIZE>0 winFile *pFd = (winFile*)fd; /* The underlying database file */ /* If p==0 (unmap the entire file) then there must be no outstanding ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), ** then there must be at least one outstanding. */ assert( (p==0)==(pFd->nFetchOut==0) ); /* If p!=0, it must match the iOff value. */ assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] ); OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n", osGetCurrentProcessId(), pFd, iOff, p)); if( p ){ pFd->nFetchOut--; }else{ /* FIXME: If Windows truly always prevents truncating or deleting a ** file while a mapping is held, then the following winUnmapfile() call ** is unnecessary can be omitted - potentially improving ** performance. */ winUnmapfile(pFd); } assert( pFd->nFetchOut>=0 ); #endif OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), fd)); return SQLITE_OK; } /* ** Here ends the implementation of all sqlite3_file methods. ** ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ /* ** This vector defines all the methods that can operate on an ** sqlite3_file for win32. */ static const sqlite3_io_methods winIoMethod = { 3, /* iVersion */ winClose, /* xClose */ winRead, /* xRead */ winWrite, /* xWrite */ winTruncate, /* xTruncate */ winSync, /* xSync */ winFileSize, /* xFileSize */ winLock, /* xLock */ winUnlock, /* xUnlock */ winCheckReservedLock, /* xCheckReservedLock */ winFileControl, /* xFileControl */ winSectorSize, /* xSectorSize */ winDeviceCharacteristics, /* xDeviceCharacteristics */ winShmMap, /* xShmMap */ winShmLock, /* xShmLock */ winShmBarrier, /* xShmBarrier */ winShmUnmap, /* xShmUnmap */ winFetch, /* xFetch */ winUnfetch /* xUnfetch */ }; /* ** This vector defines all the methods that can operate on an ** sqlite3_file for win32 without performing any locking. */ static const sqlite3_io_methods winIoNolockMethod = { 3, /* iVersion */ winClose, /* xClose */ winRead, /* xRead */ winWrite, /* xWrite */ winTruncate, /* xTruncate */ winSync, /* xSync */ winFileSize, /* xFileSize */ winNolockLock, /* xLock */ winNolockUnlock, /* xUnlock */ winNolockCheckReservedLock, /* xCheckReservedLock */ winFileControl, /* xFileControl */ winSectorSize, /* xSectorSize */ winDeviceCharacteristics, /* xDeviceCharacteristics */ winShmMap, /* xShmMap */ winShmLock, /* xShmLock */ winShmBarrier, /* xShmBarrier */ winShmUnmap, /* xShmUnmap */ winFetch, /* xFetch */ winUnfetch /* xUnfetch */ }; static winVfsAppData winAppData = { &winIoMethod, /* pMethod */ 0, /* pAppData */ 0 /* bNoLock */ }; static winVfsAppData winNolockAppData = { &winIoNolockMethod, /* pMethod */ 0, /* pAppData */ 1 /* bNoLock */ }; /**************************************************************************** **************************** sqlite3_vfs methods **************************** ** ** This division contains the implementation of methods on the ** sqlite3_vfs object. */ #if defined(__CYGWIN__) /* ** Convert a filename from whatever the underlying operating system ** supports for filenames into UTF-8. Space to hold the result is ** obtained from malloc and must be freed by the calling function. */ static char *winConvertToUtf8Filename(const void *zFilename){ char *zConverted = 0; if( osIsNT() ){ zConverted = winUnicodeToUtf8(zFilename); } #ifdef SQLITE_WIN32_HAS_ANSI else{ zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI()); } #endif /* caller will handle out of memory */ return zConverted; } #endif /* ** Convert a UTF-8 filename into whatever form the underlying ** operating system wants filenames in. Space to hold the result ** is obtained from malloc and must be freed by the calling ** function. */ static void *winConvertFromUtf8Filename(const char *zFilename){ void *zConverted = 0; if( osIsNT() ){ zConverted = winUtf8ToUnicode(zFilename); } #ifdef SQLITE_WIN32_HAS_ANSI else{ zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); } #endif /* caller will handle out of memory */ return zConverted; } /* ** This function returns non-zero if the specified UTF-8 string buffer ** ends with a directory separator character or one was successfully ** added to it. */ static int winMakeEndInDirSep(int nBuf, char *zBuf){ if( zBuf ){ int nLen = sqlite3Strlen30(zBuf); if( nLen>0 ){ if( winIsDirSep(zBuf[nLen-1]) ){ return 1; }else if( nLen+1mxPathname; nBuf = nMax + 2; zBuf = sqlite3MallocZero( nBuf ); if( !zBuf ){ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); return SQLITE_IOERR_NOMEM_BKPT; } /* Figure out the effective temporary directory. First, check if one ** has been explicitly set by the application; otherwise, use the one ** configured by the operating system. */ nDir = nMax - (nPre + 15); assert( nDir>0 ); if( winTempDirDefined() ){ int nDirLen = sqlite3Strlen30(sqlite3_temp_directory); if( nDirLen>0 ){ if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){ nDirLen++; } if( nDirLen>nDir ){ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n")); return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0); } sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory); } sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); } #if defined(__CYGWIN__) else{ static const char *azDirs[] = { 0, /* getenv("SQLITE_TMPDIR") */ 0, /* getenv("TMPDIR") */ 0, /* getenv("TMP") */ 0, /* getenv("TEMP") */ 0, /* getenv("USERPROFILE") */ "/var/tmp", "/usr/tmp", "/tmp", ".", 0 /* List terminator */ }; unsigned int i; const char *zDir = 0; if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); if( !azDirs[2] ) azDirs[2] = getenv("TMP"); if( !azDirs[3] ) azDirs[3] = getenv("TEMP"); if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE"); for(i=0; i/etilqs_XXXXXXXXXXXXXXX\0\0" ** ** If not, return SQLITE_ERROR. The number 17 is used here in order to ** account for the space used by the 15 character random suffix and the ** two trailing NUL characters. The final directory separator character ** has already added if it was not already present. */ nLen = sqlite3Strlen30(zBuf); if( (nLen + nPre + 17) > nBuf ){ sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n")); return winLogError(SQLITE_ERROR, 0, "winGetTempname5", 0); } sqlite3_snprintf(nBuf-16-nLen, zBuf+nLen, SQLITE_TEMP_FILE_PREFIX); j = sqlite3Strlen30(zBuf); sqlite3_randomness(15, &zBuf[j]); pid = osGetCurrentProcessId(); for(i=0; i<15; i++, j++){ zBuf[j] += pid & 0xff; pid >>= 8; zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; } zBuf[j] = 0; zBuf[j+1] = 0; *pzBuf = zBuf; OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf)); return SQLITE_OK; } /* ** Return TRUE if the named file is really a directory. Return false if ** it is something other than a directory, or if there is any kind of memory ** allocation failure. */ static int winIsDir(const void *zConverted){ DWORD attr; int rc = 0; DWORD lastErrno; if( osIsNT() ){ int cnt = 0; WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, GetFileExInfoStandard, &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} if( !rc ){ return 0; /* Invalid name? */ } attr = sAttrData.dwFileAttributes; #if SQLITE_OS_WINCE==0 }else{ attr = osGetFileAttributesA((char*)zConverted); #endif } return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY); } /* forward reference */ static int winAccess( sqlite3_vfs *pVfs, /* Not used on win32 */ const char *zFilename, /* Name of file to check */ int flags, /* Type of test to make on this file */ int *pResOut /* OUT: Result */ ); /* ** Open a file. */ static int winOpen( sqlite3_vfs *pVfs, /* Used to get maximum path length and AppData */ const char *zName, /* Name of the file (UTF-8) */ sqlite3_file *id, /* Write the SQLite file handle here */ int flags, /* Open mode flags */ int *pOutFlags /* Status return flags */ ){ HANDLE h; DWORD lastErrno = 0; DWORD dwDesiredAccess; DWORD dwShareMode; DWORD dwCreationDisposition; DWORD dwFlagsAndAttributes = 0; #if SQLITE_OS_WINCE int isTemp = 0; #endif winVfsAppData *pAppData; winFile *pFile = (winFile*)id; void *zConverted; /* Filename in OS encoding */ const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ int cnt = 0; /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. */ char *zTmpname = 0; /* For temporary filename, if necessary. */ int rc = SQLITE_OK; /* Function Return Code */ #if !defined(NDEBUG) || SQLITE_OS_WINCE int eType = flags&0xFFFFFF00; /* Type of file to open */ #endif int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isCreate = (flags & SQLITE_OPEN_CREATE); int isReadonly = (flags & SQLITE_OPEN_READONLY); int isReadWrite = (flags & SQLITE_OPEN_READWRITE); #ifndef NDEBUG int isOpenJournal = (isCreate && ( eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_WAL )); #endif OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n", zUtf8Name, id, flags, pOutFlags)); /* Check the following statements are true: ** ** (a) Exactly one of the READWRITE and READONLY flags must be set, and ** (b) if CREATE is set, then READWRITE must also be set, and ** (c) if EXCLUSIVE is set, then CREATE must also be set. ** (d) if DELETEONCLOSE is set, then CREATE must also be set. */ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); assert(isCreate==0 || isReadWrite); assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); /* The main DB, main journal, WAL file and super-journal are never ** automatically deleted. Nor are they ever temporary files. */ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); /* Assert that the upper layer has set one of the "file-type" flags. */ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); assert( pFile!=0 ); memset(pFile, 0, sizeof(winFile)); pFile->h = INVALID_HANDLE_VALUE; #if SQLITE_OS_WINRT if( !zUtf8Name && !sqlite3_temp_directory ){ sqlite3_log(SQLITE_ERROR, "sqlite3_temp_directory variable should be set for WinRT"); } #endif /* If the second argument to this function is NULL, generate a ** temporary file name to use */ if( !zUtf8Name ){ assert( isDelete && !isOpenJournal ); rc = winGetTempname(pVfs, &zTmpname); if( rc!=SQLITE_OK ){ OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc))); return rc; } zUtf8Name = zTmpname; } /* Database filenames are double-zero terminated if they are not ** URIs with parameters. Hence, they can always be passed into ** sqlite3_uri_parameter(). */ assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) || zUtf8Name[sqlite3Strlen30(zUtf8Name)+1]==0 ); /* Convert the filename to the system encoding. */ zConverted = winConvertFromUtf8Filename(zUtf8Name); if( zConverted==0 ){ sqlite3_free(zTmpname); OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name)); return SQLITE_IOERR_NOMEM_BKPT; } if( winIsDir(zConverted) ){ sqlite3_free(zConverted); sqlite3_free(zTmpname); OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name)); return SQLITE_CANTOPEN_ISDIR; } if( isReadWrite ){ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; }else{ dwDesiredAccess = GENERIC_READ; } /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is ** created. SQLite doesn't use it to indicate "exclusive access" ** as it is usually understood. */ if( isExclusive ){ /* Creates a new file, only if it does not already exist. */ /* If the file exists, it fails. */ dwCreationDisposition = CREATE_NEW; }else if( isCreate ){ /* Open existing file, or create if it doesn't exist */ dwCreationDisposition = OPEN_ALWAYS; }else{ /* Opens a file, only if it exists. */ dwCreationDisposition = OPEN_EXISTING; } if( 0==sqlite3_uri_boolean(zName, "exclusive", 0) ){ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; }else{ dwShareMode = 0; } if( isDelete ){ #if SQLITE_OS_WINCE dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN; isTemp = 1; #else dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_HIDDEN | FILE_FLAG_DELETE_ON_CLOSE; #endif }else{ dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; } /* Reports from the internet are that performance is always ** better if FILE_FLAG_RANDOM_ACCESS is used. Ticket #2699. */ #if SQLITE_OS_WINCE dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS; #endif if( osIsNT() ){ #if SQLITE_OS_WINRT CREATEFILE2_EXTENDED_PARAMETERS extendedParameters; extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); extendedParameters.dwFileAttributes = dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK; extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK; extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; extendedParameters.lpSecurityAttributes = NULL; extendedParameters.hTemplateFile = NULL; do{ h = osCreateFile2((LPCWSTR)zConverted, dwDesiredAccess, dwShareMode, dwCreationDisposition, &extendedParameters); if( h!=INVALID_HANDLE_VALUE ) break; if( isReadWrite ){ int rc2, isRO = 0; sqlite3BeginBenignMalloc(); rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } }while( winRetryIoerr(&cnt, &lastErrno) ); #else do{ h = osCreateFileW((LPCWSTR)zConverted, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); if( h!=INVALID_HANDLE_VALUE ) break; if( isReadWrite ){ int rc2, isRO = 0; sqlite3BeginBenignMalloc(); rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } }while( winRetryIoerr(&cnt, &lastErrno) ); #endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ do{ h = osCreateFileA((LPCSTR)zConverted, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); if( h!=INVALID_HANDLE_VALUE ) break; if( isReadWrite ){ int rc2, isRO = 0; sqlite3BeginBenignMalloc(); rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } }while( winRetryIoerr(&cnt, &lastErrno) ); } #endif winLogIoerr(cnt, __LINE__); OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name, dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); if( h==INVALID_HANDLE_VALUE ){ sqlite3_free(zConverted); sqlite3_free(zTmpname); if( isReadWrite && !isExclusive ){ return winOpen(pVfs, zName, id, ((flags|SQLITE_OPEN_READONLY) & ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); }else{ pFile->lastErrno = lastErrno; winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); return SQLITE_CANTOPEN_BKPT; } } if( pOutFlags ){ if( isReadWrite ){ *pOutFlags = SQLITE_OPEN_READWRITE; }else{ *pOutFlags = SQLITE_OPEN_READONLY; } } OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, " "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ? *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); pAppData = (winVfsAppData*)pVfs->pAppData; #if SQLITE_OS_WINCE { if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB && ((pAppData==NULL) || !pAppData->bNoLock) && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK ){ osCloseHandle(h); sqlite3_free(zConverted); sqlite3_free(zTmpname); OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); return rc; } } if( isTemp ){ pFile->zDeleteOnClose = zConverted; }else #endif { sqlite3_free(zConverted); } sqlite3_free(zTmpname); id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod; pFile->pVfs = pVfs; pFile->h = h; if( isReadonly ){ pFile->ctrlFlags |= WINFILE_RDONLY; } if( (flags & SQLITE_OPEN_MAIN_DB) && sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pFile->ctrlFlags |= WINFILE_PSOW; } pFile->lastErrno = NO_ERROR; pFile->zPath = zName; #if SQLITE_MAX_MMAP_SIZE>0 pFile->hMap = NULL; pFile->pMapRegion = 0; pFile->mmapSize = 0; pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap; #endif OpenCounter(+1); return rc; } /* ** Delete the named file. ** ** Note that Windows does not allow a file to be deleted if some other ** process has it open. Sometimes a virus scanner or indexing program ** will open a journal file shortly after it is created in order to do ** whatever it does. While this other process is holding the ** file open, we will be unable to delete it. To work around this ** problem, we delay 100 milliseconds and try to delete again. Up ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving ** up and returning an error. */ static int winDelete( sqlite3_vfs *pVfs, /* Not used on win32 */ const char *zFilename, /* Name of file to delete */ int syncDir /* Not used on win32 */ ){ int cnt = 0; int rc; DWORD attr; DWORD lastErrno = 0; void *zConverted; UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(syncDir); SimulateIOError(return SQLITE_IOERR_DELETE); OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir)); zConverted = winConvertFromUtf8Filename(zFilename); if( zConverted==0 ){ OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); return SQLITE_IOERR_NOMEM_BKPT; } if( osIsNT() ){ do { #if SQLITE_OS_WINRT WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard, &sAttrData) ){ attr = sAttrData.dwFileAttributes; }else{ lastErrno = osGetLastError(); if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ }else{ rc = SQLITE_ERROR; } break; } #else attr = osGetFileAttributesW(zConverted); #endif if ( attr==INVALID_FILE_ATTRIBUTES ){ lastErrno = osGetLastError(); if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ }else{ rc = SQLITE_ERROR; } break; } if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ rc = SQLITE_ERROR; /* Files only. */ break; } if ( osDeleteFileW(zConverted) ){ rc = SQLITE_OK; /* Deleted OK. */ break; } if ( !winRetryIoerr(&cnt, &lastErrno) ){ rc = SQLITE_ERROR; /* No more retries. */ break; } } while(1); } #ifdef SQLITE_WIN32_HAS_ANSI else{ do { attr = osGetFileAttributesA(zConverted); if ( attr==INVALID_FILE_ATTRIBUTES ){ lastErrno = osGetLastError(); if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ }else{ rc = SQLITE_ERROR; } break; } if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ rc = SQLITE_ERROR; /* Files only. */ break; } if ( osDeleteFileA(zConverted) ){ rc = SQLITE_OK; /* Deleted OK. */ break; } if ( !winRetryIoerr(&cnt, &lastErrno) ){ rc = SQLITE_ERROR; /* No more retries. */ break; } } while(1); } #endif if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename); }else{ winLogIoerr(cnt, __LINE__); } sqlite3_free(zConverted); OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc))); return rc; } /* ** Check the existence and status of a file. */ static int winAccess( sqlite3_vfs *pVfs, /* Not used on win32 */ const char *zFilename, /* Name of file to check */ int flags, /* Type of test to make on this file */ int *pResOut /* OUT: Result */ ){ DWORD attr; int rc = 0; DWORD lastErrno = 0; void *zConverted; UNUSED_PARAMETER(pVfs); SimulateIOError( return SQLITE_IOERR_ACCESS; ); OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n", zFilename, flags, pResOut)); if( zFilename==0 ){ *pResOut = 0; OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", zFilename, pResOut, *pResOut)); return SQLITE_OK; } zConverted = winConvertFromUtf8Filename(zFilename); if( zConverted==0 ){ OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); return SQLITE_IOERR_NOMEM_BKPT; } if( osIsNT() ){ int cnt = 0; WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, GetFileExInfoStandard, &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} if( rc ){ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file ** as if it does not exist. */ if( flags==SQLITE_ACCESS_EXISTS && sAttrData.nFileSizeHigh==0 && sAttrData.nFileSizeLow==0 ){ attr = INVALID_FILE_ATTRIBUTES; }else{ attr = sAttrData.dwFileAttributes; } }else{ winLogIoerr(cnt, __LINE__); if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){ sqlite3_free(zConverted); return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", zFilename); }else{ attr = INVALID_FILE_ATTRIBUTES; } } } #ifdef SQLITE_WIN32_HAS_ANSI else{ attr = osGetFileAttributesA((char*)zConverted); } #endif sqlite3_free(zConverted); switch( flags ){ case SQLITE_ACCESS_READ: case SQLITE_ACCESS_EXISTS: rc = attr!=INVALID_FILE_ATTRIBUTES; break; case SQLITE_ACCESS_READWRITE: rc = attr!=INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_READONLY)==0; break; default: assert(!"Invalid flags argument"); } *pResOut = rc; OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", zFilename, pResOut, *pResOut)); return SQLITE_OK; } /* ** Returns non-zero if the specified path name starts with the "long path" ** prefix. */ static BOOL winIsLongPathPrefix( const char *zPathname ){ return ( zPathname[0]=='\\' && zPathname[1]=='\\' && zPathname[2]=='?' && zPathname[3]=='\\' ); } /* ** Returns non-zero if the specified path name starts with a drive letter ** followed by a colon character. */ static BOOL winIsDriveLetterAndColon( const char *zPathname ){ return ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' ); } /* ** Returns non-zero if the specified path name should be used verbatim. If ** non-zero is returned from this function, the calling function must simply ** use the provided path name verbatim -OR- resolve it into a full path name ** using the GetFullPathName Win32 API function (if available). */ static BOOL winIsVerbatimPathname( const char *zPathname ){ /* ** If the path name starts with a forward slash or a backslash, it is either ** a legal UNC name, a volume relative path, or an absolute path name in the ** "Unix" format on Windows. There is no easy way to differentiate between ** the final two cases; therefore, we return the safer return value of TRUE ** so that callers of this function will simply use it verbatim. */ if ( winIsDirSep(zPathname[0]) ){ return TRUE; } /* ** If the path name starts with a letter and a colon it is either a volume ** relative path or an absolute path. Callers of this function must not ** attempt to treat it as a relative path name (i.e. they should simply use ** it verbatim). */ if ( winIsDriveLetterAndColon(zPathname) ){ return TRUE; } /* ** If we get to this point, the path name should almost certainly be a purely ** relative one (i.e. not a UNC name, not absolute, and not volume relative). */ return FALSE; } /* ** Turn a relative pathname into a full pathname. Write the full ** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname ** bytes in size. */ static int winFullPathnameNoMutex( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zRelative, /* Possibly relative input path */ int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) DWORD nByte; void *zConverted; char *zOut; #endif /* If this path name begins with "/X:" or "\\?\", where "X" is any ** alphabetic character, discard the initial "/" from the pathname. */ if( zRelative[0]=='/' && (winIsDriveLetterAndColon(zRelative+1) || winIsLongPathPrefix(zRelative+1)) ){ zRelative++; } #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); assert( nFull>=pVfs->mxPathname ); if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ /* ** NOTE: We are dealing with a relative path name and the data ** directory has been set. Therefore, use it as the basis ** for converting the relative path name to an absolute ** one by prepending the data directory and a slash. */ char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); if( !zOut ){ return SQLITE_IOERR_NOMEM_BKPT; } if( cygwin_conv_path( (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) | CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){ sqlite3_free(zOut); return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, "winFullPathname1", zRelative); }else{ char *zUtf8 = winConvertToUtf8Filename(zOut); if( !zUtf8 ){ sqlite3_free(zOut); return SQLITE_IOERR_NOMEM_BKPT; } sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", sqlite3_data_directory, winGetDirSep(), zUtf8); sqlite3_free(zUtf8); sqlite3_free(zOut); } }else{ char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); if( !zOut ){ return SQLITE_IOERR_NOMEM_BKPT; } if( cygwin_conv_path( (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A), zRelative, zOut, pVfs->mxPathname+1)<0 ){ sqlite3_free(zOut); return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, "winFullPathname2", zRelative); }else{ char *zUtf8 = winConvertToUtf8Filename(zOut); if( !zUtf8 ){ sqlite3_free(zOut); return SQLITE_IOERR_NOMEM_BKPT; } sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8); sqlite3_free(zUtf8); sqlite3_free(zOut); } } return SQLITE_OK; #endif #if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); /* WinCE has no concept of a relative pathname, or so I am told. */ /* WinRT has no way to convert a relative path to an absolute one. */ if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ /* ** NOTE: We are dealing with a relative path name and the data ** directory has been set. Therefore, use it as the basis ** for converting the relative path name to an absolute ** one by prepending the data directory and a backslash. */ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", sqlite3_data_directory, winGetDirSep(), zRelative); }else{ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative); } return SQLITE_OK; #endif #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the ** current working directory has been unlinked. */ SimulateIOError( return SQLITE_ERROR ); if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ /* ** NOTE: We are dealing with a relative path name and the data ** directory has been set. Therefore, use it as the basis ** for converting the relative path name to an absolute ** one by prepending the data directory and a backslash. */ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", sqlite3_data_directory, winGetDirSep(), zRelative); return SQLITE_OK; } zConverted = winConvertFromUtf8Filename(zRelative); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM_BKPT; } if( osIsNT() ){ LPWSTR zTemp; nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0); if( nByte==0 ){ sqlite3_free(zConverted); return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), "winFullPathname1", zRelative); } nByte += 3; zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); if( zTemp==0 ){ sqlite3_free(zConverted); return SQLITE_IOERR_NOMEM_BKPT; } nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0); if( nByte==0 ){ sqlite3_free(zConverted); sqlite3_free(zTemp); return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), "winFullPathname2", zRelative); } sqlite3_free(zConverted); zOut = winUnicodeToUtf8(zTemp); sqlite3_free(zTemp); } #ifdef SQLITE_WIN32_HAS_ANSI else{ char *zTemp; nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0); if( nByte==0 ){ sqlite3_free(zConverted); return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), "winFullPathname3", zRelative); } nByte += 3; zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); if( zTemp==0 ){ sqlite3_free(zConverted); return SQLITE_IOERR_NOMEM_BKPT; } nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0); if( nByte==0 ){ sqlite3_free(zConverted); sqlite3_free(zTemp); return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), "winFullPathname4", zRelative); } sqlite3_free(zConverted); zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI()); sqlite3_free(zTemp); } #endif if( zOut ){ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut); sqlite3_free(zOut); return SQLITE_OK; }else{ return SQLITE_IOERR_NOMEM_BKPT; } #endif } static int winFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zRelative, /* Possibly relative input path */ int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ int rc; MUTEX_LOGIC( sqlite3_mutex *pMutex; ) MUTEX_LOGIC( pMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR); ) sqlite3_mutex_enter(pMutex); rc = winFullPathnameNoMutex(pVfs, zRelative, nFull, zFull); sqlite3_mutex_leave(pMutex); return rc; } #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Interfaces for opening a shared library, finding entry points ** within the shared library, and closing the shared library. */ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ HANDLE h; #if defined(__CYGWIN__) int nFull = pVfs->mxPathname+1; char *zFull = sqlite3MallocZero( nFull ); void *zConverted = 0; if( zFull==0 ){ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); return 0; } if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){ sqlite3_free(zFull); OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); return 0; } zConverted = winConvertFromUtf8Filename(zFull); sqlite3_free(zFull); #else void *zConverted = winConvertFromUtf8Filename(zFilename); UNUSED_PARAMETER(pVfs); #endif if( zConverted==0 ){ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); return 0; } if( osIsNT() ){ #if SQLITE_OS_WINRT h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0); #else h = osLoadLibraryW((LPCWSTR)zConverted); #endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ h = osLoadLibraryA((char*)zConverted); } #endif OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h)); sqlite3_free(zConverted); return (void*)h; } static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ UNUSED_PARAMETER(pVfs); winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut); } static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){ FARPROC proc; UNUSED_PARAMETER(pVfs); proc = osGetProcAddressA((HANDLE)pH, zSym); OSTRACE(("DLSYM handle=%p, symbol=%s, address=%p\n", (void*)pH, zSym, (void*)proc)); return (void(*)(void))proc; } static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ UNUSED_PARAMETER(pVfs); osFreeLibrary((HANDLE)pHandle); OSTRACE(("DLCLOSE handle=%p\n", (void*)pHandle)); } #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ #define winDlOpen 0 #define winDlError 0 #define winDlSym 0 #define winDlClose 0 #endif /* State information for the randomness gatherer. */ typedef struct EntropyGatherer EntropyGatherer; struct EntropyGatherer { unsigned char *a; /* Gather entropy into this buffer */ int na; /* Size of a[] in bytes */ int i; /* XOR next input into a[i] */ int nXor; /* Number of XOR operations done */ }; #if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) /* Mix sz bytes of entropy into p. */ static void xorMemory(EntropyGatherer *p, unsigned char *x, int sz){ int j, k; for(j=0, k=p->i; ja[k++] ^= x[j]; if( k>=p->na ) k = 0; } p->i = k; p->nXor += sz; } #endif /* !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) */ /* ** Write up to nBuf bytes of randomness into zBuf. */ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ #if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) UNUSED_PARAMETER(pVfs); memset(zBuf, 0, nBuf); return nBuf; #else EntropyGatherer e; UNUSED_PARAMETER(pVfs); memset(zBuf, 0, nBuf); e.a = (unsigned char*)zBuf; e.na = nBuf; e.nXor = 0; e.i = 0; { SYSTEMTIME x; osGetSystemTime(&x); xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME)); } { DWORD pid = osGetCurrentProcessId(); xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD)); } #if SQLITE_OS_WINRT { ULONGLONG cnt = osGetTickCount64(); xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG)); } #else { DWORD cnt = osGetTickCount(); xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD)); } #endif /* SQLITE_OS_WINRT */ { LARGE_INTEGER i; osQueryPerformanceCounter(&i); xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER)); } #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID { UUID id; memset(&id, 0, sizeof(UUID)); osUuidCreate(&id); xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); memset(&id, 0, sizeof(UUID)); osUuidCreateSequential(&id); xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); } #endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */ return e.nXor>nBuf ? nBuf : e.nXor; #endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */ } /* ** Sleep for a little while. Return the amount of time slept. */ static int winSleep(sqlite3_vfs *pVfs, int microsec){ sqlite3_win32_sleep((microsec+999)/1000); UNUSED_PARAMETER(pVfs); return ((microsec+999)/1000)*1000; } /* ** The following variable, if set to a non-zero value, is interpreted as ** the number of seconds since 1970 and is used to set the result of ** sqlite3OsCurrentTime() during testing. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ #endif /* ** Find the current time (in Universal Coordinated Time). Write into *piNow ** the current time and date as a Julian Day number times 86_400_000. In ** other words, write into *piNow the number of milliseconds since the Julian ** epoch of noon in Greenwich on November 24, 4714 B.C according to the ** proleptic Gregorian calendar. ** ** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date ** cannot be found. */ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ /* FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). */ FILETIME ft; static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000; #ifdef SQLITE_TEST static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; #endif /* 2^32 - to avoid use of LL and warnings in gcc */ static const sqlite3_int64 max32BitValue = (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296; #if SQLITE_OS_WINCE SYSTEMTIME time; osGetSystemTime(&time); /* if SystemTimeToFileTime() fails, it returns zero. */ if (!osSystemTimeToFileTime(&time,&ft)){ return SQLITE_ERROR; } #else osGetSystemTimeAsFileTime( &ft ); #endif *piNow = winFiletimeEpoch + ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000; #ifdef SQLITE_TEST if( sqlite3_current_time ){ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch; } #endif UNUSED_PARAMETER(pVfs); return SQLITE_OK; } /* ** Find the current time (in Universal Coordinated Time). Write the ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ int rc; sqlite3_int64 i; rc = winCurrentTimeInt64(pVfs, &i); if( !rc ){ *prNow = i/86400000.0; } return rc; } /* ** The idea is that this function works like a combination of ** GetLastError() and FormatMessage() on Windows (or errno and ** strerror_r() on Unix). After an error is returned by an OS ** function, SQLite calls this function with zBuf pointing to ** a buffer of nBuf bytes. The OS layer should populate the ** buffer with a nul-terminated UTF-8 encoded error message ** describing the last IO error to have occurred within the calling ** thread. ** ** If the error message is too large for the supplied buffer, ** it should be truncated. The return value of xGetLastError ** is zero if the error message fits in the buffer, or non-zero ** otherwise (if the message was truncated). If non-zero is returned, ** then it is not necessary to include the nul-terminator character ** in the output buffer. ** ** Not supplying an error message will have no adverse effect ** on SQLite. It is fine to have an implementation that never ** returns an error message: ** ** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ ** assert(zBuf[0]=='\0'); ** return 0; ** } ** ** However if an error message is supplied, it will be incorporated ** by sqlite into the error message available to the user using ** sqlite3_errmsg(), possibly making IO errors easier to debug. */ static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ DWORD e = osGetLastError(); UNUSED_PARAMETER(pVfs); if( nBuf>0 ) winGetLastErrorMsg(e, nBuf, zBuf); return e; } /* ** Initialize and deinitialize the operating system interface. */ SQLITE_API int sqlite3_os_init(void){ static sqlite3_vfs winVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ 0, /* pNext */ "win32", /* zName */ &winAppData, /* pAppData */ winOpen, /* xOpen */ winDelete, /* xDelete */ winAccess, /* xAccess */ winFullPathname, /* xFullPathname */ winDlOpen, /* xDlOpen */ winDlError, /* xDlError */ winDlSym, /* xDlSym */ winDlClose, /* xDlClose */ winRandomness, /* xRandomness */ winSleep, /* xSleep */ winCurrentTime, /* xCurrentTime */ winGetLastError, /* xGetLastError */ winCurrentTimeInt64, /* xCurrentTimeInt64 */ winSetSystemCall, /* xSetSystemCall */ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; #if defined(SQLITE_WIN32_HAS_WIDE) static sqlite3_vfs winLongPathVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ 0, /* pNext */ "win32-longpath", /* zName */ &winAppData, /* pAppData */ winOpen, /* xOpen */ winDelete, /* xDelete */ winAccess, /* xAccess */ winFullPathname, /* xFullPathname */ winDlOpen, /* xDlOpen */ winDlError, /* xDlError */ winDlSym, /* xDlSym */ winDlClose, /* xDlClose */ winRandomness, /* xRandomness */ winSleep, /* xSleep */ winCurrentTime, /* xCurrentTime */ winGetLastError, /* xGetLastError */ winCurrentTimeInt64, /* xCurrentTimeInt64 */ winSetSystemCall, /* xSetSystemCall */ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; #endif static sqlite3_vfs winNolockVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ 0, /* pNext */ "win32-none", /* zName */ &winNolockAppData, /* pAppData */ winOpen, /* xOpen */ winDelete, /* xDelete */ winAccess, /* xAccess */ winFullPathname, /* xFullPathname */ winDlOpen, /* xDlOpen */ winDlError, /* xDlError */ winDlSym, /* xDlSym */ winDlClose, /* xDlClose */ winRandomness, /* xRandomness */ winSleep, /* xSleep */ winCurrentTime, /* xCurrentTime */ winGetLastError, /* xGetLastError */ winCurrentTimeInt64, /* xCurrentTimeInt64 */ winSetSystemCall, /* xSetSystemCall */ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; #if defined(SQLITE_WIN32_HAS_WIDE) static sqlite3_vfs winLongPathNolockVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ 0, /* pNext */ "win32-longpath-none", /* zName */ &winNolockAppData, /* pAppData */ winOpen, /* xOpen */ winDelete, /* xDelete */ winAccess, /* xAccess */ winFullPathname, /* xFullPathname */ winDlOpen, /* xDlOpen */ winDlError, /* xDlError */ winDlSym, /* xDlSym */ winDlClose, /* xDlClose */ winRandomness, /* xRandomness */ winSleep, /* xSleep */ winCurrentTime, /* xCurrentTime */ winGetLastError, /* xGetLastError */ winCurrentTimeInt64, /* xCurrentTimeInt64 */ winSetSystemCall, /* xSetSystemCall */ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; #endif /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==80 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); #if SQLITE_OS_WINRT osGetNativeSystemInfo(&winSysInfo); #else osGetSystemInfo(&winSysInfo); #endif assert( winSysInfo.dwAllocationGranularity>0 ); assert( winSysInfo.dwPageSize>0 ); sqlite3_vfs_register(&winVfs, 1); #if defined(SQLITE_WIN32_HAS_WIDE) sqlite3_vfs_register(&winLongPathVfs, 0); #endif sqlite3_vfs_register(&winNolockVfs, 0); #if defined(SQLITE_WIN32_HAS_WIDE) sqlite3_vfs_register(&winLongPathNolockVfs, 0); #endif #ifndef SQLITE_OMIT_WAL winBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); #endif return SQLITE_OK; } SQLITE_API int sqlite3_os_end(void){ #if SQLITE_OS_WINRT if( sleepObj!=NULL ){ osCloseHandle(sleepObj); sleepObj = NULL; } #endif #ifndef SQLITE_OMIT_WAL winBigLock = 0; #endif return SQLITE_OK; } #endif /* SQLITE_OS_WIN */ /************** End of os_win.c **********************************************/ /************** Begin file memdb.c *******************************************/ /* ** 2016-09-07 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file implements an in-memory VFS. A database is held as a contiguous ** block of memory. ** ** This file also implements interface sqlite3_serialize() and ** sqlite3_deserialize(). */ /* #include "sqliteInt.h" */ #ifndef SQLITE_OMIT_DESERIALIZE /* ** Forward declaration of objects used by this utility */ typedef struct sqlite3_vfs MemVfs; typedef struct MemFile MemFile; typedef struct MemStore MemStore; /* Access to a lower-level VFS that (might) implement dynamic loading, ** access to randomness, etc. */ #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) /* Storage for a memdb file. ** ** An memdb object can be shared or separate. Shared memdb objects can be ** used by more than one database connection. Mutexes are used by shared ** memdb objects to coordinate access. Separate memdb objects are only ** connected to a single database connection and do not require additional ** mutexes. ** ** Shared memdb objects have .zFName!=0 and .pMutex!=0. They are created ** using "file:/name?vfs=memdb". The first character of the name must be ** "/" or else the object will be a separate memdb object. All shared ** memdb objects are stored in memdb_g.apMemStore[] in an arbitrary order. ** ** Separate memdb objects are created using a name that does not begin ** with "/" or using sqlite3_deserialize(). ** ** Access rules for shared MemStore objects: ** ** * .zFName is initialized when the object is created and afterwards ** is unchanged until the object is destroyed. So it can be accessed ** at any time as long as we know the object is not being destroyed, ** which means while either the SQLITE_MUTEX_STATIC_VFS1 or ** .pMutex is held or the object is not part of memdb_g.apMemStore[]. ** ** * Can .pMutex can only be changed while holding the ** SQLITE_MUTEX_STATIC_VFS1 mutex or while the object is not part ** of memdb_g.apMemStore[]. ** ** * Other fields can only be changed while holding the .pMutex mutex ** or when the .nRef is less than zero and the object is not part of ** memdb_g.apMemStore[]. ** ** * The .aData pointer has the added requirement that it can can only ** be changed (for resizing) when nMmap is zero. ** */ struct MemStore { sqlite3_int64 sz; /* Size of the file */ sqlite3_int64 szAlloc; /* Space allocated to aData */ sqlite3_int64 szMax; /* Maximum allowed size of the file */ unsigned char *aData; /* content of the file */ sqlite3_mutex *pMutex; /* Used by shared stores only */ int nMmap; /* Number of memory mapped pages */ unsigned mFlags; /* Flags */ int nRdLock; /* Number of readers */ int nWrLock; /* Number of writers. (Always 0 or 1) */ int nRef; /* Number of users of this MemStore */ char *zFName; /* The filename for shared stores */ }; /* An open file */ struct MemFile { sqlite3_file base; /* IO methods */ MemStore *pStore; /* The storage */ int eLock; /* Most recent lock against this file */ }; /* ** File-scope variables for holding the memdb files that are accessible ** to multiple database connections in separate threads. ** ** Must hold SQLITE_MUTEX_STATIC_VFS1 to access any part of this object. */ static struct MemFS { int nMemStore; /* Number of shared MemStore objects */ MemStore **apMemStore; /* Array of all shared MemStore objects */ } memdb_g; /* ** Methods for MemFile */ static int memdbClose(sqlite3_file*); static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); static int memdbTruncate(sqlite3_file*, sqlite3_int64 size); static int memdbSync(sqlite3_file*, int flags); static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize); static int memdbLock(sqlite3_file*, int); static int memdbUnlock(sqlite3_file*, int); /* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */ static int memdbFileControl(sqlite3_file*, int op, void *pArg); /* static int memdbSectorSize(sqlite3_file*); // not used */ static int memdbDeviceCharacteristics(sqlite3_file*); static int memdbFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); static int memdbUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); /* ** Methods for MemVfs */ static int memdbOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); /* static int memdbDelete(sqlite3_vfs*, const char *zName, int syncDir); */ static int memdbAccess(sqlite3_vfs*, const char *zName, int flags, int *); static int memdbFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); static void *memdbDlOpen(sqlite3_vfs*, const char *zFilename); static void memdbDlError(sqlite3_vfs*, int nByte, char *zErrMsg); static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); static void memdbDlClose(sqlite3_vfs*, void*); static int memdbRandomness(sqlite3_vfs*, int nByte, char *zOut); static int memdbSleep(sqlite3_vfs*, int microseconds); /* static int memdbCurrentTime(sqlite3_vfs*, double*); */ static int memdbGetLastError(sqlite3_vfs*, int, char *); static int memdbCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); static sqlite3_vfs memdb_vfs = { 2, /* iVersion */ 0, /* szOsFile (set when registered) */ 1024, /* mxPathname */ 0, /* pNext */ "memdb", /* zName */ 0, /* pAppData (set when registered) */ memdbOpen, /* xOpen */ 0, /* memdbDelete, */ /* xDelete */ memdbAccess, /* xAccess */ memdbFullPathname, /* xFullPathname */ memdbDlOpen, /* xDlOpen */ memdbDlError, /* xDlError */ memdbDlSym, /* xDlSym */ memdbDlClose, /* xDlClose */ memdbRandomness, /* xRandomness */ memdbSleep, /* xSleep */ 0, /* memdbCurrentTime, */ /* xCurrentTime */ memdbGetLastError, /* xGetLastError */ memdbCurrentTimeInt64, /* xCurrentTimeInt64 */ 0, /* xSetSystemCall */ 0, /* xGetSystemCall */ 0, /* xNextSystemCall */ }; static const sqlite3_io_methods memdb_io_methods = { 3, /* iVersion */ memdbClose, /* xClose */ memdbRead, /* xRead */ memdbWrite, /* xWrite */ memdbTruncate, /* xTruncate */ memdbSync, /* xSync */ memdbFileSize, /* xFileSize */ memdbLock, /* xLock */ memdbUnlock, /* xUnlock */ 0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */ memdbFileControl, /* xFileControl */ 0, /* memdbSectorSize,*/ /* xSectorSize */ memdbDeviceCharacteristics, /* xDeviceCharacteristics */ 0, /* xShmMap */ 0, /* xShmLock */ 0, /* xShmBarrier */ 0, /* xShmUnmap */ memdbFetch, /* xFetch */ memdbUnfetch /* xUnfetch */ }; /* ** Enter/leave the mutex on a MemStore */ #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0 static void memdbEnter(MemStore *p){ UNUSED_PARAMETER(p); } static void memdbLeave(MemStore *p){ UNUSED_PARAMETER(p); } #else static void memdbEnter(MemStore *p){ sqlite3_mutex_enter(p->pMutex); } static void memdbLeave(MemStore *p){ sqlite3_mutex_leave(p->pMutex); } #endif /* ** Close an memdb-file. ** Free the underlying MemStore object when its refcount drops to zero ** or less. */ static int memdbClose(sqlite3_file *pFile){ MemStore *p = ((MemFile*)pFile)->pStore; if( p->zFName ){ int i; #ifndef SQLITE_MUTEX_OMIT sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); #endif sqlite3_mutex_enter(pVfsMutex); for(i=0; ALWAYS(inRef==1 ){ memdb_g.apMemStore[i] = memdb_g.apMemStore[--memdb_g.nMemStore]; if( memdb_g.nMemStore==0 ){ sqlite3_free(memdb_g.apMemStore); memdb_g.apMemStore = 0; } } break; } } sqlite3_mutex_leave(pVfsMutex); }else{ memdbEnter(p); } p->nRef--; if( p->nRef<=0 ){ if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){ sqlite3_free(p->aData); } memdbLeave(p); sqlite3_mutex_free(p->pMutex); sqlite3_free(p); }else{ memdbLeave(p); } return SQLITE_OK; } /* ** Read data from an memdb-file. */ static int memdbRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ MemStore *p = ((MemFile*)pFile)->pStore; memdbEnter(p); if( iOfst+iAmt>p->sz ){ memset(zBuf, 0, iAmt); if( iOfstsz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst); memdbLeave(p); return SQLITE_IOERR_SHORT_READ; } memcpy(zBuf, p->aData+iOfst, iAmt); memdbLeave(p); return SQLITE_OK; } /* ** Try to enlarge the memory allocation to hold at least sz bytes */ static int memdbEnlarge(MemStore *p, sqlite3_int64 newSz){ unsigned char *pNew; if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || NEVER(p->nMmap>0) ){ return SQLITE_FULL; } if( newSz>p->szMax ){ return SQLITE_FULL; } newSz *= 2; if( newSz>p->szMax ) newSz = p->szMax; pNew = sqlite3Realloc(p->aData, newSz); if( pNew==0 ) return SQLITE_IOERR_NOMEM; p->aData = pNew; p->szAlloc = newSz; return SQLITE_OK; } /* ** Write data to an memdb-file. */ static int memdbWrite( sqlite3_file *pFile, const void *z, int iAmt, sqlite_int64 iOfst ){ MemStore *p = ((MemFile*)pFile)->pStore; memdbEnter(p); if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ){ /* Can't happen: memdbLock() will return SQLITE_READONLY before ** reaching this point */ memdbLeave(p); return SQLITE_IOERR_WRITE; } if( iOfst+iAmt>p->sz ){ int rc; if( iOfst+iAmt>p->szAlloc && (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK ){ memdbLeave(p); return rc; } if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz); p->sz = iOfst+iAmt; } memcpy(p->aData+iOfst, z, iAmt); memdbLeave(p); return SQLITE_OK; } /* ** Truncate an memdb-file. ** ** In rollback mode (which is always the case for memdb, as it does not ** support WAL mode) the truncate() method is only used to reduce ** the size of a file, never to increase the size. */ static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){ MemStore *p = ((MemFile*)pFile)->pStore; int rc = SQLITE_OK; memdbEnter(p); if( size>p->sz ){ /* This can only happen with a corrupt wal mode db */ rc = SQLITE_CORRUPT; }else{ p->sz = size; } memdbLeave(p); return rc; } /* ** Sync an memdb-file. */ static int memdbSync(sqlite3_file *pFile, int flags){ UNUSED_PARAMETER(pFile); UNUSED_PARAMETER(flags); return SQLITE_OK; } /* ** Return the current file-size of an memdb-file. */ static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ MemStore *p = ((MemFile*)pFile)->pStore; memdbEnter(p); *pSize = p->sz; memdbLeave(p); return SQLITE_OK; } /* ** Lock an memdb-file. */ static int memdbLock(sqlite3_file *pFile, int eLock){ MemFile *pThis = (MemFile*)pFile; MemStore *p = pThis->pStore; int rc = SQLITE_OK; if( eLock<=pThis->eLock ) return SQLITE_OK; memdbEnter(p); assert( p->nWrLock==0 || p->nWrLock==1 ); assert( pThis->eLock<=SQLITE_LOCK_SHARED || p->nWrLock==1 ); assert( pThis->eLock==SQLITE_LOCK_NONE || p->nRdLock>=1 ); if( eLock>SQLITE_LOCK_SHARED && (p->mFlags & SQLITE_DESERIALIZE_READONLY) ){ rc = SQLITE_READONLY; }else{ switch( eLock ){ case SQLITE_LOCK_SHARED: { assert( pThis->eLock==SQLITE_LOCK_NONE ); if( p->nWrLock>0 ){ rc = SQLITE_BUSY; }else{ p->nRdLock++; } break; }; case SQLITE_LOCK_RESERVED: case SQLITE_LOCK_PENDING: { assert( pThis->eLock>=SQLITE_LOCK_SHARED ); if( ALWAYS(pThis->eLock==SQLITE_LOCK_SHARED) ){ if( p->nWrLock>0 ){ rc = SQLITE_BUSY; }else{ p->nWrLock = 1; } } break; } default: { assert( eLock==SQLITE_LOCK_EXCLUSIVE ); assert( pThis->eLock>=SQLITE_LOCK_SHARED ); if( p->nRdLock>1 ){ rc = SQLITE_BUSY; }else if( pThis->eLock==SQLITE_LOCK_SHARED ){ p->nWrLock = 1; } break; } } } if( rc==SQLITE_OK ) pThis->eLock = eLock; memdbLeave(p); return rc; } /* ** Unlock an memdb-file. */ static int memdbUnlock(sqlite3_file *pFile, int eLock){ MemFile *pThis = (MemFile*)pFile; MemStore *p = pThis->pStore; if( eLock>=pThis->eLock ) return SQLITE_OK; memdbEnter(p); assert( eLock==SQLITE_LOCK_SHARED || eLock==SQLITE_LOCK_NONE ); if( eLock==SQLITE_LOCK_SHARED ){ if( ALWAYS(pThis->eLock>SQLITE_LOCK_SHARED) ){ p->nWrLock--; } }else{ if( pThis->eLock>SQLITE_LOCK_SHARED ){ p->nWrLock--; } p->nRdLock--; } pThis->eLock = eLock; memdbLeave(p); return SQLITE_OK; } #if 0 /* ** This interface is only used for crash recovery, which does not ** occur on an in-memory database. */ static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){ *pResOut = 0; return SQLITE_OK; } #endif /* ** File control method. For custom operations on an memdb-file. */ static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){ MemStore *p = ((MemFile*)pFile)->pStore; int rc = SQLITE_NOTFOUND; memdbEnter(p); if( op==SQLITE_FCNTL_VFSNAME ){ *(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz); rc = SQLITE_OK; } if( op==SQLITE_FCNTL_SIZE_LIMIT ){ sqlite3_int64 iLimit = *(sqlite3_int64*)pArg; if( iLimitsz ){ if( iLimit<0 ){ iLimit = p->szMax; }else{ iLimit = p->sz; } } p->szMax = iLimit; *(sqlite3_int64*)pArg = iLimit; rc = SQLITE_OK; } memdbLeave(p); return rc; } #if 0 /* Not used because of SQLITE_IOCAP_POWERSAFE_OVERWRITE */ /* ** Return the sector-size in bytes for an memdb-file. */ static int memdbSectorSize(sqlite3_file *pFile){ return 1024; } #endif /* ** Return the device characteristic flags supported by an memdb-file. */ static int memdbDeviceCharacteristics(sqlite3_file *pFile){ UNUSED_PARAMETER(pFile); return SQLITE_IOCAP_ATOMIC | SQLITE_IOCAP_POWERSAFE_OVERWRITE | SQLITE_IOCAP_SAFE_APPEND | SQLITE_IOCAP_SEQUENTIAL; } /* Fetch a page of a memory-mapped file */ static int memdbFetch( sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp ){ MemStore *p = ((MemFile*)pFile)->pStore; memdbEnter(p); if( iOfst+iAmt>p->sz || (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)!=0 ){ *pp = 0; }else{ p->nMmap++; *pp = (void*)(p->aData + iOfst); } memdbLeave(p); return SQLITE_OK; } /* Release a memory-mapped page */ static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ MemStore *p = ((MemFile*)pFile)->pStore; UNUSED_PARAMETER(iOfst); UNUSED_PARAMETER(pPage); memdbEnter(p); p->nMmap--; memdbLeave(p); return SQLITE_OK; } /* ** Open an mem file handle. */ static int memdbOpen( sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFd, int flags, int *pOutFlags ){ MemFile *pFile = (MemFile*)pFd; MemStore *p = 0; int szName; UNUSED_PARAMETER(pVfs); memset(pFile, 0, sizeof(*pFile)); szName = sqlite3Strlen30(zName); if( szName>1 && (zName[0]=='/' || zName[0]=='\\') ){ int i; #ifndef SQLITE_MUTEX_OMIT sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); #endif sqlite3_mutex_enter(pVfsMutex); for(i=0; izFName,zName)==0 ){ p = memdb_g.apMemStore[i]; break; } } if( p==0 ){ MemStore **apNew; p = sqlite3Malloc( sizeof(*p) + szName + 3 ); if( p==0 ){ sqlite3_mutex_leave(pVfsMutex); return SQLITE_NOMEM; } apNew = sqlite3Realloc(memdb_g.apMemStore, sizeof(apNew[0])*(memdb_g.nMemStore+1) ); if( apNew==0 ){ sqlite3_free(p); sqlite3_mutex_leave(pVfsMutex); return SQLITE_NOMEM; } apNew[memdb_g.nMemStore++] = p; memdb_g.apMemStore = apNew; memset(p, 0, sizeof(*p)); p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE|SQLITE_DESERIALIZE_FREEONCLOSE; p->szMax = sqlite3GlobalConfig.mxMemdbSize; p->zFName = (char*)&p[1]; memcpy(p->zFName, zName, szName+1); p->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( p->pMutex==0 ){ memdb_g.nMemStore--; sqlite3_free(p); sqlite3_mutex_leave(pVfsMutex); return SQLITE_NOMEM; } p->nRef = 1; memdbEnter(p); }else{ memdbEnter(p); p->nRef++; } sqlite3_mutex_leave(pVfsMutex); }else{ p = sqlite3Malloc( sizeof(*p) ); if( p==0 ){ return SQLITE_NOMEM; } memset(p, 0, sizeof(*p)); p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE; p->szMax = sqlite3GlobalConfig.mxMemdbSize; } pFile->pStore = p; if( pOutFlags!=0 ){ *pOutFlags = flags | SQLITE_OPEN_MEMORY; } pFd->pMethods = &memdb_io_methods; memdbLeave(p); return SQLITE_OK; } #if 0 /* Only used to delete rollback journals, super-journals, and WAL ** files, none of which exist in memdb. So this routine is never used */ /* ** Delete the file located at zPath. If the dirSync argument is true, ** ensure the file-system modifications are synced to disk before ** returning. */ static int memdbDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ return SQLITE_IOERR_DELETE; } #endif /* ** Test for access permissions. Return true if the requested permission ** is available, or false otherwise. ** ** With memdb, no files ever exist on disk. So always return false. */ static int memdbAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(zPath); UNUSED_PARAMETER(flags); *pResOut = 0; return SQLITE_OK; } /* ** Populate buffer zOut with the full canonical pathname corresponding ** to the pathname in zPath. zOut is guaranteed to point to a buffer ** of at least (INST_MAX_PATHNAME+1) bytes. */ static int memdbFullPathname( sqlite3_vfs *pVfs, const char *zPath, int nOut, char *zOut ){ UNUSED_PARAMETER(pVfs); sqlite3_snprintf(nOut, zOut, "%s", zPath); return SQLITE_OK; } /* ** Open the dynamic library located at zPath and return a handle. */ static void *memdbDlOpen(sqlite3_vfs *pVfs, const char *zPath){ return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); } /* ** Populate the buffer zErrMsg (size nByte bytes) with a human readable ** utf-8 string describing the most recent error encountered associated ** with dynamic libraries. */ static void memdbDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); } /* ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. */ static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); } /* ** Close the dynamic library handle pHandle. */ static void memdbDlClose(sqlite3_vfs *pVfs, void *pHandle){ ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); } /* ** Populate the buffer pointed to by zBufOut with nByte bytes of ** random data. */ static int memdbRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); } /* ** Sleep for nMicro microseconds. Return the number of microseconds ** actually slept. */ static int memdbSleep(sqlite3_vfs *pVfs, int nMicro){ return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); } #if 0 /* Never used. Modern cores only call xCurrentTimeInt64() */ /* ** Return the current time as a Julian Day number in *pTimeOut. */ static int memdbCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); } #endif static int memdbGetLastError(sqlite3_vfs *pVfs, int a, char *b){ return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); } static int memdbCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p); } /* ** Translate a database connection pointer and schema name into a ** MemFile pointer. */ static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){ MemFile *p = 0; MemStore *pStore; int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p); if( rc ) return 0; if( p->base.pMethods!=&memdb_io_methods ) return 0; pStore = p->pStore; memdbEnter(pStore); if( pStore->zFName!=0 ) p = 0; memdbLeave(pStore); return p; } /* ** Return the serialization of a database */ SQLITE_API unsigned char *sqlite3_serialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which database within the connection */ sqlite3_int64 *piSize, /* Write size here, if not NULL */ unsigned int mFlags /* Maybe SQLITE_SERIALIZE_NOCOPY */ ){ MemFile *p; int iDb; Btree *pBt; sqlite3_int64 sz; int szPage = 0; sqlite3_stmt *pStmt = 0; unsigned char *pOut; char *zSql; int rc; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; p = memdbFromDbSchema(db, zSchema); iDb = sqlite3FindDbName(db, zSchema); if( piSize ) *piSize = -1; if( iDb<0 ) return 0; if( p ){ MemStore *pStore = p->pStore; assert( pStore->pMutex==0 ); if( piSize ) *piSize = pStore->sz; if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ pOut = pStore->aData; }else{ pOut = sqlite3_malloc64( pStore->sz ); if( pOut ) memcpy(pOut, pStore->aData, pStore->sz); } return pOut; } pBt = db->aDb[iDb].pBt; if( pBt==0 ) return 0; szPage = sqlite3BtreeGetPageSize(pBt); zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema); rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM; sqlite3_free(zSql); if( rc ) return 0; rc = sqlite3_step(pStmt); if( rc!=SQLITE_ROW ){ pOut = 0; }else{ sz = sqlite3_column_int64(pStmt, 0)*szPage; if( piSize ) *piSize = sz; if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ pOut = 0; }else{ pOut = sqlite3_malloc64( sz ); if( pOut ){ int nPage = sqlite3_column_int(pStmt, 0); Pager *pPager = sqlite3BtreePager(pBt); int pgno; for(pgno=1; pgno<=nPage; pgno++){ DbPage *pPage = 0; unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1); rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0); if( rc==SQLITE_OK ){ memcpy(pTo, sqlite3PagerGetData(pPage), szPage); }else{ memset(pTo, 0, szPage); } sqlite3PagerUnref(pPage); } } } } sqlite3_finalize(pStmt); return pOut; } /* Convert zSchema to a MemDB and initialize its content. */ SQLITE_API int sqlite3_deserialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to reopen with the deserialization */ unsigned char *pData, /* The serialized database content */ sqlite3_int64 szDb, /* Number bytes in the deserialization */ sqlite3_int64 szBuf, /* Total size of buffer pData[] */ unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ ){ MemFile *p; char *zSql; sqlite3_stmt *pStmt = 0; int rc; int iDb; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } if( szDb<0 ) return SQLITE_MISUSE_BKPT; if( szBuf<0 ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; iDb = sqlite3FindDbName(db, zSchema); testcase( iDb==1 ); if( iDb<2 && iDb!=0 ){ rc = SQLITE_ERROR; goto end_deserialize; } zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); } if( rc ) goto end_deserialize; db->init.iDb = (u8)iDb; db->init.reopenMemdb = 1; rc = sqlite3_step(pStmt); db->init.reopenMemdb = 0; if( rc!=SQLITE_DONE ){ rc = SQLITE_ERROR; goto end_deserialize; } p = memdbFromDbSchema(db, zSchema); if( p==0 ){ rc = SQLITE_ERROR; }else{ MemStore *pStore = p->pStore; pStore->aData = pData; pData = 0; pStore->sz = szDb; pStore->szAlloc = szBuf; pStore->szMax = szBuf; if( pStore->szMaxszMax = sqlite3GlobalConfig.mxMemdbSize; } pStore->mFlags = mFlags; rc = SQLITE_OK; } end_deserialize: sqlite3_finalize(pStmt); if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){ sqlite3_free(pData); } sqlite3_mutex_leave(db->mutex); return rc; } /* ** Return true if the VFS is the memvfs. */ SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs *pVfs){ return pVfs==&memdb_vfs; } /* ** This routine is called when the extension is loaded. ** Register the new VFS. */ SQLITE_PRIVATE int sqlite3MemdbInit(void){ sqlite3_vfs *pLower = sqlite3_vfs_find(0); unsigned int sz; if( NEVER(pLower==0) ) return SQLITE_ERROR; sz = pLower->szOsFile; memdb_vfs.pAppData = pLower; /* The following conditional can only be true when compiled for ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave ** it in, to be safe, but it is marked as NO_TEST since there ** is no way to reach it under most builds. */ if( szBITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is ** a hash table that will hold up to BITVEC_MXHASH distinct values. ** ** Otherwise, the value i is redirected into one of BITVEC_NPTR ** sub-bitmaps pointed to by Bitvec.u.apSub[]. Each subbitmap ** handles up to iDivisor separate values of i. apSub[0] holds ** values between 1 and iDivisor. apSub[1] holds values between ** iDivisor+1 and 2*iDivisor. apSub[N] holds values between ** N*iDivisor+1 and (N+1)*iDivisor. Each subbitmap is normalized ** to hold deal with values between 1 and iDivisor. */ struct Bitvec { u32 iSize; /* Maximum bit index. Max iSize is 4,294,967,296. */ u32 nSet; /* Number of bits that are set - only valid for aHash ** element. Max is BITVEC_NINT. For BITVEC_SZ of 512, ** this would be 125. */ u32 iDivisor; /* Number of bits handled by each apSub[] entry. */ /* Should >=0 for apSub element. */ /* Max iDivisor is max(u32) / BITVEC_NPTR + 1. */ /* For a BITVEC_SZ of 512, this would be 34,359,739. */ union { BITVEC_TELEM aBitmap[BITVEC_NELEM]; /* Bitmap representation */ u32 aHash[BITVEC_NINT]; /* Hash table representation */ Bitvec *apSub[BITVEC_NPTR]; /* Recursive representation */ } u; }; /* ** Create a new bitmap object able to handle bits between 0 and iSize, ** inclusive. Return a pointer to the new object. Return NULL if ** malloc fails. */ SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){ Bitvec *p; assert( sizeof(*p)==BITVEC_SZ ); p = sqlite3MallocZero( sizeof(*p) ); if( p ){ p->iSize = iSize; } return p; } /* ** Check to see if the i-th bit is set. Return true or false. ** If p is NULL (if the bitmap has not been created) or if ** i is out of range, then return false. */ SQLITE_PRIVATE int sqlite3BitvecTestNotNull(Bitvec *p, u32 i){ assert( p!=0 ); i--; if( i>=p->iSize ) return 0; while( p->iDivisor ){ u32 bin = i/p->iDivisor; i = i%p->iDivisor; p = p->u.apSub[bin]; if (!p) { return 0; } } if( p->iSize<=BITVEC_NBIT ){ return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0; } else{ u32 h = BITVEC_HASH(i++); while( p->u.aHash[h] ){ if( p->u.aHash[h]==i ) return 1; h = (h+1) % BITVEC_NINT; } return 0; } } SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec *p, u32 i){ return p!=0 && sqlite3BitvecTestNotNull(p,i); } /* ** Set the i-th bit. Return 0 on success and an error code if ** anything goes wrong. ** ** This routine might cause sub-bitmaps to be allocated. Failing ** to get the memory needed to hold the sub-bitmap is the only ** that can go wrong with an insert, assuming p and i are valid. ** ** The calling function must ensure that p is a valid Bitvec object ** and that the value for "i" is within range of the Bitvec object. ** Otherwise the behavior is undefined. */ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){ u32 h; if( p==0 ) return SQLITE_OK; assert( i>0 ); assert( i<=p->iSize ); i--; while((p->iSize > BITVEC_NBIT) && p->iDivisor) { u32 bin = i/p->iDivisor; i = i%p->iDivisor; if( p->u.apSub[bin]==0 ){ p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor ); if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT; } p = p->u.apSub[bin]; } if( p->iSize<=BITVEC_NBIT ){ p->u.aBitmap[i/BITVEC_SZELEM] |= 1 << (i&(BITVEC_SZELEM-1)); return SQLITE_OK; } h = BITVEC_HASH(i++); /* if there wasn't a hash collision, and this doesn't */ /* completely fill the hash, then just add it without */ /* worrying about sub-dividing and re-hashing. */ if( !p->u.aHash[h] ){ if (p->nSet<(BITVEC_NINT-1)) { goto bitvec_set_end; } else { goto bitvec_set_rehash; } } /* there was a collision, check to see if it's already */ /* in hash, if not, try to find a spot for it */ do { if( p->u.aHash[h]==i ) return SQLITE_OK; h++; if( h>=BITVEC_NINT ) h = 0; } while( p->u.aHash[h] ); /* we didn't find it in the hash. h points to the first */ /* available free spot. check to see if this is going to */ /* make our hash too "full". */ bitvec_set_rehash: if( p->nSet>=BITVEC_MXHASH ){ unsigned int j; int rc; u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash)); if( aiValues==0 ){ return SQLITE_NOMEM_BKPT; }else{ memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash)); memset(p->u.apSub, 0, sizeof(p->u.apSub)); p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR; rc = sqlite3BitvecSet(p, i); for(j=0; jnSet++; p->u.aHash[h] = i; return SQLITE_OK; } /* ** Clear the i-th bit. ** ** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage ** that BitvecClear can use to rebuilt its hash table. */ SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){ if( p==0 ) return; assert( i>0 ); i--; while( p->iDivisor ){ u32 bin = i/p->iDivisor; i = i%p->iDivisor; p = p->u.apSub[bin]; if (!p) { return; } } if( p->iSize<=BITVEC_NBIT ){ p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1))); }else{ unsigned int j; u32 *aiValues = pBuf; memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash)); memset(p->u.aHash, 0, sizeof(p->u.aHash)); p->nSet = 0; for(j=0; jnSet++; while( p->u.aHash[h] ){ h++; if( h>=BITVEC_NINT ) h = 0; } p->u.aHash[h] = aiValues[j]; } } } } /* ** Destroy a bitmap object. Reclaim all memory used. */ SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec *p){ if( p==0 ) return; if( p->iDivisor ){ unsigned int i; for(i=0; iu.apSub[i]); } } sqlite3_free(p); } /* ** Return the value of the iSize parameter specified when Bitvec *p ** was created. */ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){ return p->iSize; } #ifndef SQLITE_UNTESTABLE /* ** Let V[] be an array of unsigned characters sufficient to hold ** up to N bits. Let I be an integer between 0 and N. 0<=I>3] |= (1<<(I&7)) #define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7)) #define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0 /* ** This routine runs an extensive test of the Bitvec code. ** ** The input is an array of integers that acts as a program ** to test the Bitvec. The integers are opcodes followed ** by 0, 1, or 3 operands, depending on the opcode. Another ** opcode follows immediately after the last operand. ** ** There are 6 opcodes numbered from 0 through 5. 0 is the ** "halt" opcode and causes the test to end. ** ** 0 Halt and return the number of errors ** 1 N S X Set N bits beginning with S and incrementing by X ** 2 N S X Clear N bits beginning with S and incrementing by X ** 3 N Set N randomly chosen bits ** 4 N Clear N randomly chosen bits ** 5 N S X Set N bits from S increment X in array only, not in bitvec ** ** The opcodes 1 through 4 perform set and clear operations are performed ** on both a Bitvec object and on a linear array of bits obtained from malloc. ** Opcode 5 works on the linear array only, not on the Bitvec. ** Opcode 5 is used to deliberately induce a fault in order to ** confirm that error detection works. ** ** At the conclusion of the test the linear array is compared ** against the Bitvec object. If there are any differences, ** an error is returned. If they are the same, zero is returned. ** ** If a memory allocation error occurs, return -1. */ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ Bitvec *pBitvec = 0; unsigned char *pV = 0; int rc = -1; int i, nx, pc, op; void *pTmpSpace; /* Allocate the Bitvec to be tested and a linear array of ** bits to act as the reference */ pBitvec = sqlite3BitvecCreate( sz ); pV = sqlite3MallocZero( (sz+7)/8 + 1 ); pTmpSpace = sqlite3_malloc64(BITVEC_SZ); if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; /* NULL pBitvec tests */ sqlite3BitvecSet(0, 1); sqlite3BitvecClear(0, 1, pTmpSpace); /* Run the program */ pc = i = 0; while( (op = aOp[pc])!=0 ){ switch( op ){ case 1: case 2: case 5: { nx = 4; i = aOp[pc+2] - 1; aOp[pc+2] += aOp[pc+3]; break; } case 3: case 4: default: { nx = 2; sqlite3_randomness(sizeof(i), &i); break; } } if( (--aOp[pc+1]) > 0 ) nx = 0; pc += nx; i = (i & 0x7fffffff)%sz; if( (op & 1)!=0 ){ SETBIT(pV, (i+1)); if( op!=5 ){ if( sqlite3BitvecSet(pBitvec, i+1) ) goto bitvec_end; } }else{ CLEARBIT(pV, (i+1)); sqlite3BitvecClear(pBitvec, i+1, pTmpSpace); } } /* Test to make sure the linear array exactly matches the ** Bitvec object. Start with the assumption that they do ** match (rc==0). Change rc to non-zero if a discrepancy ** is found. */ rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1) + sqlite3BitvecTest(pBitvec, 0) + (sqlite3BitvecSize(pBitvec) - sz); for(i=1; i<=sz; i++){ if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){ rc = i; break; } } /* Free allocated structure */ bitvec_end: sqlite3_free(pTmpSpace); sqlite3_free(pV); sqlite3BitvecDestroy(pBitvec); return rc; } #endif /* SQLITE_UNTESTABLE */ /************** End of bitvec.c **********************************************/ /************** Begin file pcache.c ******************************************/ /* ** 2008 August 05 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file implements that page cache. */ /* #include "sqliteInt.h" */ /* ** A complete page cache is an instance of this structure. Every ** entry in the cache holds a single page of the database file. The ** btree layer only operates on the cached copy of the database pages. ** ** A page cache entry is "clean" if it exactly matches what is currently ** on disk. A page is "dirty" if it has been modified and needs to be ** persisted to disk. ** ** pDirty, pDirtyTail, pSynced: ** All dirty pages are linked into the doubly linked list using ** PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order ** such that p was added to the list more recently than p->pDirtyNext. ** PCache.pDirty points to the first (newest) element in the list and ** pDirtyTail to the last (oldest). ** ** The PCache.pSynced variable is used to optimize searching for a dirty ** page to eject from the cache mid-transaction. It is better to eject ** a page that does not require a journal sync than one that does. ** Therefore, pSynced is maintained so that it *almost* always points ** to either the oldest page in the pDirty/pDirtyTail list that has a ** clear PGHDR_NEED_SYNC flag or to a page that is older than this one ** (so that the right page to eject can be found by following pDirtyPrev ** pointers). */ struct PCache { PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ PgHdr *pSynced; /* Last synced page in dirty page list */ i64 nRefSum; /* Sum of ref counts over all pages */ int szCache; /* Configured cache size */ int szSpill; /* Size before spilling occurs */ int szPage; /* Size of every page in this cache */ int szExtra; /* Size of extra space for each page */ u8 bPurgeable; /* True if pages are on backing store */ u8 eCreate; /* eCreate value for for xFetch() */ int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ void *pStress; /* Argument to xStress */ sqlite3_pcache *pCache; /* Pluggable cache module */ }; /********************************** Test and Debug Logic **********************/ /* ** Debug tracing macros. Enable by by changing the "0" to "1" and ** recompiling. ** ** When sqlite3PcacheTrace is 1, single line trace messages are issued. ** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries ** is displayed for many operations, resulting in a lot of output. */ #if defined(SQLITE_DEBUG) && 0 int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */ int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */ # define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;} static void pcachePageTrace(int i, sqlite3_pcache_page *pLower){ PgHdr *pPg; unsigned char *a; int j; if( pLower==0 ){ printf("%3d: NULL\n", i); }else{ pPg = (PgHdr*)pLower->pExtra; printf("%3d: nRef %2lld flgs %02x data ", i, pPg->nRef, pPg->flags); a = (unsigned char *)pLower->pBuf; for(j=0; j<12; j++) printf("%02x", a[j]); printf(" ptr %p\n", pPg); } } static void pcacheDump(PCache *pCache){ int N; int i; sqlite3_pcache_page *pLower; if( sqlite3PcacheTrace<2 ) return; if( pCache->pCache==0 ) return; N = sqlite3PcachePagecount(pCache); if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump; for(i=1; i<=N; i++){ pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0); pcachePageTrace(i, pLower); if( pLower && ((PgHdr*)pLower)->pPage==0 ){ sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0); } } } #else # define pcacheTrace(X) # define pcachePageTrace(PGNO, X) # define pcacheDump(X) #endif /* ** Return 1 if pPg is on the dirty list for pCache. Return 0 if not. ** This routine runs inside of assert() statements only. */ #if defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){ PgHdr *p; for(p=pCache->pDirty; p; p=p->pDirtyNext){ if( p==pPg ) return 1; } return 0; } static int pageNotOnDirtyList(PCache *pCache, PgHdr *pPg){ PgHdr *p; for(p=pCache->pDirty; p; p=p->pDirtyNext){ if( p==pPg ) return 0; } return 1; } #else # define pageOnDirtyList(A,B) 1 # define pageNotOnDirtyList(A,B) 1 #endif /* ** Check invariants on a PgHdr entry. Return true if everything is OK. ** Return false if any invariant is violated. ** ** This routine is for use inside of assert() statements only. For ** example: ** ** assert( sqlite3PcachePageSanity(pPg) ); */ #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){ PCache *pCache; assert( pPg!=0 ); assert( pPg->pgno>0 || pPg->pPager==0 ); /* Page number is 1 or more */ pCache = pPg->pCache; assert( pCache!=0 ); /* Every page has an associated PCache */ if( pPg->flags & PGHDR_CLEAN ){ assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */ assert( pageNotOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirtylist */ }else{ assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */ assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg ); assert( pPg->pDirtyPrev==0 || pPg->pDirtyPrev->pDirtyNext==pPg ); assert( pPg->pDirtyPrev!=0 || pCache->pDirty==pPg ); assert( pageOnDirtyList(pCache, pPg) ); } /* WRITEABLE pages must also be DIRTY */ if( pPg->flags & PGHDR_WRITEABLE ){ assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */ } /* NEED_SYNC can be set independently of WRITEABLE. This can happen, ** for example, when using the sqlite3PagerDontWrite() optimization: ** (1) Page X is journalled, and gets WRITEABLE and NEED_SEEK. ** (2) Page X moved to freelist, WRITEABLE is cleared ** (3) Page X reused, WRITEABLE is set again ** If NEED_SYNC had been cleared in step 2, then it would not be reset ** in step 3, and page might be written into the database without first ** syncing the rollback journal, which might cause corruption on a power ** loss. ** ** Another example is when the database page size is smaller than the ** disk sector size. When any page of a sector is journalled, all pages ** in that sector are marked NEED_SYNC even if they are still CLEAN, just ** in case they are later modified, since all pages in the same sector ** must be journalled and synced before any of those pages can be safely ** written. */ return 1; } #endif /* SQLITE_DEBUG */ /********************************** Linked List Management ********************/ /* Allowed values for second argument to pcacheManageDirtyList() */ #define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */ #define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */ #define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */ /* ** Manage pPage's participation on the dirty list. Bits of the addRemove ** argument determines what operation to do. The 0x01 bit means first ** remove pPage from the dirty list. The 0x02 means add pPage back to ** the dirty list. Doing both moves pPage to the front of the dirty list. */ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ PCache *p = pPage->pCache; pcacheTrace(("%p.DIRTYLIST.%s %d\n", p, addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT", pPage->pgno)); if( addRemove & PCACHE_DIRTYLIST_REMOVE ){ assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); assert( pPage->pDirtyPrev || pPage==p->pDirty ); /* Update the PCache1.pSynced variable if necessary. */ if( p->pSynced==pPage ){ p->pSynced = pPage->pDirtyPrev; } if( pPage->pDirtyNext ){ pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; }else{ assert( pPage==p->pDirtyTail ); p->pDirtyTail = pPage->pDirtyPrev; } if( pPage->pDirtyPrev ){ pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; }else{ /* If there are now no dirty pages in the cache, set eCreate to 2. ** This is an optimization that allows sqlite3PcacheFetch() to skip ** searching for a dirty page to eject from the cache when it might ** otherwise have to. */ assert( pPage==p->pDirty ); p->pDirty = pPage->pDirtyNext; assert( p->bPurgeable || p->eCreate==2 ); if( p->pDirty==0 ){ /*OPTIMIZATION-IF-TRUE*/ assert( p->bPurgeable==0 || p->eCreate==1 ); p->eCreate = 2; } } } if( addRemove & PCACHE_DIRTYLIST_ADD ){ pPage->pDirtyPrev = 0; pPage->pDirtyNext = p->pDirty; if( pPage->pDirtyNext ){ assert( pPage->pDirtyNext->pDirtyPrev==0 ); pPage->pDirtyNext->pDirtyPrev = pPage; }else{ p->pDirtyTail = pPage; if( p->bPurgeable ){ assert( p->eCreate==2 ); p->eCreate = 1; } } p->pDirty = pPage; /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set ** pSynced to point to it. Checking the NEED_SYNC flag is an ** optimization, as if pSynced points to a page with the NEED_SYNC ** flag set sqlite3PcacheFetchStress() searches through all newer ** entries of the dirty-list for a page with NEED_SYNC clear anyway. */ if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/ ){ p->pSynced = pPage; } } pcacheDump(p); } /* ** Wrapper around the pluggable caches xUnpin method. If the cache is ** being used for an in-memory database, this function is a no-op. */ static void pcacheUnpin(PgHdr *p){ if( p->pCache->bPurgeable ){ pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno)); sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); pcacheDump(p->pCache); } } /* ** Compute the number of pages of cache requested. p->szCache is the ** cache size requested by the "PRAGMA cache_size" statement. */ static int numberOfCachePages(PCache *p){ if( p->szCache>=0 ){ /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the ** suggested cache size is set to N. */ return p->szCache; }else{ i64 n; /* IMPLEMENTATION-OF: R-59858-46238 If the argument N is negative, then the ** number of cache pages is adjusted to be a number of pages that would ** use approximately abs(N*1024) bytes of memory based on the current ** page size. */ n = ((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); if( n>1000000000 ) n = 1000000000; return (int)n; } } /*************************************************** General Interfaces ****** ** ** Initialize and shutdown the page cache subsystem. Neither of these ** functions are threadsafe. */ SQLITE_PRIVATE int sqlite3PcacheInitialize(void){ if( sqlite3GlobalConfig.pcache2.xInit==0 ){ /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the ** built-in default page cache is used instead of the application defined ** page cache. */ sqlite3PCacheSetDefault(); assert( sqlite3GlobalConfig.pcache2.xInit!=0 ); } return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg); } SQLITE_PRIVATE void sqlite3PcacheShutdown(void){ if( sqlite3GlobalConfig.pcache2.xShutdown ){ /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */ sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg); } } /* ** Return the size in bytes of a PCache object. */ SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); } /* ** Create a new PCache object. Storage space to hold the object ** has already been allocated and is passed in as the p pointer. ** The caller discovers how much space needs to be allocated by ** calling sqlite3PcacheSize(). ** ** szExtra is some extra space allocated for each page. The first ** 8 bytes of the extra space will be zeroed as the page is allocated, ** but remaining content will be uninitialized. Though it is opaque ** to this module, the extra space really ends up being the MemPage ** structure in the pager. */ SQLITE_PRIVATE int sqlite3PcacheOpen( int szPage, /* Size of every page */ int szExtra, /* Extra space associated with each page */ int bPurgeable, /* True if pages are on backing store */ int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */ void *pStress, /* Argument to xStress */ PCache *p /* Preallocated space for the PCache */ ){ memset(p, 0, sizeof(PCache)); p->szPage = 1; p->szExtra = szExtra; assert( szExtra>=8 ); /* First 8 bytes will be zeroed */ p->bPurgeable = bPurgeable; p->eCreate = 2; p->xStress = xStress; p->pStress = pStress; p->szCache = 100; p->szSpill = 1; pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable)); return sqlite3PcacheSetPageSize(p, szPage); } /* ** Change the page size for PCache object. The caller must ensure that there ** are no outstanding page references when this function is called. */ SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ assert( pCache->nRefSum==0 && pCache->pDirty==0 ); if( pCache->szPage ){ sqlite3_pcache *pNew; pNew = sqlite3GlobalConfig.pcache2.xCreate( szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)), pCache->bPurgeable ); if( pNew==0 ) return SQLITE_NOMEM_BKPT; sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache)); if( pCache->pCache ){ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } pCache->pCache = pNew; pCache->szPage = szPage; pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage)); } return SQLITE_OK; } /* ** Try to obtain a page from the cache. ** ** This routine returns a pointer to an sqlite3_pcache_page object if ** such an object is already in cache, or if a new one is created. ** This routine returns a NULL pointer if the object was not in cache ** and could not be created. ** ** The createFlags should be 0 to check for existing pages and should ** be 3 (not 1, but 3) to try to create a new page. ** ** If the createFlag is 0, then NULL is always returned if the page ** is not already in the cache. If createFlag is 1, then a new page ** is created only if that can be done without spilling dirty pages ** and without exceeding the cache size limit. ** ** The caller needs to invoke sqlite3PcacheFetchFinish() to properly ** initialize the sqlite3_pcache_page object and convert it into a ** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish() ** routines are split this way for performance reasons. When separated ** they can both (usually) operate without having to push values to ** the stack on entry and pop them back off on exit, which saves a ** lot of pushing and popping. */ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch( PCache *pCache, /* Obtain the page from this cache */ Pgno pgno, /* Page number to obtain */ int createFlag /* If true, create page if it does not exist already */ ){ int eCreate; sqlite3_pcache_page *pRes; assert( pCache!=0 ); assert( pCache->pCache!=0 ); assert( createFlag==3 || createFlag==0 ); assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) ); /* eCreate defines what to do if the page does not exist. ** 0 Do not allocate a new page. (createFlag==0) ** 1 Allocate a new page if doing so is inexpensive. ** (createFlag==1 AND bPurgeable AND pDirty) ** 2 Allocate a new page even it doing so is difficult. ** (createFlag==1 AND !(bPurgeable AND pDirty) */ eCreate = createFlag & pCache->eCreate; assert( eCreate==0 || eCreate==1 || eCreate==2 ); assert( createFlag==0 || pCache->eCreate==eCreate ); assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno, createFlag?" create":"",pRes)); pcachePageTrace(pgno, pRes); return pRes; } /* ** If the sqlite3PcacheFetch() routine is unable to allocate a new ** page because no clean pages are available for reuse and the cache ** size limit has been reached, then this routine can be invoked to ** try harder to allocate a page. This routine might invoke the stress ** callback to spill dirty pages to the journal. It will then try to ** allocate the new page and will only fail to allocate a new page on ** an OOM error. ** ** This routine should be invoked only after sqlite3PcacheFetch() fails. */ SQLITE_PRIVATE int sqlite3PcacheFetchStress( PCache *pCache, /* Obtain the page from this cache */ Pgno pgno, /* Page number to obtain */ sqlite3_pcache_page **ppPage /* Write result here */ ){ PgHdr *pPg; if( pCache->eCreate==2 ) return 0; if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){ /* Find a dirty page to write-out and recycle. First try to find a ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC ** cleared), but if that is not possible settle for any other ** unreferenced dirty page. ** ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC ** flag is currently referenced, then the following may leave pSynced ** set incorrectly (pointing to other than the LRU page with NEED_SYNC ** cleared). This is Ok, as pSynced is just an optimization. */ for(pPg=pCache->pSynced; pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); pPg=pPg->pDirtyPrev ); pCache->pSynced = pPg; if( !pPg ){ for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); } if( pPg ){ int rc; #ifdef SQLITE_LOG_CACHE_SPILL sqlite3_log(SQLITE_FULL, "spill page %d making room for %d - cache used: %d/%d", pPg->pgno, pgno, sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache), numberOfCachePages(pCache)); #endif pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno)); rc = pCache->xStress(pCache->pStress, pPg); pcacheDump(pCache); if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ return rc; } } } *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; } /* ** This is a helper routine for sqlite3PcacheFetchFinish() ** ** In the uncommon case where the page being fetched has not been ** initialized, this routine is invoked to do the initialization. ** This routine is broken out into a separate function since it ** requires extra stack manipulation that can be avoided in the common ** case. */ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit( PCache *pCache, /* Obtain the page from this cache */ Pgno pgno, /* Page number obtained */ sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */ ){ PgHdr *pPgHdr; assert( pPage!=0 ); pPgHdr = (PgHdr*)pPage->pExtra; assert( pPgHdr->pPage==0 ); memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr,pDirty)); pPgHdr->pPage = pPage; pPgHdr->pData = pPage->pBuf; pPgHdr->pExtra = (void *)&pPgHdr[1]; memset(pPgHdr->pExtra, 0, 8); pPgHdr->pCache = pCache; pPgHdr->pgno = pgno; pPgHdr->flags = PGHDR_CLEAN; return sqlite3PcacheFetchFinish(pCache,pgno,pPage); } /* ** This routine converts the sqlite3_pcache_page object returned by ** sqlite3PcacheFetch() into an initialized PgHdr object. This routine ** must be called after sqlite3PcacheFetch() in order to get a usable ** result. */ SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish( PCache *pCache, /* Obtain the page from this cache */ Pgno pgno, /* Page number obtained */ sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */ ){ PgHdr *pPgHdr; assert( pPage!=0 ); pPgHdr = (PgHdr *)pPage->pExtra; if( !pPgHdr->pPage ){ return pcacheFetchFinishWithInit(pCache, pgno, pPage); } pCache->nRefSum++; pPgHdr->nRef++; assert( sqlite3PcachePageSanity(pPgHdr) ); return pPgHdr; } /* ** Decrement the reference count on a page. If the page is clean and the ** reference count drops to 0, then it is made eligible for recycling. */ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ assert( p->nRef>0 ); p->pCache->nRefSum--; if( (--p->nRef)==0 ){ if( p->flags&PGHDR_CLEAN ){ pcacheUnpin(p); }else{ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); assert( sqlite3PcachePageSanity(p) ); } } } /* ** Increase the reference count of a supplied page by 1. */ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){ assert(p->nRef>0); assert( sqlite3PcachePageSanity(p) ); p->nRef++; p->pCache->nRefSum++; } /* ** Drop a page from the cache. There must be exactly one reference to the ** page. This function deletes that reference, so after it returns the ** page pointed to by p is invalid. */ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){ assert( p->nRef==1 ); assert( sqlite3PcachePageSanity(p) ); if( p->flags&PGHDR_DIRTY ){ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); } p->pCache->nRefSum--; sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1); } /* ** Make sure the page is marked as dirty. If it isn't dirty already, ** make it so. */ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){ assert( p->nRef>0 ); assert( sqlite3PcachePageSanity(p) ); if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/ p->flags &= ~PGHDR_DONT_WRITE; if( p->flags & PGHDR_CLEAN ){ p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN); pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno)); assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY ); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); assert( sqlite3PcachePageSanity(p) ); } assert( sqlite3PcachePageSanity(p) ); } } /* ** Make sure the page is marked as clean. If it isn't clean already, ** make it so. */ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){ assert( sqlite3PcachePageSanity(p) ); assert( (p->flags & PGHDR_DIRTY)!=0 ); assert( (p->flags & PGHDR_CLEAN)==0 ); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE); p->flags |= PGHDR_CLEAN; pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno)); assert( sqlite3PcachePageSanity(p) ); if( p->nRef==0 ){ pcacheUnpin(p); } } /* ** Make every page in the cache clean. */ SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){ PgHdr *p; pcacheTrace(("%p.CLEAN-ALL\n",pCache)); while( (p = pCache->pDirty)!=0 ){ sqlite3PcacheMakeClean(p); } } /* ** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages. */ SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache *pCache){ PgHdr *p; pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache)); for(p=pCache->pDirty; p; p=p->pDirtyNext){ p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE); } pCache->pSynced = pCache->pDirtyTail; } /* ** Clear the PGHDR_NEED_SYNC flag from all dirty pages. */ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){ PgHdr *p; for(p=pCache->pDirty; p; p=p->pDirtyNext){ p->flags &= ~PGHDR_NEED_SYNC; } pCache->pSynced = pCache->pDirtyTail; } /* ** Change the page number of page p to newPgno. */ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ PCache *pCache = p->pCache; sqlite3_pcache_page *pOther; assert( p->nRef>0 ); assert( newPgno>0 ); assert( sqlite3PcachePageSanity(p) ); pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno)); pOther = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, newPgno, 0); if( pOther ){ PgHdr *pXPage = (PgHdr*)pOther->pExtra; assert( pXPage->nRef==0 ); pXPage->nRef++; pCache->nRefSum++; sqlite3PcacheDrop(pXPage); } sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); p->pgno = newPgno; if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); assert( sqlite3PcachePageSanity(p) ); } } /* ** Drop every cache entry whose page number is greater than "pgno". The ** caller must ensure that there are no outstanding references to any pages ** other than page 1 with a page number greater than pgno. ** ** If there is a reference to page 1 and the pgno parameter passed to this ** function is 0, then the data area associated with page 1 is zeroed, but ** the page object is not dropped. */ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ if( pCache->pCache ){ PgHdr *p; PgHdr *pNext; pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno)); for(p=pCache->pDirty; p; p=pNext){ pNext = p->pDirtyNext; /* This routine never gets call with a positive pgno except right ** after sqlite3PcacheCleanAll(). So if there are dirty pages, ** it must be that pgno==0. */ assert( p->pgno>0 ); if( p->pgno>pgno ){ assert( p->flags&PGHDR_DIRTY ); sqlite3PcacheMakeClean(p); } } if( pgno==0 && pCache->nRefSum ){ sqlite3_pcache_page *pPage1; pPage1 = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache,1,0); if( ALWAYS(pPage1) ){ /* Page 1 is always available in cache, because ** pCache->nRefSum>0 */ memset(pPage1->pBuf, 0, pCache->szPage); pgno = 1; } } sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1); } } /* ** Close a cache. */ SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){ assert( pCache->pCache!=0 ); pcacheTrace(("%p.CLOSE\n",pCache)); sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } /* ** Discard the contents of the cache. */ SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){ sqlite3PcacheTruncate(pCache, 0); } /* ** Merge two lists of pages connected by pDirty and in pgno order. ** Do not bother fixing the pDirtyPrev pointers. */ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ PgHdr result, *pTail; pTail = &result; assert( pA!=0 && pB!=0 ); for(;;){ if( pA->pgnopgno ){ pTail->pDirty = pA; pTail = pA; pA = pA->pDirty; if( pA==0 ){ pTail->pDirty = pB; break; } }else{ pTail->pDirty = pB; pTail = pB; pB = pB->pDirty; if( pB==0 ){ pTail->pDirty = pA; break; } } } return result.pDirty; } /* ** Sort the list of pages in ascending order by pgno. Pages are ** connected by pDirty pointers. The pDirtyPrev pointers are ** corrupted by this sort. ** ** Since there cannot be more than 2^31 distinct pages in a database, ** there cannot be more than 31 buckets required by the merge sorter. ** One extra bucket is added to catch overflow in case something ** ever changes to make the previous sentence incorrect. */ #define N_SORT_BUCKET 32 static PgHdr *pcacheSortDirtyList(PgHdr *pIn){ PgHdr *a[N_SORT_BUCKET], *p; int i; memset(a, 0, sizeof(a)); while( pIn ){ p = pIn; pIn = p->pDirty; p->pDirty = 0; for(i=0; ALWAYS(ipDirty; p; p=p->pDirtyNext){ p->pDirty = p->pDirtyNext; } return pcacheSortDirtyList(pCache->pDirty); } /* ** Return the total number of references to all pages held by the cache. ** ** This is not the total number of pages referenced, but the sum of the ** reference count for all pages. */ SQLITE_PRIVATE i64 sqlite3PcacheRefCount(PCache *pCache){ return pCache->nRefSum; } /* ** Return the number of references to the page supplied as an argument. */ SQLITE_PRIVATE i64 sqlite3PcachePageRefcount(PgHdr *p){ return p->nRef; } /* ** Return the total number of pages in the cache. */ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){ assert( pCache->pCache!=0 ); return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache); } #ifdef SQLITE_TEST /* ** Get the suggested cache-size value. */ SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){ return numberOfCachePages(pCache); } #endif /* ** Set the suggested cache-size value. */ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ assert( pCache->pCache!=0 ); pCache->szCache = mxPage; sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache, numberOfCachePages(pCache)); } /* ** Set the suggested cache-spill value. Make no changes if if the ** argument is zero. Return the effective cache-spill size, which will ** be the larger of the szSpill and szCache. */ SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){ int res; assert( p->pCache!=0 ); if( mxPage ){ if( mxPage<0 ){ mxPage = (int)((-1024*(i64)mxPage)/(p->szPage+p->szExtra)); } p->szSpill = mxPage; } res = numberOfCachePages(p); if( resszSpill ) res = p->szSpill; return res; } /* ** Free up as much memory as possible from the page cache. */ SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){ assert( pCache->pCache!=0 ); sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); } /* ** Return the size of the header added by this middleware layer ** in the page-cache hierarchy. */ SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); } /* ** Return the number of dirty pages currently in the cache, as a percentage ** of the configured cache size. */ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){ PgHdr *pDirty; int nDirty = 0; int nCache = numberOfCachePages(pCache); for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++; return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0; } #ifdef SQLITE_DIRECT_OVERFLOW_READ /* ** Return true if there are one or more dirty pages in the cache. Else false. */ SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache){ return (pCache->pDirty!=0); } #endif #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* ** For all dirty pages currently in the cache, invoke the specified ** callback. This is only used if the SQLITE_CHECK_PAGES macro is ** defined. */ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){ PgHdr *pDirty; for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){ xIter(pDirty); } } #endif /************** End of pcache.c **********************************************/ /************** Begin file pcache1.c *****************************************/ /* ** 2008 November 05 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file implements the default page cache implementation (the ** sqlite3_pcache interface). It also contains part of the implementation ** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features. ** If the default page cache implementation is overridden, then neither of ** these two features are available. ** ** A Page cache line looks like this: ** ** ------------------------------------------------------------- ** | database page content | PgHdr1 | MemPage | PgHdr | ** ------------------------------------------------------------- ** ** The database page content is up front (so that buffer overreads tend to ** flow harmlessly into the PgHdr1, MemPage, and PgHdr extensions). MemPage ** is the extension added by the btree.c module containing information such ** as the database page number and how that database page is used. PgHdr ** is added by the pcache.c layer and contains information used to keep track ** of which pages are "dirty". PgHdr1 is an extension added by this ** module (pcache1.c). The PgHdr1 header is a subclass of sqlite3_pcache_page. ** PgHdr1 contains information needed to look up a page by its page number. ** The superclass sqlite3_pcache_page.pBuf points to the start of the ** database page content and sqlite3_pcache_page.pExtra points to PgHdr. ** ** The size of the extension (MemPage+PgHdr+PgHdr1) can be determined at ** runtime using sqlite3_config(SQLITE_CONFIG_PCACHE_HDRSZ, &size). The ** sizes of the extensions sum to 272 bytes on x64 for 3.8.10, but this ** size can vary according to architecture, compile-time options, and ** SQLite library version number. ** ** Historical note: It used to be that if the SQLITE_PCACHE_SEPARATE_HEADER ** was defined, then the page content would be held in a separate memory ** allocation from the PgHdr1. This was intended to avoid clownshoe memory ** allocations. However, the btree layer needs a small (16-byte) overrun ** area after the page content buffer. The header serves as that overrun ** area. Therefore SQLITE_PCACHE_SEPARATE_HEADER was discontinued to avoid ** any possibility of a memory error. ** ** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates ** with this module. Information is passed back and forth as PgHdr1 pointers. ** ** The pcache.c and pager.c modules deal pointers to PgHdr objects. ** The btree.c module deals with pointers to MemPage objects. ** ** SOURCE OF PAGE CACHE MEMORY: ** ** Memory for a page might come from any of three sources: ** ** (1) The general-purpose memory allocator - sqlite3Malloc() ** (2) Global page-cache memory provided using sqlite3_config() with ** SQLITE_CONFIG_PAGECACHE. ** (3) PCache-local bulk allocation. ** ** The third case is a chunk of heap memory (defaulting to 100 pages worth) ** that is allocated when the page cache is created. The size of the local ** bulk allocation can be adjusted using ** ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N). ** ** If N is positive, then N pages worth of memory are allocated using a single ** sqlite3Malloc() call and that memory is used for the first N pages allocated. ** Or if N is negative, then -1024*N bytes of memory are allocated and used ** for as many pages as can be accommodated. ** ** Only one of (2) or (3) can be used. Once the memory available to (2) or ** (3) is exhausted, subsequent allocations fail over to the general-purpose ** memory allocator (1). ** ** Earlier versions of SQLite used only methods (1) and (2). But experiments ** show that method (3) with N==100 provides about a 5% performance boost for ** common workloads. */ /* #include "sqliteInt.h" */ typedef struct PCache1 PCache1; typedef struct PgHdr1 PgHdr1; typedef struct PgFreeslot PgFreeslot; typedef struct PGroup PGroup; /* ** Each cache entry is represented by an instance of the following ** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated ** directly before this structure and is used to cache the page content. ** ** When reading a corrupt database file, it is possible that SQLite might ** read a few bytes (no more than 16 bytes) past the end of the page buffer. ** It will only read past the end of the page buffer, never write. This ** object is positioned immediately after the page buffer to serve as an ** overrun area, so that overreads are harmless. ** ** Variables isBulkLocal and isAnchor were once type "u8". That works, ** but causes a 2-byte gap in the structure for most architectures (since ** pointers must be either 4 or 8-byte aligned). As this structure is located ** in memory directly after the associated page data, if the database is ** corrupt, code at the b-tree layer may overread the page buffer and ** read part of this structure before the corruption is detected. This ** can cause a valgrind error if the uninitialized gap is accessed. Using u16 ** ensures there is no such gap, and therefore no bytes of uninitialized ** memory in the structure. ** ** The pLruNext and pLruPrev pointers form a double-linked circular list ** of all pages that are unpinned. The PGroup.lru element (which should be ** the only element on the list with PgHdr1.isAnchor set to 1) forms the ** beginning and the end of the list. */ struct PgHdr1 { sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */ unsigned int iKey; /* Key value (page number) */ u16 isBulkLocal; /* This page from bulk local storage */ u16 isAnchor; /* This is the PGroup.lru element */ PgHdr1 *pNext; /* Next in hash table chain */ PCache1 *pCache; /* Cache that currently owns this page */ PgHdr1 *pLruNext; /* Next in circular LRU list of unpinned pages */ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */ /* NB: pLruPrev is only valid if pLruNext!=0 */ }; /* ** A page is pinned if it is not on the LRU list. To be "pinned" means ** that the page is in active use and must not be deallocated. */ #define PAGE_IS_PINNED(p) ((p)->pLruNext==0) #define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0) /* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set ** of one or more PCaches that are able to recycle each other's unpinned ** pages when they are under memory pressure. A PGroup is an instance of ** the following object. ** ** This page cache implementation works in one of two modes: ** ** (1) Every PCache is the sole member of its own PGroup. There is ** one PGroup per PCache. ** ** (2) There is a single global PGroup that all PCaches are a member ** of. ** ** Mode 1 uses more memory (since PCache instances are not able to rob ** unused pages from other PCaches) but it also operates without a mutex, ** and is therefore often faster. Mode 2 requires a mutex in order to be ** threadsafe, but recycles pages more efficiently. ** ** For mode (1), PGroup.mutex is NULL. For mode (2) there is only a single ** PGroup which is the pcache1.grp global variable and its mutex is ** SQLITE_MUTEX_STATIC_LRU. */ struct PGroup { sqlite3_mutex *mutex; /* MUTEX_STATIC_LRU or NULL */ unsigned int nMaxPage; /* Sum of nMax for purgeable caches */ unsigned int nMinPage; /* Sum of nMin for purgeable caches */ unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */ unsigned int nPurgeable; /* Number of purgeable pages allocated */ PgHdr1 lru; /* The beginning and end of the LRU list */ }; /* Each page cache is an instance of the following object. Every ** open database file (including each in-memory database and each ** temporary or transient database) has a single page cache which ** is an instance of this object. ** ** Pointers to structures of this type are cast and returned as ** opaque sqlite3_pcache* handles. */ struct PCache1 { /* Cache configuration parameters. Page size (szPage) and the purgeable ** flag (bPurgeable) and the pnPurgeable pointer are all set when the ** cache is created and are never changed thereafter. nMax may be ** modified at any time by a call to the pcache1Cachesize() method. ** The PGroup mutex must be held when accessing nMax. */ PGroup *pGroup; /* PGroup this cache belongs to */ unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */ int szPage; /* Size of database content section */ int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */ int szAlloc; /* Total size of one pcache line */ int bPurgeable; /* True if cache is purgeable */ unsigned int nMin; /* Minimum number of pages reserved */ unsigned int nMax; /* Configured "cache_size" value */ unsigned int n90pct; /* nMax*9/10 */ unsigned int iMaxKey; /* Largest key seen since xTruncate() */ unsigned int nPurgeableDummy; /* pnPurgeable points here when not used*/ /* Hash table of all pages. The following variables may only be accessed ** when the accessor is holding the PGroup mutex. */ unsigned int nRecyclable; /* Number of pages in the LRU list */ unsigned int nPage; /* Total number of pages in apHash */ unsigned int nHash; /* Number of slots in apHash[] */ PgHdr1 **apHash; /* Hash table for fast lookup by key */ PgHdr1 *pFree; /* List of unused pcache-local pages */ void *pBulk; /* Bulk memory used by pcache-local */ }; /* ** Free slots in the allocator used to divide up the global page cache ** buffer provided using the SQLITE_CONFIG_PAGECACHE mechanism. */ struct PgFreeslot { PgFreeslot *pNext; /* Next free slot */ }; /* ** Global data used by this cache. */ static SQLITE_WSD struct PCacheGlobal { PGroup grp; /* The global PGroup for mode (2) */ /* Variables related to SQLITE_CONFIG_PAGECACHE settings. The ** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all ** fixed at sqlite3_initialize() time and do not require mutex protection. ** The nFreeSlot and pFree values do require mutex protection. */ int isInit; /* True if initialized */ int separateCache; /* Use a new PGroup for each PCache */ int nInitPage; /* Initial bulk allocation size */ int szSlot; /* Size of each free slot */ int nSlot; /* The number of pcache slots */ int nReserve; /* Try to keep nFreeSlot above this */ void *pStart, *pEnd; /* Bounds of global page cache memory */ /* Above requires no mutex. Use mutex below for variable that follow. */ sqlite3_mutex *mutex; /* Mutex for accessing the following: */ PgFreeslot *pFree; /* Free page blocks */ int nFreeSlot; /* Number of unused pcache slots */ /* The following value requires a mutex to change. We skip the mutex on ** reading because (1) most platforms read a 32-bit integer atomically and ** (2) even if an incorrect value is read, no great harm is done since this ** is really just an optimization. */ int bUnderPressure; /* True if low on PAGECACHE memory */ } pcache1_g; /* ** All code in this file should access the global structure above via the ** alias "pcache1". This ensures that the WSD emulation is used when ** compiling for systems that do not support real WSD. */ #define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g)) /* ** Macros to enter and leave the PCache LRU mutex. */ #if !defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0 # define pcache1EnterMutex(X) assert((X)->mutex==0) # define pcache1LeaveMutex(X) assert((X)->mutex==0) # define PCACHE1_MIGHT_USE_GROUP_MUTEX 0 #else # define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex) # define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex) # define PCACHE1_MIGHT_USE_GROUP_MUTEX 1 #endif /******************************************************************************/ /******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/ /* ** This function is called during initialization if a static buffer is ** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE ** verb to sqlite3_config(). Parameter pBuf points to an allocation large ** enough to contain 'n' buffers of 'sz' bytes each. ** ** This routine is called from sqlite3_initialize() and so it is guaranteed ** to be serialized already. There is no need for further mutexing. */ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ if( pcache1.isInit ){ PgFreeslot *p; if( pBuf==0 ) sz = n = 0; if( n==0 ) sz = 0; sz = ROUNDDOWN8(sz); pcache1.szSlot = sz; pcache1.nSlot = pcache1.nFreeSlot = n; pcache1.nReserve = n>90 ? 10 : (n/10 + 1); pcache1.pStart = pBuf; pcache1.pFree = 0; pcache1.bUnderPressure = 0; while( n-- ){ p = (PgFreeslot*)pBuf; p->pNext = pcache1.pFree; pcache1.pFree = p; pBuf = (void*)&((char*)pBuf)[sz]; } pcache1.pEnd = pBuf; } } /* ** Try to initialize the pCache->pFree and pCache->pBulk fields. Return ** true if pCache->pFree ends up containing one or more free pages. */ static int pcache1InitBulk(PCache1 *pCache){ i64 szBulk; char *zBulk; if( pcache1.nInitPage==0 ) return 0; /* Do not bother with a bulk allocation if the cache size very small */ if( pCache->nMax<3 ) return 0; sqlite3BeginBenignMalloc(); if( pcache1.nInitPage>0 ){ szBulk = pCache->szAlloc * (i64)pcache1.nInitPage; }else{ szBulk = -1024 * (i64)pcache1.nInitPage; } if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){ szBulk = pCache->szAlloc*(i64)pCache->nMax; } zBulk = pCache->pBulk = sqlite3Malloc( szBulk ); sqlite3EndBenignMalloc(); if( zBulk ){ int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc; do{ PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; pX->page.pBuf = zBulk; pX->page.pExtra = &pX[1]; pX->isBulkLocal = 1; pX->isAnchor = 0; pX->pNext = pCache->pFree; pX->pLruPrev = 0; /* Initializing this saves a valgrind error */ pCache->pFree = pX; zBulk += pCache->szAlloc; }while( --nBulk ); } return pCache->pFree!=0; } /* ** Malloc function used within this file to allocate space from the buffer ** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no ** such buffer exists or there is no space left in it, this function falls ** back to sqlite3Malloc(). ** ** Multiple threads can run this routine at the same time. Global variables ** in pcache1 need to be protected via mutex. */ static void *pcache1Alloc(int nByte){ void *p = 0; assert( sqlite3_mutex_notheld(pcache1.grp.mutex) ); if( nByte<=pcache1.szSlot ){ sqlite3_mutex_enter(pcache1.mutex); p = (PgHdr1 *)pcache1.pFree; if( p ){ pcache1.pFree = pcache1.pFree->pNext; pcache1.nFreeSlot--; pcache1.bUnderPressure = pcache1.nFreeSlot=0 ); sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte); sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1); } sqlite3_mutex_leave(pcache1.mutex); } if( p==0 ){ /* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool. Get ** it from sqlite3Malloc instead. */ p = sqlite3Malloc(nByte); #ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS if( p ){ int sz = sqlite3MallocSize(p); sqlite3_mutex_enter(pcache1.mutex); sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte); sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz); sqlite3_mutex_leave(pcache1.mutex); } #endif sqlite3MemdebugSetType(p, MEMTYPE_PCACHE); } return p; } /* ** Free an allocated buffer obtained from pcache1Alloc(). */ static void pcache1Free(void *p){ if( p==0 ) return; if( SQLITE_WITHIN(p, pcache1.pStart, pcache1.pEnd) ){ PgFreeslot *pSlot; sqlite3_mutex_enter(pcache1.mutex); sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1); pSlot = (PgFreeslot*)p; pSlot->pNext = pcache1.pFree; pcache1.pFree = pSlot; pcache1.nFreeSlot++; pcache1.bUnderPressure = pcache1.nFreeSlot=pcache1.pStart && ppGroup->mutex) ); if( pCache->pFree || (pCache->nPage==0 && pcache1InitBulk(pCache)) ){ assert( pCache->pFree!=0 ); p = pCache->pFree; pCache->pFree = p->pNext; p->pNext = 0; }else{ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* The group mutex must be released before pcache1Alloc() is called. This ** is because it might call sqlite3_release_memory(), which assumes that ** this mutex is not held. */ assert( pcache1.separateCache==0 ); assert( pCache->pGroup==&pcache1.grp ); pcache1LeaveMutex(pCache->pGroup); #endif if( benignMalloc ){ sqlite3BeginBenignMalloc(); } pPg = pcache1Alloc(pCache->szAlloc); if( benignMalloc ){ sqlite3EndBenignMalloc(); } #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT pcache1EnterMutex(pCache->pGroup); #endif if( pPg==0 ) return 0; p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage]; p->page.pBuf = pPg; p->page.pExtra = &p[1]; p->isBulkLocal = 0; p->isAnchor = 0; p->pLruPrev = 0; /* Initializing this saves a valgrind error */ } (*pCache->pnPurgeable)++; return p; } /* ** Free a page object allocated by pcache1AllocPage(). */ static void pcache1FreePage(PgHdr1 *p){ PCache1 *pCache; assert( p!=0 ); pCache = p->pCache; assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) ); if( p->isBulkLocal ){ p->pNext = pCache->pFree; pCache->pFree = p; }else{ pcache1Free(p->page.pBuf); } (*pCache->pnPurgeable)--; } /* ** Malloc function used by SQLite to obtain space from the buffer configured ** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer ** exists, this function falls back to sqlite3Malloc(). */ SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){ assert( sz<=65536+8 ); /* These allocations are never very large */ return pcache1Alloc(sz); } /* ** Free an allocated buffer obtained from sqlite3PageMalloc(). */ SQLITE_PRIVATE void sqlite3PageFree(void *p){ pcache1Free(p); } /* ** Return true if it desirable to avoid allocating a new page cache ** entry. ** ** If memory was allocated specifically to the page cache using ** SQLITE_CONFIG_PAGECACHE but that memory has all been used, then ** it is desirable to avoid allocating a new page cache entry because ** presumably SQLITE_CONFIG_PAGECACHE was suppose to be sufficient ** for all page cache needs and we should not need to spill the ** allocation onto the heap. ** ** Or, the heap is used for all page cache memory but the heap is ** under memory pressure, then again it is desirable to avoid ** allocating a new page cache entry in order to avoid stressing ** the heap even further. */ static int pcache1UnderMemoryPressure(PCache1 *pCache){ if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){ return pcache1.bUnderPressure; }else{ return sqlite3HeapNearlyFull(); } } /******************************************************************************/ /******** General Implementation Functions ************************************/ /* ** This function is used to resize the hash table used by the cache passed ** as the first argument. ** ** The PCache mutex must be held when this function is called. */ static void pcache1ResizeHash(PCache1 *p){ PgHdr1 **apNew; unsigned int nNew; unsigned int i; assert( sqlite3_mutex_held(p->pGroup->mutex) ); nNew = p->nHash*2; if( nNew<256 ){ nNew = 256; } pcache1LeaveMutex(p->pGroup); if( p->nHash ){ sqlite3BeginBenignMalloc(); } apNew = (PgHdr1 **)sqlite3MallocZero(sizeof(PgHdr1 *)*nNew); if( p->nHash ){ sqlite3EndBenignMalloc(); } pcache1EnterMutex(p->pGroup); if( apNew ){ for(i=0; inHash; i++){ PgHdr1 *pPage; PgHdr1 *pNext = p->apHash[i]; while( (pPage = pNext)!=0 ){ unsigned int h = pPage->iKey % nNew; pNext = pPage->pNext; pPage->pNext = apNew[h]; apNew[h] = pPage; } } sqlite3_free(p->apHash); p->apHash = apNew; p->nHash = nNew; } } /* ** This function is used internally to remove the page pPage from the ** PGroup LRU list, if is part of it. If pPage is not part of the PGroup ** LRU list, then this function is a no-op. ** ** The PGroup mutex must be held when this function is called. */ static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){ assert( pPage!=0 ); assert( PAGE_IS_UNPINNED(pPage) ); assert( pPage->pLruNext ); assert( pPage->pLruPrev ); assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) ); pPage->pLruPrev->pLruNext = pPage->pLruNext; pPage->pLruNext->pLruPrev = pPage->pLruPrev; pPage->pLruNext = 0; /* pPage->pLruPrev = 0; ** No need to clear pLruPrev as it is never accessed if pLruNext is 0 */ assert( pPage->isAnchor==0 ); assert( pPage->pCache->pGroup->lru.isAnchor==1 ); pPage->pCache->nRecyclable--; return pPage; } /* ** Remove the page supplied as an argument from the hash table ** (PCache1.apHash structure) that it is currently stored in. ** Also free the page if freePage is true. ** ** The PGroup mutex must be held when this function is called. */ static void pcache1RemoveFromHash(PgHdr1 *pPage, int freeFlag){ unsigned int h; PCache1 *pCache = pPage->pCache; PgHdr1 **pp; assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); h = pPage->iKey % pCache->nHash; for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext); *pp = (*pp)->pNext; pCache->nPage--; if( freeFlag ) pcache1FreePage(pPage); } /* ** If there are currently more than nMaxPage pages allocated, try ** to recycle pages to reduce the number allocated to nMaxPage. */ static void pcache1EnforceMaxPage(PCache1 *pCache){ PGroup *pGroup = pCache->pGroup; PgHdr1 *p; assert( sqlite3_mutex_held(pGroup->mutex) ); while( pGroup->nPurgeable>pGroup->nMaxPage && (p=pGroup->lru.pLruPrev)->isAnchor==0 ){ assert( p->pCache->pGroup==pGroup ); assert( PAGE_IS_UNPINNED(p) ); pcache1PinPage(p); pcache1RemoveFromHash(p, 1); } if( pCache->nPage==0 && pCache->pBulk ){ sqlite3_free(pCache->pBulk); pCache->pBulk = pCache->pFree = 0; } } /* ** Discard all pages from cache pCache with a page number (key value) ** greater than or equal to iLimit. Any pinned pages that meet this ** criteria are unpinned before they are discarded. ** ** The PCache mutex must be held when this function is called. */ static void pcache1TruncateUnsafe( PCache1 *pCache, /* The cache to truncate */ unsigned int iLimit /* Drop pages with this pgno or larger */ ){ TESTONLY( int nPage = 0; ) /* To assert pCache->nPage is correct */ unsigned int h, iStop; assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); assert( pCache->iMaxKey >= iLimit ); assert( pCache->nHash > 0 ); if( pCache->iMaxKey - iLimit < pCache->nHash ){ /* If we are just shaving the last few pages off the end of the ** cache, then there is no point in scanning the entire hash table. ** Only scan those hash slots that might contain pages that need to ** be removed. */ h = iLimit % pCache->nHash; iStop = pCache->iMaxKey % pCache->nHash; TESTONLY( nPage = -10; ) /* Disable the pCache->nPage validity check */ }else{ /* This is the general case where many pages are being removed. ** It is necessary to scan the entire hash table */ h = pCache->nHash/2; iStop = h - 1; } for(;;){ PgHdr1 **pp; PgHdr1 *pPage; assert( hnHash ); pp = &pCache->apHash[h]; while( (pPage = *pp)!=0 ){ if( pPage->iKey>=iLimit ){ pCache->nPage--; *pp = pPage->pNext; if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage); pcache1FreePage(pPage); }else{ pp = &pPage->pNext; TESTONLY( if( nPage>=0 ) nPage++; ) } } if( h==iStop ) break; h = (h+1) % pCache->nHash; } assert( nPage<0 || pCache->nPage==(unsigned)nPage ); } /******************************************************************************/ /******** sqlite3_pcache Methods **********************************************/ /* ** Implementation of the sqlite3_pcache.xInit method. */ static int pcache1Init(void *NotUsed){ UNUSED_PARAMETER(NotUsed); assert( pcache1.isInit==0 ); memset(&pcache1, 0, sizeof(pcache1)); /* ** The pcache1.separateCache variable is true if each PCache has its own ** private PGroup (mode-1). pcache1.separateCache is false if the single ** PGroup in pcache1.grp is used for all page caches (mode-2). ** ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT ** ** * Use a unified cache in single-threaded applications that have ** configured a start-time buffer for use as page-cache memory using ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL ** pBuf argument. ** ** * Otherwise use separate caches (mode-1) */ #if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) pcache1.separateCache = 0; #elif SQLITE_THREADSAFE pcache1.separateCache = sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.bCoreMutex>0; #else pcache1.separateCache = sqlite3GlobalConfig.pPage==0; #endif #if SQLITE_THREADSAFE if( sqlite3GlobalConfig.bCoreMutex ){ pcache1.grp.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU); pcache1.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PMEM); } #endif if( pcache1.separateCache && sqlite3GlobalConfig.nPage!=0 && sqlite3GlobalConfig.pPage==0 ){ pcache1.nInitPage = sqlite3GlobalConfig.nPage; }else{ pcache1.nInitPage = 0; } pcache1.grp.mxPinned = 10; pcache1.isInit = 1; return SQLITE_OK; } /* ** Implementation of the sqlite3_pcache.xShutdown method. ** Note that the static mutex allocated in xInit does ** not need to be freed. */ static void pcache1Shutdown(void *NotUsed){ UNUSED_PARAMETER(NotUsed); assert( pcache1.isInit!=0 ); memset(&pcache1, 0, sizeof(pcache1)); } /* forward declaration */ static void pcache1Destroy(sqlite3_pcache *p); /* ** Implementation of the sqlite3_pcache.xCreate method. ** ** Allocate a new cache. */ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ PCache1 *pCache; /* The newly created page cache */ PGroup *pGroup; /* The group the new page cache will belong to */ int sz; /* Bytes of memory required to allocate the new cache */ assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 ); assert( szExtra < 300 ); sz = sizeof(PCache1) + sizeof(PGroup)*pcache1.separateCache; pCache = (PCache1 *)sqlite3MallocZero(sz); if( pCache ){ if( pcache1.separateCache ){ pGroup = (PGroup*)&pCache[1]; pGroup->mxPinned = 10; }else{ pGroup = &pcache1.grp; } pcache1EnterMutex(pGroup); if( pGroup->lru.isAnchor==0 ){ pGroup->lru.isAnchor = 1; pGroup->lru.pLruPrev = pGroup->lru.pLruNext = &pGroup->lru; } pCache->pGroup = pGroup; pCache->szPage = szPage; pCache->szExtra = szExtra; pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1)); pCache->bPurgeable = (bPurgeable ? 1 : 0); pcache1ResizeHash(pCache); if( bPurgeable ){ pCache->nMin = 10; pGroup->nMinPage += pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; pCache->pnPurgeable = &pGroup->nPurgeable; }else{ pCache->pnPurgeable = &pCache->nPurgeableDummy; } pcache1LeaveMutex(pGroup); if( pCache->nHash==0 ){ pcache1Destroy((sqlite3_pcache*)pCache); pCache = 0; } } return (sqlite3_pcache *)pCache; } /* ** Implementation of the sqlite3_pcache.xCachesize method. ** ** Configure the cache_size limit for a cache. */ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){ PCache1 *pCache = (PCache1 *)p; u32 n; assert( nMax>=0 ); if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; pcache1EnterMutex(pGroup); n = (u32)nMax; if( n > 0x7fff0000 - pGroup->nMaxPage + pCache->nMax ){ n = 0x7fff0000 - pGroup->nMaxPage + pCache->nMax; } pGroup->nMaxPage += (n - pCache->nMax); pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; pCache->nMax = n; pCache->n90pct = pCache->nMax*9/10; pcache1EnforceMaxPage(pCache); pcache1LeaveMutex(pGroup); } } /* ** Implementation of the sqlite3_pcache.xShrink method. ** ** Free up as much memory as possible. */ static void pcache1Shrink(sqlite3_pcache *p){ PCache1 *pCache = (PCache1*)p; if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; unsigned int savedMaxPage; pcache1EnterMutex(pGroup); savedMaxPage = pGroup->nMaxPage; pGroup->nMaxPage = 0; pcache1EnforceMaxPage(pCache); pGroup->nMaxPage = savedMaxPage; pcache1LeaveMutex(pGroup); } } /* ** Implementation of the sqlite3_pcache.xPagecount method. */ static int pcache1Pagecount(sqlite3_pcache *p){ int n; PCache1 *pCache = (PCache1*)p; pcache1EnterMutex(pCache->pGroup); n = pCache->nPage; pcache1LeaveMutex(pCache->pGroup); return n; } /* ** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described ** in the header of the pcache1Fetch() procedure. ** ** This steps are broken out into a separate procedure because they are ** usually not needed, and by avoiding the stack initialization required ** for these steps, the main pcache1Fetch() procedure can run faster. */ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( PCache1 *pCache, unsigned int iKey, int createFlag ){ unsigned int nPinned; PGroup *pGroup = pCache->pGroup; PgHdr1 *pPage = 0; /* Step 3: Abort if createFlag is 1 but the cache is nearly full */ assert( pCache->nPage >= pCache->nRecyclable ); nPinned = pCache->nPage - pCache->nRecyclable; assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage ); assert( pCache->n90pct == pCache->nMax*9/10 ); if( createFlag==1 && ( nPinned>=pGroup->mxPinned || nPinned>=pCache->n90pct || (pcache1UnderMemoryPressure(pCache) && pCache->nRecyclablenPage>=pCache->nHash ) pcache1ResizeHash(pCache); assert( pCache->nHash>0 && pCache->apHash ); /* Step 4. Try to recycle a page. */ if( pCache->bPurgeable && !pGroup->lru.pLruPrev->isAnchor && ((pCache->nPage+1>=pCache->nMax) || pcache1UnderMemoryPressure(pCache)) ){ PCache1 *pOther; pPage = pGroup->lru.pLruPrev; assert( PAGE_IS_UNPINNED(pPage) ); pcache1RemoveFromHash(pPage, 0); pcache1PinPage(pPage); pOther = pPage->pCache; if( pOther->szAlloc != pCache->szAlloc ){ pcache1FreePage(pPage); pPage = 0; }else{ pGroup->nPurgeable -= (pOther->bPurgeable - pCache->bPurgeable); } } /* Step 5. If a usable page buffer has still not been found, ** attempt to allocate a new one. */ if( !pPage ){ pPage = pcache1AllocPage(pCache, createFlag==1); } if( pPage ){ unsigned int h = iKey % pCache->nHash; pCache->nPage++; pPage->iKey = iKey; pPage->pNext = pCache->apHash[h]; pPage->pCache = pCache; pPage->pLruNext = 0; /* pPage->pLruPrev = 0; ** No need to clear pLruPrev since it is not accessed when pLruNext==0 */ *(void **)pPage->page.pExtra = 0; pCache->apHash[h] = pPage; if( iKey>pCache->iMaxKey ){ pCache->iMaxKey = iKey; } } return pPage; } /* ** Implementation of the sqlite3_pcache.xFetch method. ** ** Fetch a page by key value. ** ** Whether or not a new page may be allocated by this function depends on ** the value of the createFlag argument. 0 means do not allocate a new ** page. 1 means allocate a new page if space is easily available. 2 ** means to try really hard to allocate a new page. ** ** For a non-purgeable cache (a cache used as the storage for an in-memory ** database) there is really no difference between createFlag 1 and 2. So ** the calling function (pcache.c) will never have a createFlag of 1 on ** a non-purgeable cache. ** ** There are three different approaches to obtaining space for a page, ** depending on the value of parameter createFlag (which may be 0, 1 or 2). ** ** 1. Regardless of the value of createFlag, the cache is searched for a ** copy of the requested page. If one is found, it is returned. ** ** 2. If createFlag==0 and the page is not already in the cache, NULL is ** returned. ** ** 3. If createFlag is 1, and the page is not already in the cache, then ** return NULL (do not allocate a new page) if any of the following ** conditions are true: ** ** (a) the number of pages pinned by the cache is greater than ** PCache1.nMax, or ** ** (b) the number of pages pinned by the cache is greater than ** the sum of nMax for all purgeable caches, less the sum of ** nMin for all other purgeable caches, or ** ** 4. If none of the first three conditions apply and the cache is marked ** as purgeable, and if one of the following is true: ** ** (a) The number of pages allocated for the cache is already ** PCache1.nMax, or ** ** (b) The number of pages allocated for all purgeable caches is ** already equal to or greater than the sum of nMax for all ** purgeable caches, ** ** (c) The system is under memory pressure and wants to avoid ** unnecessary pages cache entry allocations ** ** then attempt to recycle a page from the LRU list. If it is the right ** size, return the recycled buffer. Otherwise, free the buffer and ** proceed to step 5. ** ** 5. Otherwise, allocate and return a new page buffer. ** ** There are two versions of this routine. pcache1FetchWithMutex() is ** the general case. pcache1FetchNoMutex() is a faster implementation for ** the common case where pGroup->mutex is NULL. The pcache1Fetch() wrapper ** invokes the appropriate routine. */ static PgHdr1 *pcache1FetchNoMutex( sqlite3_pcache *p, unsigned int iKey, int createFlag ){ PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = 0; /* Step 1: Search the hash table for an existing entry. */ pPage = pCache->apHash[iKey % pCache->nHash]; while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; } /* Step 2: If the page was found in the hash table, then return it. ** If the page was not in the hash table and createFlag is 0, abort. ** Otherwise (page not in hash and createFlag!=0) continue with ** subsequent steps to try to create the page. */ if( pPage ){ if( PAGE_IS_UNPINNED(pPage) ){ return pcache1PinPage(pPage); }else{ return pPage; } }else if( createFlag ){ /* Steps 3, 4, and 5 implemented by this subroutine */ return pcache1FetchStage2(pCache, iKey, createFlag); }else{ return 0; } } #if PCACHE1_MIGHT_USE_GROUP_MUTEX static PgHdr1 *pcache1FetchWithMutex( sqlite3_pcache *p, unsigned int iKey, int createFlag ){ PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage; pcache1EnterMutex(pCache->pGroup); pPage = pcache1FetchNoMutex(p, iKey, createFlag); assert( pPage==0 || pCache->iMaxKey>=iKey ); pcache1LeaveMutex(pCache->pGroup); return pPage; } #endif static sqlite3_pcache_page *pcache1Fetch( sqlite3_pcache *p, unsigned int iKey, int createFlag ){ #if PCACHE1_MIGHT_USE_GROUP_MUTEX || defined(SQLITE_DEBUG) PCache1 *pCache = (PCache1 *)p; #endif assert( offsetof(PgHdr1,page)==0 ); assert( pCache->bPurgeable || createFlag!=1 ); assert( pCache->bPurgeable || pCache->nMin==0 ); assert( pCache->bPurgeable==0 || pCache->nMin==10 ); assert( pCache->nMin==0 || pCache->bPurgeable ); assert( pCache->nHash>0 ); #if PCACHE1_MIGHT_USE_GROUP_MUTEX if( pCache->pGroup->mutex ){ return (sqlite3_pcache_page*)pcache1FetchWithMutex(p, iKey, createFlag); }else #endif { return (sqlite3_pcache_page*)pcache1FetchNoMutex(p, iKey, createFlag); } } /* ** Implementation of the sqlite3_pcache.xUnpin method. ** ** Mark a page as unpinned (eligible for asynchronous recycling). */ static void pcache1Unpin( sqlite3_pcache *p, sqlite3_pcache_page *pPg, int reuseUnlikely ){ PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = (PgHdr1 *)pPg; PGroup *pGroup = pCache->pGroup; assert( pPage->pCache==pCache ); pcache1EnterMutex(pGroup); /* It is an error to call this function if the page is already ** part of the PGroup LRU list. */ assert( pPage->pLruNext==0 ); assert( PAGE_IS_PINNED(pPage) ); if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){ pcache1RemoveFromHash(pPage, 1); }else{ /* Add the page to the PGroup LRU list. */ PgHdr1 **ppFirst = &pGroup->lru.pLruNext; pPage->pLruPrev = &pGroup->lru; (pPage->pLruNext = *ppFirst)->pLruPrev = pPage; *ppFirst = pPage; pCache->nRecyclable++; } pcache1LeaveMutex(pCache->pGroup); } /* ** Implementation of the sqlite3_pcache.xRekey method. */ static void pcache1Rekey( sqlite3_pcache *p, sqlite3_pcache_page *pPg, unsigned int iOld, unsigned int iNew ){ PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = (PgHdr1 *)pPg; PgHdr1 **pp; unsigned int hOld, hNew; assert( pPage->iKey==iOld ); assert( pPage->pCache==pCache ); assert( iOld!=iNew ); /* The page number really is changing */ pcache1EnterMutex(pCache->pGroup); assert( pcache1FetchNoMutex(p, iOld, 0)==pPage ); /* pPg really is iOld */ hOld = iOld%pCache->nHash; pp = &pCache->apHash[hOld]; while( (*pp)!=pPage ){ pp = &(*pp)->pNext; } *pp = pPage->pNext; assert( pcache1FetchNoMutex(p, iNew, 0)==0 ); /* iNew not in cache */ hNew = iNew%pCache->nHash; pPage->iKey = iNew; pPage->pNext = pCache->apHash[hNew]; pCache->apHash[hNew] = pPage; if( iNew>pCache->iMaxKey ){ pCache->iMaxKey = iNew; } pcache1LeaveMutex(pCache->pGroup); } /* ** Implementation of the sqlite3_pcache.xTruncate method. ** ** Discard all unpinned pages in the cache with a page number equal to ** or greater than parameter iLimit. Any pinned pages with a page number ** equal to or greater than iLimit are implicitly unpinned. */ static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){ PCache1 *pCache = (PCache1 *)p; pcache1EnterMutex(pCache->pGroup); if( iLimit<=pCache->iMaxKey ){ pcache1TruncateUnsafe(pCache, iLimit); pCache->iMaxKey = iLimit-1; } pcache1LeaveMutex(pCache->pGroup); } /* ** Implementation of the sqlite3_pcache.xDestroy method. ** ** Destroy a cache allocated using pcache1Create(). */ static void pcache1Destroy(sqlite3_pcache *p){ PCache1 *pCache = (PCache1 *)p; PGroup *pGroup = pCache->pGroup; assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) ); pcache1EnterMutex(pGroup); if( pCache->nPage ) pcache1TruncateUnsafe(pCache, 0); assert( pGroup->nMaxPage >= pCache->nMax ); pGroup->nMaxPage -= pCache->nMax; assert( pGroup->nMinPage >= pCache->nMin ); pGroup->nMinPage -= pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; pcache1EnforceMaxPage(pCache); pcache1LeaveMutex(pGroup); sqlite3_free(pCache->pBulk); sqlite3_free(pCache->apHash); sqlite3_free(pCache); } /* ** This function is called during initialization (sqlite3_initialize()) to ** install the default pluggable cache module, assuming the user has not ** already provided an alternative. */ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){ static const sqlite3_pcache_methods2 defaultMethods = { 1, /* iVersion */ 0, /* pArg */ pcache1Init, /* xInit */ pcache1Shutdown, /* xShutdown */ pcache1Create, /* xCreate */ pcache1Cachesize, /* xCachesize */ pcache1Pagecount, /* xPagecount */ pcache1Fetch, /* xFetch */ pcache1Unpin, /* xUnpin */ pcache1Rekey, /* xRekey */ pcache1Truncate, /* xTruncate */ pcache1Destroy, /* xDestroy */ pcache1Shrink /* xShrink */ }; sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods); } /* ** Return the size of the header on each page of this PCACHE implementation. */ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); } /* ** Return the global mutex used by this PCACHE implementation. The ** sqlite3_status() routine needs access to this mutex. */ SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void){ return pcache1.mutex; } #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* ** This function is called to free superfluous dynamically allocated memory ** held by the pager system. Memory in use by any SQLite pager allocated ** by the current thread may be sqlite3_free()ed. ** ** nReq is the number of bytes of memory required. Once this much has ** been released, the function returns. The return value is the total number ** of bytes of memory released. */ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){ int nFree = 0; assert( sqlite3_mutex_notheld(pcache1.grp.mutex) ); assert( sqlite3_mutex_notheld(pcache1.mutex) ); if( sqlite3GlobalConfig.pPage==0 ){ PgHdr1 *p; pcache1EnterMutex(&pcache1.grp); while( (nReq<0 || nFreeisAnchor==0 ){ nFree += pcache1MemSize(p->page.pBuf); assert( PAGE_IS_UNPINNED(p) ); pcache1PinPage(p); pcache1RemoveFromHash(p, 1); } pcache1LeaveMutex(&pcache1.grp); } return nFree; } #endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ #ifdef SQLITE_TEST /* ** This function is used by test procedures to inspect the internal state ** of the global cache. */ SQLITE_PRIVATE void sqlite3PcacheStats( int *pnCurrent, /* OUT: Total number of pages cached */ int *pnMax, /* OUT: Global maximum cache size */ int *pnMin, /* OUT: Sum of PCache1.nMin for purgeable caches */ int *pnRecyclable /* OUT: Total number of pages available for recycling */ ){ PgHdr1 *p; int nRecyclable = 0; for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){ assert( PAGE_IS_UNPINNED(p) ); nRecyclable++; } *pnCurrent = pcache1.grp.nPurgeable; *pnMax = (int)pcache1.grp.nMaxPage; *pnMin = (int)pcache1.grp.nMinPage; *pnRecyclable = nRecyclable; } #endif /************** End of pcache1.c *********************************************/ /************** Begin file rowset.c ******************************************/ /* ** 2008 December 3 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This module implements an object we call a "RowSet". ** ** The RowSet object is a collection of rowids. Rowids ** are inserted into the RowSet in an arbitrary order. Inserts ** can be intermixed with tests to see if a given rowid has been ** previously inserted into the RowSet. ** ** After all inserts are finished, it is possible to extract the ** elements of the RowSet in sorted order. Once this extraction ** process has started, no new elements may be inserted. ** ** Hence, the primitive operations for a RowSet are: ** ** CREATE ** INSERT ** TEST ** SMALLEST ** DESTROY ** ** The CREATE and DESTROY primitives are the constructor and destructor, ** obviously. The INSERT primitive adds a new element to the RowSet. ** TEST checks to see if an element is already in the RowSet. SMALLEST ** extracts the least value from the RowSet. ** ** The INSERT primitive might allocate additional memory. Memory is ** allocated in chunks so most INSERTs do no allocation. There is an ** upper bound on the size of allocated memory. No memory is freed ** until DESTROY. ** ** The TEST primitive includes a "batch" number. The TEST primitive ** will only see elements that were inserted before the last change ** in the batch number. In other words, if an INSERT occurs between ** two TESTs where the TESTs have the same batch number, then the ** value added by the INSERT will not be visible to the second TEST. ** The initial batch number is zero, so if the very first TEST contains ** a non-zero batch number, it will see all prior INSERTs. ** ** No INSERTs may occurs after a SMALLEST. An assertion will fail if ** that is attempted. ** ** The cost of an INSERT is roughly constant. (Sometimes new memory ** has to be allocated on an INSERT.) The cost of a TEST with a new ** batch number is O(NlogN) where N is the number of elements in the RowSet. ** The cost of a TEST using the same batch number is O(logN). The cost ** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST ** primitives are constant time. The cost of DESTROY is O(N). ** ** TEST and SMALLEST may not be used by the same RowSet. This used to ** be possible, but the feature was not used, so it was removed in order ** to simplify the code. */ /* #include "sqliteInt.h" */ /* ** Target size for allocation chunks. */ #define ROWSET_ALLOCATION_SIZE 1024 /* ** The number of rowset entries per allocation chunk. */ #define ROWSET_ENTRY_PER_CHUNK \ ((ROWSET_ALLOCATION_SIZE-8)/sizeof(struct RowSetEntry)) /* ** Each entry in a RowSet is an instance of the following object. ** ** This same object is reused to store a linked list of trees of RowSetEntry ** objects. In that alternative use, pRight points to the next entry ** in the list, pLeft points to the tree, and v is unused. The ** RowSet.pForest value points to the head of this forest list. */ struct RowSetEntry { i64 v; /* ROWID value for this entry */ struct RowSetEntry *pRight; /* Right subtree (larger entries) or list */ struct RowSetEntry *pLeft; /* Left subtree (smaller entries) */ }; /* ** RowSetEntry objects are allocated in large chunks (instances of the ** following structure) to reduce memory allocation overhead. The ** chunks are kept on a linked list so that they can be deallocated ** when the RowSet is destroyed. */ struct RowSetChunk { struct RowSetChunk *pNextChunk; /* Next chunk on list of them all */ struct RowSetEntry aEntry[ROWSET_ENTRY_PER_CHUNK]; /* Allocated entries */ }; /* ** A RowSet in an instance of the following structure. ** ** A typedef of this structure if found in sqliteInt.h. */ struct RowSet { struct RowSetChunk *pChunk; /* List of all chunk allocations */ sqlite3 *db; /* The database connection */ struct RowSetEntry *pEntry; /* List of entries using pRight */ struct RowSetEntry *pLast; /* Last entry on the pEntry list */ struct RowSetEntry *pFresh; /* Source of new entry objects */ struct RowSetEntry *pForest; /* List of binary trees of entries */ u16 nFresh; /* Number of objects on pFresh */ u16 rsFlags; /* Various flags */ int iBatch; /* Current insert batch */ }; /* ** Allowed values for RowSet.rsFlags */ #define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */ #define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */ /* ** Allocate a RowSet object. Return NULL if a memory allocation ** error occurs. */ SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db){ RowSet *p = sqlite3DbMallocRawNN(db, sizeof(*p)); if( p ){ int N = sqlite3DbMallocSize(db, p); p->pChunk = 0; p->db = db; p->pEntry = 0; p->pLast = 0; p->pForest = 0; p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); p->rsFlags = ROWSET_SORTED; p->iBatch = 0; } return p; } /* ** Deallocate all chunks from a RowSet. This frees all memory that ** the RowSet has allocated over its lifetime. This routine is ** the destructor for the RowSet. */ SQLITE_PRIVATE void sqlite3RowSetClear(void *pArg){ RowSet *p = (RowSet*)pArg; struct RowSetChunk *pChunk, *pNextChunk; for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){ pNextChunk = pChunk->pNextChunk; sqlite3DbFree(p->db, pChunk); } p->pChunk = 0; p->nFresh = 0; p->pEntry = 0; p->pLast = 0; p->pForest = 0; p->rsFlags = ROWSET_SORTED; } /* ** Deallocate all chunks from a RowSet. This frees all memory that ** the RowSet has allocated over its lifetime. This routine is ** the destructor for the RowSet. */ SQLITE_PRIVATE void sqlite3RowSetDelete(void *pArg){ sqlite3RowSetClear(pArg); sqlite3DbFree(((RowSet*)pArg)->db, pArg); } /* ** Allocate a new RowSetEntry object that is associated with the ** given RowSet. Return a pointer to the new and completely uninitialized ** object. ** ** In an OOM situation, the RowSet.db->mallocFailed flag is set and this ** routine returns NULL. */ static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){ assert( p!=0 ); if( p->nFresh==0 ){ /*OPTIMIZATION-IF-FALSE*/ /* We could allocate a fresh RowSetEntry each time one is needed, but it ** is more efficient to pull a preallocated entry from the pool */ struct RowSetChunk *pNew; pNew = sqlite3DbMallocRawNN(p->db, sizeof(*pNew)); if( pNew==0 ){ return 0; } pNew->pNextChunk = p->pChunk; p->pChunk = pNew; p->pFresh = pNew->aEntry; p->nFresh = ROWSET_ENTRY_PER_CHUNK; } p->nFresh--; return p->pFresh++; } /* ** Insert a new value into a RowSet. ** ** The mallocFailed flag of the database connection is set if a ** memory allocation fails. */ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){ struct RowSetEntry *pEntry; /* The new entry */ struct RowSetEntry *pLast; /* The last prior entry */ /* This routine is never called after sqlite3RowSetNext() */ assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 ); pEntry = rowSetEntryAlloc(p); if( pEntry==0 ) return; pEntry->v = rowid; pEntry->pRight = 0; pLast = p->pLast; if( pLast ){ if( rowid<=pLast->v ){ /*OPTIMIZATION-IF-FALSE*/ /* Avoid unnecessary sorts by preserving the ROWSET_SORTED flags ** where possible */ p->rsFlags &= ~ROWSET_SORTED; } pLast->pRight = pEntry; }else{ p->pEntry = pEntry; } p->pLast = pEntry; } /* ** Merge two lists of RowSetEntry objects. Remove duplicates. ** ** The input lists are connected via pRight pointers and are ** assumed to each already be in sorted order. */ static struct RowSetEntry *rowSetEntryMerge( struct RowSetEntry *pA, /* First sorted list to be merged */ struct RowSetEntry *pB /* Second sorted list to be merged */ ){ struct RowSetEntry head; struct RowSetEntry *pTail; pTail = &head; assert( pA!=0 && pB!=0 ); for(;;){ assert( pA->pRight==0 || pA->v<=pA->pRight->v ); assert( pB->pRight==0 || pB->v<=pB->pRight->v ); if( pA->v<=pB->v ){ if( pA->vv ) pTail = pTail->pRight = pA; pA = pA->pRight; if( pA==0 ){ pTail->pRight = pB; break; } }else{ pTail = pTail->pRight = pB; pB = pB->pRight; if( pB==0 ){ pTail->pRight = pA; break; } } } return head.pRight; } /* ** Sort all elements on the list of RowSetEntry objects into order of ** increasing v. */ static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){ unsigned int i; struct RowSetEntry *pNext, *aBucket[40]; memset(aBucket, 0, sizeof(aBucket)); while( pIn ){ pNext = pIn->pRight; pIn->pRight = 0; for(i=0; aBucket[i]; i++){ pIn = rowSetEntryMerge(aBucket[i], pIn); aBucket[i] = 0; } aBucket[i] = pIn; pIn = pNext; } pIn = aBucket[0]; for(i=1; ipLeft ){ struct RowSetEntry *p; rowSetTreeToList(pIn->pLeft, ppFirst, &p); p->pRight = pIn; }else{ *ppFirst = pIn; } if( pIn->pRight ){ rowSetTreeToList(pIn->pRight, &pIn->pRight, ppLast); }else{ *ppLast = pIn; } assert( (*ppLast)->pRight==0 ); } /* ** Convert a sorted list of elements (connected by pRight) into a binary ** tree with depth of iDepth. A depth of 1 means the tree contains a single ** node taken from the head of *ppList. A depth of 2 means a tree with ** three nodes. And so forth. ** ** Use as many entries from the input list as required and update the ** *ppList to point to the unused elements of the list. If the input ** list contains too few elements, then construct an incomplete tree ** and leave *ppList set to NULL. ** ** Return a pointer to the root of the constructed binary tree. */ static struct RowSetEntry *rowSetNDeepTree( struct RowSetEntry **ppList, int iDepth ){ struct RowSetEntry *p; /* Root of the new tree */ struct RowSetEntry *pLeft; /* Left subtree */ if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/ /* Prevent unnecessary deep recursion when we run out of entries */ return 0; } if( iDepth>1 ){ /*OPTIMIZATION-IF-TRUE*/ /* This branch causes a *balanced* tree to be generated. A valid tree ** is still generated without this branch, but the tree is wildly ** unbalanced and inefficient. */ pLeft = rowSetNDeepTree(ppList, iDepth-1); p = *ppList; if( p==0 ){ /*OPTIMIZATION-IF-FALSE*/ /* It is safe to always return here, but the resulting tree ** would be unbalanced */ return pLeft; } p->pLeft = pLeft; *ppList = p->pRight; p->pRight = rowSetNDeepTree(ppList, iDepth-1); }else{ p = *ppList; *ppList = p->pRight; p->pLeft = p->pRight = 0; } return p; } /* ** Convert a sorted list of elements into a binary tree. Make the tree ** as deep as it needs to be in order to contain the entire list. */ static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){ int iDepth; /* Depth of the tree so far */ struct RowSetEntry *p; /* Current tree root */ struct RowSetEntry *pLeft; /* Left subtree */ assert( pList!=0 ); p = pList; pList = p->pRight; p->pLeft = p->pRight = 0; for(iDepth=1; pList; iDepth++){ pLeft = p; p = pList; pList = p->pRight; p->pLeft = pLeft; p->pRight = rowSetNDeepTree(&pList, iDepth); } return p; } /* ** Extract the smallest element from the RowSet. ** Write the element into *pRowid. Return 1 on success. Return ** 0 if the RowSet is already empty. ** ** After this routine has been called, the sqlite3RowSetInsert() ** routine may not be called again. ** ** This routine may not be called after sqlite3RowSetTest() has ** been used. Older versions of RowSet allowed that, but as the ** capability was not used by the code generator, it was removed ** for code economy. */ SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ assert( p!=0 ); assert( p->pForest==0 ); /* Cannot be used with sqlite3RowSetText() */ /* Merge the forest into a single sorted list on first call */ if( (p->rsFlags & ROWSET_NEXT)==0 ){ /*OPTIMIZATION-IF-FALSE*/ if( (p->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/ p->pEntry = rowSetEntrySort(p->pEntry); } p->rsFlags |= ROWSET_SORTED|ROWSET_NEXT; } /* Return the next entry on the list */ if( p->pEntry ){ *pRowid = p->pEntry->v; p->pEntry = p->pEntry->pRight; if( p->pEntry==0 ){ /*OPTIMIZATION-IF-TRUE*/ /* Free memory immediately, rather than waiting on sqlite3_finalize() */ sqlite3RowSetClear(p); } return 1; }else{ return 0; } } /* ** Check to see if element iRowid was inserted into the rowset as ** part of any insert batch prior to iBatch. Return 1 or 0. ** ** If this is the first test of a new batch and if there exist entries ** on pRowSet->pEntry, then sort those entries into the forest at ** pRowSet->pForest so that they can be tested. */ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){ struct RowSetEntry *p, *pTree; /* This routine is never called after sqlite3RowSetNext() */ assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 ); /* Sort entries into the forest on the first test of a new batch. ** To save unnecessary work, only do this when the batch number changes. */ if( iBatch!=pRowSet->iBatch ){ /*OPTIMIZATION-IF-FALSE*/ p = pRowSet->pEntry; if( p ){ struct RowSetEntry **ppPrevTree = &pRowSet->pForest; if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/ /* Only sort the current set of entries if they need it */ p = rowSetEntrySort(p); } for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ ppPrevTree = &pTree->pRight; if( pTree->pLeft==0 ){ pTree->pLeft = rowSetListToTree(p); break; }else{ struct RowSetEntry *pAux, *pTail; rowSetTreeToList(pTree->pLeft, &pAux, &pTail); pTree->pLeft = 0; p = rowSetEntryMerge(pAux, p); } } if( pTree==0 ){ *ppPrevTree = pTree = rowSetEntryAlloc(pRowSet); if( pTree ){ pTree->v = 0; pTree->pRight = 0; pTree->pLeft = rowSetListToTree(p); } } pRowSet->pEntry = 0; pRowSet->pLast = 0; pRowSet->rsFlags |= ROWSET_SORTED; } pRowSet->iBatch = iBatch; } /* Test to see if the iRowid value appears anywhere in the forest. ** Return 1 if it does and 0 if not. */ for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ p = pTree->pLeft; while( p ){ if( p->vpRight; }else if( p->v>iRowid ){ p = p->pLeft; }else{ return 1; } } } return 0; } /************** End of rowset.c **********************************************/ /************** Begin file pager.c *******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the implementation of the page cache subsystem or "pager". ** ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. */ #ifndef SQLITE_OMIT_DISKIO /* #include "sqliteInt.h" */ /************** Include wal.h in the middle of pager.c ***********************/ /************** Begin file wal.h *********************************************/ /* ** 2010 February 1 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface to the write-ahead logging ** system. Refer to the comments below and the header comment attached to ** the implementation of each function in log.c for further details. */ #ifndef SQLITE_WAL_H #define SQLITE_WAL_H /* #include "sqliteInt.h" */ /* Macros for extracting appropriate sync flags for either transaction ** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)): */ #define WAL_SYNC_FLAGS(X) ((X)&0x03) #define CKPT_SYNC_FLAGS(X) (((X)>>2)&0x03) #ifdef SQLITE_OMIT_WAL # define sqlite3WalOpen(x,y,z) 0 # define sqlite3WalLimit(x,y) # define sqlite3WalClose(v,w,x,y,z) 0 # define sqlite3WalBeginReadTransaction(y,z) 0 # define sqlite3WalEndReadTransaction(z) # define sqlite3WalDbsize(y) 0 # define sqlite3WalBeginWriteTransaction(y) 0 # define sqlite3WalEndWriteTransaction(x) 0 # define sqlite3WalUndo(x,y,z) 0 # define sqlite3WalSavepoint(y,z) # define sqlite3WalSavepointUndo(y,z) 0 # define sqlite3WalFrames(u,v,w,x,y,z) 0 # define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0 # define sqlite3WalCallback(z) 0 # define sqlite3WalExclusiveMode(y,z) 0 # define sqlite3WalHeapMemory(z) 0 # define sqlite3WalFramesize(z) 0 # define sqlite3WalFindFrame(x,y,z) 0 # define sqlite3WalFile(x) 0 # undef SQLITE_USE_SEH #else #define WAL_SAVEPOINT_NDATA 4 /* Connection to a write-ahead log (WAL) file. ** There is one object of this type for each pager. */ typedef struct Wal Wal; /* Open and close a connection to a write-ahead log. */ SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**); SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *); /* Set the limiting size of a WAL file. */ SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64); /* Used by readers to open (lock) and close (unlock) a snapshot. A ** snapshot is like a read-transaction. It is the state of the database ** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and ** preserves the current state even if the other threads or processes ** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the ** transaction and releases the lock. */ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *); SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal); /* Read a page from the write-ahead log, if it is present. */ SQLITE_PRIVATE int sqlite3WalFindFrame(Wal *, Pgno, u32 *); SQLITE_PRIVATE int sqlite3WalReadFrame(Wal *, u32, int, u8 *); /* If the WAL is not empty, return the size of the database. */ SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal); /* Obtain or release the WRITER lock. */ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal); SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal); /* Undo any frames written (but not committed) to the log */ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx); /* Return an integer that records the current (uncommitted) write ** position in the WAL */ SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData); /* Move the write position of the WAL back to iFrame. Called in ** response to a ROLLBACK TO command. */ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData); /* Write a frame or frames to the log. */ SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int); /* Copy pages from the log to the database file */ SQLITE_PRIVATE int sqlite3WalCheckpoint( Wal *pWal, /* Write-ahead log connection */ sqlite3 *db, /* Check this handle's interrupt flag */ int eMode, /* One of PASSIVE, FULL and RESTART */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int sync_flags, /* Flags to sync db file with (or 0) */ int nBuf, /* Size of buffer nBuf */ u8 *zBuf, /* Temporary buffer to use */ int *pnLog, /* OUT: Number of frames in WAL */ int *pnCkpt /* OUT: Number of backfilled frames in WAL */ ); /* Return the value to pass to a sqlite3_wal_hook callback, the ** number of frames in the WAL at the point of the last commit since ** sqlite3WalCallback() was called. If no commits have occurred since ** the last call, then return 0. */ SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal); /* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released) ** by the pager layer on the database file. */ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op); /* Return true if the argument is non-NULL and the WAL module is using ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the ** WAL module is using shared-memory, return false. */ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal); #ifdef SQLITE_ENABLE_SNAPSHOT SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot); SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot); SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal); SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot); SQLITE_PRIVATE void sqlite3WalSnapshotUnlock(Wal *pWal); #endif #ifdef SQLITE_ENABLE_ZIPVFS /* If the WAL file is not empty, return the number of bytes of content ** stored in each frame (i.e. the db page-size when the WAL was created). */ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal); #endif /* Return the sqlite3_file object for the WAL file */ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock); SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db); #endif #ifdef SQLITE_USE_SEH SQLITE_PRIVATE int sqlite3WalSystemErrno(Wal*); #endif #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ /************** End of wal.h *************************************************/ /************** Continuing where we left off in pager.c **********************/ /******************* NOTES ON THE DESIGN OF THE PAGER ************************ ** ** This comment block describes invariants that hold when using a rollback ** journal. These invariants do not apply for journal_mode=WAL, ** journal_mode=MEMORY, or journal_mode=OFF. ** ** Within this comment block, a page is deemed to have been synced ** automatically as soon as it is written when PRAGMA synchronous=OFF. ** Otherwise, the page is not synced until the xSync method of the VFS ** is called successfully on the file containing the page. ** ** Definition: A page of the database file is said to be "overwriteable" if ** one or more of the following are true about the page: ** ** (a) The original content of the page as it was at the beginning of ** the transaction has been written into the rollback journal and ** synced. ** ** (b) The page was a freelist leaf page at the start of the transaction. ** ** (c) The page number is greater than the largest page that existed in ** the database file at the start of the transaction. ** ** (1) A page of the database file is never overwritten unless one of the ** following are true: ** ** (a) The page and all other pages on the same sector are overwriteable. ** ** (b) The atomic page write optimization is enabled, and the entire ** transaction other than the update of the transaction sequence ** number consists of a single page change. ** ** (2) The content of a page written into the rollback journal exactly matches ** both the content in the database when the rollback journal was written ** and the content in the database at the beginning of the current ** transaction. ** ** (3) Writes to the database file are an integer multiple of the page size ** in length and are aligned on a page boundary. ** ** (4) Reads from the database file are either aligned on a page boundary and ** an integer multiple of the page size in length or are taken from the ** first 100 bytes of the database file. ** ** (5) All writes to the database file are synced prior to the rollback journal ** being deleted, truncated, or zeroed. ** ** (6) If a super-journal file is used, then all writes to the database file ** are synced prior to the super-journal being deleted. ** ** Definition: Two databases (or the same database at two points it time) ** are said to be "logically equivalent" if they give the same answer to ** all queries. Note in particular the content of freelist leaf ** pages can be changed arbitrarily without affecting the logical equivalence ** of the database. ** ** (7) At any time, if any subset, including the empty set and the total set, ** of the unsynced changes to a rollback journal are removed and the ** journal is rolled back, the resulting database file will be logically ** equivalent to the database file at the beginning of the transaction. ** ** (8) When a transaction is rolled back, the xTruncate method of the VFS ** is called to restore the database file to the same size it was at ** the beginning of the transaction. (In some VFSes, the xTruncate ** method is a no-op, but that does not change the fact the SQLite will ** invoke it.) ** ** (9) Whenever the database file is modified, at least one bit in the range ** of bytes from 24 through 39 inclusive will be changed prior to releasing ** the EXCLUSIVE lock, thus signaling other connections on the same ** database to flush their caches. ** ** (10) The pattern of bits in bytes 24 through 39 shall not repeat in less ** than one billion transactions. ** ** (11) A database file is well-formed at the beginning and at the conclusion ** of every transaction. ** ** (12) An EXCLUSIVE lock is held on the database file when writing to ** the database file. ** ** (13) A SHARED lock is held on the database file while reading any ** content out of the database file. ** ******************************************************************************/ /* ** Macros for troubleshooting. Normally turned off */ #if 0 int sqlite3PagerTrace=1; /* True to enable tracing */ #define sqlite3DebugPrintf printf #define PAGERTRACE(X) if( sqlite3PagerTrace ){ sqlite3DebugPrintf X; } #else #define PAGERTRACE(X) #endif /* ** The following two macros are used within the PAGERTRACE() macros above ** to print out file-descriptors. ** ** PAGERID() takes a pointer to a Pager struct as its argument. The ** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file ** struct as its argument. */ #define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd)) #define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd)) /* ** The Pager.eState variable stores the current 'state' of a pager. A ** pager may be in any one of the seven states shown in the following ** state diagram. ** ** OPEN <------+------+ ** | | | ** V | | ** +---------> READER-------+ | ** | | | ** | V | ** |<-------WRITER_LOCKED------> ERROR ** | | ^ ** | V | ** |<------WRITER_CACHEMOD-------->| ** | | | ** | V | ** |<-------WRITER_DBMOD---------->| ** | | | ** | V | ** +<------WRITER_FINISHED-------->+ ** ** ** List of state transitions and the C [function] that performs each: ** ** OPEN -> READER [sqlite3PagerSharedLock] ** READER -> OPEN [pager_unlock] ** ** READER -> WRITER_LOCKED [sqlite3PagerBegin] ** WRITER_LOCKED -> WRITER_CACHEMOD [pager_open_journal] ** WRITER_CACHEMOD -> WRITER_DBMOD [syncJournal] ** WRITER_DBMOD -> WRITER_FINISHED [sqlite3PagerCommitPhaseOne] ** WRITER_*** -> READER [pager_end_transaction] ** ** WRITER_*** -> ERROR [pager_error] ** ERROR -> OPEN [pager_unlock] ** ** ** OPEN: ** ** The pager starts up in this state. Nothing is guaranteed in this ** state - the file may or may not be locked and the database size is ** unknown. The database may not be read or written. ** ** * No read or write transaction is active. ** * Any lock, or no lock at all, may be held on the database file. ** * The dbSize, dbOrigSize and dbFileSize variables may not be trusted. ** ** READER: ** ** In this state all the requirements for reading the database in ** rollback (non-WAL) mode are met. Unless the pager is (or recently ** was) in exclusive-locking mode, a user-level read transaction is ** open. The database size is known in this state. ** ** A connection running with locking_mode=normal enters this state when ** it opens a read-transaction on the database and returns to state ** OPEN after the read-transaction is completed. However a connection ** running in locking_mode=exclusive (including temp databases) remains in ** this state even after the read-transaction is closed. The only way ** a locking_mode=exclusive connection can transition from READER to OPEN ** is via the ERROR state (see below). ** ** * A read transaction may be active (but a write-transaction cannot). ** * A SHARED or greater lock is held on the database file. ** * The dbSize variable may be trusted (even if a user-level read ** transaction is not active). The dbOrigSize and dbFileSize variables ** may not be trusted at this point. ** * If the database is a WAL database, then the WAL connection is open. ** * Even if a read-transaction is not open, it is guaranteed that ** there is no hot-journal in the file-system. ** ** WRITER_LOCKED: ** ** The pager moves to this state from READER when a write-transaction ** is first opened on the database. In WRITER_LOCKED state, all locks ** required to start a write-transaction are held, but no actual ** modifications to the cache or database have taken place. ** ** In rollback mode, a RESERVED or (if the transaction was opened with ** BEGIN EXCLUSIVE) EXCLUSIVE lock is obtained on the database file when ** moving to this state, but the journal file is not written to or opened ** to in this state. If the transaction is committed or rolled back while ** in WRITER_LOCKED state, all that is required is to unlock the database ** file. ** ** IN WAL mode, WalBeginWriteTransaction() is called to lock the log file. ** If the connection is running with locking_mode=exclusive, an attempt ** is made to obtain an EXCLUSIVE lock on the database file. ** ** * A write transaction is active. ** * If the connection is open in rollback-mode, a RESERVED or greater ** lock is held on the database file. ** * If the connection is open in WAL-mode, a WAL write transaction ** is open (i.e. sqlite3WalBeginWriteTransaction() has been successfully ** called). ** * The dbSize, dbOrigSize and dbFileSize variables are all valid. ** * The contents of the pager cache have not been modified. ** * The journal file may or may not be open. ** * Nothing (not even the first header) has been written to the journal. ** ** WRITER_CACHEMOD: ** ** A pager moves from WRITER_LOCKED state to this state when a page is ** first modified by the upper layer. In rollback mode the journal file ** is opened (if it is not already open) and a header written to the ** start of it. The database file on disk has not been modified. ** ** * A write transaction is active. ** * A RESERVED or greater lock is held on the database file. ** * The journal file is open and the first header has been written ** to it, but the header has not been synced to disk. ** * The contents of the page cache have been modified. ** ** WRITER_DBMOD: ** ** The pager transitions from WRITER_CACHEMOD into WRITER_DBMOD state ** when it modifies the contents of the database file. WAL connections ** never enter this state (since they do not modify the database file, ** just the log file). ** ** * A write transaction is active. ** * An EXCLUSIVE or greater lock is held on the database file. ** * The journal file is open and the first header has been written ** and synced to disk. ** * The contents of the page cache have been modified (and possibly ** written to disk). ** ** WRITER_FINISHED: ** ** It is not possible for a WAL connection to enter this state. ** ** A rollback-mode pager changes to WRITER_FINISHED state from WRITER_DBMOD ** state after the entire transaction has been successfully written into the ** database file. In this state the transaction may be committed simply ** by finalizing the journal file. Once in WRITER_FINISHED state, it is ** not possible to modify the database further. At this point, the upper ** layer must either commit or rollback the transaction. ** ** * A write transaction is active. ** * An EXCLUSIVE or greater lock is held on the database file. ** * All writing and syncing of journal and database data has finished. ** If no error occurred, all that remains is to finalize the journal to ** commit the transaction. If an error did occur, the caller will need ** to rollback the transaction. ** ** ERROR: ** ** The ERROR state is entered when an IO or disk-full error (including ** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it ** difficult to be sure that the in-memory pager state (cache contents, ** db size etc.) are consistent with the contents of the file-system. ** ** Temporary pager files may enter the ERROR state, but in-memory pagers ** cannot. ** ** For example, if an IO error occurs while performing a rollback, ** the contents of the page-cache may be left in an inconsistent state. ** At this point it would be dangerous to change back to READER state ** (as usually happens after a rollback). Any subsequent readers might ** report database corruption (due to the inconsistent cache), and if ** they upgrade to writers, they may inadvertently corrupt the database ** file. To avoid this hazard, the pager switches into the ERROR state ** instead of READER following such an error. ** ** Once it has entered the ERROR state, any attempt to use the pager ** to read or write data returns an error. Eventually, once all ** outstanding transactions have been abandoned, the pager is able to ** transition back to OPEN state, discarding the contents of the ** page-cache and any other in-memory state at the same time. Everything ** is reloaded from disk (and, if necessary, hot-journal rollback performed) ** when a read-transaction is next opened on the pager (transitioning ** the pager into READER state). At that point the system has recovered ** from the error. ** ** Specifically, the pager jumps into the ERROR state if: ** ** 1. An error occurs while attempting a rollback. This happens in ** function sqlite3PagerRollback(). ** ** 2. An error occurs while attempting to finalize a journal file ** following a commit in function sqlite3PagerCommitPhaseTwo(). ** ** 3. An error occurs while attempting to write to the journal or ** database file in function pagerStress() in order to free up ** memory. ** ** In other cases, the error is returned to the b-tree layer. The b-tree ** layer then attempts a rollback operation. If the error condition ** persists, the pager enters the ERROR state via condition (1) above. ** ** Condition (3) is necessary because it can be triggered by a read-only ** statement executed within a transaction. In this case, if the error ** code were simply returned to the user, the b-tree layer would not ** automatically attempt a rollback, as it assumes that an error in a ** read-only statement cannot leave the pager in an internally inconsistent ** state. ** ** * The Pager.errCode variable is set to something other than SQLITE_OK. ** * There are one or more outstanding references to pages (after the ** last reference is dropped the pager should move back to OPEN state). ** * The pager is not an in-memory pager. ** ** ** Notes: ** ** * A pager is never in WRITER_DBMOD or WRITER_FINISHED state if the ** connection is open in WAL mode. A WAL connection is always in one ** of the first four states. ** ** * Normally, a connection open in exclusive mode is never in PAGER_OPEN ** state. There are two exceptions: immediately after exclusive-mode has ** been turned on (and before any read or write transactions are ** executed), and when the pager is leaving the "error state". ** ** * See also: assert_pager_state(). */ #define PAGER_OPEN 0 #define PAGER_READER 1 #define PAGER_WRITER_LOCKED 2 #define PAGER_WRITER_CACHEMOD 3 #define PAGER_WRITER_DBMOD 4 #define PAGER_WRITER_FINISHED 5 #define PAGER_ERROR 6 /* ** The Pager.eLock variable is almost always set to one of the ** following locking-states, according to the lock currently held on ** the database file: NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK. ** This variable is kept up to date as locks are taken and released by ** the pagerLockDb() and pagerUnlockDb() wrappers. ** ** If the VFS xLock() or xUnlock() returns an error other than SQLITE_BUSY ** (i.e. one of the SQLITE_IOERR subtypes), it is not clear whether or not ** the operation was successful. In these circumstances pagerLockDb() and ** pagerUnlockDb() take a conservative approach - eLock is always updated ** when unlocking the file, and only updated when locking the file if the ** VFS call is successful. This way, the Pager.eLock variable may be set ** to a less exclusive (lower) value than the lock that is actually held ** at the system level, but it is never set to a more exclusive value. ** ** This is usually safe. If an xUnlock fails or appears to fail, there may ** be a few redundant xLock() calls or a lock may be held for longer than ** required, but nothing really goes wrong. ** ** The exception is when the database file is unlocked as the pager moves ** from ERROR to OPEN state. At this point there may be a hot-journal file ** in the file-system that needs to be rolled back (as part of an OPEN->SHARED ** transition, by the same pager or any other). If the call to xUnlock() ** fails at this point and the pager is left holding an EXCLUSIVE lock, this ** can confuse the call to xCheckReservedLock() call made later as part ** of hot-journal detection. ** ** xCheckReservedLock() is defined as returning true "if there is a RESERVED ** lock held by this process or any others". So xCheckReservedLock may ** return true because the caller itself is holding an EXCLUSIVE lock (but ** doesn't know it because of a previous error in xUnlock). If this happens ** a hot-journal may be mistaken for a journal being created by an active ** transaction in another process, causing SQLite to read from the database ** without rolling it back. ** ** To work around this, if a call to xUnlock() fails when unlocking the ** database in the ERROR state, Pager.eLock is set to UNKNOWN_LOCK. It ** is only changed back to a real locking state after a successful call ** to xLock(EXCLUSIVE). Also, the code to do the OPEN->SHARED state transition ** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK ** lock. Instead, it assumes a hot-journal exists and obtains an EXCLUSIVE ** lock on the database file before attempting to roll it back. See function ** PagerSharedLock() for more detail. ** ** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in ** PAGER_OPEN state. */ #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) /* ** The maximum allowed sector size. 64KiB. If the xSectorsize() method ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. ** This could conceivably cause corruption following a power failure on ** such a system. This is currently an undocumented limit. */ #define MAX_SECTOR_SIZE 0x10000 /* ** An instance of the following structure is allocated for each active ** savepoint and statement transaction in the system. All such structures ** are stored in the Pager.aSavepoint[] array, which is allocated and ** resized using sqlite3Realloc(). ** ** When a savepoint is created, the PagerSavepoint.iHdrOffset field is ** set to 0. If a journal-header is written into the main journal while ** the savepoint is active, then iHdrOffset is set to the byte offset ** immediately following the last journal record written into the main ** journal before the journal-header. This is required during savepoint ** rollback (see pagerPlaybackSavepoint()). */ typedef struct PagerSavepoint PagerSavepoint; struct PagerSavepoint { i64 iOffset; /* Starting offset in main journal */ i64 iHdrOffset; /* See above */ Bitvec *pInSavepoint; /* Set of pages in this savepoint */ Pgno nOrig; /* Original number of pages in file */ Pgno iSubRec; /* Index of first record in sub-journal */ int bTruncateOnRelease; /* If stmt journal may be truncated on RELEASE */ #ifndef SQLITE_OMIT_WAL u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */ #endif }; /* ** Bits of the Pager.doNotSpill flag. See further description below. */ #define SPILLFLAG_OFF 0x01 /* Never spill cache. Set via pragma */ #define SPILLFLAG_ROLLBACK 0x02 /* Current rolling back, so do not spill */ #define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */ /* ** An open page cache is an instance of struct Pager. A description of ** some of the more important member variables follows: ** ** eState ** ** The current 'state' of the pager object. See the comment and state ** diagram above for a description of the pager state. ** ** eLock ** ** For a real on-disk database, the current lock held on the database file - ** NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK. ** ** For a temporary or in-memory database (neither of which require any ** locks), this variable is always set to EXCLUSIVE_LOCK. Since such ** databases always have Pager.exclusiveMode==1, this tricks the pager ** logic into thinking that it already has all the locks it will ever ** need (and no reason to release them). ** ** In some (obscure) circumstances, this variable may also be set to ** UNKNOWN_LOCK. See the comment above the #define of UNKNOWN_LOCK for ** details. ** ** changeCountDone ** ** This boolean variable is used to make sure that the change-counter ** (the 4-byte header field at byte offset 24 of the database file) is ** not updated more often than necessary. ** ** It is set to true when the change-counter field is updated, which ** can only happen if an exclusive lock is held on the database file. ** It is cleared (set to false) whenever an exclusive lock is ** relinquished on the database file. Each time a transaction is committed, ** The changeCountDone flag is inspected. If it is true, the work of ** updating the change-counter is omitted for the current transaction. ** ** This mechanism means that when running in exclusive mode, a connection ** need only update the change-counter once, for the first transaction ** committed. ** ** setSuper ** ** When PagerCommitPhaseOne() is called to commit a transaction, it may ** (or may not) specify a super-journal name to be written into the ** journal file before it is synced to disk. ** ** Whether or not a journal file contains a super-journal pointer affects ** the way in which the journal file is finalized after the transaction is ** committed or rolled back when running in "journal_mode=PERSIST" mode. ** If a journal file does not contain a super-journal pointer, it is ** finalized by overwriting the first journal header with zeroes. If ** it does contain a super-journal pointer the journal file is finalized ** by truncating it to zero bytes, just as if the connection were ** running in "journal_mode=truncate" mode. ** ** Journal files that contain super-journal pointers cannot be finalized ** simply by overwriting the first journal-header with zeroes, as the ** super-journal pointer could interfere with hot-journal rollback of any ** subsequently interrupted transaction that reuses the journal file. ** ** The flag is cleared as soon as the journal file is finalized (either ** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the ** journal file from being successfully finalized, the setSuper flag ** is cleared anyway (and the pager will move to ERROR state). ** ** doNotSpill ** ** This variables control the behavior of cache-spills (calls made by ** the pcache module to the pagerStress() routine to write cached data ** to the file-system in order to free up memory). ** ** When bits SPILLFLAG_OFF or SPILLFLAG_ROLLBACK of doNotSpill are set, ** writing to the database from pagerStress() is disabled altogether. ** The SPILLFLAG_ROLLBACK case is done in a very obscure case that ** comes up during savepoint rollback that requires the pcache module ** to allocate a new page to prevent the journal file from being written ** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF ** case is a user preference. ** ** If the SPILLFLAG_NOSYNC bit is set, writing to the database from ** pagerStress() is permitted, but syncing the journal file is not. ** This flag is set by sqlite3PagerWrite() when the file-system sector-size ** is larger than the database page-size in order to prevent a journal sync ** from happening in between the journalling of two pages on the same sector. ** ** subjInMemory ** ** This is a boolean variable. If true, then any required sub-journal ** is opened as an in-memory journal file. If false, then in-memory ** sub-journals are only used for in-memory pager files. ** ** This variable is updated by the upper layer each time a new ** write-transaction is opened. ** ** dbSize, dbOrigSize, dbFileSize ** ** Variable dbSize is set to the number of pages in the database file. ** It is valid in PAGER_READER and higher states (all states except for ** OPEN and ERROR). ** ** dbSize is set based on the size of the database file, which may be ** larger than the size of the database (the value stored at offset ** 28 of the database header by the btree). If the size of the file ** is not an integer multiple of the page-size, the value stored in ** dbSize is rounded down (i.e. a 5KB file with 2K page-size has dbSize==2). ** Except, any file that is greater than 0 bytes in size is considered ** to have at least one page. (i.e. a 1KB file with 2K page-size leads ** to dbSize==1). ** ** During a write-transaction, if pages with page-numbers greater than ** dbSize are modified in the cache, dbSize is updated accordingly. ** Similarly, if the database is truncated using PagerTruncateImage(), ** dbSize is updated. ** ** Variables dbOrigSize and dbFileSize are valid in states ** PAGER_WRITER_LOCKED and higher. dbOrigSize is a copy of the dbSize ** variable at the start of the transaction. It is used during rollback, ** and to determine whether or not pages need to be journalled before ** being modified. ** ** Throughout a write-transaction, dbFileSize contains the size of ** the file on disk in pages. It is set to a copy of dbSize when the ** write-transaction is first opened, and updated when VFS calls are made ** to write or truncate the database file on disk. ** ** The only reason the dbFileSize variable is required is to suppress ** unnecessary calls to xTruncate() after committing a transaction. If, ** when a transaction is committed, the dbFileSize variable indicates ** that the database file is larger than the database image (Pager.dbSize), ** pager_truncate() is called. The pager_truncate() call uses xFilesize() ** to measure the database file on disk, and then truncates it if required. ** dbFileSize is not used when rolling back a transaction. In this case ** pager_truncate() is called unconditionally (which means there may be ** a call to xFilesize() that is not strictly required). In either case, ** pager_truncate() may cause the file to become smaller or larger. ** ** dbHintSize ** ** The dbHintSize variable is used to limit the number of calls made to ** the VFS xFileControl(FCNTL_SIZE_HINT) method. ** ** dbHintSize is set to a copy of the dbSize variable when a ** write-transaction is opened (at the same time as dbFileSize and ** dbOrigSize). If the xFileControl(FCNTL_SIZE_HINT) method is called, ** dbHintSize is increased to the number of pages that correspond to the ** size-hint passed to the method call. See pager_write_pagelist() for ** details. ** ** errCode ** ** The Pager.errCode variable is only ever used in PAGER_ERROR state. It ** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode ** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX ** sub-codes. ** ** syncFlags, walSyncFlags ** ** syncFlags is either SQLITE_SYNC_NORMAL (0x02) or SQLITE_SYNC_FULL (0x03). ** syncFlags is used for rollback mode. walSyncFlags is used for WAL mode ** and contains the flags used to sync the checkpoint operations in the ** lower two bits, and sync flags used for transaction commits in the WAL ** file in bits 0x04 and 0x08. In other words, to get the correct sync flags ** for checkpoint operations, use (walSyncFlags&0x03) and to get the correct ** sync flags for transaction commit, use ((walSyncFlags>>2)&0x03). Note ** that with synchronous=NORMAL in WAL mode, transaction commit is not synced ** meaning that the 0x04 and 0x08 bits are both zero. */ struct Pager { sqlite3_vfs *pVfs; /* OS functions to use for IO */ u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */ u8 journalMode; /* One of the PAGER_JOURNALMODE_* values */ u8 useJournal; /* Use a rollback journal on this file */ u8 noSync; /* Do not sync the journal if true */ u8 fullSync; /* Do extra syncs of the journal for robustness */ u8 extraSync; /* sync directory after journal delete */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ u8 walSyncFlags; /* See description above */ u8 tempFile; /* zFilename is a temporary or immutable file */ u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ u8 memVfs; /* VFS-implemented memory database */ /************************************************************************** ** The following block contains those class members that change during ** routine operation. Class members not in this block are either fixed ** when the pager is first created or else only change when there is a ** significant mode change (such as changing the page_size, locking_mode, ** or the journal_mode). From another view, these class members describe ** the "state" of the pager, while other class members describe the ** "configuration" of the pager. */ u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */ u8 eLock; /* Current lock held on database file */ u8 changeCountDone; /* Set after incrementing the change-counter */ u8 setSuper; /* Super-jrnl name is written into jrnl */ u8 doNotSpill; /* Do not spill the cache when non-zero */ u8 subjInMemory; /* True to use in-memory sub-journals */ u8 bUseFetch; /* True to use xFetch() */ u8 hasHeldSharedLock; /* True if a shared lock has ever been held */ Pgno dbSize; /* Number of pages in the database */ Pgno dbOrigSize; /* dbSize before the current transaction */ Pgno dbFileSize; /* Number of pages in the database file */ Pgno dbHintSize; /* Value passed to FCNTL_SIZE_HINT call */ int errCode; /* One of several kinds of errors */ int nRec; /* Pages journalled since last j-header written */ u32 cksumInit; /* Quasi-random value added to every checksum */ u32 nSubRec; /* Number of records written to sub-journal */ Bitvec *pInJournal; /* One bit for each page in the database file */ sqlite3_file *fd; /* File descriptor for database */ sqlite3_file *jfd; /* File descriptor for main journal */ sqlite3_file *sjfd; /* File descriptor for sub-journal */ i64 journalOff; /* Current write offset in the journal file */ i64 journalHdr; /* Byte offset to previous journal header */ sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ PagerSavepoint *aSavepoint; /* Array of active savepoints */ int nSavepoint; /* Number of elements in aSavepoint[] */ u32 iDataVersion; /* Changes whenever database content changes */ char dbFileVers[16]; /* Changes whenever database file changes */ int nMmapOut; /* Number of mmap pages currently outstanding */ sqlite3_int64 szMmap; /* Desired maximum mmap size */ PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */ /* ** End of the routinely-changing class members ***************************************************************************/ u16 nExtra; /* Add this many bytes to each in-memory page */ i16 nReserve; /* Number of unused bytes at end of each page */ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ u32 sectorSize; /* Assumed sector size during rollback */ Pgno mxPgno; /* Maximum allowed size of the database */ Pgno lckPgno; /* Page number for the locking page */ i64 pageSize; /* Number of bytes in a page */ i64 journalSizeLimit; /* Size limit for persistent journal files */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ int (*xBusyHandler)(void*); /* Function to call when busy */ void *pBusyHandlerArg; /* Context argument for xBusyHandler */ u32 aStat[4]; /* Total cache hits, misses, writes, spills */ #ifdef SQLITE_TEST int nRead; /* Database pages read */ #endif void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ PCache *pPCache; /* Pointer to page cache object */ #ifndef SQLITE_OMIT_WAL Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ char *zWal; /* File name for write-ahead log */ #endif }; /* ** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains ** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS ** or CACHE_WRITE to sqlite3_db_status(). */ #define PAGER_STAT_HIT 0 #define PAGER_STAT_MISS 1 #define PAGER_STAT_WRITE 2 #define PAGER_STAT_SPILL 3 /* ** The following global variables hold counters used for ** testing purposes only. These variables do not exist in ** a non-testing build. These variables are not thread-safe. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_pager_readdb_count = 0; /* Number of full pages read from DB */ SQLITE_API int sqlite3_pager_writedb_count = 0; /* Number of full pages written to DB */ SQLITE_API int sqlite3_pager_writej_count = 0; /* Number of pages written to journal */ # define PAGER_INCR(v) v++ #else # define PAGER_INCR(v) #endif /* ** Journal files begin with the following magic string. The data ** was obtained from /dev/random. It is used only as a sanity check. ** ** Since version 2.8.0, the journal format contains additional sanity ** checking information. If the power fails while the journal is being ** written, semi-random garbage data might appear in the journal ** file after power is restored. If an attempt is then made ** to roll the journal back, the database could be corrupted. The additional ** sanity checking data is an attempt to discover the garbage in the ** journal and ignore it. ** ** The sanity checking information for the new journal format consists ** of a 32-bit checksum on each page of data. The checksum covers both ** the page number and the pPager->pageSize bytes of data for the page. ** This cksum is initialized to a 32-bit random value that appears in the ** journal file right after the header. The random initializer is important, ** because garbage data that appears at the end of a journal is likely ** data that was once in other files that have now been deleted. If the ** garbage data came from an obsolete journal file, the checksums might ** be correct. But by initializing the checksum to random value which ** is different for every journal, we minimize that risk. */ static const unsigned char aJournalMagic[] = { 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7, }; /* ** The size of the of each page record in the journal is given by ** the following macro. */ #define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8) /* ** The journal header size for this pager. This is usually the same ** size as a single disk sector. See also setSectorSize(). */ #define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize) /* ** The macro MEMDB is true if we are dealing with an in-memory database. ** We do this as a macro so that if the SQLITE_OMIT_MEMORYDB macro is set, ** the value of MEMDB will be a constant and the compiler will optimize ** out code that would never execute. */ #ifdef SQLITE_OMIT_MEMORYDB # define MEMDB 0 #else # define MEMDB pPager->memDb #endif /* ** The macro USEFETCH is true if we are allowed to use the xFetch and xUnfetch ** interfaces to access the database using memory-mapped I/O. */ #if SQLITE_MAX_MMAP_SIZE>0 # define USEFETCH(x) ((x)->bUseFetch) #else # define USEFETCH(x) 0 #endif /* ** The argument to this macro is a file descriptor (type sqlite3_file*). ** Return 0 if it is not open, or non-zero (but not 1) if it is. ** ** This is so that expressions can be written as: ** ** if( isOpen(pPager->jfd) ){ ... ** ** instead of ** ** if( pPager->jfd->pMethods ){ ... */ #define isOpen(pFd) ((pFd)->pMethods!=0) #ifdef SQLITE_DIRECT_OVERFLOW_READ /* ** Return true if page pgno can be read directly from the database file ** by the b-tree layer. This is the case if: ** ** * the database file is open, ** * there are no dirty pages in the cache, and ** * the desired page is not currently in the wal file. */ SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ if( pPager->fd->pMethods==0 ) return 0; if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); return iRead==0; } #endif return 1; } #endif #ifndef SQLITE_OMIT_WAL # define pagerUseWal(x) ((x)->pWal!=0) #else # define pagerUseWal(x) 0 # define pagerRollbackWal(x) 0 # define pagerWalFrames(v,w,x,y) 0 # define pagerOpenWalIfPresent(z) SQLITE_OK # define pagerBeginReadTransaction(z) SQLITE_OK #endif #ifndef NDEBUG /* ** Usage: ** ** assert( assert_pager_state(pPager) ); ** ** This function runs many asserts to try to find inconsistencies in ** the internal state of the Pager object. */ static int assert_pager_state(Pager *p){ Pager *pPager = p; /* State must be valid. */ assert( p->eState==PAGER_OPEN || p->eState==PAGER_READER || p->eState==PAGER_WRITER_LOCKED || p->eState==PAGER_WRITER_CACHEMOD || p->eState==PAGER_WRITER_DBMOD || p->eState==PAGER_WRITER_FINISHED || p->eState==PAGER_ERROR ); /* Regardless of the current state, a temp-file connection always behaves ** as if it has an exclusive lock on the database file. It never updates ** the change-counter field, so the changeCountDone flag is always set. */ assert( p->tempFile==0 || p->eLock==EXCLUSIVE_LOCK ); assert( p->tempFile==0 || pPager->changeCountDone ); /* If the useJournal flag is clear, the journal-mode must be "OFF". ** And if the journal-mode is "OFF", the journal file must not be open. */ assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal ); assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) ); /* Check that MEMDB implies noSync. And an in-memory journal. Since ** this means an in-memory pager performs no IO at all, it cannot encounter ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing ** a journal file. (although the in-memory journal implementation may ** return SQLITE_IOERR_NOMEM while the journal file is being written). It ** is therefore not possible for an in-memory pager to enter the ERROR ** state. */ if( MEMDB ){ assert( !isOpen(p->fd) ); assert( p->noSync ); assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->journalMode==PAGER_JOURNALMODE_MEMORY ); assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN ); assert( pagerUseWal(p)==0 ); } /* If changeCountDone is set, a RESERVED lock or greater must be held ** on the file. */ assert( pPager->changeCountDone==0 || pPager->eLock>=RESERVED_LOCK ); assert( p->eLock!=PENDING_LOCK ); switch( p->eState ){ case PAGER_OPEN: assert( !MEMDB ); assert( pPager->errCode==SQLITE_OK ); assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile ); break; case PAGER_READER: assert( pPager->errCode==SQLITE_OK ); assert( p->eLock!=UNKNOWN_LOCK ); assert( p->eLock>=SHARED_LOCK ); break; case PAGER_WRITER_LOCKED: assert( p->eLock!=UNKNOWN_LOCK ); assert( pPager->errCode==SQLITE_OK ); if( !pagerUseWal(pPager) ){ assert( p->eLock>=RESERVED_LOCK ); } assert( pPager->dbSize==pPager->dbOrigSize ); assert( pPager->dbOrigSize==pPager->dbFileSize ); assert( pPager->dbOrigSize==pPager->dbHintSize ); assert( pPager->setSuper==0 ); break; case PAGER_WRITER_CACHEMOD: assert( p->eLock!=UNKNOWN_LOCK ); assert( pPager->errCode==SQLITE_OK ); if( !pagerUseWal(pPager) ){ /* It is possible that if journal_mode=wal here that neither the ** journal file nor the WAL file are open. This happens during ** a rollback transaction that switches from journal_mode=off ** to journal_mode=wal. */ assert( p->eLock>=RESERVED_LOCK ); assert( isOpen(p->jfd) || p->journalMode==PAGER_JOURNALMODE_OFF || p->journalMode==PAGER_JOURNALMODE_WAL ); } assert( pPager->dbOrigSize==pPager->dbFileSize ); assert( pPager->dbOrigSize==pPager->dbHintSize ); break; case PAGER_WRITER_DBMOD: assert( p->eLock==EXCLUSIVE_LOCK ); assert( pPager->errCode==SQLITE_OK ); assert( !pagerUseWal(pPager) ); assert( p->eLock>=EXCLUSIVE_LOCK ); assert( isOpen(p->jfd) || p->journalMode==PAGER_JOURNALMODE_OFF || p->journalMode==PAGER_JOURNALMODE_WAL || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC) ); assert( pPager->dbOrigSize<=pPager->dbHintSize ); break; case PAGER_WRITER_FINISHED: assert( p->eLock==EXCLUSIVE_LOCK ); assert( pPager->errCode==SQLITE_OK ); assert( !pagerUseWal(pPager) ); assert( isOpen(p->jfd) || p->journalMode==PAGER_JOURNALMODE_OFF || p->journalMode==PAGER_JOURNALMODE_WAL || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC) ); break; case PAGER_ERROR: /* There must be at least one outstanding reference to the pager if ** in ERROR state. Otherwise the pager should have already dropped ** back to OPEN state. */ assert( pPager->errCode!=SQLITE_OK ); assert( sqlite3PcacheRefCount(pPager->pPCache)>0 || pPager->tempFile ); break; } return 1; } #endif /* ifndef NDEBUG */ #ifdef SQLITE_DEBUG /* ** Return a pointer to a human readable string in a static buffer ** containing the state of the Pager object passed as an argument. This ** is intended to be used within debuggers. For example, as an alternative ** to "print *pPager" in gdb: ** ** (gdb) printf "%s", print_pager_state(pPager) ** ** This routine has external linkage in order to suppress compiler warnings ** about an unused function. It is enclosed within SQLITE_DEBUG and so does ** not appear in normal builds. */ char *print_pager_state(Pager *p){ static char zRet[1024]; sqlite3_snprintf(1024, zRet, "Filename: %s\n" "State: %s errCode=%d\n" "Lock: %s\n" "Locking mode: locking_mode=%s\n" "Journal mode: journal_mode=%s\n" "Backing store: tempFile=%d memDb=%d useJournal=%d\n" "Journal: journalOff=%lld journalHdr=%lld\n" "Size: dbsize=%d dbOrigSize=%d dbFileSize=%d\n" , p->zFilename , p->eState==PAGER_OPEN ? "OPEN" : p->eState==PAGER_READER ? "READER" : p->eState==PAGER_WRITER_LOCKED ? "WRITER_LOCKED" : p->eState==PAGER_WRITER_CACHEMOD ? "WRITER_CACHEMOD" : p->eState==PAGER_WRITER_DBMOD ? "WRITER_DBMOD" : p->eState==PAGER_WRITER_FINISHED ? "WRITER_FINISHED" : p->eState==PAGER_ERROR ? "ERROR" : "?error?" , (int)p->errCode , p->eLock==NO_LOCK ? "NO_LOCK" : p->eLock==RESERVED_LOCK ? "RESERVED" : p->eLock==EXCLUSIVE_LOCK ? "EXCLUSIVE" : p->eLock==SHARED_LOCK ? "SHARED" : p->eLock==UNKNOWN_LOCK ? "UNKNOWN" : "?error?" , p->exclusiveMode ? "exclusive" : "normal" , p->journalMode==PAGER_JOURNALMODE_MEMORY ? "memory" : p->journalMode==PAGER_JOURNALMODE_OFF ? "off" : p->journalMode==PAGER_JOURNALMODE_DELETE ? "delete" : p->journalMode==PAGER_JOURNALMODE_PERSIST ? "persist" : p->journalMode==PAGER_JOURNALMODE_TRUNCATE ? "truncate" : p->journalMode==PAGER_JOURNALMODE_WAL ? "wal" : "?error?" , (int)p->tempFile, (int)p->memDb, (int)p->useJournal , p->journalOff, p->journalHdr , (int)p->dbSize, (int)p->dbOrigSize, (int)p->dbFileSize ); return zRet; } #endif /* Forward references to the various page getters */ static int getPageNormal(Pager*,Pgno,DbPage**,int); static int getPageError(Pager*,Pgno,DbPage**,int); #if SQLITE_MAX_MMAP_SIZE>0 static int getPageMMap(Pager*,Pgno,DbPage**,int); #endif /* ** Set the Pager.xGet method for the appropriate routine used to fetch ** content from the pager. */ static void setGetterMethod(Pager *pPager){ if( pPager->errCode ){ pPager->xGet = getPageError; #if SQLITE_MAX_MMAP_SIZE>0 }else if( USEFETCH(pPager) ){ pPager->xGet = getPageMMap; #endif /* SQLITE_MAX_MMAP_SIZE>0 */ }else{ pPager->xGet = getPageNormal; } } /* ** Return true if it is necessary to write page *pPg into the sub-journal. ** A page needs to be written into the sub-journal if there exists one ** or more open savepoints for which: ** ** * The page-number is less than or equal to PagerSavepoint.nOrig, and ** * The bit corresponding to the page-number is not set in ** PagerSavepoint.pInSavepoint. */ static int subjRequiresPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; PagerSavepoint *p; Pgno pgno = pPg->pgno; int i; for(i=0; inSavepoint; i++){ p = &pPager->aSavepoint[i]; if( p->nOrig>=pgno && 0==sqlite3BitvecTestNotNull(p->pInSavepoint, pgno) ){ for(i=i+1; inSavepoint; i++){ pPager->aSavepoint[i].bTruncateOnRelease = 0; } return 1; } } return 0; } #ifdef SQLITE_DEBUG /* ** Return true if the page is already in the journal file. */ static int pageInJournal(Pager *pPager, PgHdr *pPg){ return sqlite3BitvecTest(pPager->pInJournal, pPg->pgno); } #endif /* ** Read a 32-bit integer from the given file descriptor. Store the integer ** that is read in *pRes. Return SQLITE_OK if everything worked, or an ** error code is something goes wrong. ** ** All values are stored on disk as big-endian. */ static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){ unsigned char ac[4]; int rc = sqlite3OsRead(fd, ac, sizeof(ac), offset); if( rc==SQLITE_OK ){ *pRes = sqlite3Get4byte(ac); } return rc; } /* ** Write a 32-bit integer into a string buffer in big-endian byte order. */ #define put32bits(A,B) sqlite3Put4byte((u8*)A,B) /* ** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK ** on success or an error code is something goes wrong. */ static int write32bits(sqlite3_file *fd, i64 offset, u32 val){ char ac[4]; put32bits(ac, val); return sqlite3OsWrite(fd, ac, 4, offset); } /* ** Unlock the database file to level eLock, which must be either NO_LOCK ** or SHARED_LOCK. Regardless of whether or not the call to xUnlock() ** succeeds, set the Pager.eLock variable to match the (attempted) new lock. ** ** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is ** called, do not modify it. See the comment above the #define of ** UNKNOWN_LOCK for an explanation of this. */ static int pagerUnlockDb(Pager *pPager, int eLock){ int rc = SQLITE_OK; assert( !pPager->exclusiveMode || pPager->eLock==eLock ); assert( eLock==NO_LOCK || eLock==SHARED_LOCK ); assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 ); if( isOpen(pPager->fd) ){ assert( pPager->eLock>=eLock ); rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock); if( pPager->eLock!=UNKNOWN_LOCK ){ pPager->eLock = (u8)eLock; } IOTRACE(("UNLOCK %p %d\n", pPager, eLock)) } pPager->changeCountDone = pPager->tempFile; /* ticket fb3b3024ea238d5c */ return rc; } /* ** Lock the database file to level eLock, which must be either SHARED_LOCK, ** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the ** Pager.eLock variable to the new locking state. ** ** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is ** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK. ** See the comment above the #define of UNKNOWN_LOCK for an explanation ** of this. */ static int pagerLockDb(Pager *pPager, int eLock){ int rc = SQLITE_OK; assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK ); if( pPager->eLockeLock==UNKNOWN_LOCK ){ rc = pPager->noLock ? SQLITE_OK : sqlite3OsLock(pPager->fd, eLock); if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){ pPager->eLock = (u8)eLock; IOTRACE(("LOCK %p %d\n", pPager, eLock)) } } return rc; } /* ** This function determines whether or not the atomic-write or ** atomic-batch-write optimizations can be used with this pager. The ** atomic-write optimization can be used if: ** ** (a) the value returned by OsDeviceCharacteristics() indicates that ** a database page may be written atomically, and ** (b) the value returned by OsSectorSize() is less than or equal ** to the page size. ** ** If it can be used, then the value returned is the size of the journal ** file when it contains rollback data for exactly one page. ** ** The atomic-batch-write optimization can be used if OsDeviceCharacteristics() ** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is ** returned in this case. ** ** If neither optimization can be used, 0 is returned. */ static int jrnlBufferSize(Pager *pPager){ assert( !MEMDB ); #if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) int dc; /* Device characteristics */ assert( isOpen(pPager->fd) ); dc = sqlite3OsDeviceCharacteristics(pPager->fd); #else UNUSED_PARAMETER(pPager); #endif #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE if( pPager->dbSize>0 && (dc&SQLITE_IOCAP_BATCH_ATOMIC) ){ return -1; } #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE { int nSector = pPager->sectorSize; int szPage = pPager->pageSize; assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); if( 0==(dc&(SQLITE_IOCAP_ATOMIC|(szPage>>8)) || nSector>szPage) ){ return 0; } } return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager); #endif return 0; } /* ** If SQLITE_CHECK_PAGES is defined then we do some sanity checking ** on the cache using a hash function. This is used for testing ** and debugging only. */ #ifdef SQLITE_CHECK_PAGES /* ** Return a 32-bit hash of the page data for pPage. */ static u32 pager_datahash(int nByte, unsigned char *pData){ u32 hash = 0; int i; for(i=0; ipPager->pageSize, (unsigned char *)pPage->pData); } static void pager_set_pagehash(PgHdr *pPage){ pPage->pageHash = pager_pagehash(pPage); } /* ** The CHECK_PAGE macro takes a PgHdr* as an argument. If SQLITE_CHECK_PAGES ** is defined, and NDEBUG is not defined, an assert() statement checks ** that the page is either dirty or still matches the calculated page-hash. */ #define CHECK_PAGE(x) checkPage(x) static void checkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; assert( pPager->eState!=PAGER_ERROR ); assert( (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) ); } #else #define pager_datahash(X,Y) 0 #define pager_pagehash(X) 0 #define pager_set_pagehash(X) #define CHECK_PAGE(x) #endif /* SQLITE_CHECK_PAGES */ /* ** When this is called the journal file for pager pPager must be open. ** This function attempts to read a super-journal file name from the ** end of the file and, if successful, copies it into memory supplied ** by the caller. See comments above writeSuperJournal() for the format ** used to store a super-journal file name at the end of a journal file. ** ** zSuper must point to a buffer of at least nSuper bytes allocated by ** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is ** enough space to write the super-journal name). If the super-journal ** name in the journal is longer than nSuper bytes (including a ** nul-terminator), then this is handled as if no super-journal name ** were present in the journal. ** ** If a super-journal file name is present at the end of the journal ** file, then it is copied into the buffer pointed to by zSuper. A ** nul-terminator byte is appended to the buffer following the ** super-journal file name. ** ** If it is determined that no super-journal file name is present ** zSuper[0] is set to 0 and SQLITE_OK returned. ** ** If an error occurs while reading from the journal file, an SQLite ** error code is returned. */ static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){ int rc; /* Return code */ u32 len; /* Length in bytes of super-journal name */ i64 szJ; /* Total size in bytes of journal file pJrnl */ u32 cksum; /* MJ checksum value read from journal */ u32 u; /* Unsigned loop counter */ unsigned char aMagic[8]; /* A buffer to hold the magic header */ zSuper[0] = '\0'; if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ)) || szJ<16 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) || len>=nSuper || len>szJ-16 || len==0 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum)) || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8)) || memcmp(aMagic, aJournalMagic, 8) || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len)) ){ return rc; } /* See if the checksum matches the super-journal name */ for(u=0; ujournalOff, assuming a sector ** size of pPager->sectorSize bytes. ** ** i.e for a sector size of 512: ** ** Pager.journalOff Return value ** --------------------------------------- ** 0 0 ** 512 512 ** 100 512 ** 2000 2048 ** */ static i64 journalHdrOffset(Pager *pPager){ i64 offset = 0; i64 c = pPager->journalOff; if( c ){ offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager); } assert( offset%JOURNAL_HDR_SZ(pPager)==0 ); assert( offset>=c ); assert( (offset-c)jfd) ); assert( !sqlite3JournalIsInMemory(pPager->jfd) ); if( pPager->journalOff ){ const i64 iLimit = pPager->journalSizeLimit; /* Local cache of jsl */ IOTRACE(("JZEROHDR %p\n", pPager)) if( doTruncate || iLimit==0 ){ rc = sqlite3OsTruncate(pPager->jfd, 0); }else{ static const char zeroHdr[28] = {0}; rc = sqlite3OsWrite(pPager->jfd, zeroHdr, sizeof(zeroHdr), 0); } if( rc==SQLITE_OK && !pPager->noSync ){ rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->syncFlags); } /* At this point the transaction is committed but the write lock ** is still held on the file. If there is a size limit configured for ** the persistent journal and the journal file currently consumes more ** space than that limit allows for, truncate it now. There is no need ** to sync the file following this operation. */ if( rc==SQLITE_OK && iLimit>0 ){ i64 sz; rc = sqlite3OsFileSize(pPager->jfd, &sz); if( rc==SQLITE_OK && sz>iLimit ){ rc = sqlite3OsTruncate(pPager->jfd, iLimit); } } } return rc; } /* ** The journal file must be open when this routine is called. A journal ** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the ** current location. ** ** The format for the journal header is as follows: ** - 8 bytes: Magic identifying journal format. ** - 4 bytes: Number of records in journal, or -1 no-sync mode is on. ** - 4 bytes: Random number used for page hash. ** - 4 bytes: Initial database page count. ** - 4 bytes: Sector size used by the process that wrote this journal. ** - 4 bytes: Database page size. ** ** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space. */ static int writeJournalHdr(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ char *zHeader = pPager->pTmpSpace; /* Temporary space used to build header */ u32 nHeader = (u32)pPager->pageSize;/* Size of buffer pointed to by zHeader */ u32 nWrite; /* Bytes of header sector written */ int ii; /* Loop counter */ assert( isOpen(pPager->jfd) ); /* Journal file must be open. */ if( nHeader>JOURNAL_HDR_SZ(pPager) ){ nHeader = JOURNAL_HDR_SZ(pPager); } /* If there are active savepoints and any of them were created ** since the most recent journal header was written, update the ** PagerSavepoint.iHdrOffset fields now. */ for(ii=0; iinSavepoint; ii++){ if( pPager->aSavepoint[ii].iHdrOffset==0 ){ pPager->aSavepoint[ii].iHdrOffset = pPager->journalOff; } } pPager->journalHdr = pPager->journalOff = journalHdrOffset(pPager); /* ** Write the nRec Field - the number of page records that follow this ** journal header. Normally, zero is written to this value at this time. ** After the records are added to the journal (and the journal synced, ** if in full-sync mode), the zero is overwritten with the true number ** of records (see syncJournal()). ** ** A faster alternative is to write 0xFFFFFFFF to the nRec field. When ** reading the journal this value tells SQLite to assume that the ** rest of the journal file contains valid page records. This assumption ** is dangerous, as if a failure occurred whilst writing to the journal ** file it may contain some garbage data. There are two scenarios ** where this risk can be ignored: ** ** * When the pager is in no-sync mode. Corruption can follow a ** power failure in this case anyway. ** ** * When the SQLITE_IOCAP_SAFE_APPEND flag is set. This guarantees ** that garbage data is never appended to the journal file. */ assert( isOpen(pPager->fd) || pPager->noSync ); if( pPager->noSync || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY) || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) ){ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); }else{ memset(zHeader, 0, sizeof(aJournalMagic)+4); } /* The random check-hash initializer */ if( pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){ sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); } #ifdef SQLITE_DEBUG else{ /* The Pager.cksumInit variable is usually randomized above to protect ** against there being existing records in the journal file. This is ** dangerous, as following a crash they may be mistaken for records ** written by the current transaction and rolled back into the database ** file, causing corruption. The following assert statements verify ** that this is not required in "journal_mode=memory" mode, as in that ** case the journal file is always 0 bytes in size at this point. ** It is advantageous to avoid the sqlite3_randomness() call if possible ** as it takes the global PRNG mutex. */ i64 sz = 0; sqlite3OsFileSize(pPager->jfd, &sz); assert( sz==0 ); assert( pPager->journalOff==journalHdrOffset(pPager) ); assert( sqlite3JournalIsInMemory(pPager->jfd) ); } #endif put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); /* The initial database size */ put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize); /* The assumed sector size for this process */ put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize); /* The page size */ put32bits(&zHeader[sizeof(aJournalMagic)+16], pPager->pageSize); /* Initializing the tail of the buffer is not necessary. Everything ** works find if the following memset() is omitted. But initializing ** the memory prevents valgrind from complaining, so we are willing to ** take the performance hit. */ memset(&zHeader[sizeof(aJournalMagic)+20], 0, nHeader-(sizeof(aJournalMagic)+20)); /* In theory, it is only necessary to write the 28 bytes that the ** journal header consumes to the journal file here. Then increment the ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next ** record is written to the following sector (leaving a gap in the file ** that will be implicitly filled in by the OS). ** ** However it has been discovered that on some systems this pattern can ** be significantly slower than contiguously writing data to the file, ** even if that means explicitly writing data to the block of ** (JOURNAL_HDR_SZ - 28) bytes that will not be used. So that is what ** is done. ** ** The loop is required here in case the sector-size is larger than the ** database page size. Since the zHeader buffer is only Pager.pageSize ** bytes in size, more than one call to sqlite3OsWrite() may be required ** to populate the entire journal header sector. */ for(nWrite=0; rc==SQLITE_OK&&nWritejournalHdr, nHeader)) rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff); assert( pPager->journalHdr <= pPager->journalOff ); pPager->journalOff += nHeader; } return rc; } /* ** The journal file must be open when this is called. A journal header file ** (JOURNAL_HDR_SZ bytes) is read from the current location in the journal ** file. The current location in the journal file is given by ** pPager->journalOff. See comments above function writeJournalHdr() for ** a description of the journal header format. ** ** If the header is read successfully, *pNRec is set to the number of ** page records following this header and *pDbSize is set to the size of the ** database before the transaction began, in pages. Also, pPager->cksumInit ** is set to the value read from the journal header. SQLITE_OK is returned ** in this case. ** ** If the journal header file appears to be corrupted, SQLITE_DONE is ** returned and *pNRec and *PDbSize are undefined. If JOURNAL_HDR_SZ bytes ** cannot be read from the journal file an error code is returned. */ static int readJournalHdr( Pager *pPager, /* Pager object */ int isHot, i64 journalSize, /* Size of the open journal file in bytes */ u32 *pNRec, /* OUT: Value read from the nRec field */ u32 *pDbSize /* OUT: Value of original database size field */ ){ int rc; /* Return code */ unsigned char aMagic[8]; /* A buffer to hold the magic header */ i64 iHdrOff; /* Offset of journal header being read */ assert( isOpen(pPager->jfd) ); /* Journal file must be open. */ /* Advance Pager.journalOff to the start of the next sector. If the ** journal file is too small for there to be a header stored at this ** point, return SQLITE_DONE. */ pPager->journalOff = journalHdrOffset(pPager); if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){ return SQLITE_DONE; } iHdrOff = pPager->journalOff; /* Read in the first 8 bytes of the journal header. If they do not match ** the magic string found at the start of each journal header, return ** SQLITE_DONE. If an IO error occurs, return an error code. Otherwise, ** proceed. */ if( isHot || iHdrOff!=pPager->journalHdr ){ rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic), iHdrOff); if( rc ){ return rc; } if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ return SQLITE_DONE; } } /* Read the first three 32-bit fields of the journal header: The nRec ** field, the checksum-initializer and the database size at the start ** of the transaction. Return an error code if anything goes wrong. */ if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+8, pNRec)) || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+12, &pPager->cksumInit)) || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+16, pDbSize)) ){ return rc; } if( pPager->journalOff==0 ){ u32 iPageSize; /* Page-size field of journal header */ u32 iSectorSize; /* Sector-size field of journal header */ /* Read the page-size and sector-size journal header fields. */ if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+20, &iSectorSize)) || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+24, &iPageSize)) ){ return rc; } /* Versions of SQLite prior to 3.5.8 set the page-size field of the ** journal header to zero. In this case, assume that the Pager.pageSize ** variable is already set to the correct page size. */ if( iPageSize==0 ){ iPageSize = pPager->pageSize; } /* Check that the values read from the page-size and sector-size fields ** are within range. To be 'in range', both values need to be a power ** of two greater than or equal to 512 or 32, and not greater than their ** respective compile time maximum limits. */ if( iPageSize<512 || iSectorSize<32 || iPageSize>SQLITE_MAX_PAGE_SIZE || iSectorSize>MAX_SECTOR_SIZE || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0 ){ /* If the either the page-size or sector-size in the journal-header is ** invalid, then the process that wrote the journal-header must have ** crashed before the header was synced. In this case stop reading ** the journal file here. */ return SQLITE_DONE; } /* Update the page-size to match the value read from the journal. ** Use a testcase() macro to make sure that malloc failure within ** PagerSetPagesize() is tested. */ rc = sqlite3PagerSetPagesize(pPager, &iPageSize, -1); testcase( rc!=SQLITE_OK ); /* Update the assumed sector-size to match the value used by ** the process that created this journal. If this journal was ** created by a process other than this one, then this routine ** is being called from within pager_playback(). The local value ** of Pager.sectorSize is restored at the end of that routine. */ pPager->sectorSize = iSectorSize; } pPager->journalOff += JOURNAL_HDR_SZ(pPager); return rc; } /* ** Write the supplied super-journal name into the journal file for pager ** pPager at the current location. The super-journal name must be the last ** thing written to a journal file. If the pager is in full-sync mode, the ** journal file descriptor is advanced to the next sector boundary before ** anything is written. The format is: ** ** + 4 bytes: PAGER_SJ_PGNO. ** + N bytes: super-journal filename in utf-8. ** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator). ** + 4 bytes: super-journal name checksum. ** + 8 bytes: aJournalMagic[]. ** ** The super-journal page checksum is the sum of the bytes in the super-journal ** name, where each byte is interpreted as a signed 8-bit integer. ** ** If zSuper is a NULL pointer (occurs for a single database transaction), ** this call is a no-op. */ static int writeSuperJournal(Pager *pPager, const char *zSuper){ int rc; /* Return code */ int nSuper; /* Length of string zSuper */ i64 iHdrOff; /* Offset of header in journal file */ i64 jrnlSize; /* Size of journal file on disk */ u32 cksum = 0; /* Checksum of string zSuper */ assert( pPager->setSuper==0 ); assert( !pagerUseWal(pPager) ); if( !zSuper || pPager->journalMode==PAGER_JOURNALMODE_MEMORY || !isOpen(pPager->jfd) ){ return SQLITE_OK; } pPager->setSuper = 1; assert( pPager->journalHdr <= pPager->journalOff ); /* Calculate the length in bytes and the checksum of zSuper */ for(nSuper=0; zSuper[nSuper]; nSuper++){ cksum += zSuper[nSuper]; } /* If in full-sync mode, advance to the next disk sector before writing ** the super-journal name. This is in case the previous page written to ** the journal has already been synced. */ if( pPager->fullSync ){ pPager->journalOff = journalHdrOffset(pPager); } iHdrOff = pPager->journalOff; /* Write the super-journal data to the end of the journal file. If ** an error occurs, return the error code to the caller. */ if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_SJ_PGNO(pPager)))) || (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum))) || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8, iHdrOff+4+nSuper+8))) ){ return rc; } pPager->journalOff += (nSuper+20); /* If the pager is in persistent-journal mode, then the physical ** journal-file may extend past the end of the super-journal name ** and 8 bytes of magic data just written to the file. This is ** dangerous because the code to rollback a hot-journal file ** will not be able to find the super-journal name to determine ** whether or not the journal is hot. ** ** Easiest thing to do in this scenario is to truncate the journal ** file to the required size. */ if( SQLITE_OK==(rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize)) && jrnlSize>pPager->journalOff ){ rc = sqlite3OsTruncate(pPager->jfd, pPager->journalOff); } return rc; } /* ** Discard the entire contents of the in-memory page-cache. */ static void pager_reset(Pager *pPager){ pPager->iDataVersion++; sqlite3BackupRestart(pPager->pBackup); sqlite3PcacheClear(pPager->pPCache); } /* ** Return the pPager->iDataVersion value */ SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){ return pPager->iDataVersion; } /* ** Free all structures in the Pager.aSavepoint[] array and set both ** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal ** if it is open and the pager is not in exclusive mode. */ static void releaseAllSavepoints(Pager *pPager){ int ii; /* Iterator for looping through Pager.aSavepoint */ for(ii=0; iinSavepoint; ii++){ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint); } if( !pPager->exclusiveMode || sqlite3JournalIsInMemory(pPager->sjfd) ){ sqlite3OsClose(pPager->sjfd); } sqlite3_free(pPager->aSavepoint); pPager->aSavepoint = 0; pPager->nSavepoint = 0; pPager->nSubRec = 0; } /* ** Set the bit number pgno in the PagerSavepoint.pInSavepoint ** bitvecs of all open savepoints. Return SQLITE_OK if successful ** or SQLITE_NOMEM if a malloc failure occurs. */ static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){ int ii; /* Loop counter */ int rc = SQLITE_OK; /* Result code */ for(ii=0; iinSavepoint; ii++){ PagerSavepoint *p = &pPager->aSavepoint[ii]; if( pgno<=p->nOrig ){ rc |= sqlite3BitvecSet(p->pInSavepoint, pgno); testcase( rc==SQLITE_NOMEM ); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); } } return rc; } /* ** This function is a no-op if the pager is in exclusive mode and not ** in the ERROR state. Otherwise, it switches the pager to PAGER_OPEN ** state. ** ** If the pager is not in exclusive-access mode, the database file is ** completely unlocked. If the file is unlocked and the file-system does ** not exhibit the UNDELETABLE_WHEN_OPEN property, the journal file is ** closed (if it is open). ** ** If the pager is in ERROR state when this function is called, the ** contents of the pager cache are discarded before switching back to ** the OPEN state. Regardless of whether the pager is in exclusive-mode ** or not, any journal file left in the file-system will be treated ** as a hot-journal and rolled back the next time a read-transaction ** is opened (by this or by any other connection). */ static void pager_unlock(Pager *pPager){ assert( pPager->eState==PAGER_READER || pPager->eState==PAGER_OPEN || pPager->eState==PAGER_ERROR ); sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; releaseAllSavepoints(pPager); if( pagerUseWal(pPager) ){ assert( !isOpen(pPager->jfd) ); sqlite3WalEndReadTransaction(pPager->pWal); pPager->eState = PAGER_OPEN; }else if( !pPager->exclusiveMode ){ int rc; /* Error code returned by pagerUnlockDb() */ int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0; /* If the operating system support deletion of open files, then ** close the journal file when dropping the database lock. Otherwise ** another connection with journal_mode=delete might delete the file ** out from under us. */ assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 ); assert( (PAGER_JOURNALMODE_OFF & 5)!=1 ); assert( (PAGER_JOURNALMODE_WAL & 5)!=1 ); assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 ); assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 ); assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 ); if( 0==(iDc & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN) || 1!=(pPager->journalMode & 5) ){ sqlite3OsClose(pPager->jfd); } /* If the pager is in the ERROR state and the call to unlock the database ** file fails, set the current lock to UNKNOWN_LOCK. See the comment ** above the #define for UNKNOWN_LOCK for an explanation of why this ** is necessary. */ rc = pagerUnlockDb(pPager, NO_LOCK); if( rc!=SQLITE_OK && pPager->eState==PAGER_ERROR ){ pPager->eLock = UNKNOWN_LOCK; } /* The pager state may be changed from PAGER_ERROR to PAGER_OPEN here ** without clearing the error code. This is intentional - the error ** code is cleared and the cache reset in the block below. */ assert( pPager->errCode || pPager->eState!=PAGER_ERROR ); pPager->eState = PAGER_OPEN; } /* If Pager.errCode is set, the contents of the pager cache cannot be ** trusted. Now that there are no outstanding references to the pager, ** it can safely move back to PAGER_OPEN state. This happens in both ** normal and exclusive-locking mode. */ assert( pPager->errCode==SQLITE_OK || !MEMDB ); if( pPager->errCode ){ if( pPager->tempFile==0 ){ pager_reset(pPager); pPager->changeCountDone = 0; pPager->eState = PAGER_OPEN; }else{ pPager->eState = (isOpen(pPager->jfd) ? PAGER_OPEN : PAGER_READER); } if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); pPager->errCode = SQLITE_OK; setGetterMethod(pPager); } pPager->journalOff = 0; pPager->journalHdr = 0; pPager->setSuper = 0; } /* ** This function is called whenever an IOERR or FULL error that requires ** the pager to transition into the ERROR state may have occurred. ** The first argument is a pointer to the pager structure, the second ** the error-code about to be returned by a pager API function. The ** value returned is a copy of the second argument to this function. ** ** If the second argument is SQLITE_FULL, SQLITE_IOERR or one of the ** IOERR sub-codes, the pager enters the ERROR state and the error code ** is stored in Pager.errCode. While the pager remains in the ERROR state, ** all major API calls on the Pager will immediately return Pager.errCode. ** ** The ERROR state indicates that the contents of the pager-cache ** cannot be trusted. This state can be cleared by completely discarding ** the contents of the pager-cache. If a transaction was active when ** the persistent error occurred, then the rollback journal may need ** to be replayed to restore the contents of the database file (as if ** it were a hot-journal). */ static int pager_error(Pager *pPager, int rc){ int rc2 = rc & 0xff; assert( rc==SQLITE_OK || !MEMDB ); assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK || (pPager->errCode & 0xff)==SQLITE_IOERR ); if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){ pPager->errCode = rc; pPager->eState = PAGER_ERROR; setGetterMethod(pPager); } return rc; } static int pager_truncate(Pager *pPager, Pgno nPage); /* ** The write transaction open on pPager is being committed (bCommit==1) ** or rolled back (bCommit==0). ** ** Return TRUE if and only if all dirty pages should be flushed to disk. ** ** Rules: ** ** * For non-TEMP databases, always sync to disk. This is necessary ** for transactions to be durable. ** ** * Sync TEMP database only on a COMMIT (not a ROLLBACK) when the backing ** file has been created already (via a spill on pagerStress()) and ** when the number of dirty pages in memory exceeds 25% of the total ** cache size. */ static int pagerFlushOnCommit(Pager *pPager, int bCommit){ if( pPager->tempFile==0 ) return 1; if( !bCommit ) return 0; if( !isOpen(pPager->fd) ) return 0; return (sqlite3PCachePercentDirty(pPager->pPCache)>=25); } /* ** This routine ends a transaction. A transaction is usually ended by ** either a COMMIT or a ROLLBACK operation. This routine may be called ** after rollback of a hot-journal, or if an error occurs while opening ** the journal file or writing the very first journal-header of a ** database transaction. ** ** This routine is never called in PAGER_ERROR state. If it is called ** in PAGER_NONE or PAGER_SHARED state and the lock held is less ** exclusive than a RESERVED lock, it is a no-op. ** ** Otherwise, any active savepoints are released. ** ** If the journal file is open, then it is "finalized". Once a journal ** file has been finalized it is not possible to use it to roll back a ** transaction. Nor will it be considered to be a hot-journal by this ** or any other database connection. Exactly how a journal is finalized ** depends on whether or not the pager is running in exclusive mode and ** the current journal-mode (Pager.journalMode value), as follows: ** ** journalMode==MEMORY ** Journal file descriptor is simply closed. This destroys an ** in-memory journal. ** ** journalMode==TRUNCATE ** Journal file is truncated to zero bytes in size. ** ** journalMode==PERSIST ** The first 28 bytes of the journal file are zeroed. This invalidates ** the first journal header in the file, and hence the entire journal ** file. An invalid journal file cannot be rolled back. ** ** journalMode==DELETE ** The journal file is closed and deleted using sqlite3OsDelete(). ** ** If the pager is running in exclusive mode, this method of finalizing ** the journal file is never used. Instead, if the journalMode is ** DELETE and the pager is in exclusive mode, the method described under ** journalMode==PERSIST is used instead. ** ** After the journal is finalized, the pager moves to PAGER_READER state. ** If running in non-exclusive rollback mode, the lock on the file is ** downgraded to a SHARED_LOCK. ** ** SQLITE_OK is returned if no error occurs. If an error occurs during ** any of the IO operations to finalize the journal file or unlock the ** database then the IO error code is returned to the user. If the ** operation to finalize the journal file fails, then the code still ** tries to unlock the database file if not in exclusive mode. If the ** unlock operation fails as well, then the first error code related ** to the first error encountered (the journal finalization one) is ** returned. */ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ int rc = SQLITE_OK; /* Error code from journal finalization operation */ int rc2 = SQLITE_OK; /* Error code from db file unlock operation */ /* Do nothing if the pager does not have an open write transaction ** or at least a RESERVED lock. This function may be called when there ** is no write-transaction active but a RESERVED or greater lock is ** held under two circumstances: ** ** 1. After a successful hot-journal rollback, it is called with ** eState==PAGER_NONE and eLock==EXCLUSIVE_LOCK. ** ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE ** lock switches back to locking_mode=normal and then executes a ** read-transaction, this function is called with eState==PAGER_READER ** and eLock==EXCLUSIVE_LOCK when the read-transaction is closed. */ assert( assert_pager_state(pPager) ); assert( pPager->eState!=PAGER_ERROR ); if( pPager->eStateeLockjfd) || pPager->pInJournal==0 || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC) ); if( isOpen(pPager->jfd) ){ assert( !pagerUseWal(pPager) ); /* Finalize the journal file. */ if( sqlite3JournalIsInMemory(pPager->jfd) ){ /* assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); */ sqlite3OsClose(pPager->jfd); }else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){ if( pPager->journalOff==0 ){ rc = SQLITE_OK; }else{ rc = sqlite3OsTruncate(pPager->jfd, 0); if( rc==SQLITE_OK && pPager->fullSync ){ /* Make sure the new file size is written into the inode right away. ** Otherwise the journal might resurrect following a power loss and ** cause the last transaction to roll back. See ** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773 */ rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); } } pPager->journalOff = 0; }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) ){ rc = zeroJournalHdr(pPager, hasSuper||pPager->tempFile); pPager->journalOff = 0; }else{ /* This branch may be executed with Pager.journalMode==MEMORY if ** a hot-journal was just rolled back. In this case the journal ** file should be closed and deleted. If this connection writes to ** the database file, it will do so using an in-memory journal. */ int bDelete = !pPager->tempFile; assert( sqlite3JournalIsInMemory(pPager->jfd)==0 ); assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE || pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->journalMode==PAGER_JOURNALMODE_WAL ); sqlite3OsClose(pPager->jfd); if( bDelete ){ rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, pPager->extraSync); } } } #ifdef SQLITE_CHECK_PAGES sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash); if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){ PgHdr *p = sqlite3PagerLookup(pPager, 1); if( p ){ p->pageHash = 0; sqlite3PagerUnrefNotNull(p); } } #endif sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; pPager->nRec = 0; if( rc==SQLITE_OK ){ if( MEMDB || pagerFlushOnCommit(pPager, bCommit) ){ sqlite3PcacheCleanAll(pPager->pPCache); }else{ sqlite3PcacheClearWritable(pPager->pPCache); } sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); } if( pagerUseWal(pPager) ){ /* Drop the WAL write-lock, if any. Also, if the connection was in ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE ** lock held on the database file. */ rc2 = sqlite3WalEndWriteTransaction(pPager->pWal); assert( rc2==SQLITE_OK ); }else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){ /* This branch is taken when committing a transaction in rollback-journal ** mode if the database file on disk is larger than the database image. ** At this point the journal has been finalized and the transaction ** successfully committed, but the EXCLUSIVE lock is still held on the ** file. So it is safe to truncate the database file to its minimum ** required size. */ assert( pPager->eLock==EXCLUSIVE_LOCK ); rc = pager_truncate(pPager, pPager->dbSize); } if( rc==SQLITE_OK && bCommit ){ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0); if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } if( !pPager->exclusiveMode && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); } pPager->eState = PAGER_READER; pPager->setSuper = 0; return (rc==SQLITE_OK?rc2:rc); } /* Forward reference */ static int pager_playback(Pager *pPager, int isHot); /* ** Execute a rollback if a transaction is active and unlock the ** database file. ** ** If the pager has already entered the ERROR state, do not attempt ** the rollback at this time. Instead, pager_unlock() is called. The ** call to pager_unlock() will discard all in-memory pages, unlock ** the database file and move the pager back to OPEN state. If this ** means that there is a hot-journal left in the file-system, the next ** connection to obtain a shared lock on the pager (which may be this one) ** will roll it back. ** ** If the pager has not already entered the ERROR state, but an IO or ** malloc error occurs during a rollback, then this will itself cause ** the pager to enter the ERROR state. Which will be cleared by the ** call to pager_unlock(), as described above. */ static void pagerUnlockAndRollback(Pager *pPager){ if( pPager->eState!=PAGER_ERROR && pPager->eState!=PAGER_OPEN ){ assert( assert_pager_state(pPager) ); if( pPager->eState>=PAGER_WRITER_LOCKED ){ sqlite3BeginBenignMalloc(); sqlite3PagerRollback(pPager); sqlite3EndBenignMalloc(); }else if( !pPager->exclusiveMode ){ assert( pPager->eState==PAGER_READER ); pager_end_transaction(pPager, 0, 0); } }else if( pPager->eState==PAGER_ERROR && pPager->journalMode==PAGER_JOURNALMODE_MEMORY && isOpen(pPager->jfd) ){ /* Special case for a ROLLBACK due to I/O error with an in-memory ** journal: We have to rollback immediately, before the journal is ** closed, because once it is closed, all content is forgotten. */ int errCode = pPager->errCode; u8 eLock = pPager->eLock; pPager->eState = PAGER_OPEN; pPager->errCode = SQLITE_OK; pPager->eLock = EXCLUSIVE_LOCK; pager_playback(pPager, 1); pPager->errCode = errCode; pPager->eLock = eLock; } pager_unlock(pPager); } /* ** Parameter aData must point to a buffer of pPager->pageSize bytes ** of data. Compute and return a checksum based on the contents of the ** page of data and the current value of pPager->cksumInit. ** ** This is not a real checksum. It is really just the sum of the ** random initial value (pPager->cksumInit) and every 200th byte ** of the page data, starting with byte offset (pPager->pageSize%200). ** Each byte is interpreted as an 8-bit unsigned integer. ** ** Changing the formula used to compute this checksum results in an ** incompatible journal file format. ** ** If journal corruption occurs due to a power failure, the most likely ** scenario is that one end or the other of the record will be changed. ** It is much less likely that the two ends of the journal record will be ** correct and the middle be corrupt. Thus, this "checksum" scheme, ** though fast and simple, catches the mostly likely kind of corruption. */ static u32 pager_cksum(Pager *pPager, const u8 *aData){ u32 cksum = pPager->cksumInit; /* Checksum value to return */ int i = pPager->pageSize-200; /* Loop counter */ while( i>0 ){ cksum += aData[i]; i -= 200; } return cksum; } /* ** Read a single page from either the journal file (if isMainJrnl==1) or ** from the sub-journal (if isMainJrnl==0) and playback that page. ** The page begins at offset *pOffset into the file. The *pOffset ** value is increased to the start of the next page in the journal. ** ** The main rollback journal uses checksums - the statement journal does ** not. ** ** If the page number of the page record read from the (sub-)journal file ** is greater than the current value of Pager.dbSize, then playback is ** skipped and SQLITE_OK is returned. ** ** If pDone is not NULL, then it is a record of pages that have already ** been played back. If the page at *pOffset has already been played back ** (if the corresponding pDone bit is set) then skip the playback. ** Make sure the pDone bit corresponding to the *pOffset page is set ** prior to returning. ** ** If the page record is successfully read from the (sub-)journal file ** and played back, then SQLITE_OK is returned. If an IO error occurs ** while reading the record from the (sub-)journal file or while writing ** to the database file, then the IO error code is returned. If data ** is successfully read from the (sub-)journal file but appears to be ** corrupted, SQLITE_DONE is returned. Data is considered corrupted in ** two circumstances: ** ** * If the record page-number is illegal (0 or PAGER_SJ_PGNO), or ** * If the record is being rolled back from the main journal file ** and the checksum field does not match the record content. ** ** Neither of these two scenarios are possible during a savepoint rollback. ** ** If this is a savepoint rollback, then memory may have to be dynamically ** allocated by this function. If this is the case and an allocation fails, ** SQLITE_NOMEM is returned. */ static int pager_playback_one_page( Pager *pPager, /* The pager being played back */ i64 *pOffset, /* Offset of record to playback */ Bitvec *pDone, /* Bitvec of pages already played back */ int isMainJrnl, /* 1 -> main journal. 0 -> sub-journal. */ int isSavepnt /* True for a savepoint rollback */ ){ int rc; PgHdr *pPg; /* An existing page in the cache */ Pgno pgno; /* The page number of a page in journal */ u32 cksum; /* Checksum used for sanity checking */ char *aData; /* Temporary storage for the page */ sqlite3_file *jfd; /* The file descriptor for the journal file */ int isSynced; /* True if journal page is synced */ assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ assert( isMainJrnl || pDone ); /* pDone always used on sub-journals */ assert( isSavepnt || pDone==0 ); /* pDone never used on non-savepoint */ aData = pPager->pTmpSpace; assert( aData ); /* Temp storage must have already been allocated */ assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) ); /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction ** or savepoint rollback done at the request of the caller) or this is ** a hot-journal rollback. If it is a hot-journal rollback, the pager ** is in state OPEN and holds an EXCLUSIVE lock. Hot-journal rollback ** only reads from the main journal, not the sub-journal. */ assert( pPager->eState>=PAGER_WRITER_CACHEMOD || (pPager->eState==PAGER_OPEN && pPager->eLock==EXCLUSIVE_LOCK) ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD || isMainJrnl ); /* Read the page number and page data from the journal or sub-journal ** file. Return an error code to the caller if an IO error occurs. */ jfd = isMainJrnl ? pPager->jfd : pPager->sjfd; rc = read32bits(jfd, *pOffset, &pgno); if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsRead(jfd, (u8*)aData, pPager->pageSize, (*pOffset)+4); if( rc!=SQLITE_OK ) return rc; *pOffset += pPager->pageSize + 4 + isMainJrnl*4; /* Sanity checking on the page. This is more important that I originally ** thought. If a power failure occurs while the journal is being written, ** it could cause invalid data to be written into the journal. We need to ** detect this invalid data (with high probability) and ignore it. */ if( pgno==0 || pgno==PAGER_SJ_PGNO(pPager) ){ assert( !isSavepnt ); return SQLITE_DONE; } if( pgno>(Pgno)pPager->dbSize || sqlite3BitvecTest(pDone, pgno) ){ return SQLITE_OK; } if( isMainJrnl ){ rc = read32bits(jfd, (*pOffset)-4, &cksum); if( rc ) return rc; if( !isSavepnt && pager_cksum(pPager, (u8*)aData)!=cksum ){ return SQLITE_DONE; } } /* If this page has already been played back before during the current ** rollback, then don't bother to play it back again. */ if( pDone && (rc = sqlite3BitvecSet(pDone, pgno))!=SQLITE_OK ){ return rc; } /* When playing back page 1, restore the nReserve setting */ if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){ pPager->nReserve = ((u8*)aData)[20]; } /* If the pager is in CACHEMOD state, then there must be a copy of this ** page in the pager cache. In this case just update the pager cache, ** not the database file. The page is left marked dirty in this case. ** ** An exception to the above rule: If the database is in no-sync mode ** and a page is moved during an incremental vacuum then the page may ** not be in the pager cache. Later: if a malloc() or IO error occurs ** during a Movepage() call, then the page may not be in the cache ** either. So the condition described in the above paragraph is not ** assert()able. ** ** If in WRITER_DBMOD, WRITER_FINISHED or OPEN state, then we update the ** pager cache if it exists and the main file. The page is then marked ** not dirty. Since this code is only executed in PAGER_OPEN state for ** a hot-journal rollback, it is guaranteed that the page-cache is empty ** if the pager is in OPEN state. ** ** Ticket #1171: The statement journal might contain page content that is ** different from the page content at the start of the transaction. ** This occurs when a page is changed prior to the start of a statement ** then changed again within the statement. When rolling back such a ** statement we must not write to the original database unless we know ** for certain that original page contents are synced into the main rollback ** journal. Otherwise, a power loss might leave modified data in the ** database file without an entry in the rollback journal that can ** restore the database to its original form. Two conditions must be ** met before writing to the database files. (1) the database must be ** locked. (2) we know that the original page content is fully synced ** in the main journal either because the page is not in cache or else ** the page is marked as needSync==0. ** ** 2008-04-14: When attempting to vacuum a corrupt database file, it ** is possible to fail a statement on a database that does not yet exist. ** Do not attempt to write if database file has never been opened. */ if( pagerUseWal(pPager) ){ pPg = 0; }else{ pPg = sqlite3PagerLookup(pPager, pgno); } assert( pPg || !MEMDB ); assert( pPager->eState!=PAGER_OPEN || pPg==0 || pPager->tempFile ); PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n", PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData), (isMainJrnl?"main-journal":"sub-journal") )); if( isMainJrnl ){ isSynced = pPager->noSync || (*pOffset <= pPager->journalHdr); }else{ isSynced = (pPg==0 || 0==(pPg->flags & PGHDR_NEED_SYNC)); } if( isOpen(pPager->fd) && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) && isSynced ){ i64 ofst = (pgno-1)*(i64)pPager->pageSize; testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 ); assert( !pagerUseWal(pPager) ); /* Write the data read from the journal back into the database file. ** This is usually safe even for an encrypted database - as the data ** was encrypted before it was written to the journal file. The exception ** is if the data was just read from an in-memory sub-journal. In that ** case it must be encrypted here before it is copied into the database ** file. */ rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } if( pPager->pBackup ){ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); } }else if( !isMainJrnl && pPg==0 ){ /* If this is a rollback of a savepoint and data was not written to ** the database and the page is not in-memory, there is a potential ** problem. When the page is next fetched by the b-tree layer, it ** will be read from the database file, which may or may not be ** current. ** ** There are a couple of different ways this can happen. All are quite ** obscure. When running in synchronous mode, this can only happen ** if the page is on the free-list at the start of the transaction, then ** populated, then moved using sqlite3PagerMovepage(). ** ** The solution is to add an in-memory page to the cache containing ** the data just read from the sub-journal. Mark the page as dirty ** and if the pager requires a journal-sync, then mark the page as ** requiring a journal-sync before it is written. */ assert( isSavepnt ); assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 ); pPager->doNotSpill |= SPILLFLAG_ROLLBACK; rc = sqlite3PagerGet(pPager, pgno, &pPg, 1); assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 ); pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK; if( rc!=SQLITE_OK ) return rc; sqlite3PcacheMakeDirty(pPg); } if( pPg ){ /* No page should ever be explicitly rolled back that is in use, except ** for page 1 which is held in use in order to keep the lock on the ** database active. However such a page may be rolled back as a result ** of an internal error resulting in an automatic call to ** sqlite3PagerRollback(). */ void *pData; pData = pPg->pData; memcpy(pData, (u8*)aData, pPager->pageSize); pPager->xReiniter(pPg); /* It used to be that sqlite3PcacheMakeClean(pPg) was called here. But ** that call was dangerous and had no detectable benefit since the cache ** is normally cleaned by sqlite3PcacheCleanAll() after rollback and so ** has been removed. */ pager_set_pagehash(pPg); /* If this was page 1, then restore the value of Pager.dbFileVers. ** Do this before any decoding. */ if( pgno==1 ){ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); } sqlite3PcacheRelease(pPg); } return rc; } /* ** Parameter zSuper is the name of a super-journal file. A single journal ** file that referred to the super-journal file has just been rolled back. ** This routine checks if it is possible to delete the super-journal file, ** and does so if it is. ** ** Argument zSuper may point to Pager.pTmpSpace. So that buffer is not ** available for use within this function. ** ** When a super-journal file is created, it is populated with the names ** of all of its child journals, one after another, formatted as utf-8 ** encoded text. The end of each child journal file is marked with a ** nul-terminator byte (0x00). i.e. the entire contents of a super-journal ** file for a transaction involving two databases might be: ** ** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00" ** ** A super-journal file may only be deleted once all of its child ** journals have been rolled back. ** ** This function reads the contents of the super-journal file into ** memory and loops through each of the child journal names. For ** each child journal, it checks if: ** ** * if the child journal exists, and if so ** * if the child journal contains a reference to super-journal ** file zSuper ** ** If a child journal can be found that matches both of the criteria ** above, this function returns without doing anything. Otherwise, if ** no such child journal can be found, file zSuper is deleted from ** the file-system using sqlite3OsDelete(). ** ** If an IO error within this function, an error code is returned. This ** function allocates memory by calling sqlite3Malloc(). If an allocation ** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors ** occur, SQLITE_OK is returned. ** ** TODO: This function allocates a single block of memory to load ** the entire contents of the super-journal file. This could be ** a couple of kilobytes or so - potentially larger than the page ** size. */ static int pager_delsuper(Pager *pPager, const char *zSuper){ sqlite3_vfs *pVfs = pPager->pVfs; int rc; /* Return code */ sqlite3_file *pSuper; /* Malloc'd super-journal file descriptor */ sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */ char *zSuperJournal = 0; /* Contents of super-journal file */ i64 nSuperJournal; /* Size of super-journal file */ char *zJournal; /* Pointer to one journal within MJ file */ char *zSuperPtr; /* Space to hold super-journal filename */ char *zFree = 0; /* Free this buffer */ int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */ /* Allocate space for both the pJournal and pSuper file descriptors. ** If successful, open the super-journal file for reading. */ pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2); if( !pSuper ){ rc = SQLITE_NOMEM_BKPT; pJournal = 0; }else{ const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL); rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0); pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile); } if( rc!=SQLITE_OK ) goto delsuper_out; /* Load the entire super-journal file into space obtained from ** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain ** sufficient space (in zSuperPtr) to hold the names of super-journal ** files extracted from regular rollback-journals. */ rc = sqlite3OsFileSize(pSuper, &nSuperJournal); if( rc!=SQLITE_OK ) goto delsuper_out; nSuperPtr = pVfs->mxPathname+1; zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2); if( !zFree ){ rc = SQLITE_NOMEM_BKPT; goto delsuper_out; } zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0; zSuperJournal = &zFree[4]; zSuperPtr = &zSuperJournal[nSuperJournal+2]; rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0); if( rc!=SQLITE_OK ) goto delsuper_out; zSuperJournal[nSuperJournal] = 0; zSuperJournal[nSuperJournal+1] = 0; zJournal = zSuperJournal; while( (zJournal-zSuperJournal)pageSize bytes). ** If the file on disk is currently larger than nPage pages, then use the VFS ** xTruncate() method to truncate it. ** ** Or, it might be the case that the file on disk is smaller than ** nPage pages. Some operating system implementations can get confused if ** you try to truncate a file to some size that is larger than it ** currently is, so detect this case and write a single zero byte to ** the end of the new file instead. ** ** If successful, return SQLITE_OK. If an IO error occurs while modifying ** the database file, return the error code to the caller. */ static int pager_truncate(Pager *pPager, Pgno nPage){ int rc = SQLITE_OK; assert( pPager->eState!=PAGER_ERROR ); assert( pPager->eState!=PAGER_READER ); PAGERTRACE(("Truncate %d npage %u\n", PAGERID(pPager), nPage)); if( isOpen(pPager->fd) && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) ){ i64 currentSize, newSize; int szPage = pPager->pageSize; assert( pPager->eLock==EXCLUSIVE_LOCK ); /* TODO: Is it safe to use Pager.dbFileSize here? */ rc = sqlite3OsFileSize(pPager->fd, ¤tSize); newSize = szPage*(i64)nPage; if( rc==SQLITE_OK && currentSize!=newSize ){ if( currentSize>newSize ){ rc = sqlite3OsTruncate(pPager->fd, newSize); }else if( (currentSize+szPage)<=newSize ){ char *pTmp = pPager->pTmpSpace; memset(pTmp, 0, szPage); testcase( (newSize-szPage) == currentSize ); testcase( (newSize-szPage) > currentSize ); sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &newSize); rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage); } if( rc==SQLITE_OK ){ pPager->dbFileSize = nPage; } } } return rc; } /* ** Return a sanitized version of the sector-size of OS file pFile. The ** return value is guaranteed to lie between 32 and MAX_SECTOR_SIZE. */ SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *pFile){ int iRet = sqlite3OsSectorSize(pFile); if( iRet<32 ){ iRet = 512; }else if( iRet>MAX_SECTOR_SIZE ){ assert( MAX_SECTOR_SIZE>=512 ); iRet = MAX_SECTOR_SIZE; } return iRet; } /* ** Set the value of the Pager.sectorSize variable for the given ** pager based on the value returned by the xSectorSize method ** of the open database file. The sector size will be used ** to determine the size and alignment of journal header and ** super-journal pointers within created journal files. ** ** For temporary files the effective sector size is always 512 bytes. ** ** Otherwise, for non-temporary files, the effective sector size is ** the value returned by the xSectorSize() method rounded up to 32 if ** it is less than 32, or rounded down to MAX_SECTOR_SIZE if it ** is greater than MAX_SECTOR_SIZE. ** ** If the file has the SQLITE_IOCAP_POWERSAFE_OVERWRITE property, then set ** the effective sector size to its minimum value (512). The purpose of ** pPager->sectorSize is to define the "blast radius" of bytes that ** might change if a crash occurs while writing to a single byte in ** that range. But with POWERSAFE_OVERWRITE, the blast radius is zero ** (that is what POWERSAFE_OVERWRITE means), so we minimize the sector ** size. For backwards compatibility of the rollback journal file format, ** we cannot reduce the effective sector size below 512. */ static void setSectorSize(Pager *pPager){ assert( isOpen(pPager->fd) || pPager->tempFile ); if( pPager->tempFile || (sqlite3OsDeviceCharacteristics(pPager->fd) & SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0 ){ /* Sector size doesn't matter for temporary files. Also, the file ** may not have been opened yet, in which case the OsSectorSize() ** call will segfault. */ pPager->sectorSize = 512; }else{ pPager->sectorSize = sqlite3SectorSize(pPager->fd); } } /* ** Playback the journal and thus restore the database file to ** the state it was in before we started making changes. ** ** The journal file format is as follows: ** ** (1) 8 byte prefix. A copy of aJournalMagic[]. ** (2) 4 byte big-endian integer which is the number of valid page records ** in the journal. If this value is 0xffffffff, then compute the ** number of page records from the journal size. ** (3) 4 byte big-endian integer which is the initial value for the ** sanity checksum. ** (4) 4 byte integer which is the number of pages to truncate the ** database to during a rollback. ** (5) 4 byte big-endian integer which is the sector size. The header ** is this many bytes in size. ** (6) 4 byte big-endian integer which is the page size. ** (7) zero padding out to the next sector size. ** (8) Zero or more pages instances, each as follows: ** + 4 byte page number. ** + pPager->pageSize bytes of data. ** + 4 byte checksum ** ** When we speak of the journal header, we mean the first 7 items above. ** Each entry in the journal is an instance of the 8th item. ** ** Call the value from the second bullet "nRec". nRec is the number of ** valid page entries in the journal. In most cases, you can compute the ** value of nRec from the size of the journal file. But if a power ** failure occurred while the journal was being written, it could be the ** case that the size of the journal file had already been increased but ** the extra entries had not yet made it safely to disk. In such a case, ** the value of nRec computed from the file size would be too large. For ** that reason, we always use the nRec value in the header. ** ** If the nRec value is 0xffffffff it means that nRec should be computed ** from the file size. This value is used when the user selects the ** no-sync option for the journal. A power failure could lead to corruption ** in this case. But for things like temporary table (which will be ** deleted when the power is restored) we don't care. ** ** If the file opened as the journal file is not a well-formed ** journal file then all pages up to the first corrupted page are rolled ** back (or no pages if the journal header is corrupted). The journal file ** is then deleted and SQLITE_OK returned, just as if no corruption had ** been encountered. ** ** If an I/O or malloc() error occurs, the journal-file is not deleted ** and an error code is returned. ** ** The isHot parameter indicates that we are trying to rollback a journal ** that might be a hot journal. Or, it could be that the journal is ** preserved because of JOURNALMODE_PERSIST or JOURNALMODE_TRUNCATE. ** If the journal really is hot, reset the pager cache prior rolling ** back any content. If the journal is merely persistent, no reset is ** needed. */ static int pager_playback(Pager *pPager, int isHot){ sqlite3_vfs *pVfs = pPager->pVfs; i64 szJ; /* Size of the journal file in bytes */ u32 nRec; /* Number of Records in the journal */ u32 u; /* Unsigned loop counter */ Pgno mxPg = 0; /* Size of the original file in pages */ int rc; /* Result code of a subroutine */ int res = 1; /* Value returned by sqlite3OsAccess() */ char *zSuper = 0; /* Name of super-journal file if any */ int needPagerReset; /* True to reset page prior to first page rollback */ int nPlayback = 0; /* Total number of pages restored from journal */ u32 savedPageSize = pPager->pageSize; /* Figure out how many records are in the journal. Abort early if ** the journal is empty. */ assert( isOpen(pPager->jfd) ); rc = sqlite3OsFileSize(pPager->jfd, &szJ); if( rc!=SQLITE_OK ){ goto end_playback; } /* Read the super-journal name from the journal, if it is present. ** If a super-journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. ** ** TODO: Technically the following is an error because it assumes that ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c, ** mxPathname is 512, which is the same as the minimum allowable value ** for pageSize. */ zSuper = pPager->pTmpSpace; rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); if( rc==SQLITE_OK && zSuper[0] ){ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); } zSuper = 0; if( rc!=SQLITE_OK || !res ){ goto end_playback; } pPager->journalOff = 0; needPagerReset = isHot; /* This loop terminates either when a readJournalHdr() or ** pager_playback_one_page() call returns SQLITE_DONE or an IO error ** occurs. */ while( 1 ){ /* Read the next journal header from the journal file. If there are ** not enough bytes left in the journal file for a complete header, or ** it is corrupted, then a process must have failed while writing it. ** This indicates nothing more needs to be rolled back. */ rc = readJournalHdr(pPager, isHot, szJ, &nRec, &mxPg); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; } goto end_playback; } /* If nRec is 0xffffffff, then this journal was created by a process ** working in no-sync mode. This means that the rest of the journal ** file consists of pages, there are no more journal headers. Compute ** the value of nRec based on this assumption. */ if( nRec==0xffffffff ){ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ); nRec = (int)((szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager)); } /* If nRec is 0 and this rollback is of a transaction created by this ** process and if this is the final header in the journal, then it means ** that this part of the journal was being filled but has not yet been ** synced to disk. Compute the number of pages based on the remaining ** size of the file. ** ** The third term of the test was added to fix ticket #2565. ** When rolling back a hot journal, nRec==0 always means that the next ** chunk of the journal contains zero pages to be rolled back. But ** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in ** the journal, it means that the journal might contain additional ** pages that need to be rolled back and that the number of pages ** should be computed based on the journal file size. */ if( nRec==0 && !isHot && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){ nRec = (int)((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager)); } /* If this is the first header read from the journal, truncate the ** database file back to its original size. */ if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){ rc = pager_truncate(pPager, mxPg); if( rc!=SQLITE_OK ){ goto end_playback; } pPager->dbSize = mxPg; if( pPager->mxPgnomxPgno = mxPg; } } /* Copy original pages out of the journal and back into the ** database file and/or page cache. */ for(u=0; ujournalOff,0,1,0); if( rc==SQLITE_OK ){ nPlayback++; }else{ if( rc==SQLITE_DONE ){ pPager->journalOff = szJ; break; }else if( rc==SQLITE_IOERR_SHORT_READ ){ /* If the journal has been truncated, simply stop reading and ** processing the journal. This might happen if the journal was ** not completely written and synced prior to a crash. In that ** case, the database should have never been written in the ** first place so it is OK to simply abandon the rollback. */ rc = SQLITE_OK; goto end_playback; }else{ /* If we are unable to rollback, quit and return the error ** code. This will cause the pager to enter the error state ** so that no further harm will be done. Perhaps the next ** process to come along will be able to rollback the database. */ goto end_playback; } } } } /*NOTREACHED*/ assert( 0 ); end_playback: if( rc==SQLITE_OK ){ rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1); } /* Following a rollback, the database file should be back in its original ** state prior to the start of the transaction, so invoke the ** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the ** assertion that the transaction counter was modified. */ #ifdef SQLITE_DEBUG sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0); #endif /* If this playback is happening automatically as a result of an IO or ** malloc error that occurred after the change-counter was updated but ** before the transaction was committed, then the change-counter ** modification may just have been reverted. If this happens in exclusive ** mode, then subsequent transactions performed by the connection will not ** update the change-counter at all. This may lead to cache inconsistency ** problems for other processes at some point in the future. So, just ** in case this has happened, clear the changeCountDone flag now. */ pPager->changeCountDone = pPager->tempFile; if( rc==SQLITE_OK ){ /* Leave 4 bytes of space before the super-journal filename in memory. ** This is because it may end up being passed to sqlite3OsOpen(), in ** which case it requires 4 0x00 bytes in memory immediately before ** the filename. */ zSuper = &pPager->pTmpSpace[4]; rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); testcase( rc!=SQLITE_OK ); } if( rc==SQLITE_OK && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) ){ rc = sqlite3PagerSync(pPager, 0); } if( rc==SQLITE_OK ){ rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0); testcase( rc!=SQLITE_OK ); } if( rc==SQLITE_OK && zSuper[0] && res ){ /* If there was a super-journal and this routine will return success, ** see if it is possible to delete the super-journal. */ assert( zSuper==&pPager->pTmpSpace[4] ); memset(pPager->pTmpSpace, 0, 4); rc = pager_delsuper(pPager, zSuper); testcase( rc!=SQLITE_OK ); } if( isHot && nPlayback ){ sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s", nPlayback, pPager->zJournal); } /* The Pager.sectorSize variable may have been updated while rolling ** back a journal created by a process with a different sector size ** value. Reset it to the correct value for this process. */ setSectorSize(pPager); return rc; } /* ** Read the content for page pPg out of the database file (or out of ** the WAL if that is where the most recent copy if found) into ** pPg->pData. A shared lock or greater must be held on the database ** file before this function is called. ** ** If page 1 is read, then the value of Pager.dbFileVers[] is set to ** the value read from the database file. ** ** If an IO error occurs, then the IO error is returned to the caller. ** Otherwise, SQLITE_OK is returned. */ static int readDbPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */ int rc = SQLITE_OK; /* Return code */ #ifndef SQLITE_OMIT_WAL u32 iFrame = 0; /* Frame of WAL containing pgno */ assert( pPager->eState>=PAGER_READER && !MEMDB ); assert( isOpen(pPager->fd) ); if( pagerUseWal(pPager) ){ rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); if( rc ) return rc; } if( iFrame ){ rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData); }else #endif { i64 iOffset = (pPg->pgno-1)*(i64)pPager->pageSize; rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } } if( pPg->pgno==1 ){ if( rc ){ /* If the read is unsuccessful, set the dbFileVers[] to something ** that will never be a valid file version. dbFileVers[] is a copy ** of bytes 24..39 of the database. Bytes 28..31 should always be ** zero or the size of the database in page. Bytes 32..35 and 35..39 ** should be page numbers which are never 0xffffffff. So filling ** pPager->dbFileVers[] with all 0xff bytes should suffice. ** ** For an encrypted database, the situation is more complex: bytes ** 24..39 of the database are white noise. But the probability of ** white noise equaling 16 bytes of 0xff is vanishingly small so ** we should still be ok. */ memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers)); }else{ u8 *dbFileVers = &((u8*)pPg->pData)[24]; memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); } } PAGER_INCR(sqlite3_pager_readdb_count); PAGER_INCR(pPager->nRead); IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); PAGERTRACE(("FETCH %d page %d hash(%08x)\n", PAGERID(pPager), pPg->pgno, pager_pagehash(pPg))); return rc; } /* ** Update the value of the change-counter at offsets 24 and 92 in ** the header and the sqlite version number at offset 96. ** ** This is an unconditional update. See also the pager_incr_changecounter() ** routine which only updates the change-counter if the update is actually ** needed, as determined by the pPager->changeCountDone state variable. */ static void pager_write_changecounter(PgHdr *pPg){ u32 change_counter; if( NEVER(pPg==0) ) return; /* Increment the value just read and write it back to byte 24. */ change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1; put32bits(((char*)pPg->pData)+24, change_counter); /* Also store the SQLite version number in bytes 96..99 and in ** bytes 92..95 store the change counter for which the version number ** is valid. */ put32bits(((char*)pPg->pData)+92, change_counter); put32bits(((char*)pPg->pData)+96, SQLITE_VERSION_NUMBER); } #ifndef SQLITE_OMIT_WAL /* ** This function is invoked once for each page that has already been ** written into the log file when a WAL transaction is rolled back. ** Parameter iPg is the page number of said page. The pCtx argument ** is actually a pointer to the Pager structure. ** ** If page iPg is present in the cache, and has no outstanding references, ** it is discarded. Otherwise, if there are one or more outstanding ** references, the page content is reloaded from the database. If the ** attempt to reload content from the database is required and fails, ** return an SQLite error code. Otherwise, SQLITE_OK. */ static int pagerUndoCallback(void *pCtx, Pgno iPg){ int rc = SQLITE_OK; Pager *pPager = (Pager *)pCtx; PgHdr *pPg; assert( pagerUseWal(pPager) ); pPg = sqlite3PagerLookup(pPager, iPg); if( pPg ){ if( sqlite3PcachePageRefcount(pPg)==1 ){ sqlite3PcacheDrop(pPg); }else{ rc = readDbPage(pPg); if( rc==SQLITE_OK ){ pPager->xReiniter(pPg); } sqlite3PagerUnrefNotNull(pPg); } } /* Normally, if a transaction is rolled back, any backup processes are ** updated as data is copied out of the rollback journal and into the ** database. This is not generally possible with a WAL database, as ** rollback involves simply truncating the log file. Therefore, if one ** or more frames have already been written to the log (and therefore ** also copied into the backup databases) as part of this transaction, ** the backups must be restarted. */ sqlite3BackupRestart(pPager->pBackup); return rc; } /* ** This function is called to rollback a transaction on a WAL database. */ static int pagerRollbackWal(Pager *pPager){ int rc; /* Return Code */ PgHdr *pList; /* List of dirty pages to revert */ /* For all pages in the cache that are currently dirty or have already ** been written (but not committed) to the log file, do one of the ** following: ** ** + Discard the cached page (if refcount==0), or ** + Reload page content from the database (if refcount>0). */ pPager->dbSize = pPager->dbOrigSize; rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager); pList = sqlite3PcacheDirtyList(pPager->pPCache); while( pList && rc==SQLITE_OK ){ PgHdr *pNext = pList->pDirty; rc = pagerUndoCallback((void *)pPager, pList->pgno); pList = pNext; } return rc; } /* ** This function is a wrapper around sqlite3WalFrames(). As well as logging ** the contents of the list of pages headed by pList (connected by pDirty), ** this function notifies any active backup processes that the pages have ** changed. ** ** The list of pages passed into this routine is always sorted by page number. ** Hence, if page 1 appears anywhere on the list, it will be the first page. */ static int pagerWalFrames( Pager *pPager, /* Pager object */ PgHdr *pList, /* List of frames to log */ Pgno nTruncate, /* Database size after this commit */ int isCommit /* True if this is a commit */ ){ int rc; /* Return code */ int nList; /* Number of pages in pList */ PgHdr *p; /* For looping over pages */ assert( pPager->pWal ); assert( pList ); #ifdef SQLITE_DEBUG /* Verify that the page list is in ascending order */ for(p=pList; p && p->pDirty; p=p->pDirty){ assert( p->pgno < p->pDirty->pgno ); } #endif assert( pList->pDirty==0 || isCommit ); if( isCommit ){ /* If a WAL transaction is being committed, there is no point in writing ** any pages with page numbers greater than nTruncate into the WAL file. ** They will never be read by any client. So remove them from the pDirty ** list here. */ PgHdr **ppNext = &pList; nList = 0; for(p=pList; (*ppNext = p)!=0; p=p->pDirty){ if( p->pgno<=nTruncate ){ ppNext = &p->pDirty; nList++; } } assert( pList ); }else{ nList = 1; } pPager->aStat[PAGER_STAT_WRITE] += nList; if( pList->pgno==1 ) pager_write_changecounter(pList); rc = sqlite3WalFrames(pPager->pWal, pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags ); if( rc==SQLITE_OK && pPager->pBackup ){ for(p=pList; p; p=p->pDirty){ sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData); } } #ifdef SQLITE_CHECK_PAGES pList = sqlite3PcacheDirtyList(pPager->pPCache); for(p=pList; p; p=p->pDirty){ pager_set_pagehash(p); } #endif return rc; } /* ** Begin a read transaction on the WAL. ** ** This routine used to be called "pagerOpenSnapshot()" because it essentially ** makes a snapshot of the database at the current point in time and preserves ** that snapshot for use by the reader in spite of concurrently changes by ** other writers or checkpointers. */ static int pagerBeginReadTransaction(Pager *pPager){ int rc; /* Return code */ int changed = 0; /* True if cache must be reset */ assert( pagerUseWal(pPager) ); assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER ); /* sqlite3WalEndReadTransaction() was not called for the previous ** transaction in locking_mode=EXCLUSIVE. So call it now. If we ** are in locking_mode=NORMAL and EndRead() was previously called, ** the duplicate call is harmless. */ sqlite3WalEndReadTransaction(pPager->pWal); rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); if( rc!=SQLITE_OK || changed ){ pager_reset(pPager); if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); } return rc; } #endif /* ** This function is called as part of the transition from PAGER_OPEN ** to PAGER_READER state to determine the size of the database file ** in pages (assuming the page size currently stored in Pager.pageSize). ** ** If no error occurs, SQLITE_OK is returned and the size of the database ** in pages is stored in *pnPage. Otherwise, an error code (perhaps ** SQLITE_IOERR_FSTAT) is returned and *pnPage is left unmodified. */ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ Pgno nPage; /* Value to return via *pnPage */ /* Query the WAL sub-system for the database size. The WalDbsize() ** function returns zero if the WAL is not open (i.e. Pager.pWal==0), or ** if the database size is not available. The database size is not ** available from the WAL sub-system if the log file is empty or ** contains no valid committed transactions. */ assert( pPager->eState==PAGER_OPEN ); assert( pPager->eLock>=SHARED_LOCK ); assert( isOpen(pPager->fd) ); assert( pPager->tempFile==0 ); nPage = sqlite3WalDbsize(pPager->pWal); /* If the number of pages in the database is not available from the ** WAL sub-system, determine the page count based on the size of ** the database file. If the size of the database file is not an ** integer multiple of the page-size, round up the result. */ if( nPage==0 && ALWAYS(isOpen(pPager->fd)) ){ i64 n = 0; /* Size of db file in bytes */ int rc = sqlite3OsFileSize(pPager->fd, &n); if( rc!=SQLITE_OK ){ return rc; } nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize); } /* If the current number of pages in the file is greater than the ** configured maximum pager number, increase the allowed limit so ** that the file can be read. */ if( nPage>pPager->mxPgno ){ pPager->mxPgno = (Pgno)nPage; } *pnPage = nPage; return SQLITE_OK; } #ifndef SQLITE_OMIT_WAL /* ** Check if the *-wal file that corresponds to the database opened by pPager ** exists if the database is not empty, or verify that the *-wal file does ** not exist (by deleting it) if the database file is empty. ** ** If the database is not empty and the *-wal file exists, open the pager ** in WAL mode. If the database is empty or if no *-wal file exists and ** if no error occurs, make sure Pager.journalMode is not set to ** PAGER_JOURNALMODE_WAL. ** ** Return SQLITE_OK or an error code. ** ** The caller must hold a SHARED lock on the database file to call this ** function. Because an EXCLUSIVE lock on the db file is required to delete ** a WAL on a none-empty database, this ensures there is no race condition ** between the xAccess() below and an xDelete() being executed by some ** other connection. */ static int pagerOpenWalIfPresent(Pager *pPager){ int rc = SQLITE_OK; assert( pPager->eState==PAGER_OPEN ); assert( pPager->eLock>=SHARED_LOCK ); if( !pPager->tempFile ){ int isWal; /* True if WAL file exists */ rc = sqlite3OsAccess( pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal ); if( rc==SQLITE_OK ){ if( isWal ){ Pgno nPage; /* Size of the database file */ rc = pagerPagecount(pPager, &nPage); if( rc ) return rc; if( nPage==0 ){ rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); }else{ testcase( sqlite3PcachePagecount(pPager->pPCache)==0 ); rc = sqlite3PagerOpenWal(pPager, 0); } }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){ pPager->journalMode = PAGER_JOURNALMODE_DELETE; } } } return rc; } #endif /* ** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback ** the entire super-journal file. The case pSavepoint==NULL occurs when ** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction ** savepoint. ** ** When pSavepoint is not NULL (meaning a non-transaction savepoint is ** being rolled back), then the rollback consists of up to three stages, ** performed in the order specified: ** ** * Pages are played back from the main journal starting at byte ** offset PagerSavepoint.iOffset and continuing to ** PagerSavepoint.iHdrOffset, or to the end of the main journal ** file if PagerSavepoint.iHdrOffset is zero. ** ** * If PagerSavepoint.iHdrOffset is not zero, then pages are played ** back starting from the journal header immediately following ** PagerSavepoint.iHdrOffset to the end of the main journal file. ** ** * Pages are then played back from the sub-journal file, starting ** with the PagerSavepoint.iSubRec and continuing to the end of ** the journal file. ** ** Throughout the rollback process, each time a page is rolled back, the ** corresponding bit is set in a bitvec structure (variable pDone in the ** implementation below). This is used to ensure that a page is only ** rolled back the first time it is encountered in either journal. ** ** If pSavepoint is NULL, then pages are only played back from the main ** journal file. There is no need for a bitvec in this case. ** ** In either case, before playback commences the Pager.dbSize variable ** is reset to the value that it held at the start of the savepoint ** (or transaction). No page with a page-number greater than this value ** is played back. If one is encountered it is simply skipped. */ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){ i64 szJ; /* Effective size of the main journal */ i64 iHdrOff; /* End of first segment of main-journal records */ int rc = SQLITE_OK; /* Return code */ Bitvec *pDone = 0; /* Bitvec to ensure pages played back only once */ assert( pPager->eState!=PAGER_ERROR ); assert( pPager->eState>=PAGER_WRITER_LOCKED ); /* Allocate a bitvec to use to store the set of pages rolled back */ if( pSavepoint ){ pDone = sqlite3BitvecCreate(pSavepoint->nOrig); if( !pDone ){ return SQLITE_NOMEM_BKPT; } } /* Set the database size back to the value it was before the savepoint ** being reverted was opened. */ pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize; pPager->changeCountDone = pPager->tempFile; if( !pSavepoint && pagerUseWal(pPager) ){ return pagerRollbackWal(pPager); } /* Use pPager->journalOff as the effective size of the main rollback ** journal. The actual file might be larger than this in ** PAGER_JOURNALMODE_TRUNCATE or PAGER_JOURNALMODE_PERSIST. But anything ** past pPager->journalOff is off-limits to us. */ szJ = pPager->journalOff; assert( pagerUseWal(pPager)==0 || szJ==0 ); /* Begin by rolling back records from the main journal starting at ** PagerSavepoint.iOffset and continuing to the next journal header. ** There might be records in the main journal that have a page number ** greater than the current database size (pPager->dbSize) but those ** will be skipped automatically. Pages are added to pDone as they ** are played back. */ if( pSavepoint && !pagerUseWal(pPager) ){ iHdrOff = pSavepoint->iHdrOffset ? pSavepoint->iHdrOffset : szJ; pPager->journalOff = pSavepoint->iOffset; while( rc==SQLITE_OK && pPager->journalOffjournalOff, pDone, 1, 1); } assert( rc!=SQLITE_DONE ); }else{ pPager->journalOff = 0; } /* Continue rolling back records out of the main journal starting at ** the first journal header seen and continuing until the effective end ** of the main journal file. Continue to skip out-of-range pages and ** continue adding pages rolled back to pDone. */ while( rc==SQLITE_OK && pPager->journalOffjournalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff" ** test is related to ticket #2565. See the discussion in the ** pager_playback() function for additional information. */ if( nJRec==0 && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){ nJRec = (u32)((szJ - pPager->journalOff)/JOURNAL_PG_SZ(pPager)); } for(ii=0; rc==SQLITE_OK && iijournalOffjournalOff, pDone, 1, 1); } assert( rc!=SQLITE_DONE ); } assert( rc!=SQLITE_OK || pPager->journalOff>=szJ ); /* Finally, rollback pages from the sub-journal. Page that were ** previously rolled back out of the main journal (and are hence in pDone) ** will be skipped. Out-of-range pages are also skipped. */ if( pSavepoint ){ u32 ii; /* Loop counter */ i64 offset = (i64)pSavepoint->iSubRec*(4+pPager->pageSize); if( pagerUseWal(pPager) ){ rc = sqlite3WalSavepointUndo(pPager->pWal, pSavepoint->aWalData); } for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && iinSubRec; ii++){ assert( offset==(i64)ii*(4+pPager->pageSize) ); rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1); } assert( rc!=SQLITE_DONE ); } sqlite3BitvecDestroy(pDone); if( rc==SQLITE_OK ){ pPager->journalOff = szJ; } return rc; } /* ** Change the maximum number of in-memory pages that are allowed ** before attempting to recycle clean and unused pages. */ SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ sqlite3PcacheSetCachesize(pPager->pPCache, mxPage); } /* ** Change the maximum number of in-memory pages that are allowed ** before attempting to spill pages to journal. */ SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager *pPager, int mxPage){ return sqlite3PcacheSetSpillsize(pPager->pPCache, mxPage); } /* ** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap. */ static void pagerFixMaplimit(Pager *pPager){ #if SQLITE_MAX_MMAP_SIZE>0 sqlite3_file *fd = pPager->fd; if( isOpen(fd) && fd->pMethods->iVersion>=3 ){ sqlite3_int64 sz; sz = pPager->szMmap; pPager->bUseFetch = (sz>0); setGetterMethod(pPager); sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz); } #endif } /* ** Change the maximum size of any memory mapping made of the database file. */ SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 szMmap){ pPager->szMmap = szMmap; pagerFixMaplimit(pPager); } /* ** Free as much memory as possible from the pager. */ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){ sqlite3PcacheShrink(pPager->pPCache); } /* ** Adjust settings of the pager to those specified in the pgFlags parameter. ** ** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness ** of the database to damage due to OS crashes or power failures by ** changing the number of syncs()s when writing the journals. ** There are four levels: ** ** OFF sqlite3OsSync() is never called. This is the default ** for temporary and transient files. ** ** NORMAL The journal is synced once before writes begin on the ** database. This is normally adequate protection, but ** it is theoretically possible, though very unlikely, ** that an inopertune power failure could leave the journal ** in a state which would cause damage to the database ** when it is rolled back. ** ** FULL The journal is synced twice before writes begin on the ** database (with some additional information - the nRec field ** of the journal header - being written in between the two ** syncs). If we assume that writing a ** single disk sector is atomic, then this mode provides ** assurance that the journal will not be corrupted to the ** point of causing damage to the database during rollback. ** ** EXTRA This is like FULL except that is also syncs the directory ** that contains the rollback journal after the rollback ** journal is unlinked. ** ** The above is for a rollback-journal mode. For WAL mode, OFF continues ** to mean that no syncs ever occur. NORMAL means that the WAL is synced ** prior to the start of checkpoint and that the database file is synced ** at the conclusion of the checkpoint if the entire content of the WAL ** was written back into the database. But no sync operations occur for ** an ordinary commit in NORMAL mode with WAL. FULL means that the WAL ** file is synced following each commit operation, in addition to the ** syncs associated with NORMAL. There is no difference between FULL ** and EXTRA for WAL mode. ** ** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL. The ** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync ** using fcntl(F_FULLFSYNC). SQLITE_SYNC_NORMAL means to do an ** ordinary fsync() call. There is no difference between SQLITE_SYNC_FULL ** and SQLITE_SYNC_NORMAL on platforms other than MacOSX. But the ** synchronous=FULL versus synchronous=NORMAL setting determines when ** the xSync primitive is called and is relevant to all platforms. ** ** Numeric values associated with these states are OFF==1, NORMAL=2, ** and FULL=3. */ SQLITE_PRIVATE void sqlite3PagerSetFlags( Pager *pPager, /* The pager to set safety level for */ unsigned pgFlags /* Various flags */ ){ unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK; if( pPager->tempFile ){ pPager->noSync = 1; pPager->fullSync = 0; pPager->extraSync = 0; }else{ pPager->noSync = level==PAGER_SYNCHRONOUS_OFF ?1:0; pPager->fullSync = level>=PAGER_SYNCHRONOUS_FULL ?1:0; pPager->extraSync = level==PAGER_SYNCHRONOUS_EXTRA ?1:0; } if( pPager->noSync ){ pPager->syncFlags = 0; }else if( pgFlags & PAGER_FULLFSYNC ){ pPager->syncFlags = SQLITE_SYNC_FULL; }else{ pPager->syncFlags = SQLITE_SYNC_NORMAL; } pPager->walSyncFlags = (pPager->syncFlags<<2); if( pPager->fullSync ){ pPager->walSyncFlags |= pPager->syncFlags; } if( (pgFlags & PAGER_CKPT_FULLFSYNC) && !pPager->noSync ){ pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2); } if( pgFlags & PAGER_CACHESPILL ){ pPager->doNotSpill &= ~SPILLFLAG_OFF; }else{ pPager->doNotSpill |= SPILLFLAG_OFF; } } /* ** The following global variable is incremented whenever the library ** attempts to open a temporary file. This information is used for ** testing and analysis only. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_opentemp_count = 0; #endif /* ** Open a temporary file. ** ** Write the file descriptor into *pFile. Return SQLITE_OK on success ** or some other error code if we fail. The OS will automatically ** delete the temporary file when it is closed. ** ** The flags passed to the VFS layer xOpen() call are those specified ** by parameter vfsFlags ORed with the following: ** ** SQLITE_OPEN_READWRITE ** SQLITE_OPEN_CREATE ** SQLITE_OPEN_EXCLUSIVE ** SQLITE_OPEN_DELETEONCLOSE */ static int pagerOpentemp( Pager *pPager, /* The pager object */ sqlite3_file *pFile, /* Write the file descriptor here */ int vfsFlags /* Flags passed through to the VFS */ ){ int rc; /* Return code */ #ifdef SQLITE_TEST sqlite3_opentemp_count++; /* Used for testing and analysis only */ #endif vfsFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE; rc = sqlite3OsOpen(pPager->pVfs, 0, pFile, vfsFlags, 0); assert( rc!=SQLITE_OK || isOpen(pFile) ); return rc; } /* ** Set the busy handler function. ** ** The pager invokes the busy-handler if sqlite3OsLock() returns ** SQLITE_BUSY when trying to upgrade from no-lock to a SHARED lock, ** or when trying to upgrade from a RESERVED lock to an EXCLUSIVE ** lock. It does *not* invoke the busy handler when upgrading from ** SHARED to RESERVED, or when upgrading from SHARED to EXCLUSIVE ** (which occurs during hot-journal rollback). Summary: ** ** Transition | Invokes xBusyHandler ** -------------------------------------------------------- ** NO_LOCK -> SHARED_LOCK | Yes ** SHARED_LOCK -> RESERVED_LOCK | No ** SHARED_LOCK -> EXCLUSIVE_LOCK | No ** RESERVED_LOCK -> EXCLUSIVE_LOCK | Yes ** ** If the busy-handler callback returns non-zero, the lock is ** retried. If it returns zero, then the SQLITE_BUSY error is ** returned to the caller of the pager API function. */ SQLITE_PRIVATE void sqlite3PagerSetBusyHandler( Pager *pPager, /* Pager object */ int (*xBusyHandler)(void *), /* Pointer to busy-handler function */ void *pBusyHandlerArg /* Argument to pass to xBusyHandler */ ){ void **ap; pPager->xBusyHandler = xBusyHandler; pPager->pBusyHandlerArg = pBusyHandlerArg; ap = (void **)&pPager->xBusyHandler; assert( ((int(*)(void *))(ap[0]))==xBusyHandler ); assert( ap[1]==pBusyHandlerArg ); sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap); } /* ** Change the page size used by the Pager object. The new page size ** is passed in *pPageSize. ** ** If the pager is in the error state when this function is called, it ** is a no-op. The value returned is the error state error code (i.e. ** one of SQLITE_IOERR, an SQLITE_IOERR_xxx sub-code or SQLITE_FULL). ** ** Otherwise, if all of the following are true: ** ** * the new page size (value of *pPageSize) is valid (a power ** of two between 512 and SQLITE_MAX_PAGE_SIZE, inclusive), and ** ** * there are no outstanding page references, and ** ** * the database is either not an in-memory database or it is ** an in-memory database that currently consists of zero pages. ** ** then the pager object page size is set to *pPageSize. ** ** If the page size is changed, then this function uses sqlite3PagerMalloc() ** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt ** fails, SQLITE_NOMEM is returned and the page size remains unchanged. ** In all other cases, SQLITE_OK is returned. ** ** If the page size is not changed, either because one of the enumerated ** conditions above is not true, the pager was in error state when this ** function was called, or because the memory allocation attempt failed, ** then *pPageSize is set to the old, retained page size before returning. */ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){ int rc = SQLITE_OK; /* It is not possible to do a full assert_pager_state() here, as this ** function may be called from within PagerOpen(), before the state ** of the Pager object is internally consistent. ** ** At one point this function returned an error if the pager was in ** PAGER_ERROR state. But since PAGER_ERROR state guarantees that ** there is at least one outstanding page reference, this function ** is a no-op for that case anyhow. */ u32 pageSize = *pPageSize; assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); if( (pPager->memDb==0 || pPager->dbSize==0) && sqlite3PcacheRefCount(pPager->pPCache)==0 && pageSize && pageSize!=(u32)pPager->pageSize ){ char *pNew = NULL; /* New temp space */ i64 nByte = 0; if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){ rc = sqlite3OsFileSize(pPager->fd, &nByte); } if( rc==SQLITE_OK ){ /* 8 bytes of zeroed overrun space is sufficient so that the b-tree * cell header parser will never run off the end of the allocation */ pNew = (char *)sqlite3PageMalloc(pageSize+8); if( !pNew ){ rc = SQLITE_NOMEM_BKPT; }else{ memset(pNew+pageSize, 0, 8); } } if( rc==SQLITE_OK ){ pager_reset(pPager); rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); } if( rc==SQLITE_OK ){ sqlite3PageFree(pPager->pTmpSpace); pPager->pTmpSpace = pNew; pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); pPager->pageSize = pageSize; pPager->lckPgno = (Pgno)(PENDING_BYTE/pageSize) + 1; }else{ sqlite3PageFree(pNew); } } *pPageSize = pPager->pageSize; if( rc==SQLITE_OK ){ if( nReserve<0 ) nReserve = pPager->nReserve; assert( nReserve>=0 && nReserve<1000 ); pPager->nReserve = (i16)nReserve; pagerFixMaplimit(pPager); } return rc; } /* ** Return a pointer to the "temporary page" buffer held internally ** by the pager. This is a buffer that is big enough to hold the ** entire content of a database page. This buffer is used internally ** during rollback and will be overwritten whenever a rollback ** occurs. But other modules are free to use it too, as long as ** no rollbacks are happening. */ SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager *pPager){ return pPager->pTmpSpace; } /* ** Attempt to set the maximum database page count if mxPage is positive. ** Make no changes if mxPage is zero or negative. And never reduce the ** maximum page count below the current size of the database. ** ** Regardless of mxPage, return the current maximum page count. */ SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager *pPager, Pgno mxPage){ if( mxPage>0 ){ pPager->mxPgno = mxPage; } assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */ /* assert( pPager->mxPgno>=pPager->dbSize ); */ /* OP_MaxPgcnt ensures that the parameter passed to this function is not ** less than the total number of valid pages in the database. But this ** may be less than Pager.dbSize, and so the assert() above is not valid */ return pPager->mxPgno; } /* ** The following set of routines are used to disable the simulated ** I/O error mechanism. These routines are used to avoid simulated ** errors in places where we do not care about errors. ** ** Unless -DSQLITE_TEST=1 is used, these routines are all no-ops ** and generate no code. */ #ifdef SQLITE_TEST SQLITE_API extern int sqlite3_io_error_pending; SQLITE_API extern int sqlite3_io_error_hit; static int saved_cnt; void disable_simulated_io_errors(void){ saved_cnt = sqlite3_io_error_pending; sqlite3_io_error_pending = -1; } void enable_simulated_io_errors(void){ sqlite3_io_error_pending = saved_cnt; } #else # define disable_simulated_io_errors() # define enable_simulated_io_errors() #endif /* ** Read the first N bytes from the beginning of the file into memory ** that pDest points to. ** ** If the pager was opened on a transient file (zFilename==""), or ** opened on a file less than N bytes in size, the output buffer is ** zeroed and SQLITE_OK returned. The rationale for this is that this ** function is used to read database headers, and a new transient or ** zero sized database has a header than consists entirely of zeroes. ** ** If any IO error apart from SQLITE_IOERR_SHORT_READ is encountered, ** the error code is returned to the caller and the contents of the ** output buffer undefined. */ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){ int rc = SQLITE_OK; memset(pDest, 0, N); assert( isOpen(pPager->fd) || pPager->tempFile ); /* This routine is only called by btree immediately after creating ** the Pager object. There has not been an opportunity to transition ** to WAL mode yet. */ assert( !pagerUseWal(pPager) ); if( isOpen(pPager->fd) ){ IOTRACE(("DBHDR %p 0 %d\n", pPager, N)) rc = sqlite3OsRead(pPager->fd, pDest, N, 0); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } } return rc; } /* ** This function may only be called when a read-transaction is open on ** the pager. It returns the total number of pages in the database. ** ** However, if the file is between 1 and bytes in size, then ** this is considered a 1 page file. */ SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){ assert( pPager->eState>=PAGER_READER ); assert( pPager->eState!=PAGER_WRITER_FINISHED ); *pnPage = (int)pPager->dbSize; } /* ** Try to obtain a lock of type locktype on the database file. If ** a similar or greater lock is already held, this function is a no-op ** (returning SQLITE_OK immediately). ** ** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke ** the busy callback if the lock is currently not available. Repeat ** until the busy callback returns false or until the attempt to ** obtain the lock succeeds. ** ** Return SQLITE_OK on success and an error code if we cannot obtain ** the lock. If the lock is obtained successfully, set the Pager.state ** variable to locktype before returning. */ static int pager_wait_on_lock(Pager *pPager, int locktype){ int rc; /* Return code */ /* Check that this is either a no-op (because the requested lock is ** already held), or one of the transitions that the busy-handler ** may be invoked during, according to the comment above ** sqlite3PagerSetBusyhandler(). */ assert( (pPager->eLock>=locktype) || (pPager->eLock==NO_LOCK && locktype==SHARED_LOCK) || (pPager->eLock==RESERVED_LOCK && locktype==EXCLUSIVE_LOCK) ); do { rc = pagerLockDb(pPager, locktype); }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) ); return rc; } /* ** Function assertTruncateConstraint(pPager) checks that one of the ** following is true for all dirty pages currently in the page-cache: ** ** a) The page number is less than or equal to the size of the ** current database image, in pages, OR ** ** b) if the page content were written at this time, it would not ** be necessary to write the current content out to the sub-journal. ** ** If the condition asserted by this function were not true, and the ** dirty page were to be discarded from the cache via the pagerStress() ** routine, pagerStress() would not write the current page content to ** the database file. If a savepoint transaction were rolled back after ** this happened, the correct behavior would be to restore the current ** content of the page. However, since this content is not present in either ** the database file or the portion of the rollback journal and ** sub-journal rolled back the content could not be restored and the ** database image would become corrupt. It is therefore fortunate that ** this circumstance cannot arise. */ #if defined(SQLITE_DEBUG) static void assertTruncateConstraintCb(PgHdr *pPg){ Pager *pPager = pPg->pPager; assert( pPg->flags&PGHDR_DIRTY ); if( pPg->pgno>pPager->dbSize ){ /* if (a) is false */ Pgno pgno = pPg->pgno; int i; for(i=0; ipPager->nSavepoint; i++){ PagerSavepoint *p = &pPager->aSavepoint[i]; assert( p->nOrigpInSavepoint,pgno) ); } } } static void assertTruncateConstraint(Pager *pPager){ sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb); } #else # define assertTruncateConstraint(pPager) #endif /* ** Truncate the in-memory database file image to nPage pages. This ** function does not actually modify the database file on disk. It ** just sets the internal state of the pager object so that the ** truncation will be done when the current transaction is committed. ** ** This function is only called right before committing a transaction. ** Once this function has been called, the transaction must either be ** rolled back or committed. It is not safe to call this function and ** then continue writing to the database. */ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ assert( pPager->dbSize>=nPage || CORRUPT_DB ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); pPager->dbSize = nPage; /* At one point the code here called assertTruncateConstraint() to ** ensure that all pages being truncated away by this operation are, ** if one or more savepoints are open, present in the savepoint ** journal so that they can be restored if the savepoint is rolled ** back. This is no longer necessary as this function is now only ** called right before committing a transaction. So although the ** Pager object may still have open savepoints (Pager.nSavepoint!=0), ** they cannot be rolled back. So the assertTruncateConstraint() call ** is no longer correct. */ } /* ** This function is called before attempting a hot-journal rollback. It ** syncs the journal file to disk, then sets pPager->journalHdr to the ** size of the journal file so that the pager_playback() routine knows ** that the entire journal file has been synced. ** ** Syncing a hot-journal to disk before attempting to roll it back ensures ** that if a power-failure occurs during the rollback, the process that ** attempts rollback following system recovery sees the same journal ** content as this process. ** ** If everything goes as planned, SQLITE_OK is returned. Otherwise, ** an SQLite error code. */ static int pagerSyncHotJournal(Pager *pPager){ int rc = SQLITE_OK; if( !pPager->noSync ){ rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_NORMAL); } if( rc==SQLITE_OK ){ rc = sqlite3OsFileSize(pPager->jfd, &pPager->journalHdr); } return rc; } #if SQLITE_MAX_MMAP_SIZE>0 /* ** Obtain a reference to a memory mapped page object for page number pgno. ** The new object will use the pointer pData, obtained from xFetch(). ** If successful, set *ppPage to point to the new page reference ** and return SQLITE_OK. Otherwise, return an SQLite error code and set ** *ppPage to zero. ** ** Page references obtained by calling this function should be released ** by calling pagerReleaseMapPage(). */ static int pagerAcquireMapPage( Pager *pPager, /* Pager object */ Pgno pgno, /* Page number */ void *pData, /* xFetch()'d data for this page */ PgHdr **ppPage /* OUT: Acquired page object */ ){ PgHdr *p; /* Memory mapped page to return */ if( pPager->pMmapFreelist ){ *ppPage = p = pPager->pMmapFreelist; pPager->pMmapFreelist = p->pDirty; p->pDirty = 0; assert( pPager->nExtra>=8 ); memset(p->pExtra, 0, 8); }else{ *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra); if( p==0 ){ sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData); return SQLITE_NOMEM_BKPT; } p->pExtra = (void *)&p[1]; p->flags = PGHDR_MMAP; p->nRef = 1; p->pPager = pPager; } assert( p->pExtra==(void *)&p[1] ); assert( p->pPage==0 ); assert( p->flags==PGHDR_MMAP ); assert( p->pPager==pPager ); assert( p->nRef==1 ); p->pgno = pgno; p->pData = pData; pPager->nMmapOut++; return SQLITE_OK; } #endif /* ** Release a reference to page pPg. pPg must have been returned by an ** earlier call to pagerAcquireMapPage(). */ static void pagerReleaseMapPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; pPager->nMmapOut--; pPg->pDirty = pPager->pMmapFreelist; pPager->pMmapFreelist = pPg; assert( pPager->fd->pMethods->iVersion>=3 ); sqlite3OsUnfetch(pPager->fd, (i64)(pPg->pgno-1)*pPager->pageSize, pPg->pData); } /* ** Free all PgHdr objects stored in the Pager.pMmapFreelist list. */ static void pagerFreeMapHdrs(Pager *pPager){ PgHdr *p; PgHdr *pNext; for(p=pPager->pMmapFreelist; p; p=pNext){ pNext = p->pDirty; sqlite3_free(p); } } /* Verify that the database file has not be deleted or renamed out from ** under the pager. Return SQLITE_OK if the database is still where it ought ** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error ** code from sqlite3OsAccess()) if the database has gone missing. */ static int databaseIsUnmoved(Pager *pPager){ int bHasMoved = 0; int rc; if( pPager->tempFile ) return SQLITE_OK; if( pPager->dbSize==0 ) return SQLITE_OK; assert( pPager->zFilename && pPager->zFilename[0] ); rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved); if( rc==SQLITE_NOTFOUND ){ /* If the HAS_MOVED file-control is unimplemented, assume that the file ** has not been moved. That is the historical behavior of SQLite: prior to ** version 3.8.3, it never checked */ rc = SQLITE_OK; }else if( rc==SQLITE_OK && bHasMoved ){ rc = SQLITE_READONLY_DBMOVED; } return rc; } /* ** Shutdown the page cache. Free all memory and close all files. ** ** If a transaction was in progress when this routine is called, that ** transaction is rolled back. All outstanding pages are invalidated ** and their memory is freed. Any attempt to use a page associated ** with this page cache after this function returns will likely ** result in a coredump. ** ** This function always succeeds. If a transaction is active an attempt ** is made to roll it back. If an error occurs during the rollback ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ u8 *pTmp = (u8*)pPager->pTmpSpace; assert( db || pagerUseWal(pPager)==0 ); assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); pagerFreeMapHdrs(pPager); /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL { u8 *a = 0; assert( db || pPager->pWal==0 ); if( db && 0==(db->flags & SQLITE_NoCkptOnClose) && SQLITE_OK==databaseIsUnmoved(pPager) ){ a = pTmp; } sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); pPager->pWal = 0; } #endif pager_reset(pPager); if( MEMDB ){ pager_unlock(pPager); }else{ /* If it is open, sync the journal file before calling UnlockAndRollback. ** If this is not done, then an unsynced portion of the open journal ** file may be played back into the database. If a power failure occurs ** while this is happening, the database could become corrupt. ** ** If an error occurs while trying to sync the journal, shift the pager ** into the ERROR state. This causes UnlockAndRollback to unlock the ** database and close the journal file without attempting to roll it ** back or finalize it. The next database user will have to do hot-journal ** rollback before accessing the database file. */ if( isOpen(pPager->jfd) ){ pager_error(pPager, pagerSyncHotJournal(pPager)); } pagerUnlockAndRollback(pPager); } sqlite3EndBenignMalloc(); enable_simulated_io_errors(); PAGERTRACE(("CLOSE %d\n", PAGERID(pPager))); IOTRACE(("CLOSE %p\n", pPager)) sqlite3OsClose(pPager->jfd); sqlite3OsClose(pPager->fd); sqlite3PageFree(pTmp); sqlite3PcacheClose(pPager->pPCache); assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); sqlite3_free(pPager); return SQLITE_OK; } #if !defined(NDEBUG) || defined(SQLITE_TEST) /* ** Return the page number for page pPg. */ SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage *pPg){ return pPg->pgno; } #endif /* ** Increment the reference count for page pPg. */ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){ sqlite3PcacheRef(pPg); } /* ** Sync the journal. In other words, make sure all the pages that have ** been written to the journal have actually reached the surface of the ** disk and can be restored in the event of a hot-journal rollback. ** ** If the Pager.noSync flag is set, then this function is a no-op. ** Otherwise, the actions required depend on the journal-mode and the ** device characteristics of the file-system, as follows: ** ** * If the journal file is an in-memory journal file, no action need ** be taken. ** ** * Otherwise, if the device does not support the SAFE_APPEND property, ** then the nRec field of the most recently written journal header ** is updated to contain the number of journal records that have ** been written following it. If the pager is operating in full-sync ** mode, then the journal file is synced before this field is updated. ** ** * If the device does not support the SEQUENTIAL property, then ** journal file is synced. ** ** Or, in pseudo-code: ** ** if( NOT ){ ** if( NOT SAFE_APPEND ){ ** if( ) xSync(); ** ** } ** if( NOT SEQUENTIAL ) xSync(); ** } ** ** If successful, this routine clears the PGHDR_NEED_SYNC flag of every ** page currently held in memory before returning SQLITE_OK. If an IO ** error is encountered, then the IO error code is returned to the caller. */ static int syncJournal(Pager *pPager, int newHdr){ int rc; /* Return code */ assert( pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_DBMOD ); assert( assert_pager_state(pPager) ); assert( !pagerUseWal(pPager) ); rc = sqlite3PagerExclusiveLock(pPager); if( rc!=SQLITE_OK ) return rc; if( !pPager->noSync ){ assert( !pPager->tempFile ); if( isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){ const int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); assert( isOpen(pPager->jfd) ); if( 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){ /* This block deals with an obscure problem. If the last connection ** that wrote to this database was operating in persistent-journal ** mode, then the journal file may at this point actually be larger ** than Pager.journalOff bytes. If the next thing in the journal ** file happens to be a journal-header (written as part of the ** previous connection's transaction), and a crash or power-failure ** occurs after nRec is updated but before this connection writes ** anything else to the journal file (or commits/rolls back its ** transaction), then SQLite may become confused when doing the ** hot-journal rollback following recovery. It may roll back all ** of this connections data, then proceed to rolling back the old, ** out-of-date data that follows it. Database corruption. ** ** To work around this, if the journal file does appear to contain ** a valid header following Pager.journalOff, then write a 0x00 ** byte to the start of it to prevent it from being recognized. ** ** Variable iNextHdrOffset is set to the offset at which this ** problematic header will occur, if it exists. aMagic is used ** as a temporary buffer to inspect the first couple of bytes of ** the potential journal header. */ i64 iNextHdrOffset; u8 aMagic[8]; u8 zHeader[sizeof(aJournalMagic)+4]; memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec); iNextHdrOffset = journalHdrOffset(pPager); rc = sqlite3OsRead(pPager->jfd, aMagic, 8, iNextHdrOffset); if( rc==SQLITE_OK && 0==memcmp(aMagic, aJournalMagic, 8) ){ static const u8 zerobyte = 0; rc = sqlite3OsWrite(pPager->jfd, &zerobyte, 1, iNextHdrOffset); } if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ return rc; } /* Write the nRec value into the journal file header. If in ** full-synchronous mode, sync the journal first. This ensures that ** all data has really hit the disk before nRec is updated to mark ** it as a candidate for rollback. ** ** This is not required if the persistent media supports the ** SAFE_APPEND property. Because in this case it is not possible ** for garbage data to be appended to the file, the nRec field ** is populated with 0xFFFFFFFF when the journal header is written ** and never needs to be updated. */ if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){ PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager))); IOTRACE(("JSYNC %p\n", pPager)) rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); if( rc!=SQLITE_OK ) return rc; } IOTRACE(("JHDR %p %lld\n", pPager, pPager->journalHdr)); rc = sqlite3OsWrite( pPager->jfd, zHeader, sizeof(zHeader), pPager->journalHdr ); if( rc!=SQLITE_OK ) return rc; } if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){ PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager))); IOTRACE(("JSYNC %p\n", pPager)) rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags| (pPager->syncFlags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0) ); if( rc!=SQLITE_OK ) return rc; } pPager->journalHdr = pPager->journalOff; if( newHdr && 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){ pPager->nRec = 0; rc = writeJournalHdr(pPager); if( rc!=SQLITE_OK ) return rc; } }else{ pPager->journalHdr = pPager->journalOff; } } /* Unless the pager is in noSync mode, the journal file was just ** successfully synced. Either way, clear the PGHDR_NEED_SYNC flag on ** all pages. */ sqlite3PcacheClearSyncFlags(pPager->pPCache); pPager->eState = PAGER_WRITER_DBMOD; assert( assert_pager_state(pPager) ); return SQLITE_OK; } /* ** The argument is the first in a linked list of dirty pages connected ** by the PgHdr.pDirty pointer. This function writes each one of the ** in-memory pages in the list to the database file. The argument may ** be NULL, representing an empty list. In this case this function is ** a no-op. ** ** The pager must hold at least a RESERVED lock when this function ** is called. Before writing anything to the database file, this lock ** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained, ** SQLITE_BUSY is returned and no data is written to the database file. ** ** If the pager is a temp-file pager and the actual file-system file ** is not yet open, it is created and opened before any data is ** written out. ** ** Once the lock has been upgraded and, if necessary, the file opened, ** the pages are written out to the database file in list order. Writing ** a page is skipped if it meets either of the following criteria: ** ** * The page number is greater than Pager.dbSize, or ** * The PGHDR_DONT_WRITE flag is set on the page. ** ** If writing out a page causes the database file to grow, Pager.dbFileSize ** is updated accordingly. If page 1 is written out, then the value cached ** in Pager.dbFileVers[] is updated to match the new value stored in ** the database file. ** ** If everything is successful, SQLITE_OK is returned. If an IO error ** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot ** be obtained, SQLITE_BUSY is returned. */ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ int rc = SQLITE_OK; /* Return code */ /* This function is only called for rollback pagers in WRITER_DBMOD state. */ assert( !pagerUseWal(pPager) ); assert( pPager->tempFile || pPager->eState==PAGER_WRITER_DBMOD ); assert( pPager->eLock==EXCLUSIVE_LOCK ); assert( isOpen(pPager->fd) || pList->pDirty==0 ); /* If the file is a temp-file has not yet been opened, open it now. It ** is not possible for rc to be other than SQLITE_OK if this branch ** is taken, as pager_wait_on_lock() is a no-op for temp-files. */ if( !isOpen(pPager->fd) ){ assert( pPager->tempFile && rc==SQLITE_OK ); rc = pagerOpentemp(pPager, pPager->fd, pPager->vfsFlags); } /* Before the first write, give the VFS a hint of what the final ** file size will be. */ assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); if( rc==SQLITE_OK && pPager->dbHintSizedbSize && (pList->pDirty || pList->pgno>pPager->dbHintSize) ){ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); pPager->dbHintSize = pPager->dbSize; } while( rc==SQLITE_OK && pList ){ Pgno pgno = pList->pgno; /* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3PagerTruncateImage() was called to ** make the file smaller (presumably by auto-vacuum code). Do not write ** any such pages to the file. ** ** Also, do not write out any page that has the PGHDR_DONT_WRITE flag ** set (set by sqlite3PagerDontWrite()). */ if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){ i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */ char *pData; /* Data to write */ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); if( pList->pgno==1 ) pager_write_changecounter(pList); pData = pList->pData; /* Write out the page data. */ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); /* If page 1 was just written, update Pager.dbFileVers to match ** the value now stored in the database file. If writing this ** page caused the database file to grow, update dbFileSize. */ if( pgno==1 ){ memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers)); } if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } pPager->aStat[PAGER_STAT_WRITE]++; /* Update any backup objects copying the contents of this pager. */ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)pList->pData); PAGERTRACE(("STORE %d page %d hash(%08x)\n", PAGERID(pPager), pgno, pager_pagehash(pList))); IOTRACE(("PGOUT %p %d\n", pPager, pgno)); PAGER_INCR(sqlite3_pager_writedb_count); }else{ PAGERTRACE(("NOSTORE %d page %d\n", PAGERID(pPager), pgno)); } pager_set_pagehash(pList); pList = pList->pDirty; } return rc; } /* ** Ensure that the sub-journal file is open. If it is already open, this ** function is a no-op. ** ** SQLITE_OK is returned if everything goes according to plan. An ** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen() ** fails. */ static int openSubJournal(Pager *pPager){ int rc = SQLITE_OK; if( !isOpen(pPager->sjfd) ){ const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE; int nStmtSpill = sqlite3Config.nStmtSpill; if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){ nStmtSpill = -1; } rc = sqlite3JournalOpen(pPager->pVfs, 0, pPager->sjfd, flags, nStmtSpill); } return rc; } /* ** Append a record of the current state of page pPg to the sub-journal. ** ** If successful, set the bit corresponding to pPg->pgno in the bitvecs ** for all open savepoints before returning. ** ** This function returns SQLITE_OK if everything is successful, an IO ** error code if the attempt to write to the sub-journal fails, or ** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint ** bitvec. */ static int subjournalPage(PgHdr *pPg){ int rc = SQLITE_OK; Pager *pPager = pPg->pPager; if( pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ /* Open the sub-journal, if it has not already been opened */ assert( pPager->useJournal ); assert( isOpen(pPager->jfd) || pagerUseWal(pPager) ); assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 ); assert( pagerUseWal(pPager) || pageInJournal(pPager, pPg) || pPg->pgno>pPager->dbOrigSize ); rc = openSubJournal(pPager); /* If the sub-journal was opened successfully (or was already open), ** write the journal record into the file. */ if( rc==SQLITE_OK ){ void *pData = pPg->pData; i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); char *pData2; pData2 = pData; PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); rc = write32bits(pPager->sjfd, offset, pPg->pgno); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4); } } } if( rc==SQLITE_OK ){ pPager->nSubRec++; assert( pPager->nSavepoint>0 ); rc = addToSavepointBitvecs(pPager, pPg->pgno); } return rc; } static int subjournalPageIfRequired(PgHdr *pPg){ if( subjRequiresPage(pPg) ){ return subjournalPage(pPg); }else{ return SQLITE_OK; } } /* ** This function is called by the pcache layer when it has reached some ** soft memory limit. The first argument is a pointer to a Pager object ** (cast as a void*). The pager is always 'purgeable' (not an in-memory ** database). The second argument is a reference to a page that is ** currently dirty but has no outstanding references. The page ** is always associated with the Pager object passed as the first ** argument. ** ** The job of this function is to make pPg clean by writing its contents ** out to the database file, if possible. This may involve syncing the ** journal file. ** ** If successful, sqlite3PcacheMakeClean() is called on the page and ** SQLITE_OK returned. If an IO error occurs while trying to make the ** page clean, the IO error code is returned. If the page cannot be ** made clean for some other reason, but no error occurs, then SQLITE_OK ** is returned by sqlite3PcacheMakeClean() is not called. */ static int pagerStress(void *p, PgHdr *pPg){ Pager *pPager = (Pager *)p; int rc = SQLITE_OK; assert( pPg->pPager==pPager ); assert( pPg->flags&PGHDR_DIRTY ); /* The doNotSpill NOSYNC bit is set during times when doing a sync of ** journal (and adding a new header) is not allowed. This occurs ** during calls to sqlite3PagerWrite() while trying to journal multiple ** pages belonging to the same sector. ** ** The doNotSpill ROLLBACK and OFF bits inhibits all cache spilling ** regardless of whether or not a sync is required. This is set during ** a rollback or by user request, respectively. ** ** Spilling is also prohibited when in an error state since that could ** lead to database corruption. In the current implementation it ** is impossible for sqlite3PcacheFetch() to be called with createFlag==3 ** while in the error state, hence it is impossible for this routine to ** be called in the error state. Nevertheless, we include a NEVER() ** test for the error state as a safeguard against future changes. */ if( NEVER(pPager->errCode) ) return SQLITE_OK; testcase( pPager->doNotSpill & SPILLFLAG_ROLLBACK ); testcase( pPager->doNotSpill & SPILLFLAG_OFF ); testcase( pPager->doNotSpill & SPILLFLAG_NOSYNC ); if( pPager->doNotSpill && ((pPager->doNotSpill & (SPILLFLAG_ROLLBACK|SPILLFLAG_OFF))!=0 || (pPg->flags & PGHDR_NEED_SYNC)!=0) ){ return SQLITE_OK; } pPager->aStat[PAGER_STAT_SPILL]++; pPg->pDirty = 0; if( pagerUseWal(pPager) ){ /* Write a single frame for this page to the log. */ rc = subjournalPageIfRequired(pPg); if( rc==SQLITE_OK ){ rc = pagerWalFrames(pPager, pPg, 0, 0); } }else{ #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE if( pPager->tempFile==0 ){ rc = sqlite3JournalCreate(pPager->jfd); if( rc!=SQLITE_OK ) return pager_error(pPager, rc); } #endif /* Sync the journal file if required. */ if( pPg->flags&PGHDR_NEED_SYNC || pPager->eState==PAGER_WRITER_CACHEMOD ){ rc = syncJournal(pPager, 1); } /* Write the contents of the page out to the database file. */ if( rc==SQLITE_OK ){ assert( (pPg->flags&PGHDR_NEED_SYNC)==0 ); rc = pager_write_pagelist(pPager, pPg); } } /* Mark the page as clean. */ if( rc==SQLITE_OK ){ PAGERTRACE(("STRESS %d page %d\n", PAGERID(pPager), pPg->pgno)); sqlite3PcacheMakeClean(pPg); } return pager_error(pPager, rc); } /* ** Flush all unreferenced dirty pages to disk. */ SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){ int rc = pPager->errCode; if( !MEMDB ){ PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); assert( assert_pager_state(pPager) ); while( rc==SQLITE_OK && pList ){ PgHdr *pNext = pList->pDirty; if( pList->nRef==0 ){ rc = pagerStress((void*)pPager, pList); } pList = pNext; } } return rc; } /* ** Allocate and initialize a new Pager object and put a pointer to it ** in *ppPager. The pager should eventually be freed by passing it ** to sqlite3PagerClose(). ** ** The zFilename argument is the path to the database file to open. ** If zFilename is NULL then a randomly-named temporary file is created ** and used as the file to be cached. Temporary files are be deleted ** automatically when they are closed. If zFilename is ":memory:" then ** all information is held in cache. It is never written to disk. ** This can be used to implement an in-memory database. ** ** The nExtra parameter specifies the number of bytes of space allocated ** along with each page reference. This space is available to the user ** via the sqlite3PagerGetExtra() API. When a new page is allocated, the ** first 8 bytes of this space are zeroed but the remainder is uninitialized. ** (The extra space is used by btree as the MemPage object.) ** ** The flags argument is used to specify properties that affect the ** operation of the pager. It should be passed some bitwise combination ** of the PAGER_* flags. ** ** The vfsFlags parameter is a bitmask to pass to the flags parameter ** of the xOpen() method of the supplied VFS when opening files. ** ** If the pager object is allocated and the specified file opened ** successfully, SQLITE_OK is returned and *ppPager set to point to ** the new pager object. If an error occurs, *ppPager is set to NULL ** and error code returned. This function may return SQLITE_NOMEM ** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or ** various SQLITE_IO_XXX errors. */ SQLITE_PRIVATE int sqlite3PagerOpen( sqlite3_vfs *pVfs, /* The virtual file system to use */ Pager **ppPager, /* OUT: Return the Pager structure here */ const char *zFilename, /* Name of the database file to open */ int nExtra, /* Extra bytes append to each in-memory page */ int flags, /* flags controlling this file */ int vfsFlags, /* flags passed through to sqlite3_vfs.xOpen() */ void (*xReinit)(DbPage*) /* Function to reinitialize pages */ ){ u8 *pPtr; Pager *pPager = 0; /* Pager object to allocate and return */ int rc = SQLITE_OK; /* Return code */ int tempFile = 0; /* True for temp files (incl. in-memory files) */ int memDb = 0; /* True if this is an in-memory file */ int memJM = 0; /* Memory journal mode */ int readOnly = 0; /* True if this is a read-only file */ int journalFileSize; /* Bytes to allocate for each journal fd */ char *zPathname = 0; /* Full path to database file */ int nPathname = 0; /* Number of bytes in zPathname */ int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */ int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */ u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */ const char *zUri = 0; /* URI args to copy */ int nUriByte = 1; /* Number of bytes of URI args at *zUri */ /* Figure out how much space is required for each journal file-handle ** (there are two of them, the main journal and the sub-journal). */ journalFileSize = ROUND8(sqlite3JournalSize(pVfs)); /* Set the output variable to NULL in case an error occurs. */ *ppPager = 0; #ifndef SQLITE_OMIT_MEMORYDB if( flags & PAGER_MEMORY ){ memDb = 1; if( zFilename && zFilename[0] ){ zPathname = sqlite3DbStrDup(0, zFilename); if( zPathname==0 ) return SQLITE_NOMEM_BKPT; nPathname = sqlite3Strlen30(zPathname); zFilename = 0; } } #endif /* Compute and store the full pathname in an allocated buffer pointed ** to by zPathname, length nPathname. Or, if this is a temporary file, ** leave both nPathname and zPathname set to 0. */ if( zFilename && zFilename[0] ){ const char *z; nPathname = pVfs->mxPathname+1; zPathname = sqlite3DbMallocRaw(0, nPathname*2); if( zPathname==0 ){ return SQLITE_NOMEM_BKPT; } zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); if( rc!=SQLITE_OK ){ if( rc==SQLITE_OK_SYMLINK ){ if( vfsFlags & SQLITE_OPEN_NOFOLLOW ){ rc = SQLITE_CANTOPEN_SYMLINK; }else{ rc = SQLITE_OK; } } } nPathname = sqlite3Strlen30(zPathname); z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1]; while( *z ){ z += strlen(z)+1; z += strlen(z)+1; } nUriByte = (int)(&z[1] - zUri); assert( nUriByte>=1 ); if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){ /* This branch is taken when the journal path required by ** the database being opened will be more than pVfs->mxPathname ** bytes in length. This means the database cannot be opened, ** as it will not be possible to open the journal file or even ** check for a hot-journal before reading. */ rc = SQLITE_CANTOPEN_BKPT; } if( rc!=SQLITE_OK ){ sqlite3DbFree(0, zPathname); return rc; } } /* Allocate memory for the Pager structure, PCache object, the ** three file descriptors, the database file name and the journal ** file name. The layout in memory is as follows: ** ** Pager object (sizeof(Pager) bytes) ** PCache object (sqlite3PcacheSize() bytes) ** Database file handle (pVfs->szOsFile bytes) ** Sub-journal file handle (journalFileSize bytes) ** Main journal file handle (journalFileSize bytes) ** Ptr back to the Pager (sizeof(Pager*) bytes) ** \0\0\0\0 database prefix (4 bytes) ** Database file name (nPathname+1 bytes) ** URI query parameters (nUriByte bytes) ** Journal filename (nPathname+8+1 bytes) ** WAL filename (nPathname+4+1 bytes) ** \0\0\0 terminator (3 bytes) ** ** Some 3rd-party software, over which we have no control, depends on ** the specific order of the filenames and the \0 separators between them ** so that it can (for example) find the database filename given the WAL ** filename without using the sqlite3_filename_database() API. This is a ** misuse of SQLite and a bug in the 3rd-party software, but the 3rd-party ** software is in widespread use, so we try to avoid changing the filename ** order and formatting if possible. In particular, the details of the ** filename format expected by 3rd-party software should be as follows: ** ** - Main Database Path ** - \0 ** - Multiple URI components consisting of: ** - Key ** - \0 ** - Value ** - \0 ** - \0 ** - Journal Path ** - \0 ** - WAL Path (zWALName) ** - \0 ** ** The sqlite3_create_filename() interface and the databaseFilename() utility ** that is used by sqlite3_filename_database() and kin also depend on the ** specific formatting and order of the various filenames, so if the format ** changes here, be sure to change it there as well. */ assert( SQLITE_PTRSIZE==sizeof(Pager*) ); pPtr = (u8 *)sqlite3MallocZero( ROUND8(sizeof(*pPager)) + /* Pager structure */ ROUND8(pcacheSize) + /* PCache object */ ROUND8(pVfs->szOsFile) + /* The main db file */ journalFileSize * 2 + /* The two journal files */ SQLITE_PTRSIZE + /* Space to hold a pointer */ 4 + /* Database prefix */ nPathname + 1 + /* database filename */ nUriByte + /* query parameters */ nPathname + 8 + 1 + /* Journal filename */ #ifndef SQLITE_OMIT_WAL nPathname + 4 + 1 + /* WAL filename */ #endif 3 /* Terminator */ ); assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) ); if( !pPtr ){ sqlite3DbFree(0, zPathname); return SQLITE_NOMEM_BKPT; } pPager = (Pager*)pPtr; pPtr += ROUND8(sizeof(*pPager)); pPager->pPCache = (PCache*)pPtr; pPtr += ROUND8(pcacheSize); pPager->fd = (sqlite3_file*)pPtr; pPtr += ROUND8(pVfs->szOsFile); pPager->sjfd = (sqlite3_file*)pPtr; pPtr += journalFileSize; pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize; assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) ); memcpy(pPtr, &pPager, SQLITE_PTRSIZE); pPtr += SQLITE_PTRSIZE; /* Fill in the Pager.zFilename and pPager.zQueryParam fields */ pPtr += 4; /* Skip zero prefix */ pPager->zFilename = (char*)pPtr; if( nPathname>0 ){ memcpy(pPtr, zPathname, nPathname); pPtr += nPathname + 1; if( zUri ){ memcpy(pPtr, zUri, nUriByte); pPtr += nUriByte; }else{ pPtr++; } } /* Fill in Pager.zJournal */ if( nPathname>0 ){ pPager->zJournal = (char*)pPtr; memcpy(pPtr, zPathname, nPathname); pPtr += nPathname; memcpy(pPtr, "-journal",8); pPtr += 8 + 1; #ifdef SQLITE_ENABLE_8_3_NAMES sqlite3FileSuffix3(zFilename,pPager->zJournal); pPtr = (u8*)(pPager->zJournal + sqlite3Strlen30(pPager->zJournal)+1); #endif }else{ pPager->zJournal = 0; } #ifndef SQLITE_OMIT_WAL /* Fill in Pager.zWal */ if( nPathname>0 ){ pPager->zWal = (char*)pPtr; memcpy(pPtr, zPathname, nPathname); pPtr += nPathname; memcpy(pPtr, "-wal", 4); pPtr += 4 + 1; #ifdef SQLITE_ENABLE_8_3_NAMES sqlite3FileSuffix3(zFilename, pPager->zWal); pPtr = (u8*)(pPager->zWal + sqlite3Strlen30(pPager->zWal)+1); #endif }else{ pPager->zWal = 0; } #endif (void)pPtr; /* Suppress warning about unused pPtr value */ if( nPathname ) sqlite3DbFree(0, zPathname); pPager->pVfs = pVfs; pPager->vfsFlags = vfsFlags; /* Open the pager file. */ if( zFilename && zFilename[0] ){ int fout = 0; /* VFS flags returned by xOpen() */ rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout); assert( !memDb ); pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0; readOnly = (fout&SQLITE_OPEN_READONLY)!=0; /* If the file was successfully opened for read/write access, ** choose a default page size in case we have to create the ** database file. The default page size is the maximum of: ** ** + SQLITE_DEFAULT_PAGE_SIZE, ** + The value returned by sqlite3OsSectorSize() ** + The largest page size that can be written atomically. */ if( rc==SQLITE_OK ){ int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); if( !readOnly ){ setSectorSize(pPager); assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE); if( szPageDfltsectorSize ){ if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE; }else{ szPageDflt = (u32)pPager->sectorSize; } } #ifdef SQLITE_ENABLE_ATOMIC_WRITE { int ii; assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ szPageDflt = ii; } } } #endif } pPager->noLock = sqlite3_uri_boolean(pPager->zFilename, "nolock", 0); if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 || sqlite3_uri_boolean(pPager->zFilename, "immutable", 0) ){ vfsFlags |= SQLITE_OPEN_READONLY; goto act_like_temp_file; } } }else{ /* If a temporary file is requested, it is not opened immediately. ** In this case we accept the default page size and delay actually ** opening the file until the first call to OsWrite(). ** ** This branch is also run for an in-memory database. An in-memory ** database is the same as a temp-file that is never written out to ** disk and uses an in-memory rollback journal. ** ** This branch also runs for files marked as immutable. */ act_like_temp_file: tempFile = 1; pPager->eState = PAGER_READER; /* Pretend we already have a lock */ pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE mode */ pPager->noLock = 1; /* Do no locking */ readOnly = (vfsFlags&SQLITE_OPEN_READONLY); } /* The following call to PagerSetPagesize() serves to set the value of ** Pager.pageSize and to allocate the Pager.pTmpSpace buffer. */ if( rc==SQLITE_OK ){ assert( pPager->memDb==0 ); rc = sqlite3PagerSetPagesize(pPager, &szPageDflt, -1); testcase( rc!=SQLITE_OK ); } /* Initialize the PCache object. */ if( rc==SQLITE_OK ){ nExtra = ROUND8(nExtra); assert( nExtra>=8 && nExtra<1000 ); rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); } /* If an error occurred above, free the Pager structure and close the file. */ if( rc!=SQLITE_OK ){ sqlite3OsClose(pPager->fd); sqlite3PageFree(pPager->pTmpSpace); sqlite3_free(pPager); return rc; } PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename)); IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename)) pPager->useJournal = (u8)useJournal; /* pPager->stmtOpen = 0; */ /* pPager->stmtInUse = 0; */ /* pPager->nRef = 0; */ /* pPager->stmtSize = 0; */ /* pPager->stmtJSize = 0; */ /* pPager->nPage = 0; */ pPager->mxPgno = SQLITE_MAX_PAGE_COUNT; /* pPager->state = PAGER_UNLOCK; */ /* pPager->errMask = 0; */ pPager->tempFile = (u8)tempFile; assert( tempFile==PAGER_LOCKINGMODE_NORMAL || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE ); assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 ); pPager->exclusiveMode = (u8)tempFile; pPager->changeCountDone = pPager->tempFile; pPager->memDb = (u8)memDb; pPager->readOnly = (u8)readOnly; assert( useJournal || pPager->tempFile ); sqlite3PagerSetFlags(pPager, (SQLITE_DEFAULT_SYNCHRONOUS+1)|PAGER_CACHESPILL); /* pPager->pFirst = 0; */ /* pPager->pFirstSynced = 0; */ /* pPager->pLast = 0; */ pPager->nExtra = (u16)nExtra; pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT; assert( isOpen(pPager->fd) || tempFile ); setSectorSize(pPager); if( !useJournal ){ pPager->journalMode = PAGER_JOURNALMODE_OFF; }else if( memDb || memJM ){ pPager->journalMode = PAGER_JOURNALMODE_MEMORY; } /* pPager->xBusyHandler = 0; */ /* pPager->pBusyHandlerArg = 0; */ pPager->xReiniter = xReinit; setGetterMethod(pPager); /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */ *ppPager = pPager; return SQLITE_OK; } /* ** Return the sqlite3_file for the main database given the name ** of the corresponding WAL or Journal name as passed into ** xOpen. */ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char *zName){ Pager *pPager; const char *p; while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){ zName--; } p = zName - 4 - sizeof(Pager*); assert( EIGHT_BYTE_ALIGNMENT(p) ); pPager = *(Pager**)p; return pPager->fd; } /* ** This function is called after transitioning from PAGER_UNLOCK to ** PAGER_SHARED state. It tests if there is a hot journal present in ** the file-system for the given pager. A hot journal is one that ** needs to be played back. According to this function, a hot-journal ** file exists if the following criteria are met: ** ** * The journal file exists in the file system, and ** * No process holds a RESERVED or greater lock on the database file, and ** * The database file itself is greater than 0 bytes in size, and ** * The first byte of the journal file exists and is not 0x00. ** ** If the current size of the database file is 0 but a journal file ** exists, that is probably an old journal left over from a prior ** database with the same name. In this case the journal file is ** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK ** is returned. ** ** This routine does not check if there is a super-journal filename ** at the end of the file. If there is, and that super-journal file ** does not exist, then the journal file is not really hot. In this ** case this routine will return a false-positive. The pager_playback() ** routine will discover that the journal file is not really hot and ** will not roll it back. ** ** If a hot-journal file is found to exist, *pExists is set to 1 and ** SQLITE_OK returned. If no hot-journal file is present, *pExists is ** set to 0 and SQLITE_OK returned. If an IO error occurs while trying ** to determine whether or not a hot-journal file exists, the IO error ** code is returned and the value of *pExists is undefined. */ static int hasHotJournal(Pager *pPager, int *pExists){ sqlite3_vfs * const pVfs = pPager->pVfs; int rc = SQLITE_OK; /* Return code */ int exists = 1; /* True if a journal file is present */ int jrnlOpen = !!isOpen(pPager->jfd); assert( pPager->useJournal ); assert( isOpen(pPager->fd) ); assert( pPager->eState==PAGER_OPEN ); assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN )); *pExists = 0; if( !jrnlOpen ){ rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists); } if( rc==SQLITE_OK && exists ){ int locked = 0; /* True if some process holds a RESERVED lock */ /* Race condition here: Another process might have been holding the ** the RESERVED lock and have a journal open at the sqlite3OsAccess() ** call above, but then delete the journal and drop the lock before ** we get to the following sqlite3OsCheckReservedLock() call. If that ** is the case, this routine might think there is a hot journal when ** in fact there is none. This results in a false-positive which will ** be dealt with by the playback routine. Ticket #3883. */ rc = sqlite3OsCheckReservedLock(pPager->fd, &locked); if( rc==SQLITE_OK && !locked ){ Pgno nPage; /* Number of pages in database file */ assert( pPager->tempFile==0 ); rc = pagerPagecount(pPager, &nPage); if( rc==SQLITE_OK ){ /* If the database is zero pages in size, that means that either (1) the ** journal is a remnant from a prior database with the same name where ** the database file but not the journal was deleted, or (2) the initial ** transaction that populates a new database is being rolled back. ** In either case, the journal file can be deleted. However, take care ** not to delete the journal file if it is already open due to ** journal_mode=PERSIST. */ if( nPage==0 && !jrnlOpen ){ sqlite3BeginBenignMalloc(); if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){ sqlite3OsDelete(pVfs, pPager->zJournal, 0); if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); } sqlite3EndBenignMalloc(); }else{ /* The journal file exists and no other connection has a reserved ** or greater lock on the database file. Now check that there is ** at least one non-zero bytes at the start of the journal file. ** If there is, then we consider this journal to be hot. If not, ** it can be ignored. */ if( !jrnlOpen ){ int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL; rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f); } if( rc==SQLITE_OK ){ u8 first = 0; rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } if( !jrnlOpen ){ sqlite3OsClose(pPager->jfd); } *pExists = (first!=0); }else if( rc==SQLITE_CANTOPEN ){ /* If we cannot open the rollback journal file in order to see if ** it has a zero header, that might be due to an I/O error, or ** it might be due to the race condition described above and in ** ticket #3883. Either way, assume that the journal is hot. ** This might be a false positive. But if it is, then the ** automatic journal playback and recovery mechanism will deal ** with it under an EXCLUSIVE lock where we do not need to ** worry so much with race conditions. */ *pExists = 1; rc = SQLITE_OK; } } } } } return rc; } /* ** This function is called to obtain a shared lock on the database file. ** It is illegal to call sqlite3PagerGet() until after this function ** has been successfully called. If a shared-lock is already held when ** this function is called, it is a no-op. ** ** The following operations are also performed by this function. ** ** 1) If the pager is currently in PAGER_OPEN state (no lock held ** on the database file), then an attempt is made to obtain a ** SHARED lock on the database file. Immediately after obtaining ** the SHARED lock, the file-system is checked for a hot-journal, ** which is played back if present. Following any hot-journal ** rollback, the contents of the cache are validated by checking ** the 'change-counter' field of the database file header and ** discarded if they are found to be invalid. ** ** 2) If the pager is running in exclusive-mode, and there are currently ** no outstanding references to any pages, and is in the error state, ** then an attempt is made to clear the error state by discarding ** the contents of the page cache and rolling back any open journal ** file. ** ** If everything is successful, SQLITE_OK is returned. If an IO error ** occurs while locking the database, checking for a hot-journal file or ** rolling back a journal file, the IO error code is returned. */ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ /* This routine is only called from b-tree and only when there are no ** outstanding pages. This implies that the pager state should either ** be OPEN or READER. READER is only possible if the pager is or was in ** exclusive access mode. */ assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); assert( assert_pager_state(pPager) ); assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER ); assert( pPager->errCode==SQLITE_OK ); if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){ int bHotJournal = 1; /* True if there exists a hot journal-file */ assert( !MEMDB ); assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK ); rc = pager_wait_on_lock(pPager, SHARED_LOCK); if( rc!=SQLITE_OK ){ assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK ); goto failed; } /* If a journal file exists, and there is no RESERVED lock on the ** database file, then it either needs to be played back or deleted. */ if( pPager->eLock<=SHARED_LOCK ){ rc = hasHotJournal(pPager, &bHotJournal); } if( rc!=SQLITE_OK ){ goto failed; } if( bHotJournal ){ if( pPager->readOnly ){ rc = SQLITE_READONLY_ROLLBACK; goto failed; } /* Get an EXCLUSIVE lock on the database file. At this point it is ** important that a RESERVED lock is not obtained on the way to the ** EXCLUSIVE lock. If it were, another process might open the ** database file, detect the RESERVED lock, and conclude that the ** database is safe to read while this process is still rolling the ** hot-journal back. ** ** Because the intermediate RESERVED lock is not requested, any ** other process attempting to access the database file will get to ** this point in the code and fail to obtain its own EXCLUSIVE lock ** on the database file. ** ** Unless the pager is in locking_mode=exclusive mode, the lock is ** downgraded to SHARED_LOCK before this function returns. */ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ goto failed; } /* If it is not already open and the file exists on disk, open the ** journal for read/write access. Write access is required because ** in exclusive-access mode the file descriptor will be kept open ** and possibly used for a transaction later on. Also, write-access ** is usually required to finalize the journal in journal_mode=persist ** mode (and also for journal_mode=truncate on some systems). ** ** If the journal does not exist, it usually means that some ** other connection managed to get in and roll it back before ** this connection obtained the exclusive lock above. Or, it ** may mean that the pager was in the error-state when this ** function was called and the journal file does not exist. */ if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ sqlite3_vfs * const pVfs = pPager->pVfs; int bExists; /* True if journal file exists */ rc = sqlite3OsAccess( pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &bExists); if( rc==SQLITE_OK && bExists ){ int fout = 0; int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL; assert( !pPager->tempFile ); rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout); assert( rc!=SQLITE_OK || isOpen(pPager->jfd) ); if( rc==SQLITE_OK && fout&SQLITE_OPEN_READONLY ){ rc = SQLITE_CANTOPEN_BKPT; sqlite3OsClose(pPager->jfd); } } } /* Playback and delete the journal. Drop the database write ** lock and reacquire the read lock. Purge the cache before ** playing back the hot-journal so that we don't end up with ** an inconsistent cache. Sync the hot journal before playing ** it back since the process that crashed and left the hot journal ** probably did not sync it and we are required to always sync ** the journal before playing it back. */ if( isOpen(pPager->jfd) ){ assert( rc==SQLITE_OK ); rc = pagerSyncHotJournal(pPager); if( rc==SQLITE_OK ){ rc = pager_playback(pPager, !pPager->tempFile); pPager->eState = PAGER_OPEN; } }else if( !pPager->exclusiveMode ){ pagerUnlockDb(pPager, SHARED_LOCK); } if( rc!=SQLITE_OK ){ /* This branch is taken if an error occurs while trying to open ** or roll back a hot-journal while holding an EXCLUSIVE lock. The ** pager_unlock() routine will be called before returning to unlock ** the file. If the unlock attempt fails, then Pager.eLock must be ** set to UNKNOWN_LOCK (see the comment above the #define for ** UNKNOWN_LOCK above for an explanation). ** ** In order to get pager_unlock() to do this, set Pager.eState to ** PAGER_ERROR now. This is not actually counted as a transition ** to ERROR state in the state diagram at the top of this file, ** since we know that the same call to pager_unlock() will very ** shortly transition the pager object to the OPEN state. Calling ** assert_pager_state() would fail now, as it should not be possible ** to be in ERROR state when there are zero outstanding page ** references. */ pager_error(pPager, rc); goto failed; } assert( pPager->eState==PAGER_OPEN ); assert( (pPager->eLock==SHARED_LOCK) || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK) ); } if( !pPager->tempFile && pPager->hasHeldSharedLock ){ /* The shared-lock has just been acquired then check to ** see if the database has been modified. If the database has changed, ** flush the cache. The hasHeldSharedLock flag prevents this from ** occurring on the very first access to a file, in order to save a ** single unnecessary sqlite3OsRead() call at the start-up. ** ** Database changes are detected by looking at 15 bytes beginning ** at offset 24 into the file. The first 4 of these 16 bytes are ** a 32-bit counter that is incremented with each change. The ** other bytes change randomly with each file change when ** a codec is in use. ** ** There is a vanishingly small chance that a change will not be ** detected. The chance of an undetected change is so small that ** it can be neglected. */ char dbFileVers[sizeof(pPager->dbFileVers)]; IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); if( rc!=SQLITE_OK ){ if( rc!=SQLITE_IOERR_SHORT_READ ){ goto failed; } memset(dbFileVers, 0, sizeof(dbFileVers)); } if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){ pager_reset(pPager); /* Unmap the database file. It is possible that external processes ** may have truncated the database file and then extended it back ** to its original size while this process was not holding a lock. ** In this case there may exist a Pager.pMap mapping that appears ** to be the right size but is not actually valid. Avoid this ** possibility by unmapping the db here. */ if( USEFETCH(pPager) ){ sqlite3OsUnfetch(pPager->fd, 0, 0); } } } /* If there is a WAL file in the file-system, open this database in WAL ** mode. Otherwise, the following function call is a no-op. */ rc = pagerOpenWalIfPresent(pPager); #ifndef SQLITE_OMIT_WAL assert( pPager->pWal==0 || rc==SQLITE_OK ); #endif } if( pagerUseWal(pPager) ){ assert( rc==SQLITE_OK ); rc = pagerBeginReadTransaction(pPager); } if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){ rc = pagerPagecount(pPager, &pPager->dbSize); } failed: if( rc!=SQLITE_OK ){ assert( !MEMDB ); pager_unlock(pPager); assert( pPager->eState==PAGER_OPEN ); }else{ pPager->eState = PAGER_READER; pPager->hasHeldSharedLock = 1; } return rc; } /* ** If the reference count has reached zero, rollback any active ** transaction and unlock the pager. ** ** Except, in locking_mode=EXCLUSIVE when there is nothing to in ** the rollback journal, the unlock is not performed and there is ** nothing to rollback, so this routine is a no-op. */ static void pagerUnlockIfUnused(Pager *pPager){ if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){ assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */ pagerUnlockAndRollback(pPager); } } /* ** The page getter methods each try to acquire a reference to a ** page with page number pgno. If the requested reference is ** successfully obtained, it is copied to *ppPage and SQLITE_OK returned. ** ** There are different implementations of the getter method depending ** on the current state of the pager. ** ** getPageNormal() -- The normal getter ** getPageError() -- Used if the pager is in an error state ** getPageMmap() -- Used if memory-mapped I/O is enabled ** ** If the requested page is already in the cache, it is returned. ** Otherwise, a new page object is allocated and populated with data ** read from the database file. In some cases, the pcache module may ** choose not to allocate a new page object and may reuse an existing ** object with no outstanding references. ** ** The extra data appended to a page is always initialized to zeros the ** first time a page is loaded into memory. If the page requested is ** already in the cache when this function is called, then the extra ** data is left as it was when the page object was last used. ** ** If the database image is smaller than the requested page or if ** the flags parameter contains the PAGER_GET_NOCONTENT bit and the ** requested page is not already stored in the cache, then no ** actual disk read occurs. In this case the memory image of the ** page is initialized to all zeros. ** ** If PAGER_GET_NOCONTENT is true, it means that we do not care about ** the contents of the page. This occurs in two scenarios: ** ** a) When reading a free-list leaf page from the database, and ** ** b) When a savepoint is being rolled back and we need to load ** a new page into the cache to be filled with the data read ** from the savepoint journal. ** ** If PAGER_GET_NOCONTENT is true, then the data returned is zeroed instead ** of being read from the database. Additionally, the bits corresponding ** to pgno in Pager.pInJournal (bitvec of pages already written to the ** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open ** savepoints are set. This means if the page is made writable at any ** point in the future, using a call to sqlite3PagerWrite(), its contents ** will not be journaled. This saves IO. ** ** The acquisition might fail for several reasons. In all cases, ** an appropriate error code is returned and *ppPage is set to NULL. ** ** See also sqlite3PagerLookup(). Both this routine and Lookup() attempt ** to find a page in the in-memory cache first. If the page is not already ** in memory, this routine goes to disk to read it in whereas Lookup() ** just returns 0. This routine acquires a read-lock the first time it ** has to go to disk, and could also playback an old journal if necessary. ** Since Lookup() never goes to disk, it never has to deal with locks ** or journal files. */ static int getPageNormal( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ int rc = SQLITE_OK; PgHdr *pPg; u8 noContent; /* True if PAGER_GET_NOCONTENT is set */ sqlite3_pcache_page *pBase; assert( pPager->errCode==SQLITE_OK ); assert( pPager->eState>=PAGER_READER ); assert( assert_pager_state(pPager) ); assert( pPager->hasHeldSharedLock==1 ); if( pgno==0 ) return SQLITE_CORRUPT_BKPT; pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); if( pBase==0 ){ pPg = 0; rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase); if( rc!=SQLITE_OK ) goto pager_acquire_err; if( pBase==0 ){ rc = SQLITE_NOMEM_BKPT; goto pager_acquire_err; } } pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase); assert( pPg==(*ppPage) ); assert( pPg->pgno==pgno ); assert( pPg->pPager==pPager || pPg->pPager==0 ); noContent = (flags & PAGER_GET_NOCONTENT)!=0; if( pPg->pPager && !noContent ){ /* In this case the pcache already contains an initialized copy of ** the page. Return without further ado. */ assert( pgno!=PAGER_SJ_PGNO(pPager) ); pPager->aStat[PAGER_STAT_HIT]++; return SQLITE_OK; }else{ /* The pager cache has created a new page. Its content needs to ** be initialized. But first some error checks: ** ** (*) obsolete. Was: maximum page number is 2^31 ** (2) Never try to fetch the locking page */ if( pgno==PAGER_SJ_PGNO(pPager) ){ rc = SQLITE_CORRUPT_BKPT; goto pager_acquire_err; } pPg->pPager = pPager; assert( !isOpen(pPager->fd) || !MEMDB ); if( !isOpen(pPager->fd) || pPager->dbSizepPager->mxPgno ){ rc = SQLITE_FULL; if( pgno<=pPager->dbSize ){ sqlite3PcacheRelease(pPg); pPg = 0; } goto pager_acquire_err; } if( noContent ){ /* Failure to set the bits in the InJournal bit-vectors is benign. ** It merely means that we might do some extra work to journal a ** page that does not need to be journaled. Nevertheless, be sure ** to test the case where a malloc error occurs while trying to set ** a bit in a bit vector. */ sqlite3BeginBenignMalloc(); if( pgno<=pPager->dbOrigSize ){ TESTONLY( rc = ) sqlite3BitvecSet(pPager->pInJournal, pgno); testcase( rc==SQLITE_NOMEM ); } TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno); testcase( rc==SQLITE_NOMEM ); sqlite3EndBenignMalloc(); } memset(pPg->pData, 0, pPager->pageSize); IOTRACE(("ZERO %p %d\n", pPager, pgno)); }else{ assert( pPg->pPager==pPager ); pPager->aStat[PAGER_STAT_MISS]++; rc = readDbPage(pPg); if( rc!=SQLITE_OK ){ goto pager_acquire_err; } } pager_set_pagehash(pPg); } return SQLITE_OK; pager_acquire_err: assert( rc!=SQLITE_OK ); if( pPg ){ sqlite3PcacheDrop(pPg); } pagerUnlockIfUnused(pPager); *ppPage = 0; return rc; } #if SQLITE_MAX_MMAP_SIZE>0 /* The page getter for when memory-mapped I/O is enabled */ static int getPageMMap( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ int rc = SQLITE_OK; PgHdr *pPg = 0; u32 iFrame = 0; /* Frame to read from WAL file */ /* It is acceptable to use a read-only (mmap) page for any page except ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY ** flag was specified by the caller. And so long as the db is not a ** temporary or in-memory database. */ const int bMmapOk = (pgno>1 && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY)) ); assert( USEFETCH(pPager) ); /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here ** allows the compiler optimizer to reuse the results of the "pgno>1" ** test in the previous statement, and avoid testing pgno==0 in the ** common case where pgno is large. */ if( pgno<=1 && pgno==0 ){ return SQLITE_CORRUPT_BKPT; } assert( pPager->eState>=PAGER_READER ); assert( assert_pager_state(pPager) ); assert( pPager->hasHeldSharedLock==1 ); assert( pPager->errCode==SQLITE_OK ); if( bMmapOk && pagerUseWal(pPager) ){ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); if( rc!=SQLITE_OK ){ *ppPage = 0; return rc; } } if( bMmapOk && iFrame==0 ){ void *pData = 0; rc = sqlite3OsFetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData ); if( rc==SQLITE_OK && pData ){ if( pPager->eState>PAGER_READER || pPager->tempFile ){ pPg = sqlite3PagerLookup(pPager, pgno); } if( pPg==0 ){ rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg); }else{ sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData); } if( pPg ){ assert( rc==SQLITE_OK ); *ppPage = pPg; return SQLITE_OK; } } if( rc!=SQLITE_OK ){ *ppPage = 0; return rc; } } return getPageNormal(pPager, pgno, ppPage, flags); } #endif /* SQLITE_MAX_MMAP_SIZE>0 */ /* The page getter method for when the pager is an error state */ static int getPageError( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ UNUSED_PARAMETER(pgno); UNUSED_PARAMETER(flags); assert( pPager->errCode!=SQLITE_OK ); *ppPage = 0; return pPager->errCode; } /* Dispatch all page fetch requests to the appropriate getter method. */ SQLITE_PRIVATE int sqlite3PagerGet( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ #if 0 /* Trace page fetch by setting to 1 */ int rc; printf("PAGE %u\n", pgno); fflush(stdout); rc = pPager->xGet(pPager, pgno, ppPage, flags); if( rc ){ printf("PAGE %u failed with 0x%02x\n", pgno, rc); fflush(stdout); } return rc; #else /* Normal, high-speed version of sqlite3PagerGet() */ return pPager->xGet(pPager, pgno, ppPage, flags); #endif } /* ** Acquire a page if it is already in the in-memory cache. Do ** not read the page from disk. Return a pointer to the page, ** or 0 if the page is not in cache. ** ** See also sqlite3PagerGet(). The difference between this routine ** and sqlite3PagerGet() is that _get() will go to the disk and read ** in the page if the page is not already in cache. This routine ** returns NULL if the page is not in cache or if a disk I/O error ** has ever happened. */ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ sqlite3_pcache_page *pPage; assert( pPager!=0 ); assert( pgno!=0 ); assert( pPager->pPCache!=0 ); pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0); assert( pPage==0 || pPager->hasHeldSharedLock ); if( pPage==0 ) return 0; return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage); } /* ** Release a page reference. ** ** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be used ** if we know that the page being released is not the last reference to page1. ** The btree layer always holds page1 open until the end, so these first ** two routines can be used to release any page other than BtShared.pPage1. ** The assert() at tag-20230419-2 proves that this constraint is always ** honored. ** ** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine ** checks the total number of outstanding pages and if the number of ** pages reaches zero it drops the database lock. */ SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){ TESTONLY( Pager *pPager = pPg->pPager; ) assert( pPg!=0 ); if( pPg->flags & PGHDR_MMAP ){ assert( pPg->pgno!=1 ); /* Page1 is never memory mapped */ pagerReleaseMapPage(pPg); }else{ sqlite3PcacheRelease(pPg); } /* Do not use this routine to release the last reference to page1 */ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); /* tag-20230419-2 */ } SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){ if( pPg ) sqlite3PagerUnrefNotNull(pPg); } SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage *pPg){ Pager *pPager; assert( pPg!=0 ); assert( pPg->pgno==1 ); assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */ pPager = pPg->pPager; sqlite3PcacheRelease(pPg); pagerUnlockIfUnused(pPager); } /* ** This function is called at the start of every write transaction. ** There must already be a RESERVED or EXCLUSIVE lock on the database ** file when this routine is called. ** ** Open the journal file for pager pPager and write a journal header ** to the start of it. If there are active savepoints, open the sub-journal ** as well. This function is only used when the journal file is being ** opened to write a rollback log for a transaction. It is not used ** when opening a hot journal file to roll it back. ** ** If the journal file is already open (as it may be in exclusive mode), ** then this function just writes a journal header to the start of the ** already open file. ** ** Whether or not the journal file is opened by this function, the ** Pager.pInJournal bitvec structure is allocated. ** ** Return SQLITE_OK if everything is successful. Otherwise, return ** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or ** an IO error code if opening or writing the journal file fails. */ static int pager_open_journal(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */ assert( pPager->eState==PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); assert( pPager->pInJournal==0 ); /* If already in the error state, this function is a no-op. But on ** the other hand, this routine is never called if we are already in ** an error state. */ if( NEVER(pPager->errCode) ) return pPager->errCode; if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize); if( pPager->pInJournal==0 ){ return SQLITE_NOMEM_BKPT; } /* Open the journal file if it is not already open. */ if( !isOpen(pPager->jfd) ){ if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){ sqlite3MemJournalOpen(pPager->jfd); }else{ int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; int nSpill; if( pPager->tempFile ){ flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL); flags |= SQLITE_OPEN_EXCLUSIVE; nSpill = sqlite3Config.nStmtSpill; }else{ flags |= SQLITE_OPEN_MAIN_JOURNAL; nSpill = jrnlBufferSize(pPager); } /* Verify that the database still has the same name as it did when ** it was originally opened. */ rc = databaseIsUnmoved(pPager); if( rc==SQLITE_OK ){ rc = sqlite3JournalOpen ( pVfs, pPager->zJournal, pPager->jfd, flags, nSpill ); } } assert( rc!=SQLITE_OK || isOpen(pPager->jfd) ); } /* Write the first journal header to the journal file and open ** the sub-journal if necessary. */ if( rc==SQLITE_OK ){ /* TODO: Check if all of these are really required. */ pPager->nRec = 0; pPager->journalOff = 0; pPager->setSuper = 0; pPager->journalHdr = 0; rc = writeJournalHdr(pPager); } } if( rc!=SQLITE_OK ){ sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; pPager->journalOff = 0; }else{ assert( pPager->eState==PAGER_WRITER_LOCKED ); pPager->eState = PAGER_WRITER_CACHEMOD; } return rc; } /* ** Begin a write-transaction on the specified pager object. If a ** write-transaction has already been opened, this function is a no-op. ** ** If the exFlag argument is false, then acquire at least a RESERVED ** lock on the database file. If exFlag is true, then acquire at least ** an EXCLUSIVE lock. If such a lock is already held, no locking ** functions need be called. ** ** If the subjInMemory argument is non-zero, then any sub-journal opened ** within this transaction will be opened as an in-memory file. This ** has no effect if the sub-journal is already opened (as it may be when ** running in exclusive mode) or if the transaction does not require a ** sub-journal. If the subjInMemory argument is zero, then any required ** sub-journal is implemented in-memory if pPager is an in-memory database, ** or using a temporary file otherwise. */ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){ int rc = SQLITE_OK; if( pPager->errCode ) return pPager->errCode; assert( pPager->eState>=PAGER_READER && pPager->eStatesubjInMemory = (u8)subjInMemory; if( pPager->eState==PAGER_READER ){ assert( pPager->pInJournal==0 ); if( pagerUseWal(pPager) ){ /* If the pager is configured to use locking_mode=exclusive, and an ** exclusive lock on the database is not already held, obtain it now. */ if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ return rc; } (void)sqlite3WalExclusiveMode(pPager->pWal, 1); } /* Grab the write lock on the log file. If successful, upgrade to ** PAGER_RESERVED state. Otherwise, return an error code to the caller. ** The busy-handler is not invoked if another connection already ** holds the write-lock. If possible, the upper layer will call it. */ rc = sqlite3WalBeginWriteTransaction(pPager->pWal); }else{ /* Obtain a RESERVED lock on the database file. If the exFlag parameter ** is true, then immediately upgrade this to an EXCLUSIVE lock. The ** busy-handler callback can be used when upgrading to the EXCLUSIVE ** lock, but not when obtaining the RESERVED lock. */ rc = pagerLockDb(pPager, RESERVED_LOCK); if( rc==SQLITE_OK && exFlag ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } } if( rc==SQLITE_OK ){ /* Change to WRITER_LOCKED state. ** ** WAL mode sets Pager.eState to PAGER_WRITER_LOCKED or CACHEMOD ** when it has an open transaction, but never to DBMOD or FINISHED. ** This is because in those states the code to roll back savepoint ** transactions may copy data from the sub-journal into the database ** file as well as into the page cache. Which would be incorrect in ** WAL mode. */ pPager->eState = PAGER_WRITER_LOCKED; pPager->dbHintSize = pPager->dbSize; pPager->dbFileSize = pPager->dbSize; pPager->dbOrigSize = pPager->dbSize; pPager->journalOff = 0; } assert( rc==SQLITE_OK || pPager->eState==PAGER_READER ); assert( rc!=SQLITE_OK || pPager->eState==PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); } PAGERTRACE(("TRANSACTION %d\n", PAGERID(pPager))); return rc; } /* ** Write page pPg onto the end of the rollback journal. */ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ Pager *pPager = pPg->pPager; int rc; u32 cksum; char *pData2; i64 iOff = pPager->journalOff; /* We should never write to the journal file the page that ** contains the database locks. The following assert verifies ** that we do not. */ assert( pPg->pgno!=PAGER_SJ_PGNO(pPager) ); assert( pPager->journalHdr<=pPager->journalOff ); pData2 = pPg->pData; cksum = pager_cksum(pPager, (u8*)pData2); /* Even if an IO or diskfull error occurs while journalling the ** page in the block above, set the need-sync flag for the page. ** Otherwise, when the transaction is rolled back, the logic in ** playback_one_page() will think that the page needs to be restored ** in the database file. And if an IO error occurs while doing so, ** then corruption may follow. */ pPg->flags |= PGHDR_NEED_SYNC; rc = write32bits(pPager->jfd, iOff, pPg->pgno); if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, iOff+4); if( rc!=SQLITE_OK ) return rc; rc = write32bits(pPager->jfd, iOff+pPager->pageSize+4, cksum); if( rc!=SQLITE_OK ) return rc; IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, pPager->journalOff, pPager->pageSize)); PAGER_INCR(sqlite3_pager_writej_count); PAGERTRACE(("JOURNAL %d page %d needSync=%d hash(%08x)\n", PAGERID(pPager), pPg->pgno, ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg))); pPager->journalOff += 8 + pPager->pageSize; pPager->nRec++; assert( pPager->pInJournal!=0 ); rc = sqlite3BitvecSet(pPager->pInJournal, pPg->pgno); testcase( rc==SQLITE_NOMEM ); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); rc |= addToSavepointBitvecs(pPager, pPg->pgno); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); return rc; } /* ** Mark a single data page as writeable. The page is written into the ** main journal or sub-journal as required. If the page is written into ** one of the journals, the corresponding bit is set in the ** Pager.pInJournal bitvec and the PagerSavepoint.pInSavepoint bitvecs ** of any open savepoints as appropriate. */ static int pager_write(PgHdr *pPg){ Pager *pPager = pPg->pPager; int rc = SQLITE_OK; /* This routine is not called unless a write-transaction has already ** been started. The journal file may or may not be open at this point. ** It is never called in the ERROR state. */ assert( pPager->eState==PAGER_WRITER_LOCKED || pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_DBMOD ); assert( assert_pager_state(pPager) ); assert( pPager->errCode==0 ); assert( pPager->readOnly==0 ); CHECK_PAGE(pPg); /* The journal file needs to be opened. Higher level routines have already ** obtained the necessary locks to begin the write-transaction, but the ** rollback journal might not yet be open. Open it now if this is the case. ** ** This is done before calling sqlite3PcacheMakeDirty() on the page. ** Otherwise, if it were done after calling sqlite3PcacheMakeDirty(), then ** an error might occur and the pager would end up in WRITER_LOCKED state ** with pages marked as dirty in the cache. */ if( pPager->eState==PAGER_WRITER_LOCKED ){ rc = pager_open_journal(pPager); if( rc!=SQLITE_OK ) return rc; } assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); assert( assert_pager_state(pPager) ); /* Mark the page that is about to be modified as dirty. */ sqlite3PcacheMakeDirty(pPg); /* If a rollback journal is in use, them make sure the page that is about ** to change is in the rollback journal, or if the page is a new page off ** then end of the file, make sure it is marked as PGHDR_NEED_SYNC. */ assert( (pPager->pInJournal!=0) == isOpen(pPager->jfd) ); if( pPager->pInJournal!=0 && sqlite3BitvecTestNotNull(pPager->pInJournal, pPg->pgno)==0 ){ assert( pagerUseWal(pPager)==0 ); if( pPg->pgno<=pPager->dbOrigSize ){ rc = pagerAddPageToRollbackJournal(pPg); if( rc!=SQLITE_OK ){ return rc; } }else{ if( pPager->eState!=PAGER_WRITER_DBMOD ){ pPg->flags |= PGHDR_NEED_SYNC; } PAGERTRACE(("APPEND %d page %d needSync=%d\n", PAGERID(pPager), pPg->pgno, ((pPg->flags&PGHDR_NEED_SYNC)?1:0))); } } /* The PGHDR_DIRTY bit is set above when the page was added to the dirty-list ** and before writing the page into the rollback journal. Wait until now, ** after the page has been successfully journalled, before setting the ** PGHDR_WRITEABLE bit that indicates that the page can be safely modified. */ pPg->flags |= PGHDR_WRITEABLE; /* If the statement journal is open and the page is not in it, ** then write the page into the statement journal. */ if( pPager->nSavepoint>0 ){ rc = subjournalPageIfRequired(pPg); } /* Update the database size and return. */ if( pPager->dbSizepgno ){ pPager->dbSize = pPg->pgno; } return rc; } /* ** This is a variant of sqlite3PagerWrite() that runs when the sector size ** is larger than the page size. SQLite makes the (reasonable) assumption that ** all bytes of a sector are written together by hardware. Hence, all bytes of ** a sector need to be journalled in case of a power loss in the middle of ** a write. ** ** Usually, the sector size is less than or equal to the page size, in which ** case pages can be individually written. This routine only runs in the ** exceptional case where the page size is smaller than the sector size. */ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){ int rc = SQLITE_OK; /* Return code */ Pgno nPageCount; /* Total number of pages in database file */ Pgno pg1; /* First page of the sector pPg is located on. */ int nPage = 0; /* Number of pages starting at pg1 to journal */ int ii; /* Loop counter */ int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */ Pager *pPager = pPg->pPager; /* The pager that owns pPg */ Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow ** a journal header to be written between the pages journaled by ** this function. */ assert( !MEMDB ); assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 ); pPager->doNotSpill |= SPILLFLAG_NOSYNC; /* This trick assumes that both the page-size and sector-size are ** an integer power of 2. It sets variable pg1 to the identifier ** of the first page of the sector pPg is located on. */ pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1; nPageCount = pPager->dbSize; if( pPg->pgno>nPageCount ){ nPage = (pPg->pgno - pg1)+1; }else if( (pg1+nPagePerSector-1)>nPageCount ){ nPage = nPageCount+1-pg1; }else{ nPage = nPagePerSector; } assert(nPage>0); assert(pg1<=pPg->pgno); assert((pg1+nPage)>pPg->pgno); for(ii=0; iipgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ if( pg!=PAGER_SJ_PGNO(pPager) ){ rc = sqlite3PagerGet(pPager, pg, &pPage, 0); if( rc==SQLITE_OK ){ rc = pager_write(pPage); if( pPage->flags&PGHDR_NEED_SYNC ){ needSync = 1; } sqlite3PagerUnrefNotNull(pPage); } } }else if( (pPage = sqlite3PagerLookup(pPager, pg))!=0 ){ if( pPage->flags&PGHDR_NEED_SYNC ){ needSync = 1; } sqlite3PagerUnrefNotNull(pPage); } } /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages ** starting at pg1, then it needs to be set for all of them. Because ** writing to any of these nPage pages may damage the others, the ** journal file must contain sync()ed copies of all of them ** before any of them can be written out to the database file. */ if( rc==SQLITE_OK && needSync ){ assert( !MEMDB ); for(ii=0; iiflags |= PGHDR_NEED_SYNC; sqlite3PagerUnrefNotNull(pPage); } } } assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 ); pPager->doNotSpill &= ~SPILLFLAG_NOSYNC; return rc; } /* ** Mark a data page as writeable. This routine must be called before ** making changes to a page. The caller must check the return value ** of this function and be careful not to change any page data unless ** this routine returns SQLITE_OK. ** ** The difference between this function and pager_write() is that this ** function also deals with the special case where 2 or more pages ** fit on a single disk sector. In this case all co-resident pages ** must have been written to the journal file before returning. ** ** If an error occurs, SQLITE_NOMEM or an IO error code is returned ** as appropriate. Otherwise, SQLITE_OK. */ SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){ Pager *pPager = pPg->pPager; assert( (pPg->flags & PGHDR_MMAP)==0 ); assert( pPager->eState>=PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){ if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg); return SQLITE_OK; }else if( pPager->errCode ){ return pPager->errCode; }else if( pPager->sectorSize > (u32)pPager->pageSize ){ assert( pPager->tempFile==0 ); return pagerWriteLargeSector(pPg); }else{ return pager_write(pPg); } } /* ** Return TRUE if the page given in the argument was previously passed ** to sqlite3PagerWrite(). In other words, return TRUE if it is ok ** to change the content of the page. */ #ifndef NDEBUG SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){ return pPg->flags & PGHDR_WRITEABLE; } #endif /* ** A call to this routine tells the pager that it is not necessary to ** write the information on page pPg back to the disk, even though ** that page might be marked as dirty. This happens, for example, when ** the page has been added as a leaf of the freelist and so its ** content no longer matters. ** ** The overlying software layer calls this routine when all of the data ** on the given page is unused. The pager marks the page as clean so ** that it does not get written to disk. ** ** Tests show that this optimization can quadruple the speed of large ** DELETE operations. ** ** This optimization cannot be used with a temp-file, as the page may ** have been dirty at the start of the transaction. In that case, if ** memory pressure forces page pPg out of the cache, the data does need ** to be written out to disk so that it may be read back in if the ** current transaction is rolled back. */ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){ Pager *pPager = pPg->pPager; if( !pPager->tempFile && (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){ PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager))); IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno)) pPg->flags |= PGHDR_DONT_WRITE; pPg->flags &= ~PGHDR_WRITEABLE; testcase( pPg->flags & PGHDR_NEED_SYNC ); pager_set_pagehash(pPg); } } /* ** This routine is called to increment the value of the database file ** change-counter, stored as a 4-byte big-endian integer starting at ** byte offset 24 of the pager file. The secondary change counter at ** 92 is also updated, as is the SQLite version number at offset 96. ** ** But this only happens if the pPager->changeCountDone flag is false. ** To avoid excess churning of page 1, the update only happens once. ** See also the pager_write_changecounter() routine that does an ** unconditional update of the change counters. ** ** If the isDirectMode flag is zero, then this is done by calling ** sqlite3PagerWrite() on page 1, then modifying the contents of the ** page data. In this case the file will be updated when the current ** transaction is committed. ** ** The isDirectMode flag may only be non-zero if the library was compiled ** with the SQLITE_ENABLE_ATOMIC_WRITE macro defined. In this case, ** if isDirect is non-zero, then the database file is updated directly ** by writing an updated version of page 1 using a call to the ** sqlite3OsWrite() function. */ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ int rc = SQLITE_OK; assert( pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_DBMOD ); assert( assert_pager_state(pPager) ); /* Declare and initialize constant integer 'isDirect'. If the ** atomic-write optimization is enabled in this build, then isDirect ** is initialized to the value passed as the isDirectMode parameter ** to this function. Otherwise, it is always set to zero. ** ** The idea is that if the atomic-write optimization is not ** enabled at compile time, the compiler can omit the tests of ** 'isDirect' below, as well as the block enclosed in the ** "if( isDirect )" condition. */ #ifndef SQLITE_ENABLE_ATOMIC_WRITE # define DIRECT_MODE 0 assert( isDirectMode==0 ); UNUSED_PARAMETER(isDirectMode); #else # define DIRECT_MODE isDirectMode #endif if( !pPager->changeCountDone && pPager->dbSize>0 ){ PgHdr *pPgHdr; /* Reference to page 1 */ assert( !pPager->tempFile && isOpen(pPager->fd) ); /* Open page 1 of the file for writing. */ rc = sqlite3PagerGet(pPager, 1, &pPgHdr, 0); assert( pPgHdr==0 || rc==SQLITE_OK ); /* If page one was fetched successfully, and this function is not ** operating in direct-mode, make page 1 writable. When not in ** direct mode, page 1 is always held in cache and hence the PagerGet() ** above is always successful - hence the ALWAYS on rc==SQLITE_OK. */ if( !DIRECT_MODE && ALWAYS(rc==SQLITE_OK) ){ rc = sqlite3PagerWrite(pPgHdr); } if( rc==SQLITE_OK ){ /* Actually do the update of the change counter */ pager_write_changecounter(pPgHdr); /* If running in direct mode, write the contents of page 1 to the file. */ if( DIRECT_MODE ){ const void *zBuf; assert( pPager->dbFileSize>0 ); zBuf = pPgHdr->pData; if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); pPager->aStat[PAGER_STAT_WRITE]++; } if( rc==SQLITE_OK ){ /* Update the pager's copy of the change-counter. Otherwise, the ** next time a read transaction is opened the cache will be ** flushed (as the change-counter values will not match). */ const void *pCopy = (const void *)&((const char *)zBuf)[24]; memcpy(&pPager->dbFileVers, pCopy, sizeof(pPager->dbFileVers)); pPager->changeCountDone = 1; } }else{ pPager->changeCountDone = 1; } } /* Release the page reference. */ sqlite3PagerUnref(pPgHdr); } return rc; } /* ** Sync the database file to disk. This is a no-op for in-memory databases ** or pages with the Pager.noSync flag set. ** ** If successful, or if called on a pager for which it is a no-op, this ** function returns SQLITE_OK. Otherwise, an IO error code is returned. */ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper){ int rc = SQLITE_OK; void *pArg = (void*)zSuper; rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg); if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; if( rc==SQLITE_OK && !pPager->noSync ){ assert( !MEMDB ); rc = sqlite3OsSync(pPager->fd, pPager->syncFlags); } return rc; } /* ** This function may only be called while a write-transaction is active in ** rollback. If the connection is in WAL mode, this call is a no-op. ** Otherwise, if the connection does not already have an EXCLUSIVE lock on ** the database file, an attempt is made to obtain one. ** ** If the EXCLUSIVE lock is already held or the attempt to obtain it is ** successful, or the connection is in WAL mode, SQLITE_OK is returned. ** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is ** returned. */ SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){ int rc = pPager->errCode; assert( assert_pager_state(pPager) ); if( rc==SQLITE_OK ){ assert( pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_DBMOD || pPager->eState==PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); if( 0==pagerUseWal(pPager) ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } } return rc; } /* ** Sync the database file for the pager pPager. zSuper points to the name ** of a super-journal file that should be written into the individual ** journal file. zSuper may be NULL, which is interpreted as no ** super-journal (a single database transaction). ** ** This routine ensures that: ** ** * The database file change-counter is updated, ** * the journal is synced (unless the atomic-write optimization is used), ** * all dirty pages are written to the database file, ** * the database file is truncated (if required), and ** * the database file synced. ** ** The only thing that remains to commit the transaction is to finalize ** (delete, truncate or zero the first part of) the journal file (or ** delete the super-journal file if specified). ** ** Note that if zSuper==NULL, this does not overwrite a previous value ** passed to an sqlite3PagerCommitPhaseOne() call. ** ** If the final parameter - noSync - is true, then the database file itself ** is not synced. The caller must call sqlite3PagerSync() directly to ** sync the database file before calling CommitPhaseTwo() to delete the ** journal file in this case. */ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( Pager *pPager, /* Pager object */ const char *zSuper, /* If not NULL, the super-journal name */ int noSync /* True to omit the xSync on the db file */ ){ int rc = SQLITE_OK; /* Return code */ assert( pPager->eState==PAGER_WRITER_LOCKED || pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_DBMOD || pPager->eState==PAGER_ERROR ); assert( assert_pager_state(pPager) ); /* If a prior error occurred, report that error again. */ if( NEVER(pPager->errCode) ) return pPager->errCode; /* Provide the ability to easily simulate an I/O error during testing */ if( sqlite3FaultSim(400) ) return SQLITE_IOERR; PAGERTRACE(("DATABASE SYNC: File=%s zSuper=%s nSize=%d\n", pPager->zFilename, zSuper, pPager->dbSize)); /* If no database changes have been made, return early. */ if( pPager->eStatetempFile ); assert( isOpen(pPager->fd) || pPager->tempFile ); if( 0==pagerFlushOnCommit(pPager, 1) ){ /* If this is an in-memory db, or no pages have been written to, or this ** function has already been called, it is mostly a no-op. However, any ** backup in progress needs to be restarted. */ sqlite3BackupRestart(pPager->pBackup); }else{ PgHdr *pList; if( pagerUseWal(pPager) ){ PgHdr *pPageOne = 0; pList = sqlite3PcacheDirtyList(pPager->pPCache); if( pList==0 ){ /* Must have at least one page for the WAL commit flag. ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */ rc = sqlite3PagerGet(pPager, 1, &pPageOne, 0); pList = pPageOne; pList->pDirty = 0; } assert( rc==SQLITE_OK ); if( ALWAYS(pList) ){ rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1); } sqlite3PagerUnref(pPageOne); if( rc==SQLITE_OK ){ sqlite3PcacheCleanAll(pPager->pPCache); } }else{ /* The bBatch boolean is true if the batch-atomic-write commit method ** should be used. No rollback journal is created if batch-atomic-write ** is enabled. */ #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE sqlite3_file *fd = pPager->fd; int bBatch = zSuper==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */ && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC) && !pPager->noSync && sqlite3JournalIsInMemory(pPager->jfd); #else # define bBatch 0 #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE /* The following block updates the change-counter. Exactly how it ** does this depends on whether or not the atomic-update optimization ** was enabled at compile time, and if this transaction meets the ** runtime criteria to use the operation: ** ** * The file-system supports the atomic-write property for ** blocks of size page-size, and ** * This commit is not part of a multi-file transaction, and ** * Exactly one page has been modified and store in the journal file. ** ** If the optimization was not enabled at compile time, then the ** pager_incr_changecounter() function is called to update the change ** counter in 'indirect-mode'. If the optimization is compiled in but ** is not applicable to this transaction, call sqlite3JournalCreate() ** to make sure the journal file has actually been created, then call ** pager_incr_changecounter() to update the change-counter in indirect ** mode. ** ** Otherwise, if the optimization is both enabled and applicable, ** then call pager_incr_changecounter() to update the change-counter ** in 'direct' mode. In this case the journal file will never be ** created for this transaction. */ if( bBatch==0 ){ PgHdr *pPg; assert( isOpen(pPager->jfd) || pPager->journalMode==PAGER_JOURNALMODE_OFF || pPager->journalMode==PAGER_JOURNALMODE_WAL ); if( !zSuper && isOpen(pPager->jfd) && pPager->journalOff==jrnlBufferSize(pPager) && pPager->dbSize>=pPager->dbOrigSize && (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty) ){ /* Update the db file change counter via the direct-write method. The ** following call will modify the in-memory representation of page 1 ** to include the updated change counter and then write page 1 ** directly to the database file. Because of the atomic-write ** property of the host file-system, this is safe. */ rc = pager_incr_changecounter(pPager, 1); }else{ rc = sqlite3JournalCreate(pPager->jfd); if( rc==SQLITE_OK ){ rc = pager_incr_changecounter(pPager, 0); } } } #else /* SQLITE_ENABLE_ATOMIC_WRITE */ #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE if( zSuper ){ rc = sqlite3JournalCreate(pPager->jfd); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; assert( bBatch==0 ); } #endif rc = pager_incr_changecounter(pPager, 0); #endif /* !SQLITE_ENABLE_ATOMIC_WRITE */ if( rc!=SQLITE_OK ) goto commit_phase_one_exit; /* Write the super-journal name into the journal file. If a ** super-journal file name has already been written to the journal file, ** or if zSuper is NULL (no super-journal), then this call is a no-op. */ rc = writeSuperJournal(pPager, zSuper); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; /* Sync the journal file and write all dirty pages to the database. ** If the atomic-update optimization is being used, this sync will not ** create the journal file or perform any real IO. ** ** Because the change-counter page was just modified, unless the ** atomic-update optimization is used it is almost certain that the ** journal requires a sync here. However, in locking_mode=exclusive ** on a system under memory pressure it is just possible that this is ** not the case. In this case it is likely enough that the redundant ** xSync() call will be changed to a no-op by the OS anyhow. */ rc = syncJournal(pPager, 0); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; pList = sqlite3PcacheDirtyList(pPager->pPCache); #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE if( bBatch ){ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0); if( rc==SQLITE_OK ){ rc = pager_write_pagelist(pPager, pList); if( rc==SQLITE_OK && pPager->dbSize>pPager->dbFileSize ){ char *pTmp = pPager->pTmpSpace; int szPage = (int)pPager->pageSize; memset(pTmp, 0, szPage); rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, ((i64)pPager->dbSize*pPager->pageSize)-szPage); } if( rc==SQLITE_OK ){ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0); } if( rc!=SQLITE_OK ){ sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0); } } if( (rc&0xFF)==SQLITE_IOERR && rc!=SQLITE_IOERR_NOMEM ){ rc = sqlite3JournalCreate(pPager->jfd); if( rc!=SQLITE_OK ){ sqlite3OsClose(pPager->jfd); goto commit_phase_one_exit; } bBatch = 0; }else{ sqlite3OsClose(pPager->jfd); } } #endif /* SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ if( bBatch==0 ){ rc = pager_write_pagelist(pPager, pList); } if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_IOERR_BLOCKED ); goto commit_phase_one_exit; } sqlite3PcacheCleanAll(pPager->pPCache); /* If the file on disk is smaller than the database image, use ** pager_truncate to grow the file here. This can happen if the database ** image was extended as part of the current transaction and then the ** last page in the db image moved to the free-list. In this case the ** last page is never written out to disk, leaving the database file ** undersized. Fix this now if it is the case. */ if( pPager->dbSize>pPager->dbFileSize ){ Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_SJ_PGNO(pPager)); assert( pPager->eState==PAGER_WRITER_DBMOD ); rc = pager_truncate(pPager, nNew); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; } /* Finally, sync the database file. */ if( !noSync ){ rc = sqlite3PagerSync(pPager, zSuper); } IOTRACE(("DBSYNC %p\n", pPager)) } } commit_phase_one_exit: if( rc==SQLITE_OK && !pagerUseWal(pPager) ){ pPager->eState = PAGER_WRITER_FINISHED; } return rc; } /* ** When this function is called, the database file has been completely ** updated to reflect the changes made by the current transaction and ** synced to disk. The journal file still exists in the file-system ** though, and if a failure occurs at this point it will eventually ** be used as a hot-journal and the current transaction rolled back. ** ** This function finalizes the journal file, either by deleting, ** truncating or partially zeroing it, so that it cannot be used ** for hot-journal rollback. Once this is done the transaction is ** irrevocably committed. ** ** If an error occurs, an IO error code is returned and the pager ** moves into the error state. Otherwise, SQLITE_OK is returned. */ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ /* This routine should not be called if a prior error has occurred. ** But if (due to a coding error elsewhere in the system) it does get ** called, just return the same error code without doing anything. */ if( NEVER(pPager->errCode) ) return pPager->errCode; pPager->iDataVersion++; assert( pPager->eState==PAGER_WRITER_LOCKED || pPager->eState==PAGER_WRITER_FINISHED || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD) ); assert( assert_pager_state(pPager) ); /* An optimization. If the database was not actually modified during ** this transaction, the pager is running in exclusive-mode and is ** using persistent journals, then this function is a no-op. ** ** The start of the journal file currently contains a single journal ** header with the nRec field set to 0. If such a journal is used as ** a hot-journal during hot-journal rollback, 0 changes will be made ** to the database file. So there is no need to zero the journal ** header. Since the pager is in exclusive mode, there is no need ** to drop any locks either. */ if( pPager->eState==PAGER_WRITER_LOCKED && pPager->exclusiveMode && pPager->journalMode==PAGER_JOURNALMODE_PERSIST ){ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff ); pPager->eState = PAGER_READER; return SQLITE_OK; } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); rc = pager_end_transaction(pPager, pPager->setSuper, 1); return pager_error(pPager, rc); } /* ** If a write transaction is open, then all changes made within the ** transaction are reverted and the current write-transaction is closed. ** The pager falls back to PAGER_READER state if successful, or PAGER_ERROR ** state if an error occurs. ** ** If the pager is already in PAGER_ERROR state when this function is called, ** it returns Pager.errCode immediately. No work is performed in this case. ** ** Otherwise, in rollback mode, this function performs two functions: ** ** 1) It rolls back the journal file, restoring all database file and ** in-memory cache pages to the state they were in when the transaction ** was opened, and ** ** 2) It finalizes the journal file, so that it is not used for hot ** rollback at any point in the future. ** ** Finalization of the journal file (task 2) is only performed if the ** rollback is successful. ** ** In WAL mode, all cache-entries containing data modified within the ** current transaction are either expelled from the cache or reverted to ** their pre-transaction state by re-reading data from the database or ** WAL files. The WAL transaction is then closed. */ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager))); /* PagerRollback() is a no-op if called in READER or OPEN state. If ** the pager is already in the ERROR state, the rollback is not ** attempted here. Instead, the error code is returned to the caller. */ assert( assert_pager_state(pPager) ); if( pPager->eState==PAGER_ERROR ) return pPager->errCode; if( pPager->eState<=PAGER_READER ) return SQLITE_OK; if( pagerUseWal(pPager) ){ int rc2; rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1); rc2 = pager_end_transaction(pPager, pPager->setSuper, 0); if( rc==SQLITE_OK ) rc = rc2; }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){ int eState = pPager->eState; rc = pager_end_transaction(pPager, 0, 0); if( !MEMDB && eState>PAGER_WRITER_LOCKED ){ /* This can happen using journal_mode=off. Move the pager to the error ** state to indicate that the contents of the cache may not be trusted. ** Any active readers will get SQLITE_ABORT. */ pPager->errCode = SQLITE_ABORT; pPager->eState = PAGER_ERROR; setGetterMethod(pPager); return rc; } }else{ rc = pager_playback(pPager, 0); } assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK ); assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR || rc==SQLITE_CANTOPEN ); /* If an error occurs during a ROLLBACK, we can no longer trust the pager ** cache. So call pager_error() on the way out to make any error persistent. */ return pager_error(pPager, rc); } /* ** Return TRUE if the database file is opened read-only. Return FALSE ** if the database is (in theory) writable. */ SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager *pPager){ return pPager->readOnly; } #ifdef SQLITE_DEBUG /* ** Return the sum of the reference counts for all pages held by pPager. */ SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){ return sqlite3PcacheRefCount(pPager->pPCache); } #endif /* ** Return the approximate number of bytes of memory currently ** used by the pager and its associated cache. */ SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){ int perPageSize = pPager->pageSize + pPager->nExtra + (int)(sizeof(PgHdr) + 5*sizeof(void*)); return perPageSize*sqlite3PcachePagecount(pPager->pPCache) + sqlite3MallocSize(pPager) + pPager->pageSize; } /* ** Return the number of references to the specified page. */ SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage *pPage){ return sqlite3PcachePageRefcount(pPage); } #ifdef SQLITE_TEST /* ** This routine is used for testing and analysis only. */ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){ static int a[11]; a[0] = sqlite3PcacheRefCount(pPager->pPCache); a[1] = sqlite3PcachePagecount(pPager->pPCache); a[2] = sqlite3PcacheGetCachesize(pPager->pPCache); a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize; a[4] = pPager->eState; a[5] = pPager->errCode; a[6] = (int)pPager->aStat[PAGER_STAT_HIT] & 0x7fffffff; a[7] = (int)pPager->aStat[PAGER_STAT_MISS] & 0x7fffffff; a[8] = 0; /* Used to be pPager->nOvfl */ a[9] = pPager->nRead; a[10] = (int)pPager->aStat[PAGER_STAT_WRITE] & 0x7fffffff; return a; } #endif /* ** Parameter eStat must be one of SQLITE_DBSTATUS_CACHE_HIT, _MISS, _WRITE, ** or _WRITE+1. The SQLITE_DBSTATUS_CACHE_WRITE+1 case is a translation ** of SQLITE_DBSTATUS_CACHE_SPILL. The _SPILL case is not contiguous because ** it was added later. ** ** Before returning, *pnVal is incremented by the ** current cache hit or miss count, according to the value of eStat. If the ** reset parameter is non-zero, the cache hit or miss count is zeroed before ** returning. */ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, u64 *pnVal){ assert( eStat==SQLITE_DBSTATUS_CACHE_HIT || eStat==SQLITE_DBSTATUS_CACHE_MISS || eStat==SQLITE_DBSTATUS_CACHE_WRITE || eStat==SQLITE_DBSTATUS_CACHE_WRITE+1 ); assert( SQLITE_DBSTATUS_CACHE_HIT+1==SQLITE_DBSTATUS_CACHE_MISS ); assert( SQLITE_DBSTATUS_CACHE_HIT+2==SQLITE_DBSTATUS_CACHE_WRITE ); assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 && PAGER_STAT_WRITE==2 && PAGER_STAT_SPILL==3 ); eStat -= SQLITE_DBSTATUS_CACHE_HIT; *pnVal += pPager->aStat[eStat]; if( reset ){ pPager->aStat[eStat] = 0; } } /* ** Return true if this is an in-memory or temp-file backed pager. */ SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){ return pPager->tempFile || pPager->memVfs; } /* ** Check that there are at least nSavepoint savepoints open. If there are ** currently less than nSavepoints open, then open one or more savepoints ** to make up the difference. If the number of savepoints is already ** equal to nSavepoint, then this function is a no-op. ** ** If a memory allocation fails, SQLITE_NOMEM is returned. If an error ** occurs while opening the sub-journal file, then an IO error code is ** returned. Otherwise, SQLITE_OK. */ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){ int rc = SQLITE_OK; /* Return code */ int nCurrent = pPager->nSavepoint; /* Current number of savepoints */ int ii; /* Iterator variable */ PagerSavepoint *aNew; /* New Pager.aSavepoint array */ assert( pPager->eState>=PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); assert( nSavepoint>nCurrent && pPager->useJournal ); /* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM ** if the allocation fails. Otherwise, zero the new portion in case a ** malloc failure occurs while populating it in the for(...) loop below. */ aNew = (PagerSavepoint *)sqlite3Realloc( pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint ); if( !aNew ){ return SQLITE_NOMEM_BKPT; } memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint)); pPager->aSavepoint = aNew; /* Populate the PagerSavepoint structures just allocated. */ for(ii=nCurrent; iidbSize; if( isOpen(pPager->jfd) && pPager->journalOff>0 ){ aNew[ii].iOffset = pPager->journalOff; }else{ aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager); } aNew[ii].iSubRec = pPager->nSubRec; aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize); aNew[ii].bTruncateOnRelease = 1; if( !aNew[ii].pInSavepoint ){ return SQLITE_NOMEM_BKPT; } if( pagerUseWal(pPager) ){ sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData); } pPager->nSavepoint = ii+1; } assert( pPager->nSavepoint==nSavepoint ); assertTruncateConstraint(pPager); return rc; } SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){ assert( pPager->eState>=PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); if( nSavepoint>pPager->nSavepoint && pPager->useJournal ){ return pagerOpenSavepoint(pPager, nSavepoint); }else{ return SQLITE_OK; } } /* ** This function is called to rollback or release (commit) a savepoint. ** The savepoint to release or rollback need not be the most recently ** created savepoint. ** ** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE. ** If it is SAVEPOINT_RELEASE, then release and destroy the savepoint with ** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes ** that have occurred since the specified savepoint was created. ** ** The savepoint to rollback or release is identified by parameter ** iSavepoint. A value of 0 means to operate on the outermost savepoint ** (the first created). A value of (Pager.nSavepoint-1) means operate ** on the most recently created savepoint. If iSavepoint is greater than ** (Pager.nSavepoint-1), then this function is a no-op. ** ** If a negative value is passed to this function, then the current ** transaction is rolled back. This is different to calling ** sqlite3PagerRollback() because this function does not terminate ** the transaction or unlock the database, it just restores the ** contents of the database to its original state. ** ** In any case, all savepoints with an index greater than iSavepoint ** are destroyed. If this is a release operation (op==SAVEPOINT_RELEASE), ** then savepoint iSavepoint is also destroyed. ** ** This function may return SQLITE_NOMEM if a memory allocation fails, ** or an IO error code if an IO error occurs while rolling back a ** savepoint. If no errors occur, SQLITE_OK is returned. */ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ int rc = pPager->errCode; #ifdef SQLITE_ENABLE_ZIPVFS if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK; #endif assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK ); assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK ); if( rc==SQLITE_OK && iSavepointnSavepoint ){ int ii; /* Iterator variable */ int nNew; /* Number of remaining savepoints after this op. */ /* Figure out how many savepoints will still be active after this ** operation. Store this value in nNew. Then free resources associated ** with any savepoints that are destroyed by this operation. */ nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1); for(ii=nNew; iinSavepoint; ii++){ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint); } pPager->nSavepoint = nNew; /* Truncate the sub-journal so that it only includes the parts ** that are still in use. */ if( op==SAVEPOINT_RELEASE ){ PagerSavepoint *pRel = &pPager->aSavepoint[nNew]; if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){ /* Only truncate if it is an in-memory sub-journal. */ if( sqlite3JournalIsInMemory(pPager->sjfd) ){ i64 sz = (pPager->pageSize+4)*(i64)pRel->iSubRec; rc = sqlite3OsTruncate(pPager->sjfd, sz); assert( rc==SQLITE_OK ); } pPager->nSubRec = pRel->iSubRec; } } /* Else this is a rollback operation, playback the specified savepoint. ** If this is a temp-file, it is possible that the journal file has ** not yet been opened. In this case there have been no changes to ** the database file, so the playback operation can be skipped. */ else if( pagerUseWal(pPager) || isOpen(pPager->jfd) ){ PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1]; rc = pagerPlaybackSavepoint(pPager, pSavepoint); assert(rc!=SQLITE_DONE); } #ifdef SQLITE_ENABLE_ZIPVFS /* If the cache has been modified but the savepoint cannot be rolled ** back journal_mode=off, put the pager in the error state. This way, ** if the VFS used by this pager includes ZipVFS, the entire transaction ** can be rolled back at the ZipVFS level. */ else if( pPager->journalMode==PAGER_JOURNALMODE_OFF && pPager->eState>=PAGER_WRITER_CACHEMOD ){ pPager->errCode = SQLITE_ABORT; pPager->eState = PAGER_ERROR; setGetterMethod(pPager); } #endif } return rc; } /* ** Return the full pathname of the database file. ** ** Except, if the pager is in-memory only, then return an empty string if ** nullIfMemDb is true. This routine is called with nullIfMemDb==1 when ** used to report the filename to the user, for compatibility with legacy ** behavior. But when the Btree needs to know the filename for matching to ** shared cache, it uses nullIfMemDb==0 so that in-memory databases can ** participate in shared-cache. ** ** The return value to this routine is always safe to use with ** sqlite3_uri_parameter() and sqlite3_filename_database() and friends. */ SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){ static const char zFake[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; if( nullIfMemDb && (pPager->memDb || sqlite3IsMemdb(pPager->pVfs)) ){ return &zFake[4]; }else{ return pPager->zFilename; } } /* ** Return the VFS structure for the pager. */ SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){ return pPager->pVfs; } /* ** Return the file handle for the database file associated ** with the pager. This might return NULL if the file has ** not yet been opened. */ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){ return pPager->fd; } /* ** Return the file handle for the journal file (if it exists). ** This will be either the rollback journal or the WAL file. */ SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){ #if SQLITE_OMIT_WAL return pPager->jfd; #else return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd; #endif } /* ** Return the full pathname of the journal file. */ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ return pPager->zJournal; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Move the page pPg to location pgno in the file. ** ** There must be no references to the page previously located at ** pgno (which we call pPgOld) though that page is allowed to be ** in cache. If the page previously located at pgno is not already ** in the rollback journal, it is not put there by by this routine. ** ** References to the page pPg remain valid. Updating any ** meta-data associated with pPg (i.e. data stored in the nExtra bytes ** allocated along with the page) is the responsibility of the caller. ** ** A transaction must be active when this routine is called. It used to be ** required that a statement transaction was not active, but this restriction ** has been removed (CREATE INDEX needs to move a page when a statement ** transaction is active). ** ** If the fourth argument, isCommit, is non-zero, then this page is being ** moved as part of a database reorganization just before the transaction ** is being committed. In this case, it is guaranteed that the database page ** pPg refers to will not be written to again within this transaction. ** ** This function may return SQLITE_NOMEM or an IO error code if an error ** occurs. Otherwise, it returns SQLITE_OK. */ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ PgHdr *pPgOld; /* The page being overwritten. */ Pgno needSyncPgno = 0; /* Old value of pPg->pgno, if sync is required */ int rc; /* Return code */ Pgno origPgno; /* The original page number */ assert( pPg->nRef>0 ); assert( pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_DBMOD ); assert( assert_pager_state(pPager) ); /* In order to be able to rollback, an in-memory database must journal ** the page we are moving from. */ assert( pPager->tempFile || !MEMDB ); if( pPager->tempFile ){ rc = sqlite3PagerWrite(pPg); if( rc ) return rc; } /* If the page being moved is dirty and has not been saved by the latest ** savepoint, then save the current contents of the page into the ** sub-journal now. This is required to handle the following scenario: ** ** BEGIN; ** ** SAVEPOINT one; ** ** ROLLBACK TO one; ** ** If page X were not written to the sub-journal here, it would not ** be possible to restore its contents when the "ROLLBACK TO one" ** statement were is processed. ** ** subjournalPage() may need to allocate space to store pPg->pgno into ** one or more savepoint bitvecs. This is the reason this function ** may return SQLITE_NOMEM. */ if( (pPg->flags & PGHDR_DIRTY)!=0 && SQLITE_OK!=(rc = subjournalPageIfRequired(pPg)) ){ return rc; } PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n", PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno)); IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno)) /* If the journal needs to be sync()ed before page pPg->pgno can ** be written to, store pPg->pgno in local variable needSyncPgno. ** ** If the isCommit flag is set, there is no need to remember that ** the journal needs to be sync()ed before database page pPg->pgno ** can be written to. The caller has already promised not to write to it. */ if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){ needSyncPgno = pPg->pgno; assert( pPager->journalMode==PAGER_JOURNALMODE_OFF || pageInJournal(pPager, pPg) || pPg->pgno>pPager->dbOrigSize ); assert( pPg->flags&PGHDR_DIRTY ); } /* If the cache contains a page with page-number pgno, remove it ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for ** page pgno before the 'move' operation, it needs to be retained ** for the page moved there. */ pPg->flags &= ~PGHDR_NEED_SYNC; pPgOld = sqlite3PagerLookup(pPager, pgno); assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB ); if( pPgOld ){ if( NEVER(pPgOld->nRef>1) ){ sqlite3PagerUnrefNotNull(pPgOld); return SQLITE_CORRUPT_BKPT; } pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); if( pPager->tempFile ){ /* Do not discard pages from an in-memory database since we might ** need to rollback later. Just move the page out of the way. */ sqlite3PcacheMove(pPgOld, pPager->dbSize+1); }else{ sqlite3PcacheDrop(pPgOld); } } origPgno = pPg->pgno; sqlite3PcacheMove(pPg, pgno); sqlite3PcacheMakeDirty(pPg); /* For an in-memory database, make sure the original page continues ** to exist, in case the transaction needs to roll back. Use pPgOld ** as the original page since it has already been allocated. */ if( pPager->tempFile && pPgOld ){ sqlite3PcacheMove(pPgOld, origPgno); sqlite3PagerUnrefNotNull(pPgOld); } if( needSyncPgno ){ /* If needSyncPgno is non-zero, then the journal file needs to be ** sync()ed before any data is written to database file page needSyncPgno. ** Currently, no such page exists in the page-cache and the ** "is journaled" bitvec flag has been set. This needs to be remedied by ** loading the page into the pager-cache and setting the PGHDR_NEED_SYNC ** flag. ** ** If the attempt to load the page into the page-cache fails, (due ** to a malloc() or IO failure), clear the bit in the pInJournal[] ** array. Otherwise, if the page is loaded and written again in ** this transaction, it may be written to the database file before ** it is synced into the journal file. This way, it may end up in ** the journal file twice, but that is not a problem. */ PgHdr *pPgHdr; rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr, 0); if( rc!=SQLITE_OK ){ if( needSyncPgno<=pPager->dbOrigSize ){ assert( pPager->pTmpSpace!=0 ); sqlite3BitvecClear(pPager->pInJournal, needSyncPgno, pPager->pTmpSpace); } return rc; } pPgHdr->flags |= PGHDR_NEED_SYNC; sqlite3PcacheMakeDirty(pPgHdr); sqlite3PagerUnrefNotNull(pPgHdr); } return SQLITE_OK; } #endif /* ** The page handle passed as the first argument refers to a dirty page ** with a page number other than iNew. This function changes the page's ** page number to iNew and sets the value of the PgHdr.flags field to ** the value passed as the third parameter. */ SQLITE_PRIVATE void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){ assert( pPg->pgno!=iNew ); pPg->flags = flags; sqlite3PcacheMove(pPg, iNew); } /* ** Return a pointer to the data for the specified page. */ SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){ assert( pPg->nRef>0 || pPg->pPager->memDb ); return pPg->pData; } /* ** Return a pointer to the Pager.nExtra bytes of "extra" space ** allocated along with the specified page. */ SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){ return pPg->pExtra; } /* ** Get/set the locking-mode for this pager. Parameter eMode must be one ** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or ** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then ** the locking-mode is set to the value specified. ** ** The returned value is either PAGER_LOCKINGMODE_NORMAL or ** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated) ** locking-mode. */ SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){ assert( eMode==PAGER_LOCKINGMODE_QUERY || eMode==PAGER_LOCKINGMODE_NORMAL || eMode==PAGER_LOCKINGMODE_EXCLUSIVE ); assert( PAGER_LOCKINGMODE_QUERY<0 ); assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 ); assert( pPager->exclusiveMode || 0==sqlite3WalHeapMemory(pPager->pWal) ); if( eMode>=0 && !pPager->tempFile && !sqlite3WalHeapMemory(pPager->pWal) ){ pPager->exclusiveMode = (u8)eMode; } return (int)pPager->exclusiveMode; } /* ** Set the journal-mode for this pager. Parameter eMode must be one of: ** ** PAGER_JOURNALMODE_DELETE ** PAGER_JOURNALMODE_TRUNCATE ** PAGER_JOURNALMODE_PERSIST ** PAGER_JOURNALMODE_OFF ** PAGER_JOURNALMODE_MEMORY ** PAGER_JOURNALMODE_WAL ** ** The journalmode is set to the value specified if the change is allowed. ** The change may be disallowed for the following reasons: ** ** * An in-memory database can only have its journal_mode set to _OFF ** or _MEMORY. ** ** * Temporary databases cannot have _WAL journalmode. ** ** The returned indicate the current (possibly updated) journal-mode. */ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ u8 eOld = pPager->journalMode; /* Prior journalmode */ /* The eMode parameter is always valid */ assert( eMode==PAGER_JOURNALMODE_DELETE /* 0 */ || eMode==PAGER_JOURNALMODE_PERSIST /* 1 */ || eMode==PAGER_JOURNALMODE_OFF /* 2 */ || eMode==PAGER_JOURNALMODE_TRUNCATE /* 3 */ || eMode==PAGER_JOURNALMODE_MEMORY /* 4 */ || eMode==PAGER_JOURNALMODE_WAL /* 5 */ ); /* This routine is only called from the OP_JournalMode opcode, and ** the logic there will never allow a temporary file to be changed ** to WAL mode. */ assert( pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL ); /* Do allow the journalmode of an in-memory database to be set to ** anything other than MEMORY or OFF */ if( MEMDB ){ assert( eOld==PAGER_JOURNALMODE_MEMORY || eOld==PAGER_JOURNALMODE_OFF ); if( eMode!=PAGER_JOURNALMODE_MEMORY && eMode!=PAGER_JOURNALMODE_OFF ){ eMode = eOld; } } if( eMode!=eOld ){ /* Change the journal mode. */ assert( pPager->eState!=PAGER_ERROR ); pPager->journalMode = (u8)eMode; /* When transitioning from TRUNCATE or PERSIST to any other journal ** mode except WAL, unless the pager is in locking_mode=exclusive mode, ** delete the journal file. */ assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 ); assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 ); assert( (PAGER_JOURNALMODE_DELETE & 5)==0 ); assert( (PAGER_JOURNALMODE_MEMORY & 5)==4 ); assert( (PAGER_JOURNALMODE_OFF & 5)==0 ); assert( (PAGER_JOURNALMODE_WAL & 5)==5 ); assert( isOpen(pPager->fd) || pPager->exclusiveMode ); if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){ /* In this case we would like to delete the journal file. If it is ** not possible, then that is not a problem. Deleting the journal file ** here is an optimization only. ** ** Before deleting the journal file, obtain a RESERVED lock on the ** database file. This ensures that the journal file is not deleted ** while it is in use by some other client. */ sqlite3OsClose(pPager->jfd); if( pPager->eLock>=RESERVED_LOCK ){ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); }else{ int rc = SQLITE_OK; int state = pPager->eState; assert( state==PAGER_OPEN || state==PAGER_READER ); if( state==PAGER_OPEN ){ rc = sqlite3PagerSharedLock(pPager); } if( pPager->eState==PAGER_READER ){ assert( rc==SQLITE_OK ); rc = pagerLockDb(pPager, RESERVED_LOCK); } if( rc==SQLITE_OK ){ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); } if( rc==SQLITE_OK && state==PAGER_READER ){ pagerUnlockDb(pPager, SHARED_LOCK); }else if( state==PAGER_OPEN ){ pager_unlock(pPager); } assert( state==pPager->eState ); } }else if( eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_MEMORY ){ sqlite3OsClose(pPager->jfd); } } /* Return the new journal mode */ return (int)pPager->journalMode; } /* ** Return the current journal mode. */ SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){ return (int)pPager->journalMode; } /* ** Return TRUE if the pager is in a state where it is OK to change the ** journalmode. Journalmode changes can only happen when the database ** is unmodified. */ SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){ assert( assert_pager_state(pPager) ); if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0; if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0; return 1; } /* ** Get/set the size-limit used for persistent journal files. ** ** Setting the size limit to -1 means no limit is enforced. ** An attempt to set a limit smaller than -1 is a no-op. */ SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){ if( iLimit>=-1 ){ pPager->journalSizeLimit = iLimit; sqlite3WalLimit(pPager->pWal, iLimit); } return pPager->journalSizeLimit; } /* ** Return a pointer to the pPager->pBackup variable. The backup module ** in backup.c maintains the content of this variable. This module ** uses it opaquely as an argument to sqlite3BackupRestart() and ** sqlite3BackupUpdate() only. */ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){ return &pPager->pBackup; } #ifndef SQLITE_OMIT_VACUUM /* ** Unless this is an in-memory or temporary database, clear the pager cache. */ SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){ assert( MEMDB==0 || pPager->tempFile ); if( pPager->tempFile==0 ) pager_reset(pPager); } #endif #ifndef SQLITE_OMIT_WAL /* ** This function is called when the user invokes "PRAGMA wal_checkpoint", ** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint() ** or wal_blocking_checkpoint() API functions. ** ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. */ SQLITE_PRIVATE int sqlite3PagerCheckpoint( Pager *pPager, /* Checkpoint on this pager */ sqlite3 *db, /* Db handle used to check for interrupts */ int eMode, /* Type of checkpoint */ int *pnLog, /* OUT: Final number of frames in log */ int *pnCkpt /* OUT: Final number of checkpointed frames */ ){ int rc = SQLITE_OK; if( pPager->pWal==0 && pPager->journalMode==PAGER_JOURNALMODE_WAL ){ /* This only happens when a database file is zero bytes in size opened and ** then "PRAGMA journal_mode=WAL" is run and then sqlite3_wal_checkpoint() ** is invoked without any intervening transactions. We need to start ** a transaction to initialize pWal. The PRAGMA table_list statement is ** used for this since it starts transactions on every database file, ** including all ATTACHed databases. This seems expensive for a single ** sqlite3_wal_checkpoint() call, but it happens very rarely. ** https://sqlite.org/forum/forumpost/fd0f19d229156939 */ sqlite3_exec(db, "PRAGMA table_list",0,0,0); } if( pPager->pWal ){ rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode, (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), pPager->pBusyHandlerArg, pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, pnLog, pnCkpt ); } return rc; } SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){ return sqlite3WalCallback(pPager->pWal); } /* ** Return true if the underlying VFS for the given pager supports the ** primitives necessary for write-ahead logging. */ SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){ const sqlite3_io_methods *pMethods = pPager->fd->pMethods; if( pPager->noLock ) return 0; return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap); } /* ** Attempt to take an exclusive lock on the database file. If a PENDING lock ** is obtained instead, immediately release it. */ static int pagerExclusiveLock(Pager *pPager){ int rc; /* Return code */ u8 eOrigLock; /* Original lock */ assert( pPager->eLock>=SHARED_LOCK ); eOrigLock = pPager->eLock; rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ /* If the attempt to grab the exclusive lock failed, release the ** pending lock that may have been obtained instead. */ pagerUnlockDb(pPager, eOrigLock); } return rc; } /* ** Call sqlite3WalOpen() to open the WAL handle. If the pager is in ** exclusive-locking mode when this function is called, take an EXCLUSIVE ** lock on the database file and use heap-memory to store the wal-index ** in. Otherwise, use the normal shared-memory. */ static int pagerOpenWal(Pager *pPager){ int rc = SQLITE_OK; assert( pPager->pWal==0 && pPager->tempFile==0 ); assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK ); /* If the pager is already in exclusive-mode, the WAL module will use ** heap-memory for the wal-index instead of the VFS shared-memory ** implementation. Take the exclusive lock now, before opening the WAL ** file, to make sure this is safe. */ if( pPager->exclusiveMode ){ rc = pagerExclusiveLock(pPager); } /* Open the connection to the log file. If this operation fails, ** (e.g. due to malloc() failure), return an error code. */ if( rc==SQLITE_OK ){ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode, pPager->journalSizeLimit, &pPager->pWal ); } pagerFixMaplimit(pPager); return rc; } /* ** The caller must be holding a SHARED lock on the database file to call ** this function. ** ** If the pager passed as the first argument is open on a real database ** file (not a temp file or an in-memory database), and the WAL file ** is not already open, make an attempt to open it now. If successful, ** return SQLITE_OK. If an error occurs or the VFS used by the pager does ** not support the xShmXXX() methods, return an error code. *pbOpen is ** not modified in either case. ** ** If the pager is open on a temp-file (or in-memory database), or if ** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK ** without doing anything. */ SQLITE_PRIVATE int sqlite3PagerOpenWal( Pager *pPager, /* Pager object */ int *pbOpen /* OUT: Set to true if call is a no-op */ ){ int rc = SQLITE_OK; /* Return code */ assert( assert_pager_state(pPager) ); assert( pPager->eState==PAGER_OPEN || pbOpen ); assert( pPager->eState==PAGER_READER || !pbOpen ); assert( pbOpen==0 || *pbOpen==0 ); assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) ); if( !pPager->tempFile && !pPager->pWal ){ if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN; /* Close any rollback journal previously open */ sqlite3OsClose(pPager->jfd); rc = pagerOpenWal(pPager); if( rc==SQLITE_OK ){ pPager->journalMode = PAGER_JOURNALMODE_WAL; pPager->eState = PAGER_OPEN; } }else{ *pbOpen = 1; } return rc; } /* ** This function is called to close the connection to the log file prior ** to switching from WAL to rollback mode. ** ** Before closing the log file, this function attempts to take an ** EXCLUSIVE lock on the database file. If this cannot be obtained, an ** error (SQLITE_BUSY) is returned and the log connection is not closed. ** If successful, the EXCLUSIVE lock is not released before returning. */ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ int rc = SQLITE_OK; assert( pPager->journalMode==PAGER_JOURNALMODE_WAL ); /* If the log file is not already open, but does exist in the file-system, ** it may need to be checkpointed before the connection can switch to ** rollback mode. Open it now so this can happen. */ if( !pPager->pWal ){ int logexists = 0; rc = pagerLockDb(pPager, SHARED_LOCK); if( rc==SQLITE_OK ){ rc = sqlite3OsAccess( pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists ); } if( rc==SQLITE_OK && logexists ){ rc = pagerOpenWal(pPager); } } /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on ** the database file, the log and log-summary files will be deleted. */ if( rc==SQLITE_OK && pPager->pWal ){ rc = pagerExclusiveLock(pPager); if( rc==SQLITE_OK ){ rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize, (u8*)pPager->pTmpSpace); pPager->pWal = 0; pagerFixMaplimit(pPager); if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); } } return rc; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* ** If pager pPager is a wal-mode database not in exclusive locking mode, ** invoke the sqlite3WalWriteLock() function on the associated Wal object ** with the same db and bLock parameters as were passed to this function. ** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise. */ SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){ int rc = SQLITE_OK; if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){ rc = sqlite3WalWriteLock(pPager->pWal, bLock); } return rc; } /* ** Set the database handle used by the wal layer to determine if ** blocking locks are required. */ SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){ if( pagerUseWal(pPager) ){ sqlite3WalDb(pPager->pWal, db); } } #endif #ifdef SQLITE_ENABLE_SNAPSHOT /* ** If this is a WAL database, obtain a snapshot handle for the snapshot ** currently open. Otherwise, return an error. */ SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){ int rc = SQLITE_ERROR; if( pPager->pWal ){ rc = sqlite3WalSnapshotGet(pPager->pWal, ppSnapshot); } return rc; } /* ** If this is a WAL database, store a pointer to pSnapshot. Next time a ** read transaction is opened, attempt to read from the snapshot it ** identifies. If this is not a WAL database, return an error. */ SQLITE_PRIVATE int sqlite3PagerSnapshotOpen( Pager *pPager, sqlite3_snapshot *pSnapshot ){ int rc = SQLITE_OK; if( pPager->pWal ){ sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot); }else{ rc = SQLITE_ERROR; } return rc; } /* ** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this ** is not a WAL database, return an error. */ SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){ int rc; if( pPager->pWal ){ rc = sqlite3WalSnapshotRecover(pPager->pWal); }else{ rc = SQLITE_ERROR; } return rc; } /* ** The caller currently has a read transaction open on the database. ** If this is not a WAL database, SQLITE_ERROR is returned. Otherwise, ** this function takes a SHARED lock on the CHECKPOINTER slot and then ** checks if the snapshot passed as the second argument is still ** available. If so, SQLITE_OK is returned. ** ** If the snapshot is not available, SQLITE_ERROR is returned. Or, if ** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error ** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER ** lock is released before returning. */ SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot){ int rc; if( pPager->pWal ){ rc = sqlite3WalSnapshotCheck(pPager->pWal, pSnapshot); }else{ rc = SQLITE_ERROR; } return rc; } /* ** Release a lock obtained by an earlier successful call to ** sqlite3PagerSnapshotCheck(). */ SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager){ assert( pPager->pWal ); sqlite3WalSnapshotUnlock(pPager->pWal); } #endif /* SQLITE_ENABLE_SNAPSHOT */ #endif /* !SQLITE_OMIT_WAL */ #ifdef SQLITE_ENABLE_ZIPVFS /* ** A read-lock must be held on the pager when this function is called. If ** the pager is in WAL mode and the WAL file currently contains one or more ** frames, return the size in bytes of the page images stored within the ** WAL frames. Otherwise, if this is not a WAL database or the WAL file ** is empty, return 0. */ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ assert( pPager->eState>=PAGER_READER ); return sqlite3WalFramesize(pPager->pWal); } #endif #if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL) SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager *pPager){ return sqlite3WalSystemErrno(pPager->pWal); } #endif #endif /* SQLITE_OMIT_DISKIO */ /************** End of pager.c ***********************************************/ /************** Begin file wal.c *********************************************/ /* ** 2010 February 1 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains the implementation of a write-ahead log (WAL) used in ** "journal_mode=WAL" mode. ** ** WRITE-AHEAD LOG (WAL) FILE FORMAT ** ** A WAL file consists of a header followed by zero or more "frames". ** Each frame records the revised content of a single page from the ** database file. All changes to the database are recorded by writing ** frames into the WAL. Transactions commit when a frame is written that ** contains a commit marker. A single WAL can and usually does record ** multiple transactions. Periodically, the content of the WAL is ** transferred back into the database file in an operation called a ** "checkpoint". ** ** A single WAL file can be used multiple times. In other words, the ** WAL can fill up with frames and then be checkpointed and then new ** frames can overwrite the old ones. A WAL always grows from beginning ** toward the end. Checksums and counters attached to each frame are ** used to determine which frames within the WAL are valid and which ** are leftovers from prior checkpoints. ** ** The WAL header is 32 bytes in size and consists of the following eight ** big-endian 32-bit unsigned integer values: ** ** 0: Magic number. 0x377f0682 or 0x377f0683 ** 4: File format version. Currently 3007000 ** 8: Database page size. Example: 1024 ** 12: Checkpoint sequence number ** 16: Salt-1, random integer incremented with each checkpoint ** 20: Salt-2, a different random integer changing with each ckpt ** 24: Checksum-1 (first part of checksum for first 24 bytes of header). ** 28: Checksum-2 (second part of checksum for first 24 bytes of header). ** ** Immediately following the wal-header are zero or more frames. Each ** frame consists of a 24-byte frame-header followed by a bytes ** of page data. The frame-header is six big-endian 32-bit unsigned ** integer values, as follows: ** ** 0: Page number. ** 4: For commit records, the size of the database image in pages ** after the commit. For all other records, zero. ** 8: Salt-1 (copied from the header) ** 12: Salt-2 (copied from the header) ** 16: Checksum-1. ** 20: Checksum-2. ** ** A frame is considered valid if and only if the following conditions are ** true: ** ** (1) The salt-1 and salt-2 values in the frame-header match ** salt values in the wal-header ** ** (2) The checksum values in the final 8 bytes of the frame-header ** exactly match the checksum computed consecutively on the ** WAL header and the first 8 bytes and the content of all frames ** up to and including the current frame. ** ** The checksum is computed using 32-bit big-endian integers if the ** magic number in the first 4 bytes of the WAL is 0x377f0683 and it ** is computed using little-endian if the magic number is 0x377f0682. ** The checksum values are always stored in the frame header in a ** big-endian format regardless of which byte order is used to compute ** the checksum. The checksum is computed by interpreting the input as ** an even number of unsigned 32-bit integers: x[0] through x[N]. The ** algorithm used for the checksum is as follows: ** ** for i from 0 to n-1 step 2: ** s0 += x[i] + s1; ** s1 += x[i+1] + s0; ** endfor ** ** Note that s0 and s1 are both weighted checksums using fibonacci weights ** in reverse order (the largest fibonacci weight occurs on the first element ** of the sequence being summed.) The s1 value spans all 32-bit ** terms of the sequence whereas s0 omits the final term. ** ** On a checkpoint, the WAL is first VFS.xSync-ed, then valid content of the ** WAL is transferred into the database, then the database is VFS.xSync-ed. ** The VFS.xSync operations serve as write barriers - all writes launched ** before the xSync must complete before any write that launches after the ** xSync begins. ** ** After each checkpoint, the salt-1 value is incremented and the salt-2 ** value is randomized. This prevents old and new frames in the WAL from ** being considered valid at the same time and being checkpointing together ** following a crash. ** ** READER ALGORITHM ** ** To read a page from the database (call it page number P), a reader ** first checks the WAL to see if it contains page P. If so, then the ** last valid instance of page P that is a followed by a commit frame ** or is a commit frame itself becomes the value read. If the WAL ** contains no copies of page P that are valid and which are a commit ** frame or are followed by a commit frame, then page P is read from ** the database file. ** ** To start a read transaction, the reader records the index of the last ** valid frame in the WAL. The reader uses this recorded "mxFrame" value ** for all subsequent read operations. New transactions can be appended ** to the WAL, but as long as the reader uses its original mxFrame value ** and ignores the newly appended content, it will see a consistent snapshot ** of the database from a single point in time. This technique allows ** multiple concurrent readers to view different versions of the database ** content simultaneously. ** ** The reader algorithm in the previous paragraphs works correctly, but ** because frames for page P can appear anywhere within the WAL, the ** reader has to scan the entire WAL looking for page P frames. If the ** WAL is large (multiple megabytes is typical) that scan can be slow, ** and read performance suffers. To overcome this problem, a separate ** data structure called the wal-index is maintained to expedite the ** search for frames of a particular page. ** ** WAL-INDEX FORMAT ** ** Conceptually, the wal-index is shared memory, though VFS implementations ** might choose to implement the wal-index using a mmapped file. Because ** the wal-index is shared memory, SQLite does not support journal_mode=WAL ** on a network filesystem. All users of the database must be able to ** share memory. ** ** In the default unix and windows implementation, the wal-index is a mmapped ** file whose name is the database name with a "-shm" suffix added. For that ** reason, the wal-index is sometimes called the "shm" file. ** ** The wal-index is transient. After a crash, the wal-index can (and should ** be) reconstructed from the original WAL file. In fact, the VFS is required ** to either truncate or zero the header of the wal-index when the last ** connection to it closes. Because the wal-index is transient, it can ** use an architecture-specific format; it does not have to be cross-platform. ** Hence, unlike the database and WAL file formats which store all values ** as big endian, the wal-index can store multi-byte values in the native ** byte order of the host computer. ** ** The purpose of the wal-index is to answer this question quickly: Given ** a page number P and a maximum frame index M, return the index of the ** last frame in the wal before frame M for page P in the WAL, or return ** NULL if there are no frames for page P in the WAL prior to M. ** ** The wal-index consists of a header region, followed by an one or ** more index blocks. ** ** The wal-index header contains the total number of frames within the WAL ** in the mxFrame field. ** ** Each index block except for the first contains information on ** HASHTABLE_NPAGE frames. The first index block contains information on ** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and ** HASHTABLE_NPAGE are selected so that together the wal-index header and ** first index block are the same size as all other index blocks in the ** wal-index. The values are: ** ** HASHTABLE_NPAGE 4096 ** HASHTABLE_NPAGE_ONE 4062 ** ** Each index block contains two sections, a page-mapping that contains the ** database page number associated with each wal frame, and a hash-table ** that allows readers to query an index block for a specific page number. ** The page-mapping is an array of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE ** for the first index block) 32-bit page numbers. The first entry in the ** first index-block contains the database page number corresponding to the ** first frame in the WAL file. The first entry in the second index block ** in the WAL file corresponds to the (HASHTABLE_NPAGE_ONE+1)th frame in ** the log, and so on. ** ** The last index block in a wal-index usually contains less than the full ** complement of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE) page-numbers, ** depending on the contents of the WAL file. This does not change the ** allocated size of the page-mapping array - the page-mapping array merely ** contains unused entries. ** ** Even without using the hash table, the last frame for page P ** can be found by scanning the page-mapping sections of each index block ** starting with the last index block and moving toward the first, and ** within each index block, starting at the end and moving toward the ** beginning. The first entry that equals P corresponds to the frame ** holding the content for that page. ** ** The hash table consists of HASHTABLE_NSLOT 16-bit unsigned integers. ** HASHTABLE_NSLOT = 2*HASHTABLE_NPAGE, and there is one entry in the ** hash table for each page number in the mapping section, so the hash ** table is never more than half full. The expected number of collisions ** prior to finding a match is 1. Each entry of the hash table is an ** 1-based index of an entry in the mapping section of the same ** index block. Let K be the 1-based index of the largest entry in ** the mapping section. (For index blocks other than the last, K will ** always be exactly HASHTABLE_NPAGE (4096) and for the last index block ** K will be (mxFrame%HASHTABLE_NPAGE).) Unused slots of the hash table ** contain a value of 0. ** ** To look for page P in the hash table, first compute a hash iKey on ** P as follows: ** ** iKey = (P * 383) % HASHTABLE_NSLOT ** ** Then start scanning entries of the hash table, starting with iKey ** (wrapping around to the beginning when the end of the hash table is ** reached) until an unused hash slot is found. Let the first unused slot ** be at index iUnused. (iUnused might be less than iKey if there was ** wrap-around.) Because the hash table is never more than half full, ** the search is guaranteed to eventually hit an unused entry. Let ** iMax be the value between iKey and iUnused, closest to iUnused, ** where aHash[iMax]==P. If there is no iMax entry (if there exists ** no hash slot such that aHash[i]==p) then page P is not in the ** current index block. Otherwise the iMax-th mapping entry of the ** current index block corresponds to the last entry that references ** page P. ** ** A hash search begins with the last index block and moves toward the ** first index block, looking for entries corresponding to page P. On ** average, only two or three slots in each index block need to be ** examined in order to either find the last entry for page P, or to ** establish that no such entry exists in the block. Each index block ** holds over 4000 entries. So two or three index blocks are sufficient ** to cover a typical 10 megabyte WAL file, assuming 1K pages. 8 or 10 ** comparisons (on average) suffice to either locate a frame in the ** WAL or to establish that the frame does not exist in the WAL. This ** is much faster than scanning the entire 10MB WAL. ** ** Note that entries are added in order of increasing K. Hence, one ** reader might be using some value K0 and a second reader that started ** at a later time (after additional transactions were added to the WAL ** and to the wal-index) might be using a different value K1, where K1>K0. ** Both readers can use the same hash table and mapping section to get ** the correct result. There may be entries in the hash table with ** K>K0 but to the first reader, those entries will appear to be unused ** slots in the hash table and so the first reader will get an answer as ** if no values greater than K0 had ever been inserted into the hash table ** in the first place - which is what reader one wants. Meanwhile, the ** second reader using K1 will see additional values that were inserted ** later, which is exactly what reader two wants. ** ** When a rollback occurs, the value of K is decreased. Hash table entries ** that correspond to frames greater than the new K value are removed ** from the hash table at this point. */ #ifndef SQLITE_OMIT_WAL /* #include "wal.h" */ /* ** Trace output macros */ #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) SQLITE_PRIVATE int sqlite3WalTrace = 0; # define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X #else # define WALTRACE(X) #endif /* ** The maximum (and only) versions of the wal and wal-index formats ** that may be interpreted by this version of SQLite. ** ** If a client begins recovering a WAL file and finds that (a) the checksum ** values in the wal-header are correct and (b) the version field is not ** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN. ** ** Similarly, if a client successfully reads a wal-index header (i.e. the ** checksum test is successful) and finds that the version field is not ** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite ** returns SQLITE_CANTOPEN. */ #define WAL_MAX_VERSION 3007000 #define WALINDEX_MAX_VERSION 3007000 /* ** Index numbers for various locking bytes. WAL_NREADER is the number ** of available reader locks and should be at least 3. The default ** is SQLITE_SHM_NLOCK==8 and WAL_NREADER==5. ** ** Technically, the various VFSes are free to implement these locks however ** they see fit. However, compatibility is encouraged so that VFSes can ** interoperate. The standard implementation used on both unix and windows ** is for the index number to indicate a byte offset into the ** WalCkptInfo.aLock[] array in the wal-index header. In other words, all ** locks are on the shm file. The WALINDEX_LOCK_OFFSET constant (which ** should be 120) is the location in the shm file for the first locking ** byte. */ #define WAL_WRITE_LOCK 0 #define WAL_ALL_BUT_WRITE 1 #define WAL_CKPT_LOCK 1 #define WAL_RECOVER_LOCK 2 #define WAL_READ_LOCK(I) (3+(I)) #define WAL_NREADER (SQLITE_SHM_NLOCK-3) /* Object declarations */ typedef struct WalIndexHdr WalIndexHdr; typedef struct WalIterator WalIterator; typedef struct WalCkptInfo WalCkptInfo; /* ** The following object holds a copy of the wal-index header content. ** ** The actual header in the wal-index consists of two copies of this ** object followed by one instance of the WalCkptInfo object. ** For all versions of SQLite through 3.10.0 and probably beyond, ** the locking bytes (WalCkptInfo.aLock) start at offset 120 and ** the total header size is 136 bytes. ** ** The szPage value can be any power of 2 between 512 and 32768, inclusive. ** Or it can be 1 to represent a 65536-byte page. The latter case was ** added in 3.7.1 when support for 64K pages was added. */ struct WalIndexHdr { u32 iVersion; /* Wal-index version */ u32 unused; /* Unused (padding) field */ u32 iChange; /* Counter incremented each transaction */ u8 isInit; /* 1 when initialized */ u8 bigEndCksum; /* True if checksums in WAL are big-endian */ u16 szPage; /* Database page size in bytes. 1==64K */ u32 mxFrame; /* Index of last valid frame in the WAL */ u32 nPage; /* Size of database in pages */ u32 aFrameCksum[2]; /* Checksum of last frame in log */ u32 aSalt[2]; /* Two salt values copied from WAL header */ u32 aCksum[2]; /* Checksum over all prior fields */ }; /* ** A copy of the following object occurs in the wal-index immediately ** following the second copy of the WalIndexHdr. This object stores ** information used by checkpoint. ** ** nBackfill is the number of frames in the WAL that have been written ** back into the database. (We call the act of moving content from WAL to ** database "backfilling".) The nBackfill number is never greater than ** WalIndexHdr.mxFrame. nBackfill can only be increased by threads ** holding the WAL_CKPT_LOCK lock (which includes a recovery thread). ** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from ** mxFrame back to zero when the WAL is reset. ** ** nBackfillAttempted is the largest value of nBackfill that a checkpoint ** has attempted to achieve. Normally nBackfill==nBackfillAtempted, however ** the nBackfillAttempted is set before any backfilling is done and the ** nBackfill is only set after all backfilling completes. So if a checkpoint ** crashes, nBackfillAttempted might be larger than nBackfill. The ** WalIndexHdr.mxFrame must never be less than nBackfillAttempted. ** ** The aLock[] field is a set of bytes used for locking. These bytes should ** never be read or written. ** ** There is one entry in aReadMark[] for each reader lock. If a reader ** holds read-lock K, then the value in aReadMark[K] is no greater than ** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff) ** for any aReadMark[] means that entry is unused. aReadMark[0] is ** a special case; its value is never used and it exists as a place-holder ** to avoid having to offset aReadMark[] indexes by one. Readers holding ** WAL_READ_LOCK(0) always ignore the entire WAL and read all content ** directly from the database. ** ** The value of aReadMark[K] may only be changed by a thread that ** is holding an exclusive lock on WAL_READ_LOCK(K). Thus, the value of ** aReadMark[K] cannot changed while there is a reader is using that mark ** since the reader will be holding a shared lock on WAL_READ_LOCK(K). ** ** The checkpointer may only transfer frames from WAL to database where ** the frame numbers are less than or equal to every aReadMark[] that is ** in use (that is, every aReadMark[j] for which there is a corresponding ** WAL_READ_LOCK(j)). New readers (usually) pick the aReadMark[] with the ** largest value and will increase an unused aReadMark[] to mxFrame if there ** is not already an aReadMark[] equal to mxFrame. The exception to the ** previous sentence is when nBackfill equals mxFrame (meaning that everything ** in the WAL has been backfilled into the database) then new readers ** will choose aReadMark[0] which has value 0 and hence such reader will ** get all their all content directly from the database file and ignore ** the WAL. ** ** Writers normally append new frames to the end of the WAL. However, ** if nBackfill equals mxFrame (meaning that all WAL content has been ** written back into the database) and if no readers are using the WAL ** (in other words, if there are no WAL_READ_LOCK(i) where i>0) then ** the writer will first "reset" the WAL back to the beginning and start ** writing new content beginning at frame 1. ** ** We assume that 32-bit loads are atomic and so no locks are needed in ** order to read from any aReadMark[] entries. */ struct WalCkptInfo { u32 nBackfill; /* Number of WAL frames backfilled into DB */ u32 aReadMark[WAL_NREADER]; /* Reader marks */ u8 aLock[SQLITE_SHM_NLOCK]; /* Reserved space for locks */ u32 nBackfillAttempted; /* WAL frames perhaps written, or maybe not */ u32 notUsed0; /* Available for future enhancements */ }; #define READMARK_NOT_USED 0xffffffff /* ** This is a schematic view of the complete 136-byte header of the ** wal-index file (also known as the -shm file): ** ** +-----------------------------+ ** 0: | iVersion | \ ** +-----------------------------+ | ** 4: | (unused padding) | | ** +-----------------------------+ | ** 8: | iChange | | ** +-------+-------+-------------+ | ** 12: | bInit | bBig | szPage | | ** +-------+-------+-------------+ | ** 16: | mxFrame | | First copy of the ** +-----------------------------+ | WalIndexHdr object ** 20: | nPage | | ** +-----------------------------+ | ** 24: | aFrameCksum | | ** | | | ** +-----------------------------+ | ** 32: | aSalt | | ** | | | ** +-----------------------------+ | ** 40: | aCksum | | ** | | / ** +-----------------------------+ ** 48: | iVersion | \ ** +-----------------------------+ | ** 52: | (unused padding) | | ** +-----------------------------+ | ** 56: | iChange | | ** +-------+-------+-------------+ | ** 60: | bInit | bBig | szPage | | ** +-------+-------+-------------+ | Second copy of the ** 64: | mxFrame | | WalIndexHdr ** +-----------------------------+ | ** 68: | nPage | | ** +-----------------------------+ | ** 72: | aFrameCksum | | ** | | | ** +-----------------------------+ | ** 80: | aSalt | | ** | | | ** +-----------------------------+ | ** 88: | aCksum | | ** | | / ** +-----------------------------+ ** 96: | nBackfill | ** +-----------------------------+ ** 100: | 5 read marks | ** | | ** | | ** | | ** | | ** +-------+-------+------+------+ ** 120: | Write | Ckpt | Rcvr | Rd0 | \ ** +-------+-------+------+------+ ) 8 lock bytes ** | Read1 | Read2 | Rd3 | Rd4 | / ** +-------+-------+------+------+ ** 128: | nBackfillAttempted | ** +-----------------------------+ ** 132: | (unused padding) | ** +-----------------------------+ */ /* A block of WALINDEX_LOCK_RESERVED bytes beginning at ** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems ** only support mandatory file-locks, we do not read or write data ** from the region of the file on which locks are applied. */ #define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2+offsetof(WalCkptInfo,aLock)) #define WALINDEX_HDR_SIZE (sizeof(WalIndexHdr)*2+sizeof(WalCkptInfo)) /* Size of header before each frame in wal */ #define WAL_FRAME_HDRSIZE 24 /* Size of write ahead log header, including checksum. */ #define WAL_HDRSIZE 32 /* WAL magic value. Either this value, or the same value with the least ** significant bit also set (WAL_MAGIC | 0x00000001) is stored in 32-bit ** big-endian format in the first 4 bytes of a WAL file. ** ** If the LSB is set, then the checksums for each frame within the WAL ** file are calculated by treating all data as an array of 32-bit ** big-endian words. Otherwise, they are calculated by interpreting ** all data as 32-bit little-endian words. */ #define WAL_MAGIC 0x377f0682 /* ** Return the offset of frame iFrame in the write-ahead log file, ** assuming a database page size of szPage bytes. The offset returned ** is to the start of the write-ahead log frame-header. */ #define walFrameOffset(iFrame, szPage) ( \ WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \ ) /* ** An open write-ahead log file is represented by an instance of the ** following object. */ struct Wal { sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */ sqlite3_file *pDbFd; /* File handle for the database file */ sqlite3_file *pWalFd; /* File handle for WAL file */ u32 iCallback; /* Value to pass to log callback (or 0) */ i64 mxWalSize; /* Truncate WAL to this size upon reset */ int nWiData; /* Size of array apWiData */ int szFirstBlock; /* Size of first block written to WAL file */ volatile u32 **apWiData; /* Pointer to wal-index content in memory */ u32 szPage; /* Database page size */ i16 readLock; /* Which read lock is being held. -1 for none */ u8 syncFlags; /* Flags to use to sync header writes */ u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */ u8 writeLock; /* True if in a write transaction */ u8 ckptLock; /* True if holding a checkpoint lock */ u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */ u8 truncateOnCommit; /* True to truncate WAL file on commit */ u8 syncHeader; /* Fsync the WAL header if true */ u8 padToSectorBoundary; /* Pad transactions out to the next sector */ u8 bShmUnreliable; /* SHM content is read-only and unreliable */ WalIndexHdr hdr; /* Wal-index header for current transaction */ u32 minFrame; /* Ignore wal frames before this one */ u32 iReCksum; /* On commit, recalculate checksums from here */ const char *zWalName; /* Name of WAL file */ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ #ifdef SQLITE_USE_SEH u32 lockMask; /* Mask of locks held */ void *pFree; /* Pointer to sqlite3_free() if exception thrown */ u32 *pWiValue; /* Value to write into apWiData[iWiPg] */ int iWiPg; /* Write pWiValue into apWiData[iWiPg] */ int iSysErrno; /* System error code following exception */ #endif #ifdef SQLITE_DEBUG int nSehTry; /* Number of nested SEH_TRY{} blocks */ u8 lockError; /* True if a locking error has occurred */ #endif #ifdef SQLITE_ENABLE_SNAPSHOT WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ #endif #ifdef SQLITE_ENABLE_SETLK_TIMEOUT sqlite3 *db; #endif }; /* ** Candidate values for Wal.exclusiveMode. */ #define WAL_NORMAL_MODE 0 #define WAL_EXCLUSIVE_MODE 1 #define WAL_HEAPMEMORY_MODE 2 /* ** Possible values for WAL.readOnly */ #define WAL_RDWR 0 /* Normal read/write connection */ #define WAL_RDONLY 1 /* The WAL file is readonly */ #define WAL_SHM_RDONLY 2 /* The SHM file is readonly */ /* ** Each page of the wal-index mapping contains a hash-table made up of ** an array of HASHTABLE_NSLOT elements of the following type. */ typedef u16 ht_slot; /* ** This structure is used to implement an iterator that loops through ** all frames in the WAL in database page order. Where two or more frames ** correspond to the same database page, the iterator visits only the ** frame most recently written to the WAL (in other words, the frame with ** the largest index). ** ** The internals of this structure are only accessed by: ** ** walIteratorInit() - Create a new iterator, ** walIteratorNext() - Step an iterator, ** walIteratorFree() - Free an iterator. ** ** This functionality is used by the checkpoint code (see walCheckpoint()). */ struct WalIterator { u32 iPrior; /* Last result returned from the iterator */ int nSegment; /* Number of entries in aSegment[] */ struct WalSegment { int iNext; /* Next slot in aIndex[] not yet returned */ ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */ u32 *aPgno; /* Array of page numbers. */ int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */ int iZero; /* Frame number associated with aPgno[0] */ } aSegment[1]; /* One for every 32KB page in the wal-index */ }; /* ** Define the parameters of the hash tables in the wal-index file. There ** is a hash-table following every HASHTABLE_NPAGE page numbers in the ** wal-index. ** ** Changing any of these constants will alter the wal-index format and ** create incompatibilities. */ #define HASHTABLE_NPAGE 4096 /* Must be power of 2 */ #define HASHTABLE_HASH_1 383 /* Should be prime */ #define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */ /* ** The block of page numbers associated with the first hash-table in a ** wal-index is smaller than usual. This is so that there is a complete ** hash-table on each aligned 32KB page of the wal-index. */ #define HASHTABLE_NPAGE_ONE (HASHTABLE_NPAGE - (WALINDEX_HDR_SIZE/sizeof(u32))) /* The wal-index is divided into pages of WALINDEX_PGSZ bytes each. */ #define WALINDEX_PGSZ ( \ sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \ ) /* ** Structured Exception Handling (SEH) is a Windows-specific technique ** for catching exceptions raised while accessing memory-mapped files. ** ** The -DSQLITE_USE_SEH compile-time option means to use SEH to catch and ** deal with system-level errors that arise during WAL -shm file processing. ** Without this compile-time option, any system-level faults that appear ** while accessing the memory-mapped -shm file will cause a process-wide ** signal to be deliver, which will more than likely cause the entire ** process to exit. */ #ifdef SQLITE_USE_SEH #include /* Beginning of a block of code in which an exception might occur */ # define SEH_TRY __try { \ assert( walAssertLockmask(pWal) && pWal->nSehTry==0 ); \ VVA_ONLY(pWal->nSehTry++); /* The end of a block of code in which an exception might occur */ # define SEH_EXCEPT(X) \ VVA_ONLY(pWal->nSehTry--); \ assert( pWal->nSehTry==0 ); \ } __except( sehExceptionFilter(pWal, GetExceptionCode(), GetExceptionInformation() ) ){ X } /* Simulate a memory-mapping fault in the -shm file for testing purposes */ # define SEH_INJECT_FAULT sehInjectFault(pWal) /* ** The second argument is the return value of GetExceptionCode() for the ** current exception. Return EXCEPTION_EXECUTE_HANDLER if the exception code ** indicates that the exception may have been caused by accessing the *-shm ** file mapping. Or EXCEPTION_CONTINUE_SEARCH otherwise. */ static int sehExceptionFilter(Wal *pWal, int eCode, EXCEPTION_POINTERS *p){ VVA_ONLY(pWal->nSehTry--); if( eCode==EXCEPTION_IN_PAGE_ERROR ){ if( p && p->ExceptionRecord && p->ExceptionRecord->NumberParameters>=3 ){ /* From MSDN: For this type of exception, the first element of the ** ExceptionInformation[] array is a read-write flag - 0 if the exception ** was thrown while reading, 1 if while writing. The second element is ** the virtual address being accessed. The "third array element specifies ** the underlying NTSTATUS code that resulted in the exception". */ pWal->iSysErrno = (int)p->ExceptionRecord->ExceptionInformation[2]; } return EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; } /* ** If one is configured, invoke the xTestCallback callback with 650 as ** the argument. If it returns true, throw the same exception that is ** thrown by the system if the *-shm file mapping is accessed after it ** has been invalidated. */ static void sehInjectFault(Wal *pWal){ int res; assert( pWal->nSehTry>0 ); res = sqlite3FaultSim(650); if( res!=0 ){ ULONG_PTR aArg[3]; aArg[0] = 0; aArg[1] = 0; aArg[2] = (ULONG_PTR)res; RaiseException(EXCEPTION_IN_PAGE_ERROR, 0, 3, (const ULONG_PTR*)aArg); } } /* ** There are two ways to use this macro. To set a pointer to be freed ** if an exception is thrown: ** ** SEH_FREE_ON_ERROR(0, pPtr); ** ** and to cancel the same: ** ** SEH_FREE_ON_ERROR(pPtr, 0); ** ** In the first case, there must not already be a pointer registered to ** be freed. In the second case, pPtr must be the registered pointer. */ #define SEH_FREE_ON_ERROR(X,Y) \ assert( (X==0 || Y==0) && pWal->pFree==X ); pWal->pFree = Y /* ** There are two ways to use this macro. To arrange for pWal->apWiData[iPg] ** to be set to pValue if an exception is thrown: ** ** SEH_SET_ON_ERROR(iPg, pValue); ** ** and to cancel the same: ** ** SEH_SET_ON_ERROR(0, 0); */ #define SEH_SET_ON_ERROR(X,Y) pWal->iWiPg = X; pWal->pWiValue = Y #else # define SEH_TRY VVA_ONLY(pWal->nSehTry++); # define SEH_EXCEPT(X) VVA_ONLY(pWal->nSehTry--); assert( pWal->nSehTry==0 ); # define SEH_INJECT_FAULT assert( pWal->nSehTry>0 ); # define SEH_FREE_ON_ERROR(X,Y) # define SEH_SET_ON_ERROR(X,Y) #endif /* ifdef SQLITE_USE_SEH */ /* ** Obtain a pointer to the iPage'th page of the wal-index. The wal-index ** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are ** numbered from zero. ** ** If the wal-index is currently smaller the iPage pages then the size ** of the wal-index might be increased, but only if it is safe to do ** so. It is safe to enlarge the wal-index if pWal->writeLock is true ** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE. ** ** Three possible result scenarios: ** ** (1) rc==SQLITE_OK and *ppPage==Requested-Wal-Index-Page ** (2) rc>=SQLITE_ERROR and *ppPage==NULL ** (3) rc==SQLITE_OK and *ppPage==NULL // only if iPage==0 ** ** Scenario (3) can only occur when pWal->writeLock is false and iPage==0 */ static SQLITE_NOINLINE int walIndexPageRealloc( Wal *pWal, /* The WAL context */ int iPage, /* The page we seek */ volatile u32 **ppPage /* Write the page pointer here */ ){ int rc = SQLITE_OK; /* Enlarge the pWal->apWiData[] array if required */ if( pWal->nWiData<=iPage ){ sqlite3_int64 nByte = sizeof(u32*)*(iPage+1); volatile u32 **apNew; apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte); if( !apNew ){ *ppPage = 0; return SQLITE_NOMEM_BKPT; } memset((void*)&apNew[pWal->nWiData], 0, sizeof(u32*)*(iPage+1-pWal->nWiData)); pWal->apWiData = apNew; pWal->nWiData = iPage+1; } /* Request a pointer to the required page from the VFS */ assert( pWal->apWiData[iPage]==0 ); if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ); if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT; }else{ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] ); assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || (pWal->writeLock==0 && iPage==0) ); testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK ); if( rc==SQLITE_OK ){ if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM; }else if( (rc&0xff)==SQLITE_READONLY ){ pWal->readOnly |= WAL_SHM_RDONLY; if( rc==SQLITE_READONLY ){ rc = SQLITE_OK; } } } *ppPage = pWal->apWiData[iPage]; assert( iPage==0 || *ppPage || rc!=SQLITE_OK ); return rc; } static int walIndexPage( Wal *pWal, /* The WAL context */ int iPage, /* The page we seek */ volatile u32 **ppPage /* Write the page pointer here */ ){ SEH_INJECT_FAULT; if( pWal->nWiData<=iPage || (*ppPage = pWal->apWiData[iPage])==0 ){ return walIndexPageRealloc(pWal, iPage, ppPage); } return SQLITE_OK; } /* ** Return a pointer to the WalCkptInfo structure in the wal-index. */ static volatile WalCkptInfo *walCkptInfo(Wal *pWal){ assert( pWal->nWiData>0 && pWal->apWiData[0] ); SEH_INJECT_FAULT; return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]); } /* ** Return a pointer to the WalIndexHdr structure in the wal-index. */ static volatile WalIndexHdr *walIndexHdr(Wal *pWal){ assert( pWal->nWiData>0 && pWal->apWiData[0] ); SEH_INJECT_FAULT; return (volatile WalIndexHdr*)pWal->apWiData[0]; } /* ** The argument to this macro must be of type u32. On a little-endian ** architecture, it returns the u32 value that results from interpreting ** the 4 bytes as a big-endian value. On a big-endian architecture, it ** returns the value that would be produced by interpreting the 4 bytes ** of the input value as a little-endian integer. */ #define BYTESWAP32(x) ( \ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \ ) /* ** Generate or extend an 8 byte checksum based on the data in ** array aByte[] and the initial values of aIn[0] and aIn[1] (or ** initial values of 0 and 0 if aIn==NULL). ** ** The checksum is written back into aOut[] before returning. ** ** nByte must be a positive multiple of 8. */ static void walChecksumBytes( int nativeCksum, /* True for native byte-order, false for non-native */ u8 *a, /* Content to be checksummed */ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */ const u32 *aIn, /* Initial checksum value input */ u32 *aOut /* OUT: Final checksum value output */ ){ u32 s1, s2; u32 *aData = (u32 *)a; u32 *aEnd = (u32 *)&a[nByte]; if( aIn ){ s1 = aIn[0]; s2 = aIn[1]; }else{ s1 = s2 = 0; } assert( nByte>=8 ); assert( (nByte&0x00000007)==0 ); assert( nByte<=65536 ); assert( nByte%4==0 ); if( !nativeCksum ){ do { s1 += BYTESWAP32(aData[0]) + s2; s2 += BYTESWAP32(aData[1]) + s1; aData += 2; }while( aDataexclusiveMode!=WAL_HEAPMEMORY_MODE ){ sqlite3OsShmBarrier(pWal->pDbFd); } } /* ** Add the SQLITE_NO_TSAN as part of the return-type of a function ** definition as a hint that the function contains constructs that ** might give false-positive TSAN warnings. ** ** See tag-20200519-1. */ #if defined(__clang__) && !defined(SQLITE_NO_TSAN) # define SQLITE_NO_TSAN __attribute__((no_sanitize_thread)) #else # define SQLITE_NO_TSAN #endif /* ** Write the header information in pWal->hdr into the wal-index. ** ** The checksum on pWal->hdr is updated before it is written. */ static SQLITE_NO_TSAN void walIndexWriteHdr(Wal *pWal){ volatile WalIndexHdr *aHdr = walIndexHdr(pWal); const int nCksum = offsetof(WalIndexHdr, aCksum); assert( pWal->writeLock ); pWal->hdr.isInit = 1; pWal->hdr.iVersion = WALINDEX_MAX_VERSION; walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum); /* Possible TSAN false-positive. See tag-20200519-1 */ memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr)); walShmBarrier(pWal); memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr)); } /* ** This function encodes a single frame header and writes it to a buffer ** supplied by the caller. A frame-header is made up of a series of ** 4-byte big-endian integers, as follows: ** ** 0: Page number. ** 4: For commit records, the size of the database image in pages ** after the commit. For all other records, zero. ** 8: Salt-1 (copied from the wal-header) ** 12: Salt-2 (copied from the wal-header) ** 16: Checksum-1. ** 20: Checksum-2. */ static void walEncodeFrame( Wal *pWal, /* The write-ahead log */ u32 iPage, /* Database page number for frame */ u32 nTruncate, /* New db size (or 0 for non-commit frames) */ u8 *aData, /* Pointer to page data */ u8 *aFrame /* OUT: Write encoded frame here */ ){ int nativeCksum; /* True for native byte-order checksums */ u32 *aCksum = pWal->hdr.aFrameCksum; assert( WAL_FRAME_HDRSIZE==24 ); sqlite3Put4byte(&aFrame[0], iPage); sqlite3Put4byte(&aFrame[4], nTruncate); if( pWal->iReCksum==0 ){ memcpy(&aFrame[8], pWal->hdr.aSalt, 8); nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); sqlite3Put4byte(&aFrame[16], aCksum[0]); sqlite3Put4byte(&aFrame[20], aCksum[1]); }else{ memset(&aFrame[8], 0, 16); } } /* ** Check to see if the frame with header in aFrame[] and content ** in aData[] is valid. If it is a valid frame, fill *piPage and ** *pnTruncate and return true. Return if the frame is not valid. */ static int walDecodeFrame( Wal *pWal, /* The write-ahead log */ u32 *piPage, /* OUT: Database page number for frame */ u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */ u8 *aData, /* Pointer to page data (for checksum) */ u8 *aFrame /* Frame data */ ){ int nativeCksum; /* True for native byte-order checksums */ u32 *aCksum = pWal->hdr.aFrameCksum; u32 pgno; /* Page number of the frame */ assert( WAL_FRAME_HDRSIZE==24 ); /* A frame is only valid if the salt values in the frame-header ** match the salt values in the wal-header. */ if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){ return 0; } /* A frame is only valid if the page number is greater than zero. */ pgno = sqlite3Get4byte(&aFrame[0]); if( pgno==0 ){ return 0; } /* A frame is only valid if a checksum of the WAL header, ** all prior frames, the first 16 bytes of this frame-header, ** and the frame-data matches the checksum in the last 8 ** bytes of this frame-header. */ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); if( aCksum[0]!=sqlite3Get4byte(&aFrame[16]) || aCksum[1]!=sqlite3Get4byte(&aFrame[20]) ){ /* Checksum failed. */ return 0; } /* If we reach this point, the frame is valid. Return the page number ** and the new database size. */ *piPage = pgno; *pnTruncate = sqlite3Get4byte(&aFrame[4]); return 1; } #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) /* ** Names of locks. This routine is used to provide debugging output and is not ** a part of an ordinary build. */ static const char *walLockName(int lockIdx){ if( lockIdx==WAL_WRITE_LOCK ){ return "WRITE-LOCK"; }else if( lockIdx==WAL_CKPT_LOCK ){ return "CKPT-LOCK"; }else if( lockIdx==WAL_RECOVER_LOCK ){ return "RECOVER-LOCK"; }else{ static char zName[15]; sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]", lockIdx-WAL_READ_LOCK(0)); return zName; } } #endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */ /* ** Set or release locks on the WAL. Locks are either shared or exclusive. ** A lock cannot be moved directly between shared and exclusive - it must go ** through the unlocked state first. ** ** In locking_mode=EXCLUSIVE, all of these routines become no-ops. */ static int walLockShared(Wal *pWal, int lockIdx){ int rc; if( pWal->exclusiveMode ) return SQLITE_OK; rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1, SQLITE_SHM_LOCK | SQLITE_SHM_SHARED); WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal, walLockName(lockIdx), rc ? "failed" : "ok")); VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); ) #ifdef SQLITE_USE_SEH if( rc==SQLITE_OK ) pWal->lockMask |= (1 << lockIdx); #endif return rc; } static void walUnlockShared(Wal *pWal, int lockIdx){ if( pWal->exclusiveMode ) return; (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1, SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED); #ifdef SQLITE_USE_SEH pWal->lockMask &= ~(1 << lockIdx); #endif WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx))); } static int walLockExclusive(Wal *pWal, int lockIdx, int n){ int rc; if( pWal->exclusiveMode ) return SQLITE_OK; rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n, SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE); WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal, walLockName(lockIdx), n, rc ? "failed" : "ok")); VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); ) #ifdef SQLITE_USE_SEH if( rc==SQLITE_OK ){ pWal->lockMask |= (((1<exclusiveMode ) return; (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n, SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE); #ifdef SQLITE_USE_SEH pWal->lockMask &= ~(((1<0 ); assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 ); return (iPage*HASHTABLE_HASH_1) & (HASHTABLE_NSLOT-1); } static int walNextHash(int iPriorHash){ return (iPriorHash+1)&(HASHTABLE_NSLOT-1); } /* ** An instance of the WalHashLoc object is used to describe the location ** of a page hash table in the wal-index. This becomes the return value ** from walHashGet(). */ typedef struct WalHashLoc WalHashLoc; struct WalHashLoc { volatile ht_slot *aHash; /* Start of the wal-index hash table */ volatile u32 *aPgno; /* aPgno[1] is the page of first frame indexed */ u32 iZero; /* One less than the frame number of first indexed*/ }; /* ** Return pointers to the hash table and page number array stored on ** page iHash of the wal-index. The wal-index is broken into 32KB pages ** numbered starting from 0. ** ** Set output variable pLoc->aHash to point to the start of the hash table ** in the wal-index file. Set pLoc->iZero to one less than the frame ** number of the first frame indexed by this hash table. If a ** slot in the hash table is set to N, it refers to frame number ** (pLoc->iZero+N) in the log. ** ** Finally, set pLoc->aPgno so that pLoc->aPgno[0] is the page number of the ** first frame indexed by the hash table, frame (pLoc->iZero). */ static int walHashGet( Wal *pWal, /* WAL handle */ int iHash, /* Find the iHash'th table */ WalHashLoc *pLoc /* OUT: Hash table location */ ){ int rc; /* Return code */ rc = walIndexPage(pWal, iHash, &pLoc->aPgno); assert( rc==SQLITE_OK || iHash>0 ); if( pLoc->aPgno ){ pLoc->aHash = (volatile ht_slot *)&pLoc->aPgno[HASHTABLE_NPAGE]; if( iHash==0 ){ pLoc->aPgno = &pLoc->aPgno[WALINDEX_HDR_SIZE/sizeof(u32)]; pLoc->iZero = 0; }else{ pLoc->iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE; } }else if( NEVER(rc==SQLITE_OK) ){ rc = SQLITE_ERROR; } return rc; } /* ** Return the number of the wal-index page that contains the hash-table ** and page-number array that contain entries corresponding to WAL frame ** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages ** are numbered starting from 0. */ static int walFramePage(u32 iFrame){ int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE; assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE) && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE) && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)) && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE) && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE)) ); assert( iHash>=0 ); return iHash; } /* ** Return the page number associated with frame iFrame in this WAL. */ static u32 walFramePgno(Wal *pWal, u32 iFrame){ int iHash = walFramePage(iFrame); SEH_INJECT_FAULT; if( iHash==0 ){ return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1]; } return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE]; } /* ** Remove entries from the hash table that point to WAL slots greater ** than pWal->hdr.mxFrame. ** ** This function is called whenever pWal->hdr.mxFrame is decreased due ** to a rollback or savepoint. ** ** At most only the hash table containing pWal->hdr.mxFrame needs to be ** updated. Any later hash tables will be automatically cleared when ** pWal->hdr.mxFrame advances to the point where those hash tables are ** actually needed. */ static void walCleanupHash(Wal *pWal){ WalHashLoc sLoc; /* Hash table location */ int iLimit = 0; /* Zero values greater than this */ int nByte; /* Number of bytes to zero in aPgno[] */ int i; /* Used to iterate through aHash[] */ assert( pWal->writeLock ); testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 ); testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE ); testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 ); if( pWal->hdr.mxFrame==0 ) return; /* Obtain pointers to the hash-table and page-number array containing ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed ** that the page said hash-table and array reside on is already mapped.(1) */ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) ); assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] ); i = walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc); if( NEVER(i) ) return; /* Defense-in-depth, in case (1) above is wrong */ /* Zero all hash-table entries that correspond to frame numbers greater ** than pWal->hdr.mxFrame. */ iLimit = pWal->hdr.mxFrame - sLoc.iZero; assert( iLimit>0 ); for(i=0; iiLimit ){ sLoc.aHash[i] = 0; } } /* Zero the entries in the aPgno array that correspond to frames with ** frame numbers greater than pWal->hdr.mxFrame. */ nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit]); assert( nByte>=0 ); memset((void *)&sLoc.aPgno[iLimit], 0, nByte); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* Verify that the every entry in the mapping region is still reachable ** via the hash table even after the cleanup. */ if( iLimit ){ int j; /* Loop counter */ int iKey; /* Hash key */ for(j=0; j=0 ); memset((void*)sLoc.aPgno, 0, nByte); } /* If the entry in aPgno[] is already set, then the previous writer ** must have exited unexpectedly in the middle of a transaction (after ** writing one or more dirty pages to the WAL to free up memory). ** Remove the remnants of that writers uncommitted transaction from ** the hash-table before writing any new entries. */ if( sLoc.aPgno[idx-1] ){ walCleanupHash(pWal); assert( !sLoc.aPgno[idx-1] ); } /* Write the aPgno[] array entry and the hash-table slot. */ nCollide = idx; for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; } sLoc.aPgno[idx-1] = iPage; AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* Verify that the number of entries in the hash table exactly equals ** the number of entries in the mapping region. */ { int i; /* Loop counter */ int nEntry = 0; /* Number of entries in the hash table */ for(i=0; ickptLock==1 || pWal->ckptLock==0 ); assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 ); assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE ); assert( pWal->writeLock ); iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); if( rc ){ return rc; } WALTRACE(("WAL%p: recovery begin...\n", pWal)); memset(&pWal->hdr, 0, sizeof(WalIndexHdr)); rc = sqlite3OsFileSize(pWal->pWalFd, &nSize); if( rc!=SQLITE_OK ){ goto recovery_error; } if( nSize>WAL_HDRSIZE ){ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */ u32 *aPrivate = 0; /* Heap copy of *-shm hash being populated */ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */ int szFrame; /* Number of bytes in buffer aFrame[] */ u8 *aData; /* Pointer to data part of aFrame buffer */ int szPage; /* Page size according to the log */ u32 magic; /* Magic value read from WAL header */ u32 version; /* Magic value read from WAL header */ int isValid; /* True if this frame is valid */ u32 iPg; /* Current 32KB wal-index page */ u32 iLastFrame; /* Last frame in wal, based on nSize alone */ /* Read in the WAL header. */ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0); if( rc!=SQLITE_OK ){ goto recovery_error; } /* If the database page size is not a power of two, or is greater than ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid ** data. Similarly, if the 'magic' value is invalid, ignore the whole ** WAL file. */ magic = sqlite3Get4byte(&aBuf[0]); szPage = sqlite3Get4byte(&aBuf[8]); if( (magic&0xFFFFFFFE)!=WAL_MAGIC || szPage&(szPage-1) || szPage>SQLITE_MAX_PAGE_SIZE || szPage<512 ){ goto finished; } pWal->hdr.bigEndCksum = (u8)(magic&0x00000001); pWal->szPage = szPage; pWal->nCkpt = sqlite3Get4byte(&aBuf[12]); memcpy(&pWal->hdr.aSalt, &aBuf[16], 8); /* Verify that the WAL header checksum is correct */ walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN, aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum ); if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24]) || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28]) ){ goto finished; } /* Verify that the version number on the WAL format is one that ** are able to understand */ version = sqlite3Get4byte(&aBuf[4]); if( version!=WAL_MAX_VERSION ){ rc = SQLITE_CANTOPEN_BKPT; goto finished; } /* Malloc a buffer to read frames into. */ szFrame = szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ); SEH_FREE_ON_ERROR(0, aFrame); if( !aFrame ){ rc = SQLITE_NOMEM_BKPT; goto recovery_error; } aData = &aFrame[WAL_FRAME_HDRSIZE]; aPrivate = (u32*)&aData[szPage]; /* Read all frames from the log file. */ iLastFrame = (nSize - WAL_HDRSIZE) / szFrame; for(iPg=0; iPg<=(u32)walFramePage(iLastFrame); iPg++){ u32 *aShare; u32 iFrame; /* Index of last frame read */ u32 iLast = MIN(iLastFrame, HASHTABLE_NPAGE_ONE+iPg*HASHTABLE_NPAGE); u32 iFirst = 1 + (iPg==0?0:HASHTABLE_NPAGE_ONE+(iPg-1)*HASHTABLE_NPAGE); u32 nHdr, nHdr32; rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare); assert( aShare!=0 || rc!=SQLITE_OK ); if( aShare==0 ) break; SEH_SET_ON_ERROR(iPg, aShare); pWal->apWiData[iPg] = aPrivate; for(iFrame=iFirst; iFrame<=iLast; iFrame++){ i64 iOffset = walFrameOffset(iFrame, szPage); u32 pgno; /* Database page number for frame */ u32 nTruncate; /* dbsize field from frame header */ /* Read and decode the next log frame. */ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset); if( rc!=SQLITE_OK ) break; isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame); if( !isValid ) break; rc = walIndexAppend(pWal, iFrame, pgno); if( NEVER(rc!=SQLITE_OK) ) break; /* If nTruncate is non-zero, this is a commit record. */ if( nTruncate ){ pWal->hdr.mxFrame = iFrame; pWal->hdr.nPage = nTruncate; pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16)); testcase( szPage<=32768 ); testcase( szPage>=65536 ); aFrameCksum[0] = pWal->hdr.aFrameCksum[0]; aFrameCksum[1] = pWal->hdr.aFrameCksum[1]; } } pWal->apWiData[iPg] = aShare; SEH_SET_ON_ERROR(0,0); nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0); nHdr32 = nHdr / sizeof(u32); #ifndef SQLITE_SAFER_WALINDEX_RECOVERY /* Memcpy() should work fine here, on all reasonable implementations. ** Technically, memcpy() might change the destination to some ** intermediate value before setting to the final value, and that might ** cause a concurrent reader to malfunction. Memcpy() is allowed to ** do that, according to the spec, but no memcpy() implementation that ** we know of actually does that, which is why we say that memcpy() ** is safe for this. Memcpy() is certainly a lot faster. */ memcpy(&aShare[nHdr32], &aPrivate[nHdr32], WALINDEX_PGSZ-nHdr); #else /* In the event that some platform is found for which memcpy() ** changes the destination to some intermediate value before ** setting the final value, this alternative copy routine is ** provided. */ { int i; for(i=nHdr32; ihdr.aFrameCksum[0] = aFrameCksum[0]; pWal->hdr.aFrameCksum[1] = aFrameCksum[1]; walIndexWriteHdr(pWal); /* Reset the checkpoint-header. This is safe because this thread is ** currently holding locks that exclude all other writers and ** checkpointers. Then set the values of read-mark slots 1 through N. */ pInfo = walCkptInfo(pWal); pInfo->nBackfill = 0; pInfo->nBackfillAttempted = pWal->hdr.mxFrame; pInfo->aReadMark[0] = 0; for(i=1; ihdr.mxFrame ){ pInfo->aReadMark[i] = pWal->hdr.mxFrame; }else{ pInfo->aReadMark[i] = READMARK_NOT_USED; } SEH_INJECT_FAULT; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); }else if( rc!=SQLITE_BUSY ){ goto recovery_error; } } /* If more than one frame was recovered from the log file, report an ** event via sqlite3_log(). This is to help with identifying performance ** problems caused by applications routinely shutting down without ** checkpointing the log file. */ if( pWal->hdr.nPage ){ sqlite3_log(SQLITE_NOTICE_RECOVER_WAL, "recovered %d frames from WAL file %s", pWal->hdr.mxFrame, pWal->zWalName ); } } recovery_error: WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok")); walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); return rc; } /* ** Close an open wal-index. */ static void walIndexClose(Wal *pWal, int isDelete){ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE || pWal->bShmUnreliable ){ int i; for(i=0; inWiData; i++){ sqlite3_free((void *)pWal->apWiData[i]); pWal->apWiData[i] = 0; } } if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){ sqlite3OsShmUnmap(pWal->pDbFd, isDelete); } } /* ** Open a connection to the WAL file zWalName. The database file must ** already be opened on connection pDbFd. The buffer that zWalName points ** to must remain valid for the lifetime of the returned Wal* handle. ** ** A SHARED lock should be held on the database file when this function ** is called. The purpose of this SHARED lock is to prevent any other ** client from unlinking the WAL or wal-index file. If another process ** were to do this just after this client opened one of these files, the ** system would be badly broken. ** ** If the log file is successfully opened, SQLITE_OK is returned and ** *ppWal is set to point to a new WAL handle. If an error occurs, ** an SQLite error code is returned and *ppWal is left unmodified. */ SQLITE_PRIVATE int sqlite3WalOpen( sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */ sqlite3_file *pDbFd, /* The open database file */ const char *zWalName, /* Name of the WAL file */ int bNoShm, /* True to run in heap-memory mode */ i64 mxWalSize, /* Truncate WAL to this size on reset */ Wal **ppWal /* OUT: Allocated Wal handle */ ){ int rc; /* Return Code */ Wal *pRet; /* Object to allocate and return */ int flags; /* Flags passed to OsOpen() */ assert( zWalName && zWalName[0] ); assert( pDbFd ); /* Verify the values of various constants. Any changes to the values ** of these constants would result in an incompatible on-disk format ** for the -shm file. Any change that causes one of these asserts to ** fail is a backward compatibility problem, even if the change otherwise ** works. ** ** This table also serves as a helpful cross-reference when trying to ** interpret hex dumps of the -shm file. */ assert( 48 == sizeof(WalIndexHdr) ); assert( 40 == sizeof(WalCkptInfo) ); assert( 120 == WALINDEX_LOCK_OFFSET ); assert( 136 == WALINDEX_HDR_SIZE ); assert( 4096 == HASHTABLE_NPAGE ); assert( 4062 == HASHTABLE_NPAGE_ONE ); assert( 8192 == HASHTABLE_NSLOT ); assert( 383 == HASHTABLE_HASH_1 ); assert( 32768 == WALINDEX_PGSZ ); assert( 8 == SQLITE_SHM_NLOCK ); assert( 5 == WAL_NREADER ); assert( 24 == WAL_FRAME_HDRSIZE ); assert( 32 == WAL_HDRSIZE ); assert( 120 == WALINDEX_LOCK_OFFSET + WAL_WRITE_LOCK ); assert( 121 == WALINDEX_LOCK_OFFSET + WAL_CKPT_LOCK ); assert( 122 == WALINDEX_LOCK_OFFSET + WAL_RECOVER_LOCK ); assert( 123 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(0) ); assert( 124 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(1) ); assert( 125 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(2) ); assert( 126 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(3) ); assert( 127 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(4) ); /* In the amalgamation, the os_unix.c and os_win.c source files come before ** this source file. Verify that the #defines of the locking byte offsets ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value. ** For that matter, if the lock offset ever changes from its initial design ** value of 120, we need to know that so there is an assert() to check it. */ #ifdef WIN_SHM_BASE assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET ); #endif #ifdef UNIX_SHM_BASE assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET ); #endif /* Allocate an instance of struct Wal to return. */ *ppWal = 0; pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile); if( !pRet ){ return SQLITE_NOMEM_BKPT; } pRet->pVfs = pVfs; pRet->pWalFd = (sqlite3_file *)&pRet[1]; pRet->pDbFd = pDbFd; pRet->readLock = -1; pRet->mxWalSize = mxWalSize; pRet->zWalName = zWalName; pRet->syncHeader = 1; pRet->padToSectorBoundary = 1; pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); /* Open file handle on the write-ahead log file. */ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags); if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){ pRet->readOnly = WAL_RDONLY; } if( rc!=SQLITE_OK ){ walIndexClose(pRet, 0); sqlite3OsClose(pRet->pWalFd); sqlite3_free(pRet); }else{ int iDC = sqlite3OsDeviceCharacteristics(pDbFd); if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; } if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){ pRet->padToSectorBoundary = 0; } *ppWal = pRet; WALTRACE(("WAL%d: opened\n", pRet)); } return rc; } /* ** Change the size to which the WAL file is truncated on each reset. */ SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){ if( pWal ) pWal->mxWalSize = iLimit; } /* ** Find the smallest page number out of all pages held in the WAL that ** has not been returned by any prior invocation of this method on the ** same WalIterator object. Write into *piFrame the frame index where ** that page was last written into the WAL. Write into *piPage the page ** number. ** ** Return 0 on success. If there are no pages in the WAL with a page ** number larger than *piPage, then return 1. */ static int walIteratorNext( WalIterator *p, /* Iterator */ u32 *piPage, /* OUT: The page number of the next page */ u32 *piFrame /* OUT: Wal frame index of next page */ ){ u32 iMin; /* Result pgno must be greater than iMin */ u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */ int i; /* For looping through segments */ iMin = p->iPrior; assert( iMin<0xffffffff ); for(i=p->nSegment-1; i>=0; i--){ struct WalSegment *pSegment = &p->aSegment[i]; while( pSegment->iNextnEntry ){ u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]]; if( iPg>iMin ){ if( iPgiZero + pSegment->aIndex[pSegment->iNext]; } break; } pSegment->iNext++; } } *piPage = p->iPrior = iRet; return (iRet==0xFFFFFFFF); } /* ** This function merges two sorted lists into a single sorted list. ** ** aLeft[] and aRight[] are arrays of indices. The sort key is ** aContent[aLeft[]] and aContent[aRight[]]. Upon entry, the following ** is guaranteed for all J0 && nRight>0 ); while( iRight=nRight || aContent[aLeft[iLeft]]=nLeft || aContent[aLeft[iLeft]]>dbpage ); assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage ); } *paRight = aLeft; *pnRight = iOut; memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut); } /* ** Sort the elements in list aList using aContent[] as the sort key. ** Remove elements with duplicate keys, preferring to keep the ** larger aList[] values. ** ** The aList[] entries are indices into aContent[]. The values in ** aList[] are to be sorted so that for all J0 ); assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) ); for(iList=0; iListaList && p->nList<=(1<aList==&aList[iList&~((2<aList, p->nList, &aMerge, &nMerge, aBuffer); } aSub[iSub].aList = aMerge; aSub[iSub].nList = nMerge; } for(iSub++; iSubnList<=(1<aList==&aList[nList&~((2<aList, p->nList, &aMerge, &nMerge, aBuffer); } } assert( aMerge==aList ); *pnList = nMerge; #ifdef SQLITE_DEBUG { int i; for(i=1; i<*pnList; i++){ assert( aContent[aList[i]] > aContent[aList[i-1]] ); } } #endif } /* ** Free an iterator allocated by walIteratorInit(). */ static void walIteratorFree(WalIterator *p){ sqlite3_free(p); } /* ** Construct a WalInterator object that can be used to loop over all ** pages in the WAL following frame nBackfill in ascending order. Frames ** nBackfill or earlier may be included - excluding them is an optimization ** only. The caller must hold the checkpoint lock. ** ** On success, make *pp point to the newly allocated WalInterator object ** return SQLITE_OK. Otherwise, return an error code. If this routine ** returns an error, the value of *pp is undefined. ** ** The calling routine should invoke walIteratorFree() to destroy the ** WalIterator object when it has finished with it. */ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ WalIterator *p; /* Return value */ int nSegment; /* Number of segments to merge */ u32 iLast; /* Last frame in log */ sqlite3_int64 nByte; /* Number of bytes to allocate */ int i; /* Iterator variable */ ht_slot *aTmp; /* Temp space used by merge-sort */ int rc = SQLITE_OK; /* Return Code */ /* This routine only runs while holding the checkpoint lock. And ** it only runs if there is actually content in the log (mxFrame>0). */ assert( pWal->ckptLock && pWal->hdr.mxFrame>0 ); iLast = pWal->hdr.mxFrame; /* Allocate space for the WalIterator object. */ nSegment = walFramePage(iLast) + 1; nByte = sizeof(WalIterator) + (nSegment-1)*sizeof(struct WalSegment) + iLast*sizeof(ht_slot); p = (WalIterator *)sqlite3_malloc64(nByte + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) ); if( !p ){ return SQLITE_NOMEM_BKPT; } memset(p, 0, nByte); p->nSegment = nSegment; aTmp = (ht_slot*)&(((u8*)p)[nByte]); SEH_FREE_ON_ERROR(0, p); for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && iaSegment[p->nSegment])[sLoc.iZero]; sLoc.iZero++; for(j=0; jaSegment[i].iZero = sLoc.iZero; p->aSegment[i].nEntry = nEntry; p->aSegment[i].aIndex = aIndex; p->aSegment[i].aPgno = (u32 *)sLoc.aPgno; } } if( rc!=SQLITE_OK ){ SEH_FREE_ON_ERROR(p, 0); walIteratorFree(p); p = 0; } *pp = p; return rc; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* ** Attempt to enable blocking locks that block for nMs ms. Return 1 if ** blocking locks are successfully enabled, or 0 otherwise. */ static int walEnableBlockingMs(Wal *pWal, int nMs){ int rc = sqlite3OsFileControl( pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&nMs ); return (rc==SQLITE_OK); } /* ** Attempt to enable blocking locks. Blocking locks are enabled only if (a) ** they are supported by the VFS, and (b) the database handle is configured ** with a busy-timeout. Return 1 if blocking locks are successfully enabled, ** or 0 otherwise. */ static int walEnableBlocking(Wal *pWal){ int res = 0; if( pWal->db ){ int tmout = pWal->db->busyTimeout; if( tmout ){ res = walEnableBlockingMs(pWal, tmout); } } return res; } /* ** Disable blocking locks. */ static void walDisableBlocking(Wal *pWal){ int tmout = 0; sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout); } /* ** If parameter bLock is true, attempt to enable blocking locks, take ** the WRITER lock, and then disable blocking locks. If blocking locks ** cannot be enabled, no attempt to obtain the WRITER lock is made. Return ** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not ** an error if blocking locks can not be enabled. ** ** If the bLock parameter is false and the WRITER lock is held, release it. */ SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock){ int rc = SQLITE_OK; assert( pWal->readLock<0 || bLock==0 ); if( bLock ){ assert( pWal->db ); if( walEnableBlocking(pWal) ){ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1); if( rc==SQLITE_OK ){ pWal->writeLock = 1; } walDisableBlocking(pWal); } }else if( pWal->writeLock ){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); pWal->writeLock = 0; } return rc; } /* ** Set the database handle used to determine if blocking locks are required. */ SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){ pWal->db = db; } #else # define walEnableBlocking(x) 0 # define walDisableBlocking(x) # define walEnableBlockingMs(pWal, ms) 0 # define sqlite3WalDb(pWal, db) #endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */ /* ** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and ** n. If the attempt fails and parameter xBusy is not NULL, then it is a ** busy-handler function. Invoke it and retry the lock until either the ** lock is successfully obtained or the busy-handler returns 0. */ static int walBusyLock( Wal *pWal, /* WAL connection */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int lockIdx, /* Offset of first byte to lock */ int n /* Number of bytes to lock */ ){ int rc; do { rc = walLockExclusive(pWal, lockIdx, n); }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) ); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ){ walDisableBlocking(pWal); rc = SQLITE_BUSY; } #endif return rc; } /* ** The cache of the wal-index header must be valid to call this function. ** Return the page-size in bytes used by the database. */ static int walPagesize(Wal *pWal){ return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16); } /* ** The following is guaranteed when this function is called: ** ** a) the WRITER lock is held, ** b) the entire log file has been checkpointed, and ** c) any existing readers are reading exclusively from the database ** file - there are no readers that may attempt to read a frame from ** the log file. ** ** This function updates the shared-memory structures so that the next ** client to write to the database (which may be this one) does so by ** writing frames into the start of the log file. ** ** The value of parameter salt1 is used as the aSalt[1] value in the ** new wal-index header. It should be passed a pseudo-random value (i.e. ** one obtained from sqlite3_randomness()). */ static void walRestartHdr(Wal *pWal, u32 salt1){ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); int i; /* Loop counter */ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ pWal->nCkpt++; pWal->hdr.mxFrame = 0; sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); memcpy(&pWal->hdr.aSalt[1], &salt1, 4); walIndexWriteHdr(pWal); AtomicStore(&pInfo->nBackfill, 0); pInfo->nBackfillAttempted = 0; pInfo->aReadMark[1] = 0; for(i=2; iaReadMark[i] = READMARK_NOT_USED; assert( pInfo->aReadMark[0]==0 ); } /* ** Copy as much content as we can from the WAL back into the database file ** in response to an sqlite3_wal_checkpoint() request or the equivalent. ** ** The amount of information copies from WAL to database might be limited ** by active readers. This routine will never overwrite a database page ** that a concurrent reader might be using. ** ** All I/O barrier operations (a.k.a fsyncs) occur in this routine when ** SQLite is in WAL-mode in synchronous=NORMAL. That means that if ** checkpoints are always run by a background thread or background ** process, foreground threads will never block on a lengthy fsync call. ** ** Fsync is called on the WAL before writing content out of the WAL and ** into the database. This ensures that if the new content is persistent ** in the WAL and can be recovered following a power-loss or hard reset. ** ** Fsync is also called on the database file if (and only if) the entire ** WAL content is copied into the database file. This second fsync makes ** it safe to delete the WAL since the new content will persist in the ** database file. ** ** This routine uses and updates the nBackfill field of the wal-index header. ** This is the only routine that will increase the value of nBackfill. ** (A WAL reset or recovery will revert nBackfill to zero, but not increase ** its value.) ** ** The caller must be holding sufficient locks to ensure that no other ** checkpoint is running (in any other thread or process) at the same ** time. */ static int walCheckpoint( Wal *pWal, /* Wal connection */ sqlite3 *db, /* Check for interrupts on this handle */ int eMode, /* One of PASSIVE, FULL or RESTART */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int sync_flags, /* Flags for OsSync() (or 0) */ u8 *zBuf /* Temporary buffer to use */ ){ int rc = SQLITE_OK; /* Return code */ int szPage; /* Database page-size */ WalIterator *pIter = 0; /* Wal iterator context */ u32 iDbpage = 0; /* Next database page to write */ u32 iFrame = 0; /* Wal frame containing data for iDbpage */ u32 mxSafeFrame; /* Max frame that can be backfilled */ u32 mxPage; /* Max database page to write */ int i; /* Loop counter */ volatile WalCkptInfo *pInfo; /* The checkpoint status information */ szPage = walPagesize(pWal); testcase( szPage<=32768 ); testcase( szPage>=65536 ); pInfo = walCkptInfo(pWal); if( pInfo->nBackfillhdr.mxFrame ){ /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); /* Compute in mxSafeFrame the index of the last frame of the WAL that is ** safe to write into the database. Frames beyond mxSafeFrame might ** overwrite database pages that are in use by active readers and thus ** cannot be backfilled from the WAL. */ mxSafeFrame = pWal->hdr.mxFrame; mxPage = pWal->hdr.nPage; for(i=1; iaReadMark+i); SEH_INJECT_FAULT; if( mxSafeFrame>y ){ assert( y<=pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED); AtomicStore(pInfo->aReadMark+i, iMark); SEH_INJECT_FAULT; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); }else if( rc==SQLITE_BUSY ){ mxSafeFrame = y; xBusy = 0; }else{ goto walcheckpoint_out; } } } /* Allocate the iterator */ if( pInfo->nBackfillnBackfill, &pIter); assert( rc==SQLITE_OK || pIter==0 ); } if( pIter && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK ){ u32 nBackfill = pInfo->nBackfill; pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT; /* Sync the WAL to disk */ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); /* If the database may grow as a result of this checkpoint, hint ** about the eventual size of the db file to the VFS layer. */ if( rc==SQLITE_OK ){ i64 nReq = ((i64)mxPage * szPage); i64 nSize; /* Current size of database file */ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0); rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); if( rc==SQLITE_OK && nSizehdr.mxFrame*szPage)pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); } } } /* Iterate through the contents of the WAL, copying data to the db file */ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ i64 iOffset; assert( walFramePgno(pWal, iFrame)==iDbpage ); SEH_INJECT_FAULT; if( AtomicLoad(&db->u1.isInterrupted) ){ rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; break; } if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ continue; } iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; iOffset = (iDbpage-1)*(i64)szPage; testcase( IS_BIG_INT(iOffset) ); rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; } sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0); /* If work was actually accomplished... */ if( rc==SQLITE_OK ){ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ i64 szDb = pWal->hdr.nPage*(i64)szPage; testcase( IS_BIG_INT(szDb) ); rc = sqlite3OsTruncate(pWal->pDbFd, szDb); if( rc==SQLITE_OK ){ rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); } } if( rc==SQLITE_OK ){ AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT; } } /* Release the reader lock held while backfilling */ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); } if( rc==SQLITE_BUSY ){ /* Reset the return code so as not to report a checkpoint failure ** just because there are active readers. */ rc = SQLITE_OK; } } /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the ** entire wal file has been copied into the database file, then block ** until all readers have finished using the wal file. This ensures that ** the next process to write to the database restarts the wal file. */ if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){ assert( pWal->writeLock ); SEH_INJECT_FAULT; if( pInfo->nBackfillhdr.mxFrame ){ rc = SQLITE_BUSY; }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ u32 salt1; sqlite3_randomness(4, &salt1); assert( pInfo->nBackfill==pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); if( rc==SQLITE_OK ){ if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){ /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as ** SQLITE_CHECKPOINT_RESTART with the addition that it also ** truncates the log file to zero bytes just prior to a ** successful return. ** ** In theory, it might be safe to do this without updating the ** wal-index header in shared memory, as all subsequent reader or ** writer clients should see that the entire log file has been ** checkpointed and behave accordingly. This seems unsafe though, ** as it would leave the system in a state where the contents of ** the wal-index header do not match the contents of the ** file-system. To avoid this, update the wal-index header to ** indicate that the log file contains zero valid frames. */ walRestartHdr(pWal, salt1); rc = sqlite3OsTruncate(pWal->pWalFd, 0); } walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); } } } walcheckpoint_out: SEH_FREE_ON_ERROR(pIter, 0); walIteratorFree(pIter); return rc; } /* ** If the WAL file is currently larger than nMax bytes in size, truncate ** it to exactly nMax bytes. If an error occurs while doing so, ignore it. */ static void walLimitSize(Wal *pWal, i64 nMax){ i64 sz; int rx; sqlite3BeginBenignMalloc(); rx = sqlite3OsFileSize(pWal->pWalFd, &sz); if( rx==SQLITE_OK && (sz > nMax ) ){ rx = sqlite3OsTruncate(pWal->pWalFd, nMax); } sqlite3EndBenignMalloc(); if( rx ){ sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName); } } #ifdef SQLITE_USE_SEH /* ** This is the "standard" exception handler used in a few places to handle ** an exception thrown by reading from the *-shm mapping after it has become ** invalid in SQLITE_USE_SEH builds. It is used as follows: ** ** SEH_TRY { ... } ** SEH_EXCEPT( rc = walHandleException(pWal); ) ** ** This function does three things: ** ** 1) Determines the locks that should be held, based on the contents of ** the Wal.readLock, Wal.writeLock and Wal.ckptLock variables. All other ** held locks are assumed to be transient locks that would have been ** released had the exception not been thrown and are dropped. ** ** 2) Frees the pointer at Wal.pFree, if any, using sqlite3_free(). ** ** 3) Set pWal->apWiData[pWal->iWiPg] to pWal->pWiValue if not NULL ** ** 4) Returns SQLITE_IOERR. */ static int walHandleException(Wal *pWal){ if( pWal->exclusiveMode==0 ){ static const int S = 1; static const int E = (1<lockMask & ~( (pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock))) | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0) | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0) ); for(ii=0; iipFree); pWal->pFree = 0; if( pWal->pWiValue ){ pWal->apWiData[pWal->iWiPg] = pWal->pWiValue; pWal->pWiValue = 0; } return SQLITE_IOERR_IN_PAGE; } /* ** Assert that the Wal.lockMask mask, which indicates the locks held ** by the connenction, is consistent with the Wal.readLock, Wal.writeLock ** and Wal.ckptLock variables. To be used as: ** ** assert( walAssertLockmask(pWal) ); */ static int walAssertLockmask(Wal *pWal){ if( pWal->exclusiveMode==0 ){ static const int S = 1; static const int E = (1<readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock))) | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0) | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0) #ifdef SQLITE_ENABLE_SNAPSHOT | (pWal->pSnapshot ? (pWal->lockMask & (1 << WAL_CKPT_LOCK)) : 0) #endif ); assert( mExpect==pWal->lockMask ); } return 1; } /* ** Return and zero the "system error" field set when an ** EXCEPTION_IN_PAGE_ERROR exception is caught. */ SQLITE_PRIVATE int sqlite3WalSystemErrno(Wal *pWal){ int iRet = 0; if( pWal ){ iRet = pWal->iSysErrno; pWal->iSysErrno = 0; } return iRet; } #else # define walAssertLockmask(x) 1 #endif /* ifdef SQLITE_USE_SEH */ /* ** Close a connection to a log file. */ SQLITE_PRIVATE int sqlite3WalClose( Wal *pWal, /* Wal to close */ sqlite3 *db, /* For interrupt flag */ int sync_flags, /* Flags to pass to OsSync() (or 0) */ int nBuf, u8 *zBuf /* Buffer of at least nBuf bytes */ ){ int rc = SQLITE_OK; if( pWal ){ int isDelete = 0; /* True to unlink wal and wal-index files */ assert( walAssertLockmask(pWal) ); /* If an EXCLUSIVE lock can be obtained on the database file (using the ** ordinary, rollback-mode locking methods, this guarantees that the ** connection associated with this log file is the only connection to ** the database. In this case checkpoint the database and unlink both ** the wal and wal-index files. ** ** The EXCLUSIVE lock is not released before returning. */ if( zBuf!=0 && SQLITE_OK==(rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE)) ){ if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; } rc = sqlite3WalCheckpoint(pWal, db, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0 ); if( rc==SQLITE_OK ){ int bPersist = -1; sqlite3OsFileControlHint( pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist ); if( bPersist!=1 ){ /* Try to delete the WAL file if the checkpoint completed and ** fsynced (rc==SQLITE_OK) and if we are not in persistent-wal ** mode (!bPersist) */ isDelete = 1; }else if( pWal->mxWalSize>=0 ){ /* Try to truncate the WAL file to zero bytes if the checkpoint ** completed and fsynced (rc==SQLITE_OK) and we are in persistent ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a ** non-negative value (pWal->mxWalSize>=0). Note that we truncate ** to zero bytes as truncating to the journal_size_limit might ** leave a corrupt WAL file on disk. */ walLimitSize(pWal, 0); } } } walIndexClose(pWal, isDelete); sqlite3OsClose(pWal->pWalFd); if( isDelete ){ sqlite3BeginBenignMalloc(); sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0); sqlite3EndBenignMalloc(); } WALTRACE(("WAL%p: closed\n", pWal)); sqlite3_free((void *)pWal->apWiData); sqlite3_free(pWal); } return rc; } /* ** Try to read the wal-index header. Return 0 on success and 1 if ** there is a problem. ** ** The wal-index is in shared memory. Another thread or process might ** be writing the header at the same time this procedure is trying to ** read it, which might result in inconsistency. A dirty read is detected ** by verifying that both copies of the header are the same and also by ** a checksum on the header. ** ** If and only if the read is consistent and the header is different from ** pWal->hdr, then pWal->hdr is updated to the content of the new header ** and *pChanged is set to 1. ** ** If the checksum cannot be verified return non-zero. If the header ** is read successfully and the checksum verified, return zero. */ static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){ u32 aCksum[2]; /* Checksum on the header content */ WalIndexHdr h1, h2; /* Two copies of the header content */ WalIndexHdr volatile *aHdr; /* Header in shared memory */ /* The first page of the wal-index must be mapped at this point. */ assert( pWal->nWiData>0 && pWal->apWiData[0] ); /* Read the header. This might happen concurrently with a write to the ** same area of shared memory on a different CPU in a SMP, ** meaning it is possible that an inconsistent snapshot is read ** from the file. If this happens, return non-zero. ** ** tag-20200519-1: ** There are two copies of the header at the beginning of the wal-index. ** When reading, read [0] first then [1]. Writes are in the reverse order. ** Memory barriers are used to prevent the compiler or the hardware from ** reordering the reads and writes. TSAN and similar tools can sometimes ** give false-positive warnings about these accesses because the tools do not ** account for the double-read and the memory barrier. The use of mutexes ** here would be problematic as the memory being accessed is potentially ** shared among multiple processes and not all mutex implementations work ** reliably in that environment. */ aHdr = walIndexHdr(pWal); memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); /* Possible TSAN false-positive */ walShmBarrier(pWal); memcpy(&h2, (void *)&aHdr[1], sizeof(h2)); if( memcmp(&h1, &h2, sizeof(h1))!=0 ){ return 1; /* Dirty read */ } if( h1.isInit==0 ){ return 1; /* Malformed header - probably all zeros */ } walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum); if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){ return 1; /* Checksum does not match */ } if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){ *pChanged = 1; memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr)); pWal->szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16); testcase( pWal->szPage<=32768 ); testcase( pWal->szPage>=65536 ); } /* The header was successfully read. Return zero. */ return 0; } /* ** This is the value that walTryBeginRead returns when it needs to ** be retried. */ #define WAL_RETRY (-1) /* ** Read the wal-index header from the wal-index and into pWal->hdr. ** If the wal-header appears to be corrupt, try to reconstruct the ** wal-index from the WAL before returning. ** ** Set *pChanged to 1 if the wal-index header value in pWal->hdr is ** changed by this operation. If pWal->hdr is unchanged, set *pChanged ** to 0. ** ** If the wal-index header is successfully read, return SQLITE_OK. ** Otherwise an SQLite error code. */ static int walIndexReadHdr(Wal *pWal, int *pChanged){ int rc; /* Return code */ int badHdr; /* True if a header read failed */ volatile u32 *page0; /* Chunk of wal-index containing header */ /* Ensure that page 0 of the wal-index (the page that contains the ** wal-index header) is mapped. Return early if an error occurs here. */ assert( pChanged ); rc = walIndexPage(pWal, 0, &page0); if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_READONLY ); /* READONLY changed to OK in walIndexPage */ if( rc==SQLITE_READONLY_CANTINIT ){ /* The SQLITE_READONLY_CANTINIT return means that the shared-memory ** was openable but is not writable, and this thread is unable to ** confirm that another write-capable connection has the shared-memory ** open, and hence the content of the shared-memory is unreliable, ** since the shared-memory might be inconsistent with the WAL file ** and there is no writer on hand to fix it. */ assert( page0==0 ); assert( pWal->writeLock==0 ); assert( pWal->readOnly & WAL_SHM_RDONLY ); pWal->bShmUnreliable = 1; pWal->exclusiveMode = WAL_HEAPMEMORY_MODE; *pChanged = 1; }else{ return rc; /* Any other non-OK return is just an error */ } }else{ /* page0 can be NULL if the SHM is zero bytes in size and pWal->writeLock ** is zero, which prevents the SHM from growing */ testcase( page0!=0 ); } assert( page0!=0 || pWal->writeLock==0 ); /* If the first page of the wal-index has been mapped, try to read the ** wal-index header immediately, without holding any lock. This usually ** works, but may fail if the wal-index header is corrupt or currently ** being modified by another thread or process. */ badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1); /* If the first attempt failed, it might have been due to a race ** with a writer. So get a WRITE lock and try again. */ if( badHdr ){ if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){ if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){ walUnlockShared(pWal, WAL_WRITE_LOCK); rc = SQLITE_READONLY_RECOVERY; } }else{ int bWriteLock = pWal->writeLock; if( bWriteLock || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){ pWal->writeLock = 1; if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ badHdr = walIndexTryHdr(pWal, pChanged); if( badHdr ){ /* If the wal-index header is still malformed even while holding ** a WRITE lock, it can only mean that the header is corrupted and ** needs to be reconstructed. So run recovery to do exactly that. ** Disable blocking locks first. */ walDisableBlocking(pWal); rc = walIndexRecover(pWal); *pChanged = 1; } } if( bWriteLock==0 ){ pWal->writeLock = 0; walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); } } } } /* If the header is read successfully, check the version number to make ** sure the wal-index was not constructed with some future format that ** this version of SQLite cannot understand. */ if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){ rc = SQLITE_CANTOPEN_BKPT; } if( pWal->bShmUnreliable ){ if( rc!=SQLITE_OK ){ walIndexClose(pWal, 0); pWal->bShmUnreliable = 0; assert( pWal->nWiData>0 && pWal->apWiData[0]==0 ); /* walIndexRecover() might have returned SHORT_READ if a concurrent ** writer truncated the WAL out from under it. If that happens, it ** indicates that a writer has fixed the SHM file for us, so retry */ if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY; } pWal->exclusiveMode = WAL_NORMAL_MODE; } return rc; } /* ** Open a transaction in a connection where the shared-memory is read-only ** and where we cannot verify that there is a separate write-capable connection ** on hand to keep the shared-memory up-to-date with the WAL file. ** ** This can happen, for example, when the shared-memory is implemented by ** memory-mapping a *-shm file, where a prior writer has shut down and ** left the *-shm file on disk, and now the present connection is trying ** to use that database but lacks write permission on the *-shm file. ** Other scenarios are also possible, depending on the VFS implementation. ** ** Precondition: ** ** The *-wal file has been read and an appropriate wal-index has been ** constructed in pWal->apWiData[] using heap memory instead of shared ** memory. ** ** If this function returns SQLITE_OK, then the read transaction has ** been successfully opened. In this case output variable (*pChanged) ** is set to true before returning if the caller should discard the ** contents of the page cache before proceeding. Or, if it returns ** WAL_RETRY, then the heap memory wal-index has been discarded and ** the caller should retry opening the read transaction from the ** beginning (including attempting to map the *-shm file). ** ** If an error occurs, an SQLite error code is returned. */ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ i64 szWal; /* Size of wal file on disk in bytes */ i64 iOffset; /* Current offset when reading wal file */ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */ int szFrame; /* Number of bytes in buffer aFrame[] */ u8 *aData; /* Pointer to data part of aFrame buffer */ volatile void *pDummy; /* Dummy argument for xShmMap */ int rc; /* Return code */ u32 aSaveCksum[2]; /* Saved copy of pWal->hdr.aFrameCksum */ assert( pWal->bShmUnreliable ); assert( pWal->readOnly & WAL_SHM_RDONLY ); assert( pWal->nWiData>0 && pWal->apWiData[0] ); /* Take WAL_READ_LOCK(0). This has the effect of preventing any ** writers from running a checkpoint, but does not stop them ** from running recovery. */ rc = walLockShared(pWal, WAL_READ_LOCK(0)); if( rc!=SQLITE_OK ){ if( rc==SQLITE_BUSY ) rc = WAL_RETRY; goto begin_unreliable_shm_out; } pWal->readLock = 0; /* Check to see if a separate writer has attached to the shared-memory area, ** thus making the shared-memory "reliable" again. Do this by invoking ** the xShmMap() routine of the VFS and looking to see if the return ** is SQLITE_READONLY instead of SQLITE_READONLY_CANTINIT. ** ** If the shared-memory is now "reliable" return WAL_RETRY, which will ** cause the heap-memory WAL-index to be discarded and the actual ** shared memory to be used in its place. ** ** This step is important because, even though this connection is holding ** the WAL_READ_LOCK(0) which prevents a checkpoint, a writer might ** have already checkpointed the WAL file and, while the current ** is active, wrap the WAL and start overwriting frames that this ** process wants to use. ** ** Once sqlite3OsShmMap() has been called for an sqlite3_file and has ** returned any SQLITE_READONLY value, it must return only SQLITE_READONLY ** or SQLITE_READONLY_CANTINIT or some error for all subsequent invocations, ** even if some external agent does a "chmod" to make the shared-memory ** writable by us, until sqlite3OsShmUnmap() has been called. ** This is a requirement on the VFS implementation. */ rc = sqlite3OsShmMap(pWal->pDbFd, 0, WALINDEX_PGSZ, 0, &pDummy); assert( rc!=SQLITE_OK ); /* SQLITE_OK not possible for read-only connection */ if( rc!=SQLITE_READONLY_CANTINIT ){ rc = (rc==SQLITE_READONLY ? WAL_RETRY : rc); goto begin_unreliable_shm_out; } /* We reach this point only if the real shared-memory is still unreliable. ** Assume the in-memory WAL-index substitute is correct and load it ** into pWal->hdr. */ memcpy(&pWal->hdr, (void*)walIndexHdr(pWal), sizeof(WalIndexHdr)); /* Make sure some writer hasn't come in and changed the WAL file out ** from under us, then disconnected, while we were not looking. */ rc = sqlite3OsFileSize(pWal->pWalFd, &szWal); if( rc!=SQLITE_OK ){ goto begin_unreliable_shm_out; } if( szWalhdr.mxFrame==0 ? SQLITE_OK : WAL_RETRY); goto begin_unreliable_shm_out; } /* Check the salt keys at the start of the wal file still match. */ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0); if( rc!=SQLITE_OK ){ goto begin_unreliable_shm_out; } if( memcmp(&pWal->hdr.aSalt, &aBuf[16], 8) ){ /* Some writer has wrapped the WAL file while we were not looking. ** Return WAL_RETRY which will cause the in-memory WAL-index to be ** rebuilt. */ rc = WAL_RETRY; goto begin_unreliable_shm_out; } /* Allocate a buffer to read frames into */ assert( (pWal->szPage & (pWal->szPage-1))==0 ); assert( pWal->szPage>=512 && pWal->szPage<=65536 ); szFrame = pWal->szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame); if( aFrame==0 ){ rc = SQLITE_NOMEM_BKPT; goto begin_unreliable_shm_out; } aData = &aFrame[WAL_FRAME_HDRSIZE]; /* Check to see if a complete transaction has been appended to the ** wal file since the heap-memory wal-index was created. If so, the ** heap-memory wal-index is discarded and WAL_RETRY returned to ** the caller. */ aSaveCksum[0] = pWal->hdr.aFrameCksum[0]; aSaveCksum[1] = pWal->hdr.aFrameCksum[1]; for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->szPage); iOffset+szFrame<=szWal; iOffset+=szFrame ){ u32 pgno; /* Database page number for frame */ u32 nTruncate; /* dbsize field from frame header */ /* Read and decode the next log frame. */ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset); if( rc!=SQLITE_OK ) break; if( !walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame) ) break; /* If nTruncate is non-zero, then a complete transaction has been ** appended to this wal file. Set rc to WAL_RETRY and break out of ** the loop. */ if( nTruncate ){ rc = WAL_RETRY; break; } } pWal->hdr.aFrameCksum[0] = aSaveCksum[0]; pWal->hdr.aFrameCksum[1] = aSaveCksum[1]; begin_unreliable_shm_out: sqlite3_free(aFrame); if( rc!=SQLITE_OK ){ int i; for(i=0; inWiData; i++){ sqlite3_free((void*)pWal->apWiData[i]); pWal->apWiData[i] = 0; } pWal->bShmUnreliable = 0; sqlite3WalEndReadTransaction(pWal); *pChanged = 1; } return rc; } /* ** The final argument passed to walTryBeginRead() is of type (int*). The ** caller should invoke walTryBeginRead as follows: ** ** int cnt = 0; ** do { ** rc = walTryBeginRead(..., &cnt); ** }while( rc==WAL_RETRY ); ** ** The final value of "cnt" is of no use to the caller. It is used by ** the implementation of walTryBeginRead() as follows: ** ** + Each time walTryBeginRead() is called, it is incremented. Once ** it reaches WAL_RETRY_PROTOCOL_LIMIT - indicating that walTryBeginRead() ** has many times been invoked and failed with WAL_RETRY - walTryBeginRead() ** returns SQLITE_PROTOCOL. ** ** + If SQLITE_ENABLE_SETLK_TIMEOUT is defined and walTryBeginRead() failed ** because a blocking lock timed out (SQLITE_BUSY_TIMEOUT from the OS ** layer), the WAL_RETRY_BLOCKED_MASK bit is set in "cnt". In this case ** the next invocation of walTryBeginRead() may omit an expected call to ** sqlite3OsSleep(). There has already been a delay when the previous call ** waited on a lock. */ #define WAL_RETRY_PROTOCOL_LIMIT 100 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT # define WAL_RETRY_BLOCKED_MASK 0x10000000 #else # define WAL_RETRY_BLOCKED_MASK 0 #endif /* ** Attempt to start a read transaction. This might fail due to a race or ** other transient condition. When that happens, it returns WAL_RETRY to ** indicate to the caller that it is safe to retry immediately. ** ** On success return SQLITE_OK. On a permanent failure (such an ** I/O error or an SQLITE_BUSY because another process is running ** recovery) return a positive error code. ** ** The useWal parameter is true to force the use of the WAL and disable ** the case where the WAL is bypassed because it has been completely ** checkpointed. If useWal==0 then this routine calls walIndexReadHdr() ** to make a copy of the wal-index header into pWal->hdr. If the ** wal-index header has changed, *pChanged is set to 1 (as an indication ** to the caller that the local page cache is obsolete and needs to be ** flushed.) When useWal==1, the wal-index header is assumed to already ** be loaded and the pChanged parameter is unused. ** ** The caller must set the cnt parameter to the number of prior calls to ** this routine during the current read attempt that returned WAL_RETRY. ** This routine will start taking more aggressive measures to clear the ** race conditions after multiple WAL_RETRY returns, and after an excessive ** number of errors will ultimately return SQLITE_PROTOCOL. The ** SQLITE_PROTOCOL return indicates that some other process has gone rogue ** and is not honoring the locking protocol. There is a vanishingly small ** chance that SQLITE_PROTOCOL could be returned because of a run of really ** bad luck when there is lots of contention for the wal-index, but that ** possibility is so small that it can be safely neglected, we believe. ** ** On success, this routine obtains a read lock on ** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is ** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1) ** that means the Wal does not hold any read lock. The reader must not ** access any database page that is modified by a WAL frame up to and ** including frame number aReadMark[pWal->readLock]. The reader will ** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0 ** Or if pWal->readLock==0, then the reader will ignore the WAL ** completely and get all content directly from the database file. ** If the useWal parameter is 1 then the WAL will never be ignored and ** this routine will always set pWal->readLock>0 on success. ** When the read transaction is completed, the caller must release the ** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1. ** ** This routine uses the nBackfill and aReadMark[] fields of the header ** to select a particular WAL_READ_LOCK() that strives to let the ** checkpoint process do as much work as possible. This routine might ** update values of the aReadMark[] array in the header, but if it does ** so it takes care to hold an exclusive lock on the corresponding ** WAL_READ_LOCK() while changing values. */ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */ u32 mxReadMark; /* Largest aReadMark[] value */ int mxI; /* Index of largest aReadMark[] value */ int i; /* Loop counter */ int rc = SQLITE_OK; /* Return code */ u32 mxFrame; /* Wal frame to lock to */ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT int nBlockTmout = 0; #endif assert( pWal->readLock<0 ); /* Not currently locked */ /* useWal may only be set for read/write connections */ assert( (pWal->readOnly & WAL_SHM_RDONLY)==0 || useWal==0 ); /* Take steps to avoid spinning forever if there is a protocol error. ** ** Circumstances that cause a RETRY should only last for the briefest ** instances of time. No I/O or other system calls are done while the ** locks are held, so the locks should not be held for very long. But ** if we are unlucky, another process that is holding a lock might get ** paged out or take a page-fault that is time-consuming to resolve, ** during the few nanoseconds that it is holding the lock. In that case, ** it might take longer than normal for the lock to free. ** ** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few ** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this ** is more of a scheduler yield than an actual delay. But on the 10th ** an subsequent retries, the delays start becoming longer and longer, ** so that on the 100th (and last) RETRY we delay for 323 milliseconds. ** The total delay time before giving up is less than 10 seconds. */ (*pCnt)++; if( *pCnt>5 ){ int nDelay = 1; /* Pause time in microseconds */ int cnt = (*pCnt & ~WAL_RETRY_BLOCKED_MASK); if( cnt>WAL_RETRY_PROTOCOL_LIMIT ){ VVA_ONLY( pWal->lockError = 1; ) return SQLITE_PROTOCOL; } if( *pCnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* In SQLITE_ENABLE_SETLK_TIMEOUT builds, configure the file-descriptor ** to block for locks for approximately nDelay us. This affects three ** locks: (a) the shared lock taken on the DMS slot in os_unix.c (if ** using os_unix.c), (b) the WRITER lock taken in walIndexReadHdr() if the ** first attempted read fails, and (c) the shared lock taken on the ** read-mark. ** ** If the previous call failed due to an SQLITE_BUSY_TIMEOUT error, ** then sleep for the minimum of 1us. The previous call already provided ** an extra delay while it was blocking on the lock. */ nBlockTmout = (nDelay+998) / 1000; if( !useWal && walEnableBlockingMs(pWal, nBlockTmout) ){ if( *pCnt & WAL_RETRY_BLOCKED_MASK ) nDelay = 1; } #endif sqlite3OsSleep(pWal->pVfs, nDelay); *pCnt &= ~WAL_RETRY_BLOCKED_MASK; } if( !useWal ){ assert( rc==SQLITE_OK ); if( pWal->bShmUnreliable==0 ){ rc = walIndexReadHdr(pWal, pChanged); } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT walDisableBlocking(pWal); if( rc==SQLITE_BUSY_TIMEOUT ){ rc = SQLITE_BUSY; *pCnt |= WAL_RETRY_BLOCKED_MASK; } #endif if( rc==SQLITE_BUSY ){ /* If there is not a recovery running in another thread or process ** then convert BUSY errors to WAL_RETRY. If recovery is known to ** be running, convert BUSY to BUSY_RECOVERY. There is a race here ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY ** would be technically correct. But the race is benign since with ** WAL_RETRY this routine will be called again and will probably be ** right on the second iteration. */ if( pWal->apWiData[0]==0 ){ /* This branch is taken when the xShmMap() method returns SQLITE_BUSY. ** We assume this is a transient condition, so return WAL_RETRY. The ** xShmMap() implementation used by the default unix and win32 VFS ** modules may return SQLITE_BUSY due to a race condition in the ** code that determines whether or not the shared-memory region ** must be zeroed before the requested page is returned. */ rc = WAL_RETRY; }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){ walUnlockShared(pWal, WAL_RECOVER_LOCK); rc = WAL_RETRY; }else if( rc==SQLITE_BUSY ){ rc = SQLITE_BUSY_RECOVERY; } } if( rc!=SQLITE_OK ){ return rc; } else if( pWal->bShmUnreliable ){ return walBeginShmUnreliable(pWal, pChanged); } } assert( pWal->nWiData>0 ); assert( pWal->apWiData[0]!=0 ); pInfo = walCkptInfo(pWal); SEH_INJECT_FAULT; if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame #ifdef SQLITE_ENABLE_SNAPSHOT && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0) #endif ){ /* The WAL has been completely backfilled (or it is empty). ** and can be safely ignored. */ rc = walLockShared(pWal, WAL_READ_LOCK(0)); walShmBarrier(pWal); if( rc==SQLITE_OK ){ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ /* It is not safe to allow the reader to continue here if frames ** may have been appended to the log before READ_LOCK(0) was obtained. ** When holding READ_LOCK(0), the reader ignores the entire log file, ** which implies that the database file contains a trustworthy ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from ** happening, this is usually correct. ** ** However, if frames have been appended to the log (or if the log ** is wrapped and written for that matter) before the READ_LOCK(0) ** is obtained, that is not necessarily true. A checkpointer may ** have started to backfill the appended frames but crashed before ** it finished. Leaving a corrupt image in the database file. */ walUnlockShared(pWal, WAL_READ_LOCK(0)); return WAL_RETRY; } pWal->readLock = 0; return SQLITE_OK; }else if( rc!=SQLITE_BUSY ){ return rc; } } /* If we get this far, it means that the reader will want to use ** the WAL to get at content from recent commits. The job now is ** to select one of the aReadMark[] entries that is closest to ** but not exceeding pWal->hdr.mxFrame and lock that entry. */ mxReadMark = 0; mxI = 0; mxFrame = pWal->hdr.mxFrame; #ifdef SQLITE_ENABLE_SNAPSHOT if( pWal->pSnapshot && pWal->pSnapshot->mxFramepSnapshot->mxFrame; } #endif for(i=1; iaReadMark+i); SEH_INJECT_FAULT; if( mxReadMark<=thisMark && thisMark<=mxFrame ){ assert( thisMark!=READMARK_NOT_USED ); mxReadMark = thisMark; mxI = i; } } if( (pWal->readOnly & WAL_SHM_RDONLY)==0 && (mxReadMarkaReadMark+i,mxFrame); mxReadMark = mxFrame; mxI = i; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); break; }else if( rc!=SQLITE_BUSY ){ return rc; } } } if( mxI==0 ){ assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 ); return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT; } (void)walEnableBlockingMs(pWal, nBlockTmout); rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); walDisableBlocking(pWal); if( rc ){ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ){ *pCnt |= WAL_RETRY_BLOCKED_MASK; } #else assert( rc!=SQLITE_BUSY_TIMEOUT ); #endif assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT ); return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc; } /* Now that the read-lock has been obtained, check that neither the ** value in the aReadMark[] array or the contents of the wal-index ** header have changed. ** ** It is necessary to check that the wal-index header did not change ** between the time it was read and when the shared-lock was obtained ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility ** that the log file may have been wrapped by a writer, or that frames ** that occur later in the log than pWal->hdr.mxFrame may have been ** copied into the database by a checkpointer. If either of these things ** happened, then reading the database with the current value of ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry ** instead. ** ** Before checking that the live wal-index header has not changed ** since it was read, set Wal.minFrame to the first frame in the wal ** file that has not yet been checkpointed. This client will not need ** to read any frames earlier than minFrame from the wal file - they ** can be safely read directly from the database file. ** ** Because a ShmBarrier() call is made between taking the copy of ** nBackfill and checking that the wal-header in shared-memory still ** matches the one cached in pWal->hdr, it is guaranteed that the ** checkpointer that set nBackfill was not working with a wal-index ** header newer than that cached in pWal->hdr. If it were, that could ** cause a problem. The checkpointer could omit to checkpoint ** a version of page X that lies before pWal->minFrame (call that version ** A) on the basis that there is a newer version (version B) of the same ** page later in the wal file. But if version B happens to like past ** frame pWal->hdr.mxFrame - then the client would incorrectly assume ** that it can read version A from the database file. However, since ** we can guarantee that the checkpointer that set nBackfill could not ** see any pages past pWal->hdr.mxFrame, this problem does not come up. */ pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; SEH_INJECT_FAULT; walShmBarrier(pWal); if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ walUnlockShared(pWal, WAL_READ_LOCK(mxI)); return WAL_RETRY; }else{ assert( mxReadMark<=pWal->hdr.mxFrame ); pWal->readLock = (i16)mxI; } return rc; } #ifdef SQLITE_ENABLE_SNAPSHOT /* ** This function does the work of sqlite3WalSnapshotRecover(). */ static int walSnapshotRecover( Wal *pWal, /* WAL handle */ void *pBuf1, /* Temp buffer pWal->szPage bytes in size */ void *pBuf2 /* Temp buffer pWal->szPage bytes in size */ ){ int szPage = (int)pWal->szPage; int rc; i64 szDb; /* Size of db file in bytes */ rc = sqlite3OsFileSize(pWal->pDbFd, &szDb); if( rc==SQLITE_OK ){ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); u32 i = pInfo->nBackfillAttempted; for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){ WalHashLoc sLoc; /* Hash table location */ u32 pgno; /* Page number in db file */ i64 iDbOff; /* Offset of db file entry */ i64 iWalOff; /* Offset of wal file entry */ rc = walHashGet(pWal, walFramePage(i), &sLoc); if( rc!=SQLITE_OK ) break; assert( i - sLoc.iZero - 1 >=0 ); pgno = sLoc.aPgno[i-sLoc.iZero-1]; iDbOff = (i64)(pgno-1) * szPage; if( iDbOff+szPage<=szDb ){ iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE; rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff); if( rc==SQLITE_OK ){ rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff); } if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){ break; } } pInfo->nBackfillAttempted = i-1; } } return rc; } /* ** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted ** variable so that older snapshots can be accessed. To do this, loop ** through all wal frames from nBackfillAttempted to (nBackfill+1), ** comparing their content to the corresponding page with the database ** file, if any. Set nBackfillAttempted to the frame number of the ** first frame for which the wal file content matches the db file. ** ** This is only really safe if the file-system is such that any page ** writes made by earlier checkpointers were atomic operations, which ** is not always true. It is also possible that nBackfillAttempted ** may be left set to a value larger than expected, if a wal frame ** contains content that duplicate of an earlier version of the same ** page. ** ** SQLITE_OK is returned if successful, or an SQLite error code if an ** error occurs. It is not an error if nBackfillAttempted cannot be ** decreased at all. */ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){ int rc; assert( pWal->readLock>=0 ); rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); if( rc==SQLITE_OK ){ void *pBuf1 = sqlite3_malloc(pWal->szPage); void *pBuf2 = sqlite3_malloc(pWal->szPage); if( pBuf1==0 || pBuf2==0 ){ rc = SQLITE_NOMEM; }else{ pWal->ckptLock = 1; SEH_TRY { rc = walSnapshotRecover(pWal, pBuf1, pBuf2); } SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; ) pWal->ckptLock = 0; } sqlite3_free(pBuf1); sqlite3_free(pBuf2); walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); } return rc; } #endif /* SQLITE_ENABLE_SNAPSHOT */ /* ** This function does the work of sqlite3WalBeginReadTransaction() (see ** below). That function simply calls this one inside an SEH_TRY{...} block. */ static int walBeginReadTransaction(Wal *pWal, int *pChanged){ int rc; /* Return code */ int cnt = 0; /* Number of TryBeginRead attempts */ #ifdef SQLITE_ENABLE_SNAPSHOT int ckptLock = 0; int bChanged = 0; WalIndexHdr *pSnapshot = pWal->pSnapshot; #endif assert( pWal->ckptLock==0 ); assert( pWal->nSehTry>0 ); #ifdef SQLITE_ENABLE_SNAPSHOT if( pSnapshot ){ if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){ bChanged = 1; } /* It is possible that there is a checkpointer thread running ** concurrent with this code. If this is the case, it may be that the ** checkpointer has already determined that it will checkpoint ** snapshot X, where X is later in the wal file than pSnapshot, but ** has not yet set the pInfo->nBackfillAttempted variable to indicate ** its intent. To avoid the race condition this leads to, ensure that ** there is no checkpointer process by taking a shared CKPT lock ** before checking pInfo->nBackfillAttempted. */ (void)walEnableBlocking(pWal); rc = walLockShared(pWal, WAL_CKPT_LOCK); walDisableBlocking(pWal); if( rc!=SQLITE_OK ){ return rc; } ckptLock = 1; } #endif do{ rc = walTryBeginRead(pWal, pChanged, 0, &cnt); }while( rc==WAL_RETRY ); testcase( (rc&0xff)==SQLITE_BUSY ); testcase( (rc&0xff)==SQLITE_IOERR ); testcase( rc==SQLITE_PROTOCOL ); testcase( rc==SQLITE_OK ); #ifdef SQLITE_ENABLE_SNAPSHOT if( rc==SQLITE_OK ){ if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){ /* At this point the client has a lock on an aReadMark[] slot holding ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr ** is populated with the wal-index header corresponding to the head ** of the wal file. Verify that pSnapshot is still valid before ** continuing. Reasons why pSnapshot might no longer be valid: ** ** (1) The WAL file has been reset since the snapshot was taken. ** In this case, the salt will have changed. ** ** (2) A checkpoint as been attempted that wrote frames past ** pSnapshot->mxFrame into the database file. Note that the ** checkpoint need not have completed for this to cause problems. */ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 ); assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame ); /* Check that the wal file has not been wrapped. Assuming that it has ** not, also check that no checkpointer has attempted to checkpoint any ** frames beyond pSnapshot->mxFrame. If either of these conditions are ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr ** with *pSnapshot and set *pChanged as appropriate for opening the ** snapshot. */ if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) && pSnapshot->mxFrame>=pInfo->nBackfillAttempted ){ assert( pWal->readLock>0 ); memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr)); *pChanged = bChanged; }else{ rc = SQLITE_ERROR_SNAPSHOT; } /* A client using a non-current snapshot may not ignore any frames ** from the start of the wal file. This is because, for a system ** where (minFrame < iSnapshot < maxFrame), a checkpointer may ** have omitted to checkpoint a frame earlier than minFrame in ** the file because there exists a frame after iSnapshot that ** is the same database page. */ pWal->minFrame = 1; if( rc!=SQLITE_OK ){ sqlite3WalEndReadTransaction(pWal); } } } /* Release the shared CKPT lock obtained above. */ if( ckptLock ){ assert( pSnapshot ); walUnlockShared(pWal, WAL_CKPT_LOCK); } #endif return rc; } /* ** Begin a read transaction on the database. ** ** This routine used to be called sqlite3OpenSnapshot() and with good reason: ** it takes a snapshot of the state of the WAL and wal-index for the current ** instant in time. The current thread will continue to use this snapshot. ** Other threads might append new content to the WAL and wal-index but ** that extra content is ignored by the current thread. ** ** If the database contents have changes since the previous read ** transaction, then *pChanged is set to 1 before returning. The ** Pager layer will use this to know that its cache is stale and ** needs to be flushed. */ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ int rc; SEH_TRY { rc = walBeginReadTransaction(pWal, pChanged); } SEH_EXCEPT( rc = walHandleException(pWal); ) return rc; } /* ** Finish with a read transaction. All this does is release the ** read-lock. */ SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){ sqlite3WalEndWriteTransaction(pWal); if( pWal->readLock>=0 ){ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock)); pWal->readLock = -1; } } /* ** Search the wal file for page pgno. If found, set *piRead to the frame that ** contains the page. Otherwise, if pgno is not in the wal file, set *piRead ** to zero. ** ** Return SQLITE_OK if successful, or an error code if an error occurs. If an ** error does occur, the final value of *piRead is undefined. */ static int walFindFrame( Wal *pWal, /* WAL handle */ Pgno pgno, /* Database page number to read data for */ u32 *piRead /* OUT: Frame number (or zero) */ ){ u32 iRead = 0; /* If !=0, WAL frame to return data from */ u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */ int iHash; /* Used to loop through N hash tables */ int iMinHash; /* This routine is only be called from within a read transaction. */ assert( pWal->readLock>=0 || pWal->lockError ); /* If the "last page" field of the wal-index header snapshot is 0, then ** no data will be read from the wal under any circumstances. Return early ** in this case as an optimization. Likewise, if pWal->readLock==0, ** then the WAL is ignored by the reader so return early, as if the ** WAL were empty. */ if( iLast==0 || (pWal->readLock==0 && pWal->bShmUnreliable==0) ){ *piRead = 0; return SQLITE_OK; } /* Search the hash table or tables for an entry matching page number ** pgno. Each iteration of the following for() loop searches one ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames). ** ** This code might run concurrently to the code in walIndexAppend() ** that adds entries to the wal-index (and possibly to this hash ** table). This means the value just read from the hash ** slot (aHash[iKey]) may have been added before or after the ** current read transaction was opened. Values added after the ** read transaction was opened may have been written incorrectly - ** i.e. these slots may contain garbage data. However, we assume ** that any slots written before the current read transaction was ** opened remain unmodified. ** ** For the reasons above, the if(...) condition featured in the inner ** loop of the following block is more stringent that would be required ** if we had exclusive access to the hash-table: ** ** (aPgno[iFrame]==pgno): ** This condition filters out normal hash-table collisions. ** ** (iFrame<=iLast): ** This condition filters out entries that were added to the hash ** table after the current read-transaction had started. */ iMinHash = walFramePage(pWal->minFrame); for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){ WalHashLoc sLoc; /* Hash table location */ int iKey; /* Hash slot index */ int nCollide; /* Number of hash collisions remaining */ int rc; /* Error code */ u32 iH; rc = walHashGet(pWal, iHash, &sLoc); if( rc!=SQLITE_OK ){ return rc; } nCollide = HASHTABLE_NSLOT; iKey = walHash(pgno); SEH_INJECT_FAULT; while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){ u32 iFrame = iH + sLoc.iZero; if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } if( (nCollide--)==0 ){ *piRead = 0; return SQLITE_CORRUPT_BKPT; } iKey = walNextHash(iKey); } if( iRead ) break; } #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* If expensive assert() statements are available, do a linear search ** of the wal-index file content. Make sure the results agree with the ** result obtained using the hash indexes above. */ { u32 iRead2 = 0; u32 iTest; assert( pWal->bShmUnreliable || pWal->minFrame>0 ); for(iTest=iLast; iTest>=pWal->minFrame && iTest>0; iTest--){ if( walFramePgno(pWal, iTest)==pgno ){ iRead2 = iTest; break; } } assert( iRead==iRead2 ); } #endif *piRead = iRead; return SQLITE_OK; } /* ** Search the wal file for page pgno. If found, set *piRead to the frame that ** contains the page. Otherwise, if pgno is not in the wal file, set *piRead ** to zero. ** ** Return SQLITE_OK if successful, or an error code if an error occurs. If an ** error does occur, the final value of *piRead is undefined. ** ** The difference between this function and walFindFrame() is that this ** function wraps walFindFrame() in an SEH_TRY{...} block. */ SQLITE_PRIVATE int sqlite3WalFindFrame( Wal *pWal, /* WAL handle */ Pgno pgno, /* Database page number to read data for */ u32 *piRead /* OUT: Frame number (or zero) */ ){ int rc; SEH_TRY { rc = walFindFrame(pWal, pgno, piRead); } SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; ) return rc; } /* ** Read the contents of frame iRead from the wal file into buffer pOut ** (which is nOut bytes in size). Return SQLITE_OK if successful, or an ** error code otherwise. */ SQLITE_PRIVATE int sqlite3WalReadFrame( Wal *pWal, /* WAL handle */ u32 iRead, /* Frame to read */ int nOut, /* Size of buffer pOut in bytes */ u8 *pOut /* Buffer to write page data to */ ){ int sz; i64 iOffset; sz = pWal->hdr.szPage; sz = (sz&0xfe00) + ((sz&0x0001)<<16); testcase( sz<=32768 ); testcase( sz>=65536 ); iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE; /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */ return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset); } /* ** Return the size of the database in pages (or zero, if unknown). */ SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){ if( pWal && ALWAYS(pWal->readLock>=0) ){ return pWal->hdr.nPage; } return 0; } /* ** This function starts a write transaction on the WAL. ** ** A read transaction must have already been started by a prior call ** to sqlite3WalBeginReadTransaction(). ** ** If another thread or process has written into the database since ** the read transaction was started, then it is not possible for this ** thread to write as doing so would cause a fork. So this routine ** returns SQLITE_BUSY in that case and no write transaction is started. ** ** There can only be a single writer active at a time. */ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){ int rc; #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* If the write-lock is already held, then it was obtained before the ** read-transaction was even opened, making this call a no-op. ** Return early. */ if( pWal->writeLock ){ assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) ); return SQLITE_OK; } #endif /* Cannot start a write transaction without first holding a read ** transaction. */ assert( pWal->readLock>=0 ); assert( pWal->writeLock==0 && pWal->iReCksum==0 ); if( pWal->readOnly ){ return SQLITE_READONLY; } /* Only one writer allowed at a time. Get the write lock. Return ** SQLITE_BUSY if unable. */ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1); if( rc ){ return rc; } pWal->writeLock = 1; /* If another connection has written to the database file since the ** time the read transaction on this connection was started, then ** the write is disallowed. */ SEH_TRY { if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){ rc = SQLITE_BUSY_SNAPSHOT; } } SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; ) if( rc!=SQLITE_OK ){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); pWal->writeLock = 0; } return rc; } /* ** End a write transaction. The commit has already been done. This ** routine merely releases the lock. */ SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){ if( pWal->writeLock ){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); pWal->writeLock = 0; pWal->iReCksum = 0; pWal->truncateOnCommit = 0; } return SQLITE_OK; } /* ** If any data has been written (but not committed) to the log file, this ** function moves the write-pointer back to the start of the transaction. ** ** Additionally, the callback function is invoked for each frame written ** to the WAL since the start of the transaction. If the callback returns ** other than SQLITE_OK, it is not invoked again and the error code is ** returned to the caller. ** ** Otherwise, if the callback function does not return an error, this ** function returns SQLITE_OK. */ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){ int rc = SQLITE_OK; if( ALWAYS(pWal->writeLock) ){ Pgno iMax = pWal->hdr.mxFrame; Pgno iFrame; SEH_TRY { /* Restore the clients cache of the wal-index header to the state it ** was in before the client began writing to the database. */ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); for(iFrame=pWal->hdr.mxFrame+1; ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; iFrame++ ){ /* This call cannot fail. Unless the page for which the page number ** is passed as the second argument is (a) in the cache and ** (b) has an outstanding reference, then xUndo is either a no-op ** (if (a) is false) or simply expels the page from the cache (if (b) ** is false). ** ** If the upper layer is doing a rollback, it is guaranteed that there ** are no outstanding references to any page other than page 1. And ** page 1 is never written to the log until the transaction is ** committed. As a result, the call to xUndo may not fail. */ assert( walFramePgno(pWal, iFrame)!=1 ); rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame)); } if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal); } SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; ) } return rc; } /* ** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32 ** values. This function populates the array with values required to ** "rollback" the write position of the WAL handle back to the current ** point in the event of a savepoint rollback (via WalSavepointUndo()). */ SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){ assert( pWal->writeLock ); aWalData[0] = pWal->hdr.mxFrame; aWalData[1] = pWal->hdr.aFrameCksum[0]; aWalData[2] = pWal->hdr.aFrameCksum[1]; aWalData[3] = pWal->nCkpt; } /* ** Move the write position of the WAL back to the point identified by ** the values in the aWalData[] array. aWalData must point to an array ** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated ** by a call to WalSavepoint(). */ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){ int rc = SQLITE_OK; assert( pWal->writeLock ); assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame ); if( aWalData[3]!=pWal->nCkpt ){ /* This savepoint was opened immediately after the write-transaction ** was started. Right after that, the writer decided to wrap around ** to the start of the log. Update the savepoint values to match. */ aWalData[0] = 0; aWalData[3] = pWal->nCkpt; } if( aWalData[0]hdr.mxFrame ){ pWal->hdr.mxFrame = aWalData[0]; pWal->hdr.aFrameCksum[0] = aWalData[1]; pWal->hdr.aFrameCksum[1] = aWalData[2]; SEH_TRY { walCleanupHash(pWal); } SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; ) } return rc; } /* ** This function is called just before writing a set of frames to the log ** file (see sqlite3WalFrames()). It checks to see if, instead of appending ** to the current log file, it is possible to overwrite the start of the ** existing log file with the new frames (i.e. "reset" the log). If so, ** it sets pWal->hdr.mxFrame to 0. Otherwise, pWal->hdr.mxFrame is left ** unchanged. ** ** SQLITE_OK is returned if no error is encountered (regardless of whether ** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned ** if an error occurs. */ static int walRestartLog(Wal *pWal){ int rc = SQLITE_OK; int cnt; if( pWal->readLock==0 ){ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); assert( pInfo->nBackfill==pWal->hdr.mxFrame ); if( pInfo->nBackfill>0 ){ u32 salt1; sqlite3_randomness(4, &salt1); rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); if( rc==SQLITE_OK ){ /* If all readers are using WAL_READ_LOCK(0) (in other words if no ** readers are currently using the WAL), then the transactions ** frames will overwrite the start of the existing log. Update the ** wal-index header to reflect this. ** ** In theory it would be Ok to update the cache of the header only ** at this point. But updating the actual wal-index header is also ** safe and means there is no special case for sqlite3WalUndo() ** to handle if this transaction is rolled back. */ walRestartHdr(pWal, salt1); walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); }else if( rc!=SQLITE_BUSY ){ return rc; } } walUnlockShared(pWal, WAL_READ_LOCK(0)); pWal->readLock = -1; cnt = 0; do{ int notUsed; rc = walTryBeginRead(pWal, ¬Used, 1, &cnt); }while( rc==WAL_RETRY ); assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */ testcase( (rc&0xff)==SQLITE_IOERR ); testcase( rc==SQLITE_PROTOCOL ); testcase( rc==SQLITE_OK ); } return rc; } /* ** Information about the current state of the WAL file and where ** the next fsync should occur - passed from sqlite3WalFrames() into ** walWriteToLog(). */ typedef struct WalWriter { Wal *pWal; /* The complete WAL information */ sqlite3_file *pFd; /* The WAL file to which we write */ sqlite3_int64 iSyncPoint; /* Fsync at this offset */ int syncFlags; /* Flags for the fsync */ int szPage; /* Size of one page */ } WalWriter; /* ** Write iAmt bytes of content into the WAL file beginning at iOffset. ** Do a sync when crossing the p->iSyncPoint boundary. ** ** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt, ** first write the part before iSyncPoint, then sync, then write the ** rest. */ static int walWriteToLog( WalWriter *p, /* WAL to write to */ void *pContent, /* Content to be written */ int iAmt, /* Number of bytes to write */ sqlite3_int64 iOffset /* Start writing at this offset */ ){ int rc; if( iOffsetiSyncPoint && iOffset+iAmt>=p->iSyncPoint ){ int iFirstAmt = (int)(p->iSyncPoint - iOffset); rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset); if( rc ) return rc; iOffset += iFirstAmt; iAmt -= iFirstAmt; pContent = (void*)(iFirstAmt + (char*)pContent); assert( WAL_SYNC_FLAGS(p->syncFlags)!=0 ); rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags)); if( iAmt==0 || rc ) return rc; } rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset); return rc; } /* ** Write out a single frame of the WAL */ static int walWriteOneFrame( WalWriter *p, /* Where to write the frame */ PgHdr *pPage, /* The page of the frame to be written */ int nTruncate, /* The commit flag. Usually 0. >0 for commit */ sqlite3_int64 iOffset /* Byte offset at which to write */ ){ int rc; /* Result code from subfunctions */ void *pData; /* Data actually written */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ pData = pPage->pData; walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame); rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset); if( rc ) return rc; /* Write the page data */ rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame)); return rc; } /* ** This function is called as part of committing a transaction within which ** one or more frames have been overwritten. It updates the checksums for ** all frames written to the wal file by the current transaction starting ** with the earliest to have been overwritten. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ static int walRewriteChecksums(Wal *pWal, u32 iLast){ const int szPage = pWal->szPage;/* Database page size */ int rc = SQLITE_OK; /* Return code */ u8 *aBuf; /* Buffer to load data from wal file into */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-headers in */ u32 iRead; /* Next frame to read from wal file */ i64 iCksumOff; aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE); if( aBuf==0 ) return SQLITE_NOMEM_BKPT; /* Find the checksum values to use as input for the recalculating the ** first checksum. If the first frame is frame 1 (implying that the current ** transaction restarted the wal file), these values must be read from the ** wal-file header. Otherwise, read them from the frame header of the ** previous frame. */ assert( pWal->iReCksum>0 ); if( pWal->iReCksum==1 ){ iCksumOff = 24; }else{ iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16; } rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff); pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf); pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]); iRead = pWal->iReCksum; pWal->iReCksum = 0; for(; rc==SQLITE_OK && iRead<=iLast; iRead++){ i64 iOff = walFrameOffset(iRead, szPage); rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff); if( rc==SQLITE_OK ){ u32 iPgno, nDbSize; iPgno = sqlite3Get4byte(aBuf); nDbSize = sqlite3Get4byte(&aBuf[4]); walEncodeFrame(pWal, iPgno, nDbSize, &aBuf[WAL_FRAME_HDRSIZE], aFrame); rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOff); } } sqlite3_free(aBuf); return rc; } /* ** Write a set of frames to the log. The caller must hold the write-lock ** on the log file (obtained using sqlite3WalBeginWriteTransaction()). */ static int walFrames( Wal *pWal, /* Wal handle to write to */ int szPage, /* Database page-size in bytes */ PgHdr *pList, /* List of dirty pages to write */ Pgno nTruncate, /* Database size after this commit */ int isCommit, /* True if this is a commit */ int sync_flags /* Flags to pass to OsSync() (or 0) */ ){ int rc; /* Used to catch return codes */ u32 iFrame; /* Next frame address */ PgHdr *p; /* Iterator to run through pList with. */ PgHdr *pLast = 0; /* Last frame in list */ int nExtra = 0; /* Number of extra copies of last page */ int szFrame; /* The size of a single frame */ i64 iOffset; /* Next byte to write in WAL file */ WalWriter w; /* The writer */ u32 iFirst = 0; /* First frame that may be overwritten */ WalIndexHdr *pLive; /* Pointer to shared header */ assert( pList ); assert( pWal->writeLock ); /* If this frame set completes a transaction, then nTruncate>0. If ** nTruncate==0 then this frame set does not complete the transaction. */ assert( (isCommit!=0)==(nTruncate!=0) ); #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){} WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n", pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill")); } #endif pLive = (WalIndexHdr*)walIndexHdr(pWal); if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){ iFirst = pLive->mxFrame+1; } /* See if it is possible to write these frames into the start of the ** log file, instead of appending to it at pWal->hdr.mxFrame. */ if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){ return rc; } /* If this is the first frame written into the log, write the WAL ** header to the start of the WAL file. See comments at the top of ** this source file for a description of the WAL header format. */ iFrame = pWal->hdr.mxFrame; if( iFrame==0 ){ u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */ u32 aCksum[2]; /* Checksum for wal-header */ sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN)); sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION); sqlite3Put4byte(&aWalHdr[8], szPage); sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt); if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt); memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8); walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum); sqlite3Put4byte(&aWalHdr[24], aCksum[0]); sqlite3Put4byte(&aWalHdr[28], aCksum[1]); pWal->szPage = szPage; pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN; pWal->hdr.aFrameCksum[0] = aCksum[0]; pWal->hdr.aFrameCksum[1] = aCksum[1]; pWal->truncateOnCommit = 1; rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0); WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok")); if( rc!=SQLITE_OK ){ return rc; } /* Sync the header (unless SQLITE_IOCAP_SEQUENTIAL is true or unless ** all syncing is turned off by PRAGMA synchronous=OFF). Otherwise ** an out-of-order write following a WAL restart could result in ** database corruption. See the ticket: ** ** https://sqlite.org/src/info/ff5be73dee */ if( pWal->syncHeader ){ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); if( rc ) return rc; } } if( (int)pWal->szPage!=szPage ){ return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */ } /* Setup information needed to write frames into the WAL */ w.pWal = pWal; w.pFd = pWal->pWalFd; w.iSyncPoint = 0; w.syncFlags = sync_flags; w.szPage = szPage; iOffset = walFrameOffset(iFrame+1, szPage); szFrame = szPage + WAL_FRAME_HDRSIZE; /* Write all frames into the log file exactly once */ for(p=pList; p; p=p->pDirty){ int nDbSize; /* 0 normally. Positive == commit flag */ /* Check if this page has already been written into the wal file by ** the current transaction. If so, overwrite the existing frame and ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that ** checksums must be recomputed when the transaction is committed. */ if( iFirst && (p->pDirty || isCommit==0) ){ u32 iWrite = 0; VVA_ONLY(rc =) walFindFrame(pWal, p->pgno, &iWrite); assert( rc==SQLITE_OK || iWrite==0 ); if( iWrite>=iFirst ){ i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE; void *pData; if( pWal->iReCksum==0 || iWriteiReCksum ){ pWal->iReCksum = iWrite; } pData = p->pData; rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); if( rc ) return rc; p->flags &= ~PGHDR_WAL_APPEND; continue; } } iFrame++; assert( iOffset==walFrameOffset(iFrame, szPage) ); nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0; rc = walWriteOneFrame(&w, p, nDbSize, iOffset); if( rc ) return rc; pLast = p; iOffset += szFrame; p->flags |= PGHDR_WAL_APPEND; } /* Recalculate checksums within the wal file if required. */ if( isCommit && pWal->iReCksum ){ rc = walRewriteChecksums(pWal, iFrame); if( rc ) return rc; } /* If this is the end of a transaction, then we might need to pad ** the transaction and/or sync the WAL file. ** ** Padding and syncing only occur if this set of frames complete a ** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL ** or synchronous==OFF, then no padding or syncing are needed. ** ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not ** needed and only the sync is done. If padding is needed, then the ** final frame is repeated (with its commit mark) until the next sector ** boundary is crossed. Only the part of the WAL prior to the last ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){ int bSync = 1; if( pWal->padToSectorBoundary ){ int sectorSize = sqlite3SectorSize(pWal->pWalFd); w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize; bSync = (w.iSyncPoint==iOffset); testcase( bSync ); while( iOffsettruncateOnCommit && pWal->mxWalSize>=0 ){ i64 sz = pWal->mxWalSize; if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){ sz = walFrameOffset(iFrame+nExtra+1, szPage); } walLimitSize(pWal, sz); pWal->truncateOnCommit = 0; } /* Append data to the wal-index. It is not necessary to lock the ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index ** guarantees that there are no other writers, and no data that may ** be in use by existing readers is being overwritten. */ iFrame = pWal->hdr.mxFrame; for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){ if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue; iFrame++; rc = walIndexAppend(pWal, iFrame, p->pgno); } assert( pLast!=0 || nExtra==0 ); while( rc==SQLITE_OK && nExtra>0 ){ iFrame++; nExtra--; rc = walIndexAppend(pWal, iFrame, pLast->pgno); } if( rc==SQLITE_OK ){ /* Update the private copy of the header. */ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16)); testcase( szPage<=32768 ); testcase( szPage>=65536 ); pWal->hdr.mxFrame = iFrame; if( isCommit ){ pWal->hdr.iChange++; pWal->hdr.nPage = nTruncate; } /* If this is a commit, update the wal-index header too. */ if( isCommit ){ walIndexWriteHdr(pWal); pWal->iCallback = iFrame; } } WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok")); return rc; } /* ** Write a set of frames to the log. The caller must hold the write-lock ** on the log file (obtained using sqlite3WalBeginWriteTransaction()). ** ** The difference between this function and walFrames() is that this ** function wraps walFrames() in an SEH_TRY{...} block. */ SQLITE_PRIVATE int sqlite3WalFrames( Wal *pWal, /* Wal handle to write to */ int szPage, /* Database page-size in bytes */ PgHdr *pList, /* List of dirty pages to write */ Pgno nTruncate, /* Database size after this commit */ int isCommit, /* True if this is a commit */ int sync_flags /* Flags to pass to OsSync() (or 0) */ ){ int rc; SEH_TRY { rc = walFrames(pWal, szPage, pList, nTruncate, isCommit, sync_flags); } SEH_EXCEPT( rc = walHandleException(pWal); ) return rc; } /* ** This routine is called to implement sqlite3_wal_checkpoint() and ** related interfaces. ** ** Obtain a CHECKPOINT lock and then backfill as much information as ** we can from WAL into the database. ** ** If parameter xBusy is not NULL, it is a pointer to a busy-handler ** callback. In this case this function runs a blocking checkpoint. */ SQLITE_PRIVATE int sqlite3WalCheckpoint( Wal *pWal, /* Wal connection */ sqlite3 *db, /* Check this handle's interrupt flag */ int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int sync_flags, /* Flags to sync db file with (or 0) */ int nBuf, /* Size of temporary buffer */ u8 *zBuf, /* Temporary buffer to use */ int *pnLog, /* OUT: Number of frames in WAL */ int *pnCkpt /* OUT: Number of backfilled frames in WAL */ ){ int rc; /* Return code */ int isChanged = 0; /* True if a new wal-index header is loaded */ int eMode2 = eMode; /* Mode to pass to walCheckpoint() */ int (*xBusy2)(void*) = xBusy; /* Busy handler for eMode2 */ assert( pWal->ckptLock==0 ); assert( pWal->writeLock==0 ); /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); if( pWal->readOnly ) return SQLITE_READONLY; WALTRACE(("WAL%p: checkpoint begins\n", pWal)); /* Enable blocking locks, if possible. */ sqlite3WalDb(pWal, db); if( xBusy2 ) (void)walEnableBlocking(pWal); /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive ** "checkpoint" lock on the database file. ** EVIDENCE-OF: R-10421-19736 If any other process is running a ** checkpoint operation at the same time, the lock cannot be obtained and ** SQLITE_BUSY is returned. ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured, ** it will not be invoked in this case. */ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); testcase( rc==SQLITE_BUSY ); testcase( rc!=SQLITE_OK && xBusy2!=0 ); if( rc==SQLITE_OK ){ pWal->ckptLock = 1; /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and ** TRUNCATE modes also obtain the exclusive "writer" lock on the database ** file. ** ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained ** immediately, and a busy-handler is configured, it is invoked and the ** writer lock retried until either the busy-handler returns 0 or the ** lock is successfully obtained. */ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1); if( rc==SQLITE_OK ){ pWal->writeLock = 1; }else if( rc==SQLITE_BUSY ){ eMode2 = SQLITE_CHECKPOINT_PASSIVE; xBusy2 = 0; rc = SQLITE_OK; } } } /* Read the wal-index header. */ SEH_TRY { if( rc==SQLITE_OK ){ /* For a passive checkpoint, do not re-enable blocking locks after ** reading the wal-index header. A passive checkpoint should not block ** or invoke the busy handler. The only lock such a checkpoint may ** attempt to obtain is a lock on a read-slot, and it should give up ** immediately and do a partial checkpoint if it cannot obtain it. */ walDisableBlocking(pWal); rc = walIndexReadHdr(pWal, &isChanged); if( eMode2!=SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal); if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ sqlite3OsUnfetch(pWal->pDbFd, 0, 0); } } /* Copy data from the log to the database file. */ if( rc==SQLITE_OK ){ if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; }else{ rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf); } /* If no error occurred, set the output variables. */ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){ if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame; SEH_INJECT_FAULT; if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill); } } } SEH_EXCEPT( rc = walHandleException(pWal); ) if( isChanged ){ /* If a new wal-index header was loaded before the checkpoint was ** performed, then the pager-cache associated with pWal is now ** out of date. So zero the cached wal-index header to ensure that ** next time the pager opens a snapshot on this database it knows that ** the cache needs to be reset. */ memset(&pWal->hdr, 0, sizeof(WalIndexHdr)); } walDisableBlocking(pWal); sqlite3WalDb(pWal, 0); /* Release the locks. */ sqlite3WalEndWriteTransaction(pWal); if( pWal->ckptLock ){ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); pWal->ckptLock = 0; } WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; #endif return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc); } /* Return the value to pass to a sqlite3_wal_hook callback, the ** number of frames in the WAL at the point of the last commit since ** sqlite3WalCallback() was called. If no commits have occurred since ** the last call, then return 0. */ SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){ u32 ret = 0; if( pWal ){ ret = pWal->iCallback; pWal->iCallback = 0; } return (int)ret; } /* ** This function is called to change the WAL subsystem into or out ** of locking_mode=EXCLUSIVE. ** ** If op is zero, then attempt to change from locking_mode=EXCLUSIVE ** into locking_mode=NORMAL. This means that we must acquire a lock ** on the pWal->readLock byte. If the WAL is already in locking_mode=NORMAL ** or if the acquisition of the lock fails, then return 0. If the ** transition out of exclusive-mode is successful, return 1. This ** operation must occur while the pager is still holding the exclusive ** lock on the main database file. ** ** If op is one, then change from locking_mode=NORMAL into ** locking_mode=EXCLUSIVE. This means that the pWal->readLock must ** be released. Return 1 if the transition is made and 0 if the ** WAL is already in exclusive-locking mode - meaning that this ** routine is a no-op. The pager must already hold the exclusive lock ** on the main database file before invoking this operation. ** ** If op is negative, then do a dry-run of the op==1 case but do ** not actually change anything. The pager uses this to see if it ** should acquire the database exclusive lock prior to invoking ** the op==1 case. */ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){ int rc; assert( pWal->writeLock==0 ); assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 ); /* pWal->readLock is usually set, but might be -1 if there was a ** prior error while attempting to acquire are read-lock. This cannot ** happen if the connection is actually in exclusive mode (as no xShmLock ** locks are taken in this case). Nor should the pager attempt to ** upgrade to exclusive-mode following such an error. */ #ifndef SQLITE_USE_SEH assert( pWal->readLock>=0 || pWal->lockError ); #endif assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) ); if( op==0 ){ if( pWal->exclusiveMode!=WAL_NORMAL_MODE ){ pWal->exclusiveMode = WAL_NORMAL_MODE; if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; } rc = pWal->exclusiveMode==WAL_NORMAL_MODE; }else{ /* Already in locking_mode=NORMAL */ rc = 0; } }else if( op>0 ){ assert( pWal->exclusiveMode==WAL_NORMAL_MODE ); assert( pWal->readLock>=0 ); walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock)); pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; rc = 1; }else{ rc = pWal->exclusiveMode==WAL_NORMAL_MODE; } return rc; } /* ** Return true if the argument is non-NULL and the WAL module is using ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the ** WAL module is using shared-memory, return false. */ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){ return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ); } #ifdef SQLITE_ENABLE_SNAPSHOT /* Create a snapshot object. The content of a snapshot is opaque to ** every other subsystem, so the WAL module can put whatever it needs ** in the object. */ SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){ int rc = SQLITE_OK; WalIndexHdr *pRet; static const u32 aZero[4] = { 0, 0, 0, 0 }; assert( pWal->readLock>=0 && pWal->writeLock==0 ); if( memcmp(&pWal->hdr.aFrameCksum[0],aZero,16)==0 ){ *ppSnapshot = 0; return SQLITE_ERROR; } pRet = (WalIndexHdr*)sqlite3_malloc(sizeof(WalIndexHdr)); if( pRet==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ memcpy(pRet, &pWal->hdr, sizeof(WalIndexHdr)); *ppSnapshot = (sqlite3_snapshot*)pRet; } return rc; } /* Try to open on pSnapshot when the next read-transaction starts */ SQLITE_PRIVATE void sqlite3WalSnapshotOpen( Wal *pWal, sqlite3_snapshot *pSnapshot ){ pWal->pSnapshot = (WalIndexHdr*)pSnapshot; } /* ** Return a +ve value if snapshot p1 is newer than p2. A -ve value if ** p1 is older than p2 and zero if p1 and p2 are the same snapshot. */ SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){ WalIndexHdr *pHdr1 = (WalIndexHdr*)p1; WalIndexHdr *pHdr2 = (WalIndexHdr*)p2; /* aSalt[0] is a copy of the value stored in the wal file header. It ** is incremented each time the wal file is restarted. */ if( pHdr1->aSalt[0]aSalt[0] ) return -1; if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1; if( pHdr1->mxFramemxFrame ) return -1; if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1; return 0; } /* ** The caller currently has a read transaction open on the database. ** This function takes a SHARED lock on the CHECKPOINTER slot and then ** checks if the snapshot passed as the second argument is still ** available. If so, SQLITE_OK is returned. ** ** If the snapshot is not available, SQLITE_ERROR is returned. Or, if ** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error ** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER ** lock is released before returning. */ SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){ int rc; SEH_TRY { rc = walLockShared(pWal, WAL_CKPT_LOCK); if( rc==SQLITE_OK ){ WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot; if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) || pNew->mxFramenBackfillAttempted ){ rc = SQLITE_ERROR_SNAPSHOT; walUnlockShared(pWal, WAL_CKPT_LOCK); } } } SEH_EXCEPT( rc = walHandleException(pWal); ) return rc; } /* ** Release a lock obtained by an earlier successful call to ** sqlite3WalSnapshotCheck(). */ SQLITE_PRIVATE void sqlite3WalSnapshotUnlock(Wal *pWal){ assert( pWal ); walUnlockShared(pWal, WAL_CKPT_LOCK); } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_ZIPVFS /* ** If the argument is not NULL, it points to a Wal object that holds a ** read-lock. This function returns the database page-size if it is known, ** or zero if it is not (or if pWal is NULL). */ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){ assert( pWal==0 || pWal->readLock>=0 ); return (pWal ? pWal->szPage : 0); } #endif /* Return the sqlite3_file object for the WAL file */ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){ return pWal->pWalFd; } #endif /* #ifndef SQLITE_OMIT_WAL */ /************** End of wal.c *************************************************/ /************** Begin file btmutex.c *****************************************/ /* ** 2007 August 27 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code used to implement mutexes on Btree objects. ** This code really belongs in btree.c. But btree.c is getting too ** big and we want to break it down some. This packaged seemed like ** a good breakout. */ /************** Include btreeInt.h in the middle of btmutex.c ****************/ /************** Begin file btreeInt.h ****************************************/ /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file implements an external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. ** ** The basic idea is that each page of the file contains N database ** entries and N+1 pointers to subpages. ** ** ---------------------------------------------------------------- ** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) | ** ---------------------------------------------------------------- ** ** All of the keys on the page that Ptr(0) points to have values less ** than Key(0). All of the keys on page Ptr(1) and its subpages have ** values greater than Key(0) and less than Key(1). All of the keys ** on Ptr(N) and its subpages have values greater than Key(N-1). And ** so forth. ** ** Finding a particular key requires reading O(log(M)) pages from the ** disk where M is the number of entries in the tree. ** ** In this implementation, a single file can hold one or more separate ** BTrees. Each BTree is identified by the index of its root page. The ** key and data for any entry are combined to form the "payload". A ** fixed amount of payload can be carried directly on the database ** page. If the payload is larger than the preset amount then surplus ** bytes are stored on overflow pages. The payload for an entry ** and the preceding pointer are combined to form a "Cell". Each ** page has a small header which contains the Ptr(N) pointer and other ** information such as the size of key and data. ** ** FORMAT DETAILS ** ** The file is divided into pages. The first page is called page 1, ** the second is page 2, and so forth. A page number of zero indicates ** "no such page". The page size can be any power of 2 between 512 and 65536. ** Each page can be either a btree page, a freelist page, an overflow ** page, or a pointer-map page. ** ** The first page is always a btree page. The first 100 bytes of the first ** page contain a special header (the "file header") that describes the file. ** The format of the file header is as follows: ** ** OFFSET SIZE DESCRIPTION ** 0 16 Header string: "SQLite format 3\000" ** 16 2 Page size in bytes. (1 means 65536) ** 18 1 File format write version ** 19 1 File format read version ** 20 1 Bytes of unused space at the end of each page ** 21 1 Max embedded payload fraction (must be 64) ** 22 1 Min embedded payload fraction (must be 32) ** 23 1 Min leaf payload fraction (must be 32) ** 24 4 File change counter ** 28 4 The size of the database in pages ** 32 4 First freelist page ** 36 4 Number of freelist pages in the file ** 40 60 15 4-byte meta values passed to higher layers ** ** 40 4 Schema cookie ** 44 4 File format of schema layer ** 48 4 Size of page cache ** 52 4 Largest root-page (auto/incr_vacuum) ** 56 4 1=UTF-8 2=UTF16le 3=UTF16be ** 60 4 User version ** 64 4 Incremental vacuum mode ** 68 4 Application-ID ** 72 20 unused ** 92 4 The version-valid-for number ** 96 4 SQLITE_VERSION_NUMBER ** ** All of the integer values are big-endian (most significant byte first). ** ** The file change counter is incremented when the database is changed ** This counter allows other processes to know when the file has changed ** and thus when they need to flush their cache. ** ** The max embedded payload fraction is the amount of the total usable ** space in a page that can be consumed by a single cell for standard ** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default ** is to limit the maximum cell size so that at least 4 cells will fit ** on one page. Thus the default max embedded payload fraction is 64. ** ** If the payload for a cell is larger than the max payload, then extra ** payload is spilled to overflow pages. Once an overflow page is allocated, ** as many bytes as possible are moved into the overflow pages without letting ** the cell size drop below the min embedded payload fraction. ** ** The min leaf payload fraction is like the min embedded payload fraction ** except that it applies to leaf nodes in a LEAFDATA tree. The maximum ** payload fraction for a LEAFDATA tree is always 100% (or 255) and it ** not specified in the header. ** ** Each btree pages is divided into three sections: The header, the ** cell pointer array, and the cell content area. Page 1 also has a 100-byte ** file header that occurs before the page header. ** ** |----------------| ** | file header | 100 bytes. Page 1 only. ** |----------------| ** | page header | 8 bytes for leaves. 12 bytes for interior nodes ** |----------------| ** | cell pointer | | 2 bytes per cell. Sorted order. ** | array | | Grows downward ** | | v ** |----------------| ** | unallocated | ** | space | ** |----------------| ^ Grows upwards ** | cell content | | Arbitrary order interspersed with freeblocks. ** | area | | and free space fragments. ** |----------------| ** ** The page headers looks like this: ** ** OFFSET SIZE DESCRIPTION ** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf ** 1 2 byte offset to the first freeblock ** 3 2 number of cells on this page ** 5 2 first byte of the cell content area ** 7 1 number of fragmented free bytes ** 8 4 Right child (the Ptr(N) value). Omitted on leaves. ** ** The flags define the format of this btree page. The leaf flag means that ** this page has no children. The zerodata flag means that this page carries ** only keys and no data. The intkey flag means that the key is an integer ** which is stored in the key size entry of the cell header rather than in ** the payload area. ** ** The cell pointer array begins on the first byte after the page header. ** The cell pointer array contains zero or more 2-byte numbers which are ** offsets from the beginning of the page to the cell content in the cell ** content area. The cell pointers occur in sorted order. The system strives ** to keep free space after the last cell pointer so that new cells can ** be easily added without having to defragment the page. ** ** Cell content is stored at the very end of the page and grows toward the ** beginning of the page. ** ** Unused space within the cell content area is collected into a linked list of ** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset ** to the first freeblock is given in the header. Freeblocks occur in ** increasing order. Because a freeblock must be at least 4 bytes in size, ** any group of 3 or fewer unused bytes in the cell content area cannot ** exist on the freeblock chain. A group of 3 or fewer free bytes is called ** a fragment. The total number of bytes in all fragments is recorded. ** in the page header at offset 7. ** ** SIZE DESCRIPTION ** 2 Byte offset of the next freeblock ** 2 Bytes in this freeblock ** ** Cells are of variable length. Cells are stored in the cell content area at ** the end of the page. Pointers to the cells are in the cell pointer array ** that immediately follows the page header. Cells is not necessarily ** contiguous or in order, but cell pointers are contiguous and in order. ** ** Cell content makes use of variable length integers. A variable ** length integer is 1 to 9 bytes where the lower 7 bits of each ** byte are used. The integer consists of all bytes that have bit 8 set and ** the first byte with bit 8 clear. The most significant byte of the integer ** appears first. A variable-length integer may not be more than 9 bytes long. ** As a special case, all 8 bits of the 9th byte are used as data. This ** allows a 64-bit integer to be encoded in 9 bytes. ** ** 0x00 becomes 0x00000000 ** 0x7f becomes 0x0000007f ** 0x81 0x00 becomes 0x00000080 ** 0x82 0x00 becomes 0x00000100 ** 0x80 0x7f becomes 0x0000007f ** 0x81 0x91 0xd1 0xac 0x78 becomes 0x12345678 ** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081 ** ** Variable length integers are used for rowids and to hold the number of ** bytes of key and data in a btree cell. ** ** The content of a cell looks like this: ** ** SIZE DESCRIPTION ** 4 Page number of the left child. Omitted if leaf flag is set. ** var Number of bytes of data. Omitted if the zerodata flag is set. ** var Number of bytes of key. Or the key itself if intkey flag is set. ** * Payload ** 4 First page of the overflow chain. Omitted if no overflow ** ** Overflow pages form a linked list. Each page except the last is completely ** filled with data (pagesize - 4 bytes). The last page can have as little ** as 1 byte of data. ** ** SIZE DESCRIPTION ** 4 Page number of next overflow page ** * Data ** ** Freelist pages come in two subtypes: trunk pages and leaf pages. The ** file header points to the first in a linked list of trunk page. Each trunk ** page points to multiple leaf pages. The content of a leaf page is ** unspecified. A trunk page looks like this: ** ** SIZE DESCRIPTION ** 4 Page number of next trunk page ** 4 Number of leaf pointers on this page ** * zero or more pages numbers of leaves */ /* #include "sqliteInt.h" */ /* The following value is the maximum cell size assuming a maximum page ** size give above. */ #define MX_CELL_SIZE(pBt) ((int)(pBt->pageSize-8)) /* The maximum number of cells on a single page of the database. This ** assumes a minimum cell size of 6 bytes (4 bytes for the cell itself ** plus 2 bytes for the index to the cell in the page header). Such ** small cells will be rare, but they are possible. */ #define MX_CELL(pBt) ((pBt->pageSize-8)/6) /* Forward declarations */ typedef struct MemPage MemPage; typedef struct BtLock BtLock; typedef struct CellInfo CellInfo; /* ** This is a magic string that appears at the beginning of every ** SQLite database in order to identify the file as a real database. ** ** You can change this value at compile-time by specifying a ** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The ** header must be exactly 16 bytes including the zero-terminator so ** the string itself should be 15 characters long. If you change ** the header, then your custom library will not be able to read ** databases generated by the standard tools and the standard tools ** will not be able to read databases created by your custom library. */ #ifndef SQLITE_FILE_HEADER /* 123456789 123456 */ # define SQLITE_FILE_HEADER "SQLite format 3" #endif /* ** Page type flags. An ORed combination of these flags appear as the ** first byte of on-disk image of every BTree page. */ #define PTF_INTKEY 0x01 #define PTF_ZERODATA 0x02 #define PTF_LEAFDATA 0x04 #define PTF_LEAF 0x08 /* ** An instance of this object stores information about each a single database ** page that has been loaded into memory. The information in this object ** is derived from the raw on-disk page content. ** ** As each database page is loaded into memory, the pager allocates an ** instance of this object and zeros the first 8 bytes. (This is the ** "extra" information associated with each page of the pager.) ** ** Access to all fields of this structure is controlled by the mutex ** stored in MemPage.pBt->mutex. */ struct MemPage { u8 isInit; /* True if previously initialized. MUST BE FIRST! */ u8 intKey; /* True if table b-trees. False for index b-trees */ u8 intKeyLeaf; /* True if the leaf of an intKey table */ Pgno pgno; /* Page number for this page */ /* Only the first 8 bytes (above) are zeroed by pager.c when a new page ** is allocated. All fields that follow must be initialized before use */ u8 leaf; /* True if a leaf page */ u8 hdrOffset; /* 100 for page 1. 0 otherwise */ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ u8 max1bytePayload; /* min(maxLocal,127) */ u8 nOverflow; /* Number of overflow cell bodies in aCell[] */ u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ int nFree; /* Number of free bytes on the page. -1 for unknown */ u16 nCell; /* Number of cells on this page, local and ovfl */ u16 maskPage; /* Mask for page offset */ u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th ** non-overflow cell */ u8 *apOvfl[4]; /* Pointers to the body of overflow cells */ BtShared *pBt; /* Pointer to BtShared that this page is part of */ u8 *aData; /* Pointer to disk image of the page data */ u8 *aDataEnd; /* One byte past the end of the entire page - not just ** the usable space, the entire page. Used to prevent ** corruption-induced buffer overflow. */ u8 *aCellIdx; /* The cell index area */ u8 *aDataOfst; /* Same as aData for leaves. aData+4 for interior */ DbPage *pDbPage; /* Pager page handle */ u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */ void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */ }; /* ** A linked list of the following structures is stored at BtShared.pLock. ** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor ** is opened on the table with root page BtShared.iTable. Locks are removed ** from this list when a transaction is committed or rolled back, or when ** a btree handle is closed. */ struct BtLock { Btree *pBtree; /* Btree handle holding this lock */ Pgno iTable; /* Root page of table */ u8 eLock; /* READ_LOCK or WRITE_LOCK */ BtLock *pNext; /* Next in BtShared.pLock list */ }; /* Candidate values for BtLock.eLock */ #define READ_LOCK 1 #define WRITE_LOCK 2 /* A Btree handle ** ** A database connection contains a pointer to an instance of ** this object for every database file that it has open. This structure ** is opaque to the database connection. The database connection cannot ** see the internals of this structure and only deals with pointers to ** this structure. ** ** For some database files, the same underlying database cache might be ** shared between multiple connections. In that case, each connection ** has it own instance of this object. But each instance of this object ** points to the same BtShared object. The database cache and the ** schema associated with the database file are all contained within ** the BtShared object. ** ** All fields in this structure are accessed under sqlite3.mutex. ** The pBt pointer itself may not be changed while there exists cursors ** in the referenced BtShared that point back to this Btree since those ** cursors have to go through this Btree to find their BtShared and ** they often do so without holding sqlite3.mutex. */ struct Btree { sqlite3 *db; /* The database connection holding this btree */ BtShared *pBt; /* Sharable content of this btree */ u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ u8 sharable; /* True if we can share pBt with another db */ u8 locked; /* True if db currently has pBt locked */ u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */ int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */ int nBackup; /* Number of backup operations reading this btree */ u32 iBDataVersion; /* Combines with pBt->pPager->iDataVersion */ Btree *pNext; /* List of other sharable Btrees from the same db */ Btree *pPrev; /* Back pointer of the same list */ #ifdef SQLITE_DEBUG u64 nSeek; /* Calls to sqlite3BtreeMovetoUnpacked() */ #endif #ifndef SQLITE_OMIT_SHARED_CACHE BtLock lock; /* Object used to lock page 1 */ #endif }; /* ** Btree.inTrans may take one of the following values. ** ** If the shared-data extension is enabled, there may be multiple users ** of the Btree structure. At most one of these may open a write transaction, ** but any number may have active read transactions. ** ** These values must match SQLITE_TXN_NONE, SQLITE_TXN_READ, and ** SQLITE_TXN_WRITE */ #define TRANS_NONE 0 #define TRANS_READ 1 #define TRANS_WRITE 2 #if TRANS_NONE!=SQLITE_TXN_NONE # error wrong numeric code for no-transaction #endif #if TRANS_READ!=SQLITE_TXN_READ # error wrong numeric code for read-transaction #endif #if TRANS_WRITE!=SQLITE_TXN_WRITE # error wrong numeric code for write-transaction #endif /* ** An instance of this object represents a single database file. ** ** A single database file can be in use at the same time by two ** or more database connections. When two or more connections are ** sharing the same database file, each connection has it own ** private Btree object for the file and each of those Btrees points ** to this one BtShared object. BtShared.nRef is the number of ** connections currently sharing this database file. ** ** Fields in this structure are accessed under the BtShared.mutex ** mutex, except for nRef and pNext which are accessed under the ** global SQLITE_MUTEX_STATIC_MAIN mutex. The pPager field ** may not be modified once it is initially set as long as nRef>0. ** The pSchema field may be set once under BtShared.mutex and ** thereafter is unchanged as long as nRef>0. ** ** isPending: ** ** If a BtShared client fails to obtain a write-lock on a database ** table (because there exists one or more read-locks on the table), ** the shared-cache enters 'pending-lock' state and isPending is ** set to true. ** ** The shared-cache leaves the 'pending lock' state when either of ** the following occur: ** ** 1) The current writer (BtShared.pWriter) concludes its transaction, OR ** 2) The number of locks held by other connections drops to zero. ** ** while in the 'pending-lock' state, no connection may start a new ** transaction. ** ** This feature is included to help prevent writer-starvation. */ struct BtShared { Pager *pPager; /* The page cache */ sqlite3 *db; /* Database connection currently using this Btree */ BtCursor *pCursor; /* A list of all open cursors */ MemPage *pPage1; /* First page of the database */ u8 openFlags; /* Flags to sqlite3BtreeOpen() */ #ifndef SQLITE_OMIT_AUTOVACUUM u8 autoVacuum; /* True if auto-vacuum is enabled */ u8 incrVacuum; /* True if incr-vacuum is enabled */ u8 bDoTruncate; /* True to truncate db on commit */ #endif u8 inTransaction; /* Transaction state */ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ u8 nReserveWanted; /* Desired number of extra bytes per page */ u16 btsFlags; /* Boolean parameters. See BTS_* macros below */ u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */ u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */ u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */ u16 minLeaf; /* Minimum local payload in a LEAFDATA table */ u32 pageSize; /* Total number of bytes on a page */ u32 usableSize; /* Number of usable bytes on each page */ int nTransaction; /* Number of open transactions (read + write) */ u32 nPage; /* Number of pages in the database */ void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */ void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ sqlite3_mutex *mutex; /* Non-recursive mutex required to access this object */ Bitvec *pHasContent; /* Set of pages moved to free-list this transaction */ #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ int nPreformatSize; /* Size of last cell written by TransferRow() */ }; /* ** Allowed values for BtShared.btsFlags */ #define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ #define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ #define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */ #define BTS_OVERWRITE 0x0008 /* Overwrite deleted content with zeros */ #define BTS_FAST_SECURE 0x000c /* Combination of the previous two */ #define BTS_INITIALLY_EMPTY 0x0010 /* Database was empty at trans start */ #define BTS_NO_WAL 0x0020 /* Do not open write-ahead-log files */ #define BTS_EXCLUSIVE 0x0040 /* pWriter has an exclusive lock */ #define BTS_PENDING 0x0080 /* Waiting for read-locks to clear */ /* ** An instance of the following structure is used to hold information ** about a cell. The parseCellPtr() function fills in this structure ** based on information extract from the raw disk page. */ struct CellInfo { i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */ u8 *pPayload; /* Pointer to the start of payload */ u32 nPayload; /* Bytes of payload */ u16 nLocal; /* Amount of payload held locally, not on overflow */ u16 nSize; /* Size of the cell content on the main b-tree page */ }; /* ** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than ** this will be declared corrupt. This value is calculated based on a ** maximum database size of 2^31 pages a minimum fanout of 2 for a ** root-node and 3 for all other internal nodes. ** ** If a tree that appears to be taller than this is encountered, it is ** assumed that the database is corrupt. */ #define BTCURSOR_MAX_DEPTH 20 /* ** A cursor is a pointer to a particular entry within a particular ** b-tree within a database file. ** ** The entry is identified by its MemPage and the index in ** MemPage.aCell[] of the entry. ** ** A single database file can be shared by two more database connections, ** but cursors cannot be shared. Each cursor is associated with a ** particular database connection identified BtCursor.pBtree.db. ** ** Fields in this structure are accessed under the BtShared.mutex ** found at self->pBt->mutex. ** ** skipNext meaning: ** The meaning of skipNext depends on the value of eState: ** ** eState Meaning of skipNext ** VALID skipNext is meaningless and is ignored ** INVALID skipNext is meaningless and is ignored ** SKIPNEXT sqlite3BtreeNext() is a no-op if skipNext>0 and ** sqlite3BtreePrevious() is no-op if skipNext<0. ** REQUIRESEEK restoreCursorPosition() restores the cursor to ** eState=SKIPNEXT if skipNext!=0 ** FAULT skipNext holds the cursor fault error code. */ struct BtCursor { u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ u8 hints; /* As configured by CursorSetHints() */ int skipNext; /* Prev() is noop if negative. Next() is noop if positive. ** Error code if eState==CURSOR_FAULT */ Btree *pBtree; /* The Btree to which this cursor belongs */ Pgno *aOverflow; /* Cache of overflow page locations */ void *pKey; /* Saved key that was cursor last known position */ /* All fields above are zeroed when the cursor is allocated. See ** sqlite3BtreeCursorZero(). Fields that follow must be manually ** initialized. */ #define BTCURSOR_FIRST_UNINIT pBt /* Name of first uninitialized field */ BtShared *pBt; /* The BtShared this cursor points to */ BtCursor *pNext; /* Forms a linked list of all cursors */ CellInfo info; /* A parse of the cell we are pointing at */ i64 nKey; /* Size of pKey, or last integer key */ Pgno pgnoRoot; /* The root page of this tree */ i8 iPage; /* Index of current page in apPage */ u8 curIntKey; /* Value of apPage[0]->intKey */ u16 ix; /* Current index for apPage[iPage] */ u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */ struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */ MemPage *pPage; /* Current page */ MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */ }; /* ** Legal values for BtCursor.curFlags */ #define BTCF_WriteFlag 0x01 /* True if a write cursor */ #define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */ #define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */ #define BTCF_AtLast 0x08 /* Cursor is pointing to the last entry */ #define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */ #define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */ #define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */ /* ** Potential values for BtCursor.eState. ** ** CURSOR_INVALID: ** Cursor does not point to a valid entry. This can happen (for example) ** because the table is empty or because BtreeCursorFirst() has not been ** called. ** ** CURSOR_VALID: ** Cursor points to a valid entry. getPayload() etc. may be called. ** ** CURSOR_SKIPNEXT: ** Cursor is valid except that the Cursor.skipNext field is non-zero ** indicating that the next sqlite3BtreeNext() or sqlite3BtreePrevious() ** operation should be a no-op. ** ** CURSOR_REQUIRESEEK: ** The table that this cursor was opened on still exists, but has been ** modified since the cursor was last used. The cursor position is saved ** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in ** this state, restoreCursorPosition() can be called to attempt to ** seek the cursor to the saved position. ** ** CURSOR_FAULT: ** An unrecoverable error (an I/O error or a malloc failure) has occurred ** on a different connection that shares the BtShared cache with this ** cursor. The error has left the cache in an inconsistent state. ** Do nothing else with this cursor. Any attempt to use the cursor ** should return the error code stored in BtCursor.skipNext */ #define CURSOR_VALID 0 #define CURSOR_INVALID 1 #define CURSOR_SKIPNEXT 2 #define CURSOR_REQUIRESEEK 3 #define CURSOR_FAULT 4 /* ** The database page the PENDING_BYTE occupies. This page is never used. */ #define PENDING_BYTE_PAGE(pBt) ((Pgno)((PENDING_BYTE/((pBt)->pageSize))+1)) /* ** These macros define the location of the pointer-map entry for a ** database page. The first argument to each is the number of usable ** bytes on each page of the database (often 1024). The second is the ** page number to look up in the pointer map. ** ** PTRMAP_PAGENO returns the database page number of the pointer-map ** page that stores the required pointer. PTRMAP_PTROFFSET returns ** the offset of the requested map entry. ** ** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page, ** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be ** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements ** this test. */ #define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno) #define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1)) #define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno)) /* ** The pointer map is a lookup table that identifies the parent page for ** each child page in the database file. The parent page is the page that ** contains a pointer to the child. Every page in the database contains ** 0 or 1 parent pages. (In this context 'database page' refers ** to any page that is not part of the pointer map itself.) Each pointer map ** entry consists of a single byte 'type' and a 4 byte parent page number. ** The PTRMAP_XXX identifiers below are the valid types. ** ** The purpose of the pointer map is to facility moving pages from one ** position in the file to another as part of autovacuum. When a page ** is moved, the pointer in its parent must be updated to point to the ** new location. The pointer map is used to locate the parent page quickly. ** ** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not ** used in this case. ** ** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number ** is not used in this case. ** ** PTRMAP_OVERFLOW1: The database page is the first page in a list of ** overflow pages. The page number identifies the page that ** contains the cell with a pointer to this overflow page. ** ** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of ** overflow pages. The page-number identifies the previous ** page in the overflow page list. ** ** PTRMAP_BTREE: The database page is a non-root btree page. The page number ** identifies the parent page in the btree. */ #define PTRMAP_ROOTPAGE 1 #define PTRMAP_FREEPAGE 2 #define PTRMAP_OVERFLOW1 3 #define PTRMAP_OVERFLOW2 4 #define PTRMAP_BTREE 5 /* A bunch of assert() statements to check the transaction state variables ** of handle p (type Btree*) are internally consistent. */ #define btreeIntegrity(p) \ assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \ assert( p->pBt->inTransaction>=p->inTrans ); /* ** The ISAUTOVACUUM macro is used within balance_nonroot() to determine ** if the database supports auto-vacuum or not. Because it is used ** within an expression that is an argument to another macro ** (sqliteMallocRaw), it is not possible to use conditional compilation. ** So, this macro is defined instead. */ #ifndef SQLITE_OMIT_AUTOVACUUM #define ISAUTOVACUUM(pBt) (pBt->autoVacuum) #else #define ISAUTOVACUUM(pBt) 0 #endif /* ** This structure is passed around through all the PRAGMA integrity_check ** checking routines in order to keep track of some global state information. ** ** The aRef[] array is allocated so that there is 1 bit for each page in ** the database. As the integrity-check proceeds, for each page used in ** the database the corresponding bit is set. This allows integrity-check to ** detect pages that are used twice and orphaned pages (both of which ** indicate corruption). */ typedef struct IntegrityCk IntegrityCk; struct IntegrityCk { BtShared *pBt; /* The tree being checked out */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ u8 *aPgRef; /* 1 bit per page in the db (see above) */ Pgno nCkPage; /* Pages in the database. 0 for partial check */ int mxErr; /* Stop accumulating errors when this reaches zero */ int nErr; /* Number of messages written to zErrMsg so far */ int rc; /* SQLITE_OK, SQLITE_NOMEM, or SQLITE_INTERRUPT */ u32 nStep; /* Number of steps into the integrity_check process */ const char *zPfx; /* Error message prefix */ Pgno v0; /* Value for first %u substitution in zPfx (root page) */ Pgno v1; /* Value for second %u substitution in zPfx (current pg) */ int v2; /* Value for third %d substitution in zPfx */ StrAccum errMsg; /* Accumulate the error message text here */ u32 *heap; /* Min-heap used for analyzing cell coverage */ sqlite3 *db; /* Database connection running the check */ }; /* ** Routines to read or write a two- and four-byte big-endian integer values. */ #define get2byte(x) ((x)[0]<<8 | (x)[1]) #define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v)) #define get4byte sqlite3Get4byte #define put4byte sqlite3Put4byte /* ** get2byteAligned(), unlike get2byte(), requires that its argument point to a ** two-byte aligned address. get2byteAligned() is only used for accessing the ** cell addresses in a btree header. */ #if SQLITE_BYTEORDER==4321 # define get2byteAligned(x) (*(u16*)(x)) #elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4008000 # define get2byteAligned(x) __builtin_bswap16(*(u16*)(x)) #elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 # define get2byteAligned(x) _byteswap_ushort(*(u16*)(x)) #else # define get2byteAligned(x) ((x)[0]<<8 | (x)[1]) #endif /************** End of btreeInt.h ********************************************/ /************** Continuing where we left off in btmutex.c ********************/ #ifndef SQLITE_OMIT_SHARED_CACHE #if SQLITE_THREADSAFE /* ** Obtain the BtShared mutex associated with B-Tree handle p. Also, ** set BtShared.db to the database handle associated with p and the ** p->locked boolean to true. */ static void lockBtreeMutex(Btree *p){ assert( p->locked==0 ); assert( sqlite3_mutex_notheld(p->pBt->mutex) ); assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3_mutex_enter(p->pBt->mutex); p->pBt->db = p->db; p->locked = 1; } /* ** Release the BtShared mutex associated with B-Tree handle p and ** clear the p->locked boolean. */ static void SQLITE_NOINLINE unlockBtreeMutex(Btree *p){ BtShared *pBt = p->pBt; assert( p->locked==1 ); assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3_mutex_held(p->db->mutex) ); assert( p->db==pBt->db ); sqlite3_mutex_leave(pBt->mutex); p->locked = 0; } /* Forward reference */ static void SQLITE_NOINLINE btreeLockCarefully(Btree *p); /* ** Enter a mutex on the given BTree object. ** ** If the object is not sharable, then no mutex is ever required ** and this routine is a no-op. The underlying mutex is non-recursive. ** But we keep a reference count in Btree.wantToLock so the behavior ** of this interface is recursive. ** ** To avoid deadlocks, multiple Btrees are locked in the same order ** by all database connections. The p->pNext is a list of other ** Btrees belonging to the same database connection as the p Btree ** which need to be locked after p. If we cannot get a lock on ** p, then first unlock all of the others on p->pNext, then wait ** for the lock to become available on p, then relock all of the ** subsequent Btrees that desire a lock. */ SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){ /* Some basic sanity checking on the Btree. The list of Btrees ** connected by pNext and pPrev should be in sorted order by ** Btree.pBt value. All elements of the list should belong to ** the same connection. Only shared Btrees are on the list. */ assert( p->pNext==0 || p->pNext->pBt>p->pBt ); assert( p->pPrev==0 || p->pPrev->pBtpBt ); assert( p->pNext==0 || p->pNext->db==p->db ); assert( p->pPrev==0 || p->pPrev->db==p->db ); assert( p->sharable || (p->pNext==0 && p->pPrev==0) ); /* Check for locking consistency */ assert( !p->locked || p->wantToLock>0 ); assert( p->sharable || p->wantToLock==0 ); /* We should already hold a lock on the database connection */ assert( sqlite3_mutex_held(p->db->mutex) ); /* Unless the database is sharable and unlocked, then BtShared.db ** should already be set correctly. */ assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db ); if( !p->sharable ) return; p->wantToLock++; if( p->locked ) return; btreeLockCarefully(p); } /* This is a helper function for sqlite3BtreeLock(). By moving ** complex, but seldom used logic, out of sqlite3BtreeLock() and ** into this routine, we avoid unnecessary stack pointer changes ** and thus help the sqlite3BtreeLock() routine to run much faster ** in the common case. */ static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){ Btree *pLater; /* In most cases, we should be able to acquire the lock we ** want without having to go through the ascending lock ** procedure that follows. Just be sure not to block. */ if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){ p->pBt->db = p->db; p->locked = 1; return; } /* To avoid deadlock, first release all locks with a larger ** BtShared address. Then acquire our lock. Then reacquire ** the other BtShared locks that we used to hold in ascending ** order. */ for(pLater=p->pNext; pLater; pLater=pLater->pNext){ assert( pLater->sharable ); assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt ); assert( !pLater->locked || pLater->wantToLock>0 ); if( pLater->locked ){ unlockBtreeMutex(pLater); } } lockBtreeMutex(p); for(pLater=p->pNext; pLater; pLater=pLater->pNext){ if( pLater->wantToLock ){ lockBtreeMutex(pLater); } } } /* ** Exit the recursive mutex on a Btree. */ SQLITE_PRIVATE void sqlite3BtreeLeave(Btree *p){ assert( sqlite3_mutex_held(p->db->mutex) ); if( p->sharable ){ assert( p->wantToLock>0 ); p->wantToLock--; if( p->wantToLock==0 ){ unlockBtreeMutex(p); } } } #ifndef NDEBUG /* ** Return true if the BtShared mutex is held on the btree, or if the ** B-Tree is not marked as sharable. ** ** This routine is used only from within assert() statements. */ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){ assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 ); assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db ); assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) ); assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) ); return (p->sharable==0 || p->locked); } #endif /* ** Enter the mutex on every Btree associated with a database ** connection. This is needed (for example) prior to parsing ** a statement since we will be comparing table and column names ** against all schemas and we do not want those schemas being ** reset out from under us. ** ** There is a corresponding leave-all procedures. ** ** Enter the mutexes in ascending order by BtShared pointer address ** to avoid the possibility of deadlock when two threads with ** two or more btrees in common both try to lock all their btrees ** at the same instant. */ static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){ int i; int skipOk = 1; Btree *p; assert( sqlite3_mutex_held(db->mutex) ); for(i=0; inDb; i++){ p = db->aDb[i].pBt; if( p && p->sharable ){ sqlite3BtreeEnter(p); skipOk = 0; } } db->noSharedCache = skipOk; } SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ if( db->noSharedCache==0 ) btreeEnterAll(db); } static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){ int i; Btree *p; assert( sqlite3_mutex_held(db->mutex) ); for(i=0; inDb; i++){ p = db->aDb[i].pBt; if( p ) sqlite3BtreeLeave(p); } } SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){ if( db->noSharedCache==0 ) btreeLeaveAll(db); } #ifndef NDEBUG /* ** Return true if the current thread holds the database connection ** mutex and all required BtShared mutexes. ** ** This routine is used inside assert() statements only. */ SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){ int i; if( !sqlite3_mutex_held(db->mutex) ){ return 0; } for(i=0; inDb; i++){ Btree *p; p = db->aDb[i].pBt; if( p && p->sharable && (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){ return 0; } } return 1; } #endif /* NDEBUG */ #ifndef NDEBUG /* ** Return true if the correct mutexes are held for accessing the ** db->aDb[iDb].pSchema structure. The mutexes required for schema ** access are: ** ** (1) The mutex on db ** (2) if iDb!=1, then the mutex on db->aDb[iDb].pBt. ** ** If pSchema is not NULL, then iDb is computed from pSchema and ** db using sqlite3SchemaToIndex(). */ SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){ Btree *p; assert( db!=0 ); if( db->pVfs==0 && db->nDb==0 ) return 1; if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema); assert( iDb>=0 && iDbnDb ); if( !sqlite3_mutex_held(db->mutex) ) return 0; if( iDb==1 ) return 1; p = db->aDb[iDb].pBt; assert( p!=0 ); return p->sharable==0 || p->locked==1; } #endif /* NDEBUG */ #else /* SQLITE_THREADSAFE>0 above. SQLITE_THREADSAFE==0 below */ /* ** The following are special cases for mutex enter routines for use ** in single threaded applications that use shared cache. Except for ** these two routines, all mutex operations are no-ops in that case and ** are null #defines in btree.h. ** ** If shared cache is disabled, then all btree mutex routines, including ** the ones below, are no-ops and are null #defines in btree.h. */ SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){ p->pBt->db = p->db; } SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ int i; for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; if( p ){ p->pBt->db = p->db; } } } #endif /* if SQLITE_THREADSAFE */ #ifndef SQLITE_OMIT_INCRBLOB /* ** Enter a mutex on a Btree given a cursor owned by that Btree. ** ** These entry points are used by incremental I/O only. Enter() is required ** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not ** the build is threadsafe. Leave() is only required by threadsafe builds. */ SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){ sqlite3BtreeEnter(pCur->pBtree); } # if SQLITE_THREADSAFE SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ sqlite3BtreeLeave(pCur->pBtree); } # endif #endif /* ifndef SQLITE_OMIT_INCRBLOB */ #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */ /************** End of btmutex.c *********************************************/ /************** Begin file btree.c *******************************************/ /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file implements an external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ /* #include "btreeInt.h" */ /* ** The header string that appears at the beginning of every ** SQLite database. */ static const char zMagicHeader[] = SQLITE_FILE_HEADER; /* ** Set this global variable to 1 to enable tracing using the TRACE ** macro. */ #if 0 int sqlite3BtreeTrace=1; /* True to enable tracing */ # define TRACE(X) if(sqlite3BtreeTrace){printf X;fflush(stdout);} #else # define TRACE(X) #endif /* ** Extract a 2-byte big-endian integer from an array of unsigned bytes. ** But if the value is zero, make it 65536. ** ** This routine is used to extract the "offset to cell content area" value ** from the header of a btree page. If the page size is 65536 and the page ** is empty, the offset should be 65536, but the 2-byte value stores zero. ** This routine makes the necessary adjustment to 65536. */ #define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1) /* ** Values passed as the 5th argument to allocateBtreePage() */ #define BTALLOC_ANY 0 /* Allocate any page */ #define BTALLOC_EXACT 1 /* Allocate exact page if possible */ #define BTALLOC_LE 2 /* Allocate any page <= the parameter */ /* ** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not ** defined, or 0 if it is. For example: ** ** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum); */ #ifndef SQLITE_OMIT_AUTOVACUUM #define IfNotOmitAV(expr) (expr) #else #define IfNotOmitAV(expr) 0 #endif #ifndef SQLITE_OMIT_SHARED_CACHE /* ** A list of BtShared objects that are eligible for participation ** in shared cache. This variable has file scope during normal builds, ** but the test harness needs to access it so we make it global for ** test builds. ** ** Access to this variable is protected by SQLITE_MUTEX_STATIC_MAIN. */ #ifdef SQLITE_TEST SQLITE_PRIVATE BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; #else static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; #endif #endif /* SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Enable or disable the shared pager and schema features. ** ** This routine has no effect on existing database connections. ** The shared cache setting effects only future calls to ** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). */ SQLITE_API int sqlite3_enable_shared_cache(int enable){ sqlite3GlobalConfig.sharedCacheEnabled = enable; return SQLITE_OK; } #endif #ifdef SQLITE_OMIT_SHARED_CACHE /* ** The functions querySharedCacheTableLock(), setSharedCacheTableLock(), ** and clearAllSharedCacheTableLocks() ** manipulate entries in the BtShared.pLock linked list used to store ** shared-cache table level locks. If the library is compiled with the ** shared-cache feature disabled, then there is only ever one user ** of each BtShared structure and so this locking is not necessary. ** So define the lock related functions as no-ops. */ #define querySharedCacheTableLock(a,b,c) SQLITE_OK #define setSharedCacheTableLock(a,b,c) SQLITE_OK #define clearAllSharedCacheTableLocks(a) #define downgradeAllSharedCacheTableLocks(a) #define hasSharedCacheTableLock(a,b,c,d) 1 #define hasReadConflicts(a, b) 0 #endif #ifdef SQLITE_DEBUG /* ** Return and reset the seek counter for a Btree object. */ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ u64 n = pBt->nSeek; pBt->nSeek = 0; return n; } #endif /* ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single ** (MemPage*) as an argument. The (MemPage*) must not be NULL. ** ** If SQLITE_DEBUG is not defined, then this macro is equivalent to ** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message ** normally produced as a side-effect of SQLITE_CORRUPT_BKPT is augmented ** with the page number and filename associated with the (MemPage*). */ #ifdef SQLITE_DEBUG int corruptPageError(int lineno, MemPage *p){ char *zMsg; sqlite3BeginBenignMalloc(); zMsg = sqlite3_mprintf("database corruption page %u of %s", p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0) ); sqlite3EndBenignMalloc(); if( zMsg ){ sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); } sqlite3_free(zMsg); return SQLITE_CORRUPT_BKPT; } # define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage) #else # define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno) #endif #ifndef SQLITE_OMIT_SHARED_CACHE #ifdef SQLITE_DEBUG /* **** This function is only used as part of an assert() statement. *** ** ** Check to see if pBtree holds the required locks to read or write to the ** table with root page iRoot. Return 1 if it does and 0 if not. ** ** For example, when writing to a table with root-page iRoot via ** Btree connection pBtree: ** ** assert( hasSharedCacheTableLock(pBtree, iRoot, 0, WRITE_LOCK) ); ** ** When writing to an index that resides in a sharable database, the ** caller should have first obtained a lock specifying the root page of ** the corresponding table. This makes things a bit more complicated, ** as this module treats each table as a separate structure. To determine ** the table corresponding to the index being written, this ** function has to search through the database schema. ** ** Instead of a lock on the table/index rooted at page iRoot, the caller may ** hold a write-lock on the schema table (root page 1). This is also ** acceptable. */ static int hasSharedCacheTableLock( Btree *pBtree, /* Handle that must hold lock */ Pgno iRoot, /* Root page of b-tree */ int isIndex, /* True if iRoot is the root of an index b-tree */ int eLockType /* Required lock type (READ_LOCK or WRITE_LOCK) */ ){ Schema *pSchema = (Schema *)pBtree->pBt->pSchema; Pgno iTab = 0; BtLock *pLock; /* If this database is not shareable, or if the client is reading ** and has the read-uncommitted flag set, then no lock is required. ** Return true immediately. */ if( (pBtree->sharable==0) || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommit)) ){ return 1; } /* If the client is reading or writing an index and the schema is ** not loaded, then it is too difficult to actually check to see if ** the correct locks are held. So do not bother - just return true. ** This case does not come up very often anyhow. */ if( isIndex && (!pSchema || (pSchema->schemaFlags&DB_SchemaLoaded)==0) ){ return 1; } /* Figure out the root-page that the lock should be held on. For table ** b-trees, this is just the root page of the b-tree being read or ** written. For index b-trees, it is the root page of the associated ** table. */ if( isIndex ){ HashElem *p; int bSeen = 0; for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){ Index *pIdx = (Index *)sqliteHashData(p); if( pIdx->tnum==iRoot ){ if( bSeen ){ /* Two or more indexes share the same root page. There must ** be imposter tables. So just return true. The assert is not ** useful in that case. */ return 1; } iTab = pIdx->pTable->tnum; bSeen = 1; } } }else{ iTab = iRoot; } /* Search for the required lock. Either a write-lock on root-page iTab, a ** write-lock on the schema table, or (if the client is reading) a ** read-lock on iTab will suffice. Return 1 if any of these are found. */ for(pLock=pBtree->pBt->pLock; pLock; pLock=pLock->pNext){ if( pLock->pBtree==pBtree && (pLock->iTable==iTab || (pLock->eLock==WRITE_LOCK && pLock->iTable==1)) && pLock->eLock>=eLockType ){ return 1; } } /* Failed to find the required lock. */ return 0; } #endif /* SQLITE_DEBUG */ #ifdef SQLITE_DEBUG /* **** This function may be used as part of assert() statements only. **** ** ** Return true if it would be illegal for pBtree to write into the ** table or index rooted at iRoot because other shared connections are ** simultaneously reading that same table or index. ** ** It is illegal for pBtree to write if some other Btree object that ** shares the same BtShared object is currently reading or writing ** the iRoot table. Except, if the other Btree object has the ** read-uncommitted flag set, then it is OK for the other object to ** have a read cursor. ** ** For example, before writing to any part of the table or index ** rooted at page iRoot, one should call: ** ** assert( !hasReadConflicts(pBtree, iRoot) ); */ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){ BtCursor *p; for(p=pBtree->pBt->pCursor; p; p=p->pNext){ if( p->pgnoRoot==iRoot && p->pBtree!=pBtree && 0==(p->pBtree->db->flags & SQLITE_ReadUncommit) ){ return 1; } } return 0; } #endif /* #ifdef SQLITE_DEBUG */ /* ** Query to see if Btree handle p may obtain a lock of type eLock ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return ** SQLITE_OK if the lock may be obtained (by calling ** setSharedCacheTableLock()), or SQLITE_LOCKED if not. */ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ BtShared *pBt = p->pBt; BtLock *pIter; assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 ); /* If requesting a write-lock, then the Btree must have an open write ** transaction on this file. And, obviously, for this to be so there ** must be an open write transaction on the file itself. */ assert( eLock==READ_LOCK || (p==pBt->pWriter && p->inTrans==TRANS_WRITE) ); assert( eLock==READ_LOCK || pBt->inTransaction==TRANS_WRITE ); /* This routine is a no-op if the shared-cache is not enabled */ if( !p->sharable ){ return SQLITE_OK; } /* If some other connection is holding an exclusive lock, the ** requested lock may not be obtained. */ if( pBt->pWriter!=p && (pBt->btsFlags & BTS_EXCLUSIVE)!=0 ){ sqlite3ConnectionBlocked(p->db, pBt->pWriter->db); return SQLITE_LOCKED_SHAREDCACHE; } for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ /* The condition (pIter->eLock!=eLock) in the following if(...) ** statement is a simplification of: ** ** (eLock==WRITE_LOCK || pIter->eLock==WRITE_LOCK) ** ** since we know that if eLock==WRITE_LOCK, then no other connection ** may hold a WRITE_LOCK on any table in this file (since there can ** only be a single writer). */ assert( pIter->eLock==READ_LOCK || pIter->eLock==WRITE_LOCK ); assert( eLock==READ_LOCK || pIter->pBtree==p || pIter->eLock==READ_LOCK); if( pIter->pBtree!=p && pIter->iTable==iTab && pIter->eLock!=eLock ){ sqlite3ConnectionBlocked(p->db, pIter->pBtree->db); if( eLock==WRITE_LOCK ){ assert( p==pBt->pWriter ); pBt->btsFlags |= BTS_PENDING; } return SQLITE_LOCKED_SHAREDCACHE; } } return SQLITE_OK; } #endif /* !SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Add a lock on the table with root-page iTable to the shared-btree used ** by Btree handle p. Parameter eLock must be either READ_LOCK or ** WRITE_LOCK. ** ** This function assumes the following: ** ** (a) The specified Btree object p is connected to a sharable ** database (one with the BtShared.sharable flag set), and ** ** (b) No other Btree objects hold a lock that conflicts ** with the requested lock (i.e. querySharedCacheTableLock() has ** already been called and returned SQLITE_OK). ** ** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM ** is returned if a malloc attempt fails. */ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ BtShared *pBt = p->pBt; BtLock *pLock = 0; BtLock *pIter; assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); /* A connection with the read-uncommitted flag set will never try to ** obtain a read-lock using this function. The only read-lock obtained ** by a connection in read-uncommitted mode is on the sqlite_schema ** table, and that lock is obtained in BtreeBeginTrans(). */ assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK ); /* This function should only be called on a sharable b-tree after it ** has been determined that no other b-tree holds a conflicting lock. */ assert( p->sharable ); assert( SQLITE_OK==querySharedCacheTableLock(p, iTable, eLock) ); /* First search the list for an existing lock on this table. */ for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ if( pIter->iTable==iTable && pIter->pBtree==p ){ pLock = pIter; break; } } /* If the above search did not find a BtLock struct associating Btree p ** with table iTable, allocate one and link it into the list. */ if( !pLock ){ pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock)); if( !pLock ){ return SQLITE_NOMEM_BKPT; } pLock->iTable = iTable; pLock->pBtree = p; pLock->pNext = pBt->pLock; pBt->pLock = pLock; } /* Set the BtLock.eLock variable to the maximum of the current lock ** and the requested lock. This means if a write-lock was already held ** and a read-lock requested, we don't incorrectly downgrade the lock. */ assert( WRITE_LOCK>READ_LOCK ); if( eLock>pLock->eLock ){ pLock->eLock = eLock; } return SQLITE_OK; } #endif /* !SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Release all the table locks (locks obtained via calls to ** the setSharedCacheTableLock() procedure) held by Btree object p. ** ** This function assumes that Btree p has an open read or write ** transaction. If it does not, then the BTS_PENDING flag ** may be incorrectly cleared. */ static void clearAllSharedCacheTableLocks(Btree *p){ BtShared *pBt = p->pBt; BtLock **ppIter = &pBt->pLock; assert( sqlite3BtreeHoldsMutex(p) ); assert( p->sharable || 0==*ppIter ); assert( p->inTrans>0 ); while( *ppIter ){ BtLock *pLock = *ppIter; assert( (pBt->btsFlags & BTS_EXCLUSIVE)==0 || pBt->pWriter==pLock->pBtree ); assert( pLock->pBtree->inTrans>=pLock->eLock ); if( pLock->pBtree==p ){ *ppIter = pLock->pNext; assert( pLock->iTable!=1 || pLock==&p->lock ); if( pLock->iTable!=1 ){ sqlite3_free(pLock); } }else{ ppIter = &pLock->pNext; } } assert( (pBt->btsFlags & BTS_PENDING)==0 || pBt->pWriter ); if( pBt->pWriter==p ){ pBt->pWriter = 0; pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING); }else if( pBt->nTransaction==2 ){ /* This function is called when Btree p is concluding its ** transaction. If there currently exists a writer, and p is not ** that writer, then the number of locks held by connections other ** than the writer must be about to drop to zero. In this case ** set the BTS_PENDING flag to 0. ** ** If there is not currently a writer, then BTS_PENDING must ** be zero already. So this next line is harmless in that case. */ pBt->btsFlags &= ~BTS_PENDING; } } /* ** This function changes all write-locks held by Btree p into read-locks. */ static void downgradeAllSharedCacheTableLocks(Btree *p){ BtShared *pBt = p->pBt; if( pBt->pWriter==p ){ BtLock *pLock; pBt->pWriter = 0; pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING); for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){ assert( pLock->eLock==READ_LOCK || pLock->pBtree==p ); pLock->eLock = READ_LOCK; } } } #endif /* SQLITE_OMIT_SHARED_CACHE */ static void releasePage(MemPage *pPage); /* Forward reference */ static void releasePageOne(MemPage *pPage); /* Forward reference */ static void releasePageNotNull(MemPage *pPage); /* Forward reference */ /* ***** This routine is used inside of assert() only **** ** ** Verify that the cursor holds the mutex on its BtShared */ #ifdef SQLITE_DEBUG static int cursorHoldsMutex(BtCursor *p){ return sqlite3_mutex_held(p->pBt->mutex); } /* Verify that the cursor and the BtShared agree about what is the current ** database connetion. This is important in shared-cache mode. If the database ** connection pointers get out-of-sync, it is possible for routines like ** btreeInitPage() to reference an stale connection pointer that references a ** a connection that has already closed. This routine is used inside assert() ** statements only and for the purpose of double-checking that the btree code ** does keep the database connection pointers up-to-date. */ static int cursorOwnsBtShared(BtCursor *p){ assert( cursorHoldsMutex(p) ); return (p->pBtree->db==p->pBt->db); } #endif /* ** Invalidate the overflow cache of the cursor passed as the first argument. ** on the shared btree structure pBt. */ #define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl) /* ** Invalidate the overflow page-list cache for all cursors opened ** on the shared btree structure pBt. */ static void invalidateAllOverflowCache(BtShared *pBt){ BtCursor *p; assert( sqlite3_mutex_held(pBt->mutex) ); for(p=pBt->pCursor; p; p=p->pNext){ invalidateOverflowCache(p); } } #ifndef SQLITE_OMIT_INCRBLOB /* ** This function is called before modifying the contents of a table ** to invalidate any incrblob cursors that are open on the ** row or one of the rows being modified. ** ** If argument isClearTable is true, then the entire contents of the ** table is about to be deleted. In this case invalidate all incrblob ** cursors open on any row within the table with root-page pgnoRoot. ** ** Otherwise, if argument isClearTable is false, then the row with ** rowid iRow is being replaced or deleted. In this case invalidate ** only those incrblob cursors open on that specific row. */ static void invalidateIncrblobCursors( Btree *pBtree, /* The database file to check */ Pgno pgnoRoot, /* The table that might be changing */ i64 iRow, /* The rowid that might be changing */ int isClearTable /* True if all rows are being deleted */ ){ BtCursor *p; assert( pBtree->hasIncrblobCur ); assert( sqlite3BtreeHoldsMutex(pBtree) ); pBtree->hasIncrblobCur = 0; for(p=pBtree->pBt->pCursor; p; p=p->pNext){ if( (p->curFlags & BTCF_Incrblob)!=0 ){ pBtree->hasIncrblobCur = 1; if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){ p->eState = CURSOR_INVALID; } } } } #else /* Stub function when INCRBLOB is omitted */ #define invalidateIncrblobCursors(w,x,y,z) #endif /* SQLITE_OMIT_INCRBLOB */ /* ** Set bit pgno of the BtShared.pHasContent bitvec. This is called ** when a page that previously contained data becomes a free-list leaf ** page. ** ** The BtShared.pHasContent bitvec exists to work around an obscure ** bug caused by the interaction of two useful IO optimizations surrounding ** free-list leaf pages: ** ** 1) When all data is deleted from a page and the page becomes ** a free-list leaf page, the page is not written to the database ** (as free-list leaf pages contain no meaningful data). Sometimes ** such a page is not even journalled (as it will not be modified, ** why bother journalling it?). ** ** 2) When a free-list leaf page is reused, its content is not read ** from the database or written to the journal file (why should it ** be, if it is not at all meaningful?). ** ** By themselves, these optimizations work fine and provide a handy ** performance boost to bulk delete or insert operations. However, if ** a page is moved to the free-list and then reused within the same ** transaction, a problem comes up. If the page is not journalled when ** it is moved to the free-list and it is also not journalled when it ** is extracted from the free-list and reused, then the original data ** may be lost. In the event of a rollback, it may not be possible ** to restore the database to its original configuration. ** ** The solution is the BtShared.pHasContent bitvec. Whenever a page is ** moved to become a free-list leaf page, the corresponding bit is ** set in the bitvec. Whenever a leaf page is extracted from the free-list, ** optimization 2 above is omitted if the corresponding bit is already ** set in BtShared.pHasContent. The contents of the bitvec are cleared ** at the end of every transaction. */ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){ int rc = SQLITE_OK; if( !pBt->pHasContent ){ assert( pgno<=pBt->nPage ); pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage); if( !pBt->pHasContent ){ rc = SQLITE_NOMEM_BKPT; } } if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){ rc = sqlite3BitvecSet(pBt->pHasContent, pgno); } return rc; } /* ** Query the BtShared.pHasContent vector. ** ** This function is called when a free-list leaf page is removed from the ** free-list for reuse. It returns false if it is safe to retrieve the ** page from the pager layer with the 'no-content' flag set. True otherwise. */ static int btreeGetHasContent(BtShared *pBt, Pgno pgno){ Bitvec *p = pBt->pHasContent; return p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTestNotNull(p, pgno)); } /* ** Clear (destroy) the BtShared.pHasContent bitvec. This should be ** invoked at the conclusion of each write-transaction. */ static void btreeClearHasContent(BtShared *pBt){ sqlite3BitvecDestroy(pBt->pHasContent); pBt->pHasContent = 0; } /* ** Release all of the apPage[] pages for a cursor. */ static void btreeReleaseAllCursorPages(BtCursor *pCur){ int i; if( pCur->iPage>=0 ){ for(i=0; iiPage; i++){ releasePageNotNull(pCur->apPage[i]); } releasePageNotNull(pCur->pPage); pCur->iPage = -1; } } /* ** The cursor passed as the only argument must point to a valid entry ** when this function is called (i.e. have eState==CURSOR_VALID). This ** function saves the current cursor key in variables pCur->nKey and ** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error ** code otherwise. ** ** If the cursor is open on an intkey table, then the integer key ** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to ** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is ** set to point to a malloced buffer pCur->nKey bytes in size containing ** the key. */ static int saveCursorKey(BtCursor *pCur){ int rc = SQLITE_OK; assert( CURSOR_VALID==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); if( pCur->curIntKey ){ /* Only the rowid is required for a table btree */ pCur->nKey = sqlite3BtreeIntegerKey(pCur); }else{ /* For an index btree, save the complete key content. It is possible ** that the current key is corrupt. In that case, it is possible that ** the sqlite3VdbeRecordUnpack() function may overread the buffer by ** up to the size of 1 varint plus 1 8-byte value when the cursor ** position is restored. Hence the 17 bytes of padding allocated ** below. */ void *pKey; pCur->nKey = sqlite3BtreePayloadSize(pCur); pKey = sqlite3Malloc( pCur->nKey + 9 + 8 ); if( pKey ){ rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ memset(((u8*)pKey)+pCur->nKey, 0, 9+8); pCur->pKey = pKey; }else{ sqlite3_free(pKey); } }else{ rc = SQLITE_NOMEM_BKPT; } } assert( !pCur->curIntKey || !pCur->pKey ); return rc; } /* ** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. ** ** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID) ** prior to calling this routine. */ static int saveCursorPosition(BtCursor *pCur){ int rc; assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); if( pCur->curFlags & BTCF_Pinned ){ return SQLITE_CONSTRAINT_PINNED; } if( pCur->eState==CURSOR_SKIPNEXT ){ pCur->eState = CURSOR_VALID; }else{ pCur->skipNext = 0; } rc = saveCursorKey(pCur); if( rc==SQLITE_OK ){ btreeReleaseAllCursorPages(pCur); pCur->eState = CURSOR_REQUIRESEEK; } pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl|BTCF_AtLast); return rc; } /* Forward reference */ static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*); /* ** Save the positions of all cursors (except pExcept) that are open on ** the table with root-page iRoot. "Saving the cursor position" means that ** the location in the btree is remembered in such a way that it can be ** moved back to the same spot after the btree has been modified. This ** routine is called just before cursor pExcept is used to modify the ** table, for example in BtreeDelete() or BtreeInsert(). ** ** If there are two or more cursors on the same btree, then all such ** cursors should have their BTCF_Multiple flag set. The btreeCursor() ** routine enforces that rule. This routine only needs to be called in ** the uncommon case when pExpect has the BTCF_Multiple flag set. ** ** If pExpect!=NULL and if no other cursors are found on the same root-page, ** then the BTCF_Multiple flag on pExpect is cleared, to avoid another ** pointless call to this routine. ** ** Implementation note: This routine merely checks to see if any cursors ** need to be saved. It calls out to saveCursorsOnList() in the (unusual) ** event that cursors are in need to being saved. */ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ BtCursor *p; assert( sqlite3_mutex_held(pBt->mutex) ); assert( pExcept==0 || pExcept->pBt==pBt ); for(p=pBt->pCursor; p; p=p->pNext){ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ) break; } if( p ) return saveCursorsOnList(p, iRoot, pExcept); if( pExcept ) pExcept->curFlags &= ~BTCF_Multiple; return SQLITE_OK; } /* This helper routine to saveAllCursors does the actual work of saving ** the cursors if and when a cursor is found that actually requires saving. ** The common case is that no cursors need to be saved, so this routine is ** broken out from its caller to avoid unnecessary stack pointer movement. */ static int SQLITE_NOINLINE saveCursorsOnList( BtCursor *p, /* The first cursor that needs saving */ Pgno iRoot, /* Only save cursor with this iRoot. Save all if zero */ BtCursor *pExcept /* Do not save this cursor */ ){ do{ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){ int rc = saveCursorPosition(p); if( SQLITE_OK!=rc ){ return rc; } }else{ testcase( p->iPage>=0 ); btreeReleaseAllCursorPages(p); } } p = p->pNext; }while( p ); return SQLITE_OK; } /* ** Clear the current cursor position. */ SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); sqlite3_free(pCur->pKey); pCur->pKey = 0; pCur->eState = CURSOR_INVALID; } /* ** In this version of BtreeMoveto, pKey is a packed index record ** such as is generated by the OP_MakeRecord opcode. Unpack the ** record and then call sqlite3BtreeIndexMoveto() to do the work. */ static int btreeMoveto( BtCursor *pCur, /* Cursor open on the btree to be searched */ const void *pKey, /* Packed key if the btree is an index */ i64 nKey, /* Integer key for tables. Size of pKey for indices */ int bias, /* Bias search to the high end */ int *pRes /* Write search results here */ ){ int rc; /* Status code */ UnpackedRecord *pIdxKey; /* Unpacked index key */ if( pKey ){ KeyInfo *pKeyInfo = pCur->pKeyInfo; assert( nKey==(i64)(int)nKey ); pIdxKey = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ rc = SQLITE_CORRUPT_BKPT; }else{ rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); } sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); }else{ pIdxKey = 0; rc = sqlite3BtreeTableMoveto(pCur, nKey, bias, pRes); } return rc; } /* ** Restore the cursor to the position it was in (or as close to as possible) ** when saveCursorPosition() was called. Note that this call deletes the ** saved position info stored by saveCursorPosition(), so there can be ** at most one effective restoreCursorPosition() call after each ** saveCursorPosition(). */ static int btreeRestoreCursorPosition(BtCursor *pCur){ int rc; int skipNext = 0; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState>=CURSOR_REQUIRESEEK ); if( pCur->eState==CURSOR_FAULT ){ return pCur->skipNext; } pCur->eState = CURSOR_INVALID; if( sqlite3FaultSim(410) ){ rc = SQLITE_IOERR; }else{ rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); } if( rc==SQLITE_OK ){ sqlite3_free(pCur->pKey); pCur->pKey = 0; assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); if( skipNext ) pCur->skipNext = skipNext; if( pCur->skipNext && pCur->eState==CURSOR_VALID ){ pCur->eState = CURSOR_SKIPNEXT; } } return rc; } #define restoreCursorPosition(p) \ (p->eState>=CURSOR_REQUIRESEEK ? \ btreeRestoreCursorPosition(p) : \ SQLITE_OK) /* ** Determine whether or not a cursor has moved from the position where ** it was last placed, or has been invalidated for any other reason. ** Cursors can move when the row they are pointing at is deleted out ** from under them, for example. Cursor might also move if a btree ** is rebalanced. ** ** Calling this routine with a NULL cursor pointer returns false. ** ** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor ** back to where it ought to be if this routine returns true. */ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ assert( EIGHT_BYTE_ALIGNMENT(pCur) || pCur==sqlite3BtreeFakeValidCursor() ); assert( offsetof(BtCursor, eState)==0 ); assert( sizeof(pCur->eState)==1 ); return CURSOR_VALID != *(u8*)pCur; } /* ** Return a pointer to a fake BtCursor object that will always answer ** false to the sqlite3BtreeCursorHasMoved() routine above. The fake ** cursor returned must not be used with any other Btree interface. */ SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){ static u8 fakeCursor = CURSOR_VALID; assert( offsetof(BtCursor, eState)==0 ); return (BtCursor*)&fakeCursor; } /* ** This routine restores a cursor back to its original position after it ** has been moved by some outside activity (such as a btree rebalance or ** a row having been deleted out from under the cursor). ** ** On success, the *pDifferentRow parameter is false if the cursor is left ** pointing at exactly the same row. *pDifferntRow is the row the cursor ** was pointing to has been deleted, forcing the cursor to point to some ** nearby row. ** ** This routine should only be called for a cursor that just returned ** TRUE from sqlite3BtreeCursorHasMoved(). */ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){ int rc; assert( pCur!=0 ); assert( pCur->eState!=CURSOR_VALID ); rc = restoreCursorPosition(pCur); if( rc ){ *pDifferentRow = 1; return rc; } if( pCur->eState!=CURSOR_VALID ){ *pDifferentRow = 1; }else{ *pDifferentRow = 0; } return SQLITE_OK; } #ifdef SQLITE_ENABLE_CURSOR_HINTS /* ** Provide hints to the cursor. The particular hint given (and the type ** and number of the varargs parameters) is determined by the eHintType ** parameter. See the definitions of the BTREE_HINT_* macros for details. */ SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){ /* Used only by system that substitute their own storage engine */ #ifdef SQLITE_DEBUG if( ALWAYS(eHintType==BTREE_HINT_RANGE) ){ va_list ap; Expr *pExpr; Walker w; memset(&w, 0, sizeof(w)); w.xExprCallback = sqlite3CursorRangeHintExprCheck; va_start(ap, eHintType); pExpr = va_arg(ap, Expr*); w.u.aMem = va_arg(ap, Mem*); va_end(ap); assert( pExpr!=0 ); assert( w.u.aMem!=0 ); sqlite3WalkExpr(&w, pExpr); } #endif /* SQLITE_DEBUG */ } #endif /* SQLITE_ENABLE_CURSOR_HINTS */ /* ** Provide flag hints to the cursor. */ SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){ assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 ); pCur->hints = x; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Given a page number of a regular database page, return the page ** number for the pointer-map page that contains the entry for the ** input page number. ** ** Return 0 (not a valid page) for pgno==1 since there is ** no pointer map associated with page 1. The integrity_check logic ** requires that ptrmapPageno(*,1)!=1. */ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){ int nPagesPerMapPage; Pgno iPtrMap, ret; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno<2 ) return 0; nPagesPerMapPage = (pBt->usableSize/5)+1; iPtrMap = (pgno-2)/nPagesPerMapPage; ret = (iPtrMap*nPagesPerMapPage) + 2; if( ret==PENDING_BYTE_PAGE(pBt) ){ ret++; } return ret; } /* ** Write an entry into the pointer map. ** ** This routine updates the pointer map entry for page number 'key' ** so that it maps to type 'eType' and parent page number 'pgno'. ** ** If *pRC is initially non-zero (non-SQLITE_OK) then this routine is ** a no-op. If an error occurs, the appropriate error code is written ** into *pRC. */ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ DbPage *pDbPage; /* The pointer map page */ u8 *pPtrmap; /* The pointer map data */ Pgno iPtrmap; /* The pointer map page number */ int offset; /* Offset in pointer map page */ int rc; /* Return code from subfunctions */ if( *pRC ) return; assert( sqlite3_mutex_held(pBt->mutex) ); /* The super-journal page number must never be used as a pointer map page */ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); assert( pBt->autoVacuum ); if( key==0 ){ *pRC = SQLITE_CORRUPT_BKPT; return; } iPtrmap = PTRMAP_PAGENO(pBt, key); rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0); if( rc!=SQLITE_OK ){ *pRC = rc; return; } if( ((char*)sqlite3PagerGetExtra(pDbPage))[0]!=0 ){ /* The first byte of the extra data is the MemPage.isInit byte. ** If that byte is set, it means this page is also being used ** as a btree page. */ *pRC = SQLITE_CORRUPT_BKPT; goto ptrmap_exit; } offset = PTRMAP_PTROFFSET(iPtrmap, key); if( offset<0 ){ *pRC = SQLITE_CORRUPT_BKPT; goto ptrmap_exit; } assert( offset <= (int)pBt->usableSize-5 ); pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){ TRACE(("PTRMAP_UPDATE: %u->(%u,%u)\n", key, eType, parent)); *pRC= rc = sqlite3PagerWrite(pDbPage); if( rc==SQLITE_OK ){ pPtrmap[offset] = eType; put4byte(&pPtrmap[offset+1], parent); } } ptrmap_exit: sqlite3PagerUnref(pDbPage); } /* ** Read an entry from the pointer map. ** ** This routine retrieves the pointer map entry for page 'key', writing ** the type and parent page number to *pEType and *pPgno respectively. ** An error code is returned if something goes wrong, otherwise SQLITE_OK. */ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ DbPage *pDbPage; /* The pointer map page */ int iPtrmap; /* Pointer map page index */ u8 *pPtrmap; /* Pointer map page data */ int offset; /* Offset of entry in pointer map */ int rc; assert( sqlite3_mutex_held(pBt->mutex) ); iPtrmap = PTRMAP_PAGENO(pBt, key); rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0); if( rc!=0 ){ return rc; } pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); offset = PTRMAP_PTROFFSET(iPtrmap, key); if( offset<0 ){ sqlite3PagerUnref(pDbPage); return SQLITE_CORRUPT_BKPT; } assert( offset <= (int)pBt->usableSize-5 ); assert( pEType!=0 ); *pEType = pPtrmap[offset]; if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); sqlite3PagerUnref(pDbPage); if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); return SQLITE_OK; } #else /* if defined SQLITE_OMIT_AUTOVACUUM */ #define ptrmapPut(w,x,y,z,rc) #define ptrmapGet(w,x,y,z) SQLITE_OK #define ptrmapPutOvflPtr(x, y, z, rc) #endif /* ** Given a btree page and a cell index (0 means the first cell on ** the page, 1 means the second cell, and so forth) return a pointer ** to the cell content. ** ** findCellPastPtr() does the same except it skips past the initial ** 4-byte child pointer found on interior pages, if there is one. ** ** This routine works only for pages that do not contain overflow cells. */ #define findCell(P,I) \ ((P)->aData + ((P)->maskPage & get2byteAligned(&(P)->aCellIdx[2*(I)]))) #define findCellPastPtr(P,I) \ ((P)->aDataOfst + ((P)->maskPage & get2byteAligned(&(P)->aCellIdx[2*(I)]))) /* ** This is common tail processing for btreeParseCellPtr() and ** btreeParseCellPtrIndex() for the case when the cell does not fit entirely ** on a single B-tree page. Make necessary adjustments to the CellInfo ** structure. */ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow( MemPage *pPage, /* Page containing the cell */ u8 *pCell, /* Pointer to the cell text. */ CellInfo *pInfo /* Fill in this structure */ ){ /* If the payload will not fit completely on the local page, we have ** to decide how much to store locally and how much to spill onto ** overflow pages. The strategy is to minimize the amount of unused ** space on overflow pages while keeping the amount of local storage ** in between minLocal and maxLocal. ** ** Warning: changing the way overflow payload is distributed in any ** way will result in an incompatible file format. */ int minLocal; /* Minimum amount of payload held locally */ int maxLocal; /* Maximum amount of payload held locally */ int surplus; /* Overflow payload available for local storage */ minLocal = pPage->minLocal; maxLocal = pPage->maxLocal; surplus = minLocal + (pInfo->nPayload - minLocal)%(pPage->pBt->usableSize-4); testcase( surplus==maxLocal ); testcase( surplus==maxLocal+1 ); if( surplus <= maxLocal ){ pInfo->nLocal = (u16)surplus; }else{ pInfo->nLocal = (u16)minLocal; } pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4; } /* ** Given a record with nPayload bytes of payload stored within btree ** page pPage, return the number of bytes of payload stored locally. */ static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){ int maxLocal; /* Maximum amount of payload held locally */ maxLocal = pPage->maxLocal; if( nPayload<=maxLocal ){ return nPayload; }else{ int minLocal; /* Minimum amount of payload held locally */ int surplus; /* Overflow payload available for local storage */ minLocal = pPage->minLocal; surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4); return ( surplus <= maxLocal ) ? surplus : minLocal; } } /* ** The following routines are implementations of the MemPage.xParseCell() ** method. ** ** Parse a cell content block and fill in the CellInfo structure. ** ** btreeParseCellPtr() => table btree leaf nodes ** btreeParseCellNoPayload() => table btree internal nodes ** btreeParseCellPtrIndex() => index btree nodes ** ** There is also a wrapper function btreeParseCell() that works for ** all MemPage types and that references the cell by index rather than ** by pointer. */ static void btreeParseCellPtrNoPayload( MemPage *pPage, /* Page containing the cell */ u8 *pCell, /* Pointer to the cell text. */ CellInfo *pInfo /* Fill in this structure */ ){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->leaf==0 ); assert( pPage->childPtrSize==4 ); #ifndef SQLITE_DEBUG UNUSED_PARAMETER(pPage); #endif pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey); pInfo->nPayload = 0; pInfo->nLocal = 0; pInfo->pPayload = 0; return; } static void btreeParseCellPtr( MemPage *pPage, /* Page containing the cell */ u8 *pCell, /* Pointer to the cell text. */ CellInfo *pInfo /* Fill in this structure */ ){ u8 *pIter; /* For scanning through pCell */ u32 nPayload; /* Number of bytes of cell payload */ u64 iKey; /* Extracted Key value */ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->leaf==0 || pPage->leaf==1 ); assert( pPage->intKeyLeaf ); assert( pPage->childPtrSize==0 ); pIter = pCell; /* The next block of code is equivalent to: ** ** pIter += getVarint32(pIter, nPayload); ** ** The code is inlined to avoid a function call. */ nPayload = *pIter; if( nPayload>=0x80 ){ u8 *pEnd = &pIter[8]; nPayload &= 0x7f; do{ nPayload = (nPayload<<7) | (*++pIter & 0x7f); }while( (*pIter)>=0x80 && pIternKey); ** ** The code is inlined and the loop is unrolled for performance. ** This routine is a high-runner. */ iKey = *pIter; if( iKey>=0x80 ){ u8 x; iKey = (iKey<<7) ^ (x = *++pIter); if( x>=0x80 ){ iKey = (iKey<<7) ^ (x = *++pIter); if( x>=0x80 ){ iKey = (iKey<<7) ^ 0x10204000 ^ (x = *++pIter); if( x>=0x80 ){ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter); if( x>=0x80 ){ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter); if( x>=0x80 ){ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter); if( x>=0x80 ){ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter); if( x>=0x80 ){ iKey = (iKey<<8) ^ 0x8000 ^ (*++pIter); } } } } } }else{ iKey ^= 0x204000; } }else{ iKey ^= 0x4000; } } pIter++; pInfo->nKey = *(i64*)&iKey; pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==(u32)pPage->maxLocal+1 ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ pInfo->nSize = nPayload + (u16)(pIter - pCell); if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; }else{ btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo); } } static void btreeParseCellPtrIndex( MemPage *pPage, /* Page containing the cell */ u8 *pCell, /* Pointer to the cell text. */ CellInfo *pInfo /* Fill in this structure */ ){ u8 *pIter; /* For scanning through pCell */ u32 nPayload; /* Number of bytes of cell payload */ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->leaf==0 || pPage->leaf==1 ); assert( pPage->intKeyLeaf==0 ); pIter = pCell + pPage->childPtrSize; nPayload = *pIter; if( nPayload>=0x80 ){ u8 *pEnd = &pIter[8]; nPayload &= 0x7f; do{ nPayload = (nPayload<<7) | (*++pIter & 0x7f); }while( *(pIter)>=0x80 && pIternKey = nPayload; pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==(u32)pPage->maxLocal+1 ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ pInfo->nSize = nPayload + (u16)(pIter - pCell); if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; }else{ btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo); } } static void btreeParseCell( MemPage *pPage, /* Page containing the cell */ int iCell, /* The cell index. First cell is 0 */ CellInfo *pInfo /* Fill in this structure */ ){ pPage->xParseCell(pPage, findCell(pPage, iCell), pInfo); } /* ** The following routines are implementations of the MemPage.xCellSize ** method. ** ** Compute the total number of bytes that a Cell needs in the cell ** data area of the btree-page. The return number includes the cell ** data header and the local payload, but not any overflow page or ** the space used by the cell pointer. ** ** cellSizePtrNoPayload() => table internal nodes ** cellSizePtrTableLeaf() => table leaf nodes ** cellSizePtr() => index internal nodes ** cellSizeIdxLeaf() => index leaf nodes */ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ u8 *pIter = pCell + 4; /* For looping over bytes of pCell */ u8 *pEnd; /* End mark for a varint */ u32 nSize; /* Size value to return */ #ifdef SQLITE_DEBUG /* The value returned by this function should always be the same as ** the (CellInfo.nSize) value found by doing a full parse of the ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of ** this function verifies that this invariant is not violated. */ CellInfo debuginfo; pPage->xParseCell(pPage, pCell, &debuginfo); #endif assert( pPage->childPtrSize==4 ); nSize = *pIter; if( nSize>=0x80 ){ pEnd = &pIter[8]; nSize &= 0x7f; do{ nSize = (nSize<<7) | (*++pIter & 0x7f); }while( *(pIter)>=0x80 && pItermaxLocal ); testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize<=pPage->maxLocal ){ nSize += (u32)(pIter - pCell); assert( nSize>4 ); }else{ int minLocal = pPage->minLocal; nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); testcase( nSize==pPage->maxLocal ); testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize>pPage->maxLocal ){ nSize = minLocal; } nSize += 4 + (u16)(pIter - pCell); } assert( nSize==debuginfo.nSize || CORRUPT_DB ); return (u16)nSize; } static u16 cellSizePtrIdxLeaf(MemPage *pPage, u8 *pCell){ u8 *pIter = pCell; /* For looping over bytes of pCell */ u8 *pEnd; /* End mark for a varint */ u32 nSize; /* Size value to return */ #ifdef SQLITE_DEBUG /* The value returned by this function should always be the same as ** the (CellInfo.nSize) value found by doing a full parse of the ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of ** this function verifies that this invariant is not violated. */ CellInfo debuginfo; pPage->xParseCell(pPage, pCell, &debuginfo); #endif assert( pPage->childPtrSize==0 ); nSize = *pIter; if( nSize>=0x80 ){ pEnd = &pIter[8]; nSize &= 0x7f; do{ nSize = (nSize<<7) | (*++pIter & 0x7f); }while( *(pIter)>=0x80 && pItermaxLocal ); testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize<=pPage->maxLocal ){ nSize += (u32)(pIter - pCell); if( nSize<4 ) nSize = 4; }else{ int minLocal = pPage->minLocal; nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); testcase( nSize==pPage->maxLocal ); testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize>pPage->maxLocal ){ nSize = minLocal; } nSize += 4 + (u16)(pIter - pCell); } assert( nSize==debuginfo.nSize || CORRUPT_DB ); return (u16)nSize; } static u16 cellSizePtrNoPayload(MemPage *pPage, u8 *pCell){ u8 *pIter = pCell + 4; /* For looping over bytes of pCell */ u8 *pEnd; /* End mark for a varint */ #ifdef SQLITE_DEBUG /* The value returned by this function should always be the same as ** the (CellInfo.nSize) value found by doing a full parse of the ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of ** this function verifies that this invariant is not violated. */ CellInfo debuginfo; pPage->xParseCell(pPage, pCell, &debuginfo); #else UNUSED_PARAMETER(pPage); #endif assert( pPage->childPtrSize==4 ); pEnd = pIter + 9; while( (*pIter++)&0x80 && pIterxParseCell(pPage, pCell, &debuginfo); #endif nSize = *pIter; if( nSize>=0x80 ){ pEnd = &pIter[8]; nSize &= 0x7f; do{ nSize = (nSize<<7) | (*++pIter & 0x7f); }while( *(pIter)>=0x80 && pItermaxLocal ); testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize<=pPage->maxLocal ){ nSize += (u32)(pIter - pCell); if( nSize<4 ) nSize = 4; }else{ int minLocal = pPage->minLocal; nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); testcase( nSize==pPage->maxLocal ); testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize>pPage->maxLocal ){ nSize = minLocal; } nSize += 4 + (u16)(pIter - pCell); } assert( nSize==debuginfo.nSize || CORRUPT_DB ); return (u16)nSize; } #ifdef SQLITE_DEBUG /* This variation on cellSizePtr() is used inside of assert() statements ** only. */ static u16 cellSize(MemPage *pPage, int iCell){ return pPage->xCellSize(pPage, findCell(pPage, iCell)); } #endif #ifndef SQLITE_OMIT_AUTOVACUUM /* ** The cell pCell is currently part of page pSrc but will ultimately be part ** of pPage. (pSrc and pPage are often the same.) If pCell contains a ** pointer to an overflow page, insert an entry into the pointer-map for ** the overflow page that will be valid after pCell has been moved to pPage. */ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ CellInfo info; if( *pRC ) return; assert( pCell!=0 ); pPage->xParseCell(pPage, pCell, &info); if( info.nLocalaDataEnd, pCell, pCell+info.nLocal) ){ testcase( pSrc!=pPage ); *pRC = SQLITE_CORRUPT_BKPT; return; } ovfl = get4byte(&pCell[info.nSize-4]); ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC); } } #endif /* ** Defragment the page given. This routine reorganizes cells within the ** page so that there are no free-blocks on the free-block list. ** ** Parameter nMaxFrag is the maximum amount of fragmented space that may be ** present in the page after this routine returns. ** ** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a ** b-tree page so that there are no freeblocks or fragment bytes, all ** unused bytes are contained in the unallocated space region, and all ** cells are packed tightly at the end of the page. */ static int defragmentPage(MemPage *pPage, int nMaxFrag){ int i; /* Loop counter */ int pc; /* Address of the i-th cell */ int hdr; /* Offset to the page header */ int size; /* Size of a cell */ int usableSize; /* Number of usable bytes on a page */ int cellOffset; /* Offset to the cell pointer array */ int cbrk; /* Offset to the cell content area */ int nCell; /* Number of cells on the page */ unsigned char *data; /* The page data */ unsigned char *temp; /* Temp area for cell content */ unsigned char *src; /* Source of content */ int iCellFirst; /* First allowable cell index */ int iCellLast; /* Last possible cell index */ int iCellStart; /* First cell offset in input */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt!=0 ); assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); assert( pPage->nOverflow==0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); data = pPage->aData; hdr = pPage->hdrOffset; cellOffset = pPage->cellOffset; nCell = pPage->nCell; assert( nCell==get2byte(&data[hdr+3]) || CORRUPT_DB ); iCellFirst = cellOffset + 2*nCell; usableSize = pPage->pBt->usableSize; /* This block handles pages with two or fewer free blocks and nMaxFrag ** or fewer fragmented bytes. In this case it is faster to move the ** two (or one) blocks of cells using memmove() and add the required ** offsets to each pointer in the cell-pointer array than it is to ** reconstruct the entire page. */ if( (int)data[hdr+7]<=nMaxFrag ){ int iFree = get2byte(&data[hdr+1]); if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); if( iFree ){ int iFree2 = get2byte(&data[iFree]); if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ u8 *pEnd = &data[cellOffset + nCell*2]; u8 *pAddr; int sz2 = 0; int sz = get2byte(&data[iFree+2]); int top = get2byte(&data[hdr+5]); if( top>=iFree ){ return SQLITE_CORRUPT_PAGE(pPage); } if( iFree2 ){ if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage); sz2 = get2byte(&data[iFree2+2]); if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); sz += sz2; }else if( iFree+sz>usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } cbrk = top+sz; assert( cbrk+(iFree-top) <= usableSize ); memmove(&data[cbrk], &data[top], iFree-top); for(pAddr=&data[cellOffset]; pAddr0 ){ temp = sqlite3PagerTempSpace(pPage->pBt->pPager); memcpy(temp, data, usableSize); src = temp; for(i=0; iiCellLast ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( pc>=0 && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; if( cbrkusableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( cbrk+size<=usableSize && cbrk>=iCellStart ); testcase( cbrk+size==usableSize ); testcase( pc+size==usableSize ); put2byte(pAddr, cbrk); memcpy(&data[cbrk], &src[pc], size); } } data[hdr+7] = 0; defragment_out: assert( pPage->nFree>=0 ); if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); data[hdr+1] = 0; data[hdr+2] = 0; memset(&data[iCellFirst], 0, cbrk-iCellFirst); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); return SQLITE_OK; } /* ** Search the free-list on page pPg for space to store a cell nByte bytes in ** size. If one can be found, return a pointer to the space and remove it ** from the free-list. ** ** If no suitable space can be found on the free-list, return NULL. ** ** This function may detect corruption within pPg. If corruption is ** detected then *pRc is set to SQLITE_CORRUPT and NULL is returned. ** ** Slots on the free list that are between 1 and 3 bytes larger than nByte ** will be ignored if adding the extra space to the fragmentation count ** causes the fragmentation count to exceed 60. */ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ const int hdr = pPg->hdrOffset; /* Offset to page header */ u8 * const aData = pPg->aData; /* Page data */ int iAddr = hdr + 1; /* Address of ptr to pc */ u8 *pTmp = &aData[iAddr]; /* Temporary ptr into aData[] */ int pc = get2byte(pTmp); /* Address of a free slot */ int x; /* Excess size of the slot */ int maxPC = pPg->pBt->usableSize - nByte; /* Max address for a usable slot */ int size; /* Size of the free slot */ assert( pc>0 ); while( pc<=maxPC ){ /* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each ** freeblock form a big-endian integer which is the size of the freeblock ** in bytes, including the 4-byte header. */ pTmp = &aData[pc+2]; size = get2byte(pTmp); if( (x = size - nByte)>=0 ){ testcase( x==4 ); testcase( x==3 ); if( x<4 ){ /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total ** number of bytes in fragments may not exceed 60. */ if( aData[hdr+7]>57 ) return 0; /* Remove the slot from the free-list. Update the number of ** fragmented bytes within the page. */ memcpy(&aData[iAddr], &aData[pc], 2); aData[hdr+7] += (u8)x; return &aData[pc]; }else if( x+pc > maxPC ){ /* This slot extends off the end of the usable part of the page */ *pRc = SQLITE_CORRUPT_PAGE(pPg); return 0; }else{ /* The slot remains on the free-list. Reduce its size to account ** for the portion used by the new allocation. */ put2byte(&aData[pc+2], x); } return &aData[pc + x]; } iAddr = pc; pTmp = &aData[pc]; pc = get2byte(pTmp); if( pc<=iAddr ){ if( pc ){ /* The next slot in the chain comes before the current slot */ *pRc = SQLITE_CORRUPT_PAGE(pPg); } return 0; } } if( pc>maxPC+nByte-4 ){ /* The free slot chain extends off the end of the page */ *pRc = SQLITE_CORRUPT_PAGE(pPg); } return 0; } /* ** Allocate nByte bytes of space from within the B-Tree page passed ** as the first argument. Write into *pIdx the index into pPage->aData[] ** of the first byte of allocated space. Return either SQLITE_OK or ** an error code (usually SQLITE_CORRUPT). ** ** The caller guarantees that there is sufficient space to make the ** allocation. This routine might need to defragment in order to bring ** all the space together, however. This routine will avoid using ** the first two bytes past the cell pointer area since presumably this ** allocation is being made in order to insert a new cell, so we will ** also end up needing a new cell pointer. */ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */ u8 * const data = pPage->aData; /* Local cache of pPage->aData */ int top; /* First byte of cell content area */ int rc = SQLITE_OK; /* Integer return code */ u8 *pTmp; /* Temp ptr into data[] */ int gap; /* First byte of gap between cell pointers and cell content */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( nByte>=0 ); /* Minimum cell size is 4 */ assert( pPage->nFree>=nByte ); assert( pPage->nOverflow==0 ); assert( nByte < (int)(pPage->pBt->usableSize-8) ); assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf ); gap = pPage->cellOffset + 2*pPage->nCell; assert( gap<=65536 ); /* EVIDENCE-OF: R-29356-02391 If the database uses a 65536-byte page size ** and the reserved space is zero (the usual value for reserved space) ** then the cell content offset of an empty page wants to be 65536. ** However, that integer is too large to be stored in a 2-byte unsigned ** integer, so a value of 0 is used in its place. */ pTmp = &data[hdr+5]; top = get2byte(pTmp); if( gap>top ){ if( top==0 && pPage->pBt->usableSize==65536 ){ top = 65536; }else{ return SQLITE_CORRUPT_PAGE(pPage); } }else if( top>(int)pPage->pBt->usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } /* If there is enough space between gap and top for one more cell pointer, ** and if the freelist is not empty, then search the ** freelist looking for a slot big enough to satisfy the request. */ testcase( gap+2==top ); testcase( gap+1==top ); testcase( gap==top ); if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){ u8 *pSpace = pageFindSlot(pPage, nByte, &rc); if( pSpace ){ int g2; assert( pSpace+nByte<=data+pPage->pBt->usableSize ); *pIdx = g2 = (int)(pSpace-data); if( g2<=gap ){ return SQLITE_CORRUPT_PAGE(pPage); }else{ return SQLITE_OK; } }else if( rc ){ return rc; } } /* The request could not be fulfilled using a freelist slot. Check ** to see if defragmentation is necessary. */ testcase( gap+2+nByte==top ); if( gap+2+nByte>top ){ assert( pPage->nCell>0 || CORRUPT_DB ); assert( pPage->nFree>=0 ); rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte))); if( rc ) return rc; top = get2byteNotZero(&data[hdr+5]); assert( gap+2+nByte<=top ); } /* Allocate memory from the gap in between the cell pointer array ** and the cell content area. The btreeComputeFreeSpace() call has already ** validated the freelist. Given that the freelist is valid, there ** is no way that the allocation can extend off the end of the page. ** The assert() below verifies the previous sentence. */ top -= nByte; put2byte(&data[hdr+5], top); assert( top+nByte <= (int)pPage->pBt->usableSize ); *pIdx = top; return SQLITE_OK; } /* ** Return a section of the pPage->aData to the freelist. ** The first byte of the new free block is pPage->aData[iStart] ** and the size of the block is iSize bytes. ** ** Adjacent freeblocks are coalesced. ** ** Even though the freeblock list was checked by btreeComputeFreeSpace(), ** that routine will not detect overlap between cells or freeblocks. Nor ** does it detect cells or freeblocks that encroach into the reserved bytes ** at the end of the page. So do additional corruption checks inside this ** routine and return SQLITE_CORRUPT if any problems are found. */ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ u16 iPtr; /* Address of ptr to next freeblock */ u16 iFreeBlk; /* Address of the next freeblock */ u8 hdr; /* Page header size. 0 or 100 */ u8 nFrag = 0; /* Reduction in fragmentation */ u16 iOrigSize = iSize; /* Original value of iSize */ u16 x; /* Offset to cell content area */ u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ unsigned char *data = pPage->aData; /* Page content */ u8 *pTmp; /* Temporary ptr into data[] */ assert( pPage->pBt!=0 ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( CORRUPT_DB || iStart>=pPage->hdrOffset+6+pPage->childPtrSize ); assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( iSize>=4 ); /* Minimum cell size is 4 */ assert( CORRUPT_DB || iStart<=pPage->pBt->usableSize-4 ); /* The list of freeblocks must be in ascending order. Find the ** spot on the list where iStart should be inserted. */ hdr = pPage->hdrOffset; iPtr = hdr + 1; if( data[iPtr+1]==0 && data[iPtr]==0 ){ iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */ }else{ while( (iFreeBlk = get2byte(&data[iPtr]))pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ return SQLITE_CORRUPT_PAGE(pPage); } assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); /* At this point: ** iFreeBlk: First freeblock after iStart, or zero if none ** iPtr: The address of a pointer to iFreeBlk ** ** Check to see if iFreeBlk should be coalesced onto the end of iStart. */ if( iFreeBlk && iEnd+3>=iFreeBlk ){ nFrag = iFreeBlk - iEnd; if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); if( iEnd > pPage->pBt->usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } iSize = iEnd - iStart; iFreeBlk = get2byte(&data[iFreeBlk]); } /* If iPtr is another freeblock (that is, if iPtr is not the freelist ** pointer in the page header) then check to see if iStart should be ** coalesced onto the end of iPtr. */ if( iPtr>hdr+1 ){ int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); if( iPtrEnd+3>=iStart ){ if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage); nFrag += iStart - iPtrEnd; iSize = iEnd - iPtr; iStart = iPtr; } } if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); data[hdr+7] -= nFrag; } pTmp = &data[hdr+5]; x = get2byte(pTmp); if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){ /* Overwrite deleted information with zeros when the secure_delete ** option is enabled */ memset(&data[iStart], 0, iSize); } if( iStart<=x ){ /* The new freeblock is at the beginning of the cell content area, ** so just extend the cell content area rather than create another ** freelist entry */ if( iStartnFree += iOrigSize; return SQLITE_OK; } /* ** Decode the flags byte (the first byte of the header) for a page ** and initialize fields of the MemPage structure accordingly. ** ** Only the following combinations are supported. Anything different ** indicates a corrupt database files: ** ** PTF_ZERODATA (0x02, 2) ** PTF_LEAFDATA | PTF_INTKEY (0x05, 5) ** PTF_ZERODATA | PTF_LEAF (0x0a, 10) ** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF (0x0d, 13) */ static int decodeFlags(MemPage *pPage, int flagByte){ BtShared *pBt; /* A copy of pPage->pBt */ assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pBt = pPage->pBt; pPage->max1bytePayload = pBt->max1bytePayload; if( flagByte>=(PTF_ZERODATA | PTF_LEAF) ){ pPage->childPtrSize = 0; pPage->leaf = 1; if( flagByte==(PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF) ){ pPage->intKeyLeaf = 1; pPage->xCellSize = cellSizePtrTableLeaf; pPage->xParseCell = btreeParseCellPtr; pPage->intKey = 1; pPage->maxLocal = pBt->maxLeaf; pPage->minLocal = pBt->minLeaf; }else if( flagByte==(PTF_ZERODATA | PTF_LEAF) ){ pPage->intKey = 0; pPage->intKeyLeaf = 0; pPage->xCellSize = cellSizePtrIdxLeaf; pPage->xParseCell = btreeParseCellPtrIndex; pPage->maxLocal = pBt->maxLocal; pPage->minLocal = pBt->minLocal; }else{ pPage->intKey = 0; pPage->intKeyLeaf = 0; pPage->xCellSize = cellSizePtrIdxLeaf; pPage->xParseCell = btreeParseCellPtrIndex; return SQLITE_CORRUPT_PAGE(pPage); } }else{ pPage->childPtrSize = 4; pPage->leaf = 0; if( flagByte==(PTF_ZERODATA) ){ pPage->intKey = 0; pPage->intKeyLeaf = 0; pPage->xCellSize = cellSizePtr; pPage->xParseCell = btreeParseCellPtrIndex; pPage->maxLocal = pBt->maxLocal; pPage->minLocal = pBt->minLocal; }else if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){ pPage->intKeyLeaf = 0; pPage->xCellSize = cellSizePtrNoPayload; pPage->xParseCell = btreeParseCellPtrNoPayload; pPage->intKey = 1; pPage->maxLocal = pBt->maxLeaf; pPage->minLocal = pBt->minLeaf; }else{ pPage->intKey = 0; pPage->intKeyLeaf = 0; pPage->xCellSize = cellSizePtr; pPage->xParseCell = btreeParseCellPtrIndex; return SQLITE_CORRUPT_PAGE(pPage); } } return SQLITE_OK; } /* ** Compute the amount of freespace on the page. In other words, fill ** in the pPage->nFree field. */ static int btreeComputeFreeSpace(MemPage *pPage){ int pc; /* Address of a freeblock within pPage->aData[] */ u8 hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ int usableSize; /* Amount of usable space on each page */ int nFree; /* Number of unused bytes on the page */ int top; /* First byte of the cell content area */ int iCellFirst; /* First allowable cell or freeblock offset */ int iCellLast; /* Last possible cell or freeblock offset */ assert( pPage->pBt!=0 ); assert( pPage->pBt->db!=0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); assert( pPage->isInit==1 ); assert( pPage->nFree<0 ); usableSize = pPage->pBt->usableSize; hdr = pPage->hdrOffset; data = pPage->aData; /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates ** the start of the cell content area. A zero value for this integer is ** interpreted as 65536. */ top = get2byteNotZero(&data[hdr+5]); iCellFirst = hdr + 8 + pPage->childPtrSize + 2*pPage->nCell; iCellLast = usableSize - 4; /* Compute the total free space on the page ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the ** start of the first freeblock on the page, or is zero if there are no ** freeblocks. */ pc = get2byte(&data[hdr+1]); nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */ if( pc>0 ){ u32 next, size; if( pciCellLast ){ /* Freeblock off the end of the page */ return SQLITE_CORRUPT_PAGE(pPage); } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); nFree = nFree + size; if( next<=pc+size+3 ) break; pc = next; } if( next>0 ){ /* Freeblock not in ascending order */ return SQLITE_CORRUPT_PAGE(pPage); } if( pc+size>(unsigned int)usableSize ){ /* Last freeblock extends past page end */ return SQLITE_CORRUPT_PAGE(pPage); } } /* At this point, nFree contains the sum of the offset to the start ** of the cell-content area plus the number of free bytes within ** the cell-content area. If this is greater than the usable-size ** of the page, then the page must be corrupted. This check also ** serves to verify that the offset to the start of the cell-content ** area, according to the page header, lies within the page. */ if( nFree>usableSize || nFreenFree = (u16)(nFree - iCellFirst); return SQLITE_OK; } /* ** Do additional sanity check after btreeInitPage() if ** PRAGMA cell_size_check=ON */ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ int iCellFirst; /* First allowable cell or freeblock offset */ int iCellLast; /* Last possible cell or freeblock offset */ int i; /* Index into the cell pointer array */ int sz; /* Size of a cell */ int pc; /* Address of a freeblock within pPage->aData[] */ u8 *data; /* Equal to pPage->aData */ int usableSize; /* Maximum usable space on the page */ int cellOffset; /* Start of cell content area */ iCellFirst = pPage->cellOffset + 2*pPage->nCell; usableSize = pPage->pBt->usableSize; iCellLast = usableSize - 4; data = pPage->aData; cellOffset = pPage->cellOffset; if( !pPage->leaf ) iCellLast--; for(i=0; inCell; i++){ pc = get2byteAligned(&data[cellOffset+i*2]); testcase( pc==iCellFirst ); testcase( pc==iCellLast ); if( pciCellLast ){ return SQLITE_CORRUPT_PAGE(pPage); } sz = pPage->xCellSize(pPage, &data[pc]); testcase( pc+sz==usableSize ); if( pc+sz>usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } } return SQLITE_OK; } /* ** Initialize the auxiliary information for a disk block. ** ** Return SQLITE_OK on success. If we see that the page does ** not contain a well-formed database page, then return ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not ** guarantee that the page is well-formed. It only shows that ** we failed to detect any corruption. */ static int btreeInitPage(MemPage *pPage){ u8 *data; /* Equal to pPage->aData */ BtShared *pBt; /* The main btree structure */ assert( pPage->pBt!=0 ); assert( pPage->pBt->db!=0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); assert( pPage->isInit==0 ); pBt = pPage->pBt; data = pPage->aData + pPage->hdrOffset; /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating ** the b-tree page type. */ if( decodeFlags(pPage, data[0]) ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); pPage->nOverflow = 0; pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize; pPage->aCellIdx = data + pPage->childPtrSize + 8; pPage->aDataEnd = pPage->aData + pBt->pageSize; pPage->aDataOfst = pPage->aData + pPage->childPtrSize; /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the ** number of cells on the page. */ pPage->nCell = get2byte(&data[3]); if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ return SQLITE_CORRUPT_PAGE(pPage); } testcase( pPage->nCell==MX_CELL(pBt) ); /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only ** possible for a root page of a table that contains no rows) then the ** offset to the cell content area will equal the page size minus the ** bytes of reserved space. */ assert( pPage->nCell>0 || get2byteNotZero(&data[5])==(int)pBt->usableSize || CORRUPT_DB ); pPage->nFree = -1; /* Indicate that this value is yet uncomputed */ pPage->isInit = 1; if( pBt->db->flags & SQLITE_CellSizeCk ){ return btreeCellSizeCheck(pPage); } return SQLITE_OK; } /* ** Set up a raw page so that it looks like a database page holding ** no entries. */ static void zeroPage(MemPage *pPage, int flags){ unsigned char *data = pPage->aData; BtShared *pBt = pPage->pBt; u8 hdr = pPage->hdrOffset; u16 first; assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno || CORRUPT_DB ); assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); assert( sqlite3PagerGetData(pPage->pDbPage) == data ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pBt->mutex) ); if( pBt->btsFlags & BTS_FAST_SECURE ){ memset(&data[hdr], 0, pBt->usableSize - hdr); } data[hdr] = (char)flags; first = hdr + ((flags&PTF_LEAF)==0 ? 12 : 8); memset(&data[hdr+1], 0, 4); data[hdr+7] = 0; put2byte(&data[hdr+5], pBt->usableSize); pPage->nFree = (u16)(pBt->usableSize - first); decodeFlags(pPage, flags); pPage->cellOffset = first; pPage->aDataEnd = &data[pBt->pageSize]; pPage->aCellIdx = &data[first]; pPage->aDataOfst = &data[pPage->childPtrSize]; pPage->nOverflow = 0; assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); pPage->nCell = 0; pPage->isInit = 1; } /* ** Convert a DbPage obtained from the pager into a MemPage used by ** the btree layer. */ static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){ MemPage *pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); if( pgno!=pPage->pgno ){ pPage->aData = sqlite3PagerGetData(pDbPage); pPage->pDbPage = pDbPage; pPage->pBt = pBt; pPage->pgno = pgno; pPage->hdrOffset = pgno==1 ? 100 : 0; } assert( pPage->aData==sqlite3PagerGetData(pDbPage) ); return pPage; } /* ** Get a page from the pager. Initialize the MemPage.pBt and ** MemPage.aData elements if needed. See also: btreeGetUnusedPage(). ** ** If the PAGER_GET_NOCONTENT flag is set, it means that we do not care ** about the content of the page at this time. So do not go to the disk ** to fetch the content. Just fill in the content with zeros for now. ** If in the future we call sqlite3PagerWrite() on this page, that ** means we have started to be concerned about content and the disk ** read should occur at that point. */ static int btreeGetPage( BtShared *pBt, /* The btree */ Pgno pgno, /* Number of the page to fetch */ MemPage **ppPage, /* Return the page in this parameter */ int flags /* PAGER_GET_NOCONTENT or PAGER_GET_READONLY */ ){ int rc; DbPage *pDbPage; assert( flags==0 || flags==PAGER_GET_NOCONTENT || flags==PAGER_GET_READONLY ); assert( sqlite3_mutex_held(pBt->mutex) ); rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, flags); if( rc ) return rc; *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt); return SQLITE_OK; } /* ** Retrieve a page from the pager cache. If the requested page is not ** already in the pager cache return NULL. Initialize the MemPage.pBt and ** MemPage.aData elements if needed. */ static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){ DbPage *pDbPage; assert( sqlite3_mutex_held(pBt->mutex) ); pDbPage = sqlite3PagerLookup(pBt->pPager, pgno); if( pDbPage ){ return btreePageFromDbPage(pDbPage, pgno, pBt); } return 0; } /* ** Return the size of the database file in pages. If there is any kind of ** error, return ((unsigned int)-1). */ static Pgno btreePagecount(BtShared *pBt){ return pBt->nPage; } SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree *p){ assert( sqlite3BtreeHoldsMutex(p) ); return btreePagecount(p->pBt); } /* ** Get a page from the pager and initialize it. */ static int getAndInitPage( BtShared *pBt, /* The database file */ Pgno pgno, /* Number of the page to get */ MemPage **ppPage, /* Write the page pointer here */ int bReadOnly /* True for a read-only page */ ){ int rc; DbPage *pDbPage; MemPage *pPage; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ *ppPage = 0; return SQLITE_CORRUPT_BKPT; } rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); if( rc ){ *ppPage = 0; return rc; } pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); if( pPage->isInit==0 ){ btreePageFromDbPage(pDbPage, pgno, pBt); rc = btreeInitPage(pPage); if( rc!=SQLITE_OK ){ releasePage(pPage); *ppPage = 0; return rc; } } assert( pPage->pgno==pgno || CORRUPT_DB ); assert( pPage->aData==sqlite3PagerGetData(pDbPage) ); *ppPage = pPage; return SQLITE_OK; } /* ** Release a MemPage. This should be called once for each prior ** call to btreeGetPage. ** ** Page1 is a special case and must be released using releasePageOne(). */ static void releasePageNotNull(MemPage *pPage){ assert( pPage->aData ); assert( pPage->pBt ); assert( pPage->pDbPage!=0 ); assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); sqlite3PagerUnrefNotNull(pPage->pDbPage); } static void releasePage(MemPage *pPage){ if( pPage ) releasePageNotNull(pPage); } static void releasePageOne(MemPage *pPage){ assert( pPage!=0 ); assert( pPage->aData ); assert( pPage->pBt ); assert( pPage->pDbPage!=0 ); assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); sqlite3PagerUnrefPageOne(pPage->pDbPage); } /* ** Get an unused page. ** ** This works just like btreeGetPage() with the addition: ** ** * If the page is already in use for some other purpose, immediately ** release it and return an SQLITE_CURRUPT error. ** * Make sure the isInit flag is clear */ static int btreeGetUnusedPage( BtShared *pBt, /* The btree */ Pgno pgno, /* Number of the page to fetch */ MemPage **ppPage, /* Return the page in this parameter */ int flags /* PAGER_GET_NOCONTENT or PAGER_GET_READONLY */ ){ int rc = btreeGetPage(pBt, pgno, ppPage, flags); if( rc==SQLITE_OK ){ if( sqlite3PagerPageRefcount((*ppPage)->pDbPage)>1 ){ releasePage(*ppPage); *ppPage = 0; return SQLITE_CORRUPT_BKPT; } (*ppPage)->isInit = 0; }else{ *ppPage = 0; } return rc; } /* ** During a rollback, when the pager reloads information into the cache ** so that the cache is restored to its original state at the start of ** the transaction, for each page restored this routine is called. ** ** This routine needs to reset the extra data section at the end of the ** page to agree with the restored data. */ static void pageReinit(DbPage *pData){ MemPage *pPage; pPage = (MemPage *)sqlite3PagerGetExtra(pData); assert( sqlite3PagerPageRefcount(pData)>0 ); if( pPage->isInit ){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->isInit = 0; if( sqlite3PagerPageRefcount(pData)>1 ){ /* pPage might not be a btree page; it might be an overflow page ** or ptrmap page or a free page. In those cases, the following ** call to btreeInitPage() will likely return SQLITE_CORRUPT. ** But no harm is done by this. And it is very important that ** btreeInitPage() be called on every btree page so we make ** the call for every page that comes in for re-initializing. */ btreeInitPage(pPage); } } } /* ** Invoke the busy handler for a btree. */ static int btreeInvokeBusyHandler(void *pArg){ BtShared *pBt = (BtShared*)pArg; assert( pBt->db ); assert( sqlite3_mutex_held(pBt->db->mutex) ); return sqlite3InvokeBusyHandler(&pBt->db->busyHandler); } /* ** Open a database file. ** ** zFilename is the name of the database file. If zFilename is NULL ** then an ephemeral database is created. The ephemeral database might ** be exclusively in memory, or it might use a disk-based memory cache. ** Either way, the ephemeral database will be automatically deleted ** when sqlite3BtreeClose() is called. ** ** If zFilename is ":memory:" then an in-memory database is created ** that is automatically destroyed when it is closed. ** ** The "flags" parameter is a bitmask that might contain bits like ** BTREE_OMIT_JOURNAL and/or BTREE_MEMORY. ** ** If the database is already opened in the same database connection ** and we are in shared cache mode, then the open will fail with an ** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared ** objects in the same database connection since doing so will lead ** to problems with locking. */ SQLITE_PRIVATE int sqlite3BtreeOpen( sqlite3_vfs *pVfs, /* VFS to use for this b-tree */ const char *zFilename, /* Name of the file containing the BTree database */ sqlite3 *db, /* Associated database handle */ Btree **ppBtree, /* Pointer to new Btree object written here */ int flags, /* Options */ int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ ){ BtShared *pBt = 0; /* Shared part of btree structure */ Btree *p; /* Handle to return */ sqlite3_mutex *mutexOpen = 0; /* Prevents a race condition. Ticket #3537 */ int rc = SQLITE_OK; /* Result code from this function */ u8 nReserve; /* Byte of unused space on each page */ unsigned char zDbHeader[100]; /* Database header content */ /* True if opening an ephemeral, temporary database */ const int isTempDb = zFilename==0 || zFilename[0]==0; /* Set the variable isMemdb to true for an in-memory database, or ** false for a file-based database. */ #ifdef SQLITE_OMIT_MEMORYDB const int isMemdb = 0; #else const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0) || (isTempDb && sqlite3TempInMemory(db)) || (vfsFlags & SQLITE_OPEN_MEMORY)!=0; #endif assert( db!=0 ); assert( pVfs!=0 ); assert( sqlite3_mutex_held(db->mutex) ); assert( (flags&0xff)==flags ); /* flags fit in 8 bits */ /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */ assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 ); /* A BTREE_SINGLE database is always a temporary and/or ephemeral */ assert( (flags & BTREE_SINGLE)==0 || isTempDb ); if( isMemdb ){ flags |= BTREE_MEMORY; } if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){ vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB; } p = sqlite3MallocZero(sizeof(Btree)); if( !p ){ return SQLITE_NOMEM_BKPT; } p->inTrans = TRANS_NONE; p->db = db; #ifndef SQLITE_OMIT_SHARED_CACHE p->lock.pBtree = p; p->lock.iTable = 1; #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* ** If this Btree is a candidate for shared cache, try to find an ** existing BtShared object that we can share with */ if( isTempDb==0 && (isMemdb==0 || (vfsFlags&SQLITE_OPEN_URI)!=0) ){ if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){ int nFilename = sqlite3Strlen30(zFilename)+1; int nFullPathname = pVfs->mxPathname+1; char *zFullPathname = sqlite3Malloc(MAX(nFullPathname,nFilename)); MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) p->sharable = 1; if( !zFullPathname ){ sqlite3_free(p); return SQLITE_NOMEM_BKPT; } if( isMemdb ){ memcpy(zFullPathname, zFilename, nFilename); }else{ rc = sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); if( rc ){ if( rc==SQLITE_OK_SYMLINK ){ rc = SQLITE_OK; }else{ sqlite3_free(zFullPathname); sqlite3_free(p); return rc; } } } #if SQLITE_THREADSAFE mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN); sqlite3_mutex_enter(mutexOpen); mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); sqlite3_mutex_enter(mutexShared); #endif for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){ assert( pBt->nRef>0 ); if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager, 0)) && sqlite3PagerVfs(pBt->pPager)==pVfs ){ int iDb; for(iDb=db->nDb-1; iDb>=0; iDb--){ Btree *pExisting = db->aDb[iDb].pBt; if( pExisting && pExisting->pBt==pBt ){ sqlite3_mutex_leave(mutexShared); sqlite3_mutex_leave(mutexOpen); sqlite3_free(zFullPathname); sqlite3_free(p); return SQLITE_CONSTRAINT; } } p->pBt = pBt; pBt->nRef++; break; } } sqlite3_mutex_leave(mutexShared); sqlite3_free(zFullPathname); } #ifdef SQLITE_DEBUG else{ /* In debug mode, we mark all persistent databases as sharable ** even when they are not. This exercises the locking code and ** gives more opportunity for asserts(sqlite3_mutex_held()) ** statements to find locking problems. */ p->sharable = 1; } #endif } #endif if( pBt==0 ){ /* ** The following asserts make sure that structures used by the btree are ** the right size. This is to guard against size changes that result ** when compiling on a different architecture. */ assert( sizeof(i64)==8 ); assert( sizeof(u64)==8 ); assert( sizeof(u32)==4 ); assert( sizeof(u16)==2 ); assert( sizeof(Pgno)==4 ); /* Suppress false-positive compiler warning from PVS-Studio */ memset(&zDbHeader[16], 0, 8); pBt = sqlite3MallocZero( sizeof(*pBt) ); if( pBt==0 ){ rc = SQLITE_NOMEM_BKPT; goto btree_open_out; } rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, sizeof(MemPage), flags, vfsFlags, pageReinit); if( rc==SQLITE_OK ){ sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap); rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); } if( rc!=SQLITE_OK ){ goto btree_open_out; } pBt->openFlags = (u8)flags; pBt->db = db; sqlite3PagerSetBusyHandler(pBt->pPager, btreeInvokeBusyHandler, pBt); p->pBt = pBt; pBt->pCursor = 0; pBt->pPage1 = 0; if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY; #if defined(SQLITE_SECURE_DELETE) pBt->btsFlags |= BTS_SECURE_DELETE; #elif defined(SQLITE_FAST_SECURE_DELETE) pBt->btsFlags |= BTS_OVERWRITE; #endif /* EVIDENCE-OF: R-51873-39618 The page size for a database file is ** determined by the 2-byte integer located at an offset of 16 bytes from ** the beginning of the database file. */ pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16); if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ pBt->pageSize = 0; #ifndef SQLITE_OMIT_AUTOVACUUM /* If the magic name ":memory:" will create an in-memory database, then ** leave the autoVacuum mode at 0 (do not auto-vacuum), even if ** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if ** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a ** regular file-name. In this case the auto-vacuum applies as per normal. */ if( zFilename && !isMemdb ){ pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0); pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0); } #endif nReserve = 0; }else{ /* EVIDENCE-OF: R-37497-42412 The size of the reserved region is ** determined by the one-byte unsigned integer found at an offset of 20 ** into the database file header. */ nReserve = zDbHeader[20]; pBt->btsFlags |= BTS_PAGESIZE_FIXED; #ifndef SQLITE_OMIT_AUTOVACUUM pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0); pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0); #endif } rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve); if( rc ) goto btree_open_out; pBt->usableSize = pBt->pageSize - nReserve; assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* Add the new BtShared object to the linked list sharable BtShareds. */ pBt->nRef = 1; if( p->sharable ){ MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);) if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){ pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST); if( pBt->mutex==0 ){ rc = SQLITE_NOMEM_BKPT; goto btree_open_out; } } sqlite3_mutex_enter(mutexShared); pBt->pNext = GLOBAL(BtShared*,sqlite3SharedCacheList); GLOBAL(BtShared*,sqlite3SharedCacheList) = pBt; sqlite3_mutex_leave(mutexShared); } #endif } #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* If the new Btree uses a sharable pBtShared, then link the new ** Btree into the list of all sharable Btrees for the same connection. ** The list is kept in ascending order by pBt address. */ if( p->sharable ){ int i; Btree *pSib; for(i=0; inDb; i++){ if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){ while( pSib->pPrev ){ pSib = pSib->pPrev; } if( (uptr)p->pBt<(uptr)pSib->pBt ){ p->pNext = pSib; p->pPrev = 0; pSib->pPrev = p; }else{ while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){ pSib = pSib->pNext; } p->pNext = pSib->pNext; p->pPrev = pSib; if( p->pNext ){ p->pNext->pPrev = p; } pSib->pNext = p; } break; } } } #endif *ppBtree = p; btree_open_out: if( rc!=SQLITE_OK ){ if( pBt && pBt->pPager ){ sqlite3PagerClose(pBt->pPager, 0); } sqlite3_free(pBt); sqlite3_free(p); *ppBtree = 0; }else{ sqlite3_file *pFile; /* If the B-Tree was successfully opened, set the pager-cache size to the ** default value. Except, when opening on an existing shared pager-cache, ** do not change the pager-cache size. */ if( sqlite3BtreeSchema(p, 0, 0)==0 ){ sqlite3BtreeSetCacheSize(p, SQLITE_DEFAULT_CACHE_SIZE); } pFile = sqlite3PagerFile(pBt->pPager); if( pFile->pMethods ){ sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_PDB, (void*)&pBt->db); } } if( mutexOpen ){ assert( sqlite3_mutex_held(mutexOpen) ); sqlite3_mutex_leave(mutexOpen); } assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 ); return rc; } /* ** Decrement the BtShared.nRef counter. When it reaches zero, ** remove the BtShared structure from the sharing list. Return ** true if the BtShared.nRef counter reaches zero and return ** false if it is still positive. */ static int removeFromSharingList(BtShared *pBt){ #ifndef SQLITE_OMIT_SHARED_CACHE MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) BtShared *pList; int removed = 0; assert( sqlite3_mutex_notheld(pBt->mutex) ); MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) sqlite3_mutex_enter(pMainMtx); pBt->nRef--; if( pBt->nRef<=0 ){ if( GLOBAL(BtShared*,sqlite3SharedCacheList)==pBt ){ GLOBAL(BtShared*,sqlite3SharedCacheList) = pBt->pNext; }else{ pList = GLOBAL(BtShared*,sqlite3SharedCacheList); while( ALWAYS(pList) && pList->pNext!=pBt ){ pList=pList->pNext; } if( ALWAYS(pList) ){ pList->pNext = pBt->pNext; } } if( SQLITE_THREADSAFE ){ sqlite3_mutex_free(pBt->mutex); } removed = 1; } sqlite3_mutex_leave(pMainMtx); return removed; #else return 1; #endif } /* ** Make sure pBt->pTmpSpace points to an allocation of ** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child ** pointer. */ static SQLITE_NOINLINE int allocateTempSpace(BtShared *pBt){ assert( pBt!=0 ); assert( pBt->pTmpSpace==0 ); /* This routine is called only by btreeCursor() when allocating the ** first write cursor for the BtShared object */ assert( pBt->pCursor!=0 && (pBt->pCursor->curFlags & BTCF_WriteFlag)!=0 ); pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize ); if( pBt->pTmpSpace==0 ){ BtCursor *pCur = pBt->pCursor; pBt->pCursor = pCur->pNext; /* Unlink the cursor */ memset(pCur, 0, sizeof(*pCur)); return SQLITE_NOMEM_BKPT; } /* One of the uses of pBt->pTmpSpace is to format cells before ** inserting them into a leaf page (function fillInCell()). If ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes ** by the various routines that manipulate binary cells. Which ** can mean that fillInCell() only initializes the first 2 or 3 ** bytes of pTmpSpace, but that the first 4 bytes are copied from ** it into a database page. This is not actually a problem, but it ** does cause a valgrind error when the 1 or 2 bytes of uninitialized ** data is passed to system call write(). So to avoid this error, ** zero the first 4 bytes of temp space here. ** ** Also: Provide four bytes of initialized space before the ** beginning of pTmpSpace as an area available to prepend the ** left-child pointer to the beginning of a cell. */ memset(pBt->pTmpSpace, 0, 8); pBt->pTmpSpace += 4; return SQLITE_OK; } /* ** Free the pBt->pTmpSpace allocation */ static void freeTempSpace(BtShared *pBt){ if( pBt->pTmpSpace ){ pBt->pTmpSpace -= 4; sqlite3PageFree(pBt->pTmpSpace); pBt->pTmpSpace = 0; } } /* ** Close an open database and invalidate all cursors. */ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ BtShared *pBt = p->pBt; /* Close all cursors opened via this handle. */ assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); /* Verify that no other cursors have this Btree open */ #ifdef SQLITE_DEBUG { BtCursor *pCur = pBt->pCursor; while( pCur ){ BtCursor *pTmp = pCur; pCur = pCur->pNext; assert( pTmp->pBtree!=p ); } } #endif /* Rollback any active transaction and free the handle structure. ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. */ sqlite3BtreeRollback(p, SQLITE_OK, 0); sqlite3BtreeLeave(p); /* If there are still other outstanding references to the shared-btree ** structure, return now. The remainder of this procedure cleans ** up the shared-btree. */ assert( p->wantToLock==0 && p->locked==0 ); if( !p->sharable || removeFromSharingList(pBt) ){ /* The pBt is no longer on the sharing list, so we can access ** it without having to hold the mutex. ** ** Clean out and delete the BtShared object. */ assert( !pBt->pCursor ); sqlite3PagerClose(pBt->pPager, p->db); if( pBt->xFreeSchema && pBt->pSchema ){ pBt->xFreeSchema(pBt->pSchema); } sqlite3DbFree(0, pBt->pSchema); freeTempSpace(pBt); sqlite3_free(pBt); } #ifndef SQLITE_OMIT_SHARED_CACHE assert( p->wantToLock==0 ); assert( p->locked==0 ); if( p->pPrev ) p->pPrev->pNext = p->pNext; if( p->pNext ) p->pNext->pPrev = p->pPrev; #endif sqlite3_free(p); return SQLITE_OK; } /* ** Change the "soft" limit on the number of pages in the cache. ** Unused and unmodified pages will be recycled when the number of ** pages in the cache exceeds this soft limit. But the size of the ** cache is allowed to grow larger than this limit if it contains ** dirty pages or pages still in active use. */ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ BtShared *pBt = p->pBt; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); sqlite3PagerSetCachesize(pBt->pPager, mxPage); sqlite3BtreeLeave(p); return SQLITE_OK; } /* ** Change the "spill" limit on the number of pages in the cache. ** If the number of pages exceeds this limit during a write transaction, ** the pager might attempt to "spill" pages to the journal early in ** order to free up memory. ** ** The value returned is the current spill size. If zero is passed ** as an argument, no changes are made to the spill size setting, so ** using mxPage of 0 is a way to query the current spill size. */ SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree *p, int mxPage){ BtShared *pBt = p->pBt; int res; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); res = sqlite3PagerSetSpillsize(pBt->pPager, mxPage); sqlite3BtreeLeave(p); return res; } #if SQLITE_MAX_MMAP_SIZE>0 /* ** Change the limit on the amount of the database file that may be ** memory mapped. */ SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){ BtShared *pBt = p->pBt; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); sqlite3PagerSetMmapLimit(pBt->pPager, szMmap); sqlite3BtreeLeave(p); return SQLITE_OK; } #endif /* SQLITE_MAX_MMAP_SIZE>0 */ /* ** Change the way data is synced to disk in order to increase or decrease ** how well the database resists damage due to OS crashes and power ** failures. Level 1 is the same as asynchronous (no syncs() occur and ** there is a high probability of damage) Level 2 is the default. There ** is a very low but non-zero probability of damage. Level 3 reduces the ** probability of damage to near zero but with a write performance reduction. */ #ifndef SQLITE_OMIT_PAGER_PRAGMAS SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags( Btree *p, /* The btree to set the safety level on */ unsigned pgFlags /* Various PAGER_* flags */ ){ BtShared *pBt = p->pBt; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); sqlite3PagerSetFlags(pBt->pPager, pgFlags); sqlite3BtreeLeave(p); return SQLITE_OK; } #endif /* ** Change the default pages size and the number of reserved bytes per page. ** Or, if the page size has already been fixed, return SQLITE_READONLY ** without changing anything. ** ** The page size must be a power of 2 between 512 and 65536. If the page ** size supplied does not meet this constraint then the page size is not ** changed. ** ** Page sizes are constrained to be a power of two so that the region ** of the database file used for locking (beginning at PENDING_BYTE, ** the first byte past the 1GB boundary, 0x40000000) needs to occur ** at the beginning of a page. ** ** If parameter nReserve is less than zero, then the number of reserved ** bytes per page is left unchanged. ** ** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size ** and autovacuum mode can no longer be changed. */ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ int rc = SQLITE_OK; int x; BtShared *pBt = p->pBt; assert( nReserve>=0 && nReserve<=255 ); sqlite3BtreeEnter(p); pBt->nReserveWanted = nReserve; x = pBt->pageSize - pBt->usableSize; if( nReservebtsFlags & BTS_PAGESIZE_FIXED ){ sqlite3BtreeLeave(p); return SQLITE_READONLY; } assert( nReserve>=0 && nReserve<=255 ); if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE && ((pageSize-1)&pageSize)==0 ){ assert( (pageSize & 7)==0 ); assert( !pBt->pCursor ); if( nReserve>32 && pageSize==512 ) pageSize = 1024; pBt->pageSize = (u32)pageSize; freeTempSpace(pBt); } rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve); pBt->usableSize = pBt->pageSize - (u16)nReserve; if( iFix ) pBt->btsFlags |= BTS_PAGESIZE_FIXED; sqlite3BtreeLeave(p); return rc; } /* ** Return the currently defined page size */ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){ return p->pBt->pageSize; } /* ** This function is similar to sqlite3BtreeGetReserve(), except that it ** may only be called if it is guaranteed that the b-tree mutex is already ** held. ** ** This is useful in one special case in the backup API code where it is ** known that the shared b-tree mutex is held, but the mutex on the ** database handle that owns *p is not. In this case if sqlite3BtreeEnter() ** were to be called, it might collide with some other operation on the ** database handle that owns *p, causing undefined behavior. */ SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){ int n; assert( sqlite3_mutex_held(p->pBt->mutex) ); n = p->pBt->pageSize - p->pBt->usableSize; return n; } /* ** Return the number of bytes of space at the end of every page that ** are intentionally left unused. This is the "reserved" space that is ** sometimes used by extensions. ** ** The value returned is the larger of the current reserve size and ** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES. ** The amount of reserve can only grow - never shrink. */ SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){ int n1, n2; sqlite3BtreeEnter(p); n1 = (int)p->pBt->nReserveWanted; n2 = sqlite3BtreeGetReserveNoMutex(p); sqlite3BtreeLeave(p); return n1>n2 ? n1 : n2; } /* ** Set the maximum page count for a database if mxPage is positive. ** No changes are made if mxPage is 0 or negative. ** Regardless of the value of mxPage, return the maximum page count. */ SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno mxPage){ Pgno n; sqlite3BtreeEnter(p); n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage); sqlite3BtreeLeave(p); return n; } /* ** Change the values for the BTS_SECURE_DELETE and BTS_OVERWRITE flags: ** ** newFlag==0 Both BTS_SECURE_DELETE and BTS_OVERWRITE are cleared ** newFlag==1 BTS_SECURE_DELETE set and BTS_OVERWRITE is cleared ** newFlag==2 BTS_SECURE_DELETE cleared and BTS_OVERWRITE is set ** newFlag==(-1) No changes ** ** This routine acts as a query if newFlag is less than zero ** ** With BTS_OVERWRITE set, deleted content is overwritten by zeros, but ** freelist leaf pages are not written back to the database. Thus in-page ** deleted content is cleared, but freelist deleted content is not. ** ** With BTS_SECURE_DELETE, operation is like BTS_OVERWRITE with the addition ** that freelist leaf pages are written back into the database, increasing ** the amount of disk I/O. */ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ int b; if( p==0 ) return 0; sqlite3BtreeEnter(p); assert( BTS_OVERWRITE==BTS_SECURE_DELETE*2 ); assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) ); if( newFlag>=0 ){ p->pBt->btsFlags &= ~BTS_FAST_SECURE; p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag; } b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE; sqlite3BtreeLeave(p); return b; } /* ** Change the 'auto-vacuum' property of the database. If the 'autoVacuum' ** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it ** is disabled. The default value for the auto-vacuum property is ** determined by the SQLITE_DEFAULT_AUTOVACUUM macro. */ SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){ #ifdef SQLITE_OMIT_AUTOVACUUM return SQLITE_READONLY; #else BtShared *pBt = p->pBt; int rc = SQLITE_OK; u8 av = (u8)autoVacuum; sqlite3BtreeEnter(p); if( (pBt->btsFlags & BTS_PAGESIZE_FIXED)!=0 && (av ?1:0)!=pBt->autoVacuum ){ rc = SQLITE_READONLY; }else{ pBt->autoVacuum = av ?1:0; pBt->incrVacuum = av==2 ?1:0; } sqlite3BtreeLeave(p); return rc; #endif } /* ** Return the value of the 'auto-vacuum' property. If auto-vacuum is ** enabled 1 is returned. Otherwise 0. */ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){ #ifdef SQLITE_OMIT_AUTOVACUUM return BTREE_AUTOVACUUM_NONE; #else int rc; sqlite3BtreeEnter(p); rc = ( (!p->pBt->autoVacuum)?BTREE_AUTOVACUUM_NONE: (!p->pBt->incrVacuum)?BTREE_AUTOVACUUM_FULL: BTREE_AUTOVACUUM_INCR ); sqlite3BtreeLeave(p); return rc; #endif } /* ** If the user has not set the safety-level for this database connection ** using "PRAGMA synchronous", and if the safety-level is not already ** set to the value passed to this function as the second parameter, ** set it so. */ #if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS \ && !defined(SQLITE_OMIT_WAL) static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){ sqlite3 *db; Db *pDb; if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){ while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; } if( pDb->bSyncSet==0 && pDb->safety_level!=safety_level && pDb!=&db->aDb[1] ){ pDb->safety_level = safety_level; sqlite3PagerSetFlags(pBt->pPager, pDb->safety_level | (db->flags & PAGER_FLAGS_MASK)); } } } #else # define setDefaultSyncFlag(pBt,safety_level) #endif /* Forward declaration */ static int newDatabase(BtShared*); /* ** Get a reference to pPage1 of the database file. This will ** also acquire a readlock on that file. ** ** SQLITE_OK is returned on success. If the file is not a ** well-formed database file, then SQLITE_CORRUPT is returned. ** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM ** is returned if we run out of memory. */ static int lockBtree(BtShared *pBt){ int rc; /* Result code from subfunctions */ MemPage *pPage1; /* Page 1 of the database file */ u32 nPage; /* Number of pages in the database */ u32 nPageFile = 0; /* Number of pages in the database file */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( pBt->pPage1==0 ); rc = sqlite3PagerSharedLock(pBt->pPager); if( rc!=SQLITE_OK ) return rc; rc = btreeGetPage(pBt, 1, &pPage1, 0); if( rc!=SQLITE_OK ) return rc; /* Do some checking to help insure the file we opened really is ** a valid database file. */ nPage = get4byte(28+(u8*)pPage1->aData); sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile); if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){ nPage = nPageFile; } if( (pBt->db->flags & SQLITE_ResetDatabase)!=0 ){ nPage = 0; } if( nPage>0 ){ u32 pageSize; u32 usableSize; u8 *page1 = pPage1->aData; rc = SQLITE_NOTADB; /* EVIDENCE-OF: R-43737-39999 Every valid SQLite database file begins ** with the following 16 bytes (in hex): 53 51 4c 69 74 65 20 66 6f 72 6d ** 61 74 20 33 00. */ if( memcmp(page1, zMagicHeader, 16)!=0 ){ goto page1_init_failed; } #ifdef SQLITE_OMIT_WAL if( page1[18]>1 ){ pBt->btsFlags |= BTS_READ_ONLY; } if( page1[19]>1 ){ goto page1_init_failed; } #else if( page1[18]>2 ){ pBt->btsFlags |= BTS_READ_ONLY; } if( page1[19]>2 ){ goto page1_init_failed; } /* If the read version is set to 2, this database should be accessed ** in WAL mode. If the log is not already open, open it now. Then ** return SQLITE_OK and return without populating BtShared.pPage1. ** The caller detects this and calls this function again. This is ** required as the version of page 1 currently in the page1 buffer ** may not be the latest version - there may be a newer one in the log ** file. */ if( page1[19]==2 && (pBt->btsFlags & BTS_NO_WAL)==0 ){ int isOpen = 0; rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen); if( rc!=SQLITE_OK ){ goto page1_init_failed; }else{ setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1); if( isOpen==0 ){ releasePageOne(pPage1); return SQLITE_OK; } } rc = SQLITE_NOTADB; }else{ setDefaultSyncFlag(pBt, SQLITE_DEFAULT_SYNCHRONOUS+1); } #endif /* EVIDENCE-OF: R-15465-20813 The maximum and minimum embedded payload ** fractions and the leaf payload fraction values must be 64, 32, and 32. ** ** The original design allowed these amounts to vary, but as of ** version 3.6.0, we require them to be fixed. */ if( memcmp(&page1[21], "\100\040\040",3)!=0 ){ goto page1_init_failed; } /* EVIDENCE-OF: R-51873-39618 The page size for a database file is ** determined by the 2-byte integer located at an offset of 16 bytes from ** the beginning of the database file. */ pageSize = (page1[16]<<8) | (page1[17]<<16); /* EVIDENCE-OF: R-25008-21688 The size of a page is a power of two ** between 512 and 65536 inclusive. */ if( ((pageSize-1)&pageSize)!=0 || pageSize>SQLITE_MAX_PAGE_SIZE || pageSize<=256 ){ goto page1_init_failed; } assert( (pageSize & 7)==0 ); /* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte ** integer at offset 20 is the number of bytes of space at the end of ** each page to reserve for extensions. ** ** EVIDENCE-OF: R-37497-42412 The size of the reserved region is ** determined by the one-byte unsigned integer found at an offset of 20 ** into the database file header. */ usableSize = pageSize - page1[20]; if( (u32)pageSize!=pBt->pageSize ){ /* After reading the first page of the database assuming a page size ** of BtShared.pageSize, we have discovered that the page-size is ** actually pageSize. Unlock the database, leave pBt->pPage1 at ** zero and return SQLITE_OK. The caller will call this function ** again with the correct page-size. */ releasePageOne(pPage1); pBt->usableSize = usableSize; pBt->pageSize = pageSize; pBt->btsFlags |= BTS_PAGESIZE_FIXED; freeTempSpace(pBt); rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, pageSize-usableSize); return rc; } if( nPage>nPageFile ){ if( sqlite3WritableSchema(pBt->db)==0 ){ rc = SQLITE_CORRUPT_BKPT; goto page1_init_failed; }else{ nPage = nPageFile; } } /* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to ** be less than 480. In other words, if the page size is 512, then the ** reserved space size cannot exceed 32. */ if( usableSize<480 ){ goto page1_init_failed; } pBt->btsFlags |= BTS_PAGESIZE_FIXED; pBt->pageSize = pageSize; pBt->usableSize = usableSize; #ifndef SQLITE_OMIT_AUTOVACUUM pBt->autoVacuum = (get4byte(&page1[36 + 4*4])?1:0); pBt->incrVacuum = (get4byte(&page1[36 + 7*4])?1:0); #endif } /* maxLocal is the maximum amount of payload to store locally for ** a cell. Make sure it is small enough so that at least minFanout ** cells can will fit on one page. We assume a 10-byte page header. ** Besides the payload, the cell must store: ** 2-byte pointer to the cell ** 4-byte child pointer ** 9-byte nKey value ** 4-byte nData value ** 4-byte overflow page pointer ** So a cell consists of a 2-byte pointer, a header which is as much as ** 17 bytes long, 0 to N bytes of payload, and an optional 4 byte overflow ** page pointer. */ pBt->maxLocal = (u16)((pBt->usableSize-12)*64/255 - 23); pBt->minLocal = (u16)((pBt->usableSize-12)*32/255 - 23); pBt->maxLeaf = (u16)(pBt->usableSize - 35); pBt->minLeaf = (u16)((pBt->usableSize-12)*32/255 - 23); if( pBt->maxLocal>127 ){ pBt->max1bytePayload = 127; }else{ pBt->max1bytePayload = (u8)pBt->maxLocal; } assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) ); pBt->pPage1 = pPage1; pBt->nPage = nPage; return SQLITE_OK; page1_init_failed: releasePageOne(pPage1); pBt->pPage1 = 0; return rc; } #ifndef NDEBUG /* ** Return the number of cursors open on pBt. This is for use ** in assert() expressions, so it is only compiled if NDEBUG is not ** defined. ** ** Only write cursors are counted if wrOnly is true. If wrOnly is ** false then all cursors are counted. ** ** For the purposes of this routine, a cursor is any cursor that ** is capable of reading or writing to the database. Cursors that ** have been tripped into the CURSOR_FAULT state are not counted. */ static int countValidCursors(BtShared *pBt, int wrOnly){ BtCursor *pCur; int r = 0; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0) && pCur->eState!=CURSOR_FAULT ) r++; } return r; } #endif /* ** If there are no outstanding cursors and we are not in the middle ** of a transaction but there is a read lock on the database, then ** this routine unrefs the first page of the database file which ** has the effect of releasing the read lock. ** ** If there is a transaction in progress, this routine is a no-op. */ static void unlockBtreeIfUnused(BtShared *pBt){ assert( sqlite3_mutex_held(pBt->mutex) ); assert( countValidCursors(pBt,0)==0 || pBt->inTransaction>TRANS_NONE ); if( pBt->inTransaction==TRANS_NONE && pBt->pPage1!=0 ){ MemPage *pPage1 = pBt->pPage1; assert( pPage1->aData ); assert( sqlite3PagerRefcount(pBt->pPager)==1 ); pBt->pPage1 = 0; releasePageOne(pPage1); } } /* ** If pBt points to an empty file then convert that empty file ** into a new empty database by initializing the first page of ** the database. */ static int newDatabase(BtShared *pBt){ MemPage *pP1; unsigned char *data; int rc; assert( sqlite3_mutex_held(pBt->mutex) ); if( pBt->nPage>0 ){ return SQLITE_OK; } pP1 = pBt->pPage1; assert( pP1!=0 ); data = pP1->aData; rc = sqlite3PagerWrite(pP1->pDbPage); if( rc ) return rc; memcpy(data, zMagicHeader, sizeof(zMagicHeader)); assert( sizeof(zMagicHeader)==16 ); data[16] = (u8)((pBt->pageSize>>8)&0xff); data[17] = (u8)((pBt->pageSize>>16)&0xff); data[18] = 1; data[19] = 1; assert( pBt->usableSize<=pBt->pageSize && pBt->usableSize+255>=pBt->pageSize); data[20] = (u8)(pBt->pageSize - pBt->usableSize); data[21] = 64; data[22] = 32; data[23] = 32; memset(&data[24], 0, 100-24); zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA ); pBt->btsFlags |= BTS_PAGESIZE_FIXED; #ifndef SQLITE_OMIT_AUTOVACUUM assert( pBt->autoVacuum==1 || pBt->autoVacuum==0 ); assert( pBt->incrVacuum==1 || pBt->incrVacuum==0 ); put4byte(&data[36 + 4*4], pBt->autoVacuum); put4byte(&data[36 + 7*4], pBt->incrVacuum); #endif pBt->nPage = 1; data[31] = 1; return SQLITE_OK; } /* ** Initialize the first page of the database file (creating a database ** consisting of a single page and no schema objects). Return SQLITE_OK ** if successful, or an SQLite error code otherwise. */ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){ int rc; sqlite3BtreeEnter(p); p->pBt->nPage = 0; rc = newDatabase(p->pBt); sqlite3BtreeLeave(p); return rc; } /* ** Attempt to start a new transaction. A write-transaction ** is started if the second argument is nonzero, otherwise a read- ** transaction. If the second argument is 2 or more and exclusive ** transaction is started, meaning that no other process is allowed ** to access the database. A preexisting transaction may not be ** upgraded to exclusive by calling this routine a second time - the ** exclusivity flag only works for a new transaction. ** ** A write-transaction must be started before attempting any ** changes to the database. None of the following routines ** will work unless a transaction is started first: ** ** sqlite3BtreeCreateTable() ** sqlite3BtreeCreateIndex() ** sqlite3BtreeClearTable() ** sqlite3BtreeDropTable() ** sqlite3BtreeInsert() ** sqlite3BtreeDelete() ** sqlite3BtreeUpdateMeta() ** ** If an initial attempt to acquire the lock fails because of lock contention ** and the database was previously unlocked, then invoke the busy handler ** if there is one. But if there was previously a read-lock, do not ** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is ** returned when there is already a read-lock in order to avoid a deadlock. ** ** Suppose there are two processes A and B. A has a read lock and B has ** a reserved lock. B tries to promote to exclusive but is blocked because ** of A's read lock. A tries to promote to reserved but is blocked by B. ** One or the other of the two processes must give way or there can be ** no progress. By returning SQLITE_BUSY and not invoking the busy callback ** when A already has a read lock, we encourage A to give up and let B ** proceed. */ static SQLITE_NOINLINE int btreeBeginTrans( Btree *p, /* The btree in which to start the transaction */ int wrflag, /* True to start a write transaction */ int *pSchemaVersion /* Put schema version number here, if not NULL */ ){ BtShared *pBt = p->pBt; Pager *pPager = pBt->pPager; int rc = SQLITE_OK; sqlite3BtreeEnter(p); btreeIntegrity(p); /* If the btree is already in a write-transaction, or it ** is already in a read-transaction and a read-transaction ** is requested, this is a no-op. */ if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ goto trans_begun; } assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 ); if( (p->db->flags & SQLITE_ResetDatabase) && sqlite3PagerIsreadonly(pPager)==0 ){ pBt->btsFlags &= ~BTS_READ_ONLY; } /* Write transactions are not possible on a read-only database */ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ rc = SQLITE_READONLY; goto trans_begun; } #ifndef SQLITE_OMIT_SHARED_CACHE { sqlite3 *pBlock = 0; /* If another database handle has already opened a write transaction ** on this shared-btree structure and a second write transaction is ** requested, return SQLITE_LOCKED. */ if( (wrflag && pBt->inTransaction==TRANS_WRITE) || (pBt->btsFlags & BTS_PENDING)!=0 ){ pBlock = pBt->pWriter->db; }else if( wrflag>1 ){ BtLock *pIter; for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ if( pIter->pBtree!=p ){ pBlock = pIter->pBtree->db; break; } } } if( pBlock ){ sqlite3ConnectionBlocked(p->db, pBlock); rc = SQLITE_LOCKED_SHAREDCACHE; goto trans_begun; } } #endif /* Any read-only or read-write transaction implies a read-lock on ** page 1. So if some other shared-cache client already has a write-lock ** on page 1, the transaction cannot be opened. */ rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK); if( SQLITE_OK!=rc ) goto trans_begun; pBt->btsFlags &= ~BTS_INITIALLY_EMPTY; if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY; do { sqlite3PagerWalDb(pPager, p->db); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* If transitioning from no transaction directly to a write transaction, ** block for the WRITER lock first if possible. */ if( pBt->pPage1==0 && wrflag ){ assert( pBt->inTransaction==TRANS_NONE ); rc = sqlite3PagerWalWriteLock(pPager, 1); if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break; } #endif /* Call lockBtree() until either pBt->pPage1 is populated or ** lockBtree() returns something other than SQLITE_OK. lockBtree() ** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after ** reading page 1 it discovers that the page-size of the database ** file is not pBt->pageSize. In this case lockBtree() will update ** pBt->pageSize to the page-size of the file on disk. */ while( pBt->pPage1==0 && SQLITE_OK==(rc = lockBtree(pBt)) ); if( rc==SQLITE_OK && wrflag ){ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){ rc = SQLITE_READONLY; }else{ rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db)); if( rc==SQLITE_OK ){ rc = newDatabase(pBt); }else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){ /* if there was no transaction opened when this function was ** called and SQLITE_BUSY_SNAPSHOT is returned, change the error ** code to SQLITE_BUSY. */ rc = SQLITE_BUSY; } } } if( rc!=SQLITE_OK ){ (void)sqlite3PagerWalWriteLock(pPager, 0); unlockBtreeIfUnused(pBt); } }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && btreeInvokeBusyHandler(pBt) ); sqlite3PagerWalDb(pPager, 0); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; #endif if( rc==SQLITE_OK ){ if( p->inTrans==TRANS_NONE ){ pBt->nTransaction++; #ifndef SQLITE_OMIT_SHARED_CACHE if( p->sharable ){ assert( p->lock.pBtree==p && p->lock.iTable==1 ); p->lock.eLock = READ_LOCK; p->lock.pNext = pBt->pLock; pBt->pLock = &p->lock; } #endif } p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); if( p->inTrans>pBt->inTransaction ){ pBt->inTransaction = p->inTrans; } if( wrflag ){ MemPage *pPage1 = pBt->pPage1; #ifndef SQLITE_OMIT_SHARED_CACHE assert( !pBt->pWriter ); pBt->pWriter = p; pBt->btsFlags &= ~BTS_EXCLUSIVE; if( wrflag>1 ) pBt->btsFlags |= BTS_EXCLUSIVE; #endif /* If the db-size header field is incorrect (as it may be if an old ** client has been writing the database file), update it now. Doing ** this sooner rather than later means the database size can safely ** re-read the database size from page 1 if a savepoint or transaction ** rollback occurs within the transaction. */ if( pBt->nPage!=get4byte(&pPage1->aData[28]) ){ rc = sqlite3PagerWrite(pPage1->pDbPage); if( rc==SQLITE_OK ){ put4byte(&pPage1->aData[28], pBt->nPage); } } } } trans_begun: if( rc==SQLITE_OK ){ if( pSchemaVersion ){ *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]); } if( wrflag ){ /* This call makes sure that the pager has the correct number of ** open savepoints. If the second parameter is greater than 0 and ** the sub-journal is not already open, then it will be opened here. */ rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint); } } btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; } SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){ BtShared *pBt; if( p->sharable || p->inTrans==TRANS_NONE || (p->inTrans==TRANS_READ && wrflag!=0) ){ return btreeBeginTrans(p,wrflag,pSchemaVersion); } pBt = p->pBt; if( pSchemaVersion ){ *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]); } if( wrflag ){ /* This call makes sure that the pager has the correct number of ** open savepoints. If the second parameter is greater than 0 and ** the sub-journal is not already open, then it will be opened here. */ return sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint); }else{ return SQLITE_OK; } } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Set the pointer-map entries for all children of page pPage. Also, if ** pPage contains cells that point to overflow pages, set the pointer ** map entries for the overflow pages as well. */ static int setChildPtrmaps(MemPage *pPage){ int i; /* Counter variable */ int nCell; /* Number of cells in page pPage */ int rc; /* Return code */ BtShared *pBt = pPage->pBt; Pgno pgno = pPage->pgno; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage); if( rc!=SQLITE_OK ) return rc; nCell = pPage->nCell; for(i=0; ileaf ){ Pgno childPgno = get4byte(pCell); ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc); } } if( !pPage->leaf ){ Pgno childPgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc); } return rc; } /* ** Somewhere on pPage is a pointer to page iFrom. Modify this pointer so ** that it points to iTo. Parameter eType describes the type of pointer to ** be modified, as follows: ** ** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child ** page of pPage. ** ** PTRMAP_OVERFLOW1: pPage is a btree-page. The pointer points at an overflow ** page pointed to by one of the cells on pPage. ** ** PTRMAP_OVERFLOW2: pPage is an overflow-page. The pointer points at the next ** overflow page in the list. */ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); if( eType==PTRMAP_OVERFLOW2 ){ /* The pointer is always the first 4 bytes of the page in this case. */ if( get4byte(pPage->aData)!=iFrom ){ return SQLITE_CORRUPT_PAGE(pPage); } put4byte(pPage->aData, iTo); }else{ int i; int nCell; int rc; rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage); if( rc ) return rc; nCell = pPage->nCell; for(i=0; ixParseCell(pPage, pCell, &info); if( info.nLocal pPage->aData+pPage->pBt->usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } if( iFrom==get4byte(pCell+info.nSize-4) ){ put4byte(pCell+info.nSize-4, iTo); break; } } }else{ if( pCell+4 > pPage->aData+pPage->pBt->usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } if( get4byte(pCell)==iFrom ){ put4byte(pCell, iTo); break; } } } if( i==nCell ){ if( eType!=PTRMAP_BTREE || get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ return SQLITE_CORRUPT_PAGE(pPage); } put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); } } return SQLITE_OK; } /* ** Move the open database page pDbPage to location iFreePage in the ** database. The pDbPage reference remains valid. ** ** The isCommit flag indicates that there is no need to remember that ** the journal needs to be sync()ed before database page pDbPage->pgno ** can be written to. The caller has already promised not to write to that ** page. */ static int relocatePage( BtShared *pBt, /* Btree */ MemPage *pDbPage, /* Open page to move */ u8 eType, /* Pointer map 'type' entry for pDbPage */ Pgno iPtrPage, /* Pointer map 'page-no' entry for pDbPage */ Pgno iFreePage, /* The location to move pDbPage to */ int isCommit /* isCommit flag passed to sqlite3PagerMovepage */ ){ MemPage *pPtrPage; /* The page that contains a pointer to pDbPage */ Pgno iDbPage = pDbPage->pgno; Pager *pPager = pBt->pPager; int rc; assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 || eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ); assert( sqlite3_mutex_held(pBt->mutex) ); assert( pDbPage->pBt==pBt ); if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT; /* Move page iDbPage from its current location to page number iFreePage */ TRACE(("AUTOVACUUM: Moving %u to free page %u (ptr page %u type %u)\n", iDbPage, iFreePage, iPtrPage, eType)); rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit); if( rc!=SQLITE_OK ){ return rc; } pDbPage->pgno = iFreePage; /* If pDbPage was a btree-page, then it may have child pages and/or cells ** that point to overflow pages. The pointer map entries for all these ** pages need to be changed. ** ** If pDbPage is an overflow page, then the first 4 bytes may store a ** pointer to a subsequent overflow page. If this is the case, then ** the pointer map needs to be updated for the subsequent overflow page. */ if( eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ){ rc = setChildPtrmaps(pDbPage); if( rc!=SQLITE_OK ){ return rc; } }else{ Pgno nextOvfl = get4byte(pDbPage->aData); if( nextOvfl!=0 ){ ptrmapPut(pBt, nextOvfl, PTRMAP_OVERFLOW2, iFreePage, &rc); if( rc!=SQLITE_OK ){ return rc; } } } /* Fix the database pointer on page iPtrPage that pointed at iDbPage so ** that it points at iFreePage. Also fix the pointer map entry for ** iPtrPage. */ if( eType!=PTRMAP_ROOTPAGE ){ rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3PagerWrite(pPtrPage->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pPtrPage); return rc; } rc = modifyPagePointer(pPtrPage, iDbPage, iFreePage, eType); releasePage(pPtrPage); if( rc==SQLITE_OK ){ ptrmapPut(pBt, iFreePage, eType, iPtrPage, &rc); } } return rc; } /* Forward declaration required by incrVacuumStep(). */ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); /* ** Perform a single step of an incremental-vacuum. If successful, return ** SQLITE_OK. If there is no work to do (and therefore no point in ** calling this function again), return SQLITE_DONE. Or, if an error ** occurs, return some other error code. ** ** More specifically, this function attempts to re-organize the database so ** that the last page of the file currently in use is no longer in use. ** ** Parameter nFin is the number of pages that this database would contain ** were this function called until it returns SQLITE_DONE. ** ** If the bCommit parameter is non-zero, this function assumes that the ** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE ** or an error. bCommit is passed true for an auto-vacuum-on-commit ** operation, or false for an incremental vacuum. */ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ Pgno nFreeList; /* Number of pages still on the free-list */ int rc; assert( sqlite3_mutex_held(pBt->mutex) ); assert( iLastPg>nFin ); if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){ u8 eType; Pgno iPtrPage; nFreeList = get4byte(&pBt->pPage1->aData[36]); if( nFreeList==0 ){ return SQLITE_DONE; } rc = ptrmapGet(pBt, iLastPg, &eType, &iPtrPage); if( rc!=SQLITE_OK ){ return rc; } if( eType==PTRMAP_ROOTPAGE ){ return SQLITE_CORRUPT_BKPT; } if( eType==PTRMAP_FREEPAGE ){ if( bCommit==0 ){ /* Remove the page from the files free-list. This is not required ** if bCommit is non-zero. In that case, the free-list will be ** truncated to zero after this function returns, so it doesn't ** matter if it still contains some garbage entries. */ Pgno iFreePg; MemPage *pFreePg; rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT); if( rc!=SQLITE_OK ){ return rc; } assert( iFreePg==iLastPg ); releasePage(pFreePg); } } else { Pgno iFreePg; /* Index of free page to move pLastPg to */ MemPage *pLastPg; u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */ Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */ rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0); if( rc!=SQLITE_OK ){ return rc; } /* If bCommit is zero, this loop runs exactly once and page pLastPg ** is swapped with the first free page pulled off the free list. ** ** On the other hand, if bCommit is greater than zero, then keep ** looping until a free-page located within the first nFin pages ** of the file is found. */ if( bCommit==0 ){ eMode = BTALLOC_LE; iNear = nFin; } do { MemPage *pFreePg; Pgno dbSize = btreePagecount(pBt); rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode); if( rc!=SQLITE_OK ){ releasePage(pLastPg); return rc; } releasePage(pFreePg); if( iFreePg>dbSize ){ releasePage(pLastPg); return SQLITE_CORRUPT_BKPT; } }while( bCommit && iFreePg>nFin ); assert( iFreePgbDoTruncate = 1; pBt->nPage = iLastPg; } return SQLITE_OK; } /* ** The database opened by the first argument is an auto-vacuum database ** nOrig pages in size containing nFree free pages. Return the expected ** size of the database in pages following an auto-vacuum operation. */ static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){ int nEntry; /* Number of entries on one ptrmap page */ Pgno nPtrmap; /* Number of PtrMap pages to be freed */ Pgno nFin; /* Return value */ nEntry = pBt->usableSize/5; nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry; nFin = nOrig - nFree - nPtrmap; if( nOrig>PENDING_BYTE_PAGE(pBt) && nFinpBt; sqlite3BtreeEnter(p); assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); if( !pBt->autoVacuum ){ rc = SQLITE_DONE; }else{ Pgno nOrig = btreePagecount(pBt); Pgno nFree = get4byte(&pBt->pPage1->aData[36]); Pgno nFin = finalDbSize(pBt, nOrig, nFree); if( nOrig=nOrig ){ rc = SQLITE_CORRUPT_BKPT; }else if( nFree>0 ){ rc = saveAllCursors(pBt, 0, 0); if( rc==SQLITE_OK ){ invalidateAllOverflowCache(pBt); rc = incrVacuumStep(pBt, nFin, nOrig, 0); } if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[28], pBt->nPage); } }else{ rc = SQLITE_DONE; } } sqlite3BtreeLeave(p); return rc; } /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is committed for an auto-vacuum database. */ static int autoVacuumCommit(Btree *p){ int rc = SQLITE_OK; Pager *pPager; BtShared *pBt; sqlite3 *db; VVA_ONLY( int nRef ); assert( p!=0 ); pBt = p->pBt; pPager = pBt->pPager; VVA_ONLY( nRef = sqlite3PagerRefcount(pPager); ) assert( sqlite3_mutex_held(pBt->mutex) ); invalidateAllOverflowCache(pBt); assert(pBt->autoVacuum); if( !pBt->incrVacuum ){ Pgno nFin; /* Number of pages in database after autovacuuming */ Pgno nFree; /* Number of pages on the freelist initially */ Pgno nVac; /* Number of pages to vacuum */ Pgno iFree; /* The next page to be freed */ Pgno nOrig; /* Database size before freeing */ nOrig = btreePagecount(pBt); if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){ /* It is not possible to create a database for which the final page ** is either a pointer-map page or the pending-byte page. If one ** is encountered, this indicates corruption. */ return SQLITE_CORRUPT_BKPT; } nFree = get4byte(&pBt->pPage1->aData[36]); db = p->db; if( db->xAutovacPages ){ int iDb; for(iDb=0; ALWAYS(iDbnDb); iDb++){ if( db->aDb[iDb].pBt==p ) break; } nVac = db->xAutovacPages( db->pAutovacPagesArg, db->aDb[iDb].zDbSName, nOrig, nFree, pBt->pageSize ); if( nVac>nFree ){ nVac = nFree; } if( nVac==0 ){ return SQLITE_OK; } }else{ nVac = nFree; } nFin = finalDbSize(pBt, nOrig, nVac); if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; if( nFinnFin && rc==SQLITE_OK; iFree--){ rc = incrVacuumStep(pBt, nFin, iFree, nVac==nFree); } if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( nVac==nFree ){ put4byte(&pBt->pPage1->aData[32], 0); put4byte(&pBt->pPage1->aData[36], 0); } put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin; } if( rc!=SQLITE_OK ){ sqlite3PagerRollback(pPager); } } assert( nRef>=sqlite3PagerRefcount(pPager) ); return rc; } #else /* ifndef SQLITE_OMIT_AUTOVACUUM */ # define setChildPtrmaps(x) SQLITE_OK #endif /* ** This routine does the first phase of a two-phase commit. This routine ** causes a rollback journal to be created (if it does not already exist) ** and populated with enough information so that if a power loss occurs ** the database can be restored to its original state by playing back ** the journal. Then the contents of the journal are flushed out to ** the disk. After the journal is safely on oxide, the changes to the ** database are written into the database file and flushed to oxide. ** At the end of this call, the rollback journal still exists on the ** disk and we are still holding all locks, so the transaction has not ** committed. See sqlite3BtreeCommitPhaseTwo() for the second phase of the ** commit process. ** ** This call is a no-op if no write-transaction is currently active on pBt. ** ** Otherwise, sync the database file for the btree pBt. zSuperJrnl points to ** the name of a super-journal file that should be written into the ** individual journal file, or is NULL, indicating no super-journal file ** (single database transaction). ** ** When this is called, the super-journal should already have been ** created, populated with this journal pointer and synced to disk. ** ** Once this is routine has returned, the only thing required to commit ** the write-transaction for this database file is to delete the journal. */ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ int rc = SQLITE_OK; if( p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ rc = autoVacuumCommit(p); if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; } } if( pBt->bDoTruncate ){ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); } #endif rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); sqlite3BtreeLeave(p); } return rc; } /* ** This function is called from both BtreeCommitPhaseTwo() and BtreeRollback() ** at the conclusion of a transaction. */ static void btreeEndTransaction(Btree *p){ BtShared *pBt = p->pBt; sqlite3 *db = p->db; assert( sqlite3BtreeHoldsMutex(p) ); #ifndef SQLITE_OMIT_AUTOVACUUM pBt->bDoTruncate = 0; #endif if( p->inTrans>TRANS_NONE && db->nVdbeRead>1 ){ /* If there are other active statements that belong to this database ** handle, downgrade to a read-only transaction. The other statements ** may still be reading from the database. */ downgradeAllSharedCacheTableLocks(p); p->inTrans = TRANS_READ; }else{ /* If the handle had any kind of transaction open, decrement the ** transaction count of the shared btree. If the transaction count ** reaches 0, set the shared state to TRANS_NONE. The unlockBtreeIfUnused() ** call below will unlock the pager. */ if( p->inTrans!=TRANS_NONE ){ clearAllSharedCacheTableLocks(p); pBt->nTransaction--; if( 0==pBt->nTransaction ){ pBt->inTransaction = TRANS_NONE; } } /* Set the current transaction state to TRANS_NONE and unlock the ** pager if this call closed the only read or write transaction. */ p->inTrans = TRANS_NONE; unlockBtreeIfUnused(pBt); } btreeIntegrity(p); } /* ** Commit the transaction currently in progress. ** ** This routine implements the second phase of a 2-phase commit. The ** sqlite3BtreeCommitPhaseOne() routine does the first phase and should ** be invoked prior to calling this routine. The sqlite3BtreeCommitPhaseOne() ** routine did all the work of writing information out to disk and flushing the ** contents so that they are written onto the disk platter. All this ** routine has to do is delete or truncate or zero the header in the ** the rollback journal (which causes the transaction to commit) and ** drop locks. ** ** Normally, if an error occurs while the pager layer is attempting to ** finalize the underlying journal file, this function returns an error and ** the upper layer will attempt a rollback. However, if the second argument ** is non-zero then this b-tree transaction is part of a multi-file ** transaction. In this case, the transaction has already been committed ** (by deleting a super-journal file) and the caller will ignore this ** functions return code. So, even if an error occurs in the pager layer, ** reset the b-tree objects internal state to indicate that the write ** transaction has been closed. This is quite safe, as the pager will have ** transitioned to the error state. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){ if( p->inTrans==TRANS_NONE ) return SQLITE_OK; sqlite3BtreeEnter(p); btreeIntegrity(p); /* If the handle has a write-transaction open, commit the shared-btrees ** transaction and set the shared state to TRANS_READ. */ if( p->inTrans==TRANS_WRITE ){ int rc; BtShared *pBt = p->pBt; assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->nTransaction>0 ); rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); if( rc!=SQLITE_OK && bCleanup==0 ){ sqlite3BtreeLeave(p); return rc; } p->iBDataVersion--; /* Compensate for pPager->iDataVersion++; */ pBt->inTransaction = TRANS_READ; btreeClearHasContent(pBt); } btreeEndTransaction(p); sqlite3BtreeLeave(p); return SQLITE_OK; } /* ** Do both phases of a commit. */ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){ int rc; sqlite3BtreeEnter(p); rc = sqlite3BtreeCommitPhaseOne(p, 0); if( rc==SQLITE_OK ){ rc = sqlite3BtreeCommitPhaseTwo(p, 0); } sqlite3BtreeLeave(p); return rc; } /* ** This routine sets the state to CURSOR_FAULT and the error ** code to errCode for every cursor on any BtShared that pBtree ** references. Or if the writeOnly flag is set to 1, then only ** trip write cursors and leave read cursors unchanged. ** ** Every cursor is a candidate to be tripped, including cursors ** that belong to other database connections that happen to be ** sharing the cache with pBtree. ** ** This routine gets called when a rollback occurs. If the writeOnly ** flag is true, then only write-cursors need be tripped - read-only ** cursors save their current positions so that they may continue ** following the rollback. Or, if writeOnly is false, all cursors are ** tripped. In general, writeOnly is false if the transaction being ** rolled back modified the database schema. In this case b-tree root ** pages may be moved or deleted from the database altogether, making ** it unsafe for read cursors to continue. ** ** If the writeOnly flag is true and an error is encountered while ** saving the current position of a read-only cursor, all cursors, ** including all read-cursors are tripped. ** ** SQLITE_OK is returned if successful, or if an error occurs while ** saving a cursor position, an SQLite error code. */ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ BtCursor *p; int rc = SQLITE_OK; assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 ); if( pBtree ){ sqlite3BtreeEnter(pBtree); for(p=pBtree->pBt->pCursor; p; p=p->pNext){ if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){ rc = saveCursorPosition(p); if( rc!=SQLITE_OK ){ (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); break; } } }else{ sqlite3BtreeClearCursor(p); p->eState = CURSOR_FAULT; p->skipNext = errCode; } btreeReleaseAllCursorPages(p); } sqlite3BtreeLeave(pBtree); } return rc; } /* ** Set the pBt->nPage field correctly, according to the current ** state of the database. Assume pBt->pPage1 is valid. */ static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){ int nPage = get4byte(&pPage1->aData[28]); testcase( nPage==0 ); if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); testcase( pBt->nPage!=(u32)nPage ); pBt->nPage = nPage; } /* ** Rollback the transaction in progress. ** ** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). ** Only write cursors are tripped if writeOnly is true but all cursors are ** tripped if writeOnly is false. Any attempt to use ** a tripped cursor will result in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ int rc; BtShared *pBt = p->pBt; MemPage *pPage1; assert( writeOnly==1 || writeOnly==0 ); assert( tripCode==SQLITE_ABORT_ROLLBACK || tripCode==SQLITE_OK ); sqlite3BtreeEnter(p); if( tripCode==SQLITE_OK ){ rc = tripCode = saveAllCursors(pBt, 0, 0); if( rc ) writeOnly = 0; }else{ rc = SQLITE_OK; } if( tripCode ){ int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) ); if( rc2!=SQLITE_OK ) rc = rc2; } btreeIntegrity(p); if( p->inTrans==TRANS_WRITE ){ int rc2; assert( TRANS_WRITE==pBt->inTransaction ); rc2 = sqlite3PagerRollback(pBt->pPager); if( rc2!=SQLITE_OK ){ rc = rc2; } /* The rollback may have destroyed the pPage1->aData value. So ** call btreeGetPage() on page 1 again to make ** sure pPage1->aData is set correctly. */ if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ btreeSetNPage(pBt, pPage1); releasePageOne(pPage1); } assert( countValidCursors(pBt, 1)==0 ); pBt->inTransaction = TRANS_READ; btreeClearHasContent(pBt); } btreeEndTransaction(p); sqlite3BtreeLeave(p); return rc; } /* ** Start a statement subtransaction. The subtransaction can be rolled ** back independently of the main transaction. You must start a transaction ** before starting a subtransaction. The subtransaction is ended automatically ** if the main transaction commits or rolls back. ** ** Statement subtransactions are used around individual SQL statements ** that are contained within a BEGIN...COMMIT block. If a constraint ** error occurs within the statement, the effect of that one statement ** can be rolled back without having to rollback the entire transaction. ** ** A statement sub-transaction is implemented as an anonymous savepoint. The ** value passed as the second parameter is the total number of savepoints, ** including the new anonymous savepoint, open on the B-Tree. i.e. if there ** are no active savepoints and no other statement-transactions open, ** iStatement is 1. This anonymous savepoint can be released or rolled back ** using the sqlite3BtreeSavepoint() function. */ SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int iStatement){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( p->inTrans==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( iStatement>0 ); assert( iStatement>p->db->nSavepoint ); assert( pBt->inTransaction==TRANS_WRITE ); /* At the pager level, a statement transaction is a savepoint with ** an index greater than all savepoints created explicitly using ** SQL statements. It is illegal to open, release or rollback any ** such savepoints while the statement transaction savepoint is active. */ rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement); sqlite3BtreeLeave(p); return rc; } /* ** The second argument to this function, op, is always SAVEPOINT_ROLLBACK ** or SAVEPOINT_RELEASE. This function either releases or rolls back the ** savepoint identified by parameter iSavepoint, depending on the value ** of op. ** ** Normally, iSavepoint is greater than or equal to zero. However, if op is ** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the ** contents of the entire transaction are rolled back. This is different ** from a normal transaction rollback, as no locks are released and the ** transaction remains open. */ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ int rc = SQLITE_OK; if( p && p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt; assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK ); assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) ); sqlite3BtreeEnter(p); if( op==SAVEPOINT_ROLLBACK ){ rc = saveAllCursors(pBt, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint); } if( rc==SQLITE_OK ){ if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){ pBt->nPage = 0; } rc = newDatabase(pBt); btreeSetNPage(pBt, pBt->pPage1); /* pBt->nPage might be zero if the database was corrupt when ** the transaction was started. Otherwise, it must be at least 1. */ assert( CORRUPT_DB || pBt->nPage>0 ); } sqlite3BtreeLeave(p); } return rc; } /* ** Create a new cursor for the BTree whose root is on the page ** iTable. If a read-only cursor is requested, it is assumed that ** the caller already has at least a read-only transaction open ** on the database already. If a write-cursor is requested, then ** the caller is assumed to have an open write transaction. ** ** If the BTREE_WRCSR bit of wrFlag is clear, then the cursor can only ** be used for reading. If the BTREE_WRCSR bit is set, then the cursor ** can be used for reading or for writing if other conditions for writing ** are also met. These are the conditions that must be met in order ** for writing to be allowed: ** ** 1: The cursor must have been opened with wrFlag containing BTREE_WRCSR ** ** 2: Other database connections that share the same pager cache ** but which are not in the READ_UNCOMMITTED state may not have ** cursors open with wrFlag==0 on the same table. Otherwise ** the changes made by this write cursor would be visible to ** the read cursors in the other database connection. ** ** 3: The database must be writable (not on read-only media) ** ** 4: There must be an active transaction. ** ** The BTREE_FORDELETE bit of wrFlag may optionally be set if BTREE_WRCSR ** is set. If FORDELETE is set, that is a hint to the implementation that ** this cursor will only be used to seek to and delete entries of an index ** as part of a larger DELETE statement. The FORDELETE hint is not used by ** this implementation. But in a hypothetical alternative storage engine ** in which index entries are automatically deleted when corresponding table ** rows are deleted, the FORDELETE flag is a hint that all SEEK and DELETE ** operations on this cursor can be no-ops and all READ operations can ** return a null row (2-bytes: 0x01 0x00). ** ** No checking is done to make sure that page iTable really is the ** root page of a b-tree. If it is not, then the cursor acquired ** will not work correctly. ** ** It is assumed that the sqlite3BtreeCursorZero() has been called ** on pCur to initialize the memory space prior to invoking this routine. */ static int btreeCursor( Btree *p, /* The btree */ Pgno iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ struct KeyInfo *pKeyInfo, /* First arg to comparison function */ BtCursor *pCur /* Space for new cursor */ ){ BtShared *pBt = p->pBt; /* Shared b-tree handle */ BtCursor *pX; /* Looping over other all cursors */ assert( sqlite3BtreeHoldsMutex(p) ); assert( wrFlag==0 || wrFlag==BTREE_WRCSR || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE) ); /* The following assert statements verify that if this is a sharable ** b-tree database, the connection is holding the required table locks, ** and that no other connection has any open cursor that conflicts with ** this lock. The iTable<1 term disables the check for corrupt schemas. */ assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) || iTable<1 ); assert( wrFlag==0 || !hasReadConflicts(p, iTable) ); /* Assert that the caller has opened the required transaction. */ assert( p->inTrans>TRANS_NONE ); assert( wrFlag==0 || p->inTrans==TRANS_WRITE ); assert( pBt->pPage1 && pBt->pPage1->aData ); assert( wrFlag==0 || (pBt->btsFlags & BTS_READ_ONLY)==0 ); if( iTable<=1 ){ if( iTable<1 ){ return SQLITE_CORRUPT_BKPT; }else if( btreePagecount(pBt)==0 ){ assert( wrFlag==0 ); iTable = 0; } } /* Now that no other errors can occur, finish filling in the BtCursor ** variables and link the cursor into the BtShared list. */ pCur->pgnoRoot = iTable; pCur->iPage = -1; pCur->pKeyInfo = pKeyInfo; pCur->pBtree = p; pCur->pBt = pBt; pCur->curFlags = 0; /* If there are two or more cursors on the same btree, then all such ** cursors *must* have the BTCF_Multiple flag set. */ for(pX=pBt->pCursor; pX; pX=pX->pNext){ if( pX->pgnoRoot==iTable ){ pX->curFlags |= BTCF_Multiple; pCur->curFlags = BTCF_Multiple; } } pCur->eState = CURSOR_INVALID; pCur->pNext = pBt->pCursor; pBt->pCursor = pCur; if( wrFlag ){ pCur->curFlags |= BTCF_WriteFlag; pCur->curPagerFlags = 0; if( pBt->pTmpSpace==0 ) return allocateTempSpace(pBt); }else{ pCur->curPagerFlags = PAGER_GET_READONLY; } return SQLITE_OK; } static int btreeCursorWithLock( Btree *p, /* The btree */ Pgno iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ struct KeyInfo *pKeyInfo, /* First arg to comparison function */ BtCursor *pCur /* Space for new cursor */ ){ int rc; sqlite3BtreeEnter(p); rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); sqlite3BtreeLeave(p); return rc; } SQLITE_PRIVATE int sqlite3BtreeCursor( Btree *p, /* The btree */ Pgno iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ struct KeyInfo *pKeyInfo, /* First arg to xCompare() */ BtCursor *pCur /* Write new cursor here */ ){ if( p->sharable ){ return btreeCursorWithLock(p, iTable, wrFlag, pKeyInfo, pCur); }else{ return btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); } } /* ** Return the size of a BtCursor object in bytes. ** ** This interfaces is needed so that users of cursors can preallocate ** sufficient storage to hold a cursor. The BtCursor object is opaque ** to users so they cannot do the sizeof() themselves - they must call ** this routine. */ SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){ return ROUND8(sizeof(BtCursor)); } /* ** Initialize memory that will be converted into a BtCursor object. ** ** The simple approach here would be to memset() the entire object ** to zero. But it turns out that the apPage[] and aiIdx[] arrays ** do not need to be zeroed and they are large, so we can save a lot ** of run-time by skipping the initialization of those elements. */ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){ memset(p, 0, offsetof(BtCursor, BTCURSOR_FIRST_UNINIT)); } /* ** Close a cursor. The read lock on the database file is released ** when the last cursor is closed. */ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ Btree *pBtree = pCur->pBtree; if( pBtree ){ BtShared *pBt = pCur->pBt; sqlite3BtreeEnter(pBtree); assert( pBt->pCursor!=0 ); if( pBt->pCursor==pCur ){ pBt->pCursor = pCur->pNext; }else{ BtCursor *pPrev = pBt->pCursor; do{ if( pPrev->pNext==pCur ){ pPrev->pNext = pCur->pNext; break; } pPrev = pPrev->pNext; }while( ALWAYS(pPrev) ); } btreeReleaseAllCursorPages(pCur); unlockBtreeIfUnused(pBt); sqlite3_free(pCur->aOverflow); sqlite3_free(pCur->pKey); if( (pBt->openFlags & BTREE_SINGLE) && pBt->pCursor==0 ){ /* Since the BtShared is not sharable, there is no need to ** worry about the missing sqlite3BtreeLeave() call here. */ assert( pBtree->sharable==0 ); sqlite3BtreeClose(pBtree); }else{ sqlite3BtreeLeave(pBtree); } pCur->pBtree = 0; } return SQLITE_OK; } /* ** Make sure the BtCursor* given in the argument has a valid ** BtCursor.info structure. If it is not already valid, call ** btreeParseCell() to fill it in. ** ** BtCursor.info is a cache of the information in the current cell. ** Using this cache reduces the number of calls to btreeParseCell(). */ #ifndef NDEBUG static int cellInfoEqual(CellInfo *a, CellInfo *b){ if( a->nKey!=b->nKey ) return 0; if( a->pPayload!=b->pPayload ) return 0; if( a->nPayload!=b->nPayload ) return 0; if( a->nLocal!=b->nLocal ) return 0; if( a->nSize!=b->nSize ) return 0; return 1; } static void assertCellInfo(BtCursor *pCur){ CellInfo info; memset(&info, 0, sizeof(info)); btreeParseCell(pCur->pPage, pCur->ix, &info); assert( CORRUPT_DB || cellInfoEqual(&info, &pCur->info) ); } #else #define assertCellInfo(x) #endif static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ pCur->curFlags |= BTCF_ValidNKey; btreeParseCell(pCur->pPage,pCur->ix,&pCur->info); }else{ assertCellInfo(pCur); } } #ifndef NDEBUG /* The next routine used only within assert() statements */ /* ** Return true if the given BtCursor is valid. A valid cursor is one ** that is currently pointing to a row in a (non-empty) table. ** This is a verification routine is used only within assert() statements. */ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){ return pCur && pCur->eState==CURSOR_VALID; } #endif /* NDEBUG */ SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor *pCur){ assert( pCur!=0 ); return pCur->eState==CURSOR_VALID; } /* ** Return the value of the integer key or "rowid" for a table btree. ** This routine is only valid for a cursor that is pointing into a ** ordinary table btree. If the cursor points to an index btree or ** is invalid, the result of this routine is undefined. */ SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->curIntKey ); getCellInfo(pCur); return pCur->info.nKey; } /* ** Pin or unpin a cursor. */ SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor *pCur){ assert( (pCur->curFlags & BTCF_Pinned)==0 ); pCur->curFlags |= BTCF_Pinned; } SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor *pCur){ assert( (pCur->curFlags & BTCF_Pinned)!=0 ); pCur->curFlags &= ~BTCF_Pinned; } /* ** Return the offset into the database file for the start of the ** payload to which the cursor is pointing. */ SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); getCellInfo(pCur); return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) + (i64)(pCur->info.pPayload - pCur->pPage->aData); } /* ** Return the number of bytes of payload for the entry that pCur is ** currently pointing to. For table btrees, this will be the amount ** of data. For index btrees, this will be the size of the key. ** ** The caller must guarantee that the cursor is pointing to a non-NULL ** valid entry. In other words, the calling procedure must guarantee ** that the cursor has Cursor.eState==CURSOR_VALID. */ SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); getCellInfo(pCur); return pCur->info.nPayload; } /* ** Return an upper bound on the size of any record for the table ** that the cursor is pointing into. ** ** This is an optimization. Everything will still work if this ** routine always returns 2147483647 (which is the largest record ** that SQLite can handle) or more. But returning a smaller value might ** prevent large memory allocations when trying to interpret a ** corrupt database. ** ** The current implementation merely returns the size of the underlying ** database file. */ SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); return pCur->pBt->pageSize * (sqlite3_int64)pCur->pBt->nPage; } /* ** Given the page number of an overflow page in the database (parameter ** ovfl), this function finds the page number of the next page in the ** linked list of overflow pages. If possible, it uses the auto-vacuum ** pointer-map data instead of reading the content of page ovfl to do so. ** ** If an error occurs an SQLite error code is returned. Otherwise: ** ** The page number of the next overflow page in the linked list is ** written to *pPgnoNext. If page ovfl is the last page in its linked ** list, *pPgnoNext is set to zero. ** ** If ppPage is not NULL, and a reference to the MemPage object corresponding ** to page number pOvfl was obtained, then *ppPage is set to point to that ** reference. It is the responsibility of the caller to call releasePage() ** on *ppPage to free the reference. In no reference was obtained (because ** the pointer-map was used to obtain the value for *pPgnoNext), then ** *ppPage is set to zero. */ static int getOverflowPage( BtShared *pBt, /* The database file */ Pgno ovfl, /* Current overflow page number */ MemPage **ppPage, /* OUT: MemPage handle (may be NULL) */ Pgno *pPgnoNext /* OUT: Next overflow page number */ ){ Pgno next = 0; MemPage *pPage = 0; int rc = SQLITE_OK; assert( sqlite3_mutex_held(pBt->mutex) ); assert(pPgnoNext); #ifndef SQLITE_OMIT_AUTOVACUUM /* Try to find the next page in the overflow list using the ** autovacuum pointer-map pages. Guess that the next page in ** the overflow list is page number (ovfl+1). If that guess turns ** out to be wrong, fall back to loading the data of page ** number ovfl to determine the next page number. */ if( pBt->autoVacuum ){ Pgno pgno; Pgno iGuess = ovfl+1; u8 eType; while( PTRMAP_ISPAGE(pBt, iGuess) || iGuess==PENDING_BYTE_PAGE(pBt) ){ iGuess++; } if( iGuess<=btreePagecount(pBt) ){ rc = ptrmapGet(pBt, iGuess, &eType, &pgno); if( rc==SQLITE_OK && eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){ next = iGuess; rc = SQLITE_DONE; } } } #endif assert( next==0 || rc==SQLITE_DONE ); if( rc==SQLITE_OK ){ rc = btreeGetPage(pBt, ovfl, &pPage, (ppPage==0) ? PAGER_GET_READONLY : 0); assert( rc==SQLITE_OK || pPage==0 ); if( rc==SQLITE_OK ){ next = get4byte(pPage->aData); } } *pPgnoNext = next; if( ppPage ){ *ppPage = pPage; }else{ releasePage(pPage); } return (rc==SQLITE_DONE ? SQLITE_OK : rc); } /* ** Copy data from a buffer to a page, or from a page to a buffer. ** ** pPayload is a pointer to data stored on database page pDbPage. ** If argument eOp is false, then nByte bytes of data are copied ** from pPayload to the buffer pointed at by pBuf. If eOp is true, ** then sqlite3PagerWrite() is called on pDbPage and nByte bytes ** of data are copied from the buffer pBuf to pPayload. ** ** SQLITE_OK is returned on success, otherwise an error code. */ static int copyPayload( void *pPayload, /* Pointer to page data */ void *pBuf, /* Pointer to buffer */ int nByte, /* Number of bytes to copy */ int eOp, /* 0 -> copy from page, 1 -> copy to page */ DbPage *pDbPage /* Page containing pPayload */ ){ if( eOp ){ /* Copy data from buffer to page (a write operation) */ int rc = sqlite3PagerWrite(pDbPage); if( rc!=SQLITE_OK ){ return rc; } memcpy(pPayload, pBuf, nByte); }else{ /* Copy data from page to buffer (a read operation) */ memcpy(pBuf, pPayload, nByte); } return SQLITE_OK; } /* ** This function is used to read or overwrite payload information ** for the entry that the pCur cursor is pointing to. The eOp ** argument is interpreted as follows: ** ** 0: The operation is a read. Populate the overflow cache. ** 1: The operation is a write. Populate the overflow cache. ** ** A total of "amt" bytes are read or written beginning at "offset". ** Data is read to or from the buffer pBuf. ** ** The content being read or written might appear on the main page ** or be scattered out on multiple overflow pages. ** ** If the current cursor entry uses one or more overflow pages ** this function may allocate space for and lazily populate ** the overflow page-list cache array (BtCursor.aOverflow). ** Subsequent calls use this cache to make seeking to the supplied offset ** more efficient. ** ** Once an overflow page-list cache has been allocated, it must be ** invalidated if some other cursor writes to the same table, or if ** the cursor is moved to a different row. Additionally, in auto-vacuum ** mode, the following events may invalidate an overflow page-list cache. ** ** * An incremental vacuum, ** * A commit in auto_vacuum="full" mode, ** * Creating a table (may require moving an overflow page). */ static int accessPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 offset, /* Begin reading this far into payload */ u32 amt, /* Read this many bytes */ unsigned char *pBuf, /* Write the bytes into this buffer */ int eOp /* zero to read. non-zero to write. */ ){ unsigned char *aPayload; int rc = SQLITE_OK; int iIdx = 0; MemPage *pPage = pCur->pPage; /* Btree page of current entry */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ #ifdef SQLITE_DIRECT_OVERFLOW_READ unsigned char * const pBufStart = pBuf; /* Start of original out buffer */ #endif assert( pPage ); assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); if( pCur->ix>=pPage->nCell ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( cursorHoldsMutex(pCur) ); getCellInfo(pCur); aPayload = pCur->info.pPayload; assert( offset+amt <= pCur->info.nPayload ); assert( aPayload > pPage->aData ); if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){ /* Trying to read or write past the end of the data is an error. The ** conditional above is really: ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ** but is recast into its current form to avoid integer overflow problems */ return SQLITE_CORRUPT_PAGE(pPage); } /* Check if data must be read/written to/from the btree page itself. */ if( offsetinfo.nLocal ){ int a = amt; if( a+offset>pCur->info.nLocal ){ a = pCur->info.nLocal - offset; } rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage); offset = 0; pBuf += a; amt -= a; }else{ offset -= pCur->info.nLocal; } if( rc==SQLITE_OK && amt>0 ){ const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */ Pgno nextPage; nextPage = get4byte(&aPayload[pCur->info.nLocal]); /* If the BtCursor.aOverflow[] has not been allocated, allocate it now. ** ** The aOverflow[] array is sized at one entry for each overflow page ** in the overflow chain. The page number of the first overflow page is ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array ** means "not yet known" (the cache is lazily populated). */ if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; if( pCur->aOverflow==0 || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow) ){ Pgno *aNew = (Pgno*)sqlite3Realloc( pCur->aOverflow, nOvfl*2*sizeof(Pgno) ); if( aNew==0 ){ return SQLITE_NOMEM_BKPT; }else{ pCur->aOverflow = aNew; } } memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno)); pCur->curFlags |= BTCF_ValidOvfl; }else{ /* If the overflow page-list cache has been allocated and the ** entry for the first required overflow page is valid, skip ** directly to it. */ if( pCur->aOverflow[offset/ovflSize] ){ iIdx = (offset/ovflSize); nextPage = pCur->aOverflow[iIdx]; offset = (offset%ovflSize); } } assert( rc==SQLITE_OK && amt>0 ); while( nextPage ){ /* If required, populate the overflow page-list cache. */ if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT; assert( pCur->aOverflow[iIdx]==0 || pCur->aOverflow[iIdx]==nextPage || CORRUPT_DB ); pCur->aOverflow[iIdx] = nextPage; if( offset>=ovflSize ){ /* The only reason to read this page is to obtain the page ** number for the next page in the overflow chain. The page ** data is not required. So first try to lookup the overflow ** page-list cache, if any, then fall back to the getOverflowPage() ** function. */ assert( pCur->curFlags & BTCF_ValidOvfl ); assert( pCur->pBtree->db==pBt->db ); if( pCur->aOverflow[iIdx+1] ){ nextPage = pCur->aOverflow[iIdx+1]; }else{ rc = getOverflowPage(pBt, nextPage, 0, &nextPage); } offset -= ovflSize; }else{ /* Need to read this page properly. It contains some of the ** range of data that is being read (eOp==0) or written (eOp!=0). */ int a = amt; if( a + offset > ovflSize ){ a = ovflSize - offset; } #ifdef SQLITE_DIRECT_OVERFLOW_READ /* If all the following are true: ** ** 1) this is a read operation, and ** 2) data is required from the start of this overflow page, and ** 3) there are no dirty pages in the page-cache ** 4) the database is file-backed, and ** 5) the page is not in the WAL file ** 6) at least 4 bytes have already been read into the output buffer ** ** then data can be read directly from the database file into the ** output buffer, bypassing the page-cache altogether. This speeds ** up loading large records that span many overflow pages. */ if( eOp==0 /* (1) */ && offset==0 /* (2) */ && sqlite3PagerDirectReadOk(pBt->pPager, nextPage) /* (3,4,5) */ && &pBuf[-4]>=pBufStart /* (6) */ ){ sqlite3_file *fd = sqlite3PagerFile(pBt->pPager); u8 aSave[4]; u8 *aWrite = &pBuf[-4]; assert( aWrite>=pBufStart ); /* due to (6) */ memcpy(aSave, aWrite, 4); rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1)); nextPage = get4byte(aWrite); memcpy(aWrite, aSave, 4); }else #endif { DbPage *pDbPage; rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage, (eOp==0 ? PAGER_GET_READONLY : 0) ); if( rc==SQLITE_OK ){ aPayload = sqlite3PagerGetData(pDbPage); nextPage = get4byte(aPayload); rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); sqlite3PagerUnref(pDbPage); offset = 0; } } amt -= a; if( amt==0 ) return rc; pBuf += a; } if( rc ) break; iIdx++; } } if( rc==SQLITE_OK && amt>0 ){ /* Overflow chain ends prematurely */ return SQLITE_CORRUPT_PAGE(pPage); } return rc; } /* ** Read part of the payload for the row at which that cursor pCur is currently ** pointing. "amt" bytes will be transferred into pBuf[]. The transfer ** begins at "offset". ** ** pCur can be pointing to either a table or an index b-tree. ** If pointing to a table btree, then the content section is read. If ** pCur is pointing to an index b-tree then the key section is read. ** ** For sqlite3BtreePayload(), the caller must ensure that pCur is pointing ** to a valid row in the table. For sqlite3BtreePayloadChecked(), the ** cursor might be invalid or might need to be restored before being read. ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 && pCur->pPage ); return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } /* ** This variant of sqlite3BtreePayload() works even if the cursor has not ** in the CURSOR_VALID state. It is only used by the sqlite3_blob_read() ** interface. */ #ifndef SQLITE_OMIT_INCRBLOB static SQLITE_NOINLINE int accessPayloadChecked( BtCursor *pCur, u32 offset, u32 amt, void *pBuf ){ int rc; if ( pCur->eState==CURSOR_INVALID ){ return SQLITE_ABORT; } assert( cursorOwnsBtShared(pCur) ); rc = btreeRestoreCursorPosition(pCur); return rc ? rc : accessPayload(pCur, offset, amt, pBuf, 0); } SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ if( pCur->eState==CURSOR_VALID ){ assert( cursorOwnsBtShared(pCur) ); return accessPayload(pCur, offset, amt, pBuf, 0); }else{ return accessPayloadChecked(pCur, offset, amt, pBuf); } } #endif /* SQLITE_OMIT_INCRBLOB */ /* ** Return a pointer to payload information from the entry that the ** pCur cursor is pointing to. The pointer is to the beginning of ** the key if index btrees (pPage->intKey==0) and is the data for ** table btrees (pPage->intKey==1). The number of bytes of available ** key/data is written into *pAmt. If *pAmt==0, then the value ** returned will not be a valid pointer. ** ** This routine is an optimization. It is common for the entire key ** and data to fit on the local page and for there to be no overflow ** pages. When that is so, this routine can be used to access the ** key and data without making a copy. If the key and/or data spills ** onto overflow pages, then accessPayload() must be used to reassemble ** the key/data and copy it into a preallocated buffer. ** ** The pointer returned by this routine looks directly into the cached ** page of the database. The data might change or move the next time ** any btree routine is called. */ static const void *fetchPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 *pAmt /* Write the number of available bytes here */ ){ int amt; assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage); assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorOwnsBtShared(pCur) ); assert( pCur->ixpPage->nCell || CORRUPT_DB ); assert( pCur->info.nSize>0 ); assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB ); assert( pCur->info.pPayloadpPage->aDataEnd ||CORRUPT_DB); amt = pCur->info.nLocal; if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){ /* There is too little space on the page for the expected amount ** of local content. Database must be corrupt. */ assert( CORRUPT_DB ); amt = MAX(0, (int)(pCur->pPage->aDataEnd - pCur->info.pPayload)); } *pAmt = (u32)amt; return (void*)pCur->info.pPayload; } /* ** For the entry that cursor pCur is point to, return as ** many bytes of the key or data as are available on the local ** b-tree page. Write the number of available bytes into *pAmt. ** ** The pointer returned is ephemeral. The key/data may move ** or be destroyed on the next call to any Btree routine, ** including calls from other threads against the same cache. ** Hence, a mutex on the BtShared should be held prior to calling ** this routine. ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){ return fetchPayload(pCur, pAmt); } /* ** Move the cursor down to a new child page. The newPgno argument is the ** page number of the child page to move to. ** ** This function returns SQLITE_CORRUPT if the page-header flags field of ** the new child page does not match the flags field of the parent (i.e. ** if an intkey page appears to be the parent of a non-intkey page, or ** vice-versa). */ static int moveToChild(BtCursor *pCur, u32 newPgno){ int rc; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPageiPage>=0 ); if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ return SQLITE_CORRUPT_BKPT; } pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); pCur->aiIdx[pCur->iPage] = pCur->ix; pCur->apPage[pCur->iPage] = pCur->pPage; pCur->ix = 0; pCur->iPage++; rc = getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur->curPagerFlags); assert( pCur->pPage!=0 || rc!=SQLITE_OK ); if( rc==SQLITE_OK && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey) ){ releasePage(pCur->pPage); rc = SQLITE_CORRUPT_PGNO(newPgno); } if( rc ){ pCur->pPage = pCur->apPage[--pCur->iPage]; } return rc; } #ifdef SQLITE_DEBUG /* ** Page pParent is an internal (non-leaf) tree page. This function ** asserts that page number iChild is the left-child if the iIdx'th ** cell in page pParent. Or, if iIdx is equal to the total number of ** cells in pParent, that page number iChild is the right-child of ** the page. */ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){ if( CORRUPT_DB ) return; /* The conditions tested below might not be true ** in a corrupt database */ assert( iIdx<=pParent->nCell ); if( iIdx==pParent->nCell ){ assert( get4byte(&pParent->aData[pParent->hdrOffset+8])==iChild ); }else{ assert( get4byte(findCell(pParent, iIdx))==iChild ); } } #else # define assertParentIndex(x,y,z) #endif /* ** Move the cursor up to the parent page. ** ** pCur->idx is set to the cell index that contains the pointer ** to the page we are coming from. If we are coming from the ** right-most child page then pCur->idx is set to one more than ** the largest cell index. */ static void moveToParent(BtCursor *pCur){ MemPage *pLeaf; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>0 ); assert( pCur->pPage ); assertParentIndex( pCur->apPage[pCur->iPage-1], pCur->aiIdx[pCur->iPage-1], pCur->pPage->pgno ); testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); pCur->ix = pCur->aiIdx[pCur->iPage-1]; pLeaf = pCur->pPage; pCur->pPage = pCur->apPage[--pCur->iPage]; releasePageNotNull(pLeaf); } /* ** Move the cursor to point to the root page of its b-tree structure. ** ** If the table has a virtual root page, then the cursor is moved to point ** to the virtual root page instead of the actual root page. A table has a ** virtual root page when the actual root page contains no cells and a ** single child page. This can only happen with the table rooted at page 1. ** ** If the b-tree structure is empty, the cursor state is set to ** CURSOR_INVALID and this routine returns SQLITE_EMPTY. Otherwise, ** the cursor is set to point to the first cell located on the root ** (or virtual root) page and the cursor state is set to CURSOR_VALID. ** ** If this function returns successfully, it may be assumed that the ** page-header flags indicate that the [virtual] root-page is the expected ** kind of b-tree page (i.e. if when opening the cursor the caller did not ** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D, ** indicating a table b-tree, or if the caller did specify a KeyInfo ** structure the flags byte is set to 0x02 or 0x0A, indicating an index ** b-tree). */ static int moveToRoot(BtCursor *pCur){ MemPage *pRoot; int rc = SQLITE_OK; assert( cursorOwnsBtShared(pCur) ); assert( CURSOR_INVALID < CURSOR_REQUIRESEEK ); assert( CURSOR_VALID < CURSOR_REQUIRESEEK ); assert( CURSOR_FAULT > CURSOR_REQUIRESEEK ); assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 ); assert( pCur->pgnoRoot>0 || pCur->iPage<0 ); if( pCur->iPage>=0 ){ if( pCur->iPage ){ releasePageNotNull(pCur->pPage); while( --pCur->iPage ){ releasePageNotNull(pCur->apPage[pCur->iPage]); } pRoot = pCur->pPage = pCur->apPage[0]; goto skip_init; } }else if( pCur->pgnoRoot==0 ){ pCur->eState = CURSOR_INVALID; return SQLITE_EMPTY; }else{ assert( pCur->iPage==(-1) ); if( pCur->eState>=CURSOR_REQUIRESEEK ){ if( pCur->eState==CURSOR_FAULT ){ assert( pCur->skipNext!=SQLITE_OK ); return pCur->skipNext; } sqlite3BtreeClearCursor(pCur); } rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage, pCur->curPagerFlags); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; } pCur->iPage = 0; pCur->curIntKey = pCur->pPage->intKey; } pRoot = pCur->pPage; assert( pRoot->pgno==pCur->pgnoRoot || CORRUPT_DB ); /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor ** expected to open it on an index b-tree. Otherwise, if pKeyInfo is ** NULL, the caller expects a table b-tree. If this is not the case, ** return an SQLITE_CORRUPT error. ** ** Earlier versions of SQLite assumed that this test could not fail ** if the root page was already loaded when this function was called (i.e. ** if pCur->iPage>=0). But this is not so if the database is corrupted ** in such a way that page pRoot is linked into a second b-tree table ** (or the freelist). */ assert( pRoot->intKey==1 || pRoot->intKey==0 ); if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ return SQLITE_CORRUPT_PAGE(pCur->pPage); } skip_init: pCur->ix = 0; pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); if( pRoot->nCell>0 ){ pCur->eState = CURSOR_VALID; }else if( !pRoot->leaf ){ Pgno subpage; if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT; subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); pCur->eState = CURSOR_VALID; rc = moveToChild(pCur, subpage); }else{ pCur->eState = CURSOR_INVALID; rc = SQLITE_EMPTY; } return rc; } /* ** Move the cursor down to the left-most leaf entry beneath the ** entry to which it is currently pointing. ** ** The left-most leaf is the one with the smallest key - the first ** in ascending order. */ static int moveToLeftmost(BtCursor *pCur){ Pgno pgno; int rc = SQLITE_OK; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ assert( pCur->ixnCell ); pgno = get4byte(findCell(pPage, pCur->ix)); rc = moveToChild(pCur, pgno); } return rc; } /* ** Move the cursor down to the right-most leaf entry beneath the ** page to which it is currently pointing. Notice the difference ** between moveToLeftmost() and moveToRightmost(). moveToLeftmost() ** finds the left-most entry beneath the *entry* whereas moveToRightmost() ** finds the right-most entry beneath the *page*. ** ** The right-most entry is the one with the largest key - the last ** key in ascending order. */ static int moveToRightmost(BtCursor *pCur){ Pgno pgno; int rc = SQLITE_OK; MemPage *pPage = 0; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); while( !(pPage = pCur->pPage)->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); pCur->ix = pPage->nCell; rc = moveToChild(pCur, pgno); if( rc ) return rc; } pCur->ix = pPage->nCell-1; assert( pCur->info.nSize==0 ); assert( (pCur->curFlags & BTCF_ValidNKey)==0 ); return SQLITE_OK; } /* Move the cursor to the first entry in the table. Return SQLITE_OK ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. */ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int rc; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ assert( pCur->pPage->nCell>0 ); *pRes = 0; rc = moveToLeftmost(pCur); }else if( rc==SQLITE_EMPTY ){ assert( pCur->pgnoRoot==0 || (pCur->pPage!=0 && pCur->pPage->nCell==0) ); *pRes = 1; rc = SQLITE_OK; } return rc; } /* Move the cursor to the last entry in the table. Return SQLITE_OK ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. */ static SQLITE_NOINLINE int btreeLast(BtCursor *pCur, int *pRes){ int rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); *pRes = 0; rc = moveToRightmost(pCur); if( rc==SQLITE_OK ){ pCur->curFlags |= BTCF_AtLast; }else{ pCur->curFlags &= ~BTCF_AtLast; } }else if( rc==SQLITE_EMPTY ){ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); *pRes = 1; rc = SQLITE_OK; } return rc; } SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* If the cursor already points to the last entry, this is a no-op. */ if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){ #ifdef SQLITE_DEBUG /* This block serves to assert() that the cursor really does point ** to the last entry in the b-tree. */ int ii; for(ii=0; iiiPage; ii++){ assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell ); } assert( pCur->ix==pCur->pPage->nCell-1 || CORRUPT_DB ); testcase( pCur->ix!=pCur->pPage->nCell-1 ); /* ^-- dbsqlfuzz b92b72e4de80b5140c30ab71372ca719b8feb618 */ assert( pCur->pPage->leaf ); #endif *pRes = 0; return SQLITE_OK; } return btreeLast(pCur, pRes); } /* Move the cursor so that it points to an entry in a table (a.k.a INTKEY) ** table near the key intKey. Return a success code. ** ** If an exact match is not found, then the cursor is always ** left pointing at a leaf page which would hold the entry if it ** were present. The cursor might point to an entry that comes ** before or after the key. ** ** An integer is written into *pRes which is the result of ** comparing the key with the entry to which the cursor is ** pointing. The meaning of the integer written into ** *pRes is as follows: ** ** *pRes<0 The cursor is left pointing at an entry that ** is smaller than intKey or if the table is empty ** and the cursor is therefore left point to nothing. ** ** *pRes==0 The cursor is left pointing at an entry that ** exactly matches intKey. ** ** *pRes>0 The cursor is left pointing at an entry that ** is larger than intKey. */ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( BtCursor *pCur, /* The cursor to be moved */ i64 intKey, /* The table key */ int biasRight, /* If true, bias the search to the high end */ int *pRes /* Write search results here */ ){ int rc; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( pCur->pKeyInfo==0 ); assert( pCur->eState!=CURSOR_VALID || pCur->curIntKey!=0 ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; } if( pCur->info.nKeycurFlags & BTCF_AtLast)!=0 ){ *pRes = -1; return SQLITE_OK; } /* If the requested key is one more than the previous key, then ** try to get there using sqlite3BtreeNext() rather than a full ** binary search. This is an optimization only. The correct answer ** is still obtained without this case, only a little more slowly. */ if( pCur->info.nKey+1==intKey ){ *pRes = 0; rc = sqlite3BtreeNext(pCur, 0); if( rc==SQLITE_OK ){ getCellInfo(pCur); if( pCur->info.nKey==intKey ){ return SQLITE_OK; } }else if( rc!=SQLITE_DONE ){ return rc; } } } } #ifdef SQLITE_DEBUG pCur->pBtree->nSeek++; /* Performance measurement during testing */ #endif rc = moveToRoot(pCur); if( rc ){ if( rc==SQLITE_EMPTY ){ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); *pRes = -1; return SQLITE_OK; } return rc; } assert( pCur->pPage ); assert( pCur->pPage->isInit ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage->nCell > 0 ); assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey ); assert( pCur->curIntKey ); for(;;){ int lwr, upr, idx, c; Pgno chldPg; MemPage *pPage = pCur->pPage; u8 *pCell; /* Pointer to current cell in pPage */ /* pPage->nCell must be greater than zero. If this is the root-page ** the cursor would have been INVALID above and this for(;;) loop ** not run. If this is not the root-page, then the moveToChild() routine ** would have already detected db corruption. Similarly, pPage must ** be the right kind (index or table) of b-tree page. Otherwise ** a moveToChild() or moveToRoot() call would have detected corruption. */ assert( pPage->nCell>0 ); assert( pPage->intKey ); lwr = 0; upr = pPage->nCell-1; assert( biasRight==0 || biasRight==1 ); idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */ for(;;){ i64 nCellKey; pCell = findCellPastPtr(pPage, idx); if( pPage->intKeyLeaf ){ while( 0x80 <= *(pCell++) ){ if( pCell>=pPage->aDataEnd ){ return SQLITE_CORRUPT_PAGE(pPage); } } } getVarint(pCell, (u64*)&nCellKey); if( nCellKeyupr ){ c = -1; break; } }else if( nCellKey>intKey ){ upr = idx-1; if( lwr>upr ){ c = +1; break; } }else{ assert( nCellKey==intKey ); pCur->ix = (u16)idx; if( !pPage->leaf ){ lwr = idx; goto moveto_table_next_layer; }else{ pCur->curFlags |= BTCF_ValidNKey; pCur->info.nKey = nCellKey; pCur->info.nSize = 0; *pRes = 0; return SQLITE_OK; } } assert( lwr+upr>=0 ); idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ } assert( lwr==upr+1 || !pPage->leaf ); assert( pPage->isInit ); if( pPage->leaf ){ assert( pCur->ixpPage->nCell ); pCur->ix = (u16)idx; *pRes = c; rc = SQLITE_OK; goto moveto_table_finish; } moveto_table_next_layer: if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ chldPg = get4byte(findCell(pPage, lwr)); } pCur->ix = (u16)lwr; rc = moveToChild(pCur, chldPg); if( rc ) break; } moveto_table_finish: pCur->info.nSize = 0; assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); return rc; } /* ** Compare the "idx"-th cell on the page the cursor pCur is currently ** pointing to to pIdxKey using xRecordCompare. Return negative or ** zero if the cell is less than or equal pIdxKey. Return positive ** if unknown. ** ** Return value negative: Cell at pCur[idx] less than pIdxKey ** ** Return value is zero: Cell at pCur[idx] equals pIdxKey ** ** Return value positive: Nothing is known about the relationship ** of the cell at pCur[idx] and pIdxKey. ** ** This routine is part of an optimization. It is always safe to return ** a positive value as that will cause the optimization to be skipped. */ static int indexCellCompare( BtCursor *pCur, int idx, UnpackedRecord *pIdxKey, RecordCompare xRecordCompare ){ MemPage *pPage = pCur->pPage; int c; int nCell; /* Size of the pCell cell in bytes */ u8 *pCell = findCellPastPtr(pPage, idx); nCell = pCell[0]; if( nCell<=pPage->max1bytePayload ){ /* This branch runs if the record-size field of the cell is a ** single byte varint and the record fits entirely on the main ** b-tree page. */ testcase( pCell+nCell+1==pPage->aDataEnd ); c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ testcase( pCell+nCell+2==pPage->aDataEnd ); c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* If the record extends into overflow pages, do not attempt ** the optimization. */ c = 99; } return c; } /* ** Return true (non-zero) if pCur is current pointing to the last ** page of a table. */ static int cursorOnLastPage(BtCursor *pCur){ int i; assert( pCur->eState==CURSOR_VALID ); for(i=0; iiPage; i++){ MemPage *pPage = pCur->apPage[i]; if( pCur->aiIdx[i]nCell ) return 0; } return 1; } /* Move the cursor so that it points to an entry in an index table ** near the key pIdxKey. Return a success code. ** ** If an exact match is not found, then the cursor is always ** left pointing at a leaf page which would hold the entry if it ** were present. The cursor might point to an entry that comes ** before or after the key. ** ** An integer is written into *pRes which is the result of ** comparing the key with the entry to which the cursor is ** pointing. The meaning of the integer written into ** *pRes is as follows: ** ** *pRes<0 The cursor is left pointing at an entry that ** is smaller than pIdxKey or if the table is empty ** and the cursor is therefore left point to nothing. ** ** *pRes==0 The cursor is left pointing at an entry that ** exactly matches pIdxKey. ** ** *pRes>0 The cursor is left pointing at an entry that ** is larger than pIdxKey. ** ** The pIdxKey->eqSeen field is set to 1 if there ** exists an entry in the table that exactly matches pIdxKey. */ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( BtCursor *pCur, /* The cursor to be moved */ UnpackedRecord *pIdxKey, /* Unpacked index key */ int *pRes /* Write search results here */ ){ int rc; RecordCompare xRecordCompare; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( pCur->pKeyInfo!=0 ); #ifdef SQLITE_DEBUG pCur->pBtree->nSeek++; /* Performance measurement during testing */ #endif xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); pIdxKey->errCode = 0; assert( pIdxKey->default_rc==1 || pIdxKey->default_rc==0 || pIdxKey->default_rc==-1 ); /* Check to see if we can skip a lot of work. Two cases: ** ** (1) If the cursor is already pointing to the very last cell ** in the table and the pIdxKey search key is greater than or ** equal to that last cell, then no movement is required. ** ** (2) If the cursor is on the last page of the table and the first ** cell on that last page is less than or equal to the pIdxKey ** search key, then we can start the search on the current page ** without needing to go back to root. */ if( pCur->eState==CURSOR_VALID && pCur->pPage->leaf && cursorOnLastPage(pCur) ){ int c; if( pCur->ix==pCur->pPage->nCell-1 && (c = indexCellCompare(pCur, pCur->ix, pIdxKey, xRecordCompare))<=0 && pIdxKey->errCode==SQLITE_OK ){ *pRes = c; return SQLITE_OK; /* Cursor already pointing at the correct spot */ } if( pCur->iPage>0 && indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0 && pIdxKey->errCode==SQLITE_OK ){ pCur->curFlags &= ~BTCF_ValidOvfl; if( !pCur->pPage->isInit ){ return SQLITE_CORRUPT_BKPT; } goto bypass_moveto_root; /* Start search on the current page */ } pIdxKey->errCode = SQLITE_OK; } rc = moveToRoot(pCur); if( rc ){ if( rc==SQLITE_EMPTY ){ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); *pRes = -1; return SQLITE_OK; } return rc; } bypass_moveto_root: assert( pCur->pPage ); assert( pCur->pPage->isInit ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage->nCell > 0 ); assert( pCur->curIntKey==0 ); assert( pIdxKey!=0 ); for(;;){ int lwr, upr, idx, c; Pgno chldPg; MemPage *pPage = pCur->pPage; u8 *pCell; /* Pointer to current cell in pPage */ /* pPage->nCell must be greater than zero. If this is the root-page ** the cursor would have been INVALID above and this for(;;) loop ** not run. If this is not the root-page, then the moveToChild() routine ** would have already detected db corruption. Similarly, pPage must ** be the right kind (index or table) of b-tree page. Otherwise ** a moveToChild() or moveToRoot() call would have detected corruption. */ assert( pPage->nCell>0 ); assert( pPage->intKey==0 ); lwr = 0; upr = pPage->nCell-1; idx = upr>>1; /* idx = (lwr+upr)/2; */ for(;;){ int nCell; /* Size of the pCell cell in bytes */ pCell = findCellPastPtr(pPage, idx); /* The maximum supported page-size is 65536 bytes. This means that ** the maximum number of record bytes stored on an index B-Tree ** page is less than 16384 bytes and may be stored as a 2-byte ** varint. This information is used to attempt to avoid parsing ** the entire cell by checking for the cases where the record is ** stored entirely within the b-tree page by inspecting the first ** 2 bytes of the cell. */ nCell = pCell[0]; if( nCell<=pPage->max1bytePayload ){ /* This branch runs if the record-size field of the cell is a ** single byte varint and the record fits entirely on the main ** b-tree page. */ testcase( pCell+nCell+1==pPage->aDataEnd ); c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ testcase( pCell+nCell+2==pPage->aDataEnd ); c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* The record flows over onto one or more overflow pages. In ** this case the whole cell needs to be parsed, a buffer allocated ** and accessPayload() used to retrieve the record into the ** buffer before VdbeRecordCompare() can be called. ** ** If the record is corrupt, the xRecordCompare routine may read ** up to two varints past the end of the buffer. An extra 18 ** bytes of padding is allocated at the end of the buffer in ** case this happens. */ void *pCellKey; u8 * const pCellBody = pCell - pPage->childPtrSize; const int nOverrun = 18; /* Size of the overrun padding */ pPage->xParseCell(pPage, pCellBody, &pCur->info); nCell = (int)pCur->info.nKey; testcase( nCell<0 ); /* True if key size is 2^32 or more */ testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ testcase( nCell==2 ); /* Minimum legal index key size */ if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ rc = SQLITE_CORRUPT_PAGE(pPage); goto moveto_index_finish; } pCellKey = sqlite3Malloc( nCell+nOverrun ); if( pCellKey==0 ){ rc = SQLITE_NOMEM_BKPT; goto moveto_index_finish; } pCur->ix = (u16)idx; rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */ pCur->curFlags &= ~BTCF_ValidOvfl; if( rc ){ sqlite3_free(pCellKey); goto moveto_index_finish; } c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); sqlite3_free(pCellKey); } assert( (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) ); if( c<0 ){ lwr = idx+1; }else if( c>0 ){ upr = idx-1; }else{ assert( c==0 ); *pRes = 0; rc = SQLITE_OK; pCur->ix = (u16)idx; if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT; goto moveto_index_finish; } if( lwr>upr ) break; assert( lwr+upr>=0 ); idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */ } assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); assert( pPage->isInit ); if( pPage->leaf ){ assert( pCur->ixpPage->nCell || CORRUPT_DB ); pCur->ix = (u16)idx; *pRes = c; rc = SQLITE_OK; goto moveto_index_finish; } if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ chldPg = get4byte(findCell(pPage, lwr)); } /* This block is similar to an in-lined version of: ** ** pCur->ix = (u16)lwr; ** rc = moveToChild(pCur, chldPg); ** if( rc ) break; */ pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ return SQLITE_CORRUPT_BKPT; } pCur->aiIdx[pCur->iPage] = (u16)lwr; pCur->apPage[pCur->iPage] = pCur->pPage; pCur->ix = 0; pCur->iPage++; rc = getAndInitPage(pCur->pBt, chldPg, &pCur->pPage, pCur->curPagerFlags); if( rc==SQLITE_OK && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey) ){ releasePage(pCur->pPage); rc = SQLITE_CORRUPT_PGNO(chldPg); } if( rc ){ pCur->pPage = pCur->apPage[--pCur->iPage]; break; } /* ***** End of in-lined moveToChild() call */ } moveto_index_finish: pCur->info.nSize = 0; assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); return rc; } /* ** Return TRUE if the cursor is not pointing at an entry of the table. ** ** TRUE will be returned after a call to sqlite3BtreeNext() moves ** past the last entry in the table or sqlite3BtreePrev() moves past ** the first entry. TRUE is also returned if the table is empty. */ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){ /* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries ** have been deleted? This API will need to change to return an error code ** as well as the boolean result value. */ return (CURSOR_VALID!=pCur->eState); } /* ** Return an estimate for the number of rows in the table that pCur is ** pointing to. Return a negative number if no estimate is currently ** available. */ SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){ i64 n; u8 i; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* Currently this interface is only called by the OP_IfSmaller ** opcode, and it that case the cursor will always be valid and ** will always point to a leaf node. */ if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1; if( NEVER(pCur->pPage->leaf==0) ) return -1; n = pCur->pPage->nCell; for(i=0; iiPage; i++){ n *= pCur->apPage[i]->nCell; } return n; } /* ** Advance the cursor to the next entry in the database. ** Return value: ** ** SQLITE_OK success ** SQLITE_DONE cursor is already pointing at the last element ** otherwise some kind of error occurred ** ** The main entry point is sqlite3BtreeNext(). That routine is optimized ** for the common case of merely incrementing the cell counter BtCursor.aiIdx ** to the next cell on the current page. The (slower) btreeNext() helper ** routine is called when it is necessary to move to a different page or ** to restore the cursor. ** ** If bit 0x01 of the F argument in sqlite3BtreeNext(C,F) is 1, then the ** cursor corresponds to an SQL index and this routine could have been ** skipped if the SQL index had been a unique index. The F argument ** is a hint to the implement. SQLite btree implementation does not use ** this hint, but COMDB2 does. */ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ int rc; int idx; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); if( pCur->eState!=CURSOR_VALID ){ assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; } if( CURSOR_INVALID==pCur->eState ){ return SQLITE_DONE; } if( pCur->eState==CURSOR_SKIPNEXT ){ pCur->eState = CURSOR_VALID; if( pCur->skipNext>0 ) return SQLITE_OK; } } pPage = pCur->pPage; idx = ++pCur->ix; if( sqlite3FaultSim(412) ) pPage->isInit = 0; if( !pPage->isInit ){ return SQLITE_CORRUPT_BKPT; } if( idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); if( rc ) return rc; return moveToLeftmost(pCur); } do{ if( pCur->iPage==0 ){ pCur->eState = CURSOR_INVALID; return SQLITE_DONE; } moveToParent(pCur); pPage = pCur->pPage; }while( pCur->ix>=pPage->nCell ); if( pPage->intKey ){ return sqlite3BtreeNext(pCur, 0); }else{ return SQLITE_OK; } } if( pPage->leaf ){ return SQLITE_OK; }else{ return moveToLeftmost(pCur); } } SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int flags){ MemPage *pPage; UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ assert( cursorOwnsBtShared(pCur) ); assert( flags==0 || flags==1 ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur); pPage = pCur->pPage; if( (++pCur->ix)>=pPage->nCell ){ pCur->ix--; return btreeNext(pCur); } if( pPage->leaf ){ return SQLITE_OK; }else{ return moveToLeftmost(pCur); } } /* ** Step the cursor to the back to the previous entry in the database. ** Return values: ** ** SQLITE_OK success ** SQLITE_DONE the cursor is already on the first element of the table ** otherwise some kind of error occurred ** ** The main entry point is sqlite3BtreePrevious(). That routine is optimized ** for the common case of merely decrementing the cell counter BtCursor.aiIdx ** to the previous cell on the current page. The (slower) btreePrevious() ** helper routine is called when it is necessary to move to a different page ** or to restore the cursor. ** ** If bit 0x01 of the F argument to sqlite3BtreePrevious(C,F) is 1, then ** the cursor corresponds to an SQL index and this routine could have been ** skipped if the SQL index had been a unique index. The F argument is a ** hint to the implement. The native SQLite btree implementation does not ** use this hint, but COMDB2 does. */ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){ int rc; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 ); assert( pCur->info.nSize==0 ); if( pCur->eState!=CURSOR_VALID ){ rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; } if( CURSOR_INVALID==pCur->eState ){ return SQLITE_DONE; } if( CURSOR_SKIPNEXT==pCur->eState ){ pCur->eState = CURSOR_VALID; if( pCur->skipNext<0 ) return SQLITE_OK; } } pPage = pCur->pPage; if( sqlite3FaultSim(412) ) pPage->isInit = 0; if( !pPage->isInit ){ return SQLITE_CORRUPT_BKPT; } if( !pPage->leaf ){ int idx = pCur->ix; rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); if( rc ) return rc; rc = moveToRightmost(pCur); }else{ while( pCur->ix==0 ){ if( pCur->iPage==0 ){ pCur->eState = CURSOR_INVALID; return SQLITE_DONE; } moveToParent(pCur); } assert( pCur->info.nSize==0 ); assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 ); pCur->ix--; pPage = pCur->pPage; if( pPage->intKey && !pPage->leaf ){ rc = sqlite3BtreePrevious(pCur, 0); }else{ rc = SQLITE_OK; } } return rc; } SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){ assert( cursorOwnsBtShared(pCur) ); assert( flags==0 || flags==1 ); UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); pCur->info.nSize = 0; if( pCur->eState!=CURSOR_VALID || pCur->ix==0 || pCur->pPage->leaf==0 ){ return btreePrevious(pCur); } pCur->ix--; return SQLITE_OK; } /* ** Allocate a new page from the database file. ** ** The new page is marked as dirty. (In other words, sqlite3PagerWrite() ** has already been called on the new page.) The new page has also ** been referenced and the calling routine is responsible for calling ** sqlite3PagerUnref() on the new page when it is done. ** ** SQLITE_OK is returned on success. Any other return value indicates ** an error. *ppPage is set to NULL in the event of an error. ** ** If the "nearby" parameter is not 0, then an effort is made to ** locate a page close to the page number "nearby". This can be used in an ** attempt to keep related pages close to each other in the database file, ** which in turn can make database access faster. ** ** If the eMode parameter is BTALLOC_EXACT and the nearby page exists ** anywhere on the free-list, then it is guaranteed to be returned. If ** eMode is BTALLOC_LT then the page returned will be less than or equal ** to nearby if any such page exists. If eMode is BTALLOC_ANY then there ** are no restrictions on which page is returned. */ static int allocateBtreePage( BtShared *pBt, /* The btree */ MemPage **ppPage, /* Store pointer to the allocated page here */ Pgno *pPgno, /* Store the page number here */ Pgno nearby, /* Search for a page near this one */ u8 eMode /* BTALLOC_EXACT, BTALLOC_LT, or BTALLOC_ANY */ ){ MemPage *pPage1; int rc; u32 n; /* Number of pages on the freelist */ u32 k; /* Number of leaves on the trunk of the freelist */ MemPage *pTrunk = 0; MemPage *pPrevTrunk = 0; Pgno mxPage; /* Total size of the database file */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) ); pPage1 = pBt->pPage1; mxPage = btreePagecount(pBt); /* EVIDENCE-OF: R-21003-45125 The 4-byte big-endian integer at offset 36 ** stores the total number of pages on the freelist. */ n = get4byte(&pPage1->aData[36]); testcase( n==mxPage-1 ); if( n>=mxPage ){ return SQLITE_CORRUPT_BKPT; } if( n>0 ){ /* There are pages on the freelist. Reuse one of those pages. */ Pgno iTrunk; u8 searchList = 0; /* If the free-list must be searched for 'nearby' */ u32 nSearch = 0; /* Count of the number of search attempts */ /* If eMode==BTALLOC_EXACT and a query of the pointer-map ** shows that the page 'nearby' is somewhere on the free-list, then ** the entire-list will be searched for that page. */ #ifndef SQLITE_OMIT_AUTOVACUUM if( eMode==BTALLOC_EXACT ){ if( nearby<=mxPage ){ u8 eType; assert( nearby>0 ); assert( pBt->autoVacuum ); rc = ptrmapGet(pBt, nearby, &eType, 0); if( rc ) return rc; if( eType==PTRMAP_FREEPAGE ){ searchList = 1; } } }else if( eMode==BTALLOC_LE ){ searchList = 1; } #endif /* Decrement the free-list count by 1. Set iTrunk to the index of the ** first free-list trunk page. iPrevTrunk is initially 1. */ rc = sqlite3PagerWrite(pPage1->pDbPage); if( rc ) return rc; put4byte(&pPage1->aData[36], n-1); /* The code within this loop is run only once if the 'searchList' variable ** is not true. Otherwise, it runs once for each trunk-page on the ** free-list until the page 'nearby' is located (eMode==BTALLOC_EXACT) ** or until a page less than 'nearby' is located (eMode==BTALLOC_LT) */ do { pPrevTrunk = pTrunk; if( pPrevTrunk ){ /* EVIDENCE-OF: R-01506-11053 The first integer on a freelist trunk page ** is the page number of the next freelist trunk page in the list or ** zero if this is the last freelist trunk page. */ iTrunk = get4byte(&pPrevTrunk->aData[0]); }else{ /* EVIDENCE-OF: R-59841-13798 The 4-byte big-endian integer at offset 32 ** stores the page number of the first page of the freelist, or zero if ** the freelist is empty. */ iTrunk = get4byte(&pPage1->aData[32]); } testcase( iTrunk==mxPage ); if( iTrunk>mxPage || nSearch++ > n ){ rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1); }else{ rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); } if( rc ){ pTrunk = 0; goto end_allocate_page; } assert( pTrunk!=0 ); assert( pTrunk->aData!=0 ); /* EVIDENCE-OF: R-13523-04394 The second integer on a freelist trunk page ** is the number of leaf page pointers to follow. */ k = get4byte(&pTrunk->aData[4]); if( k==0 && !searchList ){ /* The trunk has no leaves and the list is not being searched. ** So extract the trunk page itself and use it as the newly ** allocated page */ assert( pPrevTrunk==0 ); rc = sqlite3PagerWrite(pTrunk->pDbPage); if( rc ){ goto end_allocate_page; } *pPgno = iTrunk; memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); *ppPage = pTrunk; pTrunk = 0; TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1)); }else if( k>(u32)(pBt->usableSize/4 - 2) ){ /* Value of k is out of range. Database corruption */ rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; #ifndef SQLITE_OMIT_AUTOVACUUM }else if( searchList && (nearby==iTrunk || (iTrunkpDbPage); if( rc ){ goto end_allocate_page; } if( k==0 ){ if( !pPrevTrunk ){ memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); }else{ rc = sqlite3PagerWrite(pPrevTrunk->pDbPage); if( rc!=SQLITE_OK ){ goto end_allocate_page; } memcpy(&pPrevTrunk->aData[0], &pTrunk->aData[0], 4); } }else{ /* The trunk page is required by the caller but it contains ** pointers to free-list leaves. The first leaf becomes a trunk ** page in this case. */ MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); if( iNewTrunk>mxPage ){ rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iNewTrunk==mxPage ); rc = btreeGetUnusedPage(pBt, iNewTrunk, &pNewTrunk, 0); if( rc!=SQLITE_OK ){ goto end_allocate_page; } rc = sqlite3PagerWrite(pNewTrunk->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pNewTrunk); goto end_allocate_page; } memcpy(&pNewTrunk->aData[0], &pTrunk->aData[0], 4); put4byte(&pNewTrunk->aData[4], k-1); memcpy(&pNewTrunk->aData[8], &pTrunk->aData[12], (k-1)*4); releasePage(pNewTrunk); if( !pPrevTrunk ){ assert( sqlite3PagerIswriteable(pPage1->pDbPage) ); put4byte(&pPage1->aData[32], iNewTrunk); }else{ rc = sqlite3PagerWrite(pPrevTrunk->pDbPage); if( rc ){ goto end_allocate_page; } put4byte(&pPrevTrunk->aData[0], iNewTrunk); } } pTrunk = 0; TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1)); #endif }else if( k>0 ){ /* Extract a leaf from the trunk */ u32 closest; Pgno iPage; unsigned char *aData = pTrunk->aData; if( nearby>0 ){ u32 i; closest = 0; if( eMode==BTALLOC_LE ){ for(i=0; imxPage || iPage<2 ){ rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iPage==mxPage ); if( !searchList || (iPage==nearby || (iPagepgno, n-1)); rc = sqlite3PagerWrite(pTrunk->pDbPage); if( rc ) goto end_allocate_page; if( closestpDbPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); *ppPage = 0; } } searchList = 0; } } releasePage(pPrevTrunk); pPrevTrunk = 0; }while( searchList ); }else{ /* There are no pages on the freelist, so append a new page to the ** database image. ** ** Normally, new pages allocated by this block can be requested from the ** pager layer with the 'no-content' flag set. This prevents the pager ** from trying to read the pages content from disk. However, if the ** current transaction has already run one or more incremental-vacuum ** steps, then the page we are about to allocate may contain content ** that is required in the event of a rollback. In this case, do ** not set the no-content flag. This causes the pager to load and journal ** the current page content before overwriting it. ** ** Note that the pager will not actually attempt to load or journal ** content for any page that really does lie past the end of the database ** file on disk. So the effects of disabling the no-content optimization ** here are confined to those pages that lie between the end of the ** database image and the end of the database file. */ int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate))? PAGER_GET_NOCONTENT:0; rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( rc ) return rc; pBt->nPage++; if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, pBt->nPage) ){ /* If *pPgno refers to a pointer-map page, allocate two new pages ** at the end of the file instead of one. The first allocated page ** becomes a new pointer-map page, the second is used by the caller. */ MemPage *pPg = 0; TRACE(("ALLOCATE: %u from end of file (pointer-map page)\n", pBt->nPage)); assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) ); rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pPg->pDbPage); releasePage(pPg); } if( rc ) return rc; pBt->nPage++; if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ){ pBt->nPage++; } } #endif put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage); *pPgno = pBt->nPage; assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); rc = btreeGetUnusedPage(pBt, *pPgno, ppPage, bNoContent); if( rc ) return rc; rc = sqlite3PagerWrite((*ppPage)->pDbPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); *ppPage = 0; } TRACE(("ALLOCATE: %u from end of file\n", *pPgno)); } assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) ); end_allocate_page: releasePage(pTrunk); releasePage(pPrevTrunk); assert( rc!=SQLITE_OK || sqlite3PagerPageRefcount((*ppPage)->pDbPage)<=1 ); assert( rc!=SQLITE_OK || (*ppPage)->isInit==0 ); return rc; } /* ** This function is used to add page iPage to the database file free-list. ** It is assumed that the page is not already a part of the free-list. ** ** The value passed as the second argument to this function is optional. ** If the caller happens to have a pointer to the MemPage object ** corresponding to page iPage handy, it may pass it as the second value. ** Otherwise, it may pass NULL. ** ** If a pointer to a MemPage object is passed as the second argument, ** its reference count is not altered by this function. */ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ MemPage *pTrunk = 0; /* Free-list trunk page */ Pgno iTrunk = 0; /* Page number of free-list trunk page */ MemPage *pPage1 = pBt->pPage1; /* Local reference to page 1 */ MemPage *pPage; /* Page being freed. May be NULL. */ int rc; /* Return Code */ u32 nFree; /* Initial number of pages on free-list */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( CORRUPT_DB || iPage>1 ); assert( !pMemPage || pMemPage->pgno==iPage ); if( iPage<2 || iPage>pBt->nPage ){ return SQLITE_CORRUPT_BKPT; } if( pMemPage ){ pPage = pMemPage; sqlite3PagerRef(pPage->pDbPage); }else{ pPage = btreePageLookup(pBt, iPage); } /* Increment the free page count on pPage1 */ rc = sqlite3PagerWrite(pPage1->pDbPage); if( rc ) goto freepage_out; nFree = get4byte(&pPage1->aData[36]); put4byte(&pPage1->aData[36], nFree+1); if( pBt->btsFlags & BTS_SECURE_DELETE ){ /* If the secure_delete option is enabled, then ** always fully overwrite deleted information with zeros. */ if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) ) || ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0) ){ goto freepage_out; } memset(pPage->aData, 0, pPage->pBt->pageSize); } /* If the database supports auto-vacuum, write an entry in the pointer-map ** to indicate that the page is free. */ if( ISAUTOVACUUM(pBt) ){ ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0, &rc); if( rc ) goto freepage_out; } /* Now manipulate the actual database free-list structure. There are two ** possibilities. If the free-list is currently empty, or if the first ** trunk page in the free-list is full, then this page will become a ** new free-list trunk page. Otherwise, it will become a leaf of the ** first trunk page in the current free-list. This block tests if it ** is possible to add the page as a new free-list leaf. */ if( nFree!=0 ){ u32 nLeaf; /* Initial number of leaf cells on trunk page */ iTrunk = get4byte(&pPage1->aData[32]); if( iTrunk>btreePagecount(pBt) ){ rc = SQLITE_CORRUPT_BKPT; goto freepage_out; } rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0); if( rc!=SQLITE_OK ){ goto freepage_out; } nLeaf = get4byte(&pTrunk->aData[4]); assert( pBt->usableSize>32 ); if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ rc = SQLITE_CORRUPT_BKPT; goto freepage_out; } if( nLeaf < (u32)pBt->usableSize/4 - 8 ){ /* In this case there is room on the trunk page to insert the page ** being freed as a new leaf. ** ** Note that the trunk page is not really full until it contains ** usableSize/4 - 2 entries, not usableSize/4 - 8 entries as we have ** coded. But due to a coding error in versions of SQLite prior to ** 3.6.0, databases with freelist trunk pages holding more than ** usableSize/4 - 8 entries will be reported as corrupt. In order ** to maintain backwards compatibility with older versions of SQLite, ** we will continue to restrict the number of entries to usableSize/4 - 8 ** for now. At some point in the future (once everyone has upgraded ** to 3.6.0 or later) we should consider fixing the conditional above ** to read "usableSize/4-2" instead of "usableSize/4-8". ** ** EVIDENCE-OF: R-19920-11576 However, newer versions of SQLite still ** avoid using the last six entries in the freelist trunk page array in ** order that database files created by newer versions of SQLite can be ** read by older versions of SQLite. */ rc = sqlite3PagerWrite(pTrunk->pDbPage); if( rc==SQLITE_OK ){ put4byte(&pTrunk->aData[4], nLeaf+1); put4byte(&pTrunk->aData[8+nLeaf*4], iPage); if( pPage && (pBt->btsFlags & BTS_SECURE_DELETE)==0 ){ sqlite3PagerDontWrite(pPage->pDbPage); } rc = btreeSetHasContent(pBt, iPage); } TRACE(("FREE-PAGE: %u leaf on trunk page %u\n",pPage->pgno,pTrunk->pgno)); goto freepage_out; } } /* If control flows to this point, then it was not possible to add the ** the page being freed as a leaf page of the first trunk in the free-list. ** Possibly because the free-list is empty, or possibly because the ** first trunk in the free-list is full. Either way, the page being freed ** will become the new first trunk page in the free-list. */ if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){ goto freepage_out; } rc = sqlite3PagerWrite(pPage->pDbPage); if( rc!=SQLITE_OK ){ goto freepage_out; } put4byte(pPage->aData, iTrunk); put4byte(&pPage->aData[4], 0); put4byte(&pPage1->aData[32], iPage); TRACE(("FREE-PAGE: %u new trunk page replacing %u\n", pPage->pgno, iTrunk)); freepage_out: if( pPage ){ pPage->isInit = 0; } releasePage(pPage); releasePage(pTrunk); return rc; } static void freePage(MemPage *pPage, int *pRC){ if( (*pRC)==SQLITE_OK ){ *pRC = freePage2(pPage->pBt, pPage, pPage->pgno); } } /* ** Free the overflow pages associated with the given Cell. */ static SQLITE_NOINLINE int clearCellOverflow( MemPage *pPage, /* The page that contains the Cell */ unsigned char *pCell, /* First byte of the Cell */ CellInfo *pInfo /* Size information about the cell */ ){ BtShared *pBt; Pgno ovflPgno; int rc; int nOvfl; u32 ovflPageSize; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pInfo->nLocal!=pInfo->nPayload ); testcase( pCell + pInfo->nSize == pPage->aDataEnd ); testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); if( pCell + pInfo->nSize > pPage->aDataEnd ){ /* Cell extends past end of page */ return SQLITE_CORRUPT_PAGE(pPage); } ovflPgno = get4byte(pCell + pInfo->nSize - 4); pBt = pPage->pBt; assert( pBt->usableSize > 4 ); ovflPageSize = pBt->usableSize - 4; nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize; assert( nOvfl>0 || (CORRUPT_DB && (pInfo->nPayload + ovflPageSize)btreePagecount(pBt) ){ /* 0 is not a legal page number and page 1 cannot be an ** overflow page. Therefore if ovflPgno<2 or past the end of the ** file the database must be corrupt. */ return SQLITE_CORRUPT_BKPT; } if( nOvfl ){ rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); if( rc ) return rc; } if( ( pOvfl || ((pOvfl = btreePageLookup(pBt, ovflPgno))!=0) ) && sqlite3PagerPageRefcount(pOvfl->pDbPage)!=1 ){ /* There is no reason any cursor should have an outstanding reference ** to an overflow page belonging to a cell that is being deleted/updated. ** So if there exists more than one reference to this page, then it ** must not really be an overflow page and the database must be corrupt. ** It is helpful to detect this before calling freePage2(), as ** freePage2() may zero the page contents if secure-delete mode is ** enabled. If this 'overflow' page happens to be a page that the ** caller is iterating through or using in some other way, this ** can be problematic. */ rc = SQLITE_CORRUPT_BKPT; }else{ rc = freePage2(pBt, pOvfl, ovflPgno); } if( pOvfl ){ sqlite3PagerUnref(pOvfl->pDbPage); } if( rc ) return rc; ovflPgno = iNext; } return SQLITE_OK; } /* Call xParseCell to compute the size of a cell. If the cell contains ** overflow, then invoke cellClearOverflow to clear out that overflow. ** Store the result code (SQLITE_OK or some error code) in rc. ** ** Implemented as macro to force inlining for performance. */ #define BTREE_CLEAR_CELL(rc, pPage, pCell, sInfo) \ pPage->xParseCell(pPage, pCell, &sInfo); \ if( sInfo.nLocal!=sInfo.nPayload ){ \ rc = clearCellOverflow(pPage, pCell, &sInfo); \ }else{ \ rc = SQLITE_OK; \ } /* ** Create the byte sequence used to represent a cell on page pPage ** and write that byte sequence into pCell[]. Overflow pages are ** allocated and filled in as necessary. The calling procedure ** is responsible for making sure sufficient space has been allocated ** for pCell[]. ** ** Note that pCell does not necessary need to point to the pPage->aData ** area. pCell might point to some temporary storage. The cell will ** be constructed in this temporary area then copied into pPage->aData ** later. */ static int fillInCell( MemPage *pPage, /* The page that contains the cell */ unsigned char *pCell, /* Complete text of the cell */ const BtreePayload *pX, /* Payload with which to construct the cell */ int *pnSize /* Write cell size here */ ){ int nPayload; const u8 *pSrc; int nSrc, n, rc, mn; int spaceLeft; MemPage *pToRelease; unsigned char *pPrior; unsigned char *pPayload; BtShared *pBt; Pgno pgnoOvfl; int nHeader; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); /* pPage is not necessarily writeable since pCell might be auxiliary ** buffer space that is separate from the pPage buffer area */ assert( pCellaData || pCell>=&pPage->aData[pPage->pBt->pageSize] || sqlite3PagerIswriteable(pPage->pDbPage) ); /* Fill in the header. */ nHeader = pPage->childPtrSize; if( pPage->intKey ){ nPayload = pX->nData + pX->nZero; pSrc = pX->pData; nSrc = pX->nData; assert( pPage->intKeyLeaf ); /* fillInCell() only called for leaves */ nHeader += putVarint32(&pCell[nHeader], nPayload); nHeader += putVarint(&pCell[nHeader], *(u64*)&pX->nKey); }else{ assert( pX->nKey<=0x7fffffff && pX->pKey!=0 ); nSrc = nPayload = (int)pX->nKey; pSrc = pX->pKey; nHeader += putVarint32(&pCell[nHeader], nPayload); } /* Fill in the payload */ pPayload = &pCell[nHeader]; if( nPayload<=pPage->maxLocal ){ /* This is the common case where everything fits on the btree page ** and no overflow pages are required. */ n = nHeader + nPayload; testcase( n==3 ); testcase( n==4 ); if( n<4 ) n = 4; *pnSize = n; assert( nSrc<=nPayload ); testcase( nSrcminLocal; n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4); testcase( n==pPage->maxLocal ); testcase( n==pPage->maxLocal+1 ); if( n > pPage->maxLocal ) n = mn; spaceLeft = n; *pnSize = n + nHeader + 4; pPrior = &pCell[nHeader+n]; pToRelease = 0; pgnoOvfl = 0; pBt = pPage->pBt; /* At this point variables should be set as follows: ** ** nPayload Total payload size in bytes ** pPayload Begin writing payload here ** spaceLeft Space available at pPayload. If nPayload>spaceLeft, ** that means content must spill into overflow pages. ** *pnSize Size of the local cell (not counting overflow pages) ** pPrior Where to write the pgno of the first overflow page ** ** Use a call to btreeParseCellPtr() to verify that the values above ** were computed correctly. */ #ifdef SQLITE_DEBUG { CellInfo info; pPage->xParseCell(pPage, pCell, &info); assert( nHeader==(int)(info.pPayload - pCell) ); assert( info.nKey==pX->nKey ); assert( *pnSize == info.nSize ); assert( spaceLeft == info.nLocal ); } #endif /* Write the payload into the local Cell and any extra into overflow pages */ while( 1 ){ n = nPayload; if( n>spaceLeft ) n = spaceLeft; /* If pToRelease is not zero than pPayload points into the data area ** of pToRelease. Make sure pToRelease is still writeable. */ assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); /* If pPayload is part of the data area of pPage, then make sure pPage ** is still writeable */ assert( pPayloadaData || pPayload>=&pPage->aData[pBt->pageSize] || sqlite3PagerIswriteable(pPage->pDbPage) ); if( nSrc>=n ){ memcpy(pPayload, pSrc, n); }else if( nSrc>0 ){ n = nSrc; memcpy(pPayload, pSrc, n); }else{ memset(pPayload, 0, n); } nPayload -= n; if( nPayload<=0 ) break; pPayload += n; pSrc += n; nSrc -= n; spaceLeft -= n; if( spaceLeft==0 ){ MemPage *pOvfl = 0; #ifndef SQLITE_OMIT_AUTOVACUUM Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */ if( pBt->autoVacuum ){ do{ pgnoOvfl++; } while( PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt) ); } #endif rc = allocateBtreePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl, 0); #ifndef SQLITE_OMIT_AUTOVACUUM /* If the database supports auto-vacuum, and the second or subsequent ** overflow page is being allocated, add an entry to the pointer-map ** for that page now. ** ** If this is the first overflow page, then write a partial entry ** to the pointer-map. If we write nothing to this pointer-map slot, ** then the optimistic overflow chain processing in clearCell() ** may misinterpret the uninitialized values and delete the ** wrong pages from the database. */ if( pBt->autoVacuum && rc==SQLITE_OK ){ u8 eType = (pgnoPtrmap?PTRMAP_OVERFLOW2:PTRMAP_OVERFLOW1); ptrmapPut(pBt, pgnoOvfl, eType, pgnoPtrmap, &rc); if( rc ){ releasePage(pOvfl); } } #endif if( rc ){ releasePage(pToRelease); return rc; } /* If pToRelease is not zero than pPrior points into the data area ** of pToRelease. Make sure pToRelease is still writeable. */ assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); /* If pPrior is part of the data area of pPage, then make sure pPage ** is still writeable */ assert( pPrioraData || pPrior>=&pPage->aData[pBt->pageSize] || sqlite3PagerIswriteable(pPage->pDbPage) ); put4byte(pPrior, pgnoOvfl); releasePage(pToRelease); pToRelease = pOvfl; pPrior = pOvfl->aData; put4byte(pPrior, 0); pPayload = &pOvfl->aData[4]; spaceLeft = pBt->usableSize - 4; } } releasePage(pToRelease); return SQLITE_OK; } /* ** Remove the i-th cell from pPage. This routine effects pPage only. ** The cell content is not freed or deallocated. It is assumed that ** the cell content has been copied someplace else. This routine just ** removes the reference to the cell from pPage. ** ** "sz" must be the number of bytes in the cell. */ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ u32 pc; /* Offset to cell content of cell being deleted */ u8 *data; /* pPage->aData */ u8 *ptr; /* Used to move bytes around within data[] */ int rc; /* The return code */ int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ if( *pRC ) return; assert( idx>=0 ); assert( idxnCell ); assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->nFree>=0 ); data = pPage->aData; ptr = &pPage->aCellIdx[2*idx]; assert( pPage->pBt->usableSize > (u32)(ptr-data) ); pc = get2byte(ptr); hdr = pPage->hdrOffset; testcase( pc==(u32)get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); if( pc+sz > pPage->pBt->usableSize ){ *pRC = SQLITE_CORRUPT_BKPT; return; } rc = freeSpace(pPage, pc, sz); if( rc ){ *pRC = rc; return; } pPage->nCell--; if( pPage->nCell==0 ){ memset(&data[hdr+1], 0, 4); data[hdr+7] = 0; put2byte(&data[hdr+5], pPage->pBt->usableSize); pPage->nFree = pPage->pBt->usableSize - pPage->hdrOffset - pPage->childPtrSize - 8; }else{ memmove(ptr, ptr+2, 2*(pPage->nCell - idx)); put2byte(&data[hdr+3], pPage->nCell); pPage->nFree += 2; } } /* ** Insert a new cell on pPage at cell index "i". pCell points to the ** content of the cell. ** ** If the cell content will fit on the page, then put it there. If it ** will not fit, then make a copy of the cell content into pTemp if ** pTemp is not null. Regardless of pTemp, allocate a new entry ** in pPage->apOvfl[] and make it point to the cell content (either ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. ** ** The insertCellFast() routine below works exactly the same as ** insertCell() except that it lacks the pTemp and iChild parameters ** which are assumed zero. Other than that, the two routines are the ** same. ** ** Fixes or enhancements to this routine should be reflected in ** insertCellFast()! */ static int insertCell( MemPage *pPage, /* Page into which we are copying */ int i, /* New cell becomes the i-th cell of the page */ u8 *pCell, /* Content of the new cell */ int sz, /* Bytes of content in pCell */ u8 *pTemp, /* Temp storage space for pCell, if needed */ Pgno iChild /* If non-zero, replace first 4 bytes with this value */ ){ int idx = 0; /* Where to write new cell content in data[] */ int j; /* Loop counter */ u8 *data; /* The content of the whole page */ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */ assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( MX_CELL(pPage->pBt)<=10921 ); assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB ); assert( pPage->nFree>=0 ); assert( iChild>0 ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ memcpy(pTemp, pCell, sz); pCell = pTemp; } put4byte(pCell, iChild); j = pPage->nOverflow++; /* Comparison against ArraySize-1 since we hold back one extra slot ** as a contingency. In other words, never need more than 3 overflow ** slots but 4 are allocated, just to be safe. */ assert( j < ArraySize(pPage->apOvfl)-1 ); pPage->apOvfl[j] = pCell; pPage->aiOvfl[j] = (u16)i; /* When multiple overflows occur, they are always sequential and in ** sorted order. This invariants arise because multiple overflows can ** only occur when inserting divider cells into the parent page during ** balancing, and the dividers are adjacent and sorted. */ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */ }else{ int rc = sqlite3PagerWrite(pPage->pDbPage); if( NEVER(rc!=SQLITE_OK) ){ return rc; } assert( sqlite3PagerIswriteable(pPage->pDbPage) ); data = pPage->aData; assert( &data[pPage->cellOffset]==pPage->aCellIdx ); rc = allocateSpace(pPage, sz, &idx); if( rc ){ return rc; } /* The allocateSpace() routine guarantees the following properties ** if it returns successfully */ assert( idx >= 0 ); assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB ); assert( idx+sz <= (int)pPage->pBt->usableSize ); pPage->nFree -= (u16)(2 + sz); /* In a corrupt database where an entry in the cell index section of ** a btree page has a value of 3 or less, the pCell value might point ** as many as 4 bytes in front of the start of the aData buffer for ** the source page. Make sure this does not cause problems by not ** reading the first 4 bytes */ memcpy(&data[idx+4], pCell+4, sz-4); put4byte(&data[idx], iChild); pIns = pPage->aCellIdx + i*2; memmove(pIns+2, pIns, 2*(pPage->nCell - i)); put2byte(pIns, idx); pPage->nCell++; /* increment the cell count */ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++; assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB ); #ifndef SQLITE_OMIT_AUTOVACUUM if( pPage->pBt->autoVacuum ){ int rc2 = SQLITE_OK; /* The cell may contain a pointer to an overflow page. If so, write ** the entry for the overflow page into the pointer map. */ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2); if( rc2 ) return rc2; } #endif } return SQLITE_OK; } /* ** This variant of insertCell() assumes that the pTemp and iChild ** parameters are both zero. Use this variant in sqlite3BtreeInsert() ** for performance improvement, and also so that this variant is only ** called from that one place, and is thus inlined, and thus runs must ** faster. ** ** Fixes or enhancements to this routine should be reflected into ** the insertCell() routine. */ static int insertCellFast( MemPage *pPage, /* Page into which we are copying */ int i, /* New cell becomes the i-th cell of the page */ u8 *pCell, /* Content of the new cell */ int sz /* Bytes of content in pCell */ ){ int idx = 0; /* Where to write new cell content in data[] */ int j; /* Loop counter */ u8 *data; /* The content of the whole page */ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */ assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( MX_CELL(pPage->pBt)<=10921 ); assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB ); assert( pPage->nFree>=0 ); assert( pPage->nOverflow==0 ); if( sz+2>pPage->nFree ){ j = pPage->nOverflow++; /* Comparison against ArraySize-1 since we hold back one extra slot ** as a contingency. In other words, never need more than 3 overflow ** slots but 4 are allocated, just to be safe. */ assert( j < ArraySize(pPage->apOvfl)-1 ); pPage->apOvfl[j] = pCell; pPage->aiOvfl[j] = (u16)i; /* When multiple overflows occur, they are always sequential and in ** sorted order. This invariants arise because multiple overflows can ** only occur when inserting divider cells into the parent page during ** balancing, and the dividers are adjacent and sorted. */ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */ }else{ int rc = sqlite3PagerWrite(pPage->pDbPage); if( rc!=SQLITE_OK ){ return rc; } assert( sqlite3PagerIswriteable(pPage->pDbPage) ); data = pPage->aData; assert( &data[pPage->cellOffset]==pPage->aCellIdx ); rc = allocateSpace(pPage, sz, &idx); if( rc ){ return rc; } /* The allocateSpace() routine guarantees the following properties ** if it returns successfully */ assert( idx >= 0 ); assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB ); assert( idx+sz <= (int)pPage->pBt->usableSize ); pPage->nFree -= (u16)(2 + sz); memcpy(&data[idx], pCell, sz); pIns = pPage->aCellIdx + i*2; memmove(pIns+2, pIns, 2*(pPage->nCell - i)); put2byte(pIns, idx); pPage->nCell++; /* increment the cell count */ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++; assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB ); #ifndef SQLITE_OMIT_AUTOVACUUM if( pPage->pBt->autoVacuum ){ int rc2 = SQLITE_OK; /* The cell may contain a pointer to an overflow page. If so, write ** the entry for the overflow page into the pointer map. */ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2); if( rc2 ) return rc2; } #endif } return SQLITE_OK; } /* ** The following parameters determine how many adjacent pages get involved ** in a balancing operation. NN is the number of neighbors on either side ** of the page that participate in the balancing operation. NB is the ** total number of pages that participate, including the target page and ** NN neighbors on either side. ** ** The minimum value of NN is 1 (of course). Increasing NN above 1 ** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance ** in exchange for a larger degradation in INSERT and UPDATE performance. ** The value of NN appears to give the best results overall. ** ** (Later:) The description above makes it seem as if these values are ** tunable - as if you could change them and recompile and it would all work. ** But that is unlikely. NB has been 3 since the inception of SQLite and ** we have never tested any other value. */ #define NN 1 /* Number of neighbors on either side of pPage */ #define NB 3 /* (NN*2+1): Total pages involved in the balance */ /* ** A CellArray object contains a cache of pointers and sizes for a ** consecutive sequence of cells that might be held on multiple pages. ** ** The cells in this array are the divider cell or cells from the pParent ** page plus up to three child pages. There are a total of nCell cells. ** ** pRef is a pointer to one of the pages that contributes cells. This is ** used to access information such as MemPage.intKey and MemPage.pBt->pageSize ** which should be common to all pages that contribute cells to this array. ** ** apCell[] and szCell[] hold, respectively, pointers to the start of each ** cell and the size of each cell. Some of the apCell[] pointers might refer ** to overflow cells. In other words, some apCel[] pointers might not point ** to content area of the pages. ** ** A szCell[] of zero means the size of that cell has not yet been computed. ** ** The cells come from as many as four different pages: ** ** ----------- ** | Parent | ** ----------- ** / | \ ** / | \ ** --------- --------- --------- ** |Child-1| |Child-2| |Child-3| ** --------- --------- --------- ** ** The order of cells is in the array is for an index btree is: ** ** 1. All cells from Child-1 in order ** 2. The first divider cell from Parent ** 3. All cells from Child-2 in order ** 4. The second divider cell from Parent ** 5. All cells from Child-3 in order ** ** For a table-btree (with rowids) the items 2 and 4 are empty because ** content exists only in leaves and there are no divider cells. ** ** For an index btree, the apEnd[] array holds pointer to the end of page ** for Child-1, the Parent, Child-2, the Parent (again), and Child-3, ** respectively. The ixNx[] array holds the number of cells contained in ** each of these 5 stages, and all stages to the left. Hence: ** ** ixNx[0] = Number of cells in Child-1. ** ixNx[1] = Number of cells in Child-1 plus 1 for first divider. ** ixNx[2] = Number of cells in Child-1 and Child-2 + 1 for 1st divider. ** ixNx[3] = Number of cells in Child-1 and Child-2 + both divider cells ** ixNx[4] = Total number of cells. ** ** For a table-btree, the concept is similar, except only apEnd[0]..apEnd[2] ** are used and they point to the leaf pages only, and the ixNx value are: ** ** ixNx[0] = Number of cells in Child-1. ** ixNx[1] = Number of cells in Child-1 and Child-2. ** ixNx[2] = Total number of cells. ** ** Sometimes when deleting, a child page can have zero cells. In those ** cases, ixNx[] entries with higher indexes, and the corresponding apEnd[] ** entries, shift down. The end result is that each ixNx[] entry should ** be larger than the previous */ typedef struct CellArray CellArray; struct CellArray { int nCell; /* Number of cells in apCell[] */ MemPage *pRef; /* Reference page */ u8 **apCell; /* All cells begin balanced */ u16 *szCell; /* Local size of all cells in apCell[] */ u8 *apEnd[NB*2]; /* MemPage.aDataEnd values */ int ixNx[NB*2]; /* Index of at which we move to the next apEnd[] */ }; /* ** Make sure the cell sizes at idx, idx+1, ..., idx+N-1 have been ** computed. */ static void populateCellCache(CellArray *p, int idx, int N){ MemPage *pRef = p->pRef; u16 *szCell = p->szCell; assert( idx>=0 && idx+N<=p->nCell ); while( N>0 ){ assert( p->apCell[idx]!=0 ); if( szCell[idx]==0 ){ szCell[idx] = pRef->xCellSize(pRef, p->apCell[idx]); }else{ assert( CORRUPT_DB || szCell[idx]==pRef->xCellSize(pRef, p->apCell[idx]) ); } idx++; N--; } } /* ** Return the size of the Nth element of the cell array */ static SQLITE_NOINLINE u16 computeCellSize(CellArray *p, int N){ assert( N>=0 && NnCell ); assert( p->szCell[N]==0 ); p->szCell[N] = p->pRef->xCellSize(p->pRef, p->apCell[N]); return p->szCell[N]; } static u16 cachedCellSize(CellArray *p, int N){ assert( N>=0 && NnCell ); if( p->szCell[N] ) return p->szCell[N]; return computeCellSize(p, N); } /* ** Array apCell[] contains pointers to nCell b-tree page cells. The ** szCell[] array contains the size in bytes of each cell. This function ** replaces the current contents of page pPg with the contents of the cell ** array. ** ** Some of the cells in apCell[] may currently be stored in pPg. This ** function works around problems caused by this by making a copy of any ** such cells before overwriting the page data. ** ** The MemPage.nFree field is invalidated by this function. It is the ** responsibility of the caller to set it correctly. */ static int rebuildPage( CellArray *pCArray, /* Content to be added to page pPg */ int iFirst, /* First cell in pCArray to use */ int nCell, /* Final number of cells on page */ MemPage *pPg /* The page to be reconstructed */ ){ const int hdr = pPg->hdrOffset; /* Offset of header on pPg */ u8 * const aData = pPg->aData; /* Pointer to data for pPg */ const int usableSize = pPg->pBt->usableSize; u8 * const pEnd = &aData[usableSize]; int i = iFirst; /* Which cell to copy from pCArray*/ u32 j; /* Start of cell content area */ int iEnd = i+nCell; /* Loop terminator */ u8 *pCellptr = pPg->aCellIdx; u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); u8 *pData; int k; /* Current slot in pCArray->apEnd[] */ u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */ assert( nCell>0 ); assert( i(u32)usableSize ){ j = 0; } memcpy(&pTmp[j], &aData[j], usableSize - j); for(k=0; ALWAYS(kixNx[k]<=i; k++){} pSrcEnd = pCArray->apEnd[k]; pData = pEnd; while( 1/*exit by break*/ ){ u8 *pCell = pCArray->apCell[i]; u16 sz = pCArray->szCell[i]; assert( sz>0 ); if( SQLITE_WITHIN(pCell,aData+j,pEnd) ){ if( ((uptr)(pCell+sz))>(uptr)pEnd ) return SQLITE_CORRUPT_BKPT; pCell = &pTmp[pCell - aData]; }else if( (uptr)(pCell+sz)>(uptr)pSrcEnd && (uptr)(pCell)<(uptr)pSrcEnd ){ return SQLITE_CORRUPT_BKPT; } pData -= sz; put2byte(pCellptr, (pData - aData)); pCellptr += 2; if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT; memmove(pData, pCell, sz); assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB ); i++; if( i>=iEnd ) break; if( pCArray->ixNx[k]<=i ){ k++; pSrcEnd = pCArray->apEnd[k]; } } /* The pPg->nFree field is now set incorrectly. The caller will fix it. */ pPg->nCell = nCell; pPg->nOverflow = 0; put2byte(&aData[hdr+1], 0); put2byte(&aData[hdr+3], pPg->nCell); put2byte(&aData[hdr+5], pData - aData); aData[hdr+7] = 0x00; return SQLITE_OK; } /* ** The pCArray objects contains pointers to b-tree cells and the cell sizes. ** This function attempts to add the cells stored in the array to page pPg. ** If it cannot (because the page needs to be defragmented before the cells ** will fit), non-zero is returned. Otherwise, if the cells are added ** successfully, zero is returned. ** ** Argument pCellptr points to the first entry in the cell-pointer array ** (part of page pPg) to populate. After cell apCell[0] is written to the ** page body, a 16-bit offset is written to pCellptr. And so on, for each ** cell in the array. It is the responsibility of the caller to ensure ** that it is safe to overwrite this part of the cell-pointer array. ** ** When this function is called, *ppData points to the start of the ** content area on page pPg. If the size of the content area is extended, ** *ppData is updated to point to the new start of the content area ** before returning. ** ** Finally, argument pBegin points to the byte immediately following the ** end of the space required by this page for the cell-pointer area (for ** all cells - not just those inserted by the current call). If the content ** area must be extended to before this point in order to accommodate all ** cells in apCell[], then the cells do not fit and non-zero is returned. */ static int pageInsertArray( MemPage *pPg, /* Page to add cells to */ u8 *pBegin, /* End of cell-pointer array */ u8 **ppData, /* IN/OUT: Page content-area pointer */ u8 *pCellptr, /* Pointer to cell-pointer area */ int iFirst, /* Index of first cell to add */ int nCell, /* Number of cells to add to pPg */ CellArray *pCArray /* Array of cells */ ){ int i = iFirst; /* Loop counter - cell index to insert */ u8 *aData = pPg->aData; /* Complete page */ u8 *pData = *ppData; /* Content area. A subset of aData[] */ int iEnd = iFirst + nCell; /* End of loop. One past last cell to ins */ int k; /* Current slot in pCArray->apEnd[] */ u8 *pEnd; /* Maximum extent of cell data */ assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */ if( iEnd<=iFirst ) return 0; for(k=0; ALWAYS(kixNx[k]<=i ; k++){} pEnd = pCArray->apEnd[k]; while( 1 /*Exit by break*/ ){ int sz, rc; u8 *pSlot; assert( pCArray->szCell[i]!=0 ); sz = pCArray->szCell[i]; if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){ if( (pData - pBegin)apCell[i] will never overlap on a well-formed ** database. But they might for a corrupt database. Hence use memmove() ** since memcpy() sends SIGABORT with overlapping buffers on OpenBSD */ assert( (pSlot+sz)<=pCArray->apCell[i] || pSlot>=(pCArray->apCell[i]+sz) || CORRUPT_DB ); if( (uptr)(pCArray->apCell[i]+sz)>(uptr)pEnd && (uptr)(pCArray->apCell[i])<(uptr)pEnd ){ assert( CORRUPT_DB ); (void)SQLITE_CORRUPT_BKPT; return 1; } memmove(pSlot, pCArray->apCell[i], sz); put2byte(pCellptr, (pSlot - aData)); pCellptr += 2; i++; if( i>=iEnd ) break; if( pCArray->ixNx[k]<=i ){ k++; pEnd = pCArray->apEnd[k]; } } *ppData = pData; return 0; } /* ** The pCArray object contains pointers to b-tree cells and their sizes. ** ** This function adds the space associated with each cell in the array ** that is currently stored within the body of pPg to the pPg free-list. ** The cell-pointers and other fields of the page are not updated. ** ** This function returns the total number of cells added to the free-list. */ static int pageFreeArray( MemPage *pPg, /* Page to edit */ int iFirst, /* First cell to delete */ int nCell, /* Cells to delete */ CellArray *pCArray /* Array of cells */ ){ u8 * const aData = pPg->aData; u8 * const pEnd = &aData[pPg->pBt->usableSize]; u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize]; int nRet = 0; int i, j; int iEnd = iFirst + nCell; int nFree = 0; int aOfst[10]; int aAfter[10]; for(i=iFirst; iapCell[i]; if( SQLITE_WITHIN(pCell, pStart, pEnd) ){ int sz; int iAfter; int iOfst; /* No need to use cachedCellSize() here. The sizes of all cells that ** are to be freed have already been computing while deciding which ** cells need freeing */ sz = pCArray->szCell[i]; assert( sz>0 ); iOfst = (u16)(pCell - aData); iAfter = iOfst+sz; for(j=0; j=nFree ){ if( nFree>=(int)(sizeof(aOfst)/sizeof(aOfst[0])) ){ for(j=0; jpEnd ) return 0; nFree++; } nRet++; } } for(j=0; jnCell cells starting with ** pCArray->apCell[iOld]. After balancing, this page should hold nNew cells ** starting at apCell[iNew]. ** ** This routine makes the necessary adjustments to pPg so that it contains ** the correct cells after being balanced. ** ** The pPg->nFree field is invalid when this function returns. It is the ** responsibility of the caller to set it correctly. */ static int editPage( MemPage *pPg, /* Edit this page */ int iOld, /* Index of first cell currently on page */ int iNew, /* Index of new first cell on page */ int nNew, /* Final number of cells on page */ CellArray *pCArray /* Array of cells and sizes */ ){ u8 * const aData = pPg->aData; const int hdr = pPg->hdrOffset; u8 *pBegin = &pPg->aCellIdx[nNew * 2]; int nCell = pPg->nCell; /* Cells stored on pPg */ u8 *pData; u8 *pCellptr; int i; int iOldEnd = iOld + pPg->nCell + pPg->nOverflow; int iNewEnd = iNew + nNew; #ifdef SQLITE_DEBUG u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); memcpy(pTmp, aData, pPg->pBt->usableSize); #endif /* Remove cells from the start and end of the page */ assert( nCell>=0 ); if( iOldnCell) ) return SQLITE_CORRUPT_BKPT; memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2); nCell -= nShift; } if( iNewEnd < iOldEnd ){ int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray); assert( nCell>=nTail ); nCell -= nTail; } pData = &aData[get2byte(&aData[hdr+5])]; if( pDatapPg->aDataEnd) ) goto editpage_fail; /* Add cells to the start of the page */ if( iNew=0 ); pCellptr = pPg->aCellIdx; memmove(&pCellptr[nAdd*2], pCellptr, nCell*2); if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iNew, nAdd, pCArray ) ) goto editpage_fail; nCell += nAdd; } /* Add any overflow cells */ for(i=0; inOverflow; i++){ int iCell = (iOld + pPg->aiOvfl[i]) - iNew; if( iCell>=0 && iCellaCellIdx[iCell * 2]; if( nCell>iCell ){ memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); } nCell++; cachedCellSize(pCArray, iCell+iNew); if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iCell+iNew, 1, pCArray ) ) goto editpage_fail; } } /* Append cells to the end of the page */ assert( nCell>=0 ); pCellptr = &pPg->aCellIdx[nCell*2]; if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iNew+nCell, nNew-nCell, pCArray ) ) goto editpage_fail; pPg->nCell = nNew; pPg->nOverflow = 0; put2byte(&aData[hdr+3], pPg->nCell); put2byte(&aData[hdr+5], pData - aData); #ifdef SQLITE_DEBUG for(i=0; iapCell[i+iNew]; int iOff = get2byteAligned(&pPg->aCellIdx[i*2]); if( SQLITE_WITHIN(pCell, aData, &aData[pPg->pBt->usableSize]) ){ pCell = &pTmp[pCell - aData]; } assert( 0==memcmp(pCell, &aData[iOff], pCArray->pRef->xCellSize(pCArray->pRef, pCArray->apCell[i+iNew])) ); } #endif return SQLITE_OK; editpage_fail: /* Unable to edit this page. Rebuild it from scratch instead. */ if( nNew<1 ) return SQLITE_CORRUPT_BKPT; populateCellCache(pCArray, iNew, nNew); return rebuildPage(pCArray, iNew, nNew, pPg); } #ifndef SQLITE_OMIT_QUICKBALANCE /* ** This version of balance() handles the common special case where ** a new entry is being inserted on the extreme right-end of the ** tree, in other words, when the new entry will become the largest ** entry in the tree. ** ** Instead of trying to balance the 3 right-most leaf pages, just add ** a new page to the right-hand side and put the one new entry in ** that page. This leaves the right side of the tree somewhat ** unbalanced. But odds are that we will be inserting new entries ** at the end soon afterwards so the nearly empty page will quickly ** fill up. On average. ** ** pPage is the leaf page which is the right-most page in the tree. ** pParent is its parent. pPage must have a single overflow entry ** which is also the right-most entry on the page. ** ** The pSpace buffer is used to store a temporary copy of the divider ** cell that will be inserted into pParent. Such a cell consists of a 4 ** byte page number followed by a variable length integer. In other ** words, at most 13 bytes. Hence the pSpace buffer must be at ** least 13 bytes in size. */ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ BtShared *const pBt = pPage->pBt; /* B-Tree Database */ MemPage *pNew; /* Newly allocated page */ int rc; /* Return Code */ Pgno pgnoNew; /* Page number of pNew */ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); assert( pPage->nOverflow==1 ); if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */ assert( pPage->nFree>=0 ); assert( pParent->nFree>=0 ); /* Allocate a new page. This page will become the right-sibling of ** pPage. Make the parent page writable, so that the new divider cell ** may be inserted. If both these operations are successful, proceed. */ rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); if( rc==SQLITE_OK ){ u8 *pOut = &pSpace[4]; u8 *pCell = pPage->apOvfl[0]; u16 szCell = pPage->xCellSize(pPage, pCell); u8 *pStop; CellArray b; assert( sqlite3PagerIswriteable(pNew->pDbPage) ); assert( CORRUPT_DB || pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) ); zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF); b.nCell = 1; b.pRef = pPage; b.apCell = &pCell; b.szCell = &szCell; b.apEnd[0] = pPage->aDataEnd; b.ixNx[0] = 2; rc = rebuildPage(&b, 0, 1, pNew); if( NEVER(rc) ){ releasePage(pNew); return rc; } pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell; /* If this is an auto-vacuum database, update the pointer map ** with entries for the new page, and any pointer from the ** cell on the page to an overflow page. If either of these ** operations fails, the return code is set, but the contents ** of the parent page are still manipulated by the code below. ** That is Ok, at this point the parent page is guaranteed to ** be marked as dirty. Returning an error code will cause a ** rollback, undoing any changes made to the parent page. */ if( ISAUTOVACUUM(pBt) ){ ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc); if( szCell>pNew->minLocal ){ ptrmapPutOvflPtr(pNew, pNew, pCell, &rc); } } /* Create a divider cell to insert into pParent. The divider cell ** consists of a 4-byte page number (the page number of pPage) and ** a variable length key value (which must be the same value as the ** largest key on pPage). ** ** To find the largest key value on pPage, first find the right-most ** cell on pPage. The first two fields of this cell are the ** record-length (a variable length integer at most 32-bits in size) ** and the key value (a variable length integer, may have any value). ** The first of the while(...) loops below skips over the record-length ** field. The second while(...) loop copies the key value from the ** cell on pPage into the pSpace buffer. */ pCell = findCell(pPage, pPage->nCell-1); pStop = &pCell[9]; while( (*(pCell++)&0x80) && pCellnCell, pSpace, (int)(pOut-pSpace), 0, pPage->pgno); } /* Set the right-child pointer of pParent to point to the new page. */ put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); /* Release the reference to the new page. */ releasePage(pNew); } return rc; } #endif /* SQLITE_OMIT_QUICKBALANCE */ #if 0 /* ** This function does not contribute anything to the operation of SQLite. ** it is sometimes activated temporarily while debugging code responsible ** for setting pointer-map entries. */ static int ptrmapCheckPages(MemPage **apPage, int nPage){ int i, j; for(i=0; ipBt; assert( pPage->isInit ); for(j=0; jnCell; j++){ CellInfo info; u8 *z; z = findCell(pPage, j); pPage->xParseCell(pPage, z, &info); if( info.nLocalpgno && e==PTRMAP_OVERFLOW1 ); } if( !pPage->leaf ){ Pgno child = get4byte(z); ptrmapGet(pBt, child, &e, &n); assert( n==pPage->pgno && e==PTRMAP_BTREE ); } } if( !pPage->leaf ){ Pgno child = get4byte(&pPage->aData[pPage->hdrOffset+8]); ptrmapGet(pBt, child, &e, &n); assert( n==pPage->pgno && e==PTRMAP_BTREE ); } } return 1; } #endif /* ** This function is used to copy the contents of the b-tree node stored ** on page pFrom to page pTo. If page pFrom was not a leaf page, then ** the pointer-map entries for each child page are updated so that the ** parent page stored in the pointer map is page pTo. If pFrom contained ** any cells with overflow page pointers, then the corresponding pointer ** map entries are also updated so that the parent page is page pTo. ** ** If pFrom is currently carrying any overflow cells (entries in the ** MemPage.apOvfl[] array), they are not copied to pTo. ** ** Before returning, page pTo is reinitialized using btreeInitPage(). ** ** The performance of this function is not critical. It is only used by ** the balance_shallower() and balance_deeper() procedures, neither of ** which are called often under normal circumstances. */ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ if( (*pRC)==SQLITE_OK ){ BtShared * const pBt = pFrom->pBt; u8 * const aFrom = pFrom->aData; u8 * const aTo = pTo->aData; int const iFromHdr = pFrom->hdrOffset; int const iToHdr = ((pTo->pgno==1) ? 100 : 0); int rc; int iData; assert( pFrom->isInit ); assert( pFrom->nFree>=iToHdr ); assert( get2byte(&aFrom[iFromHdr+5]) <= (int)pBt->usableSize ); /* Copy the b-tree node content from page pFrom to page pTo. */ iData = get2byte(&aFrom[iFromHdr+5]); memcpy(&aTo[iData], &aFrom[iData], pBt->usableSize-iData); memcpy(&aTo[iToHdr], &aFrom[iFromHdr], pFrom->cellOffset + 2*pFrom->nCell); /* Reinitialize page pTo so that the contents of the MemPage structure ** match the new data. The initialization of pTo can actually fail under ** fairly obscure circumstances, even though it is a copy of initialized ** page pFrom. */ pTo->isInit = 0; rc = btreeInitPage(pTo); if( rc==SQLITE_OK ) rc = btreeComputeFreeSpace(pTo); if( rc!=SQLITE_OK ){ *pRC = rc; return; } /* If this is an auto-vacuum database, update the pointer-map entries ** for any b-tree or overflow pages that pTo now contains the pointers to. */ if( ISAUTOVACUUM(pBt) ){ *pRC = setChildPtrmaps(pTo); } } } /* ** This routine redistributes cells on the iParentIdx'th child of pParent ** (hereafter "the page") and up to 2 siblings so that all pages have about the ** same amount of free space. Usually a single sibling on either side of the ** page are used in the balancing, though both siblings might come from one ** side if the page is the first or last child of its parent. If the page ** has fewer than 2 siblings (something which can only happen if the page ** is a root page or a child of a root page) then all available siblings ** participate in the balancing. ** ** The number of siblings of the page might be increased or decreased by ** one or two in an effort to keep pages nearly full but not over full. ** ** Note that when this routine is called, some of the cells on the page ** might not actually be stored in MemPage.aData[]. This can happen ** if the page is overfull. This routine ensures that all cells allocated ** to the page and its siblings fit into MemPage.aData[] before returning. ** ** In the course of balancing the page and its siblings, cells may be ** inserted into or removed from the parent page (pParent). Doing so ** may cause the parent page to become overfull or underfull. If this ** happens, it is the responsibility of the caller to invoke the correct ** balancing routine to fix this problem (see the balance() routine). ** ** If this routine fails for any reason, it might leave the database ** in a corrupted state. So if this routine fails, the database should ** be rolled back. ** ** The third argument to this function, aOvflSpace, is a pointer to a ** buffer big enough to hold one page. If while inserting cells into the parent ** page (pParent) the parent page becomes overfull, this buffer is ** used to store the parent's overflow cells. Because this function inserts ** a maximum of four divider cells into the parent page, and the maximum ** size of a cell stored within an internal node is always less than 1/4 ** of the page-size, the aOvflSpace[] buffer is guaranteed to be large ** enough for all overflow cells. ** ** If aOvflSpace is set to a null pointer, this function returns ** SQLITE_NOMEM. */ static int balance_nonroot( MemPage *pParent, /* Parent page of siblings being balanced */ int iParentIdx, /* Index of "the page" in pParent */ u8 *aOvflSpace, /* page-size bytes of space for parent ovfl */ int isRoot, /* True if pParent is a root-page */ int bBulk /* True if this call is part of a bulk load */ ){ BtShared *pBt; /* The whole database */ int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */ int nNew = 0; /* Number of pages in apNew[] */ int nOld; /* Number of pages in apOld[] */ int i, j, k; /* Loop counters */ int nxDiv; /* Next divider slot in pParent->aCell[] */ int rc = SQLITE_OK; /* The return code */ u16 leafCorrection; /* 4 if pPage is a leaf. 0 if not */ int leafData; /* True if pPage is a leaf of a LEAFDATA tree */ int usableSpace; /* Bytes in pPage beyond the header */ int pageFlags; /* Value of pPage->aData[0] */ int iSpace1 = 0; /* First unused byte of aSpace1[] */ int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */ int szScratch; /* Size of scratch memory requested */ MemPage *apOld[NB]; /* pPage and up to two siblings */ MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ u8 *pRight; /* Location in parent of right-sibling pointer */ u8 *apDiv[NB-1]; /* Divider cells in pParent */ int cntNew[NB+2]; /* Index in b.paCell[] of cell after i-th page */ int cntOld[NB+2]; /* Old index in b.apCell[] */ int szNew[NB+2]; /* Combined size of cells placed on i-th page */ u8 *aSpace1; /* Space for copies of dividers cells */ Pgno pgno; /* Temp var to store a page number in */ u8 abDone[NB+2]; /* True after i'th new page is populated */ Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ CellArray b; /* Parsed information on cells being balanced */ memset(abDone, 0, sizeof(abDone)); memset(&b, 0, sizeof(b)); pBt = pParent->pBt; assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); /* At this point pParent may have at most one overflow cell. And if ** this overflow cell is present, it must be the cell with ** index iParentIdx. This scenario comes about when this function ** is called (indirectly) from sqlite3BtreeDelete(). */ assert( pParent->nOverflow==0 || pParent->nOverflow==1 ); assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx ); if( !aOvflSpace ){ return SQLITE_NOMEM_BKPT; } assert( pParent->nFree>=0 ); /* Find the sibling pages to balance. Also locate the cells in pParent ** that divide the siblings. An attempt is made to find NN siblings on ** either side of pPage. More siblings are taken from one side, however, ** if there are fewer than NN siblings on the other side. If pParent ** has NB or fewer children then all children of pParent are taken. ** ** This loop also drops the divider cells from the parent page. This ** way, the remainder of the function does not have to deal with any ** overflow cells in the parent page, since if any existed they will ** have already been removed. */ i = pParent->nOverflow + pParent->nCell; if( i<2 ){ nxDiv = 0; }else{ assert( bBulk==0 || bBulk==1 ); if( iParentIdx==0 ){ nxDiv = 0; }else if( iParentIdx==i ){ nxDiv = i-2+bBulk; }else{ nxDiv = iParentIdx-1; } i = 2-bBulk; } nOld = i+1; if( (i+nxDiv-pParent->nOverflow)==pParent->nCell ){ pRight = &pParent->aData[pParent->hdrOffset+8]; }else{ pRight = findCell(pParent, i+nxDiv-pParent->nOverflow); } pgno = get4byte(pRight); while( 1 ){ if( rc==SQLITE_OK ){ rc = getAndInitPage(pBt, pgno, &apOld[i], 0); } if( rc ){ memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; } if( apOld[i]->nFree<0 ){ rc = btreeComputeFreeSpace(apOld[i]); if( rc ){ memset(apOld, 0, (i)*sizeof(MemPage*)); goto balance_cleanup; } } nMaxCells += apOld[i]->nCell + ArraySize(pParent->apOvfl); if( (i--)==0 ) break; if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){ apDiv[i] = pParent->apOvfl[0]; pgno = get4byte(apDiv[i]); szNew[i] = pParent->xCellSize(pParent, apDiv[i]); pParent->nOverflow = 0; }else{ apDiv[i] = findCell(pParent, i+nxDiv-pParent->nOverflow); pgno = get4byte(apDiv[i]); szNew[i] = pParent->xCellSize(pParent, apDiv[i]); /* Drop the cell from the parent page. apDiv[i] still points to ** the cell within the parent, even though it has been dropped. ** This is safe because dropping a cell only overwrites the first ** four bytes of it, and this function does not need the first ** four bytes of the divider cell. So the pointer is safe to use ** later on. ** ** But not if we are in secure-delete mode. In secure-delete mode, ** the dropCell() routine will overwrite the entire cell with zeroes. ** In this case, temporarily copy the cell into the aOvflSpace[] ** buffer. It will be copied out again as soon as the aSpace[] buffer ** is allocated. */ if( pBt->btsFlags & BTS_FAST_SECURE ){ int iOff; /* If the following if() condition is not true, the db is corrupted. ** The call to dropCell() below will detect this. */ iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData); if( (iOff+szNew[i])<=(int)pBt->usableSize ){ memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]); apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData]; } } dropCell(pParent, i+nxDiv-pParent->nOverflow, szNew[i], &rc); } } /* Make nMaxCells a multiple of 4 in order to preserve 8-byte ** alignment */ nMaxCells = (nMaxCells + 3)&~3; /* ** Allocate space for memory structures */ szScratch = nMaxCells*sizeof(u8*) /* b.apCell */ + nMaxCells*sizeof(u16) /* b.szCell */ + pBt->pageSize; /* aSpace1 */ assert( szScratch<=7*(int)pBt->pageSize ); b.apCell = sqlite3StackAllocRaw(0, szScratch ); if( b.apCell==0 ){ rc = SQLITE_NOMEM_BKPT; goto balance_cleanup; } b.szCell = (u16*)&b.apCell[nMaxCells]; aSpace1 = (u8*)&b.szCell[nMaxCells]; assert( EIGHT_BYTE_ALIGNMENT(aSpace1) ); /* ** Load pointers to all cells on sibling pages and the divider cells ** into the local b.apCell[] array. Make copies of the divider cells ** into space obtained from aSpace1[]. The divider cells have already ** been removed from pParent. ** ** If the siblings are on leaf pages, then the child pointers of the ** divider cells are stripped from the cells before they are copied ** into aSpace1[]. In this way, all cells in b.apCell[] are without ** child pointers. If siblings are not leaves, then all cell in ** b.apCell[] include child pointers. Either way, all cells in b.apCell[] ** are alike. ** ** leafCorrection: 4 if pPage is a leaf. 0 if pPage is not a leaf. ** leafData: 1 if pPage holds key+data and pParent holds only keys. */ b.pRef = apOld[0]; leafCorrection = b.pRef->leaf*4; leafData = b.pRef->intKeyLeaf; for(i=0; inCell; u8 *aData = pOld->aData; u16 maskPage = pOld->maskPage; u8 *piCell = aData + pOld->cellOffset; u8 *piEnd; VVA_ONLY( int nCellAtStart = b.nCell; ) /* Verify that all sibling pages are of the same "type" (table-leaf, ** table-interior, index-leaf, or index-interior). */ if( pOld->aData[0]!=apOld[0]->aData[0] ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } /* Load b.apCell[] with pointers to all cells in pOld. If pOld ** contains overflow cells, include them in the b.apCell[] array ** in the correct spot. ** ** Note that when there are multiple overflow cells, it is always the ** case that they are sequential and adjacent. This invariant arises ** because multiple overflows can only occurs when inserting divider ** cells into a parent on a prior balance, and divider cells are always ** adjacent and are inserted in order. There is an assert() tagged ** with "NOTE 1" in the overflow cell insertion loop to prove this ** invariant. ** ** This must be done in advance. Once the balance starts, the cell ** offset section of the btree page will be overwritten and we will no ** long be able to find the cells if a pointer to each cell is not saved ** first. */ memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); if( pOld->nOverflow>0 ){ if( NEVER(limitaiOvfl[0]) ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } limit = pOld->aiOvfl[0]; for(j=0; jnOverflow; k++){ assert( k==0 || pOld->aiOvfl[k-1]+1==pOld->aiOvfl[k] );/* NOTE 1 */ b.apCell[b.nCell] = pOld->apOvfl[k]; b.nCell++; } } piEnd = aData + pOld->cellOffset + 2*pOld->nCell; while( piCellnCell+pOld->nOverflow) ); cntOld[i] = b.nCell; if( imaxLocal+23 ); assert( iSpace1 <= (int)pBt->pageSize ); memcpy(pTemp, apDiv[i], sz); b.apCell[b.nCell] = pTemp+leafCorrection; assert( leafCorrection==0 || leafCorrection==4 ); b.szCell[b.nCell] = b.szCell[b.nCell] - leafCorrection; if( !pOld->leaf ){ assert( leafCorrection==0 ); assert( pOld->hdrOffset==0 || CORRUPT_DB ); /* The right pointer of the child page pOld becomes the left ** pointer of the divider cell */ memcpy(b.apCell[b.nCell], &pOld->aData[8], 4); }else{ assert( leafCorrection==4 ); while( b.szCell[b.nCell]<4 ){ /* Do not allow any cells smaller than 4 bytes. If a smaller cell ** does exist, pad it with 0x00 bytes. */ assert( b.szCell[b.nCell]==3 || CORRUPT_DB ); assert( b.apCell[b.nCell]==&aSpace1[iSpace1-3] || CORRUPT_DB ); aSpace1[iSpace1++] = 0x00; b.szCell[b.nCell]++; } } b.nCell++; } } /* ** Figure out the number of pages needed to hold all b.nCell cells. ** Store this number in "k". Also compute szNew[] which is the total ** size of all cells on the i-th page and cntNew[] which is the index ** in b.apCell[] of the cell that divides page i from page i+1. ** cntNew[k] should equal b.nCell. ** ** Values computed by this block: ** ** k: The total number of sibling pages ** szNew[i]: Spaced used on the i-th sibling page. ** cntNew[i]: Index in b.apCell[] and b.szCell[] for the first cell to ** the right of the i-th sibling page. ** usableSpace: Number of bytes of space available on each sibling. ** */ usableSpace = pBt->usableSize - 12 + leafCorrection; for(i=k=0; iaDataEnd; b.ixNx[k] = cntOld[i]; if( k && b.ixNx[k]==b.ixNx[k-1] ){ k--; /* Omit b.ixNx[] entry for child pages with no cells */ } if( !leafData ){ k++; b.apEnd[k] = pParent->aDataEnd; b.ixNx[k] = cntOld[i]+1; } assert( p->nFree>=0 ); szNew[i] = usableSpace - p->nFree; for(j=0; jnOverflow; j++){ szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]); } cntNew[i] = cntOld[i]; } k = nOld; for(i=0; iusableSpace ){ if( i+1>=k ){ k = i+2; if( k>NB+2 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } szNew[k-1] = 0; cntNew[k-1] = b.nCell; } sz = 2 + cachedCellSize(&b, cntNew[i]-1); szNew[i] -= sz; if( !leafData ){ if( cntNew[i]usableSpace ) break; szNew[i] += sz; cntNew[i]++; if( !leafData ){ if( cntNew[i]=b.nCell ){ k = i+1; }else if( cntNew[i] <= (i>0 ? cntNew[i-1] : 0) ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } } /* ** The packing computed by the previous block is biased toward the siblings ** on the left side (siblings with smaller keys). The left siblings are ** always nearly full, while the right-most sibling might be nearly empty. ** The next block of code attempts to adjust the packing of siblings to ** get a better balance. ** ** This adjustment is more than an optimization. The packing above might ** be so out of balance as to be illegal. For example, the right-most ** sibling might be completely empty. This adjustment is not optional. */ for(i=k-1; i>0; i--){ int szRight = szNew[i]; /* Size of sibling on the right */ int szLeft = szNew[i-1]; /* Size of sibling on the left */ int r; /* Index of right-most cell in left sibling */ int d; /* Index of first cell to the left of right sibling */ r = cntNew[i-1] - 1; d = r + 1 - leafData; (void)cachedCellSize(&b, d); do{ int szR, szD; assert( d szLeft-(szR+(i==k-1?0:2)))){ break; } szRight += szD + 2; szLeft -= szR + 2; cntNew[i-1] = r; r--; d--; }while( r>=0 ); szNew[i] = szRight; szNew[i-1] = szLeft; if( cntNew[i-1] <= (i>1 ? cntNew[i-2] : 0) ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } } /* Sanity check: For a non-corrupt database file one of the following ** must be true: ** (1) We found one or more cells (cntNew[0])>0), or ** (2) pPage is a virtual root page. A virtual root page is when ** the real root page is page 1 and we are the only child of ** that page. */ assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB); TRACE(("BALANCE: old: %u(nc=%u) %u(nc=%u) %u(nc=%u)\n", apOld[0]->pgno, apOld[0]->nCell, nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0, nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0 )); /* ** Allocate k new pages. Reuse old pages where possible. */ pageFlags = apOld[0]->aData[0]; for(i=0; ipDbPage); nNew++; if( sqlite3PagerPageRefcount(pNew->pDbPage)!=1+(i==(iParentIdx-nxDiv)) && rc==SQLITE_OK ){ rc = SQLITE_CORRUPT_BKPT; } if( rc ) goto balance_cleanup; }else{ assert( i>0 ); rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0); if( rc ) goto balance_cleanup; zeroPage(pNew, pageFlags); apNew[i] = pNew; nNew++; cntOld[i] = b.nCell; /* Set the pointer-map entry for the new sibling page. */ if( ISAUTOVACUUM(pBt) ){ ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc); if( rc!=SQLITE_OK ){ goto balance_cleanup; } } } } /* ** Reassign page numbers so that the new pages are in ascending order. ** This helps to keep entries in the disk file in order so that a scan ** of the table is closer to a linear scan through the file. That in turn ** helps the operating system to deliver pages from the disk more rapidly. ** ** An O(N*N) sort algorithm is used, but since N is never more than NB+2 ** (5), that is not a performance concern. ** ** When NB==3, this one optimization makes the database about 25% faster ** for large insertions and deletions. */ for(i=0; ipgno; assert( apNew[i]->pDbPage->flags & PGHDR_WRITEABLE ); assert( apNew[i]->pDbPage->flags & PGHDR_DIRTY ); } for(i=0; ipgno < apNew[iB]->pgno ) iB = j; } /* If apNew[i] has a page number that is bigger than any of the ** subsequence apNew[i] entries, then swap apNew[i] with the subsequent ** entry that has the smallest page number (which we know to be ** entry apNew[iB]). */ if( iB!=i ){ Pgno pgnoA = apNew[i]->pgno; Pgno pgnoB = apNew[iB]->pgno; Pgno pgnoTemp = (PENDING_BYTE/pBt->pageSize)+1; u16 fgA = apNew[i]->pDbPage->flags; u16 fgB = apNew[iB]->pDbPage->flags; sqlite3PagerRekey(apNew[i]->pDbPage, pgnoTemp, fgB); sqlite3PagerRekey(apNew[iB]->pDbPage, pgnoA, fgA); sqlite3PagerRekey(apNew[i]->pDbPage, pgnoB, fgB); apNew[i]->pgno = pgnoB; apNew[iB]->pgno = pgnoA; } } TRACE(("BALANCE: new: %u(%u nc=%u) %u(%u nc=%u) %u(%u nc=%u) " "%u(%u nc=%u) %u(%u nc=%u)\n", apNew[0]->pgno, szNew[0], cntNew[0], nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0, nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0, nNew>=3 ? apNew[2]->pgno : 0, nNew>=3 ? szNew[2] : 0, nNew>=3 ? cntNew[2] - cntNew[1] - !leafData : 0, nNew>=4 ? apNew[3]->pgno : 0, nNew>=4 ? szNew[3] : 0, nNew>=4 ? cntNew[3] - cntNew[2] - !leafData : 0, nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0, nNew>=5 ? cntNew[4] - cntNew[3] - !leafData : 0 )); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); assert( nNew>=1 && nNew<=ArraySize(apNew) ); assert( apNew[nNew-1]!=0 ); put4byte(pRight, apNew[nNew-1]->pgno); /* If the sibling pages are not leaves, ensure that the right-child pointer ** of the right-most new sibling page is set to the value that was ** originally in the same field of the right-most old sibling page. */ if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){ MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1]; memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4); } /* Make any required updates to pointer map entries associated with ** cells stored on sibling pages following the balance operation. Pointer ** map entries associated with divider cells are set by the insertCell() ** routine. The associated pointer map entries are: ** ** a) if the cell contains a reference to an overflow chain, the ** entry associated with the first page in the overflow chain, and ** ** b) if the sibling pages are not leaves, the child page associated ** with the cell. ** ** If the sibling pages are not leaves, then the pointer map entry ** associated with the right-child of each sibling may also need to be ** updated. This happens below, after the sibling pages have been ** populated, not here. */ if( ISAUTOVACUUM(pBt) ){ MemPage *pOld; MemPage *pNew = pOld = apNew[0]; int cntOldNext = pNew->nCell + pNew->nOverflow; int iNew = 0; int iOld = 0; for(i=0; i=0 && iOldnCell + pOld->nOverflow + !leafData; } if( i==cntNew[iNew] ){ pNew = apNew[++iNew]; if( !leafData ) continue; } /* Cell pCell is destined for new sibling page pNew. Originally, it ** was either part of sibling page iOld (possibly an overflow cell), ** or else the divider cell to the left of sibling page iOld. So, ** if sibling page iOld had the same page number as pNew, and if ** pCell really was a part of sibling page iOld (not a divider or ** overflow cell), we can skip updating the pointer map entries. */ if( iOld>=nNew || pNew->pgno!=aPgno[iOld] || !SQLITE_WITHIN(pCell,pOld->aData,pOld->aDataEnd) ){ if( !leafCorrection ){ ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc); } if( cachedCellSize(&b,i)>pNew->minLocal ){ ptrmapPutOvflPtr(pNew, pOld, pCell, &rc); } if( rc ) goto balance_cleanup; } } } /* Insert new divider cells into pParent. */ for(i=0; ileaf ){ memcpy(&pNew->aData[8], pCell, 4); }else if( leafData ){ /* If the tree is a leaf-data tree, and the siblings are leaves, ** then there is no divider cell in b.apCell[]. Instead, the divider ** cell consists of the integer key for the right-most cell of ** the sibling-page assembled above only. */ CellInfo info; j--; pNew->xParseCell(pNew, b.apCell[j], &info); pCell = pTemp; sz = 4 + putVarint(&pCell[4], info.nKey); pTemp = 0; }else{ pCell -= 4; /* Obscure case for non-leaf-data trees: If the cell at pCell was ** previously stored on a leaf node, and its reported size was 4 ** bytes, then it may actually be smaller than this ** (see btreeParseCellPtr(), 4 bytes is the minimum size of ** any cell). But it is important to pass the correct size to ** insertCell(), so reparse the cell now. ** ** This can only happen for b-trees used to evaluate "IN (SELECT ...)" ** and WITHOUT ROWID tables with exactly one column which is the ** primary key. */ if( b.szCell[j]==4 ){ assert(leafCorrection==4); sz = pParent->xCellSize(pParent, pCell); } } iOvflSpace += sz; assert( sz<=pBt->maxLocal+23 ); assert( iOvflSpace <= (int)pBt->pageSize ); for(k=0; ALWAYS(kpgno); if( rc!=SQLITE_OK ) goto balance_cleanup; assert( sqlite3PagerIswriteable(pParent->pDbPage) ); } /* Now update the actual sibling pages. The order in which they are updated ** is important, as this code needs to avoid disrupting any page from which ** cells may still to be read. In practice, this means: ** ** (1) If cells are moving left (from apNew[iPg] to apNew[iPg-1]) ** then it is not safe to update page apNew[iPg] until after ** the left-hand sibling apNew[iPg-1] has been updated. ** ** (2) If cells are moving right (from apNew[iPg] to apNew[iPg+1]) ** then it is not safe to update page apNew[iPg] until after ** the right-hand sibling apNew[iPg+1] has been updated. ** ** If neither of the above apply, the page is safe to update. ** ** The iPg value in the following loop starts at nNew-1 goes down ** to 0, then back up to nNew-1 again, thus making two passes over ** the pages. On the initial downward pass, only condition (1) above ** needs to be tested because (2) will always be true from the previous ** step. On the upward pass, both conditions are always true, so the ** upwards pass simply processes pages that were missed on the downward ** pass. */ for(i=1-nNew; i=0 && iPg=1 || i>=0 ); assert( iPg=0 /* On the upwards pass, or... */ || cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */ ){ int iNew; int iOld; int nNewCell; /* Verify condition (1): If cells are moving left, update iPg ** only after iPg-1 has already been updated. */ assert( iPg==0 || cntOld[iPg-1]>=cntNew[iPg-1] || abDone[iPg-1] ); /* Verify condition (2): If cells are moving right, update iPg ** only after iPg+1 has already been updated. */ assert( cntNew[iPg]>=cntOld[iPg] || abDone[iPg+1] ); if( iPg==0 ){ iNew = iOld = 0; nNewCell = cntNew[0]; }else{ iOld = iPgnFree = usableSpace-szNew[iPg]; assert( apNew[iPg]->nOverflow==0 ); assert( apNew[iPg]->nCell==nNewCell ); } } /* All pages have been processed exactly once */ assert( memcmp(abDone, "\01\01\01\01\01", nNew)==0 ); assert( nOld>0 ); assert( nNew>0 ); if( isRoot && pParent->nCell==0 && pParent->hdrOffset<=apNew[0]->nFree ){ /* The root page of the b-tree now contains no cells. The only sibling ** page is the right-child of the parent. Copy the contents of the ** child page into the parent, decreasing the overall height of the ** b-tree structure by one. This is described as the "balance-shallower" ** sub-algorithm in some documentation. ** ** If this is an auto-vacuum database, the call to copyNodeContent() ** sets all pointer-map entries corresponding to database image pages ** for which the pointer is stored within the content being copied. ** ** It is critical that the child page be defragmented before being ** copied into the parent, because if the parent is page 1 then it will ** by smaller than the child due to the database header, and so all the ** free space needs to be up front. */ assert( nNew==1 || CORRUPT_DB ); rc = defragmentPage(apNew[0], -1); testcase( rc!=SQLITE_OK ); assert( apNew[0]->nFree == (get2byteNotZero(&apNew[0]->aData[5]) - apNew[0]->cellOffset - apNew[0]->nCell*2) || rc!=SQLITE_OK ); copyNodeContent(apNew[0], pParent, &rc); freePage(apNew[0], &rc); }else if( ISAUTOVACUUM(pBt) && !leafCorrection ){ /* Fix the pointer map entries associated with the right-child of each ** sibling page. All other pointer map entries have already been taken ** care of. */ for(i=0; iaData[8]); ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc); } } assert( pParent->isInit ); TRACE(("BALANCE: finished: old=%u new=%u cells=%u\n", nOld, nNew, b.nCell)); /* Free any old pages that were not reused as new pages. */ for(i=nNew; iisInit ){ /* The ptrmapCheckPages() contains assert() statements that verify that ** all pointer map pages are set correctly. This is helpful while ** debugging. This is usually disabled because a corrupt database may ** cause an assert() statement to fail. */ ptrmapCheckPages(apNew, nNew); ptrmapCheckPages(&pParent, 1); } #endif /* ** Cleanup before returning. */ balance_cleanup: sqlite3StackFree(0, b.apCell); for(i=0; ipBt; /* The BTree */ assert( pRoot->nOverflow>0 ); assert( sqlite3_mutex_held(pBt->mutex) ); /* Make pRoot, the root page of the b-tree, writable. Allocate a new ** page that will become the new right-child of pPage. Copy the contents ** of the node stored on pRoot into the new child page. */ rc = sqlite3PagerWrite(pRoot->pDbPage); if( rc==SQLITE_OK ){ rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0); copyNodeContent(pRoot, pChild, &rc); if( ISAUTOVACUUM(pBt) ){ ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc); } } if( rc ){ *ppChild = 0; releasePage(pChild); return rc; } assert( sqlite3PagerIswriteable(pChild->pDbPage) ); assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); assert( pChild->nCell==pRoot->nCell || CORRUPT_DB ); TRACE(("BALANCE: copy root %u into %u\n", pRoot->pgno, pChild->pgno)); /* Copy the overflow cells from pRoot to pChild */ memcpy(pChild->aiOvfl, pRoot->aiOvfl, pRoot->nOverflow*sizeof(pRoot->aiOvfl[0])); memcpy(pChild->apOvfl, pRoot->apOvfl, pRoot->nOverflow*sizeof(pRoot->apOvfl[0])); pChild->nOverflow = pRoot->nOverflow; /* Zero the contents of pRoot. Then install pChild as the right-child. */ zeroPage(pRoot, pChild->aData[0] & ~PTF_LEAF); put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild); *ppChild = pChild; return SQLITE_OK; } /* ** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid ** on the same B-tree as pCur. ** ** This can occur if a database is corrupt with two or more SQL tables ** pointing to the same b-tree. If an insert occurs on one SQL table ** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL ** table linked to the same b-tree. If the secondary insert causes a ** rebalance, that can change content out from under the cursor on the ** first SQL table, violating invariants on the first insert. */ static int anotherValidCursor(BtCursor *pCur){ BtCursor *pOther; for(pOther=pCur->pBt->pCursor; pOther; pOther=pOther->pNext){ if( pOther!=pCur && pOther->eState==CURSOR_VALID && pOther->pPage==pCur->pPage ){ return SQLITE_CORRUPT_BKPT; } } return SQLITE_OK; } /* ** The page that pCur currently points to has just been modified in ** some way. This function figures out if this modification means the ** tree needs to be balanced, and if so calls the appropriate balancing ** routine. Balancing routines are: ** ** balance_quick() ** balance_deeper() ** balance_nonroot() */ static int balance(BtCursor *pCur){ int rc = SQLITE_OK; u8 aBalanceQuickSpace[13]; u8 *pFree = 0; VVA_ONLY( int balance_quick_called = 0 ); VVA_ONLY( int balance_deeper_called = 0 ); do { int iPage; MemPage *pPage = pCur->pPage; if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break; if( pPage->nOverflow==0 && pPage->nFree*3<=(int)pCur->pBt->usableSize*2 ){ /* No rebalance required as long as: ** (1) There are no overflow cells ** (2) The amount of free space on the page is less than 2/3rds of ** the total usable space on the page. */ break; }else if( (iPage = pCur->iPage)==0 ){ if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){ /* The root page of the b-tree is overfull. In this case call the ** balance_deeper() function to create a new child for the root-page ** and copy the current contents of the root-page to it. The ** next iteration of the do-loop will balance the child page. */ assert( balance_deeper_called==0 ); VVA_ONLY( balance_deeper_called++ ); rc = balance_deeper(pPage, &pCur->apPage[1]); if( rc==SQLITE_OK ){ pCur->iPage = 1; pCur->ix = 0; pCur->aiIdx[0] = 0; pCur->apPage[0] = pPage; pCur->pPage = pCur->apPage[1]; assert( pCur->pPage->nOverflow ); } }else{ break; } }else if( sqlite3PagerPageRefcount(pPage->pDbPage)>1 ){ /* The page being written is not a root page, and there is currently ** more than one reference to it. This only happens if the page is one ** of its own ancestor pages. Corruption. */ rc = SQLITE_CORRUPT_BKPT; }else{ MemPage * const pParent = pCur->apPage[iPage-1]; int const iIdx = pCur->aiIdx[iPage-1]; rc = sqlite3PagerWrite(pParent->pDbPage); if( rc==SQLITE_OK && pParent->nFree<0 ){ rc = btreeComputeFreeSpace(pParent); } if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_QUICKBALANCE if( pPage->intKeyLeaf && pPage->nOverflow==1 && pPage->aiOvfl[0]==pPage->nCell && pParent->pgno!=1 && pParent->nCell==iIdx ){ /* Call balance_quick() to create a new sibling of pPage on which ** to store the overflow cell. balance_quick() inserts a new cell ** into pParent, which may cause pParent overflow. If this ** happens, the next iteration of the do-loop will balance pParent ** use either balance_nonroot() or balance_deeper(). Until this ** happens, the overflow cell is stored in the aBalanceQuickSpace[] ** buffer. ** ** The purpose of the following assert() is to check that only a ** single call to balance_quick() is made for each call to this ** function. If this were not verified, a subtle bug involving reuse ** of the aBalanceQuickSpace[] might sneak in. */ assert( balance_quick_called==0 ); VVA_ONLY( balance_quick_called++ ); rc = balance_quick(pParent, pPage, aBalanceQuickSpace); }else #endif { /* In this case, call balance_nonroot() to redistribute cells ** between pPage and up to 2 of its sibling pages. This involves ** modifying the contents of pParent, which may cause pParent to ** become overfull or underfull. The next iteration of the do-loop ** will balance the parent page to correct this. ** ** If the parent page becomes overfull, the overflow cell or cells ** are stored in the pSpace buffer allocated immediately below. ** A subsequent iteration of the do-loop will deal with this by ** calling balance_nonroot() (balance_deeper() may be called first, ** but it doesn't deal with overflow cells - just moves them to a ** different page). Once this subsequent call to balance_nonroot() ** has completed, it is safe to release the pSpace buffer used by ** the previous call, as the overflow cell data will have been ** copied either into the body of a database page or into the new ** pSpace buffer passed to the latter call to balance_nonroot(). */ u8 *pSpace = sqlite3PageMalloc(pCur->pBt->pageSize); rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1, pCur->hints&BTREE_BULKLOAD); if( pFree ){ /* If pFree is not NULL, it points to the pSpace buffer used ** by a previous call to balance_nonroot(). Its contents are ** now stored either on real database pages or within the ** new pSpace buffer, so it may be safely freed here. */ sqlite3PageFree(pFree); } /* The pSpace buffer will be freed after the next call to ** balance_nonroot(), or just before this function returns, whichever ** comes first. */ pFree = pSpace; } } pPage->nOverflow = 0; /* The next iteration of the do-loop balances the parent page. */ releasePage(pPage); pCur->iPage--; assert( pCur->iPage>=0 ); pCur->pPage = pCur->apPage[pCur->iPage]; } }while( rc==SQLITE_OK ); if( pFree ){ sqlite3PageFree(pFree); } return rc; } /* Overwrite content from pX into pDest. Only do the write if the ** content is different from what is already there. */ static int btreeOverwriteContent( MemPage *pPage, /* MemPage on which writing will occur */ u8 *pDest, /* Pointer to the place to start writing */ const BtreePayload *pX, /* Source of data to write */ int iOffset, /* Offset of first byte to write */ int iAmt /* Number of bytes to be written */ ){ int nData = pX->nData - iOffset; if( nData<=0 ){ /* Overwriting with zeros */ int i; for(i=0; ipDbPage); if( rc ) return rc; memset(pDest + i, 0, iAmt - i); } }else{ if( nDatapData) + iOffset, iAmt)!=0 ){ int rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; /* In a corrupt database, it is possible for the source and destination ** buffers to overlap. This is harmless since the database is already ** corrupt but it does cause valgrind and ASAN warnings. So use ** memmove(). */ memmove(pDest, ((u8*)pX->pData) + iOffset, iAmt); } } return SQLITE_OK; } /* ** Overwrite the cell that cursor pCur is pointing to with fresh content ** contained in pX. In this variant, pCur is pointing to an overflow ** cell. */ static SQLITE_NOINLINE int btreeOverwriteOverflowCell( BtCursor *pCur, /* Cursor pointing to cell to overwrite */ const BtreePayload *pX /* Content to write into the cell */ ){ int iOffset; /* Next byte of pX->pData to write */ int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */ int rc; /* Return code */ MemPage *pPage = pCur->pPage; /* Page being written */ BtShared *pBt; /* Btree */ Pgno ovflPgno; /* Next overflow page to write */ u32 ovflPageSize; /* Size to write on overflow page */ assert( pCur->info.nLocalinfo.pPayload, pX, 0, pCur->info.nLocal); if( rc ) return rc; /* Now overwrite the overflow pages */ iOffset = pCur->info.nLocal; assert( nTotal>=0 ); assert( iOffset>=0 ); ovflPgno = get4byte(pCur->info.pPayload + iOffset); pBt = pPage->pBt; ovflPageSize = pBt->usableSize - 4; do{ rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); if( rc ) return rc; if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){ rc = SQLITE_CORRUPT_BKPT; }else{ if( iOffset+ovflPageSize<(u32)nTotal ){ ovflPgno = get4byte(pPage->aData); }else{ ovflPageSize = nTotal - iOffset; } rc = btreeOverwriteContent(pPage, pPage->aData+4, pX, iOffset, ovflPageSize); } sqlite3PagerUnref(pPage->pDbPage); if( rc ) return rc; iOffset += ovflPageSize; }while( iOffsetnData + pX->nZero; /* Total bytes of to write */ MemPage *pPage = pCur->pPage; /* Page being written */ if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd || pCur->info.pPayload < pPage->aData + pPage->cellOffset ){ return SQLITE_CORRUPT_BKPT; } if( pCur->info.nLocal==nTotal ){ /* The entire cell is local */ return btreeOverwriteContent(pPage, pCur->info.pPayload, pX, 0, pCur->info.nLocal); }else{ /* The cell contains overflow content */ return btreeOverwriteOverflowCell(pCur, pX); } } /* ** Insert a new record into the BTree. The content of the new record ** is described by the pX object. The pCur cursor is used only to ** define what table the record should be inserted into, and is left ** pointing at a random location. ** ** For a table btree (used for rowid tables), only the pX.nKey value of ** the key is used. The pX.pKey value must be NULL. The pX.nKey is the ** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields ** hold the content of the row. ** ** For an index btree (used for indexes and WITHOUT ROWID tables), the ** key is an arbitrary byte sequence stored in pX.pKey,nKey. The ** pX.pData,nData,nZero fields must be zero. ** ** If the seekResult parameter is non-zero, then a successful call to ** sqlite3BtreeIndexMoveto() to seek cursor pCur to (pKey,nKey) has already ** been performed. In other words, if seekResult!=0 then the cursor ** is currently pointing to a cell that will be adjacent to the cell ** to be inserted. If seekResult<0 then pCur points to a cell that is ** smaller then (pKey,nKey). If seekResult>0 then pCur points to a cell ** that is larger than (pKey,nKey). ** ** If seekResult==0, that means pCur is pointing at some unknown location. ** In that case, this routine must seek the cursor to the correct insertion ** point for (pKey,nKey) before doing the insertion. For index btrees, ** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked ** key values and pX->aMem can be used instead of pX->pKey to avoid having ** to decode the key. */ SQLITE_PRIVATE int sqlite3BtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ const BtreePayload *pX, /* Content of the row to be inserted */ int flags, /* True if this is likely an append */ int seekResult /* Result of prior IndexMoveto() call */ ){ int rc; int loc = seekResult; /* -1: before desired location +1: after */ int szNew = 0; int idx; MemPage *pPage; Btree *p = pCur->pBtree; unsigned char *oldCell; unsigned char *newCell = 0; assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags ); assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 ); /* Save the positions of any other cursors open on this table. ** ** In some cases, the call to btreeMoveto() below is a no-op. For ** example, when inserting data into a table with auto-generated integer ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the ** integer key to use. It then calls this function to actually insert the ** data into the intkey B-Tree. In this case btreeMoveto() recognizes ** that the cursor is already where it needs to be and returns without ** doing any work. To avoid thwarting these optimizations, it is important ** not to clear the cursor here. */ if( pCur->curFlags & BTCF_Multiple ){ rc = saveAllCursors(p->pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; if( loc && pCur->iPage<0 ){ /* This can only happen if the schema is corrupt such that there is more ** than one table or index with the same root page as used by the cursor. ** Which can only happen if the SQLITE_NoSchemaError flag was set when ** the schema was loaded. This cannot be asserted though, as a user might ** set the flag, load the schema, and then unset the flag. */ return SQLITE_CORRUPT_BKPT; } } /* Ensure that the cursor is not in the CURSOR_FAULT state and that it ** points to a valid cell. */ if( pCur->eState>=CURSOR_REQUIRESEEK ){ testcase( pCur->eState==CURSOR_REQUIRESEEK ); testcase( pCur->eState==CURSOR_FAULT ); rc = moveToRoot(pCur); if( rc && rc!=SQLITE_EMPTY ) return rc; } assert( cursorOwnsBtShared(pCur) ); assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && p->pBt->inTransaction==TRANS_WRITE && (p->pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); /* Assert that the caller has been consistent. If this cursor was opened ** expecting an index b-tree, then the caller should be inserting blob ** keys with no associated data. If the cursor was opened expecting an ** intkey table, the caller should be inserting integer keys with a ** blob of associated data. */ assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) ); if( pCur->pKeyInfo==0 ){ assert( pX->pKey==0 ); /* If this is an insert into a table b-tree, invalidate any incrblob ** cursors open on the row being replaced */ if( p->hasIncrblobCur ){ invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0); } /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing ** to a row with the same key as the new entry being inserted. */ #ifdef SQLITE_DEBUG if( flags & BTREE_SAVEPOSITION ){ assert( pCur->curFlags & BTCF_ValidNKey ); assert( pX->nKey==pCur->info.nKey ); assert( loc==0 ); } #endif /* On the other hand, BTREE_SAVEPOSITION==0 does not imply ** that the cursor is not pointing to a row to be overwritten. ** So do a complete check. */ if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){ /* The cursor is pointing to the entry that is to be ** overwritten */ assert( pX->nData>=0 && pX->nZero>=0 ); if( pCur->info.nSize!=0 && pCur->info.nPayload==(u32)pX->nData+pX->nZero ){ /* New entry is the same size as the old. Do an overwrite */ return btreeOverwriteCell(pCur, pX); } assert( loc==0 ); }else if( loc==0 ){ /* The cursor is *not* pointing to the cell to be overwritten, nor ** to an adjacent cell. Move the cursor so that it is pointing either ** to the cell to be overwritten or an adjacent cell. */ rc = sqlite3BtreeTableMoveto(pCur, pX->nKey, (flags & BTREE_APPEND)!=0, &loc); if( rc ) return rc; } }else{ /* This is an index or a WITHOUT ROWID table */ /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing ** to a row with the same key as the new entry being inserted. */ assert( (flags & BTREE_SAVEPOSITION)==0 || loc==0 ); /* If the cursor is not already pointing either to the cell to be ** overwritten, or if a new cell is being inserted, if the cursor is ** not pointing to an immediately adjacent cell, then move the cursor ** so that it does. */ if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){ if( pX->nMem ){ UnpackedRecord r; r.pKeyInfo = pCur->pKeyInfo; r.aMem = pX->aMem; r.nField = pX->nMem; r.default_rc = 0; r.eqSeen = 0; rc = sqlite3BtreeIndexMoveto(pCur, &r, &loc); }else{ rc = btreeMoveto(pCur, pX->pKey, pX->nKey, (flags & BTREE_APPEND)!=0, &loc); } if( rc ) return rc; } /* If the cursor is currently pointing to an entry to be overwritten ** and the new content is the same as as the old, then use the ** overwrite optimization. */ if( loc==0 ){ getCellInfo(pCur); if( pCur->info.nKey==pX->nKey ){ BtreePayload x2; x2.pData = pX->pKey; x2.nData = pX->nKey; x2.nZero = 0; return btreeOverwriteCell(pCur, &x2); } } } assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) || CORRUPT_DB ); pPage = pCur->pPage; assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) ); assert( pPage->leaf || !pPage->intKey ); if( pPage->nFree<0 ){ if( NEVER(pCur->eState>CURSOR_INVALID) ){ /* ^^^^^--- due to the moveToRoot() call above */ rc = SQLITE_CORRUPT_BKPT; }else{ rc = btreeComputeFreeSpace(pPage); } if( rc ) return rc; } TRACE(("INSERT: table=%u nkey=%lld ndata=%u page=%u %s\n", pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); assert( pPage->isInit || CORRUPT_DB ); newCell = p->pBt->pTmpSpace; assert( newCell!=0 ); assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT ); if( flags & BTREE_PREFORMAT ){ rc = SQLITE_OK; szNew = p->pBt->nPreformatSize; if( szNew<4 ) szNew = 4; if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){ CellInfo info; pPage->xParseCell(pPage, newCell, &info); if( info.nPayload!=info.nLocal ){ Pgno ovfl = get4byte(&newCell[szNew-4]); ptrmapPut(p->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc); if( NEVER(rc) ) goto end_insert; } } }else{ rc = fillInCell(pPage, newCell, pX, &szNew); if( rc ) goto end_insert; } assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(p->pBt) ); idx = pCur->ix; pCur->info.nSize = 0; if( loc==0 ){ CellInfo info; assert( idx>=0 ); if( idx>=pPage->nCell ){ return SQLITE_CORRUPT_BKPT; } rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ){ goto end_insert; } oldCell = findCell(pPage, idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } BTREE_CLEAR_CELL(rc, pPage, oldCell, info); testcase( pCur->curFlags & BTCF_ValidOvfl ); invalidateOverflowCache(pCur); if( info.nSize==szNew && info.nLocal==info.nPayload && (!ISAUTOVACUUM(p->pBt) || szNewminLocal) ){ /* Overwrite the old cell with the new if they are the same size. ** We could also try to do this if the old cell is smaller, then add ** the leftover space to the free list. But experiments show that ** doing that is no faster then skipping this optimization and just ** calling dropCell() and insertCell(). ** ** This optimization cannot be used on an autovacuum database if the ** new entry uses overflow pages, as the insertCell() call below is ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */ assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */ if( oldCell < pPage->aData+pPage->hdrOffset+10 ){ return SQLITE_CORRUPT_BKPT; } if( oldCell+szNew > pPage->aDataEnd ){ return SQLITE_CORRUPT_BKPT; } memcpy(oldCell, newCell, szNew); return SQLITE_OK; } dropCell(pPage, idx, info.nSize, &rc); if( rc ) goto end_insert; }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); idx = ++pCur->ix; pCur->curFlags &= ~BTCF_ValidNKey; }else{ assert( pPage->leaf ); } rc = insertCellFast(pPage, idx, newCell, szNew); assert( pPage->nOverflow==0 || rc==SQLITE_OK ); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); /* If no error has occurred and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey ** variables. ** ** Previous versions of SQLite called moveToRoot() to move the cursor ** back to the root page as balance() used to invalidate the contents ** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that, ** set the cursor state to "invalid". This makes common insert operations ** slightly faster. ** ** There is a subtle but important optimization here too. When inserting ** multiple records into an intkey b-tree using a single cursor (as can ** happen while processing an "INSERT INTO ... SELECT" statement), it ** is advantageous to leave the cursor pointing to the last entry in ** the b-tree if possible. If the cursor is left pointing to the last ** entry in the table, and the next row inserted has an integer key ** larger than the largest existing key, it is possible to insert the ** row without seeking the cursor. This can be a big performance boost. */ if( pPage->nOverflow ){ assert( rc==SQLITE_OK ); pCur->curFlags &= ~(BTCF_ValidNKey); rc = balance(pCur); /* Must make sure nOverflow is reset to zero even if the balance() ** fails. Internal data structure corruption will result otherwise. ** Also, set the cursor state to invalid. This stops saveCursorPosition() ** from trying to save the current position of the cursor. */ pCur->pPage->nOverflow = 0; pCur->eState = CURSOR_INVALID; if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){ btreeReleaseAllCursorPages(pCur); if( pCur->pKeyInfo ){ assert( pCur->pKey==0 ); pCur->pKey = sqlite3Malloc( pX->nKey ); if( pCur->pKey==0 ){ rc = SQLITE_NOMEM; }else{ memcpy(pCur->pKey, pX->pKey, pX->nKey); } } pCur->eState = CURSOR_REQUIRESEEK; pCur->nKey = pX->nKey; } } assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 ); end_insert: return rc; } /* ** This function is used as part of copying the current row from cursor ** pSrc into cursor pDest. If the cursors are open on intkey tables, then ** parameter iKey is used as the rowid value when the record is copied ** into pDest. Otherwise, the record is copied verbatim. ** ** This function does not actually write the new value to cursor pDest. ** Instead, it creates and populates any required overflow pages and ** writes the data for the new cell into the BtShared.pTmpSpace buffer ** for the destination database. The size of the cell, in bytes, is left ** in BtShared.nPreformatSize. The caller completes the insertion by ** calling sqlite3BtreeInsert() with the BTREE_PREFORMAT flag specified. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){ BtShared *pBt = pDest->pBt; u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */ const u8 *aIn; /* Pointer to next input buffer */ u32 nIn; /* Size of input buffer aIn[] */ u32 nRem; /* Bytes of data still to copy */ getCellInfo(pSrc); if( pSrc->info.nPayload<0x80 ){ *(aOut++) = pSrc->info.nPayload; }else{ aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload); } if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey); nIn = pSrc->info.nLocal; aIn = pSrc->info.pPayload; if( aIn+nIn>pSrc->pPage->aDataEnd ){ return SQLITE_CORRUPT_BKPT; } nRem = pSrc->info.nPayload; if( nIn==nRem && nInpPage->maxLocal ){ memcpy(aOut, aIn, nIn); pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace); return SQLITE_OK; }else{ int rc = SQLITE_OK; Pager *pSrcPager = pSrc->pBt->pPager; u8 *pPgnoOut = 0; Pgno ovflIn = 0; DbPage *pPageIn = 0; MemPage *pPageOut = 0; u32 nOut; /* Size of output buffer aOut[] */ nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace); if( nOutinfo.nPayload ){ pPgnoOut = &aOut[nOut]; pBt->nPreformatSize += 4; } if( nRem>nIn ){ if( aIn+nIn+4>pSrc->pPage->aDataEnd ){ return SQLITE_CORRUPT_BKPT; } ovflIn = get4byte(&pSrc->info.pPayload[nIn]); } do { nRem -= nOut; do{ assert( nOut>0 ); if( nIn>0 ){ int nCopy = MIN(nOut, nIn); memcpy(aOut, aIn, nCopy); nOut -= nCopy; nIn -= nCopy; aOut += nCopy; aIn += nCopy; } if( nOut>0 ){ sqlite3PagerUnref(pPageIn); pPageIn = 0; rc = sqlite3PagerGet(pSrcPager, ovflIn, &pPageIn, PAGER_GET_READONLY); if( rc==SQLITE_OK ){ aIn = (const u8*)sqlite3PagerGetData(pPageIn); ovflIn = get4byte(aIn); aIn += 4; nIn = pSrc->pBt->usableSize - 4; } } }while( rc==SQLITE_OK && nOut>0 ); if( rc==SQLITE_OK && nRem>0 && ALWAYS(pPgnoOut) ){ Pgno pgnoNew; MemPage *pNew = 0; rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); put4byte(pPgnoOut, pgnoNew); if( ISAUTOVACUUM(pBt) && pPageOut ){ ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc); } releasePage(pPageOut); pPageOut = pNew; if( pPageOut ){ pPgnoOut = pPageOut->aData; put4byte(pPgnoOut, 0); aOut = &pPgnoOut[4]; nOut = MIN(pBt->usableSize - 4, nRem); } } }while( nRem>0 && rc==SQLITE_OK ); releasePage(pPageOut); sqlite3PagerUnref(pPageIn); return rc; } } /* ** Delete the entry that the cursor is pointing to. ** ** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then ** the cursor is left pointing at an arbitrary location after the delete. ** But if that bit is set, then the cursor is left in a state such that ** the next call to BtreeNext() or BtreePrev() moves it to the same row ** as it would have been on if the call to BtreeDelete() had been omitted. ** ** The BTREE_AUXDELETE bit of flags indicates that is one of several deletes ** associated with a single table entry and its indexes. Only one of those ** deletes is considered the "primary" delete. The primary delete occurs ** on a cursor that is not a BTREE_FORDELETE cursor. All but one delete ** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag. ** The BTREE_AUXDELETE bit is a hint that is not used by this implementation, ** but which might be used by alternative storage engines. */ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ Btree *p = pCur->pBtree; BtShared *pBt = p->pBt; int rc; /* Return code */ MemPage *pPage; /* Page to delete cell from */ unsigned char *pCell; /* Pointer to cell to delete */ int iCellIdx; /* Index of cell to delete */ int iCellDepth; /* Depth of node containing pCell */ CellInfo info; /* Size of the cell being deleted */ u8 bPreserve; /* Keep cursor valid. 2 for CURSOR_SKIPNEXT */ assert( cursorOwnsBtShared(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); if( pCur->eState!=CURSOR_VALID ){ if( pCur->eState>=CURSOR_REQUIRESEEK ){ rc = btreeRestoreCursorPosition(pCur); assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID ); if( rc || pCur->eState!=CURSOR_VALID ) return rc; }else{ return SQLITE_CORRUPT_BKPT; } } assert( pCur->eState==CURSOR_VALID ); iCellDepth = pCur->iPage; iCellIdx = pCur->ix; pPage = pCur->pPage; if( pPage->nCell<=iCellIdx ){ return SQLITE_CORRUPT_BKPT; } pCell = findCell(pPage, iCellIdx); if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){ return SQLITE_CORRUPT_BKPT; } if( pCell<&pPage->aCellIdx[pPage->nCell] ){ return SQLITE_CORRUPT_BKPT; } /* If the BTREE_SAVEPOSITION bit is on, then the cursor position must ** be preserved following this delete operation. If the current delete ** will cause a b-tree rebalance, then this is done by saving the cursor ** key and leaving the cursor in CURSOR_REQUIRESEEK state before ** returning. ** ** If the current delete will not cause a rebalance, then the cursor ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately ** before or after the deleted entry. ** ** The bPreserve value records which path is required: ** ** bPreserve==0 Not necessary to save the cursor position ** bPreserve==1 Use CURSOR_REQUIRESEEK to save the cursor position ** bPreserve==2 Cursor won't move. Set CURSOR_SKIPNEXT. */ bPreserve = (flags & BTREE_SAVEPOSITION)!=0; if( bPreserve ){ if( !pPage->leaf || (pPage->nFree+pPage->xCellSize(pPage,pCell)+2) > (int)(pBt->usableSize*2/3) || pPage->nCell==1 /* See dbfuzz001.test for a test case */ ){ /* A b-tree rebalance will be required after deleting this entry. ** Save the cursor key. */ rc = saveCursorKey(pCur); if( rc ) return rc; }else{ bPreserve = 2; } } /* If the page containing the entry to delete is not a leaf page, move ** the cursor to the largest entry in the tree that is smaller than ** the entry being deleted. This cell will replace the cell being deleted ** from the internal node. The 'previous' entry is used for this instead ** of the 'next' entry, as the previous entry is always a part of the ** sub-tree headed by the child page of the cell being deleted. This makes ** balancing the tree following the delete operation easier. */ if( !pPage->leaf ){ rc = sqlite3BtreePrevious(pCur, 0); assert( rc!=SQLITE_DONE ); if( rc ) return rc; } /* Save the positions of any other cursors open on this table before ** making any modifications. */ if( pCur->curFlags & BTCF_Multiple ){ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; } /* If this is a delete operation to remove a row from a table b-tree, ** invalidate any incrblob cursors open on the row being deleted. */ if( pCur->pKeyInfo==0 && p->hasIncrblobCur ){ invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0); } /* Make the page containing the entry to be deleted writable. Then free any ** overflow pages associated with the entry and finally remove the cell ** itself from within the page. */ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; BTREE_CLEAR_CELL(rc, pPage, pCell, info); dropCell(pPage, iCellIdx, info.nSize, &rc); if( rc ) return rc; /* If the cell deleted was not located on a leaf page, then the cursor ** is currently pointing to the largest entry in the sub-tree headed ** by the child-page of the cell that was just deleted from an internal ** node. The cell from the leaf node needs to be moved to the internal ** node to replace the deleted cell. */ if( !pPage->leaf ){ MemPage *pLeaf = pCur->pPage; int nCell; Pgno n; unsigned char *pTmp; if( pLeaf->nFree<0 ){ rc = btreeComputeFreeSpace(pLeaf); if( rc ) return rc; } if( iCellDepthiPage-1 ){ n = pCur->apPage[iCellDepth+1]->pgno; }else{ n = pCur->pPage->pgno; } pCell = findCell(pLeaf, pLeaf->nCell-1); if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); if( rc==SQLITE_OK ){ rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n); } dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); if( rc ) return rc; } /* Balance the tree. If the entry deleted was located on a leaf page, ** then the cursor still points to that page. In this case the first ** call to balance() repairs the tree, and the if(...) condition is ** never true. ** ** Otherwise, if the entry deleted was on an internal node page, then ** pCur is pointing to the leaf page from which a cell was removed to ** replace the cell deleted from the internal node. This is slightly ** tricky as the leaf node may be underfull, and the internal node may ** be either under or overfull. In this case run the balancing algorithm ** on the leaf node first. If the balance proceeds far enough up the ** tree that we can be sure that any problem in the internal node has ** been corrected, so be it. Otherwise, after balancing the leaf node, ** walk the cursor up the tree to the internal node and balance it as ** well. */ assert( pCur->pPage->nOverflow==0 ); assert( pCur->pPage->nFree>=0 ); if( pCur->pPage->nFree*3<=(int)pCur->pBt->usableSize*2 ){ /* Optimization: If the free space is less than 2/3rds of the page, ** then balance() will always be a no-op. No need to invoke it. */ rc = SQLITE_OK; }else{ rc = balance(pCur); } if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){ releasePageNotNull(pCur->pPage); pCur->iPage--; while( pCur->iPage>iCellDepth ){ releasePage(pCur->apPage[pCur->iPage--]); } pCur->pPage = pCur->apPage[pCur->iPage]; rc = balance(pCur); } if( rc==SQLITE_OK ){ if( bPreserve>1 ){ assert( (pCur->iPage==iCellDepth || CORRUPT_DB) ); assert( pPage==pCur->pPage || CORRUPT_DB ); assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell ); pCur->eState = CURSOR_SKIPNEXT; if( iCellIdx>=pPage->nCell ){ pCur->skipNext = -1; pCur->ix = pPage->nCell-1; }else{ pCur->skipNext = 1; } }else{ rc = moveToRoot(pCur); if( bPreserve ){ btreeReleaseAllCursorPages(pCur); pCur->eState = CURSOR_REQUIRESEEK; } if( rc==SQLITE_EMPTY ) rc = SQLITE_OK; } } return rc; } /* ** Create a new BTree table. Write into *piTable the page ** number for the root page of the new table. ** ** The type of type is determined by the flags parameter. Only the ** following values of flags are currently in use. Other values for ** flags might not work: ** ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys ** BTREE_ZERODATA Used for SQL indices */ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){ BtShared *pBt = p->pBt; MemPage *pRoot; Pgno pgnoRoot; int rc; int ptfFlags; /* Page-type flags for the root page of new table */ assert( sqlite3BtreeHoldsMutex(p) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); #ifdef SQLITE_OMIT_AUTOVACUUM rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); if( rc ){ return rc; } #else if( pBt->autoVacuum ){ Pgno pgnoMove; /* Move a page here to make room for the root-page */ MemPage *pPageMove; /* The page to move to. */ /* Creating a new table may probably require moving an existing database ** to make room for the new tables root page. In case this page turns ** out to be an overflow page, delete all overflow page-map caches ** held by open cursors. */ invalidateAllOverflowCache(pBt); /* Read the value of meta[3] from the database to determine where the ** root page of the new table should go. meta[3] is the largest root-page ** created so far, so the new root-page is (meta[3]+1). */ sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot); if( pgnoRoot>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } pgnoRoot++; /* The new root-page may not be allocated on a pointer-map page, or the ** PENDING_BYTE page. */ while( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) || pgnoRoot==PENDING_BYTE_PAGE(pBt) ){ pgnoRoot++; } assert( pgnoRoot>=3 ); /* Allocate a page. The page that currently resides at pgnoRoot will ** be moved to the allocated page (unless the allocated page happens ** to reside at pgnoRoot). */ rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT); if( rc!=SQLITE_OK ){ return rc; } if( pgnoMove!=pgnoRoot ){ /* pgnoRoot is the page that will be used for the root-page of ** the new table (assuming an error did not occur). But we were ** allocated pgnoMove. If required (i.e. if it was not allocated ** by extending the file), the current page at position pgnoMove ** is already journaled. */ u8 eType = 0; Pgno iPtrPage = 0; /* Save the positions of any open cursors. This is required in ** case they are holding a reference to an xFetch reference ** corresponding to page pgnoRoot. */ rc = saveAllCursors(pBt, 0, 0); releasePage(pPageMove); if( rc!=SQLITE_OK ){ return rc; } /* Move the page currently at pgnoRoot to pgnoMove. */ rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); if( rc!=SQLITE_OK ){ return rc; } rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage); if( eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){ rc = SQLITE_CORRUPT_BKPT; } if( rc!=SQLITE_OK ){ releasePage(pRoot); return rc; } assert( eType!=PTRMAP_ROOTPAGE ); assert( eType!=PTRMAP_FREEPAGE ); rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove, 0); releasePage(pRoot); /* Obtain the page at pgnoRoot */ if( rc!=SQLITE_OK ){ return rc; } rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3PagerWrite(pRoot->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pRoot); return rc; } }else{ pRoot = pPageMove; } /* Update the pointer-map and meta-data with the new root-page number. */ ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0, &rc); if( rc ){ releasePage(pRoot); return rc; } /* When the new root page was allocated, page 1 was made writable in ** order either to increase the database filesize, or to decrement the ** freelist count. Hence, the sqlite3BtreeUpdateMeta() call cannot fail. */ assert( sqlite3PagerIswriteable(pBt->pPage1->pDbPage) ); rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot); if( NEVER(rc) ){ releasePage(pRoot); return rc; } }else{ rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); if( rc ) return rc; } #endif assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); if( createTabFlags & BTREE_INTKEY ){ ptfFlags = PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF; }else{ ptfFlags = PTF_ZERODATA | PTF_LEAF; } zeroPage(pRoot, ptfFlags); sqlite3PagerUnref(pRoot->pDbPage); assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 ); *piTable = pgnoRoot; return SQLITE_OK; } SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, Pgno *piTable, int flags){ int rc; sqlite3BtreeEnter(p); rc = btreeCreateTable(p, piTable, flags); sqlite3BtreeLeave(p); return rc; } /* ** Erase the given database page and all its children. Return ** the page to the freelist. */ static int clearDatabasePage( BtShared *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ int freePageFlag, /* Deallocate page if true */ i64 *pnChange /* Add number of Cells freed to this counter */ ){ MemPage *pPage; int rc; unsigned char *pCell; int i; int hdr; CellInfo info; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, pgno, &pPage, 0); if( rc ) return rc; if( (pBt->openFlags & BTREE_SINGLE)==0 && sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1)) ){ rc = SQLITE_CORRUPT_BKPT; goto cleardatabasepage_out; } hdr = pPage->hdrOffset; for(i=0; inCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); if( rc ) goto cleardatabasepage_out; } BTREE_CLEAR_CELL(rc, pPage, pCell, info); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); if( rc ) goto cleardatabasepage_out; if( pPage->intKey ) pnChange = 0; } if( pnChange ){ testcase( !pPage->intKey ); *pnChange += pPage->nCell; } if( freePageFlag ){ freePage(pPage, &rc); }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){ zeroPage(pPage, pPage->aData[hdr] | PTF_LEAF); } cleardatabasepage_out: releasePage(pPage); return rc; } /* ** Delete all information from a single table in the database. iTable is ** the page number of the root of the table. After this routine returns, ** the root page is empty, but still exists. ** ** This routine will fail with SQLITE_LOCKED if there are any open ** read cursors on the table. Open write cursors are moved to the ** root of the table. ** ** If pnChange is not NULL, then the integer value pointed to by pnChange ** is incremented by the number of entries in the table. */ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, i64 *pnChange){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( p->inTrans==TRANS_WRITE ); rc = saveAllCursors(pBt, (Pgno)iTable, 0); if( SQLITE_OK==rc ){ /* Invalidate all incrblob cursors open on table iTable (assuming iTable ** is the root of a table b-tree - if it is not, the following call is ** a no-op). */ if( p->hasIncrblobCur ){ invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1); } rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange); } sqlite3BtreeLeave(p); return rc; } /* ** Delete all information from the single table that pCur is open on. ** ** This routine only work for pCur on an ephemeral table. */ SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){ return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0); } /* ** Erase all information in a table and add the root of the table to ** the freelist. Except, the root of the principle table (the one on ** page 1) is never added to the freelist. ** ** This routine will fail with SQLITE_LOCKED if there are any open ** cursors on the table. ** ** If AUTOVACUUM is enabled and the page at iTable is not the last ** root page in the database file, then the last root page ** in the database file is moved into the slot formerly occupied by ** iTable and that last slot formerly occupied by the last root page ** is added to the freelist instead of iTable. In this say, all ** root pages are kept at the beginning of the database file, which ** is necessary for AUTOVACUUM to work right. *piMoved is set to the ** page number that used to be the last root page in the file before ** the move. If no page gets moved, *piMoved is set to 0. ** The last root page is recorded in meta[3] and the value of ** meta[3] is updated by this procedure. */ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ int rc; MemPage *pPage = 0; BtShared *pBt = p->pBt; assert( sqlite3BtreeHoldsMutex(p) ); assert( p->inTrans==TRANS_WRITE ); assert( iTable>=2 ); if( iTable>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } rc = sqlite3BtreeClearTable(p, iTable, 0); if( rc ) return rc; rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( NEVER(rc) ){ releasePage(pPage); return rc; } *piMoved = 0; #ifdef SQLITE_OMIT_AUTOVACUUM freePage(pPage, &rc); releasePage(pPage); #else if( pBt->autoVacuum ){ Pgno maxRootPgno; sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno); if( iTable==maxRootPgno ){ /* If the table being dropped is the table with the largest root-page ** number in the database, put the root page on the free list. */ freePage(pPage, &rc); releasePage(pPage); if( rc!=SQLITE_OK ){ return rc; } }else{ /* The table being dropped does not have the largest root-page ** number in the database. So move the page that does into the ** gap left by the deleted root-page. */ MemPage *pMove; releasePage(pPage); rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); if( rc!=SQLITE_OK ){ return rc; } rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0); releasePage(pMove); if( rc!=SQLITE_OK ){ return rc; } pMove = 0; rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); freePage(pMove, &rc); releasePage(pMove); if( rc!=SQLITE_OK ){ return rc; } *piMoved = maxRootPgno; } /* Set the new 'max-root-page' value in the database header. This ** is the old value less one, less one more if that happens to ** be a root-page number, less one again if that is the ** PENDING_BYTE_PAGE. */ maxRootPgno--; while( maxRootPgno==PENDING_BYTE_PAGE(pBt) || PTRMAP_ISPAGE(pBt, maxRootPgno) ){ maxRootPgno--; } assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) ); rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); }else{ freePage(pPage, &rc); releasePage(pPage); } #endif return rc; } SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ int rc; sqlite3BtreeEnter(p); rc = btreeDropTable(p, iTable, piMoved); sqlite3BtreeLeave(p); return rc; } /* ** This function may only be called if the b-tree connection already ** has a read or write transaction open on the database. ** ** Read the meta-information out of a database file. Meta[0] ** is the number of free pages currently in the database. Meta[1] ** through meta[15] are available for use by higher layers. Meta[0] ** is read-only, the others are read/write. ** ** The schema layer numbers meta values differently. At the schema ** layer (and the SetCookie and ReadCookie opcodes) the number of ** free pages is not visible. So Cookie[0] is the same as Meta[1]. ** ** This routine treats Meta[BTREE_DATA_VERSION] as a special case. Instead ** of reading the value out of the header, it instead loads the "DataVersion" ** from the pager. The BTREE_DATA_VERSION value is not actually stored in the ** database file. It is a number computed by the pager. But its access ** pattern is the same as header meta values, and so it is convenient to ** read it from this routine. */ SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE ); assert( SQLITE_OK==querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK) ); assert( pBt->pPage1 ); assert( idx>=0 && idx<=15 ); if( idx==BTREE_DATA_VERSION ){ *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iBDataVersion; }else{ *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]); } /* If auto-vacuum is disabled in this build and this is an auto-vacuum ** database, mark the database as read-only. */ #ifdef SQLITE_OMIT_AUTOVACUUM if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ){ pBt->btsFlags |= BTS_READ_ONLY; } #endif sqlite3BtreeLeave(p); } /* ** Write meta-information back into the database. Meta[0] is ** read-only and may not be written. */ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ BtShared *pBt = p->pBt; unsigned char *pP1; int rc; assert( idx>=1 && idx<=15 ); sqlite3BtreeEnter(p); assert( p->inTrans==TRANS_WRITE ); assert( pBt->pPage1!=0 ); pP1 = pBt->pPage1->aData; rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( rc==SQLITE_OK ){ put4byte(&pP1[36 + idx*4], iMeta); #ifndef SQLITE_OMIT_AUTOVACUUM if( idx==BTREE_INCR_VACUUM ){ assert( pBt->autoVacuum || iMeta==0 ); assert( iMeta==0 || iMeta==1 ); pBt->incrVacuum = (u8)iMeta; } #endif } sqlite3BtreeLeave(p); return rc; } /* ** The first argument, pCur, is a cursor opened on some b-tree. Count the ** number of entries in the b-tree and write the result to *pnEntry. ** ** SQLITE_OK is returned if the operation is successfully executed. ** Otherwise, if an error is encountered (i.e. an IO error or database ** corruption) an SQLite error code is returned. */ SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){ i64 nEntry = 0; /* Value to return in *pnEntry */ int rc; /* Return code */ rc = moveToRoot(pCur); if( rc==SQLITE_EMPTY ){ *pnEntry = 0; return SQLITE_OK; } /* Unless an error occurs, the following loop runs one iteration for each ** page in the B-Tree structure (not including overflow pages). */ while( rc==SQLITE_OK && !AtomicLoad(&db->u1.isInterrupted) ){ int iIdx; /* Index of child node in parent */ MemPage *pPage; /* Current page of the b-tree */ /* If this is a leaf page or the tree is not an int-key tree, then ** this page contains countable entries. Increment the entry counter ** accordingly. */ pPage = pCur->pPage; if( pPage->leaf || !pPage->intKey ){ nEntry += pPage->nCell; } /* pPage is a leaf node. This loop navigates the cursor so that it ** points to the first interior cell that it points to the parent of ** the next page in the tree that has not yet been visited. The ** pCur->aiIdx[pCur->iPage] value is set to the index of the parent cell ** of the page, or to the number of cells in the page if the next page ** to visit is the right-child of its parent. ** ** If all pages in the tree have been visited, return SQLITE_OK to the ** caller. */ if( pPage->leaf ){ do { if( pCur->iPage==0 ){ /* All pages of the b-tree have been visited. Return successfully. */ *pnEntry = nEntry; return moveToRoot(pCur); } moveToParent(pCur); }while ( pCur->ix>=pCur->pPage->nCell ); pCur->ix++; pPage = pCur->pPage; } /* Descend to the child node of the cell that the cursor currently ** points at. This is the right-child if (iIdx==pPage->nCell). */ iIdx = pCur->ix; if( iIdx==pPage->nCell ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); }else{ rc = moveToChild(pCur, get4byte(findCell(pPage, iIdx))); } } /* An error has occurred. Return an error code. */ return rc; } /* ** Return the pager associated with a BTree. This routine is used for ** testing and debugging only. */ SQLITE_PRIVATE Pager *sqlite3BtreePager(Btree *p){ return p->pBt->pPager; } #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* ** Record an OOM error during integrity_check */ static void checkOom(IntegrityCk *pCheck){ pCheck->rc = SQLITE_NOMEM; pCheck->mxErr = 0; /* Causes integrity_check processing to stop */ if( pCheck->nErr==0 ) pCheck->nErr++; } /* ** Invoke the progress handler, if appropriate. Also check for an ** interrupt. */ static void checkProgress(IntegrityCk *pCheck){ sqlite3 *db = pCheck->db; if( AtomicLoad(&db->u1.isInterrupted) ){ pCheck->rc = SQLITE_INTERRUPT; pCheck->nErr++; pCheck->mxErr = 0; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( db->xProgress ){ assert( db->nProgressOps>0 ); pCheck->nStep++; if( (pCheck->nStep % db->nProgressOps)==0 && db->xProgress(db->pProgressArg) ){ pCheck->rc = SQLITE_INTERRUPT; pCheck->nErr++; pCheck->mxErr = 0; } } #endif } /* ** Append a message to the error message string. */ static void checkAppendMsg( IntegrityCk *pCheck, const char *zFormat, ... ){ va_list ap; checkProgress(pCheck); if( !pCheck->mxErr ) return; pCheck->mxErr--; pCheck->nErr++; va_start(ap, zFormat); if( pCheck->errMsg.nChar ){ sqlite3_str_append(&pCheck->errMsg, "\n", 1); } if( pCheck->zPfx ){ sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v0, pCheck->v1, pCheck->v2); } sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap); va_end(ap); if( pCheck->errMsg.accError==SQLITE_NOMEM ){ checkOom(pCheck); } } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* ** Return non-zero if the bit in the IntegrityCk.aPgRef[] array that ** corresponds to page iPg is already set. */ static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){ assert( pCheck->aPgRef!=0 ); assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 ); return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07))); } /* ** Set the bit in the IntegrityCk.aPgRef[] array that corresponds to page iPg. */ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){ assert( pCheck->aPgRef!=0 ); assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 ); pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07)); } /* ** Add 1 to the reference count for page iPage. If this is the second ** reference to the page, add an error message to pCheck->zErrMsg. ** Return 1 if there are 2 or more references to the page and 0 if ** if this is the first reference to the page. ** ** Also check that the page number is in bounds. */ static int checkRef(IntegrityCk *pCheck, Pgno iPage){ if( iPage>pCheck->nCkPage || iPage==0 ){ checkAppendMsg(pCheck, "invalid page number %u", iPage); return 1; } if( getPageReferenced(pCheck, iPage) ){ checkAppendMsg(pCheck, "2nd reference to page %u", iPage); return 1; } setPageReferenced(pCheck, iPage); return 0; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Check that the entry in the pointer-map for page iChild maps to ** page iParent, pointer type ptrType. If not, append an error message ** to pCheck. */ static void checkPtrmap( IntegrityCk *pCheck, /* Integrity check context */ Pgno iChild, /* Child page number */ u8 eType, /* Expected pointer map type */ Pgno iParent /* Expected pointer map parent page number */ ){ int rc; u8 ePtrmapType; Pgno iPtrmapParent; rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) checkOom(pCheck); checkAppendMsg(pCheck, "Failed to read ptrmap key=%u", iChild); return; } if( ePtrmapType!=eType || iPtrmapParent!=iParent ){ checkAppendMsg(pCheck, "Bad ptr map entry key=%u expected=(%u,%u) got=(%u,%u)", iChild, eType, iParent, ePtrmapType, iPtrmapParent); } } #endif /* ** Check the integrity of the freelist or of an overflow page list. ** Verify that the number of pages on the list is N. */ static void checkList( IntegrityCk *pCheck, /* Integrity checking context */ int isFreeList, /* True for a freelist. False for overflow page list */ Pgno iPage, /* Page number for first page in the list */ u32 N /* Expected number of pages in the list */ ){ int i; u32 expected = N; int nErrAtStart = pCheck->nErr; while( iPage!=0 && pCheck->mxErr ){ DbPage *pOvflPage; unsigned char *pOvflData; if( checkRef(pCheck, iPage) ) break; N--; if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){ checkAppendMsg(pCheck, "failed to get page %u", iPage); break; } pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage); if( isFreeList ){ u32 n = (u32)get4byte(&pOvflData[4]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pCheck->pBt->autoVacuum ){ checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0); } #endif if( n>pCheck->pBt->usableSize/4-2 ){ checkAppendMsg(pCheck, "freelist leaf count too big on page %u", iPage); N--; }else{ for(i=0; i<(int)n; i++){ Pgno iFreePage = get4byte(&pOvflData[8+i*4]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pCheck->pBt->autoVacuum ){ checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0); } #endif checkRef(pCheck, iFreePage); } N -= n; } } #ifndef SQLITE_OMIT_AUTOVACUUM else{ /* If this database supports auto-vacuum and iPage is not the last ** page in this overflow list, check that the pointer-map entry for ** the following page matches iPage. */ if( pCheck->pBt->autoVacuum && N>0 ){ i = get4byte(pOvflData); checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage); } } #endif iPage = get4byte(pOvflData); sqlite3PagerUnref(pOvflPage); } if( N && nErrAtStart==pCheck->nErr ){ checkAppendMsg(pCheck, "%s is %u but should be %u", isFreeList ? "size" : "overflow list length", expected-N, expected); } } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* ** An implementation of a min-heap. ** ** aHeap[0] is the number of elements on the heap. aHeap[1] is the ** root element. The daughter nodes of aHeap[N] are aHeap[N*2] ** and aHeap[N*2+1]. ** ** The heap property is this: Every node is less than or equal to both ** of its daughter nodes. A consequence of the heap property is that the ** root node aHeap[1] is always the minimum value currently in the heap. ** ** The btreeHeapInsert() routine inserts an unsigned 32-bit number onto ** the heap, preserving the heap property. The btreeHeapPull() routine ** removes the root element from the heap (the minimum value in the heap) ** and then moves other nodes around as necessary to preserve the heap ** property. ** ** This heap is used for cell overlap and coverage testing. Each u32 ** entry represents the span of a cell or freeblock on a btree page. ** The upper 16 bits are the index of the first byte of a range and the ** lower 16 bits are the index of the last byte of that range. */ static void btreeHeapInsert(u32 *aHeap, u32 x){ u32 j, i; assert( aHeap!=0 ); i = ++aHeap[0]; aHeap[i] = x; while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){ x = aHeap[j]; aHeap[j] = aHeap[i]; aHeap[i] = x; i = j; } } static int btreeHeapPull(u32 *aHeap, u32 *pOut){ u32 j, i, x; if( (x = aHeap[0])==0 ) return 0; *pOut = aHeap[1]; aHeap[1] = aHeap[x]; aHeap[x] = 0xffffffff; aHeap[0]--; i = 1; while( (j = i*2)<=aHeap[0] ){ if( aHeap[j]>aHeap[j+1] ) j++; if( aHeap[i]zPfx; int saved_v1 = pCheck->v1; int saved_v2 = pCheck->v2; u8 savedIsInit = 0; /* Check that the page exists */ checkProgress(pCheck); if( pCheck->mxErr==0 ) goto end_of_check; pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage) ) return 0; pCheck->zPfx = "Tree %u page %u: "; pCheck->v1 = iPage; if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){ checkAppendMsg(pCheck, "unable to get the page. error code=%d", rc); if( rc==SQLITE_IOERR_NOMEM ) pCheck->rc = SQLITE_NOMEM; goto end_of_check; } /* Clear MemPage.isInit to make sure the corruption detection code in ** btreeInitPage() is executed. */ savedIsInit = pPage->isInit; pPage->isInit = 0; if( (rc = btreeInitPage(pPage))!=0 ){ assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */ checkAppendMsg(pCheck, "btreeInitPage() returns error code %d", rc); goto end_of_check; } if( (rc = btreeComputeFreeSpace(pPage))!=0 ){ assert( rc==SQLITE_CORRUPT ); checkAppendMsg(pCheck, "free space corruption", rc); goto end_of_check; } data = pPage->aData; hdr = pPage->hdrOffset; /* Set up for cell analysis */ pCheck->zPfx = "Tree %u page %u cell %u: "; contentOffset = get2byteNotZero(&data[hdr+5]); assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the ** number of cells on the page. */ nCell = get2byte(&data[hdr+3]); assert( pPage->nCell==nCell ); /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page ** immediately follows the b-tree page header. */ cellStart = hdr + 12 - 4*pPage->leaf; assert( pPage->aCellIdx==&data[cellStart] ); pCellIdx = &data[cellStart + 2*(nCell-1)]; if( !pPage->leaf ){ /* Analyze the right-child page of internal pages */ pgno = get4byte(&data[hdr+8]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ pCheck->zPfx = "Tree %u page %u right child: "; checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); } #endif depth = checkTreePage(pCheck, pgno, &maxKey, maxKey); keyCanBeEqual = 0; }else{ /* For leaf pages, the coverage check will occur in the same loop ** as the other cell checks, so initialize the heap. */ heap = pCheck->heap; heap[0] = 0; } /* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte ** integer offsets to the cell contents. */ for(i=nCell-1; i>=0 && pCheck->mxErr; i--){ CellInfo info; /* Check cell size */ pCheck->v2 = i; assert( pCellIdx==&data[cellStart + i*2] ); pc = get2byteAligned(pCellIdx); pCellIdx -= 2; if( pcusableSize-4 ){ checkAppendMsg(pCheck, "Offset %u out of range %u..%u", pc, contentOffset, usableSize-4); doCoverageCheck = 0; continue; } pCell = &data[pc]; pPage->xParseCell(pPage, pCell, &info); if( pc+info.nSize>usableSize ){ checkAppendMsg(pCheck, "Extends off end of page"); doCoverageCheck = 0; continue; } /* Check for integer primary key out of range */ if( pPage->intKey ){ if( keyCanBeEqual ? (info.nKey > maxKey) : (info.nKey >= maxKey) ){ checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey); } maxKey = info.nKey; keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */ } /* Check the content overflow list */ if( info.nPayload>info.nLocal ){ u32 nPage; /* Number of pages on the overflow chain */ Pgno pgnoOvfl; /* First page of the overflow chain */ assert( pc + info.nSize - 4 <= usableSize ); nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4); pgnoOvfl = get4byte(&pCell[info.nSize - 4]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage); } #endif checkList(pCheck, 0, pgnoOvfl, nPage); } if( !pPage->leaf ){ /* Check sanity of left child page for internal pages */ pgno = get4byte(pCell); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); } #endif d2 = checkTreePage(pCheck, pgno, &maxKey, maxKey); keyCanBeEqual = 0; if( d2!=depth ){ checkAppendMsg(pCheck, "Child page depth differs"); depth = d2; } }else{ /* Populate the coverage-checking heap for leaf pages */ btreeHeapInsert(heap, (pc<<16)|(pc+info.nSize-1)); } } *piMinKey = maxKey; /* Check for complete coverage of the page */ pCheck->zPfx = 0; if( doCoverageCheck && pCheck->mxErr>0 ){ /* For leaf pages, the min-heap has already been initialized and the ** cells have already been inserted. But for internal pages, that has ** not yet been done, so do it now */ if( !pPage->leaf ){ heap = pCheck->heap; heap[0] = 0; for(i=nCell-1; i>=0; i--){ u32 size; pc = get2byteAligned(&data[cellStart+i*2]); size = pPage->xCellSize(pPage, &data[pc]); btreeHeapInsert(heap, (pc<<16)|(pc+size-1)); } } /* Add the freeblocks to the min-heap ** ** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header ** is the offset of the first freeblock, or zero if there are no ** freeblocks on the page. */ i = get2byte(&data[hdr+1]); while( i>0 ){ int size, j; assert( (u32)i<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ size = get2byte(&data[i+2]); assert( (u32)(i+size)<=usableSize ); /* due to btreeComputeFreeSpace() */ btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1)); /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a ** big-endian integer which is the offset in the b-tree page of the next ** freeblock in the chain, or zero if the freeblock is the last on the ** chain. */ j = get2byte(&data[i]); /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of ** increasing offset. */ assert( j==0 || j>i+size ); /* Enforced by btreeComputeFreeSpace() */ assert( (u32)j<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ i = j; } /* Analyze the min-heap looking for overlap between cells and/or ** freeblocks, and counting the number of untracked bytes in nFrag. ** ** Each min-heap entry is of the form: (start_address<<16)|end_address. ** There is an implied first entry the covers the page header, the cell ** pointer index, and the gap between the cell pointer index and the start ** of cell content. ** ** The loop below pulls entries from the min-heap in order and compares ** the start_address against the previous end_address. If there is an ** overlap, that means bytes are used multiple times. If there is a gap, ** that gap is added to the fragmentation count. */ nFrag = 0; prev = contentOffset - 1; /* Implied first min-heap entry */ while( btreeHeapPull(heap,&x) ){ if( (prev&0xffff)>=(x>>16) ){ checkAppendMsg(pCheck, "Multiple uses for byte %u of page %u", x>>16, iPage); break; }else{ nFrag += (x>>16) - (prev&0xffff) - 1; prev = x; } } nFrag += usableSize - (prev&0xffff) - 1; /* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments ** is stored in the fifth field of the b-tree page header. ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the ** number of fragmented free bytes within the cell content area. */ if( heap[0]==0 && nFrag!=data[hdr+7] ){ checkAppendMsg(pCheck, "Fragmentation of %u bytes reported as %u on page %u", nFrag, data[hdr+7], iPage); } } end_of_check: if( !doCoverageCheck ) pPage->isInit = savedIsInit; releasePage(pPage); pCheck->zPfx = saved_zPfx; pCheck->v1 = saved_v1; pCheck->v2 = saved_v2; return depth+1; } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* ** This routine does a complete check of the given BTree file. aRoot[] is ** an array of pages numbers were each page number is the root page of ** a table. nRoot is the number of entries in aRoot. ** ** A read-only or read-write transaction must be opened before calling ** this function. ** ** Write the number of error seen in *pnErr. Except for some memory ** allocation errors, an error message held in memory obtained from ** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is ** returned. If a memory allocation error occurs, NULL is returned. ** ** If the first entry in aRoot[] is 0, that indicates that the list of ** root pages is incomplete. This is a "partial integrity-check". This ** happens when performing an integrity check on a single table. The ** zero is skipped, of course. But in addition, the freelist checks ** and the checks to make sure every page is referenced are also skipped, ** since obviously it is not possible to know which pages are covered by ** the unverified btrees. Except, if aRoot[1] is 1, then the freelist ** checks are still performed. */ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( sqlite3 *db, /* Database connection that is running the check */ Btree *p, /* The btree to be checked */ Pgno *aRoot, /* An array of root pages numbers for individual trees */ int nRoot, /* Number of entries in aRoot[] */ int mxErr, /* Stop reporting errors after this many */ int *pnErr, /* OUT: Write number of errors seen to this variable */ char **pzOut /* OUT: Write the error message string here */ ){ Pgno i; IntegrityCk sCheck; BtShared *pBt = p->pBt; u64 savedDbFlags = pBt->db->flags; char zErr[100]; int bPartial = 0; /* True if not checking all btrees */ int bCkFreelist = 1; /* True to scan the freelist */ VVA_ONLY( int nRef ); assert( nRoot>0 ); /* aRoot[0]==0 means this is a partial check */ if( aRoot[0]==0 ){ assert( nRoot>1 ); bPartial = 1; if( aRoot[1]!=1 ) bCkFreelist = 0; } sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE ); VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) ); assert( nRef>=0 ); memset(&sCheck, 0, sizeof(sCheck)); sCheck.db = db; sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; sCheck.nCkPage = btreePagecount(sCheck.pBt); sCheck.mxErr = mxErr; sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH); sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL; if( sCheck.nCkPage==0 ){ goto integrity_ck_cleanup; } sCheck.aPgRef = sqlite3MallocZero((sCheck.nCkPage / 8)+ 1); if( !sCheck.aPgRef ){ checkOom(&sCheck); goto integrity_ck_cleanup; } sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); if( sCheck.heap==0 ){ checkOom(&sCheck); goto integrity_ck_cleanup; } i = PENDING_BYTE_PAGE(pBt); if( i<=sCheck.nCkPage ) setPageReferenced(&sCheck, i); /* Check the integrity of the freelist */ if( bCkFreelist ){ sCheck.zPfx = "Freelist: "; checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), get4byte(&pBt->pPage1->aData[36])); sCheck.zPfx = 0; } /* Check all the tables. */ #ifndef SQLITE_OMIT_AUTOVACUUM if( !bPartial ){ if( pBt->autoVacuum ){ Pgno mx = 0; Pgno mxInHdr; for(i=0; (int)ipPage1->aData[52]); if( mx!=mxInHdr ){ checkAppendMsg(&sCheck, "max rootpage (%u) disagrees with header (%u)", mx, mxInHdr ); } }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){ checkAppendMsg(&sCheck, "incremental_vacuum enabled with a max rootpage of zero" ); } } #endif testcase( pBt->db->flags & SQLITE_CellSizeCk ); pBt->db->flags &= ~(u64)SQLITE_CellSizeCk; for(i=0; (int)iautoVacuum && aRoot[i]>1 && !bPartial ){ checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); } #endif sCheck.v0 = aRoot[i]; checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64); } pBt->db->flags = savedDbFlags; /* Make sure every page in the file is referenced */ if( !bPartial ){ for(i=1; i<=sCheck.nCkPage && sCheck.mxErr; i++){ #ifdef SQLITE_OMIT_AUTOVACUUM if( getPageReferenced(&sCheck, i)==0 ){ checkAppendMsg(&sCheck, "Page %u: never used", i); } #else /* If the database supports auto-vacuum, make sure no tables contain ** references to pointer-map pages. */ if( getPageReferenced(&sCheck, i)==0 && (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ checkAppendMsg(&sCheck, "Page %u: never used", i); } if( getPageReferenced(&sCheck, i)!=0 && (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ checkAppendMsg(&sCheck, "Page %u: pointer map referenced", i); } #endif } } /* Clean up and report errors. */ integrity_ck_cleanup: sqlite3PageFree(sCheck.heap); sqlite3_free(sCheck.aPgRef); *pnErr = sCheck.nErr; if( sCheck.nErr==0 ){ sqlite3_str_reset(&sCheck.errMsg); *pzOut = 0; }else{ *pzOut = sqlite3StrAccumFinish(&sCheck.errMsg); } /* Make sure this analysis did not leave any unref() pages. */ assert( nRef==sqlite3PagerRefcount(pBt->pPager) ); sqlite3BtreeLeave(p); return sCheck.rc; } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* ** Return the full pathname of the underlying database file. Return ** an empty string if the database is in-memory or a TEMP database. ** ** The pager filename is invariant as long as the pager is ** open so it is safe to access without the BtShared mutex. */ SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *p){ assert( p->pBt->pPager!=0 ); return sqlite3PagerFilename(p->pBt->pPager, 1); } /* ** Return the pathname of the journal file for this database. The return ** value of this routine is the same regardless of whether the journal file ** has been created or not. ** ** The pager journal filename is invariant as long as the pager is ** open so it is safe to access without the BtShared mutex. */ SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *p){ assert( p->pBt->pPager!=0 ); return sqlite3PagerJournalname(p->pBt->pPager); } /* ** Return one of SQLITE_TXN_NONE, SQLITE_TXN_READ, or SQLITE_TXN_WRITE ** to describe the current transaction state of Btree p. */ SQLITE_PRIVATE int sqlite3BtreeTxnState(Btree *p){ assert( p==0 || sqlite3_mutex_held(p->db->mutex) ); return p ? p->inTrans : 0; } #ifndef SQLITE_OMIT_WAL /* ** Run a checkpoint on the Btree passed as the first argument. ** ** Return SQLITE_LOCKED if this or any other connection has an open ** transaction on the shared-cache the argument Btree is connected to. ** ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. */ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; if( p ){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); if( pBt->inTransaction!=TRANS_NONE ){ rc = SQLITE_LOCKED; }else{ rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt); } sqlite3BtreeLeave(p); } return rc; } #endif /* ** Return true if there is currently a backup running on Btree p. */ SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){ assert( p ); assert( sqlite3_mutex_held(p->db->mutex) ); return p->nBackup!=0; } /* ** This function returns a pointer to a blob of memory associated with ** a single shared-btree. The memory is used by client code for its own ** purposes (for example, to store a high-level schema associated with ** the shared-btree). The btree layer manages reference counting issues. ** ** The first time this is called on a shared-btree, nBytes bytes of memory ** are allocated, zeroed, and returned to the caller. For each subsequent ** call the nBytes parameter is ignored and a pointer to the same blob ** of memory returned. ** ** If the nBytes parameter is 0 and the blob of memory has not yet been ** allocated, a null pointer is returned. If the blob has already been ** allocated, it is returned as normal. ** ** Just before the shared-btree is closed, the function passed as the ** xFree argument when the memory allocation was made is invoked on the ** blob of allocated memory. The xFree function should not call sqlite3_free() ** on the memory, the btree layer does that. */ SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); if( !pBt->pSchema && nBytes ){ pBt->pSchema = sqlite3DbMallocZero(0, nBytes); pBt->xFreeSchema = xFree; } sqlite3BtreeLeave(p); return pBt->pSchema; } /* ** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared ** btree as the argument handle holds an exclusive lock on the ** sqlite_schema table. Otherwise SQLITE_OK. */ SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){ int rc; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK); assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE ); sqlite3BtreeLeave(p); return rc; } #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Obtain a lock on the table whose root page is iTab. The ** lock is a write lock if isWritelock is true or a read lock ** if it is false. */ SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ int rc = SQLITE_OK; assert( p->inTrans!=TRANS_NONE ); if( p->sharable ){ u8 lockType = READ_LOCK + isWriteLock; assert( READ_LOCK+1==WRITE_LOCK ); assert( isWriteLock==0 || isWriteLock==1 ); sqlite3BtreeEnter(p); rc = querySharedCacheTableLock(p, iTab, lockType); if( rc==SQLITE_OK ){ rc = setSharedCacheTableLock(p, iTab, lockType); } sqlite3BtreeLeave(p); } return rc; } #endif #ifndef SQLITE_OMIT_INCRBLOB /* ** Argument pCsr must be a cursor opened for writing on an ** INTKEY table currently pointing at a valid table entry. ** This function modifies the data stored as part of that entry. ** ** Only the data content may only be modified, it is not possible to ** change the length of the data stored. If this function is called with ** parameters that attempt to write past the end of the existing data, ** no modifications are made and SQLITE_CORRUPT is returned. */ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ int rc; assert( cursorOwnsBtShared(pCsr) ); assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); assert( pCsr->curFlags & BTCF_Incrblob ); rc = restoreCursorPosition(pCsr); if( rc!=SQLITE_OK ){ return rc; } assert( pCsr->eState!=CURSOR_REQUIRESEEK ); if( pCsr->eState!=CURSOR_VALID ){ return SQLITE_ABORT; } /* Save the positions of all other cursors open on this table. This is ** required in case any of them are holding references to an xFetch ** version of the b-tree page modified by the accessPayload call below. ** ** Note that pCsr must be open on a INTKEY table and saveCursorPosition() ** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence ** saveAllCursors can only return SQLITE_OK. */ VVA_ONLY(rc =) saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr); assert( rc==SQLITE_OK ); /* Check some assumptions: ** (a) the cursor is open for writing, ** (b) there is a read/write transaction open, ** (c) the connection holds a write-lock on the table (if required), ** (d) there are no conflicting read-locks, and ** (e) the cursor points at a valid row of an intKey table. */ if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){ return SQLITE_READONLY; } assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0 && pCsr->pBt->inTransaction==TRANS_WRITE ); assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) ); assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) ); assert( pCsr->pPage->intKey ); return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1); } /* ** Mark this cursor as an incremental blob cursor. */ SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){ pCur->curFlags |= BTCF_Incrblob; pCur->pBtree->hasIncrblobCur = 1; } #endif /* ** Set both the "read version" (single byte at byte offset 18) and ** "write version" (single byte at byte offset 19) fields in the database ** header to iVersion. */ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ BtShared *pBt = pBtree->pBt; int rc; /* Return code */ assert( iVersion==1 || iVersion==2 ); /* If setting the version fields to 1, do not automatically open the ** WAL connection, even if the version fields are currently set to 2. */ pBt->btsFlags &= ~BTS_NO_WAL; if( iVersion==1 ) pBt->btsFlags |= BTS_NO_WAL; rc = sqlite3BtreeBeginTrans(pBtree, 0, 0); if( rc==SQLITE_OK ){ u8 *aData = pBt->pPage1->aData; if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){ rc = sqlite3BtreeBeginTrans(pBtree, 2, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( rc==SQLITE_OK ){ aData[18] = (u8)iVersion; aData[19] = (u8)iVersion; } } } } pBt->btsFlags &= ~BTS_NO_WAL; return rc; } /* ** Return true if the cursor has a hint specified. This routine is ** only used from within assert() statements */ SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){ return (pCsr->hints & mask)!=0; } /* ** Return true if the given Btree is read-only. */ SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){ return (p->pBt->btsFlags & BTS_READ_ONLY)!=0; } /* ** Return the size of the header added to each page by this module. */ SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } /* ** If no transaction is active and the database is not a temp-db, clear ** the in-memory pager cache. */ SQLITE_PRIVATE void sqlite3BtreeClearCache(Btree *p){ BtShared *pBt = p->pBt; if( pBt->inTransaction==TRANS_NONE ){ sqlite3PagerClearCache(pBt->pPager); } } #if !defined(SQLITE_OMIT_SHARED_CACHE) /* ** Return true if the Btree passed as the only argument is sharable. */ SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){ return p->sharable; } /* ** Return the number of connections to the BtShared object accessed by ** the Btree handle passed as the only argument. For private caches ** this is always 1. For shared caches it may be 1 or greater. */ SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){ testcase( p->sharable ); return p->pBt->nRef; } #endif /************** End of btree.c ***********************************************/ /************** Begin file backup.c ******************************************/ /* ** 2009 January 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_backup_XXX() ** API functions and the related features. */ /* #include "sqliteInt.h" */ /* #include "btreeInt.h" */ /* ** Structure allocated for each backup operation. */ struct sqlite3_backup { sqlite3* pDestDb; /* Destination database handle */ Btree *pDest; /* Destination b-tree file */ u32 iDestSchema; /* Original schema cookie in destination */ int bDestLocked; /* True once a write-transaction is open on pDest */ Pgno iNext; /* Page number of the next source page to copy */ sqlite3* pSrcDb; /* Source database handle */ Btree *pSrc; /* Source b-tree file */ int rc; /* Backup process error code */ /* These two variables are set by every call to backup_step(). They are ** read by calls to backup_remaining() and backup_pagecount(). */ Pgno nRemaining; /* Number of pages left to copy */ Pgno nPagecount; /* Total number of pages to copy */ int isAttached; /* True once backup has been registered with pager */ sqlite3_backup *pNext; /* Next backup associated with source pager */ }; /* ** THREAD SAFETY NOTES: ** ** Once it has been created using backup_init(), a single sqlite3_backup ** structure may be accessed via two groups of thread-safe entry points: ** ** * Via the sqlite3_backup_XXX() API function backup_step() and ** backup_finish(). Both these functions obtain the source database ** handle mutex and the mutex associated with the source BtShared ** structure, in that order. ** ** * Via the BackupUpdate() and BackupRestart() functions, which are ** invoked by the pager layer to report various state changes in ** the page cache associated with the source database. The mutex ** associated with the source database BtShared structure will always ** be held when either of these functions are invoked. ** ** The other sqlite3_backup_XXX() API functions, backup_remaining() and ** backup_pagecount() are not thread-safe functions. If they are called ** while some other thread is calling backup_step() or backup_finish(), ** the values returned may be invalid. There is no way for a call to ** BackupUpdate() or BackupRestart() to interfere with backup_remaining() ** or backup_pagecount(). ** ** Depending on the SQLite configuration, the database handles and/or ** the Btree objects may have their own mutexes that require locking. ** Non-sharable Btrees (in-memory databases for example), do not have ** associated mutexes. */ /* ** Return a pointer corresponding to database zDb (i.e. "main", "temp") ** in connection handle pDb. If such a database cannot be found, return ** a NULL pointer and write an error message to pErrorDb. ** ** If the "temp" database is requested, it may need to be opened by this ** function. If an error occurs while doing so, return 0 and write an ** error message to pErrorDb. */ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ int i = sqlite3FindDbName(pDb, zDb); if( i==1 ){ Parse sParse; int rc = 0; sqlite3ParseObjectInit(&sParse,pDb); if( sqlite3OpenTempDatabase(&sParse) ){ sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg); rc = SQLITE_ERROR; } sqlite3DbFree(pErrorDb, sParse.zErrMsg); sqlite3ParseObjectReset(&sParse); if( rc ){ return 0; } } if( i<0 ){ sqlite3ErrorWithMsg(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb); return 0; } return pDb->aDb[i].pBt; } /* ** Attempt to set the page size of the destination to match the page size ** of the source. */ static int setDestPgsz(sqlite3_backup *p){ int rc; rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0); return rc; } /* ** Check that there is no open read-transaction on the b-tree passed as the ** second argument. If there is not, return SQLITE_OK. Otherwise, if there ** is an open read-transaction, return SQLITE_ERROR and leave an error ** message in database handle db. */ static int checkReadTransaction(sqlite3 *db, Btree *p){ if( sqlite3BtreeTxnState(p)!=SQLITE_TXN_NONE ){ sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use"); return SQLITE_ERROR; } return SQLITE_OK; } /* ** Create an sqlite3_backup process to copy the contents of zSrcDb from ** connection handle pSrcDb to zDestDb in pDestDb. If successful, return ** a pointer to the new sqlite3_backup object. ** ** If an error occurs, NULL is returned and an error code and error message ** stored in database handle pDestDb. */ SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3* pDestDb, /* Database to write to */ const char *zDestDb, /* Name of database within pDestDb */ sqlite3* pSrcDb, /* Database connection to read from */ const char *zSrcDb /* Name of database within pSrcDb */ ){ sqlite3_backup *p; /* Value to return */ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(pSrcDb)||!sqlite3SafetyCheckOk(pDestDb) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif /* Lock the source database handle. The destination database ** handle is not locked in this routine, but it is locked in ** sqlite3_backup_step(). The user is required to ensure that no ** other thread accesses the destination handle for the duration ** of the backup operation. Any attempt to use the destination ** database connection while a backup is in progress may cause ** a malfunction or a deadlock. */ sqlite3_mutex_enter(pSrcDb->mutex); sqlite3_mutex_enter(pDestDb->mutex); if( pSrcDb==pDestDb ){ sqlite3ErrorWithMsg( pDestDb, SQLITE_ERROR, "source and destination must be distinct" ); p = 0; }else { /* Allocate space for a new sqlite3_backup object... ** EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a ** call to sqlite3_backup_init() and is destroyed by a call to ** sqlite3_backup_finish(). */ p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup)); if( !p ){ sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT); } } /* If the allocation succeeded, populate the new object. */ if( p ){ p->pSrc = findBtree(pDestDb, pSrcDb, zSrcDb); p->pDest = findBtree(pDestDb, pDestDb, zDestDb); p->pDestDb = pDestDb; p->pSrcDb = pSrcDb; p->iNext = 1; p->isAttached = 0; if( 0==p->pSrc || 0==p->pDest || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK ){ /* One (or both) of the named databases did not exist or an OOM ** error was hit. Or there is a transaction open on the destination ** database. The error has already been written into the pDestDb ** handle. All that is left to do here is free the sqlite3_backup ** structure. */ sqlite3_free(p); p = 0; } } if( p ){ p->pSrc->nBackup++; } sqlite3_mutex_leave(pDestDb->mutex); sqlite3_mutex_leave(pSrcDb->mutex); return p; } /* ** Argument rc is an SQLite error code. Return true if this error is ** considered fatal if encountered during a backup operation. All errors ** are considered fatal except for SQLITE_BUSY and SQLITE_LOCKED. */ static int isFatalError(int rc){ return (rc!=SQLITE_OK && rc!=SQLITE_BUSY && ALWAYS(rc!=SQLITE_LOCKED)); } /* ** Parameter zSrcData points to a buffer containing the data for ** page iSrcPg from the source database. Copy this data into the ** destination database. */ static int backupOnePage( sqlite3_backup *p, /* Backup handle */ Pgno iSrcPg, /* Source database page to backup */ const u8 *zSrcData, /* Source database page data */ int bUpdate /* True for an update, false otherwise */ ){ Pager * const pDestPager = sqlite3BtreePager(p->pDest); const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; int rc = SQLITE_OK; i64 iOff; assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 ); assert( p->bDestLocked ); assert( !isFatalError(p->rc) ); assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ); assert( zSrcData ); assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 ); /* This loop runs once for each destination page spanned by the source ** page. For each iteration, variable iOff is set to the byte offset ** of the destination page. */ for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOffpDest->pBt) ) continue; if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg, 0)) && SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg)) ){ const u8 *zIn = &zSrcData[iOff%nSrcPgsz]; u8 *zDestData = sqlite3PagerGetData(pDestPg); u8 *zOut = &zDestData[iOff%nDestPgsz]; /* Copy the data from the source page into the destination page. ** Then clear the Btree layer MemPage.isInit flag. Both this module ** and the pager code use this trick (clearing the first byte ** of the page 'extra' space to invalidate the Btree layers ** cached parse of the page). MemPage.isInit is marked ** "MUST BE FIRST" for this purpose. */ memcpy(zOut, zIn, nCopy); ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0; if( iOff==0 && bUpdate==0 ){ sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc)); } } sqlite3PagerUnref(pDestPg); } return rc; } /* ** If pFile is currently larger than iSize bytes, then truncate it to ** exactly iSize bytes. If pFile is not larger than iSize bytes, then ** this function is a no-op. ** ** Return SQLITE_OK if everything is successful, or an SQLite error ** code if an error occurs. */ static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){ i64 iCurrent; int rc = sqlite3OsFileSize(pFile, &iCurrent); if( rc==SQLITE_OK && iCurrent>iSize ){ rc = sqlite3OsTruncate(pFile, iSize); } return rc; } /* ** Register this backup object with the associated source pager for ** callbacks when pages are changed or the cache invalidated. */ static void attachBackupObject(sqlite3_backup *p){ sqlite3_backup **pp; assert( sqlite3BtreeHoldsMutex(p->pSrc) ); pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); p->pNext = *pp; *pp = p; p->isAttached = 1; } /* ** Copy nPage pages from the source b-tree to the destination. */ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ int rc; int destMode; /* Destination journal mode */ int pgszSrc = 0; /* Source page size */ int pgszDest = 0; /* Destination page size */ #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); if( p->pDestDb ){ sqlite3_mutex_enter(p->pDestDb->mutex); } rc = p->rc; if( !isFatalError(rc) ){ Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ int ii; /* Iterator variable */ int nSrcPage = -1; /* Size of source db in pages */ int bCloseTrans = 0; /* True if src db requires unlocking */ /* If the source pager is currently in a write-transaction, return ** SQLITE_BUSY immediately. */ if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){ rc = SQLITE_BUSY; }else{ rc = SQLITE_OK; } /* If there is no open read-transaction on the source database, open ** one now. If a transaction is opened here, then it will be closed ** before this function exits. */ if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){ rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0); bCloseTrans = 1; } /* If the destination database has not yet been locked (i.e. if this ** is the first call to backup_step() for the current backup operation), ** try to set its page size to the same as the source database. This ** is especially important on ZipVFS systems, as in that case it is ** not possible to create a database file that uses one page size by ** writing to it with another. */ if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){ rc = SQLITE_NOMEM; } /* Lock the destination database, if it is not locked already. */ if( SQLITE_OK==rc && p->bDestLocked==0 && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2, (int*)&p->iDestSchema)) ){ p->bDestLocked = 1; } /* Do not allow backup if the destination database is in WAL mode ** and the page sizes are different between source and destination */ pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); pgszDest = sqlite3BtreeGetPageSize(p->pDest); destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest)); if( SQLITE_OK==rc && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager)) && pgszSrc!=pgszDest ){ rc = SQLITE_READONLY; } /* Now that there is a read-lock on the source database, query the ** source pager for the number of pages in the database. */ nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc); assert( nSrcPage>=0 ); for(ii=0; (nPage<0 || iiiNext<=(Pgno)nSrcPage && !rc; ii++){ const Pgno iSrcPg = p->iNext; /* Source page number */ if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){ DbPage *pSrcPg; /* Source page object */ rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg,PAGER_GET_READONLY); if( rc==SQLITE_OK ){ rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0); sqlite3PagerUnref(pSrcPg); } } p->iNext++; } if( rc==SQLITE_OK ){ p->nPagecount = nSrcPage; p->nRemaining = nSrcPage+1-p->iNext; if( p->iNext>(Pgno)nSrcPage ){ rc = SQLITE_DONE; }else if( !p->isAttached ){ attachBackupObject(p); } } /* Update the schema version field in the destination database. This ** is to make sure that the schema-version really does change in ** the case where the source and destination databases have the ** same schema version. */ if( rc==SQLITE_DONE ){ if( nSrcPage==0 ){ rc = sqlite3BtreeNewDb(p->pDest); nSrcPage = 1; } if( rc==SQLITE_OK || rc==SQLITE_DONE ){ rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1); } if( rc==SQLITE_OK ){ if( p->pDestDb ){ sqlite3ResetAllSchemasOfConnection(p->pDestDb); } if( destMode==PAGER_JOURNALMODE_WAL ){ rc = sqlite3BtreeSetVersion(p->pDest, 2); } } if( rc==SQLITE_OK ){ int nDestTruncate; /* Set nDestTruncate to the final number of pages in the destination ** database. The complication here is that the destination page ** size may be different to the source page size. ** ** If the source page size is smaller than the destination page size, ** round up. In this case the call to sqlite3OsTruncate() below will ** fix the size of the file. However it is important to call ** sqlite3PagerTruncateImage() here so that any pages in the ** destination file that lie beyond the nDestTruncate page mark are ** journalled by PagerCommitPhaseOne() before they are destroyed ** by the file truncation. */ assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) ); assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) ); if( pgszSrcpDest->pBt) ){ nDestTruncate--; } }else{ nDestTruncate = nSrcPage * (pgszSrc/pgszDest); } assert( nDestTruncate>0 ); if( pgszSrc= iSize || ( nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest )); /* This block ensures that all data required to recreate the original ** database has been stored in the journal for pDestPager and the ** journal synced to disk. So at this point we may safely modify ** the database file in any way, knowing that if a power failure ** occurs, the original database will be reconstructed from the ** journal file. */ sqlite3PagerPagecount(pDestPager, &nDstPage); for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){ if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){ DbPage *pPg; rc = sqlite3PagerGet(pDestPager, iPg, &pPg, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pPg); sqlite3PagerUnref(pPg); } } } if( rc==SQLITE_OK ){ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); } /* Write the extra pages and truncate the database file as required */ iEnd = MIN(PENDING_BYTE + pgszDest, iSize); for( iOff=PENDING_BYTE+pgszSrc; rc==SQLITE_OK && iOffpDest, 0)) ){ rc = SQLITE_DONE; } } } /* If bCloseTrans is true, then this function opened a read transaction ** on the source database. Close the read transaction here. There is ** no need to check the return values of the btree methods here, as ** "committing" a read-only transaction cannot fail. */ if( bCloseTrans ){ TESTONLY( int rc2 ); TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0); TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0); assert( rc2==SQLITE_OK ); } if( rc==SQLITE_IOERR_NOMEM ){ rc = SQLITE_NOMEM_BKPT; } p->rc = rc; } if( p->pDestDb ){ sqlite3_mutex_leave(p->pDestDb->mutex); } sqlite3BtreeLeave(p->pSrc); sqlite3_mutex_leave(p->pSrcDb->mutex); return rc; } /* ** Release all resources associated with an sqlite3_backup* handle. */ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){ sqlite3_backup **pp; /* Ptr to head of pagers backup list */ sqlite3 *pSrcDb; /* Source database connection */ int rc; /* Value to return */ /* Enter the mutexes */ if( p==0 ) return SQLITE_OK; pSrcDb = p->pSrcDb; sqlite3_mutex_enter(pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); if( p->pDestDb ){ sqlite3_mutex_enter(p->pDestDb->mutex); } /* Detach this backup from the source pager. */ if( p->pDestDb ){ p->pSrc->nBackup--; } if( p->isAttached ){ pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); assert( pp!=0 ); while( *pp!=p ){ pp = &(*pp)->pNext; assert( pp!=0 ); } *pp = p->pNext; } /* If a transaction is still open on the Btree, roll it back. */ sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; if( p->pDestDb ){ sqlite3Error(p->pDestDb, rc); /* Exit the mutexes and free the backup context structure. */ sqlite3LeaveMutexAndCloseZombie(p->pDestDb); } sqlite3BtreeLeave(p->pSrc); if( p->pDestDb ){ /* EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a ** call to sqlite3_backup_init() and is destroyed by a call to ** sqlite3_backup_finish(). */ sqlite3_free(p); } sqlite3LeaveMutexAndCloseZombie(pSrcDb); return rc; } /* ** Return the number of pages still to be backed up as of the most recent ** call to sqlite3_backup_step(). */ SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){ #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return p->nRemaining; } /* ** Return the total number of pages in the source database as of the most ** recent call to sqlite3_backup_step(). */ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){ #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return p->nPagecount; } /* ** This function is called after the contents of page iPage of the ** source database have been modified. If page iPage has already been ** copied into the destination database, then the data written to the ** destination is now invalidated. The destination copy of iPage needs ** to be updated with the new data before the backup operation is ** complete. ** ** It is assumed that the mutex associated with the BtShared object ** corresponding to the source database is held when this function is ** called. */ static SQLITE_NOINLINE void backupUpdate( sqlite3_backup *p, Pgno iPage, const u8 *aData ){ assert( p!=0 ); do{ assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) ); if( !isFatalError(p->rc) && iPageiNext ){ /* The backup process p has already copied page iPage. But now it ** has been modified by a transaction on the source pager. Copy ** the new data into the backup. */ int rc; assert( p->pDestDb ); sqlite3_mutex_enter(p->pDestDb->mutex); rc = backupOnePage(p, iPage, aData, 1); sqlite3_mutex_leave(p->pDestDb->mutex); assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED ); if( rc!=SQLITE_OK ){ p->rc = rc; } } }while( (p = p->pNext)!=0 ); } SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){ if( pBackup ) backupUpdate(pBackup, iPage, aData); } /* ** Restart the backup process. This is called when the pager layer ** detects that the database has been modified by an external database ** connection. In this case there is no way of knowing which of the ** pages that have been copied into the destination database are still ** valid and which are not, so the entire process needs to be restarted. ** ** It is assumed that the mutex associated with the BtShared object ** corresponding to the source database is held when this function is ** called. */ SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *pBackup){ sqlite3_backup *p; /* Iterator variable */ for(p=pBackup; p; p=p->pNext){ assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) ); p->iNext = 1; } } #ifndef SQLITE_OMIT_VACUUM /* ** Copy the complete content of pBtFrom into pBtTo. A transaction ** must be active for both files. ** ** The size of file pTo may be reduced by this operation. If anything ** goes wrong, the transaction on pTo is rolled back. If successful, the ** transaction is committed before returning. */ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ int rc; sqlite3_file *pFd; /* File descriptor for database pTo */ sqlite3_backup b; sqlite3BtreeEnter(pTo); sqlite3BtreeEnter(pFrom); assert( sqlite3BtreeTxnState(pTo)==SQLITE_TXN_WRITE ); pFd = sqlite3PagerFile(sqlite3BtreePager(pTo)); if( pFd->pMethods ){ i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom); rc = sqlite3OsFileControl(pFd, SQLITE_FCNTL_OVERWRITE, &nByte); if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; if( rc ) goto copy_finished; } /* Set up an sqlite3_backup object. sqlite3_backup.pDestDb must be set ** to 0. This is used by the implementations of sqlite3_backup_step() ** and sqlite3_backup_finish() to detect that they are being called ** from this function, not directly by the user. */ memset(&b, 0, sizeof(b)); b.pSrcDb = pFrom->db; b.pSrc = pFrom; b.pDest = pTo; b.iNext = 1; /* 0x7FFFFFFF is the hard limit for the number of pages in a database ** file. By passing this as the number of pages to copy to ** sqlite3_backup_step(), we can guarantee that the copy finishes ** within a single call (unless an error occurs). The assert() statement ** checks this assumption - (p->rc) should be set to either SQLITE_DONE ** or an error code. */ sqlite3_backup_step(&b, 0x7FFFFFFF); assert( b.rc!=SQLITE_OK ); rc = sqlite3_backup_finish(&b); if( rc==SQLITE_OK ){ pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; }else{ sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); } assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE ); copy_finished: sqlite3BtreeLeave(pFrom); sqlite3BtreeLeave(pTo); return rc; } #endif /* SQLITE_OMIT_VACUUM */ /************** End of backup.c **********************************************/ /************** Begin file vdbemem.c *****************************************/ /* ** 2004 May 26 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code use to manipulate "Mem" structure. A "Mem" ** stores a single value in the VDBE. Mem is an opaque structure visible ** only within the VDBE. Interface routines refer to a Mem using the ** name sqlite_value */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ /* True if X is a power of two. 0 is considered a power of two here. ** In other words, return true if X has at most one bit set. */ #define ISPOWEROF2(X) (((X)&((X)-1))==0) #ifdef SQLITE_DEBUG /* ** Check invariants on a Mem object. ** ** This routine is intended for use inside of assert() statements, like ** this: assert( sqlite3VdbeCheckMemInvariants(pMem) ); */ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ /* If MEM_Dyn is set then Mem.xDel!=0. ** Mem.xDel might not be initialized if MEM_Dyn is clear. */ assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); /* MEM_Dyn may only be set if Mem.szMalloc==0. In this way we ** ensure that if Mem.szMalloc>0 then it is safe to do ** Mem.z = Mem.zMalloc without having to check Mem.flags&MEM_Dyn. ** That saves a few cycles in inner loops. */ assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 ); /* Cannot have more than one of MEM_Int, MEM_Real, or MEM_IntReal */ assert( ISPOWEROF2(p->flags & (MEM_Int|MEM_Real|MEM_IntReal)) ); if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_Agg))==0 ); /* If MEM_Null is set, then either the value is a pure NULL (the usual ** case) or it is a pointer set using sqlite3_bind_pointer() or ** sqlite3_result_pointer(). If a pointer, then MEM_Term must also be ** set. */ if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){ /* This is a pointer type. There may be a flag to indicate what to ** do with the pointer. */ assert( ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 ); /* No other bits set */ assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype|MEM_FromBind |MEM_Dyn|MEM_Ephem|MEM_Static))==0 ); }else{ /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn, ** MEM_Ephem, MEM_Cleared, or MEM_Subtype */ } }else{ /* The MEM_Cleared bit is only allowed on NULLs */ assert( (p->flags & MEM_Cleared)==0 ); } /* The szMalloc field holds the correct memory allocation size */ assert( p->szMalloc==0 || (p->flags==MEM_Undefined && p->szMalloc<=sqlite3DbMallocSize(p->db,p->zMalloc)) || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc)); /* If p holds a string or blob, the Mem.z must point to exactly ** one of the following: ** ** (1) Memory in Mem.zMalloc and managed by the Mem object ** (2) Memory to be freed using Mem.xDel ** (3) An ephemeral string or blob ** (4) A static string or blob */ if( (p->flags & (MEM_Str|MEM_Blob)) && p->n>0 ){ assert( ((p->szMalloc>0 && p->z==p->zMalloc)? 1 : 0) + ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1 ); } return 1; } #endif /* ** Render a Mem object which is one of MEM_Int, MEM_Real, or MEM_IntReal ** into a buffer. */ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ StrAccum acc; assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) ); assert( sz>22 ); if( p->flags & MEM_Int ){ #if GCC_VERSION>=7000000 /* Work-around for GCC bug ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */ i64 x; assert( (p->flags&MEM_Int)*2==sizeof(x) ); memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2); p->n = sqlite3Int64ToText(x, zBuf); #else p->n = sqlite3Int64ToText(p->u.i, zBuf); #endif }else{ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0); sqlite3_str_appendf(&acc, "%!.15g", (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r); assert( acc.zText==zBuf && acc.mxAlloc<=0 ); zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */ p->n = acc.nChar; } } #ifdef SQLITE_DEBUG /* ** Validity checks on pMem. pMem holds a string. ** ** (1) Check that string value of pMem agrees with its integer or real value. ** (2) Check that the string is correctly zero terminated ** ** A single int or real value always converts to the same strings. But ** many different strings can be converted into the same int or real. ** If a table contains a numeric value and an index is based on the ** corresponding string value, then it is important that the string be ** derived from the numeric value, not the other way around, to ensure ** that the index and table are consistent. See ticket ** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for ** an example. ** ** This routine looks at pMem to verify that if it has both a numeric ** representation and a string representation then the string rep has ** been derived from the numeric and not the other way around. It returns ** true if everything is ok and false if there is a problem. ** ** This routine is for use inside of assert() statements only. */ SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){ Mem tmp; char zBuf[100]; char *z; int i, j, incr; if( (p->flags & MEM_Str)==0 ) return 1; if( p->db && p->db->mallocFailed ) return 1; if( p->flags & MEM_Term ){ /* Insure that the string is properly zero-terminated. Pay particular ** attention to the case where p->n is odd */ if( p->szMalloc>0 && p->z==p->zMalloc ){ assert( p->enc==SQLITE_UTF8 || p->szMalloc >= ((p->n+1)&~1)+2 ); assert( p->enc!=SQLITE_UTF8 || p->szMalloc >= p->n+1 ); } assert( p->z[p->n]==0 ); assert( p->enc==SQLITE_UTF8 || p->z[(p->n+1)&~1]==0 ); assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 ); } if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1; memcpy(&tmp, p, sizeof(tmp)); vdbeMemRenderNum(sizeof(zBuf), zBuf, &tmp); z = p->z; i = j = 0; incr = 1; if( p->enc!=SQLITE_UTF8 ){ incr = 2; if( p->enc==SQLITE_UTF16BE ) z++; } while( zBuf[j] ){ if( zBuf[j++]!=z[i] ) return 0; i += incr; } return 1; } #endif /* SQLITE_DEBUG */ /* ** If pMem is an object with a valid string representation, this routine ** ensures the internal encoding for the string representation is ** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE. ** ** If pMem is not a string object, or the encoding of the string ** representation is already stored using the requested encoding, then this ** routine is a no-op. ** ** SQLITE_OK is returned if the conversion is successful (or not required). ** SQLITE_NOMEM may be returned if a malloc() fails during conversion ** between formats. */ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ #ifndef SQLITE_OMIT_UTF16 int rc; #endif assert( pMem!=0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); if( !(pMem->flags&MEM_Str) ){ pMem->enc = desiredEnc; return SQLITE_OK; } if( pMem->enc==desiredEnc ){ return SQLITE_OK; } assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); #ifdef SQLITE_OMIT_UTF16 return SQLITE_ERROR; #else /* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned, ** then the encoding of the value may not have changed. */ rc = sqlite3VdbeMemTranslate(pMem, (u8)desiredEnc); assert(rc==SQLITE_OK || rc==SQLITE_NOMEM); assert(rc==SQLITE_OK || pMem->enc!=desiredEnc); assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc); return rc; #endif } /* ** Make sure pMem->z points to a writable allocation of at least n bytes. ** ** If the bPreserve argument is true, then copy of the content of ** pMem->z into the new allocation. pMem must be either a string or ** blob if bPreserve is true. If bPreserve is false, any prior content ** in pMem->z is discarded. */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( sqlite3VdbeCheckMemInvariants(pMem) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); testcase( pMem->db==0 ); /* If the bPreserve flag is set to true, then the memory cell must already ** contain a valid string or blob value. */ assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) ); testcase( bPreserve && pMem->z==0 ); assert( pMem->szMalloc==0 || (pMem->flags==MEM_Undefined && pMem->szMalloc<=sqlite3DbMallocSize(pMem->db,pMem->zMalloc)) || pMem->szMalloc==sqlite3DbMallocSize(pMem->db,pMem->zMalloc)); if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){ if( pMem->db ){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); }else{ pMem->zMalloc = sqlite3Realloc(pMem->z, n); if( pMem->zMalloc==0 ) sqlite3_free(pMem->z); pMem->z = pMem->zMalloc; } bPreserve = 0; }else{ if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); } if( pMem->zMalloc==0 ){ sqlite3VdbeMemSetNull(pMem); pMem->z = 0; pMem->szMalloc = 0; return SQLITE_NOMEM_BKPT; }else{ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); } if( bPreserve && pMem->z ){ assert( pMem->z!=pMem->zMalloc ); memcpy(pMem->zMalloc, pMem->z, pMem->n); } if( (pMem->flags&MEM_Dyn)!=0 ){ assert( pMem->xDel!=0 && pMem->xDel!=SQLITE_DYNAMIC ); pMem->xDel((void *)(pMem->z)); } pMem->z = pMem->zMalloc; pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static); return SQLITE_OK; } /* ** Change the pMem->zMalloc allocation to be at least szNew bytes. ** If pMem->zMalloc already meets or exceeds the requested size, this ** routine is a no-op. ** ** Any prior string or blob content in the pMem object may be discarded. ** The pMem->xDel destructor is called, if it exists. Though MEM_Str ** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, MEM_IntReal, ** and MEM_Null values are preserved. ** ** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM) ** if unable to complete the resizing. */ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ assert( CORRUPT_DB || szNew>0 ); assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 ); if( pMem->szMallocflags & MEM_Dyn)==0 ); pMem->z = pMem->zMalloc; pMem->flags &= (MEM_Null|MEM_Int|MEM_Real|MEM_IntReal); return SQLITE_OK; } /* ** If pMem is already a string, detect if it is a zero-terminated ** string, or make it into one if possible, and mark it as such. ** ** This is an optimization. Correct operation continues even if ** this routine is a no-op. */ SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ if( (pMem->flags & (MEM_Str|MEM_Term|MEM_Ephem|MEM_Static))!=MEM_Str ){ /* pMem must be a string, and it cannot be an ephemeral or static string */ return; } if( pMem->enc!=SQLITE_UTF8 ) return; if( NEVER(pMem->z==0) ) return; if( pMem->flags & MEM_Dyn ){ if( pMem->xDel==sqlite3_free && sqlite3_msize(pMem->z) >= (u64)(pMem->n+1) ){ pMem->z[pMem->n] = 0; pMem->flags |= MEM_Term; return; } if( pMem->xDel==sqlite3RCStrUnref ){ /* Blindly assume that all RCStr objects are zero-terminated */ pMem->flags |= MEM_Term; return; } }else if( pMem->szMalloc >= pMem->n+1 ){ pMem->z[pMem->n] = 0; pMem->flags |= MEM_Term; return; } } /* ** It is already known that pMem contains an unterminated string. ** Add the zero terminator. ** ** Three bytes of zero are added. In this way, there is guaranteed ** to be a double-zero byte at an even byte boundary in order to ** terminate a UTF16 string, even if the initial size of the buffer ** is an odd number of bytes. */ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ if( sqlite3VdbeMemGrow(pMem, pMem->n+3, 1) ){ return SQLITE_NOMEM_BKPT; } pMem->z[pMem->n] = 0; pMem->z[pMem->n+1] = 0; pMem->z[pMem->n+2] = 0; pMem->flags |= MEM_Term; return SQLITE_OK; } /* ** Change pMem so that its MEM_Str or MEM_Blob value is stored in ** MEM.zMalloc, where it can be safely written. ** ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){ if( ExpandBlob(pMem) ) return SQLITE_NOMEM; if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){ int rc = vdbeMemAddTerminator(pMem); if( rc ) return rc; } } pMem->flags &= ~MEM_Ephem; #ifdef SQLITE_DEBUG pMem->pScopyFrom = 0; #endif return SQLITE_OK; } /* ** If the given Mem* has a zero-filled tail, turn it into an ordinary ** blob stored in dynamically allocated space. */ #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; assert( pMem!=0 ); assert( pMem->flags & MEM_Zero ); assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) ); testcase( sqlite3_value_nochange(pMem) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); /* Set nByte to the number of bytes required to store the expanded blob. */ nByte = pMem->n + pMem->u.nZero; if( nByte<=0 ){ if( (pMem->flags & MEM_Blob)==0 ) return SQLITE_OK; nByte = 1; } if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ return SQLITE_NOMEM_BKPT; } assert( pMem->z!=0 ); assert( sqlite3DbMallocSize(pMem->db,pMem->z) >= nByte ); memset(&pMem->z[pMem->n], 0, pMem->u.nZero); pMem->n += pMem->u.nZero; pMem->flags &= ~(MEM_Zero|MEM_Term); return SQLITE_OK; } #endif /* ** Make sure the given Mem is \u0000 terminated. */ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) ); testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 ); if( (pMem->flags & (MEM_Term|MEM_Str))!=MEM_Str ){ return SQLITE_OK; /* Nothing to do */ }else{ return vdbeMemAddTerminator(pMem); } } /* ** Add MEM_Str to the set of representations for the given Mem. This ** routine is only called if pMem is a number of some kind, not a NULL ** or a BLOB. ** ** Existing representations MEM_Int, MEM_Real, or MEM_IntReal are invalidated ** if bForce is true but are retained if bForce is false. ** ** A MEM_Null value will never be passed to this function. This function is ** used for converting values to text for returning to the user (i.e. via ** sqlite3_value_text()), or for ensuring that values to be used as btree ** keys are strings. In the former case a NULL pointer is returned the ** user and the latter is an internal programming error. */ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ const int nByte = 32; assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !(pMem->flags&MEM_Zero) ); assert( !(pMem->flags&(MEM_Str|MEM_Blob)) ); assert( pMem->flags&(MEM_Int|MEM_Real|MEM_IntReal) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){ pMem->enc = 0; return SQLITE_NOMEM_BKPT; } vdbeMemRenderNum(nByte, pMem->z, pMem); assert( pMem->z!=0 ); assert( pMem->n==(int)sqlite3Strlen30NN(pMem->z) ); pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str|MEM_Term; if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); sqlite3VdbeChangeEncoding(pMem, enc); return SQLITE_OK; } /* ** Memory cell pMem contains the context of an aggregate function. ** This routine calls the finalize method for that function. The ** result of the aggregate is stored back into pMem. ** ** Return SQLITE_ERROR if the finalizer reports an error. SQLITE_OK ** otherwise. */ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ sqlite3_context ctx; Mem t; assert( pFunc!=0 ); assert( pMem!=0 ); assert( pMem->db!=0 ); assert( pFunc->xFinalize!=0 ); assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); assert( sqlite3_mutex_held(pMem->db->mutex) ); memset(&ctx, 0, sizeof(ctx)); memset(&t, 0, sizeof(t)); t.flags = MEM_Null; t.db = pMem->db; ctx.pOut = &t; ctx.pMem = pMem; ctx.pFunc = pFunc; ctx.enc = ENC(t.db); pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */ assert( (pMem->flags & MEM_Dyn)==0 ); if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); memcpy(pMem, &t, sizeof(t)); return ctx.isError; } /* ** Memory cell pAccum contains the context of an aggregate function. ** This routine calls the xValue method for that function and stores ** the results in memory cell pMem. ** ** SQLITE_ERROR is returned if xValue() reports an error. SQLITE_OK ** otherwise. */ #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){ sqlite3_context ctx; assert( pFunc!=0 ); assert( pFunc->xValue!=0 ); assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef ); assert( pAccum->db!=0 ); assert( sqlite3_mutex_held(pAccum->db->mutex) ); memset(&ctx, 0, sizeof(ctx)); sqlite3VdbeMemSetNull(pOut); ctx.pOut = pOut; ctx.pMem = pAccum; ctx.pFunc = pFunc; ctx.enc = ENC(pAccum->db); pFunc->xValue(&ctx); return ctx.isError; } #endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** If the memory cell contains a value that must be freed by ** invoking the external callback in Mem.xDel, then this routine ** will free that value. It also sets Mem.flags to MEM_Null. ** ** This is a helper routine for sqlite3VdbeMemSetNull() and ** for sqlite3VdbeMemRelease(). Use those other routines as the ** entry point for releasing Mem resources. */ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); assert( VdbeMemDynamic(p) ); if( p->flags&MEM_Agg ){ sqlite3VdbeMemFinalize(p, p->u.pDef); assert( (p->flags & MEM_Agg)==0 ); testcase( p->flags & MEM_Dyn ); } if( p->flags&MEM_Dyn ){ assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); p->xDel((void *)p->z); } p->flags = MEM_Null; } /* ** Release memory held by the Mem p, both external memory cleared ** by p->xDel and memory in p->zMalloc. ** ** This is a helper routine invoked by sqlite3VdbeMemRelease() in ** the unusual case where there really is memory in p that needs ** to be freed. */ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){ if( VdbeMemDynamic(p) ){ vdbeMemClearExternAndSetNull(p); } if( p->szMalloc ){ sqlite3DbFreeNN(p->db, p->zMalloc); p->szMalloc = 0; } p->z = 0; } /* ** Release any memory resources held by the Mem. Both the memory that is ** free by Mem.xDel and the Mem.zMalloc allocation are freed. ** ** Use this routine prior to clean up prior to abandoning a Mem, or to ** reset a Mem back to its minimum memory utilization. ** ** Use sqlite3VdbeMemSetNull() to release just the Mem.xDel space ** prior to inserting new content into the Mem. */ SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){ assert( sqlite3VdbeCheckMemInvariants(p) ); if( VdbeMemDynamic(p) || p->szMalloc ){ vdbeMemClear(p); } } /* Like sqlite3VdbeMemRelease() but faster for cases where we ** know in advance that the Mem is not MEM_Dyn or MEM_Agg. */ SQLITE_PRIVATE void sqlite3VdbeMemReleaseMalloc(Mem *p){ assert( !VdbeMemDynamic(p) ); if( p->szMalloc ) vdbeMemClear(p); } /* ** Return some kind of integer value which is the best we can do ** at representing the value that *pMem describes as an integer. ** If pMem is an integer, then the value is exact. If pMem is ** a floating-point then the value returned is the integer part. ** If pMem is a string or blob, then we make an attempt to convert ** it into an integer and return that. If pMem represents an ** an SQL-NULL value, return 0. ** ** If pMem represents a string value, its encoding might be changed. */ static SQLITE_NOINLINE i64 memIntValue(const Mem *pMem){ i64 value = 0; sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); return value; } SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem *pMem){ int flags; assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); flags = pMem->flags; if( flags & (MEM_Int|MEM_IntReal) ){ testcase( flags & MEM_IntReal ); return pMem->u.i; }else if( flags & MEM_Real ){ return sqlite3RealToI64(pMem->u.r); }else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){ return memIntValue(pMem); }else{ return 0; } } /* ** Return the best representation of pMem that we can get into a ** double. If pMem is already a double or an integer, return its ** value. If it is a string or blob, try to convert it to a double. ** If it is a NULL, return 0.0. */ static SQLITE_NOINLINE double memRealValue(Mem *pMem){ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ double val = (double)0; sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); return val; } SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( pMem->flags & MEM_Real ){ return pMem->u.r; }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ testcase( pMem->flags & MEM_IntReal ); return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ return memRealValue(pMem); }else{ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return (double)0; } } /* ** Return 1 if pMem represents true, and return 0 if pMem represents false. ** Return the value ifNull if pMem is NULL. */ SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ testcase( pMem->flags & MEM_IntReal ); if( pMem->flags & (MEM_Int|MEM_IntReal) ) return pMem->u.i!=0; if( pMem->flags & MEM_Null ) return ifNull; return sqlite3VdbeRealValue(pMem)!=0.0; } /* ** The MEM structure is already a MEM_Real or MEM_IntReal. Try to ** make it a MEM_Int if we can. */ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ assert( pMem!=0 ); assert( pMem->flags & (MEM_Real|MEM_IntReal) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( pMem->flags & MEM_IntReal ){ MemSetTypeFlag(pMem, MEM_Int); }else{ i64 ix = sqlite3RealToI64(pMem->u.r); /* Only mark the value as an integer if ** ** (1) the round-trip conversion real->int->real is a no-op, and ** (2) The integer is neither the largest nor the smallest ** possible integer (ticket #3922) ** ** The second and third terms in the following conditional enforces ** the second condition under the assumption that addition overflow causes ** values to wrap around. */ if( pMem->u.r==ix && ix>SMALLEST_INT64 && ixu.i = ix; MemSetTypeFlag(pMem, MEM_Int); } } } /* ** Convert pMem to type integer. Invalidate any prior representations. */ SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); pMem->u.i = sqlite3VdbeIntValue(pMem); MemSetTypeFlag(pMem, MEM_Int); return SQLITE_OK; } /* ** Convert pMem so that it is of type MEM_Real. ** Invalidate any prior representations. */ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); pMem->u.r = sqlite3VdbeRealValue(pMem); MemSetTypeFlag(pMem, MEM_Real); return SQLITE_OK; } /* Compare a floating point value to an integer. Return true if the two ** values are the same within the precision of the floating point value. ** ** This function assumes that i was obtained by assignment from r1. ** ** For some versions of GCC on 32-bit machines, if you do the more obvious ** comparison of "r1==(double)i" you sometimes get an answer of false even ** though the r1 and (double)i values are bit-for-bit the same. */ SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ double r2 = (double)i; return r1==0.0 || (memcmp(&r1, &r2, sizeof(r1))==0 && i >= -2251799813685248LL && i < 2251799813685248LL); } /* Convert a floating point value to its closest integer. Do so in ** a way that avoids 'outside the range of representable values' warnings ** from UBSAN. */ SQLITE_PRIVATE i64 sqlite3RealToI64(double r){ if( r<-9223372036854774784.0 ) return SMALLEST_INT64; if( r>+9223372036854774784.0 ) return LARGEST_INT64; return (i64)r; } /* ** Convert pMem so that it has type MEM_Real or MEM_Int. ** Invalidate any prior representations. ** ** Every effort is made to force the conversion, even if the input ** is a string that does not look completely like a number. Convert ** as much of the string as we can and ignore the rest. */ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ assert( pMem!=0 ); testcase( pMem->flags & MEM_Int ); testcase( pMem->flags & MEM_Real ); testcase( pMem->flags & MEM_IntReal ); testcase( pMem->flags & MEM_Null ); if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){ int rc; sqlite3_int64 ix; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1) || sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r))) ){ pMem->u.i = ix; MemSetTypeFlag(pMem, MEM_Int); }else{ MemSetTypeFlag(pMem, MEM_Real); } } assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))!=0 ); pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero); return SQLITE_OK; } /* ** Cast the datatype of the value in pMem according to the affinity ** "aff". Casting is different from applying affinity in that a cast ** is forced. In other words, the value is converted into the desired ** affinity even if that results in loss of data. This routine is ** used (for example) to implement the SQL "cast()" operator. */ SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ if( pMem->flags & MEM_Null ) return SQLITE_OK; switch( aff ){ case SQLITE_AFF_BLOB: { /* Really a cast to BLOB */ if( (pMem->flags & MEM_Blob)==0 ){ sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); if( pMem->flags & MEM_Str ) MemSetTypeFlag(pMem, MEM_Blob); }else{ pMem->flags &= ~(MEM_TypeMask&~MEM_Blob); } break; } case SQLITE_AFF_NUMERIC: { sqlite3VdbeMemNumerify(pMem); break; } case SQLITE_AFF_INTEGER: { sqlite3VdbeMemIntegerify(pMem); break; } case SQLITE_AFF_REAL: { sqlite3VdbeMemRealify(pMem); break; } default: { int rc; assert( aff==SQLITE_AFF_TEXT ); assert( MEM_Str==(MEM_Blob>>3) ); pMem->flags |= (pMem->flags&MEM_Blob)>>3; sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero); if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1; rc = sqlite3VdbeChangeEncoding(pMem, encoding); if( rc ) return rc; sqlite3VdbeMemZeroTerminateIfAble(pMem); } } return SQLITE_OK; } /* ** Initialize bulk memory to be a consistent Mem object. ** ** The minimum amount of initialization feasible is performed. */ SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem *pMem, sqlite3 *db, u16 flags){ assert( (flags & ~MEM_TypeMask)==0 ); pMem->flags = flags; pMem->db = db; pMem->szMalloc = 0; } /* ** Delete any previous value and set the value stored in *pMem to NULL. ** ** This routine calls the Mem.xDel destructor to dispose of values that ** require the destructor. But it preserves the Mem.zMalloc memory allocation. ** To free all resources, use sqlite3VdbeMemRelease(), which both calls this ** routine to invoke the destructor and deallocates Mem.zMalloc. ** ** Use this routine to reset the Mem prior to insert a new value. ** ** Use sqlite3VdbeMemRelease() to complete erase the Mem prior to abandoning it. */ SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){ if( VdbeMemDynamic(pMem) ){ vdbeMemClearExternAndSetNull(pMem); }else{ pMem->flags = MEM_Null; } } SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value *p){ sqlite3VdbeMemSetNull((Mem*)p); } /* ** Delete any previous value and set the value to be a BLOB of length ** n containing all zeros. */ #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Blob|MEM_Zero; pMem->n = 0; if( n<0 ) n = 0; pMem->u.nZero = n; pMem->enc = SQLITE_UTF8; pMem->z = 0; } #else SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ int nByte = n>0?n:1; if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){ return SQLITE_NOMEM_BKPT; } assert( pMem->z!=0 ); assert( sqlite3DbMallocSize(pMem->db, pMem->z)>=nByte ); memset(pMem->z, 0, nByte); pMem->n = n>0?n:0; pMem->flags = MEM_Blob; pMem->enc = SQLITE_UTF8; return SQLITE_OK; } #endif /* ** The pMem is known to contain content that needs to be destroyed prior ** to a value change. So invoke the destructor, then set the value to ** a 64-bit integer. */ static SQLITE_NOINLINE void vdbeReleaseAndSetInt64(Mem *pMem, i64 val){ sqlite3VdbeMemSetNull(pMem); pMem->u.i = val; pMem->flags = MEM_Int; } /* ** Delete any previous value and set the value stored in *pMem to val, ** manifest type INTEGER. */ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ if( VdbeMemDynamic(pMem) ){ vdbeReleaseAndSetInt64(pMem, val); }else{ pMem->u.i = val; pMem->flags = MEM_Int; } } /* A no-op destructor */ SQLITE_PRIVATE void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); } /* ** Set the value stored in *pMem should already be a NULL. ** Also store a pointer to go with it. */ SQLITE_PRIVATE void sqlite3VdbeMemSetPointer( Mem *pMem, void *pPtr, const char *zPType, void (*xDestructor)(void*) ){ assert( pMem->flags==MEM_Null ); vdbeMemClear(pMem); pMem->u.zPType = zPType ? zPType : ""; pMem->z = pPtr; pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term; pMem->eSubtype = 'p'; pMem->xDel = xDestructor ? xDestructor : sqlite3NoopDestructor; } #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Delete any previous value and set the value stored in *pMem to val, ** manifest type REAL. */ SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ sqlite3VdbeMemSetNull(pMem); if( !sqlite3IsNaN(val) ){ pMem->u.r = val; pMem->flags = MEM_Real; } } #endif #ifdef SQLITE_DEBUG /* ** Return true if the Mem holds a RowSet object. This routine is intended ** for use inside of assert() statements. */ SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem *pMem){ return (pMem->flags&(MEM_Blob|MEM_Dyn))==(MEM_Blob|MEM_Dyn) && pMem->xDel==sqlite3RowSetDelete; } #endif /* ** Delete any previous value and set the value of pMem to be an ** empty boolean index. ** ** Return SQLITE_OK on success and SQLITE_NOMEM if a memory allocation ** error occurs. */ SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem *pMem){ sqlite3 *db = pMem->db; RowSet *p; assert( db!=0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); sqlite3VdbeMemRelease(pMem); p = sqlite3RowSetInit(db); if( p==0 ) return SQLITE_NOMEM; pMem->z = (char*)p; pMem->flags = MEM_Blob|MEM_Dyn; pMem->xDel = sqlite3RowSetDelete; return SQLITE_OK; } /* ** Return true if the Mem object contains a TEXT or BLOB that is ** too large - whose size exceeds SQLITE_MAX_LENGTH. */ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){ assert( p->db!=0 ); if( p->flags & (MEM_Str|MEM_Blob) ){ int n = p->n; if( p->flags & MEM_Zero ){ n += p->u.nZero; } return n>p->db->aLimit[SQLITE_LIMIT_LENGTH]; } return 0; } #ifdef SQLITE_DEBUG /* ** This routine prepares a memory cell for modification by breaking ** its link to a shallow copy and by marking any current shallow ** copies of this cell as invalid. ** ** This is used for testing and debugging only - to help ensure that shallow ** copies (created by OP_SCopy) are not misused. */ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ int i; Mem *pX; for(i=1, pX=pVdbe->aMem+1; inMem; i++, pX++){ if( pX->pScopyFrom==pMem ){ u16 mFlags; if( pVdbe->db->flags & SQLITE_VdbeTrace ){ sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n", (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem)); } /* If pX is marked as a shallow copy of pMem, then try to verify that ** no significant changes have been made to pX since the OP_SCopy. ** A significant change would indicated a missed call to this ** function for pX. Minor changes, such as adding or removing a ** dual type, are allowed, as long as the underlying value is the ** same. */ mFlags = pMem->flags & pX->flags & pX->mScopyFlags; assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i ); /* pMem is the register that is changing. But also mark pX as ** undefined so that we can quickly detect the shallow-copy error */ pX->flags = MEM_Undefined; pX->pScopyFrom = 0; } } pMem->pScopyFrom = 0; } #endif /* SQLITE_DEBUG */ /* ** Make an shallow copy of pFrom into pTo. Prior contents of ** pTo are freed. The pFrom->z field is not duplicated. If ** pFrom->z is used, then pTo->z points to the same thing as pFrom->z ** and flags gets srcType (either MEM_Ephem or MEM_Static). */ static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){ vdbeMemClearExternAndSetNull(pTo); assert( !VdbeMemDynamic(pTo) ); sqlite3VdbeMemShallowCopy(pTo, pFrom, eType); } SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ assert( !sqlite3VdbeMemIsRowSet(pFrom) ); assert( pTo->db==pFrom->db ); if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; } memcpy(pTo, pFrom, MEMCELLSIZE); if( (pFrom->flags&MEM_Static)==0 ){ pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem); assert( srcType==MEM_Ephem || srcType==MEM_Static ); pTo->flags |= srcType; } } /* ** Make a full copy of pFrom into pTo. Prior contents of pTo are ** freed before the copy is made. */ SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; assert( !sqlite3VdbeMemIsRowSet(pFrom) ); if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; if( pTo->flags&(MEM_Str|MEM_Blob) ){ if( 0==(pFrom->flags&MEM_Static) ){ pTo->flags |= MEM_Ephem; rc = sqlite3VdbeMemMakeWriteable(pTo); } } return rc; } /* ** Transfer the contents of pFrom to pTo. Any existing value in pTo is ** freed. If pFrom contains ephemeral data, a copy is made. ** ** pFrom contains an SQL NULL when this routine returns. */ SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ assert( pFrom->db==0 || sqlite3_mutex_held(pFrom->db->mutex) ); assert( pTo->db==0 || sqlite3_mutex_held(pTo->db->mutex) ); assert( pFrom->db==0 || pTo->db==0 || pFrom->db==pTo->db ); sqlite3VdbeMemRelease(pTo); memcpy(pTo, pFrom, sizeof(Mem)); pFrom->flags = MEM_Null; pFrom->szMalloc = 0; } /* ** Change the value of a Mem to be a string or a BLOB. ** ** The memory management strategy depends on the value of the xDel ** parameter. If the value passed is SQLITE_TRANSIENT, then the ** string is copied into a (possibly existing) buffer managed by the ** Mem structure. Otherwise, any existing buffer is freed and the ** pointer copied. ** ** If the string is too large (if it exceeds the SQLITE_LIMIT_LENGTH ** size limit) then no memory allocation occurs. If the string can be ** stored without allocating memory, then it is. If a memory allocation ** is required to store the string, then value of pMem is unchanged. In ** either case, SQLITE_TOOBIG is returned. ** ** The "enc" parameter is the text encoding for the string, or zero ** to store a blob. ** ** If n is negative, then the string consists of all bytes up to but ** excluding the first zero character. The n parameter must be ** non-negative for blobs. */ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( Mem *pMem, /* Memory cell to set to string value */ const char *z, /* String pointer */ i64 n, /* Bytes in string, or negative */ u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ i64 nByte = n; /* New value for pMem->n */ int iLimit; /* Maximum allowed string or blob size */ u16 flags; /* New value for pMem->flags */ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( enc!=0 || n>=0 ); /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ if( !z ){ sqlite3VdbeMemSetNull(pMem); return SQLITE_OK; } if( pMem->db ){ iLimit = pMem->db->aLimit[SQLITE_LIMIT_LENGTH]; }else{ iLimit = SQLITE_MAX_LENGTH; } if( nByte<0 ){ assert( enc!=0 ); if( enc==SQLITE_UTF8 ){ nByte = strlen(z); }else{ for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} } flags= MEM_Str|MEM_Term; }else if( enc==0 ){ flags = MEM_Blob; enc = SQLITE_UTF8; }else{ flags = MEM_Str; } if( nByte>iLimit ){ if( xDel && xDel!=SQLITE_TRANSIENT ){ if( xDel==SQLITE_DYNAMIC ){ sqlite3DbFree(pMem->db, (void*)z); }else{ xDel((void*)z); } } sqlite3VdbeMemSetNull(pMem); return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); } /* The following block sets the new values of Mem.z and Mem.xDel. It ** also sets a flag in local variable "flags" to indicate the memory ** management (one of MEM_Dyn or MEM_Static). */ if( xDel==SQLITE_TRANSIENT ){ i64 nAlloc = nByte; if( flags&MEM_Term ){ nAlloc += (enc==SQLITE_UTF8?1:2); } testcase( nAlloc==0 ); testcase( nAlloc==31 ); testcase( nAlloc==32 ); if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){ return SQLITE_NOMEM_BKPT; } memcpy(pMem->z, z, nAlloc); }else{ sqlite3VdbeMemRelease(pMem); pMem->z = (char *)z; if( xDel==SQLITE_DYNAMIC ){ pMem->zMalloc = pMem->z; pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); }else{ pMem->xDel = xDel; flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); } } pMem->n = (int)(nByte & 0x7fffffff); pMem->flags = flags; pMem->enc = enc; #ifndef SQLITE_OMIT_UTF16 if( enc>SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){ return SQLITE_NOMEM_BKPT; } #endif return SQLITE_OK; } /* ** Move data out of a btree key or data field and into a Mem structure. ** The data is payload from the entry that pCur is currently pointing ** to. offset and amt determine what portion of the data or key to retrieve. ** The result is written into the pMem element. ** ** The pMem object must have been initialized. This routine will use ** pMem->zMalloc to hold the content from the btree, if possible. New ** pMem->zMalloc space will be allocated if necessary. The calling routine ** is responsible for making sure that the pMem object is eventually ** destroyed. ** ** If this routine fails for any reason (malloc returns NULL or unable ** to read from the disk) then the pMem is left in an inconsistent state. */ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( BtCursor *pCur, /* Cursor pointing at record to retrieve. */ u32 offset, /* Offset from the start of data to return bytes from. */ u32 amt, /* Number of bytes to return. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ int rc; pMem->flags = MEM_Null; if( sqlite3BtreeMaxRecordSize(pCur)z); if( rc==SQLITE_OK ){ pMem->z[amt] = 0; /* Overrun area used when reading malformed records */ pMem->flags = MEM_Blob; pMem->n = (int)amt; }else{ sqlite3VdbeMemRelease(pMem); } } return rc; } SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset( BtCursor *pCur, /* Cursor pointing at record to retrieve. */ u32 amt, /* Number of bytes to return. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ u32 available = 0; /* Number of bytes available on the local btree page */ int rc = SQLITE_OK; /* Return code */ assert( sqlite3BtreeCursorIsValid(pCur) ); assert( !VdbeMemDynamic(pMem) ); /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ assert( !sqlite3VdbeMemIsRowSet(pMem) ); pMem->z = (char *)sqlite3BtreePayloadFetch(pCur, &available); assert( pMem->z!=0 ); if( amt<=available ){ pMem->flags = MEM_Blob|MEM_Ephem; pMem->n = (int)amt; }else{ rc = sqlite3VdbeMemFromBtree(pCur, 0, amt, pMem); } return rc; } /* ** The pVal argument is known to be a value other than NULL. ** Convert it into a string with encoding enc and return a pointer ** to a zero-terminated version of that string. */ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert( pVal!=0 ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); assert( (pVal->flags & (MEM_Null))==0 ); if( pVal->flags & (MEM_Blob|MEM_Str) ){ if( ExpandBlob(pVal) ) return 0; pVal->flags |= MEM_Str; if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){ sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); } if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&SQLITE_PTR_TO_INT(pVal->z)) ){ assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 ); if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){ return 0; } } sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-31275-44060 */ }else{ sqlite3VdbeMemStringify(pVal, enc, 0); assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) ); } assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; }else{ return 0; } } /* This function is only available internally, it is not part of the ** external API. It works in a similar way to sqlite3_value_text(), ** except the data returned is in the encoding specified by the second ** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or ** SQLITE_UTF8. ** ** (2006-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED. ** If that is the case, then the result must be aligned on an even byte ** boundary. */ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ if( !pVal ) return 0; assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; } if( pVal->flags&MEM_Null ){ return 0; } return valueToText(pVal, enc); } /* Return true if sqlit3_value object pVal is a string or blob value ** that uses the destructor specified in the second argument. ** ** TODO: Maybe someday promote this interface into a published API so ** that third-party extensions can get access to it? */ SQLITE_PRIVATE int sqlite3ValueIsOfClass(const sqlite3_value *pVal, void(*xFree)(void*)){ if( ALWAYS(pVal!=0) && ALWAYS((pVal->flags & (MEM_Str|MEM_Blob))!=0) && (pVal->flags & MEM_Dyn)!=0 && pVal->xDel==xFree ){ return 1; }else{ return 0; } } /* ** Create a new sqlite3_value object. */ SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *db){ Mem *p = sqlite3DbMallocZero(db, sizeof(*p)); if( p ){ p->flags = MEM_Null; p->db = db; } return p; } /* ** Context object passed by sqlite3Stat4ProbeSetValue() through to ** valueNew(). See comments above valueNew() for details. */ struct ValueNewStat4Ctx { Parse *pParse; Index *pIdx; UnpackedRecord **ppRec; int iVal; }; /* ** Allocate and return a pointer to a new sqlite3_value object. If ** the second argument to this function is NULL, the object is allocated ** by calling sqlite3ValueNew(). ** ** Otherwise, if the second argument is non-zero, then this function is ** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not ** already been allocated, allocate the UnpackedRecord structure that ** that function will return to its caller here. Then return a pointer to ** an sqlite3_value within the UnpackedRecord.a[] array. */ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ #ifdef SQLITE_ENABLE_STAT4 if( p ){ UnpackedRecord *pRec = p->ppRec[0]; if( pRec==0 ){ Index *pIdx = p->pIdx; /* Index being probed */ int nByte; /* Bytes of space to allocate */ int i; /* Counter variable */ int nCol = pIdx->nColumn; /* Number of index columns including rowid */ nByte = sizeof(Mem) * nCol + ROUND8(sizeof(UnpackedRecord)); pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte); if( pRec ){ pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx); if( pRec->pKeyInfo ){ assert( pRec->pKeyInfo->nAllField==nCol ); assert( pRec->pKeyInfo->enc==ENC(db) ); pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord))); for(i=0; iaMem[i].flags = MEM_Null; pRec->aMem[i].db = db; } }else{ sqlite3DbFreeNN(db, pRec); pRec = 0; } } if( pRec==0 ) return 0; p->ppRec[0] = pRec; } pRec->nField = p->iVal+1; sqlite3VdbeMemSetNull(&pRec->aMem[p->iVal]); return &pRec->aMem[p->iVal]; } #else UNUSED_PARAMETER(p); #endif /* defined(SQLITE_ENABLE_STAT4) */ return sqlite3ValueNew(db); } /* ** The expression object indicated by the second argument is guaranteed ** to be a scalar SQL function. If ** ** * all function arguments are SQL literals, ** * one of the SQLITE_FUNC_CONSTANT or _SLOCHNG function flags is set, and ** * the SQLITE_FUNC_NEEDCOLL function flag is not set, ** ** then this routine attempts to invoke the SQL function. Assuming no ** error occurs, output parameter (*ppVal) is set to point to a value ** object containing the result before returning SQLITE_OK. ** ** Affinity aff is applied to the result of the function before returning. ** If the result is a text value, the sqlite3_value object uses encoding ** enc. ** ** If the conditions above are not met, this function returns SQLITE_OK ** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to ** NULL and an SQLite error code returned. */ #ifdef SQLITE_ENABLE_STAT4 static int valueFromFunction( sqlite3 *db, /* The database connection */ const Expr *p, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 aff, /* Affinity to use */ sqlite3_value **ppVal, /* Write the new value here */ struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */ ){ sqlite3_context ctx; /* Context object for function invocation */ sqlite3_value **apVal = 0; /* Function arguments */ int nVal = 0; /* Size of apVal[] array */ FuncDef *pFunc = 0; /* Function definition */ sqlite3_value *pVal = 0; /* New value */ int rc = SQLITE_OK; /* Return code */ ExprList *pList = 0; /* Function arguments */ int i; /* Iterator variable */ assert( pCtx!=0 ); assert( (p->flags & EP_TokenOnly)==0 ); assert( ExprUseXList(p) ); pList = p->x.pList; if( pList ) nVal = pList->nExpr; assert( !ExprHasProperty(p, EP_IntValue) ); pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0); #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION if( pFunc==0 ) return SQLITE_OK; #endif assert( pFunc ); if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 || (pFunc->funcFlags & (SQLITE_FUNC_NEEDCOLL|SQLITE_FUNC_RUNONLY))!=0 ){ return SQLITE_OK; } if( pList ){ apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal); if( apVal==0 ){ rc = SQLITE_NOMEM_BKPT; goto value_from_function_out; } for(i=0; ia[i].pExpr, enc, aff, &apVal[i]); if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out; } } pVal = valueNew(db, pCtx); if( pVal==0 ){ rc = SQLITE_NOMEM_BKPT; goto value_from_function_out; } memset(&ctx, 0, sizeof(ctx)); ctx.pOut = pVal; ctx.pFunc = pFunc; ctx.enc = ENC(db); pFunc->xSFunc(&ctx, nVal, apVal); if( ctx.isError ){ rc = ctx.isError; sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal)); }else{ sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8); assert( rc==SQLITE_OK ); rc = sqlite3VdbeChangeEncoding(pVal, enc); if( NEVER(rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal)) ){ rc = SQLITE_TOOBIG; pCtx->pParse->nErr++; } } value_from_function_out: if( rc!=SQLITE_OK ){ pVal = 0; pCtx->pParse->rc = rc; } if( apVal ){ for(i=0; iop)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft; if( op==TK_REGISTER ) op = pExpr->op2; /* Compressed expressions only appear when parsing the DEFAULT clause ** on a table column definition, and hence only when pCtx==0. This ** check ensures that an EP_TokenOnly expression is never passed down ** into valueFromFunction(). */ assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 ); if( op==TK_CAST ){ u8 aff; assert( !ExprHasProperty(pExpr, EP_IntValue) ); aff = sqlite3AffinityType(pExpr->u.zToken,0); rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); testcase( rc!=SQLITE_OK ); if( *ppVal ){ #ifdef SQLITE_ENABLE_STAT4 rc = ExpandBlob(*ppVal); #else /* zero-blobs only come from functions, not literal values. And ** functions are only processed under STAT4 */ assert( (ppVal[0][0].flags & MEM_Zero)==0 ); #endif sqlite3VdbeMemCast(*ppVal, aff, enc); sqlite3ValueApplyAffinity(*ppVal, affinity, enc); } return rc; } /* Handle negative integers in a single step. This is needed in the ** case when the value is -9223372036854775808. */ if( op==TK_UMINUS && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){ pExpr = pExpr->pLeft; op = pExpr->op; negInt = -1; zNeg = "-"; } if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ pVal = valueNew(db, pCtx); if( pVal==0 ) goto no_mem; if( ExprHasProperty(pExpr, EP_IntValue) ){ sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt); }else{ zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken); if( zVal==0 ) goto no_mem; sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); } if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){ sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } assert( (pVal->flags & MEM_IntReal)==0 ); if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ){ testcase( pVal->flags & MEM_Int ); testcase( pVal->flags & MEM_Real ); pVal->flags &= ~MEM_Str; } if( enc!=SQLITE_UTF8 ){ rc = sqlite3VdbeChangeEncoding(pVal, enc); } }else if( op==TK_UMINUS ) { /* This branch happens for multiple negative signs. Ex: -(-5) */ if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx) && pVal!=0 ){ sqlite3VdbeMemNumerify(pVal); if( pVal->flags & MEM_Real ){ pVal->u.r = -pVal->u.r; }else if( pVal->u.i==SMALLEST_INT64 ){ #ifndef SQLITE_OMIT_FLOATING_POINT pVal->u.r = -(double)SMALLEST_INT64; #else pVal->u.r = LARGEST_INT64; #endif MemSetTypeFlag(pVal, MEM_Real); }else{ pVal->u.i = -pVal->u.i; } sqlite3ValueApplyAffinity(pVal, affinity, enc); } }else if( op==TK_NULL ){ pVal = valueNew(db, pCtx); if( pVal==0 ) goto no_mem; sqlite3VdbeMemSetNull(pVal); } #ifndef SQLITE_OMIT_BLOB_LITERAL else if( op==TK_BLOB ){ int nVal; assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' ); assert( pExpr->u.zToken[1]=='\'' ); pVal = valueNew(db, pCtx); if( !pVal ) goto no_mem; zVal = &pExpr->u.zToken[2]; nVal = sqlite3Strlen30(zVal)-1; assert( zVal[nVal]=='\'' ); sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2, 0, SQLITE_DYNAMIC); } #endif #ifdef SQLITE_ENABLE_STAT4 else if( op==TK_FUNCTION && pCtx!=0 ){ rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx); } #endif else if( op==TK_TRUEFALSE ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); pVal = valueNew(db, pCtx); if( pVal ){ pVal->flags = MEM_Int; pVal->u.i = pExpr->u.zToken[4]==0; sqlite3ValueApplyAffinity(pVal, affinity, enc); } } *ppVal = pVal; return rc; no_mem: #ifdef SQLITE_ENABLE_STAT4 if( pCtx==0 || NEVER(pCtx->pParse->nErr==0) ) #endif sqlite3OomFault(db); sqlite3DbFree(db, zVal); assert( *ppVal==0 ); #ifdef SQLITE_ENABLE_STAT4 if( pCtx==0 ) sqlite3ValueFree(pVal); #else assert( pCtx==0 ); sqlite3ValueFree(pVal); #endif return SQLITE_NOMEM_BKPT; } /* ** Create a new sqlite3_value object, containing the value of pExpr. ** ** This only works for very simple expressions that consist of one constant ** token (i.e. "5", "5.1", "'a string'"). If the expression can ** be converted directly into a value, then the value is allocated and ** a pointer written to *ppVal. The caller is responsible for deallocating ** the value by passing it to sqlite3ValueFree() later on. If the expression ** cannot be converted to a value, then *ppVal is set to NULL. */ SQLITE_PRIVATE int sqlite3ValueFromExpr( sqlite3 *db, /* The database connection */ const Expr *pExpr, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 affinity, /* Affinity to use */ sqlite3_value **ppVal /* Write the new value here */ ){ return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0; } #ifdef SQLITE_ENABLE_STAT4 /* ** Attempt to extract a value from pExpr and use it to construct *ppVal. ** ** If pAlloc is not NULL, then an UnpackedRecord object is created for ** pAlloc if one does not exist and the new value is added to the ** UnpackedRecord object. ** ** A value is extracted in the following cases: ** ** * (pExpr==0). In this case the value is assumed to be an SQL NULL, ** ** * The expression is a bound variable, and this is a reprepare, or ** ** * The expression is a literal value. ** ** On success, *ppVal is made to point to the extracted value. The caller ** is responsible for ensuring that the value is eventually freed. */ static int stat4ValueFromExpr( Parse *pParse, /* Parse context */ Expr *pExpr, /* The expression to extract a value from */ u8 affinity, /* Affinity to use */ struct ValueNewStat4Ctx *pAlloc,/* How to allocate space. Or NULL */ sqlite3_value **ppVal /* OUT: New value object (or NULL) */ ){ int rc = SQLITE_OK; sqlite3_value *pVal = 0; sqlite3 *db = pParse->db; /* Skip over any TK_COLLATE nodes */ pExpr = sqlite3ExprSkipCollate(pExpr); assert( pExpr==0 || pExpr->op!=TK_REGISTER || pExpr->op2!=TK_VARIABLE ); if( !pExpr ){ pVal = valueNew(db, pAlloc); if( pVal ){ sqlite3VdbeMemSetNull((Mem*)pVal); } }else if( pExpr->op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *v; int iBindVar = pExpr->iColumn; sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); if( (v = pParse->pReprepare)!=0 ){ pVal = valueNew(db, pAlloc); if( pVal ){ rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); pVal->db = pParse->db; } } }else{ rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, pAlloc); } assert( pVal==0 || pVal->db==db ); *ppVal = pVal; return rc; } /* ** This function is used to allocate and populate UnpackedRecord ** structures intended to be compared against sample index keys stored ** in the sqlite_stat4 table. ** ** A single call to this function populates zero or more fields of the ** record starting with field iVal (fields are numbered from left to ** right starting with 0). A single field is populated if: ** ** * (pExpr==0). In this case the value is assumed to be an SQL NULL, ** ** * The expression is a bound variable, and this is a reprepare, or ** ** * The sqlite3ValueFromExpr() function is able to extract a value ** from the expression (i.e. the expression is a literal value). ** ** Or, if pExpr is a TK_VECTOR, one field is populated for each of the ** vector components that match either of the two latter criteria listed ** above. ** ** Before any value is appended to the record, the affinity of the ** corresponding column within index pIdx is applied to it. Before ** this function returns, output parameter *pnExtract is set to the ** number of values appended to the record. ** ** When this function is called, *ppRec must either point to an object ** allocated by an earlier call to this function, or must be NULL. If it ** is NULL and a value can be successfully extracted, a new UnpackedRecord ** is allocated (and *ppRec set to point to it) before returning. ** ** Unless an error is encountered, SQLITE_OK is returned. It is not an ** error if a value cannot be extracted from pExpr. If an error does ** occur, an SQLite error code is returned. */ SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue( Parse *pParse, /* Parse context */ Index *pIdx, /* Index being probed */ UnpackedRecord **ppRec, /* IN/OUT: Probe record */ Expr *pExpr, /* The expression to extract a value from */ int nElem, /* Maximum number of values to append */ int iVal, /* Array element to populate */ int *pnExtract /* OUT: Values appended to the record */ ){ int rc = SQLITE_OK; int nExtract = 0; if( pExpr==0 || pExpr->op!=TK_SELECT ){ int i; struct ValueNewStat4Ctx alloc; alloc.pParse = pParse; alloc.pIdx = pIdx; alloc.ppRec = ppRec; for(i=0; idb, pIdx, iVal+i); alloc.iVal = iVal+i; rc = stat4ValueFromExpr(pParse, pElem, aff, &alloc, &pVal); if( !pVal ) break; nExtract++; } } *pnExtract = nExtract; return rc; } /* ** Attempt to extract a value from expression pExpr using the methods ** as described for sqlite3Stat4ProbeSetValue() above. ** ** If successful, set *ppVal to point to a new value object and return ** SQLITE_OK. If no value can be extracted, but no other error occurs ** (e.g. OOM), return SQLITE_OK and set *ppVal to NULL. Or, if an error ** does occur, return an SQLite error code. The final value of *ppVal ** is undefined in this case. */ SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr( Parse *pParse, /* Parse context */ Expr *pExpr, /* The expression to extract a value from */ u8 affinity, /* Affinity to use */ sqlite3_value **ppVal /* OUT: New value object (or NULL) */ ){ return stat4ValueFromExpr(pParse, pExpr, affinity, 0, ppVal); } /* ** Extract the iCol-th column from the nRec-byte record in pRec. Write ** the column value into *ppVal. If *ppVal is initially NULL then a new ** sqlite3_value object is allocated. ** ** If *ppVal is initially NULL then the caller is responsible for ** ensuring that the value written into *ppVal is eventually freed. */ SQLITE_PRIVATE int sqlite3Stat4Column( sqlite3 *db, /* Database handle */ const void *pRec, /* Pointer to buffer containing record */ int nRec, /* Size of buffer pRec in bytes */ int iCol, /* Column to extract */ sqlite3_value **ppVal /* OUT: Extracted value */ ){ u32 t = 0; /* a column type code */ int nHdr; /* Size of the header in the record */ int iHdr; /* Next unread header byte */ int iField; /* Next unread data byte */ int szField = 0; /* Size of the current data field */ int i; /* Column index */ u8 *a = (u8*)pRec; /* Typecast byte array */ Mem *pMem = *ppVal; /* Write result into this Mem object */ assert( iCol>0 ); iHdr = getVarint32(a, nHdr); if( nHdr>nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT; iField = nHdr; for(i=0; i<=iCol; i++){ iHdr += getVarint32(&a[iHdr], t); testcase( iHdr==nHdr ); testcase( iHdr==nHdr+1 ); if( iHdr>nHdr ) return SQLITE_CORRUPT_BKPT; szField = sqlite3VdbeSerialTypeLen(t); iField += szField; } testcase( iField==nRec ); testcase( iField==nRec+1 ); if( iField>nRec ) return SQLITE_CORRUPT_BKPT; if( pMem==0 ){ pMem = *ppVal = sqlite3ValueNew(db); if( pMem==0 ) return SQLITE_NOMEM_BKPT; } sqlite3VdbeSerialGet(&a[iField-szField], t, pMem); pMem->enc = ENC(db); return SQLITE_OK; } /* ** Unless it is NULL, the argument must be an UnpackedRecord object returned ** by an earlier call to sqlite3Stat4ProbeSetValue(). This call deletes ** the object. */ SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){ if( pRec ){ int i; int nCol = pRec->pKeyInfo->nAllField; Mem *aMem = pRec->aMem; sqlite3 *db = aMem[0].db; for(i=0; ipKeyInfo); sqlite3DbFreeNN(db, pRec); } } #endif /* ifdef SQLITE_ENABLE_STAT4 */ /* ** Change the string value of an sqlite3_value object */ SQLITE_PRIVATE void sqlite3ValueSetStr( sqlite3_value *v, /* Value to be set */ int n, /* Length of string z */ const void *z, /* Text of the new string */ u8 enc, /* Encoding to use */ void (*xDel)(void*) /* Destructor for the string */ ){ if( v ) sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, xDel); } /* ** Free an sqlite3_value object */ SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){ if( !v ) return; sqlite3VdbeMemRelease((Mem *)v); sqlite3DbFreeNN(((Mem*)v)->db, v); } /* ** The sqlite3ValueBytes() routine returns the number of bytes in the ** sqlite3_value object assuming that it uses the encoding "enc". ** The valueBytes() routine is a helper function. */ static SQLITE_NOINLINE int valueBytes(sqlite3_value *pVal, u8 enc){ return valueToText(pVal, enc)!=0 ? pVal->n : 0; } SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ Mem *p = (Mem*)pVal; assert( (p->flags & MEM_Null)==0 || (p->flags & (MEM_Str|MEM_Blob))==0 ); if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){ return p->n; } if( (p->flags & MEM_Str)!=0 && enc!=SQLITE_UTF8 && pVal->enc!=SQLITE_UTF8 ){ return p->n; } if( (p->flags & MEM_Blob)!=0 ){ if( p->flags & MEM_Zero ){ return p->n + p->u.nZero; }else{ return p->n; } } if( p->flags & MEM_Null ) return 0; return valueBytes(pVal, enc); } /************** End of vdbemem.c *********************************************/ /************** Begin file vdbeaux.c *****************************************/ /* ** 2003 September 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ /* Forward references */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef); static void vdbeFreeOpArray(sqlite3 *, Op *, int); /* ** Create a new virtual database engine. */ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){ sqlite3 *db = pParse->db; Vdbe *p; p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) ); if( p==0 ) return 0; memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp)); p->db = db; if( db->pVdbe ){ db->pVdbe->ppVPrev = &p->pVNext; } p->pVNext = db->pVdbe; p->ppVPrev = &db->pVdbe; db->pVdbe = p; assert( p->eVdbeState==VDBE_INIT_STATE ); p->pParse = pParse; pParse->pVdbe = p; assert( pParse->aLabel==0 ); assert( pParse->nLabel==0 ); assert( p->nOpAlloc==0 ); assert( pParse->szOpAlloc==0 ); sqlite3VdbeAddOp2(p, OP_Init, 0, 1); return p; } /* ** Return the Parse object that owns a Vdbe object. */ SQLITE_PRIVATE Parse *sqlite3VdbeParser(Vdbe *p){ return p->pParse; } /* ** Change the error string stored in Vdbe.zErrMsg */ SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){ va_list ap; sqlite3DbFree(p->db, p->zErrMsg); va_start(ap, zFormat); p->zErrMsg = sqlite3VMPrintf(p->db, zFormat, ap); va_end(ap); } /* ** Remember the SQL string for a prepared statement. */ SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlags){ if( p==0 ) return; p->prepFlags = prepFlags; if( (prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){ p->expmask = 0; } assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); } #ifdef SQLITE_ENABLE_NORMALIZE /* ** Add a new element to the Vdbe->pDblStr list. */ SQLITE_PRIVATE void sqlite3VdbeAddDblquoteStr(sqlite3 *db, Vdbe *p, const char *z){ if( p ){ int n = sqlite3Strlen30(z); DblquoteStr *pStr = sqlite3DbMallocRawNN(db, sizeof(*pStr)+n+1-sizeof(pStr->z)); if( pStr ){ pStr->pNextStr = p->pDblStr; p->pDblStr = pStr; memcpy(pStr->z, z, n+1); } } } #endif #ifdef SQLITE_ENABLE_NORMALIZE /* ** zId of length nId is a double-quoted identifier. Check to see if ** that identifier is really used as a string literal. */ SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString( Vdbe *pVdbe, /* The prepared statement */ const char *zId /* The double-quoted identifier, already dequoted */ ){ DblquoteStr *pStr; assert( zId!=0 ); if( pVdbe->pDblStr==0 ) return 0; for(pStr=pVdbe->pDblStr; pStr; pStr=pStr->pNextStr){ if( strcmp(zId, pStr->z)==0 ) return 1; } return 0; } #endif /* ** Swap byte-code between two VDBE structures. ** ** This happens after pB was previously run and returned ** SQLITE_SCHEMA. The statement was then reprepared in pA. ** This routine transfers the new bytecode in pA over to pB ** so that pB can be run again. The old pB byte code is ** moved back to pA so that it will be cleaned up when pA is ** finalized. */ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ Vdbe tmp, *pTmp, **ppTmp; char *zTmp; assert( pA->db==pB->db ); tmp = *pA; *pA = *pB; *pB = tmp; pTmp = pA->pVNext; pA->pVNext = pB->pVNext; pB->pVNext = pTmp; ppTmp = pA->ppVPrev; pA->ppVPrev = pB->ppVPrev; pB->ppVPrev = ppTmp; zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; #ifdef SQLITE_ENABLE_NORMALIZE zTmp = pA->zNormSql; pA->zNormSql = pB->zNormSql; pB->zNormSql = zTmp; #endif pB->expmask = pA->expmask; pB->prepFlags = pA->prepFlags; memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter)); pB->aCounter[SQLITE_STMTSTATUS_REPREPARE]++; } /* ** Resize the Vdbe.aOp array so that it is at least nOp elements larger ** than its current size. nOp is guaranteed to be less than or equal ** to 1024/sizeof(Op). ** ** If an out-of-memory error occurs while resizing the array, return ** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain ** unchanged (this is so that any opcodes already allocated can be ** correctly deallocated along with the rest of the Vdbe). */ static int growOpArray(Vdbe *v, int nOp){ VdbeOp *pNew; Parse *p = v->pParse; /* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force ** more frequent reallocs and hence provide more opportunities for ** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used ** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array ** by the minimum* amount required until the size reaches 512. Normal ** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current ** size of the op array or add 1KB of space, whichever is smaller. */ #ifdef SQLITE_TEST_REALLOC_STRESS sqlite3_int64 nNew = (v->nOpAlloc>=512 ? 2*(sqlite3_int64)v->nOpAlloc : (sqlite3_int64)v->nOpAlloc+nOp); #else sqlite3_int64 nNew = (v->nOpAlloc ? 2*(sqlite3_int64)v->nOpAlloc : (sqlite3_int64)(1024/sizeof(Op))); UNUSED_PARAMETER(nOp); #endif /* Ensure that the size of a VDBE does not grow too large */ if( nNew > p->db->aLimit[SQLITE_LIMIT_VDBE_OP] ){ sqlite3OomFault(p->db); return SQLITE_NOMEM; } assert( nOp<=(int)(1024/sizeof(Op)) ); assert( nNew>=(v->nOpAlloc+nOp) ); pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); if( pNew ){ p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew); v->nOpAlloc = p->szOpAlloc/sizeof(Op); v->aOp = pNew; } return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT); } #ifdef SQLITE_DEBUG /* This routine is just a convenient place to set a breakpoint that will ** fire after each opcode is inserted and displayed using ** "PRAGMA vdbe_addoptrace=on". Parameters "pc" (program counter) and ** pOp are available to make the breakpoint conditional. ** ** Other useful labels for breakpoints include: ** test_trace_breakpoint(pc,pOp) ** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ static void test_addop_breakpoint(int pc, Op *pOp){ static u64 n = 0; (void)pc; (void)pOp; n++; if( n==LARGEST_UINT64 ) abort(); /* so that n is used, preventing a warning */ } #endif /* ** Slow paths for sqlite3VdbeAddOp3() and sqlite3VdbeAddOp4Int() for the ** unusual case when we need to increase the size of the Vdbe.aOp[] array ** before adding the new opcode. */ static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){ assert( p->nOpAlloc<=p->nOp ); if( growOpArray(p, 1) ) return 1; assert( p->nOpAlloc>p->nOp ); return sqlite3VdbeAddOp3(p, op, p1, p2, p3); } static SQLITE_NOINLINE int addOp4IntSlow( Vdbe *p, /* Add the opcode to this VM */ int op, /* The new opcode */ int p1, /* The P1 operand */ int p2, /* The P2 operand */ int p3, /* The P3 operand */ int p4 /* The P4 operand as an integer */ ){ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3); if( p->db->mallocFailed==0 ){ VdbeOp *pOp = &p->aOp[addr]; pOp->p4type = P4_INT32; pOp->p4.i = p4; } return addr; } /* ** Add a new instruction to the list of instructions current in the ** VDBE. Return the address of the new instruction. ** ** Parameters: ** ** p Pointer to the VDBE ** ** op The opcode for this instruction ** ** p1, p2, p3, p4 Operands */ SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe *p, int op){ return sqlite3VdbeAddOp3(p, op, 0, 0, 0); } SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){ return sqlite3VdbeAddOp3(p, op, p1, 0, 0); } SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){ return sqlite3VdbeAddOp3(p, op, p1, p2, 0); } SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ int i; VdbeOp *pOp; i = p->nOp; assert( p->eVdbeState==VDBE_INIT_STATE ); assert( op>=0 && op<0xff ); if( p->nOpAlloc<=i ){ return growOp3(p, op, p1, p2, p3); } assert( p->aOp!=0 ); p->nOp++; pOp = &p->aOp[i]; assert( pOp!=0 ); pOp->opcode = (u8)op; pOp->p5 = 0; pOp->p1 = p1; pOp->p2 = p2; pOp->p3 = p3; pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; /* Replicate this logic in sqlite3VdbeAddOp4Int() ** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS pOp->zComment = 0; #endif #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE) pOp->nExec = 0; pOp->nCycle = 0; #endif #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ sqlite3VdbePrintOp(0, i, &p->aOp[i]); test_addop_breakpoint(i, &p->aOp[i]); } #endif #ifdef SQLITE_VDBE_COVERAGE pOp->iSrcLine = 0; #endif /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ** Replicate in sqlite3VdbeAddOp4Int() */ return i; } SQLITE_PRIVATE int sqlite3VdbeAddOp4Int( Vdbe *p, /* Add the opcode to this VM */ int op, /* The new opcode */ int p1, /* The P1 operand */ int p2, /* The P2 operand */ int p3, /* The P3 operand */ int p4 /* The P4 operand as an integer */ ){ int i; VdbeOp *pOp; i = p->nOp; if( p->nOpAlloc<=i ){ return addOp4IntSlow(p, op, p1, p2, p3, p4); } p->nOp++; pOp = &p->aOp[i]; assert( pOp!=0 ); pOp->opcode = (u8)op; pOp->p5 = 0; pOp->p1 = p1; pOp->p2 = p2; pOp->p3 = p3; pOp->p4.i = p4; pOp->p4type = P4_INT32; /* Replicate this logic in sqlite3VdbeAddOp3() ** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS pOp->zComment = 0; #endif #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE) pOp->nExec = 0; pOp->nCycle = 0; #endif #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ sqlite3VdbePrintOp(0, i, &p->aOp[i]); test_addop_breakpoint(i, &p->aOp[i]); } #endif #ifdef SQLITE_VDBE_COVERAGE pOp->iSrcLine = 0; #endif /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ** Replicate in sqlite3VdbeAddOp3() */ return i; } /* Generate code for an unconditional jump to instruction iDest */ SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe *p, int iDest){ return sqlite3VdbeAddOp3(p, OP_Goto, 0, iDest, 0); } /* Generate code to cause the string zStr to be loaded into ** register iDest */ SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){ return sqlite3VdbeAddOp4(p, OP_String8, 0, iDest, 0, zStr, 0); } /* ** Generate code that initializes multiple registers to string or integer ** constants. The registers begin with iDest and increase consecutively. ** One register is initialized for each characgter in zTypes[]. For each ** "s" character in zTypes[], the register is a string if the argument is ** not NULL, or OP_Null if the value is a null pointer. For each "i" character ** in zTypes[], the register is initialized to an integer. ** ** If the input string does not end with "X" then an OP_ResultRow instruction ** is generated for the values inserted. */ SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){ va_list ap; int i; char c; va_start(ap, zTypes); for(i=0; (c = zTypes[i])!=0; i++){ if( c=='s' ){ const char *z = va_arg(ap, const char*); sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest+i, 0, z, 0); }else if( c=='i' ){ sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest+i); }else{ goto skip_op_resultrow; } } sqlite3VdbeAddOp2(p, OP_ResultRow, iDest, i); skip_op_resultrow: va_end(ap); } /* ** Add an opcode that includes the p4 value as a pointer. */ SQLITE_PRIVATE int sqlite3VdbeAddOp4( Vdbe *p, /* Add the opcode to this VM */ int op, /* The new opcode */ int p1, /* The P1 operand */ int p2, /* The P2 operand */ int p3, /* The P3 operand */ const char *zP4, /* The P4 operand */ int p4type /* P4 operand type */ ){ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3); sqlite3VdbeChangeP4(p, addr, zP4, p4type); return addr; } /* ** Add an OP_Function or OP_PureFunc opcode. ** ** The eCallCtx argument is information (typically taken from Expr.op2) ** that describes the calling context of the function. 0 means a general ** function call. NC_IsCheck means called by a check constraint, ** NC_IdxExpr means called as part of an index expression. NC_PartIdx ** means in the WHERE clause of a partial index. NC_GenCol means called ** while computing a generated column value. 0 is the usual case. */ SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall( Parse *pParse, /* Parsing context */ int p1, /* Constant argument mask */ int p2, /* First argument register */ int p3, /* Register into which results are written */ int nArg, /* Number of argument */ const FuncDef *pFunc, /* The function to be invoked */ int eCallCtx /* Calling context */ ){ Vdbe *v = pParse->pVdbe; int nByte; int addr; sqlite3_context *pCtx; assert( v ); nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*); pCtx = sqlite3DbMallocRawNN(pParse->db, nByte); if( pCtx==0 ){ assert( pParse->db->mallocFailed ); freeEphemeralFunction(pParse->db, (FuncDef*)pFunc); return 0; } pCtx->pOut = 0; pCtx->pFunc = (FuncDef*)pFunc; pCtx->pVdbe = 0; pCtx->isError = 0; pCtx->argc = nArg; pCtx->iOp = sqlite3VdbeCurrentAddr(v); addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function, p1, p2, p3, (char*)pCtx, P4_FUNCCTX); sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef); sqlite3MayAbort(pParse); return addr; } /* ** Add an opcode that includes the p4 value with a P4_INT64 or ** P4_REAL type. */ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8( Vdbe *p, /* Add the opcode to this VM */ int op, /* The new opcode */ int p1, /* The P1 operand */ int p2, /* The P2 operand */ int p3, /* The P3 operand */ const u8 *zP4, /* The P4 operand */ int p4type /* P4 operand type */ ){ char *p4copy = sqlite3DbMallocRawNN(sqlite3VdbeDb(p), 8); if( p4copy ) memcpy(p4copy, zP4, 8); return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type); } #ifndef SQLITE_OMIT_EXPLAIN /* ** Return the address of the current EXPLAIN QUERY PLAN baseline. ** 0 means "none". */ SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse *pParse){ VdbeOp *pOp; if( pParse->addrExplain==0 ) return 0; pOp = sqlite3VdbeGetOp(pParse->pVdbe, pParse->addrExplain); return pOp->p2; } /* ** Set a debugger breakpoint on the following routine in order to ** monitor the EXPLAIN QUERY PLAN code generation. */ #if defined(SQLITE_DEBUG) SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){ (void)z1; (void)z2; } #endif /* ** Add a new OP_Explain opcode. ** ** If the bPush flag is true, then make this opcode the parent for ** subsequent Explains until sqlite3VdbeExplainPop() is called. */ SQLITE_PRIVATE int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ int addr = 0; #if !defined(SQLITE_DEBUG) /* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined. ** But omit them (for performance) during production builds */ if( pParse->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) #endif { char *zMsg; Vdbe *v; va_list ap; int iThis; va_start(ap, zFmt); zMsg = sqlite3VMPrintf(pParse->db, zFmt, ap); va_end(ap); v = pParse->pVdbe; iThis = v->nOp; addr = sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0, zMsg, P4_DYNAMIC); sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetLastOp(v)->p4.z); if( bPush){ pParse->addrExplain = iThis; } sqlite3VdbeScanStatus(v, iThis, -1, -1, 0, 0); } return addr; } /* ** Pop the EXPLAIN QUERY PLAN stack one level. */ SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse *pParse){ sqlite3ExplainBreakpoint("POP", 0); pParse->addrExplain = sqlite3VdbeExplainParent(pParse); } #endif /* SQLITE_OMIT_EXPLAIN */ /* ** Add an OP_ParseSchema opcode. This routine is broken out from ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees ** as having been used. ** ** The zWhere string must have been obtained from sqlite3_malloc(). ** This routine will take ownership of the allocated memory. */ SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){ int j; sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); sqlite3VdbeChangeP5(p, p5); for(j=0; jdb->nDb; j++) sqlite3VdbeUsesBtree(p, j); sqlite3MayAbort(p->pParse); } /* Insert the end of a co-routine */ SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){ sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); /* Clear the temporary register cache, thereby ensuring that each ** co-routine has its own independent set of registers, because co-routines ** might expect their registers to be preserved across an OP_Yield, and ** that could cause problems if two or more co-routines are using the same ** temporary register. */ v->pParse->nTempReg = 0; v->pParse->nRangeReg = 0; } /* ** Create a new symbolic label for an instruction that has yet to be ** coded. The symbolic label is really just a negative number. The ** label can be used as the P2 value of an operation. Later, when ** the label is resolved to a specific address, the VDBE will scan ** through its operation list and change all values of P2 which match ** the label into the resolved address. ** ** The VDBE knows that a P2 value is a label because labels are ** always negative and P2 values are suppose to be non-negative. ** Hence, a negative P2 value is a label that has yet to be resolved. ** (Later:) This is only true for opcodes that have the OPFLG_JUMP ** property. ** ** Variable usage notes: ** ** Parse.aLabel[x] Stores the address that the x-th label resolves ** into. For testing (SQLITE_DEBUG), unresolved ** labels stores -1, but that is not required. ** Parse.nLabelAlloc Number of slots allocated to Parse.aLabel[] ** Parse.nLabel The *negative* of the number of labels that have ** been issued. The negative is stored because ** that gives a performance improvement over storing ** the equivalent positive value. */ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse *pParse){ return --pParse->nLabel; } /* ** Resolve label "x" to be the address of the next instruction to ** be inserted. The parameter "x" must have been obtained from ** a prior call to sqlite3VdbeMakeLabel(). */ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){ int nNewSize = 10 - p->nLabel; p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, nNewSize*sizeof(p->aLabel[0])); if( p->aLabel==0 ){ p->nLabelAlloc = 0; }else{ #ifdef SQLITE_DEBUG int i; for(i=p->nLabelAlloc; iaLabel[i] = -1; #endif if( nNewSize>=100 && (nNewSize/100)>(p->nLabelAlloc/100) ){ sqlite3ProgressCheck(p); } p->nLabelAlloc = nNewSize; p->aLabel[j] = v->nOp; } } SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ Parse *p = v->pParse; int j = ADDR(x); assert( v->eVdbeState==VDBE_INIT_STATE ); assert( j<-p->nLabel ); assert( j>=0 ); #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ printf("RESOLVE LABEL %d to %d\n", x, v->nOp); } #endif if( p->nLabelAlloc + p->nLabel < 0 ){ resizeResolveLabel(p,v,j); }else{ assert( p->aLabel[j]==(-1) ); /* Labels may only be resolved once */ p->aLabel[j] = v->nOp; } } /* ** Mark the VDBE as one that can only be run one time. */ SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){ sqlite3VdbeAddOp2(p, OP_Expire, 1, 1); } /* ** Mark the VDBE as one that can be run multiple times. */ SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){ int i; for(i=1; ALWAYS(inOp); i++){ if( ALWAYS(p->aOp[i].opcode==OP_Expire) ){ p->aOp[1].opcode = OP_Noop; break; } } } #ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */ /* ** The following type and function are used to iterate through all opcodes ** in a Vdbe main program and each of the sub-programs (triggers) it may ** invoke directly or indirectly. It should be used as follows: ** ** Op *pOp; ** VdbeOpIter sIter; ** ** memset(&sIter, 0, sizeof(sIter)); ** sIter.v = v; // v is of type Vdbe* ** while( (pOp = opIterNext(&sIter)) ){ ** // Do something with pOp ** } ** sqlite3DbFree(v->db, sIter.apSub); ** */ typedef struct VdbeOpIter VdbeOpIter; struct VdbeOpIter { Vdbe *v; /* Vdbe to iterate through the opcodes of */ SubProgram **apSub; /* Array of subprograms */ int nSub; /* Number of entries in apSub */ int iAddr; /* Address of next instruction to return */ int iSub; /* 0 = main program, 1 = first sub-program etc. */ }; static Op *opIterNext(VdbeOpIter *p){ Vdbe *v = p->v; Op *pRet = 0; Op *aOp; int nOp; if( p->iSub<=p->nSub ){ if( p->iSub==0 ){ aOp = v->aOp; nOp = v->nOp; }else{ aOp = p->apSub[p->iSub-1]->aOp; nOp = p->apSub[p->iSub-1]->nOp; } assert( p->iAddriAddr]; p->iAddr++; if( p->iAddr==nOp ){ p->iSub++; p->iAddr = 0; } if( pRet->p4type==P4_SUBPROGRAM ){ int nByte = (p->nSub+1)*sizeof(SubProgram*); int j; for(j=0; jnSub; j++){ if( p->apSub[j]==pRet->p4.pProgram ) break; } if( j==p->nSub ){ p->apSub = sqlite3DbReallocOrFree(v->db, p->apSub, nByte); if( !p->apSub ){ pRet = 0; }else{ p->apSub[p->nSub++] = pRet->p4.pProgram; } } } } return pRet; } /* ** Check if the program stored in the VM associated with pParse may ** throw an ABORT exception (causing the statement, but not entire transaction ** to be rolled back). This condition is true if the main program or any ** sub-programs contains any of the following: ** ** * OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort. ** * OP_HaltIfNull with P1=SQLITE_CONSTRAINT and P2=OE_Abort. ** * OP_Destroy ** * OP_VUpdate ** * OP_VCreate ** * OP_VRename ** * OP_FkCounter with P2==0 (immediate foreign key constraint) ** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine ** (for CREATE TABLE AS SELECT ...) ** ** Then check that the value of Parse.mayAbort is true if an ** ABORT may be thrown, or false otherwise. Return true if it does ** match, or false otherwise. This function is intended to be used as ** part of an assert statement in the compiler. Similar to: ** ** assert( sqlite3VdbeAssertMayAbort(pParse->pVdbe, pParse->mayAbort) ); */ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ int hasAbort = 0; int hasFkCounter = 0; int hasCreateTable = 0; int hasCreateIndex = 0; int hasInitCoroutine = 0; Op *pOp; VdbeOpIter sIter; if( v==0 ) return 0; memset(&sIter, 0, sizeof(sIter)); sIter.v = v; while( (pOp = opIterNext(&sIter))!=0 ){ int opcode = pOp->opcode; if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename || opcode==OP_VDestroy || opcode==OP_VCreate || opcode==OP_ParseSchema || opcode==OP_Function || opcode==OP_PureFunc || ((opcode==OP_Halt || opcode==OP_HaltIfNull) && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort)) ){ hasAbort = 1; break; } if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1; if( mayAbort ){ /* hasCreateIndex may also be set for some DELETE statements that use ** OP_Clear. So this routine may end up returning true in the case ** where a "DELETE FROM tbl" has a statement-journal but does not ** require one. This is not so bad - it is an inefficiency, not a bug. */ if( opcode==OP_CreateBtree && pOp->p3==BTREE_BLOBKEY ) hasCreateIndex = 1; if( opcode==OP_Clear ) hasCreateIndex = 1; } if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1; #ifndef SQLITE_OMIT_FOREIGN_KEY if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ hasFkCounter = 1; } #endif } sqlite3DbFree(v->db, sIter.apSub); /* Return true if hasAbort==mayAbort. Or if a malloc failure occurred. ** If malloc failed, then the while() loop above may not have iterated ** through all opcodes and hasAbort may be set incorrectly. Return ** true for this case to prevent the assert() in the callers frame ** from failing. */ return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter || (hasCreateTable && hasInitCoroutine) || hasCreateIndex ); } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ #ifdef SQLITE_DEBUG /* ** Increment the nWrite counter in the VDBE if the cursor is not an ** ephemeral cursor, or if the cursor argument is NULL. */ SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe *p, VdbeCursor *pC){ if( pC==0 || (pC->eCurType!=CURTYPE_SORTER && pC->eCurType!=CURTYPE_PSEUDO && !pC->isEphemeral) ){ p->nWrite++; } } #endif #ifdef SQLITE_DEBUG /* ** Assert if an Abort at this point in time might result in a corrupt ** database. */ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){ assert( p->nWrite==0 || p->usesStmtJournal ); } #endif /* ** This routine is called after all opcodes have been inserted. It loops ** through all the opcodes and fixes up some details. ** ** (1) For each jump instruction with a negative P2 value (a label) ** resolve the P2 value to an actual address. ** ** (2) Compute the maximum number of arguments used by any SQL function ** and store that value in *pMaxFuncArgs. ** ** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately ** indicate what the prepared statement actually does. ** ** (4) (discontinued) ** ** (5) Reclaim the memory allocated for storing labels. ** ** This routine will only function correctly if the mkopcodeh.tcl generator ** script numbers the opcodes correctly. Changes to this routine must be ** coordinated with changes to mkopcodeh.tcl. */ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ int nMaxArgs = *pMaxFuncArgs; Op *pOp; Parse *pParse = p->pParse; int *aLabel = pParse->aLabel; assert( pParse->db->mallocFailed==0 ); /* tag-20230419-1 */ p->readOnly = 1; p->bIsReader = 0; pOp = &p->aOp[p->nOp-1]; assert( p->aOp[0].opcode==OP_Init ); while( 1 /* Loop terminates when it reaches the OP_Init opcode */ ){ /* Only JUMP opcodes and the short list of special opcodes in the switch ** below need to be considered. The mkopcodeh.tcl generator script groups ** all these opcodes together near the front of the opcode list. Skip ** any opcode that does not need processing by virtual of the fact that ** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization. */ if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){ /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing ** cases from this switch! */ switch( pOp->opcode ){ case OP_Transaction: { if( pOp->p2!=0 ) p->readOnly = 0; /* no break */ deliberate_fall_through } case OP_AutoCommit: case OP_Savepoint: { p->bIsReader = 1; break; } #ifndef SQLITE_OMIT_WAL case OP_Checkpoint: #endif case OP_Vacuum: case OP_JournalMode: { p->readOnly = 0; p->bIsReader = 1; break; } case OP_Init: { assert( pOp->p2>=0 ); goto resolve_p2_values_loop_exit; } #ifndef SQLITE_OMIT_VIRTUALTABLE case OP_VUpdate: { if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; break; } case OP_VFilter: { int n; assert( (pOp - p->aOp) >= 3 ); assert( pOp[-1].opcode==OP_Integer ); n = pOp[-1].p1; if( n>nMaxArgs ) nMaxArgs = n; /* Fall through into the default case */ /* no break */ deliberate_fall_through } #endif default: { if( pOp->p2<0 ){ /* The mkopcodeh.tcl script has so arranged things that the only ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to ** have non-negative values for P2. */ assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ); assert( ADDR(pOp->p2)<-pParse->nLabel ); assert( aLabel!=0 ); /* True because of tag-20230419-1 */ pOp->p2 = aLabel[ADDR(pOp->p2)]; } break; } } /* The mkopcodeh.tcl script has so arranged things that the only ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to ** have non-negative values for P2. */ assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0); } assert( pOp>p->aOp ); pOp--; } resolve_p2_values_loop_exit: if( aLabel ){ sqlite3DbNNFreeNN(p->db, pParse->aLabel); pParse->aLabel = 0; } pParse->nLabel = 0; *pMaxFuncArgs = nMaxArgs; assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } #ifdef SQLITE_DEBUG /* ** Check to see if a subroutine contains a jump to a location outside of ** the subroutine. If a jump outside the subroutine is detected, add code ** that will cause the program to halt with an error message. ** ** The subroutine consists of opcodes between iFirst and iLast. Jumps to ** locations within the subroutine are acceptable. iRetReg is a register ** that contains the return address. Jumps to outside the range of iFirst ** through iLast are also acceptable as long as the jump destination is ** an OP_Return to iReturnAddr. ** ** A jump to an unresolved label means that the jump destination will be ** beyond the current address. That is normally a jump to an early ** termination and is consider acceptable. ** ** This routine only runs during debug builds. The purpose is (of course) ** to detect invalid escapes out of a subroutine. The OP_Halt opcode ** is generated rather than an assert() or other error, so that ".eqp full" ** will still work to show the original bytecode, to aid in debugging. */ SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn( Vdbe *v, /* The byte-code program under construction */ int iFirst, /* First opcode of the subroutine */ int iLast, /* Last opcode of the subroutine */ int iRetReg /* Subroutine return address register */ ){ VdbeOp *pOp; Parse *pParse; int i; sqlite3_str *pErr = 0; assert( v!=0 ); pParse = v->pParse; assert( pParse!=0 ); if( pParse->nErr ) return; assert( iLast>=iFirst ); assert( iLastnOp ); pOp = &v->aOp[iFirst]; for(i=iFirst; i<=iLast; i++, pOp++){ if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ){ int iDest = pOp->p2; /* Jump destination */ if( iDest==0 ) continue; if( pOp->opcode==OP_Gosub ) continue; if( pOp->p3==20230325 && pOp->opcode==OP_NotNull ){ /* This is a deliberately taken illegal branch. tag-20230325-2 */ continue; } if( iDest<0 ){ int j = ADDR(iDest); assert( j>=0 ); if( j>=-pParse->nLabel || pParse->aLabel[j]<0 ){ continue; } iDest = pParse->aLabel[j]; } if( iDestiLast ){ int j = iDest; for(; jnOp; j++){ VdbeOp *pX = &v->aOp[j]; if( pX->opcode==OP_Return ){ if( pX->p1==iRetReg ) break; continue; } if( pX->opcode==OP_Noop ) continue; if( pX->opcode==OP_Explain ) continue; if( pErr==0 ){ pErr = sqlite3_str_new(0); }else{ sqlite3_str_appendchar(pErr, 1, '\n'); } sqlite3_str_appendf(pErr, "Opcode at %d jumps to %d which is outside the " "subroutine at %d..%d", i, iDest, iFirst, iLast); break; } } } } if( pErr ){ char *zErr = sqlite3_str_finish(pErr); sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_INTERNAL, OE_Abort, 0, zErr, 0); sqlite3_free(zErr); sqlite3MayAbort(pParse); } } #endif /* SQLITE_DEBUG */ /* ** Return the address of the next instruction to be inserted. */ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){ assert( p->eVdbeState==VDBE_INIT_STATE ); return p->nOp; } /* ** Verify that at least N opcode slots are available in p without ** having to malloc for more space (except when compiled using ** SQLITE_TEST_REALLOC_STRESS). This interface is used during testing ** to verify that certain calls to sqlite3VdbeAddOpList() can never ** fail due to a OOM fault and hence that the return value from ** sqlite3VdbeAddOpList() will always be non-NULL. */ #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){ assert( p->nOp + N <= p->nOpAlloc ); } #endif /* ** Verify that the VM passed as the only argument does not contain ** an OP_ResultRow opcode. Fail an assert() if it does. This is used ** by code in pragma.c to ensure that the implementation of certain ** pragmas comports with the flags specified in the mkpragmatab.tcl ** script. */ #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p){ int i; for(i=0; inOp; i++){ assert( p->aOp[i].opcode!=OP_ResultRow ); } } #endif /* ** Generate code (a single OP_Abortable opcode) that will ** verify that the VDBE program can safely call Abort in the current ** context. */ #if defined(SQLITE_DEBUG) SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int onError){ if( onError==OE_Abort ) sqlite3VdbeAddOp0(p, OP_Abortable); } #endif /* ** This function returns a pointer to the array of opcodes associated with ** the Vdbe passed as the first argument. It is the callers responsibility ** to arrange for the returned array to be eventually freed using the ** vdbeFreeOpArray() function. ** ** Before returning, *pnOp is set to the number of entries in the returned ** array. Also, *pnMaxArg is set to the larger of its current value and ** the number of entries in the Vdbe.apArg[] array required to execute the ** returned program. */ SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){ VdbeOp *aOp = p->aOp; assert( aOp && !p->db->mallocFailed ); /* Check that sqlite3VdbeUsesBtree() was not called on this VM */ assert( DbMaskAllZero(p->btreeMask) ); resolveP2Values(p, pnMaxArg); *pnOp = p->nOp; p->aOp = 0; return aOp; } /* ** Add a whole list of operations to the operation stack. Return a ** pointer to the first operation inserted. ** ** Non-zero P2 arguments to jump instructions are automatically adjusted ** so that the jump target is relative to the first operation inserted. */ SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList( Vdbe *p, /* Add opcodes to the prepared statement */ int nOp, /* Number of opcodes to add */ VdbeOpList const *aOp, /* The opcodes to be added */ int iLineno /* Source-file line number of first opcode */ ){ int i; VdbeOp *pOut, *pFirst; assert( nOp>0 ); assert( p->eVdbeState==VDBE_INIT_STATE ); if( p->nOp + nOp > p->nOpAlloc && growOpArray(p, nOp) ){ return 0; } pFirst = pOut = &p->aOp[p->nOp]; for(i=0; iopcode = aOp->opcode; pOut->p1 = aOp->p1; pOut->p2 = aOp->p2; assert( aOp->p2>=0 ); if( (sqlite3OpcodeProperty[aOp->opcode] & OPFLG_JUMP)!=0 && aOp->p2>0 ){ pOut->p2 += p->nOp; } pOut->p3 = aOp->p3; pOut->p4type = P4_NOTUSED; pOut->p4.p = 0; pOut->p5 = 0; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS pOut->zComment = 0; #endif #ifdef SQLITE_VDBE_COVERAGE pOut->iSrcLine = iLineno+i; #else (void)iLineno; #endif #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ sqlite3VdbePrintOp(0, i+p->nOp, &p->aOp[i+p->nOp]); } #endif } p->nOp += nOp; return pFirst; } #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) /* ** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus(). */ SQLITE_PRIVATE void sqlite3VdbeScanStatus( Vdbe *p, /* VM to add scanstatus() to */ int addrExplain, /* Address of OP_Explain (or 0) */ int addrLoop, /* Address of loop counter */ int addrVisit, /* Address of rows visited counter */ LogEst nEst, /* Estimated number of output rows */ const char *zName /* Name of table or index being scanned */ ){ if( IS_STMT_SCANSTATUS(p->db) ){ sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); ScanStatus *aNew; aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); if( aNew ){ ScanStatus *pNew = &aNew[p->nScan++]; memset(pNew, 0, sizeof(ScanStatus)); pNew->addrExplain = addrExplain; pNew->addrLoop = addrLoop; pNew->addrVisit = addrVisit; pNew->nEst = nEst; pNew->zName = sqlite3DbStrDup(p->db, zName); p->aScan = aNew; } } } /* ** Add the range of instructions from addrStart to addrEnd (inclusive) to ** the set of those corresponding to the sqlite3_stmt_scanstatus() counters ** associated with the OP_Explain instruction at addrExplain. The ** sum of the sqlite3Hwtime() values for each of these instructions ** will be returned for SQLITE_SCANSTAT_NCYCLE requests. */ SQLITE_PRIVATE void sqlite3VdbeScanStatusRange( Vdbe *p, int addrExplain, int addrStart, int addrEnd ){ if( IS_STMT_SCANSTATUS(p->db) ){ ScanStatus *pScan = 0; int ii; for(ii=p->nScan-1; ii>=0; ii--){ pScan = &p->aScan[ii]; if( pScan->addrExplain==addrExplain ) break; pScan = 0; } if( pScan ){ if( addrEnd<0 ) addrEnd = sqlite3VdbeCurrentAddr(p)-1; for(ii=0; iiaAddrRange); ii+=2){ if( pScan->aAddrRange[ii]==0 ){ pScan->aAddrRange[ii] = addrStart; pScan->aAddrRange[ii+1] = addrEnd; break; } } } } } /* ** Set the addresses for the SQLITE_SCANSTAT_NLOOP and SQLITE_SCANSTAT_NROW ** counters for the query element associated with the OP_Explain at ** addrExplain. */ SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters( Vdbe *p, int addrExplain, int addrLoop, int addrVisit ){ if( IS_STMT_SCANSTATUS(p->db) ){ ScanStatus *pScan = 0; int ii; for(ii=p->nScan-1; ii>=0; ii--){ pScan = &p->aScan[ii]; if( pScan->addrExplain==addrExplain ) break; pScan = 0; } if( pScan ){ if( addrLoop>0 ) pScan->addrLoop = addrLoop; if( addrVisit>0 ) pScan->addrVisit = addrVisit; } } } #endif /* defined(SQLITE_ENABLE_STMT_SCANSTATUS) */ /* ** Change the value of the opcode, or P1, P2, P3, or P5 operands ** for a specific instruction. */ SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){ assert( addr>=0 ); sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode; } SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){ assert( addr>=0 ); sqlite3VdbeGetOp(p,addr)->p1 = val; } SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){ assert( addr>=0 || p->db->mallocFailed ); sqlite3VdbeGetOp(p,addr)->p2 = val; } SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){ assert( addr>=0 ); sqlite3VdbeGetOp(p,addr)->p3 = val; } SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){ assert( p->nOp>0 || p->db->mallocFailed ); if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5; } /* ** If the previous opcode is an OP_Column that delivers results ** into register iDest, then add the OPFLAG_TYPEOFARG flag to that ** opcode. */ SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){ VdbeOp *pOp = sqlite3VdbeGetLastOp(p); if( pOp->p3==iDest && pOp->opcode==OP_Column ){ pOp->p5 |= OPFLAG_TYPEOFARG; } } /* ** Change the P2 operand of instruction addr so that it points to ** the address of the next instruction to be coded. */ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){ sqlite3VdbeChangeP2(p, addr, p->nOp); } /* ** Change the P2 operand of the jump instruction at addr so that ** the jump lands on the next opcode. Or if the jump instruction was ** the previous opcode (and is thus a no-op) then simply back up ** the next instruction counter by one slot so that the jump is ** overwritten by the next inserted opcode. ** ** This routine is an optimization of sqlite3VdbeJumpHere() that ** strives to omit useless byte-code like this: ** ** 7 Once 0 8 0 ** 8 ... */ SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){ if( addr==p->nOp-1 ){ assert( p->aOp[addr].opcode==OP_Once || p->aOp[addr].opcode==OP_If || p->aOp[addr].opcode==OP_FkIfZero ); assert( p->aOp[addr].p4type==0 ); #ifdef SQLITE_VDBE_COVERAGE sqlite3VdbeGetLastOp(p)->iSrcLine = 0; /* Erase VdbeCoverage() macros */ #endif p->nOp--; }else{ sqlite3VdbeChangeP2(p, addr, p->nOp); } } /* ** If the input FuncDef structure is ephemeral, then free it. If ** the FuncDef is not ephemeral, then do nothing. */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ assert( db!=0 ); if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ sqlite3DbNNFreeNN(db, pDef); } } /* ** Delete a P4 value if necessary. */ static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); sqlite3DbNNFreeNN(db, p); } static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){ assert( db!=0 ); freeEphemeralFunction(db, p->pFunc); sqlite3DbNNFreeNN(db, p); } static void freeP4(sqlite3 *db, int p4type, void *p4){ assert( db ); switch( p4type ){ case P4_FUNCCTX: { freeP4FuncCtx(db, (sqlite3_context*)p4); break; } case P4_REAL: case P4_INT64: case P4_DYNAMIC: case P4_INTARRAY: { if( p4 ) sqlite3DbNNFreeNN(db, p4); break; } case P4_KEYINFO: { if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4); break; } #ifdef SQLITE_ENABLE_CURSOR_HINTS case P4_EXPR: { sqlite3ExprDelete(db, (Expr*)p4); break; } #endif case P4_FUNCDEF: { freeEphemeralFunction(db, (FuncDef*)p4); break; } case P4_MEM: { if( db->pnBytesFreed==0 ){ sqlite3ValueFree((sqlite3_value*)p4); }else{ freeP4Mem(db, (Mem*)p4); } break; } case P4_VTAB : { if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); break; } case P4_TABLEREF: { if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4); break; } } } /* ** Free the space allocated for aOp and any p4 values allocated for the ** opcodes contained within. If aOp is not NULL it is assumed to contain ** nOp entries. */ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ assert( nOp>=0 ); assert( db!=0 ); if( aOp ){ Op *pOp = &aOp[nOp-1]; while(1){ /* Exit via break */ if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS sqlite3DbFree(db, pOp->zComment); #endif if( pOp==aOp ) break; pOp--; } sqlite3DbNNFreeNN(db, aOp); } } /* ** Link the SubProgram object passed as the second argument into the linked ** list at Vdbe.pSubProgram. This list is used to delete all sub-program ** objects when the VM is no longer required. */ SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ p->pNext = pVdbe->pProgram; pVdbe->pProgram = p; } /* ** Return true if the given Vdbe has any SubPrograms. */ SQLITE_PRIVATE int sqlite3VdbeHasSubProgram(Vdbe *pVdbe){ return pVdbe->pProgram!=0; } /* ** Change the opcode at addr into OP_Noop */ SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ VdbeOp *pOp; if( p->db->mallocFailed ) return 0; assert( addr>=0 && addrnOp ); pOp = &p->aOp[addr]; freeP4(p->db, pOp->p4type, pOp->p4.p); pOp->p4type = P4_NOTUSED; pOp->p4.z = 0; pOp->opcode = OP_Noop; return 1; } /* ** If the last opcode is "op" and it is not a jump destination, ** then remove it. Return true if and only if an opcode was removed. */ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){ return sqlite3VdbeChangeToNoop(p, p->nOp-1); }else{ return 0; } } #ifdef SQLITE_DEBUG /* ** Generate an OP_ReleaseReg opcode to indicate that a range of ** registers, except any identified by mask, are no longer in use. */ SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters( Parse *pParse, /* Parsing context */ int iFirst, /* Index of first register to be released */ int N, /* Number of registers to release */ u32 mask, /* Mask of registers to NOT release */ int bUndefine /* If true, mark registers as undefined */ ){ if( N==0 || OptimizationDisabled(pParse->db, SQLITE_ReleaseReg) ) return; assert( pParse->pVdbe ); assert( iFirst>=1 ); assert( iFirst+N-1<=pParse->nMem ); if( N<=31 && mask!=0 ){ while( N>0 && (mask&1)!=0 ){ mask >>= 1; iFirst++; N--; } while( N>0 && N<=32 && (mask & MASKBIT32(N-1))!=0 ){ mask &= ~MASKBIT32(N-1); N--; } } if( N>0 ){ sqlite3VdbeAddOp3(pParse->pVdbe, OP_ReleaseReg, iFirst, N, *(int*)&mask); if( bUndefine ) sqlite3VdbeChangeP5(pParse->pVdbe, 1); } } #endif /* SQLITE_DEBUG */ /* ** Change the value of the P4 operand for a specific instruction. ** This routine is useful when a large program is loaded from a ** static array using sqlite3VdbeAddOpList but we want to make a ** few minor changes to the program. ** ** If n>=0 then the P4 operand is dynamic, meaning that a copy of ** the string is made into memory obtained from sqlite3_malloc(). ** A value of n==0 means copy bytes of zP4 up to and including the ** first null byte. If n>0 then copy n+1 bytes of zP4. ** ** Other values of n (P4_STATIC, P4_COLLSEQ etc.) indicate that zP4 points ** to a string or structure that is guaranteed to exist for the lifetime of ** the Vdbe. In these cases we can just copy the pointer. ** ** If addr<0 then change P4 on the most recently inserted instruction. */ static void SQLITE_NOINLINE vdbeChangeP4Full( Vdbe *p, Op *pOp, const char *zP4, int n ){ if( pOp->p4type ){ assert( pOp->p4type > P4_FREE_IF_LE ); pOp->p4type = 0; pOp->p4.p = 0; } if( n<0 ){ sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n); }else{ if( n==0 ) n = sqlite3Strlen30(zP4); pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); pOp->p4type = P4_DYNAMIC; } } SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ Op *pOp; sqlite3 *db; assert( p!=0 ); db = p->db; assert( p->eVdbeState==VDBE_INIT_STATE ); assert( p->aOp!=0 || db->mallocFailed ); if( db->mallocFailed ){ if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4); return; } assert( p->nOp>0 ); assert( addrnOp ); if( addr<0 ){ addr = p->nOp - 1; } pOp = &p->aOp[addr]; if( n>=0 || pOp->p4type ){ vdbeChangeP4Full(p, pOp, zP4, n); return; } if( n==P4_INT32 ){ /* Note: this cast is safe, because the origin data point was an int ** that was cast to a (const char *). */ pOp->p4.i = SQLITE_PTR_TO_INT(zP4); pOp->p4type = P4_INT32; }else if( zP4!=0 ){ assert( n<0 ); pOp->p4.p = (void*)zP4; pOp->p4type = (signed char)n; if( n==P4_VTAB ) sqlite3VtabLock((VTable*)zP4); } } /* ** Change the P4 operand of the most recently coded instruction ** to the value defined by the arguments. This is a high-speed ** version of sqlite3VdbeChangeP4(). ** ** The P4 operand must not have been previously defined. And the new ** P4 must not be P4_INT32. Use sqlite3VdbeChangeP4() in either of ** those cases. */ SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){ VdbeOp *pOp; assert( n!=P4_INT32 && n!=P4_VTAB ); assert( n<=0 ); if( p->db->mallocFailed ){ freeP4(p->db, n, pP4); }else{ assert( pP4!=0 || n==P4_DYNAMIC ); assert( p->nOp>0 ); pOp = &p->aOp[p->nOp-1]; assert( pOp->p4type==P4_NOTUSED ); pOp->p4type = n; pOp->p4.p = pP4; } } /* ** Set the P4 on the most recently added opcode to the KeyInfo for the ** index given. */ SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){ Vdbe *v = pParse->pVdbe; KeyInfo *pKeyInfo; assert( v!=0 ); assert( pIdx!=0 ); pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pIdx); if( pKeyInfo ) sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS /* ** Change the comment on the most recently coded instruction. Or ** insert a No-op and add the comment to that new instruction. This ** makes the code easier to read during debugging. None of this happens ** in a production build. */ static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){ assert( p->nOp>0 || p->aOp==0 ); assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->pParse->nErr>0 ); if( p->nOp ){ assert( p->aOp ); sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment); p->aOp[p->nOp-1].zComment = sqlite3VMPrintf(p->db, zFormat, ap); } } SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ va_list ap; if( p ){ va_start(ap, zFormat); vdbeVComment(p, zFormat, ap); va_end(ap); } } SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){ va_list ap; if( p ){ sqlite3VdbeAddOp0(p, OP_Noop); va_start(ap, zFormat); vdbeVComment(p, zFormat, ap); va_end(ap); } } #endif /* NDEBUG */ #ifdef SQLITE_VDBE_COVERAGE /* ** Set the value if the iSrcLine field for the previously coded instruction. */ SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){ sqlite3VdbeGetLastOp(v)->iSrcLine = iLine; } #endif /* SQLITE_VDBE_COVERAGE */ /* ** Return the opcode for a given address. The address must be non-negative. ** See sqlite3VdbeGetLastOp() to get the most recently added opcode. ** ** If a memory allocation error has occurred prior to the calling of this ** routine, then a pointer to a dummy VdbeOp will be returned. That opcode ** is readable but not writable, though it is cast to a writable value. ** The return of a dummy opcode allows the call to continue functioning ** after an OOM fault without having to check to see if the return from ** this routine is a valid pointer. But because the dummy.opcode is 0, ** dummy will never be written to. This is verified by code inspection and ** by running with Valgrind. */ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ /* C89 specifies that the constant "dummy" will be initialized to all ** zeros, which is correct. MSVC generates a warning, nevertheless. */ static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */ assert( p->eVdbeState==VDBE_INIT_STATE ); assert( (addr>=0 && addrnOp) || p->db->mallocFailed ); if( p->db->mallocFailed ){ return (VdbeOp*)&dummy; }else{ return &p->aOp[addr]; } } /* Return the most recently added opcode */ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetLastOp(Vdbe *p){ return sqlite3VdbeGetOp(p, p->nOp - 1); } #if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) /* ** Return an integer value for one of the parameters to the opcode pOp ** determined by character c. */ static int translateP(char c, const Op *pOp){ if( c=='1' ) return pOp->p1; if( c=='2' ) return pOp->p2; if( c=='3' ) return pOp->p3; if( c=='4' ) return pOp->p4.i; return pOp->p5; } /* ** Compute a string for the "comment" field of a VDBE opcode listing. ** ** The Synopsis: field in comments in the vdbe.c source file gets converted ** to an extra string that is appended to the sqlite3OpcodeName(). In the ** absence of other comments, this synopsis becomes the comment on the opcode. ** Some translation occurs: ** ** "PX" -> "r[X]" ** "PX@PY" -> "r[X..X+Y-1]" or "r[x]" if y is 0 or 1 ** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0 ** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x */ SQLITE_PRIVATE char *sqlite3VdbeDisplayComment( sqlite3 *db, /* Optional - Oom error reporting only */ const Op *pOp, /* The opcode to be commented */ const char *zP4 /* Previously obtained value for P4 */ ){ const char *zOpName; const char *zSynopsis; int nOpName; int ii; char zAlt[50]; StrAccum x; sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH); zOpName = sqlite3OpcodeName(pOp->opcode); nOpName = sqlite3Strlen30(zOpName); if( zOpName[nOpName+1] ){ int seenCom = 0; char c; zSynopsis = zOpName + nOpName + 1; if( strncmp(zSynopsis,"IF ",3)==0 ){ sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); zSynopsis = zAlt; } for(ii=0; (c = zSynopsis[ii])!=0; ii++){ if( c=='P' ){ c = zSynopsis[++ii]; if( c=='4' ){ sqlite3_str_appendall(&x, zP4); }else if( c=='X' ){ if( pOp->zComment && pOp->zComment[0] ){ sqlite3_str_appendall(&x, pOp->zComment); seenCom = 1; break; } }else{ int v1 = translateP(c, pOp); int v2; if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){ ii += 3; v2 = translateP(zSynopsis[ii], pOp); if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){ ii += 2; v2++; } if( v2<2 ){ sqlite3_str_appendf(&x, "%d", v1); }else{ sqlite3_str_appendf(&x, "%d..%d", v1, v1+v2-1); } }else if( strncmp(zSynopsis+ii+1, "@NP", 3)==0 ){ sqlite3_context *pCtx = pOp->p4.pCtx; if( pOp->p4type!=P4_FUNCCTX || pCtx->argc==1 ){ sqlite3_str_appendf(&x, "%d", v1); }else if( pCtx->argc>1 ){ sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1); }else if( x.accError==0 ){ assert( x.nChar>2 ); x.nChar -= 2; ii++; } ii += 3; }else{ sqlite3_str_appendf(&x, "%d", v1); if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){ ii += 4; } } } }else{ sqlite3_str_appendchar(&x, 1, c); } } if( !seenCom && pOp->zComment ){ sqlite3_str_appendf(&x, "; %s", pOp->zComment); } }else if( pOp->zComment ){ sqlite3_str_appendall(&x, pOp->zComment); } if( (x.accError & SQLITE_NOMEM)!=0 && db!=0 ){ sqlite3OomFault(db); } return sqlite3StrAccumFinish(&x); } #endif /* SQLITE_ENABLE_EXPLAIN_COMMENTS */ #if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) /* ** Translate the P4.pExpr value for an OP_CursorHint opcode into text ** that can be displayed in the P4 column of EXPLAIN output. */ static void displayP4Expr(StrAccum *p, Expr *pExpr){ const char *zOp = 0; switch( pExpr->op ){ case TK_STRING: assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3_str_appendf(p, "%Q", pExpr->u.zToken); break; case TK_INTEGER: sqlite3_str_appendf(p, "%d", pExpr->u.iValue); break; case TK_NULL: sqlite3_str_appendf(p, "NULL"); break; case TK_REGISTER: { sqlite3_str_appendf(p, "r[%d]", pExpr->iTable); break; } case TK_COLUMN: { if( pExpr->iColumn<0 ){ sqlite3_str_appendf(p, "rowid"); }else{ sqlite3_str_appendf(p, "c%d", (int)pExpr->iColumn); } break; } case TK_LT: zOp = "LT"; break; case TK_LE: zOp = "LE"; break; case TK_GT: zOp = "GT"; break; case TK_GE: zOp = "GE"; break; case TK_NE: zOp = "NE"; break; case TK_EQ: zOp = "EQ"; break; case TK_IS: zOp = "IS"; break; case TK_ISNOT: zOp = "ISNOT"; break; case TK_AND: zOp = "AND"; break; case TK_OR: zOp = "OR"; break; case TK_PLUS: zOp = "ADD"; break; case TK_STAR: zOp = "MUL"; break; case TK_MINUS: zOp = "SUB"; break; case TK_REM: zOp = "REM"; break; case TK_BITAND: zOp = "BITAND"; break; case TK_BITOR: zOp = "BITOR"; break; case TK_SLASH: zOp = "DIV"; break; case TK_LSHIFT: zOp = "LSHIFT"; break; case TK_RSHIFT: zOp = "RSHIFT"; break; case TK_CONCAT: zOp = "CONCAT"; break; case TK_UMINUS: zOp = "MINUS"; break; case TK_UPLUS: zOp = "PLUS"; break; case TK_BITNOT: zOp = "BITNOT"; break; case TK_NOT: zOp = "NOT"; break; case TK_ISNULL: zOp = "ISNULL"; break; case TK_NOTNULL: zOp = "NOTNULL"; break; default: sqlite3_str_appendf(p, "%s", "expr"); break; } if( zOp ){ sqlite3_str_appendf(p, "%s(", zOp); displayP4Expr(p, pExpr->pLeft); if( pExpr->pRight ){ sqlite3_str_append(p, ",", 1); displayP4Expr(p, pExpr->pRight); } sqlite3_str_append(p, ")", 1); } } #endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */ #if VDBE_DISPLAY_P4 /* ** Compute a string that describes the P4 parameter for an opcode. ** Use zTemp for any required temporary buffer space. */ SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){ char *zP4 = 0; StrAccum x; sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH); switch( pOp->p4type ){ case P4_KEYINFO: { int j; KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; assert( pKeyInfo->aSortFlags!=0 ); sqlite3_str_appendf(&x, "k(%d", pKeyInfo->nKeyField); for(j=0; jnKeyField; j++){ CollSeq *pColl = pKeyInfo->aColl[j]; const char *zColl = pColl ? pColl->zName : ""; if( strcmp(zColl, "BINARY")==0 ) zColl = "B"; sqlite3_str_appendf(&x, ",%s%s%s", (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_DESC) ? "-" : "", (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_BIGNULL)? "N." : "", zColl); } sqlite3_str_append(&x, ")", 1); break; } #ifdef SQLITE_ENABLE_CURSOR_HINTS case P4_EXPR: { displayP4Expr(&x, pOp->p4.pExpr); break; } #endif case P4_COLLSEQ: { static const char *const encnames[] = {"?", "8", "16LE", "16BE"}; CollSeq *pColl = pOp->p4.pColl; assert( pColl->enc<4 ); sqlite3_str_appendf(&x, "%.18s-%s", pColl->zName, encnames[pColl->enc]); break; } case P4_FUNCDEF: { FuncDef *pDef = pOp->p4.pFunc; sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } case P4_FUNCCTX: { FuncDef *pDef = pOp->p4.pCtx->pFunc; sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } case P4_INT64: { sqlite3_str_appendf(&x, "%lld", *pOp->p4.pI64); break; } case P4_INT32: { sqlite3_str_appendf(&x, "%d", pOp->p4.i); break; } case P4_REAL: { sqlite3_str_appendf(&x, "%.16g", *pOp->p4.pReal); break; } case P4_MEM: { Mem *pMem = pOp->p4.pMem; if( pMem->flags & MEM_Str ){ zP4 = pMem->z; }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ sqlite3_str_appendf(&x, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ sqlite3_str_appendf(&x, "%.16g", pMem->u.r); }else if( pMem->flags & MEM_Null ){ zP4 = "NULL"; }else{ assert( pMem->flags & MEM_Blob ); zP4 = "(blob)"; } break; } #ifndef SQLITE_OMIT_VIRTUALTABLE case P4_VTAB: { sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; sqlite3_str_appendf(&x, "vtab:%p", pVtab); break; } #endif case P4_INTARRAY: { u32 i; u32 *ai = pOp->p4.ai; u32 n = ai[0]; /* The first element of an INTARRAY is always the ** count of the number of elements to follow */ for(i=1; i<=n; i++){ sqlite3_str_appendf(&x, "%c%u", (i==1 ? '[' : ','), ai[i]); } sqlite3_str_append(&x, "]", 1); break; } case P4_SUBPROGRAM: { zP4 = "program"; break; } case P4_TABLE: { zP4 = pOp->p4.pTab->zName; break; } default: { zP4 = pOp->p4.z; } } if( zP4 ) sqlite3_str_appendall(&x, zP4); if( (x.accError & SQLITE_NOMEM)!=0 ){ sqlite3OomFault(db); } return sqlite3StrAccumFinish(&x); } #endif /* VDBE_DISPLAY_P4 */ /* ** Declare to the Vdbe that the BTree object at db->aDb[i] is used. ** ** The prepared statements need to know in advance the complete set of ** attached databases that will be use. A mask of these databases ** is maintained in p->btreeMask. The p->lockMask value is the subset of ** p->btreeMask of databases that will require a lock. */ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){ assert( i>=0 && idb->nDb && i<(int)sizeof(yDbMask)*8 ); assert( i<(int)sizeof(p->btreeMask)*8 ); DbMaskSet(p->btreeMask, i); if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){ DbMaskSet(p->lockMask, i); } } #if !defined(SQLITE_OMIT_SHARED_CACHE) /* ** If SQLite is compiled to support shared-cache mode and to be threadsafe, ** this routine obtains the mutex associated with each BtShared structure ** that may be accessed by the VM passed as an argument. In doing so it also ** sets the BtShared.db member of each of the BtShared structures, ensuring ** that the correct busy-handler callback is invoked if required. ** ** If SQLite is not threadsafe but does support shared-cache mode, then ** sqlite3BtreeEnter() is invoked to set the BtShared.db variables ** of all of BtShared structures accessible via the database handle ** associated with the VM. ** ** If SQLite is not threadsafe and does not support shared-cache mode, this ** function is a no-op. ** ** The p->btreeMask field is a bitmask of all btrees that the prepared ** statement p will ever use. Let N be the number of bits in p->btreeMask ** corresponding to btrees that use shared cache. Then the runtime of ** this routine is N*N. But as N is rarely more than 1, this should not ** be a problem. */ SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe *p){ int i; sqlite3 *db; Db *aDb; int nDb; if( DbMaskAllZero(p->lockMask) ) return; /* The common case */ db = p->db; aDb = db->aDb; nDb = db->nDb; for(i=0; ilockMask,i) && ALWAYS(aDb[i].pBt!=0) ){ sqlite3BtreeEnter(aDb[i].pBt); } } } #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 /* ** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter(). */ static SQLITE_NOINLINE void vdbeLeave(Vdbe *p){ int i; sqlite3 *db; Db *aDb; int nDb; db = p->db; aDb = db->aDb; nDb = db->nDb; for(i=0; ilockMask,i) && ALWAYS(aDb[i].pBt!=0) ){ sqlite3BtreeLeave(aDb[i].pBt); } } } SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){ if( DbMaskAllZero(p->lockMask) ) return; /* The common case */ vdbeLeave(p); } #endif #if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) /* ** Print a single opcode. This routine is used for debugging only. */ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){ char *zP4; char *zCom; sqlite3 dummyDb; static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n"; if( pOut==0 ) pOut = stdout; sqlite3BeginBenignMalloc(); dummyDb.mallocFailed = 1; zP4 = sqlite3VdbeDisplayP4(&dummyDb, pOp); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS zCom = sqlite3VdbeDisplayComment(0, pOp, zP4); #else zCom = 0; #endif /* NB: The sqlite3OpcodeName() function is implemented by code created ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the ** information from the vdbe.c source text */ fprintf(pOut, zFormat1, pc, sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4 ? zP4 : "", pOp->p5, zCom ? zCom : "" ); fflush(pOut); sqlite3_free(zP4); sqlite3_free(zCom); sqlite3EndBenignMalloc(); } #endif /* ** Initialize an array of N Mem element. ** ** This is a high-runner, so only those fields that really do need to ** be initialized are set. The Mem structure is organized so that ** the fields that get initialized are nearby and hopefully on the same ** cache line. ** ** Mem.flags = flags ** Mem.db = db ** Mem.szMalloc = 0 ** ** All other fields of Mem can safely remain uninitialized for now. They ** will be initialized before use. */ static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){ if( N>0 ){ do{ p->flags = flags; p->db = db; p->szMalloc = 0; #ifdef SQLITE_DEBUG p->pScopyFrom = 0; #endif p++; }while( (--N)>0 ); } } /* ** Release auxiliary memory held in an array of N Mem elements. ** ** After this routine returns, all Mem elements in the array will still ** be valid. Those Mem elements that were not holding auxiliary resources ** will be unchanged. Mem elements which had something freed will be ** set to MEM_Undefined. */ static void releaseMemArray(Mem *p, int N){ if( p && N ){ Mem *pEnd = &p[N]; sqlite3 *db = p->db; if( db->pnBytesFreed ){ do{ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); }while( (++p)flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); if( p->flags&(MEM_Agg|MEM_Dyn) ){ testcase( (p->flags & MEM_Dyn)!=0 && p->xDel==sqlite3VdbeFrameMemDel ); sqlite3VdbeMemRelease(p); p->flags = MEM_Undefined; }else if( p->szMalloc ){ sqlite3DbNNFreeNN(db, p->zMalloc); p->szMalloc = 0; p->flags = MEM_Undefined; } #ifdef SQLITE_DEBUG else{ p->flags = MEM_Undefined; } #endif }while( (++p)iFrameMagic!=SQLITE_FRAME_MAGIC ) return 0; return 1; } #endif /* ** This is a destructor on a Mem object (which is really an sqlite3_value) ** that deletes the Frame object that is attached to it as a blob. ** ** This routine does not delete the Frame right away. It merely adds the ** frame to a list of frames to be deleted when the Vdbe halts. */ SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void *pArg){ VdbeFrame *pFrame = (VdbeFrame*)pArg; assert( sqlite3VdbeFrameIsValid(pFrame) ); pFrame->pParent = pFrame->v->pDelFrame; pFrame->v->pDelFrame = pFrame; } #if defined(SQLITE_ENABLE_BYTECODE_VTAB) || !defined(SQLITE_OMIT_EXPLAIN) /* ** Locate the next opcode to be displayed in EXPLAIN or EXPLAIN ** QUERY PLAN output. ** ** Return SQLITE_ROW on success. Return SQLITE_DONE if there are no ** more opcodes to be displayed. */ SQLITE_PRIVATE int sqlite3VdbeNextOpcode( Vdbe *p, /* The statement being explained */ Mem *pSub, /* Storage for keeping track of subprogram nesting */ int eMode, /* 0: normal. 1: EQP. 2: TablesUsed */ int *piPc, /* IN/OUT: Current rowid. Overwritten with next rowid */ int *piAddr, /* OUT: Write index into (*paOp)[] here */ Op **paOp /* OUT: Write the opcode array here */ ){ int nRow; /* Stop when row count reaches this */ int nSub = 0; /* Number of sub-vdbes seen so far */ SubProgram **apSub = 0; /* Array of sub-vdbes */ int i; /* Next instruction address */ int rc = SQLITE_OK; /* Result code */ Op *aOp = 0; /* Opcode array */ int iPc; /* Rowid. Copy of value in *piPc */ /* When the number of output rows reaches nRow, that means the ** listing has finished and sqlite3_step() should return SQLITE_DONE. ** nRow is the sum of the number of rows in the main program, plus ** the sum of the number of rows in all trigger subprograms encountered ** so far. The nRow value will increase as new trigger subprograms are ** encountered, but p->pc will eventually catch up to nRow. */ nRow = p->nOp; if( pSub!=0 ){ if( pSub->flags&MEM_Blob ){ /* pSub is initiallly NULL. It is initialized to a BLOB by ** the P4_SUBPROGRAM processing logic below */ nSub = pSub->n/sizeof(Vdbe*); apSub = (SubProgram **)pSub->z; } for(i=0; inOp; } } iPc = *piPc; while(1){ /* Loop exits via break */ i = iPc++; if( i>=nRow ){ p->rc = SQLITE_OK; rc = SQLITE_DONE; break; } if( inOp ){ /* The rowid is small enough that we are still in the ** main program. */ aOp = p->aOp; }else{ /* We are currently listing subprograms. Figure out which one and ** pick up the appropriate opcode. */ int j; i -= p->nOp; assert( apSub!=0 ); assert( nSub>0 ); for(j=0; i>=apSub[j]->nOp; j++){ i -= apSub[j]->nOp; assert( inOp || j+1aOp; } /* When an OP_Program opcode is encounter (the only opcode that has ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms ** kept in p->aMem[9].z to hold the new program - assuming this subprogram ** has not already been seen. */ if( pSub!=0 && aOp[i].p4type==P4_SUBPROGRAM ){ int nByte = (nSub+1)*sizeof(SubProgram*); int j; for(j=0; jrc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0); if( p->rc!=SQLITE_OK ){ rc = SQLITE_ERROR; break; } apSub = (SubProgram **)pSub->z; apSub[nSub++] = aOp[i].p4.pProgram; MemSetTypeFlag(pSub, MEM_Blob); pSub->n = nSub*sizeof(SubProgram*); nRow += aOp[i].p4.pProgram->nOp; } } if( eMode==0 ) break; #ifdef SQLITE_ENABLE_BYTECODE_VTAB if( eMode==2 ){ Op *pOp = aOp + i; if( pOp->opcode==OP_OpenRead ) break; if( pOp->opcode==OP_OpenWrite && (pOp->p5 & OPFLAG_P2ISREG)==0 ) break; if( pOp->opcode==OP_ReopenIdx ) break; }else #endif { assert( eMode==1 ); if( aOp[i].opcode==OP_Explain ) break; if( aOp[i].opcode==OP_Init && iPc>1 ) break; } } *piPc = iPc; *piAddr = i; *paOp = aOp; return rc; } #endif /* SQLITE_ENABLE_BYTECODE_VTAB || !SQLITE_OMIT_EXPLAIN */ /* ** Delete a VdbeFrame object and its contents. VdbeFrame objects are ** allocated by the OP_Program opcode in sqlite3VdbeExec(). */ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){ int i; Mem *aMem = VdbeFrameMem(p); VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem]; assert( sqlite3VdbeFrameIsValid(p) ); for(i=0; inChildCsr; i++){ if( apCsr[i] ) sqlite3VdbeFreeCursorNN(p->v, apCsr[i]); } releaseMemArray(aMem, p->nChildMem); sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0); sqlite3DbFree(p->v->db, p); } #ifndef SQLITE_OMIT_EXPLAIN /* ** Give a listing of the program in the virtual machine. ** ** The interface is the same as sqlite3VdbeExec(). But instead of ** running the code, it invokes the callback once for each instruction. ** This feature is used to implement "EXPLAIN". ** ** When p->explain==1, each instruction is listed. When ** p->explain==2, only OP_Explain instructions are listed and these ** are shown in a different format. p->explain==2 is used to implement ** EXPLAIN QUERY PLAN. ** 2018-04-24: In p->explain==2 mode, the OP_Init opcodes of triggers ** are also shown, so that the boundaries between the main program and ** each trigger are clear. ** ** When p->explain==1, first the main program is listed, then each of ** the trigger subprograms are listed one by one. */ SQLITE_PRIVATE int sqlite3VdbeList( Vdbe *p /* The VDBE */ ){ Mem *pSub = 0; /* Memory cell hold array of subprogs */ sqlite3 *db = p->db; /* The database connection */ int i; /* Loop counter */ int rc = SQLITE_OK; /* Return code */ Mem *pMem = &p->aMem[1]; /* First Mem of result set */ int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0); Op *aOp; /* Array of opcodes */ Op *pOp; /* Current opcode */ assert( p->explain ); assert( p->eVdbeState==VDBE_RUN_STATE ); assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM ); /* Even though this opcode does not use dynamic strings for ** the result, result columns may become dynamic if the user calls ** sqlite3_column_text16(), causing a translation to UTF-16 encoding. */ releaseMemArray(pMem, 8); if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ sqlite3OomFault(db); return SQLITE_ERROR; } if( bListSubprogs ){ /* The first 8 memory cells are used for the result set. So we will ** commandeer the 9th cell to use as storage for an array of pointers ** to trigger subprograms. The VDBE is guaranteed to have at least 9 ** cells. */ assert( p->nMem>9 ); pSub = &p->aMem[9]; }else{ pSub = 0; } /* Figure out which opcode is next to display */ rc = sqlite3VdbeNextOpcode(p, pSub, p->explain==2, &p->pc, &i, &aOp); if( rc==SQLITE_OK ){ pOp = aOp + i; if( AtomicLoad(&db->u1.isInterrupted) ){ p->rc = SQLITE_INTERRUPT; rc = SQLITE_ERROR; sqlite3VdbeError(p, sqlite3ErrStr(p->rc)); }else{ char *zP4 = sqlite3VdbeDisplayP4(db, pOp); if( p->explain==2 ){ sqlite3VdbeMemSetInt64(pMem, pOp->p1); sqlite3VdbeMemSetInt64(pMem+1, pOp->p2); sqlite3VdbeMemSetInt64(pMem+2, pOp->p3); sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free); assert( p->nResColumn==4 ); }else{ sqlite3VdbeMemSetInt64(pMem+0, i); sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode), -1, SQLITE_UTF8, SQLITE_STATIC); sqlite3VdbeMemSetInt64(pMem+2, pOp->p1); sqlite3VdbeMemSetInt64(pMem+3, pOp->p2); sqlite3VdbeMemSetInt64(pMem+4, pOp->p3); /* pMem+5 for p4 is done last */ sqlite3VdbeMemSetInt64(pMem+6, pOp->p5); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS { char *zCom = sqlite3VdbeDisplayComment(db, pOp, zP4); sqlite3VdbeMemSetStr(pMem+7, zCom, -1, SQLITE_UTF8, sqlite3_free); } #else sqlite3VdbeMemSetNull(pMem+7); #endif sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free); assert( p->nResColumn==8 ); } p->pResultRow = pMem; if( db->mallocFailed ){ p->rc = SQLITE_NOMEM; rc = SQLITE_ERROR; }else{ p->rc = SQLITE_OK; rc = SQLITE_ROW; } } } return rc; } #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_DEBUG /* ** Print the SQL that was used to generate a VDBE program. */ SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe *p){ const char *z = 0; if( p->zSql ){ z = p->zSql; }else if( p->nOp>=1 ){ const VdbeOp *pOp = &p->aOp[0]; if( pOp->opcode==OP_Init && pOp->p4.z!=0 ){ z = pOp->p4.z; while( sqlite3Isspace(*z) ) z++; } } if( z ) printf("SQL: [%s]\n", z); } #endif #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) /* ** Print an IOTRACE message showing SQL content. */ SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){ int nOp = p->nOp; VdbeOp *pOp; if( sqlite3IoTrace==0 ) return; if( nOp<1 ) return; pOp = &p->aOp[0]; if( pOp->opcode==OP_Init && pOp->p4.z!=0 ){ int i, j; char z[1000]; sqlite3_snprintf(sizeof(z), z, "%s", pOp->p4.z); for(i=0; sqlite3Isspace(z[i]); i++){} for(j=0; z[i]; i++){ if( sqlite3Isspace(z[i]) ){ if( z[i-1]!=' ' ){ z[j++] = ' '; } }else{ z[j++] = z[i]; } } z[j] = 0; sqlite3IoTrace("SQL %s\n", z); } } #endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */ /* An instance of this object describes bulk memory available for use ** by subcomponents of a prepared statement. Space is allocated out ** of a ReusableSpace object by the allocSpace() routine below. */ struct ReusableSpace { u8 *pSpace; /* Available memory */ sqlite3_int64 nFree; /* Bytes of available memory */ sqlite3_int64 nNeeded; /* Total bytes that could not be allocated */ }; /* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf ** from the ReusableSpace object. Return a pointer to the allocated ** memory on success. If insufficient memory is available in the ** ReusableSpace object, increase the ReusableSpace.nNeeded ** value by the amount needed and return NULL. ** ** If pBuf is not initially NULL, that means that the memory has already ** been allocated by a prior call to this routine, so just return a copy ** of pBuf and leave ReusableSpace unchanged. ** ** This allocator is employed to repurpose unused slots at the end of the ** opcode array of prepared state for other memory needs of the prepared ** statement. */ static void *allocSpace( struct ReusableSpace *p, /* Bulk memory available for allocation */ void *pBuf, /* Pointer to a prior allocation */ sqlite3_int64 nByte /* Bytes of memory needed. */ ){ assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) ); if( pBuf==0 ){ nByte = ROUND8P(nByte); if( nByte <= p->nFree ){ p->nFree -= nByte; pBuf = &p->pSpace[p->nFree]; }else{ p->nNeeded += nByte; } } assert( EIGHT_BYTE_ALIGNMENT(pBuf) ); return pBuf; } /* ** Rewind the VDBE back to the beginning in preparation for ** running it. */ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){ #if defined(SQLITE_DEBUG) int i; #endif assert( p!=0 ); assert( p->eVdbeState==VDBE_INIT_STATE || p->eVdbeState==VDBE_READY_STATE || p->eVdbeState==VDBE_HALT_STATE ); /* There should be at least one opcode. */ assert( p->nOp>0 ); p->eVdbeState = VDBE_READY_STATE; #ifdef SQLITE_DEBUG for(i=0; inMem; i++){ assert( p->aMem[i].db==p->db ); } #endif p->pc = -1; p->rc = SQLITE_OK; p->errorAction = OE_Abort; p->nChange = 0; p->cacheCtr = 1; p->minWriteFileFormat = 255; p->iStatement = 0; p->nFkConstraint = 0; #ifdef VDBE_PROFILE for(i=0; inOp; i++){ p->aOp[i].nExec = 0; p->aOp[i].nCycle = 0; } #endif } /* ** Prepare a virtual machine for execution for the first time after ** creating the virtual machine. This involves things such ** as allocating registers and initializing the program counter. ** After the VDBE has be prepped, it can be executed by one or more ** calls to sqlite3VdbeExec(). ** ** This function may be called exactly once on each virtual machine. ** After this routine is called the VM has been "packaged" and is ready ** to run. After this routine is called, further calls to ** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects ** the Vdbe from the Parse object that helped generate it so that the ** the Vdbe becomes an independent entity and the Parse object can be ** destroyed. ** ** Use the sqlite3VdbeRewind() procedure to restore a virtual machine back ** to its initial state after it has been run. */ SQLITE_PRIVATE void sqlite3VdbeMakeReady( Vdbe *p, /* The VDBE */ Parse *pParse /* Parsing context */ ){ sqlite3 *db; /* The database connection */ int nVar; /* Number of parameters */ int nMem; /* Number of VM memory registers */ int nCursor; /* Number of cursors required */ int nArg; /* Number of arguments in subprograms */ int n; /* Loop counter */ struct ReusableSpace x; /* Reusable bulk memory */ assert( p!=0 ); assert( p->nOp>0 ); assert( pParse!=0 ); assert( p->eVdbeState==VDBE_INIT_STATE ); assert( pParse==p->pParse ); p->pVList = pParse->pVList; pParse->pVList = 0; db = p->db; assert( db->mallocFailed==0 ); nVar = pParse->nVar; nMem = pParse->nMem; nCursor = pParse->nTab; nArg = pParse->nMaxArg; /* Each cursor uses a memory cell. The first cursor (cursor 0) can ** use aMem[0] which is not otherwise used by the VDBE program. Allocate ** space at the end of aMem[] for cursors 1 and greater. ** See also: allocateCursor(). */ nMem += nCursor; if( nCursor==0 && nMem>0 ) nMem++; /* Space for aMem[0] even if not used */ /* Figure out how much reusable memory is available at the end of the ** opcode array. This extra memory will be reallocated for other elements ** of the prepared statement. */ n = ROUND8P(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */ x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */ assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) ); x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */ assert( x.nFree>=0 ); assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) ); resolveP2Values(p, &nArg); p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort); if( pParse->explain ){ if( nMem<10 ) nMem = 10; p->explain = pParse->explain; p->nResColumn = 12 - 4*p->explain; } p->expired = 0; /* Memory for registers, parameters, cursor, etc, is allocated in one or two ** passes. On the first pass, we try to reuse unused memory at the ** end of the opcode array. If we are unable to satisfy all memory ** requirements by reusing the opcode array tail, then the second ** pass will fill in the remainder using a fresh memory allocation. ** ** This two-pass approach that reuses as much memory as possible from ** the leftover memory at the end of the opcode array. This can significantly ** reduce the amount of memory held by a prepared statement. */ x.nNeeded = 0; p->aMem = allocSpace(&x, 0, nMem*sizeof(Mem)); p->aVar = allocSpace(&x, 0, nVar*sizeof(Mem)); p->apArg = allocSpace(&x, 0, nArg*sizeof(Mem*)); p->apCsr = allocSpace(&x, 0, nCursor*sizeof(VdbeCursor*)); if( x.nNeeded ){ x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded); x.nFree = x.nNeeded; if( !db->mallocFailed ){ p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem)); p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem)); p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*)); p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); } } if( db->mallocFailed ){ p->nVar = 0; p->nCursor = 0; p->nMem = 0; }else{ p->nCursor = nCursor; p->nVar = (ynVar)nVar; initMemArray(p->aVar, nVar, db, MEM_Null); p->nMem = nMem; initMemArray(p->aMem, nMem, db, MEM_Undefined); memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*)); } sqlite3VdbeRewind(p); } /* ** Close a VDBE cursor and release all the resources that cursor ** happens to hold. */ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ if( pCx ) sqlite3VdbeFreeCursorNN(p,pCx); } static SQLITE_NOINLINE void freeCursorWithCache(Vdbe *p, VdbeCursor *pCx){ VdbeTxtBlbCache *pCache = pCx->pCache; assert( pCx->colCache ); pCx->colCache = 0; pCx->pCache = 0; if( pCache->pCValue ){ sqlite3RCStrUnref(pCache->pCValue); pCache->pCValue = 0; } sqlite3DbFree(p->db, pCache); sqlite3VdbeFreeCursorNN(p, pCx); } SQLITE_PRIVATE void sqlite3VdbeFreeCursorNN(Vdbe *p, VdbeCursor *pCx){ if( pCx->colCache ){ freeCursorWithCache(p, pCx); return; } switch( pCx->eCurType ){ case CURTYPE_SORTER: { sqlite3VdbeSorterClose(p->db, pCx); break; } case CURTYPE_BTREE: { assert( pCx->uc.pCursor!=0 ); sqlite3BtreeCloseCursor(pCx->uc.pCursor); break; } #ifndef SQLITE_OMIT_VIRTUALTABLE case CURTYPE_VTAB: { sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur; const sqlite3_module *pModule = pVCur->pVtab->pModule; assert( pVCur->pVtab->nRef>0 ); pVCur->pVtab->nRef--; pModule->xClose(pVCur); break; } #endif } } /* ** Close all cursors in the current frame. */ static void closeCursorsInFrame(Vdbe *p){ int i; for(i=0; inCursor; i++){ VdbeCursor *pC = p->apCsr[i]; if( pC ){ sqlite3VdbeFreeCursorNN(p, pC); p->apCsr[i] = 0; } } } /* ** Copy the values stored in the VdbeFrame structure to its Vdbe. This ** is used, for example, when a trigger sub-program is halted to restore ** control to the main program. */ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ Vdbe *v = pFrame->v; closeCursorsInFrame(v); v->aOp = pFrame->aOp; v->nOp = pFrame->nOp; v->aMem = pFrame->aMem; v->nMem = pFrame->nMem; v->apCsr = pFrame->apCsr; v->nCursor = pFrame->nCursor; v->db->lastRowid = pFrame->lastRowid; v->nChange = pFrame->nChange; v->db->nChange = pFrame->nDbChange; sqlite3VdbeDeleteAuxData(v->db, &v->pAuxData, -1, 0); v->pAuxData = pFrame->pAuxData; pFrame->pAuxData = 0; return pFrame->pc; } /* ** Close all cursors. ** ** Also release any dynamic memory held by the VM in the Vdbe.aMem memory ** cell array. This is necessary as the memory cell array may contain ** pointers to VdbeFrame objects, which may in turn contain pointers to ** open cursors. */ static void closeAllCursors(Vdbe *p){ if( p->pFrame ){ VdbeFrame *pFrame; for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); sqlite3VdbeFrameRestore(pFrame); p->pFrame = 0; p->nFrame = 0; } assert( p->nFrame==0 ); closeCursorsInFrame(p); releaseMemArray(p->aMem, p->nMem); while( p->pDelFrame ){ VdbeFrame *pDel = p->pDelFrame; p->pDelFrame = pDel->pParent; sqlite3VdbeFrameDelete(pDel); } /* Delete any auxdata allocations made by the VM */ if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p->db, &p->pAuxData, -1, 0); assert( p->pAuxData==0 ); } /* ** Set the number of result columns that will be returned by this SQL ** statement. This is now set at compile time, rather than during ** execution of the vdbe program so that sqlite3_column_count() can ** be called on an SQL statement before sqlite3_step(). */ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ int n; sqlite3 *db = p->db; if( p->nResAlloc ){ releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N); sqlite3DbFree(db, p->aColName); } n = nResColumn*COLNAME_N; p->nResColumn = p->nResAlloc = (u16)nResColumn; p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n ); if( p->aColName==0 ) return; initMemArray(p->aColName, n, db, MEM_Null); } /* ** Set the name of the idx'th column to be returned by the SQL statement. ** zName must be a pointer to a nul terminated string. ** ** This call must be made after a call to sqlite3VdbeSetNumCols(). ** ** The final parameter, xDel, must be one of SQLITE_DYNAMIC, SQLITE_STATIC ** or SQLITE_TRANSIENT. If it is SQLITE_DYNAMIC, then the buffer pointed ** to by zName will be freed by sqlite3DbFree() when the vdbe is destroyed. */ SQLITE_PRIVATE int sqlite3VdbeSetColName( Vdbe *p, /* Vdbe being configured */ int idx, /* Index of column zName applies to */ int var, /* One of the COLNAME_* constants */ const char *zName, /* Pointer to buffer containing name */ void (*xDel)(void*) /* Memory management strategy for zName */ ){ int rc; Mem *pColName; assert( idxnResAlloc ); assert( vardb->mallocFailed ){ assert( !zName || xDel!=SQLITE_DYNAMIC ); return SQLITE_NOMEM_BKPT; } assert( p->aColName!=0 ); pColName = &(p->aColName[idx+var*p->nResAlloc]); rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, xDel); assert( rc!=0 || !zName || (pColName->flags&MEM_Term)!=0 ); return rc; } /* ** A read or write transaction may or may not be active on database handle ** db. If a transaction is active, commit it. If there is a ** write-transaction spanning more than one database file, this routine ** takes care of the super-journal trickery. */ static int vdbeCommit(sqlite3 *db, Vdbe *p){ int i; int nTrans = 0; /* Number of databases with an active write-transaction ** that are candidates for a two-phase commit using a ** super-journal */ int rc = SQLITE_OK; int needXcommit = 0; #ifdef SQLITE_OMIT_VIRTUALTABLE /* With this option, sqlite3VtabSync() is defined to be simply ** SQLITE_OK so p is not used. */ UNUSED_PARAMETER(p); #endif /* Before doing anything else, call the xSync() callback for any ** virtual module tables written in this transaction. This has to ** be done before determining whether a super-journal file is ** required, as an xSync() callback may add an attached database ** to the transaction. */ rc = sqlite3VtabSync(db, p); /* This loop determines (a) if the commit hook should be invoked and ** (b) how many database files have open write transactions, not ** including the temp database. (b) is important because if more than ** one database file has an open write transaction, a super-journal ** file is required for an atomic commit. */ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ /* Whether or not a database might need a super-journal depends upon ** its journal mode (among other things). This matrix determines which ** journal modes use a super-journal and which do not */ static const u8 aMJNeeded[] = { /* DELETE */ 1, /* PERSIST */ 1, /* OFF */ 0, /* TRUNCATE */ 1, /* MEMORY */ 0, /* WAL */ 0 }; Pager *pPager; /* Pager associated with pBt */ needXcommit = 1; sqlite3BtreeEnter(pBt); pPager = sqlite3BtreePager(pBt); if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF && aMJNeeded[sqlite3PagerGetJournalMode(pPager)] && sqlite3PagerIsMemdb(pPager)==0 ){ assert( i!=1 ); nTrans++; } rc = sqlite3PagerExclusiveLock(pPager); sqlite3BtreeLeave(pBt); } } if( rc!=SQLITE_OK ){ return rc; } /* If there are any write-transactions at all, invoke the commit hook */ if( needXcommit && db->xCommitCallback ){ rc = db->xCommitCallback(db->pCommitArg); if( rc ){ return SQLITE_CONSTRAINT_COMMITHOOK; } } /* The simple case - no more than one database file (not counting the ** TEMP database) has a transaction active. There is no need for the ** super-journal. ** ** If the return value of sqlite3BtreeGetFilename() is a zero length ** string, it means the main database is :memory: or a temp file. In ** that case we do not support atomic multi-file commits, so use the ** simple case then too. */ if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt)) || nTrans<=1 ){ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ rc = sqlite3BtreeCommitPhaseOne(pBt, 0); } } /* Do the commit only if all databases successfully complete phase 1. ** If one of the BtreeCommitPhaseOne() calls fails, this indicates an ** IO error while deleting or truncating a journal file. It is unlikely, ** but could happen. In this case abandon processing and return the error. */ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ rc = sqlite3BtreeCommitPhaseTwo(pBt, 0); } } if( rc==SQLITE_OK ){ sqlite3VtabCommit(db); } } /* The complex case - There is a multi-file write-transaction active. ** This requires a super-journal file to ensure the transaction is ** committed atomically. */ #ifndef SQLITE_OMIT_DISKIO else{ sqlite3_vfs *pVfs = db->pVfs; char *zSuper = 0; /* File-name for the super-journal */ char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); sqlite3_file *pSuperJrnl = 0; i64 offset = 0; int res; int retryCount = 0; int nMainFile; /* Select a super-journal file name */ nMainFile = sqlite3Strlen30(zMainFile); zSuper = sqlite3MPrintf(db, "%.4c%s%.16c", 0,zMainFile,0); if( zSuper==0 ) return SQLITE_NOMEM_BKPT; zSuper += 4; do { u32 iRandom; if( retryCount ){ if( retryCount>100 ){ sqlite3_log(SQLITE_FULL, "MJ delete: %s", zSuper); sqlite3OsDelete(pVfs, zSuper, 0); break; }else if( retryCount==1 ){ sqlite3_log(SQLITE_FULL, "MJ collide: %s", zSuper); } } retryCount++; sqlite3_randomness(sizeof(iRandom), &iRandom); sqlite3_snprintf(13, &zSuper[nMainFile], "-mj%06X9%02X", (iRandom>>8)&0xffffff, iRandom&0xff); /* The antipenultimate character of the super-journal name must ** be "9" to avoid name collisions when using 8+3 filenames. */ assert( zSuper[sqlite3Strlen30(zSuper)-3]=='9' ); sqlite3FileSuffix3(zMainFile, zSuper); rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); }while( rc==SQLITE_OK && res ); if( rc==SQLITE_OK ){ /* Open the super-journal. */ rc = sqlite3OsOpenMalloc(pVfs, zSuper, &pSuperJrnl, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE| SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_SUPER_JOURNAL, 0 ); } if( rc!=SQLITE_OK ){ sqlite3DbFree(db, zSuper-4); return rc; } /* Write the name of each database file in the transaction into the new ** super-journal file. If an error occurs at this point close ** and delete the super-journal file. All the individual journal files ** still have 'null' as the super-journal pointer, so they will roll ** back independently if a failure occurs. */ for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ char const *zFile = sqlite3BtreeGetJournalname(pBt); if( zFile==0 ){ continue; /* Ignore TEMP and :memory: databases */ } assert( zFile[0]!=0 ); rc = sqlite3OsWrite(pSuperJrnl, zFile, sqlite3Strlen30(zFile)+1,offset); offset += sqlite3Strlen30(zFile)+1; if( rc!=SQLITE_OK ){ sqlite3OsCloseFree(pSuperJrnl); sqlite3OsDelete(pVfs, zSuper, 0); sqlite3DbFree(db, zSuper-4); return rc; } } } /* Sync the super-journal file. If the IOCAP_SEQUENTIAL device ** flag is set this is not required. */ if( 0==(sqlite3OsDeviceCharacteristics(pSuperJrnl)&SQLITE_IOCAP_SEQUENTIAL) && SQLITE_OK!=(rc = sqlite3OsSync(pSuperJrnl, SQLITE_SYNC_NORMAL)) ){ sqlite3OsCloseFree(pSuperJrnl); sqlite3OsDelete(pVfs, zSuper, 0); sqlite3DbFree(db, zSuper-4); return rc; } /* Sync all the db files involved in the transaction. The same call ** sets the super-journal pointer in each individual journal. If ** an error occurs here, do not delete the super-journal file. ** ** If the error occurs during the first call to ** sqlite3BtreeCommitPhaseOne(), then there is a chance that the ** super-journal file will be orphaned. But we cannot delete it, ** in case the super-journal file name was written into the journal ** file before the failure occurred. */ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ rc = sqlite3BtreeCommitPhaseOne(pBt, zSuper); } } sqlite3OsCloseFree(pSuperJrnl); assert( rc!=SQLITE_BUSY ); if( rc!=SQLITE_OK ){ sqlite3DbFree(db, zSuper-4); return rc; } /* Delete the super-journal file. This commits the transaction. After ** doing this the directory is synced again before any individual ** transaction files are deleted. */ rc = sqlite3OsDelete(pVfs, zSuper, 1); sqlite3DbFree(db, zSuper-4); zSuper = 0; if( rc ){ return rc; } /* All files and directories have already been synced, so the following ** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and ** deleting or truncating journals. If something goes wrong while ** this is happening we don't really care. The integrity of the ** transaction is already guaranteed, but some stray 'cold' journals ** may be lying around. Returning an error code won't help matters. */ disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ sqlite3BtreeCommitPhaseTwo(pBt, 1); } } sqlite3EndBenignMalloc(); enable_simulated_io_errors(); sqlite3VtabCommit(db); } #endif return rc; } /* ** This routine checks that the sqlite3.nVdbeActive count variable ** matches the number of vdbe's in the list sqlite3.pVdbe that are ** currently active. An assertion fails if the two counts do not match. ** This is an internal self-check only - it is not an essential processing ** step. ** ** This is a no-op if NDEBUG is defined. */ #ifndef NDEBUG static void checkActiveVdbeCnt(sqlite3 *db){ Vdbe *p; int cnt = 0; int nWrite = 0; int nRead = 0; p = db->pVdbe; while( p ){ if( sqlite3_stmt_busy((sqlite3_stmt*)p) ){ cnt++; if( p->readOnly==0 ) nWrite++; if( p->bIsReader ) nRead++; } p = p->pVNext; } assert( cnt==db->nVdbeActive ); assert( nWrite==db->nVdbeWrite ); assert( nRead==db->nVdbeRead ); } #else #define checkActiveVdbeCnt(x) #endif /* ** If the Vdbe passed as the first argument opened a statement-transaction, ** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or ** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement ** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the ** statement transaction is committed. ** ** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. ** Otherwise SQLITE_OK. */ static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){ sqlite3 *const db = p->db; int rc = SQLITE_OK; int i; const int iSavepoint = p->iStatement-1; assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE); assert( db->nStatement>0 ); assert( p->iStatement==(db->nStatement+db->nSavepoint) ); for(i=0; inDb; i++){ int rc2 = SQLITE_OK; Btree *pBt = db->aDb[i].pBt; if( pBt ){ if( eOp==SAVEPOINT_ROLLBACK ){ rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint); } if( rc2==SQLITE_OK ){ rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint); } if( rc==SQLITE_OK ){ rc = rc2; } } } db->nStatement--; p->iStatement = 0; if( rc==SQLITE_OK ){ if( eOp==SAVEPOINT_ROLLBACK ){ rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint); } if( rc==SQLITE_OK ){ rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint); } } /* If the statement transaction is being rolled back, also restore the ** database handles deferred constraint counter to the value it had when ** the statement transaction was opened. */ if( eOp==SAVEPOINT_ROLLBACK ){ db->nDeferredCons = p->nStmtDefCons; db->nDeferredImmCons = p->nStmtDefImmCons; } return rc; } SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ if( p->db->nStatement && p->iStatement ){ return vdbeCloseStatement(p, eOp); } return SQLITE_OK; } /* ** This function is called when a transaction opened by the database ** handle associated with the VM passed as an argument is about to be ** committed. If there are outstanding deferred foreign key constraint ** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK. ** ** If there are outstanding FK violations and this function returns ** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY ** and write an error message to it. Then return SQLITE_ERROR. */ #ifndef SQLITE_OMIT_FOREIGN_KEY SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){ sqlite3 *db = p->db; if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0) || (!deferred && p->nFkConstraint>0) ){ p->rc = SQLITE_CONSTRAINT_FOREIGNKEY; p->errorAction = OE_Abort; sqlite3VdbeError(p, "FOREIGN KEY constraint failed"); if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ) return SQLITE_ERROR; return SQLITE_CONSTRAINT_FOREIGNKEY; } return SQLITE_OK; } #endif /* ** This routine is called the when a VDBE tries to halt. If the VDBE ** has made changes and is in autocommit mode, then commit those ** changes. If a rollback is needed, then do the rollback. ** ** This routine is the only way to move the sqlite3eOpenState of a VM from ** SQLITE_STATE_RUN to SQLITE_STATE_HALT. It is harmless to ** call this on a VM that is in the SQLITE_STATE_HALT state. ** ** Return an error code. If the commit could not complete because of ** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it ** means the close did not happen and needs to be repeated. */ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ int rc; /* Used to store transient return codes */ sqlite3 *db = p->db; /* This function contains the logic that determines if a statement or ** transaction will be committed or rolled back as a result of the ** execution of this virtual machine. ** ** If any of the following errors occur: ** ** SQLITE_NOMEM ** SQLITE_IOERR ** SQLITE_FULL ** SQLITE_INTERRUPT ** ** Then the internal cache might have been left in an inconsistent ** state. We need to rollback the statement transaction, if there is ** one, or the complete transaction if there is no statement transaction. */ assert( p->eVdbeState==VDBE_RUN_STATE ); if( db->mallocFailed ){ p->rc = SQLITE_NOMEM_BKPT; } closeAllCursors(p); checkActiveVdbeCnt(db); /* No commit or rollback needed if the program never started or if the ** SQL statement does not read or write a database file. */ if( p->bIsReader ){ int mrc; /* Primary error code from p->rc */ int eStatementOp = 0; int isSpecialError; /* Set to true if a 'special' error */ /* Lock all btrees used by the statement */ sqlite3VdbeEnter(p); /* Check for one of the special errors */ if( p->rc ){ mrc = p->rc & 0xff; isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; }else{ mrc = isSpecialError = 0; } if( isSpecialError ){ /* If the query was read-only and the error code is SQLITE_INTERRUPT, ** no rollback is necessary. Otherwise, at least a savepoint ** transaction must be rolled back to restore the database to a ** consistent state. ** ** Even if the statement is read-only, it is important to perform ** a statement or transaction rollback operation. If the error ** occurred while writing to the journal, sub-journal or database ** file as part of an effort to free up cache space (see function ** pagerStress() in pager.c), the rollback is required to restore ** the pager to a consistent state. */ if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){ if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){ eStatementOp = SAVEPOINT_ROLLBACK; }else{ /* We are forced to roll back the active transaction. Before doing ** so, abort any other statements this handle currently has active. */ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; p->nChange = 0; } } } /* Check for immediate foreign key violations. */ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ sqlite3VdbeCheckFk(p, 0); } /* If the auto-commit flag is set and this is the only active writer ** VM, then we do either a commit or rollback of the current transaction. ** ** Note: This block also runs if one of the special errors handled ** above has occurred. */ if( !sqlite3VtabInSync(db) && db->autoCommit && db->nVdbeWrite==(p->readOnly==0) ){ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ rc = sqlite3VdbeCheckFk(p, 1); if( rc!=SQLITE_OK ){ if( NEVER(p->readOnly) ){ sqlite3VdbeLeave(p); return SQLITE_ERROR; } rc = SQLITE_CONSTRAINT_FOREIGNKEY; }else if( db->flags & SQLITE_CorruptRdOnly ){ rc = SQLITE_CORRUPT; db->flags &= ~SQLITE_CorruptRdOnly; }else{ /* The auto-commit flag is true, the vdbe program was successful ** or hit an 'OR FAIL' constraint and there are no deferred foreign ** key constraints to hold up the transaction. This means a commit ** is required. */ rc = vdbeCommit(db, p); } if( rc==SQLITE_BUSY && p->readOnly ){ sqlite3VdbeLeave(p); return SQLITE_BUSY; }else if( rc!=SQLITE_OK ){ sqlite3SystemError(db, rc); p->rc = rc; sqlite3RollbackAll(db, SQLITE_OK); p->nChange = 0; }else{ db->nDeferredCons = 0; db->nDeferredImmCons = 0; db->flags &= ~(u64)SQLITE_DeferFKs; sqlite3CommitInternalChanges(db); } }else if( p->rc==SQLITE_SCHEMA && db->nVdbeActive>1 ){ p->nChange = 0; }else{ sqlite3RollbackAll(db, SQLITE_OK); p->nChange = 0; } db->nStatement = 0; }else if( eStatementOp==0 ){ if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ eStatementOp = SAVEPOINT_RELEASE; }else if( p->errorAction==OE_Abort ){ eStatementOp = SAVEPOINT_ROLLBACK; }else{ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; p->nChange = 0; } } /* If eStatementOp is non-zero, then a statement transaction needs to ** be committed or rolled back. Call sqlite3VdbeCloseStatement() to ** do so. If this operation returns an error, and the current statement ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the ** current statement error code. */ if( eStatementOp ){ rc = sqlite3VdbeCloseStatement(p, eStatementOp); if( rc ){ if( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ){ p->rc = rc; sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; p->nChange = 0; } } /* If this was an INSERT, UPDATE or DELETE and no statement transaction ** has been rolled back, update the database connection change-counter. */ if( p->changeCntOn ){ if( eStatementOp!=SAVEPOINT_ROLLBACK ){ sqlite3VdbeSetChanges(db, p->nChange); }else{ sqlite3VdbeSetChanges(db, 0); } p->nChange = 0; } /* Release the locks */ sqlite3VdbeLeave(p); } /* We have successfully halted and closed the VM. Record this fact. */ db->nVdbeActive--; if( !p->readOnly ) db->nVdbeWrite--; if( p->bIsReader ) db->nVdbeRead--; assert( db->nVdbeActive>=db->nVdbeRead ); assert( db->nVdbeRead>=db->nVdbeWrite ); assert( db->nVdbeWrite>=0 ); p->eVdbeState = VDBE_HALT_STATE; checkActiveVdbeCnt(db); if( db->mallocFailed ){ p->rc = SQLITE_NOMEM_BKPT; } /* If the auto-commit flag is set to true, then any locks that were held ** by connection db have now been released. Call sqlite3ConnectionUnlocked() ** to invoke any required unlock-notify callbacks. */ if( db->autoCommit ){ sqlite3ConnectionUnlocked(db); } assert( db->nVdbeActive>0 || db->autoCommit==0 || db->nStatement==0 ); return (p->rc==SQLITE_BUSY ? SQLITE_BUSY : SQLITE_OK); } /* ** Each VDBE holds the result of the most recent sqlite3_step() call ** in p->rc. This routine sets that result back to SQLITE_OK. */ SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe *p){ p->rc = SQLITE_OK; } /* ** Copy the error code and error message belonging to the VDBE passed ** as the first argument to its database handle (so that they will be ** returned by calls to sqlite3_errcode() and sqlite3_errmsg()). ** ** This function does not clear the VDBE error code or message, just ** copies them to the database handle. */ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){ sqlite3 *db = p->db; int rc = p->rc; if( p->zErrMsg ){ db->bBenignMalloc++; sqlite3BeginBenignMalloc(); if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db); sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT); sqlite3EndBenignMalloc(); db->bBenignMalloc--; }else if( db->pErr ){ sqlite3ValueSetNull(db->pErr); } db->errCode = rc; db->errByteOffset = -1; return rc; } #ifdef SQLITE_ENABLE_SQLLOG /* ** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run, ** invoke it. */ static void vdbeInvokeSqllog(Vdbe *v){ if( sqlite3GlobalConfig.xSqllog && v->rc==SQLITE_OK && v->zSql && v->pc>=0 ){ char *zExpanded = sqlite3VdbeExpandSql(v, v->zSql); assert( v->db->init.busy==0 ); if( zExpanded ){ sqlite3GlobalConfig.xSqllog( sqlite3GlobalConfig.pSqllogArg, v->db, zExpanded, 1 ); sqlite3DbFree(v->db, zExpanded); } } } #else # define vdbeInvokeSqllog(x) #endif /* ** Clean up a VDBE after execution but do not delete the VDBE just yet. ** Write any error messages into *pzErrMsg. Return the result code. ** ** After this routine is run, the VDBE should be ready to be executed ** again. ** ** To look at it another way, this routine resets the state of the ** virtual machine from VDBE_RUN_STATE or VDBE_HALT_STATE back to ** VDBE_READY_STATE. */ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) int i; #endif sqlite3 *db; db = p->db; /* If the VM did not run to completion or if it encountered an ** error, then it might not have been halted properly. So halt ** it now. */ if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p); /* If the VDBE has been run even partially, then transfer the error code ** and error message from the VDBE into the main database structure. But ** if the VDBE has just been set to run but has not actually executed any ** instructions yet, leave the main database error information unchanged. */ if( p->pc>=0 ){ vdbeInvokeSqllog(p); if( db->pErr || p->zErrMsg ){ sqlite3VdbeTransferError(p); }else{ db->errCode = p->rc; } } /* Reset register contents and reclaim error message memory. */ #ifdef SQLITE_DEBUG /* Execute assert() statements to ensure that the Vdbe.apCsr[] and ** Vdbe.aMem[] arrays have already been cleaned up. */ if( p->apCsr ) for(i=0; inCursor; i++) assert( p->apCsr[i]==0 ); if( p->aMem ){ for(i=0; inMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); } #endif if( p->zErrMsg ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } p->pResultRow = 0; #ifdef SQLITE_DEBUG p->nWrite = 0; #endif /* Save profiling information from this VDBE run. */ #ifdef VDBE_PROFILE { FILE *out = fopen("vdbe_profile.out", "a"); if( out ){ fprintf(out, "---- "); for(i=0; inOp; i++){ fprintf(out, "%02x", p->aOp[i].opcode); } fprintf(out, "\n"); if( p->zSql ){ char c, pc = 0; fprintf(out, "-- "); for(i=0; (c = p->zSql[i])!=0; i++){ if( pc=='\n' ) fprintf(out, "-- "); putc(c, out); pc = c; } if( pc!='\n' ) fprintf(out, "\n"); } for(i=0; inOp; i++){ char zHdr[100]; i64 cnt = p->aOp[i].nExec; i64 cycles = p->aOp[i].nCycle; sqlite3_snprintf(sizeof(zHdr), zHdr, "%6u %12llu %8llu ", cnt, cycles, cnt>0 ? cycles/cnt : 0 ); fprintf(out, "%s", zHdr); sqlite3VdbePrintOp(out, i, &p->aOp[i]); } fclose(out); } } #endif return p->rc & db->errMask; } /* ** Clean up and delete a VDBE after execution. Return an integer which is ** the result code. Write any error message text into *pzErrMsg. */ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){ int rc = SQLITE_OK; assert( VDBE_RUN_STATE>VDBE_READY_STATE ); assert( VDBE_HALT_STATE>VDBE_READY_STATE ); assert( VDBE_INIT_STATEeVdbeState>=VDBE_READY_STATE ){ rc = sqlite3VdbeReset(p); assert( (rc & p->db->errMask)==rc ); } sqlite3VdbeDelete(p); return rc; } /* ** If parameter iOp is less than zero, then invoke the destructor for ** all auxiliary data pointers currently cached by the VM passed as ** the first argument. ** ** Or, if iOp is greater than or equal to zero, then the destructor is ** only invoked for those auxiliary data pointers created by the user ** function invoked by the OP_Function opcode at instruction iOp of ** VM pVdbe, and only then if: ** ** * the associated function parameter is the 32nd or later (counting ** from left to right), or ** ** * the corresponding bit in argument mask is clear (where the first ** function parameter corresponds to bit 0 etc.). */ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){ while( *pp ){ AuxData *pAux = *pp; if( (iOp<0) || (pAux->iAuxOp==iOp && pAux->iAuxArg>=0 && (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg)))) ){ testcase( pAux->iAuxArg==31 ); if( pAux->xDeleteAux ){ pAux->xDeleteAux(pAux->pAux); } *pp = pAux->pNextAux; sqlite3DbFree(db, pAux); }else{ pp= &pAux->pNextAux; } } } /* ** Free all memory associated with the Vdbe passed as the second argument, ** except for object itself, which is preserved. ** ** The difference between this function and sqlite3VdbeDelete() is that ** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with ** the database connection and frees the object itself. */ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ SubProgram *pSub, *pNext; assert( db!=0 ); assert( p->db==0 || p->db==db ); if( p->aColName ){ releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N); sqlite3DbNNFreeNN(db, p->aColName); } for(pSub=p->pProgram; pSub; pSub=pNext){ pNext = pSub->pNext; vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); sqlite3DbFree(db, pSub); } if( p->eVdbeState!=VDBE_INIT_STATE ){ releaseMemArray(p->aVar, p->nVar); if( p->pVList ) sqlite3DbNNFreeNN(db, p->pVList); if( p->pFree ) sqlite3DbNNFreeNN(db, p->pFree); } vdbeFreeOpArray(db, p->aOp, p->nOp); if( p->zSql ) sqlite3DbNNFreeNN(db, p->zSql); #ifdef SQLITE_ENABLE_NORMALIZE sqlite3DbFree(db, p->zNormSql); { DblquoteStr *pThis, *pNxt; for(pThis=p->pDblStr; pThis; pThis=pNxt){ pNxt = pThis->pNextStr; sqlite3DbFree(db, pThis); } } #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS { int i; for(i=0; inScan; i++){ sqlite3DbFree(db, p->aScan[i].zName); } sqlite3DbFree(db, p->aScan); } #endif } /* ** Delete an entire VDBE. */ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){ sqlite3 *db; assert( p!=0 ); db = p->db; assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); sqlite3VdbeClearObject(db, p); if( db->pnBytesFreed==0 ){ assert( p->ppVPrev!=0 ); *p->ppVPrev = p->pVNext; if( p->pVNext ){ p->pVNext->ppVPrev = p->ppVPrev; } } sqlite3DbNNFreeNN(db, p); } /* ** The cursor "p" has a pending seek operation that has not yet been ** carried out. Seek the cursor now. If an error occurs, return ** the appropriate error code. */ SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){ int res, rc; #ifdef SQLITE_TEST extern int sqlite3_search_count; #endif assert( p->deferredMoveto ); assert( p->isTable ); assert( p->eCurType==CURTYPE_BTREE ); rc = sqlite3BtreeTableMoveto(p->uc.pCursor, p->movetoTarget, 0, &res); if( rc ) return rc; if( res!=0 ) return SQLITE_CORRUPT_BKPT; #ifdef SQLITE_TEST sqlite3_search_count++; #endif p->deferredMoveto = 0; p->cacheStatus = CACHE_STALE; return SQLITE_OK; } /* ** Something has moved cursor "p" out of place. Maybe the row it was ** pointed to was deleted out from under it. Or maybe the btree was ** rebalanced. Whatever the cause, try to restore "p" to the place it ** is supposed to be pointing. If the row was deleted out from under the ** cursor, set the cursor to point to a NULL row. */ SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeHandleMovedCursor(VdbeCursor *p){ int isDifferentRow, rc; assert( p->eCurType==CURTYPE_BTREE ); assert( p->uc.pCursor!=0 ); assert( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ); rc = sqlite3BtreeCursorRestore(p->uc.pCursor, &isDifferentRow); p->cacheStatus = CACHE_STALE; if( isDifferentRow ) p->nullRow = 1; return rc; } /* ** Check to ensure that the cursor is valid. Restore the cursor ** if need be. Return any I/O error from the restore operation. */ SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){ assert( p->eCurType==CURTYPE_BTREE || IsNullCursor(p) ); if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ return sqlite3VdbeHandleMovedCursor(p); } return SQLITE_OK; } /* ** The following functions: ** ** sqlite3VdbeSerialType() ** sqlite3VdbeSerialTypeLen() ** sqlite3VdbeSerialLen() ** sqlite3VdbeSerialPut() <--- in-lined into OP_MakeRecord as of 2022-04-02 ** sqlite3VdbeSerialGet() ** ** encapsulate the code that serializes values for storage in SQLite ** data and index records. Each serialized value consists of a ** 'serial-type' and a blob of data. The serial type is an 8-byte unsigned ** integer, stored as a varint. ** ** In an SQLite index record, the serial type is stored directly before ** the blob of data that it corresponds to. In a table record, all serial ** types are stored at the start of the record, and the blobs of data at ** the end. Hence these functions allow the caller to handle the ** serial-type and data blob separately. ** ** The following table describes the various storage classes for data: ** ** serial type bytes of data type ** -------------- --------------- --------------- ** 0 0 NULL ** 1 1 signed integer ** 2 2 signed integer ** 3 3 signed integer ** 4 4 signed integer ** 5 6 signed integer ** 6 8 signed integer ** 7 8 IEEE float ** 8 0 Integer constant 0 ** 9 0 Integer constant 1 ** 10,11 reserved for expansion ** N>=12 and even (N-12)/2 BLOB ** N>=13 and odd (N-13)/2 text ** ** The 8 and 9 types were added in 3.3.0, file format 4. Prior versions ** of SQLite will not understand those serial types. */ #if 0 /* Inlined into the OP_MakeRecord opcode */ /* ** Return the serial-type for the value stored in pMem. ** ** This routine might convert a large MEM_IntReal value into MEM_Real. ** ** 2019-07-11: The primary user of this subroutine was the OP_MakeRecord ** opcode in the byte-code engine. But by moving this routine in-line, we ** can omit some redundant tests and make that opcode a lot faster. So ** this routine is now only used by the STAT3 logic and STAT3 support has ** ended. The code is kept here for historical reference only. */ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ int flags = pMem->flags; u32 n; assert( pLen!=0 ); if( flags&MEM_Null ){ *pLen = 0; return 0; } if( flags&(MEM_Int|MEM_IntReal) ){ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ # define MAX_6BYTE ((((i64)0x00008000)<<32)-1) i64 i = pMem->u.i; u64 u; testcase( flags & MEM_Int ); testcase( flags & MEM_IntReal ); if( i<0 ){ u = ~i; }else{ u = i; } if( u<=127 ){ if( (i&1)==i && file_format>=4 ){ *pLen = 0; return 8+(u32)u; }else{ *pLen = 1; return 1; } } if( u<=32767 ){ *pLen = 2; return 2; } if( u<=8388607 ){ *pLen = 3; return 3; } if( u<=2147483647 ){ *pLen = 4; return 4; } if( u<=MAX_6BYTE ){ *pLen = 6; return 5; } *pLen = 8; if( flags&MEM_IntReal ){ /* If the value is IntReal and is going to take up 8 bytes to store ** as an integer, then we might as well make it an 8-byte floating ** point value */ pMem->u.r = (double)pMem->u.i; pMem->flags &= ~MEM_IntReal; pMem->flags |= MEM_Real; return 7; } return 6; } if( flags&MEM_Real ){ *pLen = 8; return 7; } assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) ); assert( pMem->n>=0 ); n = (u32)pMem->n; if( flags & MEM_Zero ){ n += pMem->u.nZero; } *pLen = n; return ((n*2) + 12 + ((flags&MEM_Str)!=0)); } #endif /* inlined into OP_MakeRecord */ /* ** The sizes for serial types less than 128 */ SQLITE_PRIVATE const u8 sqlite3SmallTypeSizes[128] = { /* 0 1 2 3 4 5 6 7 8 9 */ /* 0 */ 0, 1, 2, 3, 4, 6, 8, 8, 0, 0, /* 10 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, /* 20 */ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, /* 30 */ 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* 40 */ 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, /* 50 */ 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, /* 60 */ 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, /* 70 */ 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, /* 80 */ 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, /* 90 */ 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, /* 100 */ 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, /* 110 */ 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, /* 120 */ 54, 54, 55, 55, 56, 56, 57, 57 }; /* ** Return the length of the data corresponding to the supplied serial-type. */ SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){ if( serial_type>=128 ){ return (serial_type-12)/2; }else{ assert( serial_type<12 || sqlite3SmallTypeSizes[serial_type]==(serial_type - 12)/2 ); return sqlite3SmallTypeSizes[serial_type]; } } SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){ assert( serial_type<128 ); return sqlite3SmallTypeSizes[serial_type]; } /* ** If we are on an architecture with mixed-endian floating ** points (ex: ARM7) then swap the lower 4 bytes with the ** upper 4 bytes. Return the result. ** ** For most architectures, this is a no-op. ** ** (later): It is reported to me that the mixed-endian problem ** on ARM7 is an issue with GCC, not with the ARM7 chip. It seems ** that early versions of GCC stored the two words of a 64-bit ** float in the wrong order. And that error has been propagated ** ever since. The blame is not necessarily with GCC, though. ** GCC might have just copying the problem from a prior compiler. ** I am also told that newer versions of GCC that follow a different ** ABI get the byte order right. ** ** Developers using SQLite on an ARM7 should compile and run their ** application using -DSQLITE_DEBUG=1 at least once. With DEBUG ** enabled, some asserts below will ensure that the byte order of ** floating point values is correct. ** ** (2007-08-30) Frank van Vugt has studied this problem closely ** and has send his findings to the SQLite developers. Frank ** writes that some Linux kernels offer floating point hardware ** emulation that uses only 32-bit mantissas instead of a full ** 48-bits as required by the IEEE standard. (This is the ** CONFIG_FPE_FASTFPE option.) On such systems, floating point ** byte swapping becomes very complicated. To avoid problems, ** the necessary byte swapping is carried out using a 64-bit integer ** rather than a 64-bit float. Frank assures us that the code here ** works for him. We, the developers, have no way to independently ** verify this, but Frank seems to know what he is talking about ** so we trust him. */ #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT SQLITE_PRIVATE u64 sqlite3FloatSwap(u64 in){ union { u64 r; u32 i[2]; } u; u32 t; u.r = in; t = u.i[0]; u.i[0] = u.i[1]; u.i[1] = t; return u.r; } #endif /* SQLITE_MIXED_ENDIAN_64BIT_FLOAT */ /* Input "x" is a sequence of unsigned characters that represent a ** big-endian integer. Return the equivalent native integer */ #define ONE_BYTE_INT(x) ((i8)(x)[0]) #define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1]) #define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2]) #define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) #define FOUR_BYTE_INT(x) (16777216*(i8)((x)[0])|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) /* ** Deserialize the data blob pointed to by buf as serial type serial_type ** and store the result in pMem. ** ** This function is implemented as two separate routines for performance. ** The few cases that require local variables are broken out into a separate ** routine so that in most cases the overhead of moving the stack pointer ** is avoided. */ static void serialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ ){ u64 x = FOUR_BYTE_UINT(buf); u32 y = FOUR_BYTE_UINT(buf+4); x = (x<<32) + y; if( serial_type==6 ){ /* EVIDENCE-OF: R-29851-52272 Value is a big-endian 64-bit ** twos-complement integer. */ pMem->u.i = *(i64*)&x; pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); }else{ /* EVIDENCE-OF: R-57343-49114 Value is a big-endian IEEE 754-2008 64-bit ** floating point number. */ #if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT) /* Verify that integers and floating point values use the same ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is ** defined that 64-bit floating point values really are mixed ** endian. */ static const u64 t1 = ((u64)0x3ff00000)<<32; static const double r1 = 1.0; u64 t2 = t1; swapMixedEndianFloat(t2); assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); #endif assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); swapMixedEndianFloat(x); memcpy(&pMem->u.r, &x, sizeof(x)); pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real; } } SQLITE_PRIVATE void sqlite3VdbeSerialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ ){ switch( serial_type ){ case 10: { /* Internal use only: NULL with virtual table ** UPDATE no-change flag set */ pMem->flags = MEM_Null|MEM_Zero; pMem->n = 0; pMem->u.nZero = 0; return; } case 11: /* Reserved for future use */ case 0: { /* Null */ /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */ pMem->flags = MEM_Null; return; } case 1: { /* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement ** integer. */ pMem->u.i = ONE_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return; } case 2: { /* 2-byte signed integer */ /* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit ** twos-complement integer. */ pMem->u.i = TWO_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return; } case 3: { /* 3-byte signed integer */ /* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit ** twos-complement integer. */ pMem->u.i = THREE_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return; } case 4: { /* 4-byte signed integer */ /* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit ** twos-complement integer. */ pMem->u.i = FOUR_BYTE_INT(buf); #ifdef __HP_cc /* Work around a sign-extension bug in the HP compiler for HP/UX */ if( buf[0]&0x80 ) pMem->u.i |= 0xffffffff80000000LL; #endif pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return; } case 5: { /* 6-byte signed integer */ /* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit ** twos-complement integer. */ pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return; } case 6: /* 8-byte signed integer */ case 7: { /* IEEE floating point */ /* These use local variables, so do them in a separate routine ** to avoid having to move the frame pointer in the common case */ serialGet(buf,serial_type,pMem); return; } case 8: /* Integer 0 */ case 9: { /* Integer 1 */ /* EVIDENCE-OF: R-12976-22893 Value is the integer 0. */ /* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */ pMem->u.i = serial_type-8; pMem->flags = MEM_Int; return; } default: { /* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in ** length. ** EVIDENCE-OF: R-28401-00140 Value is a string in the text encoding and ** (N-13)/2 bytes in length. */ static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem }; pMem->z = (char *)buf; pMem->n = (serial_type-12)/2; pMem->flags = aFlag[serial_type&1]; return; } } return; } /* ** This routine is used to allocate sufficient space for an UnpackedRecord ** structure large enough to be used with sqlite3VdbeRecordUnpack() if ** the first argument is a pointer to KeyInfo structure pKeyInfo. ** ** The space is either allocated using sqlite3DbMallocRaw() or from within ** the unaligned buffer passed via the second and third arguments (presumably ** stack space). If the former, then *ppFree is set to a pointer that should ** be eventually freed by the caller using sqlite3DbFree(). Or, if the ** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL ** before returning. ** ** If an OOM error occurs, NULL is returned. */ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( KeyInfo *pKeyInfo /* Description of the record */ ){ UnpackedRecord *p; /* Unpacked record to return */ int nByte; /* Number of bytes required for *p */ nByte = ROUND8P(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1); p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); if( !p ) return 0; p->aMem = (Mem*)&((char*)p)[ROUND8P(sizeof(UnpackedRecord))]; assert( pKeyInfo->aSortFlags!=0 ); p->pKeyInfo = pKeyInfo; p->nField = pKeyInfo->nKeyField + 1; return p; } /* ** Given the nKey-byte encoding of a record in pKey[], populate the ** UnpackedRecord structure indicated by the fourth argument with the ** contents of the decoded record. */ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( KeyInfo *pKeyInfo, /* Information about the record format */ int nKey, /* Size of the binary record */ const void *pKey, /* The binary record */ UnpackedRecord *p /* Populate this structure before returning. */ ){ const unsigned char *aKey = (const unsigned char *)pKey; u32 d; u32 idx; /* Offset in aKey[] to read from */ u16 u; /* Unsigned loop counter */ u32 szHdr; Mem *pMem = p->aMem; p->default_rc = 0; assert( EIGHT_BYTE_ALIGNMENT(pMem) ); idx = getVarint32(aKey, szHdr); d = szHdr; u = 0; while( idxenc = pKeyInfo->enc; pMem->db = pKeyInfo->db; /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */ pMem->szMalloc = 0; pMem->z = 0; sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); d += sqlite3VdbeSerialTypeLen(serial_type); pMem++; if( (++u)>=p->nField ) break; } if( d>(u32)nKey && u ){ assert( CORRUPT_DB ); /* In a corrupt record entry, the last pMem might have been set up using ** uninitialized memory. Overwrite its value with NULL, to prevent ** warnings from MSAN. */ sqlite3VdbeMemSetNull(pMem-1); } assert( u<=pKeyInfo->nKeyField + 1 ); p->nField = u; } #ifdef SQLITE_DEBUG /* ** This function compares two index or table record keys in the same way ** as the sqlite3VdbeRecordCompare() routine. Unlike VdbeRecordCompare(), ** this function deserializes and compares values using the ** sqlite3VdbeSerialGet() and sqlite3MemCompare() functions. It is used ** in assert() statements to ensure that the optimized code in ** sqlite3VdbeRecordCompare() returns results with these two primitives. ** ** Return true if the result of comparison is equivalent to desiredResult. ** Return false if there is a disagreement. */ static int vdbeRecordCompareDebug( int nKey1, const void *pKey1, /* Left key */ const UnpackedRecord *pPKey2, /* Right key */ int desiredResult /* Correct answer */ ){ u32 d1; /* Offset into aKey[] of next data element */ u32 idx1; /* Offset into aKey[] of next header element */ u32 szHdr1; /* Number of bytes in header */ int i = 0; int rc = 0; const unsigned char *aKey1 = (const unsigned char *)pKey1; KeyInfo *pKeyInfo; Mem mem1; pKeyInfo = pPKey2->pKeyInfo; if( pKeyInfo->db==0 ) return 1; mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; /* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */ VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ /* Compilers may complain that mem1.u.i is potentially uninitialized. ** We could initialize it, as shown here, to silence those complaints. ** But in fact, mem1.u.i will never actually be used uninitialized, and doing ** the unnecessary initialization has a measurable negative performance ** impact, since this routine is a very high runner. And so, we choose ** to ignore the compiler warnings and leave this variable uninitialized. */ /* mem1.u.i = 0; // not needed, here to silence compiler warning */ idx1 = getVarint32(aKey1, szHdr1); if( szHdr1>98307 ) return SQLITE_CORRUPT; d1 = szHdr1; assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); assert( pKeyInfo->aSortFlags!=0 ); assert( pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ u32 serial_type1; /* Read the serial types for the next element in each key. */ idx1 += getVarint32( aKey1+idx1, serial_type1 ); /* Verify that there is enough key space remaining to avoid ** a buffer overread. The "d1+serial_type1+2" subexpression will ** always be greater than or equal to the amount of required key space. ** Use that approximation to avoid the more expensive call to ** sqlite3VdbeSerialTypeLen() in the common case. */ if( d1+(u64)serial_type1+2>(u64)nKey1 && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1 ){ if( serial_type1>=1 && serial_type1<=7 && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)<=(u64)nKey1+8 && CORRUPT_DB ){ return 1; /* corrupt record not detected by ** sqlite3VdbeRecordCompareWithSkip(). Return true ** to avoid firing the assert() */ } break; } /* Extract the values to be compared. */ sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1); d1 += sqlite3VdbeSerialTypeLen(serial_type1); /* Do the comparison */ rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->nAllField>i ? pKeyInfo->aColl[i] : 0); if( rc!=0 ){ assert( mem1.szMalloc==0 ); /* See comment below */ if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) && ((mem1.flags & MEM_Null) || (pPKey2->aMem[i].flags & MEM_Null)) ){ rc = -rc; } if( pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC ){ rc = -rc; /* Invert the result for DESC sort order. */ } goto debugCompareEnd; } i++; }while( idx1nField ); /* No memory allocation is ever used on mem1. Prove this using ** the following assert(). If the assert() fails, it indicates a ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ assert( mem1.szMalloc==0 ); /* rc==0 here means that one of the keys ran out of fields and ** all the fields up to that point were equal. Return the default_rc ** value. */ rc = pPKey2->default_rc; debugCompareEnd: if( desiredResult==0 && rc==0 ) return 1; if( desiredResult<0 && rc<0 ) return 1; if( desiredResult>0 && rc>0 ) return 1; if( CORRUPT_DB ) return 1; if( pKeyInfo->db->mallocFailed ) return 1; return 0; } #endif #ifdef SQLITE_DEBUG /* ** Count the number of fields (a.k.a. columns) in the record given by ** pKey,nKey. The verify that this count is less than or equal to the ** limit given by pKeyInfo->nAllField. ** ** If this constraint is not satisfied, it means that the high-speed ** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will ** not work correctly. If this assert() ever fires, it probably means ** that the KeyInfo.nKeyField or KeyInfo.nAllField values were computed ** incorrectly. */ static void vdbeAssertFieldCountWithinLimits( int nKey, const void *pKey, /* The record to verify */ const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */ ){ int nField = 0; u32 szHdr; u32 idx; u32 notUsed; const unsigned char *aKey = (const unsigned char*)pKey; if( CORRUPT_DB ) return; idx = getVarint32(aKey, szHdr); assert( nKey>=0 ); assert( szHdr<=(u32)nKey ); while( idxnAllField ); } #else # define vdbeAssertFieldCountWithinLimits(A,B,C) #endif /* ** Both *pMem1 and *pMem2 contain string values. Compare the two values ** using the collation sequence pColl. As usual, return a negative , zero ** or positive value if *pMem1 is less than, equal to or greater than ** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);". */ static int vdbeCompareMemString( const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl, u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */ ){ if( pMem1->enc==pColl->enc ){ /* The strings are already in the correct encoding. Call the ** comparison function directly */ return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z); }else{ int rc; const void *v1, *v2; Mem c1; Mem c2; sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null); sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null); sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); if( (v1==0 || v2==0) ){ if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT; rc = 0; }else{ rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2); } sqlite3VdbeMemReleaseMalloc(&c1); sqlite3VdbeMemReleaseMalloc(&c2); return rc; } } /* ** The input pBlob is guaranteed to be a Blob that is not marked ** with MEM_Zero. Return true if it could be a zero-blob. */ static int isAllZero(const char *z, int n){ int i; for(i=0; in; int n2 = pB2->n; /* It is possible to have a Blob value that has some non-zero content ** followed by zero content. But that only comes up for Blobs formed ** by the OP_MakeRecord opcode, and such Blobs never get passed into ** sqlite3MemCompare(). */ assert( (pB1->flags & MEM_Zero)==0 || n1==0 ); assert( (pB2->flags & MEM_Zero)==0 || n2==0 ); if( (pB1->flags|pB2->flags) & MEM_Zero ){ if( pB1->flags & pB2->flags & MEM_Zero ){ return pB1->u.nZero - pB2->u.nZero; }else if( pB1->flags & MEM_Zero ){ if( !isAllZero(pB2->z, pB2->n) ) return -1; return pB1->u.nZero - n2; }else{ if( !isAllZero(pB1->z, pB1->n) ) return +1; return n1 - pB2->u.nZero; } } c = memcmp(pB1->z, pB2->z, n1>n2 ? n2 : n1); if( c ) return c; return n1 - n2; } /* The following two functions are used only within testcase() to prove ** test coverage. These functions do no exist for production builds. ** We must use separate SQLITE_NOINLINE functions here, since otherwise ** optimizer code movement causes gcov to become very confused. */ #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) static int SQLITE_NOINLINE doubleLt(double a, double b){ return ar ); testcase( x==r ); return (xr); }else{ i64 y; double s; if( r<-9223372036854775808.0 ) return +1; if( r>=9223372036854775808.0 ) return -1; y = (i64)r; if( iy ) return +1; s = (double)i; testcase( doubleLt(s,r) ); testcase( doubleLt(r,s) ); testcase( doubleEq(r,s) ); return (sr); } } /* ** Compare the values contained by the two memory cells, returning ** negative, zero or positive if pMem1 is less than, equal to, or greater ** than pMem2. Sorting order is NULL's first, followed by numbers (integers ** and reals) sorted numerically, followed by text ordered by the collating ** sequence pColl and finally blob's ordered by memcmp(). ** ** Two NULL values are considered equal by this function. */ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ int f1, f2; int combined_flags; f1 = pMem1->flags; f2 = pMem2->flags; combined_flags = f1|f2; assert( !sqlite3VdbeMemIsRowSet(pMem1) && !sqlite3VdbeMemIsRowSet(pMem2) ); /* If one value is NULL, it is less than the other. If both values ** are NULL, return 0. */ if( combined_flags&MEM_Null ){ return (f2&MEM_Null) - (f1&MEM_Null); } /* At least one of the two values is a number */ if( combined_flags&(MEM_Int|MEM_Real|MEM_IntReal) ){ testcase( combined_flags & MEM_Int ); testcase( combined_flags & MEM_Real ); testcase( combined_flags & MEM_IntReal ); if( (f1 & f2 & (MEM_Int|MEM_IntReal))!=0 ){ testcase( f1 & f2 & MEM_Int ); testcase( f1 & f2 & MEM_IntReal ); if( pMem1->u.i < pMem2->u.i ) return -1; if( pMem1->u.i > pMem2->u.i ) return +1; return 0; } if( (f1 & f2 & MEM_Real)!=0 ){ if( pMem1->u.r < pMem2->u.r ) return -1; if( pMem1->u.r > pMem2->u.r ) return +1; return 0; } if( (f1&(MEM_Int|MEM_IntReal))!=0 ){ testcase( f1 & MEM_Int ); testcase( f1 & MEM_IntReal ); if( (f2&MEM_Real)!=0 ){ return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r); }else if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ if( pMem1->u.i < pMem2->u.i ) return -1; if( pMem1->u.i > pMem2->u.i ) return +1; return 0; }else{ return -1; } } if( (f1&MEM_Real)!=0 ){ if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ testcase( f2 & MEM_Int ); testcase( f2 & MEM_IntReal ); return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r); }else{ return -1; } } return +1; } /* If one value is a string and the other is a blob, the string is less. ** If both are strings, compare using the collating functions. */ if( combined_flags&MEM_Str ){ if( (f1 & MEM_Str)==0 ){ return 1; } if( (f2 & MEM_Str)==0 ){ return -1; } assert( pMem1->enc==pMem2->enc || pMem1->db->mallocFailed ); assert( pMem1->enc==SQLITE_UTF8 || pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE ); /* The collation sequence must be defined at this point, even if ** the user deletes the collation sequence after the vdbe program is ** compiled (this was not always the case). */ assert( !pColl || pColl->xCmp ); if( pColl ){ return vdbeCompareMemString(pMem1, pMem2, pColl, 0); } /* If a NULL pointer was passed as the collate function, fall through ** to the blob case and use memcmp(). */ } /* Both values must be blobs. Compare using memcmp(). */ return sqlite3BlobCompare(pMem1, pMem2); } /* ** The first argument passed to this function is a serial-type that ** corresponds to an integer - all values between 1 and 9 inclusive ** except 7. The second points to a buffer containing an integer value ** serialized according to serial_type. This function deserializes ** and returns the value. */ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ u32 y; assert( CORRUPT_DB || (serial_type>=1 && serial_type<=9 && serial_type!=7) ); switch( serial_type ){ case 0: case 1: testcase( aKey[0]&0x80 ); return ONE_BYTE_INT(aKey); case 2: testcase( aKey[0]&0x80 ); return TWO_BYTE_INT(aKey); case 3: testcase( aKey[0]&0x80 ); return THREE_BYTE_INT(aKey); case 4: { testcase( aKey[0]&0x80 ); y = FOUR_BYTE_UINT(aKey); return (i64)*(int*)&y; } case 5: { testcase( aKey[0]&0x80 ); return FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey); } case 6: { u64 x = FOUR_BYTE_UINT(aKey); testcase( aKey[0]&0x80 ); x = (x<<32) | FOUR_BYTE_UINT(aKey+4); return (i64)*(i64*)&x; } } return (serial_type - 8); } /* ** This function compares the two table rows or index records ** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero ** or positive integer if key1 is less than, equal to or ** greater than key2. The {nKey1, pKey1} key must be a blob ** created by the OP_MakeRecord opcode of the VDBE. The pPKey2 ** key must be a parsed key such as obtained from ** sqlite3VdbeParseRecord. ** ** If argument bSkip is non-zero, it is assumed that the caller has already ** determined that the first fields of the keys are equal. ** ** Key1 and Key2 do not have to contain the same number of fields. If all ** fields that appear in both keys are equal, then pPKey2->default_rc is ** returned. ** ** If database corruption is discovered, set pPKey2->errCode to ** SQLITE_CORRUPT and return 0. If an OOM error is encountered, ** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the ** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db). */ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2, /* Right key */ int bSkip /* If true, skip the first field */ ){ u32 d1; /* Offset into aKey[] of next data element */ int i; /* Index of next field to compare */ u32 szHdr1; /* Size of record header in bytes */ u32 idx1; /* Offset of first type in header */ int rc = 0; /* Return value */ Mem *pRhs = pPKey2->aMem; /* Next field of pPKey2 to compare */ KeyInfo *pKeyInfo; const unsigned char *aKey1 = (const unsigned char *)pKey1; Mem mem1; /* If bSkip is true, then the caller has already determined that the first ** two elements in the keys are equal. Fix the various stack variables so ** that this routine begins comparing at the second field. */ if( bSkip ){ u32 s1 = aKey1[1]; if( s1<0x80 ){ idx1 = 2; }else{ idx1 = 1 + sqlite3GetVarint32(&aKey1[1], &s1); } szHdr1 = aKey1[0]; d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1); i = 1; pRhs++; }else{ if( (szHdr1 = aKey1[0])<0x80 ){ idx1 = 1; }else{ idx1 = sqlite3GetVarint32(aKey1, &szHdr1); } d1 = szHdr1; i = 0; } if( d1>(unsigned)nKey1 ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ } VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); assert( pPKey2->pKeyInfo->aSortFlags!=0 ); assert( pPKey2->pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); while( 1 /*exit-by-break*/ ){ u32 serial_type; /* RHS is an integer */ if( pRhs->flags & (MEM_Int|MEM_IntReal) ){ testcase( pRhs->flags & MEM_Int ); testcase( pRhs->flags & MEM_IntReal ); serial_type = aKey1[idx1]; testcase( serial_type==12 ); if( serial_type>=10 ){ rc = serial_type==10 ? -1 : +1; }else if( serial_type==0 ){ rc = -1; }else if( serial_type==7 ){ sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r); }else{ i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]); i64 rhs = pRhs->u.i; if( lhsrhs ){ rc = +1; } } } /* RHS is real */ else if( pRhs->flags & MEM_Real ){ serial_type = aKey1[idx1]; if( serial_type>=10 ){ /* Serial types 12 or greater are strings and blobs (greater than ** numbers). Types 10 and 11 are currently "reserved for future ** use", so it doesn't really matter what the results of comparing ** them to numeric values are. */ rc = serial_type==10 ? -1 : +1; }else if( serial_type==0 ){ rc = -1; }else{ sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); if( serial_type==7 ){ if( mem1.u.ru.r ){ rc = -1; }else if( mem1.u.r>pRhs->u.r ){ rc = +1; } }else{ rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r); } } } /* RHS is a string */ else if( pRhs->flags & MEM_Str ){ getVarint32NR(&aKey1[idx1], serial_type); testcase( serial_type==12 ); if( serial_type<12 ){ rc = -1; }else if( !(serial_type & 0x01) ){ rc = +1; }else{ mem1.n = (serial_type - 12) / 2; testcase( (d1+mem1.n)==(unsigned)nKey1 ); testcase( (d1+mem1.n+1)==(unsigned)nKey1 ); if( (d1+mem1.n) > (unsigned)nKey1 || (pKeyInfo = pPKey2->pKeyInfo)->nAllField<=i ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ }else if( pKeyInfo->aColl[i] ){ mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; mem1.flags = MEM_Str; mem1.z = (char*)&aKey1[d1]; rc = vdbeCompareMemString( &mem1, pRhs, pKeyInfo->aColl[i], &pPKey2->errCode ); }else{ int nCmp = MIN(mem1.n, pRhs->n); rc = memcmp(&aKey1[d1], pRhs->z, nCmp); if( rc==0 ) rc = mem1.n - pRhs->n; } } } /* RHS is a blob */ else if( pRhs->flags & MEM_Blob ){ assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 ); getVarint32NR(&aKey1[idx1], serial_type); testcase( serial_type==12 ); if( serial_type<12 || (serial_type & 0x01) ){ rc = -1; }else{ int nStr = (serial_type - 12) / 2; testcase( (d1+nStr)==(unsigned)nKey1 ); testcase( (d1+nStr+1)==(unsigned)nKey1 ); if( (d1+nStr) > (unsigned)nKey1 ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ }else if( pRhs->flags & MEM_Zero ){ if( !isAllZero((const char*)&aKey1[d1],nStr) ){ rc = 1; }else{ rc = nStr - pRhs->u.nZero; } }else{ int nCmp = MIN(nStr, pRhs->n); rc = memcmp(&aKey1[d1], pRhs->z, nCmp); if( rc==0 ) rc = nStr - pRhs->n; } } } /* RHS is null */ else{ serial_type = aKey1[idx1]; rc = (serial_type!=0 && serial_type!=10); } if( rc!=0 ){ int sortFlags = pPKey2->pKeyInfo->aSortFlags[i]; if( sortFlags ){ if( (sortFlags & KEYINFO_ORDER_BIGNULL)==0 || ((sortFlags & KEYINFO_ORDER_DESC) !=(serial_type==0 || (pRhs->flags&MEM_Null))) ){ rc = -rc; } } assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) ); assert( mem1.szMalloc==0 ); /* See comment below */ return rc; } i++; if( i==pPKey2->nField ) break; pRhs++; d1 += sqlite3VdbeSerialTypeLen(serial_type); if( d1>(unsigned)nKey1 ) break; idx1 += sqlite3VarintLen(serial_type); if( idx1>=(unsigned)szHdr1 ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corrupt index */ } } /* No memory allocation is ever used on mem1. Prove this using ** the following assert(). If the assert() fails, it indicates a ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ assert( mem1.szMalloc==0 ); /* rc==0 here means that one or both of the keys ran out of fields and ** all the fields up to that point were equal. Return the default_rc ** value. */ assert( CORRUPT_DB || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) || pPKey2->pKeyInfo->db->mallocFailed ); pPKey2->eqSeen = 1; return pPKey2->default_rc; } SQLITE_PRIVATE int sqlite3VdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2 /* Right key */ ){ return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0); } /* ** This function is an optimized version of sqlite3VdbeRecordCompare() ** that (a) the first field of pPKey2 is an integer, and (b) the ** size-of-header varint at the start of (pKey1/nKey1) fits in a single ** byte (i.e. is less than 128). ** ** To avoid concerns about buffer overreads, this routine is only used ** on schemas where the maximum valid header size is 63 bytes or less. */ static int vdbeRecordCompareInt( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2 /* Right key */ ){ const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F]; int serial_type = ((const u8*)pKey1)[1]; int res; u32 y; u64 x; i64 v; i64 lhs; vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB ); switch( serial_type ){ case 1: { /* 1-byte signed integer */ lhs = ONE_BYTE_INT(aKey); testcase( lhs<0 ); break; } case 2: { /* 2-byte signed integer */ lhs = TWO_BYTE_INT(aKey); testcase( lhs<0 ); break; } case 3: { /* 3-byte signed integer */ lhs = THREE_BYTE_INT(aKey); testcase( lhs<0 ); break; } case 4: { /* 4-byte signed integer */ y = FOUR_BYTE_UINT(aKey); lhs = (i64)*(int*)&y; testcase( lhs<0 ); break; } case 5: { /* 6-byte signed integer */ lhs = FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey); testcase( lhs<0 ); break; } case 6: { /* 8-byte signed integer */ x = FOUR_BYTE_UINT(aKey); x = (x<<32) | FOUR_BYTE_UINT(aKey+4); lhs = *(i64*)&x; testcase( lhs<0 ); break; } case 8: lhs = 0; break; case 9: lhs = 1; break; /* This case could be removed without changing the results of running ** this code. Including it causes gcc to generate a faster switch ** statement (since the range of switch targets now starts at zero and ** is contiguous) but does not cause any duplicate code to be generated ** (as gcc is clever enough to combine the two like cases). Other ** compilers might be similar. */ case 0: case 7: return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); default: return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); } assert( pPKey2->u.i == pPKey2->aMem[0].u.i ); v = pPKey2->u.i; if( v>lhs ){ res = pPKey2->r1; }else if( vr2; }else if( pPKey2->nField>1 ){ /* The first fields of the two keys are equal. Compare the trailing ** fields. */ res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); }else{ /* The first fields of the two keys are equal and there are no trailing ** fields. Return pPKey2->default_rc in this case. */ res = pPKey2->default_rc; pPKey2->eqSeen = 1; } assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) ); return res; } /* ** This function is an optimized version of sqlite3VdbeRecordCompare() ** that (a) the first field of pPKey2 is a string, that (b) the first field ** uses the collation sequence BINARY and (c) that the size-of-header varint ** at the start of (pKey1/nKey1) fits in a single byte. */ static int vdbeRecordCompareString( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2 /* Right key */ ){ const u8 *aKey1 = (const u8*)pKey1; int serial_type; int res; assert( pPKey2->aMem[0].flags & MEM_Str ); assert( pPKey2->aMem[0].n == pPKey2->n ); assert( pPKey2->aMem[0].z == pPKey2->u.z ); vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); serial_type = (signed char)(aKey1[1]); vrcs_restart: if( serial_type<12 ){ if( serial_type<0 ){ sqlite3GetVarint32(&aKey1[1], (u32*)&serial_type); if( serial_type>=12 ) goto vrcs_restart; assert( CORRUPT_DB ); } res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */ }else if( !(serial_type & 0x01) ){ res = pPKey2->r2; /* (pKey1/nKey1) is a blob */ }else{ int nCmp; int nStr; int szHdr = aKey1[0]; nStr = (serial_type-12) / 2; if( (szHdr + nStr) > nKey1 ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ } nCmp = MIN( pPKey2->n, nStr ); res = memcmp(&aKey1[szHdr], pPKey2->u.z, nCmp); if( res>0 ){ res = pPKey2->r2; }else if( res<0 ){ res = pPKey2->r1; }else{ res = nStr - pPKey2->n; if( res==0 ){ if( pPKey2->nField>1 ){ res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); }else{ res = pPKey2->default_rc; pPKey2->eqSeen = 1; } }else if( res>0 ){ res = pPKey2->r2; }else{ res = pPKey2->r1; } } } assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) || CORRUPT_DB || pPKey2->pKeyInfo->db->mallocFailed ); return res; } /* ** Return a pointer to an sqlite3VdbeRecordCompare() compatible function ** suitable for comparing serialized records to the unpacked record passed ** as the only argument. */ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ /* varintRecordCompareInt() and varintRecordCompareString() both assume ** that the size-of-header varint that occurs at the start of each record ** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt() ** also assumes that it is safe to overread a buffer by at least the ** maximum possible legal header size plus 8 bytes. Because there is ** guaranteed to be at least 74 (but not 136) bytes of padding following each ** buffer passed to varintRecordCompareInt() this makes it convenient to ** limit the size of the header to 64 bytes in cases where the first field ** is an integer. ** ** The easiest way to enforce this limit is to consider only records with ** 13 fields or less. If the first field is an integer, the maximum legal ** header size is (12*5 + 1 + 1) bytes. */ if( p->pKeyInfo->nAllField<=13 ){ int flags = p->aMem[0].flags; if( p->pKeyInfo->aSortFlags[0] ){ if( p->pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL ){ return sqlite3VdbeRecordCompare; } p->r1 = 1; p->r2 = -1; }else{ p->r1 = -1; p->r2 = 1; } if( (flags & MEM_Int) ){ p->u.i = p->aMem[0].u.i; return vdbeRecordCompareInt; } testcase( flags & MEM_Real ); testcase( flags & MEM_Null ); testcase( flags & MEM_Blob ); if( (flags & (MEM_Real|MEM_IntReal|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){ assert( flags & MEM_Str ); p->u.z = p->aMem[0].z; p->n = p->aMem[0].n; return vdbeRecordCompareString; } } return sqlite3VdbeRecordCompare; } /* ** pCur points at an index entry created using the OP_MakeRecord opcode. ** Read the rowid (the last field in the record) and store it in *rowid. ** Return SQLITE_OK if everything works, or an error code otherwise. ** ** pCur might be pointing to text obtained from a corrupt database file. ** So the content cannot be trusted. Do appropriate checks on the content. */ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ i64 nCellKey = 0; int rc; u32 szHdr; /* Size of the header */ u32 typeRowid; /* Serial type of the rowid */ u32 lenRowid; /* Size of the rowid */ Mem m, v; /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so ** this code can safely assume that nCellKey is 32-bits */ assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); /* Read in the complete content of the index entry */ sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m); if( rc ){ return rc; } /* The index entry must begin with a header size */ getVarint32NR((u8*)m.z, szHdr); testcase( szHdr==3 ); testcase( szHdr==(u32)m.n ); testcase( szHdr>0x7fffffff ); assert( m.n>=0 ); if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){ goto idx_rowid_corruption; } /* The last field of the index should be an integer - the ROWID. ** Verify that the last entry really is an integer. */ getVarint32NR((u8*)&m.z[szHdr-1], typeRowid); testcase( typeRowid==1 ); testcase( typeRowid==2 ); testcase( typeRowid==3 ); testcase( typeRowid==4 ); testcase( typeRowid==5 ); testcase( typeRowid==6 ); testcase( typeRowid==8 ); testcase( typeRowid==9 ); if( unlikely(typeRowid<1 || typeRowid>9 || typeRowid==7) ){ goto idx_rowid_corruption; } lenRowid = sqlite3SmallTypeSizes[typeRowid]; testcase( (u32)m.n==szHdr+lenRowid ); if( unlikely((u32)m.neCurType==CURTYPE_BTREE ); pCur = pC->uc.pCursor; assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); /* nCellKey will always be between 0 and 0xffffffff because of the way ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ *res = 0; return SQLITE_CORRUPT_BKPT; } sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m); if( rc ){ return rc; } *res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, pUnpacked, 0); sqlite3VdbeMemReleaseMalloc(&m); return SQLITE_OK; } /* ** This routine sets the value to be returned by subsequent calls to ** sqlite3_changes() on the database handle 'db'. */ SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, i64 nChange){ assert( sqlite3_mutex_held(db->mutex) ); db->nChange = nChange; db->nTotalChange += nChange; } /* ** Set a flag in the vdbe to update the change counter when it is finalised ** or reset. */ SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){ v->changeCntOn = 1; } /* ** Mark every prepared statement associated with a database connection ** as expired. ** ** An expired statement means that recompilation of the statement is ** recommend. Statements expire when things happen that make their ** programs obsolete. Removing user-defined functions or collating ** sequences, or changing an authorization function are the types of ** things that make prepared statements obsolete. ** ** If iCode is 1, then expiration is advisory. The statement should ** be reprepared before being restarted, but if it is already running ** it is allowed to run to completion. ** ** Internally, this function just sets the Vdbe.expired flag on all ** prepared statements. The flag is set to 1 for an immediate expiration ** and set to 2 for an advisory expiration. */ SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){ Vdbe *p; for(p = db->pVdbe; p; p=p->pVNext){ p->expired = iCode+1; } } /* ** Return the database associated with the Vdbe. */ SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){ return v->db; } /* ** Return the SQLITE_PREPARE flags for a Vdbe. */ SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe *v){ return v->prepFlags; } /* ** Return a pointer to an sqlite3_value structure containing the value bound ** parameter iVar of VM v. Except, if the value is an SQL NULL, return ** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_* ** constants) to the value before returning it. ** ** The returned value must be freed by the caller using sqlite3ValueFree(). */ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){ assert( iVar>0 ); if( v ){ Mem *pMem = &v->aVar[iVar-1]; assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); if( 0==(pMem->flags & MEM_Null) ){ sqlite3_value *pRet = sqlite3ValueNew(v->db); if( pRet ){ sqlite3VdbeMemCopy((Mem *)pRet, pMem); sqlite3ValueApplyAffinity(pRet, aff, SQLITE_UTF8); } return pRet; } } return 0; } /* ** Configure SQL variable iVar so that binding a new value to it signals ** to sqlite3_reoptimize() that re-preparing the statement may result ** in a better query plan. */ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ assert( iVar>0 ); assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); if( iVar>=32 ){ v->expmask |= 0x80000000; }else{ v->expmask |= ((u32)1 << (iVar-1)); } } /* ** Cause a function to throw an error if it was call from OP_PureFunc ** rather than OP_Function. ** ** OP_PureFunc means that the function must be deterministic, and should ** throw an error if it is given inputs that would make it non-deterministic. ** This routine is invoked by date/time functions that use non-deterministic ** features such as 'now'. */ SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context *pCtx){ const VdbeOp *pOp; #ifdef SQLITE_ENABLE_STAT4 if( pCtx->pVdbe==0 ) return 1; #endif pOp = pCtx->pVdbe->aOp + pCtx->iOp; if( pOp->opcode==OP_PureFunc ){ const char *zContext; char *zMsg; if( pOp->p5 & NC_IsCheck ){ zContext = "a CHECK constraint"; }else if( pOp->p5 & NC_GenCol ){ zContext = "a generated column"; }else{ zContext = "an index"; } zMsg = sqlite3_mprintf("non-deterministic use of %s() in %s", pCtx->pFunc->zName, zContext); sqlite3_result_error(pCtx, zMsg, -1); sqlite3_free(zMsg); return 0; } return 1; } #if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) /* ** This Walker callback is used to help verify that calls to ** sqlite3BtreeCursorHint() with opcode BTREE_HINT_RANGE have ** byte-code register values correctly initialized. */ SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_REGISTER ){ assert( (pWalker->u.aMem[pExpr->iTable].flags & MEM_Undefined)==0 ); } return WRC_Continue; } #endif /* SQLITE_ENABLE_CURSOR_HINTS && SQLITE_DEBUG */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored ** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored ** in memory obtained from sqlite3DbMalloc). */ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){ if( pVtab->zErrMsg ){ sqlite3 *db = p->db; sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg); sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = 0; } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** If the second argument is not NULL, release any allocations associated ** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord ** structure itself, using sqlite3DbFree(). ** ** This function is used to free UnpackedRecord structures allocated by ** the vdbeUnpackRecord() function found in vdbeapi.c. */ static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){ assert( db!=0 ); if( p ){ int i; for(i=0; iaMem[i]; if( pMem->zMalloc ) sqlite3VdbeMemReleaseMalloc(pMem); } sqlite3DbNNFreeNN(db, p); } } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call, ** then cursor passed as the second argument should point to the row about ** to be update or deleted. If the application calls sqlite3_preupdate_old(), ** the required value will be read from the row the cursor points to. */ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( Vdbe *v, /* Vdbe pre-update hook is invoked by */ VdbeCursor *pCsr, /* Cursor to grab old.* values from */ int op, /* SQLITE_INSERT, UPDATE or DELETE */ const char *zDb, /* Database name */ Table *pTab, /* Modified table */ i64 iKey1, /* Initial key value */ int iReg, /* Register for new.* record */ int iBlobWrite ){ sqlite3 *db = v->db; i64 iKey2; PreUpdate preupdate; const char *zTbl = pTab->zName; static const u8 fakeSortOrder = 0; #ifdef SQLITE_DEBUG int nRealCol; if( pTab->tabFlags & TF_WithoutRowid ){ nRealCol = sqlite3PrimaryKeyIndex(pTab)->nColumn; }else if( pTab->tabFlags & TF_HasVirtual ){ nRealCol = pTab->nNVCol; }else{ nRealCol = pTab->nCol; } #endif assert( db->pPreUpdate==0 ); memset(&preupdate, 0, sizeof(PreUpdate)); if( HasRowid(pTab)==0 ){ iKey1 = iKey2 = 0; preupdate.pPk = sqlite3PrimaryKeyIndex(pTab); }else{ if( op==SQLITE_UPDATE ){ iKey2 = v->aMem[iReg].u.i; }else{ iKey2 = iKey1; } } assert( pCsr!=0 ); assert( pCsr->eCurType==CURTYPE_BTREE ); assert( pCsr->nField==nRealCol || (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1) ); preupdate.v = v; preupdate.pCsr = pCsr; preupdate.op = op; preupdate.iNewReg = iReg; preupdate.keyinfo.db = db; preupdate.keyinfo.enc = ENC(db); preupdate.keyinfo.nKeyField = pTab->nCol; preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder; preupdate.iKey1 = iKey1; preupdate.iKey2 = iKey2; preupdate.pTab = pTab; preupdate.iBlobWrite = iBlobWrite; db->pPreUpdate = &preupdate; db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2); db->pPreUpdate = 0; sqlite3DbFree(db, preupdate.aRecord); vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked); vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked); if( preupdate.aNew ){ int i; for(i=0; inField; i++){ sqlite3VdbeMemRelease(&preupdate.aNew[i]); } sqlite3DbNNFreeNN(db, preupdate.aNew); } } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ /************** End of vdbeaux.c *********************************************/ /************** Begin file vdbeapi.c *****************************************/ /* ** 2004 May 26 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code use to implement APIs that are part of the ** VDBE. */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ /* #include "opcodes.h" */ #ifndef SQLITE_OMIT_DEPRECATED /* ** Return TRUE (non-zero) of the statement supplied as an argument needs ** to be recompiled. A statement needs to be recompiled whenever the ** execution environment changes in a way that would alter the program ** that sqlite3_prepare() generates. For example, if new functions or ** collating sequences are registered or if an authorizer function is ** added or changed. */ SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; return p==0 || p->expired; } #endif /* ** Check on a Vdbe to make sure it has not been finalized. Log ** an error and return true if it has been finalized (or is otherwise ** invalid). Return false if it is ok. */ static int vdbeSafety(Vdbe *p){ if( p->db==0 ){ sqlite3_log(SQLITE_MISUSE, "API called with finalized prepared statement"); return 1; }else{ return 0; } } static int vdbeSafetyNotNull(Vdbe *p){ if( p==0 ){ sqlite3_log(SQLITE_MISUSE, "API called with NULL prepared statement"); return 1; }else{ return vdbeSafety(p); } } #ifndef SQLITE_OMIT_TRACE /* ** Invoke the profile callback. This routine is only called if we already ** know that the profile callback is defined and needs to be invoked. */ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ sqlite3_int64 iNow; sqlite3_int64 iElapse; assert( p->startTime>0 ); assert( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 ); assert( db->init.busy==0 ); assert( p->zSql!=0 ); sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); iElapse = (iNow - p->startTime)*1000000; #ifndef SQLITE_OMIT_DEPRECATED if( db->xProfile ){ db->xProfile(db->pProfileArg, p->zSql, iElapse); } #endif if( db->mTrace & SQLITE_TRACE_PROFILE ){ db->trace.xV2(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse); } p->startTime = 0; } /* ** The checkProfileCallback(DB,P) macro checks to see if a profile callback ** is needed, and it invokes the callback if it is needed. */ # define checkProfileCallback(DB,P) \ if( ((P)->startTime)>0 ){ invokeProfileCallback(DB,P); } #else # define checkProfileCallback(DB,P) /*no-op*/ #endif /* ** The following routine destroys a virtual machine that is created by ** the sqlite3_compile() routine. The integer returned is an SQLITE_ ** success/failure code that describes the result of executing the virtual ** machine. ** ** This routine sets the error code and string returned by ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16(). */ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){ int rc; if( pStmt==0 ){ /* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL ** pointer is a harmless no-op. */ rc = SQLITE_OK; }else{ Vdbe *v = (Vdbe*)pStmt; sqlite3 *db = v->db; if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT; sqlite3_mutex_enter(db->mutex); checkProfileCallback(db, v); assert( v->eVdbeState>=VDBE_READY_STATE ); rc = sqlite3VdbeReset(v); sqlite3VdbeDelete(v); rc = sqlite3ApiExit(db, rc); sqlite3LeaveMutexAndCloseZombie(db); } return rc; } /* ** Terminate the current execution of an SQL statement and reset it ** back to its starting state so that it can be reused. A success code from ** the prior execution is returned. ** ** This routine sets the error code and string returned by ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16(). */ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){ int rc; if( pStmt==0 ){ rc = SQLITE_OK; }else{ Vdbe *v = (Vdbe*)pStmt; sqlite3 *db = v->db; sqlite3_mutex_enter(db->mutex); checkProfileCallback(db, v); rc = sqlite3VdbeReset(v); sqlite3VdbeRewind(v); assert( (rc & (db->errMask))==rc ); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); } return rc; } /* ** Set all the parameters in the compiled SQL statement to NULL. */ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ int i; int rc = SQLITE_OK; Vdbe *p = (Vdbe*)pStmt; #if SQLITE_THREADSAFE sqlite3_mutex *mutex; #endif #ifdef SQLITE_ENABLE_API_ARMOR if( pStmt==0 ){ return SQLITE_MISUSE_BKPT; } #endif #if SQLITE_THREADSAFE mutex = p->db->mutex; #endif sqlite3_mutex_enter(mutex); for(i=0; inVar; i++){ sqlite3VdbeMemRelease(&p->aVar[i]); p->aVar[i].flags = MEM_Null; } assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 ); if( p->expmask ){ p->expired = 1; } sqlite3_mutex_leave(mutex); return rc; } /**************************** sqlite3_value_ ******************************* ** The following routines extract information from a Mem or sqlite3_value ** structure. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){ Mem *p = (Mem*)pVal; if( p->flags & (MEM_Blob|MEM_Str) ){ if( ExpandBlob(p)!=SQLITE_OK ){ assert( p->flags==MEM_Null && p->z==0 ); return 0; } p->flags |= MEM_Blob; return p->n ? p->z : 0; }else{ return sqlite3_value_text(pVal); } } SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){ return sqlite3ValueBytes(pVal, SQLITE_UTF8); } SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){ return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE); } SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){ return sqlite3VdbeRealValue((Mem*)pVal); } SQLITE_API int sqlite3_value_int(sqlite3_value *pVal){ return (int)sqlite3VdbeIntValue((Mem*)pVal); } SQLITE_API sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){ return sqlite3VdbeIntValue((Mem*)pVal); } SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value *pVal){ Mem *pMem = (Mem*)pVal; return ((pMem->flags & MEM_Subtype) ? pMem->eSubtype : 0); } SQLITE_API void *sqlite3_value_pointer(sqlite3_value *pVal, const char *zPType){ Mem *p = (Mem*)pVal; if( (p->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) == (MEM_Null|MEM_Term|MEM_Subtype) && zPType!=0 && p->eSubtype=='p' && strcmp(p->u.zPType, zPType)==0 ){ return (void*)p->z; }else{ return 0; } } SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){ return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_value_text16(sqlite3_value* pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); } SQLITE_API const void *sqlite3_value_text16be(sqlite3_value *pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16BE); } SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16LE); } #endif /* SQLITE_OMIT_UTF16 */ /* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five ** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating ** point number string BLOB NULL */ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ static const u8 aType[] = { SQLITE_BLOB, /* 0x00 (not possible) */ SQLITE_NULL, /* 0x01 NULL */ SQLITE_TEXT, /* 0x02 TEXT */ SQLITE_NULL, /* 0x03 (not possible) */ SQLITE_INTEGER, /* 0x04 INTEGER */ SQLITE_NULL, /* 0x05 (not possible) */ SQLITE_INTEGER, /* 0x06 INTEGER + TEXT */ SQLITE_NULL, /* 0x07 (not possible) */ SQLITE_FLOAT, /* 0x08 FLOAT */ SQLITE_NULL, /* 0x09 (not possible) */ SQLITE_FLOAT, /* 0x0a FLOAT + TEXT */ SQLITE_NULL, /* 0x0b (not possible) */ SQLITE_INTEGER, /* 0x0c (not possible) */ SQLITE_NULL, /* 0x0d (not possible) */ SQLITE_INTEGER, /* 0x0e (not possible) */ SQLITE_NULL, /* 0x0f (not possible) */ SQLITE_BLOB, /* 0x10 BLOB */ SQLITE_NULL, /* 0x11 (not possible) */ SQLITE_TEXT, /* 0x12 (not possible) */ SQLITE_NULL, /* 0x13 (not possible) */ SQLITE_INTEGER, /* 0x14 INTEGER + BLOB */ SQLITE_NULL, /* 0x15 (not possible) */ SQLITE_INTEGER, /* 0x16 (not possible) */ SQLITE_NULL, /* 0x17 (not possible) */ SQLITE_FLOAT, /* 0x18 FLOAT + BLOB */ SQLITE_NULL, /* 0x19 (not possible) */ SQLITE_FLOAT, /* 0x1a (not possible) */ SQLITE_NULL, /* 0x1b (not possible) */ SQLITE_INTEGER, /* 0x1c (not possible) */ SQLITE_NULL, /* 0x1d (not possible) */ SQLITE_INTEGER, /* 0x1e (not possible) */ SQLITE_NULL, /* 0x1f (not possible) */ SQLITE_FLOAT, /* 0x20 INTREAL */ SQLITE_NULL, /* 0x21 (not possible) */ SQLITE_FLOAT, /* 0x22 INTREAL + TEXT */ SQLITE_NULL, /* 0x23 (not possible) */ SQLITE_FLOAT, /* 0x24 (not possible) */ SQLITE_NULL, /* 0x25 (not possible) */ SQLITE_FLOAT, /* 0x26 (not possible) */ SQLITE_NULL, /* 0x27 (not possible) */ SQLITE_FLOAT, /* 0x28 (not possible) */ SQLITE_NULL, /* 0x29 (not possible) */ SQLITE_FLOAT, /* 0x2a (not possible) */ SQLITE_NULL, /* 0x2b (not possible) */ SQLITE_FLOAT, /* 0x2c (not possible) */ SQLITE_NULL, /* 0x2d (not possible) */ SQLITE_FLOAT, /* 0x2e (not possible) */ SQLITE_NULL, /* 0x2f (not possible) */ SQLITE_BLOB, /* 0x30 (not possible) */ SQLITE_NULL, /* 0x31 (not possible) */ SQLITE_TEXT, /* 0x32 (not possible) */ SQLITE_NULL, /* 0x33 (not possible) */ SQLITE_FLOAT, /* 0x34 (not possible) */ SQLITE_NULL, /* 0x35 (not possible) */ SQLITE_FLOAT, /* 0x36 (not possible) */ SQLITE_NULL, /* 0x37 (not possible) */ SQLITE_FLOAT, /* 0x38 (not possible) */ SQLITE_NULL, /* 0x39 (not possible) */ SQLITE_FLOAT, /* 0x3a (not possible) */ SQLITE_NULL, /* 0x3b (not possible) */ SQLITE_FLOAT, /* 0x3c (not possible) */ SQLITE_NULL, /* 0x3d (not possible) */ SQLITE_FLOAT, /* 0x3e (not possible) */ SQLITE_NULL, /* 0x3f (not possible) */ }; #ifdef SQLITE_DEBUG { int eType = SQLITE_BLOB; if( pVal->flags & MEM_Null ){ eType = SQLITE_NULL; }else if( pVal->flags & (MEM_Real|MEM_IntReal) ){ eType = SQLITE_FLOAT; }else if( pVal->flags & MEM_Int ){ eType = SQLITE_INTEGER; }else if( pVal->flags & MEM_Str ){ eType = SQLITE_TEXT; } assert( eType == aType[pVal->flags&MEM_AffMask] ); } #endif return aType[pVal->flags&MEM_AffMask]; } SQLITE_API int sqlite3_value_encoding(sqlite3_value *pVal){ return pVal->enc; } /* Return true if a parameter to xUpdate represents an unchanged column */ SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){ return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero); } /* Return true if a parameter value originated from an sqlite3_bind() */ SQLITE_API int sqlite3_value_frombind(sqlite3_value *pVal){ return (pVal->flags&MEM_FromBind)!=0; } /* Make a copy of an sqlite3_value object */ SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){ sqlite3_value *pNew; if( pOrig==0 ) return 0; pNew = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return 0; memset(pNew, 0, sizeof(*pNew)); memcpy(pNew, pOrig, MEMCELLSIZE); pNew->flags &= ~MEM_Dyn; pNew->db = 0; if( pNew->flags&(MEM_Str|MEM_Blob) ){ pNew->flags &= ~(MEM_Static|MEM_Dyn); pNew->flags |= MEM_Ephem; if( sqlite3VdbeMemMakeWriteable(pNew)!=SQLITE_OK ){ sqlite3ValueFree(pNew); pNew = 0; } }else if( pNew->flags & MEM_Null ){ /* Do not duplicate pointer values */ pNew->flags &= ~(MEM_Term|MEM_Subtype); } return pNew; } /* Destroy an sqlite3_value object previously obtained from ** sqlite3_value_dup(). */ SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){ sqlite3ValueFree(pOld); } /**************************** sqlite3_result_ ******************************* ** The following routines are used by user-defined functions to specify ** the function result. ** ** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the ** result as a string or blob. Appropriate errors are set if the string/blob ** is too big or if an OOM occurs. ** ** The invokeValueDestructor(P,X) routine invokes destructor function X() ** on value P if P is not going to be used and need to be destroyed. */ static void setResultStrOrError( sqlite3_context *pCtx, /* Function context */ const char *z, /* String pointer */ int n, /* Bytes in string, or negative */ u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ Mem *pOut = pCtx->pOut; int rc = sqlite3VdbeMemSetStr(pOut, z, n, enc, xDel); if( rc ){ if( rc==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(pCtx); }else{ /* The only errors possible from sqlite3VdbeMemSetStr are ** SQLITE_TOOBIG and SQLITE_NOMEM */ assert( rc==SQLITE_NOMEM ); sqlite3_result_error_nomem(pCtx); } return; } sqlite3VdbeChangeEncoding(pOut, pCtx->enc); if( sqlite3VdbeMemTooBig(pOut) ){ sqlite3_result_error_toobig(pCtx); } } static int invokeValueDestructor( const void *p, /* Value to destroy */ void (*xDel)(void*), /* The destructor */ sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if not NULL */ ){ assert( xDel!=SQLITE_DYNAMIC ); if( xDel==0 ){ /* noop */ }else if( xDel==SQLITE_TRANSIENT ){ /* noop */ }else{ xDel((void*)p); } #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx!=0 ){ sqlite3_result_error_toobig(pCtx); } #else assert( pCtx!=0 ); sqlite3_result_error_toobig(pCtx); #endif return SQLITE_TOOBIG; } SQLITE_API void sqlite3_result_blob( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) ){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 || n<0 ){ invokeValueDestructor(z, xDel, pCtx); return; } #endif assert( n>=0 ); assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, 0, xDel); } SQLITE_API void sqlite3_result_blob64( sqlite3_context *pCtx, const void *z, sqlite3_uint64 n, void (*xDel)(void *) ){ assert( xDel!=SQLITE_DYNAMIC ); #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ){ invokeValueDestructor(z, xDel, 0); return; } #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); if( n>0x7fffffff ){ (void)invokeValueDestructor(z, xDel, pCtx); }else{ setResultStrOrError(pCtx, z, (int)n, 0, xDel); } } SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetDouble(pCtx->pOut, rVal); } SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); } #endif SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal); } SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetInt64(pCtx->pOut, iVal); } SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); } SQLITE_API void sqlite3_result_pointer( sqlite3_context *pCtx, void *pPtr, const char *zPType, void (*xDestructor)(void*) ){ Mem *pOut; #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ){ invokeValueDestructor(pPtr, xDestructor, 0); return; } #endif pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); sqlite3VdbeMemRelease(pOut); pOut->flags = MEM_Null; sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor); } SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ Mem *pOut; #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif #if defined(SQLITE_STRICT_SUBTYPE) && SQLITE_STRICT_SUBTYPE+0!=0 if( pCtx->pFunc!=0 && (pCtx->pFunc->funcFlags & SQLITE_RESULT_SUBTYPE)==0 ){ char zErr[200]; sqlite3_snprintf(sizeof(zErr), zErr, "misuse of sqlite3_result_subtype() by %s()", pCtx->pFunc->zName); sqlite3_result_error(pCtx, zErr, -1); return; } #endif /* SQLITE_STRICT_SUBTYPE */ pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); pOut->eSubtype = eSubtype & 0xff; pOut->flags |= MEM_Subtype; } SQLITE_API void sqlite3_result_text( sqlite3_context *pCtx, const char *z, int n, void (*xDel)(void *) ){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ){ invokeValueDestructor(z, xDel, 0); return; } #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel); } SQLITE_API void sqlite3_result_text64( sqlite3_context *pCtx, const char *z, sqlite3_uint64 n, void (*xDel)(void *), unsigned char enc ){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ){ invokeValueDestructor(z, xDel, 0); return; } #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); if( enc!=SQLITE_UTF8 ){ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; n &= ~(u64)1; } if( n>0x7fffffff ){ (void)invokeValueDestructor(z, xDel, pCtx); }else{ setResultStrOrError(pCtx, z, (int)n, enc, xDel); sqlite3VdbeMemZeroTerminateIfAble(pCtx->pOut); } } #ifndef SQLITE_OMIT_UTF16 SQLITE_API void sqlite3_result_text16( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16NATIVE, xDel); } SQLITE_API void sqlite3_result_text16be( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16BE, xDel); } SQLITE_API void sqlite3_result_text16le( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16LE, xDel); } #endif /* SQLITE_OMIT_UTF16 */ SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ Mem *pOut; #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; if( pValue==0 ){ sqlite3_result_null(pCtx); return; } #endif pOut = pCtx->pOut; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemCopy(pOut, pValue); sqlite3VdbeChangeEncoding(pOut, pCtx->enc); if( sqlite3VdbeMemTooBig(pOut) ){ sqlite3_result_error_toobig(pCtx); } } SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ sqlite3_result_zeroblob64(pCtx, n>0 ? n : 0); } SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ Mem *pOut; #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return SQLITE_MISUSE_BKPT; #endif pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(pCtx); return SQLITE_TOOBIG; } #ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); return SQLITE_OK; #else return sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); #endif } SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif pCtx->isError = errCode ? errCode : -1; #ifdef SQLITE_DEBUG if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode; #endif if( pCtx->pOut->flags & MEM_Null ){ setResultStrOrError(pCtx, sqlite3ErrStr(errCode), -1, SQLITE_UTF8, SQLITE_STATIC); } } /* Force an SQLITE_TOOBIG error. */ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_TOOBIG; sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, SQLITE_UTF8, SQLITE_STATIC); } /* An SQLITE_NOMEM error. */ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); pCtx->isError = SQLITE_NOMEM_BKPT; sqlite3OomFault(pCtx->pOut->db); } #ifndef SQLITE_UNTESTABLE /* Force the INT64 value currently stored as the result to be ** a MEM_IntReal value. See the SQLITE_TESTCTRL_RESULT_INTREAL ** test-control. */ SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); if( pCtx->pOut->flags & MEM_Int ){ pCtx->pOut->flags &= ~MEM_Int; pCtx->pOut->flags |= MEM_IntReal; } } #endif /* ** This function is called after a transaction has been committed. It ** invokes callbacks registered with sqlite3_wal_hook() as required. */ static int doWalCallbacks(sqlite3 *db){ int rc = SQLITE_OK; #ifndef SQLITE_OMIT_WAL int i; for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ int nEntry; sqlite3BtreeEnter(pBt); nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry); } } } #endif return rc; } /* ** Execute the statement pStmt, either until a row of data is ready, the ** statement is completely executed or an error occurs. ** ** This routine implements the bulk of the logic behind the sqlite_step() ** API. The only thing omitted is the automatic recompile if a ** schema change has occurred. That detail is handled by the ** outer sqlite3_step() wrapper procedure. */ static int sqlite3Step(Vdbe *p){ sqlite3 *db; int rc; assert(p); db = p->db; if( p->eVdbeState!=VDBE_RUN_STATE ){ restart_step: if( p->eVdbeState==VDBE_READY_STATE ){ if( p->expired ){ p->rc = SQLITE_SCHEMA; rc = SQLITE_ERROR; if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){ /* If this statement was prepared using saved SQL and an ** error has occurred, then return the error code in p->rc to the ** caller. Set the error code in the database handle to the same ** value. */ rc = sqlite3VdbeTransferError(p); } goto end_of_step; } /* If there are no other statements currently running, then ** reset the interrupt flag. This prevents a call to sqlite3_interrupt ** from interrupting a statement that has not yet started. */ if( db->nVdbeActive==0 ){ AtomicStore(&db->u1.isInterrupted, 0); } assert( db->nVdbeWrite>0 || db->autoCommit==0 || (db->nDeferredCons==0 && db->nDeferredImmCons==0) ); #ifndef SQLITE_OMIT_TRACE if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 && !db->init.busy && p->zSql ){ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); }else{ assert( p->startTime==0 ); } #endif db->nVdbeActive++; if( p->readOnly==0 ) db->nVdbeWrite++; if( p->bIsReader ) db->nVdbeRead++; p->pc = 0; p->eVdbeState = VDBE_RUN_STATE; }else if( ALWAYS(p->eVdbeState==VDBE_HALT_STATE) ){ /* We used to require that sqlite3_reset() be called before retrying ** sqlite3_step() after any error or after SQLITE_DONE. But beginning ** with version 3.7.0, we changed this so that sqlite3_reset() would ** be called automatically instead of throwing the SQLITE_MISUSE error. ** This "automatic-reset" change is not technically an incompatibility, ** since any application that receives an SQLITE_MISUSE is broken by ** definition. ** ** Nevertheless, some published applications that were originally written ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE ** returns, and those were broken by the automatic-reset change. As a ** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the ** legacy behavior of returning SQLITE_MISUSE for cases where the ** previous sqlite3_step() returned something other than a SQLITE_LOCKED ** or SQLITE_BUSY error. */ #ifdef SQLITE_OMIT_AUTORESET if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){ sqlite3_reset((sqlite3_stmt*)p); }else{ return SQLITE_MISUSE_BKPT; } #else sqlite3_reset((sqlite3_stmt*)p); #endif assert( p->eVdbeState==VDBE_READY_STATE ); goto restart_step; } } #ifdef SQLITE_DEBUG p->rcApp = SQLITE_OK; #endif #ifndef SQLITE_OMIT_EXPLAIN if( p->explain ){ rc = sqlite3VdbeList(p); }else #endif /* SQLITE_OMIT_EXPLAIN */ { db->nVdbeExec++; rc = sqlite3VdbeExec(p); db->nVdbeExec--; } if( rc==SQLITE_ROW ){ assert( p->rc==SQLITE_OK ); assert( db->mallocFailed==0 ); db->errCode = SQLITE_ROW; return SQLITE_ROW; }else{ #ifndef SQLITE_OMIT_TRACE /* If the statement completed successfully, invoke the profile callback */ checkProfileCallback(db, p); #endif p->pResultRow = 0; if( rc==SQLITE_DONE && db->autoCommit ){ assert( p->rc==SQLITE_OK ); p->rc = doWalCallbacks(db); if( p->rc!=SQLITE_OK ){ rc = SQLITE_ERROR; } }else if( rc!=SQLITE_DONE && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){ /* If this statement was prepared using saved SQL and an ** error has occurred, then return the error code in p->rc to the ** caller. Set the error code in the database handle to the same value. */ rc = sqlite3VdbeTransferError(p); } } db->errCode = rc; if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){ p->rc = SQLITE_NOMEM_BKPT; if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ) rc = p->rc; } end_of_step: /* There are only a limited number of result codes allowed from the ** statements prepared using the legacy sqlite3_prepare() interface */ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE ); return (rc&db->errMask); } /* ** This is the top-level implementation of sqlite3_step(). Call ** sqlite3Step() to do most of the work. If a schema error occurs, ** call sqlite3Reprepare() and try again. */ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ int rc = SQLITE_OK; /* Result from sqlite3Step() */ Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */ int cnt = 0; /* Counter to prevent infinite loop of reprepares */ sqlite3 *db; /* The database connection */ if( vdbeSafetyNotNull(v) ){ return SQLITE_MISUSE_BKPT; } db = v->db; sqlite3_mutex_enter(db->mutex); while( (rc = sqlite3Step(v))==SQLITE_SCHEMA && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ int savedPc = v->pc; rc = sqlite3Reprepare(v); if( rc!=SQLITE_OK ){ /* This case occurs after failing to recompile an sql statement. ** The error message from the SQL compiler has already been loaded ** into the database handle. This block copies the error message ** from the database handle into the statement and sets the statement ** program counter to 0 to ensure that when the statement is ** finalized or reset the parser error message is available via ** sqlite3_errmsg() and sqlite3_errcode(). */ const char *zErr = (const char *)sqlite3_value_text(db->pErr); sqlite3DbFree(db, v->zErrMsg); if( !db->mallocFailed ){ v->zErrMsg = sqlite3DbStrDup(db, zErr); v->rc = rc = sqlite3ApiExit(db, rc); } else { v->zErrMsg = 0; v->rc = rc = SQLITE_NOMEM_BKPT; } break; } sqlite3_reset(pStmt); if( savedPc>=0 ){ /* Setting minWriteFileFormat to 254 is a signal to the OP_Init and ** OP_Trace opcodes to *not* perform SQLITE_TRACE_STMT because it has ** already been done once on a prior invocation that failed due to ** SQLITE_SCHEMA. tag-20220401a */ v->minWriteFileFormat = 254; } assert( v->expired==0 ); } sqlite3_mutex_leave(db->mutex); return rc; } /* ** Extract the user data from a sqlite3_context structure and return a ** pointer to it. */ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ) return 0; #endif assert( p && p->pFunc ); return p->pFunc->pUserData; } /* ** Extract the user data from a sqlite3_context structure and return a ** pointer to it. ** ** IMPLEMENTATION-OF: R-46798-50301 The sqlite3_context_db_handle() interface ** returns a copy of the pointer to the database connection (the 1st ** parameter) of the sqlite3_create_function() and ** sqlite3_create_function16() routines that originally registered the ** application defined function. */ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ) return 0; #else assert( p && p->pOut ); #endif return p->pOut->db; } /* ** If this routine is invoked from within an xColumn method of a virtual ** table, then it returns true if and only if the the call is during an ** UPDATE operation and the value of the column will not be modified ** by the UPDATE. ** ** If this routine is called from any context other than within the ** xColumn method of a virtual table, then the return value is meaningless ** and arbitrary. ** ** Virtual table implements might use this routine to optimize their ** performance by substituting a NULL result, or some other light-weight ** value, as a signal to the xUpdate routine that the column is unchanged. */ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){ #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ) return 0; #else assert( p ); #endif return sqlite3_value_nochange(p->pOut); } /* ** The destructor function for a ValueList object. This needs to be ** a separate function, unknowable to the application, to ensure that ** calls to sqlite3_vtab_in_first()/sqlite3_vtab_in_next() that are not ** preceded by activation of IN processing via sqlite3_vtab_int() do not ** try to access a fake ValueList object inserted by a hostile extension. */ SQLITE_PRIVATE void sqlite3VdbeValueListFree(void *pToDelete){ sqlite3_free(pToDelete); } /* ** Implementation of sqlite3_vtab_in_first() (if bNext==0) and ** sqlite3_vtab_in_next() (if bNext!=0). */ static int valueFromValueList( sqlite3_value *pVal, /* Pointer to the ValueList object */ sqlite3_value **ppOut, /* Store the next value from the list here */ int bNext /* 1 for _next(). 0 for _first() */ ){ int rc; ValueList *pRhs; *ppOut = 0; if( pVal==0 ) return SQLITE_MISUSE_BKPT; if( (pVal->flags & MEM_Dyn)==0 || pVal->xDel!=sqlite3VdbeValueListFree ){ return SQLITE_ERROR; }else{ assert( (pVal->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) == (MEM_Null|MEM_Term|MEM_Subtype) ); assert( pVal->eSubtype=='p' ); assert( pVal->u.zPType!=0 && strcmp(pVal->u.zPType,"ValueList")==0 ); pRhs = (ValueList*)pVal->z; } if( bNext ){ rc = sqlite3BtreeNext(pRhs->pCsr, 0); }else{ int dummy = 0; rc = sqlite3BtreeFirst(pRhs->pCsr, &dummy); assert( rc==SQLITE_OK || sqlite3BtreeEof(pRhs->pCsr) ); if( sqlite3BtreeEof(pRhs->pCsr) ) rc = SQLITE_DONE; } if( rc==SQLITE_OK ){ u32 sz; /* Size of current row in bytes */ Mem sMem; /* Raw content of current row */ memset(&sMem, 0, sizeof(sMem)); sz = sqlite3BtreePayloadSize(pRhs->pCsr); rc = sqlite3VdbeMemFromBtreeZeroOffset(pRhs->pCsr,(int)sz,&sMem); if( rc==SQLITE_OK ){ u8 *zBuf = (u8*)sMem.z; u32 iSerial; sqlite3_value *pOut = pRhs->pOut; int iOff = 1 + getVarint32(&zBuf[1], iSerial); sqlite3VdbeSerialGet(&zBuf[iOff], iSerial, pOut); pOut->enc = ENC(pOut->db); if( (pOut->flags & MEM_Ephem)!=0 && sqlite3VdbeMemMakeWriteable(pOut) ){ rc = SQLITE_NOMEM; }else{ *ppOut = pOut; } } sqlite3VdbeMemRelease(&sMem); } return rc; } /* ** Set the iterator value pVal to point to the first value in the set. ** Set (*ppOut) to point to this value before returning. */ SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut){ return valueFromValueList(pVal, ppOut, 0); } /* ** Set the iterator value pVal to point to the next value in the set. ** Set (*ppOut) to point to this value before returning. */ SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut){ return valueFromValueList(pVal, ppOut, 1); } /* ** Return the current time for a statement. If the current time ** is requested more than once within the same run of a single prepared ** statement, the exact same time is returned for each invocation regardless ** of the amount of time that elapses between invocations. In other words, ** the time returned is always the time of the first call. */ SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ int rc; #ifndef SQLITE_ENABLE_STAT4 sqlite3_int64 *piTime = &p->pVdbe->iCurrentTime; assert( p->pVdbe!=0 ); #else sqlite3_int64 iTime = 0; sqlite3_int64 *piTime = p->pVdbe!=0 ? &p->pVdbe->iCurrentTime : &iTime; #endif if( *piTime==0 ){ rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, piTime); if( rc ) *piTime = 0; } return *piTime; } /* ** Create a new aggregate context for p and return a pointer to ** its pMem->z element. */ static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){ Mem *pMem = p->pMem; assert( (pMem->flags & MEM_Agg)==0 ); if( nByte<=0 ){ sqlite3VdbeMemSetNull(pMem); pMem->z = 0; }else{ sqlite3VdbeMemClearAndResize(pMem, nByte); pMem->flags = MEM_Agg; pMem->u.pDef = p->pFunc; if( pMem->z ){ memset(pMem->z, 0, nByte); } } return (void*)pMem->z; } /* ** Allocate or return the aggregate context for a user function. A new ** context is allocated on the first call. Subsequent calls return the ** same context that was returned on prior calls. */ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ assert( p && p->pFunc && p->pFunc->xFinalize ); assert( sqlite3_mutex_held(p->pOut->db->mutex) ); testcase( nByte<0 ); if( (p->pMem->flags & MEM_Agg)==0 ){ return createAggContext(p, nByte); }else{ return (void*)p->pMem->z; } } /* ** Return the auxiliary data pointer, if any, for the iArg'th argument to ** the user-function defined by pCtx. ** ** The left-most argument is 0. ** ** Undocumented behavior: If iArg is negative then access a cache of ** auxiliary data pointers that is available to all functions within a ** single prepared statement. The iArg values must match. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return 0; #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); #if SQLITE_ENABLE_STAT4 if( pCtx->pVdbe==0 ) return 0; #else assert( pCtx->pVdbe!=0 ); #endif for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ return pAuxData->pAux; } } return 0; } /* ** Set the auxiliary data pointer and delete function, for the iArg'th ** argument to the user-function defined by pCtx. Any previous value is ** deleted by calling the delete function specified when it was set. ** ** The left-most argument is 0. ** ** Undocumented behavior: If iArg is negative then make the data available ** to all functions within the current prepared statement using iArg as an ** access code. */ SQLITE_API void sqlite3_set_auxdata( sqlite3_context *pCtx, int iArg, void *pAux, void (*xDelete)(void*) ){ AuxData *pAuxData; Vdbe *pVdbe; #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif pVdbe= pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); #ifdef SQLITE_ENABLE_STAT4 if( pVdbe==0 ) goto failed; #else assert( pVdbe!=0 ); #endif for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ break; } } if( pAuxData==0 ){ pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData)); if( !pAuxData ) goto failed; pAuxData->iAuxOp = pCtx->iOp; pAuxData->iAuxArg = iArg; pAuxData->pNextAux = pVdbe->pAuxData; pVdbe->pAuxData = pAuxData; if( pCtx->isError==0 ) pCtx->isError = -1; }else if( pAuxData->xDeleteAux ){ pAuxData->xDeleteAux(pAuxData->pAux); } pAuxData->pAux = pAux; pAuxData->xDeleteAux = xDelete; return; failed: if( xDelete ){ xDelete(pAux); } } #ifndef SQLITE_OMIT_DEPRECATED /* ** Return the number of times the Step function of an aggregate has been ** called. ** ** This function is deprecated. Do not use it for new code. It is ** provide only to avoid breaking legacy code. New aggregate function ** implementations should keep their own counts within their aggregate ** context. */ SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){ assert( p && p->pMem && p->pFunc && p->pFunc->xFinalize ); return p->pMem->n; } #endif /* ** Return the number of columns in the result set for the statement pStmt. */ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; if( pVm==0 ) return 0; return pVm->nResColumn; } /* ** Return the number of values available from the current row of the ** currently executing statement pStmt. */ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; if( pVm==0 || pVm->pResultRow==0 ) return 0; return pVm->nResColumn; } /* ** Return a pointer to static memory containing an SQL NULL value. */ static const Mem *columnNullValue(void){ /* Even though the Mem structure contains an element ** of type i64, on certain architectures (x86) with certain compiler ** switches (-Os), gcc may align this Mem object on a 4-byte boundary ** instead of an 8-byte one. This all works fine, except that when ** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s ** that a Mem structure is located on an 8-byte boundary. To prevent ** these assert()s from failing, when building with SQLITE_DEBUG defined ** using gcc, we force nullMem to be 8-byte aligned using the magical ** __attribute__((aligned(8))) macro. */ static const Mem nullMem #if defined(SQLITE_DEBUG) && defined(__GNUC__) __attribute__((aligned(8))) #endif = { /* .u = */ {0}, /* .z = */ (char*)0, /* .n = */ (int)0, /* .flags = */ (u16)MEM_Null, /* .enc = */ (u8)0, /* .eSubtype = */ (u8)0, /* .db = */ (sqlite3*)0, /* .szMalloc = */ (int)0, /* .uTemp = */ (u32)0, /* .zMalloc = */ (char*)0, /* .xDel = */ (void(*)(void*))0, #ifdef SQLITE_DEBUG /* .pScopyFrom = */ (Mem*)0, /* .mScopyFlags= */ 0, #endif }; return &nullMem; } /* ** Check to see if column iCol of the given statement is valid. If ** it is, return a pointer to the Mem for the value of that column. ** If iCol is not valid, return a pointer to a Mem which has a value ** of NULL. */ static Mem *columnMem(sqlite3_stmt *pStmt, int i){ Vdbe *pVm; Mem *pOut; pVm = (Vdbe *)pStmt; if( pVm==0 ) return (Mem*)columnNullValue(); assert( pVm->db ); sqlite3_mutex_enter(pVm->db->mutex); if( pVm->pResultRow!=0 && inResColumn && i>=0 ){ pOut = &pVm->pResultRow[i]; }else{ sqlite3Error(pVm->db, SQLITE_RANGE); pOut = (Mem*)columnNullValue(); } return pOut; } /* ** This function is called after invoking an sqlite3_value_XXX function on a ** column value (i.e. a value returned by evaluating an SQL expression in the ** select list of a SELECT statement) that may cause a malloc() failure. If ** malloc() has failed, the threads mallocFailed flag is cleared and the result ** code of statement pStmt set to SQLITE_NOMEM. ** ** Specifically, this is called from within: ** ** sqlite3_column_int() ** sqlite3_column_int64() ** sqlite3_column_text() ** sqlite3_column_text16() ** sqlite3_column_real() ** sqlite3_column_bytes() ** sqlite3_column_bytes16() ** sqlite3_column_blob() */ static void columnMallocFailure(sqlite3_stmt *pStmt) { /* If malloc() failed during an encoding conversion within an ** sqlite3_column_XXX API, then set the return code of the statement to ** SQLITE_NOMEM. The next call to _step() (if any) will return SQLITE_ERROR ** and _finalize() will return NOMEM. */ Vdbe *p = (Vdbe *)pStmt; if( p ){ assert( p->db!=0 ); assert( sqlite3_mutex_held(p->db->mutex) ); p->rc = sqlite3ApiExit(p->db, p->rc); sqlite3_mutex_leave(p->db->mutex); } } /**************************** sqlite3_column_ ******************************* ** The following routines are used to access elements of the current row ** in the result set. */ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){ const void *val; val = sqlite3_value_blob( columnMem(pStmt,i) ); /* Even though there is no encoding conversion, value_blob() might ** need to call malloc() to expand the result of a zeroblob() ** expression. */ columnMallocFailure(pStmt); return val; } SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){ int val = sqlite3_value_bytes( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){ int val = sqlite3_value_bytes16( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } SQLITE_API double sqlite3_column_double(sqlite3_stmt *pStmt, int i){ double val = sqlite3_value_double( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } SQLITE_API int sqlite3_column_int(sqlite3_stmt *pStmt, int i){ int val = sqlite3_value_int( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } SQLITE_API sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){ sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){ const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){ Mem *pOut = columnMem(pStmt, i); if( pOut->flags&MEM_Static ){ pOut->flags &= ~MEM_Static; pOut->flags |= MEM_Ephem; } columnMallocFailure(pStmt); return (sqlite3_value *)pOut; } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){ const void *val = sqlite3_value_text16( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } #endif /* SQLITE_OMIT_UTF16 */ SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){ int iType = sqlite3_value_type( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return iType; } /* ** Column names appropriate for EXPLAIN or EXPLAIN QUERY PLAN. */ static const char * const azExplainColNames8[] = { "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", /* EXPLAIN */ "id", "parent", "notused", "detail" /* EQP */ }; static const u16 azExplainColNames16data[] = { /* 0 */ 'a', 'd', 'd', 'r', 0, /* 5 */ 'o', 'p', 'c', 'o', 'd', 'e', 0, /* 12 */ 'p', '1', 0, /* 15 */ 'p', '2', 0, /* 18 */ 'p', '3', 0, /* 21 */ 'p', '4', 0, /* 24 */ 'p', '5', 0, /* 27 */ 'c', 'o', 'm', 'm', 'e', 'n', 't', 0, /* 35 */ 'i', 'd', 0, /* 38 */ 'p', 'a', 'r', 'e', 'n', 't', 0, /* 45 */ 'n', 'o', 't', 'u', 's', 'e', 'd', 0, /* 53 */ 'd', 'e', 't', 'a', 'i', 'l', 0 }; static const u8 iExplainColNames16[] = { 0, 5, 12, 15, 18, 21, 24, 27, 35, 38, 45, 53 }; /* ** Convert the N-th element of pStmt->pColName[] into a string using ** xFunc() then return that string. If N is out of range, return 0. ** ** There are up to 5 names for each column. useType determines which ** name is returned. Here are the names: ** ** 0 The column name as it should be displayed for output ** 1 The datatype name for the column ** 2 The name of the database that the column derives from ** 3 The name of the table that the column derives from ** 4 The name of the table column that the result column derives from ** ** If the result is not a simple column reference (if it is an expression ** or a constant) then useTypes 2, 3, and 4 return NULL. */ static const void *columnName( sqlite3_stmt *pStmt, /* The statement */ int N, /* Which column to get the name for */ int useUtf16, /* True to return the name as UTF16 */ int useType /* What type of name */ ){ const void *ret; Vdbe *p; int n; sqlite3 *db; #ifdef SQLITE_ENABLE_API_ARMOR if( pStmt==0 ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif if( N<0 ) return 0; ret = 0; p = (Vdbe *)pStmt; db = p->db; assert( db!=0 ); sqlite3_mutex_enter(db->mutex); if( p->explain ){ if( useType>0 ) goto columnName_end; n = p->explain==1 ? 8 : 4; if( N>=n ) goto columnName_end; if( useUtf16 ){ int i = iExplainColNames16[N + 8*p->explain - 8]; ret = (void*)&azExplainColNames16data[i]; }else{ ret = (void*)azExplainColNames8[N + 8*p->explain - 8]; } goto columnName_end; } n = p->nResColumn; if( NmallocFailed; N += useType*n; #ifndef SQLITE_OMIT_UTF16 if( useUtf16 ){ ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]); }else #endif { ret = sqlite3_value_text((sqlite3_value*)&p->aColName[N]); } /* A malloc may have failed inside of the _text() call. If this ** is the case, clear the mallocFailed flag and return NULL. */ assert( db->mallocFailed==0 || db->mallocFailed==1 ); if( db->mallocFailed > prior_mallocFailed ){ sqlite3OomClear(db); ret = 0; } } columnName_end: sqlite3_mutex_leave(db->mutex); return ret; } /* ** Return the name of the Nth column of the result set returned by SQL ** statement pStmt. */ SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 0, COLNAME_NAME); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 1, COLNAME_NAME); } #endif /* ** Constraint: If you have ENABLE_COLUMN_METADATA then you must ** not define OMIT_DECLTYPE. */ #if defined(SQLITE_OMIT_DECLTYPE) && defined(SQLITE_ENABLE_COLUMN_METADATA) # error "Must not define both SQLITE_OMIT_DECLTYPE \ and SQLITE_ENABLE_COLUMN_METADATA" #endif #ifndef SQLITE_OMIT_DECLTYPE /* ** Return the column declaration type (if applicable) of the 'i'th column ** of the result set of SQL statement pStmt. */ SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 0, COLNAME_DECLTYPE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 1, COLNAME_DECLTYPE); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_DECLTYPE */ #ifdef SQLITE_ENABLE_COLUMN_METADATA /* ** Return the name of the database from which a result column derives. ** NULL is returned if the result column is an expression or constant or ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 0, COLNAME_DATABASE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 1, COLNAME_DATABASE); } #endif /* SQLITE_OMIT_UTF16 */ /* ** Return the name of the table from which a result column derives. ** NULL is returned if the result column is an expression or constant or ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 0, COLNAME_TABLE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 1, COLNAME_TABLE); } #endif /* SQLITE_OMIT_UTF16 */ /* ** Return the name of the table column from which a result column derives. ** NULL is returned if the result column is an expression or constant or ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 0, COLNAME_COLUMN); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 1, COLNAME_COLUMN); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_ENABLE_COLUMN_METADATA */ /******************************* sqlite3_bind_ *************************** ** ** Routines used to attach values to wildcards in a compiled SQL statement. */ /* ** Unbind the value bound to variable i in virtual machine p. This is the ** the same as binding a NULL value to the column. If the "i" parameter is ** out of range, then SQLITE_RANGE is returned. Otherwise SQLITE_OK. ** ** A successful evaluation of this routine acquires the mutex on p. ** the mutex is released if any kind of error occurs. ** ** The error code stored in database p->db is overwritten with the return ** value in any case. */ static int vdbeUnbind(Vdbe *p, unsigned int i){ Mem *pVar; if( vdbeSafetyNotNull(p) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(p->db->mutex); if( p->eVdbeState!=VDBE_READY_STATE ){ sqlite3Error(p->db, SQLITE_MISUSE_BKPT); sqlite3_mutex_leave(p->db->mutex); sqlite3_log(SQLITE_MISUSE, "bind on a busy prepared statement: [%s]", p->zSql); return SQLITE_MISUSE_BKPT; } if( i>=(unsigned int)p->nVar ){ sqlite3Error(p->db, SQLITE_RANGE); sqlite3_mutex_leave(p->db->mutex); return SQLITE_RANGE; } pVar = &p->aVar[i]; sqlite3VdbeMemRelease(pVar); pVar->flags = MEM_Null; p->db->errCode = SQLITE_OK; /* If the bit corresponding to this variable in Vdbe.expmask is set, then ** binding a new value to this variable invalidates the current query plan. ** ** IMPLEMENTATION-OF: R-57496-20354 If the specific value bound to a host ** parameter in the WHERE clause might influence the choice of query plan ** for a statement, then the statement will be automatically recompiled, ** as if there had been a schema change, on the first sqlite3_step() call ** following any change to the bindings of that parameter. */ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 ); if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<expired = 1; } return SQLITE_OK; } /* ** Bind a text or BLOB value. */ static int bindText( sqlite3_stmt *pStmt, /* The statement to bind against */ int i, /* Index of the parameter to bind */ const void *zData, /* Pointer to the data to be bound */ i64 nData, /* Number of bytes of data to be bound */ void (*xDel)(void*), /* Destructor for the data */ u8 encoding /* Encoding for the data */ ){ Vdbe *p = (Vdbe *)pStmt; Mem *pVar; int rc; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ if( zData!=0 ){ pVar = &p->aVar[i-1]; rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); if( rc==SQLITE_OK && encoding!=0 ){ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); } if( rc ){ sqlite3Error(p->db, rc); rc = sqlite3ApiExit(p->db, rc); } } sqlite3_mutex_leave(p->db->mutex); }else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){ xDel((void*)zData); } return rc; } /* ** Bind a blob value to an SQL statement variable. */ SQLITE_API int sqlite3_bind_blob( sqlite3_stmt *pStmt, int i, const void *zData, int nData, void (*xDel)(void*) ){ #ifdef SQLITE_ENABLE_API_ARMOR if( nData<0 ) return SQLITE_MISUSE_BKPT; #endif return bindText(pStmt, i, zData, nData, xDel, 0); } SQLITE_API int sqlite3_bind_blob64( sqlite3_stmt *pStmt, int i, const void *zData, sqlite3_uint64 nData, void (*xDel)(void*) ){ assert( xDel!=SQLITE_DYNAMIC ); return bindText(pStmt, i, zData, nData, xDel, 0); } SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ int rc; Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue); sqlite3_mutex_leave(p->db->mutex); } return rc; } SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){ return sqlite3_bind_int64(p, i, (i64)iValue); } SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){ int rc; Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue); sqlite3_mutex_leave(p->db->mutex); } return rc; } SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ int rc; Vdbe *p = (Vdbe*)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ sqlite3_mutex_leave(p->db->mutex); } return rc; } SQLITE_API int sqlite3_bind_pointer( sqlite3_stmt *pStmt, int i, void *pPtr, const char *zPTtype, void (*xDestructor)(void*) ){ int rc; Vdbe *p = (Vdbe*)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor); sqlite3_mutex_leave(p->db->mutex); }else if( xDestructor ){ xDestructor(pPtr); } return rc; } SQLITE_API int sqlite3_bind_text( sqlite3_stmt *pStmt, int i, const char *zData, int nData, void (*xDel)(void*) ){ return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8); } SQLITE_API int sqlite3_bind_text64( sqlite3_stmt *pStmt, int i, const char *zData, sqlite3_uint64 nData, void (*xDel)(void*), unsigned char enc ){ assert( xDel!=SQLITE_DYNAMIC ); if( enc!=SQLITE_UTF8 ){ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; nData &= ~(u16)1; } return bindText(pStmt, i, zData, nData, xDel, enc); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API int sqlite3_bind_text16( sqlite3_stmt *pStmt, int i, const void *zData, int n, void (*xDel)(void*) ){ return bindText(pStmt, i, zData, n & ~(u64)1, xDel, SQLITE_UTF16NATIVE); } #endif /* SQLITE_OMIT_UTF16 */ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ int rc; switch( sqlite3_value_type((sqlite3_value*)pValue) ){ case SQLITE_INTEGER: { rc = sqlite3_bind_int64(pStmt, i, pValue->u.i); break; } case SQLITE_FLOAT: { assert( pValue->flags & (MEM_Real|MEM_IntReal) ); rc = sqlite3_bind_double(pStmt, i, (pValue->flags & MEM_Real) ? pValue->u.r : (double)pValue->u.i ); break; } case SQLITE_BLOB: { if( pValue->flags & MEM_Zero ){ rc = sqlite3_bind_zeroblob(pStmt, i, pValue->u.nZero); }else{ rc = sqlite3_bind_blob(pStmt, i, pValue->z, pValue->n,SQLITE_TRANSIENT); } break; } case SQLITE_TEXT: { rc = bindText(pStmt,i, pValue->z, pValue->n, SQLITE_TRANSIENT, pValue->enc); break; } default: { rc = sqlite3_bind_null(pStmt, i); break; } } return rc; } SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ int rc; Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, (u32)(i-1)); if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); #else rc = sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); #endif sqlite3_mutex_leave(p->db->mutex); } return rc; } SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){ int rc; Vdbe *p = (Vdbe *)pStmt; #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(p->db->mutex); if( n>(u64)p->db->aLimit[SQLITE_LIMIT_LENGTH] ){ rc = SQLITE_TOOBIG; }else{ assert( (n & 0x7FFFFFFF)==n ); rc = sqlite3_bind_zeroblob(pStmt, i, n); } rc = sqlite3ApiExit(p->db, rc); sqlite3_mutex_leave(p->db->mutex); return rc; } /* ** Return the number of wildcards that can be potentially bound to. ** This routine is added to support DBD::SQLite. */ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; return p ? p->nVar : 0; } /* ** Return the name of a wildcard parameter. Return NULL if the index ** is out of range or if the wildcard is unnamed. ** ** The result is always UTF-8. */ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){ Vdbe *p = (Vdbe*)pStmt; if( p==0 ) return 0; return sqlite3VListNumToName(p->pVList, i); } /* ** Given a wildcard parameter name, return the index of the variable ** with that name. If there is no variable with the given name, ** return 0. */ SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){ if( p==0 || zName==0 ) return 0; return sqlite3VListNameToNum(p->pVList, zName, nName); } SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){ return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName)); } /* ** Transfer all bindings from the first statement over to the second. */ SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ Vdbe *pFrom = (Vdbe*)pFromStmt; Vdbe *pTo = (Vdbe*)pToStmt; int i; assert( pTo->db==pFrom->db ); assert( pTo->nVar==pFrom->nVar ); sqlite3_mutex_enter(pTo->db->mutex); for(i=0; inVar; i++){ sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]); } sqlite3_mutex_leave(pTo->db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_DEPRECATED /* ** Deprecated external interface. Internal/core SQLite code ** should call sqlite3TransferBindings. ** ** It is misuse to call this routine with statements from different ** database connections. But as this is a deprecated interface, we ** will not bother to check for that condition. ** ** If the two statements contain a different number of bindings, then ** an SQLITE_ERROR is returned. Nothing else can go wrong, so otherwise ** SQLITE_OK is returned. */ SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ Vdbe *pFrom = (Vdbe*)pFromStmt; Vdbe *pTo = (Vdbe*)pToStmt; if( pFrom->nVar!=pTo->nVar ){ return SQLITE_ERROR; } assert( (pTo->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pTo->expmask==0 ); if( pTo->expmask ){ pTo->expired = 1; } assert( (pFrom->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pFrom->expmask==0 ); if( pFrom->expmask ){ pFrom->expired = 1; } return sqlite3TransferBindings(pFromStmt, pToStmt); } #endif /* ** Return the sqlite3* database handle to which the prepared statement given ** in the argument belongs. This is the same database handle that was ** the first argument to the sqlite3_prepare() that was used to create ** the statement in the first place. */ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->db : 0; } /* ** Return true if the prepared statement is guaranteed to not modify the ** database. */ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->readOnly : 1; } /* ** Return 1 if the statement is an EXPLAIN and return 2 if the ** statement is an EXPLAIN QUERY PLAN */ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->explain : 0; } /* ** Set the explain mode for a statement. */ SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode){ Vdbe *v = (Vdbe*)pStmt; int rc; #ifdef SQLITE_ENABLE_API_ARMOR if( pStmt==0 ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(v->db->mutex); if( ((int)v->explain)==eMode ){ rc = SQLITE_OK; }else if( eMode<0 || eMode>2 ){ rc = SQLITE_ERROR; }else if( (v->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){ rc = SQLITE_ERROR; }else if( v->eVdbeState!=VDBE_READY_STATE ){ rc = SQLITE_BUSY; }else if( v->nMem>=10 && (eMode!=2 || v->haveEqpOps) ){ /* No reprepare necessary */ v->explain = eMode; rc = SQLITE_OK; }else{ v->explain = eMode; rc = sqlite3Reprepare(v); v->haveEqpOps = eMode==2; } if( v->explain ){ v->nResColumn = 12 - 4*v->explain; }else{ v->nResColumn = v->nResAlloc; } sqlite3_mutex_leave(v->db->mutex); return rc; } /* ** Return true if the prepared statement is in need of being reset. */ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ Vdbe *v = (Vdbe*)pStmt; return v!=0 && v->eVdbeState==VDBE_RUN_STATE; } /* ** Return a pointer to the next prepared statement after pStmt associated ** with database connection pDb. If pStmt is NULL, return the first ** prepared statement for the database connection. Return NULL if there ** are no more. */ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){ sqlite3_stmt *pNext; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(pDb) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(pDb->mutex); if( pStmt==0 ){ pNext = (sqlite3_stmt*)pDb->pVdbe; }else{ pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pVNext; } sqlite3_mutex_leave(pDb->mutex); return pNext; } /* ** Return the value of a status counter for a prepared statement */ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ Vdbe *pVdbe = (Vdbe*)pStmt; u32 v; #ifdef SQLITE_ENABLE_API_ARMOR if( !pStmt || (op!=SQLITE_STMTSTATUS_MEMUSED && (op<0||op>=ArraySize(pVdbe->aCounter))) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif if( op==SQLITE_STMTSTATUS_MEMUSED ){ sqlite3 *db = pVdbe->db; sqlite3_mutex_enter(db->mutex); v = 0; db->pnBytesFreed = (int*)&v; assert( db->lookaside.pEnd==db->lookaside.pTrueEnd ); db->lookaside.pEnd = db->lookaside.pStart; sqlite3VdbeDelete(pVdbe); db->pnBytesFreed = 0; db->lookaside.pEnd = db->lookaside.pTrueEnd; sqlite3_mutex_leave(db->mutex); }else{ v = pVdbe->aCounter[op]; if( resetFlag ) pVdbe->aCounter[op] = 0; } return (int)v; } /* ** Return the SQL associated with a prepared statement */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe *)pStmt; return p ? p->zSql : 0; } /* ** Return the SQL associated with a prepared statement with ** bound parameters expanded. Space to hold the returned string is ** obtained from sqlite3_malloc(). The caller is responsible for ** freeing the returned string by passing it to sqlite3_free(). ** ** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of ** expanded bound parameters. */ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){ #ifdef SQLITE_OMIT_TRACE return 0; #else char *z = 0; const char *zSql = sqlite3_sql(pStmt); if( zSql ){ Vdbe *p = (Vdbe *)pStmt; sqlite3_mutex_enter(p->db->mutex); z = sqlite3VdbeExpandSql(p, zSql); sqlite3_mutex_leave(p->db->mutex); } return z; #endif } #ifdef SQLITE_ENABLE_NORMALIZE /* ** Return the normalized SQL associated with a prepared statement. */ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe *)pStmt; if( p==0 ) return 0; if( p->zNormSql==0 && ALWAYS(p->zSql!=0) ){ sqlite3_mutex_enter(p->db->mutex); p->zNormSql = sqlite3Normalize(p, p->zSql); sqlite3_mutex_leave(p->db->mutex); } return p->zNormSql; } #endif /* SQLITE_ENABLE_NORMALIZE */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Allocate and populate an UnpackedRecord structure based on the serialized ** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure ** if successful, or a NULL pointer if an OOM error is encountered. */ static UnpackedRecord *vdbeUnpackRecord( KeyInfo *pKeyInfo, int nKey, const void *pKey ){ UnpackedRecord *pRet; /* Return value */ pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); if( pRet ){ memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1)); sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet); } return pRet; } /* ** This function is called from within a pre-update callback to retrieve ** a field of the row currently being updated or deleted. */ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ PreUpdate *p; Mem *pMem; int rc = SQLITE_OK; #ifdef SQLITE_ENABLE_API_ARMOR if( db==0 || ppValue==0 ){ return SQLITE_MISUSE_BKPT; } #endif p = db->pPreUpdate; /* Test that this call is being made from within an SQLITE_DELETE or ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */ if( !p || p->op==SQLITE_INSERT ){ rc = SQLITE_MISUSE_BKPT; goto preupdate_old_out; } if( p->pPk ){ iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); } if( iIdx>=p->pCsr->nField || iIdx<0 ){ rc = SQLITE_RANGE; goto preupdate_old_out; } /* If the old.* record has not yet been loaded into memory, do so now. */ if( p->pUnpacked==0 ){ u32 nRec; u8 *aRec; assert( p->pCsr->eCurType==CURTYPE_BTREE ); nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); aRec = sqlite3DbMallocRaw(db, nRec); if( !aRec ) goto preupdate_old_out; rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); if( rc==SQLITE_OK ){ p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); if( !p->pUnpacked ) rc = SQLITE_NOMEM; } if( rc!=SQLITE_OK ){ sqlite3DbFree(db, aRec); goto preupdate_old_out; } p->aRecord = aRec; } pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; if( iIdx==p->pTab->iPKey ){ sqlite3VdbeMemSetInt64(pMem, p->iKey1); }else if( iIdx>=p->pUnpacked->nField ){ *ppValue = (sqlite3_value *)columnNullValue(); }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ if( pMem->flags & (MEM_Int|MEM_IntReal) ){ testcase( pMem->flags & MEM_Int ); testcase( pMem->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pMem); } } preupdate_old_out: sqlite3Error(db, rc); return sqlite3ApiExit(db, rc); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** This function is called from within a pre-update callback to retrieve ** the number of columns in the row being updated, deleted or inserted. */ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ PreUpdate *p; #ifdef SQLITE_ENABLE_API_ARMOR p = db!=0 ? db->pPreUpdate : 0; #else p = db->pPreUpdate; #endif return (p ? p->keyinfo.nKeyField : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** This function is designed to be called from within a pre-update callback ** only. It returns zero if the change that caused the callback was made ** immediately by a user SQL statement. Or, if the change was made by a ** trigger program, it returns the number of trigger programs currently ** on the stack (1 for a top-level trigger, 2 for a trigger fired by a ** top-level trigger etc.). ** ** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL ** or SET DEFAULT action is considered a trigger. */ SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){ PreUpdate *p; #ifdef SQLITE_ENABLE_API_ARMOR p = db!=0 ? db->pPreUpdate : 0; #else p = db->pPreUpdate; #endif return (p ? p->v->nFrame : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** This function is designed to be called from within a pre-update callback ** only. */ SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){ PreUpdate *p; #ifdef SQLITE_ENABLE_API_ARMOR p = db!=0 ? db->pPreUpdate : 0; #else p = db->pPreUpdate; #endif return (p ? p->iBlobWrite : -1); } #endif #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** This function is called from within a pre-update callback to retrieve ** a field of the row currently being updated or inserted. */ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ PreUpdate *p; int rc = SQLITE_OK; Mem *pMem; #ifdef SQLITE_ENABLE_API_ARMOR if( db==0 || ppValue==0 ){ return SQLITE_MISUSE_BKPT; } #endif p = db->pPreUpdate; if( !p || p->op==SQLITE_DELETE ){ rc = SQLITE_MISUSE_BKPT; goto preupdate_new_out; } if( p->pPk && p->op!=SQLITE_UPDATE ){ iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); } if( iIdx>=p->pCsr->nField || iIdx<0 ){ rc = SQLITE_RANGE; goto preupdate_new_out; } if( p->op==SQLITE_INSERT ){ /* For an INSERT, memory cell p->iNewReg contains the serialized record ** that is being inserted. Deserialize it. */ UnpackedRecord *pUnpack = p->pNewUnpacked; if( !pUnpack ){ Mem *pData = &p->v->aMem[p->iNewReg]; rc = ExpandBlob(pData); if( rc!=SQLITE_OK ) goto preupdate_new_out; pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z); if( !pUnpack ){ rc = SQLITE_NOMEM; goto preupdate_new_out; } p->pNewUnpacked = pUnpack; } pMem = &pUnpack->aMem[iIdx]; if( iIdx==p->pTab->iPKey ){ sqlite3VdbeMemSetInt64(pMem, p->iKey2); }else if( iIdx>=pUnpack->nField ){ pMem = (sqlite3_value *)columnNullValue(); } }else{ /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required ** value. Make a copy of the cell contents and return a pointer to it. ** It is not safe to return a pointer to the memory cell itself as the ** caller may modify the value text encoding. */ assert( p->op==SQLITE_UPDATE ); if( !p->aNew ){ p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField); if( !p->aNew ){ rc = SQLITE_NOMEM; goto preupdate_new_out; } } assert( iIdx>=0 && iIdxpCsr->nField ); pMem = &p->aNew[iIdx]; if( pMem->flags==0 ){ if( iIdx==p->pTab->iPKey ){ sqlite3VdbeMemSetInt64(pMem, p->iKey2); }else{ rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]); if( rc!=SQLITE_OK ) goto preupdate_new_out; } } } *ppValue = pMem; preupdate_new_out: sqlite3Error(db, rc); return sqlite3ApiExit(db, rc); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Return status data for a single loop within query pStmt. */ SQLITE_API int sqlite3_stmt_scanstatus_v2( sqlite3_stmt *pStmt, /* Prepared statement being queried */ int iScan, /* Index of loop to report on */ int iScanStatusOp, /* Which metric to return */ int flags, void *pOut /* OUT: Write the answer here */ ){ Vdbe *p = (Vdbe*)pStmt; VdbeOp *aOp; int nOp; ScanStatus *pScan = 0; int idx; #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 || pOut==0 || iScanStatusOpSQLITE_SCANSTAT_NCYCLE ){ return 1; } #endif aOp = p->aOp; nOp = p->nOp; if( p->pFrame ){ VdbeFrame *pFrame; for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); aOp = pFrame->aOp; nOp = pFrame->nOp; } if( iScan<0 ){ int ii; if( iScanStatusOp==SQLITE_SCANSTAT_NCYCLE ){ i64 res = 0; for(ii=0; iiaScan[idx]; }else{ /* If the COMPLEX flag is clear, then this function must ignore any ** ScanStatus structures with ScanStatus.addrLoop set to 0. */ for(idx=0; idxnScan; idx++){ pScan = &p->aScan[idx]; if( pScan->zName ){ iScan--; if( iScan<0 ) break; } } } if( idx>=p->nScan ) return 1; switch( iScanStatusOp ){ case SQLITE_SCANSTAT_NLOOP: { if( pScan->addrLoop>0 ){ *(sqlite3_int64*)pOut = aOp[pScan->addrLoop].nExec; }else{ *(sqlite3_int64*)pOut = -1; } break; } case SQLITE_SCANSTAT_NVISIT: { if( pScan->addrVisit>0 ){ *(sqlite3_int64*)pOut = aOp[pScan->addrVisit].nExec; }else{ *(sqlite3_int64*)pOut = -1; } break; } case SQLITE_SCANSTAT_EST: { double r = 1.0; LogEst x = pScan->nEst; while( x<100 ){ x += 10; r *= 0.5; } *(double*)pOut = r*sqlite3LogEstToInt(x); break; } case SQLITE_SCANSTAT_NAME: { *(const char**)pOut = pScan->zName; break; } case SQLITE_SCANSTAT_EXPLAIN: { if( pScan->addrExplain ){ *(const char**)pOut = aOp[ pScan->addrExplain ].p4.z; }else{ *(const char**)pOut = 0; } break; } case SQLITE_SCANSTAT_SELECTID: { if( pScan->addrExplain ){ *(int*)pOut = aOp[ pScan->addrExplain ].p1; }else{ *(int*)pOut = -1; } break; } case SQLITE_SCANSTAT_PARENTID: { if( pScan->addrExplain ){ *(int*)pOut = aOp[ pScan->addrExplain ].p2; }else{ *(int*)pOut = -1; } break; } case SQLITE_SCANSTAT_NCYCLE: { i64 res = 0; if( pScan->aAddrRange[0]==0 ){ res = -1; }else{ int ii; for(ii=0; iiaAddrRange); ii+=2){ int iIns = pScan->aAddrRange[ii]; int iEnd = pScan->aAddrRange[ii+1]; if( iIns==0 ) break; if( iIns>0 ){ while( iIns<=iEnd ){ res += aOp[iIns].nCycle; iIns++; } }else{ int iOp; for(iOp=0; iOpp1!=iEnd ) continue; if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){ continue; } res += aOp[iOp].nCycle; } } } } *(i64*)pOut = res; break; } default: { return 1; } } return 0; } /* ** Return status data for a single loop within query pStmt. */ SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement being queried */ int iScan, /* Index of loop to report on */ int iScanStatusOp, /* Which metric to return */ void *pOut /* OUT: Write the answer here */ ){ return sqlite3_stmt_scanstatus_v2(pStmt, iScan, iScanStatusOp, 0, pOut); } /* ** Zero all counters associated with the sqlite3_stmt_scanstatus() data. */ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; int ii; for(ii=0; p!=0 && iinOp; ii++){ Op *pOp = &p->aOp[ii]; pOp->nExec = 0; pOp->nCycle = 0; } } #endif /* SQLITE_ENABLE_STMT_SCANSTATUS */ /************** End of vdbeapi.c *********************************************/ /************** Begin file vdbetrace.c ***************************************/ /* ** 2009 November 25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code used to insert the values of host parameters ** (aka "wildcards") into the SQL text output by sqlite3_trace(). ** ** The Vdbe parse-tree explainer is also found here. */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ #ifndef SQLITE_OMIT_TRACE /* ** zSql is a zero-terminated string of UTF-8 SQL text. Return the number of ** bytes in this text up to but excluding the first character in ** a host parameter. If the text contains no host parameters, return ** the total number of bytes in the text. */ static int findNextHostParameter(const char *zSql, int *pnToken){ int tokenType; int nTotal = 0; int n; *pnToken = 0; while( zSql[0] ){ n = sqlite3GetToken((u8*)zSql, &tokenType); assert( n>0 && tokenType!=TK_ILLEGAL ); if( tokenType==TK_VARIABLE ){ *pnToken = n; break; } nTotal += n; zSql += n; } return nTotal; } /* ** This function returns a pointer to a nul-terminated string in memory ** obtained from sqlite3DbMalloc(). If sqlite3.nVdbeExec is 1, then the ** string contains a copy of zRawSql but with host parameters expanded to ** their current bindings. Or, if sqlite3.nVdbeExec is greater than 1, ** then the returned string holds a copy of zRawSql with "-- " prepended ** to each line of text. ** ** If the SQLITE_TRACE_SIZE_LIMIT macro is defined to an integer, then ** then long strings and blobs are truncated to that many bytes. This ** can be used to prevent unreasonably large trace strings when dealing ** with large (multi-megabyte) strings and blobs. ** ** The calling function is responsible for making sure the memory returned ** is eventually freed. ** ** ALGORITHM: Scan the input string looking for host parameters in any of ** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within ** string literals, quoted identifier names, and comments. For text forms, ** the host parameter index is found by scanning the prepared ** statement for the corresponding OP_Variable opcode. Once the host ** parameter index is known, locate the value in p->aVar[]. Then render ** the value as a literal in place of the host parameter name. */ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( Vdbe *p, /* The prepared statement being evaluated */ const char *zRawSql /* Raw text of the SQL statement */ ){ sqlite3 *db; /* The database connection */ int idx = 0; /* Index of a host parameter */ int nextIndex = 1; /* Index of next ? host parameter */ int n; /* Length of a token prefix */ int nToken; /* Length of the parameter token */ int i; /* Loop counter */ Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ #ifndef SQLITE_OMIT_UTF16 Mem utf8; /* Used to convert UTF16 into UTF8 for display */ #endif db = p->db; sqlite3StrAccumInit(&out, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); if( db->nVdbeExec>1 ){ while( *zRawSql ){ const char *zStart = zRawSql; while( *(zRawSql++)!='\n' && *zRawSql ); sqlite3_str_append(&out, "-- ", 3); assert( (zRawSql - zStart) > 0 ); sqlite3_str_append(&out, zStart, (int)(zRawSql-zStart)); } }else if( p->nVar==0 ){ sqlite3_str_append(&out, zRawSql, sqlite3Strlen30(zRawSql)); }else{ while( zRawSql[0] ){ n = findNextHostParameter(zRawSql, &nToken); assert( n>0 ); sqlite3_str_append(&out, zRawSql, n); zRawSql += n; assert( zRawSql[0] || nToken==0 ); if( nToken==0 ) break; if( zRawSql[0]=='?' ){ if( nToken>1 ){ assert( sqlite3Isdigit(zRawSql[1]) ); sqlite3GetInt32(&zRawSql[1], &idx); }else{ idx = nextIndex; } }else{ assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' || zRawSql[0]=='#' ); testcase( zRawSql[0]==':' ); testcase( zRawSql[0]=='$' ); testcase( zRawSql[0]=='@' ); testcase( zRawSql[0]=='#' ); idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken); assert( idx>0 ); } zRawSql += nToken; nextIndex = MAX(idx + 1, nextIndex); assert( idx>0 && idx<=p->nVar ); pVar = &p->aVar[idx-1]; if( pVar->flags & MEM_Null ){ sqlite3_str_append(&out, "NULL", 4); }else if( pVar->flags & (MEM_Int|MEM_IntReal) ){ sqlite3_str_appendf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ sqlite3_str_appendf(&out, "%!.15g", pVar->u.r); }else if( pVar->flags & MEM_Str ){ int nOut; /* Number of bytes of the string text to include in output */ #ifndef SQLITE_OMIT_UTF16 u8 enc = ENC(db); if( enc!=SQLITE_UTF8 ){ memset(&utf8, 0, sizeof(utf8)); utf8.db = db; sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC); if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){ out.accError = SQLITE_NOMEM; out.nAlloc = 0; } pVar = &utf8; } #endif nOut = pVar->n; #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOut>SQLITE_TRACE_SIZE_LIMIT ){ nOut = SQLITE_TRACE_SIZE_LIMIT; while( nOutn && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; } } #endif sqlite3_str_appendf(&out, "'%.*q'", nOut, pVar->z); #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOutn ){ sqlite3_str_appendf(&out, "/*+%d bytes*/", pVar->n-nOut); } #endif #ifndef SQLITE_OMIT_UTF16 if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8); #endif }else if( pVar->flags & MEM_Zero ){ sqlite3_str_appendf(&out, "zeroblob(%d)", pVar->u.nZero); }else{ int nOut; /* Number of bytes of the blob to include in output */ assert( pVar->flags & MEM_Blob ); sqlite3_str_append(&out, "x'", 2); nOut = pVar->n; #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT; #endif for(i=0; iz[i]&0xff); } sqlite3_str_append(&out, "'", 1); #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOutn ){ sqlite3_str_appendf(&out, "/*+%d bytes*/", pVar->n-nOut); } #endif } } } if( out.accError ) sqlite3_str_reset(&out); return sqlite3StrAccumFinish(&out); } #endif /* #ifndef SQLITE_OMIT_TRACE */ /************** End of vdbetrace.c *******************************************/ /************** Begin file vdbe.c ********************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** The code in this file implements the function that runs the ** bytecode of a prepared statement. ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ /* ** Invoke this macro on memory cells just prior to changing the ** value of the cell. This macro verifies that shallow copies are ** not misused. A shallow copy of a string or blob just copies a ** pointer to the string or blob, not the content. If the original ** is changed while the copy is still in use, the string or blob might ** be changed out from under the copy. This macro verifies that nothing ** like that ever happens. */ #ifdef SQLITE_DEBUG # define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M) #else # define memAboutToChange(P,M) #endif /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes. The test ** procedures use this information to make sure that indices are ** working correctly. This variable has no function other than to ** help verify the correct operation of the library. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_search_count = 0; #endif /* ** When this global variable is positive, it gets decremented once before ** each instruction in the VDBE. When it reaches zero, the u1.isInterrupted ** field of the sqlite3 structure is set in order to simulate an interrupt. ** ** This facility is used for testing purposes only. It does not function ** in an ordinary build. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_interrupt_count = 0; #endif /* ** The next global variable is incremented each type the OP_Sort opcode ** is executed. The test procedures use this information to make sure that ** sorting is occurring or not occurring at appropriate times. This variable ** has no function other than to help verify the correct operation of the ** library. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_sort_count = 0; #endif /* ** The next global variable records the size of the largest MEM_Blob ** or MEM_Str that has been used by a VDBE opcode. The test procedures ** use this information to make sure that the zero-blob functionality ** is working correctly. This variable has no function other than to ** help verify the correct operation of the library. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_max_blobsize = 0; static void updateMaxBlobsize(Mem *p){ if( (p->flags & (MEM_Str|MEM_Blob))!=0 && p->n>sqlite3_max_blobsize ){ sqlite3_max_blobsize = p->n; } } #endif /* ** This macro evaluates to true if either the update hook or the preupdate ** hook are enabled for database connect DB. */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK # define HAS_UPDATE_HOOK(DB) ((DB)->xPreUpdateCallback||(DB)->xUpdateCallback) #else # define HAS_UPDATE_HOOK(DB) ((DB)->xUpdateCallback) #endif /* ** The next global variable is incremented each time the OP_Found opcode ** is executed. This is used to test whether or not the foreign key ** operation implemented using OP_FkIsZero is working. This variable ** has no function other than to help verify the correct operation of the ** library. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_found_count = 0; #endif /* ** Test a register to see if it exceeds the current maximum blob size. ** If it does, record the new maximum blob size. */ #if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE) # define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P) #else # define UPDATE_MAX_BLOBSIZE(P) #endif #ifdef SQLITE_DEBUG /* This routine provides a convenient place to set a breakpoint during ** tracing with PRAGMA vdbe_trace=on. The breakpoint fires right after ** each opcode is printed. Variables "pc" (program counter) and pOp are ** available to add conditionals to the breakpoint. GDB example: ** ** break test_trace_breakpoint if pc=22 ** ** Other useful labels for breakpoints include: ** test_addop_breakpoint(pc,pOp) ** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){ static u64 n = 0; (void)pc; (void)pOp; (void)v; n++; if( n==LARGEST_UINT64 ) abort(); /* So that n is used, preventing a warning */ } #endif /* ** Invoke the VDBE coverage callback, if that callback is defined. This ** feature is used for test suite validation only and does not appear an ** production builds. ** ** M is the type of branch. I is the direction taken for this instance of ** the branch. ** ** M: 2 - two-way branch (I=0: fall-thru 1: jump ) ** 3 - two-way + NULL (I=0: fall-thru 1: jump 2: NULL ) ** 4 - OP_Jump (I=0: jump p1 1: jump p2 2: jump p3) ** ** In other words, if M is 2, then I is either 0 (for fall-through) or ** 1 (for when the branch is taken). If M is 3, the I is 0 for an ** ordinary fall-through, I is 1 if the branch was taken, and I is 2 ** if the result of comparison is NULL. For M=3, I=2 the jump may or ** may not be taken, depending on the SQLITE_JUMPIFNULL flags in p5. ** When M is 4, that means that an OP_Jump is being run. I is 0, 1, or 2 ** depending on if the operands are less than, equal, or greater than. ** ** iSrcLine is the source code line (from the __LINE__ macro) that ** generated the VDBE instruction combined with flag bits. The source ** code line number is in the lower 24 bits of iSrcLine and the upper ** 8 bytes are flags. The lower three bits of the flags indicate ** values for I that should never occur. For example, if the branch is ** always taken, the flags should be 0x05 since the fall-through and ** alternate branch are never taken. If a branch is never taken then ** flags should be 0x06 since only the fall-through approach is allowed. ** ** Bit 0x08 of the flags indicates an OP_Jump opcode that is only ** interested in equal or not-equal. In other words, I==0 and I==2 ** should be treated as equivalent ** ** Since only a line number is retained, not the filename, this macro ** only works for amalgamation builds. But that is ok, since these macros ** should be no-ops except for special builds used to measure test coverage. */ #if !defined(SQLITE_VDBE_COVERAGE) # define VdbeBranchTaken(I,M) #else # define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M) static void vdbeTakeBranch(u32 iSrcLine, u8 I, u8 M){ u8 mNever; assert( I<=2 ); /* 0: fall through, 1: taken, 2: alternate taken */ assert( M<=4 ); /* 2: two-way branch, 3: three-way branch, 4: OP_Jump */ assert( I> 24; assert( (I & mNever)==0 ); if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ /* Invoke the branch coverage callback with three arguments: ** iSrcLine - the line number of the VdbeCoverage() macro, with ** flags removed. ** I - Mask of bits 0x07 indicating which cases are are ** fulfilled by this instance of the jump. 0x01 means ** fall-thru, 0x02 means taken, 0x04 means NULL. Any ** impossible cases (ex: if the comparison is never NULL) ** are filled in automatically so that the coverage ** measurement logic does not flag those impossible cases ** as missed coverage. ** M - Type of jump. Same as M argument above */ I |= mNever; if( M==2 ) I |= 0x04; if( M==4 ){ I |= 0x08; if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/ } sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, iSrcLine&0xffffff, I, M); } #endif /* ** An ephemeral string value (signified by the MEM_Ephem flag) contains ** a pointer to a dynamically allocated string where some other entity ** is responsible for deallocating that string. Because the register ** does not control the string, it might be deleted without the register ** knowing it. ** ** This routine converts an ephemeral string into a dynamically allocated ** string that the register itself controls. In other words, it ** converts an MEM_Ephem string into a string with P.z==P.zMalloc. */ #define Deephemeralize(P) \ if( ((P)->flags&MEM_Ephem)!=0 \ && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} /* Return true if the cursor was opened using the OP_OpenSorter opcode. */ #define isSorter(x) ((x)->eCurType==CURTYPE_SORTER) /* ** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL ** if we run out of memory. */ static VdbeCursor *allocateCursor( Vdbe *p, /* The virtual machine */ int iCur, /* Index of the new VdbeCursor */ int nField, /* Number of fields in the table or index */ u8 eCurType /* Type of the new cursor */ ){ /* Find the memory cell that will be used to store the blob of memory ** required for this VdbeCursor structure. It is convenient to use a ** vdbe memory cell to manage the memory allocation required for a ** VdbeCursor structure for the following reasons: ** ** * Sometimes cursor numbers are used for a couple of different ** purposes in a vdbe program. The different uses might require ** different sized allocations. Memory cells provide growable ** allocations. ** ** * When using ENABLE_MEMORY_MANAGEMENT, memory cell buffers can ** be freed lazily via the sqlite3_release_memory() API. This ** minimizes the number of malloc calls made by the system. ** ** The memory cell for cursor 0 is aMem[0]. The rest are allocated from ** the top of the register space. Cursor 1 is at Mem[p->nMem-1]. ** Cursor 2 is at Mem[p->nMem-2]. And so forth. */ Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem; int nByte; VdbeCursor *pCx = 0; nByte = ROUND8P(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0); assert( iCur>=0 && iCurnCursor ); if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/ sqlite3VdbeFreeCursorNN(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } /* There used to be a call to sqlite3VdbeMemClearAndResize() to make sure ** the pMem used to hold space for the cursor has enough storage available ** in pMem->zMalloc. But for the special case of the aMem[] entries used ** to hold cursors, it is faster to in-line the logic. */ assert( pMem->flags==MEM_Undefined ); assert( (pMem->flags & MEM_Dyn)==0 ); assert( pMem->szMalloc==0 || pMem->z==pMem->zMalloc ); if( pMem->szMallocszMalloc>0 ){ sqlite3DbFreeNN(pMem->db, pMem->zMalloc); } pMem->z = pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, nByte); if( pMem->zMalloc==0 ){ pMem->szMalloc = 0; return 0; } pMem->szMalloc = nByte; } p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc; memset(pCx, 0, offsetof(VdbeCursor,pAltCursor)); pCx->eCurType = eCurType; pCx->nField = nField; pCx->aOffset = &pCx->aType[nField]; if( eCurType==CURTYPE_BTREE ){ pCx->uc.pCursor = (BtCursor*) &pMem->z[ROUND8P(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; sqlite3BtreeCursorZero(pCx->uc.pCursor); } return pCx; } /* ** The string in pRec is known to look like an integer and to have a ** floating point value of rValue. Return true and set *piValue to the ** integer value if the string is in range to be an integer. Otherwise, ** return false. */ static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){ i64 iValue; iValue = sqlite3RealToI64(rValue); if( sqlite3RealSameAsInt(rValue,iValue) ){ *piValue = iValue; return 1; } return 0==sqlite3Atoi64(pRec->z, piValue, pRec->n, pRec->enc); } /* ** Try to convert a value into a numeric representation if we can ** do so without loss of information. In other words, if the string ** looks like a number, convert it into a number. If it does not ** look like a number, leave it alone. ** ** If the bTryForInt flag is true, then extra effort is made to give ** an integer representation. Strings that look like floating point ** values but which have no fractional component (example: '48.00') ** will have a MEM_Int representation when bTryForInt is true. ** ** If bTryForInt is false, then if the input string contains a decimal ** point or exponential notation, the result is only MEM_Real, even ** if there is an exact integer representation of the quantity. */ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ double rValue; u8 enc = pRec->enc; int rc; assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str ); rc = sqlite3AtoF(pRec->z, &rValue, pRec->n, enc); if( rc<=0 ) return; if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){ pRec->flags |= MEM_Int; }else{ pRec->u.r = rValue; pRec->flags |= MEM_Real; if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec); } /* TEXT->NUMERIC is many->one. Hence, it is important to invalidate the ** string representation after computing a numeric equivalent, because the ** string representation might not be the canonical representation for the ** numeric value. Ticket [343634942dd54ab57b7024] 2018-01-31. */ pRec->flags &= ~MEM_Str; } /* ** Processing is determine by the affinity parameter: ** ** SQLITE_AFF_INTEGER: ** SQLITE_AFF_REAL: ** SQLITE_AFF_NUMERIC: ** Try to convert pRec to an integer representation or a ** floating-point representation if an integer representation ** is not possible. Note that the integer representation is ** always preferred, even if the affinity is REAL, because ** an integer representation is more space efficient on disk. ** ** SQLITE_AFF_FLEXNUM: ** If the value is text, then try to convert it into a number of ** some kind (integer or real) but do not make any other changes. ** ** SQLITE_AFF_TEXT: ** Convert pRec to a text representation. ** ** SQLITE_AFF_BLOB: ** SQLITE_AFF_NONE: ** No-op. pRec is unchanged. */ static void applyAffinity( Mem *pRec, /* The value to apply affinity to */ char affinity, /* The affinity to be applied */ u8 enc /* Use this text encoding */ ){ if( affinity>=SQLITE_AFF_NUMERIC ){ assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL || affinity==SQLITE_AFF_NUMERIC || affinity==SQLITE_AFF_FLEXNUM ); if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/ if( (pRec->flags & (MEM_Real|MEM_IntReal))==0 ){ if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1); }else if( affinity<=SQLITE_AFF_REAL ){ sqlite3VdbeIntegerAffinity(pRec); } } }else if( affinity==SQLITE_AFF_TEXT ){ /* Only attempt the conversion to TEXT if there is an integer or real ** representation (blob and NULL do not get converted) but no string ** representation. It would be harmless to repeat the conversion if ** there is already a string rep, but it is pointless to waste those ** CPU cycles. */ if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/ if( (pRec->flags&(MEM_Real|MEM_Int|MEM_IntReal)) ){ testcase( pRec->flags & MEM_Int ); testcase( pRec->flags & MEM_Real ); testcase( pRec->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pRec, enc, 1); } } pRec->flags &= ~(MEM_Real|MEM_Int|MEM_IntReal); } } /* ** Try to convert the type of a function argument or a result column ** into a numeric representation. Use either INTEGER or REAL whichever ** is appropriate. But only do the conversion if it is possible without ** loss of information and return the revised type of the argument. */ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ int eType = sqlite3_value_type(pVal); if( eType==SQLITE_TEXT ){ Mem *pMem = (Mem*)pVal; applyNumericAffinity(pMem, 0); eType = sqlite3_value_type(pVal); } return eType; } /* ** Exported version of applyAffinity(). This one works on sqlite3_value*, ** not the internal Mem* type. */ SQLITE_PRIVATE void sqlite3ValueApplyAffinity( sqlite3_value *pVal, u8 affinity, u8 enc ){ applyAffinity((Mem *)pVal, affinity, enc); } /* ** pMem currently only holds a string type (or maybe a BLOB that we can ** interpret as a string if we want to). Compute its corresponding ** numeric type, if has one. Set the pMem->u.r and pMem->u.i fields ** accordingly. */ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ int rc; sqlite3_int64 ix; assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ); assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); if( ExpandBlob(pMem) ){ pMem->u.i = 0; return MEM_Int; } rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); if( rc<=0 ){ if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ pMem->u.i = ix; return MEM_Int; }else{ return MEM_Real; } }else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){ pMem->u.i = ix; return MEM_Int; } return MEM_Real; } /* ** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or ** none. ** ** Unlike applyNumericAffinity(), this routine does not modify pMem->flags. ** But it does set pMem->u.r and pMem->u.i appropriately. */ static u16 numericType(Mem *pMem){ assert( (pMem->flags & MEM_Null)==0 || pMem->db==0 || pMem->db->mallocFailed ); if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null) ){ testcase( pMem->flags & MEM_Int ); testcase( pMem->flags & MEM_Real ); testcase( pMem->flags & MEM_IntReal ); return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null); } assert( pMem->flags & (MEM_Str|MEM_Blob) ); testcase( pMem->flags & MEM_Str ); testcase( pMem->flags & MEM_Blob ); return computeNumericType(pMem); return 0; } #ifdef SQLITE_DEBUG /* ** Write a nice string representation of the contents of cell pMem ** into buffer zBuf, length nBuf. */ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){ int f = pMem->flags; static const char *const encnames[] = {"(X)", "(8)", "(16LE)", "(16BE)"}; if( f&MEM_Blob ){ int i; char c; if( f & MEM_Dyn ){ c = 'z'; assert( (f & (MEM_Static|MEM_Ephem))==0 ); }else if( f & MEM_Static ){ c = 't'; assert( (f & (MEM_Dyn|MEM_Ephem))==0 ); }else if( f & MEM_Ephem ){ c = 'e'; assert( (f & (MEM_Static|MEM_Dyn))==0 ); }else{ c = 's'; } sqlite3_str_appendf(pStr, "%cx[", c); for(i=0; i<25 && in; i++){ sqlite3_str_appendf(pStr, "%02X", ((int)pMem->z[i] & 0xFF)); } sqlite3_str_appendf(pStr, "|"); for(i=0; i<25 && in; i++){ char z = pMem->z[i]; sqlite3_str_appendchar(pStr, 1, (z<32||z>126)?'.':z); } sqlite3_str_appendf(pStr,"]"); if( f & MEM_Zero ){ sqlite3_str_appendf(pStr, "+%dz",pMem->u.nZero); } }else if( f & MEM_Str ){ int j; u8 c; if( f & MEM_Dyn ){ c = 'z'; assert( (f & (MEM_Static|MEM_Ephem))==0 ); }else if( f & MEM_Static ){ c = 't'; assert( (f & (MEM_Dyn|MEM_Ephem))==0 ); }else if( f & MEM_Ephem ){ c = 'e'; assert( (f & (MEM_Static|MEM_Dyn))==0 ); }else{ c = 's'; } sqlite3_str_appendf(pStr, " %c%d[", c, pMem->n); for(j=0; j<25 && jn; j++){ c = pMem->z[j]; sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.'); } sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]); if( f & MEM_Term ){ sqlite3_str_appendf(pStr, "(0-term)"); } } } #endif #ifdef SQLITE_DEBUG /* ** Print the value of a register for tracing purposes: */ static void memTracePrint(Mem *p){ if( p->flags & MEM_Undefined ){ printf(" undefined"); }else if( p->flags & MEM_Null ){ printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL"); }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ printf(" si:%lld", p->u.i); }else if( (p->flags & (MEM_IntReal))!=0 ){ printf(" ir:%lld", p->u.i); }else if( p->flags & MEM_Int ){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT }else if( p->flags & MEM_Real ){ printf(" r:%.17g", p->u.r); #endif }else if( sqlite3VdbeMemIsRowSet(p) ){ printf(" (rowset)"); }else{ StrAccum acc; char zBuf[1000]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); sqlite3VdbeMemPrettyPrint(p, &acc); printf(" %s", sqlite3StrAccumFinish(&acc)); } if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype); } static void registerTrace(int iReg, Mem *p){ printf("R[%d] = ", iReg); memTracePrint(p); if( p->pScopyFrom ){ printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg])); } printf("\n"); sqlite3VdbeCheckMemInvariants(p); } /**/ void sqlite3PrintMem(Mem *pMem){ memTracePrint(pMem); printf("\n"); fflush(stdout); } #endif #ifdef SQLITE_DEBUG /* ** Show the values of all registers in the virtual machine. Used for ** interactive debugging. */ SQLITE_PRIVATE void sqlite3VdbeRegisterDump(Vdbe *v){ int i; for(i=1; inMem; i++) registerTrace(i, v->aMem+i); } #endif /* SQLITE_DEBUG */ #ifdef SQLITE_DEBUG # define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M) #else # define REGISTER_TRACE(R,M) #endif #ifndef NDEBUG /* ** This function is only called from within an assert() expression. It ** checks that the sqlite3.nTransaction variable is correctly set to ** the number of non-transaction savepoints currently in the ** linked list starting at sqlite3.pSavepoint. ** ** Usage: ** ** assert( checkSavepointCount(db) ); */ static int checkSavepointCount(sqlite3 *db){ int n = 0; Savepoint *p; for(p=db->pSavepoint; p; p=p->pNext) n++; assert( n==(db->nSavepoint + db->isTransactionSavepoint) ); return 1; } #endif /* ** Return the register of pOp->p2 after first preparing it to be ** overwritten with an integer value. */ static SQLITE_NOINLINE Mem *out2PrereleaseWithClear(Mem *pOut){ sqlite3VdbeMemSetNull(pOut); pOut->flags = MEM_Int; return pOut; } static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){ Mem *pOut; assert( pOp->p2>0 ); assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); pOut = &p->aMem[pOp->p2]; memAboutToChange(p, pOut); if( VdbeMemDynamic(pOut) ){ /*OPTIMIZATION-IF-FALSE*/ return out2PrereleaseWithClear(pOut); }else{ pOut->flags = MEM_Int; return pOut; } } /* ** Compute a bloom filter hash using pOp->p4.i registers from aMem[] beginning ** with pOp->p3. Return the hash. */ static u64 filterHash(const Mem *aMem, const Op *pOp){ int i, mx; u64 h = 0; assert( pOp->p4type==P4_INT32 ); for(i=pOp->p3, mx=i+pOp->p4.i; iflags & (MEM_Int|MEM_IntReal) ){ h += p->u.i; }else if( p->flags & MEM_Real ){ h += sqlite3VdbeIntValue(p); }else if( p->flags & (MEM_Str|MEM_Blob) ){ /* All strings have the same hash and all blobs have the same hash, ** though, at least, those hashes are different from each other and ** from NULL. */ h += 4093 + (p->flags & (MEM_Str|MEM_Blob)); } } return h; } /* ** For OP_Column, factor out the case where content is loaded from ** overflow pages, so that the code to implement this case is separate ** the common case where all content fits on the page. Factoring out ** the code reduces register pressure and helps the common case ** to run faster. */ static SQLITE_NOINLINE int vdbeColumnFromOverflow( VdbeCursor *pC, /* The BTree cursor from which we are reading */ int iCol, /* The column to read */ int t, /* The serial-type code for the column value */ i64 iOffset, /* Offset to the start of the content value */ u32 cacheStatus, /* Current Vdbe.cacheCtr value */ u32 colCacheCtr, /* Current value of the column cache counter */ Mem *pDest /* Store the value into this register. */ ){ int rc; sqlite3 *db = pDest->db; int encoding = pDest->enc; int len = sqlite3VdbeSerialTypeLen(t); assert( pC->eCurType==CURTYPE_BTREE ); if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) return SQLITE_TOOBIG; if( len > 4000 && pC->pKeyInfo==0 ){ /* Cache large column values that are on overflow pages using ** an RCStr (reference counted string) so that if they are reloaded, ** that do not have to be copied a second time. The overhead of ** creating and managing the cache is such that this is only ** profitable for larger TEXT and BLOB values. ** ** Only do this on table-btrees so that writes to index-btrees do not ** need to clear the cache. This buys performance in the common case ** in exchange for generality. */ VdbeTxtBlbCache *pCache; char *pBuf; if( pC->colCache==0 ){ pC->pCache = sqlite3DbMallocZero(db, sizeof(VdbeTxtBlbCache) ); if( pC->pCache==0 ) return SQLITE_NOMEM; pC->colCache = 1; } pCache = pC->pCache; if( pCache->pCValue==0 || pCache->iCol!=iCol || pCache->cacheStatus!=cacheStatus || pCache->colCacheCtr!=colCacheCtr || pCache->iOffset!=sqlite3BtreeOffset(pC->uc.pCursor) ){ if( pCache->pCValue ) sqlite3RCStrUnref(pCache->pCValue); pBuf = pCache->pCValue = sqlite3RCStrNew( len+3 ); if( pBuf==0 ) return SQLITE_NOMEM; rc = sqlite3BtreePayload(pC->uc.pCursor, iOffset, len, pBuf); if( rc ) return rc; pBuf[len] = 0; pBuf[len+1] = 0; pBuf[len+2] = 0; pCache->iCol = iCol; pCache->cacheStatus = cacheStatus; pCache->colCacheCtr = colCacheCtr; pCache->iOffset = sqlite3BtreeOffset(pC->uc.pCursor); }else{ pBuf = pCache->pCValue; } assert( t>=12 ); sqlite3RCStrRef(pBuf); if( t&1 ){ rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, encoding, sqlite3RCStrUnref); pDest->flags |= MEM_Term; }else{ rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, 0, sqlite3RCStrUnref); } }else{ rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, iOffset, len, pDest); if( rc ) return rc; sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); if( (t&1)!=0 && encoding==SQLITE_UTF8 ){ pDest->z[len] = 0; pDest->flags |= MEM_Term; } } pDest->flags &= ~MEM_Ephem; return rc; } /* ** Return the symbolic name for the data type of a pMem */ static const char *vdbeMemTypeName(Mem *pMem){ static const char *azTypes[] = { /* SQLITE_INTEGER */ "INT", /* SQLITE_FLOAT */ "REAL", /* SQLITE_TEXT */ "TEXT", /* SQLITE_BLOB */ "BLOB", /* SQLITE_NULL */ "NULL" }; return azTypes[sqlite3_value_type(pMem)-1]; } /* ** Execute as much of a VDBE program as we can. ** This is the core of sqlite3_step(). */ SQLITE_PRIVATE int sqlite3VdbeExec( Vdbe *p /* The VDBE */ ){ Op *aOp = p->aOp; /* Copy of p->aOp */ Op *pOp = aOp; /* Current operation */ #ifdef SQLITE_DEBUG Op *pOrigOp; /* Value of pOp at the top of the loop */ int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */ u8 iCompareIsInit = 0; /* iCompare is initialized */ #endif int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ u8 encoding = ENC(db); /* The database encoding */ int iCompare = 0; /* Result of last comparison */ u64 nVmStep = 0; /* Number of virtual machine steps */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK u64 nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */ #endif Mem *aMem = p->aMem; /* Copy of p->aMem */ Mem *pIn1 = 0; /* 1st input operand */ Mem *pIn2 = 0; /* 2nd input operand */ Mem *pIn3 = 0; /* 3rd input operand */ Mem *pOut = 0; /* Output operand */ u32 colCacheCtr = 0; /* Column cache counter */ #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE) u64 *pnCycle = 0; int bStmtScanStatus = IS_STMT_SCANSTATUS(db)!=0; #endif /*** INSERT STACK UNION HERE ***/ assert( p->eVdbeState==VDBE_RUN_STATE ); /* sqlite3_step() verifies this */ if( DbMaskNonZero(p->lockMask) ){ sqlite3VdbeEnter(p); } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( db->xProgress ){ u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; assert( 0 < db->nProgressOps ); nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); }else{ nProgressLimit = LARGEST_UINT64; } #endif if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ goto no_mem; } assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY ); testcase( p->rc!=SQLITE_OK ); p->rc = SQLITE_OK; assert( p->bIsReader || p->readOnly!=0 ); p->iCurrentTime = 0; assert( p->explain==0 ); db->busyHandler.nBusy = 0; if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt; sqlite3VdbeIOTraceSql(p); #ifdef SQLITE_DEBUG sqlite3BeginBenignMalloc(); if( p->pc==0 && (p->db->flags & (SQLITE_VdbeListing|SQLITE_VdbeEQP|SQLITE_VdbeTrace))!=0 ){ int i; int once = 1; sqlite3VdbePrintSql(p); if( p->db->flags & SQLITE_VdbeListing ){ printf("VDBE Program Listing:\n"); for(i=0; inOp; i++){ sqlite3VdbePrintOp(stdout, i, &aOp[i]); } } if( p->db->flags & SQLITE_VdbeEQP ){ for(i=0; inOp; i++){ if( aOp[i].opcode==OP_Explain ){ if( once ) printf("VDBE Query Plan:\n"); printf("%s\n", aOp[i].p4.z); once = 0; } } } if( p->db->flags & SQLITE_VdbeTrace ) printf("VDBE Trace:\n"); } sqlite3EndBenignMalloc(); #endif for(pOp=&aOp[p->pc]; 1; pOp++){ /* Errors are detected by individual opcodes, with an immediate ** jumps to abort_due_to_error. */ assert( rc==SQLITE_OK ); assert( pOp>=aOp && pOp<&aOp[p->nOp]); nVmStep++; #if defined(VDBE_PROFILE) pOp->nExec++; pnCycle = &pOp->nCycle; if( sqlite3NProfileCnt==0 ) *pnCycle -= sqlite3Hwtime(); #elif defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( bStmtScanStatus ){ pOp->nExec++; pnCycle = &pOp->nCycle; *pnCycle -= sqlite3Hwtime(); } #endif /* Only allow tracing if SQLITE_DEBUG is defined. */ #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp); test_trace_breakpoint((int)(pOp - aOp),pOp,p); } #endif /* Check to see if we need to simulate an interrupt. This only happens ** if we have a special test build. */ #ifdef SQLITE_TEST if( sqlite3_interrupt_count>0 ){ sqlite3_interrupt_count--; if( sqlite3_interrupt_count==0 ){ sqlite3_interrupt(db); } } #endif /* Sanity checking on other operands */ #ifdef SQLITE_DEBUG { u8 opProperty = sqlite3OpcodeProperty[pOp->opcode]; if( (opProperty & OPFLG_IN1)!=0 ){ assert( pOp->p1>0 ); assert( pOp->p1<=(p->nMem+1 - p->nCursor) ); assert( memIsValid(&aMem[pOp->p1]) ); assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) ); REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]); } if( (opProperty & OPFLG_IN2)!=0 ){ assert( pOp->p2>0 ); assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); assert( memIsValid(&aMem[pOp->p2]) ); assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) ); REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]); } if( (opProperty & OPFLG_IN3)!=0 ){ assert( pOp->p3>0 ); assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); assert( memIsValid(&aMem[pOp->p3]) ); assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) ); REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]); } if( (opProperty & OPFLG_OUT2)!=0 ){ assert( pOp->p2>0 ); assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); memAboutToChange(p, &aMem[pOp->p2]); } if( (opProperty & OPFLG_OUT3)!=0 ){ assert( pOp->p3>0 ); assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); memAboutToChange(p, &aMem[pOp->p3]); } } #endif #ifdef SQLITE_DEBUG pOrigOp = pOp; #endif switch( pOp->opcode ){ /***************************************************************************** ** What follows is a massive switch statement where each case implements a ** separate instruction in the virtual machine. If we follow the usual ** indentation conventions, each case should be indented by 6 spaces. But ** that is a lot of wasted space on the left margin. So the code within ** the switch statement will break with convention and be flush-left. Another ** big comment (similar to this one) will mark the point in the code where ** we transition back to normal indentation. ** ** The formatting of each case is important. The makefile for SQLite ** generates two C files "opcodes.h" and "opcodes.c" by scanning this ** file looking for lines that begin with "case OP_". The opcodes.h files ** will be filled with #defines that give unique integer values to each ** opcode and the opcodes.c file is filled with an array of strings where ** each string is the symbolic name for the corresponding opcode. If the ** case statement is followed by a comment of the form "/# same as ... #/" ** that comment is used to determine the particular value of the opcode. ** ** Other keywords in the comment that follows each case are used to ** construct the OPFLG_INITIALIZER value that initializes opcodeProperty[]. ** Keywords include: in1, in2, in3, out2, out3. See ** the mkopcodeh.awk script for additional information. ** ** Documentation about VDBE opcodes is generated by scanning this file ** for lines of that contain "Opcode:". That line and all subsequent ** comment lines are used in the generation of the opcode.html documentation ** file. ** ** SUMMARY: ** ** Formatting is important to scripts that scan this file. ** Do not deviate from the formatting style currently in use. ** *****************************************************************************/ /* Opcode: Goto * P2 * * * ** ** An unconditional jump to address P2. ** The next instruction executed will be ** the one at index P2 from the beginning of ** the program. ** ** The P1 parameter is not actually used by this opcode. However, it ** is sometimes set to 1 instead of 0 as a hint to the command-line shell ** that this Goto is the bottom of a loop and that the lines from P2 down ** to the current line should be indented for EXPLAIN output. */ case OP_Goto: { /* jump */ #ifdef SQLITE_DEBUG /* In debugging mode, when the p5 flags is set on an OP_Goto, that ** means we should really jump back to the preceding OP_ReleaseReg ** instruction. */ if( pOp->p5 ){ assert( pOp->p2 < (int)(pOp - aOp) ); assert( pOp->p2 > 1 ); pOp = &aOp[pOp->p2 - 2]; assert( pOp[1].opcode==OP_ReleaseReg ); goto check_for_interrupt; } #endif jump_to_p2_and_check_for_interrupt: pOp = &aOp[pOp->p2 - 1]; /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev, ** OP_VNext, or OP_SorterNext) all jump here upon ** completion. Check to see if sqlite3_interrupt() has been called ** or if the progress callback needs to be invoked. ** ** This code uses unstructured "goto" statements and does not look clean. ** But that is not due to sloppy coding habits. The code is written this ** way for performance, to avoid having to run the interrupt and progress ** checks on every opcode. This helps sqlite3_step() to run about 1.5% ** faster according to "valgrind --tool=cachegrind" */ check_for_interrupt: if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt; #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* Call the progress callback if it is configured and the required number ** of VDBE ops have been executed (either since this invocation of ** sqlite3VdbeExec() or since last time the progress callback was called). ** If the progress callback returns non-zero, exit the virtual machine with ** a return code SQLITE_ABORT. */ while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ assert( db->nProgressOps!=0 ); nProgressLimit += db->nProgressOps; if( db->xProgress(db->pProgressArg) ){ nProgressLimit = LARGEST_UINT64; rc = SQLITE_INTERRUPT; goto abort_due_to_error; } } #endif break; } /* Opcode: Gosub P1 P2 * * * ** ** Write the current address onto register P1 ** and then jump to address P2. */ case OP_Gosub: { /* jump */ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); pIn1 = &aMem[pOp->p1]; assert( VdbeMemDynamic(pIn1)==0 ); memAboutToChange(p, pIn1); pIn1->flags = MEM_Int; pIn1->u.i = (int)(pOp-aOp); REGISTER_TRACE(pOp->p1, pIn1); goto jump_to_p2_and_check_for_interrupt; } /* Opcode: Return P1 P2 P3 * * ** ** Jump to the address stored in register P1. If P1 is a return address ** register, then this accomplishes a return from a subroutine. ** ** If P3 is 1, then the jump is only taken if register P1 holds an integer ** values, otherwise execution falls through to the next opcode, and the ** OP_Return becomes a no-op. If P3 is 0, then register P1 must hold an ** integer or else an assert() is raised. P3 should be set to 1 when ** this opcode is used in combination with OP_BeginSubrtn, and set to 0 ** otherwise. ** ** The value in register P1 is unchanged by this opcode. ** ** P2 is not used by the byte-code engine. However, if P2 is positive ** and also less than the current address, then the "EXPLAIN" output ** formatter in the CLI will indent all opcodes from the P2 opcode up ** to be not including the current Return. P2 should be the first opcode ** in the subroutine from which this opcode is returning. Thus the P2 ** value is a byte-code indentation hint. See tag-20220407a in ** wherecode.c and shell.c. */ case OP_Return: { /* in1 */ pIn1 = &aMem[pOp->p1]; if( pIn1->flags & MEM_Int ){ if( pOp->p3 ){ VdbeBranchTaken(1, 2); } pOp = &aOp[pIn1->u.i]; }else if( ALWAYS(pOp->p3) ){ VdbeBranchTaken(0, 2); } break; } /* Opcode: InitCoroutine P1 P2 P3 * * ** ** Set up register P1 so that it will Yield to the coroutine ** located at address P3. ** ** If P2!=0 then the coroutine implementation immediately follows ** this opcode. So jump over the coroutine implementation to ** address P2. ** ** See also: EndCoroutine */ case OP_InitCoroutine: { /* jump */ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); assert( pOp->p2>=0 && pOp->p2nOp ); assert( pOp->p3>=0 && pOp->p3nOp ); pOut = &aMem[pOp->p1]; assert( !VdbeMemDynamic(pOut) ); pOut->u.i = pOp->p3 - 1; pOut->flags = MEM_Int; if( pOp->p2==0 ) break; /* Most jump operations do a goto to this spot in order to update ** the pOp pointer. */ jump_to_p2: assert( pOp->p2>0 ); /* There are never any jumps to instruction 0 */ assert( pOp->p2nOp ); /* Jumps must be in range */ pOp = &aOp[pOp->p2 - 1]; break; } /* Opcode: EndCoroutine P1 * * * * ** ** The instruction at the address in register P1 is a Yield. ** Jump to the P2 parameter of that Yield. ** After the jump, register P1 becomes undefined. ** ** See also: InitCoroutine */ case OP_EndCoroutine: { /* in1 */ VdbeOp *pCaller; pIn1 = &aMem[pOp->p1]; assert( pIn1->flags==MEM_Int ); assert( pIn1->u.i>=0 && pIn1->u.inOp ); pCaller = &aOp[pIn1->u.i]; assert( pCaller->opcode==OP_Yield ); assert( pCaller->p2>=0 && pCaller->p2nOp ); pOp = &aOp[pCaller->p2 - 1]; pIn1->flags = MEM_Undefined; break; } /* Opcode: Yield P1 P2 * * * ** ** Swap the program counter with the value in register P1. This ** has the effect of yielding to a coroutine. ** ** If the coroutine that is launched by this instruction ends with ** Yield or Return then continue to the next instruction. But if ** the coroutine launched by this instruction ends with ** EndCoroutine, then jump to P2 rather than continuing with the ** next instruction. ** ** See also: InitCoroutine */ case OP_Yield: { /* in1, jump */ int pcDest; pIn1 = &aMem[pOp->p1]; assert( VdbeMemDynamic(pIn1)==0 ); pIn1->flags = MEM_Int; pcDest = (int)pIn1->u.i; pIn1->u.i = (int)(pOp - aOp); REGISTER_TRACE(pOp->p1, pIn1); pOp = &aOp[pcDest]; break; } /* Opcode: HaltIfNull P1 P2 P3 P4 P5 ** Synopsis: if r[P3]=null halt ** ** Check the value in register P3. If it is NULL then Halt using ** parameter P1, P2, and P4 as if this were a Halt instruction. If the ** value in register P3 is not NULL, then this routine is a no-op. ** The P5 parameter should be 1. */ case OP_HaltIfNull: { /* in3 */ pIn3 = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } #endif if( (pIn3->flags & MEM_Null)==0 ) break; /* Fall through into OP_Halt */ /* no break */ deliberate_fall_through } /* Opcode: Halt P1 P2 * P4 P5 ** ** Exit immediately. All open cursors, etc are closed ** automatically. ** ** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(), ** or sqlite3_finalize(). For a normal halt, this should be SQLITE_OK (0). ** For errors, it can be some other value. If P1!=0 then P2 will determine ** whether or not to rollback the current transaction. Do not rollback ** if P2==OE_Fail. Do the rollback if P2==OE_Rollback. If P2==OE_Abort, ** then back out all changes that have occurred during this execution of the ** VDBE, but do not rollback the transaction. ** ** If P4 is not null then it is an error message string. ** ** P5 is a value between 0 and 4, inclusive, that modifies the P4 string. ** ** 0: (no change) ** 1: NOT NULL constraint failed: P4 ** 2: UNIQUE constraint failed: P4 ** 3: CHECK constraint failed: P4 ** 4: FOREIGN KEY constraint failed: P4 ** ** If P5 is not zero and P4 is NULL, then everything after the ":" is ** omitted. ** ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { VdbeFrame *pFrame; int pcx; #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } #endif /* A deliberately coded "OP_Halt SQLITE_INTERNAL * * * *" opcode indicates ** something is wrong with the code generator. Raise an assertion in order ** to bring this to the attention of fuzzers and other testing tools. */ assert( pOp->p1!=SQLITE_INTERNAL ); if( p->pFrame && pOp->p1==SQLITE_OK ){ /* Halt the sub-program. Return control to the parent frame. */ pFrame = p->pFrame; p->pFrame = pFrame->pParent; p->nFrame--; sqlite3VdbeSetChanges(db, p->nChange); pcx = sqlite3VdbeFrameRestore(pFrame); if( pOp->p2==OE_Ignore ){ /* Instruction pcx is the OP_Program that invoked the sub-program ** currently being halted. If the p2 instruction of this OP_Halt ** instruction is set to OE_Ignore, then the sub-program is throwing ** an IGNORE exception. In this case jump to the address specified ** as the p2 of the calling OP_Program. */ pcx = p->aOp[pcx].p2-1; } aOp = p->aOp; aMem = p->aMem; pOp = &aOp[pcx]; break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; assert( pOp->p5<=4 ); if( p->rc ){ if( pOp->p5 ){ static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK", "FOREIGN KEY" }; testcase( pOp->p5==1 ); testcase( pOp->p5==2 ); testcase( pOp->p5==3 ); testcase( pOp->p5==4 ); sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]); if( pOp->p4.z ){ p->zErrMsg = sqlite3MPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z); } }else{ sqlite3VdbeError(p, "%s", pOp->p4.z); } pcx = (int)(pOp - aOp); sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); if( rc==SQLITE_BUSY ){ p->rc = SQLITE_BUSY; }else{ assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ); assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 ); rc = p->rc ? SQLITE_ERROR : SQLITE_DONE; } goto vdbe_return; } /* Opcode: Integer P1 P2 * * * ** Synopsis: r[P2]=P1 ** ** The 32-bit integer value P1 is written into register P2. */ case OP_Integer: { /* out2 */ pOut = out2Prerelease(p, pOp); pOut->u.i = pOp->p1; break; } /* Opcode: Int64 * P2 * P4 * ** Synopsis: r[P2]=P4 ** ** P4 is a pointer to a 64-bit integer value. ** Write that value into register P2. */ case OP_Int64: { /* out2 */ pOut = out2Prerelease(p, pOp); assert( pOp->p4.pI64!=0 ); pOut->u.i = *pOp->p4.pI64; break; } #ifndef SQLITE_OMIT_FLOATING_POINT /* Opcode: Real * P2 * P4 * ** Synopsis: r[P2]=P4 ** ** P4 is a pointer to a 64-bit floating point value. ** Write that value into register P2. */ case OP_Real: { /* same as TK_FLOAT, out2 */ pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Real; assert( !sqlite3IsNaN(*pOp->p4.pReal) ); pOut->u.r = *pOp->p4.pReal; break; } #endif /* Opcode: String8 * P2 * P4 * ** Synopsis: r[P2]='P4' ** ** P4 points to a nul terminated UTF-8 string. This opcode is transformed ** into a String opcode before it is executed for the first time. During ** this transformation, the length of string P4 is computed and stored ** as the P1 parameter. */ case OP_String8: { /* same as TK_STRING, out2 */ assert( pOp->p4.z!=0 ); pOut = out2Prerelease(p, pOp); pOp->p1 = sqlite3Strlen30(pOp->p4.z); #ifndef SQLITE_OMIT_UTF16 if( encoding!=SQLITE_UTF8 ){ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG ); if( rc ) goto too_big; if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); assert( VdbeMemDynamic(pOut)==0 ); pOut->szMalloc = 0; pOut->flags |= MEM_Static; if( pOp->p4type==P4_DYNAMIC ){ sqlite3DbFree(db, pOp->p4.z); } pOp->p4type = P4_DYNAMIC; pOp->p4.z = pOut->z; pOp->p1 = pOut->n; } #endif if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } pOp->opcode = OP_String; assert( rc==SQLITE_OK ); /* Fall through to the next case, OP_String */ /* no break */ deliberate_fall_through } /* Opcode: String P1 P2 P3 P4 P5 ** Synopsis: r[P2]='P4' (len=P1) ** ** The string value P4 of length P1 (bytes) is stored in register P2. ** ** If P3 is not zero and the content of register P3 is equal to P5, then ** the datatype of the register P2 is converted to BLOB. The content is ** the same sequence of bytes, it is merely interpreted as a BLOB instead ** of a string, as if it had been CAST. In other words: ** ** if( P3!=0 and reg[P3]==P5 ) reg[P2] := CAST(reg[P2] as BLOB) */ case OP_String: { /* out2 */ assert( pOp->p4.z!=0 ); pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Str|MEM_Static|MEM_Term; pOut->z = pOp->p4.z; pOut->n = pOp->p1; pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( pOp->p3>0 ){ assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pIn3 = &aMem[pOp->p3]; assert( pIn3->flags & MEM_Int ); if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; } #endif break; } /* Opcode: BeginSubrtn * P2 * * * ** Synopsis: r[P2]=NULL ** ** Mark the beginning of a subroutine that can be entered in-line ** or that can be called using OP_Gosub. The subroutine should ** be terminated by an OP_Return instruction that has a P1 operand that ** is the same as the P2 operand to this opcode and that has P3 set to 1. ** If the subroutine is entered in-line, then the OP_Return will simply ** fall through. But if the subroutine is entered using OP_Gosub, then ** the OP_Return will jump back to the first instruction after the OP_Gosub. ** ** This routine works by loading a NULL into the P2 register. When the ** return address register contains a NULL, the OP_Return instruction is ** a no-op that simply falls through to the next instruction (assuming that ** the OP_Return opcode has a P3 value of 1). Thus if the subroutine is ** entered in-line, then the OP_Return will cause in-line execution to ** continue. But if the subroutine is entered via OP_Gosub, then the ** OP_Return will cause a return to the address following the OP_Gosub. ** ** This opcode is identical to OP_Null. It has a different name ** only to make the byte code easier to read and verify. */ /* Opcode: Null P1 P2 P3 * * ** Synopsis: r[P2..P3]=NULL ** ** Write a NULL into registers P2. If P3 greater than P2, then also write ** NULL into register P3 and every register in between P2 and P3. If P3 ** is less than P2 (typically P3 is zero) then only register P2 is ** set to NULL. ** ** If the P1 value is non-zero, then also set the MEM_Cleared flag so that ** NULL values will not compare equal even if SQLITE_NULLEQ is set on ** OP_Ne or OP_Eq. */ case OP_BeginSubrtn: case OP_Null: { /* out2 */ int cnt; u16 nullFlag; pOut = out2Prerelease(p, pOp); cnt = pOp->p3-pOp->p2; assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; pOut->n = 0; #ifdef SQLITE_DEBUG pOut->uTemp = 0; #endif while( cnt>0 ){ pOut++; memAboutToChange(p, pOut); sqlite3VdbeMemSetNull(pOut); pOut->flags = nullFlag; pOut->n = 0; cnt--; } break; } /* Opcode: SoftNull P1 * * * * ** Synopsis: r[P1]=NULL ** ** Set register P1 to have the value NULL as seen by the OP_MakeRecord ** instruction, but do not free any string or blob memory associated with ** the register, so that if the value was a string or blob that was ** previously copied using OP_SCopy, the copies will continue to be valid. */ case OP_SoftNull: { assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); pOut = &aMem[pOp->p1]; pOut->flags = (pOut->flags&~(MEM_Undefined|MEM_AffMask))|MEM_Null; break; } /* Opcode: Blob P1 P2 * P4 * ** Synopsis: r[P2]=P4 (len=P1) ** ** P4 points to a blob of data P1 bytes long. Store this ** blob in register P2. If P4 is a NULL pointer, then construct ** a zero-filled blob that is P1 bytes long in P2. */ case OP_Blob: { /* out2 */ assert( pOp->p1 <= SQLITE_MAX_LENGTH ); pOut = out2Prerelease(p, pOp); if( pOp->p4.z==0 ){ sqlite3VdbeMemSetZeroBlob(pOut, pOp->p1); if( sqlite3VdbeMemExpandBlob(pOut) ) goto no_mem; }else{ sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0); } pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Variable P1 P2 * P4 * ** Synopsis: r[P2]=parameter(P1,P4) ** ** Transfer the values of bound parameter P1 into register P2 ** ** If the parameter is named, then its name appears in P4. ** The P4 value is used by sqlite3_bind_parameter_name(). */ case OP_Variable: { /* out2 */ Mem *pVar; /* Value being transferred */ assert( pOp->p1>0 && pOp->p1<=p->nVar ); assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) ); pVar = &p->aVar[pOp->p1 - 1]; if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; } pOut = &aMem[pOp->p2]; if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut); memcpy(pOut, pVar, MEMCELLSIZE); pOut->flags &= ~(MEM_Dyn|MEM_Ephem); pOut->flags |= MEM_Static|MEM_FromBind; UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Move P1 P2 P3 * * ** Synopsis: r[P2@P3]=r[P1@P3] ** ** Move the P3 values in register P1..P1+P3-1 over into ** registers P2..P2+P3-1. Registers P1..P1+P3-1 are ** left holding a NULL. It is an error for register ranges ** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error ** for P3 to be less than 1. */ case OP_Move: { int n; /* Number of registers left to copy */ int p1; /* Register to copy from */ int p2; /* Register to copy to */ n = pOp->p3; p1 = pOp->p1; p2 = pOp->p2; assert( n>0 && p1>0 && p2>0 ); assert( p1+n<=p2 || p2+n<=p1 ); pIn1 = &aMem[p1]; pOut = &aMem[p2]; do{ assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] ); assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] ); assert( memIsValid(pIn1) ); memAboutToChange(p, pOut); sqlite3VdbeMemMove(pOut, pIn1); #ifdef SQLITE_DEBUG pIn1->pScopyFrom = 0; { int i; for(i=1; inMem; i++){ if( aMem[i].pScopyFrom==pIn1 ){ aMem[i].pScopyFrom = pOut; } } } #endif Deephemeralize(pOut); REGISTER_TRACE(p2++, pOut); pIn1++; pOut++; }while( --n ); break; } /* Opcode: Copy P1 P2 P3 * P5 ** Synopsis: r[P2@P3+1]=r[P1@P3+1] ** ** Make a copy of registers P1..P1+P3 into registers P2..P2+P3. ** ** If the 0x0002 bit of P5 is set then also clear the MEM_Subtype flag in the ** destination. The 0x0001 bit of P5 indicates that this Copy opcode cannot ** be merged. The 0x0001 bit is used by the query planner and does not ** come into play during query execution. ** ** This instruction makes a deep copy of the value. A duplicate ** is made of any string or blob constant. See also OP_SCopy. */ case OP_Copy: { int n; n = pOp->p3; pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; assert( pOut!=pIn1 ); while( 1 ){ memAboutToChange(p, pOut); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); Deephemeralize(pOut); if( (pOut->flags & MEM_Subtype)!=0 && (pOp->p5 & 0x0002)!=0 ){ pOut->flags &= ~MEM_Subtype; } #ifdef SQLITE_DEBUG pOut->pScopyFrom = 0; #endif REGISTER_TRACE(pOp->p2+pOp->p3-n, pOut); if( (n--)==0 ) break; pOut++; pIn1++; } break; } /* Opcode: SCopy P1 P2 * * * ** Synopsis: r[P2]=r[P1] ** ** Make a shallow copy of register P1 into register P2. ** ** This instruction makes a shallow copy of the value. If the value ** is a string or blob, then the copy is only a pointer to the ** original and hence if the original changes so will the copy. ** Worse, if the original is deallocated, the copy becomes invalid. ** Thus the program must guarantee that the original will not change ** during the lifetime of the copy. Use OP_Copy to make a complete ** copy. */ case OP_SCopy: { /* out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; assert( pOut!=pIn1 ); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); #ifdef SQLITE_DEBUG pOut->pScopyFrom = pIn1; pOut->mScopyFlags = pIn1->flags; #endif break; } /* Opcode: IntCopy P1 P2 * * * ** Synopsis: r[P2]=r[P1] ** ** Transfer the integer value held in register P1 into register P2. ** ** This is an optimized version of SCopy that works only for integer ** values. */ case OP_IntCopy: { /* out2 */ pIn1 = &aMem[pOp->p1]; assert( (pIn1->flags & MEM_Int)!=0 ); pOut = &aMem[pOp->p2]; sqlite3VdbeMemSetInt64(pOut, pIn1->u.i); break; } /* Opcode: FkCheck * * * * * ** ** Halt with an SQLITE_CONSTRAINT error if there are any unresolved ** foreign key constraint violations. If there are no foreign key ** constraint violations, this is a no-op. ** ** FK constraint violations are also checked when the prepared statement ** exits. This opcode is used to raise foreign key constraint errors prior ** to returning results such as a row change count or the result of a ** RETURNING clause. */ case OP_FkCheck: { if( (rc = sqlite3VdbeCheckFk(p,0))!=SQLITE_OK ){ goto abort_due_to_error; } break; } /* Opcode: ResultRow P1 P2 * * * ** Synopsis: output=r[P1@P2] ** ** The registers P1 through P1+P2-1 contain a single row of ** results. This opcode causes the sqlite3_step() call to terminate ** with an SQLITE_ROW return code and it sets up the sqlite3_stmt ** structure to provide access to the r(P1)..r(P1+P2-1) values as ** the result row. */ case OP_ResultRow: { assert( p->nResColumn==pOp->p2 ); assert( pOp->p1>0 || CORRUPT_DB ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); p->cacheCtr = (p->cacheCtr + 2)|1; p->pResultRow = &aMem[pOp->p1]; #ifdef SQLITE_DEBUG { Mem *pMem = p->pResultRow; int i; for(i=0; ip2; i++){ assert( memIsValid(&pMem[i]) ); REGISTER_TRACE(pOp->p1+i, &pMem[i]); /* The registers in the result will not be used again when the ** prepared statement restarts. This is because sqlite3_column() ** APIs might have caused type conversions of made other changes to ** the register values. Therefore, we can go ahead and break any ** OP_SCopy dependencies. */ pMem[i].pScopyFrom = 0; } } #endif if( db->mallocFailed ) goto no_mem; if( db->mTrace & SQLITE_TRACE_ROW ){ db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0); } p->pc = (int)(pOp - aOp) + 1; rc = SQLITE_ROW; goto vdbe_return; } /* Opcode: Concat P1 P2 P3 * * ** Synopsis: r[P3]=r[P2]+r[P1] ** ** Add the text in register P1 onto the end of the text in ** register P2 and store the result in register P3. ** If either the P1 or P2 text are NULL then store NULL in P3. ** ** P3 = P2 || P1 ** ** It is illegal for P1 and P3 to be the same register. Sometimes, ** if P3 is the same register as P2, the implementation is able ** to avoid a memcpy(). */ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ i64 nByte; /* Total size of the output string or blob */ u16 flags1; /* Initial flags for P1 */ u16 flags2; /* Initial flags for P2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; pOut = &aMem[pOp->p3]; testcase( pOut==pIn2 ); assert( pIn1!=pOut ); flags1 = pIn1->flags; testcase( flags1 & MEM_Null ); testcase( pIn2->flags & MEM_Null ); if( (flags1 | pIn2->flags) & MEM_Null ){ sqlite3VdbeMemSetNull(pOut); break; } if( (flags1 & (MEM_Str|MEM_Blob))==0 ){ if( sqlite3VdbeMemStringify(pIn1,encoding,0) ) goto no_mem; flags1 = pIn1->flags & ~MEM_Str; }else if( (flags1 & MEM_Zero)!=0 ){ if( sqlite3VdbeMemExpandBlob(pIn1) ) goto no_mem; flags1 = pIn1->flags & ~MEM_Str; } flags2 = pIn2->flags; if( (flags2 & (MEM_Str|MEM_Blob))==0 ){ if( sqlite3VdbeMemStringify(pIn2,encoding,0) ) goto no_mem; flags2 = pIn2->flags & ~MEM_Str; }else if( (flags2 & MEM_Zero)!=0 ){ if( sqlite3VdbeMemExpandBlob(pIn2) ) goto no_mem; flags2 = pIn2->flags & ~MEM_Str; } nByte = pIn1->n + pIn2->n; if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){ goto no_mem; } MemSetTypeFlag(pOut, MEM_Str); if( pOut!=pIn2 ){ memcpy(pOut->z, pIn2->z, pIn2->n); assert( (pIn2->flags & MEM_Dyn) == (flags2 & MEM_Dyn) ); pIn2->flags = flags2; } memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); pIn1->flags = flags1; if( encoding>SQLITE_UTF8 ) nByte &= ~1; pOut->z[nByte]=0; pOut->z[nByte+1] = 0; pOut->flags |= MEM_Term; pOut->n = (int)nByte; pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Add P1 P2 P3 * * ** Synopsis: r[P3]=r[P1]+r[P2] ** ** Add the value in register P1 to the value in register P2 ** and store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: Multiply P1 P2 P3 * * ** Synopsis: r[P3]=r[P1]*r[P2] ** ** ** Multiply the value in register P1 by the value in register P2 ** and store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: Subtract P1 P2 P3 * * ** Synopsis: r[P3]=r[P2]-r[P1] ** ** Subtract the value in register P1 from the value in register P2 ** and store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: Divide P1 P2 P3 * * ** Synopsis: r[P3]=r[P2]/r[P1] ** ** Divide the value in register P1 by the value in register P2 ** and store the result in register P3 (P3=P2/P1). If the value in ** register P1 is zero, then the result is NULL. If either input is ** NULL, the result is NULL. */ /* Opcode: Remainder P1 P2 P3 * * ** Synopsis: r[P3]=r[P2]%r[P1] ** ** Compute the remainder after integer register P2 is divided by ** register P1 and store the result in register P3. ** If the value in register P1 is zero the result is NULL. ** If either operand is NULL, the result is NULL. */ case OP_Add: /* same as TK_PLUS, in1, in2, out3 */ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ u16 type1; /* Numeric type of left operand */ u16 type2; /* Numeric type of right operand */ i64 iA; /* Integer value of left operand */ i64 iB; /* Integer value of right operand */ double rA; /* Real value of left operand */ double rB; /* Real value of right operand */ pIn1 = &aMem[pOp->p1]; type1 = pIn1->flags; pIn2 = &aMem[pOp->p2]; type2 = pIn2->flags; pOut = &aMem[pOp->p3]; if( (type1 & type2 & MEM_Int)!=0 ){ int_math: iA = pIn1->u.i; iB = pIn2->u.i; switch( pOp->opcode ){ case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break; case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break; case OP_Multiply: if( sqlite3MulInt64(&iB,iA) ) goto fp_math; break; case OP_Divide: { if( iA==0 ) goto arithmetic_result_is_null; if( iA==-1 && iB==SMALLEST_INT64 ) goto fp_math; iB /= iA; break; } default: { if( iA==0 ) goto arithmetic_result_is_null; if( iA==-1 ) iA = 1; iB %= iA; break; } } pOut->u.i = iB; MemSetTypeFlag(pOut, MEM_Int); }else if( ((type1 | type2) & MEM_Null)!=0 ){ goto arithmetic_result_is_null; }else{ type1 = numericType(pIn1); type2 = numericType(pIn2); if( (type1 & type2 & MEM_Int)!=0 ) goto int_math; fp_math: rA = sqlite3VdbeRealValue(pIn1); rB = sqlite3VdbeRealValue(pIn2); switch( pOp->opcode ){ case OP_Add: rB += rA; break; case OP_Subtract: rB -= rA; break; case OP_Multiply: rB *= rA; break; case OP_Divide: { /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ if( rA==(double)0 ) goto arithmetic_result_is_null; rB /= rA; break; } default: { iA = sqlite3VdbeIntValue(pIn1); iB = sqlite3VdbeIntValue(pIn2); if( iA==0 ) goto arithmetic_result_is_null; if( iA==-1 ) iA = 1; rB = (double)(iB % iA); break; } } #ifdef SQLITE_OMIT_FLOATING_POINT pOut->u.i = rB; MemSetTypeFlag(pOut, MEM_Int); #else if( sqlite3IsNaN(rB) ){ goto arithmetic_result_is_null; } pOut->u.r = rB; MemSetTypeFlag(pOut, MEM_Real); #endif } break; arithmetic_result_is_null: sqlite3VdbeMemSetNull(pOut); break; } /* Opcode: CollSeq P1 * * P4 ** ** P4 is a pointer to a CollSeq object. If the next call to a user function ** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will ** be returned. This is used by the built-in min(), max() and nullif() ** functions. ** ** If P1 is not zero, then it is a register that a subsequent min() or ** max() aggregate will set to 1 if the current row is not the minimum or ** maximum. The P1 register is initialized to 0 by this instruction. ** ** The interface used by the implementation of the aforementioned functions ** to retrieve the collation sequence set by this opcode is not available ** publicly. Only built-in functions have access to this feature. */ case OP_CollSeq: { assert( pOp->p4type==P4_COLLSEQ ); if( pOp->p1 ){ sqlite3VdbeMemSetInt64(&aMem[pOp->p1], 0); } break; } /* Opcode: BitAnd P1 P2 P3 * * ** Synopsis: r[P3]=r[P1]&r[P2] ** ** Take the bit-wise AND of the values in register P1 and P2 and ** store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: BitOr P1 P2 P3 * * ** Synopsis: r[P3]=r[P1]|r[P2] ** ** Take the bit-wise OR of the values in register P1 and P2 and ** store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: ShiftLeft P1 P2 P3 * * ** Synopsis: r[P3]=r[P2]<>r[P1] ** ** Shift the integer value in register P2 to the right by the ** number of bits specified by the integer in register P1. ** Store the result in register P3. ** If either input is NULL, the result is NULL. */ case OP_BitAnd: /* same as TK_BITAND, in1, in2, out3 */ case OP_BitOr: /* same as TK_BITOR, in1, in2, out3 */ case OP_ShiftLeft: /* same as TK_LSHIFT, in1, in2, out3 */ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ i64 iA; u64 uA; i64 iB; u8 op; pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; pOut = &aMem[pOp->p3]; if( (pIn1->flags | pIn2->flags) & MEM_Null ){ sqlite3VdbeMemSetNull(pOut); break; } iA = sqlite3VdbeIntValue(pIn2); iB = sqlite3VdbeIntValue(pIn1); op = pOp->opcode; if( op==OP_BitAnd ){ iA &= iB; }else if( op==OP_BitOr ){ iA |= iB; }else if( iB!=0 ){ assert( op==OP_ShiftRight || op==OP_ShiftLeft ); /* If shifting by a negative amount, shift in the other direction */ if( iB<0 ){ assert( OP_ShiftRight==OP_ShiftLeft+1 ); op = 2*OP_ShiftLeft + 1 - op; iB = iB>(-64) ? -iB : 64; } if( iB>=64 ){ iA = (iA>=0 || op==OP_ShiftLeft) ? 0 : -1; }else{ memcpy(&uA, &iA, sizeof(uA)); if( op==OP_ShiftLeft ){ uA <<= iB; }else{ uA >>= iB; /* Sign-extend on a right shift of a negative number */ if( iA<0 ) uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-iB); } memcpy(&iA, &uA, sizeof(iA)); } } pOut->u.i = iA; MemSetTypeFlag(pOut, MEM_Int); break; } /* Opcode: AddImm P1 P2 * * * ** Synopsis: r[P1]=r[P1]+P2 ** ** Add the constant P2 to the value in register P1. ** The result is always an integer. ** ** To force any register to be an integer, just add 0. */ case OP_AddImm: { /* in1 */ pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); sqlite3VdbeMemIntegerify(pIn1); *(u64*)&pIn1->u.i += (u64)pOp->p2; break; } /* Opcode: MustBeInt P1 P2 * * * ** ** Force the value in register P1 to be an integer. If the value ** in P1 is not an integer and cannot be converted into an integer ** without data loss, then jump immediately to P2, or if P2==0 ** raise an SQLITE_MISMATCH exception. */ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if( (pIn1->flags & MEM_Int)==0 ){ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); if( (pIn1->flags & MEM_Int)==0 ){ VdbeBranchTaken(1, 2); if( pOp->p2==0 ){ rc = SQLITE_MISMATCH; goto abort_due_to_error; }else{ goto jump_to_p2; } } } VdbeBranchTaken(0, 2); MemSetTypeFlag(pIn1, MEM_Int); break; } #ifndef SQLITE_OMIT_FLOATING_POINT /* Opcode: RealAffinity P1 * * * * ** ** If register P1 holds an integer convert it to a real value. ** ** This opcode is used when extracting information from a column that ** has REAL affinity. Such column values may still be stored as ** integers, for space efficiency, but after extraction we want them ** to have only a real value. */ case OP_RealAffinity: { /* in1 */ pIn1 = &aMem[pOp->p1]; if( pIn1->flags & (MEM_Int|MEM_IntReal) ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pIn1); REGISTER_TRACE(pOp->p1, pIn1); } break; } #endif #ifndef SQLITE_OMIT_CAST /* Opcode: Cast P1 P2 * * * ** Synopsis: affinity(r[P1]) ** ** Force the value in register P1 to be the type defined by P2. ** **
      **
    • P2=='A' → BLOB **
    • P2=='B' → TEXT **
    • P2=='C' → NUMERIC **
    • P2=='D' → INTEGER **
    • P2=='E' → REAL **
    ** ** A NULL value is not changed by this routine. It remains NULL. */ case OP_Cast: { /* in1 */ assert( pOp->p2>=SQLITE_AFF_BLOB && pOp->p2<=SQLITE_AFF_REAL ); testcase( pOp->p2==SQLITE_AFF_TEXT ); testcase( pOp->p2==SQLITE_AFF_BLOB ); testcase( pOp->p2==SQLITE_AFF_NUMERIC ); testcase( pOp->p2==SQLITE_AFF_INTEGER ); testcase( pOp->p2==SQLITE_AFF_REAL ); pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); rc = ExpandBlob(pIn1); if( rc ) goto abort_due_to_error; rc = sqlite3VdbeMemCast(pIn1, pOp->p2, encoding); if( rc ) goto abort_due_to_error; UPDATE_MAX_BLOBSIZE(pIn1); REGISTER_TRACE(pOp->p1, pIn1); break; } #endif /* SQLITE_OMIT_CAST */ /* Opcode: Eq P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]==r[P1] ** ** Compare the values in register P1 and P3. If reg(P3)==reg(P1) then ** jump to address P2. ** ** The SQLITE_AFF_MASK portion of P5 must be an affinity character - ** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made ** to coerce both inputs according to this affinity before the ** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric ** affinity is used. Note that the affinity conversions are stored ** back into the input registers P1 and P3. So this opcode can cause ** persistent changes to registers P1 and P3. ** ** Once any conversions have taken place, and neither value is NULL, ** the values are compared. If both values are blobs then memcmp() is ** used to determine the results of the comparison. If both values ** are text, then the appropriate collating function specified in ** P4 is used to do the comparison. If P4 is not specified then ** memcmp() is used to compare text string. If both values are ** numeric, then a numeric comparison is used. If the two values ** are of different types, then numbers are considered less than ** strings and strings are considered less than blobs. ** ** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either ** true or false and is never NULL. If both operands are NULL then the result ** of comparison is true. If either operand is NULL then the result is false. ** If neither operand is NULL the result is the same as it would be if ** the SQLITE_NULLEQ flag were omitted from P5. ** ** This opcode saves the result of comparison for use by the new ** OP_Jump opcode. */ /* Opcode: Ne P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]!=r[P1] ** ** This works just like the Eq opcode except that the jump is taken if ** the operands in registers P1 and P3 are not equal. See the Eq opcode for ** additional information. */ /* Opcode: Lt P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]r[P1] ** ** This works just like the Lt opcode except that the jump is taken if ** the content of register P3 is greater than the content of ** register P1. See the Lt opcode for additional information. */ /* Opcode: Ge P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]>=r[P1] ** ** This works just like the Lt opcode except that the jump is taken if ** the content of register P3 is greater than or equal to the content of ** register P1. See the Lt opcode for additional information. */ case OP_Eq: /* same as TK_EQ, jump, in1, in3 */ case OP_Ne: /* same as TK_NE, jump, in1, in3 */ case OP_Lt: /* same as TK_LT, jump, in1, in3 */ case OP_Le: /* same as TK_LE, jump, in1, in3 */ case OP_Gt: /* same as TK_GT, jump, in1, in3 */ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ int res, res2; /* Result of the comparison of pIn1 against pIn3 */ char affinity; /* Affinity to use for comparison */ u16 flags1; /* Copy of initial value of pIn1->flags */ u16 flags3; /* Copy of initial value of pIn3->flags */ pIn1 = &aMem[pOp->p1]; pIn3 = &aMem[pOp->p3]; flags1 = pIn1->flags; flags3 = pIn3->flags; if( (flags1 & flags3 & MEM_Int)!=0 ){ /* Common case of comparison of two integers */ if( pIn3->u.i > pIn1->u.i ){ if( sqlite3aGTb[pOp->opcode] ){ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); goto jump_to_p2; } iCompare = +1; VVA_ONLY( iCompareIsInit = 1; ) }else if( pIn3->u.i < pIn1->u.i ){ if( sqlite3aLTb[pOp->opcode] ){ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); goto jump_to_p2; } iCompare = -1; VVA_ONLY( iCompareIsInit = 1; ) }else{ if( sqlite3aEQb[pOp->opcode] ){ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); goto jump_to_p2; } iCompare = 0; VVA_ONLY( iCompareIsInit = 1; ) } VdbeBranchTaken(0, (pOp->p5 & SQLITE_NULLEQ)?2:3); break; } if( (flags1 | flags3)&MEM_Null ){ /* One or both operands are NULL */ if( pOp->p5 & SQLITE_NULLEQ ){ /* If SQLITE_NULLEQ is set (which will only happen if the operator is ** OP_Eq or OP_Ne) then take the jump or not depending on whether ** or not both operands are null. */ assert( (flags1 & MEM_Cleared)==0 ); assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 || CORRUPT_DB ); testcase( (pOp->p5 & SQLITE_JUMPIFNULL)!=0 ); if( (flags1&flags3&MEM_Null)!=0 && (flags3&MEM_Cleared)==0 ){ res = 0; /* Operands are equal */ }else{ res = ((flags3 & MEM_Null) ? -1 : +1); /* Operands are not equal */ } }else{ /* SQLITE_NULLEQ is clear and at least one operand is NULL, ** then the result is always NULL. ** The jump is taken if the SQLITE_JUMPIFNULL bit is set. */ VdbeBranchTaken(2,3); if( pOp->p5 & SQLITE_JUMPIFNULL ){ goto jump_to_p2; } iCompare = 1; /* Operands are not equal */ VVA_ONLY( iCompareIsInit = 1; ) break; } }else{ /* Neither operand is NULL and we couldn't do the special high-speed ** integer comparison case. So do a general-case comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); assert( flags3==pIn3->flags || CORRUPT_DB ); flags3 = pIn3->flags; } if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } }else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){ if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str; } if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); testcase( pIn3->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn3, encoding, 1); testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask); } } assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); } /* At this point, res is negative, zero, or positive if reg[P1] is ** less than, equal to, or greater than reg[P3], respectively. Compute ** the answer to this operator in res2, depending on what the comparison ** operator actually is. The next block of code depends on the fact ** that the 6 comparison operators are consecutive integers in this ** order: NE, EQ, GT, LE, LT, GE */ assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 ); assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 ); if( res<0 ){ res2 = sqlite3aLTb[pOp->opcode]; }else if( res==0 ){ res2 = sqlite3aEQb[pOp->opcode]; }else{ res2 = sqlite3aGTb[pOp->opcode]; } iCompare = res; VVA_ONLY( iCompareIsInit = 1; ) /* Undo any changes made by applyAffinity() to the input registers. */ assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) ); pIn3->flags = flags3; assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); pIn1->flags = flags1; VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); if( res2 ){ goto jump_to_p2; } break; } /* Opcode: ElseEq * P2 * * * ** ** This opcode must follow an OP_Lt or OP_Gt comparison operator. There ** can be zero or more OP_ReleaseReg opcodes intervening, but no other ** opcodes are allowed to occur between this instruction and the previous ** OP_Lt or OP_Gt. ** ** If the result of an OP_Eq comparison on the same two operands as ** the prior OP_Lt or OP_Gt would have been true, then jump to P2. If ** the result of an OP_Eq comparison on the two previous operands ** would have been false or NULL, then fall through. */ case OP_ElseEq: { /* same as TK_ESCAPE, jump */ #ifdef SQLITE_DEBUG /* Verify the preconditions of this opcode - that it follows an OP_Lt or ** OP_Gt with zero or more intervening OP_ReleaseReg opcodes */ int iAddr; for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){ if( aOp[iAddr].opcode==OP_ReleaseReg ) continue; assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt ); break; } #endif /* SQLITE_DEBUG */ assert( iCompareIsInit ); VdbeBranchTaken(iCompare==0, 2); if( iCompare==0 ) goto jump_to_p2; break; } /* Opcode: Permutation * * * P4 * ** ** Set the permutation used by the OP_Compare operator in the next ** instruction. The permutation is stored in the P4 operand. ** ** The permutation is only valid for the next opcode which must be ** an OP_Compare that has the OPFLAG_PERMUTE bit set in P5. ** ** The first integer in the P4 integer array is the length of the array ** and does not become part of the permutation. */ case OP_Permutation: { assert( pOp->p4type==P4_INTARRAY ); assert( pOp->p4.ai ); assert( pOp[1].opcode==OP_Compare ); assert( pOp[1].p5 & OPFLAG_PERMUTE ); break; } /* Opcode: Compare P1 P2 P3 P4 P5 ** Synopsis: r[P1@P3] <-> r[P2@P3] ** ** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this ** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of ** the comparison for use by the next OP_Jump instruct. ** ** If P5 has the OPFLAG_PERMUTE bit set, then the order of comparison is ** determined by the most recent OP_Permutation operator. If the ** OPFLAG_PERMUTE bit is clear, then register are compared in sequential ** order. ** ** P4 is a KeyInfo structure that defines collating sequences and sort ** orders for the comparison. The permutation applies to registers ** only. The KeyInfo elements are used sequentially. ** ** The comparison is a sort comparison, so NULLs compare equal, ** NULLs are less than numbers, numbers are less than strings, ** and strings are less than blobs. ** ** This opcode must be immediately followed by an OP_Jump opcode. */ case OP_Compare: { int n; int i; int p1; int p2; const KeyInfo *pKeyInfo; u32 idx; CollSeq *pColl; /* Collating sequence to use on this term */ int bRev; /* True for DESCENDING sort order */ u32 *aPermute; /* The permutation */ if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){ aPermute = 0; }else{ assert( pOp>aOp ); assert( pOp[-1].opcode==OP_Permutation ); assert( pOp[-1].p4type==P4_INTARRAY ); aPermute = pOp[-1].p4.ai + 1; assert( aPermute!=0 ); } n = pOp->p3; pKeyInfo = pOp->p4.pKeyInfo; assert( n>0 ); assert( pKeyInfo!=0 ); p1 = pOp->p1; p2 = pOp->p2; #ifdef SQLITE_DEBUG if( aPermute ){ int k, mx = 0; for(k=0; k(u32)mx ) mx = aPermute[k]; assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 ); assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 ); }else{ assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 ); assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 ); } #endif /* SQLITE_DEBUG */ for(i=0; inKeyField ); pColl = pKeyInfo->aColl[i]; bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC); iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl); VVA_ONLY( iCompareIsInit = 1; ) if( iCompare ){ if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) && ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null)) ){ iCompare = -iCompare; } if( bRev ) iCompare = -iCompare; break; } } assert( pOp[1].opcode==OP_Jump ); break; } /* Opcode: Jump P1 P2 P3 * * ** ** Jump to the instruction at address P1, P2, or P3 depending on whether ** in the most recent OP_Compare instruction the P1 vector was less than, ** equal to, or greater than the P2 vector, respectively. ** ** This opcode must immediately follow an OP_Compare opcode. */ case OP_Jump: { /* jump */ assert( pOp>aOp && pOp[-1].opcode==OP_Compare ); assert( iCompareIsInit ); if( iCompare<0 ){ VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; }else if( iCompare==0 ){ VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1]; }else{ VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1]; } break; } /* Opcode: And P1 P2 P3 * * ** Synopsis: r[P3]=(r[P1] && r[P2]) ** ** Take the logical AND of the values in registers P1 and P2 and ** write the result into register P3. ** ** If either P1 or P2 is 0 (false) then the result is 0 even if ** the other input is NULL. A NULL and true or two NULLs give ** a NULL output. */ /* Opcode: Or P1 P2 P3 * * ** Synopsis: r[P3]=(r[P1] || r[P2]) ** ** Take the logical OR of the values in register P1 and P2 and ** store the answer in register P3. ** ** If either P1 or P2 is nonzero (true) then the result is 1 (true) ** even if the other input is NULL. A NULL and false or two NULLs ** give a NULL output. */ case OP_And: /* same as TK_AND, in1, in2, out3 */ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ v1 = sqlite3VdbeBooleanValue(&aMem[pOp->p1], 2); v2 = sqlite3VdbeBooleanValue(&aMem[pOp->p2], 2); if( pOp->opcode==OP_And ){ static const unsigned char and_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 }; v1 = and_logic[v1*3+v2]; }else{ static const unsigned char or_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 }; v1 = or_logic[v1*3+v2]; } pOut = &aMem[pOp->p3]; if( v1==2 ){ MemSetTypeFlag(pOut, MEM_Null); }else{ pOut->u.i = v1; MemSetTypeFlag(pOut, MEM_Int); } break; } /* Opcode: IsTrue P1 P2 P3 P4 * ** Synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 ** ** This opcode implements the IS TRUE, IS FALSE, IS NOT TRUE, and ** IS NOT FALSE operators. ** ** Interpret the value in register P1 as a boolean value. Store that ** boolean (a 0 or 1) in register P2. Or if the value in register P1 is ** NULL, then the P3 is stored in register P2. Invert the answer if P4 ** is 1. ** ** The logic is summarized like this: ** **
      **
    • If P3==0 and P4==0 then r[P2] := r[P1] IS TRUE **
    • If P3==1 and P4==1 then r[P2] := r[P1] IS FALSE **
    • If P3==0 and P4==1 then r[P2] := r[P1] IS NOT TRUE **
    • If P3==1 and P4==0 then r[P2] := r[P1] IS NOT FALSE **
    */ case OP_IsTrue: { /* in1, out2 */ assert( pOp->p4type==P4_INT32 ); assert( pOp->p4.i==0 || pOp->p4.i==1 ); assert( pOp->p3==0 || pOp->p3==1 ); sqlite3VdbeMemSetInt64(&aMem[pOp->p2], sqlite3VdbeBooleanValue(&aMem[pOp->p1], pOp->p3) ^ pOp->p4.i); break; } /* Opcode: Not P1 P2 * * * ** Synopsis: r[P2]= !r[P1] ** ** Interpret the value in register P1 as a boolean value. Store the ** boolean complement in register P2. If the value in register P1 is ** NULL, then a NULL is stored in P2. */ case OP_Not: { /* same as TK_NOT, in1, out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; if( (pIn1->flags & MEM_Null)==0 ){ sqlite3VdbeMemSetInt64(pOut, !sqlite3VdbeBooleanValue(pIn1,0)); }else{ sqlite3VdbeMemSetNull(pOut); } break; } /* Opcode: BitNot P1 P2 * * * ** Synopsis: r[P2]= ~r[P1] ** ** Interpret the content of register P1 as an integer. Store the ** ones-complement of the P1 value into register P2. If P1 holds ** a NULL then store a NULL in P2. */ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; sqlite3VdbeMemSetNull(pOut); if( (pIn1->flags & MEM_Null)==0 ){ pOut->flags = MEM_Int; pOut->u.i = ~sqlite3VdbeIntValue(pIn1); } break; } /* Opcode: Once P1 P2 * * * ** ** Fall through to the next instruction the first time this opcode is ** encountered on each invocation of the byte-code program. Jump to P2 ** on the second and all subsequent encounters during the same invocation. ** ** Top-level programs determine first invocation by comparing the P1 ** operand against the P1 operand on the OP_Init opcode at the beginning ** of the program. If the P1 values differ, then fall through and make ** the P1 of this opcode equal to the P1 of OP_Init. If P1 values are ** the same then take the jump. ** ** For subprograms, there is a bitmask in the VdbeFrame that determines ** whether or not the jump should be taken. The bitmask is necessary ** because the self-altering code trick does not work for recursive ** triggers. */ case OP_Once: { /* jump */ u32 iAddr; /* Address of this instruction */ assert( p->aOp[0].opcode==OP_Init ); if( p->pFrame ){ iAddr = (int)(pOp - p->aOp); if( (p->pFrame->aOnce[iAddr/8] & (1<<(iAddr & 7)))!=0 ){ VdbeBranchTaken(1, 2); goto jump_to_p2; } p->pFrame->aOnce[iAddr/8] |= 1<<(iAddr & 7); }else{ if( p->aOp[0].p1==pOp->p1 ){ VdbeBranchTaken(1, 2); goto jump_to_p2; } } VdbeBranchTaken(0, 2); pOp->p1 = p->aOp[0].p1; break; } /* Opcode: If P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is true. The value ** is considered true if it is numeric and non-zero. If the value ** in P1 is NULL then take the jump if and only if P3 is non-zero. */ case OP_If: { /* jump, in1 */ int c; c = sqlite3VdbeBooleanValue(&aMem[pOp->p1], pOp->p3); VdbeBranchTaken(c!=0, 2); if( c ) goto jump_to_p2; break; } /* Opcode: IfNot P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is False. The value ** is considered false if it has a numeric value of zero. If the value ** in P1 is NULL then take the jump if and only if P3 is non-zero. */ case OP_IfNot: { /* jump, in1 */ int c; c = !sqlite3VdbeBooleanValue(&aMem[pOp->p1], !pOp->p3); VdbeBranchTaken(c!=0, 2); if( c ) goto jump_to_p2; break; } /* Opcode: IsNull P1 P2 * * * ** Synopsis: if r[P1]==NULL goto P2 ** ** Jump to P2 if the value in register P1 is NULL. */ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ pIn1 = &aMem[pOp->p1]; VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2); if( (pIn1->flags & MEM_Null)!=0 ){ goto jump_to_p2; } break; } /* Opcode: IsType P1 P2 P3 P4 P5 ** Synopsis: if typeof(P1.P3) in P5 goto P2 ** ** Jump to P2 if the type of a column in a btree is one of the types specified ** by the P5 bitmask. ** ** P1 is normally a cursor on a btree for which the row decode cache is ** valid through at least column P3. In other words, there should have been ** a prior OP_Column for column P3 or greater. If the cursor is not valid, ** then this opcode might give spurious results. ** The the btree row has fewer than P3 columns, then use P4 as the ** datatype. ** ** If P1 is -1, then P3 is a register number and the datatype is taken ** from the value in that register. ** ** P5 is a bitmask of data types. SQLITE_INTEGER is the least significant ** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04. ** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10. ** ** WARNING: This opcode does not reliably distinguish between NULL and REAL ** when P1>=0. If the database contains a NaN value, this opcode will think ** that the datatype is REAL when it should be NULL. When P1<0 and the value ** is already stored in register P3, then this opcode does reliably ** distinguish between NULL and REAL. The problem only arises then P1>=0. ** ** Take the jump to address P2 if and only if the datatype of the ** value determined by P1 and P3 corresponds to one of the bits in the ** P5 bitmask. ** */ case OP_IsType: { /* jump */ VdbeCursor *pC; u16 typeMask; u32 serialType; assert( pOp->p1>=(-1) && pOp->p1nCursor ); assert( pOp->p1>=0 || (pOp->p3>=0 && pOp->p3<=(p->nMem+1 - p->nCursor)) ); if( pOp->p1>=0 ){ pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pOp->p3>=0 ); if( pOp->p3nHdrParsed ){ serialType = pC->aType[pOp->p3]; if( serialType>=12 ){ if( serialType&1 ){ typeMask = 0x04; /* SQLITE_TEXT */ }else{ typeMask = 0x08; /* SQLITE_BLOB */ } }else{ static const unsigned char aMask[] = { 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2, 0x01, 0x01, 0x10, 0x10 }; testcase( serialType==0 ); testcase( serialType==1 ); testcase( serialType==2 ); testcase( serialType==3 ); testcase( serialType==4 ); testcase( serialType==5 ); testcase( serialType==6 ); testcase( serialType==7 ); testcase( serialType==8 ); testcase( serialType==9 ); testcase( serialType==10 ); testcase( serialType==11 ); typeMask = aMask[serialType]; } }else{ typeMask = 1 << (pOp->p4.i - 1); testcase( typeMask==0x01 ); testcase( typeMask==0x02 ); testcase( typeMask==0x04 ); testcase( typeMask==0x08 ); testcase( typeMask==0x10 ); } }else{ assert( memIsValid(&aMem[pOp->p3]) ); typeMask = 1 << (sqlite3_value_type((sqlite3_value*)&aMem[pOp->p3])-1); testcase( typeMask==0x01 ); testcase( typeMask==0x02 ); testcase( typeMask==0x04 ); testcase( typeMask==0x08 ); testcase( typeMask==0x10 ); } VdbeBranchTaken( (typeMask & pOp->p5)!=0, 2); if( typeMask & pOp->p5 ){ goto jump_to_p2; } break; } /* Opcode: ZeroOrNull P1 P2 P3 * * ** Synopsis: r[P2] = 0 OR NULL ** ** If both registers P1 and P3 are NOT NULL, then store a zero in ** register P2. If either registers P1 or P3 are NULL then put ** a NULL in register P2. */ case OP_ZeroOrNull: { /* in1, in2, out2, in3 */ if( (aMem[pOp->p1].flags & MEM_Null)!=0 || (aMem[pOp->p3].flags & MEM_Null)!=0 ){ sqlite3VdbeMemSetNull(aMem + pOp->p2); }else{ sqlite3VdbeMemSetInt64(aMem + pOp->p2, 0); } break; } /* Opcode: NotNull P1 P2 * * * ** Synopsis: if r[P1]!=NULL goto P2 ** ** Jump to P2 if the value in register P1 is not NULL. */ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ pIn1 = &aMem[pOp->p1]; VdbeBranchTaken( (pIn1->flags & MEM_Null)==0, 2); if( (pIn1->flags & MEM_Null)==0 ){ goto jump_to_p2; } break; } /* Opcode: IfNullRow P1 P2 P3 * * ** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2 ** ** Check the cursor P1 to see if it is currently pointing at a NULL row. ** If it is, then set register P3 to NULL and jump immediately to P2. ** If P1 is not on a NULL row, then fall through without making any ** changes. ** ** If P1 is not an open cursor, then this opcode is a no-op. */ case OP_IfNullRow: { /* jump */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; if( pC && pC->nullRow ){ sqlite3VdbeMemSetNull(aMem + pOp->p3); goto jump_to_p2; } break; } #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC /* Opcode: Offset P1 P2 P3 * * ** Synopsis: r[P3] = sqlite_offset(P1) ** ** Store in register r[P3] the byte offset into the database file that is the ** start of the payload for the record at which that cursor P1 is currently ** pointing. ** ** P2 is the column number for the argument to the sqlite_offset() function. ** This opcode does not use P2 itself, but the P2 value is used by the ** code generator. The P1, P2, and P3 operands to this opcode are the ** same as for OP_Column. ** ** This opcode is only available if SQLite is compiled with the ** -DSQLITE_ENABLE_OFFSET_SQL_FUNC option. */ case OP_Offset: { /* out3 */ VdbeCursor *pC; /* The VDBE cursor */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; pOut = &p->aMem[pOp->p3]; if( pC==0 || pC->eCurType!=CURTYPE_BTREE ){ sqlite3VdbeMemSetNull(pOut); }else{ if( pC->deferredMoveto ){ rc = sqlite3VdbeFinishMoveto(pC); if( rc ) goto abort_due_to_error; } if( sqlite3BtreeEof(pC->uc.pCursor) ){ sqlite3VdbeMemSetNull(pOut); }else{ sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor)); } } break; } #endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */ /* Opcode: Column P1 P2 P3 P4 P5 ** Synopsis: r[P3]=PX cursor P1 column P2 ** ** Interpret the data that cursor P1 points to as a structure built using ** the MakeRecord instruction. (See the MakeRecord opcode for additional ** information about the format of the data.) Extract the P2-th column ** from this record. If there are less than (P2+1) ** values in the record, extract a NULL. ** ** The value extracted is stored in register P3. ** ** If the record contains fewer than P2 fields, then extract a NULL. Or, ** if the P4 argument is a P4_MEM use the value of the P4 argument as ** the result. ** ** If the OPFLAG_LENGTHARG bit is set in P5 then the result is guaranteed ** to only be used by the length() function or the equivalent. The content ** of large blobs is not loaded, thus saving CPU cycles. If the ** OPFLAG_TYPEOFARG bit is set then the result will only be used by the ** typeof() function or the IS NULL or IS NOT NULL operators or the ** equivalent. In this case, all content loading can be omitted. */ case OP_Column: { /* ncycle */ u32 p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The B-Tree cursor corresponding to pC */ u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ int len; /* The length of the serialized data for the column */ int i; /* Loop counter */ Mem *pDest; /* Where to write the extracted value */ Mem sMem; /* For storing the record being decoded */ const u8 *zData; /* Part of the record being decoded */ const u8 *zHdr; /* Next unparsed byte of the header */ const u8 *zEndHdr; /* Pointer to first byte after the header */ u64 offset64; /* 64-bit offset */ u32 t; /* A type code from the record header */ Mem *pReg; /* PseudoTable input register */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pC = p->apCsr[pOp->p1]; p2 = (u32)pOp->p2; op_column_restart: assert( pC!=0 ); assert( p2<(u32)pC->nField || (pC->eCurType==CURTYPE_PSEUDO && pC->seekResult==0) ); aOffset = pC->aOffset; assert( aOffset==pC->aType+pC->nField ); assert( pC->eCurType!=CURTYPE_VTAB ); assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); assert( pC->eCurType!=CURTYPE_SORTER ); if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/ if( pC->nullRow ){ if( pC->eCurType==CURTYPE_PSEUDO && pC->seekResult>0 ){ /* For the special case of as pseudo-cursor, the seekResult field ** identifies the register that holds the record */ pReg = &aMem[pC->seekResult]; assert( pReg->flags & MEM_Blob ); assert( memIsValid(pReg) ); pC->payloadSize = pC->szRow = pReg->n; pC->aRow = (u8*)pReg->z; }else{ pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); sqlite3VdbeMemSetNull(pDest); goto op_column_out; } }else{ pCrsr = pC->uc.pCursor; if( pC->deferredMoveto ){ u32 iMap; assert( !pC->isEphemeral ); if( pC->ub.aAltMap && (iMap = pC->ub.aAltMap[1+p2])>0 ){ pC = pC->pAltCursor; p2 = iMap - 1; goto op_column_restart; } rc = sqlite3VdbeFinishMoveto(pC); if( rc ) goto abort_due_to_error; }else if( sqlite3BtreeCursorHasMoved(pCrsr) ){ rc = sqlite3VdbeHandleMovedCursor(pC); if( rc ) goto abort_due_to_error; goto op_column_restart; } assert( pC->eCurType==CURTYPE_BTREE ); assert( pCrsr ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); pC->payloadSize = sqlite3BtreePayloadSize(pCrsr); pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow); assert( pC->szRow<=pC->payloadSize ); assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */ } pC->cacheStatus = p->cacheCtr; if( (aOffset[0] = pC->aRow[0])<0x80 ){ pC->iHdrOffset = 1; }else{ pC->iHdrOffset = sqlite3GetVarint32(pC->aRow, aOffset); } pC->nHdrParsed = 0; if( pC->szRowaRow does not have to hold the entire row, but it does at least ** need to cover the header of the record. If pC->aRow does not contain ** the complete header, then set it to zero, forcing the header to be ** dynamically allocated. */ pC->aRow = 0; pC->szRow = 0; /* Make sure a corrupt database has not given us an oversize header. ** Do this now to avoid an oversize memory allocation. ** ** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte ** types use so much data space that there can only be 4096 and 32 of ** them, respectively. So the maximum header length results from a ** 3-byte type for each of the maximum of 32768 columns plus three ** extra bytes for the header length itself. 32768*3 + 3 = 98307. */ if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){ goto op_column_corrupt; } }else{ /* This is an optimization. By skipping over the first few tests ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a ** measurable performance gain. ** ** This branch is taken even if aOffset[0]==0. Such a record is never ** generated by SQLite, and could be considered corruption, but we ** accept it for historical reasons. When aOffset[0]==0, the code this ** branch jumps to reads past the end of the record, but never more ** than a few bytes. Even if the record occurs at the end of the page ** content area, the "page header" comes after the page content and so ** this overread is harmless. Similar overreads can occur for a corrupt ** database file. */ zData = pC->aRow; assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ testcase( aOffset[0]==0 ); goto op_column_read_header; } }else if( sqlite3BtreeCursorHasMoved(pC->uc.pCursor) ){ rc = sqlite3VdbeHandleMovedCursor(pC); if( rc ) goto abort_due_to_error; goto op_column_restart; } /* Make sure at least the first p2+1 entries of the header have been ** parsed and valid information is in aOffset[] and pC->aType[]. */ if( pC->nHdrParsed<=p2 ){ /* If there is more header available for parsing in the record, try ** to extract additional fields up through the p2+1-th field */ if( pC->iHdrOffsetaRow==0 ){ memset(&sMem, 0, sizeof(sMem)); rc = sqlite3VdbeMemFromBtreeZeroOffset(pC->uc.pCursor,aOffset[0],&sMem); if( rc!=SQLITE_OK ) goto abort_due_to_error; zData = (u8*)sMem.z; }else{ zData = pC->aRow; } /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */ op_column_read_header: i = pC->nHdrParsed; offset64 = aOffset[i]; zHdr = zData + pC->iHdrOffset; zEndHdr = zData + aOffset[0]; testcase( zHdr>=zEndHdr ); do{ if( (pC->aType[i] = t = zHdr[0])<0x80 ){ zHdr++; offset64 += sqlite3VdbeOneByteSerialTypeLen(t); }else{ zHdr += sqlite3GetVarint32(zHdr, &t); pC->aType[i] = t; offset64 += sqlite3VdbeSerialTypeLen(t); } aOffset[++i] = (u32)(offset64 & 0xffffffff); }while( (u32)i<=p2 && zHdr=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize)) || (offset64 > pC->payloadSize) ){ if( aOffset[0]==0 ){ i = 0; zHdr = zEndHdr; }else{ if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); goto op_column_corrupt; } } pC->nHdrParsed = i; pC->iHdrOffset = (u32)(zHdr - zData); if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); }else{ t = 0; } /* If after trying to extract new entries from the header, nHdrParsed is ** still not up to p2, that means that the record has fewer than p2 ** columns. So the result will be either the default value or a NULL. */ if( pC->nHdrParsed<=p2 ){ pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); if( pOp->p4type==P4_MEM ){ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); }else{ sqlite3VdbeMemSetNull(pDest); } goto op_column_out; } }else{ t = pC->aType[p2]; } /* Extract the content for the p2+1-th column. Control can only ** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are ** all valid. */ assert( p2nHdrParsed ); assert( rc==SQLITE_OK ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); assert( sqlite3VdbeCheckMemInvariants(pDest) ); if( VdbeMemDynamic(pDest) ){ sqlite3VdbeMemSetNull(pDest); } assert( t==pC->aType[p2] ); if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ zData = pC->aRow + aOffset[p2]; if( t<12 ){ sqlite3VdbeSerialGet(zData, t, pDest); }else{ /* If the column value is a string, we need a persistent value, not ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). */ static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; pDest->n = len = (t-12)/2; pDest->enc = encoding; if( pDest->szMalloc < len+2 ){ if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) goto too_big; pDest->flags = MEM_Null; if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; }else{ pDest->z = pDest->zMalloc; } memcpy(pDest->z, zData, len); pDest->z[len] = 0; pDest->z[len+1] = 0; pDest->flags = aFlag[t&1]; } }else{ u8 p5; pDest->enc = encoding; assert( pDest->db==db ); /* This branch happens only when content is on overflow pages */ if( ((p5 = (pOp->p5 & OPFLAG_BYTELENARG))!=0 && (p5==OPFLAG_TYPEOFARG || (t>=12 && ((t&1)==0 || p5==OPFLAG_BYTELENARG)) ) ) || sqlite3VdbeSerialTypeLen(t)==0 ){ /* Content is irrelevant for ** 1. the typeof() function, ** 2. the length(X) function if X is a blob, and ** 3. if the content length is zero. ** So we might as well use bogus content rather than reading ** content from disk. ** ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the ** buffer passed to it, debugging function VdbeMemPrettyPrint() may ** read more. Use the global constant sqlite3CtypeMap[] as the array, ** as that array is 256 bytes long (plenty for VdbeMemPrettyPrint()) ** and it begins with a bunch of zeros. */ sqlite3VdbeSerialGet((u8*)sqlite3CtypeMap, t, pDest); }else{ rc = vdbeColumnFromOverflow(pC, p2, t, aOffset[p2], p->cacheCtr, colCacheCtr, pDest); if( rc ){ if( rc==SQLITE_NOMEM ) goto no_mem; if( rc==SQLITE_TOOBIG ) goto too_big; goto abort_due_to_error; } } } op_column_out: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); break; op_column_corrupt: if( aOp[0].p3>0 ){ pOp = &aOp[aOp[0].p3-1]; break; }else{ rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } } /* Opcode: TypeCheck P1 P2 P3 P4 * ** Synopsis: typecheck(r[P1@P2]) ** ** Apply affinities to the range of P2 registers beginning with P1. ** Take the affinities from the Table object in P4. If any value ** cannot be coerced into the correct type, then raise an error. ** ** This opcode is similar to OP_Affinity except that this opcode ** forces the register type to the Table column type. This is used ** to implement "strict affinity". ** ** GENERATED ALWAYS AS ... STATIC columns are only checked if P3 ** is zero. When P3 is non-zero, no type checking occurs for ** static generated columns. Virtual columns are computed at query time ** and so they are never checked. ** ** Preconditions: ** **
      **
    • P2 should be the number of non-virtual columns in the ** table of P4. **
    • Table P4 should be a STRICT table. **
    ** ** If any precondition is false, an assertion fault occurs. */ case OP_TypeCheck: { Table *pTab; Column *aCol; int i; assert( pOp->p4type==P4_TABLE ); pTab = pOp->p4.pTab; assert( pTab->tabFlags & TF_Strict ); assert( pTab->nNVCol==pOp->p2 ); aCol = pTab->aCol; pIn1 = &aMem[pOp->p1]; for(i=0; inCol; i++){ if( aCol[i].colFlags & COLFLAG_GENERATED ){ if( aCol[i].colFlags & COLFLAG_VIRTUAL ) continue; if( pOp->p3 ){ pIn1++; continue; } } assert( pIn1 < &aMem[pOp->p1+pOp->p2] ); applyAffinity(pIn1, aCol[i].affinity, encoding); if( (pIn1->flags & MEM_Null)==0 ){ switch( aCol[i].eCType ){ case COLTYPE_BLOB: { if( (pIn1->flags & MEM_Blob)==0 ) goto vdbe_type_error; break; } case COLTYPE_INTEGER: case COLTYPE_INT: { if( (pIn1->flags & MEM_Int)==0 ) goto vdbe_type_error; break; } case COLTYPE_TEXT: { if( (pIn1->flags & MEM_Str)==0 ) goto vdbe_type_error; break; } case COLTYPE_REAL: { testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_Real ); assert( (pIn1->flags & MEM_IntReal)==0 ); if( pIn1->flags & MEM_Int ){ /* When applying REAL affinity, if the result is still an MEM_Int ** that will fit in 6 bytes, then change the type to MEM_IntReal ** so that we keep the high-resolution integer value but know that ** the type really wants to be REAL. */ testcase( pIn1->u.i==140737488355328LL ); testcase( pIn1->u.i==140737488355327LL ); testcase( pIn1->u.i==-140737488355328LL ); testcase( pIn1->u.i==-140737488355329LL ); if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL){ pIn1->flags |= MEM_IntReal; pIn1->flags &= ~MEM_Int; }else{ pIn1->u.r = (double)pIn1->u.i; pIn1->flags |= MEM_Real; pIn1->flags &= ~MEM_Int; } }else if( (pIn1->flags & (MEM_Real|MEM_IntReal))==0 ){ goto vdbe_type_error; } break; } default: { /* COLTYPE_ANY. Accept anything. */ break; } } } REGISTER_TRACE((int)(pIn1-aMem), pIn1); pIn1++; } assert( pIn1 == &aMem[pOp->p1+pOp->p2] ); break; vdbe_type_error: sqlite3VdbeError(p, "cannot store %s value in %s column %s.%s", vdbeMemTypeName(pIn1), sqlite3StdType[aCol[i].eCType-1], pTab->zName, aCol[i].zCnName); rc = SQLITE_CONSTRAINT_DATATYPE; goto abort_due_to_error; } /* Opcode: Affinity P1 P2 * P4 * ** Synopsis: affinity(r[P1@P2]) ** ** Apply affinities to a range of P2 registers starting with P1. ** ** P4 is a string that is P2 characters long. The N-th character of the ** string indicates the column affinity that should be used for the N-th ** memory cell in the range. */ case OP_Affinity: { const char *zAffinity; /* The affinity to be applied */ zAffinity = pOp->p4.z; assert( zAffinity!=0 ); assert( pOp->p2>0 ); assert( zAffinity[pOp->p2]==0 ); pIn1 = &aMem[pOp->p1]; while( 1 /*exit-by-break*/ ){ assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] ); assert( zAffinity[0]==SQLITE_AFF_NONE || memIsValid(pIn1) ); applyAffinity(pIn1, zAffinity[0], encoding); if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){ /* When applying REAL affinity, if the result is still an MEM_Int ** that will fit in 6 bytes, then change the type to MEM_IntReal ** so that we keep the high-resolution integer value but know that ** the type really wants to be REAL. */ testcase( pIn1->u.i==140737488355328LL ); testcase( pIn1->u.i==140737488355327LL ); testcase( pIn1->u.i==-140737488355328LL ); testcase( pIn1->u.i==-140737488355329LL ); if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL ){ pIn1->flags |= MEM_IntReal; pIn1->flags &= ~MEM_Int; }else{ pIn1->u.r = (double)pIn1->u.i; pIn1->flags |= MEM_Real; pIn1->flags &= ~(MEM_Int|MEM_Str); } } REGISTER_TRACE((int)(pIn1-aMem), pIn1); zAffinity++; if( zAffinity[0]==0 ) break; pIn1++; } break; } /* Opcode: MakeRecord P1 P2 P3 P4 * ** Synopsis: r[P3]=mkrec(r[P1@P2]) ** ** Convert P2 registers beginning with P1 into the [record format] ** use as a data record in a database table or as a key ** in an index. The OP_Column opcode can decode the record later. ** ** P4 may be a string that is P2 characters long. The N-th character of the ** string indicates the column affinity that should be used for the N-th ** field of the index key. ** ** The mapping from character to affinity is given by the SQLITE_AFF_ ** macros defined in sqliteInt.h. ** ** If P4 is NULL then all index fields have the affinity BLOB. ** ** The meaning of P5 depends on whether or not the SQLITE_ENABLE_NULL_TRIM ** compile-time option is enabled: ** ** * If SQLITE_ENABLE_NULL_TRIM is enabled, then the P5 is the index ** of the right-most table that can be null-trimmed. ** ** * If SQLITE_ENABLE_NULL_TRIM is omitted, then P5 has the value ** OPFLAG_NOCHNG_MAGIC if the OP_MakeRecord opcode is allowed to ** accept no-change records with serial_type 10. This value is ** only used inside an assert() and does not affect the end result. */ case OP_MakeRecord: { Mem *pRec; /* The new record */ u64 nData; /* Number of bytes of data space */ int nHdr; /* Number of bytes of header space */ i64 nByte; /* Data space required for this record */ i64 nZero; /* Number of zero bytes at the end of the record */ int nVarint; /* Number of bytes in a varint */ u32 serial_type; /* Type field */ Mem *pData0; /* First field to be combined into the record */ Mem *pLast; /* Last field of the record */ int nField; /* Number of fields in the record */ char *zAffinity; /* The affinity string for the record */ u32 len; /* Length of a field */ u8 *zHdr; /* Where to write next byte of the header */ u8 *zPayload; /* Where to write next byte of the payload */ /* Assuming the record contains N fields, the record format looks ** like this: ** ** ------------------------------------------------------------------------ ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 | ** ------------------------------------------------------------------------ ** ** Data(0) is taken from register P1. Data(1) comes from register P1+1 ** and so forth. ** ** Each type field is a varint representing the serial type of the ** corresponding data element (see sqlite3VdbeSerialType()). The ** hdr-size field is also a varint which is the offset from the beginning ** of the record to data0. */ nData = 0; /* Number of bytes of data space */ nHdr = 0; /* Number of bytes of header space */ nZero = 0; /* Number of zero bytes at the end of the record */ nField = pOp->p1; zAffinity = pOp->p4.z; assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1 ); pData0 = &aMem[nField]; nField = pOp->p2; pLast = &pData0[nField-1]; /* Identify the output register */ assert( pOp->p3p1 || pOp->p3>=pOp->p1+pOp->p2 ); pOut = &aMem[pOp->p3]; memAboutToChange(p, pOut); /* Apply the requested affinity to all inputs */ assert( pData0<=pLast ); if( zAffinity ){ pRec = pData0; do{ applyAffinity(pRec, zAffinity[0], encoding); if( zAffinity[0]==SQLITE_AFF_REAL && (pRec->flags & MEM_Int) ){ pRec->flags |= MEM_IntReal; pRec->flags &= ~(MEM_Int); } REGISTER_TRACE((int)(pRec-aMem), pRec); zAffinity++; pRec++; assert( zAffinity[0]==0 || pRec<=pLast ); }while( zAffinity[0] ); } #ifdef SQLITE_ENABLE_NULL_TRIM /* NULLs can be safely trimmed from the end of the record, as long as ** as the schema format is 2 or more and none of the omitted columns ** have a non-NULL default value. Also, the record must be left with ** at least one field. If P5>0 then it will be one more than the ** index of the right-most column with a non-NULL default value */ if( pOp->p5 ){ while( (pLast->flags & MEM_Null)!=0 && nField>pOp->p5 ){ pLast--; nField--; } } #endif /* Loop through the elements that will make up the record to figure ** out how much space is required for the new record. After this loop, ** the Mem.uTemp field of each term should hold the serial-type that will ** be used for that term in the generated record: ** ** Mem.uTemp value type ** --------------- --------------- ** 0 NULL ** 1 1-byte signed integer ** 2 2-byte signed integer ** 3 3-byte signed integer ** 4 4-byte signed integer ** 5 6-byte signed integer ** 6 8-byte signed integer ** 7 IEEE float ** 8 Integer constant 0 ** 9 Integer constant 1 ** 10,11 reserved for expansion ** N>=12 and even BLOB ** N>=13 and odd text ** ** The following additional values are computed: ** nHdr Number of bytes needed for the record header ** nData Number of bytes of data space needed for the record ** nZero Zero bytes at the end of the record */ pRec = pLast; do{ assert( memIsValid(pRec) ); if( pRec->flags & MEM_Null ){ if( pRec->flags & MEM_Zero ){ /* Values with MEM_Null and MEM_Zero are created by xColumn virtual ** table methods that never invoke sqlite3_result_xxxxx() while ** computing an unchanging column value in an UPDATE statement. ** Give such values a special internal-use-only serial-type of 10 ** so that they can be passed through to xUpdate and have ** a true sqlite3_value_nochange(). */ #ifndef SQLITE_ENABLE_NULL_TRIM assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB ); #endif pRec->uTemp = 10; }else{ pRec->uTemp = 0; } nHdr++; }else if( pRec->flags & (MEM_Int|MEM_IntReal) ){ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ i64 i = pRec->u.i; u64 uu; testcase( pRec->flags & MEM_Int ); testcase( pRec->flags & MEM_IntReal ); if( i<0 ){ uu = ~i; }else{ uu = i; } nHdr++; testcase( uu==127 ); testcase( uu==128 ); testcase( uu==32767 ); testcase( uu==32768 ); testcase( uu==8388607 ); testcase( uu==8388608 ); testcase( uu==2147483647 ); testcase( uu==2147483648LL ); testcase( uu==140737488355327LL ); testcase( uu==140737488355328LL ); if( uu<=127 ){ if( (i&1)==i && p->minWriteFileFormat>=4 ){ pRec->uTemp = 8+(u32)uu; }else{ nData++; pRec->uTemp = 1; } }else if( uu<=32767 ){ nData += 2; pRec->uTemp = 2; }else if( uu<=8388607 ){ nData += 3; pRec->uTemp = 3; }else if( uu<=2147483647 ){ nData += 4; pRec->uTemp = 4; }else if( uu<=140737488355327LL ){ nData += 6; pRec->uTemp = 5; }else{ nData += 8; if( pRec->flags & MEM_IntReal ){ /* If the value is IntReal and is going to take up 8 bytes to store ** as an integer, then we might as well make it an 8-byte floating ** point value */ pRec->u.r = (double)pRec->u.i; pRec->flags &= ~MEM_IntReal; pRec->flags |= MEM_Real; pRec->uTemp = 7; }else{ pRec->uTemp = 6; } } }else if( pRec->flags & MEM_Real ){ nHdr++; nData += 8; pRec->uTemp = 7; }else{ assert( db->mallocFailed || pRec->flags&(MEM_Str|MEM_Blob) ); assert( pRec->n>=0 ); len = (u32)pRec->n; serial_type = (len*2) + 12 + ((pRec->flags & MEM_Str)!=0); if( pRec->flags & MEM_Zero ){ serial_type += pRec->u.nZero*2; if( nData ){ if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; len += pRec->u.nZero; }else{ nZero += pRec->u.nZero; } } nData += len; nHdr += sqlite3VarintLen(serial_type); pRec->uTemp = serial_type; } if( pRec==pData0 ) break; pRec--; }while(1); /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint ** which determines the total number of bytes in the header. The varint ** value is the size of the header in bytes including the size varint ** itself. */ testcase( nHdr==126 ); testcase( nHdr==127 ); if( nHdr<=126 ){ /* The common case */ nHdr += 1; }else{ /* Rare case of a really large header */ nVarint = sqlite3VarintLen(nHdr); nHdr += nVarint; if( nVarintp3) is not allowed to ** be one of the input registers (because the following call to ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used). */ if( nByte+nZero<=pOut->szMalloc ){ /* The output register is already large enough to hold the record. ** No error checks or buffer enlargement is required */ pOut->z = pOut->zMalloc; }else{ /* Need to make sure that the output is not too big and then enlarge ** the output register to hold the full result */ if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ goto no_mem; } } pOut->n = (int)nByte; pOut->flags = MEM_Blob; if( nZero ){ pOut->u.nZero = nZero; pOut->flags |= MEM_Zero; } UPDATE_MAX_BLOBSIZE(pOut); zHdr = (u8 *)pOut->z; zPayload = zHdr + nHdr; /* Write the record */ if( nHdr<0x80 ){ *(zHdr++) = nHdr; }else{ zHdr += sqlite3PutVarint(zHdr,nHdr); } assert( pData0<=pLast ); pRec = pData0; while( 1 /*exit-by-break*/ ){ serial_type = pRec->uTemp; /* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more ** additional varints, one per column. ** EVIDENCE-OF: R-64536-51728 The values for each column in the record ** immediately follow the header. */ if( serial_type<=7 ){ *(zHdr++) = serial_type; if( serial_type==0 ){ /* NULL value. No change in zPayload */ }else{ u64 v; if( serial_type==7 ){ assert( sizeof(v)==sizeof(pRec->u.r) ); memcpy(&v, &pRec->u.r, sizeof(v)); swapMixedEndianFloat(v); }else{ v = pRec->u.i; } len = sqlite3SmallTypeSizes[serial_type]; assert( len>=1 && len<=8 && len!=5 && len!=7 ); switch( len ){ default: zPayload[7] = (u8)(v&0xff); v >>= 8; zPayload[6] = (u8)(v&0xff); v >>= 8; case 6: zPayload[5] = (u8)(v&0xff); v >>= 8; zPayload[4] = (u8)(v&0xff); v >>= 8; case 4: zPayload[3] = (u8)(v&0xff); v >>= 8; case 3: zPayload[2] = (u8)(v&0xff); v >>= 8; case 2: zPayload[1] = (u8)(v&0xff); v >>= 8; case 1: zPayload[0] = (u8)(v&0xff); } zPayload += len; } }else if( serial_type<0x80 ){ *(zHdr++) = serial_type; if( serial_type>=14 && pRec->n>0 ){ assert( pRec->z!=0 ); memcpy(zPayload, pRec->z, pRec->n); zPayload += pRec->n; } }else{ zHdr += sqlite3PutVarint(zHdr, serial_type); if( pRec->n ){ assert( pRec->z!=0 ); memcpy(zPayload, pRec->z, pRec->n); zPayload += pRec->n; } } if( pRec==pLast ) break; pRec++; } assert( nHdr==(int)(zHdr - (u8*)pOut->z) ); assert( nByte==(int)(zPayload - (u8*)pOut->z) ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); REGISTER_TRACE(pOp->p3, pOut); break; } /* Opcode: Count P1 P2 P3 * * ** Synopsis: r[P2]=count() ** ** Store the number of entries (an integer value) in the table or index ** opened by cursor P1 in register P2. ** ** If P3==0, then an exact count is obtained, which involves visiting ** every btree page of the table. But if P3 is non-zero, an estimate ** is returned based on the current cursor position. */ case OP_Count: { /* out2 */ i64 nEntry; BtCursor *pCrsr; assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE ); pCrsr = p->apCsr[pOp->p1]->uc.pCursor; assert( pCrsr ); if( pOp->p3 ){ nEntry = sqlite3BtreeRowCountEst(pCrsr); }else{ nEntry = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3BtreeCount(db, pCrsr, &nEntry); if( rc ) goto abort_due_to_error; } pOut = out2Prerelease(p, pOp); pOut->u.i = nEntry; goto check_for_interrupt; } /* Opcode: Savepoint P1 * * P4 * ** ** Open, release or rollback the savepoint named by parameter P4, depending ** on the value of P1. To open a new savepoint set P1==0 (SAVEPOINT_BEGIN). ** To release (commit) an existing savepoint set P1==1 (SAVEPOINT_RELEASE). ** To rollback an existing savepoint set P1==2 (SAVEPOINT_ROLLBACK). */ case OP_Savepoint: { int p1; /* Value of P1 operand */ char *zName; /* Name of savepoint */ int nName; Savepoint *pNew; Savepoint *pSavepoint; Savepoint *pTmp; int iSavepoint; int ii; p1 = pOp->p1; zName = pOp->p4.z; /* Assert that the p1 parameter is valid. Also that if there is no open ** transaction, then there cannot be any savepoints. */ assert( db->pSavepoint==0 || db->autoCommit==0 ); assert( p1==SAVEPOINT_BEGIN||p1==SAVEPOINT_RELEASE||p1==SAVEPOINT_ROLLBACK ); assert( db->pSavepoint || db->isTransactionSavepoint==0 ); assert( checkSavepointCount(db) ); assert( p->bIsReader ); if( p1==SAVEPOINT_BEGIN ){ if( db->nVdbeWrite>0 ){ /* A new savepoint cannot be created if there are active write ** statements (i.e. open read/write incremental blob handles). */ sqlite3VdbeError(p, "cannot open savepoint - SQL statements in progress"); rc = SQLITE_BUSY; }else{ nName = sqlite3Strlen30(zName); #ifndef SQLITE_OMIT_VIRTUALTABLE /* This call is Ok even if this savepoint is actually a transaction ** savepoint (and therefore should not prompt xSavepoint()) callbacks. ** If this is a transaction savepoint being opened, it is guaranteed ** that the db->aVTrans[] array is empty. */ assert( db->autoCommit==0 || db->nVTrans==0 ); rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, db->nStatement+db->nSavepoint); if( rc!=SQLITE_OK ) goto abort_due_to_error; #endif /* Create a new savepoint structure. */ pNew = sqlite3DbMallocRawNN(db, sizeof(Savepoint)+nName+1); if( pNew ){ pNew->zName = (char *)&pNew[1]; memcpy(pNew->zName, zName, nName+1); /* If there is no open transaction, then mark this as a special ** "transaction savepoint". */ if( db->autoCommit ){ db->autoCommit = 0; db->isTransactionSavepoint = 1; }else{ db->nSavepoint++; } /* Link the new savepoint into the database handle's list. */ pNew->pNext = db->pSavepoint; db->pSavepoint = pNew; pNew->nDeferredCons = db->nDeferredCons; pNew->nDeferredImmCons = db->nDeferredImmCons; } } }else{ assert( p1==SAVEPOINT_RELEASE || p1==SAVEPOINT_ROLLBACK ); iSavepoint = 0; /* Find the named savepoint. If there is no such savepoint, then an ** an error is returned to the user. */ for( pSavepoint = db->pSavepoint; pSavepoint && sqlite3StrICmp(pSavepoint->zName, zName); pSavepoint = pSavepoint->pNext ){ iSavepoint++; } if( !pSavepoint ){ sqlite3VdbeError(p, "no such savepoint: %s", zName); rc = SQLITE_ERROR; }else if( db->nVdbeWrite>0 && p1==SAVEPOINT_RELEASE ){ /* It is not possible to release (commit) a savepoint if there are ** active write statements. */ sqlite3VdbeError(p, "cannot release savepoint - " "SQL statements in progress"); rc = SQLITE_BUSY; }else{ /* Determine whether or not this is a transaction savepoint. If so, ** and this is a RELEASE command, then the current transaction ** is committed. */ int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint; if( isTransaction && p1==SAVEPOINT_RELEASE ){ if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ goto vdbe_return; } db->autoCommit = 1; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = 0; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } rc = p->rc; if( rc ){ db->autoCommit = 0; }else{ db->isTransactionSavepoint = 0; } }else{ int isSchemaChange; iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0; for(ii=0; iinDb; ii++){ rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT_ROLLBACK, isSchemaChange==0); if( rc!=SQLITE_OK ) goto abort_due_to_error; } }else{ assert( p1==SAVEPOINT_RELEASE ); isSchemaChange = 0; } for(ii=0; iinDb; ii++){ rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } if( isSchemaChange ){ sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); db->mDbFlags |= DBFLAG_SchemaChange; } } if( rc ) goto abort_due_to_error; /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all ** savepoints nested inside of the savepoint being operated on. */ while( db->pSavepoint!=pSavepoint ){ pTmp = db->pSavepoint; db->pSavepoint = pTmp->pNext; sqlite3DbFree(db, pTmp); db->nSavepoint--; } /* If it is a RELEASE, then destroy the savepoint being operated on ** too. If it is a ROLLBACK TO, then set the number of deferred ** constraint violations present in the database to the value stored ** when the savepoint was created. */ if( p1==SAVEPOINT_RELEASE ){ assert( pSavepoint==db->pSavepoint ); db->pSavepoint = pSavepoint->pNext; sqlite3DbFree(db, pSavepoint); if( !isTransaction ){ db->nSavepoint--; } }else{ assert( p1==SAVEPOINT_ROLLBACK ); db->nDeferredCons = pSavepoint->nDeferredCons; db->nDeferredImmCons = pSavepoint->nDeferredImmCons; } if( !isTransaction || p1==SAVEPOINT_ROLLBACK ){ rc = sqlite3VtabSavepoint(db, p1, iSavepoint); if( rc!=SQLITE_OK ) goto abort_due_to_error; } } } if( rc ) goto abort_due_to_error; if( p->eVdbeState==VDBE_HALT_STATE ){ rc = SQLITE_DONE; goto vdbe_return; } break; } /* Opcode: AutoCommit P1 P2 * * * ** ** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll ** back any currently active btree transactions. If there are any active ** VMs (apart from this one), then a ROLLBACK fails. A COMMIT fails if ** there are active writing VMs or active VMs that use shared cache. ** ** This instruction causes the VM to halt. */ case OP_AutoCommit: { int desiredAutoCommit; int iRollback; desiredAutoCommit = pOp->p1; iRollback = pOp->p2; assert( desiredAutoCommit==1 || desiredAutoCommit==0 ); assert( desiredAutoCommit==1 || iRollback==0 ); assert( db->nVdbeActive>0 ); /* At least this one VM is active */ assert( p->bIsReader ); if( desiredAutoCommit!=db->autoCommit ){ if( iRollback ){ assert( desiredAutoCommit==1 ); sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); db->autoCommit = 1; }else if( desiredAutoCommit && db->nVdbeWrite>0 ){ /* If this instruction implements a COMMIT and other VMs are writing ** return an error indicating that the other VMs must complete first. */ sqlite3VdbeError(p, "cannot commit transaction - " "SQL statements in progress"); rc = SQLITE_BUSY; goto abort_due_to_error; }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ goto vdbe_return; }else{ db->autoCommit = (u8)desiredAutoCommit; } if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = (u8)(1-desiredAutoCommit); p->rc = rc = SQLITE_BUSY; goto vdbe_return; } sqlite3CloseSavepoints(db); if( p->rc==SQLITE_OK ){ rc = SQLITE_DONE; }else{ rc = SQLITE_ERROR; } goto vdbe_return; }else{ sqlite3VdbeError(p, (!desiredAutoCommit)?"cannot start a transaction within a transaction":( (iRollback)?"cannot rollback - no transaction is active": "cannot commit - no transaction is active")); rc = SQLITE_ERROR; goto abort_due_to_error; } /*NOTREACHED*/ assert(0); } /* Opcode: Transaction P1 P2 P3 P4 P5 ** ** Begin a transaction on database P1 if a transaction is not already ** active. ** If P2 is non-zero, then a write-transaction is started, or if a ** read-transaction is already active, it is upgraded to a write-transaction. ** If P2 is zero, then a read-transaction is started. If P2 is 2 or more ** then an exclusive transaction is started. ** ** P1 is the index of the database file on which the transaction is ** started. Index 0 is the main database file and index 1 is the ** file used for temporary tables. Indices of 2 or more are used for ** attached databases. ** ** If a write-transaction is started and the Vdbe.usesStmtJournal flag is ** true (this flag is set if the Vdbe may modify more than one row and may ** throw an ABORT exception), a statement transaction may also be opened. ** More specifically, a statement transaction is opened iff the database ** connection is currently not in autocommit mode, or if there are other ** active statements. A statement transaction allows the changes made by this ** VDBE to be rolled back after an error without having to roll back the ** entire transaction. If no error is encountered, the statement transaction ** will automatically commit when the VDBE halts. ** ** If P5!=0 then this opcode also checks the schema cookie against P3 ** and the schema generation counter against P4. ** The cookie changes its value whenever the database schema changes. ** This operation is used to detect when that the cookie has changed ** and that the current process needs to reread the schema. If the schema ** cookie in P3 differs from the schema cookie in the database header or ** if the schema generation counter in P4 differs from the current ** generation counter, then an SQLITE_SCHEMA error is raised and execution ** halts. The sqlite3_step() wrapper function might then reprepare the ** statement and rerun it from the beginning. */ case OP_Transaction: { Btree *pBt; Db *pDb; int iMeta = 0; assert( p->bIsReader ); assert( p->readOnly==0 || pOp->p2==0 ); assert( pOp->p2>=0 && pOp->p2<=2 ); assert( pOp->p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( rc==SQLITE_OK ); if( pOp->p2 && (db->flags & (SQLITE_QueryOnly|SQLITE_CorruptRdOnly))!=0 ){ if( db->flags & SQLITE_QueryOnly ){ /* Writes prohibited by the "PRAGMA query_only=TRUE" statement */ rc = SQLITE_READONLY; }else{ /* Writes prohibited due to a prior SQLITE_CORRUPT in the current ** transaction */ rc = SQLITE_CORRUPT; } goto abort_due_to_error; } pDb = &db->aDb[pOp->p1]; pBt = pDb->pBt; if( pBt ){ rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, &iMeta); testcase( rc==SQLITE_BUSY_SNAPSHOT ); testcase( rc==SQLITE_BUSY_RECOVERY ); if( rc!=SQLITE_OK ){ if( (rc&0xff)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); p->rc = rc; goto vdbe_return; } goto abort_due_to_error; } if( p->usesStmtJournal && pOp->p2 && (db->autoCommit==0 || db->nVdbeRead>1) ){ assert( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); db->nStatement++; p->iStatement = db->nSavepoint + db->nStatement; } rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement-1); if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); } /* Store the current value of the database handles deferred constraint ** counter. If the statement transaction needs to be rolled back, ** the value of this counter needs to be restored too. */ p->nStmtDefCons = db->nDeferredCons; p->nStmtDefImmCons = db->nDeferredImmCons; } } assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); if( rc==SQLITE_OK && pOp->p5 && (iMeta!=pOp->p3 || pDb->pSchema->iGeneration!=pOp->p4.i) ){ /* ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema ** version is checked to ensure that the schema has not changed since the ** SQL statement was prepared. */ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); /* If the schema-cookie from the database file matches the cookie ** stored with the in-memory representation of the schema, do ** not reload the schema from the database file. ** ** If virtual-tables are in use, this is not just an optimization. ** Often, v-tables store their data in other SQLite tables, which ** are queried from within xNext() and other v-table methods using ** prepared queries. If such a query is out-of-date, we do not want to ** discard the database schema, as the user code implementing the ** v-table would have to be ready for the sqlite3_vtab structure itself ** to be invalidated whenever sqlite3_step() is called from within ** a v-table method. */ if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ sqlite3ResetOneSchema(db, pOp->p1); } p->expired = 1; rc = SQLITE_SCHEMA; /* Set changeCntOn to 0 to prevent the value returned by sqlite3_changes() ** from being modified in sqlite3VdbeHalt(). If this statement is ** reprepared, changeCntOn will be set again. */ p->changeCntOn = 0; } if( rc ) goto abort_due_to_error; break; } /* Opcode: ReadCookie P1 P2 P3 * * ** ** Read cookie number P3 from database P1 and write it into register P2. ** P3==1 is the schema version. P3==2 is the database format. ** P3==3 is the recommended pager cache size, and so forth. P1==0 is ** the main database file and P1==1 is the database file used to store ** temporary tables. ** ** There must be a read-lock on the database (either a transaction ** must be started or there must be an open cursor) before ** executing this instruction. */ case OP_ReadCookie: { /* out2 */ int iMeta; int iDb; int iCookie; assert( p->bIsReader ); iDb = pOp->p1; iCookie = pOp->p3; assert( pOp->p3=0 && iDbnDb ); assert( db->aDb[iDb].pBt!=0 ); assert( DbMaskTest(p->btreeMask, iDb) ); sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); pOut = out2Prerelease(p, pOp); pOut->u.i = iMeta; break; } /* Opcode: SetCookie P1 P2 P3 * P5 ** ** Write the integer value P3 into cookie number P2 of database P1. ** P2==1 is the schema version. P2==2 is the database format. ** P2==3 is the recommended pager cache ** size, and so forth. P1==0 is the main database file and P1==1 is the ** database file used to store temporary tables. ** ** A transaction must be started before executing this opcode. ** ** If P2 is the SCHEMA_VERSION cookie (cookie number 1) then the internal ** schema version is set to P3-P5. The "PRAGMA schema_version=N" statement ** has P5 set to 1, so that the internal schema version will be different ** from the database schema version, resulting in a schema reset. */ case OP_SetCookie: { Db *pDb; sqlite3VdbeIncrWriteCounter(p, 0); assert( pOp->p2p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); /* See note about index shifting on OP_ReadCookie */ rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3); if( pOp->p2==BTREE_SCHEMA_VERSION ){ /* When the schema cookie changes, record the new cookie internally */ *(u32*)&pDb->pSchema->schema_cookie = *(u32*)&pOp->p3 - pOp->p5; db->mDbFlags |= DBFLAG_SchemaChange; sqlite3FkClearTriggerCache(db, pOp->p1); }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ pDb->pSchema->file_format = pOp->p3; } if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database ** schema is changed. Ticket #1644 */ sqlite3ExpirePreparedStatements(db, 0); p->expired = 0; } if( rc ) goto abort_due_to_error; break; } /* Opcode: OpenRead P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** ** Open a read-only cursor for the database table whose root page is ** P2 in a database file. The database file is determined by P3. ** P3==0 means the main database, P3==1 means the database used for ** temporary tables, and P3>1 means used the corresponding attached ** database. Give the new cursor an identifier of P1. The P1 ** values need not be contiguous but all P1 values should be small integers. ** It is an error for P1 to be negative. ** ** Allowed P5 bits: **
      **
    • 0x02 OPFLAG_SEEKEQ: This cursor will only be used for ** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT ** of OP_SeekLE/OP_IdxLT) **
    ** ** The P4 value may be either an integer (P4_INT32) or a pointer to ** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo ** object, then table being opened must be an [index b-tree] where the ** KeyInfo object defines the content and collating ** sequence of that index b-tree. Otherwise, if P4 is an integer ** value, then the table being opened must be a [table b-tree] with a ** number of columns no less than the value of P4. ** ** See also: OpenWrite, ReopenIdx */ /* Opcode: ReopenIdx P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** ** The ReopenIdx opcode works like OP_OpenRead except that it first ** checks to see if the cursor on P1 is already open on the same ** b-tree and if it is this opcode becomes a no-op. In other words, ** if the cursor is already open, do not reopen it. ** ** The ReopenIdx opcode may only be used with P5==0 or P5==OPFLAG_SEEKEQ ** and with P4 being a P4_KEYINFO object. Furthermore, the P3 value must ** be the same as every other ReopenIdx or OpenRead for the same cursor ** number. ** ** Allowed P5 bits: **
      **
    • 0x02 OPFLAG_SEEKEQ: This cursor will only be used for ** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT ** of OP_SeekLE/OP_IdxLT) **
    ** ** See also: OP_OpenRead, OP_OpenWrite */ /* Opcode: OpenWrite P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** ** Open a read/write cursor named P1 on the table or index whose root ** page is P2 (or whose root page is held in register P2 if the ** OPFLAG_P2ISREG bit is set in P5 - see below). ** ** The P4 value may be either an integer (P4_INT32) or a pointer to ** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo ** object, then table being opened must be an [index b-tree] where the ** KeyInfo object defines the content and collating ** sequence of that index b-tree. Otherwise, if P4 is an integer ** value, then the table being opened must be a [table b-tree] with a ** number of columns no less than the value of P4. ** ** Allowed P5 bits: **
      **
    • 0x02 OPFLAG_SEEKEQ: This cursor will only be used for ** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT ** of OP_SeekLE/OP_IdxLT) **
    • 0x08 OPFLAG_FORDELETE: This cursor is used only to seek ** and subsequently delete entries in an index btree. This is a ** hint to the storage engine that the storage engine is allowed to ** ignore. The hint is not used by the official SQLite b*tree storage ** engine, but is used by COMDB2. **
    • 0x10 OPFLAG_P2ISREG: Use the content of register P2 ** as the root page, not the value of P2 itself. **
    ** ** This instruction works like OpenRead except that it opens the cursor ** in read/write mode. ** ** See also: OP_OpenRead, OP_ReopenIdx */ case OP_ReopenIdx: { /* ncycle */ int nField; KeyInfo *pKeyInfo; u32 p2; int iDb; int wrFlag; Btree *pX; VdbeCursor *pCur; Db *pDb; assert( pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); assert( pOp->p4type==P4_KEYINFO ); pCur = p->apCsr[pOp->p1]; if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){ assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */ assert( pCur->eCurType==CURTYPE_BTREE ); sqlite3BtreeClearCursor(pCur->uc.pCursor); goto open_cursor_set_hints; } /* If the cursor is not currently open or is open on a different ** index, then fall through into OP_OpenRead to force a reopen */ case OP_OpenRead: /* ncycle */ case OP_OpenWrite: assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); assert( p->bIsReader ); assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx || p->readOnly==0 ); if( p->expired==1 ){ rc = SQLITE_ABORT_ROLLBACK; goto abort_due_to_error; } nField = 0; pKeyInfo = 0; p2 = (u32)pOp->p2; iDb = pOp->p3; assert( iDb>=0 && iDbnDb ); assert( DbMaskTest(p->btreeMask, iDb) ); pDb = &db->aDb[iDb]; pX = pDb->pBt; assert( pX!=0 ); if( pOp->opcode==OP_OpenWrite ){ assert( OPFLAG_FORDELETE==BTREE_FORDELETE ); wrFlag = BTREE_WRCSR | (pOp->p5 & OPFLAG_FORDELETE); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( pDb->pSchema->file_format < p->minWriteFileFormat ){ p->minWriteFileFormat = pDb->pSchema->file_format; } }else{ wrFlag = 0; } if( pOp->p5 & OPFLAG_P2ISREG ){ assert( p2>0 ); assert( p2<=(u32)(p->nMem+1 - p->nCursor) ); assert( pOp->opcode==OP_OpenWrite ); pIn2 = &aMem[p2]; assert( memIsValid(pIn2) ); assert( (pIn2->flags & MEM_Int)!=0 ); sqlite3VdbeMemIntegerify(pIn2); p2 = (int)pIn2->u.i; /* The p2 value always comes from a prior OP_CreateBtree opcode and ** that opcode will always set the p2 value to 2 or more or else fail. ** If there were a failure, the prepared statement would have halted ** before reaching this instruction. */ assert( p2>=2 ); } if( pOp->p4type==P4_KEYINFO ){ pKeyInfo = pOp->p4.pKeyInfo; assert( pKeyInfo->enc==ENC(db) ); assert( pKeyInfo->db==db ); nField = pKeyInfo->nAllField; }else if( pOp->p4type==P4_INT32 ){ nField = pOp->p4.i; } assert( pOp->p1>=0 ); assert( nField>=0 ); testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */ pCur = allocateCursor(p, pOp->p1, nField, CURTYPE_BTREE); if( pCur==0 ) goto no_mem; pCur->iDb = iDb; pCur->nullRow = 1; pCur->isOrdered = 1; pCur->pgnoRoot = p2; #ifdef SQLITE_DEBUG pCur->wrFlag = wrFlag; #endif rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor); pCur->pKeyInfo = pKeyInfo; /* Set the VdbeCursor.isTable variable. Previous versions of ** SQLite used to check if the root-page flags were sane at this point ** and report database corruption if they were not, but this check has ** since moved into the btree layer. */ pCur->isTable = pOp->p4type!=P4_KEYINFO; open_cursor_set_hints: assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ ); testcase( pOp->p5 & OPFLAG_BULKCSR ); testcase( pOp->p2 & OPFLAG_SEEKEQ ); sqlite3BtreeCursorHintFlags(pCur->uc.pCursor, (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ))); if( rc ) goto abort_due_to_error; break; } /* Opcode: OpenDup P1 P2 * * * ** ** Open a new cursor P1 that points to the same ephemeral table as ** cursor P2. The P2 cursor must have been opened by a prior OP_OpenEphemeral ** opcode. Only ephemeral cursors may be duplicated. ** ** Duplicate ephemeral cursors are used for self-joins of materialized views. */ case OP_OpenDup: { /* ncycle */ VdbeCursor *pOrig; /* The original cursor to be duplicated */ VdbeCursor *pCx; /* The new cursor */ pOrig = p->apCsr[pOp->p2]; assert( pOrig ); assert( pOrig->isEphemeral ); /* Only ephemeral cursors can be duplicated */ pCx = allocateCursor(p, pOp->p1, pOrig->nField, CURTYPE_BTREE); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; pCx->isEphemeral = 1; pCx->pKeyInfo = pOrig->pKeyInfo; pCx->isTable = pOrig->isTable; pCx->pgnoRoot = pOrig->pgnoRoot; pCx->isOrdered = pOrig->isOrdered; pCx->ub.pBtx = pOrig->ub.pBtx; pCx->noReuse = 1; pOrig->noReuse = 1; rc = sqlite3BtreeCursor(pCx->ub.pBtx, pCx->pgnoRoot, BTREE_WRCSR, pCx->pKeyInfo, pCx->uc.pCursor); /* The sqlite3BtreeCursor() routine can only fail for the first cursor ** opened for a database. Since there is already an open cursor when this ** opcode is run, the sqlite3BtreeCursor() cannot fail */ assert( rc==SQLITE_OK ); break; } /* Opcode: OpenEphemeral P1 P2 P3 P4 P5 ** Synopsis: nColumn=P2 ** ** Open a new cursor P1 to a transient table. ** The cursor is always opened read/write even if ** the main database is read-only. The ephemeral ** table is deleted automatically when the cursor is closed. ** ** If the cursor P1 is already opened on an ephemeral table, the table ** is cleared (all content is erased). ** ** P2 is the number of columns in the ephemeral table. ** The cursor points to a BTree table if P4==0 and to a BTree index ** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure ** that defines the format of keys in the index. ** ** The P5 parameter can be a mask of the BTREE_* flags defined ** in btree.h. These flags control aspects of the operation of ** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are ** added automatically. ** ** If P3 is positive, then reg[P3] is modified slightly so that it ** can be used as zero-length data for OP_Insert. This is an optimization ** that avoids an extra OP_Blob opcode to initialize that register. */ /* Opcode: OpenAutoindex P1 P2 * P4 * ** Synopsis: nColumn=P2 ** ** This opcode works the same as OP_OpenEphemeral. It has a ** different name to distinguish its use. Tables created using ** by this opcode will be used for automatically created transient ** indices in joins. */ case OP_OpenAutoindex: /* ncycle */ case OP_OpenEphemeral: { /* ncycle */ VdbeCursor *pCx; KeyInfo *pKeyInfo; static const int vfsFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_TRANSIENT_DB; assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); if( pOp->p3>0 ){ /* Make register reg[P3] into a value that can be used as the data ** form sqlite3BtreeInsert() where the length of the data is zero. */ assert( pOp->p2==0 ); /* Only used when number of columns is zero */ assert( pOp->opcode==OP_OpenEphemeral ); assert( aMem[pOp->p3].flags & MEM_Null ); aMem[pOp->p3].n = 0; aMem[pOp->p3].z = ""; } pCx = p->apCsr[pOp->p1]; if( pCx && !pCx->noReuse && ALWAYS(pOp->p2<=pCx->nField) ){ /* If the ephemeral table is already open and has no duplicates from ** OP_OpenDup, then erase all existing content so that the table is ** empty again, rather than creating a new table. */ assert( pCx->isEphemeral ); pCx->seqCount = 0; pCx->cacheStatus = CACHE_STALE; rc = sqlite3BtreeClearTable(pCx->ub.pBtx, pCx->pgnoRoot, 0); }else{ pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_BTREE); if( pCx==0 ) goto no_mem; pCx->isEphemeral = 1; rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->ub.pBtx, BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginTrans(pCx->ub.pBtx, 1, 0); if( rc==SQLITE_OK ){ /* If a transient index is required, create it by calling ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before ** opening it. If a transient table is required, just use the ** automatically created table with root-page 1 (an BLOB_INTKEY table). */ if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){ assert( pOp->p4type==P4_KEYINFO ); rc = sqlite3BtreeCreateTable(pCx->ub.pBtx, &pCx->pgnoRoot, BTREE_BLOBKEY | pOp->p5); if( rc==SQLITE_OK ){ assert( pCx->pgnoRoot==SCHEMA_ROOT+1 ); assert( pKeyInfo->db==db ); assert( pKeyInfo->enc==ENC(db) ); rc = sqlite3BtreeCursor(pCx->ub.pBtx, pCx->pgnoRoot, BTREE_WRCSR, pKeyInfo, pCx->uc.pCursor); } pCx->isTable = 0; }else{ pCx->pgnoRoot = SCHEMA_ROOT; rc = sqlite3BtreeCursor(pCx->ub.pBtx, SCHEMA_ROOT, BTREE_WRCSR, 0, pCx->uc.pCursor); pCx->isTable = 1; } } pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); if( rc ){ sqlite3BtreeClose(pCx->ub.pBtx); } } } if( rc ) goto abort_due_to_error; pCx->nullRow = 1; break; } /* Opcode: SorterOpen P1 P2 P3 P4 * ** ** This opcode works like OP_OpenEphemeral except that it opens ** a transient index that is specifically designed to sort large ** tables using an external merge-sort algorithm. ** ** If argument P3 is non-zero, then it indicates that the sorter may ** assume that a stable sort considering the first P3 fields of each ** key is sufficient to produce the required results. */ case OP_SorterOpen: { VdbeCursor *pCx; assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_SORTER); if( pCx==0 ) goto no_mem; pCx->pKeyInfo = pOp->p4.pKeyInfo; assert( pCx->pKeyInfo->db==db ); assert( pCx->pKeyInfo->enc==ENC(db) ); rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx); if( rc ) goto abort_due_to_error; break; } /* Opcode: SequenceTest P1 P2 * * * ** Synopsis: if( cursor[P1].ctr++ ) pc = P2 ** ** P1 is a sorter cursor. If the sequence counter is currently zero, jump ** to P2. Regardless of whether or not the jump is taken, increment the ** the sequence value. */ case OP_SequenceTest: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); if( (pC->seqCount++)==0 ){ goto jump_to_p2; } break; } /* Opcode: OpenPseudo P1 P2 P3 * * ** Synopsis: P3 columns in r[P2] ** ** Open a new cursor that points to a fake table that contains a single ** row of data. The content of that one row is the content of memory ** register P2. In other words, cursor P1 becomes an alias for the ** MEM_Blob content contained in register P2. ** ** A pseudo-table created by this opcode is used to hold a single ** row output from the sorter so that the row can be decomposed into ** individual columns using the OP_Column opcode. The OP_Column opcode ** is the only cursor opcode that works with a pseudo-table. ** ** P3 is the number of fields in the records that will be stored by ** the pseudo-table. */ case OP_OpenPseudo: { VdbeCursor *pCx; assert( pOp->p1>=0 ); assert( pOp->p3>=0 ); pCx = allocateCursor(p, pOp->p1, pOp->p3, CURTYPE_PSEUDO); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; pCx->seekResult = pOp->p2; pCx->isTable = 1; /* Give this pseudo-cursor a fake BtCursor pointer so that pCx ** can be safely passed to sqlite3VdbeCursorMoveto(). This avoids a test ** for pCx->eCurType==CURTYPE_BTREE inside of sqlite3VdbeCursorMoveto() ** which is a performance optimization */ pCx->uc.pCursor = sqlite3BtreeFakeValidCursor(); assert( pOp->p5==0 ); break; } /* Opcode: Close P1 * * * * ** ** Close a cursor previously opened as P1. If P1 is not ** currently open, this instruction is a no-op. */ case OP_Close: { /* ncycle */ assert( pOp->p1>=0 && pOp->p1nCursor ); sqlite3VdbeFreeCursor(p, p->apCsr[pOp->p1]); p->apCsr[pOp->p1] = 0; break; } #ifdef SQLITE_ENABLE_COLUMN_USED_MASK /* Opcode: ColumnsUsed P1 * * P4 * ** ** This opcode (which only exists if SQLite was compiled with ** SQLITE_ENABLE_COLUMN_USED_MASK) identifies which columns of the ** table or index for cursor P1 are used. P4 is a 64-bit integer ** (P4_INT64) in which the first 63 bits are one for each of the ** first 63 columns of the table or index that are actually used ** by the cursor. The high-order bit is set if any column after ** the 64th is used. */ case OP_ColumnsUsed: { VdbeCursor *pC; pC = p->apCsr[pOp->p1]; assert( pC->eCurType==CURTYPE_BTREE ); pC->maskUsed = *(u64*)pOp->p4.pI64; break; } #endif /* Opcode: SeekGE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), ** use the value in register P3 as the key. If cursor P1 refers ** to an SQL index, then P3 is the first in an array of P4 registers ** that are used as an unpacked index key. ** ** Reposition cursor P1 so that it points to the smallest entry that ** is greater than or equal to the key value. If there are no records ** greater than or equal to the key and P2 is not zero, then jump to P2. ** ** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this ** opcode will either land on a record that exactly matches the key, or ** else it will cause a jump to P2. When the cursor is OPFLAG_SEEKEQ, ** this opcode must be followed by an IdxLE opcode with the same arguments. ** The IdxGT opcode will be skipped if this opcode succeeds, but the ** IdxGT opcode will be used on subsequent loop iterations. The ** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this ** is an equality search. ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. ** ** See also: Found, NotFound, SeekLt, SeekGt, SeekLe */ /* Opcode: SeekGT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), ** use the value in register P3 as a key. If cursor P1 refers ** to an SQL index, then P3 is the first in an array of P4 registers ** that are used as an unpacked index key. ** ** Reposition cursor P1 so that it points to the smallest entry that ** is greater than the key value. If there are no records greater than ** the key and P2 is not zero, then jump to P2. ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. ** ** See also: Found, NotFound, SeekLt, SeekGe, SeekLe */ /* Opcode: SeekLT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), ** use the value in register P3 as a key. If cursor P1 refers ** to an SQL index, then P3 is the first in an array of P4 registers ** that are used as an unpacked index key. ** ** Reposition cursor P1 so that it points to the largest entry that ** is less than the key value. If there are no records less than ** the key and P2 is not zero, then jump to P2. ** ** This opcode leaves the cursor configured to move in reverse order, ** from the end toward the beginning. In other words, the cursor is ** configured to use Prev, not Next. ** ** See also: Found, NotFound, SeekGt, SeekGe, SeekLe */ /* Opcode: SeekLE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), ** use the value in register P3 as a key. If cursor P1 refers ** to an SQL index, then P3 is the first in an array of P4 registers ** that are used as an unpacked index key. ** ** Reposition cursor P1 so that it points to the largest entry that ** is less than or equal to the key value. If there are no records ** less than or equal to the key and P2 is not zero, then jump to P2. ** ** This opcode leaves the cursor configured to move in reverse order, ** from the end toward the beginning. In other words, the cursor is ** configured to use Prev, not Next. ** ** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this ** opcode will either land on a record that exactly matches the key, or ** else it will cause a jump to P2. When the cursor is OPFLAG_SEEKEQ, ** this opcode must be followed by an IdxLE opcode with the same arguments. ** The IdxGE opcode will be skipped if this opcode succeeds, but the ** IdxGE opcode will be used on subsequent loop iterations. The ** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this ** is an equality search. ** ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ case OP_SeekLT: /* jump, in3, group, ncycle */ case OP_SeekLE: /* jump, in3, group, ncycle */ case OP_SeekGE: /* jump, in3, group, ncycle */ case OP_SeekGT: { /* jump, in3, group, ncycle */ int res; /* Comparison result */ int oc; /* Opcode */ VdbeCursor *pC; /* The cursor to seek */ UnpackedRecord r; /* The key to seek for */ int nField; /* Number of columns or fields in the key */ i64 iKey; /* The rowid we are to seek to */ int eqOnly; /* Only interested in == results */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p2!=0 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( OP_SeekLE == OP_SeekLT+1 ); assert( OP_SeekGE == OP_SeekLT+2 ); assert( OP_SeekGT == OP_SeekLT+3 ); assert( pC->isOrdered ); assert( pC->uc.pCursor!=0 ); oc = pOp->opcode; eqOnly = 0; pC->nullRow = 0; #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; if( pC->isTable ){ u16 flags3, newType; /* The OPFLAG_SEEKEQ/BTREE_SEEK_EQ flag is only set on index cursors */ assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 || CORRUPT_DB ); /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; flags3 = pIn3->flags; if( (flags3 & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3, 0); } iKey = sqlite3VdbeIntValue(pIn3); /* Get the integer key value */ newType = pIn3->flags; /* Record the type after applying numeric affinity */ pIn3->flags = flags3; /* But convert the type back to its original */ /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ if( (newType & (MEM_Int|MEM_IntReal))==0 ){ int c; if( (newType & MEM_Real)==0 ){ if( (newType & MEM_Null) || oc>=OP_SeekGE ){ VdbeBranchTaken(1,2); goto jump_to_p2; }else{ rc = sqlite3BtreeLast(pC->uc.pCursor, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; goto seek_not_found; } } c = sqlite3IntFloatCompare(iKey, pIn3->u.r); /* If the approximation iKey is larger than the actual real search ** term, substitute >= for > and < for <=. e.g. if the search term ** is 4.9 and the integer approximation 5: ** ** (x > 4.9) -> (x >= 5) ** (x <= 4.9) -> (x < 5) */ if( c>0 ){ assert( OP_SeekGE==(OP_SeekGT-1) ); assert( OP_SeekLT==(OP_SeekLE-1) ); assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) ); if( (oc & 0x0001)==(OP_SeekGT & 0x0001) ) oc--; } /* If the approximation iKey is smaller than the actual real search ** term, substitute <= for < and > for >=. */ else if( c<0 ){ assert( OP_SeekLE==(OP_SeekLT+1) ); assert( OP_SeekGT==(OP_SeekGE+1) ); assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; } } rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } }else{ /* For a cursor with the OPFLAG_SEEKEQ/BTREE_SEEK_EQ hint, only the ** OP_SeekGE and OP_SeekLE opcodes are allowed, and these must be ** immediately followed by an OP_IdxGT or OP_IdxLT opcode, respectively, ** with the same key. */ if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){ eqOnly = 1; assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE ); assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); assert( pOp->opcode==OP_SeekGE || pOp[1].opcode==OP_IdxLT ); assert( pOp->opcode==OP_SeekLE || pOp[1].opcode==OP_IdxGT ); assert( pOp[1].p1==pOp[0].p1 ); assert( pOp[1].p2==pOp[0].p2 ); assert( pOp[1].p3==pOp[0].p3 ); assert( pOp[1].p4.i==pOp[0].p4.i ); } nField = pOp->p4.i; assert( pOp->p4type==P4_INT32 ); assert( nField>0 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)nField; /* The next line of code computes as follows, only faster: ** if( oc==OP_SeekGT || oc==OP_SeekLE ){ ** r.default_rc = -1; ** }else{ ** r.default_rc = +1; ** } */ r.default_rc = ((1 & (oc - OP_SeekLT)) ? -1 : +1); assert( oc!=OP_SeekGT || r.default_rc==-1 ); assert( oc!=OP_SeekLE || r.default_rc==-1 ); assert( oc!=OP_SeekGE || r.default_rc==+1 ); assert( oc!=OP_SeekLT || r.default_rc==+1 ); r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG { int i; for(i=0; i0 ) REGISTER_TRACE(pOp->p3+i, &r.aMem[i]); } } #endif r.eqSeen = 0; rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( eqOnly && r.eqSeen==0 ){ assert( res!=0 ); goto seek_not_found; } } #ifdef SQLITE_TEST sqlite3_search_count++; #endif if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT ); if( res<0 || (res==0 && oc==OP_SeekGT) ){ res = 0; rc = sqlite3BtreeNext(pC->uc.pCursor, 0); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; res = 1; }else{ goto abort_due_to_error; } } }else{ res = 0; } }else{ assert( oc==OP_SeekLT || oc==OP_SeekLE ); if( res>0 || (res==0 && oc==OP_SeekLT) ){ res = 0; rc = sqlite3BtreePrevious(pC->uc.pCursor, 0); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; res = 1; }else{ goto abort_due_to_error; } } }else{ /* res might be negative because the table is empty. Check to ** see if this is the case. */ res = sqlite3BtreeEof(pC->uc.pCursor); } } seek_not_found: assert( pOp->p2>0 ); VdbeBranchTaken(res!=0,2); if( res ){ goto jump_to_p2; }else if( eqOnly ){ assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); pOp++; /* Skip the OP_IdxLt or OP_IdxGT that follows */ } break; } /* Opcode: SeekScan P1 P2 * * P5 ** Synopsis: Scan-ahead up to P1 rows ** ** This opcode is a prefix opcode to OP_SeekGE. In other words, this ** opcode must be immediately followed by OP_SeekGE. This constraint is ** checked by assert() statements. ** ** This opcode uses the P1 through P4 operands of the subsequent ** OP_SeekGE. In the text that follows, the operands of the subsequent ** OP_SeekGE opcode are denoted as SeekOP.P1 through SeekOP.P4. Only ** the P1, P2 and P5 operands of this opcode are also used, and are called ** This.P1, This.P2 and This.P5. ** ** This opcode helps to optimize IN operators on a multi-column index ** where the IN operator is on the later terms of the index by avoiding ** unnecessary seeks on the btree, substituting steps to the next row ** of the b-tree instead. A correct answer is obtained if this opcode ** is omitted or is a no-op. ** ** The SeekGE.P3 and SeekGE.P4 operands identify an unpacked key which ** is the desired entry that we want the cursor SeekGE.P1 to be pointing ** to. Call this SeekGE.P3/P4 row the "target". ** ** If the SeekGE.P1 cursor is not currently pointing to a valid row, ** then this opcode is a no-op and control passes through into the OP_SeekGE. ** ** If the SeekGE.P1 cursor is pointing to a valid row, then that row ** might be the target row, or it might be near and slightly before the ** target row, or it might be after the target row. If the cursor is ** currently before the target row, then this opcode attempts to position ** the cursor on or after the target row by invoking sqlite3BtreeStep() ** on the cursor between 1 and This.P1 times. ** ** The This.P5 parameter is a flag that indicates what to do if the ** cursor ends up pointing at a valid row that is past the target ** row. If This.P5 is false (0) then a jump is made to SeekGE.P2. If ** This.P5 is true (non-zero) then a jump is made to This.P2. The P5==0 ** case occurs when there are no inequality constraints to the right of ** the IN constraint. The jump to SeekGE.P2 ends the loop. The P5!=0 case ** occurs when there are inequality constraints to the right of the IN ** operator. In that case, the This.P2 will point either directly to or ** to setup code prior to the OP_IdxGT or OP_IdxGE opcode that checks for ** loop terminate. ** ** Possible outcomes from this opcode:
      ** **
    1. If the cursor is initially not pointed to any valid row, then ** fall through into the subsequent OP_SeekGE opcode. ** **
    2. If the cursor is left pointing to a row that is before the target ** row, even after making as many as This.P1 calls to ** sqlite3BtreeNext(), then also fall through into OP_SeekGE. ** **
    3. If the cursor is left pointing at the target row, either because it ** was at the target row to begin with or because one or more ** sqlite3BtreeNext() calls moved the cursor to the target row, ** then jump to This.P2.., ** **
    4. If the cursor started out before the target row and a call to ** to sqlite3BtreeNext() moved the cursor off the end of the index ** (indicating that the target row definitely does not exist in the ** btree) then jump to SeekGE.P2, ending the loop. ** **
    5. If the cursor ends up on a valid row that is past the target row ** (indicating that the target row does not exist in the btree) then ** jump to SeekOP.P2 if This.P5==0 or to This.P2 if This.P5>0. **
    */ case OP_SeekScan: { /* ncycle */ VdbeCursor *pC; int res; int nStep; UnpackedRecord r; assert( pOp[1].opcode==OP_SeekGE ); /* If pOp->p5 is clear, then pOp->p2 points to the first instruction past the ** OP_IdxGT that follows the OP_SeekGE. Otherwise, it points to the first ** opcode past the OP_SeekGE itself. */ assert( pOp->p2>=(int)(pOp-aOp)+2 ); #ifdef SQLITE_DEBUG if( pOp->p5==0 ){ /* There are no inequality constraints following the IN constraint. */ assert( pOp[1].p1==aOp[pOp->p2-1].p1 ); assert( pOp[1].p2==aOp[pOp->p2-1].p2 ); assert( pOp[1].p3==aOp[pOp->p2-1].p3 ); assert( aOp[pOp->p2-1].opcode==OP_IdxGT || aOp[pOp->p2-1].opcode==OP_IdxGE ); testcase( aOp[pOp->p2-1].opcode==OP_IdxGE ); }else{ /* There are inequality constraints. */ assert( pOp->p2==(int)(pOp-aOp)+2 ); assert( aOp[pOp->p2-1].opcode==OP_SeekGE ); } #endif assert( pOp->p1>0 ); pC = p->apCsr[pOp[1].p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( !pC->isTable ); if( !sqlite3BtreeCursorIsValidNN(pC->uc.pCursor) ){ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("... cursor not valid - fall through\n"); } #endif break; } nStep = pOp->p1; assert( nStep>=1 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp[1].p4.i; r.default_rc = 0; r.aMem = &aMem[pOp[1].p3]; #ifdef SQLITE_DEBUG { int i; for(i=0; i0 && pOp->p5==0 ){ seekscan_search_fail: /* Jump to SeekGE.P2, ending the loop */ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("... %d steps and then skip\n", pOp->p1 - nStep); } #endif VdbeBranchTaken(1,3); pOp++; goto jump_to_p2; } if( res>=0 ){ /* Jump to This.P2, bypassing the OP_SeekGE opcode */ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("... %d steps and then success\n", pOp->p1 - nStep); } #endif VdbeBranchTaken(2,3); goto jump_to_p2; break; } if( nStep<=0 ){ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("... fall through after %d steps\n", pOp->p1); } #endif VdbeBranchTaken(0,3); break; } nStep--; pC->cacheStatus = CACHE_STALE; rc = sqlite3BtreeNext(pC->uc.pCursor, 0); if( rc ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; goto seekscan_search_fail; }else{ goto abort_due_to_error; } } } break; } /* Opcode: SeekHit P1 P2 P3 * * ** Synopsis: set P2<=seekHit<=P3 ** ** Increase or decrease the seekHit value for cursor P1, if necessary, ** so that it is no less than P2 and no greater than P3. ** ** The seekHit integer represents the maximum of terms in an index for which ** there is known to be at least one match. If the seekHit value is smaller ** than the total number of equality terms in an index lookup, then the ** OP_IfNoHope opcode might run to see if the IN loop can be abandoned ** early, thus saving work. This is part of the IN-early-out optimization. ** ** P1 must be a valid b-tree cursor. */ case OP_SeekHit: { /* ncycle */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pOp->p3>=pOp->p2 ); if( pC->seekHitp2 ){ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("seekHit changes from %d to %d\n", pC->seekHit, pOp->p2); } #endif pC->seekHit = pOp->p2; }else if( pC->seekHit>pOp->p3 ){ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("seekHit changes from %d to %d\n", pC->seekHit, pOp->p3); } #endif pC->seekHit = pOp->p3; } break; } /* Opcode: IfNotOpen P1 P2 * * * ** Synopsis: if( !csr[P1] ) goto P2 ** ** If cursor P1 is not open or if P1 is set to a NULL row using the ** OP_NullRow opcode, then jump to instruction P2. Otherwise, fall through. */ case OP_IfNotOpen: { /* jump */ VdbeCursor *pCur; assert( pOp->p1>=0 && pOp->p1nCursor ); pCur = p->apCsr[pOp->p1]; VdbeBranchTaken(pCur==0 || pCur->nullRow, 2); if( pCur==0 || pCur->nullRow ){ goto jump_to_p2_and_check_for_interrupt; } break; } /* Opcode: Found P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If P4==0 then register P3 holds a blob constructed by MakeRecord. If ** P4>0 then register P3 is the first of P4 registers that form an unpacked ** record. ** ** Cursor P1 is on an index btree. If the record identified by P3 and P4 ** is a prefix of any entry in P1 then a jump is made to P2 and ** P1 is left pointing at the matching entry. ** ** This operation leaves the cursor in a state where it can be ** advanced in the forward direction. The Next instruction will work, ** but not the Prev instruction. ** ** See also: NotFound, NoConflict, NotExists. SeekGe */ /* Opcode: NotFound P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If P4==0 then register P3 holds a blob constructed by MakeRecord. If ** P4>0 then register P3 is the first of P4 registers that form an unpacked ** record. ** ** Cursor P1 is on an index btree. If the record identified by P3 and P4 ** is not the prefix of any entry in P1 then a jump is made to P2. If P1 ** does contain an entry whose prefix matches the P3/P4 record then control ** falls through to the next instruction and P1 is left pointing at the ** matching entry. ** ** This operation leaves the cursor in a state where it cannot be ** advanced in either direction. In other words, the Next and Prev ** opcodes do not work after this operation. ** ** See also: Found, NotExists, NoConflict, IfNoHope */ /* Opcode: IfNoHope P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** Register P3 is the first of P4 registers that form an unpacked ** record. Cursor P1 is an index btree. P2 is a jump destination. ** In other words, the operands to this opcode are the same as the ** operands to OP_NotFound and OP_IdxGT. ** ** This opcode is an optimization attempt only. If this opcode always ** falls through, the correct answer is still obtained, but extra work ** is performed. ** ** A value of N in the seekHit flag of cursor P1 means that there exists ** a key P3:N that will match some record in the index. We want to know ** if it is possible for a record P3:P4 to match some record in the ** index. If it is not possible, we can skip some work. So if seekHit ** is less than P4, attempt to find out if a match is possible by running ** OP_NotFound. ** ** This opcode is used in IN clause processing for a multi-column key. ** If an IN clause is attached to an element of the key other than the ** left-most element, and if there are no matches on the most recent ** seek over the whole key, then it might be that one of the key element ** to the left is prohibiting a match, and hence there is "no hope" of ** any match regardless of how many IN clause elements are checked. ** In such a case, we abandon the IN clause search early, using this ** opcode. The opcode name comes from the fact that the ** jump is taken if there is "no hope" of achieving a match. ** ** See also: NotFound, SeekHit */ /* Opcode: NoConflict P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If P4==0 then register P3 holds a blob constructed by MakeRecord. If ** P4>0 then register P3 is the first of P4 registers that form an unpacked ** record. ** ** Cursor P1 is on an index btree. If the record identified by P3 and P4 ** contains any NULL value, jump immediately to P2. If all terms of the ** record are not-NULL then a check is done to determine if any row in the ** P1 index btree has a matching key prefix. If there are no matches, jump ** immediately to P2. If there is a match, fall through and leave the P1 ** cursor pointing to the matching row. ** ** This opcode is similar to OP_NotFound with the exceptions that the ** branch is always taken if any part of the search key input is NULL. ** ** This operation leaves the cursor in a state where it cannot be ** advanced in either direction. In other words, the Next and Prev ** opcodes do not work after this operation. ** ** See also: NotFound, Found, NotExists */ case OP_IfNoHope: { /* jump, in3, ncycle */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("seekHit is %d\n", pC->seekHit); } #endif if( pC->seekHit>=pOp->p4.i ) break; /* Fall through into OP_NotFound */ /* no break */ deliberate_fall_through } case OP_NoConflict: /* jump, in3, ncycle */ case OP_NotFound: /* jump, in3, ncycle */ case OP_Found: { /* jump, in3, ncycle */ int alreadyExists; int ii; VdbeCursor *pC; UnpackedRecord *pIdxKey; UnpackedRecord r; #ifdef SQLITE_TEST if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++; #endif assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p4type==P4_INT32 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif r.aMem = &aMem[pOp->p3]; assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->isTable==0 ); r.nField = (u16)pOp->p4.i; if( r.nField>0 ){ /* Key values in an array of registers */ r.pKeyInfo = pC->pKeyInfo; r.default_rc = 0; #ifdef SQLITE_DEBUG for(ii=0; iip3+ii, &r.aMem[ii]); } #endif rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &pC->seekResult); }else{ /* Composite key generated by OP_MakeRecord */ assert( r.aMem->flags & MEM_Blob ); assert( pOp->opcode!=OP_NoConflict ); rc = ExpandBlob(r.aMem); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); if( rc ) goto no_mem; pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo); if( pIdxKey==0 ) goto no_mem; sqlite3VdbeRecordUnpack(pC->pKeyInfo, r.aMem->n, r.aMem->z, pIdxKey); pIdxKey->default_rc = 0; rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &pC->seekResult); sqlite3DbFreeNN(db, pIdxKey); } if( rc!=SQLITE_OK ){ goto abort_due_to_error; } alreadyExists = (pC->seekResult==0); pC->nullRow = 1-alreadyExists; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; if( pOp->opcode==OP_Found ){ VdbeBranchTaken(alreadyExists!=0,2); if( alreadyExists ) goto jump_to_p2; }else{ if( !alreadyExists ){ VdbeBranchTaken(1,2); goto jump_to_p2; } if( pOp->opcode==OP_NoConflict ){ /* For the OP_NoConflict opcode, take the jump if any of the ** input fields are NULL, since any key with a NULL will not ** conflict */ for(ii=0; iiopcode==OP_IfNoHope ){ pC->seekHit = pOp->p4.i; } } break; } /* Opcode: SeekRowid P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). If register P3 does not contain an integer or if P1 does not ** contain a record with rowid P3 then jump immediately to P2. ** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain ** a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** ** The OP_NotExists opcode performs the same operation, but with OP_NotExists ** the P3 register must be guaranteed to contain an integer value. With this ** opcode, register P3 might not contain an integer. ** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** ** See also: Found, NotFound, NoConflict, SeekRowid */ /* Opcode: NotExists P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). P3 is an integer rowid. If P1 does not contain a record with ** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an ** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** ** The OP_SeekRowid opcode performs the same operation but also allows the ** P3 register to contain a non-integer value, in which case the jump is ** always taken. This opcode requires that P3 always contain an integer. ** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** ** See also: Found, NotFound, NoConflict, SeekRowid */ case OP_SeekRowid: { /* jump, in3, ncycle */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; pIn3 = &aMem[pOp->p3]; testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_IntReal ); testcase( pIn3->flags & MEM_Real ); testcase( (pIn3->flags & (MEM_Str|MEM_Int))==MEM_Str ); if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){ /* If pIn3->u.i does not contain an integer, compute iKey as the ** integer value of pIn3. Jump to P2 if pIn3 cannot be converted ** into an integer without loss of information. Take care to avoid ** changing the datatype of pIn3, however, as it is used by other ** parts of the prepared statement. */ Mem x = pIn3[0]; applyAffinity(&x, SQLITE_AFF_NUMERIC, encoding); if( (x.flags & MEM_Int)==0 ) goto jump_to_p2; iKey = x.u.i; goto notExistsWithKey; } /* Fall through into OP_NotExists */ /* no break */ deliberate_fall_through case OP_NotExists: /* jump, in3, ncycle */ pIn3 = &aMem[pOp->p3]; assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid ); assert( pOp->p1>=0 && pOp->p1nCursor ); iKey = pIn3->u.i; notExistsWithKey: pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG if( pOp->opcode==OP_SeekRowid ) pC->seekOp = OP_SeekRowid; #endif assert( pC->isTable ); assert( pC->eCurType==CURTYPE_BTREE ); pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); res = 0; rc = sqlite3BtreeTableMoveto(pCrsr, iKey, 0, &res); assert( rc==SQLITE_OK || res==0 ); pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; VdbeBranchTaken(res!=0,2); pC->seekResult = res; if( res!=0 ){ assert( rc==SQLITE_OK ); if( pOp->p2==0 ){ rc = SQLITE_CORRUPT_BKPT; }else{ goto jump_to_p2; } } if( rc ) goto abort_due_to_error; break; } /* Opcode: Sequence P1 P2 * * * ** Synopsis: r[P2]=cursor[P1].ctr++ ** ** Find the next available sequence number for cursor P1. ** Write the sequence number into register P2. ** The sequence number on the cursor is incremented after this ** instruction. */ case OP_Sequence: { /* out2 */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( p->apCsr[pOp->p1]!=0 ); assert( p->apCsr[pOp->p1]->eCurType!=CURTYPE_VTAB ); pOut = out2Prerelease(p, pOp); pOut->u.i = p->apCsr[pOp->p1]->seqCount++; break; } /* Opcode: NewRowid P1 P2 P3 * * ** Synopsis: r[P2]=rowid ** ** Get a new integer record number (a.k.a "rowid") used as the key to a table. ** The record number is not previously used as a key in the database ** table that cursor P1 points to. The new record number is written ** written to register P2. ** ** If P3>0 then P3 is a register in the root frame of this VDBE that holds ** the largest previously generated record number. No new record numbers are ** allowed to be less than this value. When this value reaches its maximum, ** an SQLITE_FULL error is generated. The P3 register is updated with the ' ** generated record number. This P3 mechanism is used to help implement the ** AUTOINCREMENT feature. */ case OP_NewRowid: { /* out2 */ i64 v; /* The new rowid */ VdbeCursor *pC; /* Cursor of table to get the new rowid */ int res; /* Result of an sqlite3BtreeLast() */ int cnt; /* Counter to limit the number of searches */ #ifndef SQLITE_OMIT_AUTOINCREMENT Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */ VdbeFrame *pFrame; /* Root frame of VDBE */ #endif v = 0; res = 0; pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->isTable ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); { /* The next rowid or record number (different terms for the same ** thing) is obtained in a two-step algorithm. ** ** First we attempt to find the largest existing rowid and add one ** to that. But if the largest existing rowid is already the maximum ** positive integer, we have to fall through to the second ** probabilistic algorithm ** ** The second algorithm is to select a rowid at random and see if ** it already exists in the table. If it does not exist, we have ** succeeded. If the random rowid does exist, we select a new one ** and try again, up to 100 times. */ assert( pC->isTable ); #ifdef SQLITE_32BIT_ROWID # define MAX_ROWID 0x7fffffff #else /* Some compilers complain about constants of the form 0x7fffffffffffffff. ** Others complain about 0x7ffffffffffffffffLL. The following macro seems ** to provide the constant while making all compilers happy. */ # define MAX_ROWID (i64)( (((u64)0x7fffffff)<<32) | (u64)0xffffffff ) #endif if( !pC->useRandomRowid ){ rc = sqlite3BtreeLast(pC->uc.pCursor, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( res ){ v = 1; /* IMP: R-61914-48074 */ }else{ assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) ); v = sqlite3BtreeIntegerKey(pC->uc.pCursor); if( v>=MAX_ROWID ){ pC->useRandomRowid = 1; }else{ v++; /* IMP: R-29538-34987 */ } } } #ifndef SQLITE_OMIT_AUTOINCREMENT if( pOp->p3 ){ /* Assert that P3 is a valid memory cell. */ assert( pOp->p3>0 ); if( p->pFrame ){ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); /* Assert that P3 is a valid memory cell. */ assert( pOp->p3<=pFrame->nMem ); pMem = &pFrame->aMem[pOp->p3]; }else{ /* Assert that P3 is a valid memory cell. */ assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pMem = &aMem[pOp->p3]; memAboutToChange(p, pMem); } assert( memIsValid(pMem) ); REGISTER_TRACE(pOp->p3, pMem); sqlite3VdbeMemIntegerify(pMem); assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){ rc = SQLITE_FULL; /* IMP: R-17817-00630 */ goto abort_due_to_error; } if( vu.i+1 ){ v = pMem->u.i + 1; } pMem->u.i = v; } #endif if( pC->useRandomRowid ){ /* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the ** largest possible integer (9223372036854775807) then the database ** engine starts picking positive candidate ROWIDs at random until ** it finds one that is not previously used. */ assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is ** an AUTOINCREMENT table. */ cnt = 0; do{ sqlite3_randomness(sizeof(v), &v); v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */ }while( ((rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)v, 0, &res))==SQLITE_OK) && (res==0) && (++cnt<100)); if( rc ) goto abort_due_to_error; if( res==0 ){ rc = SQLITE_FULL; /* IMP: R-38219-53002 */ goto abort_due_to_error; } assert( v>0 ); /* EV: R-40812-03570 */ } pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } pOut->u.i = v; break; } /* Opcode: Insert P1 P2 P3 P4 P5 ** Synopsis: intkey=r[P3] data=r[P2] ** ** Write an entry into the table of cursor P1. A new entry is ** created if it doesn't already exist or the data for an existing ** entry is overwritten. The data is the value MEM_Blob stored in register ** number P2. The key is stored in register P3. The key must ** be a MEM_Int. ** ** If the OPFLAG_NCHANGE flag of P5 is set, then the row change count is ** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set, ** then rowid is stored for subsequent return by the ** sqlite3_last_insert_rowid() function (otherwise it is unmodified). ** ** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might ** run faster by avoiding an unnecessary seek on cursor P1. However, ** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior ** seeks on the cursor or if the most recent seek used a key equal to P3. ** ** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an ** UPDATE operation. Otherwise (if the flag is clear) then this opcode ** is part of an INSERT operation. The difference is only important to ** the update hook. ** ** Parameter P4 may point to a Table structure, or may be NULL. If it is ** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked ** following a successful insert. ** ** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically ** allocated, then ownership of P2 is transferred to the pseudo-cursor ** and register P2 becomes ephemeral. If the cursor is changed, the ** value of register P2 will then change. Make sure this does not ** cause any problems.) ** ** This instruction only works on tables. The equivalent instruction ** for indices is OP_IdxInsert. */ case OP_Insert: { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ VdbeCursor *pC; /* Cursor to table into which insert is written */ int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ const char *zDb; /* database name - used by the update hook */ Table *pTab; /* Table structure - used by update and pre-update hooks */ BtreePayload x; /* Payload to be inserted */ pData = &aMem[pOp->p2]; assert( pOp->p1>=0 && pOp->p1nCursor ); assert( memIsValid(pData) ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->deferredMoveto==0 ); assert( pC->uc.pCursor!=0 ); assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable ); assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC ); REGISTER_TRACE(pOp->p2, pData); sqlite3VdbeIncrWriteCounter(p, pC); pKey = &aMem[pOp->p3]; assert( pKey->flags & MEM_Int ); assert( memIsValid(pKey) ); REGISTER_TRACE(pOp->p3, pKey); x.nKey = pKey->u.i; if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); zDb = db->aDb[pC->iDb].zDbSName; pTab = pOp->p4.pTab; assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) ); }else{ pTab = 0; zDb = 0; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* Invoke the pre-update hook, if any */ if( pTab ){ if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){ sqlite3VdbePreUpdateHook(p,pC,SQLITE_INSERT,zDb,pTab,x.nKey,pOp->p2,-1); } if( db->xUpdateCallback==0 || pTab->aCol==0 ){ /* Prevent post-update hook from running in cases when it should not */ pTab = 0; } } if( pOp->p5 & OPFLAG_ISNOOP ) break; #endif assert( (pOp->p5 & OPFLAG_LASTROWID)==0 || (pOp->p5 & OPFLAG_NCHANGE)!=0 ); if( pOp->p5 & OPFLAG_NCHANGE ){ p->nChange++; if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey; } assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 ); x.pData = pData->z; x.nData = pData->n; seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); if( pData->flags & MEM_Zero ){ x.nZero = pData->u.nZero; }else{ x.nZero = 0; } x.pKey = 0; assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT ); rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)), seekResult ); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; colCacheCtr++; /* Invoke the update-hook if required. */ if( rc ) goto abort_due_to_error; if( pTab ){ assert( db->xUpdateCallback!=0 ); assert( pTab->aCol!=0 ); db->xUpdateCallback(db->pUpdateArg, (pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT, zDb, pTab->zName, x.nKey); } break; } /* Opcode: RowCell P1 P2 P3 * * ** ** P1 and P2 are both open cursors. Both must be opened on the same type ** of table - intkey or index. This opcode is used as part of copying ** the current row from P2 into P1. If the cursors are opened on intkey ** tables, register P3 contains the rowid to use with the new record in ** P1. If they are opened on index tables, P3 is not used. ** ** This opcode must be followed by either an Insert or InsertIdx opcode ** with the OPFLAG_PREFORMAT flag set to complete the insert operation. */ case OP_RowCell: { VdbeCursor *pDest; /* Cursor to write to */ VdbeCursor *pSrc; /* Cursor to read from */ i64 iKey; /* Rowid value to insert with */ assert( pOp[1].opcode==OP_Insert || pOp[1].opcode==OP_IdxInsert ); assert( pOp[1].opcode==OP_Insert || pOp->p3==0 ); assert( pOp[1].opcode==OP_IdxInsert || pOp->p3>0 ); assert( pOp[1].p5 & OPFLAG_PREFORMAT ); pDest = p->apCsr[pOp->p1]; pSrc = p->apCsr[pOp->p2]; iKey = pOp->p3 ? aMem[pOp->p3].u.i : 0; rc = sqlite3BtreeTransferRow(pDest->uc.pCursor, pSrc->uc.pCursor, iKey); if( rc!=SQLITE_OK ) goto abort_due_to_error; break; }; /* Opcode: Delete P1 P2 P3 P4 P5 ** ** Delete the record at which the P1 cursor is currently pointing. ** ** If the OPFLAG_SAVEPOSITION bit of the P5 parameter is set, then ** the cursor will be left pointing at either the next or the previous ** record in the table. If it is left pointing at the next record, then ** the next Next instruction will be a no-op. As a result, in this case ** it is ok to delete a record from within a Next loop. If ** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be ** left in an undefined state. ** ** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this ** delete is one of several associated with deleting a table row and ** all its associated index entries. Exactly one of those deletes is ** the "primary" delete. The others are all on OPFLAG_FORDELETE ** cursors or else are marked with the AUXDELETE flag. ** ** If the OPFLAG_NCHANGE (0x01) flag of P2 (NB: P2 not P5) is set, then ** the row change count is incremented (otherwise not). ** ** If the OPFLAG_ISNOOP (0x40) flag of P2 (not P5!) is set, then the ** pre-update-hook for deletes is run, but the btree is otherwise unchanged. ** This happens when the OP_Delete is to be shortly followed by an OP_Insert ** with the same key, causing the btree entry to be overwritten. ** ** P1 must not be pseudo-table. It has to be a real table with ** multiple rows. ** ** If P4 is not NULL then it points to a Table object. In this case either ** the update or pre-update hook, or both, may be invoked. The P1 cursor must ** have been positioned using OP_NotFound prior to invoking this opcode in ** this case. Specifically, if one is configured, the pre-update hook is ** invoked if P4 is not NULL. The update-hook is invoked if one is configured, ** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2. ** ** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address ** of the memory cell that contains the value that the rowid of the row will ** be set to by the update. */ case OP_Delete: { VdbeCursor *pC; const char *zDb; Table *pTab; int opflags; opflags = pOp->p2; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->deferredMoveto==0 ); sqlite3VdbeIncrWriteCounter(p, pC); #ifdef SQLITE_DEBUG if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 && sqlite3BtreeCursorIsValidNN(pC->uc.pCursor) ){ /* If p5 is zero, the seek operation that positioned the cursor prior to ** OP_Delete will have also set the pC->movetoTarget field to the rowid of ** the row that is being deleted */ i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor); assert( CORRUPT_DB || pC->movetoTarget==iKey ); } #endif /* If the update-hook or pre-update-hook will be invoked, set zDb to ** the name of the db to pass as to it. Also set local pTab to a copy ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set ** VdbeCursor.movetoTarget to the current rowid. */ if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); assert( pOp->p4.pTab!=0 ); zDb = db->aDb[pC->iDb].zDbSName; pTab = pOp->p4.pTab; if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){ pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor); } }else{ zDb = 0; pTab = 0; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* Invoke the pre-update-hook if required. */ assert( db->xPreUpdateCallback==0 || pTab==pOp->p4.pTab ); if( db->xPreUpdateCallback && pTab ){ assert( !(opflags & OPFLAG_ISUPDATE) || HasRowid(pTab)==0 || (aMem[pOp->p3].flags & MEM_Int) ); sqlite3VdbePreUpdateHook(p, pC, (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, zDb, pTab, pC->movetoTarget, pOp->p3, -1 ); } if( opflags & OPFLAG_ISNOOP ) break; #endif /* Only flags that can be set are SAVEPOISTION and AUXDELETE */ assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 ); assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION ); assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE ); #ifdef SQLITE_DEBUG if( p->pFrame==0 ){ if( pC->isEphemeral==0 && (pOp->p5 & OPFLAG_AUXDELETE)==0 && (pC->wrFlag & OPFLAG_FORDELETE)==0 ){ nExtraDelete++; } if( pOp->p2 & OPFLAG_NCHANGE ){ nExtraDelete--; } } #endif rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5); pC->cacheStatus = CACHE_STALE; colCacheCtr++; pC->seekResult = 0; if( rc ) goto abort_due_to_error; /* Invoke the update-hook if required. */ if( opflags & OPFLAG_NCHANGE ){ p->nChange++; if( db->xUpdateCallback && ALWAYS(pTab!=0) && HasRowid(pTab) ){ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName, pC->movetoTarget); assert( pC->iDb>=0 ); } } break; } /* Opcode: ResetCount * * * * * ** ** The value of the change counter is copied to the database handle ** change counter (returned by subsequent calls to sqlite3_changes()). ** Then the VMs internal change counter resets to 0. ** This is used by trigger programs. */ case OP_ResetCount: { sqlite3VdbeSetChanges(db, p->nChange); p->nChange = 0; break; } /* Opcode: SorterCompare P1 P2 P3 P4 ** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2 ** ** P1 is a sorter cursor. This instruction compares a prefix of the ** record blob in register P3 against a prefix of the entry that ** the sorter cursor currently points to. Only the first P4 fields ** of r[P3] and the sorter record are compared. ** ** If either P3 or the sorter contains a NULL in one of their significant ** fields (not counting the P4 fields at the end which are ignored) then ** the comparison is assumed to be equal. ** ** Fall through to next instruction if the two records compare equal to ** each other. Jump to P2 if they are different. */ case OP_SorterCompare: { VdbeCursor *pC; int res; int nKeyCol; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); assert( pOp->p4type==P4_INT32 ); pIn3 = &aMem[pOp->p3]; nKeyCol = pOp->p4.i; res = 0; rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); VdbeBranchTaken(res!=0,2); if( rc ) goto abort_due_to_error; if( res ) goto jump_to_p2; break; }; /* Opcode: SorterData P1 P2 P3 * * ** Synopsis: r[P2]=data ** ** Write into register P2 the current sorter data for sorter cursor P1. ** Then clear the column header cache on cursor P3. ** ** This opcode is normally used to move a record out of the sorter and into ** a register that is the source for a pseudo-table cursor created using ** OpenPseudo. That pseudo-table cursor is the one that is identified by ** parameter P3. Clearing the P3 column cache as part of this opcode saves ** us from having to issue a separate NullRow instruction to clear that cache. */ case OP_SorterData: { /* ncycle */ VdbeCursor *pC; pOut = &aMem[pOp->p2]; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); rc = sqlite3VdbeSorterRowkey(pC, pOut); assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); assert( pOp->p1>=0 && pOp->p1nCursor ); if( rc ) goto abort_due_to_error; p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE; break; } /* Opcode: RowData P1 P2 P3 * * ** Synopsis: r[P2]=data ** ** Write into register P2 the complete row content for the row at ** which cursor P1 is currently pointing. ** There is no interpretation of the data. ** It is just copied onto the P2 register exactly as ** it is found in the database file. ** ** If cursor P1 is an index, then the content is the key of the row. ** If cursor P2 is a table, then the content extracted is the data. ** ** If the P1 cursor must be pointing to a valid row (not a NULL row) ** of a real table, not a pseudo-table. ** ** If P3!=0 then this opcode is allowed to make an ephemeral pointer ** into the database page. That means that the content of the output ** register will be invalidated as soon as the cursor moves - including ** moves caused by other cursors that "save" the current cursors ** position in order that they can write to the same table. If P3==0 ** then a copy of the data is made into memory. P3!=0 is faster, but ** P3==0 is safer. ** ** If P3!=0 then the content of the P2 register is unsuitable for use ** in OP_Result and any OP_Result will invalidate the P2 register content. ** The P2 register content is invalidated by opcodes like OP_Function or ** by any use of another cursor pointing to the same table. */ case OP_RowData: { VdbeCursor *pC; BtCursor *pCrsr; u32 n; pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( isSorter(pC)==0 ); assert( pC->nullRow==0 ); assert( pC->uc.pCursor!=0 ); pCrsr = pC->uc.pCursor; /* The OP_RowData opcodes always follow OP_NotExists or ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions ** that might invalidate the cursor. ** If this where not the case, on of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). */ assert( pC->deferredMoveto==0 ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); n = sqlite3BtreePayloadSize(pCrsr); if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } testcase( n==0 ); rc = sqlite3VdbeMemFromBtreeZeroOffset(pCrsr, n, pOut); if( rc ) goto abort_due_to_error; if( !pOp->p3 ) Deephemeralize(pOut); UPDATE_MAX_BLOBSIZE(pOut); REGISTER_TRACE(pOp->p2, pOut); break; } /* Opcode: Rowid P1 P2 * * * ** Synopsis: r[P2]=PX rowid of P1 ** ** Store in register P2 an integer which is the key of the table entry that ** P1 is currently point to. ** ** P1 can be either an ordinary table or a virtual table. There used to ** be a separate OP_VRowid opcode for use with virtual tables, but this ** one opcode now works for both table types. */ case OP_Rowid: { /* out2, ncycle */ VdbeCursor *pC; i64 v; sqlite3_vtab *pVtab; const sqlite3_module *pModule; pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); if( pC->nullRow ){ pOut->flags = MEM_Null; break; }else if( pC->deferredMoveto ){ v = pC->movetoTarget; #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( pC->eCurType==CURTYPE_VTAB ){ assert( pC->uc.pVCur!=0 ); pVtab = pC->uc.pVCur->pVtab; pModule = pVtab->pModule; assert( pModule->xRowid ); rc = pModule->xRowid(pC->uc.pVCur, &v); sqlite3VtabImportErrmsg(p, pVtab); if( rc ) goto abort_due_to_error; #endif /* SQLITE_OMIT_VIRTUALTABLE */ }else{ assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); rc = sqlite3VdbeCursorRestore(pC); if( rc ) goto abort_due_to_error; if( pC->nullRow ){ pOut->flags = MEM_Null; break; } v = sqlite3BtreeIntegerKey(pC->uc.pCursor); } pOut->u.i = v; break; } /* Opcode: NullRow P1 * * * * ** ** Move the cursor P1 to a null row. Any OP_Column operations ** that occur while the cursor is on the null row will always ** write a NULL. ** ** If cursor P1 is not previously opened, open it now to a special ** pseudo-cursor that always returns NULL for every column. */ case OP_NullRow: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; if( pC==0 ){ /* If the cursor is not already open, create a special kind of ** pseudo-cursor that always gives null rows. */ pC = allocateCursor(p, pOp->p1, 1, CURTYPE_PSEUDO); if( pC==0 ) goto no_mem; pC->seekResult = 0; pC->isTable = 1; pC->noReuse = 1; pC->uc.pCursor = sqlite3BtreeFakeValidCursor(); } pC->nullRow = 1; pC->cacheStatus = CACHE_STALE; if( pC->eCurType==CURTYPE_BTREE ){ assert( pC->uc.pCursor!=0 ); sqlite3BtreeClearCursor(pC->uc.pCursor); } #ifdef SQLITE_DEBUG if( pC->seekOp==0 ) pC->seekOp = OP_NullRow; #endif break; } /* Opcode: SeekEnd P1 * * * * ** ** Position cursor P1 at the end of the btree for the purpose of ** appending a new entry onto the btree. ** ** It is assumed that the cursor is used only for appending and so ** if the cursor is valid, then the cursor must already be pointing ** at the end of the btree and so no changes are made to ** the cursor. */ /* Opcode: Last P1 P2 * * * ** ** The next use of the Rowid or Column or Prev instruction for P1 ** will refer to the last entry in the database table or index. ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. ** ** This opcode leaves the cursor configured to move in reverse order, ** from the end toward the beginning. In other words, the cursor is ** configured to use Prev, not Next. */ case OP_SeekEnd: /* ncycle */ case OP_Last: { /* jump, ncycle */ VdbeCursor *pC; BtCursor *pCrsr; int res; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); pCrsr = pC->uc.pCursor; res = 0; assert( pCrsr!=0 ); #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif if( pOp->opcode==OP_SeekEnd ){ assert( pOp->p2==0 ); pC->seekResult = -1; if( sqlite3BtreeCursorIsValidNN(pCrsr) ){ break; } } rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = (u8)res; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; if( rc ) goto abort_due_to_error; if( pOp->p2>0 ){ VdbeBranchTaken(res!=0,2); if( res ) goto jump_to_p2; } break; } /* Opcode: IfSmaller P1 P2 P3 * * ** ** Estimate the number of rows in the table P1. Jump to P2 if that ** estimate is less than approximately 2**(0.1*P3). */ case OP_IfSmaller: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; int res; i64 sz; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pCrsr = pC->uc.pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); if( rc ) goto abort_due_to_error; if( res==0 ){ sz = sqlite3BtreeRowCountEst(pCrsr); if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)p3 ) res = 1; } VdbeBranchTaken(res!=0,2); if( res ) goto jump_to_p2; break; } /* Opcode: SorterSort P1 P2 * * * ** ** After all records have been inserted into the Sorter object ** identified by P1, invoke this opcode to actually do the sorting. ** Jump to P2 if there are no records to be sorted. ** ** This opcode is an alias for OP_Sort and OP_Rewind that is used ** for Sorter objects. */ /* Opcode: Sort P1 P2 * * * ** ** This opcode does exactly the same thing as OP_Rewind except that ** it increments an undocumented global variable used for testing. ** ** Sorting is accomplished by writing records into a sorting index, ** then rewinding that index and playing it back from beginning to ** end. We use the OP_Sort opcode instead of OP_Rewind to do the ** rewinding so that the global variable will be incremented and ** regression tests can determine whether or not the optimizer is ** correctly optimizing out sorts. */ case OP_SorterSort: /* jump ncycle */ case OP_Sort: { /* jump ncycle */ #ifdef SQLITE_TEST sqlite3_sort_count++; sqlite3_search_count--; #endif p->aCounter[SQLITE_STMTSTATUS_SORT]++; /* Fall through into OP_Rewind */ /* no break */ deliberate_fall_through } /* Opcode: Rewind P1 P2 * * * ** ** The next use of the Rowid or Column or Next instruction for P1 ** will refer to the first entry in the database table or index. ** If the table or index is empty, jump immediately to P2. ** If the table or index is not empty, fall through to the following ** instruction. ** ** If P2 is zero, that is an assertion that the P1 table is never ** empty and hence the jump will never be taken. ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. */ case OP_Rewind: { /* jump, ncycle */ VdbeCursor *pC; BtCursor *pCrsr; int res; assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p5==0 ); assert( pOp->p2>=0 && pOp->p2nOp ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) ); res = 1; #ifdef SQLITE_DEBUG pC->seekOp = OP_Rewind; #endif if( isSorter(pC) ){ rc = sqlite3VdbeSorterRewind(pC, &res); }else{ assert( pC->eCurType==CURTYPE_BTREE ); pCrsr = pC->uc.pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } if( rc ) goto abort_due_to_error; pC->nullRow = (u8)res; if( pOp->p2>0 ){ VdbeBranchTaken(res!=0,2); if( res ) goto jump_to_p2; } break; } /* Opcode: Next P1 P2 P3 * P5 ** ** Advance cursor P1 so that it points to the next key/data pair in its ** table or index. If there are no more key/value pairs then fall through ** to the following instruction. But if the cursor advance was successful, ** jump immediately to P2. ** ** The Next opcode is only valid following an SeekGT, SeekGE, or ** OP_Rewind opcode used to position the cursor. Next is not allowed ** to follow SeekLT, SeekLE, or OP_Last. ** ** The P1 cursor must be for a real table, not a pseudo-table. P1 must have ** been opened prior to this opcode or the program will segfault. ** ** The P3 value is a hint to the btree implementation. If P3==1, that ** means P1 is an SQL index and that this instruction could have been ** omitted if that index had been unique. P3 is usually 0. P3 is ** always either 0 or 1. ** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. ** ** See also: Prev */ /* Opcode: Prev P1 P2 P3 * P5 ** ** Back up cursor P1 so that it points to the previous key/data pair in its ** table or index. If there is no previous key/value pairs then fall through ** to the following instruction. But if the cursor backup was successful, ** jump immediately to P2. ** ** ** The Prev opcode is only valid following an SeekLT, SeekLE, or ** OP_Last opcode used to position the cursor. Prev is not allowed ** to follow SeekGT, SeekGE, or OP_Rewind. ** ** The P1 cursor must be for a real table, not a pseudo-table. If P1 is ** not open then the behavior is undefined. ** ** The P3 value is a hint to the btree implementation. If P3==1, that ** means P1 is an SQL index and that this instruction could have been ** omitted if that index had been unique. P3 is usually 0. P3 is ** always either 0 or 1. ** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. */ /* Opcode: SorterNext P1 P2 * * P5 ** ** This opcode works just like OP_Next except that P1 must be a ** sorter object for which the OP_SorterSort opcode has been ** invoked. This opcode advances the cursor to the next sorted ** record, or jumps to P2 if there are no more sorted records. */ case OP_SorterNext: { /* jump */ VdbeCursor *pC; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); rc = sqlite3VdbeSorterNext(db, pC); goto next_tail; case OP_Prev: /* jump, ncycle */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p5==0 || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP || pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->deferredMoveto==0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE || pC->seekOp==OP_Last || pC->seekOp==OP_IfNoHope || pC->seekOp==OP_NullRow); rc = sqlite3BtreePrevious(pC->uc.pCursor, pOp->p3); goto next_tail; case OP_Next: /* jump, ncycle */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p5==0 || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP || pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->deferredMoveto==0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found || pC->seekOp==OP_NullRow|| pC->seekOp==OP_SeekRowid || pC->seekOp==OP_IfNoHope); rc = sqlite3BtreeNext(pC->uc.pCursor, pOp->p3); next_tail: pC->cacheStatus = CACHE_STALE; VdbeBranchTaken(rc==SQLITE_OK,2); if( rc==SQLITE_OK ){ pC->nullRow = 0; p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST sqlite3_search_count++; #endif goto jump_to_p2_and_check_for_interrupt; } if( rc!=SQLITE_DONE ) goto abort_due_to_error; rc = SQLITE_OK; pC->nullRow = 1; goto check_for_interrupt; } /* Opcode: IdxInsert P1 P2 P3 P4 P5 ** Synopsis: key=r[P2] ** ** Register P2 holds an SQL index key made using the ** MakeRecord instructions. This opcode writes that key ** into the index P1. Data for the entry is nil. ** ** If P4 is not zero, then it is the number of values in the unpacked ** key of reg(P2). In that case, P3 is the index of the first register ** for the unpacked key. The availability of the unpacked key can sometimes ** be an optimization. ** ** If P5 has the OPFLAG_APPEND bit set, that is a hint to the b-tree layer ** that this insert is likely to be an append. ** ** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is ** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear, ** then the change counter is unchanged. ** ** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might ** run faster by avoiding an unnecessary seek on cursor P1. However, ** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior ** seeks on the cursor or if the most recent seek used a key equivalent ** to P2. ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ case OP_IdxInsert: { /* in2 */ VdbeCursor *pC; BtreePayload x; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; sqlite3VdbeIncrWriteCounter(p, pC); assert( pC!=0 ); assert( !isSorter(pC) ); pIn2 = &aMem[pOp->p2]; assert( (pIn2->flags & MEM_Blob) || (pOp->p5 & OPFLAG_PREFORMAT) ); if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->isTable==0 ); rc = ExpandBlob(pIn2); if( rc ) goto abort_due_to_error; x.nKey = pIn2->n; x.pKey = pIn2->z; x.aMem = aMem + pOp->p3; x.nMem = (u16)pOp->p4.i; rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)), ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) ); assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; if( rc) goto abort_due_to_error; break; } /* Opcode: SorterInsert P1 P2 * * * ** Synopsis: key=r[P2] ** ** Register P2 holds an SQL index key made using the ** MakeRecord instructions. This opcode writes that key ** into the sorter P1. Data for the entry is nil. */ case OP_SorterInsert: { /* in2 */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; sqlite3VdbeIncrWriteCounter(p, pC); assert( pC!=0 ); assert( isSorter(pC) ); pIn2 = &aMem[pOp->p2]; assert( pIn2->flags & MEM_Blob ); assert( pC->isTable==0 ); rc = ExpandBlob(pIn2); if( rc ) goto abort_due_to_error; rc = sqlite3VdbeSorterWrite(pC, pIn2); if( rc) goto abort_due_to_error; break; } /* Opcode: IdxDelete P1 P2 P3 * P5 ** Synopsis: key=r[P2@P3] ** ** The content of P3 registers starting at register P2 form ** an unpacked index key. This opcode removes that entry from the ** index opened by cursor P1. ** ** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error ** if no matching index entry is found. This happens when running ** an UPDATE or DELETE statement and the index entry to be updated ** or deleted is not found. For some uses of IdxDelete ** (example: the EXCEPT operator) it does not matter that no matching ** entry is found. For those cases, P5 is zero. Also, do not raise ** this (self-correcting and non-critical) error if in writable_schema mode. */ case OP_IdxDelete: { VdbeCursor *pC; BtCursor *pCrsr; int res; UnpackedRecord r; assert( pOp->p3>0 ); assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 ); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); sqlite3VdbeIncrWriteCounter(p, pC); pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p3; r.default_rc = 0; r.aMem = &aMem[pOp->p2]; rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res); if( rc ) goto abort_due_to_error; if( res==0 ){ rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); if( rc ) goto abort_due_to_error; }else if( pOp->p5 && !sqlite3WritableSchema(db) ){ rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption"); goto abort_due_to_error; } assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; pC->seekResult = 0; break; } /* Opcode: DeferredSeek P1 * P3 P4 * ** Synopsis: Move P3 to P1.rowid if needed ** ** P1 is an open index cursor and P3 is a cursor on the corresponding ** table. This opcode does a deferred seek of the P3 table cursor ** to the row that corresponds to the current row of P1. ** ** This is a deferred seek. Nothing actually happens until ** the cursor is used to read a record. That way, if no reads ** occur, no unnecessary I/O happens. ** ** P4 may be an array of integers (type P4_INTARRAY) containing ** one entry for each column in the P3 table. If array entry a(i) ** is non-zero, then reading column a(i)-1 from cursor P3 is ** equivalent to performing the deferred seek and then reading column i ** from P1. This information is stored in P3 and used to redirect ** reads against P3 over to P1, thus possibly avoiding the need to ** seek and read cursor P3. */ /* Opcode: IdxRowid P1 P2 * * * ** Synopsis: r[P2]=rowid ** ** Write into register P2 an integer which is the last entry in the record at ** the end of the index key pointed to by cursor P1. This integer should be ** the rowid of the table entry to which this index entry points. ** ** See also: Rowid, MakeRecord. */ case OP_DeferredSeek: /* ncycle */ case OP_IdxRowid: { /* out2, ncycle */ VdbeCursor *pC; /* The P1 index cursor */ VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */ i64 rowid; /* Rowid that P1 current points to */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE || IsNullCursor(pC) ); assert( pC->uc.pCursor!=0 ); assert( pC->isTable==0 || IsNullCursor(pC) ); assert( pC->deferredMoveto==0 ); assert( !pC->nullRow || pOp->opcode==OP_IdxRowid ); /* The IdxRowid and Seek opcodes are combined because of the commonality ** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */ rc = sqlite3VdbeCursorRestore(pC); /* sqlite3VdbeCursorRestore() may fail if the cursor has been disturbed ** since it was last positioned and an error (e.g. OOM or an IO error) ** occurs while trying to reposition it. */ if( rc!=SQLITE_OK ) goto abort_due_to_error; if( !pC->nullRow ){ rowid = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( pOp->opcode==OP_DeferredSeek ){ assert( pOp->p3>=0 && pOp->p3nCursor ); pTabCur = p->apCsr[pOp->p3]; assert( pTabCur!=0 ); assert( pTabCur->eCurType==CURTYPE_BTREE ); assert( pTabCur->uc.pCursor!=0 ); assert( pTabCur->isTable ); pTabCur->nullRow = 0; pTabCur->movetoTarget = rowid; pTabCur->deferredMoveto = 1; pTabCur->cacheStatus = CACHE_STALE; assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 ); assert( !pTabCur->isEphemeral ); pTabCur->ub.aAltMap = pOp->p4.ai; assert( !pC->isEphemeral ); pTabCur->pAltCursor = pC; }else{ pOut = out2Prerelease(p, pOp); pOut->u.i = rowid; } }else{ assert( pOp->opcode==OP_IdxRowid ); sqlite3VdbeMemSetNull(&aMem[pOp->p2]); } break; } /* Opcode: FinishSeek P1 * * * * ** ** If cursor P1 was previously moved via OP_DeferredSeek, complete that ** seek operation now, without further delay. If the cursor seek has ** already occurred, this instruction is a no-op. */ case OP_FinishSeek: { /* ncycle */ VdbeCursor *pC; /* The P1 index cursor */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; if( pC->deferredMoveto ){ rc = sqlite3VdbeFinishMoveto(pC); if( rc ) goto abort_due_to_error; } break; } /* Opcode: IdxGE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index ** key that omits the PRIMARY KEY. Compare this key value against the index ** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID ** fields at the end. ** ** If the P1 index entry is greater than or equal to the key value ** then jump to P2. Otherwise fall through to the next instruction. */ /* Opcode: IdxGT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index ** key that omits the PRIMARY KEY. Compare this key value against the index ** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID ** fields at the end. ** ** If the P1 index entry is greater than the key value ** then jump to P2. Otherwise fall through to the next instruction. */ /* Opcode: IdxLT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index ** key that omits the PRIMARY KEY or ROWID. Compare this key value against ** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ** ROWID on the P1 index. ** ** If the P1 index entry is less than the key value then jump to P2. ** Otherwise fall through to the next instruction. */ /* Opcode: IdxLE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index ** key that omits the PRIMARY KEY or ROWID. Compare this key value against ** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ** ROWID on the P1 index. ** ** If the P1 index entry is less than or equal to the key value then jump ** to P2. Otherwise fall through to the next instruction. */ case OP_IdxLE: /* jump, ncycle */ case OP_IdxGT: /* jump, ncycle */ case OP_IdxLT: /* jump, ncycle */ case OP_IdxGE: { /* jump, ncycle */ VdbeCursor *pC; int res; UnpackedRecord r; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->isOrdered ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0); assert( pC->deferredMoveto==0 ); assert( pOp->p4type==P4_INT32 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p4.i; if( pOp->opcodeopcode==OP_IdxLE || pOp->opcode==OP_IdxGT ); r.default_rc = -1; }else{ assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxLT ); r.default_rc = 0; } r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG { int i; for(i=0; ip3+i, &aMem[pOp->p3+i]); } } #endif /* Inlined version of sqlite3VdbeIdxKeyCompare() */ { i64 nCellKey = 0; BtCursor *pCur; Mem m; assert( pC->eCurType==CURTYPE_BTREE ); pCur = pC->uc.pCursor; assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); /* nCellKey will always be between 0 and 0xffffffff because of the way ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m); if( rc ) goto abort_due_to_error; res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, &r, 0); sqlite3VdbeMemReleaseMalloc(&m); } /* End of inlined sqlite3VdbeIdxKeyCompare() */ assert( (OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1) ); if( (pOp->opcode&1)==(OP_IdxLT&1) ){ assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT ); res = -res; }else{ assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxGT ); res++; } VdbeBranchTaken(res>0,2); assert( rc==SQLITE_OK ); if( res>0 ) goto jump_to_p2; break; } /* Opcode: Destroy P1 P2 P3 * * ** ** Delete an entire database table or index whose root page in the database ** file is given by P1. ** ** The table being destroyed is in the main database file if P3==0. If ** P3==1 then the table to be destroyed is in the auxiliary database file ** that is used to store tables create using CREATE TEMPORARY TABLE. ** ** If AUTOVACUUM is enabled then it is possible that another root page ** might be moved into the newly deleted root page in order to keep all ** root pages contiguous at the beginning of the database. The former ** value of the root page that moved - its value before the move occurred - ** is stored in register P2. If no page movement was required (because the ** table being dropped was already the last one in the database) then a ** zero is stored in register P2. If AUTOVACUUM is disabled then a zero ** is stored in register P2. ** ** This opcode throws an error if there are any active reader VMs when ** it is invoked. This is done to avoid the difficulty associated with ** updating existing cursors when a root page is moved in an AUTOVACUUM ** database. This error is thrown even if the database is not an AUTOVACUUM ** db in order to avoid introducing an incompatibility between autovacuum ** and non-autovacuum modes. ** ** See also: Clear */ case OP_Destroy: { /* out2 */ int iMoved; int iDb; sqlite3VdbeIncrWriteCounter(p, 0); assert( p->readOnly==0 ); assert( pOp->p1>1 ); pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Null; if( db->nVdbeRead > db->nVDestroy+1 ){ rc = SQLITE_LOCKED; p->errorAction = OE_Abort; goto abort_due_to_error; }else{ iDb = pOp->p3; assert( DbMaskTest(p->btreeMask, iDb) ); iMoved = 0; /* Not needed. Only to silence a warning. */ rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved); pOut->flags = MEM_Int; pOut->u.i = iMoved; if( rc ) goto abort_due_to_error; #ifndef SQLITE_OMIT_AUTOVACUUM if( iMoved!=0 ){ sqlite3RootPageMoved(db, iDb, iMoved, pOp->p1); /* All OP_Destroy operations occur on the same btree */ assert( resetSchemaOnFault==0 || resetSchemaOnFault==iDb+1 ); resetSchemaOnFault = iDb+1; } #endif } break; } /* Opcode: Clear P1 P2 P3 ** ** Delete all contents of the database table or index whose root page ** in the database file is given by P1. But, unlike Destroy, do not ** remove the table or index from the database file. ** ** The table being cleared is in the main database file if P2==0. If ** P2==1 then the table to be cleared is in the auxiliary database file ** that is used to store tables create using CREATE TEMPORARY TABLE. ** ** If the P3 value is non-zero, then the row change count is incremented ** by the number of rows in the table being cleared. If P3 is greater ** than zero, then the value stored in register P3 is also incremented ** by the number of rows in the table being cleared. ** ** See also: Destroy */ case OP_Clear: { i64 nChange; sqlite3VdbeIncrWriteCounter(p, 0); nChange = 0; assert( p->readOnly==0 ); assert( DbMaskTest(p->btreeMask, pOp->p2) ); rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, (u32)pOp->p1, &nChange); if( pOp->p3 ){ p->nChange += nChange; if( pOp->p3>0 ){ assert( memIsValid(&aMem[pOp->p3]) ); memAboutToChange(p, &aMem[pOp->p3]); aMem[pOp->p3].u.i += nChange; } } if( rc ) goto abort_due_to_error; break; } /* Opcode: ResetSorter P1 * * * * ** ** Delete all contents from the ephemeral table or sorter ** that is open on cursor P1. ** ** This opcode only works for cursors used for sorting and ** opened with OP_OpenEphemeral or OP_SorterOpen. */ case OP_ResetSorter: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); if( isSorter(pC) ){ sqlite3VdbeSorterReset(db, pC->uc.pSorter); }else{ assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->isEphemeral ); rc = sqlite3BtreeClearTableOfCursor(pC->uc.pCursor); if( rc ) goto abort_due_to_error; } break; } /* Opcode: CreateBtree P1 P2 P3 * * ** Synopsis: r[P2]=root iDb=P1 flags=P3 ** ** Allocate a new b-tree in the main database file if P1==0 or in the ** TEMP database file if P1==1 or in an attached database if ** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table ** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table. ** The root page number of the new b-tree is stored in register P2. */ case OP_CreateBtree: { /* out2 */ Pgno pgno; Db *pDb; sqlite3VdbeIncrWriteCounter(p, 0); pOut = out2Prerelease(p, pOp); pgno = 0; assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY ); assert( pOp->p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, pOp->p3); if( rc ) goto abort_due_to_error; pOut->u.i = pgno; break; } /* Opcode: SqlExec * * * P4 * ** ** Run the SQL statement or statements specified in the P4 string. ** Disable Auth and Trace callbacks while those statements are running if ** P1 is true. */ case OP_SqlExec: { char *zErr; #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth; #endif u8 mTrace; sqlite3VdbeIncrWriteCounter(p, 0); db->nSqlExec++; zErr = 0; #ifndef SQLITE_OMIT_AUTHORIZATION xAuth = db->xAuth; #endif mTrace = db->mTrace; if( pOp->p1 ){ #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = 0; #endif db->mTrace = 0; } rc = sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr); db->nSqlExec--; #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif db->mTrace = mTrace; if( zErr || rc ){ sqlite3VdbeError(p, "%s", zErr); sqlite3_free(zErr); if( rc==SQLITE_NOMEM ) goto no_mem; goto abort_due_to_error; } break; } /* Opcode: ParseSchema P1 * * P4 * ** ** Read and parse all entries from the schema table of database P1 ** that match the WHERE clause P4. If P4 is a NULL pointer, then the ** entire schema for P1 is reparsed. ** ** This opcode invokes the parser to create a new virtual machine, ** then runs the new virtual machine. It is thus a re-entrant opcode. */ case OP_ParseSchema: { int iDb; const char *zSchema; char *zSql; InitData initData; /* Any prepared statement that invokes this opcode will hold mutexes ** on every btree. This is a prerequisite for invoking ** sqlite3InitCallback(). */ #ifdef SQLITE_DEBUG for(iDb=0; iDbnDb; iDb++){ assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); } #endif iDb = pOp->p1; assert( iDb>=0 && iDbnDb ); assert( DbHasProperty(db, iDb, DB_SchemaLoaded) || db->mallocFailed || (CORRUPT_DB && (db->flags & SQLITE_NoSchemaError)!=0) ); #ifndef SQLITE_OMIT_ALTERTABLE if( pOp->p4.z==0 ){ sqlite3SchemaClear(db->aDb[iDb].pSchema); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; rc = sqlite3InitOne(db, iDb, &p->zErrMsg, pOp->p5); db->mDbFlags |= DBFLAG_SchemaChange; p->expired = 0; }else #endif { zSchema = LEGACY_SCHEMA_TABLE; initData.db = db; initData.iDb = iDb; initData.pzErrMsg = &p->zErrMsg; initData.mInitFlags = 0; initData.mxPage = sqlite3BtreeLastPage(db->aDb[iDb].pBt); zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid", db->aDb[iDb].zDbSName, zSchema, pOp->p4.z); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ assert( db->init.busy==0 ); db->init.busy = 1; initData.rc = SQLITE_OK; initData.nInitRow = 0; assert( !db->mallocFailed ); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); if( rc==SQLITE_OK ) rc = initData.rc; if( rc==SQLITE_OK && initData.nInitRow==0 ){ /* The OP_ParseSchema opcode with a non-NULL P4 argument should parse ** at least one SQL statement. Any less than that indicates that ** the sqlite_schema table is corrupt. */ rc = SQLITE_CORRUPT_BKPT; } sqlite3DbFreeNN(db, zSql); db->init.busy = 0; } } if( rc ){ sqlite3ResetAllSchemasOfConnection(db); if( rc==SQLITE_NOMEM ){ goto no_mem; } goto abort_due_to_error; } break; } #if !defined(SQLITE_OMIT_ANALYZE) /* Opcode: LoadAnalysis P1 * * * * ** ** Read the sqlite_stat1 table for database P1 and load the content ** of that table into the internal index hash table. This will cause ** the analysis to be used when preparing all subsequent queries. */ case OP_LoadAnalysis: { assert( pOp->p1>=0 && pOp->p1nDb ); rc = sqlite3AnalysisLoad(db, pOp->p1); if( rc ) goto abort_due_to_error; break; } #endif /* !defined(SQLITE_OMIT_ANALYZE) */ /* Opcode: DropTable P1 * * P4 * ** ** Remove the internal (in-memory) data structures that describe ** the table named P4 in database P1. This is called after a table ** is dropped from disk (using the Destroy opcode) in order to keep ** the internal representation of the ** schema consistent with what is on disk. */ case OP_DropTable: { sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p4.z); break; } /* Opcode: DropIndex P1 * * P4 * ** ** Remove the internal (in-memory) data structures that describe ** the index named P4 in database P1. This is called after an index ** is dropped from disk (using the Destroy opcode) ** in order to keep the internal representation of the ** schema consistent with what is on disk. */ case OP_DropIndex: { sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p4.z); break; } /* Opcode: DropTrigger P1 * * P4 * ** ** Remove the internal (in-memory) data structures that describe ** the trigger named P4 in database P1. This is called after a trigger ** is dropped from disk (using the Destroy opcode) in order to keep ** the internal representation of the ** schema consistent with what is on disk. */ case OP_DropTrigger: { sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p4.z); break; } #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* Opcode: IntegrityCk P1 P2 P3 P4 P5 ** ** Do an analysis of the currently open database. Store in ** register P1 the text of an error message describing any problems. ** If no problems are found, store a NULL in register P1. ** ** The register P3 contains one less than the maximum number of allowed errors. ** At most reg(P3) errors will be reported. ** In other words, the analysis stops as soon as reg(P1) errors are ** seen. Reg(P1) is updated with the number of errors remaining. ** ** The root page numbers of all tables in the database are integers ** stored in P4_INTARRAY argument. ** ** If P5 is not zero, the check is done on the auxiliary database ** file, not the main database file. ** ** This opcode is used to implement the integrity_check pragma. */ case OP_IntegrityCk: { int nRoot; /* Number of tables to check. (Number of root pages.) */ Pgno *aRoot; /* Array of rootpage numbers for tables to be checked */ int nErr; /* Number of errors reported */ char *z; /* Text of the error report */ Mem *pnErr; /* Register keeping track of errors remaining */ assert( p->bIsReader ); nRoot = pOp->p2; aRoot = pOp->p4.ai; assert( nRoot>0 ); assert( aRoot[0]==(Pgno)nRoot ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pnErr = &aMem[pOp->p3]; assert( (pnErr->flags & MEM_Int)!=0 ); assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 ); pIn1 = &aMem[pOp->p1]; assert( pOp->p5nDb ); assert( DbMaskTest(p->btreeMask, pOp->p5) ); rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot, (int)pnErr->u.i+1, &nErr, &z); sqlite3VdbeMemSetNull(pIn1); if( nErr==0 ){ assert( z==0 ); }else if( rc ){ sqlite3_free(z); goto abort_due_to_error; }else{ pnErr->u.i -= nErr-1; sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free); } UPDATE_MAX_BLOBSIZE(pIn1); sqlite3VdbeChangeEncoding(pIn1, encoding); goto check_for_interrupt; } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* Opcode: RowSetAdd P1 P2 * * * ** Synopsis: rowset(P1)=r[P2] ** ** Insert the integer value held by register P2 into a RowSet object ** held in register P1. ** ** An assertion fails if P2 is not an integer. */ case OP_RowSetAdd: { /* in1, in2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; assert( (pIn2->flags & MEM_Int)!=0 ); if( (pIn1->flags & MEM_Blob)==0 ){ if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem; } assert( sqlite3VdbeMemIsRowSet(pIn1) ); sqlite3RowSetInsert((RowSet*)pIn1->z, pIn2->u.i); break; } /* Opcode: RowSetRead P1 P2 P3 * * ** Synopsis: r[P3]=rowset(P1) ** ** Extract the smallest value from the RowSet object in P1 ** and put that value into register P3. ** Or, if RowSet object P1 is initially empty, leave P3 ** unchanged and jump to instruction P2. */ case OP_RowSetRead: { /* jump, in1, out3 */ i64 val; pIn1 = &aMem[pOp->p1]; assert( (pIn1->flags & MEM_Blob)==0 || sqlite3VdbeMemIsRowSet(pIn1) ); if( (pIn1->flags & MEM_Blob)==0 || sqlite3RowSetNext((RowSet*)pIn1->z, &val)==0 ){ /* The boolean index is empty */ sqlite3VdbeMemSetNull(pIn1); VdbeBranchTaken(1,2); goto jump_to_p2_and_check_for_interrupt; }else{ /* A value was pulled from the index */ VdbeBranchTaken(0,2); sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val); } goto check_for_interrupt; } /* Opcode: RowSetTest P1 P2 P3 P4 ** Synopsis: if r[P3] in rowset(P1) goto P2 ** ** Register P3 is assumed to hold a 64-bit integer value. If register P1 ** contains a RowSet object and that RowSet object contains ** the value held in P3, jump to register P2. Otherwise, insert the ** integer in P3 into the RowSet and continue on to the ** next opcode. ** ** The RowSet object is optimized for the case where sets of integers ** are inserted in distinct phases, which each set contains no duplicates. ** Each set is identified by a unique P4 value. The first set ** must have P4==0, the final set must have P4==-1, and for all other sets ** must have P4>0. ** ** This allows optimizations: (a) when P4==0 there is no need to test ** the RowSet object for P3, as it is guaranteed not to contain it, ** (b) when P4==-1 there is no need to insert the value, as it will ** never be tested for, and (c) when a value that is part of set X is ** inserted, there is no need to search to see if the same value was ** previously inserted as part of set X (only if it was previously ** inserted as part of some other set). */ case OP_RowSetTest: { /* jump, in1, in3 */ int iSet; int exists; pIn1 = &aMem[pOp->p1]; pIn3 = &aMem[pOp->p3]; iSet = pOp->p4.i; assert( pIn3->flags&MEM_Int ); /* If there is anything other than a rowset object in memory cell P1, ** delete it now and initialize P1 with an empty rowset */ if( (pIn1->flags & MEM_Blob)==0 ){ if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem; } assert( sqlite3VdbeMemIsRowSet(pIn1) ); assert( pOp->p4type==P4_INT32 ); assert( iSet==-1 || iSet>=0 ); if( iSet ){ exists = sqlite3RowSetTest((RowSet*)pIn1->z, iSet, pIn3->u.i); VdbeBranchTaken(exists!=0,2); if( exists ) goto jump_to_p2; } if( iSet>=0 ){ sqlite3RowSetInsert((RowSet*)pIn1->z, pIn3->u.i); } break; } #ifndef SQLITE_OMIT_TRIGGER /* Opcode: Program P1 P2 P3 P4 P5 ** ** Execute the trigger program passed as P4 (type P4_SUBPROGRAM). ** ** P1 contains the address of the memory cell that contains the first memory ** cell in an array of values used as arguments to the sub-program. P2 ** contains the address to jump to if the sub-program throws an IGNORE ** exception using the RAISE() function. Register P3 contains the address ** of a memory cell in this (the parent) VM that is used to allocate the ** memory required by the sub-vdbe at runtime. ** ** P4 is a pointer to the VM containing the trigger program. ** ** If P5 is non-zero, then recursive program invocation is enabled. */ case OP_Program: { /* jump */ int nMem; /* Number of memory registers for sub-program */ int nByte; /* Bytes of runtime space required for sub-program */ Mem *pRt; /* Register to allocate runtime space */ Mem *pMem; /* Used to iterate through memory cells */ Mem *pEnd; /* Last memory cell in new array */ VdbeFrame *pFrame; /* New vdbe frame to execute in */ SubProgram *pProgram; /* Sub-program to execute */ void *t; /* Token identifying trigger */ pProgram = pOp->p4.pProgram; pRt = &aMem[pOp->p3]; assert( pProgram->nOp>0 ); /* If the p5 flag is clear, then recursive invocation of triggers is ** disabled for backwards compatibility (p5 is set if this sub-program ** is really a trigger, not a foreign key action, and the flag set ** and cleared by the "PRAGMA recursive_triggers" command is clear). ** ** It is recursive invocation of triggers, at the SQL level, that is ** disabled. In some cases a single trigger may generate more than one ** SubProgram (if the trigger may be executed with more than one different ** ON CONFLICT algorithm). SubProgram structures associated with a ** single trigger all have the same value for the SubProgram.token ** variable. */ if( pOp->p5 ){ t = pProgram->token; for(pFrame=p->pFrame; pFrame && pFrame->token!=t; pFrame=pFrame->pParent); if( pFrame ) break; } if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){ rc = SQLITE_ERROR; sqlite3VdbeError(p, "too many levels of trigger recursion"); goto abort_due_to_error; } /* Register pRt is used to store the memory required to save the state ** of the current program, and the memory required at runtime to execute ** the trigger program. If this trigger has been fired before, then pRt ** is already allocated. Otherwise, it must be initialized. */ if( (pRt->flags&MEM_Blob)==0 ){ /* SubProgram.nMem is set to the number of memory cells used by the ** program stored in SubProgram.aOp. As well as these, one memory ** cell is required for each cursor used by the program. Set local ** variable nMem (and later, VdbeFrame.nChildMem) to this value. */ nMem = pProgram->nMem + pProgram->nCsr; assert( nMem>0 ); if( pProgram->nCsr==0 ) nMem++; nByte = ROUND8(sizeof(VdbeFrame)) + nMem * sizeof(Mem) + pProgram->nCsr * sizeof(VdbeCursor*) + (pProgram->nOp + 7)/8; pFrame = sqlite3DbMallocZero(db, nByte); if( !pFrame ){ goto no_mem; } sqlite3VdbeMemRelease(pRt); pRt->flags = MEM_Blob|MEM_Dyn; pRt->z = (char*)pFrame; pRt->n = nByte; pRt->xDel = sqlite3VdbeFrameMemDel; pFrame->v = p; pFrame->nChildMem = nMem; pFrame->nChildCsr = pProgram->nCsr; pFrame->pc = (int)(pOp - aOp); pFrame->aMem = p->aMem; pFrame->nMem = p->nMem; pFrame->apCsr = p->apCsr; pFrame->nCursor = p->nCursor; pFrame->aOp = p->aOp; pFrame->nOp = p->nOp; pFrame->token = pProgram->token; #ifdef SQLITE_DEBUG pFrame->iFrameMagic = SQLITE_FRAME_MAGIC; #endif pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ pMem->flags = MEM_Undefined; pMem->db = db; } }else{ pFrame = (VdbeFrame*)pRt->z; assert( pRt->xDel==sqlite3VdbeFrameMemDel ); assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) ); assert( pProgram->nCsr==pFrame->nChildCsr ); assert( (int)(pOp - aOp)==pFrame->pc ); } p->nFrame++; pFrame->pParent = p->pFrame; pFrame->lastRowid = db->lastRowid; pFrame->nChange = p->nChange; pFrame->nDbChange = p->db->nChange; assert( pFrame->pAuxData==0 ); pFrame->pAuxData = p->pAuxData; p->pAuxData = 0; p->nChange = 0; p->pFrame = pFrame; p->aMem = aMem = VdbeFrameMem(pFrame); p->nMem = pFrame->nChildMem; p->nCursor = (u16)pFrame->nChildCsr; p->apCsr = (VdbeCursor **)&aMem[p->nMem]; pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr]; memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8); p->aOp = aOp = pProgram->aOp; p->nOp = pProgram->nOp; #ifdef SQLITE_DEBUG /* Verify that second and subsequent executions of the same trigger do not ** try to reuse register values from the first use. */ { int i; for(i=0; inMem; i++){ aMem[i].pScopyFrom = 0; /* Prevent false-positive AboutToChange() errs */ MemSetTypeFlag(&aMem[i], MEM_Undefined); /* Fault if this reg is reused */ } } #endif pOp = &aOp[-1]; goto check_for_interrupt; } /* Opcode: Param P1 P2 * * * ** ** This opcode is only ever present in sub-programs called via the ** OP_Program instruction. Copy a value currently stored in a memory ** cell of the calling (parent) frame to cell P2 in the current frames ** address space. This is used by trigger programs to access the new.* ** and old.* values. ** ** The address of the cell in the parent frame is determined by adding ** the value of the P1 argument to the value of the P1 argument to the ** calling OP_Program instruction. */ case OP_Param: { /* out2 */ VdbeFrame *pFrame; Mem *pIn; pOut = out2Prerelease(p, pOp); pFrame = p->pFrame; pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1]; sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem); break; } #endif /* #ifndef SQLITE_OMIT_TRIGGER */ #ifndef SQLITE_OMIT_FOREIGN_KEY /* Opcode: FkCounter P1 P2 * * * ** Synopsis: fkctr[P1]+=P2 ** ** Increment a "constraint counter" by P2 (P2 may be negative or positive). ** If P1 is non-zero, the database constraint counter is incremented ** (deferred foreign key constraints). Otherwise, if P1 is zero, the ** statement counter is incremented (immediate foreign key constraints). */ case OP_FkCounter: { if( db->flags & SQLITE_DeferFKs ){ db->nDeferredImmCons += pOp->p2; }else if( pOp->p1 ){ db->nDeferredCons += pOp->p2; }else{ p->nFkConstraint += pOp->p2; } break; } /* Opcode: FkIfZero P1 P2 * * * ** Synopsis: if fkctr[P1]==0 goto P2 ** ** This opcode tests if a foreign key constraint-counter is currently zero. ** If so, jump to instruction P2. Otherwise, fall through to the next ** instruction. ** ** If P1 is non-zero, then the jump is taken if the database constraint-counter ** is zero (the one that counts deferred constraint violations). If P1 is ** zero, the jump is taken if the statement constraint-counter is zero ** (immediate foreign key constraint violations). */ case OP_FkIfZero: { /* jump */ if( pOp->p1 ){ VdbeBranchTaken(db->nDeferredCons==0 && db->nDeferredImmCons==0, 2); if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) goto jump_to_p2; }else{ VdbeBranchTaken(p->nFkConstraint==0 && db->nDeferredImmCons==0, 2); if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) goto jump_to_p2; } break; } #endif /* #ifndef SQLITE_OMIT_FOREIGN_KEY */ #ifndef SQLITE_OMIT_AUTOINCREMENT /* Opcode: MemMax P1 P2 * * * ** Synopsis: r[P1]=max(r[P1],r[P2]) ** ** P1 is a register in the root frame of this VM (the root frame is ** different from the current frame if this instruction is being executed ** within a sub-program). Set the value of register P1 to the maximum of ** its current value and the value in register P2. ** ** This instruction throws an error if the memory cell is not initially ** an integer. */ case OP_MemMax: { /* in2 */ VdbeFrame *pFrame; if( p->pFrame ){ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); pIn1 = &pFrame->aMem[pOp->p1]; }else{ pIn1 = &aMem[pOp->p1]; } assert( memIsValid(pIn1) ); sqlite3VdbeMemIntegerify(pIn1); pIn2 = &aMem[pOp->p2]; sqlite3VdbeMemIntegerify(pIn2); if( pIn1->u.iu.i){ pIn1->u.i = pIn2->u.i; } break; } #endif /* SQLITE_OMIT_AUTOINCREMENT */ /* Opcode: IfPos P1 P2 P3 * * ** Synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 ** ** Register P1 must contain an integer. ** If the value of register P1 is 1 or greater, subtract P3 from the ** value in P1 and jump to P2. ** ** If the initial value of register P1 is less than 1, then the ** value is unchanged and control passes through to the next instruction. */ case OP_IfPos: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); VdbeBranchTaken( pIn1->u.i>0, 2); if( pIn1->u.i>0 ){ pIn1->u.i -= pOp->p3; goto jump_to_p2; } break; } /* Opcode: OffsetLimit P1 P2 P3 * * ** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) ** ** This opcode performs a commonly used computation associated with ** LIMIT and OFFSET processing. r[P1] holds the limit counter. r[P3] ** holds the offset counter. The opcode computes the combined value ** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2] ** value computed is the total number of rows that will need to be ** visited in order to complete the query. ** ** If r[P3] is zero or negative, that means there is no OFFSET ** and r[P2] is set to be the value of the LIMIT, r[P1]. ** ** if r[P1] is zero or negative, that means there is no LIMIT ** and r[P2] is set to -1. ** ** Otherwise, r[P2] is set to the sum of r[P1] and r[P3]. */ case OP_OffsetLimit: { /* in1, out2, in3 */ i64 x; pIn1 = &aMem[pOp->p1]; pIn3 = &aMem[pOp->p3]; pOut = out2Prerelease(p, pOp); assert( pIn1->flags & MEM_Int ); assert( pIn3->flags & MEM_Int ); x = pIn1->u.i; if( x<=0 || sqlite3AddInt64(&x, pIn3->u.i>0?pIn3->u.i:0) ){ /* If the LIMIT is less than or equal to zero, loop forever. This ** is documented. But also, if the LIMIT+OFFSET exceeds 2^63 then ** also loop forever. This is undocumented. In fact, one could argue ** that the loop should terminate. But assuming 1 billion iterations ** per second (far exceeding the capabilities of any current hardware) ** it would take nearly 300 years to actually reach the limit. So ** looping forever is a reasonable approximation. */ pOut->u.i = -1; }else{ pOut->u.i = x; } break; } /* Opcode: IfNotZero P1 P2 * * * ** Synopsis: if r[P1]!=0 then r[P1]--, goto P2 ** ** Register P1 must contain an integer. If the content of register P1 is ** initially greater than zero, then decrement the value in register P1. ** If it is non-zero (negative or positive) and then also jump to P2. ** If register P1 is initially zero, leave it unchanged and fall through. */ case OP_IfNotZero: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); VdbeBranchTaken(pIn1->u.i<0, 2); if( pIn1->u.i ){ if( pIn1->u.i>0 ) pIn1->u.i--; goto jump_to_p2; } break; } /* Opcode: DecrJumpZero P1 P2 * * * ** Synopsis: if (--r[P1])==0 goto P2 ** ** Register P1 must hold an integer. Decrement the value in P1 ** and jump to P2 if the new value is exactly zero. */ case OP_DecrJumpZero: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; VdbeBranchTaken(pIn1->u.i==0, 2); if( pIn1->u.i==0 ) goto jump_to_p2; break; } /* Opcode: AggStep * P2 P3 P4 P5 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** ** Execute the xStep function for an aggregate. ** The function has P5 arguments. P4 is a pointer to the ** FuncDef structure that specifies the function. Register P3 is the ** accumulator. ** ** The P5 arguments are taken from register P2 and its ** successors. */ /* Opcode: AggInverse * P2 P3 P4 P5 ** Synopsis: accum=r[P3] inverse(r[P2@P5]) ** ** Execute the xInverse function for an aggregate. ** The function has P5 arguments. P4 is a pointer to the ** FuncDef structure that specifies the function. Register P3 is the ** accumulator. ** ** The P5 arguments are taken from register P2 and its ** successors. */ /* Opcode: AggStep1 P1 P2 P3 P4 P5 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** ** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an ** aggregate. The function has P5 arguments. P4 is a pointer to the ** FuncDef structure that specifies the function. Register P3 is the ** accumulator. ** ** The P5 arguments are taken from register P2 and its ** successors. ** ** This opcode is initially coded as OP_AggStep0. On first evaluation, ** the FuncDef stored in P4 is converted into an sqlite3_context and ** the opcode is changed. In this way, the initialization of the ** sqlite3_context only happens once, instead of on each call to the ** step function. */ case OP_AggInverse: case OP_AggStep: { int n; sqlite3_context *pCtx; assert( pOp->p4type==P4_FUNCDEF ); n = pOp->p5; assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); pCtx = sqlite3DbMallocRawNN(db, n*sizeof(sqlite3_value*) + (sizeof(pCtx[0]) + sizeof(Mem) - sizeof(sqlite3_value*))); if( pCtx==0 ) goto no_mem; pCtx->pMem = 0; pCtx->pOut = (Mem*)&(pCtx->argv[n]); sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null); pCtx->pFunc = pOp->p4.pFunc; pCtx->iOp = (int)(pOp - aOp); pCtx->pVdbe = p; pCtx->skipFlag = 0; pCtx->isError = 0; pCtx->enc = encoding; pCtx->argc = n; pOp->p4type = P4_FUNCCTX; pOp->p4.pCtx = pCtx; /* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */ assert( pOp->p1==(pOp->opcode==OP_AggInverse) ); pOp->opcode = OP_AggStep1; /* Fall through into OP_AggStep */ /* no break */ deliberate_fall_through } case OP_AggStep1: { int i; sqlite3_context *pCtx; Mem *pMem; assert( pOp->p4type==P4_FUNCCTX ); pCtx = pOp->p4.pCtx; pMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG if( pOp->p1 ){ /* This is an OP_AggInverse call. Verify that xStep has always ** been called at least once prior to any xInverse call. */ assert( pMem->uTemp==0x1122e0e3 ); }else{ /* This is an OP_AggStep call. Mark it as such. */ pMem->uTemp = 0x1122e0e3; } #endif /* If this function is inside of a trigger, the register array in aMem[] ** might change from one evaluation to the next. The next block of code ** checks to see if the register array has changed, and if so it ** reinitializes the relevant parts of the sqlite3_context object */ if( pCtx->pMem != pMem ){ pCtx->pMem = pMem; for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; } #ifdef SQLITE_DEBUG for(i=0; iargc; i++){ assert( memIsValid(pCtx->argv[i]) ); REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); } #endif pMem->n++; assert( pCtx->pOut->flags==MEM_Null ); assert( pCtx->isError==0 ); assert( pCtx->skipFlag==0 ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pOp->p1 ){ (pCtx->pFunc->xInverse)(pCtx,pCtx->argc,pCtx->argv); }else #endif (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */ if( pCtx->isError ){ if( pCtx->isError>0 ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut)); rc = pCtx->isError; } if( pCtx->skipFlag ){ assert( pOp[-1].opcode==OP_CollSeq ); i = pOp[-1].p1; if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1); pCtx->skipFlag = 0; } sqlite3VdbeMemRelease(pCtx->pOut); pCtx->pOut->flags = MEM_Null; pCtx->isError = 0; if( rc ) goto abort_due_to_error; } assert( pCtx->pOut->flags==MEM_Null ); assert( pCtx->skipFlag==0 ); break; } /* Opcode: AggFinal P1 P2 * P4 * ** Synopsis: accum=r[P1] N=P2 ** ** P1 is the memory location that is the accumulator for an aggregate ** or window function. Execute the finalizer function ** for an aggregate and store the result in P1. ** ** P2 is the number of arguments that the step function takes and ** P4 is a pointer to the FuncDef for this function. The P2 ** argument is not used by this opcode. It is only there to disambiguate ** functions that can take varying numbers of arguments. The ** P4 argument is only needed for the case where ** the step function was not previously called. */ /* Opcode: AggValue * P2 P3 P4 * ** Synopsis: r[P3]=value N=P2 ** ** Invoke the xValue() function and store the result in register P3. ** ** P2 is the number of arguments that the step function takes and ** P4 is a pointer to the FuncDef for this function. The P2 ** argument is not used by this opcode. It is only there to disambiguate ** functions that can take varying numbers of arguments. The ** P4 argument is only needed for the case where ** the step function was not previously called. */ case OP_AggValue: case OP_AggFinal: { Mem *pMem; assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); assert( pOp->p3==0 || pOp->opcode==OP_AggValue ); pMem = &aMem[pOp->p1]; assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pOp->p3 ){ memAboutToChange(p, &aMem[pOp->p3]); rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc); pMem = &aMem[pOp->p3]; }else #endif { rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); } if( rc ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem)); goto abort_due_to_error; } sqlite3VdbeChangeEncoding(pMem, encoding); UPDATE_MAX_BLOBSIZE(pMem); REGISTER_TRACE((int)(pMem-aMem), pMem); break; } #ifndef SQLITE_OMIT_WAL /* Opcode: Checkpoint P1 P2 P3 * * ** ** Checkpoint database P1. This is a no-op if P1 is not currently in ** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL, ** RESTART, or TRUNCATE. Write 1 or 0 into mem[P3] if the checkpoint returns ** SQLITE_BUSY or not, respectively. Write the number of pages in the ** WAL after the checkpoint into mem[P3+1] and the number of pages ** in the WAL that have been checkpointed after the checkpoint ** completes into mem[P3+2]. However on an error, mem[P3+1] and ** mem[P3+2] are initialized to -1. */ case OP_Checkpoint: { int i; /* Loop counter */ int aRes[3]; /* Results */ Mem *pMem; /* Write results here */ assert( p->readOnly==0 ); aRes[0] = 0; aRes[1] = aRes[2] = -1; assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE || pOp->p2==SQLITE_CHECKPOINT_FULL || pOp->p2==SQLITE_CHECKPOINT_RESTART || pOp->p2==SQLITE_CHECKPOINT_TRUNCATE ); rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]); if( rc ){ if( rc!=SQLITE_BUSY ) goto abort_due_to_error; rc = SQLITE_OK; aRes[0] = 1; } for(i=0, pMem = &aMem[pOp->p3]; i<3; i++, pMem++){ sqlite3VdbeMemSetInt64(pMem, (i64)aRes[i]); } break; }; #endif #ifndef SQLITE_OMIT_PRAGMA /* Opcode: JournalMode P1 P2 P3 * * ** ** Change the journal mode of database P1 to P3. P3 must be one of the ** PAGER_JOURNALMODE_XXX values. If changing between the various rollback ** modes (delete, truncate, persist, off and memory), this is a simple ** operation. No IO is required. ** ** If changing into or out of WAL mode the procedure is more complicated. ** ** Write a string containing the final journal-mode to register P2. */ case OP_JournalMode: { /* out2 */ Btree *pBt; /* Btree to change journal mode of */ Pager *pPager; /* Pager associated with pBt */ int eNew; /* New journal mode */ int eOld; /* The old journal mode */ #ifndef SQLITE_OMIT_WAL const char *zFilename; /* Name of database file for pPager */ #endif pOut = out2Prerelease(p, pOp); eNew = pOp->p3; assert( eNew==PAGER_JOURNALMODE_DELETE || eNew==PAGER_JOURNALMODE_TRUNCATE || eNew==PAGER_JOURNALMODE_PERSIST || eNew==PAGER_JOURNALMODE_OFF || eNew==PAGER_JOURNALMODE_MEMORY || eNew==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_QUERY ); assert( pOp->p1>=0 && pOp->p1nDb ); assert( p->readOnly==0 ); pBt = db->aDb[pOp->p1].pBt; pPager = sqlite3BtreePager(pBt); eOld = sqlite3PagerGetJournalMode(pPager); if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld; assert( sqlite3BtreeHoldsMutex(pBt) ); if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld; #ifndef SQLITE_OMIT_WAL zFilename = sqlite3PagerFilename(pPager, 1); /* Do not allow a transition to journal_mode=WAL for a database ** in temporary storage or if the VFS does not support shared memory */ if( eNew==PAGER_JOURNALMODE_WAL && (sqlite3Strlen30(zFilename)==0 /* Temp file */ || !sqlite3PagerWalSupported(pPager)) /* No shared-memory support */ ){ eNew = eOld; } if( (eNew!=eOld) && (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL) ){ if( !db->autoCommit || db->nVdbeRead>1 ){ rc = SQLITE_ERROR; sqlite3VdbeError(p, "cannot change %s wal mode from within a transaction", (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of") ); goto abort_due_to_error; }else{ if( eOld==PAGER_JOURNALMODE_WAL ){ /* If leaving WAL mode, close the log file. If successful, the call ** to PagerCloseWal() checkpoints and deletes the write-ahead-log ** file. An EXCLUSIVE lock may still be held on the database file ** after a successful return. */ rc = sqlite3PagerCloseWal(pPager, db); if( rc==SQLITE_OK ){ sqlite3PagerSetJournalMode(pPager, eNew); } }else if( eOld==PAGER_JOURNALMODE_MEMORY ){ /* Cannot transition directly from MEMORY to WAL. Use mode OFF ** as an intermediate */ sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_OFF); } /* Open a transaction on the database file. Regardless of the journal ** mode, this transaction always uses a rollback journal. */ assert( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ); if( rc==SQLITE_OK ){ rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); } } } #endif /* ifndef SQLITE_OMIT_WAL */ if( rc ) eNew = eOld; eNew = sqlite3PagerSetJournalMode(pPager, eNew); pOut->flags = MEM_Str|MEM_Static|MEM_Term; pOut->z = (char *)sqlite3JournalModename(eNew); pOut->n = sqlite3Strlen30(pOut->z); pOut->enc = SQLITE_UTF8; sqlite3VdbeChangeEncoding(pOut, encoding); if( rc ) goto abort_due_to_error; break; }; #endif /* SQLITE_OMIT_PRAGMA */ #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) /* Opcode: Vacuum P1 P2 * * * ** ** Vacuum the entire database P1. P1 is 0 for "main", and 2 or more ** for an attached database. The "temp" database may not be vacuumed. ** ** If P2 is not zero, then it is a register holding a string which is ** the file into which the result of vacuum should be written. When ** P2 is zero, the vacuum overwrites the original database. */ case OP_Vacuum: { assert( p->readOnly==0 ); rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1, pOp->p2 ? &aMem[pOp->p2] : 0); if( rc ) goto abort_due_to_error; break; } #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) /* Opcode: IncrVacuum P1 P2 * * * ** ** Perform a single step of the incremental vacuum procedure on ** the P1 database. If the vacuum has finished, jump to instruction ** P2. Otherwise, fall through to the next instruction. */ case OP_IncrVacuum: { /* jump */ Btree *pBt; assert( pOp->p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pBt = db->aDb[pOp->p1].pBt; rc = sqlite3BtreeIncrVacuum(pBt); VdbeBranchTaken(rc==SQLITE_DONE,2); if( rc ){ if( rc!=SQLITE_DONE ) goto abort_due_to_error; rc = SQLITE_OK; goto jump_to_p2; } break; } #endif /* Opcode: Expire P1 P2 * * * ** ** Cause precompiled statements to expire. When an expired statement ** is executed using sqlite3_step() it will either automatically ** reprepare itself (if it was originally created using sqlite3_prepare_v2()) ** or it will fail with SQLITE_SCHEMA. ** ** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, ** then only the currently executing statement is expired. ** ** If P2 is 0, then SQL statements are expired immediately. If P2 is 1, ** then running SQL statements are allowed to continue to run to completion. ** The P2==1 case occurs when a CREATE INDEX or similar schema change happens ** that might help the statement run faster but which does not affect the ** correctness of operation. */ case OP_Expire: { assert( pOp->p2==0 || pOp->p2==1 ); if( !pOp->p1 ){ sqlite3ExpirePreparedStatements(db, pOp->p2); }else{ p->expired = pOp->p2+1; } break; } /* Opcode: CursorLock P1 * * * * ** ** Lock the btree to which cursor P1 is pointing so that the btree cannot be ** written by an other cursor. */ case OP_CursorLock: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); sqlite3BtreeCursorPin(pC->uc.pCursor); break; } /* Opcode: CursorUnlock P1 * * * * ** ** Unlock the btree to which cursor P1 is pointing so that it can be ** written by other cursors. */ case OP_CursorUnlock: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); sqlite3BtreeCursorUnpin(pC->uc.pCursor); break; } #ifndef SQLITE_OMIT_SHARED_CACHE /* Opcode: TableLock P1 P2 P3 P4 * ** Synopsis: iDb=P1 root=P2 write=P3 ** ** Obtain a lock on a particular table. This instruction is only used when ** the shared-cache feature is enabled. ** ** P1 is the index of the database in sqlite3.aDb[] of the database ** on which the lock is acquired. A readlock is obtained if P3==0 or ** a write lock if P3==1. ** ** P2 contains the root-page of the table to lock. ** ** P4 contains a pointer to the name of the table being locked. This is only ** used to generate an error message if the lock cannot be obtained. */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){ int p1 = pOp->p1; assert( p1>=0 && p1nDb ); assert( DbMaskTest(p->btreeMask, p1) ); assert( isWriteLock==0 || isWriteLock==1 ); rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); if( rc ){ if( (rc&0xFF)==SQLITE_LOCKED ){ const char *z = pOp->p4.z; sqlite3VdbeError(p, "database table is locked: %s", z); } goto abort_due_to_error; } } break; } #endif /* SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VBegin * * * P4 * ** ** P4 may be a pointer to an sqlite3_vtab structure. If so, call the ** xBegin method for that table. ** ** Also, whether or not P4 is set, check that this is not being called from ** within a callback to a virtual table xSync() method. If it is, the error ** code will be set to SQLITE_LOCKED. */ case OP_VBegin: { VTable *pVTab; pVTab = pOp->p4.pVtab; rc = sqlite3VtabBegin(db, pVTab); if( pVTab ) sqlite3VtabImportErrmsg(p, pVTab->pVtab); if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VCreate P1 P2 * * * ** ** P2 is a register that holds the name of a virtual table in database ** P1. Call the xCreate method for that table. */ case OP_VCreate: { Mem sMem; /* For storing the record being decoded */ const char *zTab; /* Name of the virtual table */ memset(&sMem, 0, sizeof(sMem)); sMem.db = db; /* Because P2 is always a static string, it is impossible for the ** sqlite3VdbeMemCopy() to fail */ assert( (aMem[pOp->p2].flags & MEM_Str)!=0 ); assert( (aMem[pOp->p2].flags & MEM_Static)!=0 ); rc = sqlite3VdbeMemCopy(&sMem, &aMem[pOp->p2]); assert( rc==SQLITE_OK ); zTab = (const char*)sqlite3_value_text(&sMem); assert( zTab || db->mallocFailed ); if( zTab ){ rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg); } sqlite3VdbeMemRelease(&sMem); if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VDestroy P1 * * P4 * ** ** P4 is the name of a virtual table in database P1. Call the xDestroy method ** of that table. */ case OP_VDestroy: { db->nVDestroy++; rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z); db->nVDestroy--; assert( p->errorAction==OE_Abort && p->usesStmtJournal ); if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VOpen P1 * * P4 * ** ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** P1 is a cursor number. This opcode opens a cursor to the virtual ** table and stores that cursor in P1. */ case OP_VOpen: { /* ncycle */ VdbeCursor *pCur; sqlite3_vtab_cursor *pVCur; sqlite3_vtab *pVtab; const sqlite3_module *pModule; assert( p->bIsReader ); pCur = 0; pVCur = 0; pVtab = pOp->p4.pVtab->pVtab; if( pVtab==0 || NEVER(pVtab->pModule==0) ){ rc = SQLITE_LOCKED; goto abort_due_to_error; } pModule = pVtab->pModule; rc = pModule->xOpen(pVtab, &pVCur); sqlite3VtabImportErrmsg(p, pVtab); if( rc ) goto abort_due_to_error; /* Initialize sqlite3_vtab_cursor base class */ pVCur->pVtab = pVtab; /* Initialize vdbe cursor object */ pCur = allocateCursor(p, pOp->p1, 0, CURTYPE_VTAB); if( pCur ){ pCur->uc.pVCur = pVCur; pVtab->nRef++; }else{ assert( db->mallocFailed ); pModule->xClose(pVCur); goto no_mem; } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VCheck P1 P2 P3 P4 * ** ** P4 is a pointer to a Table object that is a virtual table in schema P1 ** that supports the xIntegrity() method. This opcode runs the xIntegrity() ** method for that virtual table, using P3 as the integer argument. If ** an error is reported back, the table name is prepended to the error ** message and that message is stored in P2. If no errors are seen, ** register P2 is set to NULL. */ case OP_VCheck: { /* out2 */ Table *pTab; sqlite3_vtab *pVtab; const sqlite3_module *pModule; char *zErr = 0; pOut = &aMem[pOp->p2]; sqlite3VdbeMemSetNull(pOut); /* Innocent until proven guilty */ assert( pOp->p4type==P4_TABLEREF ); pTab = pOp->p4.pTab; assert( pTab!=0 ); assert( pTab->nTabRef>0 ); assert( IsVirtual(pTab) ); if( pTab->u.vtab.p==0 ) break; pVtab = pTab->u.vtab.p->pVtab; assert( pVtab!=0 ); pModule = pVtab->pModule; assert( pModule!=0 ); assert( pModule->iVersion>=4 ); assert( pModule->xIntegrity!=0 ); sqlite3VtabLock(pTab->u.vtab.p); assert( pOp->p1>=0 && pOp->p1nDb ); rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName, pOp->p3, &zErr); sqlite3VtabUnlock(pTab->u.vtab.p); if( rc ){ sqlite3_free(zErr); goto abort_due_to_error; } if( zErr ){ sqlite3VdbeMemSetStr(pOut, zErr, -1, SQLITE_UTF8, sqlite3_free); } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VInitIn P1 P2 P3 * * ** Synopsis: r[P2]=ValueList(P1,P3) ** ** Set register P2 to be a pointer to a ValueList object for cursor P1 ** with cache register P3 and output register P3+1. This ValueList object ** can be used as the first argument to sqlite3_vtab_in_first() and ** sqlite3_vtab_in_next() to extract all of the values stored in the P1 ** cursor. Register P3 is used to hold the values returned by ** sqlite3_vtab_in_first() and sqlite3_vtab_in_next(). */ case OP_VInitIn: { /* out2, ncycle */ VdbeCursor *pC; /* The cursor containing the RHS values */ ValueList *pRhs; /* New ValueList object to put in reg[P2] */ pC = p->apCsr[pOp->p1]; pRhs = sqlite3_malloc64( sizeof(*pRhs) ); if( pRhs==0 ) goto no_mem; pRhs->pCsr = pC->uc.pCursor; pRhs->pOut = &aMem[pOp->p3]; pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Null; sqlite3VdbeMemSetPointer(pOut, pRhs, "ValueList", sqlite3VdbeValueListFree); break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VFilter P1 P2 P3 P4 * ** Synopsis: iplan=r[P3] zplan='P4' ** ** P1 is a cursor opened using VOpen. P2 is an address to jump to if ** the filtered result set is empty. ** ** P4 is either NULL or a string that was generated by the xBestIndex ** method of the module. The interpretation of the P4 string is left ** to the module implementation. ** ** This opcode invokes the xFilter method on the virtual table specified ** by P1. The integer query plan parameter to xFilter is stored in register ** P3. Register P3+1 stores the argc parameter to be passed to the ** xFilter method. Registers P3+2..P3+1+argc are the argc ** additional parameters which are passed to ** xFilter as argv. Register P3+2 becomes argv[0] when passed to xFilter. ** ** A jump is made to P2 if the result set after filtering would be empty. */ case OP_VFilter: { /* jump, ncycle */ int nArg; int iQuery; const sqlite3_module *pModule; Mem *pQuery; Mem *pArgc; sqlite3_vtab_cursor *pVCur; sqlite3_vtab *pVtab; VdbeCursor *pCur; int res; int i; Mem **apArg; pQuery = &aMem[pOp->p3]; pArgc = &pQuery[1]; pCur = p->apCsr[pOp->p1]; assert( memIsValid(pQuery) ); REGISTER_TRACE(pOp->p3, pQuery); assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); pVCur = pCur->uc.pVCur; pVtab = pVCur->pVtab; pModule = pVtab->pModule; /* Grab the index number and argc parameters */ assert( (pQuery->flags&MEM_Int)!=0 && pArgc->flags==MEM_Int ); nArg = (int)pArgc->u.i; iQuery = (int)pQuery->u.i; /* Invoke the xFilter method */ apArg = p->apArg; for(i = 0; ixFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg); sqlite3VtabImportErrmsg(p, pVtab); if( rc ) goto abort_due_to_error; res = pModule->xEof(pVCur); pCur->nullRow = 0; VdbeBranchTaken(res!=0,2); if( res ) goto jump_to_p2; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VColumn P1 P2 P3 * P5 ** Synopsis: r[P3]=vcolumn(P2) ** ** Store in register P3 the value of the P2-th column of ** the current row of the virtual-table of cursor P1. ** ** If the VColumn opcode is being used to fetch the value of ** an unchanging column during an UPDATE operation, then the P5 ** value is OPFLAG_NOCHNG. This will cause the sqlite3_vtab_nochange() ** function to return true inside the xColumn method of the virtual ** table implementation. The P5 column might also contain other ** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are ** unused by OP_VColumn. */ case OP_VColumn: { /* ncycle */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; Mem *pDest; sqlite3_context sContext; FuncDef nullFunc; VdbeCursor *pCur = p->apCsr[pOp->p1]; assert( pCur!=0 ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); if( pCur->nullRow ){ sqlite3VdbeMemSetNull(pDest); break; } assert( pCur->eCurType==CURTYPE_VTAB ); pVtab = pCur->uc.pVCur->pVtab; pModule = pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = pDest; sContext.enc = encoding; nullFunc.pUserData = 0; nullFunc.funcFlags = SQLITE_RESULT_SUBTYPE; sContext.pFunc = &nullFunc; assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 ); if( pOp->p5 & OPFLAG_NOCHNG ){ sqlite3VdbeMemSetNull(pDest); pDest->flags = MEM_Null|MEM_Zero; pDest->u.nZero = 0; }else{ MemSetTypeFlag(pDest, MEM_Null); } rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2); sqlite3VtabImportErrmsg(p, pVtab); if( sContext.isError>0 ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pDest)); rc = sContext.isError; } sqlite3VdbeChangeEncoding(pDest, encoding); REGISTER_TRACE(pOp->p3, pDest); UPDATE_MAX_BLOBSIZE(pDest); if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VNext P1 P2 * * * ** ** Advance virtual table P1 to the next row in its result set and ** jump to instruction P2. Or, if the virtual table has reached ** the end of its result set, then fall through to the next instruction. */ case OP_VNext: { /* jump, ncycle */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; int res; VdbeCursor *pCur; pCur = p->apCsr[pOp->p1]; assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); if( pCur->nullRow ){ break; } pVtab = pCur->uc.pVCur->pVtab; pModule = pVtab->pModule; assert( pModule->xNext ); /* Invoke the xNext() method of the module. There is no way for the ** underlying implementation to return an error if one occurs during ** xNext(). Instead, if an error occurs, true is returned (indicating that ** data is available) and the error code returned when xColumn or ** some other method is next invoked on the save virtual table cursor. */ rc = pModule->xNext(pCur->uc.pVCur); sqlite3VtabImportErrmsg(p, pVtab); if( rc ) goto abort_due_to_error; res = pModule->xEof(pCur->uc.pVCur); VdbeBranchTaken(!res,2); if( !res ){ /* If there is data, jump to P2 */ goto jump_to_p2_and_check_for_interrupt; } goto check_for_interrupt; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VRename P1 * * P4 * ** ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** This opcode invokes the corresponding xRename method. The value ** in register P1 is passed as the zName argument to the xRename method. */ case OP_VRename: { sqlite3_vtab *pVtab; Mem *pName; int isLegacy; isLegacy = (db->flags & SQLITE_LegacyAlter); db->flags |= SQLITE_LegacyAlter; pVtab = pOp->p4.pVtab->pVtab; pName = &aMem[pOp->p1]; assert( pVtab->pModule->xRename ); assert( memIsValid(pName) ); assert( p->readOnly==0 ); REGISTER_TRACE(pOp->p1, pName); assert( pName->flags & MEM_Str ); testcase( pName->enc==SQLITE_UTF8 ); testcase( pName->enc==SQLITE_UTF16BE ); testcase( pName->enc==SQLITE_UTF16LE ); rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8); if( rc ) goto abort_due_to_error; rc = pVtab->pModule->xRename(pVtab, pName->z); if( isLegacy==0 ) db->flags &= ~(u64)SQLITE_LegacyAlter; sqlite3VtabImportErrmsg(p, pVtab); p->expired = 0; if( rc ) goto abort_due_to_error; break; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VUpdate P1 P2 P3 P4 P5 ** Synopsis: data=r[P3@P2] ** ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** This opcode invokes the corresponding xUpdate method. P2 values ** are contiguous memory cells starting at P3 to pass to the xUpdate ** invocation. The value in register (P3+P2-1) corresponds to the ** p2th element of the argv array passed to xUpdate. ** ** The xUpdate method will do a DELETE or an INSERT or both. ** The argv[0] element (which corresponds to memory cell P3) ** is the rowid of a row to delete. If argv[0] is NULL then no ** deletion occurs. The argv[1] element is the rowid of the new ** row. This can be NULL to have the virtual table select the new ** rowid for itself. The subsequent elements in the array are ** the values of columns in the new row. ** ** If P2==1 then no insert is performed. argv[0] is the rowid of ** a row to delete. ** ** P1 is a boolean flag. If it is set to true and the xUpdate call ** is successful, then the value returned by sqlite3_last_insert_rowid() ** is set to the value of the rowid for the row just inserted. ** ** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to ** apply in the case of a constraint failure on an insert or update. */ case OP_VUpdate: { sqlite3_vtab *pVtab; const sqlite3_module *pModule; int nArg; int i; sqlite_int64 rowid = 0; Mem **apArg; Mem *pX; assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace ); assert( p->readOnly==0 ); if( db->mallocFailed ) goto no_mem; sqlite3VdbeIncrWriteCounter(p, 0); pVtab = pOp->p4.pVtab->pVtab; if( pVtab==0 || NEVER(pVtab->pModule==0) ){ rc = SQLITE_LOCKED; goto abort_due_to_error; } pModule = pVtab->pModule; nArg = pOp->p2; assert( pOp->p4type==P4_VTAB ); if( ALWAYS(pModule->xUpdate) ){ u8 vtabOnConflict = db->vtabOnConflict; apArg = p->apArg; pX = &aMem[pOp->p3]; for(i=0; ivtabOnConflict = pOp->p5; rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); db->vtabOnConflict = vtabOnConflict; sqlite3VtabImportErrmsg(p, pVtab); if( rc==SQLITE_OK && pOp->p1 ){ assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); db->lastRowid = rowid; } if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ if( pOp->p5==OE_Ignore ){ rc = SQLITE_OK; }else{ p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5); } }else{ p->nChange++; } if( rc ) goto abort_due_to_error; } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* Opcode: Pagecount P1 P2 * * * ** ** Write the current number of pages in database P1 to memory cell P2. */ case OP_Pagecount: { /* out2 */ pOut = out2Prerelease(p, pOp); pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt); break; } #endif #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* Opcode: MaxPgcnt P1 P2 P3 * * ** ** Try to set the maximum page count for database P1 to the value in P3. ** Do not let the maximum page count fall below the current page count and ** do not change the maximum page count value if P3==0. ** ** Store the maximum page count after the change in register P2. */ case OP_MaxPgcnt: { /* out2 */ unsigned int newMax; Btree *pBt; pOut = out2Prerelease(p, pOp); pBt = db->aDb[pOp->p1].pBt; newMax = 0; if( pOp->p3 ){ newMax = sqlite3BtreeLastPage(pBt); if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3; } pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax); break; } #endif /* Opcode: Function P1 P2 P3 P4 * ** Synopsis: r[P3]=func(r[P2@NP]) ** ** Invoke a user function (P4 is a pointer to an sqlite3_context object that ** contains a pointer to the function to be run) with arguments taken ** from register P2 and successors. The number of arguments is in ** the sqlite3_context object that P4 points to. ** The result of the function is stored ** in register P3. Register P3 must not be one of the function inputs. ** ** P1 is a 32-bit bitmask indicating whether or not each argument to the ** function was determined to be constant at compile time. If the first ** argument was constant then bit 0 of P1 is set. This is used to determine ** whether meta data associated with a user function argument using the ** sqlite3_set_auxdata() API may be safely retained until the next ** invocation of this opcode. ** ** See also: AggStep, AggFinal, PureFunc */ /* Opcode: PureFunc P1 P2 P3 P4 * ** Synopsis: r[P3]=func(r[P2@NP]) ** ** Invoke a user function (P4 is a pointer to an sqlite3_context object that ** contains a pointer to the function to be run) with arguments taken ** from register P2 and successors. The number of arguments is in ** the sqlite3_context object that P4 points to. ** The result of the function is stored ** in register P3. Register P3 must not be one of the function inputs. ** ** P1 is a 32-bit bitmask indicating whether or not each argument to the ** function was determined to be constant at compile time. If the first ** argument was constant then bit 0 of P1 is set. This is used to determine ** whether meta data associated with a user function argument using the ** sqlite3_set_auxdata() API may be safely retained until the next ** invocation of this opcode. ** ** This opcode works exactly like OP_Function. The only difference is in ** its name. This opcode is used in places where the function must be ** purely non-deterministic. Some built-in date/time functions can be ** either deterministic of non-deterministic, depending on their arguments. ** When those function are used in a non-deterministic way, they will check ** to see if they were called using OP_PureFunc instead of OP_Function, and ** if they were, they throw an error. ** ** See also: AggStep, AggFinal, Function */ case OP_PureFunc: /* group */ case OP_Function: { /* group */ int i; sqlite3_context *pCtx; assert( pOp->p4type==P4_FUNCCTX ); pCtx = pOp->p4.pCtx; /* If this function is inside of a trigger, the register array in aMem[] ** might change from one evaluation to the next. The next block of code ** checks to see if the register array has changed, and if so it ** reinitializes the relevant parts of the sqlite3_context object */ pOut = &aMem[pOp->p3]; if( pCtx->pOut != pOut ){ pCtx->pVdbe = p; pCtx->pOut = pOut; pCtx->enc = encoding; for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; } assert( pCtx->pVdbe==p ); memAboutToChange(p, pOut); #ifdef SQLITE_DEBUG for(i=0; iargc; i++){ assert( memIsValid(pCtx->argv[i]) ); REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); } #endif MemSetTypeFlag(pOut, MEM_Null); assert( pCtx->isError==0 ); (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */ /* If the function returned an error, throw an exception */ if( pCtx->isError ){ if( pCtx->isError>0 ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut)); rc = pCtx->isError; } sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1); pCtx->isError = 0; if( rc ) goto abort_due_to_error; } assert( (pOut->flags&MEM_Str)==0 || pOut->enc==encoding || db->mallocFailed ); assert( !sqlite3VdbeMemTooBig(pOut) ); REGISTER_TRACE(pOp->p3, pOut); UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: ClrSubtype P1 * * * * ** Synopsis: r[P1].subtype = 0 ** ** Clear the subtype from register P1. */ case OP_ClrSubtype: { /* in1 */ pIn1 = &aMem[pOp->p1]; pIn1->flags &= ~MEM_Subtype; break; } /* Opcode: GetSubtype P1 P2 * * * ** Synopsis: r[P2] = r[P1].subtype ** ** Extract the subtype value from register P1 and write that subtype ** into register P2. If P1 has no subtype, then P1 gets a NULL. */ case OP_GetSubtype: { /* in1 out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; if( pIn1->flags & MEM_Subtype ){ sqlite3VdbeMemSetInt64(pOut, pIn1->eSubtype); }else{ sqlite3VdbeMemSetNull(pOut); } break; } /* Opcode: SetSubtype P1 P2 * * * ** Synopsis: r[P2].subtype = r[P1] ** ** Set the subtype value of register P2 to the integer from register P1. ** If P1 is NULL, clear the subtype from p2. */ case OP_SetSubtype: { /* in1 out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; if( pIn1->flags & MEM_Null ){ pOut->flags &= ~MEM_Subtype; }else{ assert( pIn1->flags & MEM_Int ); pOut->flags |= MEM_Subtype; pOut->eSubtype = (u8)(pIn1->u.i & 0xff); } break; } /* Opcode: FilterAdd P1 * P3 P4 * ** Synopsis: filter(P1) += key(P3@P4) ** ** Compute a hash on the P4 registers starting with r[P3] and ** add that hash to the bloom filter contained in r[P1]. */ case OP_FilterAdd: { u64 h; assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); pIn1 = &aMem[pOp->p1]; assert( pIn1->flags & MEM_Blob ); assert( pIn1->n>0 ); h = filterHash(aMem, pOp); #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ int ii; for(ii=pOp->p3; iip3+pOp->p4.i; ii++){ registerTrace(ii, &aMem[ii]); } printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n)); } #endif h %= (pIn1->n*8); pIn1->z[h/8] |= 1<<(h&7); break; } /* Opcode: Filter P1 P2 P3 P4 * ** Synopsis: if key(P3@P4) not in filter(P1) goto P2 ** ** Compute a hash on the key contained in the P4 registers starting ** with r[P3]. Check to see if that hash is found in the ** bloom filter hosted by register P1. If it is not present then ** maybe jump to P2. Otherwise fall through. ** ** False negatives are harmless. It is always safe to fall through, ** even if the value is in the bloom filter. A false negative causes ** more CPU cycles to be used, but it should still yield the correct ** answer. However, an incorrect answer may well arise from a ** false positive - if the jump is taken when it should fall through. */ case OP_Filter: { /* jump */ u64 h; assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); pIn1 = &aMem[pOp->p1]; assert( (pIn1->flags & MEM_Blob)!=0 ); assert( pIn1->n >= 1 ); h = filterHash(aMem, pOp); #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ int ii; for(ii=pOp->p3; iip3+pOp->p4.i; ii++){ registerTrace(ii, &aMem[ii]); } printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n)); } #endif h %= (pIn1->n*8); if( (pIn1->z[h/8] & (1<<(h&7)))==0 ){ VdbeBranchTaken(1, 2); p->aCounter[SQLITE_STMTSTATUS_FILTER_HIT]++; goto jump_to_p2; }else{ p->aCounter[SQLITE_STMTSTATUS_FILTER_MISS]++; VdbeBranchTaken(0, 2); } break; } /* Opcode: Trace P1 P2 * P4 * ** ** Write P4 on the statement trace output if statement tracing is ** enabled. ** ** Operand P1 must be 0x7fffffff and P2 must positive. */ /* Opcode: Init P1 P2 P3 P4 * ** Synopsis: Start at P2 ** ** Programs contain a single instance of this opcode as the very first ** opcode. ** ** If tracing is enabled (by the sqlite3_trace()) interface, then ** the UTF-8 string contained in P4 is emitted on the trace callback. ** Or if P4 is blank, use the string returned by sqlite3_sql(). ** ** If P2 is not zero, jump to instruction P2. ** ** Increment the value of P1 so that OP_Once opcodes will jump the ** first time they are evaluated for this run. ** ** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT ** error is encountered. */ case OP_Trace: case OP_Init: { /* jump */ int i; #ifndef SQLITE_OMIT_TRACE char *zTrace; #endif /* If the P4 argument is not NULL, then it must be an SQL comment string. ** The "--" string is broken up to prevent false-positives with srcck1.c. ** ** This assert() provides evidence for: ** EVIDENCE-OF: R-50676-09860 The callback can compute the same text that ** would have been returned by the legacy sqlite3_trace() interface by ** using the X argument when X begins with "--" and invoking ** sqlite3_expanded_sql(P) otherwise. */ assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 ); /* OP_Init is always instruction 0 */ assert( pOp==p->aOp || pOp->opcode==OP_Trace ); #ifndef SQLITE_OMIT_TRACE if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 && p->minWriteFileFormat!=254 /* tag-20220401a */ && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ #ifndef SQLITE_OMIT_DEPRECATED if( db->mTrace & SQLITE_TRACE_LEGACY ){ char *z = sqlite3VdbeExpandSql(p, zTrace); db->trace.xLegacy(db->pTraceArg, z); sqlite3_free(z); }else #endif if( db->nVdbeExec>1 ){ char *z = sqlite3MPrintf(db, "-- %s", zTrace); (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, z); sqlite3DbFree(db, z); }else{ (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace); } } #ifdef SQLITE_USE_FCNTL_TRACE zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); if( zTrace ){ int j; for(j=0; jnDb; j++){ if( DbMaskTest(p->btreeMask, j)==0 ) continue; sqlite3_file_control(db, db->aDb[j].zDbSName, SQLITE_FCNTL_TRACE, zTrace); } } #endif /* SQLITE_USE_FCNTL_TRACE */ #ifdef SQLITE_DEBUG if( (db->flags & SQLITE_SqlTrace)!=0 && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ sqlite3DebugPrintf("SQL-trace: %s\n", zTrace); } #endif /* SQLITE_DEBUG */ #endif /* SQLITE_OMIT_TRACE */ assert( pOp->p2>0 ); if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){ if( pOp->opcode==OP_Trace ) break; for(i=1; inOp; i++){ if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0; } pOp->p1 = 0; } pOp->p1++; p->aCounter[SQLITE_STMTSTATUS_RUN]++; goto jump_to_p2; } #ifdef SQLITE_ENABLE_CURSOR_HINTS /* Opcode: CursorHint P1 * * P4 * ** ** Provide a hint to cursor P1 that it only needs to return rows that ** satisfy the Expr in P4. TK_REGISTER terms in the P4 expression refer ** to values currently held in registers. TK_COLUMN terms in the P4 ** expression refer to columns in the b-tree to which cursor P1 is pointing. */ case OP_CursorHint: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p4type==P4_EXPR ); pC = p->apCsr[pOp->p1]; if( pC ){ assert( pC->eCurType==CURTYPE_BTREE ); sqlite3BtreeCursorHint(pC->uc.pCursor, BTREE_HINT_RANGE, pOp->p4.pExpr, aMem); } break; } #endif /* SQLITE_ENABLE_CURSOR_HINTS */ #ifdef SQLITE_DEBUG /* Opcode: Abortable * * * * * ** ** Verify that an Abort can happen. Assert if an Abort at this point ** might cause database corruption. This opcode only appears in debugging ** builds. ** ** An Abort is safe if either there have been no writes, or if there is ** an active statement journal. */ case OP_Abortable: { sqlite3VdbeAssertAbortable(p); break; } #endif #ifdef SQLITE_DEBUG /* Opcode: ReleaseReg P1 P2 P3 * P5 ** Synopsis: release r[P1@P2] mask P3 ** ** Release registers from service. Any content that was in the ** the registers is unreliable after this opcode completes. ** ** The registers released will be the P2 registers starting at P1, ** except if bit ii of P3 set, then do not release register P1+ii. ** In other words, P3 is a mask of registers to preserve. ** ** Releasing a register clears the Mem.pScopyFrom pointer. That means ** that if the content of the released register was set using OP_SCopy, ** a change to the value of the source register for the OP_SCopy will no longer ** generate an assertion fault in sqlite3VdbeMemAboutToChange(). ** ** If P5 is set, then all released registers have their type set ** to MEM_Undefined so that any subsequent attempt to read the released ** register (before it is reinitialized) will generate an assertion fault. ** ** P5 ought to be set on every call to this opcode. ** However, there are places in the code generator will release registers ** before their are used, under the (valid) assumption that the registers ** will not be reallocated for some other purpose before they are used and ** hence are safe to release. ** ** This opcode is only available in testing and debugging builds. It is ** not generated for release builds. The purpose of this opcode is to help ** validate the generated bytecode. This opcode does not actually contribute ** to computing an answer. */ case OP_ReleaseReg: { Mem *pMem; int i; u32 constMask; assert( pOp->p1>0 ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); pMem = &aMem[pOp->p1]; constMask = pOp->p3; for(i=0; ip2; i++, pMem++){ if( i>=32 || (constMask & MASKBIT32(i))==0 ){ pMem->pScopyFrom = 0; if( i<32 && pOp->p5 ) MemSetTypeFlag(pMem, MEM_Undefined); } } break; } #endif /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump ** destination. */ /* ** The magic Explain opcode are only inserted when explain==2 (which ** is to say when the EXPLAIN QUERY PLAN syntax is used.) ** This opcode records information from the optimizer. It is the ** the same as a no-op. This opcodesnever appears in a real VM program. */ default: { /* This is really OP_Noop, OP_Explain */ assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain ); break; } /***************************************************************************** ** The cases of the switch statement above this line should all be indented ** by 6 spaces. But the left-most 6 spaces have been removed to improve the ** readability. From this point on down, the normal indentation rules are ** restored. *****************************************************************************/ } #if defined(VDBE_PROFILE) *pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); pnCycle = 0; #elif defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( pnCycle ){ *pnCycle += sqlite3Hwtime(); pnCycle = 0; } #endif /* The following code adds nothing to the actual functionality ** of the program. It is only here for testing and debugging. ** On the other hand, it does burn CPU cycles every time through ** the evaluator loop. So we can leave it out when NDEBUG is defined. */ #ifndef NDEBUG assert( pOp>=&aOp[-1] && pOp<&aOp[p->nOp-1] ); #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ u8 opProperty = sqlite3OpcodeProperty[pOrigOp->opcode]; if( rc!=0 ) printf("rc=%d\n",rc); if( opProperty & (OPFLG_OUT2) ){ registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]); } if( opProperty & OPFLG_OUT3 ){ registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]); } if( opProperty==0xff ){ /* Never happens. This code exists to avoid a harmless linkage ** warning about sqlite3VdbeRegisterDump() being defined but not ** used. */ sqlite3VdbeRegisterDump(p); } } #endif /* SQLITE_DEBUG */ #endif /* NDEBUG */ } /* The end of the for(;;) loop the loops through opcodes */ /* If we reach this point, it means that execution is finished with ** an error of some kind. */ abort_due_to_error: if( db->mallocFailed ){ rc = SQLITE_NOMEM_BKPT; }else if( rc==SQLITE_IOERR_CORRUPTFS ){ rc = SQLITE_CORRUPT_BKPT; } assert( rc ); #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ const char *zTrace = p->zSql; if( zTrace==0 ){ if( aOp[0].opcode==OP_Trace ){ zTrace = aOp[0].p4.z; } if( zTrace==0 ) zTrace = "???"; } printf("ABORT-due-to-error (rc=%d): %s\n", rc, zTrace); } #endif if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){ sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); } p->rc = rc; sqlite3SystemError(db, rc); testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(rc, "statement aborts at %d: [%s] %s", (int)(pOp - aOp), p->zSql, p->zErrMsg); if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p); if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){ db->flags |= SQLITE_CorruptRdOnly; } rc = SQLITE_ERROR; if( resetSchemaOnFault>0 ){ sqlite3ResetOneSchema(db, resetSchemaOnFault-1); } /* This is the only way out of this procedure. We have to ** release the mutexes on btrees that were acquired at the ** top. */ vdbe_return: #if defined(VDBE_PROFILE) if( pnCycle ){ *pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); pnCycle = 0; } #elif defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( pnCycle ){ *pnCycle += sqlite3Hwtime(); pnCycle = 0; } #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ nProgressLimit += db->nProgressOps; if( db->xProgress(db->pProgressArg) ){ nProgressLimit = LARGEST_UINT64; rc = SQLITE_INTERRUPT; goto abort_due_to_error; } } #endif p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; if( DbMaskNonZero(p->lockMask) ){ sqlite3VdbeLeave(p); } assert( rc!=SQLITE_OK || nExtraDelete==0 || sqlite3_strlike("DELETE%",p->zSql,0)!=0 ); return rc; /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH ** is encountered. */ too_big: sqlite3VdbeError(p, "string or blob too big"); rc = SQLITE_TOOBIG; goto abort_due_to_error; /* Jump to here if a malloc() fails. */ no_mem: sqlite3OomFault(db); sqlite3VdbeError(p, "out of memory"); rc = SQLITE_NOMEM_BKPT; goto abort_due_to_error; /* Jump to here if the sqlite3_interrupt() API sets the interrupt ** flag. */ abort_due_to_interrupt: assert( AtomicLoad(&db->u1.isInterrupted) ); rc = SQLITE_INTERRUPT; goto abort_due_to_error; } /************** End of vdbe.c ************************************************/ /************** Begin file vdbeblob.c ****************************************/ /* ** 2007 May 1 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code used to implement incremental BLOB I/O. */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ #ifndef SQLITE_OMIT_INCRBLOB /* ** Valid sqlite3_blob* handles point to Incrblob structures. */ typedef struct Incrblob Incrblob; struct Incrblob { int nByte; /* Size of open blob, in bytes */ int iOffset; /* Byte offset of blob in cursor data */ u16 iCol; /* Table column this handle is open on */ BtCursor *pCsr; /* Cursor pointing at blob row */ sqlite3_stmt *pStmt; /* Statement holding cursor open */ sqlite3 *db; /* The associated database */ char *zDb; /* Database name */ Table *pTab; /* Table object */ }; /* ** This function is used by both blob_open() and blob_reopen(). It seeks ** the b-tree cursor associated with blob handle p to point to row iRow. ** If successful, SQLITE_OK is returned and subsequent calls to ** sqlite3_blob_read() or sqlite3_blob_write() access the specified row. ** ** If an error occurs, or if the specified row does not exist or does not ** contain a value of type TEXT or BLOB in the column nominated when the ** blob handle was opened, then an error code is returned and *pzErr may ** be set to point to a buffer containing an error message. It is the ** responsibility of the caller to free the error message buffer using ** sqlite3DbFree(). ** ** If an error does occur, then the b-tree cursor is closed. All subsequent ** calls to sqlite3_blob_read(), blob_write() or blob_reopen() will ** immediately return SQLITE_ABORT. */ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ int rc; /* Error code */ char *zErr = 0; /* Error message */ Vdbe *v = (Vdbe *)p->pStmt; /* Set the value of register r[1] in the SQL statement to integer iRow. ** This is done directly as a performance optimization */ sqlite3VdbeMemSetInt64(&v->aMem[1], iRow); /* If the statement has been run before (and is paused at the OP_ResultRow) ** then back it up to the point where it does the OP_NotExists. This could ** have been down with an extra OP_Goto, but simply setting the program ** counter is faster. */ if( v->pc>4 ){ v->pc = 4; assert( v->aOp[v->pc].opcode==OP_NotExists ); rc = sqlite3VdbeExec(v); }else{ rc = sqlite3_step(p->pStmt); } if( rc==SQLITE_ROW ){ VdbeCursor *pC = v->apCsr[0]; u32 type; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0; testcase( pC->nHdrParsed==p->iCol ); testcase( pC->nHdrParsed==p->iCol+1 ); if( type<12 ){ zErr = sqlite3MPrintf(p->db, "cannot open value of type %s", type==0?"null": type==7?"real": "integer" ); rc = SQLITE_ERROR; sqlite3_finalize(p->pStmt); p->pStmt = 0; }else{ p->iOffset = pC->aType[p->iCol + pC->nField]; p->nByte = sqlite3VdbeSerialTypeLen(type); p->pCsr = pC->uc.pCursor; sqlite3BtreeIncrblobCursor(p->pCsr); } } if( rc==SQLITE_ROW ){ rc = SQLITE_OK; }else if( p->pStmt ){ rc = sqlite3_finalize(p->pStmt); p->pStmt = 0; if( rc==SQLITE_OK ){ zErr = sqlite3MPrintf(p->db, "no such rowid: %lld", iRow); rc = SQLITE_ERROR; }else{ zErr = sqlite3MPrintf(p->db, "%s", sqlite3_errmsg(p->db)); } } assert( rc!=SQLITE_OK || zErr==0 ); assert( rc!=SQLITE_ROW && rc!=SQLITE_DONE ); *pzErr = zErr; return rc; } /* ** Open a blob handle. */ SQLITE_API int sqlite3_blob_open( sqlite3* db, /* The database connection */ const char *zDb, /* The attached database containing the blob */ const char *zTable, /* The table containing the blob */ const char *zColumn, /* The column containing the blob */ sqlite_int64 iRow, /* The row containing the glob */ int wrFlag, /* True -> read/write access, false -> read-only */ sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */ ){ int nAttempt = 0; int iCol; /* Index of zColumn in row-record */ int rc = SQLITE_OK; char *zErr = 0; Table *pTab; Incrblob *pBlob = 0; Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR if( ppBlob==0 ){ return SQLITE_MISUSE_BKPT; } #endif *ppBlob = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zTable==0 || zColumn==0 ){ return SQLITE_MISUSE_BKPT; } #endif wrFlag = !!wrFlag; /* wrFlag = (wrFlag ? 1 : 0); */ sqlite3_mutex_enter(db->mutex); pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob)); while(1){ sqlite3ParseObjectInit(&sParse,db); if( !pBlob ) goto blob_open_out; sqlite3DbFree(db, zErr); zErr = 0; sqlite3BtreeEnterAll(db); pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb); if( pTab && IsVirtual(pTab) ){ pTab = 0; sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable); } if( pTab && !HasRowid(pTab) ){ pTab = 0; sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable); } #ifndef SQLITE_OMIT_VIEW if( pTab && IsView(pTab) ){ pTab = 0; sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable); } #endif if( !pTab ){ if( sParse.zErrMsg ){ sqlite3DbFree(db, zErr); zErr = sParse.zErrMsg; sParse.zErrMsg = 0; } rc = SQLITE_ERROR; sqlite3BtreeLeaveAll(db); goto blob_open_out; } pBlob->pTab = pTab; pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; /* Now search pTab for the exact column. */ for(iCol=0; iColnCol; iCol++) { if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){ break; } } if( iCol==pTab->nCol ){ sqlite3DbFree(db, zErr); zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn); rc = SQLITE_ERROR; sqlite3BtreeLeaveAll(db); goto blob_open_out; } /* If the value is being opened for writing, check that the ** column is not indexed, and that it is not part of a foreign key. */ if( wrFlag ){ const char *zFault = 0; Index *pIdx; #ifndef SQLITE_OMIT_FOREIGN_KEY if( db->flags&SQLITE_ForeignKeys ){ /* Check that the column is not part of an FK child key definition. It ** is not necessary to check if it is part of a parent key, as parent ** key columns must be indexed. The check below will pick up this ** case. */ FKey *pFKey; assert( IsOrdinaryTable(pTab) ); for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ int j; for(j=0; jnCol; j++){ if( pFKey->aCol[j].iFrom==iCol ){ zFault = "foreign key"; } } } } #endif for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int j; for(j=0; jnKeyCol; j++){ /* FIXME: Be smarter about indexes that use expressions */ if( pIdx->aiColumn[j]==iCol || pIdx->aiColumn[j]==XN_EXPR ){ zFault = "indexed"; } } } if( zFault ){ sqlite3DbFree(db, zErr); zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault); rc = SQLITE_ERROR; sqlite3BtreeLeaveAll(db); goto blob_open_out; } } pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse); assert( pBlob->pStmt || db->mallocFailed ); if( pBlob->pStmt ){ /* This VDBE program seeks a btree cursor to the identified ** db/table/row entry. The reason for using a vdbe program instead ** of writing code to use the b-tree layer directly is that the ** vdbe program will take advantage of the various transaction, ** locking and error handling infrastructure built into the vdbe. ** ** After seeking the cursor, the vdbe executes an OP_ResultRow. ** Code external to the Vdbe then "borrows" the b-tree cursor and ** uses it to implement the blob_read(), blob_write() and ** blob_bytes() functions. ** ** The sqlite3_blob_close() function finalizes the vdbe program, ** which closes the b-tree cursor and (possibly) commits the ** transaction. */ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList openBlob[] = { {OP_TableLock, 0, 0, 0}, /* 0: Acquire a read or write lock */ {OP_OpenRead, 0, 0, 0}, /* 1: Open a cursor */ /* blobSeekToRow() will initialize r[1] to the desired rowid */ {OP_NotExists, 0, 5, 1}, /* 2: Seek the cursor to rowid=r[1] */ {OP_Column, 0, 0, 1}, /* 3 */ {OP_ResultRow, 1, 0, 0}, /* 4 */ {OP_Halt, 0, 0, 0}, /* 5 */ }; Vdbe *v = (Vdbe *)pBlob->pStmt; int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); VdbeOp *aOp; sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, pTab->pSchema->schema_cookie, pTab->pSchema->iGeneration); sqlite3VdbeChangeP5(v, 1); assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed ); aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn); /* Make sure a mutex is held on the table to be accessed */ sqlite3VdbeUsesBtree(v, iDb); if( db->mallocFailed==0 ){ assert( aOp!=0 ); /* Configure the OP_TableLock instruction */ #ifdef SQLITE_OMIT_SHARED_CACHE aOp[0].opcode = OP_Noop; #else aOp[0].p1 = iDb; aOp[0].p2 = pTab->tnum; aOp[0].p3 = wrFlag; sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT); } if( db->mallocFailed==0 ){ #endif /* Remove either the OP_OpenWrite or OpenRead. Set the P2 ** parameter of the other to pTab->tnum. */ if( wrFlag ) aOp[1].opcode = OP_OpenWrite; aOp[1].p2 = pTab->tnum; aOp[1].p3 = iDb; /* Configure the number of columns. Configure the cursor to ** think that the table has one more column than it really ** does. An OP_Column to retrieve this imaginary column will ** always return an SQL NULL. This is useful because it means ** we can invoke OP_Column to fill in the vdbe cursors type ** and offset cache without causing any IO. */ aOp[1].p4type = P4_INT32; aOp[1].p4.i = pTab->nCol+1; aOp[3].p2 = pTab->nCol; sParse.nVar = 0; sParse.nMem = 1; sParse.nTab = 1; sqlite3VdbeMakeReady(v, &sParse); } } pBlob->iCol = iCol; pBlob->db = db; sqlite3BtreeLeaveAll(db); if( db->mallocFailed ){ goto blob_open_out; } rc = blobSeekToRow(pBlob, iRow, &zErr); if( (++nAttempt)>=SQLITE_MAX_SCHEMA_RETRY || rc!=SQLITE_SCHEMA ) break; sqlite3ParseObjectReset(&sParse); } blob_open_out: if( rc==SQLITE_OK && db->mallocFailed==0 ){ *ppBlob = (sqlite3_blob *)pBlob; }else{ if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); sqlite3DbFree(db, pBlob); } sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr); sqlite3DbFree(db, zErr); sqlite3ParseObjectReset(&sParse); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Close a blob handle that was previously created using ** sqlite3_blob_open(). */ SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){ Incrblob *p = (Incrblob *)pBlob; int rc; sqlite3 *db; if( p ){ sqlite3_stmt *pStmt = p->pStmt; db = p->db; sqlite3_mutex_enter(db->mutex); sqlite3DbFree(db, p); sqlite3_mutex_leave(db->mutex); rc = sqlite3_finalize(pStmt); }else{ rc = SQLITE_OK; } return rc; } /* ** Perform a read or write operation on a blob */ static int blobReadWrite( sqlite3_blob *pBlob, void *z, int n, int iOffset, int (*xCall)(BtCursor*, u32, u32, void*) ){ int rc; Incrblob *p = (Incrblob *)pBlob; Vdbe *v; sqlite3 *db; if( p==0 ) return SQLITE_MISUSE_BKPT; db = p->db; sqlite3_mutex_enter(db->mutex); v = (Vdbe*)p->pStmt; if( n<0 || iOffset<0 || ((sqlite3_int64)iOffset+n)>p->nByte ){ /* Request is out of range. Return a transient error. */ rc = SQLITE_ERROR; }else if( v==0 ){ /* If there is no statement handle, then the blob-handle has ** already been invalidated. Return SQLITE_ABORT in this case. */ rc = SQLITE_ABORT; }else{ /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is ** returned, clean-up the statement handle. */ assert( db == v->db ); sqlite3BtreeEnterCursor(p->pCsr); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK if( xCall==sqlite3BtreePutData && db->xPreUpdateCallback ){ /* If a pre-update hook is registered and this is a write cursor, ** invoke it here. ** ** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this ** operation should really be an SQLITE_UPDATE. This is probably ** incorrect, but is convenient because at this point the new.* values ** are not easily obtainable. And for the sessions module, an ** SQLITE_UPDATE where the PK columns do not change is handled in the ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually ** slightly more efficient). Since you cannot write to a PK column ** using the incremental-blob API, this works. For the sessions module ** anyhow. */ sqlite3_int64 iKey; iKey = sqlite3BtreeIntegerKey(p->pCsr); assert( v->apCsr[0]!=0 ); assert( v->apCsr[0]->eCurType==CURTYPE_BTREE ); sqlite3VdbePreUpdateHook( v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1, p->iCol ); } #endif rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); sqlite3BtreeLeaveCursor(p->pCsr); if( rc==SQLITE_ABORT ){ sqlite3VdbeFinalize(v); p->pStmt = 0; }else{ v->rc = rc; } } sqlite3Error(db, rc); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Read data from a blob handle. */ SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){ return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreePayloadChecked); } /* ** Write data to a blob handle. */ SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){ return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData); } /* ** Query a blob handle for the size of the data. ** ** The Incrblob.nByte field is fixed for the lifetime of the Incrblob ** so no mutex is required for access. */ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){ Incrblob *p = (Incrblob *)pBlob; return (p && p->pStmt) ? p->nByte : 0; } /* ** Move an existing blob handle to point to a different row of the same ** database table. ** ** If an error occurs, or if the specified row does not exist or does not ** contain a blob or text value, then an error code is returned and the ** database handle error code and message set. If this happens, then all ** subsequent calls to sqlite3_blob_xxx() functions (except blob_close()) ** immediately return SQLITE_ABORT. */ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ int rc; Incrblob *p = (Incrblob *)pBlob; sqlite3 *db; if( p==0 ) return SQLITE_MISUSE_BKPT; db = p->db; sqlite3_mutex_enter(db->mutex); if( p->pStmt==0 ){ /* If there is no statement handle, then the blob-handle has ** already been invalidated. Return SQLITE_ABORT in this case. */ rc = SQLITE_ABORT; }else{ char *zErr; ((Vdbe*)p->pStmt)->rc = SQLITE_OK; rc = blobSeekToRow(p, iRow, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr); sqlite3DbFree(db, zErr); } assert( rc!=SQLITE_SCHEMA ); } rc = sqlite3ApiExit(db, rc); assert( rc==SQLITE_OK || p->pStmt==0 ); sqlite3_mutex_leave(db->mutex); return rc; } #endif /* #ifndef SQLITE_OMIT_INCRBLOB */ /************** End of vdbeblob.c ********************************************/ /************** Begin file vdbesort.c ****************************************/ /* ** 2011-07-09 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code for the VdbeSorter object, used in concert with ** a VdbeCursor to sort large numbers of keys for CREATE INDEX statements ** or by SELECT statements with ORDER BY clauses that cannot be satisfied ** using indexes and without LIMIT clauses. ** ** The VdbeSorter object implements a multi-threaded external merge sort ** algorithm that is efficient even if the number of elements being sorted ** exceeds the available memory. ** ** Here is the (internal, non-API) interface between this module and the ** rest of the SQLite system: ** ** sqlite3VdbeSorterInit() Create a new VdbeSorter object. ** ** sqlite3VdbeSorterWrite() Add a single new row to the VdbeSorter ** object. The row is a binary blob in the ** OP_MakeRecord format that contains both ** the ORDER BY key columns and result columns ** in the case of a SELECT w/ ORDER BY, or ** the complete record for an index entry ** in the case of a CREATE INDEX. ** ** sqlite3VdbeSorterRewind() Sort all content previously added. ** Position the read cursor on the ** first sorted element. ** ** sqlite3VdbeSorterNext() Advance the read cursor to the next sorted ** element. ** ** sqlite3VdbeSorterRowkey() Return the complete binary blob for the ** row currently under the read cursor. ** ** sqlite3VdbeSorterCompare() Compare the binary blob for the row ** currently under the read cursor against ** another binary blob X and report if ** X is strictly less than the read cursor. ** Used to enforce uniqueness in a ** CREATE UNIQUE INDEX statement. ** ** sqlite3VdbeSorterClose() Close the VdbeSorter object and reclaim ** all resources. ** ** sqlite3VdbeSorterReset() Refurbish the VdbeSorter for reuse. This ** is like Close() followed by Init() only ** much faster. ** ** The interfaces above must be called in a particular order. Write() can ** only occur in between Init()/Reset() and Rewind(). Next(), Rowkey(), and ** Compare() can only occur in between Rewind() and Close()/Reset(). i.e. ** ** Init() ** for each record: Write() ** Rewind() ** Rowkey()/Compare() ** Next() ** Close() ** ** Algorithm: ** ** Records passed to the sorter via calls to Write() are initially held ** unsorted in main memory. Assuming the amount of memory used never exceeds ** a threshold, when Rewind() is called the set of records is sorted using ** an in-memory merge sort. In this case, no temporary files are required ** and subsequent calls to Rowkey(), Next() and Compare() read records ** directly from main memory. ** ** If the amount of space used to store records in main memory exceeds the ** threshold, then the set of records currently in memory are sorted and ** written to a temporary file in "Packed Memory Array" (PMA) format. ** A PMA created at this point is known as a "level-0 PMA". Higher levels ** of PMAs may be created by merging existing PMAs together - for example ** merging two or more level-0 PMAs together creates a level-1 PMA. ** ** The threshold for the amount of main memory to use before flushing ** records to a PMA is roughly the same as the limit configured for the ** page-cache of the main database. Specifically, the threshold is set to ** the value returned by "PRAGMA main.page_size" multiplied by ** that returned by "PRAGMA main.cache_size", in bytes. ** ** If the sorter is running in single-threaded mode, then all PMAs generated ** are appended to a single temporary file. Or, if the sorter is running in ** multi-threaded mode then up to (N+1) temporary files may be opened, where ** N is the configured number of worker threads. In this case, instead of ** sorting the records and writing the PMA to a temporary file itself, the ** calling thread usually launches a worker thread to do so. Except, if ** there are already N worker threads running, the main thread does the work ** itself. ** ** The sorter is running in multi-threaded mode if (a) the library was built ** with pre-processor symbol SQLITE_MAX_WORKER_THREADS set to a value greater ** than zero, and (b) worker threads have been enabled at runtime by calling ** "PRAGMA threads=N" with some value of N greater than 0. ** ** When Rewind() is called, any data remaining in memory is flushed to a ** final PMA. So at this point the data is stored in some number of sorted ** PMAs within temporary files on disk. ** ** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the ** sorter is running in single-threaded mode, then these PMAs are merged ** incrementally as keys are retrieved from the sorter by the VDBE. The ** MergeEngine object, described in further detail below, performs this ** merge. ** ** Or, if running in multi-threaded mode, then a background thread is ** launched to merge the existing PMAs. Once the background thread has ** merged T bytes of data into a single sorted PMA, the main thread ** begins reading keys from that PMA while the background thread proceeds ** with merging the next T bytes of data. And so on. ** ** Parameter T is set to half the value of the memory threshold used ** by Write() above to determine when to create a new PMA. ** ** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when ** Rewind() is called, then a hierarchy of incremental-merges is used. ** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on ** disk are merged together. Then T bytes of data from the second set, and ** so on, such that no operation ever merges more than SORTER_MAX_MERGE_COUNT ** PMAs at a time. This done is to improve locality. ** ** If running in multi-threaded mode and there are more than ** SORTER_MAX_MERGE_COUNT PMAs on disk when Rewind() is called, then more ** than one background thread may be created. Specifically, there may be ** one background thread for each temporary file on disk, and one background ** thread to merge the output of each of the others to a single PMA for ** the main thread to read from. */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ /* ** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various ** messages to stderr that may be helpful in understanding the performance ** characteristics of the sorter in multi-threaded mode. */ #if 0 # define SQLITE_DEBUG_SORTER_THREADS 1 #endif /* ** Hard-coded maximum amount of data to accumulate in memory before flushing ** to a level 0 PMA. The purpose of this limit is to prevent various integer ** overflows. 512MiB. */ #define SQLITE_MAX_PMASZ (1<<29) /* ** Private objects used by the sorter */ typedef struct MergeEngine MergeEngine; /* Merge PMAs together */ typedef struct PmaReader PmaReader; /* Incrementally read one PMA */ typedef struct PmaWriter PmaWriter; /* Incrementally write one PMA */ typedef struct SorterRecord SorterRecord; /* A record being sorted */ typedef struct SortSubtask SortSubtask; /* A sub-task in the sort process */ typedef struct SorterFile SorterFile; /* Temporary file object wrapper */ typedef struct SorterList SorterList; /* In-memory list of records */ typedef struct IncrMerger IncrMerger; /* Read & merge multiple PMAs */ /* ** A container for a temp file handle and the current amount of data ** stored in the file. */ struct SorterFile { sqlite3_file *pFd; /* File handle */ i64 iEof; /* Bytes of data stored in pFd */ }; /* ** An in-memory list of objects to be sorted. ** ** If aMemory==0 then each object is allocated separately and the objects ** are connected using SorterRecord.u.pNext. If aMemory!=0 then all objects ** are stored in the aMemory[] bulk memory, one right after the other, and ** are connected using SorterRecord.u.iNext. */ struct SorterList { SorterRecord *pList; /* Linked list of records */ u8 *aMemory; /* If non-NULL, bulk memory to hold pList */ i64 szPMA; /* Size of pList as PMA in bytes */ }; /* ** The MergeEngine object is used to combine two or more smaller PMAs into ** one big PMA using a merge operation. Separate PMAs all need to be ** combined into one big PMA in order to be able to step through the sorted ** records in order. ** ** The aReadr[] array contains a PmaReader object for each of the PMAs being ** merged. An aReadr[] object either points to a valid key or else is at EOF. ** ("EOF" means "End Of File". When aReadr[] is at EOF there is no more data.) ** For the purposes of the paragraphs below, we assume that the array is ** actually N elements in size, where N is the smallest power of 2 greater ** to or equal to the number of PMAs being merged. The extra aReadr[] elements ** are treated as if they are empty (always at EOF). ** ** The aTree[] array is also N elements in size. The value of N is stored in ** the MergeEngine.nTree variable. ** ** The final (N/2) elements of aTree[] contain the results of comparing ** pairs of PMA keys together. Element i contains the result of ** comparing aReadr[2*i-N] and aReadr[2*i-N+1]. Whichever key is smaller, the ** aTree element is set to the index of it. ** ** For the purposes of this comparison, EOF is considered greater than any ** other key value. If the keys are equal (only possible with two EOF ** values), it doesn't matter which index is stored. ** ** The (N/4) elements of aTree[] that precede the final (N/2) described ** above contains the index of the smallest of each block of 4 PmaReaders ** And so on. So that aTree[1] contains the index of the PmaReader that ** currently points to the smallest key value. aTree[0] is unused. ** ** Example: ** ** aReadr[0] -> Banana ** aReadr[1] -> Feijoa ** aReadr[2] -> Elderberry ** aReadr[3] -> Currant ** aReadr[4] -> Grapefruit ** aReadr[5] -> Apple ** aReadr[6] -> Durian ** aReadr[7] -> EOF ** ** aTree[] = { X, 5 0, 5 0, 3, 5, 6 } ** ** The current element is "Apple" (the value of the key indicated by ** PmaReader 5). When the Next() operation is invoked, PmaReader 5 will ** be advanced to the next key in its segment. Say the next key is ** "Eggplant": ** ** aReadr[5] -> Eggplant ** ** The contents of aTree[] are updated first by comparing the new PmaReader ** 5 key to the current key of PmaReader 4 (still "Grapefruit"). The PmaReader ** 5 value is still smaller, so aTree[6] is set to 5. And so on up the tree. ** The value of PmaReader 6 - "Durian" - is now smaller than that of PmaReader ** 5, so aTree[3] is set to 6. Key 0 is smaller than key 6 (Bananafile2. And instead of using a ** background thread to prepare data for the PmaReader, with a single ** threaded IncrMerger the allocate part of pTask->file2 is "refilled" with ** keys from pMerger by the calling thread whenever the PmaReader runs out ** of data. */ struct IncrMerger { SortSubtask *pTask; /* Task that owns this merger */ MergeEngine *pMerger; /* Merge engine thread reads data from */ i64 iStartOff; /* Offset to start writing file at */ int mxSz; /* Maximum bytes of data to store */ int bEof; /* Set to true when merge is finished */ int bUseThread; /* True to use a bg thread for this object */ SorterFile aFile[2]; /* aFile[0] for reading, [1] for writing */ }; /* ** An instance of this object is used for writing a PMA. ** ** The PMA is written one record at a time. Each record is of an arbitrary ** size. But I/O is more efficient if it occurs in page-sized blocks where ** each block is aligned on a page boundary. This object caches writes to ** the PMA so that aligned, page-size blocks are written. */ struct PmaWriter { int eFWErr; /* Non-zero if in an error state */ u8 *aBuffer; /* Pointer to write buffer */ int nBuffer; /* Size of write buffer in bytes */ int iBufStart; /* First byte of buffer to write */ int iBufEnd; /* Last byte of buffer to write */ i64 iWriteOff; /* Offset of start of buffer in file */ sqlite3_file *pFd; /* File handle to write to */ }; /* ** This object is the header on a single record while that record is being ** held in memory and prior to being written out as part of a PMA. ** ** How the linked list is connected depends on how memory is being managed ** by this module. If using a separate allocation for each in-memory record ** (VdbeSorter.list.aMemory==0), then the list is always connected using the ** SorterRecord.u.pNext pointers. ** ** Or, if using the single large allocation method (VdbeSorter.list.aMemory!=0), ** then while records are being accumulated the list is linked using the ** SorterRecord.u.iNext offset. This is because the aMemory[] array may ** be sqlite3Realloc()ed while records are being accumulated. Once the VM ** has finished passing records to the sorter, or when the in-memory buffer ** is full, the list is sorted. As part of the sorting process, it is ** converted to use the SorterRecord.u.pNext pointers. See function ** vdbeSorterSort() for details. */ struct SorterRecord { int nVal; /* Size of the record in bytes */ union { SorterRecord *pNext; /* Pointer to next record in list */ int iNext; /* Offset within aMemory of next record */ } u; /* The data for the record immediately follows this header */ }; /* Return a pointer to the buffer containing the record data for SorterRecord ** object p. Should be used as if: ** ** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; } */ #define SRVAL(p) ((void*)((SorterRecord*)(p) + 1)) /* Maximum number of PMAs that a single MergeEngine can merge */ #define SORTER_MAX_MERGE_COUNT 16 static int vdbeIncrSwap(IncrMerger*); static void vdbeIncrFree(IncrMerger *); /* ** Free all memory belonging to the PmaReader object passed as the ** argument. All structure fields are set to zero before returning. */ static void vdbePmaReaderClear(PmaReader *pReadr){ sqlite3_free(pReadr->aAlloc); sqlite3_free(pReadr->aBuffer); if( pReadr->aMap ) sqlite3OsUnfetch(pReadr->pFd, 0, pReadr->aMap); vdbeIncrFree(pReadr->pIncr); memset(pReadr, 0, sizeof(PmaReader)); } /* ** Read the next nByte bytes of data from the PMA p. ** If successful, set *ppOut to point to a buffer containing the data ** and return SQLITE_OK. Otherwise, if an error occurs, return an SQLite ** error code. ** ** The buffer returned in *ppOut is only valid until the ** next call to this function. */ static int vdbePmaReadBlob( PmaReader *p, /* PmaReader from which to take the blob */ int nByte, /* Bytes of data to read */ u8 **ppOut /* OUT: Pointer to buffer containing data */ ){ int iBuf; /* Offset within buffer to read from */ int nAvail; /* Bytes of data available in buffer */ if( p->aMap ){ *ppOut = &p->aMap[p->iReadOff]; p->iReadOff += nByte; return SQLITE_OK; } assert( p->aBuffer ); /* If there is no more data to be read from the buffer, read the next ** p->nBuffer bytes of data from the file into it. Or, if there are less ** than p->nBuffer bytes remaining in the PMA, read all remaining data. */ iBuf = p->iReadOff % p->nBuffer; if( iBuf==0 ){ int nRead; /* Bytes to read from disk */ int rc; /* sqlite3OsRead() return code */ /* Determine how many bytes of data to read. */ if( (p->iEof - p->iReadOff) > (i64)p->nBuffer ){ nRead = p->nBuffer; }else{ nRead = (int)(p->iEof - p->iReadOff); } assert( nRead>0 ); /* Readr data from the file. Return early if an error occurs. */ rc = sqlite3OsRead(p->pFd, p->aBuffer, nRead, p->iReadOff); assert( rc!=SQLITE_IOERR_SHORT_READ ); if( rc!=SQLITE_OK ) return rc; } nAvail = p->nBuffer - iBuf; if( nByte<=nAvail ){ /* The requested data is available in the in-memory buffer. In this ** case there is no need to make a copy of the data, just return a ** pointer into the buffer to the caller. */ *ppOut = &p->aBuffer[iBuf]; p->iReadOff += nByte; }else{ /* The requested data is not all available in the in-memory buffer. ** In this case, allocate space at p->aAlloc[] to copy the requested ** range into. Then return a copy of pointer p->aAlloc to the caller. */ int nRem; /* Bytes remaining to copy */ /* Extend the p->aAlloc[] allocation if required. */ if( p->nAllocnAlloc); while( nByte>nNew ) nNew = nNew*2; aNew = sqlite3Realloc(p->aAlloc, nNew); if( !aNew ) return SQLITE_NOMEM_BKPT; p->nAlloc = nNew; p->aAlloc = aNew; } /* Copy as much data as is available in the buffer into the start of ** p->aAlloc[]. */ memcpy(p->aAlloc, &p->aBuffer[iBuf], nAvail); p->iReadOff += nAvail; nRem = nByte - nAvail; /* The following loop copies up to p->nBuffer bytes per iteration into ** the p->aAlloc[] buffer. */ while( nRem>0 ){ int rc; /* vdbePmaReadBlob() return code */ int nCopy; /* Number of bytes to copy */ u8 *aNext; /* Pointer to buffer to copy data from */ nCopy = nRem; if( nRem>p->nBuffer ) nCopy = p->nBuffer; rc = vdbePmaReadBlob(p, nCopy, &aNext); if( rc!=SQLITE_OK ) return rc; assert( aNext!=p->aAlloc ); memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy); nRem -= nCopy; } *ppOut = p->aAlloc; } return SQLITE_OK; } /* ** Read a varint from the stream of data accessed by p. Set *pnOut to ** the value read. */ static int vdbePmaReadVarint(PmaReader *p, u64 *pnOut){ int iBuf; if( p->aMap ){ p->iReadOff += sqlite3GetVarint(&p->aMap[p->iReadOff], pnOut); }else{ iBuf = p->iReadOff % p->nBuffer; if( iBuf && (p->nBuffer-iBuf)>=9 ){ p->iReadOff += sqlite3GetVarint(&p->aBuffer[iBuf], pnOut); }else{ u8 aVarint[16], *a; int i = 0, rc; do{ rc = vdbePmaReadBlob(p, 1, &a); if( rc ) return rc; aVarint[(i++)&0xf] = a[0]; }while( (a[0]&0x80)!=0 ); sqlite3GetVarint(aVarint, pnOut); } } return SQLITE_OK; } /* ** Attempt to memory map file pFile. If successful, set *pp to point to the ** new mapping and return SQLITE_OK. If the mapping is not attempted ** (because the file is too large or the VFS layer is configured not to use ** mmap), return SQLITE_OK and set *pp to NULL. ** ** Or, if an error occurs, return an SQLite error code. The final value of ** *pp is undefined in this case. */ static int vdbeSorterMapFile(SortSubtask *pTask, SorterFile *pFile, u8 **pp){ int rc = SQLITE_OK; if( pFile->iEof<=(i64)(pTask->pSorter->db->nMaxSorterMmap) ){ sqlite3_file *pFd = pFile->pFd; if( pFd->pMethods->iVersion>=3 ){ rc = sqlite3OsFetch(pFd, 0, (int)pFile->iEof, (void**)pp); testcase( rc!=SQLITE_OK ); } } return rc; } /* ** Attach PmaReader pReadr to file pFile (if it is not already attached to ** that file) and seek it to offset iOff within the file. Return SQLITE_OK ** if successful, or an SQLite error code if an error occurs. */ static int vdbePmaReaderSeek( SortSubtask *pTask, /* Task context */ PmaReader *pReadr, /* Reader whose cursor is to be moved */ SorterFile *pFile, /* Sorter file to read from */ i64 iOff /* Offset in pFile */ ){ int rc = SQLITE_OK; assert( pReadr->pIncr==0 || pReadr->pIncr->bEof==0 ); if( sqlite3FaultSim(201) ) return SQLITE_IOERR_READ; if( pReadr->aMap ){ sqlite3OsUnfetch(pReadr->pFd, 0, pReadr->aMap); pReadr->aMap = 0; } pReadr->iReadOff = iOff; pReadr->iEof = pFile->iEof; pReadr->pFd = pFile->pFd; rc = vdbeSorterMapFile(pTask, pFile, &pReadr->aMap); if( rc==SQLITE_OK && pReadr->aMap==0 ){ int pgsz = pTask->pSorter->pgsz; int iBuf = pReadr->iReadOff % pgsz; if( pReadr->aBuffer==0 ){ pReadr->aBuffer = (u8*)sqlite3Malloc(pgsz); if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM_BKPT; pReadr->nBuffer = pgsz; } if( rc==SQLITE_OK && iBuf ){ int nRead = pgsz - iBuf; if( (pReadr->iReadOff + nRead) > pReadr->iEof ){ nRead = (int)(pReadr->iEof - pReadr->iReadOff); } rc = sqlite3OsRead( pReadr->pFd, &pReadr->aBuffer[iBuf], nRead, pReadr->iReadOff ); testcase( rc!=SQLITE_OK ); } } return rc; } /* ** Advance PmaReader pReadr to the next key in its PMA. Return SQLITE_OK if ** no error occurs, or an SQLite error code if one does. */ static int vdbePmaReaderNext(PmaReader *pReadr){ int rc = SQLITE_OK; /* Return Code */ u64 nRec = 0; /* Size of record in bytes */ if( pReadr->iReadOff>=pReadr->iEof ){ IncrMerger *pIncr = pReadr->pIncr; int bEof = 1; if( pIncr ){ rc = vdbeIncrSwap(pIncr); if( rc==SQLITE_OK && pIncr->bEof==0 ){ rc = vdbePmaReaderSeek( pIncr->pTask, pReadr, &pIncr->aFile[0], pIncr->iStartOff ); bEof = 0; } } if( bEof ){ /* This is an EOF condition */ vdbePmaReaderClear(pReadr); testcase( rc!=SQLITE_OK ); return rc; } } if( rc==SQLITE_OK ){ rc = vdbePmaReadVarint(pReadr, &nRec); } if( rc==SQLITE_OK ){ pReadr->nKey = (int)nRec; rc = vdbePmaReadBlob(pReadr, (int)nRec, &pReadr->aKey); testcase( rc!=SQLITE_OK ); } return rc; } /* ** Initialize PmaReader pReadr to scan through the PMA stored in file pFile ** starting at offset iStart and ending at offset iEof-1. This function ** leaves the PmaReader pointing to the first key in the PMA (or EOF if the ** PMA is empty). ** ** If the pnByte parameter is NULL, then it is assumed that the file ** contains a single PMA, and that that PMA omits the initial length varint. */ static int vdbePmaReaderInit( SortSubtask *pTask, /* Task context */ SorterFile *pFile, /* Sorter file to read from */ i64 iStart, /* Start offset in pFile */ PmaReader *pReadr, /* PmaReader to populate */ i64 *pnByte /* IN/OUT: Increment this value by PMA size */ ){ int rc; assert( pFile->iEof>iStart ); assert( pReadr->aAlloc==0 && pReadr->nAlloc==0 ); assert( pReadr->aBuffer==0 ); assert( pReadr->aMap==0 ); rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart); if( rc==SQLITE_OK ){ u64 nByte = 0; /* Size of PMA in bytes */ rc = vdbePmaReadVarint(pReadr, &nByte); pReadr->iEof = pReadr->iReadOff + nByte; *pnByte += nByte; } if( rc==SQLITE_OK ){ rc = vdbePmaReaderNext(pReadr); } return rc; } /* ** A version of vdbeSorterCompare() that assumes that it has already been ** determined that the first field of key1 is equal to the first field of ** key2. */ static int vdbeSorterCompareTail( SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2 /* Right side of comparison */ ){ UnpackedRecord *r2 = pTask->pUnpacked; if( *pbKey2Cached==0 ){ sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); *pbKey2Cached = 1; } return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, r2, 1); } /* ** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, ** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences ** used by the comparison. Return the result of the comparison. ** ** If IN/OUT parameter *pbKey2Cached is true when this function is called, ** it is assumed that (pTask->pUnpacked) contains the unpacked version ** of key2. If it is false, (pTask->pUnpacked) is populated with the unpacked ** version of key2 and *pbKey2Cached set to true before returning. ** ** If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set ** to SQLITE_NOMEM. */ static int vdbeSorterCompare( SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2 /* Right side of comparison */ ){ UnpackedRecord *r2 = pTask->pUnpacked; if( !*pbKey2Cached ){ sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); *pbKey2Cached = 1; } return sqlite3VdbeRecordCompare(nKey1, pKey1, r2); } /* ** A specially optimized version of vdbeSorterCompare() that assumes that ** the first field of each key is a TEXT value and that the collation ** sequence to compare them with is BINARY. */ static int vdbeSorterCompareText( SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2 /* Right side of comparison */ ){ const u8 * const p1 = (const u8 * const)pKey1; const u8 * const p2 = (const u8 * const)pKey2; const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */ const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */ int n1; int n2; int res; getVarint32NR(&p1[1], n1); getVarint32NR(&p2[1], n2); res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2); if( res==0 ){ res = n1 - n2; } if( res==0 ){ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); } }else{ assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) ); if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){ res = res * -1; } } return res; } /* ** A specially optimized version of vdbeSorterCompare() that assumes that ** the first field of each key is an INTEGER value. */ static int vdbeSorterCompareInt( SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2 /* Right side of comparison */ ){ const u8 * const p1 = (const u8 * const)pKey1; const u8 * const p2 = (const u8 * const)pKey2; const int s1 = p1[1]; /* Left hand serial type */ const int s2 = p2[1]; /* Right hand serial type */ const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */ const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */ int res; /* Return value */ assert( (s1>0 && s1<7) || s1==8 || s1==9 ); assert( (s2>0 && s2<7) || s2==8 || s2==9 ); if( s1==s2 ){ /* The two values have the same sign. Compare using memcmp(). */ static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8, 0, 0, 0 }; const u8 n = aLen[s1]; int i; res = 0; for(i=0; i7 && s2>7 ){ res = s1 - s2; }else{ if( s2>7 ){ res = +1; }else if( s1>7 ){ res = -1; }else{ res = s1 - s2; } assert( res!=0 ); if( res>0 ){ if( *v1 & 0x80 ) res = -1; }else{ if( *v2 & 0x80 ) res = +1; } } if( res==0 ){ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); } }else if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){ assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) ); res = res * -1; } return res; } /* ** Initialize the temporary index cursor just opened as a sorter cursor. ** ** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField) ** to determine the number of fields that should be compared from the ** records being sorted. However, if the value passed as argument nField ** is non-zero and the sorter is able to guarantee a stable sort, nField ** is used instead. This is used when sorting records for a CREATE INDEX ** statement. In this case, keys are always delivered to the sorter in ** order of the primary key, which happens to be make up the final part ** of the records being sorted. So if the sort is stable, there is never ** any reason to compare PK fields and they can be ignored for a small ** performance boost. ** ** The sorter can guarantee a stable sort when running in single-threaded ** mode, but not in multi-threaded mode. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ SQLITE_PRIVATE int sqlite3VdbeSorterInit( sqlite3 *db, /* Database connection (for malloc()) */ int nField, /* Number of key fields in each record */ VdbeCursor *pCsr /* Cursor that holds the new sorter */ ){ int pgsz; /* Page size of main database */ int i; /* Used to iterate through aTask[] */ VdbeSorter *pSorter; /* The new sorter */ KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */ int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */ int sz; /* Size of pSorter in bytes */ int rc = SQLITE_OK; #if SQLITE_MAX_WORKER_THREADS==0 # define nWorker 0 #else int nWorker; #endif /* Initialize the upper limit on the number of worker threads */ #if SQLITE_MAX_WORKER_THREADS>0 if( sqlite3TempInMemory(db) || sqlite3GlobalConfig.bCoreMutex==0 ){ nWorker = 0; }else{ nWorker = db->aLimit[SQLITE_LIMIT_WORKER_THREADS]; } #endif /* Do not allow the total number of threads (main thread + all workers) ** to exceed the maximum merge count */ #if SQLITE_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT if( nWorker>=SORTER_MAX_MERGE_COUNT ){ nWorker = SORTER_MAX_MERGE_COUNT-1; } #endif assert( pCsr->pKeyInfo ); assert( !pCsr->isEphemeral ); assert( pCsr->eCurType==CURTYPE_SORTER ); szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*); sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); pCsr->uc.pSorter = pSorter; if( pSorter==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ Btree *pBt = db->aDb[0].pBt; pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); pKeyInfo->db = 0; if( nField && nWorker==0 ){ pKeyInfo->nKeyField = nField; } sqlite3BtreeEnter(pBt); pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(pBt); sqlite3BtreeLeave(pBt); pSorter->nTask = nWorker + 1; pSorter->iPrev = (u8)(nWorker - 1); pSorter->bUseThreads = (pSorter->nTask>1); pSorter->db = db; for(i=0; inTask; i++){ SortSubtask *pTask = &pSorter->aTask[i]; pTask->pSorter = pSorter; } if( !sqlite3TempInMemory(db) ){ i64 mxCache; /* Cache size in bytes*/ u32 szPma = sqlite3GlobalConfig.szPma; pSorter->mnPmaSize = szPma * pgsz; mxCache = db->aDb[0].pSchema->cache_size; if( mxCache<0 ){ /* A negative cache-size value C indicates that the cache is abs(C) ** KiB in size. */ mxCache = mxCache * -1024; }else{ mxCache = mxCache * pgsz; } mxCache = MIN(mxCache, SQLITE_MAX_PMASZ); pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache); /* Avoid large memory allocations if the application has requested ** SQLITE_CONFIG_SMALL_MALLOC. */ if( sqlite3GlobalConfig.bSmallMalloc==0 ){ assert( pSorter->iMemory==0 ); pSorter->nMemory = pgsz; pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM_BKPT; } } if( pKeyInfo->nAllField<13 && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) && (pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL)==0 ){ pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; } } return rc; } #undef nWorker /* Defined at the top of this function */ /* ** Free the list of sorted records starting at pRecord. */ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ SorterRecord *p; SorterRecord *pNext; for(p=pRecord; p; p=pNext){ pNext = p->u.pNext; sqlite3DbFree(db, p); } } /* ** Free all resources owned by the object indicated by argument pTask. All ** fields of *pTask are zeroed before returning. */ static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){ sqlite3DbFree(db, pTask->pUnpacked); #if SQLITE_MAX_WORKER_THREADS>0 /* pTask->list.aMemory can only be non-zero if it was handed memory ** from the main thread. That only occurs SQLITE_MAX_WORKER_THREADS>0 */ if( pTask->list.aMemory ){ sqlite3_free(pTask->list.aMemory); }else #endif { assert( pTask->list.aMemory==0 ); vdbeSorterRecordFree(0, pTask->list.pList); } if( pTask->file.pFd ){ sqlite3OsCloseFree(pTask->file.pFd); } if( pTask->file2.pFd ){ sqlite3OsCloseFree(pTask->file2.pFd); } memset(pTask, 0, sizeof(SortSubtask)); } #ifdef SQLITE_DEBUG_SORTER_THREADS static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){ i64 t; int iTask = (pTask - pTask->pSorter->aTask); sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); } static void vdbeSorterRewindDebug(const char *zEvent){ i64 t = 0; sqlite3_vfs *pVfs = sqlite3_vfs_find(0); if( ALWAYS(pVfs) ) sqlite3OsCurrentTimeInt64(pVfs, &t); fprintf(stderr, "%lld:X %s\n", t, zEvent); } static void vdbeSorterPopulateDebug( SortSubtask *pTask, const char *zEvent ){ i64 t; int iTask = (pTask - pTask->pSorter->aTask); sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); fprintf(stderr, "%lld:bg%d %s\n", t, iTask, zEvent); } static void vdbeSorterBlockDebug( SortSubtask *pTask, int bBlocked, const char *zEvent ){ if( bBlocked ){ i64 t; sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); fprintf(stderr, "%lld:main %s\n", t, zEvent); } } #else # define vdbeSorterWorkDebug(x,y) # define vdbeSorterRewindDebug(y) # define vdbeSorterPopulateDebug(x,y) # define vdbeSorterBlockDebug(x,y,z) #endif #if SQLITE_MAX_WORKER_THREADS>0 /* ** Join thread pTask->thread. */ static int vdbeSorterJoinThread(SortSubtask *pTask){ int rc = SQLITE_OK; if( pTask->pThread ){ #ifdef SQLITE_DEBUG_SORTER_THREADS int bDone = pTask->bDone; #endif void *pRet = SQLITE_INT_TO_PTR(SQLITE_ERROR); vdbeSorterBlockDebug(pTask, !bDone, "enter"); (void)sqlite3ThreadJoin(pTask->pThread, &pRet); vdbeSorterBlockDebug(pTask, !bDone, "exit"); rc = SQLITE_PTR_TO_INT(pRet); assert( pTask->bDone==1 ); pTask->bDone = 0; pTask->pThread = 0; } return rc; } /* ** Launch a background thread to run xTask(pIn). */ static int vdbeSorterCreateThread( SortSubtask *pTask, /* Thread will use this task object */ void *(*xTask)(void*), /* Routine to run in a separate thread */ void *pIn /* Argument passed into xTask() */ ){ assert( pTask->pThread==0 && pTask->bDone==0 ); return sqlite3ThreadCreate(&pTask->pThread, xTask, pIn); } /* ** Join all outstanding threads launched by SorterWrite() to create ** level-0 PMAs. */ static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){ int rc = rcin; int i; /* This function is always called by the main user thread. ** ** If this function is being called after SorterRewind() has been called, ** it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread ** is currently attempt to join one of the other threads. To avoid a race ** condition where this thread also attempts to join the same object, join ** thread pSorter->aTask[pSorter->nTask-1].pThread first. */ for(i=pSorter->nTask-1; i>=0; i--){ SortSubtask *pTask = &pSorter->aTask[i]; int rc2 = vdbeSorterJoinThread(pTask); if( rc==SQLITE_OK ) rc = rc2; } return rc; } #else # define vdbeSorterJoinAll(x,rcin) (rcin) # define vdbeSorterJoinThread(pTask) SQLITE_OK #endif /* ** Allocate a new MergeEngine object capable of handling up to ** nReader PmaReader inputs. ** ** nReader is automatically rounded up to the next power of two. ** nReader may not exceed SORTER_MAX_MERGE_COUNT even after rounding up. */ static MergeEngine *vdbeMergeEngineNew(int nReader){ int N = 2; /* Smallest power of two >= nReader */ int nByte; /* Total bytes of space to allocate */ MergeEngine *pNew; /* Pointer to allocated object to return */ assert( nReader<=SORTER_MAX_MERGE_COUNT ); while( NnTree = N; pNew->pTask = 0; pNew->aReadr = (PmaReader*)&pNew[1]; pNew->aTree = (int*)&pNew->aReadr[N]; } return pNew; } /* ** Free the MergeEngine object passed as the only argument. */ static void vdbeMergeEngineFree(MergeEngine *pMerger){ int i; if( pMerger ){ for(i=0; inTree; i++){ vdbePmaReaderClear(&pMerger->aReadr[i]); } } sqlite3_free(pMerger); } /* ** Free all resources associated with the IncrMerger object indicated by ** the first argument. */ static void vdbeIncrFree(IncrMerger *pIncr){ if( pIncr ){ #if SQLITE_MAX_WORKER_THREADS>0 if( pIncr->bUseThread ){ vdbeSorterJoinThread(pIncr->pTask); if( pIncr->aFile[0].pFd ) sqlite3OsCloseFree(pIncr->aFile[0].pFd); if( pIncr->aFile[1].pFd ) sqlite3OsCloseFree(pIncr->aFile[1].pFd); } #endif vdbeMergeEngineFree(pIncr->pMerger); sqlite3_free(pIncr); } } /* ** Reset a sorting cursor back to its original empty state. */ SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){ int i; (void)vdbeSorterJoinAll(pSorter, SQLITE_OK); assert( pSorter->bUseThreads || pSorter->pReader==0 ); #if SQLITE_MAX_WORKER_THREADS>0 if( pSorter->pReader ){ vdbePmaReaderClear(pSorter->pReader); sqlite3DbFree(db, pSorter->pReader); pSorter->pReader = 0; } #endif vdbeMergeEngineFree(pSorter->pMerger); pSorter->pMerger = 0; for(i=0; inTask; i++){ SortSubtask *pTask = &pSorter->aTask[i]; vdbeSortSubtaskCleanup(db, pTask); pTask->pSorter = pSorter; } if( pSorter->list.aMemory==0 ){ vdbeSorterRecordFree(0, pSorter->list.pList); } pSorter->list.pList = 0; pSorter->list.szPMA = 0; pSorter->bUsePMA = 0; pSorter->iMemory = 0; pSorter->mxKeysize = 0; sqlite3DbFree(db, pSorter->pUnpacked); pSorter->pUnpacked = 0; } /* ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. */ SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ VdbeSorter *pSorter; assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; if( pSorter ){ sqlite3VdbeSorterReset(db, pSorter); sqlite3_free(pSorter->list.aMemory); sqlite3DbFree(db, pSorter); pCsr->uc.pSorter = 0; } } #if SQLITE_MAX_MMAP_SIZE>0 /* ** The first argument is a file-handle open on a temporary file. The file ** is guaranteed to be nByte bytes or smaller in size. This function ** attempts to extend the file to nByte bytes in size and to ensure that ** the VFS has memory mapped it. ** ** Whether or not the file does end up memory mapped of course depends on ** the specific VFS implementation. */ static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){ if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){ void *p = 0; int chunksize = 4*1024; sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize); sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte); sqlite3OsFetch(pFd, 0, (int)nByte, &p); if( p ) sqlite3OsUnfetch(pFd, 0, p); } } #else # define vdbeSorterExtendFile(x,y,z) #endif /* ** Allocate space for a file-handle and open a temporary file. If successful, ** set *ppFd to point to the malloc'd file-handle and return SQLITE_OK. ** Otherwise, set *ppFd to 0 and return an SQLite error code. */ static int vdbeSorterOpenTempFile( sqlite3 *db, /* Database handle doing sort */ i64 nExtend, /* Attempt to extend file to this size */ sqlite3_file **ppFd ){ int rc; if( sqlite3FaultSim(202) ) return SQLITE_IOERR_ACCESS; rc = sqlite3OsOpenMalloc(db->pVfs, 0, ppFd, SQLITE_OPEN_TEMP_JOURNAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &rc ); if( rc==SQLITE_OK ){ i64 max = SQLITE_MAX_MMAP_SIZE; sqlite3OsFileControlHint(*ppFd, SQLITE_FCNTL_MMAP_SIZE, (void*)&max); if( nExtend>0 ){ vdbeSorterExtendFile(db, *ppFd, nExtend); } } return rc; } /* ** If it has not already been allocated, allocate the UnpackedRecord ** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or ** if no allocation was required), or SQLITE_NOMEM otherwise. */ static int vdbeSortAllocUnpacked(SortSubtask *pTask){ if( pTask->pUnpacked==0 ){ pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo); if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT; pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField; pTask->pUnpacked->errCode = 0; } return SQLITE_OK; } /* ** Merge the two sorted lists p1 and p2 into a single list. */ static SorterRecord *vdbeSorterMerge( SortSubtask *pTask, /* Calling thread context */ SorterRecord *p1, /* First list to merge */ SorterRecord *p2 /* Second list to merge */ ){ SorterRecord *pFinal = 0; SorterRecord **pp = &pFinal; int bCached = 0; assert( p1!=0 && p2!=0 ); for(;;){ int res; res = pTask->xCompare( pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal ); if( res<=0 ){ *pp = p1; pp = &p1->u.pNext; p1 = p1->u.pNext; if( p1==0 ){ *pp = p2; break; } }else{ *pp = p2; pp = &p2->u.pNext; p2 = p2->u.pNext; bCached = 0; if( p2==0 ){ *pp = p1; break; } } } return pFinal; } /* ** Return the SorterCompare function to compare values collected by the ** sorter object passed as the only argument. */ static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){ if( p->typeMask==SORTER_TYPE_INTEGER ){ return vdbeSorterCompareInt; }else if( p->typeMask==SORTER_TYPE_TEXT ){ return vdbeSorterCompareText; } return vdbeSorterCompare; } /* ** Sort the linked list of records headed at pTask->pList. Return ** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if ** an error occurs. */ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ int i; SorterRecord *p; int rc; SorterRecord *aSlot[64]; rc = vdbeSortAllocUnpacked(pTask); if( rc!=SQLITE_OK ) return rc; p = pList->pList; pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter); memset(aSlot, 0, sizeof(aSlot)); while( p ){ SorterRecord *pNext; if( pList->aMemory ){ if( (u8*)p==pList->aMemory ){ pNext = 0; }else{ assert( p->u.iNextaMemory) ); pNext = (SorterRecord*)&pList->aMemory[p->u.iNext]; } }else{ pNext = p->u.pNext; } p->u.pNext = 0; for(i=0; aSlot[i]; i++){ p = vdbeSorterMerge(pTask, p, aSlot[i]); aSlot[i] = 0; } aSlot[i] = p; p = pNext; } p = 0; for(i=0; ipList = p; assert( pTask->pUnpacked->errCode==SQLITE_OK || pTask->pUnpacked->errCode==SQLITE_NOMEM ); return pTask->pUnpacked->errCode; } /* ** Initialize a PMA-writer object. */ static void vdbePmaWriterInit( sqlite3_file *pFd, /* File handle to write to */ PmaWriter *p, /* Object to populate */ int nBuf, /* Buffer size */ i64 iStart /* Offset of pFd to begin writing at */ ){ memset(p, 0, sizeof(PmaWriter)); p->aBuffer = (u8*)sqlite3Malloc(nBuf); if( !p->aBuffer ){ p->eFWErr = SQLITE_NOMEM_BKPT; }else{ p->iBufEnd = p->iBufStart = (iStart % nBuf); p->iWriteOff = iStart - p->iBufStart; p->nBuffer = nBuf; p->pFd = pFd; } } /* ** Write nData bytes of data to the PMA. Return SQLITE_OK ** if successful, or an SQLite error code if an error occurs. */ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){ int nRem = nData; while( nRem>0 && p->eFWErr==0 ){ int nCopy = nRem; if( nCopy>(p->nBuffer - p->iBufEnd) ){ nCopy = p->nBuffer - p->iBufEnd; } memcpy(&p->aBuffer[p->iBufEnd], &pData[nData-nRem], nCopy); p->iBufEnd += nCopy; if( p->iBufEnd==p->nBuffer ){ p->eFWErr = sqlite3OsWrite(p->pFd, &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, p->iWriteOff + p->iBufStart ); p->iBufStart = p->iBufEnd = 0; p->iWriteOff += p->nBuffer; } assert( p->iBufEndnBuffer ); nRem -= nCopy; } } /* ** Flush any buffered data to disk and clean up the PMA-writer object. ** The results of using the PMA-writer after this call are undefined. ** Return SQLITE_OK if flushing the buffered data succeeds or is not ** required. Otherwise, return an SQLite error code. ** ** Before returning, set *piEof to the offset immediately following the ** last byte written to the file. */ static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){ int rc; if( p->eFWErr==0 && ALWAYS(p->aBuffer) && p->iBufEnd>p->iBufStart ){ p->eFWErr = sqlite3OsWrite(p->pFd, &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, p->iWriteOff + p->iBufStart ); } *piEof = (p->iWriteOff + p->iBufEnd); sqlite3_free(p->aBuffer); rc = p->eFWErr; memset(p, 0, sizeof(PmaWriter)); return rc; } /* ** Write value iVal encoded as a varint to the PMA. Return ** SQLITE_OK if successful, or an SQLite error code if an error occurs. */ static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){ int nByte; u8 aByte[10]; nByte = sqlite3PutVarint(aByte, iVal); vdbePmaWriteBlob(p, aByte, nByte); } /* ** Write the current contents of in-memory linked-list pList to a level-0 ** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if ** successful, or an SQLite error code otherwise. ** ** The format of a PMA is: ** ** * A varint. This varint contains the total number of bytes of content ** in the PMA (not including the varint itself). ** ** * One or more records packed end-to-end in order of ascending keys. ** Each record consists of a varint followed by a blob of data (the ** key). The varint is the number of bytes in the blob of data. */ static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){ sqlite3 *db = pTask->pSorter->db; int rc = SQLITE_OK; /* Return code */ PmaWriter writer; /* Object used to write to the file */ #ifdef SQLITE_DEBUG /* Set iSz to the expected size of file pTask->file after writing the PMA. ** This is used by an assert() statement at the end of this function. */ i64 iSz = pList->szPMA + sqlite3VarintLen(pList->szPMA) + pTask->file.iEof; #endif vdbeSorterWorkDebug(pTask, "enter"); memset(&writer, 0, sizeof(PmaWriter)); assert( pList->szPMA>0 ); /* If the first temporary PMA file has not been opened, open it now. */ if( pTask->file.pFd==0 ){ rc = vdbeSorterOpenTempFile(db, 0, &pTask->file.pFd); assert( rc!=SQLITE_OK || pTask->file.pFd ); assert( pTask->file.iEof==0 ); assert( pTask->nPMA==0 ); } /* Try to get the file to memory map */ if( rc==SQLITE_OK ){ vdbeSorterExtendFile(db, pTask->file.pFd, pTask->file.iEof+pList->szPMA+9); } /* Sort the list */ if( rc==SQLITE_OK ){ rc = vdbeSorterSort(pTask, pList); } if( rc==SQLITE_OK ){ SorterRecord *p; SorterRecord *pNext = 0; vdbePmaWriterInit(pTask->file.pFd, &writer, pTask->pSorter->pgsz, pTask->file.iEof); pTask->nPMA++; vdbePmaWriteVarint(&writer, pList->szPMA); for(p=pList->pList; p; p=pNext){ pNext = p->u.pNext; vdbePmaWriteVarint(&writer, p->nVal); vdbePmaWriteBlob(&writer, SRVAL(p), p->nVal); if( pList->aMemory==0 ) sqlite3_free(p); } pList->pList = p; rc = vdbePmaWriterFinish(&writer, &pTask->file.iEof); } vdbeSorterWorkDebug(pTask, "exit"); assert( rc!=SQLITE_OK || pList->pList==0 ); assert( rc!=SQLITE_OK || pTask->file.iEof==iSz ); return rc; } /* ** Advance the MergeEngine to its next entry. ** Set *pbEof to true there is no next entry because ** the MergeEngine has reached the end of all its inputs. ** ** Return SQLITE_OK if successful or an error code if an error occurs. */ static int vdbeMergeEngineStep( MergeEngine *pMerger, /* The merge engine to advance to the next row */ int *pbEof /* Set TRUE at EOF. Set false for more content */ ){ int rc; int iPrev = pMerger->aTree[1];/* Index of PmaReader to advance */ SortSubtask *pTask = pMerger->pTask; /* Advance the current PmaReader */ rc = vdbePmaReaderNext(&pMerger->aReadr[iPrev]); /* Update contents of aTree[] */ if( rc==SQLITE_OK ){ int i; /* Index of aTree[] to recalculate */ PmaReader *pReadr1; /* First PmaReader to compare */ PmaReader *pReadr2; /* Second PmaReader to compare */ int bCached = 0; /* Find the first two PmaReaders to compare. The one that was just ** advanced (iPrev) and the one next to it in the array. */ pReadr1 = &pMerger->aReadr[(iPrev & 0xFFFE)]; pReadr2 = &pMerger->aReadr[(iPrev | 0x0001)]; for(i=(pMerger->nTree+iPrev)/2; i>0; i=i/2){ /* Compare pReadr1 and pReadr2. Store the result in variable iRes. */ int iRes; if( pReadr1->pFd==0 ){ iRes = +1; }else if( pReadr2->pFd==0 ){ iRes = -1; }else{ iRes = pTask->xCompare(pTask, &bCached, pReadr1->aKey, pReadr1->nKey, pReadr2->aKey, pReadr2->nKey ); } /* If pReadr1 contained the smaller value, set aTree[i] to its index. ** Then set pReadr2 to the next PmaReader to compare to pReadr1. In this ** case there is no cache of pReadr2 in pTask->pUnpacked, so set ** pKey2 to point to the record belonging to pReadr2. ** ** Alternatively, if pReadr2 contains the smaller of the two values, ** set aTree[i] to its index and update pReadr1. If vdbeSorterCompare() ** was actually called above, then pTask->pUnpacked now contains ** a value equivalent to pReadr2. So set pKey2 to NULL to prevent ** vdbeSorterCompare() from decoding pReadr2 again. ** ** If the two values were equal, then the value from the oldest ** PMA should be considered smaller. The VdbeSorter.aReadr[] array ** is sorted from oldest to newest, so pReadr1 contains older values ** than pReadr2 iff (pReadr1aTree[i] = (int)(pReadr1 - pMerger->aReadr); pReadr2 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; bCached = 0; }else{ if( pReadr1->pFd ) bCached = 0; pMerger->aTree[i] = (int)(pReadr2 - pMerger->aReadr); pReadr1 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; } } *pbEof = (pMerger->aReadr[pMerger->aTree[1]].pFd==0); } return (rc==SQLITE_OK ? pTask->pUnpacked->errCode : rc); } #if SQLITE_MAX_WORKER_THREADS>0 /* ** The main routine for background threads that write level-0 PMAs. */ static void *vdbeSorterFlushThread(void *pCtx){ SortSubtask *pTask = (SortSubtask*)pCtx; int rc; /* Return code */ assert( pTask->bDone==0 ); rc = vdbeSorterListToPMA(pTask, &pTask->list); pTask->bDone = 1; return SQLITE_INT_TO_PTR(rc); } #endif /* SQLITE_MAX_WORKER_THREADS>0 */ /* ** Flush the current contents of VdbeSorter.list to a new PMA, possibly ** using a background thread. */ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){ #if SQLITE_MAX_WORKER_THREADS==0 pSorter->bUsePMA = 1; return vdbeSorterListToPMA(&pSorter->aTask[0], &pSorter->list); #else int rc = SQLITE_OK; int i; SortSubtask *pTask = 0; /* Thread context used to create new PMA */ int nWorker = (pSorter->nTask-1); /* Set the flag to indicate that at least one PMA has been written. ** Or will be, anyhow. */ pSorter->bUsePMA = 1; /* Select a sub-task to sort and flush the current list of in-memory ** records to disk. If the sorter is running in multi-threaded mode, ** round-robin between the first (pSorter->nTask-1) tasks. Except, if ** the background thread from a sub-tasks previous turn is still running, ** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy, ** fall back to using the final sub-task. The first (pSorter->nTask-1) ** sub-tasks are preferred as they use background threads - the final ** sub-task uses the main thread. */ for(i=0; iiPrev + i + 1) % nWorker; pTask = &pSorter->aTask[iTest]; if( pTask->bDone ){ rc = vdbeSorterJoinThread(pTask); } if( rc!=SQLITE_OK || pTask->pThread==0 ) break; } if( rc==SQLITE_OK ){ if( i==nWorker ){ /* Use the foreground thread for this operation */ rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], &pSorter->list); }else{ /* Launch a background thread for this operation */ u8 *aMem; void *pCtx; assert( pTask!=0 ); assert( pTask->pThread==0 && pTask->bDone==0 ); assert( pTask->list.pList==0 ); assert( pTask->list.aMemory==0 || pSorter->list.aMemory!=0 ); aMem = pTask->list.aMemory; pCtx = (void*)pTask; pSorter->iPrev = (u8)(pTask - pSorter->aTask); pTask->list = pSorter->list; pSorter->list.pList = 0; pSorter->list.szPMA = 0; if( aMem ){ pSorter->list.aMemory = aMem; pSorter->nMemory = sqlite3MallocSize(aMem); }else if( pSorter->list.aMemory ){ pSorter->list.aMemory = sqlite3Malloc(pSorter->nMemory); if( !pSorter->list.aMemory ) return SQLITE_NOMEM_BKPT; } rc = vdbeSorterCreateThread(pTask, vdbeSorterFlushThread, pCtx); } } return rc; #endif /* SQLITE_MAX_WORKER_THREADS!=0 */ } /* ** Add a record to the sorter. */ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal /* Memory cell containing record */ ){ VdbeSorter *pSorter; int rc = SQLITE_OK; /* Return Code */ SorterRecord *pNew; /* New list element */ int bFlush; /* True to flush contents of memory to PMA */ i64 nReq; /* Bytes of memory required */ i64 nPMA; /* Bytes of PMA space required */ int t; /* serial type of first record field */ assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; getVarint32NR((const u8*)&pVal->z[1], t); if( t>0 && t<10 && t!=7 ){ pSorter->typeMask &= SORTER_TYPE_INTEGER; }else if( t>10 && (t & 0x01) ){ pSorter->typeMask &= SORTER_TYPE_TEXT; }else{ pSorter->typeMask = 0; } assert( pSorter ); /* Figure out whether or not the current contents of memory should be ** flushed to a PMA before continuing. If so, do so. ** ** If using the single large allocation mode (pSorter->aMemory!=0), then ** flush the contents of memory to a new PMA if (a) at least one value is ** already in memory and (b) the new value will not fit in memory. ** ** Or, if using separate allocations for each record, flush the contents ** of memory to a PMA if either of the following are true: ** ** * The total memory allocated for the in-memory list is greater ** than (page-size * cache-size), or ** ** * The total memory allocated for the in-memory list is greater ** than (page-size * 10) and sqlite3HeapNearlyFull() returns true. */ nReq = pVal->n + sizeof(SorterRecord); nPMA = pVal->n + sqlite3VarintLen(pVal->n); if( pSorter->mxPmaSize ){ if( pSorter->list.aMemory ){ bFlush = pSorter->iMemory && (pSorter->iMemory+nReq) > pSorter->mxPmaSize; }else{ bFlush = ( (pSorter->list.szPMA > pSorter->mxPmaSize) || (pSorter->list.szPMA > pSorter->mnPmaSize && sqlite3HeapNearlyFull()) ); } if( bFlush ){ rc = vdbeSorterFlushPMA(pSorter); pSorter->list.szPMA = 0; pSorter->iMemory = 0; assert( rc!=SQLITE_OK || pSorter->list.pList==0 ); } } pSorter->list.szPMA += nPMA; if( nPMA>pSorter->mxKeysize ){ pSorter->mxKeysize = nPMA; } if( pSorter->list.aMemory ){ int nMin = pSorter->iMemory + nReq; if( nMin>pSorter->nMemory ){ u8 *aNew; sqlite3_int64 nNew = 2 * (sqlite3_int64)pSorter->nMemory; int iListOff = -1; if( pSorter->list.pList ){ iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory; } while( nNew < nMin ) nNew = nNew*2; if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize; if( nNew < nMin ) nNew = nMin; aNew = sqlite3Realloc(pSorter->list.aMemory, nNew); if( !aNew ) return SQLITE_NOMEM_BKPT; if( iListOff>=0 ){ pSorter->list.pList = (SorterRecord*)&aNew[iListOff]; } pSorter->list.aMemory = aNew; pSorter->nMemory = nNew; } pNew = (SorterRecord*)&pSorter->list.aMemory[pSorter->iMemory]; pSorter->iMemory += ROUND8(nReq); if( pSorter->list.pList ){ pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory); } }else{ pNew = (SorterRecord *)sqlite3Malloc(nReq); if( pNew==0 ){ return SQLITE_NOMEM_BKPT; } pNew->u.pNext = pSorter->list.pList; } memcpy(SRVAL(pNew), pVal->z, pVal->n); pNew->nVal = pVal->n; pSorter->list.pList = pNew; return rc; } /* ** Read keys from pIncr->pMerger and populate pIncr->aFile[1]. The format ** of the data stored in aFile[1] is the same as that used by regular PMAs, ** except that the number-of-bytes varint is omitted from the start. */ static int vdbeIncrPopulate(IncrMerger *pIncr){ int rc = SQLITE_OK; int rc2; i64 iStart = pIncr->iStartOff; SorterFile *pOut = &pIncr->aFile[1]; SortSubtask *pTask = pIncr->pTask; MergeEngine *pMerger = pIncr->pMerger; PmaWriter writer; assert( pIncr->bEof==0 ); vdbeSorterPopulateDebug(pTask, "enter"); vdbePmaWriterInit(pOut->pFd, &writer, pTask->pSorter->pgsz, iStart); while( rc==SQLITE_OK ){ int dummy; PmaReader *pReader = &pMerger->aReadr[ pMerger->aTree[1] ]; int nKey = pReader->nKey; i64 iEof = writer.iWriteOff + writer.iBufEnd; /* Check if the output file is full or if the input has been exhausted. ** In either case exit the loop. */ if( pReader->pFd==0 ) break; if( (iEof + nKey + sqlite3VarintLen(nKey))>(iStart + pIncr->mxSz) ) break; /* Write the next key to the output. */ vdbePmaWriteVarint(&writer, nKey); vdbePmaWriteBlob(&writer, pReader->aKey, nKey); assert( pIncr->pMerger->pTask==pTask ); rc = vdbeMergeEngineStep(pIncr->pMerger, &dummy); } rc2 = vdbePmaWriterFinish(&writer, &pOut->iEof); if( rc==SQLITE_OK ) rc = rc2; vdbeSorterPopulateDebug(pTask, "exit"); return rc; } #if SQLITE_MAX_WORKER_THREADS>0 /* ** The main routine for background threads that populate aFile[1] of ** multi-threaded IncrMerger objects. */ static void *vdbeIncrPopulateThread(void *pCtx){ IncrMerger *pIncr = (IncrMerger*)pCtx; void *pRet = SQLITE_INT_TO_PTR( vdbeIncrPopulate(pIncr) ); pIncr->pTask->bDone = 1; return pRet; } /* ** Launch a background thread to populate aFile[1] of pIncr. */ static int vdbeIncrBgPopulate(IncrMerger *pIncr){ void *p = (void*)pIncr; assert( pIncr->bUseThread ); return vdbeSorterCreateThread(pIncr->pTask, vdbeIncrPopulateThread, p); } #endif /* ** This function is called when the PmaReader corresponding to pIncr has ** finished reading the contents of aFile[0]. Its purpose is to "refill" ** aFile[0] such that the PmaReader should start rereading it from the ** beginning. ** ** For single-threaded objects, this is accomplished by literally reading ** keys from pIncr->pMerger and repopulating aFile[0]. ** ** For multi-threaded objects, all that is required is to wait until the ** background thread is finished (if it is not already) and then swap ** aFile[0] and aFile[1] in place. If the contents of pMerger have not ** been exhausted, this function also launches a new background thread ** to populate the new aFile[1]. ** ** SQLITE_OK is returned on success, or an SQLite error code otherwise. */ static int vdbeIncrSwap(IncrMerger *pIncr){ int rc = SQLITE_OK; #if SQLITE_MAX_WORKER_THREADS>0 if( pIncr->bUseThread ){ rc = vdbeSorterJoinThread(pIncr->pTask); if( rc==SQLITE_OK ){ SorterFile f0 = pIncr->aFile[0]; pIncr->aFile[0] = pIncr->aFile[1]; pIncr->aFile[1] = f0; } if( rc==SQLITE_OK ){ if( pIncr->aFile[0].iEof==pIncr->iStartOff ){ pIncr->bEof = 1; }else{ rc = vdbeIncrBgPopulate(pIncr); } } }else #endif { rc = vdbeIncrPopulate(pIncr); pIncr->aFile[0] = pIncr->aFile[1]; if( pIncr->aFile[0].iEof==pIncr->iStartOff ){ pIncr->bEof = 1; } } return rc; } /* ** Allocate and return a new IncrMerger object to read data from pMerger. ** ** If an OOM condition is encountered, return NULL. In this case free the ** pMerger argument before returning. */ static int vdbeIncrMergerNew( SortSubtask *pTask, /* The thread that will be using the new IncrMerger */ MergeEngine *pMerger, /* The MergeEngine that the IncrMerger will control */ IncrMerger **ppOut /* Write the new IncrMerger here */ ){ int rc = SQLITE_OK; IncrMerger *pIncr = *ppOut = (IncrMerger*) (sqlite3FaultSim(100) ? 0 : sqlite3MallocZero(sizeof(*pIncr))); if( pIncr ){ pIncr->pMerger = pMerger; pIncr->pTask = pTask; pIncr->mxSz = MAX(pTask->pSorter->mxKeysize+9,pTask->pSorter->mxPmaSize/2); pTask->file2.iEof += pIncr->mxSz; }else{ vdbeMergeEngineFree(pMerger); rc = SQLITE_NOMEM_BKPT; } assert( *ppOut!=0 || rc!=SQLITE_OK ); return rc; } #if SQLITE_MAX_WORKER_THREADS>0 /* ** Set the "use-threads" flag on object pIncr. */ static void vdbeIncrMergerSetThreads(IncrMerger *pIncr){ pIncr->bUseThread = 1; pIncr->pTask->file2.iEof -= pIncr->mxSz; } #endif /* SQLITE_MAX_WORKER_THREADS>0 */ /* ** Recompute pMerger->aTree[iOut] by comparing the next keys on the ** two PmaReaders that feed that entry. Neither of the PmaReaders ** are advanced. This routine merely does the comparison. */ static void vdbeMergeEngineCompare( MergeEngine *pMerger, /* Merge engine containing PmaReaders to compare */ int iOut /* Store the result in pMerger->aTree[iOut] */ ){ int i1; int i2; int iRes; PmaReader *p1; PmaReader *p2; assert( iOutnTree && iOut>0 ); if( iOut>=(pMerger->nTree/2) ){ i1 = (iOut - pMerger->nTree/2) * 2; i2 = i1 + 1; }else{ i1 = pMerger->aTree[iOut*2]; i2 = pMerger->aTree[iOut*2+1]; } p1 = &pMerger->aReadr[i1]; p2 = &pMerger->aReadr[i2]; if( p1->pFd==0 ){ iRes = i2; }else if( p2->pFd==0 ){ iRes = i1; }else{ SortSubtask *pTask = pMerger->pTask; int bCached = 0; int res; assert( pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */ res = pTask->xCompare( pTask, &bCached, p1->aKey, p1->nKey, p2->aKey, p2->nKey ); if( res<=0 ){ iRes = i1; }else{ iRes = i2; } } pMerger->aTree[iOut] = iRes; } /* ** Allowed values for the eMode parameter to vdbeMergeEngineInit() ** and vdbePmaReaderIncrMergeInit(). ** ** Only INCRINIT_NORMAL is valid in single-threaded builds (when ** SQLITE_MAX_WORKER_THREADS==0). The other values are only used ** when there exists one or more separate worker threads. */ #define INCRINIT_NORMAL 0 #define INCRINIT_TASK 1 #define INCRINIT_ROOT 2 /* ** Forward reference required as the vdbeIncrMergeInit() and ** vdbePmaReaderIncrInit() routines are called mutually recursively when ** building a merge tree. */ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode); /* ** Initialize the MergeEngine object passed as the second argument. Once this ** function returns, the first key of merged data may be read from the ** MergeEngine object in the usual fashion. ** ** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge ** objects attached to the PmaReader objects that the merger reads from have ** already been populated, but that they have not yet populated aFile[0] and ** set the PmaReader objects up to read from it. In this case all that is ** required is to call vdbePmaReaderNext() on each PmaReader to point it at ** its first key. ** ** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use ** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data ** to pMerger. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ static int vdbeMergeEngineInit( SortSubtask *pTask, /* Thread that will run pMerger */ MergeEngine *pMerger, /* MergeEngine to initialize */ int eMode /* One of the INCRINIT_XXX constants */ ){ int rc = SQLITE_OK; /* Return code */ int i; /* For looping over PmaReader objects */ int nTree; /* Number of subtrees to merge */ /* Failure to allocate the merge would have been detected prior to ** invoking this routine */ assert( pMerger!=0 ); /* eMode is always INCRINIT_NORMAL in single-threaded mode */ assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); /* Verify that the MergeEngine is assigned to a single thread */ assert( pMerger->pTask==0 ); pMerger->pTask = pTask; nTree = pMerger->nTree; for(i=0; i0 && eMode==INCRINIT_ROOT ){ /* PmaReaders should be normally initialized in order, as if they are ** reading from the same temp file this makes for more linear file IO. ** However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is ** in use it will block the vdbePmaReaderNext() call while it uses ** the main thread to fill its buffer. So calling PmaReaderNext() ** on this PmaReader before any of the multi-threaded PmaReaders takes ** better advantage of multi-processor hardware. */ rc = vdbePmaReaderNext(&pMerger->aReadr[nTree-i-1]); }else{ rc = vdbePmaReaderIncrInit(&pMerger->aReadr[i], INCRINIT_NORMAL); } if( rc!=SQLITE_OK ) return rc; } for(i=pMerger->nTree-1; i>0; i--){ vdbeMergeEngineCompare(pMerger, i); } return pTask->pUnpacked->errCode; } /* ** The PmaReader passed as the first argument is guaranteed to be an ** incremental-reader (pReadr->pIncr!=0). This function serves to open ** and/or initialize the temp file related fields of the IncrMerge ** object at (pReadr->pIncr). ** ** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders ** in the sub-tree headed by pReadr are also initialized. Data is then ** loaded into the buffers belonging to pReadr and it is set to point to ** the first key in its range. ** ** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed ** to be a multi-threaded PmaReader and this function is being called in a ** background thread. In this case all PmaReaders in the sub-tree are ** initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to ** pReadr is populated. However, pReadr itself is not set up to point ** to its first key. A call to vdbePmaReaderNext() is still required to do ** that. ** ** The reason this function does not call vdbePmaReaderNext() immediately ** in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has ** to block on thread (pTask->thread) before accessing aFile[1]. But, since ** this entire function is being run by thread (pTask->thread), that will ** lead to the current background thread attempting to join itself. ** ** Finally, if argument eMode is set to INCRINIT_ROOT, it may be assumed ** that pReadr->pIncr is a multi-threaded IncrMerge objects, and that all ** child-trees have already been initialized using IncrInit(INCRINIT_TASK). ** In this case vdbePmaReaderNext() is called on all child PmaReaders and ** the current PmaReader set to point to the first key in its range. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ int rc = SQLITE_OK; IncrMerger *pIncr = pReadr->pIncr; SortSubtask *pTask = pIncr->pTask; sqlite3 *db = pTask->pSorter->db; /* eMode is always INCRINIT_NORMAL in single-threaded mode */ assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode); /* Set up the required files for pIncr. A multi-threaded IncrMerge object ** requires two temp files to itself, whereas a single-threaded object ** only requires a region of pTask->file2. */ if( rc==SQLITE_OK ){ int mxSz = pIncr->mxSz; #if SQLITE_MAX_WORKER_THREADS>0 if( pIncr->bUseThread ){ rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd); if( rc==SQLITE_OK ){ rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd); } }else #endif /*if( !pIncr->bUseThread )*/{ if( pTask->file2.pFd==0 ){ assert( pTask->file2.iEof>0 ); rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd); pTask->file2.iEof = 0; } if( rc==SQLITE_OK ){ pIncr->aFile[1].pFd = pTask->file2.pFd; pIncr->iStartOff = pTask->file2.iEof; pTask->file2.iEof += mxSz; } } } #if SQLITE_MAX_WORKER_THREADS>0 if( rc==SQLITE_OK && pIncr->bUseThread ){ /* Use the current thread to populate aFile[1], even though this ** PmaReader is multi-threaded. If this is an INCRINIT_TASK object, ** then this function is already running in background thread ** pIncr->pTask->thread. ** ** If this is the INCRINIT_ROOT object, then it is running in the ** main VDBE thread. But that is Ok, as that thread cannot return ** control to the VDBE or proceed with anything useful until the ** first results are ready from this merger object anyway. */ assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK ); rc = vdbeIncrPopulate(pIncr); } #endif if( rc==SQLITE_OK && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) ){ rc = vdbePmaReaderNext(pReadr); } return rc; } #if SQLITE_MAX_WORKER_THREADS>0 /* ** The main routine for vdbePmaReaderIncrMergeInit() operations run in ** background threads. */ static void *vdbePmaReaderBgIncrInit(void *pCtx){ PmaReader *pReader = (PmaReader*)pCtx; void *pRet = SQLITE_INT_TO_PTR( vdbePmaReaderIncrMergeInit(pReader,INCRINIT_TASK) ); pReader->pIncr->pTask->bDone = 1; return pRet; } #endif /* ** If the PmaReader passed as the first argument is not an incremental-reader ** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes ** the vdbePmaReaderIncrMergeInit() function with the parameters passed to ** this routine to initialize the incremental merge. ** ** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1), ** then a background thread is launched to call vdbePmaReaderIncrMergeInit(). ** Or, if the IncrMerger is single threaded, the same function is called ** using the current thread. */ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode){ IncrMerger *pIncr = pReadr->pIncr; /* Incremental merger */ int rc = SQLITE_OK; /* Return code */ if( pIncr ){ #if SQLITE_MAX_WORKER_THREADS>0 assert( pIncr->bUseThread==0 || eMode==INCRINIT_TASK ); if( pIncr->bUseThread ){ void *pCtx = (void*)pReadr; rc = vdbeSorterCreateThread(pIncr->pTask, vdbePmaReaderBgIncrInit, pCtx); }else #endif { rc = vdbePmaReaderIncrMergeInit(pReadr, eMode); } } return rc; } /* ** Allocate a new MergeEngine object to merge the contents of nPMA level-0 ** PMAs from pTask->file. If no error occurs, set *ppOut to point to ** the new object and return SQLITE_OK. Or, if an error does occur, set *ppOut ** to NULL and return an SQLite error code. ** ** When this function is called, *piOffset is set to the offset of the ** first PMA to read from pTask->file. Assuming no error occurs, it is ** set to the offset immediately following the last byte of the last ** PMA before returning. If an error does occur, then the final value of ** *piOffset is undefined. */ static int vdbeMergeEngineLevel0( SortSubtask *pTask, /* Sorter task to read from */ int nPMA, /* Number of PMAs to read */ i64 *piOffset, /* IN/OUT: Readr offset in pTask->file */ MergeEngine **ppOut /* OUT: New merge-engine */ ){ MergeEngine *pNew; /* Merge engine to return */ i64 iOff = *piOffset; int i; int rc = SQLITE_OK; *ppOut = pNew = vdbeMergeEngineNew(nPMA); if( pNew==0 ) rc = SQLITE_NOMEM_BKPT; for(i=0; iaReadr[i]; rc = vdbePmaReaderInit(pTask, &pTask->file, iOff, pReadr, &nDummy); iOff = pReadr->iEof; } if( rc!=SQLITE_OK ){ vdbeMergeEngineFree(pNew); *ppOut = 0; } *piOffset = iOff; return rc; } /* ** Return the depth of a tree comprising nPMA PMAs, assuming a fanout of ** SORTER_MAX_MERGE_COUNT. The returned value does not include leaf nodes. ** ** i.e. ** ** nPMA<=16 -> TreeDepth() == 0 ** nPMA<=256 -> TreeDepth() == 1 ** nPMA<=65536 -> TreeDepth() == 2 */ static int vdbeSorterTreeDepth(int nPMA){ int nDepth = 0; i64 nDiv = SORTER_MAX_MERGE_COUNT; while( nDiv < (i64)nPMA ){ nDiv = nDiv * SORTER_MAX_MERGE_COUNT; nDepth++; } return nDepth; } /* ** pRoot is the root of an incremental merge-tree with depth nDepth (according ** to vdbeSorterTreeDepth()). pLeaf is the iSeq'th leaf to be added to the ** tree, counting from zero. This function adds pLeaf to the tree. ** ** If successful, SQLITE_OK is returned. If an error occurs, an SQLite error ** code is returned and pLeaf is freed. */ static int vdbeSorterAddToTree( SortSubtask *pTask, /* Task context */ int nDepth, /* Depth of tree according to TreeDepth() */ int iSeq, /* Sequence number of leaf within tree */ MergeEngine *pRoot, /* Root of tree */ MergeEngine *pLeaf /* Leaf to add to tree */ ){ int rc = SQLITE_OK; int nDiv = 1; int i; MergeEngine *p = pRoot; IncrMerger *pIncr; rc = vdbeIncrMergerNew(pTask, pLeaf, &pIncr); for(i=1; iaReadr[iIter]; if( pReadr->pIncr==0 ){ MergeEngine *pNew = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT); if( pNew==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ rc = vdbeIncrMergerNew(pTask, pNew, &pReadr->pIncr); } } if( rc==SQLITE_OK ){ p = pReadr->pIncr->pMerger; nDiv = nDiv / SORTER_MAX_MERGE_COUNT; } } if( rc==SQLITE_OK ){ p->aReadr[iSeq % SORTER_MAX_MERGE_COUNT].pIncr = pIncr; }else{ vdbeIncrFree(pIncr); } return rc; } /* ** This function is called as part of a SorterRewind() operation on a sorter ** that has already written two or more level-0 PMAs to one or more temp ** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that ** can be used to incrementally merge all PMAs on disk. ** ** If successful, SQLITE_OK is returned and *ppOut set to point to the ** MergeEngine object at the root of the tree before returning. Or, if an ** error occurs, an SQLite error code is returned and the final value ** of *ppOut is undefined. */ static int vdbeSorterMergeTreeBuild( VdbeSorter *pSorter, /* The VDBE cursor that implements the sort */ MergeEngine **ppOut /* Write the MergeEngine here */ ){ MergeEngine *pMain = 0; int rc = SQLITE_OK; int iTask; #if SQLITE_MAX_WORKER_THREADS>0 /* If the sorter uses more than one task, then create the top-level ** MergeEngine here. This MergeEngine will read data from exactly ** one PmaReader per sub-task. */ assert( pSorter->bUseThreads || pSorter->nTask==1 ); if( pSorter->nTask>1 ){ pMain = vdbeMergeEngineNew(pSorter->nTask); if( pMain==0 ) rc = SQLITE_NOMEM_BKPT; } #endif for(iTask=0; rc==SQLITE_OK && iTasknTask; iTask++){ SortSubtask *pTask = &pSorter->aTask[iTask]; assert( pTask->nPMA>0 || SQLITE_MAX_WORKER_THREADS>0 ); if( SQLITE_MAX_WORKER_THREADS==0 || pTask->nPMA ){ MergeEngine *pRoot = 0; /* Root node of tree for this task */ int nDepth = vdbeSorterTreeDepth(pTask->nPMA); i64 iReadOff = 0; if( pTask->nPMA<=SORTER_MAX_MERGE_COUNT ){ rc = vdbeMergeEngineLevel0(pTask, pTask->nPMA, &iReadOff, &pRoot); }else{ int i; int iSeq = 0; pRoot = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT); if( pRoot==0 ) rc = SQLITE_NOMEM_BKPT; for(i=0; inPMA && rc==SQLITE_OK; i += SORTER_MAX_MERGE_COUNT){ MergeEngine *pMerger = 0; /* New level-0 PMA merger */ int nReader; /* Number of level-0 PMAs to merge */ nReader = MIN(pTask->nPMA - i, SORTER_MAX_MERGE_COUNT); rc = vdbeMergeEngineLevel0(pTask, nReader, &iReadOff, &pMerger); if( rc==SQLITE_OK ){ rc = vdbeSorterAddToTree(pTask, nDepth, iSeq++, pRoot, pMerger); } } } if( rc==SQLITE_OK ){ #if SQLITE_MAX_WORKER_THREADS>0 if( pMain!=0 ){ rc = vdbeIncrMergerNew(pTask, pRoot, &pMain->aReadr[iTask].pIncr); }else #endif { assert( pMain==0 ); pMain = pRoot; } }else{ vdbeMergeEngineFree(pRoot); } } } if( rc!=SQLITE_OK ){ vdbeMergeEngineFree(pMain); pMain = 0; } *ppOut = pMain; return rc; } /* ** This function is called as part of an sqlite3VdbeSorterRewind() operation ** on a sorter that has written two or more PMAs to temporary files. It sets ** up either VdbeSorter.pMerger (for single threaded sorters) or pReader ** (for multi-threaded sorters) so that it can be used to iterate through ** all records stored in the sorter. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){ int rc; /* Return code */ SortSubtask *pTask0 = &pSorter->aTask[0]; MergeEngine *pMain = 0; #if SQLITE_MAX_WORKER_THREADS sqlite3 *db = pTask0->pSorter->db; int i; SorterCompare xCompare = vdbeSorterGetCompare(pSorter); for(i=0; inTask; i++){ pSorter->aTask[i].xCompare = xCompare; } #endif rc = vdbeSorterMergeTreeBuild(pSorter, &pMain); if( rc==SQLITE_OK ){ #if SQLITE_MAX_WORKER_THREADS assert( pSorter->bUseThreads==0 || pSorter->nTask>1 ); if( pSorter->bUseThreads ){ int iTask; PmaReader *pReadr = 0; SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1]; rc = vdbeSortAllocUnpacked(pLast); if( rc==SQLITE_OK ){ pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader)); pSorter->pReader = pReadr; if( pReadr==0 ) rc = SQLITE_NOMEM_BKPT; } if( rc==SQLITE_OK ){ rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr); if( rc==SQLITE_OK ){ vdbeIncrMergerSetThreads(pReadr->pIncr); for(iTask=0; iTask<(pSorter->nTask-1); iTask++){ IncrMerger *pIncr; if( (pIncr = pMain->aReadr[iTask].pIncr) ){ vdbeIncrMergerSetThreads(pIncr); assert( pIncr->pTask!=pLast ); } } for(iTask=0; rc==SQLITE_OK && iTasknTask; iTask++){ /* Check that: ** ** a) The incremental merge object is configured to use the ** right task, and ** b) If it is using task (nTask-1), it is configured to run ** in single-threaded mode. This is important, as the ** root merge (INCRINIT_ROOT) will be using the same task ** object. */ PmaReader *p = &pMain->aReadr[iTask]; assert( p->pIncr==0 || ( (p->pIncr->pTask==&pSorter->aTask[iTask]) /* a */ && (iTask!=pSorter->nTask-1 || p->pIncr->bUseThread==0) /* b */ )); rc = vdbePmaReaderIncrInit(p, INCRINIT_TASK); } } pMain = 0; } if( rc==SQLITE_OK ){ rc = vdbePmaReaderIncrMergeInit(pReadr, INCRINIT_ROOT); } }else #endif { rc = vdbeMergeEngineInit(pTask0, pMain, INCRINIT_NORMAL); pSorter->pMerger = pMain; pMain = 0; } } if( rc!=SQLITE_OK ){ vdbeMergeEngineFree(pMain); } return rc; } /* ** Once the sorter has been populated by calls to sqlite3VdbeSorterWrite, ** this function is called to prepare for iterating through the records ** in sorted order. */ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ VdbeSorter *pSorter; int rc = SQLITE_OK; /* Return code */ assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; assert( pSorter ); /* If no data has been written to disk, then do not do so now. Instead, ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly ** from the in-memory list. */ if( pSorter->bUsePMA==0 ){ if( pSorter->list.pList ){ *pbEof = 0; rc = vdbeSorterSort(&pSorter->aTask[0], &pSorter->list); }else{ *pbEof = 1; } return rc; } /* Write the current in-memory list to a PMA. When the VdbeSorterWrite() ** function flushes the contents of memory to disk, it immediately always ** creates a new list consisting of a single key immediately afterwards. ** So the list is never empty at this point. */ assert( pSorter->list.pList ); rc = vdbeSorterFlushPMA(pSorter); /* Join all threads */ rc = vdbeSorterJoinAll(pSorter, rc); vdbeSorterRewindDebug("rewind"); /* Assuming no errors have occurred, set up a merger structure to ** incrementally read and merge all remaining PMAs. */ assert( pSorter->pReader==0 ); if( rc==SQLITE_OK ){ rc = vdbeSorterSetupMerge(pSorter); *pbEof = 0; } vdbeSorterRewindDebug("rewinddone"); return rc; } /* ** Advance to the next element in the sorter. Return value: ** ** SQLITE_OK success ** SQLITE_DONE end of data ** otherwise some kind of error. */ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){ VdbeSorter *pSorter; int rc; /* Return code */ assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) ); if( pSorter->bUsePMA ){ assert( pSorter->pReader==0 || pSorter->pMerger==0 ); assert( pSorter->bUseThreads==0 || pSorter->pReader ); assert( pSorter->bUseThreads==1 || pSorter->pMerger ); #if SQLITE_MAX_WORKER_THREADS>0 if( pSorter->bUseThreads ){ rc = vdbePmaReaderNext(pSorter->pReader); if( rc==SQLITE_OK && pSorter->pReader->pFd==0 ) rc = SQLITE_DONE; }else #endif /*if( !pSorter->bUseThreads )*/ { int res = 0; assert( pSorter->pMerger!=0 ); assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) ); rc = vdbeMergeEngineStep(pSorter->pMerger, &res); if( rc==SQLITE_OK && res ) rc = SQLITE_DONE; } }else{ SorterRecord *pFree = pSorter->list.pList; pSorter->list.pList = pFree->u.pNext; pFree->u.pNext = 0; if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree); rc = pSorter->list.pList ? SQLITE_OK : SQLITE_DONE; } return rc; } /* ** Return a pointer to a buffer owned by the sorter that contains the ** current key. */ static void *vdbeSorterRowkey( const VdbeSorter *pSorter, /* Sorter object */ int *pnKey /* OUT: Size of current key in bytes */ ){ void *pKey; if( pSorter->bUsePMA ){ PmaReader *pReader; #if SQLITE_MAX_WORKER_THREADS>0 if( pSorter->bUseThreads ){ pReader = pSorter->pReader; }else #endif /*if( !pSorter->bUseThreads )*/{ pReader = &pSorter->pMerger->aReadr[pSorter->pMerger->aTree[1]]; } *pnKey = pReader->nKey; pKey = pReader->aKey; }else{ *pnKey = pSorter->list.pList->nVal; pKey = SRVAL(pSorter->list.pList); } return pKey; } /* ** Copy the current sorter key into the memory cell pOut. */ SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ VdbeSorter *pSorter; void *pKey; int nKey; /* Sorter key to copy into pOut */ assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; pKey = vdbeSorterRowkey(pSorter, &nKey); if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){ return SQLITE_NOMEM_BKPT; } pOut->n = nKey; MemSetTypeFlag(pOut, MEM_Blob); memcpy(pOut->z, pKey, nKey); return SQLITE_OK; } /* ** Compare the key in memory cell pVal with the key that the sorter cursor ** passed as the first argument currently points to. For the purposes of ** the comparison, ignore the rowid field at the end of each record. ** ** If the sorter cursor key contains any NULL values, consider it to be ** less than pVal. Even if pVal also contains NULL values. ** ** If an error occurs, return an SQLite error code (i.e. SQLITE_NOMEM). ** Otherwise, set *pRes to a negative, zero or positive value if the ** key in pVal is smaller than, equal to or larger than the current sorter ** key. ** ** This routine forms the core of the OP_SorterCompare opcode, which in ** turn is used to verify uniqueness when constructing a UNIQUE INDEX. */ SQLITE_PRIVATE int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ int nKeyCol, /* Compare this many columns */ int *pRes /* OUT: Result of comparison */ ){ VdbeSorter *pSorter; UnpackedRecord *r2; KeyInfo *pKeyInfo; int i; void *pKey; int nKey; /* Sorter key to compare pVal with */ assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; r2 = pSorter->pUnpacked; pKeyInfo = pCsr->pKeyInfo; if( r2==0 ){ r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); if( r2==0 ) return SQLITE_NOMEM_BKPT; r2->nField = nKeyCol; } assert( r2->nField==nKeyCol ); pKey = vdbeSorterRowkey(pSorter, &nKey); sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2); for(i=0; iaMem[i].flags & MEM_Null ){ *pRes = -1; return SQLITE_OK; } } *pRes = sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2); return SQLITE_OK; } /************** End of vdbesort.c ********************************************/ /************** Begin file vdbevtab.c ****************************************/ /* ** 2020-03-23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file implements virtual-tables for examining the bytecode content ** of a prepared statement. */ /* #include "sqliteInt.h" */ #if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE) /* #include "vdbeInt.h" */ /* An instance of the bytecode() table-valued function. */ typedef struct bytecodevtab bytecodevtab; struct bytecodevtab { sqlite3_vtab base; /* Base class - must be first */ sqlite3 *db; /* Database connection */ int bTablesUsed; /* 2 for tables_used(). 0 for bytecode(). */ }; /* A cursor for scanning through the bytecode */ typedef struct bytecodevtab_cursor bytecodevtab_cursor; struct bytecodevtab_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ sqlite3_stmt *pStmt; /* The statement whose bytecode is displayed */ int iRowid; /* The rowid of the output table */ int iAddr; /* Address */ int needFinalize; /* Cursors owns pStmt and must finalize it */ int showSubprograms; /* Provide a listing of subprograms */ Op *aOp; /* Operand array */ char *zP4; /* Rendered P4 value */ const char *zType; /* tables_used.type */ const char *zSchema; /* tables_used.schema */ const char *zName; /* tables_used.name */ Mem sub; /* Subprograms */ }; /* ** Create a new bytecode() table-valued function. */ static int bytecodevtabConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ bytecodevtab *pNew; int rc; int isTabUsed = pAux!=0; const char *azSchema[2] = { /* bytecode() schema */ "CREATE TABLE x(" "addr INT," "opcode TEXT," "p1 INT," "p2 INT," "p3 INT," "p4 TEXT," "p5 INT," "comment TEXT," "subprog TEXT," "nexec INT," "ncycle INT," "stmt HIDDEN" ");", /* Tables_used() schema */ "CREATE TABLE x(" "type TEXT," "schema TEXT," "name TEXT," "wr INT," "subprog TEXT," "stmt HIDDEN" ");" }; (void)argc; (void)argv; (void)pzErr; rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]); if( rc==SQLITE_OK ){ pNew = sqlite3_malloc( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); pNew->db = db; pNew->bTablesUsed = isTabUsed*2; } return rc; } /* ** This method is the destructor for bytecodevtab objects. */ static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){ bytecodevtab *p = (bytecodevtab*)pVtab; sqlite3_free(p); return SQLITE_OK; } /* ** Constructor for a new bytecodevtab_cursor object. */ static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ bytecodevtab *pVTab = (bytecodevtab*)p; bytecodevtab_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1); *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Clear all internal content from a bytecodevtab cursor. */ static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){ sqlite3_free(pCur->zP4); pCur->zP4 = 0; sqlite3VdbeMemRelease(&pCur->sub); sqlite3VdbeMemSetNull(&pCur->sub); if( pCur->needFinalize ){ sqlite3_finalize(pCur->pStmt); } pCur->pStmt = 0; pCur->needFinalize = 0; pCur->zType = 0; pCur->zSchema = 0; pCur->zName = 0; } /* ** Destructor for a bytecodevtab_cursor. */ static int bytecodevtabClose(sqlite3_vtab_cursor *cur){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; bytecodevtabCursorClear(pCur); sqlite3_free(pCur); return SQLITE_OK; } /* ** Advance a bytecodevtab_cursor to its next row of output. */ static int bytecodevtabNext(sqlite3_vtab_cursor *cur){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; bytecodevtab *pTab = (bytecodevtab*)cur->pVtab; int rc; if( pCur->zP4 ){ sqlite3_free(pCur->zP4); pCur->zP4 = 0; } if( pCur->zName ){ pCur->zName = 0; pCur->zType = 0; pCur->zSchema = 0; } rc = sqlite3VdbeNextOpcode( (Vdbe*)pCur->pStmt, pCur->showSubprograms ? &pCur->sub : 0, pTab->bTablesUsed, &pCur->iRowid, &pCur->iAddr, &pCur->aOp); if( rc!=SQLITE_OK ){ sqlite3VdbeMemSetNull(&pCur->sub); pCur->aOp = 0; } return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int bytecodevtabEof(sqlite3_vtab_cursor *cur){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; return pCur->aOp==0; } /* ** Return values of columns for the row at which the bytecodevtab_cursor ** is currently pointing. */ static int bytecodevtabColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab; Op *pOp = pCur->aOp + pCur->iAddr; if( pVTab->bTablesUsed ){ if( i==4 ){ i = 8; }else{ if( i<=2 && pCur->zType==0 ){ Schema *pSchema; HashElem *k; int iDb = pOp->p3; Pgno iRoot = (Pgno)pOp->p2; sqlite3 *db = pVTab->db; pSchema = db->aDb[iDb].pSchema; pCur->zSchema = db->aDb[iDb].zDbSName; for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ Table *pTab = (Table*)sqliteHashData(k); if( !IsVirtual(pTab) && pTab->tnum==iRoot ){ pCur->zName = pTab->zName; pCur->zType = "table"; break; } } if( pCur->zName==0 ){ for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){ Index *pIdx = (Index*)sqliteHashData(k); if( pIdx->tnum==iRoot ){ pCur->zName = pIdx->zName; pCur->zType = "index"; } } } } i += 20; } } switch( i ){ case 0: /* addr */ sqlite3_result_int(ctx, pCur->iAddr); break; case 1: /* opcode */ sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode), -1, SQLITE_STATIC); break; case 2: /* p1 */ sqlite3_result_int(ctx, pOp->p1); break; case 3: /* p2 */ sqlite3_result_int(ctx, pOp->p2); break; case 4: /* p3 */ sqlite3_result_int(ctx, pOp->p3); break; case 5: /* p4 */ case 7: /* comment */ if( pCur->zP4==0 ){ pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp); } if( i==5 ){ sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC); }else{ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4); sqlite3_result_text(ctx, zCom, -1, sqlite3_free); #endif } break; case 6: /* p5 */ sqlite3_result_int(ctx, pOp->p5); break; case 8: { /* subprog */ Op *aOp = pCur->aOp; assert( aOp[0].opcode==OP_Init ); assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 ); if( pCur->iRowid==pCur->iAddr+1 ){ break; /* Result is NULL for the main program */ }else if( aOp[0].p4.z!=0 ){ sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC); }else{ sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC); } break; } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS case 9: /* nexec */ sqlite3_result_int(ctx, pOp->nExec); break; case 10: /* ncycle */ sqlite3_result_int(ctx, pOp->nCycle); break; #else case 9: /* nexec */ case 10: /* ncycle */ sqlite3_result_int(ctx, 0); break; #endif case 20: /* tables_used.type */ sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC); break; case 21: /* tables_used.schema */ sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC); break; case 22: /* tables_used.name */ sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC); break; case 23: /* tables_used.wr */ sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite); break; } return SQLITE_OK; } /* ** Return the rowid for the current row. In this implementation, the ** rowid is the same as the output value. */ static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; *pRowid = pCur->iRowid; return SQLITE_OK; } /* ** Initialize a cursor. ** ** idxNum==0 means show all subprograms ** idxNum==1 means show only the main bytecode and omit subprograms. */ static int bytecodevtabFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor; bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab; int rc = SQLITE_OK; (void)idxStr; bytecodevtabCursorClear(pCur); pCur->iRowid = 0; pCur->iAddr = 0; pCur->showSubprograms = idxNum==0; assert( argc==1 ); if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){ const char *zSql = (const char*)sqlite3_value_text(argv[0]); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0); pCur->needFinalize = 1; } }else{ pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer"); } if( pCur->pStmt==0 ){ pVTab->base.zErrMsg = sqlite3_mprintf( "argument to %s() is not a valid SQL statement", pVTab->bTablesUsed ? "tables_used" : "bytecode" ); rc = SQLITE_ERROR; }else{ bytecodevtabNext(pVtabCursor); } return rc; } /* ** We must have a single stmt=? constraint that will be passed through ** into the xFilter method. If there is no valid stmt=? constraint, ** then return an SQLITE_CONSTRAINT error. */ static int bytecodevtabBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; int rc = SQLITE_CONSTRAINT; struct sqlite3_index_constraint *p; bytecodevtab *pVTab = (bytecodevtab*)tab; int iBaseCol = pVTab->bTablesUsed ? 4 : 10; pIdxInfo->estimatedCost = (double)100; pIdxInfo->estimatedRows = 100; pIdxInfo->idxNum = 0; for(i=0, p=pIdxInfo->aConstraint; inConstraint; i++, p++){ if( p->usable==0 ) continue; if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){ rc = SQLITE_OK; pIdxInfo->aConstraintUsage[i].omit = 1; pIdxInfo->aConstraintUsage[i].argvIndex = 1; } if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){ pIdxInfo->aConstraintUsage[i].omit = 1; pIdxInfo->idxNum = 1; } } return rc; } /* ** This following structure defines all the methods for the ** virtual table. */ static sqlite3_module bytecodevtabModule = { /* iVersion */ 0, /* xCreate */ 0, /* xConnect */ bytecodevtabConnect, /* xBestIndex */ bytecodevtabBestIndex, /* xDisconnect */ bytecodevtabDisconnect, /* xDestroy */ 0, /* xOpen */ bytecodevtabOpen, /* xClose */ bytecodevtabClose, /* xFilter */ bytecodevtabFilter, /* xNext */ bytecodevtabNext, /* xEof */ bytecodevtabEof, /* xColumn */ bytecodevtabColumn, /* xRowid */ bytecodevtabRowid, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ 0, /* xIntegrity */ 0 }; SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ int rc; rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db); } return rc; } #elif defined(SQLITE_ENABLE_BYTECODE_VTAB) SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; } #endif /* SQLITE_ENABLE_BYTECODE_VTAB */ /************** End of vdbevtab.c ********************************************/ /************** Begin file memjournal.c **************************************/ /* ** 2008 October 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code use to implement an in-memory rollback journal. ** The in-memory rollback journal is used to journal transactions for ** ":memory:" databases and when the journal_mode=MEMORY pragma is used. ** ** Update: The in-memory journal is also used to temporarily cache ** smaller journals that are not critical for power-loss recovery. ** For example, statement journals that are not too big will be held ** entirely in memory, thus reducing the number of file I/O calls, and ** more importantly, reducing temporary file creation events. If these ** journals become too large for memory, they are spilled to disk. But ** in the common case, they are usually small and no file I/O needs to ** occur. */ /* #include "sqliteInt.h" */ /* Forward references to internal structures */ typedef struct MemJournal MemJournal; typedef struct FilePoint FilePoint; typedef struct FileChunk FileChunk; /* ** The rollback journal is composed of a linked list of these structures. ** ** The zChunk array is always at least 8 bytes in size - usually much more. ** Its actual size is stored in the MemJournal.nChunkSize variable. */ struct FileChunk { FileChunk *pNext; /* Next chunk in the journal */ u8 zChunk[8]; /* Content of this chunk */ }; /* ** By default, allocate this many bytes of memory for each FileChunk object. */ #define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024 /* ** For chunk size nChunkSize, return the number of bytes that should ** be allocated for each FileChunk structure. */ #define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8)) /* ** An instance of this object serves as a cursor into the rollback journal. ** The cursor can be either for reading or writing. */ struct FilePoint { sqlite3_int64 iOffset; /* Offset from the beginning of the file */ FileChunk *pChunk; /* Specific chunk into which cursor points */ }; /* ** This structure is a subclass of sqlite3_file. Each open memory-journal ** is an instance of this class. */ struct MemJournal { const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */ int nChunkSize; /* In-memory chunk-size */ int nSpill; /* Bytes of data before flushing */ FileChunk *pFirst; /* Head of in-memory chunk-list */ FilePoint endpoint; /* Pointer to the end of the file */ FilePoint readpoint; /* Pointer to the end of the last xRead() */ int flags; /* xOpen flags */ sqlite3_vfs *pVfs; /* The "real" underlying VFS */ const char *zJournal; /* Name of the journal file */ }; /* ** Read data from the in-memory journal file. This is the implementation ** of the sqlite3_vfs.xRead method. */ static int memjrnlRead( sqlite3_file *pJfd, /* The journal file from which to read */ void *zBuf, /* Put the results here */ int iAmt, /* Number of bytes to read */ sqlite_int64 iOfst /* Begin reading at this offset */ ){ MemJournal *p = (MemJournal *)pJfd; u8 *zOut = zBuf; int nRead = iAmt; int iChunkOffset; FileChunk *pChunk; if( (iAmt+iOfst)>p->endpoint.iOffset ){ return SQLITE_IOERR_SHORT_READ; } assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 ); if( p->readpoint.iOffset!=iOfst || iOfst==0 ){ sqlite3_int64 iOff = 0; for(pChunk=p->pFirst; ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst; pChunk=pChunk->pNext ){ iOff += p->nChunkSize; } }else{ pChunk = p->readpoint.pChunk; assert( pChunk!=0 ); } iChunkOffset = (int)(iOfst%p->nChunkSize); do { int iSpace = p->nChunkSize - iChunkOffset; int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset)); memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy); zOut += nCopy; nRead -= iSpace; iChunkOffset = 0; } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 ); p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0; p->readpoint.pChunk = pChunk; return SQLITE_OK; } /* ** Free the list of FileChunk structures headed at MemJournal.pFirst. */ static void memjrnlFreeChunks(FileChunk *pFirst){ FileChunk *pIter; FileChunk *pNext; for(pIter=pFirst; pIter; pIter=pNext){ pNext = pIter->pNext; sqlite3_free(pIter); } } /* ** Flush the contents of memory to a real file on disk. */ static int memjrnlCreateFile(MemJournal *p){ int rc; sqlite3_file *pReal = (sqlite3_file*)p; MemJournal copy = *p; memset(p, 0, sizeof(MemJournal)); rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0); if( rc==SQLITE_OK ){ int nChunk = copy.nChunkSize; i64 iOff = 0; FileChunk *pIter; for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){ if( iOff + nChunk > copy.endpoint.iOffset ){ nChunk = copy.endpoint.iOffset - iOff; } rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff); if( rc ) break; iOff += nChunk; } if( rc==SQLITE_OK ){ /* No error has occurred. Free the in-memory buffers. */ memjrnlFreeChunks(copy.pFirst); } } if( rc!=SQLITE_OK ){ /* If an error occurred while creating or writing to the file, restore ** the original before returning. This way, SQLite uses the in-memory ** journal data to roll back changes made to the internal page-cache ** before this function was called. */ sqlite3OsClose(pReal); *p = copy; } return rc; } /* Forward reference */ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size); /* ** Write data to the file. */ static int memjrnlWrite( sqlite3_file *pJfd, /* The journal file into which to write */ const void *zBuf, /* Take data to be written from here */ int iAmt, /* Number of bytes to write */ sqlite_int64 iOfst /* Begin writing at this offset into the file */ ){ MemJournal *p = (MemJournal *)pJfd; int nWrite = iAmt; u8 *zWrite = (u8 *)zBuf; /* If the file should be created now, create it and write the new data ** into the file on disk. */ if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){ int rc = memjrnlCreateFile(p); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst); } return rc; } /* If the contents of this write should be stored in memory */ else{ /* An in-memory journal file should only ever be appended to. Random ** access writes are not required. The only exception to this is when ** the in-memory journal is being used by a connection using the ** atomic-write optimization. In this case the first 28 bytes of the ** journal file may be written as part of committing the transaction. */ assert( iOfst<=p->endpoint.iOffset ); if( iOfst>0 && iOfst!=p->endpoint.iOffset ){ memjrnlTruncate(pJfd, iOfst); } if( iOfst==0 && p->pFirst ){ assert( p->nChunkSize>iAmt ); memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt); }else{ while( nWrite>0 ){ FileChunk *pChunk = p->endpoint.pChunk; int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize); int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset); assert( pChunk!=0 || iChunkOffset==0 ); if( iChunkOffset==0 ){ /* New chunk is required to extend the file. */ FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize)); if( !pNew ){ return SQLITE_IOERR_NOMEM_BKPT; } pNew->pNext = 0; if( pChunk ){ assert( p->pFirst ); pChunk->pNext = pNew; }else{ assert( !p->pFirst ); p->pFirst = pNew; } pChunk = p->endpoint.pChunk = pNew; } assert( pChunk!=0 ); memcpy((u8*)pChunk->zChunk + iChunkOffset, zWrite, iSpace); zWrite += iSpace; nWrite -= iSpace; p->endpoint.iOffset += iSpace; } } } return SQLITE_OK; } /* ** Truncate the in-memory file. */ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ MemJournal *p = (MemJournal *)pJfd; assert( p->endpoint.pChunk==0 || p->endpoint.pChunk->pNext==0 ); if( sizeendpoint.iOffset ){ FileChunk *pIter = 0; if( size==0 ){ memjrnlFreeChunks(p->pFirst); p->pFirst = 0; }else{ i64 iOff = p->nChunkSize; for(pIter=p->pFirst; ALWAYS(pIter) && iOffpNext){ iOff += p->nChunkSize; } if( ALWAYS(pIter) ){ memjrnlFreeChunks(pIter->pNext); pIter->pNext = 0; } } p->endpoint.pChunk = pIter; p->endpoint.iOffset = size; p->readpoint.pChunk = 0; p->readpoint.iOffset = 0; } return SQLITE_OK; } /* ** Close the file. */ static int memjrnlClose(sqlite3_file *pJfd){ MemJournal *p = (MemJournal *)pJfd; memjrnlFreeChunks(p->pFirst); return SQLITE_OK; } /* ** Sync the file. ** ** If the real file has been created, call its xSync method. Otherwise, ** syncing an in-memory journal is a no-op. */ static int memjrnlSync(sqlite3_file *pJfd, int flags){ UNUSED_PARAMETER2(pJfd, flags); return SQLITE_OK; } /* ** Query the size of the file in bytes. */ static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){ MemJournal *p = (MemJournal *)pJfd; *pSize = (sqlite_int64) p->endpoint.iOffset; return SQLITE_OK; } /* ** Table of methods for MemJournal sqlite3_file object. */ static const struct sqlite3_io_methods MemJournalMethods = { 1, /* iVersion */ memjrnlClose, /* xClose */ memjrnlRead, /* xRead */ memjrnlWrite, /* xWrite */ memjrnlTruncate, /* xTruncate */ memjrnlSync, /* xSync */ memjrnlFileSize, /* xFileSize */ 0, /* xLock */ 0, /* xUnlock */ 0, /* xCheckReservedLock */ 0, /* xFileControl */ 0, /* xSectorSize */ 0, /* xDeviceCharacteristics */ 0, /* xShmMap */ 0, /* xShmLock */ 0, /* xShmBarrier */ 0, /* xShmUnmap */ 0, /* xFetch */ 0 /* xUnfetch */ }; /* ** Open a journal file. ** ** The behaviour of the journal file depends on the value of parameter ** nSpill. If nSpill is 0, then the journal file is always create and ** accessed using the underlying VFS. If nSpill is less than zero, then ** all content is always stored in main-memory. Finally, if nSpill is a ** positive value, then the journal file is initially created in-memory ** but may be flushed to disk later on. In this case the journal file is ** flushed to disk either when it grows larger than nSpill bytes in size, ** or when sqlite3JournalCreate() is called. */ SQLITE_PRIVATE int sqlite3JournalOpen( sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */ const char *zName, /* Name of the journal file */ sqlite3_file *pJfd, /* Preallocated, blank file handle */ int flags, /* Opening flags */ int nSpill /* Bytes buffered before opening the file */ ){ MemJournal *p = (MemJournal*)pJfd; assert( zName || nSpill<0 || (flags & SQLITE_OPEN_EXCLUSIVE) ); /* Zero the file-handle object. If nSpill was passed zero, initialize ** it using the sqlite3OsOpen() function of the underlying VFS. In this ** case none of the code in this module is executed as a result of calls ** made on the journal file-handle. */ memset(p, 0, sizeof(MemJournal)); if( nSpill==0 ){ return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0); } if( nSpill>0 ){ p->nChunkSize = nSpill; }else{ p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk); assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) ); } pJfd->pMethods = (const sqlite3_io_methods*)&MemJournalMethods; p->nSpill = nSpill; p->flags = flags; p->zJournal = zName; p->pVfs = pVfs; return SQLITE_OK; } /* ** Open an in-memory journal file. */ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){ sqlite3JournalOpen(0, 0, pJfd, 0, -1); } #if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) /* ** If the argument p points to a MemJournal structure that is not an ** in-memory-only journal file (i.e. is one that was opened with a +ve ** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying ** file has not yet been created, create it now. */ SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){ int rc = SQLITE_OK; MemJournal *p = (MemJournal*)pJfd; if( pJfd->pMethods==&MemJournalMethods && ( #ifdef SQLITE_ENABLE_ATOMIC_WRITE p->nSpill>0 #else /* While this appears to not be possible without ATOMIC_WRITE, the ** paths are complex, so it seems prudent to leave the test in as ** a NEVER(), in case our analysis is subtly flawed. */ NEVER(p->nSpill>0) #endif #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE || (p->flags & SQLITE_OPEN_MAIN_JOURNAL) #endif )){ rc = memjrnlCreateFile(p); } return rc; } #endif /* ** The file-handle passed as the only argument is open on a journal file. ** Return true if this "journal file" is currently stored in heap memory, ** or false otherwise. */ SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){ return p->pMethods==&MemJournalMethods; } /* ** Return the number of bytes required to store a JournalFile that uses vfs ** pVfs to create the underlying on-disk files. */ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){ return MAX(pVfs->szOsFile, (int)sizeof(MemJournal)); } /************** End of memjournal.c ******************************************/ /************** Begin file walker.c ******************************************/ /* ** 2008 August 16 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for walking the parser tree for ** an SQL statement. */ /* #include "sqliteInt.h" */ /* #include */ /* #include */ #if !defined(SQLITE_OMIT_WINDOWFUNC) /* ** Walk all expressions linked into the list of Window objects passed ** as the second argument. */ static int walkWindowList(Walker *pWalker, Window *pList, int bOneOnly){ Window *pWin; for(pWin=pList; pWin; pWin=pWin->pNextWin){ int rc; rc = sqlite3WalkExprList(pWalker, pWin->pOrderBy); if( rc ) return WRC_Abort; rc = sqlite3WalkExprList(pWalker, pWin->pPartition); if( rc ) return WRC_Abort; rc = sqlite3WalkExpr(pWalker, pWin->pFilter); if( rc ) return WRC_Abort; rc = sqlite3WalkExpr(pWalker, pWin->pStart); if( rc ) return WRC_Abort; rc = sqlite3WalkExpr(pWalker, pWin->pEnd); if( rc ) return WRC_Abort; if( bOneOnly ) break; } return WRC_Continue; } #endif /* ** Walk an expression tree. Invoke the callback once for each node ** of the expression, while descending. (In other words, the callback ** is invoked before visiting children.) ** ** The return value from the callback should be one of the WRC_* ** constants to specify how to proceed with the walk. ** ** WRC_Continue Continue descending down the tree. ** ** WRC_Prune Do not descend into child nodes, but allow ** the walk to continue with sibling nodes. ** ** WRC_Abort Do no more callbacks. Unwind the stack and ** return from the top-level walk call. ** ** The return value from this routine is WRC_Abort to abandon the tree walk ** and WRC_Continue to continue. */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3WalkExprNN(Walker *pWalker, Expr *pExpr){ int rc; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); while(1){ rc = pWalker->xExprCallback(pWalker, pExpr); if( rc ) return rc & WRC_Abort; if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ assert( pExpr->x.pList==0 || pExpr->pRight==0 ); if( pExpr->pLeft && sqlite3WalkExprNN(pWalker, pExpr->pLeft) ){ return WRC_Abort; } if( pExpr->pRight ){ assert( !ExprHasProperty(pExpr, EP_WinFunc) ); pExpr = pExpr->pRight; continue; }else if( ExprUseXSelect(pExpr) ){ assert( !ExprHasProperty(pExpr, EP_WinFunc) ); if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; }else{ if( pExpr->x.pList ){ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ if( walkWindowList(pWalker, pExpr->y.pWin, 1) ) return WRC_Abort; } #endif } } break; } return WRC_Continue; } SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ return pExpr ? sqlite3WalkExprNN(pWalker,pExpr) : WRC_Continue; } /* ** Call sqlite3WalkExpr() for every expression in list p or until ** an abort request is seen. */ SQLITE_PRIVATE int sqlite3WalkExprList(Walker *pWalker, ExprList *p){ int i; struct ExprList_item *pItem; if( p ){ for(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){ if( sqlite3WalkExpr(pWalker, pItem->pExpr) ) return WRC_Abort; } } return WRC_Continue; } /* ** This is a no-op callback for Walker->xSelectCallback2. If this ** callback is set, then the Select->pWinDefn list is traversed. */ SQLITE_PRIVATE void sqlite3WalkWinDefnDummyCallback(Walker *pWalker, Select *p){ UNUSED_PARAMETER(pWalker); UNUSED_PARAMETER(p); /* No-op */ } /* ** Walk all expressions associated with SELECT statement p. Do ** not invoke the SELECT callback on p, but do (of course) invoke ** any expr callbacks and SELECT callbacks that come from subqueries. ** Return WRC_Abort or WRC_Continue. */ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){ if( sqlite3WalkExprList(pWalker, p->pEList) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pWhere) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, p->pGroupBy) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort; #if !defined(SQLITE_OMIT_WINDOWFUNC) if( p->pWinDefn ){ Parse *pParse; if( pWalker->xSelectCallback2==sqlite3WalkWinDefnDummyCallback || ((pParse = pWalker->pParse)!=0 && IN_RENAME_OBJECT) #ifndef SQLITE_OMIT_CTE || pWalker->xSelectCallback2==sqlite3SelectPopWith #endif ){ /* The following may return WRC_Abort if there are unresolvable ** symbols (e.g. a table that does not exist) in a window definition. */ int rc = walkWindowList(pWalker, p->pWinDefn, 0); return rc; } } #endif return WRC_Continue; } /* ** Walk the parse trees associated with all subqueries in the ** FROM clause of SELECT statement p. Do not invoke the select ** callback on p, but do invoke it on each FROM clause subquery ** and on any subqueries further down in the tree. Return ** WRC_Abort or WRC_Continue; */ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ SrcList *pSrc; int i; SrcItem *pItem; pSrc = p->pSrc; if( ALWAYS(pSrc) ){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){ return WRC_Abort; } if( pItem->fg.isTabFunc && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg) ){ return WRC_Abort; } } } return WRC_Continue; } /* ** Call sqlite3WalkExpr() for every expression in Select statement p. ** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and ** on the compound select chain, p->pPrior. ** ** If it is not NULL, the xSelectCallback() callback is invoked before ** the walk of the expressions and FROM clause. The xSelectCallback2() ** method is invoked following the walk of the expressions and FROM clause, ** but only if both xSelectCallback and xSelectCallback2 are both non-NULL ** and if the expressions and FROM clause both return WRC_Continue; ** ** Return WRC_Continue under normal conditions. Return WRC_Abort if ** there is an abort request. ** ** If the Walker does not have an xSelectCallback() then this routine ** is a no-op returning WRC_Continue. */ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){ int rc; if( p==0 ) return WRC_Continue; if( pWalker->xSelectCallback==0 ) return WRC_Continue; do{ rc = pWalker->xSelectCallback(pWalker, p); if( rc ) return rc & WRC_Abort; if( sqlite3WalkSelectExpr(pWalker, p) || sqlite3WalkSelectFrom(pWalker, p) ){ return WRC_Abort; } if( pWalker->xSelectCallback2 ){ pWalker->xSelectCallback2(pWalker, p); } p = p->pPrior; }while( p!=0 ); return WRC_Continue; } /* Increase the walkerDepth when entering a subquery, and ** decrease when leaving the subquery. */ SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){ UNUSED_PARAMETER(pSelect); pWalker->walkerDepth++; return WRC_Continue; } SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker *pWalker, Select *pSelect){ UNUSED_PARAMETER(pSelect); pWalker->walkerDepth--; } /* ** No-op routine for the parse-tree walker. ** ** When this routine is the Walker.xExprCallback then expression trees ** are walked without any actions being taken at each node. Presumably, ** when this routine is used for Walker.xExprCallback then ** Walker.xSelectCallback is set to do something useful for every ** subquery in the parser tree. */ SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); return WRC_Continue; } /* ** No-op routine for the parse-tree walker for SELECT statements. ** subquery in the parser tree. */ SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); return WRC_Continue; } /************** End of walker.c **********************************************/ /************** Begin file resolve.c *****************************************/ /* ** 2008 August 18 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains routines used for walking the parser tree and ** resolve all identifiers by associating them with a particular ** table and column. */ /* #include "sqliteInt.h" */ /* ** Magic table number to mean the EXCLUDED table in an UPSERT statement. */ #define EXCLUDED_TABLE_NUMBER 2 /* ** Walk the expression tree pExpr and increase the aggregate function ** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node. ** This needs to occur when copying a TK_AGG_FUNCTION node from an ** outer query into an inner subquery. ** ** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..) ** is a helper function - a callback for the tree walker. ** ** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c */ static int incrAggDepth(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n; return WRC_Continue; } static void incrAggFunctionDepth(Expr *pExpr, int N){ if( N>0 ){ Walker w; memset(&w, 0, sizeof(w)); w.xExprCallback = incrAggDepth; w.u.n = N; sqlite3WalkExpr(&w, pExpr); } } /* ** Turn the pExpr expression into an alias for the iCol-th column of the ** result set in pEList. ** ** If the reference is followed by a COLLATE operator, then make sure ** the COLLATE operator is preserved. For example: ** ** SELECT a+b, c+d FROM t1 ORDER BY 1 COLLATE nocase; ** ** Should be transformed into: ** ** SELECT a+b, c+d FROM t1 ORDER BY (a+b) COLLATE nocase; ** ** The nSubquery parameter specifies how many levels of subquery the ** alias is removed from the original expression. The usual value is ** zero but it might be more if the alias is contained within a subquery ** of the original expression. The Expr.op2 field of TK_AGG_FUNCTION ** structures must be increased by the nSubquery amount. */ static void resolveAlias( Parse *pParse, /* Parsing context */ ExprList *pEList, /* A result set */ int iCol, /* A column in the result set. 0..pEList->nExpr-1 */ Expr *pExpr, /* Transform this into an alias to the result set */ int nSubquery /* Number of subqueries that the label is moving */ ){ Expr *pOrig; /* The iCol-th column of the result set */ Expr *pDup; /* Copy of pOrig */ sqlite3 *db; /* The database connection */ assert( iCol>=0 && iColnExpr ); pOrig = pEList->a[iCol].pExpr; assert( pOrig!=0 ); db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); pDup = 0; }else{ Expr temp; incrAggFunctionDepth(pDup, nSubquery); if( pExpr->op==TK_COLLATE ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); } memcpy(&temp, pDup, sizeof(Expr)); memcpy(pDup, pExpr, sizeof(Expr)); memcpy(pExpr, &temp, sizeof(Expr)); if( ExprHasProperty(pExpr, EP_WinFunc) ){ if( ALWAYS(pExpr->y.pWin!=0) ){ pExpr->y.pWin->pOwner = pExpr; } } sqlite3ExprDeferredDelete(pParse, pDup); } } /* ** Subqueries store the original database, table and column names for their ** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN", ** and mark the expression-list item by setting ExprList.a[].fg.eEName ** to ENAME_TAB. ** ** Check to see if the zSpan/eEName of the expression-list item passed to this ** routine matches the zDb, zTab, and zCol. If any of zDb, zTab, and zCol are ** NULL then those fields will match anything. Return true if there is a match, ** or false otherwise. ** ** SF_NestedFrom subqueries also store an entry for the implicit rowid (or ** _rowid_, or oid) column by setting ExprList.a[].fg.eEName to ENAME_ROWID, ** and setting zSpan to "DATABASE.TABLE.". This type of pItem ** argument matches if zCol is a rowid alias. If it is not NULL, (*pbRowid) ** is set to 1 if there is this kind of match. */ SQLITE_PRIVATE int sqlite3MatchEName( const struct ExprList_item *pItem, const char *zCol, const char *zTab, const char *zDb, int *pbRowid ){ int n; const char *zSpan; int eEName = pItem->fg.eEName; if( eEName!=ENAME_TAB && (eEName!=ENAME_ROWID || NEVER(pbRowid==0)) ){ return 0; } assert( pbRowid==0 || *pbRowid==0 ); zSpan = pItem->zEName; for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){ return 0; } zSpan += n+1; for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){ return 0; } zSpan += n+1; if( zCol ){ if( eEName==ENAME_TAB && sqlite3StrICmp(zSpan, zCol)!=0 ) return 0; if( eEName==ENAME_ROWID && sqlite3IsRowid(zCol)==0 ) return 0; } if( eEName==ENAME_ROWID ) *pbRowid = 1; return 1; } /* ** Return TRUE if the double-quoted string mis-feature should be supported. */ static int areDoubleQuotedStringsEnabled(sqlite3 *db, NameContext *pTopNC){ if( db->init.busy ) return 1; /* Always support for legacy schemas */ if( pTopNC->ncFlags & NC_IsDDL ){ /* Currently parsing a DDL statement */ if( sqlite3WritableSchema(db) && (db->flags & SQLITE_DqsDML)!=0 ){ return 1; } return (db->flags & SQLITE_DqsDDL)!=0; }else{ /* Currently parsing a DML statement */ return (db->flags & SQLITE_DqsDML)!=0; } } /* ** The argument is guaranteed to be a non-NULL Expr node of type TK_COLUMN. ** return the appropriate colUsed mask. */ SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr *pExpr){ int n; Table *pExTab; n = pExpr->iColumn; assert( ExprUseYTab(pExpr) ); pExTab = pExpr->y.pTab; assert( pExTab!=0 ); assert( n < pExTab->nCol ); if( (pExTab->tabFlags & TF_HasGenerated)!=0 && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0 ){ testcase( pExTab->nCol==BMS-1 ); testcase( pExTab->nCol==BMS ); return pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1; }else{ testcase( n==BMS-1 ); testcase( n==BMS ); if( n>=BMS ) n = BMS-1; return ((Bitmask)1)<db, TK_COLUMN, 0, 0); if( pNew ){ pNew->iTable = pMatch->iCursor; pNew->iColumn = iColumn; pNew->y.pTab = pMatch->pTab; assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ); ExprSetProperty(pNew, EP_CanBeNull); *ppList = sqlite3ExprListAppend(pParse, *ppList, pNew); } } /* ** Return TRUE (non-zero) if zTab is a valid name for the schema table pTab. */ static SQLITE_NOINLINE int isValidSchemaTableName( const char *zTab, /* Name as it appears in the SQL */ Table *pTab, /* The schema table we are trying to match */ Schema *pSchema /* non-NULL if a database qualifier is present */ ){ const char *zLegacy; assert( pTab!=0 ); assert( pTab->tnum==1 ); if( sqlite3StrNICmp(zTab, "sqlite_", 7)!=0 ) return 0; zLegacy = pTab->zName; if( strcmp(zLegacy+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){ if( sqlite3StrICmp(zTab+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){ return 1; } if( pSchema==0 ) return 0; if( sqlite3StrICmp(zTab+7, &LEGACY_SCHEMA_TABLE[7])==0 ) return 1; if( sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1; }else{ if( sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1; } return 0; } /* ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up ** that name in the set of source tables in pSrcList and make the pExpr ** expression node refer back to that source column. The following changes ** are made to pExpr: ** ** pExpr->iDb Set the index in db->aDb[] of the database X ** (even if X is implied). ** pExpr->iTable Set to the cursor number for the table obtained ** from pSrcList. ** pExpr->y.pTab Points to the Table structure of X.Y (even if ** X and/or Y are implied.) ** pExpr->iColumn Set to the column number within the table. ** pExpr->op Set to TK_COLUMN. ** pExpr->pLeft Any expression this points to is deleted ** pExpr->pRight Any expression this points to is deleted. ** ** The zDb variable is the name of the database (the "X"). This value may be ** NULL meaning that name is of the form Y.Z or Z. Any available database ** can be used. The zTable variable is the name of the table (the "Y"). This ** value can be NULL if zDb is also NULL. If zTable is NULL it ** means that the form of the name is Z and that columns from any table ** can be used. ** ** If the name cannot be resolved unambiguously, leave an error message ** in pParse and return WRC_Abort. Return WRC_Prune on success. */ static int lookupName( Parse *pParse, /* The parsing context */ const char *zDb, /* Name of the database containing table, or NULL */ const char *zTab, /* Name of table containing column, or NULL */ const char *zCol, /* Name of the column. */ NameContext *pNC, /* The name context used to resolve the name */ Expr *pExpr /* Make this EXPR node point to the selected column */ ){ int i, j; /* Loop counters */ int cnt = 0; /* Number of matching column names */ int cntTab = 0; /* Number of potential "rowid" matches */ int nSubquery = 0; /* How many levels of subquery */ sqlite3 *db = pParse->db; /* The database connection */ SrcItem *pItem; /* Use for looping over pSrcList items */ SrcItem *pMatch = 0; /* The matching pSrcList item */ NameContext *pTopNC = pNC; /* First namecontext in the list */ Schema *pSchema = 0; /* Schema of the expression */ int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */ Table *pTab = 0; /* Table holding the row */ Column *pCol; /* A column of pTab */ ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */ assert( pNC ); /* the name context cannot be NULL. */ assert( zCol ); /* The Z in X.Y.Z cannot be NULL */ assert( zDb==0 || zTab!=0 ); assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); /* Initialize the node to no-match */ pExpr->iTable = -1; ExprSetVVAProperty(pExpr, EP_NoReduce); /* Translate the schema name in zDb into a pointer to the corresponding ** schema. If not found, pSchema will remain NULL and nothing will match ** resulting in an appropriate error message toward the end of this routine */ if( zDb ){ testcase( pNC->ncFlags & NC_PartIdx ); testcase( pNC->ncFlags & NC_IsCheck ); if( (pNC->ncFlags & (NC_PartIdx|NC_IsCheck))!=0 ){ /* Silently ignore database qualifiers inside CHECK constraints and ** partial indices. Do not raise errors because that might break ** legacy and because it does not hurt anything to just ignore the ** database name. */ zDb = 0; }else{ for(i=0; inDb; i++){ assert( db->aDb[i].zDbSName ); if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){ pSchema = db->aDb[i].pSchema; break; } } if( i==db->nDb && sqlite3StrICmp("main", zDb)==0 ){ /* This branch is taken when the main database has been renamed ** using SQLITE_DBCONFIG_MAINDBNAME. */ pSchema = db->aDb[0].pSchema; zDb = db->aDb[0].zDbSName; } } } /* Start at the inner-most context and move outward until a match is found */ assert( pNC && cnt==0 ); do{ ExprList *pEList; SrcList *pSrcList = pNC->pSrcList; if( pSrcList ){ for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ u8 hCol; pTab = pItem->pTab; assert( pTab!=0 && pTab->zName!=0 ); assert( pTab->nCol>0 || pParse->nErr ); assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); if( pItem->fg.isNestedFrom ){ /* In this case, pItem is a subquery that has been formed from a ** parenthesized subset of the FROM clause terms. Example: ** .... FROM t1 LEFT JOIN (t2 RIGHT JOIN t3 USING(x)) USING(y) ... ** \_________________________/ ** This pItem -------------^ */ int hit = 0; assert( pItem->pSelect!=0 ); pEList = pItem->pSelect->pEList; assert( pEList!=0 ); assert( pEList->nExpr==pTab->nCol ); for(j=0; jnExpr; j++){ int bRowid = 0; /* True if possible rowid match */ if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){ continue; } if( bRowid==0 ){ if( cnt>0 ){ if( pItem->fg.isUsing==0 || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 ){ /* Two or more tables have the same column name which is ** not joined by USING. This is an error. Signal as much ** by clearing pFJMatch and letting cnt go above 1. */ sqlite3ExprListDelete(db, pFJMatch); pFJMatch = 0; }else if( (pItem->fg.jointype & JT_RIGHT)==0 ){ /* An INNER or LEFT JOIN. Use the left-most table */ continue; }else if( (pItem->fg.jointype & JT_LEFT)==0 ){ /* A RIGHT JOIN. Use the right-most table */ cnt = 0; sqlite3ExprListDelete(db, pFJMatch); pFJMatch = 0; }else{ /* For a FULL JOIN, we must construct a coalesce() func */ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); } } cnt++; hit = 1; }else if( cnt>0 ){ /* This is a potential rowid match, but there has already been ** a real match found. So this can be ignored. */ continue; } cntTab++; pMatch = pItem; pExpr->iColumn = j; pEList->a[j].fg.bUsed = 1; /* rowid cannot be part of a USING clause - assert() this. */ assert( bRowid==0 || pEList->a[j].fg.bUsingTerm==0 ); if( pEList->a[j].fg.bUsingTerm ) break; } if( hit || zTab==0 ) continue; } assert( zDb==0 || zTab!=0 ); if( zTab ){ if( zDb ){ if( pTab->pSchema!=pSchema ) continue; if( pSchema==0 && strcmp(zDb,"*")!=0 ) continue; } if( pItem->zAlias!=0 ){ if( sqlite3StrICmp(zTab, pItem->zAlias)!=0 ){ continue; } }else if( sqlite3StrICmp(zTab, pTab->zName)!=0 ){ if( pTab->tnum!=1 ) continue; if( !isValidSchemaTableName(zTab, pTab, pSchema) ) continue; } assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT && pItem->zAlias ){ sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); } } hCol = sqlite3StrIHash(zCol); for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ if( pCol->hName==hCol && sqlite3StrICmp(pCol->zCnName, zCol)==0 ){ if( cnt>0 ){ if( pItem->fg.isUsing==0 || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 ){ /* Two or more tables have the same column name which is ** not joined by USING. This is an error. Signal as much ** by clearing pFJMatch and letting cnt go above 1. */ sqlite3ExprListDelete(db, pFJMatch); pFJMatch = 0; }else if( (pItem->fg.jointype & JT_RIGHT)==0 ){ /* An INNER or LEFT JOIN. Use the left-most table */ continue; }else if( (pItem->fg.jointype & JT_LEFT)==0 ){ /* A RIGHT JOIN. Use the right-most table */ cnt = 0; sqlite3ExprListDelete(db, pFJMatch); pFJMatch = 0; }else{ /* For a FULL JOIN, we must construct a coalesce() func */ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); } } cnt++; pMatch = pItem; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; if( pItem->fg.isNestedFrom ){ sqlite3SrcItemColumnUsed(pItem, j); } break; } } if( 0==cnt && VisibleRowid(pTab) ){ cntTab++; pMatch = pItem; } } if( pMatch ){ pExpr->iTable = pMatch->iCursor; assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pMatch->pTab; if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } pSchema = pExpr->y.pTab->pSchema; } } /* if( pSrcList ) */ #if !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT) /* If we have not already resolved the name, then maybe ** it is a new.* or old.* trigger argument reference. Or ** maybe it is an excluded.* from an upsert. Or maybe it is ** a reference in the RETURNING clause to a table being modified. */ if( cnt==0 && zDb==0 ){ pTab = 0; #ifndef SQLITE_OMIT_TRIGGER if( pParse->pTriggerTab!=0 ){ int op = pParse->eTriggerOp; assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); if( pParse->bReturning ){ if( (pNC->ncFlags & NC_UBaseReg)!=0 && ALWAYS(zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0) ){ pExpr->iTable = op!=TK_DELETE; pTab = pParse->pTriggerTab; } }else if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){ pExpr->iTable = 1; pTab = pParse->pTriggerTab; }else if( op!=TK_INSERT && zTab && sqlite3StrICmp("old",zTab)==0 ){ pExpr->iTable = 0; pTab = pParse->pTriggerTab; } } #endif /* SQLITE_OMIT_TRIGGER */ #ifndef SQLITE_OMIT_UPSERT if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){ Upsert *pUpsert = pNC->uNC.pUpsert; if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ pTab = pUpsert->pUpsertSrc->a[0].pTab; pExpr->iTable = EXCLUDED_TABLE_NUMBER; } } #endif /* SQLITE_OMIT_UPSERT */ if( pTab ){ int iCol; u8 hCol = sqlite3StrIHash(zCol); pSchema = pTab->pSchema; cntTab++; for(iCol=0, pCol=pTab->aCol; iColnCol; iCol++, pCol++){ if( pCol->hName==hCol && sqlite3StrICmp(pCol->zCnName, zCol)==0 ){ if( iCol==pTab->iPKey ){ iCol = -1; } break; } } if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){ /* IMP: R-51414-32910 */ iCol = -1; } if( iColnCol ){ cnt++; pMatch = 0; #ifndef SQLITE_OMIT_UPSERT if( pExpr->iTable==EXCLUDED_TABLE_NUMBER ){ testcase( iCol==(-1) ); assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT ){ pExpr->iColumn = iCol; pExpr->y.pTab = pTab; eNewExprOp = TK_COLUMN; }else{ pExpr->iTable = pNC->uNC.pUpsert->regData + sqlite3TableColumnToStorage(pTab, iCol); eNewExprOp = TK_REGISTER; } }else #endif /* SQLITE_OMIT_UPSERT */ { assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pTab; if( pParse->bReturning ){ eNewExprOp = TK_REGISTER; pExpr->op2 = TK_COLUMN; pExpr->iColumn = iCol; pExpr->iTable = pNC->uNC.iBaseReg + (pTab->nCol+1)*pExpr->iTable + sqlite3TableColumnToStorage(pTab, iCol) + 1; }else{ pExpr->iColumn = (i16)iCol; eNewExprOp = TK_TRIGGER; #ifndef SQLITE_OMIT_TRIGGER if( iCol<0 ){ pExpr->affExpr = SQLITE_AFF_INTEGER; }else if( pExpr->iTable==0 ){ testcase( iCol==31 ); testcase( iCol==32 ); pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<ncFlags & (NC_IdxExpr|NC_GenCol))==0 && sqlite3IsRowid(zCol) && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom) ){ cnt = 1; if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1; pExpr->affExpr = SQLITE_AFF_INTEGER; } /* ** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z ** might refer to an result-set alias. This happens, for example, when ** we are resolving names in the WHERE clause of the following command: ** ** SELECT a+b AS x FROM table WHERE x<10; ** ** In cases like this, replace pExpr with a copy of the expression that ** forms the result set entry ("a+b" in the example) and return immediately. ** Note that the expression in the result set should have already been ** resolved by the time the WHERE clause is resolved. ** ** The ability to use an output result-set column in the WHERE, GROUP BY, ** or HAVING clauses, or as part of a larger expression in the ORDER BY ** clause is not standard SQL. This is a (goofy) SQLite extension, that ** is supported for backwards compatibility only. Hence, we issue a warning ** on sqlite3_log() whenever the capability is used. */ if( cnt==0 && (pNC->ncFlags & NC_UEList)!=0 && zTab==0 ){ pEList = pNC->uNC.pEList; assert( pEList!=0 ); for(j=0; jnExpr; j++){ char *zAs = pEList->a[j].zEName; if( pEList->a[j].fg.eEName==ENAME_NAME && sqlite3_stricmp(zAs, zCol)==0 ){ Expr *pOrig; assert( pExpr->pLeft==0 && pExpr->pRight==0 ); assert( ExprUseXList(pExpr)==0 || pExpr->x.pList==0 ); assert( ExprUseXSelect(pExpr)==0 || pExpr->x.pSelect==0 ); pOrig = pEList->a[j].pExpr; if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){ sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); return WRC_Abort; } if( ExprHasProperty(pOrig, EP_Win) && ((pNC->ncFlags&NC_AllowWin)==0 || pNC!=pTopNC ) ){ sqlite3ErrorMsg(pParse, "misuse of aliased window function %s",zAs); return WRC_Abort; } if( sqlite3ExprVectorSize(pOrig)!=1 ){ sqlite3ErrorMsg(pParse, "row value misused"); return WRC_Abort; } resolveAlias(pParse, pEList, j, pExpr, nSubquery); cnt = 1; pMatch = 0; assert( zTab==0 && zDb==0 ); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr); } goto lookupname_end; } } } /* Advance to the next name context. The loop will exit when either ** we have a match (cnt>0) or when we run out of name contexts. */ if( cnt ) break; pNC = pNC->pNext; nSubquery++; }while( pNC ); /* ** If X and Y are NULL (in other words if only the column name Z is ** supplied) and the value of Z is enclosed in double-quotes, then ** Z is a string literal if it doesn't match any column names. In that ** case, we need to return right away and not make any changes to ** pExpr. ** ** Because no reference was made to outer contexts, the pNC->nRef ** fields are not changed in any context. */ if( cnt==0 && zTab==0 ){ assert( pExpr->op==TK_ID ); if( ExprHasProperty(pExpr,EP_DblQuoted) && areDoubleQuotedStringsEnabled(db, pTopNC) ){ /* If a double-quoted identifier does not match any known column name, ** then treat it as a string. ** ** This hack was added in the early days of SQLite in a misguided attempt ** to be compatible with MySQL 3.x, which used double-quotes for strings. ** I now sorely regret putting in this hack. The effect of this hack is ** that misspelled identifier names are silently converted into strings ** rather than causing an error, to the frustration of countless ** programmers. To all those frustrated programmers, my apologies. ** ** Someday, I hope to get rid of this hack. Unfortunately there is ** a huge amount of legacy SQL that uses it. So for now, we just ** issue a warning. */ sqlite3_log(SQLITE_WARNING, "double-quoted string literal: \"%w\"", zCol); #ifdef SQLITE_ENABLE_NORMALIZE sqlite3VdbeAddDblquoteStr(db, pParse->pVdbe, zCol); #endif pExpr->op = TK_STRING; memset(&pExpr->y, 0, sizeof(pExpr->y)); return WRC_Prune; } if( sqlite3ExprIdToTrueFalse(pExpr) ){ return WRC_Prune; } } /* ** cnt==0 means there was not match. ** cnt>1 means there were two or more matches. ** ** cnt==0 is always an error. cnt>1 is often an error, but might ** be multiple matches for a NATURAL LEFT JOIN or a LEFT JOIN USING. */ assert( pFJMatch==0 || cnt>0 ); assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) ); if( cnt!=1 ){ const char *zErr; if( pFJMatch ){ if( pFJMatch->nExpr==cnt-1 ){ if( ExprHasProperty(pExpr,EP_Leaf) ){ ExprClearProperty(pExpr,EP_Leaf); }else{ sqlite3ExprDelete(db, pExpr->pLeft); pExpr->pLeft = 0; sqlite3ExprDelete(db, pExpr->pRight); pExpr->pRight = 0; } extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); pExpr->op = TK_FUNCTION; pExpr->u.zToken = "coalesce"; pExpr->x.pList = pFJMatch; cnt = 1; goto lookupname_end; }else{ sqlite3ExprListDelete(db, pFJMatch); pFJMatch = 0; } } zErr = cnt==0 ? "no such column" : "ambiguous column name"; if( zDb ){ sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol); }else if( zTab ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zErr, zTab, zCol); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol); } sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); pParse->checkSchema = 1; pTopNC->nNcErr++; eNewExprOp = TK_NULL; } assert( pFJMatch==0 ); /* Remove all substructure from pExpr */ if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ sqlite3ExprDelete(db, pExpr->pLeft); pExpr->pLeft = 0; sqlite3ExprDelete(db, pExpr->pRight); pExpr->pRight = 0; ExprSetProperty(pExpr, EP_Leaf); } /* If a column from a table in pSrcList is referenced, then record ** this fact in the pSrcList.a[].colUsed bitmask. Column 0 causes ** bit 0 to be set. Column 1 sets bit 1. And so forth. Bit 63 is ** set if the 63rd or any subsequent column is used. ** ** The colUsed mask is an optimization used to help determine if an ** index is a covering index. The correct answer is still obtained ** if the mask contains extra set bits. However, it is important to ** avoid setting bits beyond the maximum column number of the table. ** (See ticket [b92e5e8ec2cdbaa1]). ** ** If a generated column is referenced, set bits for every column ** of the table. */ if( pExpr->iColumn>=0 && cnt==1 && pMatch!=0 ){ pMatch->colUsed |= sqlite3ExprColUsed(pExpr); } pExpr->op = eNewExprOp; lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION if( pParse->db->xAuth && (pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER) ){ sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); } #endif /* Increment the nRef value on all name contexts from TopNC up to ** the point where the name matched. */ for(;;){ assert( pTopNC!=0 ); pTopNC->nRef++; if( pTopNC==pNC ) break; pTopNC = pTopNC->pNext; } return WRC_Prune; } else { return WRC_Abort; } } /* ** Allocate and return a pointer to an expression to load the column iCol ** from datasource iSrc in SrcList pSrc. */ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); if( p ){ SrcItem *pItem = &pSrc->a[iSrc]; Table *pTab; assert( ExprUseYTab(p) ); pTab = p->y.pTab = pItem->pTab; p->iTable = pItem->iCursor; if( p->y.pTab->iPKey==iCol ){ p->iColumn = -1; }else{ p->iColumn = (ynVar)iCol; if( (pTab->tabFlags & TF_HasGenerated)!=0 && (pTab->aCol[iCol].colFlags & COLFLAG_GENERATED)!=0 ){ testcase( pTab->nCol==63 ); testcase( pTab->nCol==64 ); pItem->colUsed = pTab->nCol>=64 ? ALLBITS : MASKBIT(pTab->nCol)-1; }else{ testcase( iCol==BMS ); testcase( iCol==BMS-1 ); pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); } } } return p; } /* ** Report an error that an expression is not valid for some set of ** pNC->ncFlags values determined by validMask. ** ** static void notValid( ** Parse *pParse, // Leave error message here ** NameContext *pNC, // The name context ** const char *zMsg, // Type of error ** int validMask, // Set of contexts for which prohibited ** Expr *pExpr // Invalidate this expression on error ** ){...} ** ** As an optimization, since the conditional is almost always false ** (because errors are rare), the conditional is moved outside of the ** function call using a macro. */ static void notValidImpl( Parse *pParse, /* Leave error message here */ NameContext *pNC, /* The name context */ const char *zMsg, /* Type of error */ Expr *pExpr, /* Invalidate this expression on error */ Expr *pError /* Associate error with this expression */ ){ const char *zIn = "partial index WHERE clauses"; if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions"; #ifndef SQLITE_OMIT_CHECK else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints"; #endif #ifndef SQLITE_OMIT_GENERATED_COLUMNS else if( pNC->ncFlags & NC_GenCol ) zIn = "generated columns"; #endif sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn); if( pExpr ) pExpr->op = TK_NULL; sqlite3RecordErrorOffsetOfExpr(pParse->db, pError); } #define sqlite3ResolveNotValid(P,N,M,X,E,R) \ assert( ((X)&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 ); \ if( ((N)->ncFlags & (X))!=0 ) notValidImpl(P,N,M,E,R); /* ** Expression p should encode a floating point value between 1.0 and 0.0. ** Return 1024 times this value. Or return -1 if p is not a floating point ** value between 1.0 and 0.0. */ static int exprProbability(Expr *p){ double r = -1.0; if( p->op!=TK_FLOAT ) return -1; assert( !ExprHasProperty(p, EP_IntValue) ); sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); assert( r>=0.0 ); if( r>1.0 ) return -1; return (int)(r*134217728.0); } /* ** This routine is callback for sqlite3WalkExpr(). ** ** Resolve symbolic names into TK_COLUMN operators for the current ** node in the expression tree. Return 0 to continue the search down ** the tree or 2 to abort the tree walk. ** ** This routine also does error checking and name resolution for ** function names. The operator for aggregate functions is changed ** to TK_AGG_FUNCTION. */ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ NameContext *pNC; Parse *pParse; pNC = pWalker->u.pNC; assert( pNC!=0 ); pParse = pNC->pParse; assert( pParse==pWalker->pParse ); #ifndef NDEBUG if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){ SrcList *pSrcList = pNC->pSrcList; int i; for(i=0; ipSrcList->nSrc; i++){ assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursornTab); } } #endif switch( pExpr->op ){ /* The special operator TK_ROW means use the rowid for the first ** column in the FROM clause. This is used by the LIMIT and ORDER BY ** clause processing on UPDATE and DELETE statements, and by ** UPDATE ... FROM statement processing. */ case TK_ROW: { SrcList *pSrcList = pNC->pSrcList; SrcItem *pItem; assert( pSrcList && pSrcList->nSrc>=1 ); pItem = pSrcList->a; pExpr->op = TK_COLUMN; assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pItem->pTab; pExpr->iTable = pItem->iCursor; pExpr->iColumn--; pExpr->affExpr = SQLITE_AFF_INTEGER; break; } /* An optimization: Attempt to convert ** ** "expr IS NOT NULL" --> "TRUE" ** "expr IS NULL" --> "FALSE" ** ** if we can prove that "expr" is never NULL. Call this the ** "NOT NULL strength reduction optimization". ** ** If this optimization occurs, also restore the NameContext ref-counts ** to the state they where in before the "column" LHS expression was ** resolved. This prevents "column" from being counted as having been ** referenced, which might prevent a SELECT from being erroneously ** marked as correlated. */ case TK_NOTNULL: case TK_ISNULL: { int anRef[8]; NameContext *p; int i; for(i=0, p=pNC; p && ipNext, i++){ anRef[i] = p->nRef; } sqlite3WalkExpr(pWalker, pExpr->pLeft); if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){ testcase( ExprHasProperty(pExpr, EP_OuterON) ); assert( !ExprHasProperty(pExpr, EP_IntValue) ); pExpr->u.iValue = (pExpr->op==TK_NOTNULL); pExpr->flags |= EP_IntValue; pExpr->op = TK_INTEGER; for(i=0, p=pNC; p && ipNext, i++){ p->nRef = anRef[i]; } sqlite3ExprDelete(pParse->db, pExpr->pLeft); pExpr->pLeft = 0; } return WRC_Prune; } /* A column name: ID ** Or table name and column name: ID.ID ** Or a database, table and column: ID.ID.ID ** ** The TK_ID and TK_OUT cases are combined so that there will only ** be one call to lookupName(). Then the compiler will in-line ** lookupName() for a size reduction and performance increase. */ case TK_ID: case TK_DOT: { const char *zColumn; const char *zTable; const char *zDb; Expr *pRight; if( pExpr->op==TK_ID ){ zDb = 0; zTable = 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zColumn = pExpr->u.zToken; }else{ Expr *pLeft = pExpr->pLeft; testcase( pNC->ncFlags & NC_IdxExpr ); testcase( pNC->ncFlags & NC_GenCol ); sqlite3ResolveNotValid(pParse, pNC, "the \".\" operator", NC_IdxExpr|NC_GenCol, 0, pExpr); pRight = pExpr->pRight; if( pRight->op==TK_ID ){ zDb = 0; }else{ assert( pRight->op==TK_DOT ); assert( !ExprHasProperty(pRight, EP_IntValue) ); zDb = pLeft->u.zToken; pLeft = pRight->pLeft; pRight = pRight->pRight; } assert( ExprUseUToken(pLeft) && ExprUseUToken(pRight) ); zTable = pLeft->u.zToken; zColumn = pRight->u.zToken; assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight); sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft); } } return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); } /* Resolve function names */ case TK_FUNCTION: { ExprList *pList = pExpr->x.pList; /* The argument list */ int n = pList ? pList->nExpr : 0; /* Number of arguments */ int no_such_func = 0; /* True if no such function exists */ int wrong_num_args = 0; /* True if wrong number of arguments */ int is_agg = 0; /* True if is an aggregate function */ const char *zId; /* The function name. */ FuncDef *pDef; /* Information about the function */ u8 enc = ENC(pParse->db); /* The database encoding */ int savedAllowFlags = (pNC->ncFlags & (NC_AllowAgg | NC_AllowWin)); #ifndef SQLITE_OMIT_WINDOWFUNC Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0); #endif assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) ); assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER ); zId = pExpr->u.zToken; pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0); if( pDef==0 ){ pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0); if( pDef==0 ){ no_such_func = 1; }else{ wrong_num_args = 1; } }else{ is_agg = pDef->xFinalize!=0; if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ ExprSetProperty(pExpr, EP_Unlikely); if( n==2 ){ pExpr->iTable = exprProbability(pList->a[1].pExpr); if( pExpr->iTable<0 ){ sqlite3ErrorMsg(pParse, "second argument to %#T() must be a " "constant between 0.0 and 1.0", pExpr); pNC->nNcErr++; } }else{ /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is ** equivalent to likelihood(X, 0.0625). ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is ** short-hand for likelihood(X,0.0625). ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand ** for likelihood(X,0.9375). ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent ** to likelihood(X,0.9375). */ /* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */ pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120; } } #ifndef SQLITE_OMIT_AUTHORIZATION { int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0); if( auth!=SQLITE_OK ){ if( auth==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized to use function: %#T", pExpr); pNC->nNcErr++; } pExpr->op = TK_NULL; return WRC_Prune; } } #endif if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ /* For the purposes of the EP_ConstFunc flag, date and time ** functions and other functions that change slowly are considered ** constant because they are constant for the duration of one query. ** This allows them to be factored out of inner loops. */ ExprSetProperty(pExpr,EP_ConstFunc); } if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){ /* Clearly non-deterministic functions like random(), but also ** date/time functions that use 'now', and other functions like ** sqlite_version() that might change over time cannot be used ** in an index or generated column. Curiously, they can be used ** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all ** all this. */ sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr); }else{ assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */ pExpr->op2 = pNC->ncFlags & NC_SelfRef; if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); } if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && pParse->nested==0 && (pParse->db->mDbFlags & DBFLAG_InternalFunc)==0 ){ /* Internal-use-only functions are disallowed unless the ** SQL is being compiled using sqlite3NestedParse() or ** the SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test-control has be ** used to activate internal functions for testing purposes */ no_such_func = 1; pDef = 0; }else if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 && !IN_RENAME_OBJECT ){ sqlite3ExprFunctionUsable(pParse, pExpr, pDef); } } if( 0==IN_RENAME_OBJECT ){ #ifndef SQLITE_OMIT_WINDOWFUNC assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX) || (pDef->xValue==0 && pDef->xInverse==0) || (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize) ); if( pDef && pDef->xValue==0 && pWin ){ sqlite3ErrorMsg(pParse, "%#T() may not be used as a window function", pExpr ); pNC->nNcErr++; }else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) || (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pWin) || (is_agg && pWin && (pNC->ncFlags & NC_AllowWin)==0) ){ const char *zType; if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pWin ){ zType = "window"; }else{ zType = "aggregate"; } sqlite3ErrorMsg(pParse, "misuse of %s function %#T()",zType,pExpr); pNC->nNcErr++; is_agg = 0; } #else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){ sqlite3ErrorMsg(pParse,"misuse of aggregate function %#T()",pExpr); pNC->nNcErr++; is_agg = 0; } #endif else if( no_such_func && pParse->db->init.busy==0 #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION && pParse->explain==0 #endif ){ sqlite3ErrorMsg(pParse, "no such function: %#T", pExpr); pNC->nNcErr++; }else if( wrong_num_args ){ sqlite3ErrorMsg(pParse,"wrong number of arguments to function %#T()", pExpr); pNC->nNcErr++; } #ifndef SQLITE_OMIT_WINDOWFUNC else if( is_agg==0 && ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3ErrorMsg(pParse, "FILTER may not be used with non-aggregate %#T()", pExpr ); pNC->nNcErr++; } #endif else if( is_agg==0 && pExpr->pLeft ){ sqlite3ExprOrderByAggregateError(pParse, pExpr); pNC->nNcErr++; } if( is_agg ){ /* Window functions may not be arguments of aggregate functions. ** Or arguments of other window functions. But aggregate functions ** may be arguments for window functions. */ #ifndef SQLITE_OMIT_WINDOWFUNC pNC->ncFlags &= ~(NC_AllowWin | (!pWin ? NC_AllowAgg : 0)); #else pNC->ncFlags &= ~NC_AllowAgg; #endif } } #ifndef SQLITE_OMIT_WINDOWFUNC else if( ExprHasProperty(pExpr, EP_WinFunc) ){ is_agg = 1; } #endif sqlite3WalkExprList(pWalker, pList); if( is_agg ){ if( pExpr->pLeft ){ assert( pExpr->pLeft->op==TK_ORDER ); assert( ExprUseXList(pExpr->pLeft) ); sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList); } #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ Select *pSel = pNC->pWinSelect; assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) ); if( IN_RENAME_OBJECT==0 ){ sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef); if( pParse->db->mallocFailed ) break; } sqlite3WalkExprList(pWalker, pWin->pPartition); sqlite3WalkExprList(pWalker, pWin->pOrderBy); sqlite3WalkExpr(pWalker, pWin->pFilter); sqlite3WindowLink(pSel, pWin); pNC->ncFlags |= NC_HasWin; }else #endif /* SQLITE_OMIT_WINDOWFUNC */ { NameContext *pNC2; /* For looping up thru outer contexts */ pExpr->op = TK_AGG_FUNCTION; pExpr->op2 = 0; #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter); } #endif pNC2 = pNC; while( pNC2 && sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0 ){ pExpr->op2 += (1 + pNC2->nNestedSelect); pNC2 = pNC2->pNext; } assert( pDef!=0 || IN_RENAME_OBJECT ); if( pNC2 && pDef ){ pExpr->op2 += pNC2->nNestedSelect; assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg ); testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); testcase( (pDef->funcFlags & SQLITE_FUNC_ANYORDER)!=0 ); pNC2->ncFlags |= NC_HasAgg | ((pDef->funcFlags^SQLITE_FUNC_ANYORDER) & (SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER)); } } pNC->ncFlags |= savedAllowFlags; } /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function */ return WRC_Prune; } #ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: case TK_EXISTS: testcase( pExpr->op==TK_EXISTS ); #endif case TK_IN: { testcase( pExpr->op==TK_IN ); if( ExprUseXSelect(pExpr) ){ int nRef = pNC->nRef; testcase( pNC->ncFlags & NC_IsCheck ); testcase( pNC->ncFlags & NC_PartIdx ); testcase( pNC->ncFlags & NC_IdxExpr ); testcase( pNC->ncFlags & NC_GenCol ); if( pNC->ncFlags & NC_SelfRef ){ notValidImpl(pParse, pNC, "subqueries", pExpr, pExpr); }else{ sqlite3WalkSelect(pWalker, pExpr->x.pSelect); } assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); } pNC->ncFlags |= NC_Subquery; } break; } case TK_VARIABLE: { testcase( pNC->ncFlags & NC_IsCheck ); testcase( pNC->ncFlags & NC_PartIdx ); testcase( pNC->ncFlags & NC_IdxExpr ); testcase( pNC->ncFlags & NC_GenCol ); sqlite3ResolveNotValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr, pExpr); break; } case TK_IS: case TK_ISNOT: { Expr *pRight = sqlite3ExprSkipCollateAndLikely(pExpr->pRight); assert( !ExprHasProperty(pExpr, EP_Reduced) ); /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE", ** and "x IS NOT FALSE". */ if( ALWAYS(pRight) && (pRight->op==TK_ID || pRight->op==TK_TRUEFALSE) ){ int rc = resolveExprStep(pWalker, pRight); if( rc==WRC_Abort ) return WRC_Abort; if( pRight->op==TK_TRUEFALSE ){ pExpr->op2 = pExpr->op; pExpr->op = TK_TRUTH; return WRC_Continue; } } /* no break */ deliberate_fall_through } case TK_BETWEEN: case TK_EQ: case TK_NE: case TK_LT: case TK_LE: case TK_GT: case TK_GE: { int nLeft, nRight; if( pParse->db->mallocFailed ) break; assert( pExpr->pLeft!=0 ); nLeft = sqlite3ExprVectorSize(pExpr->pLeft); if( pExpr->op==TK_BETWEEN ){ assert( ExprUseXList(pExpr) ); nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr); if( nRight==nLeft ){ nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr); } }else{ assert( pExpr->pRight!=0 ); nRight = sqlite3ExprVectorSize(pExpr->pRight); } if( nLeft!=nRight ){ testcase( pExpr->op==TK_EQ ); testcase( pExpr->op==TK_NE ); testcase( pExpr->op==TK_LT ); testcase( pExpr->op==TK_LE ); testcase( pExpr->op==TK_GT ); testcase( pExpr->op==TK_GE ); testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_ISNOT ); testcase( pExpr->op==TK_BETWEEN ); sqlite3ErrorMsg(pParse, "row value misused"); sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); } break; } } assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); return pParse->nErr ? WRC_Abort : WRC_Continue; } /* ** pEList is a list of expressions which are really the result set of the ** a SELECT statement. pE is a term in an ORDER BY or GROUP BY clause. ** This routine checks to see if pE is a simple identifier which corresponds ** to the AS-name of one of the terms of the expression list. If it is, ** this routine return an integer between 1 and N where N is the number of ** elements in pEList, corresponding to the matching entry. If there is ** no match, or if pE is not a simple identifier, then this routine ** return 0. ** ** pEList has been resolved. pE has not. */ static int resolveAsName( Parse *pParse, /* Parsing context for error messages */ ExprList *pEList, /* List of expressions to scan */ Expr *pE /* Expression we are trying to match */ ){ int i; /* Loop counter */ UNUSED_PARAMETER(pParse); if( pE->op==TK_ID ){ const char *zCol; assert( !ExprHasProperty(pE, EP_IntValue) ); zCol = pE->u.zToken; for(i=0; inExpr; i++){ if( pEList->a[i].fg.eEName==ENAME_NAME && sqlite3_stricmp(pEList->a[i].zEName, zCol)==0 ){ return i+1; } } } return 0; } /* ** pE is a pointer to an expression which is a single term in the ** ORDER BY of a compound SELECT. The expression has not been ** name resolved. ** ** At the point this routine is called, we already know that the ** ORDER BY term is not an integer index into the result set. That ** case is handled by the calling routine. ** ** Attempt to match pE against result set columns in the left-most ** SELECT statement. Return the index i of the matching column, ** as an indication to the caller that it should sort by the i-th column. ** The left-most column is 1. In other words, the value returned is the ** same integer value that would be used in the SQL statement to indicate ** the column. ** ** If there is no match, return 0. Return -1 if an error occurs. */ static int resolveOrderByTermToExprList( Parse *pParse, /* Parsing context for error messages */ Select *pSelect, /* The SELECT statement with the ORDER BY clause */ Expr *pE /* The specific ORDER BY term */ ){ int i; /* Loop counter */ ExprList *pEList; /* The columns of the result set */ NameContext nc; /* Name context for resolving pE */ sqlite3 *db; /* Database connection */ int rc; /* Return code from subprocedures */ u8 savedSuppErr; /* Saved value of db->suppressErr */ assert( sqlite3ExprIsInteger(pE, &i)==0 ); pEList = pSelect->pEList; /* Resolve all names in the ORDER BY term expression */ memset(&nc, 0, sizeof(nc)); nc.pParse = pParse; nc.pSrcList = pSelect->pSrc; nc.uNC.pEList = pEList; nc.ncFlags = NC_AllowAgg|NC_UEList|NC_NoSelect; nc.nNcErr = 0; db = pParse->db; savedSuppErr = db->suppressErr; db->suppressErr = 1; rc = sqlite3ResolveExprNames(&nc, pE); db->suppressErr = savedSuppErr; if( rc ) return 0; /* Try to match the ORDER BY expression against an expression ** in the result set. Return an 1-based index of the matching ** result-set entry. */ for(i=0; inExpr; i++){ if( sqlite3ExprCompare(0, pEList->a[i].pExpr, pE, -1)<2 ){ return i+1; } } /* If no match, return 0. */ return 0; } /* ** Generate an ORDER BY or GROUP BY term out-of-range error. */ static void resolveOutOfRangeError( Parse *pParse, /* The error context into which to write the error */ const char *zType, /* "ORDER" or "GROUP" */ int i, /* The index (1-based) of the term out of range */ int mx, /* Largest permissible value of i */ Expr *pError /* Associate the error with the expression */ ){ sqlite3ErrorMsg(pParse, "%r %s BY term out of range - should be " "between 1 and %d", i, zType, mx); sqlite3RecordErrorOffsetOfExpr(pParse->db, pError); } /* ** Analyze the ORDER BY clause in a compound SELECT statement. Modify ** each term of the ORDER BY clause is a constant integer between 1 ** and N where N is the number of columns in the compound SELECT. ** ** ORDER BY terms that are already an integer between 1 and N are ** unmodified. ORDER BY terms that are integers outside the range of ** 1 through N generate an error. ORDER BY terms that are expressions ** are matched against result set expressions of compound SELECT ** beginning with the left-most SELECT and working toward the right. ** At the first match, the ORDER BY expression is transformed into ** the integer column number. ** ** Return the number of errors seen. */ static int resolveCompoundOrderBy( Parse *pParse, /* Parsing context. Leave error messages here */ Select *pSelect /* The SELECT statement containing the ORDER BY */ ){ int i; ExprList *pOrderBy; ExprList *pEList; sqlite3 *db; int moreToDo = 1; pOrderBy = pSelect->pOrderBy; if( pOrderBy==0 ) return 0; db = pParse->db; if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause"); return 1; } for(i=0; inExpr; i++){ pOrderBy->a[i].fg.done = 0; } pSelect->pNext = 0; while( pSelect->pPrior ){ pSelect->pPrior->pNext = pSelect; pSelect = pSelect->pPrior; } while( pSelect && moreToDo ){ struct ExprList_item *pItem; moreToDo = 0; pEList = pSelect->pEList; assert( pEList!=0 ); for(i=0, pItem=pOrderBy->a; inExpr; i++, pItem++){ int iCol = -1; Expr *pE, *pDup; if( pItem->fg.done ) continue; pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr); if( NEVER(pE==0) ) continue; if( sqlite3ExprIsInteger(pE, &iCol) ){ if( iCol<=0 || iCol>pEList->nExpr ){ resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr, pE); return 1; } }else{ iCol = resolveAsName(pParse, pEList, pE); if( iCol==0 ){ /* Now test if expression pE matches one of the values returned ** by pSelect. In the usual case this is done by duplicating the ** expression, resolving any symbols in it, and then comparing ** it against each expression returned by the SELECT statement. ** Once the comparisons are finished, the duplicate expression ** is deleted. ** ** If this is running as part of an ALTER TABLE operation and ** the symbols resolve successfully, also resolve the symbols in the ** actual expression. This allows the code in alter.c to modify ** column references within the ORDER BY expression as required. */ pDup = sqlite3ExprDup(db, pE, 0); if( !db->mallocFailed ){ assert(pDup); iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup); if( IN_RENAME_OBJECT && iCol>0 ){ resolveOrderByTermToExprList(pParse, pSelect, pE); } } sqlite3ExprDelete(db, pDup); } } if( iCol>0 ){ /* Convert the ORDER BY term into an integer column number iCol, ** taking care to preserve the COLLATE clause if it exists. */ if( !IN_RENAME_OBJECT ){ Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); if( pNew==0 ) return 1; pNew->flags |= EP_IntValue; pNew->u.iValue = iCol; if( pItem->pExpr==pE ){ pItem->pExpr = pNew; }else{ Expr *pParent = pItem->pExpr; assert( pParent->op==TK_COLLATE ); while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft; assert( pParent->pLeft==pE ); pParent->pLeft = pNew; } sqlite3ExprDelete(db, pE); pItem->u.x.iOrderByCol = (u16)iCol; } pItem->fg.done = 1; }else{ moreToDo = 1; } } pSelect = pSelect->pNext; } for(i=0; inExpr; i++){ if( pOrderBy->a[i].fg.done==0 ){ sqlite3ErrorMsg(pParse, "%r ORDER BY term does not match any " "column in the result set", i+1); return 1; } } return 0; } /* ** Check every term in the ORDER BY or GROUP BY clause pOrderBy of ** the SELECT statement pSelect. If any term is reference to a ** result set expression (as determined by the ExprList.a.u.x.iOrderByCol ** field) then convert that term into a copy of the corresponding result set ** column. ** ** If any errors are detected, add an error message to pParse and ** return non-zero. Return zero if no errors are seen. */ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy( Parse *pParse, /* Parsing context. Leave error messages here */ Select *pSelect, /* The SELECT statement containing the clause */ ExprList *pOrderBy, /* The ORDER BY or GROUP BY clause to be processed */ const char *zType /* "ORDER" or "GROUP" */ ){ int i; sqlite3 *db = pParse->db; ExprList *pEList; struct ExprList_item *pItem; if( pOrderBy==0 || pParse->db->mallocFailed || IN_RENAME_OBJECT ) return 0; if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType); return 1; } pEList = pSelect->pEList; assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */ for(i=0, pItem=pOrderBy->a; inExpr; i++, pItem++){ if( pItem->u.x.iOrderByCol ){ if( pItem->u.x.iOrderByCol>pEList->nExpr ){ resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr, 0); return 1; } resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr,0); } } return 0; } #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Walker callback for windowRemoveExprFromSelect(). */ static int resolveRemoveWindowsCb(Walker *pWalker, Expr *pExpr){ UNUSED_PARAMETER(pWalker); if( ExprHasProperty(pExpr, EP_WinFunc) ){ Window *pWin = pExpr->y.pWin; sqlite3WindowUnlinkFromSelect(pWin); } return WRC_Continue; } /* ** Remove any Window objects owned by the expression pExpr from the ** Select.pWin list of Select object pSelect. */ static void windowRemoveExprFromSelect(Select *pSelect, Expr *pExpr){ if( pSelect->pWin ){ Walker sWalker; memset(&sWalker, 0, sizeof(Walker)); sWalker.xExprCallback = resolveRemoveWindowsCb; sWalker.u.pSelect = pSelect; sqlite3WalkExpr(&sWalker, pExpr); } } #else # define windowRemoveExprFromSelect(a, b) #endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** pOrderBy is an ORDER BY or GROUP BY clause in SELECT statement pSelect. ** The Name context of the SELECT statement is pNC. zType is either ** "ORDER" or "GROUP" depending on which type of clause pOrderBy is. ** ** This routine resolves each term of the clause into an expression. ** If the order-by term is an integer I between 1 and N (where N is the ** number of columns in the result set of the SELECT) then the expression ** in the resolution is a copy of the I-th result-set expression. If ** the order-by term is an identifier that corresponds to the AS-name of ** a result-set expression, then the term resolves to a copy of the ** result-set expression. Otherwise, the expression is resolved in ** the usual way - using sqlite3ResolveExprNames(). ** ** This routine returns the number of errors. If errors occur, then ** an appropriate error message might be left in pParse. (OOM errors ** excepted.) */ static int resolveOrderGroupBy( NameContext *pNC, /* The name context of the SELECT statement */ Select *pSelect, /* The SELECT statement holding pOrderBy */ ExprList *pOrderBy, /* An ORDER BY or GROUP BY clause to resolve */ const char *zType /* Either "ORDER" or "GROUP", as appropriate */ ){ int i, j; /* Loop counters */ int iCol; /* Column number */ struct ExprList_item *pItem; /* A term of the ORDER BY clause */ Parse *pParse; /* Parsing context */ int nResult; /* Number of terms in the result set */ assert( pOrderBy!=0 ); nResult = pSelect->pEList->nExpr; pParse = pNC->pParse; for(i=0, pItem=pOrderBy->a; inExpr; i++, pItem++){ Expr *pE = pItem->pExpr; Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE); if( NEVER(pE2==0) ) continue; if( zType[0]!='G' ){ iCol = resolveAsName(pParse, pSelect->pEList, pE2); if( iCol>0 ){ /* If an AS-name match is found, mark this ORDER BY column as being ** a copy of the iCol-th result-set column. The subsequent call to ** sqlite3ResolveOrderGroupBy() will convert the expression to a ** copy of the iCol-th result-set expression. */ pItem->u.x.iOrderByCol = (u16)iCol; continue; } } if( sqlite3ExprIsInteger(pE2, &iCol) ){ /* The ORDER BY term is an integer constant. Again, set the column ** number so that sqlite3ResolveOrderGroupBy() will convert the ** order-by term to a copy of the result-set expression */ if( iCol<1 || iCol>0xffff ){ resolveOutOfRangeError(pParse, zType, i+1, nResult, pE2); return 1; } pItem->u.x.iOrderByCol = (u16)iCol; continue; } /* Otherwise, treat the ORDER BY term as an ordinary expression */ pItem->u.x.iOrderByCol = 0; if( sqlite3ResolveExprNames(pNC, pE) ){ return 1; } for(j=0; jpEList->nExpr; j++){ if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ /* Since this expression is being changed into a reference ** to an identical expression in the result set, remove all Window ** objects belonging to the expression from the Select.pWin list. */ windowRemoveExprFromSelect(pSelect, pE); pItem->u.x.iOrderByCol = j+1; } } } return sqlite3ResolveOrderGroupBy(pParse, pSelect, pOrderBy, zType); } /* ** Resolve names in the SELECT statement p and all of its descendants. */ static int resolveSelectStep(Walker *pWalker, Select *p){ NameContext *pOuterNC; /* Context that contains this SELECT */ NameContext sNC; /* Name context of this SELECT */ int isCompound; /* True if p is a compound select */ int nCompound; /* Number of compound terms processed so far */ Parse *pParse; /* Parsing context */ int i; /* Loop counter */ ExprList *pGroupBy; /* The GROUP BY clause */ Select *pLeftmost; /* Left-most of SELECT of a compound */ sqlite3 *db; /* Database connection */ assert( p!=0 ); if( p->selFlags & SF_Resolved ){ return WRC_Prune; } pOuterNC = pWalker->u.pNC; pParse = pWalker->pParse; db = pParse->db; /* Normally sqlite3SelectExpand() will be called first and will have ** already expanded this SELECT. However, if this is a subquery within ** an expression, sqlite3ResolveExprNames() will be called without a ** prior call to sqlite3SelectExpand(). When that happens, let ** sqlite3SelectPrep() do all of the processing for this SELECT. ** sqlite3SelectPrep() will invoke both sqlite3SelectExpand() and ** this routine in the correct order. */ if( (p->selFlags & SF_Expanded)==0 ){ sqlite3SelectPrep(pParse, p, pOuterNC); return pParse->nErr ? WRC_Abort : WRC_Prune; } isCompound = p->pPrior!=0; nCompound = 0; pLeftmost = p; while( p ){ assert( (p->selFlags & SF_Expanded)!=0 ); assert( (p->selFlags & SF_Resolved)==0 ); p->selFlags |= SF_Resolved; /* Resolve the expressions in the LIMIT and OFFSET clauses. These ** are not allowed to refer to any names, so pass an empty NameContext. */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pWinSelect = p; if( sqlite3ResolveExprNames(&sNC, p->pLimit) ){ return WRC_Abort; } /* If the SF_Converted flags is set, then this Select object was ** was created by the convertCompoundSelectToSubquery() function. ** In this case the ORDER BY clause (p->pOrderBy) should be resolved ** as if it were part of the sub-query, not the parent. This block ** moves the pOrderBy down to the sub-query. It will be moved back ** after the names have been resolved. */ if( p->selFlags & SF_Converted ){ Select *pSub = p->pSrc->a[0].pSelect; assert( p->pSrc->nSrc==1 && p->pOrderBy ); assert( pSub->pPrior && pSub->pOrderBy==0 ); pSub->pOrderBy = p->pOrderBy; p->pOrderBy = 0; } /* Recursively resolve names in all subqueries in the FROM clause */ if( pOuterNC ) pOuterNC->nNestedSelect++; for(i=0; ipSrc->nSrc; i++){ SrcItem *pItem = &p->pSrc->a[i]; if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ int nRef = pOuterNC ? pOuterNC->nRef : 0; const char *zSavedContext = pParse->zAuthContext; if( pItem->zName ) pParse->zAuthContext = pItem->zName; sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); pParse->zAuthContext = zSavedContext; if( pParse->nErr ) return WRC_Abort; assert( db->mallocFailed==0 ); /* If the number of references to the outer context changed when ** expressions in the sub-select were resolved, the sub-select ** is correlated. It is not required to check the refcount on any ** but the innermost outer context object, as lookupName() increments ** the refcount on all contexts between the current one and the ** context containing the column when it resolves a name. */ if( pOuterNC ){ assert( pItem->fg.isCorrelated==0 && pOuterNC->nRef>=nRef ); pItem->fg.isCorrelated = (pOuterNC->nRef>nRef); } } } if( pOuterNC && ALWAYS(pOuterNC->nNestedSelect>0) ){ pOuterNC->nNestedSelect--; } /* Set up the local name-context to pass to sqlite3ResolveExprNames() to ** resolve the result-set expression list. */ sNC.ncFlags = NC_AllowAgg|NC_AllowWin; sNC.pSrcList = p->pSrc; sNC.pNext = pOuterNC; /* Resolve names in the result set. */ if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort; sNC.ncFlags &= ~NC_AllowWin; /* If there are no aggregate functions in the result-set, and no GROUP BY ** expression, do not allow aggregates in any of the other expressions. */ assert( (p->selFlags & SF_Aggregate)==0 ); pGroupBy = p->pGroupBy; if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ assert( NC_MinMaxAgg==SF_MinMaxAgg ); assert( NC_OrderAgg==SF_OrderByReqd ); p->selFlags |= SF_Aggregate | (sNC.ncFlags&(NC_MinMaxAgg|NC_OrderAgg)); }else{ sNC.ncFlags &= ~NC_AllowAgg; } /* Add the output column list to the name-context before parsing the ** other expressions in the SELECT statement. This is so that ** expressions in the WHERE clause (etc.) can refer to expressions by ** aliases in the result set. ** ** Minor point: If this is the case, then the expression will be ** re-evaluated for each reference to it. */ assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert|NC_UBaseReg))==0 ); sNC.uNC.pEList = p->pEList; sNC.ncFlags |= NC_UEList; if( p->pHaving ){ if( (p->selFlags & SF_Aggregate)==0 ){ sqlite3ErrorMsg(pParse, "HAVING clause on a non-aggregate query"); return WRC_Abort; } if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; } if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; /* Resolve names in table-valued-function arguments */ for(i=0; ipSrc->nSrc; i++){ SrcItem *pItem = &p->pSrc->a[i]; if( pItem->fg.isTabFunc && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg) ){ return WRC_Abort; } } #ifndef SQLITE_OMIT_WINDOWFUNC if( IN_RENAME_OBJECT ){ Window *pWin; for(pWin=p->pWinDefn; pWin; pWin=pWin->pNextWin){ if( sqlite3ResolveExprListNames(&sNC, pWin->pOrderBy) || sqlite3ResolveExprListNames(&sNC, pWin->pPartition) ){ return WRC_Abort; } } } #endif /* The ORDER BY and GROUP BY clauses may not refer to terms in ** outer queries */ sNC.pNext = 0; sNC.ncFlags |= NC_AllowAgg|NC_AllowWin; /* If this is a converted compound query, move the ORDER BY clause from ** the sub-query back to the parent query. At this point each term ** within the ORDER BY clause has been transformed to an integer value. ** These integers will be replaced by copies of the corresponding result ** set expressions by the call to resolveOrderGroupBy() below. */ if( p->selFlags & SF_Converted ){ Select *pSub = p->pSrc->a[0].pSelect; p->pOrderBy = pSub->pOrderBy; pSub->pOrderBy = 0; } /* Process the ORDER BY clause for singleton SELECT statements. ** The ORDER BY clause for compounds SELECT statements is handled ** below, after all of the result-sets for all of the elements of ** the compound have been resolved. ** ** If there is an ORDER BY clause on a term of a compound-select other ** than the right-most term, then that is a syntax error. But the error ** is not detected until much later, and so we need to go ahead and ** resolve those symbols on the incorrect ORDER BY for consistency. */ if( p->pOrderBy!=0 && isCompound<=nCompound /* Defer right-most ORDER BY of a compound */ && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") ){ return WRC_Abort; } if( db->mallocFailed ){ return WRC_Abort; } sNC.ncFlags &= ~NC_AllowWin; /* Resolve the GROUP BY clause. At the same time, make sure ** the GROUP BY clause does not contain aggregate functions. */ if( pGroupBy ){ struct ExprList_item *pItem; if( resolveOrderGroupBy(&sNC, p, pGroupBy, "GROUP") || db->mallocFailed ){ return WRC_Abort; } for(i=0, pItem=pGroupBy->a; inExpr; i++, pItem++){ if( ExprHasProperty(pItem->pExpr, EP_Agg) ){ sqlite3ErrorMsg(pParse, "aggregate functions are not allowed in " "the GROUP BY clause"); return WRC_Abort; } } } /* If this is part of a compound SELECT, check that it has the right ** number of expressions in the select list. */ if( p->pNext && p->pEList->nExpr!=p->pNext->pEList->nExpr ){ sqlite3SelectWrongNumTermsError(pParse, p->pNext); return WRC_Abort; } /* Advance to the next term of the compound */ p = p->pPrior; nCompound++; } /* Resolve the ORDER BY on a compound SELECT after all terms of ** the compound have been resolved. */ if( isCompound && resolveCompoundOrderBy(pParse, pLeftmost) ){ return WRC_Abort; } return WRC_Prune; } /* ** This routine walks an expression tree and resolves references to ** table columns and result-set columns. At the same time, do error ** checking on function usage and set a flag if any aggregate functions ** are seen. ** ** To resolve table columns references we look for nodes (or subtrees) of the ** form X.Y.Z or Y.Z or just Z where ** ** X: The name of a database. Ex: "main" or "temp" or ** the symbolic name assigned to an ATTACH-ed database. ** ** Y: The name of a table in a FROM clause. Or in a trigger ** one of the special names "old" or "new". ** ** Z: The name of a column in table Y. ** ** The node at the root of the subtree is modified as follows: ** ** Expr.op Changed to TK_COLUMN ** Expr.pTab Points to the Table object for X.Y ** Expr.iColumn The column index in X.Y. -1 for the rowid. ** Expr.iTable The VDBE cursor number for X.Y ** ** ** To resolve result-set references, look for expression nodes of the ** form Z (with no X and Y prefix) where the Z matches the right-hand ** size of an AS clause in the result-set of a SELECT. The Z expression ** is replaced by a copy of the left-hand side of the result-set expression. ** Table-name and function resolution occurs on the substituted expression ** tree. For example, in: ** ** SELECT a+b AS x, c+d AS y FROM t1 ORDER BY x; ** ** The "x" term of the order by is replaced by "a+b" to render: ** ** SELECT a+b AS x, c+d AS y FROM t1 ORDER BY a+b; ** ** Function calls are checked to make sure that the function is ** defined and that the correct number of arguments are specified. ** If the function is an aggregate function, then the NC_HasAgg flag is ** set and the opcode is changed from TK_FUNCTION to TK_AGG_FUNCTION. ** If an expression contains aggregate functions then the EP_Agg ** property on the expression is set. ** ** An error message is left in pParse if anything is amiss. The number ** if errors is returned. */ SQLITE_PRIVATE int sqlite3ResolveExprNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */ ){ int savedHasAgg; Walker w; if( pExpr==0 ) return SQLITE_OK; savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = (pNC->ncFlags & NC_NoSelect) ? 0 : resolveSelectStep; w.xSelectCallback2 = 0; w.u.pNC = pNC; #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight += pExpr->nHeight; if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ return SQLITE_ERROR; } #endif assert( pExpr!=0 ); sqlite3WalkExprNN(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight -= pExpr->nHeight; #endif assert( EP_Agg==NC_HasAgg ); assert( EP_Win==NC_HasWin ); testcase( pNC->ncFlags & NC_HasAgg ); testcase( pNC->ncFlags & NC_HasWin ); ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) ); pNC->ncFlags |= savedHasAgg; return pNC->nNcErr>0 || w.pParse->nErr>0; } /* ** Resolve all names for all expression in an expression list. This is ** just like sqlite3ResolveExprNames() except that it works for an expression ** list rather than a single expression. */ SQLITE_PRIVATE int sqlite3ResolveExprListNames( NameContext *pNC, /* Namespace to resolve expressions in. */ ExprList *pList /* The expression list to be analyzed. */ ){ int i; int savedHasAgg = 0; Walker w; if( pList==0 ) return WRC_Continue; w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; w.xSelectCallback2 = 0; w.u.pNC = pNC; savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); for(i=0; inExpr; i++){ Expr *pExpr = pList->a[i].pExpr; if( pExpr==0 ) continue; #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight += pExpr->nHeight; if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ return WRC_Abort; } #endif sqlite3WalkExprNN(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight -= pExpr->nHeight; #endif assert( EP_Agg==NC_HasAgg ); assert( EP_Win==NC_HasWin ); testcase( pNC->ncFlags & NC_HasAgg ); testcase( pNC->ncFlags & NC_HasWin ); if( pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg) ){ ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) ); savedHasAgg |= pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); } if( w.pParse->nErr>0 ) return WRC_Abort; } pNC->ncFlags |= savedHasAgg; return WRC_Continue; } /* ** Resolve all names in all expressions of a SELECT and in all ** descendants of the SELECT, including compounds off of p->pPrior, ** subqueries in expressions, and subqueries used as FROM clause ** terms. ** ** See sqlite3ResolveExprNames() for a description of the kinds of ** transformations that occur. ** ** All SELECT statements should have been expanded using ** sqlite3SelectExpand() prior to invoking this routine. */ SQLITE_PRIVATE void sqlite3ResolveSelectNames( Parse *pParse, /* The parser context */ Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for parent SELECT statement */ ){ Walker w; assert( p!=0 ); w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; w.xSelectCallback2 = 0; w.pParse = pParse; w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); } /* ** Resolve names in expressions that can only reference a single table ** or which cannot reference any tables at all. Examples: ** ** "type" flag ** ------------ ** (1) CHECK constraints NC_IsCheck ** (2) WHERE clauses on partial indices NC_PartIdx ** (3) Expressions in indexes on expressions NC_IdxExpr ** (4) Expression arguments to VACUUM INTO. 0 ** (5) GENERATED ALWAYS as expressions NC_GenCol ** ** In all cases except (4), the Expr.iTable value for Expr.op==TK_COLUMN ** nodes of the expression is set to -1 and the Expr.iColumn value is ** set to the column number. In case (4), TK_COLUMN nodes cause an error. ** ** Any errors cause an error message to be set in pParse. */ SQLITE_PRIVATE int sqlite3ResolveSelfReference( Parse *pParse, /* Parsing context */ Table *pTab, /* The table being referenced, or NULL */ int type, /* NC_IsCheck, NC_PartIdx, NC_IdxExpr, NC_GenCol, or 0 */ Expr *pExpr, /* Expression to resolve. May be NULL. */ ExprList *pList /* Expression list to resolve. May be NULL. */ ){ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ int rc; assert( type==0 || pTab!=0 ); assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr || type==NC_GenCol || pTab==0 ); memset(&sNC, 0, sizeof(sNC)); memset(&sSrc, 0, sizeof(sSrc)); if( pTab ){ sSrc.nSrc = 1; sSrc.a[0].zName = pTab->zName; sSrc.a[0].pTab = pTab; sSrc.a[0].iCursor = -1; if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){ /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP ** schema elements */ type |= NC_FromDDL; } } sNC.pParse = pParse; sNC.pSrcList = &sSrc; sNC.ncFlags = type | NC_IsDDL; if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc; if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList); return rc; } /************** End of resolve.c *********************************************/ /************** Begin file expr.c ********************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. */ /* #include "sqliteInt.h" */ /* Forward declarations */ static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int); static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree); /* ** Return the affinity character for a single column of a table. */ SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table *pTab, int iCol){ if( iCol<0 || NEVER(iCol>=pTab->nCol) ) return SQLITE_AFF_INTEGER; return pTab->aCol[iCol].affinity; } /* ** Return the 'affinity' of the expression pExpr if any. ** ** If pExpr is a column, a reference to a column via an 'AS' alias, ** or a sub-select with a column as the return value, then the ** affinity of that column is returned. Otherwise, 0x00 is returned, ** indicating no affinity for the expression. ** ** i.e. the WHERE clause expressions in the following statements all ** have an affinity: ** ** CREATE TABLE t1(a); ** SELECT * FROM t1 WHERE a; ** SELECT a AS b FROM t1 WHERE b; ** SELECT * FROM t1 WHERE (select a from t1); */ SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){ int op; op = pExpr->op; while( 1 /* exit-by-break */ ){ if( op==TK_COLUMN || (op==TK_AGG_COLUMN && pExpr->y.pTab!=0) ){ assert( ExprUseYTab(pExpr) ); assert( pExpr->y.pTab!=0 ); return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); } if( op==TK_SELECT ){ assert( ExprUseXSelect(pExpr) ); assert( pExpr->x.pSelect!=0 ); assert( pExpr->x.pSelect->pEList!=0 ); assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 ); return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); } #ifndef SQLITE_OMIT_CAST if( op==TK_CAST ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif if( op==TK_SELECT_COLUMN ){ assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) ); assert( pExpr->iColumn < pExpr->iTable ); assert( pExpr->iColumn >= 0 ); assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr ); return sqlite3ExprAffinity( pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr ); } if( op==TK_VECTOR ){ assert( ExprUseXList(pExpr) ); return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr); } if( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){ assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) ); pExpr = pExpr->pLeft; op = pExpr->op; continue; } if( op!=TK_REGISTER || (op = pExpr->op2)==TK_REGISTER ) break; } return pExpr->affExpr; } /* ** Make a guess at all the possible datatypes of the result that could ** be returned by an expression. Return a bitmask indicating the answer: ** ** 0x01 Numeric ** 0x02 Text ** 0x04 Blob ** ** If the expression must return NULL, then 0x00 is returned. */ SQLITE_PRIVATE int sqlite3ExprDataType(const Expr *pExpr){ while( pExpr ){ switch( pExpr->op ){ case TK_COLLATE: case TK_IF_NULL_ROW: case TK_UPLUS: { pExpr = pExpr->pLeft; break; } case TK_NULL: { pExpr = 0; break; } case TK_STRING: { return 0x02; } case TK_BLOB: { return 0x04; } case TK_CONCAT: { return 0x06; } case TK_VARIABLE: case TK_AGG_FUNCTION: case TK_FUNCTION: { return 0x07; } case TK_COLUMN: case TK_AGG_COLUMN: case TK_SELECT: case TK_CAST: case TK_SELECT_COLUMN: case TK_VECTOR: { int aff = sqlite3ExprAffinity(pExpr); if( aff>=SQLITE_AFF_NUMERIC ) return 0x05; if( aff==SQLITE_AFF_TEXT ) return 0x06; return 0x07; } case TK_CASE: { int res = 0; int ii; ExprList *pList = pExpr->x.pList; assert( ExprUseXList(pExpr) && pList!=0 ); assert( pList->nExpr > 0); for(ii=1; iinExpr; ii+=2){ res |= sqlite3ExprDataType(pList->a[ii].pExpr); } if( pList->nExpr % 2 ){ res |= sqlite3ExprDataType(pList->a[pList->nExpr-1].pExpr); } return res; } default: { return 0x01; } } /* End of switch(op) */ } /* End of while(pExpr) */ return 0x00; } /* ** Set the collating sequence for expression pExpr to be the collating ** sequence named by pToken. Return a pointer to a new Expr node that ** implements the COLLATE operator. ** ** If a memory allocation error occurs, that fact is recorded in pParse->db ** and the pExpr parameter is returned unchanged. */ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken( const Parse *pParse, /* Parsing context */ Expr *pExpr, /* Add the "COLLATE" clause to this expression */ const Token *pCollName, /* Name of collating sequence */ int dequote /* True to dequote pCollName */ ){ if( pCollName->n>0 ){ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote); if( pNew ){ pNew->pLeft = pExpr; pNew->flags |= EP_Collate|EP_Skip; pExpr = pNew; } } return pExpr; } SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString( const Parse *pParse, /* Parsing context */ Expr *pExpr, /* Add the "COLLATE" clause to this expression */ const char *zC /* The collating sequence name */ ){ Token s; assert( zC!=0 ); sqlite3TokenInit(&s, (char*)zC); return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0); } /* ** Skip over any TK_COLLATE operators. */ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){ while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){ assert( pExpr->op==TK_COLLATE ); pExpr = pExpr->pLeft; } return pExpr; } /* ** Skip over any TK_COLLATE operators and/or any unlikely() ** or likelihood() or likely() functions at the root of an ** expression. */ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){ while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){ if( ExprHasProperty(pExpr, EP_Unlikely) ){ assert( ExprUseXList(pExpr) ); assert( pExpr->x.pList->nExpr>0 ); assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; }else{ assert( pExpr->op==TK_COLLATE ); pExpr = pExpr->pLeft; } } return pExpr; } /* ** Return the collation sequence for the expression pExpr. If ** there is no defined collating sequence, return NULL. ** ** See also: sqlite3ExprNNCollSeq() ** ** The sqlite3ExprNNCollSeq() works the same exact that it returns the ** default collation if pExpr has no defined collation. ** ** The collating sequence might be determined by a COLLATE operator ** or by the presence of a column with a defined collating sequence. ** COLLATE operators take first precedence. Left operands take ** precedence over right operands. */ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ sqlite3 *db = pParse->db; CollSeq *pColl = 0; const Expr *p = pExpr; while( p ){ int op = p->op; if( op==TK_REGISTER ) op = p->op2; if( (op==TK_AGG_COLUMN && p->y.pTab!=0) || op==TK_COLUMN || op==TK_TRIGGER ){ int j; assert( ExprUseYTab(p) ); assert( p->y.pTab!=0 ); if( (j = p->iColumn)>=0 ){ const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]); pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); } break; } if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; } if( op==TK_VECTOR ){ assert( ExprUseXList(p) ); p = p->x.pList->a[0].pExpr; continue; } if( op==TK_COLLATE ){ assert( !ExprHasProperty(p, EP_IntValue) ); pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); break; } if( p->flags & EP_Collate ){ if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){ p = p->pLeft; }else{ Expr *pNext = p->pRight; /* The Expr.x union is never used at the same time as Expr.pRight */ assert( !ExprUseXList(p) || p->x.pList==0 || p->pRight==0 ); if( ExprUseXList(p) && p->x.pList!=0 && !db->mallocFailed ){ int i; for(i=0; ix.pList->nExpr; i++){ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){ pNext = p->x.pList->a[i].pExpr; break; } } } p = pNext; } }else{ break; } } if( sqlite3CheckCollSeq(pParse, pColl) ){ pColl = 0; } return pColl; } /* ** Return the collation sequence for the expression pExpr. If ** there is no defined collating sequence, return a pointer to the ** default collation sequence. ** ** See also: sqlite3ExprCollSeq() ** ** The sqlite3ExprCollSeq() routine works the same except that it ** returns NULL if there is no defined collation. */ SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr){ CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr); if( p==0 ) p = pParse->db->pDfltColl; assert( p!=0 ); return p; } /* ** Return TRUE if the two expressions have equivalent collating sequences. */ SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, const Expr *pE1, const Expr *pE2){ CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1); CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2); return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0; } /* ** pExpr is an operand of a comparison operator. aff2 is the ** type affinity of the other operand. This routine returns the ** type affinity that should be used for the comparison operator. */ SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2){ char aff1 = sqlite3ExprAffinity(pExpr); if( aff1>SQLITE_AFF_NONE && aff2>SQLITE_AFF_NONE ){ /* Both sides of the comparison are columns. If one has numeric ** affinity, use that. Otherwise use no affinity. */ if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){ return SQLITE_AFF_NUMERIC; }else{ return SQLITE_AFF_BLOB; } }else{ /* One side is a column, the other is not. Use the columns affinity. */ assert( aff1<=SQLITE_AFF_NONE || aff2<=SQLITE_AFF_NONE ); return (aff1<=SQLITE_AFF_NONE ? aff2 : aff1) | SQLITE_AFF_NONE; } } /* ** pExpr is a comparison operator. Return the type affinity that should ** be applied to both operands prior to doing the comparison. */ static char comparisonAffinity(const Expr *pExpr){ char aff; assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT || pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE || pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT ); assert( pExpr->pLeft ); aff = sqlite3ExprAffinity(pExpr->pLeft); if( pExpr->pRight ){ aff = sqlite3CompareAffinity(pExpr->pRight, aff); }else if( ExprUseXSelect(pExpr) ){ aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff); }else if( aff==0 ){ aff = SQLITE_AFF_BLOB; } return aff; } /* ** pExpr is a comparison expression, eg. '=', '<', IN(...) etc. ** idx_affinity is the affinity of an indexed column. Return true ** if the index with affinity idx_affinity may be used to implement ** the comparison in pExpr. */ SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity){ char aff = comparisonAffinity(pExpr); if( affflags & EP_Collate ){ pColl = sqlite3ExprCollSeq(pParse, pLeft); }else if( pRight && (pRight->flags & EP_Collate)!=0 ){ pColl = sqlite3ExprCollSeq(pParse, pRight); }else{ pColl = sqlite3ExprCollSeq(pParse, pLeft); if( !pColl ){ pColl = sqlite3ExprCollSeq(pParse, pRight); } } return pColl; } /* Expression p is a comparison operator. Return a collation sequence ** appropriate for the comparison operator. ** ** This is normally just a wrapper around sqlite3BinaryCompareCollSeq(). ** However, if the OP_Commuted flag is set, then the order of the operands ** is reversed in the sqlite3BinaryCompareCollSeq() call so that the ** correct collating sequence is found. */ SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse *pParse, const Expr *p){ if( ExprHasProperty(p, EP_Commuted) ){ return sqlite3BinaryCompareCollSeq(pParse, p->pRight, p->pLeft); }else{ return sqlite3BinaryCompareCollSeq(pParse, p->pLeft, p->pRight); } } /* ** Generate code for a comparison operator. */ static int codeCompare( Parse *pParse, /* The parsing (and code generating) context */ Expr *pLeft, /* The left operand */ Expr *pRight, /* The right operand */ int opcode, /* The comparison opcode */ int in1, int in2, /* Register holding operands */ int dest, /* Jump here if true. */ int jumpIfNull, /* If true, jump if either operand is NULL */ int isCommuted /* The comparison has been commuted */ ){ int p5; int addr; CollSeq *p4; if( pParse->nErr ) return 0; if( isCommuted ){ p4 = sqlite3BinaryCompareCollSeq(pParse, pRight, pLeft); }else{ p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight); } p5 = binaryCompareP5(pLeft, pRight, jumpIfNull); addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1, (void*)p4, P4_COLLSEQ); sqlite3VdbeChangeP5(pParse->pVdbe, (u8)p5); return addr; } /* ** Return true if expression pExpr is a vector, or false otherwise. ** ** A vector is defined as any expression that results in two or more ** columns of result. Every TK_VECTOR node is an vector because the ** parser will not generate a TK_VECTOR with fewer than two entries. ** But a TK_SELECT might be either a vector or a scalar. It is only ** considered a vector if it has two or more result columns. */ SQLITE_PRIVATE int sqlite3ExprIsVector(const Expr *pExpr){ return sqlite3ExprVectorSize(pExpr)>1; } /* ** If the expression passed as the only argument is of type TK_VECTOR ** return the number of expressions in the vector. Or, if the expression ** is a sub-select, return the number of columns in the sub-select. For ** any other type of expression, return 1. */ SQLITE_PRIVATE int sqlite3ExprVectorSize(const Expr *pExpr){ u8 op = pExpr->op; if( op==TK_REGISTER ) op = pExpr->op2; if( op==TK_VECTOR ){ assert( ExprUseXList(pExpr) ); return pExpr->x.pList->nExpr; }else if( op==TK_SELECT ){ assert( ExprUseXSelect(pExpr) ); return pExpr->x.pSelect->pEList->nExpr; }else{ return 1; } } /* ** Return a pointer to a subexpression of pVector that is the i-th ** column of the vector (numbered starting with 0). The caller must ** ensure that i is within range. ** ** If pVector is really a scalar (and "scalar" here includes subqueries ** that return a single column!) then return pVector unmodified. ** ** pVector retains ownership of the returned subexpression. ** ** If the vector is a (SELECT ...) then the expression returned is ** just the expression for the i-th term of the result set, and may ** not be ready for evaluation because the table cursor has not yet ** been positioned. */ SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ assert( iop==TK_ERROR ); if( sqlite3ExprIsVector(pVector) ){ assert( pVector->op2==0 || pVector->op==TK_REGISTER ); if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){ assert( ExprUseXSelect(pVector) ); return pVector->x.pSelect->pEList->a[i].pExpr; }else{ assert( ExprUseXList(pVector) ); return pVector->x.pList->a[i].pExpr; } } return pVector; } /* ** Compute and return a new Expr object which when passed to ** sqlite3ExprCode() will generate all necessary code to compute ** the iField-th column of the vector expression pVector. ** ** It is ok for pVector to be a scalar (as long as iField==0). ** In that case, this routine works like sqlite3ExprDup(). ** ** The caller owns the returned Expr object and is responsible for ** ensuring that the returned value eventually gets freed. ** ** The caller retains ownership of pVector. If pVector is a TK_SELECT, ** then the returned object will reference pVector and so pVector must remain ** valid for the life of the returned object. If pVector is a TK_VECTOR ** or a scalar expression, then it can be deleted as soon as this routine ** returns. ** ** A trick to cause a TK_SELECT pVector to be deleted together with ** the returned Expr object is to attach the pVector to the pRight field ** of the returned TK_SELECT_COLUMN Expr object. */ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField( Parse *pParse, /* Parsing context */ Expr *pVector, /* The vector. List of expressions or a sub-SELECT */ int iField, /* Which column of the vector to return */ int nField /* Total number of columns in the vector */ ){ Expr *pRet; if( pVector->op==TK_SELECT ){ assert( ExprUseXSelect(pVector) ); /* The TK_SELECT_COLUMN Expr node: ** ** pLeft: pVector containing TK_SELECT. Not deleted. ** pRight: not used. But recursively deleted. ** iColumn: Index of a column in pVector ** iTable: 0 or the number of columns on the LHS of an assignment ** pLeft->iTable: First in an array of register holding result, or 0 ** if the result is not yet computed. ** ** sqlite3ExprDelete() specifically skips the recursive delete of ** pLeft on TK_SELECT_COLUMN nodes. But pRight is followed, so pVector ** can be attached to pRight to cause this node to take ownership of ** pVector. Typically there will be multiple TK_SELECT_COLUMN nodes ** with the same pLeft pointer to the pVector, but only one of them ** will own the pVector. */ pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0); if( pRet ){ ExprSetProperty(pRet, EP_FullSize); pRet->iTable = nField; pRet->iColumn = iField; pRet->pLeft = pVector; } }else{ if( pVector->op==TK_VECTOR ){ Expr **ppVector; assert( ExprUseXList(pVector) ); ppVector = &pVector->x.pList->a[iField].pExpr; pVector = *ppVector; if( IN_RENAME_OBJECT ){ /* This must be a vector UPDATE inside a trigger */ *ppVector = 0; return pVector; } } pRet = sqlite3ExprDup(pParse->db, pVector, 0); } return pRet; } /* ** If expression pExpr is of type TK_SELECT, generate code to evaluate ** it. Return the register in which the result is stored (or, if the ** sub-select returns more than one column, the first in an array ** of registers in which the result is stored). ** ** If pExpr is not a TK_SELECT expression, return 0. */ static int exprCodeSubselect(Parse *pParse, Expr *pExpr){ int reg = 0; #ifndef SQLITE_OMIT_SUBQUERY if( pExpr->op==TK_SELECT ){ reg = sqlite3CodeSubselect(pParse, pExpr); } #endif return reg; } /* ** Argument pVector points to a vector expression - either a TK_VECTOR ** or TK_SELECT that returns more than one column. This function returns ** the register number of a register that contains the value of ** element iField of the vector. ** ** If pVector is a TK_SELECT expression, then code for it must have ** already been generated using the exprCodeSubselect() routine. In this ** case parameter regSelect should be the first in an array of registers ** containing the results of the sub-select. ** ** If pVector is of type TK_VECTOR, then code for the requested field ** is generated. In this case (*pRegFree) may be set to the number of ** a temporary register to be freed by the caller before returning. ** ** Before returning, output parameter (*ppExpr) is set to point to the ** Expr object corresponding to element iElem of the vector. */ static int exprVectorRegister( Parse *pParse, /* Parse context */ Expr *pVector, /* Vector to extract element from */ int iField, /* Field to extract from pVector */ int regSelect, /* First in array of registers */ Expr **ppExpr, /* OUT: Expression element */ int *pRegFree /* OUT: Temp register to free */ ){ u8 op = pVector->op; assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT || op==TK_ERROR ); if( op==TK_REGISTER ){ *ppExpr = sqlite3VectorFieldSubexpr(pVector, iField); return pVector->iTable+iField; } if( op==TK_SELECT ){ assert( ExprUseXSelect(pVector) ); *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr; return regSelect+iField; } if( op==TK_VECTOR ){ assert( ExprUseXList(pVector) ); *ppExpr = pVector->x.pList->a[iField].pExpr; return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree); } return 0; } /* ** Expression pExpr is a comparison between two vector values. Compute ** the result of the comparison (1, 0, or NULL) and write that ** result into register dest. ** ** The caller must satisfy the following preconditions: ** ** if pExpr->op==TK_IS: op==TK_EQ and p5==SQLITE_NULLEQ ** if pExpr->op==TK_ISNOT: op==TK_NE and p5==SQLITE_NULLEQ ** otherwise: op==pExpr->op and p5==0 */ static void codeVectorCompare( Parse *pParse, /* Code generator context */ Expr *pExpr, /* The comparison operation */ int dest, /* Write results into this register */ u8 op, /* Comparison operator */ u8 p5 /* SQLITE_NULLEQ or zero */ ){ Vdbe *v = pParse->pVdbe; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; int nLeft = sqlite3ExprVectorSize(pLeft); int i; int regLeft = 0; int regRight = 0; u8 opx = op; int addrCmp = 0; int addrDone = sqlite3VdbeMakeLabel(pParse); int isCommuted = ExprHasProperty(pExpr,EP_Commuted); assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); if( pParse->nErr ) return; if( nLeft!=sqlite3ExprVectorSize(pRight) ){ sqlite3ErrorMsg(pParse, "row value misused"); return; } assert( pExpr->op==TK_EQ || pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT || pExpr->op==TK_LT || pExpr->op==TK_GT || pExpr->op==TK_LE || pExpr->op==TK_GE ); assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ) || (pExpr->op==TK_ISNOT && op==TK_NE) ); assert( p5==0 || pExpr->op!=op ); assert( p5==SQLITE_NULLEQ || pExpr->op==op ); if( op==TK_LE ) opx = TK_LT; if( op==TK_GE ) opx = TK_GT; if( op==TK_NE ) opx = TK_EQ; regLeft = exprCodeSubselect(pParse, pLeft); regRight = exprCodeSubselect(pParse, pRight); sqlite3VdbeAddOp2(v, OP_Integer, 1, dest); for(i=0; 1 /*Loop exits by "break"*/; i++){ int regFree1 = 0, regFree2 = 0; Expr *pL = 0, *pR = 0; int r1, r2; assert( i>=0 && i0 /* ** Check that argument nHeight is less than or equal to the maximum ** expression depth allowed. If it is not, leave an error message in ** pParse. */ SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse *pParse, int nHeight){ int rc = SQLITE_OK; int mxHeight = pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH]; if( nHeight>mxHeight ){ sqlite3ErrorMsg(pParse, "Expression tree is too large (maximum depth %d)", mxHeight ); rc = SQLITE_ERROR; } return rc; } /* The following three functions, heightOfExpr(), heightOfExprList() ** and heightOfSelect(), are used to determine the maximum height ** of any expression tree referenced by the structure passed as the ** first argument. ** ** If this maximum height is greater than the current value pointed ** to by pnHeight, the second parameter, then set *pnHeight to that ** value. */ static void heightOfExpr(const Expr *p, int *pnHeight){ if( p ){ if( p->nHeight>*pnHeight ){ *pnHeight = p->nHeight; } } } static void heightOfExprList(const ExprList *p, int *pnHeight){ if( p ){ int i; for(i=0; inExpr; i++){ heightOfExpr(p->a[i].pExpr, pnHeight); } } } static void heightOfSelect(const Select *pSelect, int *pnHeight){ const Select *p; for(p=pSelect; p; p=p->pPrior){ heightOfExpr(p->pWhere, pnHeight); heightOfExpr(p->pHaving, pnHeight); heightOfExpr(p->pLimit, pnHeight); heightOfExprList(p->pEList, pnHeight); heightOfExprList(p->pGroupBy, pnHeight); heightOfExprList(p->pOrderBy, pnHeight); } } /* ** Set the Expr.nHeight variable in the structure passed as an ** argument. An expression with no children, Expr.pList or ** Expr.pSelect member has a height of 1. Any other expression ** has a height equal to the maximum height of any other ** referenced Expr plus one. ** ** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags, ** if appropriate. */ static void exprSetHeight(Expr *p){ int nHeight = p->pLeft ? p->pLeft->nHeight : 0; if( NEVER(p->pRight) && p->pRight->nHeight>nHeight ){ nHeight = p->pRight->nHeight; } if( ExprUseXSelect(p) ){ heightOfSelect(p->x.pSelect, &nHeight); }else if( p->x.pList ){ heightOfExprList(p->x.pList, &nHeight); p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } p->nHeight = nHeight + 1; } /* ** Set the Expr.nHeight variable using the exprSetHeight() function. If ** the height is greater than the maximum allowed expression depth, ** leave an error in pParse. ** ** Also propagate all EP_Propagate flags from the Expr.x.pList into ** Expr.flags. */ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ if( pParse->nErr ) return; exprSetHeight(p); sqlite3ExprCheckHeight(pParse, p->nHeight); } /* ** Return the maximum height of any expression tree referenced ** by the select statement passed as an argument. */ SQLITE_PRIVATE int sqlite3SelectExprHeight(const Select *p){ int nHeight = 0; heightOfSelect(p, &nHeight); return nHeight; } #else /* ABOVE: Height enforcement enabled. BELOW: Height enforcement off */ /* ** Propagate all EP_Propagate flags from the Expr.x.pList into ** Expr.flags. */ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ if( pParse->nErr ) return; if( p && ExprUseXList(p) && p->x.pList ){ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } } #define exprSetHeight(y) #endif /* SQLITE_MAX_EXPR_DEPTH>0 */ /* ** Set the error offset for an Expr node, if possible. */ SQLITE_PRIVATE void sqlite3ExprSetErrorOffset(Expr *pExpr, int iOfst){ if( pExpr==0 ) return; if( NEVER(ExprUseWJoin(pExpr)) ) return; pExpr->w.iOfst = iOfst; } /* ** This routine is the core allocator for Expr nodes. ** ** Construct a new expression node and return a pointer to it. Memory ** for this node and for the pToken argument is a single allocation ** obtained from sqlite3DbMalloc(). The calling function ** is responsible for making sure the node eventually gets freed. ** ** If dequote is true, then the token (if it exists) is dequoted. ** If dequote is false, no dequoting is performed. The deQuote ** parameter is ignored if pToken is NULL or if the token does not ** appear to be quoted. If the quotes were of the form "..." (double-quotes) ** then the EP_DblQuoted flag is set on the expression node. ** ** Special case: If op==TK_INTEGER and pToken points to a string that ** can be translated into a 32-bit integer, then the token is not ** stored in u.zToken. Instead, the integer values is written ** into u.iValue and the EP_IntValue flag is set. No extra storage ** is allocated to hold the integer text and the dequote flag is ignored. */ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( sqlite3 *db, /* Handle for sqlite3DbMallocRawNN() */ int op, /* Expression opcode */ const Token *pToken, /* Token argument. Might be NULL */ int dequote /* True to dequote */ ){ Expr *pNew; int nExtra = 0; int iValue = 0; assert( db!=0 ); if( pToken ){ if( op!=TK_INTEGER || pToken->z==0 || sqlite3GetInt32(pToken->z, &iValue)==0 ){ nExtra = pToken->n+1; assert( iValue>=0 ); } } pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra); if( pNew ){ memset(pNew, 0, sizeof(Expr)); pNew->op = (u8)op; pNew->iAgg = -1; if( pToken ){ if( nExtra==0 ){ pNew->flags |= EP_IntValue|EP_Leaf|(iValue?EP_IsTrue:EP_IsFalse); pNew->u.iValue = iValue; }else{ pNew->u.zToken = (char*)&pNew[1]; assert( pToken->z!=0 || pToken->n==0 ); if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); pNew->u.zToken[pToken->n] = 0; if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){ sqlite3DequoteExpr(pNew); } } } #if SQLITE_MAX_EXPR_DEPTH>0 pNew->nHeight = 1; #endif } return pNew; } /* ** Allocate a new expression node from a zero-terminated token that has ** already been dequoted. */ SQLITE_PRIVATE Expr *sqlite3Expr( sqlite3 *db, /* Handle for sqlite3DbMallocZero() (may be null) */ int op, /* Expression opcode */ const char *zToken /* Token argument. Might be NULL */ ){ Token x; x.z = zToken; x.n = sqlite3Strlen30(zToken); return sqlite3ExprAlloc(db, op, &x, 0); } /* ** Attach subtrees pLeft and pRight to the Expr node pRoot. ** ** If pRoot==NULL that means that a memory allocation error has occurred. ** In that case, delete the subtrees pLeft and pRight. */ SQLITE_PRIVATE void sqlite3ExprAttachSubtrees( sqlite3 *db, Expr *pRoot, Expr *pLeft, Expr *pRight ){ if( pRoot==0 ){ assert( db->mallocFailed ); sqlite3ExprDelete(db, pLeft); sqlite3ExprDelete(db, pRight); }else{ assert( ExprUseXList(pRoot) ); assert( pRoot->x.pSelect==0 ); if( pRight ){ pRoot->pRight = pRight; pRoot->flags |= EP_Propagate & pRight->flags; #if SQLITE_MAX_EXPR_DEPTH>0 pRoot->nHeight = pRight->nHeight+1; }else{ pRoot->nHeight = 1; #endif } if( pLeft ){ pRoot->pLeft = pLeft; pRoot->flags |= EP_Propagate & pLeft->flags; #if SQLITE_MAX_EXPR_DEPTH>0 if( pLeft->nHeight>=pRoot->nHeight ){ pRoot->nHeight = pLeft->nHeight+1; } #endif } } } /* ** Allocate an Expr node which joins as many as two subtrees. ** ** One or both of the subtrees can be NULL. Return a pointer to the new ** Expr node. Or, if an OOM error occurs, set pParse->db->mallocFailed, ** free the subtrees and return NULL. */ SQLITE_PRIVATE Expr *sqlite3PExpr( Parse *pParse, /* Parsing context */ int op, /* Expression opcode */ Expr *pLeft, /* Left operand */ Expr *pRight /* Right operand */ ){ Expr *p; p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)); if( p ){ memset(p, 0, sizeof(Expr)); p->op = op & 0xff; p->iAgg = -1; sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight); sqlite3ExprCheckHeight(pParse, p->nHeight); }else{ sqlite3ExprDelete(pParse->db, pLeft); sqlite3ExprDelete(pParse->db, pRight); } return p; } /* ** Add pSelect to the Expr.x.pSelect field. Or, if pExpr is NULL (due ** do a memory allocation failure) then delete the pSelect object. */ SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){ if( pExpr ){ pExpr->x.pSelect = pSelect; ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery); sqlite3ExprSetHeightAndFlags(pParse, pExpr); }else{ assert( pParse->db->mallocFailed ); sqlite3SelectDelete(pParse->db, pSelect); } } /* ** Expression list pEList is a list of vector values. This function ** converts the contents of pEList to a VALUES(...) Select statement ** returning 1 row for each element of the list. For example, the ** expression list: ** ** ( (1,2), (3,4) (5,6) ) ** ** is translated to the equivalent of: ** ** VALUES(1,2), (3,4), (5,6) ** ** Each of the vector values in pEList must contain exactly nElem terms. ** If a list element that is not a vector or does not contain nElem terms, ** an error message is left in pParse. ** ** This is used as part of processing IN(...) expressions with a list ** of vectors on the RHS. e.g. "... IN ((1,2), (3,4), (5,6))". */ SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse *pParse, int nElem, ExprList *pEList){ int ii; Select *pRet = 0; assert( nElem>1 ); for(ii=0; iinExpr; ii++){ Select *pSel; Expr *pExpr = pEList->a[ii].pExpr; int nExprElem; if( pExpr->op==TK_VECTOR ){ assert( ExprUseXList(pExpr) ); nExprElem = pExpr->x.pList->nExpr; }else{ nExprElem = 1; } if( nExprElem!=nElem ){ sqlite3ErrorMsg(pParse, "IN(...) element has %d term%s - expected %d", nExprElem, nExprElem>1?"s":"", nElem ); break; } assert( ExprUseXList(pExpr) ); pSel = sqlite3SelectNew(pParse, pExpr->x.pList, 0, 0, 0, 0, 0, SF_Values,0); pExpr->x.pList = 0; if( pSel ){ if( pRet ){ pSel->op = TK_ALL; pSel->pPrior = pRet; } pRet = pSel; } } if( pRet && pRet->pPrior ){ pRet->selFlags |= SF_MultiValue; } sqlite3ExprListDelete(pParse->db, pEList); return pRet; } /* ** Join two expressions using an AND operator. If either expression is ** NULL, then just return the other expression. ** ** If one side or the other of the AND is known to be false, and neither side ** is part of an ON clause, then instead of returning an AND expression, ** just return a constant expression with a value of false. */ SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ sqlite3 *db = pParse->db; if( pLeft==0 ){ return pRight; }else if( pRight==0 ){ return pLeft; }else{ u32 f = pLeft->flags | pRight->flags; if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse && !IN_RENAME_OBJECT ){ sqlite3ExprDeferredDelete(pParse, pLeft); sqlite3ExprDeferredDelete(pParse, pRight); return sqlite3Expr(db, TK_INTEGER, "0"); }else{ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); } } } /* ** Construct a new expression node for a function with multiple ** arguments. */ SQLITE_PRIVATE Expr *sqlite3ExprFunction( Parse *pParse, /* Parsing context */ ExprList *pList, /* Argument list */ const Token *pToken, /* Name of the function */ int eDistinct /* SF_Distinct or SF_ALL or 0 */ ){ Expr *pNew; sqlite3 *db = pParse->db; assert( pToken ); pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1); if( pNew==0 ){ sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */ return 0; } assert( !ExprHasProperty(pNew, EP_InnerON|EP_OuterON) ); pNew->w.iOfst = (int)(pToken->z - pParse->zTail); if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] && !pParse->nested ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken); } pNew->x.pList = pList; ExprSetProperty(pNew, EP_HasFunc); assert( ExprUseXList(pNew) ); sqlite3ExprSetHeightAndFlags(pParse, pNew); if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct); return pNew; } /* ** Report an error when attempting to use an ORDER BY clause within ** the arguments of a non-aggregate function. */ SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse *pParse, Expr *p){ sqlite3ErrorMsg(pParse, "ORDER BY may not be used with non-aggregate %#T()", p ); } /* ** Attach an ORDER BY clause to a function call. ** ** functionname( arguments ORDER BY sortlist ) ** \_____________________/ \______/ ** pExpr pOrderBy ** ** The ORDER BY clause is inserted into a new Expr node of type TK_ORDER ** and added to the Expr.pLeft field of the parent TK_FUNCTION node. */ SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The function call to which ORDER BY is to be added */ ExprList *pOrderBy /* The ORDER BY clause to add */ ){ Expr *pOB; sqlite3 *db = pParse->db; if( NEVER(pOrderBy==0) ){ assert( db->mallocFailed ); return; } if( pExpr==0 ){ assert( db->mallocFailed ); sqlite3ExprListDelete(db, pOrderBy); return; } assert( pExpr->op==TK_FUNCTION ); assert( pExpr->pLeft==0 ); assert( ExprUseXList(pExpr) ); if( pExpr->x.pList==0 || NEVER(pExpr->x.pList->nExpr==0) ){ /* Ignore ORDER BY on zero-argument aggregates */ sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pOrderBy); return; } if( IsWindowFunc(pExpr) ){ sqlite3ExprOrderByAggregateError(pParse, pExpr); sqlite3ExprListDelete(db, pOrderBy); return; } pOB = sqlite3ExprAlloc(db, TK_ORDER, 0, 0); if( pOB==0 ){ sqlite3ExprListDelete(db, pOrderBy); return; } pOB->x.pList = pOrderBy; assert( ExprUseXList(pOB) ); pExpr->pLeft = pOB; ExprSetProperty(pOB, EP_FullSize); } /* ** Check to see if a function is usable according to current access ** rules: ** ** SQLITE_FUNC_DIRECT - Only usable from top-level SQL ** ** SQLITE_FUNC_UNSAFE - Usable if TRUSTED_SCHEMA or from ** top-level SQL ** ** If the function is not usable, create an error. */ SQLITE_PRIVATE void sqlite3ExprFunctionUsable( Parse *pParse, /* Parsing and code generating context */ const Expr *pExpr, /* The function invocation */ const FuncDef *pDef /* The function being invoked */ ){ assert( !IN_RENAME_OBJECT ); assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 ); if( ExprHasProperty(pExpr, EP_FromDDL) ){ if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0 || (pParse->db->flags & SQLITE_TrustedSchema)==0 ){ /* Functions prohibited in triggers and views if: ** (1) tagged with SQLITE_DIRECTONLY ** (2) not tagged with SQLITE_INNOCUOUS (which means it ** is tagged with SQLITE_FUNC_UNSAFE) and ** SQLITE_DBCONFIG_TRUSTED_SCHEMA is off (meaning ** that the schema is possibly tainted). */ sqlite3ErrorMsg(pParse, "unsafe use of %#T()", pExpr); } } } /* ** Assign a variable number to an expression that encodes a wildcard ** in the original SQL statement. ** ** Wildcards consisting of a single "?" are assigned the next sequential ** variable number. ** ** Wildcards of the form "?nnn" are assigned the number "nnn". We make ** sure "nnn" is not too big to avoid a denial of service attack when ** the SQL statement comes from an external source. ** ** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number ** as the previous instance of the same wildcard. Or if this is the first ** instance of the wildcard, the next sequential variable number is ** assigned. */ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){ sqlite3 *db = pParse->db; const char *z; ynVar x; if( pExpr==0 ) return; assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) ); z = pExpr->u.zToken; assert( z!=0 ); assert( z[0]!=0 ); assert( n==(u32)sqlite3Strlen30(z) ); if( z[1]==0 ){ /* Wildcard of the form "?". Assign the next variable number */ assert( z[0]=='?' ); x = (ynVar)(++pParse->nVar); }else{ int doAdd = 0; if( z[0]=='?' ){ /* Wildcard of the form "?nnn". Convert "nnn" to an integer and ** use it as the variable number */ i64 i; int bOk; if( n==2 ){ /*OPTIMIZATION-IF-TRUE*/ i = z[1]-'0'; /* The common case of ?N for a single digit N */ bOk = 1; }else{ bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8); } testcase( i==0 ); testcase( i==1 ); testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 ); testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ); if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]); sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); return; } x = (ynVar)i; if( x>pParse->nVar ){ pParse->nVar = (int)x; doAdd = 1; }else if( sqlite3VListNumToName(pParse->pVList, x)==0 ){ doAdd = 1; } }else{ /* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable ** number as the prior appearance of the same name, or if the name ** has never appeared before, reuse the same variable number */ x = (ynVar)sqlite3VListNameToNum(pParse->pVList, z, n); if( x==0 ){ x = (ynVar)(++pParse->nVar); doAdd = 1; } } if( doAdd ){ pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x); } } pExpr->iColumn = x; if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "too many SQL variables"); sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); } } /* ** Recursively delete an expression tree. */ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); assert( db!=0 ); assert( !ExprUseUValue(p) || p->u.iValue>=0 ); assert( !ExprUseYWin(p) || !ExprUseYSub(p) ); assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed ); assert( p->op!=TK_FUNCTION || !ExprUseYSub(p) ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); assert( p->pRight==0 ); assert( !ExprUseXSelect(p) || p->x.pSelect==0 ); assert( !ExprUseXList(p) || p->x.pList==0 ); } #endif if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){ /* The Expr.x union is never used at the same time as Expr.pRight */ assert( (ExprUseXList(p) && p->x.pList==0) || p->pRight==0 ); if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); if( p->pRight ){ assert( !ExprHasProperty(p, EP_WinFunc) ); sqlite3ExprDeleteNN(db, p->pRight); }else if( ExprUseXSelect(p) ){ assert( !ExprHasProperty(p, EP_WinFunc) ); sqlite3SelectDelete(db, p->x.pSelect); }else{ sqlite3ExprListDelete(db, p->x.pList); #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(p, EP_WinFunc) ){ sqlite3WindowDelete(db, p->y.pWin); } #endif } } if( !ExprHasProperty(p, EP_Static) ){ sqlite3DbNNFreeNN(db, p); } } SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(db, p); } SQLITE_PRIVATE void sqlite3ExprDeleteGeneric(sqlite3 *db, void *p){ if( ALWAYS(p) ) sqlite3ExprDeleteNN(db, (Expr*)p); } /* ** Clear both elements of an OnOrUsing object */ SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){ if( p==0 ){ /* Nothing to clear */ }else if( p->pOn ){ sqlite3ExprDeleteNN(db, p->pOn); }else if( p->pUsing ){ sqlite3IdListDelete(db, p->pUsing); } } /* ** Arrange to cause pExpr to be deleted when the pParse is deleted. ** This is similar to sqlite3ExprDelete() except that the delete is ** deferred until the pParse is deleted. ** ** The pExpr might be deleted immediately on an OOM error. ** ** The deferred delete is (currently) implemented by adding the ** pExpr to the pParse->pConstExpr list with a register number of 0. */ SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){ sqlite3ParserAddCleanup(pParse, sqlite3ExprDeleteGeneric, pExpr); } /* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the ** expression. */ SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){ if( p ){ if( IN_RENAME_OBJECT ){ sqlite3RenameExprUnmap(pParse, p); } sqlite3ExprDeleteNN(pParse->db, p); } } /* ** Return the number of bytes allocated for the expression structure ** passed as the first argument. This is always one of EXPR_FULLSIZE, ** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE. */ static int exprStructSize(const Expr *p){ if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE; if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE; return EXPR_FULLSIZE; } /* ** The dupedExpr*Size() routines each return the number of bytes required ** to store a copy of an expression or expression tree. They differ in ** how much of the tree is measured. ** ** dupedExprStructSize() Size of only the Expr structure ** dupedExprNodeSize() Size of Expr + space for token ** dupedExprSize() Expr + token + subtree components ** *************************************************************************** ** ** The dupedExprStructSize() function returns two values OR-ed together: ** (1) the space required for a copy of the Expr structure only and ** (2) the EP_xxx flags that indicate what the structure size should be. ** The return values is always one of: ** ** EXPR_FULLSIZE ** EXPR_REDUCEDSIZE | EP_Reduced ** EXPR_TOKENONLYSIZE | EP_TokenOnly ** ** The size of the structure can be found by masking the return value ** of this routine with 0xfff. The flags can be found by masking the ** return value with EP_Reduced|EP_TokenOnly. ** ** Note that with flags==EXPRDUP_REDUCE, this routines works on full-size ** (unreduced) Expr objects as they or originally constructed by the parser. ** During expression analysis, extra information is computed and moved into ** later parts of the Expr object and that extra information might get chopped ** off if the expression is reduced. Note also that it does not work to ** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal ** to reduce a pristine expression tree from the parser. The implementation ** of dupedExprStructSize() contain multiple assert() statements that attempt ** to enforce this constraint. */ static int dupedExprStructSize(const Expr *p, int flags){ int nSize; assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ assert( EXPR_FULLSIZE<=0xfff ); assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); if( 0==flags || ExprHasProperty(p, EP_FullSize) ){ nSize = EXPR_FULLSIZE; }else{ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); assert( !ExprHasProperty(p, EP_OuterON) ); assert( !ExprHasVVAProperty(p, EP_NoReduce) ); if( p->pLeft || p->x.pList ){ nSize = EXPR_REDUCEDSIZE | EP_Reduced; }else{ assert( p->pRight==0 ); nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly; } } return nSize; } /* ** This function returns the space in bytes required to store the copy ** of the Expr structure and a copy of the Expr.u.zToken string (if that ** string is defined.) */ static int dupedExprNodeSize(const Expr *p, int flags){ int nByte = dupedExprStructSize(p, flags) & 0xfff; if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ nByte += sqlite3Strlen30NN(p->u.zToken)+1; } return ROUND8(nByte); } /* ** Return the number of bytes required to create a duplicate of the ** expression passed as the first argument. ** ** The value returned includes space to create a copy of the Expr struct ** itself and the buffer referred to by Expr.u.zToken, if any. ** ** The return value includes space to duplicate all Expr nodes in the ** tree formed by Expr.pLeft and Expr.pRight, but not any other ** substructure such as Expr.x.pList, Expr.x.pSelect, and Expr.y.pWin. */ static int dupedExprSize(const Expr *p){ int nByte; assert( p!=0 ); nByte = dupedExprNodeSize(p, EXPRDUP_REDUCE); if( p->pLeft ) nByte += dupedExprSize(p->pLeft); if( p->pRight ) nByte += dupedExprSize(p->pRight); assert( nByte==ROUND8(nByte) ); return nByte; } /* ** An EdupBuf is a memory allocation used to stored multiple Expr objects ** together with their Expr.zToken content. This is used to help implement ** compression while doing sqlite3ExprDup(). The top-level Expr does the ** allocation for itself and many of its decendents, then passes an instance ** of the structure down into exprDup() so that they decendents can have ** access to that memory. */ typedef struct EdupBuf EdupBuf; struct EdupBuf { u8 *zAlloc; /* Memory space available for storage */ #ifdef SQLITE_DEBUG u8 *zEnd; /* First byte past the end of memory */ #endif }; /* ** This function is similar to sqlite3ExprDup(), except that if pEdupBuf ** is not NULL then it points to memory that can be used to store a copy ** of the input Expr p together with its p->u.zToken (if any). pEdupBuf ** is updated with the new buffer tail prior to returning. */ static Expr *exprDup( sqlite3 *db, /* Database connection (for memory allocation) */ const Expr *p, /* Expr tree to be duplicated */ int dupFlags, /* EXPRDUP_REDUCE for compression. 0 if not */ EdupBuf *pEdupBuf /* Preallocated storage space, or NULL */ ){ Expr *pNew; /* Value to return */ EdupBuf sEdupBuf; /* Memory space from which to build Expr object */ u32 staticFlag; /* EP_Static if space not obtained from malloc */ int nToken = -1; /* Space needed for p->u.zToken. -1 means unknown */ assert( db!=0 ); assert( p ); assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE ); assert( pEdupBuf==0 || dupFlags==EXPRDUP_REDUCE ); /* Figure out where to write the new Expr structure. */ if( pEdupBuf ){ sEdupBuf.zAlloc = pEdupBuf->zAlloc; #ifdef SQLITE_DEBUG sEdupBuf.zEnd = pEdupBuf->zEnd; #endif staticFlag = EP_Static; assert( sEdupBuf.zAlloc!=0 ); assert( dupFlags==EXPRDUP_REDUCE ); }else{ int nAlloc; if( dupFlags ){ nAlloc = dupedExprSize(p); }else if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ nToken = sqlite3Strlen30NN(p->u.zToken)+1; nAlloc = ROUND8(EXPR_FULLSIZE + nToken); }else{ nToken = 0; nAlloc = ROUND8(EXPR_FULLSIZE); } assert( nAlloc==ROUND8(nAlloc) ); sEdupBuf.zAlloc = sqlite3DbMallocRawNN(db, nAlloc); #ifdef SQLITE_DEBUG sEdupBuf.zEnd = sEdupBuf.zAlloc ? sEdupBuf.zAlloc+nAlloc : 0; #endif staticFlag = 0; } pNew = (Expr *)sEdupBuf.zAlloc; assert( EIGHT_BYTE_ALIGNMENT(pNew) ); if( pNew ){ /* Set nNewSize to the size allocated for the structure pointed to ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed ** by the copy of the p->u.zToken string (if any). */ const unsigned nStructSize = dupedExprStructSize(p, dupFlags); int nNewSize = nStructSize & 0xfff; if( nToken<0 ){ if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ nToken = sqlite3Strlen30(p->u.zToken) + 1; }else{ nToken = 0; } } if( dupFlags ){ assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >= nNewSize+nToken ); assert( ExprHasProperty(p, EP_Reduced)==0 ); memcpy(sEdupBuf.zAlloc, p, nNewSize); }else{ u32 nSize = (u32)exprStructSize(p); assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >= (int)EXPR_FULLSIZE+nToken ); memcpy(sEdupBuf.zAlloc, p, nSize); if( nSizeflags &= ~(EP_Reduced|EP_TokenOnly|EP_Static); pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly); pNew->flags |= staticFlag; ExprClearVVAProperties(pNew); if( dupFlags ){ ExprSetVVAProperty(pNew, EP_Immutable); } /* Copy the p->u.zToken string, if any. */ assert( nToken>=0 ); if( nToken>0 ){ char *zToken = pNew->u.zToken = (char*)&sEdupBuf.zAlloc[nNewSize]; memcpy(zToken, p->u.zToken, nToken); nNewSize += nToken; } sEdupBuf.zAlloc += ROUND8(nNewSize); if( ((p->flags|pNew->flags)&(EP_TokenOnly|EP_Leaf))==0 ){ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ if( ExprUseXSelect(p) ){ pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); }else{ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, p->op!=TK_ORDER ? dupFlags : 0); } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(p, EP_WinFunc) ){ pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin); assert( ExprHasProperty(pNew, EP_WinFunc) ); } #endif /* SQLITE_OMIT_WINDOWFUNC */ /* Fill in pNew->pLeft and pNew->pRight. */ if( dupFlags ){ if( p->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; assert( p->pRight==0 || p->pRight==p->pLeft || ExprHasProperty(p->pLeft, EP_Subquery) ); }else{ pNew->pLeft = p->pLeft ? exprDup(db, p->pLeft, EXPRDUP_REDUCE, &sEdupBuf) : 0; } pNew->pRight = p->pRight ? exprDup(db, p->pRight, EXPRDUP_REDUCE, &sEdupBuf) : 0; }else{ if( p->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; assert( p->pRight==0 || p->pRight==p->pLeft || ExprHasProperty(p->pLeft, EP_Subquery) ); }else{ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0); } pNew->pRight = sqlite3ExprDup(db, p->pRight, 0); } } } if( pEdupBuf ) memcpy(pEdupBuf, &sEdupBuf, sizeof(sEdupBuf)); assert( sEdupBuf.zAlloc <= sEdupBuf.zEnd ); return pNew; } /* ** Create and return a deep copy of the object passed as the second ** argument. If an OOM condition is encountered, NULL is returned ** and the db->mallocFailed flag set. */ #ifndef SQLITE_OMIT_CTE SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){ With *pRet = 0; if( p ){ sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); pRet = sqlite3DbMallocZero(db, nByte); if( pRet ){ int i; pRet->nCte = p->nCte; for(i=0; inCte; i++){ pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0); pRet->a[i].pCols = sqlite3ExprListDup(db, p->a[i].pCols, 0); pRet->a[i].zName = sqlite3DbStrDup(db, p->a[i].zName); pRet->a[i].eM10d = p->a[i].eM10d; } } } return pRet; } #else # define sqlite3WithDup(x,y) 0 #endif #ifndef SQLITE_OMIT_WINDOWFUNC /* ** The gatherSelectWindows() procedure and its helper routine ** gatherSelectWindowsCallback() are used to scan all the expressions ** an a newly duplicated SELECT statement and gather all of the Window ** objects found there, assembling them onto the linked list at Select->pWin. */ static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_WinFunc) ){ Select *pSelect = pWalker->u.pSelect; Window *pWin = pExpr->y.pWin; assert( pWin ); assert( IsWindowFunc(pExpr) ); assert( pWin->ppThis==0 ); sqlite3WindowLink(pSelect, pWin); } return WRC_Continue; } static int gatherSelectWindowsSelectCallback(Walker *pWalker, Select *p){ return p==pWalker->u.pSelect ? WRC_Continue : WRC_Prune; } static void gatherSelectWindows(Select *p){ Walker w; w.xExprCallback = gatherSelectWindowsCallback; w.xSelectCallback = gatherSelectWindowsSelectCallback; w.xSelectCallback2 = 0; w.pParse = 0; w.u.pSelect = p; sqlite3WalkSelect(&w, p); } #endif /* ** The following group of routines make deep copies of expressions, ** expression lists, ID lists, and select statements. The copies can ** be deleted (by being passed to their respective ...Delete() routines) ** without effecting the originals. ** ** The expression list, ID, and source lists return by sqlite3ExprListDup(), ** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded ** by subsequent calls to sqlite*ListAppend() routines. ** ** Any tables that the SrcList might point to are not duplicated. ** ** The flags parameter contains a combination of the EXPRDUP_XXX flags. ** If the EXPRDUP_REDUCE flag is set, then the structure returned is a ** truncated version of the usual Expr structure that will be stored as ** part of the in-memory representation of the database schema. */ SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, const Expr *p, int flags){ assert( flags==0 || flags==EXPRDUP_REDUCE ); return p ? exprDup(db, p, flags, 0) : 0; } SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){ ExprList *pNew; struct ExprList_item *pItem; const struct ExprList_item *pOldItem; int i; Expr *pPriorSelectColOld = 0; Expr *pPriorSelectColNew = 0; assert( db!=0 ); if( p==0 ) return 0; pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p)); if( pNew==0 ) return 0; pNew->nExpr = p->nExpr; pNew->nAlloc = p->nAlloc; pItem = pNew->a; pOldItem = p->a; for(i=0; inExpr; i++, pItem++, pOldItem++){ Expr *pOldExpr = pOldItem->pExpr; Expr *pNewExpr; pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags); if( pOldExpr && pOldExpr->op==TK_SELECT_COLUMN && (pNewExpr = pItem->pExpr)!=0 ){ if( pNewExpr->pRight ){ pPriorSelectColOld = pOldExpr->pRight; pPriorSelectColNew = pNewExpr->pRight; pNewExpr->pLeft = pNewExpr->pRight; }else{ if( pOldExpr->pLeft!=pPriorSelectColOld ){ pPriorSelectColOld = pOldExpr->pLeft; pPriorSelectColNew = sqlite3ExprDup(db, pPriorSelectColOld, flags); pNewExpr->pRight = pPriorSelectColNew; } pNewExpr->pLeft = pPriorSelectColNew; } } pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName); pItem->fg = pOldItem->fg; pItem->fg.done = 0; pItem->u = pOldItem->u; } return pNew; } /* ** If cursors, triggers, views and subqueries are all omitted from ** the build, then none of the following routines, except for ** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes ** called with a NULL argument. */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \ || !defined(SQLITE_OMIT_SUBQUERY) SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){ SrcList *pNew; int i; int nByte; assert( db!=0 ); if( p==0 ) return 0; nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); pNew = sqlite3DbMallocRawNN(db, nByte ); if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; inSrc; i++){ SrcItem *pNewItem = &pNew->a[i]; const SrcItem *pOldItem = &p->a[i]; Table *pTab; pNewItem->pSchema = pOldItem->pSchema; pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->fg = pOldItem->fg; pNewItem->iCursor = pOldItem->iCursor; pNewItem->addrFillSub = pOldItem->addrFillSub; pNewItem->regReturn = pOldItem->regReturn; if( pNewItem->fg.isIndexedBy ){ pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); } pNewItem->u2 = pOldItem->u2; if( pNewItem->fg.isCte ){ pNewItem->u2.pCteUse->nUse++; } if( pNewItem->fg.isTabFunc ){ pNewItem->u1.pFuncArg = sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags); } pTab = pNewItem->pTab = pOldItem->pTab; if( pTab ){ pTab->nTabRef++; } pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags); if( pOldItem->fg.isUsing ){ assert( pNewItem->fg.isUsing ); pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing); }else{ pNewItem->u3.pOn = sqlite3ExprDup(db, pOldItem->u3.pOn, flags); } pNewItem->colUsed = pOldItem->colUsed; } return pNew; } SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){ IdList *pNew; int i; assert( db!=0 ); if( p==0 ) return 0; assert( p->eU4!=EU4_EXPR ); pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) ); if( pNew==0 ) return 0; pNew->nId = p->nId; pNew->eU4 = p->eU4; for(i=0; inId; i++){ struct IdList_item *pNewItem = &pNew->a[i]; const struct IdList_item *pOldItem = &p->a[i]; pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->u4 = pOldItem->u4; } return pNew; } SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int flags){ Select *pRet = 0; Select *pNext = 0; Select **pp = &pRet; const Select *p; assert( db!=0 ); for(p=pDup; p; p=p->pPrior){ Select *pNew = sqlite3DbMallocRawNN(db, sizeof(*p) ); if( pNew==0 ) break; pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags); pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags); pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags); pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags); pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags); pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags); pNew->op = p->op; pNew->pNext = pNext; pNew->pPrior = 0; pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); pNew->iLimit = 0; pNew->iOffset = 0; pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = p->nSelectRow; pNew->pWith = sqlite3WithDup(db, p->pWith); #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn); if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew); #endif pNew->selId = p->selId; if( db->mallocFailed ){ /* Any prior OOM might have left the Select object incomplete. ** Delete the whole thing rather than allow an incomplete Select ** to be used by the code generator. */ pNew->pNext = 0; sqlite3SelectDelete(db, pNew); break; } *pp = pNew; pp = &pNew->pPrior; pNext = pNew; } return pRet; } #else SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags){ assert( p==0 ); return 0; } #endif /* ** Add a new element to the end of an expression list. If pList is ** initially NULL, then create a new expression list. ** ** The pList argument must be either NULL or a pointer to an ExprList ** obtained from a prior call to sqlite3ExprListAppend(). ** ** If a memory allocation error occurs, the entire list is freed and ** NULL is returned. If non-NULL is returned, then it is guaranteed ** that the new entry was successfully appended. */ static const struct ExprList_item zeroItem = {0}; SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew( sqlite3 *db, /* Database handle. Used for memory allocation */ Expr *pExpr /* Expression to be appended. Might be NULL */ ){ struct ExprList_item *pItem; ExprList *pList; pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 ); if( pList==0 ){ sqlite3ExprDelete(db, pExpr); return 0; } pList->nAlloc = 4; pList->nExpr = 1; pItem = &pList->a[0]; *pItem = zeroItem; pItem->pExpr = pExpr; return pList; } SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow( sqlite3 *db, /* Database handle. Used for memory allocation */ ExprList *pList, /* List to which to append. Might be NULL */ Expr *pExpr /* Expression to be appended. Might be NULL */ ){ struct ExprList_item *pItem; ExprList *pNew; pList->nAlloc *= 2; pNew = sqlite3DbRealloc(db, pList, sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0])); if( pNew==0 ){ sqlite3ExprListDelete(db, pList); sqlite3ExprDelete(db, pExpr); return 0; }else{ pList = pNew; } pItem = &pList->a[pList->nExpr++]; *pItem = zeroItem; pItem->pExpr = pExpr; return pList; } SQLITE_PRIVATE ExprList *sqlite3ExprListAppend( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ Expr *pExpr /* Expression to be appended. Might be NULL */ ){ struct ExprList_item *pItem; if( pList==0 ){ return sqlite3ExprListAppendNew(pParse->db,pExpr); } if( pList->nAllocnExpr+1 ){ return sqlite3ExprListAppendGrow(pParse->db,pList,pExpr); } pItem = &pList->a[pList->nExpr++]; *pItem = zeroItem; pItem->pExpr = pExpr; return pList; } /* ** pColumns and pExpr form a vector assignment which is part of the SET ** clause of an UPDATE statement. Like this: ** ** (a,b,c) = (expr1,expr2,expr3) ** Or: (a,b,c) = (SELECT x,y,z FROM ....) ** ** For each term of the vector assignment, append new entries to the ** expression list pList. In the case of a subquery on the RHS, append ** TK_SELECT_COLUMN expressions. */ SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ IdList *pColumns, /* List of names of LHS of the assignment */ Expr *pExpr /* Vector expression to be appended. Might be NULL */ ){ sqlite3 *db = pParse->db; int n; int i; int iFirst = pList ? pList->nExpr : 0; /* pColumns can only be NULL due to an OOM but an OOM will cause an ** exit prior to this routine being invoked */ if( NEVER(pColumns==0) ) goto vector_append_error; if( pExpr==0 ) goto vector_append_error; /* If the RHS is a vector, then we can immediately check to see that ** the size of the RHS and LHS match. But if the RHS is a SELECT, ** wildcards ("*") in the result set of the SELECT must be expanded before ** we can do the size check, so defer the size check until code generation. */ if( pExpr->op!=TK_SELECT && pColumns->nId!=(n=sqlite3ExprVectorSize(pExpr)) ){ sqlite3ErrorMsg(pParse, "%d columns assigned %d values", pColumns->nId, n); goto vector_append_error; } for(i=0; inId; i++){ Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i, pColumns->nId); assert( pSubExpr!=0 || db->mallocFailed ); if( pSubExpr==0 ) continue; pList = sqlite3ExprListAppend(pParse, pList, pSubExpr); if( pList ){ assert( pList->nExpr==iFirst+i+1 ); pList->a[pList->nExpr-1].zEName = pColumns->a[i].zName; pColumns->a[i].zName = 0; } } if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){ Expr *pFirst = pList->a[iFirst].pExpr; assert( pFirst!=0 ); assert( pFirst->op==TK_SELECT_COLUMN ); /* Store the SELECT statement in pRight so it will be deleted when ** sqlite3ExprListDelete() is called */ pFirst->pRight = pExpr; pExpr = 0; /* Remember the size of the LHS in iTable so that we can check that ** the RHS and LHS sizes match during code generation. */ pFirst->iTable = pColumns->nId; } vector_append_error: sqlite3ExprUnmapAndDelete(pParse, pExpr); sqlite3IdListDelete(db, pColumns); return pList; } /* ** Set the sort order for the last element on the given ExprList. */ SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){ struct ExprList_item *pItem; if( p==0 ) return; assert( p->nExpr>0 ); assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC==0 && SQLITE_SO_DESC>0 ); assert( iSortOrder==SQLITE_SO_UNDEFINED || iSortOrder==SQLITE_SO_ASC || iSortOrder==SQLITE_SO_DESC ); assert( eNulls==SQLITE_SO_UNDEFINED || eNulls==SQLITE_SO_ASC || eNulls==SQLITE_SO_DESC ); pItem = &p->a[p->nExpr-1]; assert( pItem->fg.bNulls==0 ); if( iSortOrder==SQLITE_SO_UNDEFINED ){ iSortOrder = SQLITE_SO_ASC; } pItem->fg.sortFlags = (u8)iSortOrder; if( eNulls!=SQLITE_SO_UNDEFINED ){ pItem->fg.bNulls = 1; if( iSortOrder!=eNulls ){ pItem->fg.sortFlags |= KEYINFO_ORDER_BIGNULL; } } } /* ** Set the ExprList.a[].zEName element of the most recently added item ** on the expression list. ** ** pList might be NULL following an OOM error. But pName should never be ** NULL. If a memory allocation fails, the pParse->db->mallocFailed flag ** is set. */ SQLITE_PRIVATE void sqlite3ExprListSetName( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to add the span. */ const Token *pName, /* Name to be added */ int dequote /* True to cause the name to be dequoted */ ){ assert( pList!=0 || pParse->db->mallocFailed!=0 ); assert( pParse->eParseMode!=PARSE_MODE_UNMAP || dequote==0 ); if( pList ){ struct ExprList_item *pItem; assert( pList->nExpr>0 ); pItem = &pList->a[pList->nExpr-1]; assert( pItem->zEName==0 ); assert( pItem->fg.eEName==ENAME_NAME ); pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n); if( dequote ){ /* If dequote==0, then pName->z does not point to part of a DDL ** statement handled by the parser. And so no token need be added ** to the token-map. */ sqlite3Dequote(pItem->zEName); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (const void*)pItem->zEName, pName); } } } } /* ** Set the ExprList.a[].zSpan element of the most recently added item ** on the expression list. ** ** pList might be NULL following an OOM error. But pSpan should never be ** NULL. If a memory allocation fails, the pParse->db->mallocFailed flag ** is set. */ SQLITE_PRIVATE void sqlite3ExprListSetSpan( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to add the span. */ const char *zStart, /* Start of the span */ const char *zEnd /* End of the span */ ){ sqlite3 *db = pParse->db; assert( pList!=0 || db->mallocFailed!=0 ); if( pList ){ struct ExprList_item *pItem = &pList->a[pList->nExpr-1]; assert( pList->nExpr>0 ); if( pItem->zEName==0 ){ pItem->zEName = sqlite3DbSpanDup(db, zStart, zEnd); pItem->fg.eEName = ENAME_SPAN; } } } /* ** If the expression list pEList contains more than iLimit elements, ** leave an error message in pParse. */ SQLITE_PRIVATE void sqlite3ExprListCheckLength( Parse *pParse, ExprList *pEList, const char *zObject ){ int mx = pParse->db->aLimit[SQLITE_LIMIT_COLUMN]; testcase( pEList && pEList->nExpr==mx ); testcase( pEList && pEList->nExpr==mx+1 ); if( pEList && pEList->nExpr>mx ){ sqlite3ErrorMsg(pParse, "too many columns in %s", zObject); } } /* ** Delete an entire expression list. */ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){ int i = pList->nExpr; struct ExprList_item *pItem = pList->a; assert( pList->nExpr>0 ); assert( db!=0 ); do{ sqlite3ExprDelete(db, pItem->pExpr); if( pItem->zEName ) sqlite3DbNNFreeNN(db, pItem->zEName); pItem++; }while( --i>0 ); sqlite3DbNNFreeNN(db, pList); } SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ if( pList ) exprListDeleteNN(db, pList); } SQLITE_PRIVATE void sqlite3ExprListDeleteGeneric(sqlite3 *db, void *pList){ if( ALWAYS(pList) ) exprListDeleteNN(db, (ExprList*)pList); } /* ** Return the bitwise-OR of all Expr.flags fields in the given ** ExprList. */ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){ int i; u32 m = 0; assert( pList!=0 ); for(i=0; inExpr; i++){ Expr *pExpr = pList->a[i].pExpr; assert( pExpr!=0 ); m |= pExpr->flags; } return m; } /* ** This is a SELECT-node callback for the expression walker that ** always "fails". By "fail" in this case, we mean set ** pWalker->eCode to zero and abort. ** ** This callback is used by multiple expression walkers. */ SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){ UNUSED_PARAMETER(NotUsed); pWalker->eCode = 0; return WRC_Abort; } /* ** Check the input string to see if it is "true" or "false" (in any case). ** ** If the string is.... Return ** "true" EP_IsTrue ** "false" EP_IsFalse ** anything else 0 */ SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char *zIn){ if( sqlite3StrICmp(zIn, "true")==0 ) return EP_IsTrue; if( sqlite3StrICmp(zIn, "false")==0 ) return EP_IsFalse; return 0; } /* ** If the input expression is an ID with the name "true" or "false" ** then convert it into an TK_TRUEFALSE term. Return non-zero if ** the conversion happened, and zero if the expression is unaltered. */ SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){ u32 v; assert( pExpr->op==TK_ID || pExpr->op==TK_STRING ); if( !ExprHasProperty(pExpr, EP_Quoted|EP_IntValue) && (v = sqlite3IsTrueOrFalse(pExpr->u.zToken))!=0 ){ pExpr->op = TK_TRUEFALSE; ExprSetProperty(pExpr, v); return 1; } return 0; } /* ** The argument must be a TK_TRUEFALSE Expr node. Return 1 if it is TRUE ** and 0 if it is FALSE. */ SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr *pExpr){ pExpr = sqlite3ExprSkipCollateAndLikely((Expr*)pExpr); assert( pExpr->op==TK_TRUEFALSE ); assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0 || sqlite3StrICmp(pExpr->u.zToken,"false")==0 ); return pExpr->u.zToken[4]==0; } /* ** If pExpr is an AND or OR expression, try to simplify it by eliminating ** terms that are always true or false. Return the simplified expression. ** Or return the original expression if no simplification is possible. ** ** Examples: ** ** (x<10) AND true => (x<10) ** (x<10) AND false => false ** (x<10) AND (y=22 OR false) => (x<10) AND (y=22) ** (x<10) AND (y=22 OR true) => (x<10) ** (y=22) OR true => true */ SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){ assert( pExpr!=0 ); if( pExpr->op==TK_AND || pExpr->op==TK_OR ){ Expr *pRight = sqlite3ExprSimplifiedAndOr(pExpr->pRight); Expr *pLeft = sqlite3ExprSimplifiedAndOr(pExpr->pLeft); if( ExprAlwaysTrue(pLeft) || ExprAlwaysFalse(pRight) ){ pExpr = pExpr->op==TK_AND ? pRight : pLeft; }else if( ExprAlwaysTrue(pRight) || ExprAlwaysFalse(pLeft) ){ pExpr = pExpr->op==TK_AND ? pLeft : pRight; } } return pExpr; } /* ** These routines are Walker callbacks used to check expressions to ** see if they are "constant" for some definition of constant. The ** Walker.eCode value determines the type of "constant" we are looking ** for. ** ** These callback routines are used to implement the following: ** ** sqlite3ExprIsConstant() pWalker->eCode==1 ** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2 ** sqlite3ExprIsTableConstant() pWalker->eCode==3 ** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5 ** ** In all cases, the callbacks set Walker.eCode=0 and abort if the expression ** is found to not be a constant. ** ** The sqlite3ExprIsConstantOrFunction() is used for evaluating DEFAULT ** expressions in a CREATE TABLE statement. The Walker.eCode value is 5 ** when parsing an existing schema out of the sqlite_schema table and 4 ** when processing a new CREATE TABLE statement. A bound parameter raises ** an error for new statements, but is silently converted ** to NULL for existing schemas. This allows sqlite_schema tables that ** contain a bound parameter because they were generated by older versions ** of SQLite to be parsed by newer versions of SQLite without raising a ** malformed schema error. */ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ /* If pWalker->eCode is 2 then any term of the expression that comes from ** the ON or USING clauses of an outer join disqualifies the expression ** from being considered constant. */ if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_OuterON) ){ pWalker->eCode = 0; return WRC_Abort; } switch( pExpr->op ){ /* Consider functions to be constant if all their arguments are constant ** and either pWalker->eCode==4 or 5 or the function has the ** SQLITE_FUNC_CONST flag. */ case TK_FUNCTION: if( (pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc)) && !ExprHasProperty(pExpr, EP_WinFunc) ){ if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL); return WRC_Continue; }else{ pWalker->eCode = 0; return WRC_Abort; } case TK_ID: /* Convert "true" or "false" in a DEFAULT clause into the ** appropriate TK_TRUEFALSE operator */ if( sqlite3ExprIdToTrueFalse(pExpr) ){ return WRC_Prune; } /* no break */ deliberate_fall_through case TK_COLUMN: case TK_AGG_FUNCTION: case TK_AGG_COLUMN: testcase( pExpr->op==TK_ID ); testcase( pExpr->op==TK_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); testcase( pExpr->op==TK_AGG_COLUMN ); if( ExprHasProperty(pExpr, EP_FixedCol) && pWalker->eCode!=2 ){ return WRC_Continue; } if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){ return WRC_Continue; } /* no break */ deliberate_fall_through case TK_IF_NULL_ROW: case TK_REGISTER: case TK_DOT: testcase( pExpr->op==TK_REGISTER ); testcase( pExpr->op==TK_IF_NULL_ROW ); testcase( pExpr->op==TK_DOT ); pWalker->eCode = 0; return WRC_Abort; case TK_VARIABLE: if( pWalker->eCode==5 ){ /* Silently convert bound parameters that appear inside of CREATE ** statements into a NULL when parsing the CREATE statement text out ** of the sqlite_schema table */ pExpr->op = TK_NULL; }else if( pWalker->eCode==4 ){ /* A bound parameter in a CREATE statement that originates from ** sqlite3_prepare() causes an error */ pWalker->eCode = 0; return WRC_Abort; } /* no break */ deliberate_fall_through default: testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */ testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */ return WRC_Continue; } } static int exprIsConst(Expr *p, int initFlag, int iCur){ Walker w; w.eCode = initFlag; w.xExprCallback = exprNodeIsConstant; w.xSelectCallback = sqlite3SelectWalkFail; #ifdef SQLITE_DEBUG w.xSelectCallback2 = sqlite3SelectWalkAssert2; #endif w.u.iCur = iCur; sqlite3WalkExpr(&w, p); return w.eCode; } /* ** Walk an expression tree. Return non-zero if the expression is constant ** and 0 if it involves variables or function calls. ** ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){ return exprIsConst(p, 1, 0); } /* ** Walk an expression tree. Return non-zero if ** ** (1) the expression is constant, and ** (2) the expression does originate in the ON or USING clause ** of a LEFT JOIN, and ** (3) the expression does not contain any EP_FixedCol TK_COLUMN ** operands created by the constant propagation optimization. ** ** When this routine returns true, it indicates that the expression ** can be added to the pParse->pConstExpr list and evaluated once when ** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce(). */ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){ return exprIsConst(p, 2, 0); } /* ** Walk an expression tree. Return non-zero if the expression is constant ** for any single row of the table with cursor iCur. In other words, the ** expression must not refer to any non-deterministic function nor any ** table other than iCur. */ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){ return exprIsConst(p, 3, iCur); } /* ** Check pExpr to see if it is an constraint on the single data source ** pSrc = &pSrcList->a[iSrc]. In other words, check to see if pExpr ** constrains pSrc but does not depend on any other tables or data ** sources anywhere else in the query. Return true (non-zero) if pExpr ** is a constraint on pSrc only. ** ** This is an optimization. False negatives will perhaps cause slower ** queries, but false positives will yield incorrect answers. So when in ** doubt, return 0. ** ** To be an single-source constraint, the following must be true: ** ** (1) pExpr cannot refer to any table other than pSrc->iCursor. ** ** (2) pExpr cannot use subqueries or non-deterministic functions. ** ** (3) pSrc cannot be part of the left operand for a RIGHT JOIN. ** (Is there some way to relax this constraint?) ** ** (4) If pSrc is the right operand of a LEFT JOIN, then... ** (4a) pExpr must come from an ON clause.. ** (4b) and specifically the ON clause associated with the LEFT JOIN. ** ** (5) If pSrc is not the right operand of a LEFT JOIN or the left ** operand of a RIGHT JOIN, then pExpr must be from the WHERE ** clause, not an ON clause. ** ** (6) Either: ** ** (6a) pExpr does not originate in an ON or USING clause, or ** ** (6b) The ON or USING clause from which pExpr is derived is ** not to the left of a RIGHT JOIN (or FULL JOIN). ** ** Without this restriction, accepting pExpr as a single-table ** constraint might move the the ON/USING filter expression ** from the left side of a RIGHT JOIN over to the right side, ** which leads to incorrect answers. See also restriction (9) ** on push-down. */ SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint( Expr *pExpr, /* The constraint */ const SrcList *pSrcList, /* Complete FROM clause */ int iSrc /* Which element of pSrcList to use */ ){ const SrcItem *pSrc = &pSrcList->a[iSrc]; if( pSrc->fg.jointype & JT_LTORJ ){ return 0; /* rule (3) */ } if( pSrc->fg.jointype & JT_LEFT ){ if( !ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (4a) */ if( pExpr->w.iJoin!=pSrc->iCursor ) return 0; /* rule (4b) */ }else{ if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */ } if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) /* (6a) */ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (6b) */ ){ int jj; for(jj=0; jjw.iJoin==pSrcList->a[jj].iCursor ){ if( (pSrcList->a[jj].fg.jointype & JT_LTORJ)!=0 ){ return 0; /* restriction (6) */ } break; } } } return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */ } /* ** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy(). */ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ ExprList *pGroupBy = pWalker->u.pGroupBy; int i; /* Check if pExpr is identical to any GROUP BY term. If so, consider ** it constant. */ for(i=0; inExpr; i++){ Expr *p = pGroupBy->a[i].pExpr; if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){ CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p); if( sqlite3IsBinary(pColl) ){ return WRC_Prune; } } } /* Check if pExpr is a sub-select. If so, consider it variable. */ if( ExprUseXSelect(pExpr) ){ pWalker->eCode = 0; return WRC_Abort; } return exprNodeIsConstant(pWalker, pExpr); } /* ** Walk the expression tree passed as the first argument. Return non-zero ** if the expression consists entirely of constants or copies of terms ** in pGroupBy that sort with the BINARY collation sequence. ** ** This routine is used to determine if a term of the HAVING clause can ** be promoted into the WHERE clause. In order for such a promotion to work, ** the value of the HAVING clause term must be the same for all members of ** a "group". The requirement that the GROUP BY term must be BINARY ** assumes that no other collating sequence will have a finer-grained ** grouping than binary. In other words (A=B COLLATE binary) implies ** A=B in every other collating sequence. The requirement that the ** GROUP BY be BINARY is stricter than necessary. It would also work ** to promote HAVING clauses that use the same alternative collating ** sequence as the GROUP BY term, but that is much harder to check, ** alternative collating sequences are uncommon, and this is only an ** optimization, so we take the easy way out and simply require the ** GROUP BY to use the BINARY collating sequence. */ SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){ Walker w; w.eCode = 1; w.xExprCallback = exprNodeIsConstantOrGroupBy; w.xSelectCallback = 0; w.u.pGroupBy = pGroupBy; w.pParse = pParse; sqlite3WalkExpr(&w, p); return w.eCode; } /* ** Walk an expression tree for the DEFAULT field of a column definition ** in a CREATE TABLE statement. Return non-zero if the expression is ** acceptable for use as a DEFAULT. That is to say, return non-zero if ** the expression is constant or a function call with constant arguments. ** Return and 0 if there are any variables. ** ** isInit is true when parsing from sqlite_schema. isInit is false when ** processing a new CREATE TABLE statement. When isInit is true, parameters ** (such as ? or $abc) in the expression are converted into NULL. When ** isInit is false, parameters raise an error. Parameters should not be ** allowed in a CREATE TABLE statement, but some legacy versions of SQLite ** allowed it, so we need to support it when reading sqlite_schema for ** backwards compatibility. ** ** If isInit is true, set EP_FromDDL on every TK_FUNCTION node. ** ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ assert( isInit==0 || isInit==1 ); return exprIsConst(p, 4+isInit, 0); } #ifdef SQLITE_ENABLE_CURSOR_HINTS /* ** Walk an expression tree. Return 1 if the expression contains a ** subquery of some kind. Return 0 if there are no subqueries. */ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){ Walker w; w.eCode = 1; w.xExprCallback = sqlite3ExprWalkNoop; w.xSelectCallback = sqlite3SelectWalkFail; #ifdef SQLITE_DEBUG w.xSelectCallback2 = sqlite3SelectWalkAssert2; #endif sqlite3WalkExpr(&w, p); return w.eCode==0; } #endif /* ** If the expression p codes a constant integer that is small enough ** to fit in a 32-bit integer, return 1 and put the value of the integer ** in *pValue. If the expression is not an integer or if it is too big ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. */ SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr *p, int *pValue){ int rc = 0; if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */ /* If an expression is an integer literal that fits in a signed 32-bit ** integer, then the EP_IntValue flag will have already been set */ assert( p->op!=TK_INTEGER || (p->flags & EP_IntValue)!=0 || sqlite3GetInt32(p->u.zToken, &rc)==0 ); if( p->flags & EP_IntValue ){ *pValue = p->u.iValue; return 1; } switch( p->op ){ case TK_UPLUS: { rc = sqlite3ExprIsInteger(p->pLeft, pValue); break; } case TK_UMINUS: { int v = 0; if( sqlite3ExprIsInteger(p->pLeft, &v) ){ assert( ((unsigned int)v)!=0x80000000 ); *pValue = -v; rc = 1; } break; } default: break; } return rc; } /* ** Return FALSE if there is no chance that the expression can be NULL. ** ** If the expression might be NULL or if the expression is too complex ** to tell return TRUE. ** ** This routine is used as an optimization, to skip OP_IsNull opcodes ** when we know that a value cannot be NULL. Hence, a false positive ** (returning TRUE when in fact the expression can never be NULL) might ** be a small performance hit but is otherwise harmless. On the other ** hand, a false negative (returning FALSE when the result could be NULL) ** will likely result in an incorrect answer. So when in doubt, return ** TRUE. */ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ u8 op; assert( p!=0 ); while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; assert( p!=0 ); } op = p->op; if( op==TK_REGISTER ) op = p->op2; switch( op ){ case TK_INTEGER: case TK_STRING: case TK_FLOAT: case TK_BLOB: return 0; case TK_COLUMN: assert( ExprUseYTab(p) ); return ExprHasProperty(p, EP_CanBeNull) || NEVER(p->y.pTab==0) || /* Reference to column of index on expr */ (p->iColumn>=0 && p->y.pTab->aCol!=0 /* Possible due to prior error */ && ALWAYS(p->iColumny.pTab->nCol) && p->y.pTab->aCol[p->iColumn].notNull==0); default: return 1; } } /* ** Return TRUE if the given expression is a constant which would be ** unchanged by OP_Affinity with the affinity given in the second ** argument. ** ** This routine is used to determine if the OP_Affinity operation ** can be omitted. When in doubt return FALSE. A false negative ** is harmless. A false positive, however, can result in the wrong ** answer. */ SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr *p, char aff){ u8 op; int unaryMinus = 0; if( aff==SQLITE_AFF_BLOB ) return 1; while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ if( p->op==TK_UMINUS ) unaryMinus = 1; p = p->pLeft; } op = p->op; if( op==TK_REGISTER ) op = p->op2; switch( op ){ case TK_INTEGER: { return aff>=SQLITE_AFF_NUMERIC; } case TK_FLOAT: { return aff>=SQLITE_AFF_NUMERIC; } case TK_STRING: { return !unaryMinus && aff==SQLITE_AFF_TEXT; } case TK_BLOB: { return !unaryMinus; } case TK_COLUMN: { assert( p->iTable>=0 ); /* p cannot be part of a CHECK constraint */ return aff>=SQLITE_AFF_NUMERIC && p->iColumn<0; } default: { return 0; } } } /* ** Return TRUE if the given string is a row-id column name. */ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){ if( sqlite3StrICmp(z, "_ROWID_")==0 ) return 1; if( sqlite3StrICmp(z, "ROWID")==0 ) return 1; if( sqlite3StrICmp(z, "OID")==0 ) return 1; return 0; } /* ** Return a pointer to a buffer containing a usable rowid alias for table ** pTab. An alias is usable if there is not an explicit user-defined column ** of the same name. */ SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab){ const char *azOpt[] = {"_ROWID_", "ROWID", "OID"}; int ii; assert( VisibleRowid(pTab) ); for(ii=0; iinCol; iCol++){ if( sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break; } if( iCol==pTab->nCol ){ return azOpt[ii]; } } return 0; } /* ** pX is the RHS of an IN operator. If pX is a SELECT statement ** that can be simplified to a direct table access, then return ** a pointer to the SELECT statement. If pX is not a SELECT statement, ** or if the SELECT statement needs to be materialized into a transient ** table, then return NULL. */ #ifndef SQLITE_OMIT_SUBQUERY static Select *isCandidateForInOpt(const Expr *pX){ Select *p; SrcList *pSrc; ExprList *pEList; Table *pTab; int i; if( !ExprUseXSelect(pX) ) return 0; /* Not a subquery */ if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */ p = pX->x.pSelect; if( p->pPrior ) return 0; /* Not a compound SELECT */ if( p->selFlags & (SF_Distinct|SF_Aggregate) ){ testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate ); return 0; /* No DISTINCT keyword and no aggregate functions */ } assert( p->pGroupBy==0 ); /* Has no GROUP BY clause */ if( p->pLimit ) return 0; /* Has no LIMIT clause */ if( p->pWhere ) return 0; /* Has no WHERE clause */ pSrc = p->pSrc; assert( pSrc!=0 ); if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */ if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */ pTab = pSrc->a[0].pTab; assert( pTab!=0 ); assert( !IsView(pTab) ); /* FROM clause is not a view */ if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ pEList = p->pEList; assert( pEList!=0 ); /* All SELECT results must be columns. */ for(i=0; inExpr; i++){ Expr *pRes = pEList->a[i].pExpr; if( pRes->op!=TK_COLUMN ) return 0; assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */ } return p; } #endif /* SQLITE_OMIT_SUBQUERY */ #ifndef SQLITE_OMIT_SUBQUERY /* ** Generate code that checks the left-most column of index table iCur to see if ** it contains any NULL entries. Cause the register at regHasNull to be set ** to a non-NULL value if iCur contains no NULLs. Cause register regHasNull ** to be set to NULL if iCur contains one or more NULL values. */ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ int addr1; sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull); addr1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); VdbeComment((v, "first_entry_in(%d)", iCur)); sqlite3VdbeJumpHere(v, addr1); } #endif #ifndef SQLITE_OMIT_SUBQUERY /* ** The argument is an IN operator with a list (not a subquery) on the ** right-hand side. Return TRUE if that list is constant. */ static int sqlite3InRhsIsConstant(Expr *pIn){ Expr *pLHS; int res; assert( !ExprHasProperty(pIn, EP_xIsSelect) ); pLHS = pIn->pLeft; pIn->pLeft = 0; res = sqlite3ExprIsConstant(pIn); pIn->pLeft = pLHS; return res; } #endif /* ** This function is used by the implementation of the IN (...) operator. ** The pX parameter is the expression on the RHS of the IN operator, which ** might be either a list of expressions or a subquery. ** ** The job of this routine is to find or create a b-tree object that can ** be used either to test for membership in the RHS set or to iterate through ** all members of the RHS set, skipping duplicates. ** ** A cursor is opened on the b-tree object that is the RHS of the IN operator ** and the *piTab parameter is set to the index of that cursor. ** ** The returned value of this function indicates the b-tree type, as follows: ** ** IN_INDEX_ROWID - The cursor was opened on a database table. ** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index. ** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index. ** IN_INDEX_EPH - The cursor was opened on a specially created and ** populated ephemeral table. ** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be ** implemented as a sequence of comparisons. ** ** An existing b-tree might be used if the RHS expression pX is a simple ** subquery such as: ** ** SELECT , ... FROM ** ** If the RHS of the IN operator is a list or a more complex subquery, then ** an ephemeral table might need to be generated from the RHS and then ** pX->iTable made to point to the ephemeral table instead of an ** existing table. In this case, the creation and initialization of the ** ephemeral table might be put inside of a subroutine, the EP_Subrtn flag ** will be set on pX and the pX->y.sub fields will be set to show where ** the subroutine is coded. ** ** The inFlags parameter must contain, at a minimum, one of the bits ** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP but not both. If inFlags contains ** IN_INDEX_MEMBERSHIP, then the generated table will be used for a fast ** membership test. When the IN_INDEX_LOOP bit is set, the IN index will ** be used to loop over all values of the RHS of the IN operator. ** ** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate ** through the set members) then the b-tree must not contain duplicates. ** An ephemeral table will be created unless the selected columns are guaranteed ** to be unique - either because it is an INTEGER PRIMARY KEY or due to ** a UNIQUE constraint or index. ** ** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used ** for fast set membership tests) then an ephemeral table must ** be used unless is a single INTEGER PRIMARY KEY column or an ** index can be found with the specified as its left-most. ** ** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and ** if the RHS of the IN operator is a list (not a subquery) then this ** routine might decide that creating an ephemeral b-tree for membership ** testing is too expensive and return IN_INDEX_NOOP. In that case, the ** calling routine should implement the IN operator using a sequence ** of Eq or Ne comparison operations. ** ** When the b-tree is being used for membership tests, the calling function ** might need to know whether or not the RHS side of the IN operator ** contains a NULL. If prRhsHasNull is not a NULL pointer and ** if there is any chance that the (...) might contain a NULL value at ** runtime, then a register is allocated and the register number written ** to *prRhsHasNull. If there is no chance that the (...) contains a ** NULL value, then *prRhsHasNull is left unchanged. ** ** If a register is allocated and its location stored in *prRhsHasNull, then ** the value in that register will be NULL if the b-tree contains one or more ** NULL values, and it will be some non-NULL value if the b-tree contains no ** NULL values. ** ** If the aiMap parameter is not NULL, it must point to an array containing ** one element for each column returned by the SELECT statement on the RHS ** of the IN(...) operator. The i'th entry of the array is populated with the ** offset of the index column that matches the i'th column returned by the ** SELECT. For example, if the expression and selected index are: ** ** (?,?,?) IN (SELECT a, b, c FROM t1) ** CREATE INDEX i1 ON t1(b, c, a); ** ** then aiMap[] is populated with {2, 0, 1}. */ #ifndef SQLITE_OMIT_SUBQUERY SQLITE_PRIVATE int sqlite3FindInIndex( Parse *pParse, /* Parsing context */ Expr *pX, /* The IN expression */ u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */ int *prRhsHasNull, /* Register holding NULL status. See notes */ int *aiMap, /* Mapping from Index fields to RHS fields */ int *piTab /* OUT: index to use */ ){ Select *p; /* SELECT to the right of IN operator */ int eType = 0; /* Type of RHS table. IN_INDEX_* */ int iTab; /* Cursor of the RHS table */ int mustBeUnique; /* True if RHS must be unique */ Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */ assert( pX->op==TK_IN ); mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0; iTab = pParse->nTab++; /* If the RHS of this IN(...) operator is a SELECT, and if it matters ** whether or not the SELECT result contains NULL values, check whether ** or not NULL is actually possible (it may not be, for example, due ** to NOT NULL constraints in the schema). If no NULL values are possible, ** set prRhsHasNull to 0 before continuing. */ if( prRhsHasNull && ExprUseXSelect(pX) ){ int i; ExprList *pEList = pX->x.pSelect->pEList; for(i=0; inExpr; i++){ if( sqlite3ExprCanBeNull(pEList->a[i].pExpr) ) break; } if( i==pEList->nExpr ){ prRhsHasNull = 0; } } /* Check to see if an existing table or index can be used to ** satisfy the query. This is preferable to generating a new ** ephemeral table. */ if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){ sqlite3 *db = pParse->db; /* Database connection */ Table *pTab; /* Table
    . */ int iDb; /* Database idx for pTab */ ExprList *pEList = p->pEList; int nExpr = pEList->nExpr; assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */ pTab = p->pSrc->a[0].pTab; /* Code an OP_Transaction and OP_TableLock for
    . */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 && iDbtnum, 0, pTab->zName); assert(v); /* sqlite3GetVdbe() has always been previously called */ if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){ /* The "x IN (SELECT rowid FROM table)" case */ int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; ExplainQueryPlan((pParse, 0, "USING ROWID SEARCH ON TABLE %s FOR IN-OPERATOR",pTab->zName)); sqlite3VdbeJumpHere(v, iAddr); }else{ Index *pIdx; /* Iterator variable */ int affinity_ok = 1; int i; /* Check that the affinity that will be used to perform each ** comparison is the same as the affinity of each column in table ** on the RHS of the IN operator. If it not, it is not possible to ** use any index of the RHS table. */ for(i=0; ipLeft, i); int iCol = pEList->a[i].pExpr->iColumn; char idxaff = sqlite3TableColumnAffinity(pTab,iCol); /* RHS table */ char cmpaff = sqlite3CompareAffinity(pLhs, idxaff); testcase( cmpaff==SQLITE_AFF_BLOB ); testcase( cmpaff==SQLITE_AFF_TEXT ); switch( cmpaff ){ case SQLITE_AFF_BLOB: break; case SQLITE_AFF_TEXT: /* sqlite3CompareAffinity() only returns TEXT if one side or the ** other has no affinity and the other side is TEXT. Hence, ** the only way for cmpaff to be TEXT is for idxaff to be TEXT ** and for the term on the LHS of the IN to have no affinity. */ assert( idxaff==SQLITE_AFF_TEXT ); break; default: affinity_ok = sqlite3IsNumericAffinity(idxaff); } } if( affinity_ok ){ /* Search for an existing index that will work for this IN operator */ for(pIdx=pTab->pIndex; pIdx && eType==0; pIdx=pIdx->pNext){ Bitmask colUsed; /* Columns of the index used */ Bitmask mCol; /* Mask for the current column */ if( pIdx->nColumnpPartIdxWhere!=0 ) continue; /* Maximum nColumn is BMS-2, not BMS-1, so that we can compute ** BITMASK(nExpr) without overflowing */ testcase( pIdx->nColumn==BMS-2 ); testcase( pIdx->nColumn==BMS-1 ); if( pIdx->nColumn>=BMS-1 ) continue; if( mustBeUnique ){ if( pIdx->nKeyCol>nExpr ||(pIdx->nColumn>nExpr && !IsUniqueIndex(pIdx)) ){ continue; /* This index is not unique over the IN RHS columns */ } } colUsed = 0; /* Columns of index used so far */ for(i=0; ipLeft, i); Expr *pRhs = pEList->a[i].pExpr; CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); int j; for(j=0; jaiColumn[j]!=pRhs->iColumn ) continue; assert( pIdx->azColl[j] ); if( pReq!=0 && sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ){ continue; } break; } if( j==nExpr ) break; mCol = MASKBIT(j); if( mCol & colUsed ) break; /* Each column used only once */ colUsed |= mCol; if( aiMap ) aiMap[i] = j; } assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) ); if( colUsed==(MASKBIT(nExpr)-1) ){ /* If we reach this point, that means the index pIdx is usable */ int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); ExplainQueryPlan((pParse, 0, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName)); sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; if( prRhsHasNull ){ #ifdef SQLITE_ENABLE_COLUMN_USED_MASK i64 mask = (1<nMem; if( nExpr==1 ){ sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); } } sqlite3VdbeJumpHere(v, iAddr); } } /* End loop over indexes */ } /* End if( affinity_ok ) */ } /* End if not an rowid index */ } /* End attempt to optimize using an index */ /* If no preexisting index is available for the IN clause ** and IN_INDEX_NOOP is an allowed reply ** and the RHS of the IN operator is a list, not a subquery ** and the RHS is not constant or has two or fewer terms, ** then it is not worth creating an ephemeral table to evaluate ** the IN operator so return IN_INDEX_NOOP. */ if( eType==0 && (inFlags & IN_INDEX_NOOP_OK) && ExprUseXList(pX) && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) ){ pParse->nTab--; /* Back out the allocation of the unused cursor */ iTab = -1; /* Cursor is not allocated */ eType = IN_INDEX_NOOP; } if( eType==0 ){ /* Could not find an existing table or index to use as the RHS b-tree. ** We will have to generate an ephemeral table to do the job. */ u32 savedNQueryLoop = pParse->nQueryLoop; int rMayHaveNull = 0; eType = IN_INDEX_EPH; if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; }else if( prRhsHasNull ){ *prRhsHasNull = rMayHaveNull = ++pParse->nMem; } assert( pX->op==TK_IN ); sqlite3CodeRhsOfIN(pParse, pX, iTab); if( rMayHaveNull ){ sqlite3SetHasNullFlag(v, iTab, rMayHaveNull); } pParse->nQueryLoop = savedNQueryLoop; } if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){ int i, n; n = sqlite3ExprVectorSize(pX->pLeft); for(i=0; ipLeft; int nVal = sqlite3ExprVectorSize(pLeft); Select *pSelect = ExprUseXSelect(pExpr) ? pExpr->x.pSelect : 0; char *zRet; assert( pExpr->op==TK_IN ); zRet = sqlite3DbMallocRaw(pParse->db, nVal+1); if( zRet ){ int i; for(i=0; ipEList->a[i].pExpr, a); }else{ zRet[i] = a; } } zRet[nVal] = '\0'; } return zRet; } #endif #ifndef SQLITE_OMIT_SUBQUERY /* ** Load the Parse object passed as the first argument with an error ** message of the form: ** ** "sub-select returns N columns - expected M" */ SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){ if( pParse->nErr==0 ){ const char *zFmt = "sub-select returns %d columns - expected %d"; sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect); } } #endif /* ** Expression pExpr is a vector that has been used in a context where ** it is not permitted. If pExpr is a sub-select vector, this routine ** loads the Parse object with a message of the form: ** ** "sub-select returns N columns - expected 1" ** ** Or, if it is a regular scalar vector: ** ** "row value misused" */ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ #ifndef SQLITE_OMIT_SUBQUERY if( ExprUseXSelect(pExpr) ){ sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1); }else #endif { sqlite3ErrorMsg(pParse, "row value misused"); } } #ifndef SQLITE_OMIT_SUBQUERY /* ** Generate code that will construct an ephemeral table containing all terms ** in the RHS of an IN operator. The IN operator can be in either of two ** forms: ** ** x IN (4,5,11) -- IN operator with list on right-hand side ** x IN (SELECT a FROM b) -- IN operator with subquery on the right ** ** The pExpr parameter is the IN operator. The cursor number for the ** constructed ephemeral table is returned. The first time the ephemeral ** table is computed, the cursor number is also stored in pExpr->iTable, ** however the cursor number returned might not be the same, as it might ** have been duplicated using OP_OpenDup. ** ** If the LHS expression ("x" in the examples) is a column value, or ** the SELECT statement returns a column value, then the affinity of that ** column is used to build the index keys. If both 'x' and the ** SELECT... statement are columns, then numeric affinity is used ** if either column has NUMERIC or INTEGER affinity. If neither ** 'x' nor the SELECT... statement are columns, then numeric affinity ** is used. */ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The IN operator */ int iTab /* Use this cursor number */ ){ int addrOnce = 0; /* Address of the OP_Once instruction at top */ int addr; /* Address of OP_OpenEphemeral instruction */ Expr *pLeft; /* the LHS of the IN operator */ KeyInfo *pKeyInfo = 0; /* Key information */ int nVal; /* Size of vector pLeft */ Vdbe *v; /* The prepared statement under construction */ v = pParse->pVdbe; assert( v!=0 ); /* The evaluation of the IN must be repeated every time it ** is encountered if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger ** ** If all of the above are false, then we can compute the RHS just once ** and reuse it many names. */ if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){ /* Reuse of the RHS is allowed */ /* If this routine has already been coded, but the previous code ** might not have been invoked yet, so invoke it now as a subroutine. */ if( ExprHasProperty(pExpr, EP_Subrtn) ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); if( ExprUseXSelect(pExpr) ){ ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d", pExpr->x.pSelect->selId)); } assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); assert( iTab!=pExpr->iTable ); sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable); sqlite3VdbeJumpHere(v, addrOnce); return; } /* Begin coding the subroutine */ assert( !ExprUseYWin(pExpr) ); ExprSetProperty(pExpr, EP_Subrtn); assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); pExpr->y.sub.regReturn = ++pParse->nMem; pExpr->y.sub.iAddr = sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1; addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } /* Check to see if this is a vector IN operator */ pLeft = pExpr->pLeft; nVal = sqlite3ExprVectorSize(pLeft); /* Construct the ephemeral table that will contain the content of ** RHS of the IN operator. */ pExpr->iTable = iTab; addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, nVal); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS if( ExprUseXSelect(pExpr) ){ VdbeComment((v, "Result of SELECT %u", pExpr->x.pSelect->selId)); }else{ VdbeComment((v, "RHS of IN operator")); } #endif pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1); if( ExprUseXSelect(pExpr) ){ /* Case 1: expr IN (SELECT ...) ** ** Generate code to write the results of the select into the temporary ** table allocated and opened above. */ Select *pSelect = pExpr->x.pSelect; ExprList *pEList = pSelect->pEList; ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY %d", addrOnce?"":"CORRELATED ", pSelect->selId )); /* If the LHS and RHS of the IN operator do not match, that ** error will have been caught long before we reach this point. */ if( ALWAYS(pEList->nExpr==nVal) ){ Select *pCopy; SelectDest dest; int i; int rc; sqlite3SelectDestInit(&dest, SRT_Set, iTab); dest.zAffSdst = exprINAffinity(pParse, pExpr); pSelect->iLimit = 0; testcase( pSelect->selFlags & SF_Distinct ); testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); sqlite3SelectDelete(pParse->db, pCopy); sqlite3DbFree(pParse->db, dest.zAffSdst); if( rc ){ sqlite3KeyInfoUnref(pKeyInfo); return; } assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ assert( pEList!=0 ); assert( pEList->nExpr>0 ); assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); for(i=0; iaColl[i] = sqlite3BinaryCompareCollSeq( pParse, p, pEList->a[i].pExpr ); } } }else if( ALWAYS(pExpr->x.pList!=0) ){ /* Case 2: expr IN (exprlist) ** ** For each expression, build an index key from the evaluation and ** store it in the temporary table. If is a column, then use ** that columns affinity when building index keys. If is not ** a column, use numeric affinity. */ char affinity; /* Affinity of the LHS of the IN */ int i; ExprList *pList = pExpr->x.pList; struct ExprList_item *pItem; int r1, r2; affinity = sqlite3ExprAffinity(pLeft); if( affinity<=SQLITE_AFF_NONE ){ affinity = SQLITE_AFF_BLOB; }else if( affinity==SQLITE_AFF_REAL ){ affinity = SQLITE_AFF_NUMERIC; } if( pKeyInfo ){ assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); } /* Loop through each expression in . */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; /* If the expression is not constant then we will need to ** disable the test that was generated above that makes sure ** this code only executes once. Because for a non-constant ** expression we need to rerun this code each time. */ if( addrOnce && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, addrOnce-1); sqlite3VdbeChangeToNoop(v, addrOnce); ExprClearProperty(pExpr, EP_Subrtn); addrOnce = 0; } /* Evaluate the expression and insert it into the temp table */ sqlite3ExprCode(pParse, pE2, r1); sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r1, 1); } sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } if( pKeyInfo ){ sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); } if( addrOnce ){ sqlite3VdbeAddOp1(v, OP_NullRow, iTab); sqlite3VdbeJumpHere(v, addrOnce); /* Subroutine return */ assert( ExprUseYSub(pExpr) ); assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn || pParse->nErr ); sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr, 1); VdbeCoverage(v); sqlite3ClearTempRegCache(pParse); } } #endif /* SQLITE_OMIT_SUBQUERY */ /* ** Generate code for scalar subqueries used as a subquery expression ** or EXISTS operator: ** ** (SELECT a FROM b) -- subquery ** EXISTS (SELECT a FROM b) -- EXISTS subquery ** ** The pExpr parameter is the SELECT or EXISTS operator to be coded. ** ** Return the register that holds the result. For a multi-column SELECT, ** the result is stored in a contiguous array of registers and the ** return value is the register of the left-most result column. ** Return 0 if an error occurs. */ #ifndef SQLITE_OMIT_SUBQUERY SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ int addrOnce = 0; /* Address of OP_Once at top of subroutine */ int rReg = 0; /* Register storing resulting */ Select *pSel; /* SELECT statement to encode */ SelectDest dest; /* How to deal with SELECT result */ int nReg; /* Registers to allocate */ Expr *pLimit; /* New limit expression */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrExplain; /* Address of OP_Explain instruction */ #endif Vdbe *v = pParse->pVdbe; assert( v!=0 ); if( pParse->nErr ) return 0; testcase( pExpr->op==TK_EXISTS ); testcase( pExpr->op==TK_SELECT ); assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); assert( ExprUseXSelect(pExpr) ); pSel = pExpr->x.pSelect; /* If this routine has already been coded, then invoke it as a ** subroutine. */ if( ExprHasProperty(pExpr, EP_Subrtn) ){ ExplainQueryPlan((pParse, 0, "REUSE SUBQUERY %d", pSel->selId)); assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); return pExpr->iTable; } /* Begin coding the subroutine */ assert( !ExprUseYWin(pExpr) ); assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) ); ExprSetProperty(pExpr, EP_Subrtn); pExpr->y.sub.regReturn = ++pParse->nMem; pExpr->y.sub.iAddr = sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1; /* The evaluation of the EXISTS/SELECT must be repeated every time it ** is encountered if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger ** ** If all of the above are false, then we can run this code just once ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasProperty(pExpr, EP_VarSelect) ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } /* For a SELECT, generate code to put the values for all columns of ** the first row into an array of registers and return the index of ** the first register. ** ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists) ** into a register and return that register number. ** ** In both cases, the query is augmented with "LIMIT 1". Any ** preexisting limit is discarded in place of the new LIMIT 1. */ ExplainQueryPlan2(addrExplain, (pParse, 1, "%sSCALAR SUBQUERY %d", addrOnce?"":"CORRELATED ", pSel->selId)); sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, -1); nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); pParse->nMem += nReg; if( pExpr->op==TK_SELECT ){ dest.eDest = SRT_Mem; dest.iSdst = dest.iSDParm; dest.nSdst = nReg; sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1); VdbeComment((v, "Init subquery result")); }else{ dest.eDest = SRT_Exists; sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm); VdbeComment((v, "Init EXISTS result")); } if( pSel->pLimit ){ /* The subquery already has a limit. If the pre-existing limit is X ** then make the new limit X<>0 so that the new limit is either 1 or 0 */ sqlite3 *db = pParse->db; pLimit = sqlite3Expr(db, TK_INTEGER, "0"); if( pLimit ){ pLimit->affExpr = SQLITE_AFF_NUMERIC; pLimit = sqlite3PExpr(pParse, TK_NE, sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit); } sqlite3ExprDeferredDelete(pParse, pSel->pLimit->pLeft); pSel->pLimit->pLeft = pLimit; }else{ /* If there is no pre-existing limit add a limit of 1 */ pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1"); pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0); } pSel->iLimit = 0; if( sqlite3Select(pParse, pSel, &dest) ){ pExpr->op2 = pExpr->op; pExpr->op = TK_ERROR; return 0; } pExpr->iTable = rReg = dest.iSDParm; ExprSetVVAProperty(pExpr, EP_NoReduce); if( addrOnce ){ sqlite3VdbeJumpHere(v, addrOnce); } sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); /* Subroutine return */ assert( ExprUseYSub(pExpr) ); assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn || pParse->nErr ); sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr, 1); VdbeCoverage(v); sqlite3ClearTempRegCache(pParse); return rReg; } #endif /* SQLITE_OMIT_SUBQUERY */ #ifndef SQLITE_OMIT_SUBQUERY /* ** Expr pIn is an IN(...) expression. This function checks that the ** sub-select on the RHS of the IN() operator has the same number of ** columns as the vector on the LHS. Or, if the RHS of the IN() is not ** a sub-query, that the LHS is a vector of size 1. */ SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){ int nVector = sqlite3ExprVectorSize(pIn->pLeft); if( ExprUseXSelect(pIn) && !pParse->db->mallocFailed ){ if( nVector!=pIn->x.pSelect->pEList->nExpr ){ sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector); return 1; } }else if( nVector!=1 ){ sqlite3VectorErrorMsg(pParse, pIn->pLeft); return 1; } return 0; } #endif #ifndef SQLITE_OMIT_SUBQUERY /* ** Generate code for an IN expression. ** ** x IN (SELECT ...) ** x IN (value, value, ...) ** ** The left-hand side (LHS) is a scalar or vector expression. The ** right-hand side (RHS) is an array of zero or more scalar values, or a ** subquery. If the RHS is a subquery, the number of result columns must ** match the number of columns in the vector on the LHS. If the RHS is ** a list of values, the LHS must be a scalar. ** ** The IN operator is true if the LHS value is contained within the RHS. ** The result is false if the LHS is definitely not in the RHS. The ** result is NULL if the presence of the LHS in the RHS cannot be ** determined due to NULLs. ** ** This routine generates code that jumps to destIfFalse if the LHS is not ** contained within the RHS. If due to NULLs we cannot determine if the LHS ** is contained in the RHS then jump to destIfNull. If the LHS is contained ** within the RHS then fall through. ** ** See the separate in-operator.md documentation file in the canonical ** SQLite source tree for additional information. */ static void sqlite3ExprCodeIN( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* The IN expression */ int destIfFalse, /* Jump here if LHS is not contained in the RHS */ int destIfNull /* Jump here if the results are unknown due to NULLs */ ){ int rRhsHasNull = 0; /* Register that is true if RHS contains NULL values */ int eType; /* Type of the RHS */ int rLhs; /* Register(s) holding the LHS values */ int rLhsOrig; /* LHS values prior to reordering by aiMap[] */ Vdbe *v; /* Statement under construction */ int *aiMap = 0; /* Map from vector field to index column */ char *zAff = 0; /* Affinity string for comparisons */ int nVector; /* Size of vectors for this IN operator */ int iDummy; /* Dummy parameter to exprCodeVector() */ Expr *pLeft; /* The LHS of the IN operator */ int i; /* loop counter */ int destStep2; /* Where to jump when NULLs seen in step 2 */ int destStep6 = 0; /* Start of code for Step 6 */ int addrTruthOp; /* Address of opcode that determines the IN is true */ int destNotNull; /* Jump here if a comparison is not true in step 6 */ int addrTop; /* Top of the step-6 loop */ int iTab = 0; /* Index to use */ u8 okConstFactor = pParse->okConstFactor; assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); pLeft = pExpr->pLeft; if( sqlite3ExprCheckIN(pParse, pExpr) ) return; zAff = exprINAffinity(pParse, pExpr); nVector = sqlite3ExprVectorSize(pExpr->pLeft); aiMap = (int*)sqlite3DbMallocZero( pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1 ); if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; /* Attempt to compute the RHS. After this step, if anything other than ** IN_INDEX_NOOP is returned, the table opened with cursor iTab ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned, ** the RHS has not yet been coded. */ v = pParse->pVdbe; assert( v!=0 ); /* OOM detected prior to this routine */ VdbeNoopComment((v, "begin IN expr")); eType = sqlite3FindInIndex(pParse, pExpr, IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK, destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap, &iTab); assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC ); #ifdef SQLITE_DEBUG /* Confirm that aiMap[] contains nVector integer values between 0 and ** nVector-1. */ for(i=0; i from " IN (...)". If the LHS is a ** vector, then it is stored in an array of nVector registers starting ** at r1. ** ** sqlite3FindInIndex() might have reordered the fields of the LHS vector ** so that the fields are in the same order as an existing index. The ** aiMap[] array contains a mapping from the original LHS field order to ** the field order that matches the RHS index. ** ** Avoid factoring the LHS of the IN(...) expression out of the loop, ** even if it is constant, as OP_Affinity may be used on the register ** by code generated below. */ assert( pParse->okConstFactor==okConstFactor ); pParse->okConstFactor = 0; rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy); pParse->okConstFactor = okConstFactor; for(i=0; ix.pList; pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); if( destIfNull!=destIfFalse ){ regCkNull = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull); } for(ii=0; iinExpr; ii++){ r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree); if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){ sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull); } sqlite3ReleaseTempReg(pParse, regToFree); if( iinExpr-1 || destIfNull!=destIfFalse ){ int op = rLhs!=r2 ? OP_Eq : OP_NotNull; sqlite3VdbeAddOp4(v, op, rLhs, labelOk, r2, (void*)pColl, P4_COLLSEQ); VdbeCoverageIf(v, iinExpr-1 && op==OP_Eq); VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_Eq); VdbeCoverageIf(v, iinExpr-1 && op==OP_NotNull); VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_NotNull); sqlite3VdbeChangeP5(v, zAff[0]); }else{ int op = rLhs!=r2 ? OP_Ne : OP_IsNull; assert( destIfNull==destIfFalse ); sqlite3VdbeAddOp4(v, op, rLhs, destIfFalse, r2, (void*)pColl, P4_COLLSEQ); VdbeCoverageIf(v, op==OP_Ne); VdbeCoverageIf(v, op==OP_IsNull); sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL); } } if( regCkNull ){ sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v); sqlite3VdbeGoto(v, destIfFalse); } sqlite3VdbeResolveLabel(v, labelOk); sqlite3ReleaseTempReg(pParse, regCkNull); goto sqlite3ExprCodeIN_finished; } /* Step 2: Check to see if the LHS contains any NULL columns. If the ** LHS does contain NULLs then the result must be either FALSE or NULL. ** We will then skip the binary search of the RHS. */ if( destIfNull==destIfFalse ){ destStep2 = destIfFalse; }else{ destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse); } for(i=0; ipLeft, i); if( pParse->nErr ) goto sqlite3ExprCodeIN_oom_error; if( sqlite3ExprCanBeNull(p) ){ sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2); VdbeCoverage(v); } } /* Step 3. The LHS is now known to be non-NULL. Do the binary search ** of the RHS using the LHS as a probe. If found, the result is ** true. */ if( eType==IN_INDEX_ROWID ){ /* In this case, the RHS is the ROWID of table b-tree and so we also ** know that the RHS is non-NULL. Hence, we combine steps 3 and 4 ** into a single opcode. */ sqlite3VdbeAddOp3(v, OP_SeekRowid, iTab, destIfFalse, rLhs); VdbeCoverage(v); addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */ }else{ sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); if( destIfFalse==destIfNull ){ /* Combine Step 3 and Step 5 into a single opcode */ sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse, rLhs, nVector); VdbeCoverage(v); goto sqlite3ExprCodeIN_finished; } /* Ordinary Step 3, for the case where FALSE and NULL are distinct */ addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, iTab, 0, rLhs, nVector); VdbeCoverage(v); } /* Step 4. If the RHS is known to be non-NULL and we did not find ** an match on the search above, then the result must be FALSE. */ if( rRhsHasNull && nVector==1 ){ sqlite3VdbeAddOp2(v, OP_NotNull, rRhsHasNull, destIfFalse); VdbeCoverage(v); } /* Step 5. If we do not care about the difference between NULL and ** FALSE, then just return false. */ if( destIfFalse==destIfNull ) sqlite3VdbeGoto(v, destIfFalse); /* Step 6: Loop through rows of the RHS. Compare each row to the LHS. ** If any comparison is NULL, then the result is NULL. If all ** comparisons are FALSE then the final result is FALSE. ** ** For a scalar LHS, it is sufficient to check just the first row ** of the RHS. */ if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6); addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, destIfFalse); VdbeCoverage(v); if( nVector>1 ){ destNotNull = sqlite3VdbeMakeLabel(pParse); }else{ /* For nVector==1, combine steps 6 and 7 by immediately returning ** FALSE if the first comparison is not NULL */ destNotNull = destIfFalse; } for(i=0; i1 ){ sqlite3VdbeResolveLabel(v, destNotNull); sqlite3VdbeAddOp2(v, OP_Next, iTab, addrTop+1); VdbeCoverage(v); /* Step 7: If we reach this point, we know that the result must ** be false. */ sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); } /* Jumps here in order to return true. */ sqlite3VdbeJumpHere(v, addrTruthOp); sqlite3ExprCodeIN_finished: if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs); VdbeComment((v, "end IN expr")); sqlite3ExprCodeIN_oom_error: sqlite3DbFree(pParse->db, aiMap); sqlite3DbFree(pParse->db, zAff); } #endif /* SQLITE_OMIT_SUBQUERY */ #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Generate an instruction that will put the floating point ** value described by z[0..n-1] into register iMem. ** ** The z[] string will probably not be zero-terminated. But the ** z[n] character is guaranteed to be something that does not look ** like the continuation of the number. */ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ if( ALWAYS(z!=0) ){ double value; sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ if( negateFlag ) value = -value; sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL); } } #endif /* ** Generate an instruction that will put the integer describe by ** text z[0..n-1] into register iMem. ** ** Expr.u.zToken is always UTF8 and zero-terminated. */ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ Vdbe *v = pParse->pVdbe; if( pExpr->flags & EP_IntValue ){ int i = pExpr->u.iValue; assert( i>=0 ); if( negFlag ) i = -i; sqlite3VdbeAddOp2(v, OP_Integer, i, iMem); }else{ int c; i64 value; const char *z = pExpr->u.zToken; assert( z!=0 ); c = sqlite3DecOrHexToI64(z, &value); if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){ #ifdef SQLITE_OMIT_FLOATING_POINT sqlite3ErrorMsg(pParse, "oversized integer: %s%#T", negFlag?"-":"",pExpr); #else #ifndef SQLITE_OMIT_HEX_INTEGER if( sqlite3_strnicmp(z,"0x",2)==0 ){ sqlite3ErrorMsg(pParse, "hex literal too big: %s%#T", negFlag?"-":"",pExpr); }else #endif { codeReal(v, z, negFlag, iMem); } #endif }else{ if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; } sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64); } } } /* Generate code that will load into register regOut a value that is ** appropriate for the iIdxCol-th column of index pIdx. */ SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn( Parse *pParse, /* The parsing context */ Index *pIdx, /* The index whose column is to be loaded */ int iTabCur, /* Cursor pointing to a table row */ int iIdxCol, /* The column of the index to be loaded */ int regOut /* Store the index column value in this register */ ){ i16 iTabCol = pIdx->aiColumn[iIdxCol]; if( iTabCol==XN_EXPR ){ assert( pIdx->aColExpr ); assert( pIdx->aColExpr->nExpr>iIdxCol ); pParse->iSelfTab = iTabCur + 1; sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut); pParse->iSelfTab = 0; }else{ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, iTabCol, regOut); } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* ** Generate code that will compute the value of generated column pCol ** and store the result in register regOut */ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn( Parse *pParse, /* Parsing context */ Table *pTab, /* Table containing the generated column */ Column *pCol, /* The generated column */ int regOut /* Put the result in this register */ ){ int iAddr; Vdbe *v = pParse->pVdbe; int nErr = pParse->nErr; assert( v!=0 ); assert( pParse->iSelfTab!=0 ); if( pParse->iSelfTab>0 ){ iAddr = sqlite3VdbeAddOp3(v, OP_IfNullRow, pParse->iSelfTab-1, 0, regOut); }else{ iAddr = 0; } sqlite3ExprCodeCopy(pParse, sqlite3ColumnExpr(pTab,pCol), regOut); if( pCol->affinity>=SQLITE_AFF_TEXT ){ sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1); } if( iAddr ) sqlite3VdbeJumpHere(v, iAddr); if( pParse->nErr>nErr ) pParse->db->errByteOffset = -1; } #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ /* ** Generate code to extract the value of the iCol-th column of a table. */ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable( Vdbe *v, /* Parsing context */ Table *pTab, /* The table containing the value */ int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */ int iCol, /* Index of the column to extract */ int regOut /* Extract the value into this register */ ){ Column *pCol; assert( v!=0 ); assert( pTab!=0 ); assert( iCol!=XN_EXPR ); if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); VdbeComment((v, "%s.rowid", pTab->zName)); }else{ int op; int x; if( IsVirtual(pTab) ){ op = OP_VColumn; x = iCol; #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){ Parse *pParse = sqlite3VdbeParser(v); if( pCol->colFlags & COLFLAG_BUSY ){ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zCnName); }else{ int savedSelfTab = pParse->iSelfTab; pCol->colFlags |= COLFLAG_BUSY; pParse->iSelfTab = iTabCur+1; sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, regOut); pParse->iSelfTab = savedSelfTab; pCol->colFlags &= ~COLFLAG_BUSY; } return; #endif }else if( !HasRowid(pTab) ){ testcase( iCol!=sqlite3TableColumnToStorage(pTab, iCol) ); x = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), iCol); op = OP_Column; }else{ x = sqlite3TableColumnToStorage(pTab,iCol); testcase( x!=iCol ); op = OP_Column; } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); sqlite3ColumnDefault(v, pTab, iCol, regOut); } } /* ** Generate code that will extract the iColumn-th column from ** table pTab and store the column value in register iReg. ** ** There must be an open cursor to pTab in iTable when this routine ** is called. If iColumn<0 then code is generated that extracts the rowid. */ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn( Parse *pParse, /* Parsing and code generating context */ Table *pTab, /* Description of the table we are reading from */ int iColumn, /* Index of the table column */ int iTable, /* The cursor pointing to the table */ int iReg, /* Store results here */ u8 p5 /* P5 value for OP_Column + FLAGS */ ){ assert( pParse->pVdbe!=0 ); assert( (p5 & (OPFLAG_NOCHNG|OPFLAG_TYPEOFARG|OPFLAG_LENGTHARG))==p5 ); assert( IsVirtual(pTab) || (p5 & OPFLAG_NOCHNG)==0 ); sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg); if( p5 ){ VdbeOp *pOp = sqlite3VdbeGetLastOp(pParse->pVdbe); if( pOp->opcode==OP_Column ) pOp->p5 = p5; if( pOp->opcode==OP_VColumn ) pOp->p5 = (p5 & OPFLAG_NOCHNG); } return iReg; } /* ** Generate code to move content from registers iFrom...iFrom+nReg-1 ** over to iTo..iTo+nReg-1. */ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); } /* ** Convert a scalar expression node to a TK_REGISTER referencing ** register iReg. The caller must ensure that iReg already contains ** the correct value for the expression. */ static void exprToRegister(Expr *pExpr, int iReg){ Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr); if( NEVER(p==0) ) return; p->op2 = p->op; p->op = TK_REGISTER; p->iTable = iReg; ExprClearProperty(p, EP_Skip); } /* ** Evaluate an expression (either a vector or a scalar expression) and store ** the result in contiguous temporary registers. Return the index of ** the first register used to store the result. ** ** If the returned result register is a temporary scalar, then also write ** that register number into *piFreeable. If the returned result register ** is not a temporary or if the expression is a vector set *piFreeable ** to 0. */ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){ int iResult; int nResult = sqlite3ExprVectorSize(p); if( nResult==1 ){ iResult = sqlite3ExprCodeTemp(pParse, p, piFreeable); }else{ *piFreeable = 0; if( p->op==TK_SELECT ){ #if SQLITE_OMIT_SUBQUERY iResult = 0; #else iResult = sqlite3CodeSubselect(pParse, p); #endif }else{ int i; iResult = pParse->nMem+1; pParse->nMem += nResult; assert( ExprUseXList(p) ); for(i=0; ix.pList->a[i].pExpr, i+iResult); } } } return iResult; } /* ** If the last opcode is a OP_Copy, then set the do-not-merge flag (p5) ** so that a subsequent copy will not be merged into this one. */ static void setDoNotMergeFlagOnCopy(Vdbe *v){ if( sqlite3VdbeGetLastOp(v)->opcode==OP_Copy ){ sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergeable */ } } /* ** Generate code to implement special SQL functions that are implemented ** in-line rather than by using the usual callbacks. */ static int exprCodeInlineFunction( Parse *pParse, /* Parsing context */ ExprList *pFarg, /* List of function arguments */ int iFuncId, /* Function ID. One of the INTFUNC_... values */ int target /* Store function result in this register */ ){ int nFarg; Vdbe *v = pParse->pVdbe; assert( v!=0 ); assert( pFarg!=0 ); nFarg = pFarg->nExpr; assert( nFarg>0 ); /* All in-line functions have at least one argument */ switch( iFuncId ){ case INLINEFUNC_coalesce: { /* Attempt a direct implementation of the built-in COALESCE() and ** IFNULL() functions. This avoids unnecessary evaluation of ** arguments past the first non-NULL argument. */ int endCoalesce = sqlite3VdbeMakeLabel(pParse); int i; assert( nFarg>=2 ); sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); for(i=1; ia[i].pExpr, target); } setDoNotMergeFlagOnCopy(v); sqlite3VdbeResolveLabel(v, endCoalesce); break; } case INLINEFUNC_iif: { Expr caseExpr; memset(&caseExpr, 0, sizeof(caseExpr)); caseExpr.op = TK_CASE; caseExpr.x.pList = pFarg; return sqlite3ExprCodeTarget(pParse, &caseExpr, target); } #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC case INLINEFUNC_sqlite_offset: { Expr *pArg = pFarg->a[0].pExpr; if( pArg->op==TK_COLUMN && pArg->iTable>=0 ){ sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } break; } #endif default: { /* The UNLIKELY() function is a no-op. The result is the value ** of the first argument. */ assert( nFarg==1 || nFarg==2 ); target = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target); break; } /*********************************************************************** ** Test-only SQL functions that are only usable if enabled ** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS */ #if !defined(SQLITE_UNTESTABLE) case INLINEFUNC_expr_compare: { /* Compare two expressions using sqlite3ExprCompare() */ assert( nFarg==2 ); sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprCompare(0,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1), target); break; } case INLINEFUNC_expr_implies_expr: { /* Compare two expressions using sqlite3ExprImpliesExpr() */ assert( nFarg==2 ); sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprImpliesExpr(pParse,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1), target); break; } case INLINEFUNC_implies_nonnull_row: { /* Result of sqlite3ExprImpliesNonNullRow() */ Expr *pA1; assert( nFarg==2 ); pA1 = pFarg->a[1].pExpr; if( pA1->op==TK_COLUMN ){ sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable,1), target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } break; } case INLINEFUNC_affinity: { /* The AFFINITY() function evaluates to a string that describes ** the type affinity of the argument. This is used for testing of ** the SQLite type logic. */ const char *azAff[] = { "blob", "text", "numeric", "integer", "real", "flexnum" }; char aff; assert( nFarg==1 ); aff = sqlite3ExprAffinity(pFarg->a[0].pExpr); assert( aff<=SQLITE_AFF_NONE || (aff>=SQLITE_AFF_BLOB && aff<=SQLITE_AFF_FLEXNUM) ); sqlite3VdbeLoadString(v, target, (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]); break; } #endif /* !defined(SQLITE_UNTESTABLE) */ } return target; } /* ** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr. ** If it is, then resolve the expression by reading from the index and ** return the register into which the value has been read. If pExpr is ** not an indexed expression, then return negative. */ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( Parse *pParse, /* The parsing context */ Expr *pExpr, /* The expression to potentially bypass */ int target /* Where to store the result of the expression */ ){ IndexedExpr *p; Vdbe *v; for(p=pParse->pIdxEpr; p; p=p->pIENext){ u8 exprAff; int iDataCur = p->iDataCur; if( iDataCur<0 ) continue; if( pParse->iSelfTab ){ if( p->iDataCur!=pParse->iSelfTab-1 ) continue; iDataCur = -1; } if( sqlite3ExprCompare(0, pExpr, p->pExpr, iDataCur)!=0 ) continue; assert( p->aff>=SQLITE_AFF_BLOB && p->aff<=SQLITE_AFF_NUMERIC ); exprAff = sqlite3ExprAffinity(pExpr); if( (exprAff<=SQLITE_AFF_BLOB && p->aff!=SQLITE_AFF_BLOB) || (exprAff==SQLITE_AFF_TEXT && p->aff!=SQLITE_AFF_TEXT) || (exprAff>=SQLITE_AFF_NUMERIC && p->aff!=SQLITE_AFF_NUMERIC) ){ /* Affinity mismatch on a generated column */ continue; } v = pParse->pVdbe; assert( v!=0 ); if( p->bMaybeNullRow ){ /* If the index is on a NULL row due to an outer join, then we ** cannot extract the value from the index. The value must be ** computed using the original expression. */ int addr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_IfNullRow, p->iIdxCur, addr+3, target); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target); VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol)); sqlite3VdbeGoto(v, 0); p = pParse->pIdxEpr; pParse->pIdxEpr = 0; sqlite3ExprCode(pParse, pExpr, target); pParse->pIdxEpr = p; sqlite3VdbeJumpHere(v, addr+2); }else{ sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target); VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol)); } return target; } return -1; /* Not found */ } /* ** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This ** function checks the Parse.pIdxPartExpr list to see if this column ** can be replaced with a constant value. If so, it generates code to ** put the constant value in a register (ideally, but not necessarily, ** register iTarget) and returns the register number. ** ** Or, if the TK_COLUMN cannot be replaced by a constant, zero is ** returned. */ static int exprPartidxExprLookup(Parse *pParse, Expr *pExpr, int iTarget){ IndexedExpr *p; for(p=pParse->pIdxPartExpr; p; p=p->pIENext){ if( pExpr->iColumn==p->iIdxCol && pExpr->iTable==p->iDataCur ){ Vdbe *v = pParse->pVdbe; int addr = 0; int ret; if( p->bMaybeNullRow ){ addr = sqlite3VdbeAddOp1(v, OP_IfNullRow, p->iIdxCur); } ret = sqlite3ExprCodeTarget(pParse, p->pExpr, iTarget); sqlite3VdbeAddOp4(pParse->pVdbe, OP_Affinity, ret, 1, 0, (const char*)&p->aff, 1); if( addr ){ sqlite3VdbeJumpHere(v, addr); sqlite3VdbeChangeP3(v, addr, ret); } return ret; } } return 0; } /* ** Generate code into the current Vdbe to evaluate the given ** expression. Attempt to store the results in register "target". ** Return the register where results are stored. ** ** With this routine, there is no guarantee that results will ** be stored in target. The result might be stored in some other ** register if it is convenient to do so. The calling function ** must check the return code and move the results to the desired ** register. */ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ Vdbe *v = pParse->pVdbe; /* The VM under construction */ int op; /* The opcode being coded */ int inReg = target; /* Results stored in register inReg */ int regFree1 = 0; /* If non-zero free this temporary register */ int regFree2 = 0; /* If non-zero free this temporary register */ int r1, r2; /* Various register numbers */ Expr tempX; /* Temporary expression node */ int p5 = 0; assert( target>0 && target<=pParse->nMem ); assert( v!=0 ); expr_code_doover: if( pExpr==0 ){ op = TK_NULL; }else if( pParse->pIdxEpr!=0 && !ExprHasProperty(pExpr, EP_Leaf) && (r1 = sqlite3IndexedExprLookup(pParse, pExpr, target))>=0 ){ return r1; }else{ assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); op = pExpr->op; } assert( op!=TK_ORDER ); switch( op ){ case TK_AGG_COLUMN: { AggInfo *pAggInfo = pExpr->pAggInfo; struct AggInfo_col *pCol; assert( pAggInfo!=0 ); assert( pExpr->iAgg>=0 ); if( pExpr->iAgg>=pAggInfo->nColumn ){ /* Happens when the left table of a RIGHT JOIN is null and ** is using an expression index */ sqlite3VdbeAddOp2(v, OP_Null, 0, target); #ifdef SQLITE_VDBE_COVERAGE /* Verify that the OP_Null above is exercised by tests ** tag-20230325-2 */ sqlite3VdbeAddOp3(v, OP_NotNull, target, 1, 20230325); VdbeCoverageNeverTaken(v); #endif break; } pCol = &pAggInfo->aCol[pExpr->iAgg]; if( !pAggInfo->directMode ){ return AggInfoColumnReg(pAggInfo, pExpr->iAgg); }else if( pAggInfo->useSortingIdx ){ Table *pTab = pCol->pTab; sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab, pCol->iSorterColumn, target); if( pTab==0 ){ /* No comment added */ }else if( pCol->iColumn<0 ){ VdbeComment((v,"%s.rowid",pTab->zName)); }else{ VdbeComment((v,"%s.%s", pTab->zName, pTab->aCol[pCol->iColumn].zCnName)); if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, target); } } return target; }else if( pExpr->y.pTab==0 ){ /* This case happens when the argument to an aggregate function ** is rewritten by aggregateConvertIndexedExprRefToColumn() */ sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, pExpr->iColumn, target); return target; } /* Otherwise, fall thru into the TK_COLUMN case */ /* no break */ deliberate_fall_through } case TK_COLUMN: { int iTab = pExpr->iTable; int iReg; if( ExprHasProperty(pExpr, EP_FixedCol) ){ /* This COLUMN expression is really a constant due to WHERE clause ** constraints, and that constant is coded by the pExpr->pLeft ** expression. However, make sure the constant has the correct ** datatype by applying the Affinity of the table column to the ** constant. */ int aff; iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); assert( ExprUseYTab(pExpr) ); assert( pExpr->y.pTab!=0 ); aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); if( aff>SQLITE_AFF_BLOB ){ static const char zAff[] = "B\000C\000D\000E\000F"; assert( SQLITE_AFF_BLOB=='A' ); assert( SQLITE_AFF_TEXT=='B' ); sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0, &zAff[(aff-'B')*2], P4_STATIC); } return iReg; } if( iTab<0 ){ if( pParse->iSelfTab<0 ){ /* Other columns in the same row for CHECK constraints or ** generated columns or for inserting into partial index. ** The row is unpacked into registers beginning at ** 0-(pParse->iSelfTab). The rowid (if any) is in a register ** immediately prior to the first column. */ Column *pCol; Table *pTab; int iSrc; int iCol = pExpr->iColumn; assert( ExprUseYTab(pExpr) ); pTab = pExpr->y.pTab; assert( pTab!=0 ); assert( iCol>=XN_ROWID ); assert( iColnCol ); if( iCol<0 ){ return -1-pParse->iSelfTab; } pCol = pTab->aCol + iCol; testcase( iCol!=sqlite3TableColumnToStorage(pTab,iCol) ); iSrc = sqlite3TableColumnToStorage(pTab, iCol) - pParse->iSelfTab; #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pCol->colFlags & COLFLAG_GENERATED ){ if( pCol->colFlags & COLFLAG_BUSY ){ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zCnName); return 0; } pCol->colFlags |= COLFLAG_BUSY; if( pCol->colFlags & COLFLAG_NOTAVAIL ){ sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, iSrc); } pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL); return iSrc; }else #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ if( pCol->affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp2(v, OP_SCopy, iSrc, target); sqlite3VdbeAddOp1(v, OP_RealAffinity, target); return target; }else{ return iSrc; } }else{ /* Coding an expression that is part of an index where column names ** in the index refer to the table to which the index belongs */ iTab = pParse->iSelfTab - 1; } } else if( pParse->pIdxPartExpr && 0!=(r1 = exprPartidxExprLookup(pParse, pExpr, target)) ){ return r1; } assert( ExprUseYTab(pExpr) ); assert( pExpr->y.pTab!=0 ); iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab, pExpr->iColumn, iTab, target, pExpr->op2); return iReg; } case TK_INTEGER: { codeInteger(pParse, pExpr, 0, target); return target; } case TK_TRUEFALSE: { sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprTruthValue(pExpr), target); return target; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); codeReal(v, pExpr->u.zToken, 0, target); return target; } #endif case TK_STRING: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; } default: { /* Make NULL the default case so that if a bug causes an illegal ** Expr node to be passed into this function, it will be handled ** sanely and not crash. But keep the assert() to bring the problem ** to the attention of the developers. */ assert( op==TK_NULL || op==TK_ERROR || pParse->db->mallocFailed ); sqlite3VdbeAddOp2(v, OP_Null, 0, target); return target; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { int n; const char *z; char *zBlob; assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' ); assert( pExpr->u.zToken[1]=='\'' ); z = &pExpr->u.zToken[2]; n = sqlite3Strlen30(z) - 1; assert( z[n]=='\'' ); zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n); sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC); return target; } #endif case TK_VARIABLE: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken!=0 ); assert( pExpr->u.zToken[0]!=0 ); sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target); if( pExpr->u.zToken[1]!=0 ){ const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn); assert( pExpr->u.zToken[0]=='?' || (z && !strcmp(pExpr->u.zToken, z)) ); pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */ sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC); } return target; } case TK_REGISTER: { return pExpr->iTable; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ sqlite3ExprCode(pParse, pExpr->pLeft, target); assert( inReg==target ); assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeAddOp2(v, OP_Cast, target, sqlite3AffinityType(pExpr->u.zToken, 0)); return inReg; } #endif /* SQLITE_OMIT_CAST */ case TK_IS: case TK_ISNOT: op = (op==TK_IS) ? TK_EQ : TK_NE; p5 = SQLITE_NULLEQ; /* fall-through */ case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { Expr *pLeft = pExpr->pLeft; if( sqlite3ExprIsVector(pLeft) ){ codeVectorCompare(pParse, pExpr, target, op, p5); }else{ r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); sqlite3VdbeAddOp2(v, OP_Integer, 1, inReg); codeCompare(pParse, pLeft, pExpr->pRight, op, r1, r2, sqlite3VdbeCurrentAddr(v)+2, p5, ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); if( p5==SQLITE_NULLEQ ){ sqlite3VdbeAddOp2(v, OP_Integer, 0, inReg); }else{ sqlite3VdbeAddOp3(v, OP_ZeroOrNull, r1, inReg, r2); } testcase( regFree1==0 ); testcase( regFree2==0 ); } break; } case TK_AND: case TK_OR: case TK_PLUS: case TK_STAR: case TK_MINUS: case TK_REM: case TK_BITAND: case TK_BITOR: case TK_SLASH: case TK_LSHIFT: case TK_RSHIFT: case TK_CONCAT: { assert( TK_AND==OP_And ); testcase( op==TK_AND ); assert( TK_OR==OP_Or ); testcase( op==TK_OR ); assert( TK_PLUS==OP_Add ); testcase( op==TK_PLUS ); assert( TK_MINUS==OP_Subtract ); testcase( op==TK_MINUS ); assert( TK_REM==OP_Remainder ); testcase( op==TK_REM ); assert( TK_BITAND==OP_BitAnd ); testcase( op==TK_BITAND ); assert( TK_BITOR==OP_BitOr ); testcase( op==TK_BITOR ); assert( TK_SLASH==OP_Divide ); testcase( op==TK_SLASH ); assert( TK_LSHIFT==OP_ShiftLeft ); testcase( op==TK_LSHIFT ); assert( TK_RSHIFT==OP_ShiftRight ); testcase( op==TK_RSHIFT ); assert( TK_CONCAT==OP_Concat ); testcase( op==TK_CONCAT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); sqlite3VdbeAddOp3(v, op, r2, r1, target); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_UMINUS: { Expr *pLeft = pExpr->pLeft; assert( pLeft ); if( pLeft->op==TK_INTEGER ){ codeInteger(pParse, pLeft, 1, target); return target; #ifndef SQLITE_OMIT_FLOATING_POINT }else if( pLeft->op==TK_FLOAT ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); codeReal(v, pLeft->u.zToken, 1, target); return target; #endif }else{ tempX.op = TK_INTEGER; tempX.flags = EP_IntValue|EP_TokenOnly; tempX.u.iValue = 0; ExprClearVVAProperties(&tempX); r1 = sqlite3ExprCodeTemp(pParse, &tempX, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free2); sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); testcase( regFree2==0 ); } break; } case TK_BITNOT: case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); testcase( op==TK_BITNOT ); assert( TK_NOT==OP_Not ); testcase( op==TK_NOT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); testcase( regFree1==0 ); sqlite3VdbeAddOp2(v, op, r1, inReg); break; } case TK_TRUTH: { int isTrue; /* IS TRUE or IS NOT TRUE */ int bNormal; /* IS TRUE or IS FALSE */ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); testcase( regFree1==0 ); isTrue = sqlite3ExprTruthValue(pExpr->pRight); bNormal = pExpr->op2==TK_IS; testcase( isTrue && bNormal); testcase( !isTrue && bNormal); sqlite3VdbeAddOp4Int(v, OP_IsTrue, r1, inReg, !isTrue, isTrue ^ bNormal); break; } case TK_ISNULL: case TK_NOTNULL: { int addr; assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); testcase( regFree1==0 ); addr = sqlite3VdbeAddOp1(v, op, r1); VdbeCoverageIf(v, op==TK_ISNULL); VdbeCoverageIf(v, op==TK_NOTNULL); sqlite3VdbeAddOp2(v, OP_Integer, 0, target); sqlite3VdbeJumpHere(v, addr); break; } case TK_AGG_FUNCTION: { AggInfo *pInfo = pExpr->pAggInfo; if( pInfo==0 || NEVER(pExpr->iAgg<0) || NEVER(pExpr->iAgg>=pInfo->nFunc) ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3ErrorMsg(pParse, "misuse of aggregate: %#T()", pExpr); }else{ return AggInfoFuncReg(pInfo, pExpr->iAgg); } break; } case TK_FUNCTION: { ExprList *pFarg; /* List of function arguments */ int nFarg; /* Number of function arguments */ FuncDef *pDef; /* The function definition object */ const char *zId; /* The function name */ u32 constMask = 0; /* Mask of function arguments that are constant */ int i; /* Loop counter */ sqlite3 *db = pParse->db; /* The database connection */ u8 enc = ENC(db); /* The text encoding used by this database */ CollSeq *pColl = 0; /* A collating sequence */ #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ return pExpr->y.pWin->regResult; } #endif if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ /* SQL functions can be expensive. So try to avoid running them ** multiple times if we know they always give the same result */ return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); } assert( !ExprHasProperty(pExpr, EP_TokenOnly) ); assert( ExprUseXList(pExpr) ); pFarg = pExpr->x.pList; nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zId = pExpr->u.zToken; pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0); #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION if( pDef==0 && pParse->explain ){ pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0); } #endif if( pDef==0 || pDef->xFinalize!=0 ){ sqlite3ErrorMsg(pParse, "unknown function: %#T()", pExpr); break; } if( (pDef->funcFlags & SQLITE_FUNC_INLINE)!=0 && ALWAYS(pFarg!=0) ){ assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 ); assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 ); return exprCodeInlineFunction(pParse, pFarg, SQLITE_PTR_TO_INT(pDef->pUserData), target); }else if( pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE) ){ sqlite3ExprFunctionUsable(pParse, pExpr, pDef); } for(i=0; ia[i].pExpr) ){ testcase( i==31 ); constMask |= MASKBIT32(i); } if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){ pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr); } } if( pFarg ){ if( constMask ){ r1 = pParse->nMem+1; pParse->nMem += nFarg; }else{ r1 = sqlite3GetTempRange(pParse, nFarg); } /* For length() and typeof() and octet_length() functions, ** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG ** or OPFLAG_TYPEOFARG or OPFLAG_BYTELENARG respectively, to avoid ** unnecessary data loading. */ if( (pDef->funcFlags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){ u8 exprOp; assert( nFarg==1 ); assert( pFarg->a[0].pExpr!=0 ); exprOp = pFarg->a[0].pExpr->op; if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){ assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG ); assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG ); assert( SQLITE_FUNC_BYTELEN==OPFLAG_BYTELENARG ); assert( (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG)==OPFLAG_BYTELENARG ); testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_LENGTHARG ); testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_TYPEOFARG ); testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_BYTELENARG); pFarg->a[0].pExpr->op2 = pDef->funcFlags & OPFLAG_BYTELENARG; } } sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_FACTOR); }else{ r1 = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* Possibly overload the function if the first argument is ** a virtual table column. ** ** For infix functions (LIKE, GLOB, REGEXP, and MATCH) use the ** second argument, not the first, as the argument to test to ** see if it is a column in a virtual table. This is done because ** the left operand of infix functions (the operand we want to ** control overloading) ends up as the second argument to the ** function. The expression "A glob B" is equivalent to ** "glob(B,A). We want to use the A in "A glob B" to test ** for function overloading. But we use the B term in "glob(B,A)". */ if( nFarg>=2 && ExprHasProperty(pExpr, EP_InfixFunc) ){ pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[1].pExpr); }else if( nFarg>0 ){ pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr); } #endif if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){ if( !pColl ) pColl = db->pDfltColl; sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg, pDef, pExpr->op2); if( nFarg ){ if( constMask==0 ){ sqlite3ReleaseTempRange(pParse, r1, nFarg); }else{ sqlite3VdbeReleaseRegisters(pParse, r1, nFarg, constMask, 1); } } return target; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { int nCol; testcase( op==TK_EXISTS ); testcase( op==TK_SELECT ); if( pParse->db->mallocFailed ){ return 0; }else if( op==TK_SELECT && ALWAYS( ExprUseXSelect(pExpr) ) && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){ sqlite3SubselectError(pParse, nCol, 1); }else{ return sqlite3CodeSubselect(pParse, pExpr); } break; } case TK_SELECT_COLUMN: { int n; Expr *pLeft = pExpr->pLeft; if( pLeft->iTable==0 || pParse->withinRJSubrtn > pLeft->op2 ){ pLeft->iTable = sqlite3CodeSubselect(pParse, pLeft); pLeft->op2 = pParse->withinRJSubrtn; } assert( pLeft->op==TK_SELECT || pLeft->op==TK_ERROR ); n = sqlite3ExprVectorSize(pLeft); if( pExpr->iTable!=n ){ sqlite3ErrorMsg(pParse, "%d columns assigned %d values", pExpr->iTable, n); } return pLeft->iTable + pExpr->iColumn; } case TK_IN: { int destIfFalse = sqlite3VdbeMakeLabel(pParse); int destIfNull = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, target); sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); sqlite3VdbeResolveLabel(v, destIfFalse); sqlite3VdbeAddOp2(v, OP_AddImm, target, 0); sqlite3VdbeResolveLabel(v, destIfNull); return target; } #endif /* SQLITE_OMIT_SUBQUERY */ /* ** x BETWEEN y AND z ** ** This is equivalent to ** ** x>=y AND x<=z ** ** X is stored in pExpr->pLeft. ** Y is stored in pExpr->pList->a[0].pExpr. ** Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN: { exprCodeBetween(pParse, pExpr, target, 0, 0); return target; } case TK_COLLATE: { if( !ExprHasProperty(pExpr, EP_Collate) ){ /* A TK_COLLATE Expr node without the EP_Collate tag is a so-called ** "SOFT-COLLATE" that is added to constraints that are pushed down ** from outer queries into sub-queries by the push-down optimization. ** Clear subtypes as subtypes may not cross a subquery boundary. */ assert( pExpr->pLeft ); sqlite3ExprCode(pParse, pExpr->pLeft, target); sqlite3VdbeAddOp1(v, OP_ClrSubtype, target); return target; }else{ pExpr = pExpr->pLeft; goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. */ } } case TK_SPAN: case TK_UPLUS: { pExpr = pExpr->pLeft; goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. OSSFuzz. */ } case TK_TRIGGER: { /* If the opcode is TK_TRIGGER, then the expression is a reference ** to a column in the new.* or old.* pseudo-tables available to ** trigger programs. In this case Expr.iTable is set to 1 for the ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn ** is set to the column of the pseudo-table to read, or to -1 to ** read the rowid field. ** ** The expression is implemented using an OP_Param opcode. The p1 ** parameter is set to 0 for an old.rowid reference, or to (i+1) ** to reference another column of the old.* pseudo-table, where ** i is the index of the column. For a new.rowid reference, p1 is ** set to (n+1), where n is the number of columns in each pseudo-table. ** For a reference to any other column in the new.* pseudo-table, p1 ** is set to (n+2+i), where n and i are as defined previously. For ** example, if the table on which triggers are being fired is ** declared as: ** ** CREATE TABLE t1(a, b); ** ** Then p1 is interpreted as follows: ** ** p1==0 -> old.rowid p1==3 -> new.rowid ** p1==1 -> old.a p1==4 -> new.a ** p1==2 -> old.b p1==5 -> new.b */ Table *pTab; int iCol; int p1; assert( ExprUseYTab(pExpr) ); pTab = pExpr->y.pTab; iCol = pExpr->iColumn; p1 = pExpr->iTable * (pTab->nCol+1) + 1 + sqlite3TableColumnToStorage(pTab, iCol); assert( pExpr->iTable==0 || pExpr->iTable==1 ); assert( iCol>=-1 && iColnCol ); assert( pTab->iPKey<0 || iCol!=pTab->iPKey ); assert( p1>=0 && p1<(pTab->nCol*2+2) ); sqlite3VdbeAddOp2(v, OP_Param, p1, target); VdbeComment((v, "r[%d]=%s.%s", target, (pExpr->iTable ? "new" : "old"), (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[iCol].zCnName) )); #ifndef SQLITE_OMIT_FLOATING_POINT /* If the column has REAL affinity, it may currently be stored as an ** integer. Use OP_RealAffinity to make sure it is really real. ** ** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to ** floating point when extracting it from the record. */ if( iCol>=0 && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, target); } #endif break; } case TK_VECTOR: { sqlite3ErrorMsg(pParse, "row value misused"); break; } /* TK_IF_NULL_ROW Expr nodes are inserted ahead of expressions ** that derive from the right-hand table of a LEFT JOIN. The ** Expr.iTable value is the table number for the right-hand table. ** The expression is only evaluated if that table is not currently ** on a LEFT JOIN NULL row. */ case TK_IF_NULL_ROW: { int addrINR; u8 okConstFactor = pParse->okConstFactor; AggInfo *pAggInfo = pExpr->pAggInfo; if( pAggInfo ){ assert( pExpr->iAgg>=0 && pExpr->iAggnColumn ); if( !pAggInfo->directMode ){ inReg = AggInfoColumnReg(pAggInfo, pExpr->iAgg); break; } if( pExpr->pAggInfo->useSortingIdx ){ sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab, pAggInfo->aCol[pExpr->iAgg].iSorterColumn, target); inReg = target; break; } } addrINR = sqlite3VdbeAddOp3(v, OP_IfNullRow, pExpr->iTable, 0, target); /* The OP_IfNullRow opcode above can overwrite the result register with ** NULL. So we have to ensure that the result register is not a value ** that is suppose to be a constant. Two defenses are needed: ** (1) Temporarily disable factoring of constant expressions ** (2) Make sure the computed value really is stored in register ** "target" and not someplace else. */ pParse->okConstFactor = 0; /* note (1) above */ sqlite3ExprCode(pParse, pExpr->pLeft, target); assert( target==inReg ); pParse->okConstFactor = okConstFactor; sqlite3VdbeJumpHere(v, addrINR); break; } /* ** Form A: ** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END ** ** Form B: ** CASE WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END ** ** Form A is can be transformed into the equivalent form B as follows: ** CASE WHEN x=e1 THEN r1 WHEN x=e2 THEN r2 ... ** WHEN x=eN THEN rN ELSE y END ** ** X (if it exists) is in pExpr->pLeft. ** Y is in the last element of pExpr->x.pList if pExpr->x.pList->nExpr is ** odd. The Y is also optional. If the number of elements in x.pList ** is even, then Y is omitted and the "otherwise" result is NULL. ** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1]. ** ** The result of the expression is the Ri for the first matching Ei, ** or if there is no matching Ei, the ELSE term Y, or if there is ** no ELSE term, NULL. */ case TK_CASE: { int endLabel; /* GOTO label for end of CASE stmt */ int nextCase; /* GOTO label for next WHEN clause */ int nExpr; /* 2x number of WHEN terms */ int i; /* Loop counter */ ExprList *pEList; /* List of WHEN terms */ struct ExprList_item *aListelem; /* Array of WHEN terms */ Expr opCompare; /* The X==Ei expression */ Expr *pX; /* The X expression */ Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */ Expr *pDel = 0; sqlite3 *db = pParse->db; assert( ExprUseXList(pExpr) && pExpr->x.pList!=0 ); assert(pExpr->x.pList->nExpr > 0); pEList = pExpr->x.pList; aListelem = pEList->a; nExpr = pEList->nExpr; endLabel = sqlite3VdbeMakeLabel(pParse); if( (pX = pExpr->pLeft)!=0 ){ pDel = sqlite3ExprDup(db, pX, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDel); break; } testcase( pX->op==TK_COLUMN ); exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1)); testcase( regFree1==0 ); memset(&opCompare, 0, sizeof(opCompare)); opCompare.op = TK_EQ; opCompare.pLeft = pDel; pTest = &opCompare; /* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001: ** The value in regFree1 might get SCopy-ed into the file result. ** So make sure that the regFree1 register is not reused for other ** purposes and possibly overwritten. */ regFree1 = 0; } for(i=0; iop==TK_COLUMN ); sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL); testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); sqlite3VdbeGoto(v, endLabel); sqlite3VdbeResolveLabel(v, nextCase); } if( (nExpr&1)!=0 ){ sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } sqlite3ExprDelete(db, pDel); setDoNotMergeFlagOnCopy(v); sqlite3VdbeResolveLabel(v, endLabel); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { assert( pExpr->affExpr==OE_Rollback || pExpr->affExpr==OE_Abort || pExpr->affExpr==OE_Fail || pExpr->affExpr==OE_Ignore ); if( !pParse->pTriggerTab && !pParse->nested ){ sqlite3ErrorMsg(pParse, "RAISE() may only be used within a trigger-program"); return 0; } if( pExpr->affExpr==OE_Abort ){ sqlite3MayAbort(pParse); } assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->affExpr==OE_Ignore ){ sqlite3VdbeAddOp4( v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0); VdbeCoverage(v); }else{ sqlite3HaltConstraint(pParse, pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR, pExpr->affExpr, pExpr->u.zToken, 0, 0); } break; } #endif } sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); return inReg; } /* ** Generate code that will evaluate expression pExpr just one time ** per prepared statement execution. ** ** If the expression uses functions (that might throw an exception) then ** guard them with an OP_Once opcode to ensure that the code is only executed ** once. If no functions are involved, then factor the code out and put it at ** the end of the prepared statement in the initialization section. ** ** If regDest>0 then the result is always stored in that register and the ** result is not reusable. If regDest<0 then this routine is free to ** store the value wherever it wants. The register where the expression ** is stored is returned. When regDest<0, two identical expressions might ** code to the same register, if they do not contain function calls and hence ** are factored out into the initialization section at the end of the ** prepared statement. */ SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The expression to code when the VDBE initializes */ int regDest /* Store the value in this register */ ){ ExprList *p; assert( ConstFactorOk(pParse) ); assert( regDest!=0 ); p = pParse->pConstExpr; if( regDest<0 && p ){ struct ExprList_item *pItem; int i; for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){ if( pItem->fg.reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){ return pItem->u.iConstExprReg; } } } pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); if( pExpr!=0 && ExprHasProperty(pExpr, EP_HasFunc) ){ Vdbe *v = pParse->pVdbe; int addr; assert( v ); addr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); pParse->okConstFactor = 0; if( !pParse->db->mallocFailed ){ if( regDest<0 ) regDest = ++pParse->nMem; sqlite3ExprCode(pParse, pExpr, regDest); } pParse->okConstFactor = 1; sqlite3ExprDelete(pParse->db, pExpr); sqlite3VdbeJumpHere(v, addr); }else{ p = sqlite3ExprListAppend(pParse, p, pExpr); if( p ){ struct ExprList_item *pItem = &p->a[p->nExpr-1]; pItem->fg.reusable = regDest<0; if( regDest<0 ) regDest = ++pParse->nMem; pItem->u.iConstExprReg = regDest; } pParse->pConstExpr = p; } return regDest; } /* ** Generate code to evaluate an expression and store the results ** into a register. Return the register number where the results ** are stored. ** ** If the register is a temporary register that can be deallocated, ** then write its number into *pReg. If the result register is not ** a temporary, then set *pReg to zero. ** ** If pExpr is a constant, then this routine might generate this ** code to fill the register in the initialization section of the ** VDBE program, in order to factor it out of the evaluation loop. */ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ int r2; pExpr = sqlite3ExprSkipCollateAndLikely(pExpr); if( ConstFactorOk(pParse) && ALWAYS(pExpr!=0) && pExpr->op!=TK_REGISTER && sqlite3ExprIsConstantNotJoin(pExpr) ){ *pReg = 0; r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); }else{ int r1 = sqlite3GetTempReg(pParse); r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); if( r2==r1 ){ *pReg = r1; }else{ sqlite3ReleaseTempReg(pParse, r1); *pReg = 0; } } return r2; } /* ** Generate code that will evaluate expression pExpr and store the ** results in register target. The results are guaranteed to appear ** in register target. */ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ int inReg; assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) ); assert( target>0 && target<=pParse->nMem ); assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); if( pParse->pVdbe==0 ) return; inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); if( inReg!=target ){ u8 op; Expr *pX = sqlite3ExprSkipCollateAndLikely(pExpr); testcase( pX!=pExpr ); if( ALWAYS(pX) && (ExprHasProperty(pX,EP_Subquery) || pX->op==TK_REGISTER) ){ op = OP_Copy; }else{ op = OP_SCopy; } sqlite3VdbeAddOp2(pParse->pVdbe, op, inReg, target); } } /* ** Make a transient copy of expression pExpr and then code it using ** sqlite3ExprCode(). This routine works just like sqlite3ExprCode() ** except that the input expression is guaranteed to be unchanged. */ SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){ sqlite3 *db = pParse->db; pExpr = sqlite3ExprDup(db, pExpr, 0); if( !db->mallocFailed ) sqlite3ExprCode(pParse, pExpr, target); sqlite3ExprDelete(db, pExpr); } /* ** Generate code that will evaluate expression pExpr and store the ** results in register target. The results are guaranteed to appear ** in register target. If the expression is constant, then this routine ** might choose to code the expression at initialization time. */ SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target); }else{ sqlite3ExprCodeCopy(pParse, pExpr, target); } } /* ** Generate code that pushes the value of every element of the given ** expression list into a sequence of registers beginning at target. ** ** Return the number of elements evaluated. The number returned will ** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF ** is defined. ** ** The SQLITE_ECEL_DUP flag prevents the arguments from being ** filled using OP_SCopy. OP_Copy must be used instead. ** ** The SQLITE_ECEL_FACTOR argument allows constant arguments to be ** factored out into initialization code. ** ** The SQLITE_ECEL_REF flag means that expressions in the list with ** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored ** in registers at srcReg, and so the value can be copied from there. ** If SQLITE_ECEL_OMITREF is also set, then the values with u.x.iOrderByCol>0 ** are simply omitted rather than being copied from srcReg. */ SQLITE_PRIVATE int sqlite3ExprCodeExprList( Parse *pParse, /* Parsing context */ ExprList *pList, /* The expression list to be coded */ int target, /* Where to write results */ int srcReg, /* Source registers if SQLITE_ECEL_REF */ u8 flags /* SQLITE_ECEL_* flags */ ){ struct ExprList_item *pItem; int i, j, n; u8 copyOp = (flags & SQLITE_ECEL_DUP) ? OP_Copy : OP_SCopy; Vdbe *v = pParse->pVdbe; assert( pList!=0 ); assert( target>0 ); assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */ n = pList->nExpr; if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR; for(pItem=pList->a, i=0; ipExpr; #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( pItem->fg.bSorterRef ){ i--; n--; }else #endif if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){ if( flags & SQLITE_ECEL_OMITREF ){ i--; n--; }else{ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); } }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i); }else{ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); if( inReg!=target+i ){ VdbeOp *pOp; if( copyOp==OP_Copy && (pOp=sqlite3VdbeGetLastOp(v))->opcode==OP_Copy && pOp->p1+pOp->p3+1==inReg && pOp->p2+pOp->p3+1==target+i && pOp->p5==0 /* The do-not-merge flag must be clear */ ){ pOp->p3++; }else{ sqlite3VdbeAddOp2(v, copyOp, inReg, target+i); } } } } return n; } /* ** Generate code for a BETWEEN operator. ** ** x BETWEEN y AND z ** ** The above is equivalent to ** ** x>=y AND x<=z ** ** Code it as such, taking care to do the common subexpression ** elimination of x. ** ** The xJumpIf parameter determines details: ** ** NULL: Store the boolean result in reg[dest] ** sqlite3ExprIfTrue: Jump to dest if true ** sqlite3ExprIfFalse: Jump to dest if false ** ** The jumpIfNull parameter is ignored if xJumpIf is NULL. */ static void exprCodeBetween( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* The BETWEEN expression */ int dest, /* Jump destination or storage location */ void (*xJump)(Parse*,Expr*,int,int), /* Action to take */ int jumpIfNull /* Take the jump if the BETWEEN is NULL */ ){ Expr exprAnd; /* The AND operator in x>=y AND x<=z */ Expr compLeft; /* The x>=y term */ Expr compRight; /* The x<=z term */ int regFree1 = 0; /* Temporary use register */ Expr *pDel = 0; sqlite3 *db = pParse->db; memset(&compLeft, 0, sizeof(Expr)); memset(&compRight, 0, sizeof(Expr)); memset(&exprAnd, 0, sizeof(Expr)); assert( ExprUseXList(pExpr) ); pDel = sqlite3ExprDup(db, pExpr->pLeft, 0); if( db->mallocFailed==0 ){ exprAnd.op = TK_AND; exprAnd.pLeft = &compLeft; exprAnd.pRight = &compRight; compLeft.op = TK_GE; compLeft.pLeft = pDel; compLeft.pRight = pExpr->x.pList->a[0].pExpr; compRight.op = TK_LE; compRight.pLeft = pDel; compRight.pRight = pExpr->x.pList->a[1].pExpr; exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1)); if( xJump ){ xJump(pParse, &exprAnd, dest, jumpIfNull); }else{ /* Mark the expression is being from the ON or USING clause of a join ** so that the sqlite3ExprCodeTarget() routine will not attempt to move ** it into the Parse.pConstExpr list. We should use a new bit for this, ** for clarity, but we are out of bits in the Expr.flags field so we ** have to reuse the EP_OuterON bit. Bummer. */ pDel->flags |= EP_OuterON; sqlite3ExprCodeTarget(pParse, &exprAnd, dest); } sqlite3ReleaseTempReg(pParse, regFree1); } sqlite3ExprDelete(db, pDel); /* Ensure adequate test coverage */ testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 ); testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1!=0 ); testcase( xJump==sqlite3ExprIfTrue && jumpIfNull!=0 && regFree1==0 ); testcase( xJump==sqlite3ExprIfTrue && jumpIfNull!=0 && regFree1!=0 ); testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1==0 ); testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1!=0 ); testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1==0 ); testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1!=0 ); testcase( xJump==0 ); } /* ** Generate code for a boolean expression such that a jump is made ** to the label "dest" if the expression is true but execution ** continues straight thru if the expression is false. ** ** If the expression evaluates to NULL (neither true nor false), then ** take the jump if the jumpIfNull flag is SQLITE_JUMPIFNULL. ** ** This code depends on the fact that certain token values (ex: TK_EQ) ** are the same as opcode values (ex: OP_Eq) that implement the corresponding ** operation. Special comments in vdbe.c and the mkopcodeh.awk script in ** the make process cause these values to align. Assert()s in the code ** below verify that the numbers are aligned correctly. */ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; int regFree1 = 0; int regFree2 = 0; int r1, r2; assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ if( NEVER(pExpr==0) ) return; /* No way this can happen */ assert( !ExprHasVVAProperty(pExpr, EP_Immutable) ); op = pExpr->op; switch( op ){ case TK_AND: case TK_OR: { Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); if( pAlt!=pExpr ){ sqlite3ExprIfTrue(pParse, pAlt, dest, jumpIfNull); }else if( op==TK_AND ){ int d2 = sqlite3VdbeMakeLabel(pParse); testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); }else{ testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); } break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); break; } case TK_TRUTH: { int isNot; /* IS NOT TRUE or IS NOT FALSE */ int isTrue; /* IS TRUE or IS NOT TRUE */ testcase( jumpIfNull==0 ); isNot = pExpr->op2==TK_ISNOT; isTrue = sqlite3ExprTruthValue(pExpr->pRight); testcase( isTrue && isNot ); testcase( !isTrue && isNot ); if( isTrue ^ isNot ){ sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, isNot ? SQLITE_JUMPIFNULL : 0); }else{ sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, isNot ? SQLITE_JUMPIFNULL : 0); } break; } case TK_IS: case TK_ISNOT: testcase( op==TK_IS ); testcase( op==TK_ISNOT ); op = (op==TK_IS) ? TK_EQ : TK_NE; jumpIfNull = SQLITE_NULLEQ; /* no break */ deliberate_fall_through case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr; testcase( jumpIfNull==0 ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull, ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ); VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ); assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ); VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); sqlite3VdbeTypeofColumn(v, r1); sqlite3VdbeAddOp2(v, op, r1, dest); VdbeCoverageIf(v, op==TK_ISNULL); VdbeCoverageIf(v, op==TK_NOTNULL); testcase( regFree1==0 ); break; } case TK_BETWEEN: { testcase( jumpIfNull==0 ); exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_IN: { int destIfFalse = sqlite3VdbeMakeLabel(pParse); int destIfNull = jumpIfNull ? dest : destIfFalse; sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); sqlite3VdbeGoto(v, dest); sqlite3VdbeResolveLabel(v, destIfFalse); break; } #endif default: { default_expr: if( ExprAlwaysTrue(pExpr) ){ sqlite3VdbeGoto(v, dest); }else if( ExprAlwaysFalse(pExpr) ){ /* No-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0); VdbeCoverage(v); testcase( regFree1==0 ); testcase( jumpIfNull==0 ); } break; } } sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); } /* ** Generate code for a boolean expression such that a jump is made ** to the label "dest" if the expression is false but execution ** continues straight thru if the expression is true. ** ** If the expression evaluates to NULL (neither true nor false) then ** jump if jumpIfNull is SQLITE_JUMPIFNULL or fall through if jumpIfNull ** is 0. */ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; int regFree1 = 0; int regFree2 = 0; int r1, r2; assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ if( pExpr==0 ) return; assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); /* The value of pExpr->op and op are related as follows: ** ** pExpr->op op ** --------- ---------- ** TK_ISNULL OP_NotNull ** TK_NOTNULL OP_IsNull ** TK_NE OP_Eq ** TK_EQ OP_Ne ** TK_GT OP_Le ** TK_LE OP_Gt ** TK_GE OP_Lt ** TK_LT OP_Ge ** ** For other values of pExpr->op, op is undefined and unused. ** The value of TK_ and OP_ constants are arranged such that we ** can compute the mapping above using the following expression. ** Assert()s verify that the computation is correct. */ op = ((pExpr->op+(TK_ISNULL&1))^1)-(TK_ISNULL&1); /* Verify correct alignment of TK_ and OP_ constants */ assert( pExpr->op!=TK_ISNULL || op==OP_NotNull ); assert( pExpr->op!=TK_NOTNULL || op==OP_IsNull ); assert( pExpr->op!=TK_NE || op==OP_Eq ); assert( pExpr->op!=TK_EQ || op==OP_Ne ); assert( pExpr->op!=TK_LT || op==OP_Ge ); assert( pExpr->op!=TK_LE || op==OP_Gt ); assert( pExpr->op!=TK_GT || op==OP_Le ); assert( pExpr->op!=TK_GE || op==OP_Lt ); switch( pExpr->op ){ case TK_AND: case TK_OR: { Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); if( pAlt!=pExpr ){ sqlite3ExprIfFalse(pParse, pAlt, dest, jumpIfNull); }else if( pExpr->op==TK_AND ){ testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); }else{ int d2 = sqlite3VdbeMakeLabel(pParse); testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); } break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); break; } case TK_TRUTH: { int isNot; /* IS NOT TRUE or IS NOT FALSE */ int isTrue; /* IS TRUE or IS NOT TRUE */ testcase( jumpIfNull==0 ); isNot = pExpr->op2==TK_ISNOT; isTrue = sqlite3ExprTruthValue(pExpr->pRight); testcase( isTrue && isNot ); testcase( !isTrue && isNot ); if( isTrue ^ isNot ){ /* IS TRUE and IS NOT FALSE */ sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, isNot ? 0 : SQLITE_JUMPIFNULL); }else{ /* IS FALSE and IS NOT TRUE */ sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, isNot ? 0 : SQLITE_JUMPIFNULL); } break; } case TK_IS: case TK_ISNOT: testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_ISNOT ); op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; jumpIfNull = SQLITE_NULLEQ; /* no break */ deliberate_fall_through case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr; testcase( jumpIfNull==0 ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull,ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ); VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ); assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ); VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); sqlite3VdbeTypeofColumn(v, r1); sqlite3VdbeAddOp2(v, op, r1, dest); testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); testcase( regFree1==0 ); break; } case TK_BETWEEN: { testcase( jumpIfNull==0 ); exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfFalse, jumpIfNull); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_IN: { if( jumpIfNull ){ sqlite3ExprCodeIN(pParse, pExpr, dest, dest); }else{ int destIfNull = sqlite3VdbeMakeLabel(pParse); sqlite3ExprCodeIN(pParse, pExpr, dest, destIfNull); sqlite3VdbeResolveLabel(v, destIfNull); } break; } #endif default: { default_expr: if( ExprAlwaysFalse(pExpr) ){ sqlite3VdbeGoto(v, dest); }else if( ExprAlwaysTrue(pExpr) ){ /* no-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0); VdbeCoverage(v); testcase( regFree1==0 ); testcase( jumpIfNull==0 ); } break; } } sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); } /* ** Like sqlite3ExprIfFalse() except that a copy is made of pExpr before ** code generation, and that copy is deleted after code generation. This ** ensures that the original pExpr is unchanged. */ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){ sqlite3 *db = pParse->db; Expr *pCopy = sqlite3ExprDup(db, pExpr, 0); if( db->mallocFailed==0 ){ sqlite3ExprIfFalse(pParse, pCopy, dest, jumpIfNull); } sqlite3ExprDelete(db, pCopy); } /* ** Expression pVar is guaranteed to be an SQL variable. pExpr may be any ** type of expression. ** ** If pExpr is a simple SQL value - an integer, real, string, blob ** or NULL value - then the VDBE currently being prepared is configured ** to re-prepare each time a new value is bound to variable pVar. ** ** Additionally, if pExpr is a simple SQL value and the value is the ** same as that currently bound to variable pVar, non-zero is returned. ** Otherwise, if the values are not the same or if pExpr is not a simple ** SQL value, zero is returned. */ static int exprCompareVariable( const Parse *pParse, const Expr *pVar, const Expr *pExpr ){ int res = 0; int iVar; sqlite3_value *pL, *pR = 0; sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR); if( pR ){ iVar = pVar->iColumn; sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB); if( pL ){ if( sqlite3_value_type(pL)==SQLITE_TEXT ){ sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */ } res = 0==sqlite3MemCompare(pL, pR, 0); } sqlite3ValueFree(pR); sqlite3ValueFree(pL); } return res; } /* ** Do a deep comparison of two expression trees. Return 0 if the two ** expressions are completely identical. Return 1 if they differ only ** by a COLLATE operator at the top level. Return 2 if there are differences ** other than the top-level COLLATE operator. ** ** If any subelement of pB has Expr.iTable==(-1) then it is allowed ** to compare equal to an equivalent element in pA with Expr.iTable==iTab. ** ** The pA side might be using TK_REGISTER. If that is the case and pB is ** not using TK_REGISTER but is otherwise equivalent, then still return 0. ** ** Sometimes this routine will return 2 even if the two expressions ** really are equivalent. If we cannot prove that the expressions are ** identical, we return 2 just to be safe. So if this routine ** returns 2, then you do not really know for certain if the two ** expressions are the same. But if you get a 0 or 1 return, then you ** can be sure the expressions are the same. In the places where ** this routine is used, it does not hurt to get an extra 2 - that ** just might result in some slightly slower code. But returning ** an incorrect 0 or 1 could lead to a malfunction. ** ** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in ** pParse->pReprepare can be matched against literals in pB. The ** pParse->pVdbe->expmask bitmask is updated for each variable referenced. ** If pParse is NULL (the normal case) then any TK_VARIABLE term in ** Argument pParse should normally be NULL. If it is not NULL and pA or ** pB causes a return value of 2. */ SQLITE_PRIVATE int sqlite3ExprCompare( const Parse *pParse, const Expr *pA, const Expr *pB, int iTab ){ u32 combinedFlags; if( pA==0 || pB==0 ){ return pB==pA ? 0 : 2; } if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){ return 0; } combinedFlags = pA->flags | pB->flags; if( combinedFlags & EP_IntValue ){ if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){ return 0; } return 2; } if( pA->op!=pB->op || pA->op==TK_RAISE ){ if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){ return 1; } if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){ return 1; } if( pA->op==TK_AGG_COLUMN && pB->op==TK_COLUMN && pB->iTable<0 && pA->iTable==iTab ){ /* fall through */ }else{ return 2; } } assert( !ExprHasProperty(pA, EP_IntValue) ); assert( !ExprHasProperty(pB, EP_IntValue) ); if( pA->u.zToken ){ if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; #ifndef SQLITE_OMIT_WINDOWFUNC assert( pA->op==pB->op ); if( ExprHasProperty(pA,EP_WinFunc)!=ExprHasProperty(pB,EP_WinFunc) ){ return 2; } if( ExprHasProperty(pA,EP_WinFunc) ){ if( sqlite3WindowCompare(pParse, pA->y.pWin, pB->y.pWin, 1)!=0 ){ return 2; } } #endif }else if( pA->op==TK_NULL ){ return 0; }else if( pA->op==TK_COLLATE ){ if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; }else if( pB->u.zToken!=0 && pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } if( (pA->flags & (EP_Distinct|EP_Commuted)) != (pB->flags & (EP_Distinct|EP_Commuted)) ) return 2; if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ if( combinedFlags & EP_xIsSelect ) return 2; if( (combinedFlags & EP_FixedCol)==0 && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE && ALWAYS((combinedFlags & EP_Reduced)==0) ){ if( pA->iColumn!=pB->iColumn ) return 2; if( pA->op2!=pB->op2 && pA->op==TK_TRUTH ) return 2; if( pA->op!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){ return 2; } } } return 0; } /* ** Compare two ExprList objects. Return 0 if they are identical, 1 ** if they are certainly different, or 2 if it is not possible to ** determine if they are identical or not. ** ** If any subelement of pB has Expr.iTable==(-1) then it is allowed ** to compare equal to an equivalent element in pA with Expr.iTable==iTab. ** ** This routine might return non-zero for equivalent ExprLists. The ** only consequence will be disabled optimizations. But this routine ** must never return 0 if the two ExprList objects are different, or ** a malfunction will result. ** ** Two NULL pointers are considered to be the same. But a NULL pointer ** always differs from a non-NULL pointer. */ SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB, int iTab){ int i; if( pA==0 && pB==0 ) return 0; if( pA==0 || pB==0 ) return 1; if( pA->nExpr!=pB->nExpr ) return 1; for(i=0; inExpr; i++){ int res; Expr *pExprA = pA->a[i].pExpr; Expr *pExprB = pB->a[i].pExpr; if( pA->a[i].fg.sortFlags!=pB->a[i].fg.sortFlags ) return 1; if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res; } return 0; } /* ** Like sqlite3ExprCompare() except COLLATE operators at the top-level ** are ignored. */ SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){ return sqlite3ExprCompare(0, sqlite3ExprSkipCollate(pA), sqlite3ExprSkipCollate(pB), iTab); } /* ** Return non-zero if Expr p can only be true if pNN is not NULL. ** ** Or if seenNot is true, return non-zero if Expr p can only be ** non-NULL if pNN is not NULL */ static int exprImpliesNotNull( const Parse *pParse,/* Parsing context */ const Expr *p, /* The expression to be checked */ const Expr *pNN, /* The expression that is NOT NULL */ int iTab, /* Table being evaluated */ int seenNot /* Return true only if p can be any non-NULL value */ ){ assert( p ); assert( pNN ); if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ){ return pNN->op!=TK_NULL; } switch( p->op ){ case TK_IN: { if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0; assert( ExprUseXSelect(p) || (p->x.pList!=0 && p->x.pList->nExpr>0) ); return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); } case TK_BETWEEN: { ExprList *pList; assert( ExprUseXList(p) ); pList = p->x.pList; assert( pList!=0 ); assert( pList->nExpr==2 ); if( seenNot ) return 0; if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, 1) || exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, 1) ){ return 1; } return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); } case TK_EQ: case TK_NE: case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_PLUS: case TK_MINUS: case TK_BITOR: case TK_LSHIFT: case TK_RSHIFT: case TK_CONCAT: seenNot = 1; /* no break */ deliberate_fall_through case TK_STAR: case TK_REM: case TK_BITAND: case TK_SLASH: { if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1; /* no break */ deliberate_fall_through } case TK_SPAN: case TK_COLLATE: case TK_UPLUS: case TK_UMINUS: { return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); } case TK_TRUTH: { if( seenNot ) return 0; if( p->op2!=TK_IS ) return 0; return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); } case TK_BITNOT: case TK_NOT: { return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); } } return 0; } /* ** Return true if we can prove the pE2 will always be true if pE1 is ** true. Return false if we cannot complete the proof or if pE2 might ** be false. Examples: ** ** pE1: x==5 pE2: x==5 Result: true ** pE1: x>0 pE2: x==5 Result: false ** pE1: x=21 pE2: x=21 OR y=43 Result: true ** pE1: x!=123 pE2: x IS NOT NULL Result: true ** pE1: x!=?1 pE2: x IS NOT NULL Result: true ** pE1: x IS NULL pE2: x IS NOT NULL Result: false ** pE1: x IS ?2 pE2: x IS NOT NULL Result: false ** ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has ** Expr.iTable<0 then assume a table number given by iTab. ** ** If pParse is not NULL, then the values of bound variables in pE1 are ** compared against literal values in pE2 and pParse->pVdbe->expmask is ** modified to record which bound variables are referenced. If pParse ** is NULL, then false will be returned if pE1 contains any bound variables. ** ** When in doubt, return false. Returning true might give a performance ** improvement. Returning false might cause a performance reduction, but ** it will always give the correct answer and is hence always safe. */ SQLITE_PRIVATE int sqlite3ExprImpliesExpr( const Parse *pParse, const Expr *pE1, const Expr *pE2, int iTab ){ if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){ return 1; } if( pE2->op==TK_OR && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab) || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) ) ){ return 1; } if( pE2->op==TK_NOTNULL && exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0) ){ return 1; } return 0; } /* This is a helper function to impliesNotNullRow(). In this routine, ** set pWalker->eCode to one only if *both* of the input expressions ** separately have the implies-not-null-row property. */ static void bothImplyNotNullRow(Walker *pWalker, Expr *pE1, Expr *pE2){ if( pWalker->eCode==0 ){ sqlite3WalkExpr(pWalker, pE1); if( pWalker->eCode ){ pWalker->eCode = 0; sqlite3WalkExpr(pWalker, pE2); } } } /* ** This is the Expr node callback for sqlite3ExprImpliesNonNullRow(). ** If the expression node requires that the table at pWalker->iCur ** have one or more non-NULL column, then set pWalker->eCode to 1 and abort. ** ** pWalker->mWFlags is non-zero if this inquiry is being undertaking on ** behalf of a RIGHT JOIN (or FULL JOIN). That makes a difference when ** evaluating terms in the ON clause of an inner join. ** ** This routine controls an optimization. False positives (setting ** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives ** (never setting pWalker->eCode) is a harmless missed optimization. */ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_AGG_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); if( ExprHasProperty(pExpr, EP_OuterON) ) return WRC_Prune; if( ExprHasProperty(pExpr, EP_InnerON) && pWalker->mWFlags ){ /* If iCur is used in an inner-join ON clause to the left of a ** RIGHT JOIN, that does *not* mean that the table must be non-null. ** But it is difficult to check for that condition precisely. ** To keep things simple, any use of iCur from any inner-join is ** ignored while attempting to simplify a RIGHT JOIN. */ return WRC_Prune; } switch( pExpr->op ){ case TK_ISNOT: case TK_ISNULL: case TK_NOTNULL: case TK_IS: case TK_VECTOR: case TK_FUNCTION: case TK_TRUTH: case TK_CASE: testcase( pExpr->op==TK_ISNOT ); testcase( pExpr->op==TK_ISNULL ); testcase( pExpr->op==TK_NOTNULL ); testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_VECTOR ); testcase( pExpr->op==TK_FUNCTION ); testcase( pExpr->op==TK_TRUTH ); testcase( pExpr->op==TK_CASE ); return WRC_Prune; case TK_COLUMN: if( pWalker->u.iCur==pExpr->iTable ){ pWalker->eCode = 1; return WRC_Abort; } return WRC_Prune; case TK_OR: case TK_AND: /* Both sides of an AND or OR must separately imply non-null-row. ** Consider these cases: ** 1. NOT (x AND y) ** 2. x OR y ** If only one of x or y is non-null-row, then the overall expression ** can be true if the other arm is false (case 1) or true (case 2). */ testcase( pExpr->op==TK_OR ); testcase( pExpr->op==TK_AND ); bothImplyNotNullRow(pWalker, pExpr->pLeft, pExpr->pRight); return WRC_Prune; case TK_IN: /* Beware of "x NOT IN ()" and "x NOT IN (SELECT 1 WHERE false)", ** both of which can be true. But apart from these cases, if ** the left-hand side of the IN is NULL then the IN itself will be ** NULL. */ if( ExprUseXList(pExpr) && ALWAYS(pExpr->x.pList->nExpr>0) ){ sqlite3WalkExpr(pWalker, pExpr->pLeft); } return WRC_Prune; case TK_BETWEEN: /* In "x NOT BETWEEN y AND z" either x must be non-null-row or else ** both y and z must be non-null row */ assert( ExprUseXList(pExpr) ); assert( pExpr->x.pList->nExpr==2 ); sqlite3WalkExpr(pWalker, pExpr->pLeft); bothImplyNotNullRow(pWalker, pExpr->x.pList->a[0].pExpr, pExpr->x.pList->a[1].pExpr); return WRC_Prune; /* Virtual tables are allowed to use constraints like x=NULL. So ** a term of the form x=y does not prove that y is not null if x ** is the column of a virtual table */ case TK_EQ: case TK_NE: case TK_LT: case TK_LE: case TK_GT: case TK_GE: { Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; testcase( pExpr->op==TK_EQ ); testcase( pExpr->op==TK_NE ); testcase( pExpr->op==TK_LT ); testcase( pExpr->op==TK_LE ); testcase( pExpr->op==TK_GT ); testcase( pExpr->op==TK_GE ); /* The y.pTab=0 assignment in wherecode.c always happens after the ** impliesNotNullRow() test */ assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) ); assert( pRight->op!=TK_COLUMN || ExprUseYTab(pRight) ); if( (pLeft->op==TK_COLUMN && ALWAYS(pLeft->y.pTab!=0) && IsVirtual(pLeft->y.pTab)) || (pRight->op==TK_COLUMN && ALWAYS(pRight->y.pTab!=0) && IsVirtual(pRight->y.pTab)) ){ return WRC_Prune; } /* no break */ deliberate_fall_through } default: return WRC_Continue; } } /* ** Return true (non-zero) if expression p can only be true if at least ** one column of table iTab is non-null. In other words, return true ** if expression p will always be NULL or false if every column of iTab ** is NULL. ** ** False negatives are acceptable. In other words, it is ok to return ** zero even if expression p will never be true of every column of iTab ** is NULL. A false negative is merely a missed optimization opportunity. ** ** False positives are not allowed, however. A false positive may result ** in an incorrect answer. ** ** Terms of p that are marked with EP_OuterON (and hence that come from ** the ON or USING clauses of OUTER JOINS) are excluded from the analysis. ** ** This routine is used to check if a LEFT JOIN can be converted into ** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE ** clause requires that some column of the right table of the LEFT JOIN ** be non-NULL, then the LEFT JOIN can be safely converted into an ** ordinary join. */ SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab, int isRJ){ Walker w; p = sqlite3ExprSkipCollateAndLikely(p); if( p==0 ) return 0; if( p->op==TK_NOTNULL ){ p = p->pLeft; }else{ while( p->op==TK_AND ){ if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab, isRJ) ) return 1; p = p->pRight; } } w.xExprCallback = impliesNotNullRow; w.xSelectCallback = 0; w.xSelectCallback2 = 0; w.eCode = 0; w.mWFlags = isRJ!=0; w.u.iCur = iTab; sqlite3WalkExpr(&w, p); return w.eCode; } /* ** An instance of the following structure is used by the tree walker ** to determine if an expression can be evaluated by reference to the ** index only, without having to do a search for the corresponding ** table entry. The IdxCover.pIdx field is the index. IdxCover.iCur ** is the cursor for the table. */ struct IdxCover { Index *pIdx; /* The index to be tested for coverage */ int iCur; /* Cursor number for the table corresponding to the index */ }; /* ** Check to see if there are references to columns in table ** pWalker->u.pIdxCover->iCur can be satisfied using the index ** pWalker->u.pIdxCover->pIdx. */ static int exprIdxCover(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN && pExpr->iTable==pWalker->u.pIdxCover->iCur && sqlite3TableColumnToIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; return WRC_Abort; } return WRC_Continue; } /* ** Determine if an index pIdx on table with cursor iCur contains will ** the expression pExpr. Return true if the index does cover the ** expression and false if the pExpr expression references table columns ** that are not found in the index pIdx. ** ** An index covering an expression means that the expression can be ** evaluated using only the index and without having to lookup the ** corresponding table entry. */ SQLITE_PRIVATE int sqlite3ExprCoveredByIndex( Expr *pExpr, /* The index to be tested */ int iCur, /* The cursor number for the corresponding table */ Index *pIdx /* The index that might be used for coverage */ ){ Walker w; struct IdxCover xcov; memset(&w, 0, sizeof(w)); xcov.iCur = iCur; xcov.pIdx = pIdx; w.xExprCallback = exprIdxCover; w.u.pIdxCover = &xcov; sqlite3WalkExpr(&w, pExpr); return !w.eCode; } /* Structure used to pass information throughout the Walker in order to ** implement sqlite3ReferencesSrcList(). */ struct RefSrcList { sqlite3 *db; /* Database connection used for sqlite3DbRealloc() */ SrcList *pRef; /* Looking for references to these tables */ i64 nExclude; /* Number of tables to exclude from the search */ int *aiExclude; /* Cursor IDs for tables to exclude from the search */ }; /* ** Walker SELECT callbacks for sqlite3ReferencesSrcList(). ** ** When entering a new subquery on the pExpr argument, add all FROM clause ** entries for that subquery to the exclude list. ** ** When leaving the subquery, remove those entries from the exclude list. */ static int selectRefEnter(Walker *pWalker, Select *pSelect){ struct RefSrcList *p = pWalker->u.pRefSrcList; SrcList *pSrc = pSelect->pSrc; i64 i, j; int *piNew; if( pSrc->nSrc==0 ) return WRC_Continue; j = p->nExclude; p->nExclude += pSrc->nSrc; piNew = sqlite3DbRealloc(p->db, p->aiExclude, p->nExclude*sizeof(int)); if( piNew==0 ){ p->nExclude = 0; return WRC_Abort; }else{ p->aiExclude = piNew; } for(i=0; inSrc; i++, j++){ p->aiExclude[j] = pSrc->a[i].iCursor; } return WRC_Continue; } static void selectRefLeave(Walker *pWalker, Select *pSelect){ struct RefSrcList *p = pWalker->u.pRefSrcList; SrcList *pSrc = pSelect->pSrc; if( p->nExclude ){ assert( p->nExclude>=pSrc->nSrc ); p->nExclude -= pSrc->nSrc; } } /* This is the Walker EXPR callback for sqlite3ReferencesSrcList(). ** ** Set the 0x01 bit of pWalker->eCode if there is a reference to any ** of the tables shown in RefSrcList.pRef. ** ** Set the 0x02 bit of pWalker->eCode if there is a reference to a ** table is in neither RefSrcList.pRef nor RefSrcList.aiExclude. */ static int exprRefToSrcList(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){ int i; struct RefSrcList *p = pWalker->u.pRefSrcList; SrcList *pSrc = p->pRef; int nSrc = pSrc ? pSrc->nSrc : 0; for(i=0; iiTable==pSrc->a[i].iCursor ){ pWalker->eCode |= 1; return WRC_Continue; } } for(i=0; inExclude && p->aiExclude[i]!=pExpr->iTable; i++){} if( i>=p->nExclude ){ pWalker->eCode |= 2; } } return WRC_Continue; } /* ** Check to see if pExpr references any tables in pSrcList. ** Possible return values: ** ** 1 pExpr does references a table in pSrcList. ** ** 0 pExpr references some table that is not defined in either ** pSrcList or in subqueries of pExpr itself. ** ** -1 pExpr only references no tables at all, or it only ** references tables defined in subqueries of pExpr itself. ** ** As currently used, pExpr is always an aggregate function call. That ** fact is exploited for efficiency. */ SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){ Walker w; struct RefSrcList x; assert( pParse->db!=0 ); memset(&w, 0, sizeof(w)); memset(&x, 0, sizeof(x)); w.xExprCallback = exprRefToSrcList; w.xSelectCallback = selectRefEnter; w.xSelectCallback2 = selectRefLeave; w.u.pRefSrcList = &x; x.db = pParse->db; x.pRef = pSrcList; assert( pExpr->op==TK_AGG_FUNCTION ); assert( ExprUseXList(pExpr) ); sqlite3WalkExprList(&w, pExpr->x.pList); if( pExpr->pLeft ){ assert( pExpr->pLeft->op==TK_ORDER ); assert( ExprUseXList(pExpr->pLeft) ); assert( pExpr->pLeft->x.pList!=0 ); sqlite3WalkExprList(&w, pExpr->pLeft->x.pList); } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter); } #endif if( x.aiExclude ) sqlite3DbNNFreeNN(pParse->db, x.aiExclude); if( w.eCode & 0x01 ){ return 1; }else if( w.eCode ){ return 0; }else{ return -1; } } /* ** This is a Walker expression node callback. ** ** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo ** object that is referenced does not refer directly to the Expr. If ** it does, make a copy. This is done because the pExpr argument is ** subject to change. ** ** The copy is scheduled for deletion using the sqlite3ExprDeferredDelete() ** which builds on the sqlite3ParserAddCleanup() mechanism. */ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){ if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced)) && pExpr->pAggInfo!=0 ){ AggInfo *pAggInfo = pExpr->pAggInfo; int iAgg = pExpr->iAgg; Parse *pParse = pWalker->pParse; sqlite3 *db = pParse->db; assert( iAgg>=0 ); if( pExpr->op!=TK_AGG_FUNCTION ){ if( iAggnColumn && pAggInfo->aCol[iAgg].pCExpr==pExpr ){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aCol[iAgg].pCExpr = pExpr; sqlite3ExprDeferredDelete(pParse, pExpr); } } }else{ assert( pExpr->op==TK_AGG_FUNCTION ); if( ALWAYS(iAggnFunc) && pAggInfo->aFunc[iAgg].pFExpr==pExpr ){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aFunc[iAgg].pFExpr = pExpr; sqlite3ExprDeferredDelete(pParse, pExpr); } } } } return WRC_Continue; } /* ** Initialize a Walker object so that will persist AggInfo entries referenced ** by the tree that is walked. */ SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker *pWalker, Parse *pParse){ memset(pWalker, 0, sizeof(*pWalker)); pWalker->pParse = pParse; pWalker->xExprCallback = agginfoPersistExprCb; pWalker->xSelectCallback = sqlite3SelectWalkNoop; } /* ** Add a new element to the pAggInfo->aCol[] array. Return the index of ** the new element. Return a negative number if malloc fails. */ static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){ int i; pInfo->aCol = sqlite3ArrayAllocate( db, pInfo->aCol, sizeof(pInfo->aCol[0]), &pInfo->nColumn, &i ); return i; } /* ** Add a new element to the pAggInfo->aFunc[] array. Return the index of ** the new element. Return a negative number if malloc fails. */ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){ int i; pInfo->aFunc = sqlite3ArrayAllocate( db, pInfo->aFunc, sizeof(pInfo->aFunc[0]), &pInfo->nFunc, &i ); return i; } /* ** Search the AggInfo object for an aCol[] entry that has iTable and iColumn. ** Return the index in aCol[] of the entry that describes that column. ** ** If no prior entry is found, create a new one and return -1. The ** new column will have an index of pAggInfo->nColumn-1. */ static void findOrCreateAggInfoColumn( Parse *pParse, /* Parsing context */ AggInfo *pAggInfo, /* The AggInfo object to search and/or modify */ Expr *pExpr /* Expr describing the column to find or insert */ ){ struct AggInfo_col *pCol; int k; assert( pAggInfo->iFirstReg==0 ); pCol = pAggInfo->aCol; for(k=0; knColumn; k++, pCol++){ if( pCol->pCExpr==pExpr ) return; if( pCol->iTable==pExpr->iTable && pCol->iColumn==pExpr->iColumn && pExpr->op!=TK_IF_NULL_ROW ){ goto fix_up_expr; } } k = addAggInfoColumn(pParse->db, pAggInfo); if( k<0 ){ /* OOM on resize */ assert( pParse->db->mallocFailed ); return; } pCol = &pAggInfo->aCol[k]; assert( ExprUseYTab(pExpr) ); pCol->pTab = pExpr->y.pTab; pCol->iTable = pExpr->iTable; pCol->iColumn = pExpr->iColumn; pCol->iSorterColumn = -1; pCol->pCExpr = pExpr; if( pAggInfo->pGroupBy && pExpr->op!=TK_IF_NULL_ROW ){ int j, n; ExprList *pGB = pAggInfo->pGroupBy; struct ExprList_item *pTerm = pGB->a; n = pGB->nExpr; for(j=0; jpExpr; if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable && pE->iColumn==pExpr->iColumn ){ pCol->iSorterColumn = j; break; } } } if( pCol->iSorterColumn<0 ){ pCol->iSorterColumn = pAggInfo->nSortingColumn++; } fix_up_expr: ExprSetVVAProperty(pExpr, EP_NoReduce); assert( pExpr->pAggInfo==0 || pExpr->pAggInfo==pAggInfo ); pExpr->pAggInfo = pAggInfo; if( pExpr->op==TK_COLUMN ){ pExpr->op = TK_AGG_COLUMN; } pExpr->iAgg = (i16)k; } /* ** This is the xExprCallback for a tree walker. It is used to ** implement sqlite3ExprAnalyzeAggregates(). See sqlite3ExprAnalyzeAggregates ** for additional information. */ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ int i; NameContext *pNC = pWalker->u.pNC; Parse *pParse = pNC->pParse; SrcList *pSrcList = pNC->pSrcList; AggInfo *pAggInfo = pNC->uNC.pAggInfo; assert( pNC->ncFlags & NC_UAggInfo ); assert( pAggInfo->iFirstReg==0 ); switch( pExpr->op ){ default: { IndexedExpr *pIEpr; Expr tmp; assert( pParse->iSelfTab==0 ); if( (pNC->ncFlags & NC_InAggFunc)==0 ) break; if( pParse->pIdxEpr==0 ) break; for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){ int iDataCur = pIEpr->iDataCur; if( iDataCur<0 ) continue; if( sqlite3ExprCompare(0, pExpr, pIEpr->pExpr, iDataCur)==0 ) break; } if( pIEpr==0 ) break; if( NEVER(!ExprUseYTab(pExpr)) ) break; for(i=0; inSrc; i++){ if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break; } if( i>=pSrcList->nSrc ) break; if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */ if( pParse->nErr ){ return WRC_Abort; } /* If we reach this point, it means that expression pExpr can be ** translated into a reference to an index column as described by ** pIEpr. */ memset(&tmp, 0, sizeof(tmp)); tmp.op = TK_AGG_COLUMN; tmp.iTable = pIEpr->iIdxCur; tmp.iColumn = pIEpr->iIdxCol; findOrCreateAggInfoColumn(pParse, pAggInfo, &tmp); if( pParse->nErr ){ return WRC_Abort; } assert( pAggInfo->aCol!=0 ); assert( tmp.iAggnColumn ); pAggInfo->aCol[tmp.iAgg].pCExpr = pExpr; pExpr->pAggInfo = pAggInfo; pExpr->iAgg = tmp.iAgg; return WRC_Prune; } case TK_IF_NULL_ROW: case TK_AGG_COLUMN: case TK_COLUMN: { testcase( pExpr->op==TK_AGG_COLUMN ); testcase( pExpr->op==TK_COLUMN ); testcase( pExpr->op==TK_IF_NULL_ROW ); /* Check to see if the column is in one of the tables in the FROM ** clause of the aggregate query */ if( ALWAYS(pSrcList!=0) ){ SrcItem *pItem = pSrcList->a; for(i=0; inSrc; i++, pItem++){ assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); if( pExpr->iTable==pItem->iCursor ){ findOrCreateAggInfoColumn(pParse, pAggInfo, pExpr); break; } /* endif pExpr->iTable==pItem->iCursor */ } /* end loop over pSrcList */ } return WRC_Continue; } case TK_AGG_FUNCTION: { if( (pNC->ncFlags & NC_InAggFunc)==0 && pWalker->walkerDepth==pExpr->op2 && pExpr->pAggInfo==0 ){ /* Check to see if pExpr is a duplicate of another aggregate ** function that is already in the pAggInfo structure */ struct AggInfo_func *pItem = pAggInfo->aFunc; for(i=0; inFunc; i++, pItem++){ if( NEVER(pItem->pFExpr==pExpr) ) break; if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){ break; } } if( i>=pAggInfo->nFunc ){ /* pExpr is original. Make a new entry in pAggInfo->aFunc[] */ u8 enc = ENC(pParse->db); i = addAggInfoFunc(pParse->db, pAggInfo); if( i>=0 ){ int nArg; assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); pItem = &pAggInfo->aFunc[i]; pItem->pFExpr = pExpr; assert( ExprUseUToken(pExpr) ); nArg = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; pItem->pFunc = sqlite3FindFunction(pParse->db, pExpr->u.zToken, nArg, enc, 0); assert( pItem->bOBUnique==0 ); if( pExpr->pLeft && (pItem->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)==0 ){ /* The NEEDCOLL test above causes any ORDER BY clause on ** aggregate min() or max() to be ignored. */ ExprList *pOBList; assert( nArg>0 ); assert( pExpr->pLeft->op==TK_ORDER ); assert( ExprUseXList(pExpr->pLeft) ); pItem->iOBTab = pParse->nTab++; pOBList = pExpr->pLeft->x.pList; assert( pOBList->nExpr>0 ); assert( pItem->bOBUnique==0 ); if( pOBList->nExpr==1 && nArg==1 && sqlite3ExprCompare(0,pOBList->a[0].pExpr, pExpr->x.pList->a[0].pExpr,0)==0 ){ pItem->bOBPayload = 0; pItem->bOBUnique = ExprHasProperty(pExpr, EP_Distinct); }else{ pItem->bOBPayload = 1; } pItem->bUseSubtype = (pItem->pFunc->funcFlags & SQLITE_SUBTYPE)!=0; }else{ pItem->iOBTab = -1; } if( ExprHasProperty(pExpr, EP_Distinct) && !pItem->bOBUnique ){ pItem->iDistinct = pParse->nTab++; }else{ pItem->iDistinct = -1; } } } /* Make pExpr point to the appropriate pAggInfo->aFunc[] entry */ assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(pExpr, EP_NoReduce); pExpr->iAgg = (i16)i; pExpr->pAggInfo = pAggInfo; return WRC_Prune; }else{ return WRC_Continue; } } } return WRC_Continue; } /* ** Analyze the pExpr expression looking for aggregate functions and ** for variables that need to be added to AggInfo object that pNC->pAggInfo ** points to. Additional entries are made on the AggInfo object as ** necessary. ** ** This routine should only be called after the expression has been ** analyzed by sqlite3ResolveExprNames(). */ SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ Walker w; w.xExprCallback = analyzeAggregate; w.xSelectCallback = sqlite3WalkerDepthIncrease; w.xSelectCallback2 = sqlite3WalkerDepthDecrease; w.walkerDepth = 0; w.u.pNC = pNC; w.pParse = 0; assert( pNC->pSrcList!=0 ); sqlite3WalkExpr(&w, pExpr); } /* ** Call sqlite3ExprAnalyzeAggregates() for every expression in an ** expression list. Return the number of errors. ** ** If an error is found, the analysis is cut short. */ SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){ struct ExprList_item *pItem; int i; if( pList ){ for(pItem=pList->a, i=0; inExpr; i++, pItem++){ sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr); } } } /* ** Allocate a single new register for use to hold some intermediate result. */ SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){ if( pParse->nTempReg==0 ){ return ++pParse->nMem; } return pParse->aTempReg[--pParse->nTempReg]; } /* ** Deallocate a register, making available for reuse for some other ** purpose. */ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ if( iReg ){ sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0, 0); if( pParse->nTempRegaTempReg) ){ pParse->aTempReg[pParse->nTempReg++] = iReg; } } } /* ** Allocate or deallocate a block of nReg consecutive registers. */ SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){ int i, n; if( nReg==1 ) return sqlite3GetTempReg(pParse); i = pParse->iRangeReg; n = pParse->nRangeReg; if( nReg<=n ){ pParse->iRangeReg += nReg; pParse->nRangeReg -= nReg; }else{ i = pParse->nMem+1; pParse->nMem += nReg; } return i; } SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, iReg); return; } sqlite3VdbeReleaseRegisters(pParse, iReg, nReg, 0, 0); if( nReg>pParse->nRangeReg ){ pParse->nRangeReg = nReg; pParse->iRangeReg = iReg; } } /* ** Mark all temporary registers as being unavailable for reuse. ** ** Always invoke this procedure after coding a subroutine or co-routine ** that might be invoked from other parts of the code, to ensure that ** the sub/co-routine does not use registers in common with the code that ** invokes the sub/co-routine. */ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){ pParse->nTempReg = 0; pParse->nRangeReg = 0; } /* ** Make sure sufficient registers have been allocated so that ** iReg is a valid register number. */ SQLITE_PRIVATE void sqlite3TouchRegister(Parse *pParse, int iReg){ if( pParse->nMemnMem = iReg; } #if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG) /* ** Return the latest reusable register in the set of all registers. ** The value returned is no less than iMin. If any register iMin or ** greater is in permanent use, then return one more than that last ** permanent register. */ SQLITE_PRIVATE int sqlite3FirstAvailableRegister(Parse *pParse, int iMin){ const ExprList *pList = pParse->pConstExpr; if( pList ){ int i; for(i=0; inExpr; i++){ if( pList->a[i].u.iConstExprReg>=iMin ){ iMin = pList->a[i].u.iConstExprReg + 1; } } } pParse->nTempReg = 0; pParse->nRangeReg = 0; return iMin; } #endif /* SQLITE_ENABLE_STAT4 || SQLITE_DEBUG */ /* ** Validate that no temporary register falls within the range of ** iFirst..iLast, inclusive. This routine is only call from within assert() ** statements. */ #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){ int i; if( pParse->nRangeReg>0 && pParse->iRangeReg+pParse->nRangeReg > iFirst && pParse->iRangeReg <= iLast ){ return 0; } for(i=0; inTempReg; i++){ if( pParse->aTempReg[i]>=iFirst && pParse->aTempReg[i]<=iLast ){ return 0; } } if( pParse->pConstExpr ){ ExprList *pList = pParse->pConstExpr; for(i=0; inExpr; i++){ int iReg = pList->a[i].u.iConstExprReg; if( iReg==0 ) continue; if( iReg>=iFirst && iReg<=iLast ) return 0; } } return 1; } #endif /* SQLITE_DEBUG */ /************** End of expr.c ************************************************/ /************** Begin file alter.c *******************************************/ /* ** 2005 February 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that used to generate VDBE code ** that implements the ALTER TABLE command. */ /* #include "sqliteInt.h" */ /* ** The code in this file only exists if we are not omitting the ** ALTER TABLE logic from the build. */ #ifndef SQLITE_OMIT_ALTERTABLE /* ** Parameter zName is the name of a table that is about to be altered ** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN). ** If the table is a system table, this function leaves an error message ** in pParse->zErr (system tables may not be altered) and returns non-zero. ** ** Or, if zName is not a system table, zero is returned. */ static int isAlterableTable(Parse *pParse, Table *pTab){ if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) #ifndef SQLITE_OMIT_VIRTUALTABLE || (pTab->tabFlags & TF_Eponymous)!=0 || ( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(pParse->db) ) #endif ){ sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName); return 1; } return 0; } /* ** Generate code to verify that the schemas of database zDb and, if ** bTemp is not true, database "temp", can still be parsed. This is ** called at the end of the generation of an ALTER TABLE ... RENAME ... ** statement to ensure that the operation has not rendered any schema ** objects unusable. */ static void renameTestSchema( Parse *pParse, /* Parse context */ const char *zDb, /* Name of db to verify schema of */ int bTemp, /* True if this is the temp db */ const char *zWhen, /* "when" part of error message */ int bNoDQS /* Do not allow DQS in the schema */ ){ pParse->colNamesSet = 1; sqlite3NestedParse(pParse, "SELECT 1 " "FROM \"%w\"." LEGACY_SCHEMA_TABLE " " "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, %d, %Q, %d)=NULL ", zDb, zDb, bTemp, zWhen, bNoDQS ); if( bTemp==0 ){ sqlite3NestedParse(pParse, "SELECT 1 " "FROM temp." LEGACY_SCHEMA_TABLE " " "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, 1, %Q, %d)=NULL ", zDb, zWhen, bNoDQS ); } } /* ** Generate VM code to replace any double-quoted strings (but not double-quoted ** identifiers) within the "sql" column of the sqlite_schema table in ** database zDb with their single-quoted equivalents. If argument bTemp is ** not true, similarly update all SQL statements in the sqlite_schema table ** of the temp db. */ static void renameFixQuotes(Parse *pParse, const char *zDb, int bTemp){ sqlite3NestedParse(pParse, "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET sql = sqlite_rename_quotefix(%Q, sql)" "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" , zDb, zDb ); if( bTemp==0 ){ sqlite3NestedParse(pParse, "UPDATE temp." LEGACY_SCHEMA_TABLE " SET sql = sqlite_rename_quotefix('temp', sql)" "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" ); } } /* ** Generate code to reload the schema for database iDb. And, if iDb!=1, for ** the temp database as well. */ static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){ Vdbe *v = pParse->pVdbe; if( v ){ sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0, p5); if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0, p5); } } /* ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" ** command. */ SQLITE_PRIVATE void sqlite3AlterRenameTable( Parse *pParse, /* Parser context. */ SrcList *pSrc, /* The table to rename. */ Token *pName /* The new table name. */ ){ int iDb; /* Database that contains the table */ char *zDb; /* Name of database iDb */ Table *pTab; /* Table being renamed */ char *zName = 0; /* NULL-terminated version of pName */ sqlite3 *db = pParse->db; /* Database connection */ int nTabName; /* Number of UTF-8 characters in zTabName */ const char *zTabName; /* Original name of the table */ Vdbe *v; VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */ if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(db, pName); if( !zName ) goto exit_rename_table; /* Check that a table or index named 'zName' does not already exist ** in database iDb. If so, this is an error. */ if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) || sqlite3IsShadowTableOf(db, pTab, zName) ){ sqlite3ErrorMsg(pParse, "there is already another table or index with this name: %s", zName); goto exit_rename_table; } /* Make sure it is not a system table being altered, or a reserved name ** that the table is being renamed to. */ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){ goto exit_rename_table; } if( SQLITE_OK!=sqlite3CheckObjectName(pParse,zName,"table",zName) ){ goto exit_rename_table; } #ifndef SQLITE_OMIT_VIEW if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName); goto exit_rename_table; } #endif #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ goto exit_rename_table; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto exit_rename_table; } if( IsVirtual(pTab) ){ pVTab = sqlite3GetVTable(db, pTab); if( pVTab->pVtab->pModule->xRename==0 ){ pVTab = 0; } } #endif /* Begin a transaction for database iDb. Then modify the schema cookie ** (since the ALTER TABLE modifies the schema). Call sqlite3MayAbort(), ** as the scalar functions (e.g. sqlite_rename_table()) invoked by the ** nested SQL may raise an exception. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } sqlite3MayAbort(pParse); /* figure out how many UTF-8 characters are in zName */ zTabName = pTab->zName; nTabName = sqlite3Utf8CharLen(zTabName, -1); /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in ** the schema to use the new table name. */ sqlite3NestedParse(pParse, "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) " "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)" "AND name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" , zDb, zDb, zTabName, zName, (iDb==1), zTabName ); /* Update the tbl_name and name columns of the sqlite_schema table ** as required. */ sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET " "tbl_name = %Q, " "name = CASE " "WHEN type='table' THEN %Q " "WHEN name LIKE 'sqliteX_autoindex%%' ESCAPE 'X' " " AND type='index' THEN " "'sqlite_autoindex_' || %Q || substr(name,%d+18) " "ELSE name END " "WHERE tbl_name=%Q COLLATE nocase AND " "(type='table' OR type='index' OR type='trigger');", zDb, zName, zName, zName, nTabName, zTabName ); #ifndef SQLITE_OMIT_AUTOINCREMENT /* If the sqlite_sequence table exists in this database, then update ** it with the new table name. */ if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ sqlite3NestedParse(pParse, "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q", zDb, zName, pTab->zName); } #endif /* If the table being renamed is not itself part of the temp database, ** edit view and trigger definitions within the temp database ** as required. */ if( iDb!=1 ){ sqlite3NestedParse(pParse, "UPDATE sqlite_temp_schema SET " "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), " "tbl_name = " "CASE WHEN tbl_name=%Q COLLATE nocase AND " " sqlite_rename_test(%Q, sql, type, name, 1, 'after rename', 0) " "THEN %Q ELSE tbl_name END " "WHERE type IN ('view', 'trigger')" , zDb, zTabName, zName, zTabName, zDb, zName); } /* If this is a virtual table, invoke the xRename() function if ** one is defined. The xRename() callback will modify the names ** of any resources used by the v-table implementation (including other ** SQLite tables) that are identified by the name of the virtual table. */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( pVTab ){ int i = ++pParse->nMem; sqlite3VdbeLoadString(v, i, zName); sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); } #endif renameReloadSchema(pParse, iDb, INITFLAG_AlterRename); renameTestSchema(pParse, zDb, iDb==1, "after rename", 0); exit_rename_table: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zName); } /* ** Write code that will raise an error if the table described by ** zDb and zTab is not empty. */ static void sqlite3ErrorIfNotEmpty( Parse *pParse, /* Parsing context */ const char *zDb, /* Schema holding the table */ const char *zTab, /* Table to check for empty */ const char *zErr /* Error message text */ ){ sqlite3NestedParse(pParse, "SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"", zErr, zDb, zTab ); } /* ** This function is called after an "ALTER TABLE ... ADD" statement ** has been parsed. Argument pColDef contains the text of the new ** column definition. ** ** The Table structure pParse->pNewTable was extended to include ** the new column during parsing. */ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ Table *pNew; /* Copy of pParse->pNewTable */ Table *pTab; /* Table being altered */ int iDb; /* Database number */ const char *zDb; /* Database name */ const char *zTab; /* Table name */ char *zCol; /* Null-terminated column definition */ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ sqlite3 *db; /* The database connection; */ Vdbe *v; /* The prepared statement under construction */ int r1; /* Temporary registers */ db = pParse->db; assert( db->pParse==pParse ); if( pParse->nErr ) return; assert( db->mallocFailed==0 ); pNew = pParse->pNewTable; assert( pNew ); assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pNew->pSchema); zDb = db->aDb[iDb].zDbSName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ pCol = &pNew->aCol[pNew->nCol-1]; pDflt = sqlite3ColumnExpr(pNew, pCol); pTab = sqlite3FindTable(db, zTab, zDb); assert( pTab ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ return; } #endif /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. ** If there is a NOT NULL constraint, then the default value for the ** column must not be NULL. */ if( pCol->colFlags & COLFLAG_PRIMKEY ){ sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column"); return; } if( pNew->pIndex ){ sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); return; } if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){ /* If the default value for the new column was specified with a ** literal NULL, then set pDflt to 0. This simplifies checking ** for an SQL NULL default below. */ assert( pDflt==0 || pDflt->op==TK_SPAN ); if( pDflt && pDflt->pLeft->op==TK_NULL ){ pDflt = 0; } assert( IsOrdinaryTable(pNew) ); if( (db->flags&SQLITE_ForeignKeys) && pNew->u.tab.pFKey && pDflt ){ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "Cannot add a REFERENCES column with non-NULL default value"); } if( pCol->notNull && !pDflt ){ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "Cannot add a NOT NULL column with default value NULL"); } /* Ensure the default expression is something that sqlite3ValueFromExpr() ** can handle (i.e. not CURRENT_TIME etc.) */ if( pDflt ){ sqlite3_value *pVal = 0; int rc; rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); if( rc!=SQLITE_OK ){ assert( db->mallocFailed == 1 ); return; } if( !pVal ){ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "Cannot add a column with non-constant default"); } sqlite3ValueFree(pVal); } }else if( pCol->colFlags & COLFLAG_STORED ){ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column"); } /* Modify the CREATE TABLE statement. */ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){ *zEnd-- = '\0'; } /* substr() operations on characters, but addColOffset is in bytes. So we ** have to use printf() to translate between these units: */ assert( IsOrdinaryTable(pTab) ); assert( IsOrdinaryTable(pNew) ); sqlite3NestedParse(pParse, "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = printf('%%.%ds, ',sql) || %Q" " || substr(sql,1+length(printf('%%.%ds',sql))) " "WHERE type = 'table' AND name = %Q", zDb, pNew->u.tab.addColOffset, zCol, pNew->u.tab.addColOffset, zTab ); sqlite3DbFree(db, zCol); } v = sqlite3GetVdbe(pParse); if( v ){ /* Make sure the schema version is at least 3. But do not upgrade ** from less than 3 to 4, as that will corrupt any preexisting DESC ** index. */ r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2); sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); sqlite3ReleaseTempReg(pParse, r1); /* Reload the table definition */ renameReloadSchema(pParse, iDb, INITFLAG_AlterAdd); /* Verify that constraints are still satisfied */ if( pNew->pCheck!=0 || (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0) || (pTab->tabFlags & TF_Strict)!=0 ){ sqlite3NestedParse(pParse, "SELECT CASE WHEN quick_check GLOB 'CHECK*'" " THEN raise(ABORT,'CHECK constraint failed')" " WHEN quick_check GLOB 'non-* value in*'" " THEN raise(ABORT,'type mismatch on DEFAULT')" " ELSE raise(ABORT,'NOT NULL constraint failed')" " END" " FROM pragma_quick_check(%Q,%Q)" " WHERE quick_check GLOB 'CHECK*'" " OR quick_check GLOB 'NULL*'" " OR quick_check GLOB 'non-* value in*'", zTab, zDb ); } } } /* ** This function is called by the parser after the table-name in ** an "ALTER TABLE ADD" statement is parsed. Argument ** pSrc is the full-name of the table being altered. ** ** This routine makes a (partial) copy of the Table structure ** for the table being altered and sets Parse.pNewTable to point ** to it. Routines called by the parser as the column definition ** is parsed (i.e. sqlite3AddColumn()) add the new Column data to ** the copy. The copy of the Table structure is deleted by tokenize.c ** after parsing is finished. ** ** Routine sqlite3AlterFinishAddColumn() will be called to complete ** coding the "ALTER TABLE ... ADD" statement. */ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ Table *pNew; Table *pTab; int iDb; int i; int nAlloc; sqlite3 *db = pParse->db; /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); assert( sqlite3BtreeHoldsAllMutexes(db) ); if( db->mallocFailed ) goto exit_begin_add_column; pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_begin_add_column; #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "virtual tables may not be altered"); goto exit_begin_add_column; } #endif /* Make sure this is not an attempt to ALTER a view. */ if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "Cannot add a column to a view"); goto exit_begin_add_column; } if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){ goto exit_begin_add_column; } sqlite3MayAbort(pParse); assert( IsOrdinaryTable(pTab) ); assert( pTab->u.tab.addColOffset>0 ); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); /* Put a copy of the Table struct in Parse.pNewTable for the ** sqlite3AddColumn() function and friends to modify. But modify ** the name by adding an "sqlite_altertab_" prefix. By adding this ** prefix, we insure that the name will not collide with an existing ** table because user table are not allowed to have the "sqlite_" ** prefix on their name. */ pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table)); if( !pNew ) goto exit_begin_add_column; pParse->pNewTable = pNew; pNew->nTabRef = 1; pNew->nCol = pTab->nCol; assert( pNew->nCol>0 ); nAlloc = (((pNew->nCol-1)/8)*8)+8; assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 ); pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc); pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName); if( !pNew->aCol || !pNew->zName ){ assert( db->mallocFailed ); goto exit_begin_add_column; } memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); for(i=0; inCol; i++){ Column *pCol = &pNew->aCol[i]; pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName); pCol->hName = sqlite3StrIHash(pCol->zCnName); } assert( IsOrdinaryTable(pNew) ); pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0); pNew->pSchema = db->aDb[iDb].pSchema; pNew->u.tab.addColOffset = pTab->u.tab.addColOffset; assert( pNew->nTabRef==1 ); exit_begin_add_column: sqlite3SrcListDelete(db, pSrc); return; } /* ** Parameter pTab is the subject of an ALTER TABLE ... RENAME COLUMN ** command. This function checks if the table is a view or virtual ** table (columns of views or virtual tables may not be renamed). If so, ** it loads an error message into pParse and returns non-zero. ** ** Or, if pTab is not a view or virtual table, zero is returned. */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) static int isRealTable(Parse *pParse, Table *pTab, int bDrop){ const char *zType = 0; #ifndef SQLITE_OMIT_VIEW if( IsView(pTab) ){ zType = "view"; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ zType = "virtual table"; } #endif if( zType ){ sqlite3ErrorMsg(pParse, "cannot %s %s \"%s\"", (bDrop ? "drop column from" : "rename columns of"), zType, pTab->zName ); return 1; } return 0; } #else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ # define isRealTable(x,y,z) (0) #endif /* ** Handles the following parser reduction: ** ** cmd ::= ALTER TABLE pSrc RENAME COLUMN pOld TO pNew */ SQLITE_PRIVATE void sqlite3AlterRenameColumn( Parse *pParse, /* Parsing context */ SrcList *pSrc, /* Table being altered. pSrc->nSrc==1 */ Token *pOld, /* Name of column being changed */ Token *pNew /* New column name */ ){ sqlite3 *db = pParse->db; /* Database connection */ Table *pTab; /* Table being updated */ int iCol; /* Index of column being renamed */ char *zOld = 0; /* Old column name */ char *zNew = 0; /* New column name */ const char *zDb; /* Name of schema containing the table */ int iSchema; /* Index of the schema */ int bQuote; /* True to quote the new name */ /* Locate the table to be altered */ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_column; /* Cannot alter a system table */ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column; if( SQLITE_OK!=isRealTable(pParse, pTab, 0) ) goto exit_rename_column; /* Which schema holds the table to be altered */ iSchema = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iSchema>=0 ); zDb = db->aDb[iSchema].zDbSName; #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ goto exit_rename_column; } #endif /* Make sure the old name really is a column name in the table to be ** altered. Set iCol to be the index of the column being renamed */ zOld = sqlite3NameFromToken(db, pOld); if( !zOld ) goto exit_rename_column; for(iCol=0; iColnCol; iCol++){ if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break; } if( iCol==pTab->nCol ){ sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pOld); goto exit_rename_column; } /* Ensure the schema contains no double-quoted strings */ renameTestSchema(pParse, zDb, iSchema==1, "", 0); renameFixQuotes(pParse, zDb, iSchema==1); /* Do the rename operation using a recursive UPDATE statement that ** uses the sqlite_rename_column() SQL function to compute the new ** CREATE statement text for the sqlite_schema table. */ sqlite3MayAbort(pParse); zNew = sqlite3NameFromToken(db, pNew); if( !zNew ) goto exit_rename_column; assert( pNew->n>0 ); bQuote = sqlite3Isquote(pNew->z[0]); sqlite3NestedParse(pParse, "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) " "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' " " AND (type != 'index' OR tbl_name = %Q)", zDb, zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1, pTab->zName ); sqlite3NestedParse(pParse, "UPDATE temp." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) " "WHERE type IN ('trigger', 'view')", zDb, pTab->zName, iCol, zNew, bQuote ); /* Drop and reload the database schema. */ renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename); renameTestSchema(pParse, zDb, iSchema==1, "after rename", 1); exit_rename_column: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zOld); sqlite3DbFree(db, zNew); return; } /* ** Each RenameToken object maps an element of the parse tree into ** the token that generated that element. The parse tree element ** might be one of: ** ** * A pointer to an Expr that represents an ID ** * The name of a table column in Column.zName ** ** A list of RenameToken objects can be constructed during parsing. ** Each new object is created by sqlite3RenameTokenMap(). ** As the parse tree is transformed, the sqlite3RenameTokenRemap() ** routine is used to keep the mapping current. ** ** After the parse finishes, renameTokenFind() routine can be used ** to look up the actual token value that created some element in ** the parse tree. */ struct RenameToken { const void *p; /* Parse tree element created by token t */ Token t; /* The token that created parse tree element p */ RenameToken *pNext; /* Next is a list of all RenameToken objects */ }; /* ** The context of an ALTER TABLE RENAME COLUMN operation that gets passed ** down into the Walker. */ typedef struct RenameCtx RenameCtx; struct RenameCtx { RenameToken *pList; /* List of tokens to overwrite */ int nList; /* Number of tokens in pList */ int iCol; /* Index of column being renamed */ Table *pTab; /* Table being ALTERed */ const char *zOld; /* Old column name */ }; #ifdef SQLITE_DEBUG /* ** This function is only for debugging. It performs two tasks: ** ** 1. Checks that pointer pPtr does not already appear in the ** rename-token list. ** ** 2. Dereferences each pointer in the rename-token list. ** ** The second is most effective when debugging under valgrind or ** address-sanitizer or similar. If any of these pointers no longer ** point to valid objects, an exception is raised by the memory-checking ** tool. ** ** The point of this is to prevent comparisons of invalid pointer values. ** Even though this always seems to work, it is undefined according to the ** C standard. Example of undefined comparison: ** ** sqlite3_free(x); ** if( x==y ) ... ** ** Technically, as x no longer points into a valid object or to the byte ** following a valid object, it may not be used in comparison operations. */ static void renameTokenCheckAll(Parse *pParse, const void *pPtr){ assert( pParse==pParse->db->pParse ); assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); if( pParse->nErr==0 ){ const RenameToken *p; u32 i = 1; for(p=pParse->pRename; p; p=p->pNext){ if( p->p ){ assert( p->p!=pPtr ); i += *(u8*)(p->p) | 1; } } assert( i>0 ); } } #else # define renameTokenCheckAll(x,y) #endif /* ** Remember that the parser tree element pPtr was created using ** the token pToken. ** ** In other words, construct a new RenameToken object and add it ** to the list of RenameToken objects currently being built up ** in pParse->pRename. ** ** The pPtr argument is returned so that this routine can be used ** with tail recursion in tokenExpr() routine, for a small performance ** improvement. */ SQLITE_PRIVATE const void *sqlite3RenameTokenMap( Parse *pParse, const void *pPtr, const Token *pToken ){ RenameToken *pNew; assert( pPtr || pParse->db->mallocFailed ); renameTokenCheckAll(pParse, pPtr); if( ALWAYS(pParse->eParseMode!=PARSE_MODE_UNMAP) ){ pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken)); if( pNew ){ pNew->p = pPtr; pNew->t = *pToken; pNew->pNext = pParse->pRename; pParse->pRename = pNew; } } return pPtr; } /* ** It is assumed that there is already a RenameToken object associated ** with parse tree element pFrom. This function remaps the associated token ** to parse tree element pTo. */ SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse *pParse, const void *pTo, const void *pFrom){ RenameToken *p; renameTokenCheckAll(pParse, pTo); for(p=pParse->pRename; p; p=p->pNext){ if( p->p==pFrom ){ p->p = pTo; break; } } } /* ** Walker callback used by sqlite3RenameExprUnmap(). */ static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){ Parse *pParse = pWalker->pParse; sqlite3RenameTokenRemap(pParse, 0, (const void*)pExpr); if( ExprUseYTab(pExpr) ){ sqlite3RenameTokenRemap(pParse, 0, (const void*)&pExpr->y.pTab); } return WRC_Continue; } /* ** Iterate through the Select objects that are part of WITH clauses attached ** to select statement pSelect. */ static void renameWalkWith(Walker *pWalker, Select *pSelect){ With *pWith = pSelect->pWith; if( pWith ){ Parse *pParse = pWalker->pParse; int i; With *pCopy = 0; assert( pWith->nCte>0 ); if( (pWith->a[0].pSelect->selFlags & SF_Expanded)==0 ){ /* Push a copy of the With object onto the with-stack. We use a copy ** here as the original will be expanded and resolved (flags SF_Expanded ** and SF_Resolved) below. And the parser code that uses the with-stack ** fails if the Select objects on it have already been expanded and ** resolved. */ pCopy = sqlite3WithDup(pParse->db, pWith); pCopy = sqlite3WithPush(pParse, pCopy, 1); } for(i=0; inCte; i++){ Select *p = pWith->a[i].pSelect; NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; if( pCopy ) sqlite3SelectPrep(sNC.pParse, p, &sNC); if( sNC.pParse->db->mallocFailed ) return; sqlite3WalkSelect(pWalker, p); sqlite3RenameExprlistUnmap(pParse, pWith->a[i].pCols); } if( pCopy && pParse->pWith==pCopy ){ pParse->pWith = pCopy->pOuter; } } } /* ** Unmap all tokens in the IdList object passed as the second argument. */ static void unmapColumnIdlistNames( Parse *pParse, const IdList *pIdList ){ int ii; assert( pIdList!=0 ); for(ii=0; iinId; ii++){ sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName); } } /* ** Walker callback used by sqlite3RenameExprUnmap(). */ static int renameUnmapSelectCb(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; int i; if( pParse->nErr ) return WRC_Abort; testcase( p->selFlags & SF_View ); testcase( p->selFlags & SF_CopyCte ); if( p->selFlags & (SF_View|SF_CopyCte) ){ return WRC_Prune; } if( ALWAYS(p->pEList) ){ ExprList *pList = p->pEList; for(i=0; inExpr; i++){ if( pList->a[i].zEName && pList->a[i].fg.eEName==ENAME_NAME ){ sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName); } } } if( ALWAYS(p->pSrc) ){ /* Every Select as a SrcList, even if it is empty */ SrcList *pSrc = p->pSrc; for(i=0; inSrc; i++){ sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName); if( pSrc->a[i].fg.isUsing==0 ){ sqlite3WalkExpr(pWalker, pSrc->a[i].u3.pOn); }else{ unmapColumnIdlistNames(pParse, pSrc->a[i].u3.pUsing); } } } renameWalkWith(pWalker, p); return WRC_Continue; } /* ** Remove all nodes that are part of expression pExpr from the rename list. */ SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){ u8 eMode = pParse->eParseMode; Walker sWalker; memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = pParse; sWalker.xExprCallback = renameUnmapExprCb; sWalker.xSelectCallback = renameUnmapSelectCb; pParse->eParseMode = PARSE_MODE_UNMAP; sqlite3WalkExpr(&sWalker, pExpr); pParse->eParseMode = eMode; } /* ** Remove all nodes that are part of expression-list pEList from the ** rename list. */ SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){ if( pEList ){ int i; Walker sWalker; memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = pParse; sWalker.xExprCallback = renameUnmapExprCb; sqlite3WalkExprList(&sWalker, pEList); for(i=0; inExpr; i++){ if( ALWAYS(pEList->a[i].fg.eEName==ENAME_NAME) ){ sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zEName); } } } } /* ** Free the list of RenameToken objects given in the second argument */ static void renameTokenFree(sqlite3 *db, RenameToken *pToken){ RenameToken *pNext; RenameToken *p; for(p=pToken; p; p=pNext){ pNext = p->pNext; sqlite3DbFree(db, p); } } /* ** Search the Parse object passed as the first argument for a RenameToken ** object associated with parse tree element pPtr. If found, return a pointer ** to it. Otherwise, return NULL. ** ** If the second argument passed to this function is not NULL and a matching ** RenameToken object is found, remove it from the Parse object and add it to ** the list maintained by the RenameCtx object. */ static RenameToken *renameTokenFind( Parse *pParse, struct RenameCtx *pCtx, const void *pPtr ){ RenameToken **pp; if( NEVER(pPtr==0) ){ return 0; } for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){ if( (*pp)->p==pPtr ){ RenameToken *pToken = *pp; if( pCtx ){ *pp = pToken->pNext; pToken->pNext = pCtx->pList; pCtx->pList = pToken; pCtx->nList++; } return pToken; } } return 0; } /* ** This is a Walker select callback. It does nothing. It is only required ** because without a dummy callback, sqlite3WalkExpr() and similar do not ** descend into sub-select statements. */ static int renameColumnSelectCb(Walker *pWalker, Select *p){ if( p->selFlags & (SF_View|SF_CopyCte) ){ testcase( p->selFlags & SF_View ); testcase( p->selFlags & SF_CopyCte ); return WRC_Prune; } renameWalkWith(pWalker, p); return WRC_Continue; } /* ** This is a Walker expression callback. ** ** For every TK_COLUMN node in the expression tree, search to see ** if the column being references is the column being renamed by an ** ALTER TABLE statement. If it is, then attach its associated ** RenameToken object to the list of RenameToken objects being ** constructed in RenameCtx object at pWalker->u.pRename. */ static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){ RenameCtx *p = pWalker->u.pRename; if( pExpr->op==TK_TRIGGER && pExpr->iColumn==p->iCol && pWalker->pParse->pTriggerTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); }else if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol && ALWAYS(ExprUseYTab(pExpr)) && p->pTab==pExpr->y.pTab ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); } return WRC_Continue; } /* ** The RenameCtx contains a list of tokens that reference a column that ** is being renamed by an ALTER TABLE statement. Return the "last" ** RenameToken in the RenameCtx and remove that RenameToken from the ** RenameContext. "Last" means the last RenameToken encountered when ** the input SQL is parsed from left to right. Repeated calls to this routine ** return all column name tokens in the order that they are encountered ** in the SQL statement. */ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){ RenameToken *pBest = pCtx->pList; RenameToken *pToken; RenameToken **pp; for(pToken=pBest->pNext; pToken; pToken=pToken->pNext){ if( pToken->t.z>pBest->t.z ) pBest = pToken; } for(pp=&pCtx->pList; *pp!=pBest; pp=&(*pp)->pNext); *pp = pBest->pNext; return pBest; } /* ** An error occurred while parsing or otherwise processing a database ** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an ** ALTER TABLE RENAME COLUMN program. The error message emitted by the ** sub-routine is currently stored in pParse->zErrMsg. This function ** adds context to the error message and then stores it in pCtx. */ static void renameColumnParseError( sqlite3_context *pCtx, const char *zWhen, sqlite3_value *pType, sqlite3_value *pObject, Parse *pParse ){ const char *zT = (const char*)sqlite3_value_text(pType); const char *zN = (const char*)sqlite3_value_text(pObject); char *zErr; zErr = sqlite3MPrintf(pParse->db, "error in %s %s%s%s: %s", zT, zN, (zWhen[0] ? " " : ""), zWhen, pParse->zErrMsg ); sqlite3_result_error(pCtx, zErr, -1); sqlite3DbFree(pParse->db, zErr); } /* ** For each name in the the expression-list pEList (i.e. each ** pEList->a[i].zName) that matches the string in zOld, extract the ** corresponding rename-token from Parse object pParse and add it ** to the RenameCtx pCtx. */ static void renameColumnElistNames( Parse *pParse, RenameCtx *pCtx, const ExprList *pEList, const char *zOld ){ if( pEList ){ int i; for(i=0; inExpr; i++){ const char *zName = pEList->a[i].zEName; if( ALWAYS(pEList->a[i].fg.eEName==ENAME_NAME) && ALWAYS(zName!=0) && 0==sqlite3_stricmp(zName, zOld) ){ renameTokenFind(pParse, pCtx, (const void*)zName); } } } } /* ** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName) ** that matches the string in zOld, extract the corresponding rename-token ** from Parse object pParse and add it to the RenameCtx pCtx. */ static void renameColumnIdlistNames( Parse *pParse, RenameCtx *pCtx, const IdList *pIdList, const char *zOld ){ if( pIdList ){ int i; for(i=0; inId; i++){ const char *zName = pIdList->a[i].zName; if( 0==sqlite3_stricmp(zName, zOld) ){ renameTokenFind(pParse, pCtx, (const void*)zName); } } } } /* ** Parse the SQL statement zSql using Parse object (*p). The Parse object ** is initialized by this function before it is used. */ static int renameParseSql( Parse *p, /* Memory to use for Parse object */ const char *zDb, /* Name of schema SQL belongs to */ sqlite3 *db, /* Database handle */ const char *zSql, /* SQL to parse */ int bTemp /* True if SQL is from temp schema */ ){ int rc; sqlite3ParseObjectInit(p, db); if( zSql==0 ){ return SQLITE_NOMEM; } if( sqlite3StrNICmp(zSql,"CREATE ",7)!=0 ){ return SQLITE_CORRUPT_BKPT; } db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb); p->eParseMode = PARSE_MODE_RENAME; p->db = db; p->nQueryLoop = 1; rc = sqlite3RunParser(p, zSql); if( db->mallocFailed ) rc = SQLITE_NOMEM; if( rc==SQLITE_OK && NEVER(p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0) ){ rc = SQLITE_CORRUPT_BKPT; } #ifdef SQLITE_DEBUG /* Ensure that all mappings in the Parse.pRename list really do map to ** a part of the input string. */ if( rc==SQLITE_OK ){ int nSql = sqlite3Strlen30(zSql); RenameToken *pToken; for(pToken=p->pRename; pToken; pToken=pToken->pNext){ assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] ); } } #endif db->init.iDb = 0; return rc; } /* ** This function edits SQL statement zSql, replacing each token identified ** by the linked list pRename with the text of zNew. If argument bQuote is ** true, then zNew is always quoted first. If no error occurs, the result ** is loaded into context object pCtx as the result. ** ** Or, if an error occurs (i.e. an OOM condition), an error is left in ** pCtx and an SQLite error code returned. */ static int renameEditSql( sqlite3_context *pCtx, /* Return result here */ RenameCtx *pRename, /* Rename context */ const char *zSql, /* SQL statement to edit */ const char *zNew, /* New token text */ int bQuote /* True to always quote token */ ){ i64 nNew = sqlite3Strlen30(zNew); i64 nSql = sqlite3Strlen30(zSql); sqlite3 *db = sqlite3_context_db_handle(pCtx); int rc = SQLITE_OK; char *zQuot = 0; char *zOut; i64 nQuot = 0; char *zBuf1 = 0; char *zBuf2 = 0; if( zNew ){ /* Set zQuot to point to a buffer containing a quoted copy of the ** identifier zNew. If the corresponding identifier in the original ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to ** point to zQuot so that all substitutions are made using the ** quoted version of the new column name. */ zQuot = sqlite3MPrintf(db, "\"%w\" ", zNew); if( zQuot==0 ){ return SQLITE_NOMEM; }else{ nQuot = sqlite3Strlen30(zQuot)-1; } assert( nQuot>=nNew ); zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); }else{ zOut = (char*)sqlite3DbMallocZero(db, (nSql*2+1) * 3); if( zOut ){ zBuf1 = &zOut[nSql*2+1]; zBuf2 = &zOut[nSql*4+2]; } } /* At this point pRename->pList contains a list of RenameToken objects ** corresponding to all tokens in the input SQL that must be replaced ** with the new column name, or with single-quoted versions of themselves. ** All that remains is to construct and return the edited SQL string. */ if( zOut ){ int nOut = nSql; memcpy(zOut, zSql, nSql); while( pRename->pList ){ int iOff; /* Offset of token to replace in zOut */ u32 nReplace; const char *zReplace; RenameToken *pBest = renameColumnTokenNext(pRename); if( zNew ){ if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){ nReplace = nNew; zReplace = zNew; }else{ nReplace = nQuot; zReplace = zQuot; if( pBest->t.z[pBest->t.n]=='"' ) nReplace++; } }else{ /* Dequote the double-quoted token. Then requote it again, this time ** using single quotes. If the character immediately following the ** original token within the input SQL was a single quote ('), then ** add another space after the new, single-quoted version of the ** token. This is so that (SELECT "string"'alias') maps to ** (SELECT 'string' 'alias'), and not (SELECT 'string''alias'). */ memcpy(zBuf1, pBest->t.z, pBest->t.n); zBuf1[pBest->t.n] = 0; sqlite3Dequote(zBuf1); sqlite3_snprintf(nSql*2, zBuf2, "%Q%s", zBuf1, pBest->t.z[pBest->t.n]=='\'' ? " " : "" ); zReplace = zBuf2; nReplace = sqlite3Strlen30(zReplace); } iOff = pBest->t.z - zSql; if( pBest->t.n!=nReplace ){ memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n], nOut - (iOff + pBest->t.n) ); nOut += nReplace - pBest->t.n; zOut[nOut] = '\0'; } memcpy(&zOut[iOff], zReplace, nReplace); sqlite3DbFree(db, pBest); } sqlite3_result_text(pCtx, zOut, -1, SQLITE_TRANSIENT); sqlite3DbFree(db, zOut); }else{ rc = SQLITE_NOMEM; } sqlite3_free(zQuot); return rc; } /* ** Set all pEList->a[].fg.eEName fields in the expression-list to val. */ static void renameSetENames(ExprList *pEList, int val){ if( pEList ){ int i; for(i=0; inExpr; i++){ assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME ); pEList->a[i].fg.eEName = val; } } } /* ** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming ** it was read from the schema of database zDb. Return SQLITE_OK if ** successful. Otherwise, return an SQLite error code and leave an error ** message in the Parse object. */ static int renameResolveTrigger(Parse *pParse){ sqlite3 *db = pParse->db; Trigger *pNew = pParse->pNewTrigger; TriggerStep *pStep; NameContext sNC; int rc = SQLITE_OK; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; assert( pNew->pTabSchema ); pParse->pTriggerTab = sqlite3FindTable(db, pNew->table, db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName ); pParse->eTriggerOp = pNew->op; /* ALWAYS() because if the table of the trigger does not exist, the ** error would have been hit before this point */ if( ALWAYS(pParse->pTriggerTab) ){ rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab); } /* Resolve symbols in WHEN clause */ if( rc==SQLITE_OK && pNew->pWhen ){ rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen); } for(pStep=pNew->step_list; rc==SQLITE_OK && pStep; pStep=pStep->pNext){ if( pStep->pSelect ){ sqlite3SelectPrep(pParse, pStep->pSelect, &sNC); if( pParse->nErr ) rc = pParse->rc; } if( rc==SQLITE_OK && pStep->zTarget ){ SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep); if( pSrc ){ Select *pSel = sqlite3SelectNew( pParse, pStep->pExprList, pSrc, 0, 0, 0, 0, 0, 0 ); if( pSel==0 ){ pStep->pExprList = 0; pSrc = 0; rc = SQLITE_NOMEM; }else{ /* pStep->pExprList contains an expression-list used for an UPDATE ** statement. So the a[].zEName values are the RHS of the ** "= " clauses of the UPDATE statement. So, before ** running SelectPrep(), change all the eEName values in ** pStep->pExprList to ENAME_SPAN (from their current value of ** ENAME_NAME). This is to prevent any ids in ON() clauses that are ** part of pSrc from being incorrectly resolved against the ** a[].zEName values as if they were column aliases. */ renameSetENames(pStep->pExprList, ENAME_SPAN); sqlite3SelectPrep(pParse, pSel, 0); renameSetENames(pStep->pExprList, ENAME_NAME); rc = pParse->nErr ? SQLITE_ERROR : SQLITE_OK; assert( pStep->pExprList==0 || pStep->pExprList==pSel->pEList ); assert( pSrc==pSel->pSrc ); if( pStep->pExprList ) pSel->pEList = 0; pSel->pSrc = 0; sqlite3SelectDelete(db, pSel); } if( pStep->pFrom ){ int i; for(i=0; ipFrom->nSrc && rc==SQLITE_OK; i++){ SrcItem *p = &pStep->pFrom->a[i]; if( p->pSelect ){ sqlite3SelectPrep(pParse, p->pSelect, 0); } } } if( db->mallocFailed ){ rc = SQLITE_NOMEM; } sNC.pSrcList = pSrc; if( rc==SQLITE_OK && pStep->pWhere ){ rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere); } if( rc==SQLITE_OK ){ rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList); } assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) ); if( pStep->pUpsert && rc==SQLITE_OK ){ Upsert *pUpsert = pStep->pUpsert; pUpsert->pUpsertSrc = pSrc; sNC.uNC.pUpsert = pUpsert; sNC.ncFlags = NC_UUpsert; rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget); if( rc==SQLITE_OK ){ ExprList *pUpsertSet = pUpsert->pUpsertSet; rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet); } if( rc==SQLITE_OK ){ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere); } if( rc==SQLITE_OK ){ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); } sNC.ncFlags = 0; } sNC.pSrcList = 0; sqlite3SrcListDelete(db, pSrc); }else{ rc = SQLITE_NOMEM; } } } return rc; } /* ** Invoke sqlite3WalkExpr() or sqlite3WalkSelect() on all Select or Expr ** objects that are part of the trigger passed as the second argument. */ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){ TriggerStep *pStep; /* Find tokens to edit in WHEN clause */ sqlite3WalkExpr(pWalker, pTrigger->pWhen); /* Find tokens to edit in trigger steps */ for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ sqlite3WalkSelect(pWalker, pStep->pSelect); sqlite3WalkExpr(pWalker, pStep->pWhere); sqlite3WalkExprList(pWalker, pStep->pExprList); if( pStep->pUpsert ){ Upsert *pUpsert = pStep->pUpsert; sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget); sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet); sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); } if( pStep->pFrom ){ int i; for(i=0; ipFrom->nSrc; i++){ sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect); } } } } /* ** Free the contents of Parse object (*pParse). Do not free the memory ** occupied by the Parse object itself. */ static void renameParseCleanup(Parse *pParse){ sqlite3 *db = pParse->db; Index *pIdx; if( pParse->pVdbe ){ sqlite3VdbeFinalize(pParse->pVdbe); } sqlite3DeleteTable(db, pParse->pNewTable); while( (pIdx = pParse->pNewIndex)!=0 ){ pParse->pNewIndex = pIdx->pNext; sqlite3FreeIndex(db, pIdx); } sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DbFree(db, pParse->zErrMsg); renameTokenFree(db, pParse->pRename); sqlite3ParseObjectReset(pParse); } /* ** SQL function: ** ** sqlite_rename_column(SQL,TYPE,OBJ,DB,TABLE,COL,NEWNAME,QUOTE,TEMP) ** ** 0. zSql: SQL statement to rewrite ** 1. type: Type of object ("table", "view" etc.) ** 2. object: Name of object ** 3. Database: Database name (e.g. "main") ** 4. Table: Table name ** 5. iCol: Index of column to rename ** 6. zNew: New column name ** 7. bQuote: Non-zero if the new column name should be quoted. ** 8. bTemp: True if zSql comes from temp schema ** ** Do a column rename operation on the CREATE statement given in zSql. ** The iCol-th column (left-most is 0) of table zTable is renamed from zCol ** into zNew. The name should be quoted if bQuote is true. ** ** This function is used internally by the ALTER TABLE RENAME COLUMN command. ** It is only accessible to SQL created using sqlite3NestedParse(). It is ** not reachable from ordinary SQL passed into sqlite3_prepare() unless the ** SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test setting is enabled. */ static void renameColumnFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); RenameCtx sCtx; const char *zSql = (const char*)sqlite3_value_text(argv[0]); const char *zDb = (const char*)sqlite3_value_text(argv[3]); const char *zTable = (const char*)sqlite3_value_text(argv[4]); int iCol = sqlite3_value_int(argv[5]); const char *zNew = (const char*)sqlite3_value_text(argv[6]); int bQuote = sqlite3_value_int(argv[7]); int bTemp = sqlite3_value_int(argv[8]); const char *zOld; int rc; Parse sParse; Walker sWalker; Index *pIdx; int i; Table *pTab; #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; #endif UNUSED_PARAMETER(NotUsed); if( zSql==0 ) return; if( zTable==0 ) return; if( zNew==0 ) return; if( iCol<0 ) return; sqlite3BtreeEnterAll(db); pTab = sqlite3FindTable(db, zTable, zDb); if( pTab==0 || iCol>=pTab->nCol ){ sqlite3BtreeLeaveAll(db); return; } zOld = pTab->aCol[iCol].zCnName; memset(&sCtx, 0, sizeof(sCtx)); sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = 0; #endif rc = renameParseSql(&sParse, zDb, db, zSql, bTemp); /* Find tokens that need to be replaced. */ memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = &sParse; sWalker.xExprCallback = renameColumnExprCb; sWalker.xSelectCallback = renameColumnSelectCb; sWalker.u.pRename = &sCtx; sCtx.pTab = pTab; if( rc!=SQLITE_OK ) goto renameColumnFunc_done; if( sParse.pNewTable ){ if( IsView(sParse.pNewTable) ){ Select *pSelect = sParse.pNewTable->u.view.pSelect; pSelect->selFlags &= ~SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); if( rc==SQLITE_OK ){ sqlite3WalkSelect(&sWalker, pSelect); } if( rc!=SQLITE_OK ) goto renameColumnFunc_done; }else if( IsOrdinaryTable(sParse.pNewTable) ){ /* A regular table */ int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName); FKey *pFKey; sCtx.pTab = sParse.pNewTable; if( bFKOnly==0 ){ if( iColnCol ){ renameTokenFind( &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zCnName ); } if( sCtx.iCol<0 ){ renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey); } sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck); for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3WalkExprList(&sWalker, pIdx->aColExpr); } for(pIdx=sParse.pNewIndex; pIdx; pIdx=pIdx->pNext){ sqlite3WalkExprList(&sWalker, pIdx->aColExpr); } #ifndef SQLITE_OMIT_GENERATED_COLUMNS for(i=0; inCol; i++){ Expr *pExpr = sqlite3ColumnExpr(sParse.pNewTable, &sParse.pNewTable->aCol[i]); sqlite3WalkExpr(&sWalker, pExpr); } #endif } assert( IsOrdinaryTable(sParse.pNewTable) ); for(pFKey=sParse.pNewTable->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ for(i=0; inCol; i++){ if( bFKOnly==0 && pFKey->aCol[i].iFrom==iCol ){ renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]); } if( 0==sqlite3_stricmp(pFKey->zTo, zTable) && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld) ){ renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol); } } } } }else if( sParse.pNewIndex ){ sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr); sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); }else{ /* A trigger */ TriggerStep *pStep; rc = renameResolveTrigger(&sParse); if( rc!=SQLITE_OK ) goto renameColumnFunc_done; for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){ if( pStep->zTarget ){ Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb); if( pTarget==pTab ){ if( pStep->pUpsert ){ ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet; renameColumnElistNames(&sParse, &sCtx, pUpsertSet, zOld); } renameColumnIdlistNames(&sParse, &sCtx, pStep->pIdList, zOld); renameColumnElistNames(&sParse, &sCtx, pStep->pExprList, zOld); } } } /* Find tokens to edit in UPDATE OF clause */ if( sParse.pTriggerTab==pTab ){ renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld); } /* Find tokens to edit in various expressions and selects */ renameWalkTrigger(&sWalker, sParse.pNewTrigger); } assert( rc==SQLITE_OK ); rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote); renameColumnFunc_done: if( rc!=SQLITE_OK ){ if( rc==SQLITE_ERROR && sqlite3WritableSchema(db) ){ sqlite3_result_value(context, argv[0]); }else if( sParse.zErrMsg ){ renameColumnParseError(context, "", argv[1], argv[2], &sParse); }else{ sqlite3_result_error_code(context, rc); } } renameParseCleanup(&sParse); renameTokenFree(db, sCtx.pList); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif sqlite3BtreeLeaveAll(db); } /* ** Walker expression callback used by "RENAME TABLE". */ static int renameTableExprCb(Walker *pWalker, Expr *pExpr){ RenameCtx *p = pWalker->u.pRename; if( pExpr->op==TK_COLUMN && ALWAYS(ExprUseYTab(pExpr)) && p->pTab==pExpr->y.pTab ){ renameTokenFind(pWalker->pParse, p, (void*)&pExpr->y.pTab); } return WRC_Continue; } /* ** Walker select callback used by "RENAME TABLE". */ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){ int i; RenameCtx *p = pWalker->u.pRename; SrcList *pSrc = pSelect->pSrc; if( pSelect->selFlags & (SF_View|SF_CopyCte) ){ testcase( pSelect->selFlags & SF_View ); testcase( pSelect->selFlags & SF_CopyCte ); return WRC_Prune; } if( NEVER(pSrc==0) ){ assert( pWalker->pParse->db->mallocFailed ); return WRC_Abort; } for(i=0; inSrc; i++){ SrcItem *pItem = &pSrc->a[i]; if( pItem->pTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, pItem->zName); } } renameWalkWith(pWalker, pSelect); return WRC_Continue; } /* ** This C function implements an SQL user function that is used by SQL code ** generated by the ALTER TABLE ... RENAME command to modify the definition ** of any foreign key constraints that use the table being renamed as the ** parent table. It is passed three arguments: ** ** 0: The database containing the table being renamed. ** 1. type: Type of object ("table", "view" etc.) ** 2. object: Name of object ** 3: The complete text of the schema statement being modified, ** 4: The old name of the table being renamed, and ** 5: The new name of the table being renamed. ** 6: True if the schema statement comes from the temp db. ** ** It returns the new schema statement. For example: ** ** sqlite_rename_table('main', 'CREATE TABLE t1(a REFERENCES t2)','t2','t3',0) ** -> 'CREATE TABLE t1(a REFERENCES t3)' */ static void renameTableFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); const char *zDb = (const char*)sqlite3_value_text(argv[0]); const char *zInput = (const char*)sqlite3_value_text(argv[3]); const char *zOld = (const char*)sqlite3_value_text(argv[4]); const char *zNew = (const char*)sqlite3_value_text(argv[5]); int bTemp = sqlite3_value_int(argv[6]); UNUSED_PARAMETER(NotUsed); if( zInput && zOld && zNew ){ Parse sParse; int rc; int bQuote = 1; RenameCtx sCtx; Walker sWalker; #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; db->xAuth = 0; #endif sqlite3BtreeEnterAll(db); memset(&sCtx, 0, sizeof(RenameCtx)); sCtx.pTab = sqlite3FindTable(db, zOld, zDb); memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = &sParse; sWalker.xExprCallback = renameTableExprCb; sWalker.xSelectCallback = renameTableSelectCb; sWalker.u.pRename = &sCtx; rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); if( rc==SQLITE_OK ){ int isLegacy = (db->flags & SQLITE_LegacyAlter); if( sParse.pNewTable ){ Table *pTab = sParse.pNewTable; if( IsView(pTab) ){ if( isLegacy==0 ){ Select *pSelect = pTab->u.view.pSelect; NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sParse; assert( pSelect->selFlags & SF_View ); pSelect->selFlags &= ~SF_View; sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC); if( sParse.nErr ){ rc = sParse.rc; }else{ sqlite3WalkSelect(&sWalker, pTab->u.view.pSelect); } } }else{ /* Modify any FK definitions to point to the new table. */ #ifndef SQLITE_OMIT_FOREIGN_KEY if( (isLegacy==0 || (db->flags & SQLITE_ForeignKeys)) && !IsVirtual(pTab) ){ FKey *pFKey; assert( IsOrdinaryTable(pTab) ); for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){ renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo); } } } #endif /* If this is the table being altered, fix any table refs in CHECK ** expressions. Also update the name that appears right after the ** "CREATE [VIRTUAL] TABLE" bit. */ if( sqlite3_stricmp(zOld, pTab->zName)==0 ){ sCtx.pTab = pTab; if( isLegacy==0 ){ sqlite3WalkExprList(&sWalker, pTab->pCheck); } renameTokenFind(&sParse, &sCtx, pTab->zName); } } } else if( sParse.pNewIndex ){ renameTokenFind(&sParse, &sCtx, sParse.pNewIndex->zName); if( isLegacy==0 ){ sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); } } #ifndef SQLITE_OMIT_TRIGGER else{ Trigger *pTrigger = sParse.pNewTrigger; TriggerStep *pStep; if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld) && sCtx.pTab->pSchema==pTrigger->pTabSchema ){ renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table); } if( isLegacy==0 ){ rc = renameResolveTrigger(&sParse); if( rc==SQLITE_OK ){ renameWalkTrigger(&sWalker, pTrigger); for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){ renameTokenFind(&sParse, &sCtx, pStep->zTarget); } if( pStep->pFrom ){ int i; for(i=0; ipFrom->nSrc; i++){ SrcItem *pItem = &pStep->pFrom->a[i]; if( 0==sqlite3_stricmp(pItem->zName, zOld) ){ renameTokenFind(&sParse, &sCtx, pItem->zName); } } } } } } } #endif } if( rc==SQLITE_OK ){ rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote); } if( rc!=SQLITE_OK ){ if( rc==SQLITE_ERROR && sqlite3WritableSchema(db) ){ sqlite3_result_value(context, argv[3]); }else if( sParse.zErrMsg ){ renameColumnParseError(context, "", argv[1], argv[2], &sParse); }else{ sqlite3_result_error_code(context, rc); } } renameParseCleanup(&sParse); renameTokenFree(db, sCtx.pList); sqlite3BtreeLeaveAll(db); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif } return; } static int renameQuotefixExprCb(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_STRING && (pExpr->flags & EP_DblQuoted) ){ renameTokenFind(pWalker->pParse, pWalker->u.pRename, (const void*)pExpr); } return WRC_Continue; } /* SQL function: sqlite_rename_quotefix(DB,SQL) ** ** Rewrite the DDL statement "SQL" so that any string literals that use ** double-quotes use single quotes instead. ** ** Two arguments must be passed: ** ** 0: Database name ("main", "temp" etc.). ** 1: SQL statement to edit. ** ** The returned value is the modified SQL statement. For example, given ** the database schema: ** ** CREATE TABLE t1(a, b, c); ** ** SELECT sqlite_rename_quotefix('main', ** 'CREATE VIEW v1 AS SELECT "a", "string" FROM t1' ** ); ** ** returns the string: ** ** CREATE VIEW v1 AS SELECT "a", 'string' FROM t1 ** ** If there is a error in the input SQL, then raise an error, except ** if PRAGMA writable_schema=ON, then just return the input string ** unmodified following an error. */ static void renameQuotefixFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); char const *zDb = (const char*)sqlite3_value_text(argv[0]); char const *zInput = (const char*)sqlite3_value_text(argv[1]); #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; db->xAuth = 0; #endif sqlite3BtreeEnterAll(db); UNUSED_PARAMETER(NotUsed); if( zDb && zInput ){ int rc; Parse sParse; rc = renameParseSql(&sParse, zDb, db, zInput, 0); if( rc==SQLITE_OK ){ RenameCtx sCtx; Walker sWalker; /* Walker to find tokens that need to be replaced. */ memset(&sCtx, 0, sizeof(RenameCtx)); memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = &sParse; sWalker.xExprCallback = renameQuotefixExprCb; sWalker.xSelectCallback = renameColumnSelectCb; sWalker.u.pRename = &sCtx; if( sParse.pNewTable ){ if( IsView(sParse.pNewTable) ){ Select *pSelect = sParse.pNewTable->u.view.pSelect; pSelect->selFlags &= ~SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); if( rc==SQLITE_OK ){ sqlite3WalkSelect(&sWalker, pSelect); } }else{ int i; sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck); #ifndef SQLITE_OMIT_GENERATED_COLUMNS for(i=0; inCol; i++){ sqlite3WalkExpr(&sWalker, sqlite3ColumnExpr(sParse.pNewTable, &sParse.pNewTable->aCol[i])); } #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ } }else if( sParse.pNewIndex ){ sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr); sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); }else{ #ifndef SQLITE_OMIT_TRIGGER rc = renameResolveTrigger(&sParse); if( rc==SQLITE_OK ){ renameWalkTrigger(&sWalker, sParse.pNewTrigger); } #endif /* SQLITE_OMIT_TRIGGER */ } if( rc==SQLITE_OK ){ rc = renameEditSql(context, &sCtx, zInput, 0, 0); } renameTokenFree(db, sCtx.pList); } if( rc!=SQLITE_OK ){ if( sqlite3WritableSchema(db) && rc==SQLITE_ERROR ){ sqlite3_result_value(context, argv[1]); }else{ sqlite3_result_error_code(context, rc); } } renameParseCleanup(&sParse); } #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif sqlite3BtreeLeaveAll(db); } /* Function: sqlite_rename_test(DB,SQL,TYPE,NAME,ISTEMP,WHEN,DQS) ** ** An SQL user function that checks that there are no parse or symbol ** resolution problems in a CREATE TRIGGER|TABLE|VIEW|INDEX statement. ** After an ALTER TABLE .. RENAME operation is performed and the schema ** reloaded, this function is called on each SQL statement in the schema ** to ensure that it is still usable. ** ** 0: Database name ("main", "temp" etc.). ** 1: SQL statement. ** 2: Object type ("view", "table", "trigger" or "index"). ** 3: Object name. ** 4: True if object is from temp schema. ** 5: "when" part of error message. ** 6: True to disable the DQS quirk when parsing SQL. ** ** The return value is computed as follows: ** ** A. If an error is seen and not in PRAGMA writable_schema=ON mode, ** then raise the error. ** B. Else if a trigger is created and the the table that the trigger is ** attached to is in database zDb, then return 1. ** C. Otherwise return NULL. */ static void renameTableTest( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); char const *zDb = (const char*)sqlite3_value_text(argv[0]); char const *zInput = (const char*)sqlite3_value_text(argv[1]); int bTemp = sqlite3_value_int(argv[4]); int isLegacy = (db->flags & SQLITE_LegacyAlter); char const *zWhen = (const char*)sqlite3_value_text(argv[5]); int bNoDQS = sqlite3_value_int(argv[6]); #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; db->xAuth = 0; #endif UNUSED_PARAMETER(NotUsed); if( zDb && zInput ){ int rc; Parse sParse; int flags = db->flags; if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL); rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); db->flags |= (flags & (SQLITE_DqsDML|SQLITE_DqsDDL)); if( rc==SQLITE_OK ){ if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sParse; sqlite3SelectPrep(&sParse, sParse.pNewTable->u.view.pSelect, &sNC); if( sParse.nErr ) rc = sParse.rc; } else if( sParse.pNewTrigger ){ if( isLegacy==0 ){ rc = renameResolveTrigger(&sParse); } if( rc==SQLITE_OK ){ int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema); int i2 = sqlite3FindDbName(db, zDb); if( i1==i2 ){ /* Handle output case B */ sqlite3_result_int(context, 1); } } } } if( rc!=SQLITE_OK && zWhen && !sqlite3WritableSchema(db) ){ /* Output case A */ renameColumnParseError(context, zWhen, argv[2], argv[3],&sParse); } renameParseCleanup(&sParse); } #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif } /* ** The implementation of internal UDF sqlite_drop_column(). ** ** Arguments: ** ** argv[0]: An integer - the index of the schema containing the table ** argv[1]: CREATE TABLE statement to modify. ** argv[2]: An integer - the index of the column to remove. ** ** The value returned is a string containing the CREATE TABLE statement ** with column argv[2] removed. */ static void dropColumnFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); int iSchema = sqlite3_value_int(argv[0]); const char *zSql = (const char*)sqlite3_value_text(argv[1]); int iCol = sqlite3_value_int(argv[2]); const char *zDb = db->aDb[iSchema].zDbSName; int rc; Parse sParse; RenameToken *pCol; Table *pTab; const char *zEnd; char *zNew = 0; #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; db->xAuth = 0; #endif UNUSED_PARAMETER(NotUsed); rc = renameParseSql(&sParse, zDb, db, zSql, iSchema==1); if( rc!=SQLITE_OK ) goto drop_column_done; pTab = sParse.pNewTable; if( pTab==0 || pTab->nCol==1 || iCol>=pTab->nCol ){ /* This can happen if the sqlite_schema table is corrupt */ rc = SQLITE_CORRUPT_BKPT; goto drop_column_done; } pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName); if( iColnCol-1 ){ RenameToken *pEnd; pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zCnName); zEnd = (const char*)pEnd->t.z; }else{ assert( IsOrdinaryTable(pTab) ); zEnd = (const char*)&zSql[pTab->u.tab.addColOffset]; while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--; } zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd); sqlite3_result_text(context, zNew, -1, SQLITE_TRANSIENT); sqlite3_free(zNew); drop_column_done: renameParseCleanup(&sParse); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif if( rc!=SQLITE_OK ){ sqlite3_result_error_code(context, rc); } } /* ** This function is called by the parser upon parsing an ** ** ALTER TABLE pSrc DROP COLUMN pName ** ** statement. Argument pSrc contains the possibly qualified name of the ** table being edited, and token pName the name of the column to drop. */ SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const Token *pName){ sqlite3 *db = pParse->db; /* Database handle */ Table *pTab; /* Table to modify */ int iDb; /* Index of db containing pTab in aDb[] */ const char *zDb; /* Database containing pTab ("main" etc.) */ char *zCol = 0; /* Name of column to drop */ int iCol; /* Index of column zCol in pTab->aCol[] */ /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); assert( sqlite3BtreeHoldsAllMutexes(db) ); if( NEVER(db->mallocFailed) ) goto exit_drop_column; pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_drop_column; /* Make sure this is not an attempt to ALTER a view, virtual table or ** system table. */ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_drop_column; if( SQLITE_OK!=isRealTable(pParse, pTab, 1) ) goto exit_drop_column; /* Find the index of the column being dropped. */ zCol = sqlite3NameFromToken(db, pName); if( zCol==0 ){ assert( db->mallocFailed ); goto exit_drop_column; } iCol = sqlite3ColumnIndex(pTab, zCol); if( iCol<0 ){ sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pName); goto exit_drop_column; } /* Do not allow the user to drop a PRIMARY KEY column or a column ** constrained by a UNIQUE constraint. */ if( pTab->aCol[iCol].colFlags & (COLFLAG_PRIMKEY|COLFLAG_UNIQUE) ){ sqlite3ErrorMsg(pParse, "cannot drop %s column: \"%s\"", (pTab->aCol[iCol].colFlags&COLFLAG_PRIMKEY) ? "PRIMARY KEY" : "UNIQUE", zCol ); goto exit_drop_column; } /* Do not allow the number of columns to go to zero */ if( pTab->nCol<=1 ){ sqlite3ErrorMsg(pParse, "cannot drop column \"%s\": no other columns exist",zCol); goto exit_drop_column; } /* Edit the sqlite_schema table */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 ); zDb = db->aDb[iDb].zDbSName; #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, zCol) ){ goto exit_drop_column; } #endif renameTestSchema(pParse, zDb, iDb==1, "", 0); renameFixQuotes(pParse, zDb, iDb==1); sqlite3NestedParse(pParse, "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_drop_column(%d, sql, %d) " "WHERE (type=='table' AND tbl_name=%Q COLLATE nocase)" , zDb, iDb, iCol, pTab->zName ); /* Drop and reload the database schema. */ renameReloadSchema(pParse, iDb, INITFLAG_AlterDrop); renameTestSchema(pParse, zDb, iDb==1, "after drop column", 1); /* Edit rows of table on disk */ if( pParse->nErr==0 && (pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL)==0 ){ int i; int addr; int reg; int regRec; Index *pPk = 0; int nField = 0; /* Number of non-virtual columns after drop */ int iCur; Vdbe *v = sqlite3GetVdbe(pParse); iCur = pParse->nTab++; sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); reg = ++pParse->nMem; if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg); pParse->nMem += pTab->nCol; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); pParse->nMem += pPk->nColumn; for(i=0; inKeyCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, iCur, i, reg+i+1); } nField = pPk->nKeyCol; } regRec = ++pParse->nMem; for(i=0; inCol; i++){ if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ int regOut; if( pPk ){ int iPos = sqlite3TableColumnToIndex(pPk, i); int iColPos = sqlite3TableColumnToIndex(pPk, iCol); if( iPosnKeyCol ) continue; regOut = reg+1+iPos-(iPos>iColPos); }else{ regOut = reg+1+nField; } if( i==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regOut); }else{ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut); } nField++; } } if( nField==0 ){ /* dbsqlfuzz 5f09e7bcc78b4954d06bf9f2400d7715f48d1fef */ pParse->nMem++; sqlite3VdbeAddOp2(v, OP_Null, 0, reg+1); nField = 1; } sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec); if( pPk ){ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol); }else{ sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg); } sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr); } exit_drop_column: sqlite3DbFree(db, zCol); sqlite3SrcListDelete(db, pSrc); } /* ** Register built-in functions used to help implement ALTER TABLE */ SQLITE_PRIVATE void sqlite3AlterFunctions(void){ static FuncDef aAlterTableFuncs[] = { INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc), INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc), INTERNAL_FUNCTION(sqlite_rename_test, 7, renameTableTest), INTERNAL_FUNCTION(sqlite_drop_column, 3, dropColumnFunc), INTERNAL_FUNCTION(sqlite_rename_quotefix,2, renameQuotefixFunc), }; sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); } #endif /* SQLITE_ALTER_TABLE */ /************** End of alter.c ***********************************************/ /************** Begin file analyze.c *****************************************/ /* ** 2005-07-08 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code associated with the ANALYZE command. ** ** The ANALYZE command gather statistics about the content of tables ** and indices. These statistics are made available to the query planner ** to help it make better decisions about how to perform queries. ** ** The following system tables are or have been supported: ** ** CREATE TABLE sqlite_stat1(tbl, idx, stat); ** CREATE TABLE sqlite_stat2(tbl, idx, sampleno, sample); ** CREATE TABLE sqlite_stat3(tbl, idx, nEq, nLt, nDLt, sample); ** CREATE TABLE sqlite_stat4(tbl, idx, nEq, nLt, nDLt, sample); ** ** Additional tables might be added in future releases of SQLite. ** The sqlite_stat2 table is not created or used unless the SQLite version ** is between 3.6.18 and 3.7.8, inclusive, and unless SQLite is compiled ** with SQLITE_ENABLE_STAT2. The sqlite_stat2 table is deprecated. ** The sqlite_stat2 table is superseded by sqlite_stat3, which is only ** created and used by SQLite versions 3.7.9 through 3.29.0 when ** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3 ** is a superset of sqlite_stat2 and is also now deprecated. The ** sqlite_stat4 is an enhanced version of sqlite_stat3 and is only ** available when compiled with SQLITE_ENABLE_STAT4 and in SQLite ** versions 3.8.1 and later. STAT4 is the only variant that is still ** supported. ** ** For most applications, sqlite_stat1 provides all the statistics required ** for the query planner to make good choices. ** ** Format of sqlite_stat1: ** ** There is normally one row per index, with the index identified by the ** name in the idx column. The tbl column is the name of the table to ** which the index belongs. In each such row, the stat column will be ** a string consisting of a list of integers. The first integer in this ** list is the number of rows in the index. (This is the same as the ** number of rows in the table, except for partial indices.) The second ** integer is the average number of rows in the index that have the same ** value in the first column of the index. The third integer is the average ** number of rows in the index that have the same value for the first two ** columns. The N-th integer (for N>1) is the average number of rows in ** the index which have the same value for the first N-1 columns. For ** a K-column index, there will be K+1 integers in the stat column. If ** the index is unique, then the last integer will be 1. ** ** The list of integers in the stat column can optionally be followed ** by the keyword "unordered". The "unordered" keyword, if it is present, ** must be separated from the last integer by a single space. If the ** "unordered" keyword is present, then the query planner assumes that ** the index is unordered and will not use the index for a range query. ** ** If the sqlite_stat1.idx column is NULL, then the sqlite_stat1.stat ** column contains a single integer which is the (estimated) number of ** rows in the table identified by sqlite_stat1.tbl. ** ** Format of sqlite_stat2: ** ** The sqlite_stat2 is only created and is only used if SQLite is compiled ** with SQLITE_ENABLE_STAT2 and if the SQLite version number is between ** 3.6.18 and 3.7.8. The "stat2" table contains additional information ** about the distribution of keys within an index. The index is identified by ** the "idx" column and the "tbl" column is the name of the table to which ** the index belongs. There are usually 10 rows in the sqlite_stat2 ** table for each index. ** ** The sqlite_stat2 entries for an index that have sampleno between 0 and 9 ** inclusive are samples of the left-most key value in the index taken at ** evenly spaced points along the index. Let the number of samples be S ** (10 in the standard build) and let C be the number of rows in the index. ** Then the sampled rows are given by: ** ** rownumber = (i*C*2 + C)/(S*2) ** ** For i between 0 and S-1. Conceptually, the index space is divided into ** S uniform buckets and the samples are the middle row from each bucket. ** ** The format for sqlite_stat2 is recorded here for legacy reference. This ** version of SQLite does not support sqlite_stat2. It neither reads nor ** writes the sqlite_stat2 table. This version of SQLite only supports ** sqlite_stat3. ** ** Format for sqlite_stat3: ** ** The sqlite_stat3 format is a subset of sqlite_stat4. Hence, the ** sqlite_stat4 format will be described first. Further information ** about sqlite_stat3 follows the sqlite_stat4 description. ** ** Format for sqlite_stat4: ** ** As with sqlite_stat2, the sqlite_stat4 table contains histogram data ** to aid the query planner in choosing good indices based on the values ** that indexed columns are compared against in the WHERE clauses of ** queries. ** ** The sqlite_stat4 table contains multiple entries for each index. ** The idx column names the index and the tbl column is the table of the ** index. If the idx and tbl columns are the same, then the sample is ** of the INTEGER PRIMARY KEY. The sample column is a blob which is the ** binary encoding of a key from the index. The nEq column is a ** list of integers. The first integer is the approximate number ** of entries in the index whose left-most column exactly matches ** the left-most column of the sample. The second integer in nEq ** is the approximate number of entries in the index where the ** first two columns match the first two columns of the sample. ** And so forth. nLt is another list of integers that show the approximate ** number of entries that are strictly less than the sample. The first ** integer in nLt contains the number of entries in the index where the ** left-most column is less than the left-most column of the sample. ** The K-th integer in the nLt entry is the number of index entries ** where the first K columns are less than the first K columns of the ** sample. The nDLt column is like nLt except that it contains the ** number of distinct entries in the index that are less than the ** sample. ** ** There can be an arbitrary number of sqlite_stat4 entries per index. ** The ANALYZE command will typically generate sqlite_stat4 tables ** that contain between 10 and 40 samples which are distributed across ** the key space, though not uniformly, and which include samples with ** large nEq values. ** ** Format for sqlite_stat3 redux: ** ** The sqlite_stat3 table is like sqlite_stat4 except that it only ** looks at the left-most column of the index. The sqlite_stat3.sample ** column contains the actual value of the left-most column instead ** of a blob encoding of the complete index key as is found in ** sqlite_stat4.sample. The nEq, nLt, and nDLt entries of sqlite_stat3 ** all contain just a single integer which is the same as the first ** integer in the equivalent columns in sqlite_stat4. */ #ifndef SQLITE_OMIT_ANALYZE /* #include "sqliteInt.h" */ #if defined(SQLITE_ENABLE_STAT4) # define IsStat4 1 #else # define IsStat4 0 # undef SQLITE_STAT4_SAMPLES # define SQLITE_STAT4_SAMPLES 1 #endif /* ** This routine generates code that opens the sqlite_statN tables. ** The sqlite_stat1 table is always relevant. sqlite_stat2 is now ** obsolete. sqlite_stat3 and sqlite_stat4 are only opened when ** appropriate compile-time options are provided. ** ** If the sqlite_statN tables do not previously exist, it is created. ** ** Argument zWhere may be a pointer to a buffer containing a table name, ** or it may be a NULL pointer. If it is not NULL, then all entries in ** the sqlite_statN tables associated with the named table are deleted. ** If zWhere==0, then code is generated to delete all stat table entries. */ static void openStatTable( Parse *pParse, /* Parsing context */ int iDb, /* The database we are looking in */ int iStatCur, /* Open the sqlite_stat1 table on this cursor */ const char *zWhere, /* Delete entries for this table or index */ const char *zWhereType /* Either "tbl" or "idx" */ ){ static const struct { const char *zName; const char *zCols; } aTable[] = { { "sqlite_stat1", "tbl,idx,stat" }, #if defined(SQLITE_ENABLE_STAT4) { "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" }, #else { "sqlite_stat4", 0 }, #endif { "sqlite_stat3", 0 }, }; int i; sqlite3 *db = pParse->db; Db *pDb; Vdbe *v = sqlite3GetVdbe(pParse); u32 aRoot[ArraySize(aTable)]; u8 aCreateTbl[ArraySize(aTable)]; #ifdef SQLITE_ENABLE_STAT4 const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1; #else const int nToOpen = 1; #endif if( v==0 ) return; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3VdbeDb(v)==db ); pDb = &db->aDb[iDb]; /* Create new statistic tables if they do not exist, or clear them ** if they do already exist. */ for(i=0; izDbSName))==0 ){ if( iregRoot. This is important ** because the OpenWrite opcode below will be needing it. */ sqlite3NestedParse(pParse, "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); aRoot[i] = (u32)pParse->regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } }else{ /* The table already exists. If zWhere is not NULL, delete all entries ** associated with the table zWhere. If zWhere is NULL, delete the ** entire contents of the table. */ aRoot[i] = pStat->tnum; sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); if( zWhere ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE %s=%Q", pDb->zDbSName, zTab, zWhereType, zWhere ); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK }else if( db->xPreUpdateCallback ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab); #endif }else{ /* The sqlite_stat[134] table already exists. Delete all rows. */ sqlite3VdbeAddOp2(v, OP_Clear, (int)aRoot[i], iDb); } } } /* Open the sqlite_stat[134] tables for writing. */ for(i=0; inRowid ){ sqlite3DbFree(db, p->u.aRowid); p->nRowid = 0; } } #endif /* Initialize the BLOB value of a ROWID */ #ifdef SQLITE_ENABLE_STAT4 static void sampleSetRowid(sqlite3 *db, StatSample *p, int n, const u8 *pData){ assert( db!=0 ); if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid); p->u.aRowid = sqlite3DbMallocRawNN(db, n); if( p->u.aRowid ){ p->nRowid = n; memcpy(p->u.aRowid, pData, n); }else{ p->nRowid = 0; } } #endif /* Initialize the INTEGER value of a ROWID. */ #ifdef SQLITE_ENABLE_STAT4 static void sampleSetRowidInt64(sqlite3 *db, StatSample *p, i64 iRowid){ assert( db!=0 ); if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid); p->nRowid = 0; p->u.iRowid = iRowid; } #endif /* ** Copy the contents of object (*pFrom) into (*pTo). */ #ifdef SQLITE_ENABLE_STAT4 static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){ pTo->isPSample = pFrom->isPSample; pTo->iCol = pFrom->iCol; pTo->iHash = pFrom->iHash; memcpy(pTo->anEq, pFrom->anEq, sizeof(tRowcnt)*p->nCol); memcpy(pTo->anLt, pFrom->anLt, sizeof(tRowcnt)*p->nCol); memcpy(pTo->anDLt, pFrom->anDLt, sizeof(tRowcnt)*p->nCol); if( pFrom->nRowid ){ sampleSetRowid(p->db, pTo, pFrom->nRowid, pFrom->u.aRowid); }else{ sampleSetRowidInt64(p->db, pTo, pFrom->u.iRowid); } } #endif /* ** Reclaim all memory of a StatAccum structure. */ static void statAccumDestructor(void *pOld){ StatAccum *p = (StatAccum*)pOld; #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ){ int i; for(i=0; inCol; i++) sampleClear(p->db, p->aBest+i); for(i=0; imxSample; i++) sampleClear(p->db, p->a+i); sampleClear(p->db, &p->current); } #endif sqlite3DbFree(p->db, p); } /* ** Implementation of the stat_init(N,K,C,L) SQL function. The four parameters ** are: ** N: The number of columns in the index including the rowid/pk (note 1) ** K: The number of columns in the index excluding the rowid/pk. ** C: Estimated number of rows in the index ** L: A limit on the number of rows to scan, or 0 for no-limit ** ** Note 1: In the special case of the covering index that implements a ** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the ** total number of columns in the table. ** ** For indexes on ordinary rowid tables, N==K+1. But for indexes on ** WITHOUT ROWID tables, N=K+P where P is the number of columns in the ** PRIMARY KEY of the table. The covering index that implements the ** original WITHOUT ROWID table as N==K as a special case. ** ** This routine allocates the StatAccum object in heap memory. The return ** value is a pointer to the StatAccum object. The datatype of the ** return value is BLOB, but it is really just a pointer to the StatAccum ** object. */ static void statInit( sqlite3_context *context, int argc, sqlite3_value **argv ){ StatAccum *p; int nCol; /* Number of columns in index being sampled */ int nKeyCol; /* Number of key columns */ int nColUp; /* nCol rounded up for alignment */ int n; /* Bytes of space to allocate */ sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */ #ifdef SQLITE_ENABLE_STAT4 /* Maximum number of samples. 0 if STAT4 data is not collected */ int mxSample = OptimizationEnabled(db,SQLITE_Stat4) ?SQLITE_STAT4_SAMPLES :0; #endif /* Decode the three function arguments */ UNUSED_PARAMETER(argc); nCol = sqlite3_value_int(argv[0]); assert( nCol>0 ); nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol; nKeyCol = sqlite3_value_int(argv[1]); assert( nKeyCol<=nCol ); assert( nKeyCol>0 ); /* Allocate the space required for the StatAccum object */ n = sizeof(*p) + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */ #ifdef SQLITE_ENABLE_STAT4 n += sizeof(tRowcnt)*nColUp; /* StatAccum.anEq */ if( mxSample ){ n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */ + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */ + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample); } #endif p = sqlite3DbMallocZero(db, n); if( p==0 ){ sqlite3_result_error_nomem(context); return; } p->db = db; p->nEst = sqlite3_value_int64(argv[2]); p->nRow = 0; p->nLimit = sqlite3_value_int64(argv[3]); p->nCol = nCol; p->nKeyCol = nKeyCol; p->nSkipAhead = 0; p->current.anDLt = (tRowcnt*)&p[1]; #ifdef SQLITE_ENABLE_STAT4 p->current.anEq = &p->current.anDLt[nColUp]; p->mxSample = p->nLimit==0 ? mxSample : 0; if( mxSample ){ u8 *pSpace; /* Allocated space not yet assigned */ int i; /* Used to iterate through p->aSample[] */ p->iGet = -1; p->nPSample = (tRowcnt)(p->nEst/(mxSample/3+1) + 1); p->current.anLt = &p->current.anEq[nColUp]; p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]); /* Set up the StatAccum.a[] and aBest[] arrays */ p->a = (struct StatSample*)&p->current.anLt[nColUp]; p->aBest = &p->a[mxSample]; pSpace = (u8*)(&p->a[mxSample+nCol]); for(i=0; i<(mxSample+nCol); i++){ p->a[i].anEq = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); p->a[i].anLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); } assert( (pSpace - (u8*)p)==n ); for(i=0; iaBest[i].iCol = i; } } #endif /* Return a pointer to the allocated object to the caller. Note that ** only the pointer (the 2nd parameter) matters. The size of the object ** (given by the 3rd parameter) is never used and can be any positive ** value. */ sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor); } static const FuncDef statInitFuncdef = { 4, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statInit, /* xSFunc */ 0, /* xFinalize */ 0, 0, /* xValue, xInverse */ "stat_init", /* zName */ {0} }; #ifdef SQLITE_ENABLE_STAT4 /* ** pNew and pOld are both candidate non-periodic samples selected for ** the same column (pNew->iCol==pOld->iCol). Ignoring this column and ** considering only any trailing columns and the sample hash value, this ** function returns true if sample pNew is to be preferred over pOld. ** In other words, if we assume that the cardinalities of the selected ** column for pNew and pOld are equal, is pNew to be preferred over pOld. ** ** This function assumes that for each argument sample, the contents of ** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid. */ static int sampleIsBetterPost( StatAccum *pAccum, StatSample *pNew, StatSample *pOld ){ int nCol = pAccum->nCol; int i; assert( pNew->iCol==pOld->iCol ); for(i=pNew->iCol+1; ianEq[i]>pOld->anEq[i] ) return 1; if( pNew->anEq[i]anEq[i] ) return 0; } if( pNew->iHash>pOld->iHash ) return 1; return 0; } #endif #ifdef SQLITE_ENABLE_STAT4 /* ** Return true if pNew is to be preferred over pOld. ** ** This function assumes that for each argument sample, the contents of ** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid. */ static int sampleIsBetter( StatAccum *pAccum, StatSample *pNew, StatSample *pOld ){ tRowcnt nEqNew = pNew->anEq[pNew->iCol]; tRowcnt nEqOld = pOld->anEq[pOld->iCol]; assert( pOld->isPSample==0 && pNew->isPSample==0 ); assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) ); if( (nEqNew>nEqOld) ) return 1; if( nEqNew==nEqOld ){ if( pNew->iColiCol ) return 1; return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld)); } return 0; } /* ** Copy the contents of sample *pNew into the p->a[] array. If necessary, ** remove the least desirable sample from p->a[] to make room. */ static void sampleInsert(StatAccum *p, StatSample *pNew, int nEqZero){ StatSample *pSample = 0; int i; assert( IsStat4 || nEqZero==0 ); /* StatAccum.nMaxEqZero is set to the maximum number of leading 0 ** values in the anEq[] array of any sample in StatAccum.a[]. In ** other words, if nMaxEqZero is n, then it is guaranteed that there ** are no samples with StatSample.anEq[m]==0 for (m>=n). */ if( nEqZero>p->nMaxEqZero ){ p->nMaxEqZero = nEqZero; } if( pNew->isPSample==0 ){ StatSample *pUpgrade = 0; assert( pNew->anEq[pNew->iCol]>0 ); /* This sample is being added because the prefix that ends in column ** iCol occurs many times in the table. However, if we have already ** added a sample that shares this prefix, there is no need to add ** this one. Instead, upgrade the priority of the highest priority ** existing sample that shares this prefix. */ for(i=p->nSample-1; i>=0; i--){ StatSample *pOld = &p->a[i]; if( pOld->anEq[pNew->iCol]==0 ){ if( pOld->isPSample ) return; assert( pOld->iCol>pNew->iCol ); assert( sampleIsBetter(p, pNew, pOld) ); if( pUpgrade==0 || sampleIsBetter(p, pOld, pUpgrade) ){ pUpgrade = pOld; } } } if( pUpgrade ){ pUpgrade->iCol = pNew->iCol; pUpgrade->anEq[pUpgrade->iCol] = pNew->anEq[pUpgrade->iCol]; goto find_new_min; } } /* If necessary, remove sample iMin to make room for the new sample. */ if( p->nSample>=p->mxSample ){ StatSample *pMin = &p->a[p->iMin]; tRowcnt *anEq = pMin->anEq; tRowcnt *anLt = pMin->anLt; tRowcnt *anDLt = pMin->anDLt; sampleClear(p->db, pMin); memmove(pMin, &pMin[1], sizeof(p->a[0])*(p->nSample-p->iMin-1)); pSample = &p->a[p->nSample-1]; pSample->nRowid = 0; pSample->anEq = anEq; pSample->anDLt = anDLt; pSample->anLt = anLt; p->nSample = p->mxSample-1; } /* The "rows less-than" for the rowid column must be greater than that ** for the last sample in the p->a[] array. Otherwise, the samples would ** be out of order. */ assert( p->nSample==0 || pNew->anLt[p->nCol-1] > p->a[p->nSample-1].anLt[p->nCol-1] ); /* Insert the new sample */ pSample = &p->a[p->nSample]; sampleCopy(p, pSample, pNew); p->nSample++; /* Zero the first nEqZero entries in the anEq[] array. */ memset(pSample->anEq, 0, sizeof(tRowcnt)*nEqZero); find_new_min: if( p->nSample>=p->mxSample ){ int iMin = -1; for(i=0; imxSample; i++){ if( p->a[i].isPSample ) continue; if( iMin<0 || sampleIsBetter(p, &p->a[iMin], &p->a[i]) ){ iMin = i; } } assert( iMin>=0 ); p->iMin = iMin; } } #endif /* SQLITE_ENABLE_STAT4 */ #ifdef SQLITE_ENABLE_STAT4 /* ** Field iChng of the index being scanned has changed. So at this point ** p->current contains a sample that reflects the previous row of the ** index. The value of anEq[iChng] and subsequent anEq[] elements are ** correct at this point. */ static void samplePushPrevious(StatAccum *p, int iChng){ int i; /* Check if any samples from the aBest[] array should be pushed ** into IndexSample.a[] at this point. */ for(i=(p->nCol-2); i>=iChng; i--){ StatSample *pBest = &p->aBest[i]; pBest->anEq[i] = p->current.anEq[i]; if( p->nSamplemxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){ sampleInsert(p, pBest, i); } } /* Check that no sample contains an anEq[] entry with an index of ** p->nMaxEqZero or greater set to zero. */ for(i=p->nSample-1; i>=0; i--){ int j; for(j=p->nMaxEqZero; jnCol; j++) assert( p->a[i].anEq[j]>0 ); } /* Update the anEq[] fields of any samples already collected. */ if( iChngnMaxEqZero ){ for(i=p->nSample-1; i>=0; i--){ int j; for(j=iChng; jnCol; j++){ if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j]; } } p->nMaxEqZero = iChng; } } #endif /* SQLITE_ENABLE_STAT4 */ /* ** Implementation of the stat_push SQL function: stat_push(P,C,R) ** Arguments: ** ** P Pointer to the StatAccum object created by stat_init() ** C Index of left-most column to differ from previous row ** R Rowid for the current row. Might be a key record for ** WITHOUT ROWID tables. ** ** The purpose of this routine is to collect statistical data and/or ** samples from the index being analyzed into the StatAccum object. ** The stat_get() SQL function will be used afterwards to ** retrieve the information gathered. ** ** This SQL function usually returns NULL, but might return an integer ** if it wants the byte-code to do special processing. ** ** The R parameter is only used for STAT4 */ static void statPush( sqlite3_context *context, int argc, sqlite3_value **argv ){ int i; /* The three function arguments */ StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]); int iChng = sqlite3_value_int(argv[1]); UNUSED_PARAMETER( argc ); UNUSED_PARAMETER( context ); assert( p->nCol>0 ); assert( iChngnCol ); if( p->nRow==0 ){ /* This is the first call to this function. Do initialization. */ #ifdef SQLITE_ENABLE_STAT4 for(i=0; inCol; i++) p->current.anEq[i] = 1; #endif }else{ /* Second and subsequent calls get processed here */ #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ) samplePushPrevious(p, iChng); #endif /* Update anDLt[], anLt[] and anEq[] to reflect the values that apply ** to the current row of the index. */ #ifdef SQLITE_ENABLE_STAT4 for(i=0; icurrent.anEq[i]++; } #endif for(i=iChng; inCol; i++){ p->current.anDLt[i]++; #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i]; p->current.anEq[i] = 1; #endif } } p->nRow++; #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ){ tRowcnt nLt; if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){ sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2])); }else{ sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]), sqlite3_value_blob(argv[2])); } p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345; nLt = p->current.anLt[p->nCol-1]; /* Check if this is to be a periodic sample. If so, add it. */ if( (nLt/p->nPSample)!=(nLt+1)/p->nPSample ){ p->current.isPSample = 1; p->current.iCol = 0; sampleInsert(p, &p->current, p->nCol-1); p->current.isPSample = 0; } /* Update the aBest[] array. */ for(i=0; i<(p->nCol-1); i++){ p->current.iCol = i; if( i>=iChng || sampleIsBetterPost(p, &p->current, &p->aBest[i]) ){ sampleCopy(p, &p->aBest[i], &p->current); } } }else #endif if( p->nLimit && p->nRow>(tRowcnt)p->nLimit*(p->nSkipAhead+1) ){ p->nSkipAhead++; sqlite3_result_int(context, p->current.anDLt[0]>0); } } static const FuncDef statPushFuncdef = { 2+IsStat4, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statPush, /* xSFunc */ 0, /* xFinalize */ 0, 0, /* xValue, xInverse */ "stat_push", /* zName */ {0} }; #define STAT_GET_STAT1 0 /* "stat" column of stat1 table */ #define STAT_GET_ROWID 1 /* "rowid" column of stat[34] entry */ #define STAT_GET_NEQ 2 /* "neq" column of stat[34] entry */ #define STAT_GET_NLT 3 /* "nlt" column of stat[34] entry */ #define STAT_GET_NDLT 4 /* "ndlt" column of stat[34] entry */ /* ** Implementation of the stat_get(P,J) SQL function. This routine is ** used to query statistical information that has been gathered into ** the StatAccum object by prior calls to stat_push(). The P parameter ** has type BLOB but it is really just a pointer to the StatAccum object. ** The content to returned is determined by the parameter J ** which is one of the STAT_GET_xxxx values defined above. ** ** The stat_get(P,J) function is not available to generic SQL. It is ** inserted as part of a manually constructed bytecode program. (See ** the callStatGet() routine below.) It is guaranteed that the P ** parameter will always be a pointer to a StatAccum object, never a ** NULL. ** ** If STAT4 is not enabled, then J is always ** STAT_GET_STAT1 and is hence omitted and this routine becomes ** a one-parameter function, stat_get(P), that always returns the ** stat1 table entry information. */ static void statGet( sqlite3_context *context, int argc, sqlite3_value **argv ){ StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]); #ifdef SQLITE_ENABLE_STAT4 /* STAT4 has a parameter on this routine. */ int eCall = sqlite3_value_int(argv[1]); assert( argc==2 ); assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ || eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT || eCall==STAT_GET_NDLT ); assert( eCall==STAT_GET_STAT1 || p->mxSample ); if( eCall==STAT_GET_STAT1 ) #else assert( argc==1 ); #endif { /* Return the value to store in the "stat" column of the sqlite_stat1 ** table for this index. ** ** The value is a string composed of a list of integers describing ** the index. The first integer in the list is the total number of ** entries in the index. There is one additional integer in the list ** for each indexed column. This additional integer is an estimate of ** the number of rows matched by a equality query on the index using ** a key with the corresponding number of fields. In other words, ** if the index is on columns (a,b) and the sqlite_stat1 value is ** "100 10 2", then SQLite estimates that: ** ** * the index contains 100 rows, ** * "WHERE a=?" matches 10 rows, and ** * "WHERE a=? AND b=?" matches 2 rows. ** ** If D is the count of distinct values and K is the total number of ** rows, then each estimate is usually computed as: ** ** I = (K+D-1)/D ** ** In other words, I is K/D rounded up to the next whole integer. ** However, if I is between 1.0 and 1.1 (in other words if I is ** close to 1.0 but just a little larger) then do not round up but ** instead keep the I value at 1.0. */ sqlite3_str sStat; /* Text of the constructed "stat" line */ int i; /* Loop counter */ sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100); sqlite3_str_appendf(&sStat, "%llu", p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow); for(i=0; inKeyCol; i++){ u64 nDistinct = p->current.anDLt[i] + 1; u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1; sqlite3_str_appendf(&sStat, " %llu", iVal); #ifdef SQLITE_ENABLE_STAT4 assert( p->current.anEq[i] ); #endif } sqlite3ResultStrAccum(context, &sStat); } #ifdef SQLITE_ENABLE_STAT4 else if( eCall==STAT_GET_ROWID ){ if( p->iGet<0 ){ samplePushPrevious(p, 0); p->iGet = 0; } if( p->iGetnSample ){ StatSample *pS = p->a + p->iGet; if( pS->nRowid==0 ){ sqlite3_result_int64(context, pS->u.iRowid); }else{ sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid, SQLITE_TRANSIENT); } } }else{ tRowcnt *aCnt = 0; sqlite3_str sStat; int i; assert( p->iGetnSample ); switch( eCall ){ case STAT_GET_NEQ: aCnt = p->a[p->iGet].anEq; break; case STAT_GET_NLT: aCnt = p->a[p->iGet].anLt; break; default: { aCnt = p->a[p->iGet].anDLt; p->iGet++; break; } } sqlite3StrAccumInit(&sStat, 0, 0, 0, p->nCol*100); for(i=0; inCol; i++){ sqlite3_str_appendf(&sStat, "%llu ", (u64)aCnt[i]); } if( sStat.nChar ) sStat.nChar--; sqlite3ResultStrAccum(context, &sStat); } #endif /* SQLITE_ENABLE_STAT4 */ #ifndef SQLITE_DEBUG UNUSED_PARAMETER( argc ); #endif } static const FuncDef statGetFuncdef = { 1+IsStat4, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statGet, /* xSFunc */ 0, /* xFinalize */ 0, 0, /* xValue, xInverse */ "stat_get", /* zName */ {0} }; static void callStatGet(Parse *pParse, int regStat, int iParam, int regOut){ #ifdef SQLITE_ENABLE_STAT4 sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat+1); #elif SQLITE_DEBUG assert( iParam==STAT_GET_STAT1 ); #else UNUSED_PARAMETER( iParam ); #endif assert( regOut!=regStat && regOut!=regStat+1 ); sqlite3VdbeAddFunctionCall(pParse, 0, regStat, regOut, 1+IsStat4, &statGetFuncdef, 0); } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS /* Add a comment to the most recent VDBE opcode that is the name ** of the k-th column of the pIdx index. */ static void analyzeVdbeCommentIndexWithColumnName( Vdbe *v, /* Prepared statement under construction */ Index *pIdx, /* Index whose column is being loaded */ int k /* Which column index */ ){ int i; /* Index of column in the table */ assert( k>=0 && knColumn ); i = pIdx->aiColumn[k]; if( NEVER(i==XN_ROWID) ){ VdbeComment((v,"%s.rowid",pIdx->zName)); }else if( i==XN_EXPR ){ assert( pIdx->bHasExpr ); VdbeComment((v,"%s.expr(%d)",pIdx->zName, k)); }else{ VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName)); } } #else # define analyzeVdbeCommentIndexWithColumnName(a,b,c) #endif /* SQLITE_DEBUG */ /* ** Generate code to do an analysis of all indices associated with ** a single table. */ static void analyzeOneTable( Parse *pParse, /* Parser context */ Table *pTab, /* Table whose indices are to be analyzed */ Index *pOnlyIdx, /* If not NULL, only analyze this one index */ int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */ int iMem, /* Available memory locations begin here */ int iTab /* Next available cursor */ ){ sqlite3 *db = pParse->db; /* Database handle */ Index *pIdx; /* An index to being analyzed */ int iIdxCur; /* Cursor open on index being analyzed */ int iTabCur; /* Table cursor */ Vdbe *v; /* The virtual machine being built up */ int i; /* Loop counter */ int jZeroRows = -1; /* Jump from here if number of rows is zero */ int iDb; /* Index of database containing pTab */ u8 needTableCnt = 1; /* True to count the table */ int regNewRowid = iMem++; /* Rowid for the inserted record */ int regStat = iMem++; /* Register to hold StatAccum object */ int regChng = iMem++; /* Index of changed index field */ int regRowid = iMem++; /* Rowid argument passed to stat_push() */ int regTemp = iMem++; /* Temporary use register */ int regTemp2 = iMem++; /* Second temporary use register */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */ int regPrev = iMem; /* MUST BE LAST (see below) */ #ifdef SQLITE_ENABLE_STAT4 int doOnce = 1; /* Flag for a one-time computation */ #endif #ifdef SQLITE_ENABLE_PREUPDATE_HOOK Table *pStat1 = 0; #endif sqlite3TouchRegister(pParse, iMem); assert( sqlite3NoTempsInRange(pParse, regNewRowid, iMem) ); v = sqlite3GetVdbe(pParse); if( v==0 || NEVER(pTab==0) ){ return; } if( !IsOrdinaryTable(pTab) ){ /* Do not gather statistics on views or virtual tables */ return; } if( sqlite3_strlike("sqlite\\_%", pTab->zName, '\\')==0 ){ /* Do not gather statistics on system tables */ return; } assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 ); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, db->aDb[iDb].zDbSName ) ){ return; } #endif #ifdef SQLITE_ENABLE_PREUPDATE_HOOK if( db->xPreUpdateCallback ){ pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13); if( pStat1==0 ) return; pStat1->zName = (char*)&pStat1[1]; memcpy(pStat1->zName, "sqlite_stat1", 13); pStat1->nCol = 3; pStat1->iPKey = -1; sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNAMIC); } #endif /* Establish a read-lock on the table at the shared-cache level. ** Open a read-only cursor on the table. Also allocate a cursor number ** to use for scanning indexes (iIdxCur). No index cursor is opened at ** this time though. */ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); iTabCur = iTab++; iIdxCur = iTab++; pParse->nTab = MAX(pParse->nTab, iTab); sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); sqlite3VdbeLoadString(v, regTabname, pTab->zName); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int nCol; /* Number of columns in pIdx. "N" */ int addrRewind; /* Address of "OP_Rewind iIdxCur" */ int addrNextRow; /* Address of "next_row:" */ const char *zIdxName; /* Name of the index */ int nColTest; /* Number of columns to test for changes */ if( pOnlyIdx && pOnlyIdx!=pIdx ) continue; if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0; if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIdx) ){ nCol = pIdx->nKeyCol; zIdxName = pTab->zName; nColTest = nCol - 1; }else{ nCol = pIdx->nColumn; zIdxName = pIdx->zName; nColTest = pIdx->uniqNotNull ? pIdx->nKeyCol-1 : nCol-1; } /* Populate the register containing the index name. */ sqlite3VdbeLoadString(v, regIdxname, zIdxName); VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName)); /* ** Pseudo-code for loop that calls stat_push(): ** ** Rewind csr ** if eof(csr) goto end_of_scan; ** regChng = 0 ** goto chng_addr_0; ** ** next_row: ** regChng = 0 ** if( idx(0) != regPrev(0) ) goto chng_addr_0 ** regChng = 1 ** if( idx(1) != regPrev(1) ) goto chng_addr_1 ** ... ** regChng = N ** goto chng_addr_N ** ** chng_addr_0: ** regPrev(0) = idx(0) ** chng_addr_1: ** regPrev(1) = idx(1) ** ... ** ** endDistinctTest: ** regRowid = idx(rowid) ** stat_push(P, regChng, regRowid) ** Next csr ** if !eof(csr) goto next_row; ** ** end_of_scan: */ /* Make sure there are enough memory cells allocated to accommodate ** the regPrev array and a trailing rowid (the rowid slot is required ** when building a record to insert into the sample column of ** the sqlite_stat4 table. */ sqlite3TouchRegister(pParse, regPrev+nColTest); /* Open a read-only cursor on the index being analyzed. */ assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) ); sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); /* Invoke the stat_init() function. The arguments are: ** ** (1) the number of columns in the index including the rowid ** (or for a WITHOUT ROWID table, the number of PK columns), ** (2) the number of columns in the key without the rowid/pk ** (3) estimated number of rows in the index, */ sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1); assert( regRowid==regStat+2 ); sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid); #ifdef SQLITE_ENABLE_STAT4 if( OptimizationEnabled(db, SQLITE_Stat4) ){ sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp); addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); VdbeCoverage(v); }else #endif { addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1); } assert( regTemp2==regStat+4 ); sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2); sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4, &statInitFuncdef, 0); /* Implementation of the following: ** ** Rewind csr ** if eof(csr) goto end_of_scan; ** regChng = 0 ** goto next_push_0; ** */ sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng); addrNextRow = sqlite3VdbeCurrentAddr(v); if( nColTest>0 ){ int endDistinctTest = sqlite3VdbeMakeLabel(pParse); int *aGotoChng; /* Array of jump instruction addresses */ aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest); if( aGotoChng==0 ) continue; /* ** next_row: ** regChng = 0 ** if( idx(0) != regPrev(0) ) goto chng_addr_0 ** regChng = 1 ** if( idx(1) != regPrev(1) ) goto chng_addr_1 ** ... ** regChng = N ** goto endDistinctTest */ sqlite3VdbeAddOp0(v, OP_Goto); addrNextRow = sqlite3VdbeCurrentAddr(v); if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){ /* For a single-column UNIQUE index, once we have found a non-NULL ** row, we know that all the rest will be distinct, so skip ** subsequent distinctness tests. */ sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest); VdbeCoverage(v); } for(i=0; iazColl[i]); sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp); analyzeVdbeCommentIndexWithColumnName(v,pIdx,i); aGotoChng[i] = sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); VdbeCoverage(v); } sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng); sqlite3VdbeGoto(v, endDistinctTest); /* ** chng_addr_0: ** regPrev(0) = idx(0) ** chng_addr_1: ** regPrev(1) = idx(1) ** ... */ sqlite3VdbeJumpHere(v, addrNextRow-1); for(i=0; ipTable); int j, k, regKey; regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; jnKeyCol; j++){ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]); assert( k>=0 && knColumn ); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); analyzeVdbeCommentIndexWithColumnName(v,pIdx,k); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid); sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol); } } #endif assert( regChng==(regStat+1) ); { sqlite3VdbeAddFunctionCall(pParse, 1, regStat, regTemp, 2+IsStat4, &statPushFuncdef, 0); if( db->nAnalysisLimit ){ int j1, j2, j3; j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regTemp); VdbeCoverage(v); j2 = sqlite3VdbeAddOp1(v, OP_If, regTemp); VdbeCoverage(v); j3 = sqlite3VdbeAddOp4Int(v, OP_SeekGT, iIdxCur, 0, regPrev, 1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, j1); sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); sqlite3VdbeJumpHere(v, j2); sqlite3VdbeJumpHere(v, j3); }else{ sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); } } /* Add the entry to the stat1 table. */ callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1); assert( "BBB"[0]==SQLITE_AFF_TEXT ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE); #endif sqlite3VdbeChangeP5(v, OPFLAG_APPEND); /* Add the entries to the stat4 table. */ #ifdef SQLITE_ENABLE_STAT4 if( OptimizationEnabled(db, SQLITE_Stat4) && db->nAnalysisLimit==0 ){ int regEq = regStat1; int regLt = regStat1+1; int regDLt = regStat1+2; int regSample = regStat1+3; int regCol = regStat1+4; int regSampleRowid = regCol + nCol; int addrNext; int addrIsNull; u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound; if( doOnce ){ int mxCol = nCol; Index *pX; /* Compute the maximum number of columns in any index */ for(pX=pTab->pIndex; pX; pX=pX->pNext){ int nColX; /* Number of columns in pX */ if( !HasRowid(pTab) && IsPrimaryKeyIndex(pX) ){ nColX = pX->nKeyCol; }else{ nColX = pX->nColumn; } if( nColX>mxCol ) mxCol = nColX; } /* Allocate space to compute results for the largest index */ sqlite3TouchRegister(pParse, regCol+mxCol); doOnce = 0; #ifdef SQLITE_DEBUG /* Verify that the call to sqlite3ClearTempRegCache() below ** really is needed. ** https://sqlite.org/forum/forumpost/83cb4a95a0 (2023-03-25) */ testcase( !sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) ); #endif sqlite3ClearTempRegCache(pParse); /* tag-20230325-1 */ assert( sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) ); } assert( sqlite3NoTempsInRange(pParse, regEq, regCol+nCol) ); addrNext = sqlite3VdbeCurrentAddr(v); callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid); addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid); VdbeCoverage(v); callStatGet(pParse, regStat, STAT_GET_NEQ, regEq); callStatGet(pParse, regStat, STAT_GET_NLT, regLt); callStatGet(pParse, regStat, STAT_GET_NDLT, regDLt); sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0); VdbeCoverage(v); for(i=0; izName)); sqlite3VdbeAddOp2(v, OP_Count, iTabCur, regStat1); jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); assert( "BBB"[0]==SQLITE_AFF_TEXT ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE); #endif sqlite3VdbeJumpHere(v, jZeroRows); } } /* ** Generate code that will cause the most recent index analysis to ** be loaded into internal hash tables where is can be used. */ static void loadAnalysis(Parse *pParse, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb); } } /* ** Generate code that will do an analysis of an entire database */ static void analyzeDatabase(Parse *pParse, int iDb){ sqlite3 *db = pParse->db; Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ HashElem *k; int iStatCur; int iMem; int iTab; sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; pParse->nTab += 3; openStatTable(pParse, iDb, iStatCur, 0, 0); iMem = pParse->nMem+1; iTab = pParse->nTab; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ Table *pTab = (Table*)sqliteHashData(k); analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab); #ifdef SQLITE_ENABLE_STAT4 iMem = sqlite3FirstAvailableRegister(pParse, iMem); #else assert( iMem==sqlite3FirstAvailableRegister(pParse,iMem) ); #endif } loadAnalysis(pParse, iDb); } /* ** Generate code that will do an analysis of a single table in ** a database. If pOnlyIdx is not NULL then it is a single index ** in pTab that should be analyzed. */ static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){ int iDb; int iStatCur; assert( pTab!=0 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; pParse->nTab += 3; if( pOnlyIdx ){ openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx"); }else{ openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl"); } analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur,pParse->nMem+1,pParse->nTab); loadAnalysis(pParse, iDb); } /* ** Generate code for the ANALYZE command. The parser calls this routine ** when it recognizes an ANALYZE command. ** ** ANALYZE -- 1 ** ANALYZE -- 2 ** ANALYZE ?.? -- 3 ** ** Form 1 causes all indices in all attached databases to be analyzed. ** Form 2 analyzes all indices the single database named. ** Form 3 analyzes all indices associated with the named table. */ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ sqlite3 *db = pParse->db; int iDb; int i; char *z, *zDb; Table *pTab; Index *pIdx; Token *pTableName; Vdbe *v; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return; } assert( pName2!=0 || pName1==0 ); if( pName1==0 ){ /* Form 1: Analyze everything */ for(i=0; inDb; i++){ if( i==1 ) continue; /* Do not analyze the TEMP database */ analyzeDatabase(pParse, i); } }else if( pName2->n==0 && (iDb = sqlite3FindDb(db, pName1))>=0 ){ /* Analyze the schema named as the argument */ analyzeDatabase(pParse, iDb); }else{ /* Form 3: Analyze the table or index named as an argument */ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); if( iDb>=0 ){ zDb = pName2->n ? db->aDb[iDb].zDbSName : 0; z = sqlite3NameFromToken(db, pTableName); if( z ){ if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){ analyzeTable(pParse, pIdx->pTable, pIdx); }else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){ analyzeTable(pParse, pTab, 0); } sqlite3DbFree(db, z); } } } if( db->nSqlExec==0 && (v = sqlite3GetVdbe(pParse))!=0 ){ sqlite3VdbeAddOp0(v, OP_Expire); } } /* ** Used to pass information from the analyzer reader through to the ** callback routine. */ typedef struct analysisInfo analysisInfo; struct analysisInfo { sqlite3 *db; const char *zDatabase; }; /* ** The first argument points to a nul-terminated string containing a ** list of space separated integers. Read the first nOut of these into ** the array aOut[]. */ static void decodeIntArray( char *zIntArray, /* String containing int array to decode */ int nOut, /* Number of slots in aOut[] */ tRowcnt *aOut, /* Store integers here */ LogEst *aLog, /* Or, if aOut==0, here */ Index *pIndex /* Handle extra flags for this index, if not NULL */ ){ char *z = zIntArray; int c; int i; tRowcnt v; #ifdef SQLITE_ENABLE_STAT4 if( z==0 ) z = ""; #else assert( z!=0 ); #endif for(i=0; *z && i='0' && c<='9' ){ v = v*10 + c - '0'; z++; } #ifdef SQLITE_ENABLE_STAT4 if( aOut ) aOut[i] = v; if( aLog ) aLog[i] = sqlite3LogEst(v); #else assert( aOut==0 ); UNUSED_PARAMETER(aOut); assert( aLog!=0 ); aLog[i] = sqlite3LogEst(v); #endif if( *z==' ' ) z++; } #ifndef SQLITE_ENABLE_STAT4 assert( pIndex!=0 ); { #else if( pIndex ){ #endif pIndex->bUnordered = 0; pIndex->noSkipScan = 0; while( z[0] ){ if( sqlite3_strglob("unordered*", z)==0 ){ pIndex->bUnordered = 1; }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){ int sz = sqlite3Atoi(z+3); if( sz<2 ) sz = 2; pIndex->szIdxRow = sqlite3LogEst(sz); }else if( sqlite3_strglob("noskipscan*", z)==0 ){ pIndex->noSkipScan = 1; } #ifdef SQLITE_ENABLE_COSTMULT else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){ pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9)); } #endif while( z[0]!=0 && z[0]!=' ' ) z++; while( z[0]==' ' ) z++; } /* Set the bLowQual flag if the peak number of rows obtained ** from a full equality match is so large that a full table scan ** seems likely to be faster than using the index. */ if( aLog[0] > 66 /* Index has more than 100 rows */ && aLog[0] <= aLog[nOut-1] /* And only a single value seen */ ){ pIndex->bLowQual = 1; } } } /* ** This callback is invoked once for each index when reading the ** sqlite_stat1 table. ** ** argv[0] = name of the table ** argv[1] = name of the index (might be NULL) ** argv[2] = results of analysis - on integer for each column ** ** Entries for which argv[1]==NULL simply record the number of rows in ** the table. */ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ analysisInfo *pInfo = (analysisInfo*)pData; Index *pIndex; Table *pTable; const char *z; assert( argc==3 ); UNUSED_PARAMETER2(NotUsed, argc); if( argv==0 || argv[0]==0 || argv[2]==0 ){ return 0; } pTable = sqlite3FindTable(pInfo->db, argv[0], pInfo->zDatabase); if( pTable==0 ){ return 0; } if( argv[1]==0 ){ pIndex = 0; }else if( sqlite3_stricmp(argv[0],argv[1])==0 ){ pIndex = sqlite3PrimaryKeyIndex(pTable); }else{ pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); } z = argv[2]; if( pIndex ){ tRowcnt *aiRowEst = 0; int nCol = pIndex->nKeyCol+1; #ifdef SQLITE_ENABLE_STAT4 /* Index.aiRowEst may already be set here if there are duplicate ** sqlite_stat1 entries for this index. In that case just clobber ** the old data with the new instead of allocating a new array. */ if( pIndex->aiRowEst==0 ){ pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol); if( pIndex->aiRowEst==0 ) sqlite3OomFault(pInfo->db); } aiRowEst = pIndex->aiRowEst; #endif pIndex->bUnordered = 0; decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex); pIndex->hasStat1 = 1; if( pIndex->pPartIdxWhere==0 ){ pTable->nRowLogEst = pIndex->aiRowLogEst[0]; pTable->tabFlags |= TF_HasStat1; } }else{ Index fakeIdx; fakeIdx.szIdxRow = pTable->szTabRow; #ifdef SQLITE_ENABLE_COSTMULT fakeIdx.pTable = pTable; #endif decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx); pTable->szTabRow = fakeIdx.szIdxRow; pTable->tabFlags |= TF_HasStat1; } return 0; } /* ** If the Index.aSample variable is not NULL, delete the aSample[] array ** and its contents. */ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ assert( db!=0 ); assert( pIdx!=0 ); #ifdef SQLITE_ENABLE_STAT4 if( pIdx->aSample ){ int j; for(j=0; jnSample; j++){ IndexSample *p = &pIdx->aSample[j]; sqlite3DbFree(db, p->p); } sqlite3DbFree(db, pIdx->aSample); } if( db->pnBytesFreed==0 ){ pIdx->nSample = 0; pIdx->aSample = 0; } #else UNUSED_PARAMETER(db); UNUSED_PARAMETER(pIdx); #endif /* SQLITE_ENABLE_STAT4 */ } #ifdef SQLITE_ENABLE_STAT4 /* ** Populate the pIdx->aAvgEq[] array based on the samples currently ** stored in pIdx->aSample[]. */ static void initAvgEq(Index *pIdx){ if( pIdx ){ IndexSample *aSample = pIdx->aSample; IndexSample *pFinal = &aSample[pIdx->nSample-1]; int iCol; int nCol = 1; if( pIdx->nSampleCol>1 ){ /* If this is stat4 data, then calculate aAvgEq[] values for all ** sample columns except the last. The last is always set to 1, as ** once the trailing PK fields are considered all index keys are ** unique. */ nCol = pIdx->nSampleCol-1; pIdx->aAvgEq[nCol] = 1; } for(iCol=0; iColnSample; int i; /* Used to iterate through samples */ tRowcnt sumEq = 0; /* Sum of the nEq values */ tRowcnt avgEq = 0; tRowcnt nRow; /* Number of rows in index */ i64 nSum100 = 0; /* Number of terms contributing to sumEq */ i64 nDist100; /* Number of distinct values in index */ if( !pIdx->aiRowEst || iCol>=pIdx->nKeyCol || pIdx->aiRowEst[iCol+1]==0 ){ nRow = pFinal->anLt[iCol]; nDist100 = (i64)100 * pFinal->anDLt[iCol]; nSample--; }else{ nRow = pIdx->aiRowEst[0]; nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1]; } pIdx->nRowEst0 = nRow; /* Set nSum to the number of distinct (iCol+1) field prefixes that ** occur in the stat4 table for this index. Set sumEq to the sum of ** the nEq values for column iCol for the same set (adding the value ** only once where there exist duplicate prefixes). */ for(i=0; inSample-1) || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){ sumEq += aSample[i].anEq[iCol]; nSum100 += 100; } } if( nDist100>nSum100 && sumEqaAvgEq[iCol] = avgEq; } } } /* ** Look up an index by name. Or, if the name of a WITHOUT ROWID table ** is supplied instead, find the PRIMARY KEY index for that table. */ static Index *findIndexOrPrimaryKey( sqlite3 *db, const char *zName, const char *zDb ){ Index *pIdx = sqlite3FindIndex(db, zName, zDb); if( pIdx==0 ){ Table *pTab = sqlite3FindTable(db, zName, zDb); if( pTab && !HasRowid(pTab) ) pIdx = sqlite3PrimaryKeyIndex(pTab); } return pIdx; } /* ** Load the content from either the sqlite_stat4 ** into the relevant Index.aSample[] arrays. ** ** Arguments zSql1 and zSql2 must point to SQL statements that return ** data equivalent to the following: ** ** zSql1: SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx ** zSql2: SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4 ** ** where %Q is replaced with the database name before the SQL is executed. */ static int loadStatTbl( sqlite3 *db, /* Database handle */ const char *zSql1, /* SQL statement 1 (see above) */ const char *zSql2, /* SQL statement 2 (see above) */ const char *zDb /* Database name (e.g. "main") */ ){ int rc; /* Result codes from subroutines */ sqlite3_stmt *pStmt = 0; /* An SQL statement being run */ char *zSql; /* Text of the SQL statement */ Index *pPrevIdx = 0; /* Previous index in the loop */ IndexSample *pSample; /* A slot in pIdx->aSample[] */ assert( db->lookaside.bDisable ); zSql = sqlite3MPrintf(db, zSql1, zDb); if( !zSql ){ return SQLITE_NOMEM_BKPT; } rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); sqlite3DbFree(db, zSql); if( rc ) return rc; while( sqlite3_step(pStmt)==SQLITE_ROW ){ int nIdxCol = 1; /* Number of columns in stat4 records */ char *zIndex; /* Index name */ Index *pIdx; /* Pointer to the index object */ int nSample; /* Number of samples */ int nByte; /* Bytes of space required */ int i; /* Bytes of space required */ tRowcnt *pSpace; zIndex = (char *)sqlite3_column_text(pStmt, 0); if( zIndex==0 ) continue; nSample = sqlite3_column_int(pStmt, 1); pIdx = findIndexOrPrimaryKey(db, zIndex, zDb); assert( pIdx==0 || pIdx->nSample==0 ); if( pIdx==0 ) continue; if( pIdx->aSample!=0 ){ /* The same index appears in sqlite_stat4 under multiple names */ continue; } assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 ); if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){ nIdxCol = pIdx->nKeyCol; }else{ nIdxCol = pIdx->nColumn; } pIdx->nSampleCol = nIdxCol; pIdx->mxSample = nSample; nByte = sizeof(IndexSample) * nSample; nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample; nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ pIdx->aSample = sqlite3DbMallocZero(db, nByte); if( pIdx->aSample==0 ){ sqlite3_finalize(pStmt); return SQLITE_NOMEM_BKPT; } pSpace = (tRowcnt*)&pIdx->aSample[nSample]; pIdx->aAvgEq = pSpace; pSpace += nIdxCol; pIdx->pTable->tabFlags |= TF_HasStat4; for(i=0; iaSample[i].anEq = pSpace; pSpace += nIdxCol; pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol; pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol; } assert( ((u8*)pSpace)-nByte==(u8*)(pIdx->aSample) ); } rc = sqlite3_finalize(pStmt); if( rc ) return rc; zSql = sqlite3MPrintf(db, zSql2, zDb); if( !zSql ){ return SQLITE_NOMEM_BKPT; } rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); sqlite3DbFree(db, zSql); if( rc ) return rc; while( sqlite3_step(pStmt)==SQLITE_ROW ){ char *zIndex; /* Index name */ Index *pIdx; /* Pointer to the index object */ int nCol = 1; /* Number of columns in index */ zIndex = (char *)sqlite3_column_text(pStmt, 0); if( zIndex==0 ) continue; pIdx = findIndexOrPrimaryKey(db, zIndex, zDb); if( pIdx==0 ) continue; if( pIdx->nSample>=pIdx->mxSample ){ /* Too many slots used because the same index appears in ** sqlite_stat4 using multiple names */ continue; } /* This next condition is true if data has already been loaded from ** the sqlite_stat4 table. */ nCol = pIdx->nSampleCol; if( pIdx!=pPrevIdx ){ initAvgEq(pPrevIdx); pPrevIdx = pIdx; } pSample = &pIdx->aSample[pIdx->nSample]; decodeIntArray((char*)sqlite3_column_text(pStmt,1),nCol,pSample->anEq,0,0); decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0); decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0); /* Take a copy of the sample. Add 8 extra 0x00 bytes the end of the buffer. ** This is in case the sample record is corrupted. In that case, the ** sqlite3VdbeRecordCompare() may read up to two varints past the ** end of the allocated buffer before it realizes it is dealing with ** a corrupt record. Or it might try to read a large integer from the ** buffer. In any case, eight 0x00 bytes prevents this from causing ** a buffer overread. */ pSample->n = sqlite3_column_bytes(pStmt, 4); pSample->p = sqlite3DbMallocZero(db, pSample->n + 8); if( pSample->p==0 ){ sqlite3_finalize(pStmt); return SQLITE_NOMEM_BKPT; } if( pSample->n ){ memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n); } pIdx->nSample++; } rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) initAvgEq(pPrevIdx); return rc; } /* ** Load content from the sqlite_stat4 table into ** the Index.aSample[] arrays of all indices. */ static int loadStat4(sqlite3 *db, const char *zDb){ int rc = SQLITE_OK; /* Result codes from subroutines */ const Table *pStat4; assert( db->lookaside.bDisable ); if( OptimizationEnabled(db, SQLITE_Stat4) && (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0 && IsOrdinaryTable(pStat4) ){ rc = loadStatTbl(db, "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx COLLATE nocase", "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4", zDb ); } return rc; } #endif /* SQLITE_ENABLE_STAT4 */ /* ** Load the content of the sqlite_stat1 and sqlite_stat4 tables. The ** contents of sqlite_stat1 are used to populate the Index.aiRowEst[] ** arrays. The contents of sqlite_stat4 are used to populate the ** Index.aSample[] arrays. ** ** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR ** is returned. In this case, even if SQLITE_ENABLE_STAT4 was defined ** during compilation and the sqlite_stat4 table is present, no data is ** read from it. ** ** If SQLITE_ENABLE_STAT4 was defined during compilation and the ** sqlite_stat4 table is not present in the database, SQLITE_ERROR is ** returned. However, in this case, data is read from the sqlite_stat1 ** table (if it is present) before returning. ** ** If an OOM error occurs, this function always sets db->mallocFailed. ** This means if the caller does not care about other errors, the return ** code may be ignored. */ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ analysisInfo sInfo; HashElem *i; char *zSql; int rc = SQLITE_OK; Schema *pSchema = db->aDb[iDb].pSchema; const Table *pStat1; assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pBt!=0 ); /* Clear any prior statistics */ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); pTab->tabFlags &= ~TF_HasStat1; } for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); pIdx->hasStat1 = 0; #ifdef SQLITE_ENABLE_STAT4 sqlite3DeleteIndexSamples(db, pIdx); pIdx->aSample = 0; #endif } /* Load new statistics out of the sqlite_stat1 table */ sInfo.db = db; sInfo.zDatabase = db->aDb[iDb].zDbSName; if( (pStat1 = sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)) && IsOrdinaryTable(pStat1) ){ zSql = sqlite3MPrintf(db, "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); sqlite3DbFree(db, zSql); } } /* Set appropriate defaults on all indexes not in the sqlite_stat1 table */ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx); } /* Load the statistics from the sqlite_stat4 table. */ #ifdef SQLITE_ENABLE_STAT4 if( rc==SQLITE_OK ){ DisableLookaside; rc = loadStat4(db, sInfo.zDatabase); EnableLookaside; } for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3_free(pIdx->aiRowEst); pIdx->aiRowEst = 0; } #endif if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); } return rc; } #endif /* SQLITE_OMIT_ANALYZE */ /************** End of analyze.c *********************************************/ /************** Begin file attach.c ******************************************/ /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. */ /* #include "sqliteInt.h" */ #ifndef SQLITE_OMIT_ATTACH /* ** Resolve an expression that was part of an ATTACH or DETACH statement. This ** is slightly different from resolving a normal SQL expression, because simple ** identifiers are treated as strings, not possible column names or aliases. ** ** i.e. if the parser sees: ** ** ATTACH DATABASE abc AS def ** ** it treats the two expressions as literal strings 'abc' and 'def' instead of ** looking for columns of the same name. ** ** This only applies to the root node of pExpr, so the statement: ** ** ATTACH DATABASE abc||def AS 'db2' ** ** will fail because neither abc or def can be resolved. */ static int resolveAttachExpr(NameContext *pName, Expr *pExpr) { int rc = SQLITE_OK; if( pExpr ){ if( pExpr->op!=TK_ID ){ rc = sqlite3ResolveExprNames(pName, pExpr); }else{ pExpr->op = TK_STRING; } } return rc; } /* ** Return true if zName points to a name that may be used to refer to ** database iDb attached to handle db. */ SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){ return ( sqlite3StrICmp(db->aDb[iDb].zDbSName, zName)==0 || (iDb==0 && sqlite3StrICmp("main", zName)==0) ); } /* ** An SQL user-function registered to do the work of an ATTACH statement. The ** three arguments to the function come directly from an attach statement: ** ** ATTACH DATABASE x AS y KEY z ** ** SELECT sqlite_attach(x, y, z) ** ** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the ** third argument. ** ** If the db->init.reopenMemdb flags is set, then instead of attaching a ** new database, close the database on db->init.iDb and reopen it as an ** empty MemDB. */ static void attachFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ int i; int rc = 0; sqlite3 *db = sqlite3_context_db_handle(context); const char *zName; const char *zFile; char *zPath = 0; char *zErr = 0; unsigned int flags; Db *aNew; /* New array of Db pointers */ Db *pNew = 0; /* Db object for the newly attached database */ char *zErrDyn = 0; sqlite3_vfs *pVfs; UNUSED_PARAMETER(NotUsed); zFile = (const char *)sqlite3_value_text(argv[0]); zName = (const char *)sqlite3_value_text(argv[1]); if( zFile==0 ) zFile = ""; if( zName==0 ) zName = ""; #ifndef SQLITE_OMIT_DESERIALIZE # define REOPEN_AS_MEMDB(db) (db->init.reopenMemdb) #else # define REOPEN_AS_MEMDB(db) (0) #endif if( REOPEN_AS_MEMDB(db) ){ /* This is not a real ATTACH. Instead, this routine is being called ** from sqlite3_deserialize() to close database db->init.iDb and ** reopen it as a MemDB */ Btree *pNewBt = 0; pVfs = sqlite3_vfs_find("memdb"); if( pVfs==0 ) return; rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNewBt, 0, SQLITE_OPEN_MAIN_DB); if( rc==SQLITE_OK ){ Schema *pNewSchema = sqlite3SchemaGet(db, pNewBt); if( pNewSchema ){ /* Both the Btree and the new Schema were allocated successfully. ** Close the old db and update the aDb[] slot with the new memdb ** values. */ pNew = &db->aDb[db->init.iDb]; if( ALWAYS(pNew->pBt) ) sqlite3BtreeClose(pNew->pBt); pNew->pBt = pNewBt; pNew->pSchema = pNewSchema; }else{ sqlite3BtreeClose(pNewBt); rc = SQLITE_NOMEM; } } if( rc ) goto attach_error; }else{ /* This is a real ATTACH ** ** Check for the following errors: ** ** * Too many attached databases, ** * Transaction currently open ** * Specified database name already being used. */ if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", db->aLimit[SQLITE_LIMIT_ATTACHED] ); goto attach_error; } for(i=0; inDb; i++){ assert( zName ); if( sqlite3DbIsNamed(db, i, zName) ){ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); goto attach_error; } } /* Allocate the new entry in the db->aDb[] array and initialize the schema ** hash tables. */ if( db->aDb==db->aDbStatic ){ aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); if( aNew==0 ) return; } db->aDb = aNew; pNew = &db->aDb[db->nDb]; memset(pNew, 0, sizeof(*pNew)); /* Open the database file. If the btree is successfully opened, use ** it to obtain the database schema. At this point the schema may ** or may not be initialized. */ flags = db->openFlags; rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); return; } assert( pVfs ); flags |= SQLITE_OPEN_MAIN_DB; rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags); db->nDb++; pNew->zDbSName = sqlite3DbStrDup(db, zName); } db->noSharedCache = 0; if( rc==SQLITE_CONSTRAINT ){ rc = SQLITE_ERROR; zErrDyn = sqlite3MPrintf(db, "database is already attached"); }else if( rc==SQLITE_OK ){ Pager *pPager; pNew->pSchema = sqlite3SchemaGet(db, pNew->pBt); if( !pNew->pSchema ){ rc = SQLITE_NOMEM_BKPT; }else if( pNew->pSchema->file_format && pNew->pSchema->enc!=ENC(db) ){ zErrDyn = sqlite3MPrintf(db, "attached databases must use the same text encoding as main database"); rc = SQLITE_ERROR; } sqlite3BtreeEnter(pNew->pBt); pPager = sqlite3BtreePager(pNew->pBt); sqlite3PagerLockingMode(pPager, db->dfltLockMode); sqlite3BtreeSecureDelete(pNew->pBt, sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) ); #ifndef SQLITE_OMIT_PAGER_PRAGMAS sqlite3BtreeSetPagerFlags(pNew->pBt, PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); #endif sqlite3BtreeLeave(pNew->pBt); } pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; if( rc==SQLITE_OK && pNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } sqlite3_free_filename( zPath ); /* If the file was opened successfully, read the schema for the new database. ** If this fails, or if opening the file failed, then close the file and ** remove the entry from the db->aDb[] array. i.e. put everything back the ** way we found it. */ if( rc==SQLITE_OK ){ sqlite3BtreeEnterAll(db); db->init.iDb = 0; db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); if( !REOPEN_AS_MEMDB(db) ){ rc = sqlite3Init(db, &zErrDyn); } sqlite3BtreeLeaveAll(db); assert( zErrDyn==0 || rc!=SQLITE_OK ); } #ifdef SQLITE_USER_AUTHENTICATION if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){ u8 newAuth = 0; rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); if( newAuthauth.authLevel ){ rc = SQLITE_AUTH_USER; } } #endif if( rc ){ if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){ int iDb = db->nDb - 1; assert( iDb>=2 ); if( db->aDb[iDb].pBt ){ sqlite3BtreeClose(db->aDb[iDb].pBt); db->aDb[iDb].pBt = 0; db->aDb[iDb].pSchema = 0; } sqlite3ResetAllSchemasOfConnection(db); db->nDb = iDb; if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); sqlite3DbFree(db, zErrDyn); zErrDyn = sqlite3MPrintf(db, "out of memory"); }else if( zErrDyn==0 ){ zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile); } } goto attach_error; } return; attach_error: /* Return an error if we get here */ if( zErrDyn ){ sqlite3_result_error(context, zErrDyn, -1); sqlite3DbFree(db, zErrDyn); } if( rc ) sqlite3_result_error_code(context, rc); } /* ** An SQL user-function registered to do the work of an DETACH statement. The ** three arguments to the function come directly from a detach statement: ** ** DETACH DATABASE x ** ** SELECT sqlite_detach(x) */ static void detachFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ const char *zName = (const char *)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); int i; Db *pDb = 0; HashElem *pEntry; char zErr[128]; UNUSED_PARAMETER(NotUsed); if( zName==0 ) zName = ""; for(i=0; inDb; i++){ pDb = &db->aDb[i]; if( pDb->pBt==0 ) continue; if( sqlite3DbIsNamed(db, i, zName) ) break; } if( i>=db->nDb ){ sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName); goto detach_error; } if( i<2 ){ sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); goto detach_error; } if( sqlite3BtreeTxnState(pDb->pBt)!=SQLITE_TXN_NONE || sqlite3BtreeIsInBackup(pDb->pBt) ){ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); goto detach_error; } /* If any TEMP triggers reference the schema being detached, move those ** triggers to reference the TEMP schema itself. */ assert( db->aDb[1].pSchema ); pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash); while( pEntry ){ Trigger *pTrig = (Trigger*)sqliteHashData(pEntry); if( pTrig->pTabSchema==pDb->pSchema ){ pTrig->pTabSchema = pTrig->pSchema; } pEntry = sqliteHashNext(pEntry); } sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; sqlite3CollapseDatabaseArray(db); return; detach_error: sqlite3_result_error(context, zErr, -1); } /* ** This procedure generates VDBE code for a single invocation of either the ** sqlite_detach() or sqlite_attach() SQL user functions. */ static void codeAttach( Parse *pParse, /* The parser context */ int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */ FuncDef const *pFunc,/* FuncDef wrapper for detachFunc() or attachFunc() */ Expr *pAuthArg, /* Expression to pass to authorization callback */ Expr *pFilename, /* Name of database file */ Expr *pDbname, /* Name of the database to use internally */ Expr *pKey /* Database key for encryption extension */ ){ int rc; NameContext sName; Vdbe *v; sqlite3* db = pParse->db; int regArgs; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto attach_end; if( pParse->nErr ) goto attach_end; memset(&sName, 0, sizeof(NameContext)); sName.pParse = pParse; if( SQLITE_OK!=resolveAttachExpr(&sName, pFilename) || SQLITE_OK!=resolveAttachExpr(&sName, pDbname) || SQLITE_OK!=resolveAttachExpr(&sName, pKey) ){ goto attach_end; } #ifndef SQLITE_OMIT_AUTHORIZATION if( ALWAYS(pAuthArg) ){ char *zAuthArg; if( pAuthArg->op==TK_STRING ){ assert( !ExprHasProperty(pAuthArg, EP_IntValue) ); zAuthArg = pAuthArg->u.zToken; }else{ zAuthArg = 0; } rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); if(rc!=SQLITE_OK ){ goto attach_end; } } #endif /* SQLITE_OMIT_AUTHORIZATION */ v = sqlite3GetVdbe(pParse); regArgs = sqlite3GetTempRange(pParse, 4); sqlite3ExprCode(pParse, pFilename, regArgs); sqlite3ExprCode(pParse, pDbname, regArgs+1); sqlite3ExprCode(pParse, pKey, regArgs+2); assert( v || db->mallocFailed ); if( v ){ sqlite3VdbeAddFunctionCall(pParse, 0, regArgs+3-pFunc->nArg, regArgs+3, pFunc->nArg, pFunc, 0); /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this ** statement only). For DETACH, set it to false (expire all existing ** statements). */ sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH)); } attach_end: sqlite3ExprDelete(db, pFilename); sqlite3ExprDelete(db, pDbname); sqlite3ExprDelete(db, pKey); } /* ** Called by the parser to compile a DETACH statement. ** ** DETACH pDbname */ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){ static const FuncDef detach_func = { 1, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ detachFunc, /* xSFunc */ 0, /* xFinalize */ 0, 0, /* xValue, xInverse */ "sqlite_detach", /* zName */ {0} }; codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname); } /* ** Called by the parser to compile an ATTACH statement. ** ** ATTACH p AS pDbname KEY pKey */ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){ static const FuncDef attach_func = { 3, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ attachFunc, /* xSFunc */ 0, /* xFinalize */ 0, 0, /* xValue, xInverse */ "sqlite_attach", /* zName */ {0} }; codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey); } #endif /* SQLITE_OMIT_ATTACH */ /* ** Expression callback used by sqlite3FixAAAA() routines. */ static int fixExprCb(Walker *p, Expr *pExpr){ DbFixer *pFix = p->u.pFix; if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL); if( pExpr->op==TK_VARIABLE ){ if( pFix->pParse->db->init.busy ){ pExpr->op = TK_NULL; }else{ sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType); return WRC_Abort; } } return WRC_Continue; } /* ** Select callback used by sqlite3FixAAAA() routines. */ static int fixSelectCb(Walker *p, Select *pSelect){ DbFixer *pFix = p->u.pFix; int i; SrcItem *pItem; sqlite3 *db = pFix->pParse->db; int iDb = sqlite3FindDbName(db, pFix->zDb); SrcList *pList = pSelect->pSrc; if( NEVER(pList==0) ) return WRC_Continue; for(i=0, pItem=pList->a; inSrc; i++, pItem++){ if( pFix->bTemp==0 ){ if( pItem->zDatabase ){ if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ sqlite3ErrorMsg(pFix->pParse, "%s %T cannot reference objects in database %s", pFix->zType, pFix->pName, pItem->zDatabase); return WRC_Abort; } sqlite3DbFree(db, pItem->zDatabase); pItem->zDatabase = 0; pItem->fg.notCte = 1; } pItem->pSchema = pFix->pSchema; pItem->fg.fromDDL = 1; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) if( pList->a[i].fg.isUsing==0 && sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn) ){ return WRC_Abort; } #endif } if( pSelect->pWith ){ for(i=0; ipWith->nCte; i++){ if( sqlite3WalkSelect(p, pSelect->pWith->a[i].pSelect) ){ return WRC_Abort; } } } return WRC_Continue; } /* ** Initialize a DbFixer structure. This routine must be called prior ** to passing the structure to one of the sqliteFixAAAA() routines below. */ SQLITE_PRIVATE void sqlite3FixInit( DbFixer *pFix, /* The fixer to be initialized */ Parse *pParse, /* Error messages will be written here */ int iDb, /* This is the database that must be used */ const char *zType, /* "view", "trigger", or "index" */ const Token *pName /* Name of the view, trigger, or index */ ){ sqlite3 *db = pParse->db; assert( db->nDb>iDb ); pFix->pParse = pParse; pFix->zDb = db->aDb[iDb].zDbSName; pFix->pSchema = db->aDb[iDb].pSchema; pFix->zType = zType; pFix->pName = pName; pFix->bTemp = (iDb==1); pFix->w.pParse = pParse; pFix->w.xExprCallback = fixExprCb; pFix->w.xSelectCallback = fixSelectCb; pFix->w.xSelectCallback2 = sqlite3WalkWinDefnDummyCallback; pFix->w.walkerDepth = 0; pFix->w.eCode = 0; pFix->w.u.pFix = pFix; } /* ** The following set of routines walk through the parse tree and assign ** a specific database to all table references where the database name ** was left unspecified in the original SQL statement. The pFix structure ** must have been initialized by a prior call to sqlite3FixInit(). ** ** These routines are used to make sure that an index, trigger, or ** view in one database does not refer to objects in a different database. ** (Exception: indices, triggers, and views in the TEMP database are ** allowed to refer to anything.) If a reference is explicitly made ** to an object in a different database, an error message is added to ** pParse->zErrMsg and these routines return non-zero. If everything ** checks out, these routines return 0. */ SQLITE_PRIVATE int sqlite3FixSrcList( DbFixer *pFix, /* Context of the fixation */ SrcList *pList /* The Source list to check and modify */ ){ int res = 0; if( pList ){ Select s; memset(&s, 0, sizeof(s)); s.pSrc = pList; res = sqlite3WalkSelect(&pFix->w, &s); } return res; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) SQLITE_PRIVATE int sqlite3FixSelect( DbFixer *pFix, /* Context of the fixation */ Select *pSelect /* The SELECT statement to be fixed to one database */ ){ return sqlite3WalkSelect(&pFix->w, pSelect); } SQLITE_PRIVATE int sqlite3FixExpr( DbFixer *pFix, /* Context of the fixation */ Expr *pExpr /* The expression to be fixed to one database */ ){ return sqlite3WalkExpr(&pFix->w, pExpr); } #endif #ifndef SQLITE_OMIT_TRIGGER SQLITE_PRIVATE int sqlite3FixTriggerStep( DbFixer *pFix, /* Context of the fixation */ TriggerStep *pStep /* The trigger step be fixed to one database */ ){ while( pStep ){ if( sqlite3WalkSelect(&pFix->w, pStep->pSelect) || sqlite3WalkExpr(&pFix->w, pStep->pWhere) || sqlite3WalkExprList(&pFix->w, pStep->pExprList) || sqlite3FixSrcList(pFix, pStep->pFrom) ){ return 1; } #ifndef SQLITE_OMIT_UPSERT { Upsert *pUp; for(pUp=pStep->pUpsert; pUp; pUp=pUp->pNextUpsert){ if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget) || sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere) || sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet) || sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere) ){ return 1; } } } #endif pStep = pStep->pNext; } return 0; } #endif /************** End of attach.c **********************************************/ /************** Begin file auth.c ********************************************/ /* ** 2003 January 11 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the sqlite3_set_authorizer() ** API. This facility is an optional feature of the library. Embedded ** systems that do not need this facility may omit it by recompiling ** the library with -DSQLITE_OMIT_AUTHORIZATION=1 */ /* #include "sqliteInt.h" */ /* ** All of the code in this file may be omitted by defining a single ** macro. */ #ifndef SQLITE_OMIT_AUTHORIZATION /* ** Set or clear the access authorization function. ** ** The access authorization function is be called during the compilation ** phase to verify that the user has read and/or write access permission on ** various fields of the database. The first argument to the auth function ** is a copy of the 3rd argument to this routine. The second argument ** to the auth function is one of these constants: ** ** SQLITE_CREATE_INDEX ** SQLITE_CREATE_TABLE ** SQLITE_CREATE_TEMP_INDEX ** SQLITE_CREATE_TEMP_TABLE ** SQLITE_CREATE_TEMP_TRIGGER ** SQLITE_CREATE_TEMP_VIEW ** SQLITE_CREATE_TRIGGER ** SQLITE_CREATE_VIEW ** SQLITE_DELETE ** SQLITE_DROP_INDEX ** SQLITE_DROP_TABLE ** SQLITE_DROP_TEMP_INDEX ** SQLITE_DROP_TEMP_TABLE ** SQLITE_DROP_TEMP_TRIGGER ** SQLITE_DROP_TEMP_VIEW ** SQLITE_DROP_TRIGGER ** SQLITE_DROP_VIEW ** SQLITE_INSERT ** SQLITE_PRAGMA ** SQLITE_READ ** SQLITE_SELECT ** SQLITE_TRANSACTION ** SQLITE_UPDATE ** ** The third and fourth arguments to the auth function are the name of ** the table and the column that are being accessed. The auth function ** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If ** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY ** means that the SQL statement will never-run - the sqlite3_exec() call ** will return with an error. SQLITE_IGNORE means that the SQL statement ** should run but attempts to read the specified column will return NULL ** and attempts to write the column will be ignored. ** ** Setting the auth function to NULL disables this hook. The default ** setting of the auth function is NULL. */ SQLITE_API int sqlite3_set_authorizer( sqlite3 *db, int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pArg ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; if( db->xAuth ) sqlite3ExpirePreparedStatements(db, 1); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } /* ** Write an error message into pParse->zErrMsg that explains that the ** user-supplied authorization function returned an illegal value. */ static void sqliteAuthBadReturnCode(Parse *pParse){ sqlite3ErrorMsg(pParse, "authorizer malfunction"); pParse->rc = SQLITE_ERROR; } /* ** Invoke the authorization callback for permission to read column zCol from ** table zTab in database zDb. This function assumes that an authorization ** callback has been registered (i.e. that sqlite3.xAuth is not NULL). ** ** If SQLITE_IGNORE is returned and pExpr is not NULL, then pExpr is changed ** to an SQL NULL expression. Otherwise, if pExpr is NULL, then SQLITE_IGNORE ** is treated as SQLITE_DENY. In this case an error is left in pParse. */ SQLITE_PRIVATE int sqlite3AuthReadCol( Parse *pParse, /* The parser context */ const char *zTab, /* Table name */ const char *zCol, /* Column name */ int iDb /* Index of containing database. */ ){ sqlite3 *db = pParse->db; /* Database handle */ char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */ int rc; /* Auth callback return code */ if( db->init.busy ) return SQLITE_OK; rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext #ifdef SQLITE_USER_AUTHENTICATION ,db->auth.zAuthUser #endif ); if( rc==SQLITE_DENY ){ char *z = sqlite3_mprintf("%s.%s", zTab, zCol); if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z); sqlite3ErrorMsg(pParse, "access to %z is prohibited", z); pParse->rc = SQLITE_AUTH; }else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){ sqliteAuthBadReturnCode(pParse); } return rc; } /* ** The pExpr should be a TK_COLUMN expression. The table referred to ** is in pTabList or else it is the NEW or OLD table of a trigger. ** Check to see if it is OK to read this particular column. ** ** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN ** instruction into a TK_NULL. If the auth function returns SQLITE_DENY, ** then generate an error. */ SQLITE_PRIVATE void sqlite3AuthRead( Parse *pParse, /* The parser context */ Expr *pExpr, /* The expression to check authorization on */ Schema *pSchema, /* The schema of the expression */ SrcList *pTabList /* All table that pExpr might refer to */ ){ Table *pTab = 0; /* The table being read */ const char *zCol; /* Name of the column of the table */ int iSrc; /* Index in pTabList->a[] of table being read */ int iDb; /* The index of the database the expression refers to */ int iCol; /* Index of column in table */ assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); assert( !IN_RENAME_OBJECT ); assert( pParse->db->xAuth!=0 ); iDb = sqlite3SchemaToIndex(pParse->db, pSchema); if( iDb<0 ){ /* An attempt to read a column out of a subquery or other ** temporary table. */ return; } if( pExpr->op==TK_TRIGGER ){ pTab = pParse->pTriggerTab; }else{ assert( pTabList ); for(iSrc=0; iSrcnSrc; iSrc++){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ){ pTab = pTabList->a[iSrc].pTab; break; } } } iCol = pExpr->iColumn; if( pTab==0 ) return; if( iCol>=0 ){ assert( iColnCol ); zCol = pTab->aCol[iCol].zCnName; }else if( pTab->iPKey>=0 ){ assert( pTab->iPKeynCol ); zCol = pTab->aCol[pTab->iPKey].zCnName; }else{ zCol = "ROWID"; } assert( iDb>=0 && iDbdb->nDb ); if( SQLITE_IGNORE==sqlite3AuthReadCol(pParse, pTab->zName, zCol, iDb) ){ pExpr->op = TK_NULL; } } /* ** Do an authorization check using the code and arguments given. Return ** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY ** is returned, then the error count and error message in pParse are ** modified appropriately. */ SQLITE_PRIVATE int sqlite3AuthCheck( Parse *pParse, int code, const char *zArg1, const char *zArg2, const char *zArg3 ){ sqlite3 *db = pParse->db; int rc; /* Don't do any authorization checks if the database is initializing ** or if the parser is being invoked from within sqlite3_declare_vtab. */ assert( !IN_RENAME_OBJECT || db->xAuth==0 ); if( db->xAuth==0 || db->init.busy || IN_SPECIAL_PARSE ){ return SQLITE_OK; } /* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the ** callback are either NULL pointers or zero-terminated strings that ** contain additional details about the action to be authorized. ** ** The following testcase() macros show that any of the 3rd through 6th ** parameters can be either NULL or a string. */ testcase( zArg1==0 ); testcase( zArg2==0 ); testcase( zArg3==0 ); testcase( pParse->zAuthContext==0 ); rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext #ifdef SQLITE_USER_AUTHENTICATION ,db->auth.zAuthUser #endif ); if( rc==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized"); pParse->rc = SQLITE_AUTH; }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){ rc = SQLITE_DENY; sqliteAuthBadReturnCode(pParse); } return rc; } /* ** Push an authorization context. After this routine is called, the ** zArg3 argument to authorization callbacks will be zContext until ** popped. Or if pParse==0, this routine is a no-op. */ SQLITE_PRIVATE void sqlite3AuthContextPush( Parse *pParse, AuthContext *pContext, const char *zContext ){ assert( pParse ); pContext->pParse = pParse; pContext->zAuthContext = pParse->zAuthContext; pParse->zAuthContext = zContext; } /* ** Pop an authorization context that was previously pushed ** by sqlite3AuthContextPush */ SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){ if( pContext->pParse ){ pContext->pParse->zAuthContext = pContext->zAuthContext; pContext->pParse = 0; } } #endif /* SQLITE_OMIT_AUTHORIZATION */ /************** End of auth.c ************************************************/ /************** Begin file build.c *******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the SQLite parser ** when syntax rules are reduced. The routines in this file handle the ** following kinds of SQL syntax: ** ** CREATE TABLE ** DROP TABLE ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK */ /* #include "sqliteInt.h" */ #ifndef SQLITE_OMIT_SHARED_CACHE /* ** The TableLock structure is only used by the sqlite3TableLock() and ** codeTableLocks() functions. */ struct TableLock { int iDb; /* The database containing the table to be locked */ Pgno iTab; /* The root page of the table to be locked */ u8 isWriteLock; /* True for write lock. False for a read lock */ const char *zLockName; /* Name of the table */ }; /* ** Record the fact that we want to lock a table at run-time. ** ** The table to be locked has root page iTab and is found in database iDb. ** A read or a write lock can be taken depending on isWritelock. ** ** This routine just records the fact that the lock is desired. The ** code to make the lock occur is generated by a later call to ** codeTableLocks() which occurs during sqlite3FinishCoding(). */ static SQLITE_NOINLINE void lockTable( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database containing the table to lock */ Pgno iTab, /* Root page number of the table to be locked */ u8 isWriteLock, /* True for a write lock */ const char *zName /* Name of the table to be locked */ ){ Parse *pToplevel; int i; int nBytes; TableLock *p; assert( iDb>=0 ); pToplevel = sqlite3ParseToplevel(pParse); for(i=0; inTableLock; i++){ p = &pToplevel->aTableLock[i]; if( p->iDb==iDb && p->iTab==iTab ){ p->isWriteLock = (p->isWriteLock || isWriteLock); return; } } nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1); pToplevel->aTableLock = sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes); if( pToplevel->aTableLock ){ p = &pToplevel->aTableLock[pToplevel->nTableLock++]; p->iDb = iDb; p->iTab = iTab; p->isWriteLock = isWriteLock; p->zLockName = zName; }else{ pToplevel->nTableLock = 0; sqlite3OomFault(pToplevel->db); } } SQLITE_PRIVATE void sqlite3TableLock( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database containing the table to lock */ Pgno iTab, /* Root page number of the table to be locked */ u8 isWriteLock, /* True for a write lock */ const char *zName /* Name of the table to be locked */ ){ if( iDb==1 ) return; if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; lockTable(pParse, iDb, iTab, isWriteLock, zName); } /* ** Code an OP_TableLock instruction for each table locked by the ** statement (configured by calls to sqlite3TableLock()). */ static void codeTableLocks(Parse *pParse){ int i; Vdbe *pVdbe = pParse->pVdbe; assert( pVdbe!=0 ); for(i=0; inTableLock; i++){ TableLock *p = &pParse->aTableLock[i]; int p1 = p->iDb; sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, p->isWriteLock, p->zLockName, P4_STATIC); } } #else #define codeTableLocks(x) #endif /* ** Return TRUE if the given yDbMask object is empty - if it contains no ** 1 bits. This routine is used by the DbMaskAllZero() and DbMaskNotZero() ** macros when SQLITE_MAX_ATTACHED is greater than 30. */ #if SQLITE_MAX_ATTACHED>30 SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){ int i; for(i=0; ipToplevel==0 ); db = pParse->db; assert( db->pParse==pParse ); if( pParse->nested ) return; if( pParse->nErr ){ if( db->mallocFailed ) pParse->rc = SQLITE_NOMEM; return; } assert( db->mallocFailed==0 ); /* Begin by generating some termination code at the end of the ** vdbe program */ v = pParse->pVdbe; if( v==0 ){ if( db->init.busy ){ pParse->rc = SQLITE_DONE; return; } v = sqlite3GetVdbe(pParse); if( v==0 ) pParse->rc = SQLITE_ERROR; } assert( !pParse->isMultiWrite || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); if( v ){ if( pParse->bReturning ){ Returning *pReturning = pParse->u1.pReturning; int addrRewind; int reg; if( pReturning->nRetCol ){ sqlite3VdbeAddOp0(v, OP_FkCheck); addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur); VdbeCoverage(v); reg = pReturning->iRetReg; for(i=0; inRetCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, pReturning->iRetCur, i, reg+i); } sqlite3VdbeAddOp2(v, OP_ResultRow, reg, i); sqlite3VdbeAddOp2(v, OP_Next, pReturning->iRetCur, addrRewind+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrRewind); } } sqlite3VdbeAddOp0(v, OP_Halt); #if SQLITE_USER_AUTHENTICATION if( pParse->nTableLock>0 && db->init.busy==0 ){ sqlite3UserAuthInit(db); if( db->auth.authLevelrc = SQLITE_AUTH_USER; return; } } #endif /* The cookie mask contains one bit for each database file open. ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are ** set for each database that is used. Generate code to start a ** transaction on each used database and to verify the schema cookie ** on each used database. */ assert( pParse->nErr>0 || sqlite3VdbeGetOp(v, 0)->opcode==OP_Init ); sqlite3VdbeJumpHere(v, 0); assert( db->nDb>0 ); iDb = 0; do{ Schema *pSchema; if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue; sqlite3VdbeUsesBtree(v, iDb); pSchema = db->aDb[iDb].pSchema; sqlite3VdbeAddOp4Int(v, OP_Transaction, /* Opcode */ iDb, /* P1 */ DbMaskTest(pParse->writeMask,iDb), /* P2 */ pSchema->schema_cookie, /* P3 */ pSchema->iGeneration /* P4 */ ); if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1); VdbeComment((v, "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite)); }while( ++iDbnDb ); #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=0; inVtabLock; i++){ char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]); sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB); } pParse->nVtabLock = 0; #endif #ifndef SQLITE_OMIT_SHARED_CACHE /* Once all the cookies have been verified and transactions opened, ** obtain the required table-locks. This is a no-op unless the ** shared-cache feature is enabled. */ if( pParse->nTableLock ) codeTableLocks(pParse); #endif /* Initialize any AUTOINCREMENT data structures required. */ if( pParse->pAinc ) sqlite3AutoincrementBegin(pParse); /* Code constant expressions that were factored out of inner loops. */ if( pParse->pConstExpr ){ ExprList *pEL = pParse->pConstExpr; pParse->okConstFactor = 0; for(i=0; inExpr; i++){ assert( pEL->a[i].u.iConstExprReg>0 ); sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg); } } if( pParse->bReturning ){ Returning *pRet = pParse->u1.pReturning; if( pRet->nRetCol ){ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol); } } /* Finally, jump back to the beginning of the executable code. */ sqlite3VdbeGoto(v, 1); } /* Get the VDBE program ready for execution */ assert( v!=0 || pParse->nErr ); assert( db->mallocFailed==0 || pParse->nErr ); if( pParse->nErr==0 ){ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ assert( pParse->pAinc==0 || pParse->nTab>0 ); sqlite3VdbeMakeReady(v, pParse); pParse->rc = SQLITE_DONE; }else{ pParse->rc = SQLITE_ERROR; } } /* ** Run the parser and code generator recursively in order to generate ** code for the SQL statement given onto the end of the pParse context ** currently under construction. Notes: ** ** * The final OP_Halt is not appended and other initialization ** and finalization steps are omitted because those are handling by the ** outermost parser. ** ** * Built-in SQL functions always take precedence over application-defined ** SQL functions. In other words, it is not possible to override a ** built-in function. */ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ va_list ap; char *zSql; sqlite3 *db = pParse->db; u32 savedDbFlags = db->mDbFlags; char saveBuf[PARSE_TAIL_SZ]; if( pParse->nErr ) return; if( pParse->eParseMode ) return; assert( pParse->nested<10 ); /* Nesting should only be of limited depth */ va_start(ap, zFormat); zSql = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); if( zSql==0 ){ /* This can result either from an OOM or because the formatted string ** exceeds SQLITE_LIMIT_LENGTH. In the latter case, we need to set ** an error */ if( !db->mallocFailed ) pParse->rc = SQLITE_TOOBIG; pParse->nErr++; return; } pParse->nested++; memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ); memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); db->mDbFlags |= DBFLAG_PreferBuiltin; sqlite3RunParser(pParse, zSql); db->mDbFlags = savedDbFlags; sqlite3DbFree(db, zSql); memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ); pParse->nested--; } #if SQLITE_USER_AUTHENTICATION /* ** Return TRUE if zTable is the name of the system table that stores the ** list of users and their access credentials. */ SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){ return sqlite3_stricmp(zTable, "sqlite_user")==0; } #endif /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the ** database containing the table. Return NULL if not found. ** ** If zDatabase is 0, all databases are searched for the table and the ** first matching table is returned. (No checking for duplicate table ** names is done.) The search order is TEMP first, then MAIN, then any ** auxiliary databases added using the ATTACH command. ** ** See also sqlite3LocateTable(). */ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); #if SQLITE_USER_AUTHENTICATION /* Only the admin user is allowed to know that the sqlite_user table ** exists */ if( db->auth.authLevelnDb; i++){ if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break; } if( i>=db->nDb ){ /* No match against the official names. But always match "main" ** to schema 0 as a legacy fallback. */ if( sqlite3StrICmp(zDatabase,"main")==0 ){ i = 0; }else{ return 0; } } p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName); if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ if( i==1 ){ if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 || sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 || sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, LEGACY_TEMP_SCHEMA_TABLE); } }else{ if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, LEGACY_SCHEMA_TABLE); } } } }else{ /* Match against TEMP first */ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName); if( p ) return p; /* The main database is second */ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName); if( p ) return p; /* Attached databases are in order of attachment */ for(i=2; inDb; i++){ assert( sqlite3SchemaMutexHeld(db, i, 0) ); p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName); if( p ) break; } if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, LEGACY_SCHEMA_TABLE); }else if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, LEGACY_TEMP_SCHEMA_TABLE); } } } return p; } /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the ** database containing the table. Return NULL if not found. Also leave an ** error message in pParse->zErrMsg. ** ** The difference between this routine and sqlite3FindTable() is that this ** routine leaves an error message in pParse->zErrMsg where ** sqlite3FindTable() does not. */ SQLITE_PRIVATE Table *sqlite3LocateTable( Parse *pParse, /* context in which to report errors */ u32 flags, /* LOCATE_VIEW or LOCATE_NOERR */ const char *zName, /* Name of the table we are looking for */ const char *zDbase /* Name of the database. Might be NULL */ ){ Table *p; sqlite3 *db = pParse->db; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 && SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return 0; } p = sqlite3FindTable(db, zName, zDbase); if( p==0 ){ #ifndef SQLITE_OMIT_VIRTUALTABLE /* If zName is the not the name of a table in the schema created using ** CREATE, then check to see if it is the name of an virtual table that ** can be an eponymous virtual table. */ if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){ Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ pMod = sqlite3PragmaVtabRegister(db, zName); } if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ testcase( pMod->pEpoTab==0 ); return pMod->pEpoTab; } } #endif if( flags & LOCATE_NOERR ) return 0; pParse->checkSchema = 1; }else if( IsVirtual(p) && (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)!=0 ){ p = 0; } if( p==0 ){ const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; if( zDbase ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } }else{ assert( HasRowid(p) || p->iPKey<0 ); } return p; } /* ** Locate the table identified by *p. ** ** This is a wrapper around sqlite3LocateTable(). The difference between ** sqlite3LocateTable() and this function is that this function restricts ** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be ** non-NULL if it is part of a view or trigger program definition. See ** sqlite3FixSrcList() for details. */ SQLITE_PRIVATE Table *sqlite3LocateTableItem( Parse *pParse, u32 flags, SrcItem *p ){ const char *zDb; assert( p->pSchema==0 || p->zDatabase==0 ); if( p->pSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); zDb = pParse->db->aDb[iDb].zDbSName; }else{ zDb = p->zDatabase; } return sqlite3LocateTable(pParse, flags, p->zName, zDb); } /* ** Return the preferred table name for system tables. Translate legacy ** names into the new preferred names, as appropriate. */ SQLITE_PRIVATE const char *sqlite3PreferredTableName(const char *zName){ if( sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ if( sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 ){ return PREFERRED_SCHEMA_TABLE; } if( sqlite3StrICmp(zName+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){ return PREFERRED_TEMP_SCHEMA_TABLE; } } return zName; } /* ** Locate the in-memory structure that describes ** a particular index given the name of that index ** and the name of the database that contains the index. ** Return NULL if not found. ** ** If zDatabase is 0, all databases are searched for the ** table and the first matching index is returned. (No checking ** for duplicate index names is done.) The search order is ** TEMP first, then MAIN, then any auxiliary databases added ** using the ATTACH command. */ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){ Index *p = 0; int i; /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ Schema *pSchema = db->aDb[j].pSchema; assert( pSchema ); if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); p = sqlite3HashFind(&pSchema->idxHash, zName); if( p ) break; } return p; } /* ** Reclaim the memory used by an index */ SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3 *db, Index *p){ #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif sqlite3ExprDelete(db, p->pPartIdxWhere); sqlite3ExprListDelete(db, p->aColExpr); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl); #ifdef SQLITE_ENABLE_STAT4 sqlite3_free(p->aiRowEst); #endif sqlite3DbFree(db, p); } /* ** For the index called zIdxName which is found in the database iDb, ** unlike that index from its Table then remove the index from ** the index hash table and free all memory structures associated ** with the index. */ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ Index *pIndex; Hash *pHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pHash = &db->aDb[iDb].pSchema->idxHash; pIndex = sqlite3HashInsert(pHash, zIdxName, 0); if( ALWAYS(pIndex) ){ if( pIndex->pTable->pIndex==pIndex ){ pIndex->pTable->pIndex = pIndex->pNext; }else{ Index *p; /* Justification of ALWAYS(); The index must be on the list of ** indices. */ p = pIndex->pTable->pIndex; while( ALWAYS(p) && p->pNext!=pIndex ){ p = p->pNext; } if( ALWAYS(p && p->pNext==pIndex) ){ p->pNext = pIndex->pNext; } } sqlite3FreeIndex(db, pIndex); } db->mDbFlags |= DBFLAG_SchemaChange; } /* ** Look through the list of open database files in db->aDb[] and if ** any have been closed, remove them from the list. Reallocate the ** db->aDb[] structure to a smaller size, if possible. ** ** Entry 0 (the "main" database) and entry 1 (the "temp" database) ** are never candidates for being collapsed. */ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){ int i, j; for(i=j=2; inDb; i++){ struct Db *pDb = &db->aDb[i]; if( pDb->pBt==0 ){ sqlite3DbFree(db, pDb->zDbSName); pDb->zDbSName = 0; continue; } if( jaDb[j] = db->aDb[i]; } j++; } db->nDb = j; if( db->nDb<=2 && db->aDb!=db->aDbStatic ){ memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0])); sqlite3DbFree(db, db->aDb); db->aDb = db->aDbStatic; } } /* ** Reset the schema for the database at index iDb. Also reset the ** TEMP schema. The reset is deferred if db->nSchemaLock is not zero. ** Deferred resets may be run by calling with iDb<0. */ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ int i; assert( iDbnDb ); if( iDb>=0 ){ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); DbSetProperty(db, iDb, DB_ResetWanted); DbSetProperty(db, 1, DB_ResetWanted); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; } if( db->nSchemaLock==0 ){ for(i=0; inDb; i++){ if( DbHasProperty(db, i, DB_ResetWanted) ){ sqlite3SchemaClear(db->aDb[i].pSchema); } } } } /* ** Erase all schema information from all attached databases (including ** "main" and "temp") for a single database connection. */ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ int i; sqlite3BtreeEnterAll(db); for(i=0; inDb; i++){ Db *pDb = &db->aDb[i]; if( pDb->pSchema ){ if( db->nSchemaLock==0 ){ sqlite3SchemaClear(pDb->pSchema); }else{ DbSetProperty(db, i, DB_ResetWanted); } } } db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk); sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); if( db->nSchemaLock==0 ){ sqlite3CollapseDatabaseArray(db); } } /* ** This routine is called when a commit occurs. */ SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){ db->mDbFlags &= ~DBFLAG_SchemaChange; } /* ** Set the expression associated with a column. This is usually ** the DEFAULT value, but might also be the expression that computes ** the value for a generated column. */ SQLITE_PRIVATE void sqlite3ColumnSetExpr( Parse *pParse, /* Parsing context */ Table *pTab, /* The table containing the column */ Column *pCol, /* The column to receive the new DEFAULT expression */ Expr *pExpr /* The new default expression */ ){ ExprList *pList; assert( IsOrdinaryTable(pTab) ); pList = pTab->u.tab.pDfltList; if( pCol->iDflt==0 || NEVER(pList==0) || NEVER(pList->nExpriDflt) ){ pCol->iDflt = pList==0 ? 1 : pList->nExpr+1; pTab->u.tab.pDfltList = sqlite3ExprListAppend(pParse, pList, pExpr); }else{ sqlite3ExprDelete(pParse->db, pList->a[pCol->iDflt-1].pExpr); pList->a[pCol->iDflt-1].pExpr = pExpr; } } /* ** Return the expression associated with a column. The expression might be ** the DEFAULT clause or the AS clause of a generated column. ** Return NULL if the column has no associated expression. */ SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ if( pCol->iDflt==0 ) return 0; if( !IsOrdinaryTable(pTab) ) return 0; if( NEVER(pTab->u.tab.pDfltList==0) ) return 0; if( NEVER(pTab->u.tab.pDfltList->nExpriDflt) ) return 0; return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; } /* ** Set the collating sequence name for a column. */ SQLITE_PRIVATE void sqlite3ColumnSetColl( sqlite3 *db, Column *pCol, const char *zColl ){ i64 nColl; i64 n; char *zNew; assert( zColl!=0 ); n = sqlite3Strlen30(pCol->zCnName) + 1; if( pCol->colFlags & COLFLAG_HASTYPE ){ n += sqlite3Strlen30(pCol->zCnName+n) + 1; } nColl = sqlite3Strlen30(zColl) + 1; zNew = sqlite3DbRealloc(db, pCol->zCnName, nColl+n); if( zNew ){ pCol->zCnName = zNew; memcpy(pCol->zCnName + n, zColl, nColl); pCol->colFlags |= COLFLAG_HASCOLL; } } /* ** Return the collating sequence name for a column */ SQLITE_PRIVATE const char *sqlite3ColumnColl(Column *pCol){ const char *z; if( (pCol->colFlags & COLFLAG_HASCOLL)==0 ) return 0; z = pCol->zCnName; while( *z ){ z++; } if( pCol->colFlags & COLFLAG_HASTYPE ){ do{ z++; }while( *z ); } return z+1; } /* ** Delete memory allocated for the column names of a table or view (the ** Table.aCol[] array). */ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ int i; Column *pCol; assert( pTable!=0 ); assert( db!=0 ); if( (pCol = pTable->aCol)!=0 ){ for(i=0; inCol; i++, pCol++){ assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) ); sqlite3DbFree(db, pCol->zCnName); } sqlite3DbNNFreeNN(db, pTable->aCol); if( IsOrdinaryTable(pTable) ){ sqlite3ExprListDelete(db, pTable->u.tab.pDfltList); } if( db->pnBytesFreed==0 ){ pTable->aCol = 0; pTable->nCol = 0; if( IsOrdinaryTable(pTable) ){ pTable->u.tab.pDfltList = 0; } } } } /* ** Remove the memory data structures associated with the given ** Table. No changes are made to disk by this routine. ** ** This routine just deletes the data structure. It does not unlink ** the table data structure from the hash table. But it does destroy ** memory structures of the indices and foreign keys associated with ** the table. ** ** The db parameter is optional. It is needed if the Table object ** contains lookaside memory. (Table objects in the schema do not use ** lookaside memory, but some ephemeral Table objects do.) Or the ** db parameter can be used with db->pnBytesFreed to measure the memory ** used by the Table object. */ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; #ifdef SQLITE_DEBUG /* Record the number of outstanding lookaside allocations in schema Tables ** prior to doing any free() operations. Since schema Tables do not use ** lookaside, this number should not change. ** ** If malloc has already failed, it may be that it failed while allocating ** a Table object that was going to be marked ephemeral. So do not check ** that no lookaside memory is used in this case either. */ int nLookaside = 0; assert( db!=0 ); if( !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){ nLookaside = sqlite3LookasideUsed(db, 0); } #endif /* Delete all indices associated with this table. */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; assert( pIndex->pSchema==pTable->pSchema || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) ); if( db->pnBytesFreed==0 && !IsVirtual(pTable) ){ char *zName = pIndex->zName; TESTONLY ( Index *pOld = ) sqlite3HashInsert( &pIndex->pSchema->idxHash, zName, 0 ); assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); assert( pOld==pIndex || pOld==0 ); } sqlite3FreeIndex(db, pIndex); } if( IsOrdinaryTable(pTable) ){ sqlite3FkDelete(db, pTable); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( IsVirtual(pTable) ){ sqlite3VtabClear(db, pTable); } #endif else{ assert( IsView(pTable) ); sqlite3SelectDelete(db, pTable->u.view.pSelect); } /* Delete the Table structure itself. */ sqlite3DeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); sqlite3ExprListDelete(db, pTable->pCheck); sqlite3DbFree(db, pTable); /* Verify that no lookaside memory was used by schema tables */ assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) ); } SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ /* Do not delete the table until the reference count reaches zero. */ assert( db!=0 ); if( !pTable ) return; if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return; deleteTable(db, pTable); } SQLITE_PRIVATE void sqlite3DeleteTableGeneric(sqlite3 *db, void *pTable){ sqlite3DeleteTable(db, (Table*)pTable); } /* ** Unlink the given table from the hash tables and the delete the ** table structure with all its indices and foreign keys. */ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){ Table *p; Db *pDb; assert( db!=0 ); assert( iDb>=0 && iDbnDb ); assert( zTabName ); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */ pDb = &db->aDb[iDb]; p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); sqlite3DeleteTable(db, p); db->mDbFlags |= DBFLAG_SchemaChange; } /* ** Given a token, return a string that consists of the text of that ** token. Space to hold the returned string ** is obtained from sqliteMalloc() and must be freed by the calling ** function. ** ** Any quotation marks (ex: "name", 'name', [name], or `name`) that ** surround the body of the token are removed. ** ** Tokens are often just pointers into the original SQL text and so ** are not \000 terminated and are not persistent. The returned string ** is \000 terminated and is persistent. */ SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, const Token *pName){ char *zName; if( pName ){ zName = sqlite3DbStrNDup(db, (const char*)pName->z, pName->n); sqlite3Dequote(zName); }else{ zName = 0; } return zName; } /* ** Open the sqlite_schema table stored in database number iDb for ** writing. The table is opened using cursor 0. */ SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *p, int iDb){ Vdbe *v = sqlite3GetVdbe(p); sqlite3TableLock(p, iDb, SCHEMA_ROOT, 1, LEGACY_SCHEMA_TABLE); sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, SCHEMA_ROOT, iDb, 5); if( p->nTab==0 ){ p->nTab = 1; } } /* ** Parameter zName points to a nul-terminated buffer containing the name ** of a database ("main", "temp" or the name of an attached db). This ** function returns the index of the named database in db->aDb[], or ** -1 if the named db cannot be found. */ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){ int i = -1; /* Database number */ if( zName ){ Db *pDb; for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){ if( 0==sqlite3_stricmp(pDb->zDbSName, zName) ) break; /* "main" is always an acceptable alias for the primary database ** even if it has been renamed using SQLITE_DBCONFIG_MAINDBNAME. */ if( i==0 && 0==sqlite3_stricmp("main", zName) ) break; } } return i; } /* ** The token *pName contains the name of a database (either "main" or ** "temp" or the name of an attached db). This routine returns the ** index of the named database in db->aDb[], or -1 if the named db ** does not exist. */ SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){ int i; /* Database number */ char *zName; /* Name we are searching for */ zName = sqlite3NameFromToken(db, pName); i = sqlite3FindDbName(db, zName); sqlite3DbFree(db, zName); return i; } /* The table or view or trigger name is passed to this routine via tokens ** pName1 and pName2. If the table name was fully qualified, for example: ** ** CREATE TABLE xxx.yyy (...); ** ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if ** the table name is not fully qualified, i.e.: ** ** CREATE TABLE yyy(...); ** ** Then pName1 is set to "yyy" and pName2 is "". ** ** This routine sets the *ppUnqual pointer to point at the token (pName1 or ** pName2) that stores the unqualified table name. The index of the ** database "xxx" is returned. */ SQLITE_PRIVATE int sqlite3TwoPartName( Parse *pParse, /* Parsing and code generating context */ Token *pName1, /* The "xxx" in the name "xxx.yyy" or "xxx" */ Token *pName2, /* The "yyy" in the name "xxx.yyy" */ Token **pUnqual /* Write the unqualified object name here */ ){ int iDb; /* Database holding the object */ sqlite3 *db = pParse->db; assert( pName2!=0 ); if( pName2->n>0 ){ if( db->init.busy ) { sqlite3ErrorMsg(pParse, "corrupt database"); return -1; } *pUnqual = pName2; iDb = sqlite3FindDb(db, pName1); if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); return -1; } }else{ assert( db->init.iDb==0 || db->init.busy || IN_SPECIAL_PARSE || (db->mDbFlags & DBFLAG_Vacuum)!=0); iDb = db->init.iDb; *pUnqual = pName1; } return iDb; } /* ** True if PRAGMA writable_schema is ON */ SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3 *db){ testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==0 ); testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== SQLITE_WriteSchema ); testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== SQLITE_Defensive ); testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== (SQLITE_WriteSchema|SQLITE_Defensive) ); return (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==SQLITE_WriteSchema; } /* ** This routine is used to check if the UTF-8 string zName is a legal ** unqualified name for a new schema object (table, index, view or ** trigger). All names are legal except those that begin with the string ** "sqlite_" (in upper, lower or mixed case). This portion of the namespace ** is reserved for internal use. ** ** When parsing the sqlite_schema table, this routine also checks to ** make sure the "type", "name", and "tbl_name" columns are consistent ** with the SQL. */ SQLITE_PRIVATE int sqlite3CheckObjectName( Parse *pParse, /* Parsing context */ const char *zName, /* Name of the object to check */ const char *zType, /* Type of this object */ const char *zTblName /* Parent table name for triggers and indexes */ ){ sqlite3 *db = pParse->db; if( sqlite3WritableSchema(db) || db->init.imposterTable || !sqlite3Config.bExtraSchemaChecks ){ /* Skip these error checks for writable_schema=ON */ return SQLITE_OK; } if( db->init.busy ){ if( sqlite3_stricmp(zType, db->init.azInit[0]) || sqlite3_stricmp(zName, db->init.azInit[1]) || sqlite3_stricmp(zTblName, db->init.azInit[2]) ){ sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */ return SQLITE_ERROR; } }else{ if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7)) || (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName)) ){ sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName); return SQLITE_ERROR; } } return SQLITE_OK; } /* ** Return the PRIMARY KEY index of a table */ SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){ Index *p; for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){} return p; } /* ** Convert an table column number into a index column number. That is, ** for the column iCol in the table (as defined by the CREATE TABLE statement) ** find the (first) offset of that column in index pIdx. Or return -1 ** if column iCol is not used in index pIdx. */ SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){ int i; for(i=0; inColumn; i++){ if( iCol==pIdx->aiColumn[i] ) return i; } return -1; } #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Convert a storage column number into a table column number. ** ** The storage column number (0,1,2,....) is the index of the value ** as it appears in the record on disk. The true column number ** is the index (0,1,2,...) of the column in the CREATE TABLE statement. ** ** The storage column number is less than the table column number if ** and only there are VIRTUAL columns to the left. ** ** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro. */ SQLITE_PRIVATE i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){ if( pTab->tabFlags & TF_HasVirtual ){ int i; for(i=0; i<=iCol; i++){ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) iCol++; } } return iCol; } #endif #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Convert a table column number into a storage column number. ** ** The storage column number (0,1,2,....) is the index of the value ** as it appears in the record on disk. Or, if the input column is ** the N-th virtual column (zero-based) then the storage number is ** the number of non-virtual columns in the table plus N. ** ** The true column number is the index (0,1,2,...) of the column in ** the CREATE TABLE statement. ** ** If the input column is a VIRTUAL column, then it should not appear ** in storage. But the value sometimes is cached in registers that ** follow the range of registers used to construct storage. This ** avoids computing the same VIRTUAL column multiple times, and provides ** values for use by OP_Param opcodes in triggers. Hence, if the ** input column is a VIRTUAL table, put it after all the other columns. ** ** In the following, N means "normal column", S means STORED, and ** V means VIRTUAL. Suppose the CREATE TABLE has columns like this: ** ** CREATE TABLE ex(N,S,V,N,S,V,N,S,V); ** -- 0 1 2 3 4 5 6 7 8 ** ** Then the mapping from this function is as follows: ** ** INPUTS: 0 1 2 3 4 5 6 7 8 ** OUTPUTS: 0 1 6 2 3 7 4 5 8 ** ** So, in other words, this routine shifts all the virtual columns to ** the end. ** ** If SQLITE_OMIT_GENERATED_COLUMNS then there are no virtual columns and ** this routine is a no-op macro. If the pTab does not have any virtual ** columns, then this routine is no-op that always return iCol. If iCol ** is negative (indicating the ROWID column) then this routine return iCol. */ SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){ int i; i16 n; assert( iColnCol ); if( (pTab->tabFlags & TF_HasVirtual)==0 || iCol<0 ) return iCol; for(i=0, n=0; iaCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++; } if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ /* iCol is a virtual column itself */ return pTab->nNVCol + i - n; }else{ /* iCol is a normal or stored column */ return n; } } #endif /* ** Insert a single OP_JournalMode query opcode in order to force the ** prepared statement to return false for sqlite3_stmt_readonly(). This ** is used by CREATE TABLE IF NOT EXISTS and similar if the table already ** exists, so that the prepared statement for CREATE TABLE IF NOT EXISTS ** will return false for sqlite3_stmt_readonly() even if that statement ** is a read-only no-op. */ static void sqlite3ForceNotReadOnly(Parse *pParse){ int iReg = ++pParse->nMem; Vdbe *v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp3(v, OP_JournalMode, 0, iReg, PAGER_JOURNALMODE_QUERY); sqlite3VdbeUsesBtree(v, 0); } } /* ** Begin constructing a new table representation in memory. This is ** the first of several action routines that get called in response ** to a CREATE TABLE statement. In particular, this routine is called ** after seeing tokens "CREATE" and "TABLE" and the table name. The isTemp ** flag is true if the table should be stored in the auxiliary database ** file instead of in the main database file. This is normally the case ** when the "TEMP" or "TEMPORARY" keyword occurs in between ** CREATE and TABLE. ** ** The new table record is initialized and put in pParse->pNewTable. ** As more of the CREATE TABLE statement is parsed, additional action ** routines will be called to add more information to this record. ** At the end of the CREATE TABLE statement, the sqlite3EndTable() routine ** is called to complete the construction of the new table record. */ SQLITE_PRIVATE void sqlite3StartTable( Parse *pParse, /* Parser context */ Token *pName1, /* First part of the name of the table or view */ Token *pName2, /* Second part of the name of the table or view */ int isTemp, /* True if this is a TEMP table */ int isView, /* True if this is a VIEW */ int isVirtual, /* True if this is a VIRTUAL table */ int noErr /* Do nothing if table already exists */ ){ Table *pTable; char *zName = 0; /* The name of the new table */ sqlite3 *db = pParse->db; Vdbe *v; int iDb; /* Database number to create the table in */ Token *pName; /* Unqualified name of the table to create */ if( db->init.busy && db->init.newTnum==1 ){ /* Special case: Parsing the sqlite_schema or sqlite_temp_schema schema */ iDb = db->init.iDb; zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb)); pName = pName1; }else{ /* The common case */ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); if( iDb<0 ) return; if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){ /* If creating a temp table, the name may not be qualified. Unless ** the database name is "temp" anyway. */ sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); return; } if( !OMIT_TEMPDB && isTemp ) iDb = 1; zName = sqlite3NameFromToken(db, pName); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)zName, pName); } } pParse->sNameToken = *pName; if( zName==0 ) return; if( sqlite3CheckObjectName(pParse, zName, isView?"view":"table", zName) ){ goto begin_table_error; } if( db->init.iDb==1 ) isTemp = 1; #ifndef SQLITE_OMIT_AUTHORIZATION assert( isTemp==0 || isTemp==1 ); assert( isView==0 || isView==1 ); { static const u8 aCode[] = { SQLITE_CREATE_TABLE, SQLITE_CREATE_TEMP_TABLE, SQLITE_CREATE_VIEW, SQLITE_CREATE_TEMP_VIEW }; char *zDb = db->aDb[iDb].zDbSName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ goto begin_table_error; } if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView], zName, 0, zDb) ){ goto begin_table_error; } } #endif /* Make sure the new table name does not collide with an existing ** index or table name in the same database. Issue an error message if ** it does. The exception is if the statement being parsed was passed ** to an sqlite3_declare_vtab() call. In that case only the column names ** and types will be used, so there is no need to test for namespace ** collisions. */ if( !IN_SPECIAL_PARSE ){ char *zDb = db->aDb[iDb].zDbSName; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } pTable = sqlite3FindTable(db, zName, zDb); if( pTable ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "%s %T already exists", (IsView(pTable)? "view" : "table"), pName); }else{ assert( !db->init.busy || CORRUPT_DB ); sqlite3CodeVerifySchema(pParse, iDb); sqlite3ForceNotReadOnly(pParse); } goto begin_table_error; } if( sqlite3FindIndex(db, zName, zDb)!=0 ){ sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); goto begin_table_error; } } pTable = sqlite3DbMallocZero(db, sizeof(Table)); if( pTable==0 ){ assert( db->mallocFailed ); pParse->rc = SQLITE_NOMEM_BKPT; pParse->nErr++; goto begin_table_error; } pTable->zName = zName; pTable->iPKey = -1; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nTabRef = 1; #ifdef SQLITE_DEFAULT_ROWEST pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST); #else pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); #endif assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; /* Begin generating the code that will insert the table record into ** the schema table. Note in particular that we must go ahead ** and allocate the record number for the table entry now. Before any ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause ** indices to be created and the table record must come before the ** indices. Hence, the record number for the table must be allocated ** now. */ if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){ int addr1; int fileFormat; int reg1, reg2, reg3; /* nullRow[] is an OP_Record encoding of a row containing 5 NULLs */ static const char nullRow[] = { 6, 0, 0, 0, 0, 0 }; sqlite3BeginWriteOperation(pParse, 1, iDb); #ifndef SQLITE_OMIT_VIRTUALTABLE if( isVirtual ){ sqlite3VdbeAddOp0(v, OP_VBegin); } #endif /* If the file format and encoding in the database have not been set, ** set them now. */ reg1 = pParse->regRowid = ++pParse->nMem; reg2 = pParse->regRoot = ++pParse->nMem; reg3 = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT); sqlite3VdbeUsesBtree(v, iDb); addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v); fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? 1 : SQLITE_MAX_FILE_FORMAT; sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, fileFormat); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db)); sqlite3VdbeJumpHere(v, addr1); /* This just creates a place-holder record in the sqlite_schema table. ** The record created does not contain anything yet. It will be replaced ** by the real entry in code generated at sqlite3EndTable(). ** ** The rowid for the new entry is left in register pParse->regRowid. ** The root page number of the new table is left in reg pParse->regRoot. ** The rowid and root page number values are needed by the code that ** sqlite3EndTable will generate. */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) if( isView || isVirtual ){ sqlite3VdbeAddOp2(v, OP_Integer, 0, reg2); }else #endif { assert( !pParse->bReturning ); pParse->u1.addrCrTab = sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY); } sqlite3OpenSchemaTable(pParse, iDb); sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1); sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC); sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeAddOp0(v, OP_Close); } /* Normal (non-error) return. */ return; /* If an error occurs, we jump here */ begin_table_error: pParse->checkSchema = 1; sqlite3DbFree(db, zName); return; } /* Set properties of a table column based on the (magical) ** name of the column. */ #if SQLITE_ENABLE_HIDDEN_COLUMNS SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ if( sqlite3_strnicmp(pCol->zCnName, "__hidden__", 10)==0 ){ pCol->colFlags |= COLFLAG_HIDDEN; if( pTab ) pTab->tabFlags |= TF_HasHidden; }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){ pTab->tabFlags |= TF_OOOHidden; } } #endif /* ** Clean up the data structures associated with the RETURNING clause. */ static void sqlite3DeleteReturning(sqlite3 *db, void *pArg){ Returning *pRet = (Returning*)pArg; Hash *pHash; pHash = &(db->aDb[1].pSchema->trigHash); sqlite3HashInsert(pHash, pRet->zName, 0); sqlite3ExprListDelete(db, pRet->pReturnEL); sqlite3DbFree(db, pRet); } /* ** Add the RETURNING clause to the parse currently underway. ** ** This routine creates a special TEMP trigger that will fire for each row ** of the DML statement. That TEMP trigger contains a single SELECT ** statement with a result set that is the argument of the RETURNING clause. ** The trigger has the Trigger.bReturning flag and an opcode of ** TK_RETURNING instead of TK_SELECT, so that the trigger code generator ** knows to handle it specially. The TEMP trigger is automatically ** removed at the end of the parse. ** ** When this routine is called, we do not yet know if the RETURNING clause ** is attached to a DELETE, INSERT, or UPDATE, so construct it as a ** RETURNING trigger instead. It will then be converted into the appropriate ** type on the first call to sqlite3TriggersExist(). */ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){ Returning *pRet; Hash *pHash; sqlite3 *db = pParse->db; if( pParse->pNewTrigger ){ sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger"); }else{ assert( pParse->bReturning==0 || pParse->ifNotExists ); } pParse->bReturning = 1; pRet = sqlite3DbMallocZero(db, sizeof(*pRet)); if( pRet==0 ){ sqlite3ExprListDelete(db, pList); return; } pParse->u1.pReturning = pRet; pRet->pParse = pParse; pRet->pReturnEL = pList; sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet); testcase( pParse->earlyCleanup ); if( db->mallocFailed ) return; sqlite3_snprintf(sizeof(pRet->zName), pRet->zName, "sqlite_returning_%p", pParse); pRet->retTrig.zName = pRet->zName; pRet->retTrig.op = TK_RETURNING; pRet->retTrig.tr_tm = TRIGGER_AFTER; pRet->retTrig.bReturning = 1; pRet->retTrig.pSchema = db->aDb[1].pSchema; pRet->retTrig.pTabSchema = db->aDb[1].pSchema; pRet->retTrig.step_list = &pRet->retTStep; pRet->retTStep.op = TK_RETURNING; pRet->retTStep.pTrig = &pRet->retTrig; pRet->retTStep.pExprList = pList; pHash = &(db->aDb[1].pSchema->trigHash); assert( sqlite3HashFind(pHash, pRet->zName)==0 || pParse->nErr || pParse->ifNotExists ); if( sqlite3HashInsert(pHash, pRet->zName, &pRet->retTrig) ==&pRet->retTrig ){ sqlite3OomFault(db); } } /* ** Add a new column to the table currently being constructed. ** ** The parser calls this routine once for each column declaration ** in a CREATE TABLE statement. sqlite3StartTable() gets called ** first to get things going. Then this routine is called for each ** column. */ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ Table *p; int i; char *z; char *zType; Column *pCol; sqlite3 *db = pParse->db; u8 hName; Column *aNew; u8 eType = COLTYPE_CUSTOM; u8 szEst = 1; char affinity = SQLITE_AFF_BLOB; if( (p = pParse->pNewTable)==0 ) return; if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); return; } if( !IN_RENAME_OBJECT ) sqlite3DequoteToken(&sName); /* Because keywords GENERATE ALWAYS can be converted into identifiers ** by the parser, we can sometimes end up with a typename that ends ** with "generated always". Check for this case and omit the surplus ** text. */ if( sType.n>=16 && sqlite3_strnicmp(sType.z+(sType.n-6),"always",6)==0 ){ sType.n -= 6; while( ALWAYS(sType.n>0) && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--; if( sType.n>=9 && sqlite3_strnicmp(sType.z+(sType.n-9),"generated",9)==0 ){ sType.n -= 9; while( sType.n>0 && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--; } } /* Check for standard typenames. For standard typenames we will ** set the Column.eType field rather than storing the typename after ** the column name, in order to save space. */ if( sType.n>=3 ){ sqlite3DequoteToken(&sType); for(i=0; i0) ); if( z==0 ) return; if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, &sName); memcpy(z, sName.z, sName.n); z[sName.n] = 0; sqlite3Dequote(z); hName = sqlite3StrIHash(z); for(i=0; inCol; i++){ if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); sqlite3DbFree(db, z); return; } } aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0])); if( aNew==0 ){ sqlite3DbFree(db, z); return; } p->aCol = aNew; pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); pCol->zCnName = z; pCol->hName = hName; sqlite3ColumnPropertiesFromName(p, pCol); if( sType.n==0 ){ /* If there is no type specified, columns have the default affinity ** 'BLOB' with a default size of 4 bytes. */ pCol->affinity = affinity; pCol->eCType = eType; pCol->szEst = szEst; #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( affinity==SQLITE_AFF_BLOB ){ if( 4>=sqlite3GlobalConfig.szSorterRef ){ pCol->colFlags |= COLFLAG_SORTERREF; } } #endif }else{ zType = z + sqlite3Strlen30(z) + 1; memcpy(zType, sType.z, sType.n); zType[sType.n] = 0; sqlite3Dequote(zType); pCol->affinity = sqlite3AffinityType(zType, pCol); pCol->colFlags |= COLFLAG_HASTYPE; } p->nCol++; p->nNVCol++; pParse->constraintName.n = 0; } /* ** This routine is called by the parser while in the middle of ** parsing a CREATE TABLE statement. A "NOT NULL" constraint has ** been seen on a column. This routine sets the notNull flag on ** the column currently under construction. */ SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){ Table *p; Column *pCol; p = pParse->pNewTable; if( p==0 || NEVER(p->nCol<1) ) return; pCol = &p->aCol[p->nCol-1]; pCol->notNull = (u8)onError; p->tabFlags |= TF_HasNotNull; /* Set the uniqNotNull flag on any UNIQUE or PK indexes already created ** on this column. */ if( pCol->colFlags & COLFLAG_UNIQUE ){ Index *pIdx; for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nKeyCol==1 && pIdx->onError!=OE_None ); if( pIdx->aiColumn[0]==p->nCol-1 ){ pIdx->uniqNotNull = 1; } } } } /* ** Scan the column type name zType (length nType) and return the ** associated affinity type. ** ** This routine does a case-independent search of zType for the ** substrings in the following table. If one of the substrings is ** found, the corresponding affinity is returned. If zType contains ** more than one of the substrings, entries toward the top of ** the table take priority. For example, if zType is 'BLOBINT', ** SQLITE_AFF_INTEGER is returned. ** ** Substring | Affinity ** -------------------------------- ** 'INT' | SQLITE_AFF_INTEGER ** 'CHAR' | SQLITE_AFF_TEXT ** 'CLOB' | SQLITE_AFF_TEXT ** 'TEXT' | SQLITE_AFF_TEXT ** 'BLOB' | SQLITE_AFF_BLOB ** 'REAL' | SQLITE_AFF_REAL ** 'FLOA' | SQLITE_AFF_REAL ** 'DOUB' | SQLITE_AFF_REAL ** ** If none of the substrings in the above table are found, ** SQLITE_AFF_NUMERIC is returned. */ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, Column *pCol){ u32 h = 0; char aff = SQLITE_AFF_NUMERIC; const char *zChar = 0; assert( zIn!=0 ); while( zIn[0] ){ u8 x = *(u8*)zIn; h = (h<<8) + sqlite3UpperToLower[x]; zIn++; if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */ aff = SQLITE_AFF_TEXT; zChar = zIn; }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */ aff = SQLITE_AFF_TEXT; }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */ aff = SQLITE_AFF_TEXT; }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */ && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){ aff = SQLITE_AFF_BLOB; if( zIn[0]=='(' ) zChar = zIn; #ifndef SQLITE_OMIT_FLOATING_POINT }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */ && aff==SQLITE_AFF_NUMERIC ){ aff = SQLITE_AFF_REAL; }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */ && aff==SQLITE_AFF_NUMERIC ){ aff = SQLITE_AFF_REAL; }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') /* DOUB */ && aff==SQLITE_AFF_NUMERIC ){ aff = SQLITE_AFF_REAL; #endif }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */ aff = SQLITE_AFF_INTEGER; break; } } /* If pCol is not NULL, store an estimate of the field size. The ** estimate is scaled so that the size of an integer is 1. */ if( pCol ){ int v = 0; /* default size is approx 4 bytes */ if( aff r=(k/4+1) */ sqlite3GetInt32(zChar, &v); break; } zChar++; } }else{ v = 16; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/ } } #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( v>=sqlite3GlobalConfig.szSorterRef ){ pCol->colFlags |= COLFLAG_SORTERREF; } #endif v = v/4 + 1; if( v>255 ) v = 255; pCol->szEst = v; } return aff; } /* ** The expression is the default value for the most recently added column ** of the table currently under construction. ** ** Default value expressions must be constant. Raise an exception if this ** is not the case. ** ** This routine is called by the parser while in the middle of ** parsing a CREATE TABLE statement. */ SQLITE_PRIVATE void sqlite3AddDefaultValue( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The parsed expression of the default value */ const char *zStart, /* Start of the default value text */ const char *zEnd /* First character past end of default value text */ ){ Table *p; Column *pCol; sqlite3 *db = pParse->db; p = pParse->pNewTable; if( p!=0 ){ int isInit = db->init.busy && db->init.iDb!=1; pCol = &(p->aCol[p->nCol-1]); if( !sqlite3ExprIsConstantOrFunction(pExpr, isInit) ){ sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", pCol->zCnName); #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( pCol->colFlags & COLFLAG_GENERATED ){ testcase( pCol->colFlags & COLFLAG_VIRTUAL ); testcase( pCol->colFlags & COLFLAG_STORED ); sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column"); #endif }else{ /* A copy of pExpr is used instead of the original, as pExpr contains ** tokens that point to volatile memory. */ Expr x, *pDfltExpr; memset(&x, 0, sizeof(x)); x.op = TK_SPAN; x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd); x.pLeft = pExpr; x.flags = EP_Skip; pDfltExpr = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); sqlite3DbFree(db, x.u.zToken); sqlite3ColumnSetExpr(pParse, p, pCol, pDfltExpr); } } if( IN_RENAME_OBJECT ){ sqlite3RenameExprUnmap(pParse, pExpr); } sqlite3ExprDelete(db, pExpr); } /* ** Backwards Compatibility Hack: ** ** Historical versions of SQLite accepted strings as column names in ** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example: ** ** CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim) ** CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC); ** ** This is goofy. But to preserve backwards compatibility we continue to ** accept it. This routine does the necessary conversion. It converts ** the expression given in its argument from a TK_STRING into a TK_ID ** if the expression is just a TK_STRING with an optional COLLATE clause. ** If the expression is anything other than TK_STRING, the expression is ** unchanged. */ static void sqlite3StringToId(Expr *p){ if( p->op==TK_STRING ){ p->op = TK_ID; }else if( p->op==TK_COLLATE && p->pLeft->op==TK_STRING ){ p->pLeft->op = TK_ID; } } /* ** Tag the given column as being part of the PRIMARY KEY */ static void makeColumnPartOfPrimaryKey(Parse *pParse, Column *pCol){ pCol->colFlags |= COLFLAG_PRIMKEY; #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pCol->colFlags & COLFLAG_GENERATED ){ testcase( pCol->colFlags & COLFLAG_VIRTUAL ); testcase( pCol->colFlags & COLFLAG_STORED ); sqlite3ErrorMsg(pParse, "generated columns cannot be part of the PRIMARY KEY"); } #endif } /* ** Designate the PRIMARY KEY for the table. pList is a list of names ** of columns that form the primary key. If pList is NULL, then the ** most recently added column of the table is the primary key. ** ** A table can have at most one primary key. If the table already has ** a primary key (and this is the second primary key) then create an ** error. ** ** If the PRIMARY KEY is on a single column whose datatype is INTEGER, ** then we will try to use that column as the rowid. Set the Table.iPKey ** field of the table under construction to be the index of the ** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is ** no INTEGER PRIMARY KEY. ** ** If the key is not an INTEGER PRIMARY KEY, then create a unique ** index for the key. No index is created for INTEGER PRIMARY KEYs. */ SQLITE_PRIVATE void sqlite3AddPrimaryKey( Parse *pParse, /* Parsing context */ ExprList *pList, /* List of field names to be indexed */ int onError, /* What to do with a uniqueness conflict */ int autoInc, /* True if the AUTOINCREMENT keyword is present */ int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ ){ Table *pTab = pParse->pNewTable; Column *pCol = 0; int iCol = -1, i; int nTerm; if( pTab==0 ) goto primary_key_exit; if( pTab->tabFlags & TF_HasPrimaryKey ){ sqlite3ErrorMsg(pParse, "table \"%s\" has more than one primary key", pTab->zName); goto primary_key_exit; } pTab->tabFlags |= TF_HasPrimaryKey; if( pList==0 ){ iCol = pTab->nCol - 1; pCol = &pTab->aCol[iCol]; makeColumnPartOfPrimaryKey(pParse, pCol); nTerm = 1; }else{ nTerm = pList->nExpr; for(i=0; ia[i].pExpr); assert( pCExpr!=0 ); sqlite3StringToId(pCExpr); if( pCExpr->op==TK_ID ){ const char *zCName; assert( !ExprHasProperty(pCExpr, EP_IntValue) ); zCName = pCExpr->u.zToken; for(iCol=0; iColnCol; iCol++){ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){ pCol = &pTab->aCol[iCol]; makeColumnPartOfPrimaryKey(pParse, pCol); break; } } } } } if( nTerm==1 && pCol && pCol->eCType==COLTYPE_INTEGER && sortOrder!=SQLITE_SO_DESC ){ if( IN_RENAME_OBJECT && pList ){ Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[0].pExpr); sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr); } pTab->iPKey = iCol; pTab->keyConf = (u8)onError; assert( autoInc==0 || autoInc==1 ); pTab->tabFlags |= autoInc*TF_Autoincrement; if( pList ) pParse->iPkSortOrder = pList->a[0].fg.sortFlags; (void)sqlite3HasExplicitNulls(pParse, pList); }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY); pList = 0; } primary_key_exit: sqlite3ExprListDelete(pParse->db, pList); return; } /* ** Add a new CHECK constraint to the table currently under construction. */ SQLITE_PRIVATE void sqlite3AddCheckConstraint( Parse *pParse, /* Parsing context */ Expr *pCheckExpr, /* The check expression */ const char *zStart, /* Opening "(" */ const char *zEnd /* Closing ")" */ ){ #ifndef SQLITE_OMIT_CHECK Table *pTab = pParse->pNewTable; sqlite3 *db = pParse->db; if( pTab && !IN_DECLARE_VTAB && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt) ){ pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); if( pParse->constraintName.n ){ sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); }else{ Token t; for(zStart++; sqlite3Isspace(zStart[0]); zStart++){} while( sqlite3Isspace(zEnd[-1]) ){ zEnd--; } t.z = zStart; t.n = (int)(zEnd - t.z); sqlite3ExprListSetName(pParse, pTab->pCheck, &t, 1); } }else #endif { sqlite3ExprDelete(pParse->db, pCheckExpr); } } /* ** Set the collation function of the most recently parsed table column ** to the CollSeq given. */ SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){ Table *p; int i; char *zColl; /* Dequoted name of collation sequence */ sqlite3 *db; if( (p = pParse->pNewTable)==0 || IN_RENAME_OBJECT ) return; i = p->nCol-1; db = pParse->db; zColl = sqlite3NameFromToken(db, pToken); if( !zColl ) return; if( sqlite3LocateCollSeq(pParse, zColl) ){ Index *pIdx; sqlite3ColumnSetColl(db, &p->aCol[i], zColl); /* If the column is declared as " PRIMARY KEY COLLATE ", ** then an index may have been created on this column before the ** collation type was added. Correct this if it is the case. */ for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nKeyCol==1 ); if( pIdx->aiColumn[0]==i ){ pIdx->azColl[0] = sqlite3ColumnColl(&p->aCol[i]); } } } sqlite3DbFree(db, zColl); } /* Change the most recently parsed column to be a GENERATED ALWAYS AS ** column. */ SQLITE_PRIVATE void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ #ifndef SQLITE_OMIT_GENERATED_COLUMNS u8 eType = COLFLAG_VIRTUAL; Table *pTab = pParse->pNewTable; Column *pCol; if( pTab==0 ){ /* generated column in an CREATE TABLE IF NOT EXISTS that already exists */ goto generated_done; } pCol = &(pTab->aCol[pTab->nCol-1]); if( IN_DECLARE_VTAB ){ sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns"); goto generated_done; } if( pCol->iDflt>0 ) goto generated_error; if( pType ){ if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){ /* no-op */ }else if( pType->n==6 && sqlite3StrNICmp("stored",pType->z,6)==0 ){ eType = COLFLAG_STORED; }else{ goto generated_error; } } if( eType==COLFLAG_VIRTUAL ) pTab->nNVCol--; pCol->colFlags |= eType; assert( TF_HasVirtual==COLFLAG_VIRTUAL ); assert( TF_HasStored==COLFLAG_STORED ); pTab->tabFlags |= eType; if( pCol->colFlags & COLFLAG_PRIMKEY ){ makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */ } if( ALWAYS(pExpr) && pExpr->op==TK_ID ){ /* The value of a generated column needs to be a real expression, not ** just a reference to another column, in order for covering index ** optimizations to work correctly. So if the value is not an expression, ** turn it into one by adding a unary "+" operator. */ pExpr = sqlite3PExpr(pParse, TK_UPLUS, pExpr, 0); } if( pExpr && pExpr->op!=TK_RAISE ) pExpr->affExpr = pCol->affinity; sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr); pExpr = 0; goto generated_done; generated_error: sqlite3ErrorMsg(pParse, "error in generated column \"%s\"", pCol->zCnName); generated_done: sqlite3ExprDelete(pParse->db, pExpr); #else /* Throw and error for the GENERATED ALWAYS AS clause if the ** SQLITE_OMIT_GENERATED_COLUMNS compile-time option is used. */ sqlite3ErrorMsg(pParse, "generated columns not supported"); sqlite3ExprDelete(pParse->db, pExpr); #endif } /* ** Generate code that will increment the schema cookie. ** ** The schema cookie is used to determine when the schema for the ** database changes. After each schema change, the cookie value ** changes. When a process first reads the schema it records the ** cookie. Thereafter, whenever it goes to access the database, ** it checks the cookie to make sure the schema has not changed ** since it was last read. ** ** This plan is not completely bullet-proof. It is possible for ** the schema to change multiple times and for the cookie to be ** set back to prior value. But schema changes are infrequent ** and the probability of hitting the same cookie value is only ** 1 chance in 2^32. So we're safe enough. ** ** IMPLEMENTATION-OF: R-34230-56049 SQLite automatically increments ** the schema-version whenever the schema changes. */ SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){ sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, (int)(1+(unsigned)db->aDb[iDb].pSchema->schema_cookie)); } /* ** Measure the number of characters needed to output the given ** identifier. The number returned includes any quotes used ** but does not include the null terminator. ** ** The estimate is conservative. It might be larger that what is ** really needed. */ static int identLength(const char *z){ int n; for(n=0; *z; n++, z++){ if( *z=='"' ){ n++; } } return n + 2; } /* ** The first parameter is a pointer to an output buffer. The second ** parameter is a pointer to an integer that contains the offset at ** which to write into the output buffer. This function copies the ** nul-terminated string pointed to by the third parameter, zSignedIdent, ** to the specified offset in the buffer and updates *pIdx to refer ** to the first byte after the last byte written before returning. ** ** If the string zSignedIdent consists entirely of alphanumeric ** characters, does not begin with a digit and is not an SQL keyword, ** then it is copied to the output buffer exactly as it is. Otherwise, ** it is quoted using double-quotes. */ static void identPut(char *z, int *pIdx, char *zSignedIdent){ unsigned char *zIdent = (unsigned char*)zSignedIdent; int i, j, needQuote; i = *pIdx; for(j=0; zIdent[j]; j++){ if( !sqlite3Isalnum(zIdent[j]) && zIdent[j]!='_' ) break; } needQuote = sqlite3Isdigit(zIdent[0]) || sqlite3KeywordCode(zIdent, j)!=TK_ID || zIdent[j]!=0 || j==0; if( needQuote ) z[i++] = '"'; for(j=0; zIdent[j]; j++){ z[i++] = zIdent[j]; if( zIdent[j]=='"' ) z[i++] = '"'; } if( needQuote ) z[i++] = '"'; z[i] = 0; *pIdx = i; } /* ** Generate a CREATE TABLE statement appropriate for the given ** table. Memory to hold the text of the statement is obtained ** from sqliteMalloc() and must be freed by the calling function. */ static char *createTableStmt(sqlite3 *db, Table *p){ int i, k, n; char *zStmt; char *zSep, *zSep2, *zEnd; Column *pCol; n = 0; for(pCol = p->aCol, i=0; inCol; i++, pCol++){ n += identLength(pCol->zCnName) + 5; } n += identLength(p->zName); if( n<50 ){ zSep = ""; zSep2 = ","; zEnd = ")"; }else{ zSep = "\n "; zSep2 = ",\n "; zEnd = "\n)"; } n += 35 + 6*p->nCol; zStmt = sqlite3DbMallocRaw(0, n); if( zStmt==0 ){ sqlite3OomFault(db); return 0; } sqlite3_snprintf(n, zStmt, "CREATE TABLE "); k = sqlite3Strlen30(zStmt); identPut(zStmt, &k, p->zName); zStmt[k++] = '('; for(pCol=p->aCol, i=0; inCol; i++, pCol++){ static const char * const azType[] = { /* SQLITE_AFF_BLOB */ "", /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NUMERIC */ " NUM", /* SQLITE_AFF_INTEGER */ " INT", /* SQLITE_AFF_REAL */ " REAL", /* SQLITE_AFF_FLEXNUM */ " NUM", }; int len; const char *zType; sqlite3_snprintf(n-k, &zStmt[k], zSep); k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; identPut(zStmt, &k, pCol->zCnName); assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 ); assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); testcase( pCol->affinity==SQLITE_AFF_BLOB ); testcase( pCol->affinity==SQLITE_AFF_TEXT ); testcase( pCol->affinity==SQLITE_AFF_NUMERIC ); testcase( pCol->affinity==SQLITE_AFF_INTEGER ); testcase( pCol->affinity==SQLITE_AFF_REAL ); testcase( pCol->affinity==SQLITE_AFF_FLEXNUM ); zType = azType[pCol->affinity - SQLITE_AFF_BLOB]; len = sqlite3Strlen30(zType); assert( pCol->affinity==SQLITE_AFF_BLOB || pCol->affinity==SQLITE_AFF_FLEXNUM || pCol->affinity==sqlite3AffinityType(zType, 0) ); memcpy(&zStmt[k], zType, len); k += len; assert( k<=n ); } sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd); return zStmt; } /* ** Resize an Index object to hold N columns total. Return SQLITE_OK ** on success and SQLITE_NOMEM on an OOM error. */ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ char *zExtra; int nByte; if( pIdx->nColumn>=N ) return SQLITE_OK; assert( pIdx->isResized==0 ); nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N; zExtra = sqlite3DbMallocZero(db, nByte); if( zExtra==0 ) return SQLITE_NOMEM_BKPT; memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); pIdx->azColl = (const char**)zExtra; zExtra += sizeof(char*)*N; memcpy(zExtra, pIdx->aiRowLogEst, sizeof(LogEst)*(pIdx->nKeyCol+1)); pIdx->aiRowLogEst = (LogEst*)zExtra; zExtra += sizeof(LogEst)*N; memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn); pIdx->aiColumn = (i16*)zExtra; zExtra += sizeof(i16)*N; memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn); pIdx->aSortOrder = (u8*)zExtra; pIdx->nColumn = N; pIdx->isResized = 1; return SQLITE_OK; } /* ** Estimate the total row width for a table. */ static void estimateTableWidth(Table *pTab){ unsigned wTable = 0; const Column *pTabCol; int i; for(i=pTab->nCol, pTabCol=pTab->aCol; i>0; i--, pTabCol++){ wTable += pTabCol->szEst; } if( pTab->iPKey<0 ) wTable++; pTab->szTabRow = sqlite3LogEst(wTable*4); } /* ** Estimate the average size of a row for an index. */ static void estimateIndexWidth(Index *pIdx){ unsigned wIndex = 0; int i; const Column *aCol = pIdx->pTable->aCol; for(i=0; inColumn; i++){ i16 x = pIdx->aiColumn[i]; assert( xpTable->nCol ); wIndex += x<0 ? 1 : aCol[x].szEst; } pIdx->szIdxRow = sqlite3LogEst(wIndex*4); } /* Return true if column number x is any of the first nCol entries of aiCol[]. ** This is used to determine if the column number x appears in any of the ** first nCol entries of an index. */ static int hasColumn(const i16 *aiCol, int nCol, int x){ while( nCol-- > 0 ){ if( x==*(aiCol++) ){ return 1; } } return 0; } /* ** Return true if any of the first nKey entries of index pIdx exactly ** match the iCol-th entry of pPk. pPk is always a WITHOUT ROWID ** PRIMARY KEY index. pIdx is an index on the same table. pIdx may ** or may not be the same index as pPk. ** ** The first nKey entries of pIdx are guaranteed to be ordinary columns, ** not a rowid or expression. ** ** This routine differs from hasColumn() in that both the column and the ** collating sequence must match for this routine, but for hasColumn() only ** the column name must match. */ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){ int i, j; assert( nKey<=pIdx->nColumn ); assert( iColnColumn,pPk->nKeyCol) ); assert( pPk->idxType==SQLITE_IDXTYPE_PRIMARYKEY ); assert( pPk->pTable->tabFlags & TF_WithoutRowid ); assert( pPk->pTable==pIdx->pTable ); testcase( pPk==pIdx ); j = pPk->aiColumn[iCol]; assert( j!=XN_ROWID && j!=XN_EXPR ); for(i=0; iaiColumn[i]>=0 || j>=0 ); if( pIdx->aiColumn[i]==j && sqlite3StrICmp(pIdx->azColl[i], pPk->azColl[iCol])==0 ){ return 1; } } return 0; } /* Recompute the colNotIdxed field of the Index. ** ** colNotIdxed is a bitmask that has a 0 bit representing each indexed ** columns that are within the first 63 columns of the table and a 1 for ** all other bits (all columns that are not in the index). The ** high-order bit of colNotIdxed is always 1. All unindexed columns ** of the table have a 1. ** ** 2019-10-24: For the purpose of this computation, virtual columns are ** not considered to be covered by the index, even if they are in the ** index, because we do not trust the logic in whereIndexExprTrans() to be ** able to find all instances of a reference to the indexed table column ** and convert them into references to the index. Hence we always want ** the actual table at hand in order to recompute the virtual column, if ** necessary. ** ** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask ** to determine if the index is covering index. */ static void recomputeColumnsNotIndexed(Index *pIdx){ Bitmask m = 0; int j; Table *pTab = pIdx->pTable; for(j=pIdx->nColumn-1; j>=0; j--){ int x = pIdx->aiColumn[j]; if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){ testcase( x==BMS-1 ); testcase( x==BMS-2 ); if( xcolNotIdxed = ~m; assert( (pIdx->colNotIdxed>>63)==1 ); /* See note-20221022-a */ } /* ** This routine runs at the end of parsing a CREATE TABLE statement that ** has a WITHOUT ROWID clause. The job of this routine is to convert both ** internal schema data structures and the generated VDBE code so that they ** are appropriate for a WITHOUT ROWID table instead of a rowid table. ** Changes include: ** ** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL. ** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY ** into BTREE_BLOBKEY. ** (3) Bypass the creation of the sqlite_schema table entry ** for the PRIMARY KEY as the primary key index is now ** identified by the sqlite_schema table entry of the table itself. ** (4) Set the Index.tnum of the PRIMARY KEY Index object in the ** schema to the rootpage from the main table. ** (5) Add all table columns to the PRIMARY KEY Index object ** so that the PRIMARY KEY is a covering index. The surplus ** columns are part of KeyInfo.nAllField and are not used for ** sorting or lookup or uniqueness checks. ** (6) Replace the rowid tail on all automatically generated UNIQUE ** indices with the PRIMARY KEY columns. ** ** For virtual tables, only (1) is performed. */ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ Index *pIdx; Index *pPk; int nPk; int nExtra; int i, j; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables) */ if( !db->init.imposterTable ){ for(i=0; inCol; i++){ if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 && (pTab->aCol[i].notNull==OE_None) ){ pTab->aCol[i].notNull = OE_Abort; } } pTab->tabFlags |= TF_HasNotNull; } /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY ** into BTREE_BLOBKEY. */ assert( !pParse->bReturning ); if( pParse->u1.addrCrTab ){ assert( v ); sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY); } /* Locate the PRIMARY KEY index. Or, if this table was originally ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index. */ if( pTab->iPKey>=0 ){ ExprList *pList; Token ipkToken; sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zCnName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ){ pTab->tabFlags &= ~TF_WithoutRowid; return; } if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey); } pList->a[0].fg.sortFlags = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); pTab->iPKey = -1; sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); if( pParse->nErr ){ pTab->tabFlags &= ~TF_WithoutRowid; return; } assert( db->mallocFailed==0 ); pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk->nKeyCol==1 ); }else{ pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); /* ** Remove all redundant columns from the PRIMARY KEY. For example, change ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later ** code assumes the PRIMARY KEY contains no repeated columns. */ for(i=j=1; inKeyCol; i++){ if( isDupColumn(pPk, j, pPk, i) ){ pPk->nColumn--; }else{ testcase( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ); pPk->azColl[j] = pPk->azColl[i]; pPk->aSortOrder[j] = pPk->aSortOrder[i]; pPk->aiColumn[j++] = pPk->aiColumn[i]; } } pPk->nKeyCol = j; } assert( pPk!=0 ); pPk->isCovering = 1; if( !db->init.imposterTable ) pPk->uniqNotNull = 1; nPk = pPk->nColumn = pPk->nKeyCol; /* Bypass the creation of the PRIMARY KEY btree and the sqlite_schema ** table entry. This is only required if currently generating VDBE ** code for a CREATE TABLE (not when parsing one as part of reading ** a database schema). */ if( v && pPk->tnum>0 ){ assert( db->init.busy==0 ); sqlite3VdbeChangeOpcode(v, (int)pPk->tnum, OP_Goto); } /* The root page of the PRIMARY KEY is the table root page */ pPk->tnum = pTab->tnum; /* Update the in-memory representation of all UNIQUE indices by converting ** the final rowid column into one or more columns of the PRIMARY KEY. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int n; if( IsPrimaryKeyIndex(pIdx) ) continue; for(i=n=0; inKeyCol, pPk, i) ){ testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); n++; } } if( n==0 ){ /* This index is a superset of the primary key */ pIdx->nColumn = pIdx->nKeyCol; continue; } if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return; for(i=0, j=pIdx->nKeyCol; inKeyCol, pPk, i) ){ testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); pIdx->aiColumn[j] = pPk->aiColumn[i]; pIdx->azColl[j] = pPk->azColl[i]; if( pPk->aSortOrder[i] ){ /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */ pIdx->bAscKeyBug = 1; } j++; } } assert( pIdx->nColumn>=pIdx->nKeyCol+n ); assert( pIdx->nColumn>=j ); } /* Add all table columns to the PRIMARY KEY index */ nExtra = 0; for(i=0; inCol; i++){ if( !hasColumn(pPk->aiColumn, nPk, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++; } if( resizeIndexObject(db, pPk, nPk+nExtra) ) return; for(i=0, j=nPk; inCol; i++){ if( !hasColumn(pPk->aiColumn, j, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ assert( jnColumn ); pPk->aiColumn[j] = i; pPk->azColl[j] = sqlite3StrBINARY; j++; } } assert( pPk->nColumn==j ); assert( pTab->nNVCol<=j ); recomputeColumnsNotIndexed(pPk); } #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Return true if pTab is a virtual table and zName is a shadow table name ** for that virtual table. */ SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){ int nName; /* Length of zName */ Module *pMod; /* Module for the virtual table */ if( !IsVirtual(pTab) ) return 0; nName = sqlite3Strlen30(pTab->zName); if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0; if( zName[nName]!='_' ) return 0; pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]); if( pMod==0 ) return 0; if( pMod->pModule->iVersion<3 ) return 0; if( pMod->pModule->xShadowName==0 ) return 0; return pMod->pModule->xShadowName(zName+nName+1); } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Table pTab is a virtual table. If it the virtual table implementation ** exists and has an xShadowName method, then loop over all other ordinary ** tables within the same schema looking for shadow tables of pTab, and mark ** any shadow tables seen using the TF_Shadow flag. */ SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){ int nName; /* Length of pTab->zName */ Module *pMod; /* Module for the virtual table */ HashElem *k; /* For looping through the symbol table */ assert( IsVirtual(pTab) ); pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]); if( pMod==0 ) return; if( NEVER(pMod->pModule==0) ) return; if( pMod->pModule->iVersion<3 ) return; if( pMod->pModule->xShadowName==0 ) return; assert( pTab->zName!=0 ); nName = sqlite3Strlen30(pTab->zName); for(k=sqliteHashFirst(&pTab->pSchema->tblHash); k; k=sqliteHashNext(k)){ Table *pOther = sqliteHashData(k); assert( pOther->zName!=0 ); if( !IsOrdinaryTable(pOther) ) continue; if( pOther->tabFlags & TF_Shadow ) continue; if( sqlite3StrNICmp(pOther->zName, pTab->zName, nName)==0 && pOther->zName[nName]=='_' && pMod->pModule->xShadowName(pOther->zName+nName+1) ){ pOther->tabFlags |= TF_Shadow; } } } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Return true if zName is a shadow table name in the current database ** connection. ** ** zName is temporarily modified while this routine is running, but is ** restored to its original value prior to this routine returning. */ SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){ char *zTail; /* Pointer to the last "_" in zName */ Table *pTab; /* Table that zName is a shadow of */ zTail = strrchr(zName, '_'); if( zTail==0 ) return 0; *zTail = 0; pTab = sqlite3FindTable(db, zName, 0); *zTail = '_'; if( pTab==0 ) return 0; if( !IsVirtual(pTab) ) return 0; return sqlite3IsShadowTableOf(db, pTab, zName); } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ #ifdef SQLITE_DEBUG /* ** Mark all nodes of an expression as EP_Immutable, indicating that ** they should not be changed. Expressions attached to a table or ** index definition are tagged this way to help ensure that we do ** not pass them into code generator routines by mistake. */ static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){ (void)pWalker; ExprSetVVAProperty(pExpr, EP_Immutable); return WRC_Continue; } static void markExprListImmutable(ExprList *pList){ if( pList ){ Walker w; memset(&w, 0, sizeof(w)); w.xExprCallback = markImmutableExprStep; w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback2 = 0; sqlite3WalkExprList(&w, pList); } } #else #define markExprListImmutable(X) /* no-op */ #endif /* SQLITE_DEBUG */ /* ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. ** ** The table structure that other action routines have been building ** is added to the internal hash tables, assuming no errors have ** occurred. ** ** An entry for the table is made in the schema table on disk, unless ** this is a temporary table or db->init.busy==1. When db->init.busy==1 ** it means we are reading the sqlite_schema table because we just ** connected to the database or because the sqlite_schema table has ** recently changed, so the entry for this table already exists in ** the sqlite_schema table. We do not want to create it again. ** ** If the pSelect argument is not NULL, it means that this routine ** was called to create a table generated from a ** "CREATE TABLE ... AS SELECT ..." statement. The column names of ** the new table will match the result set of the SELECT. */ SQLITE_PRIVATE void sqlite3EndTable( Parse *pParse, /* Parse context */ Token *pCons, /* The ',' token after the last column defn. */ Token *pEnd, /* The ')' before options in the CREATE TABLE */ u32 tabOpts, /* Extra table options. Usually 0. */ Select *pSelect /* Select from a "CREATE ... AS SELECT" */ ){ Table *p; /* The new table */ sqlite3 *db = pParse->db; /* The database connection */ int iDb; /* Database in which the table lives */ Index *pIdx; /* An implied index of the table */ if( pEnd==0 && pSelect==0 ){ return; } p = pParse->pNewTable; if( p==0 ) return; if( pSelect==0 && sqlite3ShadowTableName(db, p->zName) ){ p->tabFlags |= TF_Shadow; } /* If the db->init.busy is 1 it means we are reading the SQL off the ** "sqlite_schema" or "sqlite_temp_schema" table on the disk. ** So do not write to the disk again. Extract the root page number ** for the table from the db->init.newTnum field. (The page number ** should have been put there by the sqliteOpenCb routine.) ** ** If the root page number is 1, that means this is the sqlite_schema ** table itself. So mark it read-only. */ if( db->init.busy ){ if( pSelect || (!IsOrdinaryTable(p) && db->init.newTnum) ){ sqlite3ErrorMsg(pParse, ""); return; } p->tnum = db->init.newTnum; if( p->tnum==1 ) p->tabFlags |= TF_Readonly; } /* Special processing for tables that include the STRICT keyword: ** ** * Do not allow custom column datatypes. Every column must have ** a datatype that is one of INT, INTEGER, REAL, TEXT, or BLOB. ** ** * If a PRIMARY KEY is defined, other than the INTEGER PRIMARY KEY, ** then all columns of the PRIMARY KEY must have a NOT NULL ** constraint. */ if( tabOpts & TF_Strict ){ int ii; p->tabFlags |= TF_Strict; for(ii=0; iinCol; ii++){ Column *pCol = &p->aCol[ii]; if( pCol->eCType==COLTYPE_CUSTOM ){ if( pCol->colFlags & COLFLAG_HASTYPE ){ sqlite3ErrorMsg(pParse, "unknown datatype for %s.%s: \"%s\"", p->zName, pCol->zCnName, sqlite3ColumnType(pCol, "") ); }else{ sqlite3ErrorMsg(pParse, "missing datatype for %s.%s", p->zName, pCol->zCnName); } return; }else if( pCol->eCType==COLTYPE_ANY ){ pCol->affinity = SQLITE_AFF_BLOB; } if( (pCol->colFlags & COLFLAG_PRIMKEY)!=0 && p->iPKey!=ii && pCol->notNull == OE_None ){ pCol->notNull = OE_Abort; p->tabFlags |= TF_HasNotNull; } } } assert( (p->tabFlags & TF_HasPrimaryKey)==0 || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 ); assert( (p->tabFlags & TF_HasPrimaryKey)!=0 || (p->iPKey<0 && sqlite3PrimaryKeyIndex(p)==0) ); /* Special processing for WITHOUT ROWID Tables */ if( tabOpts & TF_WithoutRowid ){ if( (p->tabFlags & TF_Autoincrement) ){ sqlite3ErrorMsg(pParse, "AUTOINCREMENT not allowed on WITHOUT ROWID tables"); return; } if( (p->tabFlags & TF_HasPrimaryKey)==0 ){ sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName); return; } p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid; convertToWithoutRowidTable(pParse, p); } iDb = sqlite3SchemaToIndex(db, p->pSchema); #ifndef SQLITE_OMIT_CHECK /* Resolve names in all CHECK constraint expressions. */ if( p->pCheck ){ sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck); if( pParse->nErr ){ /* If errors are seen, delete the CHECK constraints now, else they might ** actually be used if PRAGMA writable_schema=ON is set. */ sqlite3ExprListDelete(db, p->pCheck); p->pCheck = 0; }else{ markExprListImmutable(p->pCheck); } } #endif /* !defined(SQLITE_OMIT_CHECK) */ #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( p->tabFlags & TF_HasGenerated ){ int ii, nNG = 0; testcase( p->tabFlags & TF_HasVirtual ); testcase( p->tabFlags & TF_HasStored ); for(ii=0; iinCol; ii++){ u32 colFlags = p->aCol[ii].colFlags; if( (colFlags & COLFLAG_GENERATED)!=0 ){ Expr *pX = sqlite3ColumnExpr(p, &p->aCol[ii]); testcase( colFlags & COLFLAG_VIRTUAL ); testcase( colFlags & COLFLAG_STORED ); if( sqlite3ResolveSelfReference(pParse, p, NC_GenCol, pX, 0) ){ /* If there are errors in resolving the expression, change the ** expression to a NULL. This prevents code generators that operate ** on the expression from inserting extra parts into the expression ** tree that have been allocated from lookaside memory, which is ** illegal in a schema and will lead to errors or heap corruption ** when the database connection closes. */ sqlite3ColumnSetExpr(pParse, p, &p->aCol[ii], sqlite3ExprAlloc(db, TK_NULL, 0, 0)); } }else{ nNG++; } } if( nNG==0 ){ sqlite3ErrorMsg(pParse, "must have at least one non-generated column"); return; } } #endif /* Estimate the average row size for the table and for all implied indices */ estimateTableWidth(p); for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ estimateIndexWidth(pIdx); } /* If not initializing, then create a record for the new table ** in the schema table of the database. ** ** If this is a TEMPORARY table, write the entry into the auxiliary ** file instead of into the main database file. */ if( !db->init.busy ){ int n; Vdbe *v; char *zType; /* "view" or "table" */ char *zType2; /* "VIEW" or "TABLE" */ char *zStmt; /* Text of the CREATE TABLE or CREATE VIEW statement */ v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return; sqlite3VdbeAddOp1(v, OP_Close, 0); /* ** Initialize zType for the new view or table. */ if( IsOrdinaryTable(p) ){ /* A regular table */ zType = "table"; zType2 = "TABLE"; #ifndef SQLITE_OMIT_VIEW }else{ /* A view */ zType = "view"; zType2 = "VIEW"; #endif } /* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT ** statement to populate the new table. The root-page number for the ** new table is in register pParse->regRoot. ** ** Once the SELECT has been coded by sqlite3Select(), it is in a ** suitable state to query for the column names and types to be used ** by the new table. ** ** A shared-cache write-lock is not required to write to the new table, ** as a schema-lock must have already been obtained to create it. Since ** a schema-lock excludes all other database users, the write-lock would ** be redundant. */ if( pSelect ){ SelectDest dest; /* Where the SELECT should store results */ int regYield; /* Register holding co-routine entry-point */ int addrTop; /* Top of the co-routine */ int regRec; /* A record to be insert into the new table */ int regRowid; /* Rowid of the next row to insert */ int addrInsLoop; /* Top of the loop for inserting rows */ Table *pSelTab; /* A table that describes the SELECT results */ if( IN_SPECIAL_PARSE ){ pParse->rc = SQLITE_ERROR; pParse->nErr++; return; } regYield = ++pParse->nMem; regRec = ++pParse->nMem; regRowid = ++pParse->nMem; assert(pParse->nTab==1); sqlite3MayAbort(pParse); sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb); sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); pParse->nTab = 2; addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); if( pParse->nErr ) return; pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect, SQLITE_AFF_BLOB); if( pSelTab==0 ) return; assert( p->aCol==0 ); p->nCol = p->nNVCol = pSelTab->nCol; p->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; sqlite3DeleteTable(db, pSelTab); sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); sqlite3Select(pParse, pSelect, &dest); if( pParse->nErr ) return; sqlite3VdbeEndCoroutine(v, regYield); sqlite3VdbeJumpHere(v, addrTop - 1); addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec); sqlite3TableAffinity(v, p, 0); sqlite3VdbeAddOp2(v, OP_NewRowid, 1, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid); sqlite3VdbeGoto(v, addrInsLoop); sqlite3VdbeJumpHere(v, addrInsLoop); sqlite3VdbeAddOp1(v, OP_Close, 1); } /* Compute the complete text of the CREATE statement */ if( pSelect ){ zStmt = createTableStmt(db, p); }else{ Token *pEnd2 = tabOpts ? &pParse->sLastToken : pEnd; n = (int)(pEnd2->z - pParse->sNameToken.z); if( pEnd2->z[0]!=';' ) n += pEnd2->n; zStmt = sqlite3MPrintf(db, "CREATE %s %.*s", zType2, n, pParse->sNameToken.z ); } /* A slot for the record has already been allocated in the ** schema table. We just need to update that slot with all ** the information we've collected. */ sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q" " WHERE rowid=#%d", db->aDb[iDb].zDbSName, zType, p->zName, p->zName, pParse->regRoot, zStmt, pParse->regRowid ); sqlite3DbFree(db, zStmt); sqlite3ChangeCookie(pParse, iDb); #ifndef SQLITE_OMIT_AUTOINCREMENT /* Check to see if we need to create an sqlite_sequence table for ** keeping track of autoincrement keys. */ if( (p->tabFlags & TF_Autoincrement)!=0 && !IN_SPECIAL_PARSE ){ Db *pDb = &db->aDb[iDb]; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( pDb->pSchema->pSeqTab==0 ){ sqlite3NestedParse(pParse, "CREATE TABLE %Q.sqlite_sequence(name,seq)", pDb->zDbSName ); } } #endif /* Reparse everything to update our internal data structures */ sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0); /* Test for cycles in generated columns and illegal expressions ** in CHECK constraints and in DEFAULT clauses. */ if( p->tabFlags & TF_HasGenerated ){ sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0, sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"", db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC); } sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0, sqlite3MPrintf(db, "PRAGMA \"%w\".integrity_check(%Q)", db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC); } /* Add the table to the in-memory representation of the database. */ if( db->init.busy ){ Table *pOld; Schema *pSchema = p->pSchema; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); assert( HasRowid(p) || p->iPKey<0 ); pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ sqlite3OomFault(db); return; } pParse->pNewTable = 0; db->mDbFlags |= DBFLAG_SchemaChange; /* If this is the magic sqlite_sequence table used by autoincrement, ** then record a pointer to this table in the main database structure ** so that INSERT can find the table easily. */ assert( !pParse->nested ); #ifndef SQLITE_OMIT_AUTOINCREMENT if( strcmp(p->zName, "sqlite_sequence")==0 ){ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); p->pSchema->pSeqTab = p; } #endif } #ifndef SQLITE_OMIT_ALTERTABLE if( !pSelect && IsOrdinaryTable(p) ){ assert( pCons && pEnd ); if( pCons->z==0 ){ pCons = pEnd; } p->u.tab.addColOffset = 13 + (int)(pCons->z - pParse->sNameToken.z); } #endif } #ifndef SQLITE_OMIT_VIEW /* ** The parser calls this routine in order to create a new VIEW */ SQLITE_PRIVATE void sqlite3CreateView( Parse *pParse, /* The parsing context */ Token *pBegin, /* The CREATE token that begins the statement */ Token *pName1, /* The token that holds the name of the view */ Token *pName2, /* The token that holds the name of the view */ ExprList *pCNames, /* Optional list of view column names */ Select *pSelect, /* A SELECT statement that will become the new view */ int isTemp, /* TRUE for a TEMPORARY view */ int noErr /* Suppress error messages if VIEW already exists */ ){ Table *p; int n; const char *z; Token sEnd; DbFixer sFix; Token *pName = 0; int iDb; sqlite3 *db = pParse->db; if( pParse->nVar>0 ){ sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); goto create_view_fail; } sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); p = pParse->pNewTable; if( p==0 || pParse->nErr ) goto create_view_fail; /* Legacy versions of SQLite allowed the use of the magic "rowid" column ** on a view, even though views do not have rowids. The following flag ** setting fixes this problem. But the fix can be disabled by compiling ** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that ** depend upon the old buggy behavior. */ #ifndef SQLITE_ALLOW_ROWID_IN_VIEW p->tabFlags |= TF_NoVisibleRowid; #endif sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; /* Make a copy of the entire SELECT statement that defines the view. ** This will force all the Expr.token.z values to be dynamically ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ pSelect->selFlags |= SF_View; if( IN_RENAME_OBJECT ){ p->u.view.pSelect = pSelect; pSelect = 0; }else{ p->u.view.pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); } p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); p->eTabType = TABTYP_VIEW; if( db->mallocFailed ) goto create_view_fail; /* Locate the end of the CREATE VIEW statement. Make sEnd point to ** the end. */ sEnd = pParse->sLastToken; assert( sEnd.z[0]!=0 || sEnd.n==0 ); if( sEnd.z[0]!=';' ){ sEnd.z += sEnd.n; } sEnd.n = 0; n = (int)(sEnd.z - pBegin->z); assert( n>0 ); z = pBegin->z; while( sqlite3Isspace(z[n-1]) ){ n--; } sEnd.z = &z[n-1]; sEnd.n = 1; /* Use sqlite3EndTable() to add the view to the schema table */ sqlite3EndTable(pParse, 0, &sEnd, 0, 0); create_view_fail: sqlite3SelectDelete(db, pSelect); if( IN_RENAME_OBJECT ){ sqlite3RenameExprlistUnmap(pParse, pCNames); } sqlite3ExprListDelete(db, pCNames); return; } #endif /* SQLITE_OMIT_VIEW */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) /* ** The Table structure pTable is really a VIEW. Fill in the names of ** the columns of the view in the pTable structure. Return the number ** of errors. If an error is seen leave an error message in pParse->zErrMsg. */ static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){ Table *pSelTab; /* A fake table from which we get the result set */ Select *pSel; /* Copy of the SELECT that implements the view */ int nErr = 0; /* Number of errors encountered */ sqlite3 *db = pParse->db; /* Database connection for malloc errors */ #ifndef SQLITE_OMIT_VIRTUALTABLE int rc; #endif #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth; /* Saved xAuth pointer */ #endif assert( pTable ); #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTable) ){ db->nSchemaLock++; rc = sqlite3VtabCallConnect(pParse, pTable); db->nSchemaLock--; return rc; } #endif #ifndef SQLITE_OMIT_VIEW /* A positive nCol means the columns names for this view are ** already known. This routine is not called unless either the ** table is virtual or nCol is zero. */ assert( pTable->nCol<=0 ); /* A negative nCol is a special marker meaning that we are currently ** trying to compute the column names. If we enter this routine with ** a negative nCol, it means two or more views form a loop, like this: ** ** CREATE VIEW one AS SELECT * FROM two; ** CREATE VIEW two AS SELECT * FROM one; ** ** Actually, the error above is now caught prior to reaching this point. ** But the following test is still important as it does come up ** in the following: ** ** CREATE TABLE main.ex1(a); ** CREATE TEMP VIEW ex1 AS SELECT a FROM ex1; ** SELECT * FROM temp.ex1; */ if( pTable->nCol<0 ){ sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName); return 1; } assert( pTable->nCol>=0 ); /* If we get this far, it means we need to compute the table names. ** Note that the call to sqlite3ResultSetOfSelect() will expand any ** "*" elements in the results set of the view and will assign cursors ** to the elements of the FROM clause. But we do not want these changes ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ assert( IsView(pTable) ); pSel = sqlite3SelectDup(db, pTable->u.view.pSelect, 0); if( pSel ){ u8 eParseMode = pParse->eParseMode; int nTab = pParse->nTab; int nSelect = pParse->nSelect; pParse->eParseMode = PARSE_MODE_NORMAL; sqlite3SrcListAssignCursors(pParse, pSel->pSrc); pTable->nCol = -1; DisableLookaside; #ifndef SQLITE_OMIT_AUTHORIZATION xAuth = db->xAuth; db->xAuth = 0; pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE); db->xAuth = xAuth; #else pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE); #endif pParse->nTab = nTab; pParse->nSelect = nSelect; if( pSelTab==0 ){ pTable->nCol = 0; nErr++; }else if( pTable->pCheck ){ /* CREATE VIEW name(arglist) AS ... ** The names of the columns in the table are taken from ** arglist which is stored in pTable->pCheck. The pCheck field ** normally holds CHECK constraints on an ordinary table, but for ** a VIEW it holds the list of column names. */ sqlite3ColumnsFromExprList(pParse, pTable->pCheck, &pTable->nCol, &pTable->aCol); if( pParse->nErr==0 && pTable->nCol==pSel->pEList->nExpr ){ assert( db->mallocFailed==0 ); sqlite3SubqueryColumnTypes(pParse, pTable, pSel, SQLITE_AFF_NONE); } }else{ /* CREATE VIEW name AS... without an argument list. Construct ** the column names from the SELECT statement that defines the view. */ assert( pTable->aCol==0 ); pTable->nCol = pSelTab->nCol; pTable->aCol = pSelTab->aCol; pTable->tabFlags |= (pSelTab->tabFlags & COLFLAG_NOINSERT); pSelTab->nCol = 0; pSelTab->aCol = 0; assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); } pTable->nNVCol = pTable->nCol; sqlite3DeleteTable(db, pSelTab); sqlite3SelectDelete(db, pSel); EnableLookaside; pParse->eParseMode = eParseMode; } else { nErr++; } pTable->pSchema->schemaFlags |= DB_UnresetViews; if( db->mallocFailed ){ sqlite3DeleteColumnNames(db, pTable); } #endif /* SQLITE_OMIT_VIEW */ return nErr; } SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ assert( pTable!=0 ); if( !IsVirtual(pTable) && pTable->nCol>0 ) return 0; return viewGetColumnNames(pParse, pTable); } #endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ #ifndef SQLITE_OMIT_VIEW /* ** Clear the column names from every VIEW in database idx. */ static void sqliteViewResetAll(sqlite3 *db, int idx){ HashElem *i; assert( sqlite3SchemaMutexHeld(db, idx, 0) ); if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); if( IsView(pTab) ){ sqlite3DeleteColumnNames(db, pTab); } } DbClearProperty(db, idx, DB_UnresetViews); } #else # define sqliteViewResetAll(A,B) #endif /* SQLITE_OMIT_VIEW */ /* ** This function is called by the VDBE to adjust the internal schema ** used by SQLite when the btree layer moves a table root page. The ** root-page of a table or index in database iDb has changed from iFrom ** to iTo. ** ** Ticket #1728: The symbol table might still contain information ** on tables and/or indices that are the process of being deleted. ** If you are unlucky, one of those deleted indices or tables might ** have the same rootpage number as the real table or index that is ** being moved. So we cannot stop searching after the first match ** because the first match might be for one of the deleted indices ** or tables and not the table/index that is actually being moved. ** We must continue looping until all tables and indices with ** rootpage==iFrom have been converted to have a rootpage of iTo ** in order to be certain that we got the right one. */ #ifndef SQLITE_OMIT_AUTOVACUUM SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){ HashElem *pElem; Hash *pHash; Db *pDb; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pDb = &db->aDb[iDb]; pHash = &pDb->pSchema->tblHash; for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); if( pTab->tnum==iFrom ){ pTab->tnum = iTo; } } pHash = &pDb->pSchema->idxHash; for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ Index *pIdx = sqliteHashData(pElem); if( pIdx->tnum==iFrom ){ pIdx->tnum = iTo; } } } #endif /* ** Write code to erase the table with root-page iTable from database iDb. ** Also write code to modify the sqlite_schema table and internal schema ** if a root-page of another table is moved by the btree-layer whilst ** erasing iTable (this can happen with an auto-vacuum database). */ static void destroyRootPage(Parse *pParse, int iTable, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); int r1 = sqlite3GetTempReg(pParse); if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema"); sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); sqlite3MayAbort(pParse); #ifndef SQLITE_OMIT_AUTOVACUUM /* OP_Destroy stores an in integer r1. If this integer ** is non-zero, then it is the root page number of a table moved to ** location iTable. The following code modifies the sqlite_schema table to ** reflect this. ** ** The "#NNN" in the SQL is a special constant that means whatever value ** is in register NNN. See grammar rules associated with the TK_REGISTER ** token for additional information. */ sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET rootpage=%d WHERE #%d AND rootpage=#%d", pParse->db->aDb[iDb].zDbSName, iTable, r1, r1); #endif sqlite3ReleaseTempReg(pParse, r1); } /* ** Write VDBE code to erase table pTab and all associated indices on disk. ** Code to update the sqlite_schema tables and internal schema definitions ** in case a root-page belonging to another table is moved by the btree layer ** is also added (this can happen with an auto-vacuum database). */ static void destroyTable(Parse *pParse, Table *pTab){ /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM ** is not defined), then it is important to call OP_Destroy on the ** table and index root-pages in order, starting with the numerically ** largest root-page number. This guarantees that none of the root-pages ** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the ** following were coded: ** ** OP_Destroy 4 0 ** ... ** OP_Destroy 5 0 ** ** and root page 5 happened to be the largest root-page number in the ** database, then root page 5 would be moved to page 4 by the ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit ** a free-list page. */ Pgno iTab = pTab->tnum; Pgno iDestroyed = 0; while( 1 ){ Index *pIdx; Pgno iLargest = 0; if( iDestroyed==0 || iTabpIndex; pIdx; pIdx=pIdx->pNext){ Pgno iIdx = pIdx->tnum; assert( pIdx->pSchema==pTab->pSchema ); if( (iDestroyed==0 || (iIdxiLargest ){ iLargest = iIdx; } } if( iLargest==0 ){ return; }else{ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); assert( iDb>=0 && iDbdb->nDb ); destroyRootPage(pParse, iLargest, iDb); iDestroyed = iLargest; } } } /* ** Remove entries from the sqlite_statN tables (for N in (1,2,3)) ** after a DROP INDEX or DROP TABLE command. */ static void sqlite3ClearStatTables( Parse *pParse, /* The parsing context */ int iDb, /* The database number */ const char *zType, /* "idx" or "tbl" */ const char *zName /* Name of index or table */ ){ int i; const char *zDbName = pParse->db->aDb[iDb].zDbSName; for(i=1; i<=4; i++){ char zTab[24]; sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i); if( sqlite3FindTable(pParse->db, zTab, zDbName) ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE %s=%Q", zDbName, zTab, zType, zName ); } } } /* ** Generate code to drop a table. */ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){ Vdbe *v; sqlite3 *db = pParse->db; Trigger *pTrigger; Db *pDb = &db->aDb[iDb]; v = sqlite3GetVdbe(pParse); assert( v!=0 ); sqlite3BeginWriteOperation(pParse, 1, iDb); #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3VdbeAddOp0(v, OP_VBegin); } #endif /* Drop all triggers associated with the table being dropped. Code ** is generated to remove entries from sqlite_schema and/or ** sqlite_temp_schema if required. */ pTrigger = sqlite3TriggerList(pParse, pTab); while( pTrigger ){ assert( pTrigger->pSchema==pTab->pSchema || pTrigger->pSchema==db->aDb[1].pSchema ); sqlite3DropTriggerPtr(pParse, pTrigger); pTrigger = pTrigger->pNext; } #ifndef SQLITE_OMIT_AUTOINCREMENT /* Remove any entries of the sqlite_sequence table associated with ** the table being dropped. This is done before the table is dropped ** at the btree level, in case the sqlite_sequence table needs to ** move as a result of the drop (can happen in auto-vacuum mode). */ if( pTab->tabFlags & TF_Autoincrement ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_sequence WHERE name=%Q", pDb->zDbSName, pTab->zName ); } #endif /* Drop all entries in the schema table that refer to the ** table. The program name loops through the schema table and deletes ** every row that refers to a table of the same name as the one being ** dropped. Triggers are handled separately because a trigger can be ** created in the temp database that refers to a table in another ** database. */ sqlite3NestedParse(pParse, "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE tbl_name=%Q and type!='trigger'", pDb->zDbSName, pTab->zName); if( !isView && !IsVirtual(pTab) ){ destroyTable(pParse, pTab); } /* Remove the table entry from SQLite's internal schema and modify ** the schema cookie. */ if( IsVirtual(pTab) ){ sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0); sqlite3MayAbort(pParse); } sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); sqlite3ChangeCookie(pParse, iDb); sqliteViewResetAll(db, iDb); } /* ** Return TRUE if shadow tables should be read-only in the current ** context. */ SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db){ #ifndef SQLITE_OMIT_VIRTUALTABLE if( (db->flags & SQLITE_Defensive)!=0 && db->pVtabCtx==0 && db->nVdbeExec==0 && !sqlite3VtabInSync(db) ){ return 1; } #endif return 0; } /* ** Return true if it is not allowed to drop the given table */ static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ if( sqlite3StrNICmp(pTab->zName+7, "stat", 4)==0 ) return 0; if( sqlite3StrNICmp(pTab->zName+7, "parameters", 10)==0 ) return 0; return 1; } if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){ return 1; } if( pTab->tabFlags & TF_Eponymous ){ return 1; } return 0; } /* ** This routine is called to do the work of a DROP TABLE statement. ** pName is the name of the table to be dropped. */ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ Table *pTab; Vdbe *v; sqlite3 *db = pParse->db; int iDb; if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; assert( isView==0 || isView==LOCATE_VIEW ); pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; if( pTab==0 ){ if( noErr ){ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); sqlite3ForceNotReadOnly(pParse); } goto exit_drop_table; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 && iDbnDb ); /* If pTab is a virtual table, call ViewGetColumnNames() to ensure ** it is initialized. */ if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){ goto exit_drop_table; } #ifndef SQLITE_OMIT_AUTHORIZATION { int code; const char *zTab = SCHEMA_TABLE(iDb); const char *zDb = db->aDb[iDb].zDbSName; const char *zArg2 = 0; if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ goto exit_drop_table; } if( isView ){ if( !OMIT_TEMPDB && iDb==1 ){ code = SQLITE_DROP_TEMP_VIEW; }else{ code = SQLITE_DROP_VIEW; } #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( IsVirtual(pTab) ){ code = SQLITE_DROP_VTABLE; zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName; #endif }else{ if( !OMIT_TEMPDB && iDb==1 ){ code = SQLITE_DROP_TEMP_TABLE; }else{ code = SQLITE_DROP_TABLE; } } if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){ goto exit_drop_table; } if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto exit_drop_table; } } #endif if( tableMayNotBeDropped(db, pTab) ){ sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); goto exit_drop_table; } #ifndef SQLITE_OMIT_VIEW /* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used ** on a table. */ if( isView && !IsView(pTab) ){ sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName); goto exit_drop_table; } if( !isView && IsView(pTab) ){ sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName); goto exit_drop_table; } #endif /* Generate code to remove the table from the schema table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); if( !isView ){ sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); sqlite3FkDropTable(pParse, pName, pTab); } sqlite3CodeDropTable(pParse, pTab, iDb, isView); } exit_drop_table: sqlite3SrcListDelete(db, pName); } /* ** This routine is called to create a new foreign key on the table ** currently under construction. pFromCol determines which columns ** in the current table point to the foreign key. If pFromCol==0 then ** connect the key to the last column inserted. pTo is the name of ** the table referred to (a.k.a the "parent" table). pToCol is a list ** of tables in the parent pTo table. flags contains all ** information about the conflict resolution algorithms specified ** in the ON DELETE, ON UPDATE and ON INSERT clauses. ** ** An FKey structure is created and added to the table currently ** under construction in the pParse->pNewTable field. ** ** The foreign key is set for IMMEDIATE processing. A subsequent call ** to sqlite3DeferForeignKey() might change this to DEFERRED. */ SQLITE_PRIVATE void sqlite3CreateForeignKey( Parse *pParse, /* Parsing context */ ExprList *pFromCol, /* Columns in this table that point to other table */ Token *pTo, /* Name of the other table */ ExprList *pToCol, /* Columns in the other table */ int flags /* Conflict resolution algorithms. */ ){ sqlite3 *db = pParse->db; #ifndef SQLITE_OMIT_FOREIGN_KEY FKey *pFKey = 0; FKey *pNextTo; Table *p = pParse->pNewTable; i64 nByte; int i; int nCol; char *z; assert( pTo!=0 ); if( p==0 || IN_DECLARE_VTAB ) goto fk_end; if( pFromCol==0 ){ int iCol = p->nCol-1; if( NEVER(iCol<0) ) goto fk_end; if( pToCol && pToCol->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "foreign key on %s" " should reference only one column of table %T", p->aCol[iCol].zCnName, pTo); goto fk_end; } nCol = 1; }else if( pToCol && pToCol->nExpr!=pFromCol->nExpr ){ sqlite3ErrorMsg(pParse, "number of columns in foreign key does not match the number of " "columns in the referenced table"); goto fk_end; }else{ nCol = pFromCol->nExpr; } nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1; if( pToCol ){ for(i=0; inExpr; i++){ nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1; } } pFKey = sqlite3DbMallocZero(db, nByte ); if( pFKey==0 ){ goto fk_end; } pFKey->pFrom = p; assert( IsOrdinaryTable(p) ); pFKey->pNextFrom = p->u.tab.pFKey; z = (char*)&pFKey->aCol[nCol]; pFKey->zTo = z; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)z, pTo); } memcpy(z, pTo->z, pTo->n); z[pTo->n] = 0; sqlite3Dequote(z); z += pTo->n+1; pFKey->nCol = nCol; if( pFromCol==0 ){ pFKey->aCol[0].iFrom = p->nCol-1; }else{ for(i=0; inCol; j++){ if( sqlite3StrICmp(p->aCol[j].zCnName, pFromCol->a[i].zEName)==0 ){ pFKey->aCol[i].iFrom = j; break; } } if( j>=p->nCol ){ sqlite3ErrorMsg(pParse, "unknown column \"%s\" in foreign key definition", pFromCol->a[i].zEName); goto fk_end; } if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zEName); } } } if( pToCol ){ for(i=0; ia[i].zEName); pFKey->aCol[i].zCol = z; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zEName); } memcpy(z, pToCol->a[i].zEName, n); z[n] = 0; z += n+1; } } pFKey->isDeferred = 0; pFKey->aAction[0] = (u8)(flags & 0xff); /* ON DELETE action */ pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); /* ON UPDATE action */ assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash, pFKey->zTo, (void *)pFKey ); if( pNextTo==pFKey ){ sqlite3OomFault(db); goto fk_end; } if( pNextTo ){ assert( pNextTo->pPrevTo==0 ); pFKey->pNextTo = pNextTo; pNextTo->pPrevTo = pFKey; } /* Link the foreign key to the table as the last step. */ assert( IsOrdinaryTable(p) ); p->u.tab.pFKey = pFKey; pFKey = 0; fk_end: sqlite3DbFree(db, pFKey); #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ sqlite3ExprListDelete(db, pFromCol); sqlite3ExprListDelete(db, pToCol); } /* ** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED ** clause is seen as part of a foreign key definition. The isDeferred ** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE. ** The behavior of the most recently created foreign key is adjusted ** accordingly. */ SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){ #ifndef SQLITE_OMIT_FOREIGN_KEY Table *pTab; FKey *pFKey; if( (pTab = pParse->pNewTable)==0 ) return; if( NEVER(!IsOrdinaryTable(pTab)) ) return; if( (pFKey = pTab->u.tab.pFKey)==0 ) return; assert( isDeferred==0 || isDeferred==1 ); /* EV: R-30323-21917 */ pFKey->isDeferred = (u8)isDeferred; #endif } /* ** Generate code that will erase and refill index *pIdx. This is ** used to initialize a newly created index or to recompute the ** content of an index in response to a REINDEX command. ** ** if memRootPage is not negative, it means that the index is newly ** created. The register specified by memRootPage contains the ** root page number of the index. If memRootPage is negative, then ** the index already exists and must be cleared before being refilled and ** the root page number of the index is taken from pIndex->tnum. */ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ Table *pTab = pIndex->pTable; /* The table that is indexed */ int iTab = pParse->nTab++; /* Btree cursor used for pTab */ int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */ int iSorter; /* Cursor opened by OpenSorter (if in use) */ int addr1; /* Address of top of loop */ int addr2; /* Address to jump to for next iteration */ Pgno tnum; /* Root page of index */ int iPartIdxLabel; /* Jump to this label to skip a row */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ int regRecord; /* Register holding assembled index record */ sqlite3 *db = pParse->db; /* The database connection */ int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, db->aDb[iDb].zDbSName ) ){ return; } #endif /* Require a write-lock on the table to perform this operation */ sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); v = sqlite3GetVdbe(pParse); if( v==0 ) return; if( memRootPage>=0 ){ tnum = (Pgno)memRootPage; }else{ tnum = pIndex->tnum; } pKey = sqlite3KeyInfoOfIndex(pParse, pIndex); assert( pKey!=0 || pParse->nErr ); /* Open the sorter cursor if we are to use one. */ iSorter = pParse->nTab++; sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*) sqlite3KeyInfoRef(pKey), P4_KEYINFO); /* Open the table. Loop through all rows of the table, inserting index ** records into the sorter. */ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v); regRecord = sqlite3GetTempReg(pParse); sqlite3MultiWrite(pParse); sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, (int)tnum, iDb, (char *)pKey, P4_KEYINFO); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); if( IsUniqueIndex(pIndex) ){ int j2 = sqlite3VdbeGoto(v, 1); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeVerifyAbortable(v, OE_Abort); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); sqlite3VdbeJumpHere(v, j2); }else{ /* Most CREATE INDEX and REINDEX statements that are not UNIQUE can not ** abort. The exception is if one of the indexed expressions contains a ** user function that throws an exception when it is evaluated. But the ** overhead of adding a statement journal to a CREATE INDEX statement is ** very small (since most of the pages written do not contain content that ** needs to be restored if the statement aborts), so we call ** sqlite3MayAbort() for all CREATE INDEX statements. */ sqlite3MayAbort(pParse); addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); if( !pIndex->bAscKeyBug ){ /* This OP_SeekEnd opcode makes index insert for a REINDEX go much ** faster by avoiding unnecessary seeks. But the optimization does ** not work for UNIQUE constraint indexes on WITHOUT ROWID tables ** with DESC primary keys, since those indexes have there keys in ** a different order from the main table. ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf */ sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); } sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_Close, iTab); sqlite3VdbeAddOp1(v, OP_Close, iIdx); sqlite3VdbeAddOp1(v, OP_Close, iSorter); } /* ** Allocate heap space to hold an Index object with nCol columns. ** ** Increase the allocation size to provide an extra nExtra bytes ** of 8-byte aligned space after the Index object and return a ** pointer to this extra space in *ppExtra. */ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( sqlite3 *db, /* Database connection */ i16 nCol, /* Total number of columns in the index */ int nExtra, /* Number of bytes of extra space to alloc */ char **ppExtra /* Pointer to the "extra" space */ ){ Index *p; /* Allocated index object */ int nByte; /* Bytes of space for Index object + arrays */ nByte = ROUND8(sizeof(Index)) + /* Index structure */ ROUND8(sizeof(char*)*nCol) + /* Index.azColl */ ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */ sizeof(i16)*nCol + /* Index.aiColumn */ sizeof(u8)*nCol); /* Index.aSortOrder */ p = sqlite3DbMallocZero(db, nByte + nExtra); if( p ){ char *pExtra = ((char*)p)+ROUND8(sizeof(Index)); p->azColl = (const char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol); p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1); p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; p->aSortOrder = (u8*)pExtra; p->nColumn = nCol; p->nKeyCol = nCol - 1; *ppExtra = ((char*)p) + nByte; } return p; } /* ** If expression list pList contains an expression that was parsed with ** an explicit "NULLS FIRST" or "NULLS LAST" clause, leave an error in ** pParse and return non-zero. Otherwise, return zero. */ SQLITE_PRIVATE int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){ if( pList ){ int i; for(i=0; inExpr; i++){ if( pList->a[i].fg.bNulls ){ u8 sf = pList->a[i].fg.sortFlags; sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s", (sf==0 || sf==3) ? "FIRST" : "LAST" ); return 1; } } } return 0; } /* ** Create a new index for an SQL table. pName1.pName2 is the name of the index ** and pTblList is the name of the table that is to be indexed. Both will ** be NULL for a primary key or an index that is created to satisfy a ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable ** as the table to be indexed. pParse->pNewTable is a table that is ** currently being constructed by a CREATE TABLE statement. ** ** pList is a list of columns to be indexed. pList will be NULL if this ** is a primary key or unique-constraint on the most recent column added ** to the table currently under construction. */ SQLITE_PRIVATE void sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ Token *pName1, /* First part of index name. May be NULL */ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ ExprList *pList, /* A list of columns to be indexed */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ Token *pStart, /* The CREATE token that begins this statement */ Expr *pPIWhere, /* WHERE clause for partial indices */ int sortOrder, /* Sort order of primary key when pList==NULL */ int ifNotExist, /* Omit error if index already exists */ u8 idxType /* The index type */ ){ Table *pTab = 0; /* Table to be indexed */ Index *pIndex = 0; /* The index to be created */ char *zName = 0; /* Name of the index */ int nName; /* Number of characters in zName */ int i, j; DbFixer sFix; /* For assigning database names to pTable */ int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */ sqlite3 *db = pParse->db; Db *pDb; /* The specific table containing the indexed database */ int iDb; /* Index of the database that is being written */ Token *pName = 0; /* Unqualified name of the index to create */ struct ExprList_item *pListItem; /* For looping over pList */ int nExtra = 0; /* Space allocated for zExtra[] */ int nExtraCol; /* Number of extra columns needed */ char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ assert( db->pParse==pParse ); if( pParse->nErr ){ goto exit_create_index; } assert( db->mallocFailed==0 ); if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_create_index; } if( sqlite3HasExplicitNulls(pParse, pList) ){ goto exit_create_index; } /* ** Find the table that is to be indexed. Return early if not found. */ if( pTblName!=0 ){ /* Use the two-part index name to determine the database ** to search for the table. 'Fix' the table name to this db ** before looking up the table. */ assert( pName1 && pName2 ); iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); if( iDb<0 ) goto exit_create_index; assert( pName && pName->z ); #ifndef SQLITE_OMIT_TEMPDB /* If the index name was unqualified, check if the table ** is a temp table. If so, set the database to 1. Do not do this ** if initializing a database schema. */ if( !db->init.busy ){ pTab = sqlite3SrcListLookup(pParse, pTblName); if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ iDb = 1; } } #endif sqlite3FixInit(&sFix, pParse, iDb, "index", pName); if( sqlite3FixSrcList(&sFix, pTblName) ){ /* Because the parser constructs pTblName from a single identifier, ** sqlite3FixSrcList can never fail. */ assert(0); } pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]); assert( db->mallocFailed==0 || pTab==0 ); if( pTab==0 ) goto exit_create_index; if( iDb==1 && db->aDb[iDb].pSchema!=pTab->pSchema ){ sqlite3ErrorMsg(pParse, "cannot create a TEMP index on non-TEMP table \"%s\"", pTab->zName); goto exit_create_index; } if( !HasRowid(pTab) ) pPk = sqlite3PrimaryKeyIndex(pTab); }else{ assert( pName==0 ); assert( pStart==0 ); pTab = pParse->pNewTable; if( !pTab ) goto exit_create_index; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); } pDb = &db->aDb[iDb]; assert( pTab!=0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 && pTblName!=0 #if SQLITE_USER_AUTHENTICATION && sqlite3UserAuthTable(pTab->zName)==0 #endif ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; } #ifndef SQLITE_OMIT_VIEW if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "views may not be indexed"); goto exit_create_index; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "virtual tables may not be indexed"); goto exit_create_index; } #endif /* ** Find the name of the index. Make sure there is not already another ** index or table with the same name. ** ** Exception: If we are reading the names of permanent indices from the ** sqlite_schema table (because some other process changed the schema) and ** one of the index names collides with the name of a temporary table or ** index, then we will continue to process this index. ** ** If pName==0 it means that we are ** dealing with a primary key or UNIQUE constraint. We have to invent our ** own name. */ if( pName ){ zName = sqlite3NameFromToken(db, pName); if( zName==0 ) goto exit_create_index; assert( pName->z!=0 ); if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName,"index",pTab->zName) ){ goto exit_create_index; } if( !IN_RENAME_OBJECT ){ if( !db->init.busy ){ if( sqlite3FindTable(db, zName, pDb->zDbSName)!=0 ){ sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); goto exit_create_index; } } if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ if( !ifNotExist ){ sqlite3ErrorMsg(pParse, "index %s already exists", zName); }else{ assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); sqlite3ForceNotReadOnly(pParse); } goto exit_create_index; } } }else{ int n; Index *pLoop; for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} zName = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n); if( zName==0 ){ goto exit_create_index; } /* Automatic index names generated from within sqlite3_declare_vtab() ** must have names that are distinct from normal automatic index names. ** The following statement converts "sqlite3_autoindex..." into ** "sqlite3_butoindex..." in order to make the names distinct. ** The "vtab_err.test" test demonstrates the need of this statement. */ if( IN_SPECIAL_PARSE ) zName[7]++; } /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION if( !IN_RENAME_OBJECT ){ const char *zDb = pDb->zDbSName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ goto exit_create_index; } i = SQLITE_CREATE_INDEX; if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX; if( sqlite3AuthCheck(pParse, i, zName, pTab->zName, zDb) ){ goto exit_create_index; } } #endif /* If pList==0, it means this routine was called to make a primary ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ Token prevCol; Column *pCol = &pTab->aCol[pTab->nCol-1]; pCol->colFlags |= COLFLAG_UNIQUE; sqlite3TokenInit(&prevCol, pCol->zCnName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); if( pList==0 ) goto exit_create_index; assert( pList->nExpr==1 ); sqlite3ExprListSetSortOrder(pList, sortOrder, SQLITE_SO_UNDEFINED); }else{ sqlite3ExprListCheckLength(pParse, pList, "index"); if( pParse->nErr ) goto exit_create_index; } /* Figure out how many bytes of space are required to store explicitly ** specified collation sequence names. */ for(i=0; inExpr; i++){ Expr *pExpr = pList->a[i].pExpr; assert( pExpr!=0 ); if( pExpr->op==TK_COLLATE ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); } } /* ** Allocate the index structure. */ nName = sqlite3Strlen30(zName); nExtraCol = pPk ? pPk->nKeyCol : 1; assert( pList->nExpr + nExtraCol <= 32767 /* Fits in i16 */ ); pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol, nName + nExtra + 1, &zExtra); if( db->mallocFailed ){ goto exit_create_index; } assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) ); assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) ); pIndex->zName = zExtra; zExtra += nName + 1; memcpy(pIndex->zName, zName, nName+1); pIndex->pTable = pTab; pIndex->onError = (u8)onError; pIndex->uniqNotNull = onError!=OE_None; pIndex->idxType = idxType; pIndex->pSchema = db->aDb[iDb].pSchema; pIndex->nKeyCol = pList->nExpr; if( pPIWhere ){ sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0); pIndex->pPartIdxWhere = pPIWhere; pPIWhere = 0; } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); /* Check to see if we should honor DESC requests on index columns */ if( pDb->pSchema->file_format>=4 ){ sortOrderMask = -1; /* Honor DESC */ }else{ sortOrderMask = 0; /* Ignore DESC */ } /* Analyze the list of expressions that form the terms of the index and ** report any errors. In the common case where the expression is exactly ** a table column, store that column in aiColumn[]. For general expressions, ** populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[]. ** ** TODO: Issue a warning if two or more columns of the index are identical. ** TODO: Issue a warning if the table primary key is used as part of the ** index key. */ pListItem = pList->a; if( IN_RENAME_OBJECT ){ pIndex->aColExpr = pList; pList = 0; } for(i=0; inKeyCol; i++, pListItem++){ Expr *pCExpr; /* The i-th index expression */ int requestedSortOrder; /* ASC or DESC on the i-th expression */ const char *zColl; /* Collation sequence name */ sqlite3StringToId(pListItem->pExpr); sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0); if( pParse->nErr ) goto exit_create_index; pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); if( pCExpr->op!=TK_COLUMN ){ if( pTab==pParse->pNewTable ){ sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and " "UNIQUE constraints"); goto exit_create_index; } if( pIndex->aColExpr==0 ){ pIndex->aColExpr = pList; pList = 0; } j = XN_EXPR; pIndex->aiColumn[i] = XN_EXPR; pIndex->uniqNotNull = 0; pIndex->bHasExpr = 1; }else{ j = pCExpr->iColumn; assert( j<=0x7fff ); if( j<0 ){ j = pTab->iPKey; }else{ if( pTab->aCol[j].notNull==0 ){ pIndex->uniqNotNull = 0; } if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){ pIndex->bHasVCol = 1; pIndex->bHasExpr = 1; } } pIndex->aiColumn[i] = (i16)j; } zColl = 0; if( pListItem->pExpr->op==TK_COLLATE ){ int nColl; assert( !ExprHasProperty(pListItem->pExpr, EP_IntValue) ); zColl = pListItem->pExpr->u.zToken; nColl = sqlite3Strlen30(zColl) + 1; assert( nExtra>=nColl ); memcpy(zExtra, zColl, nColl); zColl = zExtra; zExtra += nColl; nExtra -= nColl; }else if( j>=0 ){ zColl = sqlite3ColumnColl(&pTab->aCol[j]); } if( !zColl ) zColl = sqlite3StrBINARY; if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ goto exit_create_index; } pIndex->azColl[i] = zColl; requestedSortOrder = pListItem->fg.sortFlags & sortOrderMask; pIndex->aSortOrder[i] = (u8)requestedSortOrder; } /* Append the table key to the end of the index. For WITHOUT ROWID ** tables (when pPk!=0) this will be the declared PRIMARY KEY. For ** normal tables (when pPk==0) this will be the rowid. */ if( pPk ){ for(j=0; jnKeyCol; j++){ int x = pPk->aiColumn[j]; assert( x>=0 ); if( isDupColumn(pIndex, pIndex->nKeyCol, pPk, j) ){ pIndex->nColumn--; }else{ testcase( hasColumn(pIndex->aiColumn,pIndex->nKeyCol,x) ); pIndex->aiColumn[i] = x; pIndex->azColl[i] = pPk->azColl[j]; pIndex->aSortOrder[i] = pPk->aSortOrder[j]; i++; } } assert( i==pIndex->nColumn ); }else{ pIndex->aiColumn[i] = XN_ROWID; pIndex->azColl[i] = sqlite3StrBINARY; } sqlite3DefaultRowEst(pIndex); if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex); /* If this index contains every column of its table, then mark ** it as a covering index */ assert( HasRowid(pTab) || pTab->iPKey<0 || sqlite3TableColumnToIndex(pIndex, pTab->iPKey)>=0 ); recomputeColumnsNotIndexed(pIndex); if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){ pIndex->isCovering = 1; for(j=0; jnCol; j++){ if( j==pTab->iPKey ) continue; if( sqlite3TableColumnToIndex(pIndex,j)>=0 ) continue; pIndex->isCovering = 0; break; } } if( pTab==pParse->pNewTable ){ /* This routine has been called to create an automatic index as a ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or ** a PRIMARY KEY or UNIQUE clause following the column definitions. ** i.e. one of: ** ** CREATE TABLE t(x PRIMARY KEY, y); ** CREATE TABLE t(x, y, UNIQUE(x, y)); ** ** Either way, check to see if the table already has such an index. If ** so, don't bother creating this one. This only applies to ** automatically created indices. Users can do as they wish with ** explicit indices. ** ** Two UNIQUE or PRIMARY KEY constraints are considered equivalent ** (and thus suppressing the second one) even if they have different ** sort orders. ** ** If there are different collating sequences or if the columns of ** the constraint occur in different orders, then the constraints are ** considered distinct and both result in separate indices. */ Index *pIdx; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int k; assert( IsUniqueIndex(pIdx) ); assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF ); assert( IsUniqueIndex(pIndex) ); if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue; for(k=0; knKeyCol; k++){ const char *z1; const char *z2; assert( pIdx->aiColumn[k]>=0 ); if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; z1 = pIdx->azColl[k]; z2 = pIndex->azColl[k]; if( sqlite3StrICmp(z1, z2) ) break; } if( k==pIdx->nKeyCol ){ if( pIdx->onError!=pIndex->onError ){ /* This constraint creates the same index as a previous ** constraint specified somewhere in the CREATE TABLE statement. ** However the ON CONFLICT clauses are different. If both this ** constraint and the previous equivalent constraint have explicit ** ON CONFLICT clauses this is an error. Otherwise, use the ** explicitly specified behavior for the index. */ if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){ sqlite3ErrorMsg(pParse, "conflicting ON CONFLICT clauses specified", 0); } if( pIdx->onError==OE_Default ){ pIdx->onError = pIndex->onError; } } if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; if( IN_RENAME_OBJECT ){ pIndex->pNext = pParse->pNewIndex; pParse->pNewIndex = pIndex; pIndex = 0; } goto exit_create_index; } } } if( !IN_RENAME_OBJECT ){ /* Link the new Index structure to its table and to the other ** in-memory database structures. */ assert( pParse->nErr==0 ); if( db->init.busy ){ Index *p; assert( !IN_SPECIAL_PARSE ); assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); if( pTblName!=0 ){ pIndex->tnum = db->init.newTnum; if( sqlite3IndexHasDuplicateRootPage(pIndex) ){ sqlite3ErrorMsg(pParse, "invalid rootpage"); pParse->rc = SQLITE_CORRUPT_BKPT; goto exit_create_index; } } p = sqlite3HashInsert(&pIndex->pSchema->idxHash, pIndex->zName, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ sqlite3OomFault(db); goto exit_create_index; } db->mDbFlags |= DBFLAG_SchemaChange; } /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then ** emit code to allocate the index rootpage on disk and make an entry for ** the index in the sqlite_schema table and populate the index with ** content. But, do not do this if we are simply reading the sqlite_schema ** table to parse the schema, or if this index is the PRIMARY KEY index ** of a WITHOUT ROWID table. ** ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY ** or UNIQUE index in a CREATE TABLE statement. Since the table ** has just been created, it contains no data and the index initialization ** step can be skipped. */ else if( HasRowid(pTab) || pTblName!=0 ){ Vdbe *v; char *zStmt; int iMem = ++pParse->nMem; v = sqlite3GetVdbe(pParse); if( v==0 ) goto exit_create_index; sqlite3BeginWriteOperation(pParse, 1, iDb); /* Create the rootpage for the index using CreateIndex. But before ** doing so, code a Noop instruction and store its address in ** Index.tnum. This is required in case this index is actually a ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In ** that case the convertToWithoutRowidTable() routine will replace ** the Noop with a Goto to jump over the VDBE code generated below. */ pIndex->tnum = (Pgno)sqlite3VdbeAddOp0(v, OP_Noop); sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY); /* Gather the complete text of the CREATE INDEX statement into ** the zStmt variable */ assert( pName!=0 || pStart==0 ); if( pStart ){ int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n; if( pName->z[n-1]==';' ) n--; /* A named index with an explicit CREATE INDEX statement */ zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", onError==OE_None ? "" : " UNIQUE", n, pName->z); }else{ /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ /* zStmt = sqlite3MPrintf(""); */ zStmt = 0; } /* Add an entry in sqlite_schema for this index */ sqlite3NestedParse(pParse, "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);", db->aDb[iDb].zDbSName, pIndex->zName, pTab->zName, iMem, zStmt ); sqlite3DbFree(db, zStmt); /* Fill the index with data and reparse the schema. Code an OP_Expire ** to invalidate all pre-compiled statements. */ if( pTblName ){ sqlite3RefillIndex(pParse, pIndex, iMem); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0); sqlite3VdbeAddOp2(v, OP_Expire, 0, 1); } sqlite3VdbeJumpHere(v, (int)pIndex->tnum); } } if( db->init.busy || pTblName==0 ){ pIndex->pNext = pTab->pIndex; pTab->pIndex = pIndex; pIndex = 0; } else if( IN_RENAME_OBJECT ){ assert( pParse->pNewIndex==0 ); pParse->pNewIndex = pIndex; pIndex = 0; } /* Clean up before exiting */ exit_create_index: if( pIndex ) sqlite3FreeIndex(db, pIndex); if( pTab ){ /* Ensure all REPLACE indexes on pTab are at the end of the pIndex list. ** The list was already ordered when this routine was entered, so at this ** point at most a single index (the newly added index) will be out of ** order. So we have to reorder at most one index. */ Index **ppFrom; Index *pThis; for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){ Index *pNext; if( pThis->onError!=OE_Replace ) continue; while( (pNext = pThis->pNext)!=0 && pNext->onError!=OE_Replace ){ *ppFrom = pNext; pThis->pNext = pNext->pNext; pNext->pNext = pThis; ppFrom = &pNext->pNext; } break; } #ifdef SQLITE_DEBUG /* Verify that all REPLACE indexes really are now at the end ** of the index list. In other words, no other index type ever ** comes after a REPLACE index on the list. */ for(pThis = pTab->pIndex; pThis; pThis=pThis->pNext){ assert( pThis->onError!=OE_Replace || pThis->pNext==0 || pThis->pNext->onError==OE_Replace ); } #endif } sqlite3ExprDelete(db, pPIWhere); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); } /* ** Fill the Index.aiRowEst[] array with default information - information ** to be used when we have not run the ANALYZE command. ** ** aiRowEst[0] is supposed to contain the number of elements in the index. ** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the ** number of rows in the table that match any particular value of the ** first column of the index. aiRowEst[2] is an estimate of the number ** of rows that match any particular combination of the first 2 columns ** of the index. And so forth. It must always be the case that * ** aiRowEst[N]<=aiRowEst[N-1] ** aiRowEst[N]>=1 ** ** Apart from that, we have little to go on besides intuition as to ** how aiRowEst[] should be initialized. The numbers generated here ** are based on typical values found in actual indices. */ SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){ /* 10, 9, 8, 7, 6 */ static const LogEst aVal[] = { 33, 32, 30, 28, 26 }; LogEst *a = pIdx->aiRowLogEst; LogEst x; int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; /* Indexes with default row estimates should not have stat1 data */ assert( !pIdx->hasStat1 ); /* Set the first entry (number of rows in the index) to the estimated ** number of rows in the table, or half the number of rows in the table ** for a partial index. ** ** 2020-05-27: If some of the stat data is coming from the sqlite_stat1 ** table but other parts we are having to guess at, then do not let the ** estimated number of rows in the table be less than 1000 (LogEst 99). ** Failure to do this can cause the indexes for which we do not have ** stat1 data to be ignored by the query planner. */ x = pIdx->pTable->nRowLogEst; assert( 99==sqlite3LogEst(1000) ); if( x<99 ){ pIdx->pTable->nRowLogEst = x = 99; } if( pIdx->pPartIdxWhere!=0 ){ x -= 10; assert( 10==sqlite3LogEst(2) ); } a[0] = x; /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is ** 6 and each subsequent value (if any) is 5. */ memcpy(&a[1], aVal, nCopy*sizeof(LogEst)); for(i=nCopy+1; i<=pIdx->nKeyCol; i++){ a[i] = 23; assert( 23==sqlite3LogEst(5) ); } assert( 0==sqlite3LogEst(1) ); if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0; } /* ** This routine will drop an existing named index. This routine ** implements the DROP INDEX statement. */ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ Index *pIndex; Vdbe *v; sqlite3 *db = pParse->db; int iDb; if( db->mallocFailed ){ goto exit_drop_index; } assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */ assert( pName->nSrc==1 ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_drop_index; } pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); if( pIndex==0 ){ if( !ifExists ){ sqlite3ErrorMsg(pParse, "no such index: %S", pName->a); }else{ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); sqlite3ForceNotReadOnly(pParse); } pParse->checkSchema = 1; goto exit_drop_index; } if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){ sqlite3ErrorMsg(pParse, "index associated with UNIQUE " "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; } iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; Table *pTab = pIndex->pTable; const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ goto exit_drop_index; } if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX; if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){ goto exit_drop_index; } } #endif /* Generate code to remove the index and from the schema table */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3NestedParse(pParse, "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='index'", db->aDb[iDb].zDbSName, pIndex->zName ); sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName); sqlite3ChangeCookie(pParse, iDb); destroyRootPage(pParse, pIndex->tnum, iDb); sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0); } exit_drop_index: sqlite3SrcListDelete(db, pName); } /* ** pArray is a pointer to an array of objects. Each object in the ** array is szEntry bytes in size. This routine uses sqlite3DbRealloc() ** to extend the array so that there is space for a new object at the end. ** ** When this function is called, *pnEntry contains the current size of ** the array (in entries - so the allocation is ((*pnEntry) * szEntry) bytes ** in total). ** ** If the realloc() is successful (i.e. if no OOM condition occurs), the ** space allocated for the new object is zeroed, *pnEntry updated to ** reflect the new size of the array and a pointer to the new allocation ** returned. *pIdx is set to the index of the new array entry in this case. ** ** Otherwise, if the realloc() fails, *pIdx is set to -1, *pnEntry remains ** unchanged and a copy of pArray returned. */ SQLITE_PRIVATE void *sqlite3ArrayAllocate( sqlite3 *db, /* Connection to notify of malloc failures */ void *pArray, /* Array of objects. Might be reallocated */ int szEntry, /* Size of each object in the array */ int *pnEntry, /* Number of objects currently in use */ int *pIdx /* Write the index of a new slot here */ ){ char *z; sqlite3_int64 n = *pIdx = *pnEntry; if( (n & (n-1))==0 ){ sqlite3_int64 sz = (n==0) ? 1 : 2*n; void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry); if( pNew==0 ){ *pIdx = -1; return pArray; } pArray = pNew; } z = (char*)pArray; memset(&z[n * szEntry], 0, szEntry); ++*pnEntry; return pArray; } /* ** Append a new element to the given IdList. Create a new IdList if ** need be. ** ** A new IdList is returned, or NULL if malloc() fails. */ SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){ sqlite3 *db = pParse->db; int i; if( pList==0 ){ pList = sqlite3DbMallocZero(db, sizeof(IdList) ); if( pList==0 ) return 0; }else{ IdList *pNew; pNew = sqlite3DbRealloc(db, pList, sizeof(IdList) + pList->nId*sizeof(pList->a)); if( pNew==0 ){ sqlite3IdListDelete(db, pList); return 0; } pList = pNew; } i = pList->nId++; pList->a[i].zName = sqlite3NameFromToken(db, pToken); if( IN_RENAME_OBJECT && pList->a[i].zName ){ sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken); } return pList; } /* ** Delete an IdList. */ SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){ int i; assert( db!=0 ); if( pList==0 ) return; assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */ for(i=0; inId; i++){ sqlite3DbFree(db, pList->a[i].zName); } sqlite3DbNNFreeNN(db, pList); } /* ** Return the index in pList of the identifier named zId. Return -1 ** if not found. */ SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){ int i; assert( pList!=0 ); for(i=0; inId; i++){ if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i; } return -1; } /* ** Maximum size of a SrcList object. ** The SrcList object is used to represent the FROM clause of a ** SELECT statement, and the query planner cannot deal with more ** than 64 tables in a join. So any value larger than 64 here ** is sufficient for most uses. Smaller values, like say 10, are ** appropriate for small and memory-limited applications. */ #ifndef SQLITE_MAX_SRCLIST # define SQLITE_MAX_SRCLIST 200 #endif /* ** Expand the space allocated for the given SrcList object by ** creating nExtra new slots beginning at iStart. iStart is zero based. ** New slots are zeroed. ** ** For example, suppose a SrcList initially contains two entries: A,B. ** To append 3 new entries onto the end, do this: ** ** sqlite3SrcListEnlarge(db, pSrclist, 3, 2); ** ** After the call above it would contain: A, B, nil, nil, nil. ** If the iStart argument had been 1 instead of 2, then the result ** would have been: A, nil, nil, nil, B. To prepend the new slots, ** the iStart value would be 0. The result then would ** be: nil, nil, nil, A, B. ** ** If a memory allocation fails or the SrcList becomes too large, leave ** the original SrcList unchanged, return NULL, and leave an error message ** in pParse. */ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( Parse *pParse, /* Parsing context into which errors are reported */ SrcList *pSrc, /* The SrcList to be enlarged */ int nExtra, /* Number of new slots to add to pSrc->a[] */ int iStart /* Index in pSrc->a[] of first new slot */ ){ int i; /* Sanity checking on calling parameters */ assert( iStart>=0 ); assert( nExtra>=1 ); assert( pSrc!=0 ); assert( iStart<=pSrc->nSrc ); /* Allocate additional space if needed */ if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){ SrcList *pNew; sqlite3_int64 nAlloc = 2*(sqlite3_int64)pSrc->nSrc+nExtra; sqlite3 *db = pParse->db; if( pSrc->nSrc+nExtra>=SQLITE_MAX_SRCLIST ){ sqlite3ErrorMsg(pParse, "too many FROM clause terms, max: %d", SQLITE_MAX_SRCLIST); return 0; } if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST; pNew = sqlite3DbRealloc(db, pSrc, sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) ); if( pNew==0 ){ assert( db->mallocFailed ); return 0; } pSrc = pNew; pSrc->nAlloc = nAlloc; } /* Move existing slots that come after the newly inserted slots ** out of the way */ for(i=pSrc->nSrc-1; i>=iStart; i--){ pSrc->a[i+nExtra] = pSrc->a[i]; } pSrc->nSrc += nExtra; /* Zero the newly allocated slots */ memset(&pSrc->a[iStart], 0, sizeof(pSrc->a[0])*nExtra); for(i=iStart; ia[i].iCursor = -1; } /* Return a pointer to the enlarged SrcList */ return pSrc; } /* ** Append a new table name to the given SrcList. Create a new SrcList if ** need be. A new entry is created in the SrcList even if pTable is NULL. ** ** A SrcList is returned, or NULL if there is an OOM error or if the ** SrcList grows to large. The returned ** SrcList might be the same as the SrcList that was input or it might be ** a new one. If an OOM error does occurs, then the prior value of pList ** that is input to this routine is automatically freed. ** ** If pDatabase is not null, it means that the table has an optional ** database name prefix. Like this: "database.table". The pDatabase ** points to the table name and the pTable points to the database name. ** The SrcList.a[].zName field is filled with the table name which might ** come from pTable (if pDatabase is NULL) or from pDatabase. ** SrcList.a[].zDatabase is filled with the database name from pTable, ** or with NULL if no database is specified. ** ** In other words, if call like this: ** ** sqlite3SrcListAppend(D,A,B,0); ** ** Then B is a table name and the database name is unspecified. If called ** like this: ** ** sqlite3SrcListAppend(D,A,B,C); ** ** Then C is the table name and B is the database name. If C is defined ** then so is B. In other words, we never have a case where: ** ** sqlite3SrcListAppend(D,A,0,C); ** ** Both pTable and pDatabase are assumed to be quoted. They are dequoted ** before being added to the SrcList. */ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( Parse *pParse, /* Parsing context, in which errors are reported */ SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */ Token *pTable, /* Table to append */ Token *pDatabase /* Database of the table */ ){ SrcItem *pItem; sqlite3 *db; assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */ assert( pParse!=0 ); assert( pParse->db!=0 ); db = pParse->db; if( pList==0 ){ pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) ); if( pList==0 ) return 0; pList->nAlloc = 1; pList->nSrc = 1; memset(&pList->a[0], 0, sizeof(pList->a[0])); pList->a[0].iCursor = -1; }else{ SrcList *pNew = sqlite3SrcListEnlarge(pParse, pList, 1, pList->nSrc); if( pNew==0 ){ sqlite3SrcListDelete(db, pList); return 0; }else{ pList = pNew; } } pItem = &pList->a[pList->nSrc-1]; if( pDatabase && pDatabase->z==0 ){ pDatabase = 0; } if( pDatabase ){ pItem->zName = sqlite3NameFromToken(db, pDatabase); pItem->zDatabase = sqlite3NameFromToken(db, pTable); }else{ pItem->zName = sqlite3NameFromToken(db, pTable); pItem->zDatabase = 0; } return pList; } /* ** Assign VdbeCursor index numbers to all tables in a SrcList */ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; SrcItem *pItem; assert( pList || pParse->db->mallocFailed ); if( ALWAYS(pList) ){ for(i=0, pItem=pList->a; inSrc; i++, pItem++){ if( pItem->iCursor>=0 ) continue; pItem->iCursor = pParse->nTab++; if( pItem->pSelect ){ sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); } } } } /* ** Delete an entire SrcList including all its substructure. */ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ int i; SrcItem *pItem; assert( db!=0 ); if( pList==0 ) return; for(pItem=pList->a, i=0; inSrc; i++, pItem++){ if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase); if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName); if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias); if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); sqlite3DeleteTable(db, pItem->pTab); if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect); if( pItem->fg.isUsing ){ sqlite3IdListDelete(db, pItem->u3.pUsing); }else if( pItem->u3.pOn ){ sqlite3ExprDelete(db, pItem->u3.pOn); } } sqlite3DbNNFreeNN(db, pList); } /* ** This routine is called by the parser to add a new term to the ** end of a growing FROM clause. The "p" parameter is the part of ** the FROM clause that has already been constructed. "p" is NULL ** if this is the first term of the FROM clause. pTable and pDatabase ** are the name of the table and database named in the FROM clause term. ** pDatabase is NULL if the database name qualifier is missing - the ** usual case. If the term has an alias, then pAlias points to the ** alias token. If the term is a subquery, then pSubquery is the ** SELECT statement that the subquery encodes. The pTable and ** pDatabase parameters are NULL for subqueries. The pOn and pUsing ** parameters are the content of the ON and USING clauses. ** ** Return a new SrcList which encodes is the FROM with the new ** term added. */ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( Parse *pParse, /* Parsing context */ SrcList *p, /* The left part of the FROM clause already seen */ Token *pTable, /* Name of the table to add to the FROM clause */ Token *pDatabase, /* Name of the database containing pTable */ Token *pAlias, /* The right-hand side of the AS subexpression */ Select *pSubquery, /* A subquery used in place of a table name */ OnOrUsing *pOnUsing /* Either the ON clause or the USING clause */ ){ SrcItem *pItem; sqlite3 *db = pParse->db; if( !p && pOnUsing!=0 && (pOnUsing->pOn || pOnUsing->pUsing) ){ sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s", (pOnUsing->pOn ? "ON" : "USING") ); goto append_from_error; } p = sqlite3SrcListAppend(pParse, p, pTable, pDatabase); if( p==0 ){ goto append_from_error; } assert( p->nSrc>0 ); pItem = &p->a[p->nSrc-1]; assert( (pTable==0)==(pDatabase==0) ); assert( pItem->zName==0 || pDatabase!=0 ); if( IN_RENAME_OBJECT && pItem->zName ){ Token *pToken = (ALWAYS(pDatabase) && pDatabase->z) ? pDatabase : pTable; sqlite3RenameTokenMap(pParse, pItem->zName, pToken); } assert( pAlias!=0 ); if( pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); } if( pSubquery ){ pItem->pSelect = pSubquery; if( pSubquery->selFlags & SF_NestedFrom ){ pItem->fg.isNestedFrom = 1; } } assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 ); assert( pItem->fg.isUsing==0 ); if( pOnUsing==0 ){ pItem->u3.pOn = 0; }else if( pOnUsing->pUsing ){ pItem->fg.isUsing = 1; pItem->u3.pUsing = pOnUsing->pUsing; }else{ pItem->u3.pOn = pOnUsing->pOn; } return p; append_from_error: assert( p==0 ); sqlite3ClearOnOrUsing(db, pOnUsing); sqlite3SelectDelete(db, pSubquery); return 0; } /* ** Add an INDEXED BY or NOT INDEXED clause to the most recently added ** element of the source-list passed as the second argument. */ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ assert( pIndexedBy!=0 ); if( p && pIndexedBy->n>0 ){ SrcItem *pItem; assert( p->nSrc>0 ); pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); if( pIndexedBy->n==1 && !pIndexedBy->z ){ /* A "NOT INDEXED" clause was supplied. See parse.y ** construct "indexed_opt" for details. */ pItem->fg.notIndexed = 1; }else{ pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); pItem->fg.isIndexedBy = 1; assert( pItem->fg.isCte==0 ); /* No collision on union u2 */ } } } /* ** Append the contents of SrcList p2 to SrcList p1 and return the resulting ** SrcList. Or, if an error occurs, return NULL. In all cases, p1 and p2 ** are deleted by this function. */ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){ assert( p1 && p1->nSrc==1 ); if( p2 ){ SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, 1); if( pNew==0 ){ sqlite3SrcListDelete(pParse->db, p2); }else{ p1 = pNew; memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(SrcItem)); sqlite3DbFree(pParse->db, p2); p1->a[0].fg.jointype |= (JT_LTORJ & p1->a[1].fg.jointype); } } return p1; } /* ** Add the list of function arguments to the SrcList entry for a ** table-valued-function. */ SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){ if( p ){ SrcItem *pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); pItem->u1.pFuncArg = pList; pItem->fg.isTabFunc = 1; }else{ sqlite3ExprListDelete(pParse->db, pList); } } /* ** When building up a FROM clause in the parser, the join operator ** is initially attached to the left operand. But the code generator ** expects the join operator to be on the right operand. This routine ** Shifts all join operators from left to right for an entire FROM ** clause. ** ** Example: Suppose the join is like this: ** ** A natural cross join B ** ** The operator is "natural cross join". The A and B operands are stored ** in p->a[0] and p->a[1], respectively. The parser initially stores the ** operator with A. This routine shifts that operator over to B. ** ** Additional changes: ** ** * All tables to the left of the right-most RIGHT JOIN are tagged with ** JT_LTORJ (mnemonic: Left Table Of Right Join) so that the ** code generator can easily tell that the table is part of ** the left operand of at least one RIGHT JOIN. */ SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(Parse *pParse, SrcList *p){ (void)pParse; if( p && p->nSrc>1 ){ int i = p->nSrc-1; u8 allFlags = 0; do{ allFlags |= p->a[i].fg.jointype = p->a[i-1].fg.jointype; }while( (--i)>0 ); p->a[0].fg.jointype = 0; /* All terms to the left of a RIGHT JOIN should be tagged with the ** JT_LTORJ flags */ if( allFlags & JT_RIGHT ){ for(i=p->nSrc-1; ALWAYS(i>0) && (p->a[i].fg.jointype&JT_RIGHT)==0; i--){} i--; assert( i>=0 ); do{ p->a[i].fg.jointype |= JT_LTORJ; }while( (--i)>=0 ); } } } /* ** Generate VDBE code for a BEGIN statement. */ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ sqlite3 *db; Vdbe *v; int i; assert( pParse!=0 ); db = pParse->db; assert( db!=0 ); if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){ return; } v = sqlite3GetVdbe(pParse); if( !v ) return; if( type!=TK_DEFERRED ){ for(i=0; inDb; i++){ int eTxnType; Btree *pBt = db->aDb[i].pBt; if( pBt && sqlite3BtreeIsReadonly(pBt) ){ eTxnType = 0; /* Read txn */ }else if( type==TK_EXCLUSIVE ){ eTxnType = 2; /* Exclusive txn */ }else{ eTxnType = 1; /* Write txn */ } sqlite3VdbeAddOp2(v, OP_Transaction, i, eTxnType); sqlite3VdbeUsesBtree(v, i); } } sqlite3VdbeAddOp0(v, OP_AutoCommit); } /* ** Generate VDBE code for a COMMIT or ROLLBACK statement. ** Code for ROLLBACK is generated if eType==TK_ROLLBACK. Otherwise ** code is generated for a COMMIT. */ SQLITE_PRIVATE void sqlite3EndTransaction(Parse *pParse, int eType){ Vdbe *v; int isRollback; assert( pParse!=0 ); assert( pParse->db!=0 ); assert( eType==TK_COMMIT || eType==TK_END || eType==TK_ROLLBACK ); isRollback = eType==TK_ROLLBACK; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, isRollback ? "ROLLBACK" : "COMMIT", 0, 0) ){ return; } v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, isRollback); } } /* ** This function is called by the parser when it parses a command to create, ** release or rollback an SQL savepoint. */ SQLITE_PRIVATE void sqlite3Savepoint(Parse *pParse, int op, Token *pName){ char *zName = sqlite3NameFromToken(pParse->db, pName); if( zName ){ Vdbe *v = sqlite3GetVdbe(pParse); #ifndef SQLITE_OMIT_AUTHORIZATION static const char * const az[] = { "BEGIN", "RELEASE", "ROLLBACK" }; assert( !SAVEPOINT_BEGIN && SAVEPOINT_RELEASE==1 && SAVEPOINT_ROLLBACK==2 ); #endif if( !v || sqlite3AuthCheck(pParse, SQLITE_SAVEPOINT, az[op], zName, 0) ){ sqlite3DbFree(pParse->db, zName); return; } sqlite3VdbeAddOp4(v, OP_Savepoint, op, 0, 0, zName, P4_DYNAMIC); } } /* ** Make sure the TEMP database is open and available for use. Return ** the number of errors. Leave any error messages in the pParse structure. */ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){ sqlite3 *db = pParse->db; if( db->aDb[1].pBt==0 && !pParse->explain ){ int rc; Btree *pBt; static const int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_TEMP_DB; rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags); if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "unable to open a temporary database " "file for storing temporary tables"); pParse->rc = rc; return 1; } db->aDb[1].pBt = pBt; assert( db->aDb[1].pSchema ); if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){ sqlite3OomFault(db); return 1; } } return 0; } /* ** Record the fact that the schema cookie will need to be verified ** for database iDb. The code to actually verify the schema cookie ** will occur at the end of the top-level VDBE and will be generated ** later, by sqlite3FinishCoding(). */ static void sqlite3CodeVerifySchemaAtToplevel(Parse *pToplevel, int iDb){ assert( iDb>=0 && iDbdb->nDb ); assert( pToplevel->db->aDb[iDb].pBt!=0 || iDb==1 ); assert( iDbdb, iDb, 0) ); if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){ DbMaskSet(pToplevel->cookieMask, iDb); if( !OMIT_TEMPDB && iDb==1 ){ sqlite3OpenTempDatabase(pToplevel); } } } SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ sqlite3CodeVerifySchemaAtToplevel(sqlite3ParseToplevel(pParse), iDb); } /* ** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each ** attached database. Otherwise, invoke it for the database named zDb only. */ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ sqlite3 *db = pParse->db; int i; for(i=0; inDb; i++){ Db *pDb = &db->aDb[i]; if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zDbSName)) ){ sqlite3CodeVerifySchema(pParse, i); } } } /* ** Generate VDBE code that prepares for doing an operation that ** might change the database. ** ** This routine starts a new transaction if we are not already within ** a transaction. If we are already within a transaction, then a checkpoint ** is set if the setStatement parameter is true. A checkpoint should ** be set for operations that might fail (due to a constraint) part of ** the way through and which will need to undo some writes without having to ** rollback the whole transaction. For operations where all constraints ** can be checked before any changes are made to the database, it is never ** necessary to undo a write and the checkpoint should not be set. */ SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3CodeVerifySchemaAtToplevel(pToplevel, iDb); DbMaskSet(pToplevel->writeMask, iDb); pToplevel->isMultiWrite |= setStatement; } /* ** Indicate that the statement currently under construction might write ** more than one entry (example: deleting one row then inserting another, ** inserting multiple rows in a table, or inserting a row and index entries.) ** If an abort occurs after some of these writes have completed, then it will ** be necessary to undo the completed writes. */ SQLITE_PRIVATE void sqlite3MultiWrite(Parse *pParse){ Parse *pToplevel = sqlite3ParseToplevel(pParse); pToplevel->isMultiWrite = 1; } /* ** The code generator calls this routine if is discovers that it is ** possible to abort a statement prior to completion. In order to ** perform this abort without corrupting the database, we need to make ** sure that the statement is protected by a statement transaction. ** ** Technically, we only need to set the mayAbort flag if the ** isMultiWrite flag was previously set. There is a time dependency ** such that the abort must occur after the multiwrite. This makes ** some statements involving the REPLACE conflict resolution algorithm ** go a little faster. But taking advantage of this time dependency ** makes it more difficult to prove that the code is correct (in ** particular, it prevents us from writing an effective ** implementation of sqlite3AssertMayAbort()) and so we have chosen ** to take the safe route and skip the optimization. */ SQLITE_PRIVATE void sqlite3MayAbort(Parse *pParse){ Parse *pToplevel = sqlite3ParseToplevel(pParse); pToplevel->mayAbort = 1; } /* ** Code an OP_Halt that causes the vdbe to return an SQLITE_CONSTRAINT ** error. The onError parameter determines which (if any) of the statement ** and/or current transaction is rolled back. */ SQLITE_PRIVATE void sqlite3HaltConstraint( Parse *pParse, /* Parsing context */ int errCode, /* extended error code */ int onError, /* Constraint type */ char *p4, /* Error message */ i8 p4type, /* P4_STATIC or P4_TRANSIENT */ u8 p5Errmsg /* P5_ErrMsg type */ ){ Vdbe *v; assert( pParse->pVdbe!=0 ); v = sqlite3GetVdbe(pParse); assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested ); if( onError==OE_Abort ){ sqlite3MayAbort(pParse); } sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type); sqlite3VdbeChangeP5(v, p5Errmsg); } /* ** Code an OP_Halt due to UNIQUE or PRIMARY KEY constraint violation. */ SQLITE_PRIVATE void sqlite3UniqueConstraint( Parse *pParse, /* Parsing context */ int onError, /* Constraint type */ Index *pIdx /* The index that triggers the constraint */ ){ char *zErr; int j; StrAccum errMsg; Table *pTab = pIdx->pTable; sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, pParse->db->aLimit[SQLITE_LIMIT_LENGTH]); if( pIdx->aColExpr ){ sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName); }else{ for(j=0; jnKeyCol; j++){ char *zCol; assert( pIdx->aiColumn[j]>=0 ); zCol = pTab->aCol[pIdx->aiColumn[j]].zCnName; if( j ) sqlite3_str_append(&errMsg, ", ", 2); sqlite3_str_appendall(&errMsg, pTab->zName); sqlite3_str_append(&errMsg, ".", 1); sqlite3_str_appendall(&errMsg, zCol); } } zErr = sqlite3StrAccumFinish(&errMsg); sqlite3HaltConstraint(pParse, IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY : SQLITE_CONSTRAINT_UNIQUE, onError, zErr, P4_DYNAMIC, P5_ConstraintUnique); } /* ** Code an OP_Halt due to non-unique rowid. */ SQLITE_PRIVATE void sqlite3RowidConstraint( Parse *pParse, /* Parsing context */ int onError, /* Conflict resolution algorithm */ Table *pTab /* The table with the non-unique rowid */ ){ char *zMsg; int rc; if( pTab->iPKey>=0 ){ zMsg = sqlite3MPrintf(pParse->db, "%s.%s", pTab->zName, pTab->aCol[pTab->iPKey].zCnName); rc = SQLITE_CONSTRAINT_PRIMARYKEY; }else{ zMsg = sqlite3MPrintf(pParse->db, "%s.rowid", pTab->zName); rc = SQLITE_CONSTRAINT_ROWID; } sqlite3HaltConstraint(pParse, rc, onError, zMsg, P4_DYNAMIC, P5_ConstraintUnique); } /* ** Check to see if pIndex uses the collating sequence pColl. Return ** true if it does and false if it does not. */ #ifndef SQLITE_OMIT_REINDEX static int collationMatch(const char *zColl, Index *pIndex){ int i; assert( zColl!=0 ); for(i=0; inColumn; i++){ const char *z = pIndex->azColl[i]; assert( z!=0 || pIndex->aiColumn[i]<0 ); if( pIndex->aiColumn[i]>=0 && 0==sqlite3StrICmp(z, zColl) ){ return 1; } } return 0; } #endif /* ** Recompute all indices of pTab that use the collating sequence pColl. ** If pColl==0 then recompute all indices of pTab. */ #ifndef SQLITE_OMIT_REINDEX static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ if( !IsVirtual(pTab) ){ Index *pIndex; /* An index associated with pTab */ for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ if( zColl==0 || collationMatch(zColl, pIndex) ){ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3RefillIndex(pParse, pIndex, -1); } } } } #endif /* ** Recompute all indices of all tables in all databases where the ** indices use the collating sequence pColl. If pColl==0 then recompute ** all indices everywhere. */ #ifndef SQLITE_OMIT_REINDEX static void reindexDatabases(Parse *pParse, char const *zColl){ Db *pDb; /* A single database */ int iDb; /* The database index number */ sqlite3 *db = pParse->db; /* The database connection */ HashElem *k; /* For looping over tables in pDb */ Table *pTab; /* A table in the database */ assert( sqlite3BtreeHoldsAllMutexes(db) ); /* Needed for schema access */ for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ assert( pDb!=0 ); for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ pTab = (Table*)sqliteHashData(k); reindexTable(pParse, pTab, zColl); } } } #endif /* ** Generate code for the REINDEX command. ** ** REINDEX -- 1 ** REINDEX -- 2 ** REINDEX ?.? -- 3 ** REINDEX ?.? -- 4 ** ** Form 1 causes all indices in all attached databases to be rebuilt. ** Form 2 rebuilds all indices in all databases that use the named ** collating function. Forms 3 and 4 rebuild the named index or all ** indices associated with the named table. */ #ifndef SQLITE_OMIT_REINDEX SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ CollSeq *pColl; /* Collating sequence to be reindexed, or NULL */ char *z; /* Name of a table or index */ const char *zDb; /* Name of the database */ Table *pTab; /* A table in the database */ Index *pIndex; /* An index associated with pTab */ int iDb; /* The database index number */ sqlite3 *db = pParse->db; /* The database connection */ Token *pObjName; /* Name of the table or index to be reindexed */ /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return; } if( pName1==0 ){ reindexDatabases(pParse, 0); return; }else if( NEVER(pName2==0) || pName2->z==0 ){ char *zColl; assert( pName1->z ); zColl = sqlite3NameFromToken(pParse->db, pName1); if( !zColl ) return; pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); if( pColl ){ reindexDatabases(pParse, zColl); sqlite3DbFree(db, zColl); return; } sqlite3DbFree(db, zColl); } iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); if( iDb<0 ) return; z = sqlite3NameFromToken(db, pObjName); if( z==0 ) return; zDb = pName2->n ? db->aDb[iDb].zDbSName : 0; pTab = sqlite3FindTable(db, z, zDb); if( pTab ){ reindexTable(pParse, pTab, 0); sqlite3DbFree(db, z); return; } pIndex = sqlite3FindIndex(db, z, zDb); sqlite3DbFree(db, z); if( pIndex ){ iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3RefillIndex(pParse, pIndex, -1); return; } sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); } #endif /* ** Return a KeyInfo structure that is appropriate for the given Index. ** ** The caller should invoke sqlite3KeyInfoUnref() on the returned object ** when it has finished using it. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ int i; int nCol = pIdx->nColumn; int nKey = pIdx->nKeyCol; KeyInfo *pKey; if( pParse->nErr ) return 0; if( pIdx->uniqNotNull ){ pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey); }else{ pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); } if( pKey ){ assert( sqlite3KeyInfoIsWriteable(pKey) ); for(i=0; iazColl[i]; pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 : sqlite3LocateCollSeq(pParse, zColl); pKey->aSortFlags[i] = pIdx->aSortOrder[i]; assert( 0==(pKey->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) ); } if( pParse->nErr ){ assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ ); if( pIdx->bNoQuery==0 ){ /* Deactivate the index because it contains an unknown collating ** sequence. The only way to reactive the index is to reload the ** schema. Adding the missing collating sequence later does not ** reactive the index. The application had the chance to register ** the missing index using the collation-needed callback. For ** simplicity, SQLite will not give the application a second chance. */ pIdx->bNoQuery = 1; pParse->rc = SQLITE_ERROR_RETRY; } sqlite3KeyInfoUnref(pKey); pKey = 0; } } return pKey; } #ifndef SQLITE_OMIT_CTE /* ** Create a new CTE object */ SQLITE_PRIVATE Cte *sqlite3CteNew( Parse *pParse, /* Parsing context */ Token *pName, /* Name of the common-table */ ExprList *pArglist, /* Optional column name list for the table */ Select *pQuery, /* Query used to initialize the table */ u8 eM10d /* The MATERIALIZED flag */ ){ Cte *pNew; sqlite3 *db = pParse->db; pNew = sqlite3DbMallocZero(db, sizeof(*pNew)); assert( pNew!=0 || db->mallocFailed ); if( db->mallocFailed ){ sqlite3ExprListDelete(db, pArglist); sqlite3SelectDelete(db, pQuery); }else{ pNew->pSelect = pQuery; pNew->pCols = pArglist; pNew->zName = sqlite3NameFromToken(pParse->db, pName); pNew->eM10d = eM10d; } return pNew; } /* ** Clear information from a Cte object, but do not deallocate storage ** for the object itself. */ static void cteClear(sqlite3 *db, Cte *pCte){ assert( pCte!=0 ); sqlite3ExprListDelete(db, pCte->pCols); sqlite3SelectDelete(db, pCte->pSelect); sqlite3DbFree(db, pCte->zName); } /* ** Free the contents of the CTE object passed as the second argument. */ SQLITE_PRIVATE void sqlite3CteDelete(sqlite3 *db, Cte *pCte){ assert( pCte!=0 ); cteClear(db, pCte); sqlite3DbFree(db, pCte); } /* ** This routine is invoked once per CTE by the parser while parsing a ** WITH clause. The CTE described by the third argument is added to ** the WITH clause of the second argument. If the second argument is ** NULL, then a new WITH argument is created. */ SQLITE_PRIVATE With *sqlite3WithAdd( Parse *pParse, /* Parsing context */ With *pWith, /* Existing WITH clause, or NULL */ Cte *pCte /* CTE to add to the WITH clause */ ){ sqlite3 *db = pParse->db; With *pNew; char *zName; if( pCte==0 ){ return pWith; } /* Check that the CTE name is unique within this WITH clause. If ** not, store an error in the Parse structure. */ zName = pCte->zName; if( zName && pWith ){ int i; for(i=0; inCte; i++){ if( sqlite3StrICmp(zName, pWith->a[i].zName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate WITH table name: %s", zName); } } } if( pWith ){ sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); pNew = sqlite3DbRealloc(db, pWith, nByte); }else{ pNew = sqlite3DbMallocZero(db, sizeof(*pWith)); } assert( (pNew!=0 && zName!=0) || db->mallocFailed ); if( db->mallocFailed ){ sqlite3CteDelete(db, pCte); pNew = pWith; }else{ pNew->a[pNew->nCte++] = *pCte; sqlite3DbFree(db, pCte); } return pNew; } /* ** Free the contents of the With object passed as the second argument. */ SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){ if( pWith ){ int i; for(i=0; inCte; i++){ cteClear(db, &pWith->a[i]); } sqlite3DbFree(db, pWith); } } SQLITE_PRIVATE void sqlite3WithDeleteGeneric(sqlite3 *db, void *pWith){ sqlite3WithDelete(db, (With*)pWith); } #endif /* !defined(SQLITE_OMIT_CTE) */ /************** End of build.c ***********************************************/ /************** Begin file callback.c ****************************************/ /* ** 2005 May 23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. */ /* #include "sqliteInt.h" */ /* ** Invoke the 'collation needed' callback to request a collation sequence ** in the encoding enc of name zName, length nName. */ static void callCollNeeded(sqlite3 *db, int enc, const char *zName){ assert( !db->xCollNeeded || !db->xCollNeeded16 ); if( db->xCollNeeded ){ char *zExternal = sqlite3DbStrDup(db, zName); if( !zExternal ) return; db->xCollNeeded(db->pCollNeededArg, db, enc, zExternal); sqlite3DbFree(db, zExternal); } #ifndef SQLITE_OMIT_UTF16 if( db->xCollNeeded16 ){ char const *zExternal; sqlite3_value *pTmp = sqlite3ValueNew(db); sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC); zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE); if( zExternal ){ db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal); } sqlite3ValueFree(pTmp); } #endif } /* ** This routine is called if the collation factory fails to deliver a ** collation function in the best encoding but there may be other versions ** of this collation function (for other text encodings) available. Use one ** of these instead if they exist. Avoid a UTF-8 <-> UTF-16 conversion if ** possible. */ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){ CollSeq *pColl2; char *z = pColl->zName; int i; static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 }; for(i=0; i<3; i++){ pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, 0); if( pColl2->xCmp!=0 ){ memcpy(pColl, pColl2, sizeof(CollSeq)); pColl->xDel = 0; /* Do not copy the destructor */ return SQLITE_OK; } } return SQLITE_ERROR; } /* ** This routine is called on a collation sequence before it is used to ** check that it is defined. An undefined collation sequence exists when ** a database is loaded that contains references to collation sequences ** that have not been defined by sqlite3_create_collation() etc. ** ** If required, this routine calls the 'collation needed' callback to ** request a definition of the collating sequence. If this doesn't work, ** an equivalent collating sequence that uses a text encoding different ** from the main database is substituted, if one is available. */ SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ if( pColl && pColl->xCmp==0 ){ const char *zName = pColl->zName; sqlite3 *db = pParse->db; CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName); if( !p ){ return SQLITE_ERROR; } assert( p==pColl ); } return SQLITE_OK; } /* ** Locate and return an entry from the db.aCollSeq hash table. If the entry ** specified by zName and nName is not found and parameter 'create' is ** true, then create a new entry. Otherwise return NULL. ** ** Each pointer stored in the sqlite3.aCollSeq hash table contains an ** array of three CollSeq structures. The first is the collation sequence ** preferred for UTF-8, the second UTF-16le, and the third UTF-16be. ** ** Stored immediately after the three collation sequences is a copy of ** the collation sequence name. A pointer to this string is stored in ** each collation sequence structure. */ static CollSeq *findCollSeqEntry( sqlite3 *db, /* Database connection */ const char *zName, /* Name of the collating sequence */ int create /* Create a new entry if true */ ){ CollSeq *pColl; pColl = sqlite3HashFind(&db->aCollSeq, zName); if( 0==pColl && create ){ int nName = sqlite3Strlen30(zName) + 1; pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName); if( pColl ){ CollSeq *pDel = 0; pColl[0].zName = (char*)&pColl[3]; pColl[0].enc = SQLITE_UTF8; pColl[1].zName = (char*)&pColl[3]; pColl[1].enc = SQLITE_UTF16LE; pColl[2].zName = (char*)&pColl[3]; pColl[2].enc = SQLITE_UTF16BE; memcpy(pColl[0].zName, zName, nName); pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl); /* If a malloc() failure occurred in sqlite3HashInsert(), it will ** return the pColl pointer to be deleted (because it wasn't added ** to the hash table). */ assert( pDel==0 || pDel==pColl ); if( pDel!=0 ){ sqlite3OomFault(db); sqlite3DbFree(db, pDel); pColl = 0; } } } return pColl; } /* ** Parameter zName points to a UTF-8 encoded string nName bytes long. ** Return the CollSeq* pointer for the collation sequence named zName ** for the encoding 'enc' from the database 'db'. ** ** If the entry specified is not found and 'create' is true, then create a ** new entry. Otherwise return NULL. ** ** A separate function sqlite3LocateCollSeq() is a wrapper around ** this routine. sqlite3LocateCollSeq() invokes the collation factory ** if necessary and generates an error message if the collating sequence ** cannot be found. ** ** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq() */ SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq( sqlite3 *db, /* Database connection to search */ u8 enc, /* Desired text encoding */ const char *zName, /* Name of the collating sequence. Might be NULL */ int create /* True to create CollSeq if doesn't already exist */ ){ CollSeq *pColl; assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); if( zName ){ pColl = findCollSeqEntry(db, zName, create); if( pColl ) pColl += enc-1; }else{ pColl = db->pDfltColl; } return pColl; } /* ** Change the text encoding for a database connection. This means that ** the pDfltColl must change as well. */ SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); db->enc = enc; /* EVIDENCE-OF: R-08308-17224 The default collating function for all ** strings is BINARY. */ db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0); sqlite3ExpirePreparedStatements(db, 1); } /* ** This function is responsible for invoking the collation factory callback ** or substituting a collation sequence of a different encoding when the ** requested collation sequence is not available in the desired encoding. ** ** If it is not NULL, then pColl must point to the database native encoding ** collation sequence with name zName, length nName. ** ** The return value is either the collation sequence to be used in database ** db for collation type name zName, length nName, or NULL, if no collation ** sequence can be found. If no collation is found, leave an error message. ** ** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq() */ SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq( Parse *pParse, /* Parsing context */ u8 enc, /* The desired encoding for the collating sequence */ CollSeq *pColl, /* Collating sequence with native encoding, or NULL */ const char *zName /* Collating sequence name */ ){ CollSeq *p; sqlite3 *db = pParse->db; p = pColl; if( !p ){ p = sqlite3FindCollSeq(db, enc, zName, 0); } if( !p || !p->xCmp ){ /* No collation sequence of this type for this encoding is registered. ** Call the collation factory to see if it can supply us with one. */ callCollNeeded(db, enc, zName); p = sqlite3FindCollSeq(db, enc, zName, 0); } if( p && !p->xCmp && synthCollSeq(db, p) ){ p = 0; } assert( !p || p->xCmp ); if( p==0 ){ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ; } return p; } /* ** This function returns the collation sequence for database native text ** encoding identified by the string zName. ** ** If the requested collation sequence is not available, or not available ** in the database native encoding, the collation factory is invoked to ** request it. If the collation factory does not supply such a sequence, ** and the sequence is available in another text encoding, then that is ** returned instead. ** ** If no versions of the requested collations sequence are available, or ** another error occurs, NULL is returned and an error message written into ** pParse. ** ** This routine is a wrapper around sqlite3FindCollSeq(). This routine ** invokes the collation factory if the named collation cannot be found ** and generates an error message. ** ** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq() */ SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){ sqlite3 *db = pParse->db; u8 enc = ENC(db); u8 initbusy = db->init.busy; CollSeq *pColl; pColl = sqlite3FindCollSeq(db, enc, zName, initbusy); if( !initbusy && (!pColl || !pColl->xCmp) ){ pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName); } return pColl; } /* During the search for the best function definition, this procedure ** is called to test how well the function passed as the first argument ** matches the request for a function with nArg arguments in a system ** that uses encoding enc. The value returned indicates how well the ** request is matched. A higher value indicates a better match. ** ** If nArg is -1 that means to only return a match (non-zero) if p->nArg ** is also -1. In other words, we are searching for a function that ** takes a variable number of arguments. ** ** If nArg is -2 that means that we are searching for any function ** regardless of the number of arguments it uses, so return a positive ** match score for any ** ** The returned value is always between 0 and 6, as follows: ** ** 0: Not a match. ** 1: UTF8/16 conversion required and function takes any number of arguments. ** 2: UTF16 byte order change required and function takes any number of args. ** 3: encoding matches and function takes any number of arguments ** 4: UTF8/16 conversion required - argument count matches exactly ** 5: UTF16 byte order conversion required - argument count matches exactly ** 6: Perfect match: encoding and argument count match exactly. ** ** If nArg==(-2) then any function with a non-null xSFunc is ** a perfect match and any function with xSFunc NULL is ** a non-match. */ #define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */ static int matchQuality( FuncDef *p, /* The function we are evaluating for match quality */ int nArg, /* Desired number of arguments. (-1)==any */ u8 enc /* Desired text encoding */ ){ int match; assert( p->nArg>=-1 ); /* Wrong number of arguments means "no match" */ if( p->nArg!=nArg ){ if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH; if( p->nArg>=0 ) return 0; } /* Give a better score to a function with a specific number of arguments ** than to function that accepts any number of arguments. */ if( p->nArg==nArg ){ match = 4; }else{ match = 1; } /* Bonus points if the text encoding matches */ if( enc==(p->funcFlags & SQLITE_FUNC_ENCMASK) ){ match += 2; /* Exact encoding match */ }else if( (enc & p->funcFlags & 2)!=0 ){ match += 1; /* Both are UTF16, but with different byte orders */ } return match; } /* ** Search a FuncDefHash for a function with the given name. Return ** a pointer to the matching FuncDef if found, or 0 if there is no match. */ SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch( int h, /* Hash of the name */ const char *zFunc /* Name of function */ ){ FuncDef *p; for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){ assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); if( sqlite3StrICmp(p->zName, zFunc)==0 ){ return p; } } return 0; } /* ** Insert a new FuncDef into a FuncDefHash hash table. */ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs( FuncDef *aDef, /* List of global functions to be inserted */ int nDef /* Length of the apDef[] list */ ){ int i; for(i=0; ipNext!=&aDef[i] ); aDef[i].pNext = pOther->pNext; pOther->pNext = &aDef[i]; }else{ aDef[i].pNext = 0; aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h]; sqlite3BuiltinFunctions.a[h] = &aDef[i]; } } } /* ** Locate a user function given a name, a number of arguments and a flag ** indicating whether the function prefers UTF-16 over UTF-8. Return a ** pointer to the FuncDef structure that defines that function, or return ** NULL if the function does not exist. ** ** If the createFlag argument is true, then a new (blank) FuncDef ** structure is created and liked into the "db" structure if a ** no matching function previously existed. ** ** If nArg is -2, then the first valid function found is returned. A ** function is valid if xSFunc is non-zero. The nArg==(-2) ** case is used to see if zName is a valid function name for some number ** of arguments. If nArg is -2, then createFlag must be 0. ** ** If createFlag is false, then a function with the required name and ** number of arguments may be returned even if the eTextRep flag does not ** match that requested. */ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( sqlite3 *db, /* An open database */ const char *zName, /* Name of the function. zero-terminated */ int nArg, /* Number of arguments. -1 means any number */ u8 enc, /* Preferred text encoding */ u8 createFlag /* Create new entry if true and does not otherwise exist */ ){ FuncDef *p; /* Iterator variable */ FuncDef *pBest = 0; /* Best match found so far */ int bestScore = 0; /* Score of best match */ int h; /* Hash value */ int nName; /* Length of the name */ assert( nArg>=(-2) ); assert( nArg>=(-1) || createFlag==0 ); nName = sqlite3Strlen30(zName); /* First search for a match amongst the application-defined functions. */ p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName); while( p ){ int score = matchQuality(p, nArg, enc); if( score>bestScore ){ pBest = p; bestScore = score; } p = p->pNext; } /* If no match is found, search the built-in functions. ** ** If the DBFLAG_PreferBuiltin flag is set, then search the built-in ** functions even if a prior app-defined function was found. And give ** priority to built-in functions. ** ** Except, if createFlag is true, that means that we are trying to ** install a new function. Whatever FuncDef structure is returned it will ** have fields overwritten with new information appropriate for the ** new function. But the FuncDefs for built-in functions are read-only. ** So we must not search for built-ins when creating a new function. */ if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){ bestScore = 0; h = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zName[0]], nName); p = sqlite3FunctionSearch(h, zName); while( p ){ int score = matchQuality(p, nArg, enc); if( score>bestScore ){ pBest = p; bestScore = score; } p = p->pNext; } } /* If the createFlag parameter is true and the search did not reveal an ** exact match for the name, number of arguments and encoding, then add a ** new entry to the hash table and return it. */ if( createFlag && bestScorezName = (const char*)&pBest[1]; pBest->nArg = (u16)nArg; pBest->funcFlags = enc; memcpy((char*)&pBest[1], zName, nName+1); for(z=(u8*)pBest->zName; *z; z++) *z = sqlite3UpperToLower[*z]; pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest); if( pOther==pBest ){ sqlite3DbFree(db, pBest); sqlite3OomFault(db); return 0; }else{ pBest->pNext = pOther; } } if( pBest && (pBest->xSFunc || createFlag) ){ return pBest; } return 0; } /* ** Free all resources held by the schema structure. The void* argument points ** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the ** pointer itself, it just cleans up subsidiary resources (i.e. the contents ** of the schema hash tables). ** ** The Schema.cache_size variable is not cleared. */ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){ Hash temp1; Hash temp2; HashElem *pElem; Schema *pSchema = (Schema *)p; sqlite3 xdb; memset(&xdb, 0, sizeof(xdb)); temp1 = pSchema->tblHash; temp2 = pSchema->trigHash; sqlite3HashInit(&pSchema->trigHash); sqlite3HashClear(&pSchema->idxHash); for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem)); } sqlite3HashClear(&temp2); sqlite3HashInit(&pSchema->tblHash); for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); sqlite3DeleteTable(&xdb, pTab); } sqlite3HashClear(&temp1); sqlite3HashClear(&pSchema->fkeyHash); pSchema->pSeqTab = 0; if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; } pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted); } /* ** Find and return the schema associated with a BTree. Create ** a new one if necessary. */ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ Schema * p; if( pBt ){ p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear); }else{ p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema)); } if( !p ){ sqlite3OomFault(db); }else if ( 0==p->file_format ){ sqlite3HashInit(&p->tblHash); sqlite3HashInit(&p->idxHash); sqlite3HashInit(&p->trigHash); sqlite3HashInit(&p->fkeyHash); p->enc = SQLITE_UTF8; } return p; } /************** End of callback.c ********************************************/ /************** Begin file delete.c ******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. */ /* #include "sqliteInt.h" */ /* ** While a SrcList can in general represent multiple tables and subqueries ** (as in the FROM clause of a SELECT statement) in this case it contains ** the name of a single table, as one might find in an INSERT, DELETE, ** or UPDATE statement. Look up that table in the symbol table and ** return a pointer. Set an error message and return NULL if the table ** name is not found or if any other error occurs. ** ** The following fields are initialized appropriate in pSrc: ** ** pSrc->a[0].pTab Pointer to the Table object ** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one ** */ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ SrcItem *pItem = pSrc->a; Table *pTab; assert( pItem && pSrc->nSrc>=1 ); pTab = sqlite3LocateTableItem(pParse, 0, pItem); if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab); pItem->pTab = pTab; pItem->fg.notCte = 1; if( pTab ){ pTab->nTabRef++; if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){ pTab = 0; } } return pTab; } /* Generate byte-code that will report the number of rows modified ** by a DELETE, INSERT, or UPDATE statement. */ SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char *zColName){ sqlite3VdbeAddOp0(v, OP_FkCheck); sqlite3VdbeAddOp2(v, OP_ResultRow, regCounter, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zColName, SQLITE_STATIC); } /* Return true if table pTab is read-only. ** ** A table is read-only if any of the following are true: ** ** 1) It is a virtual table and no implementation of the xUpdate method ** has been provided ** ** 2) A trigger is currently being coded and the table is a virtual table ** that is SQLITE_VTAB_DIRECTONLY or if PRAGMA trusted_schema=OFF and ** the table is not SQLITE_VTAB_INNOCUOUS. ** ** 3) It is a system table (i.e. sqlite_schema), this call is not ** part of a nested parse and writable_schema pragma has not ** been specified ** ** 4) The table is a shadow table, the database connection is in ** defensive mode, and the current sqlite3_prepare() ** is for a top-level SQL statement. */ static int vtabIsReadOnly(Parse *pParse, Table *pTab){ if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){ return 1; } /* Within triggers: ** * Do not allow DELETE, INSERT, or UPDATE of SQLITE_VTAB_DIRECTONLY ** virtual tables ** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS ** virtual tables if PRAGMA trusted_schema=ON. */ if( pParse->pToplevel!=0 && pTab->u.vtab.p->eVtabRisk > ((pParse->db->flags & SQLITE_TrustedSchema)!=0) ){ sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"", pTab->zName); } return 0; } static int tabIsReadOnly(Parse *pParse, Table *pTab){ sqlite3 *db; if( IsVirtual(pTab) ){ return vtabIsReadOnly(pParse, pTab); } if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0; db = pParse->db; if( (pTab->tabFlags & TF_Readonly)!=0 ){ return sqlite3WritableSchema(db)==0 && pParse->nested==0; } assert( pTab->tabFlags & TF_Shadow ); return sqlite3ReadOnlyShadowTables(db); } /* ** Check to make sure the given table is writable. ** ** If pTab is not writable -> generate an error message and return 1. ** If pTab is writable but other errors have occurred -> return 1. ** If pTab is writable and no prior errors -> return 0; */ SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, Trigger *pTrigger){ if( tabIsReadOnly(pParse, pTab) ){ sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); return 1; } #ifndef SQLITE_OMIT_VIEW if( IsView(pTab) && (pTrigger==0 || (pTrigger->bReturning && pTrigger->pNext==0)) ){ sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); return 1; } #endif return 0; } #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) /* ** Evaluate a view and store its result in an ephemeral table. The ** pWhere argument is an optional WHERE clause that restricts the ** set of rows in the view that are to be added to the ephemeral table. */ SQLITE_PRIVATE void sqlite3MaterializeView( Parse *pParse, /* Parsing context */ Table *pView, /* View definition */ Expr *pWhere, /* Optional WHERE clause to be added */ ExprList *pOrderBy, /* Optional ORDER BY clause */ Expr *pLimit, /* Optional LIMIT clause */ int iCur /* Cursor number for ephemeral table */ ){ SelectDest dest; Select *pSel; SrcList *pFrom; sqlite3 *db = pParse->db; int iDb = sqlite3SchemaToIndex(db, pView->pSchema); pWhere = sqlite3ExprDup(db, pWhere, 0); pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pFrom ){ assert( pFrom->nSrc==1 ); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); assert( pFrom->a[0].fg.isUsing==0 ); assert( pFrom->a[0].u3.pOn==0 ); } pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy, SF_IncludeHidden, pLimit); sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); sqlite3Select(pParse, pSel, &dest); sqlite3SelectDelete(db, pSel); } #endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */ #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) /* ** Generate an expression tree to implement the WHERE, ORDER BY, ** and LIMIT/OFFSET portion of DELETE and UPDATE statements. ** ** DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1; ** \__________________________/ ** pLimitWhere (pInClause) */ SQLITE_PRIVATE Expr *sqlite3LimitWhere( Parse *pParse, /* The parser context */ SrcList *pSrc, /* the FROM clause -- which tables to scan */ Expr *pWhere, /* The WHERE clause. May be null */ ExprList *pOrderBy, /* The ORDER BY clause. May be null */ Expr *pLimit, /* The LIMIT clause. May be null */ char *zStmtType /* Either DELETE or UPDATE. For err msgs. */ ){ sqlite3 *db = pParse->db; Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */ Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */ ExprList *pEList = NULL; /* Expression list containing only pSelectRowid*/ SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */ Select *pSelect = NULL; /* Complete SELECT tree */ Table *pTab; /* Check that there isn't an ORDER BY without a LIMIT clause. */ if( pOrderBy && pLimit==0 ) { sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType); sqlite3ExprDelete(pParse->db, pWhere); sqlite3ExprListDelete(pParse->db, pOrderBy); return 0; } /* We only need to generate a select expression if there ** is a limit/offset term to enforce. */ if( pLimit == 0 ) { return pWhere; } /* Generate a select expression tree to enforce the limit/offset ** term for the DELETE or UPDATE statement. For example: ** DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1 ** becomes: ** DELETE FROM table_a WHERE rowid IN ( ** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1 ** ); */ pTab = pSrc->a[0].pTab; if( HasRowid(pTab) ){ pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0); pEList = sqlite3ExprListAppend( pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0) ); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); assert( pPk->nKeyCol>=1 ); if( pPk->nKeyCol==1 ){ const char *zName; assert( pPk->aiColumn[0]>=0 && pPk->aiColumn[0]nCol ); zName = pTab->aCol[pPk->aiColumn[0]].zCnName; pLhs = sqlite3Expr(db, TK_ID, zName); pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName)); }else{ int i; for(i=0; inKeyCol; i++){ Expr *p; assert( pPk->aiColumn[i]>=0 && pPk->aiColumn[i]nCol ); p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName); pEList = sqlite3ExprListAppend(pParse, pEList, p); } pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); if( pLhs ){ pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0); } } } /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree ** and the SELECT subtree. */ pSrc->a[0].pTab = 0; pSelectSrc = sqlite3SrcListDup(db, pSrc, 0); pSrc->a[0].pTab = pTab; if( pSrc->a[0].fg.isIndexedBy ){ assert( pSrc->a[0].fg.isCte==0 ); pSrc->a[0].u2.pIBIndex = 0; pSrc->a[0].fg.isIndexedBy = 0; sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy); }else if( pSrc->a[0].fg.isCte ){ pSrc->a[0].u2.pCteUse->nUse++; } /* generate the SELECT expression tree. */ pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0, pOrderBy,0,pLimit ); /* now generate the new WHERE rowid IN clause for the DELETE/UPDATE */ pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0); sqlite3PExprAddSelect(pParse, pInClause, pSelect); return pInClause; } #endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) */ /* && !defined(SQLITE_OMIT_SUBQUERY) */ /* ** Generate code for a DELETE FROM statement. ** ** DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL; ** \________/ \________________/ ** pTabList pWhere */ SQLITE_PRIVATE void sqlite3DeleteFrom( Parse *pParse, /* The parser context */ SrcList *pTabList, /* The table from which we should delete things */ Expr *pWhere, /* The WHERE clause. May be null */ ExprList *pOrderBy, /* ORDER BY clause. May be null */ Expr *pLimit /* LIMIT clause. May be null */ ){ Vdbe *v; /* The virtual database engine */ Table *pTab; /* The table from which records will be deleted */ int i; /* Loop counter */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Index *pIdx; /* For looping over indices of the table */ int iTabCur; /* Cursor number for the table */ int iDataCur = 0; /* VDBE cursor for the canonical data source */ int iIdxCur = 0; /* Cursor number of the first index */ int nIdx; /* Number of indices */ sqlite3 *db; /* Main database structure */ AuthContext sContext; /* Authorization context */ NameContext sNC; /* Name context to resolve expressions in */ int iDb; /* Database number */ int memCnt = 0; /* Memory cell used for change counting */ int rcauth; /* Value returned by authorization callback */ int eOnePass; /* ONEPASS_OFF or _SINGLE or _MULTI */ int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ u8 *aToOpen = 0; /* Open cursor iTabCur+j if aToOpen[j] is true */ Index *pPk; /* The PRIMARY KEY index on the table */ int iPk = 0; /* First of nPk registers holding PRIMARY KEY value */ i16 nPk = 1; /* Number of columns in the PRIMARY KEY */ int iKey; /* Memory cell holding key of row to be deleted */ i16 nKey; /* Number of memory cells in the row key */ int iEphCur = 0; /* Ephemeral table holding all primary key values */ int iRowSet = 0; /* Register for rowset of rows to delete */ int addrBypass = 0; /* Address of jump over the delete logic */ int addrLoop = 0; /* Top of the delete loop */ int addrEphOpen = 0; /* Instruction to open the Ephemeral table */ int bComplex; /* True if there are triggers or FKs or ** subqueries in the WHERE clause */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ Trigger *pTrigger; /* List of table triggers, if required */ #endif memset(&sContext, 0, sizeof(sContext)); db = pParse->db; assert( db->pParse==pParse ); if( pParse->nErr ){ goto delete_from_cleanup; } assert( db->mallocFailed==0 ); assert( pTabList->nSrc==1 ); /* Locate the table which we want to delete. This table has to be ** put in an SrcList structure because some of the subroutines we ** will be calling are designed to work with multiple tables and expect ** an SrcList* parameter instead of just a Table* parameter. */ pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ) goto delete_from_cleanup; /* Figure out if we have any triggers and if the table being ** deleted from is a view */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); isView = IsView(pTab); #else # define pTrigger 0 # define isView 0 #endif bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0); #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x10000 ){ sqlite3TreeViewLine(0, "In sqlite3Delete() at %s:%d", __FILE__, __LINE__); sqlite3TreeViewDelete(pParse->pWith, pTabList, pWhere, pOrderBy, pLimit, pTrigger); } #endif #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( !isView ){ pWhere = sqlite3LimitWhere( pParse, pTabList, pWhere, pOrderBy, pLimit, "DELETE" ); pOrderBy = 0; pLimit = 0; } #endif /* If pTab is really a view, make sure it has been initialized. */ if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto delete_from_cleanup; } if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){ goto delete_from_cleanup; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDbnDb ); rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, db->aDb[iDb].zDbSName); assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE ); if( rcauth==SQLITE_DENY ){ goto delete_from_cleanup; } assert(!isView || pTrigger); /* Assign cursor numbers to the table and all its indices. */ assert( pTabList->nSrc==1 ); iTabCur = pTabList->a[0].iCursor = pParse->nTab++; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ pParse->nTab++; } /* Start the view context */ if( isView ){ sqlite3AuthContextPush(pParse, &sContext, pTab->zName); } /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto delete_from_cleanup; } if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, bComplex, iDb); /* If we are trying to delete from a view, realize that view into ** an ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( isView ){ sqlite3MaterializeView(pParse, pTab, pWhere, pOrderBy, pLimit, iTabCur ); iDataCur = iIdxCur = iTabCur; pOrderBy = 0; pLimit = 0; } #endif /* Resolve the column names in the WHERE clause. */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; if( sqlite3ResolveExprNames(&sNC, pWhere) ){ goto delete_from_cleanup; } /* Initialize the counter of the number of rows deleted, if ** we are counting rows. */ if( (db->flags & SQLITE_CountRows)!=0 && !pParse->nested && !pParse->pTriggerTab && !pParse->bReturning ){ memCnt = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); } #ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION /* Special case: A DELETE without a WHERE clause deletes everything. ** It is easier just to erase the whole table. Prior to version 3.6.5, ** this optimization caused the row change count (the value returned by ** API function sqlite3_count_changes) to be set incorrectly. ** ** The "rcauth==SQLITE_OK" terms is the ** IMPLEMENTATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and ** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but ** the truncate optimization is disabled and all rows are deleted ** individually. */ if( rcauth==SQLITE_OK && pWhere==0 && !bComplex && !IsVirtual(pTab) #ifdef SQLITE_ENABLE_PREUPDATE_HOOK && db->xPreUpdateCallback==0 #endif ){ assert( !isView ); sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); if( HasRowid(pTab) ){ sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt ? memCnt : -1, pTab->zName, P4_STATIC); } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->pSchema==pTab->pSchema ); if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Clear, pIdx->tnum, iDb, memCnt ? memCnt : -1); }else{ sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); } } }else #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ { u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK; if( sNC.ncFlags & NC_Subquery ) bComplex = 1; wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW); if( HasRowid(pTab) ){ /* For a rowid table, initialize the RowSet to an empty set */ pPk = 0; assert( nPk==1 ); iRowSet = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); }else{ /* For a WITHOUT ROWID table, create an ephemeral table used to ** hold all primary keys for rows to be deleted. */ pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); nPk = pPk->nKeyCol; iPk = pParse->nMem+1; pParse->nMem += nPk; iEphCur = pParse->nTab++; addrEphOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEphCur, nPk); sqlite3VdbeSetP4KeyInfo(pParse, pPk); } /* Construct a query to find the rowid or primary key for every row ** to be deleted, based on the WHERE clause. Set variable eOnePass ** to indicate the strategy used to implement this delete: ** ** ONEPASS_OFF: Two-pass approach - use a FIFO for rowids/PK values. ** ONEPASS_SINGLE: One-pass approach - at most one row deleted. ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted. */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,0,wcf,iTabCur+1); if( pWInfo==0 ) goto delete_from_cleanup; eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF || OptimizationDisabled(db, SQLITE_OnePass) ); if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse); if( sqlite3WhereUsesDeferredSeek(pWInfo) ){ sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur); } /* Keep track of the number of rows to be deleted */ if( memCnt ){ sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); } /* Extract the rowid or primary key for the current row */ if( pPk ){ for(i=0; iaiColumn[i]>=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i], iPk+i); } iKey = iPk; }else{ iKey = ++pParse->nMem; sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey); } if( eOnePass!=ONEPASS_OFF ){ /* For ONEPASS, no need to store the rowid/primary-key. There is only ** one, so just keep it in its register(s) and fall through to the ** delete code. */ nKey = nPk; /* OP_Found will use an unpacked key */ aToOpen = sqlite3DbMallocRawNN(db, nIdx+2); if( aToOpen==0 ){ sqlite3WhereEnd(pWInfo); goto delete_from_cleanup; } memset(aToOpen, 1, nIdx+1); aToOpen[nIdx+1] = 0; if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0; if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0; if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen); addrBypass = sqlite3VdbeMakeLabel(pParse); }else{ if( pPk ){ /* Add the PK key for this row to the temporary table */ iKey = ++pParse->nMem; nKey = 0; /* Zero tells OP_Found to use a composite key */ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey, sqlite3IndexAffinityStr(pParse->db, pPk), nPk); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk); }else{ /* Add the rowid of the row to be deleted to the RowSet */ nKey = 1; /* OP_DeferredSeek always uses a single rowid */ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); } sqlite3WhereEnd(pWInfo); } /* Unless this is a view, open cursors for the table we are ** deleting from and all its indices. If this is a view, then the ** only effect this statement has is to fire the INSTEAD OF ** triggers. */ if( !isView ){ int iAddrOnce = 0; if( eOnePass==ONEPASS_MULTI ){ iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } testcase( IsVirtual(pTab) ); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE, iTabCur, aToOpen, &iDataCur, &iIdxCur); assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur ); assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 ); if( eOnePass==ONEPASS_MULTI ){ sqlite3VdbeJumpHereOrPopInst(v, iAddrOnce); } } /* Set up a loop over the rowids/primary-keys that were found in the ** where-clause loop above. */ if( eOnePass!=ONEPASS_OFF ){ assert( nKey==nPk ); /* OP_Found will use an unpacked key */ if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){ assert( pPk!=0 || IsView(pTab) ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); VdbeCoverage(v); } }else if( pPk ){ addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v); if( IsVirtual(pTab) ){ sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey); }else{ sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey); } assert( nKey==0 ); /* OP_Found will use a composite key */ }else{ addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey); VdbeCoverage(v); assert( nKey==1 ); } /* Delete the row */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); sqlite3MayAbort(pParse); if( eOnePass==ONEPASS_SINGLE ){ sqlite3VdbeAddOp1(v, OP_Close, iTabCur); if( sqlite3IsToplevel(pParse) ){ pParse->isMultiWrite = 0; } } sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB); sqlite3VdbeChangeP5(v, OE_Abort); }else #endif { int count = (pParse->nested==0); /* True to count changes */ sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]); } /* End of the loop over all rowids/primary-keys. */ if( eOnePass!=ONEPASS_OFF ){ sqlite3VdbeResolveLabel(v, addrBypass); sqlite3WhereEnd(pWInfo); }else if( pPk ){ sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrLoop); }else{ sqlite3VdbeGoto(v, addrLoop); sqlite3VdbeJumpHere(v, addrLoop); } } /* End non-truncate path */ /* Update the sqlite_sequence table by storing the content of the ** maximum rowid counter values recorded while inserting into ** autoincrement tables. */ if( pParse->nested==0 && pParse->pTriggerTab==0 ){ sqlite3AutoincrementEnd(pParse); } /* Return the number of rows that were deleted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ if( memCnt ){ sqlite3CodeChangeCount(v, memCnt, "rows deleted"); } delete_from_cleanup: sqlite3AuthContextPop(&sContext); sqlite3SrcListDelete(db, pTabList); sqlite3ExprDelete(db, pWhere); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) sqlite3ExprListDelete(db, pOrderBy); sqlite3ExprDelete(db, pLimit); #endif if( aToOpen ) sqlite3DbNNFreeNN(db, aToOpen); return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView #endif #ifdef pTrigger #undef pTrigger #endif /* ** This routine generates VDBE code that causes a single row of a ** single table to be deleted. Both the original table entry and ** all indices are removed. ** ** Preconditions: ** ** 1. iDataCur is an open cursor on the btree that is the canonical data ** store for the table. (This will be either the table itself, ** in the case of a rowid table, or the PRIMARY KEY index in the case ** of a WITHOUT ROWID table.) ** ** 2. Read/write cursors for all indices of pTab must be open as ** cursor number iIdxCur+i for the i-th index. ** ** 3. The primary key for the row to be deleted must be stored in a ** sequence of nPk memory cells starting at iPk. If nPk==0 that means ** that a search record formed from OP_MakeRecord is contained in the ** single memory location iPk. ** ** eMode: ** Parameter eMode may be passed either ONEPASS_OFF (0), ONEPASS_SINGLE, or ** ONEPASS_MULTI. If eMode is not ONEPASS_OFF, then the cursor ** iDataCur already points to the row to delete. If eMode is ONEPASS_OFF ** then this function must seek iDataCur to the entry identified by iPk ** and nPk before reading from it. ** ** If eMode is ONEPASS_MULTI, then this call is being made as part ** of a ONEPASS delete that affects multiple rows. In this case, if ** iIdxNoSeek is a valid cursor number (>=0) and is not the same as ** iDataCur, then its position should be preserved following the delete ** operation. Or, if iIdxNoSeek is not a valid cursor number, the ** position of iDataCur should be preserved instead. ** ** iIdxNoSeek: ** If iIdxNoSeek is a valid cursor number (>=0) not equal to iDataCur, ** then it identifies an index cursor (from within array of cursors ** starting at iIdxCur) that already points to the index entry to be deleted. ** Except, this optimization is disabled if there are BEFORE triggers since ** the trigger body might have moved the cursor. */ SQLITE_PRIVATE void sqlite3GenerateRowDelete( Parse *pParse, /* Parsing context */ Table *pTab, /* Table containing the row to be deleted */ Trigger *pTrigger, /* List of triggers to (potentially) fire */ int iDataCur, /* Cursor from which column data is extracted */ int iIdxCur, /* First index cursor */ int iPk, /* First memory cell containing the PRIMARY KEY */ i16 nPk, /* Number of PRIMARY KEY memory cells */ u8 count, /* If non-zero, increment the row change counter */ u8 onconf, /* Default ON CONFLICT policy for triggers */ u8 eMode, /* ONEPASS_OFF, _SINGLE, or _MULTI. See above */ int iIdxNoSeek /* Cursor number of cursor that does not need seeking */ ){ Vdbe *v = pParse->pVdbe; /* Vdbe */ int iOld = 0; /* First register in OLD.* array */ int iLabel; /* Label resolved to end of generated code */ u8 opSeek; /* Seek opcode */ /* Vdbe is guaranteed to have been allocated by this stage. */ assert( v ); VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)", iDataCur, iIdxCur, iPk, (int)nPk)); /* Seek cursor iCur to the row to delete. If this row no longer exists ** (this can happen if a trigger program has already deleted it), do ** not attempt to delete it or fire any DELETE triggers. */ iLabel = sqlite3VdbeMakeLabel(pParse); opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound; if( eMode==ONEPASS_OFF ){ sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk); VdbeCoverageIf(v, opSeek==OP_NotExists); VdbeCoverageIf(v, opSeek==OP_NotFound); } /* If there are any triggers to fire, allocate a range of registers to ** use for the old.* references in the triggers. */ if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){ u32 mask; /* Mask of OLD.* columns in use */ int iCol; /* Iterator used while populating OLD.* */ int addrStart; /* Start of BEFORE trigger programs */ /* TODO: Could use temporary registers here. Also could attempt to ** avoid copying the contents of the rowid register. */ mask = sqlite3TriggerColmask( pParse, pTrigger, 0, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onconf ); mask |= sqlite3FkOldmask(pParse, pTab); iOld = pParse->nMem+1; pParse->nMem += (1 + pTab->nCol); /* Populate the OLD.* pseudo-table register array. These values will be ** used by any BEFORE and AFTER triggers that exist. */ sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld); for(iCol=0; iColnCol; iCol++){ testcase( mask!=0xffffffff && iCol==31 ); testcase( mask!=0xffffffff && iCol==32 ); if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){ int kk = sqlite3TableColumnToStorage(pTab, iCol); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+kk+1); } } /* Invoke BEFORE DELETE trigger programs. */ addrStart = sqlite3VdbeCurrentAddr(v); sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel ); /* If any BEFORE triggers were coded, then seek the cursor to the ** row to be deleted again. It may be that the BEFORE triggers moved ** the cursor or already deleted the row that the cursor was ** pointing to. ** ** Also disable the iIdxNoSeek optimization since the BEFORE trigger ** may have moved that cursor. */ if( addrStart=0 ); iIdxNoSeek = -1; } /* Do FK processing. This call checks that any FK constraints that ** refer to this table (i.e. constraints attached to other tables) ** are not violated by deleting this row. */ sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0); } /* Delete the index and table entries. Skip this step if pTab is really ** a view (in which case the only effect of the DELETE statement is to ** fire the INSTEAD OF triggers). ** ** If variable 'count' is non-zero, then this OP_Delete instruction should ** invoke the update-hook. The pre-update-hook, on the other hand should ** be invoked unless table pTab is a system table. The difference is that ** the update-hook is not invoked for rows removed by REPLACE, but the ** pre-update-hook is. */ if( !IsView(pTab) ){ u8 p5 = 0; sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){ sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE); } if( eMode!=ONEPASS_OFF ){ sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE); } if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){ sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek); } if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION; sqlite3VdbeChangeP5(v, p5); } /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to ** handle rows (possibly in other tables) that refer via a foreign key ** to the row just deleted. */ sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0); /* Invoke AFTER DELETE trigger programs. */ if( pTrigger ){ sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel ); } /* Jump here if the row had already been deleted before any BEFORE ** trigger programs were invoked. Or if a trigger program throws a ** RAISE(IGNORE) exception. */ sqlite3VdbeResolveLabel(v, iLabel); VdbeModuleComment((v, "END: GenRowDel()")); } /* ** This routine generates VDBE code that causes the deletion of all ** index entries associated with a single row of a single table, pTab ** ** Preconditions: ** ** 1. A read/write cursor "iDataCur" must be open on the canonical storage ** btree for the table pTab. (This will be either the table itself ** for rowid tables or to the primary key index for WITHOUT ROWID ** tables.) ** ** 2. Read/write cursors for all indices of pTab must be open as ** cursor number iIdxCur+i for the i-th index. (The pTab->pIndex ** index is the 0-th index.) ** ** 3. The "iDataCur" cursor must be already be positioned on the row ** that is to be deleted. */ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( Parse *pParse, /* Parsing and code generating context */ Table *pTab, /* Table containing the row to be deleted */ int iDataCur, /* Cursor of table holding data. */ int iIdxCur, /* First index cursor */ int *aRegIdx, /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */ int iIdxNoSeek /* Do not delete from this cursor */ ){ int i; /* Index loop counter */ int r1 = -1; /* Register holding an index key */ int iPartIdxLabel; /* Jump destination for skipping partial index entries */ Index *pIdx; /* Current index */ Index *pPrior = 0; /* Prior index */ Vdbe *v; /* The prepared statement under construction */ Index *pPk; /* PRIMARY KEY index, or NULL for rowid tables */ v = pParse->pVdbe; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ assert( iIdxCur+i!=iDataCur || pPk==pIdx ); if( aRegIdx!=0 && aRegIdx[i]==0 ) continue; if( pIdx==pPk ) continue; if( iIdxCur+i==iIdxNoSeek ) continue; VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName)); r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel, pPrior, r1); sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */ sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); pPrior = pIdx; } } /* ** Generate code that will assemble an index key and stores it in register ** regOut. The key with be for index pIdx which is an index on pTab. ** iCur is the index of a cursor open on the pTab table and pointing to ** the entry that needs indexing. If pTab is a WITHOUT ROWID table, then ** iCur must be the cursor of the PRIMARY KEY index. ** ** Return a register number which is the first in a block of ** registers that holds the elements of the index key. The ** block of registers has already been deallocated by the time ** this routine returns. ** ** If *piPartIdxLabel is not NULL, fill it in with a label and jump ** to that label if pIdx is a partial index that should be skipped. ** The label should be resolved using sqlite3ResolvePartIdxLabel(). ** A partial index should be skipped if its WHERE clause evaluates ** to false or null. If pIdx is not a partial index, *piPartIdxLabel ** will be set to zero which is an empty label that is ignored by ** sqlite3ResolvePartIdxLabel(). ** ** The pPrior and regPrior parameters are used to implement a cache to ** avoid unnecessary register loads. If pPrior is not NULL, then it is ** a pointer to a different index for which an index key has just been ** computed into register regPrior. If the current pIdx index is generating ** its key into the same sequence of registers and if pPrior and pIdx share ** a column in common, then the register corresponding to that column already ** holds the correct value and the loading of that register is skipped. ** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK ** on a table with multiple indices, and especially with the ROWID or ** PRIMARY KEY columns of the index. */ SQLITE_PRIVATE int sqlite3GenerateIndexKey( Parse *pParse, /* Parsing context */ Index *pIdx, /* The index for which to generate a key */ int iDataCur, /* Cursor number from which to take column data */ int regOut, /* Put the new key into this register if not 0 */ int prefixOnly, /* Compute only a unique prefix of the key */ int *piPartIdxLabel, /* OUT: Jump to this label to skip partial index */ Index *pPrior, /* Previously generated index key */ int regPrior /* Register holding previous generated key */ ){ Vdbe *v = pParse->pVdbe; int j; int regBase; int nCol; if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(pParse); pParse->iSelfTab = iDataCur + 1; sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); pParse->iSelfTab = 0; pPrior = 0; /* Ticket a9efb42811fa41ee 2019-11-02; ** pPartIdxWhere may have corrupted regPrior registers */ }else{ *piPartIdxLabel = 0; } } nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; regBase = sqlite3GetTempRange(pParse, nCol); if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0; for(j=0; jaiColumn[j]==pIdx->aiColumn[j] && pPrior->aiColumn[j]!=XN_EXPR ){ /* This column was already computed by the previous index */ continue; } sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j); if( pIdx->aiColumn[j]>=0 ){ /* If the column affinity is REAL but the number is an integer, then it ** might be stored in the table as an integer (using a compact ** representation) then converted to REAL by an OP_RealAffinity opcode. ** But we are getting ready to store this value back into an index, where ** it should be converted by to INTEGER again. So omit the ** OP_RealAffinity opcode if it is present */ sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity); } } if( regOut ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); } sqlite3ReleaseTempRange(pParse, regBase, nCol); return regBase; } /* ** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label ** because it was a partial index, then this routine should be called to ** resolve that label. */ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ if( iLabel ){ sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel); } } /************** End of delete.c **********************************************/ /************** Begin file func.c ********************************************/ /* ** 2002 February 23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C-language implementations for many of the SQL ** functions of SQLite. (Some function, and in particular the date and ** time functions, are implemented separately.) */ /* #include "sqliteInt.h" */ /* #include */ /* #include */ #ifndef SQLITE_OMIT_FLOATING_POINT /* #include */ #endif /* #include "vdbeInt.h" */ /* ** Return the collating function associated with a function. */ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ VdbeOp *pOp; assert( context->pVdbe!=0 ); pOp = &context->pVdbe->aOp[context->iOp-1]; assert( pOp->opcode==OP_CollSeq ); assert( pOp->p4type==P4_COLLSEQ ); return pOp->p4.pColl; } /* ** Indicate that the accumulator load should be skipped on this ** iteration of the aggregate loop. */ static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){ assert( context->isError<=0 ); context->isError = -1; context->skipFlag = 1; } /* ** Implementation of the non-aggregate min() and max() functions */ static void minmaxFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int i; int mask; /* 0 for min() or 0xffffffff for max() */ int iBest; CollSeq *pColl; assert( argc>1 ); mask = sqlite3_user_data(context)==0 ? 0 : -1; pColl = sqlite3GetFuncCollSeq(context); assert( pColl ); assert( mask==-1 || mask==0 ); iBest = 0; if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; for(i=1; i=0 ){ testcase( mask==0 ); iBest = i; } } sqlite3_result_value(context, argv[iBest]); } /* ** Return the type of the argument. */ static void typeofFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ static const char *azType[] = { "integer", "real", "text", "blob", "null" }; int i = sqlite3_value_type(argv[0]) - 1; UNUSED_PARAMETER(NotUsed); assert( i>=0 && i=0xc0 ){ while( (*z & 0xc0)==0x80 ){ z++; z0++; } } } sqlite3_result_int(context, (int)(z-z0)); break; } default: { sqlite3_result_null(context); break; } } } /* ** Implementation of the octet_length() function */ static void bytelengthFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ assert( argc==1 ); UNUSED_PARAMETER(argc); switch( sqlite3_value_type(argv[0]) ){ case SQLITE_BLOB: { sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); break; } case SQLITE_INTEGER: case SQLITE_FLOAT: { i64 m = sqlite3_context_db_handle(context)->enc<=SQLITE_UTF8 ? 1 : 2; sqlite3_result_int64(context, sqlite3_value_bytes(argv[0])*m); break; } case SQLITE_TEXT: { if( sqlite3_value_encoding(argv[0])<=SQLITE_UTF8 ){ sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); }else{ sqlite3_result_int(context, sqlite3_value_bytes16(argv[0])); } break; } default: { sqlite3_result_null(context); break; } } } /* ** Implementation of the abs() function. ** ** IMP: R-23979-26855 The abs(X) function returns the absolute value of ** the numeric argument X. */ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ assert( argc==1 ); UNUSED_PARAMETER(argc); switch( sqlite3_value_type(argv[0]) ){ case SQLITE_INTEGER: { i64 iVal = sqlite3_value_int64(argv[0]); if( iVal<0 ){ if( iVal==SMALLEST_INT64 ){ /* IMP: R-31676-45509 If X is the integer -9223372036854775808 ** then abs(X) throws an integer overflow error since there is no ** equivalent positive 64-bit two complement value. */ sqlite3_result_error(context, "integer overflow", -1); return; } iVal = -iVal; } sqlite3_result_int64(context, iVal); break; } case SQLITE_NULL: { /* IMP: R-37434-19929 Abs(X) returns NULL if X is NULL. */ sqlite3_result_null(context); break; } default: { /* Because sqlite3_value_double() returns 0.0 if the argument is not ** something that can be converted into a number, we have: ** IMP: R-01992-00519 Abs(X) returns 0.0 if X is a string or blob ** that cannot be converted to a numeric value. */ double rVal = sqlite3_value_double(argv[0]); if( rVal<0 ) rVal = -rVal; sqlite3_result_double(context, rVal); break; } } } /* ** Implementation of the instr() function. ** ** instr(haystack,needle) finds the first occurrence of needle ** in haystack and returns the number of previous characters plus 1, ** or 0 if needle does not occur within haystack. ** ** If both haystack and needle are BLOBs, then the result is one more than ** the number of bytes in haystack prior to the first occurrence of needle, ** or 0 if needle never occurs in haystack. */ static void instrFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zHaystack; const unsigned char *zNeedle; int nHaystack; int nNeedle; int typeHaystack, typeNeedle; int N = 1; int isText; unsigned char firstChar; sqlite3_value *pC1 = 0; sqlite3_value *pC2 = 0; UNUSED_PARAMETER(argc); typeHaystack = sqlite3_value_type(argv[0]); typeNeedle = sqlite3_value_type(argv[1]); if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return; nHaystack = sqlite3_value_bytes(argv[0]); nNeedle = sqlite3_value_bytes(argv[1]); if( nNeedle>0 ){ if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ zHaystack = sqlite3_value_blob(argv[0]); zNeedle = sqlite3_value_blob(argv[1]); isText = 0; }else if( typeHaystack!=SQLITE_BLOB && typeNeedle!=SQLITE_BLOB ){ zHaystack = sqlite3_value_text(argv[0]); zNeedle = sqlite3_value_text(argv[1]); isText = 1; }else{ pC1 = sqlite3_value_dup(argv[0]); zHaystack = sqlite3_value_text(pC1); if( zHaystack==0 ) goto endInstrOOM; nHaystack = sqlite3_value_bytes(pC1); pC2 = sqlite3_value_dup(argv[1]); zNeedle = sqlite3_value_text(pC2); if( zNeedle==0 ) goto endInstrOOM; nNeedle = sqlite3_value_bytes(pC2); isText = 1; } if( zNeedle==0 || (nHaystack && zHaystack==0) ) goto endInstrOOM; firstChar = zNeedle[0]; while( nNeedle<=nHaystack && (zHaystack[0]!=firstChar || memcmp(zHaystack, zNeedle, nNeedle)!=0) ){ N++; do{ nHaystack--; zHaystack++; }while( isText && (zHaystack[0]&0xc0)==0x80 ); } if( nNeedle>nHaystack ) N = 0; } sqlite3_result_int(context, N); endInstr: sqlite3_value_free(pC1); sqlite3_value_free(pC2); return; endInstrOOM: sqlite3_result_error_nomem(context); goto endInstr; } /* ** Implementation of the printf() (a.k.a. format()) SQL function. */ static void printfFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ PrintfArguments x; StrAccum str; const char *zFormat; int n; sqlite3 *db = sqlite3_context_db_handle(context); if( argc>=1 && (zFormat = (const char*)sqlite3_value_text(argv[0]))!=0 ){ x.nArg = argc-1; x.nUsed = 0; x.apArg = argv+1; sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); str.printfFlags = SQLITE_PRINTF_SQLFUNC; sqlite3_str_appendf(&str, zFormat, &x); n = str.nChar; sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, SQLITE_DYNAMIC); } } /* ** Implementation of the substr() function. ** ** substr(x,p1,p2) returns p2 characters of x[] beginning with p1. ** p1 is 1-indexed. So substr(x,1,1) returns the first character ** of x. If x is text, then we actually count UTF-8 characters. ** If x is a blob, then we count bytes. ** ** If p1 is negative, then we begin abs(p1) from the end of x[]. ** ** If p2 is negative, return the p2 characters preceding p1. */ static void substrFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *z; const unsigned char *z2; int len; int p0type; i64 p1, p2; int negP2 = 0; assert( argc==3 || argc==2 ); if( sqlite3_value_type(argv[1])==SQLITE_NULL || (argc==3 && sqlite3_value_type(argv[2])==SQLITE_NULL) ){ return; } p0type = sqlite3_value_type(argv[0]); p1 = sqlite3_value_int(argv[1]); if( p0type==SQLITE_BLOB ){ len = sqlite3_value_bytes(argv[0]); z = sqlite3_value_blob(argv[0]); if( z==0 ) return; assert( len==sqlite3_value_bytes(argv[0]) ); }else{ z = sqlite3_value_text(argv[0]); if( z==0 ) return; len = 0; if( p1<0 ){ for(z2=z; *z2; len++){ SQLITE_SKIP_UTF8(z2); } } } #ifdef SQLITE_SUBSTR_COMPATIBILITY /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as ** as substr(X,1,N) - it returns the first N characters of X. This ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8] ** from 2009-02-02 for compatibility of applications that exploited the ** old buggy behavior. */ if( p1==0 ) p1 = 1; /* */ #endif if( argc==3 ){ p2 = sqlite3_value_int(argv[2]); if( p2<0 ){ p2 = -p2; negP2 = 1; } }else{ p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH]; } if( p1<0 ){ p1 += len; if( p1<0 ){ p2 += p1; if( p2<0 ) p2 = 0; p1 = 0; } }else if( p1>0 ){ p1--; }else if( p2>0 ){ p2--; } if( negP2 ){ p1 -= p2; if( p1<0 ){ p2 += p1; p1 = 0; } } assert( p1>=0 && p2>=0 ); if( p0type!=SQLITE_BLOB ){ while( *z && p1 ){ SQLITE_SKIP_UTF8(z); p1--; } for(z2=z; *z2 && p2; p2--){ SQLITE_SKIP_UTF8(z2); } sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT, SQLITE_UTF8); }else{ if( p1+p2>len ){ p2 = len-p1; if( p2<0 ) p2 = 0; } sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT); } } /* ** Implementation of the round() function */ #ifndef SQLITE_OMIT_FLOATING_POINT static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ int n = 0; double r; char *zBuf; assert( argc==1 || argc==2 ); if( argc==2 ){ if( SQLITE_NULL==sqlite3_value_type(argv[1]) ) return; n = sqlite3_value_int(argv[1]); if( n>30 ) n = 30; if( n<0 ) n = 0; } if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; r = sqlite3_value_double(argv[0]); /* If Y==0 and X will fit in a 64-bit int, ** handle the rounding directly, ** otherwise use printf. */ if( r<-4503599627370496.0 || r>+4503599627370496.0 ){ /* The value has no fractional part so there is nothing to round */ }else if( n==0 ){ r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5))); }else{ zBuf = sqlite3_mprintf("%!.*f",n,r); if( zBuf==0 ){ sqlite3_result_error_nomem(context); return; } sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8); sqlite3_free(zBuf); } sqlite3_result_double(context, r); } #endif /* ** Allocate nByte bytes of space using sqlite3Malloc(). If the ** allocation fails, call sqlite3_result_error_nomem() to notify ** the database handle that malloc() has failed and return NULL. ** If nByte is larger than the maximum string or blob length, then ** raise an SQLITE_TOOBIG exception and return NULL. */ static void *contextMalloc(sqlite3_context *context, i64 nByte){ char *z; sqlite3 *db = sqlite3_context_db_handle(context); assert( nByte>0 ); testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH] ); testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(context); z = 0; }else{ z = sqlite3Malloc(nByte); if( !z ){ sqlite3_result_error_nomem(context); } } return z; } /* ** Implementation of the upper() and lower() SQL functions. */ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ char *z1; const char *z2; int i, n; UNUSED_PARAMETER(argc); z2 = (char*)sqlite3_value_text(argv[0]); n = sqlite3_value_bytes(argv[0]); /* Verify that the call to _bytes() does not invalidate the _text() pointer */ assert( z2==(char*)sqlite3_value_text(argv[0]) ); if( z2 ){ z1 = contextMalloc(context, ((i64)n)+1); if( z1 ){ for(i=0; imatchOne; /* "?" or "_" */ u32 matchAll = pInfo->matchAll; /* "*" or "%" */ u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */ const u8 *zEscaped = 0; /* One past the last escaped input char */ while( (c = Utf8Read(zPattern))!=0 ){ if( c==matchAll ){ /* Match "*" */ /* Skip over multiple "*" characters in the pattern. If there ** are also "?" characters, skip those as well, but consume a ** single character of the input string for each "?" skipped */ while( (c=Utf8Read(zPattern)) == matchAll || (c == matchOne && matchOne!=0) ){ if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){ return SQLITE_NOWILDCARDMATCH; } } if( c==0 ){ return SQLITE_MATCH; /* "*" at the end of the pattern matches */ }else if( c==matchOther ){ if( pInfo->matchSet==0 ){ c = sqlite3Utf8Read(&zPattern); if( c==0 ) return SQLITE_NOWILDCARDMATCH; }else{ /* "[...]" immediately follows the "*". We have to do a slow ** recursive search in this case, but it is an unusual case. */ assert( matchOther<0x80 ); /* '[' is a single-byte character */ while( *zString ){ int bMatch = patternCompare(&zPattern[-1],zString,pInfo,matchOther); if( bMatch!=SQLITE_NOMATCH ) return bMatch; SQLITE_SKIP_UTF8(zString); } return SQLITE_NOWILDCARDMATCH; } } /* At this point variable c contains the first character of the ** pattern string past the "*". Search in the input string for the ** first matching character and recursively continue the match from ** that point. ** ** For a case-insensitive search, set variable cx to be the same as ** c but in the other case and search the input string for either ** c or cx. */ if( c<0x80 ){ char zStop[3]; int bMatch; if( noCase ){ zStop[0] = sqlite3Toupper(c); zStop[1] = sqlite3Tolower(c); zStop[2] = 0; }else{ zStop[0] = c; zStop[1] = 0; } while(1){ zString += strcspn((const char*)zString, zStop); if( zString[0]==0 ) break; zString++; bMatch = patternCompare(zPattern,zString,pInfo,matchOther); if( bMatch!=SQLITE_NOMATCH ) return bMatch; } }else{ int bMatch; while( (c2 = Utf8Read(zString))!=0 ){ if( c2!=c ) continue; bMatch = patternCompare(zPattern,zString,pInfo,matchOther); if( bMatch!=SQLITE_NOMATCH ) return bMatch; } } return SQLITE_NOWILDCARDMATCH; } if( c==matchOther ){ if( pInfo->matchSet==0 ){ c = sqlite3Utf8Read(&zPattern); if( c==0 ) return SQLITE_NOMATCH; zEscaped = zPattern; }else{ u32 prior_c = 0; int seen = 0; int invert = 0; c = sqlite3Utf8Read(&zString); if( c==0 ) return SQLITE_NOMATCH; c2 = sqlite3Utf8Read(&zPattern); if( c2=='^' ){ invert = 1; c2 = sqlite3Utf8Read(&zPattern); } if( c2==']' ){ if( c==']' ) seen = 1; c2 = sqlite3Utf8Read(&zPattern); } while( c2 && c2!=']' ){ if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ c2 = sqlite3Utf8Read(&zPattern); if( c>=prior_c && c<=c2 ) seen = 1; prior_c = 0; }else{ if( c==c2 ){ seen = 1; } prior_c = c2; } c2 = sqlite3Utf8Read(&zPattern); } if( c2==0 || (seen ^ invert)==0 ){ return SQLITE_NOMATCH; } continue; } } c2 = Utf8Read(zString); if( c==c2 ) continue; if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){ continue; } if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; return SQLITE_NOMATCH; } return *zString==0 ? SQLITE_MATCH : SQLITE_NOMATCH; } /* ** The sqlite3_strglob() interface. Return 0 on a match (like strcmp()) and ** non-zero if there is no match. */ SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){ if( zString==0 ){ return zGlobPattern!=0; }else if( zGlobPattern==0 ){ return 1; }else { return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '['); } } /* ** The sqlite3_strlike() interface. Return 0 on a match and non-zero for ** a miss - like strcmp(). */ SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){ if( zStr==0 ){ return zPattern!=0; }else if( zPattern==0 ){ return 1; }else{ return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc); } } /* ** Count the number of times that the LIKE operator (or GLOB which is ** just a variation of LIKE) gets called. This is used for testing ** only. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_like_count = 0; #endif /* ** Implementation of the like() SQL function. This function implements ** the built-in LIKE operator. The first argument to the function is the ** pattern and the second argument is the string. So, the SQL statements: ** ** A LIKE B ** ** is implemented as like(B,A). ** ** This same function (with a different compareInfo structure) computes ** the GLOB operator. */ static void likeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zA, *zB; u32 escape; int nPat; sqlite3 *db = sqlite3_context_db_handle(context); struct compareInfo *pInfo = sqlite3_user_data(context); struct compareInfo backupInfo; #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( sqlite3_value_type(argv[0])==SQLITE_BLOB || sqlite3_value_type(argv[1])==SQLITE_BLOB ){ #ifdef SQLITE_TEST sqlite3_like_count++; #endif sqlite3_result_int(context, 0); return; } #endif /* Limit the length of the LIKE or GLOB pattern to avoid problems ** of deep recursion and N*N behavior in patternCompare(). */ nPat = sqlite3_value_bytes(argv[0]); testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ); testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]+1 ); if( nPat > db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ){ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); return; } if( argc==3 ){ /* The escape character string must consist of a single UTF-8 character. ** Otherwise, return an error. */ const unsigned char *zEsc = sqlite3_value_text(argv[2]); if( zEsc==0 ) return; if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){ sqlite3_result_error(context, "ESCAPE expression must be a single character", -1); return; } escape = sqlite3Utf8Read(&zEsc); if( escape==pInfo->matchAll || escape==pInfo->matchOne ){ memcpy(&backupInfo, pInfo, sizeof(backupInfo)); pInfo = &backupInfo; if( escape==pInfo->matchAll ) pInfo->matchAll = 0; if( escape==pInfo->matchOne ) pInfo->matchOne = 0; } }else{ escape = pInfo->matchSet; } zB = sqlite3_value_text(argv[0]); zA = sqlite3_value_text(argv[1]); if( zA && zB ){ #ifdef SQLITE_TEST sqlite3_like_count++; #endif sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); } } /* ** Implementation of the NULLIF(x,y) function. The result is the first ** argument if the arguments are different. The result is NULL if the ** arguments are equal to each other. */ static void nullifFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ CollSeq *pColl = sqlite3GetFuncCollSeq(context); UNUSED_PARAMETER(NotUsed); if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){ sqlite3_result_value(context, argv[0]); } } /* ** Implementation of the sqlite_version() function. The result is the version ** of the SQLite library that is running. */ static void versionFunc( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ UNUSED_PARAMETER2(NotUsed, NotUsed2); /* IMP: R-48699-48617 This function is an SQL wrapper around the ** sqlite3_libversion() C-interface. */ sqlite3_result_text(context, sqlite3_libversion(), -1, SQLITE_STATIC); } /* ** Implementation of the sqlite_source_id() function. The result is a string ** that identifies the particular version of the source code used to build ** SQLite. */ static void sourceidFunc( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ UNUSED_PARAMETER2(NotUsed, NotUsed2); /* IMP: R-24470-31136 This function is an SQL wrapper around the ** sqlite3_sourceid() C interface. */ sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC); } /* ** Implementation of the sqlite_log() function. This is a wrapper around ** sqlite3_log(). The return value is NULL. The function exists purely for ** its side-effects. */ static void errlogFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ UNUSED_PARAMETER(argc); UNUSED_PARAMETER(context); sqlite3_log(sqlite3_value_int(argv[0]), "%s", sqlite3_value_text(argv[1])); } /* ** Implementation of the sqlite_compileoption_used() function. ** The result is an integer that identifies if the compiler option ** was used to build SQLite. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS static void compileoptionusedFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zOptName; assert( argc==1 ); UNUSED_PARAMETER(argc); /* IMP: R-39564-36305 The sqlite_compileoption_used() SQL ** function is a wrapper around the sqlite3_compileoption_used() C/C++ ** function. */ if( (zOptName = (const char*)sqlite3_value_text(argv[0]))!=0 ){ sqlite3_result_int(context, sqlite3_compileoption_used(zOptName)); } } #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ /* ** Implementation of the sqlite_compileoption_get() function. ** The result is a string that identifies the compiler options ** used to build SQLite. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS static void compileoptiongetFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int n; assert( argc==1 ); UNUSED_PARAMETER(argc); /* IMP: R-04922-24076 The sqlite_compileoption_get() SQL function ** is a wrapper around the sqlite3_compileoption_get() C/C++ function. */ n = sqlite3_value_int(argv[0]); sqlite3_result_text(context, sqlite3_compileoption_get(n), -1, SQLITE_STATIC); } #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ /* Array for converting from half-bytes (nybbles) into ASCII hex ** digits. */ static const char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /* ** Append to pStr text that is the SQL literal representation of the ** value contained in pValue. */ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ /* As currently implemented, the string must be initially empty. ** we might relax this requirement in the future, but that will ** require enhancements to the implementation. */ assert( pStr!=0 && pStr->nChar==0 ); switch( sqlite3_value_type(pValue) ){ case SQLITE_FLOAT: { double r1, r2; const char *zVal; r1 = sqlite3_value_double(pValue); sqlite3_str_appendf(pStr, "%!.15g", r1); zVal = sqlite3_str_value(pStr); if( zVal ){ sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8); if( r1!=r2 ){ sqlite3_str_reset(pStr); sqlite3_str_appendf(pStr, "%!.20e", r1); } } break; } case SQLITE_INTEGER: { sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pValue)); break; } case SQLITE_BLOB: { char const *zBlob = sqlite3_value_blob(pValue); i64 nBlob = sqlite3_value_bytes(pValue); assert( zBlob==sqlite3_value_blob(pValue) ); /* No encoding change */ sqlite3StrAccumEnlarge(pStr, nBlob*2 + 4); if( pStr->accError==0 ){ char *zText = pStr->zText; int i; for(i=0; i>4)&0x0F]; zText[(i*2)+3] = hexdigits[(zBlob[i])&0x0F]; } zText[(nBlob*2)+2] = '\''; zText[(nBlob*2)+3] = '\0'; zText[0] = 'X'; zText[1] = '\''; pStr->nChar = nBlob*2 + 3; } break; } case SQLITE_TEXT: { const unsigned char *zArg = sqlite3_value_text(pValue); sqlite3_str_appendf(pStr, "%Q", zArg); break; } default: { assert( sqlite3_value_type(pValue)==SQLITE_NULL ); sqlite3_str_append(pStr, "NULL", 4); break; } } } /* ** Implementation of the QUOTE() function. ** ** The quote(X) function returns the text of an SQL literal which is the ** value of its argument suitable for inclusion into an SQL statement. ** Strings are surrounded by single-quotes with escapes on interior quotes ** as needed. BLOBs are encoded as hexadecimal literals. Strings with ** embedded NUL characters cannot be represented as string literals in SQL ** and hence the returned string literal is truncated prior to the first NUL. */ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_str str; sqlite3 *db = sqlite3_context_db_handle(context); assert( argc==1 ); UNUSED_PARAMETER(argc); sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); sqlite3QuoteValue(&str,argv[0]); sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar, SQLITE_DYNAMIC); if( str.accError!=SQLITE_OK ){ sqlite3_result_null(context); sqlite3_result_error_code(context, str.accError); } } /* ** The unicode() function. Return the integer unicode code-point value ** for the first character of the input string. */ static void unicodeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *z = sqlite3_value_text(argv[0]); (void)argc; if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z)); } /* ** The char() function takes zero or more arguments, each of which is ** an integer. It constructs a string where each character of the string ** is the unicode character for the corresponding integer argument. */ static void charFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ unsigned char *z, *zOut; int i; zOut = z = sqlite3_malloc64( argc*4+1 ); if( z==0 ){ sqlite3_result_error_nomem(context); return; } for(i=0; i0x10ffff ) x = 0xfffd; c = (unsigned)(x & 0x1fffff); if( c<0x00080 ){ *zOut++ = (u8)(c&0xFF); }else if( c<0x00800 ){ *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); *zOut++ = 0x80 + (u8)(c & 0x3F); }else if( c<0x10000 ){ *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); *zOut++ = 0x80 + (u8)(c & 0x3F); }else{ *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); *zOut++ = 0x80 + (u8)(c & 0x3F); } \ } *zOut = 0; sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8); } /* ** The hex() function. Interpret the argument as a blob. Return ** a hexadecimal rendering as text. */ static void hexFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int i, n; const unsigned char *pBlob; char *zHex, *z; assert( argc==1 ); UNUSED_PARAMETER(argc); pBlob = sqlite3_value_blob(argv[0]); n = sqlite3_value_bytes(argv[0]); assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ z = zHex = contextMalloc(context, ((i64)n)*2 + 1); if( zHex ){ for(i=0; i>4)&0xf]; *(z++) = hexdigits[c&0xf]; } *z = 0; sqlite3_result_text64(context, zHex, (u64)(z-zHex), sqlite3_free, SQLITE_UTF8); } } /* ** Buffer zStr contains nStr bytes of utf-8 encoded text. Return 1 if zStr ** contains character ch, or 0 if it does not. */ static int strContainsChar(const u8 *zStr, int nStr, u32 ch){ const u8 *zEnd = &zStr[nStr]; const u8 *z = zStr; while( zmallocFailed ); return; } if( zPattern[0]==0 ){ assert( sqlite3_value_type(argv[1])!=SQLITE_NULL ); sqlite3_result_value(context, argv[0]); return; } nPattern = sqlite3_value_bytes(argv[1]); assert( zPattern==sqlite3_value_text(argv[1]) ); /* No encoding change */ zRep = sqlite3_value_text(argv[2]); if( zRep==0 ) return; nRep = sqlite3_value_bytes(argv[2]); assert( zRep==sqlite3_value_text(argv[2]) ); nOut = nStr + 1; assert( nOutnPattern ){ nOut += nRep - nPattern; testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] ); testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] ); if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(context); sqlite3_free(zOut); return; } cntExpand++; if( (cntExpand&(cntExpand-1))==0 ){ /* Grow the size of the output buffer only on substitutions ** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */ u8 *zOld; zOld = zOut; zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1)); if( zOut==0 ){ sqlite3_result_error_nomem(context); sqlite3_free(zOld); return; } } } memcpy(&zOut[j], zRep, nRep); j += nRep; i += nPattern-1; } } assert( j+nStr-i+1<=nOut ); memcpy(&zOut[j], &zStr[i], nStr-i); j += nStr - i; assert( j<=nOut ); zOut[j] = 0; sqlite3_result_text(context, (char*)zOut, j, sqlite3_free); } /* ** Implementation of the TRIM(), LTRIM(), and RTRIM() functions. ** The userdata is 0x1 for left trim, 0x2 for right trim, 0x3 for both. */ static void trimFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zIn; /* Input string */ const unsigned char *zCharSet; /* Set of characters to trim */ unsigned int nIn; /* Number of bytes in input */ int flags; /* 1: trimleft 2: trimright 3: trim */ int i; /* Loop counter */ unsigned int *aLen = 0; /* Length of each character in zCharSet */ unsigned char **azChar = 0; /* Individual characters in zCharSet */ int nChar; /* Number of characters in zCharSet */ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ return; } zIn = sqlite3_value_text(argv[0]); if( zIn==0 ) return; nIn = (unsigned)sqlite3_value_bytes(argv[0]); assert( zIn==sqlite3_value_text(argv[0]) ); if( argc==1 ){ static const unsigned lenOne[] = { 1 }; static unsigned char * const azOne[] = { (u8*)" " }; nChar = 1; aLen = (unsigned*)lenOne; azChar = (unsigned char **)azOne; zCharSet = 0; }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){ return; }else{ const unsigned char *z; for(z=zCharSet, nChar=0; *z; nChar++){ SQLITE_SKIP_UTF8(z); } if( nChar>0 ){ azChar = contextMalloc(context, ((i64)nChar)*(sizeof(char*)+sizeof(unsigned))); if( azChar==0 ){ return; } aLen = (unsigned*)&azChar[nChar]; for(z=zCharSet, nChar=0; *z; nChar++){ azChar[nChar] = (unsigned char *)z; SQLITE_SKIP_UTF8(z); aLen[nChar] = (unsigned)(z - azChar[nChar]); } } } if( nChar>0 ){ flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context)); if( flags & 1 ){ while( nIn>0 ){ unsigned int len = 0; for(i=0; i=nChar ) break; zIn += len; nIn -= len; } } if( flags & 2 ){ while( nIn>0 ){ unsigned int len = 0; for(i=0; i=nChar ) break; nIn -= len; } } if( zCharSet ){ sqlite3_free(azChar); } } sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); } /* The core implementation of the CONCAT(...) and CONCAT_WS(SEP,...) ** functions. ** ** Return a string value that is the concatenation of all non-null ** entries in argv[]. Use zSep as the separator. */ static void concatFuncCore( sqlite3_context *context, int argc, sqlite3_value **argv, int nSep, const char *zSep ){ i64 j, k, n = 0; int i; char *z; for(i=0; i0 ){ const char *v = (const char*)sqlite3_value_text(argv[i]); if( v!=0 ){ if( j>0 && nSep>0 ){ memcpy(&z[j], zSep, nSep); j += nSep; } memcpy(&z[j], v, k); j += k; } } } z[j] = 0; assert( j<=n ); sqlite3_result_text64(context, z, j, sqlite3_free, SQLITE_UTF8); } /* ** The CONCAT(...) function. Generate a string result that is the ** concatentation of all non-null arguments. */ static void concatFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ concatFuncCore(context, argc, argv, 0, ""); } /* ** The CONCAT_WS(separator, ...) function. ** ** Generate a string that is the concatenation of 2nd through the Nth ** argument. Use the first argument (which must be non-NULL) as the ** separator. */ static void concatwsFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int nSep = sqlite3_value_bytes(argv[0]); const char *zSep = (const char*)sqlite3_value_text(argv[0]); if( zSep==0 ) return; concatFuncCore(context, argc-1, argv+1, nSep, zSep); } #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION /* ** The "unknown" function is automatically substituted in place of ** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN ** when the SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION compile-time option is used. ** When the "sqlite3" command-line shell is built using this functionality, ** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries ** involving application-defined functions to be examined in a generic ** sqlite3 shell. */ static void unknownFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ /* no-op */ (void)context; (void)argc; (void)argv; } #endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/ /* IMP: R-25361-16150 This function is omitted from SQLite by default. It ** is only available if the SQLITE_SOUNDEX compile-time option is used ** when SQLite is built. */ #ifdef SQLITE_SOUNDEX /* ** Compute the soundex encoding of a word. ** ** IMP: R-59782-00072 The soundex(X) function returns a string that is the ** soundex encoding of the string X. */ static void soundexFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ char zResult[8]; const u8 *zIn; int i, j; static const unsigned char iCode[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, }; assert( argc==1 ); zIn = (u8*)sqlite3_value_text(argv[0]); if( zIn==0 ) zIn = (u8*)""; for(i=0; zIn[i] && !sqlite3Isalpha(zIn[i]); i++){} if( zIn[i] ){ u8 prevcode = iCode[zIn[i]&0x7f]; zResult[0] = sqlite3Toupper(zIn[i]); for(j=1; j<4 && zIn[i]; i++){ int code = iCode[zIn[i]&0x7f]; if( code>0 ){ if( code!=prevcode ){ prevcode = code; zResult[j++] = code + '0'; } }else{ prevcode = 0; } } while( j<4 ){ zResult[j++] = '0'; } zResult[j] = 0; sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT); }else{ /* IMP: R-64894-50321 The string "?000" is returned if the argument ** is NULL or contains no ASCII alphabetic characters. */ sqlite3_result_text(context, "?000", 4, SQLITE_STATIC); } } #endif /* SQLITE_SOUNDEX */ #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** A function that loads a shared-library extension then returns NULL. */ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){ const char *zFile = (const char *)sqlite3_value_text(argv[0]); const char *zProc; sqlite3 *db = sqlite3_context_db_handle(context); char *zErrMsg = 0; /* Disallow the load_extension() SQL function unless the SQLITE_LoadExtFunc ** flag is set. See the sqlite3_enable_load_extension() API. */ if( (db->flags & SQLITE_LoadExtFunc)==0 ){ sqlite3_result_error(context, "not authorized", -1); return; } if( argc==2 ){ zProc = (const char *)sqlite3_value_text(argv[1]); }else{ zProc = 0; } if( zFile && sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){ sqlite3_result_error(context, zErrMsg, -1); sqlite3_free(zErrMsg); } } #endif /* ** An instance of the following structure holds the context of a ** sum() or avg() aggregate computation. */ typedef struct SumCtx SumCtx; struct SumCtx { double rSum; /* Running sum as as a double */ double rErr; /* Error term for Kahan-Babushka-Neumaier summation */ i64 iSum; /* Running sum as a signed integer */ i64 cnt; /* Number of elements summed */ u8 approx; /* True if any non-integer value was input to the sum */ u8 ovrfl; /* Integer overflow seen */ }; /* ** Do one step of the Kahan-Babushka-Neumaier summation. ** ** https://en.wikipedia.org/wiki/Kahan_summation_algorithm ** ** Variables are marked "volatile" to defeat c89 x86 floating point ** optimizations can mess up this algorithm. */ static void kahanBabuskaNeumaierStep( volatile SumCtx *pSum, volatile double r ){ volatile double s = pSum->rSum; volatile double t = s + r; if( fabs(s) > fabs(r) ){ pSum->rErr += (s - t) + r; }else{ pSum->rErr += (r - t) + s; } pSum->rSum = t; } /* ** Add a (possibly large) integer to the running sum. */ static void kahanBabuskaNeumaierStepInt64(volatile SumCtx *pSum, i64 iVal){ if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){ i64 iBig, iSm; iSm = iVal % 16384; iBig = iVal - iSm; kahanBabuskaNeumaierStep(pSum, iBig); kahanBabuskaNeumaierStep(pSum, iSm); }else{ kahanBabuskaNeumaierStep(pSum, (double)iVal); } } /* ** Initialize the Kahan-Babaska-Neumaier sum from a 64-bit integer */ static void kahanBabuskaNeumaierInit( volatile SumCtx *p, i64 iVal ){ if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){ i64 iSm = iVal % 16384; p->rSum = (double)(iVal - iSm); p->rErr = (double)iSm; }else{ p->rSum = (double)iVal; p->rErr = 0.0; } } /* ** Routines used to compute the sum, average, and total. ** ** The SUM() function follows the (broken) SQL standard which means ** that it returns NULL if it sums over no inputs. TOTAL returns ** 0.0 in that case. In addition, TOTAL always returns a float where ** SUM might return an integer if it never encounters a floating point ** value. TOTAL never fails, but SUM might through an exception if ** it overflows an integer. */ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ SumCtx *p; int type; assert( argc==1 ); UNUSED_PARAMETER(argc); p = sqlite3_aggregate_context(context, sizeof(*p)); type = sqlite3_value_numeric_type(argv[0]); if( p && type!=SQLITE_NULL ){ p->cnt++; if( p->approx==0 ){ if( type!=SQLITE_INTEGER ){ kahanBabuskaNeumaierInit(p, p->iSum); p->approx = 1; kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0])); }else{ i64 x = p->iSum; if( sqlite3AddInt64(&x, sqlite3_value_int64(argv[0]))==0 ){ p->iSum = x; }else{ p->ovrfl = 1; kahanBabuskaNeumaierInit(p, p->iSum); p->approx = 1; kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0])); } } }else{ if( type==SQLITE_INTEGER ){ kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0])); }else{ p->ovrfl = 0; kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0])); } } } } #ifndef SQLITE_OMIT_WINDOWFUNC static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){ SumCtx *p; int type; assert( argc==1 ); UNUSED_PARAMETER(argc); p = sqlite3_aggregate_context(context, sizeof(*p)); type = sqlite3_value_numeric_type(argv[0]); /* p is always non-NULL because sumStep() will have been called first ** to initialize it */ if( ALWAYS(p) && type!=SQLITE_NULL ){ assert( p->cnt>0 ); p->cnt--; if( !p->approx ){ p->iSum -= sqlite3_value_int64(argv[0]); }else if( type==SQLITE_INTEGER ){ i64 iVal = sqlite3_value_int64(argv[0]); if( iVal!=SMALLEST_INT64 ){ kahanBabuskaNeumaierStepInt64(p, -iVal); }else{ kahanBabuskaNeumaierStepInt64(p, LARGEST_INT64); kahanBabuskaNeumaierStepInt64(p, 1); } }else{ kahanBabuskaNeumaierStep(p, -sqlite3_value_double(argv[0])); } } } #else # define sumInverse 0 #endif /* SQLITE_OMIT_WINDOWFUNC */ static void sumFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>0 ){ if( p->approx ){ if( p->ovrfl ){ sqlite3_result_error(context,"integer overflow",-1); }else if( !sqlite3IsNaN(p->rErr) ){ sqlite3_result_double(context, p->rSum+p->rErr); }else{ sqlite3_result_double(context, p->rSum); } }else{ sqlite3_result_int64(context, p->iSum); } } } static void avgFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>0 ){ double r; if( p->approx ){ r = p->rSum; if( !sqlite3IsNaN(p->rErr) ) r += p->rErr; }else{ r = (double)(p->iSum); } sqlite3_result_double(context, r/(double)p->cnt); } } static void totalFinalize(sqlite3_context *context){ SumCtx *p; double r = 0.0; p = sqlite3_aggregate_context(context, 0); if( p ){ if( p->approx ){ r = p->rSum; if( !sqlite3IsNaN(p->rErr) ) r += p->rErr; }else{ r = (double)(p->iSum); } } sqlite3_result_double(context, r); } /* ** The following structure keeps track of state information for the ** count() aggregate function. */ typedef struct CountCtx CountCtx; struct CountCtx { i64 n; #ifdef SQLITE_DEBUG int bInverse; /* True if xInverse() ever called */ #endif }; /* ** Routines to implement the count() aggregate function. */ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){ CountCtx *p; p = sqlite3_aggregate_context(context, sizeof(*p)); if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p ){ p->n++; } #ifndef SQLITE_OMIT_DEPRECATED /* The sqlite3_aggregate_count() function is deprecated. But just to make ** sure it still operates correctly, verify that its count agrees with our ** internal count when using count(*) and when the total count can be ** expressed as a 32-bit integer. */ assert( argc==1 || p==0 || p->n>0x7fffffff || p->bInverse || p->n==sqlite3_aggregate_count(context) ); #endif } static void countFinalize(sqlite3_context *context){ CountCtx *p; p = sqlite3_aggregate_context(context, 0); sqlite3_result_int64(context, p ? p->n : 0); } #ifndef SQLITE_OMIT_WINDOWFUNC static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){ CountCtx *p; p = sqlite3_aggregate_context(ctx, sizeof(*p)); /* p is always non-NULL since countStep() will have been called first */ if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && ALWAYS(p) ){ p->n--; #ifdef SQLITE_DEBUG p->bInverse = 1; #endif } } #else # define countInverse 0 #endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** Routines to implement min() and max() aggregate functions. */ static void minmaxStep( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ Mem *pArg = (Mem *)argv[0]; Mem *pBest; UNUSED_PARAMETER(NotUsed); pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest)); if( !pBest ) return; if( sqlite3_value_type(pArg)==SQLITE_NULL ){ if( pBest->flags ) sqlite3SkipAccumulatorLoad(context); }else if( pBest->flags ){ int max; int cmp; CollSeq *pColl = sqlite3GetFuncCollSeq(context); /* This step function is used for both the min() and max() aggregates, ** the only difference between the two being that the sense of the ** comparison is inverted. For the max() aggregate, the ** sqlite3_user_data() function returns (void *)-1. For min() it ** returns (void *)db, where db is the sqlite3* database pointer. ** Therefore the next statement sets variable 'max' to 1 for the max() ** aggregate, or 0 for min(). */ max = sqlite3_user_data(context)!=0; cmp = sqlite3MemCompare(pBest, pArg, pColl); if( (max && cmp<0) || (!max && cmp>0) ){ sqlite3VdbeMemCopy(pBest, pArg); }else{ sqlite3SkipAccumulatorLoad(context); } }else{ pBest->db = sqlite3_context_db_handle(context); sqlite3VdbeMemCopy(pBest, pArg); } } static void minMaxValueFinalize(sqlite3_context *context, int bValue){ sqlite3_value *pRes; pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0); if( pRes ){ if( pRes->flags ){ sqlite3_result_value(context, pRes); } if( bValue==0 ) sqlite3VdbeMemRelease(pRes); } } #ifndef SQLITE_OMIT_WINDOWFUNC static void minMaxValue(sqlite3_context *context){ minMaxValueFinalize(context, 1); } #else # define minMaxValue 0 #endif /* SQLITE_OMIT_WINDOWFUNC */ static void minMaxFinalize(sqlite3_context *context){ minMaxValueFinalize(context, 0); } /* ** group_concat(EXPR, ?SEPARATOR?) ** string_agg(EXPR, SEPARATOR) ** ** The SEPARATOR goes before the EXPR string. This is tragic. The ** groupConcatInverse() implementation would have been easier if the ** SEPARATOR were appended after EXPR. And the order is undocumented, ** so we could change it, in theory. But the old behavior has been ** around for so long that we dare not, for fear of breaking something. */ typedef struct { StrAccum str; /* The accumulated concatenation */ #ifndef SQLITE_OMIT_WINDOWFUNC int nAccum; /* Number of strings presently concatenated */ int nFirstSepLength; /* Used to detect separator length change */ /* If pnSepLengths!=0, refs an array of inter-string separator lengths, ** stored as actually incorporated into presently accumulated result. ** (Hence, its slots in use number nAccum-1 between method calls.) ** If pnSepLengths==0, nFirstSepLength is the length used throughout. */ int *pnSepLengths; #endif } GroupConcatCtx; static void groupConcatStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zVal; GroupConcatCtx *pGCC; const char *zSep; int nVal, nSep; assert( argc==1 || argc==2 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); if( pGCC ){ sqlite3 *db = sqlite3_context_db_handle(context); int firstTerm = pGCC->str.mxAlloc==0; pGCC->str.mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; if( argc==1 ){ if( !firstTerm ){ sqlite3_str_appendchar(&pGCC->str, 1, ','); } #ifndef SQLITE_OMIT_WINDOWFUNC else{ pGCC->nFirstSepLength = 1; } #endif }else if( !firstTerm ){ zSep = (char*)sqlite3_value_text(argv[1]); nSep = sqlite3_value_bytes(argv[1]); if( zSep ){ sqlite3_str_append(&pGCC->str, zSep, nSep); } #ifndef SQLITE_OMIT_WINDOWFUNC else{ nSep = 0; } if( nSep != pGCC->nFirstSepLength || pGCC->pnSepLengths != 0 ){ int *pnsl = pGCC->pnSepLengths; if( pnsl == 0 ){ /* First separator length variation seen, start tracking them. */ pnsl = (int*)sqlite3_malloc64((pGCC->nAccum+1) * sizeof(int)); if( pnsl!=0 ){ int i = 0, nA = pGCC->nAccum-1; while( inFirstSepLength; } }else{ pnsl = (int*)sqlite3_realloc64(pnsl, pGCC->nAccum * sizeof(int)); } if( pnsl!=0 ){ if( ALWAYS(pGCC->nAccum>0) ){ pnsl[pGCC->nAccum-1] = nSep; } pGCC->pnSepLengths = pnsl; }else{ sqlite3StrAccumSetError(&pGCC->str, SQLITE_NOMEM); } } #endif } #ifndef SQLITE_OMIT_WINDOWFUNC else{ pGCC->nFirstSepLength = sqlite3_value_bytes(argv[1]); } pGCC->nAccum += 1; #endif zVal = (char*)sqlite3_value_text(argv[0]); nVal = sqlite3_value_bytes(argv[0]); if( zVal ) sqlite3_str_append(&pGCC->str, zVal, nVal); } } #ifndef SQLITE_OMIT_WINDOWFUNC static void groupConcatInverse( sqlite3_context *context, int argc, sqlite3_value **argv ){ GroupConcatCtx *pGCC; assert( argc==1 || argc==2 ); (void)argc; /* Suppress unused parameter warning */ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); /* pGCC is always non-NULL since groupConcatStep() will have always ** run first to initialize it */ if( ALWAYS(pGCC) ){ int nVS; /* Must call sqlite3_value_text() to convert the argument into text prior ** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */ (void)sqlite3_value_text(argv[0]); nVS = sqlite3_value_bytes(argv[0]); pGCC->nAccum -= 1; if( pGCC->pnSepLengths!=0 ){ assert(pGCC->nAccum >= 0); if( pGCC->nAccum>0 ){ nVS += *pGCC->pnSepLengths; memmove(pGCC->pnSepLengths, pGCC->pnSepLengths+1, (pGCC->nAccum-1)*sizeof(int)); } }else{ /* If removing single accumulated string, harmlessly over-do. */ nVS += pGCC->nFirstSepLength; } if( nVS>=(int)pGCC->str.nChar ){ pGCC->str.nChar = 0; }else{ pGCC->str.nChar -= nVS; memmove(pGCC->str.zText, &pGCC->str.zText[nVS], pGCC->str.nChar); } if( pGCC->str.nChar==0 ){ pGCC->str.mxAlloc = 0; sqlite3_free(pGCC->pnSepLengths); pGCC->pnSepLengths = 0; } } } #else # define groupConcatInverse 0 #endif /* SQLITE_OMIT_WINDOWFUNC */ static void groupConcatFinalize(sqlite3_context *context){ GroupConcatCtx *pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); if( pGCC ){ sqlite3ResultStrAccum(context, &pGCC->str); #ifndef SQLITE_OMIT_WINDOWFUNC sqlite3_free(pGCC->pnSepLengths); #endif } } #ifndef SQLITE_OMIT_WINDOWFUNC static void groupConcatValue(sqlite3_context *context){ GroupConcatCtx *pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); if( pGCC ){ StrAccum *pAccum = &pGCC->str; if( pAccum->accError==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(context); }else if( pAccum->accError==SQLITE_NOMEM ){ sqlite3_result_error_nomem(context); }else{ const char *zText = sqlite3_str_value(pAccum); sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT); } } } #else # define groupConcatValue 0 #endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** This routine does per-connection function registration. Most ** of the built-in functions above are part of the global function set. ** This routine only deals with those that are not global. */ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ int rc = sqlite3_overload_function(db, "MATCH", 2); assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); } } /* ** Re-register the built-in LIKE functions. The caseSensitive ** parameter determines whether or not the LIKE operator is case ** sensitive. */ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ FuncDef *pDef; struct compareInfo *pInfo; int flags; int nArg; if( caseSensitive ){ pInfo = (struct compareInfo*)&likeInfoAlt; flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE; }else{ pInfo = (struct compareInfo*)&likeInfoNorm; flags = SQLITE_FUNC_LIKE; } for(nArg=2; nArg<=3; nArg++){ sqlite3CreateFunc(db, "like", nArg, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); pDef = sqlite3FindFunction(db, "like", nArg, SQLITE_UTF8, 0); pDef->funcFlags |= flags; pDef->funcFlags &= ~SQLITE_FUNC_UNSAFE; } } /* ** pExpr points to an expression which implements a function. If ** it is appropriate to apply the LIKE optimization to that function ** then set aWc[0] through aWc[2] to the wildcard characters and the ** escape character and then return TRUE. If the function is not a ** LIKE-style function then return FALSE. ** ** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE ** operator if c is a string literal that is exactly one byte in length. ** That one byte is stored in aWc[3]. aWc[3] is set to zero if there is ** no ESCAPE clause. ** ** *pIsNocase is set to true if uppercase and lowercase are equivalent for ** the function (default for LIKE). If the function makes the distinction ** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to ** false. */ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ FuncDef *pDef; int nExpr; assert( pExpr!=0 ); assert( pExpr->op==TK_FUNCTION ); assert( ExprUseXList(pExpr) ); if( !pExpr->x.pList ){ return 0; } nExpr = pExpr->x.pList->nExpr; assert( !ExprHasProperty(pExpr, EP_IntValue) ); pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0); #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION if( pDef==0 ) return 0; #endif if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){ return 0; } /* The memcpy() statement assumes that the wildcard characters are ** the first three statements in the compareInfo structure. The ** asserts() that follow verify that assumption */ memcpy(aWc, pDef->pUserData, 3); assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll ); assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne ); assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet ); if( nExpr<3 ){ aWc[3] = 0; }else{ Expr *pEscape = pExpr->x.pList->a[2].pExpr; char *zEscape; if( pEscape->op!=TK_STRING ) return 0; assert( !ExprHasProperty(pEscape, EP_IntValue) ); zEscape = pEscape->u.zToken; if( zEscape[0]==0 || zEscape[1]!=0 ) return 0; if( zEscape[0]==aWc[0] ) return 0; if( zEscape[0]==aWc[1] ) return 0; aWc[3] = zEscape[0]; } *pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0; return 1; } /* Mathematical Constants */ #ifndef M_PI # define M_PI 3.141592653589793238462643383279502884 #endif #ifndef M_LN10 # define M_LN10 2.302585092994045684017991454684364208 #endif #ifndef M_LN2 # define M_LN2 0.693147180559945309417232121458176568 #endif /* Extra math functions that require linking with -lm */ #ifdef SQLITE_ENABLE_MATH_FUNCTIONS /* ** Implementation SQL functions: ** ** ceil(X) ** ceiling(X) ** floor(X) ** ** The sqlite3_user_data() pointer is a pointer to the libm implementation ** of the underlying C function. */ static void ceilingFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ assert( argc==1 ); switch( sqlite3_value_numeric_type(argv[0]) ){ case SQLITE_INTEGER: { sqlite3_result_int64(context, sqlite3_value_int64(argv[0])); break; } case SQLITE_FLOAT: { double (*x)(double) = (double(*)(double))sqlite3_user_data(context); sqlite3_result_double(context, x(sqlite3_value_double(argv[0]))); break; } default: { break; } } } /* ** On some systems, ceil() and floor() are intrinsic function. You are ** unable to take a pointer to these functions. Hence, we here wrap them ** in our own actual functions. */ static double xCeil(double x){ return ceil(x); } static double xFloor(double x){ return floor(x); } /* ** Some systems do not have log2() and log10() in their standard math ** libraries. */ #if defined(HAVE_LOG10) && HAVE_LOG10==0 # define log10(X) (0.4342944819032517867*log(X)) #endif #if defined(HAVE_LOG2) && HAVE_LOG2==0 # define log2(X) (1.442695040888963456*log(X)) #endif /* ** Implementation of SQL functions: ** ** ln(X) - natural logarithm ** log(X) - log X base 10 ** log10(X) - log X base 10 ** log(B,X) - log X base B */ static void logFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ double x, b, ans; assert( argc==1 || argc==2 ); switch( sqlite3_value_numeric_type(argv[0]) ){ case SQLITE_INTEGER: case SQLITE_FLOAT: x = sqlite3_value_double(argv[0]); if( x<=0.0 ) return; break; default: return; } if( argc==2 ){ switch( sqlite3_value_numeric_type(argv[0]) ){ case SQLITE_INTEGER: case SQLITE_FLOAT: b = log(x); if( b<=0.0 ) return; x = sqlite3_value_double(argv[1]); if( x<=0.0 ) return; break; default: return; } ans = log(x)/b; }else{ switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){ case 1: ans = log10(x); break; case 2: ans = log2(x); break; default: ans = log(x); break; } } sqlite3_result_double(context, ans); } /* ** Functions to converts degrees to radians and radians to degrees. */ static double degToRad(double x){ return x*(M_PI/180.0); } static double radToDeg(double x){ return x*(180.0/M_PI); } /* ** Implementation of 1-argument SQL math functions: ** ** exp(X) - Compute e to the X-th power */ static void math1Func( sqlite3_context *context, int argc, sqlite3_value **argv ){ int type0; double v0, ans; double (*x)(double); assert( argc==1 ); type0 = sqlite3_value_numeric_type(argv[0]); if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; v0 = sqlite3_value_double(argv[0]); x = (double(*)(double))sqlite3_user_data(context); ans = x(v0); sqlite3_result_double(context, ans); } /* ** Implementation of 2-argument SQL math functions: ** ** power(X,Y) - Compute X to the Y-th power */ static void math2Func( sqlite3_context *context, int argc, sqlite3_value **argv ){ int type0, type1; double v0, v1, ans; double (*x)(double,double); assert( argc==2 ); type0 = sqlite3_value_numeric_type(argv[0]); if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; type1 = sqlite3_value_numeric_type(argv[1]); if( type1!=SQLITE_INTEGER && type1!=SQLITE_FLOAT ) return; v0 = sqlite3_value_double(argv[0]); v1 = sqlite3_value_double(argv[1]); x = (double(*)(double,double))sqlite3_user_data(context); ans = x(v0, v1); sqlite3_result_double(context, ans); } /* ** Implementation of 0-argument pi() function. */ static void piFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ assert( argc==0 ); (void)argv; sqlite3_result_double(context, M_PI); } #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ /* ** Implementation of sign(X) function. */ static void signFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int type0; double x; UNUSED_PARAMETER(argc); assert( argc==1 ); type0 = sqlite3_value_numeric_type(argv[0]); if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; x = sqlite3_value_double(argv[0]); sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0); } #ifdef SQLITE_DEBUG /* ** Implementation of fpdecode(x,y,z) function. ** ** x is a real number that is to be decoded. y is the precision. ** z is the maximum real precision. */ static void fpdecodeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ FpDecode s; double x; int y, z; char zBuf[100]; UNUSED_PARAMETER(argc); assert( argc==3 ); x = sqlite3_value_double(argv[0]); y = sqlite3_value_int(argv[1]); z = sqlite3_value_int(argv[2]); sqlite3FpDecode(&s, x, y, z); if( s.isSpecial==2 ){ sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN"); }else{ sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP); } sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } #endif /* SQLITE_DEBUG */ /* ** All of the FuncDef structures in the aBuiltinFunc[] array above ** to the global function hash table. This occurs at start-time (as ** a consequence of calling sqlite3_initialize()). ** ** After this routine runs */ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ /* ** The following array holds FuncDef structures for all of the functions ** defined in this file. ** ** The array cannot be constant since changes are made to the ** FuncDef.pHash elements at start-time. The elements of this array ** are read-only after initialization is complete. ** ** For peak efficiency, put the most frequently used function last. */ static FuncDef aBuiltinFunc[] = { /***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/ #if !defined(SQLITE_UNTESTABLE) TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0), TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0), TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0), TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0), #endif /* !defined(SQLITE_UNTESTABLE) */ /***** Regular functions *****/ #ifdef SQLITE_SOUNDEX FUNCTION(soundex, 1, 0, 0, soundexFunc ), #endif #ifndef SQLITE_OMIT_LOAD_EXTENSION SFUNCTION(load_extension, 1, 0, 0, loadExt ), SFUNCTION(load_extension, 2, 0, 0, loadExt ), #endif #if SQLITE_USER_AUTHENTICATION FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), #endif #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC INLINE_FUNC(sqlite_offset, 1, INLINEFUNC_sqlite_offset, 0 ), #endif FUNCTION(ltrim, 1, 1, 0, trimFunc ), FUNCTION(ltrim, 2, 1, 0, trimFunc ), FUNCTION(rtrim, 1, 2, 0, trimFunc ), FUNCTION(rtrim, 2, 2, 0, trimFunc ), FUNCTION(trim, 1, 3, 0, trimFunc ), FUNCTION(trim, 2, 3, 0, trimFunc ), FUNCTION(min, -1, 0, 1, minmaxFunc ), FUNCTION(min, 0, 0, 1, 0 ), WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, 0, 1, 1, 0 ), WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN), FUNCTION(instr, 2, 0, 0, instrFunc ), FUNCTION(printf, -1, 0, 0, printfFunc ), FUNCTION(format, -1, 0, 0, printfFunc ), FUNCTION(unicode, 1, 0, 0, unicodeFunc ), FUNCTION(char, -1, 0, 0, charFunc ), FUNCTION(abs, 1, 0, 0, absFunc ), #ifdef SQLITE_DEBUG FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ), #endif #ifndef SQLITE_OMIT_FLOATING_POINT FUNCTION(round, 1, 0, 0, roundFunc ), FUNCTION(round, 2, 0, 0, roundFunc ), #endif FUNCTION(upper, 1, 0, 0, upperFunc ), FUNCTION(lower, 1, 0, 0, lowerFunc ), FUNCTION(hex, 1, 0, 0, hexFunc ), FUNCTION(unhex, 1, 0, 0, unhexFunc ), FUNCTION(unhex, 2, 0, 0, unhexFunc ), FUNCTION(concat, -1, 0, 0, concatFunc ), FUNCTION(concat, 0, 0, 0, 0 ), FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ), FUNCTION(concat_ws, 0, 0, 0, 0 ), FUNCTION(concat_ws, 1, 0, 0, 0 ), INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), FUNCTION(quote, 1, 0, 0, quoteFunc ), VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid), VFUNCTION(changes, 0, 0, 0, changes ), VFUNCTION(total_changes, 0, 0, 0, total_changes ), FUNCTION(replace, 3, 0, 0, replaceFunc ), FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), FUNCTION(substring, 2, 0, 0, substrFunc ), FUNCTION(substring, 3, 0, 0, substrFunc ), WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0), WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0), WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0), WAGGREGATE(count, 0,0,0, countStep, countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT|SQLITE_FUNC_ANYORDER ), WAGGREGATE(count, 1,0,0, countStep, countFinalize, countFinalize, countInverse, SQLITE_FUNC_ANYORDER ), WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), WAGGREGATE(string_agg, 2, 0, 0, groupConcatStep, groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #ifdef SQLITE_CASE_SENSITIVE_LIKE LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #else LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE), LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), #endif #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION FUNCTION(unknown, -1, 0, 0, unknownFunc ), #endif FUNCTION(coalesce, 1, 0, 0, 0 ), FUNCTION(coalesce, 0, 0, 0, 0 ), #ifdef SQLITE_ENABLE_MATH_FUNCTIONS MFUNCTION(ceil, 1, xCeil, ceilingFunc ), MFUNCTION(ceiling, 1, xCeil, ceilingFunc ), MFUNCTION(floor, 1, xFloor, ceilingFunc ), #if SQLITE_HAVE_C99_MATH_FUNCS MFUNCTION(trunc, 1, trunc, ceilingFunc ), #endif FUNCTION(ln, 1, 0, 0, logFunc ), FUNCTION(log, 1, 1, 0, logFunc ), FUNCTION(log10, 1, 1, 0, logFunc ), FUNCTION(log2, 1, 2, 0, logFunc ), FUNCTION(log, 2, 0, 0, logFunc ), MFUNCTION(exp, 1, exp, math1Func ), MFUNCTION(pow, 2, pow, math2Func ), MFUNCTION(power, 2, pow, math2Func ), MFUNCTION(mod, 2, fmod, math2Func ), MFUNCTION(acos, 1, acos, math1Func ), MFUNCTION(asin, 1, asin, math1Func ), MFUNCTION(atan, 1, atan, math1Func ), MFUNCTION(atan2, 2, atan2, math2Func ), MFUNCTION(cos, 1, cos, math1Func ), MFUNCTION(sin, 1, sin, math1Func ), MFUNCTION(tan, 1, tan, math1Func ), MFUNCTION(cosh, 1, cosh, math1Func ), MFUNCTION(sinh, 1, sinh, math1Func ), MFUNCTION(tanh, 1, tanh, math1Func ), #if SQLITE_HAVE_C99_MATH_FUNCS MFUNCTION(acosh, 1, acosh, math1Func ), MFUNCTION(asinh, 1, asinh, math1Func ), MFUNCTION(atanh, 1, atanh, math1Func ), #endif MFUNCTION(sqrt, 1, sqrt, math1Func ), MFUNCTION(radians, 1, degToRad, math1Func ), MFUNCTION(degrees, 1, radToDeg, math1Func ), FUNCTION(pi, 0, 0, 0, piFunc ), #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ FUNCTION(sign, 1, 0, 0, signFunc ), INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ), INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ), }; #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(); #endif sqlite3WindowFunctions(); sqlite3RegisterDateTimeFunctions(); sqlite3RegisterJsonFunctions(); sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc)); #if 0 /* Enable to print out how the built-in functions are hashed */ { int i; FuncDef *p; for(i=0; iu.pHash){ int n = sqlite3Strlen30(p->zName); int h = p->zName[0] + n; assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); printf(" %s(%d)", p->zName, h); } printf("\n"); } } #endif } /************** End of func.c ************************************************/ /************** Begin file fkey.c ********************************************/ /* ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used by the compiler to add foreign key ** support to compiled SQL statements. */ /* #include "sqliteInt.h" */ #ifndef SQLITE_OMIT_FOREIGN_KEY #ifndef SQLITE_OMIT_TRIGGER /* ** Deferred and Immediate FKs ** -------------------------- ** ** Foreign keys in SQLite come in two flavours: deferred and immediate. ** If an immediate foreign key constraint is violated, ** SQLITE_CONSTRAINT_FOREIGNKEY is returned and the current ** statement transaction rolled back. If a ** deferred foreign key constraint is violated, no action is taken ** immediately. However if the application attempts to commit the ** transaction before fixing the constraint violation, the attempt fails. ** ** Deferred constraints are implemented using a simple counter associated ** with the database handle. The counter is set to zero each time a ** database transaction is opened. Each time a statement is executed ** that causes a foreign key violation, the counter is incremented. Each ** time a statement is executed that removes an existing violation from ** the database, the counter is decremented. When the transaction is ** committed, the commit fails if the current value of the counter is ** greater than zero. This scheme has two big drawbacks: ** ** * When a commit fails due to a deferred foreign key constraint, ** there is no way to tell which foreign constraint is not satisfied, ** or which row it is not satisfied for. ** ** * If the database contains foreign key violations when the ** transaction is opened, this may cause the mechanism to malfunction. ** ** Despite these problems, this approach is adopted as it seems simpler ** than the alternatives. ** ** INSERT operations: ** ** I.1) For each FK for which the table is the child table, search ** the parent table for a match. If none is found increment the ** constraint counter. ** ** I.2) For each FK for which the table is the parent table, ** search the child table for rows that correspond to the new ** row in the parent table. Decrement the counter for each row ** found (as the constraint is now satisfied). ** ** DELETE operations: ** ** D.1) For each FK for which the table is the child table, ** search the parent table for a row that corresponds to the ** deleted row in the child table. If such a row is not found, ** decrement the counter. ** ** D.2) For each FK for which the table is the parent table, search ** the child table for rows that correspond to the deleted row ** in the parent table. For each found increment the counter. ** ** UPDATE operations: ** ** An UPDATE command requires that all 4 steps above are taken, but only ** for FK constraints for which the affected columns are actually ** modified (values must be compared at runtime). ** ** Note that I.1 and D.1 are very similar operations, as are I.2 and D.2. ** This simplifies the implementation a bit. ** ** For the purposes of immediate FK constraints, the OR REPLACE conflict ** resolution is considered to delete rows before the new row is inserted. ** If a delete caused by OR REPLACE violates an FK constraint, an exception ** is thrown, even if the FK constraint would be satisfied after the new ** row is inserted. ** ** Immediate constraints are usually handled similarly. The only difference ** is that the counter used is stored as part of each individual statement ** object (struct Vdbe). If, after the statement has run, its immediate ** constraint counter is greater than zero, ** it returns SQLITE_CONSTRAINT_FOREIGNKEY ** and the statement transaction is rolled back. An exception is an INSERT ** statement that inserts a single row only (no triggers). In this case, ** instead of using a counter, an exception is thrown immediately if the ** INSERT violates a foreign key constraint. This is necessary as such ** an INSERT does not open a statement transaction. ** ** TODO: How should dropping a table be handled? How should renaming a ** table be handled? ** ** ** Query API Notes ** --------------- ** ** Before coding an UPDATE or DELETE row operation, the code-generator ** for those two operations needs to know whether or not the operation ** requires any FK processing and, if so, which columns of the original ** row are required by the FK processing VDBE code (i.e. if FKs were ** implemented using triggers, which of the old.* columns would be ** accessed). No information is required by the code-generator before ** coding an INSERT operation. The functions used by the UPDATE/DELETE ** generation code to query for this information are: ** ** sqlite3FkRequired() - Test to see if FK processing is required. ** sqlite3FkOldmask() - Query for the set of required old.* columns. ** ** ** Externally accessible module functions ** -------------------------------------- ** ** sqlite3FkCheck() - Check for foreign key violations. ** sqlite3FkActions() - Code triggers for ON UPDATE/ON DELETE actions. ** sqlite3FkDelete() - Delete an FKey structure. */ /* ** VDBE Calling Convention ** ----------------------- ** ** Example: ** ** For the following INSERT statement: ** ** CREATE TABLE t1(a, b INTEGER PRIMARY KEY, c); ** INSERT INTO t1 VALUES(1, 2, 3.1); ** ** Register (x): 2 (type integer) ** Register (x+1): 1 (type integer) ** Register (x+2): NULL (type NULL) ** Register (x+3): 3.1 (type real) */ /* ** A foreign key constraint requires that the key columns in the parent ** table are collectively subject to a UNIQUE or PRIMARY KEY constraint. ** Given that pParent is the parent table for foreign key constraint pFKey, ** search the schema for a unique index on the parent key columns. ** ** If successful, zero is returned. If the parent key is an INTEGER PRIMARY ** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx ** is set to point to the unique index. ** ** If the parent key consists of a single column (the foreign key constraint ** is not a composite foreign key), output variable *paiCol is set to NULL. ** Otherwise, it is set to point to an allocated array of size N, where ** N is the number of columns in the parent key. The first element of the ** array is the index of the child table column that is mapped by the FK ** constraint to the parent table column stored in the left-most column ** of index *ppIdx. The second element of the array is the index of the ** child table column that corresponds to the second left-most column of ** *ppIdx, and so on. ** ** If the required index cannot be found, either because: ** ** 1) The named parent key columns do not exist, or ** ** 2) The named parent key columns do exist, but are not subject to a ** UNIQUE or PRIMARY KEY constraint, or ** ** 3) No parent key columns were provided explicitly as part of the ** foreign key definition, and the parent table does not have a ** PRIMARY KEY, or ** ** 4) No parent key columns were provided explicitly as part of the ** foreign key definition, and the PRIMARY KEY of the parent table ** consists of a different number of columns to the child key in ** the child table. ** ** then non-zero is returned, and a "foreign key mismatch" error loaded ** into pParse. If an OOM error occurs, non-zero is returned and the ** pParse->db->mallocFailed flag is set. */ SQLITE_PRIVATE int sqlite3FkLocateIndex( Parse *pParse, /* Parse context to store any error in */ Table *pParent, /* Parent table of FK constraint pFKey */ FKey *pFKey, /* Foreign key to find index for */ Index **ppIdx, /* OUT: Unique index on parent table */ int **paiCol /* OUT: Map of index columns in pFKey */ ){ Index *pIdx = 0; /* Value to return via *ppIdx */ int *aiCol = 0; /* Value to return via *paiCol */ int nCol = pFKey->nCol; /* Number of columns in parent key */ char *zKey = pFKey->aCol[0].zCol; /* Name of left-most parent key column */ /* The caller is responsible for zeroing output parameters. */ assert( ppIdx && *ppIdx==0 ); assert( !paiCol || *paiCol==0 ); assert( pParse ); /* If this is a non-composite (single column) foreign key, check if it ** maps to the INTEGER PRIMARY KEY of table pParent. If so, leave *ppIdx ** and *paiCol set to zero and return early. ** ** Otherwise, for a composite foreign key (more than one column), allocate ** space for the aiCol array (returned via output parameter *paiCol). ** Non-composite foreign keys do not require the aiCol array. */ if( nCol==1 ){ /* The FK maps to the IPK if any of the following are true: ** ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly ** mapped to the primary key of table pParent, or ** 2) The FK is explicitly mapped to a column declared as INTEGER ** PRIMARY KEY. */ if( pParent->iPKey>=0 ){ if( !zKey ) return 0; if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zCnName, zKey) ){ return 0; } } }else if( paiCol ){ assert( nCol>1 ); aiCol = (int *)sqlite3DbMallocRawNN(pParse->db, nCol*sizeof(int)); if( !aiCol ) return 1; *paiCol = aiCol; } for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){ /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number ** of columns. If each indexed column corresponds to a foreign key ** column of pFKey, then this index is a winner. */ if( zKey==0 ){ /* If zKey is NULL, then this foreign key is implicitly mapped to ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be ** identified by the test. */ if( IsPrimaryKeyIndex(pIdx) ){ if( aiCol ){ int i; for(i=0; iaCol[i].iFrom; } break; } }else{ /* If zKey is non-NULL, then this foreign key was declared to ** map to an explicit list of columns in table pParent. Check if this ** index matches those columns. Also, check that the index uses ** the default collation sequences for each column. */ int i, j; for(i=0; iaiColumn[i]; /* Index of column in parent tbl */ const char *zDfltColl; /* Def. collation for column */ char *zIdxCol; /* Name of indexed column */ if( iCol<0 ) break; /* No foreign keys against expression indexes */ /* If the index uses a collation sequence that is different from ** the default collation sequence for the column, this index is ** unusable. Bail out early in this case. */ zDfltColl = sqlite3ColumnColl(&pParent->aCol[iCol]); if( !zDfltColl ) zDfltColl = sqlite3StrBINARY; if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break; zIdxCol = pParent->aCol[iCol].zCnName; for(j=0; jaCol[j].zCol, zIdxCol)==0 ){ if( aiCol ) aiCol[i] = pFKey->aCol[j].iFrom; break; } } if( j==nCol ) break; } if( i==nCol ) break; /* pIdx is usable */ } } } if( !pIdx ){ if( !pParse->disableTriggers ){ sqlite3ErrorMsg(pParse, "foreign key mismatch - \"%w\" referencing \"%w\"", pFKey->pFrom->zName, pFKey->zTo); } sqlite3DbFree(pParse->db, aiCol); return 1; } *ppIdx = pIdx; return 0; } /* ** This function is called when a row is inserted into or deleted from the ** child table of foreign key constraint pFKey. If an SQL UPDATE is executed ** on the child table of pFKey, this function is invoked twice for each row ** affected - once to "delete" the old row, and then again to "insert" the ** new row. ** ** Each time it is called, this function generates VDBE code to locate the ** row in the parent table that corresponds to the row being inserted into ** or deleted from the child table. If the parent row can be found, no ** special action is taken. Otherwise, if the parent row can *not* be ** found in the parent table: ** ** Operation | FK type | Action taken ** -------------------------------------------------------------------------- ** INSERT immediate Increment the "immediate constraint counter". ** ** DELETE immediate Decrement the "immediate constraint counter". ** ** INSERT deferred Increment the "deferred constraint counter". ** ** DELETE deferred Decrement the "deferred constraint counter". ** ** These operations are identified in the comment at the top of this file ** (fkey.c) as "I.1" and "D.1". */ static void fkLookupParent( Parse *pParse, /* Parse context */ int iDb, /* Index of database housing pTab */ Table *pTab, /* Parent table of FK pFKey */ Index *pIdx, /* Unique index on parent key columns in pTab */ FKey *pFKey, /* Foreign key constraint */ int *aiCol, /* Map from parent key columns to child table columns */ int regData, /* Address of array containing child table row */ int nIncr, /* Increment constraint counter by this */ int isIgnore /* If true, pretend pTab contains all NULL values */ ){ int i; /* Iterator variable */ Vdbe *v = sqlite3GetVdbe(pParse); /* Vdbe to add code to */ int iCur = pParse->nTab - 1; /* Cursor number to use */ int iOk = sqlite3VdbeMakeLabel(pParse); /* jump here if parent key found */ sqlite3VdbeVerifyAbortable(v, (!pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs) && !pParse->pToplevel && !pParse->isMultiWrite) ? OE_Abort : OE_Ignore); /* If nIncr is less than zero, then check at runtime if there are any ** outstanding constraints to resolve. If there are not, there is no need ** to check if deleting this row resolves any outstanding violations. ** ** Check if any of the key columns in the child table row are NULL. If ** any are, then the constraint is considered satisfied. No need to ** search for a matching row in the parent table. */ if( nIncr<0 ){ sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, iOk); VdbeCoverage(v); } for(i=0; inCol; i++){ int iReg = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i]) + regData + 1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v); } if( isIgnore==0 ){ if( pIdx==0 ){ /* If pIdx is NULL, then the parent key is the INTEGER PRIMARY KEY ** column of the parent table (table pTab). */ int iMustBeInt; /* Address of MustBeInt instruction */ int regTemp = sqlite3GetTempReg(pParse); /* Invoke MustBeInt to coerce the child key value to an integer (i.e. ** apply the affinity of the parent key). If this fails, then there ** is no matching parent key. Before using MustBeInt, make a copy of ** the value. Otherwise, the value inserted into the child key column ** will have INTEGER affinity applied to it, which may not be correct. */ sqlite3VdbeAddOp2(v, OP_SCopy, sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[0])+1+regData, regTemp); iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0); VdbeCoverage(v); /* If the parent table is the same as the child table, and we are about ** to increment the constraint-counter (i.e. this is an INSERT operation), ** then check if the row being inserted matches itself. If so, do not ** increment the constraint-counter. */ if( pTab==pFKey->pFrom && nIncr==1 ){ sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); } sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); VdbeCoverage(v); sqlite3VdbeGoto(v, iOk); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); sqlite3VdbeJumpHere(v, iMustBeInt); sqlite3ReleaseTempReg(pParse, regTemp); }else{ int nCol = pFKey->nCol; int regTemp = sqlite3GetTempRange(pParse, nCol); sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); for(i=0; ipFrom, aiCol[i])+1+regData, regTemp+i); } /* If the parent table is the same as the child table, and we are about ** to increment the constraint-counter (i.e. this is an INSERT operation), ** then check if the row being inserted matches itself. If so, do not ** increment the constraint-counter. ** ** If any of the parent-key values are NULL, then the row cannot match ** itself. So set JUMPIFNULL to make sure we do the OP_Found if any ** of the parent-key values are NULL (at this point it is known that ** none of the child key values are). */ if( pTab==pFKey->pFrom && nIncr==1 ){ int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1; for(i=0; ipFrom,aiCol[i]) +1+regData; int iParent = 1+regData; iParent += sqlite3TableColumnToStorage(pIdx->pTable, pIdx->aiColumn[i]); assert( pIdx->aiColumn[i]>=0 ); assert( aiCol[i]!=pTab->iPKey ); if( pIdx->aiColumn[i]==pTab->iPKey ){ /* The parent key is a composite key that includes the IPK column */ iParent = regData; } sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); } sqlite3VdbeGoto(v, iOk); } sqlite3VdbeAddOp4(v, OP_Affinity, regTemp, nCol, 0, sqlite3IndexAffinityStr(pParse->db,pIdx), nCol); sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regTemp, nCol); VdbeCoverage(v); sqlite3ReleaseTempRange(pParse, regTemp, nCol); } } if( !pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs) && !pParse->pToplevel && !pParse->isMultiWrite ){ /* Special case: If this is an INSERT statement that will insert exactly ** one row into the table, raise a constraint immediately instead of ** incrementing a counter. This is necessary as the VM code is being ** generated for will not open a statement transaction. */ assert( nIncr==1 ); sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY, OE_Abort, 0, P4_STATIC, P5_ConstraintFK); }else{ if( nIncr>0 && pFKey->isDeferred==0 ){ sqlite3MayAbort(pParse); } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); } sqlite3VdbeResolveLabel(v, iOk); sqlite3VdbeAddOp1(v, OP_Close, iCur); } /* ** Return an Expr object that refers to a memory register corresponding ** to column iCol of table pTab. ** ** regBase is the first of an array of register that contains the data ** for pTab. regBase itself holds the rowid. regBase+1 holds the first ** column. regBase+2 holds the second column, and so forth. */ static Expr *exprTableRegister( Parse *pParse, /* Parsing and code generating context */ Table *pTab, /* The table whose content is at r[regBase]... */ int regBase, /* Contents of table pTab */ i16 iCol /* Which column of pTab is desired */ ){ Expr *pExpr; Column *pCol; const char *zColl; sqlite3 *db = pParse->db; pExpr = sqlite3Expr(db, TK_REGISTER, 0); if( pExpr ){ if( iCol>=0 && iCol!=pTab->iPKey ){ pCol = &pTab->aCol[iCol]; pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1; pExpr->affExpr = pCol->affinity; zColl = sqlite3ColumnColl(pCol); if( zColl==0 ) zColl = db->pDfltColl->zName; pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl); }else{ pExpr->iTable = regBase; pExpr->affExpr = SQLITE_AFF_INTEGER; } } return pExpr; } /* ** Return an Expr object that refers to column iCol of table pTab which ** has cursor iCur. */ static Expr *exprTableColumn( sqlite3 *db, /* The database connection */ Table *pTab, /* The table whose column is desired */ int iCursor, /* The open cursor on the table */ i16 iCol /* The column that is wanted */ ){ Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0); if( pExpr ){ assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pTab; pExpr->iTable = iCursor; pExpr->iColumn = iCol; } return pExpr; } /* ** This function is called to generate code executed when a row is deleted ** from the parent table of foreign key constraint pFKey and, if pFKey is ** deferred, when a row is inserted into the same table. When generating ** code for an SQL UPDATE operation, this function may be called twice - ** once to "delete" the old row and once to "insert" the new row. ** ** Parameter nIncr is passed -1 when inserting a row (as this may decrease ** the number of FK violations in the db) or +1 when deleting one (as this ** may increase the number of FK constraint problems). ** ** The code generated by this function scans through the rows in the child ** table that correspond to the parent table row being deleted or inserted. ** For each child row found, one of the following actions is taken: ** ** Operation | FK type | Action taken ** -------------------------------------------------------------------------- ** DELETE immediate Increment the "immediate constraint counter". ** ** INSERT immediate Decrement the "immediate constraint counter". ** ** DELETE deferred Increment the "deferred constraint counter". ** ** INSERT deferred Decrement the "deferred constraint counter". ** ** These operations are identified in the comment at the top of this file ** (fkey.c) as "I.2" and "D.2". */ static void fkScanChildren( Parse *pParse, /* Parse context */ SrcList *pSrc, /* The child table to be scanned */ Table *pTab, /* The parent table */ Index *pIdx, /* Index on parent covering the foreign key */ FKey *pFKey, /* The foreign key linking pSrc to pTab */ int *aiCol, /* Map from pIdx cols to child table cols */ int regData, /* Parent row data starts here */ int nIncr /* Amount to increment deferred counter by */ ){ sqlite3 *db = pParse->db; /* Database handle */ int i; /* Iterator variable */ Expr *pWhere = 0; /* WHERE clause to scan with */ NameContext sNameContext; /* Context used to resolve WHERE clause */ WhereInfo *pWInfo; /* Context used by sqlite3WhereXXX() */ int iFkIfZero = 0; /* Address of OP_FkIfZero */ Vdbe *v = sqlite3GetVdbe(pParse); assert( pIdx==0 || pIdx->pTable==pTab ); assert( pIdx==0 || pIdx->nKeyCol==pFKey->nCol ); assert( pIdx!=0 || pFKey->nCol==1 ); assert( pIdx!=0 || HasRowid(pTab) ); if( nIncr<0 ){ iFkIfZero = sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, 0); VdbeCoverage(v); } /* Create an Expr object representing an SQL expression like: ** ** = AND = ... ** ** The collation sequence used for the comparison should be that of ** the parent key columns. The affinity of the parent key column should ** be applied to each child key value before the comparison takes place. */ for(i=0; inCol; i++){ Expr *pLeft; /* Value from parent table row */ Expr *pRight; /* Column ref to child table */ Expr *pEq; /* Expression (pLeft = pRight) */ i16 iCol; /* Index of column in child table */ const char *zCol; /* Name of column in child table */ iCol = pIdx ? pIdx->aiColumn[i] : -1; pLeft = exprTableRegister(pParse, pTab, regData, iCol); iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iCol>=0 ); zCol = pFKey->pFrom->aCol[iCol].zCnName; pRight = sqlite3Expr(db, TK_ID, zCol); pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); } /* If the child table is the same as the parent table, then add terms ** to the WHERE clause that prevent this entry from being scanned. ** The added WHERE clause terms are like this: ** ** $current_rowid!=rowid ** NOT( $current_a==a AND $current_b==b AND ... ) ** ** The first form is used for rowid tables. The second form is used ** for WITHOUT ROWID tables. In the second form, the *parent* key is ** (a,b,...). Either the parent or primary key could be used to ** uniquely identify the current row, but the parent key is more convenient ** as the required values have already been loaded into registers ** by the caller. */ if( pTab==pFKey->pFrom && nIncr>0 ){ Expr *pNe; /* Expression (pLeft != pRight) */ Expr *pLeft; /* Value from parent table row */ Expr *pRight; /* Column ref to child table */ if( HasRowid(pTab) ){ pLeft = exprTableRegister(pParse, pTab, regData, -1); pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, -1); pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight); }else{ Expr *pEq, *pAll = 0; assert( pIdx!=0 ); for(i=0; inKeyCol; i++){ i16 iCol = pIdx->aiColumn[i]; assert( iCol>=0 ); pLeft = exprTableRegister(pParse, pTab, regData, iCol); pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zCnName); pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight); pAll = sqlite3ExprAnd(pParse, pAll, pEq); } pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0); } pWhere = sqlite3ExprAnd(pParse, pWhere, pNe); } /* Resolve the references in the WHERE clause. */ memset(&sNameContext, 0, sizeof(NameContext)); sNameContext.pSrcList = pSrc; sNameContext.pParse = pParse; sqlite3ResolveExprNames(&sNameContext, pWhere); /* Create VDBE to loop through the entries in pSrc that match the WHERE ** clause. For each row found, increment either the deferred or immediate ** foreign key constraint counter. */ if( pParse->nErr==0 ){ pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0, 0); sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); if( pWInfo ){ sqlite3WhereEnd(pWInfo); } } /* Clean up the WHERE clause constructed above. */ sqlite3ExprDelete(db, pWhere); if( iFkIfZero ){ sqlite3VdbeJumpHereOrPopInst(v, iFkIfZero); } } /* ** This function returns a linked list of FKey objects (connected by ** FKey.pNextTo) holding all children of table pTab. For example, ** given the following schema: ** ** CREATE TABLE t1(a PRIMARY KEY); ** CREATE TABLE t2(b REFERENCES t1(a); ** ** Calling this function with table "t1" as an argument returns a pointer ** to the FKey structure representing the foreign key constraint on table ** "t2". Calling this function with "t2" as the argument would return a ** NULL pointer (as there are no FK constraints for which t2 is the parent ** table). */ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){ return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName); } /* ** The second argument is a Trigger structure allocated by the ** fkActionTrigger() routine. This function deletes the Trigger structure ** and all of its sub-components. ** ** The Trigger structure or any of its sub-components may be allocated from ** the lookaside buffer belonging to database handle dbMem. */ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ if( p ){ TriggerStep *pStep = p->step_list; sqlite3ExprDelete(dbMem, pStep->pWhere); sqlite3ExprListDelete(dbMem, pStep->pExprList); sqlite3SelectDelete(dbMem, pStep->pSelect); sqlite3ExprDelete(dbMem, p->pWhen); sqlite3DbFree(dbMem, p); } } /* ** Clear the apTrigger[] cache of CASCADE triggers for all foreign keys ** in a particular database. This needs to happen when the schema ** changes. */ SQLITE_PRIVATE void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){ HashElem *k; Hash *pHash = &db->aDb[iDb].pSchema->tblHash; for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k)){ Table *pTab = sqliteHashData(k); FKey *pFKey; if( !IsOrdinaryTable(pTab) ) continue; for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ fkTriggerDelete(db, pFKey->apTrigger[0]); pFKey->apTrigger[0] = 0; fkTriggerDelete(db, pFKey->apTrigger[1]); pFKey->apTrigger[1] = 0; } } } /* ** This function is called to generate code that runs when table pTab is ** being dropped from the database. The SrcList passed as the second argument ** to this function contains a single entry guaranteed to resolve to ** table pTab. ** ** Normally, no code is required. However, if either ** ** (a) The table is the parent table of a FK constraint, or ** (b) The table is the child table of a deferred FK constraint and it is ** determined at runtime that there are outstanding deferred FK ** constraint violations in the database, ** ** then the equivalent of "DELETE FROM " is executed before dropping ** the table from the database. Triggers are disabled while running this ** DELETE, but foreign key actions are not. */ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ sqlite3 *db = pParse->db; if( (db->flags&SQLITE_ForeignKeys) && IsOrdinaryTable(pTab) ){ int iSkip = 0; Vdbe *v = sqlite3GetVdbe(pParse); assert( v ); /* VDBE has already been allocated */ assert( IsOrdinaryTable(pTab) ); if( sqlite3FkReferences(pTab)==0 ){ /* Search for a deferred foreign key constraint for which this table ** is the child table. If one cannot be found, return without ** generating any VDBE code. If one can be found, then jump over ** the entire DELETE if there are no outstanding deferred constraints ** when this statement is run. */ FKey *p; for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break; } if( !p ) return; iSkip = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); VdbeCoverage(v); } pParse->disableTriggers = 1; sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0); pParse->disableTriggers = 0; /* If the DELETE has generated immediate foreign key constraint ** violations, halt the VDBE and return an error at this point, before ** any modifications to the schema are made. This is because statement ** transactions are not able to rollback schema changes. ** ** If the SQLITE_DeferFKs flag is set, then this is not required, as ** the statement transaction will not be rolled back even if FK ** constraints are violated. */ if( (db->flags & SQLITE_DeferFKs)==0 ){ sqlite3VdbeVerifyAbortable(v, OE_Abort); sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY, OE_Abort, 0, P4_STATIC, P5_ConstraintFK); } if( iSkip ){ sqlite3VdbeResolveLabel(v, iSkip); } } } /* ** The second argument points to an FKey object representing a foreign key ** for which pTab is the child table. An UPDATE statement against pTab ** is currently being processed. For each column of the table that is ** actually updated, the corresponding element in the aChange[] array ** is zero or greater (if a column is unmodified the corresponding element ** is set to -1). If the rowid column is modified by the UPDATE statement ** the bChngRowid argument is non-zero. ** ** This function returns true if any of the columns that are part of the ** child key for FK constraint *p are modified. */ static int fkChildIsModified( Table *pTab, /* Table being updated */ FKey *p, /* Foreign key for which pTab is the child */ int *aChange, /* Array indicating modified columns */ int bChngRowid /* True if rowid is modified by this update */ ){ int i; for(i=0; inCol; i++){ int iChildKey = p->aCol[i].iFrom; if( aChange[iChildKey]>=0 ) return 1; if( iChildKey==pTab->iPKey && bChngRowid ) return 1; } return 0; } /* ** The second argument points to an FKey object representing a foreign key ** for which pTab is the parent table. An UPDATE statement against pTab ** is currently being processed. For each column of the table that is ** actually updated, the corresponding element in the aChange[] array ** is zero or greater (if a column is unmodified the corresponding element ** is set to -1). If the rowid column is modified by the UPDATE statement ** the bChngRowid argument is non-zero. ** ** This function returns true if any of the columns that are part of the ** parent key for FK constraint *p are modified. */ static int fkParentIsModified( Table *pTab, FKey *p, int *aChange, int bChngRowid ){ int i; for(i=0; inCol; i++){ char *zKey = p->aCol[i].zCol; int iKey; for(iKey=0; iKeynCol; iKey++){ if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){ Column *pCol = &pTab->aCol[iKey]; if( zKey ){ if( 0==sqlite3StrICmp(pCol->zCnName, zKey) ) return 1; }else if( pCol->colFlags & COLFLAG_PRIMKEY ){ return 1; } } } } return 0; } /* ** Return true if the parser passed as the first argument is being ** used to code a trigger that is really a "SET NULL" action belonging ** to trigger pFKey. */ static int isSetNullAction(Parse *pParse, FKey *pFKey){ Parse *pTop = sqlite3ParseToplevel(pParse); if( pTop->pTriggerPrg ){ Trigger *p = pTop->pTriggerPrg->pTrigger; if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull) || (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull) ){ assert( (pTop->db->flags & SQLITE_FkNoAction)==0 ); return 1; } } return 0; } /* ** This function is called when inserting, deleting or updating a row of ** table pTab to generate VDBE code to perform foreign key constraint ** processing for the operation. ** ** For a DELETE operation, parameter regOld is passed the index of the ** first register in an array of (pTab->nCol+1) registers containing the ** rowid of the row being deleted, followed by each of the column values ** of the row being deleted, from left to right. Parameter regNew is passed ** zero in this case. ** ** For an INSERT operation, regOld is passed zero and regNew is passed the ** first register of an array of (pTab->nCol+1) registers containing the new ** row data. ** ** For an UPDATE operation, this function is called twice. Once before ** the original record is deleted from the table using the calling convention ** described for DELETE. Then again after the original record is deleted ** but before the new record is inserted using the INSERT convention. */ SQLITE_PRIVATE void sqlite3FkCheck( Parse *pParse, /* Parse context */ Table *pTab, /* Row is being deleted from this table */ int regOld, /* Previous row data is stored here */ int regNew, /* New row data is stored here */ int *aChange, /* Array indicating UPDATEd columns (or 0) */ int bChngRowid /* True if rowid is UPDATEd */ ){ sqlite3 *db = pParse->db; /* Database handle */ FKey *pFKey; /* Used to iterate through FKs */ int iDb; /* Index of database containing pTab */ const char *zDb; /* Name of database containing pTab */ int isIgnoreErrors = pParse->disableTriggers; /* Exactly one of regOld and regNew should be non-zero. */ assert( (regOld==0)!=(regNew==0) ); /* If foreign-keys are disabled, this function is a no-op. */ if( (db->flags&SQLITE_ForeignKeys)==0 ) return; if( !IsOrdinaryTable(pTab) ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; /* Loop through all the foreign key constraints for which pTab is the ** child table (the table that the foreign key definition is part of). */ for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ Table *pTo; /* Parent table of foreign key pFKey */ Index *pIdx = 0; /* Index on key columns in pTo */ int *aiFree = 0; int *aiCol; int iCol; int i; int bIgnore = 0; if( aChange && sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0 && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0 ){ continue; } /* Find the parent table of this foreign key. Also find a unique index ** on the parent key columns in the parent table. If either of these ** schema items cannot be located, set an error in pParse and return ** early. */ if( pParse->disableTriggers ){ pTo = sqlite3FindTable(db, pFKey->zTo, zDb); }else{ pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb); } if( !pTo || sqlite3FkLocateIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) ); if( !isIgnoreErrors || db->mallocFailed ) return; if( pTo==0 ){ /* If isIgnoreErrors is true, then a table is being dropped. In this ** case SQLite runs a "DELETE FROM xxx" on the table being dropped ** before actually dropping it in order to check FK constraints. ** If the parent table of an FK constraint on the current table is ** missing, behave as if it is empty. i.e. decrement the relevant ** FK counter for each row of the current table with non-NULL keys. */ Vdbe *v = sqlite3GetVdbe(pParse); int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1; for(i=0; inCol; i++){ int iFromCol, iReg; iFromCol = pFKey->aCol[i].iFrom; iReg = sqlite3TableColumnToStorage(pFKey->pFrom,iFromCol) + regOld+1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v); } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1); } continue; } assert( pFKey->nCol==1 || (aiFree && pIdx) ); if( aiFree ){ aiCol = aiFree; }else{ iCol = pFKey->aCol[0].iFrom; aiCol = &iCol; } for(i=0; inCol; i++){ if( aiCol[i]==pTab->iPKey ){ aiCol[i] = -1; } assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Request permission to read the parent key columns. If the ** authorization callback returns SQLITE_IGNORE, behave as if any ** values read from the parent table are NULL. */ if( db->xAuth ){ int rcauth; char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zCnName; rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb); bIgnore = (rcauth==SQLITE_IGNORE); } #endif } /* Take a shared-cache advisory read-lock on the parent table. Allocate ** a cursor to use to search the unique index on the parent key columns ** in the parent table. */ sqlite3TableLock(pParse, iDb, pTo->tnum, 0, pTo->zName); pParse->nTab++; if( regOld!=0 ){ /* A row is being removed from the child table. Search for the parent. ** If the parent does not exist, removing the child row resolves an ** outstanding foreign key constraint violation. */ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore); } if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){ /* A row is being added to the child table. If a parent row cannot ** be found, adding the child row has violated the FK constraint. ** ** If this operation is being performed as part of a trigger program ** that is actually a "SET NULL" action belonging to this very ** foreign key, then omit this scan altogether. As all child key ** values are guaranteed to be NULL, it is not possible for adding ** this row to cause an FK violation. */ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1, bIgnore); } sqlite3DbFree(db, aiFree); } /* Loop through all the foreign key constraints that refer to this table. ** (the "child" constraints) */ for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){ Index *pIdx = 0; /* Foreign key index for pFKey */ SrcList *pSrc; int *aiCol = 0; if( aChange && fkParentIsModified(pTab, pFKey, aChange, bChngRowid)==0 ){ continue; } if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs) && !pParse->pToplevel && !pParse->isMultiWrite ){ assert( regOld==0 && regNew!=0 ); /* Inserting a single row into a parent table cannot cause (or fix) ** an immediate foreign key violation. So do nothing in this case. */ continue; } if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){ if( !isIgnoreErrors || db->mallocFailed ) return; continue; } assert( aiCol || pFKey->nCol==1 ); /* Create a SrcList structure containing the child table. We need the ** child table as a SrcList for sqlite3WhereBegin() */ pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc ){ SrcItem *pItem = pSrc->a; pItem->pTab = pFKey->pFrom; pItem->zName = pFKey->pFrom->zName; pItem->pTab->nTabRef++; pItem->iCursor = pParse->nTab++; if( regNew!=0 ){ fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1); } if( regOld!=0 ){ int eAction = pFKey->aAction[aChange!=0]; if( (db->flags & SQLITE_FkNoAction) ) eAction = OE_None; fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1); /* If this is a deferred FK constraint, or a CASCADE or SET NULL ** action applies, then any foreign key violations caused by ** removing the parent key will be rectified by the action trigger. ** So do not set the "may-abort" flag in this case. ** ** Note 1: If the FK is declared "ON UPDATE CASCADE", then the ** may-abort flag will eventually be set on this statement anyway ** (when this function is called as part of processing the UPDATE ** within the action trigger). ** ** Note 2: At first glance it may seem like SQLite could simply omit ** all OP_FkCounter related scans when either CASCADE or SET NULL ** applies. The trouble starts if the CASCADE or SET NULL action ** trigger causes other triggers or action rules attached to the ** child table to fire. In these cases the fk constraint counters ** might be set incorrectly if any OP_FkCounter related scans are ** omitted. */ if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){ sqlite3MayAbort(pParse); } } pItem->zName = 0; sqlite3SrcListDelete(db, pSrc); } sqlite3DbFree(db, aiCol); } } #define COLUMN_MASK(x) (((x)>31) ? 0xffffffff : ((u32)1<<(x))) /* ** This function is called before generating code to update or delete a ** row contained in table pTab. */ SQLITE_PRIVATE u32 sqlite3FkOldmask( Parse *pParse, /* Parse context */ Table *pTab /* Table being modified */ ){ u32 mask = 0; if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){ FKey *p; int i; for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ for(i=0; inCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); } for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Index *pIdx = 0; sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0); if( pIdx ){ for(i=0; inKeyCol; i++){ assert( pIdx->aiColumn[i]>=0 ); mask |= COLUMN_MASK(pIdx->aiColumn[i]); } } } } return mask; } /* ** This function is called before generating code to update or delete a ** row contained in table pTab. If the operation is a DELETE, then ** parameter aChange is passed a NULL value. For an UPDATE, aChange points ** to an array of size N, where N is the number of columns in table pTab. ** If the i'th column is not modified by the UPDATE, then the corresponding ** entry in the aChange[] array is set to -1. If the column is modified, ** the value is 0 or greater. Parameter chngRowid is set to true if the ** UPDATE statement modifies the rowid fields of the table. ** ** If any foreign key processing will be required, this function returns ** non-zero. If there is no foreign key related processing, this function ** returns zero. ** ** For an UPDATE, this function returns 2 if: ** ** * There are any FKs for which pTab is the child and the parent table ** and any FK processing at all is required (even of a different FK), or ** ** * the UPDATE modifies one or more parent keys for which the action is ** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL). ** ** Or, assuming some other foreign key processing is required, 1. */ SQLITE_PRIVATE int sqlite3FkRequired( Parse *pParse, /* Parse context */ Table *pTab, /* Table being modified */ int *aChange, /* Non-NULL for UPDATE operations */ int chngRowid /* True for UPDATE that affects rowid */ ){ int eRet = 1; /* Value to return if bHaveFK is true */ int bHaveFK = 0; /* If FK processing is required */ if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){ if( !aChange ){ /* A DELETE operation. Foreign key processing is required if the ** table in question is either the child or parent table for any ** foreign key constraint. */ bHaveFK = (sqlite3FkReferences(pTab) || pTab->u.tab.pFKey); }else{ /* This is an UPDATE. Foreign key processing is only required if the ** operation modifies one or more child or parent key columns. */ FKey *p; /* Check if any child key columns are being modified. */ for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ if( fkChildIsModified(pTab, p, aChange, chngRowid) ){ if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) eRet = 2; bHaveFK = 1; } } /* Check if any parent key columns are being modified. */ for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ if( fkParentIsModified(pTab, p, aChange, chngRowid) ){ if( (pParse->db->flags & SQLITE_FkNoAction)==0 && p->aAction[1]!=OE_None ){ return 2; } bHaveFK = 1; } } } } return bHaveFK ? eRet : 0; } /* ** This function is called when an UPDATE or DELETE operation is being ** compiled on table pTab, which is the parent table of foreign-key pFKey. ** If the current operation is an UPDATE, then the pChanges parameter is ** passed a pointer to the list of columns being modified. If it is a ** DELETE, pChanges is passed a NULL pointer. ** ** It returns a pointer to a Trigger structure containing a trigger ** equivalent to the ON UPDATE or ON DELETE action specified by pFKey. ** If the action is "NO ACTION" then a NULL pointer is returned (these actions ** require no special handling by the triggers sub-system, code for them is ** created by fkScanChildren()). ** ** For example, if pFKey is the foreign key and pTab is table "p" in ** the following schema: ** ** CREATE TABLE p(pk PRIMARY KEY); ** CREATE TABLE c(ck REFERENCES p ON DELETE CASCADE); ** ** then the returned trigger structure is equivalent to: ** ** CREATE TRIGGER ... DELETE ON p BEGIN ** DELETE FROM c WHERE ck = old.pk; ** END; ** ** The returned pointer is cached as part of the foreign key object. It ** is eventually freed along with the rest of the foreign key object by ** sqlite3FkDelete(). */ static Trigger *fkActionTrigger( Parse *pParse, /* Parse context */ Table *pTab, /* Table being updated or deleted from */ FKey *pFKey, /* Foreign key to get action for */ ExprList *pChanges /* Change-list for UPDATE, NULL for DELETE */ ){ sqlite3 *db = pParse->db; /* Database handle */ int action; /* One of OE_None, OE_Cascade etc. */ Trigger *pTrigger; /* Trigger definition to return */ int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */ action = pFKey->aAction[iAction]; if( (db->flags & SQLITE_FkNoAction) ) action = OE_None; if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){ return 0; } pTrigger = pFKey->apTrigger[iAction]; if( action!=OE_None && !pTrigger ){ char const *zFrom; /* Name of child table */ int nFrom; /* Length in bytes of zFrom */ Index *pIdx = 0; /* Parent key index for this FK */ int *aiCol = 0; /* child table cols -> parent key cols */ TriggerStep *pStep = 0; /* First (only) step of trigger program */ Expr *pWhere = 0; /* WHERE clause of trigger step */ ExprList *pList = 0; /* Changes list if ON UPDATE CASCADE */ Select *pSelect = 0; /* If RESTRICT, "SELECT RAISE(...)" */ int i; /* Iterator variable */ Expr *pWhen = 0; /* WHEN clause for the trigger */ if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0; assert( aiCol || pFKey->nCol==1 ); for(i=0; inCol; i++){ Token tOld = { "old", 3 }; /* Literal "old" token */ Token tNew = { "new", 3 }; /* Literal "new" token */ Token tFromCol; /* Name of column in child table */ Token tToCol; /* Name of column in parent table */ int iFromCol; /* Idx of column in child table */ Expr *pEq; /* tFromCol = OLD.tToCol */ iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iFromCol>=0 ); assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKeynCol) ); assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); sqlite3TokenInit(&tToCol, pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zCnName); sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zCnName); /* Create the expression "OLD.zToCol = zFromCol". It is important ** that the "OLD.zToCol" term is on the LHS of the = operator, so ** that the affinity and collation sequence associated with the ** parent table are used for the comparison. */ pEq = sqlite3PExpr(pParse, TK_EQ, sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tOld, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0) ); pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); /* For ON UPDATE, construct the next term of the WHEN clause. ** The final WHEN clause will be like this: ** ** WHEN NOT(old.col1 IS new.col1 AND ... AND old.colN IS new.colN) */ if( pChanges ){ pEq = sqlite3PExpr(pParse, TK_IS, sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tOld, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tNew, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)) ); pWhen = sqlite3ExprAnd(pParse, pWhen, pEq); } if( action!=OE_Restrict && (action!=OE_Cascade || pChanges) ){ Expr *pNew; if( action==OE_Cascade ){ pNew = sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tNew, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)); }else if( action==OE_SetDflt ){ Column *pCol = pFKey->pFrom->aCol + iFromCol; Expr *pDflt; if( pCol->colFlags & COLFLAG_GENERATED ){ testcase( pCol->colFlags & COLFLAG_VIRTUAL ); testcase( pCol->colFlags & COLFLAG_STORED ); pDflt = 0; }else{ pDflt = sqlite3ColumnExpr(pFKey->pFrom, pCol); } if( pDflt ){ pNew = sqlite3ExprDup(db, pDflt, 0); }else{ pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); } }else{ pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); } pList = sqlite3ExprListAppend(pParse, pList, pNew); sqlite3ExprListSetName(pParse, pList, &tFromCol, 0); } } sqlite3DbFree(db, aiCol); zFrom = pFKey->pFrom->zName; nFrom = sqlite3Strlen30(zFrom); if( action==OE_Restrict ){ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); SrcList *pSrc; Expr *pRaise; pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed"); if( pRaise ){ pRaise->affExpr = OE_Abort; } pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc ){ assert( pSrc->nSrc==1 ); pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom); pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); } pSelect = sqlite3SelectNew(pParse, sqlite3ExprListAppend(pParse, 0, pRaise), pSrc, pWhere, 0, 0, 0, 0, 0 ); pWhere = 0; } /* Disable lookaside memory allocation */ DisableLookaside; pTrigger = (Trigger *)sqlite3DbMallocZero(db, sizeof(Trigger) + /* struct Trigger */ sizeof(TriggerStep) + /* Single step in trigger program */ nFrom + 1 /* Space for pStep->zTarget */ ); if( pTrigger ){ pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1]; pStep->zTarget = (char *)&pStep[1]; memcpy((char *)pStep->zTarget, zFrom, nFrom); pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE); pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); if( pWhen ){ pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0); pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); } } /* Re-enable the lookaside buffer, if it was disabled earlier. */ EnableLookaside; sqlite3ExprDelete(db, pWhere); sqlite3ExprDelete(db, pWhen); sqlite3ExprListDelete(db, pList); sqlite3SelectDelete(db, pSelect); if( db->mallocFailed==1 ){ fkTriggerDelete(db, pTrigger); return 0; } assert( pStep!=0 ); assert( pTrigger!=0 ); switch( action ){ case OE_Restrict: pStep->op = TK_SELECT; break; case OE_Cascade: if( !pChanges ){ pStep->op = TK_DELETE; break; } /* no break */ deliberate_fall_through default: pStep->op = TK_UPDATE; } pStep->pTrig = pTrigger; pTrigger->pSchema = pTab->pSchema; pTrigger->pTabSchema = pTab->pSchema; pFKey->apTrigger[iAction] = pTrigger; pTrigger->op = (pChanges ? TK_UPDATE : TK_DELETE); } return pTrigger; } /* ** This function is called when deleting or updating a row to implement ** any required CASCADE, SET NULL or SET DEFAULT actions. */ SQLITE_PRIVATE void sqlite3FkActions( Parse *pParse, /* Parse context */ Table *pTab, /* Table being updated or deleted from */ ExprList *pChanges, /* Change-list for UPDATE, NULL for DELETE */ int regOld, /* Address of array containing old row */ int *aChange, /* Array indicating UPDATEd columns (or 0) */ int bChngRowid /* True if rowid is UPDATEd */ ){ /* If foreign-key support is enabled, iterate through all FKs that ** refer to table pTab. If there is an action associated with the FK ** for this operation (either update or delete), invoke the associated ** trigger sub-program. */ if( pParse->db->flags&SQLITE_ForeignKeys ){ FKey *pFKey; /* Iterator variable */ for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){ if( aChange==0 || fkParentIsModified(pTab, pFKey, aChange, bChngRowid) ){ Trigger *pAct = fkActionTrigger(pParse, pTab, pFKey, pChanges); if( pAct ){ sqlite3CodeRowTriggerDirect(pParse, pAct, pTab, regOld, OE_Abort, 0); } } } } } #endif /* ifndef SQLITE_OMIT_TRIGGER */ /* ** Free all memory associated with foreign key definitions attached to ** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash ** hash table. */ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ assert( IsOrdinaryTable(pTab) ); assert( db!=0 ); for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){ assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); /* Remove the FK from the fkeyHash hash table. */ if( db->pnBytesFreed==0 ){ if( pFKey->pPrevTo ){ pFKey->pPrevTo->pNextTo = pFKey->pNextTo; }else{ const char *z = (pFKey->pNextTo ? pFKey->pNextTo->zTo : pFKey->zTo); sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, pFKey->pNextTo); } if( pFKey->pNextTo ){ pFKey->pNextTo->pPrevTo = pFKey->pPrevTo; } } /* EV: R-30323-21917 Each foreign key constraint in SQLite is ** classified as either immediate or deferred. */ assert( pFKey->isDeferred==0 || pFKey->isDeferred==1 ); /* Delete any triggers created to implement actions for this FK. */ #ifndef SQLITE_OMIT_TRIGGER fkTriggerDelete(db, pFKey->apTrigger[0]); fkTriggerDelete(db, pFKey->apTrigger[1]); #endif pNext = pFKey->pNextFrom; sqlite3DbFree(db, pFKey); } } #endif /* ifndef SQLITE_OMIT_FOREIGN_KEY */ /************** End of fkey.c ************************************************/ /************** Begin file insert.c ******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. */ /* #include "sqliteInt.h" */ /* ** Generate code that will ** ** (1) acquire a lock for table pTab then ** (2) open pTab as cursor iCur. ** ** If pTab is a WITHOUT ROWID table, then it is the PRIMARY KEY index ** for that table that is actually opened. */ SQLITE_PRIVATE void sqlite3OpenTable( Parse *pParse, /* Generate code into this VDBE */ int iCur, /* The cursor number of the table */ int iDb, /* The database index in sqlite3.aDb[] */ Table *pTab, /* The table to be opened */ int opcode /* OP_OpenRead or OP_OpenWrite */ ){ Vdbe *v; assert( !IsVirtual(pTab) ); assert( pParse->pVdbe!=0 ); v = pParse->pVdbe; assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); if( !pParse->db->noSharedCache ){ sqlite3TableLock(pParse, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName); } if( HasRowid(pTab) ){ sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol); VdbeComment((v, "%s", pTab->zName)); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); assert( pPk->tnum==pTab->tnum || CORRUPT_DB ); sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pPk); VdbeComment((v, "%s", pTab->zName)); } } /* ** Return a pointer to the column affinity string associated with index ** pIdx. A column affinity string has one character for each column in ** the table, according to the affinity of the column: ** ** Character Column affinity ** ------------------------------ ** 'A' BLOB ** 'B' TEXT ** 'C' NUMERIC ** 'D' INTEGER ** 'F' REAL ** ** An extra 'D' is appended to the end of the string to cover the ** rowid that appears as the last column in every index. ** ** Memory for the buffer containing the column index affinity string ** is managed along with the rest of the Index structure. It will be ** released when sqlite3DeleteIndex() is called. */ static SQLITE_NOINLINE const char *computeIndexAffStr(sqlite3 *db, Index *pIdx){ /* The first time a column affinity string for a particular index is ** required, it is allocated and populated here. It is then stored as ** a member of the Index structure for subsequent use. ** ** The column affinity string will eventually be deleted by ** sqliteDeleteIndex() when the Index structure itself is cleaned ** up. */ int n; Table *pTab = pIdx->pTable; pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1); if( !pIdx->zColAff ){ sqlite3OomFault(db); return 0; } for(n=0; nnColumn; n++){ i16 x = pIdx->aiColumn[n]; char aff; if( x>=0 ){ aff = pTab->aCol[x].affinity; }else if( x==XN_ROWID ){ aff = SQLITE_AFF_INTEGER; }else{ assert( x==XN_EXPR ); assert( pIdx->bHasExpr ); assert( pIdx->aColExpr!=0 ); aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); } if( affSQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC; pIdx->zColAff[n] = aff; } pIdx->zColAff[n] = 0; return pIdx->zColAff; } SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){ if( !pIdx->zColAff ) return computeIndexAffStr(db, pIdx); return pIdx->zColAff; } /* ** Compute an affinity string for a table. Space is obtained ** from sqlite3DbMalloc(). The caller is responsible for freeing ** the space when done. */ SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3 *db, const Table *pTab){ char *zColAff; zColAff = (char *)sqlite3DbMallocRaw(db, pTab->nCol+1); if( zColAff ){ int i, j; for(i=j=0; inCol; i++){ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ zColAff[j++] = pTab->aCol[i].affinity; } } do{ zColAff[j--] = 0; }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB ); } return zColAff; } /* ** Make changes to the evolving bytecode to do affinity transformations ** of values that are about to be gathered into a row for table pTab. ** ** For ordinary (legacy, non-strict) tables: ** ----------------------------------------- ** ** Compute the affinity string for table pTab, if it has not already been ** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities. ** ** If the affinity string is empty (because it was all SQLITE_AFF_BLOB entries ** which were then optimized out) then this routine becomes a no-op. ** ** Otherwise if iReg>0 then code an OP_Affinity opcode that will set the ** affinities for register iReg and following. Or if iReg==0, ** then just set the P4 operand of the previous opcode (which should be ** an OP_MakeRecord) to the affinity string. ** ** A column affinity string has one character per column: ** ** Character Column affinity ** --------- --------------- ** 'A' BLOB ** 'B' TEXT ** 'C' NUMERIC ** 'D' INTEGER ** 'E' REAL ** ** For STRICT tables: ** ------------------ ** ** Generate an appropriate OP_TypeCheck opcode that will verify the ** datatypes against the column definitions in pTab. If iReg==0, that ** means an OP_MakeRecord opcode has already been generated and should be ** the last opcode generated. The new OP_TypeCheck needs to be inserted ** before the OP_MakeRecord. The new OP_TypeCheck should use the same ** register set as the OP_MakeRecord. If iReg>0 then register iReg is ** the first of a series of registers that will form the new record. ** Apply the type checking to that array of registers. */ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ int i; char *zColAff; if( pTab->tabFlags & TF_Strict ){ if( iReg==0 ){ /* Move the previous opcode (which should be OP_MakeRecord) forward ** by one slot and insert a new OP_TypeCheck where the current ** OP_MakeRecord is found */ VdbeOp *pPrev; sqlite3VdbeAppendP4(v, pTab, P4_TABLE); pPrev = sqlite3VdbeGetLastOp(v); assert( pPrev!=0 ); assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed ); pPrev->opcode = OP_TypeCheck; sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3); }else{ /* Insert an isolated OP_Typecheck */ sqlite3VdbeAddOp2(v, OP_TypeCheck, iReg, pTab->nNVCol); sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } return; } zColAff = pTab->zColAff; if( zColAff==0 ){ zColAff = sqlite3TableAffinityStr(0, pTab); if( !zColAff ){ sqlite3OomFault(sqlite3VdbeDb(v)); return; } pTab->zColAff = zColAff; } assert( zColAff!=0 ); i = sqlite3Strlen30NN(zColAff); if( i ){ if( iReg ){ sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i); }else{ assert( sqlite3VdbeGetLastOp(v)->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed ); sqlite3VdbeChangeP4(v, -1, zColAff, i); } } } /* ** Return non-zero if the table pTab in database iDb or any of its indices ** have been opened at any point in the VDBE program. This is used to see if ** a statement of the form "INSERT INTO SELECT ..." can ** run without using a temporary table for the results of the SELECT. */ static int readsTable(Parse *p, int iDb, Table *pTab){ Vdbe *v = sqlite3GetVdbe(p); int i; int iEnd = sqlite3VdbeCurrentAddr(v); #ifndef SQLITE_OMIT_VIRTUALTABLE VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0; #endif for(i=1; iopcode==OP_OpenRead && pOp->p3==iDb ){ Index *pIndex; Pgno tnum = pOp->p2; if( tnum==pTab->tnum ){ return 1; } for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ if( tnum==pIndex->tnum ){ return 1; } } } #ifndef SQLITE_OMIT_VIRTUALTABLE if( pOp->opcode==OP_VOpen && pOp->p4.pVtab==pVTab ){ assert( pOp->p4.pVtab!=0 ); assert( pOp->p4type==P4_VTAB ); return 1; } #endif } return 0; } /* This walker callback will compute the union of colFlags flags for all ** referenced columns in a CHECK constraint or generated column expression. */ static int exprColumnFlagUnion(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 ){ assert( pExpr->iColumn < pWalker->u.pTab->nCol ); pWalker->eCode |= pWalker->u.pTab->aCol[pExpr->iColumn].colFlags; } return WRC_Continue; } #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* ** All regular columns for table pTab have been puts into registers ** starting with iRegStore. The registers that correspond to STORED ** or VIRTUAL columns have not yet been initialized. This routine goes ** back and computes the values for those columns based on the previously ** computed normal columns. */ SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns( Parse *pParse, /* Parsing context */ int iRegStore, /* Register holding the first column */ Table *pTab /* The table */ ){ int i; Walker w; Column *pRedo; int eProgress; VdbeOp *pOp; assert( pTab->tabFlags & TF_HasGenerated ); testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); /* Before computing generated columns, first go through and make sure ** that appropriate affinity has been applied to the regular columns */ sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore); if( (pTab->tabFlags & TF_HasStored)!=0 ){ pOp = sqlite3VdbeGetLastOp(pParse->pVdbe); if( pOp->opcode==OP_Affinity ){ /* Change the OP_Affinity argument to '@' (NONE) for all stored ** columns. '@' is the no-op affinity and those columns have not ** yet been computed. */ int ii, jj; char *zP4 = pOp->p4.z; assert( zP4!=0 ); assert( pOp->p4type==P4_DYNAMIC ); for(ii=jj=0; zP4[jj]; ii++){ if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){ continue; } if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){ zP4[jj] = SQLITE_AFF_NONE; } jj++; } }else if( pOp->opcode==OP_TypeCheck ){ /* If an OP_TypeCheck was generated because the table is STRICT, ** then set the P3 operand to indicate that generated columns should ** not be checked */ pOp->p3 = 1; } } /* Because there can be multiple generated columns that refer to one another, ** this is a two-pass algorithm. On the first pass, mark all generated ** columns as "not available". */ for(i=0; inCol; i++){ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL; } } w.u.pTab = pTab; w.xExprCallback = exprColumnFlagUnion; w.xSelectCallback = 0; w.xSelectCallback2 = 0; /* On the second pass, compute the value of each NOT-AVAILABLE column. ** Companion code in the TK_COLUMN case of sqlite3ExprCodeTarget() will ** compute dependencies and mark remove the COLSPAN_NOTAVAIL mark, as ** they are needed. */ pParse->iSelfTab = -iRegStore; do{ eProgress = 0; pRedo = 0; for(i=0; inCol; i++){ Column *pCol = pTab->aCol + i; if( (pCol->colFlags & COLFLAG_NOTAVAIL)!=0 ){ int x; pCol->colFlags |= COLFLAG_BUSY; w.eCode = 0; sqlite3WalkExpr(&w, sqlite3ColumnExpr(pTab, pCol)); pCol->colFlags &= ~COLFLAG_BUSY; if( w.eCode & COLFLAG_NOTAVAIL ){ pRedo = pCol; continue; } eProgress = 1; assert( pCol->colFlags & COLFLAG_GENERATED ); x = sqlite3TableColumnToStorage(pTab, i) + iRegStore; sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, x); pCol->colFlags &= ~COLFLAG_NOTAVAIL; } } }while( pRedo && eProgress ); if( pRedo ){ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zCnName); } pParse->iSelfTab = 0; } #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ #ifndef SQLITE_OMIT_AUTOINCREMENT /* ** Locate or create an AutoincInfo structure associated with table pTab ** which is in database iDb. Return the register number for the register ** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT ** table. (Also return zero when doing a VACUUM since we do not want to ** update the AUTOINCREMENT counters during a VACUUM.) ** ** There is at most one AutoincInfo structure per table even if the ** same table is autoincremented multiple times due to inserts within ** triggers. A new AutoincInfo structure is created if this is the ** first use of table pTab. On 2nd and subsequent uses, the original ** AutoincInfo structure is used. ** ** Four consecutive registers are allocated: ** ** (1) The name of the pTab table. ** (2) The maximum ROWID of pTab. ** (3) The rowid in sqlite_sequence of pTab ** (4) The original value of the max ROWID in pTab, or NULL if none ** ** The 2nd register is the one that is returned. That is all the ** insert routine needs to know about. */ static int autoIncBegin( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database holding pTab */ Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ assert( pParse->db->aDb[iDb].pSchema!=0 ); if( (pTab->tabFlags & TF_Autoincrement)!=0 && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); AutoincInfo *pInfo; Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab; /* Verify that the sqlite_sequence table exists and is an ordinary ** rowid table with exactly two columns. ** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */ if( pSeqTab==0 || !HasRowid(pSeqTab) || NEVER(IsVirtual(pSeqTab)) || pSeqTab->nCol!=2 ){ pParse->nErr++; pParse->rc = SQLITE_CORRUPT_SEQUENCE; return 0; } pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } if( pInfo==0 ){ pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo)); sqlite3ParserAddCleanup(pToplevel, sqlite3DbFree, pInfo); testcase( pParse->earlyCleanup ); if( pParse->db->mallocFailed ) return 0; pInfo->pNext = pToplevel->pAinc; pToplevel->pAinc = pInfo; pInfo->pTab = pTab; pInfo->iDb = iDb; pToplevel->nMem++; /* Register to hold name of table */ pInfo->regCtr = ++pToplevel->nMem; /* Max rowid register */ pToplevel->nMem +=2; /* Rowid in sqlite_sequence + orig max val */ } memId = pInfo->regCtr; } return memId; } /* ** This routine generates code that will initialize all of the ** register used by the autoincrement tracker. */ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){ AutoincInfo *p; /* Information about an AUTOINCREMENT */ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* Database only autoinc table */ int memId; /* Register holding max rowid */ Vdbe *v = pParse->pVdbe; /* VDBE under construction */ /* This routine is never called during trigger-generation. It is ** only called from the top-level */ assert( pParse->pTriggerTab==0 ); assert( sqlite3IsToplevel(pParse) ); assert( v ); /* We failed long ago if this is not so */ for(p = pParse->pAinc; p; p = p->pNext){ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList autoInc[] = { /* 0 */ {OP_Null, 0, 0, 0}, /* 1 */ {OP_Rewind, 0, 10, 0}, /* 2 */ {OP_Column, 0, 0, 0}, /* 3 */ {OP_Ne, 0, 9, 0}, /* 4 */ {OP_Rowid, 0, 0, 0}, /* 5 */ {OP_Column, 0, 1, 0}, /* 6 */ {OP_AddImm, 0, 0, 0}, /* 7 */ {OP_Copy, 0, 0, 0}, /* 8 */ {OP_Goto, 0, 11, 0}, /* 9 */ {OP_Next, 0, 2, 0}, /* 10 */ {OP_Integer, 0, 0, 0}, /* 11 */ {OP_Close, 0, 0, 0} }; VdbeOp *aOp; pDb = &db->aDb[p->iDb]; memId = p->regCtr; assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead); sqlite3VdbeLoadString(v, memId-1, p->pTab->zName); aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn); if( aOp==0 ) break; aOp[0].p2 = memId; aOp[0].p3 = memId+2; aOp[2].p3 = memId; aOp[3].p1 = memId-1; aOp[3].p3 = memId; aOp[3].p5 = SQLITE_JUMPIFNULL; aOp[4].p2 = memId+1; aOp[5].p3 = memId; aOp[6].p1 = memId; aOp[7].p2 = memId+2; aOp[7].p1 = memId; aOp[10].p2 = memId; if( pParse->nTab==0 ) pParse->nTab = 1; } } /* ** Update the maximum rowid for an autoincrement calculation. ** ** This routine should be called when the regRowid register holds a ** new rowid that is about to be inserted. If that new rowid is ** larger than the maximum rowid in the memId memory cell, then the ** memory cell is updated. */ static void autoIncStep(Parse *pParse, int memId, int regRowid){ if( memId>0 ){ sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, regRowid); } } /* ** This routine generates the code needed to write autoincrement ** maximum rowid values back into the sqlite_sequence register. ** Every statement that might do an INSERT into an autoincrement ** table (either directly or through triggers) needs to call this ** routine just before the "exit" code. */ static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){ AutoincInfo *p; Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; assert( v ); for(p = pParse->pAinc; p; p = p->pNext){ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList autoIncEnd[] = { /* 0 */ {OP_NotNull, 0, 2, 0}, /* 1 */ {OP_NewRowid, 0, 0, 0}, /* 2 */ {OP_MakeRecord, 0, 2, 0}, /* 3 */ {OP_Insert, 0, 0, 0}, /* 4 */ {OP_Close, 0, 0, 0} }; VdbeOp *aOp; Db *pDb = &db->aDb[p->iDb]; int iRec; int memId = p->regCtr; iRec = sqlite3GetTempReg(pParse); assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); sqlite3VdbeAddOp3(v, OP_Le, memId+2, sqlite3VdbeCurrentAddr(v)+7, memId); VdbeCoverage(v); sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn); if( aOp==0 ) break; aOp[0].p1 = memId+1; aOp[1].p2 = memId+1; aOp[2].p1 = memId-1; aOp[2].p3 = iRec; aOp[3].p2 = iRec; aOp[3].p3 = memId+1; aOp[3].p5 = OPFLAG_APPEND; sqlite3ReleaseTempReg(pParse, iRec); } } SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){ if( pParse->pAinc ) autoIncrementEnd(pParse); } #else /* ** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines ** above are all no-ops */ # define autoIncBegin(A,B,C) (0) # define autoIncStep(A,B,C) #endif /* SQLITE_OMIT_AUTOINCREMENT */ /* Forward declaration */ static int xferOptimization( Parse *pParse, /* Parser context */ Table *pDest, /* The table we are inserting into */ Select *pSelect, /* A SELECT statement to use as the data source */ int onError, /* How to handle constraint errors */ int iDbDest /* The database of pDest */ ); /* ** This routine is called to handle SQL of the following forms: ** ** insert into TABLE (IDLIST) values(EXPRLIST),(EXPRLIST),... ** insert into TABLE (IDLIST) select ** insert into TABLE (IDLIST) default values ** ** The IDLIST following the table name is always optional. If omitted, ** then a list of all (non-hidden) columns for the table is substituted. ** The IDLIST appears in the pColumn parameter. pColumn is NULL if IDLIST ** is omitted. ** ** For the pSelect parameter holds the values to be inserted for the ** first two forms shown above. A VALUES clause is really just short-hand ** for a SELECT statement that omits the FROM clause and everything else ** that follows. If the pSelect parameter is NULL, that means that the ** DEFAULT VALUES form of the INSERT statement is intended. ** ** The code generated follows one of four templates. For a simple ** insert with data coming from a single-row VALUES clause, the code executes ** once straight down through. Pseudo-code follows (we call this ** the "1st template"): ** ** open write cursor to
    and its indices ** put VALUES clause expressions into registers ** write the resulting record into
    ** cleanup ** ** The three remaining templates assume the statement is of the form ** ** INSERT INTO
    SELECT ... ** ** If the SELECT clause is of the restricted form "SELECT * FROM " - ** in other words if the SELECT pulls all columns from a single table ** and there is no WHERE or LIMIT or GROUP BY or ORDER BY clauses, and ** if and are distinct tables but have identical ** schemas, including all the same indices, then a special optimization ** is invoked that copies raw records from over to . ** See the xferOptimization() function for the implementation of this ** template. This is the 2nd template. ** ** open a write cursor to
    ** open read cursor on ** transfer all records in over to
    ** close cursors ** foreach index on
    ** open a write cursor on the
    index ** open a read cursor on the corresponding index ** transfer all records from the read to the write cursors ** close cursors ** end foreach ** ** The 3rd template is for when the second template does not apply ** and the SELECT clause does not read from
    at any time. ** The generated code follows this template: ** ** X <- A ** goto B ** A: setup for the SELECT ** loop over the rows in the SELECT ** load values into registers R..R+n ** yield X ** end loop ** cleanup after the SELECT ** end-coroutine X ** B: open write cursor to
    and its indices ** C: yield X, at EOF goto D ** insert the select result into
    from R..R+n ** goto C ** D: cleanup ** ** The 4th template is used if the insert statement takes its ** values from a SELECT but the data is being inserted into a table ** that is also read as part of the SELECT. In the third form, ** we have to use an intermediate table to store the results of ** the select. The template is like this: ** ** X <- A ** goto B ** A: setup for the SELECT ** loop over the tables in the SELECT ** load value into register R..R+n ** yield X ** end loop ** cleanup after the SELECT ** end co-routine R ** B: open temp table ** L: yield X, at EOF goto M ** insert row from R..R+n into temp table ** goto L ** M: open write cursor to
    and its indices ** rewind temp table ** C: loop over rows of intermediate table ** transfer values form intermediate table into
    ** end loop ** D: cleanup */ SQLITE_PRIVATE void sqlite3Insert( Parse *pParse, /* Parser context */ SrcList *pTabList, /* Name of table into which we are inserting */ Select *pSelect, /* A SELECT statement to use as the data source */ IdList *pColumn, /* Column names corresponding to IDLIST, or NULL. */ int onError, /* How to handle constraint errors */ Upsert *pUpsert /* ON CONFLICT clauses for upsert, or NULL */ ){ sqlite3 *db; /* The main database structure */ Table *pTab; /* The table to insert into. aka TABLE */ int i, j; /* Loop counters */ Vdbe *v; /* Generate code into this virtual machine */ Index *pIdx; /* For looping over indices of the table */ int nColumn; /* Number of columns in the data */ int nHidden = 0; /* Number of hidden columns if TABLE is virtual */ int iDataCur = 0; /* VDBE cursor that is the main data repository */ int iIdxCur = 0; /* First index cursor */ int ipkColumn = -1; /* Column that is the INTEGER PRIMARY KEY */ int endOfLoop; /* Label for the end of the insertion loop */ int srcTab = 0; /* Data comes from this temporary cursor if >=0 */ int addrInsTop = 0; /* Jump to label "D" */ int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */ SelectDest dest; /* Destination for SELECT on rhs of INSERT */ int iDb; /* Index of database holding TABLE */ u8 useTempTable = 0; /* Store SELECT results in intermediate table */ u8 appendFlag = 0; /* True if the insert is likely to be an append */ u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ u8 bIdListInOrder; /* True if IDLIST is in table order */ ExprList *pList = 0; /* List of VALUES() to be inserted */ int iRegStore; /* Register in which to store next column */ /* Register allocations */ int regFromSelect = 0;/* Base register for data coming from SELECT */ int regAutoinc = 0; /* Register holding the AUTOINCREMENT counter */ int regRowCount = 0; /* Memory cell used for the row counter */ int regIns; /* Block of regs holding rowid+data being inserted */ int regRowid; /* registers holding insert rowid */ int regData; /* register holding first column to insert */ int *aRegIdx = 0; /* One register allocated to each index */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to insert into a view */ Trigger *pTrigger; /* List of triggers on pTab, if required */ int tmask; /* Mask of trigger times */ #endif db = pParse->db; assert( db->pParse==pParse ); if( pParse->nErr ){ goto insert_cleanup; } assert( db->mallocFailed==0 ); dest.iSDParm = 0; /* Suppress a harmless compiler warning */ /* If the Select object is really just a simple VALUES() list with a ** single row (the common case) then keep that one row of values ** and discard the other (unused) parts of the pSelect object */ if( pSelect && (pSelect->selFlags & SF_Values)!=0 && pSelect->pPrior==0 ){ pList = pSelect->pEList; pSelect->pEList = 0; sqlite3SelectDelete(db, pSelect); pSelect = 0; } /* Locate the table into which we will be inserting new information. */ assert( pTabList->nSrc==1 ); pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ){ goto insert_cleanup; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDbnDb ); if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, db->aDb[iDb].zDbSName) ){ goto insert_cleanup; } withoutRowid = !HasRowid(pTab); /* Figure out if we have any triggers and if the table being ** inserted into is a view */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask); isView = IsView(pTab); #else # define pTrigger 0 # define tmask 0 # define isView 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) ); #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x10000 ){ sqlite3TreeViewLine(0, "In sqlite3Insert() at %s:%d", __FILE__, __LINE__); sqlite3TreeViewInsert(pParse->pWith, pTabList, pColumn, pSelect, pList, onError, pUpsert, pTrigger); } #endif /* If pTab is really a view, make sure it has been initialized. ** ViewGetColumnNames() is a no-op if pTab is not a view. */ if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto insert_cleanup; } /* Cannot insert into a read-only table. */ if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){ goto insert_cleanup; } /* Allocate a VDBE */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto insert_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, pSelect || pTrigger, iDb); #ifndef SQLITE_OMIT_XFER_OPT /* If the statement is of the form ** ** INSERT INTO SELECT * FROM ; ** ** Then special optimizations can be applied that make the transfer ** very fast and which reduce fragmentation of indices. ** ** This is the 2nd template. */ if( pColumn==0 && pSelect!=0 && pTrigger==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){ assert( !pTrigger ); assert( pList==0 ); goto insert_end; } #endif /* SQLITE_OMIT_XFER_OPT */ /* If this is an AUTOINCREMENT table, look up the sequence number in the ** sqlite_sequence table and store it in memory cell regAutoinc. */ regAutoinc = autoIncBegin(pParse, iDb, pTab); /* Allocate a block registers to hold the rowid and the values ** for all columns of the new row. */ regRowid = regIns = pParse->nMem+1; pParse->nMem += pTab->nCol + 1; if( IsVirtual(pTab) ){ regRowid++; pParse->nMem++; } regData = regRowid+1; /* If the INSERT statement included an IDLIST term, then make sure ** all elements of the IDLIST really are columns of the table and ** remember the column indices. ** ** If the table has an INTEGER PRIMARY KEY column and that column ** is named in the IDLIST, then record in the ipkColumn variable ** the index into IDLIST of the primary key column. ipkColumn is ** the index of the primary key as it appears in IDLIST, not as ** is appears in the original table. (The index of the INTEGER ** PRIMARY KEY in the original table is pTab->iPKey.) After this ** loop, if ipkColumn==(-1), that means that integer primary key ** is unspecified, and hence the table is either WITHOUT ROWID or ** it will automatically generated an integer primary key. ** ** bIdListInOrder is true if the columns in IDLIST are in storage ** order. This enables an optimization that avoids shuffling the ** columns into storage order. False negatives are harmless, ** but false positives will cause database corruption. */ bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0; if( pColumn ){ assert( pColumn->eU4!=EU4_EXPR ); pColumn->eU4 = EU4_IDX; for(i=0; inId; i++){ pColumn->a[i].u4.idx = -1; } for(i=0; inId; i++){ for(j=0; jnCol; j++){ if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){ pColumn->a[i].u4.idx = j; if( i!=j ) bIdListInOrder = 0; if( j==pTab->iPKey ){ ipkColumn = i; assert( !withoutRowid ); } #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ sqlite3ErrorMsg(pParse, "cannot INSERT into generated column \"%s\"", pTab->aCol[j].zCnName); goto insert_cleanup; } #endif break; } } if( j>=pTab->nCol ){ if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ ipkColumn = i; bIdListInOrder = 0; }else{ sqlite3ErrorMsg(pParse, "table %S has no column named %s", pTabList->a, pColumn->a[i].zName); pParse->checkSchema = 1; goto insert_cleanup; } } } } /* Figure out how many columns of data are supplied. If the data ** is coming from a SELECT statement, then generate a co-routine that ** produces a single row of the SELECT on each invocation. The ** co-routine is the common header to the 3rd and 4th templates. */ if( pSelect ){ /* Data is coming from a SELECT or from a multi-row VALUES clause. ** Generate a co-routine to run the SELECT. */ int regYield; /* Register holding co-routine entry-point */ int addrTop; /* Top of the co-routine */ int rc; /* Result code */ regYield = ++pParse->nMem; addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); dest.iSdst = bIdListInOrder ? regData : 0; dest.nSdst = pTab->nCol; rc = sqlite3Select(pParse, pSelect, &dest); regFromSelect = dest.iSdst; assert( db->pParse==pParse ); if( rc || pParse->nErr ) goto insert_cleanup; assert( db->mallocFailed==0 ); sqlite3VdbeEndCoroutine(v, regYield); sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ assert( pSelect->pEList ); nColumn = pSelect->pEList->nExpr; /* Set useTempTable to TRUE if the result of the SELECT statement ** should be written into a temporary table (template 4). Set to ** FALSE if each output row of the SELECT can be written directly into ** the destination table (template 3). ** ** A temp table must be used if the table being updated is also one ** of the tables being read by the SELECT statement. Also use a ** temp table in the case of row triggers. */ if( pTrigger || readsTable(pParse, iDb, pTab) ){ useTempTable = 1; } if( useTempTable ){ /* Invoke the coroutine to extract information from the SELECT ** and add it to a transient table srcTab. The code generated ** here is from the 4th template: ** ** B: open temp table ** L: yield X, goto M at EOF ** insert row from R..R+n into temp table ** goto L ** M: ... */ int regRec; /* Register to hold packed record */ int regTempRowid; /* Register to hold temp table ROWID */ int addrL; /* Label "L" */ srcTab = pParse->nTab++; regRec = sqlite3GetTempReg(pParse); regTempRowid = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn); addrL = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec); sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid); sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid); sqlite3VdbeGoto(v, addrL); sqlite3VdbeJumpHere(v, addrL); sqlite3ReleaseTempReg(pParse, regRec); sqlite3ReleaseTempReg(pParse, regTempRowid); } }else{ /* This is the case if the data for the INSERT is coming from a ** single-row VALUES clause */ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; srcTab = -1; assert( useTempTable==0 ); if( pList ){ nColumn = pList->nExpr; if( sqlite3ResolveExprListNames(&sNC, pList) ){ goto insert_cleanup; } }else{ nColumn = 0; } } /* If there is no IDLIST term but the table has an integer primary ** key, the set the ipkColumn variable to the integer primary key ** column index in the original table definition. */ if( pColumn==0 && nColumn>0 ){ ipkColumn = pTab->iPKey; #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( ipkColumn>=0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){ testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); for(i=ipkColumn-1; i>=0; i--){ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); ipkColumn--; } } } #endif /* Make sure the number of columns in the source data matches the number ** of columns to be inserted into the table. */ assert( TF_HasHidden==COLFLAG_HIDDEN ); assert( TF_HasGenerated==COLFLAG_GENERATED ); assert( COLFLAG_NOINSERT==(COLFLAG_GENERATED|COLFLAG_HIDDEN) ); if( (pTab->tabFlags & (TF_HasGenerated|TF_HasHidden))!=0 ){ for(i=0; inCol; i++){ if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++; } } if( nColumn!=(pTab->nCol-nHidden) ){ sqlite3ErrorMsg(pParse, "table %S has %d columns but %d values were supplied", pTabList->a, pTab->nCol-nHidden, nColumn); goto insert_cleanup; } } if( pColumn!=0 && nColumn!=pColumn->nId ){ sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId); goto insert_cleanup; } /* Initialize the count of rows to be inserted */ if( (db->flags & SQLITE_CountRows)!=0 && !pParse->nested && !pParse->pTriggerTab && !pParse->bReturning ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } /* If this is not a view, open the table and and all indices */ if( !isView ){ int nIdx; nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0, &iDataCur, &iIdxCur); aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+2)); if( aRegIdx==0 ){ goto insert_cleanup; } for(i=0, pIdx=pTab->pIndex; ipNext, i++){ assert( pIdx ); aRegIdx[i] = ++pParse->nMem; pParse->nMem += pIdx->nColumn; } aRegIdx[i] = ++pParse->nMem; /* Register to store the table record */ } #ifndef SQLITE_OMIT_UPSERT if( pUpsert ){ Upsert *pNx; if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"", pTab->zName); goto insert_cleanup; } if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "cannot UPSERT a view"); goto insert_cleanup; } if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){ goto insert_cleanup; } pTabList->a[0].iCursor = iDataCur; pNx = pUpsert; do{ pNx->pUpsertSrc = pTabList; pNx->regData = regData; pNx->iDataCur = iDataCur; pNx->iIdxCur = iIdxCur; if( pNx->pUpsertTarget ){ if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){ goto insert_cleanup; } } pNx = pNx->pNextUpsert; }while( pNx!=0 ); } #endif /* This is the top of the main insertion loop */ if( useTempTable ){ /* This block codes the top of loop only. The complete loop is the ** following pseudocode (template 4): ** ** rewind temp table, if empty goto D ** C: loop over rows of intermediate table ** transfer values form intermediate table into
    ** end loop ** D: ... */ addrInsTop = sqlite3VdbeAddOp1(v, OP_Rewind, srcTab); VdbeCoverage(v); addrCont = sqlite3VdbeCurrentAddr(v); }else if( pSelect ){ /* This block codes the top of loop only. The complete loop is the ** following pseudocode (template 3): ** ** C: yield X, at EOF goto D ** insert the select result into
    from R..R+n ** goto C ** D: ... */ sqlite3VdbeReleaseRegisters(pParse, regData, pTab->nCol, 0, 0); addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); if( ipkColumn>=0 ){ /* tag-20191021-001: If the INTEGER PRIMARY KEY is being generated by the ** SELECT, go ahead and copy the value into the rowid slot now, so that ** the value does not get overwritten by a NULL at tag-20191021-002. */ sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid); } } /* Compute data for ordinary columns of the new entry. Values ** are written in storage order into registers starting with regData. ** Only ordinary columns are computed in this loop. The rowid ** (if there is one) is computed later and generated columns are ** computed after the rowid since they might depend on the value ** of the rowid. */ nHidden = 0; iRegStore = regData; assert( regData==regRowid+1 ); for(i=0; inCol; i++, iRegStore++){ int k; u32 colFlags; assert( i>=nHidden ); if( i==pTab->iPKey ){ /* tag-20191021-002: References to the INTEGER PRIMARY KEY are filled ** using the rowid. So put a NULL in the IPK slot of the record to avoid ** using excess space. The file format definition requires this extra ** NULL - we cannot optimize further by skipping the column completely */ sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); continue; } if( ((colFlags = pTab->aCol[i].colFlags) & COLFLAG_NOINSERT)!=0 ){ nHidden++; if( (colFlags & COLFLAG_VIRTUAL)!=0 ){ /* Virtual columns do not participate in OP_MakeRecord. So back up ** iRegStore by one slot to compensate for the iRegStore++ in the ** outer for() loop */ iRegStore--; continue; }else if( (colFlags & COLFLAG_STORED)!=0 ){ /* Stored columns are computed later. But if there are BEFORE ** triggers, the slots used for stored columns will be OP_Copy-ed ** to a second block of registers, so the register needs to be ** initialized to NULL to avoid an uninitialized register read */ if( tmask & TRIGGER_BEFORE ){ sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); } continue; }else if( pColumn==0 ){ /* Hidden columns that are not explicitly named in the INSERT ** get there default value */ sqlite3ExprCodeFactorable(pParse, sqlite3ColumnExpr(pTab, &pTab->aCol[i]), iRegStore); continue; } } if( pColumn ){ assert( pColumn->eU4==EU4_IDX ); for(j=0; jnId && pColumn->a[j].u4.idx!=i; j++){} if( j>=pColumn->nId ){ /* A column not named in the insert column list gets its ** default value */ sqlite3ExprCodeFactorable(pParse, sqlite3ColumnExpr(pTab, &pTab->aCol[i]), iRegStore); continue; } k = j; }else if( nColumn==0 ){ /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */ sqlite3ExprCodeFactorable(pParse, sqlite3ColumnExpr(pTab, &pTab->aCol[i]), iRegStore); continue; }else{ k = i - nHidden; } if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore); }else if( pSelect ){ if( regFromSelect!=regData ){ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore); } }else{ Expr *pX = pList->a[k].pExpr; int y = sqlite3ExprCodeTarget(pParse, pX, iRegStore); if( y!=iRegStore ){ sqlite3VdbeAddOp2(v, ExprHasProperty(pX, EP_Subquery) ? OP_Copy : OP_SCopy, y, iRegStore); } } } /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel(pParse); if( tmask & TRIGGER_BEFORE ){ int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1); /* build the NEW.* reference row. Note that if there is an INTEGER ** PRIMARY KEY into which a NULL is being inserted, that NULL will be ** translated into a unique ID for the row. But on a BEFORE trigger, ** we do not know what the unique ID will be (because the insert has ** not happened yet) so we substitute a rowid of -1 */ if( ipkColumn<0 ){ sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); }else{ int addr1; assert( !withoutRowid ); if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regCols); }else{ assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regCols); } addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v); } /* Copy the new data already generated. */ assert( pTab->nNVCol>0 || pParse->nErr>0 ); sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1); #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Compute the new value for generated columns after all other ** columns have already been computed. This must be done after ** computing the ROWID in case one of the generated columns ** refers to the ROWID. */ if( pTab->tabFlags & TF_HasGenerated ){ testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); sqlite3ComputeGeneratedColumns(pParse, regCols+1, pTab); } #endif /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, ** do not attempt any conversions before assembling the record. ** If this is a real table, attempt conversions as required by the ** table column affinities. */ if( !isView ){ sqlite3TableAffinity(v, pTab, regCols+1); } /* Fire BEFORE or INSTEAD OF triggers */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, pTab, regCols-pTab->nCol-1, onError, endOfLoop); sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1); } if( !isView ){ if( IsVirtual(pTab) ){ /* The row that the VUpdate opcode will delete: none */ sqlite3VdbeAddOp2(v, OP_Null, 0, regIns); } if( ipkColumn>=0 ){ /* Compute the new rowid */ if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid); }else if( pSelect ){ /* Rowid already initialized at tag-20191021-001 */ }else{ Expr *pIpk = pList->a[ipkColumn].pExpr; if( pIpk->op==TK_NULL && !IsVirtual(pTab) ){ sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); appendFlag = 1; }else{ sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid); } } /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid ** to generate a unique primary key value. */ if( !appendFlag ){ int addr1; if( !IsVirtual(pTab) ){ addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); sqlite3VdbeJumpHere(v, addr1); }else{ addr1 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, addr1+2); VdbeCoverage(v); } sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v); } }else if( IsVirtual(pTab) || withoutRowid ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); }else{ sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); appendFlag = 1; } autoIncStep(pParse, regAutoinc, regRowid); #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Compute the new value for generated columns after all other ** columns have already been computed. This must be done after ** computing the ROWID in case one of the generated columns ** is derived from the INTEGER PRIMARY KEY. */ if( pTab->tabFlags & TF_HasGenerated ){ sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab); } #endif /* Generate code to check constraints and generate index keys and ** do the insertion. */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB); sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); sqlite3MayAbort(pParse); }else #endif { int isReplace = 0;/* Set to true if constraints may cause a replace */ int bUseSeek; /* True to use OPFLAG_SEEKRESULT */ sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert ); if( db->flags & SQLITE_ForeignKeys ){ sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0); } /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE ** constraints or (b) there are no triggers and this table is not a ** parent table in a foreign key constraint. It is safe to set the ** flag in the second case as if any REPLACE constraint is hit, an ** OP_Delete or OP_IdxDelete instruction will be executed on each ** cursor that is disturbed. And these instructions both clear the ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT ** functionality. */ bUseSeek = (isReplace==0 || !sqlite3VdbeHasSubProgram(v)); sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur, regIns, aRegIdx, 0, appendFlag, bUseSeek ); } #ifdef SQLITE_ALLOW_ROWID_IN_VIEW }else if( pParse->bReturning ){ /* If there is a RETURNING clause, populate the rowid register with ** constant value -1, in case one or more of the returned expressions ** refer to the "rowid" of the view. */ sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid); #endif } /* Update the count of rows that are inserted */ if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } if( pTrigger ){ /* Code AFTER triggers */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, pTab, regData-2-pTab->nCol, onError, endOfLoop); } /* The bottom of the main insertion loop, if the data source ** is a SELECT statement. */ sqlite3VdbeResolveLabel(v, endOfLoop); if( useTempTable ){ sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrInsTop); sqlite3VdbeAddOp1(v, OP_Close, srcTab); }else if( pSelect ){ sqlite3VdbeGoto(v, addrCont); #ifdef SQLITE_DEBUG /* If we are jumping back to an OP_Yield that is preceded by an ** OP_ReleaseReg, set the p5 flag on the OP_Goto so that the ** OP_ReleaseReg will be included in the loop. */ if( sqlite3VdbeGetOp(v, addrCont-1)->opcode==OP_ReleaseReg ){ assert( sqlite3VdbeGetOp(v, addrCont)->opcode==OP_Yield ); sqlite3VdbeChangeP5(v, 1); } #endif sqlite3VdbeJumpHere(v, addrInsTop); } #ifndef SQLITE_OMIT_XFER_OPT insert_end: #endif /* SQLITE_OMIT_XFER_OPT */ /* Update the sqlite_sequence table by storing the content of the ** maximum rowid counter values recorded while inserting into ** autoincrement tables. */ if( pParse->nested==0 && pParse->pTriggerTab==0 ){ sqlite3AutoincrementEnd(pParse); } /* ** Return the number of rows inserted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ if( regRowCount ){ sqlite3CodeChangeCount(v, regRowCount, "rows inserted"); } insert_cleanup: sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pList); sqlite3UpsertDelete(db, pUpsert); sqlite3SelectDelete(db, pSelect); sqlite3IdListDelete(db, pColumn); if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx); } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView #endif #ifdef pTrigger #undef pTrigger #endif #ifdef tmask #undef tmask #endif /* ** Meanings of bits in of pWalker->eCode for ** sqlite3ExprReferencesUpdatedColumn() */ #define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */ #define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */ /* This is the Walker callback from sqlite3ExprReferencesUpdatedColumn(). * Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this ** expression node references any of the ** columns that are being modified by an UPDATE statement. */ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN ){ assert( pExpr->iColumn>=0 || pExpr->iColumn==-1 ); if( pExpr->iColumn>=0 ){ if( pWalker->u.aiCol[pExpr->iColumn]>=0 ){ pWalker->eCode |= CKCNSTRNT_COLUMN; } }else{ pWalker->eCode |= CKCNSTRNT_ROWID; } } return WRC_Continue; } /* ** pExpr is a CHECK constraint on a row that is being UPDATE-ed. The ** only columns that are modified by the UPDATE are those for which ** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true. ** ** Return true if CHECK constraint pExpr uses any of the ** changing columns (or the rowid if it is changing). In other words, ** return true if this CHECK constraint must be validated for ** the new row in the UPDATE statement. ** ** 2018-09-15: pExpr might also be an expression for an index-on-expressions. ** The operation of this routine is the same - return true if an only if ** the expression uses one or more of columns identified by the second and ** third arguments. */ SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn( Expr *pExpr, /* The expression to be checked */ int *aiChng, /* aiChng[x]>=0 if column x changed by the UPDATE */ int chngRowid /* True if UPDATE changes the rowid */ ){ Walker w; memset(&w, 0, sizeof(w)); w.eCode = 0; w.xExprCallback = checkConstraintExprNode; w.u.aiCol = aiChng; sqlite3WalkExpr(&w, pExpr); if( !chngRowid ){ testcase( (w.eCode & CKCNSTRNT_ROWID)!=0 ); w.eCode &= ~CKCNSTRNT_ROWID; } testcase( w.eCode==0 ); testcase( w.eCode==CKCNSTRNT_COLUMN ); testcase( w.eCode==CKCNSTRNT_ROWID ); testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) ); return w.eCode!=0; } /* ** The sqlite3GenerateConstraintChecks() routine usually wants to visit ** the indexes of a table in the order provided in the Table->pIndex list. ** However, sometimes (rarely - when there is an upsert) it wants to visit ** the indexes in a different order. The following data structures accomplish ** this. ** ** The IndexIterator object is used to walk through all of the indexes ** of a table in either Index.pNext order, or in some other order established ** by an array of IndexListTerm objects. */ typedef struct IndexListTerm IndexListTerm; typedef struct IndexIterator IndexIterator; struct IndexIterator { int eType; /* 0 for Index.pNext list. 1 for an array of IndexListTerm */ int i; /* Index of the current item from the list */ union { struct { /* Use this object for eType==0: A Index.pNext list */ Index *pIdx; /* The current Index */ } lx; struct { /* Use this object for eType==1; Array of IndexListTerm */ int nIdx; /* Size of the array */ IndexListTerm *aIdx; /* Array of IndexListTerms */ } ax; } u; }; /* When IndexIterator.eType==1, then each index is an array of instances ** of the following object */ struct IndexListTerm { Index *p; /* The index */ int ix; /* Which entry in the original Table.pIndex list is this index*/ }; /* Return the first index on the list */ static Index *indexIteratorFirst(IndexIterator *pIter, int *pIx){ assert( pIter->i==0 ); if( pIter->eType ){ *pIx = pIter->u.ax.aIdx[0].ix; return pIter->u.ax.aIdx[0].p; }else{ *pIx = 0; return pIter->u.lx.pIdx; } } /* Return the next index from the list. Return NULL when out of indexes */ static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){ if( pIter->eType ){ int i = ++pIter->i; if( i>=pIter->u.ax.nIdx ){ *pIx = i; return 0; } *pIx = pIter->u.ax.aIdx[i].ix; return pIter->u.ax.aIdx[i].p; }else{ ++(*pIx); pIter->u.lx.pIdx = pIter->u.lx.pIdx->pNext; return pIter->u.lx.pIdx; } } /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE ** on table pTab. ** ** The regNewData parameter is the first register in a range that contains ** the data to be inserted or the data after the update. There will be ** pTab->nCol+1 registers in this range. The first register (the one ** that regNewData points to) will contain the new rowid, or NULL in the ** case of a WITHOUT ROWID table. The second register in the range will ** contain the content of the first table column. The third register will ** contain the content of the second table column. And so forth. ** ** The regOldData parameter is similar to regNewData except that it contains ** the data prior to an UPDATE rather than afterwards. regOldData is zero ** for an INSERT. This routine can distinguish between UPDATE and INSERT by ** checking regOldData for zero. ** ** For an UPDATE, the pkChng boolean is true if the true primary key (the ** rowid for a normal table or the PRIMARY KEY for a WITHOUT ROWID table) ** might be modified by the UPDATE. If pkChng is false, then the key of ** the iDataCur content table is guaranteed to be unchanged by the UPDATE. ** ** For an INSERT, the pkChng boolean indicates whether or not the rowid ** was explicitly specified as part of the INSERT statement. If pkChng ** is zero, it means that the either rowid is computed automatically or ** that the table is a WITHOUT ROWID table and has no rowid. On an INSERT, ** pkChng will only be true if the INSERT statement provides an integer ** value for either the rowid column or its INTEGER PRIMARY KEY alias. ** ** The code generated by this routine will store new index entries into ** registers identified by aRegIdx[]. No index entry is created for ** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is ** the same as the order of indices on the linked list of indices ** at pTab->pIndex. ** ** (2019-05-07) The generated code also creates a new record for the ** main table, if pTab is a rowid table, and stores that record in the ** register identified by aRegIdx[nIdx] - in other words in the first ** entry of aRegIdx[] past the last index. It is important that the ** record be generated during constraint checks to avoid affinity changes ** to the register content that occur after constraint checks but before ** the new record is inserted. ** ** The caller must have already opened writeable cursors on the main ** table and all applicable indices (that is to say, all indices for which ** aRegIdx[] is not zero). iDataCur is the cursor for the main table when ** inserting or updating a rowid table, or the cursor for the PRIMARY KEY ** index when operating on a WITHOUT ROWID table. iIdxCur is the cursor ** for the first index in the pTab->pIndex list. Cursors for other indices ** are at iIdxCur+N for the N-th element of the pTab->pIndex list. ** ** This routine also generates code to check constraints. NOT NULL, ** CHECK, and UNIQUE constraints are all checked. If a constraint fails, ** then the appropriate action is performed. There are five possible ** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE. ** ** Constraint type Action What Happens ** --------------- ---------- ---------------------------------------- ** any ROLLBACK The current transaction is rolled back and ** sqlite3_step() returns immediately with a ** return code of SQLITE_CONSTRAINT. ** ** any ABORT Back out changes from the current command ** only (do not do a complete rollback) then ** cause sqlite3_step() to return immediately ** with SQLITE_CONSTRAINT. ** ** any FAIL Sqlite3_step() returns immediately with a ** return code of SQLITE_CONSTRAINT. The ** transaction is not rolled back and any ** changes to prior rows are retained. ** ** any IGNORE The attempt in insert or update the current ** row is skipped, without throwing an error. ** Processing continues with the next row. ** (There is an immediate jump to ignoreDest.) ** ** NOT NULL REPLACE The NULL value is replace by the default ** value for that column. If the default value ** is NULL, the action is the same as ABORT. ** ** UNIQUE REPLACE The other row that conflicts with the row ** being inserted is removed. ** ** CHECK REPLACE Illegal. The results in an exception. ** ** Which action to take is determined by the overrideError parameter. ** Or if overrideError==OE_Default, then the pParse->onError parameter ** is used. Or if pParse->onError==OE_Default then the onError value ** for the constraint is used. */ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( Parse *pParse, /* The parser context */ Table *pTab, /* The table being inserted or updated */ int *aRegIdx, /* Use register aRegIdx[i] for index i. 0 for unused */ int iDataCur, /* Canonical data cursor (main table or PK index) */ int iIdxCur, /* First index cursor */ int regNewData, /* First register in a range holding values to insert */ int regOldData, /* Previous content. 0 for INSERTs */ u8 pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */ u8 overrideError, /* Override onError to this if not OE_Default */ int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */ int *aiChng, /* column i is unchanged if aiChng[i]<0 */ Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */ ){ Vdbe *v; /* VDBE under construction */ Index *pIdx; /* Pointer to one of the indices */ Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */ sqlite3 *db; /* Database connection */ int i; /* loop counter */ int ix; /* Index loop counter */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ Upsert *pUpsertClause = 0; /* The specific ON CONFLICT clause for pIdx */ u8 isUpdate; /* True if this is an UPDATE operation */ u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */ int upsertIpkReturn = 0; /* Address of Goto at end of IPK uniqueness check */ int upsertIpkDelay = 0; /* Address of Goto to bypass initial IPK check */ int ipkTop = 0; /* Top of the IPK uniqueness check */ int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */ /* Variables associated with retesting uniqueness constraints after ** replace triggers fire have run */ int regTrigCnt; /* Register used to count replace trigger invocations */ int addrRecheck = 0; /* Jump here to recheck all uniqueness constraints */ int lblRecheckOk = 0; /* Each recheck jumps to this label if it passes */ Trigger *pTrigger; /* List of DELETE triggers on the table pTab */ int nReplaceTrig = 0; /* Number of replace triggers coded */ IndexIterator sIdxIter; /* Index iterator */ isUpdate = regOldData!=0; db = pParse->db; v = pParse->pVdbe; assert( v!=0 ); assert( !IsView(pTab) ); /* This table is not a VIEW */ nCol = pTab->nCol; /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for ** normal rowid tables. nPkField is the number of key fields in the ** pPk index or 1 for a rowid table. In other words, nPkField is the ** number of fields in the true primary key of the table. */ if( HasRowid(pTab) ){ pPk = 0; nPkField = 1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); nPkField = pPk->nKeyCol; } /* Record that this module has started */ VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)", iDataCur, iIdxCur, regNewData, regOldData, pkChng)); /* Test all NOT NULL constraints. */ if( pTab->tabFlags & TF_HasNotNull ){ int b2ndPass = 0; /* True if currently running 2nd pass */ int nSeenReplace = 0; /* Number of ON CONFLICT REPLACE operations */ int nGenerated = 0; /* Number of generated columns with NOT NULL */ while(1){ /* Make 2 passes over columns. Exit loop via "break" */ for(i=0; iaCol[i]; /* The column to check for NOT NULL */ int isGenerated; /* non-zero if column is generated */ onError = pCol->notNull; if( onError==OE_None ) continue; /* No NOT NULL on this column */ if( i==pTab->iPKey ){ continue; /* ROWID is never NULL */ } isGenerated = pCol->colFlags & COLFLAG_GENERATED; if( isGenerated && !b2ndPass ){ nGenerated++; continue; /* Generated columns processed on 2nd pass */ } if( aiChng && aiChng[i]<0 && !isGenerated ){ /* Do not check NOT NULL on columns that do not change */ continue; } if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( onError==OE_Replace ){ if( b2ndPass /* REPLACE becomes ABORT on the 2nd pass */ || pCol->iDflt==0 /* REPLACE is ABORT if no DEFAULT value */ ){ testcase( pCol->colFlags & COLFLAG_VIRTUAL ); testcase( pCol->colFlags & COLFLAG_STORED ); testcase( pCol->colFlags & COLFLAG_GENERATED ); onError = OE_Abort; }else{ assert( !isGenerated ); } }else if( b2ndPass && !isGenerated ){ continue; } assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); testcase( i!=sqlite3TableColumnToStorage(pTab, i) ); iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1; switch( onError ){ case OE_Replace: { int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, iReg); VdbeCoverage(v); assert( (pCol->colFlags & COLFLAG_GENERATED)==0 ); nSeenReplace++; sqlite3ExprCodeCopy(pParse, sqlite3ColumnExpr(pTab, pCol), iReg); sqlite3VdbeJumpHere(v, addr1); break; } case OE_Abort: sqlite3MayAbort(pParse); /* no break */ deliberate_fall_through case OE_Rollback: case OE_Fail: { char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, pCol->zCnName); testcase( zMsg==0 && db->mallocFailed==0 ); sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, iReg); sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); VdbeCoverage(v); break; } default: { assert( onError==OE_Ignore ); sqlite3VdbeAddOp2(v, OP_IsNull, iReg, ignoreDest); VdbeCoverage(v); break; } } /* end switch(onError) */ } /* end loop i over columns */ if( nGenerated==0 && nSeenReplace==0 ){ /* If there are no generated columns with NOT NULL constraints ** and no NOT NULL ON CONFLICT REPLACE constraints, then a single ** pass is sufficient */ break; } if( b2ndPass ) break; /* Never need more than 2 passes */ b2ndPass = 1; #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( nSeenReplace>0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){ /* If any NOT NULL ON CONFLICT REPLACE constraints fired on the ** first pass, recomputed values for all generated columns, as ** those values might depend on columns affected by the REPLACE. */ sqlite3ComputeGeneratedColumns(pParse, regNewData+1, pTab); } #endif } /* end of 2-pass loop */ } /* end if( has-not-null-constraints ) */ /* Test all CHECK constraints */ #ifndef SQLITE_OMIT_CHECK if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ ExprList *pCheck = pTab->pCheck; pParse->iSelfTab = -(regNewData+1); onError = overrideError!=OE_Default ? overrideError : OE_Abort; for(i=0; inExpr; i++){ int allOk; Expr *pCopy; Expr *pExpr = pCheck->a[i].pExpr; if( aiChng && !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng) ){ /* The check constraints do not reference any of the columns being ** updated so there is no point it verifying the check constraint */ continue; } if( bAffinityDone==0 ){ sqlite3TableAffinity(v, pTab, regNewData+1); bAffinityDone = 1; } allOk = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeVerifyAbortable(v, onError); pCopy = sqlite3ExprDup(db, pExpr, 0); if( !db->mallocFailed ){ sqlite3ExprIfTrue(pParse, pCopy, allOk, SQLITE_JUMPIFNULL); } sqlite3ExprDelete(db, pCopy); if( onError==OE_Ignore ){ sqlite3VdbeGoto(v, ignoreDest); }else{ char *zName = pCheck->a[i].zEName; assert( zName!=0 || pParse->db->mallocFailed ); if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, onError, zName, P4_TRANSIENT, P5_ConstraintCheck); } sqlite3VdbeResolveLabel(v, allOk); } pParse->iSelfTab = 0; } #endif /* !defined(SQLITE_OMIT_CHECK) */ /* UNIQUE and PRIMARY KEY constraints should be handled in the following ** order: ** ** (1) OE_Update ** (2) OE_Abort, OE_Fail, OE_Rollback, OE_Ignore ** (3) OE_Replace ** ** OE_Fail and OE_Ignore must happen before any changes are made. ** OE_Update guarantees that only a single row will change, so it ** must happen before OE_Replace. Technically, OE_Abort and OE_Rollback ** could happen in any order, but they are grouped up front for ** convenience. ** ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43 ** The order of constraints used to have OE_Update as (2) and OE_Abort ** and so forth as (1). But apparently PostgreSQL checks the OE_Update ** constraint before any others, so it had to be moved. ** ** Constraint checking code is generated in this order: ** (A) The rowid constraint ** (B) Unique index constraints that do not have OE_Replace as their ** default conflict resolution strategy ** (C) Unique index that do use OE_Replace by default. ** ** The ordering of (2) and (3) is accomplished by making sure the linked ** list of indexes attached to a table puts all OE_Replace indexes last ** in the list. See sqlite3CreateIndex() for where that happens. */ sIdxIter.eType = 0; sIdxIter.i = 0; sIdxIter.u.ax.aIdx = 0; /* Silence harmless compiler warning */ sIdxIter.u.lx.pIdx = pTab->pIndex; if( pUpsert ){ if( pUpsert->pUpsertTarget==0 ){ /* There is just on ON CONFLICT clause and it has no constraint-target */ assert( pUpsert->pNextUpsert==0 ); if( pUpsert->isDoUpdate==0 ){ /* A single ON CONFLICT DO NOTHING clause, without a constraint-target. ** Make all unique constraint resolution be OE_Ignore */ overrideError = OE_Ignore; pUpsert = 0; }else{ /* A single ON CONFLICT DO UPDATE. Make all resolutions OE_Update */ overrideError = OE_Update; } }else if( pTab->pIndex!=0 ){ /* Otherwise, we'll need to run the IndexListTerm array version of the ** iterator to ensure that all of the ON CONFLICT conditions are ** checked first and in order. */ int nIdx, jj; u64 nByte; Upsert *pTerm; u8 *bUsed; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ assert( aRegIdx[nIdx]>0 ); } sIdxIter.eType = 1; sIdxIter.u.ax.nIdx = nIdx; nByte = (sizeof(IndexListTerm)+1)*nIdx + nIdx; sIdxIter.u.ax.aIdx = sqlite3DbMallocZero(db, nByte); if( sIdxIter.u.ax.aIdx==0 ) return; /* OOM */ bUsed = (u8*)&sIdxIter.u.ax.aIdx[nIdx]; pUpsert->pToFree = sIdxIter.u.ax.aIdx; for(i=0, pTerm=pUpsert; pTerm; pTerm=pTerm->pNextUpsert){ if( pTerm->pUpsertTarget==0 ) break; if( pTerm->pUpsertIdx==0 ) continue; /* Skip ON CONFLICT for the IPK */ jj = 0; pIdx = pTab->pIndex; while( ALWAYS(pIdx!=0) && pIdx!=pTerm->pUpsertIdx ){ pIdx = pIdx->pNext; jj++; } if( bUsed[jj] ) continue; /* Duplicate ON CONFLICT clause ignored */ bUsed[jj] = 1; sIdxIter.u.ax.aIdx[i].p = pIdx; sIdxIter.u.ax.aIdx[i].ix = jj; i++; } for(jj=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, jj++){ if( bUsed[jj] ) continue; sIdxIter.u.ax.aIdx[i].p = pIdx; sIdxIter.u.ax.aIdx[i].ix = jj; i++; } assert( i==nIdx ); } } /* Determine if it is possible that triggers (either explicitly coded ** triggers or FK resolution actions) might run as a result of deletes ** that happen when OE_Replace conflict resolution occurs. (Call these ** "replace triggers".) If any replace triggers run, we will need to ** recheck all of the uniqueness constraints after they have all run. ** But on the recheck, the resolution is OE_Abort instead of OE_Replace. ** ** If replace triggers are a possibility, then ** ** (1) Allocate register regTrigCnt and initialize it to zero. ** That register will count the number of replace triggers that ** fire. Constraint recheck only occurs if the number is positive. ** (2) Initialize pTrigger to the list of all DELETE triggers on pTab. ** (3) Initialize addrRecheck and lblRecheckOk ** ** The uniqueness rechecking code will create a series of tests to run ** in a second pass. The addrRecheck and lblRecheckOk variables are ** used to link together these tests which are separated from each other ** in the generate bytecode. */ if( (db->flags & (SQLITE_RecTriggers|SQLITE_ForeignKeys))==0 ){ /* There are not DELETE triggers nor FK constraints. No constraint ** rechecks are needed. */ pTrigger = 0; regTrigCnt = 0; }else{ if( db->flags&SQLITE_RecTriggers ){ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); regTrigCnt = pTrigger!=0 || sqlite3FkRequired(pParse, pTab, 0, 0); }else{ pTrigger = 0; regTrigCnt = sqlite3FkRequired(pParse, pTab, 0, 0); } if( regTrigCnt ){ /* Replace triggers might exist. Allocate the counter and ** initialize it to zero. */ regTrigCnt = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regTrigCnt); VdbeComment((v, "trigger count")); lblRecheckOk = sqlite3VdbeMakeLabel(pParse); addrRecheck = lblRecheckOk; } } /* If rowid is changing, make sure the new rowid does not previously ** exist in the table. */ if( pkChng && pPk==0 ){ int addrRowidOk = sqlite3VdbeMakeLabel(pParse); /* Figure out what action to take in case of a rowid collision */ onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } /* figure out whether or not upsert applies in this case */ if( pUpsert ){ pUpsertClause = sqlite3UpsertOfIndex(pUpsert,0); if( pUpsertClause!=0 ){ if( pUpsertClause->isDoUpdate==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ onError = OE_Update; /* DO UPDATE */ } } if( pUpsertClause!=pUpsert ){ /* The first ON CONFLICT clause has a conflict target other than ** the IPK. We have to jump ahead to that first ON CONFLICT clause ** and then come back here and deal with the IPK afterwards */ upsertIpkDelay = sqlite3VdbeAddOp0(v, OP_Goto); } } /* If the response to a rowid conflict is REPLACE but the response ** to some other UNIQUE constraint is FAIL or IGNORE, then we need ** to defer the running of the rowid conflict checking until after ** the UNIQUE constraints have run. */ if( onError==OE_Replace /* IPK rule is REPLACE */ && onError!=overrideError /* Rules for other constraints are different */ && pTab->pIndex /* There exist other constraints */ && !upsertIpkDelay /* IPK check already deferred by UPSERT */ ){ ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; VdbeComment((v, "defer IPK REPLACE until last")); } if( isUpdate ){ /* pkChng!=0 does not mean that the rowid has changed, only that ** it might have changed. Skip the conflict logic below if the rowid ** is unchanged. */ sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v); } /* Check to see if the new rowid already exists in the table. Skip ** the following conflict logic if it does not. */ VdbeNoopComment((v, "uniqueness check for ROWID")); sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); switch( onError ){ default: { onError = OE_Abort; /* no break */ deliberate_fall_through } case OE_Rollback: case OE_Abort: case OE_Fail: { testcase( onError==OE_Rollback ); testcase( onError==OE_Abort ); testcase( onError==OE_Fail ); sqlite3RowidConstraint(pParse, onError, pTab); break; } case OE_Replace: { /* If there are DELETE triggers on this table and the ** recursive-triggers flag is set, call GenerateRowDelete() to ** remove the conflicting row from the table. This will fire ** the triggers and remove both the table and index b-tree entries. ** ** Otherwise, if there are no triggers or the recursive-triggers ** flag is not set, but the table has one or more indexes, call ** GenerateRowIndexDelete(). This removes the index b-tree entries ** only. The table b-tree entry will be replaced by the new entry ** when it is inserted. ** ** If either GenerateRowDelete() or GenerateRowIndexDelete() is called, ** also invoke MultiWrite() to indicate that this VDBE may require ** statement rollback (if the statement is aborted after the delete ** takes place). Earlier versions called sqlite3MultiWrite() regardless, ** but being more selective here allows statements like: ** ** REPLACE INTO t(rowid) VALUES($newrowid) ** ** to run without a statement journal if there are no indexes on the ** table. */ if( regTrigCnt ){ sqlite3MultiWrite(pParse); sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regNewData, 1, 0, OE_Replace, 1, -1); sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */ nReplaceTrig++; }else{ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK assert( HasRowid(pTab) ); /* This OP_Delete opcode fires the pre-update-hook only. It does ** not modify the b-tree. It is more efficient to let the coming ** OP_Insert replace the existing entry than it is to delete the ** existing entry and then insert a new one. */ sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP); sqlite3VdbeAppendP4(v, pTab, P4_TABLE); #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ if( pTab->pIndex ){ sqlite3MultiWrite(pParse); sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1); } } seenReplace = 1; break; } #ifndef SQLITE_OMIT_UPSERT case OE_Update: { sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur); /* no break */ deliberate_fall_through } #endif case OE_Ignore: { testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } } sqlite3VdbeResolveLabel(v, addrRowidOk); if( pUpsert && pUpsertClause!=pUpsert ){ upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto); }else if( ipkTop ){ ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, ipkTop-1); } } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Compute the revised record entries for indices as we go. ** ** This loop also handles the case of the PRIMARY KEY index for a ** WITHOUT ROWID table. */ for(pIdx = indexIteratorFirst(&sIdxIter, &ix); pIdx; pIdx = indexIteratorNext(&sIdxIter, &ix) ){ int regIdx; /* Range of registers holding content for pIdx */ int regR; /* Range of registers holding conflicting PK */ int iThisCur; /* Cursor for this UNIQUE index */ int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ int addrConflictCk; /* First opcode in the conflict check logic */ if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ if( pUpsert ){ pUpsertClause = sqlite3UpsertOfIndex(pUpsert, pIdx); if( upsertIpkDelay && pUpsertClause==pUpsert ){ sqlite3VdbeJumpHere(v, upsertIpkDelay); } } addrUniqueOk = sqlite3VdbeMakeLabel(pParse); if( bAffinityDone==0 ){ sqlite3TableAffinity(v, pTab, regNewData+1); bAffinityDone = 1; } VdbeNoopComment((v, "prep index %s", pIdx->zName)); iThisCur = iIdxCur+ix; /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); pParse->iSelfTab = -(regNewData+1); sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk, SQLITE_JUMPIFNULL); pParse->iSelfTab = 0; } /* Create a record for this index entry as it should appear after ** the insert or update. Store that record in the aRegIdx[ix] register */ regIdx = aRegIdx[ix]+1; for(i=0; inColumn; i++){ int iField = pIdx->aiColumn[i]; int x; if( iField==XN_EXPR ){ pParse->iSelfTab = -(regNewData+1); sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); pParse->iSelfTab = 0; VdbeComment((v, "%s column %d", pIdx->zName, i)); }else if( iField==XN_ROWID || iField==pTab->iPKey ){ x = regNewData; sqlite3VdbeAddOp2(v, OP_IntCopy, x, regIdx+i); VdbeComment((v, "rowid")); }else{ testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField ); x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1; sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); VdbeComment((v, "%s", pTab->aCol[iField].zCnName)); } } sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); VdbeComment((v, "for %s", pIdx->zName)); #ifdef SQLITE_ENABLE_NULL_TRIM if( pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ sqlite3SetMakeRecordP5(v, pIdx->pTable); } #endif sqlite3VdbeReleaseRegisters(pParse, regIdx, pIdx->nColumn, 0, 0); /* In an UPDATE operation, if this index is the PRIMARY KEY index ** of a WITHOUT ROWID table and there has been no change the ** primary key, then no collision is possible. The collision detection ** logic below can all be skipped. */ if( isUpdate && pPk==pIdx && pkChng==0 ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; } /* Find out what action to take in case there is a uniqueness conflict */ onError = pIdx->onError; if( onError==OE_None ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; /* pIdx is not a UNIQUE index */ } if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } /* Figure out if the upsert clause applies to this index */ if( pUpsertClause ){ if( pUpsertClause->isDoUpdate==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ onError = OE_Update; /* DO UPDATE */ } } /* Collision detection may be omitted if all of the following are true: ** (1) The conflict resolution algorithm is REPLACE ** (2) The table is a WITHOUT ROWID table ** (3) There are no secondary indexes on the table ** (4) No delete triggers need to be fired if there is a conflict ** (5) No FK constraint counters need to be updated if a conflict occurs. ** ** This is not possible for ENABLE_PREUPDATE_HOOK builds, as the row ** must be explicitly deleted in order to ensure any pre-update hook ** is invoked. */ assert( IsOrdinaryTable(pTab) ); #ifndef SQLITE_ENABLE_PREUPDATE_HOOK if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ && pPk==pIdx /* Condition 2 */ && onError==OE_Replace /* Condition 1 */ && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */ 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0)) && ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */ (0==pTab->u.tab.pFKey && 0==sqlite3FkReferences(pTab))) ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; } #endif /* ifndef SQLITE_ENABLE_PREUPDATE_HOOK */ /* Check to see if the new index entry will be unique */ sqlite3VdbeVerifyAbortable(v, onError); addrConflictCk = sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, regIdx, pIdx->nKeyCol); VdbeCoverage(v); /* Generate code to handle collisions */ regR = pIdx==pPk ? regIdx : sqlite3GetTempRange(pParse, nPkField); if( isUpdate || onError==OE_Replace ){ if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR); /* Conflict only if the rowid of the existing index entry ** is different from old-rowid */ if( isUpdate ){ sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v); } }else{ int x; /* Extract the PRIMARY KEY from the end of the index entry and ** store it in registers regR..regR+nPk-1 */ if( pIdx!=pPk ){ for(i=0; inKeyCol; i++){ assert( pPk->aiColumn[i]>=0 ); x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i); VdbeComment((v, "%s.%s", pTab->zName, pTab->aCol[pPk->aiColumn[i]].zCnName)); } } if( isUpdate ){ /* If currently processing the PRIMARY KEY of a WITHOUT ROWID ** table, only conflict if the new PRIMARY KEY values are actually ** different from the old. See TH3 withoutrowid04.test. ** ** For a UNIQUE index, only conflict if the PRIMARY KEY values ** of the matched index row are different from the original PRIMARY ** KEY values of this row before the update. */ int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; int op = OP_Ne; int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR); for(i=0; inKeyCol; i++){ char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); x = pPk->aiColumn[i]; assert( x>=0 ); if( i==(pPk->nKeyCol-1) ){ addrJump = addrUniqueOk; op = OP_Eq; } x = sqlite3TableColumnToStorage(pTab, x); sqlite3VdbeAddOp4(v, op, regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ ); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverageIf(v, op==OP_Eq); VdbeCoverageIf(v, op==OP_Ne); } } } } /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace || onError==OE_Update ); switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { testcase( onError==OE_Rollback ); testcase( onError==OE_Abort ); testcase( onError==OE_Fail ); sqlite3UniqueConstraint(pParse, onError, pIdx); break; } #ifndef SQLITE_OMIT_UPSERT case OE_Update: { sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix); /* no break */ deliberate_fall_through } #endif case OE_Ignore: { testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } default: { int nConflictCk; /* Number of opcodes in conflict check logic */ assert( onError==OE_Replace ); nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk; assert( nConflictCk>0 || db->mallocFailed ); testcase( nConflictCk<=0 ); testcase( nConflictCk>1 ); if( regTrigCnt ){ sqlite3MultiWrite(pParse); nReplaceTrig++; } if( pTrigger && isUpdate ){ sqlite3VdbeAddOp1(v, OP_CursorLock, iDataCur); } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); if( pTrigger && isUpdate ){ sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur); } if( regTrigCnt ){ int addrBypass; /* Jump destination to bypass recheck logic */ sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */ addrBypass = sqlite3VdbeAddOp0(v, OP_Goto); /* Bypass recheck */ VdbeComment((v, "bypass recheck")); /* Here we insert code that will be invoked after all constraint ** checks have run, if and only if one or more replace triggers ** fired. */ sqlite3VdbeResolveLabel(v, lblRecheckOk); lblRecheckOk = sqlite3VdbeMakeLabel(pParse); if( pIdx->pPartIdxWhere ){ /* Bypass the recheck if this partial index is not defined ** for the current row */ sqlite3VdbeAddOp2(v, OP_IsNull, regIdx-1, lblRecheckOk); VdbeCoverage(v); } /* Copy the constraint check code from above, except change ** the constraint-ok jump destination to be the address of ** the next retest block */ while( nConflictCk>0 ){ VdbeOp x; /* Conflict check opcode to copy */ /* The sqlite3VdbeAddOp4() call might reallocate the opcode array. ** Hence, make a complete copy of the opcode, rather than using ** a pointer to the opcode. */ x = *sqlite3VdbeGetOp(v, addrConflictCk); if( x.opcode!=OP_IdxRowid ){ int p2; /* New P2 value for copied conflict check opcode */ const char *zP4; if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){ p2 = lblRecheckOk; }else{ p2 = x.p2; } zP4 = x.p4type==P4_INT32 ? SQLITE_INT_TO_PTR(x.p4.i) : x.p4.z; sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, zP4, x.p4type); sqlite3VdbeChangeP5(v, x.p5); VdbeCoverageIf(v, p2!=x.p2); } nConflictCk--; addrConflictCk++; } /* If the retest fails, issue an abort */ sqlite3UniqueConstraint(pParse, OE_Abort, pIdx); sqlite3VdbeJumpHere(v, addrBypass); /* Terminate the recheck bypass */ } seenReplace = 1; break; } } sqlite3VdbeResolveLabel(v, addrUniqueOk); if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); if( pUpsertClause && upsertIpkReturn && sqlite3UpsertNextIsIPK(pUpsertClause) ){ sqlite3VdbeGoto(v, upsertIpkDelay+1); sqlite3VdbeJumpHere(v, upsertIpkReturn); upsertIpkReturn = 0; } } /* If the IPK constraint is a REPLACE, run it last */ if( ipkTop ){ sqlite3VdbeGoto(v, ipkTop); VdbeComment((v, "Do IPK REPLACE")); assert( ipkBottom>0 ); sqlite3VdbeJumpHere(v, ipkBottom); } /* Recheck all uniqueness constraints after replace triggers have run */ testcase( regTrigCnt!=0 && nReplaceTrig==0 ); assert( regTrigCnt!=0 || nReplaceTrig==0 ); if( nReplaceTrig ){ sqlite3VdbeAddOp2(v, OP_IfNot, regTrigCnt, lblRecheckOk);VdbeCoverage(v); if( !pPk ){ if( isUpdate ){ sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRecheck, regOldData); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRecheck, regNewData); VdbeCoverage(v); sqlite3RowidConstraint(pParse, OE_Abort, pTab); }else{ sqlite3VdbeGoto(v, addrRecheck); } sqlite3VdbeResolveLabel(v, lblRecheckOk); } /* Generate the table record */ if( HasRowid(pTab) ){ int regRec = aRegIdx[ix]; sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nNVCol, regRec); sqlite3SetMakeRecordP5(v, pTab); if( !bAffinityDone ){ sqlite3TableAffinity(v, pTab, 0); } } *pbMayReplace = seenReplace; VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace)); } #ifdef SQLITE_ENABLE_NULL_TRIM /* ** Change the P5 operand on the last opcode (which should be an OP_MakeRecord) ** to be the number of columns in table pTab that must not be NULL-trimmed. ** ** Or if no columns of pTab may be NULL-trimmed, leave P5 at zero. */ SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){ u16 i; /* Records with omitted columns are only allowed for schema format ** version 2 and later (SQLite version 3.1.4, 2005-02-20). */ if( pTab->pSchema->file_format<2 ) return; for(i=pTab->nCol-1; i>0; i--){ if( pTab->aCol[i].iDflt!=0 ) break; if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break; } sqlite3VdbeChangeP5(v, i+1); } #endif /* ** Table pTab is a WITHOUT ROWID table that is being written to. The cursor ** number is iCur, and register regData contains the new record for the ** PK index. This function adds code to invoke the pre-update hook, ** if one is registered. */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK static void codeWithoutRowidPreupdate( Parse *pParse, /* Parse context */ Table *pTab, /* Table being updated */ int iCur, /* Cursor number for table */ int regData /* Data containing new record */ ){ Vdbe *v = pParse->pVdbe; int r = sqlite3GetTempReg(pParse); assert( !HasRowid(pTab) ); assert( 0==(pParse->db->mDbFlags & DBFLAG_Vacuum) || CORRUPT_DB ); sqlite3VdbeAddOp2(v, OP_Integer, 0, r); sqlite3VdbeAddOp4(v, OP_Insert, iCur, regData, r, (char*)pTab, P4_TABLE); sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP); sqlite3ReleaseTempReg(pParse, r); } #else # define codeWithoutRowidPreupdate(a,b,c,d) #endif /* ** This routine generates code to finish the INSERT or UPDATE operation ** that was started by a prior call to sqlite3GenerateConstraintChecks. ** A consecutive range of registers starting at regNewData contains the ** rowid and the content to be inserted. ** ** The arguments to this routine should be the same as the first six ** arguments to sqlite3GenerateConstraintChecks. */ SQLITE_PRIVATE void sqlite3CompleteInsertion( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int iDataCur, /* Cursor of the canonical data source */ int iIdxCur, /* First index cursor */ int regNewData, /* Range of content */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ int update_flags, /* True for UPDATE, False for INSERT */ int appendBias, /* True if this is likely to be an append */ int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */ ){ Vdbe *v; /* Prepared statements under construction */ Index *pIdx; /* An index being inserted or updated */ u8 pik_flags; /* flag values passed to the btree insert */ int i; /* Loop counter */ assert( update_flags==0 || update_flags==OPFLAG_ISUPDATE || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION) ); v = pParse->pVdbe; assert( v!=0 ); assert( !IsView(pTab) ); /* This table is not a VIEW */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ /* All REPLACE indexes are at the end of the list */ assert( pIdx->onError!=OE_Replace || pIdx->pNext==0 || pIdx->pNext->onError==OE_Replace ); if( aRegIdx[i]==0 ) continue; if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); } pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0); if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ pik_flags |= OPFLAG_NCHANGE; pik_flags |= (update_flags & OPFLAG_SAVEPOSITION); if( update_flags==0 ){ codeWithoutRowidPreupdate(pParse, pTab, iIdxCur+i, aRegIdx[i]); } } sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i], aRegIdx[i]+1, pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn); sqlite3VdbeChangeP5(v, pik_flags); } if( !HasRowid(pTab) ) return; if( pParse->nested ){ pik_flags = 0; }else{ pik_flags = OPFLAG_NCHANGE; pik_flags |= (update_flags?update_flags:OPFLAG_LASTROWID); } if( appendBias ){ pik_flags |= OPFLAG_APPEND; } if( useSeekResult ){ pik_flags |= OPFLAG_USESEEKRESULT; } sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, aRegIdx[i], regNewData); if( !pParse->nested ){ sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } sqlite3VdbeChangeP5(v, pik_flags); } /* ** Allocate cursors for the pTab table and all its indices and generate ** code to open and initialized those cursors. ** ** The cursor for the object that contains the complete data (normally ** the table itself, but the PRIMARY KEY index in the case of a WITHOUT ** ROWID table) is returned in *piDataCur. The first index cursor is ** returned in *piIdxCur. The number of indices is returned. ** ** Use iBase as the first cursor (either the *piDataCur for rowid tables ** or the first index for WITHOUT ROWID tables) if it is non-negative. ** If iBase is negative, then allocate the next available cursor. ** ** For a rowid table, *piDataCur will be exactly one less than *piIdxCur. ** For a WITHOUT ROWID table, *piDataCur will be somewhere in the range ** of *piIdxCurs, depending on where the PRIMARY KEY index appears on the ** pTab->pIndex list. ** ** If pTab is a virtual table, then this routine is a no-op and the ** *piDataCur and *piIdxCur values are left uninitialized. */ SQLITE_PRIVATE int sqlite3OpenTableAndIndices( Parse *pParse, /* Parsing context */ Table *pTab, /* Table to be opened */ int op, /* OP_OpenRead or OP_OpenWrite */ u8 p5, /* P5 value for OP_Open* opcodes (except on WITHOUT ROWID) */ int iBase, /* Use this for the table cursor, if there is one */ u8 *aToOpen, /* If not NULL: boolean for each table and index */ int *piDataCur, /* Write the database source cursor number here */ int *piIdxCur /* Write the first index cursor number here */ ){ int i; int iDb; int iDataCur; Index *pIdx; Vdbe *v; assert( op==OP_OpenRead || op==OP_OpenWrite ); assert( op==OP_OpenWrite || p5==0 ); assert( piDataCur!=0 ); assert( piIdxCur!=0 ); if( IsVirtual(pTab) ){ /* This routine is a no-op for virtual tables. Leave the output ** variables *piDataCur and *piIdxCur set to illegal cursor numbers ** for improved error detection. */ *piDataCur = *piIdxCur = -999; return 0; } iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); v = pParse->pVdbe; assert( v!=0 ); if( iBase<0 ) iBase = pParse->nTab; iDataCur = iBase++; *piDataCur = iDataCur; if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){ sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op); }else if( pParse->db->noSharedCache==0 ){ sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName); } *piIdxCur = iBase; for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ int iIdxCur = iBase++; assert( pIdx->pSchema==pTab->pSchema ); if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ *piDataCur = iIdxCur; p5 = 0; } if( aToOpen==0 || aToOpen[i+1] ){ sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); sqlite3VdbeChangeP5(v, p5); VdbeComment((v, "%s", pIdx->zName)); } } if( iBase>pParse->nTab ) pParse->nTab = iBase; return i; } #ifdef SQLITE_TEST /* ** The following global variable is incremented whenever the ** transfer optimization is used. This is used for testing ** purposes only - to make sure the transfer optimization really ** is happening when it is supposed to. */ SQLITE_API int sqlite3_xferopt_count; #endif /* SQLITE_TEST */ #ifndef SQLITE_OMIT_XFER_OPT /* ** Check to see if index pSrc is compatible as a source of data ** for index pDest in an insert transfer optimization. The rules ** for a compatible index: ** ** * The index is over the same set of columns ** * The same DESC and ASC markings occurs on all columns ** * The same onError processing (OE_Abort, OE_Ignore, etc) ** * The same collating sequence on each column ** * The index has the exact same WHERE clause */ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ int i; assert( pDest && pSrc ); assert( pDest->pTable!=pSrc->pTable ); if( pDest->nKeyCol!=pSrc->nKeyCol || pDest->nColumn!=pSrc->nColumn ){ return 0; /* Different number of columns */ } if( pDest->onError!=pSrc->onError ){ return 0; /* Different conflict resolution strategies */ } for(i=0; inKeyCol; i++){ if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){ return 0; /* Different columns indexed */ } if( pSrc->aiColumn[i]==XN_EXPR ){ assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 ); if( sqlite3ExprCompare(0, pSrc->aColExpr->a[i].pExpr, pDest->aColExpr->a[i].pExpr, -1)!=0 ){ return 0; /* Different expressions in the index */ } } if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){ return 0; /* Different sort orders */ } if( sqlite3_stricmp(pSrc->azColl[i],pDest->azColl[i])!=0 ){ return 0; /* Different collating sequences */ } } if( sqlite3ExprCompare(0, pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){ return 0; /* Different WHERE clauses */ } /* If no test above fails then the indices must be compatible */ return 1; } /* ** Attempt the transfer optimization on INSERTs of the form ** ** INSERT INTO tab1 SELECT * FROM tab2; ** ** The xfer optimization transfers raw records from tab2 over to tab1. ** Columns are not decoded and reassembled, which greatly improves ** performance. Raw index records are transferred in the same way. ** ** The xfer optimization is only attempted if tab1 and tab2 are compatible. ** There are lots of rules for determining compatibility - see comments ** embedded in the code for details. ** ** This routine returns TRUE if the optimization is guaranteed to be used. ** Sometimes the xfer optimization will only work if the destination table ** is empty - a factor that can only be determined at run-time. In that ** case, this routine generates code for the xfer optimization but also ** does a test to see if the destination table is empty and jumps over the ** xfer optimization code if the test fails. In that case, this routine ** returns FALSE so that the caller will know to go ahead and generate ** an unoptimized transfer. This routine also returns FALSE if there ** is no chance that the xfer optimization can be applied. ** ** This optimization is particularly useful at making VACUUM run faster. */ static int xferOptimization( Parse *pParse, /* Parser context */ Table *pDest, /* The table we are inserting into */ Select *pSelect, /* A SELECT statement to use as the data source */ int onError, /* How to handle constraint errors */ int iDbDest /* The database of pDest */ ){ sqlite3 *db = pParse->db; ExprList *pEList; /* The result set of the SELECT */ Table *pSrc; /* The table in the FROM clause of SELECT */ Index *pSrcIdx, *pDestIdx; /* Source and destination indices */ SrcItem *pItem; /* An element of pSelect->pSrc */ int i; /* Loop counter */ int iDbSrc; /* The database of pSrc */ int iSrc, iDest; /* Cursors from source and destination */ int addr1, addr2; /* Loop addresses */ int emptyDestTest = 0; /* Address of test for empty pDest */ int emptySrcTest = 0; /* Address of test for empty pSrc */ Vdbe *v; /* The VDBE we are building */ int regAutoinc; /* Memory register used by AUTOINC */ int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */ int regData, regRowid; /* Registers holding data and rowid */ assert( pSelect!=0 ); if( pParse->pWith || pSelect->pWith ){ /* Do not attempt to process this query if there are an WITH clauses ** attached to it. Proceeding may generate a false "no such table: xxx" ** error if pSelect reads from a CTE named "xxx". */ return 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pDest) ){ return 0; /* tab1 must not be a virtual table */ } #endif if( onError==OE_Default ){ if( pDest->iPKey>=0 ) onError = pDest->keyConf; if( onError==OE_Default ) onError = OE_Abort; } assert(pSelect->pSrc); /* allocated even if there is no FROM clause */ if( pSelect->pSrc->nSrc!=1 ){ return 0; /* FROM clause must have exactly one term */ } if( pSelect->pSrc->a[0].pSelect ){ return 0; /* FROM clause cannot contain a subquery */ } if( pSelect->pWhere ){ return 0; /* SELECT may not have a WHERE clause */ } if( pSelect->pOrderBy ){ return 0; /* SELECT may not have an ORDER BY clause */ } /* Do not need to test for a HAVING clause. If HAVING is present but ** there is no ORDER BY, we will get an error. */ if( pSelect->pGroupBy ){ return 0; /* SELECT may not have a GROUP BY clause */ } if( pSelect->pLimit ){ return 0; /* SELECT may not have a LIMIT clause */ } if( pSelect->pPrior ){ return 0; /* SELECT may not be a compound query */ } if( pSelect->selFlags & SF_Distinct ){ return 0; /* SELECT may not be DISTINCT */ } pEList = pSelect->pEList; assert( pEList!=0 ); if( pEList->nExpr!=1 ){ return 0; /* The result set must have exactly one column */ } assert( pEList->a[0].pExpr ); if( pEList->a[0].pExpr->op!=TK_ASTERISK ){ return 0; /* The result set must be the special operator "*" */ } /* At this point we have established that the statement is of the ** correct syntactic form to participate in this optimization. Now ** we have to check the semantics. */ pItem = pSelect->pSrc->a; pSrc = sqlite3LocateTableItem(pParse, 0, pItem); if( pSrc==0 ){ return 0; /* FROM clause does not contain a real table */ } if( pSrc->tnum==pDest->tnum && pSrc->pSchema==pDest->pSchema ){ testcase( pSrc!=pDest ); /* Possible due to bad sqlite_schema.rootpage */ return 0; /* tab1 and tab2 may not be the same table */ } if( HasRowid(pDest)!=HasRowid(pSrc) ){ return 0; /* source and destination must both be WITHOUT ROWID or not */ } if( !IsOrdinaryTable(pSrc) ){ return 0; /* tab2 may not be a view or virtual table */ } if( pDest->nCol!=pSrc->nCol ){ return 0; /* Number of columns must be the same in tab1 and tab2 */ } if( pDest->iPKey!=pSrc->iPKey ){ return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ } if( (pDest->tabFlags & TF_Strict)!=0 && (pSrc->tabFlags & TF_Strict)==0 ){ return 0; /* Cannot feed from a non-strict into a strict table */ } for(i=0; inCol; i++){ Column *pDestCol = &pDest->aCol[i]; Column *pSrcCol = &pSrc->aCol[i]; #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN ){ return 0; /* Neither table may have __hidden__ columns */ } #endif #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Even if tables t1 and t2 have identical schemas, if they contain ** generated columns, then this statement is semantically incorrect: ** ** INSERT INTO t2 SELECT * FROM t1; ** ** The reason is that generated column values are returned by the ** the SELECT statement on the right but the INSERT statement on the ** left wants them to be omitted. ** ** Nevertheless, this is a useful notational shorthand to tell SQLite ** to do a bulk transfer all of the content from t1 over to t2. ** ** We could, in theory, disable this (except for internal use by the ** VACUUM command where it is actually needed). But why do that? It ** seems harmless enough, and provides a useful service. */ if( (pDestCol->colFlags & COLFLAG_GENERATED) != (pSrcCol->colFlags & COLFLAG_GENERATED) ){ return 0; /* Both columns have the same generated-column type */ } /* But the transfer is only allowed if both the source and destination ** tables have the exact same expressions for generated columns. ** This requirement could be relaxed for VIRTUAL columns, I suppose. */ if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){ if( sqlite3ExprCompare(0, sqlite3ColumnExpr(pSrc, pSrcCol), sqlite3ColumnExpr(pDest, pDestCol), -1)!=0 ){ testcase( pDestCol->colFlags & COLFLAG_VIRTUAL ); testcase( pDestCol->colFlags & COLFLAG_STORED ); return 0; /* Different generator expressions */ } } #endif if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } if( sqlite3_stricmp(sqlite3ColumnColl(pDestCol), sqlite3ColumnColl(pSrcCol))!=0 ){ return 0; /* Collating sequence must be the same on all columns */ } if( pDestCol->notNull && !pSrcCol->notNull ){ return 0; /* tab2 must be NOT NULL if tab1 is */ } /* Default values for second and subsequent columns need to match. */ if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){ Expr *pDestExpr = sqlite3ColumnExpr(pDest, pDestCol); Expr *pSrcExpr = sqlite3ColumnExpr(pSrc, pSrcCol); assert( pDestExpr==0 || pDestExpr->op==TK_SPAN ); assert( pDestExpr==0 || !ExprHasProperty(pDestExpr, EP_IntValue) ); assert( pSrcExpr==0 || pSrcExpr->op==TK_SPAN ); assert( pSrcExpr==0 || !ExprHasProperty(pSrcExpr, EP_IntValue) ); if( (pDestExpr==0)!=(pSrcExpr==0) || (pDestExpr!=0 && strcmp(pDestExpr->u.zToken, pSrcExpr->u.zToken)!=0) ){ return 0; /* Default values must be the same for all columns */ } } } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ if( IsUniqueIndex(pDestIdx) ){ destHasUniqueIdx = 1; } for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){ if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; } if( pSrcIdx==0 ){ return 0; /* pDestIdx has no corresponding index in pSrc */ } if( pSrcIdx->tnum==pDestIdx->tnum && pSrc->pSchema==pDest->pSchema && sqlite3FaultSim(411)==SQLITE_OK ){ /* The sqlite3FaultSim() call allows this corruption test to be ** bypassed during testing, in order to exercise other corruption tests ** further downstream. */ return 0; /* Corrupt schema - two indexes on the same btree */ } } #ifndef SQLITE_OMIT_CHECK if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ return 0; /* Tables have different CHECK constraints. Ticket #2252 */ } #endif #ifndef SQLITE_OMIT_FOREIGN_KEY /* Disallow the transfer optimization if the destination table contains ** any foreign key constraints. This is more restrictive than necessary. ** But the main beneficiary of the transfer optimization is the VACUUM ** command, and the VACUUM command disables foreign key constraints. So ** the extra complication to make this rule less restrictive is probably ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] */ assert( IsOrdinaryTable(pDest) ); if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->u.tab.pFKey!=0 ){ return 0; } #endif if( (db->flags & SQLITE_CountRows)!=0 ){ return 0; /* xfer opt does not play well with PRAGMA count_changes */ } /* If we get this far, it means that the xfer optimization is at ** least a possibility, though it might only work if the destination ** table (tab1) is initially empty. */ #ifdef SQLITE_TEST sqlite3_xferopt_count++; #endif iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema); v = sqlite3GetVdbe(pParse); sqlite3CodeVerifySchema(pParse, iDbSrc); iSrc = pParse->nTab++; iDest = pParse->nTab++; regAutoinc = autoIncBegin(pParse, iDbDest, pDest); regData = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, regData); regRowid = sqlite3GetTempReg(pParse); sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); assert( HasRowid(pDest) || destHasUniqueIdx ); if( (db->mDbFlags & DBFLAG_Vacuum)==0 && ( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ || destHasUniqueIdx /* (2) */ || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */ )){ /* In some circumstances, we are able to run the xfer optimization ** only if the destination table is initially empty. Unless the ** DBFLAG_Vacuum flag is set, this block generates code to make ** that determination. If DBFLAG_Vacuum is set, then the destination ** table is always empty. ** ** Conditions under which the destination must be empty: ** ** (1) There is no INTEGER PRIMARY KEY but there are indices. ** (If the destination is not initially empty, the rowid fields ** of index entries might need to change.) ** ** (2) The destination has a unique index. (The xfer optimization ** is unable to test uniqueness.) ** ** (3) onError is something other than OE_Abort and OE_Rollback. */ addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); VdbeCoverage(v); emptyDestTest = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, addr1); } if( HasRowid(pSrc) ){ u8 insFlags; sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){ sqlite3VdbeVerifyAbortable(v, onError); addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); VdbeCoverage(v); sqlite3RowidConstraint(pParse, onError, pDest); sqlite3VdbeJumpHere(v, addr2); } autoIncStep(pParse, regAutoinc, regRowid); }else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); }else{ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); assert( (pDest->tabFlags & TF_Autoincrement)==0 ); } if( db->mDbFlags & DBFLAG_Vacuum ){ sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT; }else{ insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND|OPFLAG_PREFORMAT; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){ sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); insFlags &= ~OPFLAG_PREFORMAT; }else #endif { sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regRowid); } sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid); if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){ sqlite3VdbeChangeP4(v, -1, (char*)pDest, P4_TABLE); } sqlite3VdbeChangeP5(v, insFlags); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); }else{ sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName); sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName); } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ u8 idxInsFlags = 0; for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){ if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; } assert( pSrcIdx ); sqlite3VdbeAddOp3(v, OP_OpenRead, iSrc, pSrcIdx->tnum, iDbSrc); sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx); VdbeComment((v, "%s", pSrcIdx->zName)); sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest); sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); if( db->mDbFlags & DBFLAG_Vacuum ){ /* This INSERT command is part of a VACUUM operation, which guarantees ** that the destination table is empty. If all indexed columns use ** collation sequence BINARY, then it can also be assumed that the ** index will be populated by inserting keys in strictly sorted ** order. In this case, instead of seeking within the b-tree as part ** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the ** OP_IdxInsert to seek to the point within the b-tree where each key ** should be inserted. This is faster. ** ** If any of the indexed columns use a collation sequence other than ** BINARY, this optimization is disabled. This is because the user ** might change the definition of a collation sequence and then run ** a VACUUM command. In that case keys may not be written in strictly ** sorted order. */ for(i=0; inColumn; i++){ const char *zColl = pSrcIdx->azColl[i]; if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break; } if( i==pSrcIdx->nColumn ){ idxInsFlags = OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT; sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); sqlite3VdbeAddOp2(v, OP_RowCell, iDest, iSrc); } }else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ idxInsFlags |= OPFLAG_NCHANGE; } if( idxInsFlags!=(OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT) ){ sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); if( (db->mDbFlags & DBFLAG_Vacuum)==0 && !HasRowid(pDest) && IsPrimaryKeyIndex(pDestIdx) ){ codeWithoutRowidPreupdate(pParse, pDest, iDest, regData); } } sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData); sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); } if( emptySrcTest ) sqlite3VdbeJumpHere(v, emptySrcTest); sqlite3ReleaseTempReg(pParse, regRowid); sqlite3ReleaseTempReg(pParse, regData); if( emptyDestTest ){ sqlite3AutoincrementEnd(pParse); sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0); sqlite3VdbeJumpHere(v, emptyDestTest); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); return 0; }else{ return 1; } } #endif /* SQLITE_OMIT_XFER_OPT */ /************** End of insert.c **********************************************/ /************** Begin file legacy.c ******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. */ /* #include "sqliteInt.h" */ /* ** Execute SQL code. Return one of the SQLITE_ success/failure ** codes. Also write an error message into memory obtained from ** malloc() and make *pzErrMsg point to that message. ** ** If the SQL is a query, then for each row in the query result ** the xCallback() function is called. pArg becomes the first ** argument to xCallback(). If xCallback=NULL then no callback ** is invoked, even for queries. */ SQLITE_API int sqlite3_exec( sqlite3 *db, /* The database on which the SQL executes */ const char *zSql, /* The SQL to be executed */ sqlite3_callback xCallback, /* Invoke this callback routine */ void *pArg, /* First argument to xCallback() */ char **pzErrMsg /* Write error messages here */ ){ int rc = SQLITE_OK; /* Return code */ const char *zLeftover; /* Tail of unprocessed SQL */ sqlite3_stmt *pStmt = 0; /* The current SQL statement */ char **azCols = 0; /* Names of result columns */ int callbackIsInit; /* True if callback data is initialized */ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; if( zSql==0 ) zSql = ""; sqlite3_mutex_enter(db->mutex); sqlite3Error(db, SQLITE_OK); while( rc==SQLITE_OK && zSql[0] ){ int nCol = 0; char **azVals = 0; pStmt = 0; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); assert( rc==SQLITE_OK || pStmt==0 ); if( rc!=SQLITE_OK ){ continue; } if( !pStmt ){ /* this happens for a comment or white-space */ zSql = zLeftover; continue; } callbackIsInit = 0; while( 1 ){ int i; rc = sqlite3_step(pStmt); /* Invoke the callback function if required */ if( xCallback && (SQLITE_ROW==rc || (SQLITE_DONE==rc && !callbackIsInit && db->flags&SQLITE_NullCallback)) ){ if( !callbackIsInit ){ nCol = sqlite3_column_count(pStmt); azCols = sqlite3DbMallocRaw(db, (2*nCol+1)*sizeof(const char*)); if( azCols==0 ){ goto exec_out; } for(i=0; ierrMask)==rc ); sqlite3_mutex_leave(db->mutex); return rc; } /************** End of legacy.c **********************************************/ /************** Begin file loadext.c *****************************************/ /* ** 2006 June 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to dynamically load extensions into ** the SQLite library. */ #ifndef SQLITE_CORE #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ #endif /************** Include sqlite3ext.h in the middle of loadext.c **************/ /************** Begin file sqlite3ext.h **************************************/ /* ** 2006 June 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the SQLite interface for use by ** shared libraries that want to be imported as extensions into ** an SQLite instance. Shared libraries that intend to be loaded ** as extensions by SQLite should #include this file instead of ** sqlite3.h. */ #ifndef SQLITE3EXT_H #define SQLITE3EXT_H /* #include "sqlite3.h" */ /* ** The following structure holds pointers to all of the SQLite API ** routines. ** ** WARNING: In order to maintain backwards compatibility, add new ** interfaces to the end of this structure only. If you insert new ** interfaces in the middle of this structure, then older different ** versions of SQLite will not be able to load each other's shared ** libraries! */ struct sqlite3_api_routines { void * (*aggregate_context)(sqlite3_context*,int nBytes); int (*aggregate_count)(sqlite3_context*); int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); int (*bind_double)(sqlite3_stmt*,int,double); int (*bind_int)(sqlite3_stmt*,int,int); int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); int (*bind_null)(sqlite3_stmt*,int); int (*bind_parameter_count)(sqlite3_stmt*); int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); const char * (*bind_parameter_name)(sqlite3_stmt*,int); int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); int (*busy_timeout)(sqlite3*,int ms); int (*changes)(sqlite3*); int (*close)(sqlite3*); int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, int eTextRep,const char*)); int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, int eTextRep,const void*)); const void * (*column_blob)(sqlite3_stmt*,int iCol); int (*column_bytes)(sqlite3_stmt*,int iCol); int (*column_bytes16)(sqlite3_stmt*,int iCol); int (*column_count)(sqlite3_stmt*pStmt); const char * (*column_database_name)(sqlite3_stmt*,int); const void * (*column_database_name16)(sqlite3_stmt*,int); const char * (*column_decltype)(sqlite3_stmt*,int i); const void * (*column_decltype16)(sqlite3_stmt*,int); double (*column_double)(sqlite3_stmt*,int iCol); int (*column_int)(sqlite3_stmt*,int iCol); sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); const char * (*column_name)(sqlite3_stmt*,int); const void * (*column_name16)(sqlite3_stmt*,int); const char * (*column_origin_name)(sqlite3_stmt*,int); const void * (*column_origin_name16)(sqlite3_stmt*,int); const char * (*column_table_name)(sqlite3_stmt*,int); const void * (*column_table_name16)(sqlite3_stmt*,int); const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); const void * (*column_text16)(sqlite3_stmt*,int iCol); int (*column_type)(sqlite3_stmt*,int iCol); sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); void * (*commit_hook)(sqlite3*,int(*)(void*),void*); int (*complete)(const char*sql); int (*complete16)(const void*sql); int (*create_collation)(sqlite3*,const char*,int,void*, int(*)(void*,int,const void*,int,const void*)); int (*create_collation16)(sqlite3*,const void*,int,void*, int(*)(void*,int,const void*,int,const void*)); int (*create_function)(sqlite3*,const char*,int,int,void*, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*)); int (*create_function16)(sqlite3*,const void*,int,int,void*, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*)); int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); int (*data_count)(sqlite3_stmt*pStmt); sqlite3 * (*db_handle)(sqlite3_stmt*); int (*declare_vtab)(sqlite3*,const char*); int (*enable_shared_cache)(int); int (*errcode)(sqlite3*db); const char * (*errmsg)(sqlite3*); const void * (*errmsg16)(sqlite3*); int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); int (*expired)(sqlite3_stmt*); int (*finalize)(sqlite3_stmt*pStmt); void (*free)(void*); void (*free_table)(char**result); int (*get_autocommit)(sqlite3*); void * (*get_auxdata)(sqlite3_context*,int); int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); int (*global_recover)(void); void (*interruptx)(sqlite3*); sqlite_int64 (*last_insert_rowid)(sqlite3*); const char * (*libversion)(void); int (*libversion_number)(void); void *(*malloc)(int); char * (*mprintf)(const char*,...); int (*open)(const char*,sqlite3**); int (*open16)(const void*,sqlite3**); int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); void *(*realloc)(void*,int); int (*reset)(sqlite3_stmt*pStmt); void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_double)(sqlite3_context*,double); void (*result_error)(sqlite3_context*,const char*,int); void (*result_error16)(sqlite3_context*,const void*,int); void (*result_int)(sqlite3_context*,int); void (*result_int64)(sqlite3_context*,sqlite_int64); void (*result_null)(sqlite3_context*); void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); void (*result_value)(sqlite3_context*,sqlite3_value*); void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); char * (*xsnprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, char const**,char const**,int*,int*,int*); void (*thread_cleanup)(void); int (*total_changes)(sqlite3*); void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, sqlite_int64),void*); void * (*user_data)(sqlite3_context*); const void * (*value_blob)(sqlite3_value*); int (*value_bytes)(sqlite3_value*); int (*value_bytes16)(sqlite3_value*); double (*value_double)(sqlite3_value*); int (*value_int)(sqlite3_value*); sqlite_int64 (*value_int64)(sqlite3_value*); int (*value_numeric_type)(sqlite3_value*); const unsigned char * (*value_text)(sqlite3_value*); const void * (*value_text16)(sqlite3_value*); const void * (*value_text16be)(sqlite3_value*); const void * (*value_text16le)(sqlite3_value*); int (*value_type)(sqlite3_value*); char *(*vmprintf)(const char*,va_list); /* Added ??? */ int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); /* Added by 3.3.13 */ int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); int (*clear_bindings)(sqlite3_stmt*); /* Added by 3.4.1 */ int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, void (*xDestroy)(void *)); /* Added by 3.5.0 */ int (*bind_zeroblob)(sqlite3_stmt*,int,int); int (*blob_bytes)(sqlite3_blob*); int (*blob_close)(sqlite3_blob*); int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, int,sqlite3_blob**); int (*blob_read)(sqlite3_blob*,void*,int,int); int (*blob_write)(sqlite3_blob*,const void*,int,int); int (*create_collation_v2)(sqlite3*,const char*,int,void*, int(*)(void*,int,const void*,int,const void*), void(*)(void*)); int (*file_control)(sqlite3*,const char*,int,void*); sqlite3_int64 (*memory_highwater)(int); sqlite3_int64 (*memory_used)(void); sqlite3_mutex *(*mutex_alloc)(int); void (*mutex_enter)(sqlite3_mutex*); void (*mutex_free)(sqlite3_mutex*); void (*mutex_leave)(sqlite3_mutex*); int (*mutex_try)(sqlite3_mutex*); int (*open_v2)(const char*,sqlite3**,int,const char*); int (*release_memory)(int); void (*result_error_nomem)(sqlite3_context*); void (*result_error_toobig)(sqlite3_context*); int (*sleep)(int); void (*soft_heap_limit)(int); sqlite3_vfs *(*vfs_find)(const char*); int (*vfs_register)(sqlite3_vfs*,int); int (*vfs_unregister)(sqlite3_vfs*); int (*xthreadsafe)(void); void (*result_zeroblob)(sqlite3_context*,int); void (*result_error_code)(sqlite3_context*,int); int (*test_control)(int, ...); void (*randomness)(int,void*); sqlite3 *(*context_db_handle)(sqlite3_context*); int (*extended_result_codes)(sqlite3*,int); int (*limit)(sqlite3*,int,int); sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*); const char *(*sql)(sqlite3_stmt*); int (*status)(int,int*,int*,int); int (*backup_finish)(sqlite3_backup*); sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*); int (*backup_pagecount)(sqlite3_backup*); int (*backup_remaining)(sqlite3_backup*); int (*backup_step)(sqlite3_backup*,int); const char *(*compileoption_get)(int); int (*compileoption_used)(const char*); int (*create_function_v2)(sqlite3*,const char*,int,int,void*, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*)); int (*db_config)(sqlite3*,int,...); sqlite3_mutex *(*db_mutex)(sqlite3*); int (*db_status)(sqlite3*,int,int*,int*,int); int (*extended_errcode)(sqlite3*); void (*log)(int,const char*,...); sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); const char *(*sourceid)(void); int (*stmt_status)(sqlite3_stmt*,int,int); int (*strnicmp)(const char*,const char*,int); int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); int (*wal_autocheckpoint)(sqlite3*,int); int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); int (*vtab_config)(sqlite3*,int op,...); int (*vtab_on_conflict)(sqlite3*); /* Version 3.7.16 and later */ int (*close_v2)(sqlite3*); const char *(*db_filename)(sqlite3*,const char*); int (*db_readonly)(sqlite3*,const char*); int (*db_release_memory)(sqlite3*); const char *(*errstr)(int); int (*stmt_busy)(sqlite3_stmt*); int (*stmt_readonly)(sqlite3_stmt*); int (*stricmp)(const char*,const char*); int (*uri_boolean)(const char*,const char*,int); sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); const char *(*uri_parameter)(const char*,const char*); char *(*xvsnprintf)(int,char*,const char*,va_list); int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); /* Version 3.8.7 and later */ int (*auto_extension)(void(*)(void)); int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, void(*)(void*)); int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, void(*)(void*),unsigned char); int (*cancel_auto_extension)(void(*)(void)); int (*load_extension)(sqlite3*,const char*,const char*,char**); void *(*malloc64)(sqlite3_uint64); sqlite3_uint64 (*msize)(void*); void *(*realloc64)(void*,sqlite3_uint64); void (*reset_auto_extension)(void); void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, void(*)(void*)); void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, void(*)(void*), unsigned char); int (*strglob)(const char*,const char*); /* Version 3.8.11 and later */ sqlite3_value *(*value_dup)(const sqlite3_value*); void (*value_free)(sqlite3_value*); int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64); int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64); /* Version 3.9.0 and later */ unsigned int (*value_subtype)(sqlite3_value*); void (*result_subtype)(sqlite3_context*,unsigned int); /* Version 3.10.0 and later */ int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); int (*strlike)(const char*,const char*,unsigned int); int (*db_cacheflush)(sqlite3*); /* Version 3.12.0 and later */ int (*system_errno)(sqlite3*); /* Version 3.14.0 and later */ int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); char *(*expanded_sql)(sqlite3_stmt*); /* Version 3.18.0 and later */ void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); /* Version 3.20.0 and later */ int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, sqlite3_stmt**,const char**); int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, sqlite3_stmt**,const void**); int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); void *(*value_pointer)(sqlite3_value*,const char*); int (*vtab_nochange)(sqlite3_context*); int (*value_nochange)(sqlite3_value*); const char *(*vtab_collation)(sqlite3_index_info*,int); /* Version 3.24.0 and later */ int (*keyword_count)(void); int (*keyword_name)(int,const char**,int*); int (*keyword_check)(const char*,int); sqlite3_str *(*str_new)(sqlite3*); char *(*str_finish)(sqlite3_str*); void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); void (*str_append)(sqlite3_str*, const char *zIn, int N); void (*str_appendall)(sqlite3_str*, const char *zIn); void (*str_appendchar)(sqlite3_str*, int N, char C); void (*str_reset)(sqlite3_str*); int (*str_errcode)(sqlite3_str*); int (*str_length)(sqlite3_str*); char *(*str_value)(sqlite3_str*); /* Version 3.25.0 and later */ int (*create_window_function)(sqlite3*,const char*,int,int,void*, void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInv)(sqlite3_context*,int,sqlite3_value**), void(*xDestroy)(void*)); /* Version 3.26.0 and later */ const char *(*normalized_sql)(sqlite3_stmt*); /* Version 3.28.0 and later */ int (*stmt_isexplain)(sqlite3_stmt*); int (*value_frombind)(sqlite3_value*); /* Version 3.30.0 and later */ int (*drop_modules)(sqlite3*,const char**); /* Version 3.31.0 and later */ sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64); const char *(*uri_key)(const char*,int); const char *(*filename_database)(const char*); const char *(*filename_journal)(const char*); const char *(*filename_wal)(const char*); /* Version 3.32.0 and later */ const char *(*create_filename)(const char*,const char*,const char*, int,const char**); void (*free_filename)(const char*); sqlite3_file *(*database_file_object)(const char*); /* Version 3.34.0 and later */ int (*txn_state)(sqlite3*,const char*); /* Version 3.36.1 and later */ sqlite3_int64 (*changes64)(sqlite3*); sqlite3_int64 (*total_changes64)(sqlite3*); /* Version 3.37.0 and later */ int (*autovacuum_pages)(sqlite3*, unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), void*, void(*)(void*)); /* Version 3.38.0 and later */ int (*error_offset)(sqlite3*); int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**); int (*vtab_distinct)(sqlite3_index_info*); int (*vtab_in)(sqlite3_index_info*,int,int); int (*vtab_in_first)(sqlite3_value*,sqlite3_value**); int (*vtab_in_next)(sqlite3_value*,sqlite3_value**); /* Version 3.39.0 and later */ int (*deserialize)(sqlite3*,const char*,unsigned char*, sqlite3_int64,sqlite3_int64,unsigned); unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*, unsigned int); const char *(*db_name)(sqlite3*,int); /* Version 3.40.0 and later */ int (*value_encoding)(sqlite3_value*); /* Version 3.41.0 and later */ int (*is_interrupted)(sqlite3*); /* Version 3.43.0 and later */ int (*stmt_explain)(sqlite3_stmt*,int); /* Version 3.44.0 and later */ void *(*get_clientdata)(sqlite3*,const char*); int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); }; /* ** This is the function signature used for all extension entry points. It ** is also defined in the file "loadext.c". */ typedef int (*sqlite3_loadext_entry)( sqlite3 *db, /* Handle to the database. */ char **pzErrMsg, /* Used to set error string on failure. */ const sqlite3_api_routines *pThunk /* Extension API function pointers. */ ); /* ** The following macros redefine the API routines so that they are ** redirected through the global sqlite3_api structure. ** ** This header file is also used by the loadext.c source file ** (part of the main SQLite library - not an extension) so that ** it can get access to the sqlite3_api_routines structure ** definition. But the main library does not want to redefine ** the API. So the redefinition macros are only valid if the ** SQLITE_CORE macros is undefined. */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) #define sqlite3_aggregate_context sqlite3_api->aggregate_context #ifndef SQLITE_OMIT_DEPRECATED #define sqlite3_aggregate_count sqlite3_api->aggregate_count #endif #define sqlite3_bind_blob sqlite3_api->bind_blob #define sqlite3_bind_double sqlite3_api->bind_double #define sqlite3_bind_int sqlite3_api->bind_int #define sqlite3_bind_int64 sqlite3_api->bind_int64 #define sqlite3_bind_null sqlite3_api->bind_null #define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count #define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index #define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name #define sqlite3_bind_text sqlite3_api->bind_text #define sqlite3_bind_text16 sqlite3_api->bind_text16 #define sqlite3_bind_value sqlite3_api->bind_value #define sqlite3_busy_handler sqlite3_api->busy_handler #define sqlite3_busy_timeout sqlite3_api->busy_timeout #define sqlite3_changes sqlite3_api->changes #define sqlite3_close sqlite3_api->close #define sqlite3_collation_needed sqlite3_api->collation_needed #define sqlite3_collation_needed16 sqlite3_api->collation_needed16 #define sqlite3_column_blob sqlite3_api->column_blob #define sqlite3_column_bytes sqlite3_api->column_bytes #define sqlite3_column_bytes16 sqlite3_api->column_bytes16 #define sqlite3_column_count sqlite3_api->column_count #define sqlite3_column_database_name sqlite3_api->column_database_name #define sqlite3_column_database_name16 sqlite3_api->column_database_name16 #define sqlite3_column_decltype sqlite3_api->column_decltype #define sqlite3_column_decltype16 sqlite3_api->column_decltype16 #define sqlite3_column_double sqlite3_api->column_double #define sqlite3_column_int sqlite3_api->column_int #define sqlite3_column_int64 sqlite3_api->column_int64 #define sqlite3_column_name sqlite3_api->column_name #define sqlite3_column_name16 sqlite3_api->column_name16 #define sqlite3_column_origin_name sqlite3_api->column_origin_name #define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16 #define sqlite3_column_table_name sqlite3_api->column_table_name #define sqlite3_column_table_name16 sqlite3_api->column_table_name16 #define sqlite3_column_text sqlite3_api->column_text #define sqlite3_column_text16 sqlite3_api->column_text16 #define sqlite3_column_type sqlite3_api->column_type #define sqlite3_column_value sqlite3_api->column_value #define sqlite3_commit_hook sqlite3_api->commit_hook #define sqlite3_complete sqlite3_api->complete #define sqlite3_complete16 sqlite3_api->complete16 #define sqlite3_create_collation sqlite3_api->create_collation #define sqlite3_create_collation16 sqlite3_api->create_collation16 #define sqlite3_create_function sqlite3_api->create_function #define sqlite3_create_function16 sqlite3_api->create_function16 #define sqlite3_create_module sqlite3_api->create_module #define sqlite3_create_module_v2 sqlite3_api->create_module_v2 #define sqlite3_data_count sqlite3_api->data_count #define sqlite3_db_handle sqlite3_api->db_handle #define sqlite3_declare_vtab sqlite3_api->declare_vtab #define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache #define sqlite3_errcode sqlite3_api->errcode #define sqlite3_errmsg sqlite3_api->errmsg #define sqlite3_errmsg16 sqlite3_api->errmsg16 #define sqlite3_exec sqlite3_api->exec #ifndef SQLITE_OMIT_DEPRECATED #define sqlite3_expired sqlite3_api->expired #endif #define sqlite3_finalize sqlite3_api->finalize #define sqlite3_free sqlite3_api->free #define sqlite3_free_table sqlite3_api->free_table #define sqlite3_get_autocommit sqlite3_api->get_autocommit #define sqlite3_get_auxdata sqlite3_api->get_auxdata #define sqlite3_get_table sqlite3_api->get_table #ifndef SQLITE_OMIT_DEPRECATED #define sqlite3_global_recover sqlite3_api->global_recover #endif #define sqlite3_interrupt sqlite3_api->interruptx #define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid #define sqlite3_libversion sqlite3_api->libversion #define sqlite3_libversion_number sqlite3_api->libversion_number #define sqlite3_malloc sqlite3_api->malloc #define sqlite3_mprintf sqlite3_api->mprintf #define sqlite3_open sqlite3_api->open #define sqlite3_open16 sqlite3_api->open16 #define sqlite3_prepare sqlite3_api->prepare #define sqlite3_prepare16 sqlite3_api->prepare16 #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 #define sqlite3_profile sqlite3_api->profile #define sqlite3_progress_handler sqlite3_api->progress_handler #define sqlite3_realloc sqlite3_api->realloc #define sqlite3_reset sqlite3_api->reset #define sqlite3_result_blob sqlite3_api->result_blob #define sqlite3_result_double sqlite3_api->result_double #define sqlite3_result_error sqlite3_api->result_error #define sqlite3_result_error16 sqlite3_api->result_error16 #define sqlite3_result_int sqlite3_api->result_int #define sqlite3_result_int64 sqlite3_api->result_int64 #define sqlite3_result_null sqlite3_api->result_null #define sqlite3_result_text sqlite3_api->result_text #define sqlite3_result_text16 sqlite3_api->result_text16 #define sqlite3_result_text16be sqlite3_api->result_text16be #define sqlite3_result_text16le sqlite3_api->result_text16le #define sqlite3_result_value sqlite3_api->result_value #define sqlite3_rollback_hook sqlite3_api->rollback_hook #define sqlite3_set_authorizer sqlite3_api->set_authorizer #define sqlite3_set_auxdata sqlite3_api->set_auxdata #define sqlite3_snprintf sqlite3_api->xsnprintf #define sqlite3_step sqlite3_api->step #define sqlite3_table_column_metadata sqlite3_api->table_column_metadata #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup #define sqlite3_total_changes sqlite3_api->total_changes #define sqlite3_trace sqlite3_api->trace #ifndef SQLITE_OMIT_DEPRECATED #define sqlite3_transfer_bindings sqlite3_api->transfer_bindings #endif #define sqlite3_update_hook sqlite3_api->update_hook #define sqlite3_user_data sqlite3_api->user_data #define sqlite3_value_blob sqlite3_api->value_blob #define sqlite3_value_bytes sqlite3_api->value_bytes #define sqlite3_value_bytes16 sqlite3_api->value_bytes16 #define sqlite3_value_double sqlite3_api->value_double #define sqlite3_value_int sqlite3_api->value_int #define sqlite3_value_int64 sqlite3_api->value_int64 #define sqlite3_value_numeric_type sqlite3_api->value_numeric_type #define sqlite3_value_text sqlite3_api->value_text #define sqlite3_value_text16 sqlite3_api->value_text16 #define sqlite3_value_text16be sqlite3_api->value_text16be #define sqlite3_value_text16le sqlite3_api->value_text16le #define sqlite3_value_type sqlite3_api->value_type #define sqlite3_vmprintf sqlite3_api->vmprintf #define sqlite3_vsnprintf sqlite3_api->xvsnprintf #define sqlite3_overload_function sqlite3_api->overload_function #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 #define sqlite3_clear_bindings sqlite3_api->clear_bindings #define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob #define sqlite3_blob_bytes sqlite3_api->blob_bytes #define sqlite3_blob_close sqlite3_api->blob_close #define sqlite3_blob_open sqlite3_api->blob_open #define sqlite3_blob_read sqlite3_api->blob_read #define sqlite3_blob_write sqlite3_api->blob_write #define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2 #define sqlite3_file_control sqlite3_api->file_control #define sqlite3_memory_highwater sqlite3_api->memory_highwater #define sqlite3_memory_used sqlite3_api->memory_used #define sqlite3_mutex_alloc sqlite3_api->mutex_alloc #define sqlite3_mutex_enter sqlite3_api->mutex_enter #define sqlite3_mutex_free sqlite3_api->mutex_free #define sqlite3_mutex_leave sqlite3_api->mutex_leave #define sqlite3_mutex_try sqlite3_api->mutex_try #define sqlite3_open_v2 sqlite3_api->open_v2 #define sqlite3_release_memory sqlite3_api->release_memory #define sqlite3_result_error_nomem sqlite3_api->result_error_nomem #define sqlite3_result_error_toobig sqlite3_api->result_error_toobig #define sqlite3_sleep sqlite3_api->sleep #define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit #define sqlite3_vfs_find sqlite3_api->vfs_find #define sqlite3_vfs_register sqlite3_api->vfs_register #define sqlite3_vfs_unregister sqlite3_api->vfs_unregister #define sqlite3_threadsafe sqlite3_api->xthreadsafe #define sqlite3_result_zeroblob sqlite3_api->result_zeroblob #define sqlite3_result_error_code sqlite3_api->result_error_code #define sqlite3_test_control sqlite3_api->test_control #define sqlite3_randomness sqlite3_api->randomness #define sqlite3_context_db_handle sqlite3_api->context_db_handle #define sqlite3_extended_result_codes sqlite3_api->extended_result_codes #define sqlite3_limit sqlite3_api->limit #define sqlite3_next_stmt sqlite3_api->next_stmt #define sqlite3_sql sqlite3_api->sql #define sqlite3_status sqlite3_api->status #define sqlite3_backup_finish sqlite3_api->backup_finish #define sqlite3_backup_init sqlite3_api->backup_init #define sqlite3_backup_pagecount sqlite3_api->backup_pagecount #define sqlite3_backup_remaining sqlite3_api->backup_remaining #define sqlite3_backup_step sqlite3_api->backup_step #define sqlite3_compileoption_get sqlite3_api->compileoption_get #define sqlite3_compileoption_used sqlite3_api->compileoption_used #define sqlite3_create_function_v2 sqlite3_api->create_function_v2 #define sqlite3_db_config sqlite3_api->db_config #define sqlite3_db_mutex sqlite3_api->db_mutex #define sqlite3_db_status sqlite3_api->db_status #define sqlite3_extended_errcode sqlite3_api->extended_errcode #define sqlite3_log sqlite3_api->log #define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64 #define sqlite3_sourceid sqlite3_api->sourceid #define sqlite3_stmt_status sqlite3_api->stmt_status #define sqlite3_strnicmp sqlite3_api->strnicmp #define sqlite3_unlock_notify sqlite3_api->unlock_notify #define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint #define sqlite3_wal_hook sqlite3_api->wal_hook #define sqlite3_blob_reopen sqlite3_api->blob_reopen #define sqlite3_vtab_config sqlite3_api->vtab_config #define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict /* Version 3.7.16 and later */ #define sqlite3_close_v2 sqlite3_api->close_v2 #define sqlite3_db_filename sqlite3_api->db_filename #define sqlite3_db_readonly sqlite3_api->db_readonly #define sqlite3_db_release_memory sqlite3_api->db_release_memory #define sqlite3_errstr sqlite3_api->errstr #define sqlite3_stmt_busy sqlite3_api->stmt_busy #define sqlite3_stmt_readonly sqlite3_api->stmt_readonly #define sqlite3_stricmp sqlite3_api->stricmp #define sqlite3_uri_boolean sqlite3_api->uri_boolean #define sqlite3_uri_int64 sqlite3_api->uri_int64 #define sqlite3_uri_parameter sqlite3_api->uri_parameter #define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 /* Version 3.8.7 and later */ #define sqlite3_auto_extension sqlite3_api->auto_extension #define sqlite3_bind_blob64 sqlite3_api->bind_blob64 #define sqlite3_bind_text64 sqlite3_api->bind_text64 #define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension #define sqlite3_load_extension sqlite3_api->load_extension #define sqlite3_malloc64 sqlite3_api->malloc64 #define sqlite3_msize sqlite3_api->msize #define sqlite3_realloc64 sqlite3_api->realloc64 #define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension #define sqlite3_result_blob64 sqlite3_api->result_blob64 #define sqlite3_result_text64 sqlite3_api->result_text64 #define sqlite3_strglob sqlite3_api->strglob /* Version 3.8.11 and later */ #define sqlite3_value_dup sqlite3_api->value_dup #define sqlite3_value_free sqlite3_api->value_free #define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64 #define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64 /* Version 3.9.0 and later */ #define sqlite3_value_subtype sqlite3_api->value_subtype #define sqlite3_result_subtype sqlite3_api->result_subtype /* Version 3.10.0 and later */ #define sqlite3_status64 sqlite3_api->status64 #define sqlite3_strlike sqlite3_api->strlike #define sqlite3_db_cacheflush sqlite3_api->db_cacheflush /* Version 3.12.0 and later */ #define sqlite3_system_errno sqlite3_api->system_errno /* Version 3.14.0 and later */ #define sqlite3_trace_v2 sqlite3_api->trace_v2 #define sqlite3_expanded_sql sqlite3_api->expanded_sql /* Version 3.18.0 and later */ #define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid /* Version 3.20.0 and later */ #define sqlite3_prepare_v3 sqlite3_api->prepare_v3 #define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3 #define sqlite3_bind_pointer sqlite3_api->bind_pointer #define sqlite3_result_pointer sqlite3_api->result_pointer #define sqlite3_value_pointer sqlite3_api->value_pointer /* Version 3.22.0 and later */ #define sqlite3_vtab_nochange sqlite3_api->vtab_nochange #define sqlite3_value_nochange sqlite3_api->value_nochange #define sqlite3_vtab_collation sqlite3_api->vtab_collation /* Version 3.24.0 and later */ #define sqlite3_keyword_count sqlite3_api->keyword_count #define sqlite3_keyword_name sqlite3_api->keyword_name #define sqlite3_keyword_check sqlite3_api->keyword_check #define sqlite3_str_new sqlite3_api->str_new #define sqlite3_str_finish sqlite3_api->str_finish #define sqlite3_str_appendf sqlite3_api->str_appendf #define sqlite3_str_vappendf sqlite3_api->str_vappendf #define sqlite3_str_append sqlite3_api->str_append #define sqlite3_str_appendall sqlite3_api->str_appendall #define sqlite3_str_appendchar sqlite3_api->str_appendchar #define sqlite3_str_reset sqlite3_api->str_reset #define sqlite3_str_errcode sqlite3_api->str_errcode #define sqlite3_str_length sqlite3_api->str_length #define sqlite3_str_value sqlite3_api->str_value /* Version 3.25.0 and later */ #define sqlite3_create_window_function sqlite3_api->create_window_function /* Version 3.26.0 and later */ #define sqlite3_normalized_sql sqlite3_api->normalized_sql /* Version 3.28.0 and later */ #define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain #define sqlite3_value_frombind sqlite3_api->value_frombind /* Version 3.30.0 and later */ #define sqlite3_drop_modules sqlite3_api->drop_modules /* Version 3.31.0 and later */ #define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64 #define sqlite3_uri_key sqlite3_api->uri_key #define sqlite3_filename_database sqlite3_api->filename_database #define sqlite3_filename_journal sqlite3_api->filename_journal #define sqlite3_filename_wal sqlite3_api->filename_wal /* Version 3.32.0 and later */ #define sqlite3_create_filename sqlite3_api->create_filename #define sqlite3_free_filename sqlite3_api->free_filename #define sqlite3_database_file_object sqlite3_api->database_file_object /* Version 3.34.0 and later */ #define sqlite3_txn_state sqlite3_api->txn_state /* Version 3.36.1 and later */ #define sqlite3_changes64 sqlite3_api->changes64 #define sqlite3_total_changes64 sqlite3_api->total_changes64 /* Version 3.37.0 and later */ #define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages /* Version 3.38.0 and later */ #define sqlite3_error_offset sqlite3_api->error_offset #define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value #define sqlite3_vtab_distinct sqlite3_api->vtab_distinct #define sqlite3_vtab_in sqlite3_api->vtab_in #define sqlite3_vtab_in_first sqlite3_api->vtab_in_first #define sqlite3_vtab_in_next sqlite3_api->vtab_in_next /* Version 3.39.0 and later */ #ifndef SQLITE_OMIT_DESERIALIZE #define sqlite3_deserialize sqlite3_api->deserialize #define sqlite3_serialize sqlite3_api->serialize #endif #define sqlite3_db_name sqlite3_api->db_name /* Version 3.40.0 and later */ #define sqlite3_value_encoding sqlite3_api->value_encoding /* Version 3.41.0 and later */ #define sqlite3_is_interrupted sqlite3_api->is_interrupted /* Version 3.43.0 and later */ #define sqlite3_stmt_explain sqlite3_api->stmt_explain /* Version 3.44.0 and later */ #define sqlite3_get_clientdata sqlite3_api->get_clientdata #define sqlite3_set_clientdata sqlite3_api->set_clientdata #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) /* This case when the file really is being compiled as a loadable ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; # define SQLITE_EXTENSION_INIT3 \ extern const sqlite3_api_routines *sqlite3_api; #else /* This case when the file is being statically linked into the ** application */ # define SQLITE_EXTENSION_INIT1 /*no-op*/ # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ # define SQLITE_EXTENSION_INIT3 /*no-op*/ #endif #endif /* SQLITE3EXT_H */ /************** End of sqlite3ext.h ******************************************/ /************** Continuing where we left off in loadext.c ********************/ /* #include "sqliteInt.h" */ #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Some API routines are omitted when various features are ** excluded from a build of SQLite. Substitute a NULL pointer ** for any missing APIs. */ #ifndef SQLITE_ENABLE_COLUMN_METADATA # define sqlite3_column_database_name 0 # define sqlite3_column_database_name16 0 # define sqlite3_column_table_name 0 # define sqlite3_column_table_name16 0 # define sqlite3_column_origin_name 0 # define sqlite3_column_origin_name16 0 #endif #ifdef SQLITE_OMIT_AUTHORIZATION # define sqlite3_set_authorizer 0 #endif #ifdef SQLITE_OMIT_UTF16 # define sqlite3_bind_text16 0 # define sqlite3_collation_needed16 0 # define sqlite3_column_decltype16 0 # define sqlite3_column_name16 0 # define sqlite3_column_text16 0 # define sqlite3_complete16 0 # define sqlite3_create_collation16 0 # define sqlite3_create_function16 0 # define sqlite3_errmsg16 0 # define sqlite3_open16 0 # define sqlite3_prepare16 0 # define sqlite3_prepare16_v2 0 # define sqlite3_prepare16_v3 0 # define sqlite3_result_error16 0 # define sqlite3_result_text16 0 # define sqlite3_result_text16be 0 # define sqlite3_result_text16le 0 # define sqlite3_value_text16 0 # define sqlite3_value_text16be 0 # define sqlite3_value_text16le 0 # define sqlite3_column_database_name16 0 # define sqlite3_column_table_name16 0 # define sqlite3_column_origin_name16 0 #endif #ifdef SQLITE_OMIT_COMPLETE # define sqlite3_complete 0 # define sqlite3_complete16 0 #endif #ifdef SQLITE_OMIT_DECLTYPE # define sqlite3_column_decltype16 0 # define sqlite3_column_decltype 0 #endif #ifdef SQLITE_OMIT_PROGRESS_CALLBACK # define sqlite3_progress_handler 0 #endif #ifdef SQLITE_OMIT_VIRTUALTABLE # define sqlite3_create_module 0 # define sqlite3_create_module_v2 0 # define sqlite3_declare_vtab 0 # define sqlite3_vtab_config 0 # define sqlite3_vtab_on_conflict 0 # define sqlite3_vtab_collation 0 #endif #ifdef SQLITE_OMIT_SHARED_CACHE # define sqlite3_enable_shared_cache 0 #endif #if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED) # define sqlite3_profile 0 # define sqlite3_trace 0 #endif #ifdef SQLITE_OMIT_GET_TABLE # define sqlite3_free_table 0 # define sqlite3_get_table 0 #endif #ifdef SQLITE_OMIT_INCRBLOB #define sqlite3_bind_zeroblob 0 #define sqlite3_blob_bytes 0 #define sqlite3_blob_close 0 #define sqlite3_blob_open 0 #define sqlite3_blob_read 0 #define sqlite3_blob_write 0 #define sqlite3_blob_reopen 0 #endif #if defined(SQLITE_OMIT_TRACE) # define sqlite3_trace_v2 0 #endif /* ** The following structure contains pointers to all SQLite API routines. ** A pointer to this structure is passed into extensions when they are ** loaded so that the extension can make calls back into the SQLite ** library. ** ** When adding new APIs, add them to the bottom of this structure ** in order to preserve backwards compatibility. ** ** Extensions that use newer APIs should first call the ** sqlite3_libversion_number() to make sure that the API they ** intend to use is supported by the library. Extensions should ** also check to make sure that the pointer to the function is ** not NULL before calling it. */ static const sqlite3_api_routines sqlite3Apis = { sqlite3_aggregate_context, #ifndef SQLITE_OMIT_DEPRECATED sqlite3_aggregate_count, #else 0, #endif sqlite3_bind_blob, sqlite3_bind_double, sqlite3_bind_int, sqlite3_bind_int64, sqlite3_bind_null, sqlite3_bind_parameter_count, sqlite3_bind_parameter_index, sqlite3_bind_parameter_name, sqlite3_bind_text, sqlite3_bind_text16, sqlite3_bind_value, sqlite3_busy_handler, sqlite3_busy_timeout, sqlite3_changes, sqlite3_close, sqlite3_collation_needed, sqlite3_collation_needed16, sqlite3_column_blob, sqlite3_column_bytes, sqlite3_column_bytes16, sqlite3_column_count, sqlite3_column_database_name, sqlite3_column_database_name16, sqlite3_column_decltype, sqlite3_column_decltype16, sqlite3_column_double, sqlite3_column_int, sqlite3_column_int64, sqlite3_column_name, sqlite3_column_name16, sqlite3_column_origin_name, sqlite3_column_origin_name16, sqlite3_column_table_name, sqlite3_column_table_name16, sqlite3_column_text, sqlite3_column_text16, sqlite3_column_type, sqlite3_column_value, sqlite3_commit_hook, sqlite3_complete, sqlite3_complete16, sqlite3_create_collation, sqlite3_create_collation16, sqlite3_create_function, sqlite3_create_function16, sqlite3_create_module, sqlite3_data_count, sqlite3_db_handle, sqlite3_declare_vtab, sqlite3_enable_shared_cache, sqlite3_errcode, sqlite3_errmsg, sqlite3_errmsg16, sqlite3_exec, #ifndef SQLITE_OMIT_DEPRECATED sqlite3_expired, #else 0, #endif sqlite3_finalize, sqlite3_free, sqlite3_free_table, sqlite3_get_autocommit, sqlite3_get_auxdata, sqlite3_get_table, 0, /* Was sqlite3_global_recover(), but that function is deprecated */ sqlite3_interrupt, sqlite3_last_insert_rowid, sqlite3_libversion, sqlite3_libversion_number, sqlite3_malloc, sqlite3_mprintf, sqlite3_open, sqlite3_open16, sqlite3_prepare, sqlite3_prepare16, sqlite3_profile, sqlite3_progress_handler, sqlite3_realloc, sqlite3_reset, sqlite3_result_blob, sqlite3_result_double, sqlite3_result_error, sqlite3_result_error16, sqlite3_result_int, sqlite3_result_int64, sqlite3_result_null, sqlite3_result_text, sqlite3_result_text16, sqlite3_result_text16be, sqlite3_result_text16le, sqlite3_result_value, sqlite3_rollback_hook, sqlite3_set_authorizer, sqlite3_set_auxdata, sqlite3_snprintf, sqlite3_step, sqlite3_table_column_metadata, #ifndef SQLITE_OMIT_DEPRECATED sqlite3_thread_cleanup, #else 0, #endif sqlite3_total_changes, sqlite3_trace, #ifndef SQLITE_OMIT_DEPRECATED sqlite3_transfer_bindings, #else 0, #endif sqlite3_update_hook, sqlite3_user_data, sqlite3_value_blob, sqlite3_value_bytes, sqlite3_value_bytes16, sqlite3_value_double, sqlite3_value_int, sqlite3_value_int64, sqlite3_value_numeric_type, sqlite3_value_text, sqlite3_value_text16, sqlite3_value_text16be, sqlite3_value_text16le, sqlite3_value_type, sqlite3_vmprintf, /* ** The original API set ends here. All extensions can call any ** of the APIs above provided that the pointer is not NULL. But ** before calling APIs that follow, extension should check the ** sqlite3_libversion_number() to make sure they are dealing with ** a library that is new enough to support that API. ************************************************************************* */ sqlite3_overload_function, /* ** Added after 3.3.13 */ sqlite3_prepare_v2, sqlite3_prepare16_v2, sqlite3_clear_bindings, /* ** Added for 3.4.1 */ sqlite3_create_module_v2, /* ** Added for 3.5.0 */ sqlite3_bind_zeroblob, sqlite3_blob_bytes, sqlite3_blob_close, sqlite3_blob_open, sqlite3_blob_read, sqlite3_blob_write, sqlite3_create_collation_v2, sqlite3_file_control, sqlite3_memory_highwater, sqlite3_memory_used, #ifdef SQLITE_MUTEX_OMIT 0, 0, 0, 0, 0, #else sqlite3_mutex_alloc, sqlite3_mutex_enter, sqlite3_mutex_free, sqlite3_mutex_leave, sqlite3_mutex_try, #endif sqlite3_open_v2, sqlite3_release_memory, sqlite3_result_error_nomem, sqlite3_result_error_toobig, sqlite3_sleep, sqlite3_soft_heap_limit, sqlite3_vfs_find, sqlite3_vfs_register, sqlite3_vfs_unregister, /* ** Added for 3.5.8 */ sqlite3_threadsafe, sqlite3_result_zeroblob, sqlite3_result_error_code, sqlite3_test_control, sqlite3_randomness, sqlite3_context_db_handle, /* ** Added for 3.6.0 */ sqlite3_extended_result_codes, sqlite3_limit, sqlite3_next_stmt, sqlite3_sql, sqlite3_status, /* ** Added for 3.7.4 */ sqlite3_backup_finish, sqlite3_backup_init, sqlite3_backup_pagecount, sqlite3_backup_remaining, sqlite3_backup_step, #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS sqlite3_compileoption_get, sqlite3_compileoption_used, #else 0, 0, #endif sqlite3_create_function_v2, sqlite3_db_config, sqlite3_db_mutex, sqlite3_db_status, sqlite3_extended_errcode, sqlite3_log, sqlite3_soft_heap_limit64, sqlite3_sourceid, sqlite3_stmt_status, sqlite3_strnicmp, #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY sqlite3_unlock_notify, #else 0, #endif #ifndef SQLITE_OMIT_WAL sqlite3_wal_autocheckpoint, sqlite3_wal_checkpoint, sqlite3_wal_hook, #else 0, 0, 0, #endif sqlite3_blob_reopen, sqlite3_vtab_config, sqlite3_vtab_on_conflict, sqlite3_close_v2, sqlite3_db_filename, sqlite3_db_readonly, sqlite3_db_release_memory, sqlite3_errstr, sqlite3_stmt_busy, sqlite3_stmt_readonly, sqlite3_stricmp, sqlite3_uri_boolean, sqlite3_uri_int64, sqlite3_uri_parameter, sqlite3_vsnprintf, sqlite3_wal_checkpoint_v2, /* Version 3.8.7 and later */ sqlite3_auto_extension, sqlite3_bind_blob64, sqlite3_bind_text64, sqlite3_cancel_auto_extension, sqlite3_load_extension, sqlite3_malloc64, sqlite3_msize, sqlite3_realloc64, sqlite3_reset_auto_extension, sqlite3_result_blob64, sqlite3_result_text64, sqlite3_strglob, /* Version 3.8.11 and later */ (sqlite3_value*(*)(const sqlite3_value*))sqlite3_value_dup, sqlite3_value_free, sqlite3_result_zeroblob64, sqlite3_bind_zeroblob64, /* Version 3.9.0 and later */ sqlite3_value_subtype, sqlite3_result_subtype, /* Version 3.10.0 and later */ sqlite3_status64, sqlite3_strlike, sqlite3_db_cacheflush, /* Version 3.12.0 and later */ sqlite3_system_errno, /* Version 3.14.0 and later */ sqlite3_trace_v2, sqlite3_expanded_sql, /* Version 3.18.0 and later */ sqlite3_set_last_insert_rowid, /* Version 3.20.0 and later */ sqlite3_prepare_v3, sqlite3_prepare16_v3, sqlite3_bind_pointer, sqlite3_result_pointer, sqlite3_value_pointer, /* Version 3.22.0 and later */ sqlite3_vtab_nochange, sqlite3_value_nochange, sqlite3_vtab_collation, /* Version 3.24.0 and later */ sqlite3_keyword_count, sqlite3_keyword_name, sqlite3_keyword_check, sqlite3_str_new, sqlite3_str_finish, sqlite3_str_appendf, sqlite3_str_vappendf, sqlite3_str_append, sqlite3_str_appendall, sqlite3_str_appendchar, sqlite3_str_reset, sqlite3_str_errcode, sqlite3_str_length, sqlite3_str_value, /* Version 3.25.0 and later */ sqlite3_create_window_function, /* Version 3.26.0 and later */ #ifdef SQLITE_ENABLE_NORMALIZE sqlite3_normalized_sql, #else 0, #endif /* Version 3.28.0 and later */ sqlite3_stmt_isexplain, sqlite3_value_frombind, /* Version 3.30.0 and later */ #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_drop_modules, #else 0, #endif /* Version 3.31.0 and later */ sqlite3_hard_heap_limit64, sqlite3_uri_key, sqlite3_filename_database, sqlite3_filename_journal, sqlite3_filename_wal, /* Version 3.32.0 and later */ sqlite3_create_filename, sqlite3_free_filename, sqlite3_database_file_object, /* Version 3.34.0 and later */ sqlite3_txn_state, /* Version 3.36.1 and later */ sqlite3_changes64, sqlite3_total_changes64, /* Version 3.37.0 and later */ sqlite3_autovacuum_pages, /* Version 3.38.0 and later */ sqlite3_error_offset, #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_vtab_rhs_value, sqlite3_vtab_distinct, sqlite3_vtab_in, sqlite3_vtab_in_first, sqlite3_vtab_in_next, #else 0, 0, 0, 0, 0, #endif /* Version 3.39.0 and later */ #ifndef SQLITE_OMIT_DESERIALIZE sqlite3_deserialize, sqlite3_serialize, #else 0, 0, #endif sqlite3_db_name, /* Version 3.40.0 and later */ sqlite3_value_encoding, /* Version 3.41.0 and later */ sqlite3_is_interrupted, /* Version 3.43.0 and later */ sqlite3_stmt_explain, /* Version 3.44.0 and later */ sqlite3_get_clientdata, sqlite3_set_clientdata }; /* True if x is the directory separator character */ #if SQLITE_OS_WIN # define DirSep(X) ((X)=='/'||(X)=='\\') #else # define DirSep(X) ((X)=='/') #endif /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a ** default entry point name (sqlite3_extension_init) is used. Use ** of the default name is recommended. ** ** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong. ** ** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with ** error message text. The calling function should free this memory ** by calling sqlite3DbFree(db, ). */ static int sqlite3LoadExtension( sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ){ sqlite3_vfs *pVfs = db->pVfs; void *handle; sqlite3_loadext_entry xInit; char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; u64 nMsg = strlen(zFile); int ii; int rc; /* Shared library endings to try if zFile cannot be loaded as written */ static const char *azEndings[] = { #if SQLITE_OS_WIN "dll" #elif defined(__APPLE__) "dylib" #else "so" #endif }; if( pzErrMsg ) *pzErrMsg = 0; /* Ticket #1863. To avoid a creating security problems for older ** applications that relink against newer versions of SQLite, the ** ability to run load_extension is turned off by default. One ** must call either sqlite3_enable_load_extension(db) or ** sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, 0) ** to turn on extension loading. */ if( (db->flags & SQLITE_LoadExtension)==0 ){ if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("not authorized"); } return SQLITE_ERROR; } zEntry = zProc ? zProc : "sqlite3_extension_init"; /* tag-20210611-1. Some dlopen() implementations will segfault if given ** an oversize filename. Most filesystems have a pathname limit of 4K, ** so limit the extension filename length to about twice that. ** https://sqlite.org/forum/forumpost/08a0d6d9bf ** ** Later (2023-03-25): Save an extra 6 bytes for the filename suffix. ** See https://sqlite.org/forum/forumpost/24083b579d. */ if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found; /* Do not allow sqlite3_load_extension() to link to a copy of the ** running application, by passing in an empty filename. */ if( nMsg==0 ) goto extension_not_found; handle = sqlite3OsDlOpen(pVfs, zFile); #if SQLITE_OS_UNIX || SQLITE_OS_WIN for(ii=0; ii sqlite3_example_init ** C:/lib/mathfuncs.dll ==> sqlite3_mathfuncs_init */ if( xInit==0 && zProc==0 ){ int iFile, iEntry, c; int ncFile = sqlite3Strlen30(zFile); zAltEntry = sqlite3_malloc64(ncFile+30); if( zAltEntry==0 ){ sqlite3OsDlClose(pVfs, handle); return SQLITE_NOMEM_BKPT; } memcpy(zAltEntry, "sqlite3_", 8); for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){} iFile++; if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3; for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ if( sqlite3Isalpha(c) ){ zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; } } memcpy(zAltEntry+iEntry, "_init", 6); zEntry = zAltEntry; xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); } if( xInit==0 ){ if( pzErrMsg ){ nMsg += strlen(zEntry) + 300; *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); if( zErrmsg ){ assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */ sqlite3_snprintf((int)nMsg, zErrmsg, "no entry point [%s] in shared library [%s]", zEntry, zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } sqlite3OsDlClose(pVfs, handle); sqlite3_free(zAltEntry); return SQLITE_ERROR; } sqlite3_free(zAltEntry); rc = xInit(db, &zErrmsg, &sqlite3Apis); if( rc ){ if( rc==SQLITE_OK_LOAD_PERMANENTLY ) return SQLITE_OK; if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); } sqlite3_free(zErrmsg); sqlite3OsDlClose(pVfs, handle); return SQLITE_ERROR; } /* Append the new shared library handle to the db->aExtension array. */ aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1)); if( aHandle==0 ){ return SQLITE_NOMEM_BKPT; } if( db->nExtension>0 ){ memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension); } sqlite3DbFree(db, db->aExtension); db->aExtension = aHandle; db->aExtension[db->nExtension++] = handle; return SQLITE_OK; extension_not_found: if( pzErrMsg ){ nMsg += 300; *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); if( zErrmsg ){ assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */ sqlite3_snprintf((int)nMsg, zErrmsg, "unable to open shared library [%.*s]", SQLITE_MAX_PATHLEN, zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } return SQLITE_ERROR; } SQLITE_API int sqlite3_load_extension( sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ){ int rc; sqlite3_mutex_enter(db->mutex); rc = sqlite3LoadExtension(db, zFile, zProc, pzErrMsg); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Call this routine when the database connection is closing in order ** to clean up loaded extensions */ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){ int i; assert( sqlite3_mutex_held(db->mutex) ); for(i=0; inExtension; i++){ sqlite3OsDlClose(db->pVfs, db->aExtension[i]); } sqlite3DbFree(db, db->aExtension); } /* ** Enable or disable extension loading. Extension loading is disabled by ** default so as not to open security holes in older applications. */ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); if( onoff ){ db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc; }else{ db->flags &= ~(u64)(SQLITE_LoadExtension|SQLITE_LoadExtFunc); } sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */ /* ** The following object holds the list of automatically loaded ** extensions. ** ** This list is shared across threads. The SQLITE_MUTEX_STATIC_MAIN ** mutex must be held while accessing this list. */ typedef struct sqlite3AutoExtList sqlite3AutoExtList; static SQLITE_WSD struct sqlite3AutoExtList { u32 nExt; /* Number of entries in aExt[] */ void (**aExt)(void); /* Pointers to the extension init functions */ } sqlite3Autoext = { 0, 0 }; /* The "wsdAutoext" macro will resolve to the autoextension ** state vector. If writable static data is unsupported on the target, ** we have to locate the state vector at run-time. In the more common ** case where writable static data is supported, wsdStat can refer directly ** to the "sqlite3Autoext" state vector declared above. */ #ifdef SQLITE_OMIT_WSD # define wsdAutoextInit \ sqlite3AutoExtList *x = &GLOBAL(sqlite3AutoExtList,sqlite3Autoext) # define wsdAutoext x[0] #else # define wsdAutoextInit # define wsdAutoext sqlite3Autoext #endif /* ** Register a statically linked extension that is automatically ** loaded by every new database connection. */ SQLITE_API int sqlite3_auto_extension( void (*xInit)(void) ){ int rc = SQLITE_OK; #ifdef SQLITE_ENABLE_API_ARMOR if( xInit==0 ) return SQLITE_MISUSE_BKPT; #endif #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ){ return rc; }else #endif { u32 i; #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif wsdAutoextInit; sqlite3_mutex_enter(mutex); for(i=0; i=0; i--){ if( wsdAutoext.aExt[i]==xInit ){ wsdAutoext.nExt--; wsdAutoext.aExt[i] = wsdAutoext.aExt[wsdAutoext.nExt]; n++; break; } } sqlite3_mutex_leave(mutex); return n; } /* ** Reset the automatic extension loading mechanism. */ SQLITE_API void sqlite3_reset_auto_extension(void){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize()==SQLITE_OK ) #endif { #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif wsdAutoextInit; sqlite3_mutex_enter(mutex); sqlite3_free(wsdAutoext.aExt); wsdAutoext.aExt = 0; wsdAutoext.nExt = 0; sqlite3_mutex_leave(mutex); } } /* ** Load all automatic extensions. ** ** If anything goes wrong, set an error in the database connection. */ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ u32 i; int go = 1; int rc; sqlite3_loadext_entry xInit; wsdAutoextInit; if( wsdAutoext.nExt==0 ){ /* Common case: early out without every having to acquire a mutex */ return; } for(i=0; go; i++){ char *zErrmsg; #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif #ifdef SQLITE_OMIT_LOAD_EXTENSION const sqlite3_api_routines *pThunk = 0; #else const sqlite3_api_routines *pThunk = &sqlite3Apis; #endif sqlite3_mutex_enter(mutex); if( i>=wsdAutoext.nExt ){ xInit = 0; go = 0; }else{ xInit = (sqlite3_loadext_entry)wsdAutoext.aExt[i]; } sqlite3_mutex_leave(mutex); zErrmsg = 0; if( xInit && (rc = xInit(db, &zErrmsg, pThunk))!=0 ){ sqlite3ErrorWithMsg(db, rc, "automatic extension loading failed: %s", zErrmsg); go = 0; } sqlite3_free(zErrmsg); } } /************** End of loadext.c *********************************************/ /************** Begin file pragma.c ******************************************/ /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the PRAGMA command. */ /* #include "sqliteInt.h" */ #if !defined(SQLITE_ENABLE_LOCKING_STYLE) # if defined(__APPLE__) # define SQLITE_ENABLE_LOCKING_STYLE 1 # else # define SQLITE_ENABLE_LOCKING_STYLE 0 # endif #endif /*************************************************************************** ** The "pragma.h" include file is an automatically generated file that ** that includes the PragType_XXXX macro definitions and the aPragmaName[] ** object. This ensures that the aPragmaName[] table is arranged in ** lexicographical order to facility a binary search of the pragma name. ** Do not edit pragma.h directly. Edit and rerun the script in at ** ../tool/mkpragmatab.tcl. */ /************** Include pragma.h in the middle of pragma.c *******************/ /************** Begin file pragma.h ******************************************/ /* DO NOT EDIT! ** This file is automatically generated by the script at ** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit ** that script and rerun it. */ /* The various pragma types */ #define PragTyp_ACTIVATE_EXTENSIONS 0 #define PragTyp_ANALYSIS_LIMIT 1 #define PragTyp_HEADER_VALUE 2 #define PragTyp_AUTO_VACUUM 3 #define PragTyp_FLAG 4 #define PragTyp_BUSY_TIMEOUT 5 #define PragTyp_CACHE_SIZE 6 #define PragTyp_CACHE_SPILL 7 #define PragTyp_CASE_SENSITIVE_LIKE 8 #define PragTyp_COLLATION_LIST 9 #define PragTyp_COMPILE_OPTIONS 10 #define PragTyp_DATA_STORE_DIRECTORY 11 #define PragTyp_DATABASE_LIST 12 #define PragTyp_DEFAULT_CACHE_SIZE 13 #define PragTyp_ENCODING 14 #define PragTyp_FOREIGN_KEY_CHECK 15 #define PragTyp_FOREIGN_KEY_LIST 16 #define PragTyp_FUNCTION_LIST 17 #define PragTyp_HARD_HEAP_LIMIT 18 #define PragTyp_INCREMENTAL_VACUUM 19 #define PragTyp_INDEX_INFO 20 #define PragTyp_INDEX_LIST 21 #define PragTyp_INTEGRITY_CHECK 22 #define PragTyp_JOURNAL_MODE 23 #define PragTyp_JOURNAL_SIZE_LIMIT 24 #define PragTyp_LOCK_PROXY_FILE 25 #define PragTyp_LOCKING_MODE 26 #define PragTyp_PAGE_COUNT 27 #define PragTyp_MMAP_SIZE 28 #define PragTyp_MODULE_LIST 29 #define PragTyp_OPTIMIZE 30 #define PragTyp_PAGE_SIZE 31 #define PragTyp_PRAGMA_LIST 32 #define PragTyp_SECURE_DELETE 33 #define PragTyp_SHRINK_MEMORY 34 #define PragTyp_SOFT_HEAP_LIMIT 35 #define PragTyp_SYNCHRONOUS 36 #define PragTyp_TABLE_INFO 37 #define PragTyp_TABLE_LIST 38 #define PragTyp_TEMP_STORE 39 #define PragTyp_TEMP_STORE_DIRECTORY 40 #define PragTyp_THREADS 41 #define PragTyp_WAL_AUTOCHECKPOINT 42 #define PragTyp_WAL_CHECKPOINT 43 #define PragTyp_LOCK_STATUS 44 #define PragTyp_STATS 45 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ #define PragFlg_NoColumns 0x02 /* OP_ResultRow called with zero columns */ #define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */ #define PragFlg_ReadOnly 0x08 /* Read-only HEADER_VALUE */ #define PragFlg_Result0 0x10 /* Acts as query when no argument */ #define PragFlg_Result1 0x20 /* Acts as query when has one argument */ #define PragFlg_SchemaOpt 0x40 /* Schema restricts name search if present */ #define PragFlg_SchemaReq 0x80 /* Schema required - "main" is default */ /* Names of columns for pragmas that return multi-column result ** or that return single-column results where the name of the ** result column is different from the name of the pragma */ static const char *const pragCName[] = { /* 0 */ "id", /* Used by: foreign_key_list */ /* 1 */ "seq", /* 2 */ "table", /* 3 */ "from", /* 4 */ "to", /* 5 */ "on_update", /* 6 */ "on_delete", /* 7 */ "match", /* 8 */ "cid", /* Used by: table_xinfo */ /* 9 */ "name", /* 10 */ "type", /* 11 */ "notnull", /* 12 */ "dflt_value", /* 13 */ "pk", /* 14 */ "hidden", /* table_info reuses 8 */ /* 15 */ "schema", /* Used by: table_list */ /* 16 */ "name", /* 17 */ "type", /* 18 */ "ncol", /* 19 */ "wr", /* 20 */ "strict", /* 21 */ "seqno", /* Used by: index_xinfo */ /* 22 */ "cid", /* 23 */ "name", /* 24 */ "desc", /* 25 */ "coll", /* 26 */ "key", /* 27 */ "name", /* Used by: function_list */ /* 28 */ "builtin", /* 29 */ "type", /* 30 */ "enc", /* 31 */ "narg", /* 32 */ "flags", /* 33 */ "tbl", /* Used by: stats */ /* 34 */ "idx", /* 35 */ "wdth", /* 36 */ "hght", /* 37 */ "flgs", /* 38 */ "seq", /* Used by: index_list */ /* 39 */ "name", /* 40 */ "unique", /* 41 */ "origin", /* 42 */ "partial", /* 43 */ "table", /* Used by: foreign_key_check */ /* 44 */ "rowid", /* 45 */ "parent", /* 46 */ "fkid", /* index_info reuses 21 */ /* 47 */ "seq", /* Used by: database_list */ /* 48 */ "name", /* 49 */ "file", /* 50 */ "busy", /* Used by: wal_checkpoint */ /* 51 */ "log", /* 52 */ "checkpointed", /* collation_list reuses 38 */ /* 53 */ "database", /* Used by: lock_status */ /* 54 */ "status", /* 55 */ "cache_size", /* Used by: default_cache_size */ /* module_list pragma_list reuses 9 */ /* 56 */ "timeout", /* Used by: busy_timeout */ }; /* Definitions of all built-in pragmas */ typedef struct PragmaName { const char *const zName; /* Name of pragma */ u8 ePragTyp; /* PragTyp_XXX value */ u8 mPragFlg; /* Zero or more PragFlg_XXX values */ u8 iPragCName; /* Start of column names in pragCName[] */ u8 nPragCName; /* Num of col names. 0 means use pragma name */ u64 iArg; /* Extra argument */ } PragmaName; static const PragmaName aPragmaName[] = { #if defined(SQLITE_ENABLE_CEROD) {/* zName: */ "activate_extensions", /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif {/* zName: */ "analysis_limit", /* ePragTyp: */ PragTyp_ANALYSIS_LIMIT, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "application_id", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_APPLICATION_ID }, #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) {/* zName: */ "auto_vacuum", /* ePragTyp: */ PragTyp_AUTO_VACUUM, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_AUTOMATIC_INDEX) {/* zName: */ "automatic_index", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_AutoIndex }, #endif #endif {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 56, 1, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "cache_size", /* ePragTyp: */ PragTyp_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "cache_spill", /* ePragTyp: */ PragTyp_CACHE_SPILL, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA) {/* zName: */ "case_sensitive_like", /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, /* ePragFlg: */ PragFlg_NoColumns, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif {/* zName: */ "cell_size_check", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_CellSizeCk }, #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "checkpoint_fullfsync", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_CkptFullFSync }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 38, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) {/* zName: */ "compile_options", /* ePragTyp: */ PragTyp_COMPILE_OPTIONS, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "count_changes", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_CountRows }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN {/* zName: */ "data_store_directory", /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY, /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "data_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_DATA_VERSION }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 47, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) {/* zName: */ "default_cache_size", /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 55, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) {/* zName: */ "defer_foreign_keys", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_DeferFKs }, #endif #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "empty_result_callbacks", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_NullCallback }, #endif #if !defined(SQLITE_OMIT_UTF16) {/* zName: */ "encoding", /* ePragTyp: */ PragTyp_ENCODING, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) {/* zName: */ "foreign_key_check", /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 43, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) {/* zName: */ "foreign_key_list", /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 8, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) {/* zName: */ "foreign_keys", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ForeignKeys }, #endif #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "freelist_count", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_FREE_PAGE_COUNT }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "full_column_names", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_FullColNames }, {/* zName: */ "fullfsync", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_FullFSync }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) #if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 27, 6, /* iArg: */ 0 }, #endif #endif {/* zName: */ "hard_heap_limit", /* ePragTyp: */ PragTyp_HARD_HEAP_LIMIT, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_CHECK) {/* zName: */ "ignore_check_constraints", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_IgnoreChecks }, #endif #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) {/* zName: */ "incremental_vacuum", /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_NoColumns, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 21, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 38, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 21, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "integrity_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "journal_mode", /* ePragTyp: */ PragTyp_JOURNAL_MODE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "journal_size_limit", /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "legacy_alter_table", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_LegacyAlter }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE {/* zName: */ "lock_proxy_file", /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE, /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) {/* zName: */ "lock_status", /* ePragTyp: */ PragTyp_LOCK_STATUS, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 53, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "locking_mode", /* ePragTyp: */ PragTyp_LOCKING_MODE, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "max_page_count", /* ePragTyp: */ PragTyp_PAGE_COUNT, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "mmap_size", /* ePragTyp: */ PragTyp_MMAP_SIZE, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) #if !defined(SQLITE_OMIT_VIRTUALTABLE) #if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) {/* zName: */ "module_list", /* ePragTyp: */ PragTyp_MODULE_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 9, 1, /* iArg: */ 0 }, #endif #endif #endif {/* zName: */ "optimize", /* ePragTyp: */ PragTyp_OPTIMIZE, /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "page_count", /* ePragTyp: */ PragTyp_PAGE_COUNT, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "page_size", /* ePragTyp: */ PragTyp_PAGE_SIZE, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if defined(SQLITE_DEBUG) {/* zName: */ "parser_trace", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ParserTrace }, #endif #endif #if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) {/* zName: */ "pragma_list", /* ePragTyp: */ PragTyp_PRAGMA_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 9, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "query_only", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_QueryOnly }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "quick_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "read_uncommitted", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ReadUncommit }, {/* zName: */ "recursive_triggers", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_RecTriggers }, {/* zName: */ "reverse_unordered_selects", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ReverseOrder }, #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "schema_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_SCHEMA_VERSION }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "secure_delete", /* ePragTyp: */ PragTyp_SECURE_DELETE, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "short_column_names", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ShortColNames }, #endif {/* zName: */ "shrink_memory", /* ePragTyp: */ PragTyp_SHRINK_MEMORY, /* ePragFlg: */ PragFlg_NoColumns, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "soft_heap_limit", /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if defined(SQLITE_DEBUG) {/* zName: */ "sql_trace", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_SqlTrace }, #endif #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 33, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "synchronous", /* ePragTyp: */ PragTyp_SYNCHRONOUS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "table_info", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 8, 6, /* iArg: */ 0 }, {/* zName: */ "table_list", /* ePragTyp: */ PragTyp_TABLE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1, /* ColNames: */ 15, 6, /* iArg: */ 0 }, {/* zName: */ "table_xinfo", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 8, 7, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "temp_store", /* ePragTyp: */ PragTyp_TEMP_STORE, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "temp_store_directory", /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY, /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif {/* zName: */ "threads", /* ePragTyp: */ PragTyp_THREADS, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "trusted_schema", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_TrustedSchema }, #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "user_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_USER_VERSION }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if defined(SQLITE_DEBUG) {/* zName: */ "vdbe_addoptrace", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_VdbeAddopTrace }, {/* zName: */ "vdbe_debug", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace }, {/* zName: */ "vdbe_eqp", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_VdbeEQP }, {/* zName: */ "vdbe_listing", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_VdbeListing }, {/* zName: */ "vdbe_trace", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_VdbeTrace }, #endif #endif #if !defined(SQLITE_OMIT_WAL) {/* zName: */ "wal_autocheckpoint", /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, /* ColNames: */ 50, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "writable_schema", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, #endif }; /* Number of pragmas: 68 on by default, 78 total. */ /************** End of pragma.h **********************************************/ /************** Continuing where we left off in pragma.c *********************/ /* ** Interpret the given string as a safety level. Return 0 for OFF, ** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or ** unrecognized string argument. The FULL and EXTRA option is disallowed ** if the omitFull parameter it 1. ** ** Note that the values returned are one less that the values that ** should be passed into sqlite3BtreeSetSafetyLevel(). The is done ** to support legacy SQL code. The safety level used to be boolean ** and older scripts may have used numbers 0 for OFF and 1 for ON. */ static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){ /* 123456789 123456789 123 */ static const char zText[] = "onoffalseyestruextrafull"; static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 15, 20}; static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 5, 4}; static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 3, 2}; /* on no off false yes true extra full */ int i, n; if( sqlite3Isdigit(*z) ){ return (u8)sqlite3Atoi(z); } n = sqlite3Strlen30(z); for(i=0; i=0&&i<=2)?i:0); } #endif /* ifndef SQLITE_OMIT_AUTOVACUUM */ #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** Interpret the given string as a temp db location. Return 1 for file ** backed temporary databases, 2 for the Red-Black tree in memory database ** and 0 to use the compile-time default. */ static int getTempStore(const char *z){ if( z[0]>='0' && z[0]<='2' ){ return z[0] - '0'; }else if( sqlite3StrICmp(z, "file")==0 ){ return 1; }else if( sqlite3StrICmp(z, "memory")==0 ){ return 2; }else{ return 0; } } #endif /* SQLITE_PAGER_PRAGMAS */ #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** Invalidate temp storage, either when the temp storage is changed ** from default, or when 'file' and the temp_store_directory has changed */ static int invalidateTempStorage(Parse *pParse){ sqlite3 *db = pParse->db; if( db->aDb[1].pBt!=0 ){ if( !db->autoCommit || sqlite3BtreeTxnState(db->aDb[1].pBt)!=SQLITE_TXN_NONE ){ sqlite3ErrorMsg(pParse, "temporary storage cannot be changed " "from within a transaction"); return SQLITE_ERROR; } sqlite3BtreeClose(db->aDb[1].pBt); db->aDb[1].pBt = 0; sqlite3ResetAllSchemasOfConnection(db); } return SQLITE_OK; } #endif /* SQLITE_PAGER_PRAGMAS */ #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** If the TEMP database is open, close it and mark the database schema ** as needing reloading. This must be done when using the SQLITE_TEMP_STORE ** or DEFAULT_TEMP_STORE pragmas. */ static int changeTempStorage(Parse *pParse, const char *zStorageType){ int ts = getTempStore(zStorageType); sqlite3 *db = pParse->db; if( db->temp_store==ts ) return SQLITE_OK; if( invalidateTempStorage( pParse ) != SQLITE_OK ){ return SQLITE_ERROR; } db->temp_store = (u8)ts; return SQLITE_OK; } #endif /* SQLITE_PAGER_PRAGMAS */ /* ** Set result column names for a pragma. */ static void setPragmaResultColumnNames( Vdbe *v, /* The query under construction */ const PragmaName *pPragma /* The pragma */ ){ u8 n = pPragma->nPragCName; sqlite3VdbeSetNumCols(v, n==0 ? 1 : n); if( n==0 ){ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, pPragma->zName, SQLITE_STATIC); }else{ int i, j; for(i=0, j=pPragma->iPragCName; iautoCommit ){ Db *pDb = db->aDb; int n = db->nDb; assert( SQLITE_FullFSync==PAGER_FULLFSYNC ); assert( SQLITE_CkptFullFSync==PAGER_CKPT_FULLFSYNC ); assert( SQLITE_CacheSpill==PAGER_CACHESPILL ); assert( (PAGER_FULLFSYNC | PAGER_CKPT_FULLFSYNC | PAGER_CACHESPILL) == PAGER_FLAGS_MASK ); assert( (pDb->safety_level & PAGER_SYNCHRONOUS_MASK)==pDb->safety_level ); while( (n--) > 0 ){ if( pDb->pBt ){ sqlite3BtreeSetPagerFlags(pDb->pBt, pDb->safety_level | (db->flags & PAGER_FLAGS_MASK) ); } pDb++; } } } #else # define setAllPagerFlags(X) /* no-op */ #endif /* ** Return a human-readable name for a constraint resolution action. */ #ifndef SQLITE_OMIT_FOREIGN_KEY static const char *actionName(u8 action){ const char *zName; switch( action ){ case OE_SetNull: zName = "SET NULL"; break; case OE_SetDflt: zName = "SET DEFAULT"; break; case OE_Cascade: zName = "CASCADE"; break; case OE_Restrict: zName = "RESTRICT"; break; default: zName = "NO ACTION"; assert( action==OE_None ); break; } return zName; } #endif /* ** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants ** defined in pager.h. This function returns the associated lowercase ** journal-mode name. */ SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){ static char * const azModeName[] = { "delete", "persist", "off", "truncate", "memory" #ifndef SQLITE_OMIT_WAL , "wal" #endif }; assert( PAGER_JOURNALMODE_DELETE==0 ); assert( PAGER_JOURNALMODE_PERSIST==1 ); assert( PAGER_JOURNALMODE_OFF==2 ); assert( PAGER_JOURNALMODE_TRUNCATE==3 ); assert( PAGER_JOURNALMODE_MEMORY==4 ); assert( PAGER_JOURNALMODE_WAL==5 ); assert( eMode>=0 && eMode<=ArraySize(azModeName) ); if( eMode==ArraySize(azModeName) ) return 0; return azModeName[eMode]; } /* ** Locate a pragma in the aPragmaName[] array. */ static const PragmaName *pragmaLocate(const char *zName){ int upr, lwr, mid = 0, rc; lwr = 0; upr = ArraySize(aPragmaName)-1; while( lwr<=upr ){ mid = (lwr+upr)/2; rc = sqlite3_stricmp(zName, aPragmaName[mid].zName); if( rc==0 ) break; if( rc<0 ){ upr = mid - 1; }else{ lwr = mid + 1; } } return lwr>upr ? 0 : &aPragmaName[mid]; } /* ** Create zero or more entries in the output for the SQL functions ** defined by FuncDef p. */ static void pragmaFunclistLine( Vdbe *v, /* The prepared statement being created */ FuncDef *p, /* A particular function definition */ int isBuiltin, /* True if this is a built-in function */ int showInternFuncs /* True if showing internal functions */ ){ u32 mask = SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY | SQLITE_SUBTYPE | SQLITE_INNOCUOUS | SQLITE_FUNC_INTERNAL ; if( showInternFuncs ) mask = 0xffffffff; for(; p; p=p->pNext){ const char *zType; static const char *azEnc[] = { 0, "utf8", "utf16le", "utf16be" }; assert( SQLITE_FUNC_ENCMASK==0x3 ); assert( strcmp(azEnc[SQLITE_UTF8],"utf8")==0 ); assert( strcmp(azEnc[SQLITE_UTF16LE],"utf16le")==0 ); assert( strcmp(azEnc[SQLITE_UTF16BE],"utf16be")==0 ); if( p->xSFunc==0 ) continue; if( (p->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && showInternFuncs==0 ){ continue; } if( p->xValue!=0 ){ zType = "w"; }else if( p->xFinalize!=0 ){ zType = "a"; }else{ zType = "s"; } sqlite3VdbeMultiLoad(v, 1, "sissii", p->zName, isBuiltin, zType, azEnc[p->funcFlags&SQLITE_FUNC_ENCMASK], p->nArg, (p->funcFlags & mask) ^ SQLITE_INNOCUOUS ); } } /* ** Helper subroutine for PRAGMA integrity_check: ** ** Generate code to output a single-column result row with a value of the ** string held in register 3. Decrement the result count in register 1 ** and halt if the maximum number of result rows have been issued. */ static int integrityCheckResultRow(Vdbe *v){ int addr; sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1); VdbeCoverage(v); sqlite3VdbeAddOp0(v, OP_Halt); return addr; } /* ** Process a pragma statement. ** ** Pragmas are of this form: ** ** PRAGMA [schema.]id [= value] ** ** The identifier might also be a string. The value is a string, and ** identifier, or a number. If minusFlag is true, then the value is ** a number that was preceded by a minus sign. ** ** If the left side is "database.id" then pId1 is the database name ** and pId2 is the id. If the left side is just "id" then pId1 is the ** id and pId2 is any empty string. */ SQLITE_PRIVATE void sqlite3Pragma( Parse *pParse, Token *pId1, /* First part of [schema.]id field */ Token *pId2, /* Second part of [schema.]id field, or NULL */ Token *pValue, /* Token for , or NULL */ int minusFlag /* True if a '-' sign preceded */ ){ char *zLeft = 0; /* Nul-terminated UTF-8 string */ char *zRight = 0; /* Nul-terminated UTF-8 string , or NULL */ const char *zDb = 0; /* The database name */ Token *pId; /* Pointer to token */ char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */ int iDb; /* Database index for */ int rc; /* return value form SQLITE_FCNTL_PRAGMA */ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* The specific database being pragmaed */ Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ const PragmaName *pPragma; /* The pragma */ if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; /* Interpret the [schema.] part of the pragma statement. iDb is the ** index of the database this pragma is being applied to in db.aDb[]. */ iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId); if( iDb<0 ) return; pDb = &db->aDb[iDb]; /* If the temp database has been explicitly named as part of the ** pragma, make sure it is open. */ if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){ return; } zLeft = sqlite3NameFromToken(db, pId); if( !zLeft ) return; if( minusFlag ){ zRight = sqlite3MPrintf(db, "-%T", pValue); }else{ zRight = sqlite3NameFromToken(db, pValue); } assert( pId2 ); zDb = pId2->n>0 ? pDb->zDbSName : 0; if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){ goto pragma_out; } /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS ** connection. If it returns SQLITE_OK, then assume that the VFS ** handled the pragma and generate a no-op prepared statement. ** ** IMPLEMENTATION-OF: R-12238-55120 Whenever a PRAGMA statement is parsed, ** an SQLITE_FCNTL_PRAGMA file control is sent to the open sqlite3_file ** object corresponding to the database file to which the pragma ** statement refers. ** ** IMPLEMENTATION-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA ** file control is an array of pointers to strings (char**) in which the ** second element of the array is the name of the pragma and the third ** element is the argument to the pragma or NULL if the pragma has no ** argument. */ aFcntl[0] = 0; aFcntl[1] = zLeft; aFcntl[2] = zRight; aFcntl[3] = 0; db->busyHandler.nBusy = 0; rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl); if( rc==SQLITE_OK ){ sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT); returnSingleText(v, aFcntl[0]); sqlite3_free(aFcntl[0]); goto pragma_out; } if( rc!=SQLITE_NOTFOUND ){ if( aFcntl[0] ){ sqlite3ErrorMsg(pParse, "%s", aFcntl[0]); sqlite3_free(aFcntl[0]); } pParse->nErr++; pParse->rc = rc; goto pragma_out; } /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); if( pPragma==0 ){ /* IMP: R-43042-22504 No error messages are generated if an ** unknown pragma is issued. */ goto pragma_out; } /* Make sure the database schema is loaded if the pragma requires that */ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ if( sqlite3ReadSchema(pParse) ) goto pragma_out; } /* Register the result column names for pragmas that return results */ if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0) ){ setPragmaResultColumnNames(v, pPragma); } /* Jump to the appropriate pragma handler */ switch( pPragma->ePragTyp ){ #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) /* ** PRAGMA [schema.]default_cache_size ** PRAGMA [schema.]default_cache_size=N ** ** The first form reports the current persistent setting for the ** page cache size. The value returned is the maximum number of ** pages in the page cache. The second form sets both the current ** page cache size value and the persistent page cache size value ** stored in the database file. ** ** Older versions of SQLite would set the default cache size to a ** negative number to indicate synchronous=OFF. These days, synchronous ** is always on by default regardless of the sign of the default cache ** size. But continue to take the absolute value of the default cache ** size of historical compatibility. */ case PragTyp_DEFAULT_CACHE_SIZE: { static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList getCacheSize[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */ { OP_IfPos, 1, 8, 0}, { OP_Integer, 0, 2, 0}, { OP_Subtract, 1, 2, 1}, { OP_IfPos, 1, 8, 0}, { OP_Integer, 0, 1, 0}, /* 6 */ { OP_Noop, 0, 0, 0}, { OP_ResultRow, 1, 1, 0}, }; VdbeOp *aOp; sqlite3VdbeUsesBtree(v, iDb); if( !zRight ){ pParse->nMem += 2; sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize)); aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn); if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; aOp[0].p1 = iDb; aOp[1].p1 = iDb; aOp[6].p1 = SQLITE_DEFAULT_CACHE_SIZE; }else{ int size = sqlite3AbsInt32(sqlite3Atoi(zRight)); sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, size); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } break; } #endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */ #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) /* ** PRAGMA [schema.]page_size ** PRAGMA [schema.]page_size=N ** ** The first form reports the current setting for the ** database page size in bytes. The second form sets the ** database page size value. The value can only be set if ** the database has not yet been created. */ case PragTyp_PAGE_SIZE: { Btree *pBt = pDb->pBt; assert( pBt!=0 ); if( !zRight ){ int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0; returnSingleInt(v, size); }else{ /* Malloc may fail when setting the page-size, as there is an internal ** buffer that the pager module resizes using sqlite3_realloc(). */ db->nextPagesize = sqlite3Atoi(zRight); if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){ sqlite3OomFault(db); } } break; } /* ** PRAGMA [schema.]secure_delete ** PRAGMA [schema.]secure_delete=ON/OFF/FAST ** ** The first form reports the current setting for the ** secure_delete flag. The second form changes the secure_delete ** flag setting and reports the new value. */ case PragTyp_SECURE_DELETE: { Btree *pBt = pDb->pBt; int b = -1; assert( pBt!=0 ); if( zRight ){ if( sqlite3_stricmp(zRight, "fast")==0 ){ b = 2; }else{ b = sqlite3GetBoolean(zRight, 0); } } if( pId2->n==0 && b>=0 ){ int ii; for(ii=0; iinDb; ii++){ sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b); } } b = sqlite3BtreeSecureDelete(pBt, b); returnSingleInt(v, b); break; } /* ** PRAGMA [schema.]max_page_count ** PRAGMA [schema.]max_page_count=N ** ** The first form reports the current setting for the ** maximum number of pages in the database file. The ** second form attempts to change this setting. Both ** forms return the current setting. ** ** The absolute value of N is used. This is undocumented and might ** change. The only purpose is to provide an easy way to test ** the sqlite3AbsInt32() function. ** ** PRAGMA [schema.]page_count ** ** Return the number of pages in the specified database. */ case PragTyp_PAGE_COUNT: { int iReg; i64 x = 0; sqlite3CodeVerifySchema(pParse, iDb); iReg = ++pParse->nMem; if( sqlite3Tolower(zLeft[0])=='p' ){ sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg); }else{ if( zRight && sqlite3DecOrHexToI64(zRight,&x)==0 ){ if( x<0 ) x = 0; else if( x>0xfffffffe ) x = 0xfffffffe; }else{ x = 0; } sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, (int)x); } sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1); break; } /* ** PRAGMA [schema.]locking_mode ** PRAGMA [schema.]locking_mode = (normal|exclusive) */ case PragTyp_LOCKING_MODE: { const char *zRet = "normal"; int eMode = getLockingMode(zRight); if( pId2->n==0 && eMode==PAGER_LOCKINGMODE_QUERY ){ /* Simple "PRAGMA locking_mode;" statement. This is a query for ** the current default locking mode (which may be different to ** the locking-mode of the main database). */ eMode = db->dfltLockMode; }else{ Pager *pPager; if( pId2->n==0 ){ /* This indicates that no database name was specified as part ** of the PRAGMA command. In this case the locking-mode must be ** set on all attached databases, as well as the main db file. ** ** Also, the sqlite3.dfltLockMode variable is set so that ** any subsequently attached databases also use the specified ** locking mode. */ int ii; assert(pDb==&db->aDb[0]); for(ii=2; iinDb; ii++){ pPager = sqlite3BtreePager(db->aDb[ii].pBt); sqlite3PagerLockingMode(pPager, eMode); } db->dfltLockMode = (u8)eMode; } pPager = sqlite3BtreePager(pDb->pBt); eMode = sqlite3PagerLockingMode(pPager, eMode); } assert( eMode==PAGER_LOCKINGMODE_NORMAL || eMode==PAGER_LOCKINGMODE_EXCLUSIVE ); if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){ zRet = "exclusive"; } returnSingleText(v, zRet); break; } /* ** PRAGMA [schema.]journal_mode ** PRAGMA [schema.]journal_mode = ** (delete|persist|off|truncate|memory|wal|off) */ case PragTyp_JOURNAL_MODE: { int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */ int ii; /* Loop counter */ if( zRight==0 ){ /* If there is no "=MODE" part of the pragma, do a query for the ** current mode */ eMode = PAGER_JOURNALMODE_QUERY; }else{ const char *zMode; int n = sqlite3Strlen30(zRight); for(eMode=0; (zMode = sqlite3JournalModename(eMode))!=0; eMode++){ if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break; } if( !zMode ){ /* If the "=MODE" part does not match any known journal mode, ** then do a query */ eMode = PAGER_JOURNALMODE_QUERY; } if( eMode==PAGER_JOURNALMODE_OFF && (db->flags & SQLITE_Defensive)!=0 ){ /* Do not allow journal-mode "OFF" in defensive since the database ** can become corrupted using ordinary SQL when the journal is off */ eMode = PAGER_JOURNALMODE_QUERY; } } if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){ /* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */ iDb = 0; pId2->n = 1; } for(ii=db->nDb-1; ii>=0; ii--){ if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){ sqlite3VdbeUsesBtree(v, ii); sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode); } } sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); break; } /* ** PRAGMA [schema.]journal_size_limit ** PRAGMA [schema.]journal_size_limit=N ** ** Get or set the size limit on rollback journal files. */ case PragTyp_JOURNAL_SIZE_LIMIT: { Pager *pPager = sqlite3BtreePager(pDb->pBt); i64 iLimit = -2; if( zRight ){ sqlite3DecOrHexToI64(zRight, &iLimit); if( iLimit<-1 ) iLimit = -1; } iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit); returnSingleInt(v, iLimit); break; } #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ /* ** PRAGMA [schema.]auto_vacuum ** PRAGMA [schema.]auto_vacuum=N ** ** Get or set the value of the database 'auto-vacuum' parameter. ** The value is one of: 0 NONE 1 FULL 2 INCREMENTAL */ #ifndef SQLITE_OMIT_AUTOVACUUM case PragTyp_AUTO_VACUUM: { Btree *pBt = pDb->pBt; assert( pBt!=0 ); if( !zRight ){ returnSingleInt(v, sqlite3BtreeGetAutoVacuum(pBt)); }else{ int eAuto = getAutoVacuum(zRight); assert( eAuto>=0 && eAuto<=2 ); db->nextAutovac = (u8)eAuto; /* Call SetAutoVacuum() to set initialize the internal auto and ** incr-vacuum flags. This is required in case this connection ** creates the database file. It is important that it is created ** as an auto-vacuum capable db. */ rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto); if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){ /* When setting the auto_vacuum mode to either "full" or ** "incremental", write the value of meta[6] in the database ** file. Before writing to meta[6], check that meta[3] indicates ** that this really is an auto-vacuum capable database. */ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList setMeta6[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ { OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE}, { OP_If, 1, 0, 0}, /* 2 */ { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */ { OP_SetCookie, 0, BTREE_INCR_VACUUM, 0}, /* 4 */ }; VdbeOp *aOp; int iAddr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setMeta6)); aOp = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn); if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; aOp[0].p1 = iDb; aOp[1].p1 = iDb; aOp[2].p2 = iAddr+4; aOp[4].p1 = iDb; aOp[4].p3 = eAuto - 1; sqlite3VdbeUsesBtree(v, iDb); } } break; } #endif /* ** PRAGMA [schema.]incremental_vacuum(N) ** ** Do N steps of incremental vacuuming on a database. */ #ifndef SQLITE_OMIT_AUTOVACUUM case PragTyp_INCREMENTAL_VACUUM: { int iLimit = 0, addr; if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){ iLimit = 0x7fffffff; } sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1); addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_ResultRow, 1); sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr); break; } #endif #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** PRAGMA [schema.]cache_size ** PRAGMA [schema.]cache_size=N ** ** The first form reports the current local setting for the ** page cache size. The second form sets the local ** page cache size value. If N is positive then that is the ** number of pages in the cache. If N is negative, then the ** number of pages is adjusted so that the cache uses -N kibibytes ** of memory. */ case PragTyp_CACHE_SIZE: { assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !zRight ){ returnSingleInt(v, pDb->pSchema->cache_size); }else{ int size = sqlite3Atoi(zRight); pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } break; } /* ** PRAGMA [schema.]cache_spill ** PRAGMA cache_spill=BOOLEAN ** PRAGMA [schema.]cache_spill=N ** ** The first form reports the current local setting for the ** page cache spill size. The second form turns cache spill on ** or off. When turning cache spill on, the size is set to the ** current cache_size. The third form sets a spill size that ** may be different form the cache size. ** If N is positive then that is the ** number of pages in the cache. If N is negative, then the ** number of pages is adjusted so that the cache uses -N kibibytes ** of memory. ** ** If the number of cache_spill pages is less then the number of ** cache_size pages, no spilling occurs until the page count exceeds ** the number of cache_size pages. ** ** The cache_spill=BOOLEAN setting applies to all attached schemas, ** not just the schema specified. */ case PragTyp_CACHE_SPILL: { assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !zRight ){ returnSingleInt(v, (db->flags & SQLITE_CacheSpill)==0 ? 0 : sqlite3BtreeSetSpillSize(pDb->pBt,0)); }else{ int size = 1; if( sqlite3GetInt32(zRight, &size) ){ sqlite3BtreeSetSpillSize(pDb->pBt, size); } if( sqlite3GetBoolean(zRight, size!=0) ){ db->flags |= SQLITE_CacheSpill; }else{ db->flags &= ~(u64)SQLITE_CacheSpill; } setAllPagerFlags(db); } break; } /* ** PRAGMA [schema.]mmap_size(N) ** ** Used to set mapping size limit. The mapping size limit is ** used to limit the aggregate size of all memory mapped regions of the ** database file. If this parameter is set to zero, then memory mapping ** is not used at all. If N is negative, then the default memory map ** limit determined by sqlite3_config(SQLITE_CONFIG_MMAP_SIZE) is set. ** The parameter N is measured in bytes. ** ** This value is advisory. The underlying VFS is free to memory map ** as little or as much as it wants. Except, if N is set to 0 then the ** upper layers will never invoke the xFetch interfaces to the VFS. */ case PragTyp_MMAP_SIZE: { sqlite3_int64 sz; #if SQLITE_MAX_MMAP_SIZE>0 assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( zRight ){ int ii; sqlite3DecOrHexToI64(zRight, &sz); if( sz<0 ) sz = sqlite3GlobalConfig.szMmap; if( pId2->n==0 ) db->szMmap = sz; for(ii=db->nDb-1; ii>=0; ii--){ if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){ sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz); } } } sz = -1; rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_MMAP_SIZE, &sz); #else sz = 0; rc = SQLITE_OK; #endif if( rc==SQLITE_OK ){ returnSingleInt(v, sz); }else if( rc!=SQLITE_NOTFOUND ){ pParse->nErr++; pParse->rc = rc; } break; } /* ** PRAGMA temp_store ** PRAGMA temp_store = "default"|"memory"|"file" ** ** Return or set the local value of the temp_store flag. Changing ** the local value does not make changes to the disk file and the default ** value will be restored the next time the database is opened. ** ** Note that it is possible for the library compile-time options to ** override this setting */ case PragTyp_TEMP_STORE: { if( !zRight ){ returnSingleInt(v, db->temp_store); }else{ changeTempStorage(pParse, zRight); } break; } /* ** PRAGMA temp_store_directory ** PRAGMA temp_store_directory = ""|"directory_name" ** ** Return or set the local value of the temp_store_directory flag. Changing ** the value sets a specific directory to be used for temporary files. ** Setting to a null string reverts to the default temporary directory search. ** If temporary directory is changed, then invalidateTempStorage. ** */ case PragTyp_TEMP_STORE_DIRECTORY: { sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); if( !zRight ){ returnSingleText(v, sqlite3_temp_directory); }else{ #ifndef SQLITE_OMIT_WSD if( zRight[0] ){ int res; rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res); if( rc!=SQLITE_OK || res==0 ){ sqlite3ErrorMsg(pParse, "not a writable directory"); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); goto pragma_out; } } if( SQLITE_TEMP_STORE==0 || (SQLITE_TEMP_STORE==1 && db->temp_store<=1) || (SQLITE_TEMP_STORE==2 && db->temp_store==1) ){ invalidateTempStorage(pParse); } sqlite3_free(sqlite3_temp_directory); if( zRight[0] ){ sqlite3_temp_directory = sqlite3_mprintf("%s", zRight); }else{ sqlite3_temp_directory = 0; } #endif /* SQLITE_OMIT_WSD */ } sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); break; } #if SQLITE_OS_WIN /* ** PRAGMA data_store_directory ** PRAGMA data_store_directory = ""|"directory_name" ** ** Return or set the local value of the data_store_directory flag. Changing ** the value sets a specific directory to be used for database files that ** were specified with a relative pathname. Setting to a null string reverts ** to the default database directory, which for database files specified with ** a relative path will probably be based on the current directory for the ** process. Database file specified with an absolute path are not impacted ** by this setting, regardless of its value. ** */ case PragTyp_DATA_STORE_DIRECTORY: { sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); if( !zRight ){ returnSingleText(v, sqlite3_data_directory); }else{ #ifndef SQLITE_OMIT_WSD if( zRight[0] ){ int res; rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res); if( rc!=SQLITE_OK || res==0 ){ sqlite3ErrorMsg(pParse, "not a writable directory"); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); goto pragma_out; } } sqlite3_free(sqlite3_data_directory); if( zRight[0] ){ sqlite3_data_directory = sqlite3_mprintf("%s", zRight); }else{ sqlite3_data_directory = 0; } #endif /* SQLITE_OMIT_WSD */ } sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR)); break; } #endif #if SQLITE_ENABLE_LOCKING_STYLE /* ** PRAGMA [schema.]lock_proxy_file ** PRAGMA [schema.]lock_proxy_file = ":auto:"|"lock_file_path" ** ** Return or set the value of the lock_proxy_file flag. Changing ** the value sets a specific file to be used for database access locks. ** */ case PragTyp_LOCK_PROXY_FILE: { if( !zRight ){ Pager *pPager = sqlite3BtreePager(pDb->pBt); char *proxy_file_path = NULL; sqlite3_file *pFile = sqlite3PagerFile(pPager); sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE, &proxy_file_path); returnSingleText(v, proxy_file_path); }else{ Pager *pPager = sqlite3BtreePager(pDb->pBt); sqlite3_file *pFile = sqlite3PagerFile(pPager); int res; if( zRight[0] ){ res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE, zRight); } else { res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE, NULL); } if( res!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "failed to set lock proxy file"); goto pragma_out; } } break; } #endif /* SQLITE_ENABLE_LOCKING_STYLE */ /* ** PRAGMA [schema.]synchronous ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL|EXTRA ** ** Return or set the local value of the synchronous flag. Changing ** the local value does not make changes to the disk file and the ** default value will be restored the next time the database is ** opened. */ case PragTyp_SYNCHRONOUS: { if( !zRight ){ returnSingleInt(v, pDb->safety_level-1); }else{ if( !db->autoCommit ){ sqlite3ErrorMsg(pParse, "Safety level may not be changed inside a transaction"); }else if( iDb!=1 ){ int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK; if( iLevel==0 ) iLevel = 1; pDb->safety_level = iLevel; pDb->bSyncSet = 1; setAllPagerFlags(db); } } break; } #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ #ifndef SQLITE_OMIT_FLAG_PRAGMAS case PragTyp_FLAG: { if( zRight==0 ){ setPragmaResultColumnNames(v, pPragma); returnSingleInt(v, (db->flags & pPragma->iArg)!=0 ); }else{ u64 mask = pPragma->iArg; /* Mask of bits to set or clear. */ if( db->autoCommit==0 ){ /* Foreign key support may not be enabled or disabled while not ** in auto-commit mode. */ mask &= ~(SQLITE_ForeignKeys); } #if SQLITE_USER_AUTHENTICATION if( db->auth.authLevel==UAUTH_User ){ /* Do not allow non-admin users to modify the schema arbitrarily */ mask &= ~(SQLITE_WriteSchema); } #endif if( sqlite3GetBoolean(zRight, 0) ){ if( (mask & SQLITE_WriteSchema)==0 || (db->flags & SQLITE_Defensive)==0 ){ db->flags |= mask; } }else{ db->flags &= ~mask; if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; if( (mask & SQLITE_WriteSchema)!=0 && sqlite3_stricmp(zRight, "reset")==0 ){ /* IMP: R-60817-01178 If the argument is "RESET" then schema ** writing is disabled (as with "PRAGMA writable_schema=OFF") and, ** in addition, the schema is reloaded. */ sqlite3ResetAllSchemasOfConnection(db); } } /* Many of the flag-pragmas modify the code generated by the SQL ** compiler (eg. count_changes). So add an opcode to expire all ** compiled SQL statements after modifying a pragma value. */ sqlite3VdbeAddOp0(v, OP_Expire); setAllPagerFlags(db); } break; } #endif /* SQLITE_OMIT_FLAG_PRAGMAS */ #ifndef SQLITE_OMIT_SCHEMA_PRAGMAS /* ** PRAGMA table_info(
    ) ** ** Return a single row for each column of the named table. The columns of ** the returned data set are: ** ** cid: Column id (numbered from left to right, starting at 0) ** name: Column name ** type: Column declaration type. ** notnull: True if 'NOT NULL' is part of column declaration ** dflt_value: The default value for the column, if any. ** pk: Non-zero for PK fields. */ case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; sqlite3CodeVerifyNamedSchema(pParse, zDb); pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab ){ int i, k; int nHidden = 0; Column *pCol; Index *pPk = sqlite3PrimaryKeyIndex(pTab); pParse->nMem = 7; sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ int isHidden = 0; const Expr *pColExpr; if( pCol->colFlags & COLFLAG_NOINSERT ){ if( pPragma->iArg==0 ){ nHidden++; continue; } if( pCol->colFlags & COLFLAG_VIRTUAL ){ isHidden = 2; /* GENERATED ALWAYS AS ... VIRTUAL */ }else if( pCol->colFlags & COLFLAG_STORED ){ isHidden = 3; /* GENERATED ALWAYS AS ... STORED */ }else{ assert( pCol->colFlags & COLFLAG_HIDDEN ); isHidden = 1; /* HIDDEN */ } } if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){ k = 0; }else if( pPk==0 ){ k = 1; }else{ for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} } pColExpr = sqlite3ColumnExpr(pTab,pCol); assert( pColExpr==0 || pColExpr->op==TK_SPAN || isHidden>=2 ); assert( pColExpr==0 || !ExprHasProperty(pColExpr, EP_IntValue) || isHidden>=2 ); sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi", i-nHidden, pCol->zCnName, sqlite3ColumnType(pCol,""), pCol->notNull ? 1 : 0, (isHidden>=2 || pColExpr==0) ? 0 : pColExpr->u.zToken, k, isHidden); } } } break; /* ** PRAGMA table_list ** ** Return a single row for each table, virtual table, or view in the ** entire schema. ** ** schema: Name of attached database hold this table ** name: Name of the table itself ** type: "table", "view", "virtual", "shadow" ** ncol: Number of columns ** wr: True for a WITHOUT ROWID table ** strict: True for a STRICT table */ case PragTyp_TABLE_LIST: { int ii; pParse->nMem = 6; sqlite3CodeVerifyNamedSchema(pParse, zDb); for(ii=0; iinDb; ii++){ HashElem *k; Hash *pHash; int initNCol; if( zDb && sqlite3_stricmp(zDb, db->aDb[ii].zDbSName)!=0 ) continue; /* Ensure that the Table.nCol field is initialized for all views ** and virtual tables. Each time we initialize a Table.nCol value ** for a table, that can potentially disrupt the hash table, so restart ** the initialization scan. */ pHash = &db->aDb[ii].pSchema->tblHash; initNCol = sqliteHashCount(pHash); while( initNCol-- ){ for(k=sqliteHashFirst(pHash); 1; k=sqliteHashNext(k) ){ Table *pTab; if( k==0 ){ initNCol = 0; break; } pTab = sqliteHashData(k); if( pTab->nCol==0 ){ char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName); if( zSql ){ sqlite3_stmt *pDummy = 0; (void)sqlite3_prepare(db, zSql, -1, &pDummy, 0); (void)sqlite3_finalize(pDummy); sqlite3DbFree(db, zSql); } if( db->mallocFailed ){ sqlite3ErrorMsg(db->pParse, "out of memory"); db->pParse->rc = SQLITE_NOMEM_BKPT; } pHash = &db->aDb[ii].pSchema->tblHash; break; } } } for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k) ){ Table *pTab = sqliteHashData(k); const char *zType; if( zRight && sqlite3_stricmp(zRight, pTab->zName)!=0 ) continue; if( IsView(pTab) ){ zType = "view"; }else if( IsVirtual(pTab) ){ zType = "virtual"; }else if( pTab->tabFlags & TF_Shadow ){ zType = "shadow"; }else{ zType = "table"; } sqlite3VdbeMultiLoad(v, 1, "sssiii", db->aDb[ii].zDbSName, sqlite3PreferredTableName(pTab->zName), zType, pTab->nCol, (pTab->tabFlags & TF_WithoutRowid)!=0, (pTab->tabFlags & TF_Strict)!=0 ); } } } break; #ifdef SQLITE_DEBUG case PragTyp_STATS: { Index *pIdx; HashElem *i; pParse->nMem = 5; sqlite3CodeVerifySchema(pParse, iDb); for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); sqlite3VdbeMultiLoad(v, 1, "ssiii", sqlite3PreferredTableName(pTab->zName), 0, pTab->szTabRow, pTab->nRowLogEst, pTab->tabFlags); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3VdbeMultiLoad(v, 2, "siiiX", pIdx->zName, pIdx->szIdxRow, pIdx->aiRowLogEst[0], pIdx->hasStat1); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); } } } break; #endif case PragTyp_INDEX_INFO: if( zRight ){ Index *pIdx; Table *pTab; pIdx = sqlite3FindIndex(db, zRight, zDb); if( pIdx==0 ){ /* If there is no index named zRight, check to see if there is a ** WITHOUT ROWID table named zRight, and if there is, show the ** structure of the PRIMARY KEY index for that table. */ pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab && !HasRowid(pTab) ){ pIdx = sqlite3PrimaryKeyIndex(pTab); } } if( pIdx ){ int iIdxDb = sqlite3SchemaToIndex(db, pIdx->pSchema); int i; int mx; if( pPragma->iArg ){ /* PRAGMA index_xinfo (newer version with more rows and columns) */ mx = pIdx->nColumn; pParse->nMem = 6; }else{ /* PRAGMA index_info (legacy version) */ mx = pIdx->nKeyCol; pParse->nMem = 3; } pTab = pIdx->pTable; sqlite3CodeVerifySchema(pParse, iIdxDb); assert( pParse->nMem<=pPragma->nPragCName ); for(i=0; iaiColumn[i]; sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum, cnum<0 ? 0 : pTab->aCol[cnum].zCnName); if( pPragma->iArg ){ sqlite3VdbeMultiLoad(v, 4, "isiX", pIdx->aSortOrder[i], pIdx->azColl[i], inKeyCol); } sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem); } } } break; case PragTyp_INDEX_LIST: if( zRight ){ Index *pIdx; Table *pTab; int i; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); pParse->nMem = 5; sqlite3CodeVerifySchema(pParse, iTabDb); for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ const char *azOrigin[] = { "c", "u", "pk" }; sqlite3VdbeMultiLoad(v, 1, "isisi", i, pIdx->zName, IsUniqueIndex(pIdx), azOrigin[pIdx->idxType], pIdx->pPartIdxWhere!=0); } } } break; case PragTyp_DATABASE_LIST: { int i; pParse->nMem = 3; for(i=0; inDb; i++){ if( db->aDb[i].pBt==0 ) continue; assert( db->aDb[i].zDbSName!=0 ); sqlite3VdbeMultiLoad(v, 1, "iss", i, db->aDb[i].zDbSName, sqlite3BtreeGetFilename(db->aDb[i].pBt)); } } break; case PragTyp_COLLATION_LIST: { int i = 0; HashElem *p; pParse->nMem = 2; for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ CollSeq *pColl = (CollSeq *)sqliteHashData(p); sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName); } } break; #ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS case PragTyp_FUNCTION_LIST: { int i; HashElem *j; FuncDef *p; int showInternFunc = (db->mDbFlags & DBFLAG_InternalFunc)!=0; pParse->nMem = 6; for(i=0; iu.pHash ){ assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); pragmaFunclistLine(v, p, 1, showInternFunc); } } for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){ p = (FuncDef*)sqliteHashData(j); assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 ); pragmaFunclistLine(v, p, 0, showInternFunc); } } break; #ifndef SQLITE_OMIT_VIRTUALTABLE case PragTyp_MODULE_LIST: { HashElem *j; pParse->nMem = 1; for(j=sqliteHashFirst(&db->aModule); j; j=sqliteHashNext(j)){ Module *pMod = (Module*)sqliteHashData(j); sqlite3VdbeMultiLoad(v, 1, "s", pMod->zName); } } break; #endif /* SQLITE_OMIT_VIRTUALTABLE */ case PragTyp_PRAGMA_LIST: { int i; for(i=0; iu.tab.pFKey; if( pFK ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int i = 0; pParse->nMem = 8; sqlite3CodeVerifySchema(pParse, iTabDb); while(pFK){ int j; for(j=0; jnCol; j++){ sqlite3VdbeMultiLoad(v, 1, "iissssss", i, j, pFK->zTo, pTab->aCol[pFK->aCol[j].iFrom].zCnName, pFK->aCol[j].zCol, actionName(pFK->aAction[1]), /* ON UPDATE */ actionName(pFK->aAction[0]), /* ON DELETE */ "NONE"); } ++i; pFK = pFK->pNextFrom; } } } } break; #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef SQLITE_OMIT_FOREIGN_KEY #ifndef SQLITE_OMIT_TRIGGER case PragTyp_FOREIGN_KEY_CHECK: { FKey *pFK; /* A foreign key constraint */ Table *pTab; /* Child table contain "REFERENCES" keyword */ Table *pParent; /* Parent table that child points to */ Index *pIdx; /* Index in the parent table */ int i; /* Loop counter: Foreign key number for pTab */ int j; /* Loop counter: Field of the foreign key */ HashElem *k; /* Loop counter: Next table in schema */ int x; /* result variable */ int regResult; /* 3 registers to hold a result row */ int regRow; /* Registers to hold a row from pTab */ int addrTop; /* Top of a loop checking foreign keys */ int addrOk; /* Jump here if the key is OK */ int *aiCols; /* child to parent column mapping */ regResult = pParse->nMem+1; pParse->nMem += 4; regRow = ++pParse->nMem; k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); while( k ){ if( zRight ){ pTab = sqlite3LocateTable(pParse, 0, zRight, zDb); k = 0; }else{ pTab = (Table*)sqliteHashData(k); k = sqliteHashNext(k); } if( pTab==0 || !IsOrdinaryTable(pTab) || pTab->u.tab.pFKey==0 ) continue; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); sqlite3TouchRegister(pParse, pTab->nCol+regRow); sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); sqlite3VdbeLoadString(v, regResult, pTab->zName); assert( IsOrdinaryTable(pTab) ); for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); if( pParent==0 ) continue; pIdx = 0; sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName); x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0); if( x==0 ){ if( pIdx==0 ){ sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead); }else{ sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); } }else{ k = 0; break; } } assert( pParse->nErr>0 || pFK==0 ); if( pFK ) break; if( pParse->nTabnTab = i; addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v); assert( IsOrdinaryTable(pTab) ); for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); pIdx = 0; aiCols = 0; if( pParent ){ x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols); assert( x==0 || db->mallocFailed ); } addrOk = sqlite3VdbeMakeLabel(pParse); /* Generate code to read the child key values into registers ** regRow..regRow+n. If any of the child key values are NULL, this ** row cannot cause an FK violation. Jump directly to addrOk in ** this case. */ sqlite3TouchRegister(pParse, regRow + pFK->nCol); for(j=0; jnCol; j++){ int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom; sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j); sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); } /* Generate code to query the parent index for a matching parent ** key. If a match is found, jump to addrOk. */ if( pIdx ){ sqlite3VdbeAddOp4(v, OP_Affinity, regRow, pFK->nCol, 0, sqlite3IndexAffinityStr(db,pIdx), pFK->nCol); sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regRow, pFK->nCol); VdbeCoverage(v); }else if( pParent ){ int jmp = sqlite3VdbeCurrentAddr(v)+2; sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v); sqlite3VdbeGoto(v, addrOk); assert( pFK->nCol==1 || db->mallocFailed ); } /* Generate code to report an FK violation to the caller. */ if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1); } sqlite3VdbeMultiLoad(v, regResult+2, "siX", pFK->zTo, i-1); sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4); sqlite3VdbeResolveLabel(v, addrOk); sqlite3DbFree(db, aiCols); } sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrTop); } } break; #endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA /* Reinstall the LIKE and GLOB functions. The variant of LIKE ** used will be case sensitive or not depending on the RHS. */ case PragTyp_CASE_SENSITIVE_LIKE: { if( zRight ){ sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight, 0)); } } break; #endif /* SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA */ #ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX # define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 #endif #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* PRAGMA integrity_check ** PRAGMA integrity_check(N) ** PRAGMA quick_check ** PRAGMA quick_check(N) ** ** Verify the integrity of the database. ** ** The "quick_check" is reduced version of ** integrity_check designed to detect most database corruption ** without the overhead of cross-checking indexes. Quick_check ** is linear time whereas integrity_check is O(NlogN). ** ** The maximum number of errors is 100 by default. A different default ** can be specified using a numeric parameter N. ** ** Or, the parameter N can be the name of a table. In that case, only ** the one table named is verified. The freelist is only verified if ** the named table is "sqlite_schema" (or one of its aliases). ** ** All schemas are checked by default. To check just a single ** schema, use the form: ** ** PRAGMA schema.integrity_check; */ case PragTyp_INTEGRITY_CHECK: { int i, j, addr, mxErr; Table *pObjTab = 0; /* Check only this one table, if not NULL */ int isQuick = (sqlite3Tolower(zLeft[0])=='q'); /* If the PRAGMA command was of the form "PRAGMA .integrity_check", ** then iDb is set to the index of the database identified by . ** In this case, the integrity of database iDb only is verified by ** the VDBE created below. ** ** Otherwise, if the command was simply "PRAGMA integrity_check" (or ** "PRAGMA quick_check"), then iDb is set to 0. In this case, set iDb ** to -1 here, to indicate that the VDBE should verify the integrity ** of all attached databases. */ assert( iDb>=0 ); assert( iDb==0 || pId2->z ); if( pId2->z==0 ) iDb = -1; /* Initialize the VDBE program */ pParse->nMem = 6; /* Set the maximum error count */ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; if( zRight ){ if( sqlite3GetInt32(zRight, &mxErr) ){ if( mxErr<=0 ){ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; } }else{ pObjTab = sqlite3LocateTable(pParse, 0, zRight, iDb>=0 ? db->aDb[iDb].zDbSName : 0); } } sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */ /* Do an integrity check on each database file */ for(i=0; inDb; i++){ HashElem *x; /* For looping over tables in the schema */ Hash *pTbls; /* Set of all tables in the schema */ int *aRoot; /* Array of root page numbers of all btrees */ int cnt = 0; /* Number of entries in aRoot[] */ int mxIdx = 0; /* Maximum number of indexes for any table */ if( OMIT_TEMPDB && i==1 ) continue; if( iDb>=0 && i!=iDb ) continue; sqlite3CodeVerifySchema(pParse, i); pParse->okConstFactor = 0; /* tag-20230327-1 */ /* Do an integrity check of the B-Tree ** ** Begin by finding the root pages numbers ** for all tables and indices in the database. */ assert( sqlite3SchemaMutexHeld(db, i, 0) ); pTbls = &db->aDb[i].pSchema->tblHash; for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); /* Current table */ Index *pIdx; /* An index on pTab */ int nIdx; /* Number of indexes on pTab */ if( pObjTab && pObjTab!=pTab ) continue; if( HasRowid(pTab) ) cnt++; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } if( nIdx>mxIdx ) mxIdx = nIdx; } if( cnt==0 ) continue; if( pObjTab ) cnt++; aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1)); if( aRoot==0 ) break; cnt = 0; if( pObjTab ) aRoot[++cnt] = 0; for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; if( pObjTab && pObjTab!=pTab ) continue; if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ aRoot[++cnt] = pIdx->tnum; } } aRoot[0] = cnt; /* Make sure sufficient number of registers have been allocated */ sqlite3TouchRegister(pParse, 8+mxIdx); sqlite3ClearTempRegCache(pParse); /* Do the b-tree integrity checks */ sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY); sqlite3VdbeChangeP5(v, (u8)i); addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName), P4_DYNAMIC); sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3); integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, addr); /* Make sure all the indices are constructed correctly. */ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx, *pPk; Index *pPrior = 0; /* Previous index */ int loopTop; int iDataCur, iIdxCur; int r1 = -1; int bStrict; /* True for a STRICT table */ int r2; /* Previous key for WITHOUT ROWID tables */ int mxCol; /* Maximum non-virtual column number */ if( pObjTab && pObjTab!=pTab ) continue; if( !IsOrdinaryTable(pTab) ){ #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_vtab *pVTab; int a1; if( !IsVirtual(pTab) ) continue; if( pTab->nCol<=0 ){ const char *zMod = pTab->u.vtab.azArg[0]; if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue; } sqlite3ViewGetColumnNames(pParse, pTab); if( pTab->u.vtab.p==0 ) continue; pVTab = pTab->u.vtab.p->pVtab; if( NEVER(pVTab==0) ) continue; if( NEVER(pVTab->pModule==0) ) continue; if( pVTab->pModule->iVersion<4 ) continue; if( pVTab->pModule->xIntegrity==0 ) continue; sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick); pTab->nTabRef++; sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF); a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v); integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, a1); #endif continue; } if( isQuick || HasRowid(pTab) ){ pPk = 0; r2 = 0; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); r2 = sqlite3GetTempRange(pParse, pPk->nKeyCol); sqlite3VdbeAddOp3(v, OP_Null, 1, r2, r2+pPk->nKeyCol-1); } sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, 1, 0, &iDataCur, &iIdxCur); /* reg[7] counts the number of entries in the table. ** reg[8+i] counts the number of entries in the i-th index */ sqlite3VdbeAddOp2(v, OP_Integer, 0, 7); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */ } assert( pParse->nMem>=8+j ); assert( sqlite3NoTempsInRange(pParse,1,7+j) ); sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); /* Fetch the right-most column from the table. This will cause ** the entire record header to be parsed and sanity checked. It ** will also prepopulate the cursor column cache that is used ** by the OP_IsType code, so it is a required step. */ assert( !IsVirtual(pTab) ); if( HasRowid(pTab) ){ mxCol = -1; for(j=0; jnCol; j++){ if( (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)==0 ) mxCol++; } if( mxCol==pTab->iPKey ) mxCol--; }else{ /* COLFLAG_VIRTUAL columns are not included in the WITHOUT ROWID ** PK index column-count, so there is no need to account for them ** in this case. */ mxCol = sqlite3PrimaryKeyIndex(pTab)->nColumn-1; } if( mxCol>=0 ){ sqlite3VdbeAddOp3(v, OP_Column, iDataCur, mxCol, 3); sqlite3VdbeTypeofColumn(v, 3); } if( !isQuick ){ if( pPk ){ /* Verify WITHOUT ROWID keys are in ascending order */ int a1; char *zErr; a1 = sqlite3VdbeAddOp4Int(v, OP_IdxGT, iDataCur, 0,r2,pPk->nKeyCol); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_IsNull, r2); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "row not in PRIMARY KEY order for %s", pTab->zName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, a1); sqlite3VdbeJumpHere(v, a1+1); for(j=0; jnKeyCol; j++){ sqlite3ExprCodeLoadIndexColumn(pParse, pPk, iDataCur, j, r2+j); } } } /* Verify datatypes for all columns: ** ** (1) NOT NULL columns may not contain a NULL ** (2) Datatype must be exact for non-ANY columns in STRICT tables ** (3) Datatype for TEXT columns in non-STRICT tables must be ** NULL, TEXT, or BLOB. ** (4) Datatype for numeric columns in non-STRICT tables must not ** be a TEXT value that can be losslessly converted to numeric. */ bStrict = (pTab->tabFlags & TF_Strict)!=0; for(j=0; jnCol; j++){ char *zErr; Column *pCol = pTab->aCol + j; /* The column to be checked */ int labelError; /* Jump here to report an error */ int labelOk; /* Jump here if all looks ok */ int p1, p3, p4; /* Operands to the OP_IsType opcode */ int doTypeCheck; /* Check datatypes (besides NOT NULL) */ if( j==pTab->iPKey ) continue; if( bStrict ){ doTypeCheck = pCol->eCType>COLTYPE_ANY; }else{ doTypeCheck = pCol->affinity>SQLITE_AFF_BLOB; } if( pCol->notNull==0 && !doTypeCheck ) continue; /* Compute the operands that will be needed for OP_IsType */ p4 = SQLITE_NULL; if( pCol->colFlags & COLFLAG_VIRTUAL ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); p1 = -1; p3 = 3; }else{ if( pCol->iDflt ){ sqlite3_value *pDfltValue = 0; sqlite3ValueFromExpr(db, sqlite3ColumnExpr(pTab,pCol), ENC(db), pCol->affinity, &pDfltValue); if( pDfltValue ){ p4 = sqlite3_value_type(pDfltValue); sqlite3ValueFree(pDfltValue); } } p1 = iDataCur; if( !HasRowid(pTab) ){ testcase( j!=sqlite3TableColumnToStorage(pTab, j) ); p3 = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), j); }else{ p3 = sqlite3TableColumnToStorage(pTab,j); testcase( p3!=j); } } labelError = sqlite3VdbeMakeLabel(pParse); labelOk = sqlite3VdbeMakeLabel(pParse); if( pCol->notNull ){ /* (1) NOT NULL columns may not contain a NULL */ int jmp3; int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4); VdbeCoverage(v); if( p1<0 ){ sqlite3VdbeChangeP5(v, 0x0f); /* INT, REAL, TEXT, or BLOB */ jmp3 = jmp2; }else{ sqlite3VdbeChangeP5(v, 0x0d); /* INT, TEXT, or BLOB */ /* OP_IsType does not detect NaN values in the database file ** which should be treated as a NULL. So if the header type ** is REAL, we have to load the actual data using OP_Column ** to reliably determine if the value is a NULL. */ sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3); jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk); VdbeCoverage(v); } zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, pCol->zCnName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); if( doTypeCheck ){ sqlite3VdbeGoto(v, labelError); sqlite3VdbeJumpHere(v, jmp2); sqlite3VdbeJumpHere(v, jmp3); }else{ /* VDBE byte code will fall thru */ } } if( bStrict && doTypeCheck ){ /* (2) Datatype must be exact for non-ANY columns in STRICT tables*/ static unsigned char aStdTypeMask[] = { 0x1f, /* ANY */ 0x18, /* BLOB */ 0x11, /* INT */ 0x11, /* INTEGER */ 0x13, /* REAL */ 0x14 /* TEXT */ }; sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4); assert( pCol->eCType>=1 && pCol->eCType<=sizeof(aStdTypeMask) ); sqlite3VdbeChangeP5(v, aStdTypeMask[pCol->eCType-1]); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "non-%s value in %s.%s", sqlite3StdType[pCol->eCType-1], pTab->zName, pTab->aCol[j].zCnName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); }else if( !bStrict && pCol->affinity==SQLITE_AFF_TEXT ){ /* (3) Datatype for TEXT columns in non-STRICT tables must be ** NULL, TEXT, or BLOB. */ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4); sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */ VdbeCoverage(v); zErr = sqlite3MPrintf(db, "NUMERIC value in %s.%s", pTab->zName, pTab->aCol[j].zCnName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); }else if( !bStrict && pCol->affinity>=SQLITE_AFF_NUMERIC ){ /* (4) Datatype for numeric columns in non-STRICT tables must not ** be a TEXT value that can be converted to numeric. */ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4); sqlite3VdbeChangeP5(v, 0x1b); /* NULL, INT, FLOAT, or BLOB */ VdbeCoverage(v); if( p1>=0 ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); } sqlite3VdbeAddOp4(v, OP_Affinity, 3, 1, 0, "C", P4_STATIC); sqlite3VdbeAddOp4Int(v, OP_IsType, -1, labelOk, 3, p4); sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */ VdbeCoverage(v); zErr = sqlite3MPrintf(db, "TEXT value in %s.%s", pTab->zName, pTab->aCol[j].zCnName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); } sqlite3VdbeResolveLabel(v, labelError); integrityCheckResultRow(v); sqlite3VdbeResolveLabel(v, labelOk); } /* Verify CHECK constraints */ if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0); if( db->mallocFailed==0 ){ int addrCkFault = sqlite3VdbeMakeLabel(pParse); int addrCkOk = sqlite3VdbeMakeLabel(pParse); char *zErr; int k; pParse->iSelfTab = iDataCur + 1; for(k=pCheck->nExpr-1; k>0; k--){ sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0); } sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, SQLITE_JUMPIFNULL); sqlite3VdbeResolveLabel(v, addrCkFault); pParse->iSelfTab = 0; zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s", pTab->zName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); integrityCheckResultRow(v); sqlite3VdbeResolveLabel(v, addrCkOk); } sqlite3ExprListDelete(db, pCheck); } if( !isQuick ){ /* Omit the remaining tests for quick_check */ /* Validate index entries for the current row */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2, jmp3, jmp4, jmp5, label6; int kk; int ckUniq = sqlite3VdbeMakeLabel(pParse); if( pPk==pIdx ) continue; r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, pPrior, r1); pPrior = pIdx; sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */ /* Verify that an index entry exists for the current table row */ jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, pIdx->nColumn); VdbeCoverage(v); sqlite3VdbeLoadString(v, 3, "row "); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); sqlite3VdbeLoadString(v, 4, " missing from index "); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); jmp4 = integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, jmp2); /* The OP_IdxRowid opcode is an optimized version of OP_Column ** that extracts the rowid off the end of the index record. ** But it only works correctly if index record does not have ** any extra bytes at the end. Verify that this is the case. */ if( HasRowid(pTab) ){ int jmp7; sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur+j, 3); jmp7 = sqlite3VdbeAddOp3(v, OP_Eq, 3, 0, r1+pIdx->nColumn-1); VdbeCoverageNeverNull(v); sqlite3VdbeLoadString(v, 3, "rowid not at end-of-record for row "); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); sqlite3VdbeLoadString(v, 4, " of index "); sqlite3VdbeGoto(v, jmp5-1); sqlite3VdbeJumpHere(v, jmp7); } /* Any indexed columns with non-BINARY collations must still hold ** the exact same text value as the table. */ label6 = 0; for(kk=0; kknKeyCol; kk++){ if( pIdx->azColl[kk]==sqlite3StrBINARY ) continue; if( label6==0 ) label6 = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur+j, kk, 3); sqlite3VdbeAddOp3(v, OP_Ne, 3, label6, r1+kk); VdbeCoverage(v); } if( label6 ){ int jmp6 = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeResolveLabel(v, label6); sqlite3VdbeLoadString(v, 3, "row "); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); sqlite3VdbeLoadString(v, 4, " values differ from index "); sqlite3VdbeGoto(v, jmp5-1); sqlite3VdbeJumpHere(v, jmp6); } /* For UNIQUE indexes, verify that only one entry exists with the ** current key. The entry is unique if (1) any column is NULL ** or (2) the next entry has a different key */ if( IsUniqueIndex(pIdx) ){ int uniqOk = sqlite3VdbeMakeLabel(pParse); int jmp6; for(kk=0; kknKeyCol; kk++){ int iCol = pIdx->aiColumn[kk]; assert( iCol!=XN_ROWID && iColnCol ); if( iCol>=0 && pTab->aCol[iCol].notNull ) continue; sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); VdbeCoverage(v); } jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); sqlite3VdbeGoto(v, uniqOk); sqlite3VdbeJumpHere(v, jmp6); sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, pIdx->nKeyCol); VdbeCoverage(v); sqlite3VdbeLoadString(v, 3, "non-unique entry in index "); sqlite3VdbeGoto(v, jmp5); sqlite3VdbeResolveLabel(v, uniqOk); } sqlite3VdbeJumpHere(v, jmp4); sqlite3ResolvePartIdxLabel(pParse, jmp3); } } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); if( !isQuick ){ sqlite3VdbeLoadString(v, 2, "wrong # of entries in index "); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ if( pPk==pIdx ) continue; sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3); addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); sqlite3VdbeLoadString(v, 4, pIdx->zName); sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3); integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, addr); } if( pPk ){ sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol); } } } } { static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { { OP_AddImm, 1, 0, 0}, /* 0 */ { OP_IfNotZero, 1, 4, 0}, /* 1 */ { OP_String8, 0, 3, 0}, /* 2 */ { OP_ResultRow, 3, 1, 0}, /* 3 */ { OP_Halt, 0, 0, 0}, /* 4 */ { OP_String8, 0, 3, 0}, /* 5 */ { OP_Goto, 0, 3, 0}, /* 6 */ }; VdbeOp *aOp; aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); if( aOp ){ aOp[0].p2 = 1-mxErr; aOp[2].p4type = P4_STATIC; aOp[2].p4.z = "ok"; aOp[5].p4type = P4_STATIC; aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT); } sqlite3VdbeChangeP3(v, 0, sqlite3VdbeCurrentAddr(v)-2); } } break; #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #ifndef SQLITE_OMIT_UTF16 /* ** PRAGMA encoding ** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be" ** ** In its first form, this pragma returns the encoding of the main ** database. If the database is not initialized, it is initialized now. ** ** The second form of this pragma is a no-op if the main database file ** has not already been initialized. In this case it sets the default ** encoding that will be used for the main database file if a new file ** is created. If an existing main database file is opened, then the ** default text encoding for the existing database is used. ** ** In all cases new databases created using the ATTACH command are ** created to use the same default text encoding as the main database. If ** the main database has not been initialized and/or created when ATTACH ** is executed, this is done before the ATTACH operation. ** ** In the second form this pragma sets the text encoding to be used in ** new database files created using this database handle. It is only ** useful if invoked immediately after the main database i */ case PragTyp_ENCODING: { static const struct EncName { char *zName; u8 enc; } encnames[] = { { "UTF8", SQLITE_UTF8 }, { "UTF-8", SQLITE_UTF8 }, /* Must be element [1] */ { "UTF-16le", SQLITE_UTF16LE }, /* Must be element [2] */ { "UTF-16be", SQLITE_UTF16BE }, /* Must be element [3] */ { "UTF16le", SQLITE_UTF16LE }, { "UTF16be", SQLITE_UTF16BE }, { "UTF-16", 0 }, /* SQLITE_UTF16NATIVE */ { "UTF16", 0 }, /* SQLITE_UTF16NATIVE */ { 0, 0 } }; const struct EncName *pEnc; if( !zRight ){ /* "PRAGMA encoding" */ if( sqlite3ReadSchema(pParse) ) goto pragma_out; assert( encnames[SQLITE_UTF8].enc==SQLITE_UTF8 ); assert( encnames[SQLITE_UTF16LE].enc==SQLITE_UTF16LE ); assert( encnames[SQLITE_UTF16BE].enc==SQLITE_UTF16BE ); returnSingleText(v, encnames[ENC(pParse->db)].zName); }else{ /* "PRAGMA encoding = XXX" */ /* Only change the value of sqlite.enc if the database handle is not ** initialized. If the main database exists, the new sqlite.enc value ** will be overwritten when the schema is next loaded. If it does not ** already exists, it will be created to use the new encoding value. */ if( (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){ for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ u8 enc = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; SCHEMA_ENC(db) = enc; sqlite3SetTextEncoding(db, enc); break; } } if( !pEnc->zName ){ sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight); } } } } break; #endif /* SQLITE_OMIT_UTF16 */ #ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS /* ** PRAGMA [schema.]schema_version ** PRAGMA [schema.]schema_version = ** ** PRAGMA [schema.]user_version ** PRAGMA [schema.]user_version = ** ** PRAGMA [schema.]freelist_count ** ** PRAGMA [schema.]data_version ** ** PRAGMA [schema.]application_id ** PRAGMA [schema.]application_id = ** ** The pragma's schema_version and user_version are used to set or get ** the value of the schema-version and user-version, respectively. Both ** the schema-version and the user-version are 32-bit signed integers ** stored in the database header. ** ** The schema-cookie is usually only manipulated internally by SQLite. It ** is incremented by SQLite whenever the database schema is modified (by ** creating or dropping a table or index). The schema version is used by ** SQLite each time a query is executed to ensure that the internal cache ** of the schema used when compiling the SQL query matches the schema of ** the database against which the compiled query is actually executed. ** Subverting this mechanism by using "PRAGMA schema_version" to modify ** the schema-version is potentially dangerous and may lead to program ** crashes or database corruption. Use with caution! ** ** The user-version is not used internally by SQLite. It may be used by ** applications for any purpose. */ case PragTyp_HEADER_VALUE: { int iCookie = pPragma->iArg; /* Which cookie to read or write */ sqlite3VdbeUsesBtree(v, iDb); if( zRight && (pPragma->mPragFlg & PragFlg_ReadOnly)==0 ){ /* Write the specified cookie value */ static const VdbeOpList setCookie[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ { OP_SetCookie, 0, 0, 0}, /* 1 */ }; VdbeOp *aOp; sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie)); aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0); if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; aOp[0].p1 = iDb; aOp[1].p1 = iDb; aOp[1].p2 = iCookie; aOp[1].p3 = sqlite3Atoi(zRight); aOp[1].p5 = 1; if( iCookie==BTREE_SCHEMA_VERSION && (db->flags & SQLITE_Defensive)!=0 ){ /* Do not allow the use of PRAGMA schema_version=VALUE in defensive ** mode. Change the OP_SetCookie opcode into a no-op. */ aOp[1].opcode = OP_Noop; } }else{ /* Read the specified cookie value */ static const VdbeOpList readCookie[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, 0}, /* 1 */ { OP_ResultRow, 1, 1, 0} }; VdbeOp *aOp; sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(readCookie)); aOp = sqlite3VdbeAddOpList(v, ArraySize(readCookie),readCookie,0); if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; aOp[0].p1 = iDb; aOp[1].p1 = iDb; aOp[1].p3 = iCookie; sqlite3VdbeReusable(v); } } break; #endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* ** PRAGMA compile_options ** ** Return the names of all compile-time options used in this build, ** one option per row. */ case PragTyp_COMPILE_OPTIONS: { int i = 0; const char *zOpt; pParse->nMem = 1; while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){ sqlite3VdbeLoadString(v, 1, zOpt); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); } sqlite3VdbeReusable(v); } break; #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ #ifndef SQLITE_OMIT_WAL /* ** PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate ** ** Checkpoint the database. */ case PragTyp_WAL_CHECKPOINT: { int iBt = (pId2->z?iDb:SQLITE_MAX_DB); int eMode = SQLITE_CHECKPOINT_PASSIVE; if( zRight ){ if( sqlite3StrICmp(zRight, "full")==0 ){ eMode = SQLITE_CHECKPOINT_FULL; }else if( sqlite3StrICmp(zRight, "restart")==0 ){ eMode = SQLITE_CHECKPOINT_RESTART; }else if( sqlite3StrICmp(zRight, "truncate")==0 ){ eMode = SQLITE_CHECKPOINT_TRUNCATE; } } pParse->nMem = 3; sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } break; /* ** PRAGMA wal_autocheckpoint ** PRAGMA wal_autocheckpoint = N ** ** Configure a database connection to automatically checkpoint a database ** after accumulating N frames in the log. Or query for the current value ** of N. */ case PragTyp_WAL_AUTOCHECKPOINT: { if( zRight ){ sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight)); } returnSingleInt(v, db->xWalCallback==sqlite3WalDefaultHook ? SQLITE_PTR_TO_INT(db->pWalArg) : 0); } break; #endif /* ** PRAGMA shrink_memory ** ** IMPLEMENTATION-OF: R-23445-46109 This pragma causes the database ** connection on which it is invoked to free up as much memory as it ** can, by calling sqlite3_db_release_memory(). */ case PragTyp_SHRINK_MEMORY: { sqlite3_db_release_memory(db); break; } /* ** PRAGMA optimize ** PRAGMA optimize(MASK) ** PRAGMA schema.optimize ** PRAGMA schema.optimize(MASK) ** ** Attempt to optimize the database. All schemas are optimized in the first ** two forms, and only the specified schema is optimized in the latter two. ** ** The details of optimizations performed by this pragma are expected ** to change and improve over time. Applications should anticipate that ** this pragma will perform new optimizations in future releases. ** ** The optional argument is a bitmask of optimizations to perform: ** ** 0x0001 Debugging mode. Do not actually perform any optimizations ** but instead return one line of text for each optimization ** that would have been done. Off by default. ** ** 0x0002 Run ANALYZE on tables that might benefit. On by default. ** See below for additional information. ** ** 0x0004 (Not yet implemented) Record usage and performance ** information from the current session in the ** database file so that it will be available to "optimize" ** pragmas run by future database connections. ** ** 0x0008 (Not yet implemented) Create indexes that might have ** been helpful to recent queries ** ** The default MASK is and always shall be 0xfffe. 0xfffe means perform all ** of the optimizations listed above except Debug Mode, including new ** optimizations that have not yet been invented. If new optimizations are ** ever added that should be off by default, those off-by-default ** optimizations will have bitmasks of 0x10000 or larger. ** ** DETERMINATION OF WHEN TO RUN ANALYZE ** ** In the current implementation, a table is analyzed if only if all of ** the following are true: ** ** (1) MASK bit 0x02 is set. ** ** (2) The query planner used sqlite_stat1-style statistics for one or ** more indexes of the table at some point during the lifetime of ** the current connection. ** ** (3) One or more indexes of the table are currently unanalyzed OR ** the number of rows in the table has increased by 25 times or more ** since the last time ANALYZE was run. ** ** The rules for when tables are analyzed are likely to change in ** future releases. */ case PragTyp_OPTIMIZE: { int iDbLast; /* Loop termination point for the schema loop */ int iTabCur; /* Cursor for a table whose size needs checking */ HashElem *k; /* Loop over tables of a schema */ Schema *pSchema; /* The current schema */ Table *pTab; /* A table in the schema */ Index *pIdx; /* An index of the table */ LogEst szThreshold; /* Size threshold above which reanalysis needed */ char *zSubSql; /* SQL statement for the OP_SqlExec opcode */ u32 opMask; /* Mask of operations to perform */ if( zRight ){ opMask = (u32)sqlite3Atoi(zRight); if( (opMask & 0x02)==0 ) break; }else{ opMask = 0xfffe; } iTabCur = pParse->nTab++; for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){ if( iDb==1 ) continue; sqlite3CodeVerifySchema(pParse, iDb); pSchema = db->aDb[iDb].pSchema; for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ pTab = (Table*)sqliteHashData(k); /* If table pTab has not been used in a way that would benefit from ** having analysis statistics during the current session, then skip it. ** This also has the effect of skipping virtual tables and views */ if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue; /* Reanalyze if the table is 25 times larger than the last analysis */ szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 ); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( !pIdx->hasStat1 ){ szThreshold = 0; /* Always analyze if any index lacks statistics */ break; } } if( szThreshold ){ sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold); VdbeCoverage(v); } zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"", db->aDb[iDb].zDbSName, pTab->zName); if( opMask & 0x01 ){ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC); sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1); }else{ sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC); } } } sqlite3VdbeAddOp0(v, OP_Expire); break; } /* ** PRAGMA busy_timeout ** PRAGMA busy_timeout = N ** ** Call sqlite3_busy_timeout(db, N). Return the current timeout value ** if one is set. If no busy handler or a different busy handler is set ** then 0 is returned. Setting the busy_timeout to 0 or negative ** disables the timeout. */ /*case PragTyp_BUSY_TIMEOUT*/ default: { assert( pPragma->ePragTyp==PragTyp_BUSY_TIMEOUT ); if( zRight ){ sqlite3_busy_timeout(db, sqlite3Atoi(zRight)); } returnSingleInt(v, db->busyTimeout); break; } /* ** PRAGMA soft_heap_limit ** PRAGMA soft_heap_limit = N ** ** IMPLEMENTATION-OF: R-26343-45930 This pragma invokes the ** sqlite3_soft_heap_limit64() interface with the argument N, if N is ** specified and is a non-negative integer. ** IMPLEMENTATION-OF: R-64451-07163 The soft_heap_limit pragma always ** returns the same integer that would be returned by the ** sqlite3_soft_heap_limit64(-1) C-language function. */ case PragTyp_SOFT_HEAP_LIMIT: { sqlite3_int64 N; if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ sqlite3_soft_heap_limit64(N); } returnSingleInt(v, sqlite3_soft_heap_limit64(-1)); break; } /* ** PRAGMA hard_heap_limit ** PRAGMA hard_heap_limit = N ** ** Invoke sqlite3_hard_heap_limit64() to query or set the hard heap ** limit. The hard heap limit can be activated or lowered by this ** pragma, but not raised or deactivated. Only the ** sqlite3_hard_heap_limit64() C-language API can raise or deactivate ** the hard heap limit. This allows an application to set a heap limit ** constraint that cannot be relaxed by an untrusted SQL script. */ case PragTyp_HARD_HEAP_LIMIT: { sqlite3_int64 N; if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ sqlite3_int64 iPrior = sqlite3_hard_heap_limit64(-1); if( N>0 && (iPrior==0 || iPrior>N) ) sqlite3_hard_heap_limit64(N); } returnSingleInt(v, sqlite3_hard_heap_limit64(-1)); break; } /* ** PRAGMA threads ** PRAGMA threads = N ** ** Configure the maximum number of worker threads. Return the new ** maximum, which might be less than requested. */ case PragTyp_THREADS: { sqlite3_int64 N; if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK && N>=0 ){ sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff)); } returnSingleInt(v, sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1)); break; } /* ** PRAGMA analysis_limit ** PRAGMA analysis_limit = N ** ** Configure the maximum number of rows that ANALYZE will examine ** in each index that it looks at. Return the new limit. */ case PragTyp_ANALYSIS_LIMIT: { sqlite3_int64 N; if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK /* IMP: R-40975-20399 */ && N>=0 ){ db->nAnalysisLimit = (int)(N&0x7fffffff); } returnSingleInt(v, db->nAnalysisLimit); /* IMP: R-57594-65522 */ break; } #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Report the current state of file logs for all databases */ case PragTyp_LOCK_STATUS: { static const char *const azLockName[] = { "unlocked", "shared", "reserved", "pending", "exclusive" }; int i; pParse->nMem = 2; for(i=0; inDb; i++){ Btree *pBt; const char *zState = "unknown"; int j; if( db->aDb[i].zDbSName==0 ) continue; pBt = db->aDb[i].pBt; if( pBt==0 || sqlite3BtreePager(pBt)==0 ){ zState = "closed"; }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0, SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){ zState = azLockName[j]; } sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); } break; } #endif #if defined(SQLITE_ENABLE_CEROD) case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){ if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ sqlite3_activate_cerod(&zRight[6]); } } break; #endif } /* End of the PRAGMA switch */ /* The following block is a no-op unless SQLITE_DEBUG is defined. Its only ** purpose is to execute assert() statements to verify that if the ** PragFlg_NoColumns1 flag is set and the caller specified an argument ** to the PRAGMA, the implementation has not added any OP_ResultRow ** instructions to the VM. */ if( (pPragma->mPragFlg & PragFlg_NoColumns1) && zRight ){ sqlite3VdbeVerifyNoResultRow(v); } pragma_out: sqlite3DbFree(db, zLeft); sqlite3DbFree(db, zRight); } #ifndef SQLITE_OMIT_VIRTUALTABLE /***************************************************************************** ** Implementation of an eponymous virtual table that runs a pragma. ** */ typedef struct PragmaVtab PragmaVtab; typedef struct PragmaVtabCursor PragmaVtabCursor; struct PragmaVtab { sqlite3_vtab base; /* Base class. Must be first */ sqlite3 *db; /* The database connection to which it belongs */ const PragmaName *pName; /* Name of the pragma */ u8 nHidden; /* Number of hidden columns */ u8 iHidden; /* Index of the first hidden column */ }; struct PragmaVtabCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ sqlite3_stmt *pPragma; /* The pragma statement to run */ sqlite_int64 iRowid; /* Current rowid */ char *azArg[2]; /* Value of the argument and schema */ }; /* ** Pragma virtual table module xConnect method. */ static int pragmaVtabConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ const PragmaName *pPragma = (const PragmaName*)pAux; PragmaVtab *pTab = 0; int rc; int i, j; char cSep = '('; StrAccum acc; char zBuf[200]; UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); sqlite3_str_appendall(&acc, "CREATE TABLE x"); for(i=0, j=pPragma->iPragCName; inPragCName; i++, j++){ sqlite3_str_appendf(&acc, "%c\"%s\"", cSep, pragCName[j]); cSep = ','; } if( i==0 ){ sqlite3_str_appendf(&acc, "(\"%s\"", pPragma->zName); i++; } j = 0; if( pPragma->mPragFlg & PragFlg_Result1 ){ sqlite3_str_appendall(&acc, ",arg HIDDEN"); j++; } if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){ sqlite3_str_appendall(&acc, ",schema HIDDEN"); j++; } sqlite3_str_append(&acc, ")", 1); sqlite3StrAccumFinish(&acc); assert( strlen(zBuf) < sizeof(zBuf)-1 ); rc = sqlite3_declare_vtab(db, zBuf); if( rc==SQLITE_OK ){ pTab = (PragmaVtab*)sqlite3_malloc(sizeof(PragmaVtab)); if( pTab==0 ){ rc = SQLITE_NOMEM; }else{ memset(pTab, 0, sizeof(PragmaVtab)); pTab->pName = pPragma; pTab->db = db; pTab->iHidden = i; pTab->nHidden = j; } }else{ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } *ppVtab = (sqlite3_vtab*)pTab; return rc; } /* ** Pragma virtual table module xDisconnect method. */ static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){ PragmaVtab *pTab = (PragmaVtab*)pVtab; sqlite3_free(pTab); return SQLITE_OK; } /* Figure out the best index to use to search a pragma virtual table. ** ** There are not really any index choices. But we want to encourage the ** query planner to give == constraints on as many hidden parameters as ** possible, and especially on the first hidden parameter. So return a ** high cost if hidden parameters are unconstrained. */ static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ PragmaVtab *pTab = (PragmaVtab*)tab; const struct sqlite3_index_constraint *pConstraint; int i, j; int seen[2]; pIdxInfo->estimatedCost = (double)1; if( pTab->nHidden==0 ){ return SQLITE_OK; } pConstraint = pIdxInfo->aConstraint; seen[0] = 0; seen[1] = 0; for(i=0; inConstraint; i++, pConstraint++){ if( pConstraint->usable==0 ) continue; if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; if( pConstraint->iColumn < pTab->iHidden ) continue; j = pConstraint->iColumn - pTab->iHidden; assert( j < 2 ); seen[j] = i+1; } if( seen[0]==0 ){ pIdxInfo->estimatedCost = (double)2147483647; pIdxInfo->estimatedRows = 2147483647; return SQLITE_OK; } j = seen[0]-1; pIdxInfo->aConstraintUsage[j].argvIndex = 1; pIdxInfo->aConstraintUsage[j].omit = 1; if( seen[1]==0 ) return SQLITE_OK; pIdxInfo->estimatedCost = (double)20; pIdxInfo->estimatedRows = 20; j = seen[1]-1; pIdxInfo->aConstraintUsage[j].argvIndex = 2; pIdxInfo->aConstraintUsage[j].omit = 1; return SQLITE_OK; } /* Create a new cursor for the pragma virtual table */ static int pragmaVtabOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){ PragmaVtabCursor *pCsr; pCsr = (PragmaVtabCursor*)sqlite3_malloc(sizeof(*pCsr)); if( pCsr==0 ) return SQLITE_NOMEM; memset(pCsr, 0, sizeof(PragmaVtabCursor)); pCsr->base.pVtab = pVtab; *ppCursor = &pCsr->base; return SQLITE_OK; } /* Clear all content from pragma virtual table cursor. */ static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){ int i; sqlite3_finalize(pCsr->pPragma); pCsr->pPragma = 0; for(i=0; iazArg); i++){ sqlite3_free(pCsr->azArg[i]); pCsr->azArg[i] = 0; } } /* Close a pragma virtual table cursor */ static int pragmaVtabClose(sqlite3_vtab_cursor *cur){ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)cur; pragmaVtabCursorClear(pCsr); sqlite3_free(pCsr); return SQLITE_OK; } /* Advance the pragma virtual table cursor to the next row */ static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; int rc = SQLITE_OK; /* Increment the xRowid value */ pCsr->iRowid++; assert( pCsr->pPragma ); if( SQLITE_ROW!=sqlite3_step(pCsr->pPragma) ){ rc = sqlite3_finalize(pCsr->pPragma); pCsr->pPragma = 0; pragmaVtabCursorClear(pCsr); } return rc; } /* ** Pragma virtual table module xFilter method. */ static int pragmaVtabFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab); int rc; int i, j; StrAccum acc; char *zSql; UNUSED_PARAMETER(idxNum); UNUSED_PARAMETER(idxStr); pragmaVtabCursorClear(pCsr); j = (pTab->pName->mPragFlg & PragFlg_Result1)!=0 ? 0 : 1; for(i=0; iazArg) ); assert( pCsr->azArg[j]==0 ); if( zText ){ pCsr->azArg[j] = sqlite3_mprintf("%s", zText); if( pCsr->azArg[j]==0 ){ return SQLITE_NOMEM; } } } sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]); sqlite3_str_appendall(&acc, "PRAGMA "); if( pCsr->azArg[1] ){ sqlite3_str_appendf(&acc, "%Q.", pCsr->azArg[1]); } sqlite3_str_appendall(&acc, pTab->pName->zName); if( pCsr->azArg[0] ){ sqlite3_str_appendf(&acc, "=%Q", pCsr->azArg[0]); } zSql = sqlite3StrAccumFinish(&acc); if( zSql==0 ) return SQLITE_NOMEM; rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pPragma, 0); sqlite3_free(zSql); if( rc!=SQLITE_OK ){ pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); return rc; } return pragmaVtabNext(pVtabCursor); } /* ** Pragma virtual table module xEof method. */ static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; return (pCsr->pPragma==0); } /* The xColumn method simply returns the corresponding column from ** the PRAGMA. */ static int pragmaVtabColumn( sqlite3_vtab_cursor *pVtabCursor, sqlite3_context *ctx, int i ){ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab); if( iiHidden ){ sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pPragma, i)); }else{ sqlite3_result_text(ctx, pCsr->azArg[i-pTab->iHidden],-1,SQLITE_TRANSIENT); } return SQLITE_OK; } /* ** Pragma virtual table module xRowid method. */ static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; *p = pCsr->iRowid; return SQLITE_OK; } /* The pragma virtual table object */ static const sqlite3_module pragmaVtabModule = { 0, /* iVersion */ 0, /* xCreate - create a table */ pragmaVtabConnect, /* xConnect - connect to an existing table */ pragmaVtabBestIndex, /* xBestIndex - Determine search strategy */ pragmaVtabDisconnect, /* xDisconnect - Disconnect from a table */ 0, /* xDestroy - Drop a table */ pragmaVtabOpen, /* xOpen - open a cursor */ pragmaVtabClose, /* xClose - close a cursor */ pragmaVtabFilter, /* xFilter - configure scan constraints */ pragmaVtabNext, /* xNext - advance a cursor */ pragmaVtabEof, /* xEof */ pragmaVtabColumn, /* xColumn - read data */ pragmaVtabRowid, /* xRowid - read data */ 0, /* xUpdate - write data */ 0, /* xBegin - begin transaction */ 0, /* xSync - sync transaction */ 0, /* xCommit - commit transaction */ 0, /* xRollback - rollback transaction */ 0, /* xFindFunction - function overloading */ 0, /* xRename - rename the table */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ 0 /* xIntegrity */ }; /* ** Check to see if zTabName is really the name of a pragma. If it is, ** then register an eponymous virtual table for that pragma and return ** a pointer to the Module object for the new virtual table. */ SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName){ const PragmaName *pName; assert( sqlite3_strnicmp(zName, "pragma_", 7)==0 ); pName = pragmaLocate(zName+7); if( pName==0 ) return 0; if( (pName->mPragFlg & (PragFlg_Result0|PragFlg_Result1))==0 ) return 0; assert( sqlite3HashFind(&db->aModule, zName)==0 ); return sqlite3VtabCreateModule(db, zName, &pragmaVtabModule, (void*)pName, 0); } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_PRAGMA */ /************** End of pragma.c **********************************************/ /************** Begin file prepare.c *****************************************/ /* ** 2005 May 25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_prepare() ** interface, and routines that contribute to loading the database schema ** from disk. */ /* #include "sqliteInt.h" */ /* ** Fill the InitData structure with an error message that indicates ** that the database is corrupt. */ static void corruptSchema( InitData *pData, /* Initialization context */ char **azObj, /* Type and name of object being parsed */ const char *zExtra /* Error information */ ){ sqlite3 *db = pData->db; if( db->mallocFailed ){ pData->rc = SQLITE_NOMEM_BKPT; }else if( pData->pzErrMsg[0]!=0 ){ /* A error message has already been generated. Do not overwrite it */ }else if( pData->mInitFlags & (INITFLAG_AlterMask) ){ static const char *azAlterType[] = { "rename", "drop column", "add column" }; *pData->pzErrMsg = sqlite3MPrintf(db, "error in %s %s after %s: %s", azObj[0], azObj[1], azAlterType[(pData->mInitFlags&INITFLAG_AlterMask)-1], zExtra ); pData->rc = SQLITE_ERROR; }else if( db->flags & SQLITE_WriteSchema ){ pData->rc = SQLITE_CORRUPT_BKPT; }else{ char *z; const char *zObj = azObj[1] ? azObj[1] : "?"; z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); *pData->pzErrMsg = z; pData->rc = SQLITE_CORRUPT_BKPT; } } /* ** Check to see if any sibling index (another index on the same table) ** of pIndex has the same root page number, and if it does, return true. ** This would indicate a corrupt schema. */ SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index *pIndex){ Index *p; for(p=pIndex->pTable->pIndex; p; p=p->pNext){ if( p->tnum==pIndex->tnum && p!=pIndex ) return 1; } return 0; } /* forward declaration */ static int sqlite3Prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pReprepare, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ); /* ** This is the callback routine for the code that initializes the ** database. See sqlite3Init() below for additional information. ** This routine is also called from the OP_ParseSchema opcode of the VDBE. ** ** Each callback contains the following information: ** ** argv[0] = type of object: "table", "index", "trigger", or "view". ** argv[1] = name of thing being created ** argv[2] = associated table if an index or trigger ** argv[3] = root page number for table or index. 0 for trigger or view. ** argv[4] = SQL text for the CREATE statement. ** */ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ InitData *pData = (InitData*)pInit; sqlite3 *db = pData->db; int iDb = pData->iDb; assert( argc==5 ); UNUSED_PARAMETER2(NotUsed, argc); assert( sqlite3_mutex_held(db->mutex) ); db->mDbFlags |= DBFLAG_EncodingFixed; if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ pData->nInitRow++; if( db->mallocFailed ){ corruptSchema(pData, argv, 0); return 1; } assert( iDb>=0 && iDbnDb ); if( argv[3]==0 ){ corruptSchema(pData, argv, 0); }else if( argv[4] && 'c'==sqlite3UpperToLower[(unsigned char)argv[4][0]] && 'r'==sqlite3UpperToLower[(unsigned char)argv[4][1]] ){ /* Call the parser to process a CREATE TABLE, INDEX or VIEW. ** But because db->init.busy is set to 1, no VDBE code is generated ** or executed. All the parser does is build the internal data ** structures that describe the table, index, or view. ** ** No other valid SQL statement, other than the variable CREATE statements, ** can begin with the letters "C" and "R". Thus, it is not possible run ** any other kind of statement while parsing the schema, even a corrupt ** schema. */ int rc; u8 saved_iDb = db->init.iDb; sqlite3_stmt *pStmt; TESTONLY(int rcp); /* Return code from sqlite3_prepare() */ assert( db->init.busy ); db->init.iDb = iDb; if( sqlite3GetUInt32(argv[3], &db->init.newTnum)==0 || (db->init.newTnum>pData->mxPage && pData->mxPage>0) ){ if( sqlite3Config.bExtraSchemaChecks ){ corruptSchema(pData, argv, "invalid rootpage"); } } db->init.orphanTrigger = 0; db->init.azInit = (const char**)argv; pStmt = 0; TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */ if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); }else{ if( rc > pData->rc ) pData->rc = rc; if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){ corruptSchema(pData, argv, sqlite3_errmsg(db)); } } } db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ sqlite3_finalize(pStmt); }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){ corruptSchema(pData, argv, 0); }else{ /* If the SQL column is blank it means this is an index that ** was created to be the PRIMARY KEY or to fulfill a UNIQUE ** constraint for a CREATE TABLE. The index should have already ** been created when we processed the CREATE TABLE. All we have ** to do here is record the root page number for that index. */ Index *pIndex; pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName); if( pIndex==0 ){ corruptSchema(pData, argv, "orphan index"); }else if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0 || pIndex->tnum<2 || pIndex->tnum>pData->mxPage || sqlite3IndexHasDuplicateRootPage(pIndex) ){ if( sqlite3Config.bExtraSchemaChecks ){ corruptSchema(pData, argv, "invalid rootpage"); } } } return 0; } /* ** Attempt to read the database schema and initialize internal ** data structures for a single database file. The index of the ** database file is given by iDb. iDb==0 is used for the main ** database. iDb==1 should never be used. iDb>=2 is used for ** auxiliary databases. Return one of the SQLITE_ error codes to ** indicate success or failure. */ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){ int rc; int i; #ifndef SQLITE_OMIT_DEPRECATED int size; #endif Db *pDb; char const *azArg[6]; int meta[5]; InitData initData; const char *zSchemaTabName; int openedTransaction = 0; int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed); assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ); assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pSchema ); assert( sqlite3_mutex_held(db->mutex) ); assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); db->init.busy = 1; /* Construct the in-memory representation schema tables (sqlite_schema or ** sqlite_temp_schema) by invoking the parser directly. The appropriate ** table name will be inserted automatically by the parser so we can just ** use the abbreviation "x" here. The parser will also automatically tag ** the schema table as read-only. */ azArg[0] = "table"; azArg[1] = zSchemaTabName = SCHEMA_TABLE(iDb); azArg[2] = azArg[1]; azArg[3] = "1"; azArg[4] = "CREATE TABLE x(type text,name text,tbl_name text," "rootpage int,sql text)"; azArg[5] = 0; initData.db = db; initData.iDb = iDb; initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; initData.mInitFlags = mFlags; initData.nInitRow = 0; initData.mxPage = 0; sqlite3InitCallback(&initData, 5, (char **)azArg, 0); db->mDbFlags &= mask; if( initData.rc ){ rc = initData.rc; goto error_out; } /* Create a cursor to hold the database open */ pDb = &db->aDb[iDb]; if( pDb->pBt==0 ){ assert( iDb==1 ); DbSetProperty(db, 1, DB_SchemaLoaded); rc = SQLITE_OK; goto error_out; } /* If there is not already a read-only (or read-write) transaction opened ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed before this function returns. */ sqlite3BtreeEnter(pDb->pBt); if( sqlite3BtreeTxnState(pDb->pBt)==SQLITE_TXN_NONE ){ rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0); if( rc!=SQLITE_OK ){ sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc)); goto initone_error_out; } openedTransaction = 1; } /* Get the database meta information. ** ** Meta values are as follows: ** meta[0] Schema cookie. Changes with each schema change. ** meta[1] File format of schema layer. ** meta[2] Size of the page cache. ** meta[3] Largest rootpage (auto/incr_vacuum mode) ** meta[4] Db text encoding. 1:UTF-8 2:UTF-16LE 3:UTF-16BE ** meta[5] User version ** meta[6] Incremental vacuum mode ** meta[7] unused ** meta[8] unused ** meta[9] unused ** ** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to ** the possible values of meta[4]. */ for(i=0; ipBt, i+1, (u32 *)&meta[i]); } if( (db->flags & SQLITE_ResetDatabase)!=0 ){ memset(meta, 0, sizeof(meta)); } pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1]; /* If opening a non-empty database, check the text encoding. For the ** main database, set sqlite3.enc to the encoding of the main database. ** For an attached db, it is an error if the encoding is not the same ** as sqlite3.enc. */ if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */ if( iDb==0 && (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){ u8 encoding; #ifndef SQLITE_OMIT_UTF16 /* If opening the main database, set ENC(db). */ encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3; if( encoding==0 ) encoding = SQLITE_UTF8; #else encoding = SQLITE_UTF8; #endif if( db->nVdbeActive>0 && encoding!=ENC(db) && (db->mDbFlags & DBFLAG_Vacuum)==0 ){ rc = SQLITE_LOCKED; goto initone_error_out; }else{ sqlite3SetTextEncoding(db, encoding); } }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){ sqlite3SetString(pzErrMsg, db, "attached databases must use the same" " text encoding as main database"); rc = SQLITE_ERROR; goto initone_error_out; } } } pDb->pSchema->enc = ENC(db); if( pDb->pSchema->cache_size==0 ){ #ifndef SQLITE_OMIT_DEPRECATED size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]); if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; } pDb->pSchema->cache_size = size; #else pDb->pSchema->cache_size = SQLITE_DEFAULT_CACHE_SIZE; #endif sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } /* ** file_format==1 Version 3.0.0. ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants */ pDb->pSchema->file_format = (u8)meta[BTREE_FILE_FORMAT-1]; if( pDb->pSchema->file_format==0 ){ pDb->pSchema->file_format = 1; } if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){ sqlite3SetString(pzErrMsg, db, "unsupported file format"); rc = SQLITE_ERROR; goto initone_error_out; } /* Ticket #2804: When we open a database in the newer file format, ** clear the legacy_file_format pragma flag so that a VACUUM will ** not downgrade the database and thus invalidate any descending ** indices that the user might have created. */ if( iDb==0 && meta[BTREE_FILE_FORMAT-1]>=4 ){ db->flags &= ~(u64)SQLITE_LegacyFileFmt; } /* Read the schema information out of the schema tables */ assert( db->init.busy ); initData.mxPage = sqlite3BtreeLastPage(pDb->pBt); { char *zSql; zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\".%s ORDER BY rowid", db->aDb[iDb].zDbSName, zSchemaTabName); #ifndef SQLITE_OMIT_AUTHORIZATION { sqlite3_xauth xAuth; xAuth = db->xAuth; db->xAuth = 0; #endif rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; } #endif if( rc==SQLITE_OK ) rc = initData.rc; sqlite3DbFree(db, zSql); #ifndef SQLITE_OMIT_ANALYZE if( rc==SQLITE_OK ){ sqlite3AnalysisLoad(db, iDb); } #endif } assert( pDb == &(db->aDb[iDb]) ); if( db->mallocFailed ){ rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); pDb = &db->aDb[iDb]; }else if( rc==SQLITE_OK || ((db->flags&SQLITE_NoSchemaError) && rc!=SQLITE_NOMEM)){ /* Hack: If the SQLITE_NoSchemaError flag is set, then consider ** the schema loaded, even if errors (other than OOM) occurred. In ** this situation the current sqlite3_prepare() operation will fail, ** but the following one will attempt to compile the supplied statement ** against whatever subset of the schema was loaded before the error ** occurred. ** ** The primary purpose of this is to allow access to the sqlite_schema ** table even when its contents have been corrupted. */ DbSetProperty(db, iDb, DB_SchemaLoaded); rc = SQLITE_OK; } /* Jump here for an error that occurs after successfully allocating ** curMain and calling sqlite3BtreeEnter(). For an error that occurs ** before that point, jump to error_out. */ initone_error_out: if( openedTransaction ){ sqlite3BtreeCommit(pDb->pBt); } sqlite3BtreeLeave(pDb->pBt); error_out: if( rc ){ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); } sqlite3ResetOneSchema(db, iDb); } db->init.busy = 0; return rc; } /* ** Initialize all database files - the main database file, the file ** used to store temporary tables, and any additional database files ** created using ATTACH statements. Return a success code. If an ** error occurs, write an error message into *pzErrMsg. ** ** After a database is initialized, the DB_SchemaLoaded bit is set ** bit is set in the flags field of the Db structure. */ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int i, rc; int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange); assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); assert( db->init.busy==0 ); ENC(db) = SCHEMA_ENC(db); assert( db->nDb>0 ); /* Do the main schema first */ if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, 0, pzErrMsg, 0); if( rc ) return rc; } /* All other schemas after the main schema. The "temp" schema must be last */ for(i=db->nDb-1; i>0; i--){ assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) ); if( !DbHasProperty(db, i, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, i, pzErrMsg, 0); if( rc ) return rc; } } if( commit_internal ){ sqlite3CommitInternalChanges(db); } return SQLITE_OK; } /* ** This routine is a no-op if the database schema is already initialized. ** Otherwise, the schema is loaded. An error code is returned. */ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){ int rc = SQLITE_OK; sqlite3 *db = pParse->db; assert( sqlite3_mutex_held(db->mutex) ); if( !db->init.busy ){ rc = sqlite3Init(db, &pParse->zErrMsg); if( rc!=SQLITE_OK ){ pParse->rc = rc; pParse->nErr++; }else if( db->noSharedCache ){ db->mDbFlags |= DBFLAG_SchemaKnownOk; } } return rc; } /* ** Check schema cookies in all databases. If any cookie is out ** of date set pParse->rc to SQLITE_SCHEMA. If all schema cookies ** make no changes to pParse->rc. */ static void schemaIsValid(Parse *pParse){ sqlite3 *db = pParse->db; int iDb; int rc; int cookie; assert( pParse->checkSchema ); assert( sqlite3_mutex_held(db->mutex) ); for(iDb=0; iDbnDb; iDb++){ int openedTransaction = 0; /* True if a transaction is opened */ Btree *pBt = db->aDb[iDb].pBt; /* Btree database to read cookie from */ if( pBt==0 ) continue; /* If there is not already a read-only (or read-write) transaction opened ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed immediately after reading the meta-value. */ if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_NONE ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); pParse->rc = SQLITE_NOMEM; } if( rc!=SQLITE_OK ) return; openedTransaction = 1; } /* Read the schema cookie from the database. If it does not match the ** value stored as part of the in-memory schema representation, ** set Parse.rc to SQLITE_SCHEMA. */ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){ if( DbHasProperty(db, iDb, DB_SchemaLoaded) ) pParse->rc = SQLITE_SCHEMA; sqlite3ResetOneSchema(db, iDb); } /* Close the transaction, if one was opened. */ if( openedTransaction ){ sqlite3BtreeCommit(pBt); } } } /* ** Convert a schema pointer into the iDb index that indicates ** which database file in db->aDb[] the schema refers to. ** ** If the same database is attached more than once, the first ** attached database is returned. */ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ int i = -32768; /* If pSchema is NULL, then return -32768. This happens when code in ** expr.c is trying to resolve a reference to a transient table (i.e. one ** created by a sub-select). In this case the return value of this ** function should never be used. ** ** We return -32768 instead of the more usual -1 simply because using ** -32768 as the incorrect index into db->aDb[] is much ** more likely to cause a segfault than -1 (of course there are assert() ** statements too, but it never hurts to play the odds) and ** -32768 will still fit into a 16-bit signed integer. */ assert( sqlite3_mutex_held(db->mutex) ); if( pSchema ){ for(i=0; 1; i++){ assert( inDb ); if( db->aDb[i].pSchema==pSchema ){ break; } } assert( i>=0 && inDb ); } return i; } /* ** Free all memory allocations in the pParse object */ SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){ sqlite3 *db = pParse->db; assert( db!=0 ); assert( db->pParse==pParse ); assert( pParse->nested==0 ); #ifndef SQLITE_OMIT_SHARED_CACHE if( pParse->aTableLock ) sqlite3DbNNFreeNN(db, pParse->aTableLock); #endif while( pParse->pCleanup ){ ParseCleanup *pCleanup = pParse->pCleanup; pParse->pCleanup = pCleanup->pNext; pCleanup->xCleanup(db, pCleanup->pPtr); sqlite3DbNNFreeNN(db, pCleanup); } if( pParse->aLabel ) sqlite3DbNNFreeNN(db, pParse->aLabel); if( pParse->pConstExpr ){ sqlite3ExprListDelete(db, pParse->pConstExpr); } assert( db->lookaside.bDisable >= pParse->disableLookaside ); db->lookaside.bDisable -= pParse->disableLookaside; db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue; assert( pParse->db->pParse==pParse ); db->pParse = pParse->pOuterParse; } /* ** Add a new cleanup operation to a Parser. The cleanup should happen when ** the parser object is destroyed. But, beware: the cleanup might happen ** immediately. ** ** Use this mechanism for uncommon cleanups. There is a higher setup ** cost for this mechanism (an extra malloc), so it should not be used ** for common cleanups that happen on most calls. But for less ** common cleanups, we save a single NULL-pointer comparison in ** sqlite3ParseObjectReset(), which reduces the total CPU cycle count. ** ** If a memory allocation error occurs, then the cleanup happens immediately. ** When either SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the ** pParse->earlyCleanup flag is set in that case. Calling code show verify ** that test cases exist for which this happens, to guard against possible ** use-after-free errors following an OOM. The preferred way to do this is ** to immediately follow the call to this routine with: ** ** testcase( pParse->earlyCleanup ); ** ** This routine returns a copy of its pPtr input (the third parameter) ** except if an early cleanup occurs, in which case it returns NULL. So ** another way to check for early cleanup is to check the return value. ** Or, stop using the pPtr parameter with this call and use only its ** return value thereafter. Something like this: ** ** pObj = sqlite3ParserAddCleanup(pParse, destructor, pObj); */ SQLITE_PRIVATE void *sqlite3ParserAddCleanup( Parse *pParse, /* Destroy when this Parser finishes */ void (*xCleanup)(sqlite3*,void*), /* The cleanup routine */ void *pPtr /* Pointer to object to be cleaned up */ ){ ParseCleanup *pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup)); if( pCleanup ){ pCleanup->pNext = pParse->pCleanup; pParse->pCleanup = pCleanup; pCleanup->pPtr = pPtr; pCleanup->xCleanup = xCleanup; }else{ xCleanup(pParse->db, pPtr); pPtr = 0; #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) pParse->earlyCleanup = 1; #endif } return pPtr; } /* ** Turn bulk memory into a valid Parse object and link that Parse object ** into database connection db. ** ** Call sqlite3ParseObjectReset() to undo this operation. ** ** Caution: Do not confuse this routine with sqlite3ParseObjectInit() which ** is generated by Lemon. */ SQLITE_PRIVATE void sqlite3ParseObjectInit(Parse *pParse, sqlite3 *db){ memset(PARSE_HDR(pParse), 0, PARSE_HDR_SZ); memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); assert( db->pParse!=pParse ); pParse->pOuterParse = db->pParse; db->pParse = pParse; pParse->db = db; if( db->mallocFailed ) sqlite3ErrorMsg(pParse, "out of memory"); } /* ** Maximum number of times that we will try again to prepare a statement ** that returns SQLITE_ERROR_RETRY. */ #ifndef SQLITE_MAX_PREPARE_RETRY # define SQLITE_MAX_PREPARE_RETRY 25 #endif /* ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. */ static int sqlite3Prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pReprepare, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc = SQLITE_OK; /* Result code */ int i; /* Loop counter */ Parse sParse; /* Parsing context */ /* sqlite3ParseObjectInit(&sParse, db); // inlined for performance */ memset(PARSE_HDR(&sParse), 0, PARSE_HDR_SZ); memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ); sParse.pOuterParse = db->pParse; db->pParse = &sParse; sParse.db = db; if( pReprepare ){ sParse.pReprepare = pReprepare; sParse.explain = sqlite3_stmt_isexplain((sqlite3_stmt*)pReprepare); }else{ assert( sParse.pReprepare==0 ); } assert( ppStmt && *ppStmt==0 ); if( db->mallocFailed ){ sqlite3ErrorMsg(&sParse, "out of memory"); db->errCode = rc = SQLITE_NOMEM; goto end_prepare; } assert( sqlite3_mutex_held(db->mutex) ); /* For a long-term use prepared statement avoid the use of ** lookaside memory. */ if( prepFlags & SQLITE_PREPARE_PERSISTENT ){ sParse.disableLookaside++; DisableLookaside; } sParse.prepFlags = prepFlags & 0xff; /* Check to verify that it is possible to get a read lock on all ** database schemas. The inability to get a read lock indicates that ** some other database connection is holding a write-lock, which in ** turn means that the other connection has made uncommitted changes ** to the schema. ** ** Were we to proceed and prepare the statement against the uncommitted ** schema changes and if those schema changes are subsequently rolled ** back and different changes are made in their place, then when this ** prepared statement goes to run the schema cookie would fail to detect ** the schema change. Disaster would follow. ** ** This thread is currently holding mutexes on all Btrees (because ** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it ** is not possible for another thread to start a new schema change ** while this routine is running. Hence, we do not need to hold ** locks on the schema, we just need to make sure nobody else is ** holding them. ** ** Note that setting READ_UNCOMMITTED overrides most lock detection, ** but it does *not* override schema lock detection, so this all still ** works even if READ_UNCOMMITTED is set. */ if( !db->noSharedCache ){ for(i=0; inDb; i++) { Btree *pBt = db->aDb[i].pBt; if( pBt ){ assert( sqlite3BtreeHoldsMutex(pBt) ); rc = sqlite3BtreeSchemaLocked(pBt); if( rc ){ const char *zDb = db->aDb[i].zDbSName; sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); testcase( db->flags & SQLITE_ReadUncommit ); goto end_prepare; } } } } #ifndef SQLITE_OMIT_VIRTUALTABLE if( db->pDisconnect ) sqlite3VtabUnlockList(db); #endif if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){ char *zSqlCopy; int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; testcase( nBytes==mxLen ); testcase( nBytes==mxLen+1 ); if( nBytes>mxLen ){ sqlite3ErrorWithMsg(db, SQLITE_TOOBIG, "statement too long"); rc = sqlite3ApiExit(db, SQLITE_TOOBIG); goto end_prepare; } zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes); if( zSqlCopy ){ sqlite3RunParser(&sParse, zSqlCopy); sParse.zTail = &zSql[sParse.zTail-zSqlCopy]; sqlite3DbFree(db, zSqlCopy); }else{ sParse.zTail = &zSql[nBytes]; } }else{ sqlite3RunParser(&sParse, zSql); } assert( 0==sParse.nQueryLoop ); if( pzTail ){ *pzTail = sParse.zTail; } if( db->init.busy==0 ){ sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags); } if( db->mallocFailed ){ sParse.rc = SQLITE_NOMEM_BKPT; sParse.checkSchema = 0; } if( sParse.rc!=SQLITE_OK && sParse.rc!=SQLITE_DONE ){ if( sParse.checkSchema && db->init.busy==0 ){ schemaIsValid(&sParse); } if( sParse.pVdbe ){ sqlite3VdbeFinalize(sParse.pVdbe); } assert( 0==(*ppStmt) ); rc = sParse.rc; if( sParse.zErrMsg ){ sqlite3ErrorWithMsg(db, rc, "%s", sParse.zErrMsg); sqlite3DbFree(db, sParse.zErrMsg); }else{ sqlite3Error(db, rc); } }else{ assert( sParse.zErrMsg==0 ); *ppStmt = (sqlite3_stmt*)sParse.pVdbe; rc = SQLITE_OK; sqlite3ErrorClear(db); } /* Delete any TriggerPrg structures allocated while parsing this statement. */ while( sParse.pTriggerPrg ){ TriggerPrg *pT = sParse.pTriggerPrg; sParse.pTriggerPrg = pT->pNext; sqlite3DbFree(db, pT); } end_prepare: sqlite3ParseObjectReset(&sParse); return rc; } static int sqlite3LockAndPrepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pOld, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; int cnt = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; #endif *ppStmt = 0; if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); do{ /* Make multiple attempts to compile the SQL, until it either succeeds ** or encounters a permanent error. A schema problem after one schema ** reset is considered a permanent error. */ rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); assert( rc==SQLITE_OK || *ppStmt==0 ); if( rc==SQLITE_OK || db->mallocFailed ) break; }while( (rc==SQLITE_ERROR_RETRY && (cnt++)errMask)==rc ); db->busyHandler.nBusy = 0; sqlite3_mutex_leave(db->mutex); assert( rc==SQLITE_OK || (*ppStmt)==0 ); return rc; } /* ** Rerun the compilation of a statement after a schema change. ** ** If the statement is successfully recompiled, return SQLITE_OK. Otherwise, ** if the statement cannot be recompiled because another connection has ** locked the sqlite3_schema table, return SQLITE_LOCKED. If any other error ** occurs, return SQLITE_SCHEMA. */ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){ int rc; sqlite3_stmt *pNew; const char *zSql; sqlite3 *db; u8 prepFlags; assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) ); zSql = sqlite3_sql((sqlite3_stmt *)p); assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */ db = sqlite3VdbeDb(p); assert( sqlite3_mutex_held(db->mutex) ); prepFlags = sqlite3VdbePrepareFlags(p); rc = sqlite3LockAndPrepare(db, zSql, -1, prepFlags, p, &pNew, 0); if( rc ){ if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); } assert( pNew==0 ); return rc; }else{ assert( pNew!=0 ); } sqlite3VdbeSwap((Vdbe*)pNew, p); sqlite3TransferBindings(pNew, (sqlite3_stmt*)p); sqlite3VdbeResetStepResult((Vdbe*)pNew); sqlite3VdbeFinalize((Vdbe*)pNew); return SQLITE_OK; } /* ** Two versions of the official API. Legacy and new use. In the legacy ** version, the original SQL text is not saved in the prepared statement ** and so if a schema change occurs, SQLITE_SCHEMA is returned by ** sqlite3_step(). In the new version, the original SQL text is retained ** and the statement is automatically recompiled if an schema change ** occurs. */ SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,0,ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } SQLITE_API int sqlite3_prepare_v2( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; /* EVIDENCE-OF: R-37923-12173 The sqlite3_prepare_v2() interface works ** exactly the same as sqlite3_prepare_v3() with a zero prepFlags ** parameter. ** ** Proof in that the 5th parameter to sqlite3LockAndPrepare is 0 */ rc = sqlite3LockAndPrepare(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,0, ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); return rc; } SQLITE_API int sqlite3_prepare_v3( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; /* EVIDENCE-OF: R-56861-42673 sqlite3_prepare_v3() differs from ** sqlite3_prepare_v2() only in having the extra prepFlags parameter, ** which is a bit array consisting of zero or more of the ** SQLITE_PREPARE_* flags. ** ** Proof by comparison to the implementation of sqlite3_prepare_v2() ** directly above. */ rc = sqlite3LockAndPrepare(db,zSql,nBytes, SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK), 0,ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); return rc; } #ifndef SQLITE_OMIT_UTF16 /* ** Compile the UTF-16 encoded SQL statement zSql into a statement handle. */ static int sqlite3Prepare16( sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const void **pzTail /* OUT: End of parsed string */ ){ /* This function currently works by first transforming the UTF-16 ** encoded string to UTF-8, then invoking sqlite3_prepare(). The ** tricky bit is figuring out the pointer to return in *pzTail. */ char *zSql8; const char *zTail8 = 0; int rc = SQLITE_OK; #ifdef SQLITE_ENABLE_API_ARMOR if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; #endif *ppStmt = 0; if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ return SQLITE_MISUSE_BKPT; } if( nBytes>=0 ){ int sz; const char *z = (const char*)zSql; for(sz=0; szmutex); zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE); if( zSql8 ){ rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8); } if( zTail8 && pzTail ){ /* If sqlite3_prepare returns a tail pointer, we calculate the ** equivalent pointer into the UTF-16 string by counting the unicode ** characters between zSql8 and zTail8, and then returning a pointer ** the same number of characters into the UTF-16 string. */ int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8)); *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed); } sqlite3DbFree(db, zSql8); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Two versions of the official API. Legacy and new use. In the legacy ** version, the original SQL text is not saved in the prepared statement ** and so if a schema change occurs, SQLITE_SCHEMA is returned by ** sqlite3_step(). In the new version, the original SQL text is retained ** and the statement is automatically recompiled if an schema change ** occurs. */ SQLITE_API int sqlite3_prepare16( sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const void **pzTail /* OUT: End of parsed string */ ){ int rc; rc = sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } SQLITE_API int sqlite3_prepare16_v2( sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const void **pzTail /* OUT: End of parsed string */ ){ int rc; rc = sqlite3Prepare16(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } SQLITE_API int sqlite3_prepare16_v3( sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const void **pzTail /* OUT: End of parsed string */ ){ int rc; rc = sqlite3Prepare16(db,zSql,nBytes, SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK), ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } #endif /* SQLITE_OMIT_UTF16 */ /************** End of prepare.c *********************************************/ /************** Begin file select.c ******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. */ /* #include "sqliteInt.h" */ /* ** An instance of the following object is used to record information about ** how to process the DISTINCT keyword, to simplify passing that information ** into the selectInnerLoop() routine. */ typedef struct DistinctCtx DistinctCtx; struct DistinctCtx { u8 isTnct; /* 0: Not distinct. 1: DISTICT 2: DISTINCT and ORDER BY */ u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ int tabTnct; /* Ephemeral table used for DISTINCT processing */ int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ }; /* ** An instance of the following object is used to record information about ** the ORDER BY (or GROUP BY) clause of query is being coded. ** ** The aDefer[] array is used by the sorter-references optimization. For ** example, assuming there is no index that can be used for the ORDER BY, ** for the query: ** ** SELECT a, bigblob FROM t1 ORDER BY a LIMIT 10; ** ** it may be more efficient to add just the "a" values to the sorter, and ** retrieve the associated "bigblob" values directly from table t1 as the ** 10 smallest "a" values are extracted from the sorter. ** ** When the sorter-reference optimization is used, there is one entry in the ** aDefer[] array for each database table that may be read as values are ** extracted from the sorter. */ typedef struct SortCtx SortCtx; struct SortCtx { ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */ int nOBSat; /* Number of ORDER BY terms satisfied by indices */ int iECursor; /* Cursor number for the sorter */ int regReturn; /* Register holding block-output return address */ int labelBkOut; /* Start label for the block-output subroutine */ int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ int labelDone; /* Jump here when done, ex: LIMIT reached */ int labelOBLopt; /* Jump here when sorter is full */ u8 sortFlags; /* Zero or more SORTFLAG_* bits */ #ifdef SQLITE_ENABLE_SORTER_REFERENCES u8 nDefer; /* Number of valid entries in aDefer[] */ struct DeferredCsr { Table *pTab; /* Table definition */ int iCsr; /* Cursor number for table */ int nKey; /* Number of PK columns for table pTab (>=1) */ } aDefer[4]; #endif struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrPush; /* First instruction to push data into sorter */ int addrPushEnd; /* Last instruction that pushes data into sorter */ #endif }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure. Deallocate the structure ** itself depending on the value of bFree ** ** If bFree==1, call sqlite3DbFree() on the p object. ** If bFree==0, Leave the first Select object unfreed */ static void clearSelect(sqlite3 *db, Select *p, int bFree){ assert( db!=0 ); while( p ){ Select *pPrior = p->pPrior; sqlite3ExprListDelete(db, p->pEList); sqlite3SrcListDelete(db, p->pSrc); sqlite3ExprDelete(db, p->pWhere); sqlite3ExprListDelete(db, p->pGroupBy); sqlite3ExprDelete(db, p->pHaving); sqlite3ExprListDelete(db, p->pOrderBy); sqlite3ExprDelete(db, p->pLimit); if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith); #ifndef SQLITE_OMIT_WINDOWFUNC if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){ sqlite3WindowListDelete(db, p->pWinDefn); } while( p->pWin ){ assert( p->pWin->ppThis==&p->pWin ); sqlite3WindowUnlinkFromSelect(p->pWin); } #endif if( bFree ) sqlite3DbNNFreeNN(db, p); p = pPrior; bFree = 1; } } /* ** Initialize a SelectDest structure. */ SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){ pDest->eDest = (u8)eDest; pDest->iSDParm = iParm; pDest->iSDParm2 = 0; pDest->zAffSdst = 0; pDest->iSdst = 0; pDest->nSdst = 0; } /* ** Allocate a new Select structure and return a pointer to that ** structure. */ SQLITE_PRIVATE Select *sqlite3SelectNew( Parse *pParse, /* Parsing context */ ExprList *pEList, /* which columns to include in the result */ SrcList *pSrc, /* the FROM clause -- which tables to scan */ Expr *pWhere, /* the WHERE clause */ ExprList *pGroupBy, /* the GROUP BY clause */ Expr *pHaving, /* the HAVING clause */ ExprList *pOrderBy, /* the ORDER BY clause */ u32 selFlags, /* Flag parameters, such as SF_Distinct */ Expr *pLimit /* LIMIT value. NULL means not used */ ){ Select *pNew, *pAllocated; Select standin; pAllocated = pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) ); if( pNew==0 ){ assert( pParse->db->mallocFailed ); pNew = &standin; } if( pEList==0 ){ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0)); } pNew->pEList = pEList; pNew->op = TK_SELECT; pNew->selFlags = selFlags; pNew->iLimit = 0; pNew->iOffset = 0; pNew->selId = ++pParse->nSelect; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = 0; if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc)); pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; pNew->pHaving = pHaving; pNew->pOrderBy = pOrderBy; pNew->pPrior = 0; pNew->pNext = 0; pNew->pLimit = pLimit; pNew->pWith = 0; #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = 0; #endif if( pParse->db->mallocFailed ) { clearSelect(pParse->db, pNew, pNew!=&standin); pAllocated = 0; }else{ assert( pNew->pSrc!=0 || pParse->nErr>0 ); } return pAllocated; } /* ** Delete the given Select structure and all of its substructures. */ SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){ if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1); } SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3 *db, void *p){ if( ALWAYS(p) ) clearSelect(db, (Select*)p, 1); } /* ** Return a pointer to the right-most SELECT statement in a compound. */ static Select *findRightmost(Select *p){ while( p->pNext ) p = p->pNext; return p; } /* ** Given 1 to 3 identifiers preceding the JOIN keyword, determine the ** type of join. Return an integer constant that expresses that type ** in terms of the following bit values: ** ** JT_INNER ** JT_CROSS ** JT_OUTER ** JT_NATURAL ** JT_LEFT ** JT_RIGHT ** ** A full outer join is the combination of JT_LEFT and JT_RIGHT. ** ** If an illegal or unsupported join type is seen, then still return ** a join type, but put an error in the pParse structure. ** ** These are the valid join types: ** ** ** pA pB pC Return Value ** ------- ----- ----- ------------ ** CROSS - - JT_CROSS ** INNER - - JT_INNER ** LEFT - - JT_LEFT|JT_OUTER ** LEFT OUTER - JT_LEFT|JT_OUTER ** RIGHT - - JT_RIGHT|JT_OUTER ** RIGHT OUTER - JT_RIGHT|JT_OUTER ** FULL - - JT_LEFT|JT_RIGHT|JT_OUTER ** FULL OUTER - JT_LEFT|JT_RIGHT|JT_OUTER ** NATURAL INNER - JT_NATURAL|JT_INNER ** NATURAL LEFT - JT_NATURAL|JT_LEFT|JT_OUTER ** NATURAL LEFT OUTER JT_NATURAL|JT_LEFT|JT_OUTER ** NATURAL RIGHT - JT_NATURAL|JT_RIGHT|JT_OUTER ** NATURAL RIGHT OUTER JT_NATURAL|JT_RIGHT|JT_OUTER ** NATURAL FULL - JT_NATURAL|JT_LEFT|JT_RIGHT ** NATURAL FULL OUTER JT_NATRUAL|JT_LEFT|JT_RIGHT ** ** To preserve historical compatibly, SQLite also accepts a variety ** of other non-standard and in many cases nonsensical join types. ** This routine makes as much sense at it can from the nonsense join ** type and returns a result. Examples of accepted nonsense join types ** include but are not limited to: ** ** INNER CROSS JOIN -> same as JOIN ** NATURAL CROSS JOIN -> same as NATURAL JOIN ** OUTER LEFT JOIN -> same as LEFT JOIN ** LEFT NATURAL JOIN -> same as NATURAL LEFT JOIN ** LEFT RIGHT JOIN -> same as FULL JOIN ** RIGHT OUTER FULL JOIN -> same as FULL JOIN ** CROSS CROSS CROSS JOIN -> same as JOIN ** ** The only restrictions on the join type name are: ** ** * "INNER" cannot appear together with "OUTER", "LEFT", "RIGHT", ** or "FULL". ** ** * "CROSS" cannot appear together with "OUTER", "LEFT", "RIGHT, ** or "FULL". ** ** * If "OUTER" is present then there must also be one of ** "LEFT", "RIGHT", or "FULL" */ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){ int jointype = 0; Token *apAll[3]; Token *p; /* 0123456789 123456789 123456789 123 */ static const char zKeyText[] = "naturaleftouterightfullinnercross"; static const struct { u8 i; /* Beginning of keyword text in zKeyText[] */ u8 nChar; /* Length of the keyword in characters */ u8 code; /* Join type mask */ } aKeyword[] = { /* (0) natural */ { 0, 7, JT_NATURAL }, /* (1) left */ { 6, 4, JT_LEFT|JT_OUTER }, /* (2) outer */ { 10, 5, JT_OUTER }, /* (3) right */ { 14, 5, JT_RIGHT|JT_OUTER }, /* (4) full */ { 19, 4, JT_LEFT|JT_RIGHT|JT_OUTER }, /* (5) inner */ { 23, 5, JT_INNER }, /* (6) cross */ { 28, 5, JT_INNER|JT_CROSS }, }; int i, j; apAll[0] = pA; apAll[1] = pB; apAll[2] = pC; for(i=0; i<3 && apAll[i]; i++){ p = apAll[i]; for(j=0; jn==aKeyword[j].nChar && sqlite3StrNICmp((char*)p->z, &zKeyText[aKeyword[j].i], p->n)==0 ){ jointype |= aKeyword[j].code; break; } } testcase( j==0 || j==1 || j==2 || j==3 || j==4 || j==5 || j==6 ); if( j>=ArraySize(aKeyword) ){ jointype |= JT_ERROR; break; } } if( (jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) || (jointype & JT_ERROR)!=0 || (jointype & (JT_OUTER|JT_LEFT|JT_RIGHT))==JT_OUTER ){ const char *zSp1 = " "; const char *zSp2 = " "; if( pB==0 ){ zSp1++; } if( pC==0 ){ zSp2++; } sqlite3ErrorMsg(pParse, "unknown join type: " "%T%s%T%s%T", pA, zSp1, pB, zSp2, pC); jointype = JT_INNER; } return jointype; } /* ** Return the index of a column in a table. Return -1 if the column ** is not contained in the table. */ SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){ int i; u8 h = sqlite3StrIHash(zCol); Column *pCol; for(pCol=pTab->aCol, i=0; inCol; pCol++, i++){ if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i; } return -1; } /* ** Mark a subquery result column as having been used. */ SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){ assert( pItem!=0 ); assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); if( pItem->fg.isNestedFrom ){ ExprList *pResults; assert( pItem->pSelect!=0 ); pResults = pItem->pSelect->pEList; assert( pResults!=0 ); assert( iCol>=0 && iColnExpr ); pResults->a[iCol].fg.bUsed = 1; } } /* ** Search the tables iStart..iEnd (inclusive) in pSrc, looking for a ** table that has a column named zCol. The search is left-to-right. ** The first match found is returned. ** ** When found, set *piTab and *piCol to the table index and column index ** of the matching column and return TRUE. ** ** If not found, return FALSE. */ static int tableAndColumnIndex( SrcList *pSrc, /* Array of tables to search */ int iStart, /* First member of pSrc->a[] to check */ int iEnd, /* Last member of pSrc->a[] to check */ const char *zCol, /* Name of the column we are looking for */ int *piTab, /* Write index of pSrc->a[] here */ int *piCol, /* Write index of pSrc->a[*piTab].pTab->aCol[] here */ int bIgnoreHidden /* Ignore hidden columns */ ){ int i; /* For looping over tables in pSrc */ int iCol; /* Index of column matching zCol */ assert( iEndnSrc ); assert( iStart>=0 ); assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */ for(i=iStart; i<=iEnd; i++){ iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol); if( iCol>=0 && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0) ){ if( piTab ){ sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol); *piTab = i; *piCol = iCol; } return 1; } } return 0; } /* ** Set the EP_OuterON property on all terms of the given expression. ** And set the Expr.w.iJoin to iTable for every term in the ** expression. ** ** The EP_OuterON property is used on terms of an expression to tell ** the OUTER JOIN processing logic that this term is part of the ** join restriction specified in the ON or USING clause and not a part ** of the more general WHERE clause. These terms are moved over to the ** WHERE clause during join processing but we need to remember that they ** originated in the ON or USING clause. ** ** The Expr.w.iJoin tells the WHERE clause processing that the ** expression depends on table w.iJoin even if that table is not ** explicitly mentioned in the expression. That information is needed ** for cases like this: ** ** SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.b AND t1.x=5 ** ** The where clause needs to defer the handling of the t1.x=5 ** term until after the t2 loop of the join. In that way, a ** NULL t2 row will be inserted whenever t1.x!=5. If we do not ** defer the handling of t1.x=5, it will be processed immediately ** after the t1 loop and rows with t1.x!=5 will never appear in ** the output, which is incorrect. */ SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){ assert( joinFlag==EP_OuterON || joinFlag==EP_InnerON ); while( p ){ ExprSetProperty(p, joinFlag); assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(p, EP_NoReduce); p->w.iJoin = iTable; if( p->op==TK_FUNCTION ){ assert( ExprUseXList(p) ); if( p->x.pList ){ int i; for(i=0; ix.pList->nExpr; i++){ sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable, joinFlag); } } } sqlite3SetJoinExpr(p->pLeft, iTable, joinFlag); p = p->pRight; } } /* Undo the work of sqlite3SetJoinExpr(). This is used when a LEFT JOIN ** is simplified into an ordinary JOIN, and when an ON expression is ** "pushed down" into the WHERE clause of a subquery. ** ** Convert every term that is marked with EP_OuterON and w.iJoin==iTable into ** an ordinary term that omits the EP_OuterON mark. Or if iTable<0, then ** just clear every EP_OuterON and EP_InnerON mark from the expression tree. ** ** If nullable is true, that means that Expr p might evaluate to NULL even ** if it is a reference to a NOT NULL column. This can happen, for example, ** if the table that p references is on the left side of a RIGHT JOIN. ** If nullable is true, then take care to not remove the EP_CanBeNull bit. ** See forum thread https://sqlite.org/forum/forumpost/b40696f50145d21c */ static void unsetJoinExpr(Expr *p, int iTable, int nullable){ while( p ){ if( iTable<0 || (ExprHasProperty(p, EP_OuterON) && p->w.iJoin==iTable) ){ ExprClearProperty(p, EP_OuterON|EP_InnerON); if( iTable>=0 ) ExprSetProperty(p, EP_InnerON); } if( p->op==TK_COLUMN && p->iTable==iTable && !nullable ){ ExprClearProperty(p, EP_CanBeNull); } if( p->op==TK_FUNCTION ){ assert( ExprUseXList(p) ); assert( p->pLeft==0 ); if( p->x.pList ){ int i; for(i=0; ix.pList->nExpr; i++){ unsetJoinExpr(p->x.pList->a[i].pExpr, iTable, nullable); } } } unsetJoinExpr(p->pLeft, iTable, nullable); p = p->pRight; } } /* ** This routine processes the join information for a SELECT statement. ** ** * A NATURAL join is converted into a USING join. After that, we ** do not need to be concerned with NATURAL joins and we only have ** think about USING joins. ** ** * ON and USING clauses result in extra terms being added to the ** WHERE clause to enforce the specified constraints. The extra ** WHERE clause terms will be tagged with EP_OuterON or ** EP_InnerON so that we know that they originated in ON/USING. ** ** The terms of a FROM clause are contained in the Select.pSrc structure. ** The left most table is the first entry in Select.pSrc. The right-most ** table is the last entry. The join operator is held in the entry to ** the right. Thus entry 1 contains the join operator for the join between ** entries 0 and 1. Any ON or USING clauses associated with the join are ** also attached to the right entry. ** ** This routine returns the number of errors encountered. */ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ SrcList *pSrc; /* All tables in the FROM clause */ int i, j; /* Loop counters */ SrcItem *pLeft; /* Left table being joined */ SrcItem *pRight; /* Right table being joined */ pSrc = p->pSrc; pLeft = &pSrc->a[0]; pRight = &pLeft[1]; for(i=0; inSrc-1; i++, pRight++, pLeft++){ Table *pRightTab = pRight->pTab; u32 joinType; if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON; /* If this is a NATURAL join, synthesize an appropriate USING clause ** to specify which columns should be joined. */ if( pRight->fg.jointype & JT_NATURAL ){ IdList *pUsing = 0; if( pRight->fg.isUsing || pRight->u3.pOn ){ sqlite3ErrorMsg(pParse, "a NATURAL join may not have " "an ON or USING clause", 0); return 1; } for(j=0; jnCol; j++){ char *zName; /* Name of column in the right table */ if( IsHiddenColumn(&pRightTab->aCol[j]) ) continue; zName = pRightTab->aCol[j].zCnName; if( tableAndColumnIndex(pSrc, 0, i, zName, 0, 0, 1) ){ pUsing = sqlite3IdListAppend(pParse, pUsing, 0); if( pUsing ){ assert( pUsing->nId>0 ); assert( pUsing->a[pUsing->nId-1].zName==0 ); pUsing->a[pUsing->nId-1].zName = sqlite3DbStrDup(pParse->db, zName); } } } if( pUsing ){ pRight->fg.isUsing = 1; pRight->fg.isSynthUsing = 1; pRight->u3.pUsing = pUsing; } if( pParse->nErr ) return 1; } /* Create extra terms on the WHERE clause for each column named ** in the USING clause. Example: If the two tables to be joined are ** A and B and the USING clause names X, Y, and Z, then add this ** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z ** Report an error if any column mentioned in the USING clause is ** not contained in both tables to be joined. */ if( pRight->fg.isUsing ){ IdList *pList = pRight->u3.pUsing; sqlite3 *db = pParse->db; assert( pList!=0 ); for(j=0; jnId; j++){ char *zName; /* Name of the term in the USING clause */ int iLeft; /* Table on the left with matching column name */ int iLeftCol; /* Column number of matching column on the left */ int iRightCol; /* Column number of matching column on the right */ Expr *pE1; /* Reference to the column on the LEFT of the join */ Expr *pE2; /* Reference to the column on the RIGHT of the join */ Expr *pEq; /* Equality constraint. pE1 == pE2 */ zName = pList->a[j].zName; iRightCol = sqlite3ColumnIndex(pRightTab, zName); if( iRightCol<0 || tableAndColumnIndex(pSrc, 0, i, zName, &iLeft, &iLeftCol, pRight->fg.isSynthUsing)==0 ){ sqlite3ErrorMsg(pParse, "cannot join using column %s - column " "not present in both tables", zName); return 1; } pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iLeftCol); sqlite3SrcItemColumnUsed(&pSrc->a[iLeft], iLeftCol); if( (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ /* This branch runs if the query contains one or more RIGHT or FULL ** JOINs. If only a single table on the left side of this join ** contains the zName column, then this branch is a no-op. ** But if there are two or more tables on the left side ** of the join, construct a coalesce() function that gathers all ** such tables. Raise an error if more than one of those references ** to zName is not also within a prior USING clause. ** ** We really ought to raise an error if there are two or more ** non-USING references to zName on the left of an INNER or LEFT ** JOIN. But older versions of SQLite do not do that, so we avoid ** adding a new error so as to not break legacy applications. */ ExprList *pFuncArgs = 0; /* Arguments to the coalesce() */ static const Token tkCoalesce = { "coalesce", 8 }; while( tableAndColumnIndex(pSrc, iLeft+1, i, zName, &iLeft, &iLeftCol, pRight->fg.isSynthUsing)!=0 ){ if( pSrc->a[iLeft].fg.isUsing==0 || sqlite3IdListIndex(pSrc->a[iLeft].u3.pUsing, zName)<0 ){ sqlite3ErrorMsg(pParse, "ambiguous reference to %s in USING()", zName); break; } pFuncArgs = sqlite3ExprListAppend(pParse, pFuncArgs, pE1); pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iLeftCol); sqlite3SrcItemColumnUsed(&pSrc->a[iLeft], iLeftCol); } if( pFuncArgs ){ pFuncArgs = sqlite3ExprListAppend(pParse, pFuncArgs, pE1); pE1 = sqlite3ExprFunction(pParse, pFuncArgs, &tkCoalesce, 0); } } pE2 = sqlite3CreateColumnExpr(db, pSrc, i+1, iRightCol); sqlite3SrcItemColumnUsed(pRight, iRightCol); pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2); assert( pE2!=0 || pEq==0 ); if( pEq ){ ExprSetProperty(pEq, joinType); assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(pEq, EP_NoReduce); pEq->w.iJoin = pE2->iTable; } p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pEq); } } /* Add the ON clause to the end of the WHERE clause, connected by ** an AND operator. */ else if( pRight->u3.pOn ){ sqlite3SetJoinExpr(pRight->u3.pOn, pRight->iCursor, joinType); p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->u3.pOn); pRight->u3.pOn = 0; pRight->fg.isOn = 1; } } return 0; } /* ** An instance of this object holds information (beyond pParse and pSelect) ** needed to load the next result row that is to be added to the sorter. */ typedef struct RowLoadInfo RowLoadInfo; struct RowLoadInfo { int regResult; /* Store results in array of registers here */ u8 ecelFlags; /* Flag argument to ExprCodeExprList() */ #ifdef SQLITE_ENABLE_SORTER_REFERENCES ExprList *pExtra; /* Extra columns needed by sorter refs */ int regExtraResult; /* Where to load the extra columns */ #endif }; /* ** This routine does the work of loading query data into an array of ** registers so that it can be added to the sorter. */ static void innerLoopLoadRow( Parse *pParse, /* Statement under construction */ Select *pSelect, /* The query being coded */ RowLoadInfo *pInfo /* Info needed to complete the row load */ ){ sqlite3ExprCodeExprList(pParse, pSelect->pEList, pInfo->regResult, 0, pInfo->ecelFlags); #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( pInfo->pExtra ){ sqlite3ExprCodeExprList(pParse, pInfo->pExtra, pInfo->regExtraResult, 0, 0); sqlite3ExprListDelete(pParse->db, pInfo->pExtra); } #endif } /* ** Code the OP_MakeRecord instruction that generates the entry to be ** added into the sorter. ** ** Return the register in which the result is stored. */ static int makeSorterRecord( Parse *pParse, SortCtx *pSort, Select *pSelect, int regBase, int nBase ){ int nOBSat = pSort->nOBSat; Vdbe *v = pParse->pVdbe; int regOut = ++pParse->nMem; if( pSort->pDeferredRowLoad ){ innerLoopLoadRow(pParse, pSelect, pSort->pDeferredRowLoad); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regOut); return regOut; } /* ** Generate code that will push the record in registers regData ** through regData+nData-1 onto the sorter. */ static void pushOntoSorter( Parse *pParse, /* Parser context */ SortCtx *pSort, /* Information about the ORDER BY clause */ Select *pSelect, /* The whole SELECT statement */ int regData, /* First register holding data to be sorted */ int regOrigData, /* First register holding data before packing */ int nData, /* Number of elements in the regData data array */ int nPrefixReg /* No. of reg prior to regData available for use */ ){ Vdbe *v = pParse->pVdbe; /* Stmt under construction */ int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter)==0); int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */ int nBase = nExpr + bSeq + nData; /* Fields in sorter record */ int regBase; /* Regs for sorter record */ int regRecord = 0; /* Assembled sorter record */ int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */ int op; /* Opcode to add sorter record to sorter */ int iLimit; /* LIMIT counter */ int iSkip = 0; /* End of the sorter insert loop */ assert( bSeq==0 || bSeq==1 ); /* Three cases: ** (1) The data to be sorted has already been packed into a Record ** by a prior OP_MakeRecord. In this case nData==1 and regData ** will be completely unrelated to regOrigData. ** (2) All output columns are included in the sort record. In that ** case regData==regOrigData. ** (3) Some output columns are omitted from the sort record due to ** the SQLITE_ENABLE_SORTER_REFERENCES optimization, or due to the ** SQLITE_ECEL_OMITREF optimization, or due to the ** SortCtx.pDeferredRowLoad optimization. In any of these cases ** regOrigData is 0 to prevent this routine from trying to copy ** values that might not yet exist. */ assert( nData==1 || regData==regOrigData || regOrigData==0 ); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS pSort->addrPush = sqlite3VdbeCurrentAddr(v); #endif if( nPrefixReg ){ assert( nPrefixReg==nExpr+bSeq ); regBase = regData - nPrefixReg; }else{ regBase = pParse->nMem + 1; pParse->nMem += nBase; } assert( pSelect->iOffset==0 || pSelect->iLimit!=0 ); iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit; pSort->labelDone = sqlite3VdbeMakeLabel(pParse); sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData, SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0)); if( bSeq ){ sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); } if( nPrefixReg==0 && nData>0 ){ sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData); } if( nOBSat>0 ){ int regPrevKey; /* The first nOBSat columns of the previous row */ int addrFirst; /* Address of the OP_IfNot opcode */ int addrJmp; /* Address of the OP_Jump opcode */ VdbeOp *pOp; /* Opcode that opens the sorter */ int nKey; /* Number of sorting key columns, including OP_Sequence */ KeyInfo *pKI; /* Original KeyInfo on the sorter table */ regRecord = makeSorterRecord(pParse, pSort, pSelect, regBase, nBase); regPrevKey = pParse->nMem+1; pParse->nMem += pSort->nOBSat; nKey = nExpr - pSort->nOBSat + bSeq; if( bSeq ){ addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); }else{ addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor); } VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat); pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); if( pParse->db->mallocFailed ) return; pOp->p2 = nKey + nData; pKI = pOp->p4.pKeyInfo; memset(pKI->aSortFlags, 0, pKI->nKeyField); /* Makes OP_Jump testable */ sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); testcase( pKI->nAllField > pKI->nKeyField+2 ); pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat, pKI->nAllField-pKI->nKeyField-1); pOp = 0; /* Ensure pOp not used after sqlite3VdbeAddOp3() */ addrJmp = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); pSort->labelBkOut = sqlite3VdbeMakeLabel(pParse); pSort->regReturn = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); if( iLimit ){ sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone); VdbeCoverage(v); } sqlite3VdbeJumpHere(v, addrFirst); sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat); sqlite3VdbeJumpHere(v, addrJmp); } if( iLimit ){ /* At this point the values for the new sorter entry are stored ** in an array of registers. They need to be composed into a record ** and inserted into the sorter if either (a) there are currently ** less than LIMIT+OFFSET items or (b) the new record is smaller than ** the largest record currently in the sorter. If (b) is true and there ** are already LIMIT+OFFSET items in the sorter, delete the largest ** entry before inserting the new one. This way there are never more ** than LIMIT+OFFSET items in the sorter. ** ** If the new record does not need to be inserted into the sorter, ** jump to the next iteration of the loop. If the pSort->labelOBLopt ** value is not zero, then it is a label of where to jump. Otherwise, ** just bypass the row insert logic. See the header comment on the ** sqlite3WhereOrderByLimitOptLabel() function for additional info. */ int iCsr = pSort->iECursor; sqlite3VdbeAddOp2(v, OP_IfNotZero, iLimit, sqlite3VdbeCurrentAddr(v)+4); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Last, iCsr, 0); iSkip = sqlite3VdbeAddOp4Int(v, OP_IdxLE, iCsr, 0, regBase+nOBSat, nExpr-nOBSat); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_Delete, iCsr); } if( regRecord==0 ){ regRecord = makeSorterRecord(pParse, pSort, pSelect, regBase, nBase); } if( pSort->sortFlags & SORTFLAG_UseSorter ){ op = OP_SorterInsert; }else{ op = OP_IdxInsert; } sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord, regBase+nOBSat, nBase-nOBSat); if( iSkip ){ sqlite3VdbeChangeP2(v, iSkip, pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v)); } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS pSort->addrPushEnd = sqlite3VdbeCurrentAddr(v)-1; #endif } /* ** Add code to implement the OFFSET */ static void codeOffset( Vdbe *v, /* Generate code into this VM */ int iOffset, /* Register holding the offset counter */ int iContinue /* Jump here to skip the current record */ ){ if( iOffset>0 ){ sqlite3VdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1); VdbeCoverage(v); VdbeComment((v, "OFFSET")); } } /* ** Add code that will check to make sure the array of registers starting at ** iMem form a distinct entry. This is used by both "SELECT DISTINCT ..." and ** distinct aggregates ("SELECT count(DISTINCT ) ..."). Three strategies ** are available. Which is used depends on the value of parameter eTnctType, ** as follows: ** ** WHERE_DISTINCT_UNORDERED/WHERE_DISTINCT_NOOP: ** Build an ephemeral table that contains all entries seen before and ** skip entries which have been seen before. ** ** Parameter iTab is the cursor number of an ephemeral table that must ** be opened before the VM code generated by this routine is executed. ** The ephemeral cursor table is queried for a record identical to the ** record formed by the current array of registers. If one is found, ** jump to VM address addrRepeat. Otherwise, insert a new record into ** the ephemeral cursor and proceed. ** ** The returned value in this case is a copy of parameter iTab. ** ** WHERE_DISTINCT_ORDERED: ** In this case rows are being delivered sorted order. The ephemeral ** table is not required. Instead, the current set of values ** is compared against previous row. If they match, the new row ** is not distinct and control jumps to VM address addrRepeat. Otherwise, ** the VM program proceeds with processing the new row. ** ** The returned value in this case is the register number of the first ** in an array of registers used to store the previous result row so that ** it can be compared to the next. The caller must ensure that this ** register is initialized to NULL. (The fixDistinctOpenEph() routine ** will take care of this initialization.) ** ** WHERE_DISTINCT_UNIQUE: ** In this case it has already been determined that the rows are distinct. ** No special action is required. The return value is zero. ** ** Parameter pEList is the list of expressions used to generated the ** contents of each row. It is used by this routine to determine (a) ** how many elements there are in the array of registers and (b) the ** collation sequences that should be used for the comparisons if ** eTnctType is WHERE_DISTINCT_ORDERED. */ static int codeDistinct( Parse *pParse, /* Parsing and code generating context */ int eTnctType, /* WHERE_DISTINCT_* value */ int iTab, /* A sorting index used to test for distinctness */ int addrRepeat, /* Jump to here if not distinct */ ExprList *pEList, /* Expression for each element */ int regElem /* First element */ ){ int iRet = 0; int nResultCol = pEList->nExpr; Vdbe *v = pParse->pVdbe; switch( eTnctType ){ case WHERE_DISTINCT_ORDERED: { int i; int iJump; /* Jump destination */ int regPrev; /* Previous row content */ /* Allocate space for the previous row */ iRet = regPrev = pParse->nMem+1; pParse->nMem += nResultCol; iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; for(i=0; ia[i].pExpr); if( idb->mallocFailed ); sqlite3VdbeAddOp3(v, OP_Copy, regElem, regPrev, nResultCol-1); break; } case WHERE_DISTINCT_UNIQUE: { /* nothing to do */ break; } default: { int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, regElem, nResultCol); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, regElem, nResultCol, r1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, regElem, nResultCol); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, r1); iRet = iTab; break; } } return iRet; } /* ** This routine runs after codeDistinct(). It makes necessary ** adjustments to the OP_OpenEphemeral opcode that the codeDistinct() ** routine made use of. This processing must be done separately since ** sometimes codeDistinct is called before the OP_OpenEphemeral is actually ** laid down. ** ** WHERE_DISTINCT_NOOP: ** WHERE_DISTINCT_UNORDERED: ** ** No adjustments necessary. This function is a no-op. ** ** WHERE_DISTINCT_UNIQUE: ** ** The ephemeral table is not needed. So change the ** OP_OpenEphemeral opcode into an OP_Noop. ** ** WHERE_DISTINCT_ORDERED: ** ** The ephemeral table is not needed. But we do need register ** iVal to be initialized to NULL. So change the OP_OpenEphemeral ** into an OP_Null on the iVal register. */ static void fixDistinctOpenEph( Parse *pParse, /* Parsing and code generating context */ int eTnctType, /* WHERE_DISTINCT_* value */ int iVal, /* Value returned by codeDistinct() */ int iOpenEphAddr /* Address of OP_OpenEphemeral instruction for iTab */ ){ if( pParse->nErr==0 && (eTnctType==WHERE_DISTINCT_UNIQUE || eTnctType==WHERE_DISTINCT_ORDERED) ){ Vdbe *v = pParse->pVdbe; sqlite3VdbeChangeToNoop(v, iOpenEphAddr); if( sqlite3VdbeGetOp(v, iOpenEphAddr+1)->opcode==OP_Explain ){ sqlite3VdbeChangeToNoop(v, iOpenEphAddr+1); } if( eTnctType==WHERE_DISTINCT_ORDERED ){ /* Change the OP_OpenEphemeral to an OP_Null that sets the MEM_Cleared ** bit on the first register of the previous value. This will cause the ** OP_Ne added in codeDistinct() to always fail on the first iteration of ** the loop even if the first row is all NULLs. */ VdbeOp *pOp = sqlite3VdbeGetOp(v, iOpenEphAddr); pOp->opcode = OP_Null; pOp->p1 = 1; pOp->p2 = iVal; } } } #ifdef SQLITE_ENABLE_SORTER_REFERENCES /* ** This function is called as part of inner-loop generation for a SELECT ** statement with an ORDER BY that is not optimized by an index. It ** determines the expressions, if any, that the sorter-reference ** optimization should be used for. The sorter-reference optimization ** is used for SELECT queries like: ** ** SELECT a, bigblob FROM t1 ORDER BY a LIMIT 10 ** ** If the optimization is used for expression "bigblob", then instead of ** storing values read from that column in the sorter records, the PK of ** the row from table t1 is stored instead. Then, as records are extracted from ** the sorter to return to the user, the required value of bigblob is ** retrieved directly from table t1. If the values are very large, this ** can be more efficient than storing them directly in the sorter records. ** ** The ExprList_item.fg.bSorterRef flag is set for each expression in pEList ** for which the sorter-reference optimization should be enabled. ** Additionally, the pSort->aDefer[] array is populated with entries ** for all cursors required to evaluate all selected expressions. Finally. ** output variable (*ppExtra) is set to an expression list containing ** expressions for all extra PK values that should be stored in the ** sorter records. */ static void selectExprDefer( Parse *pParse, /* Leave any error here */ SortCtx *pSort, /* Sorter context */ ExprList *pEList, /* Expressions destined for sorter */ ExprList **ppExtra /* Expressions to append to sorter record */ ){ int i; int nDefer = 0; ExprList *pExtra = 0; for(i=0; inExpr; i++){ struct ExprList_item *pItem = &pEList->a[i]; if( pItem->u.x.iOrderByCol==0 ){ Expr *pExpr = pItem->pExpr; Table *pTab; if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && ALWAYS( ExprUseYTab(pExpr) ) && (pTab = pExpr->y.pTab)!=0 && IsOrdinaryTable(pTab) && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF)!=0 ){ int j; for(j=0; jaDefer[j].iCsr==pExpr->iTable ) break; } if( j==nDefer ){ if( nDefer==ArraySize(pSort->aDefer) ){ continue; }else{ int nKey = 1; int k; Index *pPk = 0; if( !HasRowid(pTab) ){ pPk = sqlite3PrimaryKeyIndex(pTab); nKey = pPk->nKeyCol; } for(k=0; kiTable = pExpr->iTable; assert( ExprUseYTab(pNew) ); pNew->y.pTab = pExpr->y.pTab; pNew->iColumn = pPk ? pPk->aiColumn[k] : -1; pExtra = sqlite3ExprListAppend(pParse, pExtra, pNew); } } pSort->aDefer[nDefer].pTab = pExpr->y.pTab; pSort->aDefer[nDefer].iCsr = pExpr->iTable; pSort->aDefer[nDefer].nKey = nKey; nDefer++; } } pItem->fg.bSorterRef = 1; } } } pSort->nDefer = (u8)nDefer; *ppExtra = pExtra; } #endif /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. ** ** If srcTab is negative, then the p->pEList expressions ** are evaluated in order to get the data for this row. If srcTab is ** zero or more, then data is pulled from srcTab and p->pEList is used only ** to get the number of columns and the collation sequence for each column. */ static void selectInnerLoop( Parse *pParse, /* The parser context */ Select *p, /* The complete select statement being coded */ int srcTab, /* Pull data from this table if non-negative */ SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */ DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */ SelectDest *pDest, /* How to dispose of the results */ int iContinue, /* Jump here to continue with next row */ int iBreak /* Jump here to break out of the inner loop */ ){ Vdbe *v = pParse->pVdbe; int i; int hasDistinct; /* True if the DISTINCT keyword is present */ int eDest = pDest->eDest; /* How to dispose of results */ int iParm = pDest->iSDParm; /* First argument to disposal method */ int nResultCol; /* Number of result columns */ int nPrefixReg = 0; /* Number of extra registers before regResult */ RowLoadInfo sRowLoadInfo; /* Info for deferred row loading */ /* Usually, regResult is the first cell in an array of memory cells ** containing the current result row. In this case regOrig is set to the ** same value. However, if the results are being sent to the sorter, the ** values for any expressions that are also part of the sort-key are omitted ** from this array. In this case regOrig is set to zero. */ int regResult; /* Start of memory holding current results */ int regOrig; /* Start of memory holding full result (or 0) */ assert( v ); assert( p->pEList!=0 ); hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; if( pSort && pSort->pOrderBy==0 ) pSort = 0; if( pSort==0 && !hasDistinct ){ assert( iContinue!=0 ); codeOffset(v, p->iOffset, iContinue); } /* Pull the requested columns. */ nResultCol = p->pEList->nExpr; if( pDest->iSdst==0 ){ if( pSort ){ nPrefixReg = pSort->pOrderBy->nExpr; if( !(pSort->sortFlags & SORTFLAG_UseSorter) ) nPrefixReg++; pParse->nMem += nPrefixReg; } pDest->iSdst = pParse->nMem+1; pParse->nMem += nResultCol; }else if( pDest->iSdst+nResultCol > pParse->nMem ){ /* This is an error condition that can result, for example, when a SELECT ** on the right-hand side of an INSERT contains more result columns than ** there are columns in the table on the left. The error will be caught ** and reported later. But we need to make sure enough memory is allocated ** to avoid other spurious errors in the meantime. */ pParse->nMem += nResultCol; } pDest->nSdst = nResultCol; regOrig = regResult = pDest->iSdst; if( srcTab>=0 ){ for(i=0; ipEList->a[i].zEName)); } }else if( eDest!=SRT_Exists ){ #ifdef SQLITE_ENABLE_SORTER_REFERENCES ExprList *pExtra = 0; #endif /* If the destination is an EXISTS(...) expression, the actual ** values returned by the SELECT are not required. */ u8 ecelFlags; /* "ecel" is an abbreviation of "ExprCodeExprList" */ ExprList *pEList; if( eDest==SRT_Mem || eDest==SRT_Output || eDest==SRT_Coroutine ){ ecelFlags = SQLITE_ECEL_DUP; }else{ ecelFlags = 0; } if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){ /* For each expression in p->pEList that is a copy of an expression in ** the ORDER BY clause (pSort->pOrderBy), set the associated ** iOrderByCol value to one more than the index of the ORDER BY ** expression within the sort-key that pushOntoSorter() will generate. ** This allows the p->pEList field to be omitted from the sorted record, ** saving space and CPU cycles. */ ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF); for(i=pSort->nOBSat; ipOrderBy->nExpr; i++){ int j; if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){ p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat; } } #ifdef SQLITE_ENABLE_SORTER_REFERENCES selectExprDefer(pParse, pSort, p->pEList, &pExtra); if( pExtra && pParse->db->mallocFailed==0 ){ /* If there are any extra PK columns to add to the sorter records, ** allocate extra memory cells and adjust the OpenEphemeral ** instruction to account for the larger records. This is only ** required if there are one or more WITHOUT ROWID tables with ** composite primary keys in the SortCtx.aDefer[] array. */ VdbeOp *pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); pOp->p2 += (pExtra->nExpr - pSort->nDefer); pOp->p4.pKeyInfo->nAllField += (pExtra->nExpr - pSort->nDefer); pParse->nMem += pExtra->nExpr; } #endif /* Adjust nResultCol to account for columns that are omitted ** from the sorter by the optimizations in this branch */ pEList = p->pEList; for(i=0; inExpr; i++){ if( pEList->a[i].u.x.iOrderByCol>0 #ifdef SQLITE_ENABLE_SORTER_REFERENCES || pEList->a[i].fg.bSorterRef #endif ){ nResultCol--; regOrig = 0; } } testcase( regOrig ); testcase( eDest==SRT_Set ); testcase( eDest==SRT_Mem ); testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); assert( eDest==SRT_Set || eDest==SRT_Mem || eDest==SRT_Coroutine || eDest==SRT_Output || eDest==SRT_Upfrom ); } sRowLoadInfo.regResult = regResult; sRowLoadInfo.ecelFlags = ecelFlags; #ifdef SQLITE_ENABLE_SORTER_REFERENCES sRowLoadInfo.pExtra = pExtra; sRowLoadInfo.regExtraResult = regResult + nResultCol; if( pExtra ) nResultCol += pExtra->nExpr; #endif if( p->iLimit && (ecelFlags & SQLITE_ECEL_OMITREF)!=0 && nPrefixReg>0 ){ assert( pSort!=0 ); assert( hasDistinct==0 ); pSort->pDeferredRowLoad = &sRowLoadInfo; regOrig = 0; }else{ innerLoopLoadRow(pParse, p, &sRowLoadInfo); } } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ if( hasDistinct ){ int eType = pDistinct->eTnctType; int iTab = pDistinct->tabTnct; assert( nResultCol==p->pEList->nExpr ); iTab = codeDistinct(pParse, eType, iTab, iContinue, p->pEList, regResult); fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct); if( pSort==0 ){ codeOffset(v, p->iOffset, iContinue); } } switch( eDest ){ /* In this mode, write each query result to the key of the temporary ** table iParm. */ #ifndef SQLITE_OMIT_COMPOUND_SELECT case SRT_Union: { int r1; r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); sqlite3ReleaseTempReg(pParse, r1); break; } /* Construct a record from the query result, but instead of ** saving that record, use it as a key to delete elements from ** the temporary table iParm. */ case SRT_Except: { sqlite3VdbeAddOp3(v, OP_IdxDelete, iParm, regResult, nResultCol); break; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ /* Store the result as data using a unique key. */ case SRT_Fifo: case SRT_DistFifo: case SRT_Table: case SRT_EphemTab: { int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1); testcase( eDest==SRT_Table ); testcase( eDest==SRT_EphemTab ); testcase( eDest==SRT_Fifo ); testcase( eDest==SRT_DistFifo ); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg); #if !defined(SQLITE_ENABLE_NULL_TRIM) && defined(SQLITE_DEBUG) /* A destination of SRT_Table and a non-zero iSDParm2 parameter means ** that this is an "UPDATE ... FROM" on a virtual table or view. In this ** case set the p5 parameter of the OP_MakeRecord to OPFLAG_NOCHNG_MAGIC. ** This does not affect operation in any way - it just allows MakeRecord ** to process OPFLAG_NOCHANGE values without an assert() failing. */ if( eDest==SRT_Table && pDest->iSDParm2 ){ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC); } #endif #ifndef SQLITE_OMIT_CTE if( eDest==SRT_DistFifo ){ /* If the destination is DistFifo, then cursor (iParm+1) is open ** on an ephemeral index. If the current row is already present ** in the index, do not write it to the output. If not, add the ** current row to the index and proceed with writing it to the ** output table as well. */ int addr = sqlite3VdbeCurrentAddr(v) + 4; sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1,regResult,nResultCol); assert( pSort==0 ); } #endif if( pSort ){ assert( regResult==regOrig ); pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, regOrig, 1, nPrefixReg); }else{ int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); } sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1); break; } case SRT_Upfrom: { if( pSort ){ pushOntoSorter( pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else{ int i2 = pDest->iSDParm2; int r1 = sqlite3GetTempReg(pParse); /* If the UPDATE FROM join is an aggregate that matches no rows, it ** might still be trying to return one row, because that is what ** aggregates do. Don't record that empty row in the output table. */ sqlite3VdbeAddOp2(v, OP_IsNull, regResult, iBreak); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult+(i2<0), nResultCol-(i2<0), r1); if( i2<0 ){ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regResult); }else{ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, i2); } } break; } #ifndef SQLITE_OMIT_SUBQUERY /* If we are creating a set for an "expr IN (SELECT ...)" construct, ** then there should be a single item on the stack. Write this ** item into the set table with bogus data. */ case SRT_Set: { if( pSort ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ pushOntoSorter( pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else{ int r1 = sqlite3GetTempReg(pParse); assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, pDest->zAffSdst, nResultCol); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); sqlite3ReleaseTempReg(pParse, r1); } break; } /* If any row exist in the result set, record that fact and abort. */ case SRT_Exists: { sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm); /* The LIMIT clause will terminate the loop for us */ break; } /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell or array of ** memory cells and break out of the scan loop. */ case SRT_Mem: { if( pSort ){ assert( nResultCol<=pDest->nSdst ); pushOntoSorter( pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else{ assert( nResultCol==pDest->nSdst ); assert( regResult==iParm ); /* The LIMIT clause will jump out of the loop for us */ } break; } #endif /* #ifndef SQLITE_OMIT_SUBQUERY */ case SRT_Coroutine: /* Send data to a co-routine */ case SRT_Output: { /* Return the results */ testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); if( pSort ){ pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else if( eDest==SRT_Coroutine ){ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol); } break; } #ifndef SQLITE_OMIT_CTE /* Write the results into a priority queue that is order according to ** pDest->pOrderBy (in pSO). pDest->iSDParm (in iParm) is the cursor for an ** index with pSO->nExpr+2 columns. Build a key using pSO for the first ** pSO->nExpr columns, then make sure all keys are unique by adding a ** final OP_Sequence column. The last column is the record as a blob. */ case SRT_DistQueue: case SRT_Queue: { int nKey; int r1, r2, r3; int addrTest = 0; ExprList *pSO; pSO = pDest->pOrderBy; assert( pSO ); nKey = pSO->nExpr; r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempRange(pParse, nKey+2); r3 = r2+nKey+1; if( eDest==SRT_DistQueue ){ /* If the destination is DistQueue, then cursor (iParm+1) is open ** on a second ephemeral index that holds all values every previously ** added to the queue. */ addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0, regResult, nResultCol); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r3); if( eDest==SRT_DistQueue ){ sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r3); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); } for(i=0; ia[i].u.x.iOrderByCol - 1, r2+i); } sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey); sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2); if( addrTest ) sqlite3VdbeJumpHere(v, addrTest); sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempRange(pParse, r2, nKey+2); break; } #endif /* SQLITE_OMIT_CTE */ #if !defined(SQLITE_OMIT_TRIGGER) /* Discard the results. This is used for SELECT statements inside ** the body of a TRIGGER. The purpose of such selects is to call ** user-defined functions that have side effects. We do not care ** about the actual results of the select. */ default: { assert( eDest==SRT_Discard ); break; } #endif } /* Jump to the end of the loop if the LIMIT is reached. Except, if ** there is a sorter, in which case the sorter has already limited ** the output for us. */ if( pSort==0 && p->iLimit ){ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v); } } /* ** Allocate a KeyInfo object sufficient for an index of N key columns and ** X extra columns. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*); KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra); if( p ){ p->aSortFlags = (u8*)&p->aColl[N+X]; p->nKeyField = (u16)N; p->nAllField = (u16)(N+X); p->enc = ENC(db); p->db = db; p->nRef = 1; memset(&p[1], 0, nExtra); }else{ return (KeyInfo*)sqlite3OomFault(db); } return p; } /* ** Deallocate a KeyInfo object */ SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){ if( p ){ assert( p->db!=0 ); assert( p->nRef>0 ); p->nRef--; if( p->nRef==0 ) sqlite3DbNNFreeNN(p->db, p); } } /* ** Make a new pointer to a KeyInfo object */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo *p){ if( p ){ assert( p->nRef>0 ); p->nRef++; } return p; } #ifdef SQLITE_DEBUG /* ** Return TRUE if a KeyInfo object can be change. The KeyInfo object ** can only be changed if this is just a single reference to the object. ** ** This routine is used only inside of assert() statements. */ SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; } #endif /* SQLITE_DEBUG */ /* ** Given an expression list, generate a KeyInfo structure that records ** the collating sequence for each expression in that expression list. ** ** If the ExprList is an ORDER BY or GROUP BY clause then the resulting ** KeyInfo structure is appropriate for initializing a virtual index to ** implement that clause. If the ExprList is the result set of a SELECT ** then the KeyInfo structure is appropriate for initializing a virtual ** index to implement a DISTINCT test. ** ** Space to hold the KeyInfo structure is obtained from malloc. The calling ** function is responsible for seeing that this structure is eventually ** freed. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList( Parse *pParse, /* Parsing context */ ExprList *pList, /* Form the KeyInfo object from this ExprList */ int iStart, /* Begin with this column of pList */ int nExtra /* Add this many extra columns to the end */ ){ int nExpr; KeyInfo *pInfo; struct ExprList_item *pItem; sqlite3 *db = pParse->db; int i; nExpr = pList->nExpr; pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1); if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); for(i=iStart, pItem=pList->a+iStart; iaColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr); pInfo->aSortFlags[i-iStart] = pItem->fg.sortFlags; } } return pInfo; } /* ** Name of the connection operator, used for error messages. */ SQLITE_PRIVATE const char *sqlite3SelectOpName(int id){ char *z; switch( id ){ case TK_ALL: z = "UNION ALL"; break; case TK_INTERSECT: z = "INTERSECT"; break; case TK_EXCEPT: z = "EXCEPT"; break; default: z = "UNION"; break; } return z; } #ifndef SQLITE_OMIT_EXPLAIN /* ** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function ** is a no-op. Otherwise, it adds a single row of output to the EQP result, ** where the caption is of the form: ** ** "USE TEMP B-TREE FOR xxx" ** ** where xxx is one of "DISTINCT", "ORDER BY" or "GROUP BY". Exactly which ** is determined by the zUsage argument. */ static void explainTempTable(Parse *pParse, const char *zUsage){ ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s", zUsage)); } /* ** Assign expression b to lvalue a. A second, no-op, version of this macro ** is provided when SQLITE_OMIT_EXPLAIN is defined. This allows the code ** in sqlite3Select() to assign values to structure member variables that ** only exist if SQLITE_OMIT_EXPLAIN is not defined without polluting the ** code with #ifndef directives. */ # define explainSetInteger(a, b) a = b #else /* No-op versions of the explainXXX() functions and macros. */ # define explainTempTable(y,z) # define explainSetInteger(y,z) #endif /* ** If the inner loop was generated using a non-null pOrderBy argument, ** then the results were placed in a sorter. After the loop is terminated ** we need to run the sorter and output the results. The following ** routine generates the code needed to do that. */ static void generateSortTail( Parse *pParse, /* Parsing context */ Select *p, /* The SELECT statement */ SortCtx *pSort, /* Information on the ORDER BY clause */ int nColumn, /* Number of columns of data */ SelectDest *pDest /* Write the sorted results here */ ){ Vdbe *v = pParse->pVdbe; /* The prepared statement */ int addrBreak = pSort->labelDone; /* Jump here to exit loop */ int addrContinue = sqlite3VdbeMakeLabel(pParse);/* Jump here for next cycle */ int addr; /* Top of output loop. Jump for Next. */ int addrOnce = 0; int iTab; ExprList *pOrderBy = pSort->pOrderBy; int eDest = pDest->eDest; int iParm = pDest->iSDParm; int regRow; int regRowid; int iCol; int nKey; /* Number of key columns in sorter record */ int iSortTab; /* Sorter cursor to read from */ int i; int bSeq; /* True if sorter record includes seq. no. */ int nRefKey = 0; struct ExprList_item *aOutEx = p->pEList->a; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrExplain; /* Address of OP_Explain instruction */ #endif ExplainQueryPlan2(addrExplain, (pParse, 0, "USE TEMP B-TREE FOR %sORDER BY", pSort->nOBSat>0?"RIGHT PART OF ":"") ); sqlite3VdbeScanStatusRange(v, addrExplain,pSort->addrPush,pSort->addrPushEnd); sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, pSort->addrPush); assert( addrBreak<0 ); if( pSort->labelBkOut ){ sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); sqlite3VdbeGoto(v, addrBreak); sqlite3VdbeResolveLabel(v, pSort->labelBkOut); } #ifdef SQLITE_ENABLE_SORTER_REFERENCES /* Open any cursors needed for sorter-reference expressions */ for(i=0; inDefer; i++){ Table *pTab = pSort->aDefer[i].pTab; int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3OpenTable(pParse, pSort->aDefer[i].iCsr, iDb, pTab, OP_OpenRead); nRefKey = MAX(nRefKey, pSort->aDefer[i].nKey); } #endif iTab = pSort->iECursor; if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){ if( eDest==SRT_Mem && p->iOffset ){ sqlite3VdbeAddOp2(v, OP_Null, 0, pDest->iSdst); } regRowid = 0; regRow = pDest->iSdst; }else{ regRowid = sqlite3GetTempReg(pParse); if( eDest==SRT_EphemTab || eDest==SRT_Table ){ regRow = sqlite3GetTempReg(pParse); nColumn = 0; }else{ regRow = sqlite3GetTempRange(pParse, nColumn); } } nKey = pOrderBy->nExpr - pSort->nOBSat; if( pSort->sortFlags & SORTFLAG_UseSorter ){ int regSortOut = ++pParse->nMem; iSortTab = pParse->nTab++; if( pSort->labelBkOut ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nColumn+nRefKey); if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); assert( p->iLimit==0 && p->iOffset==0 ); sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab); bSeq = 0; }else{ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); iSortTab = iTab; bSeq = 1; if( p->iOffset>0 ){ sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1); } } for(i=0, iCol=nKey+bSeq-1; inDefer ){ int iKey = iCol+1; int regKey = sqlite3GetTempRange(pParse, nRefKey); for(i=0; inDefer; i++){ int iCsr = pSort->aDefer[i].iCsr; Table *pTab = pSort->aDefer[i].pTab; int nKey = pSort->aDefer[i].nKey; sqlite3VdbeAddOp1(v, OP_NullRow, iCsr); if( HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iKey++, regKey); sqlite3VdbeAddOp3(v, OP_SeekRowid, iCsr, sqlite3VdbeCurrentAddr(v)+1, regKey); }else{ int k; int iJmp; assert( sqlite3PrimaryKeyIndex(pTab)->nKeyCol==nKey ); for(k=0; k=0; i--){ #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( aOutEx[i].fg.bSorterRef ){ sqlite3ExprCode(pParse, aOutEx[i].pExpr, regRow+i); }else #endif { int iRead; if( aOutEx[i].u.x.iOrderByCol ){ iRead = aOutEx[i].u.x.iOrderByCol-1; }else{ iRead = iCol--; } sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); VdbeComment((v, "%s", aOutEx[i].zEName)); } } sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); switch( eDest ){ case SRT_Table: case SRT_EphemTab: { sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq, regRow); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); break; } #ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid, pDest->zAffSdst, nColumn); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn); break; } case SRT_Mem: { /* The LIMIT clause will terminate the loop for us */ break; } #endif case SRT_Upfrom: { int i2 = pDest->iSDParm2; int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord,regRow+(i2<0),nColumn-(i2<0),r1); if( i2<0 ){ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regRow); }else{ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regRow, i2); } break; } default: { assert( eDest==SRT_Output || eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); testcase( eDest==SRT_Coroutine ); if( eDest==SRT_Output ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn); }else{ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); } break; } } if( regRowid ){ if( eDest==SRT_Set ){ sqlite3ReleaseTempRange(pParse, regRow, nColumn); }else{ sqlite3ReleaseTempReg(pParse, regRow); } sqlite3ReleaseTempReg(pParse, regRowid); } /* The bottom of the loop */ sqlite3VdbeResolveLabel(v, addrContinue); if( pSort->sortFlags & SORTFLAG_UseSorter ){ sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v); }else{ sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v); } sqlite3VdbeScanStatusRange(v, addrExplain, sqlite3VdbeCurrentAddr(v)-1, -1); if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn); sqlite3VdbeResolveLabel(v, addrBreak); } /* ** Return a pointer to a string containing the 'declaration type' of the ** expression pExpr. The string may be treated as static by the caller. ** ** The declaration type is the exact datatype definition extracted from the ** original CREATE TABLE statement if the expression is a column. The ** declaration type for a ROWID field is INTEGER. Exactly when an expression ** is considered a column can be complex in the presence of subqueries. The ** result-set expression in all of the following SELECT statements is ** considered a column by this function. ** ** SELECT col FROM tbl; ** SELECT (SELECT col FROM tbl; ** SELECT (SELECT col FROM tbl); ** SELECT abc FROM (SELECT col AS abc FROM tbl); ** ** The declaration type for any expression other than a column is NULL. ** ** This routine has either 3 or 6 parameters depending on whether or not ** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used. */ #ifdef SQLITE_ENABLE_COLUMN_METADATA # define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E) #else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */ # define columnType(A,B,C,D,E) columnTypeImpl(A,B) #endif static const char *columnTypeImpl( NameContext *pNC, #ifndef SQLITE_ENABLE_COLUMN_METADATA Expr *pExpr #else Expr *pExpr, const char **pzOrigDb, const char **pzOrigTab, const char **pzOrigCol #endif ){ char const *zType = 0; int j; #ifdef SQLITE_ENABLE_COLUMN_METADATA char const *zOrigDb = 0; char const *zOrigTab = 0; char const *zOrigCol = 0; #endif assert( pExpr!=0 ); assert( pNC->pSrcList!=0 ); switch( pExpr->op ){ case TK_COLUMN: { /* The expression is a column. Locate the table the column is being ** extracted from in NameContext.pSrcList. This table may be real ** database table or a subquery. */ Table *pTab = 0; /* Table structure column is extracted from */ Select *pS = 0; /* Select the column is extracted from */ int iCol = pExpr->iColumn; /* Index of column in pTab */ while( pNC && !pTab ){ SrcList *pTabList = pNC->pSrcList; for(j=0;jnSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); if( jnSrc ){ pTab = pTabList->a[j].pTab; pS = pTabList->a[j].pSelect; }else{ pNC = pNC->pNext; } } if( pTab==0 ){ /* At one time, code such as "SELECT new.x" within a trigger would ** cause this condition to run. Since then, we have restructured how ** trigger code is generated and so this condition is no longer ** possible. However, it can still be true for statements like ** the following: ** ** CREATE TABLE t1(col INTEGER); ** SELECT (SELECT t1.col) FROM FROM t1; ** ** when columnType() is called on the expression "t1.col" in the ** sub-select. In this case, set the column type to NULL, even ** though it should really be "INTEGER". ** ** This is not a problem, as the column type of "t1.col" is never ** used. When columnType() is called on the expression ** "(SELECT t1.col)", the correct type is returned (see the TK_SELECT ** branch below. */ break; } assert( pTab && ExprUseYTab(pExpr) && pExpr->y.pTab==pTab ); if( pS ){ /* The "table" is actually a sub-select or a view in the FROM clause ** of the SELECT statement. Return the declaration type and origin ** data for the result-set column of the sub-select. */ if( iColpEList->nExpr #ifdef SQLITE_ALLOW_ROWID_IN_VIEW && iCol>=0 #else && ALWAYS(iCol>=0) #endif ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see ** test case misc2.2.2) - it always evaluates to NULL. */ NameContext sNC; Expr *p = pS->pEList->a[iCol].pExpr; sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol); } }else{ /* A real table or a CTE table */ assert( !pS ); #ifdef SQLITE_ENABLE_COLUMN_METADATA if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==XN_ROWID || (iCol>=0 && iColnCol) ); if( iCol<0 ){ zType = "INTEGER"; zOrigCol = "rowid"; }else{ zOrigCol = pTab->aCol[iCol].zCnName; zType = sqlite3ColumnType(&pTab->aCol[iCol],0); } zOrigTab = pTab->zName; if( pNC->pParse && pTab->pSchema ){ int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema); zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName; } #else assert( iCol==XN_ROWID || (iCol>=0 && iColnCol) ); if( iCol<0 ){ zType = "INTEGER"; }else{ zType = sqlite3ColumnType(&pTab->aCol[iCol],0); } #endif } break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: { /* The expression is a sub-select. Return the declaration type and ** origin info for the single column in the result set of the SELECT ** statement. */ NameContext sNC; Select *pS; Expr *p; assert( ExprUseXSelect(pExpr) ); pS = pExpr->x.pSelect; p = pS->pEList->a[0].pExpr; sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); break; } #endif } #ifdef SQLITE_ENABLE_COLUMN_METADATA if( pzOrigDb ){ assert( pzOrigTab && pzOrigCol ); *pzOrigDb = zOrigDb; *pzOrigTab = zOrigTab; *pzOrigCol = zOrigCol; } #endif return zType; } /* ** Generate code that will tell the VDBE the declaration types of columns ** in the result set. */ static void generateColumnTypes( Parse *pParse, /* Parser context */ SrcList *pTabList, /* List of tables */ ExprList *pEList /* Expressions defining the result set */ ){ #ifndef SQLITE_OMIT_DECLTYPE Vdbe *v = pParse->pVdbe; int i; NameContext sNC; sNC.pSrcList = pTabList; sNC.pParse = pParse; sNC.pNext = 0; for(i=0; inExpr; i++){ Expr *p = pEList->a[i].pExpr; const char *zType; #ifdef SQLITE_ENABLE_COLUMN_METADATA const char *zOrigDb = 0; const char *zOrigTab = 0; const char *zOrigCol = 0; zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); /* The vdbe must make its own copy of the column-type and other ** column specific strings, in case the schema is reset before this ** virtual machine is deleted. */ sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, SQLITE_TRANSIENT); sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT); sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT); #else zType = columnType(&sNC, p, 0, 0, 0); #endif sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT); } #endif /* !defined(SQLITE_OMIT_DECLTYPE) */ } /* ** Compute the column names for a SELECT statement. ** ** The only guarantee that SQLite makes about column names is that if the ** column has an AS clause assigning it a name, that will be the name used. ** That is the only documented guarantee. However, countless applications ** developed over the years have made baseless assumptions about column names ** and will break if those assumptions changes. Hence, use extreme caution ** when modifying this routine to avoid breaking legacy. ** ** See Also: sqlite3ColumnsFromExprList() ** ** The PRAGMA short_column_names and PRAGMA full_column_names settings are ** deprecated. The default setting is short=ON, full=OFF. 99.9% of all ** applications should operate this way. Nevertheless, we need to support the ** other modes for legacy: ** ** short=OFF, full=OFF: Column name is the text of the expression has it ** originally appears in the SELECT statement. In ** other words, the zSpan of the result expression. ** ** short=ON, full=OFF: (This is the default setting). If the result ** refers directly to a table column, then the ** result column name is just the table column ** name: COLUMN. Otherwise use zSpan. ** ** full=ON, short=ANY: If the result refers directly to a table column, ** then the result column name with the table name ** prefix, ex: TABLE.COLUMN. Otherwise use zSpan. */ SQLITE_PRIVATE void sqlite3GenerateColumnNames( Parse *pParse, /* Parser context */ Select *pSelect /* Generate column names for this SELECT statement */ ){ Vdbe *v = pParse->pVdbe; int i; Table *pTab; SrcList *pTabList; ExprList *pEList; sqlite3 *db = pParse->db; int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */ int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */ if( pParse->colNamesSet ) return; /* Column names are determined by the left-most term of a compound select */ while( pSelect->pPrior ) pSelect = pSelect->pPrior; TREETRACE(0x80,pParse,pSelect,("generating column names\n")); pTabList = pSelect->pSrc; pEList = pSelect->pEList; assert( v!=0 ); assert( pTabList!=0 ); pParse->colNamesSet = 1; fullName = (db->flags & SQLITE_FullColNames)!=0; srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; inExpr; i++){ Expr *p = pEList->a[i].pExpr; assert( p!=0 ); assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ assert( p->op!=TK_COLUMN || (ExprUseYTab(p) && p->y.pTab!=0) ); /* Covering idx not yet coded */ if( pEList->a[i].zEName && pEList->a[i].fg.eEName==ENAME_NAME ){ /* An AS clause always takes first priority */ char *zName = pEList->a[i].zEName; sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT); }else if( srcName && p->op==TK_COLUMN ){ char *zCol; int iCol = p->iColumn; pTab = p->y.pTab; assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iColnCol) ); if( iCol<0 ){ zCol = "rowid"; }else{ zCol = pTab->aCol[iCol].zCnName; } if( fullName ){ char *zName = 0; zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol); sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC); }else{ sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT); } }else{ const char *z = pEList->a[i].zEName; z = z==0 ? sqlite3MPrintf(db, "column%d", i+1) : sqlite3DbStrDup(db, z); sqlite3VdbeSetColName(v, i, COLNAME_NAME, z, SQLITE_DYNAMIC); } } generateColumnTypes(pParse, pTabList, pEList); } /* ** Given an expression list (which is really the list of expressions ** that form the result set of a SELECT statement) compute appropriate ** column names for a table that would hold the expression list. ** ** All column names will be unique. ** ** Only the column names are computed. Column.zType, Column.zColl, ** and other fields of Column are zeroed. ** ** Return SQLITE_OK on success. If a memory allocation error occurs, ** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM. ** ** The only guarantee that SQLite makes about column names is that if the ** column has an AS clause assigning it a name, that will be the name used. ** That is the only documented guarantee. However, countless applications ** developed over the years have made baseless assumptions about column names ** and will break if those assumptions changes. Hence, use extreme caution ** when modifying this routine to avoid breaking legacy. ** ** See Also: sqlite3GenerateColumnNames() */ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( Parse *pParse, /* Parsing context */ ExprList *pEList, /* Expr list from which to derive column names */ i16 *pnCol, /* Write the number of columns here */ Column **paCol /* Write the new column list here */ ){ sqlite3 *db = pParse->db; /* Database connection */ int i, j; /* Loop counters */ u32 cnt; /* Index added to make the name unique */ Column *aCol, *pCol; /* For looping over result columns */ int nCol; /* Number of columns in the result set */ char *zName; /* Column name */ int nName; /* Size of name in zName[] */ Hash ht; /* Hash table of column names */ Table *pTab; sqlite3HashInit(&ht); if( pEList ){ nCol = pEList->nExpr; aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol); testcase( aCol==0 ); if( NEVER(nCol>32767) ) nCol = 32767; }else{ nCol = 0; aCol = 0; } assert( nCol==(i16)nCol ); *pnCol = nCol; *paCol = aCol; for(i=0, pCol=aCol; inErr; i++, pCol++){ struct ExprList_item *pX = &pEList->a[i]; struct ExprList_item *pCollide; /* Get an appropriate name for the column */ if( (zName = pX->zEName)!=0 && pX->fg.eEName==ENAME_NAME ){ /* If the column contains an "AS " phrase, use as the name */ }else{ Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pX->pExpr); while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){ pColExpr = pColExpr->pRight; assert( pColExpr!=0 ); } if( pColExpr->op==TK_COLUMN && ALWAYS( ExprUseYTab(pColExpr) ) && ALWAYS( pColExpr->y.pTab!=0 ) ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; pTab = pColExpr->y.pTab; if( iCol<0 ) iCol = pTab->iPKey; zName = iCol>=0 ? pTab->aCol[iCol].zCnName : "rowid"; }else if( pColExpr->op==TK_ID ){ assert( !ExprHasProperty(pColExpr, EP_IntValue) ); zName = pColExpr->u.zToken; }else{ /* Use the original text of the column expression as its name */ assert( zName==pX->zEName ); /* pointer comparison intended */ } } if( zName && !sqlite3IsTrueOrFalse(zName) ){ zName = sqlite3DbStrDup(db, zName); }else{ zName = sqlite3MPrintf(db,"column%d",i+1); } /* Make sure the column name is unique. If the name is not unique, ** append an integer to the name so that it becomes unique. */ cnt = 0; while( zName && (pCollide = sqlite3HashFind(&ht, zName))!=0 ){ if( pCollide->fg.bUsingTerm ){ pCol->colFlags |= COLFLAG_NOEXPAND; } nName = sqlite3Strlen30(zName); if( nName>0 ){ for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){} if( zName[j]==':' ) nName = j; } zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt); sqlite3ProgressCheck(pParse); if( cnt>3 ){ sqlite3_randomness(sizeof(cnt), &cnt); } } pCol->zCnName = zName; pCol->hName = sqlite3StrIHash(zName); if( pX->fg.bNoExpand ){ pCol->colFlags |= COLFLAG_NOEXPAND; } sqlite3ColumnPropertiesFromName(0, pCol); if( zName && sqlite3HashInsert(&ht, zName, pX)==pX ){ sqlite3OomFault(db); } } sqlite3HashClear(&ht); if( pParse->nErr ){ for(j=0; jrc; } return SQLITE_OK; } /* ** pTab is a transient Table object that represents a subquery of some ** kind (maybe a parenthesized subquery in the FROM clause of a larger ** query, or a VIEW, or a CTE). This routine computes type information ** for that Table object based on the Select object that implements the ** subquery. For the purposes of this routine, "type information" means: ** ** * The datatype name, as it might appear in a CREATE TABLE statement ** * Which collating sequence to use for the column ** * The affinity of the column */ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes( Parse *pParse, /* Parsing contexts */ Table *pTab, /* Add column type information to this table */ Select *pSelect, /* SELECT used to determine types and collations */ char aff /* Default affinity. */ ){ sqlite3 *db = pParse->db; Column *pCol; CollSeq *pColl; int i,j; Expr *p; struct ExprList_item *a; NameContext sNC; assert( pSelect!=0 ); testcase( (pSelect->selFlags & SF_Resolved)==0 ); assert( (pSelect->selFlags & SF_Resolved)!=0 || IN_RENAME_OBJECT ); assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 ); assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB ); if( db->mallocFailed || IN_RENAME_OBJECT ) return; while( pSelect->pPrior ) pSelect = pSelect->pPrior; a = pSelect->pEList->a; memset(&sNC, 0, sizeof(sNC)); sNC.pSrcList = pSelect->pSrc; for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ const char *zType; i64 n; pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT); p = a[i].pExpr; /* pCol->szEst = ... // Column size est for SELECT tables never used */ pCol->affinity = sqlite3ExprAffinity(p); if( pCol->affinity<=SQLITE_AFF_NONE ){ pCol->affinity = aff; } if( pCol->affinity>=SQLITE_AFF_TEXT && pSelect->pNext ){ int m = 0; Select *pS2; for(m=0, pS2=pSelect->pNext; pS2; pS2=pS2->pNext){ m |= sqlite3ExprDataType(pS2->pEList->a[i].pExpr); } if( pCol->affinity==SQLITE_AFF_TEXT && (m&0x01)!=0 ){ pCol->affinity = SQLITE_AFF_BLOB; }else if( pCol->affinity>=SQLITE_AFF_NUMERIC && (m&0x02)!=0 ){ pCol->affinity = SQLITE_AFF_BLOB; } if( pCol->affinity>=SQLITE_AFF_NUMERIC && p->op==TK_CAST ){ pCol->affinity = SQLITE_AFF_FLEXNUM; } } zType = columnType(&sNC, p, 0, 0, 0); if( zType==0 || pCol->affinity!=sqlite3AffinityType(zType, 0) ){ if( pCol->affinity==SQLITE_AFF_NUMERIC || pCol->affinity==SQLITE_AFF_FLEXNUM ){ zType = "NUM"; }else{ zType = 0; for(j=1; jaffinity ){ zType = sqlite3StdType[j]; break; } } } } if( zType ){ i64 m = sqlite3Strlen30(zType); n = sqlite3Strlen30(pCol->zCnName); pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2); pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL); if( pCol->zCnName ){ memcpy(&pCol->zCnName[n+1], zType, m+1); pCol->colFlags |= COLFLAG_HASTYPE; } } pColl = sqlite3ExprCollSeq(pParse, p); if( pColl ){ assert( pTab->pIndex==0 ); sqlite3ColumnSetColl(db, pCol, pColl->zName); } } pTab->szTabRow = 1; /* Any non-zero value works */ } /* ** Given a SELECT statement, generate a Table structure that describes ** the result set of that SELECT. */ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, char aff){ Table *pTab; sqlite3 *db = pParse->db; u64 savedFlags; savedFlags = db->flags; db->flags &= ~(u64)SQLITE_FullColNames; db->flags |= SQLITE_ShortColNames; sqlite3SelectPrep(pParse, pSelect, 0); db->flags = savedFlags; if( pParse->nErr ) return 0; while( pSelect->pPrior ) pSelect = pSelect->pPrior; pTab = sqlite3DbMallocZero(db, sizeof(Table) ); if( pTab==0 ){ return 0; } pTab->nTabRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); sqlite3SubqueryColumnTypes(pParse, pTab, pSelect, aff); pTab->iPKey = -1; if( db->mallocFailed ){ sqlite3DeleteTable(db, pTab); return 0; } return pTab; } /* ** Get a VDBE for the given parser context. Create a new one if necessary. ** If an error occurs, return NULL and leave a message in pParse. */ SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){ if( pParse->pVdbe ){ return pParse->pVdbe; } if( pParse->pToplevel==0 && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst) ){ pParse->okConstFactor = 1; } return sqlite3VdbeCreate(pParse); } /* ** Compute the iLimit and iOffset fields of the SELECT based on the ** pLimit expressions. pLimit->pLeft and pLimit->pRight hold the expressions ** that appear in the original SQL statement after the LIMIT and OFFSET ** keywords. Or NULL if those keywords are omitted. iLimit and iOffset ** are the integer memory register numbers for counters used to compute ** the limit and offset. If there is no limit and/or offset, then ** iLimit and iOffset are negative. ** ** This routine changes the values of iLimit and iOffset only if ** a limit or offset is defined by pLimit->pLeft and pLimit->pRight. iLimit ** and iOffset should have been preset to appropriate default values (zero) ** prior to calling this routine. ** ** The iOffset register (if it exists) is initialized to the value ** of the OFFSET. The iLimit register is initialized to LIMIT. Register ** iOffset+1 is initialized to LIMIT+OFFSET. ** ** Only if pLimit->pLeft!=0 do the limit registers get ** redefined. The UNION ALL operator uses this property to force ** the reuse of the same limit and offset registers across multiple ** SELECT statements. */ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ Vdbe *v = 0; int iLimit = 0; int iOffset; int n; Expr *pLimit = p->pLimit; if( p->iLimit ) return; /* ** "LIMIT -1" always shows all rows. There is some ** controversy about what the correct behavior should be. ** The current implementation interprets "LIMIT 0" to mean ** no rows. */ if( pLimit ){ assert( pLimit->op==TK_LIMIT ); assert( pLimit->pLeft!=0 ); p->iLimit = iLimit = ++pParse->nMem; v = sqlite3GetVdbe(pParse); assert( v!=0 ); if( sqlite3ExprIsInteger(pLimit->pLeft, &n) ){ sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit); VdbeComment((v, "LIMIT counter")); if( n==0 ){ sqlite3VdbeGoto(v, iBreak); }else if( n>=0 && p->nSelectRow>sqlite3LogEst((u64)n) ){ p->nSelectRow = sqlite3LogEst((u64)n); p->selFlags |= SF_FixedLimit; } }else{ sqlite3ExprCode(pParse, pLimit->pLeft, iLimit); sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v); VdbeComment((v, "LIMIT counter")); sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v); } if( pLimit->pRight ){ p->iOffset = iOffset = ++pParse->nMem; pParse->nMem++; /* Allocate an extra register for limit+offset */ sqlite3ExprCode(pParse, pLimit->pRight, iOffset); sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v); VdbeComment((v, "OFFSET counter")); sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset); VdbeComment((v, "LIMIT+OFFSET")); } } } #ifndef SQLITE_OMIT_COMPOUND_SELECT /* ** Return the appropriate collating sequence for the iCol-th column of ** the result set for the compound-select statement "p". Return NULL if ** the column has no default collating sequence. ** ** The collating sequence for the compound select is taken from the ** left-most term of the select that has a collating sequence. */ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){ CollSeq *pRet; if( p->pPrior ){ pRet = multiSelectCollSeq(pParse, p->pPrior, iCol); }else{ pRet = 0; } assert( iCol>=0 ); /* iCol must be less than p->pEList->nExpr. Otherwise an error would ** have been thrown during name resolution and we would not have gotten ** this far */ if( pRet==0 && ALWAYS(iColpEList->nExpr) ){ pRet = sqlite3ExprCollSeq(pParse, p->pEList->a[iCol].pExpr); } return pRet; } /* ** The select statement passed as the second parameter is a compound SELECT ** with an ORDER BY clause. This function allocates and returns a KeyInfo ** structure suitable for implementing the ORDER BY. ** ** Space to hold the KeyInfo structure is obtained from malloc. The calling ** function is responsible for ensuring that this structure is eventually ** freed. */ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){ ExprList *pOrderBy = p->pOrderBy; int nOrderBy = ALWAYS(pOrderBy!=0) ? pOrderBy->nExpr : 0; sqlite3 *db = pParse->db; KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1); if( pRet ){ int i; for(i=0; ia[i]; Expr *pTerm = pItem->pExpr; CollSeq *pColl; if( pTerm->flags & EP_Collate ){ pColl = sqlite3ExprCollSeq(pParse, pTerm); }else{ pColl = multiSelectCollSeq(pParse, p, pItem->u.x.iOrderByCol-1); if( pColl==0 ) pColl = db->pDfltColl; pOrderBy->a[i].pExpr = sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName); } assert( sqlite3KeyInfoIsWriteable(pRet) ); pRet->aColl[i] = pColl; pRet->aSortFlags[i] = pOrderBy->a[i].fg.sortFlags; } } return pRet; } #ifndef SQLITE_OMIT_CTE /* ** This routine generates VDBE code to compute the content of a WITH RECURSIVE ** query of the form: ** ** AS ( UNION [ALL] ) ** \___________/ \_______________/ ** p->pPrior p ** ** ** There is exactly one reference to the recursive-table in the FROM clause ** of recursive-query, marked with the SrcList->a[].fg.isRecursive flag. ** ** The setup-query runs once to generate an initial set of rows that go ** into a Queue table. Rows are extracted from the Queue table one by ** one. Each row extracted from Queue is output to pDest. Then the single ** extracted row (now in the iCurrent table) becomes the content of the ** recursive-table for a recursive-query run. The output of the recursive-query ** is added back into the Queue table. Then another row is extracted from Queue ** and the iteration continues until the Queue table is empty. ** ** If the compound query operator is UNION then no duplicate rows are ever ** inserted into the Queue table. The iDistinct table keeps a copy of all rows ** that have ever been inserted into Queue and causes duplicates to be ** discarded. If the operator is UNION ALL, then duplicates are allowed. ** ** If the query has an ORDER BY, then entries in the Queue table are kept in ** ORDER BY order and the first entry is extracted for each cycle. Without ** an ORDER BY, the Queue table is just a FIFO. ** ** If a LIMIT clause is provided, then the iteration stops after LIMIT rows ** have been output to pDest. A LIMIT of zero means to output no rows and a ** negative LIMIT means to output all rows. If there is also an OFFSET clause ** with a positive value, then the first OFFSET outputs are discarded rather ** than being sent to pDest. The LIMIT count does not begin until after OFFSET ** rows have been skipped. */ static void generateWithRecursiveQuery( Parse *pParse, /* Parsing context */ Select *p, /* The recursive SELECT to be coded */ SelectDest *pDest /* What to do with query results */ ){ SrcList *pSrc = p->pSrc; /* The FROM clause of the recursive query */ int nCol = p->pEList->nExpr; /* Number of columns in the recursive table */ Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ Select *pSetup; /* The setup query */ Select *pFirstRec; /* Left-most recursive term */ int addrTop; /* Top of the loop */ int addrCont, addrBreak; /* CONTINUE and BREAK addresses */ int iCurrent = 0; /* The Current table */ int regCurrent; /* Register holding Current table */ int iQueue; /* The Queue table */ int iDistinct = 0; /* To ensure unique results if UNION */ int eDest = SRT_Fifo; /* How to write to Queue */ SelectDest destQueue; /* SelectDest targeting the Queue table */ int i; /* Loop counter */ int rc; /* Result code */ ExprList *pOrderBy; /* The ORDER BY clause */ Expr *pLimit; /* Saved LIMIT and OFFSET */ int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */ #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWin ){ sqlite3ErrorMsg(pParse, "cannot use window functions in recursive queries"); return; } #endif /* Obtain authorization to do a recursive query */ if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return; /* Process the LIMIT and OFFSET clauses, if they exist */ addrBreak = sqlite3VdbeMakeLabel(pParse); p->nSelectRow = 320; /* 4 billion rows */ computeLimitRegisters(pParse, p, addrBreak); pLimit = p->pLimit; regLimit = p->iLimit; regOffset = p->iOffset; p->pLimit = 0; p->iLimit = p->iOffset = 0; pOrderBy = p->pOrderBy; /* Locate the cursor number of the Current table */ for(i=0; ALWAYS(inSrc); i++){ if( pSrc->a[i].fg.isRecursive ){ iCurrent = pSrc->a[i].iCursor; break; } } /* Allocate cursors numbers for Queue and Distinct. The cursor number for ** the Distinct table must be exactly one greater than Queue in order ** for the SRT_DistFifo and SRT_DistQueue destinations to work. */ iQueue = pParse->nTab++; if( p->op==TK_UNION ){ eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo; iDistinct = pParse->nTab++; }else{ eDest = pOrderBy ? SRT_Queue : SRT_Fifo; } sqlite3SelectDestInit(&destQueue, eDest, iQueue); /* Allocate cursors for Current, Queue, and Distinct. */ regCurrent = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol); if( pOrderBy ){ KeyInfo *pKeyInfo = multiSelectOrderByKeyInfo(pParse, p, 1); sqlite3VdbeAddOp4(v, OP_OpenEphemeral, iQueue, pOrderBy->nExpr+2, 0, (char*)pKeyInfo, P4_KEYINFO); destQueue.pOrderBy = pOrderBy; }else{ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iQueue, nCol); } VdbeComment((v, "Queue table")); if( iDistinct ){ p->addrOpenEphm[0] = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0); p->selFlags |= SF_UsesEphemeral; } /* Detach the ORDER BY clause from the compound SELECT */ p->pOrderBy = 0; /* Figure out how many elements of the compound SELECT are part of the ** recursive query. Make sure no recursive elements use aggregate ** functions. Mark the recursive elements as UNION ALL even if they ** are really UNION because the distinctness will be enforced by the ** iDistinct table. pFirstRec is left pointing to the left-most ** recursive term of the CTE. */ for(pFirstRec=p; ALWAYS(pFirstRec!=0); pFirstRec=pFirstRec->pPrior){ if( pFirstRec->selFlags & SF_Aggregate ){ sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); goto end_of_recursive_query; } pFirstRec->op = TK_ALL; if( (pFirstRec->pPrior->selFlags & SF_Recursive)==0 ) break; } /* Store the results of the setup-query in Queue. */ pSetup = pFirstRec->pPrior; pSetup->pNext = 0; ExplainQueryPlan((pParse, 1, "SETUP")); rc = sqlite3Select(pParse, pSetup, &destQueue); pSetup->pNext = p; if( rc ) goto end_of_recursive_query; /* Find the next row in the Queue and output that row */ addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); VdbeCoverage(v); /* Transfer the next row in Queue over to Current */ sqlite3VdbeAddOp1(v, OP_NullRow, iCurrent); /* To reset column cache */ if( pOrderBy ){ sqlite3VdbeAddOp3(v, OP_Column, iQueue, pOrderBy->nExpr+1, regCurrent); }else{ sqlite3VdbeAddOp2(v, OP_RowData, iQueue, regCurrent); } sqlite3VdbeAddOp1(v, OP_Delete, iQueue); /* Output the single row in Current */ addrCont = sqlite3VdbeMakeLabel(pParse); codeOffset(v, regOffset, addrCont); selectInnerLoop(pParse, p, iCurrent, 0, 0, pDest, addrCont, addrBreak); if( regLimit ){ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak); VdbeCoverage(v); } sqlite3VdbeResolveLabel(v, addrCont); /* Execute the recursive SELECT taking the single row in Current as ** the value for the recursive-table. Store the results in the Queue. */ pFirstRec->pPrior = 0; ExplainQueryPlan((pParse, 1, "RECURSIVE STEP")); sqlite3Select(pParse, p, &destQueue); assert( pFirstRec->pPrior==0 ); pFirstRec->pPrior = pSetup; /* Keep running the loop until the Queue is empty */ sqlite3VdbeGoto(v, addrTop); sqlite3VdbeResolveLabel(v, addrBreak); end_of_recursive_query: sqlite3ExprListDelete(pParse->db, p->pOrderBy); p->pOrderBy = pOrderBy; p->pLimit = pLimit; return; } #endif /* SQLITE_OMIT_CTE */ /* Forward references */ static int multiSelectOrderBy( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ); /* ** Handle the special case of a compound-select that originates from a ** VALUES clause. By handling this as a special case, we avoid deep ** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT ** on a VALUES clause. ** ** Because the Select object originates from a VALUES clause: ** (1) There is no LIMIT or OFFSET or else there is a LIMIT of exactly 1 ** (2) All terms are UNION ALL ** (3) There is no ORDER BY clause ** ** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES ** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))"). ** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case. ** Since the limit is exactly 1, we only need to evaluate the left-most VALUES. */ static int multiSelectValues( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ){ int nRow = 1; int rc = 0; int bShowAll = p->pLimit==0; assert( p->selFlags & SF_MultiValue ); do{ assert( p->selFlags & SF_Values ); assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr ); #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWin ) return -1; #endif if( p->pPrior==0 ) break; assert( p->pPrior->pNext==p ); p = p->pPrior; nRow += bShowAll; }while(1); ExplainQueryPlan((pParse, 0, "SCAN %d CONSTANT ROW%s", nRow, nRow==1 ? "" : "S")); while( p ){ selectInnerLoop(pParse, p, -1, 0, 0, pDest, 1, 1); if( !bShowAll ) break; p->nSelectRow = nRow; p = p->pNext; } return rc; } /* ** Return true if the SELECT statement which is known to be the recursive ** part of a recursive CTE still has its anchor terms attached. If the ** anchor terms have already been removed, then return false. */ static int hasAnchor(Select *p){ while( p && (p->selFlags & SF_Recursive)!=0 ){ p = p->pPrior; } return p!=0; } /* ** This routine is called to process a compound query form from ** two or more separate queries using UNION, UNION ALL, EXCEPT, or ** INTERSECT ** ** "p" points to the right-most of the two queries. the query on the ** left is p->pPrior. The left query could also be a compound query ** in which case this routine will be called recursively. ** ** The results of the total query are to be written into a destination ** of type eDest with parameter iParm. ** ** Example 1: Consider a three-way compound SQL statement. ** ** SELECT a FROM t1 UNION SELECT b FROM t2 UNION SELECT c FROM t3 ** ** This statement is parsed up as follows: ** ** SELECT c FROM t3 ** | ** `-----> SELECT b FROM t2 ** | ** `------> SELECT a FROM t1 ** ** The arrows in the diagram above represent the Select.pPrior pointer. ** So if this routine is called with p equal to the t3 query, then ** pPrior will be the t2 query. p->op will be TK_UNION in this case. ** ** Notice that because of the way SQLite parses compound SELECTs, the ** individual selects always group from left to right. */ static int multiSelect( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ){ int rc = SQLITE_OK; /* Success code from a subroutine */ Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ SelectDest dest; /* Alternative data destination */ Select *pDelete = 0; /* Chain of simple selects to delete */ sqlite3 *db; /* Database connection */ /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. */ assert( p && p->pPrior ); /* Calling function guarantees this much */ assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION ); assert( p->selFlags & SF_Compound ); db = pParse->db; pPrior = p->pPrior; dest = *pDest; assert( pPrior->pOrderBy==0 ); assert( pPrior->pLimit==0 ); v = sqlite3GetVdbe(pParse); assert( v!=0 ); /* The VDBE already created by calling function */ /* Create the destination temporary table if necessary */ if( dest.eDest==SRT_EphemTab ){ assert( p->pEList ); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr); dest.eDest = SRT_Table; } /* Special handling for a compound-select that originates as a VALUES clause. */ if( p->selFlags & SF_MultiValue ){ rc = multiSelectValues(pParse, p, &dest); if( rc>=0 ) goto multi_select_end; rc = SQLITE_OK; } /* Make sure all SELECTs in the statement have the same number of elements ** in their result sets. */ assert( p->pEList && pPrior->pEList ); assert( p->pEList->nExpr==pPrior->pEList->nExpr ); #ifndef SQLITE_OMIT_CTE if( (p->selFlags & SF_Recursive)!=0 && hasAnchor(p) ){ generateWithRecursiveQuery(pParse, p, &dest); }else #endif /* Compound SELECTs that have an ORDER BY clause are handled separately. */ if( p->pOrderBy ){ return multiSelectOrderBy(pParse, p, pDest); }else{ #ifndef SQLITE_OMIT_EXPLAIN if( pPrior->pPrior==0 ){ ExplainQueryPlan((pParse, 1, "COMPOUND QUERY")); ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY")); } #endif /* Generate code for the left and right SELECT statements. */ switch( p->op ){ case TK_ALL: { int addr = 0; int nLimit = 0; /* Initialize to suppress harmless compiler warning */ assert( !pPrior->pLimit ); pPrior->iLimit = p->iLimit; pPrior->iOffset = p->iOffset; pPrior->pLimit = p->pLimit; TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n")); rc = sqlite3Select(pParse, pPrior, &dest); pPrior->pLimit = 0; if( rc ){ goto multi_select_end; } p->pPrior = 0; p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; if( p->iLimit ){ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); VdbeComment((v, "Jump ahead if LIMIT reached")); if( p->iOffset ){ sqlite3VdbeAddOp3(v, OP_OffsetLimit, p->iLimit, p->iOffset+1, p->iOffset); } } ExplainQueryPlan((pParse, 1, "UNION ALL")); TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n")); rc = sqlite3Select(pParse, p, &dest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); if( p->pLimit && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit) && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) ){ p->nSelectRow = sqlite3LogEst((u64)nLimit); } if( addr ){ sqlite3VdbeJumpHere(v, addr); } break; } case TK_EXCEPT: case TK_UNION: { int unionTab; /* Cursor number of the temp table holding result */ u8 op = 0; /* One of the SRT_ operations to apply to self */ int priorOp; /* The SRT_ operation to apply to prior selects */ Expr *pLimit; /* Saved values of p->nLimit */ int addr; SelectDest uniondest; testcase( p->op==TK_EXCEPT ); testcase( p->op==TK_UNION ); priorOp = SRT_Union; if( dest.eDest==priorOp ){ /* We can reuse a temporary table generated by a SELECT to our ** right. */ assert( p->pLimit==0 ); /* Not allowed on leftward elements */ unionTab = dest.iSDParm; }else{ /* We will need to create our own temporary table to hold the ** intermediate results. */ unionTab = pParse->nTab++; assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); } /* Code the SELECT statements to our left */ assert( !pPrior->pOrderBy ); sqlite3SelectDestInit(&uniondest, priorOp, unionTab); TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION left...\n")); rc = sqlite3Select(pParse, pPrior, &uniondest); if( rc ){ goto multi_select_end; } /* Code the current SELECT statement */ if( p->op==TK_EXCEPT ){ op = SRT_Except; }else{ assert( p->op==TK_UNION ); op = SRT_Union; } p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; uniondest.eDest = op; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", sqlite3SelectOpName(p->op))); TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION right...\n")); rc = sqlite3Select(pParse, p, &uniondest); testcase( rc!=SQLITE_OK ); assert( p->pOrderBy==0 ); pDelete = p->pPrior; p->pPrior = pPrior; p->pOrderBy = 0; if( p->op==TK_UNION ){ p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); } sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; p->iLimit = 0; p->iOffset = 0; /* Convert the data in the temporary table into whatever form ** it is that we currently need. */ assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); assert( p->pEList || db->mallocFailed ); if( dest.eDest!=priorOp && db->mallocFailed==0 ){ int iCont, iBreak, iStart; iBreak = sqlite3VdbeMakeLabel(pParse); iCont = sqlite3VdbeMakeLabel(pParse); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); iStart = sqlite3VdbeCurrentAddr(v); selectInnerLoop(pParse, p, unionTab, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); } break; } default: assert( p->op==TK_INTERSECT ); { int tab1, tab2; int iCont, iBreak, iStart; Expr *pLimit; int addr; SelectDest intersectdest; int r1; /* INTERSECT is different from the others since it requires ** two temporary tables. Hence it has its own case. Begin ** by allocating the tables we will need. */ tab1 = pParse->nTab++; tab2 = pParse->nTab++; assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". */ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT left...\n")); rc = sqlite3Select(pParse, pPrior, &intersectdest); if( rc ){ goto multi_select_end; } /* Code the current SELECT into temporary table "tab2" */ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); assert( p->addrOpenEphm[1] == -1 ); p->addrOpenEphm[1] = addr; p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; intersectdest.iSDParm = tab2; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", sqlite3SelectOpName(p->op))); TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT right...\n")); rc = sqlite3Select(pParse, p, &intersectdest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; if( p->nSelectRow>pPrior->nSelectRow ){ p->nSelectRow = pPrior->nSelectRow; } sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; /* Generate code to take the intersection of the two temporary ** tables. */ if( rc ) break; assert( p->pEList ); iBreak = sqlite3VdbeMakeLabel(pParse); iCont = sqlite3VdbeMakeLabel(pParse); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); r1 = sqlite3GetTempReg(pParse); iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, r1); selectInnerLoop(pParse, p, tab1, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); break; } } #ifndef SQLITE_OMIT_EXPLAIN if( p->pNext==0 ){ ExplainQueryPlanPop(pParse); } #endif } if( pParse->nErr ) goto multi_select_end; /* Compute collating sequences used by ** temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. ** ** This section is run by the right-most SELECT statement only. ** SELECT statements to the left always skip this part. The right-most ** SELECT might also skip this part if it has no ORDER BY clause and ** no temp tables are required. */ if( p->selFlags & SF_UsesEphemeral ){ int i; /* Loop counter */ KeyInfo *pKeyInfo; /* Collating sequence for the result set */ Select *pLoop; /* For looping through SELECT statements */ CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ int nCol; /* Number of columns in result set */ assert( p->pNext==0 ); assert( p->pEList!=0 ); nCol = p->pEList->nExpr; pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); if( !pKeyInfo ){ rc = SQLITE_NOMEM_BKPT; goto multi_select_end; } for(i=0, apColl=pKeyInfo->aColl; ipDfltColl; } } for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ for(i=0; i<2; i++){ int addr = pLoop->addrOpenEphm[i]; if( addr<0 ){ /* If [0] is unused then [1] is also unused. So we can ** always safely abort as soon as the first unused slot is found */ assert( pLoop->addrOpenEphm[1]<0 ); break; } sqlite3VdbeChangeP2(v, addr, nCol); sqlite3VdbeChangeP4(v, addr, (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO); pLoop->addrOpenEphm[i] = -1; } } sqlite3KeyInfoUnref(pKeyInfo); } multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; if( pDelete ){ sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete); } return rc; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ /* ** Error message for when two or more terms of a compound select have different ** size result sets. */ SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){ if( p->selFlags & SF_Values ){ sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms"); }else{ sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" " do not have the same number of result columns", sqlite3SelectOpName(p->op)); } } /* ** Code an output subroutine for a coroutine implementation of a ** SELECT statement. ** ** The data to be output is contained in pIn->iSdst. There are ** pIn->nSdst columns to be output. pDest is where the output should ** be sent. ** ** regReturn is the number of the register holding the subroutine ** return address. ** ** If regPrev>0 then it is the first register in a vector that ** records the previous output. mem[regPrev] is a flag that is false ** if there has been no previous output. If regPrev>0 then code is ** generated to suppress duplicates. pKeyInfo is used for comparing ** keys. ** ** If the LIMIT found in p->iLimit is reached, jump immediately to ** iBreak. */ static int generateOutputSubroutine( Parse *pParse, /* Parsing context */ Select *p, /* The SELECT statement */ SelectDest *pIn, /* Coroutine supplying data */ SelectDest *pDest, /* Where to send the data */ int regReturn, /* The return address register */ int regPrev, /* Previous result register. No uniqueness if 0 */ KeyInfo *pKeyInfo, /* For comparing with previous entry */ int iBreak /* Jump here if we hit the LIMIT */ ){ Vdbe *v = pParse->pVdbe; int iContinue; int addr; addr = sqlite3VdbeCurrentAddr(v); iContinue = sqlite3VdbeMakeLabel(pParse); /* Suppress duplicates for UNION, EXCEPT, and INTERSECT */ if( regPrev ){ int addr1, addr2; addr1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v); addr2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst, (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO); sqlite3VdbeAddOp3(v, OP_Jump, addr2+2, iContinue, addr2+2); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev+1, pIn->nSdst-1); sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev); } if( pParse->db->mallocFailed ) return 0; /* Suppress the first OFFSET entries if there is an OFFSET clause */ codeOffset(v, p->iOffset, iContinue); assert( pDest->eDest!=SRT_Exists ); assert( pDest->eDest!=SRT_Table ); switch( pDest->eDest ){ /* Store the result as data using a unique key. */ case SRT_EphemTab: { int r1 = sqlite3GetTempReg(pParse); int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1); sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iSDParm, r2); sqlite3VdbeAddOp3(v, OP_Insert, pDest->iSDParm, r1, r2); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); sqlite3ReleaseTempReg(pParse, r1); break; } #ifndef SQLITE_OMIT_SUBQUERY /* If we are creating a set for an "expr IN (SELECT ...)". */ case SRT_Set: { int r1; testcase( pIn->nSdst>1 ); r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1, pDest->zAffSdst, pIn->nSdst); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1, pIn->iSdst, pIn->nSdst); sqlite3ReleaseTempReg(pParse, r1); break; } /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. Note that the select might return multiple columns ** if it is the RHS of a row-value IN operator. */ case SRT_Mem: { testcase( pIn->nSdst>1 ); sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, pIn->nSdst); /* The LIMIT clause will jump out of the loop for us */ break; } #endif /* #ifndef SQLITE_OMIT_SUBQUERY */ /* The results are stored in a sequence of registers ** starting at pDest->iSdst. Then the co-routine yields. */ case SRT_Coroutine: { if( pDest->iSdst==0 ){ pDest->iSdst = sqlite3GetTempRange(pParse, pIn->nSdst); pDest->nSdst = pIn->nSdst; } sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSdst, pIn->nSdst); sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); break; } /* If none of the above, then the result destination must be ** SRT_Output. This routine is never called with any other ** destination other than the ones handled above or SRT_Output. ** ** For SRT_Output, results are stored in a sequence of registers. ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to ** return the next row of result. */ default: { assert( pDest->eDest==SRT_Output ); sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst); break; } } /* Jump to the end of the loop if the LIMIT is reached. */ if( p->iLimit ){ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v); } /* Generate the subroutine return */ sqlite3VdbeResolveLabel(v, iContinue); sqlite3VdbeAddOp1(v, OP_Return, regReturn); return addr; } /* ** Alternative compound select code generator for cases when there ** is an ORDER BY clause. ** ** We assume a query of the following form: ** ** ORDER BY ** ** is one of UNION ALL, UNION, EXCEPT, or INTERSECT. The idea ** is to code both and with the ORDER BY clause as ** co-routines. Then run the co-routines in parallel and merge the results ** into the output. In addition to the two coroutines (called selectA and ** selectB) there are 7 subroutines: ** ** outA: Move the output of the selectA coroutine into the output ** of the compound query. ** ** outB: Move the output of the selectB coroutine into the output ** of the compound query. (Only generated for UNION and ** UNION ALL. EXCEPT and INSERTSECT never output a row that ** appears only in B.) ** ** AltB: Called when there is data from both coroutines and AB. ** ** EofA: Called when data is exhausted from selectA. ** ** EofB: Called when data is exhausted from selectB. ** ** The implementation of the latter five subroutines depend on which ** is used: ** ** ** UNION ALL UNION EXCEPT INTERSECT ** ------------- ----------------- -------------- ----------------- ** AltB: outA, nextA outA, nextA outA, nextA nextA ** ** AeqB: outA, nextA nextA nextA outA, nextA ** ** AgtB: outB, nextB outB, nextB nextB nextB ** ** EofA: outB, nextB outB, nextB halt halt ** ** EofB: outA, nextA outA, nextA outA, nextA halt ** ** In the AltB, AeqB, and AgtB subroutines, an EOF on A following nextA ** causes an immediate jump to EofA and an EOF on B following nextB causes ** an immediate jump to EofB. Within EofA and EofB, and EOF on entry or ** following nextX causes a jump to the end of the select processing. ** ** Duplicate removal in the UNION, EXCEPT, and INTERSECT cases is handled ** within the output subroutine. The regPrev register set holds the previously ** output value. A comparison is made against this value and the output ** is skipped if the next results would be the same as the previous. ** ** The implementation plan is to implement the two coroutines and seven ** subroutines first, then put the control logic at the bottom. Like this: ** ** goto Init ** coA: coroutine for left query (A) ** coB: coroutine for right query (B) ** outA: output one row of A ** outB: output one row of B (UNION and UNION ALL only) ** EofA: ... ** EofB: ... ** AltB: ... ** AeqB: ... ** AgtB: ... ** Init: initialize coroutine registers ** yield coA ** if eof(A) goto EofA ** yield coB ** if eof(B) goto EofB ** Cmpr: Compare A, B ** Jump AltB, AeqB, AgtB ** End: ... ** ** We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not ** actually called using Gosub and they do not Return. EofA and EofB loop ** until all data is exhausted then jump to the "end" label. AltB, AeqB, ** and AgtB jump to either L2 or to one of EofA or EofB. */ #ifndef SQLITE_OMIT_COMPOUND_SELECT static int multiSelectOrderBy( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ){ int i, j; /* Loop counters */ Select *pPrior; /* Another SELECT immediately to our left */ Select *pSplit; /* Left-most SELECT in the right-hand group */ int nSelect; /* Number of SELECT statements in the compound */ Vdbe *v; /* Generate code to this VDBE */ SelectDest destA; /* Destination for coroutine A */ SelectDest destB; /* Destination for coroutine B */ int regAddrA; /* Address register for select-A coroutine */ int regAddrB; /* Address register for select-B coroutine */ int addrSelectA; /* Address of the select-A coroutine */ int addrSelectB; /* Address of the select-B coroutine */ int regOutA; /* Address register for the output-A subroutine */ int regOutB; /* Address register for the output-B subroutine */ int addrOutA; /* Address of the output-A subroutine */ int addrOutB = 0; /* Address of the output-B subroutine */ int addrEofA; /* Address of the select-A-exhausted subroutine */ int addrEofA_noB; /* Alternate addrEofA if B is uninitialized */ int addrEofB; /* Address of the select-B-exhausted subroutine */ int addrAltB; /* Address of the AB subroutine */ int regLimitA; /* Limit register for select-A */ int regLimitB; /* Limit register for select-A */ int regPrev; /* A range of registers to hold previous output */ int savedLimit; /* Saved value of p->iLimit */ int savedOffset; /* Saved value of p->iOffset */ int labelCmpr; /* Label for the start of the merge algorithm */ int labelEnd; /* Label for the end of the overall SELECT stmt */ int addr1; /* Jump instructions that get retargeted */ int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */ KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */ KeyInfo *pKeyMerge; /* Comparison information for merging rows */ sqlite3 *db; /* Database connection */ ExprList *pOrderBy; /* The ORDER BY clause */ int nOrderBy; /* Number of terms in the ORDER BY clause */ u32 *aPermute; /* Mapping from ORDER BY terms to result set columns */ assert( p->pOrderBy!=0 ); assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */ db = pParse->db; v = pParse->pVdbe; assert( v!=0 ); /* Already thrown the error if VDBE alloc failed */ labelEnd = sqlite3VdbeMakeLabel(pParse); labelCmpr = sqlite3VdbeMakeLabel(pParse); /* Patch up the ORDER BY clause */ op = p->op; assert( p->pPrior->pOrderBy==0 ); pOrderBy = p->pOrderBy; assert( pOrderBy ); nOrderBy = pOrderBy->nExpr; /* For operators other than UNION ALL we have to make sure that ** the ORDER BY clause covers every term of the result set. Add ** terms to the ORDER BY clause as necessary. */ if( op!=TK_ALL ){ for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){ struct ExprList_item *pItem; for(j=0, pItem=pOrderBy->a; ju.x.iOrderByCol>0 ); if( pItem->u.x.iOrderByCol==i ) break; } if( j==nOrderBy ){ Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); if( pNew==0 ) return SQLITE_NOMEM_BKPT; pNew->flags |= EP_IntValue; pNew->u.iValue = i; p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew); if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i; } } } /* Compute the comparison permutation and keyinfo that is used with ** the permutation used to determine if the next ** row of results comes from selectA or selectB. Also add explicit ** collations to the ORDER BY clause terms so that when the subqueries ** to the right and the left are evaluated, they use the correct ** collation. */ aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1)); if( aPermute ){ struct ExprList_item *pItem; aPermute[0] = nOrderBy; for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){ assert( pItem!=0 ); assert( pItem->u.x.iOrderByCol>0 ); assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ); aPermute[i] = pItem->u.x.iOrderByCol - 1; } pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1); }else{ pKeyMerge = 0; } /* Allocate a range of temporary registers and the KeyInfo needed ** for the logic that removes duplicate result rows when the ** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL). */ if( op==TK_ALL ){ regPrev = 0; }else{ int nExpr = p->pEList->nExpr; assert( nOrderBy>=nExpr || db->mallocFailed ); regPrev = pParse->nMem+1; pParse->nMem += nExpr+1; sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev); pKeyDup = sqlite3KeyInfoAlloc(db, nExpr, 1); if( pKeyDup ){ assert( sqlite3KeyInfoIsWriteable(pKeyDup) ); for(i=0; iaColl[i] = multiSelectCollSeq(pParse, p, i); pKeyDup->aSortFlags[i] = 0; } } } /* Separate the left and the right query from one another */ nSelect = 1; if( (op==TK_ALL || op==TK_UNION) && OptimizationEnabled(db, SQLITE_BalancedMerge) ){ for(pSplit=p; pSplit->pPrior!=0 && pSplit->op==op; pSplit=pSplit->pPrior){ nSelect++; assert( pSplit->pPrior->pNext==pSplit ); } } if( nSelect<=3 ){ pSplit = p; }else{ pSplit = p; for(i=2; ipPrior; } } pPrior = pSplit->pPrior; assert( pPrior!=0 ); pSplit->pPrior = 0; pPrior->pNext = 0; assert( p->pOrderBy == pOrderBy ); assert( pOrderBy!=0 || db->mallocFailed ); pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0); sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER"); sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER"); /* Compute the limit registers */ computeLimitRegisters(pParse, p, labelEnd); if( p->iLimit && op==TK_ALL ){ regLimitA = ++pParse->nMem; regLimitB = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, p->iOffset ? p->iOffset+1 : p->iLimit, regLimitA); sqlite3VdbeAddOp2(v, OP_Copy, regLimitA, regLimitB); }else{ regLimitA = regLimitB = 0; } sqlite3ExprDelete(db, p->pLimit); p->pLimit = 0; regAddrA = ++pParse->nMem; regAddrB = ++pParse->nMem; regOutA = ++pParse->nMem; regOutB = ++pParse->nMem; sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); ExplainQueryPlan((pParse, 1, "MERGE (%s)", sqlite3SelectOpName(p->op))); /* Generate a coroutine to evaluate the SELECT statement to the ** left of the compound operator - the "A" select. */ addrSelectA = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA); VdbeComment((v, "left SELECT")); pPrior->iLimit = regLimitA; ExplainQueryPlan((pParse, 1, "LEFT")); sqlite3Select(pParse, pPrior, &destA); sqlite3VdbeEndCoroutine(v, regAddrA); sqlite3VdbeJumpHere(v, addr1); /* Generate a coroutine to evaluate the SELECT statement on ** the right - the "B" select */ addrSelectB = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB); VdbeComment((v, "right SELECT")); savedLimit = p->iLimit; savedOffset = p->iOffset; p->iLimit = regLimitB; p->iOffset = 0; ExplainQueryPlan((pParse, 1, "RIGHT")); sqlite3Select(pParse, p, &destB); p->iLimit = savedLimit; p->iOffset = savedOffset; sqlite3VdbeEndCoroutine(v, regAddrB); /* Generate a subroutine that outputs the current row of the A ** select as the next output row of the compound select. */ VdbeNoopComment((v, "Output routine for A")); addrOutA = generateOutputSubroutine(pParse, p, &destA, pDest, regOutA, regPrev, pKeyDup, labelEnd); /* Generate a subroutine that outputs the current row of the B ** select as the next output row of the compound select. */ if( op==TK_ALL || op==TK_UNION ){ VdbeNoopComment((v, "Output routine for B")); addrOutB = generateOutputSubroutine(pParse, p, &destB, pDest, regOutB, regPrev, pKeyDup, labelEnd); } sqlite3KeyInfoUnref(pKeyDup); /* Generate a subroutine to run when the results from select A ** are exhausted and only data in select B remains. */ if( op==TK_EXCEPT || op==TK_INTERSECT ){ addrEofA_noB = addrEofA = labelEnd; }else{ VdbeNoopComment((v, "eof-A subroutine")); addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd); VdbeCoverage(v); sqlite3VdbeGoto(v, addrEofA); p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); } /* Generate a subroutine to run when the results from select B ** are exhausted and only data in select A remains. */ if( op==TK_INTERSECT ){ addrEofB = addrEofA; if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow; }else{ VdbeNoopComment((v, "eof-B subroutine")); addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v); sqlite3VdbeGoto(v, addrEofB); } /* Generate code to handle the case of AB */ VdbeNoopComment((v, "A-gt-B subroutine")); addrAgtB = sqlite3VdbeCurrentAddr(v); if( op==TK_ALL || op==TK_UNION ){ sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); } sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); sqlite3VdbeGoto(v, labelCmpr); /* This code runs once to initialize everything. */ sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); /* Implement the main merge loop */ sqlite3VdbeResolveLabel(v, labelCmpr); sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY); sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy, (char*)pKeyMerge, P4_KEYINFO); sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); VdbeCoverage(v); /* Jump to the this point in order to terminate the query. */ sqlite3VdbeResolveLabel(v, labelEnd); /* Make arrangements to free the 2nd and subsequent arms of the compound ** after the parse has finished */ if( pSplit->pPrior ){ sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pSplit->pPrior); } pSplit->pPrior = pPrior; pPrior->pNext = pSplit; sqlite3ExprListDelete(db, pPrior->pOrderBy); pPrior->pOrderBy = 0; /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ ExplainQueryPlanPop(pParse); return pParse->nErr!=0; } #endif #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* An instance of the SubstContext object describes an substitution edit ** to be performed on a parse tree. ** ** All references to columns in table iTable are to be replaced by corresponding ** expressions in pEList. ** ** ## About "isOuterJoin": ** ** The isOuterJoin column indicates that the replacement will occur into a ** position in the parent that NULL-able due to an OUTER JOIN. Either the ** target slot in the parent is the right operand of a LEFT JOIN, or one of ** the left operands of a RIGHT JOIN. In either case, we need to potentially ** bypass the substituted expression with OP_IfNullRow. ** ** Suppose the original expression is an integer constant. Even though the table ** has the nullRow flag set, because the expression is an integer constant, ** it will not be NULLed out. So instead, we insert an OP_IfNullRow opcode ** that checks to see if the nullRow flag is set on the table. If the nullRow ** flag is set, then the value in the register is set to NULL and the original ** expression is bypassed. If the nullRow flag is not set, then the original ** expression runs to populate the register. ** ** Example where this is needed: ** ** CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT); ** CREATE TABLE t2(x INT UNIQUE); ** ** SELECT a,b,m,x FROM t1 LEFT JOIN (SELECT 59 AS m,x FROM t2) ON b=x; ** ** When the subquery on the right side of the LEFT JOIN is flattened, we ** have to add OP_IfNullRow in front of the OP_Integer that implements the ** "m" value of the subquery so that a NULL will be loaded instead of 59 ** when processing a non-matched row of the left. */ typedef struct SubstContext { Parse *pParse; /* The parsing context */ int iTable; /* Replace references to this table */ int iNewTable; /* New table number */ int isOuterJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */ ExprList *pEList; /* Replacement expressions */ ExprList *pCList; /* Collation sequences for replacement expr */ } SubstContext; /* Forward Declarations */ static void substExprList(SubstContext*, ExprList*); static void substSelect(SubstContext*, Select*, int); /* ** Scan through the expression pExpr. Replace every reference to ** a column in table number iTable with a copy of the iColumn-th ** entry in pEList. (But leave references to the ROWID column ** unchanged.) ** ** This routine is part of the flattening procedure. A subquery ** whose result set is defined by pEList appears as entry in the ** FROM clause of a SELECT such that the VDBE cursor assigned to that ** FORM clause entry is iTable. This routine makes the necessary ** changes to pExpr so that it refers directly to the source table ** of the subquery rather the result set of the subquery. */ static Expr *substExpr( SubstContext *pSubst, /* Description of the substitution */ Expr *pExpr /* Expr in which substitution occurs */ ){ if( pExpr==0 ) return 0; if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) && pExpr->w.iJoin==pSubst->iTable ){ testcase( ExprHasProperty(pExpr, EP_InnerON) ); pExpr->w.iJoin = pSubst->iNewTable; } if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable && !ExprHasProperty(pExpr, EP_FixedCol) ){ #ifdef SQLITE_ALLOW_ROWID_IN_VIEW if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; }else #endif { Expr *pNew; int iColumn; Expr *pCopy; Expr ifNullRow; iColumn = pExpr->iColumn; assert( iColumn>=0 ); assert( pSubst->pEList!=0 && iColumnpEList->nExpr ); assert( pExpr->pRight==0 ); pCopy = pSubst->pEList->a[iColumn].pExpr; if( sqlite3ExprIsVector(pCopy) ){ sqlite3VectorErrorMsg(pSubst->pParse, pCopy); }else{ sqlite3 *db = pSubst->pParse->db; if( pSubst->isOuterJoin && (pCopy->op!=TK_COLUMN || pCopy->iTable!=pSubst->iNewTable) ){ memset(&ifNullRow, 0, sizeof(ifNullRow)); ifNullRow.op = TK_IF_NULL_ROW; ifNullRow.pLeft = pCopy; ifNullRow.iTable = pSubst->iNewTable; ifNullRow.iColumn = -99; ifNullRow.flags = EP_IfNullRow; pCopy = &ifNullRow; } testcase( ExprHasProperty(pCopy, EP_Subquery) ); pNew = sqlite3ExprDup(db, pCopy, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pNew); return pExpr; } if( pSubst->isOuterJoin ){ ExprSetProperty(pNew, EP_CanBeNull); } if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){ sqlite3SetJoinExpr(pNew, pExpr->w.iJoin, pExpr->flags & (EP_OuterON|EP_InnerON)); } sqlite3ExprDelete(db, pExpr); pExpr = pNew; if( pExpr->op==TK_TRUEFALSE ){ pExpr->u.iValue = sqlite3ExprTruthValue(pExpr); pExpr->op = TK_INTEGER; ExprSetProperty(pExpr, EP_IntValue); } /* Ensure that the expression now has an implicit collation sequence, ** just as it did when it was a column of a view or sub-query. */ { CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pExpr); CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pSubst->pCList->a[iColumn].pExpr ); if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){ pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr, (pColl ? pColl->zName : "BINARY") ); } } ExprClearProperty(pExpr, EP_Collate); } } }else{ if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){ pExpr->iTable = pSubst->iNewTable; } pExpr->pLeft = substExpr(pSubst, pExpr->pLeft); pExpr->pRight = substExpr(pSubst, pExpr->pRight); if( ExprUseXSelect(pExpr) ){ substSelect(pSubst, pExpr->x.pSelect, 1); }else{ substExprList(pSubst, pExpr->x.pList); } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ Window *pWin = pExpr->y.pWin; pWin->pFilter = substExpr(pSubst, pWin->pFilter); substExprList(pSubst, pWin->pPartition); substExprList(pSubst, pWin->pOrderBy); } #endif } return pExpr; } static void substExprList( SubstContext *pSubst, /* Description of the substitution */ ExprList *pList /* List to scan and in which to make substitutes */ ){ int i; if( pList==0 ) return; for(i=0; inExpr; i++){ pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr); } } static void substSelect( SubstContext *pSubst, /* Description of the substitution */ Select *p, /* SELECT statement in which to make substitutions */ int doPrior /* Do substitutes on p->pPrior too */ ){ SrcList *pSrc; SrcItem *pItem; int i; if( !p ) return; do{ substExprList(pSubst, p->pEList); substExprList(pSubst, p->pGroupBy); substExprList(pSubst, p->pOrderBy); p->pHaving = substExpr(pSubst, p->pHaving); p->pWhere = substExpr(pSubst, p->pWhere); pSrc = p->pSrc; assert( pSrc!=0 ); for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ substSelect(pSubst, pItem->pSelect, 1); if( pItem->fg.isTabFunc ){ substExprList(pSubst, pItem->u1.pFuncArg); } } }while( doPrior && (p = p->pPrior)!=0 ); } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** pSelect is a SELECT statement and pSrcItem is one item in the FROM ** clause of that SELECT. ** ** This routine scans the entire SELECT statement and recomputes the ** pSrcItem->colUsed mask. */ static int recomputeColumnsUsedExpr(Walker *pWalker, Expr *pExpr){ SrcItem *pItem; if( pExpr->op!=TK_COLUMN ) return WRC_Continue; pItem = pWalker->u.pSrcItem; if( pItem->iCursor!=pExpr->iTable ) return WRC_Continue; if( pExpr->iColumn<0 ) return WRC_Continue; pItem->colUsed |= sqlite3ExprColUsed(pExpr); return WRC_Continue; } static void recomputeColumnsUsed( Select *pSelect, /* The complete SELECT statement */ SrcItem *pSrcItem /* Which FROM clause item to recompute */ ){ Walker w; if( NEVER(pSrcItem->pTab==0) ) return; memset(&w, 0, sizeof(w)); w.xExprCallback = recomputeColumnsUsedExpr; w.xSelectCallback = sqlite3SelectWalkNoop; w.u.pSrcItem = pSrcItem; pSrcItem->colUsed = 0; sqlite3WalkSelect(&w, pSelect); } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** Assign new cursor numbers to each of the items in pSrc. For each ** new cursor number assigned, set an entry in the aCsrMap[] array ** to map the old cursor number to the new: ** ** aCsrMap[iOld+1] = iNew; ** ** The array is guaranteed by the caller to be large enough for all ** existing cursor numbers in pSrc. aCsrMap[0] is the array size. ** ** If pSrc contains any sub-selects, call this routine recursively ** on the FROM clause of each such sub-select, with iExcept set to -1. */ static void srclistRenumberCursors( Parse *pParse, /* Parse context */ int *aCsrMap, /* Array to store cursor mappings in */ SrcList *pSrc, /* FROM clause to renumber */ int iExcept /* FROM clause item to skip */ ){ int i; SrcItem *pItem; for(i=0, pItem=pSrc->a; inSrc; i++, pItem++){ if( i!=iExcept ){ Select *p; assert( pItem->iCursor < aCsrMap[0] ); if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor+1]==0 ){ aCsrMap[pItem->iCursor+1] = pParse->nTab++; } pItem->iCursor = aCsrMap[pItem->iCursor+1]; for(p=pItem->pSelect; p; p=p->pPrior){ srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); } } } } /* ** *piCursor is a cursor number. Change it if it needs to be mapped. */ static void renumberCursorDoMapping(Walker *pWalker, int *piCursor){ int *aCsrMap = pWalker->u.aiCol; int iCsr = *piCursor; if( iCsr < aCsrMap[0] && aCsrMap[iCsr+1]>0 ){ *piCursor = aCsrMap[iCsr+1]; } } /* ** Expression walker callback used by renumberCursors() to update ** Expr objects to match newly assigned cursor numbers. */ static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){ int op = pExpr->op; if( op==TK_COLUMN || op==TK_IF_NULL_ROW ){ renumberCursorDoMapping(pWalker, &pExpr->iTable); } if( ExprHasProperty(pExpr, EP_OuterON) ){ renumberCursorDoMapping(pWalker, &pExpr->w.iJoin); } return WRC_Continue; } /* ** Assign a new cursor number to each cursor in the FROM clause (Select.pSrc) ** of the SELECT statement passed as the second argument, and to each ** cursor in the FROM clause of any FROM clause sub-selects, recursively. ** Except, do not assign a new cursor number to the iExcept'th element in ** the FROM clause of (*p). Update all expressions and other references ** to refer to the new cursor numbers. ** ** Argument aCsrMap is an array that may be used for temporary working ** space. Two guarantees are made by the caller: ** ** * the array is larger than the largest cursor number used within the ** select statement passed as an argument, and ** ** * the array entries for all cursor numbers that do *not* appear in ** FROM clauses of the select statement as described above are ** initialized to zero. */ static void renumberCursors( Parse *pParse, /* Parse context */ Select *p, /* Select to renumber cursors within */ int iExcept, /* FROM clause item to skip */ int *aCsrMap /* Working space */ ){ Walker w; srclistRenumberCursors(pParse, aCsrMap, p->pSrc, iExcept); memset(&w, 0, sizeof(w)); w.u.aiCol = aCsrMap; w.xExprCallback = renumberCursorsCb; w.xSelectCallback = sqlite3SelectWalkNoop; sqlite3WalkSelect(&w, p); } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* ** If pSel is not part of a compound SELECT, return a pointer to its ** expression list. Otherwise, return a pointer to the expression list ** of the leftmost SELECT in the compound. */ static ExprList *findLeftmostExprlist(Select *pSel){ while( pSel->pPrior ){ pSel = pSel->pPrior; } return pSel->pEList; } /* ** Return true if any of the result-set columns in the compound query ** have incompatible affinities on one or more arms of the compound. */ static int compoundHasDifferentAffinities(Select *p){ int ii; ExprList *pList; assert( p!=0 ); assert( p->pEList!=0 ); assert( p->pPrior!=0 ); pList = p->pEList; for(ii=0; iinExpr; ii++){ char aff; Select *pSub1; assert( pList->a[ii].pExpr!=0 ); aff = sqlite3ExprAffinity(pList->a[ii].pExpr); for(pSub1=p->pPrior; pSub1; pSub1=pSub1->pPrior){ assert( pSub1->pEList!=0 ); assert( pSub1->pEList->nExpr>ii ); assert( pSub1->pEList->a[ii].pExpr!=0 ); if( sqlite3ExprAffinity(pSub1->pEList->a[ii].pExpr)!=aff ){ return 1; } } } return 0; } #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** This routine attempts to flatten subqueries as a performance optimization. ** This routine returns 1 if it makes changes and 0 if no flattening occurs. ** ** To understand the concept of flattening, consider the following ** query: ** ** SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5 ** ** The default way of implementing this query is to execute the ** subquery first and store the results in a temporary table, then ** run the outer query on that temporary table. This requires two ** passes over the data. Furthermore, because the temporary table ** has no indices, the WHERE clause on the outer query cannot be ** optimized. ** ** This routine attempts to rewrite queries such as the above into ** a single flat select, like this: ** ** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5 ** ** The code generated for this simplification gives the same result ** but only has to scan the data once. And because indices might ** exist on the table t1, a complete scan of the data might be ** avoided. ** ** Flattening is subject to the following constraints: ** ** (**) We no longer attempt to flatten aggregate subqueries. Was: ** The subquery and the outer query cannot both be aggregates. ** ** (**) We no longer attempt to flatten aggregate subqueries. Was: ** (2) If the subquery is an aggregate then ** (2a) the outer query must not be a join and ** (2b) the outer query must not use subqueries ** other than the one FROM-clause subquery that is a candidate ** for flattening. (This is due to ticket [2f7170d73bf9abf80] ** from 2015-02-09.) ** ** (3) If the subquery is the right operand of a LEFT JOIN then ** (3a) the subquery may not be a join and ** (3b) the FROM clause of the subquery may not contain a virtual ** table and ** (**) Was: "The outer query may not have a GROUP BY." This case ** is now managed correctly ** (3d) the outer query may not be DISTINCT. ** See also (26) for restrictions on RIGHT JOIN. ** ** (4) The subquery can not be DISTINCT. ** ** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT ** sub-queries that were excluded from this optimization. Restriction ** (4) has since been expanded to exclude all DISTINCT subqueries. ** ** (**) We no longer attempt to flatten aggregate subqueries. Was: ** If the subquery is aggregate, the outer query may not be DISTINCT. ** ** (7) The subquery must have a FROM clause. TODO: For subqueries without ** A FROM clause, consider adding a FROM clause with the special ** table sqlite_once that consists of a single row containing a ** single NULL. ** ** (8) If the subquery uses LIMIT then the outer query may not be a join. ** ** (9) If the subquery uses LIMIT then the outer query may not be aggregate. ** ** (**) Restriction (10) was removed from the code on 2005-02-05 but we ** accidentally carried the comment forward until 2014-09-15. Original ** constraint: "If the subquery is aggregate then the outer query ** may not use LIMIT." ** ** (11) The subquery and the outer query may not both have ORDER BY clauses. ** ** (**) Not implemented. Subsumed into restriction (3). Was previously ** a separate restriction deriving from ticket #350. ** ** (13) The subquery and outer query may not both use LIMIT. ** ** (14) The subquery may not use OFFSET. ** ** (15) If the outer query is part of a compound select, then the ** subquery may not use LIMIT. ** (See ticket #2339 and ticket [02a8e81d44]). ** ** (16) If the outer query is aggregate, then the subquery may not ** use ORDER BY. (Ticket #2942) This used to not matter ** until we introduced the group_concat() function. ** ** (17) If the subquery is a compound select, then ** (17a) all compound operators must be a UNION ALL, and ** (17b) no terms within the subquery compound may be aggregate ** or DISTINCT, and ** (17c) every term within the subquery compound must have a FROM clause ** (17d) the outer query may not be ** (17d1) aggregate, or ** (17d2) DISTINCT ** (17e) the subquery may not contain window functions, and ** (17f) the subquery must not be the RHS of a LEFT JOIN. ** (17g) either the subquery is the first element of the outer ** query or there are no RIGHT or FULL JOINs in any arm ** of the subquery. (This is a duplicate of condition (27b).) ** (17h) The corresponding result set expressions in all arms of the ** compound must have the same affinity. ** ** The parent and sub-query may contain WHERE clauses. Subject to ** rules (11), (13) and (14), they may also contain ORDER BY, ** LIMIT and OFFSET clauses. The subquery cannot use any compound ** operator other than UNION ALL because all the other compound ** operators have an implied DISTINCT which is disallowed by ** restriction (4). ** ** Also, each component of the sub-query must return the same number ** of result columns. This is actually a requirement for any compound ** SELECT statement, but all the code here does is make sure that no ** such (illegal) sub-query is flattened. The caller will detect the ** syntax error and return a detailed message. ** ** (18) If the sub-query is a compound select, then all terms of the ** ORDER BY clause of the parent must be copies of a term returned ** by the parent query. ** ** (19) If the subquery uses LIMIT then the outer query may not ** have a WHERE clause. ** ** (20) If the sub-query is a compound select, then it must not use ** an ORDER BY clause. Ticket #3773. We could relax this constraint ** somewhat by saying that the terms of the ORDER BY clause must ** appear as unmodified result columns in the outer query. But we ** have other optimizations in mind to deal with that case. ** ** (21) If the subquery uses LIMIT then the outer query may not be ** DISTINCT. (See ticket [752e1646fc]). ** ** (22) The subquery may not be a recursive CTE. ** ** (23) If the outer query is a recursive CTE, then the sub-query may not be ** a compound query. This restriction is because transforming the ** parent to a compound query confuses the code that handles ** recursive queries in multiSelect(). ** ** (**) We no longer attempt to flatten aggregate subqueries. Was: ** The subquery may not be an aggregate that uses the built-in min() or ** or max() functions. (Without this restriction, a query like: ** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily ** return the value X for which Y was maximal.) ** ** (25) If either the subquery or the parent query contains a window ** function in the select list or ORDER BY clause, flattening ** is not attempted. ** ** (26) The subquery may not be the right operand of a RIGHT JOIN. ** See also (3) for restrictions on LEFT JOIN. ** ** (27) The subquery may not contain a FULL or RIGHT JOIN unless it ** is the first element of the parent query. Two subcases: ** (27a) the subquery is not a compound query. ** (27b) the subquery is a compound query and the RIGHT JOIN occurs ** in any arm of the compound query. (See also (17g).) ** ** (28) The subquery is not a MATERIALIZED CTE. (This is handled ** in the caller before ever reaching this routine.) ** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and returns 0. ** If flattening is attempted this routine returns 1. ** ** All of the expression analysis must occur on both the outer query and ** the subquery before this routine runs. */ static int flattenSubquery( Parse *pParse, /* Parsing context */ Select *p, /* The parent or outer SELECT statement */ int iFrom, /* Index in p->pSrc->a[] of the inner subquery */ int isAgg /* True if outer SELECT uses aggregate functions */ ){ const char *zSavedAuthContext = pParse->zAuthContext; Select *pParent; /* Current UNION ALL term of the other query */ Select *pSub; /* The inner query or "subquery" */ Select *pSub1; /* Pointer to the rightmost select in sub-query */ SrcList *pSrc; /* The FROM clause of the outer query */ SrcList *pSubSrc; /* The FROM clause of the subquery */ int iParent; /* VDBE cursor number of the pSub result set temp table */ int iNewParent = -1;/* Replacement table for iParent */ int isOuterJoin = 0; /* True if pSub is the right side of a LEFT JOIN */ int i; /* Loop counter */ Expr *pWhere; /* The WHERE clause */ SrcItem *pSubitem; /* The subquery */ sqlite3 *db = pParse->db; Walker w; /* Walker to persist agginfo data */ int *aCsrMap = 0; /* Check to see if flattening is permitted. Return 0 if not. */ assert( p!=0 ); assert( p->pPrior==0 ); if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0; pSrc = p->pSrc; assert( pSrc && iFrom>=0 && iFromnSrc ); pSubitem = &pSrc->a[iFrom]; iParent = pSubitem->iCursor; pSub = pSubitem->pSelect; assert( pSub!=0 ); #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWin || pSub->pWin ) return 0; /* Restriction (25) */ #endif pSubSrc = pSub->pSrc; assert( pSubSrc ); /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, ** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET ** because they could be computed at compile-time. But when LIMIT and OFFSET ** became arbitrary expressions, we were forced to add restrictions (13) ** and (14). */ if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */ if( pSub->pLimit && pSub->pLimit->pRight ) return 0; /* Restriction (14) */ if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){ return 0; /* Restriction (15) */ } if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */ if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (4) */ if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){ return 0; /* Restrictions (8)(9) */ } if( p->pOrderBy && pSub->pOrderBy ){ return 0; /* Restriction (11) */ } if( isAgg && pSub->pOrderBy ) return 0; /* Restriction (16) */ if( pSub->pLimit && p->pWhere ) return 0; /* Restriction (19) */ if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){ return 0; /* Restriction (21) */ } if( pSub->selFlags & (SF_Recursive) ){ return 0; /* Restrictions (22) */ } /* ** If the subquery is the right operand of a LEFT JOIN, then the ** subquery may not be a join itself (3a). Example of why this is not ** allowed: ** ** t1 LEFT OUTER JOIN (t2 JOIN t3) ** ** If we flatten the above, we would get ** ** (t1 LEFT OUTER JOIN t2) JOIN t3 ** ** which is not at all the same thing. ** ** See also tickets #306, #350, and #3300. */ if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){ if( pSubSrc->nSrc>1 /* (3a) */ || IsVirtual(pSubSrc->a[0].pTab) /* (3b) */ || (p->selFlags & SF_Distinct)!=0 /* (3d) */ || (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */ ){ return 0; } isOuterJoin = 1; } assert( pSubSrc->nSrc>0 ); /* True by restriction (7) */ if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ return 0; /* Restriction (27a) */ } /* Condition (28) is blocked by the caller */ assert( !pSubitem->fg.isCte || pSubitem->u2.pCteUse->eM10d!=M10d_Yes ); /* Restriction (17): If the sub-query is a compound SELECT, then it must ** use only the UNION ALL operator. And none of the simple select queries ** that make up the compound SELECT are allowed to be aggregate or distinct ** queries. */ if( pSub->pPrior ){ int ii; if( pSub->pOrderBy ){ return 0; /* Restriction (20) */ } if( isAgg || (p->selFlags & SF_Distinct)!=0 || isOuterJoin>0 ){ return 0; /* (17d1), (17d2), or (17f) */ } for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){ testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate ); assert( pSub->pSrc!=0 ); assert( (pSub->selFlags & SF_Recursive)==0 ); assert( pSub->pEList->nExpr==pSub1->pEList->nExpr ); if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */ || (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */ || pSub1->pSrc->nSrc<1 /* (17c) */ #ifndef SQLITE_OMIT_WINDOWFUNC || pSub1->pWin /* (17e) */ #endif ){ return 0; } if( iFrom>0 && (pSub1->pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ /* Without this restriction, the JT_LTORJ flag would end up being ** omitted on left-hand tables of the right join that is being ** flattened. */ return 0; /* Restrictions (17g), (27b) */ } testcase( pSub1->pSrc->nSrc>1 ); } /* Restriction (18). */ if( p->pOrderBy ){ for(ii=0; iipOrderBy->nExpr; ii++){ if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0; } } /* Restriction (23) */ if( (p->selFlags & SF_Recursive) ) return 0; /* Restriction (17h) */ if( compoundHasDifferentAffinities(pSub) ) return 0; if( pSrc->nSrc>1 ){ if( pParse->nSelect>500 ) return 0; if( OptimizationDisabled(db, SQLITE_FlttnUnionAll) ) return 0; aCsrMap = sqlite3DbMallocZero(db, ((i64)pParse->nTab+1)*sizeof(int)); if( aCsrMap ) aCsrMap[0] = pParse->nTab; } } /***** If we reach this point, flattening is permitted. *****/ TREETRACE(0x4,pParse,p,("flatten %u.%p from term %d\n", pSub->selId, pSub, iFrom)); /* Authorize the subquery */ pParse->zAuthContext = pSubitem->zName; TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0); testcase( i==SQLITE_DENY ); pParse->zAuthContext = zSavedAuthContext; /* Delete the transient structures associated with the subquery */ pSub1 = pSubitem->pSelect; sqlite3DbFree(db, pSubitem->zDatabase); sqlite3DbFree(db, pSubitem->zName); sqlite3DbFree(db, pSubitem->zAlias); pSubitem->zDatabase = 0; pSubitem->zName = 0; pSubitem->zAlias = 0; pSubitem->pSelect = 0; assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 ); /* If the sub-query is a compound SELECT statement, then (by restrictions ** 17 and 18 above) it must be a UNION ALL and the parent query must ** be of the form: ** ** SELECT FROM () ** ** followed by any ORDER BY, LIMIT and/or OFFSET clauses. This block ** creates N-1 copies of the parent query without any ORDER BY, LIMIT or ** OFFSET clauses and joins them to the left-hand-side of the original ** using UNION ALL operators. In this case N is the number of simple ** select statements in the compound sub-query. ** ** Example: ** ** SELECT a+1 FROM ( ** SELECT x FROM tab ** UNION ALL ** SELECT y FROM tab ** UNION ALL ** SELECT abs(z*2) FROM tab2 ** ) WHERE a!=5 ORDER BY 1 ** ** Transformed into: ** ** SELECT x+1 FROM tab WHERE x+1!=5 ** UNION ALL ** SELECT y+1 FROM tab WHERE y+1!=5 ** UNION ALL ** SELECT abs(z*2)+1 FROM tab2 WHERE abs(z*2)+1!=5 ** ORDER BY 1 ** ** We call this the "compound-subquery flattening". */ for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){ Select *pNew; ExprList *pOrderBy = p->pOrderBy; Expr *pLimit = p->pLimit; Select *pPrior = p->pPrior; Table *pItemTab = pSubitem->pTab; pSubitem->pTab = 0; p->pOrderBy = 0; p->pPrior = 0; p->pLimit = 0; pNew = sqlite3SelectDup(db, p, 0); p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->op = TK_ALL; pSubitem->pTab = pItemTab; if( pNew==0 ){ p->pPrior = pPrior; }else{ pNew->selId = ++pParse->nSelect; if( aCsrMap && ALWAYS(db->mallocFailed==0) ){ renumberCursors(pParse, pNew, iFrom, aCsrMap); } pNew->pPrior = pPrior; if( pPrior ) pPrior->pNext = pNew; pNew->pNext = p; p->pPrior = pNew; TREETRACE(0x4,pParse,p,("compound-subquery flattener" " creates %u as peer\n",pNew->selId)); } assert( pSubitem->pSelect==0 ); } sqlite3DbFree(db, aCsrMap); if( db->mallocFailed ){ pSubitem->pSelect = pSub1; return 1; } /* Defer deleting the Table object associated with the ** subquery until code generation is ** complete, since there may still exist Expr.pTab entries that ** refer to the subquery even after flattening. Ticket #3346. ** ** pSubitem->pTab is always non-NULL by test restrictions and tests above. */ if( ALWAYS(pSubitem->pTab!=0) ){ Table *pTabToDel = pSubitem->pTab; if( pTabToDel->nTabRef==1 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel); testcase( pToplevel->earlyCleanup ); }else{ pTabToDel->nTabRef--; } pSubitem->pTab = 0; } /* The following loop runs once for each term in a compound-subquery ** flattening (as described above). If we are doing a different kind ** of flattening - a flattening other than a compound-subquery flattening - ** then this loop only runs once. ** ** This loop moves all of the FROM elements of the subquery into the ** the FROM clause of the outer query. Before doing this, remember ** the cursor number for the original outer query FROM element in ** iParent. The iParent cursor will never be used. Subsequent code ** will scan expressions looking for iParent references and replace ** those references with expressions that resolve to the subquery FROM ** elements we are now copying in. */ pSub = pSub1; for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){ int nSubSrc; u8 jointype = 0; u8 ltorj = pSrc->a[iFrom].fg.jointype & JT_LTORJ; assert( pSub!=0 ); pSubSrc = pSub->pSrc; /* FROM clause of subquery */ nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */ pSrc = pParent->pSrc; /* FROM clause of the outer query */ if( pParent==p ){ jointype = pSubitem->fg.jointype; /* First time through the loop */ } /* The subquery uses a single slot of the FROM clause of the outer ** query. If the subquery has more than one element in its FROM clause, ** then expand the outer query to make space for it to hold all elements ** of the subquery. ** ** Example: ** ** SELECT * FROM tabA, (SELECT * FROM sub1, sub2), tabB; ** ** The outer query has 3 slots in its FROM clause. One slot of the ** outer query (the middle slot) is used by the subquery. The next ** block of code will expand the outer query FROM clause to 4 slots. ** The middle slot is expanded to two slots in order to make space ** for the two elements in the FROM clause of the subquery. */ if( nSubSrc>1 ){ pSrc = sqlite3SrcListEnlarge(pParse, pSrc, nSubSrc-1,iFrom+1); if( pSrc==0 ) break; pParent->pSrc = pSrc; } /* Transfer the FROM clause terms from the subquery into the ** outer query. */ for(i=0; ia[i+iFrom]; if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing); assert( pItem->fg.isTabFunc==0 ); *pItem = pSubSrc->a[i]; pItem->fg.jointype |= ltorj; iNewParent = pSubSrc->a[i].iCursor; memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); } pSrc->a[iFrom].fg.jointype &= JT_LTORJ; pSrc->a[iFrom].fg.jointype |= jointype | ltorj; /* Now begin substituting subquery result set expressions for ** references to the iParent in the outer query. ** ** Example: ** ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b; ** \ \_____________ subquery __________/ / ** \_____________________ outer query ______________________________/ ** ** We look at every expression in the outer query and every place we see ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". */ if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){ /* At this point, any non-zero iOrderByCol values indicate that the ** ORDER BY column expression is identical to the iOrderByCol'th ** expression returned by SELECT statement pSub. Since these values ** do not necessarily correspond to columns in SELECT statement pParent, ** zero them before transferring the ORDER BY clause. ** ** Not doing this may cause an error if a subsequent call to this ** function attempts to flatten a compound sub-query into pParent ** (the only way this can happen is if the compound sub-query is ** currently part of pSub->pSrc). See ticket [d11a6e908f]. */ ExprList *pOrderBy = pSub->pOrderBy; for(i=0; inExpr; i++){ pOrderBy->a[i].u.x.iOrderByCol = 0; } assert( pParent->pOrderBy==0 ); pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; } pWhere = pSub->pWhere; pSub->pWhere = 0; if( isOuterJoin>0 ){ sqlite3SetJoinExpr(pWhere, iNewParent, EP_OuterON); } if( pWhere ){ if( pParent->pWhere ){ pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere); }else{ pParent->pWhere = pWhere; } } if( db->mallocFailed==0 ){ SubstContext x; x.pParse = pParse; x.iTable = iParent; x.iNewTable = iNewParent; x.isOuterJoin = isOuterJoin; x.pEList = pSub->pEList; x.pCList = findLeftmostExprlist(pSub); substSelect(&x, pParent, 0); } /* The flattened query is a compound if either the inner or the ** outer query is a compound. */ pParent->selFlags |= pSub->selFlags & SF_Compound; assert( (pSub->selFlags & SF_Distinct)==0 ); /* restriction (17b) */ /* ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y; ** ** One is tempted to try to add a and b to combine the limits. But this ** does not work if either limit is negative. */ if( pSub->pLimit ){ pParent->pLimit = pSub->pLimit; pSub->pLimit = 0; } /* Recompute the SrcItem.colUsed masks for the flattened ** tables. */ for(i=0; ia[i+iFrom]); } } /* Finally, delete what is left of the subquery and return success. */ sqlite3AggInfoPersistWalkerInit(&w, pParse); sqlite3WalkSelect(&w,pSub1); sqlite3SelectDelete(db, pSub1); #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x4 ){ TREETRACE(0x4,pParse,p,("After flattening:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* ** A structure to keep track of all of the column values that are fixed to ** a known value due to WHERE clause constraints of the form COLUMN=VALUE. */ typedef struct WhereConst WhereConst; struct WhereConst { Parse *pParse; /* Parsing context */ u8 *pOomFault; /* Pointer to pParse->db->mallocFailed */ int nConst; /* Number for COLUMN=CONSTANT terms */ int nChng; /* Number of times a constant is propagated */ int bHasAffBlob; /* At least one column in apExpr[] as affinity BLOB */ u32 mExcludeOn; /* Which ON expressions to exclude from considertion. ** Either EP_OuterON or EP_InnerON|EP_OuterON */ Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */ }; /* ** Add a new entry to the pConst object. Except, do not add duplicate ** pColumn entries. Also, do not add if doing so would not be appropriate. ** ** The caller guarantees the pColumn is a column and pValue is a constant. ** This routine has to do some additional checks before completing the ** insert. */ static void constInsert( WhereConst *pConst, /* The WhereConst into which we are inserting */ Expr *pColumn, /* The COLUMN part of the constraint */ Expr *pValue, /* The VALUE part of the constraint */ Expr *pExpr /* Overall expression: COLUMN=VALUE or VALUE=COLUMN */ ){ int i; assert( pColumn->op==TK_COLUMN ); assert( sqlite3ExprIsConstant(pValue) ); if( ExprHasProperty(pColumn, EP_FixedCol) ) return; if( sqlite3ExprAffinity(pValue)!=0 ) return; if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr)) ){ return; } /* 2018-10-25 ticket [cf5ed20f] ** Make sure the same pColumn is not inserted more than once */ for(i=0; inConst; i++){ const Expr *pE2 = pConst->apExpr[i*2]; assert( pE2->op==TK_COLUMN ); if( pE2->iTable==pColumn->iTable && pE2->iColumn==pColumn->iColumn ){ return; /* Already present. Return without doing anything. */ } } if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ pConst->bHasAffBlob = 1; } pConst->nConst++; pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr, pConst->nConst*2*sizeof(Expr*)); if( pConst->apExpr==0 ){ pConst->nConst = 0; }else{ pConst->apExpr[pConst->nConst*2-2] = pColumn; pConst->apExpr[pConst->nConst*2-1] = pValue; } } /* ** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE ** is a constant expression and where the term must be true because it ** is part of the AND-connected terms of the expression. For each term ** found, add it to the pConst structure. */ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ Expr *pRight, *pLeft; if( NEVER(pExpr==0) ) return; if( ExprHasProperty(pExpr, pConst->mExcludeOn) ){ testcase( ExprHasProperty(pExpr, EP_OuterON) ); testcase( ExprHasProperty(pExpr, EP_InnerON) ); return; } if( pExpr->op==TK_AND ){ findConstInWhere(pConst, pExpr->pRight); findConstInWhere(pConst, pExpr->pLeft); return; } if( pExpr->op!=TK_EQ ) return; pRight = pExpr->pRight; pLeft = pExpr->pLeft; assert( pRight!=0 ); assert( pLeft!=0 ); if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){ constInsert(pConst,pRight,pLeft,pExpr); } if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){ constInsert(pConst,pLeft,pRight,pExpr); } } /* ** This is a helper function for Walker callback propagateConstantExprRewrite(). ** ** Argument pExpr is a candidate expression to be replaced by a value. If ** pExpr is equivalent to one of the columns named in pWalker->u.pConst, ** then overwrite it with the corresponding value. Except, do not do so ** if argument bIgnoreAffBlob is non-zero and the affinity of pExpr ** is SQLITE_AFF_BLOB. */ static int propagateConstantExprRewriteOne( WhereConst *pConst, Expr *pExpr, int bIgnoreAffBlob ){ int i; if( pConst->pOomFault[0] ) return WRC_Prune; if( pExpr->op!=TK_COLUMN ) return WRC_Continue; if( ExprHasProperty(pExpr, EP_FixedCol|pConst->mExcludeOn) ){ testcase( ExprHasProperty(pExpr, EP_FixedCol) ); testcase( ExprHasProperty(pExpr, EP_OuterON) ); testcase( ExprHasProperty(pExpr, EP_InnerON) ); return WRC_Continue; } for(i=0; inConst; i++){ Expr *pColumn = pConst->apExpr[i*2]; if( pColumn==pExpr ) continue; if( pColumn->iTable!=pExpr->iTable ) continue; if( pColumn->iColumn!=pExpr->iColumn ) continue; if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ break; } /* A match is found. Add the EP_FixedCol property */ pConst->nChng++; ExprClearProperty(pExpr, EP_Leaf); ExprSetProperty(pExpr, EP_FixedCol); assert( pExpr->pLeft==0 ); pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0); if( pConst->pParse->db->mallocFailed ) return WRC_Prune; break; } return WRC_Prune; } /* ** This is a Walker expression callback. pExpr is a node from the WHERE ** clause of a SELECT statement. This function examines pExpr to see if ** any substitutions based on the contents of pWalker->u.pConst should ** be made to pExpr or its immediate children. ** ** A substitution is made if: ** ** + pExpr is a column with an affinity other than BLOB that matches ** one of the columns in pWalker->u.pConst, or ** ** + pExpr is a binary comparison operator (=, <=, >=, <, >) that ** uses an affinity other than TEXT and one of its immediate ** children is a column that matches one of the columns in ** pWalker->u.pConst. */ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){ WhereConst *pConst = pWalker->u.pConst; assert( TK_GT==TK_EQ+1 ); assert( TK_LE==TK_EQ+2 ); assert( TK_LT==TK_EQ+3 ); assert( TK_GE==TK_EQ+4 ); if( pConst->bHasAffBlob ){ if( (pExpr->op>=TK_EQ && pExpr->op<=TK_GE) || pExpr->op==TK_IS ){ propagateConstantExprRewriteOne(pConst, pExpr->pLeft, 0); if( pConst->pOomFault[0] ) return WRC_Prune; if( sqlite3ExprAffinity(pExpr->pLeft)!=SQLITE_AFF_TEXT ){ propagateConstantExprRewriteOne(pConst, pExpr->pRight, 0); } } } return propagateConstantExprRewriteOne(pConst, pExpr, pConst->bHasAffBlob); } /* ** The WHERE-clause constant propagation optimization. ** ** If the WHERE clause contains terms of the form COLUMN=CONSTANT or ** CONSTANT=COLUMN that are top-level AND-connected terms that are not ** part of a ON clause from a LEFT JOIN, then throughout the query ** replace all other occurrences of COLUMN with CONSTANT. ** ** For example, the query: ** ** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=t1.a AND t3.c=t2.b ** ** Is transformed into ** ** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=39 AND t3.c=39 ** ** Return true if any transformations where made and false if not. ** ** Implementation note: Constant propagation is tricky due to affinity ** and collating sequence interactions. Consider this example: ** ** CREATE TABLE t1(a INT,b TEXT); ** INSERT INTO t1 VALUES(123,'0123'); ** SELECT * FROM t1 WHERE a=123 AND b=a; ** SELECT * FROM t1 WHERE a=123 AND b=123; ** ** The two SELECT statements above should return different answers. b=a ** is always true because the comparison uses numeric affinity, but b=123 ** is false because it uses text affinity and '0123' is not the same as '123'. ** To work around this, the expression tree is not actually changed from ** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol ** and the "123" value is hung off of the pLeft pointer. Code generator ** routines know to generate the constant "123" instead of looking up the ** column value. Also, to avoid collation problems, this optimization is ** only attempted if the "a=123" term uses the default BINARY collation. ** ** 2021-05-25 forum post 6a06202608: Another troublesome case is... ** ** CREATE TABLE t1(x); ** INSERT INTO t1 VALUES(10.0); ** SELECT 1 FROM t1 WHERE x=10 AND x LIKE 10; ** ** The query should return no rows, because the t1.x value is '10.0' not '10' ** and '10.0' is not LIKE '10'. But if we are not careful, the first WHERE ** term "x=10" will cause the second WHERE term to become "10 LIKE 10", ** resulting in a false positive. To avoid this, constant propagation for ** columns with BLOB affinity is only allowed if the constant is used with ** operators ==, <=, <, >=, >, or IS in a way that will cause the correct ** type conversions to occur. See logic associated with the bHasAffBlob flag ** for details. */ static int propagateConstants( Parse *pParse, /* The parsing context */ Select *p /* The query in which to propagate constants */ ){ WhereConst x; Walker w; int nChng = 0; x.pParse = pParse; x.pOomFault = &pParse->db->mallocFailed; do{ x.nConst = 0; x.nChng = 0; x.apExpr = 0; x.bHasAffBlob = 0; if( ALWAYS(p->pSrc!=0) && p->pSrc->nSrc>0 && (p->pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ /* Do not propagate constants on any ON clause if there is a ** RIGHT JOIN anywhere in the query */ x.mExcludeOn = EP_InnerON | EP_OuterON; }else{ /* Do not propagate constants through the ON clause of a LEFT JOIN */ x.mExcludeOn = EP_OuterON; } findConstInWhere(&x, p->pWhere); if( x.nConst ){ memset(&w, 0, sizeof(w)); w.pParse = pParse; w.xExprCallback = propagateConstantExprRewrite; w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback2 = 0; w.walkerDepth = 0; w.u.pConst = &x; sqlite3WalkExpr(&w, p->pWhere); sqlite3DbFree(x.pParse->db, x.apExpr); nChng += x.nChng; } }while( x.nChng ); return nChng; } #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) # if !defined(SQLITE_OMIT_WINDOWFUNC) /* ** This function is called to determine whether or not it is safe to ** push WHERE clause expression pExpr down to FROM clause sub-query ** pSubq, which contains at least one window function. Return 1 ** if it is safe and the expression should be pushed down, or 0 ** otherwise. ** ** It is only safe to push the expression down if it consists only ** of constants and copies of expressions that appear in the PARTITION ** BY clause of all window function used by the sub-query. It is safe ** to filter out entire partitions, but not rows within partitions, as ** this may change the results of the window functions. ** ** At the time this function is called it is guaranteed that ** ** * the sub-query uses only one distinct window frame, and ** * that the window frame has a PARTITION BY clause. */ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){ assert( pSubq->pWin->pPartition ); assert( (pSubq->selFlags & SF_MultiPart)==0 ); assert( pSubq->pPrior==0 ); return sqlite3ExprIsConstantOrGroupBy(pParse, pExpr, pSubq->pWin->pPartition); } # endif /* SQLITE_OMIT_WINDOWFUNC */ #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** Make copies of relevant WHERE clause terms of the outer query into ** the WHERE clause of subquery. Example: ** ** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10; ** ** Transformed into: ** ** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1 WHERE a=5 AND c-d=10) ** WHERE x=5 AND y=10; ** ** The hope is that the terms added to the inner query will make it more ** efficient. ** ** Do not attempt this optimization if: ** ** (1) (** This restriction was removed on 2017-09-29. We used to ** disallow this optimization for aggregate subqueries, but now ** it is allowed by putting the extra terms on the HAVING clause. ** The added HAVING clause is pointless if the subquery lacks ** a GROUP BY clause. But such a HAVING clause is also harmless ** so there does not appear to be any reason to add extra logic ** to suppress it. **) ** ** (2) The inner query is the recursive part of a common table expression. ** ** (3) The inner query has a LIMIT clause (since the changes to the WHERE ** clause would change the meaning of the LIMIT). ** ** (4) The inner query is the right operand of a LEFT JOIN and the ** expression to be pushed down does not come from the ON clause ** on that LEFT JOIN. ** ** (5) The WHERE clause expression originates in the ON or USING clause ** of a LEFT JOIN where iCursor is not the right-hand table of that ** left join. An example: ** ** SELECT * ** FROM (SELECT 1 AS a1 UNION ALL SELECT 2) AS aa ** JOIN (SELECT 1 AS b2 UNION ALL SELECT 2) AS bb ON (a1=b2) ** LEFT JOIN (SELECT 8 AS c3 UNION ALL SELECT 9) AS cc ON (b2=2); ** ** The correct answer is three rows: (1,1,NULL),(2,2,8),(2,2,9). ** But if the (b2=2) term were to be pushed down into the bb subquery, ** then the (1,1,NULL) row would be suppressed. ** ** (6) Window functions make things tricky as changes to the WHERE clause ** of the inner query could change the window over which window ** functions are calculated. Therefore, do not attempt the optimization ** if: ** ** (6a) The inner query uses multiple incompatible window partitions. ** ** (6b) The inner query is a compound and uses window-functions. ** ** (6c) The WHERE clause does not consist entirely of constants and ** copies of expressions found in the PARTITION BY clause of ** all window-functions used by the sub-query. It is safe to ** filter out entire partitions, as this does not change the ** window over which any window-function is calculated. ** ** (7) The inner query is a Common Table Expression (CTE) that should ** be materialized. (This restriction is implemented in the calling ** routine.) ** ** (8) If the subquery is a compound that uses UNION, INTERSECT, ** or EXCEPT, then all of the result set columns for all arms of ** the compound must use the BINARY collating sequence. ** ** (9) All three of the following are true: ** ** (9a) The WHERE clause expression originates in the ON or USING clause ** of a join (either an INNER or an OUTER join), and ** ** (9b) The subquery is to the right of the ON/USING clause ** ** (9c) There is a RIGHT JOIN (or FULL JOIN) in between the ON/USING ** clause and the subquery. ** ** Without this restriction, the push-down optimization might move ** the ON/USING filter expression from the left side of a RIGHT JOIN ** over to the right side, which leads to incorrect answers. See ** also restriction (6) in sqlite3ExprIsSingleTableConstraint(). ** ** (10) The inner query is not the right-hand table of a RIGHT JOIN. ** ** (11) The subquery is not a VALUES clause ** ** Return 0 if no changes are made and non-zero if one or more WHERE clause ** terms are duplicated into the subquery. */ static int pushDownWhereTerms( Parse *pParse, /* Parse context (for malloc() and error reporting) */ Select *pSubq, /* The subquery whose WHERE clause is to be augmented */ Expr *pWhere, /* The WHERE clause of the outer query */ SrcList *pSrcList, /* The complete from clause of the outer query */ int iSrc /* Which FROM clause term to try to push into */ ){ Expr *pNew; SrcItem *pSrc; /* The subquery FROM term into which WHERE is pushed */ int nChng = 0; pSrc = &pSrcList->a[iSrc]; if( pWhere==0 ) return 0; if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ){ return 0; /* restrictions (2) and (11) */ } if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ){ return 0; /* restrictions (10) */ } if( pSubq->pPrior ){ Select *pSel; int notUnionAll = 0; for(pSel=pSubq; pSel; pSel=pSel->pPrior){ u8 op = pSel->op; assert( op==TK_ALL || op==TK_SELECT || op==TK_UNION || op==TK_INTERSECT || op==TK_EXCEPT ); if( op!=TK_ALL && op!=TK_SELECT ){ notUnionAll = 1; } #ifndef SQLITE_OMIT_WINDOWFUNC if( pSel->pWin ) return 0; /* restriction (6b) */ #endif } if( notUnionAll ){ /* If any of the compound arms are connected using UNION, INTERSECT, ** or EXCEPT, then we must ensure that none of the columns use a ** non-BINARY collating sequence. */ for(pSel=pSubq; pSel; pSel=pSel->pPrior){ int ii; const ExprList *pList = pSel->pEList; assert( pList!=0 ); for(ii=0; iinExpr; ii++){ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[ii].pExpr); if( !sqlite3IsBinary(pColl) ){ return 0; /* Restriction (8) */ } } } } }else{ #ifndef SQLITE_OMIT_WINDOWFUNC if( pSubq->pWin && pSubq->pWin->pPartition==0 ) return 0; #endif } #ifdef SQLITE_DEBUG /* Only the first term of a compound can have a WITH clause. But make ** sure no other terms are marked SF_Recursive in case something changes ** in the future. */ { Select *pX; for(pX=pSubq; pX; pX=pX->pPrior){ assert( (pX->selFlags & (SF_Recursive))==0 ); } } #endif if( pSubq->pLimit!=0 ){ return 0; /* restriction (3) */ } while( pWhere->op==TK_AND ){ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrcList, iSrc); pWhere = pWhere->pLeft; } #if 0 /* These checks now done by sqlite3ExprIsSingleTableConstraint() */ if( ExprHasProperty(pWhere, EP_OuterON|EP_InnerON) /* (9a) */ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (9c) */ ){ int jj; for(jj=0; jjw.iJoin==pSrcList->a[jj].iCursor ){ /* If we reach this point, both (9a) and (9b) are satisfied. ** The following loop checks (9c): */ for(jj++; jja[jj].fg.jointype & JT_RIGHT)!=0 ){ return 0; /* restriction (9) */ } } } } } if( isLeftJoin && (ExprHasProperty(pWhere,EP_OuterON)==0 || pWhere->w.iJoin!=iCursor) ){ return 0; /* restriction (4) */ } if( ExprHasProperty(pWhere,EP_OuterON) && pWhere->w.iJoin!=iCursor ){ return 0; /* restriction (5) */ } #endif if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc) ){ nChng++; pSubq->selFlags |= SF_PushDown; while( pSubq ){ SubstContext x; pNew = sqlite3ExprDup(pParse->db, pWhere, 0); unsetJoinExpr(pNew, -1, 1); x.pParse = pParse; x.iTable = pSrc->iCursor; x.iNewTable = pSrc->iCursor; x.isOuterJoin = 0; x.pEList = pSubq->pEList; x.pCList = findLeftmostExprlist(pSubq); pNew = substExpr(&x, pNew); #ifndef SQLITE_OMIT_WINDOWFUNC if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){ /* Restriction 6c has prevented push-down in this case */ sqlite3ExprDelete(pParse->db, pNew); nChng--; break; } #endif if( pSubq->selFlags & SF_Aggregate ){ pSubq->pHaving = sqlite3ExprAnd(pParse, pSubq->pHaving, pNew); }else{ pSubq->pWhere = sqlite3ExprAnd(pParse, pSubq->pWhere, pNew); } pSubq = pSubq->pPrior; } } return nChng; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* ** Check to see if a subquery contains result-set columns that are ** never used. If it does, change the value of those result-set columns ** to NULL so that they do not cause unnecessary work to compute. ** ** Return the number of column that were changed to NULL. */ static int disableUnusedSubqueryResultColumns(SrcItem *pItem){ int nCol; Select *pSub; /* The subquery to be simplified */ Select *pX; /* For looping over compound elements of pSub */ Table *pTab; /* The table that describes the subquery */ int j; /* Column number */ int nChng = 0; /* Number of columns converted to NULL */ Bitmask colUsed; /* Columns that may not be NULLed out */ assert( pItem!=0 ); if( pItem->fg.isCorrelated || pItem->fg.isCte ){ return 0; } assert( pItem->pTab!=0 ); pTab = pItem->pTab; assert( pItem->pSelect!=0 ); pSub = pItem->pSelect; assert( pSub->pEList->nExpr==pTab->nCol ); for(pX=pSub; pX; pX=pX->pPrior){ if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){ testcase( pX->selFlags & SF_Distinct ); testcase( pX->selFlags & SF_Aggregate ); return 0; } if( pX->pPrior && pX->op!=TK_ALL ){ /* This optimization does not work for compound subqueries that ** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */ return 0; } #ifndef SQLITE_OMIT_WINDOWFUNC if( pX->pWin ){ /* This optimization does not work for subqueries that use window ** functions. */ return 0; } #endif } colUsed = pItem->colUsed; if( pSub->pOrderBy ){ ExprList *pList = pSub->pOrderBy; for(j=0; jnExpr; j++){ u16 iCol = pList->a[j].u.x.iOrderByCol; if( iCol>0 ){ iCol--; colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); } } } nCol = pTab->nCol; for(j=0; jpPrior) { Expr *pY = pX->pEList->a[j].pExpr; if( pY->op==TK_NULL ) continue; pY->op = TK_NULL; ExprClearProperty(pY, EP_Skip|EP_Unlikely); pX->selFlags |= SF_PushDown; nChng++; } } return nChng; } /* ** The pFunc is the only aggregate function in the query. Check to see ** if the query is a candidate for the min/max optimization. ** ** If the query is a candidate for the min/max optimization, then set ** *ppMinMax to be an ORDER BY clause to be used for the optimization ** and return either WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX depending on ** whether pFunc is a min() or max() function. ** ** If the query is not a candidate for the min/max optimization, return ** WHERE_ORDERBY_NORMAL (which must be zero). ** ** This routine must be called after aggregate functions have been ** located but before their arguments have been subjected to aggregate ** analysis. */ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){ int eRet = WHERE_ORDERBY_NORMAL; /* Return value */ ExprList *pEList; /* Arguments to agg function */ const char *zFunc; /* Name of aggregate function pFunc */ ExprList *pOrderBy; u8 sortFlags = 0; assert( *ppMinMax==0 ); assert( pFunc->op==TK_AGG_FUNCTION ); assert( !IsWindowFunc(pFunc) ); assert( ExprUseXList(pFunc) ); pEList = pFunc->x.pList; if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_WinFunc) || OptimizationDisabled(db, SQLITE_MinMaxOpt) ){ return eRet; } assert( !ExprHasProperty(pFunc, EP_IntValue) ); zFunc = pFunc->u.zToken; if( sqlite3StrICmp(zFunc, "min")==0 ){ eRet = WHERE_ORDERBY_MIN; if( sqlite3ExprCanBeNull(pEList->a[0].pExpr) ){ sortFlags = KEYINFO_ORDER_BIGNULL; } }else if( sqlite3StrICmp(zFunc, "max")==0 ){ eRet = WHERE_ORDERBY_MAX; sortFlags = KEYINFO_ORDER_DESC; }else{ return eRet; } *ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0); assert( pOrderBy!=0 || db->mallocFailed ); if( pOrderBy ) pOrderBy->a[0].fg.sortFlags = sortFlags; return eRet; } /* ** The select statement passed as the first argument is an aggregate query. ** The second argument is the associated aggregate-info object. This ** function tests if the SELECT is of the form: ** ** SELECT count(*) FROM ** ** where table is a database table, not a sub-select or view. If the query ** does match this pattern, then a pointer to the Table object representing ** is returned. Otherwise, NULL is returned. ** ** This routine checks to see if it is safe to use the count optimization. ** A correct answer is still obtained (though perhaps more slowly) if ** this routine returns NULL when it could have returned a table pointer. ** But returning the pointer when NULL should have been returned can ** result in incorrect answers and/or crashes. So, when in doubt, return NULL. */ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ Table *pTab; Expr *pExpr; assert( !p->pGroupBy ); if( p->pWhere || p->pEList->nExpr!=1 || p->pSrc->nSrc!=1 || p->pSrc->a[0].pSelect || pAggInfo->nFunc!=1 || p->pHaving ){ return 0; } pTab = p->pSrc->a[0].pTab; assert( pTab!=0 ); assert( !IsView(pTab) ); if( !IsOrdinaryTable(pTab) ) return 0; pExpr = p->pEList->a[0].pExpr; assert( pExpr!=0 ); if( pExpr->op!=TK_AGG_FUNCTION ) return 0; if( pExpr->pAggInfo!=pAggInfo ) return 0; if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0; assert( pAggInfo->aFunc[0].pFExpr==pExpr ); testcase( ExprHasProperty(pExpr, EP_Distinct) ); testcase( ExprHasProperty(pExpr, EP_WinFunc) ); if( ExprHasProperty(pExpr, EP_Distinct|EP_WinFunc) ) return 0; return pTab; } /* ** If the source-list item passed as an argument was augmented with an ** INDEXED BY clause, then try to locate the specified index. If there ** was such a clause and the named index cannot be found, return ** SQLITE_ERROR and leave an error in pParse. Otherwise, populate ** pFrom->pIndex and return SQLITE_OK. */ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){ Table *pTab = pFrom->pTab; char *zIndexedBy = pFrom->u1.zIndexedBy; Index *pIdx; assert( pTab!=0 ); assert( pFrom->fg.isIndexedBy!=0 ); for(pIdx=pTab->pIndex; pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy); pIdx=pIdx->pNext ); if( !pIdx ){ sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0); pParse->checkSchema = 1; return SQLITE_ERROR; } assert( pFrom->fg.isCte==0 ); pFrom->u2.pIBIndex = pIdx; return SQLITE_OK; } /* ** Detect compound SELECT statements that use an ORDER BY clause with ** an alternative collating sequence. ** ** SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ... ** ** These are rewritten as a subquery: ** ** SELECT * FROM (SELECT ... FROM t1 EXCEPT SELECT ... FROM t2) ** ORDER BY ... COLLATE ... ** ** This transformation is necessary because the multiSelectOrderBy() routine ** above that generates the code for a compound SELECT with an ORDER BY clause ** uses a merge algorithm that requires the same collating sequence on the ** result columns as on the ORDER BY clause. See ticket ** http://www.sqlite.org/src/info/6709574d2a ** ** This transformation is only needed for EXCEPT, INTERSECT, and UNION. ** The UNION ALL operator works fine with multiSelectOrderBy() even when ** there are COLLATE terms in the ORDER BY. */ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ int i; Select *pNew; Select *pX; sqlite3 *db; struct ExprList_item *a; SrcList *pNewSrc; Parse *pParse; Token dummy; if( p->pPrior==0 ) return WRC_Continue; if( p->pOrderBy==0 ) return WRC_Continue; for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){} if( pX==0 ) return WRC_Continue; a = p->pOrderBy->a; #ifndef SQLITE_OMIT_WINDOWFUNC /* If iOrderByCol is already non-zero, then it has already been matched ** to a result column of the SELECT statement. This occurs when the ** SELECT is rewritten for window-functions processing and then passed ** to sqlite3SelectPrep() and similar a second time. The rewriting done ** by this function is not required in this case. */ if( a[0].u.x.iOrderByCol ) return WRC_Continue; #endif for(i=p->pOrderBy->nExpr-1; i>=0; i--){ if( a[i].pExpr->flags & EP_Collate ) break; } if( i<0 ) return WRC_Continue; /* If we reach this point, that means the transformation is required. */ pParse = pWalker->pParse; db = pParse->db; pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); if( pNew==0 ) return WRC_Abort; memset(&dummy, 0, sizeof(dummy)); pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0); if( pNewSrc==0 ) return WRC_Abort; *pNew = *p; p->pSrc = pNewSrc; p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0)); p->op = TK_SELECT; p->pWhere = 0; pNew->pGroupBy = 0; pNew->pHaving = 0; pNew->pOrderBy = 0; p->pPrior = 0; p->pNext = 0; p->pWith = 0; #ifndef SQLITE_OMIT_WINDOWFUNC p->pWinDefn = 0; #endif p->selFlags &= ~SF_Compound; assert( (p->selFlags & SF_Converted)==0 ); p->selFlags |= SF_Converted; assert( pNew->pPrior!=0 ); pNew->pPrior->pNext = pNew; pNew->pLimit = 0; return WRC_Continue; } /* ** Check to see if the FROM clause term pFrom has table-valued function ** arguments. If it does, leave an error message in pParse and return ** non-zero, since pFrom is not allowed to be a table-valued function. */ static int cannotBeFunction(Parse *pParse, SrcItem *pFrom){ if( pFrom->fg.isTabFunc ){ sqlite3ErrorMsg(pParse, "'%s' is not a function", pFrom->zName); return 1; } return 0; } #ifndef SQLITE_OMIT_CTE /* ** Argument pWith (which may be NULL) points to a linked list of nested ** WITH contexts, from inner to outermost. If the table identified by ** FROM clause element pItem is really a common-table-expression (CTE) ** then return a pointer to the CTE definition for that table. Otherwise ** return NULL. ** ** If a non-NULL value is returned, set *ppContext to point to the With ** object that the returned CTE belongs to. */ static struct Cte *searchWith( With *pWith, /* Current innermost WITH clause */ SrcItem *pItem, /* FROM clause element to resolve */ With **ppContext /* OUT: WITH clause return value belongs to */ ){ const char *zName = pItem->zName; With *p; assert( pItem->zDatabase==0 ); assert( zName!=0 ); for(p=pWith; p; p=p->pOuter){ int i; for(i=0; inCte; i++){ if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){ *ppContext = p; return &p->a[i]; } } if( p->bView ) break; } return 0; } /* The code generator maintains a stack of active WITH clauses ** with the inner-most WITH clause being at the top of the stack. ** ** This routine pushes the WITH clause passed as the second argument ** onto the top of the stack. If argument bFree is true, then this ** WITH clause will never be popped from the stack but should instead ** be freed along with the Parse object. In other cases, when ** bFree==0, the With object will be freed along with the SELECT ** statement with which it is associated. ** ** This routine returns a copy of pWith. Or, if bFree is true and ** the pWith object is destroyed immediately due to an OOM condition, ** then this routine return NULL. ** ** If bFree is true, do not continue to use the pWith pointer after ** calling this routine, Instead, use only the return value. */ SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ if( pWith ){ if( bFree ){ pWith = (With*)sqlite3ParserAddCleanup(pParse, sqlite3WithDeleteGeneric, pWith); if( pWith==0 ) return 0; } if( pParse->nErr==0 ){ assert( pParse->pWith!=pWith ); pWith->pOuter = pParse->pWith; pParse->pWith = pWith; } } return pWith; } /* ** This function checks if argument pFrom refers to a CTE declared by ** a WITH clause on the stack currently maintained by the parser (on the ** pParse->pWith linked list). And if currently processing a CTE ** CTE expression, through routine checks to see if the reference is ** a recursive reference to the CTE. ** ** If pFrom matches a CTE according to either of these two above, pFrom->pTab ** and other fields are populated accordingly. ** ** Return 0 if no match is found. ** Return 1 if a match is found. ** Return 2 if an error condition is detected. */ static int resolveFromTermToCte( Parse *pParse, /* The parsing context */ Walker *pWalker, /* Current tree walker */ SrcItem *pFrom /* The FROM clause term to check */ ){ Cte *pCte; /* Matched CTE (or NULL if no match) */ With *pWith; /* The matching WITH */ assert( pFrom->pTab==0 ); if( pParse->pWith==0 ){ /* There are no WITH clauses in the stack. No match is possible */ return 0; } if( pParse->nErr ){ /* Prior errors might have left pParse->pWith in a goofy state, so ** go no further. */ return 0; } if( pFrom->zDatabase!=0 ){ /* The FROM term contains a schema qualifier (ex: main.t1) and so ** it cannot possibly be a CTE reference. */ return 0; } if( pFrom->fg.notCte ){ /* The FROM term is specifically excluded from matching a CTE. ** (1) It is part of a trigger that used to have zDatabase but had ** zDatabase removed by sqlite3FixTriggerStep(). ** (2) This is the first term in the FROM clause of an UPDATE. */ return 0; } pCte = searchWith(pParse->pWith, pFrom, &pWith); if( pCte ){ sqlite3 *db = pParse->db; Table *pTab; ExprList *pEList; Select *pSel; Select *pLeft; /* Left-most SELECT statement */ Select *pRecTerm; /* Left-most recursive term */ int bMayRecursive; /* True if compound joined by UNION [ALL] */ With *pSavedWith; /* Initial value of pParse->pWith */ int iRecTab = -1; /* Cursor for recursive table */ CteUse *pCteUse; /* If pCte->zCteErr is non-NULL at this point, then this is an illegal ** recursive reference to CTE pCte. Leave an error in pParse and return ** early. If pCte->zCteErr is NULL, then this is not a recursive reference. ** In this case, proceed. */ if( pCte->zCteErr ){ sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName); return 2; } if( cannotBeFunction(pParse, pFrom) ) return 2; assert( pFrom->pTab==0 ); pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return 2; pCteUse = pCte->pUse; if( pCteUse==0 ){ pCte->pUse = pCteUse = sqlite3DbMallocZero(db, sizeof(pCteUse[0])); if( pCteUse==0 || sqlite3ParserAddCleanup(pParse,sqlite3DbFree,pCteUse)==0 ){ sqlite3DbFree(db, pTab); return 2; } pCteUse->eM10d = pCte->eM10d; } pFrom->pTab = pTab; pTab->nTabRef = 1; pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); if( db->mallocFailed ) return 2; pFrom->pSelect->selFlags |= SF_CopyCte; assert( pFrom->pSelect ); if( pFrom->fg.isIndexedBy ){ sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy); return 2; } pFrom->fg.isCte = 1; pFrom->u2.pCteUse = pCteUse; pCteUse->nUse++; /* Check if this is a recursive CTE. */ pRecTerm = pSel = pFrom->pSelect; bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); while( bMayRecursive && pRecTerm->op==pSel->op ){ int i; SrcList *pSrc = pRecTerm->pSrc; assert( pRecTerm->pPrior!=0 ); for(i=0; inSrc; i++){ SrcItem *pItem = &pSrc->a[i]; if( pItem->zDatabase==0 && pItem->zName!=0 && 0==sqlite3StrICmp(pItem->zName, pCte->zName) ){ pItem->pTab = pTab; pTab->nTabRef++; pItem->fg.isRecursive = 1; if( pRecTerm->selFlags & SF_Recursive ){ sqlite3ErrorMsg(pParse, "multiple references to recursive table: %s", pCte->zName ); return 2; } pRecTerm->selFlags |= SF_Recursive; if( iRecTab<0 ) iRecTab = pParse->nTab++; pItem->iCursor = iRecTab; } } if( (pRecTerm->selFlags & SF_Recursive)==0 ) break; pRecTerm = pRecTerm->pPrior; } pCte->zCteErr = "circular reference: %s"; pSavedWith = pParse->pWith; pParse->pWith = pWith; if( pSel->selFlags & SF_Recursive ){ int rc; assert( pRecTerm!=0 ); assert( (pRecTerm->selFlags & SF_Recursive)==0 ); assert( pRecTerm->pNext!=0 ); assert( (pRecTerm->pNext->selFlags & SF_Recursive)!=0 ); assert( pRecTerm->pWith==0 ); pRecTerm->pWith = pSel->pWith; rc = sqlite3WalkSelect(pWalker, pRecTerm); pRecTerm->pWith = 0; if( rc ){ pParse->pWith = pSavedWith; return 2; } }else{ if( sqlite3WalkSelect(pWalker, pSel) ){ pParse->pWith = pSavedWith; return 2; } } pParse->pWith = pWith; for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior); pEList = pLeft->pEList; if( pCte->pCols ){ if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){ sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns", pCte->zName, pEList->nExpr, pCte->pCols->nExpr ); pParse->pWith = pSavedWith; return 2; } pEList = pCte->pCols; } sqlite3ColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol); if( bMayRecursive ){ if( pSel->selFlags & SF_Recursive ){ pCte->zCteErr = "multiple recursive references: %s"; }else{ pCte->zCteErr = "recursive reference in a subquery: %s"; } sqlite3WalkSelect(pWalker, pSel); } pCte->zCteErr = 0; pParse->pWith = pSavedWith; return 1; /* Success */ } return 0; /* No match */ } #endif #ifndef SQLITE_OMIT_CTE /* ** If the SELECT passed as the second argument has an associated WITH ** clause, pop it from the stack stored as part of the Parse object. ** ** This function is used as the xSelectCallback2() callback by ** sqlite3SelectExpand() when walking a SELECT tree to resolve table ** names and other FROM clause elements. */ SQLITE_PRIVATE void sqlite3SelectPopWith(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){ With *pWith = findRightmost(p)->pWith; if( pWith!=0 ){ assert( pParse->pWith==pWith || pParse->nErr ); pParse->pWith = pWith->pOuter; } } } #endif /* ** The SrcItem structure passed as the second argument represents a ** sub-query in the FROM clause of a SELECT statement. This function ** allocates and populates the SrcItem.pTab object. If successful, ** SQLITE_OK is returned. Otherwise, if an OOM error is encountered, ** SQLITE_NOMEM. */ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ Select *pSel = pFrom->pSelect; Table *pTab; assert( pSel ); pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); if( pTab==0 ) return SQLITE_NOMEM; pTab->nTabRef = 1; if( pFrom->zAlias ){ pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias); }else{ pTab->zName = sqlite3MPrintf(pParse->db, "%!S", pFrom); } while( pSel->pPrior ){ pSel = pSel->pPrior; } sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); #ifndef SQLITE_ALLOW_ROWID_IN_VIEW /* The usual case - do not allow ROWID on a subquery */ pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; #else pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */ #endif return pParse->nErr ? SQLITE_ERROR : SQLITE_OK; } /* ** Check the N SrcItem objects to the right of pBase. (N might be zero!) ** If any of those SrcItem objects have a USING clause containing zName ** then return true. ** ** If N is zero, or none of the N SrcItem objects to the right of pBase ** contains a USING clause, or if none of the USING clauses contain zName, ** then return false. */ static int inAnyUsingClause( const char *zName, /* Name we are looking for */ SrcItem *pBase, /* The base SrcItem. Looking at pBase[1] and following */ int N /* How many SrcItems to check */ ){ while( N>0 ){ N--; pBase++; if( pBase->fg.isUsing==0 ) continue; if( NEVER(pBase->u3.pUsing==0) ) continue; if( sqlite3IdListIndex(pBase->u3.pUsing, zName)>=0 ) return 1; } return 0; } /* ** This routine is a Walker callback for "expanding" a SELECT statement. ** "Expanding" means to do the following: ** ** (1) Make sure VDBE cursor numbers have been assigned to every ** element of the FROM clause. ** ** (2) Fill in the pTabList->a[].pTab fields in the SrcList that ** defines FROM clause. When views appear in the FROM clause, ** fill pTabList->a[].pSelect with a copy of the SELECT statement ** that implements the view. A copy is made of the view's SELECT ** statement so that we can freely modify or delete that statement ** without worrying about messing up the persistent representation ** of the view. ** ** (3) Add terms to the WHERE clause to accommodate the NATURAL keyword ** on joins and the ON and USING clause of joins. ** ** (4) Scan the list of columns in the result set (pEList) looking ** for instances of the "*" operator or the TABLE.* operator. ** If found, expand each "*" to be every column in every table ** and TABLE.* to be every column in TABLE. ** */ static int selectExpander(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; int i, j, k, rc; SrcList *pTabList; ExprList *pEList; SrcItem *pFrom; sqlite3 *db = pParse->db; Expr *pE, *pRight, *pExpr; u16 selFlags = p->selFlags; u32 elistFlags = 0; p->selFlags |= SF_Expanded; if( db->mallocFailed ){ return WRC_Abort; } assert( p->pSrc!=0 ); if( (selFlags & SF_Expanded)!=0 ){ return WRC_Prune; } if( pWalker->eCode ){ /* Renumber selId because it has been copied from a view */ p->selId = ++pParse->nSelect; } pTabList = p->pSrc; pEList = p->pEList; if( pParse->pWith && (p->selFlags & SF_View) ){ if( p->pWith==0 ){ p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With)); if( p->pWith==0 ){ return WRC_Abort; } } p->pWith->bView = 1; } sqlite3WithPush(pParse, p->pWith, 0); /* Make sure cursor numbers have been assigned to all entries in ** the FROM clause of the SELECT statement. */ sqlite3SrcListAssignCursors(pParse, pTabList); /* Look up every table named in the FROM clause of the select. If ** an entry of the FROM clause is a subquery instead of a table or view, ** then create a transient table structure to describe the subquery. */ for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ Table *pTab; assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 ); if( pFrom->pTab ) continue; assert( pFrom->fg.isRecursive==0 ); if( pFrom->zName==0 ){ #ifndef SQLITE_OMIT_SUBQUERY Select *pSel = pFrom->pSelect; /* A sub-query in the FROM clause of a SELECT */ assert( pSel!=0 ); assert( pFrom->pTab==0 ); if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort; #endif #ifndef SQLITE_OMIT_CTE }else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){ if( rc>1 ) return WRC_Abort; pTab = pFrom->pTab; assert( pTab!=0 ); #endif }else{ /* An ordinary table or view name in the FROM clause */ assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); if( pTab==0 ) return WRC_Abort; if( pTab->nTabRef>=0xffff ){ sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", pTab->zName); pFrom->pTab = 0; return WRC_Abort; } pTab->nTabRef++; if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){ return WRC_Abort; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) if( !IsOrdinaryTable(pTab) ){ i16 nCol; u8 eCodeOrig = pWalker->eCode; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); if( IsView(pTab) ){ if( (db->flags & SQLITE_EnableView)==0 && pTab->pSchema!=db->aDb[1].pSchema ){ sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited", pTab->zName); } pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( ALWAYS(IsVirtual(pTab)) && pFrom->fg.fromDDL && ALWAYS(pTab->u.vtab.p!=0) && pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0) ){ sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"", pTab->zName); } assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 ); #endif nCol = pTab->nCol; pTab->nCol = -1; pWalker->eCode = 1; /* Turn on Select.selId renumbering */ sqlite3WalkSelect(pWalker, pFrom->pSelect); pWalker->eCode = eCodeOrig; pTab->nCol = nCol; } #endif } /* Locate the index named by the INDEXED BY clause, if any. */ if( pFrom->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pFrom) ){ return WRC_Abort; } } /* Process NATURAL keywords, and ON and USING clauses of joins. */ assert( db->mallocFailed==0 || pParse->nErr!=0 ); if( pParse->nErr || sqlite3ProcessJoin(pParse, p) ){ return WRC_Abort; } /* For every "*" that occurs in the column list, insert the names of ** all columns in all tables. And for every TABLE.* insert the names ** of all columns in TABLE. The parser inserted a special expression ** with the TK_ASTERISK operator for each "*" that it found in the column ** list. The following code just has to locate the TK_ASTERISK ** expressions and expand each one to the list of all columns in ** all tables. ** ** The first loop just checks to see if there are any "*" operators ** that need expanding. */ for(k=0; knExpr; k++){ pE = pEList->a[k].pExpr; if( pE->op==TK_ASTERISK ) break; assert( pE->op!=TK_DOT || pE->pRight!=0 ); assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) ); if( pE->op==TK_DOT && pE->pRight->op==TK_ASTERISK ) break; elistFlags |= pE->flags; } if( knExpr ){ /* ** If we get here it means the result set contains one or more "*" ** operators that need to be expanded. Loop through each expression ** in the result set and expand them one by one. */ struct ExprList_item *a = pEList->a; ExprList *pNew = 0; int flags = pParse->db->flags; int longNames = (flags & SQLITE_FullColNames)!=0 && (flags & SQLITE_ShortColNames)==0; for(k=0; knExpr; k++){ pE = a[k].pExpr; elistFlags |= pE->flags; pRight = pE->pRight; assert( pE->op!=TK_DOT || pRight!=0 ); if( pE->op!=TK_ASTERISK && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK) ){ /* This particular expression does not need to be expanded. */ pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr); if( pNew ){ pNew->a[pNew->nExpr-1].zEName = a[k].zEName; pNew->a[pNew->nExpr-1].fg.eEName = a[k].fg.eEName; a[k].zEName = 0; } a[k].pExpr = 0; }else{ /* This expression is a "*" or a "TABLE.*" and needs to be ** expanded. */ int tableSeen = 0; /* Set to 1 when TABLE matches */ char *zTName = 0; /* text of name of TABLE */ int iErrOfst; if( pE->op==TK_DOT ){ assert( (selFlags & SF_NestedFrom)==0 ); assert( pE->pLeft!=0 ); assert( !ExprHasProperty(pE->pLeft, EP_IntValue) ); zTName = pE->pLeft->u.zToken; assert( ExprUseWOfst(pE->pLeft) ); iErrOfst = pE->pRight->w.iOfst; }else{ assert( ExprUseWOfst(pE) ); iErrOfst = pE->w.iOfst; } for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ int nAdd; /* Number of cols including rowid */ Table *pTab = pFrom->pTab; /* Table for this data source */ ExprList *pNestedFrom; /* Result-set of a nested FROM clause */ char *zTabName; /* AS name for this data source */ const char *zSchemaName = 0; /* Schema name for this data source */ int iDb; /* Schema index for this data src */ IdList *pUsing; /* USING clause for pFrom[1] */ if( (zTabName = pFrom->zAlias)==0 ){ zTabName = pTab->zName; } if( db->mallocFailed ) break; assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) ); if( pFrom->fg.isNestedFrom ){ assert( pFrom->pSelect!=0 ); pNestedFrom = pFrom->pSelect->pEList; assert( pNestedFrom!=0 ); assert( pNestedFrom->nExpr==pTab->nCol ); assert( VisibleRowid(pTab)==0 ); }else{ if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; } pNestedFrom = 0; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*"; } if( i+1nSrc && pFrom[1].fg.isUsing && (selFlags & SF_NestedFrom)!=0 ){ int ii; pUsing = pFrom[1].u3.pUsing; for(ii=0; iinId; ii++){ const char *zUName = pUsing->a[ii].zName; pRight = sqlite3Expr(db, TK_ID, zUName); sqlite3ExprSetErrorOffset(pRight, iErrOfst); pNew = sqlite3ExprListAppend(pParse, pNew, pRight); if( pNew ){ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1]; assert( pX->zEName==0 ); pX->zEName = sqlite3MPrintf(db,"..%s", zUName); pX->fg.eEName = ENAME_TAB; pX->fg.bUsingTerm = 1; } } }else{ pUsing = 0; } nAdd = pTab->nCol + (VisibleRowid(pTab) && (selFlags&SF_NestedFrom)); for(j=0; jnCol ){ zName = sqlite3RowidAlias(pTab); if( zName==0 ) continue; }else{ zName = pTab->aCol[j].zCnName; /* If pTab is actually an SF_NestedFrom sub-select, do not ** expand any ENAME_ROWID columns. */ if( pNestedFrom && pNestedFrom->a[j].fg.eEName==ENAME_ROWID ){ continue; } if( zTName && pNestedFrom && sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0, 0)==0 ){ continue; } /* If a column is marked as 'hidden', omit it from the expanded ** result-set list unless the SELECT has the SF_IncludeHidden ** bit set. */ if( (p->selFlags & SF_IncludeHidden)==0 && IsHiddenColumn(&pTab->aCol[j]) ){ continue; } if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0 && zTName==0 && (selFlags & (SF_NestedFrom))==0 ){ continue; } } assert( zName ); tableSeen = 1; if( i>0 && zTName==0 && (selFlags & SF_NestedFrom)==0 ){ if( pFrom->fg.isUsing && sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0 ){ /* In a join with a USING clause, omit columns in the ** using clause from the table on the right. */ continue; } } pRight = sqlite3Expr(db, TK_ID, zName); if( (pTabList->nSrc>1 && ( (pFrom->fg.jointype & JT_LTORJ)==0 || (selFlags & SF_NestedFrom)!=0 || !inAnyUsingClause(zName,pFrom,pTabList->nSrc-i-1) ) ) || IN_RENAME_OBJECT ){ Expr *pLeft; pLeft = sqlite3Expr(db, TK_ID, zTabName); pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); if( IN_RENAME_OBJECT && pE->pLeft ){ sqlite3RenameTokenRemap(pParse, pLeft, pE->pLeft); } if( zSchemaName ){ pLeft = sqlite3Expr(db, TK_ID, zSchemaName); pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr); } }else{ pExpr = pRight; } sqlite3ExprSetErrorOffset(pExpr, iErrOfst); pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); if( pNew==0 ){ break; /* OOM */ } pX = &pNew->a[pNew->nExpr-1]; assert( pX->zEName==0 ); if( (selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){ if( pNestedFrom ){ pX->zEName = sqlite3DbStrDup(db, pNestedFrom->a[j].zEName); testcase( pX->zEName==0 ); }else{ pX->zEName = sqlite3MPrintf(db, "%s.%s.%s", zSchemaName, zTabName, zName); testcase( pX->zEName==0 ); } pX->fg.eEName = (j==pTab->nCol ? ENAME_ROWID : ENAME_TAB); if( (pFrom->fg.isUsing && sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0) || (pUsing && sqlite3IdListIndex(pUsing, zName)>=0) || (jnCol && (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)) ){ pX->fg.bNoExpand = 1; } }else if( longNames ){ pX->zEName = sqlite3MPrintf(db, "%s.%s", zTabName, zName); pX->fg.eEName = ENAME_NAME; }else{ pX->zEName = sqlite3DbStrDup(db, zName); pX->fg.eEName = ENAME_NAME; } } } if( !tableSeen ){ if( zTName ){ sqlite3ErrorMsg(pParse, "no such table: %s", zTName); }else{ sqlite3ErrorMsg(pParse, "no tables specified"); } } } } sqlite3ExprListDelete(db, pEList); p->pEList = pNew; } if( p->pEList ){ if( p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns in result set"); return WRC_Abort; } if( (elistFlags & (EP_HasFunc|EP_Subquery))!=0 ){ p->selFlags |= SF_ComplexResult; } } #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x8 ){ TREETRACE(0x8,pParse,p,("After result-set wildcard expansion:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif return WRC_Continue; } #if SQLITE_DEBUG /* ** Always assert. This xSelectCallback2 implementation proves that the ** xSelectCallback2 is never invoked. */ SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker *NotUsed, Select *NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); assert( 0 ); } #endif /* ** This routine "expands" a SELECT statement and all of its subqueries. ** For additional information on what it means to "expand" a SELECT ** statement, see the comment on the selectExpand worker callback above. ** ** Expanding a SELECT statement is the first step in processing a ** SELECT statement. The SELECT statement must be expanded before ** name resolution is performed. ** ** If anything goes wrong, an error message is written into pParse. ** The calling function can detect the problem by looking at pParse->nErr ** and/or pParse->db->mallocFailed. */ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ Walker w; w.xExprCallback = sqlite3ExprWalkNoop; w.pParse = pParse; if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){ w.xSelectCallback = convertCompoundSelectToSubquery; w.xSelectCallback2 = 0; sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; w.xSelectCallback2 = sqlite3SelectPopWith; w.eCode = 0; sqlite3WalkSelect(&w, pSelect); } #ifndef SQLITE_OMIT_SUBQUERY /* ** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo() ** interface. ** ** For each FROM-clause subquery, add Column.zType, Column.zColl, and ** Column.affinity information to the Table structure that represents ** the result set of that subquery. ** ** The Table structure that represents the result set was constructed ** by selectExpander() but the type and collation and affinity information ** was omitted at that point because identifiers had not yet been resolved. ** This routine is called after identifier resolution. */ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ Parse *pParse; int i; SrcList *pTabList; SrcItem *pFrom; if( p->selFlags & SF_HasTypeInfo ) return; p->selFlags |= SF_HasTypeInfo; pParse = pWalker->pParse; testcase( (p->selFlags & SF_Resolved)==0 ); assert( (p->selFlags & SF_Resolved) || IN_RENAME_OBJECT ); pTabList = p->pSrc; for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; assert( pTab!=0 ); if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ /* A sub-query in the FROM clause of a SELECT */ Select *pSel = pFrom->pSelect; if( pSel ){ sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE); } } } } #endif /* ** This routine adds datatype and collating sequence information to ** the Table structures of all FROM-clause subqueries in a ** SELECT statement. ** ** Use this routine after name resolution. */ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ #ifndef SQLITE_OMIT_SUBQUERY Walker w; w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback2 = selectAddSubqueryTypeInfo; w.xExprCallback = sqlite3ExprWalkNoop; w.pParse = pParse; sqlite3WalkSelect(&w, pSelect); #endif } /* ** This routine sets up a SELECT statement for processing. The ** following is accomplished: ** ** * VDBE Cursor numbers are assigned to all FROM-clause terms. ** * Ephemeral Table objects are created for all FROM-clause subqueries. ** * ON and USING clauses are shifted into WHERE statements ** * Wildcards "*" and "TABLE.*" in result sets are expanded. ** * Identifiers in expression are matched to tables. ** ** This routine acts recursively on all subqueries within the SELECT. */ SQLITE_PRIVATE void sqlite3SelectPrep( Parse *pParse, /* The parser context */ Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for container */ ){ assert( p!=0 || pParse->db->mallocFailed ); assert( pParse->db->pParse==pParse ); if( pParse->db->mallocFailed ) return; if( p->selFlags & SF_HasTypeInfo ) return; sqlite3SelectExpand(pParse, p); if( pParse->nErr ) return; sqlite3ResolveSelectNames(pParse, p, pOuterNC); if( pParse->nErr ) return; sqlite3SelectAddTypeInfo(pParse, p); } #if TREETRACE_ENABLED /* ** Display all information about an AggInfo object */ static void printAggInfo(AggInfo *pAggInfo){ int ii; for(ii=0; iinColumn; ii++){ struct AggInfo_col *pCol = &pAggInfo->aCol[ii]; sqlite3DebugPrintf( "agg-column[%d] pTab=%s iTable=%d iColumn=%d iMem=%d" " iSorterColumn=%d %s\n", ii, pCol->pTab ? pCol->pTab->zName : "NULL", pCol->iTable, pCol->iColumn, pAggInfo->iFirstReg+ii, pCol->iSorterColumn, ii>=pAggInfo->nAccumulator ? "" : " Accumulator"); sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0); } for(ii=0; iinFunc; ii++){ sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n", ii, pAggInfo->iFirstReg+pAggInfo->nColumn+ii); sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0); } } #endif /* TREETRACE_ENABLED */ /* ** Analyze the arguments to aggregate functions. Create new pAggInfo->aCol[] ** entries for columns that are arguments to aggregate functions but which ** are not otherwise used. ** ** The aCol[] entries in AggInfo prior to nAccumulator are columns that ** are referenced outside of aggregate functions. These might be columns ** that are part of the GROUP by clause, for example. Other database engines ** would throw an error if there is a column reference that is not in the ** GROUP BY clause and that is not part of an aggregate function argument. ** But SQLite allows this. ** ** The aCol[] entries beginning with the aCol[nAccumulator] and following ** are column references that are used exclusively as arguments to ** aggregate functions. This routine is responsible for computing ** (or recomputing) those aCol[] entries. */ static void analyzeAggFuncArgs( AggInfo *pAggInfo, NameContext *pNC ){ int i; assert( pAggInfo!=0 ); assert( pAggInfo->iFirstReg==0 ); pNC->ncFlags |= NC_InAggFunc; for(i=0; inFunc; i++){ Expr *pExpr = pAggInfo->aFunc[i].pFExpr; assert( pExpr->op==TK_FUNCTION || pExpr->op==TK_AGG_FUNCTION ); assert( ExprUseXList(pExpr) ); sqlite3ExprAnalyzeAggList(pNC, pExpr->x.pList); if( pExpr->pLeft ){ assert( pExpr->pLeft->op==TK_ORDER ); assert( ExprUseXList(pExpr->pLeft) ); sqlite3ExprAnalyzeAggList(pNC, pExpr->pLeft->x.pList); } #ifndef SQLITE_OMIT_WINDOWFUNC assert( !IsWindowFunc(pExpr) ); if( ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3ExprAnalyzeAggregates(pNC, pExpr->y.pWin->pFilter); } #endif } pNC->ncFlags &= ~NC_InAggFunc; } /* ** An index on expressions is being used in the inner loop of an ** aggregate query with a GROUP BY clause. This routine attempts ** to adjust the AggInfo object to take advantage of index and to ** perhaps use the index as a covering index. ** */ static void optimizeAggregateUseOfIndexedExpr( Parse *pParse, /* Parsing context */ Select *pSelect, /* The SELECT statement being processed */ AggInfo *pAggInfo, /* The aggregate info */ NameContext *pNC /* Name context used to resolve agg-func args */ ){ assert( pAggInfo->iFirstReg==0 ); assert( pSelect!=0 ); assert( pSelect->pGroupBy!=0 ); pAggInfo->nColumn = pAggInfo->nAccumulator; if( ALWAYS(pAggInfo->nSortingColumn>0) ){ int mx = pSelect->pGroupBy->nExpr - 1; int j, k; for(j=0; jnColumn; j++){ k = pAggInfo->aCol[j].iSorterColumn; if( k>mx ) mx = k; } pAggInfo->nSortingColumn = mx+1; } analyzeAggFuncArgs(pAggInfo, pNC); #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x20 ){ IndexedExpr *pIEpr; TREETRACE(0x20, pParse, pSelect, ("AggInfo (possibly) adjusted for Indexed Exprs\n")); sqlite3TreeViewSelect(0, pSelect, 0); for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){ printf("data-cursor=%d index={%d,%d}\n", pIEpr->iDataCur, pIEpr->iIdxCur, pIEpr->iIdxCol); sqlite3TreeViewExpr(0, pIEpr->pExpr, 0); } printAggInfo(pAggInfo); } #else UNUSED_PARAMETER(pSelect); UNUSED_PARAMETER(pParse); #endif } /* ** Walker callback for aggregateConvertIndexedExprRefToColumn(). */ static int aggregateIdxEprRefToColCallback(Walker *pWalker, Expr *pExpr){ AggInfo *pAggInfo; struct AggInfo_col *pCol; UNUSED_PARAMETER(pWalker); if( pExpr->pAggInfo==0 ) return WRC_Continue; if( pExpr->op==TK_AGG_COLUMN ) return WRC_Continue; if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue; if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue; pAggInfo = pExpr->pAggInfo; if( NEVER(pExpr->iAgg>=pAggInfo->nColumn) ) return WRC_Continue; assert( pExpr->iAgg>=0 ); pCol = &pAggInfo->aCol[pExpr->iAgg]; pExpr->op = TK_AGG_COLUMN; pExpr->iTable = pCol->iTable; pExpr->iColumn = pCol->iColumn; ExprClearProperty(pExpr, EP_Skip|EP_Collate|EP_Unlikely); return WRC_Prune; } /* ** Convert every pAggInfo->aFunc[].pExpr such that any node within ** those expressions that has pAppInfo set is changed into a TK_AGG_COLUMN ** opcode. */ static void aggregateConvertIndexedExprRefToColumn(AggInfo *pAggInfo){ int i; Walker w; memset(&w, 0, sizeof(w)); w.xExprCallback = aggregateIdxEprRefToColCallback; for(i=0; inFunc; i++){ sqlite3WalkExpr(&w, pAggInfo->aFunc[i].pFExpr); } } /* ** Allocate a block of registers so that there is one register for each ** pAggInfo->aCol[] and pAggInfo->aFunc[] entry in pAggInfo. The first ** register in this block is stored in pAggInfo->iFirstReg. ** ** This routine may only be called once for each AggInfo object. Prior ** to calling this routine: ** ** * The aCol[] and aFunc[] arrays may be modified ** * The AggInfoColumnReg() and AggInfoFuncReg() macros may not be used ** ** After calling this routine: ** ** * The aCol[] and aFunc[] arrays are fixed ** * The AggInfoColumnReg() and AggInfoFuncReg() macros may be used ** */ static void assignAggregateRegisters(Parse *pParse, AggInfo *pAggInfo){ assert( pAggInfo!=0 ); assert( pAggInfo->iFirstReg==0 ); pAggInfo->iFirstReg = pParse->nMem + 1; pParse->nMem += pAggInfo->nColumn + pAggInfo->nFunc; } /* ** Reset the aggregate accumulator. ** ** The aggregate accumulator is a set of memory cells that hold ** intermediate results while calculating an aggregate. This ** routine generates code that stores NULLs in all of those memory ** cells. */ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ Vdbe *v = pParse->pVdbe; int i; struct AggInfo_func *pFunc; int nReg = pAggInfo->nFunc + pAggInfo->nColumn; assert( pAggInfo->iFirstReg>0 ); assert( pParse->db->pParse==pParse ); assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); if( nReg==0 ) return; if( pParse->nErr ) return; sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->iFirstReg, pAggInfo->iFirstReg+nReg-1); for(pFunc=pAggInfo->aFunc, i=0; inFunc; i++, pFunc++){ if( pFunc->iDistinct>=0 ){ Expr *pE = pFunc->pFExpr; assert( ExprUseXList(pE) ); if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one " "argument"); pFunc->iDistinct = -1; }else{ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pE->x.pList,0,0); pFunc->iDistAddr = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO); ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(DISTINCT)", pFunc->pFunc->zName)); } } if( pFunc->iOBTab>=0 ){ ExprList *pOBList; KeyInfo *pKeyInfo; int nExtra = 0; assert( pFunc->pFExpr->pLeft!=0 ); assert( pFunc->pFExpr->pLeft->op==TK_ORDER ); assert( ExprUseXList(pFunc->pFExpr->pLeft) ); assert( pFunc->pFunc!=0 ); pOBList = pFunc->pFExpr->pLeft->x.pList; if( !pFunc->bOBUnique ){ nExtra++; /* One extra column for the OP_Sequence */ } if( pFunc->bOBPayload ){ /* extra columns for the function arguments */ assert( ExprUseXList(pFunc->pFExpr) ); nExtra += pFunc->pFExpr->x.pList->nExpr; } if( pFunc->bUseSubtype ){ nExtra += pFunc->pFExpr->x.pList->nExpr; } pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra); if( !pFunc->bOBUnique && pParse->nErr==0 ){ pKeyInfo->nKeyField++; } sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iOBTab, pOBList->nExpr+nExtra, 0, (char*)pKeyInfo, P4_KEYINFO); ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(ORDER BY)", pFunc->pFunc->zName)); } } } /* ** Invoke the OP_AggFinalize opcode for every aggregate function ** in the AggInfo structure. */ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ Vdbe *v = pParse->pVdbe; int i; struct AggInfo_func *pF; for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); pList = pF->pFExpr->x.pList; if( pF->iOBTab>=0 ){ /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs ** were stored in emphermal table pF->iOBTab. Here, we extract those ** inputs (in ORDER BY order) and make all calls to OP_AggStep ** before doing the OP_AggFinal call. */ int iTop; /* Start of loop for extracting columns */ int nArg; /* Number of columns to extract */ int nKey; /* Key columns to be skipped */ int regAgg; /* Extract into this array */ int j; /* Loop counter */ assert( pF->pFunc!=0 ); nArg = pList->nExpr; regAgg = sqlite3GetTempRange(pParse, nArg); if( pF->bOBPayload==0 ){ nKey = 0; }else{ assert( pF->pFExpr->pLeft!=0 ); assert( ExprUseXList(pF->pFExpr->pLeft) ); assert( pF->pFExpr->pLeft->x.pList!=0 ); nKey = pF->pFExpr->pLeft->x.pList->nExpr; if( ALWAYS(!pF->bOBUnique) ) nKey++; } iTop = sqlite3VdbeAddOp1(v, OP_Rewind, pF->iOBTab); VdbeCoverage(v); for(j=nArg-1; j>=0; j--){ sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j); } if( pF->bUseSubtype ){ int regSubtype = sqlite3GetTempReg(pParse); int iBaseCol = nKey + nArg + (pF->bOBPayload==0 && pF->bOBUnique==0); for(j=nArg-1; j>=0; j--){ sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, iBaseCol+j, regSubtype); sqlite3VdbeAddOp2(v, OP_SetSubtype, regSubtype, regAgg+j); } sqlite3ReleaseTempReg(pParse, regSubtype); } sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, iTop); sqlite3ReleaseTempRange(pParse, regAgg, nArg); } sqlite3VdbeAddOp2(v, OP_AggFinal, AggInfoFuncReg(pAggInfo,i), pList ? pList->nExpr : 0); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); } } /* ** Generate code that will update the accumulator memory cells for an ** aggregate based on the current cursor position. ** ** If regAcc is non-zero and there are no min() or max() aggregates ** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator ** registers if register regAcc contains 0. The caller will take care ** of setting and clearing regAcc. ** ** For an ORDER BY aggregate, the actual accumulator memory cell update ** is deferred until after all input rows have been received, so that they ** can be run in the requested order. In that case, instead of invoking ** OP_AggStep to update the accumulator, just add the arguments that would ** have been passed into OP_AggStep into the sorting ephemeral table ** (along with the appropriate sort key). */ static void updateAccumulator( Parse *pParse, int regAcc, AggInfo *pAggInfo, int eDistinctType ){ Vdbe *v = pParse->pVdbe; int i; int regHit = 0; int addrHitTest = 0; struct AggInfo_func *pF; struct AggInfo_col *pC; assert( pAggInfo->iFirstReg>0 ); if( pParse->nErr ) return; pAggInfo->directMode = 1; for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ int nArg; int addrNext = 0; int regAgg; int regAggSz = 0; int regDistinct = 0; ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); assert( !IsWindowFunc(pF->pFExpr) ); assert( pF->pFunc!=0 ); pList = pF->pFExpr->x.pList; if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){ Expr *pFilter = pF->pFExpr->y.pWin->pFilter; if( pAggInfo->nAccumulator && (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) && regAcc ){ /* If regAcc==0, there there exists some min() or max() function ** without a FILTER clause that will ensure the magnet registers ** are populated. */ if( regHit==0 ) regHit = ++pParse->nMem; /* If this is the first row of the group (regAcc contains 0), clear the ** "magnet" register regHit so that the accumulator registers ** are populated if the FILTER clause jumps over the the ** invocation of min() or max() altogether. Or, if this is not ** the first row (regAcc contains 1), set the magnet register so that ** the accumulators are not populated unless the min()/max() is invoked ** and indicates that they should be. */ sqlite3VdbeAddOp2(v, OP_Copy, regAcc, regHit); } addrNext = sqlite3VdbeMakeLabel(pParse); sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL); } if( pF->iOBTab>=0 ){ /* Instead of invoking AggStep, we must push the arguments that would ** have been passed to AggStep onto the sorting table. */ int jj; /* Registered used so far in building the record */ ExprList *pOBList; /* The ORDER BY clause */ assert( pList!=0 ); nArg = pList->nExpr; assert( nArg>0 ); assert( pF->pFExpr->pLeft!=0 ); assert( pF->pFExpr->pLeft->op==TK_ORDER ); assert( ExprUseXList(pF->pFExpr->pLeft) ); pOBList = pF->pFExpr->pLeft->x.pList; assert( pOBList!=0 ); assert( pOBList->nExpr>0 ); regAggSz = pOBList->nExpr; if( !pF->bOBUnique ){ regAggSz++; /* One register for OP_Sequence */ } if( pF->bOBPayload ){ regAggSz += nArg; } if( pF->bUseSubtype ){ regAggSz += nArg; } regAggSz++; /* One extra register to hold result of MakeRecord */ regAgg = sqlite3GetTempRange(pParse, regAggSz); regDistinct = regAgg; sqlite3ExprCodeExprList(pParse, pOBList, regAgg, 0, SQLITE_ECEL_DUP); jj = pOBList->nExpr; if( !pF->bOBUnique ){ sqlite3VdbeAddOp2(v, OP_Sequence, pF->iOBTab, regAgg+jj); jj++; } if( pF->bOBPayload ){ regDistinct = regAgg+jj; sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP); jj += nArg; } if( pF->bUseSubtype ){ int kk; int regBase = pF->bOBPayload ? regDistinct : regAgg; for(kk=0; kknExpr; regAgg = sqlite3GetTempRange(pParse, nArg); regDistinct = regAgg; sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP); }else{ nArg = 0; regAgg = 0; } if( pF->iDistinct>=0 && pList ){ if( addrNext==0 ){ addrNext = sqlite3VdbeMakeLabel(pParse); } pF->iDistinct = codeDistinct(pParse, eDistinctType, pF->iDistinct, addrNext, pList, regDistinct); } if( pF->iOBTab>=0 ){ /* Insert a new record into the ORDER BY table */ sqlite3VdbeAddOp3(v, OP_MakeRecord, regAgg, regAggSz-1, regAgg+regAggSz-1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pF->iOBTab, regAgg+regAggSz-1, regAgg, regAggSz-1); sqlite3ReleaseTempRange(pParse, regAgg, regAggSz); }else{ /* Invoke the AggStep function */ if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl = 0; struct ExprList_item *pItem; int j; assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */ for(j=0, pItem=pList->a; !pColl && jpExpr); } if( !pColl ){ pColl = pParse->db->pDfltColl; } if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); } sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); sqlite3ReleaseTempRange(pParse, regAgg, nArg); } if( addrNext ){ sqlite3VdbeResolveLabel(v, addrNext); } } if( regHit==0 && pAggInfo->nAccumulator ){ regHit = regAcc; } if( regHit ){ addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v); } for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){ sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i)); } pAggInfo->directMode = 0; if( addrHitTest ){ sqlite3VdbeJumpHereOrPopInst(v, addrHitTest); } } /* ** Add a single OP_Explain instruction to the VDBE to explain a simple ** count(*) query ("SELECT count(*) FROM pTab"). */ #ifndef SQLITE_OMIT_EXPLAIN static void explainSimpleCount( Parse *pParse, /* Parse context */ Table *pTab, /* Table being queried */ Index *pIdx /* Index used to optimize scan, or NULL */ ){ if( pParse->explain==2 ){ int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); sqlite3VdbeExplain(pParse, 0, "SCAN %s%s%s", pTab->zName, bCover ? " USING COVERING INDEX " : "", bCover ? pIdx->zName : "" ); } } #else # define explainSimpleCount(a,b,c) #endif /* ** sqlite3WalkExpr() callback used by havingToWhere(). ** ** If the node passed to the callback is a TK_AND node, return ** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes. ** ** Otherwise, return WRC_Prune. In this case, also check if the ** sub-expression matches the criteria for being moved to the WHERE ** clause. If so, add it to the WHERE clause and replace the sub-expression ** within the HAVING expression with a constant "1". */ static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ if( pExpr->op!=TK_AND ){ Select *pS = pWalker->u.pSelect; /* This routine is called before the HAVING clause of the current ** SELECT is analyzed for aggregates. So if pExpr->pAggInfo is set ** here, it indicates that the expression is a correlated reference to a ** column from an outer aggregate query, or an aggregate function that ** belongs to an outer query. Do not move the expression to the WHERE ** clause in this obscure case, as doing so may corrupt the outer Select ** statements AggInfo structure. */ if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) && ExprAlwaysFalse(pExpr)==0 && pExpr->pAggInfo==0 ){ sqlite3 *db = pWalker->pParse->db; Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1"); if( pNew ){ Expr *pWhere = pS->pWhere; SWAP(Expr, *pNew, *pExpr); pNew = sqlite3ExprAnd(pWalker->pParse, pWhere, pNew); pS->pWhere = pNew; pWalker->eCode = 1; } } return WRC_Prune; } return WRC_Continue; } /* ** Transfer eligible terms from the HAVING clause of a query, which is ** processed after grouping, to the WHERE clause, which is processed before ** grouping. For example, the query: ** ** SELECT * FROM WHERE a=? GROUP BY b HAVING b=? AND c=? ** ** can be rewritten as: ** ** SELECT * FROM WHERE a=? AND b=? GROUP BY b HAVING c=? ** ** A term of the HAVING expression is eligible for transfer if it consists ** entirely of constants and expressions that are also GROUP BY terms that ** use the "BINARY" collation sequence. */ static void havingToWhere(Parse *pParse, Select *p){ Walker sWalker; memset(&sWalker, 0, sizeof(sWalker)); sWalker.pParse = pParse; sWalker.xExprCallback = havingToWhereExprCb; sWalker.u.pSelect = p; sqlite3WalkExpr(&sWalker, p->pHaving); #if TREETRACE_ENABLED if( sWalker.eCode && (sqlite3TreeTrace & 0x100)!=0 ){ TREETRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif } /* ** Check to see if the pThis entry of pTabList is a self-join of another view. ** Search FROM-clause entries in the range of iFirst..iEnd, including iFirst ** but stopping before iEnd. ** ** If pThis is a self-join, then return the SrcItem for the first other ** instance of that view found. If pThis is not a self-join then return 0. */ static SrcItem *isSelfJoinView( SrcList *pTabList, /* Search for self-joins in this FROM clause */ SrcItem *pThis, /* Search for prior reference to this subquery */ int iFirst, int iEnd /* Range of FROM-clause entries to search. */ ){ SrcItem *pItem; assert( pThis->pSelect!=0 ); if( pThis->pSelect->selFlags & SF_PushDown ) return 0; while( iFirsta[iFirst++]; if( pItem->pSelect==0 ) continue; if( pItem->fg.viaCoroutine ) continue; if( pItem->zName==0 ) continue; assert( pItem->pTab!=0 ); assert( pThis->pTab!=0 ); if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue; if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; pS1 = pItem->pSelect; if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){ /* The query flattener left two different CTE tables with identical ** names in the same FROM clause. */ continue; } if( pItem->pSelect->selFlags & SF_PushDown ){ /* The view was modified by some other optimization such as ** pushDownWhereTerms() */ continue; } return pItem; } return 0; } /* ** Deallocate a single AggInfo object */ static void agginfoFree(sqlite3 *db, void *pArg){ AggInfo *p = (AggInfo*)pArg; sqlite3DbFree(db, p->aCol); sqlite3DbFree(db, p->aFunc); sqlite3DbFreeNN(db, p); } /* ** Attempt to transform a query of the form ** ** SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2) ** ** Into this: ** ** SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2) ** ** The transformation only works if all of the following are true: ** ** * The subquery is a UNION ALL of two or more terms ** * The subquery does not have a LIMIT clause ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries ** * The outer query is a simple count(*) with no WHERE clause or other ** extraneous syntax. ** ** Return TRUE if the optimization is undertaken. */ static int countOfViewOptimization(Parse *pParse, Select *p){ Select *pSub, *pPrior; Expr *pExpr; Expr *pCount; sqlite3 *db; if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ if( p->pWhere ) return 0; if( p->pHaving ) return 0; if( p->pGroupBy ) return 0; if( p->pOrderBy ) return 0; pExpr = p->pEList->a[0].pExpr; if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */ assert( ExprUseUToken(pExpr) ); if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */ assert( ExprUseXList(pExpr) ); if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */ pSub = p->pSrc->a[0].pSelect; if( pSub==0 ) return 0; /* The FROM is a subquery */ if( pSub->pPrior==0 ) return 0; /* Must be a compound */ if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */ do{ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ if( pSub->pWhere ) return 0; /* No WHERE clause */ if( pSub->pLimit ) return 0; /* No LIMIT clause */ if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ assert( pSub->pHaving==0 ); /* Due to the previous */ pSub = pSub->pPrior; /* Repeat over compound */ }while( pSub ); /* If we reach this point then it is OK to perform the transformation */ db = pParse->db; pCount = pExpr; pExpr = 0; pSub = p->pSrc->a[0].pSelect; p->pSrc->a[0].pSelect = 0; sqlite3SrcListDelete(db, p->pSrc); p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); while( pSub ){ Expr *pTerm; pPrior = pSub->pPrior; pSub->pPrior = 0; pSub->pNext = 0; pSub->selFlags |= SF_Aggregate; pSub->selFlags &= ~SF_Compound; pSub->nSelectRow = 0; sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList); pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount; pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm); pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0); sqlite3PExprAddSelect(pParse, pTerm, pSub); if( pExpr==0 ){ pExpr = pTerm; }else{ pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr); } pSub = pPrior; } p->pEList->a[0].pExpr = pExpr; p->selFlags &= ~SF_Aggregate; #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x200 ){ TREETRACE(0x200,pParse,p,("After count-of-view optimization:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif return 1; } /* ** If any term of pSrc, or any SF_NestedFrom sub-query, is not the same ** as pSrcItem but has the same alias as p0, then return true. ** Otherwise return false. */ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){ int i; for(i=0; inSrc; i++){ SrcItem *p1 = &pSrc->a[i]; if( p1==p0 ) continue; if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ return 1; } if( p1->pSelect && (p1->pSelect->selFlags & SF_NestedFrom)!=0 && sameSrcAlias(p0, p1->pSelect->pSrc) ){ return 1; } } return 0; } /* ** Return TRUE (non-zero) if the i-th entry in the pTabList SrcList can ** be implemented as a co-routine. The i-th entry is guaranteed to be ** a subquery. ** ** The subquery is implemented as a co-routine if all of the following are ** true: ** ** (1) The subquery will likely be implemented in the outer loop of ** the query. This will be the case if any one of the following ** conditions hold: ** (a) The subquery is the only term in the FROM clause ** (b) The subquery is the left-most term and a CROSS JOIN or similar ** requires it to be the outer loop ** (c) All of the following are true: ** (i) The subquery is the left-most subquery in the FROM clause ** (ii) There is nothing that would prevent the subquery from ** being used as the outer loop if the sqlite3WhereBegin() ** routine nominates it to that position. ** (iii) The query is not a UPDATE ... FROM ** (2) The subquery is not a CTE that should be materialized because ** (a) the AS MATERIALIZED keyword is used, or ** (b) the CTE is used multiple times and does not have the ** NOT MATERIALIZED keyword ** (3) The subquery is not part of a left operand for a RIGHT JOIN ** (4) The SQLITE_Coroutine optimization disable flag is not set ** (5) The subquery is not self-joined */ static int fromClauseTermCanBeCoroutine( Parse *pParse, /* Parsing context */ SrcList *pTabList, /* FROM clause */ int i, /* Which term of the FROM clause holds the subquery */ int selFlags /* Flags on the SELECT statement */ ){ SrcItem *pItem = &pTabList->a[i]; if( pItem->fg.isCte ){ const CteUse *pCteUse = pItem->u2.pCteUse; if( pCteUse->eM10d==M10d_Yes ) return 0; /* (2a) */ if( pCteUse->nUse>=2 && pCteUse->eM10d!=M10d_No ) return 0; /* (2b) */ } if( pTabList->a[0].fg.jointype & JT_LTORJ ) return 0; /* (3) */ if( OptimizationDisabled(pParse->db, SQLITE_Coroutines) ) return 0; /* (4) */ if( isSelfJoinView(pTabList, pItem, i+1, pTabList->nSrc)!=0 ){ return 0; /* (5) */ } if( i==0 ){ if( pTabList->nSrc==1 ) return 1; /* (1a) */ if( pTabList->a[1].fg.jointype & JT_CROSS ) return 1; /* (1b) */ if( selFlags & SF_UpdateFrom ) return 0; /* (1c-iii) */ return 1; } if( selFlags & SF_UpdateFrom ) return 0; /* (1c-iii) */ while( 1 /*exit-by-break*/ ){ if( pItem->fg.jointype & (JT_OUTER|JT_CROSS) ) return 0; /* (1c-ii) */ if( i==0 ) break; i--; pItem--; if( pItem->pSelect!=0 ) return 0; /* (1c-i) */ } return 1; } /* ** Generate code for the SELECT statement given in the p argument. ** ** The results are returned according to the SelectDest structure. ** See comments in sqliteInt.h for further information. ** ** This routine returns the number of errors. If any errors are ** encountered, then an appropriate error message is left in ** pParse->zErrMsg. ** ** This routine does NOT free the Select structure passed in. The ** calling function needs to do that. */ SQLITE_PRIVATE int sqlite3Select( Parse *pParse, /* The parser context */ Select *p, /* The SELECT statement being coded. */ SelectDest *pDest /* What to do with the query results */ ){ int i, j; /* Loop counters */ WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */ Vdbe *v; /* The virtual machine under construction */ int isAgg; /* True for select lists like "count(*)" */ ExprList *pEList = 0; /* List of columns to extract. */ SrcList *pTabList; /* List of tables to select from */ Expr *pWhere; /* The WHERE clause. May be NULL */ ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ Expr *pHaving; /* The HAVING clause. May be NULL */ AggInfo *pAggInfo = 0; /* Aggregate information */ int rc = 1; /* Value to return from this function */ DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */ SortCtx sSort; /* Info on how to code the ORDER BY clause */ int iEnd; /* Address of the end of the query */ sqlite3 *db; /* The database connection */ ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */ u8 minMaxFlag; /* Flag for min/max queries */ db = pParse->db; assert( pParse==db->pParse ); v = sqlite3GetVdbe(pParse); if( p==0 || pParse->nErr ){ return 1; } assert( db->mallocFailed==0 ); if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; #if TREETRACE_ENABLED TREETRACE(0x1,pParse,p, ("begin processing:\n", pParse->addrExplain)); if( sqlite3TreeTrace & 0x10000 ){ if( (sqlite3TreeTrace & 0x10001)==0x10000 ){ sqlite3TreeViewLine(0, "In sqlite3Select() at %s:%d", __FILE__, __LINE__); } sqlite3ShowSelect(p); } #endif assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); if( IgnorableDistinct(pDest) ){ assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_DistFifo ); /* All of these destinations are also able to ignore the ORDER BY clause */ if( p->pOrderBy ){ #if TREETRACE_ENABLED TREETRACE(0x800,pParse,p, ("dropping superfluous ORDER BY:\n")); if( sqlite3TreeTrace & 0x800 ){ sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY"); } #endif sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, p->pOrderBy); testcase( pParse->earlyCleanup ); p->pOrderBy = 0; } p->selFlags &= ~SF_Distinct; p->selFlags |= SF_NoopOrderBy; } sqlite3SelectPrep(pParse, p, 0); if( pParse->nErr ){ goto select_end; } assert( db->mallocFailed==0 ); assert( p->pEList!=0 ); #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x10 ){ TREETRACE(0x10,pParse,p, ("after name resolution:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif /* If the SF_UFSrcCheck flag is set, then this function is being called ** as part of populating the temp table for an UPDATE...FROM statement. ** In this case, it is an error if the target object (pSrc->a[0]) name ** or alias is duplicated within FROM clause (pSrc->a[1..n]). ** ** Postgres disallows this case too. The reason is that some other ** systems handle this case differently, and not all the same way, ** which is just confusing. To avoid this, we follow PG's lead and ** disallow it altogether. */ if( p->selFlags & SF_UFSrcCheck ){ SrcItem *p0 = &p->pSrc->a[0]; if( sameSrcAlias(p0, p->pSrc) ){ sqlite3ErrorMsg(pParse, "target object/alias may not appear in FROM clause: %s", p0->zAlias ? p0->zAlias : p0->pTab->zName ); goto select_end; } /* Clear the SF_UFSrcCheck flag. The check has already been performed, ** and leaving this flag set can cause errors if a compound sub-query ** in p->pSrc is flattened into this query and this function called ** again as part of compound SELECT processing. */ p->selFlags &= ~SF_UFSrcCheck; } if( pDest->eDest==SRT_Output ){ sqlite3GenerateColumnNames(pParse, p); } #ifndef SQLITE_OMIT_WINDOWFUNC if( sqlite3WindowRewrite(pParse, p) ){ assert( pParse->nErr ); goto select_end; } #if TREETRACE_ENABLED if( p->pWin && (sqlite3TreeTrace & 0x40)!=0 ){ TREETRACE(0x40,pParse,p, ("after window rewrite:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif #endif /* SQLITE_OMIT_WINDOWFUNC */ pTabList = p->pSrc; isAgg = (p->selFlags & SF_Aggregate)!=0; memset(&sSort, 0, sizeof(sSort)); sSort.pOrderBy = p->pOrderBy; /* Try to do various optimizations (flattening subqueries, and strength ** reduction of join operators) in the FROM clause up into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && inSrc; i++){ SrcItem *pItem = &pTabList->a[i]; Select *pSub = pItem->pSelect; Table *pTab = pItem->pTab; /* The expander should have already created transient Table objects ** even for FROM clause elements such as subqueries that do not correspond ** to a real table */ assert( pTab!=0 ); /* Try to simplify joins: ** ** LEFT JOIN -> JOIN ** RIGHT JOIN -> JOIN ** FULL JOIN -> RIGHT JOIN ** ** If terms of the i-th table are used in the WHERE clause in such a ** way that the i-th table cannot be the NULL row of a join, then ** perform the appropriate simplification. This is called ** "OUTER JOIN strength reduction" in the SQLite documentation. */ if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor, pItem->fg.jointype & JT_LTORJ) && OptimizationEnabled(db, SQLITE_SimplifyJoin) ){ if( pItem->fg.jointype & JT_LEFT ){ if( pItem->fg.jointype & JT_RIGHT ){ TREETRACE(0x1000,pParse,p, ("FULL-JOIN simplifies to RIGHT-JOIN on term %d\n",i)); pItem->fg.jointype &= ~JT_LEFT; }else{ TREETRACE(0x1000,pParse,p, ("LEFT-JOIN simplifies to JOIN on term %d\n",i)); pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER); unsetJoinExpr(p->pWhere, pItem->iCursor, 0); } } if( pItem->fg.jointype & JT_LTORJ ){ for(j=i+1; jnSrc; j++){ SrcItem *pI2 = &pTabList->a[j]; if( pI2->fg.jointype & JT_RIGHT ){ if( pI2->fg.jointype & JT_LEFT ){ TREETRACE(0x1000,pParse,p, ("FULL-JOIN simplifies to LEFT-JOIN on term %d\n",j)); pI2->fg.jointype &= ~JT_RIGHT; }else{ TREETRACE(0x1000,pParse,p, ("RIGHT-JOIN simplifies to JOIN on term %d\n",j)); pI2->fg.jointype &= ~(JT_RIGHT|JT_OUTER); unsetJoinExpr(p->pWhere, pI2->iCursor, 1); } } } for(j=pTabList->nSrc-1; j>=0; j--){ pTabList->a[j].fg.jointype &= ~JT_LTORJ; if( pTabList->a[j].fg.jointype & JT_RIGHT ) break; } } } /* No further action if this term of the FROM clause is not a subquery */ if( pSub==0 ) continue; /* Catch mismatch in the declared columns of a view and the number of ** columns in the SELECT on the RHS */ if( pTab->nCol!=pSub->pEList->nExpr ){ sqlite3ErrorMsg(pParse, "expected %d columns for '%s' but got %d", pTab->nCol, pTab->zName, pSub->pEList->nExpr); goto select_end; } /* Do not attempt the usual optimizations (flattening and ORDER BY ** elimination) on a MATERIALIZED common table expression because ** a MATERIALIZED common table expression is an optimization fence. */ if( pItem->fg.isCte && pItem->u2.pCteUse->eM10d==M10d_Yes ){ continue; } /* Do not try to flatten an aggregate subquery. ** ** Flattening an aggregate subquery is only possible if the outer query ** is not a join. But if the outer query is not a join, then the subquery ** will be implemented as a co-routine and there is no advantage to ** flattening in that case. */ if( (pSub->selFlags & SF_Aggregate)!=0 ) continue; assert( pSub->pGroupBy==0 ); /* If a FROM-clause subquery has an ORDER BY clause that is not ** really doing anything, then delete it now so that it does not ** interfere with query flattening. See the discussion at ** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a ** ** Beware of these cases where the ORDER BY clause may not be safely ** omitted: ** ** (1) There is also a LIMIT clause ** (2) The subquery was added to help with window-function ** processing ** (3) The subquery is in the FROM clause of an UPDATE ** (4) The outer query uses an aggregate function other than ** the built-in count(), min(), or max(). ** (5) The ORDER BY isn't going to accomplish anything because ** one of: ** (a) The outer query has a different ORDER BY clause ** (b) The subquery is part of a join ** See forum post 062d576715d277c8 ** ** Also retain the ORDER BY if the OmitOrderBy optimization is disabled. */ if( pSub->pOrderBy!=0 && (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */ && pSub->pLimit==0 /* Condition (1) */ && (pSub->selFlags & SF_OrderByReqd)==0 /* Condition (2) */ && (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */ && OptimizationEnabled(db, SQLITE_OmitOrderBy) ){ TREETRACE(0x800,pParse,p, ("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1)); sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pOrderBy); pSub->pOrderBy = 0; } /* If the outer query contains a "complex" result set (that is, ** if the result set of the outer query uses functions or subqueries) ** and if the subquery contains an ORDER BY clause and if ** it will be implemented as a co-routine, then do not flatten. This ** restriction allows SQL constructs like this: ** ** SELECT expensive_function(x) ** FROM (SELECT x FROM tab ORDER BY y LIMIT 10); ** ** The expensive_function() is only computed on the 10 rows that ** are output, rather than every row of the table. ** ** The requirement that the outer query have a complex result set ** means that flattening does occur on simpler SQL constraints without ** the expensive_function() like: ** ** SELECT x FROM (SELECT x FROM tab ORDER BY y LIMIT 10); */ if( pSub->pOrderBy!=0 && i==0 && (p->selFlags & SF_ComplexResult)!=0 && (pTabList->nSrc==1 || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0) ){ continue; } if( flattenSubquery(pParse, p, i, isAgg) ){ if( pParse->nErr ) goto select_end; /* This subquery can be absorbed into its parent. */ i = -1; } pTabList = p->pSrc; if( db->mallocFailed ) goto select_end; if( !IgnorableOrderby(pDest) ){ sSort.pOrderBy = p->pOrderBy; } } #endif #ifndef SQLITE_OMIT_COMPOUND_SELECT /* Handle compound SELECT statements using the separate multiSelect() ** procedure. */ if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); #if TREETRACE_ENABLED TREETRACE(0x400,pParse,p,("end compound-select processing\n")); if( (sqlite3TreeTrace & 0x400)!=0 && ExplainQueryPlanParent(pParse)==0 ){ sqlite3TreeViewSelect(0, p, 0); } #endif if( p->pNext==0 ) ExplainQueryPlanPop(pParse); return rc; } #endif /* Do the WHERE-clause constant propagation optimization if this is ** a join. No need to speed time on this operation for non-join queries ** as the equivalent optimization will be handled by query planner in ** sqlite3WhereBegin(). */ if( p->pWhere!=0 && p->pWhere->op==TK_AND && OptimizationEnabled(db, SQLITE_PropagateConst) && propagateConstants(pParse, p) ){ #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x2000 ){ TREETRACE(0x2000,pParse,p,("After constant propagation:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif }else{ TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n")); } if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) && countOfViewOptimization(pParse, p) ){ if( db->mallocFailed ) goto select_end; pTabList = p->pSrc; } /* For each term in the FROM clause, do two things: ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries */ for(i=0; inSrc; i++){ SrcItem *pItem = &pTabList->a[i]; SrcItem *pPrior; SelectDest dest; Select *pSub; #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) const char *zSavedAuthContext; #endif /* Issue SQLITE_READ authorizations with a fake column name for any ** tables that are referenced but from which no values are extracted. ** Examples of where these kinds of null SQLITE_READ authorizations ** would occur: ** ** SELECT count(*) FROM t1; -- SQLITE_READ t1."" ** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2."" ** ** The fake column name is an empty string. It is possible for a table to ** have a column named by the empty string, in which case there is no way to ** distinguish between an unreferenced table and an actual reference to the ** "" column. The original design was for the fake column name to be a NULL, ** which would be unambiguous. But legacy authorization callbacks might ** assume the column name is non-NULL and segfault. The use of an empty ** string for the fake column name seems safer. */ if( pItem->colUsed==0 && pItem->zName!=0 ){ sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); } #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* Generate code for all sub-queries in the FROM clause */ pSub = pItem->pSelect; if( pSub==0 ) continue; /* The code for a subquery should only be generated once. */ assert( pItem->addrFillSub==0 ); /* Increment Parse.nHeight by the height of the largest expression ** tree referred to by this, the parent select. The child select ** may contain expression trees of at most ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit ** more conservative than necessary, but much easier than enforcing ** an exact limit. */ pParse->nHeight += sqlite3SelectExprHeight(p); /* Make copies of constant WHERE-clause terms in the outer query down ** inside the subquery. This can help the subquery to run more efficiently. */ if( OptimizationEnabled(db, SQLITE_PushDown) && (pItem->fg.isCte==0 || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2)) && pushDownWhereTerms(pParse, pSub, p->pWhere, pTabList, i) ){ #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x4000 ){ TREETRACE(0x4000,pParse,p, ("After WHERE-clause push-down into subquery %d:\n", pSub->selId)); sqlite3TreeViewSelect(0, p, 0); } #endif assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 ); }else{ TREETRACE(0x4000,pParse,p,("Push-down not possible\n")); } /* Convert unused result columns of the subquery into simple NULL ** expressions, to avoid unneeded searching and computation. */ if( OptimizationEnabled(db, SQLITE_NullUnusedCols) && disableUnusedSubqueryResultColumns(pItem) ){ #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x4000 ){ TREETRACE(0x4000,pParse,p, ("Change unused result columns to NULL for subquery %d:\n", pSub->selId)); sqlite3TreeViewSelect(0, p, 0); } #endif } zSavedAuthContext = pParse->zAuthContext; pParse->zAuthContext = pItem->zName; /* Generate code to implement the subquery */ if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. */ int addrTop = sqlite3VdbeCurrentAddr(v)+1; pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%!S", pItem)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; pItem->regResult = dest.iSdst; sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){ /* This is a CTE for which materialization code has already been ** generated. Invoke the subroutine to compute the materialization, ** the make the pItem->iCursor be a copy of the ephemeral table that ** holds the result of the materialization. */ CteUse *pCteUse = pItem->u2.pCteUse; sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e); if( pItem->iCursor!=pCteUse->iCur ){ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur); VdbeComment((v, "%!S", pItem)); } pSub->nSelectRow = pCteUse->nRowEst; }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){ /* This view has already been materialized by a prior entry in ** this same FROM clause. Reuse it. */ if( pPrior->addrFillSub ){ sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub); } sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); pSub->nSelectRow = pPrior->pSelect->nSelectRow; }else{ /* Materialize the view. If the view is not correlated, generate a ** subroutine to do the materialization so that subsequent uses of ** the same view can reuse the materialization. */ int topAddr; int onceAddr = 0; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrExplain; #endif pItem->regReturn = ++pParse->nMem; topAddr = sqlite3VdbeAddOp0(v, OP_Goto); pItem->addrFillSub = topAddr+1; pItem->fg.isMaterialized = 1; if( pItem->fg.isCorrelated==0 ){ /* If the subquery is not correlated and if we are not inside of ** a trigger, then we only need to compute the value of the subquery ** once. */ onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); VdbeComment((v, "materialize %!S", pItem)); }else{ VdbeNoopComment((v, "materialize %!S", pItem)); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1); VdbeComment((v, "end %!S", pItem)); sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); sqlite3VdbeJumpHere(v, topAddr); sqlite3ClearTempRegCache(pParse); if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ CteUse *pCteUse = pItem->u2.pCteUse; pCteUse->addrM9e = pItem->addrFillSub; pCteUse->regRtn = pItem->regReturn; pCteUse->iCur = pItem->iCursor; pCteUse->nRowEst = pSub->nSelectRow; } } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); pParse->zAuthContext = zSavedAuthContext; #endif } /* Various elements of the SELECT copied into local variables for ** convenience */ pEList = p->pEList; pWhere = p->pWhere; pGroupBy = p->pGroupBy; pHaving = p->pHaving; sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0; #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x8000 ){ TREETRACE(0x8000,pParse,p,("After all FROM-clause analysis:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query ** can be rewritten as a GROUP BY. In other words, this: ** ** SELECT DISTINCT xyz FROM ... ORDER BY xyz ** ** is transformed to: ** ** SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz ** ** The second form is preferred as a single index (or temp-table) may be ** used for both the ORDER BY and DISTINCT processing. As originally ** written the query must use a temp-table for at least one of the ORDER ** BY and DISTINCT, and an index or separate temp-table for the other. */ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0 #ifndef SQLITE_OMIT_WINDOWFUNC && p->pWin==0 #endif ){ p->selFlags &= ~SF_Distinct; pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0); p->selFlags |= SF_Aggregate; /* Notice that even thought SF_Distinct has been cleared from p->selFlags, ** the sDistinct.isTnct is still set. Hence, isTnct represents the ** original setting of the SF_Distinct flag, not the current setting */ assert( sDistinct.isTnct ); sDistinct.isTnct = 2; #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x20000 ){ TREETRACE(0x20000,pParse,p,("Transform DISTINCT into GROUP BY:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif } /* If there is an ORDER BY clause, then create an ephemeral index to ** do the sorting. But this sorting ephemeral index might end up ** being unused if the data can be extracted in pre-sorted order. ** If that is the case, then the OP_OpenEphemeral instruction will be ** changed to an OP_Noop once we figure out that the sorting index is ** not needed. The sSort.addrSortIndex variable is used to facilitate ** that change. */ if( sSort.pOrderBy ){ KeyInfo *pKeyInfo; pKeyInfo = sqlite3KeyInfoFromExprList( pParse, sSort.pOrderBy, 0, pEList->nExpr); sSort.iECursor = pParse->nTab++; sSort.addrSortIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0, (char*)pKeyInfo, P4_KEYINFO ); }else{ sSort.addrSortIndex = -1; } /* If the output is destined for a temporary table, open that table. */ if( pDest->eDest==SRT_EphemTab ){ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr); if( p->selFlags & SF_NestedFrom ){ /* Delete or NULL-out result columns that will never be used */ int ii; for(ii=pEList->nExpr-1; ii>0 && pEList->a[ii].fg.bUsed==0; ii--){ sqlite3ExprDelete(db, pEList->a[ii].pExpr); sqlite3DbFree(db, pEList->a[ii].zEName); pEList->nExpr--; } for(ii=0; iinExpr; ii++){ if( pEList->a[ii].fg.bUsed==0 ) pEList->a[ii].pExpr->op = TK_NULL; } } } /* Set the limiter. */ iEnd = sqlite3VdbeMakeLabel(pParse); if( (p->selFlags & SF_FixedLimit)==0 ){ p->nSelectRow = 320; /* 4 billion rows */ } if( p->pLimit ) computeLimitRegisters(pParse, p, iEnd); if( p->iLimit==0 && sSort.addrSortIndex>=0 ){ sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen); sSort.sortFlags |= SORTFLAG_UseSorter; } /* Open an ephemeral index to use for the distinct set. */ if( p->selFlags & SF_Distinct ){ sDistinct.tabTnct = pParse->nTab++; sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, sDistinct.tabTnct, 0, 0, (char*)sqlite3KeyInfoFromExprList(pParse, p->pEList,0,0), P4_KEYINFO); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; }else{ sDistinct.eTnctType = WHERE_DISTINCT_NOOP; } if( !isAgg && pGroupBy==0 ){ /* No aggregate functions and no GROUP BY clause */ u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0) | (p->selFlags & SF_FixedLimit); #ifndef SQLITE_OMIT_WINDOWFUNC Window *pWin = p->pWin; /* Main window object (or NULL) */ if( pWin ){ sqlite3WindowCodeInit(pParse, p); } #endif assert( WHERE_USE_LIMIT==SF_FixedLimit ); /* Begin the database scan. */ TREETRACE(0x2,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, p->pEList, p, wctrlFlags, p->nSelectRow); if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); sSort.labelOBLopt = sqlite3WhereOrderByLimitOptLabel(pWInfo); if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ sSort.pOrderBy = 0; } } TREETRACE(0x2,pParse,p,("WhereBegin returns\n")); /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral ** into an OP_Noop. */ if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){ sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } assert( p->pEList==pEList ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ int addrGosub = sqlite3VdbeMakeLabel(pParse); int iCont = sqlite3VdbeMakeLabel(pParse); int iBreak = sqlite3VdbeMakeLabel(pParse); int regGosub = ++pParse->nMem; sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub); sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); sqlite3VdbeResolveLabel(v, addrGosub); VdbeNoopComment((v, "inner-loop subroutine")); sSort.labelOBLopt = 0; selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp1(v, OP_Return, regGosub); VdbeComment((v, "end inner-loop subroutine")); sqlite3VdbeResolveLabel(v, iBreak); }else #endif /* SQLITE_OMIT_WINDOWFUNC */ { /* Use the standard inner loop. */ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, sqlite3WhereContinueLabel(pWInfo), sqlite3WhereBreakLabel(pWInfo)); /* End the database scan loop. */ TREETRACE(0x2,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); } }else{ /* This case when there exist aggregate functions or a GROUP BY clause ** or both */ NameContext sNC; /* Name context for processing aggregate information */ int iAMem; /* First Mem address for storing current GROUP BY */ int iBMem; /* First Mem address for previous GROUP BY */ int iUseFlag; /* Mem address holding flag indicating that at least ** one row of the input to the aggregator has been ** processed */ int iAbortFlag; /* Mem address which causes query abort if positive */ int groupBySort; /* Rows come from source in GROUP BY order */ int addrEnd; /* End of processing for this SELECT */ int sortPTab = 0; /* Pseudotable used to decode sorting results */ int sortOut = 0; /* Output register from the sorter */ int orderByGrp = 0; /* True if the GROUP BY and ORDER BY are the same */ /* Remove any and all aliases between the result set and the ** GROUP BY clause. */ if( pGroupBy ){ int k; /* Loop counter */ struct ExprList_item *pItem; /* For looping over expression in a list */ for(k=p->pEList->nExpr, pItem=p->pEList->a; k>0; k--, pItem++){ pItem->u.x.iAlias = 0; } for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){ pItem->u.x.iAlias = 0; } assert( 66==sqlite3LogEst(100) ); if( p->nSelectRow>66 ) p->nSelectRow = 66; /* If there is both a GROUP BY and an ORDER BY clause and they are ** identical, then it may be possible to disable the ORDER BY clause ** on the grounds that the GROUP BY will cause elements to come out ** in the correct order. It also may not - the GROUP BY might use a ** database index that causes rows to be grouped together as required ** but not actually sorted. Either way, record the fact that the ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp ** variable. */ if( sSort.pOrderBy && pGroupBy->nExpr==sSort.pOrderBy->nExpr ){ int ii; /* The GROUP BY processing doesn't care whether rows are delivered in ** ASC or DESC order - only that each group is returned contiguously. ** So set the ASC/DESC flags in the GROUP BY to match those in the ** ORDER BY to maximize the chances of rows being delivered in an ** order that makes the ORDER BY redundant. */ for(ii=0; iinExpr; ii++){ u8 sortFlags; sortFlags = sSort.pOrderBy->a[ii].fg.sortFlags & KEYINFO_ORDER_DESC; pGroupBy->a[ii].fg.sortFlags = sortFlags; } if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ orderByGrp = 1; } } }else{ assert( 0==sqlite3LogEst(1) ); p->nSelectRow = 0; } /* Create a label to jump to when we want to abort the query */ addrEnd = sqlite3VdbeMakeLabel(pParse); /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the ** SELECT statement. */ pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) ); if( pAggInfo ){ sqlite3ParserAddCleanup(pParse, agginfoFree, pAggInfo); testcase( pParse->earlyCleanup ); } if( db->mallocFailed ){ goto select_end; } pAggInfo->selId = p->selId; #ifdef SQLITE_DEBUG pAggInfo->pSelect = p; #endif memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; sNC.uNC.pAggInfo = pAggInfo; VVA_ONLY( sNC.ncFlags = NC_UAggInfo; ) pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; pAggInfo->pGroupBy = pGroupBy; sqlite3ExprAnalyzeAggList(&sNC, pEList); sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); if( pHaving ){ if( pGroupBy ){ assert( pWhere==p->pWhere ); assert( pHaving==p->pHaving ); assert( pGroupBy==p->pGroupBy ); havingToWhere(pParse, p); pWhere = p->pWhere; } sqlite3ExprAnalyzeAggregates(&sNC, pHaving); } pAggInfo->nAccumulator = pAggInfo->nColumn; if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){ minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pFExpr, &pMinMaxOrderBy); }else{ minMaxFlag = WHERE_ORDERBY_NORMAL; } analyzeAggFuncArgs(pAggInfo, &sNC); if( db->mallocFailed ) goto select_end; #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x20 ){ TREETRACE(0x20,pParse,p,("After aggregate analysis %p:\n", pAggInfo)); sqlite3TreeViewSelect(0, p, 0); if( minMaxFlag ){ sqlite3DebugPrintf("MIN/MAX Optimization (0x%02x) adds:\n", minMaxFlag); sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY"); } printAggInfo(pAggInfo); } #endif /* Processing for aggregates with GROUP BY is very different and ** much more complex than aggregates without a GROUP BY. */ if( pGroupBy ){ KeyInfo *pKeyInfo; /* Keying information for the group by clause */ int addr1; /* A-vs-B comparison jump */ int addrOutputRow; /* Start of subroutine that outputs a result row */ int regOutputRow; /* Return address register for output subroutine */ int addrSetAbort; /* Set the abort flag and return */ int addrTopOfLoop; /* Top of the input loop */ int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ int addrReset; /* Subroutine for resetting the accumulator */ int regReset; /* Return address register for reset subroutine */ ExprList *pDistinct = 0; u16 distFlag = 0; int eDist = WHERE_DISTINCT_NOOP; if( pAggInfo->nFunc==1 && pAggInfo->aFunc[0].iDistinct>=0 && ALWAYS(pAggInfo->aFunc[0].pFExpr!=0) && ALWAYS(ExprUseXList(pAggInfo->aFunc[0].pFExpr)) && pAggInfo->aFunc[0].pFExpr->x.pList!=0 ){ Expr *pExpr = pAggInfo->aFunc[0].pFExpr->x.pList->a[0].pExpr; pExpr = sqlite3ExprDup(db, pExpr, 0); pDistinct = sqlite3ExprListDup(db, pGroupBy, 0); pDistinct = sqlite3ExprListAppend(pParse, pDistinct, pExpr); distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0; } /* If there is a GROUP BY clause we might need a sorting index to ** implement it. Allocate that sorting index now. If it turns out ** that we do not need it after all, the OP_SorterOpen instruction ** will be converted into a Noop. */ pAggInfo->sortingIdx = pParse->nTab++; pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pGroupBy, 0, pAggInfo->nColumn); addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, pAggInfo->sortingIdx, pAggInfo->nSortingColumn, 0, (char*)pKeyInfo, P4_KEYINFO); /* Initialize memory locations used by GROUP BY aggregate processing */ iUseFlag = ++pParse->nMem; iAbortFlag = ++pParse->nMem; regOutputRow = ++pParse->nMem; addrOutputRow = sqlite3VdbeMakeLabel(pParse); regReset = ++pParse->nMem; addrReset = sqlite3VdbeMakeLabel(pParse); iAMem = pParse->nMem + 1; pParse->nMem += pGroupBy->nExpr; iBMem = pParse->nMem + 1; pParse->nMem += pGroupBy->nExpr; sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag); VdbeComment((v, "clear abort flag")); sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1); /* Begin a loop that will extract all source rows in GROUP BY order. ** This might involve two separate loops with an OP_Sort in between, or ** it might be a single loop that uses an index to extract information ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); TREETRACE(0x2,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct, p, (sDistinct.isTnct==2 ? WHERE_DISTINCTBY : WHERE_GROUPBY) | (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0 ); if( pWInfo==0 ){ sqlite3ExprListDelete(db, pDistinct); goto select_end; } if( pParse->pIdxEpr ){ optimizeAggregateUseOfIndexedExpr(pParse, p, pAggInfo, &sNC); } assignAggregateRegisters(pParse, pAggInfo); eDist = sqlite3WhereIsDistinct(pWInfo); TREETRACE(0x2,pParse,p,("WhereBegin returns\n")); if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){ /* The optimizer is able to deliver rows in group by order so ** we do not have to sort. The OP_OpenEphemeral table will be ** cancelled later because we still need to use the pKeyInfo */ groupBySort = 0; }else{ /* Rows are coming out in undetermined order. We have to push ** each row into a sorting index, terminate the first loop, ** then loop over the sorting index in order to get the output ** in sorted order */ int regBase; int regRecord; int nCol; int nGroupBy; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrExp; /* Address of OP_Explain instruction */ #endif ExplainQueryPlan2(addrExp, (pParse, 0, "USE TEMP B-TREE FOR %s", (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ? "DISTINCT" : "GROUP BY" )); groupBySort = 1; nGroupBy = pGroupBy->nExpr; nCol = nGroupBy; j = nGroupBy; for(i=0; inColumn; i++){ if( pAggInfo->aCol[i].iSorterColumn>=j ){ nCol++; j++; } } regBase = sqlite3GetTempRange(pParse, nCol); sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0); j = nGroupBy; pAggInfo->directMode = 1; for(i=0; inColumn; i++){ struct AggInfo_col *pCol = &pAggInfo->aCol[i]; if( pCol->iSorterColumn>=j ){ sqlite3ExprCode(pParse, pCol->pCExpr, j + regBase); j++; } } pAggInfo->directMode = 0; regRecord = sqlite3GetTempReg(pParse); sqlite3VdbeScanStatusCounters(v, addrExp, 0, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord); sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord); sqlite3VdbeScanStatusRange(v, addrExp, sqlite3VdbeCurrentAddr(v)-2, -1); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nCol); TREETRACE(0x2,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++; sortOut = sqlite3GetTempReg(pParse); sqlite3VdbeScanStatusCounters(v, addrExp, sqlite3VdbeCurrentAddr(v), 0); sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol); sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd); VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); pAggInfo->useSortingIdx = 1; sqlite3VdbeScanStatusRange(v, addrExp, -1, sortPTab); sqlite3VdbeScanStatusRange(v, addrExp, -1, pAggInfo->sortingIdx); } /* If there are entries in pAgggInfo->aFunc[] that contain subexpressions ** that are indexed (and that were previously identified and tagged ** in optimizeAggregateUseOfIndexedExpr()) then those subexpressions ** must now be converted into a TK_AGG_COLUMN node so that the value ** is correctly pulled from the index rather than being recomputed. */ if( pParse->pIdxEpr ){ aggregateConvertIndexedExprRefToColumn(pAggInfo); #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x20 ){ TREETRACE(0x20, pParse, p, ("AggInfo function expressions converted to reference index\n")); sqlite3TreeViewSelect(0, p, 0); printAggInfo(pAggInfo); } #endif } /* If the index or temporary table used by the GROUP BY sort ** will naturally deliver rows in the order required by the ORDER BY ** clause, cancel the ephemeral table open coded earlier. ** ** This is an optimization - the correct answer should result regardless. ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to ** disable this optimization for testing purposes. */ if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder) && (groupBySort || sqlite3WhereIsSorted(pWInfo)) ){ sSort.pOrderBy = 0; sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } /* Evaluate the current GROUP BY terms and store in b0, b1, b2... ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) ** Then compare the current GROUP BY terms against the GROUP BY terms ** from the previous row currently stored in a0, a1, a2... */ addrTopOfLoop = sqlite3VdbeCurrentAddr(v); if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_SorterData, pAggInfo->sortingIdx, sortOut, sortPTab); } for(j=0; jnExpr; j++){ if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); }else{ pAggInfo->directMode = 1; sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); } } sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr, (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO); addr1 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addr1+1, 0, addr1+1); VdbeCoverage(v); /* Generate code that runs whenever the GROUP BY changes. ** Changes in the GROUP BY are detected by the previous code ** block. If there were no changes, this block is skipped. ** ** This code copies current group by terms in b0,b1,b2,... ** over to a0,a1,a2. It then calls the output subroutine ** and resets the aggregate accumulator registers in preparation ** for the next GROUP BY batch. */ sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr); sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); VdbeComment((v, "output one row")); sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); VdbeCoverage(v); VdbeComment((v, "check abort flag")); sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); VdbeComment((v, "reset accumulator")); /* Update the aggregate accumulators based on the content of ** the current row */ sqlite3VdbeJumpHere(v, addr1); updateAccumulator(pParse, iUseFlag, pAggInfo, eDist); sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag); VdbeComment((v, "indicate data in accumulator")); /* End of the loop */ if( groupBySort ){ sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx,addrTopOfLoop); VdbeCoverage(v); }else{ TREETRACE(0x2,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); sqlite3VdbeChangeToNoop(v, addrSortingIdx); } sqlite3ExprListDelete(db, pDistinct); /* Output the final row of result */ sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); VdbeComment((v, "output final row")); /* Jump over the subroutines */ sqlite3VdbeGoto(v, addrEnd); /* Generate a subroutine that outputs a single row of the result ** set. This subroutine first looks at the iUseFlag. If iUseFlag ** is less than or equal to zero, the subroutine is a no-op. If ** the processing calls for the query to abort, this subroutine ** increments the iAbortFlag memory location before returning in ** order to signal the caller to abort. */ addrSetAbort = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, iAbortFlag); VdbeComment((v, "set abort flag")); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); sqlite3VdbeResolveLabel(v, addrOutputRow); addrOutputRow = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v); VdbeComment((v, "Groupby result generator entry point")); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); finalizeAggFunctions(pParse, pAggInfo); sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, addrOutputRow+1, addrSetAbort); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); VdbeComment((v, "end groupby result generator")); /* Generate a subroutine that will reset the group-by accumulator */ sqlite3VdbeResolveLabel(v, addrReset); resetAccumulator(pParse, pAggInfo); sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); VdbeComment((v, "indicate accumulator empty")); sqlite3VdbeAddOp1(v, OP_Return, regReset); if( distFlag!=0 && eDist!=WHERE_DISTINCT_NOOP ){ struct AggInfo_func *pF = &pAggInfo->aFunc[0]; fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr); } } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */ else { Table *pTab; if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){ /* If isSimpleCount() returns a pointer to a Table structure, then ** the SQL statement is of the form: ** ** SELECT count(*) FROM ** ** where the Table structure returned represents table . ** ** This statement is so common that it is optimized specially. The ** OP_Count instruction is executed either on the intkey table that ** contains the data for table or on one of its indexes. It ** is better to execute the op on an index, as indexes are almost ** always spread across less pages than their corresponding tables. */ const int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */ Index *pIdx; /* Iterator variable */ KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */ Index *pBest = 0; /* Best index found so far */ Pgno iRoot = pTab->tnum; /* Root page of scanned b-tree */ sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); /* Search for the index that has the lowest scan cost. ** ** (2011-04-15) Do not do a full scan of an unordered index. ** ** (2013-10-03) Do not count the entries in a partial index. ** ** In practice the KeyInfo structure will not be used. It is only ** passed to keep OP_OpenRead happy. */ if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab); if( !p->pSrc->a[0].fg.notIndexed ){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->bUnordered==0 && pIdx->szIdxRowszTabRow && pIdx->pPartIdxWhere==0 && (!pBest || pIdx->szIdxRowszIdxRow) ){ pBest = pIdx; } } } if( pBest ){ iRoot = pBest->tnum; pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest); } /* Open a read-only cursor, execute the OP_Count, close the cursor. */ sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, (int)iRoot, iDb, 1); if( pKeyInfo ){ sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO); } assignAggregateRegisters(pParse, pAggInfo); sqlite3VdbeAddOp2(v, OP_Count, iCsr, AggInfoFuncReg(pAggInfo,0)); sqlite3VdbeAddOp1(v, OP_Close, iCsr); explainSimpleCount(pParse, pTab, pBest); }else{ int regAcc = 0; /* "populate accumulators" flag */ ExprList *pDistinct = 0; u16 distFlag = 0; int eDist; /* If there are accumulator registers but no min() or max() functions ** without FILTER clauses, allocate register regAcc. Register regAcc ** will contain 0 the first time the inner loop runs, and 1 thereafter. ** The code generated by updateAccumulator() uses this to ensure ** that the accumulator registers are (a) updated only once if ** there are no min() or max functions or (b) always updated for the ** first row visited by the aggregate, so that they are updated at ** least once even if the FILTER clause means the min() or max() ** function visits zero rows. */ if( pAggInfo->nAccumulator ){ for(i=0; inFunc; i++){ if( ExprHasProperty(pAggInfo->aFunc[i].pFExpr, EP_WinFunc) ){ continue; } if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){ break; } } if( i==pAggInfo->nFunc ){ regAcc = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc); } }else if( pAggInfo->nFunc==1 && pAggInfo->aFunc[0].iDistinct>=0 ){ assert( ExprUseXList(pAggInfo->aFunc[0].pFExpr) ); pDistinct = pAggInfo->aFunc[0].pFExpr->x.pList; distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0; } assignAggregateRegisters(pParse, pAggInfo); /* This case runs if the aggregate has no GROUP BY clause. The ** processing is much simpler since there is only a single row ** of output. */ assert( p->pGroupBy==0 ); resetAccumulator(pParse, pAggInfo); /* If this query is a candidate for the min/max optimization, then ** minMaxFlag will have been previously set to either ** WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX and pMinMaxOrderBy will ** be an appropriate ORDER BY expression for the optimization. */ assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 ); assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 ); TREETRACE(0x2,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy, pDistinct, p, minMaxFlag|distFlag, 0); if( pWInfo==0 ){ goto select_end; } TREETRACE(0x2,pParse,p,("WhereBegin returns\n")); eDist = sqlite3WhereIsDistinct(pWInfo); updateAccumulator(pParse, regAcc, pAggInfo, eDist); if( eDist!=WHERE_DISTINCT_NOOP ){ struct AggInfo_func *pF = pAggInfo->aFunc; if( pF ){ fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr); } } if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc); if( minMaxFlag ){ sqlite3WhereMinMaxOptEarlyOut(v, pWInfo); } TREETRACE(0x2,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); finalizeAggFunctions(pParse, pAggInfo); } sSort.pOrderBy = 0; sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); selectInnerLoop(pParse, p, -1, 0, 0, pDest, addrEnd, addrEnd); } sqlite3VdbeResolveLabel(v, addrEnd); } /* endif aggregate query */ if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){ explainTempTable(pParse, "DISTINCT"); } /* If there is an ORDER BY clause, then we need to sort the results ** and send them to the callback one by one. */ if( sSort.pOrderBy ){ assert( p->pEList==pEList ); generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); } /* Jump here to skip this query */ sqlite3VdbeResolveLabel(v, iEnd); /* The SELECT has been coded. If there is an error in the Parse structure, ** set the return code to 1. Otherwise 0. */ rc = (pParse->nErr>0); /* Control jumps to here if an error is encountered above, or upon ** successful coding of the SELECT. */ select_end: assert( db->mallocFailed==0 || db->mallocFailed==1 ); assert( db->mallocFailed==0 || pParse->nErr!=0 ); sqlite3ExprListDelete(db, pMinMaxOrderBy); #ifdef SQLITE_DEBUG if( pAggInfo && !db->mallocFailed ){ for(i=0; inColumn; i++){ Expr *pExpr = pAggInfo->aCol[i].pCExpr; if( pExpr==0 ) continue; assert( pExpr->pAggInfo==pAggInfo ); assert( pExpr->iAgg==i ); } for(i=0; inFunc; i++){ Expr *pExpr = pAggInfo->aFunc[i].pFExpr; assert( pExpr!=0 ); assert( pExpr->pAggInfo==pAggInfo ); assert( pExpr->iAgg==i ); } } #endif #if TREETRACE_ENABLED TREETRACE(0x1,pParse,p,("end processing\n")); if( (sqlite3TreeTrace & 0x40000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ sqlite3TreeViewSelect(0, p, 0); } #endif ExplainQueryPlanPop(pParse); return rc; } /************** End of select.c **********************************************/ /************** Begin file table.c *******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the sqlite3_get_table() and sqlite3_free_table() ** interface routines. These are just wrappers around the main ** interface routine of sqlite3_exec(). ** ** These routines are in a separate files so that they will not be linked ** if they are not used. */ /* #include "sqliteInt.h" */ #ifndef SQLITE_OMIT_GET_TABLE /* ** This structure is used to pass data from sqlite3_get_table() through ** to the callback function is uses to build the result. */ typedef struct TabResult { char **azResult; /* Accumulated output */ char *zErrMsg; /* Error message text, if an error occurs */ u32 nAlloc; /* Slots allocated for azResult[] */ u32 nRow; /* Number of rows in the result */ u32 nColumn; /* Number of columns in the result */ u32 nData; /* Slots used in azResult[]. (nRow+1)*nColumn */ int rc; /* Return code from sqlite3_exec() */ } TabResult; /* ** This routine is called once for each row in the result table. Its job ** is to fill in the TabResult structure appropriately, allocating new ** memory as necessary. */ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ TabResult *p = (TabResult*)pArg; /* Result accumulator */ int need; /* Slots needed in p->azResult[] */ int i; /* Loop counter */ char *z; /* A single column of result */ /* Make sure there is enough space in p->azResult to hold everything ** we need to remember from this invocation of the callback. */ if( p->nRow==0 && argv!=0 ){ need = nCol*2; }else{ need = nCol; } if( p->nData + need > p->nAlloc ){ char **azNew; p->nAlloc = p->nAlloc*2 + need; azNew = sqlite3Realloc( p->azResult, sizeof(char*)*p->nAlloc ); if( azNew==0 ) goto malloc_failed; p->azResult = azNew; } /* If this is the first row, then generate an extra row containing ** the names of all columns. */ if( p->nRow==0 ){ p->nColumn = nCol; for(i=0; iazResult[p->nData++] = z; } }else if( (int)p->nColumn!=nCol ){ sqlite3_free(p->zErrMsg); p->zErrMsg = sqlite3_mprintf( "sqlite3_get_table() called with two or more incompatible queries" ); p->rc = SQLITE_ERROR; return 1; } /* Copy over the row data */ if( argv!=0 ){ for(i=0; iazResult[p->nData++] = z; } p->nRow++; } return 0; malloc_failed: p->rc = SQLITE_NOMEM_BKPT; return 1; } /* ** Query the database. But instead of invoking a callback for each row, ** malloc() for space to hold the result and return the entire results ** at the conclusion of the call. ** ** The result that is written to ***pazResult is held in memory obtained ** from malloc(). But the caller cannot free this memory directly. ** Instead, the entire table should be passed to sqlite3_free_table() when ** the calling procedure is finished using it. */ SQLITE_API int sqlite3_get_table( sqlite3 *db, /* The database on which the SQL executes */ const char *zSql, /* The SQL to be executed */ char ***pazResult, /* Write the result table here */ int *pnRow, /* Write the number of rows in the result here */ int *pnColumn, /* Write the number of columns of result here */ char **pzErrMsg /* Write error messages here */ ){ int rc; TabResult res; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || pazResult==0 ) return SQLITE_MISUSE_BKPT; #endif *pazResult = 0; if( pnColumn ) *pnColumn = 0; if( pnRow ) *pnRow = 0; if( pzErrMsg ) *pzErrMsg = 0; res.zErrMsg = 0; res.nRow = 0; res.nColumn = 0; res.nData = 1; res.nAlloc = 20; res.rc = SQLITE_OK; res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc ); if( res.azResult==0 ){ db->errCode = SQLITE_NOMEM; return SQLITE_NOMEM_BKPT; } res.azResult[0] = 0; rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg); assert( sizeof(res.azResult[0])>= sizeof(res.nData) ); res.azResult[0] = SQLITE_INT_TO_PTR(res.nData); if( (rc&0xff)==SQLITE_ABORT ){ sqlite3_free_table(&res.azResult[1]); if( res.zErrMsg ){ if( pzErrMsg ){ sqlite3_free(*pzErrMsg); *pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg); } sqlite3_free(res.zErrMsg); } db->errCode = res.rc; /* Assume 32-bit assignment is atomic */ return res.rc; } sqlite3_free(res.zErrMsg); if( rc!=SQLITE_OK ){ sqlite3_free_table(&res.azResult[1]); return rc; } if( res.nAlloc>res.nData ){ char **azNew; azNew = sqlite3Realloc( res.azResult, sizeof(char*)*res.nData ); if( azNew==0 ){ sqlite3_free_table(&res.azResult[1]); db->errCode = SQLITE_NOMEM; return SQLITE_NOMEM_BKPT; } res.azResult = azNew; } *pazResult = &res.azResult[1]; if( pnColumn ) *pnColumn = res.nColumn; if( pnRow ) *pnRow = res.nRow; return rc; } /* ** This routine frees the space the sqlite3_get_table() malloced. */ SQLITE_API void sqlite3_free_table( char **azResult /* Result returned from sqlite3_get_table() */ ){ if( azResult ){ int i, n; azResult--; assert( azResult!=0 ); n = SQLITE_PTR_TO_INT(azResult[0]); for(i=1; ipNext; sqlite3ExprDelete(db, pTmp->pWhere); sqlite3ExprListDelete(db, pTmp->pExprList); sqlite3SelectDelete(db, pTmp->pSelect); sqlite3IdListDelete(db, pTmp->pIdList); sqlite3UpsertDelete(db, pTmp->pUpsert); sqlite3SrcListDelete(db, pTmp->pFrom); sqlite3DbFree(db, pTmp->zSpan); sqlite3DbFree(db, pTmp); } } /* ** Given table pTab, return a list of all the triggers attached to ** the table. The list is connected by Trigger.pNext pointers. ** ** All of the triggers on pTab that are in the same database as pTab ** are already attached to pTab->pTrigger. But there might be additional ** triggers on pTab in the TEMP schema. This routine prepends all ** TEMP triggers on pTab to the beginning of the pTab->pTrigger list ** and returns the combined list. ** ** To state it another way: This routine returns a list of all triggers ** that fire off of pTab. The list will include any TEMP triggers on ** pTab as well as the triggers lised in pTab->pTrigger. */ SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ Schema *pTmpSchema; /* Schema of the pTab table */ Trigger *pList; /* List of triggers to return */ HashElem *p; /* Loop variable for TEMP triggers */ assert( pParse->disableTriggers==0 ); pTmpSchema = pParse->db->aDb[1].pSchema; p = sqliteHashFirst(&pTmpSchema->trigHash); pList = pTab->pTrigger; while( p ){ Trigger *pTrig = (Trigger *)sqliteHashData(p); if( pTrig->pTabSchema==pTab->pSchema && pTrig->table && 0==sqlite3StrICmp(pTrig->table, pTab->zName) && (pTrig->pTabSchema!=pTmpSchema || pTrig->bReturning) ){ pTrig->pNext = pList; pList = pTrig; }else if( pTrig->op==TK_RETURNING ){ #ifndef SQLITE_OMIT_VIRTUALTABLE assert( pParse->db->pVtabCtx==0 ); #endif assert( pParse->bReturning ); assert( &(pParse->u1.pReturning->retTrig) == pTrig ); pTrig->table = pTab->zName; pTrig->pTabSchema = pTab->pSchema; pTrig->pNext = pList; pList = pTrig; } p = sqliteHashNext(p); } #if 0 if( pList ){ Trigger *pX; printf("Triggers for %s:", pTab->zName); for(pX=pList; pX; pX=pX->pNext){ printf(" %s", pX->zName); } printf("\n"); fflush(stdout); } #endif return pList; } /* ** This is called by the parser when it sees a CREATE TRIGGER statement ** up to the point of the BEGIN before the trigger actions. A Trigger ** structure is generated based on the information available and stored ** in pParse->pNewTrigger. After the trigger actions have been parsed, the ** sqlite3FinishTrigger() function is called to complete the trigger ** construction process. */ SQLITE_PRIVATE void sqlite3BeginTrigger( Parse *pParse, /* The parse context of the CREATE TRIGGER statement */ Token *pName1, /* The name of the trigger */ Token *pName2, /* The name of the trigger */ int tr_tm, /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */ int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */ IdList *pColumns, /* column list if this is an UPDATE OF trigger */ SrcList *pTableName,/* The name of the table/view the trigger applies to */ Expr *pWhen, /* WHEN clause */ int isTemp, /* True if the TEMPORARY keyword is present */ int noErr /* Suppress errors if the trigger already exists */ ){ Trigger *pTrigger = 0; /* The new trigger */ Table *pTab; /* Table that the trigger fires off of */ char *zName = 0; /* Name of the trigger */ sqlite3 *db = pParse->db; /* The database connection */ int iDb; /* The database to store the trigger in */ Token *pName; /* The unqualified db name */ DbFixer sFix; /* State vector for the DB fixer */ assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */ assert( pName2!=0 ); assert( op==TK_INSERT || op==TK_UPDATE || op==TK_DELETE ); assert( op>0 && op<0xff ); if( isTemp ){ /* If TEMP was specified, then the trigger name may not be qualified. */ if( pName2->n>0 ){ sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name"); goto trigger_cleanup; } iDb = 1; pName = pName1; }else{ /* Figure out the db that the trigger will be created in */ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); if( iDb<0 ){ goto trigger_cleanup; } } if( !pTableName || db->mallocFailed ){ goto trigger_cleanup; } /* A long-standing parser bug is that this syntax was allowed: ** ** CREATE TRIGGER attached.demo AFTER INSERT ON attached.tab .... ** ^^^^^^^^ ** ** To maintain backwards compatibility, ignore the database ** name on pTableName if we are reparsing out of the schema table */ if( db->init.busy && iDb!=1 ){ sqlite3DbFree(db, pTableName->a[0].zDatabase); pTableName->a[0].zDatabase = 0; } /* If the trigger name was unqualified, and the table is a temp table, ** then set iDb to 1 to create the trigger in the temporary database. ** If sqlite3SrcListLookup() returns 0, indicating the table does not ** exist, the error is caught by the block below. */ pTab = sqlite3SrcListLookup(pParse, pTableName); if( db->init.busy==0 && pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ iDb = 1; } /* Ensure the table name matches database name and that the table exists */ if( db->mallocFailed ) goto trigger_cleanup; assert( pTableName->nSrc==1 ); sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName); if( sqlite3FixSrcList(&sFix, pTableName) ){ goto trigger_cleanup; } pTab = sqlite3SrcListLookup(pParse, pTableName); if( !pTab ){ /* The table does not exist. */ goto trigger_orphan_error; } if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); goto trigger_orphan_error; } if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){ sqlite3ErrorMsg(pParse, "cannot create triggers on shadow tables"); goto trigger_orphan_error; } /* Check that the trigger name is not reserved and that no trigger of the ** specified name exists */ zName = sqlite3NameFromToken(db, pName); if( zName==0 ){ assert( db->mallocFailed ); goto trigger_cleanup; } if( sqlite3CheckObjectName(pParse, zName, "trigger", pTab->zName) ){ goto trigger_cleanup; } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !IN_RENAME_OBJECT ){ if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); }else{ assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); VVA_ONLY( pParse->ifNotExists = 1; ) } goto trigger_cleanup; } } /* Do not create a trigger on a system table */ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); goto trigger_cleanup; } /* INSTEAD of triggers are only for views and views only support INSTEAD ** of triggers. */ if( IsView(pTab) && tr_tm!=TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName->a); goto trigger_orphan_error; } if( !IsView(pTab) && tr_tm==TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" " trigger on table: %S", pTableName->a); goto trigger_orphan_error; } #ifndef SQLITE_OMIT_AUTHORIZATION if( !IN_RENAME_OBJECT ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int code = SQLITE_CREATE_TRIGGER; const char *zDb = db->aDb[iTabDb].zDbSName; const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb; if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ goto trigger_cleanup; } if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){ goto trigger_cleanup; } } #endif /* INSTEAD OF triggers can only appear on views and BEFORE triggers ** cannot appear on views. So we might as well translate every ** INSTEAD OF trigger into a BEFORE trigger. It simplifies code ** elsewhere. */ if (tr_tm == TK_INSTEAD){ tr_tm = TK_BEFORE; } /* Build the Trigger object */ pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); if( pTrigger==0 ) goto trigger_cleanup; pTrigger->zName = zName; zName = 0; pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName); pTrigger->pWhen = pWhen; pWhen = 0; }else{ pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); } pTrigger->pColumns = pColumns; pColumns = 0; assert( pParse->pNewTrigger==0 ); pParse->pNewTrigger = pTrigger; trigger_cleanup: sqlite3DbFree(db, zName); sqlite3SrcListDelete(db, pTableName); sqlite3IdListDelete(db, pColumns); sqlite3ExprDelete(db, pWhen); if( !pParse->pNewTrigger ){ sqlite3DeleteTrigger(db, pTrigger); }else{ assert( pParse->pNewTrigger==pTrigger ); } return; trigger_orphan_error: if( db->init.iDb==1 ){ /* Ticket #3810. ** Normally, whenever a table is dropped, all associated triggers are ** dropped too. But if a TEMP trigger is created on a non-TEMP table ** and the table is dropped by a different database connection, the ** trigger is not visible to the database connection that does the ** drop so the trigger cannot be dropped. This results in an ** "orphaned trigger" - a trigger whose associated table is missing. ** ** 2020-11-05 see also https://sqlite.org/forum/forumpost/157dc791df */ db->init.orphanTrigger = 1; } goto trigger_cleanup; } /* ** This routine is called after all of the trigger actions have been parsed ** in order to complete the process of building the trigger. */ SQLITE_PRIVATE void sqlite3FinishTrigger( Parse *pParse, /* Parser context */ TriggerStep *pStepList, /* The triggered program */ Token *pAll /* Token that describes the complete CREATE TRIGGER */ ){ Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */ char *zName; /* Name of trigger */ sqlite3 *db = pParse->db; /* The database */ DbFixer sFix; /* Fixer object */ int iDb; /* Database containing the trigger */ Token nameToken; /* Trigger name for error reporting */ pParse->pNewTrigger = 0; if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; zName = pTrig->zName; iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); pTrig->step_list = pStepList; while( pStepList ){ pStepList->pTrig = pTrig; pStepList = pStepList->pNext; } sqlite3TokenInit(&nameToken, pTrig->zName); sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken); if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) || sqlite3FixExpr(&sFix, pTrig->pWhen) ){ goto triggerfinish_cleanup; } #ifndef SQLITE_OMIT_ALTERTABLE if( IN_RENAME_OBJECT ){ assert( !db->init.busy ); pParse->pNewTrigger = pTrig; pTrig = 0; }else #endif /* if we are not initializing, ** build the sqlite_schema entry */ if( !db->init.busy ){ Vdbe *v; char *z; /* If this is a new CREATE TABLE statement, and if shadow tables ** are read-only, and the trigger makes a change to a shadow table, ** then raise an error - do not allow the trigger to be created. */ if( sqlite3ReadOnlyShadowTables(db) ){ TriggerStep *pStep; for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){ if( pStep->zTarget!=0 && sqlite3ShadowTableName(db, pStep->zTarget) ){ sqlite3ErrorMsg(pParse, "trigger \"%s\" may not write to shadow table \"%s\"", pTrig->zName, pStep->zTarget); goto triggerfinish_cleanup; } } } /* Make an entry in the sqlite_schema table */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); testcase( z==0 ); sqlite3NestedParse(pParse, "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db->aDb[iDb].zDbSName, zName, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0); } if( db->init.busy ){ Trigger *pLink = pTrig; Hash *pHash = &db->aDb[iDb].pSchema->trigHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); assert( pLink!=0 ); pTrig = sqlite3HashInsert(pHash, zName, pTrig); if( pTrig ){ sqlite3OomFault(db); }else if( pLink->pSchema==pLink->pTabSchema ){ Table *pTab; pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table); assert( pTab!=0 ); pLink->pNext = pTab->pTrigger; pTab->pTrigger = pLink; } } triggerfinish_cleanup: sqlite3DeleteTrigger(db, pTrig); assert( IN_RENAME_OBJECT || !pParse->pNewTrigger ); sqlite3DeleteTriggerStep(db, pStepList); } /* ** Duplicate a range of text from an SQL statement, then convert all ** whitespace characters into ordinary space characters. */ static char *triggerSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){ char *z = sqlite3DbSpanDup(db, zStart, zEnd); int i; if( z ) for(i=0; z[i]; i++) if( sqlite3Isspace(z[i]) ) z[i] = ' '; return z; } /* ** Turn a SELECT statement (that the pSelect parameter points to) into ** a trigger step. Return a pointer to a TriggerStep structure. ** ** The parser calls this routine when it finds a SELECT statement in ** body of a TRIGGER. */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep( sqlite3 *db, /* Database connection */ Select *pSelect, /* The SELECT statement */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep)); if( pTriggerStep==0 ) { sqlite3SelectDelete(db, pSelect); return 0; } pTriggerStep->op = TK_SELECT; pTriggerStep->pSelect = pSelect; pTriggerStep->orconf = OE_Default; pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); return pTriggerStep; } /* ** Allocate space to hold a new trigger step. The allocated space ** holds both the TriggerStep object and the TriggerStep.target.z string. ** ** If an OOM error occurs, NULL is returned and db->mallocFailed is set. */ static TriggerStep *triggerStepAllocate( Parse *pParse, /* Parser context */ u8 op, /* Trigger opcode */ Token *pName, /* The target name */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; if( pParse->nErr ) return 0; pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1); if( pTriggerStep ){ char *z = (char*)&pTriggerStep[1]; memcpy(z, pName->z, pName->n); sqlite3Dequote(z); pTriggerStep->zTarget = z; pTriggerStep->op = op; pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName); } } return pTriggerStep; } /* ** Build a trigger step out of an INSERT statement. Return a pointer ** to the new trigger step. ** ** The parser calls this routine when it sees an INSERT inside the ** body of a trigger. */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table into which we insert */ IdList *pColumn, /* List of columns in pTableName to insert into */ Select *pSelect, /* A SELECT statement that supplies values */ u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ Upsert *pUpsert, /* ON CONFLICT clauses for upsert */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; assert(pSelect != 0 || db->mallocFailed); pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pSelect = pSelect; pSelect = 0; }else{ pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); } pTriggerStep->pIdList = pColumn; pTriggerStep->pUpsert = pUpsert; pTriggerStep->orconf = orconf; if( pUpsert ){ sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget); } }else{ testcase( pColumn ); sqlite3IdListDelete(db, pColumn); testcase( pUpsert ); sqlite3UpsertDelete(db, pUpsert); } sqlite3SelectDelete(db, pSelect); return pTriggerStep; } /* ** Construct a trigger step that implements an UPDATE statement and return ** a pointer to that trigger step. The parser calls this routine when it ** sees an UPDATE statement inside the body of a CREATE TRIGGER. */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table to be updated */ SrcList *pFrom, /* FROM clause for an UPDATE-FROM, or NULL */ ExprList *pEList, /* The SET clause: list of column and new values */ Expr *pWhere, /* The WHERE clause */ u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pExprList = pEList; pTriggerStep->pWhere = pWhere; pTriggerStep->pFrom = pFrom; pEList = 0; pWhere = 0; pFrom = 0; }else{ pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pTriggerStep->pFrom = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE); } pTriggerStep->orconf = orconf; } sqlite3ExprListDelete(db, pEList); sqlite3ExprDelete(db, pWhere); sqlite3SrcListDelete(db, pFrom); return pTriggerStep; } /* ** Construct a trigger step that implements a DELETE statement and return ** a pointer to that trigger step. The parser calls this routine when it ** sees a DELETE statement inside the body of a CREATE TRIGGER. */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep( Parse *pParse, /* Parser */ Token *pTableName, /* The table from which rows are deleted */ Expr *pWhere, /* The WHERE clause */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pWhere = pWhere; pWhere = 0; }else{ pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); } pTriggerStep->orconf = OE_Default; } sqlite3ExprDelete(db, pWhere); return pTriggerStep; } /* ** Recursively delete a Trigger structure */ SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ if( pTrigger==0 || pTrigger->bReturning ) return; sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); sqlite3ExprDelete(db, pTrigger->pWhen); sqlite3IdListDelete(db, pTrigger->pColumns); sqlite3DbFree(db, pTrigger); } /* ** This function is called to drop a trigger from the database schema. ** ** This may be called directly from the parser and therefore identifies ** the trigger by name. The sqlite3DropTriggerPtr() routine does the ** same job as this routine except it takes a pointer to the trigger ** instead of the trigger name. **/ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){ Trigger *pTrigger = 0; int i; const char *zDb; const char *zName; sqlite3 *db = pParse->db; if( db->mallocFailed ) goto drop_trigger_cleanup; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto drop_trigger_cleanup; } assert( pName->nSrc==1 ); zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); if( pTrigger ) break; } if( !pTrigger ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a); }else{ sqlite3CodeVerifyNamedSchema(pParse, zDb); } pParse->checkSchema = 1; goto drop_trigger_cleanup; } sqlite3DropTriggerPtr(pParse, pTrigger); drop_trigger_cleanup: sqlite3SrcListDelete(db, pName); } /* ** Return a pointer to the Table structure for the table that a trigger ** is set on. */ static Table *tableOfTrigger(Trigger *pTrigger){ return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table); } /* ** Drop a trigger given a pointer to that trigger. */ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ Table *pTable; Vdbe *v; sqlite3 *db = pParse->db; int iDb; iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); assert( iDb>=0 && iDbnDb ); pTable = tableOfTrigger(pTrigger); assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION if( pTable ){ int code = SQLITE_DROP_TRIGGER; const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) || sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ return; } } #endif /* Generate code to destroy the database record of the trigger. */ if( (v = sqlite3GetVdbe(pParse))!=0 ){ sqlite3NestedParse(pParse, "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'", db->aDb[iDb].zDbSName, pTrigger->zName ); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); } } /* ** Remove a trigger from the hash tables of the sqlite* pointer. */ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ Trigger *pTrigger; Hash *pHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pHash = &(db->aDb[iDb].pSchema->trigHash); pTrigger = sqlite3HashInsert(pHash, zName, 0); if( ALWAYS(pTrigger) ){ if( pTrigger->pSchema==pTrigger->pTabSchema ){ Table *pTab = tableOfTrigger(pTrigger); if( pTab ){ Trigger **pp; for(pp=&pTab->pTrigger; *pp; pp=&((*pp)->pNext)){ if( *pp==pTrigger ){ *pp = (*pp)->pNext; break; } } } } sqlite3DeleteTrigger(db, pTrigger); db->mDbFlags |= DBFLAG_SchemaChange; } } /* ** pEList is the SET clause of an UPDATE statement. Each entry ** in pEList is of the format =. If any of the entries ** in pEList have an which matches an identifier in pIdList, ** then return TRUE. If pIdList==NULL, then it is considered a ** wildcard that matches anything. Likewise if pEList==NULL then ** it matches anything so always return true. Return false only ** if there is no match. */ static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){ int e; if( pIdList==0 || NEVER(pEList==0) ) return 1; for(e=0; enExpr; e++){ if( sqlite3IdListIndex(pIdList, pEList->a[e].zEName)>=0 ) return 1; } return 0; } /* ** Return true if any TEMP triggers exist */ static int tempTriggersExist(sqlite3 *db){ if( NEVER(db->aDb[1].pSchema==0) ) return 0; if( sqliteHashFirst(&db->aDb[1].pSchema->trigHash)==0 ) return 0; return 1; } /* ** Return a list of all triggers on table pTab if there exists at least ** one trigger that must be fired when an operation of type 'op' is ** performed on the table, and, if that operation is an UPDATE, if at ** least one of the columns in pChanges is being modified. */ static SQLITE_NOINLINE Trigger *triggersReallyExist( Parse *pParse, /* Parse context */ Table *pTab, /* The table the contains the triggers */ int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ ExprList *pChanges, /* Columns that change in an UPDATE statement */ int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ ){ int mask = 0; Trigger *pList = 0; Trigger *p; pList = sqlite3TriggerList(pParse, pTab); assert( pList==0 || IsVirtual(pTab)==0 || (pList->bReturning && pList->pNext==0) ); if( pList!=0 ){ p = pList; if( (pParse->db->flags & SQLITE_EnableTrigger)==0 && pTab->pTrigger!=0 ){ /* The SQLITE_DBCONFIG_ENABLE_TRIGGER setting is off. That means that ** only TEMP triggers are allowed. Truncate the pList so that it ** includes only TEMP triggers */ if( pList==pTab->pTrigger ){ pList = 0; goto exit_triggers_exist; } while( ALWAYS(p->pNext) && p->pNext!=pTab->pTrigger ) p = p->pNext; p->pNext = 0; p = pList; } do{ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ mask |= p->tr_tm; }else if( p->op==TK_RETURNING ){ /* The first time a RETURNING trigger is seen, the "op" value tells ** us what time of trigger it should be. */ assert( sqlite3IsToplevel(pParse) ); p->op = op; if( IsVirtual(pTab) ){ if( op!=TK_INSERT ){ sqlite3ErrorMsg(pParse, "%s RETURNING is not available on virtual tables", op==TK_DELETE ? "DELETE" : "UPDATE"); } p->tr_tm = TRIGGER_BEFORE; }else{ p->tr_tm = TRIGGER_AFTER; } mask |= p->tr_tm; }else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE && sqlite3IsToplevel(pParse) ){ /* Also fire a RETURNING trigger for an UPSERT */ mask |= p->tr_tm; } p = p->pNext; }while( p ); } exit_triggers_exist: if( pMask ){ *pMask = mask; } return (mask ? pList : 0); } SQLITE_PRIVATE Trigger *sqlite3TriggersExist( Parse *pParse, /* Parse context */ Table *pTab, /* The table the contains the triggers */ int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ ExprList *pChanges, /* Columns that change in an UPDATE statement */ int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ ){ assert( pTab!=0 ); if( (pTab->pTrigger==0 && !tempTriggersExist(pParse->db)) || pParse->disableTriggers ){ if( pMask ) *pMask = 0; return 0; } return triggersReallyExist(pParse,pTab,op,pChanges,pMask); } /* ** Convert the pStep->zTarget string into a SrcList and return a pointer ** to that SrcList. ** ** This routine adds a specific database name, if needed, to the target when ** forming the SrcList. This prevents a trigger in one database from ** referring to a target in another database. An exception is when the ** trigger is in TEMP in which case it can refer to any other database it ** wants. */ SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc( Parse *pParse, /* The parsing context */ TriggerStep *pStep /* The trigger containing the target token */ ){ sqlite3 *db = pParse->db; SrcList *pSrc; /* SrcList to be returned */ char *zName = sqlite3DbStrDup(db, pStep->zTarget); pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); assert( pSrc==0 || pSrc->nSrc==1 ); assert( zName || pSrc==0 ); if( pSrc ){ Schema *pSchema = pStep->pTrig->pSchema; pSrc->a[0].zName = zName; if( pSchema!=db->aDb[1].pSchema ){ pSrc->a[0].pSchema = pSchema; } if( pStep->pFrom ){ SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0); if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){ Select *pSubquery; Token as; pSubquery = sqlite3SelectNew(pParse,0,pDup,0,0,0,0,SF_NestedFrom,0); as.n = 0; as.z = 0; pDup = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); } pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup); } }else{ sqlite3DbFree(db, zName); } return pSrc; } /* ** Return true if the pExpr term from the RETURNING clause argument ** list is of the form "*". Raise an error if the terms if of the ** form "table.*". */ static int isAsteriskTerm( Parse *pParse, /* Parsing context */ Expr *pTerm /* A term in the RETURNING clause */ ){ assert( pTerm!=0 ); if( pTerm->op==TK_ASTERISK ) return 1; if( pTerm->op!=TK_DOT ) return 0; assert( pTerm->pRight!=0 ); assert( pTerm->pLeft!=0 ); if( pTerm->pRight->op!=TK_ASTERISK ) return 0; sqlite3ErrorMsg(pParse, "RETURNING may not use \"TABLE.*\" wildcards"); return 1; } /* The input list pList is the list of result set terms from a RETURNING ** clause. The table that we are returning from is pTab. ** ** This routine makes a copy of the pList, and at the same time expands ** any "*" wildcards to be the complete set of columns from pTab. */ static ExprList *sqlite3ExpandReturning( Parse *pParse, /* Parsing context */ ExprList *pList, /* The arguments to RETURNING */ Table *pTab /* The table being updated */ ){ ExprList *pNew = 0; sqlite3 *db = pParse->db; int i; for(i=0; inExpr; i++){ Expr *pOldExpr = pList->a[i].pExpr; if( NEVER(pOldExpr==0) ) continue; if( isAsteriskTerm(pParse, pOldExpr) ){ int jj; for(jj=0; jjnCol; jj++){ Expr *pNewExpr; if( IsHiddenColumn(pTab->aCol+jj) ) continue; pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zCnName); pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); if( !db->mallocFailed ){ struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zCnName); pItem->fg.eEName = ENAME_NAME; } } }else{ Expr *pNewExpr = sqlite3ExprDup(db, pOldExpr, 0); pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); if( !db->mallocFailed && ALWAYS(pList->a[i].zEName!=0) ){ struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; pItem->zEName = sqlite3DbStrDup(db, pList->a[i].zEName); pItem->fg.eEName = pList->a[i].fg.eEName; } } } return pNew; } /* ** Generate code for the RETURNING trigger. Unlike other triggers ** that invoke a subprogram in the bytecode, the code for RETURNING ** is generated in-line. */ static void codeReturningTrigger( Parse *pParse, /* Parse context */ Trigger *pTrigger, /* The trigger step that defines the RETURNING */ Table *pTab, /* The table to code triggers from */ int regIn /* The first in an array of registers */ ){ Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; ExprList *pNew; Returning *pReturning; Select sSelect; SrcList sFrom; assert( v!=0 ); if( !pParse->bReturning ){ /* This RETURNING trigger must be for a different statement as ** this statement lacks a RETURNING clause. */ return; } assert( db->pParse==pParse ); pReturning = pParse->u1.pReturning; if( pTrigger != &(pReturning->retTrig) ){ /* This RETURNING trigger is for a different statement */ return; } memset(&sSelect, 0, sizeof(sSelect)); memset(&sFrom, 0, sizeof(sFrom)); sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); sSelect.pSrc = &sFrom; sFrom.nSrc = 1; sFrom.a[0].pTab = pTab; sFrom.a[0].iCursor = -1; sqlite3SelectPrep(pParse, &sSelect, 0); if( pParse->nErr==0 ){ assert( db->mallocFailed==0 ); sqlite3GenerateColumnNames(pParse, &sSelect); } sqlite3ExprListDelete(db, sSelect.pEList); pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab); if( pParse->nErr==0 ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); if( pReturning->nRetCol==0 ){ pReturning->nRetCol = pNew->nExpr; pReturning->iRetCur = pParse->nTab++; } sNC.pParse = pParse; sNC.uNC.iBaseReg = regIn; sNC.ncFlags = NC_UBaseReg; pParse->eTriggerOp = pTrigger->op; pParse->pTriggerTab = pTab; if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK && ALWAYS(!db->mallocFailed) ){ int i; int nCol = pNew->nExpr; int reg = pParse->nMem+1; pParse->nMem += nCol+2; pReturning->iRetReg = reg; for(i=0; ia[i].pExpr; assert( pCol!=0 ); /* Due to !db->mallocFailed ~9 lines above */ sqlite3ExprCodeFactorable(pParse, pCol, reg+i); if( sqlite3ExprAffinity(pCol)==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, reg+i); } } sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, i, reg+i); sqlite3VdbeAddOp2(v, OP_NewRowid, pReturning->iRetCur, reg+i+1); sqlite3VdbeAddOp3(v, OP_Insert, pReturning->iRetCur, reg+i, reg+i+1); } } sqlite3ExprListDelete(db, pNew); pParse->eTriggerOp = 0; pParse->pTriggerTab = 0; } /* ** Generate VDBE code for the statements inside the body of a single ** trigger. */ static int codeTriggerProgram( Parse *pParse, /* The parser context */ TriggerStep *pStepList, /* List of statements inside the trigger body */ int orconf /* Conflict algorithm. (OE_Abort, etc) */ ){ TriggerStep *pStep; Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; assert( pParse->pTriggerTab && pParse->pToplevel ); assert( pStepList ); assert( v!=0 ); for(pStep=pStepList; pStep; pStep=pStep->pNext){ /* Figure out the ON CONFLICT policy that will be used for this step ** of the trigger program. If the statement that caused this trigger ** to fire had an explicit ON CONFLICT, then use it. Otherwise, use ** the ON CONFLICT policy that was specified as part of the trigger ** step statement. Example: ** ** CREATE TRIGGER AFTER INSERT ON t1 BEGIN; ** INSERT OR REPLACE INTO t2 VALUES(new.a, new.b); ** END; ** ** INSERT INTO t1 ... ; -- insert into t2 uses REPLACE policy ** INSERT OR IGNORE INTO t1 ... ; -- insert into t2 uses IGNORE policy */ pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf; assert( pParse->okConstFactor==0 ); #ifndef SQLITE_OMIT_TRACE if( pStep->zSpan ){ sqlite3VdbeAddOp4(v, OP_Trace, 0x7fffffff, 1, 0, sqlite3MPrintf(db, "-- %s", pStep->zSpan), P4_DYNAMIC); } #endif switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, sqlite3TriggerStepSrc(pParse, pStep), sqlite3ExprListDup(db, pStep->pExprList, 0), sqlite3ExprDup(db, pStep->pWhere, 0), pParse->eOrconf, 0, 0, 0 ); sqlite3VdbeAddOp0(v, OP_ResetCount); break; } case TK_INSERT: { sqlite3Insert(pParse, sqlite3TriggerStepSrc(pParse, pStep), sqlite3SelectDup(db, pStep->pSelect, 0), sqlite3IdListDup(db, pStep->pIdList), pParse->eOrconf, sqlite3UpsertDup(db, pStep->pUpsert) ); sqlite3VdbeAddOp0(v, OP_ResetCount); break; } case TK_DELETE: { sqlite3DeleteFrom(pParse, sqlite3TriggerStepSrc(pParse, pStep), sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0 ); sqlite3VdbeAddOp0(v, OP_ResetCount); break; } default: assert( pStep->op==TK_SELECT ); { SelectDest sDest; Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0); sqlite3SelectDestInit(&sDest, SRT_Discard, 0); sqlite3Select(pParse, pSelect, &sDest); sqlite3SelectDelete(db, pSelect); break; } } } return 0; } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS /* ** This function is used to add VdbeComment() annotations to a VDBE ** program. It is not used in production code, only for debugging. */ static const char *onErrorText(int onError){ switch( onError ){ case OE_Abort: return "abort"; case OE_Rollback: return "rollback"; case OE_Fail: return "fail"; case OE_Replace: return "replace"; case OE_Ignore: return "ignore"; case OE_Default: return "default"; } return "n/a"; } #endif /* ** Parse context structure pFrom has just been used to create a sub-vdbe ** (trigger program). If an error has occurred, transfer error information ** from pFrom to pTo. */ static void transferParseError(Parse *pTo, Parse *pFrom){ assert( pFrom->zErrMsg==0 || pFrom->nErr ); assert( pTo->zErrMsg==0 || pTo->nErr ); if( pTo->nErr==0 ){ pTo->zErrMsg = pFrom->zErrMsg; pTo->nErr = pFrom->nErr; pTo->rc = pFrom->rc; }else{ sqlite3DbFree(pFrom->db, pFrom->zErrMsg); } } /* ** Create and populate a new TriggerPrg object with a sub-program ** implementing trigger pTrigger with ON CONFLICT policy orconf. */ static TriggerPrg *codeRowTrigger( Parse *pParse, /* Current parse context */ Trigger *pTrigger, /* Trigger to code */ Table *pTab, /* The table pTrigger is attached to */ int orconf /* ON CONFLICT policy to code trigger program with */ ){ Parse *pTop = sqlite3ParseToplevel(pParse); sqlite3 *db = pParse->db; /* Database handle */ TriggerPrg *pPrg; /* Value to return */ Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */ Vdbe *v; /* Temporary VM */ NameContext sNC; /* Name context for sub-vdbe */ SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ int iEndTrigger = 0; /* Label to jump to if WHEN is false */ Parse sSubParse; /* Parse context for sub-vdbe */ assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); assert( pTop->pVdbe ); /* Allocate the TriggerPrg and SubProgram objects. To ensure that they ** are freed if an error occurs, link them into the Parse.pTriggerPrg ** list of the top-level Parse object sooner rather than later. */ pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg)); if( !pPrg ) return 0; pPrg->pNext = pTop->pTriggerPrg; pTop->pTriggerPrg = pPrg; pPrg->pProgram = pProgram = sqlite3DbMallocZero(db, sizeof(SubProgram)); if( !pProgram ) return 0; sqlite3VdbeLinkSubProgram(pTop->pVdbe, pProgram); pPrg->pTrigger = pTrigger; pPrg->orconf = orconf; pPrg->aColmask[0] = 0xffffffff; pPrg->aColmask[1] = 0xffffffff; /* Allocate and populate a new Parse context to use for coding the ** trigger sub-program. */ sqlite3ParseObjectInit(&sSubParse, db); memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sSubParse; sSubParse.pTriggerTab = pTab; sSubParse.pToplevel = pTop; sSubParse.zAuthContext = pTrigger->zName; sSubParse.eTriggerOp = pTrigger->op; sSubParse.nQueryLoop = pParse->nQueryLoop; sSubParse.prepFlags = pParse->prepFlags; v = sqlite3GetVdbe(&sSubParse); if( v ){ VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)", pTrigger->zName, onErrorText(orconf), (pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"), (pTrigger->op==TK_UPDATE ? "UPDATE" : ""), (pTrigger->op==TK_INSERT ? "INSERT" : ""), (pTrigger->op==TK_DELETE ? "DELETE" : ""), pTab->zName )); #ifndef SQLITE_OMIT_TRACE if( pTrigger->zName ){ sqlite3VdbeChangeP4(v, -1, sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC ); } #endif /* If one was specified, code the WHEN clause. If it evaluates to false ** (or NULL) the sub-vdbe is immediately halted by jumping to the ** OP_Halt inserted at the end of the program. */ if( pTrigger->pWhen ){ pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0); if( db->mallocFailed==0 && SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) ){ iEndTrigger = sqlite3VdbeMakeLabel(&sSubParse); sqlite3ExprIfFalse(&sSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL); } sqlite3ExprDelete(db, pWhen); } /* Code the trigger program into the sub-vdbe. */ codeTriggerProgram(&sSubParse, pTrigger->step_list, orconf); /* Insert an OP_Halt at the end of the sub-program. */ if( iEndTrigger ){ sqlite3VdbeResolveLabel(v, iEndTrigger); } sqlite3VdbeAddOp0(v, OP_Halt); VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf))); transferParseError(pParse, &sSubParse); if( pParse->nErr==0 ){ assert( db->mallocFailed==0 ); pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); } pProgram->nMem = sSubParse.nMem; pProgram->nCsr = sSubParse.nTab; pProgram->token = (void *)pTrigger; pPrg->aColmask[0] = sSubParse.oldmask; pPrg->aColmask[1] = sSubParse.newmask; sqlite3VdbeDelete(v); }else{ transferParseError(pParse, &sSubParse); } assert( !sSubParse.pTriggerPrg && !sSubParse.nMaxArg ); sqlite3ParseObjectReset(&sSubParse); return pPrg; } /* ** Return a pointer to a TriggerPrg object containing the sub-program for ** trigger pTrigger with default ON CONFLICT algorithm orconf. If no such ** TriggerPrg object exists, a new object is allocated and populated before ** being returned. */ static TriggerPrg *getRowTrigger( Parse *pParse, /* Current parse context */ Trigger *pTrigger, /* Trigger to code */ Table *pTab, /* The table trigger pTrigger is attached to */ int orconf /* ON CONFLICT algorithm. */ ){ Parse *pRoot = sqlite3ParseToplevel(pParse); TriggerPrg *pPrg; assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); /* It may be that this trigger has already been coded (or is in the ** process of being coded). If this is the case, then an entry with ** a matching TriggerPrg.pTrigger field will be present somewhere ** in the Parse.pTriggerPrg list. Search for such an entry. */ for(pPrg=pRoot->pTriggerPrg; pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf); pPrg=pPrg->pNext ); /* If an existing TriggerPrg could not be located, create a new one. */ if( !pPrg ){ pPrg = codeRowTrigger(pParse, pTrigger, pTab, orconf); pParse->db->errByteOffset = -1; } return pPrg; } /* ** Generate code for the trigger program associated with trigger p on ** table pTab. The reg, orconf and ignoreJump parameters passed to this ** function are the same as those described in the header function for ** sqlite3CodeRowTrigger() */ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect( Parse *pParse, /* Parse context */ Trigger *p, /* Trigger to code */ Table *pTab, /* The table to code triggers from */ int reg, /* Reg array containing OLD.* and NEW.* values */ int orconf, /* ON CONFLICT policy */ int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ ){ Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */ TriggerPrg *pPrg; pPrg = getRowTrigger(pParse, p, pTab, orconf); assert( pPrg || pParse->nErr ); /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program ** is a pointer to the sub-vdbe containing the trigger program. */ if( pPrg ){ int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers)); sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem, (const char *)pPrg->pProgram, P4_SUBPROGRAM); VdbeComment( (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf))); /* Set the P5 operand of the OP_Program instruction to non-zero if ** recursive invocation of this trigger program is disallowed. Recursive ** invocation is disallowed if (a) the sub-program is really a trigger, ** not a foreign key action, and (b) the flag to enable recursive triggers ** is clear. */ sqlite3VdbeChangeP5(v, (u8)bRecursive); } } /* ** This is called to code the required FOR EACH ROW triggers for an operation ** on table pTab. The operation to code triggers for (INSERT, UPDATE or DELETE) ** is given by the op parameter. The tr_tm parameter determines whether the ** BEFORE or AFTER triggers are coded. If the operation is an UPDATE, then ** parameter pChanges is passed the list of columns being modified. ** ** If there are no triggers that fire at the specified time for the specified ** operation on pTab, this function is a no-op. ** ** The reg argument is the address of the first in an array of registers ** that contain the values substituted for the new.* and old.* references ** in the trigger program. If N is the number of columns in table pTab ** (a copy of pTab->nCol), then registers are populated as follows: ** ** Register Contains ** ------------------------------------------------------ ** reg+0 OLD.rowid ** reg+1 OLD.* value of left-most column of pTab ** ... ... ** reg+N OLD.* value of right-most column of pTab ** reg+N+1 NEW.rowid ** reg+N+2 NEW.* value of left-most column of pTab ** ... ... ** reg+N+N+1 NEW.* value of right-most column of pTab ** ** For ON DELETE triggers, the registers containing the NEW.* values will ** never be accessed by the trigger program, so they are not allocated or ** populated by the caller (there is no data to populate them with anyway). ** Similarly, for ON INSERT triggers the values stored in the OLD.* registers ** are never accessed, and so are not allocated by the caller. So, for an ** ON INSERT trigger, the value passed to this function as parameter reg ** is not a readable register, although registers (reg+N) through ** (reg+N+N+1) are. ** ** Parameter orconf is the default conflict resolution algorithm for the ** trigger program to use (REPLACE, IGNORE etc.). Parameter ignoreJump ** is the instruction that control should jump to if a trigger program ** raises an IGNORE exception. */ SQLITE_PRIVATE void sqlite3CodeRowTrigger( Parse *pParse, /* Parse context */ Trigger *pTrigger, /* List of triggers on table pTab */ int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ int tr_tm, /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ Table *pTab, /* The table to code triggers from */ int reg, /* The first in an array of registers (see above) */ int orconf, /* ON CONFLICT policy */ int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ ){ Trigger *p; /* Used to iterate through pTrigger list */ assert( op==TK_UPDATE || op==TK_INSERT || op==TK_DELETE ); assert( tr_tm==TRIGGER_BEFORE || tr_tm==TRIGGER_AFTER ); assert( (op==TK_UPDATE)==(pChanges!=0) ); for(p=pTrigger; p; p=p->pNext){ /* Sanity checking: The schema for the trigger and for the table are ** always defined. The trigger must be in the same schema as the table ** or else it must be a TEMP trigger. */ assert( p->pSchema!=0 ); assert( p->pTabSchema!=0 ); assert( p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema ); /* Determine whether we should code this trigger. One of two choices: ** 1. The trigger is an exact match to the current DML statement ** 2. This is a RETURNING trigger for INSERT but we are currently ** doing the UPDATE part of an UPSERT. */ if( (p->op==op || (p->bReturning && p->op==TK_INSERT && op==TK_UPDATE)) && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns, pChanges) ){ if( !p->bReturning ){ sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump); }else if( sqlite3IsToplevel(pParse) ){ codeReturningTrigger(pParse, p, pTab, reg); } } } } /* ** Triggers may access values stored in the old.* or new.* pseudo-table. ** This function returns a 32-bit bitmask indicating which columns of the ** old.* or new.* tables actually are used by triggers. This information ** may be used by the caller, for example, to avoid having to load the entire ** old.* record into memory when executing an UPDATE or DELETE command. ** ** Bit 0 of the returned mask is set if the left-most column of the ** table may be accessed using an [old|new].reference. Bit 1 is set if ** the second leftmost column value is required, and so on. If there ** are more than 32 columns in the table, and at least one of the columns ** with an index greater than 32 may be accessed, 0xffffffff is returned. ** ** It is not possible to determine if the old.rowid or new.rowid column is ** accessed by triggers. The caller must always assume that it is. ** ** Parameter isNew must be either 1 or 0. If it is 0, then the mask returned ** applies to the old.* table. If 1, the new.* table. ** ** Parameter tr_tm must be a mask with one or both of the TRIGGER_BEFORE ** and TRIGGER_AFTER bits set. Values accessed by BEFORE triggers are only ** included in the returned mask if the TRIGGER_BEFORE bit is set in the ** tr_tm parameter. Similarly, values accessed by AFTER triggers are only ** included in the returned mask if the TRIGGER_AFTER bit is set in tr_tm. */ SQLITE_PRIVATE u32 sqlite3TriggerColmask( Parse *pParse, /* Parse context */ Trigger *pTrigger, /* List of triggers on table pTab */ ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ int isNew, /* 1 for new.* ref mask, 0 for old.* ref mask */ int tr_tm, /* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ Table *pTab, /* The table to code triggers from */ int orconf /* Default ON CONFLICT policy for trigger steps */ ){ const int op = pChanges ? TK_UPDATE : TK_DELETE; u32 mask = 0; Trigger *p; assert( isNew==1 || isNew==0 ); if( IsView(pTab) ){ return 0xffffffff; } for(p=pTrigger; p; p=p->pNext){ if( p->op==op && (tr_tm&p->tr_tm) && checkColumnOverlap(p->pColumns,pChanges) ){ if( p->bReturning ){ mask = 0xffffffff; }else{ TriggerPrg *pPrg; pPrg = getRowTrigger(pParse, p, pTab, orconf); if( pPrg ){ mask |= pPrg->aColmask[isNew]; } } } } return mask; } #endif /* !defined(SQLITE_OMIT_TRIGGER) */ /************** End of trigger.c *********************************************/ /************** Begin file update.c ******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. */ /* #include "sqliteInt.h" */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Forward declaration */ static void updateVirtualTable( Parse *pParse, /* The parsing context */ SrcList *pSrc, /* The virtual table to be modified */ Table *pTab, /* The virtual table */ ExprList *pChanges, /* The columns to change in the UPDATE statement */ Expr *pRowidExpr, /* Expression used to recompute the rowid */ int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ Expr *pWhere, /* WHERE clause of the UPDATE statement */ int onError /* ON CONFLICT strategy */ ); #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** The most recently coded instruction was an OP_Column to retrieve the ** i-th column of table pTab. This routine sets the P4 parameter of the ** OP_Column to the default value, if any. ** ** The default value of a column is specified by a DEFAULT clause in the ** column definition. This was either supplied by the user when the table ** was created, or added later to the table definition by an ALTER TABLE ** command. If the latter, then the row-records in the table btree on disk ** may not contain a value for the column and the default value, taken ** from the P4 parameter of the OP_Column instruction, is returned instead. ** If the former, then all row-records are guaranteed to include a value ** for the column and the P4 value is not required. ** ** Column definitions created by an ALTER TABLE command may only have ** literal default values specified: a number, null or a string. (If a more ** complicated default expression value was provided, it is evaluated ** when the ALTER TABLE is executed and one of the literal values written ** into the sqlite_schema table.) ** ** Therefore, the P4 parameter is only required if the default value for ** the column is a literal number, string or null. The sqlite3ValueFromExpr() ** function is capable of transforming these types of expressions into ** sqlite3_value objects. ** ** If column as REAL affinity and the table is an ordinary b-tree table ** (not a virtual table) then the value might have been stored as an ** integer. In that case, add an OP_RealAffinity opcode to make sure ** it has been converted into REAL. */ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ Column *pCol; assert( pTab!=0 ); assert( pTab->nCol>i ); pCol = &pTab->aCol[i]; if( pCol->iDflt ){ sqlite3_value *pValue = 0; u8 enc = ENC(sqlite3VdbeDb(v)); assert( !IsView(pTab) ); VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName)); assert( inCol ); sqlite3ValueFromExpr(sqlite3VdbeDb(v), sqlite3ColumnExpr(pTab,pCol), enc, pCol->affinity, &pValue); if( pValue ){ sqlite3VdbeAppendP4(v, pValue, P4_MEM); } } #ifndef SQLITE_OMIT_FLOATING_POINT if( pCol->affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } #endif } /* ** Check to see if column iCol of index pIdx references any of the ** columns defined by aXRef and chngRowid. Return true if it does ** and false if not. This is an optimization. False-positives are a ** performance degradation, but false-negatives can result in a corrupt ** index and incorrect answers. ** ** aXRef[j] will be non-negative if column j of the original table is ** being updated. chngRowid will be true if the rowid of the table is ** being updated. */ static int indexColumnIsBeingUpdated( Index *pIdx, /* The index to check */ int iCol, /* Which column of the index to check */ int *aXRef, /* aXRef[j]>=0 if column j is being updated */ int chngRowid /* true if the rowid is being updated */ ){ i16 iIdxCol = pIdx->aiColumn[iCol]; assert( iIdxCol!=XN_ROWID ); /* Cannot index rowid */ if( iIdxCol>=0 ){ return aXRef[iIdxCol]>=0; } assert( iIdxCol==XN_EXPR ); assert( pIdx->aColExpr!=0 ); assert( pIdx->aColExpr->a[iCol].pExpr!=0 ); return sqlite3ExprReferencesUpdatedColumn(pIdx->aColExpr->a[iCol].pExpr, aXRef,chngRowid); } /* ** Check to see if index pIdx is a partial index whose conditional ** expression might change values due to an UPDATE. Return true if ** the index is subject to change and false if the index is guaranteed ** to be unchanged. This is an optimization. False-positives are a ** performance degradation, but false-negatives can result in a corrupt ** index and incorrect answers. ** ** aXRef[j] will be non-negative if column j of the original table is ** being updated. chngRowid will be true if the rowid of the table is ** being updated. */ static int indexWhereClauseMightChange( Index *pIdx, /* The index to check */ int *aXRef, /* aXRef[j]>=0 if column j is being updated */ int chngRowid /* true if the rowid is being updated */ ){ if( pIdx->pPartIdxWhere==0 ) return 0; return sqlite3ExprReferencesUpdatedColumn(pIdx->pPartIdxWhere, aXRef, chngRowid); } /* ** Allocate and return a pointer to an expression of type TK_ROW with ** Expr.iColumn set to value (iCol+1). The resolver will modify the ** expression to be a TK_COLUMN reading column iCol of the first ** table in the source-list (pSrc->a[0]). */ static Expr *exprRowColumn(Parse *pParse, int iCol){ Expr *pRet = sqlite3PExpr(pParse, TK_ROW, 0, 0); if( pRet ) pRet->iColumn = iCol+1; return pRet; } /* ** Assuming both the pLimit and pOrderBy parameters are NULL, this function ** generates VM code to run the query: ** ** SELECT , pChanges FROM pTabList WHERE pWhere ** ** and write the results to the ephemeral table already opened as cursor ** iEph. None of pChanges, pTabList or pWhere are modified or consumed by ** this function, they must be deleted by the caller. ** ** Or, if pLimit and pOrderBy are not NULL, and pTab is not a view: ** ** SELECT , pChanges FROM pTabList ** WHERE pWhere ** GROUP BY ** ORDER BY pOrderBy LIMIT pLimit ** ** If pTab is a view, the GROUP BY clause is omitted. ** ** Exactly how results are written to table iEph, and exactly what ** the in the query above are is determined by the type ** of table pTabList->a[0].pTab. ** ** If the table is a WITHOUT ROWID table, then argument pPk must be its ** PRIMARY KEY. In this case are the primary key columns ** of the table, in order. The results of the query are written to ephemeral ** table iEph as index keys, using OP_IdxInsert. ** ** If the table is actually a view, then are all columns of ** the view. The results are written to the ephemeral table iEph as records ** with automatically assigned integer keys. ** ** If the table is a virtual or ordinary intkey table, then ** is its rowid. For a virtual table, the results are written to iEph as ** records with automatically assigned integer keys For intkey tables, the ** rowid value in is used as the integer key, and the ** remaining fields make up the table record. */ static void updateFromSelect( Parse *pParse, /* Parse context */ int iEph, /* Cursor for open eph. table */ Index *pPk, /* PK if table 0 is WITHOUT ROWID */ ExprList *pChanges, /* List of expressions to return */ SrcList *pTabList, /* List of tables to select from */ Expr *pWhere, /* WHERE clause for query */ ExprList *pOrderBy, /* ORDER BY clause */ Expr *pLimit /* LIMIT clause */ ){ int i; SelectDest dest; Select *pSelect = 0; ExprList *pList = 0; ExprList *pGrp = 0; Expr *pLimit2 = 0; ExprList *pOrderBy2 = 0; sqlite3 *db = pParse->db; Table *pTab = pTabList->a[0].pTab; SrcList *pSrc; Expr *pWhere2; int eDest; #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( pOrderBy && pLimit==0 ) { sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on UPDATE"); return; } pOrderBy2 = sqlite3ExprListDup(db, pOrderBy, 0); pLimit2 = sqlite3ExprDup(db, pLimit, 0); #else UNUSED_PARAMETER(pOrderBy); UNUSED_PARAMETER(pLimit); #endif pSrc = sqlite3SrcListDup(db, pTabList, 0); pWhere2 = sqlite3ExprDup(db, pWhere, 0); assert( pTabList->nSrc>1 ); if( pSrc ){ assert( pSrc->a[0].fg.notCte ); pSrc->a[0].iCursor = -1; pSrc->a[0].pTab->nTabRef--; pSrc->a[0].pTab = 0; } if( pPk ){ for(i=0; inKeyCol; i++){ Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]); #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( pLimit ){ pGrp = sqlite3ExprListAppend(pParse, pGrp, sqlite3ExprDup(db, pNew, 0)); } #endif pList = sqlite3ExprListAppend(pParse, pList, pNew); } eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom; }else if( IsView(pTab) ){ for(i=0; inCol; i++){ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i)); } eDest = SRT_Table; }else{ eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom; pList = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0)); #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( pLimit ){ pGrp = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0)); } #endif } assert( pChanges!=0 || pParse->db->mallocFailed ); if( pChanges ){ for(i=0; inExpr; i++){ pList = sqlite3ExprListAppend(pParse, pList, sqlite3ExprDup(db, pChanges->a[i].pExpr, 0) ); } } pSelect = sqlite3SelectNew(pParse, pList, pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UFSrcCheck|SF_IncludeHidden|SF_UpdateFrom, pLimit2 ); if( pSelect ) pSelect->selFlags |= SF_OrderByReqd; sqlite3SelectDestInit(&dest, eDest, iEph); dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1); sqlite3Select(pParse, pSelect, &dest); sqlite3SelectDelete(db, pSelect); } /* ** Process an UPDATE statement. ** ** UPDATE OR IGNORE tbl SET a=b, c=d FROM tbl2... WHERE e<5 AND f NOT NULL; ** \_______/ \_/ \______/ \_____/ \________________/ ** onError | pChanges | pWhere ** \_______________________/ ** pTabList */ SQLITE_PRIVATE void sqlite3Update( Parse *pParse, /* The parser context */ SrcList *pTabList, /* The table in which we should change things */ ExprList *pChanges, /* Things to be changed */ Expr *pWhere, /* The WHERE clause. May be null */ int onError, /* How to handle constraint errors */ ExprList *pOrderBy, /* ORDER BY clause. May be null */ Expr *pLimit, /* LIMIT clause. May be null */ Upsert *pUpsert /* ON CONFLICT clause, or null */ ){ int i, j, k; /* Loop counters */ Table *pTab; /* The table to be updated */ int addrTop = 0; /* VDBE instruction address of the start of the loop */ WhereInfo *pWInfo = 0; /* Information about the WHERE clause */ Vdbe *v; /* The virtual database engine */ Index *pIdx; /* For looping over indices */ Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */ int nIdx; /* Number of indices that need updating */ int nAllIdx; /* Total number of indexes */ int iBaseCur; /* Base cursor number */ int iDataCur; /* Cursor for the canonical data btree */ int iIdxCur; /* Cursor for the first index */ sqlite3 *db; /* The database structure */ int *aRegIdx = 0; /* Registers for to each index and the main table */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ u8 *aToOpen; /* 1 for tables and indices to be opened */ u8 chngPk; /* PRIMARY KEY changed in a WITHOUT ROWID table */ u8 chngRowid; /* Rowid changed in a normal table */ u8 chngKey; /* Either chngPk or chngRowid */ Expr *pRowidExpr = 0; /* Expression defining the new record number */ int iRowidExpr = -1; /* Index of "rowid=" (or IPK) assignment in pChanges */ AuthContext sContext; /* The authorization context */ NameContext sNC; /* The name-context to resolve expressions in */ int iDb; /* Database containing the table being updated */ int eOnePass; /* ONEPASS_XXX value from where.c */ int hasFK; /* True if foreign key processing is required */ int labelBreak; /* Jump here to break out of UPDATE loop */ int labelContinue; /* Jump here to continue next step of UPDATE loop */ int flags; /* Flags for sqlite3WhereBegin() */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True when updating a view (INSTEAD OF trigger) */ Trigger *pTrigger; /* List of triggers on pTab, if required */ int tmask; /* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ #endif int newmask; /* Mask of NEW.* columns accessed by BEFORE triggers */ int iEph = 0; /* Ephemeral table holding all primary key values */ int nKey = 0; /* Number of elements in regKey for WITHOUT ROWID */ int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ int addrOpen = 0; /* Address of OP_OpenEphemeral */ int iPk = 0; /* First of nPk cells holding PRIMARY KEY value */ i16 nPk = 0; /* Number of components of the PRIMARY KEY */ int bReplace = 0; /* True if REPLACE conflict resolution might happen */ int bFinishSeek = 1; /* The OP_FinishSeek opcode is needed */ int nChangeFrom = 0; /* If there is a FROM, pChanges->nExpr, else 0 */ /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ int regOldRowid = 0; /* The old rowid */ int regNewRowid = 0; /* The new rowid */ int regNew = 0; /* Content of the NEW.* table in triggers */ int regOld = 0; /* Content of OLD.* table in triggers */ int regRowSet = 0; /* Rowset of rows to be updated */ int regKey = 0; /* composite PRIMARY KEY value */ memset(&sContext, 0, sizeof(sContext)); db = pParse->db; assert( db->pParse==pParse ); if( pParse->nErr ){ goto update_cleanup; } assert( db->mallocFailed==0 ); /* Locate the table which we want to update. */ pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ) goto update_cleanup; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); /* Figure out if we have any triggers and if the table being ** updated is a view. */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, &tmask); isView = IsView(pTab); assert( pTrigger || tmask==0 ); #else # define pTrigger 0 # define isView 0 # define tmask 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x10000 ){ sqlite3TreeViewLine(0, "In sqlite3Update() at %s:%d", __FILE__, __LINE__); sqlite3TreeViewUpdate(pParse->pWith, pTabList, pChanges, pWhere, onError, pOrderBy, pLimit, pUpsert, pTrigger); } #endif /* If there was a FROM clause, set nChangeFrom to the number of expressions ** in the change-list. Otherwise, set it to 0. There cannot be a FROM ** clause if this function is being called to generate code for part of ** an UPSERT statement. */ nChangeFrom = (pTabList->nSrc>1) ? pChanges->nExpr : 0; assert( nChangeFrom==0 || pUpsert==0 ); #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( !isView && nChangeFrom==0 ){ pWhere = sqlite3LimitWhere( pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE" ); pOrderBy = 0; pLimit = 0; } #endif if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto update_cleanup; } if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){ goto update_cleanup; } /* Allocate a cursors for the main database table and for all indices. ** The index cursors might not be used, but if they are used they ** need to occur right after the database cursor. So go ahead and ** allocate enough space, just in case. */ iBaseCur = iDataCur = pParse->nTab++; iIdxCur = iDataCur+1; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); testcase( pPk!=0 && pPk!=pTab->pIndex ); for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ if( pPk==pIdx ){ iDataCur = pParse->nTab; } pParse->nTab++; } if( pUpsert ){ /* On an UPSERT, reuse the same cursors already opened by INSERT */ iDataCur = pUpsert->iDataCur; iIdxCur = pUpsert->iIdxCur; pParse->nTab = iBaseCur; } pTabList->a[0].iCursor = iDataCur; /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. ** Initialize aXRef[] and aToOpen[] to their default values. */ aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx+1) + nIdx+2 ); if( aXRef==0 ) goto update_cleanup; aRegIdx = aXRef+pTab->nCol; aToOpen = (u8*)(aRegIdx+nIdx+1); memset(aToOpen, 1, nIdx+1); aToOpen[nIdx+1] = 0; for(i=0; inCol; i++) aXRef[i] = -1; /* Initialize the name-context */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; sNC.uNC.pUpsert = pUpsert; sNC.ncFlags = NC_UUpsert; /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto update_cleanup; /* Resolve the column names in all the expressions of the ** of the UPDATE statement. Also find the column index ** for each column to be updated in the pChanges array. For each ** column to be updated, make sure we have authorization to change ** that column. */ chngRowid = chngPk = 0; for(i=0; inExpr; i++){ u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName); /* If this is an UPDATE with a FROM clause, do not resolve expressions ** here. The call to sqlite3Select() below will do that. */ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ goto update_cleanup; } for(j=0; jnCol; j++){ if( pTab->aCol[j].hName==hCol && sqlite3StrICmp(pTab->aCol[j].zCnName, pChanges->a[i].zEName)==0 ){ if( j==pTab->iPKey ){ chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; iRowidExpr = i; }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ chngPk = 1; } #ifndef SQLITE_OMIT_GENERATED_COLUMNS else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ); testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); sqlite3ErrorMsg(pParse, "cannot UPDATE generated column \"%s\"", pTab->aCol[j].zCnName); goto update_cleanup; } #endif aXRef[j] = i; break; } } if( j>=pTab->nCol ){ if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){ j = -1; chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; iRowidExpr = i; }else{ sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zEName); pParse->checkSchema = 1; goto update_cleanup; } } #ifndef SQLITE_OMIT_AUTHORIZATION { int rc; rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, j<0 ? "ROWID" : pTab->aCol[j].zCnName, db->aDb[iDb].zDbSName); if( rc==SQLITE_DENY ){ goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } } #endif } assert( (chngRowid & chngPk)==0 ); assert( chngRowid==0 || chngRowid==1 ); assert( chngPk==0 || chngPk==1 ); chngKey = chngRowid + chngPk; #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Mark generated columns as changing if their generator expressions ** reference any changing column. The actual aXRef[] value for ** generated expressions is not used, other than to check to see that it ** is non-negative, so the value of aXRef[] for generated columns can be ** set to any non-negative number. We use 99999 so that the value is ** obvious when looking at aXRef[] in a symbolic debugger. */ if( pTab->tabFlags & TF_HasGenerated ){ int bProgress; testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); do{ bProgress = 0; for(i=0; inCol; i++){ if( aXRef[i]>=0 ) continue; if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ) continue; if( sqlite3ExprReferencesUpdatedColumn( sqlite3ColumnExpr(pTab, &pTab->aCol[i]), aXRef, chngRowid) ){ aXRef[i] = 99999; bProgress = 1; } } }while( bProgress ); } #endif /* The SET expressions are not actually used inside the WHERE loop. ** So reset the colUsed mask. Unless this is a virtual table. In that ** case, set all bits of the colUsed mask (to ensure that the virtual ** table implementation makes all columns available). */ pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0; hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey); /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold ** the key for accessing each index. */ if( onError==OE_Replace ) bReplace = 1; for(nAllIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nAllIdx++){ int reg; if( chngKey || hasFK>1 || pIdx==pPk || indexWhereClauseMightChange(pIdx,aXRef,chngRowid) ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; }else{ reg = 0; for(i=0; inKeyCol; i++){ if( indexColumnIsBeingUpdated(pIdx, i, aXRef, chngRowid) ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; if( onError==OE_Default && pIdx->onError==OE_Replace ){ bReplace = 1; } break; } } } if( reg==0 ) aToOpen[nAllIdx+1] = 0; aRegIdx[nAllIdx] = reg; } aRegIdx[nAllIdx] = ++pParse->nMem; /* Register storing the table record */ if( bReplace ){ /* If REPLACE conflict resolution might be invoked, open cursors on all ** indexes in case they are needed to delete records. */ memset(aToOpen, 1, nIdx+1); } if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, pTrigger || hasFK, iDb); /* Allocate required registers. */ if( !IsVirtual(pTab) ){ /* For now, regRowSet and aRegIdx[nAllIdx] share the same register. ** If regRowSet turns out to be needed, then aRegIdx[nAllIdx] will be ** reallocated. aRegIdx[nAllIdx] is the register in which the main ** table record is written. regRowSet holds the RowSet for the ** two-pass update algorithm. */ assert( aRegIdx[nAllIdx]==pParse->nMem ); regRowSet = aRegIdx[nAllIdx]; regOldRowid = regNewRowid = ++pParse->nMem; if( chngPk || pTrigger || hasFK ){ regOld = pParse->nMem + 1; pParse->nMem += pTab->nCol; } if( chngKey || pTrigger || hasFK ){ regNewRowid = ++pParse->nMem; } regNew = pParse->nMem + 1; pParse->nMem += pTab->nCol; } /* Start the view context. */ if( isView ){ sqlite3AuthContextPush(pParse, &sContext, pTab->zName); } /* If we are trying to update a view, realize that view into ** an ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( nChangeFrom==0 && isView ){ sqlite3MaterializeView(pParse, pTab, pWhere, pOrderBy, pLimit, iDataCur ); pOrderBy = 0; pLimit = 0; } #endif /* Resolve the column names in all the expressions in the ** WHERE clause. */ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pWhere) ){ goto update_cleanup; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* Virtual tables must be handled separately */ if( IsVirtual(pTab) ){ updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, pWhere, onError); goto update_cleanup; } #endif /* Jump to labelBreak to abandon further processing of this UPDATE */ labelContinue = labelBreak = sqlite3VdbeMakeLabel(pParse); /* Not an UPSERT. Normal processing. Begin by ** initialize the count of updated rows */ if( (db->flags&SQLITE_CountRows)!=0 && !pParse->pTriggerTab && !pParse->nested && !pParse->bReturning && pUpsert==0 ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } if( nChangeFrom==0 && HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); iEph = pParse->nTab++; addrOpen = sqlite3VdbeAddOp3(v, OP_OpenEphemeral, iEph, 0, regRowSet); }else{ assert( pPk!=0 || HasRowid(pTab) ); nPk = pPk ? pPk->nKeyCol : 0; iPk = pParse->nMem+1; pParse->nMem += nPk; pParse->nMem += nChangeFrom; regKey = ++pParse->nMem; if( pUpsert==0 ){ int nEphCol = nPk + nChangeFrom + (isView ? pTab->nCol : 0); iEph = pParse->nTab++; if( pPk ) sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1); addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nEphCol); if( pPk ){ KeyInfo *pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pPk); if( pKeyInfo ){ pKeyInfo->nAllField = nEphCol; sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); } } if( nChangeFrom ){ updateFromSelect( pParse, iEph, pPk, pChanges, pTabList, pWhere, pOrderBy, pLimit ); #ifndef SQLITE_OMIT_SUBQUERY if( isView ) iDataCur = iEph; #endif } } } if( nChangeFrom ){ sqlite3MultiWrite(pParse); eOnePass = ONEPASS_OFF; nKey = nPk; regKey = iPk; }else{ if( pUpsert ){ /* If this is an UPSERT, then all cursors have already been opened by ** the outer INSERT and the data cursor should be pointing at the row ** that is to be updated. So bypass the code that searches for the ** row(s) to be updated. */ pWInfo = 0; eOnePass = ONEPASS_SINGLE; sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL); bFinishSeek = 0; }else{ /* Begin the database scan. ** ** Do not consider a single-pass strategy for a multi-row update if ** there is anything that might disrupt the cursor being used to do ** the UPDATE: ** (1) This is a nested UPDATE ** (2) There are triggers ** (3) There are FOREIGN KEY constraints ** (4) There are REPLACE conflict handlers ** (5) There are subqueries in the WHERE clause */ flags = WHERE_ONEPASS_DESIRED; if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace && (pWhere==0 || !ExprHasProperty(pWhere, EP_Subquery)) ){ flags |= WHERE_ONEPASS_MULTIROW; } pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur); if( pWInfo==0 ) goto update_cleanup; /* A one-pass strategy that might update more than one row may not ** be used if any column of the index used for the scan is being ** updated. Otherwise, if there is an index on "b", statements like ** the following could create an infinite loop: ** ** UPDATE t1 SET b=b+1 WHERE b>? ** ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI ** strategy that uses an index for which one or more columns are being ** updated. */ eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo); if( eOnePass!=ONEPASS_SINGLE ){ sqlite3MultiWrite(pParse); if( eOnePass==ONEPASS_MULTI ){ int iCur = aiCurOnePass[1]; if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){ eOnePass = ONEPASS_OFF; } assert( iCur!=iDataCur || !HasRowid(pTab) ); } } } if( HasRowid(pTab) ){ /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF ** mode, write the rowid into the FIFO. In either of the one-pass modes, ** leave it in register regOldRowid. */ sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); if( eOnePass==ONEPASS_OFF ){ aRegIdx[nAllIdx] = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_Insert, iEph, regRowSet, regOldRowid); }else{ if( ALWAYS(addrOpen) ) sqlite3VdbeChangeToNoop(v, addrOpen); } }else{ /* Read the PK of the current row into an array of registers. In ** ONEPASS_OFF mode, serialize the array into a record and store it in ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table ** is not required) and leave the PK fields in the array of registers. */ for(i=0; iaiColumn[i]>=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i], iPk+i); } if( eOnePass ){ if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen); nKey = nPk; regKey = iPk; }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey, sqlite3IndexAffinityStr(db, pPk), nPk); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk); } } } if( pUpsert==0 ){ if( nChangeFrom==0 && eOnePass!=ONEPASS_MULTI ){ sqlite3WhereEnd(pWInfo); } if( !isView ){ int addrOnce = 0; int iNotUsed1 = 0; int iNotUsed2 = 0; /* Open every index that needs updating. */ if( eOnePass!=ONEPASS_OFF ){ if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0; if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0; } if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen, &iNotUsed1, &iNotUsed2); if( addrOnce ){ sqlite3VdbeJumpHereOrPopInst(v, addrOnce); } } /* Top of the update loop */ if( eOnePass!=ONEPASS_OFF ){ if( aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur #ifdef SQLITE_ALLOW_ROWID_IN_VIEW && !isView #endif ){ assert( pPk ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey); VdbeCoverage(v); } if( eOnePass!=ONEPASS_SINGLE ){ labelContinue = sqlite3VdbeMakeLabel(pParse); } sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); VdbeCoverageIf(v, pPk==0); VdbeCoverageIf(v, pPk!=0); }else if( pPk || nChangeFrom ){ labelContinue = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); addrTop = sqlite3VdbeCurrentAddr(v); if( nChangeFrom ){ if( !isView ){ if( pPk ){ for(i=0; i=0 ); if( nChangeFrom==0 ){ sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); }else{ sqlite3VdbeAddOp3(v, OP_Column, iEph, iRowidExpr, regNewRowid); } sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v); } /* Compute the old pre-UPDATE content of the row being changed, if that ** information is needed */ if( chngPk || hasFK || pTrigger ){ u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0); oldmask |= sqlite3TriggerColmask(pParse, pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError ); for(i=0; inCol; i++){ u32 colFlags = pTab->aCol[i].colFlags; k = sqlite3TableColumnToStorage(pTab, i) + regOld; if( oldmask==0xffffffff || (i<32 && (oldmask & MASKBIT32(i))!=0) || (colFlags & COLFLAG_PRIMKEY)!=0 ){ testcase( oldmask!=0xffffffff && i==31 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, k); } } if( chngRowid==0 && pPk==0 ){ sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); } } /* Populate the array of registers beginning at regNew with the new ** row data. This array is used to check constants, create the new ** table and index records, and as the values for any new.* references ** made by triggers. ** ** If there are one or more BEFORE triggers, then do not populate the ** registers associated with columns that are (a) not modified by ** this UPDATE statement and (b) not accessed by new.* references. The ** values for registers not modified by the UPDATE must be reloaded from ** the database after the BEFORE triggers are fired anyway (as the trigger ** may have modified them). So not loading those that are not going to ** be used eliminates some redundant opcodes. */ newmask = sqlite3TriggerColmask( pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError ); for(i=0, k=regNew; inCol; i++, k++){ if( i==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Null, 0, k); }else if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)!=0 ){ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--; }else{ j = aXRef[i]; if( j>=0 ){ if( nChangeFrom ){ int nOff = (isView ? pTab->nCol : nPk); assert( eOnePass==ONEPASS_OFF ); sqlite3VdbeAddOp3(v, OP_Column, iEph, nOff+j, k); }else{ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k); } }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){ /* This branch loads the value of a column that will not be changed ** into a register. This is done if there are no BEFORE triggers, or ** if there are one or more BEFORE triggers that use this value via ** a new.* reference in a trigger program. */ testcase( i==31 ); testcase( i==32 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); bFinishSeek = 0; }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, k); } } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pTab->tabFlags & TF_HasGenerated ){ testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); sqlite3ComputeGeneratedColumns(pParse, regNew, pTab); } #endif /* Fire any BEFORE UPDATE triggers. This happens before constraints are ** verified. One could argue that this is wrong. */ if( tmask&TRIGGER_BEFORE ){ sqlite3TableAffinity(v, pTab, regNew); sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue); if( !isView ){ /* The row-trigger may have deleted the row being updated. In this ** case, jump to the next row. No updates or AFTER triggers are ** required. This behavior - what happens when the row being updated ** is deleted or renamed by a BEFORE trigger - is left undefined in the ** documentation. */ if( pPk ){ sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey); VdbeCoverage(v); }else{ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid); VdbeCoverage(v); } /* After-BEFORE-trigger-reload-loop: ** If it did not delete it, the BEFORE trigger may still have modified ** some of the columns of the row being updated. Load the values for ** all columns not modified by the update statement into their registers ** in case this has happened. Only unmodified columns are reloaded. ** The values computed for modified columns use the values before the ** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26) ** for an example. */ for(i=0, k=regNew; inCol; i++, k++){ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--; }else if( aXRef[i]<0 && i!=pTab->iPKey ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pTab->tabFlags & TF_HasGenerated ){ testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); sqlite3ComputeGeneratedColumns(pParse, regNew, pTab); } #endif } } if( !isView ){ /* Do constraint checks. */ assert( regOldRowid>0 ); sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace, aXRef, 0); /* If REPLACE conflict handling may have been used, or if the PK of the ** row is changing, then the GenerateConstraintChecks() above may have ** moved cursor iDataCur. Reseek it. */ if( bReplace || chngKey ){ if( pPk ){ sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey); }else{ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid); } VdbeCoverage(v); } /* Do FK constraint checks. */ if( hasFK ){ sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey); } /* Delete the index entries associated with the current record. */ sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1); /* We must run the OP_FinishSeek opcode to resolve a prior ** OP_DeferredSeek if there is any possibility that there have been ** no OP_Column opcodes since the OP_DeferredSeek was issued. But ** we want to avoid the OP_FinishSeek if possible, as running it ** costs CPU cycles. */ if( bFinishSeek ){ sqlite3VdbeAddOp1(v, OP_FinishSeek, iDataCur); } /* If changing the rowid value, or if there are foreign key constraints ** to process, delete the old record. Otherwise, add a noop OP_Delete ** to invoke the pre-update hook. ** ** That (regNew==regnewRowid+1) is true is also important for the ** pre-update hook. If the caller invokes preupdate_new(), the returned ** value is copied from memory cell (regNewRowid+1+iCol), where iCol ** is the column index supplied by the user. */ assert( regNew==regNewRowid+1 ); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK sqlite3VdbeAddOp3(v, OP_Delete, iDataCur, OPFLAG_ISUPDATE | ((hasFK>1 || chngKey) ? 0 : OPFLAG_ISNOOP), regNewRowid ); if( eOnePass==ONEPASS_MULTI ){ assert( hasFK==0 && chngKey==0 ); sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); } if( !pParse->nested ){ sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } #else if( hasFK>1 || chngKey ){ sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0); } #endif if( hasFK ){ sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey); } /* Insert the new index entries and the new record. */ sqlite3CompleteInsertion( pParse, pTab, iDataCur, iIdxCur, regNewRowid, aRegIdx, OPFLAG_ISUPDATE | (eOnePass==ONEPASS_MULTI ? OPFLAG_SAVEPOSITION : 0), 0, 0 ); /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to ** handle rows (possibly in other tables) that refer via a foreign key ** to the row just updated. */ if( hasFK ){ sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngKey); } } /* Increment the row counter */ if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } if( pTrigger ){ sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue); } /* Repeat the above with the next record to be updated, until ** all record selected by the WHERE clause have been updated. */ if( eOnePass==ONEPASS_SINGLE ){ /* Nothing to do at end-of-loop for a single-pass */ }else if( eOnePass==ONEPASS_MULTI ){ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3WhereEnd(pWInfo); }else{ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v); } sqlite3VdbeResolveLabel(v, labelBreak); /* Update the sqlite_sequence table by storing the content of the ** maximum rowid counter values recorded while inserting into ** autoincrement tables. */ if( pParse->nested==0 && pParse->pTriggerTab==0 && pUpsert==0 ){ sqlite3AutoincrementEnd(pParse); } /* ** Return the number of rows that were changed, if we are tracking ** that information. */ if( regRowCount ){ sqlite3CodeChangeCount(v, regRowCount, "rows updated"); } update_cleanup: sqlite3AuthContextPop(&sContext); sqlite3DbFree(db, aXRef); /* Also frees aRegIdx[] and aToOpen[] */ sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pChanges); sqlite3ExprDelete(db, pWhere); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) sqlite3ExprListDelete(db, pOrderBy); sqlite3ExprDelete(db, pLimit); #endif return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView #endif #ifdef pTrigger #undef pTrigger #endif #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Generate code for an UPDATE of a virtual table. ** ** There are two possible strategies - the default and the special ** "onepass" strategy. Onepass is only used if the virtual table ** implementation indicates that pWhere may match at most one row. ** ** The default strategy is to create an ephemeral table that contains ** for each row to be changed: ** ** (A) The original rowid of that row. ** (B) The revised rowid for the row. ** (C) The content of every column in the row. ** ** Then loop through the contents of this ephemeral table executing a ** VUpdate for each row. When finished, drop the ephemeral table. ** ** The "onepass" strategy does not use an ephemeral table. Instead, it ** stores the same values (A, B and C above) in a register array and ** makes a single invocation of VUpdate. */ static void updateVirtualTable( Parse *pParse, /* The parsing context */ SrcList *pSrc, /* The virtual table to be modified */ Table *pTab, /* The virtual table */ ExprList *pChanges, /* The columns to change in the UPDATE statement */ Expr *pRowid, /* Expression used to recompute the rowid */ int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ Expr *pWhere, /* WHERE clause of the UPDATE statement */ int onError /* ON CONFLICT strategy */ ){ Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ int ephemTab; /* Table holding the result of the SELECT */ int i; /* Loop counter */ sqlite3 *db = pParse->db; /* Database connection */ const char *pVTab = (const char*)sqlite3GetVTable(db, pTab); WhereInfo *pWInfo = 0; int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */ int regArg; /* First register in VUpdate arg array */ int regRec; /* Register in which to assemble record */ int regRowid; /* Register for ephemeral table rowid */ int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */ int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */ int eOnePass; /* True to use onepass strategy */ int addr; /* Address of OP_OpenEphemeral */ /* Allocate nArg registers in which to gather the arguments for VUpdate. Then ** create and open the ephemeral table in which the records created from ** these arguments will be temporarily stored. */ assert( v ); ephemTab = pParse->nTab++; addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg); regArg = pParse->nMem + 1; pParse->nMem += nArg; if( pSrc->nSrc>1 ){ Index *pPk = 0; Expr *pRow; ExprList *pList; if( HasRowid(pTab) ){ if( pRowid ){ pRow = sqlite3ExprDup(db, pRowid, 0); }else{ pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0); } }else{ i16 iPk; /* PRIMARY KEY column */ pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); assert( pPk->nKeyCol==1 ); iPk = pPk->aiColumn[0]; if( aXRef[iPk]>=0 ){ pRow = sqlite3ExprDup(db, pChanges->a[aXRef[iPk]].pExpr, 0); }else{ pRow = exprRowColumn(pParse, iPk); } } pList = sqlite3ExprListAppend(pParse, 0, pRow); for(i=0; inCol; i++){ if( aXRef[i]>=0 ){ pList = sqlite3ExprListAppend(pParse, pList, sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0) ); }else{ Expr *pRowExpr = exprRowColumn(pParse, i); if( pRowExpr ) pRowExpr->op2 = OPFLAG_NOCHNG; pList = sqlite3ExprListAppend(pParse, pList, pRowExpr); } } updateFromSelect(pParse, ephemTab, pPk, pList, pSrc, pWhere, 0, 0); sqlite3ExprListDelete(db, pList); eOnePass = ONEPASS_OFF; }else{ regRec = ++pParse->nMem; regRowid = ++pParse->nMem; /* Start scanning the virtual table */ pWInfo = sqlite3WhereBegin( pParse, pSrc, pWhere, 0, 0, 0, WHERE_ONEPASS_DESIRED, 0 ); if( pWInfo==0 ) return; /* Populate the argument registers. */ for(i=0; inCol; i++){ assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ); if( aXRef[i]>=0 ){ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); }else{ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* For sqlite3_vtab_nochange() */ } } if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg); if( pRowid ){ sqlite3ExprCode(pParse, pRowid, regArg+1); }else{ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1); } }else{ Index *pPk; /* PRIMARY KEY index */ i16 iPk; /* PRIMARY KEY column */ pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); assert( pPk->nKeyCol==1 ); iPk = pPk->aiColumn[0]; sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg); sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1); } eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); /* There is no ONEPASS_MULTI on virtual tables */ assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); if( eOnePass ){ /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded ** above. */ sqlite3VdbeChangeToNoop(v, addr); sqlite3VdbeAddOp1(v, OP_Close, iCsr); }else{ /* Create a record from the argument register contents and insert it into ** the ephemeral table. */ sqlite3MultiWrite(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec); #if defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_NULL_TRIM) /* Signal an assert() within OP_MakeRecord that it is allowed to ** accept no-change records with serial_type 10 */ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC); #endif sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid); } } if( eOnePass==ONEPASS_OFF ){ /* End the virtual table scan */ if( pSrc->nSrc==1 ){ sqlite3WhereEnd(pWInfo); } /* Begin scanning through the ephemeral table. */ addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v); /* Extract arguments from the current row of the ephemeral table and ** invoke the VUpdate method. */ for(i=0; ipNextUpsert; sqlite3ExprListDelete(db, p->pUpsertTarget); sqlite3ExprDelete(db, p->pUpsertTargetWhere); sqlite3ExprListDelete(db, p->pUpsertSet); sqlite3ExprDelete(db, p->pUpsertWhere); sqlite3DbFree(db, p->pToFree); sqlite3DbFree(db, p); p = pNext; }while( p ); } SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){ if( p ) upsertDelete(db, p); } /* ** Duplicate an Upsert object. */ SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){ if( p==0 ) return 0; return sqlite3UpsertNew(db, sqlite3ExprListDup(db, p->pUpsertTarget, 0), sqlite3ExprDup(db, p->pUpsertTargetWhere, 0), sqlite3ExprListDup(db, p->pUpsertSet, 0), sqlite3ExprDup(db, p->pUpsertWhere, 0), sqlite3UpsertDup(db, p->pNextUpsert) ); } /* ** Create a new Upsert object. */ SQLITE_PRIVATE Upsert *sqlite3UpsertNew( sqlite3 *db, /* Determines which memory allocator to use */ ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */ Expr *pTargetWhere, /* Optional WHERE clause on the target */ ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */ Expr *pWhere, /* WHERE clause for the ON CONFLICT UPDATE */ Upsert *pNext /* Next ON CONFLICT clause in the list */ ){ Upsert *pNew; pNew = sqlite3DbMallocZero(db, sizeof(Upsert)); if( pNew==0 ){ sqlite3ExprListDelete(db, pTarget); sqlite3ExprDelete(db, pTargetWhere); sqlite3ExprListDelete(db, pSet); sqlite3ExprDelete(db, pWhere); sqlite3UpsertDelete(db, pNext); return 0; }else{ pNew->pUpsertTarget = pTarget; pNew->pUpsertTargetWhere = pTargetWhere; pNew->pUpsertSet = pSet; pNew->pUpsertWhere = pWhere; pNew->isDoUpdate = pSet!=0; pNew->pNextUpsert = pNext; } return pNew; } /* ** Analyze the ON CONFLICT clause described by pUpsert. Resolve all ** symbols in the conflict-target. ** ** Return SQLITE_OK if everything works, or an error code is something ** is wrong. */ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( Parse *pParse, /* The parsing context */ SrcList *pTabList, /* Table into which we are inserting */ Upsert *pUpsert /* The ON CONFLICT clauses */ ){ Table *pTab; /* That table into which we are inserting */ int rc; /* Result code */ int iCursor; /* Cursor used by pTab */ Index *pIdx; /* One of the indexes of pTab */ ExprList *pTarget; /* The conflict-target clause */ Expr *pTerm; /* One term of the conflict-target clause */ NameContext sNC; /* Context for resolving symbolic names */ Expr sCol[2]; /* Index column converted into an Expr */ int nClause = 0; /* Counter of ON CONFLICT clauses */ assert( pTabList->nSrc==1 ); assert( pTabList->a[0].pTab!=0 ); assert( pUpsert!=0 ); assert( pUpsert->pUpsertTarget!=0 ); /* Resolve all symbolic names in the conflict-target clause, which ** includes both the list of columns and the optional partial-index ** WHERE clause. */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; for(; pUpsert && pUpsert->pUpsertTarget; pUpsert=pUpsert->pNextUpsert, nClause++){ rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget); if( rc ) return rc; rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); if( rc ) return rc; /* Check to see if the conflict target matches the rowid. */ pTab = pTabList->a[0].pTab; pTarget = pUpsert->pUpsertTarget; iCursor = pTabList->a[0].iCursor; if( HasRowid(pTab) && pTarget->nExpr==1 && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN && pTerm->iColumn==XN_ROWID ){ /* The conflict-target is the rowid of the primary table */ assert( pUpsert->pUpsertIdx==0 ); continue; } /* Initialize sCol[0..1] to be an expression parse tree for a ** single column of an index. The sCol[0] node will be the TK_COLLATE ** operator and sCol[1] will be the TK_COLUMN operator. Code below ** will populate the specific collation and column number values ** prior to comparing against the conflict-target expression. */ memset(sCol, 0, sizeof(sCol)); sCol[0].op = TK_COLLATE; sCol[0].pLeft = &sCol[1]; sCol[1].op = TK_COLUMN; sCol[1].iTable = pTabList->a[0].iCursor; /* Check for matches against other indexes */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int ii, jj, nn; if( !IsUniqueIndex(pIdx) ) continue; if( pTarget->nExpr!=pIdx->nKeyCol ) continue; if( pIdx->pPartIdxWhere ){ if( pUpsert->pUpsertTargetWhere==0 ) continue; if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere, pIdx->pPartIdxWhere, iCursor)!=0 ){ continue; } } nn = pIdx->nKeyCol; for(ii=0; iiazColl[ii]; if( pIdx->aiColumn[ii]==XN_EXPR ){ assert( pIdx->aColExpr!=0 ); assert( pIdx->aColExpr->nExpr>ii ); assert( pIdx->bHasExpr ); pExpr = pIdx->aColExpr->a[ii].pExpr; if( pExpr->op!=TK_COLLATE ){ sCol[0].pLeft = pExpr; pExpr = &sCol[0]; } }else{ sCol[0].pLeft = &sCol[1]; sCol[1].iColumn = pIdx->aiColumn[ii]; pExpr = &sCol[0]; } for(jj=0; jja[jj].pExpr,pExpr,iCursor)<2 ){ break; /* Column ii of the index matches column jj of target */ } } if( jj>=nn ){ /* The target contains no match for column jj of the index */ break; } } if( iipUpsertIdx = pIdx; break; } if( pUpsert->pUpsertIdx==0 ){ char zWhich[16]; if( nClause==0 && pUpsert->pNextUpsert==0 ){ zWhich[0] = 0; }else{ sqlite3_snprintf(sizeof(zWhich),zWhich,"%r ", nClause+1); } sqlite3ErrorMsg(pParse, "%sON CONFLICT clause does not match any " "PRIMARY KEY or UNIQUE constraint", zWhich); return SQLITE_ERROR; } } return SQLITE_OK; } /* ** Return true if pUpsert is the last ON CONFLICT clause with a ** conflict target, or if pUpsert is followed by another ON CONFLICT ** clause that targets the INTEGER PRIMARY KEY. */ SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert *pUpsert){ Upsert *pNext; if( NEVER(pUpsert==0) ) return 0; pNext = pUpsert->pNextUpsert; if( pNext==0 ) return 1; if( pNext->pUpsertTarget==0 ) return 1; if( pNext->pUpsertIdx==0 ) return 1; return 0; } /* ** Given the list of ON CONFLICT clauses described by pUpsert, and ** a particular index pIdx, return a pointer to the particular ON CONFLICT ** clause that applies to the index. Or, if the index is not subject to ** any ON CONFLICT clause, return NULL. */ SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert *pUpsert, Index *pIdx){ while( pUpsert && pUpsert->pUpsertTarget!=0 && pUpsert->pUpsertIdx!=pIdx ){ pUpsert = pUpsert->pNextUpsert; } return pUpsert; } /* ** Generate bytecode that does an UPDATE as part of an upsert. ** ** If pIdx is NULL, then the UNIQUE constraint that failed was the IPK. ** In this case parameter iCur is a cursor open on the table b-tree that ** currently points to the conflicting table row. Otherwise, if pIdx ** is not NULL, then pIdx is the constraint that failed and iCur is a ** cursor points to the conflicting row. */ SQLITE_PRIVATE void sqlite3UpsertDoUpdate( Parse *pParse, /* The parsing and code-generating context */ Upsert *pUpsert, /* The ON CONFLICT clause for the upsert */ Table *pTab, /* The table being updated */ Index *pIdx, /* The UNIQUE constraint that failed */ int iCur /* Cursor for pIdx (or pTab if pIdx==NULL) */ ){ Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; SrcList *pSrc; /* FROM clause for the UPDATE */ int iDataCur; int i; Upsert *pTop = pUpsert; assert( v!=0 ); assert( pUpsert!=0 ); iDataCur = pUpsert->iDataCur; pUpsert = sqlite3UpsertOfIndex(pTop, pIdx); VdbeNoopComment((v, "Begin DO UPDATE of UPSERT")); if( pIdx && iCur!=iDataCur ){ if( HasRowid(pTab) ){ int regRowid = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid); sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, regRowid); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); int nPk = pPk->nKeyCol; int iPk = pParse->nMem+1; pParse->nMem += nPk; for(i=0; iaiColumn[i]>=0 ); k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i); VdbeComment((v, "%s.%s", pIdx->zName, pTab->aCol[pPk->aiColumn[i]].zCnName)); } sqlite3VdbeVerifyAbortable(v, OE_Abort); i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk); VdbeCoverage(v); sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0, "corrupt database", P4_STATIC); sqlite3MayAbort(pParse); sqlite3VdbeJumpHere(v, i); } } /* pUpsert does not own pTop->pUpsertSrc - the outer INSERT statement does. ** So we have to make a copy before passing it down into sqlite3Update() */ pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0); /* excluded.* columns of type REAL need to be converted to a hard real */ for(i=0; inCol; i++){ if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i); } } sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0), sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert); VdbeNoopComment((v, "End DO UPDATE of UPSERT")); } #endif /* SQLITE_OMIT_UPSERT */ /************** End of upsert.c **********************************************/ /************** Begin file vacuum.c ******************************************/ /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the VACUUM command. ** ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) /* ** Execute zSql on database db. ** ** If zSql returns rows, then each row will have exactly one ** column. (This will only happen if zSql begins with "SELECT".) ** Take each row of result and call execSql() again recursively. ** ** The execSqlF() routine does the same thing, except it accepts ** a format string as its third argument */ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ sqlite3_stmt *pStmt; int rc; /* printf("SQL: [%s]\n", zSql); fflush(stdout); */ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0); assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 ); /* The secondary SQL must be one of CREATE TABLE, CREATE INDEX, ** or INSERT. Historically there have been attacks that first ** corrupt the sqlite_schema.sql field with other kinds of statements ** then run VACUUM to get those statements to execute at inappropriate ** times. */ if( zSubSql && (strncmp(zSubSql,"CRE",3)==0 || strncmp(zSubSql,"INS",3)==0) ){ rc = execSql(db, pzErrMsg, zSubSql); if( rc!=SQLITE_OK ) break; } } assert( rc!=SQLITE_ROW ); if( rc==SQLITE_DONE ) rc = SQLITE_OK; if( rc ){ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); } (void)sqlite3_finalize(pStmt); return rc; } static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){ char *z; va_list ap; int rc; va_start(ap, zSql); z = sqlite3VMPrintf(db, zSql, ap); va_end(ap); if( z==0 ) return SQLITE_NOMEM; rc = execSql(db, pzErrMsg, z); sqlite3DbFree(db, z); return rc; } /* ** The VACUUM command is used to clean up the database, ** collapse free space, etc. It is modelled after the VACUUM command ** in PostgreSQL. The VACUUM command works as follows: ** ** (1) Create a new transient database file ** (2) Copy all content from the database being vacuumed into ** the new transient database file ** (3) Copy content from the transient database back into the ** original database. ** ** The transient database requires temporary disk space approximately ** equal to the size of the original database. The copy operation of ** step (3) requires additional temporary disk space approximately equal ** to the size of the original database for the rollback journal. ** Hence, temporary disk space that is approximately 2x the size of the ** original database is required. Every page of the database is written ** approximately 3 times: Once for step (2) and twice for step (3). ** Two writes per page are required in step (3) because the original ** database content must be written into the rollback journal prior to ** overwriting the database with the vacuumed content. ** ** Only 1x temporary space and only 1x writes would be required if ** the copy of step (3) were replaced by deleting the original database ** and renaming the transient database as the original. But that will ** not work if other processes are attached to the original database. ** And a power loss in between deleting the original and renaming the ** transient would cause the database file to appear to be deleted ** following reboot. */ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){ Vdbe *v = sqlite3GetVdbe(pParse); int iDb = 0; if( v==0 ) goto build_vacuum_end; if( pParse->nErr ) goto build_vacuum_end; if( pNm ){ #ifndef SQLITE_BUG_COMPATIBLE_20160819 /* Default behavior: Report an error if the argument to VACUUM is ** not recognized */ iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm); if( iDb<0 ) goto build_vacuum_end; #else /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments ** to VACUUM are silently ignored. This is a back-out of a bug fix that ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270). ** The buggy behavior is required for binary compatibility with some ** legacy applications. */ iDb = sqlite3FindDb(pParse->db, pNm); if( iDb<0 ) iDb = 0; #endif } if( iDb!=1 ){ int iIntoReg = 0; if( pInto && sqlite3ResolveSelfReference(pParse,0,0,pInto,0)==0 ){ iIntoReg = ++pParse->nMem; sqlite3ExprCode(pParse, pInto, iIntoReg); } sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg); sqlite3VdbeUsesBtree(v, iDb); } build_vacuum_end: sqlite3ExprDelete(pParse->db, pInto); return; } /* ** This routine implements the OP_Vacuum opcode of the VDBE. */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( char **pzErrMsg, /* Write error message here */ sqlite3 *db, /* Database connection */ int iDb, /* Which attached DB to vacuum */ sqlite3_value *pOut /* Write results here, if not NULL. VACUUM INTO */ ){ int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ u32 saved_mDbFlags; /* Saved value of db->mDbFlags */ u64 saved_flags; /* Saved value of db->flags */ i64 saved_nChange; /* Saved value of db->nChange */ i64 saved_nTotalChange; /* Saved value of db->nTotalChange */ u32 saved_openFlags; /* Saved value of db->openFlags */ u8 saved_mTrace; /* Saved trace settings */ Db *pDb = 0; /* Database to detach at end of vacuum */ int isMemDb; /* True if vacuuming a :memory: database */ int nRes; /* Bytes of reserved space at the end of each page */ int nDb; /* Number of attached databases */ const char *zDbMain; /* Schema name of database to vacuum */ const char *zOut; /* Name of output file */ u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */ if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); return SQLITE_ERROR; /* IMP: R-12218-18073 */ } if( db->nVdbeActive>1 ){ sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); return SQLITE_ERROR; /* IMP: R-15610-35227 */ } saved_openFlags = db->openFlags; if( pOut ){ if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){ sqlite3SetString(pzErrMsg, db, "non-text filename"); return SQLITE_ERROR; } zOut = (const char*)sqlite3_value_text(pOut); db->openFlags &= ~SQLITE_OPEN_READONLY; db->openFlags |= SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE; }else{ zOut = ""; } /* Save the current value of the database flags so that it can be ** restored before returning. Then set the writable-schema flag, and ** disable CHECK and foreign key constraints. */ saved_flags = db->flags; saved_mDbFlags = db->mDbFlags; saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; saved_mTrace = db->mTrace; db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_Defensive | SQLITE_CountRows); db->mTrace = 0; zDbMain = db->aDb[iDb].zDbSName; pMain = db->aDb[iDb].pBt; isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); /* Attach the temporary database as 'vacuum_db'. The synchronous pragma ** can be set to 'off' for this file, as it is not recovered if a crash ** occurs anyway. The integrity of the database is maintained by a ** (possibly synchronous) transaction opened on the main database before ** sqlite3BtreeCopyFile() is called. ** ** An optimization would be to use a non-journaled pager. ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but ** that actually made the VACUUM run slower. Very little journalling ** actually occurs when doing a vacuum since the vacuum_db is initially ** empty. Only the journal header is written. Apparently it takes more ** time to parse and run the PRAGMA to turn journalling off than it does ** to write the journal header file. */ nDb = db->nDb; rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut); db->openFlags = saved_openFlags; if( rc!=SQLITE_OK ) goto end_of_vacuum; assert( (db->nDb-1)==nDb ); pDb = &db->aDb[nDb]; assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); pTemp = pDb->pBt; if( pOut ){ sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); i64 sz = 0; if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){ rc = SQLITE_ERROR; sqlite3SetString(pzErrMsg, db, "output file already exists"); goto end_of_vacuum; } db->mDbFlags |= DBFLAG_VacuumInto; /* For a VACUUM INTO, the pager-flags are set to the same values as ** they are for the database being vacuumed, except that PAGER_CACHESPILL ** is always set. */ pgflags = db->aDb[iDb].safety_level | (db->flags & PAGER_FLAGS_MASK); } nRes = sqlite3BtreeGetRequestedReserve(pMain); sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL); /* Begin a transaction and take an exclusive lock on the main database ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, ** to ensure that we do not try to change the page-size on a WAL database. */ rc = execSql(db, pzErrMsg, "BEGIN"); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = sqlite3BtreeBeginTrans(pMain, pOut==0 ? 2 : 0, 0); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Do not attempt to change the page size for a WAL database */ if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain)) ==PAGER_JOURNALMODE_WAL && pOut==0 ){ db->nextPagesize = 0; } if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0) || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0)) || NEVER(db->mallocFailed) ){ rc = SQLITE_NOMEM_BKPT; goto end_of_vacuum; } #ifndef SQLITE_OMIT_AUTOVACUUM sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac : sqlite3BtreeGetAutoVacuum(pMain)); #endif /* Query the schema of the main database. Create a mirror schema ** in the temporary database. */ db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */ rc = execSqlF(db, pzErrMsg, "SELECT sql FROM \"%w\".sqlite_schema" " WHERE type='table'AND name<>'sqlite_sequence'" " AND coalesce(rootpage,1)>0", zDbMain ); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = execSqlF(db, pzErrMsg, "SELECT sql FROM \"%w\".sqlite_schema" " WHERE type='index'", zDbMain ); if( rc!=SQLITE_OK ) goto end_of_vacuum; db->init.iDb = 0; /* Loop through the tables in the main database. For each, do ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy ** the contents to the temporary database. */ rc = execSqlF(db, pzErrMsg, "SELECT'INSERT INTO vacuum_db.'||quote(name)" "||' SELECT*FROM\"%w\".'||quote(name)" "FROM vacuum_db.sqlite_schema " "WHERE type='table'AND coalesce(rootpage,1)>0", zDbMain ); assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 ); db->mDbFlags &= ~DBFLAG_Vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Copy the triggers, views, and virtual tables from the main database ** over to the temporary database. None of these objects has any ** associated storage, so all we have to do is copy their entries ** from the schema table. */ rc = execSqlF(db, pzErrMsg, "INSERT INTO vacuum_db.sqlite_schema" " SELECT*FROM \"%w\".sqlite_schema" " WHERE type IN('view','trigger')" " OR(type='table'AND rootpage=0)", zDbMain ); if( rc ) goto end_of_vacuum; /* At this point, there is a write transaction open on both the ** vacuum database and the main database. Assuming no error occurs, ** both transactions are closed by this block - the main database ** transaction by sqlite3BtreeCopyFile() and the other by an explicit ** call to sqlite3BtreeCommit(). */ { u32 meta; int i; /* This array determines which meta meta values are preserved in the ** vacuum. Even entries are the meta value number and odd entries ** are an increment to apply to the meta value after the vacuum. ** The increment is used to increase the schema cookie so that other ** connections to the same database will know to reread the schema. */ static const unsigned char aCopy[] = { BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */ BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */ BTREE_USER_VERSION, 0, /* Preserve the user version */ BTREE_APPLICATION_ID, 0, /* Preserve the application id */ }; assert( SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pTemp) ); assert( pOut!=0 || SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pMain) ); /* Copy Btree meta values */ for(i=0; iflags */ db->init.iDb = 0; db->mDbFlags = saved_mDbFlags; db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; db->mTrace = saved_mTrace; sqlite3BtreeSetPageSize(pMain, -1, 0, 1); /* Currently there is an SQL level transaction open on the vacuum ** database. No locks are held on any other files (since the main file ** was committed at the btree level). So it safe to end the transaction ** by manually setting the autoCommit flag to true and detaching the ** vacuum database. The vacuum_db journal file is deleted when the pager ** is closed by the DETACH. */ db->autoCommit = 1; if( pDb ){ sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; } /* This both clears the schemas and reduces the size of the db->aDb[] ** array. */ sqlite3ResetAllSchemasOfConnection(db); return rc; } #endif /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */ /************** End of vacuum.c **********************************************/ /************** Begin file vtab.c ********************************************/ /* ** 2006 June 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to help implement virtual tables. */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* #include "sqliteInt.h" */ /* ** Before a virtual table xCreate() or xConnect() method is invoked, the ** sqlite3.pVtabCtx member variable is set to point to an instance of ** this struct allocated on the stack. It is used by the implementation of ** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which ** are invoked only from within xCreate and xConnect methods. */ struct VtabCtx { VTable *pVTable; /* The virtual table being constructed */ Table *pTab; /* The Table object to which the virtual table belongs */ VtabCtx *pPrior; /* Parent context (if any) */ int bDeclared; /* True after sqlite3_declare_vtab() is called */ }; /* ** Construct and install a Module object for a virtual table. When this ** routine is called, it is guaranteed that all appropriate locks are held ** and the module is not already part of the connection. ** ** If there already exists a module with zName, replace it with the new one. ** If pModule==0, then delete the module zName if it exists. */ SQLITE_PRIVATE Module *sqlite3VtabCreateModule( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ void *pAux, /* Context pointer for xCreate/xConnect */ void (*xDestroy)(void *) /* Module destructor function */ ){ Module *pMod; Module *pDel; char *zCopy; if( pModule==0 ){ zCopy = (char*)zName; pMod = 0; }else{ int nName = sqlite3Strlen30(zName); pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1); if( pMod==0 ){ sqlite3OomFault(db); return 0; } zCopy = (char *)(&pMod[1]); memcpy(zCopy, zName, nName+1); pMod->zName = zCopy; pMod->pModule = pModule; pMod->pAux = pAux; pMod->xDestroy = xDestroy; pMod->pEpoTab = 0; pMod->nRefModule = 1; } pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); if( pDel ){ if( pDel==pMod ){ sqlite3OomFault(db); sqlite3DbFree(db, pDel); pMod = 0; }else{ sqlite3VtabEponymousTableClear(db, pDel); sqlite3VtabModuleUnref(db, pDel); } } return pMod; } /* ** The actual function that does the work of creating a new module. ** This function implements the sqlite3_create_module() and ** sqlite3_create_module_v2() interfaces. */ static int createModule( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ void *pAux, /* Context pointer for xCreate/xConnect */ void (*xDestroy)(void *) /* Module destructor function */ ){ int rc = SQLITE_OK; sqlite3_mutex_enter(db->mutex); (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy); rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux); sqlite3_mutex_leave(db->mutex); return rc; } /* ** External API function used to create a new virtual-table module. */ SQLITE_API int sqlite3_create_module( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ void *pAux /* Context pointer for xCreate/xConnect */ ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; #endif return createModule(db, zName, pModule, pAux, 0); } /* ** External API function used to create a new virtual-table module. */ SQLITE_API int sqlite3_create_module_v2( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ void *pAux, /* Context pointer for xCreate/xConnect */ void (*xDestroy)(void *) /* Module destructor function */ ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; #endif return createModule(db, zName, pModule, pAux, xDestroy); } /* ** External API to drop all virtual-table modules, except those named ** on the azNames list. */ SQLITE_API int sqlite3_drop_modules(sqlite3 *db, const char** azNames){ HashElem *pThis, *pNext; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif for(pThis=sqliteHashFirst(&db->aModule); pThis; pThis=pNext){ Module *pMod = (Module*)sqliteHashData(pThis); pNext = sqliteHashNext(pThis); if( azNames ){ int ii; for(ii=0; azNames[ii]!=0 && strcmp(azNames[ii],pMod->zName)!=0; ii++){} if( azNames[ii]!=0 ) continue; } createModule(db, pMod->zName, 0, 0, 0); } return SQLITE_OK; } /* ** Decrement the reference count on a Module object. Destroy the ** module when the reference count reaches zero. */ SQLITE_PRIVATE void sqlite3VtabModuleUnref(sqlite3 *db, Module *pMod){ assert( pMod->nRefModule>0 ); pMod->nRefModule--; if( pMod->nRefModule==0 ){ if( pMod->xDestroy ){ pMod->xDestroy(pMod->pAux); } assert( pMod->pEpoTab==0 ); sqlite3DbFree(db, pMod); } } /* ** Lock the virtual table so that it cannot be disconnected. ** Locks nest. Every lock should have a corresponding unlock. ** If an unlock is omitted, resources leaks will occur. ** ** If a disconnect is attempted while a virtual table is locked, ** the disconnect is deferred until all locks have been removed. */ SQLITE_PRIVATE void sqlite3VtabLock(VTable *pVTab){ pVTab->nRef++; } /* ** pTab is a pointer to a Table structure representing a virtual-table. ** Return a pointer to the VTable object used by connection db to access ** this virtual-table, if one has been created, or NULL otherwise. */ SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){ VTable *pVtab; assert( IsVirtual(pTab) ); for(pVtab=pTab->u.vtab.p; pVtab && pVtab->db!=db; pVtab=pVtab->pNext); return pVtab; } /* ** Decrement the ref-count on a virtual table object. When the ref-count ** reaches zero, call the xDisconnect() method to delete the object. */ SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){ sqlite3 *db = pVTab->db; assert( db ); assert( pVTab->nRef>0 ); assert( db->eOpenState==SQLITE_STATE_OPEN || db->eOpenState==SQLITE_STATE_ZOMBIE ); pVTab->nRef--; if( pVTab->nRef==0 ){ sqlite3_vtab *p = pVTab->pVtab; if( p ){ p->pModule->xDisconnect(p); } sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod); sqlite3DbFree(db, pVTab); } } /* ** Table p is a virtual table. This function moves all elements in the ** p->u.vtab.p list to the sqlite3.pDisconnect lists of their associated ** database connections to be disconnected at the next opportunity. ** Except, if argument db is not NULL, then the entry associated with ** connection db is left in the p->u.vtab.p list. */ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){ VTable *pRet = 0; VTable *pVTable; assert( IsVirtual(p) ); pVTable = p->u.vtab.p; p->u.vtab.p = 0; /* Assert that the mutex (if any) associated with the BtShared database ** that contains table p is held by the caller. See header comments ** above function sqlite3VtabUnlockList() for an explanation of why ** this makes it safe to access the sqlite3.pDisconnect list of any ** database connection that may have an entry in the p->u.vtab.p list. */ assert( db==0 || sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); while( pVTable ){ sqlite3 *db2 = pVTable->db; VTable *pNext = pVTable->pNext; assert( db2 ); if( db2==db ){ pRet = pVTable; p->u.vtab.p = pRet; pRet->pNext = 0; }else{ pVTable->pNext = db2->pDisconnect; db2->pDisconnect = pVTable; } pVTable = pNext; } assert( !db || pRet ); return pRet; } /* ** Table *p is a virtual table. This function removes the VTable object ** for table *p associated with database connection db from the linked ** list in p->pVTab. It also decrements the VTable ref count. This is ** used when closing database connection db to free all of its VTable ** objects without disturbing the rest of the Schema object (which may ** be being used by other shared-cache connections). */ SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ VTable **ppVTab; assert( IsVirtual(p) ); assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); for(ppVTab=&p->u.vtab.p; *ppVTab; ppVTab=&(*ppVTab)->pNext){ if( (*ppVTab)->db==db ){ VTable *pVTab = *ppVTab; *ppVTab = pVTab->pNext; sqlite3VtabUnlock(pVTab); break; } } } /* ** Disconnect all the virtual table objects in the sqlite3.pDisconnect list. ** ** This function may only be called when the mutexes associated with all ** shared b-tree databases opened using connection db are held by the ** caller. This is done to protect the sqlite3.pDisconnect list. The ** sqlite3.pDisconnect list is accessed only as follows: ** ** 1) By this function. In this case, all BtShared mutexes and the mutex ** associated with the database handle itself must be held. ** ** 2) By function vtabDisconnectAll(), when it adds a VTable entry to ** the sqlite3.pDisconnect list. In this case either the BtShared mutex ** associated with the database the virtual table is stored in is held ** or, if the virtual table is stored in a non-sharable database, then ** the database handle mutex is held. ** ** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously ** by multiple threads. It is thread-safe. */ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){ VTable *p = db->pDisconnect; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); if( p ){ db->pDisconnect = 0; do { VTable *pNext = p->pNext; sqlite3VtabUnlock(p); p = pNext; }while( p ); } } /* ** Clear any and all virtual-table information from the Table record. ** This routine is called, for example, just before deleting the Table ** record. ** ** Since it is a virtual-table, the Table structure contains a pointer ** to the head of a linked list of VTable structures. Each VTable ** structure is associated with a single sqlite3* user of the schema. ** The reference count of the VTable structure associated with database ** connection db is decremented immediately (which may lead to the ** structure being xDisconnected and free). Any other VTable structures ** in the list are moved to the sqlite3.pDisconnect list of the associated ** database connection. */ SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){ assert( IsVirtual(p) ); assert( db!=0 ); if( db->pnBytesFreed==0 ) vtabDisconnectAll(0, p); if( p->u.vtab.azArg ){ int i; for(i=0; iu.vtab.nArg; i++){ if( i!=1 ) sqlite3DbFree(db, p->u.vtab.azArg[i]); } sqlite3DbFree(db, p->u.vtab.azArg); } } /* ** Add a new module argument to pTable->u.vtab.azArg[]. ** The string is not copied - the pointer is stored. The ** string will be freed automatically when the table is ** deleted. */ static void addModuleArgument(Parse *pParse, Table *pTable, char *zArg){ sqlite3_int64 nBytes; char **azModuleArg; sqlite3 *db = pParse->db; assert( IsVirtual(pTable) ); nBytes = sizeof(char *)*(2+pTable->u.vtab.nArg); if( pTable->u.vtab.nArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", pTable->zName); } azModuleArg = sqlite3DbRealloc(db, pTable->u.vtab.azArg, nBytes); if( azModuleArg==0 ){ sqlite3DbFree(db, zArg); }else{ int i = pTable->u.vtab.nArg++; azModuleArg[i] = zArg; azModuleArg[i+1] = 0; pTable->u.vtab.azArg = azModuleArg; } } /* ** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE ** statement. The module name has been parsed, but the optional list ** of parameters that follow the module name are still pending. */ SQLITE_PRIVATE void sqlite3VtabBeginParse( Parse *pParse, /* Parsing context */ Token *pName1, /* Name of new table, or database name */ Token *pName2, /* Name of new table or NULL */ Token *pModuleName, /* Name of the module for the virtual table */ int ifNotExists /* No error if the table already exists */ ){ Table *pTable; /* The new virtual table */ sqlite3 *db; /* Database connection */ sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, ifNotExists); pTable = pParse->pNewTable; if( pTable==0 ) return; assert( 0==pTable->pIndex ); pTable->eTabType = TABTYP_VTAB; db = pParse->db; assert( pTable->u.vtab.nArg==0 ); addModuleArgument(pParse, pTable, sqlite3NameFromToken(db, pModuleName)); addModuleArgument(pParse, pTable, 0); addModuleArgument(pParse, pTable, sqlite3DbStrDup(db, pTable->zName)); assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0) || (pParse->sNameToken.z==pName1->z && pName2->z==0) ); pParse->sNameToken.n = (int)( &pModuleName->z[pModuleName->n] - pParse->sNameToken.z ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Creating a virtual table invokes the authorization callback twice. ** The first invocation, to obtain permission to INSERT a row into the ** sqlite_schema table, has already been made by sqlite3StartTable(). ** The second call, to obtain permission to create the table, is made now. */ if( pTable->u.vtab.azArg ){ int iDb = sqlite3SchemaToIndex(db, pTable->pSchema); assert( iDb>=0 ); /* The database the table is being created in */ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, pTable->u.vtab.azArg[0], pParse->db->aDb[iDb].zDbSName); } #endif } /* ** This routine takes the module argument that has been accumulating ** in pParse->zArg[] and appends it to the list of arguments on the ** virtual table currently under construction in pParse->pTable. */ static void addArgumentToVtab(Parse *pParse){ if( pParse->sArg.z && pParse->pNewTable ){ const char *z = (const char*)pParse->sArg.z; int n = pParse->sArg.n; sqlite3 *db = pParse->db; addModuleArgument(pParse, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); } } /* ** The parser calls this routine after the CREATE VIRTUAL TABLE statement ** has been completely parsed. */ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ Table *pTab = pParse->pNewTable; /* The table being constructed */ sqlite3 *db = pParse->db; /* The database connection */ if( pTab==0 ) return; assert( IsVirtual(pTab) ); addArgumentToVtab(pParse); pParse->sArg.z = 0; if( pTab->u.vtab.nArg<1 ) return; /* If the CREATE VIRTUAL TABLE statement is being entered for the ** first time (in other words if the virtual table is actually being ** created now instead of just being read out of sqlite_schema) then ** do additional initialization work and store the statement text ** in the sqlite_schema table. */ if( !db->init.busy ){ char *zStmt; char *zWhere; int iDb; int iReg; Vdbe *v; sqlite3MayAbort(pParse); /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ if( pEnd ){ pParse->sNameToken.n = (int)(pEnd->z - pParse->sNameToken.z) + pEnd->n; } zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken); /* A slot for the record has already been allocated in the ** schema table. We just need to update that slot with all ** the information we've collected. ** ** The VM register number pParse->regRowid holds the rowid of an ** entry in the sqlite_schema table that was created for this vtab ** by sqlite3StartTable(). */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "WHERE rowid=#%d", db->aDb[iDb].zDbSName, pTab->zName, pTab->zName, zStmt, pParse->regRowid ); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp0(v, OP_Expire); zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt); sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere, 0); sqlite3DbFree(db, zStmt); iReg = ++pParse->nMem; sqlite3VdbeLoadString(v, iReg, pTab->zName); sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg); }else{ /* If we are rereading the sqlite_schema table create the in-memory ** record of the table. */ Table *pOld; Schema *pSchema = pTab->pSchema; const char *zName = pTab->zName; assert( zName!=0 ); sqlite3MarkAllShadowTablesOf(db, pTab); pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); if( pOld ){ sqlite3OomFault(db); assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ return; } pParse->pNewTable = 0; } } /* ** The parser calls this routine when it sees the first token ** of an argument to the module name in a CREATE VIRTUAL TABLE statement. */ SQLITE_PRIVATE void sqlite3VtabArgInit(Parse *pParse){ addArgumentToVtab(pParse); pParse->sArg.z = 0; pParse->sArg.n = 0; } /* ** The parser calls this routine for each token after the first token ** in an argument to the module name in a CREATE VIRTUAL TABLE statement. */ SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse *pParse, Token *p){ Token *pArg = &pParse->sArg; if( pArg->z==0 ){ pArg->z = p->z; pArg->n = p->n; }else{ assert(pArg->z <= p->z); pArg->n = (int)(&p->z[p->n] - pArg->z); } } /* ** Invoke a virtual table constructor (either xCreate or xConnect). The ** pointer to the function to invoke is passed as the fourth parameter ** to this procedure. */ static int vtabCallConstructor( sqlite3 *db, Table *pTab, Module *pMod, int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), char **pzErr ){ VtabCtx sCtx; VTable *pVTable; int rc; const char *const*azArg; int nArg = pTab->u.vtab.nArg; char *zErr = 0; char *zModuleName; int iDb; VtabCtx *pCtx; assert( IsVirtual(pTab) ); azArg = (const char *const*)pTab->u.vtab.azArg; /* Check that the virtual-table is not already being initialized */ for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){ if( pCtx->pTab==pTab ){ *pzErr = sqlite3MPrintf(db, "vtable constructor called recursively: %s", pTab->zName ); return SQLITE_LOCKED; } } zModuleName = sqlite3DbStrDup(db, pTab->zName); if( !zModuleName ){ return SQLITE_NOMEM_BKPT; } pVTable = sqlite3MallocZero(sizeof(VTable)); if( !pVTable ){ sqlite3OomFault(db); sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM_BKPT; } pVTable->db = db; pVTable->pMod = pMod; pVTable->eVtabRisk = SQLITE_VTABRISK_Normal; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pTab->u.vtab.azArg[1] = db->aDb[iDb].zDbSName; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); assert( xConstruct ); sCtx.pTab = pTab; sCtx.pVTable = pVTable; sCtx.pPrior = db->pVtabCtx; sCtx.bDeclared = 0; db->pVtabCtx = &sCtx; pTab->nTabRef++; rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); sqlite3DeleteTable(db, pTab); db->pVtabCtx = sCtx.pPrior; if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); assert( sCtx.pTab==pTab ); if( SQLITE_OK!=rc ){ if( zErr==0 ){ *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); }else { *pzErr = sqlite3MPrintf(db, "%s", zErr); sqlite3_free(zErr); } sqlite3DbFree(db, pVTable); }else if( ALWAYS(pVTable->pVtab) ){ /* Justification of ALWAYS(): A correct vtab constructor must allocate ** the sqlite3_vtab object if successful. */ memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); pVTable->pVtab->pModule = pMod->pModule; pMod->nRefModule++; pVTable->nRef = 1; if( sCtx.bDeclared==0 ){ const char *zFormat = "vtable constructor did not declare schema: %s"; *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; }else{ int iCol; u16 oooHidden = 0; /* If everything went according to plan, link the new VTable structure ** into the linked list headed by pTab->u.vtab.p. Then loop through the ** columns of the table to see if any of them contain the token "hidden". ** If so, set the Column COLFLAG_HIDDEN flag and remove the token from ** the type string. */ pVTable->pNext = pTab->u.vtab.p; pTab->u.vtab.p = pVTable; for(iCol=0; iColnCol; iCol++){ char *zType = sqlite3ColumnType(&pTab->aCol[iCol], ""); int nType; int i = 0; nType = sqlite3Strlen30(zType); for(i=0; i0 ){ assert(zType[i-1]==' '); zType[i-1] = '\0'; } pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN; pTab->tabFlags |= TF_HasHidden; oooHidden = TF_OOOHidden; }else{ pTab->tabFlags |= oooHidden; } } } } sqlite3DbFree(db, zModuleName); return rc; } /* ** This function is invoked by the parser to call the xConnect() method ** of the virtual table pTab. If an error occurs, an error code is returned ** and an error left in pParse. ** ** This call is a no-op if table pTab is not a virtual table. */ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ sqlite3 *db = pParse->db; const char *zMod; Module *pMod; int rc; assert( pTab ); assert( IsVirtual(pTab) ); if( sqlite3GetVTable(db, pTab) ){ return SQLITE_OK; } /* Locate the required virtual table module */ zMod = pTab->u.vtab.azArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); if( !pMod ){ const char *zModule = pTab->u.vtab.azArg[0]; sqlite3ErrorMsg(pParse, "no such module: %s", zModule); rc = SQLITE_ERROR; }else{ char *zErr = 0; rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "%s", zErr); pParse->rc = rc; } sqlite3DbFree(db, zErr); } return rc; } /* ** Grow the db->aVTrans[] array so that there is room for at least one ** more v-table. Return SQLITE_NOMEM if a malloc fails, or SQLITE_OK otherwise. */ static int growVTrans(sqlite3 *db){ const int ARRAY_INCR = 5; /* Grow the sqlite3.aVTrans array if required */ if( (db->nVTrans%ARRAY_INCR)==0 ){ VTable **aVTrans; sqlite3_int64 nBytes = sizeof(sqlite3_vtab*)* ((sqlite3_int64)db->nVTrans + ARRAY_INCR); aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes); if( !aVTrans ){ return SQLITE_NOMEM_BKPT; } memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR); db->aVTrans = aVTrans; } return SQLITE_OK; } /* ** Add the virtual table pVTab to the array sqlite3.aVTrans[]. Space should ** have already been reserved using growVTrans(). */ static void addToVTrans(sqlite3 *db, VTable *pVTab){ /* Add pVtab to the end of sqlite3.aVTrans */ db->aVTrans[db->nVTrans++] = pVTab; sqlite3VtabLock(pVTab); } /* ** This function is invoked by the vdbe to call the xCreate method ** of the virtual table named zTab in database iDb. ** ** If an error occurs, *pzErr is set to point to an English language ** description of the error and an SQLITE_XXX error code is returned. ** In this case the caller must call sqlite3DbFree(db, ) on *pzErr. */ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ int rc = SQLITE_OK; Table *pTab; Module *pMod; const char *zMod; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); assert( pTab && IsVirtual(pTab) && !pTab->u.vtab.p ); /* Locate the required virtual table module */ zMod = pTab->u.vtab.azArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); /* If the module has been registered and includes a Create method, ** invoke it now. If the module has not been registered, return an ** error. Otherwise, do nothing. */ if( pMod==0 || pMod->pModule->xCreate==0 || pMod->pModule->xDestroy==0 ){ *pzErr = sqlite3MPrintf(db, "no such module: %s", zMod); rc = SQLITE_ERROR; }else{ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); } /* Justification of ALWAYS(): The xConstructor method is required to ** create a valid sqlite3_vtab if it returns SQLITE_OK. */ if( rc==SQLITE_OK && ALWAYS(sqlite3GetVTable(db, pTab)) ){ rc = growVTrans(db); if( rc==SQLITE_OK ){ addToVTrans(db, sqlite3GetVTable(db, pTab)); } } return rc; } /* ** This function is used to set the schema of a virtual table. It is only ** valid to call this function from within the xCreate() or xConnect() of a ** virtual table module. */ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ VtabCtx *pCtx; int rc = SQLITE_OK; Table *pTab; Parse sParse; int initBusy; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); pCtx = db->pVtabCtx; if( !pCtx || pCtx->bDeclared ){ sqlite3Error(db, SQLITE_MISUSE_BKPT); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } pTab = pCtx->pTab; assert( IsVirtual(pTab) ); sqlite3ParseObjectInit(&sParse, db); sParse.eParseMode = PARSE_MODE_DECLARE_VTAB; sParse.disableTriggers = 1; /* We should never be able to reach this point while loading the ** schema. Nevertheless, defend against that (turn off db->init.busy) ** in case a bug arises. */ assert( db->init.busy==0 ); initBusy = db->init.busy; db->init.busy = 0; sParse.nQueryLoop = 1; if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable) && ALWAYS(sParse.pNewTable!=0) && ALWAYS(!db->mallocFailed) && IsOrdinaryTable(sParse.pNewTable) ){ assert( sParse.zErrMsg==0 ); if( !pTab->aCol ){ Table *pNew = sParse.pNewTable; Index *pIdx; pTab->aCol = pNew->aCol; sqlite3ExprListDelete(db, pNew->u.tab.pDfltList); pTab->nNVCol = pTab->nCol = pNew->nCol; pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); pNew->nCol = 0; pNew->aCol = 0; assert( pTab->pIndex==0 ); assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 ); if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 && sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1 ){ /* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0) ** or else must have a single-column PRIMARY KEY */ rc = SQLITE_ERROR; } pIdx = pNew->pIndex; if( pIdx ){ assert( pIdx->pNext==0 ); pTab->pIndex = pIdx; pNew->pIndex = 0; pIdx->pTable = pTab; } } pCtx->bDeclared = 1; }else{ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (sParse.zErrMsg ? "%s" : 0), sParse.zErrMsg); sqlite3DbFree(db, sParse.zErrMsg); rc = SQLITE_ERROR; } sParse.eParseMode = PARSE_MODE_NORMAL; if( sParse.pVdbe ){ sqlite3VdbeFinalize(sParse.pVdbe); } sqlite3DeleteTable(db, sParse.pNewTable); sqlite3ParseObjectReset(&sParse); db->init.busy = initBusy; assert( (rc&0xff)==rc ); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** This function is invoked by the vdbe to call the xDestroy method ** of the virtual table named zTab in database iDb. This occurs ** when a DROP TABLE is mentioned. ** ** This call is a no-op if zTab is not a virtual table. */ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); if( ALWAYS(pTab!=0) && ALWAYS(IsVirtual(pTab)) && ALWAYS(pTab->u.vtab.p!=0) ){ VTable *p; int (*xDestroy)(sqlite3_vtab *); for(p=pTab->u.vtab.p; p; p=p->pNext){ assert( p->pVtab ); if( p->pVtab->nRef>0 ){ return SQLITE_LOCKED; } } p = vtabDisconnectAll(db, pTab); xDestroy = p->pMod->pModule->xDestroy; if( xDestroy==0 ) xDestroy = p->pMod->pModule->xDisconnect; assert( xDestroy!=0 ); pTab->nTabRef++; rc = xDestroy(p->pVtab); /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ if( rc==SQLITE_OK ){ assert( pTab->u.vtab.p==p && p->pNext==0 ); p->pVtab = 0; pTab->u.vtab.p = 0; sqlite3VtabUnlock(p); } sqlite3DeleteTable(db, pTab); } return rc; } /* ** This function invokes either the xRollback or xCommit method ** of each of the virtual tables in the sqlite3.aVTrans array. The method ** called is identified by the second argument, "offset", which is ** the offset of the method to call in the sqlite3_module structure. ** ** The array is cleared after invoking the callbacks. */ static void callFinaliser(sqlite3 *db, int offset){ int i; if( db->aVTrans ){ VTable **aVTrans = db->aVTrans; db->aVTrans = 0; for(i=0; inVTrans; i++){ VTable *pVTab = aVTrans[i]; sqlite3_vtab *p = pVTab->pVtab; if( p ){ int (*x)(sqlite3_vtab *); x = *(int (**)(sqlite3_vtab *))((char *)p->pModule + offset); if( x ) x(p); } pVTab->iSavepoint = 0; sqlite3VtabUnlock(pVTab); } sqlite3DbFree(db, aVTrans); db->nVTrans = 0; } } /* ** Invoke the xSync method of all virtual tables in the sqlite3.aVTrans ** array. Return the error code for the first error that occurs, or ** SQLITE_OK if all xSync operations are successful. ** ** If an error message is available, leave it in p->zErrMsg. */ SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, Vdbe *p){ int i; int rc = SQLITE_OK; VTable **aVTrans = db->aVTrans; db->aVTrans = 0; for(i=0; rc==SQLITE_OK && inVTrans; i++){ int (*x)(sqlite3_vtab *); sqlite3_vtab *pVtab = aVTrans[i]->pVtab; if( pVtab && (x = pVtab->pModule->xSync)!=0 ){ rc = x(pVtab); sqlite3VtabImportErrmsg(p, pVtab); } } db->aVTrans = aVTrans; return rc; } /* ** Invoke the xRollback method of all virtual tables in the ** sqlite3.aVTrans array. Then clear the array itself. */ SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db){ callFinaliser(db, offsetof(sqlite3_module,xRollback)); return SQLITE_OK; } /* ** Invoke the xCommit method of all virtual tables in the ** sqlite3.aVTrans array. Then clear the array itself. */ SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db){ callFinaliser(db, offsetof(sqlite3_module,xCommit)); return SQLITE_OK; } /* ** If the virtual table pVtab supports the transaction interface ** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is ** not currently open, invoke the xBegin method now. ** ** If the xBegin call is successful, place the sqlite3_vtab pointer ** in the sqlite3.aVTrans array. */ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ int rc = SQLITE_OK; const sqlite3_module *pModule; /* Special case: If db->aVTrans is NULL and db->nVTrans is greater ** than zero, then this function is being called from within a ** virtual module xSync() callback. It is illegal to write to ** virtual module tables in this case, so return SQLITE_LOCKED. */ if( sqlite3VtabInSync(db) ){ return SQLITE_LOCKED; } if( !pVTab ){ return SQLITE_OK; } pModule = pVTab->pVtab->pModule; if( pModule->xBegin ){ int i; /* If pVtab is already in the aVTrans array, return early */ for(i=0; inVTrans; i++){ if( db->aVTrans[i]==pVTab ){ return SQLITE_OK; } } /* Invoke the xBegin method. If successful, add the vtab to the ** sqlite3.aVTrans[] array. */ rc = growVTrans(db); if( rc==SQLITE_OK ){ rc = pModule->xBegin(pVTab->pVtab); if( rc==SQLITE_OK ){ int iSvpt = db->nStatement + db->nSavepoint; addToVTrans(db, pVTab); if( iSvpt && pModule->xSavepoint ){ pVTab->iSavepoint = iSvpt; rc = pModule->xSavepoint(pVTab->pVtab, iSvpt-1); } } } } return rc; } /* ** Invoke either the xSavepoint, xRollbackTo or xRelease method of all ** virtual tables that currently have an open transaction. Pass iSavepoint ** as the second argument to the virtual table method invoked. ** ** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is ** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is ** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with ** an open transaction is invoked. ** ** If any virtual table method returns an error code other than SQLITE_OK, ** processing is abandoned and the error returned to the caller of this ** function immediately. If all calls to virtual table methods are successful, ** SQLITE_OK is returned. */ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ int rc = SQLITE_OK; assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN ); assert( iSavepoint>=-1 ); if( db->aVTrans ){ int i; for(i=0; rc==SQLITE_OK && inVTrans; i++){ VTable *pVTab = db->aVTrans[i]; const sqlite3_module *pMod = pVTab->pMod->pModule; if( pVTab->pVtab && pMod->iVersion>=2 ){ int (*xMethod)(sqlite3_vtab *, int); sqlite3VtabLock(pVTab); switch( op ){ case SAVEPOINT_BEGIN: xMethod = pMod->xSavepoint; pVTab->iSavepoint = iSavepoint+1; break; case SAVEPOINT_ROLLBACK: xMethod = pMod->xRollbackTo; break; default: xMethod = pMod->xRelease; break; } if( xMethod && pVTab->iSavepoint>iSavepoint ){ u64 savedFlags = (db->flags & SQLITE_Defensive); db->flags &= ~(u64)SQLITE_Defensive; rc = xMethod(pVTab->pVtab, iSavepoint); db->flags |= savedFlags; } sqlite3VtabUnlock(pVTab); } } } return rc; } /* ** The first parameter (pDef) is a function implementation. The ** second parameter (pExpr) is the first argument to this function. ** If pExpr is a column in a virtual table, then let the virtual ** table implementation have an opportunity to overload the function. ** ** This routine is used to allow virtual table implementations to ** overload MATCH, LIKE, GLOB, and REGEXP operators. ** ** Return either the pDef argument (indicating no change) or a ** new FuncDef structure that is marked as ephemeral using the ** SQLITE_FUNC_EPHEM flag. */ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( sqlite3 *db, /* Database connection for reporting malloc problems */ FuncDef *pDef, /* Function to possibly overload */ int nArg, /* Number of arguments to the function */ Expr *pExpr /* First argument to the function */ ){ Table *pTab; sqlite3_vtab *pVtab; sqlite3_module *pMod; void (*xSFunc)(sqlite3_context*,int,sqlite3_value**) = 0; void *pArg = 0; FuncDef *pNew; int rc = 0; /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; assert( ExprUseYTab(pExpr) ); pTab = pExpr->y.pTab; if( NEVER(pTab==0) ) return pDef; if( !IsVirtual(pTab) ) return pDef; pVtab = sqlite3GetVTable(db, pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); pMod = (sqlite3_module *)pVtab->pModule; if( pMod->xFindFunction==0 ) return pDef; /* Call the xFindFunction method on the virtual table implementation ** to see if the implementation wants to overload this function. ** ** Though undocumented, we have historically always invoked xFindFunction ** with an all lower-case function name. Continue in this tradition to ** avoid any chance of an incompatibility. */ #ifdef SQLITE_DEBUG { int i; for(i=0; pDef->zName[i]; i++){ unsigned char x = (unsigned char)pDef->zName[i]; assert( x==sqlite3UpperToLower[x] ); } } #endif rc = pMod->xFindFunction(pVtab, nArg, pDef->zName, &xSFunc, &pArg); if( rc==0 ){ return pDef; } /* Create a new ephemeral function definition for the overloaded ** function */ pNew = sqlite3DbMallocZero(db, sizeof(*pNew) + sqlite3Strlen30(pDef->zName) + 1); if( pNew==0 ){ return pDef; } *pNew = *pDef; pNew->zName = (const char*)&pNew[1]; memcpy((char*)&pNew[1], pDef->zName, sqlite3Strlen30(pDef->zName)+1); pNew->xSFunc = xSFunc; pNew->pUserData = pArg; pNew->funcFlags |= SQLITE_FUNC_EPHEM; return pNew; } /* ** Make sure virtual table pTab is contained in the pParse->apVirtualLock[] ** array so that an OP_VBegin will get generated for it. Add pTab to the ** array if it is missing. If pTab is already in the array, this routine ** is a no-op. */ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ Parse *pToplevel = sqlite3ParseToplevel(pParse); int i, n; Table **apVtabLock; assert( IsVirtual(pTab) ); for(i=0; inVtabLock; i++){ if( pTab==pToplevel->apVtabLock[i] ) return; } n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]); apVtabLock = sqlite3Realloc(pToplevel->apVtabLock, n); if( apVtabLock ){ pToplevel->apVtabLock = apVtabLock; pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; }else{ sqlite3OomFault(pToplevel->db); } } /* ** Check to see if virtual table module pMod can be have an eponymous ** virtual table instance. If it can, create one if one does not already ** exist. Return non-zero if either the eponymous virtual table instance ** exists when this routine returns or if an attempt to create it failed ** and an error message was left in pParse. ** ** An eponymous virtual table instance is one that is named after its ** module, and more importantly, does not require a CREATE VIRTUAL TABLE ** statement in order to come into existence. Eponymous virtual table ** instances always exist. They cannot be DROP-ed. ** ** Any virtual table module for which xConnect and xCreate are the same ** method can have an eponymous virtual table instance. */ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ const sqlite3_module *pModule = pMod->pModule; Table *pTab; char *zErr = 0; int rc; sqlite3 *db = pParse->db; if( pMod->pEpoTab ) return 1; if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0; pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return 0; pTab->zName = sqlite3DbStrDup(db, pMod->zName); if( pTab->zName==0 ){ sqlite3DbFree(db, pTab); return 0; } pMod->pEpoTab = pTab; pTab->nTabRef = 1; pTab->eTabType = TABTYP_VTAB; pTab->pSchema = db->aDb[0].pSchema; assert( pTab->u.vtab.nArg==0 ); pTab->iPKey = -1; pTab->tabFlags |= TF_Eponymous; addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); addModuleArgument(pParse, pTab, 0); addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr); if( rc ){ sqlite3ErrorMsg(pParse, "%s", zErr); sqlite3DbFree(db, zErr); sqlite3VtabEponymousTableClear(db, pMod); } return 1; } /* ** Erase the eponymous virtual table instance associated with ** virtual table module pMod, if it exists. */ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; if( pTab!=0 ){ /* Mark the table as Ephemeral prior to deleting it, so that the ** sqlite3DeleteTable() routine will know that it is not stored in ** the schema. */ pTab->tabFlags |= TF_Ephemeral; sqlite3DeleteTable(db, pTab); pMod->pEpoTab = 0; } } /* ** Return the ON CONFLICT resolution mode in effect for the virtual ** table update operation currently in progress. ** ** The results of this routine are undefined unless it is called from ** within an xUpdate method. */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){ static const unsigned char aMap[] = { SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE }; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 ); assert( OE_Ignore==4 && OE_Replace==5 ); assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 ); return (int)aMap[db->vtabOnConflict-1]; } /* ** Call from within the xCreate() or xConnect() methods to provide ** the SQLite core with additional information about the behavior ** of the virtual table being implemented. */ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){ va_list ap; int rc = SQLITE_OK; VtabCtx *p; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); p = db->pVtabCtx; if( !p ){ rc = SQLITE_MISUSE_BKPT; }else{ assert( p->pTab==0 || IsVirtual(p->pTab) ); va_start(ap, op); switch( op ){ case SQLITE_VTAB_CONSTRAINT_SUPPORT: { p->pVTable->bConstraint = (u8)va_arg(ap, int); break; } case SQLITE_VTAB_INNOCUOUS: { p->pVTable->eVtabRisk = SQLITE_VTABRISK_Low; break; } case SQLITE_VTAB_DIRECTONLY: { p->pVTable->eVtabRisk = SQLITE_VTABRISK_High; break; } case SQLITE_VTAB_USES_ALL_SCHEMAS: { p->pVTable->bAllSchemas = 1; break; } default: { rc = SQLITE_MISUSE_BKPT; break; } } va_end(ap); } if( rc!=SQLITE_OK ) sqlite3Error(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /************** End of vtab.c ************************************************/ /************** Begin file wherecode.c ***************************************/ /* ** 2015-06-06 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** ** This file was split off from where.c on 2015-06-06 in order to reduce the ** size of where.c and make it easier to edit. This file contains the routines ** that actually generate the bulk of the WHERE loop code. The original where.c ** file retains the code that does query planning and analysis. */ /* #include "sqliteInt.h" */ /************** Include whereInt.h in the middle of wherecode.c **************/ /************** Begin file whereInt.h ****************************************/ /* ** 2013-11-12 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains structure and macro definitions for the query ** planner logic in "where.c". These definitions are broken out into ** a separate source file for easier editing. */ #ifndef SQLITE_WHEREINT_H #define SQLITE_WHEREINT_H /* Forward references */ typedef struct WhereClause WhereClause; typedef struct WhereMaskSet WhereMaskSet; typedef struct WhereOrInfo WhereOrInfo; typedef struct WhereAndInfo WhereAndInfo; typedef struct WhereLevel WhereLevel; typedef struct WhereLoop WhereLoop; typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; typedef struct WhereLoopBuilder WhereLoopBuilder; typedef struct WhereScan WhereScan; typedef struct WhereOrCost WhereOrCost; typedef struct WhereOrSet WhereOrSet; typedef struct WhereMemBlock WhereMemBlock; typedef struct WhereRightJoin WhereRightJoin; /* ** This object is a header on a block of allocated memory that will be ** automatically freed when its WInfo object is destructed. */ struct WhereMemBlock { WhereMemBlock *pNext; /* Next block in the chain */ u64 sz; /* Bytes of space */ }; /* ** Extra information attached to a WhereLevel that is a RIGHT JOIN. */ struct WhereRightJoin { int iMatch; /* Cursor used to determine prior matched rows */ int regBloom; /* Bloom filter for iRJMatch */ int regReturn; /* Return register for the interior subroutine */ int addrSubrtn; /* Starting address for the interior subroutine */ int endSubrtn; /* The last opcode in the interior subroutine */ }; /* ** This object contains information needed to implement a single nested ** loop in WHERE clause. ** ** Contrast this object with WhereLoop. This object describes the ** implementation of the loop. WhereLoop describes the algorithm. ** This object contains a pointer to the WhereLoop algorithm as one of ** its elements. ** ** The WhereInfo object contains a single instance of this object for ** each term in the FROM clause (which is to say, for each of the ** nested loops as implemented). The order of WhereLevel objects determines ** the loop nested order, with WhereInfo.a[0] being the outer loop and ** WhereInfo.a[WhereInfo.nLevel-1] being the inner loop. */ struct WhereLevel { int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */ int iTabCur; /* The VDBE cursor used to access the table */ int iIdxCur; /* The VDBE cursor used to access pIdx */ int addrBrk; /* Jump here to break out of the loop */ int addrNxt; /* Jump here to start the next IN combination */ int addrSkip; /* Jump here for next iteration of skip-scan */ int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ int regBignull; /* big-null flag reg. True if a NULL-scan is needed */ int addrBignull; /* Jump here for next part of big-null scan */ #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */ int addrLikeRep; /* LIKE range processing address */ #endif int regFilter; /* Bloom filter */ WhereRightJoin *pRJ; /* Extra information for RIGHT JOIN */ u8 iFrom; /* Which entry in the FROM clause */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ int p1, p2; /* Operands of the opcode used to end the loop */ union { /* Information that depends on pWLoop->wsFlags */ struct { int nIn; /* Number of entries in aInLoop[] */ struct InLoop { int iCur; /* The VDBE cursor used by this IN operator */ int addrInTop; /* Top of the IN loop */ int iBase; /* Base register of multi-key index record */ int nPrefix; /* Number of prior entries in the key */ u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */ Index *pCoveringIdx; /* Possible covering index for WHERE_MULTI_OR */ } u; struct WhereLoop *pWLoop; /* The selected WhereLoop object */ Bitmask notReady; /* FROM entries not usable at this level */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrVisit; /* Address at which row is visited */ #endif }; /* ** Each instance of this object represents an algorithm for evaluating one ** term of a join. Every term of the FROM clause will have at least ** one corresponding WhereLoop object (unless INDEXED BY constraints ** prevent a query solution - which is an error) and many terms of the ** FROM clause will have multiple WhereLoop objects, each describing a ** potential way of implementing that FROM-clause term, together with ** dependencies and cost estimates for using the chosen algorithm. ** ** Query planning consists of building up a collection of these WhereLoop ** objects, then computing a particular sequence of WhereLoop objects, with ** one WhereLoop object per FROM clause term, that satisfy all dependencies ** and that minimize the overall cost. */ struct WhereLoop { Bitmask prereq; /* Bitmask of other loops that must run first */ Bitmask maskSelf; /* Bitmask identifying table iTab */ #ifdef SQLITE_DEBUG char cId; /* Symbolic ID of this loop for debugging use */ #endif u8 iTab; /* Position in FROM clause of table for this loop */ u8 iSortIdx; /* Sorting index number. 0==None */ LogEst rSetup; /* One-time setup cost (ex: create transient index) */ LogEst rRun; /* Cost of running each loop */ LogEst nOut; /* Estimated number of output rows */ union { struct { /* Information for internal btree tables */ u16 nEq; /* Number of equality constraints */ u16 nBtm; /* Size of BTM vector */ u16 nTop; /* Size of TOP vector */ u16 nDistinctCol; /* Index columns used to sort for DISTINCT */ Index *pIndex; /* Index used, or NULL */ } btree; struct { /* Information for virtual tables */ int idxNum; /* Index number */ u32 needFree : 1; /* True if sqlite3_free(idxStr) is needed */ u32 bOmitOffset : 1; /* True to let virtual table handle offset */ i8 isOrdered; /* True if satisfies ORDER BY */ u16 omitMask; /* Terms that may be omitted */ char *idxStr; /* Index identifier string */ u32 mHandleIn; /* Terms to handle as IN(...) instead of == */ } vtab; } u; u32 wsFlags; /* WHERE_* flags describing the plan */ u16 nLTerm; /* Number of entries in aLTerm[] */ u16 nSkip; /* Number of NULL aLTerm[] entries */ /**** whereLoopXfer() copies fields above ***********************/ # define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot) u16 nLSlot; /* Number of slots allocated for aLTerm[] */ WhereTerm **aLTerm; /* WhereTerms used */ WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */ }; /* This object holds the prerequisites and the cost of running a ** subquery on one operand of an OR operator in the WHERE clause. ** See WhereOrSet for additional information */ struct WhereOrCost { Bitmask prereq; /* Prerequisites */ LogEst rRun; /* Cost of running this subquery */ LogEst nOut; /* Number of outputs for this subquery */ }; /* The WhereOrSet object holds a set of possible WhereOrCosts that ** correspond to the subquery(s) of OR-clause processing. Only the ** best N_OR_COST elements are retained. */ #define N_OR_COST 3 struct WhereOrSet { u16 n; /* Number of valid a[] entries */ WhereOrCost a[N_OR_COST]; /* Set of best costs */ }; /* ** Each instance of this object holds a sequence of WhereLoop objects ** that implement some or all of a query plan. ** ** Think of each WhereLoop object as a node in a graph with arcs ** showing dependencies and costs for travelling between nodes. (That is ** not a completely accurate description because WhereLoop costs are a ** vector, not a scalar, and because dependencies are many-to-one, not ** one-to-one as are graph nodes. But it is a useful visualization aid.) ** Then a WherePath object is a path through the graph that visits some ** or all of the WhereLoop objects once. ** ** The "solver" works by creating the N best WherePath objects of length ** 1. Then using those as a basis to compute the N best WherePath objects ** of length 2. And so forth until the length of WherePaths equals the ** number of nodes in the FROM clause. The best (lowest cost) WherePath ** at the end is the chosen query plan. */ struct WherePath { Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */ LogEst nRow; /* Estimated number of rows generated by this path */ LogEst rCost; /* Total cost of this path */ LogEst rUnsorted; /* Total cost of this path ignoring sorting costs */ i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */ WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */ }; /* ** The query generator uses an array of instances of this structure to ** help it analyze the subexpressions of the WHERE clause. Each WHERE ** clause subexpression is separated from the others by AND operators, ** usually, or sometimes subexpressions separated by OR. ** ** All WhereTerms are collected into a single WhereClause structure. ** The following identity holds: ** ** WhereTerm.pWC->a[WhereTerm.idx] == WhereTerm ** ** When a term is of the form: ** ** X ** ** where X is a column name and is one of certain operators, ** then WhereTerm.leftCursor and WhereTerm.u.leftColumn record the ** cursor number and column number for X. WhereTerm.eOperator records ** the using a bitmask encoding defined by WO_xxx below. The ** use of a bitmask encoding for the operator allows us to search ** quickly for terms that match any of several different operators. ** ** A WhereTerm might also be two or more subterms connected by OR: ** ** (t1.X ) OR (t1.Y ) OR .... ** ** In this second case, wtFlag has the TERM_ORINFO bit set and eOperator==WO_OR ** and the WhereTerm.u.pOrInfo field points to auxiliary information that ** is collected about the OR clause. ** ** If a term in the WHERE clause does not match either of the two previous ** categories, then eOperator==0. The WhereTerm.pExpr field is still set ** to the original subexpression content and wtFlags is set up appropriately ** but no other fields in the WhereTerm object are meaningful. ** ** When eOperator!=0, prereqRight and prereqAll record sets of cursor numbers, ** but they do so indirectly. A single WhereMaskSet structure translates ** cursor number into bits and the translated bit is stored in the prereq ** fields. The translation is used in order to maximize the number of ** bits that will fit in a Bitmask. The VDBE cursor numbers might be ** spread out over the non-negative integers. For example, the cursor ** numbers might be 3, 8, 9, 10, 20, 23, 41, and 45. The WhereMaskSet ** translates these sparse cursor numbers into consecutive integers ** beginning with 0 in order to make the best possible use of the available ** bits in the Bitmask. So, in the example above, the cursor numbers ** would be mapped into integers 0 through 7. ** ** The number of terms in a join is limited by the number of bits ** in prereqRight and prereqAll. The default is 64 bits, hence SQLite ** is only able to process joins with 64 or fewer tables. */ struct WhereTerm { Expr *pExpr; /* Pointer to the subexpression that is this term */ WhereClause *pWC; /* The clause this term is part of */ LogEst truthProb; /* Probability of truth for this expression */ u16 wtFlags; /* TERM_xxx bit flags. See below */ u16 eOperator; /* A WO_xx value describing */ u8 nChild; /* Number of children that must disable us */ u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X " */ union { struct { int leftColumn; /* Column number of X in "X " */ int iField; /* Field in (?,?,?) IN (SELECT...) vector */ } x; /* Opcode other than OP_OR or OP_AND */ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ } u; Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */ Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */ }; /* ** Allowed values of WhereTerm.wtFlags */ #define TERM_DYNAMIC 0x0001 /* Need to call sqlite3ExprDelete(db, pExpr) */ #define TERM_VIRTUAL 0x0002 /* Added by the optimizer. Do not code */ #define TERM_CODED 0x0004 /* This term is already coded */ #define TERM_COPIED 0x0008 /* Has a child */ #define TERM_ORINFO 0x0010 /* Need to free the WhereTerm.u.pOrInfo object */ #define TERM_ANDINFO 0x0020 /* Need to free the WhereTerm.u.pAndInfo obj */ #define TERM_OK 0x0040 /* Used during OR-clause processing */ #define TERM_VNULL 0x0080 /* Manufactured x>NULL or x<=NULL term */ #define TERM_LIKEOPT 0x0100 /* Virtual terms from the LIKE optimization */ #define TERM_LIKECOND 0x0200 /* Conditionally this LIKE operator term */ #define TERM_LIKE 0x0400 /* The original LIKE operator */ #define TERM_IS 0x0800 /* Term.pExpr is an IS operator */ #define TERM_VARSELECT 0x1000 /* Term.pExpr contains a correlated sub-query */ #define TERM_HEURTRUTH 0x2000 /* Heuristic truthProb used */ #ifdef SQLITE_ENABLE_STAT4 # define TERM_HIGHTRUTH 0x4000 /* Term excludes few rows */ #else # define TERM_HIGHTRUTH 0 /* Only used with STAT4 */ #endif #define TERM_SLICE 0x8000 /* One slice of a row-value/vector comparison */ /* ** An instance of the WhereScan object is used as an iterator for locating ** terms in the WHERE clause that are useful to the query planner. */ struct WhereScan { WhereClause *pOrigWC; /* Original, innermost WhereClause */ WhereClause *pWC; /* WhereClause currently being scanned */ const char *zCollName; /* Required collating sequence, if not NULL */ Expr *pIdxExpr; /* Search for this index expression */ int k; /* Resume scanning at this->pWC->a[this->k] */ u32 opMask; /* Acceptable operators */ char idxaff; /* Must match this affinity, if zCollName!=NULL */ unsigned char iEquiv; /* Current slot in aiCur[] and aiColumn[] */ unsigned char nEquiv; /* Number of entries in aiCur[] and aiColumn[] */ int aiCur[11]; /* Cursors in the equivalence class */ i16 aiColumn[11]; /* Corresponding column number in the eq-class */ }; /* ** An instance of the following structure holds all information about a ** WHERE clause. Mostly this is a container for one or more WhereTerms. ** ** Explanation of pOuter: For a WHERE clause of the form ** ** a AND ((b AND c) OR (d AND e)) AND f ** ** There are separate WhereClause objects for the whole clause and for ** the subclauses "(b AND c)" and "(d AND e)". The pOuter field of the ** subclauses points to the WhereClause object for the whole clause. */ struct WhereClause { WhereInfo *pWInfo; /* WHERE clause processing context */ WhereClause *pOuter; /* Outer conjunction */ u8 op; /* Split operator. TK_AND or TK_OR */ u8 hasOr; /* True if any a[].eOperator is WO_OR */ int nTerm; /* Number of terms */ int nSlot; /* Number of entries in a[] */ int nBase; /* Number of terms through the last non-Virtual */ WhereTerm *a; /* Each a[] describes a term of the WHERE clause */ #if defined(SQLITE_SMALL_STACK) WhereTerm aStatic[1]; /* Initial static space for a[] */ #else WhereTerm aStatic[8]; /* Initial static space for a[] */ #endif }; /* ** A WhereTerm with eOperator==WO_OR has its u.pOrInfo pointer set to ** a dynamically allocated instance of the following structure. */ struct WhereOrInfo { WhereClause wc; /* Decomposition into subterms */ Bitmask indexable; /* Bitmask of all indexable tables in the clause */ }; /* ** A WhereTerm with eOperator==WO_AND has its u.pAndInfo pointer set to ** a dynamically allocated instance of the following structure. */ struct WhereAndInfo { WhereClause wc; /* The subexpression broken out */ }; /* ** An instance of the following structure keeps track of a mapping ** between VDBE cursor numbers and bits of the bitmasks in WhereTerm. ** ** The VDBE cursor numbers are small integers contained in ** SrcItem.iCursor and Expr.iTable fields. For any given WHERE ** clause, the cursor numbers might not begin with 0 and they might ** contain gaps in the numbering sequence. But we want to make maximum ** use of the bits in our bitmasks. This structure provides a mapping ** from the sparse cursor numbers into consecutive integers beginning ** with 0. ** ** If WhereMaskSet.ix[A]==B it means that The A-th bit of a Bitmask ** corresponds VDBE cursor number B. The A-th bit of a bitmask is 1<3, 5->1, 8->2, 29->0, ** 57->5, 73->4. Or one of 719 other combinations might be used. It ** does not really matter. What is important is that sparse cursor ** numbers all get mapped into bit numbers that begin with 0 and contain ** no gaps. */ struct WhereMaskSet { int bVarSelect; /* Used by sqlite3WhereExprUsage() */ int n; /* Number of assigned cursor values */ int ix[BMS]; /* Cursor assigned to each bit */ }; /* ** This object is a convenience wrapper holding all information needed ** to construct WhereLoop objects for a particular query. */ struct WhereLoopBuilder { WhereInfo *pWInfo; /* Information about this WHERE */ WhereClause *pWC; /* WHERE clause terms */ WhereLoop *pNew; /* Template WhereLoop */ WhereOrSet *pOrSet; /* Record best loops here, if not NULL */ #ifdef SQLITE_ENABLE_STAT4 UnpackedRecord *pRec; /* Probe for stat4 (if required) */ int nRecValid; /* Number of valid fields currently in pRec */ #endif unsigned char bldFlags1; /* First set of SQLITE_BLDF_* flags */ unsigned char bldFlags2; /* Second set of SQLITE_BLDF_* flags */ unsigned int iPlanLimit; /* Search limiter */ }; /* Allowed values for WhereLoopBuider.bldFlags */ #define SQLITE_BLDF1_INDEXED 0x0001 /* An index is used */ #define SQLITE_BLDF1_UNIQUE 0x0002 /* All keys of a UNIQUE index used */ #define SQLITE_BLDF2_2NDPASS 0x0004 /* Second builder pass needed */ /* The WhereLoopBuilder.iPlanLimit is used to limit the number of ** index+constraint combinations the query planner will consider for a ** particular query. If this parameter is unlimited, then certain ** pathological queries can spend excess time in the sqlite3WhereBegin() ** routine. The limit is high enough that is should not impact real-world ** queries. ** ** SQLITE_QUERY_PLANNER_LIMIT is the baseline limit. The limit is ** increased by SQLITE_QUERY_PLANNER_LIMIT_INCR before each term of the FROM ** clause is processed, so that every table in a join is guaranteed to be ** able to propose a some index+constraint combinations even if the initial ** baseline limit was exhausted by prior tables of the join. */ #ifndef SQLITE_QUERY_PLANNER_LIMIT # define SQLITE_QUERY_PLANNER_LIMIT 20000 #endif #ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR # define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000 #endif /* ** The WHERE clause processing routine has two halves. The ** first part does the start of the WHERE loop and the second ** half does the tail of the WHERE loop. An instance of ** this structure is returned by the first half and passed ** into the second half to give some continuity. ** ** An instance of this object holds the complete state of the query ** planner. */ struct WhereInfo { Parse *pParse; /* Parsing and code generating context */ SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ ExprList *pResultSet; /* Result set of the query */ #if WHERETRACE_ENABLED Expr *pWhere; /* The complete WHERE clause */ #endif Select *pSelect; /* The entire SELECT statement containing WHERE */ int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */ u8 nLevel; /* Number of nested loop */ i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values */ unsigned bDeferredSeek :1; /* Uses OP_DeferredSeek */ unsigned untestedTerms :1; /* Not all WHERE terms resolved by outer loop */ unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */ unsigned sorted :1; /* True if really sorted (not just grouped) */ LogEst nRowOut; /* Estimated number of output rows */ int iTop; /* The very beginning of the WHERE loop */ int iEndWhere; /* End of the WHERE clause itself */ WhereLoop *pLoops; /* List of all WhereLoop objects */ WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereLevel a[1]; /* Information about each nest loop in WHERE */ }; /* ** Private interfaces - callable only by other where.c routines. ** ** where.c: */ SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); #ifdef WHERETRACE_ENABLED SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC); SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm); SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC); #endif SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ ); SQLITE_PRIVATE void *sqlite3WhereMalloc(WhereInfo *pWInfo, u64 nByte); SQLITE_PRIVATE void *sqlite3WhereRealloc(WhereInfo *pWInfo, void *pOld, u64 nByte); /* wherecode.c: */ #ifndef SQLITE_OMIT_EXPLAIN SQLITE_PRIVATE int sqlite3WhereExplainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ); SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter( const Parse *pParse, /* Parse context */ const WhereInfo *pWInfo, /* WHERE clause */ const WhereLevel *pLevel /* Bloom filter on this level */ ); #else # define sqlite3WhereExplainOneScan(u,v,w,x) 0 # define sqlite3WhereExplainBloomFilter(u,v,w) 0 #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS SQLITE_PRIVATE void sqlite3WhereAddScanStatus( Vdbe *v, /* Vdbe to add scanstatus entry to */ SrcList *pSrclist, /* FROM clause pLvl reads data from */ WhereLevel *pLvl, /* Level to add scanstatus() entry for */ int addrExplain /* Address of OP_Explain (or 0) */ ); #else # define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d) #endif SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( Parse *pParse, /* Parsing context */ Vdbe *v, /* Prepared statement under construction */ WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ WhereLevel *pLevel, /* The current level pointer */ Bitmask notReady /* Which tables are currently available */ ); SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( WhereInfo *pWInfo, int iLevel, WhereLevel *pLevel ); /* whereexpr.c: */ SQLITE_PRIVATE void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause*); SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause*,Expr*,u8); SQLITE_PRIVATE void sqlite3WhereAddLimit(WhereClause*, Select*); SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*); SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*); SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); SQLITE_PRIVATE void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*); /* ** Bitmasks for the operators on WhereTerm objects. These are all ** operators that are of interest to the query planner. An ** OR-ed combination of these values can be used when searching for ** particular WhereTerms within a WhereClause. ** ** Value constraints: ** WO_EQ == SQLITE_INDEX_CONSTRAINT_EQ ** WO_LT == SQLITE_INDEX_CONSTRAINT_LT ** WO_LE == SQLITE_INDEX_CONSTRAINT_LE ** WO_GT == SQLITE_INDEX_CONSTRAINT_GT ** WO_GE == SQLITE_INDEX_CONSTRAINT_GE */ #define WO_IN 0x0001 #define WO_EQ 0x0002 #define WO_LT (WO_EQ<<(TK_LT-TK_EQ)) #define WO_LE (WO_EQ<<(TK_LE-TK_EQ)) #define WO_GT (WO_EQ<<(TK_GT-TK_EQ)) #define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) #define WO_AUX 0x0040 /* Op useful to virtual tables only */ #define WO_IS 0x0080 #define WO_ISNULL 0x0100 #define WO_OR 0x0200 /* Two or more OR-connected terms */ #define WO_AND 0x0400 /* Two or more AND-connected terms */ #define WO_EQUIV 0x0800 /* Of the form A==B, both columns */ #define WO_NOOP 0x1000 /* This term does not restrict search space */ #define WO_ROWVAL 0x2000 /* A row-value term */ #define WO_ALL 0x3fff /* Mask of all possible WO_* values */ #define WO_SINGLE 0x01ff /* Mask of all non-compound WO_* values */ /* ** These are definitions of bits in the WhereLoop.wsFlags field. ** The particular combination of bits in each WhereLoop help to ** determine the algorithm that WhereLoop represents. */ #define WHERE_COLUMN_EQ 0x00000001 /* x=EXPR */ #define WHERE_COLUMN_RANGE 0x00000002 /* xEXPR */ #define WHERE_COLUMN_IN 0x00000004 /* x IN (...) */ #define WHERE_COLUMN_NULL 0x00000008 /* x IS NULL */ #define WHERE_CONSTRAINT 0x0000000f /* Any of the WHERE_COLUMN_xxx values */ #define WHERE_TOP_LIMIT 0x00000010 /* xEXPR or x>=EXPR constraint */ #define WHERE_BOTH_LIMIT 0x00000030 /* Both x>EXPR and xaiColumn[i]; if( i==XN_EXPR ) return ""; if( i==XN_ROWID ) return "rowid"; return pIdx->pTable->aCol[i].zCnName; } /* ** This routine is a helper for explainIndexRange() below ** ** pStr holds the text of an expression that we are building up one term ** at a time. This routine adds a new term to the end of the expression. ** Terms are separated by AND so add the "AND" text for second and subsequent ** terms only. */ static void explainAppendTerm( StrAccum *pStr, /* The text expression being built */ Index *pIdx, /* Index to read column names from */ int nTerm, /* Number of terms */ int iTerm, /* Zero-based index of first term. */ int bAnd, /* Non-zero to append " AND " */ const char *zOp /* Name of the operator */ ){ int i; assert( nTerm>=1 ); if( bAnd ) sqlite3_str_append(pStr, " AND ", 5); if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1); for(i=0; i1 ) sqlite3_str_append(pStr, ")", 1); sqlite3_str_append(pStr, zOp, 1); if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1); for(i=0; i1 ) sqlite3_str_append(pStr, ")", 1); } /* ** Argument pLevel describes a strategy for scanning table pTab. This ** function appends text to pStr that describes the subset of table ** rows scanned by the strategy in the form of an SQL expression. ** ** For example, if the query: ** ** SELECT * FROM t1 WHERE a=1 AND b>2; ** ** is run and there is an index on (a, b), then this function returns a ** string similar to: ** ** "a=? AND b>?" */ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ Index *pIndex = pLoop->u.btree.pIndex; u16 nEq = pLoop->u.btree.nEq; u16 nSkip = pLoop->nSkip; int i, j; if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; sqlite3_str_append(pStr, " (", 2); for(i=0; i=nSkip ? "%s=?" : "ANY(%s)", z); } j = i; if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ explainAppendTerm(pStr, pIndex, pLoop->u.btree.nBtm, j, i, ">"); i = 1; } if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<"); } sqlite3_str_append(pStr, ")", 1); } /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN ** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG ** was defined at compile-time. If it is not a no-op, a single OP_Explain ** opcode is added to the output to describe the table scan strategy in pLevel. ** ** If an OP_Explain opcode is added to the VM, its address is returned. ** Otherwise, if no OP_Explain is coded, zero is returned. */ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ int ret = 0; #if !defined(SQLITE_DEBUG) if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) #endif { SrcItem *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ char *zMsg; /* Text to add to EQP output */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); str.printfFlags = SQLITE_PRINTF_INTERNAL; sqlite3_str_appendf(&str, "%s %S", isSearch ? "SEARCH" : "SCAN", pItem); if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ const char *zFmt = 0; Index *pIdx; assert( pLoop->u.btree.pIndex!=0 ); pIdx = pLoop->u.btree.pIndex; assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ if( isSearch ){ zFmt = "PRIMARY KEY"; } }else if( flags & WHERE_PARTIALIDX ){ zFmt = "AUTOMATIC PARTIAL COVERING INDEX"; }else if( flags & WHERE_AUTO_INDEX ){ zFmt = "AUTOMATIC COVERING INDEX"; }else if( flags & WHERE_IDX_ONLY ){ zFmt = "COVERING INDEX %s"; }else{ zFmt = "INDEX %s"; } if( zFmt ){ sqlite3_str_append(&str, " USING ", 7); sqlite3_str_appendf(&str, zFmt, pIdx->zName); explainIndexRange(&str, pLoop); } }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ char cRangeOp; #if 0 /* Better output, but breaks many tests */ const Table *pTab = pItem->pTab; const char *zRowid = pTab->iPKey>=0 ? pTab->aCol[pTab->iPKey].zCnName: "rowid"; #else const char *zRowid = "rowid"; #endif sqlite3_str_appendf(&str, " USING INTEGER PRIMARY KEY (%s", zRowid); if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ cRangeOp = '='; }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ sqlite3_str_appendf(&str, ">? AND %s", zRowid); cRangeOp = '<'; }else if( flags&WHERE_BTM_LIMIT ){ cRangeOp = '>'; }else{ assert( flags&WHERE_TOP_LIMIT); cRangeOp = '<'; } sqlite3_str_appendf(&str, "%c?)", cRangeOp); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s", pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif if( pItem->fg.jointype & JT_LEFT ){ sqlite3_str_appendf(&str, " LEFT-JOIN"); } #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS if( pLoop->nOut>=10 ){ sqlite3_str_appendf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); }else{ sqlite3_str_append(&str, " (~1 row)", 9); } #endif zMsg = sqlite3StrAccumFinish(&str); sqlite3ExplainBreakpoint("",zMsg); ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), pParse->addrExplain, 0, zMsg,P4_DYNAMIC); } return ret; } /* ** Add a single OP_Explain opcode that describes a Bloom filter. ** ** Or if not processing EXPLAIN QUERY PLAN and not in a SQLITE_DEBUG and/or ** SQLITE_ENABLE_STMT_SCANSTATUS build, then OP_Explain opcodes are not ** required and this routine is a no-op. ** ** If an OP_Explain opcode is added to the VM, its address is returned. ** Otherwise, if no OP_Explain is coded, zero is returned. */ SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter( const Parse *pParse, /* Parse context */ const WhereInfo *pWInfo, /* WHERE clause */ const WhereLevel *pLevel /* Bloom filter on this level */ ){ int ret = 0; SrcItem *pItem = &pWInfo->pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ char *zMsg; /* Text to add to EQP output */ int i; /* Loop counter */ WhereLoop *pLoop; /* The where loop */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); str.printfFlags = SQLITE_PRINTF_INTERNAL; sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem); pLoop = pLevel->pWLoop; if( pLoop->wsFlags & WHERE_IPK ){ const Table *pTab = pItem->pTab; if( pTab->iPKey>=0 ){ sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName); }else{ sqlite3_str_appendf(&str, "rowid=?"); } }else{ for(i=pLoop->nSkip; iu.btree.nEq; i++){ const char *z = explainIndexColumnName(pLoop->u.btree.pIndex, i); if( i>pLoop->nSkip ) sqlite3_str_append(&str, " AND ", 5); sqlite3_str_appendf(&str, "%s=?", z); } } sqlite3_str_append(&str, ")", 1); zMsg = sqlite3StrAccumFinish(&str); ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), pParse->addrExplain, 0, zMsg,P4_DYNAMIC); sqlite3VdbeScanStatus(v, sqlite3VdbeCurrentAddr(v)-1, 0, 0, 0, 0); return ret; } #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Configure the VM passed as the first argument with an ** sqlite3_stmt_scanstatus() entry corresponding to the scan used to ** implement level pLvl. Argument pSrclist is a pointer to the FROM ** clause that the scan reads data from. ** ** If argument addrExplain is not 0, it must be the address of an ** OP_Explain instruction that describes the same loop. */ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( Vdbe *v, /* Vdbe to add scanstatus entry to */ SrcList *pSrclist, /* FROM clause pLvl reads data from */ WhereLevel *pLvl, /* Level to add scanstatus() entry for */ int addrExplain /* Address of OP_Explain (or 0) */ ){ if( IS_STMT_SCANSTATUS( sqlite3VdbeDb(v) ) ){ const char *zObj = 0; WhereLoop *pLoop = pLvl->pWLoop; int wsFlags = pLoop->wsFlags; int viaCoroutine = 0; if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){ zObj = pLoop->u.btree.pIndex->zName; }else{ zObj = pSrclist->a[pLvl->iFrom].zName; viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine; } sqlite3VdbeScanStatus( v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj ); if( viaCoroutine==0 ){ if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){ sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur); } if( wsFlags & WHERE_INDEXED ){ sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur); } }else{ int addr = pSrclist->a[pLvl->iFrom].addrFillSub; VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine ); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr ); sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1); } } } #endif /* ** Disable a term in the WHERE clause. Except, do not disable the term ** if it controls a LEFT OUTER JOIN and it did not originate in the ON ** or USING clause of that join. ** ** Consider the term t2.z='ok' in the following queries: ** ** (1) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok' ** (2) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok' ** (3) SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok' ** ** The t2.z='ok' is disabled in the in (2) because it originates ** in the ON clause. The term is disabled in (3) because it is not part ** of a LEFT OUTER JOIN. In (1), the term is not disabled. ** ** Disabling a term causes that term to not be tested in the inner loop ** of the join. Disabling is an optimization. When terms are satisfied ** by indices, we disable them to prevent redundant tests in the inner ** loop. We would get the correct results if nothing were ever disabled, ** but joins might run a little slower. The trick is to disable as much ** as we can without disabling too much. If we disabled in (1), we'd get ** the wrong answer. See ticket #813. ** ** If all the children of a term are disabled, then that term is also ** automatically disabled. In this way, terms get disabled if derived ** virtual terms are tested first. For example: ** ** x GLOB 'abc*' AND x>='abc' AND x<'acd' ** \___________/ \______/ \_____/ ** parent child1 child2 ** ** Only the parent term was in the original WHERE clause. The child1 ** and child2 terms were added by the LIKE optimization. If both of ** the virtual child terms are valid, then testing of the parent can be ** skipped. ** ** Usually the parent term is marked as TERM_CODED. But if the parent ** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead. ** The TERM_LIKECOND marking indicates that the term should be coded inside ** a conditional such that is only evaluated on the second pass of a ** LIKE-optimization loop, when scanning BLOBs instead of strings. */ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ int nLoop = 0; assert( pTerm!=0 ); while( (pTerm->wtFlags & TERM_CODED)==0 && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_OuterON)) && (pLevel->notReady & pTerm->prereqAll)==0 ){ if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){ pTerm->wtFlags |= TERM_LIKECOND; }else{ pTerm->wtFlags |= TERM_CODED; } #ifdef WHERETRACE_ENABLED if( (sqlite3WhereTrace & 0x4001)==0x4001 ){ sqlite3DebugPrintf("DISABLE-"); sqlite3WhereTermPrint(pTerm, (int)(pTerm - (pTerm->pWC->a))); } #endif if( pTerm->iParent<0 ) break; pTerm = &pTerm->pWC->a[pTerm->iParent]; assert( pTerm!=0 ); pTerm->nChild--; if( pTerm->nChild!=0 ) break; nLoop++; } } /* ** Code an OP_Affinity opcode to apply the column affinity string zAff ** to the n registers starting at base. ** ** As an optimization, SQLITE_AFF_BLOB and SQLITE_AFF_NONE entries (which ** are no-ops) at the beginning and end of zAff are ignored. If all entries ** in zAff are SQLITE_AFF_BLOB or SQLITE_AFF_NONE, then no code gets generated. ** ** This routine makes its own copy of zAff so that the caller is free ** to modify zAff after this routine returns. */ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ Vdbe *v = pParse->pVdbe; if( zAff==0 ){ assert( pParse->db->mallocFailed ); return; } assert( v!=0 ); /* Adjust base and n to skip over SQLITE_AFF_BLOB and SQLITE_AFF_NONE ** entries at the beginning and end of the affinity string. */ assert( SQLITE_AFF_NONE0 && zAff[0]<=SQLITE_AFF_BLOB ){ n--; base++; zAff++; } while( n>1 && zAff[n-1]<=SQLITE_AFF_BLOB ){ n--; } /* Code the OP_Affinity opcode if there is anything left to do. */ if( n>0 ){ sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); } } /* ** Expression pRight, which is the RHS of a comparison operation, is ** either a vector of n elements or, if n==1, a scalar expression. ** Before the comparison operation, affinity zAff is to be applied ** to the pRight values. This function modifies characters within the ** affinity string to SQLITE_AFF_BLOB if either: ** ** * the comparison will be performed with no affinity, or ** * the affinity change in zAff is guaranteed not to change the value. */ static void updateRangeAffinityStr( Expr *pRight, /* RHS of comparison */ int n, /* Number of vector elements in comparison */ char *zAff /* Affinity string to modify */ ){ int i; for(i=0; idb; Select *pSelect; /* Pointer to the SELECT on the RHS */ Expr *pNew; pNew = sqlite3ExprDup(db, pX, 0); if( db->mallocFailed==0 ){ for(pSelect=pNew->x.pSelect; pSelect; pSelect=pSelect->pPrior){ ExprList *pOrigRhs; /* Original unmodified RHS */ ExprList *pOrigLhs = 0; /* Original unmodified LHS */ ExprList *pRhs = 0; /* New RHS after modifications */ ExprList *pLhs = 0; /* New LHS after mods */ int i; /* Loop counter */ assert( ExprUseXSelect(pNew) ); pOrigRhs = pSelect->pEList; assert( pNew->pLeft!=0 ); assert( ExprUseXList(pNew->pLeft) ); if( pSelect==pNew->x.pSelect ){ pOrigLhs = pNew->pLeft->x.pList; } for(i=iEq; inLTerm; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ int iField; assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 ); iField = pLoop->aLTerm[i]->u.x.iField - 1; if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */ pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); pOrigRhs->a[iField].pExpr = 0; if( pOrigLhs ){ assert( pOrigLhs->a[iField].pExpr!=0 ); pLhs = sqlite3ExprListAppend(pParse,pLhs,pOrigLhs->a[iField].pExpr); pOrigLhs->a[iField].pExpr = 0; } } } sqlite3ExprListDelete(db, pOrigRhs); if( pOrigLhs ){ sqlite3ExprListDelete(db, pOrigLhs); pNew->pLeft->x.pList = pLhs; } pSelect->pEList = pRhs; if( pLhs && pLhs->nExpr==1 ){ /* Take care here not to generate a TK_VECTOR containing only a ** single value. Since the parser never creates such a vector, some ** of the subroutines do not handle this case. */ Expr *p = pLhs->a[0].pExpr; pLhs->a[0].pExpr = 0; sqlite3ExprDelete(db, pNew->pLeft); pNew->pLeft = p; } if( pSelect->pOrderBy ){ /* If the SELECT statement has an ORDER BY clause, zero the ** iOrderByCol variables. These are set to non-zero when an ** ORDER BY term exactly matches one of the terms of the ** result-set. Since the result-set of the SELECT statement may ** have been modified or reordered, these variables are no longer ** set correctly. Since setting them is just an optimization, ** it's easiest just to zero them here. */ ExprList *pOrderBy = pSelect->pOrderBy; for(i=0; inExpr; i++){ pOrderBy->a[i].u.x.iOrderByCol = 0; } } #if 0 printf("For indexing, change the IN expr:\n"); sqlite3TreeViewExpr(0, pX, 0); printf("Into:\n"); sqlite3TreeViewExpr(0, pNew, 0); #endif } } return pNew; } /* ** Generate code for a single equality term of the WHERE clause. An equality ** term can be either X=expr or X IN (...). pTerm is the term to be ** coded. ** ** The current value for the constraint is left in a register, the index ** of which is returned. An attempt is made store the result in iTarget but ** this is only guaranteed for TK_ISNULL and TK_IN constraints. If the ** constraint is a TK_EQ or TK_IS, then the current value might be left in ** some other register and it is the caller's responsibility to compensate. ** ** For a constraint of the form X=expr, the expression is evaluated in ** straight-line code. For constraints of the form X IN (...) ** this routine sets up a loop that will iterate over all values of X. */ static int codeEqualityTerm( Parse *pParse, /* The parsing context */ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ WhereLevel *pLevel, /* The level of the FROM clause we are working on */ int iEq, /* Index of the equality term within this level */ int bRev, /* True for reverse-order IN operations */ int iTarget /* Attempt to leave results in this register */ ){ Expr *pX = pTerm->pExpr; Vdbe *v = pParse->pVdbe; int iReg; /* Register holding results */ assert( pLevel->pWLoop->aLTerm[iEq]==pTerm ); assert( iTarget>0 ); if( pX->op==TK_EQ || pX->op==TK_IS ){ iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); }else if( pX->op==TK_ISNULL ){ iReg = iTarget; sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); #ifndef SQLITE_OMIT_SUBQUERY }else{ int eType = IN_INDEX_NOOP; int iTab; struct InLoop *pIn; WhereLoop *pLoop = pLevel->pWLoop; int i; int nEq = 0; int *aiMap = 0; if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 && pLoop->u.btree.pIndex->aSortOrder[iEq] ){ testcase( iEq==0 ); testcase( bRev ); bRev = !bRev; } assert( pX->op==TK_IN ); iReg = iTarget; for(i=0; iaLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){ disableTerm(pLevel, pTerm); return iTarget; } } for(i=iEq;inLTerm; i++){ assert( pLoop->aLTerm[i]!=0 ); if( pLoop->aLTerm[i]->pExpr==pX ) nEq++; } iTab = 0; if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab); }else{ Expr *pExpr = pTerm->pExpr; if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){ sqlite3 *db = pParse->db; pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX); if( !db->mallocFailed ){ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq); eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab); pExpr->iTable = iTab; } sqlite3ExprDelete(db, pX); }else{ int n = sqlite3ExprVectorSize(pX->pLeft); aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n)); eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab); } pX = pExpr; } if( eType==IN_INDEX_INDEX_DESC ){ testcase( bRev ); bRev = !bRev; } sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); VdbeCoverageIf(v, bRev); VdbeCoverageIf(v, !bRev); assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); pLoop->wsFlags |= WHERE_IN_ABLE; if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); } if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){ pLoop->wsFlags |= WHERE_IN_EARLYOUT; } i = pLevel->u.in.nIn; pLevel->u.in.nIn += nEq; pLevel->u.in.aInLoop = sqlite3WhereRealloc(pTerm->pWC->pWInfo, pLevel->u.in.aInLoop, sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn); pIn = pLevel->u.in.aInLoop; if( pIn ){ int iMap = 0; /* Index in aiMap[] */ pIn += i; for(i=iEq;inLTerm; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ int iOut = iReg + i - iEq; if( eType==IN_INDEX_ROWID ){ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut); }else{ int iCol = aiMap ? aiMap[iMap++] : 0; pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut); } sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v); if( i==iEq ){ pIn->iCur = iTab; pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next; if( iEq>0 ){ pIn->iBase = iReg - i; pIn->nPrefix = i; }else{ pIn->nPrefix = 0; } }else{ pIn->eEndLoopOp = OP_Noop; } pIn++; } } testcase( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 && (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ); if( iEq>0 && (pLoop->wsFlags & (WHERE_IN_SEEKSCAN|WHERE_VIRTUALTABLE))==0 ){ sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq); } }else{ pLevel->u.in.nIn = 0; } sqlite3DbFree(pParse->db, aiMap); #endif } /* As an optimization, try to disable the WHERE clause term that is ** driving the index as it will always be true. The correct answer is ** obtained regardless, but we might get the answer with fewer CPU cycles ** by omitting the term. ** ** But do not disable the term unless we are certain that the term is ** not a transitive constraint. For an example of where that does not ** work, see https://sqlite.org/forum/forumpost/eb8613976a (2021-05-04) */ if( (pLevel->pWLoop->wsFlags & WHERE_TRANSCONS)==0 || (pTerm->eOperator & WO_EQUIV)==0 ){ disableTerm(pLevel, pTerm); } return iReg; } /* ** Generate code that will evaluate all == and IN constraints for an ** index scan. ** ** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c). ** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10 ** The index has as many as three equality constraints, but in this ** example, the third "c" value is an inequality. So only two ** constraints are coded. This routine will generate code to evaluate ** a==5 and b IN (1,2,3). The current values for a and b will be stored ** in consecutive registers and the index of the first register is returned. ** ** In the example above nEq==2. But this subroutine works for any value ** of nEq including 0. If nEq==0, this routine is nearly a no-op. ** The only thing it does is allocate the pLevel->iMem memory cell and ** compute the affinity string. ** ** The nExtraReg parameter is 0 or 1. It is 0 if all WHERE clause constraints ** are == or IN and are covered by the nEq. nExtraReg is 1 if there is ** an inequality constraint (such as the "c>=5 AND c<10" in the example) that ** occurs after the nEq quality constraints. ** ** This routine allocates a range of nEq+nExtraReg memory cells and returns ** the index of the first memory cell in that range. The code that ** calls this routine will use that memory range to store keys for ** start and termination conditions of the loop. ** key value of the loop. If one or more IN operators appear, then ** this routine allocates an additional nEq memory cells for internal ** use. ** ** Before returning, *pzAff is set to point to a buffer containing a ** copy of the column affinity string of the index allocated using ** sqlite3DbMalloc(). Except, entries in the copy of the string associated ** with equality constraints that use BLOB or NONE affinity are set to ** SQLITE_AFF_BLOB. This is to deal with SQL such as the following: ** ** CREATE TABLE t1(a TEXT PRIMARY KEY, b); ** SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b; ** ** In the example above, the index on t1(a) has TEXT affinity. But since ** the right hand side of the equality constraint (t2.b) has BLOB/NONE affinity, ** no conversion should be attempted before using a t2.b value as part of ** a key to search the index. Hence the first byte in the returned affinity ** string in this example would be set to SQLITE_AFF_BLOB. */ static int codeAllEqualityTerms( Parse *pParse, /* Parsing context */ WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ int bRev, /* Reverse the order of IN operators */ int nExtraReg, /* Number of extra registers to allocate */ char **pzAff /* OUT: Set to point to affinity string */ ){ u16 nEq; /* The number of == or IN constraints to code */ u16 nSkip; /* Number of left-most columns to skip */ Vdbe *v = pParse->pVdbe; /* The vm under construction */ Index *pIdx; /* The index being used for this loop */ WhereTerm *pTerm; /* A single constraint term */ WhereLoop *pLoop; /* The WhereLoop object */ int j; /* Loop counter */ int regBase; /* Base register */ int nReg; /* Number of registers to allocate */ char *zAff; /* Affinity string to return */ /* This module is only called on query plans that use an index. */ pLoop = pLevel->pWLoop; assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); nEq = pLoop->u.btree.nEq; nSkip = pLoop->nSkip; pIdx = pLoop->u.btree.pIndex; assert( pIdx!=0 ); /* Figure out how many memory cells we will need then allocate them. */ regBase = pParse->nMem + 1; nReg = nEq + nExtraReg; pParse->nMem += nReg; zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx)); assert( zAff!=0 || pParse->db->mallocFailed ); if( nSkip ){ int iIdxCur = pLevel->iIdxCur; sqlite3VdbeAddOp3(v, OP_Null, 0, regBase, regBase+nSkip-1); sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); VdbeComment((v, "begin skip-scan on %s", pIdx->zName)); j = sqlite3VdbeAddOp0(v, OP_Goto); assert( pLevel->addrSkip==0 ); pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT), iIdxCur, 0, regBase, nSkip); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); sqlite3VdbeJumpHere(v, j); for(j=0; jaiColumn[j]==XN_EXPR ); VdbeComment((v, "%s", explainIndexColumnName(pIdx, j))); } } /* Evaluate the equality constraints */ assert( zAff==0 || (int)strlen(zAff)>=nEq ); for(j=nSkip; jaLTerm[j]; assert( pTerm!=0 ); /* The following testcase is true for indices with redundant columns. ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j); if( r1!=regBase+j ){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, regBase); regBase = r1; }else{ sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j); } } if( pTerm->eOperator & WO_IN ){ if( pTerm->pExpr->flags & EP_xIsSelect ){ /* No affinity ever needs to be (or should be) applied to a value ** from the RHS of an "? IN (SELECT ...)" expression. The ** sqlite3FindInIndex() routine has already ensured that the ** affinity of the comparison has been applied to the value. */ if( zAff ) zAff[j] = SQLITE_AFF_BLOB; } }else if( (pTerm->eOperator & WO_ISNULL)==0 ){ Expr *pRight = pTerm->pExpr->pRight; if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); VdbeCoverage(v); } if( pParse->nErr==0 ){ assert( pParse->db->mallocFailed==0 ); if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){ zAff[j] = SQLITE_AFF_BLOB; } if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){ zAff[j] = SQLITE_AFF_BLOB; } } } } *pzAff = zAff; return regBase; } #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS /* ** If the most recently coded instruction is a constant range constraint ** (a string literal) that originated from the LIKE optimization, then ** set P3 and P5 on the OP_String opcode so that the string will be cast ** to a BLOB at appropriate times. ** ** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range ** expression: "x>='ABC' AND x<'abd'". But this requires that the range ** scan loop run twice, once for strings and a second time for BLOBs. ** The OP_String opcodes on the second pass convert the upper and lower ** bound string constants to blobs. This routine makes the necessary changes ** to the OP_String opcodes for that to happen. ** ** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then ** only the one pass through the string space is required, so this routine ** becomes a no-op. */ static void whereLikeOptimizationStringFixup( Vdbe *v, /* prepared statement under construction */ WhereLevel *pLevel, /* The loop that contains the LIKE operator */ WhereTerm *pTerm /* The upper or lower bound just coded */ ){ if( pTerm->wtFlags & TERM_LIKEOPT ){ VdbeOp *pOp; assert( pLevel->iLikeRepCntr>0 ); pOp = sqlite3VdbeGetLastOp(v); assert( pOp!=0 ); assert( pOp->opcode==OP_String8 || pTerm->pWC->pWInfo->pParse->db->mallocFailed ); pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */ pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */ } } #else # define whereLikeOptimizationStringFixup(A,B,C) #endif #ifdef SQLITE_ENABLE_CURSOR_HINTS /* ** Information is passed from codeCursorHint() down to individual nodes of ** the expression tree (by sqlite3WalkExpr()) using an instance of this ** structure. */ struct CCurHint { int iTabCur; /* Cursor for the main table */ int iIdxCur; /* Cursor for the index, if pIdx!=0. Unused otherwise */ Index *pIdx; /* The index used to access the table */ }; /* ** This function is called for every node of an expression that is a candidate ** for a cursor hint on an index cursor. For TK_COLUMN nodes that reference ** the table CCurHint.iTabCur, verify that the same column can be ** accessed through the index. If it cannot, then set pWalker->eCode to 1. */ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ struct CCurHint *pHint = pWalker->u.pCCurHint; assert( pHint->pIdx!=0 ); if( pExpr->op==TK_COLUMN && pExpr->iTable==pHint->iTabCur && sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; } return WRC_Continue; } /* ** Test whether or not expression pExpr, which was part of a WHERE clause, ** should be included in the cursor-hint for a table that is on the rhs ** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the ** expression is not suitable. ** ** An expression is unsuitable if it might evaluate to non NULL even if ** a TK_COLUMN node that does affect the value of the expression is set ** to NULL. For example: ** ** col IS NULL ** col IS NOT NULL ** coalesce(col, 1) ** CASE WHEN col THEN 0 ELSE 1 END */ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_IS || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE ){ pWalker->eCode = 1; }else if( pExpr->op==TK_FUNCTION ){ int d1; char d2[4]; if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){ pWalker->eCode = 1; } } return WRC_Continue; } /* ** This function is called on every node of an expression tree used as an ** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN ** that accesses any table other than the one identified by ** CCurHint.iTabCur, then do the following: ** ** 1) allocate a register and code an OP_Column instruction to read ** the specified column into the new register, and ** ** 2) transform the expression node to a TK_REGISTER node that reads ** from the newly populated register. ** ** Also, if the node is a TK_COLUMN that does access the table identified ** by pCCurHint.iTabCur, and an index is being used (which we will ** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into ** an access of the index rather than the original table. */ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ int rc = WRC_Continue; int reg; struct CCurHint *pHint = pWalker->u.pCCurHint; if( pExpr->op==TK_COLUMN ){ if( pExpr->iTable!=pHint->iTabCur ){ reg = ++pWalker->pParse->nMem; /* Register for column value */ reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg); pExpr->op = TK_REGISTER; pExpr->iTable = reg; }else if( pHint->pIdx!=0 ){ pExpr->iTable = pHint->iIdxCur; pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn); assert( pExpr->iColumn>=0 ); } }else if( pExpr->pAggInfo ){ rc = WRC_Prune; reg = ++pWalker->pParse->nMem; /* Register for column value */ reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg); pExpr->op = TK_REGISTER; pExpr->iTable = reg; }else if( pExpr->op==TK_TRUEFALSE ){ /* Do not walk disabled expressions. tag-20230504-1 */ return WRC_Prune; } return rc; } /* ** Insert an OP_CursorHint instruction if it is appropriate to do so. */ static void codeCursorHint( SrcItem *pTabItem, /* FROM clause item */ WhereInfo *pWInfo, /* The where clause */ WhereLevel *pLevel, /* Which loop to provide hints for */ WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */ ){ Parse *pParse = pWInfo->pParse; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; Expr *pExpr = 0; WhereLoop *pLoop = pLevel->pWLoop; int iCur; WhereClause *pWC; WhereTerm *pTerm; int i, j; struct CCurHint sHint; Walker sWalker; if( OptimizationDisabled(db, SQLITE_CursorHints) ) return; iCur = pLevel->iTabCur; assert( iCur==pWInfo->pTabList->a[pLevel->iFrom].iCursor ); sHint.iTabCur = iCur; sHint.iIdxCur = pLevel->iIdxCur; sHint.pIdx = pLoop->u.btree.pIndex; memset(&sWalker, 0, sizeof(sWalker)); sWalker.pParse = pParse; sWalker.u.pCCurHint = &sHint; pWC = &pWInfo->sWC; for(i=0; inBase; i++){ pTerm = &pWC->a[i]; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->prereqAll & pLevel->notReady ) continue; /* Any terms specified as part of the ON(...) clause for any LEFT ** JOIN for which the current table is not the rhs are omitted ** from the cursor-hint. ** ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms ** that were specified as part of the WHERE clause must be excluded. ** This is to address the following: ** ** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL; ** ** Say there is a single row in t2 that matches (t1.a=t2.b), but its ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is ** pushed down to the cursor, this row is filtered out, causing ** SQLite to synthesize a row of NULL values. Which does match the ** WHERE clause, and so the query returns a row. Which is incorrect. ** ** For the same reason, WHERE terms such as: ** ** WHERE 1 = (t2.c IS NULL) ** ** are also excluded. See codeCursorHintIsOrFunction() for details. */ if( pTabItem->fg.jointype & JT_LEFT ){ Expr *pExpr = pTerm->pExpr; if( !ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin!=pTabItem->iCursor ){ sWalker.eCode = 0; sWalker.xExprCallback = codeCursorHintIsOrFunction; sqlite3WalkExpr(&sWalker, pTerm->pExpr); if( sWalker.eCode ) continue; } }else{ if( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) continue; } /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize ** the cursor. These terms are not needed as hints for a pure range ** scan (that has no == terms) so omit them. */ if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){ for(j=0; jnLTerm && pLoop->aLTerm[j]!=pTerm; j++){} if( jnLTerm ) continue; } /* No subqueries or non-deterministic functions allowed */ if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue; /* For an index scan, make sure referenced columns are actually in ** the index. */ if( sHint.pIdx!=0 ){ sWalker.eCode = 0; sWalker.xExprCallback = codeCursorHintCheckExpr; sqlite3WalkExpr(&sWalker, pTerm->pExpr); if( sWalker.eCode ) continue; } /* If we survive all prior tests, that means this term is worth hinting */ pExpr = sqlite3ExprAnd(pParse, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); } if( pExpr!=0 ){ sWalker.xExprCallback = codeCursorHintFixExpr; if( pParse->nErr==0 ) sqlite3WalkExpr(&sWalker, pExpr); sqlite3VdbeAddOp4(v, OP_CursorHint, (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0, (const char*)pExpr, P4_EXPR); } } #else # define codeCursorHint(A,B,C,D) /* No-op */ #endif /* SQLITE_ENABLE_CURSOR_HINTS */ /* ** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains ** a rowid value just read from cursor iIdxCur, open on index pIdx. This ** function generates code to do a deferred seek of cursor iCur to the ** rowid stored in register iRowid. ** ** Normally, this is just: ** ** OP_DeferredSeek $iCur $iRowid ** ** Which causes a seek on $iCur to the row with rowid $iRowid. ** ** However, if the scan currently being coded is a branch of an OR-loop and ** the statement currently being coded is a SELECT, then additional information ** is added that might allow OP_Column to omit the seek and instead do its ** lookup on the index, thus avoiding an expensive seek operation. To ** enable this optimization, the P3 of OP_DeferredSeek is set to iIdxCur ** and P4 is set to an array of integers containing one entry for each column ** in the table. For each table column, if the column is the i'th ** column of the index, then the corresponding array entry is set to (i+1). ** If the column does not appear in the index at all, the array entry is set ** to 0. The OP_Column opcode can check this array to see if the column it ** wants is in the index and if it is, it will substitute the index cursor ** and column number and continue with those new values, rather than seeking ** the table cursor. */ static void codeDeferredSeek( WhereInfo *pWInfo, /* Where clause context */ Index *pIdx, /* Index scan is using */ int iCur, /* Cursor for IPK b-tree */ int iIdxCur /* Index cursor */ ){ Parse *pParse = pWInfo->pParse; /* Parse context */ Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */ assert( iIdxCur>0 ); assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); pWInfo->bDeferredSeek = 1; sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur); if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN)) && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) ){ int i; Table *pTab = pIdx->pTable; u32 *ai = (u32*)sqlite3DbMallocZero(pParse->db, sizeof(u32)*(pTab->nCol+1)); if( ai ){ ai[0] = pTab->nCol; for(i=0; inColumn-1; i++){ int x1, x2; assert( pIdx->aiColumn[i]nCol ); x1 = pIdx->aiColumn[i]; x2 = sqlite3TableColumnToStorage(pTab, x1); testcase( x1!=x2 ); if( x1>=0 ) ai[x2+1] = i+1; } sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY); } } } /* ** If the expression passed as the second argument is a vector, generate ** code to write the first nReg elements of the vector into an array ** of registers starting with iReg. ** ** If the expression is not a vector, then nReg must be passed 1. In ** this case, generate code to evaluate the expression and leave the ** result in register iReg. */ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ assert( nReg>0 ); if( p && sqlite3ExprIsVector(p) ){ #ifndef SQLITE_OMIT_SUBQUERY if( ExprUseXSelect(p) ){ Vdbe *v = pParse->pVdbe; int iSelect; assert( p->op==TK_SELECT ); iSelect = sqlite3CodeSubselect(pParse, p); sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1); }else #endif { int i; const ExprList *pList; assert( ExprUseXList(p) ); pList = p->x.pList; assert( nReg<=pList->nExpr ); for(i=0; ia[i].pExpr, iReg+i); } } }else{ assert( nReg==1 || pParse->nErr ); sqlite3ExprCode(pParse, p, iReg); } } /* ** The pTruth expression is always true because it is the WHERE clause ** a partial index that is driving a query loop. Look through all of the ** WHERE clause terms on the query, and if any of those terms must be ** true because pTruth is true, then mark those WHERE clause terms as ** coded. */ static void whereApplyPartialIndexConstraints( Expr *pTruth, int iTabCur, WhereClause *pWC ){ int i; WhereTerm *pTerm; while( pTruth->op==TK_AND ){ whereApplyPartialIndexConstraints(pTruth->pLeft, iTabCur, pWC); pTruth = pTruth->pRight; } for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ Expr *pExpr; if( pTerm->wtFlags & TERM_CODED ) continue; pExpr = pTerm->pExpr; if( sqlite3ExprCompare(0, pExpr, pTruth, iTabCur)==0 ){ pTerm->wtFlags |= TERM_CODED; } } } /* ** This routine is called right after An OP_Filter has been generated and ** before the corresponding index search has been performed. This routine ** checks to see if there are additional Bloom filters in inner loops that ** can be checked prior to doing the index lookup. If there are available ** inner-loop Bloom filters, then evaluate those filters now, before the ** index lookup. The idea is that a Bloom filter check is way faster than ** an index lookup, and the Bloom filter might return false, meaning that ** the index lookup can be skipped. ** ** We know that an inner loop uses a Bloom filter because it has the ** WhereLevel.regFilter set. If an inner-loop Bloom filter is checked, ** then clear the WhereLevel.regFilter value to prevent the Bloom filter ** from being checked a second time when the inner loop is evaluated. */ static SQLITE_NOINLINE void filterPullDown( Parse *pParse, /* Parsing context */ WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ int addrNxt, /* Jump here to bypass inner loops */ Bitmask notReady /* Loops that are not ready */ ){ while( ++iLevel < pWInfo->nLevel ){ WhereLevel *pLevel = &pWInfo->a[iLevel]; WhereLoop *pLoop = pLevel->pWLoop; if( pLevel->regFilter==0 ) continue; if( pLevel->pWLoop->nSkip ) continue; /* ,--- Because sqlite3ConstructBloomFilter() has will not have set ** vvvvv--' pLevel->regFilter if this were true. */ if( NEVER(pLoop->prereq & notReady) ) continue; assert( pLevel->addrBrk==0 ); pLevel->addrBrk = addrNxt; if( pLoop->wsFlags & WHERE_IPK ){ WhereTerm *pTerm = pLoop->aLTerm[0]; int regRowid; assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); regRowid = sqlite3GetTempReg(pParse); regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid); sqlite3VdbeAddOp2(pParse->pVdbe, OP_MustBeInt, regRowid, addrNxt); VdbeCoverage(pParse->pVdbe); sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter, addrNxt, regRowid, 1); VdbeCoverage(pParse->pVdbe); }else{ u16 nEq = pLoop->u.btree.nEq; int r1; char *zStartAff; assert( pLoop->wsFlags & WHERE_INDEXED ); assert( (pLoop->wsFlags & WHERE_COLUMN_IN)==0 ); r1 = codeAllEqualityTerms(pParse,pLevel,0,0,&zStartAff); codeApplyAffinity(pParse, r1, nEq, zStartAff); sqlite3DbFree(pParse->db, zStartAff); sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter, addrNxt, r1, nEq); VdbeCoverage(pParse->pVdbe); } pLevel->regFilter = 0; pLevel->addrBrk = 0; } } /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( Parse *pParse, /* Parsing context */ Vdbe *v, /* Prepared statement under construction */ WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ WhereLevel *pLevel, /* The current level pointer */ Bitmask notReady /* Which tables are currently available */ ){ int j, k; /* Loop counters */ int iCur; /* The VDBE cursor for the table */ int addrNxt; /* Where to jump to continue with the next IN case */ int bRev; /* True if we need to scan in reverse order */ WhereLoop *pLoop; /* The WhereLoop object being coded */ WhereClause *pWC; /* Decomposition of the entire WHERE clause */ WhereTerm *pTerm; /* A WHERE clause term */ sqlite3 *db; /* Database connection */ SrcItem *pTabItem; /* FROM clause term being coded */ int addrBrk; /* Jump here to break out of the loop */ int addrHalt; /* addrBrk for the outermost loop */ int addrCont; /* Jump here to continue with next cycle */ int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ int iReleaseReg = 0; /* Temp register to free before returning */ Index *pIdx = 0; /* Index used by loop (if any) */ int iLoop; /* Iteration of constraint generator loop */ pWC = &pWInfo->sWC; db = pParse->db; pLoop = pLevel->pWLoop; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); #if WHERETRACE_ENABLED /* 0x4001 */ if( sqlite3WhereTrace & 0x1 ){ sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n", iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom); if( sqlite3WhereTrace & 0x1000 ){ sqlite3WhereLoopPrint(pLoop, pWC); } } if( (sqlite3WhereTrace & 0x4001)==0x4001 ){ if( iLevel==0 ){ sqlite3DebugPrintf("WHERE clause being coded:\n"); sqlite3TreeViewExpr(0, pWInfo->pWhere, 0); } sqlite3DebugPrintf("All WHERE-clause terms before coding:\n"); sqlite3WhereClausePrint(pWC); } #endif /* Create labels for the "break" and "continue" instructions ** for the current loop. Jump to addrBrk to break out of a loop. ** Jump to cont to go immediately to the next iteration of the ** loop. ** ** When there is an IN operator, we also have a "addrNxt" label that ** means to continue with the next IN value combination. When ** there are no IN operators in the constraints, the "addrNxt" label ** is the same as "addrBrk". */ addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(pParse); /* If this is the right table of a LEFT OUTER JOIN, allocate and ** initialize a memory cell that records if this table matches any ** row of the left table of the join. */ assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN)) || pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0 ); if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){ pLevel->iLeftJoin = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); VdbeComment((v, "init LEFT JOIN no-match flag")); } /* Compute a safe address to jump to if we discover that the table for ** this loop is empty and can never contribute content. */ for(j=iLevel; j>0; j--){ if( pWInfo->a[j].iLeftJoin ) break; if( pWInfo->a[j].pRJ ) break; } addrHalt = pWInfo->a[j].addrBrk; /* Special case of a FROM clause subquery implemented as a co-routine */ if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); VdbeCoverage(v); VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); pLevel->op = OP_Goto; }else #ifndef SQLITE_OMIT_VIRTUALTABLE if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ /* Case 1: The table is a virtual-table. Use the VFilter and VNext ** to access the data. */ int iReg; /* P3 Value for OP_VFilter */ int addrNotFound; int nConstraint = pLoop->nLTerm; iReg = sqlite3GetTempRange(pParse, nConstraint+2); addrNotFound = pLevel->addrBrk; for(j=0; jaLTerm[j]; if( NEVER(pTerm==0) ) continue; if( pTerm->eOperator & WO_IN ){ if( SMASKBIT32(j) & pLoop->u.vtab.mHandleIn ){ int iTab = pParse->nTab++; int iCache = ++pParse->nMem; sqlite3CodeRhsOfIN(pParse, pTerm->pExpr, iTab); sqlite3VdbeAddOp3(v, OP_VInitIn, iTab, iTarget, iCache); }else{ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); addrNotFound = pLevel->addrNxt; } }else{ Expr *pRight = pTerm->pExpr->pRight; codeExprOrVector(pParse, pRight, iTarget, 1); if( pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET && pLoop->u.vtab.bOmitOffset ){ assert( pTerm->eOperator==WO_AUX ); assert( pWInfo->pSelect!=0 ); assert( pWInfo->pSelect->iOffset>0 ); sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pSelect->iOffset); VdbeComment((v,"Zero OFFSET counter")); } } } sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pLoop->u.vtab.idxStr, pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); VdbeCoverage(v); pLoop->u.vtab.needFree = 0; /* An OOM inside of AddOp4(OP_VFilter) instruction above might have freed ** the u.vtab.idxStr. NULL it out to prevent a use-after-free */ if( db->mallocFailed ) pLoop->u.vtab.idxStr = 0; pLevel->p1 = iCur; pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext; pLevel->p2 = sqlite3VdbeCurrentAddr(v); assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); for(j=0; jaLTerm[j]; if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){ disableTerm(pLevel, pTerm); continue; } if( (pTerm->eOperator & WO_IN)!=0 && (SMASKBIT32(j) & pLoop->u.vtab.mHandleIn)==0 && !db->mallocFailed ){ Expr *pCompare; /* The comparison operator */ Expr *pRight; /* RHS of the comparison */ VdbeOp *pOp; /* Opcode to access the value of the IN constraint */ int iIn; /* IN loop corresponding to the j-th constraint */ /* Reload the constraint value into reg[iReg+j+2]. The same value ** was loaded into the same register prior to the OP_VFilter, but ** the xFilter implementation might have changed the datatype or ** encoding of the value in the register, so it *must* be reloaded. */ for(iIn=0; ALWAYS(iInu.in.nIn); iIn++){ pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[iIn].addrInTop); if( (pOp->opcode==OP_Column && pOp->p3==iReg+j+2) || (pOp->opcode==OP_Rowid && pOp->p2==iReg+j+2) ){ testcase( pOp->opcode==OP_Rowid ); sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3); break; } } /* Generate code that will continue to the next row if ** the IN constraint is not satisfied */ pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0); if( !db->mallocFailed ){ int iFld = pTerm->u.x.iField; Expr *pLeft = pTerm->pExpr->pLeft; assert( pLeft!=0 ); if( iFld>0 ){ assert( pLeft->op==TK_VECTOR ); assert( ExprUseXList(pLeft) ); assert( iFld<=pLeft->x.pList->nExpr ); pCompare->pLeft = pLeft->x.pList->a[iFld-1].pExpr; }else{ pCompare->pLeft = pLeft; } pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0); if( pRight ){ pRight->iTable = iReg+j+2; sqlite3ExprIfFalse( pParse, pCompare, pLevel->addrCont, SQLITE_JUMPIFNULL ); } pCompare->pLeft = 0; } sqlite3ExprDelete(db, pCompare); } } /* These registers need to be preserved in case there is an IN operator ** loop. So we could deallocate the registers here (and potentially ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems ** simpler and safer to simply not reuse the registers. ** ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); */ }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0 ){ /* Case 2: We can directly reference a single row using an ** equality comparison against the ROWID field. Or ** we reference multiple rows using a "rowid IN (...)" ** construct. */ assert( pLoop->u.btree.nEq==1 ); pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; if( pLevel->regFilter ){ sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v); sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt, iRowidReg, 1); VdbeCoverage(v); filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady); } sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); VdbeCoverage(v); pLevel->op = OP_Noop; }else if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 ){ /* Case 3: We have an inequality comparison against the ROWID field. */ int testOp = OP_Noop; int start; int memEndValue = 0; WhereTerm *pStart, *pEnd; j = 0; pStart = pEnd = 0; if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++]; if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; assert( pStart!=0 || pEnd!=0 ); if( bRev ){ pTerm = pStart; pStart = pEnd; pEnd = pTerm; } codeCursorHint(pTabItem, pWInfo, pLevel, pEnd); if( pStart ){ Expr *pX; /* The expression that defines the start bound */ int r1, rTemp; /* Registers for holding the start boundary */ int op; /* Cursor seek operation */ /* The following constant maps TK_xx codes into corresponding ** seek opcodes. It depends on a particular ordering of TK_xx */ const u8 aMoveOp[] = { /* TK_GT */ OP_SeekGT, /* TK_LE */ OP_SeekLE, /* TK_LT */ OP_SeekLT, /* TK_GE */ OP_SeekGE }; assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */ assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */ assert( TK_GE==TK_GT+3 ); /* ... is correct. */ assert( (pStart->wtFlags & TERM_VNULL)==0 ); testcase( pStart->wtFlags & TERM_VIRTUAL ); pX = pStart->pExpr; assert( pX!=0 ); testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ if( sqlite3ExprIsVector(pX->pRight) ){ r1 = rTemp = sqlite3GetTempReg(pParse); codeExprOrVector(pParse, pX->pRight, r1, 1); testcase( pX->op==TK_GT ); testcase( pX->op==TK_GE ); testcase( pX->op==TK_LT ); testcase( pX->op==TK_LE ); op = aMoveOp[((pX->op - TK_GT - 1) & 0x3) | 0x1]; assert( pX->op!=TK_GT || op==OP_SeekGE ); assert( pX->op!=TK_GE || op==OP_SeekGE ); assert( pX->op!=TK_LT || op==OP_SeekLE ); assert( pX->op!=TK_LE || op==OP_SeekLE ); }else{ r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); disableTerm(pLevel, pStart); op = aMoveOp[(pX->op - TK_GT)]; } sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1); VdbeComment((v, "pk")); VdbeCoverageIf(v, pX->op==TK_GT); VdbeCoverageIf(v, pX->op==TK_LE); VdbeCoverageIf(v, pX->op==TK_LT); VdbeCoverageIf(v, pX->op==TK_GE); sqlite3ReleaseTempReg(pParse, rTemp); }else{ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); } if( pEnd ){ Expr *pX; pX = pEnd->pExpr; assert( pX!=0 ); assert( (pEnd->wtFlags & TERM_VNULL)==0 ); testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */ testcase( pEnd->wtFlags & TERM_VIRTUAL ); memEndValue = ++pParse->nMem; codeExprOrVector(pParse, pX->pRight, memEndValue, 1); if( 0==sqlite3ExprIsVector(pX->pRight) && (pX->op==TK_LT || pX->op==TK_GT) ){ testOp = bRev ? OP_Le : OP_Ge; }else{ testOp = bRev ? OP_Lt : OP_Gt; } if( 0==sqlite3ExprIsVector(pX->pRight) ){ disableTerm(pLevel, pEnd); } } start = sqlite3VdbeCurrentAddr(v); pLevel->op = bRev ? OP_Prev : OP_Next; pLevel->p1 = iCur; pLevel->p2 = start; assert( pLevel->p5==0 ); if( testOp!=OP_Noop ){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); VdbeCoverageIf(v, testOp==OP_Le); VdbeCoverageIf(v, testOp==OP_Lt); VdbeCoverageIf(v, testOp==OP_Ge); VdbeCoverageIf(v, testOp==OP_Gt); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); } }else if( pLoop->wsFlags & WHERE_INDEXED ){ /* Case 4: A scan using an index. ** ** The WHERE clause may contain zero or more equality ** terms ("==" or "IN" operators) that refer to the N ** left-most columns of the index. It may also contain ** inequality constraints (>, <, >= or <=) on the indexed ** column that immediately follows the N equalities. Only ** the right-most column can be an inequality - the rest must ** use the "==" and "IN" operators. For example, if the ** index is on (x,y,z), then the following clauses are all ** optimized: ** ** x=5 ** x=5 AND y=10 ** x=5 AND y<10 ** x=5 AND y>5 AND y<10 ** x=5 AND y=5 AND z<=10 ** ** The z<10 term of the following cannot be used, only ** the x=5 term: ** ** x=5 AND z<10 ** ** N may be zero if there are inequality constraints. ** If there are no inequality constraints, then N is at ** least one. ** ** This case is also used when there are no WHERE clause ** constraints but an index is selected anyway, in order ** to force the output order to conform to an ORDER BY. */ static const u8 aStartOp[] = { 0, 0, OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */ OP_Last, /* 3: (!start_constraints && startEq && bRev) */ OP_SeekGT, /* 4: (start_constraints && !startEq && !bRev) */ OP_SeekLT, /* 5: (start_constraints && !startEq && bRev) */ OP_SeekGE, /* 6: (start_constraints && startEq && !bRev) */ OP_SeekLE /* 7: (start_constraints && startEq && bRev) */ }; static const u8 aEndOp[] = { OP_IdxGE, /* 0: (end_constraints && !bRev && !endEq) */ OP_IdxGT, /* 1: (end_constraints && !bRev && endEq) */ OP_IdxLE, /* 2: (end_constraints && bRev && !endEq) */ OP_IdxLT, /* 3: (end_constraints && bRev && endEq) */ }; u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */ u16 nBtm = pLoop->u.btree.nBtm; /* Length of BTM vector */ u16 nTop = pLoop->u.btree.nTop; /* Length of TOP vector */ int regBase; /* Base register holding constraint values */ WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */ WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */ int startEq; /* True if range start uses ==, >= or <= */ int endEq; /* True if range end uses ==, >= or <= */ int start_constraints; /* Start of range is constrained */ int nConstraint; /* Number of constraint terms */ int iIdxCur; /* The VDBE cursor for the index */ int nExtraReg = 0; /* Number of extra registers needed */ int op; /* Instruction opcode */ char *zStartAff; /* Affinity for start of range constraint */ char *zEndAff = 0; /* Affinity for end of range constraint */ u8 bSeekPastNull = 0; /* True to seek past initial nulls */ u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ int omitTable; /* True if we use the index only */ int regBignull = 0; /* big-null flag register */ int addrSeekScan = 0; /* Opcode of the OP_SeekScan, if any */ pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; assert( nEq>=pLoop->nSkip ); /* Find any inequality constraint terms for the start and end ** of the range. */ j = nEq; if( pLoop->wsFlags & WHERE_BTM_LIMIT ){ pRangeStart = pLoop->aLTerm[j++]; nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm); /* Like optimization range constraints always occur in pairs */ assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 || (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 ); } if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ pRangeEnd = pLoop->aLTerm[j++]; nExtraReg = MAX(nExtraReg, pLoop->u.btree.nTop); #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){ assert( pRangeStart!=0 ); /* LIKE opt constraints */ assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */ pLevel->iLikeRepCntr = (u32)++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr); VdbeComment((v, "LIKE loop counter")); pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v); /* iLikeRepCntr actually stores 2x the counter register number. The ** bottom bit indicates whether the search order is ASC or DESC. */ testcase( bRev ); testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); assert( (bRev & ~1)==0 ); pLevel->iLikeRepCntr <<=1; pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC); } #endif if( pRangeStart==0 ){ j = pIdx->aiColumn[nEq]; if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){ bSeekPastNull = 1; } } } assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); /* If the WHERE_BIGNULL_SORT flag is set, then index column nEq uses ** a non-default "big-null" sort (either ASC NULLS LAST or DESC NULLS ** FIRST). In both cases separate ordered scans are made of those ** index entries for which the column is null and for those for which ** it is not. For an ASC sort, the non-NULL entries are scanned first. ** For DESC, NULL entries are scanned first. */ if( (pLoop->wsFlags & (WHERE_TOP_LIMIT|WHERE_BTM_LIMIT))==0 && (pLoop->wsFlags & WHERE_BIGNULL_SORT)!=0 ){ assert( bSeekPastNull==0 && nExtraReg==0 && nBtm==0 && nTop==0 ); assert( pRangeEnd==0 && pRangeStart==0 ); testcase( pLoop->nSkip>0 ); nExtraReg = 1; bSeekPastNull = 1; pLevel->regBignull = regBignull = ++pParse->nMem; if( pLevel->iLeftJoin ){ sqlite3VdbeAddOp2(v, OP_Integer, 0, regBignull); } pLevel->addrBignull = sqlite3VdbeMakeLabel(pParse); } /* If we are doing a reverse order scan on an ascending index, or ** a forward order scan on a descending index, interchange the ** start and end terms (pRangeStart and pRangeEnd). */ if( (nEqnColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) ){ SWAP(WhereTerm *, pRangeEnd, pRangeStart); SWAP(u8, bSeekPastNull, bStopAtNull); SWAP(u8, nBtm, nTop); } if( iLevel>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 ){ /* In case OP_SeekScan is used, ensure that the index cursor does not ** point to a valid row for the first iteration of this loop. */ sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur); } /* Generate code to evaluate all constraint terms using == or IN ** and store the values of those terms in an array of registers ** starting at regBase. */ codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd); regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq ); if( zStartAff && nTop ){ zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]); } addrNxt = (regBignull ? pLevel->addrBignull : pLevel->addrNxt); testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 ); testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 ); startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE); endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE); start_constraints = pRangeStart || nEq>0; /* Seek the index cursor to the start of the range. */ nConstraint = nEq; if( pRangeStart ){ Expr *pRight = pRangeStart->pExpr->pRight; codeExprOrVector(pParse, pRight, regBase+nEq, nBtm); whereLikeOptimizationStringFixup(v, pLevel, pRangeStart); if( (pRangeStart->wtFlags & TERM_VNULL)==0 && sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); VdbeCoverage(v); } if( zStartAff ){ updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]); } nConstraint += nBtm; testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeStart); }else{ startEq = 1; } bSeekPastNull = 0; }else if( bSeekPastNull ){ startEq = 0; sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); start_constraints = 1; nConstraint++; }else if( regBignull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); start_constraints = 1; nConstraint++; } codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){ /* The skip-scan logic inside the call to codeAllEqualityConstraints() ** above has already left the cursor sitting on the correct row, ** so no further seeking is needed */ }else{ if( regBignull ){ sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull); VdbeComment((v, "NULL-scan pass ctr")); } if( pLevel->regFilter ){ sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt, regBase, nEq); VdbeCoverage(v); filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady); } op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; assert( op!=0 ); if( (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 && op==OP_SeekGE ){ assert( regBignull==0 ); /* TUNING: The OP_SeekScan opcode seeks to reduce the number ** of expensive seek operations by replacing a single seek with ** 1 or more step operations. The question is, how many steps ** should we try before giving up and going with a seek. The cost ** of a seek is proportional to the logarithm of the of the number ** of entries in the tree, so basing the number of steps to try ** on the estimated number of rows in the btree seems like a good ** guess. */ addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan, (pIdx->aiRowLogEst[0]+9)/10); if( pRangeStart || pRangeEnd ){ sqlite3VdbeChangeP5(v, 1); sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1); addrSeekScan = 0; } VdbeCoverage(v); } sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); VdbeCoverage(v); VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT ); VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); assert( bSeekPastNull==0 || bStopAtNull==0 ); if( regBignull ){ assert( bSeekPastNull==1 || bStopAtNull==1 ); assert( bSeekPastNull==!bStopAtNull ); assert( bStopAtNull==startEq ); sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2); op = aStartOp[(nConstraint>1)*4 + 2 + bRev]; sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint-startEq); VdbeCoverage(v); VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); assert( op==OP_Rewind || op==OP_Last || op==OP_SeekGE || op==OP_SeekLE); } } /* Load the value for the inequality constraint at the end of the ** range (if any). */ nConstraint = nEq; assert( pLevel->p2==0 ); if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; assert( addrSeekScan==0 ); codeExprOrVector(pParse, pRight, regBase+nEq, nTop); whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); if( (pRangeEnd->wtFlags & TERM_VNULL)==0 && sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); VdbeCoverage(v); } if( zEndAff ){ updateRangeAffinityStr(pRight, nTop, zEndAff); codeApplyAffinity(pParse, regBase+nEq, nTop, zEndAff); }else{ assert( pParse->db->mallocFailed ); } nConstraint += nTop; testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeEnd); }else{ endEq = 1; } }else if( bStopAtNull ){ if( regBignull==0 ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); endEq = 0; } nConstraint++; } if( zStartAff ) sqlite3DbNNFreeNN(db, zStartAff); if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff); /* Top of the loop body */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); /* Check if the index cursor is past the end of the range. */ if( nConstraint ){ if( regBignull ){ /* Except, skip the end-of-range check while doing the NULL-scan */ sqlite3VdbeAddOp2(v, OP_IfNot, regBignull, sqlite3VdbeCurrentAddr(v)+3); VdbeComment((v, "If NULL-scan 2nd pass")); VdbeCoverage(v); } op = aEndOp[bRev*2 + endEq]; sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); if( addrSeekScan ) sqlite3VdbeJumpHere(v, addrSeekScan); } if( regBignull ){ /* During a NULL-scan, check to see if we have reached the end of ** the NULLs */ assert( bSeekPastNull==!bStopAtNull ); assert( bSeekPastNull+bStopAtNull==1 ); assert( nConstraint+bSeekPastNull>0 ); sqlite3VdbeAddOp2(v, OP_If, regBignull, sqlite3VdbeCurrentAddr(v)+2); VdbeComment((v, "If NULL-scan 1st pass")); VdbeCoverage(v); op = aEndOp[bRev*2 + bSeekPastNull]; sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint+bSeekPastNull); testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); } if( (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0 ){ sqlite3VdbeAddOp3(v, OP_SeekHit, iIdxCur, nEq, nEq); } /* Seek the table cursor, if required */ omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 && (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0; if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); }else if( iCur!=iIdxCur ){ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; jnKeyCol; j++){ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j); } sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont, iRowidReg, pPk->nKeyCol); VdbeCoverage(v); } if( pLevel->iLeftJoin==0 ){ /* If a partial index is driving the loop, try to eliminate WHERE clause ** terms from the query that must be true due to the WHERE clause of ** the partial index. ** ** 2019-11-02 ticket 623eff57e76d45f6: This optimization does not work ** for a LEFT JOIN. */ if( pIdx->pPartIdxWhere ){ whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC); } }else{ testcase( pIdx->pPartIdxWhere ); /* The following assert() is not a requirement, merely an observation: ** The OR-optimization doesn't work for the right hand table of ** a LEFT JOIN: */ assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 ); } /* Record the instruction used to terminate the loop. */ if( pLoop->wsFlags & WHERE_ONEROW ){ pLevel->op = OP_Noop; }else if( bRev ){ pLevel->op = OP_Prev; }else{ pLevel->op = OP_Next; } pLevel->p1 = iIdxCur; pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0; if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; }else{ assert( pLevel->p5==0 ); } if( omitTable ) pIdx = 0; }else #ifndef SQLITE_OMIT_OR_OPTIMIZATION if( pLoop->wsFlags & WHERE_MULTI_OR ){ /* Case 5: Two or more separately indexed terms connected by OR ** ** Example: ** ** CREATE TABLE t1(a,b,c,d); ** CREATE INDEX i1 ON t1(a); ** CREATE INDEX i2 ON t1(b); ** CREATE INDEX i3 ON t1(c); ** ** SELECT * FROM t1 WHERE a=5 OR b=7 OR (c=11 AND d=13) ** ** In the example, there are three indexed terms connected by OR. ** The top of the loop looks like this: ** ** Null 1 # Zero the rowset in reg 1 ** ** Then, for each indexed term, the following. The arguments to ** RowSetTest are such that the rowid of the current row is inserted ** into the RowSet. If it is already present, control skips the ** Gosub opcode and jumps straight to the code generated by WhereEnd(). ** ** sqlite3WhereBegin() ** RowSetTest # Insert rowid into rowset ** Gosub 2 A ** sqlite3WhereEnd() ** ** Following the above, code to terminate the loop. Label A, the target ** of the Gosub above, jumps to the instruction right after the Goto. ** ** Null 1 # Zero the rowset in reg 1 ** Goto B # The loop is finished. ** ** A: # Return data, whatever. ** ** Return 2 # Jump back to the Gosub ** ** B: ** ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then ** use an ephemeral index instead of a RowSet to record the primary ** keys of the rows we have already seen. ** */ WhereClause *pOrWc; /* The OR-clause broken out into subterms */ SrcList *pOrTab; /* Shortened table list or OR-clause generation */ Index *pCov = 0; /* Potential covering index (or NULL) */ int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */ int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ int regRowset = 0; /* Register for RowSet object */ int regRowid = 0; /* Register holding rowid */ int iLoopBody = sqlite3VdbeMakeLabel(pParse);/* Start of loop body */ int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ Table *pTab = pTabItem->pTab; pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->eOperator & WO_OR ); assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); pOrWc = &pTerm->u.pOrInfo->wc; pLevel->op = OP_Return; pLevel->p1 = regReturn; /* Set up a new SrcList in pOrTab containing the table being scanned ** by this loop in the a[0] slot and all notReady tables in a[1..] slots. ** This becomes the SrcList in the recursive call to sqlite3WhereBegin(). */ if( pWInfo->nLevel>1 ){ int nNotReady; /* The number of notReady tables */ SrcItem *origSrc; /* Original list of tables */ nNotReady = pWInfo->nLevel - iLevel - 1; pOrTab = sqlite3DbMallocRawNN(db, sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); if( pOrTab==0 ) return notReady; pOrTab->nAlloc = (u8)(nNotReady + 1); pOrTab->nSrc = pOrTab->nAlloc; memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem)); origSrc = pWInfo->pTabList->a; for(k=1; k<=nNotReady; k++){ memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k])); } }else{ pOrTab = pWInfo->pTabList; } /* Initialize the rowset register to contain NULL. An SQL NULL is ** equivalent to an empty rowset. Or, create an ephemeral index ** capable of holding primary keys in the case of a WITHOUT ROWID. ** ** Also initialize regReturn to contain the address of the instruction ** immediately following the OP_Return at the bottom of the loop. This ** is required in a few obscure LEFT JOIN cases where control jumps ** over the top of the loop into the body of it. In this case the ** correct response for the end-of-loop code (the OP_Return) is to ** fall through to the next instruction, just as an OP_Next does if ** called on an uninitialized cursor. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ if( HasRowid(pTab) ){ regRowset = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); regRowset = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenEphemeral, regRowset, pPk->nKeyCol); sqlite3VdbeSetP4KeyInfo(pParse, pPk); } regRowid = ++pParse->nMem; } iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y ** Then for every term xN, evaluate as the subexpression: xN AND y ** That way, terms in y that are factored into the disjunction will ** be picked up by the recursive calls to sqlite3WhereBegin() below. ** ** Actually, each subexpression is converted to "xN AND w" where w is ** the "interesting" terms of z - terms that did not originate in the ** ON or USING clause of a LEFT JOIN, and terms that are usable as ** indices. ** ** This optimization also only applies if the (x1 OR x2 OR ...) term ** is not contained in the ON clause of a LEFT JOIN. ** See ticket http://www.sqlite.org/src/info/f2369304e4 ** ** 2022-02-04: Do not push down slices of a row-value comparison. ** In other words, "w" or "y" may not be a slice of a vector. Otherwise, ** the initialization of the right-hand operand of the vector comparison ** might not occur, or might occur only in an OR branch that is not ** taken. dbsqlfuzz 80a9fade844b4fb43564efc972bcb2c68270f5d1. ** ** 2022-03-03: Do not push down expressions that involve subqueries. ** The subquery might get coded as a subroutine. Any table-references ** in the subquery might be resolved to index-references for the index on ** the OR branch in which the subroutine is coded. But if the subroutine ** is invoked from a different OR branch that uses a different index, such ** index-references will not work. tag-20220303a ** https://sqlite.org/forum/forumpost/36937b197273d403 */ if( pWC->nTerm>1 ){ int iTerm; for(iTerm=0; iTermnTerm; iTerm++){ Expr *pExpr = pWC->a[iTerm].pExpr; if( &pWC->a[iTerm] == pTerm ) continue; testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL ); testcase( pWC->a[iTerm].wtFlags & TERM_CODED ); testcase( pWC->a[iTerm].wtFlags & TERM_SLICE ); if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED|TERM_SLICE))!=0 ){ continue; } if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; if( ExprHasProperty(pExpr, EP_Subquery) ) continue; /* tag-20220303a */ pExpr = sqlite3ExprDup(db, pExpr, 0); pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr); } if( pAndExpr ){ /* The extra 0x10000 bit on the opcode is masked off and does not ** become part of the new Expr.op. However, it does make the ** op==TK_AND comparison inside of sqlite3PExpr() false, and this ** prevents sqlite3PExpr() from applying the AND short-circuit ** optimization, which we do not want here. */ pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr); } } /* Run a separate WHERE clause for each term of the OR clause. After ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR")); for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ Expr *pDelete; /* Local copy of OR clause term */ int jmp1 = 0; /* Address of jump operation */ testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0 && !ExprHasProperty(pOrExpr, EP_OuterON) ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */ pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDelete); continue; } if( pAndExpr ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1)); WHERETRACE(0xffffffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, 0, WHERE_OR_SUBCLAUSE, iCovCur); assert( pSubWInfo || pParse->nErr ); if( pSubWInfo ){ WhereLoop *pSubLoop; int addrExplain = sqlite3WhereExplainOneScan( pParse, pOrTab, &pSubWInfo->a[0], 0 ); sqlite3WhereAddScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain); /* This is the sub-WHERE clause body. First skip over ** duplicate rows from prior sub-WHERE clauses, and record the ** rowid (or PRIMARY KEY) for the current row so that the same ** row will be skipped in subsequent sub-WHERE clauses. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); if( HasRowid(pTab) ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, regRowid); jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, regRowid, iSet); VdbeCoverage(v); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); int nPk = pPk->nKeyCol; int iPk; int r; /* Read the PK into an array of temp registers. */ r = sqlite3GetTempRange(pParse, nPk); for(iPk=0; iPkaiColumn[iPk]; sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); } /* Check if the temp table already contains this key. If so, ** the row has already been included in the result set and ** can be ignored (by jumping past the Gosub below). Otherwise, ** insert the key into the temp table and proceed with processing ** the row. ** ** Use some of the same optimizations as OP_RowSetTest: If iSet ** is zero, assume that the key cannot already be present in ** the temp table. And if iSet is -1, assume that there is no ** need to insert the key into the temp table, as it will never ** be tested for. */ if( iSet ){ jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk); VdbeCoverage(v); } if( iSet>=0 ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, regRowset, regRowid, r, nPk); if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); } /* Release the array of temp registers */ sqlite3ReleaseTempRange(pParse, r, nPk); } } /* Invoke the main loop body as a subroutine */ sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody); /* Jump here (skipping the main loop body subroutine) if the ** current sub-WHERE row is a duplicate from prior sub-WHEREs. */ if( jmp1 ) sqlite3VdbeJumpHere(v, jmp1); /* The pSubWInfo->untestedTerms flag means that this OR term ** contained one or more AND term from a notReady table. The ** terms from the notReady table could not be tested and will ** need to be tested later. */ if( pSubWInfo->untestedTerms ) untestedTerms = 1; /* If all of the OR-connected terms are optimized using the same ** index, and the index is opened using the same cursor number ** by each call to sqlite3WhereBegin() made by this loop, it may ** be possible to use that index as a covering index. ** ** If the call to sqlite3WhereBegin() above resulted in a scan that ** uses an index, and this is either the first OR-connected term ** processed or the index is the same as that used by all previous ** terms, set pCov to the candidate covering index. Otherwise, set ** pCov to NULL to indicate that no candidate covering index will ** be available. */ pSubLoop = pSubWInfo->a[0].pWLoop; assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 && (ii==0 || pSubLoop->u.btree.pIndex==pCov) && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex)) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; }else{ pCov = 0; } if( sqlite3WhereUsesDeferredSeek(pSubWInfo) ){ pWInfo->bDeferredSeek = 1; } /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); ExplainQueryPlanPop(pParse); } sqlite3ExprDelete(db, pDelete); } } ExplainQueryPlanPop(pParse); assert( pLevel->pWLoop==pLoop ); assert( (pLoop->wsFlags & WHERE_MULTI_OR)!=0 ); assert( (pLoop->wsFlags & WHERE_IN_ABLE)==0 ); pLevel->u.pCoveringIdx = pCov; if( pCov ) pLevel->iIdxCur = iCovCur; if( pAndExpr ){ pAndExpr->pLeft = 0; sqlite3ExprDelete(db, pAndExpr); } sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeGoto(v, pLevel->addrBrk); sqlite3VdbeResolveLabel(v, iLoopBody); /* Set the P2 operand of the OP_Return opcode that will end the current ** loop to point to this spot, which is the top of the next containing ** loop. The byte-code formatter will use that P2 value as a hint to ** indent everything in between the this point and the final OP_Return. ** See tag-20220407a in vdbe.c and shell.c */ assert( pLevel->op==OP_Return ); pLevel->p2 = sqlite3VdbeCurrentAddr(v); if( pWInfo->nLevel>1 ){ sqlite3DbFreeNN(db, pOrTab); } if( !untestedTerms ) disableTerm(pLevel, pTerm); }else #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ { /* Case 6: There is no usable index. We must do a complete ** scan of the entire table. */ static const u8 aStep[] = { OP_Next, OP_Prev }; static const u8 aStart[] = { OP_Rewind, OP_Last }; assert( bRev==0 || bRev==1 ); if( pTabItem->fg.isRecursive ){ /* Tables marked isRecursive have only a single row that is stored in ** a pseudo-cursor. No need to Rewind or Next such cursors. */ pLevel->op = OP_Noop; }else{ codeCursorHint(pTabItem, pWInfo, pLevel, 0); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrHalt); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS pLevel->addrVisit = sqlite3VdbeCurrentAddr(v); #endif /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. ** ** This loop may run between one and three times, depending on the ** constraints to be generated. The value of stack variable iLoop ** determines the constraints coded by each iteration, as follows: ** ** iLoop==1: Code only expressions that are entirely covered by pIdx. ** iLoop==2: Code remaining expressions that do not contain correlated ** sub-queries. ** iLoop==3: Code all remaining expressions. ** ** An effort is made to skip unnecessary iterations of the loop. */ iLoop = (pIdx ? 1 : 2); do{ int iNext = 0; /* Next value for iLoop */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE; int skipLikeAddr = 0; testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ testcase( pWInfo->untestedTerms==0 && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ); pWInfo->untestedTerms = 1; continue; } pE = pTerm->pExpr; assert( pE!=0 ); if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ){ if( !ExprHasProperty(pE,EP_OuterON|EP_InnerON) ){ /* Defer processing WHERE clause constraints until after outer ** join processing. tag-20220513a */ continue; }else if( (pTabItem->fg.jointype & JT_LEFT)==JT_LEFT && !ExprHasProperty(pE,EP_OuterON) ){ continue; }else{ Bitmask m = sqlite3WhereGetMask(&pWInfo->sMaskSet, pE->w.iJoin); if( m & pLevel->notReady ){ /* An ON clause that is not ripe */ continue; } } } if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){ iNext = 2; continue; } if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){ if( iNext==0 ) iNext = 3; continue; } if( (pTerm->wtFlags & TERM_LIKECOND)!=0 ){ /* If the TERM_LIKECOND flag is set, that means that the range search ** is sufficient to guarantee that the LIKE operator is true, so we ** can skip the call to the like(A,B) function. But this only works ** for strings. So do not skip the call to the function on the pass ** that compares BLOBs. */ #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS continue; #else u32 x = pLevel->iLikeRepCntr; if( x>0 ){ skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If,(int)(x>>1)); VdbeCoverageIf(v, (x&1)==1); VdbeCoverageIf(v, (x&1)==0); } #endif } #ifdef WHERETRACE_ENABLED /* 0xffffffff */ if( sqlite3WhereTrace ){ VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d", pWC->nTerm-j, pTerm, iLoop)); } if( sqlite3WhereTrace & 0x4000 ){ sqlite3DebugPrintf("Coding auxiliary constraint:\n"); sqlite3WhereTermPrint(pTerm, pWC->nTerm-j); } #endif sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); pTerm->wtFlags |= TERM_CODED; } iLoop = iNext; }while( iLoop>0 ); /* Insert code to test for implied constraints based on transitivity ** of the "==" operator. ** ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123" ** and we are coding the t1 loop and the t2 loop has not yet coded, ** then we cannot use the "t1.a=t2.b" constraint, but we can code ** the implied "t1.a=123" constraint. */ for(pTerm=pWC->a, j=pWC->nBase; j>0; j--, pTerm++){ Expr *pE, sEAlt; WhereTerm *pAlt; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; if( (pTerm->eOperator & WO_EQUIV)==0 ) continue; if( pTerm->leftCursor!=iCur ) continue; if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ) continue; pE = pTerm->pExpr; #ifdef WHERETRACE_ENABLED /* 0x4001 */ if( (sqlite3WhereTrace & 0x4001)==0x4001 ){ sqlite3DebugPrintf("Coding transitive constraint:\n"); sqlite3WhereTermPrint(pTerm, pWC->nTerm-j); } #endif assert( !ExprHasProperty(pE, EP_OuterON) ); assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady, WO_EQ|WO_IN|WO_IS, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; if( (pAlt->eOperator & WO_IN) && ExprUseXSelect(pAlt->pExpr) && (pAlt->pExpr->x.pSelect->pEList->nExpr>1) ){ continue; } testcase( pAlt->eOperator & WO_EQ ); testcase( pAlt->eOperator & WO_IS ); testcase( pAlt->eOperator & WO_IN ); VdbeModuleComment((v, "begin transitive constraint")); sEAlt = *pAlt->pExpr; sEAlt.pLeft = pE->pLeft; sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL); pAlt->wtFlags |= TERM_CODED; } /* For a RIGHT OUTER JOIN, record the fact that the current row has ** been matched at least once. */ if( pLevel->pRJ ){ Table *pTab; int nPk; int r; int jmp1 = 0; WhereRightJoin *pRJ = pLevel->pRJ; /* pTab is the right-hand table of the RIGHT JOIN. Generate code that ** will record that the current row of that table has been matched at ** least once. This is accomplished by storing the PK for the row in ** both the iMatch index and the regBloom Bloom filter. */ pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab; if( HasRowid(pTab) ){ r = sqlite3GetTempRange(pParse, 2); sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1); nPk = 1; }else{ int iPk; Index *pPk = sqlite3PrimaryKeyIndex(pTab); nPk = pPk->nKeyCol; r = sqlite3GetTempRange(pParse, nPk+1); for(iPk=0; iPkaiColumn[iPk]; sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+1+iPk); } } jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, 0, r+1, nPk); VdbeCoverage(v); VdbeComment((v, "match against %s", pTab->zName)); sqlite3VdbeAddOp3(v, OP_MakeRecord, r+1, nPk, r); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pRJ->iMatch, r, r+1, nPk); sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3VdbeJumpHere(v, jmp1); sqlite3ReleaseTempRange(pParse, r, nPk+1); } /* For a LEFT OUTER JOIN, generate code that will record the fact that ** at least one row of the right table has matched the left table. */ if( pLevel->iLeftJoin ){ pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); VdbeComment((v, "record LEFT JOIN hit")); if( pLevel->pRJ==0 ){ goto code_outer_join_constraints; /* WHERE clause constraints */ } } if( pLevel->pRJ ){ /* Create a subroutine used to process all interior loops and code ** of the RIGHT JOIN. During normal operation, the subroutine will ** be in-line with the rest of the code. But at the end, a separate ** loop will run that invokes this subroutine for unmatched rows ** of pTab, with all tables to left begin set to NULL. */ WhereRightJoin *pRJ = pLevel->pRJ; sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn); pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v); assert( pParse->withinRJSubrtn < 255 ); pParse->withinRJSubrtn++; /* WHERE clause constraints must be deferred until after outer join ** row elimination has completed, since WHERE clause constraints apply ** to the results of the OUTER JOIN. The following loop generates the ** appropriate WHERE clause constraint checks. tag-20220513a. */ code_outer_join_constraints: for(pTerm=pWC->a, j=0; jnBase; j++, pTerm++){ testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ assert( pWInfo->untestedTerms ); continue; } if( pTabItem->fg.jointype & JT_LTORJ ) continue; assert( pTerm->pExpr ); sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; } } #if WHERETRACE_ENABLED /* 0x4001 */ if( sqlite3WhereTrace & 0x4000 ){ sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n", iLevel); sqlite3WhereClausePrint(pWC); } if( sqlite3WhereTrace & 0x1 ){ sqlite3DebugPrintf("End Coding level %d: notReady=%llx\n", iLevel, (u64)pLevel->notReady); } #endif return pLevel->notReady; } /* ** Generate the code for the loop that finds all non-matched terms ** for a RIGHT JOIN. */ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( WhereInfo *pWInfo, int iLevel, WhereLevel *pLevel ){ Parse *pParse = pWInfo->pParse; Vdbe *v = pParse->pVdbe; WhereRightJoin *pRJ = pLevel->pRJ; Expr *pSubWhere = 0; WhereClause *pWC = &pWInfo->sWC; WhereInfo *pSubWInfo; WhereLoop *pLoop = pLevel->pWLoop; SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; SrcList sFrom; Bitmask mAll = 0; int k; ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName)); sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn, pRJ->regReturn); for(k=0; ka[k].pWLoop->maskSelf; sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); iIdxCur = pWInfo->a[k].iIdxCur; if( iIdxCur ){ sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur); } } if( (pTabItem->fg.jointype & JT_LTORJ)==0 ){ mAll |= pLoop->maskSelf; for(k=0; knTerm; k++){ WhereTerm *pTerm = &pWC->a[k]; if( (pTerm->wtFlags & (TERM_VIRTUAL|TERM_SLICE))!=0 && pTerm->eOperator!=WO_ROWVAL ){ break; } if( pTerm->prereqAll & ~mAll ) continue; if( ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON) ) continue; pSubWhere = sqlite3ExprAnd(pParse, pSubWhere, sqlite3ExprDup(pParse->db, pTerm->pExpr, 0)); } } sFrom.nSrc = 1; sFrom.nAlloc = 1; memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem)); sFrom.a[0].fg.jointype = 0; assert( pParse->withinRJSubrtn < 100 ); pParse->withinRJSubrtn++; pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0, WHERE_RIGHT_JOIN, 0); if( pSubWInfo ){ int iCur = pLevel->iTabCur; int r = ++pParse->nMem; int nPk; int jmp; int addrCont = sqlite3WhereContinueLabel(pSubWInfo); Table *pTab = pTabItem->pTab; if( HasRowid(pTab) ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r); nPk = 1; }else{ int iPk; Index *pPk = sqlite3PrimaryKeyIndex(pTab); nPk = pPk->nKeyCol; pParse->nMem += nPk - 1; for(iPk=0; iPkaiColumn[iPk]; sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); } } jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk); VdbeCoverage(v); sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk); VdbeCoverage(v); sqlite3VdbeJumpHere(v, jmp); sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn); sqlite3WhereEnd(pSubWInfo); } sqlite3ExprDelete(pParse->db, pSubWhere); ExplainQueryPlanPop(pParse); assert( pParse->withinRJSubrtn>0 ); pParse->withinRJSubrtn--; } /************** End of wherecode.c *******************************************/ /************** Begin file whereexpr.c ***************************************/ /* ** 2015-06-08 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** ** This file was originally part of where.c but was split out to improve ** readability and editability. This file contains utility routines for ** analyzing Expr objects in the WHERE clause. */ /* #include "sqliteInt.h" */ /* #include "whereInt.h" */ /* Forward declarations */ static void exprAnalyze(SrcList*, WhereClause*, int); /* ** Deallocate all memory associated with a WhereOrInfo object. */ static void whereOrInfoDelete(sqlite3 *db, WhereOrInfo *p){ sqlite3WhereClauseClear(&p->wc); sqlite3DbFree(db, p); } /* ** Deallocate all memory associated with a WhereAndInfo object. */ static void whereAndInfoDelete(sqlite3 *db, WhereAndInfo *p){ sqlite3WhereClauseClear(&p->wc); sqlite3DbFree(db, p); } /* ** Add a single new WhereTerm entry to the WhereClause object pWC. ** The new WhereTerm object is constructed from Expr p and with wtFlags. ** The index in pWC->a[] of the new WhereTerm is returned on success. ** 0 is returned if the new WhereTerm could not be added due to a memory ** allocation error. The memory allocation failure will be recorded in ** the db->mallocFailed flag so that higher-level functions can detect it. ** ** This routine will increase the size of the pWC->a[] array as necessary. ** ** If the wtFlags argument includes TERM_DYNAMIC, then responsibility ** for freeing the expression p is assumed by the WhereClause object pWC. ** This is true even if this routine fails to allocate a new WhereTerm. ** ** WARNING: This routine might reallocate the space used to store ** WhereTerms. All pointers to WhereTerms should be invalidated after ** calling this routine. Such pointers may be reinitialized by referencing ** the pWC->a[] array. */ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ WhereTerm *pTerm; int idx; testcase( wtFlags & TERM_VIRTUAL ); if( pWC->nTerm>=pWC->nSlot ){ WhereTerm *pOld = pWC->a; sqlite3 *db = pWC->pWInfo->pParse->db; pWC->a = sqlite3WhereMalloc(pWC->pWInfo, sizeof(pWC->a[0])*pWC->nSlot*2 ); if( pWC->a==0 ){ if( wtFlags & TERM_DYNAMIC ){ sqlite3ExprDelete(db, p); } pWC->a = pOld; return 0; } memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm); pWC->nSlot = pWC->nSlot*2; } pTerm = &pWC->a[idx = pWC->nTerm++]; if( (wtFlags & TERM_VIRTUAL)==0 ) pWC->nBase = pWC->nTerm; if( p && ExprHasProperty(p, EP_Unlikely) ){ pTerm->truthProb = sqlite3LogEst(p->iTable) - 270; }else{ pTerm->truthProb = 1; } pTerm->pExpr = sqlite3ExprSkipCollateAndLikely(p); pTerm->wtFlags = wtFlags; pTerm->pWC = pWC; pTerm->iParent = -1; memset(&pTerm->eOperator, 0, sizeof(WhereTerm) - offsetof(WhereTerm,eOperator)); return idx; } /* ** Return TRUE if the given operator is one of the operators that is ** allowed for an indexable WHERE clause term. The allowed operators are ** "=", "<", ">", "<=", ">=", "IN", "IS", and "IS NULL" */ static int allowedOp(int op){ assert( TK_GT>TK_EQ && TK_GTTK_EQ && TK_LTTK_EQ && TK_LE=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS; } /* ** Commute a comparison operator. Expressions of the form "X op Y" ** are converted into "Y op X". */ static u16 exprCommute(Parse *pParse, Expr *pExpr){ if( pExpr->pLeft->op==TK_VECTOR || pExpr->pRight->op==TK_VECTOR || sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight) != sqlite3BinaryCompareCollSeq(pParse, pExpr->pRight, pExpr->pLeft) ){ pExpr->flags ^= EP_Commuted; } SWAP(Expr*,pExpr->pRight,pExpr->pLeft); if( pExpr->op>=TK_GT ){ assert( TK_LT==TK_GT+2 ); assert( TK_GE==TK_LE+2 ); assert( TK_GT>TK_EQ ); assert( TK_GTop>=TK_GT && pExpr->op<=TK_GE ); pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT; } return 0; } /* ** Translate from TK_xx operator to WO_xx bitmask. */ static u16 operatorMask(int op){ u16 c; assert( allowedOp(op) ); if( op==TK_IN ){ c = WO_IN; }else if( op==TK_ISNULL ){ c = WO_ISNULL; }else if( op==TK_IS ){ c = WO_IS; }else{ assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff ); c = (u16)(WO_EQ<<(op-TK_EQ)); } assert( op!=TK_ISNULL || c==WO_ISNULL ); assert( op!=TK_IN || c==WO_IN ); assert( op!=TK_EQ || c==WO_EQ ); assert( op!=TK_LT || c==WO_LT ); assert( op!=TK_LE || c==WO_LE ); assert( op!=TK_GT || c==WO_GT ); assert( op!=TK_GE || c==WO_GE ); assert( op!=TK_IS || c==WO_IS ); return c; } #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION /* ** Check to see if the given expression is a LIKE or GLOB operator that ** can be optimized using inequality constraints. Return TRUE if it is ** so and false if not. ** ** In order for the operator to be optimizible, the RHS must be a string ** literal that does not begin with a wildcard. The LHS must be a column ** that may only be NULL, a string, or a BLOB, never a number. (This means ** that virtual tables cannot participate in the LIKE optimization.) The ** collating sequence for the column on the LHS must be appropriate for ** the operator. */ static int isLikeOrGlob( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* Test this expression */ Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */ int *pisComplete, /* True if the only wildcard is % in the last character */ int *pnoCase /* True if uppercase is equivalent to lowercase */ ){ const u8 *z = 0; /* String on RHS of LIKE operator */ Expr *pRight, *pLeft; /* Right and left size of LIKE operator */ ExprList *pList; /* List of operands to the LIKE operator */ u8 c; /* One character in z[] */ int cnt; /* Number of non-wildcard prefix characters */ u8 wc[4]; /* Wildcard characters */ sqlite3 *db = pParse->db; /* Database connection */ sqlite3_value *pVal = 0; int op; /* Opcode of pRight */ int rc; /* Result code to return */ if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, (char*)wc) ){ return 0; } #ifdef SQLITE_EBCDIC if( *pnoCase ) return 0; #endif assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; pLeft = pList->a[1].pExpr; pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr); op = pRight->op; if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *pReprepare = pParse->pReprepare; int iCol = pRight->iColumn; pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB); if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ z = sqlite3_value_text(pVal); } sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ assert( !ExprHasProperty(pRight, EP_IntValue) ); z = (u8*)pRight->u.zToken; } if( z ){ /* Count the number of prefix characters prior to the first wildcard */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; if( c==wc[3] && z[cnt]!=0 ) cnt++; } /* The optimization is possible only if (1) the pattern does not begin ** with a wildcard and if (2) the non-wildcard prefix does not end with ** an (illegal 0xff) character, or (3) the pattern does not consist of ** a single escape character. The second condition is necessary so ** that we can increment the prefix key to find an upper bound for the ** range search. The third is because the caller assumes that the pattern ** consists of at least one character after all escapes have been ** removed. */ if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){ Expr *pPrefix; /* A "complete" match if the pattern ends with "*" or "%" */ *pisComplete = c==wc[0] && z[cnt+1]==0; /* Get the pattern prefix. Remove all escapes from the prefix. */ pPrefix = sqlite3Expr(db, TK_STRING, (char*)z); if( pPrefix ){ int iFrom, iTo; char *zNew; assert( !ExprHasProperty(pPrefix, EP_IntValue) ); zNew = pPrefix->u.zToken; zNew[cnt] = 0; for(iFrom=iTo=0; iFrom0 ); /* If the LHS is not an ordinary column with TEXT affinity, then the ** pattern prefix boundaries (both the start and end boundaries) must ** not look like a number. Otherwise the pattern might be treated as ** a number, which will invalidate the LIKE optimization. ** ** Getting this right has been a persistent source of bugs in the ** LIKE optimization. See, for example: ** 2018-09-10 https://sqlite.org/src/info/c94369cae9b561b1 ** 2019-05-02 https://sqlite.org/src/info/b043a54c3de54b28 ** 2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07 ** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975 ** 2019-09-03 https://sqlite.org/src/info/0f0428096f17252a */ if( pLeft->op!=TK_COLUMN || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT || (ALWAYS( ExprUseYTab(pLeft) ) && ALWAYS(pLeft->y.pTab) && IsVirtual(pLeft->y.pTab)) /* Might be numeric */ ){ int isNum; double rDummy; isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); if( isNum<=0 ){ if( iTo==1 && zNew[0]=='-' ){ isNum = +1; }else{ zNew[iTo-1]++; isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); zNew[iTo-1]--; } } if( isNum>0 ){ sqlite3ExprDelete(db, pPrefix); sqlite3ValueFree(pVal); return 0; } } } *ppPrefix = pPrefix; /* If the RHS pattern is a bound parameter, make arrangements to ** reprepare the statement when that parameter is rebound */ if( op==TK_VARIABLE ){ Vdbe *v = pParse->pVdbe; sqlite3VdbeSetVarmask(v, pRight->iColumn); assert( !ExprHasProperty(pRight, EP_IntValue) ); if( *pisComplete && pRight->u.zToken[1] ){ /* If the rhs of the LIKE expression is a variable, and the current ** value of the variable means there is no need to invoke the LIKE ** function, then no OP_Variable will be added to the program. ** This causes problems for the sqlite3_bind_parameter_name() ** API. To work around them, add a dummy OP_Variable here. */ int r1 = sqlite3GetTempReg(pParse); sqlite3ExprCodeTarget(pParse, pRight, r1); sqlite3VdbeChangeP3(v, sqlite3VdbeCurrentAddr(v)-1, 0); sqlite3ReleaseTempReg(pParse, r1); } } }else{ z = 0; } } rc = (z!=0); sqlite3ValueFree(pVal); return rc; } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Check to see if the pExpr expression is a form that needs to be passed ** to the xBestIndex method of virtual tables. Forms of interest include: ** ** Expression Virtual Table Operator ** ----------------------- --------------------------------- ** 1. column MATCH expr SQLITE_INDEX_CONSTRAINT_MATCH ** 2. column GLOB expr SQLITE_INDEX_CONSTRAINT_GLOB ** 3. column LIKE expr SQLITE_INDEX_CONSTRAINT_LIKE ** 4. column REGEXP expr SQLITE_INDEX_CONSTRAINT_REGEXP ** 5. column != expr SQLITE_INDEX_CONSTRAINT_NE ** 6. expr != column SQLITE_INDEX_CONSTRAINT_NE ** 7. column IS NOT expr SQLITE_INDEX_CONSTRAINT_ISNOT ** 8. expr IS NOT column SQLITE_INDEX_CONSTRAINT_ISNOT ** 9. column IS NOT NULL SQLITE_INDEX_CONSTRAINT_ISNOTNULL ** ** In every case, "column" must be a column of a virtual table. If there ** is a match, set *ppLeft to the "column" expression, set *ppRight to the ** "expr" expression (even though in forms (6) and (8) the column is on the ** right and the expression is on the left). Also set *peOp2 to the ** appropriate virtual table operator. The return value is 1 or 2 if there ** is a match. The usual return is 1, but if the RHS is also a column ** of virtual table in forms (5) or (7) then return 2. ** ** If the expression matches none of the patterns above, return 0. */ static int isAuxiliaryVtabOperator( sqlite3 *db, /* Parsing context */ Expr *pExpr, /* Test this expression */ unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */ Expr **ppLeft, /* Column expression to left of MATCH/op2 */ Expr **ppRight /* Expression to left of MATCH/op2 */ ){ if( pExpr->op==TK_FUNCTION ){ static const struct Op2 { const char *zOp; unsigned char eOp2; } aOp[] = { { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } }; ExprList *pList; Expr *pCol; /* Column reference */ int i; assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; if( pList==0 || pList->nExpr!=2 ){ return 0; } /* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a ** virtual table on their second argument, which is the same as ** the left-hand side operand in their in-fix form. ** ** vtab_column MATCH expression ** MATCH(expression,vtab_column) */ pCol = pList->a[1].pExpr; assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) ); if( ExprIsVtab(pCol) ){ for(i=0; iu.zToken, aOp[i].zOp)==0 ){ *peOp2 = aOp[i].eOp2; *ppRight = pList->a[0].pExpr; *ppLeft = pCol; return 1; } } } /* We can also match against the first column of overloaded ** functions where xFindFunction returns a value of at least ** SQLITE_INDEX_CONSTRAINT_FUNCTION. ** ** OVERLOADED(vtab_column,expression) ** ** Historically, xFindFunction expected to see lower-case function ** names. But for this use case, xFindFunction is expected to deal ** with function names in an arbitrary case. */ pCol = pList->a[0].pExpr; assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) ); assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) ); if( ExprIsVtab(pCol) ){ sqlite3_vtab *pVtab; sqlite3_module *pMod; void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**); void *pNotUsed; pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); assert( !ExprHasProperty(pExpr, EP_IntValue) ); pMod = (sqlite3_module *)pVtab->pModule; if( pMod->xFindFunction!=0 ){ i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed); if( i>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ *peOp2 = i; *ppRight = pList->a[1].pExpr; *ppLeft = pCol; return 1; } } } }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){ int res = 0; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; assert( pLeft->op!=TK_COLUMN || (ExprUseYTab(pLeft) && pLeft->y.pTab!=0) ); if( ExprIsVtab(pLeft) ){ res++; } assert( pRight==0 || pRight->op!=TK_COLUMN || (ExprUseYTab(pRight) && pRight->y.pTab!=0) ); if( pRight && ExprIsVtab(pRight) ){ res++; SWAP(Expr*, pLeft, pRight); } *ppLeft = pLeft; *ppRight = pRight; if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE; if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT; if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL; return res; } return 0; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** If the pBase expression originated in the ON or USING clause of ** a join, then transfer the appropriate markings over to derived. */ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ if( pDerived && ExprHasProperty(pBase, EP_OuterON|EP_InnerON) ){ pDerived->flags |= pBase->flags & (EP_OuterON|EP_InnerON); pDerived->w.iJoin = pBase->w.iJoin; } } /* ** Mark term iChild as being a child of term iParent */ static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ pWC->a[iChild].iParent = iParent; pWC->a[iChild].truthProb = pWC->a[iParent].truthProb; pWC->a[iParent].nChild++; } /* ** Return the N-th AND-connected subterm of pTerm. Or if pTerm is not ** a conjunction, then return just pTerm when N==0. If N is exceeds ** the number of available subterms, return NULL. */ static WhereTerm *whereNthSubterm(WhereTerm *pTerm, int N){ if( pTerm->eOperator!=WO_AND ){ return N==0 ? pTerm : 0; } if( Nu.pAndInfo->wc.nTerm ){ return &pTerm->u.pAndInfo->wc.a[N]; } return 0; } /* ** Subterms pOne and pTwo are contained within WHERE clause pWC. The ** two subterms are in disjunction - they are OR-ed together. ** ** If these two terms are both of the form: "A op B" with the same ** A and B values but different operators and if the operators are ** compatible (if one is = and the other is <, for example) then ** add a new virtual AND term to pWC that is the combination of the ** two. ** ** Some examples: ** ** x x<=y ** x=y OR x=y --> x=y ** x<=y OR x x<=y ** ** The following is NOT generated: ** ** xy --> x!=y */ static void whereCombineDisjuncts( SrcList *pSrc, /* the FROM clause */ WhereClause *pWC, /* The complete WHERE clause */ WhereTerm *pOne, /* First disjunct */ WhereTerm *pTwo /* Second disjunct */ ){ u16 eOp = pOne->eOperator | pTwo->eOperator; sqlite3 *db; /* Database connection (for malloc) */ Expr *pNew; /* New virtual expression */ int op; /* Operator for the combined expression */ int idxNew; /* Index in pWC of the next virtual term */ if( (pOne->wtFlags | pTwo->wtFlags) & TERM_VNULL ) return; if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 ); if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; if( sqlite3ExprCompare(0,pOne->pExpr->pRight, pTwo->pExpr->pRight,-1) )return; /* If we reach this point, it means the two subterms can be combined */ if( (eOp & (eOp-1))!=0 ){ if( eOp & (WO_LT|WO_LE) ){ eOp = WO_LE; }else{ assert( eOp & (WO_GT|WO_GE) ); eOp = WO_GE; } } db = pWC->pWInfo->pParse->db; pNew = sqlite3ExprDup(db, pOne->pExpr, 0); if( pNew==0 ) return; for(op=TK_EQ; eOp!=(WO_EQ<<(op-TK_EQ)); op++){ assert( opop = op; idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); exprAnalyze(pSrc, pWC, idxNew); } #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) /* ** Analyze a term that consists of two or more OR-connected ** subterms. So in: ** ** ... WHERE (a=5) AND (b=7 OR c=9 OR d=13) AND (d=13) ** ^^^^^^^^^^^^^^^^^^^^ ** ** This routine analyzes terms such as the middle term in the above example. ** A WhereOrTerm object is computed and attached to the term under ** analysis, regardless of the outcome of the analysis. Hence: ** ** WhereTerm.wtFlags |= TERM_ORINFO ** WhereTerm.u.pOrInfo = a dynamically allocated WhereOrTerm object ** ** The term being analyzed must have two or more of OR-connected subterms. ** A single subterm might be a set of AND-connected sub-subterms. ** Examples of terms under analysis: ** ** (A) t1.x=t2.y OR t1.x=t2.z OR t1.y=15 OR t1.z=t3.a+5 ** (B) x=expr1 OR expr2=x OR x=expr3 ** (C) t1.x=t2.y OR (t1.x=t2.z AND t1.y=15) ** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*') ** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6) ** (F) x>A OR (x=A AND y>=B) ** ** CASE 1: ** ** If all subterms are of the form T.C=expr for some single column of C and ** a single table T (as shown in example B above) then create a new virtual ** term that is an equivalent IN expression. In other words, if the term ** being analyzed is: ** ** x = expr1 OR expr2 = x OR x = expr3 ** ** then create a new virtual term like this: ** ** x IN (expr1,expr2,expr3) ** ** CASE 2: ** ** If there are exactly two disjuncts and one side has x>A and the other side ** has x=A (for the same x and A) then add a new virtual conjunct term to the ** WHERE clause of the form "x>=A". Example: ** ** x>A OR (x=A AND y>B) adds: x>=A ** ** The added conjunct can sometimes be helpful in query planning. ** ** CASE 3: ** ** If all subterms are indexable by a single table T, then set ** ** WhereTerm.eOperator = WO_OR ** WhereTerm.u.pOrInfo->indexable |= the cursor number for table T ** ** A subterm is "indexable" if it is of the form ** "T.C " where C is any column of table T and ** is one of "=", "<", "<=", ">", ">=", "IS NULL", or "IN". ** A subterm is also indexable if it is an AND of two or more ** subsubterms at least one of which is indexable. Indexable AND ** subterms have their eOperator set to WO_AND and they have ** u.pAndInfo set to a dynamically allocated WhereAndTerm object. ** ** From another point of view, "indexable" means that the subterm could ** potentially be used with an index if an appropriate index exists. ** This analysis does not consider whether or not the index exists; that ** is decided elsewhere. This analysis only looks at whether subterms ** appropriate for indexing exist. ** ** All examples A through E above satisfy case 3. But if a term ** also satisfies case 1 (such as B) we know that the optimizer will ** always prefer case 1, so in that case we pretend that case 3 is not ** satisfied. ** ** It might be the case that multiple tables are indexable. For example, ** (E) above is indexable on tables P, Q, and R. ** ** Terms that satisfy case 3 are candidates for lookup by using ** separate indices to find rowids for each subterm and composing ** the union of all rowids using a RowSet object. This is similar ** to "bitmap indices" in other database engines. ** ** OTHERWISE: ** ** If none of cases 1, 2, or 3 apply, then leave the eOperator set to ** zero. This term is not useful for search. */ static void exprAnalyzeOrTerm( SrcList *pSrc, /* the FROM clause */ WhereClause *pWC, /* the complete WHERE clause */ int idxTerm /* Index of the OR-term to be analyzed */ ){ WhereInfo *pWInfo = pWC->pWInfo; /* WHERE clause processing context */ Parse *pParse = pWInfo->pParse; /* Parser context */ sqlite3 *db = pParse->db; /* Database connection */ WhereTerm *pTerm = &pWC->a[idxTerm]; /* The term to be analyzed */ Expr *pExpr = pTerm->pExpr; /* The expression of the term */ int i; /* Loop counters */ WhereClause *pOrWc; /* Breakup of pTerm into subterms */ WhereTerm *pOrTerm; /* A Sub-term within the pOrWc */ WhereOrInfo *pOrInfo; /* Additional information associated with pTerm */ Bitmask chngToIN; /* Tables that might satisfy case 1 */ Bitmask indexable; /* Tables that are indexable, satisfying case 2 */ /* ** Break the OR clause into its separate subterms. The subterms are ** stored in a WhereClause structure containing within the WhereOrInfo ** object that is attached to the original OR clause term. */ assert( (pTerm->wtFlags & (TERM_DYNAMIC|TERM_ORINFO|TERM_ANDINFO))==0 ); assert( pExpr->op==TK_OR ); pTerm->u.pOrInfo = pOrInfo = sqlite3DbMallocZero(db, sizeof(*pOrInfo)); if( pOrInfo==0 ) return; pTerm->wtFlags |= TERM_ORINFO; pOrWc = &pOrInfo->wc; memset(pOrWc->aStatic, 0, sizeof(pOrWc->aStatic)); sqlite3WhereClauseInit(pOrWc, pWInfo); sqlite3WhereSplit(pOrWc, pExpr, TK_OR); sqlite3WhereExprAnalyze(pSrc, pOrWc); if( db->mallocFailed ) return; assert( pOrWc->nTerm>=2 ); /* ** Compute the set of tables that might satisfy cases 1 or 3. */ indexable = ~(Bitmask)0; chngToIN = ~(Bitmask)0; for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){ if( (pOrTerm->eOperator & WO_SINGLE)==0 ){ WhereAndInfo *pAndInfo; assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 ); chngToIN = 0; pAndInfo = sqlite3DbMallocRawNN(db, sizeof(*pAndInfo)); if( pAndInfo ){ WhereClause *pAndWC; WhereTerm *pAndTerm; int j; Bitmask b = 0; pOrTerm->u.pAndInfo = pAndInfo; pOrTerm->wtFlags |= TERM_ANDINFO; pOrTerm->eOperator = WO_AND; pOrTerm->leftCursor = -1; pAndWC = &pAndInfo->wc; memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic)); sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND); sqlite3WhereExprAnalyze(pSrc, pAndWC); pAndWC->pOuter = pWC; if( !db->mallocFailed ){ for(j=0, pAndTerm=pAndWC->a; jnTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); if( allowedOp(pAndTerm->pExpr->op) || pAndTerm->eOperator==WO_AUX ){ b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); } } } indexable &= b; } }else if( pOrTerm->wtFlags & TERM_COPIED ){ /* Skip this term for now. We revisit it when we process the ** corresponding TERM_VIRTUAL term */ }else{ Bitmask b; b = sqlite3WhereGetMask(&pWInfo->sMaskSet, pOrTerm->leftCursor); if( pOrTerm->wtFlags & TERM_VIRTUAL ){ WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent]; b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pOther->leftCursor); } indexable &= b; if( (pOrTerm->eOperator & WO_EQ)==0 ){ chngToIN = 0; }else{ chngToIN &= b; } } } /* ** Record the set of tables that satisfy case 3. The set might be ** empty. */ pOrInfo->indexable = indexable; pTerm->eOperator = WO_OR; pTerm->leftCursor = -1; if( indexable ){ pWC->hasOr = 1; } /* For a two-way OR, attempt to implementation case 2. */ if( indexable && pOrWc->nTerm==2 ){ int iOne = 0; WhereTerm *pOne; while( (pOne = whereNthSubterm(&pOrWc->a[0],iOne++))!=0 ){ int iTwo = 0; WhereTerm *pTwo; while( (pTwo = whereNthSubterm(&pOrWc->a[1],iTwo++))!=0 ){ whereCombineDisjuncts(pSrc, pWC, pOne, pTwo); } } } /* ** chngToIN holds a set of tables that *might* satisfy case 1. But ** we have to do some additional checking to see if case 1 really ** is satisfied. ** ** chngToIN will hold either 0, 1, or 2 bits. The 0-bit case means ** that there is no possibility of transforming the OR clause into an ** IN operator because one or more terms in the OR clause contain ** something other than == on a column in the single table. The 1-bit ** case means that every term of the OR clause is of the form ** "table.column=expr" for some single table. The one bit that is set ** will correspond to the common table. We still need to check to make ** sure the same column is used on all terms. The 2-bit case is when ** the all terms are of the form "table1.column=table2.column". It ** might be possible to form an IN operator with either table1.column ** or table2.column as the LHS if either is common to every term of ** the OR clause. ** ** Note that terms of the form "table.column1=table.column2" (the ** same table on both sizes of the ==) cannot be optimized. */ if( chngToIN ){ int okToChngToIN = 0; /* True if the conversion to IN is valid */ int iColumn = -1; /* Column index on lhs of IN operator */ int iCursor = -1; /* Table cursor common to all terms */ int j = 0; /* Loop counter */ /* Search for a table and column that appears on one side or the ** other of the == operator in every subterm. That table and column ** will be recorded in iCursor and iColumn. There might not be any ** such table and column. Set okToChngToIN if an appropriate table ** and column is found but leave okToChngToIN false if not found. */ for(j=0; j<2 && !okToChngToIN; j++){ Expr *pLeft = 0; pOrTerm = pOrWc->a; for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); pOrTerm->wtFlags &= ~TERM_OK; if( pOrTerm->leftCursor==iCursor ){ /* This is the 2-bit case and we are on the second iteration and ** current term is from the first iteration. So skip this term. */ assert( j==1 ); continue; } if( (chngToIN & sqlite3WhereGetMask(&pWInfo->sMaskSet, pOrTerm->leftCursor))==0 ){ /* This term must be of the form t1.a==t2.b where t2 is in the ** chngToIN set but t1 is not. This term will be either preceded ** or followed by an inverted copy (t2.b==t1.a). Skip this term ** and use its inversion. */ testcase( pOrTerm->wtFlags & TERM_COPIED ); testcase( pOrTerm->wtFlags & TERM_VIRTUAL ); assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) ); continue; } assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); iColumn = pOrTerm->u.x.leftColumn; iCursor = pOrTerm->leftCursor; pLeft = pOrTerm->pExpr->pLeft; break; } if( i<0 ){ /* No candidate table+column was found. This can only occur ** on the second iteration */ assert( j==1 ); assert( IsPowerOfTwo(chngToIN) ); assert( chngToIN==sqlite3WhereGetMask(&pWInfo->sMaskSet, iCursor) ); break; } testcase( j==1 ); /* We have found a candidate table and column. Check to see if that ** table and column is common to every term in the OR clause */ okToChngToIN = 1; for(; i>=0 && okToChngToIN; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); if( pOrTerm->leftCursor!=iCursor ){ pOrTerm->wtFlags &= ~TERM_OK; }else if( pOrTerm->u.x.leftColumn!=iColumn || (iColumn==XN_EXPR && sqlite3ExprCompare(pParse, pOrTerm->pExpr->pLeft, pLeft, -1) )){ okToChngToIN = 0; }else{ int affLeft, affRight; /* If the right-hand side is also a column, then the affinities ** of both right and left sides must be such that no type ** conversions are required on the right. (Ticket #2249) */ affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight); affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft); if( affRight!=0 && affRight!=affLeft ){ okToChngToIN = 0; }else{ pOrTerm->wtFlags |= TERM_OK; } } } } /* At this point, okToChngToIN is true if original pTerm satisfies ** case 1. In that case, construct a new virtual term that is ** pTerm converted into an IN operator. */ if( okToChngToIN ){ Expr *pDup; /* A transient duplicate expression */ ExprList *pList = 0; /* The RHS of the IN operator */ Expr *pLeft = 0; /* The LHS of the IN operator */ Expr *pNew; /* The complete IN operator */ for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ if( (pOrTerm->wtFlags & TERM_OK)==0 ) continue; assert( pOrTerm->eOperator & WO_EQ ); assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( pOrTerm->leftCursor==iCursor ); assert( pOrTerm->u.x.leftColumn==iColumn ); pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup); pLeft = pOrTerm->pExpr->pLeft; } assert( pLeft!=0 ); pDup = sqlite3ExprDup(db, pLeft, 0); pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0); if( pNew ){ int idxNew; transferJoinMarkings(pNew, pExpr); assert( ExprUseXList(pNew) ); pNew->x.pList = pList; idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where reused */ markTermAsChild(pWC, idxNew, idxTerm); }else{ sqlite3ExprListDelete(db, pList); } } } } #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */ /* ** We already know that pExpr is a binary operator where both operands are ** column references. This routine checks to see if pExpr is an equivalence ** relation: ** 1. The SQLITE_Transitive optimization must be enabled ** 2. Must be either an == or an IS operator ** 3. Not originating in the ON clause of an OUTER JOIN ** 4. The affinities of A and B must be compatible ** 5a. Both operands use the same collating sequence OR ** 5b. The overall collating sequence is BINARY ** If this routine returns TRUE, that means that the RHS can be substituted ** for the LHS anyplace else in the WHERE clause where the LHS column occurs. ** This is an optimization. No harm comes from returning 0. But if 1 is ** returned when it should not be, then incorrect answers might result. */ static int termIsEquivalence(Parse *pParse, Expr *pExpr){ char aff1, aff2; CollSeq *pColl; if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; aff1 = sqlite3ExprAffinity(pExpr->pLeft); aff2 = sqlite3ExprAffinity(pExpr->pRight); if( aff1!=aff2 && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ return 0; } pColl = sqlite3ExprCompareCollSeq(pParse, pExpr); if( sqlite3IsBinary(pColl) ) return 1; return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight); } /* ** Recursively walk the expressions of a SELECT statement and generate ** a bitmask indicating which tables are used in that expression ** tree. */ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){ Bitmask mask = 0; while( pS ){ SrcList *pSrc = pS->pSrc; mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pEList); mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pGroupBy); mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pOrderBy); mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere); mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving); if( ALWAYS(pSrc!=0) ){ int i; for(i=0; inSrc; i++){ mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); if( pSrc->a[i].fg.isUsing==0 ){ mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn); } if( pSrc->a[i].fg.isTabFunc ){ mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg); } } } pS = pS->pPrior; } return mask; } /* ** Expression pExpr is one operand of a comparison operator that might ** be useful for indexing. This routine checks to see if pExpr appears ** in any index. Return TRUE (1) if pExpr is an indexed term and return ** FALSE (0) if not. If TRUE is returned, also set aiCurCol[0] to the cursor ** number of the table that is indexed and aiCurCol[1] to the column number ** of the column that is indexed, or XN_EXPR (-2) if an expression is being ** indexed. ** ** If pExpr is a TK_COLUMN column reference, then this routine always returns ** true even if that particular column is not indexed, because the column ** might be added to an automatic index later. */ static SQLITE_NOINLINE int exprMightBeIndexed2( SrcList *pFrom, /* The FROM clause */ int *aiCurCol, /* Write the referenced table cursor and column here */ Expr *pExpr, /* An operand of a comparison operator */ int j /* Start looking with the j-th pFrom entry */ ){ Index *pIdx; int i; int iCur; do{ iCur = pFrom->a[j].iCursor; for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->aColExpr==0 ) continue; for(i=0; inKeyCol; i++){ if( pIdx->aiColumn[i]!=XN_EXPR ) continue; assert( pIdx->bHasExpr ); if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0 && pExpr->op!=TK_STRING ){ aiCurCol[0] = iCur; aiCurCol[1] = XN_EXPR; return 1; } } } }while( ++j < pFrom->nSrc ); return 0; } static int exprMightBeIndexed( SrcList *pFrom, /* The FROM clause */ int *aiCurCol, /* Write the referenced table cursor & column here */ Expr *pExpr, /* An operand of a comparison operator */ int op /* The specific comparison operator */ ){ int i; /* If this expression is a vector to the left or right of a ** inequality constraint (>, <, >= or <=), perform the processing ** on the first element of the vector. */ assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE ); assert( TK_ISop==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){ assert( ExprUseXList(pExpr) ); pExpr = pExpr->x.pList->a[0].pExpr; } if( pExpr->op==TK_COLUMN ){ aiCurCol[0] = pExpr->iTable; aiCurCol[1] = pExpr->iColumn; return 1; } for(i=0; inSrc; i++){ Index *pIdx; for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->aColExpr ){ return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i); } } } return 0; } /* ** The input to this routine is an WhereTerm structure with only the ** "pExpr" field filled in. The job of this routine is to analyze the ** subexpression and populate all the other fields of the WhereTerm ** structure. ** ** If the expression is of the form " X" it gets commuted ** to the standard form of "X ". ** ** If the expression is of the form "X Y" where both X and Y are ** columns, then the original expression is unchanged and a new virtual ** term of the form "Y X" is added to the WHERE clause and ** analyzed separately. The original term is marked with TERM_COPIED ** and the new term is marked with TERM_DYNAMIC (because it's pExpr ** needs to be freed with the WhereClause) and TERM_VIRTUAL (because it ** is a commuted copy of a prior term.) The original term has nChild=1 ** and the copy has idxParent set to the index of the original term. */ static void exprAnalyze( SrcList *pSrc, /* the FROM clause */ WhereClause *pWC, /* the WHERE clause */ int idxTerm /* Index of the term to be analyzed */ ){ WhereInfo *pWInfo = pWC->pWInfo; /* WHERE clause processing context */ WhereTerm *pTerm; /* The term to be analyzed */ WhereMaskSet *pMaskSet; /* Set of table index masks */ Expr *pExpr; /* The expression to be analyzed */ Bitmask prereqLeft; /* Prerequisites of the pExpr->pLeft */ Bitmask prereqAll; /* Prerequisites of pExpr */ Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */ Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */ int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */ int noCase = 0; /* uppercase equivalent to lowercase */ int op; /* Top-level operator. pExpr->op */ Parse *pParse = pWInfo->pParse; /* Parsing context */ sqlite3 *db = pParse->db; /* Database connection */ unsigned char eOp2 = 0; /* op2 value for LIKE/REGEXP/GLOB */ int nLeft; /* Number of elements on left side vector */ if( db->mallocFailed ){ return; } assert( pWC->nTerm > idxTerm ); pTerm = &pWC->a[idxTerm]; pMaskSet = &pWInfo->sMaskSet; pExpr = pTerm->pExpr; assert( pExpr!=0 ); /* Because malloc() has not failed */ assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); pMaskSet->bVarSelect = 0; prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft); op = pExpr->op; if( op==TK_IN ){ assert( pExpr->pRight==0 ); if( sqlite3ExprCheckIN(pParse, pExpr) ) return; if( ExprUseXSelect(pExpr) ){ pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect); }else{ pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList); } prereqAll = prereqLeft | pTerm->prereqRight; }else{ pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight); if( pExpr->pLeft==0 || ExprHasProperty(pExpr, EP_xIsSelect|EP_IfNullRow) || pExpr->x.pList!=0 ){ prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr); }else{ prereqAll = prereqLeft | pTerm->prereqRight; } } if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT; #ifdef SQLITE_DEBUG if( prereqAll!=sqlite3WhereExprUsageNN(pMaskSet, pExpr) ){ printf("\n*** Incorrect prereqAll computed for:\n"); sqlite3TreeViewExpr(0,pExpr,0); assert( 0 ); } #endif if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) ){ Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iJoin); if( ExprHasProperty(pExpr, EP_OuterON) ){ prereqAll |= x; extraRight = x-1; /* ON clause terms may not be used with an index ** on left table of a LEFT JOIN. Ticket #3015 */ if( (prereqAll>>1)>=x ){ sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); return; } }else if( (prereqAll>>1)>=x ){ /* The ON clause of an INNER JOIN references a table to its right. ** Most other SQL database engines raise an error. But SQLite versions ** 3.0 through 3.38 just put the ON clause constraint into the WHERE ** clause and carried on. Beginning with 3.39, raise an error only ** if there is a RIGHT or FULL JOIN in the query. This makes SQLite ** more like other systems, and also preserves legacy. */ if( ALWAYS(pSrc->nSrc>0) && (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); return; } ExprClearProperty(pExpr, EP_InnerON); } } pTerm->prereqAll = prereqAll; pTerm->leftCursor = -1; pTerm->iParent = -1; pTerm->eOperator = 0; if( allowedOp(op) ){ int aiCurCol[2]; Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; if( pTerm->u.x.iField>0 ){ assert( op==TK_IN ); assert( pLeft->op==TK_VECTOR ); assert( ExprUseXList(pLeft) ); pLeft = pLeft->x.pList->a[pTerm->u.x.iField-1].pExpr; } if( exprMightBeIndexed(pSrc, aiCurCol, pLeft, op) ){ pTerm->leftCursor = aiCurCol[0]; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pTerm->u.x.leftColumn = aiCurCol[1]; pTerm->eOperator = operatorMask(op) & opMask; } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; if( pRight && exprMightBeIndexed(pSrc, aiCurCol, pRight, op) && !ExprHasProperty(pRight, EP_FixedCol) ){ WhereTerm *pNew; Expr *pDup; u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ assert( pTerm->u.x.iField==0 ); if( pTerm->leftCursor>=0 ){ int idxNew; pDup = sqlite3ExprDup(db, pExpr, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); return; } idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC); if( idxNew==0 ) return; pNew = &pWC->a[idxNew]; markTermAsChild(pWC, idxNew, idxTerm); if( op==TK_IS ) pNew->wtFlags |= TERM_IS; pTerm = &pWC->a[idxTerm]; pTerm->wtFlags |= TERM_COPIED; if( termIsEquivalence(pParse, pDup) ){ pTerm->eOperator |= WO_EQUIV; eExtraOp = WO_EQUIV; } }else{ pDup = pExpr; pNew = pTerm; } pNew->wtFlags |= exprCommute(pParse, pDup); pNew->leftCursor = aiCurCol[0]; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pNew->u.x.leftColumn = aiCurCol[1]; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; }else if( op==TK_ISNULL && !ExprHasProperty(pExpr,EP_OuterON) && 0==sqlite3ExprCanBeNull(pLeft) ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); pExpr->op = TK_TRUEFALSE; /* See tag-20230504-1 */ pExpr->u.zToken = "false"; ExprSetProperty(pExpr, EP_IsFalse); pTerm->prereqAll = 0; pTerm->eOperator = 0; } } #ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION /* If a term is the BETWEEN operator, create two new virtual terms ** that define the range that the BETWEEN implements. For example: ** ** a BETWEEN b AND c ** ** is converted into: ** ** (a BETWEEN b AND c) AND (a>=b) AND (a<=c) ** ** The two new terms are added onto the end of the WhereClause object. ** The new terms are "dynamic" and are children of the original BETWEEN ** term. That means that if the BETWEEN term is coded, the children are ** skipped. Or, if the children are satisfied by an index, the original ** BETWEEN term is skipped. */ else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){ ExprList *pList; int i; static const u8 ops[] = {TK_GE, TK_LE}; assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; assert( pList!=0 ); assert( pList->nExpr==2 ); for(i=0; i<2; i++){ Expr *pNewExpr; int idxNew; pNewExpr = sqlite3PExpr(pParse, ops[i], sqlite3ExprDup(db, pExpr->pLeft, 0), sqlite3ExprDup(db, pList->a[i].pExpr, 0)); transferJoinMarkings(pNewExpr, pExpr); idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); pTerm = &pWC->a[idxTerm]; markTermAsChild(pWC, idxNew, idxTerm); } } #endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */ #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) /* Analyze a term that is composed of two or more subterms connected by ** an OR operator. */ else if( pExpr->op==TK_OR ){ assert( pWC->op==TK_AND ); exprAnalyzeOrTerm(pSrc, pWC, idxTerm); pTerm = &pWC->a[idxTerm]; } #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ /* The form "x IS NOT NULL" can sometimes be evaluated more efficiently ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a ** virtual term of that form. ** ** The virtual term must be tagged with TERM_VNULL. */ else if( pExpr->op==TK_NOTNULL ){ if( pExpr->pLeft->op==TK_COLUMN && pExpr->pLeft->iColumn>=0 && !ExprHasProperty(pExpr, EP_OuterON) ){ Expr *pNewExpr; Expr *pLeft = pExpr->pLeft; int idxNew; WhereTerm *pNewTerm; pNewExpr = sqlite3PExpr(pParse, TK_GT, sqlite3ExprDup(db, pLeft, 0), sqlite3ExprAlloc(db, TK_NULL, 0, 0)); idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL); if( idxNew ){ pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = 0; pNewTerm->leftCursor = pLeft->iTable; pNewTerm->u.x.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_GT; markTermAsChild(pWC, idxNew, idxTerm); pTerm = &pWC->a[idxTerm]; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } } } #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION /* Add constraints to reduce the search space on a LIKE or GLOB ** operator. ** ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints ** ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%' ** ** The last character of the prefix "abc" is incremented to form the ** termination condition "abd". If case is not significant (the default ** for LIKE) then the lower-bound is made all uppercase and the upper- ** bound is made all lowercase so that the bounds also work when comparing ** BLOBs. */ else if( pExpr->op==TK_FUNCTION && pWC->op==TK_AND && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase) ){ Expr *pLeft; /* LHS of LIKE/GLOB operator */ Expr *pStr2; /* Copy of pStr1 - RHS of LIKE/GLOB operator */ Expr *pNewExpr1; Expr *pNewExpr2; int idxNew1; int idxNew2; const char *zCollSeqName; /* Name of collating sequence */ const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC; assert( ExprUseXList(pExpr) ); pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); assert( pStr1==0 || !ExprHasProperty(pStr1, EP_IntValue) ); assert( pStr2==0 || !ExprHasProperty(pStr2, EP_IntValue) ); /* Convert the lower bound to upper-case and the upper bound to ** lower-case (upper-case is less than lower-case in ASCII) so that ** the range constraints also work for BLOBs */ if( noCase && !pParse->db->mallocFailed ){ int i; char c; pTerm->wtFlags |= TERM_LIKE; for(i=0; (c = pStr1->u.zToken[i])!=0; i++){ pStr1->u.zToken[i] = sqlite3Toupper(c); pStr2->u.zToken[i] = sqlite3Tolower(c); } } if( !db->mallocFailed ){ u8 c, *pC; /* Last character before the first wildcard */ pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1]; c = *pC; if( noCase ){ /* The point is to increment the last character before the first ** wildcard. But if we increment '@', that will push it into the ** alphabetic range where case conversions will mess up the ** inequality. To avoid this, make sure to also run the full ** LIKE on all candidate expressions by clearing the isComplete flag */ if( c=='A'-1 ) isComplete = 0; c = sqlite3UpperToLower[c]; } *pC = c + 1; } zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY; pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), pStr1); transferJoinMarkings(pNewExpr1, pExpr); idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); testcase( idxNew1==0 ); pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), pStr2); transferJoinMarkings(pNewExpr2, pExpr); idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); testcase( idxNew2==0 ); exprAnalyze(pSrc, pWC, idxNew1); exprAnalyze(pSrc, pWC, idxNew2); pTerm = &pWC->a[idxTerm]; if( isComplete ){ markTermAsChild(pWC, idxNew1, idxTerm); markTermAsChild(pWC, idxNew2, idxTerm); } } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ /* If there is a vector == or IS term - e.g. "(a, b) == (?, ?)" - create ** new terms for each component comparison - "a = ?" and "b = ?". The ** new terms completely replace the original vector comparison, which is ** no longer used. ** ** This is only required if at least one side of the comparison operation ** is not a sub-select. ** ** tag-20220128a */ if( (pExpr->op==TK_EQ || pExpr->op==TK_IS) && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1 && sqlite3ExprVectorSize(pExpr->pRight)==nLeft && ( (pExpr->pLeft->flags & EP_xIsSelect)==0 || (pExpr->pRight->flags & EP_xIsSelect)==0) && pWC->op==TK_AND ){ int i; for(i=0; ipLeft, i, nLeft); Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i, nLeft); pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight); transferJoinMarkings(pNew, pExpr); idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC|TERM_SLICE); exprAnalyze(pSrc, pWC, idxNew); } pTerm = &pWC->a[idxTerm]; pTerm->wtFlags |= TERM_CODED|TERM_VIRTUAL; /* Disable the original */ pTerm->eOperator = WO_ROWVAL; } /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create ** a virtual term for each vector component. The expression object ** used by each such virtual term is pExpr (the full vector IN(...) ** expression). The WhereTerm.u.x.iField variable identifies the index within ** the vector on the LHS that the virtual term represents. ** ** This only works if the RHS is a simple SELECT (not a compound) that does ** not use window functions. */ else if( pExpr->op==TK_IN && pTerm->u.x.iField==0 && pExpr->pLeft->op==TK_VECTOR && ALWAYS( ExprUseXSelect(pExpr) ) && (pExpr->x.pSelect->pPrior==0 || (pExpr->x.pSelect->selFlags & SF_Values)) #ifndef SQLITE_OMIT_WINDOWFUNC && pExpr->x.pSelect->pWin==0 #endif && pWC->op==TK_AND ){ int i; for(i=0; ipLeft); i++){ int idxNew; idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL|TERM_SLICE); pWC->a[idxNew].u.x.iField = i+1; exprAnalyze(pSrc, pWC, idxNew); markTermAsChild(pWC, idxNew, idxTerm); } } #ifndef SQLITE_OMIT_VIRTUALTABLE /* Add a WO_AUX auxiliary term to the constraint set if the ** current expression is of the form "column OP expr" where OP ** is an operator that gets passed into virtual tables but which is ** not normally optimized for ordinary tables. In other words, OP ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL. ** This information is used by the xBestIndex methods of ** virtual tables. The native query optimizer does not attempt ** to do anything with MATCH functions. */ else if( pWC->op==TK_AND ){ Expr *pRight = 0, *pLeft = 0; int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight); while( res-- > 0 ){ int idxNew; WhereTerm *pNewTerm; Bitmask prereqColumn, prereqExpr; prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight); prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft); if( (prereqExpr & prereqColumn)==0 ){ Expr *pNewExpr; pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 0, sqlite3ExprDup(db, pRight, 0)); if( ExprHasProperty(pExpr, EP_OuterON) && pNewExpr ){ ExprSetProperty(pNewExpr, EP_OuterON); pNewExpr->w.iJoin = pExpr->w.iJoin; } idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = prereqExpr; pNewTerm->leftCursor = pLeft->iTable; pNewTerm->u.x.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_AUX; pNewTerm->eMatchOp = eOp2; markTermAsChild(pWC, idxNew, idxTerm); pTerm = &pWC->a[idxTerm]; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } SWAP(Expr*, pLeft, pRight); } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* Prevent ON clause terms of a LEFT JOIN from being used to drive ** an index for tables to the left of the join. */ testcase( pTerm!=&pWC->a[idxTerm] ); pTerm = &pWC->a[idxTerm]; pTerm->prereqRight |= extraRight; } /*************************************************************************** ** Routines with file scope above. Interface to the rest of the where.c ** subsystem follows. ***************************************************************************/ /* ** This routine identifies subexpressions in the WHERE clause where ** each subexpression is separated by the AND operator or some other ** operator specified in the op parameter. The WhereClause structure ** is filled with pointers to subexpressions. For example: ** ** WHERE a=='hello' AND coalesce(b,11)<10 AND (c+12!=d OR c==22) ** \________/ \_______________/ \________________/ ** slot[0] slot[1] slot[2] ** ** The original WHERE clause in pExpr is unaltered. All this routine ** does is make slot[] entries point to substructure within pExpr. ** ** In the previous sentence and in the diagram, "slot[]" refers to ** the WhereClause.a[] array. The slot[] array grows as needed to contain ** all terms of the WHERE clause. */ SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr); pWC->op = op; assert( pE2!=0 || pExpr==0 ); if( pE2==0 ) return; if( pE2->op!=op ){ whereClauseInsert(pWC, pExpr, 0); }else{ sqlite3WhereSplit(pWC, pE2->pLeft, op); sqlite3WhereSplit(pWC, pE2->pRight, op); } } /* ** Add either a LIMIT (if eMatchOp==SQLITE_INDEX_CONSTRAINT_LIMIT) or ** OFFSET (if eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET) term to the ** where-clause passed as the first argument. The value for the term ** is found in register iReg. ** ** In the common case where the value is a simple integer ** (example: "LIMIT 5 OFFSET 10") then the expression codes as a ** TK_INTEGER so that it will be available to sqlite3_vtab_rhs_value(). ** If not, then it codes as a TK_REGISTER expression. */ static void whereAddLimitExpr( WhereClause *pWC, /* Add the constraint to this WHERE clause */ int iReg, /* Register that will hold value of the limit/offset */ Expr *pExpr, /* Expression that defines the limit/offset */ int iCsr, /* Cursor to which the constraint applies */ int eMatchOp /* SQLITE_INDEX_CONSTRAINT_LIMIT or _OFFSET */ ){ Parse *pParse = pWC->pWInfo->pParse; sqlite3 *db = pParse->db; Expr *pNew; int iVal = 0; if( sqlite3ExprIsInteger(pExpr, &iVal) && iVal>=0 ){ Expr *pVal = sqlite3Expr(db, TK_INTEGER, 0); if( pVal==0 ) return; ExprSetProperty(pVal, EP_IntValue); pVal->u.iValue = iVal; pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal); }else{ Expr *pVal = sqlite3Expr(db, TK_REGISTER, 0); if( pVal==0 ) return; pVal->iTable = iReg; pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal); } if( pNew ){ WhereTerm *pTerm; int idx; idx = whereClauseInsert(pWC, pNew, TERM_DYNAMIC|TERM_VIRTUAL); pTerm = &pWC->a[idx]; pTerm->leftCursor = iCsr; pTerm->eOperator = WO_AUX; pTerm->eMatchOp = eMatchOp; } } /* ** Possibly add terms corresponding to the LIMIT and OFFSET clauses of the ** SELECT statement passed as the second argument. These terms are only ** added if: ** ** 1. The SELECT statement has a LIMIT clause, and ** 2. The SELECT statement is not an aggregate or DISTINCT query, and ** 3. The SELECT statement has exactly one object in its from clause, and ** that object is a virtual table, and ** 4. There are no terms in the WHERE clause that will not be passed ** to the virtual table xBestIndex method. ** 5. The ORDER BY clause, if any, will be made available to the xBestIndex ** method. ** ** LIMIT and OFFSET terms are ignored by most of the planner code. They ** exist only so that they may be passed to the xBestIndex method of the ** single virtual table in the FROM clause of the SELECT. */ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){ assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */ if( p->pGroupBy==0 && (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */ && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */ ){ ExprList *pOrderBy = p->pOrderBy; int iCsr = p->pSrc->a[0].iCursor; int ii; /* Check condition (4). Return early if it is not met. */ for(ii=0; iinTerm; ii++){ if( pWC->a[ii].wtFlags & TERM_CODED ){ /* This term is a vector operation that has been decomposed into ** other, subsequent terms. It can be ignored. See tag-20220128a */ assert( pWC->a[ii].wtFlags & TERM_VIRTUAL ); assert( pWC->a[ii].eOperator==WO_ROWVAL ); continue; } if( pWC->a[ii].nChild ){ /* If this term has child terms, then they are also part of the ** pWC->a[] array. So this term can be ignored, as a LIMIT clause ** will only be added if each of the child terms passes the ** (leftCursor==iCsr) test below. */ continue; } if( pWC->a[ii].leftCursor!=iCsr ) return; } /* Check condition (5). Return early if it is not met. */ if( pOrderBy ){ for(ii=0; iinExpr; ii++){ Expr *pExpr = pOrderBy->a[ii].pExpr; if( pExpr->op!=TK_COLUMN ) return; if( pExpr->iTable!=iCsr ) return; if( pOrderBy->a[ii].fg.sortFlags & KEYINFO_ORDER_BIGNULL ) return; } } /* All conditions are met. Add the terms to the where-clause object. */ assert( p->pLimit->op==TK_LIMIT ); whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft, iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT); if( p->iOffset>0 ){ whereAddLimitExpr(pWC, p->iOffset, p->pLimit->pRight, iCsr, SQLITE_INDEX_CONSTRAINT_OFFSET); } } } /* ** Initialize a preallocated WhereClause structure. */ SQLITE_PRIVATE void sqlite3WhereClauseInit( WhereClause *pWC, /* The WhereClause to be initialized */ WhereInfo *pWInfo /* The WHERE processing context */ ){ pWC->pWInfo = pWInfo; pWC->hasOr = 0; pWC->pOuter = 0; pWC->nTerm = 0; pWC->nBase = 0; pWC->nSlot = ArraySize(pWC->aStatic); pWC->a = pWC->aStatic; } /* ** Deallocate a WhereClause structure. The WhereClause structure ** itself is not freed. This routine is the inverse of ** sqlite3WhereClauseInit(). */ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){ sqlite3 *db = pWC->pWInfo->pParse->db; assert( pWC->nTerm>=pWC->nBase ); if( pWC->nTerm>0 ){ WhereTerm *a = pWC->a; WhereTerm *aLast = &pWC->a[pWC->nTerm-1]; #ifdef SQLITE_DEBUG int i; /* Verify that every term past pWC->nBase is virtual */ for(i=pWC->nBase; inTerm; i++){ assert( (pWC->a[i].wtFlags & TERM_VIRTUAL)!=0 ); } #endif while(1){ assert( a->eMatchOp==0 || a->eOperator==WO_AUX ); if( a->wtFlags & TERM_DYNAMIC ){ sqlite3ExprDelete(db, a->pExpr); } if( a->wtFlags & (TERM_ORINFO|TERM_ANDINFO) ){ if( a->wtFlags & TERM_ORINFO ){ assert( (a->wtFlags & TERM_ANDINFO)==0 ); whereOrInfoDelete(db, a->u.pOrInfo); }else{ assert( (a->wtFlags & TERM_ANDINFO)!=0 ); whereAndInfoDelete(db, a->u.pAndInfo); } } if( a==aLast ) break; a++; } } } /* ** These routines walk (recursively) an expression tree and generate ** a bitmask indicating which tables are used in that expression ** tree. ** ** sqlite3WhereExprUsage(MaskSet, Expr) -> ** ** Return a Bitmask of all tables referenced by Expr. Expr can be ** be NULL, in which case 0 is returned. ** ** sqlite3WhereExprUsageNN(MaskSet, Expr) -> ** ** Same as sqlite3WhereExprUsage() except that Expr must not be ** NULL. The "NN" suffix on the name stands for "Not Null". ** ** sqlite3WhereExprListUsage(MaskSet, ExprList) -> ** ** Return a Bitmask of all tables referenced by every expression ** in the expression list ExprList. ExprList can be NULL, in which ** case 0 is returned. ** ** sqlite3WhereExprUsageFull(MaskSet, ExprList) -> ** ** Internal use only. Called only by sqlite3WhereExprUsageNN() for ** complex expressions that require pushing register values onto ** the stack. Many calls to sqlite3WhereExprUsageNN() do not need ** the more complex analysis done by this routine. Hence, the ** computations done by this routine are broken out into a separate ** "no-inline" function to avoid the stack push overhead in the ** common case where it is not needed. */ static SQLITE_NOINLINE Bitmask sqlite3WhereExprUsageFull( WhereMaskSet *pMaskSet, Expr *p ){ Bitmask mask; mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0; if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft); if( p->pRight ){ mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight); assert( p->x.pList==0 ); }else if( ExprUseXSelect(p) ){ if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1; mask |= exprSelectUsage(pMaskSet, p->x.pSelect); }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); } #ifndef SQLITE_OMIT_WINDOWFUNC if( (p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION) && ExprUseYWin(p) ){ assert( p->y.pWin!=0 ); mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition); mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy); mask |= sqlite3WhereExprUsage(pMaskSet, p->y.pWin->pFilter); } #endif return mask; } SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){ if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){ return sqlite3WhereGetMask(pMaskSet, p->iTable); }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ assert( p->op!=TK_IF_NULL_ROW ); return 0; } return sqlite3WhereExprUsageFull(pMaskSet, p); } SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0; } SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){ int i; Bitmask mask = 0; if( pList ){ for(i=0; inExpr; i++){ mask |= sqlite3WhereExprUsage(pMaskSet, pList->a[i].pExpr); } } return mask; } /* ** Call exprAnalyze on all terms in a WHERE clause. ** ** Note that exprAnalyze() might add new virtual terms onto the ** end of the WHERE clause. We do not want to analyze these new ** virtual terms, so start analyzing at the end and work forward ** so that the added virtual terms are never processed. */ SQLITE_PRIVATE void sqlite3WhereExprAnalyze( SrcList *pTabList, /* the FROM clause */ WhereClause *pWC /* the WHERE clause to be analyzed */ ){ int i; for(i=pWC->nTerm-1; i>=0; i--){ exprAnalyze(pTabList, pWC, i); } } /* ** For table-valued-functions, transform the function arguments into ** new WHERE clause terms. ** ** Each function argument translates into an equality constraint against ** a HIDDEN column in the table. */ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( Parse *pParse, /* Parsing context */ SrcItem *pItem, /* The FROM clause term to process */ WhereClause *pWC /* Xfer function arguments to here */ ){ Table *pTab; int j, k; ExprList *pArgs; Expr *pColRef; Expr *pTerm; if( pItem->fg.isTabFunc==0 ) return; pTab = pItem->pTab; assert( pTab!=0 ); pArgs = pItem->u1.pFuncArg; if( pArgs==0 ) return; for(j=k=0; jnExpr; j++){ Expr *pRhs; u32 joinType; while( knCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;} if( k>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d", pTab->zName, j); return; } pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0); if( pColRef==0 ) return; pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; assert( ExprUseYTab(pColRef) ); pColRef->y.pTab = pTab; pItem->colUsed |= sqlite3ExprColUsed(pColRef); pRhs = sqlite3PExpr(pParse, TK_UPLUS, sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); if( pItem->fg.jointype & (JT_LEFT|JT_RIGHT) ){ testcase( pItem->fg.jointype & JT_LEFT ); /* testtag-20230227a */ testcase( pItem->fg.jointype & JT_RIGHT ); /* testtag-20230227b */ joinType = EP_OuterON; }else{ testcase( pItem->fg.jointype & JT_LTORJ ); /* testtag-20230227c */ joinType = EP_InnerON; } sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } /************** End of whereexpr.c *******************************************/ /************** Begin file where.c *******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. This module is responsible for ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". */ /* #include "sqliteInt.h" */ /* #include "whereInt.h" */ /* ** Extra information appended to the end of sqlite3_index_info but not ** visible to the xBestIndex function, at least not directly. The ** sqlite3_vtab_collation() interface knows how to reach it, however. ** ** This object is not an API and can be changed from one release to the ** next. As long as allocateIndexInfo() and sqlite3_vtab_collation() ** agree on the structure, all will be well. */ typedef struct HiddenIndexInfo HiddenIndexInfo; struct HiddenIndexInfo { WhereClause *pWC; /* The Where clause being analyzed */ Parse *pParse; /* The parsing context */ int eDistinct; /* Value to return from sqlite3_vtab_distinct() */ u32 mIn; /* Mask of terms that are IN (...) */ u32 mHandleIn; /* Terms that vtab will handle as IN (...) */ sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST ** because extra space is allocated to hold up ** to nTerm such values */ }; /* Forward declaration of methods */ static int whereLoopResize(sqlite3*, WhereLoop*, int); /* ** Return the estimated number of output rows from a WHERE clause */ SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo *pWInfo){ return pWInfo->nRowOut; } /* ** Return one of the WHERE_DISTINCT_xxxxx values to indicate how this ** WHERE clause returns outputs for DISTINCT processing. */ SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){ return pWInfo->eDistinct; } /* ** Return the number of ORDER BY terms that are satisfied by the ** WHERE clause. A return of 0 means that the output must be ** completely sorted. A return equal to the number of ORDER BY ** terms means that no sorting is needed at all. A return that ** is positive but less than the number of ORDER BY terms means that ** block sorting is required. */ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat<0 ? 0 : pWInfo->nOBSat; } /* ** In the ORDER BY LIMIT optimization, if the inner-most loop is known ** to emit rows in increasing order, and if the last row emitted by the ** inner-most loop did not fit within the sorter, then we can skip all ** subsequent rows for the current iteration of the inner loop (because they ** will not fit in the sorter either) and continue with the second inner ** loop - the loop immediately outside the inner-most. ** ** When a row does not fit in the sorter (because the sorter already ** holds LIMIT+OFFSET rows that are smaller), then a jump is made to the ** label returned by this function. ** ** If the ORDER BY LIMIT optimization applies, the jump destination should ** be the continuation for the second-inner-most loop. If the ORDER BY ** LIMIT optimization does not apply, then the jump destination should ** be the continuation for the inner-most loop. ** ** It is always safe for this routine to return the continuation of the ** inner-most loop, in the sense that a correct answer will result. ** Returning the continuation the second inner loop is an optimization ** that might make the code run a little faster, but should not change ** the final answer. */ SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){ WhereLevel *pInner; if( !pWInfo->bOrderedInnerLoop ){ /* The ORDER BY LIMIT optimization does not apply. Jump to the ** continuation of the inner-most loop. */ return pWInfo->iContinue; } pInner = &pWInfo->a[pWInfo->nLevel-1]; assert( pInner->addrNxt!=0 ); return pInner->pRJ ? pWInfo->iContinue : pInner->addrNxt; } /* ** While generating code for the min/max optimization, after handling ** the aggregate-step call to min() or max(), check to see if any ** additional looping is required. If the output order is such that ** we are certain that the correct answer has already been found, then ** code an OP_Goto to by pass subsequent processing. ** ** Any extra OP_Goto that is coded here is an optimization. The ** correct answer should be obtained regardless. This OP_Goto just ** makes the answer appear faster. */ SQLITE_PRIVATE void sqlite3WhereMinMaxOptEarlyOut(Vdbe *v, WhereInfo *pWInfo){ WhereLevel *pInner; int i; if( !pWInfo->bOrderedInnerLoop ) return; if( pWInfo->nOBSat==0 ) return; for(i=pWInfo->nLevel-1; i>=0; i--){ pInner = &pWInfo->a[i]; if( (pInner->pWLoop->wsFlags & WHERE_COLUMN_IN)!=0 ){ sqlite3VdbeGoto(v, pInner->addrNxt); return; } } sqlite3VdbeGoto(v, pWInfo->iBreak); } /* ** Return the VDBE address or label to jump to in order to continue ** immediately with the next row of a WHERE clause. */ SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){ assert( pWInfo->iContinue!=0 ); return pWInfo->iContinue; } /* ** Return the VDBE address or label to jump to in order to break ** out of a WHERE loop. */ SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){ return pWInfo->iBreak; } /* ** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to ** operate directly on the rowids returned by a WHERE clause. Return ** ONEPASS_SINGLE (1) if the statement can operation directly because only ** a single row is to be changed. Return ONEPASS_MULTI (2) if the one-pass ** optimization can be used on multiple ** ** If the ONEPASS optimization is used (if this routine returns true) ** then also write the indices of open cursors used by ONEPASS ** into aiCur[0] and aiCur[1]. iaCur[0] gets the cursor of the data ** table and iaCur[1] gets the cursor used by an auxiliary index. ** Either value may be -1, indicating that cursor is not used. ** Any cursors returned will have been opened for writing. ** ** aiCur[0] and aiCur[1] both get -1 if the where-clause logic is ** unable to use the ONEPASS optimization. */ SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){ memcpy(aiCur, pWInfo->aiCurOnePass, sizeof(int)*2); #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace && pWInfo->eOnePass!=ONEPASS_OFF ){ sqlite3DebugPrintf("%s cursors: %d %d\n", pWInfo->eOnePass==ONEPASS_SINGLE ? "ONEPASS_SINGLE" : "ONEPASS_MULTI", aiCur[0], aiCur[1]); } #endif return pWInfo->eOnePass; } /* ** Return TRUE if the WHERE loop uses the OP_DeferredSeek opcode to move ** the data cursor to the row selected by the index cursor. */ SQLITE_PRIVATE int sqlite3WhereUsesDeferredSeek(WhereInfo *pWInfo){ return pWInfo->bDeferredSeek; } /* ** Move the content of pSrc into pDest */ static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){ pDest->n = pSrc->n; memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0])); } /* ** Try to insert a new prerequisite/cost entry into the WhereOrSet pSet. ** ** The new entry might overwrite an existing entry, or it might be ** appended, or it might be discarded. Do whatever is the right thing ** so that pSet keeps the N_OR_COST best entries seen so far. */ static int whereOrInsert( WhereOrSet *pSet, /* The WhereOrSet to be updated */ Bitmask prereq, /* Prerequisites of the new entry */ LogEst rRun, /* Run-cost of the new entry */ LogEst nOut /* Number of outputs for the new entry */ ){ u16 i; WhereOrCost *p; for(i=pSet->n, p=pSet->a; i>0; i--, p++){ if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){ goto whereOrInsert_done; } if( p->rRun<=rRun && (p->prereq & prereq)==p->prereq ){ return 0; } } if( pSet->na[pSet->n++]; p->nOut = nOut; }else{ p = pSet->a; for(i=1; in; i++){ if( p->rRun>pSet->a[i].rRun ) p = pSet->a + i; } if( p->rRun<=rRun ) return 0; } whereOrInsert_done: p->prereq = prereq; p->rRun = rRun; if( p->nOut>nOut ) p->nOut = nOut; return 1; } /* ** Return the bitmask for the given cursor number. Return 0 if ** iCursor is not in the set. */ SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){ int i; assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 ); assert( pMaskSet->n>0 || pMaskSet->ix[0]<0 ); assert( iCursor>=-1 ); if( pMaskSet->ix[0]==iCursor ){ return 1; } for(i=1; in; i++){ if( pMaskSet->ix[i]==iCursor ){ return MASKBIT(i); } } return 0; } /* Allocate memory that is automatically freed when pWInfo is freed. */ SQLITE_PRIVATE void *sqlite3WhereMalloc(WhereInfo *pWInfo, u64 nByte){ WhereMemBlock *pBlock; pBlock = sqlite3DbMallocRawNN(pWInfo->pParse->db, nByte+sizeof(*pBlock)); if( pBlock ){ pBlock->pNext = pWInfo->pMemToFree; pBlock->sz = nByte; pWInfo->pMemToFree = pBlock; pBlock++; } return (void*)pBlock; } SQLITE_PRIVATE void *sqlite3WhereRealloc(WhereInfo *pWInfo, void *pOld, u64 nByte){ void *pNew = sqlite3WhereMalloc(pWInfo, nByte); if( pNew && pOld ){ WhereMemBlock *pOldBlk = (WhereMemBlock*)pOld; pOldBlk--; assert( pOldBlk->szsz); } return pNew; } /* ** Create a new mask for cursor iCursor. ** ** There is one cursor per table in the FROM clause. The number of ** tables in the FROM clause is limited by a test early in the ** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[] ** array will never overflow. */ static void createMask(WhereMaskSet *pMaskSet, int iCursor){ assert( pMaskSet->n < ArraySize(pMaskSet->ix) ); pMaskSet->ix[pMaskSet->n++] = iCursor; } /* ** If the right-hand branch of the expression is a TK_COLUMN, then return ** a pointer to the right-hand branch. Otherwise, return NULL. */ static Expr *whereRightSubexprIsColumn(Expr *p){ p = sqlite3ExprSkipCollateAndLikely(p->pRight); if( ALWAYS(p!=0) && p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){ return p; } return 0; } /* ** Advance to the next WhereTerm that matches according to the criteria ** established when the pScan object was initialized by whereScanInit(). ** Return NULL if there are no more matching WhereTerms. */ static WhereTerm *whereScanNext(WhereScan *pScan){ int iCur; /* The cursor on the LHS of the term */ i16 iColumn; /* The column on the LHS of the term. -1 for IPK */ Expr *pX; /* An expression being tested */ WhereClause *pWC; /* Shorthand for pScan->pWC */ WhereTerm *pTerm; /* The term being tested */ int k = pScan->k; /* Where to start scanning */ assert( pScan->iEquiv<=pScan->nEquiv ); pWC = pScan->pWC; while(1){ iColumn = pScan->aiColumn[pScan->iEquiv-1]; iCur = pScan->aiCur[pScan->iEquiv-1]; assert( pWC!=0 ); assert( iCur>=0 ); do{ for(pTerm=pWC->a+k; knTerm; k++, pTerm++){ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 || pTerm->leftCursor<0 ); if( pTerm->leftCursor==iCur && pTerm->u.x.leftColumn==iColumn && (iColumn!=XN_EXPR || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft, pScan->pIdxExpr,iCur)==0) && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_OuterON)) ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquivaiCur) && (pX = whereRightSubexprIsColumn(pTerm->pExpr))!=0 ){ int j; for(j=0; jnEquiv; j++){ if( pScan->aiCur[j]==pX->iTable && pScan->aiColumn[j]==pX->iColumn ){ break; } } if( j==pScan->nEquiv ){ pScan->aiCur[j] = pX->iTable; pScan->aiColumn[j] = pX->iColumn; pScan->nEquiv++; } } if( (pTerm->eOperator & pScan->opMask)!=0 ){ /* Verify the affinity and collating sequence match */ if( pScan->zCollName && (pTerm->eOperator & WO_ISNULL)==0 ){ CollSeq *pColl; Parse *pParse = pWC->pWInfo->pParse; pX = pTerm->pExpr; if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ continue; } assert(pX->pLeft); pColl = sqlite3ExprCompareCollSeq(pParse, pX); if( pColl==0 ) pColl = pParse->db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ continue; } } if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0 && (pX = pTerm->pExpr->pRight, ALWAYS(pX!=0)) && pX->op==TK_COLUMN && pX->iTable==pScan->aiCur[0] && pX->iColumn==pScan->aiColumn[0] ){ testcase( pTerm->eOperator & WO_IS ); continue; } pScan->pWC = pWC; pScan->k = k+1; #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x20000 ){ int ii; sqlite3DebugPrintf("SCAN-TERM %p: nEquiv=%d", pTerm, pScan->nEquiv); for(ii=0; iinEquiv; ii++){ sqlite3DebugPrintf(" {%d:%d}", pScan->aiCur[ii], pScan->aiColumn[ii]); } sqlite3DebugPrintf("\n"); } #endif return pTerm; } } } pWC = pWC->pOuter; k = 0; }while( pWC!=0 ); if( pScan->iEquiv>=pScan->nEquiv ) break; pWC = pScan->pOrigWC; k = 0; pScan->iEquiv++; } return 0; } /* ** This is whereScanInit() for the case of an index on an expression. ** It is factored out into a separate tail-recursion subroutine so that ** the normal whereScanInit() routine, which is a high-runner, does not ** need to push registers onto the stack as part of its prologue. */ static SQLITE_NOINLINE WhereTerm *whereScanInitIndexExpr(WhereScan *pScan){ pScan->idxaff = sqlite3ExprAffinity(pScan->pIdxExpr); return whereScanNext(pScan); } /* ** Initialize a WHERE clause scanner object. Return a pointer to the ** first match. Return NULL if there are no matches. ** ** The scanner will be searching the WHERE clause pWC. It will look ** for terms of the form "X " where X is column iColumn of table ** iCur. Or if pIdx!=0 then X is column iColumn of index pIdx. pIdx ** must be one of the indexes of table iCur. ** ** The must be one of the operators described by opMask. ** ** If the search is for X and the WHERE clause contains terms of the ** form X=Y then this routine might also return terms of the form ** "Y ". The number of levels of transitivity is limited, ** but is enough to handle most commonly occurring SQL statements. ** ** If X is not the INTEGER PRIMARY KEY then X must be compatible with ** index pIdx. */ static WhereTerm *whereScanInit( WhereScan *pScan, /* The WhereScan object being initialized */ WhereClause *pWC, /* The WHERE clause to be scanned */ int iCur, /* Cursor to scan for */ int iColumn, /* Column to scan for */ u32 opMask, /* Operator(s) to scan for */ Index *pIdx /* Must be compatible with this index */ ){ pScan->pOrigWC = pWC; pScan->pWC = pWC; pScan->pIdxExpr = 0; pScan->idxaff = 0; pScan->zCollName = 0; pScan->opMask = opMask; pScan->k = 0; pScan->aiCur[0] = iCur; pScan->nEquiv = 1; pScan->iEquiv = 1; if( pIdx ){ int j = iColumn; iColumn = pIdx->aiColumn[j]; if( iColumn==pIdx->pTable->iPKey ){ iColumn = XN_ROWID; }else if( iColumn>=0 ){ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; pScan->zCollName = pIdx->azColl[j]; }else if( iColumn==XN_EXPR ){ pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; pScan->zCollName = pIdx->azColl[j]; pScan->aiColumn[0] = XN_EXPR; return whereScanInitIndexExpr(pScan); } }else if( iColumn==XN_EXPR ){ return 0; } pScan->aiColumn[0] = iColumn; return whereScanNext(pScan); } /* ** Search for a term in the WHERE clause that is of the form "X " ** where X is a reference to the iColumn of table iCur or of index pIdx ** if pIdx!=0 and is one of the WO_xx operator codes specified by ** the op parameter. Return a pointer to the term. Return 0 if not found. ** ** If pIdx!=0 then it must be one of the indexes of table iCur. ** Search for terms matching the iColumn-th column of pIdx ** rather than the iColumn-th column of table iCur. ** ** The term returned might by Y= if there is another constraint in ** the WHERE clause that specifies that X=Y. Any such constraints will be ** identified by the WO_EQUIV bit in the pTerm->eOperator field. The ** aiCur[]/iaColumn[] arrays hold X and all its equivalents. There are 11 ** slots in aiCur[]/aiColumn[] so that means we can look for X plus up to 10 ** other equivalent values. Hence a search for X will return if X=A1 ** and A1=A2 and A2=A3 and ... and A9=A10 and A10=. ** ** If there are multiple terms in the WHERE clause of the form "X " ** then try for the one with no dependencies on - in other words where ** is a constant expression of some kind. Only return entries of ** the form "X Y" where Y is a column in another table if no terms of ** the form "X " exist. If no terms with a constant RHS ** exist, try to return a term that does not use WO_EQUIV. */ SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ ){ WhereTerm *pResult = 0; WhereTerm *p; WhereScan scan; p = whereScanInit(&scan, pWC, iCur, iColumn, op, pIdx); op &= WO_EQ|WO_IS; while( p ){ if( (p->prereqRight & notReady)==0 ){ if( p->prereqRight==0 && (p->eOperator&op)!=0 ){ testcase( p->eOperator & WO_IS ); return p; } if( pResult==0 ) pResult = p; } p = whereScanNext(&scan); } return pResult; } /* ** This function searches pList for an entry that matches the iCol-th column ** of index pIdx. ** ** If such an expression is found, its index in pList->a[] is returned. If ** no expression is found, -1 is returned. */ static int findIndexCol( Parse *pParse, /* Parse context */ ExprList *pList, /* Expression list to search */ int iBase, /* Cursor for table associated with pIdx */ Index *pIdx, /* Index to match column of */ int iCol /* Column of index to match */ ){ int i; const char *zColl = pIdx->azColl[iCol]; for(i=0; inExpr; i++){ Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr); if( ALWAYS(p!=0) && (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN) && p->iColumn==pIdx->aiColumn[iCol] && p->iTable==iBase ){ CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr); if( 0==sqlite3StrICmp(pColl->zName, zColl) ){ return i; } } } return -1; } /* ** Return TRUE if the iCol-th column of index pIdx is NOT NULL */ static int indexColumnNotNull(Index *pIdx, int iCol){ int j; assert( pIdx!=0 ); assert( iCol>=0 && iColnColumn ); j = pIdx->aiColumn[iCol]; if( j>=0 ){ return pIdx->pTable->aCol[j].notNull; }else if( j==(-1) ){ return 1; }else{ assert( j==(-2) ); return 0; /* Assume an indexed expression can always yield a NULL */ } } /* ** Return true if the DISTINCT expression-list passed as the third argument ** is redundant. ** ** A DISTINCT list is redundant if any subset of the columns in the ** DISTINCT list are collectively unique and individually non-null. */ static int isDistinctRedundant( Parse *pParse, /* Parsing context */ SrcList *pTabList, /* The FROM clause */ WhereClause *pWC, /* The WHERE clause */ ExprList *pDistinct /* The result set that needs to be DISTINCT */ ){ Table *pTab; Index *pIdx; int i; int iBase; /* If there is more than one table or sub-select in the FROM clause of ** this query, then it will not be possible to show that the DISTINCT ** clause is redundant. */ if( pTabList->nSrc!=1 ) return 0; iBase = pTabList->a[0].iCursor; pTab = pTabList->a[0].pTab; /* If any of the expressions is an IPK column on table iBase, then return ** true. Note: The (p->iTable==iBase) part of this test may be false if the ** current SELECT is a correlated sub-query. */ for(i=0; inExpr; i++){ Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr); if( NEVER(p==0) ) continue; if( p->op!=TK_COLUMN && p->op!=TK_AGG_COLUMN ) continue; if( p->iTable==iBase && p->iColumn<0 ) return 1; } /* Loop through all indices on the table, checking each to see if it makes ** the DISTINCT qualifier redundant. It does so if: ** ** 1. The index is itself UNIQUE, and ** ** 2. All of the columns in the index are either part of the pDistinct ** list, or else the WHERE clause contains a term of the form "col=X", ** where X is a constant value. The collation sequences of the ** comparison and select-list expressions must match those of the index. ** ** 3. All of those index columns for which the WHERE clause does not ** contain a "col=X" term are subject to a NOT NULL constraint. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( !IsUniqueIndex(pIdx) ) continue; if( pIdx->pPartIdxWhere ) continue; for(i=0; inKeyCol; i++){ if( 0==sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask)0, WO_EQ, pIdx) ){ if( findIndexCol(pParse, pDistinct, iBase, pIdx, i)<0 ) break; if( indexColumnNotNull(pIdx, i)==0 ) break; } } if( i==pIdx->nKeyCol ){ /* This index implies that the DISTINCT qualifier is redundant. */ return 1; } } return 0; } /* ** Estimate the logarithm of the input value to base 2. */ static LogEst estLog(LogEst N){ return N<=10 ? 0 : sqlite3LogEst(N) - 33; } /* ** Convert OP_Column opcodes to OP_Copy in previously generated code. ** ** This routine runs over generated VDBE code and translates OP_Column ** opcodes into OP_Copy when the table is being accessed via co-routine ** instead of via table lookup. ** ** If the iAutoidxCur is not zero, then any OP_Rowid instructions on ** cursor iTabCur are transformed into OP_Sequence opcode for the ** iAutoidxCur cursor, in order to generate unique rowids for the ** automatic index being generated. */ static void translateColumnToCopy( Parse *pParse, /* Parsing context */ int iStart, /* Translate from this opcode to the end */ int iTabCur, /* OP_Column/OP_Rowid references to this table */ int iRegister, /* The first column is in this register */ int iAutoidxCur /* If non-zero, cursor of autoindex being generated */ ){ Vdbe *v = pParse->pVdbe; VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart); int iEnd = sqlite3VdbeCurrentAddr(v); if( pParse->db->mallocFailed ) return; for(; iStartp1!=iTabCur ) continue; if( pOp->opcode==OP_Column ){ #ifdef SQLITE_DEBUG if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ printf("TRANSLATE OP_Column to OP_Copy at %d\n", iStart); } #endif pOp->opcode = OP_Copy; pOp->p1 = pOp->p2 + iRegister; pOp->p2 = pOp->p3; pOp->p3 = 0; pOp->p5 = 2; /* Cause the MEM_Subtype flag to be cleared */ }else if( pOp->opcode==OP_Rowid ){ #ifdef SQLITE_DEBUG if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ printf("TRANSLATE OP_Rowid to OP_Sequence at %d\n", iStart); } #endif pOp->opcode = OP_Sequence; pOp->p1 = iAutoidxCur; #ifdef SQLITE_ALLOW_ROWID_IN_VIEW if( iAutoidxCur==0 ){ pOp->opcode = OP_Null; pOp->p3 = 0; } #endif } } } /* ** Two routines for printing the content of an sqlite3_index_info ** structure. Used for testing and debugging only. If neither ** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines ** are no-ops. */ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED) static void whereTraceIndexInfoInputs(sqlite3_index_info *p){ int i; if( (sqlite3WhereTrace & 0x10)==0 ) return; for(i=0; inConstraint; i++){ sqlite3DebugPrintf( " constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n", i, p->aConstraint[i].iColumn, p->aConstraint[i].iTermOffset, p->aConstraint[i].op, p->aConstraint[i].usable, sqlite3_vtab_collation(p,i)); } for(i=0; inOrderBy; i++){ sqlite3DebugPrintf(" orderby[%d]: col=%d desc=%d\n", i, p->aOrderBy[i].iColumn, p->aOrderBy[i].desc); } } static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){ int i; if( (sqlite3WhereTrace & 0x10)==0 ) return; for(i=0; inConstraint; i++){ sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n", i, p->aConstraintUsage[i].argvIndex, p->aConstraintUsage[i].omit); } sqlite3DebugPrintf(" idxNum=%d\n", p->idxNum); sqlite3DebugPrintf(" idxStr=%s\n", p->idxStr); sqlite3DebugPrintf(" orderByConsumed=%d\n", p->orderByConsumed); sqlite3DebugPrintf(" estimatedCost=%g\n", p->estimatedCost); sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows); } #else #define whereTraceIndexInfoInputs(A) #define whereTraceIndexInfoOutputs(A) #endif /* ** We know that pSrc is an operand of an outer join. Return true if ** pTerm is a constraint that is compatible with that join. ** ** pTerm must be EP_OuterON if pSrc is the right operand of an ** outer join. pTerm can be either EP_OuterON or EP_InnerON if pSrc ** is the left operand of a RIGHT join. ** ** See https://sqlite.org/forum/forumpost/206d99a16dd9212f ** for an example of a WHERE clause constraints that may not be used on ** the right table of a RIGHT JOIN because the constraint implies a ** not-NULL condition on the left table of the RIGHT JOIN. */ static int constraintCompatibleWithOuterJoin( const WhereTerm *pTerm, /* WHERE clause term to check */ const SrcItem *pSrc /* Table we are trying to access */ ){ assert( (pSrc->fg.jointype&(JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ); /* By caller */ testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT ); testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ ); testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) ); if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON) || pTerm->pExpr->w.iJoin != pSrc->iCursor ){ return 0; } if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0 && ExprHasProperty(pTerm->pExpr, EP_InnerON) ){ return 0; } return 1; } #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* ** Return TRUE if the WHERE clause term pTerm is of a form where it ** could be used with an index to access pSrc, assuming an appropriate ** index existed. */ static int termCanDriveIndex( const WhereTerm *pTerm, /* WHERE clause term to check */ const SrcItem *pSrc, /* Table we are trying to access */ const Bitmask notReady /* Tables in outer loops of the join */ ){ char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0; assert( (pSrc->fg.jointype & JT_RIGHT)==0 ); if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 && !constraintCompatibleWithOuterJoin(pTerm,pSrc) ){ return 0; /* See https://sqlite.org/forum/forumpost/51e6959f61 */ } if( (pTerm->prereqRight & notReady)!=0 ) return 0; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); if( pTerm->u.x.leftColumn<0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.x.leftColumn].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; testcase( pTerm->pExpr->op==TK_IS ); return 1; } #endif #ifndef SQLITE_OMIT_AUTOMATIC_INDEX #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Argument pIdx represents an automatic index that the current statement ** will create and populate. Add an OP_Explain with text of the form: ** ** CREATE AUTOMATIC INDEX ON
    () [WHERE ] ** ** This is only required if sqlite3_stmt_scanstatus() is enabled, to ** associate an SQLITE_SCANSTAT_NCYCLE and SQLITE_SCANSTAT_NLOOP ** values with. In order to avoid breaking legacy code and test cases, ** the OP_Explain is not added if this is an EXPLAIN QUERY PLAN command. */ static void explainAutomaticIndex( Parse *pParse, Index *pIdx, /* Automatic index to explain */ int bPartial, /* True if pIdx is a partial index */ int *pAddrExplain /* OUT: Address of OP_Explain */ ){ if( IS_STMT_SCANSTATUS(pParse->db) && pParse->explain!=2 ){ Table *pTab = pIdx->pTable; const char *zSep = ""; char *zText = 0; int ii = 0; sqlite3_str *pStr = sqlite3_str_new(pParse->db); sqlite3_str_appendf(pStr,"CREATE AUTOMATIC INDEX ON %s(", pTab->zName); assert( pIdx->nColumn>1 ); assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID ); for(ii=0; ii<(pIdx->nColumn-1); ii++){ const char *zName = 0; int iCol = pIdx->aiColumn[ii]; zName = pTab->aCol[iCol].zCnName; sqlite3_str_appendf(pStr, "%s%s", zSep, zName); zSep = ", "; } zText = sqlite3_str_finish(pStr); if( zText==0 ){ sqlite3OomFault(pParse->db); }else{ *pAddrExplain = sqlite3VdbeExplain( pParse, 0, "%s)%s", zText, (bPartial ? " WHERE " : "") ); sqlite3_free(zText); } } } #else # define explainAutomaticIndex(a,b,c,d) #endif /* ** Generate code to construct the Index object for an automatic index ** and to set up the WhereLevel object pLevel so that the code generator ** makes use of the automatic index. */ static SQLITE_NOINLINE void constructAutomaticIndex( Parse *pParse, /* The parsing context */ WhereClause *pWC, /* The WHERE clause */ const Bitmask notReady, /* Mask of cursors that are not available */ WhereLevel *pLevel /* Write new index here */ ){ int nKeyCol; /* Number of columns in the constructed index */ WhereTerm *pTerm; /* A single term of the WHERE clause */ WhereTerm *pWCEnd; /* End of pWC->a[] */ Index *pIdx; /* Object describing the transient index */ Vdbe *v; /* Prepared statement under construction */ int addrInit; /* Address of the initialization bypass jump */ Table *pTable; /* The table being indexed */ int addrTop; /* Top of the index fill loop */ int regRecord; /* Register holding an index record */ int n; /* Column counter */ int i; /* Loop counter */ int mxBitCol; /* Maximum column in pSrc->colUsed */ CollSeq *pColl; /* Collating sequence to on a column */ WhereLoop *pLoop; /* The Loop object */ char *zNotUsed; /* Extra space on the end of pIdx */ Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ u8 sentWarning = 0; /* True if a warning has been issued */ u8 useBloomFilter = 0; /* True to also add a Bloom filter */ Expr *pPartial = 0; /* Partial Index Expression */ int iContinue = 0; /* Jump here to skip excluded rows */ SrcList *pTabList; /* The complete FROM clause */ SrcItem *pSrc; /* The FROM clause term to get the next index */ int addrCounter = 0; /* Address where integer counter is initialized */ int regBase; /* Array of registers where record is assembled */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrExp = 0; /* Address of OP_Explain */ #endif /* Generate code to skip over the creation and initialization of the ** transient index on 2nd and subsequent iterations of the loop. */ v = pParse->pVdbe; assert( v!=0 ); addrInit = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); /* Count the number of columns that will be added to the index ** and used to match WHERE clause constraints */ nKeyCol = 0; pTabList = pWC->pWInfo->pTabList; pSrc = &pTabList->a[pLevel->iFrom]; pTable = pSrc->pTab; pWCEnd = &pWC->a[pWC->nTerm]; pLoop = pLevel->pWLoop; idxCols = 0; for(pTerm=pWC->a; pTermpExpr; /* Make the automatic index a partial index if there are terms in the ** WHERE clause (or the ON clause of a LEFT join) that constrain which ** rows of the target table (pSrc) that can be used. */ if( (pTerm->wtFlags & TERM_VIRTUAL)==0 && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom) ){ pPartial = sqlite3ExprAnd(pParse, pPartial, sqlite3ExprDup(pParse->db, pExpr, 0)); } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ int iCol; Bitmask cMask; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); iCol = pTerm->u.x.leftColumn; cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS ); testcase( iCol==BMS-1 ); if( !sentWarning ){ sqlite3_log(SQLITE_WARNING_AUTOINDEX, "automatic index on %s(%s)", pTable->zName, pTable->aCol[iCol].zCnName); sentWarning = 1; } if( (idxCols & cMask)==0 ){ if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ){ goto end_auto_index_create; } pLoop->aLTerm[nKeyCol++] = pTerm; idxCols |= cMask; } } } assert( nKeyCol>0 || pParse->db->mallocFailed ); pLoop->u.btree.nEq = pLoop->nLTerm = nKeyCol; pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED | WHERE_AUTO_INDEX; /* Count the number of additional columns needed to create a ** covering index. A "covering index" is an index that contains all ** columns that are needed by the query. With a covering index, the ** original table never needs to be accessed. Automatic indices must ** be a covering index because the index will not be updated if the ** original table changes and the index and table cannot both be used ** if they go out of sync. */ if( IsView(pTable) ){ extraCols = ALLBITS; }else{ extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); } mxBitCol = MIN(BMS-1,pTable->nCol); testcase( pTable->nCol==BMS-1 ); testcase( pTable->nCol==BMS-2 ); for(i=0; icolUsed & MASKBIT(BMS-1) ){ nKeyCol += pTable->nCol - BMS + 1; } /* Construct the Index object to describe this index */ pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed); if( pIdx==0 ) goto end_auto_index_create; pLoop->u.btree.pIndex = pIdx; pIdx->zName = "auto-index"; pIdx->pTable = pTable; n = 0; idxCols = 0; for(pTerm=pWC->a; pTermeOperator & (WO_OR|WO_AND))==0 ); iCol = pTerm->u.x.leftColumn; cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS-1 ); testcase( iCol==BMS ); if( (idxCols & cMask)==0 ){ Expr *pX = pTerm->pExpr; idxCols |= cMask; pIdx->aiColumn[n] = pTerm->u.x.leftColumn; pColl = sqlite3ExprCompareCollSeq(pParse, pX); assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */ pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY; n++; if( ALWAYS(pX->pLeft!=0) && sqlite3ExprAffinity(pX->pLeft)!=SQLITE_AFF_TEXT ){ /* TUNING: only use a Bloom filter on an automatic index ** if one or more key columns has the ability to hold numeric ** values, since strings all have the same hash in the Bloom ** filter implementation and hence a Bloom filter on a text column ** is not usually helpful. */ useBloomFilter = 1; } } } } assert( (u32)n==pLoop->u.btree.nEq ); /* Add additional columns needed to make the automatic index into ** a covering index */ for(i=0; iaiColumn[n] = i; pIdx->azColl[n] = sqlite3StrBINARY; n++; } } if( pSrc->colUsed & MASKBIT(BMS-1) ){ for(i=BMS-1; inCol; i++){ pIdx->aiColumn[n] = i; pIdx->azColl[n] = sqlite3StrBINARY; n++; } } assert( n==nKeyCol ); pIdx->aiColumn[n] = XN_ROWID; pIdx->azColl[n] = sqlite3StrBINARY; /* Create the automatic index */ explainAutomaticIndex(pParse, pIdx, pPartial!=0, &addrExp); assert( pLevel->iIdxCur>=0 ); pLevel->iIdxCur = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) && useBloomFilter ){ sqlite3WhereExplainBloomFilter(pParse, pWC->pWInfo, pLevel); pLevel->regFilter = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Blob, 10000, pLevel->regFilter); } /* Fill the automatic index with content */ assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] ); if( pSrc->fg.viaCoroutine ){ int regYield = pSrc->regReturn; addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); VdbeComment((v, "next row of %s", pSrc->pTab->zName)); }else{ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } if( pPartial ){ iContinue = sqlite3VdbeMakeLabel(pParse); sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL); pLoop->wsFlags |= WHERE_PARTIALIDX; } regRecord = sqlite3GetTempReg(pParse); regBase = sqlite3GenerateIndexKey( pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0 ); if( pLevel->regFilter ){ sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, regBase, pLoop->u.btree.nEq); } sqlite3VdbeScanStatusCounters(v, addrExp, addrExp, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); if( pSrc->fg.viaCoroutine ){ sqlite3VdbeChangeP2(v, addrCounter, regBase+n); testcase( pParse->db->mallocFailed ); assert( pLevel->iIdxCur>0 ); translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, pSrc->regResult, pLevel->iIdxCur); sqlite3VdbeGoto(v, addrTop); pSrc->fg.viaCoroutine = 0; }else{ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); } sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); /* Jump here when skipping the initialization */ sqlite3VdbeJumpHere(v, addrInit); sqlite3VdbeScanStatusRange(v, addrExp, addrExp, -1); end_auto_index_create: sqlite3ExprDelete(pParse->db, pPartial); } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ /* ** Generate bytecode that will initialize a Bloom filter that is appropriate ** for pLevel. ** ** If there are inner loops within pLevel that have the WHERE_BLOOMFILTER ** flag set, initialize a Bloomfilter for them as well. Except don't do ** this recursive initialization if the SQLITE_BloomPulldown optimization has ** been turned off. ** ** When the Bloom filter is initialized, the WHERE_BLOOMFILTER flag is cleared ** from the loop, but the regFilter value is set to a register that implements ** the Bloom filter. When regFilter is positive, the ** sqlite3WhereCodeOneLoopStart() will generate code to test the Bloom filter ** and skip the subsequence B-Tree seek if the Bloom filter indicates that ** no matching rows exist. ** ** This routine may only be called if it has previously been determined that ** the loop would benefit from a Bloom filter, and the WHERE_BLOOMFILTER bit ** is set. */ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( WhereInfo *pWInfo, /* The WHERE clause */ int iLevel, /* Index in pWInfo->a[] that is pLevel */ WhereLevel *pLevel, /* Make a Bloom filter for this FROM term */ Bitmask notReady /* Loops that are not ready */ ){ int addrOnce; /* Address of opening OP_Once */ int addrTop; /* Address of OP_Rewind */ int addrCont; /* Jump here to skip a row */ const WhereTerm *pTerm; /* For looping over WHERE clause terms */ const WhereTerm *pWCEnd; /* Last WHERE clause term */ Parse *pParse = pWInfo->pParse; /* Parsing context */ Vdbe *v = pParse->pVdbe; /* VDBE under construction */ WhereLoop *pLoop = pLevel->pWLoop; /* The loop being coded */ int iCur; /* Cursor for table getting the filter */ IndexedExpr *saved_pIdxEpr; /* saved copy of Parse.pIdxEpr */ IndexedExpr *saved_pIdxPartExpr; /* saved copy of Parse.pIdxPartExpr */ saved_pIdxEpr = pParse->pIdxEpr; saved_pIdxPartExpr = pParse->pIdxPartExpr; pParse->pIdxEpr = 0; pParse->pIdxPartExpr = 0; assert( pLoop!=0 ); assert( v!=0 ); assert( pLoop->wsFlags & WHERE_BLOOMFILTER ); assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 ); addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); do{ const SrcList *pTabList; const SrcItem *pItem; const Table *pTab; u64 sz; int iSrc; sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel); addrCont = sqlite3VdbeMakeLabel(pParse); iCur = pLevel->iTabCur; pLevel->regFilter = ++pParse->nMem; /* The Bloom filter is a Blob held in a register. Initialize it ** to zero-filled blob of at least 80K bits, but maybe more if the ** estimated size of the table is larger. We could actually ** measure the size of the table at run-time using OP_Count with ** P3==1 and use that value to initialize the blob. But that makes ** testing complicated. By basing the blob size on the value in the ** sqlite_stat1 table, testing is much easier. */ pTabList = pWInfo->pTabList; iSrc = pLevel->iFrom; pItem = &pTabList->a[iSrc]; assert( pItem!=0 ); pTab = pItem->pTab; assert( pTab!=0 ); sz = sqlite3LogEstToInt(pTab->nRowLogEst); if( sz<10000 ){ sz = 10000; }else if( sz>10000000 ){ sz = 10000000; } sqlite3VdbeAddOp2(v, OP_Blob, (int)sz, pLevel->regFilter); addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); pWCEnd = &pWInfo->sWC.a[pWInfo->sWC.nTerm]; for(pTerm=pWInfo->sWC.a; pTermpExpr; if( (pTerm->wtFlags & TERM_VIRTUAL)==0 && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc) ){ sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); } } if( pLoop->wsFlags & WHERE_IPK ){ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1); sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, 1); sqlite3ReleaseTempReg(pParse, r1); }else{ Index *pIdx = pLoop->u.btree.pIndex; int n = pLoop->u.btree.nEq; int r1 = sqlite3GetTempRange(pParse, n); int jj; for(jj=0; jjpTable==pItem->pTab ); sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj); } sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n); sqlite3ReleaseTempRange(pParse, r1, n); } sqlite3VdbeResolveLabel(v, addrCont); sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrTop); pLoop->wsFlags &= ~WHERE_BLOOMFILTER; if( OptimizationDisabled(pParse->db, SQLITE_BloomPulldown) ) break; while( ++iLevel < pWInfo->nLevel ){ const SrcItem *pTabItem; pLevel = &pWInfo->a[iLevel]; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue; pLoop = pLevel->pWLoop; if( NEVER(pLoop==0) ) continue; if( pLoop->prereq & notReady ) continue; if( (pLoop->wsFlags & (WHERE_BLOOMFILTER|WHERE_COLUMN_IN)) ==WHERE_BLOOMFILTER ){ /* This is a candidate for bloom-filter pull-down (early evaluation). ** The test that WHERE_COLUMN_IN is omitted is important, as we are ** not able to do early evaluation of bloom filters that make use of ** the IN operator */ break; } } }while( iLevel < pWInfo->nLevel ); sqlite3VdbeJumpHere(v, addrOnce); pParse->pIdxEpr = saved_pIdxEpr; pParse->pIdxPartExpr = saved_pIdxPartExpr; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Allocate and populate an sqlite3_index_info structure. It is the ** responsibility of the caller to eventually release the structure ** by passing the pointer returned by this function to freeIndexInfo(). */ static sqlite3_index_info *allocateIndexInfo( WhereInfo *pWInfo, /* The WHERE clause */ WhereClause *pWC, /* The WHERE clause being analyzed */ Bitmask mUnusable, /* Ignore terms with these prereqs */ SrcItem *pSrc, /* The FROM clause term that is the vtab */ u16 *pmNoOmit /* Mask of terms not to omit */ ){ int i, j; int nTerm; Parse *pParse = pWInfo->pParse; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_orderby *pIdxOrderBy; struct sqlite3_index_constraint_usage *pUsage; struct HiddenIndexInfo *pHidden; WhereTerm *pTerm; int nOrderBy; sqlite3_index_info *pIdxInfo; u16 mNoOmit = 0; const Table *pTab; int eDistinct = 0; ExprList *pOrderBy = pWInfo->pOrderBy; assert( pSrc!=0 ); pTab = pSrc->pTab; assert( pTab!=0 ); assert( IsVirtual(pTab) ); /* Find all WHERE clause constraints referring to this virtual table. ** Mark each term with the TERM_OK flag. Set nTerm to the number of ** terms found. */ for(i=nTerm=0, pTerm=pWC->a; inTerm; i++, pTerm++){ pTerm->wtFlags &= ~TERM_OK; if( pTerm->leftCursor != pSrc->iCursor ) continue; if( pTerm->prereqRight & mUnusable ) continue; assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( pTerm->u.x.leftColumn>=XN_ROWID ); assert( pTerm->u.x.leftColumnnCol ); if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 && !constraintCompatibleWithOuterJoin(pTerm,pSrc) ){ continue; } nTerm++; pTerm->wtFlags |= TERM_OK; } /* If the ORDER BY clause contains only columns in the current ** virtual table then allocate space for the aOrderBy part of ** the sqlite3_index_info structure. */ nOrderBy = 0; if( pOrderBy ){ int n = pOrderBy->nExpr; for(i=0; ia[i].pExpr; Expr *pE2; /* Skip over constant terms in the ORDER BY clause */ if( sqlite3ExprIsConstant(pExpr) ){ continue; } /* Virtual tables are unable to deal with NULLS FIRST */ if( pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_BIGNULL ) break; /* First case - a direct column references without a COLLATE operator */ if( pExpr->op==TK_COLUMN && pExpr->iTable==pSrc->iCursor ){ assert( pExpr->iColumn>=XN_ROWID && pExpr->iColumnnCol ); continue; } /* 2nd case - a column reference with a COLLATE operator. Only match ** of the COLLATE operator matches the collation of the column. */ if( pExpr->op==TK_COLLATE && (pE2 = pExpr->pLeft)->op==TK_COLUMN && pE2->iTable==pSrc->iCursor ){ const char *zColl; /* The collating sequence name */ assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken!=0 ); assert( pE2->iColumn>=XN_ROWID && pE2->iColumnnCol ); pExpr->iColumn = pE2->iColumn; if( pE2->iColumn<0 ) continue; /* Collseq does not matter for rowid */ zColl = sqlite3ColumnColl(&pTab->aCol[pE2->iColumn]); if( zColl==0 ) zColl = sqlite3StrBINARY; if( sqlite3_stricmp(pExpr->u.zToken, zColl)==0 ) continue; } /* No matches cause a break out of the loop */ break; } if( i==n ){ nOrderBy = n; if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) ){ eDistinct = 2 + ((pWInfo->wctrlFlags & WHERE_SORTBYGROUP)!=0); }else if( pWInfo->wctrlFlags & WHERE_GROUPBY ){ eDistinct = 1; } } } /* Allocate the sqlite3_index_info structure */ pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo) + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) + sizeof(sqlite3_value*)*nTerm ); if( pIdxInfo==0 ){ sqlite3ErrorMsg(pParse, "out of memory"); return 0; } pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1]; pIdxCons = (struct sqlite3_index_constraint*)&pHidden->aRhs[nTerm]; pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm]; pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy]; pIdxInfo->aConstraint = pIdxCons; pIdxInfo->aOrderBy = pIdxOrderBy; pIdxInfo->aConstraintUsage = pUsage; pHidden->pWC = pWC; pHidden->pParse = pParse; pHidden->eDistinct = eDistinct; pHidden->mIn = 0; for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){ u16 op; if( (pTerm->wtFlags & TERM_OK)==0 ) continue; pIdxCons[j].iColumn = pTerm->u.x.leftColumn; pIdxCons[j].iTermOffset = i; op = pTerm->eOperator & WO_ALL; if( op==WO_IN ){ if( (pTerm->wtFlags & TERM_SLICE)==0 ){ pHidden->mIn |= SMASKBIT32(j); } op = WO_EQ; } if( op==WO_AUX ){ pIdxCons[j].op = pTerm->eMatchOp; }else if( op & (WO_ISNULL|WO_IS) ){ if( op==WO_ISNULL ){ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL; }else{ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS; } }else{ pIdxCons[j].op = (u8)op; /* The direct assignment in the previous line is possible only because ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The ** following asserts verify this fact. */ assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) ); if( op & (WO_LT|WO_LE|WO_GT|WO_GE) && sqlite3ExprIsVector(pTerm->pExpr->pRight) ){ testcase( j!=i ); if( j<16 ) mNoOmit |= (1 << j); if( op==WO_LT ) pIdxCons[j].op = WO_LE; if( op==WO_GT ) pIdxCons[j].op = WO_GE; } } j++; } assert( j==nTerm ); pIdxInfo->nConstraint = j; for(i=j=0; ia[i].pExpr; if( sqlite3ExprIsConstant(pExpr) ) continue; assert( pExpr->op==TK_COLUMN || (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN && pExpr->iColumn==pExpr->pLeft->iColumn) ); pIdxOrderBy[j].iColumn = pExpr->iColumn; pIdxOrderBy[j].desc = pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_DESC; j++; } pIdxInfo->nOrderBy = j; *pmNoOmit = mNoOmit; return pIdxInfo; } /* ** Free an sqlite3_index_info structure allocated by allocateIndexInfo() ** and possibly modified by xBestIndex methods. */ static void freeIndexInfo(sqlite3 *db, sqlite3_index_info *pIdxInfo){ HiddenIndexInfo *pHidden; int i; assert( pIdxInfo!=0 ); pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; assert( pHidden->pParse!=0 ); assert( pHidden->pParse->db==db ); for(i=0; inConstraint; i++){ sqlite3ValueFree(pHidden->aRhs[i]); /* IMP: R-14553-25174 */ pHidden->aRhs[i] = 0; } sqlite3DbFree(db, pIdxInfo); } /* ** The table object reference passed as the second argument to this function ** must represent a virtual table. This function invokes the xBestIndex() ** method of the virtual table with the sqlite3_index_info object that ** comes in as the 3rd argument to this function. ** ** If an error occurs, pParse is populated with an error message and an ** appropriate error code is returned. A return of SQLITE_CONSTRAINT from ** xBestIndex is not considered an error. SQLITE_CONSTRAINT indicates that ** the current configuration of "unusable" flags in sqlite3_index_info can ** not result in a valid plan. ** ** Whether or not an error is returned, it is the responsibility of the ** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates ** that this is required. */ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; int rc; whereTraceIndexInfoInputs(p); pParse->db->nSchemaLock++; rc = pVtab->pModule->xBestIndex(pVtab, p); pParse->db->nSchemaLock--; whereTraceIndexInfoOutputs(p); if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){ if( rc==SQLITE_NOMEM ){ sqlite3OomFault(pParse->db); }else if( !pVtab->zErrMsg ){ sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc)); }else{ sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg); } } if( pTab->u.vtab.p->bAllSchemas ){ sqlite3VtabUsesAllSchemas(pParse); } sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = 0; return rc; } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ #ifdef SQLITE_ENABLE_STAT4 /* ** Estimate the location of a particular key among all keys in an ** index. Store the results in aStat as follows: ** ** aStat[0] Est. number of rows less than pRec ** aStat[1] Est. number of rows equal to pRec ** ** Return the index of the sample that is the smallest sample that ** is greater than or equal to pRec. Note that this index is not an index ** into the aSample[] array - it is an index into a virtual set of samples ** based on the contents of aSample[] and the number of fields in record ** pRec. */ static int whereKeyStats( Parse *pParse, /* Database connection */ Index *pIdx, /* Index to consider domain of */ UnpackedRecord *pRec, /* Vector of values to consider */ int roundUp, /* Round up if true. Round down if false */ tRowcnt *aStat /* OUT: stats written here */ ){ IndexSample *aSample = pIdx->aSample; int iCol; /* Index of required stats in anEq[] etc. */ int i; /* Index of first sample >= pRec */ int iSample; /* Smallest sample larger than or equal to pRec */ int iMin = 0; /* Smallest sample not yet tested */ int iTest; /* Next sample to test */ int res; /* Result of comparison operation */ int nField; /* Number of fields in pRec */ tRowcnt iLower = 0; /* anLt[] + anEq[] of largest sample pRec is > */ #ifndef SQLITE_DEBUG UNUSED_PARAMETER( pParse ); #endif assert( pRec!=0 ); assert( pIdx->nSample>0 ); assert( pRec->nField>0 ); /* Do a binary search to find the first sample greater than or equal ** to pRec. If pRec contains a single field, the set of samples to search ** is simply the aSample[] array. If the samples in aSample[] contain more ** than one fields, all fields following the first are ignored. ** ** If pRec contains N fields, where N is more than one, then as well as the ** samples in aSample[] (truncated to N fields), the search also has to ** consider prefixes of those samples. For example, if the set of samples ** in aSample is: ** ** aSample[0] = (a, 5) ** aSample[1] = (a, 10) ** aSample[2] = (b, 5) ** aSample[3] = (c, 100) ** aSample[4] = (c, 105) ** ** Then the search space should ideally be the samples above and the ** unique prefixes [a], [b] and [c]. But since that is hard to organize, ** the code actually searches this set: ** ** 0: (a) ** 1: (a, 5) ** 2: (a, 10) ** 3: (a, 10) ** 4: (b) ** 5: (b, 5) ** 6: (c) ** 7: (c, 100) ** 8: (c, 105) ** 9: (c, 105) ** ** For each sample in the aSample[] array, N samples are present in the ** effective sample array. In the above, samples 0 and 1 are based on ** sample aSample[0]. Samples 2 and 3 on aSample[1] etc. ** ** Often, sample i of each block of N effective samples has (i+1) fields. ** Except, each sample may be extended to ensure that it is greater than or ** equal to the previous sample in the array. For example, in the above, ** sample 2 is the first sample of a block of N samples, so at first it ** appears that it should be 1 field in size. However, that would make it ** smaller than sample 1, so the binary search would not work. As a result, ** it is extended to two fields. The duplicates that this creates do not ** cause any problems. */ if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){ nField = pIdx->nKeyCol; }else{ nField = pIdx->nColumn; } nField = MIN(pRec->nField, nField); iCol = 0; iSample = pIdx->nSample * nField; do{ int iSamp; /* Index in aSample[] of test sample */ int n; /* Number of fields in test sample */ iTest = (iMin+iSample)/2; iSamp = iTest / nField; if( iSamp>0 ){ /* The proposed effective sample is a prefix of sample aSample[iSamp]. ** Specifically, the shortest prefix of at least (1 + iTest%nField) ** fields that is greater than the previous effective sample. */ for(n=(iTest % nField) + 1; nnField = n; res = sqlite3VdbeRecordCompare(aSample[iSamp].n, aSample[iSamp].p, pRec); if( res<0 ){ iLower = aSample[iSamp].anLt[n-1] + aSample[iSamp].anEq[n-1]; iMin = iTest+1; }else if( res==0 && ndb->mallocFailed==0 ){ if( res==0 ){ /* If (res==0) is true, then pRec must be equal to sample i. */ assert( inSample ); assert( iCol==nField-1 ); pRec->nField = nField; assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec) || pParse->db->mallocFailed ); }else{ /* Unless i==pIdx->nSample, indicating that pRec is larger than ** all samples in the aSample[] array, pRec must be smaller than the ** (iCol+1) field prefix of sample i. */ assert( i<=pIdx->nSample && i>=0 ); pRec->nField = iCol+1; assert( i==pIdx->nSample || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0 || pParse->db->mallocFailed ); /* if i==0 and iCol==0, then record pRec is smaller than all samples ** in the aSample[] array. Otherwise, if (iCol>0) then pRec must ** be greater than or equal to the (iCol) field prefix of sample i. ** If (i>0), then pRec must also be greater than sample (i-1). */ if( iCol>0 ){ pRec->nField = iCol; assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0 || pParse->db->mallocFailed || CORRUPT_DB ); } if( i>0 ){ pRec->nField = nField; assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 || pParse->db->mallocFailed || CORRUPT_DB ); } } } #endif /* ifdef SQLITE_DEBUG */ if( res==0 ){ /* Record pRec is equal to sample i */ assert( iCol==nField-1 ); aStat[0] = aSample[i].anLt[iCol]; aStat[1] = aSample[i].anEq[iCol]; }else{ /* At this point, the (iCol+1) field prefix of aSample[i] is the first ** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec ** is larger than all samples in the array. */ tRowcnt iUpper, iGap; if( i>=pIdx->nSample ){ iUpper = pIdx->nRowEst0; }else{ iUpper = aSample[i].anLt[iCol]; } if( iLower>=iUpper ){ iGap = 0; }else{ iGap = iUpper - iLower; } if( roundUp ){ iGap = (iGap*2)/3; }else{ iGap = iGap/3; } aStat[0] = iLower + iGap; aStat[1] = pIdx->aAvgEq[nField-1]; } /* Restore the pRec->nField value before returning. */ pRec->nField = nField; return i; } #endif /* SQLITE_ENABLE_STAT4 */ /* ** If it is not NULL, pTerm is a term that provides an upper or lower ** bound on a range scan. Without considering pTerm, it is estimated ** that the scan will visit nNew rows. This function returns the number ** estimated to be visited after taking pTerm into account. ** ** If the user explicitly specified a likelihood() value for this term, ** then the return value is the likelihood multiplied by the number of ** input rows. Otherwise, this function assumes that an "IS NOT NULL" term ** has a likelihood of 0.50, and any other term a likelihood of 0.25. */ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){ LogEst nRet = nNew; if( pTerm ){ if( pTerm->truthProb<=0 ){ nRet += pTerm->truthProb; }else if( (pTerm->wtFlags & TERM_VNULL)==0 ){ nRet -= 20; assert( 20==sqlite3LogEst(4) ); } } return nRet; } #ifdef SQLITE_ENABLE_STAT4 /* ** Return the affinity for a single column of an index. */ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){ assert( iCol>=0 && iColnColumn ); if( !pIdx->zColAff ){ if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB; } assert( pIdx->zColAff[iCol]!=0 ); return pIdx->zColAff[iCol]; } #endif #ifdef SQLITE_ENABLE_STAT4 /* ** This function is called to estimate the number of rows visited by a ** range-scan on a skip-scan index. For example: ** ** CREATE INDEX i1 ON t1(a, b, c); ** SELECT * FROM t1 WHERE a=? AND c BETWEEN ? AND ?; ** ** Value pLoop->nOut is currently set to the estimated number of rows ** visited for scanning (a=? AND b=?). This function reduces that estimate ** by some factor to account for the (c BETWEEN ? AND ?) expression based ** on the stat4 data for the index. this scan will be performed multiple ** times (once for each (a,b) combination that matches a=?) is dealt with ** by the caller. ** ** It does this by scanning through all stat4 samples, comparing values ** extracted from pLower and pUpper with the corresponding column in each ** sample. If L and U are the number of samples found to be less than or ** equal to the values extracted from pLower and pUpper respectively, and ** N is the total number of samples, the pLoop->nOut value is adjusted ** as follows: ** ** nOut = nOut * ( min(U - L, 1) / N ) ** ** If pLower is NULL, or a value cannot be extracted from the term, L is ** set to zero. If pUpper is NULL, or a value cannot be extracted from it, ** U is set to N. ** ** Normally, this function sets *pbDone to 1 before returning. However, ** if no value can be extracted from either pLower or pUpper (and so the ** estimate of the number of rows delivered remains unchanged), *pbDone ** is left as is. ** ** If an error occurs, an SQLite error code is returned. Otherwise, ** SQLITE_OK. */ static int whereRangeSkipScanEst( Parse *pParse, /* Parsing & code generating context */ WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */ WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ WhereLoop *pLoop, /* Update the .nOut value of this loop */ int *pbDone /* Set to true if at least one expr. value extracted */ ){ Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; sqlite3 *db = pParse->db; int nLower = -1; int nUpper = p->nSample+1; int rc = SQLITE_OK; u8 aff = sqlite3IndexColumnAffinity(db, p, nEq); CollSeq *pColl; sqlite3_value *p1 = 0; /* Value extracted from pLower */ sqlite3_value *p2 = 0; /* Value extracted from pUpper */ sqlite3_value *pVal = 0; /* Value extracted from record */ pColl = sqlite3LocateCollSeq(pParse, p->azColl[nEq]); if( pLower ){ rc = sqlite3Stat4ValueFromExpr(pParse, pLower->pExpr->pRight, aff, &p1); nLower = 0; } if( pUpper && rc==SQLITE_OK ){ rc = sqlite3Stat4ValueFromExpr(pParse, pUpper->pExpr->pRight, aff, &p2); nUpper = p2 ? 0 : p->nSample; } if( p1 || p2 ){ int i; int nDiff; for(i=0; rc==SQLITE_OK && inSample; i++){ rc = sqlite3Stat4Column(db, p->aSample[i].p, p->aSample[i].n, nEq, &pVal); if( rc==SQLITE_OK && p1 ){ int res = sqlite3MemCompare(p1, pVal, pColl); if( res>=0 ) nLower++; } if( rc==SQLITE_OK && p2 ){ int res = sqlite3MemCompare(p2, pVal, pColl); if( res>=0 ) nUpper++; } } nDiff = (nUpper - nLower); if( nDiff<=0 ) nDiff = 1; /* If there is both an upper and lower bound specified, and the ** comparisons indicate that they are close together, use the fallback ** method (assume that the scan visits 1/64 of the rows) for estimating ** the number of rows visited. Otherwise, estimate the number of rows ** using the method described in the header comment for this function. */ if( nDiff!=1 || pUpper==0 || pLower==0 ){ int nAdjust = (sqlite3LogEst(p->nSample) - sqlite3LogEst(nDiff)); pLoop->nOut -= nAdjust; *pbDone = 1; WHERETRACE(0x20, ("range skip-scan regions: %u..%u adjust=%d est=%d\n", nLower, nUpper, nAdjust*-1, pLoop->nOut)); } }else{ assert( *pbDone==0 ); } sqlite3ValueFree(p1); sqlite3ValueFree(p2); sqlite3ValueFree(pVal); return rc; } #endif /* SQLITE_ENABLE_STAT4 */ /* ** This function is used to estimate the number of rows that will be visited ** by scanning an index for a range of values. The range may have an upper ** bound, a lower bound, or both. The WHERE clause terms that set the upper ** and lower bounds are represented by pLower and pUpper respectively. For ** example, assuming that index p is on t1(a): ** ** ... FROM t1 WHERE a > ? AND a < ? ... ** |_____| |_____| ** | | ** pLower pUpper ** ** If either of the upper or lower bound is not present, then NULL is passed in ** place of the corresponding WhereTerm. ** ** The value in (pBuilder->pNew->u.btree.nEq) is the number of the index ** column subject to the range constraint. Or, equivalently, the number of ** equality constraints optimized by the proposed index scan. For example, ** assuming index p is on t1(a, b), and the SQL query is: ** ** ... FROM t1 WHERE a = ? AND b > ? AND b < ? ... ** ** then nEq is set to 1 (as the range restricted column, b, is the second ** left-most column of the index). Or, if the query is: ** ** ... FROM t1 WHERE a > ? AND a < ? ... ** ** then nEq is set to 0. ** ** When this function is called, *pnOut is set to the sqlite3LogEst() of the ** number of rows that the index scan is expected to visit without ** considering the range constraints. If nEq is 0, then *pnOut is the number of ** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced) ** to account for the range constraints pLower and pUpper. ** ** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be ** used, a single range inequality reduces the search space by a factor of 4. ** and a pair of constraints (x>? AND x123" Might be NULL */ WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ WhereLoop *pLoop /* Modify the .nOut and maybe .rRun fields */ ){ int rc = SQLITE_OK; int nOut = pLoop->nOut; LogEst nNew; #ifdef SQLITE_ENABLE_STAT4 Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; if( p->nSample>0 && ALWAYS(nEqnSampleCol) && OptimizationEnabled(pParse->db, SQLITE_Stat4) ){ if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; int nBtm = pLoop->u.btree.nBtm; int nTop = pLoop->u.btree.nTop; /* Variable iLower will be set to the estimate of the number of rows in ** the index that are less than the lower bound of the range query. The ** lower bound being the concatenation of $P and $L, where $P is the ** key-prefix formed by the nEq values matched against the nEq left-most ** columns of the index, and $L is the value in pLower. ** ** Or, if pLower is NULL or $L cannot be extracted from it (because it ** is not a simple variable or literal value), the lower bound of the ** range is $P. Due to a quirk in the way whereKeyStats() works, even ** if $L is available, whereKeyStats() is called for both ($P) and ** ($P:$L) and the larger of the two returned values is used. ** ** Similarly, iUpper is to be set to the estimate of the number of rows ** less than the upper bound of the range query. Where the upper bound ** is either ($P) or ($P:$U). Again, even if $U is available, both values ** of iUpper are requested of whereKeyStats() and the smaller used. ** ** The number of rows between the two bounds is then just iUpper-iLower. */ tRowcnt iLower; /* Rows less than the lower bound */ tRowcnt iUpper; /* Rows less than the upper bound */ int iLwrIdx = -2; /* aSample[] for the lower bound */ int iUprIdx = -1; /* aSample[] for the upper bound */ if( pRec ){ testcase( pRec->nField!=pBuilder->nRecValid ); pRec->nField = pBuilder->nRecValid; } /* Determine iLower and iUpper using ($P) only. */ if( nEq==0 ){ iLower = 0; iUpper = p->nRowEst0; }else{ /* Note: this call could be optimized away - since the same values must ** have been requested when testing key $P in whereEqualScanEst(). */ whereKeyStats(pParse, p, pRec, 0, a); iLower = a[0]; iUpper = a[0] + a[1]; } assert( pLower==0 || (pLower->eOperator & (WO_GT|WO_GE))!=0 ); assert( pUpper==0 || (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); assert( p->aSortOrder!=0 ); if( p->aSortOrder[nEq] ){ /* The roles of pLower and pUpper are swapped for a DESC index */ SWAP(WhereTerm*, pLower, pUpper); SWAP(int, nBtm, nTop); } /* If possible, improve on the iLower estimate using ($P:$L). */ if( pLower ){ int n; /* Values extracted from pExpr */ Expr *pExpr = pLower->pExpr->pRight; rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nBtm, nEq, &n); if( rc==SQLITE_OK && n ){ tRowcnt iNew; u16 mask = WO_GT|WO_LE; if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT); iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a); iNew = a[0] + ((pLower->eOperator & mask) ? a[1] : 0); if( iNew>iLower ) iLower = iNew; nOut--; pLower = 0; } } /* If possible, improve on the iUpper estimate using ($P:$U). */ if( pUpper ){ int n; /* Values extracted from pExpr */ Expr *pExpr = pUpper->pExpr->pRight; rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nTop, nEq, &n); if( rc==SQLITE_OK && n ){ tRowcnt iNew; u16 mask = WO_GT|WO_LE; if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT); iUprIdx = whereKeyStats(pParse, p, pRec, 1, a); iNew = a[0] + ((pUpper->eOperator & mask) ? a[1] : 0); if( iNewpRec = pRec; if( rc==SQLITE_OK ){ if( iUpper>iLower ){ nNew = sqlite3LogEst(iUpper - iLower); /* TUNING: If both iUpper and iLower are derived from the same ** sample, then assume they are 4x more selective. This brings ** the estimated selectivity more in line with what it would be ** if estimated without the use of STAT4 tables. */ if( iLwrIdx==iUprIdx ){ nNew -= 20; } assert( 20==sqlite3LogEst(4) ); }else{ nNew = 10; assert( 10==sqlite3LogEst(2) ); } if( nNewwtFlags & TERM_VNULL)==0 || pParse->nErr>0 ); nNew = whereRangeAdjust(pLower, nOut); nNew = whereRangeAdjust(pUpper, nNew); /* TUNING: If there is both an upper and lower limit and neither limit ** has an application-defined likelihood(), assume the range is ** reduced by an additional 75%. This means that, by default, an open-ended ** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the ** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to ** match 1/64 of the index. */ if( pLower && pLower->truthProb>0 && pUpper && pUpper->truthProb>0 ){ nNew -= 20; } nOut -= (pLower!=0) + (pUpper!=0); if( nNew<10 ) nNew = 10; if( nNewnOut>nOut ){ WHERETRACE(0x20,("Range scan lowers nOut from %d to %d\n", pLoop->nOut, nOut)); } #endif pLoop->nOut = (LogEst)nOut; return rc; } #ifdef SQLITE_ENABLE_STAT4 /* ** Estimate the number of rows that will be returned based on ** an equality constraint x=VALUE and where that VALUE occurs in ** the histogram data. This only works when x is the left-most ** column of an index and sqlite_stat4 histogram data is available ** for that index. When pExpr==NULL that means the constraint is ** "x IS NULL" instead of "x=VALUE". ** ** Write the estimated row count into *pnRow and return SQLITE_OK. ** If unable to make an estimate, leave *pnRow unchanged and return ** non-zero. ** ** This routine can fail if it is unable to load a collating sequence ** required for string comparison, or if unable to allocate memory ** for a UTF conversion required for comparison. The error is stored ** in the pParse structure. */ static int whereEqualScanEst( Parse *pParse, /* Parsing & code generating context */ WhereLoopBuilder *pBuilder, Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */ tRowcnt *pnRow /* Write the revised row estimate here */ ){ Index *p = pBuilder->pNew->u.btree.pIndex; int nEq = pBuilder->pNew->u.btree.nEq; UnpackedRecord *pRec = pBuilder->pRec; int rc; /* Subfunction return code */ tRowcnt a[2]; /* Statistics */ int bOk; assert( nEq>=1 ); assert( nEq<=p->nColumn ); assert( p->aSample!=0 ); assert( p->nSample>0 ); assert( pBuilder->nRecValidnRecValid<(nEq-1) ){ return SQLITE_NOTFOUND; } /* This is an optimization only. The call to sqlite3Stat4ProbeSetValue() ** below would return the same value. */ if( nEq>=p->nColumn ){ *pnRow = 1; return SQLITE_OK; } rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, 1, nEq-1, &bOk); pBuilder->pRec = pRec; if( rc!=SQLITE_OK ) return rc; if( bOk==0 ) return SQLITE_NOTFOUND; pBuilder->nRecValid = nEq; whereKeyStats(pParse, p, pRec, 0, a); WHERETRACE(0x20,("equality scan regions %s(%d): %d\n", p->zName, nEq-1, (int)a[1])); *pnRow = a[1]; return rc; } #endif /* SQLITE_ENABLE_STAT4 */ #ifdef SQLITE_ENABLE_STAT4 /* ** Estimate the number of rows that will be returned based on ** an IN constraint where the right-hand side of the IN operator ** is a list of values. Example: ** ** WHERE x IN (1,2,3,4) ** ** Write the estimated row count into *pnRow and return SQLITE_OK. ** If unable to make an estimate, leave *pnRow unchanged and return ** non-zero. ** ** This routine can fail if it is unable to load a collating sequence ** required for string comparison, or if unable to allocate memory ** for a UTF conversion required for comparison. The error is stored ** in the pParse structure. */ static int whereInScanEst( Parse *pParse, /* Parsing & code generating context */ WhereLoopBuilder *pBuilder, ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ tRowcnt *pnRow /* Write the revised row estimate here */ ){ Index *p = pBuilder->pNew->u.btree.pIndex; i64 nRow0 = sqlite3LogEstToInt(p->aiRowLogEst[0]); int nRecValid = pBuilder->nRecValid; int rc = SQLITE_OK; /* Subfunction return code */ tRowcnt nEst; /* Number of rows for a single term */ tRowcnt nRowEst = 0; /* New estimate of the number of rows */ int i; /* Loop counter */ assert( p->aSample!=0 ); for(i=0; rc==SQLITE_OK && inExpr; i++){ nEst = nRow0; rc = whereEqualScanEst(pParse, pBuilder, pList->a[i].pExpr, &nEst); nRowEst += nEst; pBuilder->nRecValid = nRecValid; } if( rc==SQLITE_OK ){ if( nRowEst > (tRowcnt)nRow0 ) nRowEst = nRow0; *pnRow = nRowEst; WHERETRACE(0x20,("IN row estimate: est=%d\n", nRowEst)); } assert( pBuilder->nRecValid==nRecValid ); return rc; } #endif /* SQLITE_ENABLE_STAT4 */ #ifdef WHERETRACE_ENABLED /* ** Print the content of a WhereTerm object */ SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm==0 ){ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); }else{ char zType[8]; char zLeft[50]; memcpy(zType, "....", 5); if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; if( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) zType[2] = 'L'; if( pTerm->wtFlags & TERM_CODED ) zType[3] = 'C'; if( pTerm->eOperator & WO_SINGLE ){ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", pTerm->leftCursor, pTerm->u.x.leftColumn); }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%llx", pTerm->u.pOrInfo->indexable); }else{ sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); } sqlite3DebugPrintf( "TERM-%-3d %p %s %-12s op=%03x wtFlags=%04x", iTerm, pTerm, zType, zLeft, pTerm->eOperator, pTerm->wtFlags); /* The 0x10000 .wheretrace flag causes extra information to be ** shown about each Term */ if( sqlite3WhereTrace & 0x10000 ){ sqlite3DebugPrintf(" prob=%-3d prereq=%llx,%llx", pTerm->truthProb, (u64)pTerm->prereqAll, (u64)pTerm->prereqRight); } if( (pTerm->eOperator & (WO_OR|WO_AND))==0 && pTerm->u.x.iField ){ sqlite3DebugPrintf(" iField=%d", pTerm->u.x.iField); } if( pTerm->iParent>=0 ){ sqlite3DebugPrintf(" iParent=%d", pTerm->iParent); } sqlite3DebugPrintf("\n"); sqlite3TreeViewExpr(0, pTerm->pExpr, 0); } } #endif #ifdef WHERETRACE_ENABLED /* ** Show the complete content of a WhereClause */ SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){ int i; for(i=0; inTerm; i++){ sqlite3WhereTermPrint(&pWC->a[i], i); } } #endif #ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes ** ** Format example: ** ** .--- Position in WHERE clause rSetup, rRun, nOut ---. ** | | ** | .--- selfMask nTerm ------. | ** | | | | ** | | .-- prereq Idx wsFlags----. | | ** | | | Name | | | ** | | | __|__ nEq ---. ___|__ | __|__ ** | / \ / \ / \ | / \ / \ / \ ** 1.002.001 t2.t2xy 2 f 010241 N 2 cost 0,56,31 */ SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){ if( pWC ){ WhereInfo *pWInfo = pWC->pWInfo; int nb = 1+(pWInfo->pTabList->nSrc+3)/4; SrcItem *pItem = pWInfo->pTabList->a + p->iTab; Table *pTab = pItem->pTab; Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); sqlite3DebugPrintf(" %12s", pItem->zAlias ? pItem->zAlias : pTab->zName); }else{ sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d", p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab); } if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ const char *zName; if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){ if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){ int i = sqlite3Strlen30(zName) - 1; while( zName[i]!='_' ) i--; zName += i; } sqlite3DebugPrintf(".%-16s %2d", zName, p->u.btree.nEq); }else{ sqlite3DebugPrintf("%20s",""); } }else{ char *z; if( p->u.vtab.idxStr ){ z = sqlite3_mprintf("(%d,\"%s\",%#x)", p->u.vtab.idxNum, p->u.vtab.idxStr, p->u.vtab.omitMask); }else{ z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask); } sqlite3DebugPrintf(" %-19s", z); sqlite3_free(z); } if( p->wsFlags & WHERE_SKIPSCAN ){ sqlite3DebugPrintf(" f %06x %d-%d", p->wsFlags, p->nLTerm,p->nSkip); }else{ sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm); } sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); if( p->nLTerm && (sqlite3WhereTrace & 0x4000)!=0 ){ int i; for(i=0; inLTerm; i++){ sqlite3WhereTermPrint(p->aLTerm[i], i); } } } SQLITE_PRIVATE void sqlite3ShowWhereLoop(const WhereLoop *p){ if( p ) sqlite3WhereLoopPrint(p, 0); } SQLITE_PRIVATE void sqlite3ShowWhereLoopList(const WhereLoop *p){ while( p ){ sqlite3ShowWhereLoop(p); p = p->pNextLoop; } } #endif /* ** Convert bulk memory into a valid WhereLoop that can be passed ** to whereLoopClear harmlessly. */ static void whereLoopInit(WhereLoop *p){ p->aLTerm = p->aLTermSpace; p->nLTerm = 0; p->nLSlot = ArraySize(p->aLTermSpace); p->wsFlags = 0; } /* ** Clear the WhereLoop.u union. Leave WhereLoop.pLTerm intact. */ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ if( p->wsFlags & (WHERE_VIRTUALTABLE|WHERE_AUTO_INDEX) ){ if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 && p->u.vtab.needFree ){ sqlite3_free(p->u.vtab.idxStr); p->u.vtab.needFree = 0; p->u.vtab.idxStr = 0; }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){ sqlite3DbFree(db, p->u.btree.pIndex->zColAff); sqlite3DbFreeNN(db, p->u.btree.pIndex); p->u.btree.pIndex = 0; } } } /* ** Deallocate internal memory used by a WhereLoop object. Leave the ** object in an initialized state, as if it had been newly allocated. */ static void whereLoopClear(sqlite3 *db, WhereLoop *p){ if( p->aLTerm!=p->aLTermSpace ){ sqlite3DbFreeNN(db, p->aLTerm); p->aLTerm = p->aLTermSpace; p->nLSlot = ArraySize(p->aLTermSpace); } whereLoopClearUnion(db, p); p->nLTerm = 0; p->wsFlags = 0; } /* ** Increase the memory allocation for pLoop->aLTerm[] to be at least n. */ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){ WhereTerm **paNew; if( p->nLSlot>=n ) return SQLITE_OK; n = (n+7)&~7; paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n); if( paNew==0 ) return SQLITE_NOMEM_BKPT; memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot); if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm); p->aLTerm = paNew; p->nLSlot = n; return SQLITE_OK; } /* ** Transfer content from the second pLoop into the first. */ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ whereLoopClearUnion(db, pTo); if( pFrom->nLTerm > pTo->nLSlot && whereLoopResize(db, pTo, pFrom->nLTerm) ){ memset(pTo, 0, WHERE_LOOP_XFER_SZ); return SQLITE_NOMEM_BKPT; } memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ); memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0])); if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){ pFrom->u.vtab.needFree = 0; }else if( (pFrom->wsFlags & WHERE_AUTO_INDEX)!=0 ){ pFrom->u.btree.pIndex = 0; } return SQLITE_OK; } /* ** Delete a WhereLoop object */ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ assert( db!=0 ); whereLoopClear(db, p); sqlite3DbNNFreeNN(db, p); } /* ** Free a WhereInfo structure */ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ assert( pWInfo!=0 ); assert( db!=0 ); sqlite3WhereClauseClear(&pWInfo->sWC); while( pWInfo->pLoops ){ WhereLoop *p = pWInfo->pLoops; pWInfo->pLoops = p->pNextLoop; whereLoopDelete(db, p); } while( pWInfo->pMemToFree ){ WhereMemBlock *pNext = pWInfo->pMemToFree->pNext; sqlite3DbNNFreeNN(db, pWInfo->pMemToFree); pWInfo->pMemToFree = pNext; } sqlite3DbNNFreeNN(db, pWInfo); } /* ** Return TRUE if X is a proper subset of Y but is of equal or less cost. ** In other words, return true if all constraints of X are also part of Y ** and Y has additional constraints that might speed the search that X lacks ** but the cost of running X is not more than the cost of running Y. ** ** In other words, return true if the cost relationwship between X and Y ** is inverted and needs to be adjusted. ** ** Case 1: ** ** (1a) X and Y use the same index. ** (1b) X has fewer == terms than Y ** (1c) Neither X nor Y use skip-scan ** (1d) X does not have a a greater cost than Y ** ** Case 2: ** ** (2a) X has the same or lower cost, or returns the same or fewer rows, ** than Y. ** (2b) X uses fewer WHERE clause terms than Y ** (2c) Every WHERE clause term used by X is also used by Y ** (2d) X skips at least as many columns as Y ** (2e) If X is a covering index, than Y is too */ static int whereLoopCheaperProperSubset( const WhereLoop *pX, /* First WhereLoop to compare */ const WhereLoop *pY /* Compare against this WhereLoop */ ){ int i, j; if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; /* (1d) and (2a) */ assert( (pX->wsFlags & WHERE_VIRTUALTABLE)==0 ); assert( (pY->wsFlags & WHERE_VIRTUALTABLE)==0 ); if( pX->u.btree.nEq < pY->u.btree.nEq /* (1b) */ && pX->u.btree.pIndex==pY->u.btree.pIndex /* (1a) */ && pX->nSkip==0 && pY->nSkip==0 /* (1c) */ ){ return 1; /* Case 1 is true */ } if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ return 0; /* (2b) */ } if( pY->nSkip > pX->nSkip ) return 0; /* (2d) */ for(i=pX->nLTerm-1; i>=0; i--){ if( pX->aLTerm[i]==0 ) continue; for(j=pY->nLTerm-1; j>=0; j--){ if( pY->aLTerm[j]==pX->aLTerm[i] ) break; } if( j<0 ) return 0; /* (2c) */ } if( (pX->wsFlags&WHERE_IDX_ONLY)!=0 && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){ return 0; /* (2e) */ } return 1; /* Case 2 is true */ } /* ** Try to adjust the cost and number of output rows of WhereLoop pTemplate ** upwards or downwards so that: ** ** (1) pTemplate costs less than any other WhereLoops that are a proper ** subset of pTemplate ** ** (2) pTemplate costs more than any other WhereLoops for which pTemplate ** is a proper subset. ** ** To say "WhereLoop X is a proper subset of Y" means that X uses fewer ** WHERE clause terms than Y and that every WHERE clause term used by X is ** also used by Y. */ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return; for(; p; p=p->pNextLoop){ if( p->iTab!=pTemplate->iTab ) continue; if( (p->wsFlags & WHERE_INDEXED)==0 ) continue; if( whereLoopCheaperProperSubset(p, pTemplate) ){ /* Adjust pTemplate cost downward so that it is cheaper than its ** subset p. */ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", pTemplate->rRun, pTemplate->nOut, MIN(p->rRun, pTemplate->rRun), MIN(p->nOut - 1, pTemplate->nOut))); pTemplate->rRun = MIN(p->rRun, pTemplate->rRun); pTemplate->nOut = MIN(p->nOut - 1, pTemplate->nOut); }else if( whereLoopCheaperProperSubset(pTemplate, p) ){ /* Adjust pTemplate cost upward so that it is costlier than p since ** pTemplate is a proper subset of p */ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", pTemplate->rRun, pTemplate->nOut, MAX(p->rRun, pTemplate->rRun), MAX(p->nOut + 1, pTemplate->nOut))); pTemplate->rRun = MAX(p->rRun, pTemplate->rRun); pTemplate->nOut = MAX(p->nOut + 1, pTemplate->nOut); } } } /* ** Search the list of WhereLoops in *ppPrev looking for one that can be ** replaced by pTemplate. ** ** Return NULL if pTemplate does not belong on the WhereLoop list. ** In other words if pTemplate ought to be dropped from further consideration. ** ** If pX is a WhereLoop that pTemplate can replace, then return the ** link that points to pX. ** ** If pTemplate cannot replace any existing element of the list but needs ** to be added to the list as a new entry, then return a pointer to the ** tail of the list. */ static WhereLoop **whereLoopFindLesser( WhereLoop **ppPrev, const WhereLoop *pTemplate ){ WhereLoop *p; for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){ if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){ /* If either the iTab or iSortIdx values for two WhereLoop are different ** then those WhereLoops need to be considered separately. Neither is ** a candidate to replace the other. */ continue; } /* In the current implementation, the rSetup value is either zero ** or the cost of building an automatic index (NlogN) and the NlogN ** is the same for compatible WhereLoops. */ assert( p->rSetup==0 || pTemplate->rSetup==0 || p->rSetup==pTemplate->rSetup ); /* whereLoopAddBtree() always generates and inserts the automatic index ** case first. Hence compatible candidate WhereLoops never have a larger ** rSetup. Call this SETUP-INVARIANT */ assert( p->rSetup>=pTemplate->rSetup ); /* Any loop using an application-defined index (or PRIMARY KEY or ** UNIQUE constraint) with one or more == constraints is better ** than an automatic index. Unless it is a skip-scan. */ if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && (pTemplate->nSkip)==0 && (pTemplate->wsFlags & WHERE_INDEXED)!=0 && (pTemplate->wsFlags & WHERE_COLUMN_EQ)!=0 && (p->prereq & pTemplate->prereq)==pTemplate->prereq ){ break; } /* If existing WhereLoop p is better than pTemplate, pTemplate can be ** discarded. WhereLoop p is better if: ** (1) p has no more dependencies than pTemplate, and ** (2) p has an equal or lower cost than pTemplate */ if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */ && p->rSetup<=pTemplate->rSetup /* (2a) */ && p->rRun<=pTemplate->rRun /* (2b) */ && p->nOut<=pTemplate->nOut /* (2c) */ ){ return 0; /* Discard pTemplate */ } /* If pTemplate is always better than p, then cause p to be overwritten ** with pTemplate. pTemplate is better than p if: ** (1) pTemplate has no more dependencies than p, and ** (2) pTemplate has an equal or lower cost than p. */ if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */ && p->rRun>=pTemplate->rRun /* (2a) */ && p->nOut>=pTemplate->nOut /* (2b) */ ){ assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */ break; /* Cause p to be overwritten by pTemplate */ } } return ppPrev; } /* ** Insert or replace a WhereLoop entry using the template supplied. ** ** An existing WhereLoop entry might be overwritten if the new template ** is better and has fewer dependencies. Or the template will be ignored ** and no insert will occur if an existing WhereLoop is faster and has ** fewer dependencies than the template. Otherwise a new WhereLoop is ** added based on the template. ** ** If pBuilder->pOrSet is not NULL then we care about only the ** prerequisites and rRun and nOut costs of the N best loops. That ** information is gathered in the pBuilder->pOrSet object. This special ** processing mode is used only for OR clause processing. ** ** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we ** still might overwrite similar loops with the new template if the ** new template is better. Loops may be overwritten if the following ** conditions are met: ** ** (1) They have the same iTab. ** (2) They have the same iSortIdx. ** (3) The template has same or fewer dependencies than the current loop ** (4) The template has the same or lower cost than the current loop */ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ WhereLoop **ppPrev, *p; WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; int rc; /* Stop the search once we hit the query planner search limit */ if( pBuilder->iPlanLimit==0 ){ WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n")); if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0; return SQLITE_DONE; } pBuilder->iPlanLimit--; whereLoopAdjustCost(pWInfo->pLoops, pTemplate); /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. */ if( pBuilder->pOrSet!=0 ){ if( pTemplate->nLTerm ){ #if WHERETRACE_ENABLED u16 n = pBuilder->pOrSet->n; int x = #endif whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun, pTemplate->nOut); #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n); sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC); } #endif } return SQLITE_OK; } /* Look for an existing WhereLoop to replace with pTemplate */ ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate); if( ppPrev==0 ){ /* There already exists a WhereLoop on the list that is better ** than pTemplate, so just ignore pTemplate */ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" skip: "); sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC); } #endif return SQLITE_OK; }else{ p = *ppPrev; } /* If we reach this point it means that either p[] should be overwritten ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new ** WhereLoop and insert it. */ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ if( p!=0 ){ sqlite3DebugPrintf("replace: "); sqlite3WhereLoopPrint(p, pBuilder->pWC); sqlite3DebugPrintf(" with: "); }else{ sqlite3DebugPrintf(" add: "); } sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC); } #endif if( p==0 ){ /* Allocate a new WhereLoop to add to the end of the list */ *ppPrev = p = sqlite3DbMallocRawNN(db, sizeof(WhereLoop)); if( p==0 ) return SQLITE_NOMEM_BKPT; whereLoopInit(p); p->pNextLoop = 0; }else{ /* We will be overwriting WhereLoop p[]. But before we do, first ** go through the rest of the list and delete any other entries besides ** p[] that are also supplanted by pTemplate */ WhereLoop **ppTail = &p->pNextLoop; WhereLoop *pToDel; while( *ppTail ){ ppTail = whereLoopFindLesser(ppTail, pTemplate); if( ppTail==0 ) break; pToDel = *ppTail; if( pToDel==0 ) break; *ppTail = pToDel->pNextLoop; #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" delete: "); sqlite3WhereLoopPrint(pToDel, pBuilder->pWC); } #endif whereLoopDelete(db, pToDel); } } rc = whereLoopXfer(db, p, pTemplate); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ Index *pIndex = p->u.btree.pIndex; if( pIndex && pIndex->idxType==SQLITE_IDXTYPE_IPK ){ p->u.btree.pIndex = 0; } } return rc; } /* ** Adjust the WhereLoop.nOut value downward to account for terms of the ** WHERE clause that reference the loop but which are not used by an ** index. * ** For every WHERE clause term that is not used by the index ** and which has a truth probability assigned by one of the likelihood(), ** likely(), or unlikely() SQL functions, reduce the estimated number ** of output rows by the probability specified. ** ** TUNING: For every WHERE clause term that is not used by the index ** and which does not have an assigned truth probability, heuristics ** described below are used to try to estimate the truth probability. ** TODO --> Perhaps this is something that could be improved by better ** table statistics. ** ** Heuristic 1: Estimate the truth probability as 93.75%. The 93.75% ** value corresponds to -1 in LogEst notation, so this means decrement ** the WhereLoop.nOut field for every such WHERE clause term. ** ** Heuristic 2: If there exists one or more WHERE clause terms of the ** form "x==EXPR" and EXPR is not a constant 0 or 1, then make sure the ** final output row estimate is no greater than 1/4 of the total number ** of rows in the table. In other words, assume that x==EXPR will filter ** out at least 3 out of 4 rows. If EXPR is -1 or 0 or 1, then maybe the ** "x" column is boolean or else -1 or 0 or 1 is a common default value ** on the "x" column and so in that case only cap the output row estimate ** at 1/2 instead of 1/4. */ static void whereLoopOutputAdjust( WhereClause *pWC, /* The WHERE clause */ WhereLoop *pLoop, /* The loop to adjust downward */ LogEst nRow /* Number of rows in the entire table */ ){ WhereTerm *pTerm, *pX; Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf); int i, j; LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */ assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); for(i=pWC->nBase, pTerm=pWC->a; i>0; i--, pTerm++){ assert( pTerm!=0 ); if( (pTerm->prereqAll & notAllowed)!=0 ) continue; if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue; if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) continue; for(j=pLoop->nLTerm-1; j>=0; j--){ pX = pLoop->aLTerm[j]; if( pX==0 ) continue; if( pX==pTerm ) break; if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; } if( j<0 ){ sqlite3ProgressCheck(pWC->pWInfo->pParse); if( pLoop->maskSelf==pTerm->prereqAll ){ /* If there are extra terms in the WHERE clause not used by an index ** that depend only on the table being scanned, and that will tend to ** cause many rows to be omitted, then mark that table as ** "self-culling". ** ** 2022-03-24: Self-culling only applies if either the extra terms ** are straight comparison operators that are non-true with NULL ** operand, or if the loop is not an OUTER JOIN. */ if( (pTerm->eOperator & 0x3f)!=0 || (pWC->pWInfo->pTabList->a[pLoop->iTab].fg.jointype & (JT_LEFT|JT_LTORJ))==0 ){ pLoop->wsFlags |= WHERE_SELFCULL; } } if( pTerm->truthProb<=0 ){ /* If a truth probability is specified using the likelihood() hints, ** then use the probability provided by the application. */ pLoop->nOut += pTerm->truthProb; }else{ /* In the absence of explicit truth probabilities, use heuristics to ** guess a reasonable truth probability. */ pLoop->nOut--; if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && (pTerm->wtFlags & TERM_HIGHTRUTH)==0 /* tag-20200224-1 */ ){ Expr *pRight = pTerm->pExpr->pRight; int k = 0; testcase( pTerm->pExpr->op==TK_IS ); if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){ k = 10; }else{ k = 20; } if( iReducewtFlags |= TERM_HEURTRUTH; iReduce = k; } } } } } if( pLoop->nOut > nRow-iReduce ){ pLoop->nOut = nRow - iReduce; } } /* ** Term pTerm is a vector range comparison operation. The first comparison ** in the vector can be optimized using column nEq of the index. This ** function returns the total number of vector elements that can be used ** as part of the range comparison. ** ** For example, if the query is: ** ** WHERE a = ? AND (b, c, d) > (?, ?, ?) ** ** and the index: ** ** CREATE INDEX ... ON (a, b, c, d, e) ** ** then this function would be invoked with nEq=1. The value returned in ** this case is 3. */ static int whereRangeVectorLen( Parse *pParse, /* Parsing context */ int iCur, /* Cursor open on pIdx */ Index *pIdx, /* The index to be used for a inequality constraint */ int nEq, /* Number of prior equality constraints on same index */ WhereTerm *pTerm /* The vector inequality constraint */ ){ int nCmp = sqlite3ExprVectorSize(pTerm->pExpr->pLeft); int i; nCmp = MIN(nCmp, (pIdx->nColumn - nEq)); for(i=1; ipExpr->pLeft) ); pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr; pRhs = pTerm->pExpr->pRight; if( ExprUseXSelect(pRhs) ){ pRhs = pRhs->x.pSelect->pEList->a[i].pExpr; }else{ pRhs = pRhs->x.pList->a[i].pExpr; } /* Check that the LHS of the comparison is a column reference to ** the right column of the right source table. And that the sort ** order of the index column is the same as the sort order of the ** leftmost index column. */ if( pLhs->op!=TK_COLUMN || pLhs->iTable!=iCur || pLhs->iColumn!=pIdx->aiColumn[i+nEq] || pIdx->aSortOrder[i+nEq]!=pIdx->aSortOrder[nEq] ){ break; } testcase( pLhs->iColumn==XN_ROWID ); aff = sqlite3CompareAffinity(pRhs, sqlite3ExprAffinity(pLhs)); idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn); if( aff!=idxaff ) break; pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); if( pColl==0 ) break; if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break; } return i; } /* ** Adjust the cost C by the costMult factor T. This only occurs if ** compiled with -DSQLITE_ENABLE_COSTMULT */ #ifdef SQLITE_ENABLE_COSTMULT # define ApplyCostMultiplier(C,T) C += T #else # define ApplyCostMultiplier(C,T) #endif /* ** We have so far matched pBuilder->pNew->u.btree.nEq terms of the ** index pIndex. Try to match one more. ** ** When this function is called, pBuilder->pNew->nOut contains the ** number of rows expected to be visited by filtering using the nEq ** terms only. If it is modified, this value is restored before this ** function returns. ** ** If pProbe->idxType==SQLITE_IDXTYPE_IPK, that means pIndex is ** a fake index used for the INTEGER PRIMARY KEY. */ static int whereLoopAddBtreeIndex( WhereLoopBuilder *pBuilder, /* The WhereLoop factory */ SrcItem *pSrc, /* FROM clause term being analyzed */ Index *pProbe, /* An index on pSrc */ LogEst nInMul /* log(Number of iterations due to IN) */ ){ WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyze context */ Parse *pParse = pWInfo->pParse; /* Parsing context */ sqlite3 *db = pParse->db; /* Database connection malloc context */ WhereLoop *pNew; /* Template WhereLoop under construction */ WhereTerm *pTerm; /* A WhereTerm under consideration */ int opMask; /* Valid operators for constraints */ WhereScan scan; /* Iterator for WHERE terms */ Bitmask saved_prereq; /* Original value of pNew->prereq */ u16 saved_nLTerm; /* Original value of pNew->nLTerm */ u16 saved_nEq; /* Original value of pNew->u.btree.nEq */ u16 saved_nBtm; /* Original value of pNew->u.btree.nBtm */ u16 saved_nTop; /* Original value of pNew->u.btree.nTop */ u16 saved_nSkip; /* Original value of pNew->nSkip */ u32 saved_wsFlags; /* Original value of pNew->wsFlags */ LogEst saved_nOut; /* Original value of pNew->nOut */ int rc = SQLITE_OK; /* Return code */ LogEst rSize; /* Number of rows in the table */ LogEst rLogSize; /* Logarithm of table size */ WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ pNew = pBuilder->pNew; assert( db->mallocFailed==0 || pParse->nErr>0 ); if( pParse->nErr ){ return pParse->rc; } WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d, rRun=%d\n", pProbe->pTable->zName,pProbe->zName, pNew->u.btree.nEq, pNew->nSkip, pNew->rRun)); assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); if( pNew->wsFlags & WHERE_BTM_LIMIT ){ opMask = WO_LT|WO_LE; }else{ assert( pNew->u.btree.nBtm==0 ); opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; } if( pProbe->bUnordered || pProbe->bLowQual ){ if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); if( pProbe->bLowQual ) opMask &= ~(WO_EQ|WO_IN|WO_IS); } assert( pNew->u.btree.nEqnColumn ); assert( pNew->u.btree.nEqnKeyCol || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY ); saved_nEq = pNew->u.btree.nEq; saved_nBtm = pNew->u.btree.nBtm; saved_nTop = pNew->u.btree.nTop; saved_nSkip = pNew->nSkip; saved_nLTerm = pNew->nLTerm; saved_wsFlags = pNew->wsFlags; saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, saved_nEq, opMask, pProbe); pNew->rSetup = 0; rSize = pProbe->aiRowLogEst[0]; rLogSize = estLog(rSize); for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */ LogEst rCostIdx; LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */ int nIn = 0; #ifdef SQLITE_ENABLE_STAT4 int nRecValid = pBuilder->nRecValid; #endif if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) && indexColumnNotNull(pProbe, saved_nEq) ){ continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */ } if( pTerm->prereqRight & pNew->maskSelf ) continue; /* Do not allow the upper bound of a LIKE optimization range constraint ** to mix with a lower range bound from some other source */ if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue; if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 && !constraintCompatibleWithOuterJoin(pTerm,pSrc) ){ continue; } if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){ pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE; }else{ pBuilder->bldFlags1 |= SQLITE_BLDF1_INDEXED; } pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; pNew->u.btree.nBtm = saved_nBtm; pNew->u.btree.nTop = saved_nTop; pNew->nLTerm = saved_nLTerm; if( pNew->nLTerm>=pNew->nLSlot && whereLoopResize(db, pNew, pNew->nLTerm+1) ){ break; /* OOM while trying to enlarge the pNew->aLTerm array */ } pNew->aLTerm[pNew->nLTerm++] = pTerm; pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf; assert( nInMul==0 || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0 || (pNew->wsFlags & WHERE_COLUMN_IN)!=0 || (pNew->wsFlags & WHERE_SKIPSCAN)!=0 ); if( eOp & WO_IN ){ Expr *pExpr = pTerm->pExpr; if( ExprUseXSelect(pExpr) ){ /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ int i; nIn = 46; assert( 46==sqlite3LogEst(25) ); /* The expression may actually be of the form (x, y) IN (SELECT...). ** In this case there is a separate term for each of (x) and (y). ** However, the nIn multiplier should only be applied once, not once ** for each such term. The following loop checks that pTerm is the ** first such term in use, and sets nIn back to 0 if it is not. */ for(i=0; inLTerm-1; i++){ if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0; } }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ nIn = sqlite3LogEst(pExpr->x.pList->nExpr); } if( pProbe->hasStat1 && rLogSize>=10 ){ LogEst M, logK, x; /* Let: ** N = the total number of rows in the table ** K = the number of entries on the RHS of the IN operator ** M = the number of rows in the table that match terms to the ** to the left in the same index. If the IN operator is on ** the left-most index column, M==N. ** ** Given the definitions above, it is better to omit the IN operator ** from the index lookup and instead do a scan of the M elements, ** testing each scanned row against the IN operator separately, if: ** ** M*log(K) < K*log(N) ** ** Our estimates for M, K, and N might be inaccurate, so we build in ** a safety margin of 2 (LogEst: 10) that favors using the IN operator ** with the index, as using an index has better worst-case behavior. ** If we do not have real sqlite_stat1 data, always prefer to use ** the index. Do not bother with this optimization on very small ** tables (less than 2 rows) as it is pointless in that case. */ M = pProbe->aiRowLogEst[saved_nEq]; logK = estLog(nIn); /* TUNING v----- 10 to bias toward indexed IN */ x = M + logK + 10 - (nIn + rLogSize); if( x>=0 ){ WHERETRACE(0x40, ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d) " "prefers indexed lookup\n", saved_nEq, M, logK, nIn, rLogSize, x)); }else if( nInMul<2 && OptimizationEnabled(db, SQLITE_SeekScan) ){ WHERETRACE(0x40, ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d" " nInMul=%d) prefers skip-scan\n", saved_nEq, M, logK, nIn, rLogSize, x, nInMul)); pNew->wsFlags |= WHERE_IN_SEEKSCAN; }else{ WHERETRACE(0x40, ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d" " nInMul=%d) prefers normal scan\n", saved_nEq, M, logK, nIn, rLogSize, x, nInMul)); continue; } } pNew->wsFlags |= WHERE_COLUMN_IN; }else if( eOp & (WO_EQ|WO_IS) ){ int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; assert( saved_nEq==pNew->u.btree.nEq ); if( iCol==XN_ROWID || (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){ if( iCol==XN_ROWID || pProbe->uniqNotNull || (pProbe->nKeyCol==1 && pProbe->onError && eOp==WO_EQ) ){ pNew->wsFlags |= WHERE_ONEROW; }else{ pNew->wsFlags |= WHERE_UNQ_WANTED; } } if( scan.iEquiv>1 ) pNew->wsFlags |= WHERE_TRANSCONS; }else if( eOp & WO_ISNULL ){ pNew->wsFlags |= WHERE_COLUMN_NULL; }else{ int nVecLen = whereRangeVectorLen( pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm ); if( eOp & (WO_GT|WO_GE) ){ testcase( eOp & WO_GT ); testcase( eOp & WO_GE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pNew->u.btree.nBtm = nVecLen; pBtm = pTerm; pTop = 0; if( pTerm->wtFlags & TERM_LIKEOPT ){ /* Range constraints that come from the LIKE optimization are ** always used in pairs. */ pTop = &pTerm[1]; assert( (pTop-(pTerm->pWC->a))pWC->nTerm ); assert( pTop->wtFlags & TERM_LIKEOPT ); assert( pTop->eOperator==WO_LT ); if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ pNew->aLTerm[pNew->nLTerm++] = pTop; pNew->wsFlags |= WHERE_TOP_LIMIT; pNew->u.btree.nTop = 1; } }else{ assert( eOp & (WO_LT|WO_LE) ); testcase( eOp & WO_LT ); testcase( eOp & WO_LE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; pNew->u.btree.nTop = nVecLen; pTop = pTerm; pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? pNew->aLTerm[pNew->nLTerm-2] : 0; } } /* At this point pNew->nOut is set to the number of rows expected to ** be visited by the index scan before considering term pTerm, or the ** values of nIn and nInMul. In other words, assuming that all ** "x IN(...)" terms are replaced with "x = ?". This block updates ** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */ assert( pNew->nOut==saved_nOut ); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ /* Adjust nOut using stat4 data. Or, if there is no stat4 ** data, using some other estimate. */ whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew); }else{ int nEq = ++pNew->u.btree.nEq; assert( eOp & (WO_ISNULL|WO_EQ|WO_IN|WO_IS) ); assert( pNew->nOut==saved_nOut ); if( pTerm->truthProb<=0 && pProbe->aiColumn[saved_nEq]>=0 ){ assert( (eOp & WO_IN) || nIn==0 ); testcase( eOp & WO_IN ); pNew->nOut += pTerm->truthProb; pNew->nOut -= nIn; }else{ #ifdef SQLITE_ENABLE_STAT4 tRowcnt nOut = 0; if( nInMul==0 && pProbe->nSample && ALWAYS(pNew->u.btree.nEq<=pProbe->nSampleCol) && ((eOp & WO_IN)==0 || ExprUseXList(pTerm->pExpr)) && OptimizationEnabled(db, SQLITE_Stat4) ){ Expr *pExpr = pTerm->pExpr; if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){ testcase( eOp & WO_EQ ); testcase( eOp & WO_IS ); testcase( eOp & WO_ISNULL ); rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); }else{ rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut); } if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */ if( nOut ){ pNew->nOut = sqlite3LogEst(nOut); if( nEq==1 /* TUNING: Mark terms as "low selectivity" if they seem likely ** to be true for half or more of the rows in the table. ** See tag-202002240-1 */ && pNew->nOut+10 > pProbe->aiRowLogEst[0] ){ #if WHERETRACE_ENABLED /* 0x01 */ if( sqlite3WhereTrace & 0x20 ){ sqlite3DebugPrintf( "STAT4 determines term has low selectivity:\n"); sqlite3WhereTermPrint(pTerm, 999); } #endif pTerm->wtFlags |= TERM_HIGHTRUTH; if( pTerm->wtFlags & TERM_HEURTRUTH ){ /* If the term has previously been used with an assumption of ** higher selectivity, then set the flag to rerun the ** loop computations. */ pBuilder->bldFlags2 |= SQLITE_BLDF2_2NDPASS; } } if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; pNew->nOut -= nIn; } } if( nOut==0 ) #endif { pNew->nOut += (pProbe->aiRowLogEst[nEq] - pProbe->aiRowLogEst[nEq-1]); if( eOp & WO_ISNULL ){ /* TUNING: If there is no likelihood() value, assume that a ** "col IS NULL" expression matches twice as many rows ** as (col=?). */ pNew->nOut += 10; } } } } /* Set rCostIdx to the cost of visiting selected rows in index. Add ** it to pNew->rRun, which is currently set to the cost of the index ** seek only. Then, if this is a non-covering index, add the cost of ** visiting the rows in the main table. */ assert( pSrc->pTab->szTabRow>0 ); if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ /* The pProbe->szIdxRow is low for an IPK table since the interior ** pages are small. Thus szIdxRow gives a good estimate of seek cost. ** But the leaf pages are full-size, so pProbe->szIdxRow would badly ** under-estimate the scanning cost. */ rCostIdx = pNew->nOut + 16; }else{ rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; } pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK|WHERE_EXPRIDX))==0 ){ pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16); } ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult); nOutUnadjusted = pNew->nOut; pNew->rRun += nInMul + nIn; pNew->nOut += nInMul + nIn; whereLoopOutputAdjust(pBuilder->pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ pNew->nOut = saved_nOut; }else{ pNew->nOut = nOutUnadjusted; } if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEqnColumn && (pNew->u.btree.nEqnKeyCol || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) ){ if( pNew->u.btree.nEq>3 ){ sqlite3ProgressCheck(pParse); } whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } pNew->nOut = saved_nOut; #ifdef SQLITE_ENABLE_STAT4 pBuilder->nRecValid = nRecValid; #endif } pNew->prereq = saved_prereq; pNew->u.btree.nEq = saved_nEq; pNew->u.btree.nBtm = saved_nBtm; pNew->u.btree.nTop = saved_nTop; pNew->nSkip = saved_nSkip; pNew->wsFlags = saved_wsFlags; pNew->nOut = saved_nOut; pNew->nLTerm = saved_nLTerm; /* Consider using a skip-scan if there are no WHERE clause constraints ** available for the left-most terms of the index, and if the average ** number of repeats in the left-most terms is at least 18. ** ** The magic number 18 is selected on the basis that scanning 17 rows ** is almost always quicker than an index seek (even though if the index ** contains fewer than 2^17 rows we assume otherwise in other parts of ** the code). And, even if it is not, it should not be too much slower. ** On the other hand, the extra seeks could end up being significantly ** more expensive. */ assert( 42==sqlite3LogEst(18) ); if( saved_nEq==saved_nSkip && saved_nEq+1nKeyCol && saved_nEq==pNew->nLTerm && pProbe->noSkipScan==0 && pProbe->hasStat1!=0 && OptimizationEnabled(db, SQLITE_SkipScan) && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK ){ LogEst nIter; pNew->u.btree.nEq++; pNew->nSkip++; pNew->aLTerm[pNew->nLTerm++] = 0; pNew->wsFlags |= WHERE_SKIPSCAN; nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1]; pNew->nOut -= nIter; /* TUNING: Because uncertainties in the estimates for skip-scan queries, ** add a 1.375 fudge factor to make skip-scan slightly less likely. */ nIter += 5; whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul); pNew->nOut = saved_nOut; pNew->u.btree.nEq = saved_nEq; pNew->nSkip = saved_nSkip; pNew->wsFlags = saved_wsFlags; } WHERETRACE(0x800, ("END %s.addBtreeIdx(%s), nEq=%d, rc=%d\n", pProbe->pTable->zName, pProbe->zName, saved_nEq, rc)); return rc; } /* ** Return True if it is possible that pIndex might be useful in ** implementing the ORDER BY clause in pBuilder. ** ** Return False if pBuilder does not contain an ORDER BY clause or ** if there is no way for pIndex to be useful in implementing that ** ORDER BY clause. */ static int indexMightHelpWithOrderBy( WhereLoopBuilder *pBuilder, Index *pIndex, int iCursor ){ ExprList *pOB; ExprList *aColExpr; int ii, jj; if( pIndex->bUnordered ) return 0; if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; for(ii=0; iinExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr); if( NEVER(pExpr==0) ) continue; if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){ if( pExpr->iColumn<0 ) return 1; for(jj=0; jjnKeyCol; jj++){ if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; } }else if( (aColExpr = pIndex->aColExpr)!=0 ){ for(jj=0; jjnKeyCol; jj++){ if( pIndex->aiColumn[jj]!=XN_EXPR ) continue; if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ return 1; } } } } return 0; } /* Check to see if a partial index with pPartIndexWhere can be used ** in the current query. Return true if it can be and false if not. */ static int whereUsablePartialIndex( int iTab, /* The table for which we want an index */ u8 jointype, /* The JT_* flags on the join */ WhereClause *pWC, /* The WHERE clause of the query */ Expr *pWhere /* The WHERE clause from the partial index */ ){ int i; WhereTerm *pTerm; Parse *pParse; if( jointype & JT_LTORJ ) return 0; pParse = pWC->pWInfo->pParse; while( pWhere->op==TK_AND ){ if( !whereUsablePartialIndex(iTab,jointype,pWC,pWhere->pLeft) ) return 0; pWhere = pWhere->pRight; } if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0; for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ Expr *pExpr; pExpr = pTerm->pExpr; if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab) && ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON)) && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) && (pTerm->wtFlags & TERM_VNULL)==0 ){ return 1; } } return 0; } /* ** pIdx is an index containing expressions. Check it see if any of the ** expressions in the index match the pExpr expression. */ static int exprIsCoveredByIndex( const Expr *pExpr, const Index *pIdx, int iTabCur ){ int i; for(i=0; inColumn; i++){ if( pIdx->aiColumn[i]==XN_EXPR && sqlite3ExprCompare(0, pExpr, pIdx->aColExpr->a[i].pExpr, iTabCur)==0 ){ return 1; } } return 0; } /* ** Structure passed to the whereIsCoveringIndex Walker callback. */ typedef struct CoveringIndexCheck CoveringIndexCheck; struct CoveringIndexCheck { Index *pIdx; /* The index */ int iTabCur; /* Cursor number for the corresponding table */ u8 bExpr; /* Uses an indexed expression */ u8 bUnidx; /* Uses an unindexed column not within an indexed expr */ }; /* ** Information passed in is pWalk->u.pCovIdxCk. Call it pCk. ** ** If the Expr node references the table with cursor pCk->iTabCur, then ** make sure that column is covered by the index pCk->pIdx. We know that ** all columns less than 63 (really BMS-1) are covered, so we don't need ** to check them. But we do need to check any column at 63 or greater. ** ** If the index does not cover the column, then set pWalk->eCode to ** non-zero and return WRC_Abort to stop the search. ** ** If this node does not disprove that the index can be a covering index, ** then just return WRC_Continue, to continue the search. ** ** If pCk->pIdx contains indexed expressions and one of those expressions ** matches pExpr, then prune the search. */ static int whereIsCoveringIndexWalkCallback(Walker *pWalk, Expr *pExpr){ int i; /* Loop counter */ const Index *pIdx; /* The index of interest */ const i16 *aiColumn; /* Columns contained in the index */ u16 nColumn; /* Number of columns in the index */ CoveringIndexCheck *pCk; /* Info about this search */ pCk = pWalk->u.pCovIdxCk; pIdx = pCk->pIdx; if( (pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN) ){ /* if( pExpr->iColumn<(BMS-1) && pIdx->bHasExpr==0 ) return WRC_Continue;*/ if( pExpr->iTable!=pCk->iTabCur ) return WRC_Continue; pIdx = pWalk->u.pCovIdxCk->pIdx; aiColumn = pIdx->aiColumn; nColumn = pIdx->nColumn; for(i=0; iiColumn ) return WRC_Continue; } pCk->bUnidx = 1; return WRC_Abort; }else if( pIdx->bHasExpr && exprIsCoveredByIndex(pExpr, pIdx, pWalk->u.pCovIdxCk->iTabCur) ){ pCk->bExpr = 1; return WRC_Prune; } return WRC_Continue; } /* ** pIdx is an index that covers all of the low-number columns used by ** pWInfo->pSelect (columns from 0 through 62) or an index that has ** expressions terms. Hence, we cannot determine whether or not it is ** a covering index by using the colUsed bitmasks. We have to do a search ** to see if the index is covering. This routine does that search. ** ** The return value is one of these: ** ** 0 The index is definitely not a covering index ** ** WHERE_IDX_ONLY The index is definitely a covering index ** ** WHERE_EXPRIDX The index is likely a covering index, but it is ** difficult to determine precisely because of the ** expressions that are indexed. Score it as a ** covering index, but still keep the main table open ** just in case we need it. ** ** This routine is an optimization. It is always safe to return zero. ** But returning one of the other two values when zero should have been ** returned can lead to incorrect bytecode and assertion faults. */ static SQLITE_NOINLINE u32 whereIsCoveringIndex( WhereInfo *pWInfo, /* The WHERE clause context */ Index *pIdx, /* Index that is being tested */ int iTabCur /* Cursor for the table being indexed */ ){ int i, rc; struct CoveringIndexCheck ck; Walker w; if( pWInfo->pSelect==0 ){ /* We don't have access to the full query, so we cannot check to see ** if pIdx is covering. Assume it is not. */ return 0; } if( pIdx->bHasExpr==0 ){ for(i=0; inColumn; i++){ if( pIdx->aiColumn[i]>=BMS-1 ) break; } if( i>=pIdx->nColumn ){ /* pIdx does not index any columns greater than 62, but we know from ** colMask that columns greater than 62 are used, so this is not a ** covering index */ return 0; } } ck.pIdx = pIdx; ck.iTabCur = iTabCur; ck.bExpr = 0; ck.bUnidx = 0; memset(&w, 0, sizeof(w)); w.xExprCallback = whereIsCoveringIndexWalkCallback; w.xSelectCallback = sqlite3SelectWalkNoop; w.u.pCovIdxCk = &ck; sqlite3WalkSelect(&w, pWInfo->pSelect); if( ck.bUnidx ){ rc = 0; }else if( ck.bExpr ){ rc = WHERE_EXPRIDX; }else{ rc = WHERE_IDX_ONLY; } return rc; } /* ** This is an sqlite3ParserAddCleanup() callback that is invoked to ** free the Parse->pIdxEpr list when the Parse object is destroyed. */ static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){ IndexedExpr **pp = (IndexedExpr**)pObject; while( *pp!=0 ){ IndexedExpr *p = *pp; *pp = p->pIENext; sqlite3ExprDelete(db, p->pExpr); sqlite3DbFreeNN(db, p); } } /* ** This function is called for a partial index - one with a WHERE clause - in ** two scenarios. In both cases, it determines whether or not the WHERE ** clause on the index implies that a column of the table may be safely ** replaced by a constant expression. For example, in the following ** SELECT: ** ** CREATE INDEX i1 ON t1(b, c) WHERE a=; ** SELECT a, b, c FROM t1 WHERE a= AND b=?; ** ** The "a" in the select-list may be replaced by , iff: ** ** (a) is a constant expression, and ** (b) The (a=) comparison uses the BINARY collation sequence, and ** (c) Column "a" has an affinity other than NONE or BLOB. ** ** If argument pItem is NULL, then pMask must not be NULL. In this case this ** function is being called as part of determining whether or not pIdx ** is a covering index. This function clears any bits in (*pMask) ** corresponding to columns that may be replaced by constants as described ** above. ** ** Otherwise, if pItem is not NULL, then this function is being called ** as part of coding a loop that uses index pIdx. In this case, add entries ** to the Parse.pIdxPartExpr list for each column that can be replaced ** by a constant. */ static void wherePartIdxExpr( Parse *pParse, /* Parse context */ Index *pIdx, /* Partial index being processed */ Expr *pPart, /* WHERE clause being processed */ Bitmask *pMask, /* Mask to clear bits in */ int iIdxCur, /* Cursor number for index */ SrcItem *pItem /* The FROM clause entry for the table */ ){ assert( pItem==0 || (pItem->fg.jointype & JT_RIGHT)==0 ); assert( (pItem==0 || pMask==0) && (pMask!=0 || pItem!=0) ); if( pPart->op==TK_AND ){ wherePartIdxExpr(pParse, pIdx, pPart->pRight, pMask, iIdxCur, pItem); pPart = pPart->pLeft; } if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){ Expr *pLeft = pPart->pLeft; Expr *pRight = pPart->pRight; u8 aff; if( pLeft->op!=TK_COLUMN ) return; if( !sqlite3ExprIsConstant(pRight) ) return; if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return; if( pLeft->iColumn<0 ) return; aff = pIdx->pTable->aCol[pLeft->iColumn].affinity; if( aff>=SQLITE_AFF_TEXT ){ if( pItem ){ sqlite3 *db = pParse->db; IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocRaw(db, sizeof(*p)); if( p ){ int bNullRow = (pItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0; p->pExpr = sqlite3ExprDup(db, pRight, 0); p->iDataCur = pItem->iCursor; p->iIdxCur = iIdxCur; p->iIdxCol = pLeft->iColumn; p->bMaybeNullRow = bNullRow; p->pIENext = pParse->pIdxPartExpr; p->aff = aff; pParse->pIdxPartExpr = p; if( p->pIENext==0 ){ void *pArg = (void*)&pParse->pIdxPartExpr; sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg); } } }else if( pLeft->iColumn<(BMS-1) ){ *pMask &= ~((Bitmask)1 << pLeft->iColumn); } } } } /* ** Add all WhereLoop objects for a single table of the join where the table ** is identified by pBuilder->pNew->iTab. That table is guaranteed to be ** a b-tree table, not a virtual table. ** ** The costs (WhereLoop.rRun) of the b-tree loops added by this function ** are calculated as follows: ** ** For a full scan, assuming the table (or index) contains nRow rows: ** ** cost = nRow * 3.0 // full-table scan ** cost = nRow * K // scan of covering index ** cost = nRow * (K+3.0) // scan of non-covering index ** ** where K is a value between 1.1 and 3.0 set based on the relative ** estimated average size of the index and table records. ** ** For an index scan, where nVisit is the number of index rows visited ** by the scan, and nSeek is the number of seek operations required on ** the index b-tree: ** ** cost = nSeek * (log(nRow) + K * nVisit) // covering index ** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index ** ** Normally, nSeek is 1. nSeek values greater than 1 come about if the ** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when ** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans. ** ** The estimated values (nRow, nVisit, nSeek) often contain a large amount ** of uncertainty. For this reason, scoring is designed to pick plans that ** "do the least harm" if the estimates are inaccurate. For example, a ** log(nRow) factor is omitted from a non-covering index scan in order to ** bias the scoring in favor of using an index, since the worst-case ** performance of using an index is far better than the worst-case performance ** of a full table scan. */ static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ Bitmask mPrereq /* Extra prerequisites for using this table */ ){ WhereInfo *pWInfo; /* WHERE analysis context */ Index *pProbe; /* An index we are evaluating */ Index sPk; /* A fake index object for the primary key */ LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */ SrcList *pTabList; /* The FROM clause */ SrcItem *pSrc; /* The FROM clause btree term to add */ WhereLoop *pNew; /* Template WhereLoop object */ int rc = SQLITE_OK; /* Return code */ int iSortIdx = 1; /* Index number */ int b; /* A boolean value */ LogEst rSize; /* number of rows in the table */ WhereClause *pWC; /* The parsed WHERE clause */ Table *pTab; /* Table being queried */ pNew = pBuilder->pNew; pWInfo = pBuilder->pWInfo; pTabList = pWInfo->pTabList; pSrc = pTabList->a + pNew->iTab; pTab = pSrc->pTab; pWC = pBuilder->pWC; assert( !IsVirtual(pSrc->pTab) ); if( pSrc->fg.isIndexedBy ){ assert( pSrc->fg.isCte==0 ); /* An INDEXED BY clause specifies a particular index to use */ pProbe = pSrc->u2.pIBIndex; }else if( !HasRowid(pTab) ){ pProbe = pTab->pIndex; }else{ /* There is no INDEXED BY clause. Create a fake Index object in local ** variable sPk to represent the rowid primary key index. Make this ** fake index the first in a chain of Index objects with all of the real ** indices to follow */ Index *pFirst; /* First of real indices on the table */ memset(&sPk, 0, sizeof(Index)); sPk.nKeyCol = 1; sPk.nColumn = 1; sPk.aiColumn = &aiColumnPk; sPk.aiRowLogEst = aiRowEstPk; sPk.onError = OE_Replace; sPk.pTable = pTab; sPk.szIdxRow = 3; /* TUNING: Interior rows of IPK table are very small */ sPk.idxType = SQLITE_IDXTYPE_IPK; aiRowEstPk[0] = pTab->nRowLogEst; aiRowEstPk[1] = 0; pFirst = pSrc->pTab->pIndex; if( pSrc->fg.notIndexed==0 ){ /* The real indices of the table are only considered if the ** NOT INDEXED qualifier is omitted from the FROM clause */ sPk.pNext = pFirst; } pProbe = &sPk; } rSize = pTab->nRowLogEst; #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet /* Not part of an OR optimization */ && (pWInfo->wctrlFlags & (WHERE_RIGHT_JOIN|WHERE_OR_SUBCLAUSE))==0 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ && !pSrc->fg.isCorrelated /* Not a correlated subquery */ && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ && (pSrc->fg.jointype & JT_RIGHT)==0 /* Not the right tab of a RIGHT JOIN */ ){ /* Generate auto-index WhereLoops */ LogEst rLogSize; /* Logarithm of the number of rows in the table */ WhereTerm *pTerm; WhereTerm *pWCEnd = pWC->a + pWC->nTerm; rLogSize = estLog(rSize); for(pTerm=pWC->a; rc==SQLITE_OK && pTermprereqRight & pNew->maskSelf ) continue; if( termCanDriveIndex(pTerm, pSrc, 0) ){ pNew->u.btree.nEq = 1; pNew->nSkip = 0; pNew->u.btree.pIndex = 0; pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; /* TUNING: One-time cost for computing the automatic index is ** estimated to be X*N*log2(N) where N is the number of rows in ** the table being indexed and where X is 7 (LogEst=28) for normal ** tables or 0.5 (LogEst=-10) for views and subqueries. The value ** of X is smaller for views and subqueries so that the query planner ** will be more aggressive about generating automatic indexes for ** those objects, since there is no opportunity to add schema ** indexes on subqueries and views. */ pNew->rSetup = rLogSize + rSize; if( !IsView(pTab) && (pTab->tabFlags & TF_Ephemeral)==0 ){ pNew->rSetup += 28; }else{ pNew->rSetup -= 25; /* Greatly reduced setup cost for auto indexes ** on ephemeral materializations of views */ } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); if( pNew->rSetup<0 ) pNew->rSetup = 0; /* TUNING: Each index lookup yields 20 rows in the table. This ** is more than the usual guess of 10 rows, since we have no way ** of knowing how selective the index will ultimately be. It would ** not be unreasonable to make this value much larger. */ pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut); pNew->wsFlags = WHERE_AUTO_INDEX; pNew->prereq = mPrereq | pTerm->prereqRight; rc = whereLoopInsert(pBuilder, pNew); } } } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ /* Loop over all indices. If there was an INDEXED BY clause, then only ** consider index pProbe. */ for(; rc==SQLITE_OK && pProbe; pProbe=(pSrc->fg.isIndexedBy ? 0 : pProbe->pNext), iSortIdx++ ){ if( pProbe->pPartIdxWhere!=0 && !whereUsablePartialIndex(pSrc->iCursor, pSrc->fg.jointype, pWC, pProbe->pPartIdxWhere) ){ testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */ continue; /* Partial index inappropriate for this query */ } if( pProbe->bNoQuery ) continue; rSize = pProbe->aiRowLogEst[0]; pNew->u.btree.nEq = 0; pNew->u.btree.nBtm = 0; pNew->u.btree.nTop = 0; pNew->nSkip = 0; pNew->nLTerm = 0; pNew->iSortIdx = 0; pNew->rSetup = 0; pNew->prereq = mPrereq; pNew->nOut = rSize; pNew->u.btree.pIndex = pProbe; b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */ assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 ); if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ /* Integer primary key index */ pNew->wsFlags = WHERE_IPK; /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; /* TUNING: Cost of full table scan is 3.0*N. The 3.0 factor is an ** extra cost designed to discourage the use of full table scans, ** since index lookups have better worst-case performance if our ** stat guesses are wrong. Reduce the 3.0 penalty slightly ** (to 2.75) if we have valid STAT4 information for the table. ** At 2.75, a full table scan is preferred over using an index on ** a column with just two distinct values where each value has about ** an equal number of appearances. Without STAT4 data, we still want ** to use an index in that case, since the constraint might be for ** the scarcer of the two values, and in that case an index lookup is ** better. */ #ifdef SQLITE_ENABLE_STAT4 pNew->rRun = rSize + 16 - 2*((pTab->tabFlags & TF_HasStat4)!=0); #else pNew->rRun = rSize + 16; #endif ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; }else{ Bitmask m; if( pProbe->isCovering ){ m = 0; pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; }else{ m = pSrc->colUsed & pProbe->colNotIdxed; if( pProbe->pPartIdxWhere ){ wherePartIdxExpr( pWInfo->pParse, pProbe, pProbe->pPartIdxWhere, &m, 0, 0 ); } pNew->wsFlags = WHERE_INDEXED; if( m==TOPBIT || (pProbe->bHasExpr && !pProbe->bHasVCol && m!=0) ){ u32 isCov = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor); if( isCov==0 ){ WHERETRACE(0x200, ("-> %s is not a covering index" " according to whereIsCoveringIndex()\n", pProbe->zName)); assert( m!=0 ); }else{ m = 0; pNew->wsFlags |= isCov; if( isCov & WHERE_IDX_ONLY ){ WHERETRACE(0x200, ("-> %s is a covering expression index" " according to whereIsCoveringIndex()\n", pProbe->zName)); }else{ assert( isCov==WHERE_EXPRIDX ); WHERETRACE(0x200, ("-> %s might be a covering expression index" " according to whereIsCoveringIndex()\n", pProbe->zName)); } } }else if( m==0 ){ WHERETRACE(0x200, ("-> %s a covering index according to bitmasks\n", pProbe->zName, m==0 ? "is" : "is not")); pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; } } /* Full scan via index */ if( b || !HasRowid(pTab) || pProbe->pPartIdxWhere!=0 || pSrc->fg.isIndexedBy || ( m==0 && pProbe->bUnordered==0 && (pProbe->szIdxRowszTabRow) && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) ) ){ pNew->iSortIdx = b ? iSortIdx : 0; /* The cost of visiting the index rows is N*K, where K is ** between 1.1 and 3.0, depending on the relative sizes of the ** index and table rows. */ pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow; if( m!=0 ){ /* If this is a non-covering index scan, add in the cost of ** doing table lookups. The cost will be 3x the number of ** lookups. Take into account WHERE clause terms that can be ** satisfied using just the index, and that do not require a ** table lookup. */ LogEst nLookup = rSize + 16; /* Base cost: N*3 */ int ii; int iCur = pSrc->iCursor; WhereClause *pWC2 = &pWInfo->sWC; for(ii=0; iinTerm; ii++){ WhereTerm *pTerm = &pWC2->a[ii]; if( !sqlite3ExprCoveredByIndex(pTerm->pExpr, iCur, pProbe) ){ break; } /* pTerm can be evaluated using just the index. So reduce ** the expected number of table lookups accordingly */ if( pTerm->truthProb<=0 ){ nLookup += pTerm->truthProb; }else{ nLookup--; if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19; } } pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup); } ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); if( (pSrc->fg.jointype & JT_RIGHT)!=0 && pProbe->aColExpr ){ /* Do not do an SCAN of a index-on-expression in a RIGHT JOIN ** because the cursor used to access the index might not be ** positioned to the correct row during the right-join no-match ** loop. */ }else{ rc = whereLoopInsert(pBuilder, pNew); } pNew->nOut = rSize; if( rc ) break; } } pBuilder->bldFlags1 = 0; rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0); if( pBuilder->bldFlags1==SQLITE_BLDF1_INDEXED ){ /* If a non-unique index is used, or if a prefix of the key for ** unique index is used (making the index functionally non-unique) ** then the sqlite_stat1 data becomes important for scoring the ** plan */ pTab->tabFlags |= TF_StatsUsed; } #ifdef SQLITE_ENABLE_STAT4 sqlite3Stat4ProbeFree(pBuilder->pRec); pBuilder->nRecValid = 0; pBuilder->pRec = 0; #endif } return rc; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Return true if pTerm is a virtual table LIMIT or OFFSET term. */ static int isLimitTerm(WhereTerm *pTerm){ assert( pTerm->eOperator==WO_AUX || pTerm->eMatchOp==0 ); return pTerm->eMatchOp>=SQLITE_INDEX_CONSTRAINT_LIMIT && pTerm->eMatchOp<=SQLITE_INDEX_CONSTRAINT_OFFSET; } /* ** Argument pIdxInfo is already populated with all constraints that may ** be used by the virtual table identified by pBuilder->pNew->iTab. This ** function marks a subset of those constraints usable, invokes the ** xBestIndex method and adds the returned plan to pBuilder. ** ** A constraint is marked usable if: ** ** * Argument mUsable indicates that its prerequisites are available, and ** ** * It is not one of the operators specified in the mExclude mask passed ** as the fourth argument (which in practice is either WO_IN or 0). ** ** Argument mPrereq is a mask of tables that must be scanned before the ** virtual table in question. These are added to the plans prerequisites ** before it is added to pBuilder. ** ** Output parameter *pbIn is set to true if the plan added to pBuilder ** uses one or more WO_IN terms, or false otherwise. */ static int whereLoopAddVirtualOne( WhereLoopBuilder *pBuilder, Bitmask mPrereq, /* Mask of tables that must be used. */ Bitmask mUsable, /* Mask of usable tables */ u16 mExclude, /* Exclude terms using these operators */ sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */ u16 mNoOmit, /* Do not omit these constraints */ int *pbIn, /* OUT: True if plan uses an IN(...) op */ int *pbRetryLimit /* OUT: Retry without LIMIT/OFFSET */ ){ WhereClause *pWC = pBuilder->pWC; HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage; int i; int mxTerm; int rc = SQLITE_OK; WhereLoop *pNew = pBuilder->pNew; Parse *pParse = pBuilder->pWInfo->pParse; SrcItem *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab]; int nConstraint = pIdxInfo->nConstraint; assert( (mUsable & mPrereq)==mPrereq ); *pbIn = 0; pNew->prereq = mPrereq; /* Set the usable flag on the subset of constraints identified by ** arguments mUsable and mExclude. */ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; ia[pIdxCons->iTermOffset]; pIdxCons->usable = 0; if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight && (pTerm->eOperator & mExclude)==0 && (pbRetryLimit || !isLimitTerm(pTerm)) ){ pIdxCons->usable = 1; } } /* Initialize the output fields of the sqlite3_index_info structure */ memset(pUsage, 0, sizeof(pUsage[0])*nConstraint); assert( pIdxInfo->needToFreeIdxStr==0 ); pIdxInfo->idxStr = 0; pIdxInfo->idxNum = 0; pIdxInfo->orderByConsumed = 0; pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; pIdxInfo->estimatedRows = 25; pIdxInfo->idxFlags = 0; pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; pHidden->mHandleIn = 0; /* Invoke the virtual table xBestIndex() method */ rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); if( rc ){ if( rc==SQLITE_CONSTRAINT ){ /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means ** that the particular combination of parameters provided is unusable. ** Make no entries in the loop table. */ WHERETRACE(0xffffffff, (" ^^^^--- non-viable plan rejected!\n")); return SQLITE_OK; } return rc; } mxTerm = -1; assert( pNew->nLSlot>=nConstraint ); memset(pNew->aLTerm, 0, sizeof(pNew->aLTerm[0])*nConstraint ); memset(&pNew->u.vtab, 0, sizeof(pNew->u.vtab)); pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; i=0 ){ WhereTerm *pTerm; int j = pIdxCons->iTermOffset; if( iTerm>=nConstraint || j<0 || j>=pWC->nTerm || pNew->aLTerm[iTerm]!=0 || pIdxCons->usable==0 ){ sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); testcase( pIdxInfo->needToFreeIdxStr ); return SQLITE_ERROR; } testcase( iTerm==nConstraint-1 ); testcase( j==0 ); testcase( j==pWC->nTerm-1 ); pTerm = &pWC->a[j]; pNew->prereq |= pTerm->prereqRight; assert( iTermnLSlot ); pNew->aLTerm[iTerm] = pTerm; if( iTerm>mxTerm ) mxTerm = iTerm; testcase( iTerm==15 ); testcase( iTerm==16 ); if( pUsage[i].omit ){ if( i<16 && ((1<u.vtab.omitMask |= 1<eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET ){ pNew->u.vtab.bOmitOffset = 1; } } if( SMASKBIT32(i) & pHidden->mHandleIn ){ pNew->u.vtab.mHandleIn |= MASKBIT32(iTerm); }else if( (pTerm->eOperator & WO_IN)!=0 ){ /* A virtual table that is constrained by an IN clause may not ** consume the ORDER BY clause because (1) the order of IN terms ** is not necessarily related to the order of output terms and ** (2) Multiple outputs from a single IN value will not merge ** together. */ pIdxInfo->orderByConsumed = 0; pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE; *pbIn = 1; assert( (mExclude & WO_IN)==0 ); } assert( pbRetryLimit || !isLimitTerm(pTerm) ); if( isLimitTerm(pTerm) && *pbIn ){ /* If there is an IN(...) term handled as an == (separate call to ** xFilter for each value on the RHS of the IN) and a LIMIT or ** OFFSET term handled as well, the plan is unusable. Set output ** variable *pbRetryLimit to true to tell the caller to retry with ** LIMIT and OFFSET disabled. */ if( pIdxInfo->needToFreeIdxStr ){ sqlite3_free(pIdxInfo->idxStr); pIdxInfo->idxStr = 0; pIdxInfo->needToFreeIdxStr = 0; } *pbRetryLimit = 1; return SQLITE_OK; } } } pNew->nLTerm = mxTerm+1; for(i=0; i<=mxTerm; i++){ if( pNew->aLTerm[i]==0 ){ /* The non-zero argvIdx values must be contiguous. Raise an ** error if they are not */ sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); testcase( pIdxInfo->needToFreeIdxStr ); return SQLITE_ERROR; } } assert( pNew->nLTerm<=pNew->nLSlot ); pNew->u.vtab.idxNum = pIdxInfo->idxNum; pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; pIdxInfo->needToFreeIdxStr = 0; pNew->u.vtab.idxStr = pIdxInfo->idxStr; pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? pIdxInfo->nOrderBy : 0); pNew->rSetup = 0; pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated ** that the scan will visit at most one row. Clear it otherwise. */ if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){ pNew->wsFlags |= WHERE_ONEROW; }else{ pNew->wsFlags &= ~WHERE_ONEROW; } rc = whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ sqlite3_free(pNew->u.vtab.idxStr); pNew->u.vtab.needFree = 0; } WHERETRACE(0xffffffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n", *pbIn, (sqlite3_uint64)mPrereq, (sqlite3_uint64)(pNew->prereq & ~mPrereq))); return rc; } /* ** Return the collating sequence for a constraint passed into xBestIndex. ** ** pIdxInfo must be an sqlite3_index_info structure passed into xBestIndex. ** This routine depends on there being a HiddenIndexInfo structure immediately ** following the sqlite3_index_info structure. ** ** Return a pointer to the collation name: ** ** 1. If there is an explicit COLLATE operator on the constraint, return it. ** ** 2. Else, if the column has an alternative collation, return that. ** ** 3. Otherwise, return "BINARY". */ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){ HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; const char *zRet = 0; if( iCons>=0 && iConsnConstraint ){ CollSeq *pC = 0; int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset; Expr *pX = pHidden->pWC->a[iTerm].pExpr; if( pX->pLeft ){ pC = sqlite3ExprCompareCollSeq(pHidden->pParse, pX); } zRet = (pC ? pC->zName : sqlite3StrBINARY); } return zRet; } /* ** Return true if constraint iCons is really an IN(...) constraint, or ** false otherwise. If iCons is an IN(...) constraint, set (if bHandle!=0) ** or clear (if bHandle==0) the flag to handle it using an iterator. */ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info *pIdxInfo, int iCons, int bHandle){ HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; u32 m = SMASKBIT32(iCons); if( m & pHidden->mIn ){ if( bHandle==0 ){ pHidden->mHandleIn &= ~m; }else if( bHandle>0 ){ pHidden->mHandleIn |= m; } return 1; } return 0; } /* ** This interface is callable from within the xBestIndex callback only. ** ** If possible, set (*ppVal) to point to an object containing the value ** on the right-hand-side of constraint iCons. */ SQLITE_API int sqlite3_vtab_rhs_value( sqlite3_index_info *pIdxInfo, /* Copy of first argument to xBestIndex */ int iCons, /* Constraint for which RHS is wanted */ sqlite3_value **ppVal /* Write value extracted here */ ){ HiddenIndexInfo *pH = (HiddenIndexInfo*)&pIdxInfo[1]; sqlite3_value *pVal = 0; int rc = SQLITE_OK; if( iCons<0 || iCons>=pIdxInfo->nConstraint ){ rc = SQLITE_MISUSE_BKPT; /* EV: R-30545-25046 */ }else{ if( pH->aRhs[iCons]==0 ){ WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset]; rc = sqlite3ValueFromExpr( pH->pParse->db, pTerm->pExpr->pRight, ENC(pH->pParse->db), SQLITE_AFF_BLOB, &pH->aRhs[iCons] ); testcase( rc!=SQLITE_OK ); } pVal = pH->aRhs[iCons]; } *ppVal = pVal; if( rc==SQLITE_OK && pVal==0 ){ /* IMP: R-19933-32160 */ rc = SQLITE_NOTFOUND; /* IMP: R-36424-56542 */ } return rc; } /* ** Return true if ORDER BY clause may be handled as DISTINCT. */ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){ HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; assert( pHidden->eDistinct>=0 && pHidden->eDistinct<=3 ); return pHidden->eDistinct; } /* ** Cause the prepared statement that is associated with a call to ** xBestIndex to potentially use all schemas. If the statement being ** prepared is read-only, then just start read transactions on all ** schemas. But if this is a write operation, start writes on all ** schemas. ** ** This is used by the (built-in) sqlite_dbpage virtual table. */ SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(Parse *pParse){ int nDb = pParse->db->nDb; int i; for(i=0; iwriteMask) ){ for(i=0; ipNew->iTab. That table is guaranteed to be a virtual table. ** ** If there are no LEFT or CROSS JOIN joins in the query, both mPrereq and ** mUnusable are set to 0. Otherwise, mPrereq is a mask of all FROM clause ** entries that occur before the virtual table in the FROM clause and are ** separated from it by at least one LEFT or CROSS JOIN. Similarly, the ** mUnusable mask contains all FROM clause entries that occur after the ** virtual table and are separated from it by at least one LEFT or ** CROSS JOIN. ** ** For example, if the query were: ** ** ... FROM t1, t2 LEFT JOIN t3, t4, vt CROSS JOIN t5, t6; ** ** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6). ** ** All the tables in mPrereq must be scanned before the current virtual ** table. So any terms for which all prerequisites are satisfied by ** mPrereq may be specified as "usable" in all calls to xBestIndex. ** Conversely, all tables in mUnusable must be scanned after the current ** virtual table, so any terms for which the prerequisites overlap with ** mUnusable should always be configured as "not-usable" for xBestIndex. */ static int whereLoopAddVirtual( WhereLoopBuilder *pBuilder, /* WHERE clause information */ Bitmask mPrereq, /* Tables that must be scanned before this one */ Bitmask mUnusable /* Tables that must be scanned after this one */ ){ int rc = SQLITE_OK; /* Return code */ WhereInfo *pWInfo; /* WHERE analysis context */ Parse *pParse; /* The parsing context */ WhereClause *pWC; /* The WHERE clause */ SrcItem *pSrc; /* The FROM clause term to search */ sqlite3_index_info *p; /* Object to pass to xBestIndex() */ int nConstraint; /* Number of constraints in p */ int bIn; /* True if plan uses IN(...) operator */ WhereLoop *pNew; Bitmask mBest; /* Tables used by best possible plan */ u16 mNoOmit; int bRetry = 0; /* True to retry with LIMIT/OFFSET disabled */ assert( (mPrereq & mUnusable)==0 ); pWInfo = pBuilder->pWInfo; pParse = pWInfo->pParse; pWC = pBuilder->pWC; pNew = pBuilder->pNew; pSrc = &pWInfo->pTabList->a[pNew->iTab]; assert( IsVirtual(pSrc->pTab) ); p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit); if( p==0 ) return SQLITE_NOMEM_BKPT; pNew->rSetup = 0; pNew->wsFlags = WHERE_VIRTUALTABLE; pNew->nLTerm = 0; pNew->u.vtab.needFree = 0; nConstraint = p->nConstraint; if( whereLoopResize(pParse->db, pNew, nConstraint) ){ freeIndexInfo(pParse->db, p); return SQLITE_NOMEM_BKPT; } /* First call xBestIndex() with all constraints usable. */ WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName)); WHERETRACE(0x800, (" VirtualOne: all usable\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry ); if( bRetry ){ assert( rc==SQLITE_OK ); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, 0 ); } /* If the call to xBestIndex() with all terms enabled produced a plan ** that does not require any source tables (IOW: a plan with mBest==0) ** and does not use an IN(...) operator, then there is no point in making ** any further calls to xBestIndex() since they will all return the same ** result (if the xBestIndex() implementation is sane). */ if( rc==SQLITE_OK && ((mBest = (pNew->prereq & ~mPrereq))!=0 || bIn) ){ int seenZero = 0; /* True if a plan with no prereqs seen */ int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */ Bitmask mPrev = 0; Bitmask mBestNoIn = 0; /* If the plan produced by the earlier call uses an IN(...) term, call ** xBestIndex again, this time with IN(...) terms disabled. */ if( bIn ){ WHERETRACE(0x800, (" VirtualOne: all usable w/o IN\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn, 0); assert( bIn==0 ); mBestNoIn = pNew->prereq & ~mPrereq; if( mBestNoIn==0 ){ seenZero = 1; seenZeroNoIN = 1; } } /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq) ** in the set of terms that apply to the current virtual table. */ while( rc==SQLITE_OK ){ int i; Bitmask mNext = ALLBITS; assert( mNext>0 ); for(i=0; ia[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq ); if( mThis>mPrev && mThisprereq==mPrereq ){ seenZero = 1; if( bIn==0 ) seenZeroNoIN = 1; } } /* If the calls to xBestIndex() in the above loop did not find a plan ** that requires no source tables at all (i.e. one guaranteed to be ** usable), make a call here with all source tables disabled */ if( rc==SQLITE_OK && seenZero==0 ){ WHERETRACE(0x800, (" VirtualOne: all disabled\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn, 0); if( bIn==0 ) seenZeroNoIN = 1; } /* If the calls to xBestIndex() have so far failed to find a plan ** that requires no source tables at all and does not use an IN(...) ** operator, make a final call to obtain one here. */ if( rc==SQLITE_OK && seenZeroNoIN==0 ){ WHERETRACE(0x800, (" VirtualOne: all disabled and w/o IN\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0); } } if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr); freeIndexInfo(pParse->db, p); WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc)); return rc; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** Add WhereLoop entries to handle OR terms. This works for either ** btrees or virtual tables. */ static int whereLoopAddOr( WhereLoopBuilder *pBuilder, Bitmask mPrereq, Bitmask mUnusable ){ WhereInfo *pWInfo = pBuilder->pWInfo; WhereClause *pWC; WhereLoop *pNew; WhereTerm *pTerm, *pWCEnd; int rc = SQLITE_OK; int iCur; WhereClause tempWC; WhereLoopBuilder sSubBuild; WhereOrSet sSum, sCur; SrcItem *pItem; pWC = pBuilder->pWC; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; memset(&sSum, 0, sizeof(sSum)); pItem = pWInfo->pTabList->a + pNew->iTab; iCur = pItem->iCursor; /* The multi-index OR optimization does not work for RIGHT and FULL JOIN */ if( pItem->fg.jointype & JT_RIGHT ) return SQLITE_OK; for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 ){ WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; WhereTerm *pOrTerm; int once = 1; int i, j; sSubBuild = *pBuilder; sSubBuild.pOrSet = &sCur; WHERETRACE(0x400, ("Begin processing OR-clause %p\n", pTerm)); for(pOrTerm=pOrWC->a; pOrTermeOperator & WO_AND)!=0 ){ sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; }else if( pOrTerm->leftCursor==iCur ){ tempWC.pWInfo = pWC->pWInfo; tempWC.pOuter = pWC; tempWC.op = TK_AND; tempWC.nTerm = 1; tempWC.nBase = 1; tempWC.a = pOrTerm; sSubBuild.pWC = &tempWC; }else{ continue; } sCur.n = 0; #ifdef WHERETRACE_ENABLED WHERETRACE(0x400, ("OR-term %d of %p has %d subterms:\n", (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); if( sqlite3WhereTrace & 0x20000 ){ sqlite3WhereClausePrint(sSubBuild.pWC); } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); }else #endif { rc = whereLoopAddBtree(&sSubBuild, mPrereq); } if( rc==SQLITE_OK ){ rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable); } testcase( rc==SQLITE_NOMEM && sCur.n>0 ); testcase( rc==SQLITE_DONE ); if( sCur.n==0 ){ sSum.n = 0; break; }else if( once ){ whereOrMove(&sSum, &sCur); once = 0; }else{ WhereOrSet sPrev; whereOrMove(&sPrev, &sSum); sSum.n = 0; for(i=0; inLTerm = 1; pNew->aLTerm[0] = pTerm; pNew->wsFlags = WHERE_MULTI_OR; pNew->rSetup = 0; pNew->iSortIdx = 0; memset(&pNew->u, 0, sizeof(pNew->u)); for(i=0; rc==SQLITE_OK && irRun = sSum.a[i].rRun + 1; pNew->nOut = sSum.a[i].nOut; pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); } WHERETRACE(0x400, ("End processing OR-clause %p\n", pTerm)); } } return rc; } /* ** Add all WhereLoop objects for all tables */ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo = pBuilder->pWInfo; Bitmask mPrereq = 0; Bitmask mPrior = 0; int iTab; SrcList *pTabList = pWInfo->pTabList; SrcItem *pItem; SrcItem *pEnd = &pTabList->a[pWInfo->nLevel]; sqlite3 *db = pWInfo->pParse->db; int rc = SQLITE_OK; int bFirstPastRJ = 0; int hasRightJoin = 0; WhereLoop *pNew; /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; /* Verify that pNew has already been initialized */ assert( pNew->nLTerm==0 ); assert( pNew->wsFlags==0 ); assert( pNew->nLSlot>=ArraySize(pNew->aLTermSpace) ); assert( pNew->aLTerm!=0 ); pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT; for(iTab=0, pItem=pTabList->a; pItemiTab = iTab; pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); if( bFirstPastRJ || (pItem->fg.jointype & (JT_OUTER|JT_CROSS|JT_LTORJ))!=0 ){ /* Add prerequisites to prevent reordering of FROM clause terms ** across CROSS joins and outer joins. The bFirstPastRJ boolean ** prevents the right operand of a RIGHT JOIN from being swapped with ** other elements even further to the right. ** ** The JT_LTORJ case and the hasRightJoin flag work together to ** prevent FROM-clause terms from moving from the right side of ** a LEFT JOIN over to the left side of that join if the LEFT JOIN ** is itself on the left side of a RIGHT JOIN. */ if( pItem->fg.jointype & JT_LTORJ ) hasRightJoin = 1; mPrereq |= mPrior; bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0; }else if( !hasRightJoin ){ mPrereq = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ SrcItem *p; for(p=&pItem[1]; pfg.jointype & (JT_OUTER|JT_CROSS)) ){ mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); } } rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ { rc = whereLoopAddBtree(pBuilder, mPrereq); } if( rc==SQLITE_OK && pBuilder->pWC->hasOr ){ rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); } mPrior |= pNew->maskSelf; if( rc || db->mallocFailed ){ if( rc==SQLITE_DONE ){ /* We hit the query planner search limit set by iPlanLimit */ sqlite3_log(SQLITE_WARNING, "abbreviated query algorithm search"); rc = SQLITE_OK; }else{ break; } } } whereLoopClear(db, pNew); return rc; } /* ** Examine a WherePath (with the addition of the extra WhereLoop of the 6th ** parameters) to see if it outputs rows in the requested ORDER BY ** (or GROUP BY) without requiring a separate sort operation. Return N: ** ** N>0: N terms of the ORDER BY clause are satisfied ** N==0: No terms of the ORDER BY clause are satisfied ** N<0: Unknown yet how many terms of ORDER BY might be satisfied. ** ** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as ** strict. With GROUP BY and DISTINCT the only requirement is that ** equivalent rows appear immediately adjacent to one another. GROUP BY ** and DISTINCT do not require rows to appear in any particular order as long ** as equivalent rows are grouped together. Thus for GROUP BY and DISTINCT ** the pOrderBy terms can be matched in any order. With ORDER BY, the ** pOrderBy terms must be matched in strict left-to-right order. */ static i8 wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ WherePath *pPath, /* The WherePath to check */ u16 wctrlFlags, /* WHERE_GROUPBY or _DISTINCTBY or _ORDERBY_LIMIT */ u16 nLoop, /* Number of entries in pPath->aLoop[] */ WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */ ){ u8 revSet; /* True if rev is known */ u8 rev; /* Composite sort order */ u8 revIdx; /* Index sort order */ u8 isOrderDistinct; /* All prior WhereLoops are order-distinct */ u8 distinctColumns; /* True if the loop has UNIQUE NOT NULL columns */ u8 isMatch; /* iColumn matches a term of the ORDER BY clause */ u16 eqOpMask; /* Allowed equality operators */ u16 nKeyCol; /* Number of key columns in pIndex */ u16 nColumn; /* Total number of ordered columns in the index */ u16 nOrderBy; /* Number terms in the ORDER BY clause */ int iLoop; /* Index of WhereLoop in pPath being processed */ int i, j; /* Loop counters */ int iCur; /* Cursor number for current WhereLoop */ int iColumn; /* A column number within table iCur */ WhereLoop *pLoop = 0; /* Current WhereLoop being processed. */ WhereTerm *pTerm; /* A single term of the WHERE clause */ Expr *pOBExpr; /* An expression from the ORDER BY clause */ CollSeq *pColl; /* COLLATE function from an ORDER BY clause term */ Index *pIndex; /* The index associated with pLoop */ sqlite3 *db = pWInfo->pParse->db; /* Database connection */ Bitmask obSat = 0; /* Mask of ORDER BY terms satisfied so far */ Bitmask obDone; /* Mask of all ORDER BY terms */ Bitmask orderDistinctMask; /* Mask of all well-ordered loops */ Bitmask ready; /* Mask of inner loops */ /* ** We say the WhereLoop is "one-row" if it generates no more than one ** row of output. A WhereLoop is one-row if all of the following are true: ** (a) All index columns match with WHERE_COLUMN_EQ. ** (b) The index is unique ** Any WhereLoop with an WHERE_COLUMN_EQ constraint on the rowid is one-row. ** Every one-row WhereLoop will have the WHERE_ONEROW bit set in wsFlags. ** ** We say the WhereLoop is "order-distinct" if the set of columns from ** that WhereLoop that are in the ORDER BY clause are different for every ** row of the WhereLoop. Every one-row WhereLoop is automatically ** order-distinct. A WhereLoop that has no columns in the ORDER BY clause ** is not order-distinct. To be order-distinct is not quite the same as being ** UNIQUE since a UNIQUE column or index can have multiple rows that ** are NULL and NULL values are equivalent for the purpose of order-distinct. ** To be order-distinct, the columns must be UNIQUE and NOT NULL. ** ** The rowid for a table is always UNIQUE and NOT NULL so whenever the ** rowid appears in the ORDER BY clause, the corresponding WhereLoop is ** automatically order-distinct. */ assert( pOrderBy!=0 ); if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; nOrderBy = pOrderBy->nExpr; testcase( nOrderBy==BMS-1 ); if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; orderDistinctMask = 0; ready = 0; eqOpMask = WO_EQ | WO_IS | WO_ISNULL; if( wctrlFlags & (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MAX|WHERE_ORDERBY_MIN) ){ eqOpMask |= WO_IN; } for(iLoop=0; isOrderDistinct && obSat0 ) ready |= pLoop->maskSelf; if( iLoopaLoop[iLoop]; if( wctrlFlags & WHERE_ORDERBY_LIMIT ) continue; }else{ pLoop = pLast; } if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ if( pLoop->u.vtab.isOrdered && ((wctrlFlags&(WHERE_DISTINCTBY|WHERE_SORTBYGROUP))!=WHERE_DISTINCTBY) ){ obSat = obDone; } break; }else if( wctrlFlags & WHERE_DISTINCTBY ){ pLoop->u.btree.nDistinctCol = 0; } iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; /* Mark off any ORDER BY term X that is a column in the table of ** the current loop for which there is term in the WHERE ** clause of the form X IS NULL or X=? that reference only outer ** loops. */ for(i=0; ia[i].pExpr); if( NEVER(pOBExpr==0) ) continue; if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, ~ready, eqOpMask, 0); if( pTerm==0 ) continue; if( pTerm->eOperator==WO_IN ){ /* IN terms are only valid for sorting in the ORDER BY LIMIT ** optimization, and then only if they are actually used ** by the query plan */ assert( wctrlFlags & (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) ); for(j=0; jnLTerm && pTerm!=pLoop->aLTerm[j]; j++){} if( j>=pLoop->nLTerm ) continue; } if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ Parse *pParse = pWInfo->pParse; CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[i].pExpr); CollSeq *pColl2 = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr); assert( pColl1 ); if( pColl2==0 || sqlite3StrICmp(pColl1->zName, pColl2->zName) ){ continue; } testcase( pTerm->pExpr->op==TK_IS ); } obSat |= MASKBIT(i); } if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){ if( pLoop->wsFlags & WHERE_IPK ){ pIndex = 0; nKeyCol = 0; nColumn = 1; }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ return 0; }else{ nKeyCol = pIndex->nKeyCol; nColumn = pIndex->nColumn; assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); assert( pIndex->aiColumn[nColumn-1]==XN_ROWID || !HasRowid(pIndex->pTable)); /* All relevant terms of the index must also be non-NULL in order ** for isOrderDistinct to be true. So the isOrderDistint value ** computed here might be a false positive. Corrections will be ** made at tag-20210426-1 below */ isOrderDistinct = IsUniqueIndex(pIndex) && (pLoop->wsFlags & WHERE_SKIPSCAN)==0; } /* Loop through all columns of the index and deal with the ones ** that are not constrained by == or IN. */ rev = revSet = 0; distinctColumns = 0; for(j=0; j=pLoop->u.btree.nEq || (pLoop->aLTerm[j]==0)==(jnSkip) ); if( ju.btree.nEq && j>=pLoop->nSkip ){ u16 eOp = pLoop->aLTerm[j]->eOperator; /* Skip over == and IS and ISNULL terms. (Also skip IN terms when ** doing WHERE_ORDERBY_LIMIT processing). Except, IS and ISNULL ** terms imply that the index is not UNIQUE NOT NULL in which case ** the loop need to be marked as not order-distinct because it can ** have repeated NULL rows. ** ** If the current term is a column of an ((?,?) IN (SELECT...)) ** expression for which the SELECT returns more than one column, ** check that it is the only column used by this loop. Otherwise, ** if it is one of two or more, none of the columns can be ** considered to match an ORDER BY term. */ if( (eOp & eqOpMask)!=0 ){ if( eOp & (WO_ISNULL|WO_IS) ){ testcase( eOp & WO_ISNULL ); testcase( eOp & WO_IS ); testcase( isOrderDistinct ); isOrderDistinct = 0; } continue; }else if( ALWAYS(eOp & WO_IN) ){ /* ALWAYS() justification: eOp is an equality operator due to the ** ju.btree.nEq constraint above. Any equality other ** than WO_IN is captured by the previous "if". So this one ** always has to be WO_IN. */ Expr *pX = pLoop->aLTerm[j]->pExpr; for(i=j+1; iu.btree.nEq; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ assert( (pLoop->aLTerm[i]->eOperator & WO_IN) ); bOnce = 0; break; } } } } /* Get the column number in the table (iColumn) and sort order ** (revIdx) for the j-th column of the index. */ if( pIndex ){ iColumn = pIndex->aiColumn[j]; revIdx = pIndex->aSortOrder[j] & KEYINFO_ORDER_DESC; if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID; }else{ iColumn = XN_ROWID; revIdx = 0; } /* An unconstrained column that might be NULL means that this ** WhereLoop is not well-ordered. tag-20210426-1 */ if( isOrderDistinct ){ if( iColumn>=0 && j>=pLoop->u.btree.nEq && pIndex->pTable->aCol[iColumn].notNull==0 ){ isOrderDistinct = 0; } if( iColumn==XN_EXPR ){ isOrderDistinct = 0; } } /* Find the ORDER BY term that corresponds to the j-th column ** of the index and mark that ORDER BY term off */ isMatch = 0; for(i=0; bOnce && ia[i].pExpr); testcase( wctrlFlags & WHERE_GROUPBY ); testcase( wctrlFlags & WHERE_DISTINCTBY ); if( NEVER(pOBExpr==0) ) continue; if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; if( iColumn>=XN_ROWID ){ if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; }else{ Expr *pIxExpr = pIndex->aColExpr->a[j].pExpr; if( sqlite3ExprCompareSkip(pOBExpr, pIxExpr, iCur) ){ continue; } } if( iColumn!=XN_ROWID ){ pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } if( wctrlFlags & WHERE_DISTINCTBY ){ pLoop->u.btree.nDistinctCol = j+1; } isMatch = 1; break; } if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){ /* Make sure the sort order is compatible in an ORDER BY clause. ** Sort order is irrelevant for a GROUP BY clause. */ if( revSet ){ if( (rev ^ revIdx) != (pOrderBy->a[i].fg.sortFlags&KEYINFO_ORDER_DESC) ){ isMatch = 0; } }else{ rev = revIdx ^ (pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_DESC); if( rev ) *pRevMask |= MASKBIT(iLoop); revSet = 1; } } if( isMatch && (pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_BIGNULL) ){ if( j==pLoop->u.btree.nEq ){ pLoop->wsFlags |= WHERE_BIGNULL_SORT; }else{ isMatch = 0; } } if( isMatch ){ if( iColumn==XN_ROWID ){ testcase( distinctColumns==0 ); distinctColumns = 1; } obSat |= MASKBIT(i); }else{ /* No match found */ if( j==0 || jmaskSelf; for(i=0; ia[i].pExpr; mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p); if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue; if( (mTerm&~orderDistinctMask)==0 ){ obSat |= MASKBIT(i); } } } } /* End the loop over all WhereLoops from outer-most down to inner-most */ if( obSat==obDone ) return (i8)nOrderBy; if( !isOrderDistinct ){ for(i=nOrderBy-1; i>0; i--){ Bitmask m = ALWAYS(iwctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY) ); assert( pWInfo->wctrlFlags & WHERE_SORTBYGROUP ); return pWInfo->sorted; } #ifdef WHERETRACE_ENABLED /* For debugging use only: */ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ static char zName[65]; int i; for(i=0; iaLoop[i]->cId; } if( pLast ) zName[i++] = pLast->cId; zName[i] = 0; return zName; } #endif /* ** Return the cost of sorting nRow rows, assuming that the keys have ** nOrderby columns and that the first nSorted columns are already in ** order. */ static LogEst whereSortingCost( WhereInfo *pWInfo, /* Query planning context */ LogEst nRow, /* Estimated number of rows to sort */ int nOrderBy, /* Number of ORDER BY clause terms */ int nSorted /* Number of initial ORDER BY terms naturally in order */ ){ /* Estimated cost of a full external sort, where N is ** the number of rows to sort is: ** ** cost = (K * N * log(N)). ** ** Or, if the order-by clause has X terms but only the last Y ** terms are out of order, then block-sorting will reduce the ** sorting cost to: ** ** cost = (K * N * log(N)) * (Y/X) ** ** The constant K is at least 2.0 but will be larger if there are a ** large number of columns to be sorted, as the sorting time is ** proportional to the amount of content to be sorted. The algorithm ** does not currently distinguish between fat columns (BLOBs and TEXTs) ** and skinny columns (INTs). It just uses the number of columns as ** an approximation for the row width. ** ** And extra factor of 2.0 or 3.0 is added to the sorting cost if the sort ** is built using OP_IdxInsert and OP_Sort rather than with OP_SorterInsert. */ LogEst rSortCost, nCol; assert( pWInfo->pSelect!=0 ); assert( pWInfo->pSelect->pEList!=0 ); /* TUNING: sorting cost proportional to the number of output columns: */ nCol = sqlite3LogEst((pWInfo->pSelect->pEList->nExpr+59)/30); rSortCost = nRow + nCol; if( nSorted>0 ){ /* Scale the result by (Y/X) */ rSortCost += sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; } /* Multiple by log(M) where M is the number of output rows. ** Use the LIMIT for M if it is smaller. Or if this sort is for ** a DISTINCT operator, M will be the number of distinct output ** rows, so fudge it downwards a bit. */ if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 ){ rSortCost += 10; /* TUNING: Extra 2.0x if using LIMIT */ if( nSorted!=0 ){ rSortCost += 6; /* TUNING: Extra 1.5x if also using partial sort */ } if( pWInfo->iLimitiLimit; } }else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){ /* TUNING: In the sort for a DISTINCT operator, assume that the DISTINCT ** reduces the number of output rows by a factor of 2 */ if( nRow>10 ){ nRow -= 10; assert( 10==sqlite3LogEst(2) ); } } rSortCost += estLog(nRow); return rSortCost; } /* ** Given the list of WhereLoop objects at pWInfo->pLoops, this routine ** attempts to find the lowest cost path that visits each WhereLoop ** once. This path is then loaded into the pWInfo->a[].pWLoop fields. ** ** Assume that the total number of output rows that will need to be sorted ** will be nRowEst (in the 10*log2 representation). Or, ignore sorting ** costs if nRowEst==0. ** ** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation ** error occurs. */ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ int mxChoice; /* Maximum number of simultaneous paths tracked */ int nLoop; /* Number of terms in the join */ Parse *pParse; /* Parsing context */ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ int mxI = 0; /* Index of next entry to replace */ int nOrderBy; /* Number of ORDER BY clause terms */ LogEst mxCost = 0; /* Maximum cost of a set of paths */ LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ WherePath *pFrom; /* An element of aFrom[] that we are working on */ WherePath *pTo; /* An element of aTo[] that we are working on */ WhereLoop *pWLoop; /* One of the WhereLoop objects */ WhereLoop **pX; /* Used to divy up the pSpace memory */ LogEst *aSortCost = 0; /* Sorting and partial sorting costs */ char *pSpace; /* Temporary memory used by this routine */ int nSpace; /* Bytes of space allocated at pSpace */ pParse = pWInfo->pParse; nLoop = pWInfo->nLevel; /* TUNING: For simple queries, only the best path is tracked. ** For 2-way joins, the 5 best paths are followed. ** For joins of 3 or more tables, track the 10 best paths */ mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10); assert( nLoop<=pWInfo->pTabList->nSrc ); WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d, nQueryLoop=%d)\n", nRowEst, pParse->nQueryLoop)); /* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this ** case the purpose of this call is to estimate the number of rows returned ** by the overall query. Once this estimate has been obtained, the caller ** will invoke this function a second time, passing the estimate as the ** nRowEst parameter. */ if( pWInfo->pOrderBy==0 || nRowEst==0 ){ nOrderBy = 0; }else{ nOrderBy = pWInfo->pOrderBy->nExpr; } /* Allocate and initialize space for aTo, aFrom and aSortCost[] */ nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; nSpace += sizeof(LogEst) * nOrderBy; pSpace = sqlite3StackAllocRawNN(pParse->db, nSpace); if( pSpace==0 ) return SQLITE_NOMEM_BKPT; aTo = (WherePath*)pSpace; aFrom = aTo+mxChoice; memset(aFrom, 0, sizeof(aFrom[0])); pX = (WhereLoop**)(aFrom+mxChoice); for(ii=mxChoice*2, pFrom=aTo; ii>0; ii--, pFrom++, pX += nLoop){ pFrom->aLoop = pX; } if( nOrderBy ){ /* If there is an ORDER BY clause and it is not being ignored, set up ** space for the aSortCost[] array. Each element of the aSortCost array ** is either zero - meaning it has not yet been initialized - or the ** cost of sorting nRowEst rows of data where the first X terms of ** the ORDER BY clause are already in order, where X is the array ** index. */ aSortCost = (LogEst*)pX; memset(aSortCost, 0, sizeof(LogEst) * nOrderBy); } assert( aSortCost==0 || &pSpace[nSpace]==(char*)&aSortCost[nOrderBy] ); assert( aSortCost!=0 || &pSpace[nSpace]==(char*)pX ); /* Seed the search with a single WherePath containing zero WhereLoops. ** ** TUNING: Do not let the number of iterations go above 28. If the cost ** of computing an automatic index is not paid back within the first 28 ** rows, then do not use the automatic index. */ aFrom[0].nRow = MIN(pParse->nQueryLoop, 48); assert( 48==sqlite3LogEst(28) ); nFrom = 1; assert( aFrom[0].isOrdered==0 ); if( nOrderBy ){ /* If nLoop is zero, then there are no FROM terms in the query. Since ** in this case the query may return a maximum of one row, the results ** are already in the requested order. Set isOrdered to nOrderBy to ** indicate this. Or, if nLoop is greater than zero, set isOrdered to ** -1, indicating that the result set may or may not be ordered, ** depending on the loops added to the current plan. */ aFrom[0].isOrdered = nLoop>0 ? -1 : nOrderBy; } /* Compute successively longer WherePaths using the previous generation ** of WherePaths as the basis for the next. Keep track of the mxChoice ** best paths at each generation */ for(iLoop=0; iLooppLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ LogEst nOut; /* Rows visited by (pFrom+pWLoop) */ LogEst rCost; /* Cost of path (pFrom+pWLoop) */ LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */ i8 isOrdered; /* isOrdered for (pFrom+pWLoop) */ Bitmask maskNew; /* Mask of src visited by (..) */ Bitmask revMask; /* Mask of rev-order loops for (..) */ if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<3 ){ /* Do not use an automatic index if the this loop is expected ** to run less than 1.25 times. It is tempting to also exclude ** automatic index usage on an outer loop, but sometimes an automatic ** index is useful in the outer loop of a correlated subquery. */ assert( 10==sqlite3LogEst(2) ); continue; } /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */ rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted); nOut = pFrom->nRow + pWLoop->nOut; maskNew = pFrom->maskLoop | pWLoop->maskSelf; isOrdered = pFrom->isOrdered; if( isOrdered<0 ){ revMask = 0; isOrdered = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags, iLoop, pWLoop, &revMask); }else{ revMask = pFrom->revLoop; } if( isOrdered>=0 && isOrderedisOrdered^isOrdered)&0x80)==0" is equivalent ** to (pTo->isOrdered==(-1))==(isOrdered==(-1))" for the range ** of legal values for isOrdered, -1..64. */ for(jj=0, pTo=aTo; jjmaskLoop==maskNew && ((pTo->isOrdered^isOrdered)&0x80)==0 ){ testcase( jj==nTo-1 ); break; } } if( jj>=nTo ){ /* None of the existing best-so-far paths match the candidate. */ if( nTo>=mxChoice && (rCost>mxCost || (rCost==mxCost && rUnsorted>=mxUnsorted)) ){ /* The current candidate is no better than any of the mxChoice ** paths currently in the best-so-far buffer. So discard ** this candidate as not viable. */ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); } #endif continue; } /* If we reach this points it means that the new candidate path ** needs to be added to the set of best-so-far paths. */ if( nTo=0 ? isOrdered+'0' : '?'); } #endif }else{ /* Control reaches here if best-so-far path pTo=aTo[jj] covers the ** same set of loops and has the same isOrdered setting as the ** candidate path. Check to see if the candidate should replace ** pTo or if the candidate should be skipped. ** ** The conditional is an expanded vector comparison equivalent to: ** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted) */ if( pTo->rCostrCost==rCost && (pTo->nRownRow==nOut && pTo->rUnsorted<=rUnsorted) ) ) ){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Skip %s cost=%-3d,%3d,%3d order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif /* Discard the candidate path from further consideration */ testcase( pTo->rCost==rCost ); continue; } testcase( pTo->rCost==rCost+1 ); /* Control reaches here if the candidate path is better than the ** pTo path. Replace pTo with the candidate. */ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Update %s cost=%-3d,%3d,%3d order=%c", wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif } /* pWLoop is a winner. Add it to the set of best so far */ pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; pTo->revLoop = revMask; pTo->nRow = nOut; pTo->rCost = rCost; pTo->rUnsorted = rUnsorted; pTo->isOrdered = isOrdered; memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop); pTo->aLoop[iLoop] = pWLoop; if( nTo>=mxChoice ){ mxI = 0; mxCost = aTo[0].rCost; mxUnsorted = aTo[0].nRow; for(jj=1, pTo=&aTo[1]; jjrCost>mxCost || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted) ){ mxCost = pTo->rCost; mxUnsorted = pTo->rUnsorted; mxI = jj; } } } } } #ifdef WHERETRACE_ENABLED /* >=2 */ if( sqlite3WhereTrace & 0x02 ){ sqlite3DebugPrintf("---- after round %d ----\n", iLoop); for(ii=0, pTo=aTo; iirCost, pTo->nRow, pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?'); if( pTo->isOrdered>0 ){ sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop); }else{ sqlite3DebugPrintf("\n"); } } } #endif /* Swap the roles of aFrom and aTo for the next generation */ pFrom = aTo; aTo = aFrom; aFrom = pFrom; nFrom = nTo; } if( nFrom==0 ){ sqlite3ErrorMsg(pParse, "no query solution"); sqlite3StackFreeNN(pParse->db, pSpace); return SQLITE_ERROR; } /* Find the lowest cost path. pFrom will be left pointing to that path */ pFrom = aFrom; for(ii=1; iirCost>aFrom[ii].rCost ) pFrom = &aFrom[ii]; } assert( pWInfo->nLevel==nLoop ); /* Load the lowest cost path into pWInfo */ for(iLoop=0; iLoopa + iLoop; pLevel->pWLoop = pWLoop = pFrom->aLoop[iLoop]; pLevel->iFrom = pWLoop->iTab; pLevel->iTabCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; } if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 && (pWInfo->wctrlFlags & WHERE_DISTINCTBY)==0 && pWInfo->eDistinct==WHERE_DISTINCT_NOOP && nRowEst ){ Bitmask notUsed; int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom, WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); if( rc==pWInfo->pResultSet->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } } pWInfo->bOrderedInnerLoop = 0; if( pWInfo->pOrderBy ){ pWInfo->nOBSat = pFrom->isOrdered; if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } if( pWInfo->pSelect->pOrderBy && pWInfo->nOBSat > pWInfo->pSelect->pOrderBy->nExpr ){ pWInfo->nOBSat = pWInfo->pSelect->pOrderBy->nExpr; } }else{ pWInfo->revMask = pFrom->revLoop; if( pWInfo->nOBSat<=0 ){ pWInfo->nOBSat = 0; if( nLoop>0 ){ u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags; if( (wsFlags & WHERE_ONEROW)==0 && (wsFlags&(WHERE_IPK|WHERE_COLUMN_IN))!=(WHERE_IPK|WHERE_COLUMN_IN) ){ Bitmask m = 0; int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m); testcase( wsFlags & WHERE_IPK ); testcase( wsFlags & WHERE_COLUMN_IN ); if( rc==pWInfo->pOrderBy->nExpr ){ pWInfo->bOrderedInnerLoop = 1; pWInfo->revMask = m; } } } }else if( nLoop && pWInfo->nOBSat==1 && (pWInfo->wctrlFlags & (WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX))!=0 ){ pWInfo->bOrderedInnerLoop = 1; } } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0 ){ Bitmask revMask = 0; int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask ); assert( pWInfo->sorted==0 ); if( nOrder==pWInfo->pOrderBy->nExpr ){ pWInfo->sorted = 1; pWInfo->revMask = revMask; } } } pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ sqlite3StackFreeNN(pParse->db, pSpace); return SQLITE_OK; } /* ** Most queries use only a single table (they are not joins) and have ** simple == constraints against indexed fields. This routine attempts ** to plan those simple cases using much less ceremony than the ** general-purpose query planner, and thereby yield faster sqlite3_prepare() ** times for the common case. ** ** Return non-zero on success, if this query can be handled by this ** no-frills query planner. Return zero if this query needs the ** general-purpose query planner. */ static int whereShortCut(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo; SrcItem *pItem; WhereClause *pWC; WhereTerm *pTerm; WhereLoop *pLoop; int iCur; int j; Table *pTab; Index *pIdx; WhereScan scan; pWInfo = pBuilder->pWInfo; if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; assert( pWInfo->pTabList->nSrc>=1 ); pItem = pWInfo->pTabList->a; pTab = pItem->pTab; if( IsVirtual(pTab) ) return 0; if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){ testcase( pItem->fg.isIndexedBy ); testcase( pItem->fg.notIndexed ); return 0; } iCur = pItem->iCursor; pWC = &pWInfo->sWC; pLoop = pBuilder->pNew; pLoop->wsFlags = 0; pLoop->nSkip = 0; pTerm = whereScanInit(&scan, pWC, iCur, -1, WO_EQ|WO_IS, 0); while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan); if( pTerm ){ testcase( pTerm->eOperator & WO_IS ); pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; pLoop->aLTerm[0] = pTerm; pLoop->nLTerm = 1; pLoop->u.btree.nEq = 1; /* TUNING: Cost of a rowid lookup is 10 */ pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */ }else{ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int opMask; assert( pLoop->aLTermSpace==pLoop->aLTerm ); if( !IsUniqueIndex(pIdx) || pIdx->pPartIdxWhere!=0 || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) ) continue; opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ; for(j=0; jnKeyCol; j++){ pTerm = whereScanInit(&scan, pWC, iCur, j, opMask, pIdx); while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan); if( pTerm==0 ) break; testcase( pTerm->eOperator & WO_IS ); pLoop->aLTerm[j] = pTerm; } if( j!=pIdx->nKeyCol ) continue; pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED; if( pIdx->isCovering || (pItem->colUsed & pIdx->colNotIdxed)==0 ){ pLoop->wsFlags |= WHERE_IDX_ONLY; } pLoop->nLTerm = j; pLoop->u.btree.nEq = j; pLoop->u.btree.pIndex = pIdx; /* TUNING: Cost of a unique index lookup is 15 */ pLoop->rRun = 39; /* 39==sqlite3LogEst(15) */ break; } } if( pLoop->wsFlags ){ pLoop->nOut = (LogEst)1; pWInfo->a[0].pWLoop = pLoop; assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] ); pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */ pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } if( scan.iEquiv>1 ) pLoop->wsFlags |= WHERE_TRANSCONS; #ifdef SQLITE_DEBUG pLoop->cId = '0'; #endif #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x02 ){ sqlite3DebugPrintf("whereShortCut() used to compute solution\n"); } #endif return 1; } return 0; } /* ** Helper function for exprIsDeterministic(). */ static int exprNodeIsDeterministic(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_ConstFunc)==0 ){ pWalker->eCode = 0; return WRC_Abort; } return WRC_Continue; } /* ** Return true if the expression contains no non-deterministic SQL ** functions. Do not consider non-deterministic SQL functions that are ** part of sub-select statements. */ static int exprIsDeterministic(Expr *p){ Walker w; memset(&w, 0, sizeof(w)); w.eCode = 1; w.xExprCallback = exprNodeIsDeterministic; w.xSelectCallback = sqlite3SelectWalkFail; sqlite3WalkExpr(&w, p); return w.eCode; } #ifdef WHERETRACE_ENABLED /* ** Display all WhereLoops in pWInfo */ static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){ if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */ WhereLoop *p; int i; static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){ p->cId = zLabel[i%(sizeof(zLabel)-1)]; sqlite3WhereLoopPrint(p, pWC); } } } # define WHERETRACE_ALL_LOOPS(W,C) showAllWhereLoops(W,C) #else # define WHERETRACE_ALL_LOOPS(W,C) #endif /* Attempt to omit tables from a join that do not affect the result. ** For a table to not affect the result, the following must be true: ** ** 1) The query must not be an aggregate. ** 2) The table must be the RHS of a LEFT JOIN. ** 3) Either the query must be DISTINCT, or else the ON or USING clause ** must contain a constraint that limits the scan of the table to ** at most a single row. ** 4) The table must not be referenced by any part of the query apart ** from its own USING or ON clause. ** 5) The table must not have an inner-join ON or USING clause if there is ** a RIGHT JOIN anywhere in the query. Otherwise the ON/USING clause ** might move from the right side to the left side of the RIGHT JOIN. ** Note: Due to (2), this condition can only arise if the table is ** the right-most table of a subquery that was flattened into the ** main query and that subquery was the right-hand operand of an ** inner join that held an ON or USING clause. ** ** For example, given: ** ** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1); ** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2); ** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3); ** ** then table t2 can be omitted from the following: ** ** SELECT v1, v3 FROM t1 ** LEFT JOIN t2 ON (t1.ipk=t2.ipk) ** LEFT JOIN t3 ON (t1.ipk=t3.ipk) ** ** or from: ** ** SELECT DISTINCT v1, v3 FROM t1 ** LEFT JOIN t2 ** LEFT JOIN t3 ON (t1.ipk=t3.ipk) */ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( WhereInfo *pWInfo, Bitmask notReady ){ int i; Bitmask tabUsed; int hasRightJoin; /* Preconditions checked by the caller */ assert( pWInfo->nLevel>=2 ); assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_OmitNoopJoin) ); /* These two preconditions checked by the caller combine to guarantee ** condition (1) of the header comment */ assert( pWInfo->pResultSet!=0 ); assert( 0==(pWInfo->wctrlFlags & WHERE_AGG_DISTINCT) ); tabUsed = sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pResultSet); if( pWInfo->pOrderBy ){ tabUsed |= sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pOrderBy); } hasRightJoin = (pWInfo->pTabList->a[0].fg.jointype & JT_LTORJ)!=0; for(i=pWInfo->nLevel-1; i>=1; i--){ WhereTerm *pTerm, *pEnd; SrcItem *pItem; WhereLoop *pLoop; pLoop = pWInfo->a[i].pWLoop; pItem = &pWInfo->pTabList->a[pLoop->iTab]; if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ) continue; if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)==0 && (pLoop->wsFlags & WHERE_ONEROW)==0 ){ continue; } if( (tabUsed & pLoop->maskSelf)!=0 ) continue; pEnd = pWInfo->sWC.a + pWInfo->sWC.nTerm; for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){ if( !ExprHasProperty(pTerm->pExpr, EP_OuterON) || pTerm->pExpr->w.iJoin!=pItem->iCursor ){ break; } } if( hasRightJoin && ExprHasProperty(pTerm->pExpr, EP_InnerON) && pTerm->pExpr->w.iJoin==pItem->iCursor ){ break; /* restriction (5) */ } } if( pTerm drop loop %c not used\n", pLoop->cId)); notReady &= ~pLoop->maskSelf; for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){ pTerm->wtFlags |= TERM_CODED; } } if( i!=pWInfo->nLevel-1 ){ int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel); memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte); } pWInfo->nLevel--; assert( pWInfo->nLevel>0 ); } return notReady; } /* ** Check to see if there are any SEARCH loops that might benefit from ** using a Bloom filter. Consider a Bloom filter if: ** ** (1) The SEARCH happens more than N times where N is the number ** of rows in the table that is being considered for the Bloom ** filter. ** (2) Some searches are expected to find zero rows. (This is determined ** by the WHERE_SELFCULL flag on the term.) ** (3) Bloom-filter processing is not disabled. (Checked by the ** caller.) ** (4) The size of the table being searched is known by ANALYZE. ** ** This block of code merely checks to see if a Bloom filter would be ** appropriate, and if so sets the WHERE_BLOOMFILTER flag on the ** WhereLoop. The implementation of the Bloom filter comes further ** down where the code for each WhereLoop is generated. */ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( const WhereInfo *pWInfo ){ int i; LogEst nSearch = 0; assert( pWInfo->nLevel>=2 ); assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) ); for(i=0; inLevel; i++){ WhereLoop *pLoop = pWInfo->a[i].pWLoop; const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ); SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab]; Table *pTab = pItem->pTab; if( (pTab->tabFlags & TF_HasStat1)==0 ) break; pTab->tabFlags |= TF_StatsUsed; if( i>=1 && (pLoop->wsFlags & reqFlags)==reqFlags /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */ && ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0) ){ if( nSearch > pTab->nRowLogEst ){ testcase( pItem->fg.jointype & JT_LEFT ); pLoop->wsFlags |= WHERE_BLOOMFILTER; pLoop->wsFlags &= ~WHERE_IDX_ONLY; WHERETRACE(0xffffffff, ( "-> use Bloom-filter on loop %c because there are ~%.1e " "lookups into %s which has only ~%.1e rows\n", pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName, (double)sqlite3LogEstToInt(pTab->nRowLogEst))); } } nSearch += pLoop->nOut; } } /* ** The index pIdx is used by a query and contains one or more expressions. ** In other words pIdx is an index on an expression. iIdxCur is the cursor ** number for the index and iDataCur is the cursor number for the corresponding ** table. ** ** This routine adds IndexedExpr entries to the Parse->pIdxEpr field for ** each of the expressions in the index so that the expression code generator ** will know to replace occurrences of the indexed expression with ** references to the corresponding column of the index. */ static SQLITE_NOINLINE void whereAddIndexedExpr( Parse *pParse, /* Add IndexedExpr entries to pParse->pIdxEpr */ Index *pIdx, /* The index-on-expression that contains the expressions */ int iIdxCur, /* Cursor number for pIdx */ SrcItem *pTabItem /* The FROM clause entry for the table */ ){ int i; IndexedExpr *p; Table *pTab; assert( pIdx->bHasExpr ); pTab = pIdx->pTable; for(i=0; inColumn; i++){ Expr *pExpr; int j = pIdx->aiColumn[i]; int bMaybeNullRow; if( j==XN_EXPR ){ pExpr = pIdx->aColExpr->a[i].pExpr; testcase( pTabItem->fg.jointype & JT_LEFT ); testcase( pTabItem->fg.jointype & JT_RIGHT ); testcase( pTabItem->fg.jointype & JT_LTORJ ); bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0; }else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){ pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]); bMaybeNullRow = 0; }else{ continue; } if( sqlite3ExprIsConstant(pExpr) ) continue; if( pExpr->op==TK_FUNCTION ){ /* Functions that might set a subtype should not be replaced by the ** value taken from an expression index since the index omits the ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */ int n; FuncDef *pDef; sqlite3 *db = pParse->db; assert( ExprUseXList(pExpr) ); n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ continue; } } p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break; p->pIENext = pParse->pIdxEpr; #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x200 ){ sqlite3DebugPrintf("New pParse->pIdxEpr term {%d,%d}\n", iIdxCur, i); if( sqlite3WhereTrace & 0x5000 ) sqlite3ShowExpr(pExpr); } #endif p->pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); p->iDataCur = pTabItem->iCursor; p->iIdxCur = iIdxCur; p->iIdxCol = i; p->bMaybeNullRow = bMaybeNullRow; if( sqlite3IndexAffinityStr(pParse->db, pIdx) ){ p->aff = pIdx->zColAff[i]; } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS p->zIdxName = pIdx->zName; #endif pParse->pIdxEpr = p; if( p->pIENext==0 ){ void *pArg = (void*)&pParse->pIdxEpr; sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg); } } } /* ** Set the reverse-scan order mask to one for all tables in the query ** with the exception of MATERIALIZED common table expressions that have ** their own internal ORDER BY clauses. ** ** This implements the PRAGMA reverse_unordered_selects=ON setting. ** (Also SQLITE_DBCONFIG_REVERSE_SCANORDER). */ static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){ int ii; for(ii=0; iipTabList->nSrc; ii++){ SrcItem *pItem = &pWInfo->pTabList->a[ii]; if( !pItem->fg.isCte || pItem->u2.pCteUse->eM10d!=M10d_Yes || NEVER(pItem->pSelect==0) || pItem->pSelect->pOrderBy==0 ){ pWInfo->revMask |= MASKBIT(ii); } } } /* ** Generate the beginning of the loop used for WHERE clause processing. ** The return value is a pointer to an opaque structure that contains ** information needed to terminate the loop. Later, the calling routine ** should invoke sqlite3WhereEnd() with the return value of this function ** in order to complete the WHERE clause processing. ** ** If an error occurs, this routine returns NULL. ** ** The basic idea is to do a nested loop, one loop for each table in ** the FROM clause of a select. (INSERT and UPDATE statements are the ** same as a SELECT with only a single table in the FROM clause.) For ** example, if the SQL is this: ** ** SELECT * FROM t1, t2, t3 WHERE ...; ** ** Then the code generated is conceptually like the following: ** ** foreach row1 in t1 do \ Code generated ** foreach row2 in t2 do |-- by sqlite3WhereBegin() ** foreach row3 in t3 do / ** ... ** end \ Code generated ** end |-- by sqlite3WhereEnd() ** end / ** ** Note that the loops might not be nested in the order in which they ** appear in the FROM clause if a different order is better able to make ** use of indices. Note also that when the IN operator appears in ** the WHERE clause, it might result in additional nested loops for ** scanning through all values on the right-hand side of the IN. ** ** There are Btree cursors associated with each table. t1 uses cursor ** number pTabList->a[0].iCursor. t2 uses the cursor pTabList->a[1].iCursor. ** And so forth. This routine generates code to open those VDBE cursors ** and sqlite3WhereEnd() generates the code to close them. ** ** The code that sqlite3WhereBegin() generates leaves the cursors named ** in pTabList pointing at their appropriate entries. The [...] code ** can use OP_Column and OP_Rowid opcodes on these cursors to extract ** data from the various tables of the loop. ** ** If the WHERE clause is empty, the foreach loops must each scan their ** entire tables. Thus a three-way join is an O(N^3) operation. But if ** the tables have indices and there are terms in the WHERE clause that ** refer to those indices, a complete table scan can be avoided and the ** code will run much faster. Most of the work of this routine is checking ** to see if there are indices that can be used to speed up the loop. ** ** Terms of the WHERE clause are also used to limit which rows actually ** make it to the "..." in the middle of the loop. After each "foreach", ** terms of the WHERE clause that use only terms in that loop and outer ** loops are evaluated and if false a jump is made around all subsequent ** inner loops (or around the "..." if the test occurs within the inner- ** most loop) ** ** OUTER JOINS ** ** An outer join of tables t1 and t2 is conceptually coded as follows: ** ** foreach row1 in t1 do ** flag = 0 ** foreach row2 in t2 do ** start: ** ... ** flag = 1 ** end ** if flag==0 then ** move the row2 cursor to a null row ** goto start ** fi ** end ** ** ORDER BY CLAUSE PROCESSING ** ** pOrderBy is a pointer to the ORDER BY clause (or the GROUP BY clause ** if the WHERE_GROUPBY flag is set in wctrlFlags) of a SELECT statement ** if there is one. If there is no ORDER BY clause or if this routine ** is called from an UPDATE or DELETE statement, then pOrderBy is NULL. ** ** The iIdxCur parameter is the cursor number of an index. If ** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index ** to use for OR clause processing. The WHERE clause should use this ** specific cursor. If WHERE_ONEPASS_DESIRED is set, then iIdxCur is ** the first cursor in an array of cursors for all indices. iIdxCur should ** be used to compute the appropriate cursor depending on which index is ** used. */ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */ Select *pSelect, /* The entire SELECT statement */ u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */ int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number ** If WHERE_USE_LIMIT, then the limit amount */ ){ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ int nTabList; /* Number of elements in pTabList */ WhereInfo *pWInfo; /* Will become the return value of this function */ Vdbe *v = pParse->pVdbe; /* The virtual database engine */ Bitmask notReady; /* Cursors that are not yet positioned */ WhereLoopBuilder sWLB; /* The WhereLoop builder */ WhereMaskSet *pMaskSet; /* The expression mask set */ WhereLevel *pLevel; /* A single level in pWInfo->a[] */ WhereLoop *pLoop; /* Pointer to a single WhereLoop object */ int ii; /* Loop counter */ sqlite3 *db; /* Database connection */ int rc; /* Return code */ u8 bFordelete = 0; /* OPFLAG_FORDELETE or zero, as appropriate */ assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || ( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 )); /* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */ assert( (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 || (wctrlFlags & WHERE_USE_LIMIT)==0 ); /* Variable initialization */ db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ testcase( pOrderBy && pOrderBy->nExpr==BMS-1 ); if( pOrderBy && pOrderBy->nExpr>=BMS ){ pOrderBy = 0; wctrlFlags &= ~WHERE_WANT_DISTINCT; } /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask */ testcase( pTabList->nSrc==BMS ); if( pTabList->nSrc>BMS ){ sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS); return 0; } /* This function normally generates a nested loop for all tables in ** pTabList. But if the WHERE_OR_SUBCLAUSE flag is set, then we should ** only generate code for the first table in pTabList and assume that ** any cursors associated with subsequent tables are uninitialized. */ nTabList = (wctrlFlags & WHERE_OR_SUBCLAUSE) ? 1 : pTabList->nSrc; /* Allocate and initialize the WhereInfo structure that will become the ** return value. A single allocation is used to store the WhereInfo ** struct, the contents of WhereInfo.a[], the WhereClause structure ** and the WhereMaskSet structure. Since WhereClause contains an 8-byte ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ nByteWInfo = ROUND8P(sizeof(WhereInfo)); if( nTabList>1 ){ nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel)); } pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ sqlite3DbFree(db, pWInfo); pWInfo = 0; goto whereBeginError; } pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; #if WHERETRACE_ENABLED pWInfo->pWhere = pWhere; #endif pWInfo->pResultSet = pResultSet; pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1; pWInfo->nLevel = nTabList; pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(pParse); pWInfo->wctrlFlags = wctrlFlags; pWInfo->iLimit = iAuxArg; pWInfo->savedNQueryLoop = pParse->nQueryLoop; pWInfo->pSelect = pSelect; memset(&pWInfo->nOBSat, 0, offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat)); memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel)); assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */ pMaskSet = &pWInfo->sMaskSet; pMaskSet->n = 0; pMaskSet->ix[0] = -99; /* Initialize ix[0] to a value that can never be ** a valid cursor number, to avoid an initial ** test for pMaskSet->n==0 in sqlite3WhereGetMask() */ sWLB.pWInfo = pWInfo; sWLB.pWC = &pWInfo->sWC; sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo); assert( EIGHT_BYTE_ALIGNMENT(sWLB.pNew) ); whereLoopInit(sWLB.pNew); #ifdef SQLITE_DEBUG sWLB.pNew->cId = '*'; #endif /* Split the WHERE clause into separate subexpressions where each ** subexpression is separated by an AND operator. */ sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo); sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND); /* Special case: No FROM clause */ if( nTabList==0 ){ if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr; if( (wctrlFlags & WHERE_WANT_DISTINCT)!=0 && OptimizationEnabled(db, SQLITE_DistinctOpt) ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW")); }else{ /* Assign a bit from the bitmask to every term in the FROM clause. ** ** The N-th term of the FROM clause is assigned a bitmask of 1<nSrc tables in ** pTabList, not just the first nTabList tables. nTabList is normally ** equal to pTabList->nSrc but might be shortened to 1 if the ** WHERE_OR_SUBCLAUSE flag is set. */ ii = 0; do{ createMask(pMaskSet, pTabList->a[ii].iCursor); sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); }while( (++ii)nSrc ); #ifdef SQLITE_DEBUG { Bitmask mx = 0; for(ii=0; iinSrc; ii++){ Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); assert( m>=mx ); mx = m; } } #endif } /* Analyze all of the subexpressions. */ sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC); if( pSelect && pSelect->pLimit ){ sqlite3WhereAddLimit(&pWInfo->sWC, pSelect); } if( pParse->nErr ) goto whereBeginError; /* The False-WHERE-Term-Bypass optimization: ** ** If there are WHERE terms that are false, then no rows will be output, ** so skip over all of the code generated here. ** ** Conditions: ** ** (1) The WHERE term must not refer to any tables in the join. ** (2) The term must not come from an ON clause on the ** right-hand side of a LEFT or FULL JOIN. ** (3) The term must not come from an ON clause, or there must be ** no RIGHT or FULL OUTER joins in pTabList. ** (4) If the expression contains non-deterministic functions ** that are not within a sub-select. This is not required ** for correctness but rather to preserves SQLite's legacy ** behaviour in the following two cases: ** ** WHERE random()>0; -- eval random() once per row ** WHERE (SELECT random())>0; -- eval random() just once overall ** ** Note that the Where term need not be a constant in order for this ** optimization to apply, though it does need to be constant relative to ** the current subquery (condition 1). The term might include variables ** from outer queries so that the value of the term changes from one ** invocation of the current subquery to the next. */ for(ii=0; iinBase; ii++){ WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */ Expr *pX; /* The expression of pT */ if( pT->wtFlags & TERM_VIRTUAL ) continue; pX = pT->pExpr; assert( pX!=0 ); assert( pT->prereqAll!=0 || !ExprHasProperty(pX, EP_OuterON) ); if( pT->prereqAll==0 /* Conditions (1) and (2) */ && (nTabList==0 || exprIsDeterministic(pX)) /* Condition (4) */ && !(ExprHasProperty(pX, EP_InnerON) /* Condition (3) */ && (pTabList->a[0].fg.jointype & JT_LTORJ)!=0 ) ){ sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL); pT->wtFlags |= TERM_CODED; } } if( wctrlFlags & WHERE_WANT_DISTINCT ){ if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ wctrlFlags &= ~WHERE_WANT_DISTINCT; pWInfo->wctrlFlags &= ~WHERE_WANT_DISTINCT; }else if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ /* The DISTINCT marking is pointless. Ignore it. */ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; }else if( pOrderBy==0 ){ /* Try to ORDER BY the result set to make distinct processing easier */ pWInfo->wctrlFlags |= WHERE_DISTINCTBY; pWInfo->pOrderBy = pResultSet; } } /* Construct the WhereLoop objects */ #if defined(WHERETRACE_ENABLED) if( sqlite3WhereTrace & 0xffffffff ){ sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags); if( wctrlFlags & WHERE_USE_LIMIT ){ sqlite3DebugPrintf(", limit: %d", iAuxArg); } sqlite3DebugPrintf(")\n"); if( sqlite3WhereTrace & 0x8000 ){ Select sSelect; memset(&sSelect, 0, sizeof(sSelect)); sSelect.selFlags = SF_WhereBegin; sSelect.pSrc = pTabList; sSelect.pWhere = pWhere; sSelect.pOrderBy = pOrderBy; sSelect.pEList = pResultSet; sqlite3TreeViewSelect(0, &sSelect, 0); } if( sqlite3WhereTrace & 0x4000 ){ /* Display all WHERE clause terms */ sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n"); sqlite3WhereClausePrint(sWLB.pWC); } } #endif if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; #ifdef SQLITE_ENABLE_STAT4 /* If one or more WhereTerm.truthProb values were used in estimating ** loop parameters, but then those truthProb values were subsequently ** changed based on STAT4 information while computing subsequent loops, ** then we need to rerun the whole loop building process so that all ** loops will be built using the revised truthProb values. */ if( sWLB.bldFlags2 & SQLITE_BLDF2_2NDPASS ){ WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC); WHERETRACE(0xffffffff, ("**** Redo all loop computations due to" " TERM_HIGHTRUTH changes ****\n")); while( pWInfo->pLoops ){ WhereLoop *p = pWInfo->pLoops; pWInfo->pLoops = p->pNextLoop; whereLoopDelete(db, p); } rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; } #endif WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC); wherePathSolver(pWInfo, 0); if( db->mallocFailed ) goto whereBeginError; if( pWInfo->pOrderBy ){ wherePathSolver(pWInfo, pWInfo->nRowOut+1); if( db->mallocFailed ) goto whereBeginError; } /* TUNING: Assume that a DISTINCT clause on a subquery reduces ** the output size by a factor of 8 (LogEst -30). */ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){ WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n", pWInfo->nRowOut, pWInfo->nRowOut-30)); pWInfo->nRowOut -= 30; } } assert( pWInfo->pTabList!=0 ); if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ whereReverseScanOrder(pWInfo); } if( pParse->nErr ){ goto whereBeginError; } assert( db->mallocFailed==0 ); #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); if( pWInfo->nOBSat>0 ){ sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask); } switch( pWInfo->eDistinct ){ case WHERE_DISTINCT_UNIQUE: { sqlite3DebugPrintf(" DISTINCT=unique"); break; } case WHERE_DISTINCT_ORDERED: { sqlite3DebugPrintf(" DISTINCT=ordered"); break; } case WHERE_DISTINCT_UNORDERED: { sqlite3DebugPrintf(" DISTINCT=unordered"); break; } } sqlite3DebugPrintf("\n"); for(ii=0; iinLevel; ii++){ sqlite3WhereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC); } } #endif /* Attempt to omit tables from a join that do not affect the result. ** See the comment on whereOmitNoopJoin() for further information. ** ** This query optimization is factored out into a separate "no-inline" ** procedure to keep the sqlite3WhereBegin() procedure from becoming ** too large. If sqlite3WhereBegin() becomes too large, that prevents ** some C-compiler optimizers from in-lining the ** sqlite3WhereCodeOneLoopStart() procedure, and it is important to ** in-line sqlite3WhereCodeOneLoopStart() for performance reasons. */ notReady = ~(Bitmask)0; if( pWInfo->nLevel>=2 && pResultSet!=0 /* these two combine to guarantee */ && 0==(wctrlFlags & WHERE_AGG_DISTINCT) /* condition (1) above */ && OptimizationEnabled(db, SQLITE_OmitNoopJoin) ){ notReady = whereOmitNoopJoin(pWInfo, notReady); nTabList = pWInfo->nLevel; assert( nTabList>0 ); } /* Check to see if there are any SEARCH loops that might benefit from ** using a Bloom filter. */ if( pWInfo->nLevel>=2 && OptimizationEnabled(db, SQLITE_BloomFilter) ){ whereCheckIfBloomFilterIsUseful(pWInfo); } #if defined(WHERETRACE_ENABLED) if( sqlite3WhereTrace & 0x4000 ){ /* Display all terms of the WHERE clause */ sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n"); sqlite3WhereClausePrint(sWLB.pWC); } WHERETRACE(0xffffffff,("*** Optimizer Finished ***\n")); #endif pWInfo->pParse->nQueryLoop += pWInfo->nRowOut; /* If the caller is an UPDATE or DELETE statement that is requesting ** to use a one-pass algorithm, determine if this is appropriate. ** ** A one-pass approach can be used if the caller has requested one ** and either (a) the scan visits at most one row or (b) each ** of the following are true: ** ** * the caller has indicated that a one-pass approach can be used ** with multiple rows (by setting WHERE_ONEPASS_MULTIROW), and ** * the table is not a virtual table, and ** * either the scan does not use the OR optimization or the caller ** is a DELETE operation (WHERE_DUPLICATES_OK is only specified ** for DELETE). ** ** The last qualification is because an UPDATE statement uses ** WhereInfo.aiCurOnePass[1] to determine whether or not it really can ** use a one-pass approach, and this is not set accurately for scans ** that use the OR optimization. */ assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 ); if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ int wsFlags = pWInfo->a[0].pWLoop->wsFlags; int bOnerow = (wsFlags & WHERE_ONEROW)!=0; assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) ); if( bOnerow || ( 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW) && !IsVirtual(pTabList->a[0].pTab) && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK)) && OptimizationEnabled(db, SQLITE_OnePass) )){ pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){ if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){ bFordelete = OPFLAG_FORDELETE; } pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY); } } } /* Open all tables in the pTabList and any indices selected for ** searching those tables. */ for(ii=0, pLevel=pWInfo->a; iia[pLevel->iFrom]; pTab = pTabItem->pTab; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pLoop = pLevel->pWLoop; if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){ /* Do nothing */ }else #ifndef SQLITE_OMIT_VIRTUALTABLE if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); int iCur = pTabItem->iCursor; sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB); }else if( IsVirtual(pTab) ){ /* noop */ }else #endif if( ((pLoop->wsFlags & WHERE_IDX_ONLY)==0 && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0) || (pTabItem->fg.jointype & (JT_LTORJ|JT_RIGHT))!=0 ){ int op = OP_OpenRead; if( pWInfo->eOnePass!=ONEPASS_OFF ){ op = OP_OpenWrite; pWInfo->aiCurOnePass[0] = pTabItem->iCursor; }; sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); assert( pTabItem->iCursor==pLevel->iTabCur ); testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS-1 ); testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS ); if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nColtabFlags & (TF_HasGenerated|TF_WithoutRowid))==0 && (pLoop->wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))==0 ){ /* If we know that only a prefix of the record will be used, ** it is advantageous to reduce the "column count" field in ** the P4 operand of the OP_OpenRead/Write opcode. */ Bitmask b = pTabItem->colUsed; int n = 0; for(; b; b=b>>1, n++){} sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32); assert( n<=pTab->nCol ); } #ifdef SQLITE_ENABLE_CURSOR_HINTS if( pLoop->u.btree.pIndex!=0 && (pTab->tabFlags & TF_WithoutRowid)==0 ){ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete); }else #endif { sqlite3VdbeChangeP5(v, bFordelete); } #ifdef SQLITE_ENABLE_COLUMN_USED_MASK sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0, (const u8*)&pTabItem->colUsed, P4_INT64); #endif }else{ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); } if( pLoop->wsFlags & WHERE_INDEXED ){ Index *pIx = pLoop->u.btree.pIndex; int iIndexCur; int op = OP_OpenRead; /* iAuxArg is always set to a positive value if ONEPASS is possible */ assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ /* This is one term of an OR-optimization using the PRIMARY KEY of a ** WITHOUT ROWID table. No need for a separate index */ iIndexCur = pLevel->iTabCur; op = 0; }else if( pWInfo->eOnePass!=ONEPASS_OFF ){ Index *pJ = pTabItem->pTab->pIndex; iIndexCur = iAuxArg; assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); while( ALWAYS(pJ) && pJ!=pIx ){ iIndexCur++; pJ = pJ->pNext; } op = OP_OpenWrite; pWInfo->aiCurOnePass[1] = iIndexCur; }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ iIndexCur = iAuxArg; op = OP_ReopenIdx; }else{ iIndexCur = pParse->nTab++; if( pIx->bHasExpr && OptimizationEnabled(db, SQLITE_IndexedExpr) ){ whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem); } if( pIx->pPartIdxWhere && (pTabItem->fg.jointype & JT_RIGHT)==0 ){ wherePartIdxExpr( pParse, pIx, pIx->pPartIdxWhere, 0, iIndexCur, pTabItem ); } } pLevel->iIdxCur = iIndexCur; assert( pIx!=0 ); assert( pIx->pSchema==pTab->pSchema ); assert( iIndexCur>=0 ); if( op ){ sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIx); if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0 && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0 && (pLoop->wsFlags & WHERE_BIGNULL_SORT)==0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED ){ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); } VdbeComment((v, "%s", pIx->zName)); #ifdef SQLITE_ENABLE_COLUMN_USED_MASK { u64 colUsed = 0; int ii, jj; for(ii=0; iinColumn; ii++){ jj = pIx->aiColumn[ii]; if( jj<0 ) continue; if( jj>63 ) jj = 63; if( (pTabItem->colUsed & MASKBIT(jj))==0 ) continue; colUsed |= ((u64)1)<<(ii<63 ? ii : 63); } sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, iIndexCur, 0, 0, (u8*)&colUsed, P4_INT64); } #endif /* SQLITE_ENABLE_COLUMN_USED_MASK */ } } if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); if( (pTabItem->fg.jointype & JT_RIGHT)!=0 && (pLevel->pRJ = sqlite3WhereMalloc(pWInfo, sizeof(WhereRightJoin)))!=0 ){ WhereRightJoin *pRJ = pLevel->pRJ; pRJ->iMatch = pParse->nTab++; pRJ->regBloom = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); pRJ->regReturn = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn); assert( pTab==pTabItem->pTab ); if( HasRowid(pTab) ){ KeyInfo *pInfo; sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1); pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0); if( pInfo ){ pInfo->aColl[0] = 0; pInfo->aSortFlags[0] = 0; sqlite3VdbeAppendP4(v, pInfo, P4_KEYINFO); } }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, pPk->nKeyCol); sqlite3VdbeSetP4KeyInfo(pParse, pPk); } pLoop->wsFlags &= ~WHERE_IDX_ONLY; /* The nature of RIGHT JOIN processing is such that it messes up ** the output order. So omit any ORDER BY/GROUP BY elimination ** optimizations. We need to do an actual sort for RIGHT JOIN. */ pWInfo->nOBSat = 0; pWInfo->eDistinct = WHERE_DISTINCT_UNORDERED; } } pWInfo->iTop = sqlite3VdbeCurrentAddr(v); if( db->mallocFailed ) goto whereBeginError; /* Generate the code to do the search. Each iteration of the for ** loop below generates code for a single nested loop of the VM ** program. */ for(ii=0; iinErr ) goto whereBeginError; pLevel = &pWInfo->a[ii]; wsFlags = pLevel->pWLoop->wsFlags; pSrc = &pTabList->a[pLevel->iFrom]; if( pSrc->fg.isMaterialized ){ if( pSrc->fg.isCorrelated ){ sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); }else{ int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); sqlite3VdbeJumpHere(v, iOnce); } } assert( pTabList == pWInfo->pTabList ); if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){ if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){ #ifndef SQLITE_OMIT_AUTOMATIC_INDEX constructAutomaticIndex(pParse, &pWInfo->sWC, notReady, pLevel); #endif }else{ sqlite3ConstructBloomFilter(pWInfo, ii, pLevel, notReady); } if( db->mallocFailed ) goto whereBeginError; } addrExplain = sqlite3WhereExplainOneScan( pParse, pTabList, pLevel, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = sqlite3WhereCodeOneLoopStart(pParse,v,pWInfo,ii,pLevel,notReady); pWInfo->iContinue = pLevel->addrCont; if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){ sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain); } } /* Done. */ VdbeModuleComment((v, "Begin WHERE-core")); pWInfo->iEndWhere = sqlite3VdbeCurrentAddr(v); return pWInfo; /* Jump here if malloc fails */ whereBeginError: if( pWInfo ){ pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); } #ifdef WHERETRACE_ENABLED /* Prevent harmless compiler warnings about debugging routines ** being declared but never used */ sqlite3ShowWhereLoopList(0); #endif /* WHERETRACE_ENABLED */ return 0; } /* ** Part of sqlite3WhereEnd() will rewrite opcodes to reference the ** index rather than the main table. In SQLITE_DEBUG mode, we want ** to trace those changes if PRAGMA vdbe_addoptrace=on. This routine ** does that. */ #ifndef SQLITE_DEBUG # define OpcodeRewriteTrace(D,K,P) /* no-op */ #else # define OpcodeRewriteTrace(D,K,P) sqlite3WhereOpcodeRewriteTrace(D,K,P) static void sqlite3WhereOpcodeRewriteTrace( sqlite3 *db, int pc, VdbeOp *pOp ){ if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return; sqlite3VdbePrintOp(0, pc, pOp); } #endif #ifdef SQLITE_DEBUG /* ** Return true if cursor iCur is opened by instruction k of the ** bytecode. Used inside of assert() only. */ static int cursorIsOpen(Vdbe *v, int iCur, int k){ while( k>=0 ){ VdbeOp *pOp = sqlite3VdbeGetOp(v,k--); if( pOp->p1!=iCur ) continue; if( pOp->opcode==OP_Close ) return 0; if( pOp->opcode==OP_OpenRead ) return 1; if( pOp->opcode==OP_OpenWrite ) return 1; if( pOp->opcode==OP_OpenDup ) return 1; if( pOp->opcode==OP_OpenAutoindex ) return 1; if( pOp->opcode==OP_OpenEphemeral ) return 1; } return 0; } #endif /* SQLITE_DEBUG */ /* ** Generate the end of the WHERE loop. See comments on ** sqlite3WhereBegin() for additional information. */ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ Parse *pParse = pWInfo->pParse; Vdbe *v = pParse->pVdbe; int i; WhereLevel *pLevel; WhereLoop *pLoop; SrcList *pTabList = pWInfo->pTabList; sqlite3 *db = pParse->db; int iEnd = sqlite3VdbeCurrentAddr(v); int nRJ = 0; /* Generate loop termination code. */ VdbeModuleComment((v, "End WHERE-core")); for(i=pWInfo->nLevel-1; i>=0; i--){ int addr; pLevel = &pWInfo->a[i]; if( pLevel->pRJ ){ /* Terminate the subroutine that forms the interior of the loop of ** the RIGHT JOIN table */ WhereRightJoin *pRJ = pLevel->pRJ; sqlite3VdbeResolveLabel(v, pLevel->addrCont); pLevel->addrCont = 0; pRJ->endSubrtn = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn, 1); VdbeCoverage(v); nRJ++; } pLoop = pLevel->pWLoop; if( pLevel->op!=OP_Noop ){ #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT int addrSeek = 0; Index *pIdx; int n; if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED && i==pWInfo->nLevel-1 /* Ticket [ef9318757b152e3] 2017-10-21 */ && (pLoop->wsFlags & WHERE_INDEXED)!=0 && (pIdx = pLoop->u.btree.pIndex)->hasStat1 && (n = pLoop->u.btree.nDistinctCol)>0 && pIdx->aiRowLogEst[n]>=36 ){ int r1 = pParse->nMem+1; int j, op; for(j=0; jiIdxCur, j, r1+j); } pParse->nMem += n+1; op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT; addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n); VdbeCoverageIf(v, op==OP_SeekLT); VdbeCoverageIf(v, op==OP_SeekGT); sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2); } #endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */ /* The common case: Advance to the next row */ if( pLevel->addrCont ) sqlite3VdbeResolveLabel(v, pLevel->addrCont); sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3); sqlite3VdbeChangeP5(v, pLevel->p5); VdbeCoverage(v); VdbeCoverageIf(v, pLevel->op==OP_Next); VdbeCoverageIf(v, pLevel->op==OP_Prev); VdbeCoverageIf(v, pLevel->op==OP_VNext); if( pLevel->regBignull ){ sqlite3VdbeResolveLabel(v, pLevel->addrBignull); sqlite3VdbeAddOp2(v, OP_DecrJumpZero, pLevel->regBignull, pLevel->p2-1); VdbeCoverage(v); } #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek); #endif }else if( pLevel->addrCont ){ sqlite3VdbeResolveLabel(v, pLevel->addrCont); } if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ assert( sqlite3VdbeGetOp(v, pIn->addrInTop+1)->opcode==OP_IsNull || pParse->db->mallocFailed ); sqlite3VdbeJumpHere(v, pIn->addrInTop+1); if( pIn->eEndLoopOp!=OP_Noop ){ if( pIn->nPrefix ){ int bEarlyOut = (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0; if( pLevel->iLeftJoin ){ /* For LEFT JOIN queries, cursor pIn->iCur may not have been ** opened yet. This occurs for WHERE clauses such as ** "a = ? AND b IN (...)", where the index is on (a, b). If ** the RHS of the (a=?) is NULL, then the "b IN (...)" may ** never have been coded, but the body of the loop run to ** return the null-row. So, if the cursor is not open yet, ** jump over the OP_Next or OP_Prev instruction about to ** be coded. */ sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur, sqlite3VdbeCurrentAddr(v) + 2 + bEarlyOut); VdbeCoverage(v); } if( bEarlyOut ){ sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur, sqlite3VdbeCurrentAddr(v)+2, pIn->iBase, pIn->nPrefix); VdbeCoverage(v); /* Retarget the OP_IsNull against the left operand of IN so ** it jumps past the OP_IfNoHope. This is because the ** OP_IsNull also bypasses the OP_Affinity opcode that is ** required by OP_IfNoHope. */ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); } } sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); VdbeCoverage(v); VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Prev); VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Next); } sqlite3VdbeJumpHere(v, pIn->addrInTop-1); } } sqlite3VdbeResolveLabel(v, pLevel->addrBrk); if( pLevel->pRJ ){ sqlite3VdbeAddOp3(v, OP_Return, pLevel->pRJ->regReturn, 0, 1); VdbeCoverage(v); } if( pLevel->addrSkip ){ sqlite3VdbeGoto(v, pLevel->addrSkip); VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName)); sqlite3VdbeJumpHere(v, pLevel->addrSkip); sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); } #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( pLevel->addrLikeRep ){ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, (int)(pLevel->iLikeRepCntr>>1), pLevel->addrLikeRep); VdbeCoverage(v); } #endif if( pLevel->iLeftJoin ){ int ws = pLoop->wsFlags; addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 ); if( (ws & WHERE_IDX_ONLY)==0 ){ assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor ); sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur); } if( (ws & WHERE_INDEXED) || ((ws & WHERE_MULTI_OR) && pLevel->u.pCoveringIdx) ){ if( ws & WHERE_MULTI_OR ){ Index *pIx = pLevel->u.pCoveringIdx; int iDb = sqlite3SchemaToIndex(db, pIx->pSchema); sqlite3VdbeAddOp3(v, OP_ReopenIdx, pLevel->iIdxCur, pIx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIx); } sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); } if( pLevel->op==OP_Return ){ sqlite3VdbeAddOp2(v, OP_Gosub, pLevel->p1, pLevel->addrFirst); }else{ sqlite3VdbeGoto(v, pLevel->addrFirst); } sqlite3VdbeJumpHere(v, addr); } VdbeModuleComment((v, "End WHERE-loop%d: %s", i, pWInfo->pTabList->a[pLevel->iFrom].pTab->zName)); } assert( pWInfo->nLevel<=pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ int k, last; VdbeOp *pOp, *pLastOp; Index *pIdx = 0; SrcItem *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; assert( pTab!=0 ); pLoop = pLevel->pWLoop; /* Do RIGHT JOIN processing. Generate code that will output the ** unmatched rows of the right operand of the RIGHT JOIN with ** all of the columns of the left operand set to NULL. */ if( pLevel->pRJ ){ sqlite3WhereRightJoinLoop(pWInfo, i, pLevel); continue; } /* For a co-routine, change all OP_Column references to the table of ** the co-routine into OP_Copy of result contained in a register. ** OP_Rowid becomes OP_Null. */ if( pTabItem->fg.viaCoroutine ){ testcase( pParse->db->mallocFailed ); translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, pTabItem->regResult, 0); continue; } /* If this scan uses an index, make VDBE code substitutions to read data ** from the index instead of from the table where possible. In some cases ** this optimization prevents the table from ever being read, which can ** yield a significant performance boost. ** ** Calls to the code generator in between sqlite3WhereBegin and ** sqlite3WhereEnd will have created code that references the table ** directly. This loop scans all that code looking for opcodes ** that reference the table and converts them into opcodes that ** reference the index. */ if( pLoop->wsFlags & (WHERE_INDEXED|WHERE_IDX_ONLY) ){ pIdx = pLoop->u.btree.pIndex; }else if( pLoop->wsFlags & WHERE_MULTI_OR ){ pIdx = pLevel->u.pCoveringIdx; } if( pIdx && !db->mallocFailed ){ if( pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable) ){ last = iEnd; }else{ last = pWInfo->iEndWhere; } if( pIdx->bHasExpr ){ IndexedExpr *p = pParse->pIdxEpr; while( p ){ if( p->iIdxCur==pLevel->iIdxCur ){ #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x200 ){ sqlite3DebugPrintf("Disable pParse->pIdxEpr term {%d,%d}\n", p->iIdxCur, p->iIdxCol); if( sqlite3WhereTrace & 0x5000 ) sqlite3ShowExpr(p->pExpr); } #endif p->iDataCur = -1; p->iIdxCur = -1; } p = p->pIENext; } } k = pLevel->addrBody + 1; #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeAddopTrace ){ printf("TRANSLATE cursor %d->%d in opcode range %d..%d\n", pLevel->iTabCur, pLevel->iIdxCur, k, last-1); } /* Proof that the "+1" on the k value above is safe */ pOp = sqlite3VdbeGetOp(v, k - 1); assert( pOp->opcode!=OP_Column || pOp->p1!=pLevel->iTabCur ); assert( pOp->opcode!=OP_Rowid || pOp->p1!=pLevel->iTabCur ); assert( pOp->opcode!=OP_IfNullRow || pOp->p1!=pLevel->iTabCur ); #endif pOp = sqlite3VdbeGetOp(v, k); pLastOp = pOp + (last - k); assert( pOp<=pLastOp ); do{ if( pOp->p1!=pLevel->iTabCur ){ /* no-op */ }else if( pOp->opcode==OP_Column #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC || pOp->opcode==OP_Offset #endif ){ int x = pOp->p2; assert( pIdx->pTable==pTab ); #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC if( pOp->opcode==OP_Offset ){ /* Do not need to translate the column number */ }else #endif if( !HasRowid(pTab) ){ Index *pPk = sqlite3PrimaryKeyIndex(pTab); x = pPk->aiColumn[x]; assert( x>=0 ); }else{ testcase( x!=sqlite3StorageColumnToTable(pTab,x) ); x = sqlite3StorageColumnToTable(pTab,x); } x = sqlite3TableColumnToIndex(pIdx, x); if( x>=0 ){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; OpcodeRewriteTrace(db, k, pOp); }else{ /* Unable to translate the table reference into an index ** reference. Verify that this is harmless - that the ** table being referenced really is open. */ #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || cursorIsOpen(v,pOp->p1,k) || pOp->opcode==OP_Offset ); #else assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || cursorIsOpen(v,pOp->p1,k) ); #endif } }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur; pOp->opcode = OP_IdxRowid; OpcodeRewriteTrace(db, k, pOp); }else if( pOp->opcode==OP_IfNullRow ){ pOp->p1 = pLevel->iIdxCur; OpcodeRewriteTrace(db, k, pOp); } #ifdef SQLITE_DEBUG k++; #endif }while( (++pOp)flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n"); #endif } } /* The "break" point is here, just past the end of the outer loop. ** Set it. */ sqlite3VdbeResolveLabel(v, pWInfo->iBreak); /* Final cleanup */ pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); pParse->withinRJSubrtn -= nRJ; return; } /************** End of where.c ***********************************************/ /************** Begin file window.c ******************************************/ /* ** 2018 May 08 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* */ /* #include "sqliteInt.h" */ #ifndef SQLITE_OMIT_WINDOWFUNC /* ** SELECT REWRITING ** ** Any SELECT statement that contains one or more window functions in ** either the select list or ORDER BY clause (the only two places window ** functions may be used) is transformed by function sqlite3WindowRewrite() ** in order to support window function processing. For example, with the ** schema: ** ** CREATE TABLE t1(a, b, c, d, e, f, g); ** ** the statement: ** ** SELECT a+1, max(b) OVER (PARTITION BY c ORDER BY d) FROM t1 ORDER BY e; ** ** is transformed to: ** ** SELECT a+1, max(b) OVER (PARTITION BY c ORDER BY d) FROM ( ** SELECT a, e, c, d, b FROM t1 ORDER BY c, d ** ) ORDER BY e; ** ** The flattening optimization is disabled when processing this transformed ** SELECT statement. This allows the implementation of the window function ** (in this case max()) to process rows sorted in order of (c, d), which ** makes things easier for obvious reasons. More generally: ** ** * FROM, WHERE, GROUP BY and HAVING clauses are all moved to ** the sub-query. ** ** * ORDER BY, LIMIT and OFFSET remain part of the parent query. ** ** * Terminals from each of the expression trees that make up the ** select-list and ORDER BY expressions in the parent query are ** selected by the sub-query. For the purposes of the transformation, ** terminals are column references and aggregate functions. ** ** If there is more than one window function in the SELECT that uses ** the same window declaration (the OVER bit), then a single scan may ** be used to process more than one window function. For example: ** ** SELECT max(b) OVER (PARTITION BY c ORDER BY d), ** min(e) OVER (PARTITION BY c ORDER BY d) ** FROM t1; ** ** is transformed in the same way as the example above. However: ** ** SELECT max(b) OVER (PARTITION BY c ORDER BY d), ** min(e) OVER (PARTITION BY a ORDER BY b) ** FROM t1; ** ** Must be transformed to: ** ** SELECT max(b) OVER (PARTITION BY c ORDER BY d) FROM ( ** SELECT e, min(e) OVER (PARTITION BY a ORDER BY b), c, d, b FROM ** SELECT a, e, c, d, b FROM t1 ORDER BY a, b ** ) ORDER BY c, d ** ) ORDER BY e; ** ** so that both min() and max() may process rows in the order defined by ** their respective window declarations. ** ** INTERFACE WITH SELECT.C ** ** When processing the rewritten SELECT statement, code in select.c calls ** sqlite3WhereBegin() to begin iterating through the results of the ** sub-query, which is always implemented as a co-routine. It then calls ** sqlite3WindowCodeStep() to process rows and finish the scan by calling ** sqlite3WhereEnd(). ** ** sqlite3WindowCodeStep() generates VM code so that, for each row returned ** by the sub-query a sub-routine (OP_Gosub) coded by select.c is invoked. ** When the sub-routine is invoked: ** ** * The results of all window-functions for the row are stored ** in the associated Window.regResult registers. ** ** * The required terminal values are stored in the current row of ** temp table Window.iEphCsr. ** ** In some cases, depending on the window frame and the specific window ** functions invoked, sqlite3WindowCodeStep() caches each entire partition ** in a temp table before returning any rows. In other cases it does not. ** This detail is encapsulated within this file, the code generated by ** select.c is the same in either case. ** ** BUILT-IN WINDOW FUNCTIONS ** ** This implementation features the following built-in window functions: ** ** row_number() ** rank() ** dense_rank() ** percent_rank() ** cume_dist() ** ntile(N) ** lead(expr [, offset [, default]]) ** lag(expr [, offset [, default]]) ** first_value(expr) ** last_value(expr) ** nth_value(expr, N) ** ** These are the same built-in window functions supported by Postgres. ** Although the behaviour of aggregate window functions (functions that ** can be used as either aggregates or window functions) allows them to ** be implemented using an API, built-in window functions are much more ** esoteric. Additionally, some window functions (e.g. nth_value()) ** may only be implemented by caching the entire partition in memory. ** As such, some built-in window functions use the same API as aggregate ** window functions and some are implemented directly using VDBE ** instructions. Additionally, for those functions that use the API, the ** window frame is sometimes modified before the SELECT statement is ** rewritten. For example, regardless of the specified window frame, the ** row_number() function always uses: ** ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ** ** See sqlite3WindowUpdate() for details. ** ** As well as some of the built-in window functions, aggregate window ** functions min() and max() are implemented using VDBE instructions if ** the start of the window frame is declared as anything other than ** UNBOUNDED PRECEDING. */ /* ** Implementation of built-in window function row_number(). Assumes that the ** window frame has been coerced to: ** ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ static void row_numberStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ) (*p)++; UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); } static void row_numberValueFunc(sqlite3_context *pCtx){ i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p)); sqlite3_result_int64(pCtx, (p ? *p : 0)); } /* ** Context object type used by rank(), dense_rank(), percent_rank() and ** cume_dist(). */ struct CallCount { i64 nValue; i64 nStep; i64 nTotal; }; /* ** Implementation of built-in window function dense_rank(). Assumes that ** the window frame has been set to: ** ** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ static void dense_rankStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ) p->nStep = 1; UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); } static void dense_rankValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ if( p->nStep ){ p->nValue++; p->nStep = 0; } sqlite3_result_int64(pCtx, p->nValue); } } /* ** Implementation of built-in window function nth_value(). This ** implementation is used in "slow mode" only - when the EXCLUDE clause ** is not set to the default value "NO OTHERS". */ struct NthValueCtx { i64 nStep; sqlite3_value *pValue; }; static void nth_valueStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct NthValueCtx *p; p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ i64 iVal; switch( sqlite3_value_numeric_type(apArg[1]) ){ case SQLITE_INTEGER: iVal = sqlite3_value_int64(apArg[1]); break; case SQLITE_FLOAT: { double fVal = sqlite3_value_double(apArg[1]); if( ((i64)fVal)!=fVal ) goto error_out; iVal = (i64)fVal; break; } default: goto error_out; } if( iVal<=0 ) goto error_out; p->nStep++; if( iVal==p->nStep ){ p->pValue = sqlite3_value_dup(apArg[0]); if( !p->pValue ){ sqlite3_result_error_nomem(pCtx); } } } UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); return; error_out: sqlite3_result_error( pCtx, "second argument to nth_value must be a positive integer", -1 ); } static void nth_valueFinalizeFunc(sqlite3_context *pCtx){ struct NthValueCtx *p; p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, 0); if( p && p->pValue ){ sqlite3_result_value(pCtx, p->pValue); sqlite3_value_free(p->pValue); p->pValue = 0; } } #define nth_valueInvFunc noopStepFunc #define nth_valueValueFunc noopValueFunc static void first_valueStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct NthValueCtx *p; p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->pValue==0 ){ p->pValue = sqlite3_value_dup(apArg[0]); if( !p->pValue ){ sqlite3_result_error_nomem(pCtx); } } UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); } static void first_valueFinalizeFunc(sqlite3_context *pCtx){ struct NthValueCtx *p; p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->pValue ){ sqlite3_result_value(pCtx, p->pValue); sqlite3_value_free(p->pValue); p->pValue = 0; } } #define first_valueInvFunc noopStepFunc #define first_valueValueFunc noopValueFunc /* ** Implementation of built-in window function rank(). Assumes that ** the window frame has been set to: ** ** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ static void rankStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ p->nStep++; if( p->nValue==0 ){ p->nValue = p->nStep; } } UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); } static void rankValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ sqlite3_result_int64(pCtx, p->nValue); p->nValue = 0; } } /* ** Implementation of built-in window function percent_rank(). Assumes that ** the window frame has been set to: ** ** GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING */ static void percent_rankStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; UNUSED_PARAMETER(nArg); assert( nArg==0 ); UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ p->nTotal++; } } static void percent_rankInvFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; UNUSED_PARAMETER(nArg); assert( nArg==0 ); UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); p->nStep++; } static void percent_rankValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ p->nValue = p->nStep; if( p->nTotal>1 ){ double r = (double)p->nValue / (double)(p->nTotal-1); sqlite3_result_double(pCtx, r); }else{ sqlite3_result_double(pCtx, 0.0); } } } #define percent_rankFinalizeFunc percent_rankValueFunc /* ** Implementation of built-in window function cume_dist(). Assumes that ** the window frame has been set to: ** ** GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING */ static void cume_distStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; UNUSED_PARAMETER(nArg); assert( nArg==0 ); UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ p->nTotal++; } } static void cume_distInvFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; UNUSED_PARAMETER(nArg); assert( nArg==0 ); UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); p->nStep++; } static void cume_distValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, 0); if( p ){ double r = (double)(p->nStep) / (double)(p->nTotal); sqlite3_result_double(pCtx, r); } } #define cume_distFinalizeFunc cume_distValueFunc /* ** Context object for ntile() window function. */ struct NtileCtx { i64 nTotal; /* Total rows in partition */ i64 nParam; /* Parameter passed to ntile(N) */ i64 iRow; /* Current row */ }; /* ** Implementation of ntile(). This assumes that the window frame has ** been coerced to: ** ** ROWS CURRENT ROW AND UNBOUNDED FOLLOWING */ static void ntileStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct NtileCtx *p; assert( nArg==1 ); UNUSED_PARAMETER(nArg); p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ if( p->nTotal==0 ){ p->nParam = sqlite3_value_int64(apArg[0]); if( p->nParam<=0 ){ sqlite3_result_error( pCtx, "argument of ntile must be a positive integer", -1 ); } } p->nTotal++; } } static void ntileInvFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct NtileCtx *p; assert( nArg==1 ); UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); p->iRow++; } static void ntileValueFunc(sqlite3_context *pCtx){ struct NtileCtx *p; p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->nParam>0 ){ int nSize = (p->nTotal / p->nParam); if( nSize==0 ){ sqlite3_result_int64(pCtx, p->iRow+1); }else{ i64 nLarge = p->nTotal - p->nParam*nSize; i64 iSmall = nLarge*(nSize+1); i64 iRow = p->iRow; assert( (nLarge*(nSize+1) + (p->nParam-nLarge)*nSize)==p->nTotal ); if( iRowpVal); p->pVal = sqlite3_value_dup(apArg[0]); if( p->pVal==0 ){ sqlite3_result_error_nomem(pCtx); }else{ p->nVal++; } } } static void last_valueInvFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct LastValueCtx *p; UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( ALWAYS(p) ){ p->nVal--; if( p->nVal==0 ){ sqlite3_value_free(p->pVal); p->pVal = 0; } } } static void last_valueValueFunc(sqlite3_context *pCtx){ struct LastValueCtx *p; p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, 0); if( p && p->pVal ){ sqlite3_result_value(pCtx, p->pVal); } } static void last_valueFinalizeFunc(sqlite3_context *pCtx){ struct LastValueCtx *p; p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->pVal ){ sqlite3_result_value(pCtx, p->pVal); sqlite3_value_free(p->pVal); p->pVal = 0; } } /* ** Static names for the built-in window function names. These static ** names are used, rather than string literals, so that FuncDef objects ** can be associated with a particular window function by direct ** comparison of the zName pointer. Example: ** ** if( pFuncDef->zName==row_valueName ){ ... } */ static const char row_numberName[] = "row_number"; static const char dense_rankName[] = "dense_rank"; static const char rankName[] = "rank"; static const char percent_rankName[] = "percent_rank"; static const char cume_distName[] = "cume_dist"; static const char ntileName[] = "ntile"; static const char last_valueName[] = "last_value"; static const char nth_valueName[] = "nth_value"; static const char first_valueName[] = "first_value"; static const char leadName[] = "lead"; static const char lagName[] = "lag"; /* ** No-op implementations of xStep() and xFinalize(). Used as place-holders ** for built-in window functions that never call those interfaces. ** ** The noopValueFunc() is called but is expected to do nothing. The ** noopStepFunc() is never called, and so it is marked with NO_TEST to ** let the test coverage routine know not to expect this function to be ** invoked. */ static void noopStepFunc( /*NO_TEST*/ sqlite3_context *p, /*NO_TEST*/ int n, /*NO_TEST*/ sqlite3_value **a /*NO_TEST*/ ){ /*NO_TEST*/ UNUSED_PARAMETER(p); /*NO_TEST*/ UNUSED_PARAMETER(n); /*NO_TEST*/ UNUSED_PARAMETER(a); /*NO_TEST*/ assert(0); /*NO_TEST*/ } /*NO_TEST*/ static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ } /* Window functions that use all window interfaces: xStep, xFinal, ** xValue, and xInverse */ #define WINDOWFUNCALL(name,nArg,extra) { \ nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \ name ## InvFunc, name ## Name, {0} \ } /* Window functions that are implemented using bytecode and thus have ** no-op routines for their methods */ #define WINDOWFUNCNOOP(name,nArg,extra) { \ nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ noopStepFunc, noopValueFunc, noopValueFunc, \ noopStepFunc, name ## Name, {0} \ } /* Window functions that use all window interfaces: xStep, the ** same routine for xFinalize and xValue and which never call ** xInverse. */ #define WINDOWFUNCX(name,nArg,extra) { \ nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \ noopStepFunc, name ## Name, {0} \ } /* ** Register those built-in window functions that are not also aggregates. */ SQLITE_PRIVATE void sqlite3WindowFunctions(void){ static FuncDef aWindowFuncs[] = { WINDOWFUNCX(row_number, 0, 0), WINDOWFUNCX(dense_rank, 0, 0), WINDOWFUNCX(rank, 0, 0), WINDOWFUNCALL(percent_rank, 0, 0), WINDOWFUNCALL(cume_dist, 0, 0), WINDOWFUNCALL(ntile, 1, 0), WINDOWFUNCALL(last_value, 1, 0), WINDOWFUNCALL(nth_value, 2, 0), WINDOWFUNCALL(first_value, 1, 0), WINDOWFUNCNOOP(lead, 1, 0), WINDOWFUNCNOOP(lead, 2, 0), WINDOWFUNCNOOP(lead, 3, 0), WINDOWFUNCNOOP(lag, 1, 0), WINDOWFUNCNOOP(lag, 2, 0), WINDOWFUNCNOOP(lag, 3, 0), }; sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs)); } static Window *windowFind(Parse *pParse, Window *pList, const char *zName){ Window *p; for(p=pList; p; p=p->pNextWin){ if( sqlite3StrICmp(p->zName, zName)==0 ) break; } if( p==0 ){ sqlite3ErrorMsg(pParse, "no such window: %s", zName); } return p; } /* ** This function is called immediately after resolving the function name ** for a window function within a SELECT statement. Argument pList is a ** linked list of WINDOW definitions for the current SELECT statement. ** Argument pFunc is the function definition just resolved and pWin ** is the Window object representing the associated OVER clause. This ** function updates the contents of pWin as follows: ** ** * If the OVER clause referred to a named window (as in "max(x) OVER win"), ** search list pList for a matching WINDOW definition, and update pWin ** accordingly. If no such WINDOW clause can be found, leave an error ** in pParse. ** ** * If the function is a built-in window function that requires the ** window to be coerced (see "BUILT-IN WINDOW FUNCTIONS" at the top ** of this file), pWin is updated here. */ SQLITE_PRIVATE void sqlite3WindowUpdate( Parse *pParse, Window *pList, /* List of named windows for this SELECT */ Window *pWin, /* Window frame to update */ FuncDef *pFunc /* Window function definition */ ){ if( pWin->zName && pWin->eFrmType==0 ){ Window *p = windowFind(pParse, pList, pWin->zName); if( p==0 ) return; pWin->pPartition = sqlite3ExprListDup(pParse->db, p->pPartition, 0); pWin->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy, 0); pWin->pStart = sqlite3ExprDup(pParse->db, p->pStart, 0); pWin->pEnd = sqlite3ExprDup(pParse->db, p->pEnd, 0); pWin->eStart = p->eStart; pWin->eEnd = p->eEnd; pWin->eFrmType = p->eFrmType; pWin->eExclude = p->eExclude; }else{ sqlite3WindowChain(pParse, pWin, pList); } if( (pWin->eFrmType==TK_RANGE) && (pWin->pStart || pWin->pEnd) && (pWin->pOrderBy==0 || pWin->pOrderBy->nExpr!=1) ){ sqlite3ErrorMsg(pParse, "RANGE with offset PRECEDING/FOLLOWING requires one ORDER BY expression" ); }else if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){ sqlite3 *db = pParse->db; if( pWin->pFilter ){ sqlite3ErrorMsg(pParse, "FILTER clause may only be used with aggregate window functions" ); }else{ struct WindowUpdate { const char *zFunc; int eFrmType; int eStart; int eEnd; } aUp[] = { { row_numberName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT }, { dense_rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT }, { rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT }, { percent_rankName, TK_GROUPS, TK_CURRENT, TK_UNBOUNDED }, { cume_distName, TK_GROUPS, TK_FOLLOWING, TK_UNBOUNDED }, { ntileName, TK_ROWS, TK_CURRENT, TK_UNBOUNDED }, { leadName, TK_ROWS, TK_UNBOUNDED, TK_UNBOUNDED }, { lagName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT }, }; int i; for(i=0; izName==aUp[i].zFunc ){ sqlite3ExprDelete(db, pWin->pStart); sqlite3ExprDelete(db, pWin->pEnd); pWin->pEnd = pWin->pStart = 0; pWin->eFrmType = aUp[i].eFrmType; pWin->eStart = aUp[i].eStart; pWin->eEnd = aUp[i].eEnd; pWin->eExclude = 0; if( pWin->eStart==TK_FOLLOWING ){ pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1"); } break; } } } } pWin->pWFunc = pFunc; } /* ** Context object passed through sqlite3WalkExprList() to ** selectWindowRewriteExprCb() by selectWindowRewriteEList(). */ typedef struct WindowRewrite WindowRewrite; struct WindowRewrite { Window *pWin; SrcList *pSrc; ExprList *pSub; Table *pTab; Select *pSubSelect; /* Current sub-select, if any */ }; /* ** Callback function used by selectWindowRewriteEList(). If necessary, ** this function appends to the output expression-list and updates ** expression (*ppExpr) in place. */ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ struct WindowRewrite *p = pWalker->u.pRewrite; Parse *pParse = pWalker->pParse; assert( p!=0 ); assert( p->pWin!=0 ); /* If this function is being called from within a scalar sub-select ** that used by the SELECT statement being processed, only process ** TK_COLUMN expressions that refer to it (the outer SELECT). Do ** not process aggregates or window functions at all, as they belong ** to the scalar sub-select. */ if( p->pSubSelect ){ if( pExpr->op!=TK_COLUMN ){ return WRC_Continue; }else{ int nSrc = p->pSrc->nSrc; int i; for(i=0; iiTable==p->pSrc->a[i].iCursor ) break; } if( i==nSrc ) return WRC_Continue; } } switch( pExpr->op ){ case TK_FUNCTION: if( !ExprHasProperty(pExpr, EP_WinFunc) ){ break; }else{ Window *pWin; for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){ if( pExpr->y.pWin==pWin ){ assert( pWin->pOwner==pExpr ); return WRC_Prune; } } } /* no break */ deliberate_fall_through case TK_IF_NULL_ROW: case TK_AGG_FUNCTION: case TK_COLUMN: { int iCol = -1; if( pParse->db->mallocFailed ) return WRC_Abort; if( p->pSub ){ int i; for(i=0; ipSub->nExpr; i++){ if( 0==sqlite3ExprCompare(0, p->pSub->a[i].pExpr, pExpr, -1) ){ iCol = i; break; } } } if( iCol<0 ){ Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0); if( pDup && pDup->op==TK_AGG_FUNCTION ) pDup->op = TK_FUNCTION; p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup); } if( p->pSub ){ int f = pExpr->flags & EP_Collate; assert( ExprHasProperty(pExpr, EP_Static)==0 ); ExprSetProperty(pExpr, EP_Static); sqlite3ExprDelete(pParse->db, pExpr); ExprClearProperty(pExpr, EP_Static); memset(pExpr, 0, sizeof(Expr)); pExpr->op = TK_COLUMN; pExpr->iColumn = (iCol<0 ? p->pSub->nExpr-1: iCol); pExpr->iTable = p->pWin->iEphCsr; pExpr->y.pTab = p->pTab; pExpr->flags = f; } if( pParse->db->mallocFailed ) return WRC_Abort; break; } default: /* no-op */ break; } return WRC_Continue; } static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){ struct WindowRewrite *p = pWalker->u.pRewrite; Select *pSave = p->pSubSelect; if( pSave==pSelect ){ return WRC_Continue; }else{ p->pSubSelect = pSelect; sqlite3WalkSelect(pWalker, pSelect); p->pSubSelect = pSave; } return WRC_Prune; } /* ** Iterate through each expression in expression-list pEList. For each: ** ** * TK_COLUMN, ** * aggregate function, or ** * window function with a Window object that is not a member of the ** Window list passed as the second argument (pWin). ** ** Append the node to output expression-list (*ppSub). And replace it ** with a TK_COLUMN that reads the (N-1)th element of table ** pWin->iEphCsr, where N is the number of elements in (*ppSub) after ** appending the new one. */ static void selectWindowRewriteEList( Parse *pParse, Window *pWin, SrcList *pSrc, ExprList *pEList, /* Rewrite expressions in this list */ Table *pTab, ExprList **ppSub /* IN/OUT: Sub-select expression-list */ ){ Walker sWalker; WindowRewrite sRewrite; assert( pWin!=0 ); memset(&sWalker, 0, sizeof(Walker)); memset(&sRewrite, 0, sizeof(WindowRewrite)); sRewrite.pSub = *ppSub; sRewrite.pWin = pWin; sRewrite.pSrc = pSrc; sRewrite.pTab = pTab; sWalker.pParse = pParse; sWalker.xExprCallback = selectWindowRewriteExprCb; sWalker.xSelectCallback = selectWindowRewriteSelectCb; sWalker.u.pRewrite = &sRewrite; (void)sqlite3WalkExprList(&sWalker, pEList); *ppSub = sRewrite.pSub; } /* ** Append a copy of each expression in expression-list pAppend to ** expression list pList. Return a pointer to the result list. */ static ExprList *exprListAppendList( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ ExprList *pAppend, /* List of values to append. Might be NULL */ int bIntToNull ){ if( pAppend ){ int i; int nInit = pList ? pList->nExpr : 0; for(i=0; inExpr; i++){ sqlite3 *db = pParse->db; Expr *pDup = sqlite3ExprDup(db, pAppend->a[i].pExpr, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); break; } if( bIntToNull ){ int iDummy; Expr *pSub; pSub = sqlite3ExprSkipCollateAndLikely(pDup); if( sqlite3ExprIsInteger(pSub, &iDummy) ){ pSub->op = TK_NULL; pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse); pSub->u.zToken = 0; } } pList = sqlite3ExprListAppend(pParse, pList, pDup); if( pList ) pList->a[nInit+i].fg.sortFlags = pAppend->a[i].fg.sortFlags; } } return pList; } /* ** When rewriting a query, if the new subquery in the FROM clause ** contains TK_AGG_FUNCTION nodes that refer to an outer query, ** then we have to increase the Expr->op2 values of those nodes ** due to the extra subquery layer that was added. ** ** See also the incrAggDepth() routine in resolve.c */ static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION && pExpr->op2>=pWalker->walkerDepth ){ pExpr->op2++; } return WRC_Continue; } static int disallowAggregatesInOrderByCb(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION && pExpr->pAggInfo==0 ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3ErrorMsg(pWalker->pParse, "misuse of aggregate: %s()", pExpr->u.zToken); } return WRC_Continue; } /* ** If the SELECT statement passed as the second argument does not invoke ** any SQL window functions, this function is a no-op. Otherwise, it ** rewrites the SELECT statement so that window function xStep functions ** are invoked in the correct order as described under "SELECT REWRITING" ** at the top of this file. */ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ int rc = SQLITE_OK; if( p->pWin && p->pPrior==0 && ALWAYS((p->selFlags & SF_WinRewrite)==0) && ALWAYS(!IN_RENAME_OBJECT) ){ Vdbe *v = sqlite3GetVdbe(pParse); sqlite3 *db = pParse->db; Select *pSub = 0; /* The subquery */ SrcList *pSrc = p->pSrc; Expr *pWhere = p->pWhere; ExprList *pGroupBy = p->pGroupBy; Expr *pHaving = p->pHaving; ExprList *pSort = 0; ExprList *pSublist = 0; /* Expression list for sub-query */ Window *pMWin = p->pWin; /* Main window object */ Window *pWin; /* Window object iterator */ Table *pTab; Walker w; u32 selFlags = p->selFlags; pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ){ return sqlite3ErrorToParser(db, SQLITE_NOMEM); } sqlite3AggInfoPersistWalkerInit(&w, pParse); sqlite3WalkSelect(&w, p); if( (p->selFlags & SF_Aggregate)==0 ){ w.xExprCallback = disallowAggregatesInOrderByCb; w.xSelectCallback = 0; sqlite3WalkExprList(&w, p->pOrderBy); } p->pSrc = 0; p->pWhere = 0; p->pGroupBy = 0; p->pHaving = 0; p->selFlags &= ~SF_Aggregate; p->selFlags |= SF_WinRewrite; /* Create the ORDER BY clause for the sub-select. This is the concatenation ** of the window PARTITION and ORDER BY clauses. Then, if this makes it ** redundant, remove the ORDER BY from the parent SELECT. */ pSort = exprListAppendList(pParse, 0, pMWin->pPartition, 1); pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1); if( pSort && p->pOrderBy && p->pOrderBy->nExpr<=pSort->nExpr ){ int nSave = pSort->nExpr; pSort->nExpr = p->pOrderBy->nExpr; if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){ sqlite3ExprListDelete(db, p->pOrderBy); p->pOrderBy = 0; } pSort->nExpr = nSave; } /* Assign a cursor number for the ephemeral table used to buffer rows. ** The OpenEphemeral instruction is coded later, after it is known how ** many columns the table will have. */ pMWin->iEphCsr = pParse->nTab++; pParse->nTab += 3; selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, pTab, &pSublist); selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, pTab, &pSublist); pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0); /* Append the PARTITION BY and ORDER BY expressions to the to the ** sub-select expression list. They are required to figure out where ** boundaries for partitions and sets of peer rows lie. */ pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition, 0); pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy, 0); /* Append the arguments passed to each window function to the ** sub-select expression list. Also allocate two registers for each ** window function - one for the accumulator, another for interim ** results. */ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ ExprList *pArgs; assert( ExprUseXList(pWin->pOwner) ); assert( pWin->pWFunc!=0 ); pArgs = pWin->pOwner->x.pList; if( pWin->pWFunc->funcFlags & SQLITE_SUBTYPE ){ selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist); pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); pWin->bExprArgs = 1; }else{ pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); pSublist = exprListAppendList(pParse, pSublist, pArgs, 0); } if( pWin->pFilter ){ Expr *pFilter = sqlite3ExprDup(db, pWin->pFilter, 0); pSublist = sqlite3ExprListAppend(pParse, pSublist, pFilter); } pWin->regAccum = ++pParse->nMem; pWin->regResult = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); } /* If there is no ORDER BY or PARTITION BY clause, and the window ** function accepts zero arguments, and there are no other columns ** selected (e.g. "SELECT row_number() OVER () FROM t1"), it is possible ** that pSublist is still NULL here. Add a constant expression here to ** keep everything legal in this case. */ if( pSublist==0 ){ pSublist = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_INTEGER, "0") ); } pSub = sqlite3SelectNew( pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0 ); TREETRACE(0x40,pParse,pSub, ("New window-function subquery in FROM clause of (%u/%p)\n", p->selId, p)); p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside ** of sqlite3DbMallocRawNN() called from ** sqlite3SrcListAppend() */ if( p->pSrc ){ Table *pTab2; p->pSrc->a[0].pSelect = pSub; p->pSrc->a[0].fg.isCorrelated = 1; sqlite3SrcListAssignCursors(pParse, p->pSrc); pSub->selFlags |= SF_Expanded|SF_OrderByReqd; pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE); pSub->selFlags |= (selFlags & SF_Aggregate); if( pTab2==0 ){ /* Might actually be some other kind of error, but in that case ** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get ** the correct error message regardless. */ rc = SQLITE_NOMEM; }else{ memcpy(pTab, pTab2, sizeof(Table)); pTab->tabFlags |= TF_Ephemeral; p->pSrc->a[0].pTab = pTab; pTab = pTab2; memset(&w, 0, sizeof(w)); w.xExprCallback = sqlite3WindowExtraAggFuncDepth; w.xSelectCallback = sqlite3WalkerDepthIncrease; w.xSelectCallback2 = sqlite3WalkerDepthDecrease; sqlite3WalkSelect(&w, pSub); } }else{ sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; /* Defer deleting the temporary table pTab because if an error occurred, ** there could still be references to that table embedded in the ** result-set or ORDER BY clause of the SELECT statement p. */ sqlite3ParserAddCleanup(pParse, sqlite3DbFree, pTab); } assert( rc==SQLITE_OK || pParse->nErr!=0 ); return rc; } /* ** Unlink the Window object from the Select to which it is attached, ** if it is attached. */ SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window *p){ if( p->ppThis ){ *p->ppThis = p->pNextWin; if( p->pNextWin ) p->pNextWin->ppThis = p->ppThis; p->ppThis = 0; } } /* ** Free the Window object passed as the second argument. */ SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3 *db, Window *p){ if( p ){ sqlite3WindowUnlinkFromSelect(p); sqlite3ExprDelete(db, p->pFilter); sqlite3ExprListDelete(db, p->pPartition); sqlite3ExprListDelete(db, p->pOrderBy); sqlite3ExprDelete(db, p->pEnd); sqlite3ExprDelete(db, p->pStart); sqlite3DbFree(db, p->zName); sqlite3DbFree(db, p->zBase); sqlite3DbFree(db, p); } } /* ** Free the linked list of Window objects starting at the second argument. */ SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p){ while( p ){ Window *pNext = p->pNextWin; sqlite3WindowDelete(db, p); p = pNext; } } /* ** The argument expression is an PRECEDING or FOLLOWING offset. The ** value should be a non-negative integer. If the value is not a ** constant, change it to NULL. The fact that it is then a non-negative ** integer will be caught later. But it is important not to leave ** variable values in the expression tree. */ static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ if( 0==sqlite3ExprIsConstant(pExpr) ){ if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr); sqlite3ExprDelete(pParse->db, pExpr); pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0); } return pExpr; } /* ** Allocate and return a new Window object describing a Window Definition. */ SQLITE_PRIVATE Window *sqlite3WindowAlloc( Parse *pParse, /* Parsing context */ int eType, /* Frame type. TK_RANGE, TK_ROWS, TK_GROUPS, or 0 */ int eStart, /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */ Expr *pStart, /* Start window size if TK_PRECEDING or FOLLOWING */ int eEnd, /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */ Expr *pEnd, /* End window size if TK_FOLLOWING or PRECEDING */ u8 eExclude /* EXCLUDE clause */ ){ Window *pWin = 0; int bImplicitFrame = 0; /* Parser assures the following: */ assert( eType==0 || eType==TK_RANGE || eType==TK_ROWS || eType==TK_GROUPS ); assert( eStart==TK_CURRENT || eStart==TK_PRECEDING || eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING ); assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING || eEnd==TK_UNBOUNDED || eEnd==TK_PRECEDING ); assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) ); assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) ); if( eType==0 ){ bImplicitFrame = 1; eType = TK_RANGE; } /* Additionally, the ** starting boundary type may not occur earlier in the following list than ** the ending boundary type: ** ** UNBOUNDED PRECEDING ** PRECEDING ** CURRENT ROW ** FOLLOWING ** UNBOUNDED FOLLOWING ** ** The parser ensures that "UNBOUNDED PRECEDING" cannot be used as an ending ** boundary, and than "UNBOUNDED FOLLOWING" cannot be used as a starting ** frame boundary. */ if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING) || (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT)) ){ sqlite3ErrorMsg(pParse, "unsupported frame specification"); goto windowAllocErr; } pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( pWin==0 ) goto windowAllocErr; pWin->eFrmType = eType; pWin->eStart = eStart; pWin->eEnd = eEnd; if( eExclude==0 && OptimizationDisabled(pParse->db, SQLITE_WindowFunc) ){ eExclude = TK_NO; } pWin->eExclude = eExclude; pWin->bImplicitFrame = bImplicitFrame; pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd); pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart); return pWin; windowAllocErr: sqlite3ExprDelete(pParse->db, pEnd); sqlite3ExprDelete(pParse->db, pStart); return 0; } /* ** Attach PARTITION and ORDER BY clauses pPartition and pOrderBy to window ** pWin. Also, if parameter pBase is not NULL, set pWin->zBase to the ** equivalent nul-terminated string. */ SQLITE_PRIVATE Window *sqlite3WindowAssemble( Parse *pParse, Window *pWin, ExprList *pPartition, ExprList *pOrderBy, Token *pBase ){ if( pWin ){ pWin->pPartition = pPartition; pWin->pOrderBy = pOrderBy; if( pBase ){ pWin->zBase = sqlite3DbStrNDup(pParse->db, pBase->z, pBase->n); } }else{ sqlite3ExprListDelete(pParse->db, pPartition); sqlite3ExprListDelete(pParse->db, pOrderBy); } return pWin; } /* ** Window *pWin has just been created from a WINDOW clause. Token pBase ** is the base window. Earlier windows from the same WINDOW clause are ** stored in the linked list starting at pWin->pNextWin. This function ** either updates *pWin according to the base specification, or else ** leaves an error in pParse. */ SQLITE_PRIVATE void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pList){ if( pWin->zBase ){ sqlite3 *db = pParse->db; Window *pExist = windowFind(pParse, pList, pWin->zBase); if( pExist ){ const char *zErr = 0; /* Check for errors */ if( pWin->pPartition ){ zErr = "PARTITION clause"; }else if( pExist->pOrderBy && pWin->pOrderBy ){ zErr = "ORDER BY clause"; }else if( pExist->bImplicitFrame==0 ){ zErr = "frame specification"; } if( zErr ){ sqlite3ErrorMsg(pParse, "cannot override %s of window: %s", zErr, pWin->zBase ); }else{ pWin->pPartition = sqlite3ExprListDup(db, pExist->pPartition, 0); if( pExist->pOrderBy ){ assert( pWin->pOrderBy==0 ); pWin->pOrderBy = sqlite3ExprListDup(db, pExist->pOrderBy, 0); } sqlite3DbFree(db, pWin->zBase); pWin->zBase = 0; } } } } /* ** Attach window object pWin to expression p. */ SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ if( p ){ assert( p->op==TK_FUNCTION ); assert( pWin ); assert( ExprIsFullSize(p) ); p->y.pWin = pWin; ExprSetProperty(p, EP_WinFunc|EP_FullSize); pWin->pOwner = p; if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){ sqlite3ErrorMsg(pParse, "DISTINCT is not supported for window functions" ); } }else{ sqlite3WindowDelete(pParse->db, pWin); } } /* ** Possibly link window pWin into the list at pSel->pWin (window functions ** to be processed as part of SELECT statement pSel). The window is linked ** in if either (a) there are no other windows already linked to this ** SELECT, or (b) the windows already linked use a compatible window frame. */ SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin){ if( pSel ){ if( 0==pSel->pWin || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0) ){ pWin->pNextWin = pSel->pWin; if( pSel->pWin ){ pSel->pWin->ppThis = &pWin->pNextWin; } pSel->pWin = pWin; pWin->ppThis = &pSel->pWin; }else{ if( sqlite3ExprListCompare(pWin->pPartition, pSel->pWin->pPartition,-1) ){ pSel->selFlags |= SF_MultiPart; } } } } /* ** Return 0 if the two window objects are identical, 1 if they are ** different, or 2 if it cannot be determined if the objects are identical ** or not. Identical window objects can be processed in a single scan. */ SQLITE_PRIVATE int sqlite3WindowCompare( const Parse *pParse, const Window *p1, const Window *p2, int bFilter ){ int res; if( NEVER(p1==0) || NEVER(p2==0) ) return 1; if( p1->eFrmType!=p2->eFrmType ) return 1; if( p1->eStart!=p2->eStart ) return 1; if( p1->eEnd!=p2->eEnd ) return 1; if( p1->eExclude!=p2->eExclude ) return 1; if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1; if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1; if( (res = sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1)) ){ return res; } if( (res = sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1)) ){ return res; } if( bFilter ){ if( (res = sqlite3ExprCompare(pParse, p1->pFilter, p2->pFilter, -1)) ){ return res; } } return 0; } /* ** This is called by code in select.c before it calls sqlite3WhereBegin() ** to begin iterating through the sub-query results. It is used to allocate ** and initialize registers and cursors used by sqlite3WindowCodeStep(). */ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){ int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr; Window *pMWin = pSelect->pWin; Window *pWin; Vdbe *v = sqlite3GetVdbe(pParse); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr); /* Allocate registers to use for PARTITION BY values, if any. Initialize ** said registers to NULL. */ if( pMWin->pPartition ){ int nExpr = pMWin->pPartition->nExpr; pMWin->regPart = pParse->nMem+1; pParse->nMem += nExpr; sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nExpr-1); } pMWin->regOne = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regOne); if( pMWin->eExclude ){ pMWin->regStartRowid = ++pParse->nMem; pMWin->regEndRowid = ++pParse->nMem; pMWin->csrApp = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid); sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->csrApp, pMWin->iEphCsr); return; } for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *p = pWin->pWFunc; if( (p->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){ /* The inline versions of min() and max() require a single ephemeral ** table and 3 registers. The registers are used as follows: ** ** regApp+0: slot to copy min()/max() argument to for MakeRecord ** regApp+1: integer value used to ensure keys are unique ** regApp+2: output of MakeRecord */ ExprList *pList; KeyInfo *pKeyInfo; assert( ExprUseXList(pWin->pOwner) ); pList = pWin->pOwner->x.pList; pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pList, 0, 0); pWin->csrApp = pParse->nTab++; pWin->regApp = pParse->nMem+1; pParse->nMem += 3; if( pKeyInfo && pWin->pWFunc->zName[1]=='i' ){ assert( pKeyInfo->aSortFlags[0]==0 ); pKeyInfo->aSortFlags[0] = KEYINFO_ORDER_DESC; } sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->csrApp, 2); sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); } else if( p->zName==nth_valueName || p->zName==first_valueName ){ /* Allocate two registers at pWin->regApp. These will be used to ** store the start and end index of the current frame. */ pWin->regApp = pParse->nMem+1; pWin->csrApp = pParse->nTab++; pParse->nMem += 2; sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); } else if( p->zName==leadName || p->zName==lagName ){ pWin->csrApp = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); } } } #define WINDOW_STARTING_INT 0 #define WINDOW_ENDING_INT 1 #define WINDOW_NTH_VALUE_INT 2 #define WINDOW_STARTING_NUM 3 #define WINDOW_ENDING_NUM 4 /* ** A "PRECEDING " (eCond==0) or "FOLLOWING " (eCond==1) or the ** value of the second argument to nth_value() (eCond==2) has just been ** evaluated and the result left in register reg. This function generates VM ** code to check that the value is a non-negative integer and throws an ** exception if it is not. */ static void windowCheckValue(Parse *pParse, int reg, int eCond){ static const char *azErr[] = { "frame starting offset must be a non-negative integer", "frame ending offset must be a non-negative integer", "second argument to nth_value must be a positive integer", "frame starting offset must be a non-negative number", "frame ending offset must be a non-negative number", }; static int aOp[] = { OP_Ge, OP_Ge, OP_Gt, OP_Ge, OP_Ge }; Vdbe *v = sqlite3GetVdbe(pParse); int regZero = sqlite3GetTempReg(pParse); assert( eCond>=0 && eCond=WINDOW_STARTING_NUM ){ int regString = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); sqlite3VdbeAddOp3(v, OP_Ge, regString, sqlite3VdbeCurrentAddr(v)+2, reg); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC|SQLITE_JUMPIFNULL); VdbeCoverage(v); assert( eCond==3 || eCond==4 ); VdbeCoverageIf(v, eCond==3); VdbeCoverageIf(v, eCond==4); }else{ sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); assert( eCond==0 || eCond==1 || eCond==2 ); VdbeCoverageIf(v, eCond==0); VdbeCoverageIf(v, eCond==1); VdbeCoverageIf(v, eCond==2); } sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC); VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */ VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */ VdbeCoverageNeverNullIf(v, eCond==2); VdbeCoverageNeverNullIf(v, eCond==3); /* NULL case caught by */ VdbeCoverageNeverNullIf(v, eCond==4); /* the OP_Ge */ sqlite3MayAbort(pParse); sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort); sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC); sqlite3ReleaseTempReg(pParse, regZero); } /* ** Return the number of arguments passed to the window-function associated ** with the object passed as the only argument to this function. */ static int windowArgCount(Window *pWin){ const ExprList *pList; assert( ExprUseXList(pWin->pOwner) ); pList = pWin->pOwner->x.pList; return (pList ? pList->nExpr : 0); } typedef struct WindowCodeArg WindowCodeArg; typedef struct WindowCsrAndReg WindowCsrAndReg; /* ** See comments above struct WindowCodeArg. */ struct WindowCsrAndReg { int csr; /* Cursor number */ int reg; /* First in array of peer values */ }; /* ** A single instance of this structure is allocated on the stack by ** sqlite3WindowCodeStep() and a pointer to it passed to the various helper ** routines. This is to reduce the number of arguments required by each ** helper function. ** ** regArg: ** Each window function requires an accumulator register (just as an ** ordinary aggregate function does). This variable is set to the first ** in an array of accumulator registers - one for each window function ** in the WindowCodeArg.pMWin list. ** ** eDelete: ** The window functions implementation sometimes caches the input rows ** that it processes in a temporary table. If it is not zero, this ** variable indicates when rows may be removed from the temp table (in ** order to reduce memory requirements - it would always be safe just ** to leave them there). Possible values for eDelete are: ** ** WINDOW_RETURN_ROW: ** An input row can be discarded after it is returned to the caller. ** ** WINDOW_AGGINVERSE: ** An input row can be discarded after the window functions xInverse() ** callbacks have been invoked in it. ** ** WINDOW_AGGSTEP: ** An input row can be discarded after the window functions xStep() ** callbacks have been invoked in it. ** ** start,current,end ** Consider a window-frame similar to the following: ** ** (ORDER BY a, b GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING) ** ** The windows functions implementation caches the input rows in a temp ** table, sorted by "a, b" (it actually populates the cache lazily, and ** aggressively removes rows once they are no longer required, but that's ** a mere detail). It keeps three cursors open on the temp table. One ** (current) that points to the next row to return to the query engine ** once its window function values have been calculated. Another (end) ** points to the next row to call the xStep() method of each window function ** on (so that it is 2 groups ahead of current). And a third (start) that ** points to the next row to call the xInverse() method of each window ** function on. ** ** Each cursor (start, current and end) consists of a VDBE cursor ** (WindowCsrAndReg.csr) and an array of registers (starting at ** WindowCodeArg.reg) that always contains a copy of the peer values ** read from the corresponding cursor. ** ** Depending on the window-frame in question, all three cursors may not ** be required. In this case both WindowCodeArg.csr and reg are set to ** 0. */ struct WindowCodeArg { Parse *pParse; /* Parse context */ Window *pMWin; /* First in list of functions being processed */ Vdbe *pVdbe; /* VDBE object */ int addrGosub; /* OP_Gosub to this address to return one row */ int regGosub; /* Register used with OP_Gosub(addrGosub) */ int regArg; /* First in array of accumulator registers */ int eDelete; /* See above */ int regRowid; WindowCsrAndReg start; WindowCsrAndReg current; WindowCsrAndReg end; }; /* ** Generate VM code to read the window frames peer values from cursor csr into ** an array of registers starting at reg. */ static void windowReadPeerValues( WindowCodeArg *p, int csr, int reg ){ Window *pMWin = p->pMWin; ExprList *pOrderBy = pMWin->pOrderBy; if( pOrderBy ){ Vdbe *v = sqlite3GetVdbe(p->pParse); ExprList *pPart = pMWin->pPartition; int iColOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0); int i; for(i=0; inExpr; i++){ sqlite3VdbeAddOp3(v, OP_Column, csr, iColOff+i, reg+i); } } } /* ** Generate VM code to invoke either xStep() (if bInverse is 0) or ** xInverse (if bInverse is non-zero) for each window function in the ** linked list starting at pMWin. Or, for built-in window functions ** that do not use the standard function API, generate the required ** inline VM code. ** ** If argument csr is greater than or equal to 0, then argument reg is ** the first register in an array of registers guaranteed to be large ** enough to hold the array of arguments for each function. In this case ** the arguments are extracted from the current row of csr into the ** array of registers before invoking OP_AggStep or OP_AggInverse ** ** Or, if csr is less than zero, then the array of registers at reg is ** already populated with all columns from the current row of the sub-query. ** ** If argument regPartSize is non-zero, then it is a register containing the ** number of rows in the current partition. */ static void windowAggStep( WindowCodeArg *p, Window *pMWin, /* Linked list of window functions */ int csr, /* Read arguments from this cursor */ int bInverse, /* True to invoke xInverse instead of xStep */ int reg /* Array of registers */ ){ Parse *pParse = p->pParse; Vdbe *v = sqlite3GetVdbe(pParse); Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pWFunc; int regArg; int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin); int i; assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED ); /* All OVER clauses in the same window function aggregate step must ** be the same. */ assert( pWin==pMWin || sqlite3WindowCompare(pParse,pWin,pMWin,0)!=1 ); for(i=0; izName!=nth_valueName ){ sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i); }else{ sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i); } } regArg = reg; if( pMWin->regStartRowid==0 && (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && (pWin->eStart!=TK_UNBOUNDED) ){ int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg); VdbeCoverage(v); if( bInverse==0 ){ sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1, 1); sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp); sqlite3VdbeAddOp3(v, OP_MakeRecord, pWin->regApp, 2, pWin->regApp+2); sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2); }else{ sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1); VdbeCoverageNeverTaken(v); sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); } sqlite3VdbeJumpHere(v, addrIsNull); }else if( pWin->regApp ){ assert( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ); assert( bInverse==0 || bInverse==1 ); sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); }else if( pFunc->xSFunc!=noopStepFunc ){ int addrIf = 0; if( pWin->pFilter ){ int regTmp; assert( ExprUseXList(pWin->pOwner) ); assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr ); assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 ); regTmp = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, regTmp); } if( pWin->bExprArgs ){ int iOp = sqlite3VdbeCurrentAddr(v); int iEnd; assert( ExprUseXList(pWin->pOwner) ); nArg = pWin->pOwner->x.pList->nExpr; regArg = sqlite3GetTempRange(pParse, nArg); sqlite3ExprCodeExprList(pParse, pWin->pOwner->x.pList, regArg, 0, 0); for(iEnd=sqlite3VdbeCurrentAddr(v); iOpopcode==OP_Column && pOp->p1==pMWin->iEphCsr ){ pOp->p1 = csr; } } } if( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl; assert( nArg>0 ); assert( ExprUseXList(pWin->pOwner) ); pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr); sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ); } sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep, bInverse, regArg, pWin->regAccum); sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); if( pWin->bExprArgs ){ sqlite3ReleaseTempRange(pParse, regArg, nArg); } if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } } } /* ** Values that may be passed as the second argument to windowCodeOp(). */ #define WINDOW_RETURN_ROW 1 #define WINDOW_AGGINVERSE 2 #define WINDOW_AGGSTEP 3 /* ** Generate VM code to invoke either xValue() (bFin==0) or xFinalize() ** (bFin==1) for each window function in the linked list starting at ** pMWin. Or, for built-in window-functions that do not use the standard ** API, generate the equivalent VM code. */ static void windowAggFinal(WindowCodeArg *p, int bFin){ Parse *pParse = p->pParse; Window *pMWin = p->pMWin; Vdbe *v = sqlite3GetVdbe(pParse); Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ if( pMWin->regStartRowid==0 && (pWin->pWFunc->funcFlags & SQLITE_FUNC_MINMAX) && (pWin->eStart!=TK_UNBOUNDED) ){ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); sqlite3VdbeAddOp1(v, OP_Last, pWin->csrApp); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, pWin->csrApp, 0, pWin->regResult); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); }else if( pWin->regApp ){ assert( pMWin->regStartRowid==0 ); }else{ int nArg = windowArgCount(pWin); if( bFin ){ sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, nArg); sqlite3VdbeAppendP4(v, pWin->pWFunc, P4_FUNCDEF); sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); }else{ sqlite3VdbeAddOp3(v, OP_AggValue,pWin->regAccum,nArg,pWin->regResult); sqlite3VdbeAppendP4(v, pWin->pWFunc, P4_FUNCDEF); } } } } /* ** Generate code to calculate the current values of all window functions in the ** p->pMWin list by doing a full scan of the current window frame. Store the ** results in the Window.regResult registers, ready to return the upper ** layer. */ static void windowFullScan(WindowCodeArg *p){ Window *pWin; Parse *pParse = p->pParse; Window *pMWin = p->pMWin; Vdbe *v = p->pVdbe; int regCRowid = 0; /* Current rowid value */ int regCPeer = 0; /* Current peer values */ int regRowid = 0; /* AggStep rowid value */ int regPeer = 0; /* AggStep peer values */ int nPeer; int lblNext; int lblBrk; int addrNext; int csr; VdbeModuleComment((v, "windowFullScan begin")); assert( pMWin!=0 ); csr = pMWin->csrApp; nPeer = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); lblNext = sqlite3VdbeMakeLabel(pParse); lblBrk = sqlite3VdbeMakeLabel(pParse); regCRowid = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); if( nPeer ){ regCPeer = sqlite3GetTempRange(pParse, nPeer); regPeer = sqlite3GetTempRange(pParse, nPeer); } sqlite3VdbeAddOp2(v, OP_Rowid, pMWin->iEphCsr, regCRowid); windowReadPeerValues(p, pMWin->iEphCsr, regCPeer); for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); } sqlite3VdbeAddOp3(v, OP_SeekGE, csr, lblBrk, pMWin->regStartRowid); VdbeCoverage(v); addrNext = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Rowid, csr, regRowid); sqlite3VdbeAddOp3(v, OP_Gt, pMWin->regEndRowid, lblBrk, regRowid); VdbeCoverageNeverNull(v); if( pMWin->eExclude==TK_CURRENT ){ sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, lblNext, regRowid); VdbeCoverageNeverNull(v); }else if( pMWin->eExclude!=TK_NO ){ int addr; int addrEq = 0; KeyInfo *pKeyInfo = 0; if( pMWin->pOrderBy ){ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pMWin->pOrderBy, 0, 0); } if( pMWin->eExclude==TK_TIES ){ addrEq = sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, 0, regRowid); VdbeCoverageNeverNull(v); } if( pKeyInfo ){ windowReadPeerValues(p, csr, regPeer); sqlite3VdbeAddOp3(v, OP_Compare, regPeer, regCPeer, nPeer); sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); addr = sqlite3VdbeCurrentAddr(v)+1; sqlite3VdbeAddOp3(v, OP_Jump, addr, lblNext, addr); VdbeCoverageEqNe(v); }else{ sqlite3VdbeAddOp2(v, OP_Goto, 0, lblNext); } if( addrEq ) sqlite3VdbeJumpHere(v, addrEq); } windowAggStep(p, pMWin, csr, 0, p->regArg); sqlite3VdbeResolveLabel(v, lblNext); sqlite3VdbeAddOp2(v, OP_Next, csr, addrNext); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrNext-1); sqlite3VdbeJumpHere(v, addrNext+1); sqlite3ReleaseTempReg(pParse, regRowid); sqlite3ReleaseTempReg(pParse, regCRowid); if( nPeer ){ sqlite3ReleaseTempRange(pParse, regPeer, nPeer); sqlite3ReleaseTempRange(pParse, regCPeer, nPeer); } windowAggFinal(p, 1); VdbeModuleComment((v, "windowFullScan end")); } /* ** Invoke the sub-routine at regGosub (generated by code in select.c) to ** return the current row of Window.iEphCsr. If all window functions are ** aggregate window functions that use the standard API, a single ** OP_Gosub instruction is all that this routine generates. Extra VM code ** for per-row processing is only generated for the following built-in window ** functions: ** ** nth_value() ** first_value() ** lag() ** lead() */ static void windowReturnOneRow(WindowCodeArg *p){ Window *pMWin = p->pMWin; Vdbe *v = p->pVdbe; if( pMWin->regStartRowid ){ windowFullScan(p); }else{ Parse *pParse = p->pParse; Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pWFunc; assert( ExprUseXList(pWin->pOwner) ); if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){ int csr = pWin->csrApp; int lbl = sqlite3VdbeMakeLabel(pParse); int tmpReg = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); if( pFunc->zName==nth_valueName ){ sqlite3VdbeAddOp3(v, OP_Column,pMWin->iEphCsr,pWin->iArgCol+1,tmpReg); windowCheckValue(pParse, tmpReg, 2); }else{ sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); } sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg); sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg); VdbeCoverageNeverNull(v); sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg); VdbeCoverageNeverTaken(v); sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); sqlite3VdbeResolveLabel(v, lbl); sqlite3ReleaseTempReg(pParse, tmpReg); } else if( pFunc->zName==leadName || pFunc->zName==lagName ){ int nArg = pWin->pOwner->x.pList->nExpr; int csr = pWin->csrApp; int lbl = sqlite3VdbeMakeLabel(pParse); int tmpReg = sqlite3GetTempReg(pParse); int iEph = pMWin->iEphCsr; if( nArg<3 ){ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); }else{ sqlite3VdbeAddOp3(v, OP_Column, iEph,pWin->iArgCol+2,pWin->regResult); } sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg); if( nArg<2 ){ int val = (pFunc->zName==leadName ? 1 : -1); sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val); }else{ int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract); int tmpReg2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2); sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg); sqlite3ReleaseTempReg(pParse, tmpReg2); } sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); sqlite3VdbeResolveLabel(v, lbl); sqlite3ReleaseTempReg(pParse, tmpReg); } } } sqlite3VdbeAddOp2(v, OP_Gosub, p->regGosub, p->addrGosub); } /* ** Generate code to set the accumulator register for each window function ** in the linked list passed as the second argument to NULL. And perform ** any equivalent initialization required by any built-in window functions ** in the list. */ static int windowInitAccum(Parse *pParse, Window *pMWin){ Vdbe *v = sqlite3GetVdbe(pParse); int regArg; int nArg = 0; Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pWFunc; assert( pWin->regAccum ); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); nArg = MAX(nArg, windowArgCount(pWin)); if( pMWin->regStartRowid==0 ){ if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){ sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp); sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); } if( (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->csrApp ){ assert( pWin->eStart!=TK_UNBOUNDED ); sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); } } } regArg = pParse->nMem+1; pParse->nMem += nArg; return regArg; } /* ** Return true if the current frame should be cached in the ephemeral table, ** even if there are no xInverse() calls required. */ static int windowCacheFrame(Window *pMWin){ Window *pWin; if( pMWin->regStartRowid ) return 1; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pWFunc; if( (pFunc->zName==nth_valueName) || (pFunc->zName==first_valueName) || (pFunc->zName==leadName) || (pFunc->zName==lagName) ){ return 1; } } return 0; } /* ** regOld and regNew are each the first register in an array of size ** pOrderBy->nExpr. This function generates code to compare the two ** arrays of registers using the collation sequences and other comparison ** parameters specified by pOrderBy. ** ** If the two arrays are not equal, the contents of regNew is copied to ** regOld and control falls through. Otherwise, if the contents of the arrays ** are equal, an OP_Goto is executed. The address of the OP_Goto is returned. */ static void windowIfNewPeer( Parse *pParse, ExprList *pOrderBy, int regNew, /* First in array of new values */ int regOld, /* First in array of old values */ int addr /* Jump here */ ){ Vdbe *v = sqlite3GetVdbe(pParse); if( pOrderBy ){ int nVal = pOrderBy->nExpr; KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); sqlite3VdbeAddOp3(v, OP_Compare, regOld, regNew, nVal); sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); sqlite3VdbeAddOp3(v, OP_Jump, sqlite3VdbeCurrentAddr(v)+1, addr, sqlite3VdbeCurrentAddr(v)+1 ); VdbeCoverageEqNe(v); sqlite3VdbeAddOp3(v, OP_Copy, regNew, regOld, nVal-1); }else{ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); } } /* ** This function is called as part of generating VM programs for RANGE ** offset PRECEDING/FOLLOWING frame boundaries. Assuming "ASC" order for ** the ORDER BY term in the window, and that argument op is OP_Ge, it generates ** code equivalent to: ** ** if( csr1.peerVal + regVal >= csr2.peerVal ) goto lbl; ** ** The value of parameter op may also be OP_Gt or OP_Le. In these cases the ** operator in the above pseudo-code is replaced with ">" or "<=", respectively. ** ** If the sort-order for the ORDER BY term in the window is DESC, then the ** comparison is reversed. Instead of adding regVal to csr1.peerVal, it is ** subtracted. And the comparison operator is inverted to - ">=" becomes "<=", ** ">" becomes "<", and so on. So, with DESC sort order, if the argument op ** is OP_Ge, the generated code is equivalent to: ** ** if( csr1.peerVal - regVal <= csr2.peerVal ) goto lbl; ** ** A special type of arithmetic is used such that if csr1.peerVal is not ** a numeric type (real or integer), then the result of the addition ** or subtraction is a a copy of csr1.peerVal. */ static void windowCodeRangeTest( WindowCodeArg *p, int op, /* OP_Ge, OP_Gt, or OP_Le */ int csr1, /* Cursor number for cursor 1 */ int regVal, /* Register containing non-negative number */ int csr2, /* Cursor number for cursor 2 */ int lbl /* Jump destination if condition is true */ ){ Parse *pParse = p->pParse; Vdbe *v = sqlite3GetVdbe(pParse); ExprList *pOrderBy = p->pMWin->pOrderBy; /* ORDER BY clause for window */ int reg1 = sqlite3GetTempReg(pParse); /* Reg. for csr1.peerVal+regVal */ int reg2 = sqlite3GetTempReg(pParse); /* Reg. for csr2.peerVal */ int regString = ++pParse->nMem; /* Reg. for constant value '' */ int arith = OP_Add; /* OP_Add or OP_Subtract */ int addrGe; /* Jump destination */ int addrDone = sqlite3VdbeMakeLabel(pParse); /* Address past OP_Ge */ CollSeq *pColl; /* Read the peer-value from each cursor into a register */ windowReadPeerValues(p, csr1, reg1); windowReadPeerValues(p, csr2, reg2); assert( op==OP_Ge || op==OP_Gt || op==OP_Le ); assert( pOrderBy && pOrderBy->nExpr==1 ); if( pOrderBy->a[0].fg.sortFlags & KEYINFO_ORDER_DESC ){ switch( op ){ case OP_Ge: op = OP_Le; break; case OP_Gt: op = OP_Lt; break; default: assert( op==OP_Le ); op = OP_Ge; break; } arith = OP_Subtract; } VdbeModuleComment((v, "CodeRangeTest: if( R%d %s R%d %s R%d ) goto lbl", reg1, (arith==OP_Add ? "+" : "-"), regVal, ((op==OP_Ge) ? ">=" : (op==OP_Le) ? "<=" : (op==OP_Gt) ? ">" : "<"), reg2 )); /* If the BIGNULL flag is set for the ORDER BY, then it is required to ** consider NULL values to be larger than all other values, instead of ** the usual smaller. The VDBE opcodes OP_Ge and so on do not handle this ** (and adding that capability causes a performance regression), so ** instead if the BIGNULL flag is set then cases where either reg1 or ** reg2 are NULL are handled separately in the following block. The code ** generated is equivalent to: ** ** if( reg1 IS NULL ){ ** if( op==OP_Ge ) goto lbl; ** if( op==OP_Gt && reg2 IS NOT NULL ) goto lbl; ** if( op==OP_Le && reg2 IS NULL ) goto lbl; ** }else if( reg2 IS NULL ){ ** if( op==OP_Le ) goto lbl; ** } ** ** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is ** not taken, control jumps over the comparison operator coded below this ** block. */ if( pOrderBy->a[0].fg.sortFlags & KEYINFO_ORDER_BIGNULL ){ /* This block runs if reg1 contains a NULL. */ int addr = sqlite3VdbeAddOp1(v, OP_NotNull, reg1); VdbeCoverage(v); switch( op ){ case OP_Ge: sqlite3VdbeAddOp2(v, OP_Goto, 0, lbl); break; case OP_Gt: sqlite3VdbeAddOp2(v, OP_NotNull, reg2, lbl); VdbeCoverage(v); break; case OP_Le: sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v); break; default: assert( op==OP_Lt ); /* no-op */ break; } sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone); /* This block runs if reg1 is not NULL, but reg2 is. */ sqlite3VdbeJumpHere(v, addr); sqlite3VdbeAddOp2(v, OP_IsNull, reg2, (op==OP_Gt || op==OP_Ge) ? addrDone : lbl); VdbeCoverage(v); } /* Register reg1 currently contains csr1.peerVal (the peer-value from csr1). ** This block adds (or subtracts for DESC) the numeric value in regVal ** from it. Or, if reg1 is not numeric (it is a NULL, a text value or a blob), ** then leave reg1 as it is. In pseudo-code, this is implemented as: ** ** if( reg1>='' ) goto addrGe; ** reg1 = reg1 +/- regVal ** addrGe: ** ** Since all strings and blobs are greater-than-or-equal-to an empty string, ** the add/subtract is skipped for these, as required. If reg1 is a NULL, ** then the arithmetic is performed, but since adding or subtracting from ** NULL is always NULL anyway, this case is handled as required too. */ sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1); VdbeCoverage(v); if( (op==OP_Ge && arith==OP_Add) || (op==OP_Le && arith==OP_Subtract) ){ sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1); sqlite3VdbeJumpHere(v, addrGe); /* Compare registers reg2 and reg1, taking the jump if required. Note that ** control skips over this test if the BIGNULL flag is set and either ** reg1 or reg2 contain a NULL value. */ sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); pColl = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[0].pExpr); sqlite3VdbeAppendP4(v, (void*)pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); sqlite3VdbeResolveLabel(v, addrDone); assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le ); testcase(op==OP_Ge); VdbeCoverageIf(v, op==OP_Ge); testcase(op==OP_Lt); VdbeCoverageIf(v, op==OP_Lt); testcase(op==OP_Le); VdbeCoverageIf(v, op==OP_Le); testcase(op==OP_Gt); VdbeCoverageIf(v, op==OP_Gt); sqlite3ReleaseTempReg(pParse, reg1); sqlite3ReleaseTempReg(pParse, reg2); VdbeModuleComment((v, "CodeRangeTest: end")); } /* ** Helper function for sqlite3WindowCodeStep(). Each call to this function ** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE ** operation. Refer to the header comment for sqlite3WindowCodeStep() for ** details. */ static int windowCodeOp( WindowCodeArg *p, /* Context object */ int op, /* WINDOW_RETURN_ROW, AGGSTEP or AGGINVERSE */ int regCountdown, /* Register for OP_IfPos countdown */ int jumpOnEof /* Jump here if stepped cursor reaches EOF */ ){ int csr, reg; Parse *pParse = p->pParse; Window *pMWin = p->pMWin; int ret = 0; Vdbe *v = p->pVdbe; int addrContinue = 0; int bPeer = (pMWin->eFrmType!=TK_ROWS); int lblDone = sqlite3VdbeMakeLabel(pParse); int addrNextRange = 0; /* Special case - WINDOW_AGGINVERSE is always a no-op if the frame ** starts with UNBOUNDED PRECEDING. */ if( op==WINDOW_AGGINVERSE && pMWin->eStart==TK_UNBOUNDED ){ assert( regCountdown==0 && jumpOnEof==0 ); return 0; } if( regCountdown>0 ){ if( pMWin->eFrmType==TK_RANGE ){ addrNextRange = sqlite3VdbeCurrentAddr(v); assert( op==WINDOW_AGGINVERSE || op==WINDOW_AGGSTEP ); if( op==WINDOW_AGGINVERSE ){ if( pMWin->eStart==TK_FOLLOWING ){ windowCodeRangeTest( p, OP_Le, p->current.csr, regCountdown, p->start.csr, lblDone ); }else{ windowCodeRangeTest( p, OP_Ge, p->start.csr, regCountdown, p->current.csr, lblDone ); } }else{ windowCodeRangeTest( p, OP_Gt, p->end.csr, regCountdown, p->current.csr, lblDone ); } }else{ sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, lblDone, 1); VdbeCoverage(v); } } if( op==WINDOW_RETURN_ROW && pMWin->regStartRowid==0 ){ windowAggFinal(p, 0); } addrContinue = sqlite3VdbeCurrentAddr(v); /* If this is a (RANGE BETWEEN a FOLLOWING AND b FOLLOWING) or ** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the ** start cursor does not advance past the end cursor within the ** temporary table. It otherwise might, if (a>b). Also ensure that, ** if the input cursor is still finding new rows, that the end ** cursor does not go past it to EOF. */ if( pMWin->eStart==pMWin->eEnd && regCountdown && pMWin->eFrmType==TK_RANGE ){ int regRowid1 = sqlite3GetTempReg(pParse); int regRowid2 = sqlite3GetTempReg(pParse); if( op==WINDOW_AGGINVERSE ){ sqlite3VdbeAddOp2(v, OP_Rowid, p->start.csr, regRowid1); sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid2); sqlite3VdbeAddOp3(v, OP_Ge, regRowid2, lblDone, regRowid1); VdbeCoverage(v); }else if( p->regRowid ){ sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid1); sqlite3VdbeAddOp3(v, OP_Ge, p->regRowid, lblDone, regRowid1); VdbeCoverageNeverNull(v); } sqlite3ReleaseTempReg(pParse, regRowid1); sqlite3ReleaseTempReg(pParse, regRowid2); assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ); } switch( op ){ case WINDOW_RETURN_ROW: csr = p->current.csr; reg = p->current.reg; windowReturnOneRow(p); break; case WINDOW_AGGINVERSE: csr = p->start.csr; reg = p->start.reg; if( pMWin->regStartRowid ){ assert( pMWin->regEndRowid ); sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regStartRowid, 1); }else{ windowAggStep(p, pMWin, csr, 1, p->regArg); } break; default: assert( op==WINDOW_AGGSTEP ); csr = p->end.csr; reg = p->end.reg; if( pMWin->regStartRowid ){ assert( pMWin->regEndRowid ); sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regEndRowid, 1); }else{ windowAggStep(p, pMWin, csr, 0, p->regArg); } break; } if( op==p->eDelete ){ sqlite3VdbeAddOp1(v, OP_Delete, csr); sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); } if( jumpOnEof ){ sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); ret = sqlite3VdbeAddOp0(v, OP_Goto); }else{ sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+1+bPeer); VdbeCoverage(v); if( bPeer ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, lblDone); } } if( bPeer ){ int nReg = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); int regTmp = (nReg ? sqlite3GetTempRange(pParse, nReg) : 0); windowReadPeerValues(p, csr, regTmp); windowIfNewPeer(pParse, pMWin->pOrderBy, regTmp, reg, addrContinue); sqlite3ReleaseTempRange(pParse, regTmp, nReg); } if( addrNextRange ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNextRange); } sqlite3VdbeResolveLabel(v, lblDone); return ret; } /* ** Allocate and return a duplicate of the Window object indicated by the ** third argument. Set the Window.pOwner field of the new object to ** pOwner. */ SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){ Window *pNew = 0; if( ALWAYS(p) ){ pNew = sqlite3DbMallocZero(db, sizeof(Window)); if( pNew ){ pNew->zName = sqlite3DbStrDup(db, p->zName); pNew->zBase = sqlite3DbStrDup(db, p->zBase); pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0); pNew->pWFunc = p->pWFunc; pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0); pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0); pNew->eFrmType = p->eFrmType; pNew->eEnd = p->eEnd; pNew->eStart = p->eStart; pNew->eExclude = p->eExclude; pNew->regResult = p->regResult; pNew->regAccum = p->regAccum; pNew->iArgCol = p->iArgCol; pNew->iEphCsr = p->iEphCsr; pNew->bExprArgs = p->bExprArgs; pNew->pStart = sqlite3ExprDup(db, p->pStart, 0); pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0); pNew->pOwner = pOwner; pNew->bImplicitFrame = p->bImplicitFrame; } } return pNew; } /* ** Return a copy of the linked list of Window objects passed as the ** second argument. */ SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p){ Window *pWin; Window *pRet = 0; Window **pp = &pRet; for(pWin=p; pWin; pWin=pWin->pNextWin){ *pp = sqlite3WindowDup(db, 0, pWin); if( *pp==0 ) break; pp = &((*pp)->pNextWin); } return pRet; } /* ** Return true if it can be determined at compile time that expression ** pExpr evaluates to a value that, when cast to an integer, is greater ** than zero. False otherwise. ** ** If an OOM error occurs, this function sets the Parse.db.mallocFailed ** flag and returns zero. */ static int windowExprGtZero(Parse *pParse, Expr *pExpr){ int ret = 0; sqlite3 *db = pParse->db; sqlite3_value *pVal = 0; sqlite3ValueFromExpr(db, pExpr, db->enc, SQLITE_AFF_NUMERIC, &pVal); if( pVal && sqlite3_value_int(pVal)>0 ){ ret = 1; } sqlite3ValueFree(pVal); return ret; } /* ** sqlite3WhereBegin() has already been called for the SELECT statement ** passed as the second argument when this function is invoked. It generates ** code to populate the Window.regResult register for each window function ** and invoke the sub-routine at instruction addrGosub once for each row. ** sqlite3WhereEnd() is always called before returning. ** ** This function handles several different types of window frames, which ** require slightly different processing. The following pseudo code is ** used to implement window frames of the form: ** ** ROWS BETWEEN PRECEDING AND FOLLOWING ** ** Other window frame types use variants of the following: ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** ** if( first row of partition ){ ** // Rewind three cursors, all open on the eph table. ** Rewind(csrEnd); ** Rewind(csrStart); ** Rewind(csrCurrent); ** ** regEnd = // FOLLOWING expression ** regStart = // PRECEDING expression ** }else{ ** // First time this branch is taken, the eph table contains two ** // rows. The first row in the partition, which all three cursors ** // currently point to, and the following row. ** AGGSTEP ** if( (regEnd--)<=0 ){ ** RETURN_ROW ** if( (regStart--)<=0 ){ ** AGGINVERSE ** } ** } ** } ** } ** flush: ** AGGSTEP ** while( 1 ){ ** RETURN ROW ** if( csrCurrent is EOF ) break; ** if( (regStart--)<=0 ){ ** AggInverse(csrStart) ** Next(csrStart) ** } ** } ** ** The pseudo-code above uses the following shorthand: ** ** AGGSTEP: invoke the aggregate xStep() function for each window function ** with arguments read from the current row of cursor csrEnd, then ** step cursor csrEnd forward one row (i.e. sqlite3BtreeNext()). ** ** RETURN_ROW: return a row to the caller based on the contents of the ** current row of csrCurrent and the current state of all ** aggregates. Then step cursor csrCurrent forward one row. ** ** AGGINVERSE: invoke the aggregate xInverse() function for each window ** functions with arguments read from the current row of cursor ** csrStart. Then step csrStart forward one row. ** ** There are two other ROWS window frames that are handled significantly ** differently from the above - "BETWEEN PRECEDING AND PRECEDING" ** and "BETWEEN FOLLOWING AND FOLLOWING". These are special ** cases because they change the order in which the three cursors (csrStart, ** csrCurrent and csrEnd) iterate through the ephemeral table. Cases that ** use UNBOUNDED or CURRENT ROW are much simpler variations on one of these ** three. ** ** ROWS BETWEEN PRECEDING AND PRECEDING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = ** regStart = ** }else{ ** if( (regEnd--)<=0 ){ ** AGGSTEP ** } ** RETURN_ROW ** if( (regStart--)<=0 ){ ** AGGINVERSE ** } ** } ** } ** flush: ** if( (regEnd--)<=0 ){ ** AGGSTEP ** } ** RETURN_ROW ** ** ** ROWS BETWEEN FOLLOWING AND FOLLOWING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = ** regStart = regEnd - ** }else{ ** AGGSTEP ** if( (regEnd--)<=0 ){ ** RETURN_ROW ** } ** if( (regStart--)<=0 ){ ** AGGINVERSE ** } ** } ** } ** flush: ** AGGSTEP ** while( 1 ){ ** if( (regEnd--)<=0 ){ ** RETURN_ROW ** if( eof ) break; ** } ** if( (regStart--)<=0 ){ ** AGGINVERSE ** if( eof ) break ** } ** } ** while( !eof csrCurrent ){ ** RETURN_ROW ** } ** ** For the most part, the patterns above are adapted to support UNBOUNDED by ** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and ** CURRENT ROW by assuming that it is equivalent to "0 PRECEDING/FOLLOWING". ** This is optimized of course - branches that will never be taken and ** conditions that are always true are omitted from the VM code. The only ** exceptional case is: ** ** ROWS BETWEEN FOLLOWING AND UNBOUNDED FOLLOWING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regStart = ** }else{ ** AGGSTEP ** } ** } ** flush: ** AGGSTEP ** while( 1 ){ ** if( (regStart--)<=0 ){ ** AGGINVERSE ** if( eof ) break ** } ** RETURN_ROW ** } ** while( !eof csrCurrent ){ ** RETURN_ROW ** } ** ** Also requiring special handling are the cases: ** ** ROWS BETWEEN PRECEDING AND PRECEDING ** ROWS BETWEEN FOLLOWING AND FOLLOWING ** ** when (expr1 < expr2). This is detected at runtime, not by this function. ** To handle this case, the pseudo-code programs depicted above are modified ** slightly to be: ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = ** regStart = ** if( regEnd < regStart ){ ** RETURN_ROW ** delete eph table contents ** continue ** } ** ... ** ** The new "continue" statement in the above jumps to the next iteration ** of the outer loop - the one started by sqlite3WhereBegin(). ** ** The various GROUPS cases are implemented using the same patterns as ** ROWS. The VM code is modified slightly so that: ** ** 1. The else branch in the main loop is only taken if the row just ** added to the ephemeral table is the start of a new group. In ** other words, it becomes: ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = ** regStart = ** }else if( new group ){ ** ... ** } ** } ** ** 2. Instead of processing a single row, each RETURN_ROW, AGGSTEP or ** AGGINVERSE step processes the current row of the relevant cursor and ** all subsequent rows belonging to the same group. ** ** RANGE window frames are a little different again. As for GROUPS, the ** main loop runs once per group only. And RETURN_ROW, AGGSTEP and AGGINVERSE ** deal in groups instead of rows. As for ROWS and GROUPS, there are three ** basic cases: ** ** RANGE BETWEEN PRECEDING AND FOLLOWING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = ** regStart = ** }else{ ** AGGSTEP ** while( (csrCurrent.key + regEnd) < csrEnd.key ){ ** RETURN_ROW ** while( csrStart.key + regStart) < csrCurrent.key ){ ** AGGINVERSE ** } ** } ** } ** } ** flush: ** AGGSTEP ** while( 1 ){ ** RETURN ROW ** if( csrCurrent is EOF ) break; ** while( csrStart.key + regStart) < csrCurrent.key ){ ** AGGINVERSE ** } ** } ** } ** ** In the above notation, "csr.key" means the current value of the ORDER BY ** expression (there is only ever 1 for a RANGE that uses an FOLLOWING ** or PRECEDING AND PRECEDING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = ** regStart = ** }else{ ** while( (csrEnd.key + regEnd) <= csrCurrent.key ){ ** AGGSTEP ** } ** while( (csrStart.key + regStart) < csrCurrent.key ){ ** AGGINVERSE ** } ** RETURN_ROW ** } ** } ** flush: ** while( (csrEnd.key + regEnd) <= csrCurrent.key ){ ** AGGSTEP ** } ** while( (csrStart.key + regStart) < csrCurrent.key ){ ** AGGINVERSE ** } ** RETURN_ROW ** ** RANGE BETWEEN FOLLOWING AND FOLLOWING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = ** regStart = ** }else{ ** AGGSTEP ** while( (csrCurrent.key + regEnd) < csrEnd.key ){ ** while( (csrCurrent.key + regStart) > csrStart.key ){ ** AGGINVERSE ** } ** RETURN_ROW ** } ** } ** } ** flush: ** AGGSTEP ** while( 1 ){ ** while( (csrCurrent.key + regStart) > csrStart.key ){ ** AGGINVERSE ** if( eof ) break "while( 1 )" loop. ** } ** RETURN_ROW ** } ** while( !eof csrCurrent ){ ** RETURN_ROW ** } ** ** The text above leaves out many details. Refer to the code and comments ** below for a more complete picture. */ SQLITE_PRIVATE void sqlite3WindowCodeStep( Parse *pParse, /* Parse context */ Select *p, /* Rewritten SELECT statement */ WhereInfo *pWInfo, /* Context returned by sqlite3WhereBegin() */ int regGosub, /* Register for OP_Gosub */ int addrGosub /* OP_Gosub here to return each row */ ){ Window *pMWin = p->pWin; ExprList *pOrderBy = pMWin->pOrderBy; Vdbe *v = sqlite3GetVdbe(pParse); int csrWrite; /* Cursor used to write to eph. table */ int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */ int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */ int iInput; /* To iterate through sub cols */ int addrNe; /* Address of OP_Ne */ int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */ int addrInteger = 0; /* Address of OP_Integer */ int addrEmpty; /* Address of OP_Rewind in flush: */ int regNew; /* Array of registers holding new input row */ int regRecord; /* regNew array in record form */ int regNewPeer = 0; /* Peer values for new row (part of regNew) */ int regPeer = 0; /* Peer values for current row */ int regFlushPart = 0; /* Register for "Gosub flush_partition" */ WindowCodeArg s; /* Context object for sub-routines */ int lblWhereEnd; /* Label just before sqlite3WhereEnd() code */ int regStart = 0; /* Value of PRECEDING */ int regEnd = 0; /* Value of FOLLOWING */ assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT || pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED ); assert( pMWin->eEnd==TK_FOLLOWING || pMWin->eEnd==TK_CURRENT || pMWin->eEnd==TK_UNBOUNDED || pMWin->eEnd==TK_PRECEDING ); assert( pMWin->eExclude==0 || pMWin->eExclude==TK_CURRENT || pMWin->eExclude==TK_GROUP || pMWin->eExclude==TK_TIES || pMWin->eExclude==TK_NO ); lblWhereEnd = sqlite3VdbeMakeLabel(pParse); /* Fill in the context object */ memset(&s, 0, sizeof(WindowCodeArg)); s.pParse = pParse; s.pMWin = pMWin; s.pVdbe = v; s.regGosub = regGosub; s.addrGosub = addrGosub; s.current.csr = pMWin->iEphCsr; csrWrite = s.current.csr+1; s.start.csr = s.current.csr+2; s.end.csr = s.current.csr+3; /* Figure out when rows may be deleted from the ephemeral table. There ** are four options - they may never be deleted (eDelete==0), they may ** be deleted as soon as they are no longer part of the window frame ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row ** has been returned to the caller (WINDOW_RETURN_ROW), or they may ** be deleted after they enter the frame (WINDOW_AGGSTEP). */ switch( pMWin->eStart ){ case TK_FOLLOWING: if( pMWin->eFrmType!=TK_RANGE && windowExprGtZero(pParse, pMWin->pStart) ){ s.eDelete = WINDOW_RETURN_ROW; } break; case TK_UNBOUNDED: if( windowCacheFrame(pMWin)==0 ){ if( pMWin->eEnd==TK_PRECEDING ){ if( pMWin->eFrmType!=TK_RANGE && windowExprGtZero(pParse, pMWin->pEnd) ){ s.eDelete = WINDOW_AGGSTEP; } }else{ s.eDelete = WINDOW_RETURN_ROW; } } break; default: s.eDelete = WINDOW_AGGINVERSE; break; } /* Allocate registers for the array of values from the sub-query, the ** same values in record form, and the rowid used to insert said record ** into the ephemeral table. */ regNew = pParse->nMem+1; pParse->nMem += nInput; regRecord = ++pParse->nMem; s.regRowid = ++pParse->nMem; /* If the window frame contains an " PRECEDING" or " FOLLOWING" ** clause, allocate registers to store the results of evaluating each ** . */ if( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ){ regStart = ++pParse->nMem; } if( pMWin->eEnd==TK_PRECEDING || pMWin->eEnd==TK_FOLLOWING ){ regEnd = ++pParse->nMem; } /* If this is not a "ROWS BETWEEN ..." frame, then allocate arrays of ** registers to store copies of the ORDER BY expressions (peer values) ** for the main loop, and for each cursor (start, current and end). */ if( pMWin->eFrmType!=TK_ROWS ){ int nPeer = (pOrderBy ? pOrderBy->nExpr : 0); regNewPeer = regNew + pMWin->nBufferCol; if( pMWin->pPartition ) regNewPeer += pMWin->pPartition->nExpr; regPeer = pParse->nMem+1; pParse->nMem += nPeer; s.start.reg = pParse->nMem+1; pParse->nMem += nPeer; s.current.reg = pParse->nMem+1; pParse->nMem += nPeer; s.end.reg = pParse->nMem+1; pParse->nMem += nPeer; } /* Load the column values for the row returned by the sub-select ** into an array of registers starting at regNew. Assemble them into ** a record in register regRecord. */ for(iInput=0; iInputpPartition ){ int addr; ExprList *pPart = pMWin->pPartition; int nPart = pPart->nExpr; int regNewPart = regNew + pMWin->nBufferCol; KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); regFlushPart = ++pParse->nMem; addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart, nPart); sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2); VdbeCoverageEqNe(v); addrGosubFlush = sqlite3VdbeAddOp1(v, OP_Gosub, regFlushPart); VdbeComment((v, "call flush_partition")); sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1); } /* Insert the new row into the ephemeral table */ sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, s.regRowid); sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, s.regRowid); addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, s.regRowid); VdbeCoverageNeverNull(v); /* This block is run for the first row of each partition */ s.regArg = windowInitAccum(pParse, pMWin); if( regStart ){ sqlite3ExprCode(pParse, pMWin->pStart, regStart); windowCheckValue(pParse, regStart, 0 + (pMWin->eFrmType==TK_RANGE?3:0)); } if( regEnd ){ sqlite3ExprCode(pParse, pMWin->pEnd, regEnd); windowCheckValue(pParse, regEnd, 1 + (pMWin->eFrmType==TK_RANGE?3:0)); } if( pMWin->eFrmType!=TK_RANGE && pMWin->eStart==pMWin->eEnd && regStart ){ int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le); int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd); VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound */ VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */ windowAggFinal(&s, 0); sqlite3VdbeAddOp1(v, OP_Rewind, s.current.csr); windowReturnOneRow(&s); sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); sqlite3VdbeJumpHere(v, addrGe); } if( pMWin->eStart==TK_FOLLOWING && pMWin->eFrmType!=TK_RANGE && regEnd ){ assert( pMWin->eEnd==TK_FOLLOWING ); sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regStart); } if( pMWin->eStart!=TK_UNBOUNDED ){ sqlite3VdbeAddOp1(v, OP_Rewind, s.start.csr); } sqlite3VdbeAddOp1(v, OP_Rewind, s.current.csr); sqlite3VdbeAddOp1(v, OP_Rewind, s.end.csr); if( regPeer && pOrderBy ){ sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, pOrderBy->nExpr-1); sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.start.reg, pOrderBy->nExpr-1); sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.current.reg, pOrderBy->nExpr-1); sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.end.reg, pOrderBy->nExpr-1); } sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); sqlite3VdbeJumpHere(v, addrNe); /* Beginning of the block executed for the second and subsequent rows. */ if( regPeer ){ windowIfNewPeer(pParse, pOrderBy, regNewPeer, regPeer, lblWhereEnd); } if( pMWin->eStart==TK_FOLLOWING ){ windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); if( pMWin->eEnd!=TK_UNBOUNDED ){ if( pMWin->eFrmType==TK_RANGE ){ int lbl = sqlite3VdbeMakeLabel(pParse); int addrNext = sqlite3VdbeCurrentAddr(v); windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl); windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext); sqlite3VdbeResolveLabel(v, lbl); }else{ windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 0); windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); } } }else if( pMWin->eEnd==TK_PRECEDING ){ int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE); windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0); if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); if( !bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); }else{ int addr = 0; windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); if( pMWin->eEnd!=TK_UNBOUNDED ){ if( pMWin->eFrmType==TK_RANGE ){ int lbl = 0; addr = sqlite3VdbeCurrentAddr(v); if( regEnd ){ lbl = sqlite3VdbeMakeLabel(pParse); windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl); } windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); if( regEnd ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); sqlite3VdbeResolveLabel(v, lbl); } }else{ if( regEnd ){ addr = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1); VdbeCoverage(v); } windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); if( regEnd ) sqlite3VdbeJumpHere(v, addr); } } } /* End of the main input loop */ sqlite3VdbeResolveLabel(v, lblWhereEnd); sqlite3WhereEnd(pWInfo); /* Fall through */ if( pMWin->pPartition ){ addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart); sqlite3VdbeJumpHere(v, addrGosubFlush); } s.regRowid = 0; addrEmpty = sqlite3VdbeAddOp1(v, OP_Rewind, csrWrite); VdbeCoverage(v); if( pMWin->eEnd==TK_PRECEDING ){ int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE); windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0); if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); }else if( pMWin->eStart==TK_FOLLOWING ){ int addrStart; int addrBreak1; int addrBreak2; int addrBreak3; windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); if( pMWin->eFrmType==TK_RANGE ){ addrStart = sqlite3VdbeCurrentAddr(v); addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); }else if( pMWin->eEnd==TK_UNBOUNDED ){ addrStart = sqlite3VdbeCurrentAddr(v); addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regStart, 1); addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, 0, 1); }else{ assert( pMWin->eEnd==TK_FOLLOWING ); addrStart = sqlite3VdbeCurrentAddr(v); addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 1); addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); } sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); sqlite3VdbeJumpHere(v, addrBreak2); addrStart = sqlite3VdbeCurrentAddr(v); addrBreak3 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); sqlite3VdbeJumpHere(v, addrBreak1); sqlite3VdbeJumpHere(v, addrBreak3); }else{ int addrBreak; int addrStart; windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); addrStart = sqlite3VdbeCurrentAddr(v); addrBreak = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); sqlite3VdbeJumpHere(v, addrBreak); } sqlite3VdbeJumpHere(v, addrEmpty); sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); if( pMWin->pPartition ){ if( pMWin->regStartRowid ){ sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid); sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid); } sqlite3VdbeChangeP1(v, addrInteger, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); } } #endif /* SQLITE_OMIT_WINDOWFUNC */ /************** End of window.c **********************************************/ /************** Begin file parse.c *******************************************/ /* This file is automatically generated by Lemon from input grammar ** source file "parse.y". */ /* ** 2001-09-15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains SQLite's SQL parser. ** ** The canonical source code to this file ("parse.y") is a Lemon grammar ** file that specifies the input grammar and actions to take while parsing. ** That input file is processed by Lemon to generate a C-language ** implementation of a parser for the given grammar. You might be reading ** this comment as part of the translated C-code. Edits should be made ** to the original parse.y sources. */ /* #include "sqliteInt.h" */ /* ** Disable all error recovery processing in the parser push-down ** automaton. */ #define YYNOERRORRECOVERY 1 /* ** Make yytestcase() the same as testcase() */ #define yytestcase(X) testcase(X) /* ** Indicate that sqlite3ParserFree() will never be called with a null ** pointer. */ #define YYPARSEFREENEVERNULL 1 /* ** In the amalgamation, the parse.c file generated by lemon and the ** tokenize.c file are concatenated. In that case, sqlite3RunParser() ** has access to the the size of the yyParser object and so the parser ** engine can be allocated from stack. In that case, only the ** sqlite3ParserInit() and sqlite3ParserFinalize() routines are invoked ** and the sqlite3ParserAlloc() and sqlite3ParserFree() routines can be ** omitted. */ #ifdef SQLITE_AMALGAMATION # define sqlite3Parser_ENGINEALWAYSONSTACK 1 #endif /* ** Alternative datatype for the argument to the malloc() routine passed ** into sqlite3ParserAlloc(). The default is size_t. */ #define YYMALLOCARGTYPE u64 /* ** An instance of the following structure describes the event of a ** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT, ** TK_DELETE, or TK_INSTEAD. If the event is of the form ** ** UPDATE ON (a,b,c) ** ** Then the "b" IdList records the list "a,b,c". */ struct TrigEvent { int a; IdList * b; }; struct FrameBound { int eType; Expr *pExpr; }; /* ** Disable lookaside memory allocation for objects that might be ** shared across database connections. */ static void disableLookaside(Parse *pParse){ sqlite3 *db = pParse->db; pParse->disableLookaside++; DisableLookaside; } #if !defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) \ && defined(SQLITE_UDL_CAPABLE_PARSER) /* ** Issue an error message if an ORDER BY or LIMIT clause occurs on an ** UPDATE or DELETE statement. */ static void updateDeleteLimitError( Parse *pParse, ExprList *pOrderBy, Expr *pLimit ){ if( pOrderBy ){ sqlite3ErrorMsg(pParse, "syntax error near \"ORDER BY\""); }else{ sqlite3ErrorMsg(pParse, "syntax error near \"LIMIT\""); } sqlite3ExprListDelete(pParse->db, pOrderBy); sqlite3ExprDelete(pParse->db, pLimit); } #endif /* SQLITE_ENABLE_UPDATE_DELETE_LIMIT */ /* ** For a compound SELECT statement, make sure p->pPrior->pNext==p for ** all elements in the list. And make sure list length does not exceed ** SQLITE_LIMIT_COMPOUND_SELECT. */ static void parserDoubleLinkSelect(Parse *pParse, Select *p){ assert( p!=0 ); if( p->pPrior ){ Select *pNext = 0, *pLoop = p; int mxSelect, cnt = 1; while(1){ pLoop->pNext = pNext; pLoop->selFlags |= SF_Compound; pNext = pLoop; pLoop = pLoop->pPrior; if( pLoop==0 ) break; cnt++; if( pLoop->pOrderBy || pLoop->pLimit ){ sqlite3ErrorMsg(pParse,"%s clause should come after %s not before", pLoop->pOrderBy!=0 ? "ORDER BY" : "LIMIT", sqlite3SelectOpName(pNext->op)); break; } } if( (p->selFlags & SF_MultiValue)==0 && (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && cnt>mxSelect ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); } } } /* Attach a With object describing the WITH clause to a Select ** object describing the query for which the WITH clause is a prefix. */ static Select *attachWithToSelect(Parse *pParse, Select *pSelect, With *pWith){ if( pSelect ){ pSelect->pWith = pWith; parserDoubleLinkSelect(pParse, pSelect); }else{ sqlite3WithDelete(pParse->db, pWith); } return pSelect; } /* Construct a new Expr object from a single token */ static Expr *tokenExpr(Parse *pParse, int op, Token t){ Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); if( p ){ /* memset(p, 0, sizeof(Expr)); */ p->op = (u8)op; p->affExpr = 0; p->flags = EP_Leaf; ExprClearVVAProperties(p); /* p->iAgg = -1; // Not required */ p->pLeft = p->pRight = 0; p->pAggInfo = 0; memset(&p->x, 0, sizeof(p->x)); memset(&p->y, 0, sizeof(p->y)); p->op2 = 0; p->iTable = 0; p->iColumn = 0; p->u.zToken = (char*)&p[1]; memcpy(p->u.zToken, t.z, t.n); p->u.zToken[t.n] = 0; p->w.iOfst = (int)(t.z - pParse->zTail); if( sqlite3Isquote(p->u.zToken[0]) ){ sqlite3DequoteExpr(p); } #if SQLITE_MAX_EXPR_DEPTH>0 p->nHeight = 1; #endif if( IN_RENAME_OBJECT ){ return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t); } } return p; } /* A routine to convert a binary TK_IS or TK_ISNOT expression into a ** unary TK_ISNULL or TK_NOTNULL expression. */ static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ sqlite3 *db = pParse->db; if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){ pA->op = (u8)op; sqlite3ExprDelete(db, pA->pRight); pA->pRight = 0; } } /* Add a single new term to an ExprList that is used to store a ** list of identifiers. Report an error if the ID list contains ** a COLLATE clause or an ASC or DESC keyword, except ignore the ** error while parsing a legacy schema. */ static ExprList *parserAddExprIdListTerm( Parse *pParse, ExprList *pPrior, Token *pIdToken, int hasCollate, int sortOrder ){ ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0); if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED) && pParse->db->init.busy==0 ){ sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"", pIdToken->n, pIdToken->z); } sqlite3ExprListSetName(pParse, p, pIdToken, 1); return p; } #if TK_SPAN>255 # error too many tokens in the grammar #endif /**************** End of %include directives **********************************/ /* These constants specify the various numeric values for terminal symbols. ***************** Begin token definitions *************************************/ #ifndef TK_SEMI #define TK_SEMI 1 #define TK_EXPLAIN 2 #define TK_QUERY 3 #define TK_PLAN 4 #define TK_BEGIN 5 #define TK_TRANSACTION 6 #define TK_DEFERRED 7 #define TK_IMMEDIATE 8 #define TK_EXCLUSIVE 9 #define TK_COMMIT 10 #define TK_END 11 #define TK_ROLLBACK 12 #define TK_SAVEPOINT 13 #define TK_RELEASE 14 #define TK_TO 15 #define TK_TABLE 16 #define TK_CREATE 17 #define TK_IF 18 #define TK_NOT 19 #define TK_EXISTS 20 #define TK_TEMP 21 #define TK_LP 22 #define TK_RP 23 #define TK_AS 24 #define TK_COMMA 25 #define TK_WITHOUT 26 #define TK_ABORT 27 #define TK_ACTION 28 #define TK_AFTER 29 #define TK_ANALYZE 30 #define TK_ASC 31 #define TK_ATTACH 32 #define TK_BEFORE 33 #define TK_BY 34 #define TK_CASCADE 35 #define TK_CAST 36 #define TK_CONFLICT 37 #define TK_DATABASE 38 #define TK_DESC 39 #define TK_DETACH 40 #define TK_EACH 41 #define TK_FAIL 42 #define TK_OR 43 #define TK_AND 44 #define TK_IS 45 #define TK_MATCH 46 #define TK_LIKE_KW 47 #define TK_BETWEEN 48 #define TK_IN 49 #define TK_ISNULL 50 #define TK_NOTNULL 51 #define TK_NE 52 #define TK_EQ 53 #define TK_GT 54 #define TK_LE 55 #define TK_LT 56 #define TK_GE 57 #define TK_ESCAPE 58 #define TK_ID 59 #define TK_COLUMNKW 60 #define TK_DO 61 #define TK_FOR 62 #define TK_IGNORE 63 #define TK_INITIALLY 64 #define TK_INSTEAD 65 #define TK_NO 66 #define TK_KEY 67 #define TK_OF 68 #define TK_OFFSET 69 #define TK_PRAGMA 70 #define TK_RAISE 71 #define TK_RECURSIVE 72 #define TK_REPLACE 73 #define TK_RESTRICT 74 #define TK_ROW 75 #define TK_ROWS 76 #define TK_TRIGGER 77 #define TK_VACUUM 78 #define TK_VIEW 79 #define TK_VIRTUAL 80 #define TK_WITH 81 #define TK_NULLS 82 #define TK_FIRST 83 #define TK_LAST 84 #define TK_CURRENT 85 #define TK_FOLLOWING 86 #define TK_PARTITION 87 #define TK_PRECEDING 88 #define TK_RANGE 89 #define TK_UNBOUNDED 90 #define TK_EXCLUDE 91 #define TK_GROUPS 92 #define TK_OTHERS 93 #define TK_TIES 94 #define TK_GENERATED 95 #define TK_ALWAYS 96 #define TK_MATERIALIZED 97 #define TK_REINDEX 98 #define TK_RENAME 99 #define TK_CTIME_KW 100 #define TK_ANY 101 #define TK_BITAND 102 #define TK_BITOR 103 #define TK_LSHIFT 104 #define TK_RSHIFT 105 #define TK_PLUS 106 #define TK_MINUS 107 #define TK_STAR 108 #define TK_SLASH 109 #define TK_REM 110 #define TK_CONCAT 111 #define TK_PTR 112 #define TK_COLLATE 113 #define TK_BITNOT 114 #define TK_ON 115 #define TK_INDEXED 116 #define TK_STRING 117 #define TK_JOIN_KW 118 #define TK_CONSTRAINT 119 #define TK_DEFAULT 120 #define TK_NULL 121 #define TK_PRIMARY 122 #define TK_UNIQUE 123 #define TK_CHECK 124 #define TK_REFERENCES 125 #define TK_AUTOINCR 126 #define TK_INSERT 127 #define TK_DELETE 128 #define TK_UPDATE 129 #define TK_SET 130 #define TK_DEFERRABLE 131 #define TK_FOREIGN 132 #define TK_DROP 133 #define TK_UNION 134 #define TK_ALL 135 #define TK_EXCEPT 136 #define TK_INTERSECT 137 #define TK_SELECT 138 #define TK_VALUES 139 #define TK_DISTINCT 140 #define TK_DOT 141 #define TK_FROM 142 #define TK_JOIN 143 #define TK_USING 144 #define TK_ORDER 145 #define TK_GROUP 146 #define TK_HAVING 147 #define TK_LIMIT 148 #define TK_WHERE 149 #define TK_RETURNING 150 #define TK_INTO 151 #define TK_NOTHING 152 #define TK_FLOAT 153 #define TK_BLOB 154 #define TK_INTEGER 155 #define TK_VARIABLE 156 #define TK_CASE 157 #define TK_WHEN 158 #define TK_THEN 159 #define TK_ELSE 160 #define TK_INDEX 161 #define TK_ALTER 162 #define TK_ADD 163 #define TK_WINDOW 164 #define TK_OVER 165 #define TK_FILTER 166 #define TK_COLUMN 167 #define TK_AGG_FUNCTION 168 #define TK_AGG_COLUMN 169 #define TK_TRUEFALSE 170 #define TK_ISNOT 171 #define TK_FUNCTION 172 #define TK_UMINUS 173 #define TK_UPLUS 174 #define TK_TRUTH 175 #define TK_REGISTER 176 #define TK_VECTOR 177 #define TK_SELECT_COLUMN 178 #define TK_IF_NULL_ROW 179 #define TK_ASTERISK 180 #define TK_SPAN 181 #define TK_ERROR 182 #define TK_SPACE 183 #define TK_ILLEGAL 184 #endif /**************** End token definitions ***************************************/ /* The next sections is a series of control #defines. ** various aspects of the generated parser. ** YYCODETYPE is the data type used to store the integer codes ** that represent terminal and non-terminal symbols. ** "unsigned char" is used if there are fewer than ** 256 symbols. Larger types otherwise. ** YYNOCODE is a number of type YYCODETYPE that is not used for ** any terminal or nonterminal symbol. ** YYFALLBACK If defined, this indicates that one or more tokens ** (also known as: "terminal symbols") have fall-back ** values which should be used if the original symbol ** would not parse. This permits keywords to sometimes ** be used as identifiers, for example. ** YYACTIONTYPE is the data type used for "action codes" - numbers ** that indicate what to do in response to the next ** token. ** sqlite3ParserTOKENTYPE is the data type used for minor type for terminal ** symbols. Background: A "minor type" is a semantic ** value associated with a terminal or non-terminal ** symbols. For example, for an "ID" terminal symbol, ** the minor type might be the name of the identifier. ** Each non-terminal can have a different minor type. ** Terminal symbols all have the same minor type, though. ** This macros defines the minor type for terminal ** symbols. ** YYMINORTYPE is the data type used for all minor types. ** This is typically a union of many types, one of ** which is sqlite3ParserTOKENTYPE. The entry in the union ** for terminal symbols is called "yy0". ** YYSTACKDEPTH is the maximum depth of the parser's stack. If ** zero the stack is dynamically sized using realloc() ** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument ** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument ** sqlite3ParserARG_PARAM Code to pass %extra_argument as a subroutine parameter ** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser ** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser ** sqlite3ParserCTX_* As sqlite3ParserARG_ except for %extra_context ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** YYNSTATE the combined number of states. ** YYNRULE the number of rules in the grammar ** YYNTOKEN Number of terminal symbols ** YY_MAX_SHIFT Maximum value for shift actions ** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions ** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions ** YY_ERROR_ACTION The yy_action[] code for syntax error ** YY_ACCEPT_ACTION The yy_action[] code for accept ** YY_NO_ACTION The yy_action[] code for no-op ** YY_MIN_REDUCE Minimum value for reduce actions ** YY_MAX_REDUCE Maximum value for reduce actions */ #ifndef INTERFACE # define INTERFACE 1 #endif /************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned short int #define YYNOCODE 319 #define YYACTIONTYPE unsigned short int #define YYWILDCARD 101 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; sqlite3ParserTOKENTYPE yy0; TriggerStep* yy33; Window* yy41; Select* yy47; SrcList* yy131; struct TrigEvent yy180; struct {int value; int mask;} yy231; IdList* yy254; u32 yy285; ExprList* yy322; Cte* yy385; int yy394; Upsert* yy444; u8 yy516; With* yy521; const char* yy522; Expr* yy528; OnOrUsing yy561; struct FrameBound yy595; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 #endif #define sqlite3ParserARG_SDECL #define sqlite3ParserARG_PDECL #define sqlite3ParserARG_PARAM #define sqlite3ParserARG_FETCH #define sqlite3ParserARG_STORE #define sqlite3ParserCTX_SDECL Parse *pParse; #define sqlite3ParserCTX_PDECL ,Parse *pParse #define sqlite3ParserCTX_PARAM ,pParse #define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse; #define sqlite3ParserCTX_STORE yypParser->pParse=pParse; #define YYFALLBACK 1 #define YYNSTATE 579 #define YYNRULE 405 #define YYNRULE_WITH_ACTION 340 #define YYNTOKEN 185 #define YY_MAX_SHIFT 578 #define YY_MIN_SHIFTREDUCE 838 #define YY_MAX_SHIFTREDUCE 1242 #define YY_ERROR_ACTION 1243 #define YY_ACCEPT_ACTION 1244 #define YY_NO_ACTION 1245 #define YY_MIN_REDUCE 1246 #define YY_MAX_REDUCE 1650 /************* End control #defines *******************************************/ #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) /* Define the yytestcase() macro to be a no-op if is not already defined ** otherwise. ** ** Applications can choose to define yytestcase() in the %include section ** to a macro that can assist in verifying code coverage. For production ** code the yytestcase() macro should be turned off. But it is useful ** for testing. */ #ifndef yytestcase # define yytestcase(X) #endif /* Next are the tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an ** action integer. ** ** Suppose the action integer is N. Then the action is determined as ** follows ** ** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead ** token onto the stack and goto state N. ** ** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then ** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. ** ** N == YY_ERROR_ACTION A syntax error has occurred. ** ** N == YY_ACCEPT_ACTION The parser accepts its input. ** ** N == YY_NO_ACTION No such action. Denotes unused ** slots in the yy_action[] table. ** ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE ** and YY_MAX_REDUCE ** ** The action table is constructed as a single large table named yy_action[]. ** Given state S and lookahead X, the action is computed as either: ** ** (A) N = yy_action[ yy_shift_ofst[S] + X ] ** (B) N = yy_default[S] ** ** The (A) formula is preferred. The B formula is used instead if ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X. ** ** The formulas above are for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the yy_reduce_ofst[] array is used in place of ** the yy_shift_ofst[] array. ** ** The following are the tables generated in this section: ** ** yy_action[] A single table containing all actions. ** yy_lookahead[] A table containing the lookahead for each entry in ** yy_action. Used to detect hash collisions. ** yy_shift_ofst[] For each state, the offset into yy_action for ** shifting terminals. ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ #define YY_ACTTAB_COUNT (2100) static const YYACTIONTYPE yy_action[] = { /* 0 */ 572, 210, 572, 119, 116, 231, 572, 119, 116, 231, /* 10 */ 572, 1317, 379, 1296, 410, 566, 566, 566, 572, 411, /* 20 */ 380, 1317, 1279, 42, 42, 42, 42, 210, 1529, 72, /* 30 */ 72, 974, 421, 42, 42, 495, 305, 281, 305, 975, /* 40 */ 399, 72, 72, 126, 127, 81, 1217, 1217, 1054, 1057, /* 50 */ 1044, 1044, 124, 124, 125, 125, 125, 125, 480, 411, /* 60 */ 1244, 1, 1, 578, 2, 1248, 554, 119, 116, 231, /* 70 */ 319, 484, 147, 484, 528, 119, 116, 231, 533, 1330, /* 80 */ 419, 527, 143, 126, 127, 81, 1217, 1217, 1054, 1057, /* 90 */ 1044, 1044, 124, 124, 125, 125, 125, 125, 119, 116, /* 100 */ 231, 329, 123, 123, 123, 123, 122, 122, 121, 121, /* 110 */ 121, 120, 117, 448, 286, 286, 286, 286, 446, 446, /* 120 */ 446, 1568, 378, 1570, 1193, 377, 1164, 569, 1164, 569, /* 130 */ 411, 1568, 541, 261, 228, 448, 102, 146, 453, 318, /* 140 */ 563, 242, 123, 123, 123, 123, 122, 122, 121, 121, /* 150 */ 121, 120, 117, 448, 126, 127, 81, 1217, 1217, 1054, /* 160 */ 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, 143, /* 170 */ 296, 1193, 341, 452, 121, 121, 121, 120, 117, 448, /* 180 */ 128, 1193, 1194, 1193, 149, 445, 444, 572, 120, 117, /* 190 */ 448, 125, 125, 125, 125, 118, 123, 123, 123, 123, /* 200 */ 122, 122, 121, 121, 121, 120, 117, 448, 458, 114, /* 210 */ 13, 13, 550, 123, 123, 123, 123, 122, 122, 121, /* 220 */ 121, 121, 120, 117, 448, 424, 318, 563, 1193, 1194, /* 230 */ 1193, 150, 1225, 411, 1225, 125, 125, 125, 125, 123, /* 240 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117, /* 250 */ 448, 469, 344, 1041, 1041, 1055, 1058, 126, 127, 81, /* 260 */ 1217, 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, /* 270 */ 125, 125, 1282, 526, 224, 1193, 572, 411, 226, 519, /* 280 */ 177, 83, 84, 123, 123, 123, 123, 122, 122, 121, /* 290 */ 121, 121, 120, 117, 448, 1010, 16, 16, 1193, 134, /* 300 */ 134, 126, 127, 81, 1217, 1217, 1054, 1057, 1044, 1044, /* 310 */ 124, 124, 125, 125, 125, 125, 123, 123, 123, 123, /* 320 */ 122, 122, 121, 121, 121, 120, 117, 448, 1045, 550, /* 330 */ 1193, 375, 1193, 1194, 1193, 254, 1438, 401, 508, 505, /* 340 */ 504, 112, 564, 570, 4, 929, 929, 435, 503, 342, /* 350 */ 464, 330, 362, 396, 1238, 1193, 1194, 1193, 567, 572, /* 360 */ 123, 123, 123, 123, 122, 122, 121, 121, 121, 120, /* 370 */ 117, 448, 286, 286, 371, 1581, 1607, 445, 444, 155, /* 380 */ 411, 449, 72, 72, 1289, 569, 1222, 1193, 1194, 1193, /* 390 */ 86, 1224, 273, 561, 547, 520, 520, 572, 99, 1223, /* 400 */ 6, 1281, 476, 143, 126, 127, 81, 1217, 1217, 1054, /* 410 */ 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, 554, /* 420 */ 13, 13, 1031, 511, 1225, 1193, 1225, 553, 110, 110, /* 430 */ 224, 572, 1239, 177, 572, 429, 111, 199, 449, 573, /* 440 */ 449, 432, 1555, 1019, 327, 555, 1193, 272, 289, 370, /* 450 */ 514, 365, 513, 259, 72, 72, 547, 72, 72, 361, /* 460 */ 318, 563, 1613, 123, 123, 123, 123, 122, 122, 121, /* 470 */ 121, 121, 120, 117, 448, 1019, 1019, 1021, 1022, 28, /* 480 */ 286, 286, 1193, 1194, 1193, 1159, 572, 1612, 411, 904, /* 490 */ 192, 554, 358, 569, 554, 940, 537, 521, 1159, 437, /* 500 */ 415, 1159, 556, 1193, 1194, 1193, 572, 548, 548, 52, /* 510 */ 52, 216, 126, 127, 81, 1217, 1217, 1054, 1057, 1044, /* 520 */ 1044, 124, 124, 125, 125, 125, 125, 1193, 478, 136, /* 530 */ 136, 411, 286, 286, 1493, 509, 122, 122, 121, 121, /* 540 */ 121, 120, 117, 448, 1010, 569, 522, 219, 545, 545, /* 550 */ 318, 563, 143, 6, 536, 126, 127, 81, 1217, 1217, /* 560 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, /* 570 */ 1557, 123, 123, 123, 123, 122, 122, 121, 121, 121, /* 580 */ 120, 117, 448, 489, 1193, 1194, 1193, 486, 283, 1270, /* 590 */ 960, 254, 1193, 375, 508, 505, 504, 1193, 342, 574, /* 600 */ 1193, 574, 411, 294, 503, 960, 879, 193, 484, 318, /* 610 */ 563, 386, 292, 382, 123, 123, 123, 123, 122, 122, /* 620 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, /* 630 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, /* 640 */ 125, 411, 396, 1139, 1193, 872, 101, 286, 286, 1193, /* 650 */ 1194, 1193, 375, 1096, 1193, 1194, 1193, 1193, 1194, 1193, /* 660 */ 569, 459, 33, 375, 235, 126, 127, 81, 1217, 1217, /* 670 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, /* 680 */ 1437, 962, 572, 230, 961, 123, 123, 123, 123, 122, /* 690 */ 122, 121, 121, 121, 120, 117, 448, 1159, 230, 1193, /* 700 */ 158, 1193, 1194, 1193, 1556, 13, 13, 303, 960, 1233, /* 710 */ 1159, 154, 411, 1159, 375, 1584, 1177, 5, 371, 1581, /* 720 */ 431, 1239, 3, 960, 123, 123, 123, 123, 122, 122, /* 730 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, /* 740 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, /* 750 */ 125, 411, 210, 571, 1193, 1032, 1193, 1194, 1193, 1193, /* 760 */ 390, 855, 156, 1555, 376, 404, 1101, 1101, 492, 572, /* 770 */ 469, 344, 1322, 1322, 1555, 126, 127, 81, 1217, 1217, /* 780 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, /* 790 */ 130, 572, 13, 13, 532, 123, 123, 123, 123, 122, /* 800 */ 122, 121, 121, 121, 120, 117, 448, 304, 572, 457, /* 810 */ 229, 1193, 1194, 1193, 13, 13, 1193, 1194, 1193, 1300, /* 820 */ 467, 1270, 411, 1320, 1320, 1555, 1015, 457, 456, 436, /* 830 */ 301, 72, 72, 1268, 123, 123, 123, 123, 122, 122, /* 840 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, /* 850 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, /* 860 */ 125, 411, 384, 1076, 1159, 286, 286, 421, 314, 280, /* 870 */ 280, 287, 287, 461, 408, 407, 1539, 1159, 569, 572, /* 880 */ 1159, 1196, 569, 409, 569, 126, 127, 81, 1217, 1217, /* 890 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, /* 900 */ 457, 1485, 13, 13, 1541, 123, 123, 123, 123, 122, /* 910 */ 122, 121, 121, 121, 120, 117, 448, 202, 572, 462, /* 920 */ 1587, 578, 2, 1248, 843, 844, 845, 1563, 319, 409, /* 930 */ 147, 6, 411, 257, 256, 255, 208, 1330, 9, 1196, /* 940 */ 264, 72, 72, 1436, 123, 123, 123, 123, 122, 122, /* 950 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, /* 960 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, /* 970 */ 125, 572, 286, 286, 572, 1213, 411, 577, 315, 1248, /* 980 */ 421, 371, 1581, 356, 319, 569, 147, 495, 529, 1644, /* 990 */ 397, 935, 495, 1330, 71, 71, 934, 72, 72, 242, /* 1000 */ 1328, 105, 81, 1217, 1217, 1054, 1057, 1044, 1044, 124, /* 1010 */ 124, 125, 125, 125, 125, 123, 123, 123, 123, 122, /* 1020 */ 122, 121, 121, 121, 120, 117, 448, 1117, 286, 286, /* 1030 */ 1422, 452, 1528, 1213, 443, 286, 286, 1492, 1355, 313, /* 1040 */ 478, 569, 1118, 454, 351, 495, 354, 1266, 569, 209, /* 1050 */ 572, 418, 179, 572, 1031, 242, 385, 1119, 523, 123, /* 1060 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117, /* 1070 */ 448, 1020, 108, 72, 72, 1019, 13, 13, 915, 572, /* 1080 */ 1498, 572, 286, 286, 98, 530, 1537, 452, 916, 1334, /* 1090 */ 1329, 203, 411, 286, 286, 569, 152, 211, 1498, 1500, /* 1100 */ 426, 569, 56, 56, 57, 57, 569, 1019, 1019, 1021, /* 1110 */ 447, 572, 411, 531, 12, 297, 126, 127, 81, 1217, /* 1120 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, /* 1130 */ 125, 572, 411, 867, 15, 15, 126, 127, 81, 1217, /* 1140 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, /* 1150 */ 125, 373, 529, 264, 44, 44, 126, 115, 81, 1217, /* 1160 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, /* 1170 */ 125, 1498, 478, 1271, 417, 123, 123, 123, 123, 122, /* 1180 */ 122, 121, 121, 121, 120, 117, 448, 205, 1213, 495, /* 1190 */ 430, 867, 468, 322, 495, 123, 123, 123, 123, 122, /* 1200 */ 122, 121, 121, 121, 120, 117, 448, 572, 557, 1140, /* 1210 */ 1642, 1422, 1642, 543, 572, 123, 123, 123, 123, 122, /* 1220 */ 122, 121, 121, 121, 120, 117, 448, 572, 1422, 572, /* 1230 */ 13, 13, 542, 323, 1325, 411, 334, 58, 58, 349, /* 1240 */ 1422, 1170, 326, 286, 286, 549, 1213, 300, 895, 530, /* 1250 */ 45, 45, 59, 59, 1140, 1643, 569, 1643, 565, 417, /* 1260 */ 127, 81, 1217, 1217, 1054, 1057, 1044, 1044, 124, 124, /* 1270 */ 125, 125, 125, 125, 1367, 373, 500, 290, 1193, 512, /* 1280 */ 1366, 427, 394, 394, 393, 275, 391, 896, 1138, 852, /* 1290 */ 478, 258, 1422, 1170, 463, 1159, 12, 331, 428, 333, /* 1300 */ 1117, 460, 236, 258, 325, 460, 544, 1544, 1159, 1098, /* 1310 */ 491, 1159, 324, 1098, 440, 1118, 335, 516, 123, 123, /* 1320 */ 123, 123, 122, 122, 121, 121, 121, 120, 117, 448, /* 1330 */ 1119, 318, 563, 1138, 572, 1193, 1194, 1193, 112, 564, /* 1340 */ 201, 4, 238, 433, 935, 490, 285, 228, 1517, 934, /* 1350 */ 170, 560, 572, 142, 1516, 567, 572, 60, 60, 572, /* 1360 */ 416, 572, 441, 572, 535, 302, 875, 8, 487, 572, /* 1370 */ 237, 572, 416, 572, 485, 61, 61, 572, 449, 62, /* 1380 */ 62, 332, 63, 63, 46, 46, 47, 47, 361, 572, /* 1390 */ 561, 572, 48, 48, 50, 50, 51, 51, 572, 295, /* 1400 */ 64, 64, 482, 295, 539, 412, 471, 1031, 572, 538, /* 1410 */ 318, 563, 65, 65, 66, 66, 409, 475, 572, 1031, /* 1420 */ 572, 14, 14, 875, 1020, 110, 110, 409, 1019, 572, /* 1430 */ 474, 67, 67, 111, 455, 449, 573, 449, 98, 317, /* 1440 */ 1019, 132, 132, 133, 133, 572, 1561, 572, 974, 409, /* 1450 */ 6, 1562, 68, 68, 1560, 6, 975, 572, 6, 1559, /* 1460 */ 1019, 1019, 1021, 6, 346, 218, 101, 531, 53, 53, /* 1470 */ 69, 69, 1019, 1019, 1021, 1022, 28, 1586, 1181, 451, /* 1480 */ 70, 70, 290, 87, 215, 31, 1363, 394, 394, 393, /* 1490 */ 275, 391, 350, 109, 852, 107, 572, 112, 564, 483, /* 1500 */ 4, 1212, 572, 239, 153, 572, 39, 236, 1299, 325, /* 1510 */ 112, 564, 1298, 4, 567, 572, 32, 324, 572, 54, /* 1520 */ 54, 572, 1135, 353, 398, 165, 165, 567, 166, 166, /* 1530 */ 572, 291, 355, 572, 17, 357, 572, 449, 77, 77, /* 1540 */ 1313, 55, 55, 1297, 73, 73, 572, 238, 470, 561, /* 1550 */ 449, 472, 364, 135, 135, 170, 74, 74, 142, 163, /* 1560 */ 163, 374, 561, 539, 572, 321, 572, 886, 540, 137, /* 1570 */ 137, 339, 1353, 422, 298, 237, 539, 572, 1031, 572, /* 1580 */ 340, 538, 101, 369, 110, 110, 162, 131, 131, 164, /* 1590 */ 164, 1031, 111, 368, 449, 573, 449, 110, 110, 1019, /* 1600 */ 157, 157, 141, 141, 572, 111, 572, 449, 573, 449, /* 1610 */ 412, 288, 1019, 572, 882, 318, 563, 572, 219, 572, /* 1620 */ 241, 1012, 477, 263, 263, 894, 893, 140, 140, 138, /* 1630 */ 138, 1019, 1019, 1021, 1022, 28, 139, 139, 525, 455, /* 1640 */ 76, 76, 78, 78, 1019, 1019, 1021, 1022, 28, 1181, /* 1650 */ 451, 572, 1083, 290, 112, 564, 1575, 4, 394, 394, /* 1660 */ 393, 275, 391, 572, 1023, 852, 572, 479, 345, 263, /* 1670 */ 101, 567, 882, 1376, 75, 75, 1421, 501, 236, 260, /* 1680 */ 325, 112, 564, 359, 4, 101, 43, 43, 324, 49, /* 1690 */ 49, 901, 902, 161, 449, 101, 977, 978, 567, 1079, /* 1700 */ 1349, 260, 965, 932, 263, 114, 561, 1095, 517, 1095, /* 1710 */ 1083, 1094, 865, 1094, 151, 933, 1144, 114, 238, 1361, /* 1720 */ 558, 449, 1023, 559, 1426, 1278, 170, 1269, 1257, 142, /* 1730 */ 1601, 1256, 1258, 561, 1594, 1031, 496, 278, 213, 1346, /* 1740 */ 310, 110, 110, 939, 311, 312, 237, 11, 234, 111, /* 1750 */ 221, 449, 573, 449, 293, 395, 1019, 1408, 337, 1403, /* 1760 */ 1396, 338, 1031, 299, 343, 1413, 1412, 481, 110, 110, /* 1770 */ 506, 402, 225, 1296, 206, 367, 111, 1358, 449, 573, /* 1780 */ 449, 412, 1359, 1019, 1489, 1488, 318, 563, 1019, 1019, /* 1790 */ 1021, 1022, 28, 562, 207, 220, 80, 564, 389, 4, /* 1800 */ 1597, 1357, 552, 1356, 1233, 181, 267, 232, 1536, 1534, /* 1810 */ 455, 1230, 420, 567, 82, 1019, 1019, 1021, 1022, 28, /* 1820 */ 86, 217, 85, 1494, 190, 175, 183, 465, 185, 466, /* 1830 */ 36, 1409, 186, 187, 188, 499, 449, 244, 37, 99, /* 1840 */ 400, 1415, 1414, 488, 1417, 194, 473, 403, 561, 1483, /* 1850 */ 248, 92, 1505, 494, 198, 279, 112, 564, 250, 4, /* 1860 */ 348, 497, 405, 352, 1259, 251, 252, 515, 1316, 434, /* 1870 */ 1315, 1314, 94, 567, 1307, 886, 1306, 1031, 226, 406, /* 1880 */ 1611, 1610, 438, 110, 110, 1580, 1286, 524, 439, 308, /* 1890 */ 266, 111, 1285, 449, 573, 449, 449, 309, 1019, 366, /* 1900 */ 1284, 1609, 265, 1566, 1565, 442, 372, 1381, 561, 129, /* 1910 */ 550, 1380, 10, 1470, 383, 106, 316, 551, 100, 35, /* 1920 */ 534, 575, 212, 1339, 381, 387, 1187, 1338, 274, 276, /* 1930 */ 1019, 1019, 1021, 1022, 28, 277, 413, 1031, 576, 1254, /* 1940 */ 388, 1521, 1249, 110, 110, 167, 1522, 168, 148, 1520, /* 1950 */ 1519, 111, 306, 449, 573, 449, 222, 223, 1019, 839, /* 1960 */ 169, 79, 450, 214, 414, 233, 320, 145, 1093, 1091, /* 1970 */ 328, 182, 171, 1212, 918, 184, 240, 336, 243, 1107, /* 1980 */ 189, 172, 173, 423, 425, 88, 180, 191, 89, 90, /* 1990 */ 1019, 1019, 1021, 1022, 28, 91, 174, 1110, 245, 1106, /* 2000 */ 246, 159, 18, 247, 347, 1099, 263, 195, 1227, 493, /* 2010 */ 249, 196, 38, 854, 498, 368, 253, 360, 897, 197, /* 2020 */ 502, 93, 19, 20, 507, 884, 363, 510, 95, 307, /* 2030 */ 160, 96, 518, 97, 1175, 1060, 1146, 40, 21, 227, /* 2040 */ 176, 1145, 282, 284, 969, 200, 963, 114, 262, 1165, /* 2050 */ 22, 23, 24, 1161, 1169, 25, 1163, 1150, 34, 26, /* 2060 */ 1168, 546, 27, 204, 101, 103, 104, 1074, 7, 1061, /* 2070 */ 1059, 1063, 1116, 1064, 1115, 268, 269, 29, 41, 270, /* 2080 */ 1024, 866, 113, 30, 568, 392, 1183, 144, 178, 1182, /* 2090 */ 271, 928, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1602, }; static const YYCODETYPE yy_lookahead[] = { /* 0 */ 193, 193, 193, 274, 275, 276, 193, 274, 275, 276, /* 10 */ 193, 223, 219, 225, 206, 210, 211, 212, 193, 19, /* 20 */ 219, 233, 216, 216, 217, 216, 217, 193, 295, 216, /* 30 */ 217, 31, 193, 216, 217, 193, 228, 213, 230, 39, /* 40 */ 206, 216, 217, 43, 44, 45, 46, 47, 48, 49, /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 193, 19, /* 60 */ 185, 186, 187, 188, 189, 190, 253, 274, 275, 276, /* 70 */ 195, 193, 197, 193, 261, 274, 275, 276, 253, 204, /* 80 */ 238, 204, 81, 43, 44, 45, 46, 47, 48, 49, /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 274, 275, /* 100 */ 276, 262, 102, 103, 104, 105, 106, 107, 108, 109, /* 110 */ 110, 111, 112, 113, 239, 240, 239, 240, 210, 211, /* 120 */ 212, 314, 315, 314, 59, 316, 86, 252, 88, 252, /* 130 */ 19, 314, 315, 256, 257, 113, 25, 72, 296, 138, /* 140 */ 139, 266, 102, 103, 104, 105, 106, 107, 108, 109, /* 150 */ 110, 111, 112, 113, 43, 44, 45, 46, 47, 48, /* 160 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 81, /* 170 */ 292, 59, 292, 298, 108, 109, 110, 111, 112, 113, /* 180 */ 69, 116, 117, 118, 72, 106, 107, 193, 111, 112, /* 190 */ 113, 54, 55, 56, 57, 58, 102, 103, 104, 105, /* 200 */ 106, 107, 108, 109, 110, 111, 112, 113, 120, 25, /* 210 */ 216, 217, 145, 102, 103, 104, 105, 106, 107, 108, /* 220 */ 109, 110, 111, 112, 113, 231, 138, 139, 116, 117, /* 230 */ 118, 164, 153, 19, 155, 54, 55, 56, 57, 102, /* 240 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, /* 250 */ 113, 128, 129, 46, 47, 48, 49, 43, 44, 45, /* 260 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, /* 270 */ 56, 57, 216, 193, 25, 59, 193, 19, 165, 166, /* 280 */ 193, 67, 24, 102, 103, 104, 105, 106, 107, 108, /* 290 */ 109, 110, 111, 112, 113, 73, 216, 217, 59, 216, /* 300 */ 217, 43, 44, 45, 46, 47, 48, 49, 50, 51, /* 310 */ 52, 53, 54, 55, 56, 57, 102, 103, 104, 105, /* 320 */ 106, 107, 108, 109, 110, 111, 112, 113, 121, 145, /* 330 */ 59, 193, 116, 117, 118, 119, 273, 204, 122, 123, /* 340 */ 124, 19, 20, 134, 22, 136, 137, 19, 132, 127, /* 350 */ 128, 129, 24, 22, 23, 116, 117, 118, 36, 193, /* 360 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, /* 370 */ 112, 113, 239, 240, 311, 312, 215, 106, 107, 241, /* 380 */ 19, 59, 216, 217, 223, 252, 115, 116, 117, 118, /* 390 */ 151, 120, 26, 71, 193, 308, 309, 193, 149, 128, /* 400 */ 313, 216, 269, 81, 43, 44, 45, 46, 47, 48, /* 410 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 253, /* 420 */ 216, 217, 100, 95, 153, 59, 155, 261, 106, 107, /* 430 */ 25, 193, 101, 193, 193, 231, 114, 25, 116, 117, /* 440 */ 118, 113, 304, 121, 193, 204, 59, 119, 120, 121, /* 450 */ 122, 123, 124, 125, 216, 217, 193, 216, 217, 131, /* 460 */ 138, 139, 230, 102, 103, 104, 105, 106, 107, 108, /* 470 */ 109, 110, 111, 112, 113, 153, 154, 155, 156, 157, /* 480 */ 239, 240, 116, 117, 118, 76, 193, 23, 19, 25, /* 490 */ 22, 253, 23, 252, 253, 108, 87, 204, 89, 261, /* 500 */ 198, 92, 261, 116, 117, 118, 193, 306, 307, 216, /* 510 */ 217, 150, 43, 44, 45, 46, 47, 48, 49, 50, /* 520 */ 51, 52, 53, 54, 55, 56, 57, 59, 193, 216, /* 530 */ 217, 19, 239, 240, 283, 23, 106, 107, 108, 109, /* 540 */ 110, 111, 112, 113, 73, 252, 253, 142, 308, 309, /* 550 */ 138, 139, 81, 313, 145, 43, 44, 45, 46, 47, /* 560 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, /* 570 */ 307, 102, 103, 104, 105, 106, 107, 108, 109, 110, /* 580 */ 111, 112, 113, 281, 116, 117, 118, 285, 23, 193, /* 590 */ 25, 119, 59, 193, 122, 123, 124, 59, 127, 203, /* 600 */ 59, 205, 19, 268, 132, 25, 23, 22, 193, 138, /* 610 */ 139, 249, 204, 251, 102, 103, 104, 105, 106, 107, /* 620 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 630 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, /* 640 */ 57, 19, 22, 23, 59, 23, 25, 239, 240, 116, /* 650 */ 117, 118, 193, 11, 116, 117, 118, 116, 117, 118, /* 660 */ 252, 269, 22, 193, 15, 43, 44, 45, 46, 47, /* 670 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, /* 680 */ 273, 143, 193, 118, 143, 102, 103, 104, 105, 106, /* 690 */ 107, 108, 109, 110, 111, 112, 113, 76, 118, 59, /* 700 */ 241, 116, 117, 118, 304, 216, 217, 292, 143, 60, /* 710 */ 89, 241, 19, 92, 193, 193, 23, 22, 311, 312, /* 720 */ 231, 101, 22, 143, 102, 103, 104, 105, 106, 107, /* 730 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 740 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, /* 750 */ 57, 19, 193, 193, 59, 23, 116, 117, 118, 59, /* 760 */ 201, 21, 241, 304, 193, 206, 127, 128, 129, 193, /* 770 */ 128, 129, 235, 236, 304, 43, 44, 45, 46, 47, /* 780 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, /* 790 */ 22, 193, 216, 217, 193, 102, 103, 104, 105, 106, /* 800 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 193, /* 810 */ 193, 116, 117, 118, 216, 217, 116, 117, 118, 226, /* 820 */ 80, 193, 19, 235, 236, 304, 23, 211, 212, 231, /* 830 */ 204, 216, 217, 205, 102, 103, 104, 105, 106, 107, /* 840 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 850 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, /* 860 */ 57, 19, 193, 123, 76, 239, 240, 193, 253, 239, /* 870 */ 240, 239, 240, 244, 106, 107, 193, 89, 252, 193, /* 880 */ 92, 59, 252, 254, 252, 43, 44, 45, 46, 47, /* 890 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, /* 900 */ 284, 161, 216, 217, 193, 102, 103, 104, 105, 106, /* 910 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 244, /* 920 */ 187, 188, 189, 190, 7, 8, 9, 309, 195, 254, /* 930 */ 197, 313, 19, 127, 128, 129, 262, 204, 22, 117, /* 940 */ 24, 216, 217, 273, 102, 103, 104, 105, 106, 107, /* 950 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, /* 970 */ 57, 193, 239, 240, 193, 59, 19, 188, 253, 190, /* 980 */ 193, 311, 312, 16, 195, 252, 197, 193, 19, 301, /* 990 */ 302, 135, 193, 204, 216, 217, 140, 216, 217, 266, /* 1000 */ 204, 159, 45, 46, 47, 48, 49, 50, 51, 52, /* 1010 */ 53, 54, 55, 56, 57, 102, 103, 104, 105, 106, /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 12, 239, 240, /* 1030 */ 193, 298, 238, 117, 253, 239, 240, 238, 259, 260, /* 1040 */ 193, 252, 27, 193, 77, 193, 79, 204, 252, 262, /* 1050 */ 193, 299, 300, 193, 100, 266, 278, 42, 204, 102, /* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, /* 1070 */ 113, 117, 159, 216, 217, 121, 216, 217, 63, 193, /* 1080 */ 193, 193, 239, 240, 115, 116, 193, 298, 73, 240, /* 1090 */ 238, 231, 19, 239, 240, 252, 22, 24, 211, 212, /* 1100 */ 263, 252, 216, 217, 216, 217, 252, 153, 154, 155, /* 1110 */ 253, 193, 19, 144, 213, 268, 43, 44, 45, 46, /* 1120 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, /* 1130 */ 57, 193, 19, 59, 216, 217, 43, 44, 45, 46, /* 1140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, /* 1150 */ 57, 193, 19, 24, 216, 217, 43, 44, 45, 46, /* 1160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, /* 1170 */ 57, 284, 193, 208, 209, 102, 103, 104, 105, 106, /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 286, 59, 193, /* 1190 */ 232, 117, 291, 193, 193, 102, 103, 104, 105, 106, /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 193, 204, 22, /* 1210 */ 23, 193, 25, 66, 193, 102, 103, 104, 105, 106, /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 193, 193, 193, /* 1230 */ 216, 217, 85, 193, 238, 19, 16, 216, 217, 238, /* 1240 */ 193, 94, 193, 239, 240, 231, 117, 268, 35, 116, /* 1250 */ 216, 217, 216, 217, 22, 23, 252, 25, 208, 209, /* 1260 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, /* 1270 */ 54, 55, 56, 57, 193, 193, 19, 5, 59, 66, /* 1280 */ 193, 263, 10, 11, 12, 13, 14, 74, 101, 17, /* 1290 */ 193, 46, 193, 146, 193, 76, 213, 77, 263, 79, /* 1300 */ 12, 260, 30, 46, 32, 264, 87, 193, 89, 29, /* 1310 */ 263, 92, 40, 33, 232, 27, 193, 108, 102, 103, /* 1320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, /* 1330 */ 42, 138, 139, 101, 193, 116, 117, 118, 19, 20, /* 1340 */ 255, 22, 70, 130, 135, 65, 256, 257, 193, 140, /* 1350 */ 78, 63, 193, 81, 193, 36, 193, 216, 217, 193, /* 1360 */ 115, 193, 263, 193, 145, 268, 59, 48, 193, 193, /* 1370 */ 98, 193, 115, 193, 291, 216, 217, 193, 59, 216, /* 1380 */ 217, 161, 216, 217, 216, 217, 216, 217, 131, 193, /* 1390 */ 71, 193, 216, 217, 216, 217, 216, 217, 193, 260, /* 1400 */ 216, 217, 19, 264, 85, 133, 244, 100, 193, 90, /* 1410 */ 138, 139, 216, 217, 216, 217, 254, 244, 193, 100, /* 1420 */ 193, 216, 217, 116, 117, 106, 107, 254, 121, 193, /* 1430 */ 115, 216, 217, 114, 162, 116, 117, 118, 115, 244, /* 1440 */ 121, 216, 217, 216, 217, 193, 309, 193, 31, 254, /* 1450 */ 313, 309, 216, 217, 309, 313, 39, 193, 313, 309, /* 1460 */ 153, 154, 155, 313, 193, 150, 25, 144, 216, 217, /* 1470 */ 216, 217, 153, 154, 155, 156, 157, 0, 1, 2, /* 1480 */ 216, 217, 5, 149, 150, 22, 193, 10, 11, 12, /* 1490 */ 13, 14, 193, 158, 17, 160, 193, 19, 20, 116, /* 1500 */ 22, 25, 193, 24, 22, 193, 24, 30, 226, 32, /* 1510 */ 19, 20, 226, 22, 36, 193, 53, 40, 193, 216, /* 1520 */ 217, 193, 23, 193, 25, 216, 217, 36, 216, 217, /* 1530 */ 193, 99, 193, 193, 22, 193, 193, 59, 216, 217, /* 1540 */ 193, 216, 217, 193, 216, 217, 193, 70, 129, 71, /* 1550 */ 59, 129, 193, 216, 217, 78, 216, 217, 81, 216, /* 1560 */ 217, 193, 71, 85, 193, 133, 193, 126, 90, 216, /* 1570 */ 217, 152, 258, 61, 152, 98, 85, 193, 100, 193, /* 1580 */ 23, 90, 25, 121, 106, 107, 23, 216, 217, 216, /* 1590 */ 217, 100, 114, 131, 116, 117, 118, 106, 107, 121, /* 1600 */ 216, 217, 216, 217, 193, 114, 193, 116, 117, 118, /* 1610 */ 133, 22, 121, 193, 59, 138, 139, 193, 142, 193, /* 1620 */ 141, 23, 23, 25, 25, 120, 121, 216, 217, 216, /* 1630 */ 217, 153, 154, 155, 156, 157, 216, 217, 19, 162, /* 1640 */ 216, 217, 216, 217, 153, 154, 155, 156, 157, 1, /* 1650 */ 2, 193, 59, 5, 19, 20, 318, 22, 10, 11, /* 1660 */ 12, 13, 14, 193, 59, 17, 193, 23, 23, 25, /* 1670 */ 25, 36, 117, 193, 216, 217, 193, 23, 30, 25, /* 1680 */ 32, 19, 20, 23, 22, 25, 216, 217, 40, 216, /* 1690 */ 217, 7, 8, 23, 59, 25, 83, 84, 36, 23, /* 1700 */ 193, 25, 23, 23, 25, 25, 71, 153, 145, 155, /* 1710 */ 117, 153, 23, 155, 25, 23, 97, 25, 70, 193, /* 1720 */ 193, 59, 117, 236, 193, 193, 78, 193, 193, 81, /* 1730 */ 141, 193, 193, 71, 193, 100, 288, 287, 242, 255, /* 1740 */ 255, 106, 107, 108, 255, 255, 98, 243, 297, 114, /* 1750 */ 214, 116, 117, 118, 245, 191, 121, 271, 293, 267, /* 1760 */ 267, 246, 100, 246, 245, 271, 271, 293, 106, 107, /* 1770 */ 220, 271, 229, 225, 249, 219, 114, 259, 116, 117, /* 1780 */ 118, 133, 259, 121, 219, 219, 138, 139, 153, 154, /* 1790 */ 155, 156, 157, 280, 249, 243, 19, 20, 245, 22, /* 1800 */ 196, 259, 140, 259, 60, 297, 141, 297, 200, 200, /* 1810 */ 162, 38, 200, 36, 294, 153, 154, 155, 156, 157, /* 1820 */ 151, 150, 294, 283, 22, 43, 234, 18, 237, 200, /* 1830 */ 270, 272, 237, 237, 237, 18, 59, 199, 270, 149, /* 1840 */ 246, 272, 272, 200, 234, 234, 246, 246, 71, 246, /* 1850 */ 199, 158, 290, 62, 22, 200, 19, 20, 199, 22, /* 1860 */ 289, 221, 221, 200, 200, 199, 199, 115, 218, 64, /* 1870 */ 218, 218, 22, 36, 227, 126, 227, 100, 165, 221, /* 1880 */ 224, 224, 24, 106, 107, 312, 218, 305, 113, 282, /* 1890 */ 91, 114, 220, 116, 117, 118, 59, 282, 121, 218, /* 1900 */ 218, 218, 200, 317, 317, 82, 221, 265, 71, 148, /* 1910 */ 145, 265, 22, 277, 200, 158, 279, 140, 147, 25, /* 1920 */ 146, 202, 248, 250, 249, 247, 13, 250, 194, 194, /* 1930 */ 153, 154, 155, 156, 157, 6, 303, 100, 192, 192, /* 1940 */ 246, 213, 192, 106, 107, 207, 213, 207, 222, 213, /* 1950 */ 213, 114, 222, 116, 117, 118, 214, 214, 121, 4, /* 1960 */ 207, 213, 3, 22, 303, 15, 163, 16, 23, 23, /* 1970 */ 139, 151, 130, 25, 20, 142, 24, 16, 144, 1, /* 1980 */ 142, 130, 130, 61, 37, 53, 300, 151, 53, 53, /* 1990 */ 153, 154, 155, 156, 157, 53, 130, 116, 34, 1, /* 2000 */ 141, 5, 22, 115, 161, 68, 25, 68, 75, 41, /* 2010 */ 141, 115, 24, 20, 19, 131, 125, 23, 28, 22, /* 2020 */ 67, 22, 22, 22, 67, 59, 24, 96, 22, 67, /* 2030 */ 23, 149, 22, 25, 23, 23, 23, 22, 34, 141, /* 2040 */ 37, 97, 23, 23, 116, 22, 143, 25, 34, 75, /* 2050 */ 34, 34, 34, 88, 75, 34, 86, 23, 22, 34, /* 2060 */ 93, 24, 34, 25, 25, 142, 142, 23, 44, 23, /* 2070 */ 23, 23, 23, 11, 23, 25, 22, 22, 22, 141, /* 2080 */ 23, 23, 22, 22, 25, 15, 1, 23, 25, 1, /* 2090 */ 141, 135, 319, 319, 319, 319, 319, 319, 319, 141, /* 2100 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2110 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2120 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2130 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2140 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2150 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2160 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2170 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2180 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2190 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2200 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2210 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2220 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2230 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2240 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2250 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2260 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2270 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, /* 2280 */ 319, 319, 319, 319, 319, }; #define YY_SHIFT_COUNT (578) #define YY_SHIFT_MIN (0) #define YY_SHIFT_MAX (2088) static const unsigned short int yy_shift_ofst[] = { /* 0 */ 1648, 1477, 1272, 322, 322, 1, 1319, 1478, 1491, 1837, /* 10 */ 1837, 1837, 471, 0, 0, 214, 1093, 1837, 1837, 1837, /* 20 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, /* 30 */ 1837, 271, 271, 1219, 1219, 216, 88, 1, 1, 1, /* 40 */ 1, 1, 40, 111, 258, 361, 469, 512, 583, 622, /* 50 */ 693, 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, /* 60 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, /* 70 */ 1093, 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1635, /* 80 */ 1662, 1777, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, /* 90 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, /* 100 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, /* 110 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, /* 120 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, /* 130 */ 1837, 137, 181, 181, 181, 181, 181, 181, 181, 94, /* 140 */ 430, 66, 65, 112, 366, 533, 533, 740, 1257, 533, /* 150 */ 533, 79, 79, 533, 412, 412, 412, 77, 412, 123, /* 160 */ 113, 113, 113, 22, 22, 2100, 2100, 328, 328, 328, /* 170 */ 239, 468, 468, 468, 468, 1015, 1015, 409, 366, 1187, /* 180 */ 1232, 533, 533, 533, 533, 533, 533, 533, 533, 533, /* 190 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533, /* 200 */ 533, 969, 621, 621, 533, 642, 788, 788, 1133, 1133, /* 210 */ 822, 822, 67, 1193, 2100, 2100, 2100, 2100, 2100, 2100, /* 220 */ 2100, 1307, 954, 954, 585, 472, 640, 387, 695, 538, /* 230 */ 541, 700, 533, 533, 533, 533, 533, 533, 533, 533, /* 240 */ 533, 533, 222, 533, 533, 533, 533, 533, 533, 533, /* 250 */ 533, 533, 533, 533, 533, 1213, 1213, 1213, 533, 533, /* 260 */ 533, 565, 533, 533, 533, 916, 1147, 533, 533, 1288, /* 270 */ 533, 533, 533, 533, 533, 533, 533, 533, 639, 1280, /* 280 */ 209, 1129, 1129, 1129, 1129, 580, 209, 209, 1209, 768, /* 290 */ 917, 649, 1315, 1334, 405, 1334, 1383, 249, 1315, 1315, /* 300 */ 249, 1315, 405, 1383, 1441, 464, 1245, 1417, 1417, 1417, /* 310 */ 1323, 1323, 1323, 1323, 184, 184, 1335, 1476, 856, 1482, /* 320 */ 1744, 1744, 1665, 1665, 1773, 1773, 1665, 1669, 1671, 1802, /* 330 */ 1782, 1809, 1809, 1809, 1809, 1665, 1817, 1690, 1671, 1671, /* 340 */ 1690, 1802, 1782, 1690, 1782, 1690, 1665, 1817, 1693, 1791, /* 350 */ 1665, 1817, 1832, 1665, 1817, 1665, 1817, 1832, 1752, 1752, /* 360 */ 1752, 1805, 1850, 1850, 1832, 1752, 1749, 1752, 1805, 1752, /* 370 */ 1752, 1713, 1858, 1775, 1775, 1832, 1665, 1799, 1799, 1823, /* 380 */ 1823, 1761, 1765, 1890, 1665, 1757, 1761, 1771, 1774, 1690, /* 390 */ 1894, 1913, 1913, 1929, 1929, 1929, 2100, 2100, 2100, 2100, /* 400 */ 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, /* 410 */ 2100, 207, 1220, 331, 620, 967, 806, 1074, 1499, 1432, /* 420 */ 1463, 1479, 1419, 1422, 1557, 1512, 1598, 1599, 1644, 1645, /* 430 */ 1654, 1660, 1555, 1505, 1684, 1462, 1670, 1563, 1619, 1593, /* 440 */ 1676, 1679, 1613, 1680, 1554, 1558, 1689, 1692, 1605, 1589, /* 450 */ 1955, 1959, 1941, 1803, 1950, 1951, 1945, 1946, 1831, 1820, /* 460 */ 1842, 1948, 1948, 1952, 1833, 1954, 1834, 1961, 1978, 1838, /* 470 */ 1851, 1948, 1852, 1922, 1947, 1948, 1836, 1932, 1935, 1936, /* 480 */ 1942, 1866, 1881, 1964, 1859, 1998, 1996, 1980, 1888, 1843, /* 490 */ 1937, 1981, 1939, 1933, 1968, 1869, 1896, 1988, 1993, 1995, /* 500 */ 1884, 1891, 1997, 1953, 1999, 2000, 1994, 2001, 1957, 1966, /* 510 */ 2002, 1931, 1990, 2006, 1962, 2003, 2007, 2004, 1882, 2010, /* 520 */ 2011, 2012, 2008, 2013, 2015, 1944, 1898, 2019, 2020, 1928, /* 530 */ 2014, 2023, 1903, 2022, 2016, 2017, 2018, 2021, 1965, 1974, /* 540 */ 1970, 2024, 1979, 1967, 2025, 2034, 2036, 2037, 2038, 2039, /* 550 */ 2028, 1923, 1924, 2044, 2022, 2046, 2047, 2048, 2049, 2050, /* 560 */ 2051, 2054, 2062, 2055, 2056, 2057, 2058, 2060, 2061, 2059, /* 570 */ 1956, 1938, 1949, 1958, 2063, 2064, 2070, 2085, 2088, }; #define YY_REDUCE_COUNT (410) #define YY_REDUCE_MIN (-271) #define YY_REDUCE_MAX (1753) static const short yy_reduce_ofst[] = { /* 0 */ -125, 733, 789, 241, 293, -123, -193, -191, -183, -187, /* 10 */ 166, 238, 133, -207, -199, -267, -176, -6, 204, 489, /* 20 */ 576, 598, -175, 686, 860, 615, 725, 1014, 778, 781, /* 30 */ 857, 616, 887, 87, 240, -192, 408, 626, 796, 843, /* 40 */ 854, 1004, -271, -271, -271, -271, -271, -271, -271, -271, /* 50 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271, /* 60 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271, /* 70 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, 80, /* 80 */ 83, 313, 886, 888, 918, 938, 1021, 1034, 1036, 1141, /* 90 */ 1159, 1163, 1166, 1168, 1170, 1176, 1178, 1180, 1184, 1196, /* 100 */ 1198, 1205, 1215, 1225, 1227, 1236, 1252, 1254, 1264, 1303, /* 110 */ 1309, 1312, 1322, 1325, 1328, 1337, 1340, 1343, 1353, 1371, /* 120 */ 1373, 1384, 1386, 1411, 1413, 1420, 1424, 1426, 1458, 1470, /* 130 */ 1473, -271, -271, -271, -271, -271, -271, -271, -271, -271, /* 140 */ -271, -271, 138, 459, 396, -158, 470, 302, -212, 521, /* 150 */ 201, -195, -92, 559, 630, 632, 630, -271, 632, 901, /* 160 */ 63, 407, 670, -271, -271, -271, -271, 161, 161, 161, /* 170 */ 251, 335, 847, 979, 1097, 537, 588, 618, 628, 688, /* 180 */ 688, -166, -161, 674, 787, 794, 799, 852, 996, -122, /* 190 */ 837, -120, 1018, 1035, 415, 1047, 1001, 958, 1082, 400, /* 200 */ 1099, 779, 1137, 1142, 263, 1083, 1145, 1150, 1041, 1139, /* 210 */ 965, 1050, 362, 849, 752, 629, 675, 1162, 1173, 1090, /* 220 */ 1195, -194, 56, 185, -135, 232, 522, 560, 571, 601, /* 230 */ 617, 669, 683, 711, 850, 893, 1000, 1040, 1049, 1081, /* 240 */ 1087, 1101, 392, 1114, 1123, 1155, 1161, 1175, 1271, 1293, /* 250 */ 1299, 1330, 1339, 1342, 1347, 593, 1282, 1286, 1350, 1359, /* 260 */ 1368, 1314, 1480, 1483, 1507, 1085, 1338, 1526, 1527, 1487, /* 270 */ 1531, 560, 1532, 1534, 1535, 1538, 1539, 1541, 1448, 1450, /* 280 */ 1496, 1484, 1485, 1489, 1490, 1314, 1496, 1496, 1504, 1536, /* 290 */ 1564, 1451, 1486, 1492, 1509, 1493, 1465, 1515, 1494, 1495, /* 300 */ 1517, 1500, 1519, 1474, 1550, 1543, 1548, 1556, 1565, 1566, /* 310 */ 1518, 1523, 1542, 1544, 1525, 1545, 1513, 1553, 1552, 1604, /* 320 */ 1508, 1510, 1608, 1609, 1520, 1528, 1612, 1540, 1559, 1560, /* 330 */ 1592, 1591, 1595, 1596, 1597, 1629, 1638, 1594, 1569, 1570, /* 340 */ 1600, 1568, 1610, 1601, 1611, 1603, 1643, 1651, 1562, 1571, /* 350 */ 1655, 1659, 1640, 1663, 1666, 1664, 1667, 1641, 1650, 1652, /* 360 */ 1653, 1647, 1656, 1657, 1658, 1668, 1672, 1681, 1649, 1682, /* 370 */ 1683, 1573, 1582, 1607, 1615, 1685, 1702, 1586, 1587, 1642, /* 380 */ 1646, 1673, 1675, 1636, 1714, 1637, 1677, 1674, 1678, 1694, /* 390 */ 1719, 1734, 1735, 1746, 1747, 1750, 1633, 1661, 1686, 1738, /* 400 */ 1728, 1733, 1736, 1737, 1740, 1726, 1730, 1742, 1743, 1748, /* 410 */ 1753, }; static const YYACTIONTYPE yy_default[] = { /* 0 */ 1648, 1648, 1648, 1478, 1243, 1354, 1243, 1243, 1243, 1478, /* 10 */ 1478, 1478, 1243, 1384, 1384, 1531, 1276, 1243, 1243, 1243, /* 20 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1477, 1243, /* 30 */ 1243, 1243, 1243, 1564, 1564, 1243, 1243, 1243, 1243, 1243, /* 40 */ 1243, 1243, 1243, 1393, 1243, 1400, 1243, 1243, 1243, 1243, /* 50 */ 1243, 1479, 1480, 1243, 1243, 1243, 1530, 1532, 1495, 1407, /* 60 */ 1406, 1405, 1404, 1513, 1372, 1398, 1391, 1395, 1474, 1475, /* 70 */ 1473, 1626, 1480, 1479, 1243, 1394, 1442, 1458, 1441, 1243, /* 80 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 90 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 100 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 110 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 120 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 130 */ 1243, 1450, 1457, 1456, 1455, 1464, 1454, 1451, 1444, 1443, /* 140 */ 1445, 1446, 1243, 1243, 1267, 1243, 1243, 1264, 1318, 1243, /* 150 */ 1243, 1243, 1243, 1243, 1550, 1549, 1243, 1447, 1243, 1276, /* 160 */ 1435, 1434, 1433, 1461, 1448, 1460, 1459, 1538, 1600, 1599, /* 170 */ 1496, 1243, 1243, 1243, 1243, 1243, 1243, 1564, 1243, 1243, /* 180 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 190 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 200 */ 1243, 1374, 1564, 1564, 1243, 1276, 1564, 1564, 1375, 1375, /* 210 */ 1272, 1272, 1378, 1243, 1545, 1345, 1345, 1345, 1345, 1354, /* 220 */ 1345, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 230 */ 1243, 1243, 1243, 1243, 1243, 1243, 1535, 1533, 1243, 1243, /* 240 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 250 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 260 */ 1243, 1243, 1243, 1243, 1243, 1350, 1243, 1243, 1243, 1243, /* 270 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1593, 1243, 1508, /* 280 */ 1332, 1350, 1350, 1350, 1350, 1352, 1333, 1331, 1344, 1277, /* 290 */ 1250, 1640, 1410, 1399, 1351, 1399, 1637, 1397, 1410, 1410, /* 300 */ 1397, 1410, 1351, 1637, 1293, 1615, 1288, 1384, 1384, 1384, /* 310 */ 1374, 1374, 1374, 1374, 1378, 1378, 1476, 1351, 1344, 1243, /* 320 */ 1640, 1640, 1360, 1360, 1639, 1639, 1360, 1496, 1623, 1419, /* 330 */ 1321, 1327, 1327, 1327, 1327, 1360, 1261, 1397, 1623, 1623, /* 340 */ 1397, 1419, 1321, 1397, 1321, 1397, 1360, 1261, 1512, 1634, /* 350 */ 1360, 1261, 1486, 1360, 1261, 1360, 1261, 1486, 1319, 1319, /* 360 */ 1319, 1308, 1243, 1243, 1486, 1319, 1293, 1319, 1308, 1319, /* 370 */ 1319, 1582, 1243, 1490, 1490, 1486, 1360, 1574, 1574, 1387, /* 380 */ 1387, 1392, 1378, 1481, 1360, 1243, 1392, 1390, 1388, 1397, /* 390 */ 1311, 1596, 1596, 1592, 1592, 1592, 1645, 1645, 1545, 1608, /* 400 */ 1276, 1276, 1276, 1276, 1608, 1295, 1295, 1277, 1277, 1276, /* 410 */ 1608, 1243, 1243, 1243, 1243, 1243, 1243, 1603, 1243, 1540, /* 420 */ 1497, 1364, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 430 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1551, 1243, /* 440 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1424, /* 450 */ 1243, 1246, 1542, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 460 */ 1243, 1401, 1402, 1365, 1243, 1243, 1243, 1243, 1243, 1243, /* 470 */ 1243, 1416, 1243, 1243, 1243, 1411, 1243, 1243, 1243, 1243, /* 480 */ 1243, 1243, 1243, 1243, 1636, 1243, 1243, 1243, 1243, 1243, /* 490 */ 1243, 1511, 1510, 1243, 1243, 1362, 1243, 1243, 1243, 1243, /* 500 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1291, /* 510 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 520 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, /* 530 */ 1243, 1243, 1243, 1389, 1243, 1243, 1243, 1243, 1243, 1243, /* 540 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1579, 1379, /* 550 */ 1243, 1243, 1243, 1243, 1627, 1243, 1243, 1243, 1243, 1243, /* 560 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1619, /* 570 */ 1335, 1425, 1243, 1428, 1265, 1243, 1255, 1243, 1243, }; /********** End of lemon-generated parsing tables *****************************/ /* The next table maps tokens (terminal symbols) into fallback tokens. ** If a construct like the following: ** ** %fallback ID X Y Z. ** ** appears in the grammar, then ID becomes a fallback token for X, Y, ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser ** but it does not parse, the type of the token is changed to ID and ** the parse is retried before an error is thrown. ** ** This feature can be used, for example, to cause some keywords in a language ** to revert to identifiers if they keyword does not apply in the context where ** it appears. */ #ifdef YYFALLBACK static const YYCODETYPE yyFallback[] = { 0, /* $ => nothing */ 0, /* SEMI => nothing */ 59, /* EXPLAIN => ID */ 59, /* QUERY => ID */ 59, /* PLAN => ID */ 59, /* BEGIN => ID */ 0, /* TRANSACTION => nothing */ 59, /* DEFERRED => ID */ 59, /* IMMEDIATE => ID */ 59, /* EXCLUSIVE => ID */ 0, /* COMMIT => nothing */ 59, /* END => ID */ 59, /* ROLLBACK => ID */ 59, /* SAVEPOINT => ID */ 59, /* RELEASE => ID */ 0, /* TO => nothing */ 0, /* TABLE => nothing */ 0, /* CREATE => nothing */ 59, /* IF => ID */ 0, /* NOT => nothing */ 0, /* EXISTS => nothing */ 59, /* TEMP => ID */ 0, /* LP => nothing */ 0, /* RP => nothing */ 0, /* AS => nothing */ 0, /* COMMA => nothing */ 59, /* WITHOUT => ID */ 59, /* ABORT => ID */ 59, /* ACTION => ID */ 59, /* AFTER => ID */ 59, /* ANALYZE => ID */ 59, /* ASC => ID */ 59, /* ATTACH => ID */ 59, /* BEFORE => ID */ 59, /* BY => ID */ 59, /* CASCADE => ID */ 59, /* CAST => ID */ 59, /* CONFLICT => ID */ 59, /* DATABASE => ID */ 59, /* DESC => ID */ 59, /* DETACH => ID */ 59, /* EACH => ID */ 59, /* FAIL => ID */ 0, /* OR => nothing */ 0, /* AND => nothing */ 0, /* IS => nothing */ 59, /* MATCH => ID */ 59, /* LIKE_KW => ID */ 0, /* BETWEEN => nothing */ 0, /* IN => nothing */ 0, /* ISNULL => nothing */ 0, /* NOTNULL => nothing */ 0, /* NE => nothing */ 0, /* EQ => nothing */ 0, /* GT => nothing */ 0, /* LE => nothing */ 0, /* LT => nothing */ 0, /* GE => nothing */ 0, /* ESCAPE => nothing */ 0, /* ID => nothing */ 59, /* COLUMNKW => ID */ 59, /* DO => ID */ 59, /* FOR => ID */ 59, /* IGNORE => ID */ 59, /* INITIALLY => ID */ 59, /* INSTEAD => ID */ 59, /* NO => ID */ 59, /* KEY => ID */ 59, /* OF => ID */ 59, /* OFFSET => ID */ 59, /* PRAGMA => ID */ 59, /* RAISE => ID */ 59, /* RECURSIVE => ID */ 59, /* REPLACE => ID */ 59, /* RESTRICT => ID */ 59, /* ROW => ID */ 59, /* ROWS => ID */ 59, /* TRIGGER => ID */ 59, /* VACUUM => ID */ 59, /* VIEW => ID */ 59, /* VIRTUAL => ID */ 59, /* WITH => ID */ 59, /* NULLS => ID */ 59, /* FIRST => ID */ 59, /* LAST => ID */ 59, /* CURRENT => ID */ 59, /* FOLLOWING => ID */ 59, /* PARTITION => ID */ 59, /* PRECEDING => ID */ 59, /* RANGE => ID */ 59, /* UNBOUNDED => ID */ 59, /* EXCLUDE => ID */ 59, /* GROUPS => ID */ 59, /* OTHERS => ID */ 59, /* TIES => ID */ 59, /* GENERATED => ID */ 59, /* ALWAYS => ID */ 59, /* MATERIALIZED => ID */ 59, /* REINDEX => ID */ 59, /* RENAME => ID */ 59, /* CTIME_KW => ID */ 0, /* ANY => nothing */ 0, /* BITAND => nothing */ 0, /* BITOR => nothing */ 0, /* LSHIFT => nothing */ 0, /* RSHIFT => nothing */ 0, /* PLUS => nothing */ 0, /* MINUS => nothing */ 0, /* STAR => nothing */ 0, /* SLASH => nothing */ 0, /* REM => nothing */ 0, /* CONCAT => nothing */ 0, /* PTR => nothing */ 0, /* COLLATE => nothing */ 0, /* BITNOT => nothing */ 0, /* ON => nothing */ 0, /* INDEXED => nothing */ 0, /* STRING => nothing */ 0, /* JOIN_KW => nothing */ 0, /* CONSTRAINT => nothing */ 0, /* DEFAULT => nothing */ 0, /* NULL => nothing */ 0, /* PRIMARY => nothing */ 0, /* UNIQUE => nothing */ 0, /* CHECK => nothing */ 0, /* REFERENCES => nothing */ 0, /* AUTOINCR => nothing */ 0, /* INSERT => nothing */ 0, /* DELETE => nothing */ 0, /* UPDATE => nothing */ 0, /* SET => nothing */ 0, /* DEFERRABLE => nothing */ 0, /* FOREIGN => nothing */ 0, /* DROP => nothing */ 0, /* UNION => nothing */ 0, /* ALL => nothing */ 0, /* EXCEPT => nothing */ 0, /* INTERSECT => nothing */ 0, /* SELECT => nothing */ 0, /* VALUES => nothing */ 0, /* DISTINCT => nothing */ 0, /* DOT => nothing */ 0, /* FROM => nothing */ 0, /* JOIN => nothing */ 0, /* USING => nothing */ 0, /* ORDER => nothing */ 0, /* GROUP => nothing */ 0, /* HAVING => nothing */ 0, /* LIMIT => nothing */ 0, /* WHERE => nothing */ 0, /* RETURNING => nothing */ 0, /* INTO => nothing */ 0, /* NOTHING => nothing */ 0, /* FLOAT => nothing */ 0, /* BLOB => nothing */ 0, /* INTEGER => nothing */ 0, /* VARIABLE => nothing */ 0, /* CASE => nothing */ 0, /* WHEN => nothing */ 0, /* THEN => nothing */ 0, /* ELSE => nothing */ 0, /* INDEX => nothing */ 0, /* ALTER => nothing */ 0, /* ADD => nothing */ 0, /* WINDOW => nothing */ 0, /* OVER => nothing */ 0, /* FILTER => nothing */ 0, /* COLUMN => nothing */ 0, /* AGG_FUNCTION => nothing */ 0, /* AGG_COLUMN => nothing */ 0, /* TRUEFALSE => nothing */ 0, /* ISNOT => nothing */ 0, /* FUNCTION => nothing */ 0, /* UMINUS => nothing */ 0, /* UPLUS => nothing */ 0, /* TRUTH => nothing */ 0, /* REGISTER => nothing */ 0, /* VECTOR => nothing */ 0, /* SELECT_COLUMN => nothing */ 0, /* IF_NULL_ROW => nothing */ 0, /* ASTERISK => nothing */ 0, /* SPAN => nothing */ 0, /* ERROR => nothing */ 0, /* SPACE => nothing */ 0, /* ILLEGAL => nothing */ }; #endif /* YYFALLBACK */ /* The following structure represents a single element of the ** parser's stack. Information stored includes: ** ** + The state number for the parser at this level of the stack. ** ** + The value of the token stored at this level of the stack. ** (In other words, the "major" token.) ** ** + The semantic value stored at this level of the stack. This is ** the information used by the action routines in the grammar. ** It is sometimes called the "minor" token. ** ** After the "shift" half of a SHIFTREDUCE action, the stateno field ** actually contains the reduce action for the second half of the ** SHIFTREDUCE. */ struct yyStackEntry { YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ YYCODETYPE major; /* The major token value. This is the code ** number for the token at this stack level */ YYMINORTYPE minor; /* The user-supplied minor token value. This ** is the value of the token */ }; typedef struct yyStackEntry yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct yyParser { yyStackEntry *yytos; /* Pointer to top element of the stack */ #ifdef YYTRACKMAXSTACKDEPTH int yyhwm; /* High-water mark of the stack */ #endif #ifndef YYNOERRORRECOVERY int yyerrcnt; /* Shifts left before out of the error */ #endif sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ sqlite3ParserCTX_SDECL /* A place to hold %extra_context */ #if YYSTACKDEPTH<=0 int yystksz; /* Current side of the stack */ yyStackEntry *yystack; /* The parser's stack */ yyStackEntry yystk0; /* First stack entry */ #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; /* #include */ #ifndef NDEBUG /* #include */ static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG /* ** Turn parser tracing on by giving a stream to which to write the trace ** and a prompt to preface each trace message. Tracing is turned off ** by making either argument NULL ** ** Inputs: **
      **
    • A FILE* to which trace output should be written. ** If NULL, then tracing is turned off. **
    • A prefix string written at the beginning of every ** line of trace output. If NULL, then tracing is ** turned off. **
    ** ** Outputs: ** None. */ SQLITE_PRIVATE void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){ yyTraceFILE = TraceFILE; yyTracePrompt = zTracePrompt; if( yyTraceFILE==0 ) yyTracePrompt = 0; else if( yyTracePrompt==0 ) yyTraceFILE = 0; } #endif /* NDEBUG */ #if defined(YYCOVERAGE) || !defined(NDEBUG) /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ static const char *const yyTokenName[] = { /* 0 */ "$", /* 1 */ "SEMI", /* 2 */ "EXPLAIN", /* 3 */ "QUERY", /* 4 */ "PLAN", /* 5 */ "BEGIN", /* 6 */ "TRANSACTION", /* 7 */ "DEFERRED", /* 8 */ "IMMEDIATE", /* 9 */ "EXCLUSIVE", /* 10 */ "COMMIT", /* 11 */ "END", /* 12 */ "ROLLBACK", /* 13 */ "SAVEPOINT", /* 14 */ "RELEASE", /* 15 */ "TO", /* 16 */ "TABLE", /* 17 */ "CREATE", /* 18 */ "IF", /* 19 */ "NOT", /* 20 */ "EXISTS", /* 21 */ "TEMP", /* 22 */ "LP", /* 23 */ "RP", /* 24 */ "AS", /* 25 */ "COMMA", /* 26 */ "WITHOUT", /* 27 */ "ABORT", /* 28 */ "ACTION", /* 29 */ "AFTER", /* 30 */ "ANALYZE", /* 31 */ "ASC", /* 32 */ "ATTACH", /* 33 */ "BEFORE", /* 34 */ "BY", /* 35 */ "CASCADE", /* 36 */ "CAST", /* 37 */ "CONFLICT", /* 38 */ "DATABASE", /* 39 */ "DESC", /* 40 */ "DETACH", /* 41 */ "EACH", /* 42 */ "FAIL", /* 43 */ "OR", /* 44 */ "AND", /* 45 */ "IS", /* 46 */ "MATCH", /* 47 */ "LIKE_KW", /* 48 */ "BETWEEN", /* 49 */ "IN", /* 50 */ "ISNULL", /* 51 */ "NOTNULL", /* 52 */ "NE", /* 53 */ "EQ", /* 54 */ "GT", /* 55 */ "LE", /* 56 */ "LT", /* 57 */ "GE", /* 58 */ "ESCAPE", /* 59 */ "ID", /* 60 */ "COLUMNKW", /* 61 */ "DO", /* 62 */ "FOR", /* 63 */ "IGNORE", /* 64 */ "INITIALLY", /* 65 */ "INSTEAD", /* 66 */ "NO", /* 67 */ "KEY", /* 68 */ "OF", /* 69 */ "OFFSET", /* 70 */ "PRAGMA", /* 71 */ "RAISE", /* 72 */ "RECURSIVE", /* 73 */ "REPLACE", /* 74 */ "RESTRICT", /* 75 */ "ROW", /* 76 */ "ROWS", /* 77 */ "TRIGGER", /* 78 */ "VACUUM", /* 79 */ "VIEW", /* 80 */ "VIRTUAL", /* 81 */ "WITH", /* 82 */ "NULLS", /* 83 */ "FIRST", /* 84 */ "LAST", /* 85 */ "CURRENT", /* 86 */ "FOLLOWING", /* 87 */ "PARTITION", /* 88 */ "PRECEDING", /* 89 */ "RANGE", /* 90 */ "UNBOUNDED", /* 91 */ "EXCLUDE", /* 92 */ "GROUPS", /* 93 */ "OTHERS", /* 94 */ "TIES", /* 95 */ "GENERATED", /* 96 */ "ALWAYS", /* 97 */ "MATERIALIZED", /* 98 */ "REINDEX", /* 99 */ "RENAME", /* 100 */ "CTIME_KW", /* 101 */ "ANY", /* 102 */ "BITAND", /* 103 */ "BITOR", /* 104 */ "LSHIFT", /* 105 */ "RSHIFT", /* 106 */ "PLUS", /* 107 */ "MINUS", /* 108 */ "STAR", /* 109 */ "SLASH", /* 110 */ "REM", /* 111 */ "CONCAT", /* 112 */ "PTR", /* 113 */ "COLLATE", /* 114 */ "BITNOT", /* 115 */ "ON", /* 116 */ "INDEXED", /* 117 */ "STRING", /* 118 */ "JOIN_KW", /* 119 */ "CONSTRAINT", /* 120 */ "DEFAULT", /* 121 */ "NULL", /* 122 */ "PRIMARY", /* 123 */ "UNIQUE", /* 124 */ "CHECK", /* 125 */ "REFERENCES", /* 126 */ "AUTOINCR", /* 127 */ "INSERT", /* 128 */ "DELETE", /* 129 */ "UPDATE", /* 130 */ "SET", /* 131 */ "DEFERRABLE", /* 132 */ "FOREIGN", /* 133 */ "DROP", /* 134 */ "UNION", /* 135 */ "ALL", /* 136 */ "EXCEPT", /* 137 */ "INTERSECT", /* 138 */ "SELECT", /* 139 */ "VALUES", /* 140 */ "DISTINCT", /* 141 */ "DOT", /* 142 */ "FROM", /* 143 */ "JOIN", /* 144 */ "USING", /* 145 */ "ORDER", /* 146 */ "GROUP", /* 147 */ "HAVING", /* 148 */ "LIMIT", /* 149 */ "WHERE", /* 150 */ "RETURNING", /* 151 */ "INTO", /* 152 */ "NOTHING", /* 153 */ "FLOAT", /* 154 */ "BLOB", /* 155 */ "INTEGER", /* 156 */ "VARIABLE", /* 157 */ "CASE", /* 158 */ "WHEN", /* 159 */ "THEN", /* 160 */ "ELSE", /* 161 */ "INDEX", /* 162 */ "ALTER", /* 163 */ "ADD", /* 164 */ "WINDOW", /* 165 */ "OVER", /* 166 */ "FILTER", /* 167 */ "COLUMN", /* 168 */ "AGG_FUNCTION", /* 169 */ "AGG_COLUMN", /* 170 */ "TRUEFALSE", /* 171 */ "ISNOT", /* 172 */ "FUNCTION", /* 173 */ "UMINUS", /* 174 */ "UPLUS", /* 175 */ "TRUTH", /* 176 */ "REGISTER", /* 177 */ "VECTOR", /* 178 */ "SELECT_COLUMN", /* 179 */ "IF_NULL_ROW", /* 180 */ "ASTERISK", /* 181 */ "SPAN", /* 182 */ "ERROR", /* 183 */ "SPACE", /* 184 */ "ILLEGAL", /* 185 */ "input", /* 186 */ "cmdlist", /* 187 */ "ecmd", /* 188 */ "cmdx", /* 189 */ "explain", /* 190 */ "cmd", /* 191 */ "transtype", /* 192 */ "trans_opt", /* 193 */ "nm", /* 194 */ "savepoint_opt", /* 195 */ "create_table", /* 196 */ "create_table_args", /* 197 */ "createkw", /* 198 */ "temp", /* 199 */ "ifnotexists", /* 200 */ "dbnm", /* 201 */ "columnlist", /* 202 */ "conslist_opt", /* 203 */ "table_option_set", /* 204 */ "select", /* 205 */ "table_option", /* 206 */ "columnname", /* 207 */ "carglist", /* 208 */ "typetoken", /* 209 */ "typename", /* 210 */ "signed", /* 211 */ "plus_num", /* 212 */ "minus_num", /* 213 */ "scanpt", /* 214 */ "scantok", /* 215 */ "ccons", /* 216 */ "term", /* 217 */ "expr", /* 218 */ "onconf", /* 219 */ "sortorder", /* 220 */ "autoinc", /* 221 */ "eidlist_opt", /* 222 */ "refargs", /* 223 */ "defer_subclause", /* 224 */ "generated", /* 225 */ "refarg", /* 226 */ "refact", /* 227 */ "init_deferred_pred_opt", /* 228 */ "conslist", /* 229 */ "tconscomma", /* 230 */ "tcons", /* 231 */ "sortlist", /* 232 */ "eidlist", /* 233 */ "defer_subclause_opt", /* 234 */ "orconf", /* 235 */ "resolvetype", /* 236 */ "raisetype", /* 237 */ "ifexists", /* 238 */ "fullname", /* 239 */ "selectnowith", /* 240 */ "oneselect", /* 241 */ "wqlist", /* 242 */ "multiselect_op", /* 243 */ "distinct", /* 244 */ "selcollist", /* 245 */ "from", /* 246 */ "where_opt", /* 247 */ "groupby_opt", /* 248 */ "having_opt", /* 249 */ "orderby_opt", /* 250 */ "limit_opt", /* 251 */ "window_clause", /* 252 */ "values", /* 253 */ "nexprlist", /* 254 */ "sclp", /* 255 */ "as", /* 256 */ "seltablist", /* 257 */ "stl_prefix", /* 258 */ "joinop", /* 259 */ "on_using", /* 260 */ "indexed_by", /* 261 */ "exprlist", /* 262 */ "xfullname", /* 263 */ "idlist", /* 264 */ "indexed_opt", /* 265 */ "nulls", /* 266 */ "with", /* 267 */ "where_opt_ret", /* 268 */ "setlist", /* 269 */ "insert_cmd", /* 270 */ "idlist_opt", /* 271 */ "upsert", /* 272 */ "returning", /* 273 */ "filter_over", /* 274 */ "likeop", /* 275 */ "between_op", /* 276 */ "in_op", /* 277 */ "paren_exprlist", /* 278 */ "case_operand", /* 279 */ "case_exprlist", /* 280 */ "case_else", /* 281 */ "uniqueflag", /* 282 */ "collate", /* 283 */ "vinto", /* 284 */ "nmnum", /* 285 */ "trigger_decl", /* 286 */ "trigger_cmd_list", /* 287 */ "trigger_time", /* 288 */ "trigger_event", /* 289 */ "foreach_clause", /* 290 */ "when_clause", /* 291 */ "trigger_cmd", /* 292 */ "trnm", /* 293 */ "tridxby", /* 294 */ "database_kw_opt", /* 295 */ "key_opt", /* 296 */ "add_column_fullname", /* 297 */ "kwcolumn_opt", /* 298 */ "create_vtab", /* 299 */ "vtabarglist", /* 300 */ "vtabarg", /* 301 */ "vtabargtoken", /* 302 */ "lp", /* 303 */ "anylist", /* 304 */ "wqitem", /* 305 */ "wqas", /* 306 */ "windowdefn_list", /* 307 */ "windowdefn", /* 308 */ "window", /* 309 */ "frame_opt", /* 310 */ "part_opt", /* 311 */ "filter_clause", /* 312 */ "over_clause", /* 313 */ "range_or_rows", /* 314 */ "frame_bound", /* 315 */ "frame_bound_s", /* 316 */ "frame_bound_e", /* 317 */ "frame_exclude_opt", /* 318 */ "frame_exclude", }; #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ #ifndef NDEBUG /* For tracing reduce actions, the names of all rules are required. */ static const char *const yyRuleName[] = { /* 0 */ "explain ::= EXPLAIN", /* 1 */ "explain ::= EXPLAIN QUERY PLAN", /* 2 */ "cmdx ::= cmd", /* 3 */ "cmd ::= BEGIN transtype trans_opt", /* 4 */ "transtype ::=", /* 5 */ "transtype ::= DEFERRED", /* 6 */ "transtype ::= IMMEDIATE", /* 7 */ "transtype ::= EXCLUSIVE", /* 8 */ "cmd ::= COMMIT|END trans_opt", /* 9 */ "cmd ::= ROLLBACK trans_opt", /* 10 */ "cmd ::= SAVEPOINT nm", /* 11 */ "cmd ::= RELEASE savepoint_opt nm", /* 12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", /* 13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", /* 14 */ "createkw ::= CREATE", /* 15 */ "ifnotexists ::=", /* 16 */ "ifnotexists ::= IF NOT EXISTS", /* 17 */ "temp ::= TEMP", /* 18 */ "temp ::=", /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP table_option_set", /* 20 */ "create_table_args ::= AS select", /* 21 */ "table_option_set ::=", /* 22 */ "table_option_set ::= table_option_set COMMA table_option", /* 23 */ "table_option ::= WITHOUT nm", /* 24 */ "table_option ::= nm", /* 25 */ "columnname ::= nm typetoken", /* 26 */ "typetoken ::=", /* 27 */ "typetoken ::= typename LP signed RP", /* 28 */ "typetoken ::= typename LP signed COMMA signed RP", /* 29 */ "typename ::= typename ID|STRING", /* 30 */ "scanpt ::=", /* 31 */ "scantok ::=", /* 32 */ "ccons ::= CONSTRAINT nm", /* 33 */ "ccons ::= DEFAULT scantok term", /* 34 */ "ccons ::= DEFAULT LP expr RP", /* 35 */ "ccons ::= DEFAULT PLUS scantok term", /* 36 */ "ccons ::= DEFAULT MINUS scantok term", /* 37 */ "ccons ::= DEFAULT scantok ID|INDEXED", /* 38 */ "ccons ::= NOT NULL onconf", /* 39 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", /* 40 */ "ccons ::= UNIQUE onconf", /* 41 */ "ccons ::= CHECK LP expr RP", /* 42 */ "ccons ::= REFERENCES nm eidlist_opt refargs", /* 43 */ "ccons ::= defer_subclause", /* 44 */ "ccons ::= COLLATE ID|STRING", /* 45 */ "generated ::= LP expr RP", /* 46 */ "generated ::= LP expr RP ID", /* 47 */ "autoinc ::=", /* 48 */ "autoinc ::= AUTOINCR", /* 49 */ "refargs ::=", /* 50 */ "refargs ::= refargs refarg", /* 51 */ "refarg ::= MATCH nm", /* 52 */ "refarg ::= ON INSERT refact", /* 53 */ "refarg ::= ON DELETE refact", /* 54 */ "refarg ::= ON UPDATE refact", /* 55 */ "refact ::= SET NULL", /* 56 */ "refact ::= SET DEFAULT", /* 57 */ "refact ::= CASCADE", /* 58 */ "refact ::= RESTRICT", /* 59 */ "refact ::= NO ACTION", /* 60 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", /* 61 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", /* 62 */ "init_deferred_pred_opt ::=", /* 63 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", /* 64 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", /* 65 */ "conslist_opt ::=", /* 66 */ "tconscomma ::= COMMA", /* 67 */ "tcons ::= CONSTRAINT nm", /* 68 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", /* 69 */ "tcons ::= UNIQUE LP sortlist RP onconf", /* 70 */ "tcons ::= CHECK LP expr RP onconf", /* 71 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", /* 72 */ "defer_subclause_opt ::=", /* 73 */ "onconf ::=", /* 74 */ "onconf ::= ON CONFLICT resolvetype", /* 75 */ "orconf ::=", /* 76 */ "orconf ::= OR resolvetype", /* 77 */ "resolvetype ::= IGNORE", /* 78 */ "resolvetype ::= REPLACE", /* 79 */ "cmd ::= DROP TABLE ifexists fullname", /* 80 */ "ifexists ::= IF EXISTS", /* 81 */ "ifexists ::=", /* 82 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", /* 83 */ "cmd ::= DROP VIEW ifexists fullname", /* 84 */ "cmd ::= select", /* 85 */ "select ::= WITH wqlist selectnowith", /* 86 */ "select ::= WITH RECURSIVE wqlist selectnowith", /* 87 */ "select ::= selectnowith", /* 88 */ "selectnowith ::= selectnowith multiselect_op oneselect", /* 89 */ "multiselect_op ::= UNION", /* 90 */ "multiselect_op ::= UNION ALL", /* 91 */ "multiselect_op ::= EXCEPT|INTERSECT", /* 92 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", /* 93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", /* 94 */ "values ::= VALUES LP nexprlist RP", /* 95 */ "values ::= values COMMA LP nexprlist RP", /* 96 */ "distinct ::= DISTINCT", /* 97 */ "distinct ::= ALL", /* 98 */ "distinct ::=", /* 99 */ "sclp ::=", /* 100 */ "selcollist ::= sclp scanpt expr scanpt as", /* 101 */ "selcollist ::= sclp scanpt STAR", /* 102 */ "selcollist ::= sclp scanpt nm DOT STAR", /* 103 */ "as ::= AS nm", /* 104 */ "as ::=", /* 105 */ "from ::=", /* 106 */ "from ::= FROM seltablist", /* 107 */ "stl_prefix ::= seltablist joinop", /* 108 */ "stl_prefix ::=", /* 109 */ "seltablist ::= stl_prefix nm dbnm as on_using", /* 110 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using", /* 111 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using", /* 112 */ "seltablist ::= stl_prefix LP select RP as on_using", /* 113 */ "seltablist ::= stl_prefix LP seltablist RP as on_using", /* 114 */ "dbnm ::=", /* 115 */ "dbnm ::= DOT nm", /* 116 */ "fullname ::= nm", /* 117 */ "fullname ::= nm DOT nm", /* 118 */ "xfullname ::= nm", /* 119 */ "xfullname ::= nm DOT nm", /* 120 */ "xfullname ::= nm DOT nm AS nm", /* 121 */ "xfullname ::= nm AS nm", /* 122 */ "joinop ::= COMMA|JOIN", /* 123 */ "joinop ::= JOIN_KW JOIN", /* 124 */ "joinop ::= JOIN_KW nm JOIN", /* 125 */ "joinop ::= JOIN_KW nm nm JOIN", /* 126 */ "on_using ::= ON expr", /* 127 */ "on_using ::= USING LP idlist RP", /* 128 */ "on_using ::=", /* 129 */ "indexed_opt ::=", /* 130 */ "indexed_by ::= INDEXED BY nm", /* 131 */ "indexed_by ::= NOT INDEXED", /* 132 */ "orderby_opt ::=", /* 133 */ "orderby_opt ::= ORDER BY sortlist", /* 134 */ "sortlist ::= sortlist COMMA expr sortorder nulls", /* 135 */ "sortlist ::= expr sortorder nulls", /* 136 */ "sortorder ::= ASC", /* 137 */ "sortorder ::= DESC", /* 138 */ "sortorder ::=", /* 139 */ "nulls ::= NULLS FIRST", /* 140 */ "nulls ::= NULLS LAST", /* 141 */ "nulls ::=", /* 142 */ "groupby_opt ::=", /* 143 */ "groupby_opt ::= GROUP BY nexprlist", /* 144 */ "having_opt ::=", /* 145 */ "having_opt ::= HAVING expr", /* 146 */ "limit_opt ::=", /* 147 */ "limit_opt ::= LIMIT expr", /* 148 */ "limit_opt ::= LIMIT expr OFFSET expr", /* 149 */ "limit_opt ::= LIMIT expr COMMA expr", /* 150 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret", /* 151 */ "where_opt ::=", /* 152 */ "where_opt ::= WHERE expr", /* 153 */ "where_opt_ret ::=", /* 154 */ "where_opt_ret ::= WHERE expr", /* 155 */ "where_opt_ret ::= RETURNING selcollist", /* 156 */ "where_opt_ret ::= WHERE expr RETURNING selcollist", /* 157 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret", /* 158 */ "setlist ::= setlist COMMA nm EQ expr", /* 159 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", /* 160 */ "setlist ::= nm EQ expr", /* 161 */ "setlist ::= LP idlist RP EQ expr", /* 162 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", /* 163 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning", /* 164 */ "upsert ::=", /* 165 */ "upsert ::= RETURNING selcollist", /* 166 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert", /* 167 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert", /* 168 */ "upsert ::= ON CONFLICT DO NOTHING returning", /* 169 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning", /* 170 */ "returning ::= RETURNING selcollist", /* 171 */ "insert_cmd ::= INSERT orconf", /* 172 */ "insert_cmd ::= REPLACE", /* 173 */ "idlist_opt ::=", /* 174 */ "idlist_opt ::= LP idlist RP", /* 175 */ "idlist ::= idlist COMMA nm", /* 176 */ "idlist ::= nm", /* 177 */ "expr ::= LP expr RP", /* 178 */ "expr ::= ID|INDEXED|JOIN_KW", /* 179 */ "expr ::= nm DOT nm", /* 180 */ "expr ::= nm DOT nm DOT nm", /* 181 */ "term ::= NULL|FLOAT|BLOB", /* 182 */ "term ::= STRING", /* 183 */ "term ::= INTEGER", /* 184 */ "expr ::= VARIABLE", /* 185 */ "expr ::= expr COLLATE ID|STRING", /* 186 */ "expr ::= CAST LP expr AS typetoken RP", /* 187 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP", /* 188 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP", /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP", /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over", /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over", /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over", /* 193 */ "term ::= CTIME_KW", /* 194 */ "expr ::= LP nexprlist COMMA expr RP", /* 195 */ "expr ::= expr AND expr", /* 196 */ "expr ::= expr OR expr", /* 197 */ "expr ::= expr LT|GT|GE|LE expr", /* 198 */ "expr ::= expr EQ|NE expr", /* 199 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", /* 200 */ "expr ::= expr PLUS|MINUS expr", /* 201 */ "expr ::= expr STAR|SLASH|REM expr", /* 202 */ "expr ::= expr CONCAT expr", /* 203 */ "likeop ::= NOT LIKE_KW|MATCH", /* 204 */ "expr ::= expr likeop expr", /* 205 */ "expr ::= expr likeop expr ESCAPE expr", /* 206 */ "expr ::= expr ISNULL|NOTNULL", /* 207 */ "expr ::= expr NOT NULL", /* 208 */ "expr ::= expr IS expr", /* 209 */ "expr ::= expr IS NOT expr", /* 210 */ "expr ::= expr IS NOT DISTINCT FROM expr", /* 211 */ "expr ::= expr IS DISTINCT FROM expr", /* 212 */ "expr ::= NOT expr", /* 213 */ "expr ::= BITNOT expr", /* 214 */ "expr ::= PLUS|MINUS expr", /* 215 */ "expr ::= expr PTR expr", /* 216 */ "between_op ::= BETWEEN", /* 217 */ "between_op ::= NOT BETWEEN", /* 218 */ "expr ::= expr between_op expr AND expr", /* 219 */ "in_op ::= IN", /* 220 */ "in_op ::= NOT IN", /* 221 */ "expr ::= expr in_op LP exprlist RP", /* 222 */ "expr ::= LP select RP", /* 223 */ "expr ::= expr in_op LP select RP", /* 224 */ "expr ::= expr in_op nm dbnm paren_exprlist", /* 225 */ "expr ::= EXISTS LP select RP", /* 226 */ "expr ::= CASE case_operand case_exprlist case_else END", /* 227 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", /* 228 */ "case_exprlist ::= WHEN expr THEN expr", /* 229 */ "case_else ::= ELSE expr", /* 230 */ "case_else ::=", /* 231 */ "case_operand ::=", /* 232 */ "exprlist ::=", /* 233 */ "nexprlist ::= nexprlist COMMA expr", /* 234 */ "nexprlist ::= expr", /* 235 */ "paren_exprlist ::=", /* 236 */ "paren_exprlist ::= LP exprlist RP", /* 237 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", /* 238 */ "uniqueflag ::= UNIQUE", /* 239 */ "uniqueflag ::=", /* 240 */ "eidlist_opt ::=", /* 241 */ "eidlist_opt ::= LP eidlist RP", /* 242 */ "eidlist ::= eidlist COMMA nm collate sortorder", /* 243 */ "eidlist ::= nm collate sortorder", /* 244 */ "collate ::=", /* 245 */ "collate ::= COLLATE ID|STRING", /* 246 */ "cmd ::= DROP INDEX ifexists fullname", /* 247 */ "cmd ::= VACUUM vinto", /* 248 */ "cmd ::= VACUUM nm vinto", /* 249 */ "vinto ::= INTO expr", /* 250 */ "vinto ::=", /* 251 */ "cmd ::= PRAGMA nm dbnm", /* 252 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", /* 253 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", /* 254 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", /* 255 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", /* 256 */ "plus_num ::= PLUS INTEGER|FLOAT", /* 257 */ "minus_num ::= MINUS INTEGER|FLOAT", /* 258 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", /* 259 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", /* 260 */ "trigger_time ::= BEFORE|AFTER", /* 261 */ "trigger_time ::= INSTEAD OF", /* 262 */ "trigger_time ::=", /* 263 */ "trigger_event ::= DELETE|INSERT", /* 264 */ "trigger_event ::= UPDATE", /* 265 */ "trigger_event ::= UPDATE OF idlist", /* 266 */ "when_clause ::=", /* 267 */ "when_clause ::= WHEN expr", /* 268 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", /* 269 */ "trigger_cmd_list ::= trigger_cmd SEMI", /* 270 */ "trnm ::= nm DOT nm", /* 271 */ "tridxby ::= INDEXED BY nm", /* 272 */ "tridxby ::= NOT INDEXED", /* 273 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", /* 274 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", /* 275 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", /* 276 */ "trigger_cmd ::= scanpt select scanpt", /* 277 */ "expr ::= RAISE LP IGNORE RP", /* 278 */ "expr ::= RAISE LP raisetype COMMA nm RP", /* 279 */ "raisetype ::= ROLLBACK", /* 280 */ "raisetype ::= ABORT", /* 281 */ "raisetype ::= FAIL", /* 282 */ "cmd ::= DROP TRIGGER ifexists fullname", /* 283 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", /* 284 */ "cmd ::= DETACH database_kw_opt expr", /* 285 */ "key_opt ::=", /* 286 */ "key_opt ::= KEY expr", /* 287 */ "cmd ::= REINDEX", /* 288 */ "cmd ::= REINDEX nm dbnm", /* 289 */ "cmd ::= ANALYZE", /* 290 */ "cmd ::= ANALYZE nm dbnm", /* 291 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", /* 292 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", /* 293 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", /* 294 */ "add_column_fullname ::= fullname", /* 295 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", /* 296 */ "cmd ::= create_vtab", /* 297 */ "cmd ::= create_vtab LP vtabarglist RP", /* 298 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", /* 299 */ "vtabarg ::=", /* 300 */ "vtabargtoken ::= ANY", /* 301 */ "vtabargtoken ::= lp anylist RP", /* 302 */ "lp ::= LP", /* 303 */ "with ::= WITH wqlist", /* 304 */ "with ::= WITH RECURSIVE wqlist", /* 305 */ "wqas ::= AS", /* 306 */ "wqas ::= AS MATERIALIZED", /* 307 */ "wqas ::= AS NOT MATERIALIZED", /* 308 */ "wqitem ::= nm eidlist_opt wqas LP select RP", /* 309 */ "wqlist ::= wqitem", /* 310 */ "wqlist ::= wqlist COMMA wqitem", /* 311 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", /* 312 */ "windowdefn ::= nm AS LP window RP", /* 313 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", /* 314 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", /* 315 */ "window ::= ORDER BY sortlist frame_opt", /* 316 */ "window ::= nm ORDER BY sortlist frame_opt", /* 317 */ "window ::= nm frame_opt", /* 318 */ "frame_opt ::=", /* 319 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", /* 320 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", /* 321 */ "range_or_rows ::= RANGE|ROWS|GROUPS", /* 322 */ "frame_bound_s ::= frame_bound", /* 323 */ "frame_bound_s ::= UNBOUNDED PRECEDING", /* 324 */ "frame_bound_e ::= frame_bound", /* 325 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", /* 326 */ "frame_bound ::= expr PRECEDING|FOLLOWING", /* 327 */ "frame_bound ::= CURRENT ROW", /* 328 */ "frame_exclude_opt ::=", /* 329 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", /* 330 */ "frame_exclude ::= NO OTHERS", /* 331 */ "frame_exclude ::= CURRENT ROW", /* 332 */ "frame_exclude ::= GROUP|TIES", /* 333 */ "window_clause ::= WINDOW windowdefn_list", /* 334 */ "filter_over ::= filter_clause over_clause", /* 335 */ "filter_over ::= over_clause", /* 336 */ "filter_over ::= filter_clause", /* 337 */ "over_clause ::= OVER LP window RP", /* 338 */ "over_clause ::= OVER nm", /* 339 */ "filter_clause ::= FILTER LP WHERE expr RP", /* 340 */ "input ::= cmdlist", /* 341 */ "cmdlist ::= cmdlist ecmd", /* 342 */ "cmdlist ::= ecmd", /* 343 */ "ecmd ::= SEMI", /* 344 */ "ecmd ::= cmdx SEMI", /* 345 */ "ecmd ::= explain cmdx SEMI", /* 346 */ "trans_opt ::=", /* 347 */ "trans_opt ::= TRANSACTION", /* 348 */ "trans_opt ::= TRANSACTION nm", /* 349 */ "savepoint_opt ::= SAVEPOINT", /* 350 */ "savepoint_opt ::=", /* 351 */ "cmd ::= create_table create_table_args", /* 352 */ "table_option_set ::= table_option", /* 353 */ "columnlist ::= columnlist COMMA columnname carglist", /* 354 */ "columnlist ::= columnname carglist", /* 355 */ "nm ::= ID|INDEXED|JOIN_KW", /* 356 */ "nm ::= STRING", /* 357 */ "typetoken ::= typename", /* 358 */ "typename ::= ID|STRING", /* 359 */ "signed ::= plus_num", /* 360 */ "signed ::= minus_num", /* 361 */ "carglist ::= carglist ccons", /* 362 */ "carglist ::=", /* 363 */ "ccons ::= NULL onconf", /* 364 */ "ccons ::= GENERATED ALWAYS AS generated", /* 365 */ "ccons ::= AS generated", /* 366 */ "conslist_opt ::= COMMA conslist", /* 367 */ "conslist ::= conslist tconscomma tcons", /* 368 */ "conslist ::= tcons", /* 369 */ "tconscomma ::=", /* 370 */ "defer_subclause_opt ::= defer_subclause", /* 371 */ "resolvetype ::= raisetype", /* 372 */ "selectnowith ::= oneselect", /* 373 */ "oneselect ::= values", /* 374 */ "sclp ::= selcollist COMMA", /* 375 */ "as ::= ID|STRING", /* 376 */ "indexed_opt ::= indexed_by", /* 377 */ "returning ::=", /* 378 */ "expr ::= term", /* 379 */ "likeop ::= LIKE_KW|MATCH", /* 380 */ "case_operand ::= expr", /* 381 */ "exprlist ::= nexprlist", /* 382 */ "nmnum ::= plus_num", /* 383 */ "nmnum ::= nm", /* 384 */ "nmnum ::= ON", /* 385 */ "nmnum ::= DELETE", /* 386 */ "nmnum ::= DEFAULT", /* 387 */ "plus_num ::= INTEGER|FLOAT", /* 388 */ "foreach_clause ::=", /* 389 */ "foreach_clause ::= FOR EACH ROW", /* 390 */ "trnm ::= nm", /* 391 */ "tridxby ::=", /* 392 */ "database_kw_opt ::= DATABASE", /* 393 */ "database_kw_opt ::=", /* 394 */ "kwcolumn_opt ::=", /* 395 */ "kwcolumn_opt ::= COLUMNKW", /* 396 */ "vtabarglist ::= vtabarg", /* 397 */ "vtabarglist ::= vtabarglist COMMA vtabarg", /* 398 */ "vtabarg ::= vtabarg vtabargtoken", /* 399 */ "anylist ::=", /* 400 */ "anylist ::= anylist LP anylist RP", /* 401 */ "anylist ::= anylist ANY", /* 402 */ "with ::=", /* 403 */ "windowdefn_list ::= windowdefn", /* 404 */ "window ::= frame_opt", }; #endif /* NDEBUG */ #if YYSTACKDEPTH<=0 /* ** Try to increase the size of the parser stack. Return the number ** of errors. Return 0 on success. */ static int yyGrowStack(yyParser *p){ int newSize; int idx; yyStackEntry *pNew; newSize = p->yystksz*2 + 100; idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; if( p->yystack==&p->yystk0 ){ pNew = malloc(newSize*sizeof(pNew[0])); if( pNew ) pNew[0] = p->yystk0; }else{ pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); } if( pNew ){ p->yystack = pNew; p->yytos = &p->yystack[idx]; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", yyTracePrompt, p->yystksz, newSize); } #endif p->yystksz = newSize; } return pNew==0; } #endif /* Datatype of the argument to the memory allocated passed as the ** second argument to sqlite3ParserAlloc() below. This can be changed by ** putting an appropriate #define in the %include section of the input ** grammar. */ #ifndef YYMALLOCARGTYPE # define YYMALLOCARGTYPE size_t #endif /* Initialize a new parser that has already been allocated. */ SQLITE_PRIVATE void sqlite3ParserInit(void *yypRawParser sqlite3ParserCTX_PDECL){ yyParser *yypParser = (yyParser*)yypRawParser; sqlite3ParserCTX_STORE #ifdef YYTRACKMAXSTACKDEPTH yypParser->yyhwm = 0; #endif #if YYSTACKDEPTH<=0 yypParser->yytos = NULL; yypParser->yystack = NULL; yypParser->yystksz = 0; if( yyGrowStack(yypParser) ){ yypParser->yystack = &yypParser->yystk0; yypParser->yystksz = 1; } #endif #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif yypParser->yytos = yypParser->yystack; yypParser->yystack[0].stateno = 0; yypParser->yystack[0].major = 0; #if YYSTACKDEPTH>0 yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1]; #endif } #ifndef sqlite3Parser_ENGINEALWAYSONSTACK /* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like ** malloc. ** ** Inputs: ** A pointer to the function used to allocate memory. ** ** Outputs: ** A pointer to a parser. This pointer is used in subsequent calls ** to sqlite3Parser and sqlite3ParserFree. */ SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) sqlite3ParserCTX_PDECL){ yyParser *yypParser; yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); if( yypParser ){ sqlite3ParserCTX_STORE sqlite3ParserInit(yypParser sqlite3ParserCTX_PARAM); } return (void*)yypParser; } #endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ /* The following function deletes the "minor type" or semantic value ** associated with a symbol. The symbol can be either a terminal ** or nonterminal. "yymajor" is the symbol code, and "yypminor" is ** a pointer to the value to be deleted. The code used to do the ** deletions is derived from the %destructor and/or %token_destructor ** directives of the input grammar. */ static void yy_destructor( yyParser *yypParser, /* The parser */ YYCODETYPE yymajor, /* Type code for object to destroy */ YYMINORTYPE *yypminor /* The object to be destroyed */ ){ sqlite3ParserARG_FETCH sqlite3ParserCTX_FETCH switch( yymajor ){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen ** when the symbol is popped from the stack during a ** reduce or during error processing or when a parser is ** being destroyed before it is finished parsing. ** ** Note: during a reduce, the only symbols destroyed are those ** which appear on the RHS of the rule, but which are *not* used ** inside the C code. */ /********* Begin destructor definitions ***************************************/ case 204: /* select */ case 239: /* selectnowith */ case 240: /* oneselect */ case 252: /* values */ { sqlite3SelectDelete(pParse->db, (yypminor->yy47)); } break; case 216: /* term */ case 217: /* expr */ case 246: /* where_opt */ case 248: /* having_opt */ case 267: /* where_opt_ret */ case 278: /* case_operand */ case 280: /* case_else */ case 283: /* vinto */ case 290: /* when_clause */ case 295: /* key_opt */ case 311: /* filter_clause */ { sqlite3ExprDelete(pParse->db, (yypminor->yy528)); } break; case 221: /* eidlist_opt */ case 231: /* sortlist */ case 232: /* eidlist */ case 244: /* selcollist */ case 247: /* groupby_opt */ case 249: /* orderby_opt */ case 253: /* nexprlist */ case 254: /* sclp */ case 261: /* exprlist */ case 268: /* setlist */ case 277: /* paren_exprlist */ case 279: /* case_exprlist */ case 310: /* part_opt */ { sqlite3ExprListDelete(pParse->db, (yypminor->yy322)); } break; case 238: /* fullname */ case 245: /* from */ case 256: /* seltablist */ case 257: /* stl_prefix */ case 262: /* xfullname */ { sqlite3SrcListDelete(pParse->db, (yypminor->yy131)); } break; case 241: /* wqlist */ { sqlite3WithDelete(pParse->db, (yypminor->yy521)); } break; case 251: /* window_clause */ case 306: /* windowdefn_list */ { sqlite3WindowListDelete(pParse->db, (yypminor->yy41)); } break; case 263: /* idlist */ case 270: /* idlist_opt */ { sqlite3IdListDelete(pParse->db, (yypminor->yy254)); } break; case 273: /* filter_over */ case 307: /* windowdefn */ case 308: /* window */ case 309: /* frame_opt */ case 312: /* over_clause */ { sqlite3WindowDelete(pParse->db, (yypminor->yy41)); } break; case 286: /* trigger_cmd_list */ case 291: /* trigger_cmd */ { sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy33)); } break; case 288: /* trigger_event */ { sqlite3IdListDelete(pParse->db, (yypminor->yy180).b); } break; case 314: /* frame_bound */ case 315: /* frame_bound_s */ case 316: /* frame_bound_e */ { sqlite3ExprDelete(pParse->db, (yypminor->yy595).pExpr); } break; /********* End destructor definitions *****************************************/ default: break; /* If no destructor action specified: do nothing */ } } /* ** Pop the parser's stack once. ** ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. */ static void yy_pop_parser_stack(yyParser *pParser){ yyStackEntry *yytos; assert( pParser->yytos!=0 ); assert( pParser->yytos > pParser->yystack ); yytos = pParser->yytos--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sPopping %s\n", yyTracePrompt, yyTokenName[yytos->major]); } #endif yy_destructor(pParser, yytos->major, &yytos->minor); } /* ** Clear all secondary memory allocations from the parser */ SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){ yyParser *pParser = (yyParser*)p; while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); #if YYSTACKDEPTH<=0 if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); #endif } #ifndef sqlite3Parser_ENGINEALWAYSONSTACK /* ** Deallocate and destroy a parser. Destructors are called for ** all stack elements before shutting the parser down. ** ** If the YYPARSEFREENEVERNULL macro exists (for example because it ** is defined in a %include section of the input grammar) then it is ** assumed that the input pointer is never NULL. */ SQLITE_PRIVATE void sqlite3ParserFree( void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ #ifndef YYPARSEFREENEVERNULL if( p==0 ) return; #endif sqlite3ParserFinalize(p); (*freeProc)(p); } #endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ /* ** Return the peak depth of the stack for a parser. */ #ifdef YYTRACKMAXSTACKDEPTH SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){ yyParser *pParser = (yyParser*)p; return pParser->yyhwm; } #endif /* This array of booleans keeps track of the parser statement ** coverage. The element yycoverage[X][Y] is set when the parser ** is in state X and has a lookahead token Y. In a well-tested ** systems, every element of this matrix should end up being set. */ #if defined(YYCOVERAGE) static unsigned char yycoverage[YYNSTATE][YYNTOKEN]; #endif /* ** Write into out a description of every state/lookahead combination that ** ** (1) has not been used by the parser, and ** (2) is not a syntax error. ** ** Return the number of missed state/lookahead combinations. */ #if defined(YYCOVERAGE) SQLITE_PRIVATE int sqlite3ParserCoverage(FILE *out){ int stateno, iLookAhead, i; int nMissed = 0; for(stateno=0; statenoYY_MAX_SHIFT ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); #if defined(YYCOVERAGE) yycoverage[stateno][iLookAhead] = 1; #endif do{ i = yy_shift_ofst[stateno]; assert( i>=0 ); assert( i<=YY_ACTTAB_COUNT ); assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); assert( iLookAhead!=YYNOCODE ); assert( iLookAhead < YYNTOKEN ); i += iLookAhead; assert( i<(int)YY_NLOOKAHEAD ); if( yy_lookahead[i]!=iLookAhead ){ #ifdef YYFALLBACK YYCODETYPE iFallback; /* Fallback token */ assert( iLookAhead %s\n", yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); } #endif assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ iLookAhead = iFallback; continue; } #endif #ifdef YYWILDCARD { int j = i - iLookAhead + YYWILDCARD; assert( j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) ); if( yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); } #endif /* NDEBUG */ return yy_action[j]; } } #endif /* YYWILDCARD */ return yy_default[stateno]; }else{ assert( i>=0 && i<(int)(sizeof(yy_action)/sizeof(yy_action[0])) ); return yy_action[i]; } }while(1); } /* ** Find the appropriate action for a parser given the non-terminal ** look-ahead token iLookAhead. */ static YYACTIONTYPE yy_find_reduce_action( YYACTIONTYPE stateno, /* Current state number */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; #ifdef YYERRORSYMBOL if( stateno>YY_REDUCE_COUNT ){ return yy_default[stateno]; } #else assert( stateno<=YY_REDUCE_COUNT ); #endif i = yy_reduce_ofst[stateno]; assert( iLookAhead!=YYNOCODE ); i += iLookAhead; #ifdef YYERRORSYMBOL if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ return yy_default[stateno]; } #else assert( i>=0 && iyytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ sqlite3ErrorMsg(pParse, "parser stack overflow"); /******** End %stack_overflow code ********************************************/ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument var */ sqlite3ParserCTX_STORE } /* ** Print tracing information for a SHIFT action */ #ifndef NDEBUG static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){ if( yyTraceFILE ){ if( yyNewStateyytos->major], yyNewState); }else{ fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n", yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major], yyNewState - YY_MIN_REDUCE); } } } #else # define yyTraceShift(X,Y,Z) #endif /* ** Perform a shift action. */ static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ YYACTIONTYPE yyNewState, /* The new state to shift in */ YYCODETYPE yyMajor, /* The major token to shift in */ sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */ ){ yyStackEntry *yytos; yypParser->yytos++; #ifdef YYTRACKMAXSTACKDEPTH if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ yypParser->yyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); } #endif #if YYSTACKDEPTH>0 if( yypParser->yytos>yypParser->yystackEnd ){ yypParser->yytos--; yyStackOverflow(yypParser); return; } #else if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ if( yyGrowStack(yypParser) ){ yypParser->yytos--; yyStackOverflow(yypParser); return; } } #endif if( yyNewState > YY_MAX_SHIFT ){ yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; } yytos = yypParser->yytos; yytos->stateno = yyNewState; yytos->major = yyMajor; yytos->minor.yy0 = yyMinor; yyTraceShift(yypParser, yyNewState, "Shift"); } /* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side ** of that rule */ static const YYCODETYPE yyRuleInfoLhs[] = { 189, /* (0) explain ::= EXPLAIN */ 189, /* (1) explain ::= EXPLAIN QUERY PLAN */ 188, /* (2) cmdx ::= cmd */ 190, /* (3) cmd ::= BEGIN transtype trans_opt */ 191, /* (4) transtype ::= */ 191, /* (5) transtype ::= DEFERRED */ 191, /* (6) transtype ::= IMMEDIATE */ 191, /* (7) transtype ::= EXCLUSIVE */ 190, /* (8) cmd ::= COMMIT|END trans_opt */ 190, /* (9) cmd ::= ROLLBACK trans_opt */ 190, /* (10) cmd ::= SAVEPOINT nm */ 190, /* (11) cmd ::= RELEASE savepoint_opt nm */ 190, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ 195, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ 197, /* (14) createkw ::= CREATE */ 199, /* (15) ifnotexists ::= */ 199, /* (16) ifnotexists ::= IF NOT EXISTS */ 198, /* (17) temp ::= TEMP */ 198, /* (18) temp ::= */ 196, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ 196, /* (20) create_table_args ::= AS select */ 203, /* (21) table_option_set ::= */ 203, /* (22) table_option_set ::= table_option_set COMMA table_option */ 205, /* (23) table_option ::= WITHOUT nm */ 205, /* (24) table_option ::= nm */ 206, /* (25) columnname ::= nm typetoken */ 208, /* (26) typetoken ::= */ 208, /* (27) typetoken ::= typename LP signed RP */ 208, /* (28) typetoken ::= typename LP signed COMMA signed RP */ 209, /* (29) typename ::= typename ID|STRING */ 213, /* (30) scanpt ::= */ 214, /* (31) scantok ::= */ 215, /* (32) ccons ::= CONSTRAINT nm */ 215, /* (33) ccons ::= DEFAULT scantok term */ 215, /* (34) ccons ::= DEFAULT LP expr RP */ 215, /* (35) ccons ::= DEFAULT PLUS scantok term */ 215, /* (36) ccons ::= DEFAULT MINUS scantok term */ 215, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ 215, /* (38) ccons ::= NOT NULL onconf */ 215, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ 215, /* (40) ccons ::= UNIQUE onconf */ 215, /* (41) ccons ::= CHECK LP expr RP */ 215, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ 215, /* (43) ccons ::= defer_subclause */ 215, /* (44) ccons ::= COLLATE ID|STRING */ 224, /* (45) generated ::= LP expr RP */ 224, /* (46) generated ::= LP expr RP ID */ 220, /* (47) autoinc ::= */ 220, /* (48) autoinc ::= AUTOINCR */ 222, /* (49) refargs ::= */ 222, /* (50) refargs ::= refargs refarg */ 225, /* (51) refarg ::= MATCH nm */ 225, /* (52) refarg ::= ON INSERT refact */ 225, /* (53) refarg ::= ON DELETE refact */ 225, /* (54) refarg ::= ON UPDATE refact */ 226, /* (55) refact ::= SET NULL */ 226, /* (56) refact ::= SET DEFAULT */ 226, /* (57) refact ::= CASCADE */ 226, /* (58) refact ::= RESTRICT */ 226, /* (59) refact ::= NO ACTION */ 223, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ 223, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ 227, /* (62) init_deferred_pred_opt ::= */ 227, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ 227, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ 202, /* (65) conslist_opt ::= */ 229, /* (66) tconscomma ::= COMMA */ 230, /* (67) tcons ::= CONSTRAINT nm */ 230, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ 230, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ 230, /* (70) tcons ::= CHECK LP expr RP onconf */ 230, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ 233, /* (72) defer_subclause_opt ::= */ 218, /* (73) onconf ::= */ 218, /* (74) onconf ::= ON CONFLICT resolvetype */ 234, /* (75) orconf ::= */ 234, /* (76) orconf ::= OR resolvetype */ 235, /* (77) resolvetype ::= IGNORE */ 235, /* (78) resolvetype ::= REPLACE */ 190, /* (79) cmd ::= DROP TABLE ifexists fullname */ 237, /* (80) ifexists ::= IF EXISTS */ 237, /* (81) ifexists ::= */ 190, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ 190, /* (83) cmd ::= DROP VIEW ifexists fullname */ 190, /* (84) cmd ::= select */ 204, /* (85) select ::= WITH wqlist selectnowith */ 204, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ 204, /* (87) select ::= selectnowith */ 239, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ 242, /* (89) multiselect_op ::= UNION */ 242, /* (90) multiselect_op ::= UNION ALL */ 242, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ 240, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ 240, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ 252, /* (94) values ::= VALUES LP nexprlist RP */ 252, /* (95) values ::= values COMMA LP nexprlist RP */ 243, /* (96) distinct ::= DISTINCT */ 243, /* (97) distinct ::= ALL */ 243, /* (98) distinct ::= */ 254, /* (99) sclp ::= */ 244, /* (100) selcollist ::= sclp scanpt expr scanpt as */ 244, /* (101) selcollist ::= sclp scanpt STAR */ 244, /* (102) selcollist ::= sclp scanpt nm DOT STAR */ 255, /* (103) as ::= AS nm */ 255, /* (104) as ::= */ 245, /* (105) from ::= */ 245, /* (106) from ::= FROM seltablist */ 257, /* (107) stl_prefix ::= seltablist joinop */ 257, /* (108) stl_prefix ::= */ 256, /* (109) seltablist ::= stl_prefix nm dbnm as on_using */ 256, /* (110) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ 256, /* (111) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ 256, /* (112) seltablist ::= stl_prefix LP select RP as on_using */ 256, /* (113) seltablist ::= stl_prefix LP seltablist RP as on_using */ 200, /* (114) dbnm ::= */ 200, /* (115) dbnm ::= DOT nm */ 238, /* (116) fullname ::= nm */ 238, /* (117) fullname ::= nm DOT nm */ 262, /* (118) xfullname ::= nm */ 262, /* (119) xfullname ::= nm DOT nm */ 262, /* (120) xfullname ::= nm DOT nm AS nm */ 262, /* (121) xfullname ::= nm AS nm */ 258, /* (122) joinop ::= COMMA|JOIN */ 258, /* (123) joinop ::= JOIN_KW JOIN */ 258, /* (124) joinop ::= JOIN_KW nm JOIN */ 258, /* (125) joinop ::= JOIN_KW nm nm JOIN */ 259, /* (126) on_using ::= ON expr */ 259, /* (127) on_using ::= USING LP idlist RP */ 259, /* (128) on_using ::= */ 264, /* (129) indexed_opt ::= */ 260, /* (130) indexed_by ::= INDEXED BY nm */ 260, /* (131) indexed_by ::= NOT INDEXED */ 249, /* (132) orderby_opt ::= */ 249, /* (133) orderby_opt ::= ORDER BY sortlist */ 231, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */ 231, /* (135) sortlist ::= expr sortorder nulls */ 219, /* (136) sortorder ::= ASC */ 219, /* (137) sortorder ::= DESC */ 219, /* (138) sortorder ::= */ 265, /* (139) nulls ::= NULLS FIRST */ 265, /* (140) nulls ::= NULLS LAST */ 265, /* (141) nulls ::= */ 247, /* (142) groupby_opt ::= */ 247, /* (143) groupby_opt ::= GROUP BY nexprlist */ 248, /* (144) having_opt ::= */ 248, /* (145) having_opt ::= HAVING expr */ 250, /* (146) limit_opt ::= */ 250, /* (147) limit_opt ::= LIMIT expr */ 250, /* (148) limit_opt ::= LIMIT expr OFFSET expr */ 250, /* (149) limit_opt ::= LIMIT expr COMMA expr */ 190, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ 246, /* (151) where_opt ::= */ 246, /* (152) where_opt ::= WHERE expr */ 267, /* (153) where_opt_ret ::= */ 267, /* (154) where_opt_ret ::= WHERE expr */ 267, /* (155) where_opt_ret ::= RETURNING selcollist */ 267, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */ 190, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ 268, /* (158) setlist ::= setlist COMMA nm EQ expr */ 268, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */ 268, /* (160) setlist ::= nm EQ expr */ 268, /* (161) setlist ::= LP idlist RP EQ expr */ 190, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ 190, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ 271, /* (164) upsert ::= */ 271, /* (165) upsert ::= RETURNING selcollist */ 271, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ 271, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ 271, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */ 271, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ 272, /* (170) returning ::= RETURNING selcollist */ 269, /* (171) insert_cmd ::= INSERT orconf */ 269, /* (172) insert_cmd ::= REPLACE */ 270, /* (173) idlist_opt ::= */ 270, /* (174) idlist_opt ::= LP idlist RP */ 263, /* (175) idlist ::= idlist COMMA nm */ 263, /* (176) idlist ::= nm */ 217, /* (177) expr ::= LP expr RP */ 217, /* (178) expr ::= ID|INDEXED|JOIN_KW */ 217, /* (179) expr ::= nm DOT nm */ 217, /* (180) expr ::= nm DOT nm DOT nm */ 216, /* (181) term ::= NULL|FLOAT|BLOB */ 216, /* (182) term ::= STRING */ 216, /* (183) term ::= INTEGER */ 217, /* (184) expr ::= VARIABLE */ 217, /* (185) expr ::= expr COLLATE ID|STRING */ 217, /* (186) expr ::= CAST LP expr AS typetoken RP */ 217, /* (187) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ 217, /* (188) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ 217, /* (189) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ 217, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ 217, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ 217, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ 216, /* (193) term ::= CTIME_KW */ 217, /* (194) expr ::= LP nexprlist COMMA expr RP */ 217, /* (195) expr ::= expr AND expr */ 217, /* (196) expr ::= expr OR expr */ 217, /* (197) expr ::= expr LT|GT|GE|LE expr */ 217, /* (198) expr ::= expr EQ|NE expr */ 217, /* (199) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ 217, /* (200) expr ::= expr PLUS|MINUS expr */ 217, /* (201) expr ::= expr STAR|SLASH|REM expr */ 217, /* (202) expr ::= expr CONCAT expr */ 274, /* (203) likeop ::= NOT LIKE_KW|MATCH */ 217, /* (204) expr ::= expr likeop expr */ 217, /* (205) expr ::= expr likeop expr ESCAPE expr */ 217, /* (206) expr ::= expr ISNULL|NOTNULL */ 217, /* (207) expr ::= expr NOT NULL */ 217, /* (208) expr ::= expr IS expr */ 217, /* (209) expr ::= expr IS NOT expr */ 217, /* (210) expr ::= expr IS NOT DISTINCT FROM expr */ 217, /* (211) expr ::= expr IS DISTINCT FROM expr */ 217, /* (212) expr ::= NOT expr */ 217, /* (213) expr ::= BITNOT expr */ 217, /* (214) expr ::= PLUS|MINUS expr */ 217, /* (215) expr ::= expr PTR expr */ 275, /* (216) between_op ::= BETWEEN */ 275, /* (217) between_op ::= NOT BETWEEN */ 217, /* (218) expr ::= expr between_op expr AND expr */ 276, /* (219) in_op ::= IN */ 276, /* (220) in_op ::= NOT IN */ 217, /* (221) expr ::= expr in_op LP exprlist RP */ 217, /* (222) expr ::= LP select RP */ 217, /* (223) expr ::= expr in_op LP select RP */ 217, /* (224) expr ::= expr in_op nm dbnm paren_exprlist */ 217, /* (225) expr ::= EXISTS LP select RP */ 217, /* (226) expr ::= CASE case_operand case_exprlist case_else END */ 279, /* (227) case_exprlist ::= case_exprlist WHEN expr THEN expr */ 279, /* (228) case_exprlist ::= WHEN expr THEN expr */ 280, /* (229) case_else ::= ELSE expr */ 280, /* (230) case_else ::= */ 278, /* (231) case_operand ::= */ 261, /* (232) exprlist ::= */ 253, /* (233) nexprlist ::= nexprlist COMMA expr */ 253, /* (234) nexprlist ::= expr */ 277, /* (235) paren_exprlist ::= */ 277, /* (236) paren_exprlist ::= LP exprlist RP */ 190, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ 281, /* (238) uniqueflag ::= UNIQUE */ 281, /* (239) uniqueflag ::= */ 221, /* (240) eidlist_opt ::= */ 221, /* (241) eidlist_opt ::= LP eidlist RP */ 232, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */ 232, /* (243) eidlist ::= nm collate sortorder */ 282, /* (244) collate ::= */ 282, /* (245) collate ::= COLLATE ID|STRING */ 190, /* (246) cmd ::= DROP INDEX ifexists fullname */ 190, /* (247) cmd ::= VACUUM vinto */ 190, /* (248) cmd ::= VACUUM nm vinto */ 283, /* (249) vinto ::= INTO expr */ 283, /* (250) vinto ::= */ 190, /* (251) cmd ::= PRAGMA nm dbnm */ 190, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */ 190, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */ 190, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */ 190, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */ 211, /* (256) plus_num ::= PLUS INTEGER|FLOAT */ 212, /* (257) minus_num ::= MINUS INTEGER|FLOAT */ 190, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ 285, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ 287, /* (260) trigger_time ::= BEFORE|AFTER */ 287, /* (261) trigger_time ::= INSTEAD OF */ 287, /* (262) trigger_time ::= */ 288, /* (263) trigger_event ::= DELETE|INSERT */ 288, /* (264) trigger_event ::= UPDATE */ 288, /* (265) trigger_event ::= UPDATE OF idlist */ 290, /* (266) when_clause ::= */ 290, /* (267) when_clause ::= WHEN expr */ 286, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ 286, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */ 292, /* (270) trnm ::= nm DOT nm */ 293, /* (271) tridxby ::= INDEXED BY nm */ 293, /* (272) tridxby ::= NOT INDEXED */ 291, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ 291, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ 291, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ 291, /* (276) trigger_cmd ::= scanpt select scanpt */ 217, /* (277) expr ::= RAISE LP IGNORE RP */ 217, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */ 236, /* (279) raisetype ::= ROLLBACK */ 236, /* (280) raisetype ::= ABORT */ 236, /* (281) raisetype ::= FAIL */ 190, /* (282) cmd ::= DROP TRIGGER ifexists fullname */ 190, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ 190, /* (284) cmd ::= DETACH database_kw_opt expr */ 295, /* (285) key_opt ::= */ 295, /* (286) key_opt ::= KEY expr */ 190, /* (287) cmd ::= REINDEX */ 190, /* (288) cmd ::= REINDEX nm dbnm */ 190, /* (289) cmd ::= ANALYZE */ 190, /* (290) cmd ::= ANALYZE nm dbnm */ 190, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */ 190, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ 190, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ 296, /* (294) add_column_fullname ::= fullname */ 190, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ 190, /* (296) cmd ::= create_vtab */ 190, /* (297) cmd ::= create_vtab LP vtabarglist RP */ 298, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ 300, /* (299) vtabarg ::= */ 301, /* (300) vtabargtoken ::= ANY */ 301, /* (301) vtabargtoken ::= lp anylist RP */ 302, /* (302) lp ::= LP */ 266, /* (303) with ::= WITH wqlist */ 266, /* (304) with ::= WITH RECURSIVE wqlist */ 305, /* (305) wqas ::= AS */ 305, /* (306) wqas ::= AS MATERIALIZED */ 305, /* (307) wqas ::= AS NOT MATERIALIZED */ 304, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */ 241, /* (309) wqlist ::= wqitem */ 241, /* (310) wqlist ::= wqlist COMMA wqitem */ 306, /* (311) windowdefn_list ::= windowdefn_list COMMA windowdefn */ 307, /* (312) windowdefn ::= nm AS LP window RP */ 308, /* (313) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ 308, /* (314) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ 308, /* (315) window ::= ORDER BY sortlist frame_opt */ 308, /* (316) window ::= nm ORDER BY sortlist frame_opt */ 308, /* (317) window ::= nm frame_opt */ 309, /* (318) frame_opt ::= */ 309, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ 309, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ 313, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */ 315, /* (322) frame_bound_s ::= frame_bound */ 315, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */ 316, /* (324) frame_bound_e ::= frame_bound */ 316, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */ 314, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */ 314, /* (327) frame_bound ::= CURRENT ROW */ 317, /* (328) frame_exclude_opt ::= */ 317, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */ 318, /* (330) frame_exclude ::= NO OTHERS */ 318, /* (331) frame_exclude ::= CURRENT ROW */ 318, /* (332) frame_exclude ::= GROUP|TIES */ 251, /* (333) window_clause ::= WINDOW windowdefn_list */ 273, /* (334) filter_over ::= filter_clause over_clause */ 273, /* (335) filter_over ::= over_clause */ 273, /* (336) filter_over ::= filter_clause */ 312, /* (337) over_clause ::= OVER LP window RP */ 312, /* (338) over_clause ::= OVER nm */ 311, /* (339) filter_clause ::= FILTER LP WHERE expr RP */ 185, /* (340) input ::= cmdlist */ 186, /* (341) cmdlist ::= cmdlist ecmd */ 186, /* (342) cmdlist ::= ecmd */ 187, /* (343) ecmd ::= SEMI */ 187, /* (344) ecmd ::= cmdx SEMI */ 187, /* (345) ecmd ::= explain cmdx SEMI */ 192, /* (346) trans_opt ::= */ 192, /* (347) trans_opt ::= TRANSACTION */ 192, /* (348) trans_opt ::= TRANSACTION nm */ 194, /* (349) savepoint_opt ::= SAVEPOINT */ 194, /* (350) savepoint_opt ::= */ 190, /* (351) cmd ::= create_table create_table_args */ 203, /* (352) table_option_set ::= table_option */ 201, /* (353) columnlist ::= columnlist COMMA columnname carglist */ 201, /* (354) columnlist ::= columnname carglist */ 193, /* (355) nm ::= ID|INDEXED|JOIN_KW */ 193, /* (356) nm ::= STRING */ 208, /* (357) typetoken ::= typename */ 209, /* (358) typename ::= ID|STRING */ 210, /* (359) signed ::= plus_num */ 210, /* (360) signed ::= minus_num */ 207, /* (361) carglist ::= carglist ccons */ 207, /* (362) carglist ::= */ 215, /* (363) ccons ::= NULL onconf */ 215, /* (364) ccons ::= GENERATED ALWAYS AS generated */ 215, /* (365) ccons ::= AS generated */ 202, /* (366) conslist_opt ::= COMMA conslist */ 228, /* (367) conslist ::= conslist tconscomma tcons */ 228, /* (368) conslist ::= tcons */ 229, /* (369) tconscomma ::= */ 233, /* (370) defer_subclause_opt ::= defer_subclause */ 235, /* (371) resolvetype ::= raisetype */ 239, /* (372) selectnowith ::= oneselect */ 240, /* (373) oneselect ::= values */ 254, /* (374) sclp ::= selcollist COMMA */ 255, /* (375) as ::= ID|STRING */ 264, /* (376) indexed_opt ::= indexed_by */ 272, /* (377) returning ::= */ 217, /* (378) expr ::= term */ 274, /* (379) likeop ::= LIKE_KW|MATCH */ 278, /* (380) case_operand ::= expr */ 261, /* (381) exprlist ::= nexprlist */ 284, /* (382) nmnum ::= plus_num */ 284, /* (383) nmnum ::= nm */ 284, /* (384) nmnum ::= ON */ 284, /* (385) nmnum ::= DELETE */ 284, /* (386) nmnum ::= DEFAULT */ 211, /* (387) plus_num ::= INTEGER|FLOAT */ 289, /* (388) foreach_clause ::= */ 289, /* (389) foreach_clause ::= FOR EACH ROW */ 292, /* (390) trnm ::= nm */ 293, /* (391) tridxby ::= */ 294, /* (392) database_kw_opt ::= DATABASE */ 294, /* (393) database_kw_opt ::= */ 297, /* (394) kwcolumn_opt ::= */ 297, /* (395) kwcolumn_opt ::= COLUMNKW */ 299, /* (396) vtabarglist ::= vtabarg */ 299, /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ 300, /* (398) vtabarg ::= vtabarg vtabargtoken */ 303, /* (399) anylist ::= */ 303, /* (400) anylist ::= anylist LP anylist RP */ 303, /* (401) anylist ::= anylist ANY */ 266, /* (402) with ::= */ 306, /* (403) windowdefn_list ::= windowdefn */ 308, /* (404) window ::= frame_opt */ }; /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number ** of symbols on the right-hand side of that rule. */ static const signed char yyRuleInfoNRhs[] = { -1, /* (0) explain ::= EXPLAIN */ -3, /* (1) explain ::= EXPLAIN QUERY PLAN */ -1, /* (2) cmdx ::= cmd */ -3, /* (3) cmd ::= BEGIN transtype trans_opt */ 0, /* (4) transtype ::= */ -1, /* (5) transtype ::= DEFERRED */ -1, /* (6) transtype ::= IMMEDIATE */ -1, /* (7) transtype ::= EXCLUSIVE */ -2, /* (8) cmd ::= COMMIT|END trans_opt */ -2, /* (9) cmd ::= ROLLBACK trans_opt */ -2, /* (10) cmd ::= SAVEPOINT nm */ -3, /* (11) cmd ::= RELEASE savepoint_opt nm */ -5, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ -6, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ -1, /* (14) createkw ::= CREATE */ 0, /* (15) ifnotexists ::= */ -3, /* (16) ifnotexists ::= IF NOT EXISTS */ -1, /* (17) temp ::= TEMP */ 0, /* (18) temp ::= */ -5, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ -2, /* (20) create_table_args ::= AS select */ 0, /* (21) table_option_set ::= */ -3, /* (22) table_option_set ::= table_option_set COMMA table_option */ -2, /* (23) table_option ::= WITHOUT nm */ -1, /* (24) table_option ::= nm */ -2, /* (25) columnname ::= nm typetoken */ 0, /* (26) typetoken ::= */ -4, /* (27) typetoken ::= typename LP signed RP */ -6, /* (28) typetoken ::= typename LP signed COMMA signed RP */ -2, /* (29) typename ::= typename ID|STRING */ 0, /* (30) scanpt ::= */ 0, /* (31) scantok ::= */ -2, /* (32) ccons ::= CONSTRAINT nm */ -3, /* (33) ccons ::= DEFAULT scantok term */ -4, /* (34) ccons ::= DEFAULT LP expr RP */ -4, /* (35) ccons ::= DEFAULT PLUS scantok term */ -4, /* (36) ccons ::= DEFAULT MINUS scantok term */ -3, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ -3, /* (38) ccons ::= NOT NULL onconf */ -5, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ -2, /* (40) ccons ::= UNIQUE onconf */ -4, /* (41) ccons ::= CHECK LP expr RP */ -4, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ -1, /* (43) ccons ::= defer_subclause */ -2, /* (44) ccons ::= COLLATE ID|STRING */ -3, /* (45) generated ::= LP expr RP */ -4, /* (46) generated ::= LP expr RP ID */ 0, /* (47) autoinc ::= */ -1, /* (48) autoinc ::= AUTOINCR */ 0, /* (49) refargs ::= */ -2, /* (50) refargs ::= refargs refarg */ -2, /* (51) refarg ::= MATCH nm */ -3, /* (52) refarg ::= ON INSERT refact */ -3, /* (53) refarg ::= ON DELETE refact */ -3, /* (54) refarg ::= ON UPDATE refact */ -2, /* (55) refact ::= SET NULL */ -2, /* (56) refact ::= SET DEFAULT */ -1, /* (57) refact ::= CASCADE */ -1, /* (58) refact ::= RESTRICT */ -2, /* (59) refact ::= NO ACTION */ -3, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ -2, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ 0, /* (62) init_deferred_pred_opt ::= */ -2, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ -2, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ 0, /* (65) conslist_opt ::= */ -1, /* (66) tconscomma ::= COMMA */ -2, /* (67) tcons ::= CONSTRAINT nm */ -7, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ -5, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ -5, /* (70) tcons ::= CHECK LP expr RP onconf */ -10, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ 0, /* (72) defer_subclause_opt ::= */ 0, /* (73) onconf ::= */ -3, /* (74) onconf ::= ON CONFLICT resolvetype */ 0, /* (75) orconf ::= */ -2, /* (76) orconf ::= OR resolvetype */ -1, /* (77) resolvetype ::= IGNORE */ -1, /* (78) resolvetype ::= REPLACE */ -4, /* (79) cmd ::= DROP TABLE ifexists fullname */ -2, /* (80) ifexists ::= IF EXISTS */ 0, /* (81) ifexists ::= */ -9, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ -4, /* (83) cmd ::= DROP VIEW ifexists fullname */ -1, /* (84) cmd ::= select */ -3, /* (85) select ::= WITH wqlist selectnowith */ -4, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ -1, /* (87) select ::= selectnowith */ -3, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ -1, /* (89) multiselect_op ::= UNION */ -2, /* (90) multiselect_op ::= UNION ALL */ -1, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ -9, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ -10, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ -4, /* (94) values ::= VALUES LP nexprlist RP */ -5, /* (95) values ::= values COMMA LP nexprlist RP */ -1, /* (96) distinct ::= DISTINCT */ -1, /* (97) distinct ::= ALL */ 0, /* (98) distinct ::= */ 0, /* (99) sclp ::= */ -5, /* (100) selcollist ::= sclp scanpt expr scanpt as */ -3, /* (101) selcollist ::= sclp scanpt STAR */ -5, /* (102) selcollist ::= sclp scanpt nm DOT STAR */ -2, /* (103) as ::= AS nm */ 0, /* (104) as ::= */ 0, /* (105) from ::= */ -2, /* (106) from ::= FROM seltablist */ -2, /* (107) stl_prefix ::= seltablist joinop */ 0, /* (108) stl_prefix ::= */ -5, /* (109) seltablist ::= stl_prefix nm dbnm as on_using */ -6, /* (110) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ -8, /* (111) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ -6, /* (112) seltablist ::= stl_prefix LP select RP as on_using */ -6, /* (113) seltablist ::= stl_prefix LP seltablist RP as on_using */ 0, /* (114) dbnm ::= */ -2, /* (115) dbnm ::= DOT nm */ -1, /* (116) fullname ::= nm */ -3, /* (117) fullname ::= nm DOT nm */ -1, /* (118) xfullname ::= nm */ -3, /* (119) xfullname ::= nm DOT nm */ -5, /* (120) xfullname ::= nm DOT nm AS nm */ -3, /* (121) xfullname ::= nm AS nm */ -1, /* (122) joinop ::= COMMA|JOIN */ -2, /* (123) joinop ::= JOIN_KW JOIN */ -3, /* (124) joinop ::= JOIN_KW nm JOIN */ -4, /* (125) joinop ::= JOIN_KW nm nm JOIN */ -2, /* (126) on_using ::= ON expr */ -4, /* (127) on_using ::= USING LP idlist RP */ 0, /* (128) on_using ::= */ 0, /* (129) indexed_opt ::= */ -3, /* (130) indexed_by ::= INDEXED BY nm */ -2, /* (131) indexed_by ::= NOT INDEXED */ 0, /* (132) orderby_opt ::= */ -3, /* (133) orderby_opt ::= ORDER BY sortlist */ -5, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */ -3, /* (135) sortlist ::= expr sortorder nulls */ -1, /* (136) sortorder ::= ASC */ -1, /* (137) sortorder ::= DESC */ 0, /* (138) sortorder ::= */ -2, /* (139) nulls ::= NULLS FIRST */ -2, /* (140) nulls ::= NULLS LAST */ 0, /* (141) nulls ::= */ 0, /* (142) groupby_opt ::= */ -3, /* (143) groupby_opt ::= GROUP BY nexprlist */ 0, /* (144) having_opt ::= */ -2, /* (145) having_opt ::= HAVING expr */ 0, /* (146) limit_opt ::= */ -2, /* (147) limit_opt ::= LIMIT expr */ -4, /* (148) limit_opt ::= LIMIT expr OFFSET expr */ -4, /* (149) limit_opt ::= LIMIT expr COMMA expr */ -6, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ 0, /* (151) where_opt ::= */ -2, /* (152) where_opt ::= WHERE expr */ 0, /* (153) where_opt_ret ::= */ -2, /* (154) where_opt_ret ::= WHERE expr */ -2, /* (155) where_opt_ret ::= RETURNING selcollist */ -4, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */ -9, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ -5, /* (158) setlist ::= setlist COMMA nm EQ expr */ -7, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */ -3, /* (160) setlist ::= nm EQ expr */ -5, /* (161) setlist ::= LP idlist RP EQ expr */ -7, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ -8, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ 0, /* (164) upsert ::= */ -2, /* (165) upsert ::= RETURNING selcollist */ -12, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ -9, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ -5, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */ -8, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ -2, /* (170) returning ::= RETURNING selcollist */ -2, /* (171) insert_cmd ::= INSERT orconf */ -1, /* (172) insert_cmd ::= REPLACE */ 0, /* (173) idlist_opt ::= */ -3, /* (174) idlist_opt ::= LP idlist RP */ -3, /* (175) idlist ::= idlist COMMA nm */ -1, /* (176) idlist ::= nm */ -3, /* (177) expr ::= LP expr RP */ -1, /* (178) expr ::= ID|INDEXED|JOIN_KW */ -3, /* (179) expr ::= nm DOT nm */ -5, /* (180) expr ::= nm DOT nm DOT nm */ -1, /* (181) term ::= NULL|FLOAT|BLOB */ -1, /* (182) term ::= STRING */ -1, /* (183) term ::= INTEGER */ -1, /* (184) expr ::= VARIABLE */ -3, /* (185) expr ::= expr COLLATE ID|STRING */ -6, /* (186) expr ::= CAST LP expr AS typetoken RP */ -5, /* (187) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ -8, /* (188) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ -4, /* (189) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ -6, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ -9, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ -5, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ -1, /* (193) term ::= CTIME_KW */ -5, /* (194) expr ::= LP nexprlist COMMA expr RP */ -3, /* (195) expr ::= expr AND expr */ -3, /* (196) expr ::= expr OR expr */ -3, /* (197) expr ::= expr LT|GT|GE|LE expr */ -3, /* (198) expr ::= expr EQ|NE expr */ -3, /* (199) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ -3, /* (200) expr ::= expr PLUS|MINUS expr */ -3, /* (201) expr ::= expr STAR|SLASH|REM expr */ -3, /* (202) expr ::= expr CONCAT expr */ -2, /* (203) likeop ::= NOT LIKE_KW|MATCH */ -3, /* (204) expr ::= expr likeop expr */ -5, /* (205) expr ::= expr likeop expr ESCAPE expr */ -2, /* (206) expr ::= expr ISNULL|NOTNULL */ -3, /* (207) expr ::= expr NOT NULL */ -3, /* (208) expr ::= expr IS expr */ -4, /* (209) expr ::= expr IS NOT expr */ -6, /* (210) expr ::= expr IS NOT DISTINCT FROM expr */ -5, /* (211) expr ::= expr IS DISTINCT FROM expr */ -2, /* (212) expr ::= NOT expr */ -2, /* (213) expr ::= BITNOT expr */ -2, /* (214) expr ::= PLUS|MINUS expr */ -3, /* (215) expr ::= expr PTR expr */ -1, /* (216) between_op ::= BETWEEN */ -2, /* (217) between_op ::= NOT BETWEEN */ -5, /* (218) expr ::= expr between_op expr AND expr */ -1, /* (219) in_op ::= IN */ -2, /* (220) in_op ::= NOT IN */ -5, /* (221) expr ::= expr in_op LP exprlist RP */ -3, /* (222) expr ::= LP select RP */ -5, /* (223) expr ::= expr in_op LP select RP */ -5, /* (224) expr ::= expr in_op nm dbnm paren_exprlist */ -4, /* (225) expr ::= EXISTS LP select RP */ -5, /* (226) expr ::= CASE case_operand case_exprlist case_else END */ -5, /* (227) case_exprlist ::= case_exprlist WHEN expr THEN expr */ -4, /* (228) case_exprlist ::= WHEN expr THEN expr */ -2, /* (229) case_else ::= ELSE expr */ 0, /* (230) case_else ::= */ 0, /* (231) case_operand ::= */ 0, /* (232) exprlist ::= */ -3, /* (233) nexprlist ::= nexprlist COMMA expr */ -1, /* (234) nexprlist ::= expr */ 0, /* (235) paren_exprlist ::= */ -3, /* (236) paren_exprlist ::= LP exprlist RP */ -12, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ -1, /* (238) uniqueflag ::= UNIQUE */ 0, /* (239) uniqueflag ::= */ 0, /* (240) eidlist_opt ::= */ -3, /* (241) eidlist_opt ::= LP eidlist RP */ -5, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */ -3, /* (243) eidlist ::= nm collate sortorder */ 0, /* (244) collate ::= */ -2, /* (245) collate ::= COLLATE ID|STRING */ -4, /* (246) cmd ::= DROP INDEX ifexists fullname */ -2, /* (247) cmd ::= VACUUM vinto */ -3, /* (248) cmd ::= VACUUM nm vinto */ -2, /* (249) vinto ::= INTO expr */ 0, /* (250) vinto ::= */ -3, /* (251) cmd ::= PRAGMA nm dbnm */ -5, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */ -6, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */ -5, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */ -6, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */ -2, /* (256) plus_num ::= PLUS INTEGER|FLOAT */ -2, /* (257) minus_num ::= MINUS INTEGER|FLOAT */ -5, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ -11, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ -1, /* (260) trigger_time ::= BEFORE|AFTER */ -2, /* (261) trigger_time ::= INSTEAD OF */ 0, /* (262) trigger_time ::= */ -1, /* (263) trigger_event ::= DELETE|INSERT */ -1, /* (264) trigger_event ::= UPDATE */ -3, /* (265) trigger_event ::= UPDATE OF idlist */ 0, /* (266) when_clause ::= */ -2, /* (267) when_clause ::= WHEN expr */ -3, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ -2, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */ -3, /* (270) trnm ::= nm DOT nm */ -3, /* (271) tridxby ::= INDEXED BY nm */ -2, /* (272) tridxby ::= NOT INDEXED */ -9, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ -8, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ -6, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ -3, /* (276) trigger_cmd ::= scanpt select scanpt */ -4, /* (277) expr ::= RAISE LP IGNORE RP */ -6, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */ -1, /* (279) raisetype ::= ROLLBACK */ -1, /* (280) raisetype ::= ABORT */ -1, /* (281) raisetype ::= FAIL */ -4, /* (282) cmd ::= DROP TRIGGER ifexists fullname */ -6, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ -3, /* (284) cmd ::= DETACH database_kw_opt expr */ 0, /* (285) key_opt ::= */ -2, /* (286) key_opt ::= KEY expr */ -1, /* (287) cmd ::= REINDEX */ -3, /* (288) cmd ::= REINDEX nm dbnm */ -1, /* (289) cmd ::= ANALYZE */ -3, /* (290) cmd ::= ANALYZE nm dbnm */ -6, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */ -7, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ -6, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ -1, /* (294) add_column_fullname ::= fullname */ -8, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ -1, /* (296) cmd ::= create_vtab */ -4, /* (297) cmd ::= create_vtab LP vtabarglist RP */ -8, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ 0, /* (299) vtabarg ::= */ -1, /* (300) vtabargtoken ::= ANY */ -3, /* (301) vtabargtoken ::= lp anylist RP */ -1, /* (302) lp ::= LP */ -2, /* (303) with ::= WITH wqlist */ -3, /* (304) with ::= WITH RECURSIVE wqlist */ -1, /* (305) wqas ::= AS */ -2, /* (306) wqas ::= AS MATERIALIZED */ -3, /* (307) wqas ::= AS NOT MATERIALIZED */ -6, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */ -1, /* (309) wqlist ::= wqitem */ -3, /* (310) wqlist ::= wqlist COMMA wqitem */ -3, /* (311) windowdefn_list ::= windowdefn_list COMMA windowdefn */ -5, /* (312) windowdefn ::= nm AS LP window RP */ -5, /* (313) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ -6, /* (314) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ -4, /* (315) window ::= ORDER BY sortlist frame_opt */ -5, /* (316) window ::= nm ORDER BY sortlist frame_opt */ -2, /* (317) window ::= nm frame_opt */ 0, /* (318) frame_opt ::= */ -3, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ -6, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ -1, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */ -1, /* (322) frame_bound_s ::= frame_bound */ -2, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */ -1, /* (324) frame_bound_e ::= frame_bound */ -2, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */ -2, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */ -2, /* (327) frame_bound ::= CURRENT ROW */ 0, /* (328) frame_exclude_opt ::= */ -2, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */ -2, /* (330) frame_exclude ::= NO OTHERS */ -2, /* (331) frame_exclude ::= CURRENT ROW */ -1, /* (332) frame_exclude ::= GROUP|TIES */ -2, /* (333) window_clause ::= WINDOW windowdefn_list */ -2, /* (334) filter_over ::= filter_clause over_clause */ -1, /* (335) filter_over ::= over_clause */ -1, /* (336) filter_over ::= filter_clause */ -4, /* (337) over_clause ::= OVER LP window RP */ -2, /* (338) over_clause ::= OVER nm */ -5, /* (339) filter_clause ::= FILTER LP WHERE expr RP */ -1, /* (340) input ::= cmdlist */ -2, /* (341) cmdlist ::= cmdlist ecmd */ -1, /* (342) cmdlist ::= ecmd */ -1, /* (343) ecmd ::= SEMI */ -2, /* (344) ecmd ::= cmdx SEMI */ -3, /* (345) ecmd ::= explain cmdx SEMI */ 0, /* (346) trans_opt ::= */ -1, /* (347) trans_opt ::= TRANSACTION */ -2, /* (348) trans_opt ::= TRANSACTION nm */ -1, /* (349) savepoint_opt ::= SAVEPOINT */ 0, /* (350) savepoint_opt ::= */ -2, /* (351) cmd ::= create_table create_table_args */ -1, /* (352) table_option_set ::= table_option */ -4, /* (353) columnlist ::= columnlist COMMA columnname carglist */ -2, /* (354) columnlist ::= columnname carglist */ -1, /* (355) nm ::= ID|INDEXED|JOIN_KW */ -1, /* (356) nm ::= STRING */ -1, /* (357) typetoken ::= typename */ -1, /* (358) typename ::= ID|STRING */ -1, /* (359) signed ::= plus_num */ -1, /* (360) signed ::= minus_num */ -2, /* (361) carglist ::= carglist ccons */ 0, /* (362) carglist ::= */ -2, /* (363) ccons ::= NULL onconf */ -4, /* (364) ccons ::= GENERATED ALWAYS AS generated */ -2, /* (365) ccons ::= AS generated */ -2, /* (366) conslist_opt ::= COMMA conslist */ -3, /* (367) conslist ::= conslist tconscomma tcons */ -1, /* (368) conslist ::= tcons */ 0, /* (369) tconscomma ::= */ -1, /* (370) defer_subclause_opt ::= defer_subclause */ -1, /* (371) resolvetype ::= raisetype */ -1, /* (372) selectnowith ::= oneselect */ -1, /* (373) oneselect ::= values */ -2, /* (374) sclp ::= selcollist COMMA */ -1, /* (375) as ::= ID|STRING */ -1, /* (376) indexed_opt ::= indexed_by */ 0, /* (377) returning ::= */ -1, /* (378) expr ::= term */ -1, /* (379) likeop ::= LIKE_KW|MATCH */ -1, /* (380) case_operand ::= expr */ -1, /* (381) exprlist ::= nexprlist */ -1, /* (382) nmnum ::= plus_num */ -1, /* (383) nmnum ::= nm */ -1, /* (384) nmnum ::= ON */ -1, /* (385) nmnum ::= DELETE */ -1, /* (386) nmnum ::= DEFAULT */ -1, /* (387) plus_num ::= INTEGER|FLOAT */ 0, /* (388) foreach_clause ::= */ -3, /* (389) foreach_clause ::= FOR EACH ROW */ -1, /* (390) trnm ::= nm */ 0, /* (391) tridxby ::= */ -1, /* (392) database_kw_opt ::= DATABASE */ 0, /* (393) database_kw_opt ::= */ 0, /* (394) kwcolumn_opt ::= */ -1, /* (395) kwcolumn_opt ::= COLUMNKW */ -1, /* (396) vtabarglist ::= vtabarg */ -3, /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ -2, /* (398) vtabarg ::= vtabarg vtabargtoken */ 0, /* (399) anylist ::= */ -4, /* (400) anylist ::= anylist LP anylist RP */ -2, /* (401) anylist ::= anylist ANY */ 0, /* (402) with ::= */ -1, /* (403) windowdefn_list ::= windowdefn */ -1, /* (404) window ::= frame_opt */ }; static void yy_accept(yyParser*); /* Forward Declaration */ /* ** Perform a reduce action and the shift that must immediately ** follow the reduce. ** ** The yyLookahead and yyLookaheadToken parameters provide reduce actions ** access to the lookahead token (if any). The yyLookahead will be YYNOCODE ** if the lookahead token has already been consumed. As this procedure is ** only called from one place, optimizing compilers will in-line it, which ** means that the extra parameters have no performance impact. */ static YYACTIONTYPE yy_reduce( yyParser *yypParser, /* The parser */ unsigned int yyruleno, /* Number of the rule by which to reduce */ int yyLookahead, /* Lookahead token, or YYNOCODE if none */ sqlite3ParserTOKENTYPE yyLookaheadToken /* Value of the lookahead token */ sqlite3ParserCTX_PDECL /* %extra_context */ ){ int yygoto; /* The next state */ YYACTIONTYPE yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ sqlite3ParserARG_FETCH (void)yyLookahead; (void)yyLookaheadToken; yymsp = yypParser->yytos; switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example ** follows: ** case 0: ** #line ** { ... } // User supplied code ** #line ** break; */ /********** Begin reduce actions **********************************************/ YYMINORTYPE yylhsminor; case 0: /* explain ::= EXPLAIN */ { if( pParse->pReprepare==0 ) pParse->explain = 1; } break; case 1: /* explain ::= EXPLAIN QUERY PLAN */ { if( pParse->pReprepare==0 ) pParse->explain = 2; } break; case 2: /* cmdx ::= cmd */ { sqlite3FinishCoding(pParse); } break; case 3: /* cmd ::= BEGIN transtype trans_opt */ {sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy394);} break; case 4: /* transtype ::= */ {yymsp[1].minor.yy394 = TK_DEFERRED;} break; case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); case 321: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==321); {yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/} break; case 8: /* cmd ::= COMMIT|END trans_opt */ case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); {sqlite3EndTransaction(pParse,yymsp[-1].major);} break; case 10: /* cmd ::= SAVEPOINT nm */ { sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0); } break; case 11: /* cmd ::= RELEASE savepoint_opt nm */ { sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0); } break; case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ { sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); } break; case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy394,0,0,yymsp[-2].minor.yy394); } break; case 14: /* createkw ::= CREATE */ {disableLookaside(pParse);} break; case 15: /* ifnotexists ::= */ case 18: /* temp ::= */ yytestcase(yyruleno==18); case 47: /* autoinc ::= */ yytestcase(yyruleno==47); case 62: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==62); case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72); case 81: /* ifexists ::= */ yytestcase(yyruleno==81); case 98: /* distinct ::= */ yytestcase(yyruleno==98); case 244: /* collate ::= */ yytestcase(yyruleno==244); {yymsp[1].minor.yy394 = 0;} break; case 16: /* ifnotexists ::= IF NOT EXISTS */ {yymsp[-2].minor.yy394 = 1;} break; case 17: /* temp ::= TEMP */ {yymsp[0].minor.yy394 = pParse->db->init.busy==0;} break; case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */ { sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy285,0); } break; case 20: /* create_table_args ::= AS select */ { sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy47); sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47); } break; case 21: /* table_option_set ::= */ {yymsp[1].minor.yy285 = 0;} break; case 22: /* table_option_set ::= table_option_set COMMA table_option */ {yylhsminor.yy285 = yymsp[-2].minor.yy285|yymsp[0].minor.yy285;} yymsp[-2].minor.yy285 = yylhsminor.yy285; break; case 23: /* table_option ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ yymsp[-1].minor.yy285 = TF_WithoutRowid | TF_NoVisibleRowid; }else{ yymsp[-1].minor.yy285 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } break; case 24: /* table_option ::= nm */ { if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){ yylhsminor.yy285 = TF_Strict; }else{ yylhsminor.yy285 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } yymsp[0].minor.yy285 = yylhsminor.yy285; break; case 25: /* columnname ::= nm typetoken */ {sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);} break; case 26: /* typetoken ::= */ case 65: /* conslist_opt ::= */ yytestcase(yyruleno==65); case 104: /* as ::= */ yytestcase(yyruleno==104); {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} break; case 27: /* typetoken ::= typename LP signed RP */ { yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); } break; case 28: /* typetoken ::= typename LP signed COMMA signed RP */ { yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z); } break; case 29: /* typename ::= typename ID|STRING */ {yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} break; case 30: /* scanpt ::= */ { assert( yyLookahead!=YYNOCODE ); yymsp[1].minor.yy522 = yyLookaheadToken.z; } break; case 31: /* scantok ::= */ { assert( yyLookahead!=YYNOCODE ); yymsp[1].minor.yy0 = yyLookaheadToken; } break; case 32: /* ccons ::= CONSTRAINT nm */ case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67); {pParse->constraintName = yymsp[0].minor.yy0;} break; case 33: /* ccons ::= DEFAULT scantok term */ {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; case 34: /* ccons ::= DEFAULT LP expr RP */ {sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} break; case 35: /* ccons ::= DEFAULT PLUS scantok term */ {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; case 36: /* ccons ::= DEFAULT MINUS scantok term */ { Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy528, 0); sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]); } break; case 37: /* ccons ::= DEFAULT scantok ID|INDEXED */ { Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0); if( p ){ sqlite3ExprIdToTrueFalse(p); testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) ); } sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n); } break; case 38: /* ccons ::= NOT NULL onconf */ {sqlite3AddNotNull(pParse, yymsp[0].minor.yy394);} break; case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ {sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy394,yymsp[0].minor.yy394,yymsp[-2].minor.yy394);} break; case 40: /* ccons ::= UNIQUE onconf */ {sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy394,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; case 41: /* ccons ::= CHECK LP expr RP */ {sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} break; case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */ {sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy394);} break; case 43: /* ccons ::= defer_subclause */ {sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy394);} break; case 44: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; case 45: /* generated ::= LP expr RP */ {sqlite3AddGenerated(pParse,yymsp[-1].minor.yy528,0);} break; case 46: /* generated ::= LP expr RP ID */ {sqlite3AddGenerated(pParse,yymsp[-2].minor.yy528,&yymsp[0].minor.yy0);} break; case 48: /* autoinc ::= AUTOINCR */ {yymsp[0].minor.yy394 = 1;} break; case 49: /* refargs ::= */ { yymsp[1].minor.yy394 = OE_None*0x0101; /* EV: R-19803-45884 */} break; case 50: /* refargs ::= refargs refarg */ { yymsp[-1].minor.yy394 = (yymsp[-1].minor.yy394 & ~yymsp[0].minor.yy231.mask) | yymsp[0].minor.yy231.value; } break; case 51: /* refarg ::= MATCH nm */ { yymsp[-1].minor.yy231.value = 0; yymsp[-1].minor.yy231.mask = 0x000000; } break; case 52: /* refarg ::= ON INSERT refact */ { yymsp[-2].minor.yy231.value = 0; yymsp[-2].minor.yy231.mask = 0x000000; } break; case 53: /* refarg ::= ON DELETE refact */ { yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394; yymsp[-2].minor.yy231.mask = 0x0000ff; } break; case 54: /* refarg ::= ON UPDATE refact */ { yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394<<8; yymsp[-2].minor.yy231.mask = 0x00ff00; } break; case 55: /* refact ::= SET NULL */ { yymsp[-1].minor.yy394 = OE_SetNull; /* EV: R-33326-45252 */} break; case 56: /* refact ::= SET DEFAULT */ { yymsp[-1].minor.yy394 = OE_SetDflt; /* EV: R-33326-45252 */} break; case 57: /* refact ::= CASCADE */ { yymsp[0].minor.yy394 = OE_Cascade; /* EV: R-33326-45252 */} break; case 58: /* refact ::= RESTRICT */ { yymsp[0].minor.yy394 = OE_Restrict; /* EV: R-33326-45252 */} break; case 59: /* refact ::= NO ACTION */ { yymsp[-1].minor.yy394 = OE_None; /* EV: R-33326-45252 */} break; case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ {yymsp[-2].minor.yy394 = 0;} break; case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76); case 171: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==171); {yymsp[-1].minor.yy394 = yymsp[0].minor.yy394;} break; case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80); case 217: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==217); case 220: /* in_op ::= NOT IN */ yytestcase(yyruleno==220); case 245: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==245); {yymsp[-1].minor.yy394 = 1;} break; case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ {yymsp[-1].minor.yy394 = 0;} break; case 66: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ {sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy394,yymsp[-2].minor.yy394,0);} break; case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */ {sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy394,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; case 70: /* tcons ::= CHECK LP expr RP onconf */ {sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy528,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);} break; case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy394); sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy394); } break; case 73: /* onconf ::= */ case 75: /* orconf ::= */ yytestcase(yyruleno==75); {yymsp[1].minor.yy394 = OE_Default;} break; case 74: /* onconf ::= ON CONFLICT resolvetype */ {yymsp[-2].minor.yy394 = yymsp[0].minor.yy394;} break; case 77: /* resolvetype ::= IGNORE */ {yymsp[0].minor.yy394 = OE_Ignore;} break; case 78: /* resolvetype ::= REPLACE */ case 172: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==172); {yymsp[0].minor.yy394 = OE_Replace;} break; case 79: /* cmd ::= DROP TABLE ifexists fullname */ { sqlite3DropTable(pParse, yymsp[0].minor.yy131, 0, yymsp[-1].minor.yy394); } break; case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[0].minor.yy47, yymsp[-7].minor.yy394, yymsp[-5].minor.yy394); } break; case 83: /* cmd ::= DROP VIEW ifexists fullname */ { sqlite3DropTable(pParse, yymsp[0].minor.yy131, 1, yymsp[-1].minor.yy394); } break; case 84: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0}; sqlite3Select(pParse, yymsp[0].minor.yy47, &dest); sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47); } break; case 85: /* select ::= WITH wqlist selectnowith */ {yymsp[-2].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);} break; case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */ {yymsp[-3].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);} break; case 87: /* select ::= selectnowith */ { Select *p = yymsp[0].minor.yy47; if( p ){ parserDoubleLinkSelect(pParse, p); } } break; case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */ { Select *pRhs = yymsp[0].minor.yy47; Select *pLhs = yymsp[-2].minor.yy47; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; x.n = 0; parserDoubleLinkSelect(pParse, pRhs); pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0); pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); } if( pRhs ){ pRhs->op = (u8)yymsp[-1].minor.yy394; pRhs->pPrior = pLhs; if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; pRhs->selFlags &= ~SF_MultiValue; if( yymsp[-1].minor.yy394!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); } yymsp[-2].minor.yy47 = pRhs; } break; case 89: /* multiselect_op ::= UNION */ case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91); {yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-OP*/} break; case 90: /* multiselect_op ::= UNION ALL */ {yymsp[-1].minor.yy394 = TK_ALL;} break; case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { yymsp[-8].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy131,yymsp[-4].minor.yy528,yymsp[-3].minor.yy322,yymsp[-2].minor.yy528,yymsp[-1].minor.yy322,yymsp[-7].minor.yy394,yymsp[0].minor.yy528); } break; case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ { yymsp[-9].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy322,yymsp[-6].minor.yy131,yymsp[-5].minor.yy528,yymsp[-4].minor.yy322,yymsp[-3].minor.yy528,yymsp[-1].minor.yy322,yymsp[-8].minor.yy394,yymsp[0].minor.yy528); if( yymsp[-9].minor.yy47 ){ yymsp[-9].minor.yy47->pWinDefn = yymsp[-2].minor.yy41; }else{ sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy41); } } break; case 94: /* values ::= VALUES LP nexprlist RP */ { yymsp[-3].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0); } break; case 95: /* values ::= values COMMA LP nexprlist RP */ { Select *pRight, *pLeft = yymsp[-4].minor.yy47; pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0); if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; if( pRight ){ pRight->op = TK_ALL; pRight->pPrior = pLeft; yymsp[-4].minor.yy47 = pRight; }else{ yymsp[-4].minor.yy47 = pLeft; } } break; case 96: /* distinct ::= DISTINCT */ {yymsp[0].minor.yy394 = SF_Distinct;} break; case 97: /* distinct ::= ALL */ {yymsp[0].minor.yy394 = SF_All;} break; case 99: /* sclp ::= */ case 132: /* orderby_opt ::= */ yytestcase(yyruleno==132); case 142: /* groupby_opt ::= */ yytestcase(yyruleno==142); case 232: /* exprlist ::= */ yytestcase(yyruleno==232); case 235: /* paren_exprlist ::= */ yytestcase(yyruleno==235); case 240: /* eidlist_opt ::= */ yytestcase(yyruleno==240); {yymsp[1].minor.yy322 = 0;} break; case 100: /* selcollist ::= sclp scanpt expr scanpt as */ { yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[-2].minor.yy528); if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[0].minor.yy0, 1); sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy322,yymsp[-3].minor.yy522,yymsp[-1].minor.yy522); } break; case 101: /* selcollist ::= sclp scanpt STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail)); yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p); } break; case 102: /* selcollist ::= sclp scanpt nm DOT STAR */ { Expr *pRight, *pLeft, *pDot; pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); sqlite3ExprSetErrorOffset(pRight, (int)(yymsp[0].minor.yy0.z - pParse->zTail)); pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0); pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, pDot); } break; case 103: /* as ::= AS nm */ case 115: /* dbnm ::= DOT nm */ yytestcase(yyruleno==115); case 256: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==256); case 257: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==257); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; case 105: /* from ::= */ case 108: /* stl_prefix ::= */ yytestcase(yyruleno==108); {yymsp[1].minor.yy131 = 0;} break; case 106: /* from ::= FROM seltablist */ { yymsp[-1].minor.yy131 = yymsp[0].minor.yy131; sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy131); } break; case 107: /* stl_prefix ::= seltablist joinop */ { if( ALWAYS(yymsp[-1].minor.yy131 && yymsp[-1].minor.yy131->nSrc>0) ) yymsp[-1].minor.yy131->a[yymsp[-1].minor.yy131->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy394; } break; case 109: /* seltablist ::= stl_prefix nm dbnm as on_using */ { yymsp[-4].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy131,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561); } break; case 110: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ { yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy561); sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-1].minor.yy0); } break; case 111: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ { yymsp[-7].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy131,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561); sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy131, yymsp[-3].minor.yy322); } break; case 112: /* seltablist ::= stl_prefix LP select RP as on_using */ { yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy47,&yymsp[0].minor.yy561); } break; case 113: /* seltablist ::= stl_prefix LP seltablist RP as on_using */ { if( yymsp[-5].minor.yy131==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy561.pOn==0 && yymsp[0].minor.yy561.pUsing==0 ){ yymsp[-5].minor.yy131 = yymsp[-3].minor.yy131; }else if( ALWAYS(yymsp[-3].minor.yy131!=0) && yymsp[-3].minor.yy131->nSrc==1 ){ yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561); if( yymsp[-5].minor.yy131 ){ SrcItem *pNew = &yymsp[-5].minor.yy131->a[yymsp[-5].minor.yy131->nSrc-1]; SrcItem *pOld = yymsp[-3].minor.yy131->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){ pNew->fg.isNestedFrom = 1; } if( pOld->fg.isTabFunc ){ pNew->u1.pFuncArg = pOld->u1.pFuncArg; pOld->u1.pFuncArg = 0; pOld->fg.isTabFunc = 0; pNew->fg.isTabFunc = 1; } pOld->zName = pOld->zDatabase = 0; pOld->pSelect = 0; } sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy131); }else{ Select *pSubquery; sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy131); pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy131,0,0,0,0,SF_NestedFrom,0); yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy561); } } break; case 114: /* dbnm ::= */ case 129: /* indexed_opt ::= */ yytestcase(yyruleno==129); {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; case 116: /* fullname ::= nm */ { yylhsminor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0); } yymsp[0].minor.yy131 = yylhsminor.yy131; break; case 117: /* fullname ::= nm DOT nm */ { yylhsminor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0); } yymsp[-2].minor.yy131 = yylhsminor.yy131; break; case 118: /* xfullname ::= nm */ {yymsp[0].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} break; case 119: /* xfullname ::= nm DOT nm */ {yymsp[-2].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} break; case 120: /* xfullname ::= nm DOT nm AS nm */ { yymsp[-4].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ if( yymsp[-4].minor.yy131 ) yymsp[-4].minor.yy131->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; case 121: /* xfullname ::= nm AS nm */ { yymsp[-2].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ if( yymsp[-2].minor.yy131 ) yymsp[-2].minor.yy131->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; case 122: /* joinop ::= COMMA|JOIN */ { yymsp[0].minor.yy394 = JT_INNER; } break; case 123: /* joinop ::= JOIN_KW JOIN */ {yymsp[-1].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; case 124: /* joinop ::= JOIN_KW nm JOIN */ {yymsp[-2].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} break; case 125: /* joinop ::= JOIN_KW nm nm JOIN */ {yymsp[-3].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} break; case 126: /* on_using ::= ON expr */ {yymsp[-1].minor.yy561.pOn = yymsp[0].minor.yy528; yymsp[-1].minor.yy561.pUsing = 0;} break; case 127: /* on_using ::= USING LP idlist RP */ {yymsp[-3].minor.yy561.pOn = 0; yymsp[-3].minor.yy561.pUsing = yymsp[-1].minor.yy254;} break; case 128: /* on_using ::= */ {yymsp[1].minor.yy561.pOn = 0; yymsp[1].minor.yy561.pUsing = 0;} break; case 130: /* indexed_by ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; case 131: /* indexed_by ::= NOT INDEXED */ {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; case 133: /* orderby_opt ::= ORDER BY sortlist */ case 143: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==143); {yymsp[-2].minor.yy322 = yymsp[0].minor.yy322;} break; case 134: /* sortlist ::= sortlist COMMA expr sortorder nulls */ { yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322,yymsp[-2].minor.yy528); sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394); } break; case 135: /* sortlist ::= expr sortorder nulls */ { yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy528); /*A-overwrites-Y*/ sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394); } break; case 136: /* sortorder ::= ASC */ {yymsp[0].minor.yy394 = SQLITE_SO_ASC;} break; case 137: /* sortorder ::= DESC */ {yymsp[0].minor.yy394 = SQLITE_SO_DESC;} break; case 138: /* sortorder ::= */ case 141: /* nulls ::= */ yytestcase(yyruleno==141); {yymsp[1].minor.yy394 = SQLITE_SO_UNDEFINED;} break; case 139: /* nulls ::= NULLS FIRST */ {yymsp[-1].minor.yy394 = SQLITE_SO_ASC;} break; case 140: /* nulls ::= NULLS LAST */ {yymsp[-1].minor.yy394 = SQLITE_SO_DESC;} break; case 144: /* having_opt ::= */ case 146: /* limit_opt ::= */ yytestcase(yyruleno==146); case 151: /* where_opt ::= */ yytestcase(yyruleno==151); case 153: /* where_opt_ret ::= */ yytestcase(yyruleno==153); case 230: /* case_else ::= */ yytestcase(yyruleno==230); case 231: /* case_operand ::= */ yytestcase(yyruleno==231); case 250: /* vinto ::= */ yytestcase(yyruleno==250); {yymsp[1].minor.yy528 = 0;} break; case 145: /* having_opt ::= HAVING expr */ case 152: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==152); case 154: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==154); case 229: /* case_else ::= ELSE expr */ yytestcase(yyruleno==229); case 249: /* vinto ::= INTO expr */ yytestcase(yyruleno==249); {yymsp[-1].minor.yy528 = yymsp[0].minor.yy528;} break; case 147: /* limit_opt ::= LIMIT expr */ {yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,0);} break; case 148: /* limit_opt ::= LIMIT expr OFFSET expr */ {yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} break; case 149: /* limit_opt ::= LIMIT expr COMMA expr */ {yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,yymsp[-2].minor.yy528);} break; case 150: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ { sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy131, &yymsp[-1].minor.yy0); sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy131,yymsp[0].minor.yy528,0,0); } break; case 155: /* where_opt_ret ::= RETURNING selcollist */ {sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-1].minor.yy528 = 0;} break; case 156: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ {sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-3].minor.yy528 = yymsp[-2].minor.yy528;} break; case 157: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ { sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-4].minor.yy0); sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy322,"set list"); if( yymsp[-1].minor.yy131 ){ SrcList *pFromClause = yymsp[-1].minor.yy131; if( pFromClause->nSrc>1 ){ Select *pSubquery; Token as; pSubquery = sqlite3SelectNew(pParse,0,pFromClause,0,0,0,0,SF_NestedFrom,0); as.n = 0; as.z = 0; pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); } yymsp[-5].minor.yy131 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy131, pFromClause); } sqlite3Update(pParse,yymsp[-5].minor.yy131,yymsp[-2].minor.yy322,yymsp[0].minor.yy528,yymsp[-6].minor.yy394,0,0,0); } break; case 158: /* setlist ::= setlist COMMA nm EQ expr */ { yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy528); sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, 1); } break; case 159: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { yymsp[-6].minor.yy322 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy322, yymsp[-3].minor.yy254, yymsp[0].minor.yy528); } break; case 160: /* setlist ::= nm EQ expr */ { yylhsminor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy528); sqlite3ExprListSetName(pParse, yylhsminor.yy322, &yymsp[-2].minor.yy0, 1); } yymsp[-2].minor.yy322 = yylhsminor.yy322; break; case 161: /* setlist ::= LP idlist RP EQ expr */ { yymsp[-4].minor.yy322 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy528); } break; case 162: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ { sqlite3Insert(pParse, yymsp[-3].minor.yy131, yymsp[-1].minor.yy47, yymsp[-2].minor.yy254, yymsp[-5].minor.yy394, yymsp[0].minor.yy444); } break; case 163: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ { sqlite3Insert(pParse, yymsp[-4].minor.yy131, 0, yymsp[-3].minor.yy254, yymsp[-6].minor.yy394, 0); } break; case 164: /* upsert ::= */ { yymsp[1].minor.yy444 = 0; } break; case 165: /* upsert ::= RETURNING selcollist */ { yymsp[-1].minor.yy444 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy322); } break; case 166: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ { yymsp[-11].minor.yy444 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy322,yymsp[-6].minor.yy528,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,yymsp[0].minor.yy444);} break; case 167: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ { yymsp[-8].minor.yy444 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy322,yymsp[-3].minor.yy528,0,0,yymsp[0].minor.yy444); } break; case 168: /* upsert ::= ON CONFLICT DO NOTHING returning */ { yymsp[-4].minor.yy444 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } break; case 169: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ { yymsp[-7].minor.yy444 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,0);} break; case 170: /* returning ::= RETURNING selcollist */ {sqlite3AddReturning(pParse,yymsp[0].minor.yy322);} break; case 173: /* idlist_opt ::= */ {yymsp[1].minor.yy254 = 0;} break; case 174: /* idlist_opt ::= LP idlist RP */ {yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} break; case 175: /* idlist ::= idlist COMMA nm */ {yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);} break; case 176: /* idlist ::= nm */ {yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} break; case 177: /* expr ::= LP expr RP */ {yymsp[-2].minor.yy528 = yymsp[-1].minor.yy528;} break; case 178: /* expr ::= ID|INDEXED|JOIN_KW */ {yymsp[0].minor.yy528=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; case 179: /* expr ::= nm DOT nm */ { Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); yylhsminor.yy528 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } yymsp[-2].minor.yy528 = yylhsminor.yy528; break; case 180: /* expr ::= nm DOT nm DOT nm */ { Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-4].minor.yy0); Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); Expr *temp3 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, 0, temp1); } yylhsminor.yy528 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); } yymsp[-4].minor.yy528 = yylhsminor.yy528; break; case 181: /* term ::= NULL|FLOAT|BLOB */ case 182: /* term ::= STRING */ yytestcase(yyruleno==182); {yymsp[0].minor.yy528=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; case 183: /* term ::= INTEGER */ { yylhsminor.yy528 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); if( yylhsminor.yy528 ) yylhsminor.yy528->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail); } yymsp[0].minor.yy528 = yylhsminor.yy528; break; case 184: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; yymsp[0].minor.yy528 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy528, n); }else{ /* When doing a nested parse, one can include terms in an expression ** that look like this: #1 #2 ... These terms refer to registers ** in the virtual machine. #N is the N-th register. */ Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/ assert( t.n>=2 ); if( pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); yymsp[0].minor.yy528 = 0; }else{ yymsp[0].minor.yy528 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); if( yymsp[0].minor.yy528 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy528->iTable); } } } break; case 185: /* expr ::= expr COLLATE ID|STRING */ { yymsp[-2].minor.yy528 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy528, &yymsp[0].minor.yy0, 1); } break; case 186: /* expr ::= CAST LP expr AS typetoken RP */ { yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy528, yymsp[-3].minor.yy528, 0); } break; case 187: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy394); } yymsp[-4].minor.yy528 = yylhsminor.yy528; break; case 188: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy322, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy394); sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy528, yymsp[-1].minor.yy322); } yymsp[-7].minor.yy528 = yylhsminor.yy528; break; case 189: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); } yymsp[-3].minor.yy528 = yylhsminor.yy528; break; case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy322, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy394); sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); } yymsp[-5].minor.yy528 = yylhsminor.yy528; break; case 191: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy322, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy394); sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy528, yymsp[-2].minor.yy322); } yymsp[-8].minor.yy528 = yylhsminor.yy528; break; case 192: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); } yymsp[-4].minor.yy528 = yylhsminor.yy528; break; case 193: /* term ::= CTIME_KW */ { yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); } yymsp[0].minor.yy528 = yylhsminor.yy528; break; case 194: /* expr ::= LP nexprlist COMMA expr RP */ { ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528); yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); if( yymsp[-4].minor.yy528 ){ yymsp[-4].minor.yy528->x.pList = pList; if( ALWAYS(pList->nExpr) ){ yymsp[-4].minor.yy528->flags |= pList->a[0].pExpr->flags & EP_Propagate; } }else{ sqlite3ExprListDelete(pParse->db, pList); } } break; case 195: /* expr ::= expr AND expr */ {yymsp[-2].minor.yy528=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} break; case 196: /* expr ::= expr OR expr */ case 197: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==197); case 198: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==198); case 199: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==199); case 200: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==200); case 201: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==201); case 202: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==202); {yymsp[-2].minor.yy528=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} break; case 203: /* likeop ::= NOT LIKE_KW|MATCH */ {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} break; case 204: /* expr ::= expr likeop expr */ { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; yymsp[-1].minor.yy0.n &= 0x7fffffff; pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy528); pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy528); yymsp[-2].minor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); if( bNot ) yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy528, 0); if( yymsp[-2].minor.yy528 ) yymsp[-2].minor.yy528->flags |= EP_InfixFunc; } break; case 205: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; yymsp[-3].minor.yy0.n &= 0x7fffffff; pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy528); pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528); yymsp[-4].minor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); if( bNot ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); if( yymsp[-4].minor.yy528 ) yymsp[-4].minor.yy528->flags |= EP_InfixFunc; } break; case 206: /* expr ::= expr ISNULL|NOTNULL */ {yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy528,0);} break; case 207: /* expr ::= expr NOT NULL */ {yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy528,0);} break; case 208: /* expr ::= expr IS expr */ { yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy528,yymsp[0].minor.yy528); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-2].minor.yy528, TK_ISNULL); } break; case 209: /* expr ::= expr IS NOT expr */ { yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy528,yymsp[0].minor.yy528); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-3].minor.yy528, TK_NOTNULL); } break; case 210: /* expr ::= expr IS NOT DISTINCT FROM expr */ { yymsp[-5].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy528,yymsp[0].minor.yy528); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-5].minor.yy528, TK_ISNULL); } break; case 211: /* expr ::= expr IS DISTINCT FROM expr */ { yymsp[-4].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy528,yymsp[0].minor.yy528); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-4].minor.yy528, TK_NOTNULL); } break; case 212: /* expr ::= NOT expr */ case 213: /* expr ::= BITNOT expr */ yytestcase(yyruleno==213); {yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy528, 0);/*A-overwrites-B*/} break; case 214: /* expr ::= PLUS|MINUS expr */ { yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy528, 0); /*A-overwrites-B*/ } break; case 215: /* expr ::= expr PTR expr */ { ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy528); pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy528); yylhsminor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); } yymsp[-2].minor.yy528 = yylhsminor.yy528; break; case 216: /* between_op ::= BETWEEN */ case 219: /* in_op ::= IN */ yytestcase(yyruleno==219); {yymsp[0].minor.yy394 = 0;} break; case 218: /* expr ::= expr between_op expr AND expr */ { ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528); yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy528, 0); if( yymsp[-4].minor.yy528 ){ yymsp[-4].minor.yy528->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; case 221: /* expr ::= expr in_op LP exprlist RP */ { if( yymsp[-1].minor.yy322==0 ){ /* Expressions of the form ** ** expr1 IN () ** expr1 NOT IN () ** ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy528); yymsp[-4].minor.yy528 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy394 ? "true" : "false"); if( yymsp[-4].minor.yy528 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy528); }else{ Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr; if( yymsp[-1].minor.yy322->nExpr==1 && sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy528->op!=TK_VECTOR ){ yymsp[-1].minor.yy322->a[0].pExpr = 0; sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy528, pRHS); }else if( yymsp[-1].minor.yy322->nExpr==1 && pRHS->op==TK_SELECT ){ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pRHS->x.pSelect); pRHS->x.pSelect = 0; sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); }else{ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); if( yymsp[-4].minor.yy528==0 ){ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); }else if( yymsp[-4].minor.yy528->pLeft->op==TK_VECTOR ){ int nExpr = yymsp[-4].minor.yy528->pLeft->x.pList->nExpr; Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy322); if( pSelectRHS ){ parserDoubleLinkSelect(pParse, pSelectRHS); sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelectRHS); } }else{ yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy322; sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528); } } if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } } break; case 222: /* expr ::= LP select RP */ { yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy528, yymsp[-1].minor.yy47); } break; case 223: /* expr ::= expr in_op LP select RP */ { yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, yymsp[-1].minor.yy47); if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; case 224: /* expr ::= expr in_op nm dbnm paren_exprlist */ { SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); if( yymsp[0].minor.yy322 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy322); yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelect); if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; case 225: /* expr ::= EXISTS LP select RP */ { Expr *p; p = yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy47); } break; case 226: /* expr ::= CASE case_operand case_exprlist case_else END */ { yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy528, 0); if( yymsp[-4].minor.yy528 ){ yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy528 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528) : yymsp[-2].minor.yy322; sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528); }else{ sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322); sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528); } } break; case 227: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy528); yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy528); } break; case 228: /* case_exprlist ::= WHEN expr THEN expr */ { yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy528); } break; case 233: /* nexprlist ::= nexprlist COMMA expr */ {yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy528);} break; case 234: /* nexprlist ::= expr */ {yymsp[0].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy528); /*A-overwrites-Y*/} break; case 236: /* paren_exprlist ::= LP exprlist RP */ case 241: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==241); {yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;} break; case 237: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy394, &yymsp[-11].minor.yy0, yymsp[0].minor.yy528, SQLITE_SO_ASC, yymsp[-8].minor.yy394, SQLITE_IDXTYPE_APPDEF); if( IN_RENAME_OBJECT && pParse->pNewIndex ){ sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0); } } break; case 238: /* uniqueflag ::= UNIQUE */ case 280: /* raisetype ::= ABORT */ yytestcase(yyruleno==280); {yymsp[0].minor.yy394 = OE_Abort;} break; case 239: /* uniqueflag ::= */ {yymsp[1].minor.yy394 = OE_None;} break; case 242: /* eidlist ::= eidlist COMMA nm collate sortorder */ { yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); } break; case 243: /* eidlist ::= nm collate sortorder */ { yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); /*A-overwrites-Y*/ } break; case 246: /* cmd ::= DROP INDEX ifexists fullname */ {sqlite3DropIndex(pParse, yymsp[0].minor.yy131, yymsp[-1].minor.yy394);} break; case 247: /* cmd ::= VACUUM vinto */ {sqlite3Vacuum(pParse,0,yymsp[0].minor.yy528);} break; case 248: /* cmd ::= VACUUM nm vinto */ {sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy528);} break; case 251: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; case 252: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; case 253: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; case 254: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; case 255: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; case 258: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy33, &all); } break; case 259: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy394, yymsp[-4].minor.yy180.a, yymsp[-4].minor.yy180.b, yymsp[-2].minor.yy131, yymsp[0].minor.yy528, yymsp[-10].minor.yy394, yymsp[-8].minor.yy394); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; case 260: /* trigger_time ::= BEFORE|AFTER */ { yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/ } break; case 261: /* trigger_time ::= INSTEAD OF */ { yymsp[-1].minor.yy394 = TK_INSTEAD;} break; case 262: /* trigger_time ::= */ { yymsp[1].minor.yy394 = TK_BEFORE; } break; case 263: /* trigger_event ::= DELETE|INSERT */ case 264: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==264); {yymsp[0].minor.yy180.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy180.b = 0;} break; case 265: /* trigger_event ::= UPDATE OF idlist */ {yymsp[-2].minor.yy180.a = TK_UPDATE; yymsp[-2].minor.yy180.b = yymsp[0].minor.yy254;} break; case 266: /* when_clause ::= */ case 285: /* key_opt ::= */ yytestcase(yyruleno==285); { yymsp[1].minor.yy528 = 0; } break; case 267: /* when_clause ::= WHEN expr */ case 286: /* key_opt ::= KEY expr */ yytestcase(yyruleno==286); { yymsp[-1].minor.yy528 = yymsp[0].minor.yy528; } break; case 268: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { assert( yymsp[-2].minor.yy33!=0 ); yymsp[-2].minor.yy33->pLast->pNext = yymsp[-1].minor.yy33; yymsp[-2].minor.yy33->pLast = yymsp[-1].minor.yy33; } break; case 269: /* trigger_cmd_list ::= trigger_cmd SEMI */ { assert( yymsp[-1].minor.yy33!=0 ); yymsp[-1].minor.yy33->pLast = yymsp[-1].minor.yy33; } break; case 270: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, "qualified table names are not allowed on INSERT, UPDATE, and DELETE " "statements within triggers"); } break; case 271: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; case 272: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; case 273: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ {yylhsminor.yy33 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy131, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528, yymsp[-7].minor.yy394, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy522);} yymsp[-8].minor.yy33 = yylhsminor.yy33; break; case 274: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ { yylhsminor.yy33 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy254,yymsp[-2].minor.yy47,yymsp[-6].minor.yy394,yymsp[-1].minor.yy444,yymsp[-7].minor.yy522,yymsp[0].minor.yy522);/*yylhsminor.yy33-overwrites-yymsp[-6].minor.yy394*/ } yymsp[-7].minor.yy33 = yylhsminor.yy33; break; case 275: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ {yylhsminor.yy33 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy528, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy522);} yymsp[-5].minor.yy33 = yylhsminor.yy33; break; case 276: /* trigger_cmd ::= scanpt select scanpt */ {yylhsminor.yy33 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy47, yymsp[-2].minor.yy522, yymsp[0].minor.yy522); /*yylhsminor.yy33-overwrites-yymsp[-1].minor.yy47*/} yymsp[-2].minor.yy33 = yylhsminor.yy33; break; case 277: /* expr ::= RAISE LP IGNORE RP */ { yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); if( yymsp[-3].minor.yy528 ){ yymsp[-3].minor.yy528->affExpr = OE_Ignore; } } break; case 278: /* expr ::= RAISE LP raisetype COMMA nm RP */ { yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); if( yymsp[-5].minor.yy528 ) { yymsp[-5].minor.yy528->affExpr = (char)yymsp[-3].minor.yy394; } } break; case 279: /* raisetype ::= ROLLBACK */ {yymsp[0].minor.yy394 = OE_Rollback;} break; case 281: /* raisetype ::= FAIL */ {yymsp[0].minor.yy394 = OE_Fail;} break; case 282: /* cmd ::= DROP TRIGGER ifexists fullname */ { sqlite3DropTrigger(pParse,yymsp[0].minor.yy131,yymsp[-1].minor.yy394); } break; case 283: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { sqlite3Attach(pParse, yymsp[-3].minor.yy528, yymsp[-1].minor.yy528, yymsp[0].minor.yy528); } break; case 284: /* cmd ::= DETACH database_kw_opt expr */ { sqlite3Detach(pParse, yymsp[0].minor.yy528); } break; case 287: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; case 288: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; case 289: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; case 290: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; case 291: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy131,&yymsp[0].minor.yy0); } break; case 292: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; case 293: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ { sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy131, &yymsp[0].minor.yy0); } break; case 294: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy131); } break; case 295: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ { sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy131, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); } break; case 296: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; case 297: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; case 298: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy394); } break; case 299: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; case 300: /* vtabargtoken ::= ANY */ case 301: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==301); case 302: /* lp ::= LP */ yytestcase(yyruleno==302); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; case 303: /* with ::= WITH wqlist */ case 304: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==304); { sqlite3WithPush(pParse, yymsp[0].minor.yy521, 1); } break; case 305: /* wqas ::= AS */ {yymsp[0].minor.yy516 = M10d_Any;} break; case 306: /* wqas ::= AS MATERIALIZED */ {yymsp[-1].minor.yy516 = M10d_Yes;} break; case 307: /* wqas ::= AS NOT MATERIALIZED */ {yymsp[-2].minor.yy516 = M10d_No;} break; case 308: /* wqitem ::= nm eidlist_opt wqas LP select RP */ { yymsp[-5].minor.yy385 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy47, yymsp[-3].minor.yy516); /*A-overwrites-X*/ } break; case 309: /* wqlist ::= wqitem */ { yymsp[0].minor.yy521 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy385); /*A-overwrites-X*/ } break; case 310: /* wqlist ::= wqlist COMMA wqitem */ { yymsp[-2].minor.yy521 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy521, yymsp[0].minor.yy385); } break; case 311: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ { assert( yymsp[0].minor.yy41!=0 ); sqlite3WindowChain(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy41); yymsp[0].minor.yy41->pNextWin = yymsp[-2].minor.yy41; yylhsminor.yy41 = yymsp[0].minor.yy41; } yymsp[-2].minor.yy41 = yylhsminor.yy41; break; case 312: /* windowdefn ::= nm AS LP window RP */ { if( ALWAYS(yymsp[-1].minor.yy41) ){ yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); } yylhsminor.yy41 = yymsp[-1].minor.yy41; } yymsp[-4].minor.yy41 = yylhsminor.yy41; break; case 313: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ { yymsp[-4].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, 0); } break; case 314: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ { yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, &yymsp[-5].minor.yy0); } yymsp[-5].minor.yy41 = yylhsminor.yy41; break; case 315: /* window ::= ORDER BY sortlist frame_opt */ { yymsp[-3].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, 0); } break; case 316: /* window ::= nm ORDER BY sortlist frame_opt */ { yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0); } yymsp[-4].minor.yy41 = yylhsminor.yy41; break; case 317: /* window ::= nm frame_opt */ { yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, 0, &yymsp[-1].minor.yy0); } yymsp[-1].minor.yy41 = yylhsminor.yy41; break; case 318: /* frame_opt ::= */ { yymsp[1].minor.yy41 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); } break; case 319: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ { yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy394, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy516); } yymsp[-2].minor.yy41 = yylhsminor.yy41; break; case 320: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ { yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy394, yymsp[-3].minor.yy595.eType, yymsp[-3].minor.yy595.pExpr, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, yymsp[0].minor.yy516); } yymsp[-5].minor.yy41 = yylhsminor.yy41; break; case 322: /* frame_bound_s ::= frame_bound */ case 324: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==324); {yylhsminor.yy595 = yymsp[0].minor.yy595;} yymsp[0].minor.yy595 = yylhsminor.yy595; break; case 323: /* frame_bound_s ::= UNBOUNDED PRECEDING */ case 325: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==325); case 327: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==327); {yylhsminor.yy595.eType = yymsp[-1].major; yylhsminor.yy595.pExpr = 0;} yymsp[-1].minor.yy595 = yylhsminor.yy595; break; case 326: /* frame_bound ::= expr PRECEDING|FOLLOWING */ {yylhsminor.yy595.eType = yymsp[0].major; yylhsminor.yy595.pExpr = yymsp[-1].minor.yy528;} yymsp[-1].minor.yy595 = yylhsminor.yy595; break; case 328: /* frame_exclude_opt ::= */ {yymsp[1].minor.yy516 = 0;} break; case 329: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ {yymsp[-1].minor.yy516 = yymsp[0].minor.yy516;} break; case 330: /* frame_exclude ::= NO OTHERS */ case 331: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==331); {yymsp[-1].minor.yy516 = yymsp[-1].major; /*A-overwrites-X*/} break; case 332: /* frame_exclude ::= GROUP|TIES */ {yymsp[0].minor.yy516 = yymsp[0].major; /*A-overwrites-X*/} break; case 333: /* window_clause ::= WINDOW windowdefn_list */ { yymsp[-1].minor.yy41 = yymsp[0].minor.yy41; } break; case 334: /* filter_over ::= filter_clause over_clause */ { if( yymsp[0].minor.yy41 ){ yymsp[0].minor.yy41->pFilter = yymsp[-1].minor.yy528; }else{ sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528); } yylhsminor.yy41 = yymsp[0].minor.yy41; } yymsp[-1].minor.yy41 = yylhsminor.yy41; break; case 335: /* filter_over ::= over_clause */ { yylhsminor.yy41 = yymsp[0].minor.yy41; } yymsp[0].minor.yy41 = yylhsminor.yy41; break; case 336: /* filter_over ::= filter_clause */ { yylhsminor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( yylhsminor.yy41 ){ yylhsminor.yy41->eFrmType = TK_FILTER; yylhsminor.yy41->pFilter = yymsp[0].minor.yy528; }else{ sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy528); } } yymsp[0].minor.yy41 = yylhsminor.yy41; break; case 337: /* over_clause ::= OVER LP window RP */ { yymsp[-3].minor.yy41 = yymsp[-1].minor.yy41; assert( yymsp[-3].minor.yy41!=0 ); } break; case 338: /* over_clause ::= OVER nm */ { yymsp[-1].minor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( yymsp[-1].minor.yy41 ){ yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); } } break; case 339: /* filter_clause ::= FILTER LP WHERE expr RP */ { yymsp[-4].minor.yy528 = yymsp[-1].minor.yy528; } break; default: /* (340) input ::= cmdlist */ yytestcase(yyruleno==340); /* (341) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==341); /* (342) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=342); /* (343) ecmd ::= SEMI */ yytestcase(yyruleno==343); /* (344) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==344); /* (345) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=345); /* (346) trans_opt ::= */ yytestcase(yyruleno==346); /* (347) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==347); /* (348) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==348); /* (349) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==349); /* (350) savepoint_opt ::= */ yytestcase(yyruleno==350); /* (351) cmd ::= create_table create_table_args */ yytestcase(yyruleno==351); /* (352) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=352); /* (353) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==353); /* (354) columnlist ::= columnname carglist */ yytestcase(yyruleno==354); /* (355) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==355); /* (356) nm ::= STRING */ yytestcase(yyruleno==356); /* (357) typetoken ::= typename */ yytestcase(yyruleno==357); /* (358) typename ::= ID|STRING */ yytestcase(yyruleno==358); /* (359) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=359); /* (360) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=360); /* (361) carglist ::= carglist ccons */ yytestcase(yyruleno==361); /* (362) carglist ::= */ yytestcase(yyruleno==362); /* (363) ccons ::= NULL onconf */ yytestcase(yyruleno==363); /* (364) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==364); /* (365) ccons ::= AS generated */ yytestcase(yyruleno==365); /* (366) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==366); /* (367) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==367); /* (368) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=368); /* (369) tconscomma ::= */ yytestcase(yyruleno==369); /* (370) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=370); /* (371) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=371); /* (372) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=372); /* (373) oneselect ::= values */ yytestcase(yyruleno==373); /* (374) sclp ::= selcollist COMMA */ yytestcase(yyruleno==374); /* (375) as ::= ID|STRING */ yytestcase(yyruleno==375); /* (376) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=376); /* (377) returning ::= */ yytestcase(yyruleno==377); /* (378) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=378); /* (379) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==379); /* (380) case_operand ::= expr */ yytestcase(yyruleno==380); /* (381) exprlist ::= nexprlist */ yytestcase(yyruleno==381); /* (382) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=382); /* (383) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=383); /* (384) nmnum ::= ON */ yytestcase(yyruleno==384); /* (385) nmnum ::= DELETE */ yytestcase(yyruleno==385); /* (386) nmnum ::= DEFAULT */ yytestcase(yyruleno==386); /* (387) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==387); /* (388) foreach_clause ::= */ yytestcase(yyruleno==388); /* (389) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==389); /* (390) trnm ::= nm */ yytestcase(yyruleno==390); /* (391) tridxby ::= */ yytestcase(yyruleno==391); /* (392) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==392); /* (393) database_kw_opt ::= */ yytestcase(yyruleno==393); /* (394) kwcolumn_opt ::= */ yytestcase(yyruleno==394); /* (395) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==395); /* (396) vtabarglist ::= vtabarg */ yytestcase(yyruleno==396); /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==397); /* (398) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==398); /* (399) anylist ::= */ yytestcase(yyruleno==399); /* (400) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==400); /* (401) anylist ::= anylist ANY */ yytestcase(yyruleno==401); /* (402) with ::= */ yytestcase(yyruleno==402); /* (403) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=403); /* (404) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=404); break; /********** End reduce actions ************************************************/ }; assert( yyrulenoYY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) ); /* It is not possible for a REDUCE to be followed by an error */ assert( yyact!=YY_ERROR_ACTION ); yymsp += yysize+1; yypParser->yytos = yymsp; yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yyTraceShift(yypParser, yyact, "... then shift"); return yyact; } /* ** The following code executes when the parse fails */ #ifndef YYNOERRORRECOVERY static void yy_parse_failed( yyParser *yypParser /* The parser */ ){ sqlite3ParserARG_FETCH sqlite3ParserCTX_FETCH #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); } #endif while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ /************ Begin %parse_failure code ***************************************/ /************ End %parse_failure code *****************************************/ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ sqlite3ParserCTX_STORE } #endif /* YYNOERRORRECOVERY */ /* ** The following code executes when a syntax error first occurs. */ static void yy_syntax_error( yyParser *yypParser, /* The parser */ int yymajor, /* The major type of the error token */ sqlite3ParserTOKENTYPE yyminor /* The minor type of the error token */ ){ sqlite3ParserARG_FETCH sqlite3ParserCTX_FETCH #define TOKEN yyminor /************ Begin %syntax_error code ****************************************/ UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */ if( TOKEN.z[0] ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); }else{ sqlite3ErrorMsg(pParse, "incomplete input"); } /************ End %syntax_error code ******************************************/ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ sqlite3ParserCTX_STORE } /* ** The following is executed when the parser accepts */ static void yy_accept( yyParser *yypParser /* The parser */ ){ sqlite3ParserARG_FETCH sqlite3ParserCTX_FETCH #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); } #endif #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif assert( yypParser->yytos==yypParser->yystack ); /* Here code is inserted which will be executed whenever the ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ /*********** End %parse_accept code *******************************************/ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ sqlite3ParserCTX_STORE } /* The main parser program. ** The first argument is a pointer to a structure obtained from ** "sqlite3ParserAlloc" which describes the current state of the parser. ** The second argument is the major token number. The third is ** the minor token. The fourth optional argument is whatever the ** user wants (and specified in the grammar) and is available for ** use by the action routines. ** ** Inputs: **
      **
    • A pointer to the parser (an opaque structure.) **
    • The major token number. **
    • The minor token number. **
    • An option argument of a grammar-specified type. **
    ** ** Outputs: ** None. */ SQLITE_PRIVATE void sqlite3Parser( void *yyp, /* The parser */ int yymajor, /* The major token code number */ sqlite3ParserTOKENTYPE yyminor /* The value for the token */ sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */ ){ YYMINORTYPE yyminorunion; YYACTIONTYPE yyact; /* The parser action. */ #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) int yyendofinput; /* True if we are at the end of input */ #endif #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif yyParser *yypParser = (yyParser*)yyp; /* The parser */ sqlite3ParserCTX_FETCH sqlite3ParserARG_STORE assert( yypParser->yytos!=0 ); #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) yyendofinput = (yymajor==0); #endif yyact = yypParser->yytos->stateno; #ifndef NDEBUG if( yyTraceFILE ){ if( yyact < YY_MIN_REDUCE ){ fprintf(yyTraceFILE,"%sInput '%s' in state %d\n", yyTracePrompt,yyTokenName[yymajor],yyact); }else{ fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); } } #endif while(1){ /* Exit by "break" */ assert( yypParser->yytos>=yypParser->yystack ); assert( yyact==yypParser->yytos->stateno ); yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); if( yyact >= YY_MIN_REDUCE ){ unsigned int yyruleno = yyact - YY_MIN_REDUCE; /* Reduce by this rule */ #ifndef NDEBUG assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ); if( yyTraceFILE ){ int yysize = yyRuleInfoNRhs[yyruleno]; if( yysize ){ fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n", yyTracePrompt, yyruleno, yyRuleName[yyruleno], yyrulenoyytos[yysize].stateno); }else{ fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n", yyTracePrompt, yyruleno, yyRuleName[yyruleno], yyrulenoyytos - yypParser->yystack)>yypParser->yyhwm ){ yypParser->yyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); } #endif #if YYSTACKDEPTH>0 if( yypParser->yytos>=yypParser->yystackEnd ){ yyStackOverflow(yypParser); break; } #else if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); break; } } #endif } yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor sqlite3ParserCTX_PARAM); }else if( yyact <= YY_MAX_SHIFTREDUCE ){ yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt--; #endif break; }else if( yyact==YY_ACCEPT_ACTION ){ yypParser->yytos--; yy_accept(yypParser); return; }else{ assert( yyact == YY_ERROR_ACTION ); yyminorunion.yy0 = yyminor; #ifdef YYERRORSYMBOL int yymx; #endif #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); } #endif #ifdef YYERRORSYMBOL /* A syntax error has occurred. ** The response to an error depends upon whether or not the ** grammar defines an error token "ERROR". ** ** This is what we do if the grammar does define ERROR: ** ** * Call the %syntax_error function. ** ** * Begin popping the stack until we enter a state where ** it is legal to shift the error symbol, then shift ** the error symbol. ** ** * Set the error count to three. ** ** * Begin accepting and shifting new tokens. No new error ** processing will occur until three tokens have been ** shifted successfully. ** */ if( yypParser->yyerrcnt<0 ){ yy_syntax_error(yypParser,yymajor,yyminor); } yymx = yypParser->yytos->major; if( yymx==YYERRORSYMBOL || yyerrorhit ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sDiscard input token %s\n", yyTracePrompt,yyTokenName[yymajor]); } #endif yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ while( yypParser->yytos > yypParser->yystack ){ yyact = yy_find_reduce_action(yypParser->yytos->stateno, YYERRORSYMBOL); if( yyact<=YY_MAX_SHIFTREDUCE ) break; yy_pop_parser_stack(yypParser); } if( yypParser->yytos <= yypParser->yystack || yymajor==0 ){ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); } } yypParser->yyerrcnt = 3; yyerrorhit = 1; if( yymajor==YYNOCODE ) break; yyact = yypParser->yytos->stateno; #elif defined(YYNOERRORRECOVERY) /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to ** do any kind of error recovery. Instead, simply invoke the syntax ** error routine and continue going as if nothing had happened. ** ** Applications can set this macro (for example inside %include) if ** they intend to abandon the parse upon the first syntax error seen. */ yy_syntax_error(yypParser,yymajor, yyminor); yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); break; #else /* YYERRORSYMBOL is not defined */ /* This is what we do if the grammar does not define ERROR: ** ** * Report an error message, and throw away the input token. ** ** * If the input token is $, then fail the parse. ** ** As before, subsequent error messages are suppressed until ** three input tokens have been successfully shifted. */ if( yypParser->yyerrcnt<=0 ){ yy_syntax_error(yypParser,yymajor, yyminor); } yypParser->yyerrcnt = 3; yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif } break; #endif } } #ifndef NDEBUG if( yyTraceFILE ){ yyStackEntry *i; char cDiv = '['; fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); cDiv = ' '; } fprintf(yyTraceFILE,"]\n"); } #endif return; } /* ** Return the fallback token corresponding to canonical token iToken, or ** 0 if iToken has no fallback. */ SQLITE_PRIVATE int sqlite3ParserFallback(int iToken){ #ifdef YYFALLBACK assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ); return yyFallback[iToken]; #else (void)iToken; return 0; #endif } /************** End of parse.c ***********************************************/ /************** Begin file tokenize.c ****************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. */ /* #include "sqliteInt.h" */ /* #include */ /* Character classes for tokenizing ** ** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented ** using a lookup table, whereas a switch() directly on c uses a binary search. ** The lookup table is much faster. To maximize speed, and to ensure that ** a lookup table is used, all of the classes need to be small integers and ** all of them need to be used within the switch. */ #define CC_X 0 /* The letter 'x', or start of BLOB literal */ #define CC_KYWD0 1 /* First letter of a keyword */ #define CC_KYWD 2 /* Alphabetics or '_'. Usable in a keyword */ #define CC_DIGIT 3 /* Digits */ #define CC_DOLLAR 4 /* '$' */ #define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */ #define CC_VARNUM 6 /* '?'. Numeric SQL variables */ #define CC_SPACE 7 /* Space characters */ #define CC_QUOTE 8 /* '"', '\'', or '`'. String literals, quoted ids */ #define CC_QUOTE2 9 /* '['. [...] style quoted ids */ #define CC_PIPE 10 /* '|'. Bitwise OR or concatenate */ #define CC_MINUS 11 /* '-'. Minus or SQL-style comment */ #define CC_LT 12 /* '<'. Part of < or <= or <> */ #define CC_GT 13 /* '>'. Part of > or >= */ #define CC_EQ 14 /* '='. Part of = or == */ #define CC_BANG 15 /* '!'. Part of != */ #define CC_SLASH 16 /* '/'. / or c-style comment */ #define CC_LP 17 /* '(' */ #define CC_RP 18 /* ')' */ #define CC_SEMI 19 /* ';' */ #define CC_PLUS 20 /* '+' */ #define CC_STAR 21 /* '*' */ #define CC_PERCENT 22 /* '%' */ #define CC_COMMA 23 /* ',' */ #define CC_AND 24 /* '&' */ #define CC_TILDA 25 /* '~' */ #define CC_DOT 26 /* '.' */ #define CC_ID 27 /* unicode characters usable in IDs */ #define CC_ILLEGAL 28 /* Illegal character */ #define CC_NUL 29 /* 0x00 */ #define CC_BOM 30 /* First byte of UTF8 BOM: 0xEF 0xBB 0xBF */ static const unsigned char aiClass[] = { #ifdef SQLITE_ASCII /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ /* 0x */ 29, 28, 28, 28, 28, 28, 28, 28, 28, 7, 7, 28, 7, 7, 28, 28, /* 1x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, /* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, /* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6, /* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 9, 28, 28, 28, 2, /* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 28, 10, 28, 25, 28, /* 8x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* 9x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* Ax */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* Cx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* Dx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* Ex */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 30, /* Fx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27 #endif #ifdef SQLITE_EBCDIC /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ /* 0x */ 29, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 7, 7, 28, 28, /* 1x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, /* 2x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, /* 3x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, /* 4x */ 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 12, 17, 20, 10, /* 5x */ 24, 28, 28, 28, 28, 28, 28, 28, 28, 28, 15, 4, 21, 18, 19, 28, /* 6x */ 11, 16, 28, 28, 28, 28, 28, 28, 28, 28, 28, 23, 22, 2, 13, 6, /* 7x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 8, 5, 5, 5, 8, 14, 8, /* 8x */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, /* 9x */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, /* Ax */ 28, 25, 1, 1, 1, 1, 1, 0, 2, 2, 28, 28, 28, 28, 28, 28, /* Bx */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 9, 28, 28, 28, 28, 28, /* Cx */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, /* Dx */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, /* Ex */ 28, 28, 1, 1, 1, 1, 1, 0, 2, 2, 28, 28, 28, 28, 28, 28, /* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 28, 28, 28, 28, 28, 28, #endif }; /* ** The charMap() macro maps alphabetic characters (only) into their ** lower-case ASCII equivalent. On ASCII machines, this is just ** an upper-to-lower case map. On EBCDIC machines we also need ** to adjust the encoding. The mapping is only valid for alphabetics ** which are the only characters for which this feature is used. ** ** Used by keywordhash.h */ #ifdef SQLITE_ASCII # define charMap(X) sqlite3UpperToLower[(unsigned char)X] #endif #ifdef SQLITE_EBCDIC # define charMap(X) ebcdicToAscii[(unsigned char)X] const unsigned char ebcdicToAscii[] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, /* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* 8x */ 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* 9x */ 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* Cx */ 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* Dx */ 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Fx */ }; #endif /* ** The sqlite3KeywordCode function looks up an identifier to determine if ** it is a keyword. If it is a keyword, the token code of that keyword is ** returned. If the input is not a keyword, TK_ID is returned. ** ** The implementation of this routine was generated by a program, ** mkkeywordhash.c, located in the tool subdirectory of the distribution. ** The output of the mkkeywordhash.c program is written into a file ** named keywordhash.h and then included into this source file by ** the #include below. */ /************** Include keywordhash.h in the middle of tokenize.c ************/ /************** Begin file keywordhash.h *************************************/ /***** This file contains automatically generated code ****** ** ** The code in this file has been automatically generated by ** ** sqlite/tool/mkkeywordhash.c ** ** The code in this file implements a function that determines whether ** or not a given identifier is really an SQL keyword. The same thing ** might be implemented more directly using a hand-written hash table. ** But by using this automatically generated code, the size of the code ** is substantially reduced. This is important for embedded applications ** on platforms with limited memory. */ /* Hash score: 231 */ /* zKWText[] encodes 1007 bytes of keyword text in 667 bytes */ /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ /* ABLEFTHENDEFERRABLELSEXCLUDELETEMPORARYISNULLSAVEPOINTERSECT */ /* IESNOTNULLIKEXCEPTRANSACTIONATURALTERAISEXCLUSIVEXISTS */ /* CONSTRAINTOFFSETRIGGERANGENERATEDETACHAVINGLOBEGINNEREFERENCES */ /* UNIQUERYWITHOUTERELEASEATTACHBETWEENOTHINGROUPSCASCADEFAULT */ /* CASECOLLATECREATECURRENT_DATEIMMEDIATEJOINSERTMATCHPLANALYZE */ /* PRAGMATERIALIZEDEFERREDISTINCTUPDATEVALUESVIRTUALWAYSWHENWHERE */ /* CURSIVEABORTAFTERENAMEANDROPARTITIONAUTOINCREMENTCASTCOLUMN */ /* COMMITCONFLICTCROSSCURRENT_TIMESTAMPRECEDINGFAILASTFILTER */ /* EPLACEFIRSTFOLLOWINGFROMFULLIMITIFORDERESTRICTOTHERSOVER */ /* ETURNINGRIGHTROLLBACKROWSUNBOUNDEDUNIONUSINGVACUUMVIEWINDOWBY */ /* INITIALLYPRIMARY */ static const char zKWText[666] = { 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', 'E','R','R','A','B','L','E','L','S','E','X','C','L','U','D','E','L','E', 'T','E','M','P','O','R','A','R','Y','I','S','N','U','L','L','S','A','V', 'E','P','O','I','N','T','E','R','S','E','C','T','I','E','S','N','O','T', 'N','U','L','L','I','K','E','X','C','E','P','T','R','A','N','S','A','C', 'T','I','O','N','A','T','U','R','A','L','T','E','R','A','I','S','E','X', 'C','L','U','S','I','V','E','X','I','S','T','S','C','O','N','S','T','R', 'A','I','N','T','O','F','F','S','E','T','R','I','G','G','E','R','A','N', 'G','E','N','E','R','A','T','E','D','E','T','A','C','H','A','V','I','N', 'G','L','O','B','E','G','I','N','N','E','R','E','F','E','R','E','N','C', 'E','S','U','N','I','Q','U','E','R','Y','W','I','T','H','O','U','T','E', 'R','E','L','E','A','S','E','A','T','T','A','C','H','B','E','T','W','E', 'E','N','O','T','H','I','N','G','R','O','U','P','S','C','A','S','C','A', 'D','E','F','A','U','L','T','C','A','S','E','C','O','L','L','A','T','E', 'C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A','T','E', 'I','M','M','E','D','I','A','T','E','J','O','I','N','S','E','R','T','M', 'A','T','C','H','P','L','A','N','A','L','Y','Z','E','P','R','A','G','M', 'A','T','E','R','I','A','L','I','Z','E','D','E','F','E','R','R','E','D', 'I','S','T','I','N','C','T','U','P','D','A','T','E','V','A','L','U','E', 'S','V','I','R','T','U','A','L','W','A','Y','S','W','H','E','N','W','H', 'E','R','E','C','U','R','S','I','V','E','A','B','O','R','T','A','F','T', 'E','R','E','N','A','M','E','A','N','D','R','O','P','A','R','T','I','T', 'I','O','N','A','U','T','O','I','N','C','R','E','M','E','N','T','C','A', 'S','T','C','O','L','U','M','N','C','O','M','M','I','T','C','O','N','F', 'L','I','C','T','C','R','O','S','S','C','U','R','R','E','N','T','_','T', 'I','M','E','S','T','A','M','P','R','E','C','E','D','I','N','G','F','A', 'I','L','A','S','T','F','I','L','T','E','R','E','P','L','A','C','E','F', 'I','R','S','T','F','O','L','L','O','W','I','N','G','F','R','O','M','F', 'U','L','L','I','M','I','T','I','F','O','R','D','E','R','E','S','T','R', 'I','C','T','O','T','H','E','R','S','O','V','E','R','E','T','U','R','N', 'I','N','G','R','I','G','H','T','R','O','L','L','B','A','C','K','R','O', 'W','S','U','N','B','O','U','N','D','E','D','U','N','I','O','N','U','S', 'I','N','G','V','A','C','U','U','M','V','I','E','W','I','N','D','O','W', 'B','Y','I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R','Y', }; /* aKWHash[i] is the hash value for the i-th keyword */ static const unsigned char aKWHash[127] = { 84, 92, 134, 82, 105, 29, 0, 0, 94, 0, 85, 72, 0, 53, 35, 86, 15, 0, 42, 97, 54, 89, 135, 19, 0, 0, 140, 0, 40, 129, 0, 22, 107, 0, 9, 0, 0, 123, 80, 0, 78, 6, 0, 65, 103, 147, 0, 136, 115, 0, 0, 48, 0, 90, 24, 0, 17, 0, 27, 70, 23, 26, 5, 60, 142, 110, 122, 0, 73, 91, 71, 145, 61, 120, 74, 0, 49, 0, 11, 41, 0, 113, 0, 0, 0, 109, 10, 111, 116, 125, 14, 50, 124, 0, 100, 0, 18, 121, 144, 56, 130, 139, 88, 83, 37, 30, 126, 0, 0, 108, 51, 131, 128, 0, 34, 0, 0, 132, 0, 98, 38, 39, 0, 20, 45, 117, 93, }; /* aKWNext[] forms the hash collision chain. If aKWHash[i]==0 ** then the i-th keyword has no more hash collisions. Otherwise, ** the next keyword with the same hash is aKWHash[i]-1. */ static const unsigned char aKWNext[148] = {0, 0, 0, 0, 0, 4, 0, 43, 0, 0, 106, 114, 0, 0, 0, 2, 0, 0, 143, 0, 0, 0, 13, 0, 0, 0, 0, 141, 0, 0, 119, 52, 0, 0, 137, 12, 0, 0, 62, 0, 138, 0, 133, 0, 0, 36, 0, 0, 28, 77, 0, 0, 0, 0, 59, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 146, 3, 0, 58, 0, 1, 75, 0, 0, 0, 31, 0, 0, 0, 0, 0, 127, 0, 104, 0, 64, 66, 63, 0, 0, 0, 0, 0, 46, 0, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 101, 0, 112, 21, 7, 67, 0, 79, 96, 118, 0, 0, 68, 0, 0, 99, 44, 0, 55, 0, 76, 0, 95, 32, 33, 57, 25, 0, 102, 0, 0, 87, }; /* aKWLen[i] is the length (in bytes) of the i-th keyword */ static const unsigned char aKWLen[148] = {0, 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7, 6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4, 4, 6, 11, 6, 2, 7, 5, 5, 9, 6, 10, 4, 6, 2, 3, 7, 5, 9, 6, 6, 4, 5, 5, 10, 6, 5, 7, 4, 5, 7, 6, 7, 7, 6, 5, 7, 3, 7, 4, 7, 6, 12, 9, 4, 6, 5, 4, 7, 6, 12, 8, 8, 2, 6, 6, 7, 6, 4, 5, 9, 5, 5, 6, 3, 4, 9, 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 9, 4, 4, 6, 7, 5, 9, 4, 4, 5, 2, 5, 8, 6, 4, 9, 5, 8, 4, 3, 9, 5, 5, 6, 4, 6, 2, 2, 9, 3, 7, }; /* aKWOffset[i] is the index into zKWText[] of the start of ** the text for the i-th keyword. */ static const unsigned short int aKWOffset[148] = {0, 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, 86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126, 129, 132, 137, 142, 146, 147, 152, 156, 160, 168, 174, 181, 184, 184, 187, 189, 195, 198, 206, 211, 216, 219, 222, 226, 236, 239, 244, 244, 248, 252, 259, 265, 271, 277, 277, 283, 284, 288, 295, 299, 306, 312, 324, 333, 335, 341, 346, 348, 355, 359, 370, 377, 378, 385, 391, 397, 402, 408, 412, 415, 424, 429, 433, 439, 441, 444, 453, 455, 457, 466, 470, 476, 482, 490, 495, 495, 495, 511, 520, 523, 527, 532, 539, 544, 553, 557, 560, 565, 567, 571, 579, 585, 588, 597, 602, 610, 610, 614, 623, 628, 633, 639, 642, 645, 648, 650, 655, 659, }; /* aKWCode[i] is the parser symbol code for the i-th keyword */ static const unsigned char aKWCode[148] = {0, TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, TK_EXCLUDE, TK_DELETE, TK_TEMP, TK_TEMP, TK_OR, TK_ISNULL, TK_NULLS, TK_SAVEPOINT, TK_INTERSECT, TK_TIES, TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_CONSTRAINT, TK_INTO, TK_OFFSET, TK_OF, TK_SET, TK_TRIGGER, TK_RANGE, TK_GENERATED, TK_DETACH, TK_HAVING, TK_LIKE_KW, TK_BEGIN, TK_JOIN_KW, TK_REFERENCES, TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, TK_JOIN_KW, TK_RELEASE, TK_ATTACH, TK_BETWEEN, TK_NOTHING, TK_GROUPS, TK_GROUP, TK_CASCADE, TK_ASC, TK_DEFAULT, TK_CASE, TK_COLLATE, TK_CREATE, TK_CTIME_KW, TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_MATERIALIZED, TK_DEFERRED, TK_DISTINCT, TK_IS, TK_UPDATE, TK_VALUES, TK_VIRTUAL, TK_ALWAYS, TK_WHEN, TK_WHERE, TK_RECURSIVE, TK_ABORT, TK_AFTER, TK_RENAME, TK_AND, TK_DROP, TK_PARTITION, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_CURRENT, TK_PRECEDING, TK_FAIL, TK_LAST, TK_FILTER, TK_REPLACE, TK_FIRST, TK_FOLLOWING, TK_FROM, TK_JOIN_KW, TK_LIMIT, TK_IF, TK_ORDER, TK_RESTRICT, TK_OTHERS, TK_OVER, TK_RETURNING, TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, TK_ROW, TK_UNBOUNDED, TK_UNION, TK_USING, TK_VACUUM, TK_VIEW, TK_WINDOW, TK_DO, TK_BY, TK_INITIALLY, TK_ALL, TK_PRIMARY, }; /* Hash table decoded: ** 0: INSERT ** 1: IS ** 2: ROLLBACK TRIGGER ** 3: IMMEDIATE ** 4: PARTITION ** 5: TEMP ** 6: ** 7: ** 8: VALUES WITHOUT ** 9: ** 10: MATCH ** 11: NOTHING ** 12: ** 13: OF ** 14: TIES IGNORE ** 15: PLAN ** 16: INSTEAD INDEXED ** 17: ** 18: TRANSACTION RIGHT ** 19: WHEN ** 20: SET HAVING ** 21: MATERIALIZED IF ** 22: ROWS ** 23: SELECT ** 24: ** 25: ** 26: VACUUM SAVEPOINT ** 27: ** 28: LIKE UNION VIRTUAL REFERENCES ** 29: RESTRICT ** 30: ** 31: THEN REGEXP ** 32: TO ** 33: ** 34: BEFORE ** 35: ** 36: ** 37: FOLLOWING COLLATE CASCADE ** 38: CREATE ** 39: ** 40: CASE REINDEX ** 41: EACH ** 42: ** 43: QUERY ** 44: AND ADD ** 45: PRIMARY ANALYZE ** 46: ** 47: ROW ASC DETACH ** 48: CURRENT_TIME CURRENT_DATE ** 49: ** 50: ** 51: EXCLUSIVE TEMPORARY ** 52: ** 53: DEFERRED ** 54: DEFERRABLE ** 55: ** 56: DATABASE ** 57: ** 58: DELETE VIEW GENERATED ** 59: ATTACH ** 60: END ** 61: EXCLUDE ** 62: ESCAPE DESC ** 63: GLOB ** 64: WINDOW ELSE ** 65: COLUMN ** 66: FIRST ** 67: ** 68: GROUPS ALL ** 69: DISTINCT DROP KEY ** 70: BETWEEN ** 71: INITIALLY ** 72: BEGIN ** 73: FILTER CHECK ACTION ** 74: GROUP INDEX ** 75: ** 76: EXISTS DEFAULT ** 77: ** 78: FOR CURRENT_TIMESTAMP ** 79: EXCEPT ** 80: ** 81: CROSS ** 82: ** 83: ** 84: ** 85: CAST ** 86: FOREIGN AUTOINCREMENT ** 87: COMMIT ** 88: CURRENT AFTER ALTER ** 89: FULL FAIL CONFLICT ** 90: EXPLAIN ** 91: CONSTRAINT ** 92: FROM ALWAYS ** 93: ** 94: ABORT ** 95: ** 96: AS DO ** 97: REPLACE WITH RELEASE ** 98: BY RENAME ** 99: RANGE RAISE ** 100: OTHERS ** 101: USING NULLS ** 102: PRAGMA ** 103: JOIN ISNULL OFFSET ** 104: NOT ** 105: OR LAST LEFT ** 106: LIMIT ** 107: ** 108: ** 109: IN ** 110: INTO ** 111: OVER RECURSIVE ** 112: ORDER OUTER ** 113: ** 114: INTERSECT UNBOUNDED ** 115: ** 116: ** 117: RETURNING ON ** 118: ** 119: WHERE ** 120: NO INNER ** 121: NULL ** 122: ** 123: TABLE ** 124: NATURAL NOTNULL ** 125: PRECEDING ** 126: UPDATE UNIQUE */ /* Check to see if z[0..n-1] is a keyword. If it is, write the ** parser symbol code for that keyword into *pType. Always ** return the integer n (the length of the token). */ static int keywordCode(const char *z, int n, int *pType){ int i, j; const char *zKW; assert( n>=2 ); i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127; for(i=(int)aKWHash[i]; i>0; i=aKWNext[i]){ if( aKWLen[i]!=n ) continue; zKW = &zKWText[aKWOffset[i]]; #ifdef SQLITE_ASCII if( (z[0]&~0x20)!=zKW[0] ) continue; if( (z[1]&~0x20)!=zKW[1] ) continue; j = 2; while( j=2 ) keywordCode((char*)z, n, &id); return id; } #define SQLITE_N_KEYWORD 147 SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){ if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR; i++; *pzName = zKWText + aKWOffset[i]; *pnName = aKWLen[i]; return SQLITE_OK; } SQLITE_API int sqlite3_keyword_count(void){ return SQLITE_N_KEYWORD; } SQLITE_API int sqlite3_keyword_check(const char *zName, int nName){ return TK_ID!=sqlite3KeywordCode((const u8*)zName, nName); } /************** End of keywordhash.h *****************************************/ /************** Continuing where we left off in tokenize.c *******************/ /* ** If X is a character that can be used in an identifier then ** IdChar(X) will be true. Otherwise it is false. ** ** For ASCII, any character with the high-order bit set is ** allowed in an identifier. For 7-bit characters, ** sqlite3IsIdChar[X] must be 1. ** ** For EBCDIC, the rules are more complex but have the same ** end result. ** ** Ticket #1066. the SQL standard does not allow '$' in the ** middle of identifiers. But many SQL implementations do. ** SQLite will allow '$' in identifiers for compatibility. ** But the feature is undocumented. */ #ifdef SQLITE_ASCII #define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0) #endif #ifdef SQLITE_EBCDIC SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 4x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, /* 5x */ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 6x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* 7x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, /* 8x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, /* 9x */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Cx */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Dx */ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */ }; #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) #endif /* Make the IdChar function accessible from ctime.c and alter.c */ SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); } #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Return the id of the next token in string (*pz). Before returning, set ** (*pz) to point to the byte following the parsed token. */ static int getToken(const unsigned char **pz){ const unsigned char *z = *pz; int t; /* Token type to return */ do { z += sqlite3GetToken(z, &t); }while( t==TK_SPACE ); if( t==TK_ID || t==TK_STRING || t==TK_JOIN_KW || t==TK_WINDOW || t==TK_OVER || sqlite3ParserFallback(t)==TK_ID ){ t = TK_ID; } *pz = z; return t; } /* ** The following three functions are called immediately after the tokenizer ** reads the keywords WINDOW, OVER and FILTER, respectively, to determine ** whether the token should be treated as a keyword or an SQL identifier. ** This cannot be handled by the usual lemon %fallback method, due to ** the ambiguity in some constructions. e.g. ** ** SELECT sum(x) OVER ... ** ** In the above, "OVER" might be a keyword, or it might be an alias for the ** sum(x) expression. If a "%fallback ID OVER" directive were added to ** grammar, then SQLite would always treat "OVER" as an alias, making it ** impossible to call a window-function without a FILTER clause. ** ** WINDOW is treated as a keyword if: ** ** * the following token is an identifier, or a keyword that can fallback ** to being an identifier, and ** * the token after than one is TK_AS. ** ** OVER is a keyword if: ** ** * the previous token was TK_RP, and ** * the next token is either TK_LP or an identifier. ** ** FILTER is a keyword if: ** ** * the previous token was TK_RP, and ** * the next token is TK_LP. */ static int analyzeWindowKeyword(const unsigned char *z){ int t; t = getToken(&z); if( t!=TK_ID ) return TK_ID; t = getToken(&z); if( t!=TK_AS ) return TK_ID; return TK_WINDOW; } static int analyzeOverKeyword(const unsigned char *z, int lastToken){ if( lastToken==TK_RP ){ int t = getToken(&z); if( t==TK_LP || t==TK_ID ) return TK_OVER; } return TK_ID; } static int analyzeFilterKeyword(const unsigned char *z, int lastToken){ if( lastToken==TK_RP && getToken(&z)==TK_LP ){ return TK_FILTER; } return TK_ID; } #endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** Return the length (in bytes) of the token that begins at z[0]. ** Store the token type in *tokenType before returning. */ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ int i, c; switch( aiClass[*z] ){ /* Switch on the character-class of the first byte ** of the token. See the comment on the CC_ defines ** above. */ case CC_SPACE: { testcase( z[0]==' ' ); testcase( z[0]=='\t' ); testcase( z[0]=='\n' ); testcase( z[0]=='\f' ); testcase( z[0]=='\r' ); for(i=1; sqlite3Isspace(z[i]); i++){} *tokenType = TK_SPACE; return i; } case CC_MINUS: { if( z[1]=='-' ){ for(i=2; (c=z[i])!=0 && c!='\n'; i++){} *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ return i; }else if( z[1]=='>' ){ *tokenType = TK_PTR; return 2 + (z[2]=='>'); } *tokenType = TK_MINUS; return 1; } case CC_LP: { *tokenType = TK_LP; return 1; } case CC_RP: { *tokenType = TK_RP; return 1; } case CC_SEMI: { *tokenType = TK_SEMI; return 1; } case CC_PLUS: { *tokenType = TK_PLUS; return 1; } case CC_STAR: { *tokenType = TK_STAR; return 1; } case CC_SLASH: { if( z[1]!='*' || z[2]==0 ){ *tokenType = TK_SLASH; return 1; } for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} if( c ) i++; *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ return i; } case CC_PERCENT: { *tokenType = TK_REM; return 1; } case CC_EQ: { *tokenType = TK_EQ; return 1 + (z[1]=='='); } case CC_LT: { if( (c=z[1])=='=' ){ *tokenType = TK_LE; return 2; }else if( c=='>' ){ *tokenType = TK_NE; return 2; }else if( c=='<' ){ *tokenType = TK_LSHIFT; return 2; }else{ *tokenType = TK_LT; return 1; } } case CC_GT: { if( (c=z[1])=='=' ){ *tokenType = TK_GE; return 2; }else if( c=='>' ){ *tokenType = TK_RSHIFT; return 2; }else{ *tokenType = TK_GT; return 1; } } case CC_BANG: { if( z[1]!='=' ){ *tokenType = TK_ILLEGAL; return 1; }else{ *tokenType = TK_NE; return 2; } } case CC_PIPE: { if( z[1]!='|' ){ *tokenType = TK_BITOR; return 1; }else{ *tokenType = TK_CONCAT; return 2; } } case CC_COMMA: { *tokenType = TK_COMMA; return 1; } case CC_AND: { *tokenType = TK_BITAND; return 1; } case CC_TILDA: { *tokenType = TK_BITNOT; return 1; } case CC_QUOTE: { int delim = z[0]; testcase( delim=='`' ); testcase( delim=='\'' ); testcase( delim=='"' ); for(i=1; (c=z[i])!=0; i++){ if( c==delim ){ if( z[i+1]==delim ){ i++; }else{ break; } } } if( c=='\'' ){ *tokenType = TK_STRING; return i+1; }else if( c!=0 ){ *tokenType = TK_ID; return i+1; }else{ *tokenType = TK_ILLEGAL; return i; } } case CC_DOT: { #ifndef SQLITE_OMIT_FLOATING_POINT if( !sqlite3Isdigit(z[1]) ) #endif { *tokenType = TK_DOT; return 1; } /* If the next character is a digit, this is a floating point ** number that begins with ".". Fall thru into the next case */ /* no break */ deliberate_fall_through } case CC_DIGIT: { testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' ); testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' ); testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); testcase( z[0]=='9' ); testcase( z[0]=='.' ); *tokenType = TK_INTEGER; #ifndef SQLITE_OMIT_HEX_INTEGER if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ for(i=3; sqlite3Isxdigit(z[i]); i++){} return i; } #endif for(i=0; sqlite3Isdigit(z[i]); i++){} #ifndef SQLITE_OMIT_FLOATING_POINT if( z[i]=='.' ){ i++; while( sqlite3Isdigit(z[i]) ){ i++; } *tokenType = TK_FLOAT; } if( (z[i]=='e' || z[i]=='E') && ( sqlite3Isdigit(z[i+1]) || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2])) ) ){ i += 2; while( sqlite3Isdigit(z[i]) ){ i++; } *tokenType = TK_FLOAT; } #endif while( IdChar(z[i]) ){ *tokenType = TK_ILLEGAL; i++; } return i; } case CC_QUOTE2: { for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){} *tokenType = c==']' ? TK_ID : TK_ILLEGAL; return i; } case CC_VARNUM: { *tokenType = TK_VARIABLE; for(i=1; sqlite3Isdigit(z[i]); i++){} return i; } case CC_DOLLAR: case CC_VARALPHA: { int n = 0; testcase( z[0]=='$' ); testcase( z[0]=='@' ); testcase( z[0]==':' ); testcase( z[0]=='#' ); *tokenType = TK_VARIABLE; for(i=1; (c=z[i])!=0; i++){ if( IdChar(c) ){ n++; #ifndef SQLITE_OMIT_TCL_VARIABLE }else if( c=='(' && n>0 ){ do{ i++; }while( (c=z[i])!=0 && !sqlite3Isspace(c) && c!=')' ); if( c==')' ){ i++; }else{ *tokenType = TK_ILLEGAL; } break; }else if( c==':' && z[i+1]==':' ){ i++; #endif }else{ break; } } if( n==0 ) *tokenType = TK_ILLEGAL; return i; } case CC_KYWD0: { if( aiClass[z[1]]>CC_KYWD ){ i = 1; break; } for(i=2; aiClass[z[i]]<=CC_KYWD; i++){} if( IdChar(z[i]) ){ /* This token started out using characters that can appear in keywords, ** but z[i] is a character not allowed within keywords, so this must ** be an identifier instead */ i++; break; } *tokenType = TK_ID; return keywordCode((char*)z, i, tokenType); } case CC_X: { #ifndef SQLITE_OMIT_BLOB_LITERAL testcase( z[0]=='x' ); testcase( z[0]=='X' ); if( z[1]=='\'' ){ *tokenType = TK_BLOB; for(i=2; sqlite3Isxdigit(z[i]); i++){} if( z[i]!='\'' || i%2 ){ *tokenType = TK_ILLEGAL; while( z[i] && z[i]!='\'' ){ i++; } } if( z[i] ) i++; return i; } #endif /* If it is not a BLOB literal, then it must be an ID, since no ** SQL keywords start with the letter 'x'. Fall through */ /* no break */ deliberate_fall_through } case CC_KYWD: case CC_ID: { i = 1; break; } case CC_BOM: { if( z[1]==0xbb && z[2]==0xbf ){ *tokenType = TK_SPACE; return 3; } i = 1; break; } case CC_NUL: { *tokenType = TK_ILLEGAL; return 0; } default: { *tokenType = TK_ILLEGAL; return 1; } } while( IdChar(z[i]) ){ i++; } *tokenType = TK_ID; return i; } /* ** Run the parser on the given SQL string. */ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ int nErr = 0; /* Number of errors encountered */ void *pEngine; /* The LEMON-generated LALR(1) parser */ int n = 0; /* Length of the next token token */ int tokenType; /* type of the next token */ int lastTokenParsed = -1; /* type of the previous token */ sqlite3 *db = pParse->db; /* The database connection */ int mxSqlLen; /* Max length of an SQL string */ Parse *pParentParse = 0; /* Outer parse context, if any */ #ifdef sqlite3Parser_ENGINEALWAYSONSTACK yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ #endif VVA_ONLY( u8 startedWithOom = db->mallocFailed ); assert( zSql!=0 ); mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; if( db->nVdbeActive==0 ){ AtomicStore(&db->u1.isInterrupted, 0); } pParse->rc = SQLITE_OK; pParse->zTail = zSql; #ifdef SQLITE_DEBUG if( db->flags & SQLITE_ParserTrace ){ printf("parser: [[[%s]]]\n", zSql); sqlite3ParserTrace(stdout, "parser: "); }else{ sqlite3ParserTrace(0, 0); } #endif #ifdef sqlite3Parser_ENGINEALWAYSONSTACK pEngine = &sEngine; sqlite3ParserInit(pEngine, pParse); #else pEngine = sqlite3ParserAlloc(sqlite3Malloc, pParse); if( pEngine==0 ){ sqlite3OomFault(db); return SQLITE_NOMEM_BKPT; } #endif assert( pParse->pNewTable==0 ); assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->pVList==0 ); pParentParse = db->pParse; db->pParse = pParse; while( 1 ){ n = sqlite3GetToken((u8*)zSql, &tokenType); mxSqlLen -= n; if( mxSqlLen<0 ){ pParse->rc = SQLITE_TOOBIG; pParse->nErr++; break; } #ifndef SQLITE_OMIT_WINDOWFUNC if( tokenType>=TK_WINDOW ){ assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW ); #else if( tokenType>=TK_SPACE ){ assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); #endif /* SQLITE_OMIT_WINDOWFUNC */ if( AtomicLoad(&db->u1.isInterrupted) ){ pParse->rc = SQLITE_INTERRUPT; pParse->nErr++; break; } if( tokenType==TK_SPACE ){ zSql += n; continue; } if( zSql[0]==0 ){ /* Upon reaching the end of input, call the parser two more times ** with tokens TK_SEMI and 0, in that order. */ if( lastTokenParsed==TK_SEMI ){ tokenType = 0; }else if( lastTokenParsed==0 ){ break; }else{ tokenType = TK_SEMI; } n = 0; #ifndef SQLITE_OMIT_WINDOWFUNC }else if( tokenType==TK_WINDOW ){ assert( n==6 ); tokenType = analyzeWindowKeyword((const u8*)&zSql[6]); }else if( tokenType==TK_OVER ){ assert( n==4 ); tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed); }else if( tokenType==TK_FILTER ){ assert( n==6 ); tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed); #endif /* SQLITE_OMIT_WINDOWFUNC */ }else{ Token x; x.z = zSql; x.n = n; sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &x); break; } } pParse->sLastToken.z = zSql; pParse->sLastToken.n = n; sqlite3Parser(pEngine, tokenType, pParse->sLastToken); lastTokenParsed = tokenType; zSql += n; assert( db->mallocFailed==0 || pParse->rc!=SQLITE_OK || startedWithOom ); if( pParse->rc!=SQLITE_OK ) break; } assert( nErr==0 ); #ifdef YYTRACKMAXSTACKDEPTH sqlite3_mutex_enter(sqlite3MallocMutex()); sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK, sqlite3ParserStackPeak(pEngine) ); sqlite3_mutex_leave(sqlite3MallocMutex()); #endif /* YYDEBUG */ #ifdef sqlite3Parser_ENGINEALWAYSONSTACK sqlite3ParserFinalize(pEngine); #else sqlite3ParserFree(pEngine, sqlite3_free); #endif if( db->mallocFailed ){ pParse->rc = SQLITE_NOMEM_BKPT; } if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){ if( pParse->zErrMsg==0 ){ pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc)); } sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail); nErr++; } pParse->zTail = zSql; #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_free(pParse->apVtabLock); #endif if( pParse->pNewTable && !IN_SPECIAL_PARSE ){ /* If the pParse->declareVtab flag is set, do not delete any table ** structure built up in pParse->pNewTable. The calling code (see vtab.c) ** will take responsibility for freeing the Table structure. */ sqlite3DeleteTable(db, pParse->pNewTable); } if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){ sqlite3DeleteTrigger(db, pParse->pNewTrigger); } if( pParse->pVList ) sqlite3DbNNFreeNN(db, pParse->pVList); db->pParse = pParentParse; assert( nErr==0 || pParse->rc!=SQLITE_OK ); return nErr; } #ifdef SQLITE_ENABLE_NORMALIZE /* ** Insert a single space character into pStr if the current string ** ends with an identifier */ static void addSpaceSeparator(sqlite3_str *pStr){ if( pStr->nChar && sqlite3IsIdChar(pStr->zText[pStr->nChar-1]) ){ sqlite3_str_append(pStr, " ", 1); } } /* ** Compute a normalization of the SQL given by zSql[0..nSql-1]. Return ** the normalization in space obtained from sqlite3DbMalloc(). Or return ** NULL if anything goes wrong or if zSql is NULL. */ SQLITE_PRIVATE char *sqlite3Normalize( Vdbe *pVdbe, /* VM being reprepared */ const char *zSql /* The original SQL string */ ){ sqlite3 *db; /* The database connection */ int i; /* Next unread byte of zSql[] */ int n; /* length of current token */ int tokenType; /* type of current token */ int prevType = 0; /* Previous non-whitespace token */ int nParen; /* Number of nested levels of parentheses */ int iStartIN; /* Start of RHS of IN operator in z[] */ int nParenAtIN; /* Value of nParent at start of RHS of IN operator */ u32 j; /* Bytes of normalized SQL generated so far */ sqlite3_str *pStr; /* The normalized SQL string under construction */ db = sqlite3VdbeDb(pVdbe); tokenType = -1; nParen = iStartIN = nParenAtIN = 0; pStr = sqlite3_str_new(db); assert( pStr!=0 ); /* sqlite3_str_new() never returns NULL */ for(i=0; zSql[i] && pStr->accError==0; i+=n){ if( tokenType!=TK_SPACE ){ prevType = tokenType; } n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType); if( NEVER(n<=0) ) break; switch( tokenType ){ case TK_SPACE: { break; } case TK_NULL: { if( prevType==TK_IS || prevType==TK_NOT ){ sqlite3_str_append(pStr, " NULL", 5); break; } /* Fall through */ } case TK_STRING: case TK_INTEGER: case TK_FLOAT: case TK_VARIABLE: case TK_BLOB: { sqlite3_str_append(pStr, "?", 1); break; } case TK_LP: { nParen++; if( prevType==TK_IN ){ iStartIN = pStr->nChar; nParenAtIN = nParen; } sqlite3_str_append(pStr, "(", 1); break; } case TK_RP: { if( iStartIN>0 && nParen==nParenAtIN ){ assert( pStr->nChar>=(u32)iStartIN ); pStr->nChar = iStartIN+1; sqlite3_str_append(pStr, "?,?,?", 5); iStartIN = 0; } nParen--; sqlite3_str_append(pStr, ")", 1); break; } case TK_ID: { iStartIN = 0; j = pStr->nChar; if( sqlite3Isquote(zSql[i]) ){ char *zId = sqlite3DbStrNDup(db, zSql+i, n); int nId; int eType = 0; if( zId==0 ) break; sqlite3Dequote(zId); if( zSql[i]=='"' && sqlite3VdbeUsesDoubleQuotedString(pVdbe, zId) ){ sqlite3_str_append(pStr, "?", 1); sqlite3DbFree(db, zId); break; } nId = sqlite3Strlen30(zId); if( sqlite3GetToken((u8*)zId, &eType)==nId && eType==TK_ID ){ addSpaceSeparator(pStr); sqlite3_str_append(pStr, zId, nId); }else{ sqlite3_str_appendf(pStr, "\"%w\"", zId); } sqlite3DbFree(db, zId); }else{ addSpaceSeparator(pStr); sqlite3_str_append(pStr, zSql+i, n); } while( jnChar ){ pStr->zText[j] = sqlite3Tolower(pStr->zText[j]); j++; } break; } case TK_SELECT: { iStartIN = 0; /* fall through */ } default: { if( sqlite3IsIdChar(zSql[i]) ) addSpaceSeparator(pStr); j = pStr->nChar; sqlite3_str_append(pStr, zSql+i, n); while( jnChar ){ pStr->zText[j] = sqlite3Toupper(pStr->zText[j]); j++; } break; } } } if( tokenType!=TK_SEMI ) sqlite3_str_append(pStr, ";", 1); return sqlite3_str_finish(pStr); } #endif /* SQLITE_ENABLE_NORMALIZE */ /************** End of tokenize.c ********************************************/ /************** Begin file complete.c ****************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that implements the sqlite3_complete() API. ** This code used to be part of the tokenizer.c source file. But by ** separating it out, the code will be automatically omitted from ** static links that do not use it. */ /* #include "sqliteInt.h" */ #ifndef SQLITE_OMIT_COMPLETE /* ** This is defined in tokenize.c. We just have to import the definition. */ #ifndef SQLITE_AMALGAMATION #ifdef SQLITE_ASCII #define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0) #endif #ifdef SQLITE_EBCDIC SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[]; #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) #endif #endif /* SQLITE_AMALGAMATION */ /* ** Token types used by the sqlite3_complete() routine. See the header ** comments on that procedure for additional information. */ #define tkSEMI 0 #define tkWS 1 #define tkOTHER 2 #ifndef SQLITE_OMIT_TRIGGER #define tkEXPLAIN 3 #define tkCREATE 4 #define tkTEMP 5 #define tkTRIGGER 6 #define tkEND 7 #endif /* ** Return TRUE if the given SQL string ends in a semicolon. ** ** Special handling is require for CREATE TRIGGER statements. ** Whenever the CREATE TRIGGER keywords are seen, the statement ** must end with ";END;". ** ** This implementation uses a state machine with 8 states: ** ** (0) INVALID We have not yet seen a non-whitespace character. ** ** (1) START At the beginning or end of an SQL statement. This routine ** returns 1 if it ends in the START state and 0 if it ends ** in any other state. ** ** (2) NORMAL We are in the middle of statement which ends with a single ** semicolon. ** ** (3) EXPLAIN The keyword EXPLAIN has been seen at the beginning of ** a statement. ** ** (4) CREATE The keyword CREATE has been seen at the beginning of a ** statement, possibly preceded by EXPLAIN and/or followed by ** TEMP or TEMPORARY ** ** (5) TRIGGER We are in the middle of a trigger definition that must be ** ended by a semicolon, the keyword END, and another semicolon. ** ** (6) SEMI We've seen the first semicolon in the ";END;" that occurs at ** the end of a trigger definition. ** ** (7) END We've seen the ";END" of the ";END;" that occurs at the end ** of a trigger definition. ** ** Transitions between states above are determined by tokens extracted ** from the input. The following tokens are significant: ** ** (0) tkSEMI A semicolon. ** (1) tkWS Whitespace. ** (2) tkOTHER Any other SQL token. ** (3) tkEXPLAIN The "explain" keyword. ** (4) tkCREATE The "create" keyword. ** (5) tkTEMP The "temp" or "temporary" keyword. ** (6) tkTRIGGER The "trigger" keyword. ** (7) tkEND The "end" keyword. ** ** Whitespace never causes a state transition and is always ignored. ** This means that a SQL string of all whitespace is invalid. ** ** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed ** to recognize the end of a trigger can be omitted. All we have to do ** is look for a semicolon that is not part of an string or comment. */ SQLITE_API int sqlite3_complete(const char *zSql){ u8 state = 0; /* Current state, using numbers defined in header comment */ u8 token; /* Value of the next token */ #ifndef SQLITE_OMIT_TRIGGER /* A complex statement machine used to detect the end of a CREATE TRIGGER ** statement. This is the normal case. */ static const u8 trans[8][8] = { /* Token: */ /* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */ /* 0 INVALID: */ { 1, 0, 2, 3, 4, 2, 2, 2, }, /* 1 START: */ { 1, 1, 2, 3, 4, 2, 2, 2, }, /* 2 NORMAL: */ { 1, 2, 2, 2, 2, 2, 2, 2, }, /* 3 EXPLAIN: */ { 1, 3, 3, 2, 4, 2, 2, 2, }, /* 4 CREATE: */ { 1, 4, 2, 2, 2, 4, 5, 2, }, /* 5 TRIGGER: */ { 6, 5, 5, 5, 5, 5, 5, 5, }, /* 6 SEMI: */ { 6, 6, 5, 5, 5, 5, 5, 7, }, /* 7 END: */ { 1, 7, 5, 5, 5, 5, 5, 5, }, }; #else /* If triggers are not supported by this compile then the statement machine ** used to detect the end of a statement is much simpler */ static const u8 trans[3][3] = { /* Token: */ /* State: ** SEMI WS OTHER */ /* 0 INVALID: */ { 1, 0, 2, }, /* 1 START: */ { 1, 1, 2, }, /* 2 NORMAL: */ { 1, 2, 2, }, }; #endif /* SQLITE_OMIT_TRIGGER */ #ifdef SQLITE_ENABLE_API_ARMOR if( zSql==0 ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif while( *zSql ){ switch( *zSql ){ case ';': { /* A semicolon */ token = tkSEMI; break; } case ' ': case '\r': case '\t': case '\n': case '\f': { /* White space is ignored */ token = tkWS; break; } case '/': { /* C-style comments */ if( zSql[1]!='*' ){ token = tkOTHER; break; } zSql += 2; while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; } if( zSql[0]==0 ) return 0; zSql++; token = tkWS; break; } case '-': { /* SQL-style comments from "--" to end of line */ if( zSql[1]!='-' ){ token = tkOTHER; break; } while( *zSql && *zSql!='\n' ){ zSql++; } if( *zSql==0 ) return state==1; token = tkWS; break; } case '[': { /* Microsoft-style identifiers in [...] */ zSql++; while( *zSql && *zSql!=']' ){ zSql++; } if( *zSql==0 ) return 0; token = tkOTHER; break; } case '`': /* Grave-accent quoted symbols used by MySQL */ case '"': /* single- and double-quoted strings */ case '\'': { int c = *zSql; zSql++; while( *zSql && *zSql!=c ){ zSql++; } if( *zSql==0 ) return 0; token = tkOTHER; break; } default: { #ifdef SQLITE_EBCDIC unsigned char c; #endif if( IdChar((u8)*zSql) ){ /* Keywords and unquoted identifiers */ int nId; for(nId=1; IdChar(zSql[nId]); nId++){} #ifdef SQLITE_OMIT_TRIGGER token = tkOTHER; #else switch( *zSql ){ case 'c': case 'C': { if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){ token = tkCREATE; }else{ token = tkOTHER; } break; } case 't': case 'T': { if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){ token = tkTRIGGER; }else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){ token = tkTEMP; }else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){ token = tkTEMP; }else{ token = tkOTHER; } break; } case 'e': case 'E': { if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){ token = tkEND; }else #ifndef SQLITE_OMIT_EXPLAIN if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){ token = tkEXPLAIN; }else #endif { token = tkOTHER; } break; } default: { token = tkOTHER; break; } } #endif /* SQLITE_OMIT_TRIGGER */ zSql += nId-1; }else{ /* Operators and special symbols */ token = tkOTHER; } break; } } state = trans[state][token]; zSql++; } return state==1; } #ifndef SQLITE_OMIT_UTF16 /* ** This routine is the same as the sqlite3_complete() routine described ** above, except that the parameter is required to be UTF-16 encoded, not ** UTF-8. */ SQLITE_API int sqlite3_complete16(const void *zSql){ sqlite3_value *pVal; char const *zSql8; int rc; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ) return rc; #endif pVal = sqlite3ValueNew(0); sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zSql8 ){ rc = sqlite3_complete(zSql8); }else{ rc = SQLITE_NOMEM_BKPT; } sqlite3ValueFree(pVal); return rc & 0xff; } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_COMPLETE */ /************** End of complete.c ********************************************/ /************** Begin file main.c ********************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. */ /* #include "sqliteInt.h" */ #ifdef SQLITE_ENABLE_FTS3 /************** Include fts3.h in the middle of main.c ***********************/ /************** Begin file fts3.h ********************************************/ /* ** 2006 Oct 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This header file is used by programs that want to link against the ** FTS3 library. All it does is declare the sqlite3Fts3Init() interface. */ /* #include "sqlite3.h" */ #if 0 extern "C" { #endif /* __cplusplus */ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db); #if 0 } /* extern "C" */ #endif /* __cplusplus */ /************** End of fts3.h ************************************************/ /************** Continuing where we left off in main.c ***********************/ #endif #ifdef SQLITE_ENABLE_RTREE /************** Include rtree.h in the middle of main.c **********************/ /************** Begin file rtree.h *******************************************/ /* ** 2008 May 26 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This header file is used by programs that want to link against the ** RTREE library. All it does is declare the sqlite3RtreeInit() interface. */ /* #include "sqlite3.h" */ #ifdef SQLITE_OMIT_VIRTUALTABLE # undef SQLITE_ENABLE_RTREE #endif #if 0 extern "C" { #endif /* __cplusplus */ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); #if 0 } /* extern "C" */ #endif /* __cplusplus */ /************** End of rtree.h ***********************************************/ /************** Continuing where we left off in main.c ***********************/ #endif #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) /************** Include sqliteicu.h in the middle of main.c ******************/ /************** Begin file sqliteicu.h ***************************************/ /* ** 2008 May 26 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This header file is used by programs that want to link against the ** ICU extension. All it does is declare the sqlite3IcuInit() interface. */ /* #include "sqlite3.h" */ #if 0 extern "C" { #endif /* __cplusplus */ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db); #if 0 } /* extern "C" */ #endif /* __cplusplus */ /************** End of sqliteicu.h *******************************************/ /************** Continuing where we left off in main.c ***********************/ #endif /* ** This is an extension initializer that is a no-op and always ** succeeds, except that it fails if the fault-simulation is set ** to 500. */ static int sqlite3TestExtInit(sqlite3 *db){ (void)db; return sqlite3FaultSim(500); } /* ** Forward declarations of external module initializer functions ** for modules that need them. */ #ifdef SQLITE_ENABLE_FTS5 SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*); #endif #ifdef SQLITE_ENABLE_STMTVTAB SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*); #endif #ifdef SQLITE_EXTRA_AUTOEXT int SQLITE_EXTRA_AUTOEXT(sqlite3*); #endif /* ** An array of pointers to extension initializer functions for ** built-in extensions. */ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { #ifdef SQLITE_ENABLE_FTS3 sqlite3Fts3Init, #endif #ifdef SQLITE_ENABLE_FTS5 sqlite3Fts5Init, #endif #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) sqlite3IcuInit, #endif #ifdef SQLITE_ENABLE_RTREE sqlite3RtreeInit, #endif #ifdef SQLITE_ENABLE_DBPAGE_VTAB sqlite3DbpageRegister, #endif #ifdef SQLITE_ENABLE_DBSTAT_VTAB sqlite3DbstatRegister, #endif sqlite3TestExtInit, #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) sqlite3JsonTableFunctions, #endif #ifdef SQLITE_ENABLE_STMTVTAB sqlite3StmtVtabInit, #endif #ifdef SQLITE_ENABLE_BYTECODE_VTAB sqlite3VdbeBytecodeVtabInit, #endif #ifdef SQLITE_EXTRA_AUTOEXT SQLITE_EXTRA_AUTOEXT, #endif }; #ifndef SQLITE_AMALGAMATION /* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant ** contains the text of SQLITE_VERSION macro. */ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; #endif /* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns ** a pointer to the to the sqlite3_version[] string constant. */ SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; } /* IMPLEMENTATION-OF: R-25063-23286 The sqlite3_sourceid() function returns a ** pointer to a string constant whose value is the same as the ** SQLITE_SOURCE_ID C preprocessor macro. Except if SQLite is built using ** an edited copy of the amalgamation, then the last four characters of ** the hash might be different from SQLITE_SOURCE_ID. */ /* SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } */ /* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function ** returns an integer equal to SQLITE_VERSION_NUMBER. */ SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; } /* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns ** zero if and only if SQLite was compiled with mutexing code omitted due to ** the SQLITE_THREADSAFE compile-time option being set to 0. */ SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } /* ** When compiling the test fixture or with debugging enabled (on Win32), ** this variable being set to non-zero will cause OSTRACE macros to emit ** extra diagnostic information. */ #ifdef SQLITE_HAVE_OS_TRACE # ifndef SQLITE_DEBUG_OS_TRACE # define SQLITE_DEBUG_OS_TRACE 0 # endif int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; #endif #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) /* ** If the following function pointer is not NULL and if ** SQLITE_ENABLE_IOTRACE is enabled, then messages describing ** I/O active are written using this function. These messages ** are intended for debugging activity only. */ SQLITE_API void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0; #endif /* ** If the following global variable points to a string which is the ** name of a directory, then that directory will be used to store ** temporary files. ** ** See also the "PRAGMA temp_store_directory" SQL command. */ SQLITE_API char *sqlite3_temp_directory = 0; /* ** If the following global variable points to a string which is the ** name of a directory, then that directory will be used to store ** all database files specified with a relative pathname. ** ** See also the "PRAGMA data_store_directory" SQL command. */ SQLITE_API char *sqlite3_data_directory = 0; /* ** Determine whether or not high-precision (long double) floating point ** math works correctly on CPU currently running. */ static SQLITE_NOINLINE int hasHighPrecisionDouble(int rc){ if( sizeof(LONGDOUBLE_TYPE)<=8 ){ /* If the size of "long double" is not more than 8, then ** high-precision math is not possible. */ return 0; }else{ /* Just because sizeof(long double)>8 does not mean that the underlying ** hardware actually supports high-precision floating point. For example, ** clearing the 0x100 bit in the floating-point control word on Intel ** processors will make long double work like double, even though long ** double takes up more space. The only way to determine if long double ** actually works is to run an experiment. */ LONGDOUBLE_TYPE a, b, c; rc++; a = 1.0+rc*0.1; b = 1.0e+18+rc*25.0; c = a+b; return b!=c; } } /* ** Initialize SQLite. ** ** This routine must be called to initialize the memory allocation, ** VFS, and mutex subsystems prior to doing any serious work with ** SQLite. But as long as you do not compile with SQLITE_OMIT_AUTOINIT ** this routine will be called automatically by key routines such as ** sqlite3_open(). ** ** This routine is a no-op except on its very first call for the process, ** or for the first call after a call to sqlite3_shutdown. ** ** The first thread to call this routine runs the initialization to ** completion. If subsequent threads call this routine before the first ** thread has finished the initialization process, then the subsequent ** threads must block until the first thread finishes with the initialization. ** ** The first thread might call this routine recursively. Recursive ** calls to this routine should not block, of course. Otherwise the ** initialization process would never complete. ** ** Let X be the first thread to enter this routine. Let Y be some other ** thread. Then while the initial invocation of this routine by X is ** incomplete, it is required that: ** ** * Calls to this routine from Y must block until the outer-most ** call by X completes. ** ** * Recursive calls to this routine from thread X return immediately ** without blocking. */ SQLITE_API int sqlite3_initialize(void){ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */ int rc; /* Result code */ #ifdef SQLITE_EXTRA_INIT int bRunExtraInit = 0; /* Extra initialization needed */ #endif #ifdef SQLITE_OMIT_WSD rc = sqlite3_wsd_init(4096, 24); if( rc!=SQLITE_OK ){ return rc; } #endif /* If the following assert() fails on some obscure processor/compiler ** combination, the work-around is to set the correct pointer ** size at compile-time using -DSQLITE_PTRSIZE=n compile-time option */ assert( SQLITE_PTRSIZE==sizeof(char*) ); /* If SQLite is already completely initialized, then this call ** to sqlite3_initialize() should be a no-op. But the initialization ** must be complete. So isInit must not be set until the very end ** of this routine. */ if( sqlite3GlobalConfig.isInit ){ sqlite3MemoryBarrier(); return SQLITE_OK; } /* Make sure the mutex subsystem is initialized. If unable to ** initialize the mutex subsystem, return early with the error. ** If the system is so sick that we are unable to allocate a mutex, ** there is not much SQLite is going to be able to do. ** ** The mutex subsystem must take care of serializing its own ** initialization. */ rc = sqlite3MutexInit(); if( rc ) return rc; /* Initialize the malloc() system and the recursive pInitMutex mutex. ** This operation is protected by the STATIC_MAIN mutex. Note that ** MutexAlloc() is called for a static mutex prior to initializing the ** malloc subsystem - this implies that the allocation of a static ** mutex must not require support from the malloc subsystem. */ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) sqlite3_mutex_enter(pMainMtx); sqlite3GlobalConfig.isMutexInit = 1; if( !sqlite3GlobalConfig.isMallocInit ){ rc = sqlite3MallocInit(); } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.isMallocInit = 1; if( !sqlite3GlobalConfig.pInitMutex ){ sqlite3GlobalConfig.pInitMutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){ rc = SQLITE_NOMEM_BKPT; } } } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.nRefInitMutex++; } sqlite3_mutex_leave(pMainMtx); /* If rc is not SQLITE_OK at this point, then either the malloc ** subsystem could not be initialized or the system failed to allocate ** the pInitMutex mutex. Return an error in either case. */ if( rc!=SQLITE_OK ){ return rc; } /* Do the rest of the initialization under the recursive mutex so ** that we will be able to handle recursive calls into ** sqlite3_initialize(). The recursive calls normally come through ** sqlite3_os_init() when it invokes sqlite3_vfs_register(), but other ** recursive calls might also be possible. ** ** IMPLEMENTATION-OF: R-00140-37445 SQLite automatically serializes calls ** to the xInit method, so the xInit method need not be threadsafe. ** ** The following mutex is what serializes access to the appdef pcache xInit ** methods. The sqlite3_pcache_methods.xInit() all is embedded in the ** call to sqlite3PcacheInitialize(). */ sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex); if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){ sqlite3GlobalConfig.inProgress = 1; #ifdef SQLITE_ENABLE_SQLLOG { extern void sqlite3_init_sqllog(void); sqlite3_init_sqllog(); } #endif memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions)); sqlite3RegisterBuiltinFunctions(); if( sqlite3GlobalConfig.isPCacheInit==0 ){ rc = sqlite3PcacheInitialize(); } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.isPCacheInit = 1; rc = sqlite3OsInit(); } #ifndef SQLITE_OMIT_DESERIALIZE if( rc==SQLITE_OK ){ rc = sqlite3MemdbInit(); } #endif if( rc==SQLITE_OK ){ sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage); sqlite3MemoryBarrier(); sqlite3GlobalConfig.isInit = 1; #ifdef SQLITE_EXTRA_INIT bRunExtraInit = 1; #endif } sqlite3GlobalConfig.inProgress = 0; } sqlite3_mutex_leave(sqlite3GlobalConfig.pInitMutex); /* Go back under the static mutex and clean up the recursive ** mutex to prevent a resource leak. */ sqlite3_mutex_enter(pMainMtx); sqlite3GlobalConfig.nRefInitMutex--; if( sqlite3GlobalConfig.nRefInitMutex<=0 ){ assert( sqlite3GlobalConfig.nRefInitMutex==0 ); sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex); sqlite3GlobalConfig.pInitMutex = 0; } sqlite3_mutex_leave(pMainMtx); /* The following is just a sanity check to make sure SQLite has ** been compiled correctly. It is important to run this code, but ** we don't want to run it too often and soak up CPU cycles for no ** reason. So we run it once during initialization. */ #ifndef NDEBUG #ifndef SQLITE_OMIT_FLOATING_POINT /* This section of code's only "output" is via assert() statements. */ if( rc==SQLITE_OK ){ u64 x = (((u64)1)<<63)-1; double y; assert(sizeof(x)==8); assert(sizeof(x)==sizeof(y)); memcpy(&y, &x, 8); assert( sqlite3IsNaN(y) ); } #endif #endif /* Do extra initialization steps requested by the SQLITE_EXTRA_INIT ** compile-time option. */ #ifdef SQLITE_EXTRA_INIT if( bRunExtraInit ){ int SQLITE_EXTRA_INIT(const char*); rc = SQLITE_EXTRA_INIT(0); } #endif /* Experimentally determine if high-precision floating point is ** available. */ #ifndef SQLITE_OMIT_WSD sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc); #endif return rc; } /* ** Undo the effects of sqlite3_initialize(). Must not be called while ** there are outstanding database connections or memory allocations or ** while any part of SQLite is otherwise in use in any thread. This ** routine is not threadsafe. But it is safe to invoke this routine ** on when SQLite is already shut down. If SQLite is already shut down ** when this routine is invoked, then this routine is a harmless no-op. */ SQLITE_API int sqlite3_shutdown(void){ #ifdef SQLITE_OMIT_WSD int rc = sqlite3_wsd_init(4096, 24); if( rc!=SQLITE_OK ){ return rc; } #endif if( sqlite3GlobalConfig.isInit ){ #ifdef SQLITE_EXTRA_SHUTDOWN void SQLITE_EXTRA_SHUTDOWN(void); SQLITE_EXTRA_SHUTDOWN(); #endif sqlite3_os_end(); sqlite3_reset_auto_extension(); sqlite3GlobalConfig.isInit = 0; } if( sqlite3GlobalConfig.isPCacheInit ){ sqlite3PcacheShutdown(); sqlite3GlobalConfig.isPCacheInit = 0; } if( sqlite3GlobalConfig.isMallocInit ){ sqlite3MallocEnd(); sqlite3GlobalConfig.isMallocInit = 0; #ifndef SQLITE_OMIT_SHUTDOWN_DIRECTORIES /* The heap subsystem has now been shutdown and these values are supposed ** to be NULL or point to memory that was obtained from sqlite3_malloc(), ** which would rely on that heap subsystem; therefore, make sure these ** values cannot refer to heap memory that was just invalidated when the ** heap subsystem was shutdown. This is only done if the current call to ** this function resulted in the heap subsystem actually being shutdown. */ sqlite3_data_directory = 0; sqlite3_temp_directory = 0; #endif } if( sqlite3GlobalConfig.isMutexInit ){ sqlite3MutexEnd(); sqlite3GlobalConfig.isMutexInit = 0; } return SQLITE_OK; } /* ** This API allows applications to modify the global configuration of ** the SQLite library at run-time. ** ** This routine should only be called when there are no outstanding ** database connections or memory allocations. This routine is not ** threadsafe. Failure to heed these warnings can lead to unpredictable ** behavior. */ SQLITE_API int sqlite3_config(int op, ...){ va_list ap; int rc = SQLITE_OK; /* sqlite3_config() normally returns SQLITE_MISUSE if it is invoked while ** the SQLite library is in use. Except, a few selected opcodes ** are allowed. */ if( sqlite3GlobalConfig.isInit ){ static const u64 mAnytimeConfigOption = 0 | MASKBIT64( SQLITE_CONFIG_LOG ) | MASKBIT64( SQLITE_CONFIG_PCACHE_HDRSZ ) ; if( op<0 || op>63 || (MASKBIT64(op) & mAnytimeConfigOption)==0 ){ return SQLITE_MISUSE_BKPT; } testcase( op==SQLITE_CONFIG_LOG ); testcase( op==SQLITE_CONFIG_PCACHE_HDRSZ ); } va_start(ap, op); switch( op ){ /* Mutex configuration options are only available in a threadsafe ** compile. */ #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ case SQLITE_CONFIG_SINGLETHREAD: { /* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to ** Single-thread. */ sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */ sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ break; } #endif #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ case SQLITE_CONFIG_MULTITHREAD: { /* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to ** Multi-thread. */ sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ break; } #endif #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ case SQLITE_CONFIG_SERIALIZED: { /* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to ** Serialized. */ sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */ break; } #endif #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */ case SQLITE_CONFIG_MUTEX: { /* Specify an alternative mutex implementation */ sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*); break; } #endif #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */ case SQLITE_CONFIG_GETMUTEX: { /* Retrieve the current mutex implementation */ *va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex; break; } #endif case SQLITE_CONFIG_MALLOC: { /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a ** single argument which is a pointer to an instance of the ** sqlite3_mem_methods structure. The argument specifies alternative ** low-level memory allocation routines to be used in place of the memory ** allocation routines built into SQLite. */ sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*); break; } case SQLITE_CONFIG_GETMALLOC: { /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC option takes a ** single argument which is a pointer to an instance of the ** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is ** filled with the currently defined memory allocation routines. */ if( sqlite3GlobalConfig.m.xMalloc==0 ) sqlite3MemSetDefault(); *va_arg(ap, sqlite3_mem_methods*) = sqlite3GlobalConfig.m; break; } case SQLITE_CONFIG_MEMSTATUS: { assert( !sqlite3GlobalConfig.isInit ); /* Cannot change at runtime */ /* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes ** single argument of type int, interpreted as a boolean, which enables ** or disables the collection of memory allocation statistics. */ sqlite3GlobalConfig.bMemstat = va_arg(ap, int); break; } case SQLITE_CONFIG_SMALL_MALLOC: { sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int); break; } case SQLITE_CONFIG_PAGECACHE: { /* EVIDENCE-OF: R-18761-36601 There are three arguments to ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory (pMem), ** the size of each page cache line (sz), and the number of cache lines ** (N). */ sqlite3GlobalConfig.pPage = va_arg(ap, void*); sqlite3GlobalConfig.szPage = va_arg(ap, int); sqlite3GlobalConfig.nPage = va_arg(ap, int); break; } case SQLITE_CONFIG_PCACHE_HDRSZ: { /* EVIDENCE-OF: R-39100-27317 The SQLITE_CONFIG_PCACHE_HDRSZ option takes ** a single parameter which is a pointer to an integer and writes into ** that integer the number of extra bytes per page required for each page ** in SQLITE_CONFIG_PAGECACHE. */ *va_arg(ap, int*) = sqlite3HeaderSizeBtree() + sqlite3HeaderSizePcache() + sqlite3HeaderSizePcache1(); break; } case SQLITE_CONFIG_PCACHE: { /* no-op */ break; } case SQLITE_CONFIG_GETPCACHE: { /* now an error */ rc = SQLITE_ERROR; break; } case SQLITE_CONFIG_PCACHE2: { /* EVIDENCE-OF: R-63325-48378 The SQLITE_CONFIG_PCACHE2 option takes a ** single argument which is a pointer to an sqlite3_pcache_methods2 ** object. This object specifies the interface to a custom page cache ** implementation. */ sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*); break; } case SQLITE_CONFIG_GETPCACHE2: { /* EVIDENCE-OF: R-22035-46182 The SQLITE_CONFIG_GETPCACHE2 option takes a ** single argument which is a pointer to an sqlite3_pcache_methods2 ** object. SQLite copies of the current page cache implementation into ** that object. */ if( sqlite3GlobalConfig.pcache2.xInit==0 ){ sqlite3PCacheSetDefault(); } *va_arg(ap, sqlite3_pcache_methods2*) = sqlite3GlobalConfig.pcache2; break; } /* EVIDENCE-OF: R-06626-12911 The SQLITE_CONFIG_HEAP option is only ** available if SQLite is compiled with either SQLITE_ENABLE_MEMSYS3 or ** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) case SQLITE_CONFIG_HEAP: { /* EVIDENCE-OF: R-19854-42126 There are three arguments to ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the ** number of bytes in the memory buffer, and the minimum allocation size. */ sqlite3GlobalConfig.pHeap = va_arg(ap, void*); sqlite3GlobalConfig.nHeap = va_arg(ap, int); sqlite3GlobalConfig.mnReq = va_arg(ap, int); if( sqlite3GlobalConfig.mnReq<1 ){ sqlite3GlobalConfig.mnReq = 1; }else if( sqlite3GlobalConfig.mnReq>(1<<12) ){ /* cap min request size at 2^12 */ sqlite3GlobalConfig.mnReq = (1<<12); } if( sqlite3GlobalConfig.pHeap==0 ){ /* EVIDENCE-OF: R-49920-60189 If the first pointer (the memory pointer) ** is NULL, then SQLite reverts to using its default memory allocator ** (the system malloc() implementation), undoing any prior invocation of ** SQLITE_CONFIG_MALLOC. ** ** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to ** revert to its default implementation when sqlite3_initialize() is run */ memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m)); }else{ /* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the ** alternative memory allocator is engaged to handle all of SQLites ** memory allocation needs. */ #ifdef SQLITE_ENABLE_MEMSYS3 sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3(); #endif #ifdef SQLITE_ENABLE_MEMSYS5 sqlite3GlobalConfig.m = *sqlite3MemGetMemsys5(); #endif } break; } #endif case SQLITE_CONFIG_LOOKASIDE: { sqlite3GlobalConfig.szLookaside = va_arg(ap, int); sqlite3GlobalConfig.nLookaside = va_arg(ap, int); break; } /* Record a pointer to the logger function and its first argument. ** The default is NULL. Logging is disabled if the function pointer is ** NULL. */ case SQLITE_CONFIG_LOG: { /* MSVC is picky about pulling func ptrs from va lists. ** http://support.microsoft.com/kb/47961 ** sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*)); */ typedef void(*LOGFUNC_t)(void*,int,const char*); LOGFUNC_t xLog = va_arg(ap, LOGFUNC_t); void *pLogArg = va_arg(ap, void*); AtomicStore(&sqlite3GlobalConfig.xLog, xLog); AtomicStore(&sqlite3GlobalConfig.pLogArg, pLogArg); break; } /* EVIDENCE-OF: R-55548-33817 The compile-time setting for URI filenames ** can be changed at start-time using the ** sqlite3_config(SQLITE_CONFIG_URI,1) or ** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls. */ case SQLITE_CONFIG_URI: { /* EVIDENCE-OF: R-25451-61125 The SQLITE_CONFIG_URI option takes a single ** argument of type int. If non-zero, then URI handling is globally ** enabled. If the parameter is zero, then URI handling is globally ** disabled. */ int bOpenUri = va_arg(ap, int); AtomicStore(&sqlite3GlobalConfig.bOpenUri, bOpenUri); break; } case SQLITE_CONFIG_COVERING_INDEX_SCAN: { /* EVIDENCE-OF: R-36592-02772 The SQLITE_CONFIG_COVERING_INDEX_SCAN ** option takes a single integer argument which is interpreted as a ** boolean in order to enable or disable the use of covering indices for ** full table scans in the query optimizer. */ sqlite3GlobalConfig.bUseCis = va_arg(ap, int); break; } #ifdef SQLITE_ENABLE_SQLLOG case SQLITE_CONFIG_SQLLOG: { typedef void(*SQLLOGFUNC_t)(void*, sqlite3*, const char*, int); sqlite3GlobalConfig.xSqllog = va_arg(ap, SQLLOGFUNC_t); sqlite3GlobalConfig.pSqllogArg = va_arg(ap, void *); break; } #endif case SQLITE_CONFIG_MMAP_SIZE: { /* EVIDENCE-OF: R-58063-38258 SQLITE_CONFIG_MMAP_SIZE takes two 64-bit ** integer (sqlite3_int64) values that are the default mmap size limit ** (the default setting for PRAGMA mmap_size) and the maximum allowed ** mmap size limit. */ sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64); sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64); /* EVIDENCE-OF: R-53367-43190 If either argument to this option is ** negative, then that argument is changed to its compile-time default. ** ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be ** silently truncated if necessary so that it does not exceed the ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE ** compile-time option. */ if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ mxMmap = SQLITE_MAX_MMAP_SIZE; } if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; if( szMmap>mxMmap) szMmap = mxMmap; sqlite3GlobalConfig.mxMmap = mxMmap; sqlite3GlobalConfig.szMmap = szMmap; break; } #if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) /* IMP: R-04780-55815 */ case SQLITE_CONFIG_WIN32_HEAPSIZE: { /* EVIDENCE-OF: R-34926-03360 SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit ** unsigned integer value that specifies the maximum size of the created ** heap. */ sqlite3GlobalConfig.nHeap = va_arg(ap, int); break; } #endif case SQLITE_CONFIG_PMASZ: { sqlite3GlobalConfig.szPma = va_arg(ap, unsigned int); break; } case SQLITE_CONFIG_STMTJRNL_SPILL: { sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int); break; } #ifdef SQLITE_ENABLE_SORTER_REFERENCES case SQLITE_CONFIG_SORTERREF_SIZE: { int iVal = va_arg(ap, int); if( iVal<0 ){ iVal = SQLITE_DEFAULT_SORTERREF_SIZE; } sqlite3GlobalConfig.szSorterRef = (u32)iVal; break; } #endif /* SQLITE_ENABLE_SORTER_REFERENCES */ #ifndef SQLITE_OMIT_DESERIALIZE case SQLITE_CONFIG_MEMDB_MAXSIZE: { sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64); break; } #endif /* SQLITE_OMIT_DESERIALIZE */ default: { rc = SQLITE_ERROR; break; } } va_end(ap); return rc; } /* ** Set up the lookaside buffers for a database connection. ** Return SQLITE_OK on success. ** If lookaside is already active, return SQLITE_BUSY. ** ** The sz parameter is the number of bytes in each lookaside slot. ** The cnt parameter is the number of slots. If pStart is NULL the ** space for the lookaside memory is obtained from sqlite3_malloc(). ** If pStart is not NULL then it is sz*cnt bytes of memory to use for ** the lookaside memory. */ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ #ifndef SQLITE_OMIT_LOOKASIDE void *pStart; sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt; int nBig; /* Number of full-size slots */ int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */ if( sqlite3LookasideUsed(db,0)>0 ){ return SQLITE_BUSY; } /* Free any existing lookaside buffer for this handle before ** allocating a new one so we don't have to have space for ** both at the same time. */ if( db->lookaside.bMalloced ){ sqlite3_free(db->lookaside.pStart); } /* The size of a lookaside slot after ROUNDDOWN8 needs to be larger ** than a pointer to be useful. */ sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */ if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0; if( cnt<0 ) cnt = 0; if( sz==0 || cnt==0 ){ sz = 0; pStart = 0; }else if( pBuf==0 ){ sqlite3BeginBenignMalloc(); pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */ sqlite3EndBenignMalloc(); if( pStart ) szAlloc = sqlite3MallocSize(pStart); }else{ pStart = pBuf; } #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( sz>=LOOKASIDE_SMALL*3 ){ nBig = szAlloc/(3*LOOKASIDE_SMALL+sz); nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL; }else if( sz>=LOOKASIDE_SMALL*2 ){ nBig = szAlloc/(LOOKASIDE_SMALL+sz); nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL; }else #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ if( sz>0 ){ nBig = szAlloc/sz; nSm = 0; }else{ nBig = nSm = 0; } db->lookaside.pStart = pStart; db->lookaside.pInit = 0; db->lookaside.pFree = 0; db->lookaside.sz = (u16)sz; db->lookaside.szTrue = (u16)sz; if( pStart ){ int i; LookasideSlot *p; assert( sz > (int)sizeof(LookasideSlot*) ); p = (LookasideSlot*)pStart; for(i=0; ipNext = db->lookaside.pInit; db->lookaside.pInit = p; p = (LookasideSlot*)&((u8*)p)[sz]; } #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE db->lookaside.pSmallInit = 0; db->lookaside.pSmallFree = 0; db->lookaside.pMiddle = p; for(i=0; ipNext = db->lookaside.pSmallInit; db->lookaside.pSmallInit = p; p = (LookasideSlot*)&((u8*)p)[LOOKASIDE_SMALL]; } #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ assert( ((uptr)p)<=szAlloc + (uptr)pStart ); db->lookaside.pEnd = p; db->lookaside.bDisable = 0; db->lookaside.bMalloced = pBuf==0 ?1:0; db->lookaside.nSlot = nBig+nSm; }else{ db->lookaside.pStart = 0; #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE db->lookaside.pSmallInit = 0; db->lookaside.pSmallFree = 0; db->lookaside.pMiddle = 0; #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ db->lookaside.pEnd = 0; db->lookaside.bDisable = 1; db->lookaside.sz = 0; db->lookaside.bMalloced = 0; db->lookaside.nSlot = 0; } db->lookaside.pTrueEnd = db->lookaside.pEnd; assert( sqlite3LookasideUsed(db,0)==0 ); #endif /* SQLITE_OMIT_LOOKASIDE */ return SQLITE_OK; } /* ** Return the mutex associated with a database connection. */ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return db->mutex; } /* ** Free up as much memory as we can from the given database ** connection. */ SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){ int i; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ Pager *pPager = sqlite3BtreePager(pBt); sqlite3PagerShrink(pPager); } } sqlite3BtreeLeaveAll(db); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } /* ** Flush any dirty pages in the pager-cache for any attached database ** to disk. */ SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){ int i; int rc = SQLITE_OK; int bSeenBusy = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt && sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ Pager *pPager = sqlite3BtreePager(pBt); rc = sqlite3PagerFlush(pPager); if( rc==SQLITE_BUSY ){ bSeenBusy = 1; rc = SQLITE_OK; } } } sqlite3BtreeLeaveAll(db); sqlite3_mutex_leave(db->mutex); return ((rc==SQLITE_OK && bSeenBusy) ? SQLITE_BUSY : rc); } /* ** Configuration settings for an individual database connection */ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ va_list ap; int rc; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); va_start(ap, op); switch( op ){ case SQLITE_DBCONFIG_MAINDBNAME: { /* IMP: R-06824-28531 */ /* IMP: R-36257-52125 */ db->aDb[0].zDbSName = va_arg(ap,char*); rc = SQLITE_OK; break; } case SQLITE_DBCONFIG_LOOKASIDE: { void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */ int sz = va_arg(ap, int); /* IMP: R-47871-25994 */ int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */ rc = setupLookaside(db, pBuf, sz, cnt); break; } default: { static const struct { int op; /* The opcode */ u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */ } aFlagOp[] = { { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys }, { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger }, { SQLITE_DBCONFIG_ENABLE_VIEW, SQLITE_EnableView }, { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer }, { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension }, { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG }, { SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP }, { SQLITE_DBCONFIG_RESET_DATABASE, SQLITE_ResetDatabase }, { SQLITE_DBCONFIG_DEFENSIVE, SQLITE_Defensive }, { SQLITE_DBCONFIG_WRITABLE_SCHEMA, SQLITE_WriteSchema| SQLITE_NoSchemaError }, { SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, SQLITE_LegacyAlter }, { SQLITE_DBCONFIG_DQS_DDL, SQLITE_DqsDDL }, { SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML }, { SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, SQLITE_LegacyFileFmt }, { SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema }, { SQLITE_DBCONFIG_STMT_SCANSTATUS, SQLITE_StmtScanStatus }, { SQLITE_DBCONFIG_REVERSE_SCANORDER, SQLITE_ReverseOrder }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ for(i=0; iflags; if( onoff>0 ){ db->flags |= aFlagOp[i].mask; }else if( onoff==0 ){ db->flags &= ~(u64)aFlagOp[i].mask; } if( oldFlags!=db->flags ){ sqlite3ExpirePreparedStatements(db, 0); } if( pRes ){ *pRes = (db->flags & aFlagOp[i].mask)!=0; } rc = SQLITE_OK; break; } } break; } } va_end(ap); sqlite3_mutex_leave(db->mutex); return rc; } /* ** This is the default collating function named "BINARY" which is always ** available. */ static int binCollFunc( void *NotUsed, int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ int rc, n; UNUSED_PARAMETER(NotUsed); n = nKey1xCmp!=binCollFunc || strcmp(p->zName,"BINARY")==0 ); return p==0 || p->xCmp==binCollFunc; } /* ** Another built-in collating sequence: NOCASE. ** ** This collating sequence is intended to be used for "case independent ** comparison". SQLite's knowledge of upper and lower case equivalents ** extends only to the 26 characters used in the English language. ** ** At the moment there is only a UTF-8 implementation. */ static int nocaseCollatingFunc( void *NotUsed, int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ int r = sqlite3StrNICmp( (const char *)pKey1, (const char *)pKey2, (nKey1lastRowid; } /* ** Set the value returned by the sqlite3_last_insert_rowid() API function. */ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return; } #endif sqlite3_mutex_enter(db->mutex); db->lastRowid = iRowid; sqlite3_mutex_leave(db->mutex); } /* ** Return the number of changes in the most recent call to sqlite3_exec(). */ SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return db->nChange; } SQLITE_API int sqlite3_changes(sqlite3 *db){ return (int)sqlite3_changes64(db); } /* ** Return the number of changes since the database handle was opened. */ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return db->nTotalChange; } SQLITE_API int sqlite3_total_changes(sqlite3 *db){ return (int)sqlite3_total_changes64(db); } /* ** Close all open savepoints. This function only manipulates fields of the ** database handle object, it does not close any savepoints that may be open ** at the b-tree/pager level. */ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){ while( db->pSavepoint ){ Savepoint *pTmp = db->pSavepoint; db->pSavepoint = pTmp->pNext; sqlite3DbFree(db, pTmp); } db->nSavepoint = 0; db->nStatement = 0; db->isTransactionSavepoint = 0; } /* ** Invoke the destructor function associated with FuncDef p, if any. Except, ** if this is not the last copy of the function, do not invoke it. Multiple ** copies of a single function are created when create_function() is called ** with SQLITE_ANY as the encoding. */ static void functionDestroy(sqlite3 *db, FuncDef *p){ FuncDestructor *pDestructor; assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 ); pDestructor = p->u.pDestructor; if( pDestructor ){ pDestructor->nRef--; if( pDestructor->nRef==0 ){ pDestructor->xDestroy(pDestructor->pUserData); sqlite3DbFree(db, pDestructor); } } } /* ** Disconnect all sqlite3_vtab objects that belong to database connection ** db. This is called when db is being closed. */ static void disconnectAllVtab(sqlite3 *db){ #ifndef SQLITE_OMIT_VIRTUALTABLE int i; HashElem *p; sqlite3BtreeEnterAll(db); for(i=0; inDb; i++){ Schema *pSchema = db->aDb[i].pSchema; if( pSchema ){ for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ Table *pTab = (Table *)sqliteHashData(p); if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); } } } for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){ Module *pMod = (Module *)sqliteHashData(p); if( pMod->pEpoTab ){ sqlite3VtabDisconnect(db, pMod->pEpoTab); } } sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); #else UNUSED_PARAMETER(db); #endif } /* ** Return TRUE if database connection db has unfinalized prepared ** statements or unfinished sqlite3_backup objects. */ static int connectionIsBusy(sqlite3 *db){ int j; assert( sqlite3_mutex_held(db->mutex) ); if( db->pVdbe ) return 1; for(j=0; jnDb; j++){ Btree *pBt = db->aDb[j].pBt; if( pBt && sqlite3BtreeIsInBackup(pBt) ) return 1; } return 0; } /* ** Close an existing SQLite database */ static int sqlite3Close(sqlite3 *db, int forceZombie){ if( !db ){ /* EVIDENCE-OF: R-63257-11740 Calling sqlite3_close() or ** sqlite3_close_v2() with a NULL pointer argument is a harmless no-op. */ return SQLITE_OK; } if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); if( db->mTrace & SQLITE_TRACE_CLOSE ){ db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0); } /* Force xDisconnect calls on all virtual tables */ disconnectAllVtab(db); /* If a transaction is open, the disconnectAllVtab() call above ** will not have called the xDisconnect() method on any virtual ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback() ** call will do so. We need to do this before the check for active ** SQL statements below, as the v-table implementation may be storing ** some prepared statements internally. */ sqlite3VtabRollback(db); /* Legacy behavior (sqlite3_close() behavior) is to return ** SQLITE_BUSY if the connection can not be closed immediately. */ if( !forceZombie && connectionIsBusy(db) ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to close due to unfinalized " "statements or unfinished backups"); sqlite3_mutex_leave(db->mutex); return SQLITE_BUSY; } #ifdef SQLITE_ENABLE_SQLLOG if( sqlite3GlobalConfig.xSqllog ){ /* Closing the handle. Fourth parameter is passed the value 2. */ sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2); } #endif while( db->pDbData ){ DbClientData *p = db->pDbData; db->pDbData = p->pNext; assert( p->pData!=0 ); if( p->xDestructor ) p->xDestructor(p->pData); sqlite3_free(p); } /* Convert the connection into a zombie and then close it. */ db->eOpenState = SQLITE_STATE_ZOMBIE; sqlite3LeaveMutexAndCloseZombie(db); return SQLITE_OK; } /* ** Return the transaction state for a single databse, or the maximum ** transaction state over all attached databases if zSchema is null. */ SQLITE_API int sqlite3_txn_state(sqlite3 *db, const char *zSchema){ int iDb, nDb; int iTxn = -1; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return -1; } #endif sqlite3_mutex_enter(db->mutex); if( zSchema ){ nDb = iDb = sqlite3FindDbName(db, zSchema); if( iDb<0 ) nDb--; }else{ iDb = 0; nDb = db->nDb-1; } for(; iDb<=nDb; iDb++){ Btree *pBt = db->aDb[iDb].pBt; int x = pBt!=0 ? sqlite3BtreeTxnState(pBt) : SQLITE_TXN_NONE; if( x>iTxn ) iTxn = x; } sqlite3_mutex_leave(db->mutex); return iTxn; } /* ** Two variations on the public interface for closing a database ** connection. The sqlite3_close() version returns SQLITE_BUSY and ** leaves the connection open if there are unfinalized prepared ** statements or unfinished sqlite3_backups. The sqlite3_close_v2() ** version forces the connection to become a zombie if there are ** unclosed resources, and arranges for deallocation when the last ** prepare statement or sqlite3_backup closes. */ SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); } SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); } /* ** Close the mutex on database connection db. ** ** Furthermore, if database connection db is a zombie (meaning that there ** has been a prior call to sqlite3_close(db) or sqlite3_close_v2(db)) and ** every sqlite3_stmt has now been finalized and every sqlite3_backup has ** finished, then free all resources. */ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ HashElem *i; /* Hash table iterator */ int j; /* If there are outstanding sqlite3_stmt or sqlite3_backup objects ** or if the connection has not yet been closed by sqlite3_close_v2(), ** then just leave the mutex and return. */ if( db->eOpenState!=SQLITE_STATE_ZOMBIE || connectionIsBusy(db) ){ sqlite3_mutex_leave(db->mutex); return; } /* If we reach this point, it means that the database connection has ** closed all sqlite3_stmt and sqlite3_backup objects and has been ** passed to sqlite3_close (meaning that it is a zombie). Therefore, ** go ahead and free all resources. */ /* If a transaction is open, roll it back. This also ensures that if ** any database schemas have been modified by an uncommitted transaction ** they are reset. And that the required b-tree mutex is held to make ** the pager rollback and schema reset an atomic operation. */ sqlite3RollbackAll(db, SQLITE_OK); /* Free any outstanding Savepoint structures. */ sqlite3CloseSavepoints(db); /* Close all database connections */ for(j=0; jnDb; j++){ struct Db *pDb = &db->aDb[j]; if( pDb->pBt ){ sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; if( j!=1 ){ pDb->pSchema = 0; } } } /* Clear the TEMP schema separately and last */ if( db->aDb[1].pSchema ){ sqlite3SchemaClear(db->aDb[1].pSchema); } sqlite3VtabUnlockList(db); /* Free up the array of auxiliary databases */ sqlite3CollapseDatabaseArray(db); assert( db->nDb<=2 ); assert( db->aDb==db->aDbStatic ); /* Tell the code in notify.c that the connection no longer holds any ** locks and does not require any further unlock-notify callbacks. */ sqlite3ConnectionClosed(db); for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){ FuncDef *pNext, *p; p = sqliteHashData(i); do{ functionDestroy(db, p); pNext = p->pNext; sqlite3DbFree(db, p); p = pNext; }while( p ); } sqlite3HashClear(&db->aFunc); for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){ CollSeq *pColl = (CollSeq *)sqliteHashData(i); /* Invoke any destructors registered for collation sequence user data. */ for(j=0; j<3; j++){ if( pColl[j].xDel ){ pColl[j].xDel(pColl[j].pUser); } } sqlite3DbFree(db, pColl); } sqlite3HashClear(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ Module *pMod = (Module *)sqliteHashData(i); sqlite3VtabEponymousTableClear(db, pMod); sqlite3VtabModuleUnref(db, pMod); } sqlite3HashClear(&db->aModule); #endif sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ sqlite3ValueFree(db->pErr); sqlite3CloseExtensions(db); #if SQLITE_USER_AUTHENTICATION sqlite3_free(db->auth.zAuthUser); sqlite3_free(db->auth.zAuthPW); #endif db->eOpenState = SQLITE_STATE_ERROR; /* The temp-database schema is allocated differently from the other schema ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). ** So it needs to be freed here. Todo: Why not roll the temp schema into ** the same sqliteMalloc() as the one that allocates the database ** structure? */ sqlite3DbFree(db, db->aDb[1].pSchema); if( db->xAutovacDestr ){ db->xAutovacDestr(db->pAutovacPagesArg); } sqlite3_mutex_leave(db->mutex); db->eOpenState = SQLITE_STATE_CLOSED; sqlite3_mutex_free(db->mutex); assert( sqlite3LookasideUsed(db,0)==0 ); if( db->lookaside.bMalloced ){ sqlite3_free(db->lookaside.pStart); } sqlite3_free(db); } /* ** Rollback all database files. If tripCode is not SQLITE_OK, then ** any write cursors are invalidated ("tripped" - as in "tripping a circuit ** breaker") and made to return tripCode if there are any further ** attempts to use that cursor. Read cursors remain open and valid ** but are "saved" in case the table pages are moved around. */ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ int i; int inTrans = 0; int schemaChange; assert( sqlite3_mutex_held(db->mutex) ); sqlite3BeginBenignMalloc(); /* Obtain all b-tree mutexes before making any calls to BtreeRollback(). ** This is important in case the transaction being rolled back has ** modified the database schema. If the b-tree mutexes are not taken ** here, then another shared-cache connection might sneak in between ** the database rollback and schema reset, which can cause false ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0; for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; if( p ){ if( sqlite3BtreeTxnState(p)==SQLITE_TXN_WRITE ){ inTrans = 1; } sqlite3BtreeRollback(p, tripCode, !schemaChange); } } sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); if( schemaChange ){ sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); } sqlite3BtreeLeaveAll(db); /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; db->nDeferredImmCons = 0; db->flags &= ~(u64)(SQLITE_DeferFKs|SQLITE_CorruptRdOnly); /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ db->xRollbackCallback(db->pRollbackArg); } } /* ** Return a static string containing the name corresponding to the error code ** specified in the argument. */ #if defined(SQLITE_NEED_ERR_NAME) SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ const char *zName = 0; int i, origRc = rc; for(i=0; i<2 && zName==0; i++, rc &= 0xff){ switch( rc ){ case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; case SQLITE_ERROR_SNAPSHOT: zName = "SQLITE_ERROR_SNAPSHOT"; break; case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; case SQLITE_ABORT_ROLLBACK: zName = "SQLITE_ABORT_ROLLBACK"; break; case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; case SQLITE_BUSY_RECOVERY: zName = "SQLITE_BUSY_RECOVERY"; break; case SQLITE_BUSY_SNAPSHOT: zName = "SQLITE_BUSY_SNAPSHOT"; break; case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break; case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break; case SQLITE_READONLY_CANTINIT: zName = "SQLITE_READONLY_CANTINIT"; break; case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break; case SQLITE_READONLY_DBMOVED: zName = "SQLITE_READONLY_DBMOVED"; break; case SQLITE_READONLY_DIRECTORY: zName = "SQLITE_READONLY_DIRECTORY";break; case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break; case SQLITE_IOERR_SHORT_READ: zName = "SQLITE_IOERR_SHORT_READ"; break; case SQLITE_IOERR_WRITE: zName = "SQLITE_IOERR_WRITE"; break; case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break; case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break; case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break; case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break; case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break; case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break; case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break; case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break; case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; case SQLITE_IOERR_CHECKRESERVEDLOCK: zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break; case SQLITE_IOERR_CLOSE: zName = "SQLITE_IOERR_CLOSE"; break; case SQLITE_IOERR_DIR_CLOSE: zName = "SQLITE_IOERR_DIR_CLOSE"; break; case SQLITE_IOERR_SHMOPEN: zName = "SQLITE_IOERR_SHMOPEN"; break; case SQLITE_IOERR_SHMSIZE: zName = "SQLITE_IOERR_SHMSIZE"; break; case SQLITE_IOERR_SHMLOCK: zName = "SQLITE_IOERR_SHMLOCK"; break; case SQLITE_IOERR_SHMMAP: zName = "SQLITE_IOERR_SHMMAP"; break; case SQLITE_IOERR_SEEK: zName = "SQLITE_IOERR_SEEK"; break; case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break; case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break; case SQLITE_IOERR_GETTEMPPATH: zName = "SQLITE_IOERR_GETTEMPPATH"; break; case SQLITE_IOERR_CONVPATH: zName = "SQLITE_IOERR_CONVPATH"; break; case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break; case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; case SQLITE_FULL: zName = "SQLITE_FULL"; break; case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break; case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break; case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break; case SQLITE_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; break; case SQLITE_CANTOPEN_SYMLINK: zName = "SQLITE_CANTOPEN_SYMLINK"; break; case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break; case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; case SQLITE_CONSTRAINT_UNIQUE: zName = "SQLITE_CONSTRAINT_UNIQUE"; break; case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break; case SQLITE_CONSTRAINT_FOREIGNKEY: zName = "SQLITE_CONSTRAINT_FOREIGNKEY"; break; case SQLITE_CONSTRAINT_CHECK: zName = "SQLITE_CONSTRAINT_CHECK"; break; case SQLITE_CONSTRAINT_PRIMARYKEY: zName = "SQLITE_CONSTRAINT_PRIMARYKEY"; break; case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break; case SQLITE_CONSTRAINT_COMMITHOOK: zName = "SQLITE_CONSTRAINT_COMMITHOOK"; break; case SQLITE_CONSTRAINT_VTAB: zName = "SQLITE_CONSTRAINT_VTAB"; break; case SQLITE_CONSTRAINT_FUNCTION: zName = "SQLITE_CONSTRAINT_FUNCTION"; break; case SQLITE_CONSTRAINT_ROWID: zName = "SQLITE_CONSTRAINT_ROWID"; break; case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; case SQLITE_ROW: zName = "SQLITE_ROW"; break; case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break; case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break; case SQLITE_NOTICE_RECOVER_ROLLBACK: zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; case SQLITE_NOTICE_RBU: zName = "SQLITE_NOTICE_RBU"; break; case SQLITE_WARNING: zName = "SQLITE_WARNING"; break; case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break; case SQLITE_DONE: zName = "SQLITE_DONE"; break; } } if( zName==0 ){ static char zBuf[50]; sqlite3_snprintf(sizeof(zBuf), zBuf, "SQLITE_UNKNOWN(%d)", origRc); zName = zBuf; } return zName; } #endif /* ** Return a static string that describes the kind of error specified in the ** argument. */ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ static const char* const aMsg[] = { /* SQLITE_OK */ "not an error", /* SQLITE_ERROR */ "SQL logic error", /* SQLITE_INTERNAL */ 0, /* SQLITE_PERM */ "access permission denied", /* SQLITE_ABORT */ "query aborted", /* SQLITE_BUSY */ "database is locked", /* SQLITE_LOCKED */ "database table is locked", /* SQLITE_NOMEM */ "out of memory", /* SQLITE_READONLY */ "attempt to write a readonly database", /* SQLITE_INTERRUPT */ "interrupted", /* SQLITE_IOERR */ "disk I/O error", /* SQLITE_CORRUPT */ "database disk image is malformed", /* SQLITE_NOTFOUND */ "unknown operation", /* SQLITE_FULL */ "database or disk is full", /* SQLITE_CANTOPEN */ "unable to open database file", /* SQLITE_PROTOCOL */ "locking protocol", /* SQLITE_EMPTY */ 0, /* SQLITE_SCHEMA */ "database schema has changed", /* SQLITE_TOOBIG */ "string or blob too big", /* SQLITE_CONSTRAINT */ "constraint failed", /* SQLITE_MISMATCH */ "datatype mismatch", /* SQLITE_MISUSE */ "bad parameter or other API misuse", #ifdef SQLITE_DISABLE_LFS /* SQLITE_NOLFS */ "large file support is disabled", #else /* SQLITE_NOLFS */ 0, #endif /* SQLITE_AUTH */ "authorization denied", /* SQLITE_FORMAT */ 0, /* SQLITE_RANGE */ "column index out of range", /* SQLITE_NOTADB */ "file is not a database", /* SQLITE_NOTICE */ "notification message", /* SQLITE_WARNING */ "warning message", }; const char *zErr = "unknown error"; switch( rc ){ case SQLITE_ABORT_ROLLBACK: { zErr = "abort due to ROLLBACK"; break; } case SQLITE_ROW: { zErr = "another row available"; break; } case SQLITE_DONE: { zErr = "no more rows available"; break; } default: { rc &= 0xff; if( ALWAYS(rc>=0) && rcbusyTimeout; int delay, prior; assert( count>=0 ); if( count < NDELAY ){ delay = delays[count]; prior = totals[count]; }else{ delay = delays[NDELAY-1]; prior = totals[NDELAY-1] + delay*(count-(NDELAY-1)); } if( prior + delay > tmout ){ delay = tmout - prior; if( delay<=0 ) return 0; } sqlite3OsSleep(db->pVfs, delay*1000); return 1; #else /* This case for unix systems that lack usleep() support. Sleeping ** must be done in increments of whole seconds */ sqlite3 *db = (sqlite3 *)ptr; int tmout = ((sqlite3 *)ptr)->busyTimeout; if( (count+1)*1000 > tmout ){ return 0; } sqlite3OsSleep(db->pVfs, 1000000); return 1; #endif } /* ** Invoke the given busy handler. ** ** This routine is called when an operation failed to acquire a ** lock on VFS file pFile. ** ** If this routine returns non-zero, the lock is retried. If it ** returns 0, the operation aborts with an SQLITE_BUSY error. */ SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){ int rc; if( p->xBusyHandler==0 || p->nBusy<0 ) return 0; rc = p->xBusyHandler(p->pBusyArg, p->nBusy); if( rc==0 ){ p->nBusy = -1; }else{ p->nBusy++; } return rc; } /* ** This routine sets the busy callback for an Sqlite database to the ** given callback function with the given argument. */ SQLITE_API int sqlite3_busy_handler( sqlite3 *db, int (*xBusy)(void*,int), void *pArg ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->busyHandler.xBusyHandler = xBusy; db->busyHandler.pBusyArg = pArg; db->busyHandler.nBusy = 0; db->busyTimeout = 0; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* ** This routine sets the progress callback for an Sqlite database to the ** given callback function with the given argument. The progress callback will ** be invoked every nOps opcodes. */ SQLITE_API void sqlite3_progress_handler( sqlite3 *db, int nOps, int (*xProgress)(void*), void *pArg ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return; } #endif sqlite3_mutex_enter(db->mutex); if( nOps>0 ){ db->xProgress = xProgress; db->nProgressOps = (unsigned)nOps; db->pProgressArg = pArg; }else{ db->xProgress = 0; db->nProgressOps = 0; db->pProgressArg = 0; } sqlite3_mutex_leave(db->mutex); } #endif /* ** This routine installs a default busy handler that waits for the ** specified number of milliseconds before returning 0. */ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif if( ms>0 ){ sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback, (void*)db); db->busyTimeout = ms; }else{ sqlite3_busy_handler(db, 0, 0); } return SQLITE_OK; } /* ** Cause any pending operation to stop at its earliest opportunity. */ SQLITE_API void sqlite3_interrupt(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) ){ (void)SQLITE_MISUSE_BKPT; return; } #endif AtomicStore(&db->u1.isInterrupted, 1); } /* ** Return true or false depending on whether or not an interrupt is ** pending on connection db. */ SQLITE_API int sqlite3_is_interrupted(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return AtomicLoad(&db->u1.isInterrupted)!=0; } /* ** This function is exactly the same as sqlite3_create_function(), except ** that it is designed to be called by internal code. The difference is ** that if a malloc() fails in sqlite3_create_function(), an error code ** is returned and the mallocFailed flag cleared. */ SQLITE_PRIVATE int sqlite3CreateFunc( sqlite3 *db, const char *zFunctionName, int nArg, int enc, void *pUserData, void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInverse)(sqlite3_context*,int,sqlite3_value **), FuncDestructor *pDestructor ){ FuncDef *p; int extraFlags; assert( sqlite3_mutex_held(db->mutex) ); assert( xValue==0 || xSFunc==0 ); if( zFunctionName==0 /* Must have a valid name */ || (xSFunc!=0 && xFinal!=0) /* Not both xSFunc and xFinal */ || ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */ || ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */ || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) || (255funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){ if( db->nVdbeActive ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify user-function due to active statements"); assert( !db->mallocFailed ); return SQLITE_BUSY; }else{ sqlite3ExpirePreparedStatements(db, 0); } }else if( xSFunc==0 && xFinal==0 ){ /* Trying to delete a function that does not exist. This is a no-op. ** https://sqlite.org/forum/forumpost/726219164b */ return SQLITE_OK; } p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1); assert(p || db->mallocFailed); if( !p ){ return SQLITE_NOMEM_BKPT; } /* If an older version of the function with a configured destructor is ** being replaced invoke the destructor function here. */ functionDestroy(db, p); if( pDestructor ){ pDestructor->nRef++; } p->u.pDestructor = pDestructor; p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags; testcase( p->funcFlags & SQLITE_DETERMINISTIC ); testcase( p->funcFlags & SQLITE_DIRECTONLY ); p->xSFunc = xSFunc ? xSFunc : xStep; p->xFinalize = xFinal; p->xValue = xValue; p->xInverse = xInverse; p->pUserData = pUserData; p->nArg = (u16)nArg; return SQLITE_OK; } /* ** Worker function used by utf-8 APIs that create new functions: ** ** sqlite3_create_function() ** sqlite3_create_function_v2() ** sqlite3_create_window_function() */ static int createFunctionApi( sqlite3 *db, const char *zFunc, int nArg, int enc, void *p, void (*xSFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInverse)(sqlite3_context*,int,sqlite3_value**), void(*xDestroy)(void*) ){ int rc = SQLITE_ERROR; FuncDestructor *pArg = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( xDestroy ){ pArg = (FuncDestructor *)sqlite3Malloc(sizeof(FuncDestructor)); if( !pArg ){ sqlite3OomFault(db); xDestroy(p); goto out; } pArg->nRef = 0; pArg->xDestroy = xDestroy; pArg->pUserData = p; } rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, xValue, xInverse, pArg ); if( pArg && pArg->nRef==0 ){ assert( rc!=SQLITE_OK || (xStep==0 && xFinal==0) ); xDestroy(p); sqlite3_free(pArg); } out: rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Create new user functions. */ SQLITE_API int sqlite3_create_function( sqlite3 *db, const char *zFunc, int nArg, int enc, void *p, void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*) ){ return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, 0, 0, 0); } SQLITE_API int sqlite3_create_function_v2( sqlite3 *db, const char *zFunc, int nArg, int enc, void *p, void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*), void (*xDestroy)(void *) ){ return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, 0, 0, xDestroy); } SQLITE_API int sqlite3_create_window_function( sqlite3 *db, const char *zFunc, int nArg, int enc, void *p, void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInverse)(sqlite3_context*,int,sqlite3_value **), void (*xDestroy)(void *) ){ return createFunctionApi(db, zFunc, nArg, enc, p, 0, xStep, xFinal, xValue, xInverse, xDestroy); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API int sqlite3_create_function16( sqlite3 *db, const void *zFunctionName, int nArg, int eTextRep, void *p, void (*xSFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ){ int rc; char *zFunc8; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE); rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0,0,0); sqlite3DbFree(db, zFunc8); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } #endif /* ** The following is the implementation of an SQL function that always ** fails with an error message stating that the function is used in the ** wrong context. The sqlite3_overload_function() API might construct ** SQL function that use this routine so that the functions will exist ** for name resolution but are actually overloaded by the xFindFunction ** method of virtual tables. */ static void sqlite3InvalidFunction( sqlite3_context *context, /* The function calling context */ int NotUsed, /* Number of arguments to the function */ sqlite3_value **NotUsed2 /* Value of each argument */ ){ const char *zName = (const char*)sqlite3_user_data(context); char *zErr; UNUSED_PARAMETER2(NotUsed, NotUsed2); zErr = sqlite3_mprintf( "unable to use function %s in the requested context", zName); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); } /* ** Declare that a function has been overloaded by a virtual table. ** ** If the function already exists as a regular global function, then ** this routine is a no-op. If the function does not exist, then create ** a new one that always throws a run-time error. ** ** When virtual tables intend to provide an overloaded function, they ** should call this routine to make sure the global function exists. ** A global function must exist in order for name resolution to work ** properly. */ SQLITE_API int sqlite3_overload_function( sqlite3 *db, const char *zName, int nArg ){ int rc; char *zCopy; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0; sqlite3_mutex_leave(db->mutex); if( rc ) return SQLITE_OK; zCopy = sqlite3_mprintf("%s", zName); if( zCopy==0 ) return SQLITE_NOMEM; return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8, zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free); } #ifndef SQLITE_OMIT_TRACE /* ** Register a trace function. The pArg from the previously registered trace ** is returned. ** ** A NULL trace function means that no tracing is executes. A non-NULL ** trace is a pointer to a function that is invoked at the start of each ** SQL statement. */ #ifndef SQLITE_OMIT_DEPRECATED SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){ void *pOld; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; db->trace.xLegacy = xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_DEPRECATED */ /* Register a trace callback using the version-2 interface. */ SQLITE_API int sqlite3_trace_v2( sqlite3 *db, /* Trace this connection */ unsigned mTrace, /* Mask of events to be traced */ int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */ void *pArg /* Context */ ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( mTrace==0 ) xTrace = 0; if( xTrace==0 ) mTrace = 0; db->mTrace = mTrace; db->trace.xV2 = xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_DEPRECATED /* ** Register a profile function. The pArg from the previously registered ** profile function is returned. ** ** A NULL profile function means that no profiling is executes. A non-NULL ** profile is a pointer to a function that is invoked at the conclusion of ** each SQL statement that is run. */ SQLITE_API void *sqlite3_profile( sqlite3 *db, void (*xProfile)(void*,const char*,sqlite_uint64), void *pArg ){ void *pOld; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pOld = db->pProfileArg; db->xProfile = xProfile; db->pProfileArg = pArg; db->mTrace &= SQLITE_TRACE_NONLEGACY_MASK; if( db->xProfile ) db->mTrace |= SQLITE_TRACE_XPROFILE; sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_DEPRECATED */ #endif /* SQLITE_OMIT_TRACE */ /* ** Register a function to be invoked when a transaction commits. ** If the invoked function returns non-zero, then the commit becomes a ** rollback. */ SQLITE_API void *sqlite3_commit_hook( sqlite3 *db, /* Attach the hook to this database */ int (*xCallback)(void*), /* Function to invoke on each commit */ void *pArg /* Argument to the function */ ){ void *pOld; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pOld = db->pCommitArg; db->xCommitCallback = xCallback; db->pCommitArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } /* ** Register a callback to be invoked each time a row is updated, ** inserted or deleted using this database connection. */ SQLITE_API void *sqlite3_update_hook( sqlite3 *db, /* Attach the hook to this database */ void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), void *pArg /* Argument to the function */ ){ void *pRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pRet = db->pUpdateArg; db->xUpdateCallback = xCallback; db->pUpdateArg = pArg; sqlite3_mutex_leave(db->mutex); return pRet; } /* ** Register a callback to be invoked each time a transaction is rolled ** back by this database connection. */ SQLITE_API void *sqlite3_rollback_hook( sqlite3 *db, /* Attach the hook to this database */ void (*xCallback)(void*), /* Callback function */ void *pArg /* Argument to the function */ ){ void *pRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pRet = db->pRollbackArg; db->xRollbackCallback = xCallback; db->pRollbackArg = pArg; sqlite3_mutex_leave(db->mutex); return pRet; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Register a callback to be invoked each time a row is updated, ** inserted or deleted using this database connection. */ SQLITE_API void *sqlite3_preupdate_hook( sqlite3 *db, /* Attach the hook to this database */ void(*xCallback)( /* Callback function */ void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64), void *pArg /* First callback argument */ ){ void *pRet; #ifdef SQLITE_ENABLE_API_ARMOR if( db==0 ){ return 0; } #endif sqlite3_mutex_enter(db->mutex); pRet = db->pPreUpdateArg; db->xPreUpdateCallback = xCallback; db->pPreUpdateArg = pArg; sqlite3_mutex_leave(db->mutex); return pRet; } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ /* ** Register a function to be invoked prior to each autovacuum that ** determines the number of pages to vacuum. */ SQLITE_API int sqlite3_autovacuum_pages( sqlite3 *db, /* Attach the hook to this database */ unsigned int (*xCallback)(void*,const char*,u32,u32,u32), void *pArg, /* Argument to the function */ void (*xDestructor)(void*) /* Destructor for pArg */ ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ if( xDestructor ) xDestructor(pArg); return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( db->xAutovacDestr ){ db->xAutovacDestr(db->pAutovacPagesArg); } db->xAutovacPages = xCallback; db->pAutovacPagesArg = pArg; db->xAutovacDestr = xDestructor; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_WAL /* ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). ** Invoke sqlite3_wal_checkpoint if the number of frames in the log file ** is greater than sqlite3.pWalArg cast to an integer (the value configured by ** wal_autocheckpoint()). */ SQLITE_PRIVATE int sqlite3WalDefaultHook( void *pClientData, /* Argument */ sqlite3 *db, /* Connection */ const char *zDb, /* Database */ int nFrame /* Size of WAL */ ){ if( nFrame>=SQLITE_PTR_TO_INT(pClientData) ){ sqlite3BeginBenignMalloc(); sqlite3_wal_checkpoint(db, zDb); sqlite3EndBenignMalloc(); } return SQLITE_OK; } #endif /* SQLITE_OMIT_WAL */ /* ** Configure an sqlite3_wal_hook() callback to automatically checkpoint ** a database after committing a transaction if there are nFrame or ** more frames in the log file. Passing zero or a negative value as the ** nFrame parameter disables automatic checkpoints entirely. ** ** The callback registered by this function replaces any existing callback ** registered using sqlite3_wal_hook(). Likewise, registering a callback ** using sqlite3_wal_hook() disables the automatic checkpoint mechanism ** configured by this function. */ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){ #ifdef SQLITE_OMIT_WAL UNUSED_PARAMETER(db); UNUSED_PARAMETER(nFrame); #else #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif if( nFrame>0 ){ sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame)); }else{ sqlite3_wal_hook(db, 0, 0); } #endif return SQLITE_OK; } /* ** Register a callback to be invoked each time a transaction is written ** into the write-ahead-log by this database connection. */ SQLITE_API void *sqlite3_wal_hook( sqlite3 *db, /* Attach the hook to this db handle */ int(*xCallback)(void *, sqlite3*, const char*, int), void *pArg /* First argument passed to xCallback() */ ){ #ifndef SQLITE_OMIT_WAL void *pRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pRet = db->pWalArg; db->xWalCallback = xCallback; db->pWalArg = pArg; sqlite3_mutex_leave(db->mutex); return pRet; #else return 0; #endif } /* ** Checkpoint database zDb. */ SQLITE_API int sqlite3_wal_checkpoint_v2( sqlite3 *db, /* Database handle */ const char *zDb, /* Name of attached database (or NULL) */ int eMode, /* SQLITE_CHECKPOINT_* value */ int *pnLog, /* OUT: Size of WAL log in frames */ int *pnCkpt /* OUT: Total number of frames checkpointed */ ){ #ifdef SQLITE_OMIT_WAL return SQLITE_OK; #else int rc; /* Return code */ int iDb; /* Schema to checkpoint */ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif /* Initialize the output variables to -1 in case an error occurs. */ if( pnLog ) *pnLog = -1; if( pnCkpt ) *pnCkpt = -1; assert( SQLITE_CHECKPOINT_PASSIVE==0 ); assert( SQLITE_CHECKPOINT_FULL==1 ); assert( SQLITE_CHECKPOINT_RESTART==2 ); assert( SQLITE_CHECKPOINT_TRUNCATE==3 ); if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint ** mode: */ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); if( zDb && zDb[0] ){ iDb = sqlite3FindDbName(db, zDb); }else{ iDb = SQLITE_MAX_DB; /* This means process all schemas */ } if( iDb<0 ){ rc = SQLITE_ERROR; sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb); }else{ db->busyHandler.nBusy = 0; rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt); sqlite3Error(db, rc); } rc = sqlite3ApiExit(db, rc); /* If there are no active statements, clear the interrupt flag at this ** point. */ if( db->nVdbeActive==0 ){ AtomicStore(&db->u1.isInterrupted, 0); } sqlite3_mutex_leave(db->mutex); return rc; #endif } /* ** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points ** to contains a zero-length string, all attached databases are ** checkpointed. */ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ /* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to ** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */ return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0); } #ifndef SQLITE_OMIT_WAL /* ** Run a checkpoint on database iDb. This is a no-op if database iDb is ** not currently open in WAL mode. ** ** If a transaction is open on the database being checkpointed, this ** function returns SQLITE_LOCKED and a checkpoint is not attempted. If ** an error occurs while running the checkpoint, an SQLite error code is ** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK. ** ** The mutex on database handle db should be held by the caller. The mutex ** associated with the specific b-tree being checkpointed is taken by ** this function while the checkpoint is running. ** ** If iDb is passed SQLITE_MAX_DB then all attached databases are ** checkpointed. If an error is encountered it is returned immediately - ** no attempt is made to checkpoint any remaining databases. ** ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART ** or TRUNCATE. */ SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; /* Return code */ int i; /* Used to iterate through attached dbs */ int bBusy = 0; /* True if SQLITE_BUSY has been encountered */ assert( sqlite3_mutex_held(db->mutex) ); assert( !pnLog || *pnLog==-1 ); assert( !pnCkpt || *pnCkpt==-1 ); testcase( iDb==SQLITE_MAX_ATTACHED ); /* See forum post a006d86f72 */ testcase( iDb==SQLITE_MAX_DB ); for(i=0; inDb && rc==SQLITE_OK; i++){ if( i==iDb || iDb==SQLITE_MAX_DB ){ rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, eMode, pnLog, pnCkpt); pnLog = 0; pnCkpt = 0; if( rc==SQLITE_BUSY ){ bBusy = 1; rc = SQLITE_OK; } } } return (rc==SQLITE_OK && bBusy) ? SQLITE_BUSY : rc; } #endif /* SQLITE_OMIT_WAL */ /* ** This function returns true if main-memory should be used instead of ** a temporary file for transient pager files and statement journals. ** The value returned depends on the value of db->temp_store (runtime ** parameter) and the compile time value of SQLITE_TEMP_STORE. The ** following table describes the relationship between these two values ** and this functions return value. ** ** SQLITE_TEMP_STORE db->temp_store Location of temporary database ** ----------------- -------------- ------------------------------ ** 0 any file (return 0) ** 1 1 file (return 0) ** 1 2 memory (return 1) ** 1 0 file (return 0) ** 2 1 file (return 0) ** 2 2 memory (return 1) ** 2 0 memory (return 1) ** 3 any memory (return 1) */ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){ #if SQLITE_TEMP_STORE==1 return ( db->temp_store==2 ); #endif #if SQLITE_TEMP_STORE==2 return ( db->temp_store!=1 ); #endif #if SQLITE_TEMP_STORE==3 UNUSED_PARAMETER(db); return 1; #endif #if SQLITE_TEMP_STORE<1 || SQLITE_TEMP_STORE>3 UNUSED_PARAMETER(db); return 0; #endif } /* ** Return UTF-8 encoded English language explanation of the most recent ** error. */ SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){ const char *z; if( !db ){ return sqlite3ErrStr(SQLITE_NOMEM_BKPT); } if( !sqlite3SafetyCheckSickOrOk(db) ){ return sqlite3ErrStr(SQLITE_MISUSE_BKPT); } sqlite3_mutex_enter(db->mutex); if( db->mallocFailed ){ z = sqlite3ErrStr(SQLITE_NOMEM_BKPT); }else{ testcase( db->pErr==0 ); z = db->errCode ? (char*)sqlite3_value_text(db->pErr) : 0; assert( !db->mallocFailed ); if( z==0 ){ z = sqlite3ErrStr(db->errCode); } } sqlite3_mutex_leave(db->mutex); return z; } /* ** Return the byte offset of the most recent error */ SQLITE_API int sqlite3_error_offset(sqlite3 *db){ int iOffset = -1; if( db && sqlite3SafetyCheckSickOrOk(db) && db->errCode ){ sqlite3_mutex_enter(db->mutex); iOffset = db->errByteOffset; sqlite3_mutex_leave(db->mutex); } return iOffset; } #ifndef SQLITE_OMIT_UTF16 /* ** Return UTF-16 encoded English language explanation of the most recent ** error. */ SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){ static const u16 outOfMem[] = { 'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0 }; static const u16 misuse[] = { 'b', 'a', 'd', ' ', 'p', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', ' ', 'o', 'r', ' ', 'o', 't', 'h', 'e', 'r', ' ', 'A', 'P', 'I', ' ', 'm', 'i', 's', 'u', 's', 'e', 0 }; const void *z; if( !db ){ return (void *)outOfMem; } if( !sqlite3SafetyCheckSickOrOk(db) ){ return (void *)misuse; } sqlite3_mutex_enter(db->mutex); if( db->mallocFailed ){ z = (void *)outOfMem; }else{ z = sqlite3_value_text16(db->pErr); if( z==0 ){ sqlite3ErrorWithMsg(db, db->errCode, sqlite3ErrStr(db->errCode)); z = sqlite3_value_text16(db->pErr); } /* A malloc() may have failed within the call to sqlite3_value_text16() ** above. If this is the case, then the db->mallocFailed flag needs to ** be cleared before returning. Do this directly, instead of via ** sqlite3ApiExit(), to avoid setting the database handle error message. */ sqlite3OomClear(db); } sqlite3_mutex_leave(db->mutex); return z; } #endif /* SQLITE_OMIT_UTF16 */ /* ** Return the most recent error code generated by an SQLite routine. If NULL is ** passed to this function, we assume a malloc() failed during sqlite3_open(). */ SQLITE_API int sqlite3_errcode(sqlite3 *db){ if( db && !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } if( !db || db->mallocFailed ){ return SQLITE_NOMEM_BKPT; } return db->errCode & db->errMask; } SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){ if( db && !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } if( !db || db->mallocFailed ){ return SQLITE_NOMEM_BKPT; } return db->errCode; } SQLITE_API int sqlite3_system_errno(sqlite3 *db){ return db ? db->iSysErrno : 0; } /* ** Return a string that describes the kind of error specified in the ** argument. For now, this simply calls the internal sqlite3ErrStr() ** function. */ SQLITE_API const char *sqlite3_errstr(int rc){ return sqlite3ErrStr(rc); } /* ** Create a new collating function for database "db". The name is zName ** and the encoding is enc. */ static int createCollation( sqlite3* db, const char *zName, u8 enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*), void(*xDel)(void*) ){ CollSeq *pColl; int enc2; assert( sqlite3_mutex_held(db->mutex) ); /* If SQLITE_UTF16 is specified as the encoding type, transform this ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. */ enc2 = enc; testcase( enc2==SQLITE_UTF16 ); testcase( enc2==SQLITE_UTF16_ALIGNED ); if( enc2==SQLITE_UTF16 || enc2==SQLITE_UTF16_ALIGNED ){ enc2 = SQLITE_UTF16NATIVE; } if( enc2SQLITE_UTF16BE ){ return SQLITE_MISUSE_BKPT; } /* Check if this call is removing or replacing an existing collation ** sequence. If so, and there are active VMs, return busy. If there ** are no active VMs, invalidate any pre-compiled statements. */ pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0); if( pColl && pColl->xCmp ){ if( db->nVdbeActive ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify collation sequence due to active statements"); return SQLITE_BUSY; } sqlite3ExpirePreparedStatements(db, 0); /* If collation sequence pColl was created directly by a call to ** sqlite3_create_collation, and not generated by synthCollSeq(), ** then any copies made by synthCollSeq() need to be invalidated. ** Also, collation destructor - CollSeq.xDel() - function may need ** to be called. */ if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){ CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName); int j; for(j=0; j<3; j++){ CollSeq *p = &aColl[j]; if( p->enc==pColl->enc ){ if( p->xDel ){ p->xDel(p->pUser); } p->xCmp = 0; } } } } pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1); if( pColl==0 ) return SQLITE_NOMEM_BKPT; pColl->xCmp = xCompare; pColl->pUser = pCtx; pColl->xDel = xDel; pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED)); sqlite3Error(db, SQLITE_OK); return SQLITE_OK; } /* ** This array defines hard upper bounds on limit values. The ** initializer must be kept in sync with the SQLITE_LIMIT_* ** #defines in sqlite3.h. */ static const int aHardLimit[] = { SQLITE_MAX_LENGTH, SQLITE_MAX_SQL_LENGTH, SQLITE_MAX_COLUMN, SQLITE_MAX_EXPR_DEPTH, SQLITE_MAX_COMPOUND_SELECT, SQLITE_MAX_VDBE_OP, SQLITE_MAX_FUNCTION_ARG, SQLITE_MAX_ATTACHED, SQLITE_MAX_LIKE_PATTERN_LENGTH, SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ SQLITE_MAX_TRIGGER_DEPTH, SQLITE_MAX_WORKER_THREADS, }; /* ** Make sure the hard limits are set to reasonable values */ #if SQLITE_MAX_LENGTH<100 # error SQLITE_MAX_LENGTH must be at least 100 #endif #if SQLITE_MAX_SQL_LENGTH<100 # error SQLITE_MAX_SQL_LENGTH must be at least 100 #endif #if SQLITE_MAX_SQL_LENGTH>SQLITE_MAX_LENGTH # error SQLITE_MAX_SQL_LENGTH must not be greater than SQLITE_MAX_LENGTH #endif #if SQLITE_MAX_COMPOUND_SELECT<2 # error SQLITE_MAX_COMPOUND_SELECT must be at least 2 #endif #if SQLITE_MAX_VDBE_OP<40 # error SQLITE_MAX_VDBE_OP must be at least 40 #endif #if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127 # error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127 #endif #if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125 # error SQLITE_MAX_ATTACHED must be between 0 and 125 #endif #if SQLITE_MAX_LIKE_PATTERN_LENGTH<1 # error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1 #endif #if SQLITE_MAX_COLUMN>32767 # error SQLITE_MAX_COLUMN must not exceed 32767 #endif #if SQLITE_MAX_TRIGGER_DEPTH<1 # error SQLITE_MAX_TRIGGER_DEPTH must be at least 1 #endif #if SQLITE_MAX_WORKER_THREADS<0 || SQLITE_MAX_WORKER_THREADS>50 # error SQLITE_MAX_WORKER_THREADS must be between 0 and 50 #endif /* ** Change the value of a limit. Report the old value. ** If an invalid limit index is supplied, report -1. ** Make no changes but still report the old value if the ** new limit is negative. ** ** A new lower limit does not shrink existing constructs. ** It merely prevents new constructs that exceed the limit ** from forming. */ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ int oldLimit; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return -1; } #endif /* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME ** there is a hard upper bound set at compile-time by a C preprocessor ** macro called SQLITE_MAX_NAME. (The "_LIMIT_" in the name is changed to ** "_MAX_".) */ assert( aHardLimit[SQLITE_LIMIT_LENGTH]==SQLITE_MAX_LENGTH ); assert( aHardLimit[SQLITE_LIMIT_SQL_LENGTH]==SQLITE_MAX_SQL_LENGTH ); assert( aHardLimit[SQLITE_LIMIT_COLUMN]==SQLITE_MAX_COLUMN ); assert( aHardLimit[SQLITE_LIMIT_EXPR_DEPTH]==SQLITE_MAX_EXPR_DEPTH ); assert( aHardLimit[SQLITE_LIMIT_COMPOUND_SELECT]==SQLITE_MAX_COMPOUND_SELECT); assert( aHardLimit[SQLITE_LIMIT_VDBE_OP]==SQLITE_MAX_VDBE_OP ); assert( aHardLimit[SQLITE_LIMIT_FUNCTION_ARG]==SQLITE_MAX_FUNCTION_ARG ); assert( aHardLimit[SQLITE_LIMIT_ATTACHED]==SQLITE_MAX_ATTACHED ); assert( aHardLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]== SQLITE_MAX_LIKE_PATTERN_LENGTH ); assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER); assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH ); assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS ); assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) ); if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ return -1; } oldLimit = db->aLimit[limitId]; if( newLimit>=0 ){ /* IMP: R-52476-28732 */ if( newLimit>aHardLimit[limitId] ){ newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){ newLimit = 1; } db->aLimit[limitId] = newLimit; } return oldLimit; /* IMP: R-53341-35419 */ } /* ** This function is used to parse both URIs and non-URI filenames passed by the ** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database ** URIs specified as part of ATTACH statements. ** ** The first argument to this function is the name of the VFS to use (or ** a NULL to signify the default VFS) if the URI does not contain a "vfs=xxx" ** query parameter. The second argument contains the URI (or non-URI filename) ** itself. When this function is called the *pFlags variable should contain ** the default flags to open the database handle with. The value stored in ** *pFlags may be updated before returning if the URI filename contains ** "cache=xxx" or "mode=xxx" query parameters. ** ** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to ** the VFS that should be used to open the database file. *pzFile is set to ** point to a buffer containing the name of the file to open. The value ** stored in *pzFile is a database name acceptable to sqlite3_uri_parameter() ** and is in the same format as names created using sqlite3_create_filename(). ** The caller must invoke sqlite3_free_filename() (not sqlite3_free()!) on ** the value returned in *pzFile to avoid a memory leak. ** ** If an error occurs, then an SQLite error code is returned and *pzErrMsg ** may be set to point to a buffer containing an English language error ** message. It is the responsibility of the caller to eventually release ** this buffer by calling sqlite3_free(). */ SQLITE_PRIVATE int sqlite3ParseUri( const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */ const char *zUri, /* Nul-terminated URI to parse */ unsigned int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */ sqlite3_vfs **ppVfs, /* OUT: VFS to use */ char **pzFile, /* OUT: Filename component of URI */ char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */ ){ int rc = SQLITE_OK; unsigned int flags = *pFlags; const char *zVfs = zDefaultVfs; char *zFile; char c; int nUri = sqlite3Strlen30(zUri); assert( *pzErrMsg==0 ); if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */ || AtomicLoad(&sqlite3GlobalConfig.bOpenUri)) /* IMP: R-51689-46548 */ && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ ){ char *zOpt; int eState; /* Parser state when parsing URI */ int iIn; /* Input character index */ int iOut = 0; /* Output character index */ u64 nByte = nUri+8; /* Bytes of space to allocate */ /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen ** method that there may be extra parameters following the file-name. */ flags |= SQLITE_OPEN_URI; for(iIn=0; iIn=0 && octet<256 ); if( octet==0 ){ #ifndef SQLITE_ENABLE_URI_00_ERROR /* This branch is taken when "%00" appears within the URI. In this ** case we ignore all text in the remainder of the path, name or ** value currently being parsed. So ignore the current character ** and skip to the next "?", "=" or "&", as appropriate. */ while( (c = zUri[iIn])!=0 && c!='#' && (eState!=0 || c!='?') && (eState!=1 || (c!='=' && c!='&')) && (eState!=2 || c!='&') ){ iIn++; } continue; #else /* If ENABLE_URI_00_ERROR is defined, "%00" in a URI is an error. */ *pzErrMsg = sqlite3_mprintf("unexpected %%00 in uri"); rc = SQLITE_ERROR; goto parse_uri_out; #endif } c = octet; }else if( eState==1 && (c=='&' || c=='=') ){ if( zFile[iOut-1]==0 ){ /* An empty option name. Ignore this option altogether. */ while( zUri[iIn] && zUri[iIn]!='#' && zUri[iIn-1]!='&' ) iIn++; continue; } if( c=='&' ){ zFile[iOut++] = '\0'; }else{ eState = 2; } c = 0; }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ c = 0; eState = 1; } zFile[iOut++] = c; } if( eState==1 ) zFile[iOut++] = '\0'; memset(zFile+iOut, 0, 4); /* end-of-options + empty journal filenames */ /* Check if there were any options specified that should be interpreted ** here. Options that are interpreted here include "vfs" and those that ** correspond to flags that may be passed to the sqlite3_open_v2() ** method. */ zOpt = &zFile[sqlite3Strlen30(zFile)+1]; while( zOpt[0] ){ int nOpt = sqlite3Strlen30(zOpt); char *zVal = &zOpt[nOpt+1]; int nVal = sqlite3Strlen30(zVal); if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){ zVfs = zVal; }else{ struct OpenMode { const char *z; int mode; } *aMode = 0; char *zModeType = 0; int mask = 0; int limit = 0; if( nOpt==5 && memcmp("cache", zOpt, 5)==0 ){ static struct OpenMode aCacheMode[] = { { "shared", SQLITE_OPEN_SHAREDCACHE }, { "private", SQLITE_OPEN_PRIVATECACHE }, { 0, 0 } }; mask = SQLITE_OPEN_SHAREDCACHE|SQLITE_OPEN_PRIVATECACHE; aMode = aCacheMode; limit = mask; zModeType = "cache"; } if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){ static struct OpenMode aOpenMode[] = { { "ro", SQLITE_OPEN_READONLY }, { "rw", SQLITE_OPEN_READWRITE }, { "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE }, { "memory", SQLITE_OPEN_MEMORY }, { 0, 0 } }; mask = SQLITE_OPEN_READONLY | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY; aMode = aOpenMode; limit = mask & flags; zModeType = "access"; } if( aMode ){ int i; int mode = 0; for(i=0; aMode[i].z; i++){ const char *z = aMode[i].z; if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){ mode = aMode[i].mode; break; } } if( mode==0 ){ *pzErrMsg = sqlite3_mprintf("no such %s mode: %s", zModeType, zVal); rc = SQLITE_ERROR; goto parse_uri_out; } if( (mode & ~SQLITE_OPEN_MEMORY)>limit ){ *pzErrMsg = sqlite3_mprintf("%s mode not allowed: %s", zModeType, zVal); rc = SQLITE_PERM; goto parse_uri_out; } flags = (flags & ~mask) | mode; } } zOpt = &zVal[nVal+1]; } }else{ zFile = sqlite3_malloc64(nUri+8); if( !zFile ) return SQLITE_NOMEM_BKPT; memset(zFile, 0, 4); zFile += 4; if( nUri ){ memcpy(zFile, zUri, nUri); } memset(zFile+nUri, 0, 4); flags &= ~SQLITE_OPEN_URI; } *ppVfs = sqlite3_vfs_find(zVfs); if( *ppVfs==0 ){ *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs); rc = SQLITE_ERROR; } parse_uri_out: if( rc!=SQLITE_OK ){ sqlite3_free_filename(zFile); zFile = 0; } *pFlags = flags; *pzFile = zFile; return rc; } /* ** This routine does the core work of extracting URI parameters from a ** database filename for the sqlite3_uri_parameter() interface. */ static const char *uriParameter(const char *zFilename, const char *zParam){ zFilename += sqlite3Strlen30(zFilename) + 1; while( ALWAYS(zFilename!=0) && zFilename[0] ){ int x = strcmp(zFilename, zParam); zFilename += sqlite3Strlen30(zFilename) + 1; if( x==0 ) return zFilename; zFilename += sqlite3Strlen30(zFilename) + 1; } return 0; } /* ** This routine does the work of opening a database on behalf of ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" ** is UTF-8 encoded. */ static int openDatabase( const char *zFilename, /* Database filename UTF-8 encoded */ sqlite3 **ppDb, /* OUT: Returned database handle */ unsigned int flags, /* Operational flags */ const char *zVfs /* Name of the VFS to use */ ){ sqlite3 *db; /* Store allocated handle here */ int rc; /* Return code */ int isThreadsafe; /* True for threadsafe connections */ char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */ int i; /* Loop counter */ #ifdef SQLITE_ENABLE_API_ARMOR if( ppDb==0 ) return SQLITE_MISUSE_BKPT; #endif *ppDb = 0; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ) return rc; #endif if( sqlite3GlobalConfig.bCoreMutex==0 ){ isThreadsafe = 0; }else if( flags & SQLITE_OPEN_NOMUTEX ){ isThreadsafe = 0; }else if( flags & SQLITE_OPEN_FULLMUTEX ){ isThreadsafe = 1; }else{ isThreadsafe = sqlite3GlobalConfig.bFullMutex; } if( flags & SQLITE_OPEN_PRIVATECACHE ){ flags &= ~SQLITE_OPEN_SHAREDCACHE; }else if( sqlite3GlobalConfig.sharedCacheEnabled ){ flags |= SQLITE_OPEN_SHAREDCACHE; } /* Remove harmful bits from the flags parameter ** ** The SQLITE_OPEN_NOMUTEX and SQLITE_OPEN_FULLMUTEX flags were ** dealt with in the previous code block. Besides these, the only ** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY, ** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE, ** SQLITE_OPEN_PRIVATECACHE, SQLITE_OPEN_EXRESCODE, and some reserved ** bits. Silently mask off all other flags. */ flags &= ~( SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_TRANSIENT_DB | SQLITE_OPEN_MAIN_JOURNAL | SQLITE_OPEN_TEMP_JOURNAL | SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_SUPER_JOURNAL | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_WAL ); /* Allocate the sqlite data structure */ db = sqlite3MallocZero( sizeof(sqlite3) ); if( db==0 ) goto opendb_out; if( isThreadsafe #ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS || sqlite3GlobalConfig.bCoreMutex #endif ){ db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); if( db->mutex==0 ){ sqlite3_free(db); db = 0; goto opendb_out; } if( isThreadsafe==0 ){ sqlite3MutexWarnOnContention(db->mutex); } } sqlite3_mutex_enter(db->mutex); db->errMask = (flags & SQLITE_OPEN_EXRESCODE)!=0 ? 0xffffffff : 0xff; db->nDb = 2; db->eOpenState = SQLITE_STATE_BUSY; db->aDb = db->aDbStatic; db->lookaside.bDisable = 1; db->lookaside.sz = 0; assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS; db->autoCommit = 1; db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ #ifdef SQLITE_ENABLE_SORTER_MMAP /* Beginning with version 3.37.0, using the VFS xFetch() API to memory-map ** the temporary files used to do external sorts (see code in vdbesort.c) ** is disabled. It can still be used either by defining ** SQLITE_ENABLE_SORTER_MMAP at compile time or by using the ** SQLITE_TESTCTRL_SORTER_MMAP test-control at runtime. */ db->nMaxSorterMmap = 0x7FFFFFFF; #endif db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_EnableView | SQLITE_CacheSpill #if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0 | SQLITE_TrustedSchema #endif /* The SQLITE_DQS compile-time option determines the default settings ** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML. ** ** SQLITE_DQS SQLITE_DBCONFIG_DQS_DDL SQLITE_DBCONFIG_DQS_DML ** ---------- ----------------------- ----------------------- ** undefined on on ** 3 on on ** 2 on off ** 1 off on ** 0 off off ** ** Legacy behavior is 3 (double-quoted string literals are allowed anywhere) ** and so that is the default. But developers are encouraged to use ** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible. */ #if !defined(SQLITE_DQS) # define SQLITE_DQS 3 #endif #if (SQLITE_DQS&1)==1 | SQLITE_DqsDML #endif #if (SQLITE_DQS&2)==2 | SQLITE_DqsDDL #endif #if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX | SQLITE_AutoIndex #endif #if SQLITE_DEFAULT_CKPTFULLFSYNC | SQLITE_CkptFullFSync #endif #if SQLITE_DEFAULT_FILE_FORMAT<4 | SQLITE_LegacyFileFmt #endif #ifdef SQLITE_ENABLE_LOAD_EXTENSION | SQLITE_LoadExtension #endif #if SQLITE_DEFAULT_RECURSIVE_TRIGGERS | SQLITE_RecTriggers #endif #if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS | SQLITE_ForeignKeys #endif #if defined(SQLITE_REVERSE_UNORDERED_SELECTS) | SQLITE_ReverseOrder #endif #if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK) | SQLITE_CellSizeCk #endif #if defined(SQLITE_ENABLE_FTS3_TOKENIZER) | SQLITE_Fts3Tokenizer #endif #if defined(SQLITE_ENABLE_QPSG) | SQLITE_EnableQPSG #endif #if defined(SQLITE_DEFAULT_DEFENSIVE) | SQLITE_Defensive #endif #if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE) | SQLITE_LegacyAlter #endif #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) | SQLITE_StmtScanStatus #endif ; sqlite3HashInit(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3HashInit(&db->aModule); #endif /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. ** ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating ** functions: */ createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0); createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0); createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0); createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0); if( db->mallocFailed ){ goto opendb_out; } #if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) /* Process magic filenames ":localStorage:" and ":sessionStorage:" */ if( zFilename && zFilename[0]==':' ){ if( strcmp(zFilename, ":localStorage:")==0 ){ zFilename = "file:local?vfs=kvvfs"; flags |= SQLITE_OPEN_URI; }else if( strcmp(zFilename, ":sessionStorage:")==0 ){ zFilename = "file:session?vfs=kvvfs"; flags |= SQLITE_OPEN_URI; } } #endif /* SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) */ /* Parse the filename/URI argument ** ** Only allow sensible combinations of bits in the flags argument. ** Throw an error if any non-sense combination is used. If we ** do not block illegal combinations here, it could trigger ** assert() statements in deeper layers. Sensible combinations ** are: ** ** 1: SQLITE_OPEN_READONLY ** 2: SQLITE_OPEN_READWRITE ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE */ db->openFlags = flags; assert( SQLITE_OPEN_READONLY == 0x01 ); assert( SQLITE_OPEN_READWRITE == 0x02 ); assert( SQLITE_OPEN_CREATE == 0x04 ); testcase( (1<<(flags&7))==0x02 ); /* READONLY */ testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ if( ((1<<(flags&7)) & 0x46)==0 ){ rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */ }else{ rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); } if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg); sqlite3_free(zErrMsg); goto opendb_out; } assert( db->pVfs!=0 ); #if SQLITE_OS_KV || defined(SQLITE_OS_KV_OPTIONAL) if( sqlite3_stricmp(db->pVfs->zName, "kvvfs")==0 ){ db->temp_store = 2; } #endif /* Open the backend database driver */ rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0, flags | SQLITE_OPEN_MAIN_DB); if( rc!=SQLITE_OK ){ if( rc==SQLITE_IOERR_NOMEM ){ rc = SQLITE_NOMEM_BKPT; } sqlite3Error(db, rc); goto opendb_out; } sqlite3BtreeEnter(db->aDb[0].pBt); db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); if( !db->mallocFailed ){ sqlite3SetTextEncoding(db, SCHEMA_ENC(db)); } sqlite3BtreeLeave(db->aDb[0].pBt); db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); /* The default safety_level for the main database is FULL; for the temp ** database it is OFF. This matches the pager layer defaults. */ db->aDb[0].zDbSName = "main"; db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; db->aDb[1].zDbSName = "temp"; db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF; db->eOpenState = SQLITE_STATE_OPEN; if( db->mallocFailed ){ goto opendb_out; } /* Register all built-in functions, but do not attempt to read the ** database schema yet. This is delayed until the first time the database ** is accessed. */ sqlite3Error(db, SQLITE_OK); sqlite3RegisterPerConnectionBuiltinFunctions(db); rc = sqlite3_errcode(db); /* Load compiled-in extensions */ for(i=0; rc==SQLITE_OK && imDbFlags |= DBFLAG_InternalFunc; #endif /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking ** mode. Doing nothing at all also makes NORMAL the default. */ #ifdef SQLITE_DEFAULT_LOCKING_MODE db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE; sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt), SQLITE_DEFAULT_LOCKING_MODE); #endif if( rc ) sqlite3Error(db, rc); /* Enable the lookaside-malloc subsystem */ setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside, sqlite3GlobalConfig.nLookaside); sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); opendb_out: if( db ){ assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); sqlite3_mutex_leave(db->mutex); } rc = sqlite3_errcode(db); assert( db!=0 || (rc&0xff)==SQLITE_NOMEM ); if( (rc&0xff)==SQLITE_NOMEM ){ sqlite3_close(db); db = 0; }else if( rc!=SQLITE_OK ){ db->eOpenState = SQLITE_STATE_SICK; } *ppDb = db; #ifdef SQLITE_ENABLE_SQLLOG if( sqlite3GlobalConfig.xSqllog ){ /* Opening a db handle. Fourth parameter is passed 0. */ void *pArg = sqlite3GlobalConfig.pSqllogArg; sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); } #endif sqlite3_free_filename(zOpen); return rc; } /* ** Open a new database handle. */ SQLITE_API int sqlite3_open( const char *zFilename, sqlite3 **ppDb ){ return openDatabase(zFilename, ppDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); } SQLITE_API int sqlite3_open_v2( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb, /* OUT: SQLite db handle */ int flags, /* Flags */ const char *zVfs /* Name of VFS module to use */ ){ return openDatabase(filename, ppDb, (unsigned int)flags, zVfs); } #ifndef SQLITE_OMIT_UTF16 /* ** Open a new database handle. */ SQLITE_API int sqlite3_open16( const void *zFilename, sqlite3 **ppDb ){ char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */ sqlite3_value *pVal; int rc; #ifdef SQLITE_ENABLE_API_ARMOR if( ppDb==0 ) return SQLITE_MISUSE_BKPT; #endif *ppDb = 0; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ) return rc; #endif if( zFilename==0 ) zFilename = "\000\000"; pVal = sqlite3ValueNew(0); sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC); zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zFilename8 ){ rc = openDatabase(zFilename8, ppDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); assert( *ppDb || rc==SQLITE_NOMEM ); if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){ SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE; } }else{ rc = SQLITE_NOMEM_BKPT; } sqlite3ValueFree(pVal); return rc & 0xff; } #endif /* SQLITE_OMIT_UTF16 */ /* ** Register a new collation sequence with the database handle db. */ SQLITE_API int sqlite3_create_collation( sqlite3* db, const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ return sqlite3_create_collation_v2(db, zName, enc, pCtx, xCompare, 0); } /* ** Register a new collation sequence with the database handle db. */ SQLITE_API int sqlite3_create_collation_v2( sqlite3* db, const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*), void(*xDel)(void*) ){ int rc; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } #ifndef SQLITE_OMIT_UTF16 /* ** Register a new collation sequence with the database handle db. */ SQLITE_API int sqlite3_create_collation16( sqlite3* db, const void *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ int rc = SQLITE_OK; char *zName8; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE); if( zName8 ){ rc = createCollation(db, zName8, (u8)enc, pCtx, xCompare, 0); sqlite3DbFree(db, zName8); } rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } #endif /* SQLITE_OMIT_UTF16 */ /* ** Register a collation sequence factory callback with the database handle ** db. Replace any previously installed collation sequence factory. */ SQLITE_API int sqlite3_collation_needed( sqlite3 *db, void *pCollNeededArg, void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*) ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->xCollNeeded = xCollNeeded; db->xCollNeeded16 = 0; db->pCollNeededArg = pCollNeededArg; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_UTF16 /* ** Register a collation sequence factory callback with the database handle ** db. Replace any previously installed collation sequence factory. */ SQLITE_API int sqlite3_collation_needed16( sqlite3 *db, void *pCollNeededArg, void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*) ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->xCollNeeded = 0; db->xCollNeeded16 = xCollNeeded16; db->pCollNeededArg = pCollNeededArg; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #endif /* SQLITE_OMIT_UTF16 */ /* ** Find existing client data. */ SQLITE_API void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){ DbClientData *p; sqlite3_mutex_enter(db->mutex); for(p=db->pDbData; p; p=p->pNext){ if( strcmp(p->zName, zName)==0 ){ void *pResult = p->pData; sqlite3_mutex_leave(db->mutex); return pResult; } } sqlite3_mutex_leave(db->mutex); return 0; } /* ** Add new client data to a database connection. */ SQLITE_API int sqlite3_set_clientdata( sqlite3 *db, /* Attach client data to this connection */ const char *zName, /* Name of the client data */ void *pData, /* The client data itself */ void (*xDestructor)(void*) /* Destructor */ ){ DbClientData *p, **pp; sqlite3_mutex_enter(db->mutex); pp = &db->pDbData; for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){ pp = &p->pNext; } if( p ){ assert( p->pData!=0 ); if( p->xDestructor ) p->xDestructor(p->pData); if( pData==0 ){ *pp = p->pNext; sqlite3_free(p); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } }else if( pData==0 ){ sqlite3_mutex_leave(db->mutex); return SQLITE_OK; }else{ size_t n = strlen(zName); p = sqlite3_malloc64( sizeof(DbClientData)+n+1 ); if( p==0 ){ if( xDestructor ) xDestructor(pData); sqlite3_mutex_leave(db->mutex); return SQLITE_NOMEM; } memcpy(p->zName, zName, n+1); p->pNext = db->pDbData; db->pDbData = p; } p->pData = pData; p->xDestructor = xDestructor; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_DEPRECATED /* ** This function is now an anachronism. It used to be used to recover from a ** malloc() failure, but SQLite now does this automatically. */ SQLITE_API int sqlite3_global_recover(void){ return SQLITE_OK; } #endif /* ** Test to see whether or not the database connection is in autocommit ** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on ** by default. Autocommit is disabled by a BEGIN statement and reenabled ** by the next COMMIT or ROLLBACK. */ SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return db->autoCommit; } /* ** The following routines are substitutes for constants SQLITE_CORRUPT, ** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_NOMEM and possibly other error ** constants. They serve two purposes: ** ** 1. Serve as a convenient place to set a breakpoint in a debugger ** to detect when version error conditions occurs. ** ** 2. Invoke sqlite3_log() to provide the source code location where ** a low-level error is first detected. */ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){ sqlite3_log(iErr, "%s at line %d of [%.10s]", zType, lineno, 20+sqlite3_sourceid()); return iErr; } SQLITE_PRIVATE int sqlite3CorruptError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption"); } SQLITE_PRIVATE int sqlite3MisuseError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse"); } SQLITE_PRIVATE int sqlite3CantopenError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file"); } #if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) SQLITE_PRIVATE int sqlite3CorruptPgnoError(int lineno, Pgno pgno){ char zMsg[100]; sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno); testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); } #endif #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3NomemError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM"); } SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error"); } #endif #ifndef SQLITE_OMIT_DEPRECATED /* ** This is a convenience routine that makes sure that all thread-specific ** data for this thread has been deallocated. ** ** SQLite no longer uses thread-specific data so this routine is now a ** no-op. It is retained for historical compatibility. */ SQLITE_API void sqlite3_thread_cleanup(void){ } #endif /* ** Return meta information about a specific column of a database table. ** See comment in sqlite3.h (sqlite.h.in) for details. */ SQLITE_API int sqlite3_table_column_metadata( sqlite3 *db, /* Connection handle */ const char *zDbName, /* Database name or NULL */ const char *zTableName, /* Table name */ const char *zColumnName, /* Column name */ char const **pzDataType, /* OUTPUT: Declared data type */ char const **pzCollSeq, /* OUTPUT: Collation sequence name */ int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ int *pPrimaryKey, /* OUTPUT: True if column part of PK */ int *pAutoinc /* OUTPUT: True if column is auto-increment */ ){ int rc; char *zErrMsg = 0; Table *pTab = 0; Column *pCol = 0; int iCol = 0; char const *zDataType = 0; char const *zCollSeq = 0; int notnull = 0; int primarykey = 0; int autoinc = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){ return SQLITE_MISUSE_BKPT; } #endif /* Ensure the database schema has been loaded */ sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); rc = sqlite3Init(db, &zErrMsg); if( SQLITE_OK!=rc ){ goto error_out; } /* Locate the table in question */ pTab = sqlite3FindTable(db, zTableName, zDbName); if( !pTab || IsView(pTab) ){ pTab = 0; goto error_out; } /* Find the column for which info is requested */ if( zColumnName==0 ){ /* Query for existence of table only */ }else{ for(iCol=0; iColnCol; iCol++){ pCol = &pTab->aCol[iCol]; if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){ break; } } if( iCol==pTab->nCol ){ if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ iCol = pTab->iPKey; pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; }else{ pTab = 0; goto error_out; } } } /* The following block stores the meta information that will be returned ** to the caller in local variables zDataType, zCollSeq, notnull, primarykey ** and autoinc. At this point there are two possibilities: ** ** 1. The specified column name was rowid", "oid" or "_rowid_" ** and there is no explicitly declared IPK column. ** ** 2. The table is not a view and the column name identified an ** explicitly declared column. Copy meta information from *pCol. */ if( pCol ){ zDataType = sqlite3ColumnType(pCol,0); zCollSeq = sqlite3ColumnColl(pCol); notnull = pCol->notNull!=0; primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0; autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0; }else{ zDataType = "INTEGER"; primarykey = 1; } if( !zCollSeq ){ zCollSeq = sqlite3StrBINARY; } error_out: sqlite3BtreeLeaveAll(db); /* Whether the function call succeeded or failed, set the output parameters ** to whatever their local counterparts contain. If an error did occur, ** this has the effect of zeroing all output parameters. */ if( pzDataType ) *pzDataType = zDataType; if( pzCollSeq ) *pzCollSeq = zCollSeq; if( pNotNull ) *pNotNull = notnull; if( pPrimaryKey ) *pPrimaryKey = primarykey; if( pAutoinc ) *pAutoinc = autoinc; if( SQLITE_OK==rc && !pTab ){ sqlite3DbFree(db, zErrMsg); zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName, zColumnName); rc = SQLITE_ERROR; } sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg); sqlite3DbFree(db, zErrMsg); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Sleep for a little while. Return the amount of time slept. */ SQLITE_API int sqlite3_sleep(int ms){ sqlite3_vfs *pVfs; int rc; pVfs = sqlite3_vfs_find(0); if( pVfs==0 ) return 0; /* This function works in milliseconds, but the underlying OsSleep() ** API uses microseconds. Hence the 1000's. */ rc = (sqlite3OsSleep(pVfs, ms<0 ? 0 : 1000*ms)/1000); return rc; } /* ** Enable or disable the extended result codes. */ SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->errMask = onoff ? 0xffffffff : 0xff; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } /* ** Invoke the xFileControl method on a particular database. */ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ int rc = SQLITE_ERROR; Btree *pBtree; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); pBtree = sqlite3DbNameToBtree(db, zDbName); if( pBtree ){ Pager *pPager; sqlite3_file *fd; sqlite3BtreeEnter(pBtree); pPager = sqlite3BtreePager(pBtree); assert( pPager!=0 ); fd = sqlite3PagerFile(pPager); assert( fd!=0 ); if( op==SQLITE_FCNTL_FILE_POINTER ){ *(sqlite3_file**)pArg = fd; rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_VFS_POINTER ){ *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){ *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_DATA_VERSION ){ *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){ int iNew = *(int*)pArg; *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree); if( iNew>=0 && iNew<=255 ){ sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0); } rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_RESET_CACHE ){ sqlite3BtreeClearCache(pBtree); rc = SQLITE_OK; }else{ int nSave = db->busyHandler.nBusy; rc = sqlite3OsFileControl(fd, op, pArg); db->busyHandler.nBusy = nSave; } sqlite3BtreeLeave(pBtree); } sqlite3_mutex_leave(db->mutex); return rc; } /* ** Interface to the testing logic. */ SQLITE_API int sqlite3_test_control(int op, ...){ int rc = 0; #ifdef SQLITE_UNTESTABLE UNUSED_PARAMETER(op); #else va_list ap; va_start(ap, op); switch( op ){ /* ** Save the current state of the PRNG. */ case SQLITE_TESTCTRL_PRNG_SAVE: { sqlite3PrngSaveState(); break; } /* ** Restore the state of the PRNG to the last state saved using ** PRNG_SAVE. If PRNG_SAVE has never before been called, then ** this verb acts like PRNG_RESET. */ case SQLITE_TESTCTRL_PRNG_RESTORE: { sqlite3PrngRestoreState(); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, int x, sqlite3 *db); ** ** Control the seed for the pseudo-random number generator (PRNG) that ** is built into SQLite. Cases: ** ** x!=0 && db!=0 Seed the PRNG to the current value of the ** schema cookie in the main database for db, or ** x if the schema cookie is zero. This case ** is convenient to use with database fuzzers ** as it allows the fuzzer some control over the ** the PRNG seed. ** ** x!=0 && db==0 Seed the PRNG to the value of x. ** ** x==0 && db==0 Revert to default behavior of using the ** xRandomness method on the primary VFS. ** ** This test-control also resets the PRNG so that the new seed will ** be used for the next call to sqlite3_randomness(). */ #ifndef SQLITE_OMIT_WSD case SQLITE_TESTCTRL_PRNG_SEED: { int x = va_arg(ap, int); int y; sqlite3 *db = va_arg(ap, sqlite3*); assert( db==0 || db->aDb[0].pSchema!=0 ); if( db && (y = db->aDb[0].pSchema->schema_cookie)!=0 ){ x = y; } sqlite3Config.iPrngSeed = x; sqlite3_randomness(0,0); break; } #endif /* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b); ** ** If b is true, then activate the SQLITE_FkNoAction setting. If b is ** false then clearn that setting. If the SQLITE_FkNoAction setting is ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if ** they were NO ACTION, regardless of how they are defined. ** ** NB: One must usually run "PRAGMA writable_schema=RESET" after ** using this test-control, before it will take full effect. failing ** to reset the schema can result in some unexpected behavior. */ case SQLITE_TESTCTRL_FK_NO_ACTION: { sqlite3 *db = va_arg(ap, sqlite3*); int b = va_arg(ap, int); if( b ){ db->flags |= SQLITE_FkNoAction; }else{ db->flags &= ~SQLITE_FkNoAction; } break; } /* ** sqlite3_test_control(BITVEC_TEST, size, program) ** ** Run a test against a Bitvec object of size. The program argument ** is an array of integers that defines the test. Return -1 on a ** memory allocation error, 0 on success, or non-zero for an error. ** See the sqlite3BitvecBuiltinTest() for additional information. */ case SQLITE_TESTCTRL_BITVEC_TEST: { int sz = va_arg(ap, int); int *aProg = va_arg(ap, int*); rc = sqlite3BitvecBuiltinTest(sz, aProg); break; } /* ** sqlite3_test_control(FAULT_INSTALL, xCallback) ** ** Arrange to invoke xCallback() whenever sqlite3FaultSim() is called, ** if xCallback is not NULL. ** ** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0) ** is called immediately after installing the new callback and the return ** value from sqlite3FaultSim(0) becomes the return from ** sqlite3_test_control(). */ case SQLITE_TESTCTRL_FAULT_INSTALL: { /* A bug in MSVC prevents it from understanding pointers to functions ** types in the second argument to va_arg(). Work around the problem ** using a typedef. ** http://support.microsoft.com/kb/47961 <-- dead hyperlink ** Search at http://web.archive.org/ to find the 2015-03-16 archive ** of the link above to see the original text. ** sqlite3GlobalConfig.xTestCallback = va_arg(ap, int(*)(int)); */ typedef int(*sqlite3FaultFuncType)(int); sqlite3GlobalConfig.xTestCallback = va_arg(ap, sqlite3FaultFuncType); rc = sqlite3FaultSim(0); break; } /* ** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd) ** ** Register hooks to call to indicate which malloc() failures ** are benign. */ case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: { typedef void (*void_function)(void); void_function xBenignBegin; void_function xBenignEnd; xBenignBegin = va_arg(ap, void_function); xBenignEnd = va_arg(ap, void_function); sqlite3BenignMallocHooks(xBenignBegin, xBenignEnd); break; } /* ** sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, unsigned int X) ** ** Set the PENDING byte to the value in the argument, if X>0. ** Make no changes if X==0. Return the value of the pending byte ** as it existing before this routine was called. ** ** IMPORTANT: Changing the PENDING byte from 0x40000000 results in ** an incompatible database file format. Changing the PENDING byte ** while any database connection is open results in undefined and ** deleterious behavior. */ case SQLITE_TESTCTRL_PENDING_BYTE: { rc = PENDING_BYTE; #ifndef SQLITE_OMIT_WSD { unsigned int newVal = va_arg(ap, unsigned int); if( newVal ) sqlite3PendingByte = newVal; } #endif break; } /* ** sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, int X) ** ** This action provides a run-time test to see whether or not ** assert() was enabled at compile-time. If X is true and assert() ** is enabled, then the return value is true. If X is true and ** assert() is disabled, then the return value is zero. If X is ** false and assert() is enabled, then the assertion fires and the ** process aborts. If X is false and assert() is disabled, then the ** return value is zero. */ case SQLITE_TESTCTRL_ASSERT: { volatile int x = 0; assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 ); rc = x; #if defined(SQLITE_DEBUG) /* Invoke these debugging routines so that the compiler does not ** issue "defined but not used" warnings. */ if( x==9999 ){ sqlite3ShowExpr(0); sqlite3ShowExpr(0); sqlite3ShowExprList(0); sqlite3ShowIdList(0); sqlite3ShowSrcList(0); sqlite3ShowWith(0); sqlite3ShowUpsert(0); #ifndef SQLITE_OMIT_TRIGGER sqlite3ShowTriggerStep(0); sqlite3ShowTriggerStepList(0); sqlite3ShowTrigger(0); sqlite3ShowTriggerList(0); #endif #ifndef SQLITE_OMIT_WINDOWFUNC sqlite3ShowWindow(0); sqlite3ShowWinFunc(0); #endif sqlite3ShowSelect(0); } #endif break; } /* ** sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, int X) ** ** This action provides a run-time test to see how the ALWAYS and ** NEVER macros were defined at compile-time. ** ** The return value is ALWAYS(X) if X is true, or 0 if X is false. ** ** The recommended test is X==2. If the return value is 2, that means ** ALWAYS() and NEVER() are both no-op pass-through macros, which is the ** default setting. If the return value is 1, then ALWAYS() is either ** hard-coded to true or else it asserts if its argument is false. ** The first behavior (hard-coded to true) is the case if ** SQLITE_TESTCTRL_ASSERT shows that assert() is disabled and the second ** behavior (assert if the argument to ALWAYS() is false) is the case if ** SQLITE_TESTCTRL_ASSERT shows that assert() is enabled. ** ** The run-time test procedure might look something like this: ** ** if( sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, 2)==2 ){ ** // ALWAYS() and NEVER() are no-op pass-through macros ** }else if( sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, 1) ){ ** // ALWAYS(x) asserts that x is true. NEVER(x) asserts x is false. ** }else{ ** // ALWAYS(x) is a constant 1. NEVER(x) is a constant 0. ** } */ case SQLITE_TESTCTRL_ALWAYS: { int x = va_arg(ap,int); rc = x ? ALWAYS(x) : 0; break; } /* ** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER); ** ** The integer returned reveals the byte-order of the computer on which ** SQLite is running: ** ** 1 big-endian, determined at run-time ** 10 little-endian, determined at run-time ** 432101 big-endian, determined at compile-time ** 123410 little-endian, determined at compile-time */ case SQLITE_TESTCTRL_BYTEORDER: { rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN; break; } /* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N) ** ** Enable or disable various optimizations for testing purposes. The ** argument N is a bitmask of optimizations to be disabled. For normal ** operation N should be 0. The idea is that a test program (like the ** SQL Logic Test or SLT test module) can run the same SQL multiple times ** with various optimizations disabled to verify that the same answer ** is obtained in every case. */ case SQLITE_TESTCTRL_OPTIMIZATIONS: { sqlite3 *db = va_arg(ap, sqlite3*); db->dbOptFlags = va_arg(ap, u32); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt); ** ** If parameter onoff is 1, subsequent calls to localtime() fail. ** If 2, then invoke xAlt() instead of localtime(). If 0, normal ** processing. ** ** xAlt arguments are void pointers, but they really want to be: ** ** int xAlt(const time_t*, struct tm*); ** ** xAlt should write results in to struct tm object of its 2nd argument ** and return zero on success, or return non-zero on failure. */ case SQLITE_TESTCTRL_LOCALTIME_FAULT: { sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int); if( sqlite3GlobalConfig.bLocaltimeFault==2 ){ typedef int(*sqlite3LocaltimeType)(const void*,void*); sqlite3GlobalConfig.xAltLocaltime = va_arg(ap, sqlite3LocaltimeType); }else{ sqlite3GlobalConfig.xAltLocaltime = 0; } break; } /* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, sqlite3*); ** ** Toggle the ability to use internal functions on or off for ** the database connection given in the argument. */ case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: { sqlite3 *db = va_arg(ap, sqlite3*); db->mDbFlags ^= DBFLAG_InternalFunc; break; } /* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int); ** ** Set or clear a flag that indicates that the database file is always well- ** formed and never corrupt. This flag is clear by default, indicating that ** database files might have arbitrary corruption. Setting the flag during ** testing causes certain assert() statements in the code to be activated ** that demonstrate invariants on well-formed database files. */ case SQLITE_TESTCTRL_NEVER_CORRUPT: { sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int); ** ** Set or clear a flag that causes SQLite to verify that type, name, ** and tbl_name fields of the sqlite_schema table. This is normally ** on, but it is sometimes useful to turn it off for testing. ** ** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the ** verification of rootpage numbers when parsing the schema. This ** is useful to make it easier to reach strange internal error states ** during testing. The EXTRA_SCHEMA_CHECKS setting is always enabled ** in production. */ case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: { sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int); break; } /* Set the threshold at which OP_Once counters reset back to zero. ** By default this is 0x7ffffffe (over 2 billion), but that value is ** too big to test in a reasonable amount of time, so this control is ** provided to set a small and easily reachable reset value. */ case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: { sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr); ** ** Set the VDBE coverage callback function to xCallback with context ** pointer ptr. */ case SQLITE_TESTCTRL_VDBE_COVERAGE: { #ifdef SQLITE_VDBE_COVERAGE typedef void (*branch_callback)(void*,unsigned int, unsigned char,unsigned char); sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback); sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*); #endif break; } /* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */ case SQLITE_TESTCTRL_SORTER_MMAP: { sqlite3 *db = va_arg(ap, sqlite3*); db->nMaxSorterMmap = va_arg(ap, int); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT); ** ** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if ** not. */ case SQLITE_TESTCTRL_ISINIT: { if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; break; } /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); ** ** This test control is used to create imposter tables. "db" is a pointer ** to the database connection. dbName is the database name (ex: "main" or ** "temp") which will receive the imposter. "onOff" turns imposter mode on ** or off. "tnum" is the root page of the b-tree to which the imposter ** table should connect. ** ** Enable imposter mode only when the schema has already been parsed. Then ** run a single CREATE TABLE statement to construct the imposter table in ** the parsed schema. Then turn imposter mode back off again. ** ** If onOff==0 and tnum>0 then reset the schema for all databases, causing ** the schema to be reparsed the next time it is needed. This has the ** effect of erasing all imposter tables. */ case SQLITE_TESTCTRL_IMPOSTER: { sqlite3 *db = va_arg(ap, sqlite3*); int iDb; sqlite3_mutex_enter(db->mutex); iDb = sqlite3FindDbName(db, va_arg(ap,const char*)); if( iDb>=0 ){ db->init.iDb = iDb; db->init.busy = db->init.imposterTable = va_arg(ap,int); db->init.newTnum = va_arg(ap,int); if( db->init.busy==0 && db->init.newTnum>0 ){ sqlite3ResetAllSchemasOfConnection(db); } } sqlite3_mutex_leave(db->mutex); break; } #if defined(YYCOVERAGE) /* sqlite3_test_control(SQLITE_TESTCTRL_PARSER_COVERAGE, FILE *out) ** ** This test control (only available when SQLite is compiled with ** -DYYCOVERAGE) writes a report onto "out" that shows all ** state/lookahead combinations in the parser state machine ** which are never exercised. If any state is missed, make the ** return code SQLITE_ERROR. */ case SQLITE_TESTCTRL_PARSER_COVERAGE: { FILE *out = va_arg(ap, FILE*); if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR; break; } #endif /* defined(YYCOVERAGE) */ /* sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, sqlite3_context*); ** ** This test-control causes the most recent sqlite3_result_int64() value ** to be interpreted as a MEM_IntReal instead of as an MEM_Int. Normally, ** MEM_IntReal values only arise during an INSERT operation of integer ** values into a REAL column, so they can be challenging to test. This ** test-control enables us to write an intreal() SQL function that can ** inject an intreal() value at arbitrary places in an SQL statement, ** for testing purposes. */ case SQLITE_TESTCTRL_RESULT_INTREAL: { sqlite3_context *pCtx = va_arg(ap, sqlite3_context*); sqlite3ResultIntReal(pCtx); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_SEEK_COUNT, ** sqlite3 *db, // Database connection ** u64 *pnSeek // Write seek count here ** ); ** ** This test-control queries the seek-counter on the "main" database ** file. The seek-counter is written into *pnSeek and is then reset. ** The seek-count is only available if compiled with SQLITE_DEBUG. */ case SQLITE_TESTCTRL_SEEK_COUNT: { sqlite3 *db = va_arg(ap, sqlite3*); u64 *pn = va_arg(ap, sqlite3_uint64*); *pn = sqlite3BtreeSeekCount(db->aDb->pBt); (void)db; /* Silence harmless unused variable warning */ break; } /* sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, op, ptr) ** ** "ptr" is a pointer to a u32. ** ** op==0 Store the current sqlite3TreeTrace in *ptr ** op==1 Set sqlite3TreeTrace to the value *ptr ** op==2 Store the current sqlite3WhereTrace in *ptr ** op==3 Set sqlite3WhereTrace to the value *ptr */ case SQLITE_TESTCTRL_TRACEFLAGS: { int opTrace = va_arg(ap, int); u32 *ptr = va_arg(ap, u32*); switch( opTrace ){ case 0: *ptr = sqlite3TreeTrace; break; case 1: sqlite3TreeTrace = *ptr; break; case 2: *ptr = sqlite3WhereTrace; break; case 3: sqlite3WhereTrace = *ptr; break; } break; } /* sqlite3_test_control(SQLITE_TESTCTRL_LOGEST, ** double fIn, // Input value ** int *pLogEst, // sqlite3LogEstFromDouble(fIn) ** u64 *pInt, // sqlite3LogEstToInt(*pLogEst) ** int *pLogEst2 // sqlite3LogEst(*pInt) ** ); ** ** Test access for the LogEst conversion routines. */ case SQLITE_TESTCTRL_LOGEST: { double rIn = va_arg(ap, double); LogEst rLogEst = sqlite3LogEstFromDouble(rIn); int *pI1 = va_arg(ap,int*); u64 *pU64 = va_arg(ap,u64*); int *pI2 = va_arg(ap,int*); *pI1 = rLogEst; *pU64 = sqlite3LogEstToInt(rLogEst); *pI2 = sqlite3LogEst(*pU64); break; } #if !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X); ** ** X<0 Make no changes to the bUseLongDouble. Just report value. ** X==0 Disable bUseLongDouble ** X==1 Enable bUseLongDouble ** X>=2 Set bUseLongDouble to its default value for this platform */ case SQLITE_TESTCTRL_USELONGDOUBLE: { int b = va_arg(ap, int); if( b>=2 ) b = hasHighPrecisionDouble(b); if( b>=0 ) sqlite3Config.bUseLongDouble = b>0; rc = sqlite3Config.bUseLongDouble!=0; break; } #endif #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue) ** ** If "id" is an integer between 1 and SQLITE_NTUNE then set the value ** of the id-th tuning parameter to *piValue. If "id" is between -1 ** and -SQLITE_NTUNE, then write the current value of the (-id)-th ** tuning parameter into *piValue. ** ** Tuning parameters are for use during transient development builds, ** to help find the best values for constants in the query planner. ** Access tuning parameters using the Tuning(ID) macro. Set the ** parameters in the CLI using ".testctrl tune ID VALUE". ** ** Transient use only. Tuning parameters should not be used in ** checked-in code. */ case SQLITE_TESTCTRL_TUNE: { int id = va_arg(ap, int); int *piValue = va_arg(ap, int*); if( id>0 && id<=SQLITE_NTUNE ){ Tuning(id) = *piValue; }else if( id<0 && id>=-SQLITE_NTUNE ){ *piValue = Tuning(-id); }else{ rc = SQLITE_NOTFOUND; } break; } #endif /* sqlite3_test_control(SQLITE_TESTCTRL_JSON_SELFCHECK, &onOff); ** ** Activate or deactivate validation of JSONB that is generated from ** text. Off by default, as the validation is slow. Validation is ** only available if compiled using SQLITE_DEBUG. ** ** If onOff is initially 1, then turn it on. If onOff is initially ** off, turn it off. If onOff is initially -1, then change onOff ** to be the current setting. */ case SQLITE_TESTCTRL_JSON_SELFCHECK: { #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) int *pOnOff = va_arg(ap, int*); if( *pOnOff<0 ){ *pOnOff = sqlite3Config.bJsonSelfcheck; }else{ sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff); } #endif break; } } va_end(ap); #endif /* SQLITE_UNTESTABLE */ return rc; } /* ** The Pager stores the Database filename, Journal filename, and WAL filename ** consecutively in memory, in that order. The database filename is prefixed ** by four zero bytes. Locate the start of the database filename by searching ** backwards for the first byte following four consecutive zero bytes. ** ** This only works if the filename passed in was obtained from the Pager. */ static const char *databaseName(const char *zName){ while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){ zName--; } return zName; } /* ** Append text z[] to the end of p[]. Return a pointer to the first ** character after then zero terminator on the new text in p[]. */ static char *appendText(char *p, const char *z){ size_t n = strlen(z); memcpy(p, z, n+1); return p+n+1; } /* ** Allocate memory to hold names for a database, journal file, WAL file, ** and query parameters. The pointer returned is valid for use by ** sqlite3_filename_database() and sqlite3_uri_parameter() and related ** functions. ** ** Memory layout must be compatible with that generated by the pager ** and expected by sqlite3_uri_parameter() and databaseName(). */ SQLITE_API const char *sqlite3_create_filename( const char *zDatabase, const char *zJournal, const char *zWal, int nParam, const char **azParam ){ sqlite3_int64 nByte; int i; char *pResult, *p; nByte = strlen(zDatabase) + strlen(zJournal) + strlen(zWal) + 10; for(i=0; i0 ){ zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1; } return zFilename[0] ? zFilename : 0; } /* ** Return a boolean value for a query parameter. */ SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){ const char *z = sqlite3_uri_parameter(zFilename, zParam); bDflt = bDflt!=0; return z ? sqlite3GetBoolean(z, bDflt) : bDflt; } /* ** Return a 64-bit integer value for a query parameter. */ SQLITE_API sqlite3_int64 sqlite3_uri_int64( const char *zFilename, /* Filename as passed to xOpen */ const char *zParam, /* URI parameter sought */ sqlite3_int64 bDflt /* return if parameter is missing */ ){ const char *z = sqlite3_uri_parameter(zFilename, zParam); sqlite3_int64 v; if( z && sqlite3DecOrHexToI64(z, &v)==0 ){ bDflt = v; } return bDflt; } /* ** Translate a filename that was handed to a VFS routine into the corresponding ** database, journal, or WAL file. ** ** It is an error to pass this routine a filename string that was not ** passed into the VFS from the SQLite core. Doing so is similar to ** passing free() a pointer that was not obtained from malloc() - it is ** an error that we cannot easily detect but that will likely cause memory ** corruption. */ SQLITE_API const char *sqlite3_filename_database(const char *zFilename){ if( zFilename==0 ) return 0; return databaseName(zFilename); } SQLITE_API const char *sqlite3_filename_journal(const char *zFilename){ if( zFilename==0 ) return 0; zFilename = databaseName(zFilename); zFilename += sqlite3Strlen30(zFilename) + 1; while( ALWAYS(zFilename) && zFilename[0] ){ zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1; } return zFilename + 1; } SQLITE_API const char *sqlite3_filename_wal(const char *zFilename){ #ifdef SQLITE_OMIT_WAL return 0; #else zFilename = sqlite3_filename_journal(zFilename); if( zFilename ) zFilename += sqlite3Strlen30(zFilename) + 1; return zFilename; #endif } /* ** Return the Btree pointer identified by zDbName. Return NULL if not found. */ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0; return iDb<0 ? 0 : db->aDb[iDb].pBt; } /* ** Return the name of the N-th database schema. Return NULL if N is out ** of range. */ SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif if( N<0 || N>=db->nDb ){ return 0; }else{ return db->aDb[N].zDbSName; } } /* ** Return the filename of the database associated with a database ** connection. */ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ Btree *pBt; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif pBt = sqlite3DbNameToBtree(db, zDbName); return pBt ? sqlite3BtreeGetFilename(pBt) : 0; } /* ** Return 1 if database is read-only or 0 if read/write. Return -1 if ** no such database exists. */ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ Btree *pBt; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return -1; } #endif pBt = sqlite3DbNameToBtree(db, zDbName); return pBt ? sqlite3BtreeIsReadonly(pBt) : -1; } #ifdef SQLITE_ENABLE_SNAPSHOT /* ** Obtain a snapshot handle for the snapshot of database zDb currently ** being read by handle db. */ SQLITE_API int sqlite3_snapshot_get( sqlite3 *db, const char *zDb, sqlite3_snapshot **ppSnapshot ){ int rc = SQLITE_ERROR; #ifndef SQLITE_OMIT_WAL #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( db->autoCommit==0 ){ int iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); } } } } sqlite3_mutex_leave(db->mutex); #endif /* SQLITE_OMIT_WAL */ return rc; } /* ** Open a read-transaction on the snapshot identified by pSnapshot. */ SQLITE_API int sqlite3_snapshot_open( sqlite3 *db, const char *zDb, sqlite3_snapshot *pSnapshot ){ int rc = SQLITE_ERROR; #ifndef SQLITE_OMIT_WAL #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( db->autoCommit==0 ){ int iDb; iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ){ Pager *pPager = sqlite3BtreePager(pBt); int bUnlock = 0; if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_NONE ){ if( db->nVdbeActive==0 ){ rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot); if( rc==SQLITE_OK ){ bUnlock = 1; rc = sqlite3BtreeCommit(pBt); } } }else{ rc = SQLITE_OK; } if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotOpen(pPager, pSnapshot); } if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); sqlite3PagerSnapshotOpen(pPager, 0); } if( bUnlock ){ sqlite3PagerSnapshotUnlock(pPager); } } } } sqlite3_mutex_leave(db->mutex); #endif /* SQLITE_OMIT_WAL */ return rc; } /* ** Recover as many snapshots as possible from the wal file associated with ** schema zDb of database db. */ SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ int rc = SQLITE_ERROR; #ifndef SQLITE_OMIT_WAL int iDb; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( SQLITE_TXN_NONE==sqlite3BtreeTxnState(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt)); sqlite3BtreeCommit(pBt); } } } sqlite3_mutex_leave(db->mutex); #endif /* SQLITE_OMIT_WAL */ return rc; } /* ** Free a snapshot handle obtained from sqlite3_snapshot_get(). */ SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ sqlite3_free(pSnapshot); } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* ** Given the name of a compile-time option, return true if that option ** was used and false if not. ** ** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix ** is not required for a match. */ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){ int i, n; int nOpt; const char **azCompileOpt; #ifdef SQLITE_ENABLE_API_ARMOR if( zOptName==0 ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif azCompileOpt = sqlite3CompileOptions(&nOpt); if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; n = sqlite3Strlen30(zOptName); /* Since nOpt is normally in single digits, a linear search is ** adequate. No need for a binary search. */ for(i=0; i=0 && NpNextBlocked){ int seen = 0; sqlite3 *p2; /* Verify property (1) */ assert( p->pUnlockConnection || p->pBlockingConnection ); /* Verify property (2) */ for(p2=sqlite3BlockedList; p2!=p; p2=p2->pNextBlocked){ if( p2->xUnlockNotify==p->xUnlockNotify ) seen = 1; assert( p2->xUnlockNotify==p->xUnlockNotify || !seen ); assert( db==0 || p->pUnlockConnection!=db ); assert( db==0 || p->pBlockingConnection!=db ); } } } #else # define checkListProperties(x) #endif /* ** Remove connection db from the blocked connections list. If connection ** db is not currently a part of the list, this function is a no-op. */ static void removeFromBlockedList(sqlite3 *db){ sqlite3 **pp; assertMutexHeld(); for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){ if( *pp==db ){ *pp = (*pp)->pNextBlocked; break; } } } /* ** Add connection db to the blocked connections list. It is assumed ** that it is not already a part of the list. */ static void addToBlockedList(sqlite3 *db){ sqlite3 **pp; assertMutexHeld(); for( pp=&sqlite3BlockedList; *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify; pp=&(*pp)->pNextBlocked ); db->pNextBlocked = *pp; *pp = db; } /* ** Obtain the STATIC_MAIN mutex. */ static void enterMutex(void){ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)); checkListProperties(0); } /* ** Release the STATIC_MAIN mutex. */ static void leaveMutex(void){ assertMutexHeld(); checkListProperties(0); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)); } /* ** Register an unlock-notify callback. ** ** This is called after connection "db" has attempted some operation ** but has received an SQLITE_LOCKED error because another connection ** (call it pOther) in the same process was busy using the same shared ** cache. pOther is found by looking at db->pBlockingConnection. ** ** If there is no blocking connection, the callback is invoked immediately, ** before this routine returns. ** ** If pOther is already blocked on db, then report SQLITE_LOCKED, to indicate ** a deadlock. ** ** Otherwise, make arrangements to invoke xNotify when pOther drops ** its locks. ** ** Each call to this routine overrides any prior callbacks registered ** on the same "db". If xNotify==0 then any prior callbacks are immediately ** cancelled. */ SQLITE_API int sqlite3_unlock_notify( sqlite3 *db, void (*xNotify)(void **, int), void *pArg ){ int rc = SQLITE_OK; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); enterMutex(); if( xNotify==0 ){ removeFromBlockedList(db); db->pBlockingConnection = 0; db->pUnlockConnection = 0; db->xUnlockNotify = 0; db->pUnlockArg = 0; }else if( 0==db->pBlockingConnection ){ /* The blocking transaction has been concluded. Or there never was a ** blocking transaction. In either case, invoke the notify callback ** immediately. */ xNotify(&pArg, 1); }else{ sqlite3 *p; for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection){} if( p ){ rc = SQLITE_LOCKED; /* Deadlock detected. */ }else{ db->pUnlockConnection = db->pBlockingConnection; db->xUnlockNotify = xNotify; db->pUnlockArg = pArg; removeFromBlockedList(db); addToBlockedList(db); } } leaveMutex(); assert( !db->mallocFailed ); sqlite3ErrorWithMsg(db, rc, (rc?"database is deadlocked":0)); sqlite3_mutex_leave(db->mutex); return rc; } /* ** This function is called while stepping or preparing a statement ** associated with connection db. The operation will return SQLITE_LOCKED ** to the user because it requires a lock that will not be available ** until connection pBlocker concludes its current transaction. */ SQLITE_PRIVATE void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){ enterMutex(); if( db->pBlockingConnection==0 && db->pUnlockConnection==0 ){ addToBlockedList(db); } db->pBlockingConnection = pBlocker; leaveMutex(); } /* ** This function is called when ** the transaction opened by database db has just finished. Locks held ** by database connection db have been released. ** ** This function loops through each entry in the blocked connections ** list and does the following: ** ** 1) If the sqlite3.pBlockingConnection member of a list entry is ** set to db, then set pBlockingConnection=0. ** ** 2) If the sqlite3.pUnlockConnection member of a list entry is ** set to db, then invoke the configured unlock-notify callback and ** set pUnlockConnection=0. ** ** 3) If the two steps above mean that pBlockingConnection==0 and ** pUnlockConnection==0, remove the entry from the blocked connections ** list. */ SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){ void (*xUnlockNotify)(void **, int) = 0; /* Unlock-notify cb to invoke */ int nArg = 0; /* Number of entries in aArg[] */ sqlite3 **pp; /* Iterator variable */ void **aArg; /* Arguments to the unlock callback */ void **aDyn = 0; /* Dynamically allocated space for aArg[] */ void *aStatic[16]; /* Starter space for aArg[]. No malloc required */ aArg = aStatic; enterMutex(); /* Enter STATIC_MAIN mutex */ /* This loop runs once for each entry in the blocked-connections list. */ for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){ sqlite3 *p = *pp; /* Step 1. */ if( p->pBlockingConnection==db ){ p->pBlockingConnection = 0; } /* Step 2. */ if( p->pUnlockConnection==db ){ assert( p->xUnlockNotify ); if( p->xUnlockNotify!=xUnlockNotify && nArg!=0 ){ xUnlockNotify(aArg, nArg); nArg = 0; } sqlite3BeginBenignMalloc(); assert( aArg==aDyn || (aDyn==0 && aArg==aStatic) ); assert( nArg<=(int)ArraySize(aStatic) || aArg==aDyn ); if( (!aDyn && nArg==(int)ArraySize(aStatic)) || (aDyn && nArg==(int)(sqlite3MallocSize(aDyn)/sizeof(void*))) ){ /* The aArg[] array needs to grow. */ void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2); if( pNew ){ memcpy(pNew, aArg, nArg*sizeof(void *)); sqlite3_free(aDyn); aDyn = aArg = pNew; }else{ /* This occurs when the array of context pointers that need to ** be passed to the unlock-notify callback is larger than the ** aStatic[] array allocated on the stack and the attempt to ** allocate a larger array from the heap has failed. ** ** This is a difficult situation to handle. Returning an error ** code to the caller is insufficient, as even if an error code ** is returned the transaction on connection db will still be ** closed and the unlock-notify callbacks on blocked connections ** will go unissued. This might cause the application to wait ** indefinitely for an unlock-notify callback that will never ** arrive. ** ** Instead, invoke the unlock-notify callback with the context ** array already accumulated. We can then clear the array and ** begin accumulating any further context pointers without ** requiring any dynamic allocation. This is sub-optimal because ** it means that instead of one callback with a large array of ** context pointers the application will receive two or more ** callbacks with smaller arrays of context pointers, which will ** reduce the applications ability to prioritize multiple ** connections. But it is the best that can be done under the ** circumstances. */ xUnlockNotify(aArg, nArg); nArg = 0; } } sqlite3EndBenignMalloc(); aArg[nArg++] = p->pUnlockArg; xUnlockNotify = p->xUnlockNotify; p->pUnlockConnection = 0; p->xUnlockNotify = 0; p->pUnlockArg = 0; } /* Step 3. */ if( p->pBlockingConnection==0 && p->pUnlockConnection==0 ){ /* Remove connection p from the blocked connections list. */ *pp = p->pNextBlocked; p->pNextBlocked = 0; }else{ pp = &p->pNextBlocked; } } if( nArg!=0 ){ xUnlockNotify(aArg, nArg); } sqlite3_free(aDyn); leaveMutex(); /* Leave STATIC_MAIN mutex */ } /* ** This is called when the database connection passed as an argument is ** being closed. The connection is removed from the blocked list. */ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){ sqlite3ConnectionUnlocked(db); enterMutex(); removeFromBlockedList(db); checkListProperties(db); leaveMutex(); } #endif /************** End of notify.c **********************************************/ /************** Begin file fts3.c ********************************************/ /* ** 2006 Oct 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This is an SQLite module implementing full-text search. */ /* ** The code in this file is only compiled if: ** ** * The FTS3 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ /* The full-text index is stored in a series of b+tree (-like) ** structures called segments which map terms to doclists. The ** structures are like b+trees in layout, but are constructed from the ** bottom up in optimal fashion and are not updatable. Since trees ** are built from the bottom up, things will be described from the ** bottom up. ** ** **** Varints **** ** The basic unit of encoding is a variable-length integer called a ** varint. We encode variable-length integers in little-endian order ** using seven bits * per byte as follows: ** ** KEY: ** A = 0xxxxxxx 7 bits of data and one flag bit ** B = 1xxxxxxx 7 bits of data and one flag bit ** ** 7 bits - A ** 14 bits - BA ** 21 bits - BBA ** and so on. ** ** This is similar in concept to how sqlite encodes "varints" but ** the encoding is not the same. SQLite varints are big-endian ** are are limited to 9 bytes in length whereas FTS3 varints are ** little-endian and can be up to 10 bytes in length (in theory). ** ** Example encodings: ** ** 1: 0x01 ** 127: 0x7f ** 128: 0x81 0x00 ** ** **** Document lists **** ** A doclist (document list) holds a docid-sorted list of hits for a ** given term. Doclists hold docids and associated token positions. ** A docid is the unique integer identifier for a single document. ** A position is the index of a word within the document. The first ** word of the document has a position of 0. ** ** FTS3 used to optionally store character offsets using a compile-time ** option. But that functionality is no longer supported. ** ** A doclist is stored like this: ** ** array { ** varint docid; (delta from previous doclist) ** array { (position list for column 0) ** varint position; (2 more than the delta from previous position) ** } ** array { ** varint POS_COLUMN; (marks start of position list for new column) ** varint column; (index of new column) ** array { ** varint position; (2 more than the delta from previous position) ** } ** } ** varint POS_END; (marks end of positions for this document. ** } ** ** Here, array { X } means zero or more occurrences of X, adjacent in ** memory. A "position" is an index of a token in the token stream ** generated by the tokenizer. Note that POS_END and POS_COLUMN occur ** in the same logical place as the position element, and act as sentinals ** ending a position list array. POS_END is 0. POS_COLUMN is 1. ** The positions numbers are not stored literally but rather as two more ** than the difference from the prior position, or the just the position plus ** 2 for the first position. Example: ** ** label: A B C D E F G H I J K ** value: 123 5 9 1 1 14 35 0 234 72 0 ** ** The 123 value is the first docid. For column zero in this document ** there are two matches at positions 3 and 10 (5-2 and 9-2+3). The 1 ** at D signals the start of a new column; the 1 at E indicates that the ** new column is column number 1. There are two positions at 12 and 45 ** (14-2 and 35-2+12). The 0 at H indicate the end-of-document. The ** 234 at I is the delta to next docid (357). It has one position 70 ** (72-2) and then terminates with the 0 at K. ** ** A "position-list" is the list of positions for multiple columns for ** a single docid. A "column-list" is the set of positions for a single ** column. Hence, a position-list consists of one or more column-lists, ** a document record consists of a docid followed by a position-list and ** a doclist consists of one or more document records. ** ** A bare doclist omits the position information, becoming an ** array of varint-encoded docids. ** **** Segment leaf nodes **** ** Segment leaf nodes store terms and doclists, ordered by term. Leaf ** nodes are written using LeafWriter, and read using LeafReader (to ** iterate through a single leaf node's data) and LeavesReader (to ** iterate through a segment's entire leaf layer). Leaf nodes have ** the format: ** ** varint iHeight; (height from leaf level, always 0) ** varint nTerm; (length of first term) ** char pTerm[nTerm]; (content of first term) ** varint nDoclist; (length of term's associated doclist) ** char pDoclist[nDoclist]; (content of doclist) ** array { ** (further terms are delta-encoded) ** varint nPrefix; (length of prefix shared with previous term) ** varint nSuffix; (length of unshared suffix) ** char pTermSuffix[nSuffix];(unshared suffix of next term) ** varint nDoclist; (length of term's associated doclist) ** char pDoclist[nDoclist]; (content of doclist) ** } ** ** Here, array { X } means zero or more occurrences of X, adjacent in ** memory. ** ** Leaf nodes are broken into blocks which are stored contiguously in ** the %_segments table in sorted order. This means that when the end ** of a node is reached, the next term is in the node with the next ** greater node id. ** ** New data is spilled to a new leaf node when the current node ** exceeds LEAF_MAX bytes (default 2048). New data which itself is ** larger than STANDALONE_MIN (default 1024) is placed in a standalone ** node (a leaf node with a single term and doclist). The goal of ** these settings is to pack together groups of small doclists while ** making it efficient to directly access large doclists. The ** assumption is that large doclists represent terms which are more ** likely to be query targets. ** ** TODO(shess) It may be useful for blocking decisions to be more ** dynamic. For instance, it may make more sense to have a 2.5k leaf ** node rather than splitting into 2k and .5k nodes. My intuition is ** that this might extend through 2x or 4x the pagesize. ** ** **** Segment interior nodes **** ** Segment interior nodes store blockids for subtree nodes and terms ** to describe what data is stored by the each subtree. Interior ** nodes are written using InteriorWriter, and read using ** InteriorReader. InteriorWriters are created as needed when ** SegmentWriter creates new leaf nodes, or when an interior node ** itself grows too big and must be split. The format of interior ** nodes: ** ** varint iHeight; (height from leaf level, always >0) ** varint iBlockid; (block id of node's leftmost subtree) ** optional { ** varint nTerm; (length of first term) ** char pTerm[nTerm]; (content of first term) ** array { ** (further terms are delta-encoded) ** varint nPrefix; (length of shared prefix with previous term) ** varint nSuffix; (length of unshared suffix) ** char pTermSuffix[nSuffix]; (unshared suffix of next term) ** } ** } ** ** Here, optional { X } means an optional element, while array { X } ** means zero or more occurrences of X, adjacent in memory. ** ** An interior node encodes n terms separating n+1 subtrees. The ** subtree blocks are contiguous, so only the first subtree's blockid ** is encoded. The subtree at iBlockid will contain all terms less ** than the first term encoded (or all terms if no term is encoded). ** Otherwise, for terms greater than or equal to pTerm[i] but less ** than pTerm[i+1], the subtree for that term will be rooted at ** iBlockid+i. Interior nodes only store enough term data to ** distinguish adjacent children (if the rightmost term of the left ** child is "something", and the leftmost term of the right child is ** "wicked", only "w" is stored). ** ** New data is spilled to a new interior node at the same height when ** the current node exceeds INTERIOR_MAX bytes (default 2048). ** INTERIOR_MIN_TERMS (default 7) keeps large terms from monopolizing ** interior nodes and making the tree too skinny. The interior nodes ** at a given height are naturally tracked by interior nodes at ** height+1, and so on. ** ** **** Segment directory **** ** The segment directory in table %_segdir stores meta-information for ** merging and deleting segments, and also the root node of the ** segment's tree. ** ** The root node is the top node of the segment's tree after encoding ** the entire segment, restricted to ROOT_MAX bytes (default 1024). ** This could be either a leaf node or an interior node. If the top ** node requires more than ROOT_MAX bytes, it is flushed to %_segments ** and a new root interior node is generated (which should always fit ** within ROOT_MAX because it only needs space for 2 varints, the ** height and the blockid of the previous root). ** ** The meta-information in the segment directory is: ** level - segment level (see below) ** idx - index within level ** - (level,idx uniquely identify a segment) ** start_block - first leaf node ** leaves_end_block - last leaf node ** end_block - last block (including interior nodes) ** root - contents of root node ** ** If the root node is a leaf node, then start_block, ** leaves_end_block, and end_block are all 0. ** ** **** Segment merging **** ** To amortize update costs, segments are grouped into levels and ** merged in batches. Each increase in level represents exponentially ** more documents. ** ** New documents (actually, document updates) are tokenized and ** written individually (using LeafWriter) to a level 0 segment, with ** incrementing idx. When idx reaches MERGE_COUNT (default 16), all ** level 0 segments are merged into a single level 1 segment. Level 1 ** is populated like level 0, and eventually MERGE_COUNT level 1 ** segments are merged to a single level 2 segment (representing ** MERGE_COUNT^2 updates), and so on. ** ** A segment merge traverses all segments at a given level in ** parallel, performing a straightforward sorted merge. Since segment ** leaf nodes are written in to the %_segments table in order, this ** merge traverses the underlying sqlite disk structures efficiently. ** After the merge, all segment blocks from the merged level are ** deleted. ** ** MERGE_COUNT controls how often we merge segments. 16 seems to be ** somewhat of a sweet spot for insertion performance. 32 and 64 show ** very similar performance numbers to 16 on insertion, though they're ** a tiny bit slower (perhaps due to more overhead in merge-time ** sorting). 8 is about 20% slower than 16, 4 about 50% slower than ** 16, 2 about 66% slower than 16. ** ** At query time, high MERGE_COUNT increases the number of segments ** which need to be scanned and merged. For instance, with 100k docs ** inserted: ** ** MERGE_COUNT segments ** 16 25 ** 8 12 ** 4 10 ** 2 6 ** ** This appears to have only a moderate impact on queries for very ** frequent terms (which are somewhat dominated by segment merge ** costs), and infrequent and non-existent terms still seem to be fast ** even with many segments. ** ** TODO(shess) That said, it would be nice to have a better query-side ** argument for MERGE_COUNT of 16. Also, it is possible/likely that ** optimizations to things like doclist merging will swing the sweet ** spot around. ** ** ** **** Handling of deletions and updates **** ** Since we're using a segmented structure, with no docid-oriented ** index into the term index, we clearly cannot simply update the term ** index when a document is deleted or updated. For deletions, we ** write an empty doclist (varint(docid) varint(POS_END)), for updates ** we simply write the new doclist. Segment merges overwrite older ** data for a particular docid with newer data, so deletes or updates ** will eventually overtake the earlier data and knock it out. The ** query logic likewise merges doclists so that newer data knocks out ** older data. */ /************** Include fts3Int.h in the middle of fts3.c ********************/ /************** Begin file fts3Int.h *****************************************/ /* ** 2009 Nov 12 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** */ #ifndef _FTSINT_H #define _FTSINT_H #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif /* FTS3/FTS4 require virtual tables */ #ifdef SQLITE_OMIT_VIRTUALTABLE # undef SQLITE_ENABLE_FTS3 # undef SQLITE_ENABLE_FTS4 #endif /* ** FTS4 is really an extension for FTS3. It is enabled using the ** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all ** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3. */ #if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3) # define SQLITE_ENABLE_FTS3 #endif #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* If not building as part of the core, include sqlite3ext.h. */ #ifndef SQLITE_CORE /* # include "sqlite3ext.h" */ SQLITE_EXTENSION_INIT3 #endif /* #include "sqlite3.h" */ /************** Include fts3_tokenizer.h in the middle of fts3Int.h **********/ /************** Begin file fts3_tokenizer.h **********************************/ /* ** 2006 July 10 ** ** The author disclaims copyright to this source code. ** ************************************************************************* ** Defines the interface to tokenizers used by fulltext-search. There ** are three basic components: ** ** sqlite3_tokenizer_module is a singleton defining the tokenizer ** interface functions. This is essentially the class structure for ** tokenizers. ** ** sqlite3_tokenizer is used to define a particular tokenizer, perhaps ** including customization information defined at creation time. ** ** sqlite3_tokenizer_cursor is generated by a tokenizer to generate ** tokens from a particular input. */ #ifndef _FTS3_TOKENIZER_H_ #define _FTS3_TOKENIZER_H_ /* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. ** If tokenizers are to be allowed to call sqlite3_*() functions, then ** we will need a way to register the API consistently. */ /* #include "sqlite3.h" */ /* ** Structures used by the tokenizer interface. When a new tokenizer ** implementation is registered, the caller provides a pointer to ** an sqlite3_tokenizer_module containing pointers to the callback ** functions that make up an implementation. ** ** When an fts3 table is created, it passes any arguments passed to ** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the ** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer ** implementation. The xCreate() function in turn returns an ** sqlite3_tokenizer structure representing the specific tokenizer to ** be used for the fts3 table (customized by the tokenizer clause arguments). ** ** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() ** method is called. It returns an sqlite3_tokenizer_cursor object ** that may be used to tokenize a specific input buffer based on ** the tokenization rules supplied by a specific sqlite3_tokenizer ** object. */ typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; typedef struct sqlite3_tokenizer sqlite3_tokenizer; typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; struct sqlite3_tokenizer_module { /* ** Structure version. Should always be set to 0 or 1. */ int iVersion; /* ** Create a new tokenizer. The values in the argv[] array are the ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL ** TABLE statement that created the fts3 table. For example, if ** the following SQL is executed: ** ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) ** ** then argc is set to 2, and the argv[] array contains pointers ** to the strings "arg1" and "arg2". ** ** This method should return either SQLITE_OK (0), or an SQLite error ** code. If SQLITE_OK is returned, then *ppTokenizer should be set ** to point at the newly created tokenizer structure. The generic ** sqlite3_tokenizer.pModule variable should not be initialized by ** this callback. The caller will do so. */ int (*xCreate)( int argc, /* Size of argv array */ const char *const*argv, /* Tokenizer argument strings */ sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ ); /* ** Destroy an existing tokenizer. The fts3 module calls this method ** exactly once for each successful call to xCreate(). */ int (*xDestroy)(sqlite3_tokenizer *pTokenizer); /* ** Create a tokenizer cursor to tokenize an input buffer. The caller ** is responsible for ensuring that the input buffer remains valid ** until the cursor is closed (using the xClose() method). */ int (*xOpen)( sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ const char *pInput, int nBytes, /* Input buffer */ sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ ); /* ** Destroy an existing tokenizer cursor. The fts3 module calls this ** method exactly once for each successful call to xOpen(). */ int (*xClose)(sqlite3_tokenizer_cursor *pCursor); /* ** Retrieve the next token from the tokenizer cursor pCursor. This ** method should either return SQLITE_OK and set the values of the ** "OUT" variables identified below, or SQLITE_DONE to indicate that ** the end of the buffer has been reached, or an SQLite error code. ** ** *ppToken should be set to point at a buffer containing the ** normalized version of the token (i.e. after any case-folding and/or ** stemming has been performed). *pnBytes should be set to the length ** of this buffer in bytes. The input text that generated the token is ** identified by the byte offsets returned in *piStartOffset and ** *piEndOffset. *piStartOffset should be set to the index of the first ** byte of the token in the input buffer. *piEndOffset should be set ** to the index of the first byte just past the end of the token in ** the input buffer. ** ** The buffer *ppToken is set to point at is managed by the tokenizer ** implementation. It is only required to be valid until the next call ** to xNext() or xClose(). */ /* TODO(shess) current implementation requires pInput to be ** nul-terminated. This should either be fixed, or pInput/nBytes ** should be converted to zInput. */ int (*xNext)( sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ int *piStartOffset, /* OUT: Byte offset of token in input buffer */ int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ int *piPosition /* OUT: Number of tokens returned before this one */ ); /*********************************************************************** ** Methods below this point are only available if iVersion>=1. */ /* ** Configure the language id of a tokenizer cursor. */ int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); }; struct sqlite3_tokenizer { const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ /* Tokenizer implementations will typically add additional fields */ }; struct sqlite3_tokenizer_cursor { sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ /* Tokenizer implementations will typically add additional fields */ }; int fts3_global_term_cnt(int iTerm, int iCol); int fts3_term_cnt(int iTerm, int iCol); #endif /* _FTS3_TOKENIZER_H_ */ /************** End of fts3_tokenizer.h **************************************/ /************** Continuing where we left off in fts3Int.h ********************/ /************** Include fts3_hash.h in the middle of fts3Int.h ***************/ /************** Begin file fts3_hash.h ***************************************/ /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the header file for the generic hash-table implementation ** used in SQLite. We've modified it slightly to serve as a standalone ** hash table implementation for the full-text indexing module. ** */ #ifndef _FTS3_HASH_H_ #define _FTS3_HASH_H_ /* Forward declarations of structures. */ typedef struct Fts3Hash Fts3Hash; typedef struct Fts3HashElem Fts3HashElem; /* A complete hash table is an instance of the following structure. ** The internals of this structure are intended to be opaque -- client ** code should not attempt to access or modify the fields of this structure ** directly. Change this structure only by using the routines below. ** However, many of the "procedures" and "functions" for modifying and ** accessing this structure are really macros, so we can't really make ** this structure opaque. */ struct Fts3Hash { char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */ char copyKey; /* True if copy of key made on insert */ int count; /* Number of entries in this table */ Fts3HashElem *first; /* The first element of the array */ int htsize; /* Number of buckets in the hash table */ struct _fts3ht { /* the hash table */ int count; /* Number of entries with this hash */ Fts3HashElem *chain; /* Pointer to first entry with this hash */ } *ht; }; /* Each element in the hash table is an instance of the following ** structure. All elements are stored on a single doubly-linked list. ** ** Again, this structure is intended to be opaque, but it can't really ** be opaque because it is used by macros. */ struct Fts3HashElem { Fts3HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ void *pKey; int nKey; /* Key associated with this element */ }; /* ** There are 2 different modes of operation for a hash table: ** ** FTS3_HASH_STRING pKey points to a string that is nKey bytes long ** (including the null-terminator, if any). Case ** is respected in comparisons. ** ** FTS3_HASH_BINARY pKey points to binary data nKey bytes long. ** memcmp() is used to compare keys. ** ** A copy of the key is made if the copyKey parameter to fts3HashInit is 1. */ #define FTS3_HASH_STRING 1 #define FTS3_HASH_BINARY 2 /* ** Access routines. To delete, insert a NULL pointer. */ SQLITE_PRIVATE void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey); SQLITE_PRIVATE void *sqlite3Fts3HashInsert(Fts3Hash*, const void *pKey, int nKey, void *pData); SQLITE_PRIVATE void *sqlite3Fts3HashFind(const Fts3Hash*, const void *pKey, int nKey); SQLITE_PRIVATE void sqlite3Fts3HashClear(Fts3Hash*); SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const void *, int); /* ** Shorthand for the functions above */ #define fts3HashInit sqlite3Fts3HashInit #define fts3HashInsert sqlite3Fts3HashInsert #define fts3HashFind sqlite3Fts3HashFind #define fts3HashClear sqlite3Fts3HashClear #define fts3HashFindElem sqlite3Fts3HashFindElem /* ** Macros for looping over all elements of a hash table. The idiom is ** like this: ** ** Fts3Hash h; ** Fts3HashElem *p; ** ... ** for(p=fts3HashFirst(&h); p; p=fts3HashNext(p)){ ** SomeStructure *pData = fts3HashData(p); ** // do something with pData ** } */ #define fts3HashFirst(H) ((H)->first) #define fts3HashNext(E) ((E)->next) #define fts3HashData(E) ((E)->data) #define fts3HashKey(E) ((E)->pKey) #define fts3HashKeysize(E) ((E)->nKey) /* ** Number of entries in a hash table */ #define fts3HashCount(H) ((H)->count) #endif /* _FTS3_HASH_H_ */ /************** End of fts3_hash.h *******************************************/ /************** Continuing where we left off in fts3Int.h ********************/ /* ** This constant determines the maximum depth of an FTS expression tree ** that the library will create and use. FTS uses recursion to perform ** various operations on the query tree, so the disadvantage of a large ** limit is that it may allow very large queries to use large amounts ** of stack space (perhaps causing a stack overflow). */ #ifndef SQLITE_FTS3_MAX_EXPR_DEPTH # define SQLITE_FTS3_MAX_EXPR_DEPTH 12 #endif /* ** This constant controls how often segments are merged. Once there are ** FTS3_MERGE_COUNT segments of level N, they are merged into a single ** segment of level N+1. */ #define FTS3_MERGE_COUNT 16 /* ** This is the maximum amount of data (in bytes) to store in the ** Fts3Table.pendingTerms hash table. Normally, the hash table is ** populated as documents are inserted/updated/deleted in a transaction ** and used to create a new segment when the transaction is committed. ** However if this limit is reached midway through a transaction, a new ** segment is created and the hash table cleared immediately. */ #define FTS3_MAX_PENDING_DATA (1*1024*1024) /* ** Macro to return the number of elements in an array. SQLite has a ** similar macro called ArraySize(). Use a different name to avoid ** a collision when building an amalgamation with built-in FTS3. */ #define SizeofArray(X) ((int)(sizeof(X)/sizeof(X[0]))) #ifndef MIN # define MIN(x,y) ((x)<(y)?(x):(y)) #endif #ifndef MAX # define MAX(x,y) ((x)>(y)?(x):(y)) #endif /* ** Maximum length of a varint encoded integer. The varint format is different ** from that used by SQLite, so the maximum length is 10, not 9. */ #define FTS3_VARINT_MAX 10 #define FTS3_BUFFER_PADDING 8 /* ** FTS4 virtual tables may maintain multiple indexes - one index of all terms ** in the document set and zero or more prefix indexes. All indexes are stored ** as one or more b+-trees in the %_segments and %_segdir tables. ** ** It is possible to determine which index a b+-tree belongs to based on the ** value stored in the "%_segdir.level" column. Given this value L, the index ** that the b+-tree belongs to is (L<<10). In other words, all b+-trees with ** level values between 0 and 1023 (inclusive) belong to index 0, all levels ** between 1024 and 2047 to index 1, and so on. ** ** It is considered impossible for an index to use more than 1024 levels. In ** theory though this may happen, but only after at least ** (FTS3_MERGE_COUNT^1024) separate flushes of the pending-terms tables. */ #define FTS3_SEGDIR_MAXLEVEL 1024 #define FTS3_SEGDIR_MAXLEVEL_STR "1024" /* ** The testcase() macro is only used by the amalgamation. If undefined, ** make it a no-op. */ #ifndef testcase # define testcase(X) #endif /* ** Terminator values for position-lists and column-lists. */ #define POS_COLUMN (1) /* Column-list terminator */ #define POS_END (0) /* Position-list terminator */ /* ** The assert_fts3_nc() macro is similar to the assert() macro, except that it ** is used for assert() conditions that are true only if it can be ** guranteed that the database is not corrupt. */ #ifdef SQLITE_DEBUG SQLITE_API extern int sqlite3_fts3_may_be_corrupt; # define assert_fts3_nc(x) assert(sqlite3_fts3_may_be_corrupt || (x)) #else # define assert_fts3_nc(x) assert(x) #endif /* ** This section provides definitions to allow the ** FTS3 extension to be compiled outside of the ** amalgamation. */ #ifndef SQLITE_AMALGAMATION /* ** Macros indicating that conditional expressions are always true or ** false. */ #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 #endif #if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) # define NEVER(X) (X) #endif /* ** Internal types used by SQLite. */ typedef unsigned char u8; /* 1-byte (or larger) unsigned integer */ typedef short int i16; /* 2-byte (or larger) signed integer */ typedef unsigned int u32; /* 4-byte unsigned integer */ typedef sqlite3_uint64 u64; /* 8-byte unsigned integer */ typedef sqlite3_int64 i64; /* 8-byte signed integer */ /* ** Macro used to suppress compiler warnings for unused parameters. */ #define UNUSED_PARAMETER(x) (void)(x) /* ** Activate assert() only if SQLITE_TEST is enabled. */ #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif /* ** The TESTONLY macro is used to enclose variable declarations or ** other bits of code that are needed to support the arguments ** within testcase() and assert() macros. */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) # define TESTONLY(X) X #else # define TESTONLY(X) #endif #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) #define deliberate_fall_through #endif /* SQLITE_AMALGAMATION */ #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3Fts3Corrupt(void); # define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt() #else # define FTS_CORRUPT_VTAB SQLITE_CORRUPT_VTAB #endif typedef struct Fts3Table Fts3Table; typedef struct Fts3Cursor Fts3Cursor; typedef struct Fts3Expr Fts3Expr; typedef struct Fts3Phrase Fts3Phrase; typedef struct Fts3PhraseToken Fts3PhraseToken; typedef struct Fts3Doclist Fts3Doclist; typedef struct Fts3SegFilter Fts3SegFilter; typedef struct Fts3DeferredToken Fts3DeferredToken; typedef struct Fts3SegReader Fts3SegReader; typedef struct Fts3MultiSegReader Fts3MultiSegReader; typedef struct MatchinfoBuffer MatchinfoBuffer; /* ** A connection to a fulltext index is an instance of the following ** structure. The xCreate and xConnect methods create an instance ** of this structure and xDestroy and xDisconnect free that instance. ** All other methods receive a pointer to the structure as one of their ** arguments. */ struct Fts3Table { sqlite3_vtab base; /* Base class used by SQLite core */ sqlite3 *db; /* The database connection */ const char *zDb; /* logical database name */ const char *zName; /* virtual table name */ int nColumn; /* number of named columns in virtual table */ char **azColumn; /* column names. malloced */ u8 *abNotindexed; /* True for 'notindexed' columns */ sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ char *zContentTbl; /* content=xxx option, or NULL */ char *zLanguageid; /* languageid=xxx option, or NULL */ int nAutoincrmerge; /* Value configured by 'automerge' */ u32 nLeafAdd; /* Number of leaf blocks added this trans */ int bLock; /* Used to prevent recursive content= tbls */ /* Precompiled statements used by the implementation. Each of these ** statements is run and reset within a single virtual table API call. */ sqlite3_stmt *aStmt[40]; sqlite3_stmt *pSeekStmt; /* Cache for fts3CursorSeekStmt() */ char *zReadExprlist; char *zWriteExprlist; int nNodeSize; /* Soft limit for node size */ u8 bFts4; /* True for FTS4, false for FTS3 */ u8 bHasStat; /* True if %_stat table exists (2==unknown) */ u8 bHasDocsize; /* True if %_docsize table exists */ u8 bDescIdx; /* True if doclists are in reverse order */ u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */ int nPgsz; /* Page size for host database */ char *zSegmentsTbl; /* Name of %_segments table */ sqlite3_blob *pSegments; /* Blob handle open on %_segments table */ int iSavepoint; /* ** The following array of hash tables is used to buffer pending index ** updates during transactions. All pending updates buffered at any one ** time must share a common language-id (see the FTS4 langid= feature). ** The current language id is stored in variable iPrevLangid. ** ** A single FTS4 table may have multiple full-text indexes. For each index ** there is an entry in the aIndex[] array. Index 0 is an index of all the ** terms that appear in the document set. Each subsequent index in aIndex[] ** is an index of prefixes of a specific length. ** ** Variable nPendingData contains an estimate the memory consumed by the ** pending data structures, including hash table overhead, but not including ** malloc overhead. When nPendingData exceeds nMaxPendingData, all hash ** tables are flushed to disk. Variable iPrevDocid is the docid of the most ** recently inserted record. */ int nIndex; /* Size of aIndex[] */ struct Fts3Index { int nPrefix; /* Prefix length (0 for main terms index) */ Fts3Hash hPending; /* Pending terms table for this index */ } *aIndex; int nMaxPendingData; /* Max pending data before flush to disk */ int nPendingData; /* Current bytes of pending data */ sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ int iPrevLangid; /* Langid of recently inserted document */ int bPrevDelete; /* True if last operation was a delete */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) /* State variables used for validating that the transaction control ** methods of the virtual table are called at appropriate times. These ** values do not contribute to FTS functionality; they are used for ** verifying the operation of the SQLite core. */ int inTransaction; /* True after xBegin but before xCommit/xRollback */ int mxSavepoint; /* Largest valid xSavepoint integer */ #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* True to disable the incremental doclist optimization. This is controled ** by special insert command 'test-no-incr-doclist'. */ int bNoIncrDoclist; /* Number of segments in a level */ int nMergeCount; #endif }; /* Macro to find the number of segments to merge */ #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) # define MergeCount(P) ((P)->nMergeCount) #else # define MergeCount(P) FTS3_MERGE_COUNT #endif /* ** When the core wants to read from the virtual table, it creates a ** virtual table cursor (an instance of the following structure) using ** the xOpen method. Cursors are destroyed using the xClose method. */ struct Fts3Cursor { sqlite3_vtab_cursor base; /* Base class used by SQLite core */ i16 eSearch; /* Search strategy (see below) */ u8 isEof; /* True if at End Of Results */ u8 isRequireSeek; /* True if must seek pStmt to %_content row */ u8 bSeekStmt; /* True if pStmt is a seek */ sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */ Fts3Expr *pExpr; /* Parsed MATCH query string */ int iLangid; /* Language being queried for */ int nPhrase; /* Number of matchable phrases in query */ Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */ sqlite3_int64 iPrevId; /* Previous id read from aDoclist */ char *pNextId; /* Pointer into the body of aDoclist */ char *aDoclist; /* List of docids for full-text queries */ int nDoclist; /* Size of buffer at aDoclist */ u8 bDesc; /* True to sort in descending order */ int eEvalmode; /* An FTS3_EVAL_XX constant */ int nRowAvg; /* Average size of database rows, in pages */ sqlite3_int64 nDoc; /* Documents in table */ i64 iMinDocid; /* Minimum docid to return */ i64 iMaxDocid; /* Maximum docid to return */ int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */ MatchinfoBuffer *pMIBuffer; /* Buffer for matchinfo data */ }; #define FTS3_EVAL_FILTER 0 #define FTS3_EVAL_NEXT 1 #define FTS3_EVAL_MATCHINFO 2 /* ** The Fts3Cursor.eSearch member is always set to one of the following. ** Actualy, Fts3Cursor.eSearch can be greater than or equal to ** FTS3_FULLTEXT_SEARCH. If so, then Fts3Cursor.eSearch - 2 is the index ** of the column to be searched. For example, in ** ** CREATE VIRTUAL TABLE ex1 USING fts3(a,b,c,d); ** SELECT docid FROM ex1 WHERE b MATCH 'one two three'; ** ** Because the LHS of the MATCH operator is 2nd column "b", ** Fts3Cursor.eSearch will be set to FTS3_FULLTEXT_SEARCH+1. (+0 for a, ** +1 for b, +2 for c, +3 for d.) If the LHS of MATCH were "ex1" ** indicating that all columns should be searched, ** then eSearch would be set to FTS3_FULLTEXT_SEARCH+4. */ #define FTS3_FULLSCAN_SEARCH 0 /* Linear scan of %_content table */ #define FTS3_DOCID_SEARCH 1 /* Lookup by rowid on %_content table */ #define FTS3_FULLTEXT_SEARCH 2 /* Full-text index search */ /* ** The lower 16-bits of the sqlite3_index_info.idxNum value set by ** the xBestIndex() method contains the Fts3Cursor.eSearch value described ** above. The upper 16-bits contain a combination of the following ** bits, used to describe extra constraints on full-text searches. */ #define FTS3_HAVE_LANGID 0x00010000 /* languageid=? */ #define FTS3_HAVE_DOCID_GE 0x00020000 /* docid>=? */ #define FTS3_HAVE_DOCID_LE 0x00040000 /* docid<=? */ struct Fts3Doclist { char *aAll; /* Array containing doclist (or NULL) */ int nAll; /* Size of a[] in bytes */ char *pNextDocid; /* Pointer to next docid */ sqlite3_int64 iDocid; /* Current docid (if pList!=0) */ int bFreeList; /* True if pList should be sqlite3_free()d */ char *pList; /* Pointer to position list following iDocid */ int nList; /* Length of position list */ }; /* ** A "phrase" is a sequence of one or more tokens that must match in ** sequence. A single token is the base case and the most common case. ** For a sequence of tokens contained in double-quotes (i.e. "one two three") ** nToken will be the number of tokens in the string. */ struct Fts3PhraseToken { char *z; /* Text of the token */ int n; /* Number of bytes in buffer z */ int isPrefix; /* True if token ends with a "*" character */ int bFirst; /* True if token must appear at position 0 */ /* Variables above this point are populated when the expression is ** parsed (by code in fts3_expr.c). Below this point the variables are ** used when evaluating the expression. */ Fts3DeferredToken *pDeferred; /* Deferred token object for this token */ Fts3MultiSegReader *pSegcsr; /* Segment-reader for this token */ }; struct Fts3Phrase { /* Cache of doclist for this phrase. */ Fts3Doclist doclist; int bIncr; /* True if doclist is loaded incrementally */ int iDoclistToken; /* Used by sqlite3Fts3EvalPhrasePoslist() if this is a descendent of an ** OR condition. */ char *pOrPoslist; i64 iOrDocid; /* Variables below this point are populated by fts3_expr.c when parsing ** a MATCH expression. Everything above is part of the evaluation phase. */ int nToken; /* Number of tokens in the phrase */ int iColumn; /* Index of column this phrase must match */ Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */ }; /* ** A tree of these objects forms the RHS of a MATCH operator. ** ** If Fts3Expr.eType is FTSQUERY_PHRASE and isLoaded is true, then aDoclist ** points to a malloced buffer, size nDoclist bytes, containing the results ** of this phrase query in FTS3 doclist format. As usual, the initial ** "Length" field found in doclists stored on disk is omitted from this ** buffer. ** ** Variable aMI is used only for FTSQUERY_NEAR nodes to store the global ** matchinfo data. If it is not NULL, it points to an array of size nCol*3, ** where nCol is the number of columns in the queried FTS table. The array ** is populated as follows: ** ** aMI[iCol*3 + 0] = Undefined ** aMI[iCol*3 + 1] = Number of occurrences ** aMI[iCol*3 + 2] = Number of rows containing at least one instance ** ** The aMI array is allocated using sqlite3_malloc(). It should be freed ** when the expression node is. */ struct Fts3Expr { int eType; /* One of the FTSQUERY_XXX values defined below */ int nNear; /* Valid if eType==FTSQUERY_NEAR */ Fts3Expr *pParent; /* pParent->pLeft==this or pParent->pRight==this */ Fts3Expr *pLeft; /* Left operand */ Fts3Expr *pRight; /* Right operand */ Fts3Phrase *pPhrase; /* Valid if eType==FTSQUERY_PHRASE */ /* The following are used by the fts3_eval.c module. */ sqlite3_int64 iDocid; /* Current docid */ u8 bEof; /* True this expression is at EOF already */ u8 bStart; /* True if iDocid is valid */ u8 bDeferred; /* True if this expression is entirely deferred */ /* The following are used by the fts3_snippet.c module. */ int iPhrase; /* Index of this phrase in matchinfo() results */ u32 *aMI; /* See above */ }; /* ** Candidate values for Fts3Query.eType. Note that the order of the first ** four values is in order of precedence when parsing expressions. For ** example, the following: ** ** "a OR b AND c NOT d NEAR e" ** ** is equivalent to: ** ** "a OR (b AND (c NOT (d NEAR e)))" */ #define FTSQUERY_NEAR 1 #define FTSQUERY_NOT 2 #define FTSQUERY_AND 3 #define FTSQUERY_OR 4 #define FTSQUERY_PHRASE 5 /* fts3_write.c */ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*); SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *); SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *); SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *); SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(int, int, sqlite3_int64, sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**); SQLITE_PRIVATE int sqlite3Fts3SegReaderPending( Fts3Table*,int,const char*,int,int,Fts3SegReader**); SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *); SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, int, int, int, sqlite3_stmt **); SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*, int*); SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **); SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **); #ifndef SQLITE_DISABLE_FTS4_DEFERRED SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *); SQLITE_PRIVATE int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int); SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *); SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *); SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(Fts3DeferredToken *, char **, int *); #else # define sqlite3Fts3FreeDeferredTokens(x) # define sqlite3Fts3DeferToken(x,y,z) SQLITE_OK # define sqlite3Fts3CacheDeferredDoclists(x) SQLITE_OK # define sqlite3Fts3FreeDeferredDoclists(x) # define sqlite3Fts3DeferredTokenList(x,y,z) SQLITE_OK #endif SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *); SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *, int *); /* Special values interpreted by sqlite3SegReaderCursor() */ #define FTS3_SEGCURSOR_PENDING -1 #define FTS3_SEGCURSOR_ALL -2 SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3MultiSegReader*, Fts3SegFilter*); SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3MultiSegReader *); SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(Fts3MultiSegReader *); SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(Fts3Table *, int, int, int, const char *, int, int, int, Fts3MultiSegReader *); /* Flags allowed as part of the 4th argument to SegmentReaderIterate() */ #define FTS3_SEGMENT_REQUIRE_POS 0x00000001 #define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002 #define FTS3_SEGMENT_COLUMN_FILTER 0x00000004 #define FTS3_SEGMENT_PREFIX 0x00000008 #define FTS3_SEGMENT_SCAN 0x00000010 #define FTS3_SEGMENT_FIRST 0x00000020 /* Type passed as 4th argument to SegmentReaderIterate() */ struct Fts3SegFilter { const char *zTerm; int nTerm; int iCol; int flags; }; struct Fts3MultiSegReader { /* Used internally by sqlite3Fts3SegReaderXXX() calls */ Fts3SegReader **apSegment; /* Array of Fts3SegReader objects */ int nSegment; /* Size of apSegment array */ int nAdvance; /* How many seg-readers to advance */ Fts3SegFilter *pFilter; /* Pointer to filter object */ char *aBuffer; /* Buffer to merge doclists in */ i64 nBuffer; /* Allocated size of aBuffer[] in bytes */ int iColFilter; /* If >=0, filter for this column */ int bRestart; /* Used by fts3.c only. */ int nCost; /* Cost of running iterator */ int bLookup; /* True if a lookup of a single entry. */ /* Output values. Valid only after Fts3SegReaderStep() returns SQLITE_ROW. */ char *zTerm; /* Pointer to term buffer */ int nTerm; /* Size of zTerm in bytes */ char *aDoclist; /* Pointer to doclist buffer */ int nDoclist; /* Size of aDoclist[] in bytes */ }; SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table*,int,int); #define fts3GetVarint32(p, piVal) ( \ (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \ ) /* fts3.c */ SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char**,const char*,...); SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64); SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); SQLITE_PRIVATE int sqlite3Fts3GetVarintU(const char *, sqlite_uint64 *); SQLITE_PRIVATE int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*); SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *); SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64); SQLITE_PRIVATE void sqlite3Fts3Dequote(char *); SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *); SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*); SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc); SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut); /* fts3_tokenizer.c */ SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *); SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *); SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *, sqlite3_tokenizer **, char ** ); SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char); /* fts3_snippet.c */ SQLITE_PRIVATE void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*); SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *, const char *, const char *, int, int ); SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p); /* fts3_expr.c */ SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, char **, int, int, int, const char *, int, Fts3Expr **, char ** ); SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); #ifdef SQLITE_TEST SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash*); SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); #endif SQLITE_PRIVATE void *sqlite3Fts3MallocZero(i64 nByte); SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int, sqlite3_tokenizer_cursor ** ); /* fts3_aux.c */ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db); SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *); SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart( Fts3Table*, Fts3MultiSegReader*, int, const char*, int); SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *); SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **); SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); /* fts3_tokenize_vtab.c */ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *, void(*xDestroy)(void*)); /* fts3_unicode2.c (functions generated by parsing unicode text files) */ #ifndef SQLITE_DISABLE_FTS3_UNICODE SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int, int); SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int); SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int); #endif SQLITE_PRIVATE int sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*); SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk); #endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ #endif /* _FTSINT_H */ /************** End of fts3Int.h *********************************************/ /************** Continuing where we left off in fts3.c ***********************/ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_CORE) # define SQLITE_CORE 1 #endif /* #include */ /* #include */ /* #include */ /* #include */ /* #include */ /* #include */ /* #include "fts3.h" */ #ifndef SQLITE_CORE /* # include "sqlite3ext.h" */ SQLITE_EXTENSION_INIT1 #endif typedef struct Fts3HashWrapper Fts3HashWrapper; struct Fts3HashWrapper { Fts3Hash hash; /* Hash table */ int nRef; /* Number of pointers to this object */ }; static int fts3EvalNext(Fts3Cursor *pCsr); static int fts3EvalStart(Fts3Cursor *pCsr); static int fts3TermSegReaderCursor( Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); /* ** This variable is set to false when running tests for which the on disk ** structures should not be corrupt. Otherwise, true. If it is false, extra ** assert() conditions in the fts3 code are activated - conditions that are ** only true if it is guaranteed that the fts3 database is not corrupt. */ #ifdef SQLITE_DEBUG SQLITE_API int sqlite3_fts3_may_be_corrupt = 1; #endif /* ** Write a 64-bit variable-length integer to memory starting at p[0]. ** The length of data written will be between 1 and FTS3_VARINT_MAX bytes. ** The number of bytes written is returned. */ SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){ unsigned char *q = (unsigned char *) p; sqlite_uint64 vu = v; do{ *q++ = (unsigned char) ((vu & 0x7f) | 0x80); vu >>= 7; }while( vu!=0 ); q[-1] &= 0x7f; /* turn off high bit in final byte */ assert( q - (unsigned char *)p <= FTS3_VARINT_MAX ); return (int) (q - (unsigned char *)p); } #define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \ v = (v & mask1) | ( (*(const unsigned char*)(ptr++)) << shift ); \ if( (v & mask2)==0 ){ var = v; return ret; } #define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \ v = (*ptr++); \ if( (v & mask2)==0 ){ var = v; return ret; } SQLITE_PRIVATE int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){ const unsigned char *p = (const unsigned char*)pBuf; const unsigned char *pStart = p; u32 a; u64 b; int shift; GETVARINT_INIT(a, p, 0, 0x00, 0x80, *v, 1); GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *v, 2); GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *v, 3); GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *v, 4); b = (a & 0x0FFFFFFF ); for(shift=28; shift<=63; shift+=7){ u64 c = *p++; b += (c&0x7F) << shift; if( (c & 0x80)==0 ) break; } *v = b; return (int)(p - pStart); } /* ** Read a 64-bit variable-length integer from memory starting at p[0]. ** Return the number of bytes read, or 0 on error. ** The value is stored in *v. */ SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){ return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v); } /* ** Read a 64-bit variable-length integer from memory starting at p[0] and ** not extending past pEnd[-1]. ** Return the number of bytes read, or 0 on error. ** The value is stored in *v. */ SQLITE_PRIVATE int sqlite3Fts3GetVarintBounded( const char *pBuf, const char *pEnd, sqlite_int64 *v ){ const unsigned char *p = (const unsigned char*)pBuf; const unsigned char *pStart = p; const unsigned char *pX = (const unsigned char*)pEnd; u64 b = 0; int shift; for(shift=0; shift<=63; shift+=7){ u64 c = p=0 ); return 5; } /* ** Return the number of bytes required to encode v as a varint */ SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64 v){ int i = 0; do{ i++; v >>= 7; }while( v!=0 ); return i; } /* ** Convert an SQL-style quoted string into a normal string by removing ** the quote characters. The conversion is done in-place. If the ** input does not begin with a quote character, then this routine ** is a no-op. ** ** Examples: ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno ** */ SQLITE_PRIVATE void sqlite3Fts3Dequote(char *z){ char quote; /* Quote character (if any ) */ quote = z[0]; if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ int iIn = 1; /* Index of next byte to read from input */ int iOut = 0; /* Index of next byte to write to output */ /* If the first byte was a '[', then the close-quote character is a ']' */ if( quote=='[' ) quote = ']'; while( z[iIn] ){ if( z[iIn]==quote ){ if( z[iIn+1]!=quote ) break; z[iOut++] = quote; iIn += 2; }else{ z[iOut++] = z[iIn++]; } } z[iOut] = '\0'; } } /* ** Read a single varint from the doclist at *pp and advance *pp to point ** to the first byte past the end of the varint. Add the value of the varint ** to *pVal. */ static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){ sqlite3_int64 iVal; *pp += sqlite3Fts3GetVarint(*pp, &iVal); *pVal += iVal; } /* ** When this function is called, *pp points to the first byte following a ** varint that is part of a doclist (or position-list, or any other list ** of varints). This function moves *pp to point to the start of that varint, ** and sets *pVal by the varint value. ** ** Argument pStart points to the first byte of the doclist that the ** varint is part of. */ static void fts3GetReverseVarint( char **pp, char *pStart, sqlite3_int64 *pVal ){ sqlite3_int64 iVal; char *p; /* Pointer p now points at the first byte past the varint we are ** interested in. So, unless the doclist is corrupt, the 0x80 bit is ** clear on character p[-1]. */ for(p = (*pp)-2; p>=pStart && *p&0x80; p--); p++; *pp = p; sqlite3Fts3GetVarint(p, &iVal); *pVal = iVal; } /* ** The xDisconnect() virtual table method. */ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table *)pVtab; int i; assert( p->nPendingData==0 ); assert( p->pSegments==0 ); /* Free any prepared statements held */ sqlite3_finalize(p->pSeekStmt); for(i=0; iaStmt); i++){ sqlite3_finalize(p->aStmt[i]); } sqlite3_free(p->zSegmentsTbl); sqlite3_free(p->zReadExprlist); sqlite3_free(p->zWriteExprlist); sqlite3_free(p->zContentTbl); sqlite3_free(p->zLanguageid); /* Invoke the tokenizer destructor to free the tokenizer. */ p->pTokenizer->pModule->xDestroy(p->pTokenizer); sqlite3_free(p); return SQLITE_OK; } /* ** Write an error message into *pzErr */ SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char **pzErr, const char *zFormat, ...){ va_list ap; sqlite3_free(*pzErr); va_start(ap, zFormat); *pzErr = sqlite3_vmprintf(zFormat, ap); va_end(ap); } /* ** Construct one or more SQL statements from the format string given ** and then evaluate those statements. The success code is written ** into *pRc. ** ** If *pRc is initially non-zero then this routine is a no-op. */ static void fts3DbExec( int *pRc, /* Success code */ sqlite3 *db, /* Database in which to run SQL */ const char *zFormat, /* Format string for SQL */ ... /* Arguments to the format string */ ){ va_list ap; char *zSql; if( *pRc ) return; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( zSql==0 ){ *pRc = SQLITE_NOMEM; }else{ *pRc = sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); } } /* ** The xDestroy() virtual table method. */ static int fts3DestroyMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table *)pVtab; int rc = SQLITE_OK; /* Return code */ const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */ sqlite3 *db = p->db; /* Database handle */ /* Drop the shadow tables */ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments';" "DROP TABLE IF EXISTS %Q.'%q_segdir';" "DROP TABLE IF EXISTS %Q.'%q_docsize';" "DROP TABLE IF EXISTS %Q.'%q_stat';" "%s DROP TABLE IF EXISTS %Q.'%q_content';", zDb, p->zName, zDb, p->zName, zDb, p->zName, zDb, p->zName, (p->zContentTbl ? "--" : ""), zDb,p->zName ); /* If everything has worked, invoke fts3DisconnectMethod() to free the ** memory associated with the Fts3Table structure and return SQLITE_OK. ** Otherwise, return an SQLite error code. */ return (rc==SQLITE_OK ? fts3DisconnectMethod(pVtab) : rc); } /* ** Invoke sqlite3_declare_vtab() to declare the schema for the FTS3 table ** passed as the first argument. This is done as part of the xConnect() ** and xCreate() methods. ** ** If *pRc is non-zero when this function is called, it is a no-op. ** Otherwise, if an error occurs, an SQLite error code is stored in *pRc ** before returning. */ static void fts3DeclareVtab(int *pRc, Fts3Table *p){ if( *pRc==SQLITE_OK ){ int i; /* Iterator variable */ int rc; /* Return code */ char *zSql; /* SQL statement passed to declare_vtab() */ char *zCols; /* List of user defined columns */ const char *zLanguageid; zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid"); sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); sqlite3_vtab_config(p->db, SQLITE_VTAB_INNOCUOUS); /* Create a list of user columns for the virtual table */ zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]); for(i=1; zCols && inColumn; i++){ zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]); } /* Create the whole "CREATE TABLE" statement to pass to SQLite */ zSql = sqlite3_mprintf( "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN, %Q HIDDEN)", zCols, p->zName, zLanguageid ); if( !zCols || !zSql ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_declare_vtab(p->db, zSql); } sqlite3_free(zSql); sqlite3_free(zCols); *pRc = rc; } } /* ** Create the %_stat table if it does not already exist. */ SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int *pRc, Fts3Table *p){ fts3DbExec(pRc, p->db, "CREATE TABLE IF NOT EXISTS %Q.'%q_stat'" "(id INTEGER PRIMARY KEY, value BLOB);", p->zDb, p->zName ); if( (*pRc)==SQLITE_OK ) p->bHasStat = 1; } /* ** Create the backing store tables (%_content, %_segments and %_segdir) ** required by the FTS3 table passed as the only argument. This is done ** as part of the vtab xCreate() method. ** ** If the p->bHasDocsize boolean is true (indicating that this is an ** FTS4 table, not an FTS3 table) then also create the %_docsize and ** %_stat tables required by FTS4. */ static int fts3CreateTables(Fts3Table *p){ int rc = SQLITE_OK; /* Return code */ int i; /* Iterator variable */ sqlite3 *db = p->db; /* The database connection */ if( p->zContentTbl==0 ){ const char *zLanguageid = p->zLanguageid; char *zContentCols; /* Columns of %_content table */ /* Create a list of user columns for the content table */ zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY"); for(i=0; zContentCols && inColumn; i++){ char *z = p->azColumn[i]; zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z); } if( zLanguageid && zContentCols ){ zContentCols = sqlite3_mprintf("%z, langid", zContentCols, zLanguageid); } if( zContentCols==0 ) rc = SQLITE_NOMEM; /* Create the content table */ fts3DbExec(&rc, db, "CREATE TABLE %Q.'%q_content'(%s)", p->zDb, p->zName, zContentCols ); sqlite3_free(zContentCols); } /* Create other tables */ fts3DbExec(&rc, db, "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);", p->zDb, p->zName ); fts3DbExec(&rc, db, "CREATE TABLE %Q.'%q_segdir'(" "level INTEGER," "idx INTEGER," "start_block INTEGER," "leaves_end_block INTEGER," "end_block INTEGER," "root BLOB," "PRIMARY KEY(level, idx)" ");", p->zDb, p->zName ); if( p->bHasDocsize ){ fts3DbExec(&rc, db, "CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);", p->zDb, p->zName ); } assert( p->bHasStat==p->bFts4 ); if( p->bHasStat ){ sqlite3Fts3CreateStatTable(&rc, p); } return rc; } /* ** Store the current database page-size in bytes in p->nPgsz. ** ** If *pRc is non-zero when this function is called, it is a no-op. ** Otherwise, if an error occurs, an SQLite error code is stored in *pRc ** before returning. */ static void fts3DatabasePageSize(int *pRc, Fts3Table *p){ if( *pRc==SQLITE_OK ){ int rc; /* Return code */ char *zSql; /* SQL text "PRAGMA %Q.page_size" */ sqlite3_stmt *pStmt; /* Compiled "PRAGMA %Q.page_size" statement */ zSql = sqlite3_mprintf("PRAGMA %Q.page_size", p->zDb); if( !zSql ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_step(pStmt); p->nPgsz = sqlite3_column_int(pStmt, 0); rc = sqlite3_finalize(pStmt); }else if( rc==SQLITE_AUTH ){ p->nPgsz = 1024; rc = SQLITE_OK; } } assert( p->nPgsz>0 || rc!=SQLITE_OK ); sqlite3_free(zSql); *pRc = rc; } } /* ** "Special" FTS4 arguments are column specifications of the following form: ** ** = ** ** There may not be whitespace surrounding the "=" character. The ** term may be quoted, but the may not. */ static int fts3IsSpecialColumn( const char *z, int *pnKey, char **pzValue ){ char *zValue; const char *zCsr = z; while( *zCsr!='=' ){ if( *zCsr=='\0' ) return 0; zCsr++; } *pnKey = (int)(zCsr-z); zValue = sqlite3_mprintf("%s", &zCsr[1]); if( zValue ){ sqlite3Fts3Dequote(zValue); } *pzValue = zValue; return 1; } /* ** Append the output of a printf() style formatting to an existing string. */ static void fts3Appendf( int *pRc, /* IN/OUT: Error code */ char **pz, /* IN/OUT: Pointer to string buffer */ const char *zFormat, /* Printf format string to append */ ... /* Arguments for printf format string */ ){ if( *pRc==SQLITE_OK ){ va_list ap; char *z; va_start(ap, zFormat); z = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( z && *pz ){ char *z2 = sqlite3_mprintf("%s%s", *pz, z); sqlite3_free(z); z = z2; } if( z==0 ) *pRc = SQLITE_NOMEM; sqlite3_free(*pz); *pz = z; } } /* ** Return a copy of input string zInput enclosed in double-quotes (") and ** with all double quote characters escaped. For example: ** ** fts3QuoteId("un \"zip\"") -> "un \"\"zip\"\"" ** ** The pointer returned points to memory obtained from sqlite3_malloc(). It ** is the callers responsibility to call sqlite3_free() to release this ** memory. */ static char *fts3QuoteId(char const *zInput){ sqlite3_int64 nRet; char *zRet; nRet = 2 + (int)strlen(zInput)*2 + 1; zRet = sqlite3_malloc64(nRet); if( zRet ){ int i; char *z = zRet; *(z++) = '"'; for(i=0; zInput[i]; i++){ if( zInput[i]=='"' ) *(z++) = '"'; *(z++) = zInput[i]; } *(z++) = '"'; *(z++) = '\0'; } return zRet; } /* ** Return a list of comma separated SQL expressions and a FROM clause that ** could be used in a SELECT statement such as the following: ** ** SELECT FROM %_content AS x ... ** ** to return the docid, followed by each column of text data in order ** from left to write. If parameter zFunc is not NULL, then instead of ** being returned directly each column of text data is passed to an SQL ** function named zFunc first. For example, if zFunc is "unzip" and the ** table has the three user-defined columns "a", "b", and "c", the following ** string is returned: ** ** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c') FROM %_content AS x" ** ** The pointer returned points to a buffer allocated by sqlite3_malloc(). It ** is the responsibility of the caller to eventually free it. ** ** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and ** a NULL pointer is returned). Otherwise, if an OOM error is encountered ** by this function, NULL is returned and *pRc is set to SQLITE_NOMEM. If ** no error occurs, *pRc is left unmodified. */ static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){ char *zRet = 0; char *zFree = 0; char *zFunction; int i; if( p->zContentTbl==0 ){ if( !zFunc ){ zFunction = ""; }else{ zFree = zFunction = fts3QuoteId(zFunc); } fts3Appendf(pRc, &zRet, "docid"); for(i=0; inColumn; i++){ fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]); } if( p->zLanguageid ){ fts3Appendf(pRc, &zRet, ", x.%Q", "langid"); } sqlite3_free(zFree); }else{ fts3Appendf(pRc, &zRet, "rowid"); for(i=0; inColumn; i++){ fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]); } if( p->zLanguageid ){ fts3Appendf(pRc, &zRet, ", x.%Q", p->zLanguageid); } } fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x", p->zDb, (p->zContentTbl ? p->zContentTbl : p->zName), (p->zContentTbl ? "" : "_content") ); return zRet; } /* ** Return a list of N comma separated question marks, where N is the number ** of columns in the %_content table (one for the docid plus one for each ** user-defined text column). ** ** If argument zFunc is not NULL, then all but the first question mark ** is preceded by zFunc and an open bracket, and followed by a closed ** bracket. For example, if zFunc is "zip" and the FTS3 table has three ** user-defined text columns, the following string is returned: ** ** "?, zip(?), zip(?), zip(?)" ** ** The pointer returned points to a buffer allocated by sqlite3_malloc(). It ** is the responsibility of the caller to eventually free it. ** ** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and ** a NULL pointer is returned). Otherwise, if an OOM error is encountered ** by this function, NULL is returned and *pRc is set to SQLITE_NOMEM. If ** no error occurs, *pRc is left unmodified. */ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){ char *zRet = 0; char *zFree = 0; char *zFunction; int i; if( !zFunc ){ zFunction = ""; }else{ zFree = zFunction = fts3QuoteId(zFunc); } fts3Appendf(pRc, &zRet, "?"); for(i=0; inColumn; i++){ fts3Appendf(pRc, &zRet, ",%s(?)", zFunction); } if( p->zLanguageid ){ fts3Appendf(pRc, &zRet, ", ?"); } sqlite3_free(zFree); return zRet; } /* ** Buffer z contains a positive integer value encoded as utf-8 text. ** Decode this value and store it in *pnOut, returning the number of bytes ** consumed. If an overflow error occurs return a negative value. */ SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut){ u64 iVal = 0; int i; for(i=0; z[i]>='0' && z[i]<='9'; i++){ iVal = iVal*10 + (z[i] - '0'); if( iVal>0x7FFFFFFF ) return -1; } *pnOut = (int)iVal; return i; } /* ** This function interprets the string at (*pp) as a non-negative integer ** value. It reads the integer and sets *pnOut to the value read, then ** sets *pp to point to the byte immediately following the last byte of ** the integer value. ** ** Only decimal digits ('0'..'9') may be part of an integer value. ** ** If *pp does not being with a decimal digit SQLITE_ERROR is returned and ** the output value undefined. Otherwise SQLITE_OK is returned. ** ** This function is used when parsing the "prefix=" FTS4 parameter. */ static int fts3GobbleInt(const char **pp, int *pnOut){ const int MAX_NPREFIX = 10000000; int nInt = 0; /* Output value */ int nByte; nByte = sqlite3Fts3ReadInt(*pp, &nInt); if( nInt>MAX_NPREFIX ){ nInt = 0; } if( nByte==0 ){ return SQLITE_ERROR; } *pnOut = nInt; *pp += nByte; return SQLITE_OK; } /* ** This function is called to allocate an array of Fts3Index structures ** representing the indexes maintained by the current FTS table. FTS tables ** always maintain the main "terms" index, but may also maintain one or ** more "prefix" indexes, depending on the value of the "prefix=" parameter ** (if any) specified as part of the CREATE VIRTUAL TABLE statement. ** ** Argument zParam is passed the value of the "prefix=" option if one was ** specified, or NULL otherwise. ** ** If no error occurs, SQLITE_OK is returned and *apIndex set to point to ** the allocated array. *pnIndex is set to the number of elements in the ** array. If an error does occur, an SQLite error code is returned. ** ** Regardless of whether or not an error is returned, it is the responsibility ** of the caller to call sqlite3_free() on the output array to free it. */ static int fts3PrefixParameter( const char *zParam, /* ABC in prefix=ABC parameter to parse */ int *pnIndex, /* OUT: size of *apIndex[] array */ struct Fts3Index **apIndex /* OUT: Array of indexes for this table */ ){ struct Fts3Index *aIndex; /* Allocated array */ int nIndex = 1; /* Number of entries in array */ if( zParam && zParam[0] ){ const char *p; nIndex++; for(p=zParam; *p; p++){ if( *p==',' ) nIndex++; } } aIndex = sqlite3_malloc64(sizeof(struct Fts3Index) * nIndex); *apIndex = aIndex; if( !aIndex ){ return SQLITE_NOMEM; } memset(aIndex, 0, sizeof(struct Fts3Index) * nIndex); if( zParam ){ const char *p = zParam; int i; for(i=1; i=0 ); if( nPrefix==0 ){ nIndex--; i--; }else{ aIndex[i].nPrefix = nPrefix; } p++; } } *pnIndex = nIndex; return SQLITE_OK; } /* ** This function is called when initializing an FTS4 table that uses the ** content=xxx option. It determines the number of and names of the columns ** of the new FTS4 table. ** ** The third argument passed to this function is the value passed to the ** config=xxx option (i.e. "xxx"). This function queries the database for ** a table of that name. If found, the output variables are populated ** as follows: ** ** *pnCol: Set to the number of columns table xxx has, ** ** *pnStr: Set to the total amount of space required to store a copy ** of each columns name, including the nul-terminator. ** ** *pazCol: Set to point to an array of *pnCol strings. Each string is ** the name of the corresponding column in table xxx. The array ** and its contents are allocated using a single allocation. It ** is the responsibility of the caller to free this allocation ** by eventually passing the *pazCol value to sqlite3_free(). ** ** If the table cannot be found, an error code is returned and the output ** variables are undefined. Or, if an OOM is encountered, SQLITE_NOMEM is ** returned (and the output variables are undefined). */ static int fts3ContentColumns( sqlite3 *db, /* Database handle */ const char *zDb, /* Name of db (i.e. "main", "temp" etc.) */ const char *zTbl, /* Name of content table */ const char ***pazCol, /* OUT: Malloc'd array of column names */ int *pnCol, /* OUT: Size of array *pazCol */ int *pnStr, /* OUT: Bytes of string content */ char **pzErr /* OUT: error message */ ){ int rc = SQLITE_OK; /* Return code */ char *zSql; /* "SELECT *" statement on zTbl */ sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */ zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl); if( !zSql ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ){ sqlite3Fts3ErrMsg(pzErr, "%s", sqlite3_errmsg(db)); } } sqlite3_free(zSql); if( rc==SQLITE_OK ){ const char **azCol; /* Output array */ sqlite3_int64 nStr = 0; /* Size of all column names (incl. 0x00) */ int nCol; /* Number of table columns */ int i; /* Used to iterate through columns */ /* Loop through the returned columns. Set nStr to the number of bytes of ** space required to store a copy of each column name, including the ** nul-terminator byte. */ nCol = sqlite3_column_count(pStmt); for(i=0; i module name ("fts3" or "fts4") ** argv[1] -> database name ** argv[2] -> table name ** argv[...] -> "column name" and other module argument fields. */ static int fts3InitVtab( int isCreate, /* True for xCreate, false for xConnect */ sqlite3 *db, /* The SQLite database connection */ void *pAux, /* Hash table containing tokenizers */ int argc, /* Number of elements in argv array */ const char * const *argv, /* xCreate/xConnect argument array */ sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ char **pzErr /* Write any error message here */ ){ Fts3Hash *pHash = &((Fts3HashWrapper*)pAux)->hash; Fts3Table *p = 0; /* Pointer to allocated vtab */ int rc = SQLITE_OK; /* Return code */ int i; /* Iterator variable */ sqlite3_int64 nByte; /* Size of allocation used for *p */ int iCol; /* Column index */ int nString = 0; /* Bytes required to hold all column names */ int nCol = 0; /* Number of columns in the FTS table */ char *zCsr; /* Space for holding column names */ int nDb; /* Bytes required to hold database name */ int nName; /* Bytes required to hold table name */ int isFts4 = (argv[0][3]=='4'); /* True for FTS4, false for FTS3 */ const char **aCol; /* Array of column names */ sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */ int nIndex = 0; /* Size of aIndex[] array */ struct Fts3Index *aIndex = 0; /* Array of indexes for this table */ /* The results of parsing supported FTS4 key=value options: */ int bNoDocsize = 0; /* True to omit %_docsize table */ int bDescIdx = 0; /* True to store descending indexes */ char *zPrefix = 0; /* Prefix parameter value (or NULL) */ char *zCompress = 0; /* compress=? parameter (or NULL) */ char *zUncompress = 0; /* uncompress=? parameter (or NULL) */ char *zContent = 0; /* content=? parameter (or NULL) */ char *zLanguageid = 0; /* languageid=? parameter (or NULL) */ char **azNotindexed = 0; /* The set of notindexed= columns */ int nNotindexed = 0; /* Size of azNotindexed[] array */ assert( strlen(argv[0])==4 ); assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4) || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4) ); nDb = (int)strlen(argv[1]) + 1; nName = (int)strlen(argv[2]) + 1; nByte = sizeof(const char *) * (argc-2); aCol = (const char **)sqlite3_malloc64(nByte); if( aCol ){ memset((void*)aCol, 0, nByte); azNotindexed = (char **)sqlite3_malloc64(nByte); } if( azNotindexed ){ memset(azNotindexed, 0, nByte); } if( !aCol || !azNotindexed ){ rc = SQLITE_NOMEM; goto fts3_init_out; } /* Loop through all of the arguments passed by the user to the FTS3/4 ** module (i.e. all the column names and special arguments). This loop ** does the following: ** ** + Figures out the number of columns the FTSX table will have, and ** the number of bytes of space that must be allocated to store copies ** of the column names. ** ** + If there is a tokenizer specification included in the arguments, ** initializes the tokenizer pTokenizer. */ for(i=3; rc==SQLITE_OK && i8 && 0==sqlite3_strnicmp(z, "tokenize", 8) && 0==sqlite3Fts3IsIdChar(z[8]) ){ rc = sqlite3Fts3InitTokenizer(pHash, &z[9], &pTokenizer, pzErr); } /* Check if it is an FTS4 special argument. */ else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){ struct Fts4Option { const char *zOpt; int nOpt; } aFts4Opt[] = { { "matchinfo", 9 }, /* 0 -> MATCHINFO */ { "prefix", 6 }, /* 1 -> PREFIX */ { "compress", 8 }, /* 2 -> COMPRESS */ { "uncompress", 10 }, /* 3 -> UNCOMPRESS */ { "order", 5 }, /* 4 -> ORDER */ { "content", 7 }, /* 5 -> CONTENT */ { "languageid", 10 }, /* 6 -> LANGUAGEID */ { "notindexed", 10 } /* 7 -> NOTINDEXED */ }; int iOpt; if( !zVal ){ rc = SQLITE_NOMEM; }else{ for(iOpt=0; iOptnOpt && !sqlite3_strnicmp(z, pOp->zOpt, pOp->nOpt) ){ break; } } switch( iOpt ){ case 0: /* MATCHINFO */ if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){ sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal); rc = SQLITE_ERROR; } bNoDocsize = 1; break; case 1: /* PREFIX */ sqlite3_free(zPrefix); zPrefix = zVal; zVal = 0; break; case 2: /* COMPRESS */ sqlite3_free(zCompress); zCompress = zVal; zVal = 0; break; case 3: /* UNCOMPRESS */ sqlite3_free(zUncompress); zUncompress = zVal; zVal = 0; break; case 4: /* ORDER */ if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) ){ sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal); rc = SQLITE_ERROR; } bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); break; case 5: /* CONTENT */ sqlite3_free(zContent); zContent = zVal; zVal = 0; break; case 6: /* LANGUAGEID */ assert( iOpt==6 ); sqlite3_free(zLanguageid); zLanguageid = zVal; zVal = 0; break; case 7: /* NOTINDEXED */ azNotindexed[nNotindexed++] = zVal; zVal = 0; break; default: assert( iOpt==SizeofArray(aFts4Opt) ); sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z); rc = SQLITE_ERROR; break; } sqlite3_free(zVal); } } /* Otherwise, the argument is a column name. */ else { nString += (int)(strlen(z) + 1); aCol[nCol++] = z; } } /* If a content=xxx option was specified, the following: ** ** 1. Ignore any compress= and uncompress= options. ** ** 2. If no column names were specified as part of the CREATE VIRTUAL ** TABLE statement, use all columns from the content table. */ if( rc==SQLITE_OK && zContent ){ sqlite3_free(zCompress); sqlite3_free(zUncompress); zCompress = 0; zUncompress = 0; if( nCol==0 ){ sqlite3_free((void*)aCol); aCol = 0; rc = fts3ContentColumns(db, argv[1], zContent,&aCol,&nCol,&nString,pzErr); /* If a languageid= option was specified, remove the language id ** column from the aCol[] array. */ if( rc==SQLITE_OK && zLanguageid ){ int j; for(j=0; jdb = db; p->nColumn = nCol; p->nPendingData = 0; p->azColumn = (char **)&p[1]; p->pTokenizer = pTokenizer; p->nMaxPendingData = FTS3_MAX_PENDING_DATA; p->bHasDocsize = (isFts4 && bNoDocsize==0); p->bHasStat = (u8)isFts4; p->bFts4 = (u8)isFts4; p->bDescIdx = (u8)bDescIdx; p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */ p->zContentTbl = zContent; p->zLanguageid = zLanguageid; zContent = 0; zLanguageid = 0; TESTONLY( p->inTransaction = -1 ); TESTONLY( p->mxSavepoint = -1 ); p->aIndex = (struct Fts3Index *)&p->azColumn[nCol]; memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex); p->nIndex = nIndex; for(i=0; iaIndex[i].hPending, FTS3_HASH_STRING, 1); } p->abNotindexed = (u8 *)&p->aIndex[nIndex]; /* Fill in the zName and zDb fields of the vtab structure. */ zCsr = (char *)&p->abNotindexed[nCol]; p->zName = zCsr; memcpy(zCsr, argv[2], nName); zCsr += nName; p->zDb = zCsr; memcpy(zCsr, argv[1], nDb); zCsr += nDb; /* Fill in the azColumn array */ for(iCol=0; iCol0 ){ memcpy(zCsr, z, n); } zCsr[n] = '\0'; sqlite3Fts3Dequote(zCsr); p->azColumn[iCol] = zCsr; zCsr += n+1; assert( zCsr <= &((char *)p)[nByte] ); } /* Fill in the abNotindexed array */ for(iCol=0; iColazColumn[iCol]); for(i=0; iazColumn[iCol], zNot, n) ){ p->abNotindexed[iCol] = 1; sqlite3_free(zNot); azNotindexed[i] = 0; } } } for(i=0; izReadExprlist = fts3ReadExprList(p, zUncompress, &rc); p->zWriteExprlist = fts3WriteExprList(p, zCompress, &rc); if( rc!=SQLITE_OK ) goto fts3_init_out; /* If this is an xCreate call, create the underlying tables in the ** database. TODO: For xConnect(), it could verify that said tables exist. */ if( isCreate ){ rc = fts3CreateTables(p); } /* Check to see if a legacy fts3 table has been "upgraded" by the ** addition of a %_stat table so that it can use incremental merge. */ if( !isFts4 && !isCreate ){ p->bHasStat = 2; } /* Figure out the page-size for the database. This is required in order to ** estimate the cost of loading large doclists from the database. */ fts3DatabasePageSize(&rc, p); p->nNodeSize = p->nPgsz-35; #if defined(SQLITE_DEBUG)||defined(SQLITE_TEST) p->nMergeCount = FTS3_MERGE_COUNT; #endif /* Declare the table schema to SQLite. */ fts3DeclareVtab(&rc, p); fts3_init_out: sqlite3_free(zPrefix); sqlite3_free(aIndex); sqlite3_free(zCompress); sqlite3_free(zUncompress); sqlite3_free(zContent); sqlite3_free(zLanguageid); for(i=0; ipModule->xDestroy(pTokenizer); } }else{ assert( p->pSegments==0 ); *ppVTab = &p->base; } return rc; } /* ** The xConnect() and xCreate() methods for the virtual table. All the ** work is done in function fts3InitVtab(). */ static int fts3ConnectMethod( sqlite3 *db, /* Database connection */ void *pAux, /* Pointer to tokenizer hash table */ int argc, /* Number of elements in argv array */ const char * const *argv, /* xCreate/xConnect argument array */ sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ return fts3InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr); } static int fts3CreateMethod( sqlite3 *db, /* Database connection */ void *pAux, /* Pointer to tokenizer hash table */ int argc, /* Number of elements in argv array */ const char * const *argv, /* xCreate/xConnect argument array */ sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ return fts3InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr); } /* ** Set the pIdxInfo->estimatedRows variable to nRow. Unless this ** extension is currently being used by a version of SQLite too old to ** support estimatedRows. In that case this function is a no-op. */ static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ #if SQLITE_VERSION_NUMBER>=3008002 if( sqlite3_libversion_number()>=3008002 ){ pIdxInfo->estimatedRows = nRow; } #endif } /* ** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this ** extension is currently being used by a version of SQLite too old to ** support index-info flags. In that case this function is a no-op. */ static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){ #if SQLITE_VERSION_NUMBER>=3008012 if( sqlite3_libversion_number()>=3008012 ){ pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; } #endif } /* ** Implementation of the xBestIndex method for FTS3 tables. There ** are three possible strategies, in order of preference: ** ** 1. Direct lookup by rowid or docid. ** 2. Full-text search using a MATCH operator on a non-docid column. ** 3. Linear scan of %_content table. */ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ Fts3Table *p = (Fts3Table *)pVTab; int i; /* Iterator variable */ int iCons = -1; /* Index of constraint to use */ int iLangidCons = -1; /* Index of langid=x constraint, if present */ int iDocidGe = -1; /* Index of docid>=x constraint, if present */ int iDocidLe = -1; /* Index of docid<=x constraint, if present */ int iIdx; if( p->bLock ){ return SQLITE_ERROR; } /* By default use a full table scan. This is an expensive option, ** so search through the constraints to see if a more efficient ** strategy is possible. */ pInfo->idxNum = FTS3_FULLSCAN_SEARCH; pInfo->estimatedCost = 5000000; for(i=0; inConstraint; i++){ int bDocid; /* True if this constraint is on docid */ struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i]; if( pCons->usable==0 ){ if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ /* There exists an unusable MATCH constraint. This means that if ** the planner does elect to use the results of this call as part ** of the overall query plan the user will see an "unable to use ** function MATCH in the requested context" error. To discourage ** this, return a very high cost here. */ pInfo->idxNum = FTS3_FULLSCAN_SEARCH; pInfo->estimatedCost = 1e50; fts3SetEstimatedRows(pInfo, ((sqlite3_int64)1) << 50); return SQLITE_OK; } continue; } bDocid = (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1); /* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */ if( iCons<0 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && bDocid ){ pInfo->idxNum = FTS3_DOCID_SEARCH; pInfo->estimatedCost = 1.0; iCons = i; } /* A MATCH constraint. Use a full-text search. ** ** If there is more than one MATCH constraint available, use the first ** one encountered. If there is both a MATCH constraint and a direct ** rowid/docid lookup, prefer the MATCH strategy. This is done even ** though the rowid/docid lookup is faster than a MATCH query, selecting ** it would lead to an "unable to use function MATCH in the requested ** context" error. */ if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH && pCons->iColumn>=0 && pCons->iColumn<=p->nColumn ){ pInfo->idxNum = FTS3_FULLTEXT_SEARCH + pCons->iColumn; pInfo->estimatedCost = 2.0; iCons = i; } /* Equality constraint on the langid column */ if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && pCons->iColumn==p->nColumn + 2 ){ iLangidCons = i; } if( bDocid ){ switch( pCons->op ){ case SQLITE_INDEX_CONSTRAINT_GE: case SQLITE_INDEX_CONSTRAINT_GT: iDocidGe = i; break; case SQLITE_INDEX_CONSTRAINT_LE: case SQLITE_INDEX_CONSTRAINT_LT: iDocidLe = i; break; } } } /* If using a docid=? or rowid=? strategy, set the UNIQUE flag. */ if( pInfo->idxNum==FTS3_DOCID_SEARCH ) fts3SetUniqueFlag(pInfo); iIdx = 1; if( iCons>=0 ){ pInfo->aConstraintUsage[iCons].argvIndex = iIdx++; pInfo->aConstraintUsage[iCons].omit = 1; } if( iLangidCons>=0 ){ pInfo->idxNum |= FTS3_HAVE_LANGID; pInfo->aConstraintUsage[iLangidCons].argvIndex = iIdx++; } if( iDocidGe>=0 ){ pInfo->idxNum |= FTS3_HAVE_DOCID_GE; pInfo->aConstraintUsage[iDocidGe].argvIndex = iIdx++; } if( iDocidLe>=0 ){ pInfo->idxNum |= FTS3_HAVE_DOCID_LE; pInfo->aConstraintUsage[iDocidLe].argvIndex = iIdx++; } /* Regardless of the strategy selected, FTS can deliver rows in rowid (or ** docid) order. Both ascending and descending are possible. */ if( pInfo->nOrderBy==1 ){ struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0]; if( pOrder->iColumn<0 || pOrder->iColumn==p->nColumn+1 ){ if( pOrder->desc ){ pInfo->idxStr = "DESC"; }else{ pInfo->idxStr = "ASC"; } pInfo->orderByConsumed = 1; } } assert( p->pSegments==0 ); return SQLITE_OK; } /* ** Implementation of xOpen method. */ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ sqlite3_vtab_cursor *pCsr; /* Allocated cursor */ UNUSED_PARAMETER(pVTab); /* Allocate a buffer large enough for an Fts3Cursor structure. If the ** allocation succeeds, zero it and return SQLITE_OK. Otherwise, ** if the allocation fails, return SQLITE_NOMEM. */ *ppCsr = pCsr = (sqlite3_vtab_cursor *)sqlite3_malloc(sizeof(Fts3Cursor)); if( !pCsr ){ return SQLITE_NOMEM; } memset(pCsr, 0, sizeof(Fts3Cursor)); return SQLITE_OK; } /* ** Finalize the statement handle at pCsr->pStmt. ** ** Or, if that statement handle is one created by fts3CursorSeekStmt(), ** and the Fts3Table.pSeekStmt slot is currently NULL, save the statement ** pointer there instead of finalizing it. */ static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){ if( pCsr->bSeekStmt ){ Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; if( p->pSeekStmt==0 ){ p->pSeekStmt = pCsr->pStmt; sqlite3_reset(pCsr->pStmt); pCsr->pStmt = 0; } pCsr->bSeekStmt = 0; } sqlite3_finalize(pCsr->pStmt); } /* ** Free all resources currently held by the cursor passed as the only ** argument. */ static void fts3ClearCursor(Fts3Cursor *pCsr){ fts3CursorFinalizeStmt(pCsr); sqlite3Fts3FreeDeferredTokens(pCsr); sqlite3_free(pCsr->aDoclist); sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); sqlite3Fts3ExprFree(pCsr->pExpr); memset(&(&pCsr->base)[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); } /* ** Close the cursor. For additional information see the documentation ** on the xClose method of the virtual table interface. */ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){ Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); fts3ClearCursor(pCsr); assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); sqlite3_free(pCsr); return SQLITE_OK; } /* ** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then ** compose and prepare an SQL statement of the form: ** ** "SELECT FROM %_content WHERE rowid = ?" ** ** (or the equivalent for a content=xxx table) and set pCsr->pStmt to ** it. If an error occurs, return an SQLite error code. */ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){ int rc = SQLITE_OK; if( pCsr->pStmt==0 ){ Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; char *zSql; if( p->pSeekStmt ){ pCsr->pStmt = p->pSeekStmt; p->pSeekStmt = 0; }else{ zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); if( !zSql ) return SQLITE_NOMEM; p->bLock++; rc = sqlite3_prepare_v3( p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 ); p->bLock--; sqlite3_free(zSql); } if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1; } return rc; } /* ** Position the pCsr->pStmt statement so that it is on the row ** of the %_content table that contains the last match. Return ** SQLITE_OK on success. */ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ int rc = SQLITE_OK; if( pCsr->isRequireSeek ){ rc = fts3CursorSeekStmt(pCsr); if( rc==SQLITE_OK ){ Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab; pTab->bLock++; sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); pCsr->isRequireSeek = 0; if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ pTab->bLock--; return SQLITE_OK; }else{ pTab->bLock--; rc = sqlite3_reset(pCsr->pStmt); if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ /* If no row was found and no error has occurred, then the %_content ** table is missing a row that is present in the full-text index. ** The data structures are corrupt. */ rc = FTS_CORRUPT_VTAB; pCsr->isEof = 1; } } } } if( rc!=SQLITE_OK && pContext ){ sqlite3_result_error_code(pContext, rc); } return rc; } /* ** This function is used to process a single interior node when searching ** a b-tree for a term or term prefix. The node data is passed to this ** function via the zNode/nNode parameters. The term to search for is ** passed in zTerm/nTerm. ** ** If piFirst is not NULL, then this function sets *piFirst to the blockid ** of the child node that heads the sub-tree that may contain the term. ** ** If piLast is not NULL, then *piLast is set to the right-most child node ** that heads a sub-tree that may contain a term for which zTerm/nTerm is ** a prefix. ** ** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK. */ static int fts3ScanInteriorNode( const char *zTerm, /* Term to select leaves for */ int nTerm, /* Size of term zTerm in bytes */ const char *zNode, /* Buffer containing segment interior node */ int nNode, /* Size of buffer at zNode */ sqlite3_int64 *piFirst, /* OUT: Selected child node */ sqlite3_int64 *piLast /* OUT: Selected child node */ ){ int rc = SQLITE_OK; /* Return code */ const char *zCsr = zNode; /* Cursor to iterate through node */ const char *zEnd = &zCsr[nNode];/* End of interior node buffer */ char *zBuffer = 0; /* Buffer to load terms into */ i64 nAlloc = 0; /* Size of allocated buffer */ int isFirstTerm = 1; /* True when processing first term on page */ u64 iChild; /* Block id of child node to descend to */ int nBuffer = 0; /* Total term size */ /* Skip over the 'height' varint that occurs at the start of every ** interior node. Then load the blockid of the left-child of the b-tree ** node into variable iChild. ** ** Even if the data structure on disk is corrupted, this (reading two ** varints from the buffer) does not risk an overread. If zNode is a ** root node, then the buffer comes from a SELECT statement. SQLite does ** not make this guarantee explicitly, but in practice there are always ** either more than 20 bytes of allocated space following the nNode bytes of ** contents, or two zero bytes. Or, if the node is read from the %_segments ** table, then there are always 20 bytes of zeroed padding following the ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). */ zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); if( zCsr>zEnd ){ return FTS_CORRUPT_VTAB; } while( zCsrnBuffer ){ rc = FTS_CORRUPT_VTAB; goto finish_scan; } } isFirstTerm = 0; zCsr += fts3GetVarint32(zCsr, &nSuffix); assert( nPrefix>=0 && nSuffix>=0 ); if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){ rc = FTS_CORRUPT_VTAB; goto finish_scan; } if( (i64)nPrefix+nSuffix>nAlloc ){ char *zNew; nAlloc = ((i64)nPrefix+nSuffix) * 2; zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc); if( !zNew ){ rc = SQLITE_NOMEM; goto finish_scan; } zBuffer = zNew; } assert( zBuffer ); memcpy(&zBuffer[nPrefix], zCsr, nSuffix); nBuffer = nPrefix + nSuffix; zCsr += nSuffix; /* Compare the term we are searching for with the term just loaded from ** the interior node. If the specified term is greater than or equal ** to the term from the interior node, then all terms on the sub-tree ** headed by node iChild are smaller than zTerm. No need to search ** iChild. ** ** If the interior node term is larger than the specified term, then ** the tree headed by iChild may contain the specified term. */ cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ *piFirst = (i64)iChild; piFirst = 0; } if( piLast && cmp<0 ){ *piLast = (i64)iChild; piLast = 0; } iChild++; }; if( piFirst ) *piFirst = (i64)iChild; if( piLast ) *piLast = (i64)iChild; finish_scan: sqlite3_free(zBuffer); return rc; } /* ** The buffer pointed to by argument zNode (size nNode bytes) contains an ** interior node of a b-tree segment. The zTerm buffer (size nTerm bytes) ** contains a term. This function searches the sub-tree headed by the zNode ** node for the range of leaf nodes that may contain the specified term ** or terms for which the specified term is a prefix. ** ** If piLeaf is not NULL, then *piLeaf is set to the blockid of the ** left-most leaf node in the tree that may contain the specified term. ** If piLeaf2 is not NULL, then *piLeaf2 is set to the blockid of the ** right-most leaf node that may contain a term for which the specified ** term is a prefix. ** ** It is possible that the range of returned leaf nodes does not contain ** the specified term or any terms for which it is a prefix. However, if the ** segment does contain any such terms, they are stored within the identified ** range. Because this function only inspects interior segment nodes (and ** never loads leaf nodes into memory), it is not possible to be sure. ** ** If an error occurs, an error code other than SQLITE_OK is returned. */ static int fts3SelectLeaf( Fts3Table *p, /* Virtual table handle */ const char *zTerm, /* Term to select leaves for */ int nTerm, /* Size of term zTerm in bytes */ const char *zNode, /* Buffer containing segment interior node */ int nNode, /* Size of buffer at zNode */ sqlite3_int64 *piLeaf, /* Selected leaf node */ sqlite3_int64 *piLeaf2 /* Selected leaf node */ ){ int rc = SQLITE_OK; /* Return code */ int iHeight; /* Height of this node in tree */ assert( piLeaf || piLeaf2 ); fts3GetVarint32(zNode, &iHeight); rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2); assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) ); if( rc==SQLITE_OK && iHeight>1 ){ char *zBlob = 0; /* Blob read from %_segments table */ int nBlob = 0; /* Size of zBlob in bytes */ if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){ rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0); if( rc==SQLITE_OK ){ rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0); } sqlite3_free(zBlob); piLeaf = 0; zBlob = 0; } if( rc==SQLITE_OK ){ rc = sqlite3Fts3ReadBlock(p, piLeaf?*piLeaf:*piLeaf2, &zBlob, &nBlob, 0); } if( rc==SQLITE_OK ){ int iNewHeight = 0; fts3GetVarint32(zBlob, &iNewHeight); if( iNewHeight>=iHeight ){ rc = FTS_CORRUPT_VTAB; }else{ rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2); } } sqlite3_free(zBlob); } return rc; } /* ** This function is used to create delta-encoded serialized lists of FTS3 ** varints. Each call to this function appends a single varint to a list. */ static void fts3PutDeltaVarint( char **pp, /* IN/OUT: Output pointer */ sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ sqlite3_int64 iVal /* Write this value to the list */ ){ assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) ); *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); *piPrev = iVal; } /* ** When this function is called, *ppPoslist is assumed to point to the ** start of a position-list. After it returns, *ppPoslist points to the ** first byte after the position-list. ** ** A position list is list of positions (delta encoded) and columns for ** a single document record of a doclist. So, in other words, this ** routine advances *ppPoslist so that it points to the next docid in ** the doclist, or to the first byte past the end of the doclist. ** ** If pp is not NULL, then the contents of the position list are copied ** to *pp. *pp is set to point to the first byte past the last byte copied ** before this function returns. */ static void fts3PoslistCopy(char **pp, char **ppPoslist){ char *pEnd = *ppPoslist; char c = 0; /* The end of a position list is marked by a zero encoded as an FTS3 ** varint. A single POS_END (0) byte. Except, if the 0 byte is preceded by ** a byte with the 0x80 bit set, then it is not a varint 0, but the tail ** of some other, multi-byte, value. ** ** The following while-loop moves pEnd to point to the first byte that is not ** immediately preceded by a byte with the 0x80 bit set. Then increments ** pEnd once more so that it points to the byte immediately following the ** last byte in the position-list. */ while( *pEnd | c ){ c = *pEnd++ & 0x80; testcase( c!=0 && (*pEnd)==0 ); } pEnd++; /* Advance past the POS_END terminator byte */ if( pp ){ int n = (int)(pEnd - *ppPoslist); char *p = *pp; memcpy(p, *ppPoslist, n); p += n; *pp = p; } *ppPoslist = pEnd; } /* ** When this function is called, *ppPoslist is assumed to point to the ** start of a column-list. After it returns, *ppPoslist points to the ** to the terminator (POS_COLUMN or POS_END) byte of the column-list. ** ** A column-list is list of delta-encoded positions for a single column ** within a single document within a doclist. ** ** The column-list is terminated either by a POS_COLUMN varint (1) or ** a POS_END varint (0). This routine leaves *ppPoslist pointing to ** the POS_COLUMN or POS_END that terminates the column-list. ** ** If pp is not NULL, then the contents of the column-list are copied ** to *pp. *pp is set to point to the first byte past the last byte copied ** before this function returns. The POS_COLUMN or POS_END terminator ** is not copied into *pp. */ static void fts3ColumnlistCopy(char **pp, char **ppPoslist){ char *pEnd = *ppPoslist; char c = 0; /* A column-list is terminated by either a 0x01 or 0x00 byte that is ** not part of a multi-byte varint. */ while( 0xFE & (*pEnd | c) ){ c = *pEnd++ & 0x80; testcase( c!=0 && ((*pEnd)&0xfe)==0 ); } if( pp ){ int n = (int)(pEnd - *ppPoslist); char *p = *pp; memcpy(p, *ppPoslist, n); p += n; *pp = p; } *ppPoslist = pEnd; } /* ** Value used to signify the end of an position-list. This must be ** as large or larger than any value that might appear on the ** position-list, even a position list that has been corrupted. */ #define POSITION_LIST_END LARGEST_INT64 /* ** This function is used to help parse position-lists. When this function is ** called, *pp may point to the start of the next varint in the position-list ** being parsed, or it may point to 1 byte past the end of the position-list ** (in which case **pp will be a terminator bytes POS_END (0) or ** (1)). ** ** If *pp points past the end of the current position-list, set *pi to ** POSITION_LIST_END and return. Otherwise, read the next varint from *pp, ** increment the current value of *pi by the value read, and set *pp to ** point to the next value before returning. ** ** Before calling this routine *pi must be initialized to the value of ** the previous position, or zero if we are reading the first position ** in the position-list. Because positions are delta-encoded, the value ** of the previous position is needed in order to compute the value of ** the next position. */ static void fts3ReadNextPos( char **pp, /* IN/OUT: Pointer into position-list buffer */ sqlite3_int64 *pi /* IN/OUT: Value read from position-list */ ){ if( (**pp)&0xFE ){ int iVal; *pp += fts3GetVarint32((*pp), &iVal); *pi += iVal; *pi -= 2; }else{ *pi = POSITION_LIST_END; } } /* ** If parameter iCol is not 0, write an POS_COLUMN (1) byte followed by ** the value of iCol encoded as a varint to *pp. This will start a new ** column list. ** ** Set *pp to point to the byte just after the last byte written before ** returning (do not modify it if iCol==0). Return the total number of bytes ** written (0 if iCol==0). */ static int fts3PutColNumber(char **pp, int iCol){ int n = 0; /* Number of bytes written */ if( iCol ){ char *p = *pp; /* Output pointer */ n = 1 + sqlite3Fts3PutVarint(&p[1], iCol); *p = 0x01; *pp = &p[n]; } return n; } /* ** Compute the union of two position lists. The output written ** into *pp contains all positions of both *pp1 and *pp2 in sorted ** order and with any duplicates removed. All pointers are ** updated appropriately. The caller is responsible for insuring ** that there is enough space in *pp to hold the complete output. */ static int fts3PoslistMerge( char **pp, /* Output buffer */ char **pp1, /* Left input list */ char **pp2 /* Right input list */ ){ char *p = *pp; char *p1 = *pp1; char *p2 = *pp2; while( *p1 || *p2 ){ int iCol1; /* The current column index in pp1 */ int iCol2; /* The current column index in pp2 */ if( *p1==POS_COLUMN ){ fts3GetVarint32(&p1[1], &iCol1); if( iCol1==0 ) return FTS_CORRUPT_VTAB; } else if( *p1==POS_END ) iCol1 = 0x7fffffff; else iCol1 = 0; if( *p2==POS_COLUMN ){ fts3GetVarint32(&p2[1], &iCol2); if( iCol2==0 ) return FTS_CORRUPT_VTAB; } else if( *p2==POS_END ) iCol2 = 0x7fffffff; else iCol2 = 0; if( iCol1==iCol2 ){ sqlite3_int64 i1 = 0; /* Last position from pp1 */ sqlite3_int64 i2 = 0; /* Last position from pp2 */ sqlite3_int64 iPrev = 0; int n = fts3PutColNumber(&p, iCol1); p1 += n; p2 += n; /* At this point, both p1 and p2 point to the start of column-lists ** for the same column (the column with index iCol1 and iCol2). ** A column-list is a list of non-negative delta-encoded varints, each ** incremented by 2 before being stored. Each list is terminated by a ** POS_END (0) or POS_COLUMN (1). The following block merges the two lists ** and writes the results to buffer p. p is left pointing to the byte ** after the list written. No terminator (POS_END or POS_COLUMN) is ** written to the output. */ fts3GetDeltaVarint(&p1, &i1); fts3GetDeltaVarint(&p2, &i2); if( i1<2 || i2<2 ){ break; } do { fts3PutDeltaVarint(&p, &iPrev, (i1pos(*pp1) && pos(*pp2)-pos(*pp1)<=nToken). i.e. ** when the *pp1 token appears before the *pp2 token, but not more than nToken ** slots before it. ** ** e.g. nToken==1 searches for adjacent positions. */ static int fts3PoslistPhraseMerge( char **pp, /* IN/OUT: Preallocated output buffer */ int nToken, /* Maximum difference in token positions */ int isSaveLeft, /* Save the left position */ int isExact, /* If *pp1 is exactly nTokens before *pp2 */ char **pp1, /* IN/OUT: Left input list */ char **pp2 /* IN/OUT: Right input list */ ){ char *p = *pp; char *p1 = *pp1; char *p2 = *pp2; int iCol1 = 0; int iCol2 = 0; /* Never set both isSaveLeft and isExact for the same invocation. */ assert( isSaveLeft==0 || isExact==0 ); assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 ); if( *p1==POS_COLUMN ){ p1++; p1 += fts3GetVarint32(p1, &iCol1); } if( *p2==POS_COLUMN ){ p2++; p2 += fts3GetVarint32(p2, &iCol2); } while( 1 ){ if( iCol1==iCol2 ){ char *pSave = p; sqlite3_int64 iPrev = 0; sqlite3_int64 iPos1 = 0; sqlite3_int64 iPos2 = 0; if( iCol1 ){ *p++ = POS_COLUMN; p += sqlite3Fts3PutVarint(p, iCol1); } fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2; fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; if( iPos1<0 || iPos2<0 ) break; while( 1 ){ if( iPos2==iPos1+nToken || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken) ){ sqlite3_int64 iSave; iSave = isSaveLeft ? iPos1 : iPos2; fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2; pSave = 0; assert( p ); } if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){ if( (*p2&0xFE)==0 ) break; fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; }else{ if( (*p1&0xFE)==0 ) break; fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2; } } if( pSave ){ assert( pp && p ); p = pSave; } fts3ColumnlistCopy(0, &p1); fts3ColumnlistCopy(0, &p2); assert( (*p1&0xFE)==0 && (*p2&0xFE)==0 ); if( 0==*p1 || 0==*p2 ) break; p1++; p1 += fts3GetVarint32(p1, &iCol1); p2++; p2 += fts3GetVarint32(p2, &iCol2); } /* Advance pointer p1 or p2 (whichever corresponds to the smaller of ** iCol1 and iCol2) so that it points to either the 0x00 that marks the ** end of the position list, or the 0x01 that precedes the next ** column-number in the position list. */ else if( iCol1=pEnd ){ *pp = 0; }else{ u64 iVal; *pp += sqlite3Fts3GetVarintU(*pp, &iVal); if( bDescIdx ){ *pVal = (i64)((u64)*pVal - iVal); }else{ *pVal = (i64)((u64)*pVal + iVal); } } } /* ** This function is used to write a single varint to a buffer. The varint ** is written to *pp. Before returning, *pp is set to point 1 byte past the ** end of the value written. ** ** If *pbFirst is zero when this function is called, the value written to ** the buffer is that of parameter iVal. ** ** If *pbFirst is non-zero when this function is called, then the value ** written is either (iVal-*piPrev) (if bDescIdx is zero) or (*piPrev-iVal) ** (if bDescIdx is non-zero). ** ** Before returning, this function always sets *pbFirst to 1 and *piPrev ** to the value of parameter iVal. */ static void fts3PutDeltaVarint3( char **pp, /* IN/OUT: Output pointer */ int bDescIdx, /* True for descending docids */ sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ int *pbFirst, /* IN/OUT: True after first int written */ sqlite3_int64 iVal /* Write this value to the list */ ){ sqlite3_uint64 iWrite; if( bDescIdx==0 || *pbFirst==0 ){ assert_fts3_nc( *pbFirst==0 || iVal>=*piPrev ); iWrite = (u64)iVal - (u64)*piPrev; }else{ assert_fts3_nc( *piPrev>=iVal ); iWrite = (u64)*piPrev - (u64)iVal; } assert( *pbFirst || *piPrev==0 ); assert_fts3_nc( *pbFirst==0 || iWrite>0 ); *pp += sqlite3Fts3PutVarint(*pp, iWrite); *piPrev = iVal; *pbFirst = 1; } /* ** This macro is used by various functions that merge doclists. The two ** arguments are 64-bit docid values. If the value of the stack variable ** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2). ** Otherwise, (i2-i1). ** ** Using this makes it easier to write code that can merge doclists that are ** sorted in either ascending or descending order. */ /* #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i64)((u64)i1-i2)) */ #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1>i2?1:((i1==i2)?0:-1))) /* ** This function does an "OR" merge of two doclists (output contains all ** positions contained in either argument doclist). If the docids in the ** input doclists are sorted in ascending order, parameter bDescDoclist ** should be false. If they are sorted in ascending order, it should be ** passed a non-zero value. ** ** If no error occurs, *paOut is set to point at an sqlite3_malloc'd buffer ** containing the output doclist and SQLITE_OK is returned. In this case ** *pnOut is set to the number of bytes in the output doclist. ** ** If an error occurs, an SQLite error code is returned. The output values ** are undefined in this case. */ static int fts3DoclistOrMerge( int bDescDoclist, /* True if arguments are desc */ char *a1, int n1, /* First doclist */ char *a2, int n2, /* Second doclist */ char **paOut, int *pnOut /* OUT: Malloc'd doclist */ ){ int rc = SQLITE_OK; sqlite3_int64 i1 = 0; sqlite3_int64 i2 = 0; sqlite3_int64 iPrev = 0; char *pEnd1 = &a1[n1]; char *pEnd2 = &a2[n2]; char *p1 = a1; char *p2 = a2; char *p; char *aOut; int bFirstOut = 0; *paOut = 0; *pnOut = 0; /* Allocate space for the output. Both the input and output doclists ** are delta encoded. If they are in ascending order (bDescDoclist==0), ** then the first docid in each list is simply encoded as a varint. For ** each subsequent docid, the varint stored is the difference between the ** current and previous docid (a positive number - since the list is in ** ascending order). ** ** The first docid written to the output is therefore encoded using the ** same number of bytes as it is in whichever of the input lists it is ** read from. And each subsequent docid read from the same input list ** consumes either the same or less bytes as it did in the input (since ** the difference between it and the previous value in the output must ** be a positive value less than or equal to the delta value read from ** the input list). The same argument applies to all but the first docid ** read from the 'other' list. And to the contents of all position lists ** that will be copied and merged from the input to the output. ** ** However, if the first docid copied to the output is a negative number, ** then the encoding of the first docid from the 'other' input list may ** be larger in the output than it was in the input (since the delta value ** may be a larger positive integer than the actual docid). ** ** The space required to store the output is therefore the sum of the ** sizes of the two inputs, plus enough space for exactly one of the input ** docids to grow. ** ** A symetric argument may be made if the doclists are in descending ** order. */ aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING); if( !aOut ) return SQLITE_NOMEM; p = aOut; fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); while( p1 || p2 ){ sqlite3_int64 iDiff = DOCID_CMP(i1, i2); if( p2 && p1 && iDiff==0 ){ fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); rc = fts3PoslistMerge(&p, &p1, &p2); if( rc ) break; fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); }else if( !p2 || (p1 && iDiff<0) ){ fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); fts3PoslistCopy(&p, &p1); fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); }else{ fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i2); fts3PoslistCopy(&p, &p2); fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); } assert( (p-aOut)<=((p1?(p1-a1):n1)+(p2?(p2-a2):n2)+FTS3_VARINT_MAX-1) ); } if( rc!=SQLITE_OK ){ sqlite3_free(aOut); p = aOut = 0; }else{ assert( (p-aOut)<=n1+n2+FTS3_VARINT_MAX-1 ); memset(&aOut[(p-aOut)], 0, FTS3_BUFFER_PADDING); } *paOut = aOut; *pnOut = (int)(p-aOut); return rc; } /* ** This function does a "phrase" merge of two doclists. In a phrase merge, ** the output contains a copy of each position from the right-hand input ** doclist for which there is a position in the left-hand input doclist ** exactly nDist tokens before it. ** ** If the docids in the input doclists are sorted in ascending order, ** parameter bDescDoclist should be false. If they are sorted in ascending ** order, it should be passed a non-zero value. ** ** The right-hand input doclist is overwritten by this function. */ static int fts3DoclistPhraseMerge( int bDescDoclist, /* True if arguments are desc */ int nDist, /* Distance from left to right (1=adjacent) */ char *aLeft, int nLeft, /* Left doclist */ char **paRight, int *pnRight /* IN/OUT: Right/output doclist */ ){ sqlite3_int64 i1 = 0; sqlite3_int64 i2 = 0; sqlite3_int64 iPrev = 0; char *aRight = *paRight; char *pEnd1 = &aLeft[nLeft]; char *pEnd2 = &aRight[*pnRight]; char *p1 = aLeft; char *p2 = aRight; char *p; int bFirstOut = 0; char *aOut; assert( nDist>0 ); if( bDescDoclist ){ aOut = sqlite3_malloc64((sqlite3_int64)*pnRight + FTS3_VARINT_MAX); if( aOut==0 ) return SQLITE_NOMEM; }else{ aOut = aRight; } p = aOut; fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); while( p1 && p2 ){ sqlite3_int64 iDiff = DOCID_CMP(i1, i2); if( iDiff==0 ){ char *pSave = p; sqlite3_int64 iPrevSave = iPrev; int bFirstOutSave = bFirstOut; fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); if( 0==fts3PoslistPhraseMerge(&p, nDist, 0, 1, &p1, &p2) ){ p = pSave; iPrev = iPrevSave; bFirstOut = bFirstOutSave; } fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); }else if( iDiff<0 ){ fts3PoslistCopy(0, &p1); fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); }else{ fts3PoslistCopy(0, &p2); fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); } } *pnRight = (int)(p - aOut); if( bDescDoclist ){ sqlite3_free(aRight); *paRight = aOut; } return SQLITE_OK; } /* ** Argument pList points to a position list nList bytes in size. This ** function checks to see if the position list contains any entries for ** a token in position 0 (of any column). If so, it writes argument iDelta ** to the output buffer pOut, followed by a position list consisting only ** of the entries from pList at position 0, and terminated by an 0x00 byte. ** The value returned is the number of bytes written to pOut (if any). */ SQLITE_PRIVATE int sqlite3Fts3FirstFilter( sqlite3_int64 iDelta, /* Varint that may be written to pOut */ char *pList, /* Position list (no 0x00 term) */ int nList, /* Size of pList in bytes */ char *pOut /* Write output here */ ){ int nOut = 0; int bWritten = 0; /* True once iDelta has been written */ char *p = pList; char *pEnd = &pList[nList]; if( *p!=0x01 ){ if( *p==0x02 ){ nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta); pOut[nOut++] = 0x02; bWritten = 1; } fts3ColumnlistCopy(0, &p); } while( paaOutput); i++){ if( pTS->aaOutput[i] ){ if( !aOut ){ aOut = pTS->aaOutput[i]; nOut = pTS->anOutput[i]; pTS->aaOutput[i] = 0; }else{ int nNew; char *aNew; int rc = fts3DoclistOrMerge(p->bDescIdx, pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut, &aNew, &nNew ); if( rc!=SQLITE_OK ){ sqlite3_free(aOut); return rc; } sqlite3_free(pTS->aaOutput[i]); sqlite3_free(aOut); pTS->aaOutput[i] = 0; aOut = aNew; nOut = nNew; } } } pTS->aaOutput[0] = aOut; pTS->anOutput[0] = nOut; return SQLITE_OK; } /* ** Merge the doclist aDoclist/nDoclist into the TermSelect object passed ** as the first argument. The merge is an "OR" merge (see function ** fts3DoclistOrMerge() for details). ** ** This function is called with the doclist for each term that matches ** a queried prefix. It merges all these doclists into one, the doclist ** for the specified prefix. Since there can be a very large number of ** doclists to merge, the merging is done pair-wise using the TermSelect ** object. ** ** This function returns SQLITE_OK if the merge is successful, or an ** SQLite error code (SQLITE_NOMEM) if an error occurs. */ static int fts3TermSelectMerge( Fts3Table *p, /* FTS table handle */ TermSelect *pTS, /* TermSelect object to merge into */ char *aDoclist, /* Pointer to doclist */ int nDoclist /* Size of aDoclist in bytes */ ){ if( pTS->aaOutput[0]==0 ){ /* If this is the first term selected, copy the doclist to the output ** buffer using memcpy(). ** ** Add FTS3_VARINT_MAX bytes of unused space to the end of the ** allocation. This is so as to ensure that the buffer is big enough ** to hold the current doclist AND'd with any other doclist. If the ** doclists are stored in order=ASC order, this padding would not be ** required (since the size of [doclistA AND doclistB] is always less ** than or equal to the size of [doclistA] in that case). But this is ** not true for order=DESC. For example, a doclist containing (1, -1) ** may be smaller than (-1), as in the first example the -1 may be stored ** as a single-byte delta, whereas in the second it must be stored as a ** FTS3_VARINT_MAX byte varint. ** ** Similar padding is added in the fts3DoclistOrMerge() function. */ pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1); pTS->anOutput[0] = nDoclist; if( pTS->aaOutput[0] ){ memcpy(pTS->aaOutput[0], aDoclist, nDoclist); memset(&pTS->aaOutput[0][nDoclist], 0, FTS3_VARINT_MAX); }else{ return SQLITE_NOMEM; } }else{ char *aMerge = aDoclist; int nMerge = nDoclist; int iOut; for(iOut=0; iOutaaOutput); iOut++){ if( pTS->aaOutput[iOut]==0 ){ assert( iOut>0 ); pTS->aaOutput[iOut] = aMerge; pTS->anOutput[iOut] = nMerge; break; }else{ char *aNew; int nNew; int rc = fts3DoclistOrMerge(p->bDescIdx, aMerge, nMerge, pTS->aaOutput[iOut], pTS->anOutput[iOut], &aNew, &nNew ); if( rc!=SQLITE_OK ){ if( aMerge!=aDoclist ) sqlite3_free(aMerge); return rc; } if( aMerge!=aDoclist ) sqlite3_free(aMerge); sqlite3_free(pTS->aaOutput[iOut]); pTS->aaOutput[iOut] = 0; aMerge = aNew; nMerge = nNew; if( (iOut+1)==SizeofArray(pTS->aaOutput) ){ pTS->aaOutput[iOut] = aMerge; pTS->anOutput[iOut] = nMerge; } } } } return SQLITE_OK; } /* ** Append SegReader object pNew to the end of the pCsr->apSegment[] array. */ static int fts3SegReaderCursorAppend( Fts3MultiSegReader *pCsr, Fts3SegReader *pNew ){ if( (pCsr->nSegment%16)==0 ){ Fts3SegReader **apNew; sqlite3_int64 nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*); apNew = (Fts3SegReader **)sqlite3_realloc64(pCsr->apSegment, nByte); if( !apNew ){ sqlite3Fts3SegReaderFree(pNew); return SQLITE_NOMEM; } pCsr->apSegment = apNew; } pCsr->apSegment[pCsr->nSegment++] = pNew; return SQLITE_OK; } /* ** Add seg-reader objects to the Fts3MultiSegReader object passed as the ** 8th argument. ** ** This function returns SQLITE_OK if successful, or an SQLite error code ** otherwise. */ static int fts3SegReaderCursor( Fts3Table *p, /* FTS3 table handle */ int iLangid, /* Language id */ int iIndex, /* Index to search (from 0 to p->nIndex-1) */ int iLevel, /* Level of segments to scan */ const char *zTerm, /* Term to query for */ int nTerm, /* Size of zTerm in bytes */ int isPrefix, /* True for a prefix search */ int isScan, /* True to scan from zTerm to EOF */ Fts3MultiSegReader *pCsr /* Cursor object to populate */ ){ int rc = SQLITE_OK; /* Error code */ sqlite3_stmt *pStmt = 0; /* Statement to iterate through segments */ int rc2; /* Result of sqlite3_reset() */ /* If iLevel is less than 0 and this is not a scan, include a seg-reader ** for the pending-terms. If this is a scan, then this call must be being ** made by an fts4aux module, not an FTS table. In this case calling ** Fts3SegReaderPending might segfault, as the data structures used by ** fts4aux are not completely populated. So it's easiest to filter these ** calls out here. */ if( iLevel<0 && p->aIndex && p->iPrevLangid==iLangid ){ Fts3SegReader *pSeg = 0; rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg); if( rc==SQLITE_OK && pSeg ){ rc = fts3SegReaderCursorAppend(pCsr, pSeg); } } if( iLevel!=FTS3_SEGCURSOR_PENDING ){ if( rc==SQLITE_OK ){ rc = sqlite3Fts3AllSegdirs(p, iLangid, iIndex, iLevel, &pStmt); } while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ Fts3SegReader *pSeg = 0; /* Read the values returned by the SELECT into local variables. */ sqlite3_int64 iStartBlock = sqlite3_column_int64(pStmt, 1); sqlite3_int64 iLeavesEndBlock = sqlite3_column_int64(pStmt, 2); sqlite3_int64 iEndBlock = sqlite3_column_int64(pStmt, 3); int nRoot = sqlite3_column_bytes(pStmt, 4); char const *zRoot = sqlite3_column_blob(pStmt, 4); /* If zTerm is not NULL, and this segment is not stored entirely on its ** root node, the range of leaves scanned can be reduced. Do this. */ if( iStartBlock && zTerm && zRoot ){ sqlite3_int64 *pi = (isPrefix ? &iLeavesEndBlock : 0); rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &iStartBlock, pi); if( rc!=SQLITE_OK ) goto finished; if( isPrefix==0 && isScan==0 ) iLeavesEndBlock = iStartBlock; } rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1, (isPrefix==0 && isScan==0), iStartBlock, iLeavesEndBlock, iEndBlock, zRoot, nRoot, &pSeg ); if( rc!=SQLITE_OK ) goto finished; rc = fts3SegReaderCursorAppend(pCsr, pSeg); } } finished: rc2 = sqlite3_reset(pStmt); if( rc==SQLITE_DONE ) rc = rc2; return rc; } /* ** Set up a cursor object for iterating through a full-text index or a ** single level therein. */ SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor( Fts3Table *p, /* FTS3 table handle */ int iLangid, /* Language-id to search */ int iIndex, /* Index to search (from 0 to p->nIndex-1) */ int iLevel, /* Level of segments to scan */ const char *zTerm, /* Term to query for */ int nTerm, /* Size of zTerm in bytes */ int isPrefix, /* True for a prefix search */ int isScan, /* True to scan from zTerm to EOF */ Fts3MultiSegReader *pCsr /* Cursor object to populate */ ){ assert( iIndex>=0 && iIndexnIndex ); assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel==FTS3_SEGCURSOR_PENDING || iLevel>=0 ); assert( iLevelbase.pVtab; if( isPrefix ){ for(i=1; bFound==0 && inIndex; i++){ if( p->aIndex[i].nPrefix==nTerm ){ bFound = 1; rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0, pSegcsr ); pSegcsr->bLookup = 1; } } for(i=1; bFound==0 && inIndex; i++){ if( p->aIndex[i].nPrefix==nTerm+1 ){ bFound = 1; rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 1, 0, pSegcsr ); if( rc==SQLITE_OK ){ rc = fts3SegReaderCursorAddZero( p, pCsr->iLangid, zTerm, nTerm, pSegcsr ); } } } } if( bFound==0 ){ rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr ); pSegcsr->bLookup = !isPrefix; } } *ppSegcsr = pSegcsr; return rc; } /* ** Free an Fts3MultiSegReader allocated by fts3TermSegReaderCursor(). */ static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){ sqlite3Fts3SegReaderFinish(pSegcsr); sqlite3_free(pSegcsr); } /* ** This function retrieves the doclist for the specified term (or term ** prefix) from the database. */ static int fts3TermSelect( Fts3Table *p, /* Virtual table handle */ Fts3PhraseToken *pTok, /* Token to query for */ int iColumn, /* Column to query (or -ve for all columns) */ int *pnOut, /* OUT: Size of buffer at *ppOut */ char **ppOut /* OUT: Malloced result buffer */ ){ int rc; /* Return code */ Fts3MultiSegReader *pSegcsr; /* Seg-reader cursor for this term */ TermSelect tsc; /* Object for pair-wise doclist merging */ Fts3SegFilter filter; /* Segment term filter configuration */ pSegcsr = pTok->pSegcsr; memset(&tsc, 0, sizeof(TermSelect)); filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0) | (pTok->bFirst ? FTS3_SEGMENT_FIRST : 0) | (iColumnnColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0); filter.iCol = iColumn; filter.zTerm = pTok->z; filter.nTerm = pTok->n; rc = sqlite3Fts3SegReaderStart(p, pSegcsr, &filter); while( SQLITE_OK==rc && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pSegcsr)) ){ rc = fts3TermSelectMerge(p, &tsc, pSegcsr->aDoclist, pSegcsr->nDoclist); } if( rc==SQLITE_OK ){ rc = fts3TermSelectFinishMerge(p, &tsc); } if( rc==SQLITE_OK ){ *ppOut = tsc.aaOutput[0]; *pnOut = tsc.anOutput[0]; }else{ int i; for(i=0; ipSegcsr = 0; return rc; } /* ** This function counts the total number of docids in the doclist stored ** in buffer aList[], size nList bytes. ** ** If the isPoslist argument is true, then it is assumed that the doclist ** contains a position-list following each docid. Otherwise, it is assumed ** that the doclist is simply a list of docids stored as delta encoded ** varints. */ static int fts3DoclistCountDocids(char *aList, int nList){ int nDoc = 0; /* Return value */ if( aList ){ char *aEnd = &aList[nList]; /* Pointer to one byte after EOF */ char *p = aList; /* Cursor */ while( peSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){ Fts3Table *pTab = (Fts3Table*)pCursor->pVtab; pTab->bLock++; if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){ pCsr->isEof = 1; rc = sqlite3_reset(pCsr->pStmt); }else{ pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0); rc = SQLITE_OK; } pTab->bLock--; }else{ rc = fts3EvalNext((Fts3Cursor *)pCursor); } assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); return rc; } /* ** If the numeric type of argument pVal is "integer", then return it ** converted to a 64-bit signed integer. Otherwise, return a copy of ** the second parameter, iDefault. */ static sqlite3_int64 fts3DocidRange(sqlite3_value *pVal, i64 iDefault){ if( pVal ){ int eType = sqlite3_value_numeric_type(pVal); if( eType==SQLITE_INTEGER ){ return sqlite3_value_int64(pVal); } } return iDefault; } /* ** This is the xFilter interface for the virtual table. See ** the virtual table xFilter method documentation for additional ** information. ** ** If idxNum==FTS3_FULLSCAN_SEARCH then do a full table scan against ** the %_content table. ** ** If idxNum==FTS3_DOCID_SEARCH then do a docid lookup for a single entry ** in the %_content table. ** ** If idxNum>=FTS3_FULLTEXT_SEARCH then use the full text index. The ** column on the left-hand side of the MATCH operator is column ** number idxNum-FTS3_FULLTEXT_SEARCH, 0 indexed. argv[0] is the right-hand ** side of the MATCH operator. */ static int fts3FilterMethod( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, /* Strategy index */ const char *idxStr, /* Unused */ int nVal, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ int rc = SQLITE_OK; char *zSql; /* SQL statement used to access %_content */ int eSearch; Fts3Table *p = (Fts3Table *)pCursor->pVtab; Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; sqlite3_value *pCons = 0; /* The MATCH or rowid constraint, if any */ sqlite3_value *pLangid = 0; /* The "langid = ?" constraint, if any */ sqlite3_value *pDocidGe = 0; /* The "docid >= ?" constraint, if any */ sqlite3_value *pDocidLe = 0; /* The "docid <= ?" constraint, if any */ int iIdx; UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(nVal); if( p->bLock ){ return SQLITE_ERROR; } eSearch = (idxNum & 0x0000FFFF); assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) ); assert( p->pSegments==0 ); /* Collect arguments into local variables */ iIdx = 0; if( eSearch!=FTS3_FULLSCAN_SEARCH ) pCons = apVal[iIdx++]; if( idxNum & FTS3_HAVE_LANGID ) pLangid = apVal[iIdx++]; if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++]; if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++]; assert( iIdx==nVal ); /* In case the cursor has been used before, clear it now. */ fts3ClearCursor(pCsr); /* Set the lower and upper bounds on docids to return */ pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64); pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64); if( idxStr ){ pCsr->bDesc = (idxStr[0]=='D'); }else{ pCsr->bDesc = p->bDescIdx; } pCsr->eSearch = (i16)eSearch; if( eSearch!=FTS3_DOCID_SEARCH && eSearch!=FTS3_FULLSCAN_SEARCH ){ int iCol = eSearch-FTS3_FULLTEXT_SEARCH; const char *zQuery = (const char *)sqlite3_value_text(pCons); if( zQuery==0 && sqlite3_value_type(pCons)!=SQLITE_NULL ){ return SQLITE_NOMEM; } pCsr->iLangid = 0; if( pLangid ) pCsr->iLangid = sqlite3_value_int(pLangid); assert( p->base.zErrMsg==0 ); rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid, p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr, &p->base.zErrMsg ); if( rc!=SQLITE_OK ){ return rc; } rc = fts3EvalStart(pCsr); sqlite3Fts3SegmentsClose(p); if( rc!=SQLITE_OK ) return rc; pCsr->pNextId = pCsr->aDoclist; pCsr->iPrevId = 0; } /* Compile a SELECT statement for this cursor. For a full-table-scan, the ** statement loops through all rows of the %_content table. For a ** full-text query or docid lookup, the statement retrieves a single ** row by docid. */ if( eSearch==FTS3_FULLSCAN_SEARCH ){ if( pDocidGe || pDocidLe ){ zSql = sqlite3_mprintf( "SELECT %s WHERE rowid BETWEEN %lld AND %lld ORDER BY rowid %s", p->zReadExprlist, pCsr->iMinDocid, pCsr->iMaxDocid, (pCsr->bDesc ? "DESC" : "ASC") ); }else{ zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s", p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") ); } if( zSql ){ p->bLock++; rc = sqlite3_prepare_v3( p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 ); p->bLock--; sqlite3_free(zSql); }else{ rc = SQLITE_NOMEM; } }else if( eSearch==FTS3_DOCID_SEARCH ){ rc = fts3CursorSeekStmt(pCsr); if( rc==SQLITE_OK ){ rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons); } } if( rc!=SQLITE_OK ) return rc; return fts3NextMethod(pCursor); } /* ** This is the xEof method of the virtual table. SQLite calls this ** routine to find out if it has reached the end of a result set. */ static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){ Fts3Cursor *pCsr = (Fts3Cursor*)pCursor; if( pCsr->isEof ){ fts3ClearCursor(pCsr); pCsr->isEof = 1; } return pCsr->isEof; } /* ** This is the xRowid method. The SQLite core calls this routine to ** retrieve the rowid for the current row of the result set. fts3 ** exposes %_content.docid as the rowid for the virtual table. The ** rowid should be written to *pRowid. */ static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ Fts3Cursor *pCsr = (Fts3Cursor *) pCursor; *pRowid = pCsr->iPrevId; return SQLITE_OK; } /* ** This is the xColumn method, called by SQLite to request a value from ** the row that the supplied cursor currently points to. ** ** If: ** ** (iCol < p->nColumn) -> The value of the iCol'th user column. ** (iCol == p->nColumn) -> Magic column with the same name as the table. ** (iCol == p->nColumn+1) -> Docid column ** (iCol == p->nColumn+2) -> Langid column */ static int fts3ColumnMethod( sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ int iCol /* Index of column to read value from */ ){ int rc = SQLITE_OK; /* Return Code */ Fts3Cursor *pCsr = (Fts3Cursor *) pCursor; Fts3Table *p = (Fts3Table *)pCursor->pVtab; /* The column value supplied by SQLite must be in range. */ assert( iCol>=0 && iCol<=p->nColumn+2 ); switch( iCol-p->nColumn ){ case 0: /* The special 'table-name' column */ sqlite3_result_pointer(pCtx, pCsr, "fts3cursor", 0); break; case 1: /* The docid column */ sqlite3_result_int64(pCtx, pCsr->iPrevId); break; case 2: if( pCsr->pExpr ){ sqlite3_result_int64(pCtx, pCsr->iLangid); break; }else if( p->zLanguageid==0 ){ sqlite3_result_int(pCtx, 0); break; }else{ iCol = p->nColumn; /* no break */ deliberate_fall_through } default: /* A user column. Or, if this is a full-table scan, possibly the ** language-id column. Seek the cursor. */ rc = fts3CursorSeek(0, pCsr); if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){ sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); } break; } assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); return rc; } /* ** This function is the implementation of the xUpdate callback used by ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be ** inserted, updated or deleted. */ static int fts3UpdateMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ int nArg, /* Size of argument array */ sqlite3_value **apVal, /* Array of arguments */ sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ return sqlite3Fts3UpdateMethod(pVtab, nArg, apVal, pRowid); } /* ** Implementation of xSync() method. Flush the contents of the pending-terms ** hash-table to the database. */ static int fts3SyncMethod(sqlite3_vtab *pVtab){ /* Following an incremental-merge operation, assuming that the input ** segments are not completely consumed (the usual case), they are updated ** in place to remove the entries that have already been merged. This ** involves updating the leaf block that contains the smallest unmerged ** entry and each block (if any) between the leaf and the root node. So ** if the height of the input segment b-trees is N, and input segments ** are merged eight at a time, updating the input segments at the end ** of an incremental-merge requires writing (8*(1+N)) blocks. N is usually ** small - often between 0 and 2. So the overhead of the incremental ** merge is somewhere between 8 and 24 blocks. To avoid this overhead ** dwarfing the actual productive work accomplished, the incremental merge ** is only attempted if it will write at least 64 leaf blocks. Hence ** nMinMerge. ** ** Of course, updating the input segments also involves deleting a bunch ** of blocks from the segments table. But this is not considered overhead ** as it would also be required by a crisis-merge that used the same input ** segments. */ const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */ Fts3Table *p = (Fts3Table*)pVtab; int rc; i64 iLastRowid = sqlite3_last_insert_rowid(p->db); rc = sqlite3Fts3PendingTermsFlush(p); if( rc==SQLITE_OK && p->nLeafAdd>(nMinMerge/16) && p->nAutoincrmerge && p->nAutoincrmerge!=0xff ){ int mxLevel = 0; /* Maximum relative level value in db */ int A; /* Incr-merge parameter A */ rc = sqlite3Fts3MaxLevel(p, &mxLevel); assert( rc==SQLITE_OK || mxLevel==0 ); A = p->nLeafAdd * mxLevel; A += (A/2); if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge); } sqlite3Fts3SegmentsClose(p); sqlite3_set_last_insert_rowid(p->db, iLastRowid); return rc; } /* ** If it is currently unknown whether or not the FTS table has an %_stat ** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat ** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code ** if an error occurs. */ static int fts3SetHasStat(Fts3Table *p){ int rc = SQLITE_OK; if( p->bHasStat==2 ){ char *zTbl = sqlite3_mprintf("%s_stat", p->zName); if( zTbl ){ int res = sqlite3_table_column_metadata(p->db, p->zDb, zTbl, 0,0,0,0,0,0); sqlite3_free(zTbl); p->bHasStat = (res==SQLITE_OK); }else{ rc = SQLITE_NOMEM; } } return rc; } /* ** Implementation of xBegin() method. */ static int fts3BeginMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; int rc; UNUSED_PARAMETER(pVtab); assert( p->pSegments==0 ); assert( p->nPendingData==0 ); assert( p->inTransaction!=1 ); p->nLeafAdd = 0; rc = fts3SetHasStat(p); #ifdef SQLITE_DEBUG if( rc==SQLITE_OK ){ p->inTransaction = 1; p->mxSavepoint = -1; } #endif return rc; } /* ** Implementation of xCommit() method. This is a no-op. The contents of ** the pending-terms hash-table have already been flushed into the database ** by fts3SyncMethod(). */ static int fts3CommitMethod(sqlite3_vtab *pVtab){ TESTONLY( Fts3Table *p = (Fts3Table*)pVtab ); UNUSED_PARAMETER(pVtab); assert( p->nPendingData==0 ); assert( p->inTransaction!=0 ); assert( p->pSegments==0 ); TESTONLY( p->inTransaction = 0 ); TESTONLY( p->mxSavepoint = -1; ); return SQLITE_OK; } /* ** Implementation of xRollback(). Discard the contents of the pending-terms ** hash-table. Any changes made to the database are reverted by SQLite. */ static int fts3RollbackMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; sqlite3Fts3PendingTermsClear(p); assert( p->inTransaction!=0 ); TESTONLY( p->inTransaction = 0 ); TESTONLY( p->mxSavepoint = -1; ); return SQLITE_OK; } /* ** When called, *ppPoslist must point to the byte immediately following the ** end of a position-list. i.e. ( (*ppPoslist)[-1]==POS_END ). This function ** moves *ppPoslist so that it instead points to the first byte of the ** same position list. */ static void fts3ReversePoslist(char *pStart, char **ppPoslist){ char *p = &(*ppPoslist)[-2]; char c = 0; /* Skip backwards passed any trailing 0x00 bytes added by NearTrim() */ while( p>pStart && (c=*p--)==0 ); /* Search backwards for a varint with value zero (the end of the previous ** poslist). This is an 0x00 byte preceded by some byte that does not ** have the 0x80 bit set. */ while( p>pStart && (*p & 0x80) | c ){ c = *p--; } assert( p==pStart || c==0 ); /* At this point p points to that preceding byte without the 0x80 bit ** set. So to find the start of the poslist, skip forward 2 bytes then ** over a varint. ** ** Normally. The other case is that p==pStart and the poslist to return ** is the first in the doclist. In this case do not skip forward 2 bytes. ** The second part of the if condition (c==0 && *ppPoslist>&p[2]) ** is required for cases where the first byte of a doclist and the ** doclist is empty. For example, if the first docid is 10, a doclist ** that begins with: ** ** 0x0A 0x00 */ if( p>pStart || (c==0 && *ppPoslist>&p[2]) ){ p = &p[2]; } while( *p++&0x80 ); *ppPoslist = p; } /* ** Helper function used by the implementation of the overloaded snippet(), ** offsets() and optimize() SQL functions. ** ** If the value passed as the third argument is a blob of size ** sizeof(Fts3Cursor*), then the blob contents are copied to the ** output variable *ppCsr and SQLITE_OK is returned. Otherwise, an error ** message is written to context pContext and SQLITE_ERROR returned. The ** string passed via zFunc is used as part of the error message. */ static int fts3FunctionArg( sqlite3_context *pContext, /* SQL function call context */ const char *zFunc, /* Function name */ sqlite3_value *pVal, /* argv[0] passed to function */ Fts3Cursor **ppCsr /* OUT: Store cursor handle here */ ){ int rc; *ppCsr = (Fts3Cursor*)sqlite3_value_pointer(pVal, "fts3cursor"); if( (*ppCsr)!=0 ){ rc = SQLITE_OK; }else{ char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc); sqlite3_result_error(pContext, zErr, -1); sqlite3_free(zErr); rc = SQLITE_ERROR; } return rc; } /* ** Implementation of the snippet() function for FTS3 */ static void fts3SnippetFunc( sqlite3_context *pContext, /* SQLite function call context */ int nVal, /* Size of apVal[] array */ sqlite3_value **apVal /* Array of arguments */ ){ Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ const char *zStart = ""; const char *zEnd = ""; const char *zEllipsis = "..."; int iCol = -1; int nToken = 15; /* Default number of tokens in snippet */ /* There must be at least one argument passed to this function (otherwise ** the non-overloaded version would have been called instead of this one). */ assert( nVal>=1 ); if( nVal>6 ){ sqlite3_result_error(pContext, "wrong number of arguments to function snippet()", -1); return; } if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return; switch( nVal ){ case 6: nToken = sqlite3_value_int(apVal[5]); /* no break */ deliberate_fall_through case 5: iCol = sqlite3_value_int(apVal[4]); /* no break */ deliberate_fall_through case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]); /* no break */ deliberate_fall_through case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]); /* no break */ deliberate_fall_through case 2: zStart = (const char*)sqlite3_value_text(apVal[1]); } if( !zEllipsis || !zEnd || !zStart ){ sqlite3_result_error_nomem(pContext); }else if( nToken==0 ){ sqlite3_result_text(pContext, "", -1, SQLITE_STATIC); }else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken); } } /* ** Implementation of the offsets() function for FTS3 */ static void fts3OffsetsFunc( sqlite3_context *pContext, /* SQLite function call context */ int nVal, /* Size of argument array */ sqlite3_value **apVal /* Array of arguments */ ){ Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ UNUSED_PARAMETER(nVal); assert( nVal==1 ); if( fts3FunctionArg(pContext, "offsets", apVal[0], &pCsr) ) return; assert( pCsr ); if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ sqlite3Fts3Offsets(pContext, pCsr); } } /* ** Implementation of the special optimize() function for FTS3. This ** function merges all segments in the database to a single segment. ** Example usage is: ** ** SELECT optimize(t) FROM t LIMIT 1; ** ** where 't' is the name of an FTS3 table. */ static void fts3OptimizeFunc( sqlite3_context *pContext, /* SQLite function call context */ int nVal, /* Size of argument array */ sqlite3_value **apVal /* Array of arguments */ ){ int rc; /* Return code */ Fts3Table *p; /* Virtual table handle */ Fts3Cursor *pCursor; /* Cursor handle passed through apVal[0] */ UNUSED_PARAMETER(nVal); assert( nVal==1 ); if( fts3FunctionArg(pContext, "optimize", apVal[0], &pCursor) ) return; p = (Fts3Table *)pCursor->base.pVtab; assert( p ); rc = sqlite3Fts3Optimize(p); switch( rc ){ case SQLITE_OK: sqlite3_result_text(pContext, "Index optimized", -1, SQLITE_STATIC); break; case SQLITE_DONE: sqlite3_result_text(pContext, "Index already optimal", -1, SQLITE_STATIC); break; default: sqlite3_result_error_code(pContext, rc); break; } } /* ** Implementation of the matchinfo() function for FTS3 */ static void fts3MatchinfoFunc( sqlite3_context *pContext, /* SQLite function call context */ int nVal, /* Size of argument array */ sqlite3_value **apVal /* Array of arguments */ ){ Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ assert( nVal==1 || nVal==2 ); if( SQLITE_OK==fts3FunctionArg(pContext, "matchinfo", apVal[0], &pCsr) ){ const char *zArg = 0; if( nVal>1 ){ zArg = (const char *)sqlite3_value_text(apVal[1]); } sqlite3Fts3Matchinfo(pContext, pCsr, zArg); } } /* ** This routine implements the xFindFunction method for the FTS3 ** virtual table. */ static int fts3FindFunctionMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ int nArg, /* Number of SQL function arguments */ const char *zName, /* Name of SQL function */ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* Unused */ ){ struct Overloaded { const char *zName; void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } aOverload[] = { { "snippet", fts3SnippetFunc }, { "offsets", fts3OffsetsFunc }, { "optimize", fts3OptimizeFunc }, { "matchinfo", fts3MatchinfoFunc }, }; int i; /* Iterator variable */ UNUSED_PARAMETER(pVtab); UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(ppArg); for(i=0; idb; /* Database connection */ int rc; /* Return Code */ /* At this point it must be known if the %_stat table exists or not. ** So bHasStat may not be 2. */ rc = fts3SetHasStat(p); /* As it happens, the pending terms table is always empty here. This is ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction ** always opens a savepoint transaction. And the xSavepoint() method ** flushes the pending terms table. But leave the (no-op) call to ** PendingTermsFlush() in in case that changes. */ assert( p->nPendingData==0 ); if( rc==SQLITE_OK ){ rc = sqlite3Fts3PendingTermsFlush(p); } p->bIgnoreSavepoint = 1; if( p->zContentTbl==0 ){ fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", p->zDb, p->zName, zName ); } if( p->bHasDocsize ){ fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';", p->zDb, p->zName, zName ); } if( p->bHasStat ){ fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_stat' RENAME TO '%q_stat';", p->zDb, p->zName, zName ); } fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_segments' RENAME TO '%q_segments';", p->zDb, p->zName, zName ); fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", p->zDb, p->zName, zName ); p->bIgnoreSavepoint = 0; return rc; } /* ** The xSavepoint() method. ** ** Flush the contents of the pending-terms table to disk. */ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ int rc = SQLITE_OK; Fts3Table *pTab = (Fts3Table*)pVtab; assert( pTab->inTransaction ); assert( pTab->mxSavepoint<=iSavepoint ); TESTONLY( pTab->mxSavepoint = iSavepoint ); if( pTab->bIgnoreSavepoint==0 ){ if( fts3HashCount(&pTab->aIndex[0].hPending)>0 ){ char *zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')", pTab->zDb, pTab->zName, pTab->zName ); if( zSql ){ pTab->bIgnoreSavepoint = 1; rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0); pTab->bIgnoreSavepoint = 0; sqlite3_free(zSql); }else{ rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK ){ pTab->iSavepoint = iSavepoint+1; } } return rc; } /* ** The xRelease() method. ** ** This is a no-op. */ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts3Table *pTab = (Fts3Table*)pVtab; assert( pTab->inTransaction ); assert( pTab->mxSavepoint >= iSavepoint ); TESTONLY( pTab->mxSavepoint = iSavepoint-1 ); pTab->iSavepoint = iSavepoint; return SQLITE_OK; } /* ** The xRollbackTo() method. ** ** Discard the contents of the pending terms table. */ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts3Table *pTab = (Fts3Table*)pVtab; UNUSED_PARAMETER(iSavepoint); assert( pTab->inTransaction ); TESTONLY( pTab->mxSavepoint = iSavepoint ); if( (iSavepoint+1)<=pTab->iSavepoint ){ sqlite3Fts3PendingTermsClear(pTab); } return SQLITE_OK; } /* ** Return true if zName is the extension on one of the shadow tables used ** by this module. */ static int fts3ShadowName(const char *zName){ static const char *azName[] = { "content", "docsize", "segdir", "segments", "stat", }; unsigned int i; for(i=0; ibFts4 ? 4 : 3, zSchema, zTabname, sqlite3_errstr(rc)); }else if( bOk==0 ){ *pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s", p->bFts4 ? 4 : 3, zSchema, zTabname); } sqlite3Fts3SegmentsClose(p); return SQLITE_OK; } static const sqlite3_module fts3Module = { /* iVersion */ 4, /* xCreate */ fts3CreateMethod, /* xConnect */ fts3ConnectMethod, /* xBestIndex */ fts3BestIndexMethod, /* xDisconnect */ fts3DisconnectMethod, /* xDestroy */ fts3DestroyMethod, /* xOpen */ fts3OpenMethod, /* xClose */ fts3CloseMethod, /* xFilter */ fts3FilterMethod, /* xNext */ fts3NextMethod, /* xEof */ fts3EofMethod, /* xColumn */ fts3ColumnMethod, /* xRowid */ fts3RowidMethod, /* xUpdate */ fts3UpdateMethod, /* xBegin */ fts3BeginMethod, /* xSync */ fts3SyncMethod, /* xCommit */ fts3CommitMethod, /* xRollback */ fts3RollbackMethod, /* xFindFunction */ fts3FindFunctionMethod, /* xRename */ fts3RenameMethod, /* xSavepoint */ fts3SavepointMethod, /* xRelease */ fts3ReleaseMethod, /* xRollbackTo */ fts3RollbackToMethod, /* xShadowName */ fts3ShadowName, /* xIntegrity */ fts3IntegrityMethod, }; /* ** This function is registered as the module destructor (called when an ** FTS3 enabled database connection is closed). It frees the memory ** allocated for the tokenizer hash table. */ static void hashDestroy(void *p){ Fts3HashWrapper *pHash = (Fts3HashWrapper *)p; pHash->nRef--; if( pHash->nRef<=0 ){ sqlite3Fts3HashClear(&pHash->hash); sqlite3_free(pHash); } } /* ** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are ** implemented in files fts3_tokenizer1.c, fts3_porter.c and fts3_icu.c ** respectively. The following three forward declarations are for functions ** declared in these files used to retrieve the respective implementations. ** ** Calling sqlite3Fts3SimpleTokenizerModule() sets the value pointed ** to by the argument to point to the "simple" tokenizer implementation. ** And so on. */ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); #ifndef SQLITE_DISABLE_FTS3_UNICODE SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); #endif #ifdef SQLITE_ENABLE_ICU SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); #endif /* ** Initialize the fts3 extension. If this extension is built as part ** of the sqlite library, then this function is called directly by ** SQLite. If fts3 is built as a dynamically loadable extension, this ** function is called by the sqlite3_extension_init() entry point. */ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ int rc = SQLITE_OK; Fts3HashWrapper *pHash = 0; const sqlite3_tokenizer_module *pSimple = 0; const sqlite3_tokenizer_module *pPorter = 0; #ifndef SQLITE_DISABLE_FTS3_UNICODE const sqlite3_tokenizer_module *pUnicode = 0; #endif #ifdef SQLITE_ENABLE_ICU const sqlite3_tokenizer_module *pIcu = 0; sqlite3Fts3IcuTokenizerModule(&pIcu); #endif #ifndef SQLITE_DISABLE_FTS3_UNICODE sqlite3Fts3UnicodeTokenizer(&pUnicode); #endif #ifdef SQLITE_TEST rc = sqlite3Fts3InitTerm(db); if( rc!=SQLITE_OK ) return rc; #endif rc = sqlite3Fts3InitAux(db); if( rc!=SQLITE_OK ) return rc; sqlite3Fts3SimpleTokenizerModule(&pSimple); sqlite3Fts3PorterTokenizerModule(&pPorter); /* Allocate and initialize the hash-table used to store tokenizers. */ pHash = sqlite3_malloc(sizeof(Fts3HashWrapper)); if( !pHash ){ rc = SQLITE_NOMEM; }else{ sqlite3Fts3HashInit(&pHash->hash, FTS3_HASH_STRING, 1); pHash->nRef = 0; } /* Load the built-in tokenizers into the hash table */ if( rc==SQLITE_OK ){ if( sqlite3Fts3HashInsert(&pHash->hash, "simple", 7, (void *)pSimple) || sqlite3Fts3HashInsert(&pHash->hash, "porter", 7, (void *)pPorter) #ifndef SQLITE_DISABLE_FTS3_UNICODE || sqlite3Fts3HashInsert(&pHash->hash, "unicode61", 10, (void *)pUnicode) #endif #ifdef SQLITE_ENABLE_ICU || (pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu)) #endif ){ rc = SQLITE_NOMEM; } } #ifdef SQLITE_TEST if( rc==SQLITE_OK ){ rc = sqlite3Fts3ExprInitTestInterface(db, &pHash->hash); } #endif /* Create the virtual table wrapper around the hash-table and overload ** the four scalar functions. If this is successful, register the ** module with sqlite. */ if( SQLITE_OK==rc && SQLITE_OK==(rc=sqlite3Fts3InitHashTable(db,&pHash->hash,"fts3_tokenizer")) && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1)) ){ pHash->nRef++; rc = sqlite3_create_module_v2( db, "fts3", &fts3Module, (void *)pHash, hashDestroy ); if( rc==SQLITE_OK ){ pHash->nRef++; rc = sqlite3_create_module_v2( db, "fts4", &fts3Module, (void *)pHash, hashDestroy ); } if( rc==SQLITE_OK ){ pHash->nRef++; rc = sqlite3Fts3InitTok(db, (void *)pHash, hashDestroy); } return rc; } /* An error has occurred. Delete the hash table and return the error code. */ assert( rc!=SQLITE_OK ); if( pHash ){ sqlite3Fts3HashClear(&pHash->hash); sqlite3_free(pHash); } return rc; } /* ** Allocate an Fts3MultiSegReader for each token in the expression headed ** by pExpr. ** ** An Fts3SegReader object is a cursor that can seek or scan a range of ** entries within a single segment b-tree. An Fts3MultiSegReader uses multiple ** Fts3SegReader objects internally to provide an interface to seek or scan ** within the union of all segments of a b-tree. Hence the name. ** ** If the allocated Fts3MultiSegReader just seeks to a single entry in a ** segment b-tree (if the term is not a prefix or it is a prefix for which ** there exists prefix b-tree of the right length) then it may be traversed ** and merged incrementally. Otherwise, it has to be merged into an in-memory ** doclist and then traversed. */ static void fts3EvalAllocateReaders( Fts3Cursor *pCsr, /* FTS cursor handle */ Fts3Expr *pExpr, /* Allocate readers for this expression */ int *pnToken, /* OUT: Total number of tokens in phrase. */ int *pnOr, /* OUT: Total number of OR nodes in expr. */ int *pRc /* IN/OUT: Error code */ ){ if( pExpr && SQLITE_OK==*pRc ){ if( pExpr->eType==FTSQUERY_PHRASE ){ int i; int nToken = pExpr->pPhrase->nToken; *pnToken += nToken; for(i=0; ipPhrase->aToken[i]; int rc = fts3TermSegReaderCursor(pCsr, pToken->z, pToken->n, pToken->isPrefix, &pToken->pSegcsr ); if( rc!=SQLITE_OK ){ *pRc = rc; return; } } assert( pExpr->pPhrase->iDoclistToken==0 ); pExpr->pPhrase->iDoclistToken = -1; }else{ *pnOr += (pExpr->eType==FTSQUERY_OR); fts3EvalAllocateReaders(pCsr, pExpr->pLeft, pnToken, pnOr, pRc); fts3EvalAllocateReaders(pCsr, pExpr->pRight, pnToken, pnOr, pRc); } } } /* ** Arguments pList/nList contain the doclist for token iToken of phrase p. ** It is merged into the main doclist stored in p->doclist.aAll/nAll. ** ** This function assumes that pList points to a buffer allocated using ** sqlite3_malloc(). This function takes responsibility for eventually ** freeing the buffer. ** ** SQLITE_OK is returned if successful, or SQLITE_NOMEM if an error occurs. */ static int fts3EvalPhraseMergeToken( Fts3Table *pTab, /* FTS Table pointer */ Fts3Phrase *p, /* Phrase to merge pList/nList into */ int iToken, /* Token pList/nList corresponds to */ char *pList, /* Pointer to doclist */ int nList /* Number of bytes in pList */ ){ int rc = SQLITE_OK; assert( iToken!=p->iDoclistToken ); if( pList==0 ){ sqlite3_free(p->doclist.aAll); p->doclist.aAll = 0; p->doclist.nAll = 0; } else if( p->iDoclistToken<0 ){ p->doclist.aAll = pList; p->doclist.nAll = nList; } else if( p->doclist.aAll==0 ){ sqlite3_free(pList); } else { char *pLeft; char *pRight; int nLeft; int nRight; int nDiff; if( p->iDoclistTokendoclist.aAll; nLeft = p->doclist.nAll; pRight = pList; nRight = nList; nDiff = iToken - p->iDoclistToken; }else{ pRight = p->doclist.aAll; nRight = p->doclist.nAll; pLeft = pList; nLeft = nList; nDiff = p->iDoclistToken - iToken; } rc = fts3DoclistPhraseMerge( pTab->bDescIdx, nDiff, pLeft, nLeft, &pRight, &nRight ); sqlite3_free(pLeft); p->doclist.aAll = pRight; p->doclist.nAll = nRight; } if( iToken>p->iDoclistToken ) p->iDoclistToken = iToken; return rc; } /* ** Load the doclist for phrase p into p->doclist.aAll/nAll. The loaded doclist ** does not take deferred tokens into account. ** ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. */ static int fts3EvalPhraseLoad( Fts3Cursor *pCsr, /* FTS Cursor handle */ Fts3Phrase *p /* Phrase object */ ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int iToken; int rc = SQLITE_OK; for(iToken=0; rc==SQLITE_OK && iTokennToken; iToken++){ Fts3PhraseToken *pToken = &p->aToken[iToken]; assert( pToken->pDeferred==0 || pToken->pSegcsr==0 ); if( pToken->pSegcsr ){ int nThis = 0; char *pThis = 0; rc = fts3TermSelect(pTab, pToken, p->iColumn, &nThis, &pThis); if( rc==SQLITE_OK ){ rc = fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis); } } assert( pToken->pSegcsr==0 ); } return rc; } #ifndef SQLITE_DISABLE_FTS4_DEFERRED /* ** This function is called on each phrase after the position lists for ** any deferred tokens have been loaded into memory. It updates the phrases ** current position list to include only those positions that are really ** instances of the phrase (after considering deferred tokens). If this ** means that the phrase does not appear in the current row, doclist.pList ** and doclist.nList are both zeroed. ** ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. */ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ int iToken; /* Used to iterate through phrase tokens */ char *aPoslist = 0; /* Position list for deferred tokens */ int nPoslist = 0; /* Number of bytes in aPoslist */ int iPrev = -1; /* Token number of previous deferred token */ char *aFree = (pPhrase->doclist.bFreeList ? pPhrase->doclist.pList : 0); for(iToken=0; iTokennToken; iToken++){ Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; Fts3DeferredToken *pDeferred = pToken->pDeferred; if( pDeferred ){ char *pList; int nList; int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); if( rc!=SQLITE_OK ) return rc; if( pList==0 ){ sqlite3_free(aPoslist); sqlite3_free(aFree); pPhrase->doclist.pList = 0; pPhrase->doclist.nList = 0; return SQLITE_OK; }else if( aPoslist==0 ){ aPoslist = pList; nPoslist = nList; }else{ char *aOut = pList; char *p1 = aPoslist; char *p2 = aOut; assert( iPrev>=0 ); fts3PoslistPhraseMerge(&aOut, iToken-iPrev, 0, 1, &p1, &p2); sqlite3_free(aPoslist); aPoslist = pList; nPoslist = (int)(aOut - aPoslist); if( nPoslist==0 ){ sqlite3_free(aPoslist); sqlite3_free(aFree); pPhrase->doclist.pList = 0; pPhrase->doclist.nList = 0; return SQLITE_OK; } } iPrev = iToken; } } if( iPrev>=0 ){ int nMaxUndeferred = pPhrase->iDoclistToken; if( nMaxUndeferred<0 ){ pPhrase->doclist.pList = aPoslist; pPhrase->doclist.nList = nPoslist; pPhrase->doclist.iDocid = pCsr->iPrevId; pPhrase->doclist.bFreeList = 1; }else{ int nDistance; char *p1; char *p2; char *aOut; if( nMaxUndeferred>iPrev ){ p1 = aPoslist; p2 = pPhrase->doclist.pList; nDistance = nMaxUndeferred - iPrev; }else{ p1 = pPhrase->doclist.pList; p2 = aPoslist; nDistance = iPrev - nMaxUndeferred; } aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING); if( !aOut ){ sqlite3_free(aPoslist); return SQLITE_NOMEM; } pPhrase->doclist.pList = aOut; assert( p1 && p2 ); if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){ pPhrase->doclist.bFreeList = 1; pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList); }else{ sqlite3_free(aOut); pPhrase->doclist.pList = 0; pPhrase->doclist.nList = 0; } sqlite3_free(aPoslist); } } if( pPhrase->doclist.pList!=aFree ) sqlite3_free(aFree); return SQLITE_OK; } #endif /* SQLITE_DISABLE_FTS4_DEFERRED */ /* ** Maximum number of tokens a phrase may have to be considered for the ** incremental doclists strategy. */ #define MAX_INCR_PHRASE_TOKENS 4 /* ** This function is called for each Fts3Phrase in a full-text query ** expression to initialize the mechanism for returning rows. Once this ** function has been called successfully on an Fts3Phrase, it may be ** used with fts3EvalPhraseNext() to iterate through the matching docids. ** ** If parameter bOptOk is true, then the phrase may (or may not) use the ** incremental loading strategy. Otherwise, the entire doclist is loaded into ** memory within this call. ** ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. */ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int rc = SQLITE_OK; /* Error code */ int i; /* Determine if doclists may be loaded from disk incrementally. This is ** possible if the bOptOk argument is true, the FTS doclists will be ** scanned in forward order, and the phrase consists of ** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first" ** tokens or prefix tokens that cannot use a prefix-index. */ int bHaveIncr = 0; int bIncrOk = (bOptOk && pCsr->bDesc==pTab->bDescIdx && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) && pTab->bNoIncrDoclist==0 #endif ); for(i=0; bIncrOk==1 && inToken; i++){ Fts3PhraseToken *pToken = &p->aToken[i]; if( pToken->bFirst || (pToken->pSegcsr!=0 && !pToken->pSegcsr->bLookup) ){ bIncrOk = 0; } if( pToken->pSegcsr ) bHaveIncr = 1; } if( bIncrOk && bHaveIncr ){ /* Use the incremental approach. */ int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn); for(i=0; rc==SQLITE_OK && inToken; i++){ Fts3PhraseToken *pToken = &p->aToken[i]; Fts3MultiSegReader *pSegcsr = pToken->pSegcsr; if( pSegcsr ){ rc = sqlite3Fts3MsrIncrStart(pTab, pSegcsr, iCol, pToken->z, pToken->n); } } p->bIncr = 1; }else{ /* Load the full doclist for the phrase into memory. */ rc = fts3EvalPhraseLoad(pCsr, p); p->bIncr = 0; } assert( rc!=SQLITE_OK || p->nToken<1 || p->aToken[0].pSegcsr==0 || p->bIncr ); return rc; } /* ** This function is used to iterate backwards (from the end to start) ** through doclists. It is used by this module to iterate through phrase ** doclists in reverse and by the fts3_write.c module to iterate through ** pending-terms lists when writing to databases with "order=desc". ** ** The doclist may be sorted in ascending (parameter bDescIdx==0) or ** descending (parameter bDescIdx==1) order of docid. Regardless, this ** function iterates from the end of the doclist to the beginning. */ SQLITE_PRIVATE void sqlite3Fts3DoclistPrev( int bDescIdx, /* True if the doclist is desc */ char *aDoclist, /* Pointer to entire doclist */ int nDoclist, /* Length of aDoclist in bytes */ char **ppIter, /* IN/OUT: Iterator pointer */ sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */ int *pnList, /* OUT: List length pointer */ u8 *pbEof /* OUT: End-of-file flag */ ){ char *p = *ppIter; assert( nDoclist>0 ); assert( *pbEof==0 ); assert_fts3_nc( p || *piDocid==0 ); assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) ); if( p==0 ){ sqlite3_int64 iDocid = 0; char *pNext = 0; char *pDocid = aDoclist; char *pEnd = &aDoclist[nDoclist]; int iMul = 1; while( pDocid0 ); assert( *pbEof==0 ); assert_fts3_nc( p || *piDocid==0 ); assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) ); if( p==0 ){ p = aDoclist; p += sqlite3Fts3GetVarint(p, piDocid); }else{ fts3PoslistCopy(0, &p); while( p<&aDoclist[nDoclist] && *p==0 ) p++; if( p>=&aDoclist[nDoclist] ){ *pbEof = 1; }else{ sqlite3_int64 iVar; p += sqlite3Fts3GetVarint(p, &iVar); *piDocid += ((bDescIdx ? -1 : 1) * iVar); } } *ppIter = p; } /* ** Advance the iterator pDL to the next entry in pDL->aAll/nAll. Set *pbEof ** to true if EOF is reached. */ static void fts3EvalDlPhraseNext( Fts3Table *pTab, Fts3Doclist *pDL, u8 *pbEof ){ char *pIter; /* Used to iterate through aAll */ char *pEnd; /* 1 byte past end of aAll */ if( pDL->pNextDocid ){ pIter = pDL->pNextDocid; assert( pDL->aAll!=0 || pIter==0 ); }else{ pIter = pDL->aAll; } if( pIter==0 || pIter>=(pEnd = pDL->aAll + pDL->nAll) ){ /* We have already reached the end of this doclist. EOF. */ *pbEof = 1; }else{ sqlite3_int64 iDelta; pIter += sqlite3Fts3GetVarint(pIter, &iDelta); if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){ pDL->iDocid += iDelta; }else{ pDL->iDocid -= iDelta; } pDL->pList = pIter; fts3PoslistCopy(0, &pIter); pDL->nList = (int)(pIter - pDL->pList); /* pIter now points just past the 0x00 that terminates the position- ** list for document pDL->iDocid. However, if this position-list was ** edited in place by fts3EvalNearTrim(), then pIter may not actually ** point to the start of the next docid value. The following line deals ** with this case by advancing pIter past the zero-padding added by ** fts3EvalNearTrim(). */ while( pIterpNextDocid = pIter; assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter ); *pbEof = 0; } } /* ** Helper type used by fts3EvalIncrPhraseNext() and incrPhraseTokenNext(). */ typedef struct TokenDoclist TokenDoclist; struct TokenDoclist { int bIgnore; sqlite3_int64 iDocid; char *pList; int nList; }; /* ** Token pToken is an incrementally loaded token that is part of a ** multi-token phrase. Advance it to the next matching document in the ** database and populate output variable *p with the details of the new ** entry. Or, if the iterator has reached EOF, set *pbEof to true. ** ** If an error occurs, return an SQLite error code. Otherwise, return ** SQLITE_OK. */ static int incrPhraseTokenNext( Fts3Table *pTab, /* Virtual table handle */ Fts3Phrase *pPhrase, /* Phrase to advance token of */ int iToken, /* Specific token to advance */ TokenDoclist *p, /* OUT: Docid and doclist for new entry */ u8 *pbEof /* OUT: True if iterator is at EOF */ ){ int rc = SQLITE_OK; if( pPhrase->iDoclistToken==iToken ){ assert( p->bIgnore==0 ); assert( pPhrase->aToken[iToken].pSegcsr==0 ); fts3EvalDlPhraseNext(pTab, &pPhrase->doclist, pbEof); p->pList = pPhrase->doclist.pList; p->nList = pPhrase->doclist.nList; p->iDocid = pPhrase->doclist.iDocid; }else{ Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; assert( pToken->pDeferred==0 ); assert( pToken->pSegcsr || pPhrase->iDoclistToken>=0 ); if( pToken->pSegcsr ){ assert( p->bIgnore==0 ); rc = sqlite3Fts3MsrIncrNext( pTab, pToken->pSegcsr, &p->iDocid, &p->pList, &p->nList ); if( p->pList==0 ) *pbEof = 1; }else{ p->bIgnore = 1; } } return rc; } /* ** The phrase iterator passed as the second argument: ** ** * features at least one token that uses an incremental doclist, and ** ** * does not contain any deferred tokens. ** ** Advance it to the next matching documnent in the database and populate ** the Fts3Doclist.pList and nList fields. ** ** If there is no "next" entry and no error occurs, then *pbEof is set to ** 1 before returning. Otherwise, if no error occurs and the iterator is ** successfully advanced, *pbEof is set to 0. ** ** If an error occurs, return an SQLite error code. Otherwise, return ** SQLITE_OK. */ static int fts3EvalIncrPhraseNext( Fts3Cursor *pCsr, /* FTS Cursor handle */ Fts3Phrase *p, /* Phrase object to advance to next docid */ u8 *pbEof /* OUT: Set to 1 if EOF */ ){ int rc = SQLITE_OK; Fts3Doclist *pDL = &p->doclist; Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; u8 bEof = 0; /* This is only called if it is guaranteed that the phrase has at least ** one incremental token. In which case the bIncr flag is set. */ assert( p->bIncr==1 ); if( p->nToken==1 ){ rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr, &pDL->iDocid, &pDL->pList, &pDL->nList ); if( pDL->pList==0 ) bEof = 1; }else{ int bDescDoclist = pCsr->bDesc; struct TokenDoclist a[MAX_INCR_PHRASE_TOKENS]; memset(a, 0, sizeof(a)); assert( p->nToken<=MAX_INCR_PHRASE_TOKENS ); assert( p->iDoclistTokennToken && bEof==0; i++){ rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof); if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){ iMax = a[i].iDocid; bMaxSet = 1; } } assert( rc!=SQLITE_OK || (p->nToken>=1 && a[p->nToken-1].bIgnore==0) ); assert( rc!=SQLITE_OK || bMaxSet ); /* Keep advancing iterators until they all point to the same document */ for(i=0; inToken; i++){ while( rc==SQLITE_OK && bEof==0 && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0 ){ rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof); if( DOCID_CMP(a[i].iDocid, iMax)>0 ){ iMax = a[i].iDocid; i = 0; } } } /* Check if the current entries really are a phrase match */ if( bEof==0 ){ int nList = 0; int nByte = a[p->nToken-1].nList; char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING); if( !aDoclist ) return SQLITE_NOMEM; memcpy(aDoclist, a[p->nToken-1].pList, nByte+1); memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING); for(i=0; i<(p->nToken-1); i++){ if( a[i].bIgnore==0 ){ char *pL = a[i].pList; char *pR = aDoclist; char *pOut = aDoclist; int nDist = p->nToken-1-i; int res = fts3PoslistPhraseMerge(&pOut, nDist, 0, 1, &pL, &pR); if( res==0 ) break; nList = (int)(pOut - aDoclist); } } if( i==(p->nToken-1) ){ pDL->iDocid = iMax; pDL->pList = aDoclist; pDL->nList = nList; pDL->bFreeList = 1; break; } sqlite3_free(aDoclist); } } } *pbEof = bEof; return rc; } /* ** Attempt to move the phrase iterator to point to the next matching docid. ** If an error occurs, return an SQLite error code. Otherwise, return ** SQLITE_OK. ** ** If there is no "next" entry and no error occurs, then *pbEof is set to ** 1 before returning. Otherwise, if no error occurs and the iterator is ** successfully advanced, *pbEof is set to 0. */ static int fts3EvalPhraseNext( Fts3Cursor *pCsr, /* FTS Cursor handle */ Fts3Phrase *p, /* Phrase object to advance to next docid */ u8 *pbEof /* OUT: Set to 1 if EOF */ ){ int rc = SQLITE_OK; Fts3Doclist *pDL = &p->doclist; Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; if( p->bIncr ){ rc = fts3EvalIncrPhraseNext(pCsr, p, pbEof); }else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){ sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll, &pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof ); pDL->pList = pDL->pNextDocid; }else{ fts3EvalDlPhraseNext(pTab, pDL, pbEof); } return rc; } /* ** ** If *pRc is not SQLITE_OK when this function is called, it is a no-op. ** Otherwise, fts3EvalPhraseStart() is called on all phrases within the ** expression. Also the Fts3Expr.bDeferred variable is set to true for any ** expressions for which all descendent tokens are deferred. ** ** If parameter bOptOk is zero, then it is guaranteed that the ** Fts3Phrase.doclist.aAll/nAll variables contain the entire doclist for ** each phrase in the expression (subject to deferred token processing). ** Or, if bOptOk is non-zero, then one or more tokens within the expression ** may be loaded incrementally, meaning doclist.aAll/nAll is not available. ** ** If an error occurs within this function, *pRc is set to an SQLite error ** code before returning. */ static void fts3EvalStartReaders( Fts3Cursor *pCsr, /* FTS Cursor handle */ Fts3Expr *pExpr, /* Expression to initialize phrases in */ int *pRc /* IN/OUT: Error code */ ){ if( pExpr && SQLITE_OK==*pRc ){ if( pExpr->eType==FTSQUERY_PHRASE ){ int nToken = pExpr->pPhrase->nToken; if( nToken ){ int i; for(i=0; ipPhrase->aToken[i].pDeferred==0 ) break; } pExpr->bDeferred = (i==nToken); } *pRc = fts3EvalPhraseStart(pCsr, 1, pExpr->pPhrase); }else{ fts3EvalStartReaders(pCsr, pExpr->pLeft, pRc); fts3EvalStartReaders(pCsr, pExpr->pRight, pRc); pExpr->bDeferred = (pExpr->pLeft->bDeferred && pExpr->pRight->bDeferred); } } } /* ** An array of the following structures is assembled as part of the process ** of selecting tokens to defer before the query starts executing (as part ** of the xFilter() method). There is one element in the array for each ** token in the FTS expression. ** ** Tokens are divided into AND/NEAR clusters. All tokens in a cluster belong ** to phrases that are connected only by AND and NEAR operators (not OR or ** NOT). When determining tokens to defer, each AND/NEAR cluster is considered ** separately. The root of a tokens AND/NEAR cluster is stored in ** Fts3TokenAndCost.pRoot. */ typedef struct Fts3TokenAndCost Fts3TokenAndCost; struct Fts3TokenAndCost { Fts3Phrase *pPhrase; /* The phrase the token belongs to */ int iToken; /* Position of token in phrase */ Fts3PhraseToken *pToken; /* The token itself */ Fts3Expr *pRoot; /* Root of NEAR/AND cluster */ int nOvfl; /* Number of overflow pages to load doclist */ int iCol; /* The column the token must match */ }; /* ** This function is used to populate an allocated Fts3TokenAndCost array. ** ** If *pRc is not SQLITE_OK when this function is called, it is a no-op. ** Otherwise, if an error occurs during execution, *pRc is set to an ** SQLite error code. */ static void fts3EvalTokenCosts( Fts3Cursor *pCsr, /* FTS Cursor handle */ Fts3Expr *pRoot, /* Root of current AND/NEAR cluster */ Fts3Expr *pExpr, /* Expression to consider */ Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */ Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */ int *pRc /* IN/OUT: Error code */ ){ if( *pRc==SQLITE_OK ){ if( pExpr->eType==FTSQUERY_PHRASE ){ Fts3Phrase *pPhrase = pExpr->pPhrase; int i; for(i=0; *pRc==SQLITE_OK && inToken; i++){ Fts3TokenAndCost *pTC = (*ppTC)++; pTC->pPhrase = pPhrase; pTC->iToken = i; pTC->pRoot = pRoot; pTC->pToken = &pPhrase->aToken[i]; pTC->iCol = pPhrase->iColumn; *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl); } }else if( pExpr->eType!=FTSQUERY_NOT ){ assert( pExpr->eType==FTSQUERY_OR || pExpr->eType==FTSQUERY_AND || pExpr->eType==FTSQUERY_NEAR ); assert( pExpr->pLeft && pExpr->pRight ); if( pExpr->eType==FTSQUERY_OR ){ pRoot = pExpr->pLeft; **ppOr = pRoot; (*ppOr)++; } fts3EvalTokenCosts(pCsr, pRoot, pExpr->pLeft, ppTC, ppOr, pRc); if( pExpr->eType==FTSQUERY_OR ){ pRoot = pExpr->pRight; **ppOr = pRoot; (*ppOr)++; } fts3EvalTokenCosts(pCsr, pRoot, pExpr->pRight, ppTC, ppOr, pRc); } } } /* ** Determine the average document (row) size in pages. If successful, ** write this value to *pnPage and return SQLITE_OK. Otherwise, return ** an SQLite error code. ** ** The average document size in pages is calculated by first calculating ** determining the average size in bytes, B. If B is less than the amount ** of data that will fit on a single leaf page of an intkey table in ** this database, then the average docsize is 1. Otherwise, it is 1 plus ** the number of overflow pages consumed by a record B bytes in size. */ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){ int rc = SQLITE_OK; if( pCsr->nRowAvg==0 ){ /* The average document size, which is required to calculate the cost ** of each doclist, has not yet been determined. Read the required ** data from the %_stat table to calculate it. ** ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3 ** varints, where nCol is the number of columns in the FTS3 table. ** The first varint is the number of documents currently stored in ** the table. The following nCol varints contain the total amount of ** data stored in all rows of each column of the table, from left ** to right. */ Fts3Table *p = (Fts3Table*)pCsr->base.pVtab; sqlite3_stmt *pStmt; sqlite3_int64 nDoc = 0; sqlite3_int64 nByte = 0; const char *pEnd; const char *a; rc = sqlite3Fts3SelectDoctotal(p, &pStmt); if( rc!=SQLITE_OK ) return rc; a = sqlite3_column_blob(pStmt, 0); testcase( a==0 ); /* If %_stat.value set to X'' */ if( a ){ pEnd = &a[sqlite3_column_bytes(pStmt, 0)]; a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc); while( anDoc = nDoc; pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz); assert( pCsr->nRowAvg>0 ); rc = sqlite3_reset(pStmt); } *pnPage = pCsr->nRowAvg; return rc; } /* ** This function is called to select the tokens (if any) that will be ** deferred. The array aTC[] has already been populated when this is ** called. ** ** This function is called once for each AND/NEAR cluster in the ** expression. Each invocation determines which tokens to defer within ** the cluster with root node pRoot. See comments above the definition ** of struct Fts3TokenAndCost for more details. ** ** If no error occurs, SQLITE_OK is returned and sqlite3Fts3DeferToken() ** called on each token to defer. Otherwise, an SQLite error code is ** returned. */ static int fts3EvalSelectDeferred( Fts3Cursor *pCsr, /* FTS Cursor handle */ Fts3Expr *pRoot, /* Consider tokens with this root node */ Fts3TokenAndCost *aTC, /* Array of expression tokens and costs */ int nTC /* Number of entries in aTC[] */ ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int nDocSize = 0; /* Number of pages per doc loaded */ int rc = SQLITE_OK; /* Return code */ int ii; /* Iterator variable for various purposes */ int nOvfl = 0; /* Total overflow pages used by doclists */ int nToken = 0; /* Total number of tokens in cluster */ int nMinEst = 0; /* The minimum count for any phrase so far. */ int nLoad4 = 1; /* (Phrases that will be loaded)^4. */ /* Tokens are never deferred for FTS tables created using the content=xxx ** option. The reason being that it is not guaranteed that the content ** table actually contains the same data as the index. To prevent this from ** causing any problems, the deferred token optimization is completely ** disabled for content=xxx tables. */ if( pTab->zContentTbl ){ return SQLITE_OK; } /* Count the tokens in this AND/NEAR cluster. If none of the doclists ** associated with the tokens spill onto overflow pages, or if there is ** only 1 token, exit early. No tokens to defer in this case. */ for(ii=0; ii0 ); /* Iterate through all tokens in this AND/NEAR cluster, in ascending order ** of the number of overflow pages that will be loaded by the pager layer ** to retrieve the entire doclist for the token from the full-text index. ** Load the doclists for tokens that are either: ** ** a. The cheapest token in the entire query (i.e. the one visited by the ** first iteration of this loop), or ** ** b. Part of a multi-token phrase. ** ** After each token doclist is loaded, merge it with the others from the ** same phrase and count the number of documents that the merged doclist ** contains. Set variable "nMinEst" to the smallest number of documents in ** any phrase doclist for which 1 or more token doclists have been loaded. ** Let nOther be the number of other phrases for which it is certain that ** one or more tokens will not be deferred. ** ** Then, for each token, defer it if loading the doclist would result in ** loading N or more overflow pages into memory, where N is computed as: ** ** (nMinEst + 4^nOther - 1) / (4^nOther) */ for(ii=0; iinOvfl) ){ pTC = &aTC[iTC]; } } assert( pTC ); if( ii && pTC->nOvfl>=((nMinEst+(nLoad4/4)-1)/(nLoad4/4))*nDocSize ){ /* The number of overflow pages to load for this (and therefore all ** subsequent) tokens is greater than the estimated number of pages ** that will be loaded if all subsequent tokens are deferred. */ Fts3PhraseToken *pToken = pTC->pToken; rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol); fts3SegReaderCursorFree(pToken->pSegcsr); pToken->pSegcsr = 0; }else{ /* Set nLoad4 to the value of (4^nOther) for the next iteration of the ** for-loop. Except, limit the value to 2^24 to prevent it from ** overflowing the 32-bit integer it is stored in. */ if( ii<12 ) nLoad4 = nLoad4*4; if( ii==0 || (pTC->pPhrase->nToken>1 && ii!=nToken-1) ){ /* Either this is the cheapest token in the entire query, or it is ** part of a multi-token phrase. Either way, the entire doclist will ** (eventually) be loaded into memory. It may as well be now. */ Fts3PhraseToken *pToken = pTC->pToken; int nList = 0; char *pList = 0; rc = fts3TermSelect(pTab, pToken, pTC->iCol, &nList, &pList); assert( rc==SQLITE_OK || pList==0 ); if( rc==SQLITE_OK ){ rc = fts3EvalPhraseMergeToken( pTab, pTC->pPhrase, pTC->iToken,pList,nList ); } if( rc==SQLITE_OK ){ int nCount; nCount = fts3DoclistCountDocids( pTC->pPhrase->doclist.aAll, pTC->pPhrase->doclist.nAll ); if( ii==0 || nCountpToken = 0; } return rc; } /* ** This function is called from within the xFilter method. It initializes ** the full-text query currently stored in pCsr->pExpr. To iterate through ** the results of a query, the caller does: ** ** fts3EvalStart(pCsr); ** while( 1 ){ ** fts3EvalNext(pCsr); ** if( pCsr->bEof ) break; ** ... return row pCsr->iPrevId to the caller ... ** } */ static int fts3EvalStart(Fts3Cursor *pCsr){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int rc = SQLITE_OK; int nToken = 0; int nOr = 0; /* Allocate a MultiSegReader for each token in the expression. */ fts3EvalAllocateReaders(pCsr, pCsr->pExpr, &nToken, &nOr, &rc); /* Determine which, if any, tokens in the expression should be deferred. */ #ifndef SQLITE_DISABLE_FTS4_DEFERRED if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){ Fts3TokenAndCost *aTC; aTC = (Fts3TokenAndCost *)sqlite3_malloc64( sizeof(Fts3TokenAndCost) * nToken + sizeof(Fts3Expr *) * nOr * 2 ); if( !aTC ){ rc = SQLITE_NOMEM; }else{ Fts3Expr **apOr = (Fts3Expr **)&aTC[nToken]; int ii; Fts3TokenAndCost *pTC = aTC; Fts3Expr **ppOr = apOr; fts3EvalTokenCosts(pCsr, 0, pCsr->pExpr, &pTC, &ppOr, &rc); nToken = (int)(pTC-aTC); nOr = (int)(ppOr-apOr); if( rc==SQLITE_OK ){ rc = fts3EvalSelectDeferred(pCsr, 0, aTC, nToken); for(ii=0; rc==SQLITE_OK && iipExpr, &rc); return rc; } /* ** Invalidate the current position list for phrase pPhrase. */ static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){ if( pPhrase->doclist.bFreeList ){ sqlite3_free(pPhrase->doclist.pList); } pPhrase->doclist.pList = 0; pPhrase->doclist.nList = 0; pPhrase->doclist.bFreeList = 0; } /* ** This function is called to edit the position list associated with ** the phrase object passed as the fifth argument according to a NEAR ** condition. For example: ** ** abc NEAR/5 "def ghi" ** ** Parameter nNear is passed the NEAR distance of the expression (5 in ** the example above). When this function is called, *paPoslist points to ** the position list, and *pnToken is the number of phrase tokens in the ** phrase on the other side of the NEAR operator to pPhrase. For example, ** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to ** the position list associated with phrase "abc". ** ** All positions in the pPhrase position list that are not sufficiently ** close to a position in the *paPoslist position list are removed. If this ** leaves 0 positions, zero is returned. Otherwise, non-zero. ** ** Before returning, *paPoslist is set to point to the position lsit ** associated with pPhrase. And *pnToken is set to the number of tokens in ** pPhrase. */ static int fts3EvalNearTrim( int nNear, /* NEAR distance. As in "NEAR/nNear". */ char *aTmp, /* Temporary space to use */ char **paPoslist, /* IN/OUT: Position list */ int *pnToken, /* IN/OUT: Tokens in phrase of *paPoslist */ Fts3Phrase *pPhrase /* The phrase object to trim the doclist of */ ){ int nParam1 = nNear + pPhrase->nToken; int nParam2 = nNear + *pnToken; int nNew; char *p2; char *pOut; int res; assert( pPhrase->doclist.pList ); p2 = pOut = pPhrase->doclist.pList; res = fts3PoslistNearMerge( &pOut, aTmp, nParam1, nParam2, paPoslist, &p2 ); if( res ){ nNew = (int)(pOut - pPhrase->doclist.pList) - 1; assert_fts3_nc( nNew<=pPhrase->doclist.nList && nNew>0 ); if( nNew>=0 && nNew<=pPhrase->doclist.nList ){ assert( pPhrase->doclist.pList[nNew]=='\0' ); memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew); pPhrase->doclist.nList = nNew; } *paPoslist = pPhrase->doclist.pList; *pnToken = pPhrase->nToken; } return res; } /* ** This function is a no-op if *pRc is other than SQLITE_OK when it is called. ** Otherwise, it advances the expression passed as the second argument to ** point to the next matching row in the database. Expressions iterate through ** matching rows in docid order. Ascending order if Fts3Cursor.bDesc is zero, ** or descending if it is non-zero. ** ** If an error occurs, *pRc is set to an SQLite error code. Otherwise, if ** successful, the following variables in pExpr are set: ** ** Fts3Expr.bEof (non-zero if EOF - there is no next row) ** Fts3Expr.iDocid (valid if bEof==0. The docid of the next row) ** ** If the expression is of type FTSQUERY_PHRASE, and the expression is not ** at EOF, then the following variables are populated with the position list ** for the phrase for the visited row: ** ** FTs3Expr.pPhrase->doclist.nList (length of pList in bytes) ** FTs3Expr.pPhrase->doclist.pList (pointer to position list) ** ** It says above that this function advances the expression to the next ** matching row. This is usually true, but there are the following exceptions: ** ** 1. Deferred tokens are not taken into account. If a phrase consists ** entirely of deferred tokens, it is assumed to match every row in ** the db. In this case the position-list is not populated at all. ** ** Or, if a phrase contains one or more deferred tokens and one or ** more non-deferred tokens, then the expression is advanced to the ** next possible match, considering only non-deferred tokens. In other ** words, if the phrase is "A B C", and "B" is deferred, the expression ** is advanced to the next row that contains an instance of "A * C", ** where "*" may match any single token. The position list in this case ** is populated as for "A * C" before returning. ** ** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is ** advanced to point to the next row that matches "x AND y". ** ** See sqlite3Fts3EvalTestDeferred() for details on testing if a row is ** really a match, taking into account deferred tokens and NEAR operators. */ static void fts3EvalNextRow( Fts3Cursor *pCsr, /* FTS Cursor handle */ Fts3Expr *pExpr, /* Expr. to advance to next matching row */ int *pRc /* IN/OUT: Error code */ ){ if( *pRc==SQLITE_OK && pExpr->bEof==0 ){ int bDescDoclist = pCsr->bDesc; /* Used by DOCID_CMP() macro */ pExpr->bStart = 1; switch( pExpr->eType ){ case FTSQUERY_NEAR: case FTSQUERY_AND: { Fts3Expr *pLeft = pExpr->pLeft; Fts3Expr *pRight = pExpr->pRight; assert( !pLeft->bDeferred || !pRight->bDeferred ); if( pLeft->bDeferred ){ /* LHS is entirely deferred. So we assume it matches every row. ** Advance the RHS iterator to find the next row visited. */ fts3EvalNextRow(pCsr, pRight, pRc); pExpr->iDocid = pRight->iDocid; pExpr->bEof = pRight->bEof; }else if( pRight->bDeferred ){ /* RHS is entirely deferred. So we assume it matches every row. ** Advance the LHS iterator to find the next row visited. */ fts3EvalNextRow(pCsr, pLeft, pRc); pExpr->iDocid = pLeft->iDocid; pExpr->bEof = pLeft->bEof; }else{ /* Neither the RHS or LHS are deferred. */ fts3EvalNextRow(pCsr, pLeft, pRc); fts3EvalNextRow(pCsr, pRight, pRc); while( !pLeft->bEof && !pRight->bEof && *pRc==SQLITE_OK ){ sqlite3_int64 iDiff = DOCID_CMP(pLeft->iDocid, pRight->iDocid); if( iDiff==0 ) break; if( iDiff<0 ){ fts3EvalNextRow(pCsr, pLeft, pRc); }else{ fts3EvalNextRow(pCsr, pRight, pRc); } } pExpr->iDocid = pLeft->iDocid; pExpr->bEof = (pLeft->bEof || pRight->bEof); if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){ assert( pRight->eType==FTSQUERY_PHRASE ); if( pRight->pPhrase->doclist.aAll ){ Fts3Doclist *pDl = &pRight->pPhrase->doclist; while( *pRc==SQLITE_OK && pRight->bEof==0 ){ memset(pDl->pList, 0, pDl->nList); fts3EvalNextRow(pCsr, pRight, pRc); } } if( pLeft->pPhrase && pLeft->pPhrase->doclist.aAll ){ Fts3Doclist *pDl = &pLeft->pPhrase->doclist; while( *pRc==SQLITE_OK && pLeft->bEof==0 ){ memset(pDl->pList, 0, pDl->nList); fts3EvalNextRow(pCsr, pLeft, pRc); } } pRight->bEof = pLeft->bEof = 1; } } break; } case FTSQUERY_OR: { Fts3Expr *pLeft = pExpr->pLeft; Fts3Expr *pRight = pExpr->pRight; sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); assert_fts3_nc( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); assert_fts3_nc( pRight->bStart || pLeft->iDocid==pRight->iDocid ); if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ fts3EvalNextRow(pCsr, pLeft, pRc); }else if( pLeft->bEof || iCmp>0 ){ fts3EvalNextRow(pCsr, pRight, pRc); }else{ fts3EvalNextRow(pCsr, pLeft, pRc); fts3EvalNextRow(pCsr, pRight, pRc); } pExpr->bEof = (pLeft->bEof && pRight->bEof); iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ pExpr->iDocid = pLeft->iDocid; }else{ pExpr->iDocid = pRight->iDocid; } break; } case FTSQUERY_NOT: { Fts3Expr *pLeft = pExpr->pLeft; Fts3Expr *pRight = pExpr->pRight; if( pRight->bStart==0 ){ fts3EvalNextRow(pCsr, pRight, pRc); assert( *pRc!=SQLITE_OK || pRight->bStart ); } fts3EvalNextRow(pCsr, pLeft, pRc); if( pLeft->bEof==0 ){ while( !*pRc && !pRight->bEof && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0 ){ fts3EvalNextRow(pCsr, pRight, pRc); } } pExpr->iDocid = pLeft->iDocid; pExpr->bEof = pLeft->bEof; break; } default: { Fts3Phrase *pPhrase = pExpr->pPhrase; fts3EvalInvalidatePoslist(pPhrase); *pRc = fts3EvalPhraseNext(pCsr, pPhrase, &pExpr->bEof); pExpr->iDocid = pPhrase->doclist.iDocid; break; } } } } /* ** If *pRc is not SQLITE_OK, or if pExpr is not the root node of a NEAR ** cluster, then this function returns 1 immediately. ** ** Otherwise, it checks if the current row really does match the NEAR ** expression, using the data currently stored in the position lists ** (Fts3Expr->pPhrase.doclist.pList/nList) for each phrase in the expression. ** ** If the current row is a match, the position list associated with each ** phrase in the NEAR expression is edited in place to contain only those ** phrase instances sufficiently close to their peers to satisfy all NEAR ** constraints. In this case it returns 1. If the NEAR expression does not ** match the current row, 0 is returned. The position lists may or may not ** be edited if 0 is returned. */ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ int res = 1; /* The following block runs if pExpr is the root of a NEAR query. ** For example, the query: ** ** "w" NEAR "x" NEAR "y" NEAR "z" ** ** which is represented in tree form as: ** ** | ** +--NEAR--+ <-- root of NEAR query ** | | ** +--NEAR--+ "z" ** | | ** +--NEAR--+ "y" ** | | ** "w" "x" ** ** The right-hand child of a NEAR node is always a phrase. The ** left-hand child may be either a phrase or a NEAR node. There are ** no exceptions to this - it's the way the parser in fts3_expr.c works. */ if( *pRc==SQLITE_OK && pExpr->eType==FTSQUERY_NEAR && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) ){ Fts3Expr *p; sqlite3_int64 nTmp = 0; /* Bytes of temp space */ char *aTmp; /* Temp space for PoslistNearMerge() */ /* Allocate temporary working space. */ for(p=pExpr; p->pLeft; p=p->pLeft){ assert( p->pRight->pPhrase->doclist.nList>0 ); nTmp += p->pRight->pPhrase->doclist.nList; } nTmp += p->pPhrase->doclist.nList; aTmp = sqlite3_malloc64(nTmp*2); if( !aTmp ){ *pRc = SQLITE_NOMEM; res = 0; }else{ char *aPoslist = p->pPhrase->doclist.pList; int nToken = p->pPhrase->nToken; for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){ Fts3Phrase *pPhrase = p->pRight->pPhrase; int nNear = p->nNear; res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); } aPoslist = pExpr->pRight->pPhrase->doclist.pList; nToken = pExpr->pRight->pPhrase->nToken; for(p=pExpr->pLeft; p && res; p=p->pLeft){ int nNear; Fts3Phrase *pPhrase; assert( p->pParent && p->pParent->pLeft==p ); nNear = p->pParent->nNear; pPhrase = ( p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase ); res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); } } sqlite3_free(aTmp); } return res; } /* ** This function is a helper function for sqlite3Fts3EvalTestDeferred(). ** Assuming no error occurs or has occurred, It returns non-zero if the ** expression passed as the second argument matches the row that pCsr ** currently points to, or zero if it does not. ** ** If *pRc is not SQLITE_OK when this function is called, it is a no-op. ** If an error occurs during execution of this function, *pRc is set to ** the appropriate SQLite error code. In this case the returned value is ** undefined. */ static int fts3EvalTestExpr( Fts3Cursor *pCsr, /* FTS cursor handle */ Fts3Expr *pExpr, /* Expr to test. May or may not be root. */ int *pRc /* IN/OUT: Error code */ ){ int bHit = 1; /* Return value */ if( *pRc==SQLITE_OK ){ switch( pExpr->eType ){ case FTSQUERY_NEAR: case FTSQUERY_AND: bHit = ( fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) && fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) && fts3EvalNearTest(pExpr, pRc) ); /* If the NEAR expression does not match any rows, zero the doclist for ** all phrases involved in the NEAR. This is because the snippet(), ** offsets() and matchinfo() functions are not supposed to recognize ** any instances of phrases that are part of unmatched NEAR queries. ** For example if this expression: ** ** ... MATCH 'a OR (b NEAR c)' ** ** is matched against a row containing: ** ** 'a b d e' ** ** then any snippet() should ony highlight the "a" term, not the "b" ** (as "b" is part of a non-matching NEAR clause). */ if( bHit==0 && pExpr->eType==FTSQUERY_NEAR && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) ){ Fts3Expr *p; for(p=pExpr; p->pPhrase==0; p=p->pLeft){ if( p->pRight->iDocid==pCsr->iPrevId ){ fts3EvalInvalidatePoslist(p->pRight->pPhrase); } } if( p->iDocid==pCsr->iPrevId ){ fts3EvalInvalidatePoslist(p->pPhrase); } } break; case FTSQUERY_OR: { int bHit1 = fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc); int bHit2 = fts3EvalTestExpr(pCsr, pExpr->pRight, pRc); bHit = bHit1 || bHit2; break; } case FTSQUERY_NOT: bHit = ( fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) && !fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) ); break; default: { #ifndef SQLITE_DISABLE_FTS4_DEFERRED if( pCsr->pDeferred && (pExpr->bDeferred || ( pExpr->iDocid==pCsr->iPrevId && pExpr->pPhrase->doclist.pList ))){ Fts3Phrase *pPhrase = pExpr->pPhrase; if( pExpr->bDeferred ){ fts3EvalInvalidatePoslist(pPhrase); } *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase); bHit = (pPhrase->doclist.pList!=0); pExpr->iDocid = pCsr->iPrevId; }else #endif { bHit = ( pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId && pExpr->pPhrase->doclist.nList>0 ); } break; } } } return bHit; } /* ** This function is called as the second part of each xNext operation when ** iterating through the results of a full-text query. At this point the ** cursor points to a row that matches the query expression, with the ** following caveats: ** ** * Up until this point, "NEAR" operators in the expression have been ** treated as "AND". ** ** * Deferred tokens have not yet been considered. ** ** If *pRc is not SQLITE_OK when this function is called, it immediately ** returns 0. Otherwise, it tests whether or not after considering NEAR ** operators and deferred tokens the current row is still a match for the ** expression. It returns 1 if both of the following are true: ** ** 1. *pRc is SQLITE_OK when this function returns, and ** ** 2. After scanning the current FTS table row for the deferred tokens, ** it is determined that the row does *not* match the query. ** ** Or, if no error occurs and it seems the current row does match the FTS ** query, return 0. */ SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc){ int rc = *pRc; int bMiss = 0; if( rc==SQLITE_OK ){ /* If there are one or more deferred tokens, load the current row into ** memory and scan it to determine the position list for each deferred ** token. Then, see if this row is really a match, considering deferred ** tokens and NEAR operators (neither of which were taken into account ** earlier, by fts3EvalNextRow()). */ if( pCsr->pDeferred ){ rc = fts3CursorSeek(0, pCsr); if( rc==SQLITE_OK ){ rc = sqlite3Fts3CacheDeferredDoclists(pCsr); } } bMiss = (0==fts3EvalTestExpr(pCsr, pCsr->pExpr, &rc)); /* Free the position-lists accumulated for each deferred token above. */ sqlite3Fts3FreeDeferredDoclists(pCsr); *pRc = rc; } return (rc==SQLITE_OK && bMiss); } /* ** Advance to the next document that matches the FTS expression in ** Fts3Cursor.pExpr. */ static int fts3EvalNext(Fts3Cursor *pCsr){ int rc = SQLITE_OK; /* Return Code */ Fts3Expr *pExpr = pCsr->pExpr; assert( pCsr->isEof==0 ); if( pExpr==0 ){ pCsr->isEof = 1; }else{ do { if( pCsr->isRequireSeek==0 ){ sqlite3_reset(pCsr->pStmt); } assert( sqlite3_data_count(pCsr->pStmt)==0 ); fts3EvalNextRow(pCsr, pExpr, &rc); pCsr->isEof = pExpr->bEof; pCsr->isRequireSeek = 1; pCsr->isMatchinfoNeeded = 1; pCsr->iPrevId = pExpr->iDocid; }while( pCsr->isEof==0 && sqlite3Fts3EvalTestDeferred(pCsr, &rc) ); } /* Check if the cursor is past the end of the docid range specified ** by Fts3Cursor.iMinDocid/iMaxDocid. If so, set the EOF flag. */ if( rc==SQLITE_OK && ( (pCsr->bDesc==0 && pCsr->iPrevId>pCsr->iMaxDocid) || (pCsr->bDesc!=0 && pCsr->iPrevIdiMinDocid) )){ pCsr->isEof = 1; } return rc; } /* ** Restart interation for expression pExpr so that the next call to ** fts3EvalNext() visits the first row. Do not allow incremental ** loading or merging of phrase doclists for this iteration. ** ** If *pRc is other than SQLITE_OK when this function is called, it is ** a no-op. If an error occurs within this function, *pRc is set to an ** SQLite error code before returning. */ static void fts3EvalRestart( Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc ){ if( pExpr && *pRc==SQLITE_OK ){ Fts3Phrase *pPhrase = pExpr->pPhrase; if( pPhrase ){ fts3EvalInvalidatePoslist(pPhrase); if( pPhrase->bIncr ){ int i; for(i=0; inToken; i++){ Fts3PhraseToken *pToken = &pPhrase->aToken[i]; assert( pToken->pDeferred==0 ); if( pToken->pSegcsr ){ sqlite3Fts3MsrIncrRestart(pToken->pSegcsr); } } *pRc = fts3EvalPhraseStart(pCsr, 0, pPhrase); } pPhrase->doclist.pNextDocid = 0; pPhrase->doclist.iDocid = 0; pPhrase->pOrPoslist = 0; } pExpr->iDocid = 0; pExpr->bEof = 0; pExpr->bStart = 0; fts3EvalRestart(pCsr, pExpr->pLeft, pRc); fts3EvalRestart(pCsr, pExpr->pRight, pRc); } } /* ** After allocating the Fts3Expr.aMI[] array for each phrase in the ** expression rooted at pExpr, the cursor iterates through all rows matched ** by pExpr, calling this function for each row. This function increments ** the values in Fts3Expr.aMI[] according to the position-list currently ** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase ** expression nodes. */ static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){ if( pExpr ){ Fts3Phrase *pPhrase = pExpr->pPhrase; if( pPhrase && pPhrase->doclist.pList ){ int iCol = 0; char *p = pPhrase->doclist.pList; do{ u8 c = 0; int iCnt = 0; while( 0xFE & (*p | c) ){ if( (c&0x80)==0 ) iCnt++; c = *p++ & 0x80; } /* aMI[iCol*3 + 1] = Number of occurrences ** aMI[iCol*3 + 2] = Number of rows containing at least one instance */ pExpr->aMI[iCol*3 + 1] += iCnt; pExpr->aMI[iCol*3 + 2] += (iCnt>0); if( *p==0x00 ) break; p++; p += fts3GetVarint32(p, &iCol); }while( iColpLeft, nCol); fts3EvalUpdateCounts(pExpr->pRight, nCol); } } /* ** This is an sqlite3Fts3ExprIterate() callback. If the Fts3Expr.aMI[] array ** has not yet been allocated, allocate and zero it. Otherwise, just zero ** it. */ static int fts3AllocateMSI(Fts3Expr *pExpr, int iPhrase, void *pCtx){ Fts3Table *pTab = (Fts3Table*)pCtx; UNUSED_PARAMETER(iPhrase); if( pExpr->aMI==0 ){ pExpr->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32)); if( pExpr->aMI==0 ) return SQLITE_NOMEM; } memset(pExpr->aMI, 0, pTab->nColumn * 3 * sizeof(u32)); return SQLITE_OK; } /* ** Expression pExpr must be of type FTSQUERY_PHRASE. ** ** If it is not already allocated and populated, this function allocates and ** populates the Fts3Expr.aMI[] array for expression pExpr. If pExpr is part ** of a NEAR expression, then it also allocates and populates the same array ** for all other phrases that are part of the NEAR expression. ** ** SQLITE_OK is returned if the aMI[] array is successfully allocated and ** populated. Otherwise, if an error occurs, an SQLite error code is returned. */ static int fts3EvalGatherStats( Fts3Cursor *pCsr, /* Cursor object */ Fts3Expr *pExpr /* FTSQUERY_PHRASE expression */ ){ int rc = SQLITE_OK; /* Return code */ assert( pExpr->eType==FTSQUERY_PHRASE ); if( pExpr->aMI==0 ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; Fts3Expr *pRoot; /* Root of NEAR expression */ sqlite3_int64 iPrevId = pCsr->iPrevId; sqlite3_int64 iDocid; u8 bEof; /* Find the root of the NEAR expression */ pRoot = pExpr; while( pRoot->pParent && (pRoot->pParent->eType==FTSQUERY_NEAR || pRoot->bDeferred) ){ pRoot = pRoot->pParent; } iDocid = pRoot->iDocid; bEof = pRoot->bEof; assert( pRoot->bStart ); /* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */ rc = sqlite3Fts3ExprIterate(pRoot, fts3AllocateMSI, (void*)pTab); if( rc!=SQLITE_OK ) return rc; fts3EvalRestart(pCsr, pRoot, &rc); while( pCsr->isEof==0 && rc==SQLITE_OK ){ do { /* Ensure the %_content statement is reset. */ if( pCsr->isRequireSeek==0 ) sqlite3_reset(pCsr->pStmt); assert( sqlite3_data_count(pCsr->pStmt)==0 ); /* Advance to the next document */ fts3EvalNextRow(pCsr, pRoot, &rc); pCsr->isEof = pRoot->bEof; pCsr->isRequireSeek = 1; pCsr->isMatchinfoNeeded = 1; pCsr->iPrevId = pRoot->iDocid; }while( pCsr->isEof==0 && pRoot->eType==FTSQUERY_NEAR && sqlite3Fts3EvalTestDeferred(pCsr, &rc) ); if( rc==SQLITE_OK && pCsr->isEof==0 ){ fts3EvalUpdateCounts(pRoot, pTab->nColumn); } } pCsr->isEof = 0; pCsr->iPrevId = iPrevId; if( bEof ){ pRoot->bEof = bEof; }else{ /* Caution: pRoot may iterate through docids in ascending or descending ** order. For this reason, even though it seems more defensive, the ** do loop can not be written: ** ** do {...} while( pRoot->iDocidbEof==0 ); if( pRoot->bEof ) rc = FTS_CORRUPT_VTAB; }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK ); } } return rc; } /* ** This function is used by the matchinfo() module to query a phrase ** expression node for the following information: ** ** 1. The total number of occurrences of the phrase in each column of ** the FTS table (considering all rows), and ** ** 2. For each column, the number of rows in the table for which the ** column contains at least one instance of the phrase. ** ** If no error occurs, SQLITE_OK is returned and the values for each column ** written into the array aiOut as follows: ** ** aiOut[iCol*3 + 1] = Number of occurrences ** aiOut[iCol*3 + 2] = Number of rows containing at least one instance ** ** Caveats: ** ** * If a phrase consists entirely of deferred tokens, then all output ** values are set to the number of documents in the table. In other ** words we assume that very common tokens occur exactly once in each ** column of each row of the table. ** ** * If a phrase contains some deferred tokens (and some non-deferred ** tokens), count the potential occurrence identified by considering ** the non-deferred tokens instead of actual phrase occurrences. ** ** * If the phrase is part of a NEAR expression, then only phrase instances ** that meet the NEAR constraint are included in the counts. */ SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats( Fts3Cursor *pCsr, /* FTS cursor handle */ Fts3Expr *pExpr, /* Phrase expression */ u32 *aiOut /* Array to write results into (see above) */ ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int rc = SQLITE_OK; int iCol; if( pExpr->bDeferred && pExpr->pParent->eType!=FTSQUERY_NEAR ){ assert( pCsr->nDoc>0 ); for(iCol=0; iColnColumn; iCol++){ aiOut[iCol*3 + 1] = (u32)pCsr->nDoc; aiOut[iCol*3 + 2] = (u32)pCsr->nDoc; } }else{ rc = fts3EvalGatherStats(pCsr, pExpr); if( rc==SQLITE_OK ){ assert( pExpr->aMI ); for(iCol=0; iColnColumn; iCol++){ aiOut[iCol*3 + 1] = pExpr->aMI[iCol*3 + 1]; aiOut[iCol*3 + 2] = pExpr->aMI[iCol*3 + 2]; } } } return rc; } /* ** The expression pExpr passed as the second argument to this function ** must be of type FTSQUERY_PHRASE. ** ** The returned value is either NULL or a pointer to a buffer containing ** a position-list indicating the occurrences of the phrase in column iCol ** of the current row. ** ** More specifically, the returned buffer contains 1 varint for each ** occurrence of the phrase in the column, stored using the normal (delta+2) ** compression and is terminated by either an 0x01 or 0x00 byte. For example, ** if the requested column contains "a b X c d X X" and the position-list ** for 'X' is requested, the buffer returned may contain: ** ** 0x04 0x05 0x03 0x01 or 0x04 0x05 0x03 0x00 ** ** This function works regardless of whether or not the phrase is deferred, ** incremental, or neither. */ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist( Fts3Cursor *pCsr, /* FTS3 cursor object */ Fts3Expr *pExpr, /* Phrase to return doclist for */ int iCol, /* Column to return position list for */ char **ppOut /* OUT: Pointer to position list */ ){ Fts3Phrase *pPhrase = pExpr->pPhrase; Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; char *pIter; int iThis; sqlite3_int64 iDocid; /* If this phrase is applies specifically to some column other than ** column iCol, return a NULL pointer. */ *ppOut = 0; assert( iCol>=0 && iColnColumn ); if( (pPhrase->iColumnnColumn && pPhrase->iColumn!=iCol) ){ return SQLITE_OK; } iDocid = pExpr->iDocid; pIter = pPhrase->doclist.pList; if( iDocid!=pCsr->iPrevId || pExpr->bEof ){ int rc = SQLITE_OK; int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */ int bOr = 0; u8 bTreeEof = 0; Fts3Expr *p; /* Used to iterate from pExpr to root */ Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */ Fts3Expr *pRun; /* Closest non-deferred ancestor of pNear */ int bMatch; /* Check if this phrase descends from an OR expression node. If not, ** return NULL. Otherwise, the entry that corresponds to docid ** pCsr->iPrevId may lie earlier in the doclist buffer. Or, if the ** tree that the node is part of has been marked as EOF, but the node ** itself is not EOF, then it may point to an earlier entry. */ pNear = pExpr; for(p=pExpr->pParent; p; p=p->pParent){ if( p->eType==FTSQUERY_OR ) bOr = 1; if( p->eType==FTSQUERY_NEAR ) pNear = p; if( p->bEof ) bTreeEof = 1; } if( bOr==0 ) return SQLITE_OK; pRun = pNear; while( pRun->bDeferred ){ assert( pRun->pParent ); pRun = pRun->pParent; } /* This is the descendent of an OR node. In this case we cannot use ** an incremental phrase. Load the entire doclist for the phrase ** into memory in this case. */ if( pPhrase->bIncr ){ int bEofSave = pRun->bEof; fts3EvalRestart(pCsr, pRun, &rc); while( rc==SQLITE_OK && !pRun->bEof ){ fts3EvalNextRow(pCsr, pRun, &rc); if( bEofSave==0 && pRun->iDocid==iDocid ) break; } assert( rc!=SQLITE_OK || pPhrase->bIncr==0 ); if( rc==SQLITE_OK && pRun->bEof!=bEofSave ){ rc = FTS_CORRUPT_VTAB; } } if( bTreeEof ){ while( rc==SQLITE_OK && !pRun->bEof ){ fts3EvalNextRow(pCsr, pRun, &rc); } } if( rc!=SQLITE_OK ) return rc; bMatch = 1; for(p=pNear; p; p=p->pLeft){ u8 bEof = 0; Fts3Expr *pTest = p; Fts3Phrase *pPh; assert( pTest->eType==FTSQUERY_NEAR || pTest->eType==FTSQUERY_PHRASE ); if( pTest->eType==FTSQUERY_NEAR ) pTest = pTest->pRight; assert( pTest->eType==FTSQUERY_PHRASE ); pPh = pTest->pPhrase; pIter = pPh->pOrPoslist; iDocid = pPh->iOrDocid; if( pCsr->bDesc==bDescDoclist ){ bEof = !pPh->doclist.nAll || (pIter >= (pPh->doclist.aAll + pPh->doclist.nAll)); while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){ sqlite3Fts3DoclistNext( bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll, &pIter, &iDocid, &bEof ); } }else{ bEof = !pPh->doclist.nAll || (pIter && pIter<=pPh->doclist.aAll); while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){ int dummy; sqlite3Fts3DoclistPrev( bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll, &pIter, &iDocid, &dummy, &bEof ); } } pPh->pOrPoslist = pIter; pPh->iOrDocid = iDocid; if( bEof || iDocid!=pCsr->iPrevId ) bMatch = 0; } if( bMatch ){ pIter = pPhrase->pOrPoslist; }else{ pIter = 0; } } if( pIter==0 ) return SQLITE_OK; if( *pIter==0x01 ){ pIter++; pIter += fts3GetVarint32(pIter, &iThis); }else{ iThis = 0; } while( iThisdoclist, and ** * any Fts3MultiSegReader objects held by phrase tokens. */ SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *pPhrase){ if( pPhrase ){ int i; sqlite3_free(pPhrase->doclist.aAll); fts3EvalInvalidatePoslist(pPhrase); memset(&pPhrase->doclist, 0, sizeof(Fts3Doclist)); for(i=0; inToken; i++){ fts3SegReaderCursorFree(pPhrase->aToken[i].pSegcsr); pPhrase->aToken[i].pSegcsr = 0; } } } /* ** Return SQLITE_CORRUPT_VTAB. */ #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3Fts3Corrupt(){ return SQLITE_CORRUPT_VTAB; } #endif #if !SQLITE_CORE /* ** Initialize API pointer table, if required. */ #ifdef _WIN32 __declspec(dllexport) #endif SQLITE_API int sqlite3_fts3_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi) return sqlite3Fts3Init(db); } #endif #endif /************** End of fts3.c ************************************************/ /************** Begin file fts3_aux.c ****************************************/ /* ** 2011 Jan 27 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** */ /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include */ /* #include */ typedef struct Fts3auxTable Fts3auxTable; typedef struct Fts3auxCursor Fts3auxCursor; struct Fts3auxTable { sqlite3_vtab base; /* Base class used by SQLite core */ Fts3Table *pFts3Tab; }; struct Fts3auxCursor { sqlite3_vtab_cursor base; /* Base class used by SQLite core */ Fts3MultiSegReader csr; /* Must be right after "base" */ Fts3SegFilter filter; char *zStop; int nStop; /* Byte-length of string zStop */ int iLangid; /* Language id to query */ int isEof; /* True if cursor is at EOF */ sqlite3_int64 iRowid; /* Current rowid */ int iCol; /* Current value of 'col' column */ int nStat; /* Size of aStat[] array */ struct Fts3auxColstats { sqlite3_int64 nDoc; /* 'documents' values for current csr row */ sqlite3_int64 nOcc; /* 'occurrences' values for current csr row */ } *aStat; }; /* ** Schema of the terms table. */ #define FTS3_AUX_SCHEMA \ "CREATE TABLE x(term, col, documents, occurrences, languageid HIDDEN)" /* ** This function does all the work for both the xConnect and xCreate methods. ** These tables have no persistent representation of their own, so xConnect ** and xCreate are identical operations. */ static int fts3auxConnectMethod( sqlite3 *db, /* Database connection */ void *pUnused, /* Unused */ int argc, /* Number of elements in argv array */ const char * const *argv, /* xCreate/xConnect argument array */ sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ char const *zDb; /* Name of database (e.g. "main") */ char const *zFts3; /* Name of fts3 table */ int nDb; /* Result of strlen(zDb) */ int nFts3; /* Result of strlen(zFts3) */ sqlite3_int64 nByte; /* Bytes of space to allocate here */ int rc; /* value returned by declare_vtab() */ Fts3auxTable *p; /* Virtual table object to return */ UNUSED_PARAMETER(pUnused); /* The user should invoke this in one of two forms: ** ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table); ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table-db, fts4-table); */ if( argc!=4 && argc!=5 ) goto bad_args; zDb = argv[1]; nDb = (int)strlen(zDb); if( argc==5 ){ if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){ zDb = argv[3]; nDb = (int)strlen(zDb); zFts3 = argv[4]; }else{ goto bad_args; } }else{ zFts3 = argv[3]; } nFts3 = (int)strlen(zFts3); rc = sqlite3_declare_vtab(db, FTS3_AUX_SCHEMA); if( rc!=SQLITE_OK ) return rc; nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; p = (Fts3auxTable *)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, nByte); p->pFts3Tab = (Fts3Table *)&p[1]; p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; p->pFts3Tab->db = db; p->pFts3Tab->nIndex = 1; memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); *ppVtab = (sqlite3_vtab *)p; return SQLITE_OK; bad_args: sqlite3Fts3ErrMsg(pzErr, "invalid arguments to fts4aux constructor"); return SQLITE_ERROR; } /* ** This function does the work for both the xDisconnect and xDestroy methods. ** These tables have no persistent representation of their own, so xDisconnect ** and xDestroy are identical operations. */ static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){ Fts3auxTable *p = (Fts3auxTable *)pVtab; Fts3Table *pFts3 = p->pFts3Tab; int i; /* Free any prepared statements held */ for(i=0; iaStmt); i++){ sqlite3_finalize(pFts3->aStmt[i]); } sqlite3_free(pFts3->zSegmentsTbl); sqlite3_free(p); return SQLITE_OK; } #define FTS4AUX_EQ_CONSTRAINT 1 #define FTS4AUX_GE_CONSTRAINT 2 #define FTS4AUX_LE_CONSTRAINT 4 /* ** xBestIndex - Analyze a WHERE and ORDER BY clause. */ static int fts3auxBestIndexMethod( sqlite3_vtab *pVTab, sqlite3_index_info *pInfo ){ int i; int iEq = -1; int iGe = -1; int iLe = -1; int iLangid = -1; int iNext = 1; /* Next free argvIndex value */ UNUSED_PARAMETER(pVTab); /* This vtab delivers always results in "ORDER BY term ASC" order. */ if( pInfo->nOrderBy==1 && pInfo->aOrderBy[0].iColumn==0 && pInfo->aOrderBy[0].desc==0 ){ pInfo->orderByConsumed = 1; } /* Search for equality and range constraints on the "term" column. ** And equality constraints on the hidden "languageid" column. */ for(i=0; inConstraint; i++){ if( pInfo->aConstraint[i].usable ){ int op = pInfo->aConstraint[i].op; int iCol = pInfo->aConstraint[i].iColumn; if( iCol==0 ){ if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i; if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i; if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i; if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i; if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i; } if( iCol==4 ){ if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iLangid = i; } } } if( iEq>=0 ){ pInfo->idxNum = FTS4AUX_EQ_CONSTRAINT; pInfo->aConstraintUsage[iEq].argvIndex = iNext++; pInfo->estimatedCost = 5; }else{ pInfo->idxNum = 0; pInfo->estimatedCost = 20000; if( iGe>=0 ){ pInfo->idxNum += FTS4AUX_GE_CONSTRAINT; pInfo->aConstraintUsage[iGe].argvIndex = iNext++; pInfo->estimatedCost /= 2; } if( iLe>=0 ){ pInfo->idxNum += FTS4AUX_LE_CONSTRAINT; pInfo->aConstraintUsage[iLe].argvIndex = iNext++; pInfo->estimatedCost /= 2; } } if( iLangid>=0 ){ pInfo->aConstraintUsage[iLangid].argvIndex = iNext++; pInfo->estimatedCost--; } return SQLITE_OK; } /* ** xOpen - Open a cursor. */ static int fts3auxOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ Fts3auxCursor *pCsr; /* Pointer to cursor object to return */ UNUSED_PARAMETER(pVTab); pCsr = (Fts3auxCursor *)sqlite3_malloc(sizeof(Fts3auxCursor)); if( !pCsr ) return SQLITE_NOMEM; memset(pCsr, 0, sizeof(Fts3auxCursor)); *ppCsr = (sqlite3_vtab_cursor *)pCsr; return SQLITE_OK; } /* ** xClose - Close a cursor. */ static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){ Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; sqlite3Fts3SegmentsClose(pFts3); sqlite3Fts3SegReaderFinish(&pCsr->csr); sqlite3_free((void *)pCsr->filter.zTerm); sqlite3_free(pCsr->zStop); sqlite3_free(pCsr->aStat); sqlite3_free(pCsr); return SQLITE_OK; } static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){ if( nSize>pCsr->nStat ){ struct Fts3auxColstats *aNew; aNew = (struct Fts3auxColstats *)sqlite3_realloc64(pCsr->aStat, sizeof(struct Fts3auxColstats) * nSize ); if( aNew==0 ) return SQLITE_NOMEM; memset(&aNew[pCsr->nStat], 0, sizeof(struct Fts3auxColstats) * (nSize - pCsr->nStat) ); pCsr->aStat = aNew; pCsr->nStat = nSize; } return SQLITE_OK; } /* ** xNext - Advance the cursor to the next row, if any. */ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){ Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; int rc; /* Increment our pretend rowid value. */ pCsr->iRowid++; for(pCsr->iCol++; pCsr->iColnStat; pCsr->iCol++){ if( pCsr->aStat[pCsr->iCol].nDoc>0 ) return SQLITE_OK; } rc = sqlite3Fts3SegReaderStep(pFts3, &pCsr->csr); if( rc==SQLITE_ROW ){ int i = 0; int nDoclist = pCsr->csr.nDoclist; char *aDoclist = pCsr->csr.aDoclist; int iCol; int eState = 0; if( pCsr->zStop ){ int n = (pCsr->nStopcsr.nTerm) ? pCsr->nStop : pCsr->csr.nTerm; int mc = memcmp(pCsr->zStop, pCsr->csr.zTerm, n); if( mc<0 || (mc==0 && pCsr->csr.nTerm>pCsr->nStop) ){ pCsr->isEof = 1; return SQLITE_OK; } } if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM; memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat); iCol = 0; rc = SQLITE_OK; while( iaStat[0].nDoc++; eState = 1; iCol = 0; break; /* State 1. In this state we are expecting either a 1, indicating ** that the following integer will be a column number, or the ** start of a position list for column 0. ** ** The only difference between state 1 and state 2 is that if the ** integer encountered in state 1 is not 0 or 1, then we need to ** increment the column 0 "nDoc" count for this term. */ case 1: assert( iCol==0 ); if( v>1 ){ pCsr->aStat[1].nDoc++; } eState = 2; /* fall through */ case 2: if( v==0 ){ /* 0x00. Next integer will be a docid. */ eState = 0; }else if( v==1 ){ /* 0x01. Next integer will be a column number. */ eState = 3; }else{ /* 2 or greater. A position. */ pCsr->aStat[iCol+1].nOcc++; pCsr->aStat[0].nOcc++; } break; /* State 3. The integer just read is a column number. */ default: assert( eState==3 ); iCol = (int)v; if( iCol<1 ){ rc = SQLITE_CORRUPT_VTAB; break; } if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM; pCsr->aStat[iCol+1].nDoc++; eState = 2; break; } } pCsr->iCol = 0; }else{ pCsr->isEof = 1; } return rc; } /* ** xFilter - Initialize a cursor to point at the start of its data. */ static int fts3auxFilterMethod( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, /* Strategy index */ const char *idxStr, /* Unused */ int nVal, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; int rc; int isScan = 0; int iLangVal = 0; /* Language id to query */ int iEq = -1; /* Index of term=? value in apVal */ int iGe = -1; /* Index of term>=? value in apVal */ int iLe = -1; /* Index of term<=? value in apVal */ int iLangid = -1; /* Index of languageid=? value in apVal */ int iNext = 0; UNUSED_PARAMETER(nVal); UNUSED_PARAMETER(idxStr); assert( idxStr==0 ); assert( idxNum==FTS4AUX_EQ_CONSTRAINT || idxNum==0 || idxNum==FTS4AUX_LE_CONSTRAINT || idxNum==FTS4AUX_GE_CONSTRAINT || idxNum==(FTS4AUX_LE_CONSTRAINT|FTS4AUX_GE_CONSTRAINT) ); if( idxNum==FTS4AUX_EQ_CONSTRAINT ){ iEq = iNext++; }else{ isScan = 1; if( idxNum & FTS4AUX_GE_CONSTRAINT ){ iGe = iNext++; } if( idxNum & FTS4AUX_LE_CONSTRAINT ){ iLe = iNext++; } } if( iNextfilter.zTerm); sqlite3Fts3SegReaderFinish(&pCsr->csr); sqlite3_free((void *)pCsr->filter.zTerm); sqlite3_free(pCsr->aStat); sqlite3_free(pCsr->zStop); memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN; if( iEq>=0 || iGe>=0 ){ const unsigned char *zStr = sqlite3_value_text(apVal[0]); assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) ); if( zStr ){ pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr); if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM; pCsr->filter.nTerm = (int)strlen(pCsr->filter.zTerm); } } if( iLe>=0 ){ pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe])); if( pCsr->zStop==0 ) return SQLITE_NOMEM; pCsr->nStop = (int)strlen(pCsr->zStop); } if( iLangid>=0 ){ iLangVal = sqlite3_value_int(apVal[iLangid]); /* If the user specified a negative value for the languageid, use zero ** instead. This works, as the "languageid=?" constraint will also ** be tested by the VDBE layer. The test will always be false (since ** this module will not return a row with a negative languageid), and ** so the overall query will return zero rows. */ if( iLangVal<0 ) iLangVal = 0; } pCsr->iLangid = iLangVal; rc = sqlite3Fts3SegReaderCursor(pFts3, iLangVal, 0, FTS3_SEGCURSOR_ALL, pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr ); if( rc==SQLITE_OK ){ rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter); } if( rc==SQLITE_OK ) rc = fts3auxNextMethod(pCursor); return rc; } /* ** xEof - Return true if the cursor is at EOF, or false otherwise. */ static int fts3auxEofMethod(sqlite3_vtab_cursor *pCursor){ Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; return pCsr->isEof; } /* ** xColumn - Return a column value. */ static int fts3auxColumnMethod( sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ int iCol /* Index of column to read value from */ ){ Fts3auxCursor *p = (Fts3auxCursor *)pCursor; assert( p->isEof==0 ); switch( iCol ){ case 0: /* term */ sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT); break; case 1: /* col */ if( p->iCol ){ sqlite3_result_int(pCtx, p->iCol-1); }else{ sqlite3_result_text(pCtx, "*", -1, SQLITE_STATIC); } break; case 2: /* documents */ sqlite3_result_int64(pCtx, p->aStat[p->iCol].nDoc); break; case 3: /* occurrences */ sqlite3_result_int64(pCtx, p->aStat[p->iCol].nOcc); break; default: /* languageid */ assert( iCol==4 ); sqlite3_result_int(pCtx, p->iLangid); break; } return SQLITE_OK; } /* ** xRowid - Return the current rowid for the cursor. */ static int fts3auxRowidMethod( sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ sqlite_int64 *pRowid /* OUT: Rowid value */ ){ Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; *pRowid = pCsr->iRowid; return SQLITE_OK; } /* ** Register the fts3aux module with database connection db. Return SQLITE_OK ** if successful or an error code if sqlite3_create_module() fails. */ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){ static const sqlite3_module fts3aux_module = { 0, /* iVersion */ fts3auxConnectMethod, /* xCreate */ fts3auxConnectMethod, /* xConnect */ fts3auxBestIndexMethod, /* xBestIndex */ fts3auxDisconnectMethod, /* xDisconnect */ fts3auxDisconnectMethod, /* xDestroy */ fts3auxOpenMethod, /* xOpen */ fts3auxCloseMethod, /* xClose */ fts3auxFilterMethod, /* xFilter */ fts3auxNextMethod, /* xNext */ fts3auxEofMethod, /* xEof */ fts3auxColumnMethod, /* xColumn */ fts3auxRowidMethod, /* xRowid */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindFunction */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ 0 /* xIntegrity */ }; int rc; /* Return code */ rc = sqlite3_create_module(db, "fts4aux", &fts3aux_module, 0); return rc; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ /************** End of fts3_aux.c ********************************************/ /************** Begin file fts3_expr.c ***************************************/ /* ** 2008 Nov 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This module contains code that implements a parser for fts3 query strings ** (the right-hand argument to the MATCH operator). Because the supported ** syntax is relatively simple, the whole tokenizer/parser system is ** hand-coded. */ /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* ** By default, this module parses the legacy syntax that has been ** traditionally used by fts3. Or, if SQLITE_ENABLE_FTS3_PARENTHESIS ** is defined, then it uses the new syntax. The differences between ** the new and the old syntaxes are: ** ** a) The new syntax supports parenthesis. The old does not. ** ** b) The new syntax supports the AND and NOT operators. The old does not. ** ** c) The old syntax supports the "-" token qualifier. This is not ** supported by the new syntax (it is replaced by the NOT operator). ** ** d) When using the old syntax, the OR operator has a greater precedence ** than an implicit AND. When using the new, both implicity and explicit ** AND operators have a higher precedence than OR. ** ** If compiled with SQLITE_TEST defined, then this module exports the ** symbol "int sqlite3_fts3_enable_parentheses". Setting this variable ** to zero causes the module to use the old syntax. If it is set to ** non-zero the new syntax is activated. This is so both syntaxes can ** be tested using a single build of testfixture. ** ** The following describes the syntax supported by the fts3 MATCH ** operator in a similar format to that used by the lemon parser ** generator. This module does not use actually lemon, it uses a ** custom parser. ** ** query ::= andexpr (OR andexpr)*. ** ** andexpr ::= notexpr (AND? notexpr)*. ** ** notexpr ::= nearexpr (NOT nearexpr|-TOKEN)*. ** notexpr ::= LP query RP. ** ** nearexpr ::= phrase (NEAR distance_opt nearexpr)*. ** ** distance_opt ::= . ** distance_opt ::= / INTEGER. ** ** phrase ::= TOKEN. ** phrase ::= COLUMN:TOKEN. ** phrase ::= "TOKEN TOKEN TOKEN...". */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_fts3_enable_parentheses = 0; #else # ifdef SQLITE_ENABLE_FTS3_PARENTHESIS # define sqlite3_fts3_enable_parentheses 1 # else # define sqlite3_fts3_enable_parentheses 0 # endif #endif /* ** Default span for NEAR operators. */ #define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10 /* #include */ /* #include */ /* ** isNot: ** This variable is used by function getNextNode(). When getNextNode() is ** called, it sets ParseContext.isNot to true if the 'next node' is a ** FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the ** FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to ** zero. */ typedef struct ParseContext ParseContext; struct ParseContext { sqlite3_tokenizer *pTokenizer; /* Tokenizer module */ int iLangid; /* Language id used with tokenizer */ const char **azCol; /* Array of column names for fts3 table */ int bFts4; /* True to allow FTS4-only syntax */ int nCol; /* Number of entries in azCol[] */ int iDefaultCol; /* Default column to query */ int isNot; /* True if getNextNode() sees a unary - */ sqlite3_context *pCtx; /* Write error message here */ int nNest; /* Number of nested brackets */ }; /* ** This function is equivalent to the standard isspace() function. ** ** The standard isspace() can be awkward to use safely, because although it ** is defined to accept an argument of type int, its behavior when passed ** an integer that falls outside of the range of the unsigned char type ** is undefined (and sometimes, "undefined" means segfault). This wrapper ** is defined to accept an argument of type char, and always returns 0 for ** any values that fall outside of the range of the unsigned char type (i.e. ** negative values). */ static int fts3isspace(char c){ return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; } /* ** Allocate nByte bytes of memory using sqlite3_malloc(). If successful, ** zero the memory before returning a pointer to it. If unsuccessful, ** return NULL. */ SQLITE_PRIVATE void *sqlite3Fts3MallocZero(sqlite3_int64 nByte){ void *pRet = sqlite3_malloc64(nByte); if( pRet ) memset(pRet, 0, nByte); return pRet; } SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer( sqlite3_tokenizer *pTokenizer, int iLangid, const char *z, int n, sqlite3_tokenizer_cursor **ppCsr ){ sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; sqlite3_tokenizer_cursor *pCsr = 0; int rc; rc = pModule->xOpen(pTokenizer, z, n, &pCsr); assert( rc==SQLITE_OK || pCsr==0 ); if( rc==SQLITE_OK ){ pCsr->pTokenizer = pTokenizer; if( pModule->iVersion>=1 ){ rc = pModule->xLanguageid(pCsr, iLangid); if( rc!=SQLITE_OK ){ pModule->xClose(pCsr); pCsr = 0; } } } *ppCsr = pCsr; return rc; } /* ** Function getNextNode(), which is called by fts3ExprParse(), may itself ** call fts3ExprParse(). So this forward declaration is required. */ static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *); /* ** Extract the next token from buffer z (length n) using the tokenizer ** and other information (column names etc.) in pParse. Create an Fts3Expr ** structure of type FTSQUERY_PHRASE containing a phrase consisting of this ** single token and set *ppExpr to point to it. If the end of the buffer is ** reached before a token is found, set *ppExpr to zero. It is the ** responsibility of the caller to eventually deallocate the allocated ** Fts3Expr structure (if any) by passing it to sqlite3_free(). ** ** Return SQLITE_OK if successful, or SQLITE_NOMEM if a memory allocation ** fails. */ static int getNextToken( ParseContext *pParse, /* fts3 query parse context */ int iCol, /* Value for Fts3Phrase.iColumn */ const char *z, int n, /* Input string */ Fts3Expr **ppExpr, /* OUT: expression */ int *pnConsumed /* OUT: Number of bytes consumed */ ){ sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; int rc; sqlite3_tokenizer_cursor *pCursor; Fts3Expr *pRet = 0; int i = 0; /* Set variable i to the maximum number of bytes of input to tokenize. */ for(i=0; iiLangid, z, i, &pCursor); if( rc==SQLITE_OK ){ const char *zToken; int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; sqlite3_int64 nByte; /* total space to allocate */ rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); if( rc==SQLITE_OK ){ nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte); if( !pRet ){ rc = SQLITE_NOMEM; }else{ pRet->eType = FTSQUERY_PHRASE; pRet->pPhrase = (Fts3Phrase *)&pRet[1]; pRet->pPhrase->nToken = 1; pRet->pPhrase->iColumn = iCol; pRet->pPhrase->aToken[0].n = nToken; pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1]; memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken); if( iEndpPhrase->aToken[0].isPrefix = 1; iEnd++; } while( 1 ){ if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){ pParse->isNot = 1; iStart--; }else if( pParse->bFts4 && iStart>0 && z[iStart-1]=='^' ){ pRet->pPhrase->aToken[0].bFirst = 1; iStart--; }else{ break; } } } *pnConsumed = iEnd; }else if( i && rc==SQLITE_DONE ){ rc = SQLITE_OK; } pModule->xClose(pCursor); } *ppExpr = pRet; return rc; } /* ** Enlarge a memory allocation. If an out-of-memory allocation occurs, ** then free the old allocation. */ static void *fts3ReallocOrFree(void *pOrig, sqlite3_int64 nNew){ void *pRet = sqlite3_realloc64(pOrig, nNew); if( !pRet ){ sqlite3_free(pOrig); } return pRet; } /* ** Buffer zInput, length nInput, contains the contents of a quoted string ** that appeared as part of an fts3 query expression. Neither quote character ** is included in the buffer. This function attempts to tokenize the entire ** input buffer and create an Fts3Expr structure of type FTSQUERY_PHRASE ** containing the results. ** ** If successful, SQLITE_OK is returned and *ppExpr set to point at the ** allocated Fts3Expr structure. Otherwise, either SQLITE_NOMEM (out of memory ** error) or SQLITE_ERROR (tokenization error) is returned and *ppExpr set ** to 0. */ static int getNextString( ParseContext *pParse, /* fts3 query parse context */ const char *zInput, int nInput, /* Input string */ Fts3Expr **ppExpr /* OUT: expression */ ){ sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; int rc; Fts3Expr *p = 0; sqlite3_tokenizer_cursor *pCursor = 0; char *zTemp = 0; int nTemp = 0; const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase); int nToken = 0; /* The final Fts3Expr data structure, including the Fts3Phrase, ** Fts3PhraseToken structures token buffers are all stored as a single ** allocation so that the expression can be freed with a single call to ** sqlite3_free(). Setting this up requires a two pass approach. ** ** The first pass, in the block below, uses a tokenizer cursor to iterate ** through the tokens in the expression. This pass uses fts3ReallocOrFree() ** to assemble data in two dynamic buffers: ** ** Buffer p: Points to the Fts3Expr structure, followed by the Fts3Phrase ** structure, followed by the array of Fts3PhraseToken ** structures. This pass only populates the Fts3PhraseToken array. ** ** Buffer zTemp: Contains copies of all tokens. ** ** The second pass, in the block that begins "if( rc==SQLITE_DONE )" below, ** appends buffer zTemp to buffer p, and fills in the Fts3Expr and Fts3Phrase ** structures. */ rc = sqlite3Fts3OpenTokenizer( pTokenizer, pParse->iLangid, zInput, nInput, &pCursor); if( rc==SQLITE_OK ){ int ii; for(ii=0; rc==SQLITE_OK; ii++){ const char *zByte; int nByte = 0, iBegin = 0, iEnd = 0, iPos = 0; rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos); if( rc==SQLITE_OK ){ Fts3PhraseToken *pToken; p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken)); if( !p ) goto no_mem; zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte); if( !zTemp ) goto no_mem; assert( nToken==ii ); pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii]; memset(pToken, 0, sizeof(Fts3PhraseToken)); memcpy(&zTemp[nTemp], zByte, nByte); nTemp += nByte; pToken->n = nByte; pToken->isPrefix = (iEndbFirst = (iBegin>0 && zInput[iBegin-1]=='^'); nToken = ii+1; } } pModule->xClose(pCursor); pCursor = 0; } if( rc==SQLITE_DONE ){ int jj; char *zBuf = 0; p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp); if( !p ) goto no_mem; memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p); p->eType = FTSQUERY_PHRASE; p->pPhrase = (Fts3Phrase *)&p[1]; p->pPhrase->iColumn = pParse->iDefaultCol; p->pPhrase->nToken = nToken; zBuf = (char *)&p->pPhrase->aToken[nToken]; if( zTemp ){ memcpy(zBuf, zTemp, nTemp); sqlite3_free(zTemp); }else{ assert( nTemp==0 ); } for(jj=0; jjpPhrase->nToken; jj++){ p->pPhrase->aToken[jj].z = zBuf; zBuf += p->pPhrase->aToken[jj].n; } rc = SQLITE_OK; } *ppExpr = p; return rc; no_mem: if( pCursor ){ pModule->xClose(pCursor); } sqlite3_free(zTemp); sqlite3_free(p); *ppExpr = 0; return SQLITE_NOMEM; } /* ** The output variable *ppExpr is populated with an allocated Fts3Expr ** structure, or set to 0 if the end of the input buffer is reached. ** ** Returns an SQLite error code. SQLITE_OK if everything works, SQLITE_NOMEM ** if a malloc failure occurs, or SQLITE_ERROR if a parse error is encountered. ** If SQLITE_ERROR is returned, pContext is populated with an error message. */ static int getNextNode( ParseContext *pParse, /* fts3 query parse context */ const char *z, int n, /* Input string */ Fts3Expr **ppExpr, /* OUT: expression */ int *pnConsumed /* OUT: Number of bytes consumed */ ){ static const struct Fts3Keyword { char *z; /* Keyword text */ unsigned char n; /* Length of the keyword */ unsigned char parenOnly; /* Only valid in paren mode */ unsigned char eType; /* Keyword code */ } aKeyword[] = { { "OR" , 2, 0, FTSQUERY_OR }, { "AND", 3, 1, FTSQUERY_AND }, { "NOT", 3, 1, FTSQUERY_NOT }, { "NEAR", 4, 0, FTSQUERY_NEAR } }; int ii; int iCol; int iColLen; int rc; Fts3Expr *pRet = 0; const char *zInput = z; int nInput = n; pParse->isNot = 0; /* Skip over any whitespace before checking for a keyword, an open or ** close bracket, or a quoted string. */ while( nInput>0 && fts3isspace(*zInput) ){ nInput--; zInput++; } if( nInput==0 ){ return SQLITE_DONE; } /* See if we are dealing with a keyword. */ for(ii=0; ii<(int)(sizeof(aKeyword)/sizeof(struct Fts3Keyword)); ii++){ const struct Fts3Keyword *pKey = &aKeyword[ii]; if( (pKey->parenOnly & ~sqlite3_fts3_enable_parentheses)!=0 ){ continue; } if( nInput>=pKey->n && 0==memcmp(zInput, pKey->z, pKey->n) ){ int nNear = SQLITE_FTS3_DEFAULT_NEAR_PARAM; int nKey = pKey->n; char cNext; /* If this is a "NEAR" keyword, check for an explicit nearness. */ if( pKey->eType==FTSQUERY_NEAR ){ assert( nKey==4 ); if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){ nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear); } } /* At this point this is probably a keyword. But for that to be true, ** the next byte must contain either whitespace, an open or close ** parenthesis, a quote character, or EOF. */ cNext = zInput[nKey]; if( fts3isspace(cNext) || cNext=='"' || cNext=='(' || cNext==')' || cNext==0 ){ pRet = (Fts3Expr *)sqlite3Fts3MallocZero(sizeof(Fts3Expr)); if( !pRet ){ return SQLITE_NOMEM; } pRet->eType = pKey->eType; pRet->nNear = nNear; *ppExpr = pRet; *pnConsumed = (int)((zInput - z) + nKey); return SQLITE_OK; } /* Turns out that wasn't a keyword after all. This happens if the ** user has supplied a token such as "ORacle". Continue. */ } } /* See if we are dealing with a quoted phrase. If this is the case, then ** search for the closing quote and pass the whole string to getNextString() ** for processing. This is easy to do, as fts3 has no syntax for escaping ** a quote character embedded in a string. */ if( *zInput=='"' ){ for(ii=1; iinNest++; #if !defined(SQLITE_MAX_EXPR_DEPTH) if( pParse->nNest>1000 ) return SQLITE_ERROR; #elif SQLITE_MAX_EXPR_DEPTH>0 if( pParse->nNest>SQLITE_MAX_EXPR_DEPTH ) return SQLITE_ERROR; #endif rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed); *pnConsumed = (int)(zInput - z) + 1 + nConsumed; return rc; }else if( *zInput==')' ){ pParse->nNest--; *pnConsumed = (int)((zInput - z) + 1); *ppExpr = 0; return SQLITE_DONE; } } /* If control flows to this point, this must be a regular token, or ** the end of the input. Read a regular token using the sqlite3_tokenizer ** interface. Before doing so, figure out if there is an explicit ** column specifier for the token. ** ** TODO: Strangely, it is not possible to associate a column specifier ** with a quoted phrase, only with a single token. Not sure if this was ** an implementation artifact or an intentional decision when fts3 was ** first implemented. Whichever it was, this module duplicates the ** limitation. */ iCol = pParse->iDefaultCol; iColLen = 0; for(ii=0; iinCol; ii++){ const char *zStr = pParse->azCol[ii]; int nStr = (int)strlen(zStr); if( nInput>nStr && zInput[nStr]==':' && sqlite3_strnicmp(zStr, zInput, nStr)==0 ){ iCol = ii; iColLen = (int)((zInput - z) + nStr + 1); break; } } rc = getNextToken(pParse, iCol, &z[iColLen], n-iColLen, ppExpr, pnConsumed); *pnConsumed += iColLen; return rc; } /* ** The argument is an Fts3Expr structure for a binary operator (any type ** except an FTSQUERY_PHRASE). Return an integer value representing the ** precedence of the operator. Lower values have a higher precedence (i.e. ** group more tightly). For example, in the C language, the == operator ** groups more tightly than ||, and would therefore have a higher precedence. ** ** When using the new fts3 query syntax (when SQLITE_ENABLE_FTS3_PARENTHESIS ** is defined), the order of the operators in precedence from highest to ** lowest is: ** ** NEAR ** NOT ** AND (including implicit ANDs) ** OR ** ** Note that when using the old query syntax, the OR operator has a higher ** precedence than the AND operator. */ static int opPrecedence(Fts3Expr *p){ assert( p->eType!=FTSQUERY_PHRASE ); if( sqlite3_fts3_enable_parentheses ){ return p->eType; }else if( p->eType==FTSQUERY_NEAR ){ return 1; }else if( p->eType==FTSQUERY_OR ){ return 2; } assert( p->eType==FTSQUERY_AND ); return 3; } /* ** Argument ppHead contains a pointer to the current head of a query ** expression tree being parsed. pPrev is the expression node most recently ** inserted into the tree. This function adds pNew, which is always a binary ** operator node, into the expression tree based on the relative precedence ** of pNew and the existing nodes of the tree. This may result in the head ** of the tree changing, in which case *ppHead is set to the new root node. */ static void insertBinaryOperator( Fts3Expr **ppHead, /* Pointer to the root node of a tree */ Fts3Expr *pPrev, /* Node most recently inserted into the tree */ Fts3Expr *pNew /* New binary node to insert into expression tree */ ){ Fts3Expr *pSplit = pPrev; while( pSplit->pParent && opPrecedence(pSplit->pParent)<=opPrecedence(pNew) ){ pSplit = pSplit->pParent; } if( pSplit->pParent ){ assert( pSplit->pParent->pRight==pSplit ); pSplit->pParent->pRight = pNew; pNew->pParent = pSplit->pParent; }else{ *ppHead = pNew; } pNew->pLeft = pSplit; pSplit->pParent = pNew; } /* ** Parse the fts3 query expression found in buffer z, length n. This function ** returns either when the end of the buffer is reached or an unmatched ** closing bracket - ')' - is encountered. ** ** If successful, SQLITE_OK is returned, *ppExpr is set to point to the ** parsed form of the expression and *pnConsumed is set to the number of ** bytes read from buffer z. Otherwise, *ppExpr is set to 0 and SQLITE_NOMEM ** (out of memory error) or SQLITE_ERROR (parse error) is returned. */ static int fts3ExprParse( ParseContext *pParse, /* fts3 query parse context */ const char *z, int n, /* Text of MATCH query */ Fts3Expr **ppExpr, /* OUT: Parsed query structure */ int *pnConsumed /* OUT: Number of bytes consumed */ ){ Fts3Expr *pRet = 0; Fts3Expr *pPrev = 0; Fts3Expr *pNotBranch = 0; /* Only used in legacy parse mode */ int nIn = n; const char *zIn = z; int rc = SQLITE_OK; int isRequirePhrase = 1; while( rc==SQLITE_OK ){ Fts3Expr *p = 0; int nByte = 0; rc = getNextNode(pParse, zIn, nIn, &p, &nByte); assert( nByte>0 || (rc!=SQLITE_OK && p==0) ); if( rc==SQLITE_OK ){ if( p ){ int isPhrase; if( !sqlite3_fts3_enable_parentheses && p->eType==FTSQUERY_PHRASE && pParse->isNot ){ /* Create an implicit NOT operator. */ Fts3Expr *pNot = sqlite3Fts3MallocZero(sizeof(Fts3Expr)); if( !pNot ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; goto exprparse_out; } pNot->eType = FTSQUERY_NOT; pNot->pRight = p; p->pParent = pNot; if( pNotBranch ){ pNot->pLeft = pNotBranch; pNotBranch->pParent = pNot; } pNotBranch = pNot; p = pPrev; }else{ int eType = p->eType; isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); /* The isRequirePhrase variable is set to true if a phrase or ** an expression contained in parenthesis is required. If a ** binary operator (AND, OR, NOT or NEAR) is encounted when ** isRequirePhrase is set, this is a syntax error. */ if( !isPhrase && isRequirePhrase ){ sqlite3Fts3ExprFree(p); rc = SQLITE_ERROR; goto exprparse_out; } if( isPhrase && !isRequirePhrase ){ /* Insert an implicit AND operator. */ Fts3Expr *pAnd; assert( pRet && pPrev ); pAnd = sqlite3Fts3MallocZero(sizeof(Fts3Expr)); if( !pAnd ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; goto exprparse_out; } pAnd->eType = FTSQUERY_AND; insertBinaryOperator(&pRet, pPrev, pAnd); pPrev = pAnd; } /* This test catches attempts to make either operand of a NEAR ** operator something other than a phrase. For example, either of ** the following: ** ** (bracketed expression) NEAR phrase ** phrase NEAR (bracketed expression) ** ** Return an error in either case. */ if( pPrev && ( (eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE) || (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR) )){ sqlite3Fts3ExprFree(p); rc = SQLITE_ERROR; goto exprparse_out; } if( isPhrase ){ if( pRet ){ assert( pPrev && pPrev->pLeft && pPrev->pRight==0 ); pPrev->pRight = p; p->pParent = pPrev; }else{ pRet = p; } }else{ insertBinaryOperator(&pRet, pPrev, p); } isRequirePhrase = !isPhrase; } pPrev = p; } assert( nByte>0 ); } assert( rc!=SQLITE_OK || (nByte>0 && nByte<=nIn) ); nIn -= nByte; zIn += nByte; } if( rc==SQLITE_DONE && pRet && isRequirePhrase ){ rc = SQLITE_ERROR; } if( rc==SQLITE_DONE ){ rc = SQLITE_OK; if( !sqlite3_fts3_enable_parentheses && pNotBranch ){ if( !pRet ){ rc = SQLITE_ERROR; }else{ Fts3Expr *pIter = pNotBranch; while( pIter->pLeft ){ pIter = pIter->pLeft; } pIter->pLeft = pRet; pRet->pParent = pIter; pRet = pNotBranch; } } } *pnConsumed = n - nIn; exprparse_out: if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(pRet); sqlite3Fts3ExprFree(pNotBranch); pRet = 0; } *ppExpr = pRet; return rc; } /* ** Return SQLITE_ERROR if the maximum depth of the expression tree passed ** as the only argument is more than nMaxDepth. */ static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){ int rc = SQLITE_OK; if( p ){ if( nMaxDepth<0 ){ rc = SQLITE_TOOBIG; }else{ rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1); if( rc==SQLITE_OK ){ rc = fts3ExprCheckDepth(p->pRight, nMaxDepth-1); } } } return rc; } /* ** This function attempts to transform the expression tree at (*pp) to ** an equivalent but more balanced form. The tree is modified in place. ** If successful, SQLITE_OK is returned and (*pp) set to point to the ** new root expression node. ** ** nMaxDepth is the maximum allowable depth of the balanced sub-tree. ** ** Otherwise, if an error occurs, an SQLite error code is returned and ** expression (*pp) freed. */ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){ int rc = SQLITE_OK; /* Return code */ Fts3Expr *pRoot = *pp; /* Initial root node */ Fts3Expr *pFree = 0; /* List of free nodes. Linked by pParent. */ int eType = pRoot->eType; /* Type of node in this tree */ if( nMaxDepth==0 ){ rc = SQLITE_ERROR; } if( rc==SQLITE_OK ){ if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ Fts3Expr **apLeaf; apLeaf = (Fts3Expr **)sqlite3_malloc64(sizeof(Fts3Expr *) * nMaxDepth); if( 0==apLeaf ){ rc = SQLITE_NOMEM; }else{ memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth); } if( rc==SQLITE_OK ){ int i; Fts3Expr *p; /* Set $p to point to the left-most leaf in the tree of eType nodes. */ for(p=pRoot; p->eType==eType; p=p->pLeft){ assert( p->pParent==0 || p->pParent->pLeft==p ); assert( p->pLeft && p->pRight ); } /* This loop runs once for each leaf in the tree of eType nodes. */ while( 1 ){ int iLvl; Fts3Expr *pParent = p->pParent; /* Current parent of p */ assert( pParent==0 || pParent->pLeft==p ); p->pParent = 0; if( pParent ){ pParent->pLeft = 0; }else{ pRoot = 0; } rc = fts3ExprBalance(&p, nMaxDepth-1); if( rc!=SQLITE_OK ) break; for(iLvl=0; p && iLvlpLeft = apLeaf[iLvl]; pFree->pRight = p; pFree->pLeft->pParent = pFree; pFree->pRight->pParent = pFree; p = pFree; pFree = pFree->pParent; p->pParent = 0; apLeaf[iLvl] = 0; } } if( p ){ sqlite3Fts3ExprFree(p); rc = SQLITE_TOOBIG; break; } /* If that was the last leaf node, break out of the loop */ if( pParent==0 ) break; /* Set $p to point to the next leaf in the tree of eType nodes */ for(p=pParent->pRight; p->eType==eType; p=p->pLeft); /* Remove pParent from the original tree. */ assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent ); pParent->pRight->pParent = pParent->pParent; if( pParent->pParent ){ pParent->pParent->pLeft = pParent->pRight; }else{ assert( pParent==pRoot ); pRoot = pParent->pRight; } /* Link pParent into the free node list. It will be used as an ** internal node of the new tree. */ pParent->pParent = pFree; pFree = pParent; } if( rc==SQLITE_OK ){ p = 0; for(i=0; ipParent = 0; }else{ assert( pFree!=0 ); pFree->pRight = p; pFree->pLeft = apLeaf[i]; pFree->pLeft->pParent = pFree; pFree->pRight->pParent = pFree; p = pFree; pFree = pFree->pParent; p->pParent = 0; } } } pRoot = p; }else{ /* An error occurred. Delete the contents of the apLeaf[] array ** and pFree list. Everything else is cleaned up by the call to ** sqlite3Fts3ExprFree(pRoot) below. */ Fts3Expr *pDel; for(i=0; ipParent; sqlite3_free(pDel); } } assert( pFree==0 ); sqlite3_free( apLeaf ); } }else if( eType==FTSQUERY_NOT ){ Fts3Expr *pLeft = pRoot->pLeft; Fts3Expr *pRight = pRoot->pRight; pRoot->pLeft = 0; pRoot->pRight = 0; pLeft->pParent = 0; pRight->pParent = 0; rc = fts3ExprBalance(&pLeft, nMaxDepth-1); if( rc==SQLITE_OK ){ rc = fts3ExprBalance(&pRight, nMaxDepth-1); } if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(pRight); sqlite3Fts3ExprFree(pLeft); }else{ assert( pLeft && pRight ); pRoot->pLeft = pLeft; pLeft->pParent = pRoot; pRoot->pRight = pRight; pRight->pParent = pRoot; } } } if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(pRoot); pRoot = 0; } *pp = pRoot; return rc; } /* ** This function is similar to sqlite3Fts3ExprParse(), with the following ** differences: ** ** 1. It does not do expression rebalancing. ** 2. It does not check that the expression does not exceed the ** maximum allowable depth. ** 3. Even if it fails, *ppExpr may still be set to point to an ** expression tree. It should be deleted using sqlite3Fts3ExprFree() ** in this case. */ static int fts3ExprParseUnbalanced( sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ int iLangid, /* Language id for tokenizer */ char **azCol, /* Array of column names for fts3 table */ int bFts4, /* True to allow FTS4-only syntax */ int nCol, /* Number of entries in azCol[] */ int iDefaultCol, /* Default column to query */ const char *z, int n, /* Text of MATCH query */ Fts3Expr **ppExpr /* OUT: Parsed query structure */ ){ int nParsed; int rc; ParseContext sParse; memset(&sParse, 0, sizeof(ParseContext)); sParse.pTokenizer = pTokenizer; sParse.iLangid = iLangid; sParse.azCol = (const char **)azCol; sParse.nCol = nCol; sParse.iDefaultCol = iDefaultCol; sParse.bFts4 = bFts4; if( z==0 ){ *ppExpr = 0; return SQLITE_OK; } if( n<0 ){ n = (int)strlen(z); } rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed); assert( rc==SQLITE_OK || *ppExpr==0 ); /* Check for mismatched parenthesis */ if( rc==SQLITE_OK && sParse.nNest ){ rc = SQLITE_ERROR; } return rc; } /* ** Parameters z and n contain a pointer to and length of a buffer containing ** an fts3 query expression, respectively. This function attempts to parse the ** query expression and create a tree of Fts3Expr structures representing the ** parsed expression. If successful, *ppExpr is set to point to the head ** of the parsed expression tree and SQLITE_OK is returned. If an error ** occurs, either SQLITE_NOMEM (out-of-memory error) or SQLITE_ERROR (parse ** error) is returned and *ppExpr is set to 0. ** ** If parameter n is a negative number, then z is assumed to point to a ** nul-terminated string and the length is determined using strlen(). ** ** The first parameter, pTokenizer, is passed the fts3 tokenizer module to ** use to normalize query tokens while parsing the expression. The azCol[] ** array, which is assumed to contain nCol entries, should contain the names ** of each column in the target fts3 table, in order from left to right. ** Column names must be nul-terminated strings. ** ** The iDefaultCol parameter should be passed the index of the table column ** that appears on the left-hand-side of the MATCH operator (the default ** column to match against for tokens for which a column name is not explicitly ** specified as part of the query string), or -1 if tokens may by default ** match any table column. */ SQLITE_PRIVATE int sqlite3Fts3ExprParse( sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ int iLangid, /* Language id for tokenizer */ char **azCol, /* Array of column names for fts3 table */ int bFts4, /* True to allow FTS4-only syntax */ int nCol, /* Number of entries in azCol[] */ int iDefaultCol, /* Default column to query */ const char *z, int n, /* Text of MATCH query */ Fts3Expr **ppExpr, /* OUT: Parsed query structure */ char **pzErr /* OUT: Error message (sqlite3_malloc) */ ){ int rc = fts3ExprParseUnbalanced( pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr ); /* Rebalance the expression. And check that its depth does not exceed ** SQLITE_FTS3_MAX_EXPR_DEPTH. */ if( rc==SQLITE_OK && *ppExpr ){ rc = fts3ExprBalance(ppExpr, SQLITE_FTS3_MAX_EXPR_DEPTH); if( rc==SQLITE_OK ){ rc = fts3ExprCheckDepth(*ppExpr, SQLITE_FTS3_MAX_EXPR_DEPTH); } } if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(*ppExpr); *ppExpr = 0; if( rc==SQLITE_TOOBIG ){ sqlite3Fts3ErrMsg(pzErr, "FTS expression tree is too large (maximum depth %d)", SQLITE_FTS3_MAX_EXPR_DEPTH ); rc = SQLITE_ERROR; }else if( rc==SQLITE_ERROR ){ sqlite3Fts3ErrMsg(pzErr, "malformed MATCH expression: [%s]", z); } } return rc; } /* ** Free a single node of an expression tree. */ static void fts3FreeExprNode(Fts3Expr *p){ assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 ); sqlite3Fts3EvalPhraseCleanup(p->pPhrase); sqlite3_free(p->aMI); sqlite3_free(p); } /* ** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse(). ** ** This function would be simpler if it recursively called itself. But ** that would mean passing a sufficiently large expression to ExprParse() ** could cause a stack overflow. */ SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *pDel){ Fts3Expr *p; assert( pDel==0 || pDel->pParent==0 ); for(p=pDel; p && (p->pLeft||p->pRight); p=(p->pLeft ? p->pLeft : p->pRight)){ assert( p->pParent==0 || p==p->pParent->pRight || p==p->pParent->pLeft ); } while( p ){ Fts3Expr *pParent = p->pParent; fts3FreeExprNode(p); if( pParent && p==pParent->pLeft && pParent->pRight ){ p = pParent->pRight; while( p && (p->pLeft || p->pRight) ){ assert( p==p->pParent->pRight || p==p->pParent->pLeft ); p = (p->pLeft ? p->pLeft : p->pRight); } }else{ p = pParent; } } } /**************************************************************************** ***************************************************************************** ** Everything after this point is just test code. */ #ifdef SQLITE_TEST /* #include */ /* ** Return a pointer to a buffer containing a text representation of the ** expression passed as the first argument. The buffer is obtained from ** sqlite3_malloc(). It is the responsibility of the caller to use ** sqlite3_free() to release the memory. If an OOM condition is encountered, ** NULL is returned. ** ** If the second argument is not NULL, then its contents are prepended to ** the returned expression text and then freed using sqlite3_free(). */ static char *exprToString(Fts3Expr *pExpr, char *zBuf){ if( pExpr==0 ){ return sqlite3_mprintf(""); } switch( pExpr->eType ){ case FTSQUERY_PHRASE: { Fts3Phrase *pPhrase = pExpr->pPhrase; int i; zBuf = sqlite3_mprintf( "%zPHRASE %d 0", zBuf, pPhrase->iColumn); for(i=0; zBuf && inToken; i++){ zBuf = sqlite3_mprintf("%z %.*s%s", zBuf, pPhrase->aToken[i].n, pPhrase->aToken[i].z, (pPhrase->aToken[i].isPrefix?"+":"") ); } return zBuf; } case FTSQUERY_NEAR: zBuf = sqlite3_mprintf("%zNEAR/%d ", zBuf, pExpr->nNear); break; case FTSQUERY_NOT: zBuf = sqlite3_mprintf("%zNOT ", zBuf); break; case FTSQUERY_AND: zBuf = sqlite3_mprintf("%zAND ", zBuf); break; case FTSQUERY_OR: zBuf = sqlite3_mprintf("%zOR ", zBuf); break; } if( zBuf ) zBuf = sqlite3_mprintf("%z{", zBuf); if( zBuf ) zBuf = exprToString(pExpr->pLeft, zBuf); if( zBuf ) zBuf = sqlite3_mprintf("%z} {", zBuf); if( zBuf ) zBuf = exprToString(pExpr->pRight, zBuf); if( zBuf ) zBuf = sqlite3_mprintf("%z}", zBuf); return zBuf; } /* ** This is the implementation of a scalar SQL function used to test the ** expression parser. It should be called as follows: ** ** fts3_exprtest(, , , ...); ** ** The first argument, , is the name of the fts3 tokenizer used ** to parse the query expression (see README.tokenizers). The second argument ** is the query expression to parse. Each subsequent argument is the name ** of a column of the fts3 table that the query expression may refer to. ** For example: ** ** SELECT fts3_exprtest('simple', 'Bill col2:Bloggs', 'col1', 'col2'); */ static void fts3ExprTestCommon( int bRebalance, sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_tokenizer *pTokenizer = 0; int rc; char **azCol = 0; const char *zExpr; int nExpr; int nCol; int ii; Fts3Expr *pExpr; char *zBuf = 0; Fts3Hash *pHash = (Fts3Hash*)sqlite3_user_data(context); const char *zTokenizer = 0; char *zErr = 0; if( argc<3 ){ sqlite3_result_error(context, "Usage: fts3_exprtest(tokenizer, expr, col1, ...", -1 ); return; } zTokenizer = (const char*)sqlite3_value_text(argv[0]); rc = sqlite3Fts3InitTokenizer(pHash, zTokenizer, &pTokenizer, &zErr); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_error(context, zErr, -1); } sqlite3_free(zErr); return; } zExpr = (const char *)sqlite3_value_text(argv[1]); nExpr = sqlite3_value_bytes(argv[1]); nCol = argc-2; azCol = (char **)sqlite3_malloc64(nCol*sizeof(char *)); if( !azCol ){ sqlite3_result_error_nomem(context); goto exprtest_out; } for(ii=0; iipModule->xDestroy(pTokenizer); } sqlite3_free(azCol); } static void fts3ExprTest( sqlite3_context *context, int argc, sqlite3_value **argv ){ fts3ExprTestCommon(0, context, argc, argv); } static void fts3ExprTestRebalance( sqlite3_context *context, int argc, sqlite3_value **argv ){ fts3ExprTestCommon(1, context, argc, argv); } /* ** Register the query expression parser test function fts3_exprtest() ** with database connection db. */ SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash *pHash){ int rc = sqlite3_create_function( db, "fts3_exprtest", -1, SQLITE_UTF8, (void*)pHash, fts3ExprTest, 0, 0 ); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "fts3_exprtest_rebalance", -1, SQLITE_UTF8, (void*)pHash, fts3ExprTestRebalance, 0, 0 ); } return rc; } #endif #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ /************** End of fts3_expr.c *******************************************/ /************** Begin file fts3_hash.c ***************************************/ /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the implementation of generic hash-tables used in SQLite. ** We've modified it slightly to serve as a standalone hash table ** implementation for the full-text indexing module. */ /* ** The code in this file is only compiled if: ** ** * The FTS3 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include */ /* #include */ /* #include */ /* #include "fts3_hash.h" */ /* ** Malloc and Free functions */ static void *fts3HashMalloc(sqlite3_int64 n){ void *p = sqlite3_malloc64(n); if( p ){ memset(p, 0, n); } return p; } static void fts3HashFree(void *p){ sqlite3_free(p); } /* Turn bulk memory into a hash table object by initializing the ** fields of the Hash structure. ** ** "pNew" is a pointer to the hash table that is to be initialized. ** keyClass is one of the constants ** FTS3_HASH_BINARY or FTS3_HASH_STRING. The value of keyClass ** determines what kind of key the hash table will use. "copyKey" is ** true if the hash table should make its own private copy of keys and ** false if it should just use the supplied pointer. */ SQLITE_PRIVATE void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey){ assert( pNew!=0 ); assert( keyClass>=FTS3_HASH_STRING && keyClass<=FTS3_HASH_BINARY ); pNew->keyClass = keyClass; pNew->copyKey = copyKey; pNew->first = 0; pNew->count = 0; pNew->htsize = 0; pNew->ht = 0; } /* Remove all entries from a hash table. Reclaim all memory. ** Call this routine to delete a hash table or to reset a hash table ** to the empty state. */ SQLITE_PRIVATE void sqlite3Fts3HashClear(Fts3Hash *pH){ Fts3HashElem *elem; /* For looping over all elements of the table */ assert( pH!=0 ); elem = pH->first; pH->first = 0; fts3HashFree(pH->ht); pH->ht = 0; pH->htsize = 0; while( elem ){ Fts3HashElem *next_elem = elem->next; if( pH->copyKey && elem->pKey ){ fts3HashFree(elem->pKey); } fts3HashFree(elem); elem = next_elem; } pH->count = 0; } /* ** Hash and comparison functions when the mode is FTS3_HASH_STRING */ static int fts3StrHash(const void *pKey, int nKey){ const char *z = (const char *)pKey; unsigned h = 0; if( nKey<=0 ) nKey = (int) strlen(z); while( nKey > 0 ){ h = (h<<3) ^ h ^ *z++; nKey--; } return (int)(h & 0x7fffffff); } static int fts3StrCompare(const void *pKey1, int n1, const void *pKey2, int n2){ if( n1!=n2 ) return 1; return strncmp((const char*)pKey1,(const char*)pKey2,n1); } /* ** Hash and comparison functions when the mode is FTS3_HASH_BINARY */ static int fts3BinHash(const void *pKey, int nKey){ int h = 0; const char *z = (const char *)pKey; while( nKey-- > 0 ){ h = (h<<3) ^ h ^ *(z++); } return h & 0x7fffffff; } static int fts3BinCompare(const void *pKey1, int n1, const void *pKey2, int n2){ if( n1!=n2 ) return 1; return memcmp(pKey1,pKey2,n1); } /* ** Return a pointer to the appropriate hash function given the key class. ** ** The C syntax in this function definition may be unfamilar to some ** programmers, so we provide the following additional explanation: ** ** The name of the function is "ftsHashFunction". The function takes a ** single parameter "keyClass". The return value of ftsHashFunction() ** is a pointer to another function. Specifically, the return value ** of ftsHashFunction() is a pointer to a function that takes two parameters ** with types "const void*" and "int" and returns an "int". */ static int (*ftsHashFunction(int keyClass))(const void*,int){ if( keyClass==FTS3_HASH_STRING ){ return &fts3StrHash; }else{ assert( keyClass==FTS3_HASH_BINARY ); return &fts3BinHash; } } /* ** Return a pointer to the appropriate hash function given the key class. ** ** For help in interpreted the obscure C code in the function definition, ** see the header comment on the previous function. */ static int (*ftsCompareFunction(int keyClass))(const void*,int,const void*,int){ if( keyClass==FTS3_HASH_STRING ){ return &fts3StrCompare; }else{ assert( keyClass==FTS3_HASH_BINARY ); return &fts3BinCompare; } } /* Link an element into the hash table */ static void fts3HashInsertElement( Fts3Hash *pH, /* The complete hash table */ struct _fts3ht *pEntry, /* The entry into which pNew is inserted */ Fts3HashElem *pNew /* The element to be inserted */ ){ Fts3HashElem *pHead; /* First element already in pEntry */ pHead = pEntry->chain; if( pHead ){ pNew->next = pHead; pNew->prev = pHead->prev; if( pHead->prev ){ pHead->prev->next = pNew; } else { pH->first = pNew; } pHead->prev = pNew; }else{ pNew->next = pH->first; if( pH->first ){ pH->first->prev = pNew; } pNew->prev = 0; pH->first = pNew; } pEntry->count++; pEntry->chain = pNew; } /* Resize the hash table so that it cantains "new_size" buckets. ** "new_size" must be a power of 2. The hash table might fail ** to resize if sqliteMalloc() fails. ** ** Return non-zero if a memory allocation error occurs. */ static int fts3Rehash(Fts3Hash *pH, int new_size){ struct _fts3ht *new_ht; /* The new hash table */ Fts3HashElem *elem, *next_elem; /* For looping over existing elements */ int (*xHash)(const void*,int); /* The hash function */ assert( (new_size & (new_size-1))==0 ); new_ht = (struct _fts3ht *)fts3HashMalloc( new_size*sizeof(struct _fts3ht) ); if( new_ht==0 ) return 1; fts3HashFree(pH->ht); pH->ht = new_ht; pH->htsize = new_size; xHash = ftsHashFunction(pH->keyClass); for(elem=pH->first, pH->first=0; elem; elem = next_elem){ int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); next_elem = elem->next; fts3HashInsertElement(pH, &new_ht[h], elem); } return 0; } /* This function (for internal use only) locates an element in an ** hash table that matches the given key. The hash for this key has ** already been computed and is passed as the 4th parameter. */ static Fts3HashElem *fts3FindElementByHash( const Fts3Hash *pH, /* The pH to be searched */ const void *pKey, /* The key we are searching for */ int nKey, int h /* The hash for this key. */ ){ Fts3HashElem *elem; /* Used to loop thru the element list */ int count; /* Number of elements left to test */ int (*xCompare)(const void*,int,const void*,int); /* comparison function */ if( pH->ht ){ struct _fts3ht *pEntry = &pH->ht[h]; elem = pEntry->chain; count = pEntry->count; xCompare = ftsCompareFunction(pH->keyClass); while( count-- && elem ){ if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ return elem; } elem = elem->next; } } return 0; } /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. */ static void fts3RemoveElementByHash( Fts3Hash *pH, /* The pH containing "elem" */ Fts3HashElem* elem, /* The element to be removed from the pH */ int h /* Hash value for the element */ ){ struct _fts3ht *pEntry; if( elem->prev ){ elem->prev->next = elem->next; }else{ pH->first = elem->next; } if( elem->next ){ elem->next->prev = elem->prev; } pEntry = &pH->ht[h]; if( pEntry->chain==elem ){ pEntry->chain = elem->next; } pEntry->count--; if( pEntry->count<=0 ){ pEntry->chain = 0; } if( pH->copyKey && elem->pKey ){ fts3HashFree(elem->pKey); } fts3HashFree( elem ); pH->count--; if( pH->count<=0 ){ assert( pH->first==0 ); assert( pH->count==0 ); fts3HashClear(pH); } } SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem( const Fts3Hash *pH, const void *pKey, int nKey ){ int h; /* A hash on key */ int (*xHash)(const void*,int); /* The hash function */ if( pH==0 || pH->ht==0 ) return 0; xHash = ftsHashFunction(pH->keyClass); assert( xHash!=0 ); h = (*xHash)(pKey,nKey); assert( (pH->htsize & (pH->htsize-1))==0 ); return fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1)); } /* ** Attempt to locate an element of the hash table pH with a key ** that matches pKey,nKey. Return the data for this element if it is ** found, or NULL if there is no match. */ SQLITE_PRIVATE void *sqlite3Fts3HashFind(const Fts3Hash *pH, const void *pKey, int nKey){ Fts3HashElem *pElem; /* The element that matches key (if any) */ pElem = sqlite3Fts3HashFindElem(pH, pKey, nKey); return pElem ? pElem->data : 0; } /* Insert an element into the hash table pH. The key is pKey,nKey ** and the data is "data". ** ** If no element exists with a matching key, then a new ** element is created. A copy of the key is made if the copyKey ** flag is set. NULL is returned. ** ** If another element already exists with the same key, then the ** new data replaces the old data and the old data is returned. ** The key is not copied in this instance. If a malloc fails, then ** the new data is returned and the hash table is unchanged. ** ** If the "data" parameter to this function is NULL, then the ** element corresponding to "key" is removed from the hash table. */ SQLITE_PRIVATE void *sqlite3Fts3HashInsert( Fts3Hash *pH, /* The hash table to insert into */ const void *pKey, /* The key */ int nKey, /* Number of bytes in the key */ void *data /* The data */ ){ int hraw; /* Raw hash value of the key */ int h; /* the hash of the key modulo hash table size */ Fts3HashElem *elem; /* Used to loop thru the element list */ Fts3HashElem *new_elem; /* New element added to the pH */ int (*xHash)(const void*,int); /* The hash function */ assert( pH!=0 ); xHash = ftsHashFunction(pH->keyClass); assert( xHash!=0 ); hraw = (*xHash)(pKey, nKey); assert( (pH->htsize & (pH->htsize-1))==0 ); h = hraw & (pH->htsize-1); elem = fts3FindElementByHash(pH,pKey,nKey,h); if( elem ){ void *old_data = elem->data; if( data==0 ){ fts3RemoveElementByHash(pH,elem,h); }else{ elem->data = data; } return old_data; } if( data==0 ) return 0; if( (pH->htsize==0 && fts3Rehash(pH,8)) || (pH->count>=pH->htsize && fts3Rehash(pH, pH->htsize*2)) ){ pH->count = 0; return data; } assert( pH->htsize>0 ); new_elem = (Fts3HashElem*)fts3HashMalloc( sizeof(Fts3HashElem) ); if( new_elem==0 ) return data; if( pH->copyKey && pKey!=0 ){ new_elem->pKey = fts3HashMalloc( nKey ); if( new_elem->pKey==0 ){ fts3HashFree(new_elem); return data; } memcpy((void*)new_elem->pKey, pKey, nKey); }else{ new_elem->pKey = (void*)pKey; } new_elem->nKey = nKey; pH->count++; assert( pH->htsize>0 ); assert( (pH->htsize & (pH->htsize-1))==0 ); h = hraw & (pH->htsize-1); fts3HashInsertElement(pH, &pH->ht[h], new_elem); new_elem->data = data; return 0; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ /************** End of fts3_hash.c *******************************************/ /************** Begin file fts3_porter.c *************************************/ /* ** 2006 September 30 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Implementation of the full-text-search tokenizer that implements ** a Porter stemmer. */ /* ** The code in this file is only compiled if: ** ** * The FTS3 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include */ /* #include */ /* #include */ /* #include */ /* #include "fts3_tokenizer.h" */ /* ** Class derived from sqlite3_tokenizer */ typedef struct porter_tokenizer { sqlite3_tokenizer base; /* Base class */ } porter_tokenizer; /* ** Class derived from sqlite3_tokenizer_cursor */ typedef struct porter_tokenizer_cursor { sqlite3_tokenizer_cursor base; const char *zInput; /* input we are tokenizing */ int nInput; /* size of the input */ int iOffset; /* current position in zInput */ int iToken; /* index of next token to be returned */ char *zToken; /* storage for current token */ int nAllocated; /* space allocated to zToken buffer */ } porter_tokenizer_cursor; /* ** Create a new tokenizer instance. */ static int porterCreate( int argc, const char * const *argv, sqlite3_tokenizer **ppTokenizer ){ porter_tokenizer *t; UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); t = (porter_tokenizer *) sqlite3_malloc(sizeof(*t)); if( t==NULL ) return SQLITE_NOMEM; memset(t, 0, sizeof(*t)); *ppTokenizer = &t->base; return SQLITE_OK; } /* ** Destroy a tokenizer */ static int porterDestroy(sqlite3_tokenizer *pTokenizer){ sqlite3_free(pTokenizer); return SQLITE_OK; } /* ** Prepare to begin tokenizing a particular string. The input ** string to be tokenized is zInput[0..nInput-1]. A cursor ** used to incrementally tokenize this string is returned in ** *ppCursor. */ static int porterOpen( sqlite3_tokenizer *pTokenizer, /* The tokenizer */ const char *zInput, int nInput, /* String to be tokenized */ sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ ){ porter_tokenizer_cursor *c; UNUSED_PARAMETER(pTokenizer); c = (porter_tokenizer_cursor *) sqlite3_malloc(sizeof(*c)); if( c==NULL ) return SQLITE_NOMEM; c->zInput = zInput; if( zInput==0 ){ c->nInput = 0; }else if( nInput<0 ){ c->nInput = (int)strlen(zInput); }else{ c->nInput = nInput; } c->iOffset = 0; /* start tokenizing at the beginning */ c->iToken = 0; c->zToken = NULL; /* no space allocated, yet. */ c->nAllocated = 0; *ppCursor = &c->base; return SQLITE_OK; } /* ** Close a tokenization cursor previously opened by a call to ** porterOpen() above. */ static int porterClose(sqlite3_tokenizer_cursor *pCursor){ porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; sqlite3_free(c->zToken); sqlite3_free(c); return SQLITE_OK; } /* ** Vowel or consonant */ static const char cType[] = { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 2, 1 }; /* ** isConsonant() and isVowel() determine if their first character in ** the string they point to is a consonant or a vowel, according ** to Porter ruls. ** ** A consonate is any letter other than 'a', 'e', 'i', 'o', or 'u'. ** 'Y' is a consonant unless it follows another consonant, ** in which case it is a vowel. ** ** In these routine, the letters are in reverse order. So the 'y' rule ** is that 'y' is a consonant unless it is followed by another ** consonent. */ static int isVowel(const char*); static int isConsonant(const char *z){ int j; char x = *z; if( x==0 ) return 0; assert( x>='a' && x<='z' ); j = cType[x-'a']; if( j<2 ) return j; return z[1]==0 || isVowel(z + 1); } static int isVowel(const char *z){ int j; char x = *z; if( x==0 ) return 0; assert( x>='a' && x<='z' ); j = cType[x-'a']; if( j<2 ) return 1-j; return isConsonant(z + 1); } /* ** Let any sequence of one or more vowels be represented by V and let ** C be sequence of one or more consonants. Then every word can be ** represented as: ** ** [C] (VC){m} [V] ** ** In prose: A word is an optional consonant followed by zero or ** vowel-consonant pairs followed by an optional vowel. "m" is the ** number of vowel consonant pairs. This routine computes the value ** of m for the first i bytes of a word. ** ** Return true if the m-value for z is 1 or more. In other words, ** return true if z contains at least one vowel that is followed ** by a consonant. ** ** In this routine z[] is in reverse order. So we are really looking ** for an instance of a consonant followed by a vowel. */ static int m_gt_0(const char *z){ while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } return *z!=0; } /* Like mgt0 above except we are looking for a value of m which is ** exactly 1 */ static int m_eq_1(const char *z){ while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } if( *z==0 ) return 0; while( isVowel(z) ){ z++; } if( *z==0 ) return 1; while( isConsonant(z) ){ z++; } return *z==0; } /* Like mgt0 above except we are looking for a value of m>1 instead ** or m>0 */ static int m_gt_1(const char *z){ while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } if( *z==0 ) return 0; while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } return *z!=0; } /* ** Return TRUE if there is a vowel anywhere within z[0..n-1] */ static int hasVowel(const char *z){ while( isConsonant(z) ){ z++; } return *z!=0; } /* ** Return TRUE if the word ends in a double consonant. ** ** The text is reversed here. So we are really looking at ** the first two characters of z[]. */ static int doubleConsonant(const char *z){ return isConsonant(z) && z[0]==z[1]; } /* ** Return TRUE if the word ends with three letters which ** are consonant-vowel-consonent and where the final consonant ** is not 'w', 'x', or 'y'. ** ** The word is reversed here. So we are really checking the ** first three letters and the first one cannot be in [wxy]. */ static int star_oh(const char *z){ return isConsonant(z) && z[0]!='w' && z[0]!='x' && z[0]!='y' && isVowel(z+1) && isConsonant(z+2); } /* ** If the word ends with zFrom and xCond() is true for the stem ** of the word that preceeds the zFrom ending, then change the ** ending to zTo. ** ** The input word *pz and zFrom are both in reverse order. zTo ** is in normal order. ** ** Return TRUE if zFrom matches. Return FALSE if zFrom does not ** match. Not that TRUE is returned even if xCond() fails and ** no substitution occurs. */ static int stem( char **pz, /* The word being stemmed (Reversed) */ const char *zFrom, /* If the ending matches this... (Reversed) */ const char *zTo, /* ... change the ending to this (not reversed) */ int (*xCond)(const char*) /* Condition that must be true */ ){ char *z = *pz; while( *zFrom && *zFrom==*z ){ z++; zFrom++; } if( *zFrom!=0 ) return 0; if( xCond && !xCond(z) ) return 1; while( *zTo ){ *(--z) = *(zTo++); } *pz = z; return 1; } /* ** This is the fallback stemmer used when the porter stemmer is ** inappropriate. The input word is copied into the output with ** US-ASCII case folding. If the input word is too long (more ** than 20 bytes if it contains no digits or more than 6 bytes if ** it contains digits) then word is truncated to 20 or 6 bytes ** by taking 10 or 3 bytes from the beginning and end. */ static void copy_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){ int i, mx, j; int hasDigit = 0; for(i=0; i='A' && c<='Z' ){ zOut[i] = c - 'A' + 'a'; }else{ if( c>='0' && c<='9' ) hasDigit = 1; zOut[i] = c; } } mx = hasDigit ? 3 : 10; if( nIn>mx*2 ){ for(j=mx, i=nIn-mx; i=(int)sizeof(zReverse)-7 ){ /* The word is too big or too small for the porter stemmer. ** Fallback to the copy stemmer */ copy_stemmer(zIn, nIn, zOut, pnOut); return; } for(i=0, j=sizeof(zReverse)-6; i='A' && c<='Z' ){ zReverse[j] = c + 'a' - 'A'; }else if( c>='a' && c<='z' ){ zReverse[j] = c; }else{ /* The use of a character not in [a-zA-Z] means that we fallback ** to the copy stemmer */ copy_stemmer(zIn, nIn, zOut, pnOut); return; } } memset(&zReverse[sizeof(zReverse)-5], 0, 5); z = &zReverse[j+1]; /* Step 1a */ if( z[0]=='s' ){ if( !stem(&z, "sess", "ss", 0) && !stem(&z, "sei", "i", 0) && !stem(&z, "ss", "ss", 0) ){ z++; } } /* Step 1b */ z2 = z; if( stem(&z, "dee", "ee", m_gt_0) ){ /* Do nothing. The work was all in the test */ }else if( (stem(&z, "gni", "", hasVowel) || stem(&z, "de", "", hasVowel)) && z!=z2 ){ if( stem(&z, "ta", "ate", 0) || stem(&z, "lb", "ble", 0) || stem(&z, "zi", "ize", 0) ){ /* Do nothing. The work was all in the test */ }else if( doubleConsonant(z) && (*z!='l' && *z!='s' && *z!='z') ){ z++; }else if( m_eq_1(z) && star_oh(z) ){ *(--z) = 'e'; } } /* Step 1c */ if( z[0]=='y' && hasVowel(z+1) ){ z[0] = 'i'; } /* Step 2 */ switch( z[1] ){ case 'a': if( !stem(&z, "lanoita", "ate", m_gt_0) ){ stem(&z, "lanoit", "tion", m_gt_0); } break; case 'c': if( !stem(&z, "icne", "ence", m_gt_0) ){ stem(&z, "icna", "ance", m_gt_0); } break; case 'e': stem(&z, "rezi", "ize", m_gt_0); break; case 'g': stem(&z, "igol", "log", m_gt_0); break; case 'l': if( !stem(&z, "ilb", "ble", m_gt_0) && !stem(&z, "illa", "al", m_gt_0) && !stem(&z, "iltne", "ent", m_gt_0) && !stem(&z, "ile", "e", m_gt_0) ){ stem(&z, "ilsuo", "ous", m_gt_0); } break; case 'o': if( !stem(&z, "noitazi", "ize", m_gt_0) && !stem(&z, "noita", "ate", m_gt_0) ){ stem(&z, "rota", "ate", m_gt_0); } break; case 's': if( !stem(&z, "msila", "al", m_gt_0) && !stem(&z, "ssenevi", "ive", m_gt_0) && !stem(&z, "ssenluf", "ful", m_gt_0) ){ stem(&z, "ssensuo", "ous", m_gt_0); } break; case 't': if( !stem(&z, "itila", "al", m_gt_0) && !stem(&z, "itivi", "ive", m_gt_0) ){ stem(&z, "itilib", "ble", m_gt_0); } break; } /* Step 3 */ switch( z[0] ){ case 'e': if( !stem(&z, "etaci", "ic", m_gt_0) && !stem(&z, "evita", "", m_gt_0) ){ stem(&z, "ezila", "al", m_gt_0); } break; case 'i': stem(&z, "itici", "ic", m_gt_0); break; case 'l': if( !stem(&z, "laci", "ic", m_gt_0) ){ stem(&z, "luf", "", m_gt_0); } break; case 's': stem(&z, "ssen", "", m_gt_0); break; } /* Step 4 */ switch( z[1] ){ case 'a': if( z[0]=='l' && m_gt_1(z+2) ){ z += 2; } break; case 'c': if( z[0]=='e' && z[2]=='n' && (z[3]=='a' || z[3]=='e') && m_gt_1(z+4) ){ z += 4; } break; case 'e': if( z[0]=='r' && m_gt_1(z+2) ){ z += 2; } break; case 'i': if( z[0]=='c' && m_gt_1(z+2) ){ z += 2; } break; case 'l': if( z[0]=='e' && z[2]=='b' && (z[3]=='a' || z[3]=='i') && m_gt_1(z+4) ){ z += 4; } break; case 'n': if( z[0]=='t' ){ if( z[2]=='a' ){ if( m_gt_1(z+3) ){ z += 3; } }else if( z[2]=='e' ){ if( !stem(&z, "tneme", "", m_gt_1) && !stem(&z, "tnem", "", m_gt_1) ){ stem(&z, "tne", "", m_gt_1); } } } break; case 'o': if( z[0]=='u' ){ if( m_gt_1(z+2) ){ z += 2; } }else if( z[3]=='s' || z[3]=='t' ){ stem(&z, "noi", "", m_gt_1); } break; case 's': if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){ z += 3; } break; case 't': if( !stem(&z, "eta", "", m_gt_1) ){ stem(&z, "iti", "", m_gt_1); } break; case 'u': if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){ z += 3; } break; case 'v': case 'z': if( z[0]=='e' && z[2]=='i' && m_gt_1(z+3) ){ z += 3; } break; } /* Step 5a */ if( z[0]=='e' ){ if( m_gt_1(z+1) ){ z++; }else if( m_eq_1(z+1) && !star_oh(z+1) ){ z++; } } /* Step 5b */ if( m_gt_1(z) && z[0]=='l' && z[1]=='l' ){ z++; } /* z[] is now the stemmed word in reverse order. Flip it back ** around into forward order and return. */ *pnOut = i = (int)strlen(z); zOut[i] = 0; while( *z ){ zOut[--i] = *(z++); } } /* ** Characters that can be part of a token. We assume any character ** whose value is greater than 0x80 (any UTF character) can be ** part of a token. In other words, delimiters all must have ** values of 0x7f or lower. */ static const char porterIdChar[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ }; #define isDelim(C) (((ch=C)&0x80)==0 && (ch<0x30 || !porterIdChar[ch-0x30])) /* ** Extract the next token from a tokenization cursor. The cursor must ** have been opened by a prior call to porterOpen(). */ static int porterNext( sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by porterOpen */ const char **pzToken, /* OUT: *pzToken is the token text */ int *pnBytes, /* OUT: Number of bytes in token */ int *piStartOffset, /* OUT: Starting offset of token */ int *piEndOffset, /* OUT: Ending offset of token */ int *piPosition /* OUT: Position integer of token */ ){ porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; const char *z = c->zInput; while( c->iOffsetnInput ){ int iStartOffset, ch; /* Scan past delimiter characters */ while( c->iOffsetnInput && isDelim(z[c->iOffset]) ){ c->iOffset++; } /* Count non-delimiter characters. */ iStartOffset = c->iOffset; while( c->iOffsetnInput && !isDelim(z[c->iOffset]) ){ c->iOffset++; } if( c->iOffset>iStartOffset ){ int n = c->iOffset-iStartOffset; if( n>c->nAllocated ){ char *pNew; c->nAllocated = n+20; pNew = sqlite3_realloc64(c->zToken, c->nAllocated); if( !pNew ) return SQLITE_NOMEM; c->zToken = pNew; } porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes); *pzToken = c->zToken; *piStartOffset = iStartOffset; *piEndOffset = c->iOffset; *piPosition = c->iToken++; return SQLITE_OK; } } return SQLITE_DONE; } /* ** The set of routines that implement the porter-stemmer tokenizer */ static const sqlite3_tokenizer_module porterTokenizerModule = { 0, porterCreate, porterDestroy, porterOpen, porterClose, porterNext, 0 }; /* ** Allocate a new porter tokenizer. Return a pointer to the new ** tokenizer in *ppModule */ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule( sqlite3_tokenizer_module const**ppModule ){ *ppModule = &porterTokenizerModule; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ /************** End of fts3_porter.c *****************************************/ /************** Begin file fts3_tokenizer.c **********************************/ /* ** 2007 June 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This is part of an SQLite module implementing full-text search. ** This particular file implements the generic tokenizer interface. */ /* ** The code in this file is only compiled if: ** ** * The FTS3 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include */ /* #include */ /* ** Return true if the two-argument version of fts3_tokenizer() ** has been activated via a prior call to sqlite3_db_config(db, ** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0); */ static int fts3TokenizerEnabled(sqlite3_context *context){ sqlite3 *db = sqlite3_context_db_handle(context); int isEnabled = 0; sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled); return isEnabled; } /* ** Implementation of the SQL scalar function for accessing the underlying ** hash table. This function may be called as follows: ** ** SELECT (); ** SELECT (, ); ** ** where is the name passed as the second argument ** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer'). ** ** If the argument is specified, it must be a blob value ** containing a pointer to be stored as the hash data corresponding ** to the string . If is not specified, then ** the string must already exist in the has table. Otherwise, ** an error is returned. ** ** Whether or not the argument is specified, the value returned ** is a blob containing the pointer stored as the hash data corresponding ** to string (after the hash-table is updated, if applicable). */ static void fts3TokenizerFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ Fts3Hash *pHash; void *pPtr = 0; const unsigned char *zName; int nName; assert( argc==1 || argc==2 ); pHash = (Fts3Hash *)sqlite3_user_data(context); zName = sqlite3_value_text(argv[0]); nName = sqlite3_value_bytes(argv[0])+1; if( argc==2 ){ if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[1]) ){ void *pOld; int n = sqlite3_value_bytes(argv[1]); if( zName==0 || n!=sizeof(pPtr) ){ sqlite3_result_error(context, "argument type mismatch", -1); return; } pPtr = *(void **)sqlite3_value_blob(argv[1]); pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr); if( pOld==pPtr ){ sqlite3_result_error(context, "out of memory", -1); } }else{ sqlite3_result_error(context, "fts3tokenize disabled", -1); return; } }else{ if( zName ){ pPtr = sqlite3Fts3HashFind(pHash, zName, nName); } if( !pPtr ){ char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); return; } } if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[0]) ){ sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); } } SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char c){ static const char isFtsIdChar[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ }; return (c&0x80 || isFtsIdChar[(int)(c)]); } SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *zStr, int *pn){ const char *z1; const char *z2 = 0; /* Find the start of the next token. */ z1 = zStr; while( z2==0 ){ char c = *z1; switch( c ){ case '\0': return 0; /* No more tokens here */ case '\'': case '"': case '`': { z2 = z1; while( *++z2 && (*z2!=c || *++z2==c) ); break; } case '[': z2 = &z1[1]; while( *z2 && z2[0]!=']' ) z2++; if( *z2 ) z2++; break; default: if( sqlite3Fts3IsIdChar(*z1) ){ z2 = &z1[1]; while( sqlite3Fts3IsIdChar(*z2) ) z2++; }else{ z1++; } } } *pn = (int)(z2-z1); return z1; } SQLITE_PRIVATE int sqlite3Fts3InitTokenizer( Fts3Hash *pHash, /* Tokenizer hash table */ const char *zArg, /* Tokenizer name */ sqlite3_tokenizer **ppTok, /* OUT: Tokenizer (if applicable) */ char **pzErr /* OUT: Set to malloced error message */ ){ int rc; char *z = (char *)zArg; int n = 0; char *zCopy; char *zEnd; /* Pointer to nul-term of zCopy */ sqlite3_tokenizer_module *m; zCopy = sqlite3_mprintf("%s", zArg); if( !zCopy ) return SQLITE_NOMEM; zEnd = &zCopy[strlen(zCopy)]; z = (char *)sqlite3Fts3NextToken(zCopy, &n); if( z==0 ){ assert( n==0 ); z = zCopy; } z[n] = '\0'; sqlite3Fts3Dequote(z); m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash,z,(int)strlen(z)+1); if( !m ){ sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", z); rc = SQLITE_ERROR; }else{ char const **aArg = 0; int iArg = 0; z = &z[n+1]; while( zxCreate(iArg, aArg, ppTok); assert( rc!=SQLITE_OK || *ppTok ); if( rc!=SQLITE_OK ){ sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer"); }else{ (*ppTok)->pModule = m; } sqlite3_free((void *)aArg); } sqlite3_free(zCopy); return rc; } #ifdef SQLITE_TEST #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif /* #include */ /* ** Implementation of a special SQL scalar function for testing tokenizers ** designed to be used in concert with the Tcl testing framework. This ** function must be called with two or more arguments: ** ** SELECT (, ..., ); ** ** where is the name passed as the second argument ** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer') ** concatenated with the string '_test' (e.g. 'fts3_tokenizer_test'). ** ** The return value is a string that may be interpreted as a Tcl ** list. For each token in the , three elements are ** added to the returned list. The first is the token position, the ** second is the token text (folded, stemmed, etc.) and the third is the ** substring of associated with the token. For example, ** using the built-in "simple" tokenizer: ** ** SELECT fts_tokenizer_test('simple', 'I don't see how'); ** ** will return the string: ** ** "{0 i I 1 dont don't 2 see see 3 how how}" ** */ static void testFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ Fts3Hash *pHash; sqlite3_tokenizer_module *p; sqlite3_tokenizer *pTokenizer = 0; sqlite3_tokenizer_cursor *pCsr = 0; const char *zErr = 0; const char *zName; int nName; const char *zInput; int nInput; const char *azArg[64]; const char *zToken; int nToken = 0; int iStart = 0; int iEnd = 0; int iPos = 0; int i; Tcl_Obj *pRet; if( argc<2 ){ sqlite3_result_error(context, "insufficient arguments", -1); return; } nName = sqlite3_value_bytes(argv[0]); zName = (const char *)sqlite3_value_text(argv[0]); nInput = sqlite3_value_bytes(argv[argc-1]); zInput = (const char *)sqlite3_value_text(argv[argc-1]); pHash = (Fts3Hash *)sqlite3_user_data(context); p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); if( !p ){ char *zErr2 = sqlite3_mprintf("unknown tokenizer: %s", zName); sqlite3_result_error(context, zErr2, -1); sqlite3_free(zErr2); return; } pRet = Tcl_NewObj(); Tcl_IncrRefCount(pRet); for(i=1; ixCreate(argc-2, azArg, &pTokenizer) ){ zErr = "error in xCreate()"; goto finish; } pTokenizer->pModule = p; if( sqlite3Fts3OpenTokenizer(pTokenizer, 0, zInput, nInput, &pCsr) ){ zErr = "error in xOpen()"; goto finish; } while( SQLITE_OK==p->xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos) ){ Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(iPos)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken)); zToken = &zInput[iStart]; nToken = iEnd-iStart; Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken)); } if( SQLITE_OK!=p->xClose(pCsr) ){ zErr = "error in xClose()"; goto finish; } if( SQLITE_OK!=p->xDestroy(pTokenizer) ){ zErr = "error in xDestroy()"; goto finish; } finish: if( zErr ){ sqlite3_result_error(context, zErr, -1); }else{ sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT); } Tcl_DecrRefCount(pRet); } static int registerTokenizer( sqlite3 *db, char *zName, const sqlite3_tokenizer_module *p ){ int rc; sqlite3_stmt *pStmt; const char zSql[] = "SELECT fts3_tokenizer(?, ?)"; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ){ return rc; } sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC); sqlite3_step(pStmt); return sqlite3_finalize(pStmt); } static int queryTokenizer( sqlite3 *db, char *zName, const sqlite3_tokenizer_module **pp ){ int rc; sqlite3_stmt *pStmt; const char zSql[] = "SELECT fts3_tokenizer(?)"; *pp = 0; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ){ return rc; } sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); if( SQLITE_ROW==sqlite3_step(pStmt) ){ if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB && sqlite3_column_bytes(pStmt, 0)==sizeof(*pp) ){ memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); } } return sqlite3_finalize(pStmt); } SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); /* ** Implementation of the scalar function fts3_tokenizer_internal_test(). ** This function is used for testing only, it is not included in the ** build unless SQLITE_TEST is defined. ** ** The purpose of this is to test that the fts3_tokenizer() function ** can be used as designed by the C-code in the queryTokenizer and ** registerTokenizer() functions above. These two functions are repeated ** in the README.tokenizer file as an example, so it is important to ** test them. ** ** To run the tests, evaluate the fts3_tokenizer_internal_test() scalar ** function with no arguments. An assert() will fail if a problem is ** detected. i.e.: ** ** SELECT fts3_tokenizer_internal_test(); ** */ static void intTestFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int rc; const sqlite3_tokenizer_module *p1; const sqlite3_tokenizer_module *p2; sqlite3 *db = (sqlite3 *)sqlite3_user_data(context); UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); /* Test the query function */ sqlite3Fts3SimpleTokenizerModule(&p1); rc = queryTokenizer(db, "simple", &p2); assert( rc==SQLITE_OK ); assert( p1==p2 ); rc = queryTokenizer(db, "nosuchtokenizer", &p2); assert( rc==SQLITE_ERROR ); assert( p2==0 ); assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") ); /* Test the storage function */ if( fts3TokenizerEnabled(context) ){ rc = registerTokenizer(db, "nosuchtokenizer", p1); assert( rc==SQLITE_OK ); rc = queryTokenizer(db, "nosuchtokenizer", &p2); assert( rc==SQLITE_OK ); assert( p2==p1 ); } sqlite3_result_text(context, "ok", -1, SQLITE_STATIC); } #endif /* ** Set up SQL objects in database db used to access the contents of ** the hash table pointed to by argument pHash. The hash table must ** been initialized to use string keys, and to take a private copy ** of the key when a value is inserted. i.e. by a call similar to: ** ** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); ** ** This function adds a scalar function (see header comment above ** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is ** defined at compilation time, a temporary virtual table (see header ** comment above struct HashTableVtab) to the database schema. Both ** provide read/write access to the contents of *pHash. ** ** The third argument to this function, zName, is used as the name ** of both the scalar and, if created, the virtual table. */ SQLITE_PRIVATE int sqlite3Fts3InitHashTable( sqlite3 *db, Fts3Hash *pHash, const char *zName ){ int rc = SQLITE_OK; void *p = (void *)pHash; const int any = SQLITE_UTF8|SQLITE_DIRECTONLY; #ifdef SQLITE_TEST char *zTest = 0; char *zTest2 = 0; void *pdb = (void *)db; zTest = sqlite3_mprintf("%s_test", zName); zTest2 = sqlite3_mprintf("%s_internal_test", zName); if( !zTest || !zTest2 ){ rc = SQLITE_NOMEM; } #endif if( SQLITE_OK==rc ){ rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0); } if( SQLITE_OK==rc ){ rc = sqlite3_create_function(db, zName, 2, any, p, fts3TokenizerFunc, 0, 0); } #ifdef SQLITE_TEST if( SQLITE_OK==rc ){ rc = sqlite3_create_function(db, zTest, -1, any, p, testFunc, 0, 0); } if( SQLITE_OK==rc ){ rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0); } #endif #ifdef SQLITE_TEST sqlite3_free(zTest); sqlite3_free(zTest2); #endif return rc; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ /************** End of fts3_tokenizer.c **************************************/ /************** Begin file fts3_tokenizer1.c *********************************/ /* ** 2006 Oct 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** Implementation of the "simple" full-text-search tokenizer. */ /* ** The code in this file is only compiled if: ** ** * The FTS3 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include */ /* #include */ /* #include */ /* #include */ /* #include "fts3_tokenizer.h" */ typedef struct simple_tokenizer { sqlite3_tokenizer base; char delim[128]; /* flag ASCII delimiters */ } simple_tokenizer; typedef struct simple_tokenizer_cursor { sqlite3_tokenizer_cursor base; const char *pInput; /* input we are tokenizing */ int nBytes; /* size of the input */ int iOffset; /* current position in pInput */ int iToken; /* index of next token to be returned */ char *pToken; /* storage for current token */ int nTokenAllocated; /* space allocated to zToken buffer */ } simple_tokenizer_cursor; static int simpleDelim(simple_tokenizer *t, unsigned char c){ return c<0x80 && t->delim[c]; } static int fts3_isalnum(int x){ return (x>='0' && x<='9') || (x>='A' && x<='Z') || (x>='a' && x<='z'); } /* ** Create a new tokenizer instance. */ static int simpleCreate( int argc, const char * const *argv, sqlite3_tokenizer **ppTokenizer ){ simple_tokenizer *t; t = (simple_tokenizer *) sqlite3_malloc(sizeof(*t)); if( t==NULL ) return SQLITE_NOMEM; memset(t, 0, sizeof(*t)); /* TODO(shess) Delimiters need to remain the same from run to run, ** else we need to reindex. One solution would be a meta-table to ** track such information in the database, then we'd only want this ** information on the initial create. */ if( argc>1 ){ int i, n = (int)strlen(argv[1]); for(i=0; i=0x80 ){ sqlite3_free(t); return SQLITE_ERROR; } t->delim[ch] = 1; } } else { /* Mark non-alphanumeric ASCII characters as delimiters */ int i; for(i=1; i<0x80; i++){ t->delim[i] = !fts3_isalnum(i) ? -1 : 0; } } *ppTokenizer = &t->base; return SQLITE_OK; } /* ** Destroy a tokenizer */ static int simpleDestroy(sqlite3_tokenizer *pTokenizer){ sqlite3_free(pTokenizer); return SQLITE_OK; } /* ** Prepare to begin tokenizing a particular string. The input ** string to be tokenized is pInput[0..nBytes-1]. A cursor ** used to incrementally tokenize this string is returned in ** *ppCursor. */ static int simpleOpen( sqlite3_tokenizer *pTokenizer, /* The tokenizer */ const char *pInput, int nBytes, /* String to be tokenized */ sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ ){ simple_tokenizer_cursor *c; UNUSED_PARAMETER(pTokenizer); c = (simple_tokenizer_cursor *) sqlite3_malloc(sizeof(*c)); if( c==NULL ) return SQLITE_NOMEM; c->pInput = pInput; if( pInput==0 ){ c->nBytes = 0; }else if( nBytes<0 ){ c->nBytes = (int)strlen(pInput); }else{ c->nBytes = nBytes; } c->iOffset = 0; /* start tokenizing at the beginning */ c->iToken = 0; c->pToken = NULL; /* no space allocated, yet. */ c->nTokenAllocated = 0; *ppCursor = &c->base; return SQLITE_OK; } /* ** Close a tokenization cursor previously opened by a call to ** simpleOpen() above. */ static int simpleClose(sqlite3_tokenizer_cursor *pCursor){ simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; sqlite3_free(c->pToken); sqlite3_free(c); return SQLITE_OK; } /* ** Extract the next token from a tokenization cursor. The cursor must ** have been opened by a prior call to simpleOpen(). */ static int simpleNext( sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ const char **ppToken, /* OUT: *ppToken is the token text */ int *pnBytes, /* OUT: Number of bytes in token */ int *piStartOffset, /* OUT: Starting offset of token */ int *piEndOffset, /* OUT: Ending offset of token */ int *piPosition /* OUT: Position integer of token */ ){ simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer; unsigned char *p = (unsigned char *)c->pInput; while( c->iOffsetnBytes ){ int iStartOffset; /* Scan past delimiter characters */ while( c->iOffsetnBytes && simpleDelim(t, p[c->iOffset]) ){ c->iOffset++; } /* Count non-delimiter characters. */ iStartOffset = c->iOffset; while( c->iOffsetnBytes && !simpleDelim(t, p[c->iOffset]) ){ c->iOffset++; } if( c->iOffset>iStartOffset ){ int i, n = c->iOffset-iStartOffset; if( n>c->nTokenAllocated ){ char *pNew; c->nTokenAllocated = n+20; pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated); if( !pNew ) return SQLITE_NOMEM; c->pToken = pNew; } for(i=0; ipToken[i] = (char)((ch>='A' && ch<='Z') ? ch-'A'+'a' : ch); } *ppToken = c->pToken; *pnBytes = n; *piStartOffset = iStartOffset; *piEndOffset = c->iOffset; *piPosition = c->iToken++; return SQLITE_OK; } } return SQLITE_DONE; } /* ** The set of routines that implement the simple tokenizer */ static const sqlite3_tokenizer_module simpleTokenizerModule = { 0, simpleCreate, simpleDestroy, simpleOpen, simpleClose, simpleNext, 0, }; /* ** Allocate a new simple tokenizer. Return a pointer to the new ** tokenizer in *ppModule */ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule( sqlite3_tokenizer_module const**ppModule ){ *ppModule = &simpleTokenizerModule; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ /************** End of fts3_tokenizer1.c *************************************/ /************** Begin file fts3_tokenize_vtab.c ******************************/ /* ** 2013 Apr 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code for the "fts3tokenize" virtual table module. ** An fts3tokenize virtual table is created as follows: ** ** CREATE VIRTUAL TABLE USING fts3tokenize( ** , , ... ** ); ** ** The table created has the following schema: ** ** CREATE TABLE (input, token, start, end, position) ** ** When queried, the query must include a WHERE clause of type: ** ** input = ** ** The virtual table module tokenizes this , using the FTS3 ** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE ** statement and returns one row for each token in the result. With ** fields set as follows: ** ** input: Always set to a copy of ** token: A token from the input. ** start: Byte offset of the token within the input . ** end: Byte offset of the byte immediately following the end of the ** token within the input string. ** pos: Token offset of token within input. ** */ /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include */ /* #include */ typedef struct Fts3tokTable Fts3tokTable; typedef struct Fts3tokCursor Fts3tokCursor; /* ** Virtual table structure. */ struct Fts3tokTable { sqlite3_vtab base; /* Base class used by SQLite core */ const sqlite3_tokenizer_module *pMod; sqlite3_tokenizer *pTok; }; /* ** Virtual table cursor structure. */ struct Fts3tokCursor { sqlite3_vtab_cursor base; /* Base class used by SQLite core */ char *zInput; /* Input string */ sqlite3_tokenizer_cursor *pCsr; /* Cursor to iterate through zInput */ int iRowid; /* Current 'rowid' value */ const char *zToken; /* Current 'token' value */ int nToken; /* Size of zToken in bytes */ int iStart; /* Current 'start' value */ int iEnd; /* Current 'end' value */ int iPos; /* Current 'pos' value */ }; /* ** Query FTS for the tokenizer implementation named zName. */ static int fts3tokQueryTokenizer( Fts3Hash *pHash, const char *zName, const sqlite3_tokenizer_module **pp, char **pzErr ){ sqlite3_tokenizer_module *p; int nName = (int)strlen(zName); p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); if( !p ){ sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", zName); return SQLITE_ERROR; } *pp = p; return SQLITE_OK; } /* ** The second argument, argv[], is an array of pointers to nul-terminated ** strings. This function makes a copy of the array and strings into a ** single block of memory. It then dequotes any of the strings that appear ** to be quoted. ** ** If successful, output parameter *pazDequote is set to point at the ** array of dequoted strings and SQLITE_OK is returned. The caller is ** responsible for eventually calling sqlite3_free() to free the array ** in this case. Or, if an error occurs, an SQLite error code is returned. ** The final value of *pazDequote is undefined in this case. */ static int fts3tokDequoteArray( int argc, /* Number of elements in argv[] */ const char * const *argv, /* Input array */ char ***pazDequote /* Output array */ ){ int rc = SQLITE_OK; /* Return code */ if( argc==0 ){ *pazDequote = 0; }else{ int i; int nByte = 0; char **azDequote; for(i=0; i1 ) azArg = (const char * const *)&azDequote[1]; rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok); } if( rc==SQLITE_OK ){ pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable)); if( pTab==0 ){ rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK ){ memset(pTab, 0, sizeof(Fts3tokTable)); pTab->pMod = pMod; pTab->pTok = pTok; *ppVtab = &pTab->base; }else{ if( pTok ){ pMod->xDestroy(pTok); } } sqlite3_free(azDequote); return rc; } /* ** This function does the work for both the xDisconnect and xDestroy methods. ** These tables have no persistent representation of their own, so xDisconnect ** and xDestroy are identical operations. */ static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){ Fts3tokTable *pTab = (Fts3tokTable *)pVtab; pTab->pMod->xDestroy(pTab->pTok); sqlite3_free(pTab); return SQLITE_OK; } /* ** xBestIndex - Analyze a WHERE and ORDER BY clause. */ static int fts3tokBestIndexMethod( sqlite3_vtab *pVTab, sqlite3_index_info *pInfo ){ int i; UNUSED_PARAMETER(pVTab); for(i=0; inConstraint; i++){ if( pInfo->aConstraint[i].usable && pInfo->aConstraint[i].iColumn==0 && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ ){ pInfo->idxNum = 1; pInfo->aConstraintUsage[i].argvIndex = 1; pInfo->aConstraintUsage[i].omit = 1; pInfo->estimatedCost = 1; return SQLITE_OK; } } pInfo->idxNum = 0; assert( pInfo->estimatedCost>1000000.0 ); return SQLITE_OK; } /* ** xOpen - Open a cursor. */ static int fts3tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ Fts3tokCursor *pCsr; UNUSED_PARAMETER(pVTab); pCsr = (Fts3tokCursor *)sqlite3_malloc(sizeof(Fts3tokCursor)); if( pCsr==0 ){ return SQLITE_NOMEM; } memset(pCsr, 0, sizeof(Fts3tokCursor)); *ppCsr = (sqlite3_vtab_cursor *)pCsr; return SQLITE_OK; } /* ** Reset the tokenizer cursor passed as the only argument. As if it had ** just been returned by fts3tokOpenMethod(). */ static void fts3tokResetCursor(Fts3tokCursor *pCsr){ if( pCsr->pCsr ){ Fts3tokTable *pTab = (Fts3tokTable *)(pCsr->base.pVtab); pTab->pMod->xClose(pCsr->pCsr); pCsr->pCsr = 0; } sqlite3_free(pCsr->zInput); pCsr->zInput = 0; pCsr->zToken = 0; pCsr->nToken = 0; pCsr->iStart = 0; pCsr->iEnd = 0; pCsr->iPos = 0; pCsr->iRowid = 0; } /* ** xClose - Close a cursor. */ static int fts3tokCloseMethod(sqlite3_vtab_cursor *pCursor){ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; fts3tokResetCursor(pCsr); sqlite3_free(pCsr); return SQLITE_OK; } /* ** xNext - Advance the cursor to the next row, if any. */ static int fts3tokNextMethod(sqlite3_vtab_cursor *pCursor){ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); int rc; /* Return code */ pCsr->iRowid++; rc = pTab->pMod->xNext(pCsr->pCsr, &pCsr->zToken, &pCsr->nToken, &pCsr->iStart, &pCsr->iEnd, &pCsr->iPos ); if( rc!=SQLITE_OK ){ fts3tokResetCursor(pCsr); if( rc==SQLITE_DONE ) rc = SQLITE_OK; } return rc; } /* ** xFilter - Initialize a cursor to point at the start of its data. */ static int fts3tokFilterMethod( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, /* Strategy index */ const char *idxStr, /* Unused */ int nVal, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ int rc = SQLITE_ERROR; Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(nVal); fts3tokResetCursor(pCsr); if( idxNum==1 ){ const char *zByte = (const char *)sqlite3_value_text(apVal[0]); int nByte = sqlite3_value_bytes(apVal[0]); pCsr->zInput = sqlite3_malloc64(nByte+1); if( pCsr->zInput==0 ){ rc = SQLITE_NOMEM; }else{ if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte); pCsr->zInput[nByte] = 0; rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr); if( rc==SQLITE_OK ){ pCsr->pCsr->pTokenizer = pTab->pTok; } } } if( rc!=SQLITE_OK ) return rc; return fts3tokNextMethod(pCursor); } /* ** xEof - Return true if the cursor is at EOF, or false otherwise. */ static int fts3tokEofMethod(sqlite3_vtab_cursor *pCursor){ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; return (pCsr->zToken==0); } /* ** xColumn - Return a column value. */ static int fts3tokColumnMethod( sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ int iCol /* Index of column to read value from */ ){ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; /* CREATE TABLE x(input, token, start, end, position) */ switch( iCol ){ case 0: sqlite3_result_text(pCtx, pCsr->zInput, -1, SQLITE_TRANSIENT); break; case 1: sqlite3_result_text(pCtx, pCsr->zToken, pCsr->nToken, SQLITE_TRANSIENT); break; case 2: sqlite3_result_int(pCtx, pCsr->iStart); break; case 3: sqlite3_result_int(pCtx, pCsr->iEnd); break; default: assert( iCol==4 ); sqlite3_result_int(pCtx, pCsr->iPos); break; } return SQLITE_OK; } /* ** xRowid - Return the current rowid for the cursor. */ static int fts3tokRowidMethod( sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ sqlite_int64 *pRowid /* OUT: Rowid value */ ){ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; *pRowid = (sqlite3_int64)pCsr->iRowid; return SQLITE_OK; } /* ** Register the fts3tok module with database connection db. Return SQLITE_OK ** if successful or an error code if sqlite3_create_module() fails. */ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash, void(*xDestroy)(void*)){ static const sqlite3_module fts3tok_module = { 0, /* iVersion */ fts3tokConnectMethod, /* xCreate */ fts3tokConnectMethod, /* xConnect */ fts3tokBestIndexMethod, /* xBestIndex */ fts3tokDisconnectMethod, /* xDisconnect */ fts3tokDisconnectMethod, /* xDestroy */ fts3tokOpenMethod, /* xOpen */ fts3tokCloseMethod, /* xClose */ fts3tokFilterMethod, /* xFilter */ fts3tokNextMethod, /* xNext */ fts3tokEofMethod, /* xEof */ fts3tokColumnMethod, /* xColumn */ fts3tokRowidMethod, /* xRowid */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindFunction */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ 0 /* xIntegrity */ }; int rc; /* Return code */ rc = sqlite3_create_module_v2( db, "fts3tokenize", &fts3tok_module, (void*)pHash, xDestroy ); return rc; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ /************** End of fts3_tokenize_vtab.c **********************************/ /************** Begin file fts3_write.c **************************************/ /* ** 2009 Oct 23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file is part of the SQLite FTS3 extension module. Specifically, ** this file contains code to insert, update and delete rows from FTS3 ** tables. It also contains code to merge FTS3 b-tree segments. Some ** of the sub-routines used to merge segments are also used by the query ** code in fts3.c. */ /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include */ /* #include */ /* #include */ /* #include */ #define FTS_MAX_APPENDABLE_HEIGHT 16 /* ** When full-text index nodes are loaded from disk, the buffer that they ** are loaded into has the following number of bytes of padding at the end ** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer ** of 920 bytes is allocated for it. ** ** This means that if we have a pointer into a buffer containing node data, ** it is always safe to read up to two varints from it without risking an ** overread, even if the node data is corrupted. */ #define FTS3_NODE_PADDING (FTS3_VARINT_MAX*2) /* ** Under certain circumstances, b-tree nodes (doclists) can be loaded into ** memory incrementally instead of all at once. This can be a big performance ** win (reduced IO and CPU) if SQLite stops calling the virtual table xNext() ** method before retrieving all query results (as may happen, for example, ** if a query has a LIMIT clause). ** ** Incremental loading is used for b-tree nodes FTS3_NODE_CHUNK_THRESHOLD ** bytes and larger. Nodes are loaded in chunks of FTS3_NODE_CHUNKSIZE bytes. ** The code is written so that the hard lower-limit for each of these values ** is 1. Clearly such small values would be inefficient, but can be useful ** for testing purposes. ** ** If this module is built with SQLITE_TEST defined, these constants may ** be overridden at runtime for testing purposes. File fts3_test.c contains ** a Tcl interface to read and write the values. */ #ifdef SQLITE_TEST int test_fts3_node_chunksize = (4*1024); int test_fts3_node_chunk_threshold = (4*1024)*4; # define FTS3_NODE_CHUNKSIZE test_fts3_node_chunksize # define FTS3_NODE_CHUNK_THRESHOLD test_fts3_node_chunk_threshold #else # define FTS3_NODE_CHUNKSIZE (4*1024) # define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4) #endif /* ** The values that may be meaningfully bound to the :1 parameter in ** statements SQL_REPLACE_STAT and SQL_SELECT_STAT. */ #define FTS_STAT_DOCTOTAL 0 #define FTS_STAT_INCRMERGEHINT 1 #define FTS_STAT_AUTOINCRMERGE 2 /* ** If FTS_LOG_MERGES is defined, call sqlite3_log() to report each automatic ** and incremental merge operation that takes place. This is used for ** debugging FTS only, it should not usually be turned on in production ** systems. */ #ifdef FTS3_LOG_MERGES static void fts3LogMerge(int nMerge, sqlite3_int64 iAbsLevel){ sqlite3_log(SQLITE_OK, "%d-way merge from level %d", nMerge, (int)iAbsLevel); } #else #define fts3LogMerge(x, y) #endif typedef struct PendingList PendingList; typedef struct SegmentNode SegmentNode; typedef struct SegmentWriter SegmentWriter; /* ** An instance of the following data structure is used to build doclists ** incrementally. See function fts3PendingListAppend() for details. */ struct PendingList { int nData; char *aData; int nSpace; sqlite3_int64 iLastDocid; sqlite3_int64 iLastCol; sqlite3_int64 iLastPos; }; /* ** Each cursor has a (possibly empty) linked list of the following objects. */ struct Fts3DeferredToken { Fts3PhraseToken *pToken; /* Pointer to corresponding expr token */ int iCol; /* Column token must occur in */ Fts3DeferredToken *pNext; /* Next in list of deferred tokens */ PendingList *pList; /* Doclist is assembled here */ }; /* ** An instance of this structure is used to iterate through the terms on ** a contiguous set of segment b-tree leaf nodes. Although the details of ** this structure are only manipulated by code in this file, opaque handles ** of type Fts3SegReader* are also used by code in fts3.c to iterate through ** terms when querying the full-text index. See functions: ** ** sqlite3Fts3SegReaderNew() ** sqlite3Fts3SegReaderFree() ** sqlite3Fts3SegReaderIterate() ** ** Methods used to manipulate Fts3SegReader structures: ** ** fts3SegReaderNext() ** fts3SegReaderFirstDocid() ** fts3SegReaderNextDocid() */ struct Fts3SegReader { int iIdx; /* Index within level, or 0x7FFFFFFF for PT */ u8 bLookup; /* True for a lookup only */ u8 rootOnly; /* True for a root-only reader */ sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */ sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */ sqlite3_int64 iEndBlock; /* Rowid of final block in segment (or 0) */ sqlite3_int64 iCurrentBlock; /* Current leaf block (or 0) */ char *aNode; /* Pointer to node data (or NULL) */ int nNode; /* Size of buffer at aNode (or 0) */ int nPopulate; /* If >0, bytes of buffer aNode[] loaded */ sqlite3_blob *pBlob; /* If not NULL, blob handle to read node */ Fts3HashElem **ppNextElem; /* Variables set by fts3SegReaderNext(). These may be read directly ** by the caller. They are valid from the time SegmentReaderNew() returns ** until SegmentReaderNext() returns something other than SQLITE_OK ** (i.e. SQLITE_DONE). */ int nTerm; /* Number of bytes in current term */ char *zTerm; /* Pointer to current term */ int nTermAlloc; /* Allocated size of zTerm buffer */ char *aDoclist; /* Pointer to doclist of current entry */ int nDoclist; /* Size of doclist in current entry */ /* The following variables are used by fts3SegReaderNextDocid() to iterate ** through the current doclist (aDoclist/nDoclist). */ char *pOffsetList; int nOffsetList; /* For descending pending seg-readers only */ sqlite3_int64 iDocid; }; #define fts3SegReaderIsPending(p) ((p)->ppNextElem!=0) #define fts3SegReaderIsRootOnly(p) ((p)->rootOnly!=0) /* ** An instance of this structure is used to create a segment b-tree in the ** database. The internal details of this type are only accessed by the ** following functions: ** ** fts3SegWriterAdd() ** fts3SegWriterFlush() ** fts3SegWriterFree() */ struct SegmentWriter { SegmentNode *pTree; /* Pointer to interior tree structure */ sqlite3_int64 iFirst; /* First slot in %_segments written */ sqlite3_int64 iFree; /* Next free slot in %_segments */ char *zTerm; /* Pointer to previous term buffer */ int nTerm; /* Number of bytes in zTerm */ int nMalloc; /* Size of malloc'd buffer at zMalloc */ char *zMalloc; /* Malloc'd space (possibly) used for zTerm */ int nSize; /* Size of allocation at aData */ int nData; /* Bytes of data in aData */ char *aData; /* Pointer to block from malloc() */ i64 nLeafData; /* Number of bytes of leaf data written */ }; /* ** Type SegmentNode is used by the following three functions to create ** the interior part of the segment b+-tree structures (everything except ** the leaf nodes). These functions and type are only ever used by code ** within the fts3SegWriterXXX() family of functions described above. ** ** fts3NodeAddTerm() ** fts3NodeWrite() ** fts3NodeFree() ** ** When a b+tree is written to the database (either as a result of a merge ** or the pending-terms table being flushed), leaves are written into the ** database file as soon as they are completely populated. The interior of ** the tree is assembled in memory and written out only once all leaves have ** been populated and stored. This is Ok, as the b+-tree fanout is usually ** very large, meaning that the interior of the tree consumes relatively ** little memory. */ struct SegmentNode { SegmentNode *pParent; /* Parent node (or NULL for root node) */ SegmentNode *pRight; /* Pointer to right-sibling */ SegmentNode *pLeftmost; /* Pointer to left-most node of this depth */ int nEntry; /* Number of terms written to node so far */ char *zTerm; /* Pointer to previous term buffer */ int nTerm; /* Number of bytes in zTerm */ int nMalloc; /* Size of malloc'd buffer at zMalloc */ char *zMalloc; /* Malloc'd space (possibly) used for zTerm */ int nData; /* Bytes of valid data so far */ char *aData; /* Node data */ }; /* ** Valid values for the second argument to fts3SqlStmt(). */ #define SQL_DELETE_CONTENT 0 #define SQL_IS_EMPTY 1 #define SQL_DELETE_ALL_CONTENT 2 #define SQL_DELETE_ALL_SEGMENTS 3 #define SQL_DELETE_ALL_SEGDIR 4 #define SQL_DELETE_ALL_DOCSIZE 5 #define SQL_DELETE_ALL_STAT 6 #define SQL_SELECT_CONTENT_BY_ROWID 7 #define SQL_NEXT_SEGMENT_INDEX 8 #define SQL_INSERT_SEGMENTS 9 #define SQL_NEXT_SEGMENTS_ID 10 #define SQL_INSERT_SEGDIR 11 #define SQL_SELECT_LEVEL 12 #define SQL_SELECT_LEVEL_RANGE 13 #define SQL_SELECT_LEVEL_COUNT 14 #define SQL_SELECT_SEGDIR_MAX_LEVEL 15 #define SQL_DELETE_SEGDIR_LEVEL 16 #define SQL_DELETE_SEGMENTS_RANGE 17 #define SQL_CONTENT_INSERT 18 #define SQL_DELETE_DOCSIZE 19 #define SQL_REPLACE_DOCSIZE 20 #define SQL_SELECT_DOCSIZE 21 #define SQL_SELECT_STAT 22 #define SQL_REPLACE_STAT 23 #define SQL_SELECT_ALL_PREFIX_LEVEL 24 #define SQL_DELETE_ALL_TERMS_SEGDIR 25 #define SQL_DELETE_SEGDIR_RANGE 26 #define SQL_SELECT_ALL_LANGID 27 #define SQL_FIND_MERGE_LEVEL 28 #define SQL_MAX_LEAF_NODE_ESTIMATE 29 #define SQL_DELETE_SEGDIR_ENTRY 30 #define SQL_SHIFT_SEGDIR_ENTRY 31 #define SQL_SELECT_SEGDIR 32 #define SQL_CHOMP_SEGDIR 33 #define SQL_SEGMENT_IS_APPENDABLE 34 #define SQL_SELECT_INDEXES 35 #define SQL_SELECT_MXLEVEL 36 #define SQL_SELECT_LEVEL_RANGE2 37 #define SQL_UPDATE_LEVEL_IDX 38 #define SQL_UPDATE_LEVEL 39 /* ** This function is used to obtain an SQLite prepared statement handle ** for the statement identified by the second argument. If successful, ** *pp is set to the requested statement handle and SQLITE_OK returned. ** Otherwise, an SQLite error code is returned and *pp is set to 0. ** ** If argument apVal is not NULL, then it must point to an array with ** at least as many entries as the requested statement has bound ** parameters. The values are bound to the statements parameters before ** returning. */ static int fts3SqlStmt( Fts3Table *p, /* Virtual table handle */ int eStmt, /* One of the SQL_XXX constants above */ sqlite3_stmt **pp, /* OUT: Statement handle */ sqlite3_value **apVal /* Values to bind to statement */ ){ const char *azSql[] = { /* 0 */ "DELETE FROM %Q.'%q_content' WHERE rowid = ?", /* 1 */ "SELECT NOT EXISTS(SELECT docid FROM %Q.'%q_content' WHERE rowid!=?)", /* 2 */ "DELETE FROM %Q.'%q_content'", /* 3 */ "DELETE FROM %Q.'%q_segments'", /* 4 */ "DELETE FROM %Q.'%q_segdir'", /* 5 */ "DELETE FROM %Q.'%q_docsize'", /* 6 */ "DELETE FROM %Q.'%q_stat'", /* 7 */ "SELECT %s WHERE rowid=?", /* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1", /* 9 */ "REPLACE INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)", /* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)", /* 11 */ "REPLACE INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)", /* Return segments in order from oldest to newest.*/ /* 12 */ "SELECT idx, start_block, leaves_end_block, end_block, root " "FROM %Q.'%q_segdir' WHERE level = ? ORDER BY idx ASC", /* 13 */ "SELECT idx, start_block, leaves_end_block, end_block, root " "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?" "ORDER BY level DESC, idx ASC", /* 14 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?", /* 15 */ "SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", /* 16 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?", /* 17 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?", /* 18 */ "INSERT INTO %Q.'%q_content' VALUES(%s)", /* 19 */ "DELETE FROM %Q.'%q_docsize' WHERE docid = ?", /* 20 */ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", /* 21 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?", /* 22 */ "SELECT value FROM %Q.'%q_stat' WHERE id=?", /* 23 */ "REPLACE INTO %Q.'%q_stat' VALUES(?,?)", /* 24 */ "", /* 25 */ "", /* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", /* 27 */ "SELECT ? UNION SELECT level / (1024 * ?) FROM %Q.'%q_segdir'", /* This statement is used to determine which level to read the input from ** when performing an incremental merge. It returns the absolute level number ** of the oldest level in the db that contains at least ? segments. Or, ** if no level in the FTS index contains more than ? segments, the statement ** returns zero rows. */ /* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' " " GROUP BY level HAVING cnt>=?" " ORDER BY (level %% 1024) ASC, 2 DESC LIMIT 1", /* Estimate the upper limit on the number of leaf nodes in a new segment ** created by merging the oldest :2 segments from absolute level :1. See ** function sqlite3Fts3Incrmerge() for details. */ /* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) " " FROM (SELECT * FROM %Q.'%q_segdir' " " WHERE level = ? ORDER BY idx ASC LIMIT ?" " )", /* SQL_DELETE_SEGDIR_ENTRY ** Delete the %_segdir entry on absolute level :1 with index :2. */ /* 30 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?", /* SQL_SHIFT_SEGDIR_ENTRY ** Modify the idx value for the segment with idx=:3 on absolute level :2 ** to :1. */ /* 31 */ "UPDATE %Q.'%q_segdir' SET idx = ? WHERE level=? AND idx=?", /* SQL_SELECT_SEGDIR ** Read a single entry from the %_segdir table. The entry from absolute ** level :1 with index value :2. */ /* 32 */ "SELECT idx, start_block, leaves_end_block, end_block, root " "FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?", /* SQL_CHOMP_SEGDIR ** Update the start_block (:1) and root (:2) fields of the %_segdir ** entry located on absolute level :3 with index :4. */ /* 33 */ "UPDATE %Q.'%q_segdir' SET start_block = ?, root = ?" "WHERE level = ? AND idx = ?", /* SQL_SEGMENT_IS_APPENDABLE ** Return a single row if the segment with end_block=? is appendable. Or ** no rows otherwise. */ /* 34 */ "SELECT 1 FROM %Q.'%q_segments' WHERE blockid=? AND block IS NULL", /* SQL_SELECT_INDEXES ** Return the list of valid segment indexes for absolute level ? */ /* 35 */ "SELECT idx FROM %Q.'%q_segdir' WHERE level=? ORDER BY 1 ASC", /* SQL_SELECT_MXLEVEL ** Return the largest relative level in the FTS index or indexes. */ /* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'", /* Return segments in order from oldest to newest.*/ /* 37 */ "SELECT level, idx, end_block " "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? " "ORDER BY level DESC, idx ASC", /* Update statements used while promoting segments */ /* 38 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=-1,idx=? " "WHERE level=? AND idx=?", /* 39 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=? WHERE level=-1" }; int rc = SQLITE_OK; sqlite3_stmt *pStmt; assert( SizeofArray(azSql)==SizeofArray(p->aStmt) ); assert( eStmt=0 ); pStmt = p->aStmt[eStmt]; if( !pStmt ){ int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB; char *zSql; if( eStmt==SQL_CONTENT_INSERT ){ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ f &= ~SQLITE_PREPARE_NO_VTAB; zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); }else{ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); } if( !zSql ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL); sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); p->aStmt[eStmt] = pStmt; } } if( apVal ){ int i; int nParam = sqlite3_bind_parameter_count(pStmt); for(i=0; rc==SQLITE_OK && inPendingData==0 ){ sqlite3_stmt *pStmt; rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_null(pStmt, 1); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); } } return rc; } /* ** FTS maintains a separate indexes for each language-id (a 32-bit integer). ** Within each language id, a separate index is maintained to store the ** document terms, and each configured prefix size (configured the FTS ** "prefix=" option). And each index consists of multiple levels ("relative ** levels"). ** ** All three of these values (the language id, the specific index and the ** level within the index) are encoded in 64-bit integer values stored ** in the %_segdir table on disk. This function is used to convert three ** separate component values into the single 64-bit integer value that ** can be used to query the %_segdir table. ** ** Specifically, each language-id/index combination is allocated 1024 ** 64-bit integer level values ("absolute levels"). The main terms index ** for language-id 0 is allocate values 0-1023. The first prefix index ** (if any) for language-id 0 is allocated values 1024-2047. And so on. ** Language 1 indexes are allocated immediately following language 0. ** ** So, for a system with nPrefix prefix indexes configured, the block of ** absolute levels that corresponds to language-id iLangid and index ** iIndex starts at absolute level ((iLangid * (nPrefix+1) + iIndex) * 1024). */ static sqlite3_int64 getAbsoluteLevel( Fts3Table *p, /* FTS3 table handle */ int iLangid, /* Language id */ int iIndex, /* Index in p->aIndex[] */ int iLevel /* Level of segments */ ){ sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */ assert_fts3_nc( iLangid>=0 ); assert( p->nIndex>0 ); assert( iIndex>=0 && iIndexnIndex ); iBase = ((sqlite3_int64)iLangid * p->nIndex + iIndex) * FTS3_SEGDIR_MAXLEVEL; return iBase + iLevel; } /* ** Set *ppStmt to a statement handle that may be used to iterate through ** all rows in the %_segdir table, from oldest to newest. If successful, ** return SQLITE_OK. If an error occurs while preparing the statement, ** return an SQLite error code. ** ** There is only ever one instance of this SQL statement compiled for ** each FTS3 table. ** ** The statement returns the following columns from the %_segdir table: ** ** 0: idx ** 1: start_block ** 2: leaves_end_block ** 3: end_block ** 4: root */ SQLITE_PRIVATE int sqlite3Fts3AllSegdirs( Fts3Table *p, /* FTS3 table */ int iLangid, /* Language being queried */ int iIndex, /* Index for p->aIndex[] */ int iLevel, /* Level to select (relative level) */ sqlite3_stmt **ppStmt /* OUT: Compiled statement */ ){ int rc; sqlite3_stmt *pStmt = 0; assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel>=0 ); assert( iLevel=0 && iIndexnIndex ); if( iLevel<0 ){ /* "SELECT * FROM %_segdir WHERE level BETWEEN ? AND ? ORDER BY ..." */ rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); sqlite3_bind_int64(pStmt, 2, getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) ); } }else{ /* "SELECT * FROM %_segdir WHERE level = ? ORDER BY ..." */ rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex,iLevel)); } } *ppStmt = pStmt; return rc; } /* ** Append a single varint to a PendingList buffer. SQLITE_OK is returned ** if successful, or an SQLite error code otherwise. ** ** This function also serves to allocate the PendingList structure itself. ** For example, to create a new PendingList structure containing two ** varints: ** ** PendingList *p = 0; ** fts3PendingListAppendVarint(&p, 1); ** fts3PendingListAppendVarint(&p, 2); */ static int fts3PendingListAppendVarint( PendingList **pp, /* IN/OUT: Pointer to PendingList struct */ sqlite3_int64 i /* Value to append to data */ ){ PendingList *p = *pp; /* Allocate or grow the PendingList as required. */ if( !p ){ p = sqlite3_malloc64(sizeof(*p) + 100); if( !p ){ return SQLITE_NOMEM; } p->nSpace = 100; p->aData = (char *)&p[1]; p->nData = 0; } else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){ i64 nNew = p->nSpace * 2; p = sqlite3_realloc64(p, sizeof(*p) + nNew); if( !p ){ sqlite3_free(*pp); *pp = 0; return SQLITE_NOMEM; } p->nSpace = (int)nNew; p->aData = (char *)&p[1]; } /* Append the new serialized varint to the end of the list. */ p->nData += sqlite3Fts3PutVarint(&p->aData[p->nData], i); p->aData[p->nData] = '\0'; *pp = p; return SQLITE_OK; } /* ** Add a docid/column/position entry to a PendingList structure. Non-zero ** is returned if the structure is sqlite3_realloced as part of adding ** the entry. Otherwise, zero. ** ** If an OOM error occurs, *pRc is set to SQLITE_NOMEM before returning. ** Zero is always returned in this case. Otherwise, if no OOM error occurs, ** it is set to SQLITE_OK. */ static int fts3PendingListAppend( PendingList **pp, /* IN/OUT: PendingList structure */ sqlite3_int64 iDocid, /* Docid for entry to add */ sqlite3_int64 iCol, /* Column for entry to add */ sqlite3_int64 iPos, /* Position of term for entry to add */ int *pRc /* OUT: Return code */ ){ PendingList *p = *pp; int rc = SQLITE_OK; assert( !p || p->iLastDocid<=iDocid ); if( !p || p->iLastDocid!=iDocid ){ u64 iDelta = (u64)iDocid - (u64)(p ? p->iLastDocid : 0); if( p ){ assert( p->nDatanSpace ); assert( p->aData[p->nData]==0 ); p->nData++; } if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iDelta)) ){ goto pendinglistappend_out; } p->iLastCol = -1; p->iLastPos = 0; p->iLastDocid = iDocid; } if( iCol>0 && p->iLastCol!=iCol ){ if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, 1)) || SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iCol)) ){ goto pendinglistappend_out; } p->iLastCol = iCol; p->iLastPos = 0; } if( iCol>=0 ){ assert( iPos>p->iLastPos || (iPos==0 && p->iLastPos==0) ); rc = fts3PendingListAppendVarint(&p, 2+iPos-p->iLastPos); if( rc==SQLITE_OK ){ p->iLastPos = iPos; } } pendinglistappend_out: *pRc = rc; if( p!=*pp ){ *pp = p; return 1; } return 0; } /* ** Free a PendingList object allocated by fts3PendingListAppend(). */ static void fts3PendingListDelete(PendingList *pList){ sqlite3_free(pList); } /* ** Add an entry to one of the pending-terms hash tables. */ static int fts3PendingTermsAddOne( Fts3Table *p, int iCol, int iPos, Fts3Hash *pHash, /* Pending terms hash table to add entry to */ const char *zToken, int nToken ){ PendingList *pList; int rc = SQLITE_OK; pList = (PendingList *)fts3HashFind(pHash, zToken, nToken); if( pList ){ p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem)); } if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){ if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){ /* Malloc failed while inserting the new entry. This can only ** happen if there was no previous entry for this token. */ assert( 0==fts3HashFind(pHash, zToken, nToken) ); sqlite3_free(pList); rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK ){ p->nPendingData += (pList->nData + nToken + sizeof(Fts3HashElem)); } return rc; } /* ** Tokenize the nul-terminated string zText and add all tokens to the ** pending-terms hash-table. The docid used is that currently stored in ** p->iPrevDocid, and the column is specified by argument iCol. ** ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. */ static int fts3PendingTermsAdd( Fts3Table *p, /* Table into which text will be inserted */ int iLangid, /* Language id to use */ const char *zText, /* Text of document to be inserted */ int iCol, /* Column into which text is being inserted */ u32 *pnWord /* IN/OUT: Incr. by number tokens inserted */ ){ int rc; int iStart = 0; int iEnd = 0; int iPos = 0; int nWord = 0; char const *zToken; int nToken = 0; sqlite3_tokenizer *pTokenizer = p->pTokenizer; sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; sqlite3_tokenizer_cursor *pCsr; int (*xNext)(sqlite3_tokenizer_cursor *pCursor, const char**,int*,int*,int*,int*); assert( pTokenizer && pModule ); /* If the user has inserted a NULL value, this function may be called with ** zText==0. In this case, add zero token entries to the hash table and ** return early. */ if( zText==0 ){ *pnWord = 0; return SQLITE_OK; } rc = sqlite3Fts3OpenTokenizer(pTokenizer, iLangid, zText, -1, &pCsr); if( rc!=SQLITE_OK ){ return rc; } xNext = pModule->xNext; while( SQLITE_OK==rc && SQLITE_OK==(rc = xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos)) ){ int i; if( iPos>=nWord ) nWord = iPos+1; /* Positions cannot be negative; we use -1 as a terminator internally. ** Tokens must have a non-zero length. */ if( iPos<0 || !zToken || nToken<=0 ){ rc = SQLITE_ERROR; break; } /* Add the term to the terms index */ rc = fts3PendingTermsAddOne( p, iCol, iPos, &p->aIndex[0].hPending, zToken, nToken ); /* Add the term to each of the prefix indexes that it is not too ** short for. */ for(i=1; rc==SQLITE_OK && inIndex; i++){ struct Fts3Index *pIndex = &p->aIndex[i]; if( nTokennPrefix ) continue; rc = fts3PendingTermsAddOne( p, iCol, iPos, &pIndex->hPending, zToken, pIndex->nPrefix ); } } pModule->xClose(pCsr); *pnWord += nWord; return (rc==SQLITE_DONE ? SQLITE_OK : rc); } /* ** Calling this function indicates that subsequent calls to ** fts3PendingTermsAdd() are to add term/position-list pairs for the ** contents of the document with docid iDocid. */ static int fts3PendingTermsDocid( Fts3Table *p, /* Full-text table handle */ int bDelete, /* True if this op is a delete */ int iLangid, /* Language id of row being written */ sqlite_int64 iDocid /* Docid of row being written */ ){ assert( iLangid>=0 ); assert( bDelete==1 || bDelete==0 ); /* TODO(shess) Explore whether partially flushing the buffer on ** forced-flush would provide better performance. I suspect that if ** we ordered the doclists by size and flushed the largest until the ** buffer was half empty, that would let the less frequent terms ** generate longer doclists. */ if( iDocidiPrevDocid || (iDocid==p->iPrevDocid && p->bPrevDelete==0) || p->iPrevLangid!=iLangid || p->nPendingData>p->nMaxPendingData ){ int rc = sqlite3Fts3PendingTermsFlush(p); if( rc!=SQLITE_OK ) return rc; } p->iPrevDocid = iDocid; p->iPrevLangid = iLangid; p->bPrevDelete = bDelete; return SQLITE_OK; } /* ** Discard the contents of the pending-terms hash tables. */ SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){ int i; for(i=0; inIndex; i++){ Fts3HashElem *pElem; Fts3Hash *pHash = &p->aIndex[i].hPending; for(pElem=fts3HashFirst(pHash); pElem; pElem=fts3HashNext(pElem)){ PendingList *pList = (PendingList *)fts3HashData(pElem); fts3PendingListDelete(pList); } fts3HashClear(pHash); } p->nPendingData = 0; } /* ** This function is called by the xUpdate() method as part of an INSERT ** operation. It adds entries for each term in the new record to the ** pendingTerms hash table. ** ** Argument apVal is the same as the similarly named argument passed to ** fts3InsertData(). Parameter iDocid is the docid of the new row. */ static int fts3InsertTerms( Fts3Table *p, int iLangid, sqlite3_value **apVal, u32 *aSz ){ int i; /* Iterator variable */ for(i=2; inColumn+2; i++){ int iCol = i-2; if( p->abNotindexed[iCol]==0 ){ const char *zText = (const char *)sqlite3_value_text(apVal[i]); int rc = fts3PendingTermsAdd(p, iLangid, zText, iCol, &aSz[iCol]); if( rc!=SQLITE_OK ){ return rc; } aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]); } } return SQLITE_OK; } /* ** This function is called by the xUpdate() method for an INSERT operation. ** The apVal parameter is passed a copy of the apVal argument passed by ** SQLite to the xUpdate() method. i.e: ** ** apVal[0] Not used for INSERT. ** apVal[1] rowid ** apVal[2] Left-most user-defined column ** ... ** apVal[p->nColumn+1] Right-most user-defined column ** apVal[p->nColumn+2] Hidden column with same name as table ** apVal[p->nColumn+3] Hidden "docid" column (alias for rowid) ** apVal[p->nColumn+4] Hidden languageid column */ static int fts3InsertData( Fts3Table *p, /* Full-text table */ sqlite3_value **apVal, /* Array of values to insert */ sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */ ){ int rc; /* Return code */ sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ if( p->zContentTbl ){ sqlite3_value *pRowid = apVal[p->nColumn+3]; if( sqlite3_value_type(pRowid)==SQLITE_NULL ){ pRowid = apVal[1]; } if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){ return SQLITE_CONSTRAINT; } *piDocid = sqlite3_value_int64(pRowid); return SQLITE_OK; } /* Locate the statement handle used to insert data into the %_content ** table. The SQL for this statement is: ** ** INSERT INTO %_content VALUES(?, ?, ?, ...) ** ** The statement features N '?' variables, where N is the number of user ** defined columns in the FTS3 table, plus one for the docid field. */ rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]); if( rc==SQLITE_OK && p->zLanguageid ){ rc = sqlite3_bind_int( pContentInsert, p->nColumn+2, sqlite3_value_int(apVal[p->nColumn+4]) ); } if( rc!=SQLITE_OK ) return rc; /* There is a quirk here. The users INSERT statement may have specified ** a value for the "rowid" field, for the "docid" field, or for both. ** Which is a problem, since "rowid" and "docid" are aliases for the ** same value. For example: ** ** INSERT INTO fts3tbl(rowid, docid) VALUES(1, 2); ** ** In FTS3, this is an error. It is an error to specify non-NULL values ** for both docid and some other rowid alias. */ if( SQLITE_NULL!=sqlite3_value_type(apVal[3+p->nColumn]) ){ if( SQLITE_NULL==sqlite3_value_type(apVal[0]) && SQLITE_NULL!=sqlite3_value_type(apVal[1]) ){ /* A rowid/docid conflict. */ return SQLITE_ERROR; } rc = sqlite3_bind_value(pContentInsert, 1, apVal[3+p->nColumn]); if( rc!=SQLITE_OK ) return rc; } /* Execute the statement to insert the record. Set *piDocid to the ** new docid value. */ sqlite3_step(pContentInsert); rc = sqlite3_reset(pContentInsert); *piDocid = sqlite3_last_insert_rowid(p->db); return rc; } /* ** Remove all data from the FTS3 table. Clear the hash table containing ** pending terms. */ static int fts3DeleteAll(Fts3Table *p, int bContent){ int rc = SQLITE_OK; /* Return code */ /* Discard the contents of the pending-terms hash table. */ sqlite3Fts3PendingTermsClear(p); /* Delete everything from the shadow tables. Except, leave %_content as ** is if bContent is false. */ assert( p->zContentTbl==0 || bContent==0 ); if( bContent ) fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0); fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0); fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0); if( p->bHasDocsize ){ fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0); } if( p->bHasStat ){ fts3SqlExec(&rc, p, SQL_DELETE_ALL_STAT, 0); } return rc; } /* ** */ static int langidFromSelect(Fts3Table *p, sqlite3_stmt *pSelect){ int iLangid = 0; if( p->zLanguageid ) iLangid = sqlite3_column_int(pSelect, p->nColumn+1); return iLangid; } /* ** The first element in the apVal[] array is assumed to contain the docid ** (an integer) of a row about to be deleted. Remove all terms from the ** full-text index. */ static void fts3DeleteTerms( int *pRC, /* Result code */ Fts3Table *p, /* The FTS table to delete from */ sqlite3_value *pRowid, /* The docid to be deleted */ u32 *aSz, /* Sizes of deleted document written here */ int *pbFound /* OUT: Set to true if row really does exist */ ){ int rc; sqlite3_stmt *pSelect; assert( *pbFound==0 ); if( *pRC ) return; rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pSelect) ){ int i; int iLangid = langidFromSelect(p, pSelect); i64 iDocid = sqlite3_column_int64(pSelect, 0); rc = fts3PendingTermsDocid(p, 1, iLangid, iDocid); for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){ int iCol = i-1; if( p->abNotindexed[iCol]==0 ){ const char *zText = (const char *)sqlite3_column_text(pSelect, i); rc = fts3PendingTermsAdd(p, iLangid, zText, -1, &aSz[iCol]); aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i); } } if( rc!=SQLITE_OK ){ sqlite3_reset(pSelect); *pRC = rc; return; } *pbFound = 1; } rc = sqlite3_reset(pSelect); }else{ sqlite3_reset(pSelect); } *pRC = rc; } /* ** Forward declaration to account for the circular dependency between ** functions fts3SegmentMerge() and fts3AllocateSegdirIdx(). */ static int fts3SegmentMerge(Fts3Table *, int, int, int); /* ** This function allocates a new level iLevel index in the segdir table. ** Usually, indexes are allocated within a level sequentially starting ** with 0, so the allocated index is one greater than the value returned ** by: ** ** SELECT max(idx) FROM %_segdir WHERE level = :iLevel ** ** However, if there are already FTS3_MERGE_COUNT indexes at the requested ** level, they are merged into a single level (iLevel+1) segment and the ** allocated index is 0. ** ** If successful, *piIdx is set to the allocated index slot and SQLITE_OK ** returned. Otherwise, an SQLite error code is returned. */ static int fts3AllocateSegdirIdx( Fts3Table *p, int iLangid, /* Language id */ int iIndex, /* Index for p->aIndex */ int iLevel, int *piIdx ){ int rc; /* Return Code */ sqlite3_stmt *pNextIdx; /* Query for next idx at level iLevel */ int iNext = 0; /* Result of query pNextIdx */ assert( iLangid>=0 ); assert( p->nIndex>=1 ); /* Set variable iNext to the next available segdir index at level iLevel. */ rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pNextIdx, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64( pNextIdx, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel) ); if( SQLITE_ROW==sqlite3_step(pNextIdx) ){ iNext = sqlite3_column_int(pNextIdx, 0); } rc = sqlite3_reset(pNextIdx); } if( rc==SQLITE_OK ){ /* If iNext is FTS3_MERGE_COUNT, indicating that level iLevel is already ** full, merge all segments in level iLevel into a single iLevel+1 ** segment and allocate (newly freed) index 0 at level iLevel. Otherwise, ** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext. */ if( iNext>=MergeCount(p) ){ fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel)); rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel); *piIdx = 0; }else{ *piIdx = iNext; } } return rc; } /* ** The %_segments table is declared as follows: ** ** CREATE TABLE %_segments(blockid INTEGER PRIMARY KEY, block BLOB) ** ** This function reads data from a single row of the %_segments table. The ** specific row is identified by the iBlockid parameter. If paBlob is not ** NULL, then a buffer is allocated using sqlite3_malloc() and populated ** with the contents of the blob stored in the "block" column of the ** identified table row is. Whether or not paBlob is NULL, *pnBlob is set ** to the size of the blob in bytes before returning. ** ** If an error occurs, or the table does not contain the specified row, ** an SQLite error code is returned. Otherwise, SQLITE_OK is returned. If ** paBlob is non-NULL, then it is the responsibility of the caller to ** eventually free the returned buffer. ** ** This function may leave an open sqlite3_blob* handle in the ** Fts3Table.pSegments variable. This handle is reused by subsequent calls ** to this function. The handle may be closed by calling the ** sqlite3Fts3SegmentsClose() function. Reusing a blob handle is a handy ** performance improvement, but the blob handle should always be closed ** before control is returned to the user (to prevent a lock being held ** on the database file for longer than necessary). Thus, any virtual table ** method (xFilter etc.) that may directly or indirectly call this function ** must call sqlite3Fts3SegmentsClose() before returning. */ SQLITE_PRIVATE int sqlite3Fts3ReadBlock( Fts3Table *p, /* FTS3 table handle */ sqlite3_int64 iBlockid, /* Access the row with blockid=$iBlockid */ char **paBlob, /* OUT: Blob data in malloc'd buffer */ int *pnBlob, /* OUT: Size of blob data */ int *pnLoad /* OUT: Bytes actually loaded */ ){ int rc; /* Return code */ /* pnBlob must be non-NULL. paBlob may be NULL or non-NULL. */ assert( pnBlob ); if( p->pSegments ){ rc = sqlite3_blob_reopen(p->pSegments, iBlockid); }else{ if( 0==p->zSegmentsTbl ){ p->zSegmentsTbl = sqlite3_mprintf("%s_segments", p->zName); if( 0==p->zSegmentsTbl ) return SQLITE_NOMEM; } rc = sqlite3_blob_open( p->db, p->zDb, p->zSegmentsTbl, "block", iBlockid, 0, &p->pSegments ); } if( rc==SQLITE_OK ){ int nByte = sqlite3_blob_bytes(p->pSegments); *pnBlob = nByte; if( paBlob ){ char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING); if( !aByte ){ rc = SQLITE_NOMEM; }else{ if( pnLoad && nByte>(FTS3_NODE_CHUNK_THRESHOLD) ){ nByte = FTS3_NODE_CHUNKSIZE; *pnLoad = nByte; } rc = sqlite3_blob_read(p->pSegments, aByte, nByte, 0); memset(&aByte[nByte], 0, FTS3_NODE_PADDING); if( rc!=SQLITE_OK ){ sqlite3_free(aByte); aByte = 0; } } *paBlob = aByte; } }else if( rc==SQLITE_ERROR ){ rc = FTS_CORRUPT_VTAB; } return rc; } /* ** Close the blob handle at p->pSegments, if it is open. See comments above ** the sqlite3Fts3ReadBlock() function for details. */ SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *p){ sqlite3_blob_close(p->pSegments); p->pSegments = 0; } static int fts3SegReaderIncrRead(Fts3SegReader *pReader){ int nRead; /* Number of bytes to read */ int rc; /* Return code */ nRead = MIN(pReader->nNode - pReader->nPopulate, FTS3_NODE_CHUNKSIZE); rc = sqlite3_blob_read( pReader->pBlob, &pReader->aNode[pReader->nPopulate], nRead, pReader->nPopulate ); if( rc==SQLITE_OK ){ pReader->nPopulate += nRead; memset(&pReader->aNode[pReader->nPopulate], 0, FTS3_NODE_PADDING); if( pReader->nPopulate==pReader->nNode ){ sqlite3_blob_close(pReader->pBlob); pReader->pBlob = 0; pReader->nPopulate = 0; } } return rc; } static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){ int rc = SQLITE_OK; assert( !pReader->pBlob || (pFrom>=pReader->aNode && pFrom<&pReader->aNode[pReader->nNode]) ); while( pReader->pBlob && rc==SQLITE_OK && (pFrom - pReader->aNode + nByte)>pReader->nPopulate ){ rc = fts3SegReaderIncrRead(pReader); } return rc; } /* ** Set an Fts3SegReader cursor to point at EOF. */ static void fts3SegReaderSetEof(Fts3SegReader *pSeg){ if( !fts3SegReaderIsRootOnly(pSeg) ){ sqlite3_free(pSeg->aNode); sqlite3_blob_close(pSeg->pBlob); pSeg->pBlob = 0; } pSeg->aNode = 0; } /* ** Move the iterator passed as the first argument to the next term in the ** segment. If successful, SQLITE_OK is returned. If there is no next term, ** SQLITE_DONE. Otherwise, an SQLite error code. */ static int fts3SegReaderNext( Fts3Table *p, Fts3SegReader *pReader, int bIncr ){ int rc; /* Return code of various sub-routines */ char *pNext; /* Cursor variable */ int nPrefix; /* Number of bytes in term prefix */ int nSuffix; /* Number of bytes in term suffix */ if( !pReader->aDoclist ){ pNext = pReader->aNode; }else{ pNext = &pReader->aDoclist[pReader->nDoclist]; } if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){ if( fts3SegReaderIsPending(pReader) ){ Fts3HashElem *pElem = *(pReader->ppNextElem); sqlite3_free(pReader->aNode); pReader->aNode = 0; if( pElem ){ char *aCopy; PendingList *pList = (PendingList *)fts3HashData(pElem); int nCopy = pList->nData+1; int nTerm = fts3HashKeysize(pElem); if( (nTerm+1)>pReader->nTermAlloc ){ sqlite3_free(pReader->zTerm); pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2); if( !pReader->zTerm ) return SQLITE_NOMEM; pReader->nTermAlloc = (nTerm+1)*2; } memcpy(pReader->zTerm, fts3HashKey(pElem), nTerm); pReader->zTerm[nTerm] = '\0'; pReader->nTerm = nTerm; aCopy = (char*)sqlite3_malloc64(nCopy); if( !aCopy ) return SQLITE_NOMEM; memcpy(aCopy, pList->aData, nCopy); pReader->nNode = pReader->nDoclist = nCopy; pReader->aNode = pReader->aDoclist = aCopy; pReader->ppNextElem++; assert( pReader->aNode ); } return SQLITE_OK; } fts3SegReaderSetEof(pReader); /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf ** blocks have already been traversed. */ #ifdef CORRUPT_DB assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock || CORRUPT_DB ); #endif if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){ return SQLITE_OK; } rc = sqlite3Fts3ReadBlock( p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode, (bIncr ? &pReader->nPopulate : 0) ); if( rc!=SQLITE_OK ) return rc; assert( pReader->pBlob==0 ); if( bIncr && pReader->nPopulatenNode ){ pReader->pBlob = p->pSegments; p->pSegments = 0; } pNext = pReader->aNode; } assert( !fts3SegReaderIsPending(pReader) ); rc = fts3SegReaderRequire(pReader, pNext, FTS3_VARINT_MAX*2); if( rc!=SQLITE_OK ) return rc; /* Because of the FTS3_NODE_PADDING bytes of padding, the following is ** safe (no risk of overread) even if the node data is corrupted. */ pNext += fts3GetVarint32(pNext, &nPrefix); pNext += fts3GetVarint32(pNext, &nSuffix); if( nSuffix<=0 || (&pReader->aNode[pReader->nNode] - pNext)pReader->nTerm ){ return FTS_CORRUPT_VTAB; } /* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are ** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer ** overflow - hence the (i64) casts. */ if( (i64)nPrefix+nSuffix>(i64)pReader->nTermAlloc ){ i64 nNew = ((i64)nPrefix+nSuffix)*2; char *zNew = sqlite3_realloc64(pReader->zTerm, nNew); if( !zNew ){ return SQLITE_NOMEM; } pReader->zTerm = zNew; pReader->nTermAlloc = nNew; } rc = fts3SegReaderRequire(pReader, pNext, nSuffix+FTS3_VARINT_MAX); if( rc!=SQLITE_OK ) return rc; memcpy(&pReader->zTerm[nPrefix], pNext, nSuffix); pReader->nTerm = nPrefix+nSuffix; pNext += nSuffix; pNext += fts3GetVarint32(pNext, &pReader->nDoclist); pReader->aDoclist = pNext; pReader->pOffsetList = 0; /* Check that the doclist does not appear to extend past the end of the ** b-tree node. And that the final byte of the doclist is 0x00. If either ** of these statements is untrue, then the data structure is corrupt. */ if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode) || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1]) || pReader->nDoclist==0 ){ return FTS_CORRUPT_VTAB; } return SQLITE_OK; } /* ** Set the SegReader to point to the first docid in the doclist associated ** with the current term. */ static int fts3SegReaderFirstDocid(Fts3Table *pTab, Fts3SegReader *pReader){ int rc = SQLITE_OK; assert( pReader->aDoclist ); assert( !pReader->pOffsetList ); if( pTab->bDescIdx && fts3SegReaderIsPending(pReader) ){ u8 bEof = 0; pReader->iDocid = 0; pReader->nOffsetList = 0; sqlite3Fts3DoclistPrev(0, pReader->aDoclist, pReader->nDoclist, &pReader->pOffsetList, &pReader->iDocid, &pReader->nOffsetList, &bEof ); }else{ rc = fts3SegReaderRequire(pReader, pReader->aDoclist, FTS3_VARINT_MAX); if( rc==SQLITE_OK ){ int n = sqlite3Fts3GetVarint(pReader->aDoclist, &pReader->iDocid); pReader->pOffsetList = &pReader->aDoclist[n]; } } return rc; } /* ** Advance the SegReader to point to the next docid in the doclist ** associated with the current term. ** ** If arguments ppOffsetList and pnOffsetList are not NULL, then ** *ppOffsetList is set to point to the first column-offset list ** in the doclist entry (i.e. immediately past the docid varint). ** *pnOffsetList is set to the length of the set of column-offset ** lists, not including the nul-terminator byte. For example: */ static int fts3SegReaderNextDocid( Fts3Table *pTab, Fts3SegReader *pReader, /* Reader to advance to next docid */ char **ppOffsetList, /* OUT: Pointer to current position-list */ int *pnOffsetList /* OUT: Length of *ppOffsetList in bytes */ ){ int rc = SQLITE_OK; char *p = pReader->pOffsetList; char c = 0; assert( p ); if( pTab->bDescIdx && fts3SegReaderIsPending(pReader) ){ /* A pending-terms seg-reader for an FTS4 table that uses order=desc. ** Pending-terms doclists are always built up in ascending order, so ** we have to iterate through them backwards here. */ u8 bEof = 0; if( ppOffsetList ){ *ppOffsetList = pReader->pOffsetList; *pnOffsetList = pReader->nOffsetList - 1; } sqlite3Fts3DoclistPrev(0, pReader->aDoclist, pReader->nDoclist, &p, &pReader->iDocid, &pReader->nOffsetList, &bEof ); if( bEof ){ pReader->pOffsetList = 0; }else{ pReader->pOffsetList = p; } }else{ char *pEnd = &pReader->aDoclist[pReader->nDoclist]; /* Pointer p currently points at the first byte of an offset list. The ** following block advances it to point one byte past the end of ** the same offset list. */ while( 1 ){ /* The following line of code (and the "p++" below the while() loop) is ** normally all that is required to move pointer p to the desired ** position. The exception is if this node is being loaded from disk ** incrementally and pointer "p" now points to the first byte past ** the populated part of pReader->aNode[]. */ while( *p | c ) c = *p++ & 0x80; assert( *p==0 ); if( pReader->pBlob==0 || p<&pReader->aNode[pReader->nPopulate] ) break; rc = fts3SegReaderIncrRead(pReader); if( rc!=SQLITE_OK ) return rc; } p++; /* If required, populate the output variables with a pointer to and the ** size of the previous offset-list. */ if( ppOffsetList ){ *ppOffsetList = pReader->pOffsetList; *pnOffsetList = (int)(p - pReader->pOffsetList - 1); } /* List may have been edited in place by fts3EvalNearTrim() */ while( p=pEnd ){ pReader->pOffsetList = 0; }else{ rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX); if( rc==SQLITE_OK ){ u64 iDelta; pReader->pOffsetList = p + sqlite3Fts3GetVarintU(p, &iDelta); if( pTab->bDescIdx ){ pReader->iDocid = (i64)((u64)pReader->iDocid - iDelta); }else{ pReader->iDocid = (i64)((u64)pReader->iDocid + iDelta); } } } } return rc; } SQLITE_PRIVATE int sqlite3Fts3MsrOvfl( Fts3Cursor *pCsr, Fts3MultiSegReader *pMsr, int *pnOvfl ){ Fts3Table *p = (Fts3Table*)pCsr->base.pVtab; int nOvfl = 0; int ii; int rc = SQLITE_OK; int pgsz = p->nPgsz; assert( p->bFts4 ); assert( pgsz>0 ); for(ii=0; rc==SQLITE_OK && iinSegment; ii++){ Fts3SegReader *pReader = pMsr->apSegment[ii]; if( !fts3SegReaderIsPending(pReader) && !fts3SegReaderIsRootOnly(pReader) ){ sqlite3_int64 jj; for(jj=pReader->iStartBlock; jj<=pReader->iLeafEndBlock; jj++){ int nBlob; rc = sqlite3Fts3ReadBlock(p, jj, 0, &nBlob, 0); if( rc!=SQLITE_OK ) break; if( (nBlob+35)>pgsz ){ nOvfl += (nBlob + 34)/pgsz; } } } } *pnOvfl = nOvfl; return rc; } /* ** Free all allocations associated with the iterator passed as the ** second argument. */ SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ if( pReader ){ sqlite3_free(pReader->zTerm); if( !fts3SegReaderIsRootOnly(pReader) ){ sqlite3_free(pReader->aNode); } sqlite3_blob_close(pReader->pBlob); } sqlite3_free(pReader); } /* ** Allocate a new SegReader object. */ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew( int iAge, /* Segment "age". */ int bLookup, /* True for a lookup only */ sqlite3_int64 iStartLeaf, /* First leaf to traverse */ sqlite3_int64 iEndLeaf, /* Final leaf to traverse */ sqlite3_int64 iEndBlock, /* Final block of segment */ const char *zRoot, /* Buffer containing root node */ int nRoot, /* Size of buffer containing root node */ Fts3SegReader **ppReader /* OUT: Allocated Fts3SegReader */ ){ Fts3SegReader *pReader; /* Newly allocated SegReader object */ int nExtra = 0; /* Bytes to allocate segment root node */ assert( zRoot!=0 || nRoot==0 ); #ifdef CORRUPT_DB assert( zRoot!=0 || CORRUPT_DB ); #endif if( iStartLeaf==0 ){ if( iEndLeaf!=0 ) return FTS_CORRUPT_VTAB; nExtra = nRoot + FTS3_NODE_PADDING; } pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra); if( !pReader ){ return SQLITE_NOMEM; } memset(pReader, 0, sizeof(Fts3SegReader)); pReader->iIdx = iAge; pReader->bLookup = bLookup!=0; pReader->iStartBlock = iStartLeaf; pReader->iLeafEndBlock = iEndLeaf; pReader->iEndBlock = iEndBlock; if( nExtra ){ /* The entire segment is stored in the root node. */ pReader->aNode = (char *)&pReader[1]; pReader->rootOnly = 1; pReader->nNode = nRoot; if( nRoot ) memcpy(pReader->aNode, zRoot, nRoot); memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING); }else{ pReader->iCurrentBlock = iStartLeaf-1; } *ppReader = pReader; return SQLITE_OK; } /* ** This is a comparison function used as a qsort() callback when sorting ** an array of pending terms by term. This occurs as part of flushing ** the contents of the pending-terms hash table to the database. */ static int SQLITE_CDECL fts3CompareElemByTerm( const void *lhs, const void *rhs ){ char *z1 = fts3HashKey(*(Fts3HashElem **)lhs); char *z2 = fts3HashKey(*(Fts3HashElem **)rhs); int n1 = fts3HashKeysize(*(Fts3HashElem **)lhs); int n2 = fts3HashKeysize(*(Fts3HashElem **)rhs); int n = (n1aIndex */ const char *zTerm, /* Term to search for */ int nTerm, /* Size of buffer zTerm */ int bPrefix, /* True for a prefix iterator */ Fts3SegReader **ppReader /* OUT: SegReader for pending-terms */ ){ Fts3SegReader *pReader = 0; /* Fts3SegReader object to return */ Fts3HashElem *pE; /* Iterator variable */ Fts3HashElem **aElem = 0; /* Array of term hash entries to scan */ int nElem = 0; /* Size of array at aElem */ int rc = SQLITE_OK; /* Return Code */ Fts3Hash *pHash; pHash = &p->aIndex[iIndex].hPending; if( bPrefix ){ int nAlloc = 0; /* Size of allocated array at aElem */ for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){ char *zKey = (char *)fts3HashKey(pE); int nKey = fts3HashKeysize(pE); if( nTerm==0 || (nKey>=nTerm && 0==memcmp(zKey, zTerm, nTerm)) ){ if( nElem==nAlloc ){ Fts3HashElem **aElem2; nAlloc += 16; aElem2 = (Fts3HashElem **)sqlite3_realloc64( aElem, nAlloc*sizeof(Fts3HashElem *) ); if( !aElem2 ){ rc = SQLITE_NOMEM; nElem = 0; break; } aElem = aElem2; } aElem[nElem++] = pE; } } /* If more than one term matches the prefix, sort the Fts3HashElem ** objects in term order using qsort(). This uses the same comparison ** callback as is used when flushing terms to disk. */ if( nElem>1 ){ qsort(aElem, nElem, sizeof(Fts3HashElem *), fts3CompareElemByTerm); } }else{ /* The query is a simple term lookup that matches at most one term in ** the index. All that is required is a straight hash-lookup. ** ** Because the stack address of pE may be accessed via the aElem pointer ** below, the "Fts3HashElem *pE" must be declared so that it is valid ** within this entire function, not just this "else{...}" block. */ pE = fts3HashFindElem(pHash, zTerm, nTerm); if( pE ){ aElem = &pE; nElem = 1; } } if( nElem>0 ){ sqlite3_int64 nByte; nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *); pReader = (Fts3SegReader *)sqlite3_malloc64(nByte); if( !pReader ){ rc = SQLITE_NOMEM; }else{ memset(pReader, 0, nByte); pReader->iIdx = 0x7FFFFFFF; pReader->ppNextElem = (Fts3HashElem **)&pReader[1]; memcpy(pReader->ppNextElem, aElem, nElem*sizeof(Fts3HashElem *)); } } if( bPrefix ){ sqlite3_free(aElem); } *ppReader = pReader; return rc; } /* ** Compare the entries pointed to by two Fts3SegReader structures. ** Comparison is as follows: ** ** 1) EOF is greater than not EOF. ** ** 2) The current terms (if any) are compared using memcmp(). If one ** term is a prefix of another, the longer term is considered the ** larger. ** ** 3) By segment age. An older segment is considered larger. */ static int fts3SegReaderCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ int rc; if( pLhs->aNode && pRhs->aNode ){ int rc2 = pLhs->nTerm - pRhs->nTerm; if( rc2<0 ){ rc = memcmp(pLhs->zTerm, pRhs->zTerm, pLhs->nTerm); }else{ rc = memcmp(pLhs->zTerm, pRhs->zTerm, pRhs->nTerm); } if( rc==0 ){ rc = rc2; } }else{ rc = (pLhs->aNode==0) - (pRhs->aNode==0); } if( rc==0 ){ rc = pRhs->iIdx - pLhs->iIdx; } assert_fts3_nc( rc!=0 ); return rc; } /* ** A different comparison function for SegReader structures. In this ** version, it is assumed that each SegReader points to an entry in ** a doclist for identical terms. Comparison is made as follows: ** ** 1) EOF (end of doclist in this case) is greater than not EOF. ** ** 2) By current docid. ** ** 3) By segment age. An older segment is considered larger. */ static int fts3SegReaderDoclistCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ int rc = (pLhs->pOffsetList==0)-(pRhs->pOffsetList==0); if( rc==0 ){ if( pLhs->iDocid==pRhs->iDocid ){ rc = pRhs->iIdx - pLhs->iIdx; }else{ rc = (pLhs->iDocid > pRhs->iDocid) ? 1 : -1; } } assert( pLhs->aNode && pRhs->aNode ); return rc; } static int fts3SegReaderDoclistCmpRev(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ int rc = (pLhs->pOffsetList==0)-(pRhs->pOffsetList==0); if( rc==0 ){ if( pLhs->iDocid==pRhs->iDocid ){ rc = pRhs->iIdx - pLhs->iIdx; }else{ rc = (pLhs->iDocid < pRhs->iDocid) ? 1 : -1; } } assert( pLhs->aNode && pRhs->aNode ); return rc; } /* ** Compare the term that the Fts3SegReader object passed as the first argument ** points to with the term specified by arguments zTerm and nTerm. ** ** If the pSeg iterator is already at EOF, return 0. Otherwise, return ** -ve if the pSeg term is less than zTerm/nTerm, 0 if the two terms are ** equal, or +ve if the pSeg term is greater than zTerm/nTerm. */ static int fts3SegReaderTermCmp( Fts3SegReader *pSeg, /* Segment reader object */ const char *zTerm, /* Term to compare to */ int nTerm /* Size of term zTerm in bytes */ ){ int res = 0; if( pSeg->aNode ){ if( pSeg->nTerm>nTerm ){ res = memcmp(pSeg->zTerm, zTerm, nTerm); }else{ res = memcmp(pSeg->zTerm, zTerm, pSeg->nTerm); } if( res==0 ){ res = pSeg->nTerm-nTerm; } } return res; } /* ** Argument apSegment is an array of nSegment elements. It is known that ** the final (nSegment-nSuspect) members are already in sorted order ** (according to the comparison function provided). This function shuffles ** the array around until all entries are in sorted order. */ static void fts3SegReaderSort( Fts3SegReader **apSegment, /* Array to sort entries of */ int nSegment, /* Size of apSegment array */ int nSuspect, /* Unsorted entry count */ int (*xCmp)(Fts3SegReader *, Fts3SegReader *) /* Comparison function */ ){ int i; /* Iterator variable */ assert( nSuspect<=nSegment ); if( nSuspect==nSegment ) nSuspect--; for(i=nSuspect-1; i>=0; i--){ int j; for(j=i; j<(nSegment-1); j++){ Fts3SegReader *pTmp; if( xCmp(apSegment[j], apSegment[j+1])<0 ) break; pTmp = apSegment[j+1]; apSegment[j+1] = apSegment[j]; apSegment[j] = pTmp; } } #ifndef NDEBUG /* Check that the list really is sorted now. */ for(i=0; i<(nSuspect-1); i++){ assert( xCmp(apSegment[i], apSegment[i+1])<0 ); } #endif } /* ** Insert a record into the %_segments table. */ static int fts3WriteSegment( Fts3Table *p, /* Virtual table handle */ sqlite3_int64 iBlock, /* Block id for new block */ char *z, /* Pointer to buffer containing block data */ int n /* Size of buffer z in bytes */ ){ sqlite3_stmt *pStmt; int rc = fts3SqlStmt(p, SQL_INSERT_SEGMENTS, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pStmt, 1, iBlock); sqlite3_bind_blob(pStmt, 2, z, n, SQLITE_STATIC); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); sqlite3_bind_null(pStmt, 2); } return rc; } /* ** Find the largest relative level number in the table. If successful, set ** *pnMax to this value and return SQLITE_OK. Otherwise, if an error occurs, ** set *pnMax to zero and return an SQLite error code. */ SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *p, int *pnMax){ int rc; int mxLevel = 0; sqlite3_stmt *pStmt = 0; rc = fts3SqlStmt(p, SQL_SELECT_MXLEVEL, &pStmt, 0); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ mxLevel = sqlite3_column_int(pStmt, 0); } rc = sqlite3_reset(pStmt); } *pnMax = mxLevel; return rc; } /* ** Insert a record into the %_segdir table. */ static int fts3WriteSegdir( Fts3Table *p, /* Virtual table handle */ sqlite3_int64 iLevel, /* Value for "level" field (absolute level) */ int iIdx, /* Value for "idx" field */ sqlite3_int64 iStartBlock, /* Value for "start_block" field */ sqlite3_int64 iLeafEndBlock, /* Value for "leaves_end_block" field */ sqlite3_int64 iEndBlock, /* Value for "end_block" field */ sqlite3_int64 nLeafData, /* Bytes of leaf data in segment */ char *zRoot, /* Blob value for "root" field */ int nRoot /* Number of bytes in buffer zRoot */ ){ sqlite3_stmt *pStmt; int rc = fts3SqlStmt(p, SQL_INSERT_SEGDIR, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pStmt, 1, iLevel); sqlite3_bind_int(pStmt, 2, iIdx); sqlite3_bind_int64(pStmt, 3, iStartBlock); sqlite3_bind_int64(pStmt, 4, iLeafEndBlock); if( nLeafData==0 ){ sqlite3_bind_int64(pStmt, 5, iEndBlock); }else{ char *zEnd = sqlite3_mprintf("%lld %lld", iEndBlock, nLeafData); if( !zEnd ) return SQLITE_NOMEM; sqlite3_bind_text(pStmt, 5, zEnd, -1, sqlite3_free); } sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); sqlite3_bind_null(pStmt, 6); } return rc; } /* ** Return the size of the common prefix (if any) shared by zPrev and ** zNext, in bytes. For example, ** ** fts3PrefixCompress("abc", 3, "abcdef", 6) // returns 3 ** fts3PrefixCompress("abX", 3, "abcdef", 6) // returns 2 ** fts3PrefixCompress("abX", 3, "Xbcdef", 6) // returns 0 */ static int fts3PrefixCompress( const char *zPrev, /* Buffer containing previous term */ int nPrev, /* Size of buffer zPrev in bytes */ const char *zNext, /* Buffer containing next term */ int nNext /* Size of buffer zNext in bytes */ ){ int n; for(n=0; nnData; /* Current size of node in bytes */ int nReq = nData; /* Required space after adding zTerm */ int nPrefix; /* Number of bytes of prefix compression */ int nSuffix; /* Suffix length */ nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm); nSuffix = nTerm-nPrefix; /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of ** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when ** compared with BINARY collation. This indicates corruption. */ if( nSuffix<=0 ) return FTS_CORRUPT_VTAB; nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix; if( nReq<=p->nNodeSize || !pTree->zTerm ){ if( nReq>p->nNodeSize ){ /* An unusual case: this is the first term to be added to the node ** and the static node buffer (p->nNodeSize bytes) is not large ** enough. Use a separately malloced buffer instead This wastes ** p->nNodeSize bytes, but since this scenario only comes about when ** the database contain two terms that share a prefix of almost 2KB, ** this is not expected to be a serious problem. */ assert( pTree->aData==(char *)&pTree[1] ); pTree->aData = (char *)sqlite3_malloc64(nReq); if( !pTree->aData ){ return SQLITE_NOMEM; } } if( pTree->zTerm ){ /* There is no prefix-length field for first term in a node */ nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nPrefix); } nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nSuffix); memcpy(&pTree->aData[nData], &zTerm[nPrefix], nSuffix); pTree->nData = nData + nSuffix; pTree->nEntry++; if( isCopyTerm ){ if( pTree->nMalloczMalloc, (i64)nTerm*2); if( !zNew ){ return SQLITE_NOMEM; } pTree->nMalloc = nTerm*2; pTree->zMalloc = zNew; } pTree->zTerm = pTree->zMalloc; memcpy(pTree->zTerm, zTerm, nTerm); pTree->nTerm = nTerm; }else{ pTree->zTerm = (char *)zTerm; pTree->nTerm = nTerm; } return SQLITE_OK; } } /* If control flows to here, it was not possible to append zTerm to the ** current node. Create a new node (a right-sibling of the current node). ** If this is the first node in the tree, the term is added to it. ** ** Otherwise, the term is not added to the new node, it is left empty for ** now. Instead, the term is inserted into the parent of pTree. If pTree ** has no parent, one is created here. */ pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize); if( !pNew ){ return SQLITE_NOMEM; } memset(pNew, 0, sizeof(SegmentNode)); pNew->nData = 1 + FTS3_VARINT_MAX; pNew->aData = (char *)&pNew[1]; if( pTree ){ SegmentNode *pParent = pTree->pParent; rc = fts3NodeAddTerm(p, &pParent, isCopyTerm, zTerm, nTerm); if( pTree->pParent==0 ){ pTree->pParent = pParent; } pTree->pRight = pNew; pNew->pLeftmost = pTree->pLeftmost; pNew->pParent = pParent; pNew->zMalloc = pTree->zMalloc; pNew->nMalloc = pTree->nMalloc; pTree->zMalloc = 0; }else{ pNew->pLeftmost = pNew; rc = fts3NodeAddTerm(p, &pNew, isCopyTerm, zTerm, nTerm); } *ppTree = pNew; return rc; } /* ** Helper function for fts3NodeWrite(). */ static int fts3TreeFinishNode( SegmentNode *pTree, int iHeight, sqlite3_int64 iLeftChild ){ int nStart; assert( iHeight>=1 && iHeight<128 ); nStart = FTS3_VARINT_MAX - sqlite3Fts3VarintLen(iLeftChild); pTree->aData[nStart] = (char)iHeight; sqlite3Fts3PutVarint(&pTree->aData[nStart+1], iLeftChild); return nStart; } /* ** Write the buffer for the segment node pTree and all of its peers to the ** database. Then call this function recursively to write the parent of ** pTree and its peers to the database. ** ** Except, if pTree is a root node, do not write it to the database. Instead, ** set output variables *paRoot and *pnRoot to contain the root node. ** ** If successful, SQLITE_OK is returned and output variable *piLast is ** set to the largest blockid written to the database (or zero if no ** blocks were written to the db). Otherwise, an SQLite error code is ** returned. */ static int fts3NodeWrite( Fts3Table *p, /* Virtual table handle */ SegmentNode *pTree, /* SegmentNode handle */ int iHeight, /* Height of this node in tree */ sqlite3_int64 iLeaf, /* Block id of first leaf node */ sqlite3_int64 iFree, /* Block id of next free slot in %_segments */ sqlite3_int64 *piLast, /* OUT: Block id of last entry written */ char **paRoot, /* OUT: Data for root node */ int *pnRoot /* OUT: Size of root node in bytes */ ){ int rc = SQLITE_OK; if( !pTree->pParent ){ /* Root node of the tree. */ int nStart = fts3TreeFinishNode(pTree, iHeight, iLeaf); *piLast = iFree-1; *pnRoot = pTree->nData - nStart; *paRoot = &pTree->aData[nStart]; }else{ SegmentNode *pIter; sqlite3_int64 iNextFree = iFree; sqlite3_int64 iNextLeaf = iLeaf; for(pIter=pTree->pLeftmost; pIter && rc==SQLITE_OK; pIter=pIter->pRight){ int nStart = fts3TreeFinishNode(pIter, iHeight, iNextLeaf); int nWrite = pIter->nData - nStart; rc = fts3WriteSegment(p, iNextFree, &pIter->aData[nStart], nWrite); iNextFree++; iNextLeaf += (pIter->nEntry+1); } if( rc==SQLITE_OK ){ assert( iNextLeaf==iFree ); rc = fts3NodeWrite( p, pTree->pParent, iHeight+1, iFree, iNextFree, piLast, paRoot, pnRoot ); } } return rc; } /* ** Free all memory allocations associated with the tree pTree. */ static void fts3NodeFree(SegmentNode *pTree){ if( pTree ){ SegmentNode *p = pTree->pLeftmost; fts3NodeFree(p->pParent); while( p ){ SegmentNode *pRight = p->pRight; if( p->aData!=(char *)&p[1] ){ sqlite3_free(p->aData); } assert( pRight==0 || p->zMalloc==0 ); sqlite3_free(p->zMalloc); sqlite3_free(p); p = pRight; } } } /* ** Add a term to the segment being constructed by the SegmentWriter object ** *ppWriter. When adding the first term to a segment, *ppWriter should ** be passed NULL. This function will allocate a new SegmentWriter object ** and return it via the input/output variable *ppWriter in this case. ** ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. */ static int fts3SegWriterAdd( Fts3Table *p, /* Virtual table handle */ SegmentWriter **ppWriter, /* IN/OUT: SegmentWriter handle */ int isCopyTerm, /* True if buffer zTerm must be copied */ const char *zTerm, /* Pointer to buffer containing term */ int nTerm, /* Size of term in bytes */ const char *aDoclist, /* Pointer to buffer containing doclist */ int nDoclist /* Size of doclist in bytes */ ){ int nPrefix; /* Size of term prefix in bytes */ int nSuffix; /* Size of term suffix in bytes */ i64 nReq; /* Number of bytes required on leaf page */ int nData; SegmentWriter *pWriter = *ppWriter; if( !pWriter ){ int rc; sqlite3_stmt *pStmt; /* Allocate the SegmentWriter structure */ pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter)); if( !pWriter ) return SQLITE_NOMEM; memset(pWriter, 0, sizeof(SegmentWriter)); *ppWriter = pWriter; /* Allocate a buffer in which to accumulate data */ pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize); if( !pWriter->aData ) return SQLITE_NOMEM; pWriter->nSize = p->nNodeSize; /* Find the next free blockid in the %_segments table */ rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; if( SQLITE_ROW==sqlite3_step(pStmt) ){ pWriter->iFree = sqlite3_column_int64(pStmt, 0); pWriter->iFirst = pWriter->iFree; } rc = sqlite3_reset(pStmt); if( rc!=SQLITE_OK ) return rc; } nData = pWriter->nData; nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm); nSuffix = nTerm-nPrefix; /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of ** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when ** compared with BINARY collation. This indicates corruption. */ if( nSuffix<=0 ) return FTS_CORRUPT_VTAB; /* Figure out how many bytes are required by this new entry */ nReq = sqlite3Fts3VarintLen(nPrefix) + /* varint containing prefix size */ sqlite3Fts3VarintLen(nSuffix) + /* varint containing suffix size */ nSuffix + /* Term suffix */ sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ nDoclist; /* Doclist data */ if( nData>0 && nData+nReq>p->nNodeSize ){ int rc; /* The current leaf node is full. Write it out to the database. */ if( pWriter->iFree==LARGEST_INT64 ) return FTS_CORRUPT_VTAB; rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData); if( rc!=SQLITE_OK ) return rc; p->nLeafAdd++; /* Add the current term to the interior node tree. The term added to ** the interior tree must: ** ** a) be greater than the largest term on the leaf node just written ** to the database (still available in pWriter->zTerm), and ** ** b) be less than or equal to the term about to be added to the new ** leaf node (zTerm/nTerm). ** ** In other words, it must be the prefix of zTerm 1 byte longer than ** the common prefix (if any) of zTerm and pWriter->zTerm. */ assert( nPrefixpTree, isCopyTerm, zTerm, nPrefix+1); if( rc!=SQLITE_OK ) return rc; nData = 0; pWriter->nTerm = 0; nPrefix = 0; nSuffix = nTerm; nReq = 1 + /* varint containing prefix size */ sqlite3Fts3VarintLen(nTerm) + /* varint containing suffix size */ nTerm + /* Term suffix */ sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ nDoclist; /* Doclist data */ } /* Increase the total number of bytes written to account for the new entry. */ pWriter->nLeafData += nReq; /* If the buffer currently allocated is too small for this entry, realloc ** the buffer to make it large enough. */ if( nReq>pWriter->nSize ){ char *aNew = sqlite3_realloc64(pWriter->aData, nReq); if( !aNew ) return SQLITE_NOMEM; pWriter->aData = aNew; pWriter->nSize = nReq; } assert( nData+nReq<=pWriter->nSize ); /* Append the prefix-compressed term and doclist to the buffer. */ nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nPrefix); nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nSuffix); assert( nSuffix>0 ); memcpy(&pWriter->aData[nData], &zTerm[nPrefix], nSuffix); nData += nSuffix; nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nDoclist); assert( nDoclist>0 ); memcpy(&pWriter->aData[nData], aDoclist, nDoclist); pWriter->nData = nData + nDoclist; /* Save the current term so that it can be used to prefix-compress the next. ** If the isCopyTerm parameter is true, then the buffer pointed to by ** zTerm is transient, so take a copy of the term data. Otherwise, just ** store a copy of the pointer. */ if( isCopyTerm ){ if( nTerm>pWriter->nMalloc ){ char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2); if( !zNew ){ return SQLITE_NOMEM; } pWriter->nMalloc = nTerm*2; pWriter->zMalloc = zNew; pWriter->zTerm = zNew; } assert( pWriter->zTerm==pWriter->zMalloc ); assert( nTerm>0 ); memcpy(pWriter->zTerm, zTerm, nTerm); }else{ pWriter->zTerm = (char *)zTerm; } pWriter->nTerm = nTerm; return SQLITE_OK; } /* ** Flush all data associated with the SegmentWriter object pWriter to the ** database. This function must be called after all terms have been added ** to the segment using fts3SegWriterAdd(). If successful, SQLITE_OK is ** returned. Otherwise, an SQLite error code. */ static int fts3SegWriterFlush( Fts3Table *p, /* Virtual table handle */ SegmentWriter *pWriter, /* SegmentWriter to flush to the db */ sqlite3_int64 iLevel, /* Value for 'level' column of %_segdir */ int iIdx /* Value for 'idx' column of %_segdir */ ){ int rc; /* Return code */ if( pWriter->pTree ){ sqlite3_int64 iLast = 0; /* Largest block id written to database */ sqlite3_int64 iLastLeaf; /* Largest leaf block id written to db */ char *zRoot = NULL; /* Pointer to buffer containing root node */ int nRoot = 0; /* Size of buffer zRoot */ iLastLeaf = pWriter->iFree; rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, pWriter->nData); if( rc==SQLITE_OK ){ rc = fts3NodeWrite(p, pWriter->pTree, 1, pWriter->iFirst, pWriter->iFree, &iLast, &zRoot, &nRoot); } if( rc==SQLITE_OK ){ rc = fts3WriteSegdir(p, iLevel, iIdx, pWriter->iFirst, iLastLeaf, iLast, pWriter->nLeafData, zRoot, nRoot); } }else{ /* The entire tree fits on the root node. Write it to the segdir table. */ rc = fts3WriteSegdir(p, iLevel, iIdx, 0, 0, 0, pWriter->nLeafData, pWriter->aData, pWriter->nData); } p->nLeafAdd++; return rc; } /* ** Release all memory held by the SegmentWriter object passed as the ** first argument. */ static void fts3SegWriterFree(SegmentWriter *pWriter){ if( pWriter ){ sqlite3_free(pWriter->aData); sqlite3_free(pWriter->zMalloc); fts3NodeFree(pWriter->pTree); sqlite3_free(pWriter); } } /* ** The first value in the apVal[] array is assumed to contain an integer. ** This function tests if there exist any documents with docid values that ** are different from that integer. i.e. if deleting the document with docid ** pRowid would mean the FTS3 table were empty. ** ** If successful, *pisEmpty is set to true if the table is empty except for ** document pRowid, or false otherwise, and SQLITE_OK is returned. If an ** error occurs, an SQLite error code is returned. */ static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ sqlite3_stmt *pStmt; int rc; if( p->zContentTbl ){ /* If using the content=xxx option, assume the table is never empty */ *pisEmpty = 0; rc = SQLITE_OK; }else{ rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ *pisEmpty = sqlite3_column_int(pStmt, 0); } rc = sqlite3_reset(pStmt); } } return rc; } /* ** Set *pnMax to the largest segment level in the database for the index ** iIndex. ** ** Segment levels are stored in the 'level' column of the %_segdir table. ** ** Return SQLITE_OK if successful, or an SQLite error code if not. */ static int fts3SegmentMaxLevel( Fts3Table *p, int iLangid, int iIndex, sqlite3_int64 *pnMax ){ sqlite3_stmt *pStmt; int rc; assert( iIndex>=0 && iIndexnIndex ); /* Set pStmt to the compiled version of: ** ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? ** ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). */ rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); sqlite3_bind_int64(pStmt, 2, getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) ); if( SQLITE_ROW==sqlite3_step(pStmt) ){ *pnMax = sqlite3_column_int64(pStmt, 0); } return sqlite3_reset(pStmt); } /* ** iAbsLevel is an absolute level that may be assumed to exist within ** the database. This function checks if it is the largest level number ** within its index. Assuming no error occurs, *pbMax is set to 1 if ** iAbsLevel is indeed the largest level, or 0 otherwise, and SQLITE_OK ** is returned. If an error occurs, an error code is returned and the ** final value of *pbMax is undefined. */ static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){ /* Set pStmt to the compiled version of: ** ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? ** ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). */ sqlite3_stmt *pStmt; int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; sqlite3_bind_int64(pStmt, 1, iAbsLevel+1); sqlite3_bind_int64(pStmt, 2, (((u64)iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL ); *pbMax = 0; if( SQLITE_ROW==sqlite3_step(pStmt) ){ *pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL; } return sqlite3_reset(pStmt); } /* ** Delete all entries in the %_segments table associated with the segment ** opened with seg-reader pSeg. This function does not affect the contents ** of the %_segdir table. */ static int fts3DeleteSegment( Fts3Table *p, /* FTS table handle */ Fts3SegReader *pSeg /* Segment to delete */ ){ int rc = SQLITE_OK; /* Return code */ if( pSeg->iStartBlock ){ sqlite3_stmt *pDelete; /* SQL statement to delete rows */ rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDelete, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pDelete, 1, pSeg->iStartBlock); sqlite3_bind_int64(pDelete, 2, pSeg->iEndBlock); sqlite3_step(pDelete); rc = sqlite3_reset(pDelete); } } return rc; } /* ** This function is used after merging multiple segments into a single large ** segment to delete the old, now redundant, segment b-trees. Specifically, ** it: ** ** 1) Deletes all %_segments entries for the segments associated with ** each of the SegReader objects in the array passed as the third ** argument, and ** ** 2) deletes all %_segdir entries with level iLevel, or all %_segdir ** entries regardless of level if (iLevel<0). ** ** SQLITE_OK is returned if successful, otherwise an SQLite error code. */ static int fts3DeleteSegdir( Fts3Table *p, /* Virtual table handle */ int iLangid, /* Language id */ int iIndex, /* Index for p->aIndex */ int iLevel, /* Level of %_segdir entries to delete */ Fts3SegReader **apSegment, /* Array of SegReader objects */ int nReader /* Size of array apSegment */ ){ int rc = SQLITE_OK; /* Return Code */ int i; /* Iterator variable */ sqlite3_stmt *pDelete = 0; /* SQL statement to delete rows */ for(i=0; rc==SQLITE_OK && i=0 || iLevel==FTS3_SEGCURSOR_ALL ); if( iLevel==FTS3_SEGCURSOR_ALL ){ rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_RANGE, &pDelete, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); sqlite3_bind_int64(pDelete, 2, getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) ); } }else{ rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pDelete, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64( pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel) ); } } if( rc==SQLITE_OK ){ sqlite3_step(pDelete); rc = sqlite3_reset(pDelete); } return rc; } /* ** When this function is called, buffer *ppList (size *pnList bytes) contains ** a position list that may (or may not) feature multiple columns. This ** function adjusts the pointer *ppList and the length *pnList so that they ** identify the subset of the position list that corresponds to column iCol. ** ** If there are no entries in the input position list for column iCol, then ** *pnList is set to zero before returning. ** ** If parameter bZero is non-zero, then any part of the input list following ** the end of the output list is zeroed before returning. */ static void fts3ColumnFilter( int iCol, /* Column to filter on */ int bZero, /* Zero out anything following *ppList */ char **ppList, /* IN/OUT: Pointer to position list */ int *pnList /* IN/OUT: Size of buffer *ppList in bytes */ ){ char *pList = *ppList; int nList = *pnList; char *pEnd = &pList[nList]; int iCurrent = 0; char *p = pList; assert( iCol>=0 ); while( 1 ){ char c = 0; while( p0){ memset(&pList[nList], 0, pEnd - &pList[nList]); } *ppList = pList; *pnList = nList; } /* ** Cache data in the Fts3MultiSegReader.aBuffer[] buffer (overwriting any ** existing data). Grow the buffer if required. ** ** If successful, return SQLITE_OK. Otherwise, if an OOM error is encountered ** trying to resize the buffer, return SQLITE_NOMEM. */ static int fts3MsrBufferData( Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ char *pList, i64 nList ){ if( (nList+FTS3_NODE_PADDING)>pMsr->nBuffer ){ char *pNew; int nNew = nList*2 + FTS3_NODE_PADDING; pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, nNew); if( !pNew ) return SQLITE_NOMEM; pMsr->aBuffer = pNew; pMsr->nBuffer = nNew; } assert( nList>0 ); memcpy(pMsr->aBuffer, pList, nList); memset(&pMsr->aBuffer[nList], 0, FTS3_NODE_PADDING); return SQLITE_OK; } SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( Fts3Table *p, /* Virtual table handle */ Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ sqlite3_int64 *piDocid, /* OUT: Docid value */ char **paPoslist, /* OUT: Pointer to position list */ int *pnPoslist /* OUT: Size of position list in bytes */ ){ int nMerge = pMsr->nAdvance; Fts3SegReader **apSegment = pMsr->apSegment; int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp ); if( nMerge==0 ){ *paPoslist = 0; return SQLITE_OK; } while( 1 ){ Fts3SegReader *pSeg; pSeg = pMsr->apSegment[0]; if( pSeg->pOffsetList==0 ){ *paPoslist = 0; break; }else{ int rc; char *pList; int nList; int j; sqlite3_int64 iDocid = apSegment[0]->iDocid; rc = fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList); j = 1; while( rc==SQLITE_OK && jpOffsetList && apSegment[j]->iDocid==iDocid ){ rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0); j++; } if( rc!=SQLITE_OK ) return rc; fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1); if( rc!=SQLITE_OK ) return rc; assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); pList = pMsr->aBuffer; } if( pMsr->iColFilter>=0 ){ fts3ColumnFilter(pMsr->iColFilter, 1, &pList, &nList); } if( nList>0 ){ *paPoslist = pList; *piDocid = iDocid; *pnPoslist = nList; break; } } } return SQLITE_OK; } static int fts3SegReaderStart( Fts3Table *p, /* Virtual table handle */ Fts3MultiSegReader *pCsr, /* Cursor object */ const char *zTerm, /* Term searched for (or NULL) */ int nTerm /* Length of zTerm in bytes */ ){ int i; int nSeg = pCsr->nSegment; /* If the Fts3SegFilter defines a specific term (or term prefix) to search ** for, then advance each segment iterator until it points to a term of ** equal or greater value than the specified term. This prevents many ** unnecessary merge/sort operations for the case where single segment ** b-tree leaf nodes contain more than one term. */ for(i=0; pCsr->bRestart==0 && inSegment; i++){ int res = 0; Fts3SegReader *pSeg = pCsr->apSegment[i]; do { int rc = fts3SegReaderNext(p, pSeg, 0); if( rc!=SQLITE_OK ) return rc; }while( zTerm && (res = fts3SegReaderTermCmp(pSeg, zTerm, nTerm))<0 ); if( pSeg->bLookup && res!=0 ){ fts3SegReaderSetEof(pSeg); } } fts3SegReaderSort(pCsr->apSegment, nSeg, nSeg, fts3SegReaderCmp); return SQLITE_OK; } SQLITE_PRIVATE int sqlite3Fts3SegReaderStart( Fts3Table *p, /* Virtual table handle */ Fts3MultiSegReader *pCsr, /* Cursor object */ Fts3SegFilter *pFilter /* Restrictions on range of iteration */ ){ pCsr->pFilter = pFilter; return fts3SegReaderStart(p, pCsr, pFilter->zTerm, pFilter->nTerm); } SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart( Fts3Table *p, /* Virtual table handle */ Fts3MultiSegReader *pCsr, /* Cursor object */ int iCol, /* Column to match on. */ const char *zTerm, /* Term to iterate through a doclist for */ int nTerm /* Number of bytes in zTerm */ ){ int i; int rc; int nSegment = pCsr->nSegment; int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp ); assert( pCsr->pFilter==0 ); assert( zTerm && nTerm>0 ); /* Advance each segment iterator until it points to the term zTerm/nTerm. */ rc = fts3SegReaderStart(p, pCsr, zTerm, nTerm); if( rc!=SQLITE_OK ) return rc; /* Determine how many of the segments actually point to zTerm/nTerm. */ for(i=0; iapSegment[i]; if( !pSeg->aNode || fts3SegReaderTermCmp(pSeg, zTerm, nTerm) ){ break; } } pCsr->nAdvance = i; /* Advance each of the segments to point to the first docid. */ for(i=0; inAdvance; i++){ rc = fts3SegReaderFirstDocid(p, pCsr->apSegment[i]); if( rc!=SQLITE_OK ) return rc; } fts3SegReaderSort(pCsr->apSegment, i, i, xCmp); assert( iCol<0 || iColnColumn ); pCsr->iColFilter = iCol; return SQLITE_OK; } /* ** This function is called on a MultiSegReader that has been started using ** sqlite3Fts3MsrIncrStart(). One or more calls to MsrIncrNext() may also ** have been made. Calling this function puts the MultiSegReader in such ** a state that if the next two calls are: ** ** sqlite3Fts3SegReaderStart() ** sqlite3Fts3SegReaderStep() ** ** then the entire doclist for the term is available in ** MultiSegReader.aDoclist/nDoclist. */ SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){ int i; /* Used to iterate through segment-readers */ assert( pCsr->zTerm==0 ); assert( pCsr->nTerm==0 ); assert( pCsr->aDoclist==0 ); assert( pCsr->nDoclist==0 ); pCsr->nAdvance = 0; pCsr->bRestart = 1; for(i=0; inSegment; i++){ pCsr->apSegment[i]->pOffsetList = 0; pCsr->apSegment[i]->nOffsetList = 0; pCsr->apSegment[i]->iDocid = 0; } return SQLITE_OK; } static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){ if( nReq>pCsr->nBuffer ){ char *aNew; pCsr->nBuffer = nReq*2; aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer); if( !aNew ){ return SQLITE_NOMEM; } pCsr->aBuffer = aNew; } return SQLITE_OK; } SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( Fts3Table *p, /* Virtual table handle */ Fts3MultiSegReader *pCsr /* Cursor object */ ){ int rc = SQLITE_OK; int isIgnoreEmpty = (pCsr->pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY); int isRequirePos = (pCsr->pFilter->flags & FTS3_SEGMENT_REQUIRE_POS); int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER); int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX); int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN); int isFirst = (pCsr->pFilter->flags & FTS3_SEGMENT_FIRST); Fts3SegReader **apSegment = pCsr->apSegment; int nSegment = pCsr->nSegment; Fts3SegFilter *pFilter = pCsr->pFilter; int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp ); if( pCsr->nSegment==0 ) return SQLITE_OK; do { int nMerge; int i; /* Advance the first pCsr->nAdvance entries in the apSegment[] array ** forward. Then sort the list in order of current term again. */ for(i=0; inAdvance; i++){ Fts3SegReader *pSeg = apSegment[i]; if( pSeg->bLookup ){ fts3SegReaderSetEof(pSeg); }else{ rc = fts3SegReaderNext(p, pSeg, 0); } if( rc!=SQLITE_OK ) return rc; } fts3SegReaderSort(apSegment, nSegment, pCsr->nAdvance, fts3SegReaderCmp); pCsr->nAdvance = 0; /* If all the seg-readers are at EOF, we're finished. return SQLITE_OK. */ assert( rc==SQLITE_OK ); if( apSegment[0]->aNode==0 ) break; pCsr->nTerm = apSegment[0]->nTerm; pCsr->zTerm = apSegment[0]->zTerm; /* If this is a prefix-search, and if the term that apSegment[0] points ** to does not share a suffix with pFilter->zTerm/nTerm, then all ** required callbacks have been made. In this case exit early. ** ** Similarly, if this is a search for an exact match, and the first term ** of segment apSegment[0] is not a match, exit early. */ if( pFilter->zTerm && !isScan ){ if( pCsr->nTermnTerm || (!isPrefix && pCsr->nTerm>pFilter->nTerm) || memcmp(pCsr->zTerm, pFilter->zTerm, pFilter->nTerm) ){ break; } } nMerge = 1; while( nMergeaNode && apSegment[nMerge]->nTerm==pCsr->nTerm && 0==memcmp(pCsr->zTerm, apSegment[nMerge]->zTerm, pCsr->nTerm) ){ nMerge++; } assert( isIgnoreEmpty || (isRequirePos && !isColFilter) ); if( nMerge==1 && !isIgnoreEmpty && !isFirst && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0) ){ pCsr->nDoclist = apSegment[0]->nDoclist; if( fts3SegReaderIsPending(apSegment[0]) ){ rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, (i64)pCsr->nDoclist); pCsr->aDoclist = pCsr->aBuffer; }else{ pCsr->aDoclist = apSegment[0]->aDoclist; } if( rc==SQLITE_OK ) rc = SQLITE_ROW; }else{ int nDoclist = 0; /* Size of doclist */ sqlite3_int64 iPrev = 0; /* Previous docid stored in doclist */ /* The current term of the first nMerge entries in the array ** of Fts3SegReader objects is the same. The doclists must be merged ** and a single term returned with the merged doclist. */ for(i=0; ipOffsetList ){ int j; /* Number of segments that share a docid */ char *pList = 0; int nList = 0; int nByte; sqlite3_int64 iDocid = apSegment[0]->iDocid; fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList); j = 1; while( jpOffsetList && apSegment[j]->iDocid==iDocid ){ fts3SegReaderNextDocid(p, apSegment[j], 0, 0); j++; } if( isColFilter ){ fts3ColumnFilter(pFilter->iCol, 0, &pList, &nList); } if( !isIgnoreEmpty || nList>0 ){ /* Calculate the 'docid' delta value to write into the merged ** doclist. */ sqlite3_int64 iDelta; if( p->bDescIdx && nDoclist>0 ){ if( iPrev<=iDocid ) return FTS_CORRUPT_VTAB; iDelta = (i64)((u64)iPrev - (u64)iDocid); }else{ if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB; iDelta = (i64)((u64)iDocid - (u64)iPrev); } nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0); rc = fts3GrowSegReaderBuffer(pCsr, (i64)nByte+nDoclist+FTS3_NODE_PADDING); if( rc ) return rc; if( isFirst ){ char *a = &pCsr->aBuffer[nDoclist]; int nWrite; nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a); if( nWrite ){ iPrev = iDocid; nDoclist += nWrite; } }else{ nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta); iPrev = iDocid; if( isRequirePos ){ memcpy(&pCsr->aBuffer[nDoclist], pList, nList); nDoclist += nList; pCsr->aBuffer[nDoclist++] = '\0'; } } } fts3SegReaderSort(apSegment, nMerge, j, xCmp); } if( nDoclist>0 ){ rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING); if( rc ) return rc; memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING); pCsr->aDoclist = pCsr->aBuffer; pCsr->nDoclist = nDoclist; rc = SQLITE_ROW; } } pCsr->nAdvance = nMerge; }while( rc==SQLITE_OK ); return rc; } SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish( Fts3MultiSegReader *pCsr /* Cursor object */ ){ if( pCsr ){ int i; for(i=0; inSegment; i++){ sqlite3Fts3SegReaderFree(pCsr->apSegment[i]); } sqlite3_free(pCsr->apSegment); sqlite3_free(pCsr->aBuffer); pCsr->nSegment = 0; pCsr->apSegment = 0; pCsr->aBuffer = 0; } } /* ** Decode the "end_block" field, selected by column iCol of the SELECT ** statement passed as the first argument. ** ** The "end_block" field may contain either an integer, or a text field ** containing the text representation of two non-negative integers separated ** by one or more space (0x20) characters. In the first case, set *piEndBlock ** to the integer value and *pnByte to zero before returning. In the second, ** set *piEndBlock to the first value and *pnByte to the second. */ static void fts3ReadEndBlockField( sqlite3_stmt *pStmt, int iCol, i64 *piEndBlock, i64 *pnByte ){ const unsigned char *zText = sqlite3_column_text(pStmt, iCol); if( zText ){ int i; int iMul = 1; u64 iVal = 0; for(i=0; zText[i]>='0' && zText[i]<='9'; i++){ iVal = iVal*10 + (zText[i] - '0'); } *piEndBlock = (i64)iVal; while( zText[i]==' ' ) i++; iVal = 0; if( zText[i]=='-' ){ i++; iMul = -1; } for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ iVal = iVal*10 + (zText[i] - '0'); } *pnByte = ((i64)iVal * (i64)iMul); } } /* ** A segment of size nByte bytes has just been written to absolute level ** iAbsLevel. Promote any segments that should be promoted as a result. */ static int fts3PromoteSegments( Fts3Table *p, /* FTS table handle */ sqlite3_int64 iAbsLevel, /* Absolute level just updated */ sqlite3_int64 nByte /* Size of new segment at iAbsLevel */ ){ int rc = SQLITE_OK; sqlite3_stmt *pRange; rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE2, &pRange, 0); if( rc==SQLITE_OK ){ int bOk = 0; i64 iLast = (iAbsLevel/FTS3_SEGDIR_MAXLEVEL + 1) * FTS3_SEGDIR_MAXLEVEL - 1; i64 nLimit = (nByte*3)/2; /* Loop through all entries in the %_segdir table corresponding to ** segments in this index on levels greater than iAbsLevel. If there is ** at least one such segment, and it is possible to determine that all ** such segments are smaller than nLimit bytes in size, they will be ** promoted to level iAbsLevel. */ sqlite3_bind_int64(pRange, 1, iAbsLevel+1); sqlite3_bind_int64(pRange, 2, iLast); while( SQLITE_ROW==sqlite3_step(pRange) ){ i64 nSize = 0, dummy; fts3ReadEndBlockField(pRange, 2, &dummy, &nSize); if( nSize<=0 || nSize>nLimit ){ /* If nSize==0, then the %_segdir.end_block field does not not ** contain a size value. This happens if it was written by an ** old version of FTS. In this case it is not possible to determine ** the size of the segment, and so segment promotion does not ** take place. */ bOk = 0; break; } bOk = 1; } rc = sqlite3_reset(pRange); if( bOk ){ int iIdx = 0; sqlite3_stmt *pUpdate1 = 0; sqlite3_stmt *pUpdate2 = 0; if( rc==SQLITE_OK ){ rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0); } if( rc==SQLITE_OK ){ rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL, &pUpdate2, 0); } if( rc==SQLITE_OK ){ /* Loop through all %_segdir entries for segments in this index with ** levels equal to or greater than iAbsLevel. As each entry is visited, ** updated it to set (level = -1) and (idx = N), where N is 0 for the ** oldest segment in the range, 1 for the next oldest, and so on. ** ** In other words, move all segments being promoted to level -1, ** setting the "idx" fields as appropriate to keep them in the same ** order. The contents of level -1 (which is never used, except ** transiently here), will be moved back to level iAbsLevel below. */ sqlite3_bind_int64(pRange, 1, iAbsLevel); while( SQLITE_ROW==sqlite3_step(pRange) ){ sqlite3_bind_int(pUpdate1, 1, iIdx++); sqlite3_bind_int(pUpdate1, 2, sqlite3_column_int(pRange, 0)); sqlite3_bind_int(pUpdate1, 3, sqlite3_column_int(pRange, 1)); sqlite3_step(pUpdate1); rc = sqlite3_reset(pUpdate1); if( rc!=SQLITE_OK ){ sqlite3_reset(pRange); break; } } } if( rc==SQLITE_OK ){ rc = sqlite3_reset(pRange); } /* Move level -1 to level iAbsLevel */ if( rc==SQLITE_OK ){ sqlite3_bind_int64(pUpdate2, 1, iAbsLevel); sqlite3_step(pUpdate2); rc = sqlite3_reset(pUpdate2); } } } return rc; } /* ** Merge all level iLevel segments in the database into a single ** iLevel+1 segment. Or, if iLevel<0, merge all segments into a ** single segment with a level equal to the numerically largest level ** currently present in the database. ** ** If this function is called with iLevel<0, but there is only one ** segment in the database, SQLITE_DONE is returned immediately. ** Otherwise, if successful, SQLITE_OK is returned. If an error occurs, ** an SQLite error code is returned. */ static int fts3SegmentMerge( Fts3Table *p, int iLangid, /* Language id to merge */ int iIndex, /* Index in p->aIndex[] to merge */ int iLevel /* Level to merge */ ){ int rc; /* Return code */ int iIdx = 0; /* Index of new segment */ sqlite3_int64 iNewLevel = 0; /* Level/index to create new segment at */ SegmentWriter *pWriter = 0; /* Used to write the new, merged, segment */ Fts3SegFilter filter; /* Segment term filter condition */ Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */ int bIgnoreEmpty = 0; /* True to ignore empty segments */ i64 iMaxLevel = 0; /* Max level number for this index/langid */ assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel==FTS3_SEGCURSOR_PENDING || iLevel>=0 ); assert( iLevel=0 && iIndexnIndex ); rc = sqlite3Fts3SegReaderCursor(p, iLangid, iIndex, iLevel, 0, 0, 1, 0, &csr); if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished; if( iLevel!=FTS3_SEGCURSOR_PENDING ){ rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iMaxLevel); if( rc!=SQLITE_OK ) goto finished; } if( iLevel==FTS3_SEGCURSOR_ALL ){ /* This call is to merge all segments in the database to a single ** segment. The level of the new segment is equal to the numerically ** greatest segment level currently present in the database for this ** index. The idx of the new segment is always 0. */ if( csr.nSegment==1 && 0==fts3SegReaderIsPending(csr.apSegment[0]) ){ rc = SQLITE_DONE; goto finished; } iNewLevel = iMaxLevel; bIgnoreEmpty = 1; }else{ /* This call is to merge all segments at level iLevel. find the next ** available segment index at level iLevel+1. The call to ** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to ** a single iLevel+2 segment if necessary. */ assert( FTS3_SEGCURSOR_PENDING==-1 ); iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1); rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); bIgnoreEmpty = (iLevel!=FTS3_SEGCURSOR_PENDING) && (iNewLevel>iMaxLevel); } if( rc!=SQLITE_OK ) goto finished; assert( csr.nSegment>0 ); assert_fts3_nc( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); assert_fts3_nc( iNewLevelnLeafData); } } } finished: fts3SegWriterFree(pWriter); sqlite3Fts3SegReaderFinish(&csr); return rc; } /* ** Flush the contents of pendingTerms to level 0 segments. */ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ int rc = SQLITE_OK; int i; for(i=0; rc==SQLITE_OK && inIndex; i++){ rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING); if( rc==SQLITE_DONE ) rc = SQLITE_OK; } /* Determine the auto-incr-merge setting if unknown. If enabled, ** estimate the number of leaf blocks of content to be written */ if( rc==SQLITE_OK && p->bHasStat && p->nAutoincrmerge==0xff && p->nLeafAdd>0 ){ sqlite3_stmt *pStmt = 0; rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); rc = sqlite3_step(pStmt); if( rc==SQLITE_ROW ){ p->nAutoincrmerge = sqlite3_column_int(pStmt, 0); if( p->nAutoincrmerge==1 ) p->nAutoincrmerge = 8; }else if( rc==SQLITE_DONE ){ p->nAutoincrmerge = 0; } rc = sqlite3_reset(pStmt); } } if( rc==SQLITE_OK ){ sqlite3Fts3PendingTermsClear(p); } return rc; } /* ** Encode N integers as varints into a blob. */ static void fts3EncodeIntArray( int N, /* The number of integers to encode */ u32 *a, /* The integer values */ char *zBuf, /* Write the BLOB here */ int *pNBuf /* Write number of bytes if zBuf[] used here */ ){ int i, j; for(i=j=0; iiPrevDocid. The sizes are encoded as ** a blob of varints. */ static void fts3InsertDocsize( int *pRC, /* Result code */ Fts3Table *p, /* Table into which to insert */ u32 *aSz /* Sizes of each column, in tokens */ ){ char *pBlob; /* The BLOB encoding of the document size */ int nBlob; /* Number of bytes in the BLOB */ sqlite3_stmt *pStmt; /* Statement used to insert the encoding */ int rc; /* Result code from subfunctions */ if( *pRC ) return; pBlob = sqlite3_malloc64( 10*(sqlite3_int64)p->nColumn ); if( pBlob==0 ){ *pRC = SQLITE_NOMEM; return; } fts3EncodeIntArray(p->nColumn, aSz, pBlob, &nBlob); rc = fts3SqlStmt(p, SQL_REPLACE_DOCSIZE, &pStmt, 0); if( rc ){ sqlite3_free(pBlob); *pRC = rc; return; } sqlite3_bind_int64(pStmt, 1, p->iPrevDocid); sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, sqlite3_free); sqlite3_step(pStmt); *pRC = sqlite3_reset(pStmt); } /* ** Record 0 of the %_stat table contains a blob consisting of N varints, ** where N is the number of user defined columns in the fts3 table plus ** two. If nCol is the number of user defined columns, then values of the ** varints are set as follows: ** ** Varint 0: Total number of rows in the table. ** ** Varint 1..nCol: For each column, the total number of tokens stored in ** the column for all rows of the table. ** ** Varint 1+nCol: The total size, in bytes, of all text values in all ** columns of all rows of the table. ** */ static void fts3UpdateDocTotals( int *pRC, /* The result code */ Fts3Table *p, /* Table being updated */ u32 *aSzIns, /* Size increases */ u32 *aSzDel, /* Size decreases */ int nChng /* Change in the number of documents */ ){ char *pBlob; /* Storage for BLOB written into %_stat */ int nBlob; /* Size of BLOB written into %_stat */ u32 *a; /* Array of integers that becomes the BLOB */ sqlite3_stmt *pStmt; /* Statement for reading and writing */ int i; /* Loop counter */ int rc; /* Result code from subfunctions */ const int nStat = p->nColumn+2; if( *pRC ) return; a = sqlite3_malloc64( (sizeof(u32)+10)*(sqlite3_int64)nStat ); if( a==0 ){ *pRC = SQLITE_NOMEM; return; } pBlob = (char*)&a[nStat]; rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); if( rc ){ sqlite3_free(a); *pRC = rc; return; } sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); if( sqlite3_step(pStmt)==SQLITE_ROW ){ fts3DecodeIntArray(nStat, a, sqlite3_column_blob(pStmt, 0), sqlite3_column_bytes(pStmt, 0)); }else{ memset(a, 0, sizeof(u32)*(nStat) ); } rc = sqlite3_reset(pStmt); if( rc!=SQLITE_OK ){ sqlite3_free(a); *pRC = rc; return; } if( nChng<0 && a[0]<(u32)(-nChng) ){ a[0] = 0; }else{ a[0] += nChng; } for(i=0; inColumn+1; i++){ u32 x = a[i+1]; if( x+aSzIns[i] < aSzDel[i] ){ x = 0; }else{ x = x + aSzIns[i] - aSzDel[i]; } a[i+1] = x; } fts3EncodeIntArray(nStat, a, pBlob, &nBlob); rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); if( rc ){ sqlite3_free(a); *pRC = rc; return; } sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, SQLITE_STATIC); sqlite3_step(pStmt); *pRC = sqlite3_reset(pStmt); sqlite3_bind_null(pStmt, 2); sqlite3_free(a); } /* ** Merge the entire database so that there is one segment for each ** iIndex/iLangid combination. */ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){ int bSeenDone = 0; int rc; sqlite3_stmt *pAllLangid = 0; rc = sqlite3Fts3PendingTermsFlush(p); if( rc==SQLITE_OK ){ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); } if( rc==SQLITE_OK ){ int rc2; sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid); sqlite3_bind_int(pAllLangid, 2, p->nIndex); while( sqlite3_step(pAllLangid)==SQLITE_ROW ){ int i; int iLangid = sqlite3_column_int(pAllLangid, 0); for(i=0; rc==SQLITE_OK && inIndex; i++){ rc = fts3SegmentMerge(p, iLangid, i, FTS3_SEGCURSOR_ALL); if( rc==SQLITE_DONE ){ bSeenDone = 1; rc = SQLITE_OK; } } } rc2 = sqlite3_reset(pAllLangid); if( rc==SQLITE_OK ) rc = rc2; } sqlite3Fts3SegmentsClose(p); return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc; } /* ** This function is called when the user executes the following statement: ** ** INSERT INTO () VALUES('rebuild'); ** ** The entire FTS index is discarded and rebuilt. If the table is one ** created using the content=xxx option, then the new index is based on ** the current contents of the xxx table. Otherwise, it is rebuilt based ** on the contents of the %_content table. */ static int fts3DoRebuild(Fts3Table *p){ int rc; /* Return Code */ rc = fts3DeleteAll(p, 0); if( rc==SQLITE_OK ){ u32 *aSz = 0; u32 *aSzIns = 0; u32 *aSzDel = 0; sqlite3_stmt *pStmt = 0; int nEntry = 0; /* Compose and prepare an SQL statement to loop through the content table */ char *zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); if( !zSql ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); } if( rc==SQLITE_OK ){ sqlite3_int64 nByte = sizeof(u32) * ((sqlite3_int64)p->nColumn+1)*3; aSz = (u32 *)sqlite3_malloc64(nByte); if( aSz==0 ){ rc = SQLITE_NOMEM; }else{ memset(aSz, 0, nByte); aSzIns = &aSz[p->nColumn+1]; aSzDel = &aSzIns[p->nColumn+1]; } } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ int iCol; int iLangid = langidFromSelect(p, pStmt); rc = fts3PendingTermsDocid(p, 0, iLangid, sqlite3_column_int64(pStmt, 0)); memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1)); for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ if( p->abNotindexed[iCol]==0 ){ const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]); aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); } } if( p->bHasDocsize ){ fts3InsertDocsize(&rc, p, aSz); } if( rc!=SQLITE_OK ){ sqlite3_finalize(pStmt); pStmt = 0; }else{ nEntry++; for(iCol=0; iCol<=p->nColumn; iCol++){ aSzIns[iCol] += aSz[iCol]; } } } if( p->bFts4 ){ fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry); } sqlite3_free(aSz); if( pStmt ){ int rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ){ rc = rc2; } } } return rc; } /* ** This function opens a cursor used to read the input data for an ** incremental merge operation. Specifically, it opens a cursor to scan ** the oldest nSeg segments (idx=0 through idx=(nSeg-1)) in absolute ** level iAbsLevel. */ static int fts3IncrmergeCsr( Fts3Table *p, /* FTS3 table handle */ sqlite3_int64 iAbsLevel, /* Absolute level to open */ int nSeg, /* Number of segments to merge */ Fts3MultiSegReader *pCsr /* Cursor object to populate */ ){ int rc; /* Return Code */ sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */ sqlite3_int64 nByte; /* Bytes allocated at pCsr->apSegment[] */ /* Allocate space for the Fts3MultiSegReader.aCsr[] array */ memset(pCsr, 0, sizeof(*pCsr)); nByte = sizeof(Fts3SegReader *) * nSeg; pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc64(nByte); if( pCsr->apSegment==0 ){ rc = SQLITE_NOMEM; }else{ memset(pCsr->apSegment, 0, nByte); rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0); } if( rc==SQLITE_OK ){ int i; int rc2; sqlite3_bind_int64(pStmt, 1, iAbsLevel); assert( pCsr->nSegment==0 ); for(i=0; rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW && iapSegment[i] ); pCsr->nSegment++; } rc2 = sqlite3_reset(pStmt); if( rc==SQLITE_OK ) rc = rc2; } return rc; } typedef struct IncrmergeWriter IncrmergeWriter; typedef struct NodeWriter NodeWriter; typedef struct Blob Blob; typedef struct NodeReader NodeReader; /* ** An instance of the following structure is used as a dynamic buffer ** to build up nodes or other blobs of data in. ** ** The function blobGrowBuffer() is used to extend the allocation. */ struct Blob { char *a; /* Pointer to allocation */ int n; /* Number of valid bytes of data in a[] */ int nAlloc; /* Allocated size of a[] (nAlloc>=n) */ }; /* ** This structure is used to build up buffers containing segment b-tree ** nodes (blocks). */ struct NodeWriter { sqlite3_int64 iBlock; /* Current block id */ Blob key; /* Last key written to the current block */ Blob block; /* Current block image */ }; /* ** An object of this type contains the state required to create or append ** to an appendable b-tree segment. */ struct IncrmergeWriter { int nLeafEst; /* Space allocated for leaf blocks */ int nWork; /* Number of leaf pages flushed */ sqlite3_int64 iAbsLevel; /* Absolute level of input segments */ int iIdx; /* Index of *output* segment in iAbsLevel+1 */ sqlite3_int64 iStart; /* Block number of first allocated block */ sqlite3_int64 iEnd; /* Block number of last allocated block */ sqlite3_int64 nLeafData; /* Bytes of leaf page data so far */ u8 bNoLeafData; /* If true, store 0 for segment size */ NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT]; }; /* ** An object of the following type is used to read data from a single ** FTS segment node. See the following functions: ** ** nodeReaderInit() ** nodeReaderNext() ** nodeReaderRelease() */ struct NodeReader { const char *aNode; int nNode; int iOff; /* Current offset within aNode[] */ /* Output variables. Containing the current node entry. */ sqlite3_int64 iChild; /* Pointer to child node */ Blob term; /* Current term */ const char *aDoclist; /* Pointer to doclist */ int nDoclist; /* Size of doclist in bytes */ }; /* ** If *pRc is not SQLITE_OK when this function is called, it is a no-op. ** Otherwise, if the allocation at pBlob->a is not already at least nMin ** bytes in size, extend (realloc) it to be so. ** ** If an OOM error occurs, set *pRc to SQLITE_NOMEM and leave pBlob->a ** unmodified. Otherwise, if the allocation succeeds, update pBlob->nAlloc ** to reflect the new size of the pBlob->a[] buffer. */ static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){ if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){ int nAlloc = nMin; char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc); if( a ){ pBlob->nAlloc = nAlloc; pBlob->a = a; }else{ *pRc = SQLITE_NOMEM; } } } /* ** Attempt to advance the node-reader object passed as the first argument to ** the next entry on the node. ** ** Return an error code if an error occurs (SQLITE_NOMEM is possible). ** Otherwise return SQLITE_OK. If there is no next entry on the node ** (e.g. because the current entry is the last) set NodeReader->aNode to ** NULL to indicate EOF. Otherwise, populate the NodeReader structure output ** variables for the new entry. */ static int nodeReaderNext(NodeReader *p){ int bFirst = (p->term.n==0); /* True for first term on the node */ int nPrefix = 0; /* Bytes to copy from previous term */ int nSuffix = 0; /* Bytes to append to the prefix */ int rc = SQLITE_OK; /* Return code */ assert( p->aNode ); if( p->iChild && bFirst==0 ) p->iChild++; if( p->iOff>=p->nNode ){ /* EOF */ p->aNode = 0; }else{ if( bFirst==0 ){ p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nPrefix); } p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix); if( nPrefix>p->term.n || nSuffix>p->nNode-p->iOff || nSuffix==0 ){ return FTS_CORRUPT_VTAB; } blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc); if( rc==SQLITE_OK && ALWAYS(p->term.a!=0) ){ memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix); p->term.n = nPrefix+nSuffix; p->iOff += nSuffix; if( p->iChild==0 ){ p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist); if( (p->nNode-p->iOff)nDoclist ){ return FTS_CORRUPT_VTAB; } p->aDoclist = &p->aNode[p->iOff]; p->iOff += p->nDoclist; } } } assert_fts3_nc( p->iOff<=p->nNode ); return rc; } /* ** Release all dynamic resources held by node-reader object *p. */ static void nodeReaderRelease(NodeReader *p){ sqlite3_free(p->term.a); } /* ** Initialize a node-reader object to read the node in buffer aNode/nNode. ** ** If successful, SQLITE_OK is returned and the NodeReader object set to ** point to the first entry on the node (if any). Otherwise, an SQLite ** error code is returned. */ static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){ memset(p, 0, sizeof(NodeReader)); p->aNode = aNode; p->nNode = nNode; /* Figure out if this is a leaf or an internal node. */ if( aNode && aNode[0] ){ /* An internal node. */ p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild); }else{ p->iOff = 1; } return aNode ? nodeReaderNext(p) : SQLITE_OK; } /* ** This function is called while writing an FTS segment each time a leaf o ** node is finished and written to disk. The key (zTerm/nTerm) is guaranteed ** to be greater than the largest key on the node just written, but smaller ** than or equal to the first key that will be written to the next leaf ** node. ** ** The block id of the leaf node just written to disk may be found in ** (pWriter->aNodeWriter[0].iBlock) when this function is called. */ static int fts3IncrmergePush( Fts3Table *p, /* Fts3 table handle */ IncrmergeWriter *pWriter, /* Writer object */ const char *zTerm, /* Term to write to internal node */ int nTerm /* Bytes at zTerm */ ){ sqlite3_int64 iPtr = pWriter->aNodeWriter[0].iBlock; int iLayer; assert( nTerm>0 ); for(iLayer=1; ALWAYS(iLayeraNodeWriter[iLayer]; int rc = SQLITE_OK; int nPrefix; int nSuffix; int nSpace; /* Figure out how much space the key will consume if it is written to ** the current node of layer iLayer. Due to the prefix compression, ** the space required changes depending on which node the key is to ** be added to. */ nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm); nSuffix = nTerm - nPrefix; if(nSuffix<=0 ) return FTS_CORRUPT_VTAB; nSpace = sqlite3Fts3VarintLen(nPrefix); nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){ /* If the current node of layer iLayer contains zero keys, or if adding ** the key to it will not cause it to grow to larger than nNodeSize ** bytes in size, write the key here. */ Blob *pBlk = &pNode->block; if( pBlk->n==0 ){ blobGrowBuffer(pBlk, p->nNodeSize, &rc); if( rc==SQLITE_OK ){ pBlk->a[0] = (char)iLayer; pBlk->n = 1 + sqlite3Fts3PutVarint(&pBlk->a[1], iPtr); } } blobGrowBuffer(pBlk, pBlk->n + nSpace, &rc); blobGrowBuffer(&pNode->key, nTerm, &rc); if( rc==SQLITE_OK ){ if( pNode->key.n ){ pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix); } pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix); assert( nPrefix+nSuffix<=nTerm ); assert( nPrefix>=0 ); memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix); pBlk->n += nSuffix; memcpy(pNode->key.a, zTerm, nTerm); pNode->key.n = nTerm; } }else{ /* Otherwise, flush the current node of layer iLayer to disk. ** Then allocate a new, empty sibling node. The key will be written ** into the parent of this node. */ rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n); assert( pNode->block.nAlloc>=p->nNodeSize ); pNode->block.a[0] = (char)iLayer; pNode->block.n = 1 + sqlite3Fts3PutVarint(&pNode->block.a[1], iPtr+1); iNextPtr = pNode->iBlock; pNode->iBlock++; pNode->key.n = 0; } if( rc!=SQLITE_OK || iNextPtr==0 ) return rc; iPtr = iNextPtr; } assert( 0 ); return 0; } /* ** Append a term and (optionally) doclist to the FTS segment node currently ** stored in blob *pNode. The node need not contain any terms, but the ** header must be written before this function is called. ** ** A node header is a single 0x00 byte for a leaf node, or a height varint ** followed by the left-hand-child varint for an internal node. ** ** The term to be appended is passed via arguments zTerm/nTerm. For a ** leaf node, the doclist is passed as aDoclist/nDoclist. For an internal ** node, both aDoclist and nDoclist must be passed 0. ** ** If the size of the value in blob pPrev is zero, then this is the first ** term written to the node. Otherwise, pPrev contains a copy of the ** previous term. Before this function returns, it is updated to contain a ** copy of zTerm/nTerm. ** ** It is assumed that the buffer associated with pNode is already large ** enough to accommodate the new entry. The buffer associated with pPrev ** is extended by this function if requrired. ** ** If an error (i.e. OOM condition) occurs, an SQLite error code is ** returned. Otherwise, SQLITE_OK. */ static int fts3AppendToNode( Blob *pNode, /* Current node image to append to */ Blob *pPrev, /* Buffer containing previous term written */ const char *zTerm, /* New term to write */ int nTerm, /* Size of zTerm in bytes */ const char *aDoclist, /* Doclist (or NULL) to write */ int nDoclist /* Size of aDoclist in bytes */ ){ int rc = SQLITE_OK; /* Return code */ int bFirst = (pPrev->n==0); /* True if this is the first term written */ int nPrefix; /* Size of term prefix in bytes */ int nSuffix; /* Size of term suffix in bytes */ /* Node must have already been started. There must be a doclist for a ** leaf node, and there must not be a doclist for an internal node. */ assert( pNode->n>0 ); assert_fts3_nc( (pNode->a[0]=='\0')==(aDoclist!=0) ); blobGrowBuffer(pPrev, nTerm, &rc); if( rc!=SQLITE_OK ) return rc; assert( pPrev!=0 ); assert( pPrev->a!=0 ); nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm); nSuffix = nTerm - nPrefix; if( nSuffix<=0 ) return FTS_CORRUPT_VTAB; memcpy(pPrev->a, zTerm, nTerm); pPrev->n = nTerm; if( bFirst==0 ){ pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nPrefix); } pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nSuffix); memcpy(&pNode->a[pNode->n], &zTerm[nPrefix], nSuffix); pNode->n += nSuffix; if( aDoclist ){ pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nDoclist); memcpy(&pNode->a[pNode->n], aDoclist, nDoclist); pNode->n += nDoclist; } assert( pNode->n<=pNode->nAlloc ); return SQLITE_OK; } /* ** Append the current term and doclist pointed to by cursor pCsr to the ** appendable b-tree segment opened for writing by pWriter. ** ** Return SQLITE_OK if successful, or an SQLite error code otherwise. */ static int fts3IncrmergeAppend( Fts3Table *p, /* Fts3 table handle */ IncrmergeWriter *pWriter, /* Writer object */ Fts3MultiSegReader *pCsr /* Cursor containing term and doclist */ ){ const char *zTerm = pCsr->zTerm; int nTerm = pCsr->nTerm; const char *aDoclist = pCsr->aDoclist; int nDoclist = pCsr->nDoclist; int rc = SQLITE_OK; /* Return code */ int nSpace; /* Total space in bytes required on leaf */ int nPrefix; /* Size of prefix shared with previous term */ int nSuffix; /* Size of suffix (nTerm - nPrefix) */ NodeWriter *pLeaf; /* Object used to write leaf nodes */ pLeaf = &pWriter->aNodeWriter[0]; nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm); nSuffix = nTerm - nPrefix; if(nSuffix<=0 ) return FTS_CORRUPT_VTAB; nSpace = sqlite3Fts3VarintLen(nPrefix); nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; /* If the current block is not empty, and if adding this term/doclist ** to the current block would make it larger than Fts3Table.nNodeSize bytes, ** and if there is still room for another leaf page, write this block out to ** the database. */ if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize && pLeaf->iBlock < (pWriter->iStart + pWriter->nLeafEst) ){ rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n); pWriter->nWork++; /* Add the current term to the parent node. The term added to the ** parent must: ** ** a) be greater than the largest term on the leaf node just written ** to the database (still available in pLeaf->key), and ** ** b) be less than or equal to the term about to be added to the new ** leaf node (zTerm/nTerm). ** ** In other words, it must be the prefix of zTerm 1 byte longer than ** the common prefix (if any) of zTerm and pWriter->zTerm. */ if( rc==SQLITE_OK ){ rc = fts3IncrmergePush(p, pWriter, zTerm, nPrefix+1); } /* Advance to the next output block */ pLeaf->iBlock++; pLeaf->key.n = 0; pLeaf->block.n = 0; nSuffix = nTerm; nSpace = 1; nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; } pWriter->nLeafData += nSpace; blobGrowBuffer(&pLeaf->block, pLeaf->block.n + nSpace, &rc); if( rc==SQLITE_OK ){ if( pLeaf->block.n==0 ){ pLeaf->block.n = 1; pLeaf->block.a[0] = '\0'; } rc = fts3AppendToNode( &pLeaf->block, &pLeaf->key, zTerm, nTerm, aDoclist, nDoclist ); } return rc; } /* ** This function is called to release all dynamic resources held by the ** merge-writer object pWriter, and if no error has occurred, to flush ** all outstanding node buffers held by pWriter to disk. ** ** If *pRc is not SQLITE_OK when this function is called, then no attempt ** is made to write any data to disk. Instead, this function serves only ** to release outstanding resources. ** ** Otherwise, if *pRc is initially SQLITE_OK and an error occurs while ** flushing buffers to disk, *pRc is set to an SQLite error code before ** returning. */ static void fts3IncrmergeRelease( Fts3Table *p, /* FTS3 table handle */ IncrmergeWriter *pWriter, /* Merge-writer object */ int *pRc /* IN/OUT: Error code */ ){ int i; /* Used to iterate through non-root layers */ int iRoot; /* Index of root in pWriter->aNodeWriter */ NodeWriter *pRoot; /* NodeWriter for root node */ int rc = *pRc; /* Error code */ /* Set iRoot to the index in pWriter->aNodeWriter[] of the output segment ** root node. If the segment fits entirely on a single leaf node, iRoot ** will be set to 0. If the root node is the parent of the leaves, iRoot ** will be 1. And so on. */ for(iRoot=FTS_MAX_APPENDABLE_HEIGHT-1; iRoot>=0; iRoot--){ NodeWriter *pNode = &pWriter->aNodeWriter[iRoot]; if( pNode->block.n>0 ) break; assert( *pRc || pNode->block.nAlloc==0 ); assert( *pRc || pNode->key.nAlloc==0 ); sqlite3_free(pNode->block.a); sqlite3_free(pNode->key.a); } /* Empty output segment. This is a no-op. */ if( iRoot<0 ) return; /* The entire output segment fits on a single node. Normally, this means ** the node would be stored as a blob in the "root" column of the %_segdir ** table. However, this is not permitted in this case. The problem is that ** space has already been reserved in the %_segments table, and so the ** start_block and end_block fields of the %_segdir table must be populated. ** And, by design or by accident, released versions of FTS cannot handle ** segments that fit entirely on the root node with start_block!=0. ** ** Instead, create a synthetic root node that contains nothing but a ** pointer to the single content node. So that the segment consists of a ** single leaf and a single interior (root) node. ** ** Todo: Better might be to defer allocating space in the %_segments ** table until we are sure it is needed. */ if( iRoot==0 ){ Blob *pBlock = &pWriter->aNodeWriter[1].block; blobGrowBuffer(pBlock, 1 + FTS3_VARINT_MAX, &rc); if( rc==SQLITE_OK ){ pBlock->a[0] = 0x01; pBlock->n = 1 + sqlite3Fts3PutVarint( &pBlock->a[1], pWriter->aNodeWriter[0].iBlock ); } iRoot = 1; } pRoot = &pWriter->aNodeWriter[iRoot]; /* Flush all currently outstanding nodes to disk. */ for(i=0; iaNodeWriter[i]; if( pNode->block.n>0 && rc==SQLITE_OK ){ rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n); } sqlite3_free(pNode->block.a); sqlite3_free(pNode->key.a); } /* Write the %_segdir record. */ if( rc==SQLITE_OK ){ rc = fts3WriteSegdir(p, pWriter->iAbsLevel+1, /* level */ pWriter->iIdx, /* idx */ pWriter->iStart, /* start_block */ pWriter->aNodeWriter[0].iBlock, /* leaves_end_block */ pWriter->iEnd, /* end_block */ (pWriter->bNoLeafData==0 ? pWriter->nLeafData : 0), /* end_block */ pRoot->block.a, pRoot->block.n /* root */ ); } sqlite3_free(pRoot->block.a); sqlite3_free(pRoot->key.a); *pRc = rc; } /* ** Compare the term in buffer zLhs (size in bytes nLhs) with that in ** zRhs (size in bytes nRhs) using memcmp. If one term is a prefix of ** the other, it is considered to be smaller than the other. ** ** Return -ve if zLhs is smaller than zRhs, 0 if it is equal, or +ve ** if it is greater. */ static int fts3TermCmp( const char *zLhs, int nLhs, /* LHS of comparison */ const char *zRhs, int nRhs /* RHS of comparison */ ){ int nCmp = MIN(nLhs, nRhs); int res; if( nCmp && ALWAYS(zLhs) && ALWAYS(zRhs) ){ res = memcmp(zLhs, zRhs, nCmp); }else{ res = 0; } if( res==0 ) res = nLhs - nRhs; return res; } /* ** Query to see if the entry in the %_segments table with blockid iEnd is ** NULL. If no error occurs and the entry is NULL, set *pbRes 1 before ** returning. Otherwise, set *pbRes to 0. ** ** Or, if an error occurs while querying the database, return an SQLite ** error code. The final value of *pbRes is undefined in this case. ** ** This is used to test if a segment is an "appendable" segment. If it ** is, then a NULL entry has been inserted into the %_segments table ** with blockid %_segdir.end_block. */ static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){ int bRes = 0; /* Result to set *pbRes to */ sqlite3_stmt *pCheck = 0; /* Statement to query database with */ int rc; /* Return code */ rc = fts3SqlStmt(p, SQL_SEGMENT_IS_APPENDABLE, &pCheck, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pCheck, 1, iEnd); if( SQLITE_ROW==sqlite3_step(pCheck) ) bRes = 1; rc = sqlite3_reset(pCheck); } *pbRes = bRes; return rc; } /* ** This function is called when initializing an incremental-merge operation. ** It checks if the existing segment with index value iIdx at absolute level ** (iAbsLevel+1) can be appended to by the incremental merge. If it can, the ** merge-writer object *pWriter is initialized to write to it. ** ** An existing segment can be appended to by an incremental merge if: ** ** * It was initially created as an appendable segment (with all required ** space pre-allocated), and ** ** * The first key read from the input (arguments zKey and nKey) is ** greater than the largest key currently stored in the potential ** output segment. */ static int fts3IncrmergeLoad( Fts3Table *p, /* Fts3 table handle */ sqlite3_int64 iAbsLevel, /* Absolute level of input segments */ int iIdx, /* Index of candidate output segment */ const char *zKey, /* First key to write */ int nKey, /* Number of bytes in nKey */ IncrmergeWriter *pWriter /* Populate this object */ ){ int rc; /* Return code */ sqlite3_stmt *pSelect = 0; /* SELECT to read %_segdir entry */ rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pSelect, 0); if( rc==SQLITE_OK ){ sqlite3_int64 iStart = 0; /* Value of %_segdir.start_block */ sqlite3_int64 iLeafEnd = 0; /* Value of %_segdir.leaves_end_block */ sqlite3_int64 iEnd = 0; /* Value of %_segdir.end_block */ const char *aRoot = 0; /* Pointer to %_segdir.root buffer */ int nRoot = 0; /* Size of aRoot[] in bytes */ int rc2; /* Return code from sqlite3_reset() */ int bAppendable = 0; /* Set to true if segment is appendable */ /* Read the %_segdir entry for index iIdx absolute level (iAbsLevel+1) */ sqlite3_bind_int64(pSelect, 1, iAbsLevel+1); sqlite3_bind_int(pSelect, 2, iIdx); if( sqlite3_step(pSelect)==SQLITE_ROW ){ iStart = sqlite3_column_int64(pSelect, 1); iLeafEnd = sqlite3_column_int64(pSelect, 2); fts3ReadEndBlockField(pSelect, 3, &iEnd, &pWriter->nLeafData); if( pWriter->nLeafData<0 ){ pWriter->nLeafData = pWriter->nLeafData * -1; } pWriter->bNoLeafData = (pWriter->nLeafData==0); nRoot = sqlite3_column_bytes(pSelect, 4); aRoot = sqlite3_column_blob(pSelect, 4); if( aRoot==0 ){ sqlite3_reset(pSelect); return nRoot ? SQLITE_NOMEM : FTS_CORRUPT_VTAB; } }else{ return sqlite3_reset(pSelect); } /* Check for the zero-length marker in the %_segments table */ rc = fts3IsAppendable(p, iEnd, &bAppendable); /* Check that zKey/nKey is larger than the largest key the candidate */ if( rc==SQLITE_OK && bAppendable ){ char *aLeaf = 0; int nLeaf = 0; rc = sqlite3Fts3ReadBlock(p, iLeafEnd, &aLeaf, &nLeaf, 0); if( rc==SQLITE_OK ){ NodeReader reader; for(rc = nodeReaderInit(&reader, aLeaf, nLeaf); rc==SQLITE_OK && reader.aNode; rc = nodeReaderNext(&reader) ){ assert( reader.aNode ); } if( fts3TermCmp(zKey, nKey, reader.term.a, reader.term.n)<=0 ){ bAppendable = 0; } nodeReaderRelease(&reader); } sqlite3_free(aLeaf); } if( rc==SQLITE_OK && bAppendable ){ /* It is possible to append to this segment. Set up the IncrmergeWriter ** object to do so. */ int i; int nHeight = (int)aRoot[0]; NodeWriter *pNode; if( nHeight<1 || nHeight>=FTS_MAX_APPENDABLE_HEIGHT ){ sqlite3_reset(pSelect); return FTS_CORRUPT_VTAB; } pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT; pWriter->iStart = iStart; pWriter->iEnd = iEnd; pWriter->iAbsLevel = iAbsLevel; pWriter->iIdx = iIdx; for(i=nHeight+1; iaNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst; } pNode = &pWriter->aNodeWriter[nHeight]; pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight; blobGrowBuffer(&pNode->block, MAX(nRoot, p->nNodeSize)+FTS3_NODE_PADDING, &rc ); if( rc==SQLITE_OK ){ memcpy(pNode->block.a, aRoot, nRoot); pNode->block.n = nRoot; memset(&pNode->block.a[nRoot], 0, FTS3_NODE_PADDING); } for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){ NodeReader reader; memset(&reader, 0, sizeof(reader)); pNode = &pWriter->aNodeWriter[i]; if( pNode->block.a){ rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n); while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader); blobGrowBuffer(&pNode->key, reader.term.n, &rc); if( rc==SQLITE_OK ){ assert_fts3_nc( reader.term.n>0 || reader.aNode==0 ); if( reader.term.n>0 ){ memcpy(pNode->key.a, reader.term.a, reader.term.n); } pNode->key.n = reader.term.n; if( i>0 ){ char *aBlock = 0; int nBlock = 0; pNode = &pWriter->aNodeWriter[i-1]; pNode->iBlock = reader.iChild; rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock,0); blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc ); if( rc==SQLITE_OK ){ memcpy(pNode->block.a, aBlock, nBlock); pNode->block.n = nBlock; memset(&pNode->block.a[nBlock], 0, FTS3_NODE_PADDING); } sqlite3_free(aBlock); } } } nodeReaderRelease(&reader); } } rc2 = sqlite3_reset(pSelect); if( rc==SQLITE_OK ) rc = rc2; } return rc; } /* ** Determine the largest segment index value that exists within absolute ** level iAbsLevel+1. If no error occurs, set *piIdx to this value plus ** one before returning SQLITE_OK. Or, if there are no segments at all ** within level iAbsLevel, set *piIdx to zero. ** ** If an error occurs, return an SQLite error code. The final value of ** *piIdx is undefined in this case. */ static int fts3IncrmergeOutputIdx( Fts3Table *p, /* FTS Table handle */ sqlite3_int64 iAbsLevel, /* Absolute index of input segments */ int *piIdx /* OUT: Next free index at iAbsLevel+1 */ ){ int rc; sqlite3_stmt *pOutputIdx = 0; /* SQL used to find output index */ rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pOutputIdx, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pOutputIdx, 1, iAbsLevel+1); sqlite3_step(pOutputIdx); *piIdx = sqlite3_column_int(pOutputIdx, 0); rc = sqlite3_reset(pOutputIdx); } return rc; } /* ** Allocate an appendable output segment on absolute level iAbsLevel+1 ** with idx value iIdx. ** ** In the %_segdir table, a segment is defined by the values in three ** columns: ** ** start_block ** leaves_end_block ** end_block ** ** When an appendable segment is allocated, it is estimated that the ** maximum number of leaf blocks that may be required is the sum of the ** number of leaf blocks consumed by the input segments, plus the number ** of input segments, multiplied by two. This value is stored in stack ** variable nLeafEst. ** ** A total of 16*nLeafEst blocks are allocated when an appendable segment ** is created ((1 + end_block - start_block)==16*nLeafEst). The contiguous ** array of leaf nodes starts at the first block allocated. The array ** of interior nodes that are parents of the leaf nodes start at block ** (start_block + (1 + end_block - start_block) / 16). And so on. ** ** In the actual code below, the value "16" is replaced with the ** pre-processor macro FTS_MAX_APPENDABLE_HEIGHT. */ static int fts3IncrmergeWriter( Fts3Table *p, /* Fts3 table handle */ sqlite3_int64 iAbsLevel, /* Absolute level of input segments */ int iIdx, /* Index of new output segment */ Fts3MultiSegReader *pCsr, /* Cursor that data will be read from */ IncrmergeWriter *pWriter /* Populate this object */ ){ int rc; /* Return Code */ int i; /* Iterator variable */ int nLeafEst = 0; /* Blocks allocated for leaf nodes */ sqlite3_stmt *pLeafEst = 0; /* SQL used to determine nLeafEst */ sqlite3_stmt *pFirstBlock = 0; /* SQL used to determine first block */ /* Calculate nLeafEst. */ rc = fts3SqlStmt(p, SQL_MAX_LEAF_NODE_ESTIMATE, &pLeafEst, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pLeafEst, 1, iAbsLevel); sqlite3_bind_int64(pLeafEst, 2, pCsr->nSegment); if( SQLITE_ROW==sqlite3_step(pLeafEst) ){ nLeafEst = sqlite3_column_int(pLeafEst, 0); } rc = sqlite3_reset(pLeafEst); } if( rc!=SQLITE_OK ) return rc; /* Calculate the first block to use in the output segment */ rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pFirstBlock, 0); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pFirstBlock) ){ pWriter->iStart = sqlite3_column_int64(pFirstBlock, 0); pWriter->iEnd = pWriter->iStart - 1; pWriter->iEnd += nLeafEst * FTS_MAX_APPENDABLE_HEIGHT; } rc = sqlite3_reset(pFirstBlock); } if( rc!=SQLITE_OK ) return rc; /* Insert the marker in the %_segments table to make sure nobody tries ** to steal the space just allocated. This is also used to identify ** appendable segments. */ rc = fts3WriteSegment(p, pWriter->iEnd, 0, 0); if( rc!=SQLITE_OK ) return rc; pWriter->iAbsLevel = iAbsLevel; pWriter->nLeafEst = nLeafEst; pWriter->iIdx = iIdx; /* Set up the array of NodeWriter objects */ for(i=0; iaNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst; } return SQLITE_OK; } /* ** Remove an entry from the %_segdir table. This involves running the ** following two statements: ** ** DELETE FROM %_segdir WHERE level = :iAbsLevel AND idx = :iIdx ** UPDATE %_segdir SET idx = idx - 1 WHERE level = :iAbsLevel AND idx > :iIdx ** ** The DELETE statement removes the specific %_segdir level. The UPDATE ** statement ensures that the remaining segments have contiguously allocated ** idx values. */ static int fts3RemoveSegdirEntry( Fts3Table *p, /* FTS3 table handle */ sqlite3_int64 iAbsLevel, /* Absolute level to delete from */ int iIdx /* Index of %_segdir entry to delete */ ){ int rc; /* Return code */ sqlite3_stmt *pDelete = 0; /* DELETE statement */ rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_ENTRY, &pDelete, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pDelete, 1, iAbsLevel); sqlite3_bind_int(pDelete, 2, iIdx); sqlite3_step(pDelete); rc = sqlite3_reset(pDelete); } return rc; } /* ** One or more segments have just been removed from absolute level iAbsLevel. ** Update the 'idx' values of the remaining segments in the level so that ** the idx values are a contiguous sequence starting from 0. */ static int fts3RepackSegdirLevel( Fts3Table *p, /* FTS3 table handle */ sqlite3_int64 iAbsLevel /* Absolute level to repack */ ){ int rc; /* Return code */ int *aIdx = 0; /* Array of remaining idx values */ int nIdx = 0; /* Valid entries in aIdx[] */ int nAlloc = 0; /* Allocated size of aIdx[] */ int i; /* Iterator variable */ sqlite3_stmt *pSelect = 0; /* Select statement to read idx values */ sqlite3_stmt *pUpdate = 0; /* Update statement to modify idx values */ rc = fts3SqlStmt(p, SQL_SELECT_INDEXES, &pSelect, 0); if( rc==SQLITE_OK ){ int rc2; sqlite3_bind_int64(pSelect, 1, iAbsLevel); while( SQLITE_ROW==sqlite3_step(pSelect) ){ if( nIdx>=nAlloc ){ int *aNew; nAlloc += 16; aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int)); if( !aNew ){ rc = SQLITE_NOMEM; break; } aIdx = aNew; } aIdx[nIdx++] = sqlite3_column_int(pSelect, 0); } rc2 = sqlite3_reset(pSelect); if( rc==SQLITE_OK ) rc = rc2; } if( rc==SQLITE_OK ){ rc = fts3SqlStmt(p, SQL_SHIFT_SEGDIR_ENTRY, &pUpdate, 0); } if( rc==SQLITE_OK ){ sqlite3_bind_int64(pUpdate, 2, iAbsLevel); } assert( p->bIgnoreSavepoint==0 ); p->bIgnoreSavepoint = 1; for(i=0; rc==SQLITE_OK && ibIgnoreSavepoint = 0; sqlite3_free(aIdx); return rc; } static void fts3StartNode(Blob *pNode, int iHeight, sqlite3_int64 iChild){ pNode->a[0] = (char)iHeight; if( iChild ){ assert( pNode->nAlloc>=1+sqlite3Fts3VarintLen(iChild) ); pNode->n = 1 + sqlite3Fts3PutVarint(&pNode->a[1], iChild); }else{ assert( pNode->nAlloc>=1 ); pNode->n = 1; } } /* ** The first two arguments are a pointer to and the size of a segment b-tree ** node. The node may be a leaf or an internal node. ** ** This function creates a new node image in blob object *pNew by copying ** all terms that are greater than or equal to zTerm/nTerm (for leaf nodes) ** or greater than zTerm/nTerm (for internal nodes) from aNode/nNode. */ static int fts3TruncateNode( const char *aNode, /* Current node image */ int nNode, /* Size of aNode in bytes */ Blob *pNew, /* OUT: Write new node image here */ const char *zTerm, /* Omit all terms smaller than this */ int nTerm, /* Size of zTerm in bytes */ sqlite3_int64 *piBlock /* OUT: Block number in next layer down */ ){ NodeReader reader; /* Reader object */ Blob prev = {0, 0, 0}; /* Previous term written to new node */ int rc = SQLITE_OK; /* Return code */ int bLeaf; /* True for a leaf node */ if( nNode<1 ) return FTS_CORRUPT_VTAB; bLeaf = aNode[0]=='\0'; /* Allocate required output space */ blobGrowBuffer(pNew, nNode, &rc); if( rc!=SQLITE_OK ) return rc; pNew->n = 0; /* Populate new node buffer */ for(rc = nodeReaderInit(&reader, aNode, nNode); rc==SQLITE_OK && reader.aNode; rc = nodeReaderNext(&reader) ){ if( pNew->n==0 ){ int res = fts3TermCmp(reader.term.a, reader.term.n, zTerm, nTerm); if( res<0 || (bLeaf==0 && res==0) ) continue; fts3StartNode(pNew, (int)aNode[0], reader.iChild); *piBlock = reader.iChild; } rc = fts3AppendToNode( pNew, &prev, reader.term.a, reader.term.n, reader.aDoclist, reader.nDoclist ); if( rc!=SQLITE_OK ) break; } if( pNew->n==0 ){ fts3StartNode(pNew, (int)aNode[0], reader.iChild); *piBlock = reader.iChild; } assert( pNew->n<=pNew->nAlloc ); nodeReaderRelease(&reader); sqlite3_free(prev.a); return rc; } /* ** Remove all terms smaller than zTerm/nTerm from segment iIdx in absolute ** level iAbsLevel. This may involve deleting entries from the %_segments ** table, and modifying existing entries in both the %_segments and %_segdir ** tables. ** ** SQLITE_OK is returned if the segment is updated successfully. Or an ** SQLite error code otherwise. */ static int fts3TruncateSegment( Fts3Table *p, /* FTS3 table handle */ sqlite3_int64 iAbsLevel, /* Absolute level of segment to modify */ int iIdx, /* Index within level of segment to modify */ const char *zTerm, /* Remove terms smaller than this */ int nTerm /* Number of bytes in buffer zTerm */ ){ int rc = SQLITE_OK; /* Return code */ Blob root = {0,0,0}; /* New root page image */ Blob block = {0,0,0}; /* Buffer used for any other block */ sqlite3_int64 iBlock = 0; /* Block id */ sqlite3_int64 iNewStart = 0; /* New value for iStartBlock */ sqlite3_int64 iOldStart = 0; /* Old value for iStartBlock */ sqlite3_stmt *pFetch = 0; /* Statement used to fetch segdir */ rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pFetch, 0); if( rc==SQLITE_OK ){ int rc2; /* sqlite3_reset() return code */ sqlite3_bind_int64(pFetch, 1, iAbsLevel); sqlite3_bind_int(pFetch, 2, iIdx); if( SQLITE_ROW==sqlite3_step(pFetch) ){ const char *aRoot = sqlite3_column_blob(pFetch, 4); int nRoot = sqlite3_column_bytes(pFetch, 4); iOldStart = sqlite3_column_int64(pFetch, 1); rc = fts3TruncateNode(aRoot, nRoot, &root, zTerm, nTerm, &iBlock); } rc2 = sqlite3_reset(pFetch); if( rc==SQLITE_OK ) rc = rc2; } while( rc==SQLITE_OK && iBlock ){ char *aBlock = 0; int nBlock = 0; iNewStart = iBlock; rc = sqlite3Fts3ReadBlock(p, iBlock, &aBlock, &nBlock, 0); if( rc==SQLITE_OK ){ rc = fts3TruncateNode(aBlock, nBlock, &block, zTerm, nTerm, &iBlock); } if( rc==SQLITE_OK ){ rc = fts3WriteSegment(p, iNewStart, block.a, block.n); } sqlite3_free(aBlock); } /* Variable iNewStart now contains the first valid leaf node. */ if( rc==SQLITE_OK && iNewStart ){ sqlite3_stmt *pDel = 0; rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDel, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pDel, 1, iOldStart); sqlite3_bind_int64(pDel, 2, iNewStart-1); sqlite3_step(pDel); rc = sqlite3_reset(pDel); } } if( rc==SQLITE_OK ){ sqlite3_stmt *pChomp = 0; rc = fts3SqlStmt(p, SQL_CHOMP_SEGDIR, &pChomp, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pChomp, 1, iNewStart); sqlite3_bind_blob(pChomp, 2, root.a, root.n, SQLITE_STATIC); sqlite3_bind_int64(pChomp, 3, iAbsLevel); sqlite3_bind_int(pChomp, 4, iIdx); sqlite3_step(pChomp); rc = sqlite3_reset(pChomp); sqlite3_bind_null(pChomp, 2); } } sqlite3_free(root.a); sqlite3_free(block.a); return rc; } /* ** This function is called after an incrmental-merge operation has run to ** merge (or partially merge) two or more segments from absolute level ** iAbsLevel. ** ** Each input segment is either removed from the db completely (if all of ** its data was copied to the output segment by the incrmerge operation) ** or modified in place so that it no longer contains those entries that ** have been duplicated in the output segment. */ static int fts3IncrmergeChomp( Fts3Table *p, /* FTS table handle */ sqlite3_int64 iAbsLevel, /* Absolute level containing segments */ Fts3MultiSegReader *pCsr, /* Chomp all segments opened by this cursor */ int *pnRem /* Number of segments not deleted */ ){ int i; int nRem = 0; int rc = SQLITE_OK; for(i=pCsr->nSegment-1; i>=0 && rc==SQLITE_OK; i--){ Fts3SegReader *pSeg = 0; int j; /* Find the Fts3SegReader object with Fts3SegReader.iIdx==i. It is hiding ** somewhere in the pCsr->apSegment[] array. */ for(j=0; ALWAYS(jnSegment); j++){ pSeg = pCsr->apSegment[j]; if( pSeg->iIdx==i ) break; } assert( jnSegment && pSeg->iIdx==i ); if( pSeg->aNode==0 ){ /* Seg-reader is at EOF. Remove the entire input segment. */ rc = fts3DeleteSegment(p, pSeg); if( rc==SQLITE_OK ){ rc = fts3RemoveSegdirEntry(p, iAbsLevel, pSeg->iIdx); } *pnRem = 0; }else{ /* The incremental merge did not copy all the data from this ** segment to the upper level. The segment is modified in place ** so that it contains no keys smaller than zTerm/nTerm. */ const char *zTerm = pSeg->zTerm; int nTerm = pSeg->nTerm; rc = fts3TruncateSegment(p, iAbsLevel, pSeg->iIdx, zTerm, nTerm); nRem++; } } if( rc==SQLITE_OK && nRem!=pCsr->nSegment ){ rc = fts3RepackSegdirLevel(p, iAbsLevel); } *pnRem = nRem; return rc; } /* ** Store an incr-merge hint in the database. */ static int fts3IncrmergeHintStore(Fts3Table *p, Blob *pHint){ sqlite3_stmt *pReplace = 0; int rc; /* Return code */ rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pReplace, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int(pReplace, 1, FTS_STAT_INCRMERGEHINT); sqlite3_bind_blob(pReplace, 2, pHint->a, pHint->n, SQLITE_STATIC); sqlite3_step(pReplace); rc = sqlite3_reset(pReplace); sqlite3_bind_null(pReplace, 2); } return rc; } /* ** Load an incr-merge hint from the database. The incr-merge hint, if one ** exists, is stored in the rowid==1 row of the %_stat table. ** ** If successful, populate blob *pHint with the value read from the %_stat ** table and return SQLITE_OK. Otherwise, if an error occurs, return an ** SQLite error code. */ static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){ sqlite3_stmt *pSelect = 0; int rc; pHint->n = 0; rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pSelect, 0); if( rc==SQLITE_OK ){ int rc2; sqlite3_bind_int(pSelect, 1, FTS_STAT_INCRMERGEHINT); if( SQLITE_ROW==sqlite3_step(pSelect) ){ const char *aHint = sqlite3_column_blob(pSelect, 0); int nHint = sqlite3_column_bytes(pSelect, 0); if( aHint ){ blobGrowBuffer(pHint, nHint, &rc); if( rc==SQLITE_OK ){ if( ALWAYS(pHint->a!=0) ) memcpy(pHint->a, aHint, nHint); pHint->n = nHint; } } } rc2 = sqlite3_reset(pSelect); if( rc==SQLITE_OK ) rc = rc2; } return rc; } /* ** If *pRc is not SQLITE_OK when this function is called, it is a no-op. ** Otherwise, append an entry to the hint stored in blob *pHint. Each entry ** consists of two varints, the absolute level number of the input segments ** and the number of input segments. ** ** If successful, leave *pRc set to SQLITE_OK and return. If an error occurs, ** set *pRc to an SQLite error code before returning. */ static void fts3IncrmergeHintPush( Blob *pHint, /* Hint blob to append to */ i64 iAbsLevel, /* First varint to store in hint */ int nInput, /* Second varint to store in hint */ int *pRc /* IN/OUT: Error code */ ){ blobGrowBuffer(pHint, pHint->n + 2*FTS3_VARINT_MAX, pRc); if( *pRc==SQLITE_OK ){ pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], iAbsLevel); pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], (i64)nInput); } } /* ** Read the last entry (most recently pushed) from the hint blob *pHint ** and then remove the entry. Write the two values read to *piAbsLevel and ** *pnInput before returning. ** ** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does ** not contain at least two valid varints, return SQLITE_CORRUPT_VTAB. */ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){ const int nHint = pHint->n; int i; i = pHint->n-1; if( (pHint->a[i] & 0x80) ) return FTS_CORRUPT_VTAB; while( i>0 && (pHint->a[i-1] & 0x80) ) i--; if( i==0 ) return FTS_CORRUPT_VTAB; i--; while( i>0 && (pHint->a[i-1] & 0x80) ) i--; pHint->n = i; i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel); i += fts3GetVarint32(&pHint->a[i], pnInput); assert( i<=nHint ); if( i!=nHint ) return FTS_CORRUPT_VTAB; return SQLITE_OK; } /* ** Attempt an incremental merge that writes nMerge leaf blocks. ** ** Incremental merges happen nMin segments at a time. The segments ** to be merged are the nMin oldest segments (the ones with the smallest ** values for the _segdir.idx field) in the highest level that contains ** at least nMin segments. Multiple merges might occur in an attempt to ** write the quota of nMerge leaf blocks. */ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ int rc; /* Return code */ int nRem = nMerge; /* Number of leaf pages yet to be written */ Fts3MultiSegReader *pCsr; /* Cursor used to read input data */ Fts3SegFilter *pFilter; /* Filter used with cursor pCsr */ IncrmergeWriter *pWriter; /* Writer object */ int nSeg = 0; /* Number of input segments */ sqlite3_int64 iAbsLevel = 0; /* Absolute level number to work on */ Blob hint = {0, 0, 0}; /* Hint read from %_stat table */ int bDirtyHint = 0; /* True if blob 'hint' has been modified */ /* Allocate space for the cursor, filter and writer objects */ const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter); pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc); if( !pWriter ) return SQLITE_NOMEM; pFilter = (Fts3SegFilter *)&pWriter[1]; pCsr = (Fts3MultiSegReader *)&pFilter[1]; rc = fts3IncrmergeHintLoad(p, &hint); while( rc==SQLITE_OK && nRem>0 ){ const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex; sqlite3_stmt *pFindLevel = 0; /* SQL used to determine iAbsLevel */ int bUseHint = 0; /* True if attempting to append */ int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */ /* Search the %_segdir table for the absolute level with the smallest ** relative level number that contains at least nMin segments, if any. ** If one is found, set iAbsLevel to the absolute level number and ** nSeg to nMin. If no level with at least nMin segments can be found, ** set nSeg to -1. */ rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0); sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin)); if( sqlite3_step(pFindLevel)==SQLITE_ROW ){ iAbsLevel = sqlite3_column_int64(pFindLevel, 0); nSeg = sqlite3_column_int(pFindLevel, 1); assert( nSeg>=2 ); }else{ nSeg = -1; } rc = sqlite3_reset(pFindLevel); /* If the hint read from the %_stat table is not empty, check if the ** last entry in it specifies a relative level smaller than or equal ** to the level identified by the block above (if any). If so, this ** iteration of the loop will work on merging at the hinted level. */ if( rc==SQLITE_OK && hint.n ){ int nHint = hint.n; sqlite3_int64 iHintAbsLevel = 0; /* Hint level */ int nHintSeg = 0; /* Hint number of segments */ rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg); if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){ /* Based on the scan in the block above, it is known that there ** are no levels with a relative level smaller than that of ** iAbsLevel with more than nSeg segments, or if nSeg is -1, ** no levels with more than nMin segments. Use this to limit the ** value of nHintSeg to avoid a large memory allocation in case the ** merge-hint is corrupt*/ iAbsLevel = iHintAbsLevel; nSeg = MIN(MAX(nMin,nSeg), nHintSeg); bUseHint = 1; bDirtyHint = 1; }else{ /* This undoes the effect of the HintPop() above - so that no entry ** is removed from the hint blob. */ hint.n = nHint; } } /* If nSeg is less that zero, then there is no level with at least ** nMin segments and no hint in the %_stat table. No work to do. ** Exit early in this case. */ if( nSeg<=0 ) break; assert( nMod<=0x7FFFFFFF ); if( iAbsLevel<0 || iAbsLevel>(nMod<<32) ){ rc = FTS_CORRUPT_VTAB; break; } /* Open a cursor to iterate through the contents of the oldest nSeg ** indexes of absolute level iAbsLevel. If this cursor is opened using ** the 'hint' parameters, it is possible that there are less than nSeg ** segments available in level iAbsLevel. In this case, no work is ** done on iAbsLevel - fall through to the next iteration of the loop ** to start work on some other level. */ memset(pWriter, 0, nAlloc); pFilter->flags = FTS3_SEGMENT_REQUIRE_POS; if( rc==SQLITE_OK ){ rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx); assert( bUseHint==1 || bUseHint==0 ); if( iIdx==0 || (bUseHint && iIdx==1) ){ int bIgnore = 0; rc = fts3SegmentIsMaxLevel(p, iAbsLevel+1, &bIgnore); if( bIgnore ){ pFilter->flags |= FTS3_SEGMENT_IGNORE_EMPTY; } } } if( rc==SQLITE_OK ){ rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr); } if( SQLITE_OK==rc && pCsr->nSegment==nSeg && SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter)) ){ int bEmpty = 0; rc = sqlite3Fts3SegReaderStep(p, pCsr); if( rc==SQLITE_OK ){ bEmpty = 1; }else if( rc!=SQLITE_ROW ){ sqlite3Fts3SegReaderFinish(pCsr); break; } if( bUseHint && iIdx>0 ){ const char *zKey = pCsr->zTerm; int nKey = pCsr->nTerm; rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); }else{ rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); } if( rc==SQLITE_OK && pWriter->nLeafEst ){ fts3LogMerge(nSeg, iAbsLevel); if( bEmpty==0 ){ do { rc = fts3IncrmergeAppend(p, pWriter, pCsr); if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr); if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK; }while( rc==SQLITE_ROW ); } /* Update or delete the input segments */ if( rc==SQLITE_OK ){ nRem -= (1 + pWriter->nWork); rc = fts3IncrmergeChomp(p, iAbsLevel, pCsr, &nSeg); if( nSeg!=0 ){ bDirtyHint = 1; fts3IncrmergeHintPush(&hint, iAbsLevel, nSeg, &rc); } } } if( nSeg!=0 ){ pWriter->nLeafData = pWriter->nLeafData * -1; } fts3IncrmergeRelease(p, pWriter, &rc); if( nSeg==0 && pWriter->bNoLeafData==0 ){ fts3PromoteSegments(p, iAbsLevel+1, pWriter->nLeafData); } } sqlite3Fts3SegReaderFinish(pCsr); } /* Write the hint values into the %_stat table for the next incr-merger */ if( bDirtyHint && rc==SQLITE_OK ){ rc = fts3IncrmergeHintStore(p, &hint); } sqlite3_free(pWriter); sqlite3_free(hint.a); return rc; } /* ** Convert the text beginning at *pz into an integer and return ** its value. Advance *pz to point to the first character past ** the integer. ** ** This function used for parameters to merge= and incrmerge= ** commands. */ static int fts3Getint(const char **pz){ const char *z = *pz; int i = 0; while( (*z)>='0' && (*z)<='9' && i<214748363 ) i = 10*i + *(z++) - '0'; *pz = z; return i; } /* ** Process statements of the form: ** ** INSERT INTO table(table) VALUES('merge=A,B'); ** ** A and B are integers that decode to be the number of leaf pages ** written for the merge, and the minimum number of segments on a level ** before it will be selected for a merge, respectively. */ static int fts3DoIncrmerge( Fts3Table *p, /* FTS3 table handle */ const char *zParam /* Nul-terminated string containing "A,B" */ ){ int rc; int nMin = (MergeCount(p) / 2); int nMerge = 0; const char *z = zParam; /* Read the first integer value */ nMerge = fts3Getint(&z); /* If the first integer value is followed by a ',', read the second ** integer value. */ if( z[0]==',' && z[1]!='\0' ){ z++; nMin = fts3Getint(&z); } if( z[0]!='\0' || nMin<2 ){ rc = SQLITE_ERROR; }else{ rc = SQLITE_OK; if( !p->bHasStat ){ assert( p->bFts4==0 ); sqlite3Fts3CreateStatTable(&rc, p); } if( rc==SQLITE_OK ){ rc = sqlite3Fts3Incrmerge(p, nMerge, nMin); } sqlite3Fts3SegmentsClose(p); } return rc; } /* ** Process statements of the form: ** ** INSERT INTO table(table) VALUES('automerge=X'); ** ** where X is an integer. X==0 means to turn automerge off. X!=0 means ** turn it on. The setting is persistent. */ static int fts3DoAutoincrmerge( Fts3Table *p, /* FTS3 table handle */ const char *zParam /* Nul-terminated string containing boolean */ ){ int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; p->nAutoincrmerge = fts3Getint(&zParam); if( p->nAutoincrmerge==1 || p->nAutoincrmerge>MergeCount(p) ){ p->nAutoincrmerge = 8; } if( !p->bHasStat ){ assert( p->bFts4==0 ); sqlite3Fts3CreateStatTable(&rc, p); if( rc ) return rc; } rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); if( rc ) return rc; sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); sqlite3_bind_int(pStmt, 2, p->nAutoincrmerge); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); return rc; } /* ** Return a 64-bit checksum for the FTS index entry specified by the ** arguments to this function. */ static u64 fts3ChecksumEntry( const char *zTerm, /* Pointer to buffer containing term */ int nTerm, /* Size of zTerm in bytes */ int iLangid, /* Language id for current row */ int iIndex, /* Index (0..Fts3Table.nIndex-1) */ i64 iDocid, /* Docid for current row. */ int iCol, /* Column number */ int iPos /* Position */ ){ int i; u64 ret = (u64)iDocid; ret += (ret<<3) + iLangid; ret += (ret<<3) + iIndex; ret += (ret<<3) + iCol; ret += (ret<<3) + iPos; for(i=0; inIndex-1) */ int *pRc /* OUT: Return code */ ){ Fts3SegFilter filter; Fts3MultiSegReader csr; int rc; u64 cksum = 0; if( *pRc ) return 0; memset(&filter, 0, sizeof(filter)); memset(&csr, 0, sizeof(csr)); filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; filter.flags |= FTS3_SEGMENT_SCAN; rc = sqlite3Fts3SegReaderCursor( p, iLangid, iIndex, FTS3_SEGCURSOR_ALL, 0, 0, 0, 1,&csr ); if( rc==SQLITE_OK ){ rc = sqlite3Fts3SegReaderStart(p, &csr, &filter); } if( rc==SQLITE_OK ){ while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){ char *pCsr = csr.aDoclist; char *pEnd = &pCsr[csr.nDoclist]; i64 iDocid = 0; i64 iCol = 0; u64 iPos = 0; pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid); while( pCsrbDescIdx ){ iDocid = (i64)((u64)iDocid - iVal); }else{ iDocid = (i64)((u64)iDocid + iVal); } } }else{ iPos += (iVal - 2); cksum = cksum ^ fts3ChecksumEntry( csr.zTerm, csr.nTerm, iLangid, iIndex, iDocid, (int)iCol, (int)iPos ); } } } } } sqlite3Fts3SegReaderFinish(&csr); *pRc = rc; return cksum; } /* ** Check if the contents of the FTS index match the current contents of the ** content table. If no error occurs and the contents do match, set *pbOk ** to true and return SQLITE_OK. Or if the contents do not match, set *pbOk ** to false before returning. ** ** If an error occurs (e.g. an OOM or IO error), return an SQLite error ** code. The final value of *pbOk is undefined in this case. */ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ int rc = SQLITE_OK; /* Return code */ u64 cksum1 = 0; /* Checksum based on FTS index contents */ u64 cksum2 = 0; /* Checksum based on %_content contents */ sqlite3_stmt *pAllLangid = 0; /* Statement to return all language-ids */ /* This block calculates the checksum according to the FTS index. */ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); if( rc==SQLITE_OK ){ int rc2; sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid); sqlite3_bind_int(pAllLangid, 2, p->nIndex); while( rc==SQLITE_OK && sqlite3_step(pAllLangid)==SQLITE_ROW ){ int iLangid = sqlite3_column_int(pAllLangid, 0); int i; for(i=0; inIndex; i++){ cksum1 = cksum1 ^ fts3ChecksumIndex(p, iLangid, i, &rc); } } rc2 = sqlite3_reset(pAllLangid); if( rc==SQLITE_OK ) rc = rc2; } /* This block calculates the checksum according to the %_content table */ if( rc==SQLITE_OK ){ sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule; sqlite3_stmt *pStmt = 0; char *zSql; zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); if( !zSql ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ i64 iDocid = sqlite3_column_int64(pStmt, 0); int iLang = langidFromSelect(p, pStmt); int iCol; for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ if( p->abNotindexed[iCol]==0 ){ const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1); sqlite3_tokenizer_cursor *pT = 0; rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, -1, &pT); while( rc==SQLITE_OK ){ char const *zToken; /* Buffer containing token */ int nToken = 0; /* Number of bytes in token */ int iDum1 = 0, iDum2 = 0; /* Dummy variables */ int iPos = 0; /* Position of token in zText */ rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos); if( rc==SQLITE_OK ){ int i; cksum2 = cksum2 ^ fts3ChecksumEntry( zToken, nToken, iLang, 0, iDocid, iCol, iPos ); for(i=1; inIndex; i++){ if( p->aIndex[i].nPrefix<=nToken ){ cksum2 = cksum2 ^ fts3ChecksumEntry( zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos ); } } } } if( pT ) pModule->xClose(pT); if( rc==SQLITE_DONE ) rc = SQLITE_OK; } } } sqlite3_finalize(pStmt); } *pbOk = (rc==SQLITE_OK && cksum1==cksum2); return rc; } /* ** Run the integrity-check. If no error occurs and the current contents of ** the FTS index are correct, return SQLITE_OK. Or, if the contents of the ** FTS index are incorrect, return SQLITE_CORRUPT_VTAB. ** ** Or, if an error (e.g. an OOM or IO error) occurs, return an SQLite ** error code. ** ** The integrity-check works as follows. For each token and indexed token ** prefix in the document set, a 64-bit checksum is calculated (by code ** in fts3ChecksumEntry()) based on the following: ** ** + The index number (0 for the main index, 1 for the first prefix ** index etc.), ** + The token (or token prefix) text itself, ** + The language-id of the row it appears in, ** + The docid of the row it appears in, ** + The column it appears in, and ** + The tokens position within that column. ** ** The checksums for all entries in the index are XORed together to create ** a single checksum for the entire index. ** ** The integrity-check code calculates the same checksum in two ways: ** ** 1. By scanning the contents of the FTS index, and ** 2. By scanning and tokenizing the content table. ** ** If the two checksums are identical, the integrity-check is deemed to have ** passed. */ static int fts3DoIntegrityCheck( Fts3Table *p /* FTS3 table handle */ ){ int rc; int bOk = 0; rc = sqlite3Fts3IntegrityCheck(p, &bOk); if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB; return rc; } /* ** Handle a 'special' INSERT of the form: ** ** "INSERT INTO tbl(tbl) VALUES()" ** ** Argument pVal contains the result of . Currently the only ** meaningful value to insert is the text 'optimize'. */ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ int rc = SQLITE_ERROR; /* Return Code */ const char *zVal = (const char *)sqlite3_value_text(pVal); int nVal = sqlite3_value_bytes(pVal); if( !zVal ){ return SQLITE_NOMEM; }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){ rc = fts3DoOptimize(p, 0); }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){ rc = fts3DoRebuild(p); }else if( nVal==15 && 0==sqlite3_strnicmp(zVal, "integrity-check", 15) ){ rc = fts3DoIntegrityCheck(p); }else if( nVal>6 && 0==sqlite3_strnicmp(zVal, "merge=", 6) ){ rc = fts3DoIncrmerge(p, &zVal[6]); }else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){ rc = fts3DoAutoincrmerge(p, &zVal[10]); }else if( nVal==5 && 0==sqlite3_strnicmp(zVal, "flush", 5) ){ rc = sqlite3Fts3PendingTermsFlush(p); } #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) else{ int v; if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ v = atoi(&zVal[9]); if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v; rc = SQLITE_OK; }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){ v = atoi(&zVal[11]); if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v; rc = SQLITE_OK; }else if( nVal>21 && 0==sqlite3_strnicmp(zVal,"test-no-incr-doclist=",21) ){ p->bNoIncrDoclist = atoi(&zVal[21]); rc = SQLITE_OK; }else if( nVal>11 && 0==sqlite3_strnicmp(zVal,"mergecount=",11) ){ v = atoi(&zVal[11]); if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v; rc = SQLITE_OK; } } #endif return rc; } #ifndef SQLITE_DISABLE_FTS4_DEFERRED /* ** Delete all cached deferred doclists. Deferred doclists are cached ** (allocated) by the sqlite3Fts3CacheDeferredDoclists() function. */ SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){ Fts3DeferredToken *pDef; for(pDef=pCsr->pDeferred; pDef; pDef=pDef->pNext){ fts3PendingListDelete(pDef->pList); pDef->pList = 0; } } /* ** Free all entries in the pCsr->pDeffered list. Entries are added to ** this list using sqlite3Fts3DeferToken(). */ SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){ Fts3DeferredToken *pDef; Fts3DeferredToken *pNext; for(pDef=pCsr->pDeferred; pDef; pDef=pNext){ pNext = pDef->pNext; fts3PendingListDelete(pDef->pList); sqlite3_free(pDef); } pCsr->pDeferred = 0; } /* ** Generate deferred-doclists for all tokens in the pCsr->pDeferred list ** based on the row that pCsr currently points to. ** ** A deferred-doclist is like any other doclist with position information ** included, except that it only contains entries for a single row of the ** table, not for all rows. */ SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){ int rc = SQLITE_OK; /* Return code */ if( pCsr->pDeferred ){ int i; /* Used to iterate through table columns */ sqlite3_int64 iDocid; /* Docid of the row pCsr points to */ Fts3DeferredToken *pDef; /* Used to iterate through deferred tokens */ Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; sqlite3_tokenizer *pT = p->pTokenizer; sqlite3_tokenizer_module const *pModule = pT->pModule; assert( pCsr->isRequireSeek==0 ); iDocid = sqlite3_column_int64(pCsr->pStmt, 0); for(i=0; inColumn && rc==SQLITE_OK; i++){ if( p->abNotindexed[i]==0 ){ const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1); sqlite3_tokenizer_cursor *pTC = 0; rc = sqlite3Fts3OpenTokenizer(pT, pCsr->iLangid, zText, -1, &pTC); while( rc==SQLITE_OK ){ char const *zToken; /* Buffer containing token */ int nToken = 0; /* Number of bytes in token */ int iDum1 = 0, iDum2 = 0; /* Dummy variables */ int iPos = 0; /* Position of token in zText */ rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos); for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ Fts3PhraseToken *pPT = pDef->pToken; if( (pDef->iCol>=p->nColumn || pDef->iCol==i) && (pPT->bFirst==0 || iPos==0) && (pPT->n==nToken || (pPT->isPrefix && pPT->nz, pPT->n)) ){ fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc); } } } if( pTC ) pModule->xClose(pTC); if( rc==SQLITE_DONE ) rc = SQLITE_OK; } } for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ if( pDef->pList ){ rc = fts3PendingListAppendVarint(&pDef->pList, 0); } } } return rc; } SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList( Fts3DeferredToken *p, char **ppData, int *pnData ){ char *pRet; int nSkip; sqlite3_int64 dummy; *ppData = 0; *pnData = 0; if( p->pList==0 ){ return SQLITE_OK; } pRet = (char *)sqlite3_malloc64(p->pList->nData); if( !pRet ) return SQLITE_NOMEM; nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy); *pnData = p->pList->nData - nSkip; *ppData = pRet; memcpy(pRet, &p->pList->aData[nSkip], *pnData); return SQLITE_OK; } /* ** Add an entry for token pToken to the pCsr->pDeferred list. */ SQLITE_PRIVATE int sqlite3Fts3DeferToken( Fts3Cursor *pCsr, /* Fts3 table cursor */ Fts3PhraseToken *pToken, /* Token to defer */ int iCol /* Column that token must appear in (or -1) */ ){ Fts3DeferredToken *pDeferred; pDeferred = sqlite3_malloc64(sizeof(*pDeferred)); if( !pDeferred ){ return SQLITE_NOMEM; } memset(pDeferred, 0, sizeof(*pDeferred)); pDeferred->pToken = pToken; pDeferred->pNext = pCsr->pDeferred; pDeferred->iCol = iCol; pCsr->pDeferred = pDeferred; assert( pToken->pDeferred==0 ); pToken->pDeferred = pDeferred; return SQLITE_OK; } #endif /* ** SQLite value pRowid contains the rowid of a row that may or may not be ** present in the FTS3 table. If it is, delete it and adjust the contents ** of subsiduary data structures accordingly. */ static int fts3DeleteByRowid( Fts3Table *p, sqlite3_value *pRowid, int *pnChng, /* IN/OUT: Decrement if row is deleted */ u32 *aSzDel ){ int rc = SQLITE_OK; /* Return code */ int bFound = 0; /* True if *pRowid really is in the table */ fts3DeleteTerms(&rc, p, pRowid, aSzDel, &bFound); if( bFound && rc==SQLITE_OK ){ int isEmpty = 0; /* Deleting *pRowid leaves the table empty */ rc = fts3IsEmpty(p, pRowid, &isEmpty); if( rc==SQLITE_OK ){ if( isEmpty ){ /* Deleting this row means the whole table is empty. In this case ** delete the contents of all three tables and throw away any ** data in the pendingTerms hash table. */ rc = fts3DeleteAll(p, 1); *pnChng = 0; memset(aSzDel, 0, sizeof(u32) * (p->nColumn+1) * 2); }else{ *pnChng = *pnChng - 1; if( p->zContentTbl==0 ){ fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); } if( p->bHasDocsize ){ fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); } } } } return rc; } /* ** This function does the work for the xUpdate method of FTS3 virtual ** tables. The schema of the virtual table being: ** ** CREATE TABLE
    ( ** , **
    HIDDEN, ** docid HIDDEN, ** HIDDEN ** ); ** ** */ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod( sqlite3_vtab *pVtab, /* FTS3 vtab object */ int nArg, /* Size of argument array */ sqlite3_value **apVal, /* Array of arguments */ sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ Fts3Table *p = (Fts3Table *)pVtab; int rc = SQLITE_OK; /* Return Code */ u32 *aSzIns = 0; /* Sizes of inserted documents */ u32 *aSzDel = 0; /* Sizes of deleted documents */ int nChng = 0; /* Net change in number of documents */ int bInsertDone = 0; /* At this point it must be known if the %_stat table exists or not. ** So bHasStat may not be 2. */ assert( p->bHasStat==0 || p->bHasStat==1 ); assert( p->pSegments==0 ); assert( nArg==1 /* DELETE operations */ || nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */ ); /* Check for a "special" INSERT operation. One of the form: ** ** INSERT INTO xyz(xyz) VALUES('command'); */ if( nArg>1 && sqlite3_value_type(apVal[0])==SQLITE_NULL && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL ){ rc = fts3SpecialInsert(p, apVal[p->nColumn+2]); goto update_out; } if( nArg>1 && sqlite3_value_int(apVal[2 + p->nColumn + 2])<0 ){ rc = SQLITE_CONSTRAINT; goto update_out; } /* Allocate space to hold the change in document sizes */ aSzDel = sqlite3_malloc64(sizeof(aSzDel[0])*((sqlite3_int64)p->nColumn+1)*2); if( aSzDel==0 ){ rc = SQLITE_NOMEM; goto update_out; } aSzIns = &aSzDel[p->nColumn+1]; memset(aSzDel, 0, sizeof(aSzDel[0])*(p->nColumn+1)*2); rc = fts3Writelock(p); if( rc!=SQLITE_OK ) goto update_out; /* If this is an INSERT operation, or an UPDATE that modifies the rowid ** value, then this operation requires constraint handling. ** ** If the on-conflict mode is REPLACE, this means that the existing row ** should be deleted from the database before inserting the new row. Or, ** if the on-conflict mode is other than REPLACE, then this method must ** detect the conflict and return SQLITE_CONSTRAINT before beginning to ** modify the database file. */ if( nArg>1 && p->zContentTbl==0 ){ /* Find the value object that holds the new rowid value. */ sqlite3_value *pNewRowid = apVal[3+p->nColumn]; if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ pNewRowid = apVal[1]; } if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( sqlite3_value_type(apVal[0])==SQLITE_NULL || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid) )){ /* The new rowid is not NULL (in this case the rowid will be ** automatically assigned and there is no chance of a conflict), and ** the statement is either an INSERT or an UPDATE that modifies the ** rowid column. So if the conflict mode is REPLACE, then delete any ** existing row with rowid=pNewRowid. ** ** Or, if the conflict mode is not REPLACE, insert the new record into ** the %_content table. If we hit the duplicate rowid constraint (or any ** other error) while doing so, return immediately. ** ** This branch may also run if pNewRowid contains a value that cannot ** be losslessly converted to an integer. In this case, the eventual ** call to fts3InsertData() (either just below or further on in this ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is ** invoked, it will delete zero rows (since no row will have ** docid=$pNewRowid if $pNewRowid is not an integer value). */ if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); }else{ rc = fts3InsertData(p, apVal, pRowid); bInsertDone = 1; } } } if( rc!=SQLITE_OK ){ goto update_out; } /* If this is a DELETE or UPDATE operation, remove the old record. */ if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); } /* If this is an INSERT or UPDATE operation, insert the new record. */ if( nArg>1 && rc==SQLITE_OK ){ int iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]); if( bInsertDone==0 ){ rc = fts3InsertData(p, apVal, pRowid); if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ rc = FTS_CORRUPT_VTAB; } } if( rc==SQLITE_OK ){ rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid); } if( rc==SQLITE_OK ){ assert( p->iPrevDocid==*pRowid ); rc = fts3InsertTerms(p, iLangid, apVal, aSzIns); } if( p->bHasDocsize ){ fts3InsertDocsize(&rc, p, aSzIns); } nChng++; } if( p->bFts4 ){ fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng); } update_out: sqlite3_free(aSzDel); sqlite3Fts3SegmentsClose(p); return rc; } /* ** Flush any data in the pending-terms hash table to disk. If successful, ** merge all segments in the database (including the new segment, if ** there was any data to flush) into a single segment. */ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){ int rc; rc = sqlite3_exec(p->db, "SAVEPOINT fts3", 0, 0, 0); if( rc==SQLITE_OK ){ rc = fts3DoOptimize(p, 1); if( rc==SQLITE_OK || rc==SQLITE_DONE ){ int rc2 = sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0); if( rc2!=SQLITE_OK ) rc = rc2; }else{ sqlite3_exec(p->db, "ROLLBACK TO fts3", 0, 0, 0); sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0); } } sqlite3Fts3SegmentsClose(p); return rc; } #endif /************** End of fts3_write.c ******************************************/ /************** Begin file fts3_snippet.c ************************************/ /* ** 2009 Oct 23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** */ /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include */ /* #include */ #ifndef SQLITE_AMALGAMATION typedef sqlite3_int64 i64; #endif /* ** Characters that may appear in the second argument to matchinfo(). */ #define FTS3_MATCHINFO_NPHRASE 'p' /* 1 value */ #define FTS3_MATCHINFO_NCOL 'c' /* 1 value */ #define FTS3_MATCHINFO_NDOC 'n' /* 1 value */ #define FTS3_MATCHINFO_AVGLENGTH 'a' /* nCol values */ #define FTS3_MATCHINFO_LENGTH 'l' /* nCol values */ #define FTS3_MATCHINFO_LCS 's' /* nCol values */ #define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */ #define FTS3_MATCHINFO_LHITS 'y' /* nCol*nPhrase values */ #define FTS3_MATCHINFO_LHITS_BM 'b' /* nCol*nPhrase values */ /* ** The default value for the second argument to matchinfo(). */ #define FTS3_MATCHINFO_DEFAULT "pcx" /* ** Used as an sqlite3Fts3ExprIterate() context when loading phrase doclists to ** Fts3Expr.aDoclist[]/nDoclist. */ typedef struct LoadDoclistCtx LoadDoclistCtx; struct LoadDoclistCtx { Fts3Cursor *pCsr; /* FTS3 Cursor */ int nPhrase; /* Number of phrases seen so far */ int nToken; /* Number of tokens seen so far */ }; /* ** The following types are used as part of the implementation of the ** fts3BestSnippet() routine. */ typedef struct SnippetIter SnippetIter; typedef struct SnippetPhrase SnippetPhrase; typedef struct SnippetFragment SnippetFragment; struct SnippetIter { Fts3Cursor *pCsr; /* Cursor snippet is being generated from */ int iCol; /* Extract snippet from this column */ int nSnippet; /* Requested snippet length (in tokens) */ int nPhrase; /* Number of phrases in query */ SnippetPhrase *aPhrase; /* Array of size nPhrase */ int iCurrent; /* First token of current snippet */ }; struct SnippetPhrase { int nToken; /* Number of tokens in phrase */ char *pList; /* Pointer to start of phrase position list */ i64 iHead; /* Next value in position list */ char *pHead; /* Position list data following iHead */ i64 iTail; /* Next value in trailing position list */ char *pTail; /* Position list data following iTail */ }; struct SnippetFragment { int iCol; /* Column snippet is extracted from */ int iPos; /* Index of first token in snippet */ u64 covered; /* Mask of query phrases covered */ u64 hlmask; /* Mask of snippet terms to highlight */ }; /* ** This type is used as an sqlite3Fts3ExprIterate() context object while ** accumulating the data returned by the matchinfo() function. */ typedef struct MatchInfo MatchInfo; struct MatchInfo { Fts3Cursor *pCursor; /* FTS3 Cursor */ int nCol; /* Number of columns in table */ int nPhrase; /* Number of matchable phrases in query */ sqlite3_int64 nDoc; /* Number of docs in database */ char flag; u32 *aMatchinfo; /* Pre-allocated buffer */ }; /* ** An instance of this structure is used to manage a pair of buffers, each ** (nElem * sizeof(u32)) bytes in size. See the MatchinfoBuffer code below ** for details. */ struct MatchinfoBuffer { u8 aRef[3]; int nElem; int bGlobal; /* Set if global data is loaded */ char *zMatchinfo; u32 aMatchinfo[1]; }; /* ** The snippet() and offsets() functions both return text values. An instance ** of the following structure is used to accumulate those values while the ** functions are running. See fts3StringAppend() for details. */ typedef struct StrBuffer StrBuffer; struct StrBuffer { char *z; /* Pointer to buffer containing string */ int n; /* Length of z in bytes (excl. nul-term) */ int nAlloc; /* Allocated size of buffer z in bytes */ }; /************************************************************************* ** Start of MatchinfoBuffer code. */ /* ** Allocate a two-slot MatchinfoBuffer object. */ static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ MatchinfoBuffer *pRet; sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1) + sizeof(MatchinfoBuffer); sqlite3_int64 nStr = strlen(zMatchinfo); pRet = sqlite3Fts3MallocZero(nByte + nStr+1); if( pRet ){ pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*((int)nElem+1); pRet->nElem = (int)nElem; pRet->zMatchinfo = ((char*)pRet) + nByte; memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1); pRet->aRef[0] = 1; } return pRet; } static void fts3MIBufferFree(void *p){ MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]); assert( (u32*)p==&pBuf->aMatchinfo[1] || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2] ); if( (u32*)p==&pBuf->aMatchinfo[1] ){ pBuf->aRef[1] = 0; }else{ pBuf->aRef[2] = 0; } if( pBuf->aRef[0]==0 && pBuf->aRef[1]==0 && pBuf->aRef[2]==0 ){ sqlite3_free(pBuf); } } static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ void (*xRet)(void*) = 0; u32 *aOut = 0; if( p->aRef[1]==0 ){ p->aRef[1] = 1; aOut = &p->aMatchinfo[1]; xRet = fts3MIBufferFree; } else if( p->aRef[2]==0 ){ p->aRef[2] = 1; aOut = &p->aMatchinfo[p->nElem+2]; xRet = fts3MIBufferFree; }else{ aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32)); if( aOut ){ xRet = sqlite3_free; if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32)); } } *paOut = aOut; return xRet; } static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){ p->bGlobal = 1; memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32)); } /* ** Free a MatchinfoBuffer object allocated using fts3MIBufferNew() */ SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){ if( p ){ assert( p->aRef[0]==1 ); p->aRef[0] = 0; if( p->aRef[0]==0 && p->aRef[1]==0 && p->aRef[2]==0 ){ sqlite3_free(p); } } } /* ** End of MatchinfoBuffer code. *************************************************************************/ /* ** This function is used to help iterate through a position-list. A position ** list is a list of unique integers, sorted from smallest to largest. Each ** element of the list is represented by an FTS3 varint that takes the value ** of the difference between the current element and the previous one plus ** two. For example, to store the position-list: ** ** 4 9 113 ** ** the three varints: ** ** 6 7 106 ** ** are encoded. ** ** When this function is called, *pp points to the start of an element of ** the list. *piPos contains the value of the previous entry in the list. ** After it returns, *piPos contains the value of the next element of the ** list and *pp is advanced to the following varint. */ static void fts3GetDeltaPosition(char **pp, i64 *piPos){ int iVal; *pp += fts3GetVarint32(*pp, &iVal); *piPos += (iVal-2); } /* ** Helper function for sqlite3Fts3ExprIterate() (see below). */ static int fts3ExprIterate2( Fts3Expr *pExpr, /* Expression to iterate phrases of */ int *piPhrase, /* Pointer to phrase counter */ int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */ void *pCtx /* Second argument to pass to callback */ ){ int rc; /* Return code */ int eType = pExpr->eType; /* Type of expression node pExpr */ if( eType!=FTSQUERY_PHRASE ){ assert( pExpr->pLeft && pExpr->pRight ); rc = fts3ExprIterate2(pExpr->pLeft, piPhrase, x, pCtx); if( rc==SQLITE_OK && eType!=FTSQUERY_NOT ){ rc = fts3ExprIterate2(pExpr->pRight, piPhrase, x, pCtx); } }else{ rc = x(pExpr, *piPhrase, pCtx); (*piPhrase)++; } return rc; } /* ** Iterate through all phrase nodes in an FTS3 query, except those that ** are part of a sub-tree that is the right-hand-side of a NOT operator. ** For each phrase node found, the supplied callback function is invoked. ** ** If the callback function returns anything other than SQLITE_OK, ** the iteration is abandoned and the error code returned immediately. ** Otherwise, SQLITE_OK is returned after a callback has been made for ** all eligible phrase nodes. */ SQLITE_PRIVATE int sqlite3Fts3ExprIterate( Fts3Expr *pExpr, /* Expression to iterate phrases of */ int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */ void *pCtx /* Second argument to pass to callback */ ){ int iPhrase = 0; /* Variable used as the phrase counter */ return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx); } /* ** This is an sqlite3Fts3ExprIterate() callback used while loading the ** doclists for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also ** fts3ExprLoadDoclists(). */ static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ int rc = SQLITE_OK; Fts3Phrase *pPhrase = pExpr->pPhrase; LoadDoclistCtx *p = (LoadDoclistCtx *)ctx; UNUSED_PARAMETER(iPhrase); p->nPhrase++; p->nToken += pPhrase->nToken; return rc; } /* ** Load the doclists for each phrase in the query associated with FTS3 cursor ** pCsr. ** ** If pnPhrase is not NULL, then *pnPhrase is set to the number of matchable ** phrases in the expression (all phrases except those directly or ** indirectly descended from the right-hand-side of a NOT operator). If ** pnToken is not NULL, then it is set to the number of tokens in all ** matchable phrases of the expression. */ static int fts3ExprLoadDoclists( Fts3Cursor *pCsr, /* Fts3 cursor for current query */ int *pnPhrase, /* OUT: Number of phrases in query */ int *pnToken /* OUT: Number of tokens in query */ ){ int rc; /* Return Code */ LoadDoclistCtx sCtx = {0,0,0}; /* Context for sqlite3Fts3ExprIterate() */ sCtx.pCsr = pCsr; rc = sqlite3Fts3ExprIterate(pCsr->pExpr,fts3ExprLoadDoclistsCb,(void*)&sCtx); if( pnPhrase ) *pnPhrase = sCtx.nPhrase; if( pnToken ) *pnToken = sCtx.nToken; return rc; } static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ (*(int *)ctx)++; pExpr->iPhrase = iPhrase; return SQLITE_OK; } static int fts3ExprPhraseCount(Fts3Expr *pExpr){ int nPhrase = 0; (void)sqlite3Fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase); return nPhrase; } /* ** Advance the position list iterator specified by the first two ** arguments so that it points to the first element with a value greater ** than or equal to parameter iNext. */ static void fts3SnippetAdvance(char **ppIter, i64 *piIter, int iNext){ char *pIter = *ppIter; if( pIter ){ i64 iIter = *piIter; while( iIteriCurrent<0 ){ /* The SnippetIter object has just been initialized. The first snippet ** candidate always starts at offset 0 (even if this candidate has a ** score of 0.0). */ pIter->iCurrent = 0; /* Advance the 'head' iterator of each phrase to the first offset that ** is greater than or equal to (iNext+nSnippet). */ for(i=0; inPhrase; i++){ SnippetPhrase *pPhrase = &pIter->aPhrase[i]; fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, pIter->nSnippet); } }else{ int iStart; int iEnd = 0x7FFFFFFF; for(i=0; inPhrase; i++){ SnippetPhrase *pPhrase = &pIter->aPhrase[i]; if( pPhrase->pHead && pPhrase->iHeadiHead; } } if( iEnd==0x7FFFFFFF ){ return 1; } pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1; for(i=0; inPhrase; i++){ SnippetPhrase *pPhrase = &pIter->aPhrase[i]; fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, iEnd+1); fts3SnippetAdvance(&pPhrase->pTail, &pPhrase->iTail, iStart); } } return 0; } /* ** Retrieve information about the current candidate snippet of snippet ** iterator pIter. */ static void fts3SnippetDetails( SnippetIter *pIter, /* Snippet iterator */ u64 mCovered, /* Bitmask of phrases already covered */ int *piToken, /* OUT: First token of proposed snippet */ int *piScore, /* OUT: "Score" for this snippet */ u64 *pmCover, /* OUT: Bitmask of phrases covered */ u64 *pmHighlight /* OUT: Bitmask of terms to highlight */ ){ int iStart = pIter->iCurrent; /* First token of snippet */ int iScore = 0; /* Score of this snippet */ int i; /* Loop counter */ u64 mCover = 0; /* Mask of phrases covered by this snippet */ u64 mHighlight = 0; /* Mask of tokens to highlight in snippet */ for(i=0; inPhrase; i++){ SnippetPhrase *pPhrase = &pIter->aPhrase[i]; if( pPhrase->pTail ){ char *pCsr = pPhrase->pTail; i64 iCsr = pPhrase->iTail; while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){ int j; u64 mPhrase = (u64)1 << (i%64); u64 mPos = (u64)1 << (iCsr - iStart); assert( iCsr>=iStart && (iCsr - iStart)<=64 ); assert( i>=0 ); if( (mCover|mCovered)&mPhrase ){ iScore++; }else{ iScore += 1000; } mCover |= mPhrase; for(j=0; jnToken; j++){ mHighlight |= (mPos>>j); } if( 0==(*pCsr & 0x0FE) ) break; fts3GetDeltaPosition(&pCsr, &iCsr); } } } /* Set the output variables before returning. */ *piToken = iStart; *piScore = iScore; *pmCover = mCover; *pmHighlight = mHighlight; } /* ** This function is an sqlite3Fts3ExprIterate() callback used by ** fts3BestSnippet(). Each invocation populates an element of the ** SnippetIter.aPhrase[] array. */ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){ SnippetIter *p = (SnippetIter *)ctx; SnippetPhrase *pPhrase = &p->aPhrase[iPhrase]; char *pCsr; int rc; pPhrase->nToken = pExpr->pPhrase->nToken; rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr); assert( rc==SQLITE_OK || pCsr==0 ); if( pCsr ){ i64 iFirst = 0; pPhrase->pList = pCsr; fts3GetDeltaPosition(&pCsr, &iFirst); if( iFirst<0 ){ rc = FTS_CORRUPT_VTAB; }else{ pPhrase->pHead = pCsr; pPhrase->pTail = pCsr; pPhrase->iHead = iFirst; pPhrase->iTail = iFirst; } }else{ assert( rc!=SQLITE_OK || ( pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 )); } return rc; } /* ** Select the fragment of text consisting of nFragment contiguous tokens ** from column iCol that represent the "best" snippet. The best snippet ** is the snippet with the highest score, where scores are calculated ** by adding: ** ** (a) +1 point for each occurrence of a matchable phrase in the snippet. ** ** (b) +1000 points for the first occurrence of each matchable phrase in ** the snippet for which the corresponding mCovered bit is not set. ** ** The selected snippet parameters are stored in structure *pFragment before ** returning. The score of the selected snippet is stored in *piScore ** before returning. */ static int fts3BestSnippet( int nSnippet, /* Desired snippet length */ Fts3Cursor *pCsr, /* Cursor to create snippet for */ int iCol, /* Index of column to create snippet from */ u64 mCovered, /* Mask of phrases already covered */ u64 *pmSeen, /* IN/OUT: Mask of phrases seen */ SnippetFragment *pFragment, /* OUT: Best snippet found */ int *piScore /* OUT: Score of snippet pFragment */ ){ int rc; /* Return Code */ int nList; /* Number of phrases in expression */ SnippetIter sIter; /* Iterates through snippet candidates */ sqlite3_int64 nByte; /* Number of bytes of space to allocate */ int iBestScore = -1; /* Best snippet score found so far */ int i; /* Loop counter */ memset(&sIter, 0, sizeof(sIter)); /* Iterate through the phrases in the expression to count them. The same ** callback makes sure the doclists are loaded for each phrase. */ rc = fts3ExprLoadDoclists(pCsr, &nList, 0); if( rc!=SQLITE_OK ){ return rc; } /* Now that it is known how many phrases there are, allocate and zero ** the required space using malloc(). */ nByte = sizeof(SnippetPhrase) * nList; sIter.aPhrase = (SnippetPhrase *)sqlite3Fts3MallocZero(nByte); if( !sIter.aPhrase ){ return SQLITE_NOMEM; } /* Initialize the contents of the SnippetIter object. Then iterate through ** the set of phrases in the expression to populate the aPhrase[] array. */ sIter.pCsr = pCsr; sIter.iCol = iCol; sIter.nSnippet = nSnippet; sIter.nPhrase = nList; sIter.iCurrent = -1; rc = sqlite3Fts3ExprIterate( pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter ); if( rc==SQLITE_OK ){ /* Set the *pmSeen output variable. */ for(i=0; iiCol = iCol; while( !fts3SnippetNextCandidate(&sIter) ){ int iPos; int iScore; u64 mCover; u64 mHighlite; fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover,&mHighlite); assert( iScore>=0 ); if( iScore>iBestScore ){ pFragment->iPos = iPos; pFragment->hlmask = mHighlite; pFragment->covered = mCover; iBestScore = iScore; } } *piScore = iBestScore; } sqlite3_free(sIter.aPhrase); return rc; } /* ** Append a string to the string-buffer passed as the first argument. ** ** If nAppend is negative, then the length of the string zAppend is ** determined using strlen(). */ static int fts3StringAppend( StrBuffer *pStr, /* Buffer to append to */ const char *zAppend, /* Pointer to data to append to buffer */ int nAppend /* Size of zAppend in bytes (or -1) */ ){ if( nAppend<0 ){ nAppend = (int)strlen(zAppend); } /* If there is insufficient space allocated at StrBuffer.z, use realloc() ** to grow the buffer until so that it is big enough to accomadate the ** appended data. */ if( pStr->n+nAppend+1>=pStr->nAlloc ){ sqlite3_int64 nAlloc = pStr->nAlloc+(sqlite3_int64)nAppend+100; char *zNew = sqlite3_realloc64(pStr->z, nAlloc); if( !zNew ){ return SQLITE_NOMEM; } pStr->z = zNew; pStr->nAlloc = nAlloc; } assert( pStr->z!=0 && (pStr->nAlloc >= pStr->n+nAppend+1) ); /* Append the data to the string buffer. */ memcpy(&pStr->z[pStr->n], zAppend, nAppend); pStr->n += nAppend; pStr->z[pStr->n] = '\0'; return SQLITE_OK; } /* ** The fts3BestSnippet() function often selects snippets that end with a ** query term. That is, the final term of the snippet is always a term ** that requires highlighting. For example, if 'X' is a highlighted term ** and '.' is a non-highlighted term, BestSnippet() may select: ** ** ........X.....X ** ** This function "shifts" the beginning of the snippet forward in the ** document so that there are approximately the same number of ** non-highlighted terms to the right of the final highlighted term as there ** are to the left of the first highlighted term. For example, to this: ** ** ....X.....X.... ** ** This is done as part of extracting the snippet text, not when selecting ** the snippet. Snippet selection is done based on doclists only, so there ** is no way for fts3BestSnippet() to know whether or not the document ** actually contains terms that follow the final highlighted term. */ static int fts3SnippetShift( Fts3Table *pTab, /* FTS3 table snippet comes from */ int iLangid, /* Language id to use in tokenizing */ int nSnippet, /* Number of tokens desired for snippet */ const char *zDoc, /* Document text to extract snippet from */ int nDoc, /* Size of buffer zDoc in bytes */ int *piPos, /* IN/OUT: First token of snippet */ u64 *pHlmask /* IN/OUT: Mask of tokens to highlight */ ){ u64 hlmask = *pHlmask; /* Local copy of initial highlight-mask */ if( hlmask ){ int nLeft; /* Tokens to the left of first highlight */ int nRight; /* Tokens to the right of last highlight */ int nDesired; /* Ideal number of tokens to shift forward */ for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++); for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++); assert( (nSnippet-1-nRight)<=63 && (nSnippet-1-nRight)>=0 ); nDesired = (nLeft-nRight)/2; /* Ideally, the start of the snippet should be pushed forward in the ** document nDesired tokens. This block checks if there are actually ** nDesired tokens to the right of the snippet. If so, *piPos and ** *pHlMask are updated to shift the snippet nDesired tokens to the ** right. Otherwise, the snippet is shifted by the number of tokens ** available. */ if( nDesired>0 ){ int nShift; /* Number of tokens to shift snippet by */ int iCurrent = 0; /* Token counter */ int rc; /* Return Code */ sqlite3_tokenizer_module *pMod; sqlite3_tokenizer_cursor *pC; pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule; /* Open a cursor on zDoc/nDoc. Check if there are (nSnippet+nDesired) ** or more tokens in zDoc/nDoc. */ rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, iLangid, zDoc, nDoc, &pC); if( rc!=SQLITE_OK ){ return rc; } while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){ const char *ZDUMMY; int DUMMY1 = 0, DUMMY2 = 0, DUMMY3 = 0; rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent); } pMod->xClose(pC); if( rc!=SQLITE_OK && rc!=SQLITE_DONE ){ return rc; } nShift = (rc==SQLITE_DONE)+iCurrent-nSnippet; assert( nShift<=nDesired ); if( nShift>0 ){ *piPos += nShift; *pHlmask = hlmask >> nShift; } } } return SQLITE_OK; } /* ** Extract the snippet text for fragment pFragment from cursor pCsr and ** append it to string buffer pOut. */ static int fts3SnippetText( Fts3Cursor *pCsr, /* FTS3 Cursor */ SnippetFragment *pFragment, /* Snippet to extract */ int iFragment, /* Fragment number */ int isLast, /* True for final fragment in snippet */ int nSnippet, /* Number of tokens in extracted snippet */ const char *zOpen, /* String inserted before highlighted term */ const char *zClose, /* String inserted after highlighted term */ const char *zEllipsis, /* String inserted between snippets */ StrBuffer *pOut /* Write output here */ ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int rc; /* Return code */ const char *zDoc; /* Document text to extract snippet from */ int nDoc; /* Size of zDoc in bytes */ int iCurrent = 0; /* Current token number of document */ int iEnd = 0; /* Byte offset of end of current token */ int isShiftDone = 0; /* True after snippet is shifted */ int iPos = pFragment->iPos; /* First token of snippet */ u64 hlmask = pFragment->hlmask; /* Highlight-mask for snippet */ int iCol = pFragment->iCol+1; /* Query column to extract text from */ sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */ sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */ zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol); if( zDoc==0 ){ if( sqlite3_column_type(pCsr->pStmt, iCol)!=SQLITE_NULL ){ return SQLITE_NOMEM; } return SQLITE_OK; } nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol); /* Open a token cursor on the document. */ pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule; rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, zDoc,nDoc,&pC); if( rc!=SQLITE_OK ){ return rc; } while( rc==SQLITE_OK ){ const char *ZDUMMY; /* Dummy argument used with tokenizer */ int DUMMY1 = -1; /* Dummy argument used with tokenizer */ int iBegin = 0; /* Offset in zDoc of start of token */ int iFin = 0; /* Offset in zDoc of end of token */ int isHighlight = 0; /* True for highlighted terms */ /* Variable DUMMY1 is initialized to a negative value above. Elsewhere ** in the FTS code the variable that the third argument to xNext points to ** is initialized to zero before the first (*but not necessarily ** subsequent*) call to xNext(). This is done for a particular application ** that needs to know whether or not the tokenizer is being used for ** snippet generation or for some other purpose. ** ** Extreme care is required when writing code to depend on this ** initialization. It is not a documented part of the tokenizer interface. ** If a tokenizer is used directly by any code outside of FTS, this ** convention might not be respected. */ rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ /* Special case - the last token of the snippet is also the last token ** of the column. Append any punctuation that occurred between the end ** of the previous token and the end of the document to the output. ** Then break out of the loop. */ rc = fts3StringAppend(pOut, &zDoc[iEnd], -1); } break; } if( iCurrentiLangid, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask ); isShiftDone = 1; /* Now that the shift has been done, check if the initial "..." are ** required. They are required if (a) this is not the first fragment, ** or (b) this fragment does not begin at position 0 of its column. */ if( rc==SQLITE_OK ){ if( iPos>0 || iFragment>0 ){ rc = fts3StringAppend(pOut, zEllipsis, -1); }else if( iBegin ){ rc = fts3StringAppend(pOut, zDoc, iBegin); } } if( rc!=SQLITE_OK || iCurrent=(iPos+nSnippet) ){ if( isLast ){ rc = fts3StringAppend(pOut, zEllipsis, -1); } break; } /* Set isHighlight to true if this term should be highlighted. */ isHighlight = (hlmask & ((u64)1 << (iCurrent-iPos)))!=0; if( iCurrent>iPos ) rc = fts3StringAppend(pOut, &zDoc[iEnd], iBegin-iEnd); if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zOpen, -1); if( rc==SQLITE_OK ) rc = fts3StringAppend(pOut, &zDoc[iBegin], iFin-iBegin); if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zClose, -1); iEnd = iFin; } pMod->xClose(pC); return rc; } /* ** This function is used to count the entries in a column-list (a ** delta-encoded list of term offsets within a single column of a single ** row). When this function is called, *ppCollist should point to the ** beginning of the first varint in the column-list (the varint that ** contains the position of the first matching term in the column data). ** Before returning, *ppCollist is set to point to the first byte after ** the last varint in the column-list (either the 0x00 signifying the end ** of the position-list, or the 0x01 that precedes the column number of ** the next column in the position-list). ** ** The number of elements in the column-list is returned. */ static int fts3ColumnlistCount(char **ppCollist){ char *pEnd = *ppCollist; char c = 0; int nEntry = 0; /* A column-list is terminated by either a 0x01 or 0x00. */ while( 0xFE & (*pEnd | c) ){ c = *pEnd++ & 0x80; if( !c ) nEntry++; } *ppCollist = pEnd; return nEntry; } /* ** This function gathers 'y' or 'b' data for a single phrase. */ static int fts3ExprLHits( Fts3Expr *pExpr, /* Phrase expression node */ MatchInfo *p /* Matchinfo context */ ){ Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab; int iStart; Fts3Phrase *pPhrase = pExpr->pPhrase; char *pIter = pPhrase->doclist.pList; int iCol = 0; assert( p->flag==FTS3_MATCHINFO_LHITS_BM || p->flag==FTS3_MATCHINFO_LHITS ); if( p->flag==FTS3_MATCHINFO_LHITS ){ iStart = pExpr->iPhrase * p->nCol; }else{ iStart = pExpr->iPhrase * ((p->nCol + 31) / 32); } if( pIter ) while( 1 ){ int nHit = fts3ColumnlistCount(&pIter); if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){ if( p->flag==FTS3_MATCHINFO_LHITS ){ p->aMatchinfo[iStart + iCol] = (u32)nHit; }else if( nHit ){ p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F)); } } assert( *pIter==0x00 || *pIter==0x01 ); if( *pIter!=0x01 ) break; pIter++; pIter += fts3GetVarint32(pIter, &iCol); if( iCol>=p->nCol ) return FTS_CORRUPT_VTAB; } return SQLITE_OK; } /* ** Gather the results for matchinfo directives 'y' and 'b'. */ static int fts3ExprLHitGather( Fts3Expr *pExpr, MatchInfo *p ){ int rc = SQLITE_OK; assert( (pExpr->pLeft==0)==(pExpr->pRight==0) ); if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){ if( pExpr->pLeft ){ rc = fts3ExprLHitGather(pExpr->pLeft, p); if( rc==SQLITE_OK ) rc = fts3ExprLHitGather(pExpr->pRight, p); }else{ rc = fts3ExprLHits(pExpr, p); } } return rc; } /* ** sqlite3Fts3ExprIterate() callback used to collect the "global" matchinfo ** stats for a single query. ** ** sqlite3Fts3ExprIterate() callback to load the 'global' elements of a ** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements ** of the matchinfo array that are constant for all rows returned by the ** current query. ** ** Argument pCtx is actually a pointer to a struct of type MatchInfo. This ** function populates Matchinfo.aMatchinfo[] as follows: ** ** for(iCol=0; iColpCursor, pExpr, &p->aMatchinfo[3*iPhrase*p->nCol] ); } /* ** sqlite3Fts3ExprIterate() callback used to collect the "local" part of the ** FTS3_MATCHINFO_HITS array. The local stats are those elements of the ** array that are different for each row returned by the query. */ static int fts3ExprLocalHitsCb( Fts3Expr *pExpr, /* Phrase expression node */ int iPhrase, /* Phrase number */ void *pCtx /* Pointer to MatchInfo structure */ ){ int rc = SQLITE_OK; MatchInfo *p = (MatchInfo *)pCtx; int iStart = iPhrase * p->nCol * 3; int i; for(i=0; inCol && rc==SQLITE_OK; i++){ char *pCsr; rc = sqlite3Fts3EvalPhrasePoslist(p->pCursor, pExpr, i, &pCsr); if( pCsr ){ p->aMatchinfo[iStart+i*3] = fts3ColumnlistCount(&pCsr); }else{ p->aMatchinfo[iStart+i*3] = 0; } } return rc; } static int fts3MatchinfoCheck( Fts3Table *pTab, char cArg, char **pzErr ){ if( (cArg==FTS3_MATCHINFO_NPHRASE) || (cArg==FTS3_MATCHINFO_NCOL) || (cArg==FTS3_MATCHINFO_NDOC && pTab->bFts4) || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bFts4) || (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize) || (cArg==FTS3_MATCHINFO_LCS) || (cArg==FTS3_MATCHINFO_HITS) || (cArg==FTS3_MATCHINFO_LHITS) || (cArg==FTS3_MATCHINFO_LHITS_BM) ){ return SQLITE_OK; } sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo request: %c", cArg); return SQLITE_ERROR; } static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ size_t nVal; /* Number of integers output by cArg */ switch( cArg ){ case FTS3_MATCHINFO_NDOC: case FTS3_MATCHINFO_NPHRASE: case FTS3_MATCHINFO_NCOL: nVal = 1; break; case FTS3_MATCHINFO_AVGLENGTH: case FTS3_MATCHINFO_LENGTH: case FTS3_MATCHINFO_LCS: nVal = pInfo->nCol; break; case FTS3_MATCHINFO_LHITS: nVal = pInfo->nCol * pInfo->nPhrase; break; case FTS3_MATCHINFO_LHITS_BM: nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32); break; default: assert( cArg==FTS3_MATCHINFO_HITS ); nVal = pInfo->nCol * pInfo->nPhrase * 3; break; } return nVal; } static int fts3MatchinfoSelectDoctotal( Fts3Table *pTab, sqlite3_stmt **ppStmt, sqlite3_int64 *pnDoc, const char **paLen, const char **ppEnd ){ sqlite3_stmt *pStmt; const char *a; const char *pEnd; sqlite3_int64 nDoc; int n; if( !*ppStmt ){ int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt); if( rc!=SQLITE_OK ) return rc; } pStmt = *ppStmt; assert( sqlite3_data_count(pStmt)==1 ); n = sqlite3_column_bytes(pStmt, 0); a = sqlite3_column_blob(pStmt, 0); if( a==0 ){ return FTS_CORRUPT_VTAB; } pEnd = a + n; a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc); if( nDoc<=0 || a>pEnd ){ return FTS_CORRUPT_VTAB; } *pnDoc = nDoc; if( paLen ) *paLen = a; if( ppEnd ) *ppEnd = pEnd; return SQLITE_OK; } /* ** An instance of the following structure is used to store state while ** iterating through a multi-column position-list corresponding to the ** hits for a single phrase on a single row in order to calculate the ** values for a matchinfo() FTS3_MATCHINFO_LCS request. */ typedef struct LcsIterator LcsIterator; struct LcsIterator { Fts3Expr *pExpr; /* Pointer to phrase expression */ int iPosOffset; /* Tokens count up to end of this phrase */ char *pRead; /* Cursor used to iterate through aDoclist */ int iPos; /* Current position */ }; /* ** If LcsIterator.iCol is set to the following value, the iterator has ** finished iterating through all offsets for all columns. */ #define LCS_ITERATOR_FINISHED 0x7FFFFFFF; static int fts3MatchinfoLcsCb( Fts3Expr *pExpr, /* Phrase expression node */ int iPhrase, /* Phrase number (numbered from zero) */ void *pCtx /* Pointer to MatchInfo structure */ ){ LcsIterator *aIter = (LcsIterator *)pCtx; aIter[iPhrase].pExpr = pExpr; return SQLITE_OK; } /* ** Advance the iterator passed as an argument to the next position. Return ** 1 if the iterator is at EOF or if it now points to the start of the ** position list for the next column. */ static int fts3LcsIteratorAdvance(LcsIterator *pIter){ char *pRead; sqlite3_int64 iRead; int rc = 0; if( NEVER(pIter==0) ) return 1; pRead = pIter->pRead; pRead += sqlite3Fts3GetVarint(pRead, &iRead); if( iRead==0 || iRead==1 ){ pRead = 0; rc = 1; }else{ pIter->iPos += (int)(iRead-2); } pIter->pRead = pRead; return rc; } /* ** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag. ** ** If the call is successful, the longest-common-substring lengths for each ** column are written into the first nCol elements of the pInfo->aMatchinfo[] ** array before returning. SQLITE_OK is returned in this case. ** ** Otherwise, if an error occurs, an SQLite error code is returned and the ** data written to the first nCol elements of pInfo->aMatchinfo[] is ** undefined. */ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ LcsIterator *aIter; int i; int iCol; int nToken = 0; int rc = SQLITE_OK; /* Allocate and populate the array of LcsIterator objects. The array ** contains one element for each matchable phrase in the query. **/ aIter = sqlite3Fts3MallocZero(sizeof(LcsIterator) * pCsr->nPhrase); if( !aIter ) return SQLITE_NOMEM; (void)sqlite3Fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); for(i=0; inPhrase; i++){ LcsIterator *pIter = &aIter[i]; nToken -= pIter->pExpr->pPhrase->nToken; pIter->iPosOffset = nToken; } for(iCol=0; iColnCol; iCol++){ int nLcs = 0; /* LCS value for this column */ int nLive = 0; /* Number of iterators in aIter not at EOF */ for(i=0; inPhrase; i++){ LcsIterator *pIt = &aIter[i]; rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead); if( rc!=SQLITE_OK ) goto matchinfo_lcs_out; if( pIt->pRead ){ pIt->iPos = pIt->iPosOffset; fts3LcsIteratorAdvance(pIt); if( pIt->pRead==0 ){ rc = FTS_CORRUPT_VTAB; goto matchinfo_lcs_out; } nLive++; } } while( nLive>0 ){ LcsIterator *pAdv = 0; /* The iterator to advance by one position */ int nThisLcs = 0; /* LCS for the current iterator positions */ for(i=0; inPhrase; i++){ LcsIterator *pIter = &aIter[i]; if( pIter->pRead==0 ){ /* This iterator is already at EOF for this column. */ nThisLcs = 0; }else{ if( pAdv==0 || pIter->iPosiPos ){ pAdv = pIter; } if( nThisLcs==0 || pIter->iPos==pIter[-1].iPos ){ nThisLcs++; }else{ nThisLcs = 1; } if( nThisLcs>nLcs ) nLcs = nThisLcs; } } if( fts3LcsIteratorAdvance(pAdv) ) nLive--; } pInfo->aMatchinfo[iCol] = nLcs; } matchinfo_lcs_out: sqlite3_free(aIter); return rc; } /* ** Populate the buffer pInfo->aMatchinfo[] with an array of integers to ** be returned by the matchinfo() function. Argument zArg contains the ** format string passed as the second argument to matchinfo (or the ** default value "pcx" if no second argument was specified). The format ** string has already been validated and the pInfo->aMatchinfo[] array ** is guaranteed to be large enough for the output. ** ** If bGlobal is true, then populate all fields of the matchinfo() output. ** If it is false, then assume that those fields that do not change between ** rows (i.e. FTS3_MATCHINFO_NPHRASE, NCOL, NDOC, AVGLENGTH and part of HITS) ** have already been populated. ** ** Return SQLITE_OK if successful, or an SQLite error code if an error ** occurs. If a value other than SQLITE_OK is returned, the state the ** pInfo->aMatchinfo[] buffer is left in is undefined. */ static int fts3MatchinfoValues( Fts3Cursor *pCsr, /* FTS3 cursor object */ int bGlobal, /* True to grab the global stats */ MatchInfo *pInfo, /* Matchinfo context object */ const char *zArg /* Matchinfo format string */ ){ int rc = SQLITE_OK; int i; Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; sqlite3_stmt *pSelect = 0; for(i=0; rc==SQLITE_OK && zArg[i]; i++){ pInfo->flag = zArg[i]; switch( zArg[i] ){ case FTS3_MATCHINFO_NPHRASE: if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase; break; case FTS3_MATCHINFO_NCOL: if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol; break; case FTS3_MATCHINFO_NDOC: if( bGlobal ){ sqlite3_int64 nDoc = 0; rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0, 0); pInfo->aMatchinfo[0] = (u32)nDoc; } break; case FTS3_MATCHINFO_AVGLENGTH: if( bGlobal ){ sqlite3_int64 nDoc; /* Number of rows in table */ const char *a; /* Aggregate column length array */ const char *pEnd; /* First byte past end of length array */ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a, &pEnd); if( rc==SQLITE_OK ){ int iCol; for(iCol=0; iColnCol; iCol++){ u32 iVal; sqlite3_int64 nToken; a += sqlite3Fts3GetVarint(a, &nToken); if( a>pEnd ){ rc = SQLITE_CORRUPT_VTAB; break; } iVal = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc); pInfo->aMatchinfo[iCol] = iVal; } } } break; case FTS3_MATCHINFO_LENGTH: { sqlite3_stmt *pSelectDocsize = 0; rc = sqlite3Fts3SelectDocsize(pTab, pCsr->iPrevId, &pSelectDocsize); if( rc==SQLITE_OK ){ int iCol; const char *a = sqlite3_column_blob(pSelectDocsize, 0); const char *pEnd = a + sqlite3_column_bytes(pSelectDocsize, 0); for(iCol=0; iColnCol; iCol++){ sqlite3_int64 nToken; a += sqlite3Fts3GetVarintBounded(a, pEnd, &nToken); if( a>pEnd ){ rc = SQLITE_CORRUPT_VTAB; break; } pInfo->aMatchinfo[iCol] = (u32)nToken; } } sqlite3_reset(pSelectDocsize); break; } case FTS3_MATCHINFO_LCS: rc = fts3ExprLoadDoclists(pCsr, 0, 0); if( rc==SQLITE_OK ){ rc = fts3MatchinfoLcs(pCsr, pInfo); } break; case FTS3_MATCHINFO_LHITS_BM: case FTS3_MATCHINFO_LHITS: { size_t nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); memset(pInfo->aMatchinfo, 0, nZero); rc = fts3ExprLHitGather(pCsr->pExpr, pInfo); break; } default: { Fts3Expr *pExpr; assert( zArg[i]==FTS3_MATCHINFO_HITS ); pExpr = pCsr->pExpr; rc = fts3ExprLoadDoclists(pCsr, 0, 0); if( rc!=SQLITE_OK ) break; if( bGlobal ){ if( pCsr->pDeferred ){ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0); if( rc!=SQLITE_OK ) break; } rc = sqlite3Fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo); sqlite3Fts3EvalTestDeferred(pCsr, &rc); if( rc!=SQLITE_OK ) break; } (void)sqlite3Fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo); break; } } pInfo->aMatchinfo += fts3MatchinfoSize(pInfo, zArg[i]); } sqlite3_reset(pSelect); return rc; } /* ** Populate pCsr->aMatchinfo[] with data for the current row. The ** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32). */ static void fts3GetMatchinfo( sqlite3_context *pCtx, /* Return results here */ Fts3Cursor *pCsr, /* FTS3 Cursor object */ const char *zArg /* Second argument to matchinfo() function */ ){ MatchInfo sInfo; Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int rc = SQLITE_OK; int bGlobal = 0; /* Collect 'global' stats as well as local */ u32 *aOut = 0; void (*xDestroyOut)(void*) = 0; memset(&sInfo, 0, sizeof(MatchInfo)); sInfo.pCursor = pCsr; sInfo.nCol = pTab->nColumn; /* If there is cached matchinfo() data, but the format string for the ** cache does not match the format string for this request, discard ** the cached data. */ if( pCsr->pMIBuffer && strcmp(pCsr->pMIBuffer->zMatchinfo, zArg) ){ sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); pCsr->pMIBuffer = 0; } /* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the ** matchinfo function has been called for this query. In this case ** allocate the array used to accumulate the matchinfo data and ** initialize those elements that are constant for every row. */ if( pCsr->pMIBuffer==0 ){ size_t nMatchinfo = 0; /* Number of u32 elements in match-info */ int i; /* Used to iterate through zArg */ /* Determine the number of phrases in the query */ pCsr->nPhrase = fts3ExprPhraseCount(pCsr->pExpr); sInfo.nPhrase = pCsr->nPhrase; /* Determine the number of integers in the buffer returned by this call. */ for(i=0; zArg[i]; i++){ char *zErr = 0; if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){ sqlite3_result_error(pCtx, zErr, -1); sqlite3_free(zErr); return; } nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]); } /* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */ pCsr->pMIBuffer = fts3MIBufferNew(nMatchinfo, zArg); if( !pCsr->pMIBuffer ) rc = SQLITE_NOMEM; pCsr->isMatchinfoNeeded = 1; bGlobal = 1; } if( rc==SQLITE_OK ){ xDestroyOut = fts3MIBufferAlloc(pCsr->pMIBuffer, &aOut); if( xDestroyOut==0 ){ rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK ){ sInfo.aMatchinfo = aOut; sInfo.nPhrase = pCsr->nPhrase; rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg); if( bGlobal ){ fts3MIBufferSetGlobal(pCsr->pMIBuffer); } } if( rc!=SQLITE_OK ){ sqlite3_result_error_code(pCtx, rc); if( xDestroyOut ) xDestroyOut(aOut); }else{ int n = pCsr->pMIBuffer->nElem * sizeof(u32); sqlite3_result_blob(pCtx, aOut, n, xDestroyOut); } } /* ** Implementation of snippet() function. */ SQLITE_PRIVATE void sqlite3Fts3Snippet( sqlite3_context *pCtx, /* SQLite function call context */ Fts3Cursor *pCsr, /* Cursor object */ const char *zStart, /* Snippet start text - "" */ const char *zEnd, /* Snippet end text - "" */ const char *zEllipsis, /* Snippet ellipsis text - "..." */ int iCol, /* Extract snippet from this column */ int nToken /* Approximate number of tokens in snippet */ ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int rc = SQLITE_OK; int i; StrBuffer res = {0, 0, 0}; /* The returned text includes up to four fragments of text extracted from ** the data in the current row. The first iteration of the for(...) loop ** below attempts to locate a single fragment of text nToken tokens in ** size that contains at least one instance of all phrases in the query ** expression that appear in the current row. If such a fragment of text ** cannot be found, the second iteration of the loop attempts to locate ** a pair of fragments, and so on. */ int nSnippet = 0; /* Number of fragments in this snippet */ SnippetFragment aSnippet[4]; /* Maximum of 4 fragments per snippet */ int nFToken = -1; /* Number of tokens in each fragment */ if( !pCsr->pExpr ){ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); return; } /* Limit the snippet length to 64 tokens. */ if( nToken<-64 ) nToken = -64; if( nToken>+64 ) nToken = +64; for(nSnippet=1; 1; nSnippet++){ int iSnip; /* Loop counter 0..nSnippet-1 */ u64 mCovered = 0; /* Bitmask of phrases covered by snippet */ u64 mSeen = 0; /* Bitmask of phrases seen by BestSnippet() */ if( nToken>=0 ){ nFToken = (nToken+nSnippet-1) / nSnippet; }else{ nFToken = -1 * nToken; } for(iSnip=0; iSnipnColumn; iRead++){ SnippetFragment sF = {0, 0, 0, 0}; int iS = 0; if( iCol>=0 && iRead!=iCol ) continue; /* Find the best snippet of nFToken tokens in column iRead. */ rc = fts3BestSnippet(nFToken, pCsr, iRead, mCovered, &mSeen, &sF, &iS); if( rc!=SQLITE_OK ){ goto snippet_out; } if( iS>iBestScore ){ *pFragment = sF; iBestScore = iS; } } mCovered |= pFragment->covered; } /* If all query phrases seen by fts3BestSnippet() are present in at least ** one of the nSnippet snippet fragments, break out of the loop. */ assert( (mCovered&mSeen)==mCovered ); if( mSeen==mCovered || nSnippet==SizeofArray(aSnippet) ) break; } assert( nFToken>0 ); for(i=0; ipCsr, pExpr, p->iCol, &pList); nTerm = pExpr->pPhrase->nToken; if( pList ){ fts3GetDeltaPosition(&pList, &iPos); assert_fts3_nc( iPos>=0 ); } for(iTerm=0; iTermaTerm[p->iTerm++]; pT->iOff = nTerm-iTerm-1; pT->pList = pList; pT->iPos = iPos; } return rc; } /* ** Implementation of offsets() function. */ SQLITE_PRIVATE void sqlite3Fts3Offsets( sqlite3_context *pCtx, /* SQLite function call context */ Fts3Cursor *pCsr /* Cursor object */ ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; sqlite3_tokenizer_module const *pMod = pTab->pTokenizer->pModule; int rc; /* Return Code */ int nToken; /* Number of tokens in query */ int iCol; /* Column currently being processed */ StrBuffer res = {0, 0, 0}; /* Result string */ TermOffsetCtx sCtx; /* Context for fts3ExprTermOffsetInit() */ if( !pCsr->pExpr ){ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); return; } memset(&sCtx, 0, sizeof(sCtx)); assert( pCsr->isRequireSeek==0 ); /* Count the number of terms in the query */ rc = fts3ExprLoadDoclists(pCsr, 0, &nToken); if( rc!=SQLITE_OK ) goto offsets_out; /* Allocate the array of TermOffset iterators. */ sCtx.aTerm = (TermOffset *)sqlite3Fts3MallocZero(sizeof(TermOffset)*nToken); if( 0==sCtx.aTerm ){ rc = SQLITE_NOMEM; goto offsets_out; } sCtx.iDocid = pCsr->iPrevId; sCtx.pCsr = pCsr; /* Loop through the table columns, appending offset information to ** string-buffer res for each column. */ for(iCol=0; iColnColumn; iCol++){ sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor */ const char *ZDUMMY; /* Dummy argument used with xNext() */ int NDUMMY = 0; /* Dummy argument used with xNext() */ int iStart = 0; int iEnd = 0; int iCurrent = 0; const char *zDoc; int nDoc; /* Initialize the contents of sCtx.aTerm[] for column iCol. This ** operation may fail if the database contains corrupt records. */ sCtx.iCol = iCol; sCtx.iTerm = 0; rc = sqlite3Fts3ExprIterate( pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx ); if( rc!=SQLITE_OK ) goto offsets_out; /* Retreive the text stored in column iCol. If an SQL NULL is stored ** in column iCol, jump immediately to the next iteration of the loop. ** If an OOM occurs while retrieving the data (this can happen if SQLite ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM ** to the caller. */ zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol+1); nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol+1); if( zDoc==0 ){ if( sqlite3_column_type(pCsr->pStmt, iCol+1)==SQLITE_NULL ){ continue; } rc = SQLITE_NOMEM; goto offsets_out; } /* Initialize a tokenizer iterator to iterate through column iCol. */ rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, zDoc, nDoc, &pC ); if( rc!=SQLITE_OK ) goto offsets_out; rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent); while( rc==SQLITE_OK ){ int i; /* Used to loop through terms */ int iMinPos = 0x7FFFFFFF; /* Position of next token */ TermOffset *pTerm = 0; /* TermOffset associated with next token */ for(i=0; ipList && (pT->iPos-pT->iOff)iPos-pT->iOff; pTerm = pT; } } if( !pTerm ){ /* All offsets for this column have been gathered. */ rc = SQLITE_DONE; }else{ assert_fts3_nc( iCurrent<=iMinPos ); if( 0==(0xFE&*pTerm->pList) ){ pTerm->pList = 0; }else{ fts3GetDeltaPosition(&pTerm->pList, &pTerm->iPos); } while( rc==SQLITE_OK && iCurrentxNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent); } if( rc==SQLITE_OK ){ char aBuffer[64]; sqlite3_snprintf(sizeof(aBuffer), aBuffer, "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart ); rc = fts3StringAppend(&res, aBuffer, -1); }else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){ rc = FTS_CORRUPT_VTAB; } } } if( rc==SQLITE_DONE ){ rc = SQLITE_OK; } pMod->xClose(pC); if( rc!=SQLITE_OK ) goto offsets_out; } offsets_out: sqlite3_free(sCtx.aTerm); assert( rc!=SQLITE_DONE ); sqlite3Fts3SegmentsClose(pTab); if( rc!=SQLITE_OK ){ sqlite3_result_error_code(pCtx, rc); sqlite3_free(res.z); }else{ sqlite3_result_text(pCtx, res.z, res.n-1, sqlite3_free); } return; } /* ** Implementation of matchinfo() function. */ SQLITE_PRIVATE void sqlite3Fts3Matchinfo( sqlite3_context *pContext, /* Function call context */ Fts3Cursor *pCsr, /* FTS3 table cursor */ const char *zArg /* Second arg to matchinfo() function */ ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; const char *zFormat; if( zArg ){ zFormat = zArg; }else{ zFormat = FTS3_MATCHINFO_DEFAULT; } if( !pCsr->pExpr ){ sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC); return; }else{ /* Retrieve matchinfo() data. */ fts3GetMatchinfo(pContext, pCsr, zFormat); sqlite3Fts3SegmentsClose(pTab); } } #endif /************** End of fts3_snippet.c ****************************************/ /************** Begin file fts3_unicode.c ************************************/ /* ** 2012 May 24 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** Implementation of the "unicode" full-text-search tokenizer. */ #ifndef SQLITE_DISABLE_FTS3_UNICODE /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include */ /* #include */ /* #include */ /* #include */ /* #include "fts3_tokenizer.h" */ /* ** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied ** from the sqlite3 source file utf.c. If this file is compiled as part ** of the amalgamation, they are not required. */ #ifndef SQLITE_AMALGAMATION static const unsigned char sqlite3Utf8Trans1[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, }; #define READ_UTF8(zIn, zTerm, c) \ c = *(zIn++); \ if( c>=0xc0 ){ \ c = sqlite3Utf8Trans1[c-0xc0]; \ while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ c = (c<<6) + (0x3f & *(zIn++)); \ } \ if( c<0x80 \ || (c&0xFFFFF800)==0xD800 \ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ } #define WRITE_UTF8(zOut, c) { \ if( c<0x00080 ){ \ *zOut++ = (u8)(c&0xFF); \ } \ else if( c<0x00800 ){ \ *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); \ *zOut++ = 0x80 + (u8)(c & 0x3F); \ } \ else if( c<0x10000 ){ \ *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ *zOut++ = 0x80 + (u8)(c & 0x3F); \ }else{ \ *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \ *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ *zOut++ = 0x80 + (u8)(c & 0x3F); \ } \ } #endif /* ifndef SQLITE_AMALGAMATION */ typedef struct unicode_tokenizer unicode_tokenizer; typedef struct unicode_cursor unicode_cursor; struct unicode_tokenizer { sqlite3_tokenizer base; int eRemoveDiacritic; int nException; int *aiException; }; struct unicode_cursor { sqlite3_tokenizer_cursor base; const unsigned char *aInput; /* Input text being tokenized */ int nInput; /* Size of aInput[] in bytes */ int iOff; /* Current offset within aInput[] */ int iToken; /* Index of next token to be returned */ char *zToken; /* storage for current token */ int nAlloc; /* space allocated at zToken */ }; /* ** Destroy a tokenizer allocated by unicodeCreate(). */ static int unicodeDestroy(sqlite3_tokenizer *pTokenizer){ if( pTokenizer ){ unicode_tokenizer *p = (unicode_tokenizer *)pTokenizer; sqlite3_free(p->aiException); sqlite3_free(p); } return SQLITE_OK; } /* ** As part of a tokenchars= or separators= option, the CREATE VIRTUAL TABLE ** statement has specified that the tokenizer for this table shall consider ** all characters in string zIn/nIn to be separators (if bAlnum==0) or ** token characters (if bAlnum==1). ** ** For each codepoint in the zIn/nIn string, this function checks if the ** sqlite3FtsUnicodeIsalnum() function already returns the desired result. ** If so, no action is taken. Otherwise, the codepoint is added to the ** unicode_tokenizer.aiException[] array. For the purposes of tokenization, ** the return value of sqlite3FtsUnicodeIsalnum() is inverted for all ** codepoints in the aiException[] array. ** ** If a standalone diacritic mark (one that sqlite3FtsUnicodeIsdiacritic() ** identifies as a diacritic) occurs in the zIn/nIn string it is ignored. ** It is not possible to change the behavior of the tokenizer with respect ** to these codepoints. */ static int unicodeAddExceptions( unicode_tokenizer *p, /* Tokenizer to add exceptions to */ int bAlnum, /* Replace Isalnum() return value with this */ const char *zIn, /* Array of characters to make exceptions */ int nIn /* Length of z in bytes */ ){ const unsigned char *z = (const unsigned char *)zIn; const unsigned char *zTerm = &z[nIn]; unsigned int iCode; int nEntry = 0; assert( bAlnum==0 || bAlnum==1 ); while( zaiException,(p->nException+nEntry)*sizeof(int)); if( aNew==0 ) return SQLITE_NOMEM; nNew = p->nException; z = (const unsigned char *)zIn; while( zi; j--) aNew[j] = aNew[j-1]; aNew[i] = (int)iCode; nNew++; } } p->aiException = aNew; p->nException = nNew; } return SQLITE_OK; } /* ** Return true if the p->aiException[] array contains the value iCode. */ static int unicodeIsException(unicode_tokenizer *p, int iCode){ if( p->nException>0 ){ int *a = p->aiException; int iLo = 0; int iHi = p->nException-1; while( iHi>=iLo ){ int iTest = (iHi + iLo) / 2; if( iCode==a[iTest] ){ return 1; }else if( iCode>a[iTest] ){ iLo = iTest+1; }else{ iHi = iTest-1; } } } return 0; } /* ** Return true if, for the purposes of tokenization, codepoint iCode is ** considered a token character (not a separator). */ static int unicodeIsAlnum(unicode_tokenizer *p, int iCode){ assert( (sqlite3FtsUnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 ); return sqlite3FtsUnicodeIsalnum(iCode) ^ unicodeIsException(p, iCode); } /* ** Create a new tokenizer instance. */ static int unicodeCreate( int nArg, /* Size of array argv[] */ const char * const *azArg, /* Tokenizer creation arguments */ sqlite3_tokenizer **pp /* OUT: New tokenizer handle */ ){ unicode_tokenizer *pNew; /* New tokenizer object */ int i; int rc = SQLITE_OK; pNew = (unicode_tokenizer *) sqlite3_malloc(sizeof(unicode_tokenizer)); if( pNew==NULL ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(unicode_tokenizer)); pNew->eRemoveDiacritic = 1; for(i=0; rc==SQLITE_OK && ieRemoveDiacritic = 1; } else if( n==19 && memcmp("remove_diacritics=0", z, 19)==0 ){ pNew->eRemoveDiacritic = 0; } else if( n==19 && memcmp("remove_diacritics=2", z, 19)==0 ){ pNew->eRemoveDiacritic = 2; } else if( n>=11 && memcmp("tokenchars=", z, 11)==0 ){ rc = unicodeAddExceptions(pNew, 1, &z[11], n-11); } else if( n>=11 && memcmp("separators=", z, 11)==0 ){ rc = unicodeAddExceptions(pNew, 0, &z[11], n-11); } else{ /* Unrecognized argument */ rc = SQLITE_ERROR; } } if( rc!=SQLITE_OK ){ unicodeDestroy((sqlite3_tokenizer *)pNew); pNew = 0; } *pp = (sqlite3_tokenizer *)pNew; return rc; } /* ** Prepare to begin tokenizing a particular string. The input ** string to be tokenized is pInput[0..nBytes-1]. A cursor ** used to incrementally tokenize this string is returned in ** *ppCursor. */ static int unicodeOpen( sqlite3_tokenizer *p, /* The tokenizer */ const char *aInput, /* Input string */ int nInput, /* Size of string aInput in bytes */ sqlite3_tokenizer_cursor **pp /* OUT: New cursor object */ ){ unicode_cursor *pCsr; pCsr = (unicode_cursor *)sqlite3_malloc(sizeof(unicode_cursor)); if( pCsr==0 ){ return SQLITE_NOMEM; } memset(pCsr, 0, sizeof(unicode_cursor)); pCsr->aInput = (const unsigned char *)aInput; if( aInput==0 ){ pCsr->nInput = 0; pCsr->aInput = (const unsigned char*)""; }else if( nInput<0 ){ pCsr->nInput = (int)strlen(aInput); }else{ pCsr->nInput = nInput; } *pp = &pCsr->base; UNUSED_PARAMETER(p); return SQLITE_OK; } /* ** Close a tokenization cursor previously opened by a call to ** simpleOpen() above. */ static int unicodeClose(sqlite3_tokenizer_cursor *pCursor){ unicode_cursor *pCsr = (unicode_cursor *) pCursor; sqlite3_free(pCsr->zToken); sqlite3_free(pCsr); return SQLITE_OK; } /* ** Extract the next token from a tokenization cursor. The cursor must ** have been opened by a prior call to simpleOpen(). */ static int unicodeNext( sqlite3_tokenizer_cursor *pC, /* Cursor returned by simpleOpen */ const char **paToken, /* OUT: Token text */ int *pnToken, /* OUT: Number of bytes at *paToken */ int *piStart, /* OUT: Starting offset of token */ int *piEnd, /* OUT: Ending offset of token */ int *piPos /* OUT: Position integer of token */ ){ unicode_cursor *pCsr = (unicode_cursor *)pC; unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer); unsigned int iCode = 0; char *zOut; const unsigned char *z = &pCsr->aInput[pCsr->iOff]; const unsigned char *zStart = z; const unsigned char *zEnd; const unsigned char *zTerm = &pCsr->aInput[pCsr->nInput]; /* Scan past any delimiter characters before the start of the next token. ** Return SQLITE_DONE early if this takes us all the way to the end of ** the input. */ while( z=zTerm ) return SQLITE_DONE; zOut = pCsr->zToken; do { int iOut; /* Grow the output buffer if required. */ if( (zOut-pCsr->zToken)>=(pCsr->nAlloc-4) ){ char *zNew = sqlite3_realloc64(pCsr->zToken, pCsr->nAlloc+64); if( !zNew ) return SQLITE_NOMEM; zOut = &zNew[zOut - pCsr->zToken]; pCsr->zToken = zNew; pCsr->nAlloc += 64; } /* Write the folded case of the last character read to the output */ zEnd = z; iOut = sqlite3FtsUnicodeFold((int)iCode, p->eRemoveDiacritic); if( iOut ){ WRITE_UTF8(zOut, iOut); } /* If the cursor is not at EOF, read the next character */ if( z>=zTerm ) break; READ_UTF8(z, zTerm, iCode); }while( unicodeIsAlnum(p, (int)iCode) || sqlite3FtsUnicodeIsdiacritic((int)iCode) ); /* Set the output variables and return. */ pCsr->iOff = (int)(z - pCsr->aInput); *paToken = pCsr->zToken; *pnToken = (int)(zOut - pCsr->zToken); *piStart = (int)(zStart - pCsr->aInput); *piEnd = (int)(zEnd - pCsr->aInput); *piPos = pCsr->iToken++; return SQLITE_OK; } /* ** Set *ppModule to a pointer to the sqlite3_tokenizer_module ** structure for the unicode tokenizer. */ SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const **ppModule){ static const sqlite3_tokenizer_module module = { 0, unicodeCreate, unicodeDestroy, unicodeOpen, unicodeClose, unicodeNext, 0, }; *ppModule = &module; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ #endif /* ifndef SQLITE_DISABLE_FTS3_UNICODE */ /************** End of fts3_unicode.c ****************************************/ /************** Begin file fts3_unicode2.c ***********************************/ /* ** 2012-05-25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** */ /* ** DO NOT EDIT THIS MACHINE GENERATED FILE. */ #ifndef SQLITE_DISABLE_FTS3_UNICODE #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) /* #include */ /* ** Return true if the argument corresponds to a unicode codepoint ** classified as either a letter or a number. Otherwise false. ** ** The results are undefined if the value passed to this function ** is less than zero. */ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){ /* Each unsigned integer in the following array corresponds to a contiguous ** range of unicode codepoints that are not either letters or numbers (i.e. ** codepoints for which this function should return 0). ** ** The most significant 22 bits in each 32-bit value contain the first ** codepoint in the range. The least significant 10 bits are used to store ** the size of the range (always at least 1). In other words, the value ** ((C<<22) + N) represents a range of N codepoints starting with codepoint ** C. It is not possible to represent a range larger than 1023 codepoints ** using this format. */ static const unsigned int aEntry[] = { 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07, 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01, 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401, 0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01, 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01, 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802, 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F, 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401, 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804, 0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403, 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812, 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805, 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401, 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807, 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001, 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01, 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804, 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001, 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802, 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01, 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006, 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417, 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14, 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07, 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01, 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001, 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802, 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F, 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802, 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006, 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D, 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802, 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027, 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805, 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04, 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401, 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B, 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A, 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59, 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100, 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10, 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402, 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804, 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012, 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004, 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002, 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803, 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07, 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013, 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06, 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003, 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01, 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403, 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003, 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003, 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E, 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046, 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401, 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401, 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C, 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002, 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025, 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6, 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46, 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060, 0x380400F0, }; static const unsigned int aAscii[4] = { 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, }; if( (unsigned int)c<128 ){ return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 ); }else if( (unsigned int)c<(1<<22) ){ unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; int iRes = 0; int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; int iLo = 0; while( iHi>=iLo ){ int iTest = (iHi + iLo) / 2; if( key >= aEntry[iTest] ){ iRes = iTest; iLo = iTest+1; }else{ iHi = iTest-1; } } assert( aEntry[0]=aEntry[iRes] ); return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF))); } return 1; } /* ** If the argument is a codepoint corresponding to a lowercase letter ** in the ASCII range with a diacritic added, return the codepoint ** of the ASCII letter only. For example, if passed 235 - "LATIN ** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER ** E"). The resuls of passing a codepoint that corresponds to an ** uppercase letter are undefined. */ static int remove_diacritic(int c, int bComplex){ unsigned short aDia[] = { 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896, 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106, 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344, 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468, 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704, 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914, 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218, 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766, 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118, 63182, 63242, 63274, 63310, 63368, 63390, }; #define HIBIT ((unsigned char)0x80) unsigned char aChar[] = { '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o', 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a', 'e', 'i', 'o', 'r', 'u', 's', 't', 'h', 'a', 'e', 'o'|HIBIT, 'o', 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 'a', 'b', 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT, 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT, 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n', 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's', 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT, 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT, 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y', }; unsigned int key = (((unsigned int)c)<<3) | 0x00000007; int iRes = 0; int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1; int iLo = 0; while( iHi>=iLo ){ int iTest = (iHi + iLo) / 2; if( key >= aDia[iTest] ){ iRes = iTest; iLo = iTest+1; }else{ iHi = iTest-1; } } assert( key>=aDia[iRes] ); if( bComplex==0 && (aChar[iRes] & 0x80) ) return c; return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F); } /* ** Return true if the argument interpreted as a unicode codepoint ** is a diacritical modifier character. */ SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int c){ unsigned int mask0 = 0x08029FDF; unsigned int mask1 = 0x000361F8; if( c<768 || c>817 ) return 0; return (c < 768+32) ? (mask0 & ((unsigned int)1 << (c-768))) : (mask1 & ((unsigned int)1 << (c-768-32))); } /* ** Interpret the argument as a unicode codepoint. If the codepoint ** is an upper case character that has a lower case equivalent, ** return the codepoint corresponding to the lower case version. ** Otherwise, return a copy of the argument. ** ** The results are undefined if the value passed to this function ** is less than zero. */ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ /* Each entry in the following array defines a rule for folding a range ** of codepoints to lower case. The rule applies to a range of nRange ** codepoints starting at codepoint iCode. ** ** If the least significant bit in flags is clear, then the rule applies ** to all nRange codepoints (i.e. all nRange codepoints are upper case and ** need to be folded). Or, if it is set, then the rule only applies to ** every second codepoint in the range, starting with codepoint C. ** ** The 7 most significant bits in flags are an index into the aiOff[] ** array. If a specific codepoint C does require folding, then its lower ** case equivalent is ((C + aiOff[flags>>1]) & 0xFFFF). ** ** The contents of this array are generated by parsing the CaseFolding.txt ** file distributed as part of the "Unicode Character Database". See ** http://www.unicode.org for details. */ static const struct TableEntry { unsigned short iCode; unsigned char flags; unsigned char nRange; } aEntry[] = { {65, 14, 26}, {181, 64, 1}, {192, 14, 23}, {216, 14, 7}, {256, 1, 48}, {306, 1, 6}, {313, 1, 16}, {330, 1, 46}, {376, 116, 1}, {377, 1, 6}, {383, 104, 1}, {385, 50, 1}, {386, 1, 4}, {390, 44, 1}, {391, 0, 1}, {393, 42, 2}, {395, 0, 1}, {398, 32, 1}, {399, 38, 1}, {400, 40, 1}, {401, 0, 1}, {403, 42, 1}, {404, 46, 1}, {406, 52, 1}, {407, 48, 1}, {408, 0, 1}, {412, 52, 1}, {413, 54, 1}, {415, 56, 1}, {416, 1, 6}, {422, 60, 1}, {423, 0, 1}, {425, 60, 1}, {428, 0, 1}, {430, 60, 1}, {431, 0, 1}, {433, 58, 2}, {435, 1, 4}, {439, 62, 1}, {440, 0, 1}, {444, 0, 1}, {452, 2, 1}, {453, 0, 1}, {455, 2, 1}, {456, 0, 1}, {458, 2, 1}, {459, 1, 18}, {478, 1, 18}, {497, 2, 1}, {498, 1, 4}, {502, 122, 1}, {503, 134, 1}, {504, 1, 40}, {544, 110, 1}, {546, 1, 18}, {570, 70, 1}, {571, 0, 1}, {573, 108, 1}, {574, 68, 1}, {577, 0, 1}, {579, 106, 1}, {580, 28, 1}, {581, 30, 1}, {582, 1, 10}, {837, 36, 1}, {880, 1, 4}, {886, 0, 1}, {902, 18, 1}, {904, 16, 3}, {908, 26, 1}, {910, 24, 2}, {913, 14, 17}, {931, 14, 9}, {962, 0, 1}, {975, 4, 1}, {976, 140, 1}, {977, 142, 1}, {981, 146, 1}, {982, 144, 1}, {984, 1, 24}, {1008, 136, 1}, {1009, 138, 1}, {1012, 130, 1}, {1013, 128, 1}, {1015, 0, 1}, {1017, 152, 1}, {1018, 0, 1}, {1021, 110, 3}, {1024, 34, 16}, {1040, 14, 32}, {1120, 1, 34}, {1162, 1, 54}, {1216, 6, 1}, {1217, 1, 14}, {1232, 1, 88}, {1329, 22, 38}, {4256, 66, 38}, {4295, 66, 1}, {4301, 66, 1}, {7680, 1, 150}, {7835, 132, 1}, {7838, 96, 1}, {7840, 1, 96}, {7944, 150, 8}, {7960, 150, 6}, {7976, 150, 8}, {7992, 150, 8}, {8008, 150, 6}, {8025, 151, 8}, {8040, 150, 8}, {8072, 150, 8}, {8088, 150, 8}, {8104, 150, 8}, {8120, 150, 2}, {8122, 126, 2}, {8124, 148, 1}, {8126, 100, 1}, {8136, 124, 4}, {8140, 148, 1}, {8152, 150, 2}, {8154, 120, 2}, {8168, 150, 2}, {8170, 118, 2}, {8172, 152, 1}, {8184, 112, 2}, {8186, 114, 2}, {8188, 148, 1}, {8486, 98, 1}, {8490, 92, 1}, {8491, 94, 1}, {8498, 12, 1}, {8544, 8, 16}, {8579, 0, 1}, {9398, 10, 26}, {11264, 22, 47}, {11360, 0, 1}, {11362, 88, 1}, {11363, 102, 1}, {11364, 90, 1}, {11367, 1, 6}, {11373, 84, 1}, {11374, 86, 1}, {11375, 80, 1}, {11376, 82, 1}, {11378, 0, 1}, {11381, 0, 1}, {11390, 78, 2}, {11392, 1, 100}, {11499, 1, 4}, {11506, 0, 1}, {42560, 1, 46}, {42624, 1, 24}, {42786, 1, 14}, {42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1}, {42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1}, {42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1}, {65313, 14, 26}, }; static const unsigned short aiOff[] = { 1, 2, 8, 15, 16, 26, 28, 32, 37, 38, 40, 48, 63, 64, 69, 71, 79, 80, 116, 202, 203, 205, 206, 207, 209, 210, 211, 213, 214, 217, 218, 219, 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721, 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274, 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406, 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462, 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511, 65514, 65521, 65527, 65528, 65529, }; int ret = c; assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 ); if( c<128 ){ if( c>='A' && c<='Z' ) ret = c + ('a' - 'A'); }else if( c<65536 ){ const struct TableEntry *p; int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; int iLo = 0; int iRes = -1; assert( c>aEntry[0].iCode ); while( iHi>=iLo ){ int iTest = (iHi + iLo) / 2; int cmp = (c - aEntry[iTest].iCode); if( cmp>=0 ){ iRes = iTest; iLo = iTest+1; }else{ iHi = iTest-1; } } assert( iRes>=0 && c>=aEntry[iRes].iCode ); p = &aEntry[iRes]; if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; assert( ret>0 ); } if( eRemoveDiacritic ){ ret = remove_diacritic(ret, eRemoveDiacritic==2); } } else if( c>=66560 && c<66600 ){ ret = c + 40; } return ret; } #endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */ #endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */ /************** End of fts3_unicode2.c ***************************************/ /************** Begin file json.c ********************************************/ /* ** 2015-08-12 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** SQLite JSON functions. ** ** This file began as an extension in ext/misc/json1.c in 2015. That ** extension proved so useful that it has now been moved into the core. ** ** The original design stored all JSON as pure text, canonical RFC-8259. ** Support for JSON-5 extensions was added with version 3.42.0 (2023-05-16). ** All generated JSON text still conforms strictly to RFC-8259, but text ** with JSON-5 extensions is accepted as input. ** ** Beginning with version 3.45.0 (circa 2024-01-01), these routines also ** accept BLOB values that have JSON encoded using a binary representation ** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk ** format SQLite JSONB is completely different and incompatible with ** PostgreSQL JSONB. ** ** Decoding and interpreting JSONB is still O(N) where N is the size of ** the input, the same as text JSON. However, the constant of proportionality ** for JSONB is much smaller due to faster parsing. The size of each ** element in JSONB is encoded in its header, so there is no need to search ** for delimiters using persnickety syntax rules. JSONB seems to be about ** 3x faster than text JSON as a result. JSONB is also tends to be slightly ** smaller than text JSON, by 5% or 10%, but there are corner cases where ** JSONB can be slightly larger. So you are not far mistaken to say that ** a JSONB blob is the same size as the equivalent RFC-8259 text. ** ** ** THE JSONB ENCODING: ** ** Every JSON element is encoded in JSONB as a header and a payload. ** The header is between 1 and 9 bytes in size. The payload is zero ** or more bytes. ** ** The lower 4 bits of the first byte of the header determines the ** element type: ** ** 0: NULL ** 1: TRUE ** 2: FALSE ** 3: INT -- RFC-8259 integer literal ** 4: INT5 -- JSON5 integer literal ** 5: FLOAT -- RFC-8259 floating point literal ** 6: FLOAT5 -- JSON5 floating point literal ** 7: TEXT -- Text literal acceptable to both SQL and JSON ** 8: TEXTJ -- Text containing RFC-8259 escapes ** 9: TEXT5 -- Text containing JSON5 and/or RFC-8259 escapes ** 10: TEXTRAW -- Text containing unescaped syntax characters ** 11: ARRAY ** 12: OBJECT ** ** The other three possible values (13-15) are reserved for future ** enhancements. ** ** The upper 4 bits of the first byte determine the size of the header ** and sometimes also the size of the payload. If X is the first byte ** of the element and if X>>4 is between 0 and 11, then the payload ** will be that many bytes in size and the header is exactly one byte ** in size. Other four values for X>>4 (12-15) indicate that the header ** is more than one byte in size and that the payload size is determined ** by the remainder of the header, interpreted as a unsigned big-endian ** integer. ** ** Value of X>>4 Size integer Total header size ** ------------- -------------------- ----------------- ** 12 1 byte (0-255) 2 ** 13 2 byte (0-65535) 3 ** 14 4 byte (0-4294967295) 5 ** 15 8 byte (0-1.8e19) 9 ** ** The payload size need not be expressed in its minimal form. For example, ** if the payload size is 10, the size can be expressed in any of 5 different ** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte, ** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by ** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and ** a single byte of 0x0a. The shorter forms are preferred, of course, but ** sometimes when generating JSONB, the payload size is not known in advance ** and it is convenient to reserve sufficient header space to cover the ** largest possible payload size and then come back later and patch up ** the size when it becomes known, resulting in a non-minimal encoding. ** ** The value (X>>4)==15 is not actually used in the current implementation ** (as SQLite is currently unable handle BLOBs larger than about 2GB) ** but is included in the design to allow for future enhancements. ** ** The payload follows the header. NULL, TRUE, and FALSE have no payload and ** their payload size must always be zero. The payload for INT, INT5, ** FLOAT, FLOAT5, TEXT, TEXTJ, TEXT5, and TEXTROW is text. Note that the ** "..." or '...' delimiters are omitted from the various text encodings. ** The payload for ARRAY and OBJECT is a list of additional elements that ** are the content for the array or object. The payload for an OBJECT ** must be an even number of elements. The first element of each pair is ** the label and must be of type TEXT, TEXTJ, TEXT5, or TEXTRAW. ** ** A valid JSONB blob consists of a single element, as described above. ** Usually this will be an ARRAY or OBJECT element which has many more ** elements as its content. But the overall blob is just a single element. ** ** Input validation for JSONB blobs simply checks that the element type ** code is between 0 and 12 and that the total size of the element ** (header plus payload) is the same as the size of the BLOB. If those ** checks are true, the BLOB is assumed to be JSONB and processing continues. ** Errors are only raised if some other miscoding is discovered during ** processing. ** ** Additional information can be found in the doc/jsonb.md file of the ** canonical SQLite source tree. */ #ifndef SQLITE_OMIT_JSON /* #include "sqliteInt.h" */ /* JSONB element types */ #define JSONB_NULL 0 /* "null" */ #define JSONB_TRUE 1 /* "true" */ #define JSONB_FALSE 2 /* "false" */ #define JSONB_INT 3 /* integer acceptable to JSON and SQL */ #define JSONB_INT5 4 /* integer in 0x000 notation */ #define JSONB_FLOAT 5 /* float acceptable to JSON and SQL */ #define JSONB_FLOAT5 6 /* float with JSON5 extensions */ #define JSONB_TEXT 7 /* Text compatible with both JSON and SQL */ #define JSONB_TEXTJ 8 /* Text with JSON escapes */ #define JSONB_TEXT5 9 /* Text with JSON-5 escape */ #define JSONB_TEXTRAW 10 /* SQL text that needs escaping for JSON */ #define JSONB_ARRAY 11 /* An array */ #define JSONB_OBJECT 12 /* An object */ /* Human-readable names for the JSONB values. The index for each ** string must correspond to the JSONB_* integer above. */ static const char * const jsonbType[] = { "null", "true", "false", "integer", "integer", "real", "real", "text", "text", "text", "text", "array", "object", "", "", "", "" }; /* ** Growing our own isspace() routine this way is twice as fast as ** the library isspace() function, resulting in a 7% overall performance ** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). */ static const char jsonIsSpace[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #define jsonIsspace(x) (jsonIsSpace[(unsigned char)x]) /* ** The set of all space characters recognized by jsonIsspace(). ** Useful as the second argument to strspn(). */ static const char jsonSpaces[] = "\011\012\015\040"; /* ** Characters that are special to JSON. Control characters, ** '"' and '\\' and '\''. Actually, '\'' is not special to ** canonical JSON, but it is special in JSON-5, so we include ** it in the set of special characters. */ static const char jsonIsOk[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; /* Objects */ typedef struct JsonCache JsonCache; typedef struct JsonString JsonString; typedef struct JsonParse JsonParse; /* ** Magic number used for the JSON parse cache in sqlite3_get_auxdata() */ #define JSON_CACHE_ID (-429938) /* Cache entry */ #define JSON_CACHE_SIZE 4 /* Max number of cache entries */ /* ** jsonUnescapeOneChar() returns this invalid code point if it encounters ** a syntax error. */ #define JSON_INVALID_CHAR 0x99999 /* A cache mapping JSON text into JSONB blobs. ** ** Each cache entry is a JsonParse object with the following restrictions: ** ** * The bReadOnly flag must be set ** ** * The aBlob[] array must be owned by the JsonParse object. In other ** words, nBlobAlloc must be non-zero. ** ** * eEdit and delta must be zero. ** ** * zJson must be an RCStr. In other words bJsonIsRCStr must be true. */ struct JsonCache { sqlite3 *db; /* Database connection */ int nUsed; /* Number of active entries in the cache */ JsonParse *a[JSON_CACHE_SIZE]; /* One line for each cache entry */ }; /* An instance of this object represents a JSON string ** under construction. Really, this is a generic string accumulator ** that can be and is used to create strings other than JSON. ** ** If the generated string is longer than will fit into the zSpace[] buffer, ** then it will be an RCStr string. This aids with caching of large ** JSON strings. */ struct JsonString { sqlite3_context *pCtx; /* Function context - put error messages here */ char *zBuf; /* Append JSON content here */ u64 nAlloc; /* Bytes of storage available in zBuf[] */ u64 nUsed; /* Bytes of zBuf[] currently used */ u8 bStatic; /* True if zBuf is static space */ u8 eErr; /* True if an error has been encountered */ char zSpace[100]; /* Initial static space */ }; /* Allowed values for JsonString.eErr */ #define JSTRING_OOM 0x01 /* Out of memory */ #define JSTRING_MALFORMED 0x02 /* Malformed JSONB */ #define JSTRING_ERR 0x04 /* Error already sent to sqlite3_result */ /* The "subtype" set for text JSON values passed through using ** sqlite3_result_subtype() and sqlite3_value_subtype(). */ #define JSON_SUBTYPE 74 /* Ascii for "J" */ /* ** Bit values for the flags passed into various SQL function implementations ** via the sqlite3_user_data() value. */ #define JSON_JSON 0x01 /* Result is always JSON */ #define JSON_SQL 0x02 /* Result is always SQL */ #define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */ #define JSON_ISSET 0x04 /* json_set(), not json_insert() */ #define JSON_BLOB 0x08 /* Use the BLOB output format */ /* A parsed JSON value. Lifecycle: ** ** 1. JSON comes in and is parsed into a JSONB value in aBlob. The ** original text is stored in zJson. This step is skipped if the ** input is JSONB instead of text JSON. ** ** 2. The aBlob[] array is searched using the JSON path notation, if needed. ** ** 3. Zero or more changes are made to aBlob[] (via json_remove() or ** json_replace() or json_patch() or similar). ** ** 4. New JSON text is generated from the aBlob[] for output. This step ** is skipped if the function is one of the jsonb_* functions that ** returns JSONB instead of text JSON. */ struct JsonParse { u8 *aBlob; /* JSONB representation of JSON value */ u32 nBlob; /* Bytes of aBlob[] actually used */ u32 nBlobAlloc; /* Bytes allocated to aBlob[]. 0 if aBlob is external */ char *zJson; /* Json text used for parsing */ sqlite3 *db; /* The database connection to which this object belongs */ int nJson; /* Length of the zJson string in bytes */ u32 nJPRef; /* Number of references to this object */ u32 iErr; /* Error location in zJson[] */ u16 iDepth; /* Nesting depth */ u8 nErr; /* Number of errors seen */ u8 oom; /* Set to true if out of memory */ u8 bJsonIsRCStr; /* True if zJson is an RCStr */ u8 hasNonstd; /* True if input uses non-standard features like JSON5 */ u8 bReadOnly; /* Do not modify. */ /* Search and edit information. See jsonLookupStep() */ u8 eEdit; /* Edit operation to apply */ int delta; /* Size change due to the edit */ u32 nIns; /* Number of bytes to insert */ u32 iLabel; /* Location of label if search landed on an object value */ u8 *aIns; /* Content to be inserted */ }; /* Allowed values for JsonParse.eEdit */ #define JEDIT_DEL 1 /* Delete if exists */ #define JEDIT_REPL 2 /* Overwrite if exists */ #define JEDIT_INS 3 /* Insert if not exists */ #define JEDIT_SET 4 /* Insert or overwrite */ /* ** Maximum nesting depth of JSON for this implementation. ** ** This limit is needed to avoid a stack overflow in the recursive ** descent parser. A depth of 1000 is far deeper than any sane JSON ** should go. Historical note: This limit was 2000 prior to version 3.42.0 */ #ifndef SQLITE_JSON_MAX_DEPTH # define JSON_MAX_DEPTH 1000 #else # define JSON_MAX_DEPTH SQLITE_JSON_MAX_DEPTH #endif /* ** Allowed values for the flgs argument to jsonParseFuncArg(); */ #define JSON_EDITABLE 0x01 /* Generate a writable JsonParse object */ #define JSON_KEEPERROR 0x02 /* Return non-NULL even if there is an error */ /************************************************************************** ** Forward references **************************************************************************/ static void jsonReturnStringAsBlob(JsonString*); static int jsonFuncArgMightBeBinary(sqlite3_value *pJson); static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); static void jsonReturnParse(sqlite3_context*,JsonParse*); static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); static void jsonParseFree(JsonParse*); static u32 jsonbPayloadSize(const JsonParse*, u32, u32*); static u32 jsonUnescapeOneChar(const char*, u32, u32*); /************************************************************************** ** Utility routines for dealing with JsonCache objects **************************************************************************/ /* ** Free a JsonCache object. */ static void jsonCacheDelete(JsonCache *p){ int i; for(i=0; inUsed; i++){ jsonParseFree(p->a[i]); } sqlite3DbFree(p->db, p); } static void jsonCacheDeleteGeneric(void *p){ jsonCacheDelete((JsonCache*)p); } /* ** Insert a new entry into the cache. If the cache is full, expel ** the least recently used entry. Return SQLITE_OK on success or a ** result code otherwise. ** ** Cache entries are stored in age order, oldest first. */ static int jsonCacheInsert( sqlite3_context *ctx, /* The SQL statement context holding the cache */ JsonParse *pParse /* The parse object to be added to the cache */ ){ JsonCache *p; assert( pParse->zJson!=0 ); assert( pParse->bJsonIsRCStr ); assert( pParse->delta==0 ); p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); if( p==0 ){ sqlite3 *db = sqlite3_context_db_handle(ctx); p = sqlite3DbMallocZero(db, sizeof(*p)); if( p==0 ) return SQLITE_NOMEM; p->db = db; sqlite3_set_auxdata(ctx, JSON_CACHE_ID, p, jsonCacheDeleteGeneric); p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); if( p==0 ) return SQLITE_NOMEM; } if( p->nUsed >= JSON_CACHE_SIZE ){ jsonParseFree(p->a[0]); memmove(p->a, &p->a[1], (JSON_CACHE_SIZE-1)*sizeof(p->a[0])); p->nUsed = JSON_CACHE_SIZE-1; } assert( pParse->nBlobAlloc>0 ); pParse->eEdit = 0; pParse->nJPRef++; pParse->bReadOnly = 1; p->a[p->nUsed] = pParse; p->nUsed++; return SQLITE_OK; } /* ** Search for a cached translation the json text supplied by pArg. Return ** the JsonParse object if found. Return NULL if not found. ** ** When a match if found, the matching entry is moved to become the ** most-recently used entry if it isn't so already. ** ** The JsonParse object returned still belongs to the Cache and might ** be deleted at any moment. If the caller whants the JsonParse to ** linger, it needs to increment the nPJRef reference counter. */ static JsonParse *jsonCacheSearch( sqlite3_context *ctx, /* The SQL statement context holding the cache */ sqlite3_value *pArg /* Function argument containing SQL text */ ){ JsonCache *p; int i; const char *zJson; int nJson; if( sqlite3_value_type(pArg)!=SQLITE_TEXT ){ return 0; } zJson = (const char*)sqlite3_value_text(pArg); if( zJson==0 ) return 0; nJson = sqlite3_value_bytes(pArg); p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); if( p==0 ){ return 0; } for(i=0; inUsed; i++){ if( p->a[i]->zJson==zJson ) break; } if( i>=p->nUsed ){ for(i=0; inUsed; i++){ if( p->a[i]->nJson!=nJson ) continue; if( memcmp(p->a[i]->zJson, zJson, nJson)==0 ) break; } } if( inUsed ){ if( inUsed-1 ){ /* Make the matching entry the most recently used entry */ JsonParse *tmp = p->a[i]; memmove(&p->a[i], &p->a[i+1], (p->nUsed-i-1)*sizeof(tmp)); p->a[p->nUsed-1] = tmp; i = p->nUsed - 1; } assert( p->a[i]->delta==0 ); return p->a[i]; }else{ return 0; } } /************************************************************************** ** Utility routines for dealing with JsonString objects **************************************************************************/ /* Turn uninitialized bulk memory into a valid JsonString object ** holding a zero-length string. */ static void jsonStringZero(JsonString *p){ p->zBuf = p->zSpace; p->nAlloc = sizeof(p->zSpace); p->nUsed = 0; p->bStatic = 1; } /* Initialize the JsonString object */ static void jsonStringInit(JsonString *p, sqlite3_context *pCtx){ p->pCtx = pCtx; p->eErr = 0; jsonStringZero(p); } /* Free all allocated memory and reset the JsonString object back to its ** initial state. */ static void jsonStringReset(JsonString *p){ if( !p->bStatic ) sqlite3RCStrUnref(p->zBuf); jsonStringZero(p); } /* Report an out-of-memory (OOM) condition */ static void jsonStringOom(JsonString *p){ p->eErr |= JSTRING_OOM; if( p->pCtx ) sqlite3_result_error_nomem(p->pCtx); jsonStringReset(p); } /* Enlarge pJson->zBuf so that it can hold at least N more bytes. ** Return zero on success. Return non-zero on an OOM error */ static int jsonStringGrow(JsonString *p, u32 N){ u64 nTotal = NnAlloc ? p->nAlloc*2 : p->nAlloc+N+10; char *zNew; if( p->bStatic ){ if( p->eErr ) return 1; zNew = sqlite3RCStrNew(nTotal); if( zNew==0 ){ jsonStringOom(p); return SQLITE_NOMEM; } memcpy(zNew, p->zBuf, (size_t)p->nUsed); p->zBuf = zNew; p->bStatic = 0; }else{ p->zBuf = sqlite3RCStrResize(p->zBuf, nTotal); if( p->zBuf==0 ){ p->eErr |= JSTRING_OOM; jsonStringZero(p); return SQLITE_NOMEM; } } p->nAlloc = nTotal; return SQLITE_OK; } /* Append N bytes from zIn onto the end of the JsonString string. */ static SQLITE_NOINLINE void jsonStringExpandAndAppend( JsonString *p, const char *zIn, u32 N ){ assert( N>0 ); if( jsonStringGrow(p,N) ) return; memcpy(p->zBuf+p->nUsed, zIn, N); p->nUsed += N; } static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ if( N==0 ) return; if( N+p->nUsed >= p->nAlloc ){ jsonStringExpandAndAppend(p,zIn,N); }else{ memcpy(p->zBuf+p->nUsed, zIn, N); p->nUsed += N; } } static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){ assert( N>0 ); if( N+p->nUsed >= p->nAlloc ){ jsonStringExpandAndAppend(p,zIn,N); }else{ memcpy(p->zBuf+p->nUsed, zIn, N); p->nUsed += N; } } /* Append formatted text (not to exceed N bytes) to the JsonString. */ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ va_list ap; if( (p->nUsed + N >= p->nAlloc) && jsonStringGrow(p, N) ) return; va_start(ap, zFormat); sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); va_end(ap); p->nUsed += (int)strlen(p->zBuf+p->nUsed); } /* Append a single character */ static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){ if( jsonStringGrow(p,1) ) return; p->zBuf[p->nUsed++] = c; } static void jsonAppendChar(JsonString *p, char c){ if( p->nUsed>=p->nAlloc ){ jsonAppendCharExpand(p,c); }else{ p->zBuf[p->nUsed++] = c; } } /* Remove a single character from the end of the string */ static void jsonStringTrimOneChar(JsonString *p){ if( p->eErr==0 ){ assert( p->nUsed>0 ); p->nUsed--; } } /* Make sure there is a zero terminator on p->zBuf[] ** ** Return true on success. Return false if an OOM prevents this ** from happening. */ static int jsonStringTerminate(JsonString *p){ jsonAppendChar(p, 0); jsonStringTrimOneChar(p); return p->eErr==0; } /* Append a comma separator to the output buffer, if the previous ** character is not '[' or '{'. */ static void jsonAppendSeparator(JsonString *p){ char c; if( p->nUsed==0 ) return; c = p->zBuf[p->nUsed-1]; if( c=='[' || c=='{' ) return; jsonAppendChar(p, ','); } /* Append the N-byte string in zIn to the end of the JsonString string ** under construction. Enclose the string in double-quotes ("...") and ** escape any double-quotes or backslash characters contained within the ** string. ** ** This routine is a high-runner. There is a measurable performance ** increase associated with unwinding the jsonIsOk[] loop. */ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ u32 k; u8 c; const u8 *z = (const u8*)zIn; if( z==0 ) return; if( (N+p->nUsed+2 >= p->nAlloc) && jsonStringGrow(p,N+2)!=0 ) return; p->zBuf[p->nUsed++] = '"'; while( 1 /*exit-by-break*/ ){ k = 0; /* The following while() is the 4-way unwound equivalent of ** ** while( k=N ){ while( k=N ){ if( k>0 ){ memcpy(&p->zBuf[p->nUsed], z, k); p->nUsed += k; } break; } if( k>0 ){ memcpy(&p->zBuf[p->nUsed], z, k); p->nUsed += k; z += k; N -= k; } c = z[0]; if( c=='"' || c=='\\' ){ json_simple_escape: if( (p->nUsed+N+3 > p->nAlloc) && jsonStringGrow(p,N+3)!=0 ) return; p->zBuf[p->nUsed++] = '\\'; p->zBuf[p->nUsed++] = c; }else if( c=='\'' ){ p->zBuf[p->nUsed++] = c; }else{ static const char aSpecial[] = { 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; assert( sizeof(aSpecial)==32 ); assert( aSpecial['\b']=='b' ); assert( aSpecial['\f']=='f' ); assert( aSpecial['\n']=='n' ); assert( aSpecial['\r']=='r' ); assert( aSpecial['\t']=='t' ); assert( c>=0 && cnUsed+N+7 > p->nAlloc) && jsonStringGrow(p,N+7)!=0 ) return; p->zBuf[p->nUsed++] = '\\'; p->zBuf[p->nUsed++] = 'u'; p->zBuf[p->nUsed++] = '0'; p->zBuf[p->nUsed++] = '0'; p->zBuf[p->nUsed++] = "0123456789abcdef"[c>>4]; p->zBuf[p->nUsed++] = "0123456789abcdef"[c&0xf]; } z++; N--; } p->zBuf[p->nUsed++] = '"'; assert( p->nUsednAlloc ); } /* ** Append an sqlite3_value (such as a function parameter) to the JSON ** string under construction in p. */ static void jsonAppendSqlValue( JsonString *p, /* Append to this JSON string */ sqlite3_value *pValue /* Value to append */ ){ switch( sqlite3_value_type(pValue) ){ case SQLITE_NULL: { jsonAppendRawNZ(p, "null", 4); break; } case SQLITE_FLOAT: { jsonPrintf(100, p, "%!0.15g", sqlite3_value_double(pValue)); break; } case SQLITE_INTEGER: { const char *z = (const char*)sqlite3_value_text(pValue); u32 n = (u32)sqlite3_value_bytes(pValue); jsonAppendRaw(p, z, n); break; } case SQLITE_TEXT: { const char *z = (const char*)sqlite3_value_text(pValue); u32 n = (u32)sqlite3_value_bytes(pValue); if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){ jsonAppendRaw(p, z, n); }else{ jsonAppendString(p, z, n); } break; } default: { if( jsonFuncArgMightBeBinary(pValue) ){ JsonParse px; memset(&px, 0, sizeof(px)); px.aBlob = (u8*)sqlite3_value_blob(pValue); px.nBlob = sqlite3_value_bytes(pValue); jsonTranslateBlobToText(&px, 0, p); }else if( p->eErr==0 ){ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); p->eErr = JSTRING_ERR; jsonStringReset(p); } break; } } } /* Make the text in p (which is probably a generated JSON text string) ** the result of the SQL function. ** ** The JsonString is reset. ** ** If pParse and ctx are both non-NULL, then the SQL string in p is ** loaded into the zJson field of the pParse object as a RCStr and the ** pParse is added to the cache. */ static void jsonReturnString( JsonString *p, /* String to return */ JsonParse *pParse, /* JSONB source or NULL */ sqlite3_context *ctx /* Where to cache */ ){ assert( (pParse!=0)==(ctx!=0) ); assert( ctx==0 || ctx==p->pCtx ); if( p->eErr==0 ){ int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(p->pCtx)); if( flags & JSON_BLOB ){ jsonReturnStringAsBlob(p); }else if( p->bStatic ){ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, SQLITE_TRANSIENT, SQLITE_UTF8); }else if( jsonStringTerminate(p) ){ if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){ int rc; pParse->zJson = sqlite3RCStrRef(p->zBuf); pParse->nJson = p->nUsed; pParse->bJsonIsRCStr = 1; rc = jsonCacheInsert(ctx, pParse); if( rc==SQLITE_NOMEM ){ sqlite3_result_error_nomem(ctx); jsonStringReset(p); return; } } sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed, sqlite3RCStrUnref, SQLITE_UTF8); }else{ sqlite3_result_error_nomem(p->pCtx); } }else if( p->eErr & JSTRING_OOM ){ sqlite3_result_error_nomem(p->pCtx); }else if( p->eErr & JSTRING_MALFORMED ){ sqlite3_result_error(p->pCtx, "malformed JSON", -1); } jsonStringReset(p); } /************************************************************************** ** Utility routines for dealing with JsonParse objects **************************************************************************/ /* ** Reclaim all memory allocated by a JsonParse object. But do not ** delete the JsonParse object itself. */ static void jsonParseReset(JsonParse *pParse){ assert( pParse->nJPRef<=1 ); if( pParse->bJsonIsRCStr ){ sqlite3RCStrUnref(pParse->zJson); pParse->zJson = 0; pParse->nJson = 0; pParse->bJsonIsRCStr = 0; } if( pParse->nBlobAlloc ){ sqlite3DbFree(pParse->db, pParse->aBlob); pParse->aBlob = 0; pParse->nBlob = 0; pParse->nBlobAlloc = 0; } } /* ** Decrement the reference count on the JsonParse object. When the ** count reaches zero, free the object. */ static void jsonParseFree(JsonParse *pParse){ if( pParse ){ if( pParse->nJPRef>1 ){ pParse->nJPRef--; }else{ jsonParseReset(pParse); sqlite3DbFree(pParse->db, pParse); } } } /************************************************************************** ** Utility routines for the JSON text parser **************************************************************************/ /* ** Translate a single byte of Hex into an integer. ** This routine only gives a correct answer if h really is a valid hexadecimal ** character: 0..9a..fA..F. But unlike sqlite3HexToInt(), it does not ** assert() if the digit is not hex. */ static u8 jsonHexToInt(int h){ #ifdef SQLITE_ASCII h += 9*(1&(h>>6)); #endif #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); #endif return (u8)(h & 0xf); } /* ** Convert a 4-byte hex string into an integer */ static u32 jsonHexToInt4(const char *z){ u32 v; v = (jsonHexToInt(z[0])<<12) + (jsonHexToInt(z[1])<<8) + (jsonHexToInt(z[2])<<4) + jsonHexToInt(z[3]); return v; } /* ** Return true if z[] begins with 2 (or more) hexadecimal digits */ static int jsonIs2Hex(const char *z){ return sqlite3Isxdigit(z[0]) && sqlite3Isxdigit(z[1]); } /* ** Return true if z[] begins with 4 (or more) hexadecimal digits */ static int jsonIs4Hex(const char *z){ return jsonIs2Hex(z) && jsonIs2Hex(&z[2]); } /* ** Return the number of bytes of JSON5 whitespace at the beginning of ** the input string z[]. ** ** JSON5 whitespace consists of any of the following characters: ** ** Unicode UTF-8 Name ** U+0009 09 horizontal tab ** U+000a 0a line feed ** U+000b 0b vertical tab ** U+000c 0c form feed ** U+000d 0d carriage return ** U+0020 20 space ** U+00a0 c2 a0 non-breaking space ** U+1680 e1 9a 80 ogham space mark ** U+2000 e2 80 80 en quad ** U+2001 e2 80 81 em quad ** U+2002 e2 80 82 en space ** U+2003 e2 80 83 em space ** U+2004 e2 80 84 three-per-em space ** U+2005 e2 80 85 four-per-em space ** U+2006 e2 80 86 six-per-em space ** U+2007 e2 80 87 figure space ** U+2008 e2 80 88 punctuation space ** U+2009 e2 80 89 thin space ** U+200a e2 80 8a hair space ** U+2028 e2 80 a8 line separator ** U+2029 e2 80 a9 paragraph separator ** U+202f e2 80 af narrow no-break space (NNBSP) ** U+205f e2 81 9f medium mathematical space (MMSP) ** U+3000 e3 80 80 ideographical space ** U+FEFF ef bb bf byte order mark ** ** In addition, comments between '/', '*' and '*', '/' and ** from '/', '/' to end-of-line are also considered to be whitespace. */ static int json5Whitespace(const char *zIn){ int n = 0; const u8 *z = (u8*)zIn; while( 1 /*exit by "goto whitespace_done"*/ ){ switch( z[n] ){ case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x20: { n++; break; } case '/': { if( z[n+1]=='*' && z[n+2]!=0 ){ int j; for(j=n+3; z[j]!='/' || z[j-1]!='*'; j++){ if( z[j]==0 ) goto whitespace_done; } n = j+1; break; }else if( z[n+1]=='/' ){ int j; char c; for(j=n+2; (c = z[j])!=0; j++){ if( c=='\n' || c=='\r' ) break; if( 0xe2==(u8)c && 0x80==(u8)z[j+1] && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]) ){ j += 2; break; } } n = j; if( z[n] ) n++; break; } goto whitespace_done; } case 0xc2: { if( z[n+1]==0xa0 ){ n += 2; break; } goto whitespace_done; } case 0xe1: { if( z[n+1]==0x9a && z[n+2]==0x80 ){ n += 3; break; } goto whitespace_done; } case 0xe2: { if( z[n+1]==0x80 ){ u8 c = z[n+2]; if( c<0x80 ) goto whitespace_done; if( c<=0x8a || c==0xa8 || c==0xa9 || c==0xaf ){ n += 3; break; } }else if( z[n+1]==0x81 && z[n+2]==0x9f ){ n += 3; break; } goto whitespace_done; } case 0xe3: { if( z[n+1]==0x80 && z[n+2]==0x80 ){ n += 3; break; } goto whitespace_done; } case 0xef: { if( z[n+1]==0xbb && z[n+2]==0xbf ){ n += 3; break; } goto whitespace_done; } default: { goto whitespace_done; } } } whitespace_done: return n; } /* ** Extra floating-point literals to allow in JSON. */ static const struct NanInfName { char c1; char c2; char n; char eType; char nRepl; char *zMatch; char *zRepl; } aNanInfName[] = { { 'i', 'I', 3, JSONB_FLOAT, 7, "inf", "9.0e999" }, { 'i', 'I', 8, JSONB_FLOAT, 7, "infinity", "9.0e999" }, { 'n', 'N', 3, JSONB_NULL, 4, "NaN", "null" }, { 'q', 'Q', 4, JSONB_NULL, 4, "QNaN", "null" }, { 's', 'S', 4, JSONB_NULL, 4, "SNaN", "null" }, }; /* ** Report the wrong number of arguments for json_insert(), json_replace() ** or json_set(). */ static void jsonWrongNumArgs( sqlite3_context *pCtx, const char *zFuncName ){ char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", zFuncName); sqlite3_result_error(pCtx, zMsg, -1); sqlite3_free(zMsg); } /**************************************************************************** ** Utility routines for dealing with the binary BLOB representation of JSON ****************************************************************************/ /* ** Expand pParse->aBlob so that it holds at least N bytes. ** ** Return the number of errors. */ static int jsonBlobExpand(JsonParse *pParse, u32 N){ u8 *aNew; u32 t; assert( N>pParse->nBlobAlloc ); if( pParse->nBlobAlloc==0 ){ t = 100; }else{ t = pParse->nBlobAlloc*2; } if( tdb, pParse->aBlob, t); if( aNew==0 ){ pParse->oom = 1; return 1; } pParse->aBlob = aNew; pParse->nBlobAlloc = t; return 0; } /* ** If pParse->aBlob is not previously editable (because it is taken ** from sqlite3_value_blob(), as indicated by the fact that ** pParse->nBlobAlloc==0 and pParse->nBlob>0) then make it editable ** by making a copy into space obtained from malloc. ** ** Return true on success. Return false on OOM. */ static int jsonBlobMakeEditable(JsonParse *pParse, u32 nExtra){ u8 *aOld; u32 nSize; assert( !pParse->bReadOnly ); if( pParse->oom ) return 0; if( pParse->nBlobAlloc>0 ) return 1; aOld = pParse->aBlob; nSize = pParse->nBlob + nExtra; pParse->aBlob = 0; if( jsonBlobExpand(pParse, nSize) ){ return 0; } assert( pParse->nBlobAlloc >= pParse->nBlob + nExtra ); memcpy(pParse->aBlob, aOld, pParse->nBlob); return 1; } /* Expand pParse->aBlob and append one bytes. */ static SQLITE_NOINLINE void jsonBlobExpandAndAppendOneByte( JsonParse *pParse, u8 c ){ jsonBlobExpand(pParse, pParse->nBlob+1); if( pParse->oom==0 ){ assert( pParse->nBlob+1<=pParse->nBlobAlloc ); pParse->aBlob[pParse->nBlob++] = c; } } /* Append a single character. */ static void jsonBlobAppendOneByte(JsonParse *pParse, u8 c){ if( pParse->nBlob >= pParse->nBlobAlloc ){ jsonBlobExpandAndAppendOneByte(pParse, c); }else{ pParse->aBlob[pParse->nBlob++] = c; } } /* Slow version of jsonBlobAppendNode() that first resizes the ** pParse->aBlob structure. */ static void jsonBlobAppendNode(JsonParse*,u8,u32,const void*); static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( JsonParse *pParse, u8 eType, u32 szPayload, const void *aPayload ){ if( jsonBlobExpand(pParse, pParse->nBlob+szPayload+9) ) return; jsonBlobAppendNode(pParse, eType, szPayload, aPayload); } /* Append an node type byte together with the payload size and ** possibly also the payload. ** ** If aPayload is not NULL, then it is a pointer to the payload which ** is also appended. If aPayload is NULL, the pParse->aBlob[] array ** is resized (if necessary) so that it is big enough to hold the ** payload, but the payload is not appended and pParse->nBlob is left ** pointing to where the first byte of payload will eventually be. */ static void jsonBlobAppendNode( JsonParse *pParse, /* The JsonParse object under construction */ u8 eType, /* Node type. One of JSONB_* */ u32 szPayload, /* Number of bytes of payload */ const void *aPayload /* The payload. Might be NULL */ ){ u8 *a; if( pParse->nBlob+szPayload+9 > pParse->nBlobAlloc ){ jsonBlobExpandAndAppendNode(pParse,eType,szPayload,aPayload); return; } assert( pParse->aBlob!=0 ); a = &pParse->aBlob[pParse->nBlob]; if( szPayload<=11 ){ a[0] = eType | (szPayload<<4); pParse->nBlob += 1; }else if( szPayload<=0xff ){ a[0] = eType | 0xc0; a[1] = szPayload & 0xff; pParse->nBlob += 2; }else if( szPayload<=0xffff ){ a[0] = eType | 0xd0; a[1] = (szPayload >> 8) & 0xff; a[2] = szPayload & 0xff; pParse->nBlob += 3; }else{ a[0] = eType | 0xe0; a[1] = (szPayload >> 24) & 0xff; a[2] = (szPayload >> 16) & 0xff; a[3] = (szPayload >> 8) & 0xff; a[4] = szPayload & 0xff; pParse->nBlob += 5; } if( aPayload ){ pParse->nBlob += szPayload; memcpy(&pParse->aBlob[pParse->nBlob-szPayload], aPayload, szPayload); } } /* Change the payload size for the node at index i to be szPayload. */ static int jsonBlobChangePayloadSize( JsonParse *pParse, u32 i, u32 szPayload ){ u8 *a; u8 szType; u8 nExtra; u8 nNeeded; int delta; if( pParse->oom ) return 0; a = &pParse->aBlob[i]; szType = a[0]>>4; if( szType<=11 ){ nExtra = 0; }else if( szType==12 ){ nExtra = 1; }else if( szType==13 ){ nExtra = 2; }else{ nExtra = 4; } if( szPayload<=11 ){ nNeeded = 0; }else if( szPayload<=0xff ){ nNeeded = 1; }else if( szPayload<=0xffff ){ nNeeded = 2; }else{ nNeeded = 4; } delta = nNeeded - nExtra; if( delta ){ u32 newSize = pParse->nBlob + delta; if( delta>0 ){ if( newSize>pParse->nBlobAlloc && jsonBlobExpand(pParse, newSize) ){ return 0; /* OOM error. Error state recorded in pParse->oom. */ } a = &pParse->aBlob[i]; memmove(&a[1+delta], &a[1], pParse->nBlob - (i+1)); }else{ memmove(&a[1], &a[1-delta], pParse->nBlob - (i+1-delta)); } pParse->nBlob = newSize; } if( nNeeded==0 ){ a[0] = (a[0] & 0x0f) | (szPayload<<4); }else if( nNeeded==1 ){ a[0] = (a[0] & 0x0f) | 0xc0; a[1] = szPayload & 0xff; }else if( nNeeded==2 ){ a[0] = (a[0] & 0x0f) | 0xd0; a[1] = (szPayload >> 8) & 0xff; a[2] = szPayload & 0xff; }else{ a[0] = (a[0] & 0x0f) | 0xe0; a[1] = (szPayload >> 24) & 0xff; a[2] = (szPayload >> 16) & 0xff; a[3] = (szPayload >> 8) & 0xff; a[4] = szPayload & 0xff; } return delta; } /* ** If z[0] is 'u' and is followed by exactly 4 hexadecimal character, ** then set *pOp to JSONB_TEXTJ and return true. If not, do not make ** any changes to *pOp and return false. */ static int jsonIs4HexB(const char *z, int *pOp){ if( z[0]!='u' ) return 0; if( !jsonIs4Hex(&z[1]) ) return 0; *pOp = JSONB_TEXTJ; return 1; } /* ** Check a single element of the JSONB in pParse for validity. ** ** The element to be checked starts at offset i and must end at on the ** last byte before iEnd. ** ** Return 0 if everything is correct. Return the 1-based byte offset of the ** error if a problem is detected. (In other words, if the error is at offset ** 0, return 1). */ static u32 jsonbValidityCheck( const JsonParse *pParse, /* Input JSONB. Only aBlob and nBlob are used */ u32 i, /* Start of element as pParse->aBlob[i] */ u32 iEnd, /* One more than the last byte of the element */ u32 iDepth /* Current nesting depth */ ){ u32 n, sz, j, k; const u8 *z; u8 x; if( iDepth>JSON_MAX_DEPTH ) return i+1; sz = 0; n = jsonbPayloadSize(pParse, i, &sz); if( NEVER(n==0) ) return i+1; /* Checked by caller */ if( NEVER(i+n+sz!=iEnd) ) return i+1; /* Checked by caller */ z = pParse->aBlob; x = z[i] & 0x0f; switch( x ){ case JSONB_NULL: case JSONB_TRUE: case JSONB_FALSE: { return n+sz==1 ? 0 : i+1; } case JSONB_INT: { if( sz<1 ) return i+1; j = i+n; if( z[j]=='-' ){ j++; if( sz<2 ) return i+1; } k = i+n+sz; while( jk ) return j+1; if( z[j+1]!='.' && z[j+1]!='e' && z[j+1]!='E' ) return j+1; j++; } for(; j0 ) return j+1; if( x==JSONB_FLOAT && (j==k-1 || !sqlite3Isdigit(z[j+1])) ){ return j+1; } seen = 1; continue; } if( z[j]=='e' || z[j]=='E' ){ if( seen==2 ) return j+1; if( j==k-1 ) return j+1; if( z[j+1]=='+' || z[j+1]=='-' ){ j++; if( j==k-1 ) return j+1; } seen = 2; continue; } return j+1; } if( seen==0 ) return i+1; return 0; } case JSONB_TEXT: { j = i+n; k = j+sz; while( j=k ){ return j+1; }else if( strchr("\"\\/bfnrt",z[j+1])!=0 ){ j++; }else if( z[j+1]=='u' ){ if( j+5>=k ) return j+1; if( !jsonIs4Hex((const char*)&z[j+2]) ) return j+1; j++; }else if( x!=JSONB_TEXT5 ){ return j+1; }else{ u32 c = 0; u32 szC = jsonUnescapeOneChar((const char*)&z[j], k-j, &c); if( c==JSON_INVALID_CHAR ) return j+1; j += szC - 1; } } j++; } return 0; } case JSONB_TEXTRAW: { return 0; } case JSONB_ARRAY: { u32 sub; j = i+n; k = j+sz; while( jk ) return j+1; sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1); if( sub ) return sub; j += n + sz; } assert( j==k ); return 0; } case JSONB_OBJECT: { u32 cnt = 0; u32 sub; j = i+n; k = j+sz; while( jk ) return j+1; if( (cnt & 1)==0 ){ x = z[j] & 0x0f; if( xJSONB_TEXTRAW ) return j+1; } sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1); if( sub ) return sub; cnt++; j += n + sz; } assert( j==k ); if( (cnt & 1)!=0 ) return j+1; return 0; } default: { return i+1; } } } /* ** Translate a single element of JSON text at pParse->zJson[i] into ** its equivalent binary JSONB representation. Append the translation into ** pParse->aBlob[] beginning at pParse->nBlob. The size of ** pParse->aBlob[] is increased as necessary. ** ** Return the index of the first character past the end of the element parsed, ** or one of the following special result codes: ** ** 0 End of input ** -1 Syntax error or OOM ** -2 '}' seen \ ** -3 ']' seen \___ For these returns, pParse->iErr is set to ** -4 ',' seen / the index in zJson[] of the seen character ** -5 ':' seen / */ static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){ char c; u32 j; u32 iThis, iStart; int x; u8 t; const char *z = pParse->zJson; json_parse_restart: switch( (u8)z[i] ){ case '{': { /* Parse object */ iThis = pParse->nBlob; jsonBlobAppendNode(pParse, JSONB_OBJECT, pParse->nJson-i, 0); if( ++pParse->iDepth > JSON_MAX_DEPTH ){ pParse->iErr = i; return -1; } iStart = pParse->nBlob; for(j=i+1;;j++){ u32 iBlob = pParse->nBlob; x = jsonTranslateTextToBlob(pParse, j); if( x<=0 ){ int op; if( x==(-2) ){ j = pParse->iErr; if( pParse->nBlob!=(u32)iStart ) pParse->hasNonstd = 1; break; } j += json5Whitespace(&z[j]); op = JSONB_TEXT; if( sqlite3JsonId1(z[j]) || (z[j]=='\\' && jsonIs4HexB(&z[j+1], &op)) ){ int k = j+1; while( (sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0) || (z[k]=='\\' && jsonIs4HexB(&z[k+1], &op)) ){ k++; } assert( iBlob==pParse->nBlob ); jsonBlobAppendNode(pParse, op, k-j, &z[j]); pParse->hasNonstd = 1; x = k; }else{ if( x!=-1 ) pParse->iErr = j; return -1; } } if( pParse->oom ) return -1; t = pParse->aBlob[iBlob] & 0x0f; if( tJSONB_TEXTRAW ){ pParse->iErr = j; return -1; } j = x; if( z[j]==':' ){ j++; }else{ if( jsonIsspace(z[j]) ){ /* strspn() is not helpful here */ do{ j++; }while( jsonIsspace(z[j]) ); if( z[j]==':' ){ j++; goto parse_object_value; } } x = jsonTranslateTextToBlob(pParse, j); if( x!=(-5) ){ if( x!=(-1) ) pParse->iErr = j; return -1; } j = pParse->iErr+1; } parse_object_value: x = jsonTranslateTextToBlob(pParse, j); if( x<=0 ){ if( x!=(-1) ) pParse->iErr = j; return -1; } j = x; if( z[j]==',' ){ continue; }else if( z[j]=='}' ){ break; }else{ if( jsonIsspace(z[j]) ){ j += 1 + (u32)strspn(&z[j+1], jsonSpaces); if( z[j]==',' ){ continue; }else if( z[j]=='}' ){ break; } } x = jsonTranslateTextToBlob(pParse, j); if( x==(-4) ){ j = pParse->iErr; continue; } if( x==(-2) ){ j = pParse->iErr; break; } } pParse->iErr = j; return -1; } jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart); pParse->iDepth--; return j+1; } case '[': { /* Parse array */ iThis = pParse->nBlob; jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0); iStart = pParse->nBlob; if( pParse->oom ) return -1; if( ++pParse->iDepth > JSON_MAX_DEPTH ){ pParse->iErr = i; return -1; } for(j=i+1;;j++){ x = jsonTranslateTextToBlob(pParse, j); if( x<=0 ){ if( x==(-3) ){ j = pParse->iErr; if( pParse->nBlob!=iStart ) pParse->hasNonstd = 1; break; } if( x!=(-1) ) pParse->iErr = j; return -1; } j = x; if( z[j]==',' ){ continue; }else if( z[j]==']' ){ break; }else{ if( jsonIsspace(z[j]) ){ j += 1 + (u32)strspn(&z[j+1], jsonSpaces); if( z[j]==',' ){ continue; }else if( z[j]==']' ){ break; } } x = jsonTranslateTextToBlob(pParse, j); if( x==(-4) ){ j = pParse->iErr; continue; } if( x==(-3) ){ j = pParse->iErr; break; } } pParse->iErr = j; return -1; } jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart); pParse->iDepth--; return j+1; } case '\'': { u8 opcode; char cDelim; pParse->hasNonstd = 1; opcode = JSONB_TEXT; goto parse_string; case '"': /* Parse string */ opcode = JSONB_TEXT; parse_string: cDelim = z[i]; j = i+1; while( 1 /*exit-by-break*/ ){ if( jsonIsOk[(u8)z[j]] ){ if( !jsonIsOk[(u8)z[j+1]] ){ j += 1; }else if( !jsonIsOk[(u8)z[j+2]] ){ j += 2; }else{ j += 3; continue; } } c = z[j]; if( c==cDelim ){ break; }else if( c=='\\' ){ c = z[++j]; if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' || c=='n' || c=='r' || c=='t' || (c=='u' && jsonIs4Hex(&z[j+1])) ){ if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ; }else if( c=='\'' || c=='0' || c=='v' || c=='\n' || (0xe2==(u8)c && 0x80==(u8)z[j+1] && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])) || (c=='x' && jsonIs2Hex(&z[j+1])) ){ opcode = JSONB_TEXT5; pParse->hasNonstd = 1; }else if( c=='\r' ){ if( z[j+1]=='\n' ) j++; opcode = JSONB_TEXT5; pParse->hasNonstd = 1; }else{ pParse->iErr = j; return -1; } }else if( c<=0x1f ){ /* Control characters are not allowed in strings */ pParse->iErr = j; return -1; }else if( c=='"' ){ opcode = JSONB_TEXT5; } j++; } jsonBlobAppendNode(pParse, opcode, j-1-i, &z[i+1]); return j+1; } case 't': { if( strncmp(z+i,"true",4)==0 && !sqlite3Isalnum(z[i+4]) ){ jsonBlobAppendOneByte(pParse, JSONB_TRUE); return i+4; } pParse->iErr = i; return -1; } case 'f': { if( strncmp(z+i,"false",5)==0 && !sqlite3Isalnum(z[i+5]) ){ jsonBlobAppendOneByte(pParse, JSONB_FALSE); return i+5; } pParse->iErr = i; return -1; } case '+': { u8 seenE; pParse->hasNonstd = 1; t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */ goto parse_number; case '.': if( sqlite3Isdigit(z[i+1]) ){ pParse->hasNonstd = 1; t = 0x03; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */ seenE = 0; goto parse_number_2; } pParse->iErr = i; return -1; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* Parse number */ t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */ parse_number: seenE = 0; assert( '-' < '0' ); assert( '+' < '0' ); assert( '.' < '0' ); c = z[i]; if( c<='0' ){ if( c=='0' ){ if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){ assert( t==0x00 ); pParse->hasNonstd = 1; t = 0x01; for(j=i+3; sqlite3Isxdigit(z[j]); j++){} goto parse_number_finish; }else if( sqlite3Isdigit(z[i+1]) ){ pParse->iErr = i+1; return -1; } }else{ if( !sqlite3Isdigit(z[i+1]) ){ /* JSON5 allows for "+Infinity" and "-Infinity" using exactly ** that case. SQLite also allows these in any case and it allows ** "+inf" and "-inf". */ if( (z[i+1]=='I' || z[i+1]=='i') && sqlite3StrNICmp(&z[i+1], "inf",3)==0 ){ pParse->hasNonstd = 1; if( z[i]=='-' ){ jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999"); }else{ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999"); } return i + (sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4); } if( z[i+1]=='.' ){ pParse->hasNonstd = 1; t |= 0x01; goto parse_number_2; } pParse->iErr = i; return -1; } if( z[i+1]=='0' ){ if( sqlite3Isdigit(z[i+2]) ){ pParse->iErr = i+1; return -1; }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){ pParse->hasNonstd = 1; t |= 0x01; for(j=i+4; sqlite3Isxdigit(z[j]); j++){} goto parse_number_finish; } } } } parse_number_2: for(j=i+1;; j++){ c = z[j]; if( sqlite3Isdigit(c) ) continue; if( c=='.' ){ if( (t & 0x02)!=0 ){ pParse->iErr = j; return -1; } t |= 0x02; continue; } if( c=='e' || c=='E' ){ if( z[j-1]<'0' ){ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){ pParse->hasNonstd = 1; t |= 0x01; }else{ pParse->iErr = j; return -1; } } if( seenE ){ pParse->iErr = j; return -1; } t |= 0x02; seenE = 1; c = z[j+1]; if( c=='+' || c=='-' ){ j++; c = z[j+1]; } if( c<'0' || c>'9' ){ pParse->iErr = j; return -1; } continue; } break; } if( z[j-1]<'0' ){ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){ pParse->hasNonstd = 1; t |= 0x01; }else{ pParse->iErr = j; return -1; } } parse_number_finish: assert( JSONB_INT+0x01==JSONB_INT5 ); assert( JSONB_FLOAT+0x01==JSONB_FLOAT5 ); assert( JSONB_INT+0x02==JSONB_FLOAT ); if( z[i]=='+' ) i++; jsonBlobAppendNode(pParse, JSONB_INT+t, j-i, &z[i]); return j; } case '}': { pParse->iErr = i; return -2; /* End of {...} */ } case ']': { pParse->iErr = i; return -3; /* End of [...] */ } case ',': { pParse->iErr = i; return -4; /* List separator */ } case ':': { pParse->iErr = i; return -5; /* Object label/value separator */ } case 0: { return 0; /* End of file */ } case 0x09: case 0x0a: case 0x0d: case 0x20: { i += 1 + (u32)strspn(&z[i+1], jsonSpaces); goto json_parse_restart; } case 0x0b: case 0x0c: case '/': case 0xc2: case 0xe1: case 0xe2: case 0xe3: case 0xef: { j = json5Whitespace(&z[i]); if( j>0 ){ i += j; pParse->hasNonstd = 1; goto json_parse_restart; } pParse->iErr = i; return -1; } case 'n': { if( strncmp(z+i,"null",4)==0 && !sqlite3Isalnum(z[i+4]) ){ jsonBlobAppendOneByte(pParse, JSONB_NULL); return i+4; } /* fall-through into the default case that checks for NaN */ } default: { u32 k; int nn; c = z[i]; for(k=0; khasNonstd = 1; return i + nn; } pParse->iErr = i; return -1; /* Syntax error */ } } /* End switch(z[i]) */ } /* ** Parse a complete JSON string. Return 0 on success or non-zero if there ** are any errors. If an error occurs, free all memory held by pParse, ** but not pParse itself. ** ** pParse must be initialized to an empty parse object prior to calling ** this routine. */ static int jsonConvertTextToBlob( JsonParse *pParse, /* Initialize and fill this JsonParse object */ sqlite3_context *pCtx /* Report errors here */ ){ int i; const char *zJson = pParse->zJson; i = jsonTranslateTextToBlob(pParse, 0); if( pParse->oom ) i = -1; if( i>0 ){ #ifdef SQLITE_DEBUG assert( pParse->iDepth==0 ); if( sqlite3Config.bJsonSelfcheck ){ assert( jsonbValidityCheck(pParse, 0, pParse->nBlob, 0)==0 ); } #endif while( jsonIsspace(zJson[i]) ) i++; if( zJson[i] ){ i += json5Whitespace(&zJson[i]); if( zJson[i] ){ if( pCtx ) sqlite3_result_error(pCtx, "malformed JSON", -1); jsonParseReset(pParse); return 1; } pParse->hasNonstd = 1; } } if( i<=0 ){ if( pCtx!=0 ){ if( pParse->oom ){ sqlite3_result_error_nomem(pCtx); }else{ sqlite3_result_error(pCtx, "malformed JSON", -1); } } jsonParseReset(pParse); return 1; } return 0; } /* ** The input string pStr is a well-formed JSON text string. Convert ** this into the JSONB format and make it the return value of the ** SQL function. */ static void jsonReturnStringAsBlob(JsonString *pStr){ JsonParse px; memset(&px, 0, sizeof(px)); jsonStringTerminate(pStr); px.zJson = pStr->zBuf; px.nJson = pStr->nUsed; px.db = sqlite3_context_db_handle(pStr->pCtx); (void)jsonTranslateTextToBlob(&px, 0); if( px.oom ){ sqlite3DbFree(px.db, px.aBlob); sqlite3_result_error_nomem(pStr->pCtx); }else{ assert( px.nBlobAlloc>0 ); assert( !px.bReadOnly ); sqlite3_result_blob(pStr->pCtx, px.aBlob, px.nBlob, SQLITE_DYNAMIC); } } /* The byte at index i is a node type-code. This routine ** determines the payload size for that node and writes that ** payload size in to *pSz. It returns the offset from i to the ** beginning of the payload. Return 0 on error. */ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ u8 x; u32 sz; u32 n; if( NEVER(i>pParse->nBlob) ){ *pSz = 0; return 0; } x = pParse->aBlob[i]>>4; if( x<=11 ){ sz = x; n = 1; }else if( x==12 ){ if( i+1>=pParse->nBlob ){ *pSz = 0; return 0; } sz = pParse->aBlob[i+1]; n = 2; }else if( x==13 ){ if( i+2>=pParse->nBlob ){ *pSz = 0; return 0; } sz = (pParse->aBlob[i+1]<<8) + pParse->aBlob[i+2]; n = 3; }else if( x==14 ){ if( i+4>=pParse->nBlob ){ *pSz = 0; return 0; } sz = ((u32)pParse->aBlob[i+1]<<24) + (pParse->aBlob[i+2]<<16) + (pParse->aBlob[i+3]<<8) + pParse->aBlob[i+4]; n = 5; }else{ if( i+8>=pParse->nBlob || pParse->aBlob[i+1]!=0 || pParse->aBlob[i+2]!=0 || pParse->aBlob[i+3]!=0 || pParse->aBlob[i+4]!=0 ){ *pSz = 0; return 0; } sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8]; n = 9; } if( (i64)i+sz+n > pParse->nBlob && (i64)i+sz+n > pParse->nBlob-pParse->delta ){ sz = 0; n = 0; } *pSz = sz; return n; } /* ** Translate the binary JSONB representation of JSON beginning at ** pParse->aBlob[i] into a JSON text string. Append the JSON ** text onto the end of pOut. Return the index in pParse->aBlob[] ** of the first byte past the end of the element that is translated. ** ** If an error is detected in the BLOB input, the pOut->eErr flag ** might get set to JSTRING_MALFORMED. But not all BLOB input errors ** are detected. So a malformed JSONB input might either result ** in an error, or in incorrect JSON. ** ** The pOut->eErr JSTRING_OOM flag is set on a OOM. */ static u32 jsonTranslateBlobToText( const JsonParse *pParse, /* the complete parse of the JSON */ u32 i, /* Start rendering at this index */ JsonString *pOut /* Write JSON here */ ){ u32 sz, n, j, iEnd; n = jsonbPayloadSize(pParse, i, &sz); if( n==0 ){ pOut->eErr |= JSTRING_MALFORMED; return pParse->nBlob+1; } switch( pParse->aBlob[i] & 0x0f ){ case JSONB_NULL: { jsonAppendRawNZ(pOut, "null", 4); return i+1; } case JSONB_TRUE: { jsonAppendRawNZ(pOut, "true", 4); return i+1; } case JSONB_FALSE: { jsonAppendRawNZ(pOut, "false", 5); return i+1; } case JSONB_INT: case JSONB_FLOAT: { if( sz==0 ) goto malformed_jsonb; jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz); break; } case JSONB_INT5: { /* Integer literal in hexadecimal notation */ u32 k = 2; sqlite3_uint64 u = 0; const char *zIn = (const char*)&pParse->aBlob[i+n]; int bOverflow = 0; if( sz==0 ) goto malformed_jsonb; if( zIn[0]=='-' ){ jsonAppendChar(pOut, '-'); k++; }else if( zIn[0]=='+' ){ k++; } for(; keErr |= JSTRING_MALFORMED; break; }else if( (u>>60)!=0 ){ bOverflow = 1; }else{ u = u*16 + sqlite3HexToInt(zIn[k]); } } jsonPrintf(100,pOut,bOverflow?"9.0e999":"%llu", u); break; } case JSONB_FLOAT5: { /* Float literal missing digits beside "." */ u32 k = 0; const char *zIn = (const char*)&pParse->aBlob[i+n]; if( sz==0 ) goto malformed_jsonb; if( zIn[0]=='-' ){ jsonAppendChar(pOut, '-'); k++; } if( zIn[k]=='.' ){ jsonAppendChar(pOut, '0'); } for(; kaBlob[i+n], sz); jsonAppendChar(pOut, '"'); break; } case JSONB_TEXT5: { const char *zIn; u32 k; u32 sz2 = sz; zIn = (const char*)&pParse->aBlob[i+n]; jsonAppendChar(pOut, '"'); while( sz2>0 ){ for(k=0; k0 ){ jsonAppendRawNZ(pOut, zIn, k); if( k>=sz2 ){ break; } zIn += k; sz2 -= k; } if( zIn[0]=='"' ){ jsonAppendRawNZ(pOut, "\\\"", 2); zIn++; sz2--; continue; } assert( zIn[0]=='\\' ); assert( sz2>=1 ); if( sz2<2 ){ pOut->eErr |= JSTRING_MALFORMED; break; } switch( (u8)zIn[1] ){ case '\'': jsonAppendChar(pOut, '\''); break; case 'v': jsonAppendRawNZ(pOut, "\\u0009", 6); break; case 'x': if( sz2<4 ){ pOut->eErr |= JSTRING_MALFORMED; sz2 = 2; break; } jsonAppendRawNZ(pOut, "\\u00", 4); jsonAppendRawNZ(pOut, &zIn[2], 2); zIn += 2; sz2 -= 2; break; case '0': jsonAppendRawNZ(pOut, "\\u0000", 6); break; case '\r': if( sz2>2 && zIn[2]=='\n' ){ zIn++; sz2--; } break; case '\n': break; case 0xe2: /* '\' followed by either U+2028 or U+2029 is ignored as ** whitespace. Not that in UTF8, U+2028 is 0xe2 0x80 0x29. ** U+2029 is the same except for the last byte */ if( sz2<4 || 0x80!=(u8)zIn[2] || (0xa8!=(u8)zIn[3] && 0xa9!=(u8)zIn[3]) ){ pOut->eErr |= JSTRING_MALFORMED; sz2 = 2; break; } zIn += 2; sz2 -= 2; break; default: jsonAppendRawNZ(pOut, zIn, 2); break; } assert( sz2>=2 ); zIn += 2; sz2 -= 2; } jsonAppendChar(pOut, '"'); break; } case JSONB_TEXTRAW: { jsonAppendString(pOut, (const char*)&pParse->aBlob[i+n], sz); break; } case JSONB_ARRAY: { jsonAppendChar(pOut, '['); j = i+n; iEnd = j+sz; while( jeErr==0 ){ j = jsonTranslateBlobToText(pParse, j, pOut); jsonAppendChar(pOut, ','); } if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED; if( sz>0 ) jsonStringTrimOneChar(pOut); jsonAppendChar(pOut, ']'); break; } case JSONB_OBJECT: { int x = 0; jsonAppendChar(pOut, '{'); j = i+n; iEnd = j+sz; while( jeErr==0 ){ j = jsonTranslateBlobToText(pParse, j, pOut); jsonAppendChar(pOut, (x++ & 1) ? ',' : ':'); } if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED; if( sz>0 ) jsonStringTrimOneChar(pOut); jsonAppendChar(pOut, '}'); break; } default: { malformed_jsonb: pOut->eErr |= JSTRING_MALFORMED; break; } } return i+n+sz; } /* Return true if the input pJson ** ** For performance reasons, this routine does not do a detailed check of the ** input BLOB to ensure that it is well-formed. Hence, false positives are ** possible. False negatives should never occur, however. */ static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){ u32 sz, n; const u8 *aBlob; int nBlob; JsonParse s; if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0; aBlob = sqlite3_value_blob(pJson); nBlob = sqlite3_value_bytes(pJson); if( nBlob<1 ) return 0; if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0; memset(&s, 0, sizeof(s)); s.aBlob = (u8*)aBlob; s.nBlob = nBlob; n = jsonbPayloadSize(&s, 0, &sz); if( n==0 ) return 0; if( sz+n!=(u32)nBlob ) return 0; if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0; return sz+n==(u32)nBlob; } /* ** Given that a JSONB_ARRAY object starts at offset i, return ** the number of entries in that array. */ static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){ u32 n, sz, i, iEnd; u32 k = 0; n = jsonbPayloadSize(pParse, iRoot, &sz); iEnd = iRoot+n+sz; for(i=iRoot+n; n>0 && idelta. */ static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){ u32 sz = 0; u32 nBlob; assert( pParse->delta!=0 ); assert( pParse->nBlobAlloc >= pParse->nBlob ); nBlob = pParse->nBlob; pParse->nBlob = pParse->nBlobAlloc; (void)jsonbPayloadSize(pParse, iRoot, &sz); pParse->nBlob = nBlob; sz += pParse->delta; pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz); } /* ** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of ** content beginning at iDel, and replacing them with nIns bytes of ** content given by aIns. ** ** nDel may be zero, in which case no bytes are removed. But iDel is ** still important as new bytes will be insert beginning at iDel. ** ** aIns may be zero, in which case space is created to hold nIns bytes ** beginning at iDel, but that space is uninitialized. ** ** Set pParse->oom if an OOM occurs. */ static void jsonBlobEdit( JsonParse *pParse, /* The JSONB to be modified is in pParse->aBlob */ u32 iDel, /* First byte to be removed */ u32 nDel, /* Number of bytes to remove */ const u8 *aIns, /* Content to insert */ u32 nIns /* Bytes of content to insert */ ){ i64 d = (i64)nIns - (i64)nDel; if( d!=0 ){ if( pParse->nBlob + d > pParse->nBlobAlloc ){ jsonBlobExpand(pParse, pParse->nBlob+d); if( pParse->oom ) return; } memmove(&pParse->aBlob[iDel+nIns], &pParse->aBlob[iDel+nDel], pParse->nBlob - (iDel+nDel)); pParse->nBlob += d; pParse->delta += d; } if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns); } /* ** Return the number of escaped newlines to be ignored. ** An escaped newline is a one of the following byte sequences: ** ** 0x5c 0x0a ** 0x5c 0x0d ** 0x5c 0x0d 0x0a ** 0x5c 0xe2 0x80 0xa8 ** 0x5c 0xe2 0x80 0xa9 */ static u32 jsonBytesToBypass(const char *z, u32 n){ u32 i = 0; while( i+10 ); assert( z[0]=='\\' ); if( n<2 ){ *piOut = JSON_INVALID_CHAR; return n; } switch( (u8)z[1] ){ case 'u': { u32 v, vlo; if( n<6 ){ *piOut = JSON_INVALID_CHAR; return n; } v = jsonHexToInt4(&z[2]); if( (v & 0xfc00)==0xd800 && n>=12 && z[6]=='\\' && z[7]=='u' && ((vlo = jsonHexToInt4(&z[8]))&0xfc00)==0xdc00 ){ *piOut = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000; return 12; }else{ *piOut = v; return 6; } } case 'b': { *piOut = '\b'; return 2; } case 'f': { *piOut = '\f'; return 2; } case 'n': { *piOut = '\n'; return 2; } case 'r': { *piOut = '\r'; return 2; } case 't': { *piOut = '\t'; return 2; } case 'v': { *piOut = '\v'; return 2; } case '0': { *piOut = 0; return 2; } case '\'': case '"': case '/': case '\\':{ *piOut = z[1]; return 2; } case 'x': { if( n<4 ){ *piOut = JSON_INVALID_CHAR; return n; } *piOut = (jsonHexToInt(z[2])<<4) | jsonHexToInt(z[3]); return 4; } case 0xe2: case '\r': case '\n': { u32 nSkip = jsonBytesToBypass(z, n); if( nSkip==0 ){ *piOut = JSON_INVALID_CHAR; return n; }else if( nSkip==n ){ *piOut = 0; return n; }else if( z[nSkip]=='\\' ){ return nSkip + jsonUnescapeOneChar(&z[nSkip], n-nSkip, piOut); }else{ int sz = sqlite3Utf8ReadLimited((u8*)&z[nSkip], n-nSkip, piOut); return nSkip + sz; } } default: { *piOut = JSON_INVALID_CHAR; return 2; } } } /* ** Compare two object labels. Return 1 if they are equal and ** 0 if they differ. ** ** In this version, we know that one or the other or both of the ** two comparands contains an escape sequence. */ static SQLITE_NOINLINE int jsonLabelCompareEscaped( const char *zLeft, /* The left label */ u32 nLeft, /* Size of the left label in bytes */ int rawLeft, /* True if zLeft contains no escapes */ const char *zRight, /* The right label */ u32 nRight, /* Size of the right label in bytes */ int rawRight /* True if zRight is escape-free */ ){ u32 cLeft, cRight; assert( rawLeft==0 || rawRight==0 ); while( 1 /*exit-by-return*/ ){ if( nLeft==0 ){ cLeft = 0; }else if( rawLeft || zLeft[0]!='\\' ){ cLeft = ((u8*)zLeft)[0]; if( cLeft>=0xc0 ){ int sz = sqlite3Utf8ReadLimited((u8*)zLeft, nLeft, &cLeft); zLeft += sz; nLeft -= sz; }else{ zLeft++; nLeft--; } }else{ u32 n = jsonUnescapeOneChar(zLeft, nLeft, &cLeft); zLeft += n; assert( n<=nLeft ); nLeft -= n; } if( nRight==0 ){ cRight = 0; }else if( rawRight || zRight[0]!='\\' ){ cRight = ((u8*)zRight)[0]; if( cRight>=0xc0 ){ int sz = sqlite3Utf8ReadLimited((u8*)zRight, nRight, &cRight); zRight += sz; nRight -= sz; }else{ zRight++; nRight--; } }else{ u32 n = jsonUnescapeOneChar(zRight, nRight, &cRight); zRight += n; assert( n<=nRight ); nRight -= n; } if( cLeft!=cRight ) return 0; if( cLeft==0 ) return 1; } } /* ** Compare two object labels. Return 1 if they are equal and ** 0 if they differ. Return -1 if an OOM occurs. */ static int jsonLabelCompare( const char *zLeft, /* The left label */ u32 nLeft, /* Size of the left label in bytes */ int rawLeft, /* True if zLeft contains no escapes */ const char *zRight, /* The right label */ u32 nRight, /* Size of the right label in bytes */ int rawRight /* True if zRight is escape-free */ ){ if( rawLeft && rawRight ){ /* Simpliest case: Neither label contains escapes. A simple ** memcmp() is sufficient. */ if( nLeft!=nRight ) return 0; return memcmp(zLeft, zRight, nLeft)==0; }else{ return jsonLabelCompareEscaped(zLeft, nLeft, rawLeft, zRight, nRight, rawRight); } } /* ** Error returns from jsonLookupStep() */ #define JSON_LOOKUP_ERROR 0xffffffff #define JSON_LOOKUP_NOTFOUND 0xfffffffe #define JSON_LOOKUP_PATHERROR 0xfffffffd #define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR) /* Forward declaration */ static u32 jsonLookupStep(JsonParse*,u32,const char*,u32); /* This helper routine for jsonLookupStep() populates pIns with ** binary data that is to be inserted into pParse. ** ** In the common case, pIns just points to pParse->aIns and pParse->nIns. ** But if the zPath of the original edit operation includes path elements ** that go deeper, additional substructure must be created. ** ** For example: ** ** json_insert('{}', '$.a.b.c', 123); ** ** The search stops at '$.a' But additional substructure must be ** created for the ".b.c" part of the patch so that the final result ** is: {"a":{"b":{"c"::123}}}. This routine populates pIns with ** the binary equivalent of {"b":{"c":123}} so that it can be inserted. ** ** The caller is responsible for resetting pIns when it has finished ** using the substructure. */ static u32 jsonCreateEditSubstructure( JsonParse *pParse, /* The original JSONB that is being edited */ JsonParse *pIns, /* Populate this with the blob data to insert */ const char *zTail /* Tail of the path that determins substructure */ ){ static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT }; int rc; memset(pIns, 0, sizeof(*pIns)); pIns->db = pParse->db; if( zTail[0]==0 ){ /* No substructure. Just insert what is given in pParse. */ pIns->aBlob = pParse->aIns; pIns->nBlob = pParse->nIns; rc = 0; }else{ /* Construct the binary substructure */ pIns->nBlob = 1; pIns->aBlob = (u8*)&emptyObject[zTail[0]=='.']; pIns->eEdit = pParse->eEdit; pIns->nIns = pParse->nIns; pIns->aIns = pParse->aIns; rc = jsonLookupStep(pIns, 0, zTail, 0); pParse->oom |= pIns->oom; } return rc; /* Error code only */ } /* ** Search along zPath to find the Json element specified. Return an ** index into pParse->aBlob[] for the start of that element's value. ** ** If the value found by this routine is the value half of label/value pair ** within an object, then set pPath->iLabel to the start of the corresponding ** label, before returning. ** ** Return one of the JSON_LOOKUP error codes if problems are seen. ** ** This routine will also modify the blob. If pParse->eEdit is one of ** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be ** made to the selected value. If an edit is performed, then the return ** value does not necessarily point to the select element. If an edit ** is performed, the return value is only useful for detecting error ** conditions. */ static u32 jsonLookupStep( JsonParse *pParse, /* The JSON to search */ u32 iRoot, /* Begin the search at this element of aBlob[] */ const char *zPath, /* The path to search */ u32 iLabel /* Label if iRoot is a value of in an object */ ){ u32 i, j, k, nKey, sz, n, iEnd, rc; const char *zKey; u8 x; if( zPath[0]==0 ){ if( pParse->eEdit && jsonBlobMakeEditable(pParse, pParse->nIns) ){ n = jsonbPayloadSize(pParse, iRoot, &sz); sz += n; if( pParse->eEdit==JEDIT_DEL ){ if( iLabel>0 ){ sz += iRoot - iLabel; iRoot = iLabel; } jsonBlobEdit(pParse, iRoot, sz, 0, 0); }else if( pParse->eEdit==JEDIT_INS ){ /* Already exists, so json_insert() is a no-op */ }else{ /* json_set() or json_replace() */ jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns); } } pParse->iLabel = iLabel; return iRoot; } if( zPath[0]=='.' ){ int rawKey = 1; x = pParse->aBlob[iRoot]; zPath++; if( zPath[0]=='"' ){ zKey = zPath + 1; for(i=1; zPath[i] && zPath[i]!='"'; i++){} nKey = i-1; if( zPath[i] ){ i++; }else{ return JSON_LOOKUP_PATHERROR; } testcase( nKey==0 ); rawKey = memchr(zKey, '\\', nKey)==0; }else{ zKey = zPath; for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} nKey = i; if( nKey==0 ){ return JSON_LOOKUP_PATHERROR; } } if( (x & 0x0f)!=JSONB_OBJECT ) return JSON_LOOKUP_NOTFOUND; n = jsonbPayloadSize(pParse, iRoot, &sz); j = iRoot + n; /* j is the index of a label */ iEnd = j+sz; while( jaBlob[j] & 0x0f; if( xJSONB_TEXTRAW ) return JSON_LOOKUP_ERROR; n = jsonbPayloadSize(pParse, j, &sz); if( n==0 ) return JSON_LOOKUP_ERROR; k = j+n; /* k is the index of the label text */ if( k+sz>=iEnd ) return JSON_LOOKUP_ERROR; zLabel = (const char*)&pParse->aBlob[k]; rawLabel = x==JSONB_TEXT || x==JSONB_TEXTRAW; if( jsonLabelCompare(zKey, nKey, rawKey, zLabel, sz, rawLabel) ){ u32 v = k+sz; /* v is the index of the value */ if( ((pParse->aBlob[v])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR; n = jsonbPayloadSize(pParse, v, &sz); if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR; assert( j>0 ); rc = jsonLookupStep(pParse, v, &zPath[i], j); if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); return rc; } j = k+sz; if( ((pParse->aBlob[j])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR; n = jsonbPayloadSize(pParse, j, &sz); if( n==0 ) return JSON_LOOKUP_ERROR; j += n+sz; } if( j>iEnd ) return JSON_LOOKUP_ERROR; if( pParse->eEdit>=JEDIT_INS ){ u32 nIns; /* Total bytes to insert (label+value) */ JsonParse v; /* BLOB encoding of the value to be inserted */ JsonParse ix; /* Header of the label to be inserted */ testcase( pParse->eEdit==JEDIT_INS ); testcase( pParse->eEdit==JEDIT_SET ); memset(&ix, 0, sizeof(ix)); ix.db = pParse->db; jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0); pParse->oom |= ix.oom; rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i]); if( !JSON_LOOKUP_ISERROR(rc) && jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob) ){ assert( !pParse->oom ); nIns = ix.nBlob + nKey + v.nBlob; jsonBlobEdit(pParse, j, 0, 0, nIns); if( !pParse->oom ){ assert( pParse->aBlob!=0 ); /* Because pParse->oom!=0 */ assert( ix.aBlob!=0 ); /* Because pPasre->oom!=0 */ memcpy(&pParse->aBlob[j], ix.aBlob, ix.nBlob); k = j + ix.nBlob; memcpy(&pParse->aBlob[k], zKey, nKey); k += nKey; memcpy(&pParse->aBlob[k], v.aBlob, v.nBlob); if( ALWAYS(pParse->delta) ) jsonAfterEditSizeAdjust(pParse, iRoot); } } jsonParseReset(&v); jsonParseReset(&ix); return rc; } }else if( zPath[0]=='[' ){ x = pParse->aBlob[iRoot] & 0x0f; if( x!=JSONB_ARRAY ) return JSON_LOOKUP_NOTFOUND; n = jsonbPayloadSize(pParse, iRoot, &sz); k = 0; i = 1; while( sqlite3Isdigit(zPath[i]) ){ k = k*10 + zPath[i] - '0'; i++; } if( i<2 || zPath[i]!=']' ){ if( zPath[1]=='#' ){ k = jsonbArrayCount(pParse, iRoot); i = 2; if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){ unsigned int nn = 0; i = 3; do{ nn = nn*10 + zPath[i] - '0'; i++; }while( sqlite3Isdigit(zPath[i]) ); if( nn>k ) return JSON_LOOKUP_NOTFOUND; k -= nn; } if( zPath[i]!=']' ){ return JSON_LOOKUP_PATHERROR; } }else{ return JSON_LOOKUP_PATHERROR; } } j = iRoot+n; iEnd = j+sz; while( jdelta ) jsonAfterEditSizeAdjust(pParse, iRoot); return rc; } k--; n = jsonbPayloadSize(pParse, j, &sz); if( n==0 ) return JSON_LOOKUP_ERROR; j += n+sz; } if( j>iEnd ) return JSON_LOOKUP_ERROR; if( k>0 ) return JSON_LOOKUP_NOTFOUND; if( pParse->eEdit>=JEDIT_INS ){ JsonParse v; testcase( pParse->eEdit==JEDIT_INS ); testcase( pParse->eEdit==JEDIT_SET ); rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]); if( !JSON_LOOKUP_ISERROR(rc) && jsonBlobMakeEditable(pParse, v.nBlob) ){ assert( !pParse->oom ); jsonBlobEdit(pParse, j, 0, v.aBlob, v.nBlob); } jsonParseReset(&v); if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); return rc; } }else{ return JSON_LOOKUP_PATHERROR; } return JSON_LOOKUP_NOTFOUND; } /* ** Convert a JSON BLOB into text and make that text the return value ** of an SQL function. */ static void jsonReturnTextJsonFromBlob( sqlite3_context *ctx, const u8 *aBlob, u32 nBlob ){ JsonParse x; JsonString s; if( NEVER(aBlob==0) ) return; memset(&x, 0, sizeof(x)); x.aBlob = (u8*)aBlob; x.nBlob = nBlob; jsonStringInit(&s, ctx); jsonTranslateBlobToText(&x, 0, &s); jsonReturnString(&s, 0, 0); } /* ** Return the value of the BLOB node at index i. ** ** If the value is a primitive, return it as an SQL value. ** If the value is an array or object, return it as either ** JSON text or the BLOB encoding, depending on the JSON_B flag ** on the userdata. */ static void jsonReturnFromBlob( JsonParse *pParse, /* Complete JSON parse tree */ u32 i, /* Index of the node */ sqlite3_context *pCtx, /* Return value for this function */ int textOnly /* return text JSON. Disregard user-data */ ){ u32 n, sz; int rc; sqlite3 *db = sqlite3_context_db_handle(pCtx); n = jsonbPayloadSize(pParse, i, &sz); if( n==0 ){ sqlite3_result_error(pCtx, "malformed JSON", -1); return; } switch( pParse->aBlob[i] & 0x0f ){ case JSONB_NULL: { if( sz ) goto returnfromblob_malformed; sqlite3_result_null(pCtx); break; } case JSONB_TRUE: { if( sz ) goto returnfromblob_malformed; sqlite3_result_int(pCtx, 1); break; } case JSONB_FALSE: { if( sz ) goto returnfromblob_malformed; sqlite3_result_int(pCtx, 0); break; } case JSONB_INT5: case JSONB_INT: { sqlite3_int64 iRes = 0; char *z; int bNeg = 0; char x; if( sz==0 ) goto returnfromblob_malformed; x = (char)pParse->aBlob[i+n]; if( x=='-' ){ if( sz<2 ) goto returnfromblob_malformed; n++; sz--; bNeg = 1; } z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); if( z==0 ) goto returnfromblob_oom; rc = sqlite3DecOrHexToI64(z, &iRes); sqlite3DbFree(db, z); if( rc==0 ){ sqlite3_result_int64(pCtx, bNeg ? -iRes : iRes); }else if( rc==3 && bNeg ){ sqlite3_result_int64(pCtx, SMALLEST_INT64); }else if( rc==1 ){ goto returnfromblob_malformed; }else{ if( bNeg ){ n--; sz++; } goto to_double; } break; } case JSONB_FLOAT5: case JSONB_FLOAT: { double r; char *z; if( sz==0 ) goto returnfromblob_malformed; to_double: z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); if( z==0 ) goto returnfromblob_oom; rc = sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); sqlite3DbFree(db, z); if( rc<=0 ) goto returnfromblob_malformed; sqlite3_result_double(pCtx, r); break; } case JSONB_TEXTRAW: case JSONB_TEXT: { sqlite3_result_text(pCtx, (char*)&pParse->aBlob[i+n], sz, SQLITE_TRANSIENT); break; } case JSONB_TEXT5: case JSONB_TEXTJ: { /* Translate JSON formatted string into raw text */ u32 iIn, iOut; const char *z; char *zOut; u32 nOut = sz; z = (const char*)&pParse->aBlob[i+n]; zOut = sqlite3DbMallocRaw(db, nOut+1); if( zOut==0 ) goto returnfromblob_oom; for(iIn=iOut=0; iIn=2 ); zOut[iOut++] = (char)(0xc0 | (v>>6)); zOut[iOut++] = 0x80 | (v&0x3f); }else if( v<0x10000 ){ assert( szEscape>=3 ); zOut[iOut++] = 0xe0 | (v>>12); zOut[iOut++] = 0x80 | ((v>>6)&0x3f); zOut[iOut++] = 0x80 | (v&0x3f); }else if( v==JSON_INVALID_CHAR ){ /* Silently ignore illegal unicode */ }else{ assert( szEscape>=4 ); zOut[iOut++] = 0xf0 | (v>>18); zOut[iOut++] = 0x80 | ((v>>12)&0x3f); zOut[iOut++] = 0x80 | ((v>>6)&0x3f); zOut[iOut++] = 0x80 | (v&0x3f); } iIn += szEscape - 1; }else{ zOut[iOut++] = c; } } /* end for() */ assert( iOut<=nOut ); zOut[iOut] = 0; sqlite3_result_text(pCtx, zOut, iOut, SQLITE_DYNAMIC); break; } case JSONB_ARRAY: case JSONB_OBJECT: { int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx)); if( flags & JSON_BLOB ){ sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT); }else{ jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n); } break; } default: { goto returnfromblob_malformed; } } return; returnfromblob_oom: sqlite3_result_error_nomem(pCtx); return; returnfromblob_malformed: sqlite3_result_error(pCtx, "malformed JSON", -1); return; } /* ** pArg is a function argument that might be an SQL value or a JSON ** value. Figure out what it is and encode it as a JSONB blob. ** Return the results in pParse. ** ** pParse is uninitialized upon entry. This routine will handle the ** initialization of pParse. The result will be contained in ** pParse->aBlob and pParse->nBlob. pParse->aBlob might be dynamically ** allocated (if pParse->nBlobAlloc is greater than zero) in which case ** the caller is responsible for freeing the space allocated to pParse->aBlob ** when it has finished with it. Or pParse->aBlob might be a static string ** or a value obtained from sqlite3_value_blob(pArg). ** ** If the argument is a BLOB that is clearly not a JSONB, then this ** function might set an error message in ctx and return non-zero. ** It might also set an error message and return non-zero on an OOM error. */ static int jsonFunctionArgToBlob( sqlite3_context *ctx, sqlite3_value *pArg, JsonParse *pParse ){ int eType = sqlite3_value_type(pArg); static u8 aNull[] = { 0x00 }; memset(pParse, 0, sizeof(pParse[0])); pParse->db = sqlite3_context_db_handle(ctx); switch( eType ){ default: { pParse->aBlob = aNull; pParse->nBlob = 1; return 0; } case SQLITE_BLOB: { if( jsonFuncArgMightBeBinary(pArg) ){ pParse->aBlob = (u8*)sqlite3_value_blob(pArg); pParse->nBlob = sqlite3_value_bytes(pArg); }else{ sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1); return 1; } break; } case SQLITE_TEXT: { const char *zJson = (const char*)sqlite3_value_text(pArg); int nJson = sqlite3_value_bytes(pArg); if( zJson==0 ) return 1; if( sqlite3_value_subtype(pArg)==JSON_SUBTYPE ){ pParse->zJson = (char*)zJson; pParse->nJson = nJson; if( jsonConvertTextToBlob(pParse, ctx) ){ sqlite3_result_error(ctx, "malformed JSON", -1); sqlite3DbFree(pParse->db, pParse->aBlob); memset(pParse, 0, sizeof(pParse[0])); return 1; } }else{ jsonBlobAppendNode(pParse, JSONB_TEXTRAW, nJson, zJson); } break; } case SQLITE_FLOAT: { double r = sqlite3_value_double(pArg); if( NEVER(sqlite3IsNaN(r)) ){ jsonBlobAppendNode(pParse, JSONB_NULL, 0, 0); }else{ int n = sqlite3_value_bytes(pArg); const char *z = (const char*)sqlite3_value_text(pArg); if( z==0 ) return 1; if( z[0]=='I' ){ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999"); }else if( z[0]=='-' && z[1]=='I' ){ jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999"); }else{ jsonBlobAppendNode(pParse, JSONB_FLOAT, n, z); } } break; } case SQLITE_INTEGER: { int n = sqlite3_value_bytes(pArg); const char *z = (const char*)sqlite3_value_text(pArg); if( z==0 ) return 1; jsonBlobAppendNode(pParse, JSONB_INT, n, z); break; } } if( pParse->oom ){ sqlite3_result_error_nomem(ctx); return 1; }else{ return 0; } } /* ** Generate a bad path error. ** ** If ctx is not NULL then push the error message into ctx and return NULL. ** If ctx is NULL, then return the text of the error message. */ static char *jsonBadPathError( sqlite3_context *ctx, /* The function call containing the error */ const char *zPath /* The path with the problem */ ){ char *zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath); if( ctx==0 ) return zMsg; if( zMsg ){ sqlite3_result_error(ctx, zMsg, -1); sqlite3_free(zMsg); }else{ sqlite3_result_error_nomem(ctx); } return 0; } /* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent ** arguments come in parse where each pair contains a JSON path and ** content to insert or set at that patch. Do the updates ** and return the result. ** ** The specific operation is determined by eEdit, which can be one ** of JEDIT_INS, JEDIT_REPL, or JEDIT_SET. */ static void jsonInsertIntoBlob( sqlite3_context *ctx, int argc, sqlite3_value **argv, int eEdit /* JEDIT_INS, JEDIT_REPL, or JEDIT_SET */ ){ int i; u32 rc = 0; const char *zPath = 0; int flgs; JsonParse *p; JsonParse ax; assert( (argc&1)==1 ); flgs = argc==1 ? 0 : JSON_EDITABLE; p = jsonParseFuncArg(ctx, argv[0], flgs); if( p==0 ) return; for(i=1; inBlob, ax.aBlob, ax.nBlob); } rc = 0; }else{ p->eEdit = eEdit; p->nIns = ax.nBlob; p->aIns = ax.aBlob; p->delta = 0; rc = jsonLookupStep(p, 0, zPath+1, 0); } jsonParseReset(&ax); if( rc==JSON_LOOKUP_NOTFOUND ) continue; if( JSON_LOOKUP_ISERROR(rc) ) goto jsonInsertIntoBlob_patherror; } jsonReturnParse(ctx, p); jsonParseFree(p); return; jsonInsertIntoBlob_patherror: jsonParseFree(p); if( rc==JSON_LOOKUP_ERROR ){ sqlite3_result_error(ctx, "malformed JSON", -1); }else{ jsonBadPathError(ctx, zPath); } return; } /* ** If pArg is a blob that seems like a JSONB blob, then initialize ** p to point to that JSONB and return TRUE. If pArg does not seem like ** a JSONB blob, then return FALSE; ** ** This routine is only called if it is already known that pArg is a ** blob. The only open question is whether or not the blob appears ** to be a JSONB blob. */ static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){ u32 n, sz = 0; p->aBlob = (u8*)sqlite3_value_blob(pArg); p->nBlob = (u32)sqlite3_value_bytes(pArg); if( p->nBlob==0 ){ p->aBlob = 0; return 0; } if( NEVER(p->aBlob==0) ){ return 0; } if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT && (n = jsonbPayloadSize(p, 0, &sz))>0 && sz+n==p->nBlob && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0) ){ return 1; } p->aBlob = 0; p->nBlob = 0; return 0; } /* ** Generate a JsonParse object, containing valid JSONB in aBlob and nBlob, ** from the SQL function argument pArg. Return a pointer to the new ** JsonParse object. ** ** Ownership of the new JsonParse object is passed to the caller. The ** caller should invoke jsonParseFree() on the return value when it ** has finished using it. ** ** If any errors are detected, an appropriate error messages is set ** using sqlite3_result_error() or the equivalent and this routine ** returns NULL. This routine also returns NULL if the pArg argument ** is an SQL NULL value, but no error message is set in that case. This ** is so that SQL functions that are given NULL arguments will return ** a NULL value. */ static JsonParse *jsonParseFuncArg( sqlite3_context *ctx, sqlite3_value *pArg, u32 flgs ){ int eType; /* Datatype of pArg */ JsonParse *p = 0; /* Value to be returned */ JsonParse *pFromCache = 0; /* Value taken from cache */ sqlite3 *db; /* The database connection */ assert( ctx!=0 ); eType = sqlite3_value_type(pArg); if( eType==SQLITE_NULL ){ return 0; } pFromCache = jsonCacheSearch(ctx, pArg); if( pFromCache ){ pFromCache->nJPRef++; if( (flgs & JSON_EDITABLE)==0 ){ return pFromCache; } } db = sqlite3_context_db_handle(ctx); rebuild_from_cache: p = sqlite3DbMallocZero(db, sizeof(*p)); if( p==0 ) goto json_pfa_oom; memset(p, 0, sizeof(*p)); p->db = db; p->nJPRef = 1; if( pFromCache!=0 ){ u32 nBlob = pFromCache->nBlob; p->aBlob = sqlite3DbMallocRaw(db, nBlob); if( p->aBlob==0 ) goto json_pfa_oom; memcpy(p->aBlob, pFromCache->aBlob, nBlob); p->nBlobAlloc = p->nBlob = nBlob; p->hasNonstd = pFromCache->hasNonstd; jsonParseFree(pFromCache); return p; } if( eType==SQLITE_BLOB ){ if( jsonArgIsJsonb(pArg,p) ){ if( (flgs & JSON_EDITABLE)!=0 && jsonBlobMakeEditable(p, 0)==0 ){ goto json_pfa_oom; } return p; } /* If the blob is not valid JSONB, fall through into trying to cast ** the blob into text which is then interpreted as JSON. (tag-20240123-a) ** ** This goes against all historical documentation about how the SQLite ** JSON functions were suppose to work. From the beginning, blob was ** reserved for expansion and a blob value should have raised an error. ** But it did not, due to a bug. And many applications came to depend ** upon this buggy behavior, espeically when using the CLI and reading ** JSON text using readfile(), which returns a blob. For this reason ** we will continue to support the bug moving forward. ** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d */ } p->zJson = (char*)sqlite3_value_text(pArg); p->nJson = sqlite3_value_bytes(pArg); if( p->nJson==0 ) goto json_pfa_malformed; if( NEVER(p->zJson==0) ) goto json_pfa_oom; if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){ if( flgs & JSON_KEEPERROR ){ p->nErr = 1; return p; }else{ jsonParseFree(p); return 0; } }else{ int isRCStr = sqlite3ValueIsOfClass(pArg, sqlite3RCStrUnref); int rc; if( !isRCStr ){ char *zNew = sqlite3RCStrNew( p->nJson ); if( zNew==0 ) goto json_pfa_oom; memcpy(zNew, p->zJson, p->nJson); p->zJson = zNew; p->zJson[p->nJson] = 0; }else{ sqlite3RCStrRef(p->zJson); } p->bJsonIsRCStr = 1; rc = jsonCacheInsert(ctx, p); if( rc==SQLITE_NOMEM ) goto json_pfa_oom; if( flgs & JSON_EDITABLE ){ pFromCache = p; p = 0; goto rebuild_from_cache; } } return p; json_pfa_malformed: if( flgs & JSON_KEEPERROR ){ p->nErr = 1; return p; }else{ jsonParseFree(p); sqlite3_result_error(ctx, "malformed JSON", -1); return 0; } json_pfa_oom: jsonParseFree(pFromCache); jsonParseFree(p); sqlite3_result_error_nomem(ctx); return 0; } /* ** Make the return value of a JSON function either the raw JSONB blob ** or make it JSON text, depending on whether the JSON_BLOB flag is ** set on the function. */ static void jsonReturnParse( sqlite3_context *ctx, JsonParse *p ){ int flgs; if( p->oom ){ sqlite3_result_error_nomem(ctx); return; } flgs = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); if( flgs & JSON_BLOB ){ if( p->nBlobAlloc>0 && !p->bReadOnly ){ sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_DYNAMIC); p->nBlobAlloc = 0; }else{ sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_TRANSIENT); } }else{ JsonString s; jsonStringInit(&s, ctx); p->delta = 0; jsonTranslateBlobToText(p, 0, &s); jsonReturnString(&s, p, ctx); sqlite3_result_subtype(ctx, JSON_SUBTYPE); } } /**************************************************************************** ** SQL functions used for testing and debugging ****************************************************************************/ #if SQLITE_DEBUG /* ** Decode JSONB bytes in aBlob[] starting at iStart through but not ** including iEnd. Indent the ** content by nIndent spaces. */ static void jsonDebugPrintBlob( JsonParse *pParse, /* JSON content */ u32 iStart, /* Start rendering here */ u32 iEnd, /* Do not render this byte or any byte after this one */ int nIndent, /* Indent by this many spaces */ sqlite3_str *pOut /* Generate output into this sqlite3_str object */ ){ while( iStartaBlob[iStart] & 0x0f; u32 savedNBlob = pParse->nBlob; sqlite3_str_appendf(pOut, "%5d:%*s", iStart, nIndent, ""); if( pParse->nBlobAlloc>pParse->nBlob ){ pParse->nBlob = pParse->nBlobAlloc; } nn = n = jsonbPayloadSize(pParse, iStart, &sz); if( nn==0 ) nn = 1; if( sz>0 && xaBlob[iStart+i]); } if( n==0 ){ sqlite3_str_appendf(pOut, " ERROR invalid node size\n"); iStart = n==0 ? iStart+1 : iEnd; continue; } pParse->nBlob = savedNBlob; if( iStart+n+sz>iEnd ){ iEnd = iStart+n+sz; if( iEnd>pParse->nBlob ){ if( pParse->nBlobAlloc>0 && iEnd>pParse->nBlobAlloc ){ iEnd = pParse->nBlobAlloc; }else{ iEnd = pParse->nBlob; } } } sqlite3_str_appendall(pOut," <-- "); switch( x ){ case JSONB_NULL: sqlite3_str_appendall(pOut,"null"); break; case JSONB_TRUE: sqlite3_str_appendall(pOut,"true"); break; case JSONB_FALSE: sqlite3_str_appendall(pOut,"false"); break; case JSONB_INT: sqlite3_str_appendall(pOut,"int"); break; case JSONB_INT5: sqlite3_str_appendall(pOut,"int5"); break; case JSONB_FLOAT: sqlite3_str_appendall(pOut,"float"); break; case JSONB_FLOAT5: sqlite3_str_appendall(pOut,"float5"); break; case JSONB_TEXT: sqlite3_str_appendall(pOut,"text"); break; case JSONB_TEXTJ: sqlite3_str_appendall(pOut,"textj"); break; case JSONB_TEXT5: sqlite3_str_appendall(pOut,"text5"); break; case JSONB_TEXTRAW: sqlite3_str_appendall(pOut,"textraw"); break; case JSONB_ARRAY: { sqlite3_str_appendf(pOut,"array, %u bytes\n", sz); jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut); showContent = 0; break; } case JSONB_OBJECT: { sqlite3_str_appendf(pOut, "object, %u bytes\n", sz); jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut); showContent = 0; break; } default: { sqlite3_str_appendall(pOut, "ERROR: unknown node type\n"); showContent = 0; break; } } if( showContent ){ if( sz==0 && x<=JSONB_FALSE ){ sqlite3_str_append(pOut, "\n", 1); }else{ u32 i; sqlite3_str_appendall(pOut, ": \""); for(i=iStart+n; iaBlob[i]; if( c<0x20 || c>=0x7f ) c = '.'; sqlite3_str_append(pOut, (char*)&c, 1); } sqlite3_str_append(pOut, "\"\n", 2); } } iStart += n + sz; } } static void jsonShowParse(JsonParse *pParse){ sqlite3_str out; char zBuf[1000]; if( pParse==0 ){ printf("NULL pointer\n"); return; }else{ printf("nBlobAlloc = %u\n", pParse->nBlobAlloc); printf("nBlob = %u\n", pParse->nBlob); printf("delta = %d\n", pParse->delta); if( pParse->nBlob==0 ) return; printf("content (bytes 0..%u):\n", pParse->nBlob-1); } sqlite3StrAccumInit(&out, 0, zBuf, sizeof(zBuf), 1000000); jsonDebugPrintBlob(pParse, 0, pParse->nBlob, 0, &out); printf("%s", sqlite3_str_value(&out)); sqlite3_str_reset(&out); } #endif /* SQLITE_DEBUG */ #ifdef SQLITE_DEBUG /* ** SQL function: json_parse(JSON) ** ** Parse JSON using jsonParseFuncArg(). Return text that is a ** human-readable dump of the binary JSONB for the input parameter. */ static void jsonParseFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ sqlite3_str out; assert( argc>=1 ); sqlite3StrAccumInit(&out, 0, 0, 0, 1000000); p = jsonParseFuncArg(ctx, argv[0], 0); if( p==0 ) return; if( argc==1 ){ jsonDebugPrintBlob(p, 0, p->nBlob, 0, &out); sqlite3_result_text64(ctx, out.zText, out.nChar, SQLITE_DYNAMIC, SQLITE_UTF8); }else{ jsonShowParse(p); } jsonParseFree(p); } #endif /* SQLITE_DEBUG */ /**************************************************************************** ** Scalar SQL function implementations ****************************************************************************/ /* ** Implementation of the json_quote(VALUE) function. Return a JSON value ** corresponding to the SQL value input. Mostly this means putting ** double-quotes around strings and returning the unquoted string "null" ** when given a NULL input. */ static void jsonQuoteFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonString jx; UNUSED_PARAMETER(argc); jsonStringInit(&jx, ctx); jsonAppendSqlValue(&jx, argv[0]); jsonReturnString(&jx, 0, 0); sqlite3_result_subtype(ctx, JSON_SUBTYPE); } /* ** Implementation of the json_array(VALUE,...) function. Return a JSON ** array that contains all values given in arguments. Or if any argument ** is a BLOB, throw an error. */ static void jsonArrayFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ int i; JsonString jx; jsonStringInit(&jx, ctx); jsonAppendChar(&jx, '['); for(i=0; iaBlob[i] & 0x0f)==JSONB_ARRAY ){ cnt = jsonbArrayCount(p, i); } if( !eErr ) sqlite3_result_int64(ctx, cnt); jsonParseFree(p); } /* True if the string is all digits */ static int jsonAllDigits(const char *z, int n){ int i; for(i=0; i"(JSON,PATH) ** "->>"(JSON,PATH) ** ** Return the element described by PATH. Return NULL if that PATH element ** is not found. ** ** If JSON_JSON is set or if more that one PATH argument is supplied then ** always return a JSON representation of the result. If JSON_SQL is set, ** then always return an SQL representation of the result. If neither flag ** is present and argc==2, then return JSON for objects and arrays and SQL ** for all other values. ** ** When multiple PATH arguments are supplied, the result is a JSON array ** containing the result of each PATH. ** ** Abbreviated JSON path expressions are allows if JSON_ABPATH, for ** compatibility with PG. */ static void jsonExtractFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p = 0; /* The parse */ int flags; /* Flags associated with the function */ int i; /* Loop counter */ JsonString jx; /* String for array result */ if( argc<2 ) return; p = jsonParseFuncArg(ctx, argv[0], 0); if( p==0 ) return; flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); jsonStringInit(&jx, ctx); if( argc>2 ){ jsonAppendChar(&jx, '['); } for(i=1; i and ->> operators accept abbreviated PATH arguments. This ** is mostly for compatibility with PostgreSQL, but also for ** convenience. ** ** NUMBER ==> $[NUMBER] // PG compatible ** LABEL ==> $.LABEL // PG compatible ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience */ jsonStringInit(&jx, ctx); if( jsonAllDigits(zPath, nPath) ){ jsonAppendRawNZ(&jx, "[", 1); jsonAppendRaw(&jx, zPath, nPath); jsonAppendRawNZ(&jx, "]", 2); }else if( jsonAllAlphanum(zPath, nPath) ){ jsonAppendRawNZ(&jx, ".", 1); jsonAppendRaw(&jx, zPath, nPath); }else if( zPath[0]=='[' && nPath>=3 && zPath[nPath-1]==']' ){ jsonAppendRaw(&jx, zPath, nPath); }else{ jsonAppendRawNZ(&jx, ".\"", 2); jsonAppendRaw(&jx, zPath, nPath); jsonAppendRawNZ(&jx, "\"", 1); } jsonStringTerminate(&jx); j = jsonLookupStep(p, 0, jx.zBuf, 0); jsonStringReset(&jx); }else{ jsonBadPathError(ctx, zPath); goto json_extract_error; } if( jnBlob ){ if( argc==2 ){ if( flags & JSON_JSON ){ jsonStringInit(&jx, ctx); jsonTranslateBlobToText(p, j, &jx); jsonReturnString(&jx, 0, 0); jsonStringReset(&jx); assert( (flags & JSON_BLOB)==0 ); sqlite3_result_subtype(ctx, JSON_SUBTYPE); }else{ jsonReturnFromBlob(p, j, ctx, 0); if( (flags & (JSON_SQL|JSON_BLOB))==0 && (p->aBlob[j]&0x0f)>=JSONB_ARRAY ){ sqlite3_result_subtype(ctx, JSON_SUBTYPE); } } }else{ jsonAppendSeparator(&jx); jsonTranslateBlobToText(p, j, &jx); } }else if( j==JSON_LOOKUP_NOTFOUND ){ if( argc==2 ){ goto json_extract_error; /* Return NULL if not found */ }else{ jsonAppendSeparator(&jx); jsonAppendRawNZ(&jx, "null", 4); } }else if( j==JSON_LOOKUP_ERROR ){ sqlite3_result_error(ctx, "malformed JSON", -1); goto json_extract_error; }else{ jsonBadPathError(ctx, zPath); goto json_extract_error; } } if( argc>2 ){ jsonAppendChar(&jx, ']'); jsonReturnString(&jx, 0, 0); if( (flags & JSON_BLOB)==0 ){ sqlite3_result_subtype(ctx, JSON_SUBTYPE); } } json_extract_error: jsonStringReset(&jx); jsonParseFree(p); return; } /* ** Return codes for jsonMergePatch() */ #define JSON_MERGE_OK 0 /* Success */ #define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */ #define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */ #define JSON_MERGE_OOM 3 /* Out-of-memory condition */ /* ** RFC-7396 MergePatch for two JSONB blobs. ** ** pTarget is the target. pPatch is the patch. The target is updated ** in place. The patch is read-only. ** ** The original RFC-7396 algorithm is this: ** ** define MergePatch(Target, Patch): ** if Patch is an Object: ** if Target is not an Object: ** Target = {} # Ignore the contents and set it to an empty Object ** for each Name/Value pair in Patch: ** if Value is null: ** if Name exists in Target: ** remove the Name/Value pair from Target ** else: ** Target[Name] = MergePatch(Target[Name], Value) ** return Target ** else: ** return Patch ** ** Here is an equivalent algorithm restructured to show the actual ** implementation: ** ** 01 define MergePatch(Target, Patch): ** 02 if Patch is not an Object: ** 03 return Patch ** 04 else: // if Patch is an Object ** 05 if Target is not an Object: ** 06 Target = {} ** 07 for each Name/Value pair in Patch: ** 08 if Name exists in Target: ** 09 if Value is null: ** 10 remove the Name/Value pair from Target ** 11 else ** 12 Target[name] = MergePatch(Target[Name], Value) ** 13 else if Value is not NULL: ** 14 if Value is not an Object: ** 15 Target[name] = Value ** 16 else: ** 17 Target[name] = MergePatch('{}',value) ** 18 return Target ** | ** ^---- Line numbers referenced in comments in the implementation */ static int jsonMergePatch( JsonParse *pTarget, /* The JSON parser that contains the TARGET */ u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */ const JsonParse *pPatch, /* The PATCH */ u32 iPatch /* Index of PATCH in pPatch->aBlob[] */ ){ u8 x; /* Type of a single node */ u32 n, sz=0; /* Return values from jsonbPayloadSize() */ u32 iTCursor; /* Cursor position while scanning the target object */ u32 iTStart; /* First label in the target object */ u32 iTEndBE; /* Original first byte past end of target, before edit */ u32 iTEnd; /* Current first byte past end of target */ u8 eTLabel; /* Node type of the target label */ u32 iTLabel = 0; /* Index of the label */ u32 nTLabel = 0; /* Header size in bytes for the target label */ u32 szTLabel = 0; /* Size of the target label payload */ u32 iTValue = 0; /* Index of the target value */ u32 nTValue = 0; /* Header size of the target value */ u32 szTValue = 0; /* Payload size for the target value */ u32 iPCursor; /* Cursor position while scanning the patch */ u32 iPEnd; /* First byte past the end of the patch */ u8 ePLabel; /* Node type of the patch label */ u32 iPLabel; /* Start of patch label */ u32 nPLabel; /* Size of header on the patch label */ u32 szPLabel; /* Payload size of the patch label */ u32 iPValue; /* Start of patch value */ u32 nPValue; /* Header size for the patch value */ u32 szPValue; /* Payload size of the patch value */ assert( iTarget>=0 && iTargetnBlob ); assert( iPatch>=0 && iPatchnBlob ); x = pPatch->aBlob[iPatch] & 0x0f; if( x!=JSONB_OBJECT ){ /* Algorithm line 02 */ u32 szPatch; /* Total size of the patch, header+payload */ u32 szTarget; /* Total size of the target, header+payload */ n = jsonbPayloadSize(pPatch, iPatch, &sz); szPatch = n+sz; sz = 0; n = jsonbPayloadSize(pTarget, iTarget, &sz); szTarget = n+sz; jsonBlobEdit(pTarget, iTarget, szTarget, pPatch->aBlob+iPatch, szPatch); return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK; /* Line 03 */ } x = pTarget->aBlob[iTarget] & 0x0f; if( x!=JSONB_OBJECT ){ /* Algorithm line 05 */ n = jsonbPayloadSize(pTarget, iTarget, &sz); jsonBlobEdit(pTarget, iTarget+n, sz, 0, 0); x = pTarget->aBlob[iTarget]; pTarget->aBlob[iTarget] = (x & 0xf0) | JSONB_OBJECT; } n = jsonbPayloadSize(pPatch, iPatch, &sz); if( NEVER(n==0) ) return JSON_MERGE_BADPATCH; iPCursor = iPatch+n; iPEnd = iPCursor+sz; n = jsonbPayloadSize(pTarget, iTarget, &sz); if( NEVER(n==0) ) return JSON_MERGE_BADTARGET; iTStart = iTarget+n; iTEndBE = iTStart+sz; while( iPCursoraBlob[iPCursor] & 0x0f; if( ePLabelJSONB_TEXTRAW ){ return JSON_MERGE_BADPATCH; } nPLabel = jsonbPayloadSize(pPatch, iPCursor, &szPLabel); if( nPLabel==0 ) return JSON_MERGE_BADPATCH; iPValue = iPCursor + nPLabel + szPLabel; if( iPValue>=iPEnd ) return JSON_MERGE_BADPATCH; nPValue = jsonbPayloadSize(pPatch, iPValue, &szPValue); if( nPValue==0 ) return JSON_MERGE_BADPATCH; iPCursor = iPValue + nPValue + szPValue; if( iPCursor>iPEnd ) return JSON_MERGE_BADPATCH; iTCursor = iTStart; iTEnd = iTEndBE + pTarget->delta; while( iTCursoraBlob[iTCursor] & 0x0f; if( eTLabelJSONB_TEXTRAW ){ return JSON_MERGE_BADTARGET; } nTLabel = jsonbPayloadSize(pTarget, iTCursor, &szTLabel); if( nTLabel==0 ) return JSON_MERGE_BADTARGET; iTValue = iTLabel + nTLabel + szTLabel; if( iTValue>=iTEnd ) return JSON_MERGE_BADTARGET; nTValue = jsonbPayloadSize(pTarget, iTValue, &szTValue); if( nTValue==0 ) return JSON_MERGE_BADTARGET; if( iTValue + nTValue + szTValue > iTEnd ) return JSON_MERGE_BADTARGET; isEqual = jsonLabelCompare( (const char*)&pPatch->aBlob[iPLabel+nPLabel], szPLabel, (ePLabel==JSONB_TEXT || ePLabel==JSONB_TEXTRAW), (const char*)&pTarget->aBlob[iTLabel+nTLabel], szTLabel, (eTLabel==JSONB_TEXT || eTLabel==JSONB_TEXTRAW)); if( isEqual ) break; iTCursor = iTValue + nTValue + szTValue; } x = pPatch->aBlob[iPValue] & 0x0f; if( iTCursoroom) ) return JSON_MERGE_OOM; }else{ /* Algorithm line 12 */ int rc, savedDelta = pTarget->delta; pTarget->delta = 0; rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue); if( rc ) return rc; pTarget->delta += savedDelta; } }else if( x>0 ){ /* Algorithm line 13 */ /* No match and patch value is not NULL */ u32 szNew = szPLabel+nPLabel; if( (pPatch->aBlob[iPValue] & 0x0f)!=JSONB_OBJECT ){ /* Line 14 */ jsonBlobEdit(pTarget, iTEnd, 0, 0, szPValue+nPValue+szNew); if( pTarget->oom ) return JSON_MERGE_OOM; memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew); memcpy(&pTarget->aBlob[iTEnd+szNew], &pPatch->aBlob[iPValue], szPValue+nPValue); }else{ int rc, savedDelta; jsonBlobEdit(pTarget, iTEnd, 0, 0, szNew+1); if( pTarget->oom ) return JSON_MERGE_OOM; memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew); pTarget->aBlob[iTEnd+szNew] = 0x00; savedDelta = pTarget->delta; pTarget->delta = 0; rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue); if( rc ) return rc; pTarget->delta += savedDelta; } } } if( pTarget->delta ) jsonAfterEditSizeAdjust(pTarget, iTarget); return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK; } /* ** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON ** object that is the result of running the RFC 7396 MergePatch() algorithm ** on the two arguments. */ static void jsonPatchFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *pTarget; /* The TARGET */ JsonParse *pPatch; /* The PATCH */ int rc; /* Result code */ UNUSED_PARAMETER(argc); assert( argc==2 ); pTarget = jsonParseFuncArg(ctx, argv[0], JSON_EDITABLE); if( pTarget==0 ) return; pPatch = jsonParseFuncArg(ctx, argv[1], 0); if( pPatch ){ rc = jsonMergePatch(pTarget, 0, pPatch, 0); if( rc==JSON_MERGE_OK ){ jsonReturnParse(ctx, pTarget); }else if( rc==JSON_MERGE_OOM ){ sqlite3_result_error_nomem(ctx); }else{ sqlite3_result_error(ctx, "malformed JSON", -1); } jsonParseFree(pPatch); } jsonParseFree(pTarget); } /* ** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON ** object that contains all name/value given in arguments. Or if any name ** is not a string or if any value is a BLOB, throw an error. */ static void jsonObjectFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ int i; JsonString jx; const char *z; u32 n; if( argc&1 ){ sqlite3_result_error(ctx, "json_object() requires an even number " "of arguments", -1); return; } jsonStringInit(&jx, ctx); jsonAppendChar(&jx, '{'); for(i=0; i1 ? JSON_EDITABLE : 0); if( p==0 ) return; for(i=1; ieEdit = JEDIT_DEL; p->delta = 0; rc = jsonLookupStep(p, 0, zPath+1, 0); if( JSON_LOOKUP_ISERROR(rc) ){ if( rc==JSON_LOOKUP_NOTFOUND ){ continue; /* No-op */ }else if( rc==JSON_LOOKUP_PATHERROR ){ jsonBadPathError(ctx, zPath); }else{ sqlite3_result_error(ctx, "malformed JSON", -1); } goto json_remove_done; } } jsonReturnParse(ctx, p); jsonParseFree(p); return; json_remove_patherror: jsonBadPathError(ctx, zPath); json_remove_done: jsonParseFree(p); return; } /* ** json_replace(JSON, PATH, VALUE, ...) ** ** Replace the value at PATH with VALUE. If PATH does not already exist, ** this routine is a no-op. If JSON or PATH is malformed, throw an error. */ static void jsonReplaceFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ if( argc<1 ) return; if( (argc&1)==0 ) { jsonWrongNumArgs(ctx, "replace"); return; } jsonInsertIntoBlob(ctx, argc, argv, JEDIT_REPL); } /* ** json_set(JSON, PATH, VALUE, ...) ** ** Set the value at PATH to VALUE. Create the PATH if it does not already ** exist. Overwrite existing values that do exist. ** If JSON or PATH is malformed, throw an error. ** ** json_insert(JSON, PATH, VALUE, ...) ** ** Create PATH and initialize it to VALUE. If PATH already exists, this ** routine is a no-op. If JSON or PATH is malformed, throw an error. */ static void jsonSetFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); int bIsSet = (flags&JSON_ISSET)!=0; if( argc<1 ) return; if( (argc&1)==0 ) { jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); return; } jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS); } /* ** json_type(JSON) ** json_type(JSON, PATH) ** ** Return the top-level "type" of a JSON string. json_type() raises an ** error if either the JSON or PATH inputs are not well-formed. */ static void jsonTypeFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ const char *zPath = 0; u32 i; p = jsonParseFuncArg(ctx, argv[0], 0); if( p==0 ) return; if( argc==2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); if( zPath==0 ) goto json_type_done; if( zPath[0]!='$' ){ jsonBadPathError(ctx, zPath); goto json_type_done; } i = jsonLookupStep(p, 0, zPath+1, 0); if( JSON_LOOKUP_ISERROR(i) ){ if( i==JSON_LOOKUP_NOTFOUND ){ /* no-op */ }else if( i==JSON_LOOKUP_PATHERROR ){ jsonBadPathError(ctx, zPath); }else{ sqlite3_result_error(ctx, "malformed JSON", -1); } goto json_type_done; } }else{ i = 0; } sqlite3_result_text(ctx, jsonbType[p->aBlob[i]&0x0f], -1, SQLITE_STATIC); json_type_done: jsonParseFree(p); } /* ** json_valid(JSON) ** json_valid(JSON, FLAGS) ** ** Check the JSON argument to see if it is well-formed. The FLAGS argument ** encodes the various constraints on what is meant by "well-formed": ** ** 0x01 Canonical RFC-8259 JSON text ** 0x02 JSON text with optional JSON-5 extensions ** 0x04 Superficially appears to be JSONB ** 0x08 Strictly well-formed JSONB ** ** If the FLAGS argument is omitted, it defaults to 1. Useful values for ** FLAGS include: ** ** 1 Strict canonical JSON text ** 2 JSON text perhaps with JSON-5 extensions ** 4 Superficially appears to be JSONB ** 5 Canonical JSON text or superficial JSONB ** 6 JSON-5 text or superficial JSONB ** 8 Strict JSONB ** 9 Canonical JSON text or strict JSONB ** 10 JSON-5 text or strict JSONB ** ** Other flag combinations are redundant. For example, every canonical ** JSON text is also well-formed JSON-5 text, so FLAG values 2 and 3 ** are the same. Similarly, any input that passes a strict JSONB validation ** will also pass the superficial validation so 12 through 15 are the same ** as 8 through 11 respectively. ** ** This routine runs in linear time to validate text and when doing strict ** JSONB validation. Superficial JSONB validation is constant time, ** assuming the BLOB is already in memory. The performance advantage ** of superficial JSONB validation is why that option is provided. ** Application developers can choose to do fast superficial validation or ** slower strict validation, according to their specific needs. ** ** Only the lower four bits of the FLAGS argument are currently used. ** Higher bits are reserved for future expansion. To facilitate ** compatibility, the current implementation raises an error if any bit ** in FLAGS is set other than the lower four bits. ** ** The original circa 2015 implementation of the JSON routines in ** SQLite only supported canonical RFC-8259 JSON text and the json_valid() ** function only accepted one argument. That is why the default value ** for the FLAGS argument is 1, since FLAGS=1 causes this routine to only ** recognize canonical RFC-8259 JSON text as valid. The extra FLAGS ** argument was added when the JSON routines were extended to support ** JSON5-like extensions and binary JSONB stored in BLOBs. ** ** Return Values: ** ** * Raise an error if FLAGS is outside the range of 1 to 15. ** * Return NULL if the input is NULL ** * Return 1 if the input is well-formed. ** * Return 0 if the input is not well-formed. */ static void jsonValidFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ u8 flags = 1; u8 res = 0; if( argc==2 ){ i64 f = sqlite3_value_int64(argv[1]); if( f<1 || f>15 ){ sqlite3_result_error(ctx, "FLAGS parameter to json_valid() must be" " between 1 and 15", -1); return; } flags = f & 0x0f; } switch( sqlite3_value_type(argv[0]) ){ case SQLITE_NULL: { #ifdef SQLITE_LEGACY_JSON_VALID /* Incorrect legacy behavior was to return FALSE for a NULL input */ sqlite3_result_int(ctx, 0); #endif return; } case SQLITE_BLOB: { if( jsonFuncArgMightBeBinary(argv[0]) ){ if( flags & 0x04 ){ /* Superficial checking only - accomplished by the ** jsonFuncArgMightBeBinary() call above. */ res = 1; }else if( flags & 0x08 ){ /* Strict checking. Check by translating BLOB->TEXT->BLOB. If ** no errors occur, call that a "strict check". */ JsonParse px; u32 iErr; memset(&px, 0, sizeof(px)); px.aBlob = (u8*)sqlite3_value_blob(argv[0]); px.nBlob = sqlite3_value_bytes(argv[0]); iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1); res = iErr==0; } break; } /* Fall through into interpreting the input as text. See note ** above at tag-20240123-a. */ /* no break */ deliberate_fall_through } default: { JsonParse px; if( (flags & 0x3)==0 ) break; memset(&px, 0, sizeof(px)); p = jsonParseFuncArg(ctx, argv[0], JSON_KEEPERROR); if( p ){ if( p->oom ){ sqlite3_result_error_nomem(ctx); }else if( p->nErr ){ /* no-op */ }else if( (flags & 0x02)!=0 || p->hasNonstd==0 ){ res = 1; } jsonParseFree(p); }else{ sqlite3_result_error_nomem(ctx); } break; } } sqlite3_result_int(ctx, res); } /* ** json_error_position(JSON) ** ** If the argument is NULL, return NULL ** ** If the argument is BLOB, do a full validity check and return non-zero ** if the check fails. The return value is the approximate 1-based offset ** to the byte of the element that contains the first error. ** ** Otherwise interpret the argument is TEXT (even if it is numeric) and ** return the 1-based character position for where the parser first recognized ** that the input was not valid JSON, or return 0 if the input text looks ** ok. JSON-5 extensions are accepted. */ static void jsonErrorFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ i64 iErrPos = 0; /* Error position to be returned */ JsonParse s; assert( argc==1 ); UNUSED_PARAMETER(argc); memset(&s, 0, sizeof(s)); s.db = sqlite3_context_db_handle(ctx); if( jsonFuncArgMightBeBinary(argv[0]) ){ s.aBlob = (u8*)sqlite3_value_blob(argv[0]); s.nBlob = sqlite3_value_bytes(argv[0]); iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1); }else{ s.zJson = (char*)sqlite3_value_text(argv[0]); if( s.zJson==0 ) return; /* NULL input or OOM */ s.nJson = sqlite3_value_bytes(argv[0]); if( jsonConvertTextToBlob(&s,0) ){ if( s.oom ){ iErrPos = -1; }else{ /* Convert byte-offset s.iErr into a character offset */ u32 k; assert( s.zJson!=0 ); /* Because s.oom is false */ for(k=0; kzBuf==0 ){ jsonStringInit(pStr, ctx); jsonAppendChar(pStr, '['); }else if( pStr->nUsed>1 ){ jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; jsonAppendSqlValue(pStr, argv[0]); } } static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ int flags; pStr->pCtx = ctx; jsonAppendChar(pStr, ']'); flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); if( pStr->eErr ){ jsonReturnString(pStr, 0, 0); return; }else if( flags & JSON_BLOB ){ jsonReturnStringAsBlob(pStr); if( isFinal ){ if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf); }else{ jsonStringTrimOneChar(pStr); } return; }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : sqlite3RCStrUnref); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); jsonStringTrimOneChar(pStr); } }else{ sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); } sqlite3_result_subtype(ctx, JSON_SUBTYPE); } static void jsonArrayValue(sqlite3_context *ctx){ jsonArrayCompute(ctx, 0); } static void jsonArrayFinal(sqlite3_context *ctx){ jsonArrayCompute(ctx, 1); } #ifndef SQLITE_OMIT_WINDOWFUNC /* ** This method works for both json_group_array() and json_group_object(). ** It works by removing the first element of the group by searching forward ** to the first comma (",") that is not within a string and deleting all ** text through that comma. */ static void jsonGroupInverse( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ unsigned int i; int inStr = 0; int nNest = 0; char *z; char c; JsonString *pStr; UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); #ifdef NEVER /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will ** always have been called to initialize it */ if( NEVER(!pStr) ) return; #endif z = pStr->zBuf; for(i=1; inUsed && ((c = z[i])!=',' || inStr || nNest); i++){ if( c=='"' ){ inStr = !inStr; }else if( c=='\\' ){ i++; }else if( !inStr ){ if( c=='{' || c=='[' ) nNest++; if( c=='}' || c==']' ) nNest--; } } if( inUsed ){ pStr->nUsed -= i; memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1); z[pStr->nUsed] = 0; }else{ pStr->nUsed = 1; } } #else # define jsonGroupInverse 0 #endif /* ** json_group_obj(NAME,VALUE) ** ** Return a JSON object composed of all names and values in the aggregate. */ static void jsonObjectStep( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonString *pStr; const char *z; u32 n; UNUSED_PARAMETER(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ if( pStr->zBuf==0 ){ jsonStringInit(pStr, ctx); jsonAppendChar(pStr, '{'); }else if( pStr->nUsed>1 ){ jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; z = (const char*)sqlite3_value_text(argv[0]); n = sqlite3Strlen30(z); jsonAppendString(pStr, z, n); jsonAppendChar(pStr, ':'); jsonAppendSqlValue(pStr, argv[1]); } } static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ int flags; jsonAppendChar(pStr, '}'); pStr->pCtx = ctx; flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); if( pStr->eErr ){ jsonReturnString(pStr, 0, 0); return; }else if( flags & JSON_BLOB ){ jsonReturnStringAsBlob(pStr); if( isFinal ){ if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf); }else{ jsonStringTrimOneChar(pStr); } return; }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : sqlite3RCStrUnref); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); jsonStringTrimOneChar(pStr); } }else{ sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); } sqlite3_result_subtype(ctx, JSON_SUBTYPE); } static void jsonObjectValue(sqlite3_context *ctx){ jsonObjectCompute(ctx, 0); } static void jsonObjectFinal(sqlite3_context *ctx){ jsonObjectCompute(ctx, 1); } #ifndef SQLITE_OMIT_VIRTUALTABLE /**************************************************************************** ** The json_each virtual table ****************************************************************************/ typedef struct JsonParent JsonParent; struct JsonParent { u32 iHead; /* Start of object or array */ u32 iValue; /* Start of the value */ u32 iEnd; /* First byte past the end */ u32 nPath; /* Length of path */ i64 iKey; /* Key for JSONB_ARRAY */ }; typedef struct JsonEachCursor JsonEachCursor; struct JsonEachCursor { sqlite3_vtab_cursor base; /* Base class - must be first */ u32 iRowid; /* The rowid */ u32 i; /* Index in sParse.aBlob[] of current row */ u32 iEnd; /* EOF when i equals or exceeds this value */ u32 nRoot; /* Size of the root path in bytes */ u8 eType; /* Type of the container for element i */ u8 bRecursive; /* True for json_tree(). False for json_each() */ u32 nParent; /* Current nesting depth */ u32 nParentAlloc; /* Space allocated for aParent[] */ JsonParent *aParent; /* Parent elements of i */ sqlite3 *db; /* Database connection */ JsonString path; /* Current path */ JsonParse sParse; /* Parse of the input JSON */ }; typedef struct JsonEachConnection JsonEachConnection; struct JsonEachConnection { sqlite3_vtab base; /* Base class - must be first */ sqlite3 *db; /* Database connection */ }; /* Constructor for the json_each virtual table */ static int jsonEachConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ JsonEachConnection *pNew; int rc; /* Column numbers */ #define JEACH_KEY 0 #define JEACH_VALUE 1 #define JEACH_TYPE 2 #define JEACH_ATOM 3 #define JEACH_ID 4 #define JEACH_PARENT 5 #define JEACH_FULLKEY 6 #define JEACH_PATH 7 /* The xBestIndex method assumes that the JSON and ROOT columns are ** the last two columns in the table. Should this ever changes, be ** sure to update the xBestIndex method. */ #define JEACH_JSON 8 #define JEACH_ROOT 9 UNUSED_PARAMETER(pzErr); UNUSED_PARAMETER(argv); UNUSED_PARAMETER(argc); UNUSED_PARAMETER(pAux); rc = sqlite3_declare_vtab(db, "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," "json HIDDEN,root HIDDEN)"); if( rc==SQLITE_OK ){ pNew = (JsonEachConnection*)sqlite3DbMallocZero(db, sizeof(*pNew)); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); pNew->db = db; } return rc; } /* destructor for json_each virtual table */ static int jsonEachDisconnect(sqlite3_vtab *pVtab){ JsonEachConnection *p = (JsonEachConnection*)pVtab; sqlite3DbFree(p->db, pVtab); return SQLITE_OK; } /* constructor for a JsonEachCursor object for json_each(). */ static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ JsonEachConnection *pVtab = (JsonEachConnection*)p; JsonEachCursor *pCur; UNUSED_PARAMETER(p); pCur = sqlite3DbMallocZero(pVtab->db, sizeof(*pCur)); if( pCur==0 ) return SQLITE_NOMEM; pCur->db = pVtab->db; jsonStringZero(&pCur->path); *ppCursor = &pCur->base; return SQLITE_OK; } /* constructor for a JsonEachCursor object for json_tree(). */ static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ int rc = jsonEachOpenEach(p, ppCursor); if( rc==SQLITE_OK ){ JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; pCur->bRecursive = 1; } return rc; } /* Reset a JsonEachCursor back to its original state. Free any memory ** held. */ static void jsonEachCursorReset(JsonEachCursor *p){ jsonParseReset(&p->sParse); jsonStringReset(&p->path); sqlite3DbFree(p->db, p->aParent); p->iRowid = 0; p->i = 0; p->aParent = 0; p->nParent = 0; p->nParentAlloc = 0; p->iEnd = 0; p->eType = 0; } /* Destructor for a jsonEachCursor object */ static int jsonEachClose(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; jsonEachCursorReset(p); sqlite3DbFree(p->db, cur); return SQLITE_OK; } /* Return TRUE if the jsonEachCursor object has been advanced off the end ** of the JSON object */ static int jsonEachEof(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; return p->i >= p->iEnd; } /* ** If the cursor is currently pointing at the label of a object entry, ** then return the index of the value. For all other cases, return the ** current pointer position, which is the value. */ static int jsonSkipLabel(JsonEachCursor *p){ if( p->eType==JSONB_OBJECT ){ u32 sz = 0; u32 n = jsonbPayloadSize(&p->sParse, p->i, &sz); return p->i + n + sz; }else{ return p->i; } } /* ** Append the path name for the current element. */ static void jsonAppendPathName(JsonEachCursor *p){ assert( p->nParent>0 ); assert( p->eType==JSONB_ARRAY || p->eType==JSONB_OBJECT ); if( p->eType==JSONB_ARRAY ){ jsonPrintf(30, &p->path, "[%lld]", p->aParent[p->nParent-1].iKey); }else{ u32 n, sz = 0, k, i; const char *z; int needQuote = 0; n = jsonbPayloadSize(&p->sParse, p->i, &sz); k = p->i + n; z = (const char*)&p->sParse.aBlob[k]; if( sz==0 || !sqlite3Isalpha(z[0]) ){ needQuote = 1; }else{ for(i=0; ipath,".\"%.*s\"", sz, z); }else{ jsonPrintf(sz+2,&p->path,".%.*s", sz, z); } } } /* Advance the cursor to the next element for json_tree() */ static int jsonEachNext(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; int rc = SQLITE_OK; if( p->bRecursive ){ u8 x; u8 levelChange = 0; u32 n, sz = 0; u32 i = jsonSkipLabel(p); x = p->sParse.aBlob[i] & 0x0f; n = jsonbPayloadSize(&p->sParse, i, &sz); if( x==JSONB_OBJECT || x==JSONB_ARRAY ){ JsonParent *pParent; if( p->nParent>=p->nParentAlloc ){ JsonParent *pNew; u64 nNew; nNew = p->nParentAlloc*2 + 3; pNew = sqlite3DbRealloc(p->db, p->aParent, sizeof(JsonParent)*nNew); if( pNew==0 ) return SQLITE_NOMEM; p->nParentAlloc = (u32)nNew; p->aParent = pNew; } levelChange = 1; pParent = &p->aParent[p->nParent]; pParent->iHead = p->i; pParent->iValue = i; pParent->iEnd = i + n + sz; pParent->iKey = -1; pParent->nPath = (u32)p->path.nUsed; if( p->eType && p->nParent ){ jsonAppendPathName(p); if( p->path.eErr ) rc = SQLITE_NOMEM; } p->nParent++; p->i = i + n; }else{ p->i = i + n + sz; } while( p->nParent>0 && p->i >= p->aParent[p->nParent-1].iEnd ){ p->nParent--; p->path.nUsed = p->aParent[p->nParent].nPath; levelChange = 1; } if( levelChange ){ if( p->nParent>0 ){ JsonParent *pParent = &p->aParent[p->nParent-1]; u32 iVal = pParent->iValue; p->eType = p->sParse.aBlob[iVal] & 0x0f; }else{ p->eType = 0; } } }else{ u32 n, sz = 0; u32 i = jsonSkipLabel(p); n = jsonbPayloadSize(&p->sParse, i, &sz); p->i = i + n + sz; } if( p->eType==JSONB_ARRAY && p->nParent ){ p->aParent[p->nParent-1].iKey++; } p->iRowid++; return rc; } /* Length of the path for rowid==0 in bRecursive mode. */ static int jsonEachPathLength(JsonEachCursor *p){ u32 n = p->path.nUsed; char *z = p->path.zBuf; if( p->iRowid==0 && p->bRecursive && n>=2 ){ while( n>1 ){ n--; if( z[n]=='[' || z[n]=='.' ){ u32 x, sz = 0; char cSaved = z[n]; z[n] = 0; assert( p->sParse.eEdit==0 ); x = jsonLookupStep(&p->sParse, 0, z+1, 0); z[n] = cSaved; if( JSON_LOOKUP_ISERROR(x) ) continue; if( x + jsonbPayloadSize(&p->sParse, x, &sz) == p->i ) break; } } } return n; } /* Return the value of a column */ static int jsonEachColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int iColumn /* Which column to return */ ){ JsonEachCursor *p = (JsonEachCursor*)cur; switch( iColumn ){ case JEACH_KEY: { if( p->nParent==0 ){ u32 n, j; if( p->nRoot==1 ) break; j = jsonEachPathLength(p); n = p->nRoot - j; if( n==0 ){ break; }else if( p->path.zBuf[j]=='[' ){ i64 x; sqlite3Atoi64(&p->path.zBuf[j+1], &x, n-1, SQLITE_UTF8); sqlite3_result_int64(ctx, x); }else if( p->path.zBuf[j+1]=='"' ){ sqlite3_result_text(ctx, &p->path.zBuf[j+2], n-3, SQLITE_TRANSIENT); }else{ sqlite3_result_text(ctx, &p->path.zBuf[j+1], n-1, SQLITE_TRANSIENT); } break; } if( p->eType==JSONB_OBJECT ){ jsonReturnFromBlob(&p->sParse, p->i, ctx, 1); }else{ assert( p->eType==JSONB_ARRAY ); sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey); } break; } case JEACH_VALUE: { u32 i = jsonSkipLabel(p); jsonReturnFromBlob(&p->sParse, i, ctx, 1); break; } case JEACH_TYPE: { u32 i = jsonSkipLabel(p); u8 eType = p->sParse.aBlob[i] & 0x0f; sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC); break; } case JEACH_ATOM: { u32 i = jsonSkipLabel(p); if( (p->sParse.aBlob[i] & 0x0f)sParse, i, ctx, 1); } break; } case JEACH_ID: { sqlite3_result_int64(ctx, (sqlite3_int64)p->i); break; } case JEACH_PARENT: { if( p->nParent>0 && p->bRecursive ){ sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead); } break; } case JEACH_FULLKEY: { u64 nBase = p->path.nUsed; if( p->nParent ) jsonAppendPathName(p); sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed, SQLITE_TRANSIENT, SQLITE_UTF8); p->path.nUsed = nBase; break; } case JEACH_PATH: { u32 n = jsonEachPathLength(p); sqlite3_result_text64(ctx, p->path.zBuf, n, SQLITE_TRANSIENT, SQLITE_UTF8); break; } default: { sqlite3_result_text(ctx, p->path.zBuf, p->nRoot, SQLITE_STATIC); break; } case JEACH_JSON: { if( p->sParse.zJson==0 ){ sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob, SQLITE_STATIC); }else{ sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); } break; } } return SQLITE_OK; } /* Return the current rowid value */ static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ JsonEachCursor *p = (JsonEachCursor*)cur; *pRowid = p->iRowid; return SQLITE_OK; } /* The query strategy is to look for an equality constraint on the json ** column. Without such a constraint, the table cannot operate. idxNum is ** 1 if the constraint is found, 3 if the constraint and zRoot are found, ** and 0 otherwise. */ static int jsonEachBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; /* Loop counter or computed array index */ int aIdx[2]; /* Index of constraints for JSON and ROOT */ int unusableMask = 0; /* Mask of unusable JSON and ROOT constraints */ int idxMask = 0; /* Mask of usable == constraints JSON and ROOT */ const struct sqlite3_index_constraint *pConstraint; /* This implementation assumes that JSON and ROOT are the last two ** columns in the table */ assert( JEACH_ROOT == JEACH_JSON+1 ); UNUSED_PARAMETER(tab); aIdx[0] = aIdx[1] = -1; pConstraint = pIdxInfo->aConstraint; for(i=0; inConstraint; i++, pConstraint++){ int iCol; int iMask; if( pConstraint->iColumn < JEACH_JSON ) continue; iCol = pConstraint->iColumn - JEACH_JSON; assert( iCol==0 || iCol==1 ); testcase( iCol==0 ); iMask = 1 << iCol; if( pConstraint->usable==0 ){ unusableMask |= iMask; }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ aIdx[iCol] = i; idxMask |= iMask; } } if( pIdxInfo->nOrderBy>0 && pIdxInfo->aOrderBy[0].iColumn<0 && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } if( (unusableMask & ~idxMask)!=0 ){ /* If there are any unusable constraints on JSON or ROOT, then reject ** this entire plan */ return SQLITE_CONSTRAINT; } if( aIdx[0]<0 ){ /* No JSON input. Leave estimatedCost at the huge value that it was ** initialized to to discourage the query planner from selecting this ** plan. */ pIdxInfo->idxNum = 0; }else{ pIdxInfo->estimatedCost = 1.0; i = aIdx[0]; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; if( aIdx[1]<0 ){ pIdxInfo->idxNum = 1; /* Only JSON supplied. Plan 1 */ }else{ i = aIdx[1]; pIdxInfo->aConstraintUsage[i].argvIndex = 2; pIdxInfo->aConstraintUsage[i].omit = 1; pIdxInfo->idxNum = 3; /* Both JSON and ROOT are supplied. Plan 3 */ } } return SQLITE_OK; } /* Start a search on a new JSON string */ static int jsonEachFilter( sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ JsonEachCursor *p = (JsonEachCursor*)cur; const char *zRoot = 0; u32 i, n, sz; UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(argc); jsonEachCursorReset(p); if( idxNum==0 ) return SQLITE_OK; memset(&p->sParse, 0, sizeof(p->sParse)); p->sParse.nJPRef = 1; p->sParse.db = p->db; if( jsonFuncArgMightBeBinary(argv[0]) ){ p->sParse.nBlob = sqlite3_value_bytes(argv[0]); p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]); }else{ p->sParse.zJson = (char*)sqlite3_value_text(argv[0]); p->sParse.nJson = sqlite3_value_bytes(argv[0]); if( p->sParse.zJson==0 ){ p->i = p->iEnd = 0; return SQLITE_OK; } if( jsonConvertTextToBlob(&p->sParse, 0) ){ if( p->sParse.oom ){ return SQLITE_NOMEM; } goto json_each_malformed_input; } } if( idxNum==3 ){ zRoot = (const char*)sqlite3_value_text(argv[1]); if( zRoot==0 ) return SQLITE_OK; if( zRoot[0]!='$' ){ sqlite3_free(cur->pVtab->zErrMsg); cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); jsonEachCursorReset(p); return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; } p->nRoot = sqlite3Strlen30(zRoot); if( zRoot[1]==0 ){ i = p->i = 0; p->eType = 0; }else{ i = jsonLookupStep(&p->sParse, 0, zRoot+1, 0); if( JSON_LOOKUP_ISERROR(i) ){ if( i==JSON_LOOKUP_NOTFOUND ){ p->i = 0; p->eType = 0; p->iEnd = 0; return SQLITE_OK; } sqlite3_free(cur->pVtab->zErrMsg); cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); jsonEachCursorReset(p); return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; } if( p->sParse.iLabel ){ p->i = p->sParse.iLabel; p->eType = JSONB_OBJECT; }else{ p->i = i; p->eType = JSONB_ARRAY; } } jsonAppendRaw(&p->path, zRoot, p->nRoot); }else{ i = p->i = 0; p->eType = 0; p->nRoot = 1; jsonAppendRaw(&p->path, "$", 1); } p->nParent = 0; n = jsonbPayloadSize(&p->sParse, i, &sz); p->iEnd = i+n+sz; if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY && !p->bRecursive ){ p->i = i + n; p->eType = p->sParse.aBlob[i] & 0x0f; p->aParent = sqlite3DbMallocZero(p->db, sizeof(JsonParent)); if( p->aParent==0 ) return SQLITE_NOMEM; p->nParent = 1; p->nParentAlloc = 1; p->aParent[0].iKey = 0; p->aParent[0].iEnd = p->iEnd; p->aParent[0].iHead = p->i; p->aParent[0].iValue = i; } return SQLITE_OK; json_each_malformed_input: sqlite3_free(cur->pVtab->zErrMsg); cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); jsonEachCursorReset(p); return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; } /* The methods of the json_each virtual table */ static sqlite3_module jsonEachModule = { 0, /* iVersion */ 0, /* xCreate */ jsonEachConnect, /* xConnect */ jsonEachBestIndex, /* xBestIndex */ jsonEachDisconnect, /* xDisconnect */ 0, /* xDestroy */ jsonEachOpenEach, /* xOpen - open a cursor */ jsonEachClose, /* xClose - close a cursor */ jsonEachFilter, /* xFilter - configure scan constraints */ jsonEachNext, /* xNext - advance a cursor */ jsonEachEof, /* xEof - check for end of scan */ jsonEachColumn, /* xColumn - read data */ jsonEachRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ 0 /* xIntegrity */ }; /* The methods of the json_tree virtual table. */ static sqlite3_module jsonTreeModule = { 0, /* iVersion */ 0, /* xCreate */ jsonEachConnect, /* xConnect */ jsonEachBestIndex, /* xBestIndex */ jsonEachDisconnect, /* xDisconnect */ 0, /* xDestroy */ jsonEachOpenTree, /* xOpen - open a cursor */ jsonEachClose, /* xClose - close a cursor */ jsonEachFilter, /* xFilter - configure scan constraints */ jsonEachNext, /* xNext - advance a cursor */ jsonEachEof, /* xEof - check for end of scan */ jsonEachColumn, /* xColumn - read data */ jsonEachRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ 0 /* xIntegrity */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* !defined(SQLITE_OMIT_JSON) */ /* ** Register JSON functions. */ SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){ #ifndef SQLITE_OMIT_JSON static FuncDef aJsonFunc[] = { /* sqlite3_result_subtype() ----, ,--- sqlite3_value_subtype() */ /* | | */ /* Uses cache ------, | | ,---- Returns JSONB */ /* | | | | */ /* Number of arguments ---, | | | | ,--- Flags */ /* | | | | | | */ JFUNCTION(json, 1,1,1, 0,0,0, jsonRemoveFunc), JFUNCTION(jsonb, 1,1,0, 0,1,0, jsonRemoveFunc), JFUNCTION(json_array, -1,0,1, 1,0,0, jsonArrayFunc), JFUNCTION(jsonb_array, -1,0,1, 1,1,0, jsonArrayFunc), JFUNCTION(json_array_length, 1,1,0, 0,0,0, jsonArrayLengthFunc), JFUNCTION(json_array_length, 2,1,0, 0,0,0, jsonArrayLengthFunc), JFUNCTION(json_error_position,1,1,0, 0,0,0, jsonErrorFunc), JFUNCTION(json_extract, -1,1,1, 0,0,0, jsonExtractFunc), JFUNCTION(jsonb_extract, -1,1,0, 0,1,0, jsonExtractFunc), JFUNCTION(->, 2,1,1, 0,0,JSON_JSON, jsonExtractFunc), JFUNCTION(->>, 2,1,0, 0,0,JSON_SQL, jsonExtractFunc), JFUNCTION(json_insert, -1,1,1, 1,0,0, jsonSetFunc), JFUNCTION(jsonb_insert, -1,1,0, 1,1,0, jsonSetFunc), JFUNCTION(json_object, -1,0,1, 1,0,0, jsonObjectFunc), JFUNCTION(jsonb_object, -1,0,1, 1,1,0, jsonObjectFunc), JFUNCTION(json_patch, 2,1,1, 0,0,0, jsonPatchFunc), JFUNCTION(jsonb_patch, 2,1,0, 0,1,0, jsonPatchFunc), JFUNCTION(json_quote, 1,0,1, 1,0,0, jsonQuoteFunc), JFUNCTION(json_remove, -1,1,1, 0,0,0, jsonRemoveFunc), JFUNCTION(jsonb_remove, -1,1,0, 0,1,0, jsonRemoveFunc), JFUNCTION(json_replace, -1,1,1, 1,0,0, jsonReplaceFunc), JFUNCTION(jsonb_replace, -1,1,0, 1,1,0, jsonReplaceFunc), JFUNCTION(json_set, -1,1,1, 1,0,JSON_ISSET, jsonSetFunc), JFUNCTION(jsonb_set, -1,1,0, 1,1,JSON_ISSET, jsonSetFunc), JFUNCTION(json_type, 1,1,0, 0,0,0, jsonTypeFunc), JFUNCTION(json_type, 2,1,0, 0,0,0, jsonTypeFunc), JFUNCTION(json_valid, 1,1,0, 0,0,0, jsonValidFunc), JFUNCTION(json_valid, 2,1,0, 0,0,0, jsonValidFunc), #if SQLITE_DEBUG JFUNCTION(json_parse, 1,1,0, 0,0,0, jsonParseFunc), #endif WAGGREGATE(json_group_array, 1, 0, 0, jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| SQLITE_DETERMINISTIC), WAGGREGATE(jsonb_group_array, 1, JSON_BLOB, 0, jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC), WAGGREGATE(json_group_object, 2, 0, 0, jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC), WAGGREGATE(jsonb_group_object,2, JSON_BLOB, 0, jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| SQLITE_DETERMINISTIC) }; sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc)); #endif } #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) /* ** Register the JSON table-valued functions */ SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3 *db){ int rc = SQLITE_OK; static const struct { const char *zName; sqlite3_module *pModule; } aMod[] = { { "json_each", &jsonEachModule }, { "json_tree", &jsonTreeModule }, }; unsigned int i; for(i=0; i */ /* #include */ /* #include */ /* #include */ /* The following macro is used to suppress compiler warnings. */ #ifndef UNUSED_PARAMETER # define UNUSED_PARAMETER(x) (void)(x) #endif typedef struct Rtree Rtree; typedef struct RtreeCursor RtreeCursor; typedef struct RtreeNode RtreeNode; typedef struct RtreeCell RtreeCell; typedef struct RtreeConstraint RtreeConstraint; typedef struct RtreeMatchArg RtreeMatchArg; typedef struct RtreeGeomCallback RtreeGeomCallback; typedef union RtreeCoord RtreeCoord; typedef struct RtreeSearchPoint RtreeSearchPoint; /* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */ #define RTREE_MAX_DIMENSIONS 5 /* Maximum number of auxiliary columns */ #define RTREE_MAX_AUX_COLUMN 100 /* Size of hash table Rtree.aHash. This hash table is not expected to ** ever contain very many entries, so a fixed number of buckets is ** used. */ #define HASHSIZE 97 /* The xBestIndex method of this virtual table requires an estimate of ** the number of rows in the virtual table to calculate the costs of ** various strategies. If possible, this estimate is loaded from the ** sqlite_stat1 table (with RTREE_MIN_ROWEST as a hard-coded minimum). ** Otherwise, if no sqlite_stat1 entry is available, use ** RTREE_DEFAULT_ROWEST. */ #define RTREE_DEFAULT_ROWEST 1048576 #define RTREE_MIN_ROWEST 100 /* ** An rtree virtual-table object. */ struct Rtree { sqlite3_vtab base; /* Base class. Must be first */ sqlite3 *db; /* Host database connection */ int iNodeSize; /* Size in bytes of each node in the node table */ u8 nDim; /* Number of dimensions */ u8 nDim2; /* Twice the number of dimensions */ u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ u8 nBytesPerCell; /* Bytes consumed per cell */ u8 inWrTrans; /* True if inside write transaction */ u8 nAux; /* # of auxiliary columns in %_rowid */ #ifdef SQLITE_ENABLE_GEOPOLY u8 nAuxNotNull; /* Number of initial not-null aux columns */ #endif #ifdef SQLITE_DEBUG u8 bCorrupt; /* Shadow table corruption detected */ #endif int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ char *zNodeName; /* Name of the %_node table */ u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ u32 nCursor; /* Number of open cursors */ u32 nNodeRef; /* Number RtreeNodes with positive nRef */ char *zReadAuxSql; /* SQL for statement to read aux data */ /* List of nodes removed during a CondenseTree operation. List is ** linked together via the pointer normally used for hash chains - ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree ** headed by the node (leaf nodes have RtreeNode.iNode==0). */ RtreeNode *pDeleted; /* Blob I/O on xxx_node */ sqlite3_blob *pNodeBlob; /* Statements to read/write/delete a record from xxx_node */ sqlite3_stmt *pWriteNode; sqlite3_stmt *pDeleteNode; /* Statements to read/write/delete a record from xxx_rowid */ sqlite3_stmt *pReadRowid; sqlite3_stmt *pWriteRowid; sqlite3_stmt *pDeleteRowid; /* Statements to read/write/delete a record from xxx_parent */ sqlite3_stmt *pReadParent; sqlite3_stmt *pWriteParent; sqlite3_stmt *pDeleteParent; /* Statement for writing to the "aux:" fields, if there are any */ sqlite3_stmt *pWriteAux; RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ }; /* Possible values for Rtree.eCoordType: */ #define RTREE_COORD_REAL32 0 #define RTREE_COORD_INT32 1 /* ** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will ** only deal with integer coordinates. No floating point operations ** will be done. */ #ifdef SQLITE_RTREE_INT_ONLY typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */ typedef int RtreeValue; /* Low accuracy coordinate */ # define RTREE_ZERO 0 #else typedef double RtreeDValue; /* High accuracy coordinate */ typedef float RtreeValue; /* Low accuracy coordinate */ # define RTREE_ZERO 0.0 #endif /* ** Set the Rtree.bCorrupt flag */ #ifdef SQLITE_DEBUG # define RTREE_IS_CORRUPT(X) ((X)->bCorrupt = 1) #else # define RTREE_IS_CORRUPT(X) #endif /* ** When doing a search of an r-tree, instances of the following structure ** record intermediate results from the tree walk. ** ** The id is always a node-id. For iLevel>=1 the id is the node-id of ** the node that the RtreeSearchPoint represents. When iLevel==0, however, ** the id is of the parent node and the cell that RtreeSearchPoint ** represents is the iCell-th entry in the parent node. */ struct RtreeSearchPoint { RtreeDValue rScore; /* The score for this node. Smallest goes first. */ sqlite3_int64 id; /* Node ID */ u8 iLevel; /* 0=entries. 1=leaf node. 2+ for higher */ u8 eWithin; /* PARTLY_WITHIN or FULLY_WITHIN */ u8 iCell; /* Cell index within the node */ }; /* ** The minimum number of cells allowed for a node is a third of the ** maximum. In Gutman's notation: ** ** m = M/3 ** ** If an R*-tree "Reinsert" operation is required, the same number of ** cells are removed from the overfull node and reinserted into the tree. */ #define RTREE_MINCELLS(p) ((((p)->iNodeSize-4)/(p)->nBytesPerCell)/3) #define RTREE_REINSERT(p) RTREE_MINCELLS(p) #define RTREE_MAXCELLS 51 /* ** The smallest possible node-size is (512-64)==448 bytes. And the largest ** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates). ** Therefore all non-root nodes must contain at least 3 entries. Since ** 3^40 is greater than 2^64, an r-tree structure always has a depth of ** 40 or less. */ #define RTREE_MAX_DEPTH 40 /* ** Number of entries in the cursor RtreeNode cache. The first entry is ** used to cache the RtreeNode for RtreeCursor.sPoint. The remaining ** entries cache the RtreeNode for the first elements of the priority queue. */ #define RTREE_CACHE_SZ 5 /* ** An rtree cursor object. */ struct RtreeCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ u8 atEOF; /* True if at end of search */ u8 bPoint; /* True if sPoint is valid */ u8 bAuxValid; /* True if pReadAux is valid */ int iStrategy; /* Copy of idxNum search parameter */ int nConstraint; /* Number of entries in aConstraint */ RtreeConstraint *aConstraint; /* Search constraints. */ int nPointAlloc; /* Number of slots allocated for aPoint[] */ int nPoint; /* Number of slots used in aPoint[] */ int mxLevel; /* iLevel value for root of the tree */ RtreeSearchPoint *aPoint; /* Priority queue for search points */ sqlite3_stmt *pReadAux; /* Statement to read aux-data */ RtreeSearchPoint sPoint; /* Cached next search point */ RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ }; /* Return the Rtree of a RtreeCursor */ #define RTREE_OF_CURSOR(X) ((Rtree*)((X)->base.pVtab)) /* ** A coordinate can be either a floating point number or a integer. All ** coordinates within a single R-Tree are always of the same time. */ union RtreeCoord { RtreeValue f; /* Floating point value */ int i; /* Integer value */ u32 u; /* Unsigned for byte-order conversions */ }; /* ** The argument is an RtreeCoord. Return the value stored within the RtreeCoord ** formatted as a RtreeDValue (double or int64). This macro assumes that local ** variable pRtree points to the Rtree structure associated with the ** RtreeCoord. */ #ifdef SQLITE_RTREE_INT_ONLY # define DCOORD(coord) ((RtreeDValue)coord.i) #else # define DCOORD(coord) ( \ (pRtree->eCoordType==RTREE_COORD_REAL32) ? \ ((double)coord.f) : \ ((double)coord.i) \ ) #endif /* ** A search constraint. */ struct RtreeConstraint { int iCoord; /* Index of constrained coordinate */ int op; /* Constraining operation */ union { RtreeDValue rValue; /* Constraint value. */ int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*); int (*xQueryFunc)(sqlite3_rtree_query_info*); } u; sqlite3_rtree_query_info *pInfo; /* xGeom and xQueryFunc argument */ }; /* Possible values for RtreeConstraint.op */ #define RTREE_EQ 0x41 /* A */ #define RTREE_LE 0x42 /* B */ #define RTREE_LT 0x43 /* C */ #define RTREE_GE 0x44 /* D */ #define RTREE_GT 0x45 /* E */ #define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */ #define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */ /* Special operators available only on cursors. Needs to be consecutive ** with the normal values above, but must be less than RTREE_MATCH. These ** are used in the cursor for contraints such as x=NULL (RTREE_FALSE) or ** x<'xyz' (RTREE_TRUE) */ #define RTREE_TRUE 0x3f /* ? */ #define RTREE_FALSE 0x40 /* @ */ /* ** An rtree structure node. */ struct RtreeNode { RtreeNode *pParent; /* Parent node */ i64 iNode; /* The node number */ int nRef; /* Number of references to this node */ int isDirty; /* True if the node needs to be written to disk */ u8 *zData; /* Content of the node, as should be on disk */ RtreeNode *pNext; /* Next node in this hash collision chain */ }; /* Return the number of cells in a node */ #define NCELL(pNode) readInt16(&(pNode)->zData[2]) /* ** A single cell from a node, deserialized */ struct RtreeCell { i64 iRowid; /* Node or entry ID */ RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2]; /* Bounding box coordinates */ }; /* ** This object becomes the sqlite3_user_data() for the SQL functions ** that are created by sqlite3_rtree_geometry_callback() and ** sqlite3_rtree_query_callback() and which appear on the right of MATCH ** operators in order to constrain a search. ** ** xGeom and xQueryFunc are the callback functions. Exactly one of ** xGeom and xQueryFunc fields is non-NULL, depending on whether the ** SQL function was created using sqlite3_rtree_geometry_callback() or ** sqlite3_rtree_query_callback(). ** ** This object is deleted automatically by the destructor mechanism in ** sqlite3_create_function_v2(). */ struct RtreeGeomCallback { int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); int (*xQueryFunc)(sqlite3_rtree_query_info*); void (*xDestructor)(void*); void *pContext; }; /* ** An instance of this structure (in the form of a BLOB) is returned by ** the SQL functions that sqlite3_rtree_geometry_callback() and ** sqlite3_rtree_query_callback() create, and is read as the right-hand ** operand to the MATCH operator of an R-Tree. */ struct RtreeMatchArg { u32 iSize; /* Size of this object */ RtreeGeomCallback cb; /* Info about the callback functions */ int nParam; /* Number of parameters to the SQL function */ sqlite3_value **apSqlParam; /* Original SQL parameter values */ RtreeDValue aParam[1]; /* Values for parameters to the SQL function */ }; #ifndef MAX # define MAX(x,y) ((x) < (y) ? (y) : (x)) #endif #ifndef MIN # define MIN(x,y) ((x) > (y) ? (y) : (x)) #endif /* What version of GCC is being used. 0 means GCC is not being used . ** Note that the GCC_VERSION macro will also be set correctly when using ** clang, since clang works hard to be gcc compatible. So the gcc ** optimizations will also work when compiling with clang. */ #ifndef GCC_VERSION #if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) #else # define GCC_VERSION 0 #endif #endif /* The testcase() macro should already be defined in the amalgamation. If ** it is not, make it a no-op. */ #ifndef SQLITE_AMALGAMATION # if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) unsigned int sqlite3RtreeTestcase = 0; # define testcase(X) if( X ){ sqlite3RtreeTestcase += __LINE__; } # else # define testcase(X) # endif #endif /* ** Make sure that the compiler intrinsics we desire are enabled when ** compiling with an appropriate version of MSVC unless prevented by ** the SQLITE_DISABLE_INTRINSIC define. */ #if !defined(SQLITE_DISABLE_INTRINSIC) # if defined(_MSC_VER) && _MSC_VER>=1400 # if !defined(_WIN32_WCE) /* # include */ # pragma intrinsic(_byteswap_ulong) # pragma intrinsic(_byteswap_uint64) # else /* # include */ # endif # endif #endif /* ** Macros to determine whether the machine is big or little endian, ** and whether or not that determination is run-time or compile-time. ** ** For best performance, an attempt is made to guess at the byte-order ** using C-preprocessor macros. If that is unsuccessful, or if ** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined ** at run-time. */ #ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */ # if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ # define SQLITE_BYTEORDER 4321 # elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ # define SQLITE_BYTEORDER 1234 # elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1 # define SQLITE_BYTEORDER 4321 # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64) # define SQLITE_BYTEORDER 1234 # elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__) # define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 # endif #endif /* What version of MSVC is being used. 0 means MSVC is not being used */ #ifndef MSVC_VERSION #if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) # define MSVC_VERSION _MSC_VER #else # define MSVC_VERSION 0 #endif #endif /* ** Functions to deserialize a 16 bit integer, 32 bit real number and ** 64 bit integer. The deserialized value is returned. */ static int readInt16(u8 *p){ return (p[0]<<8) + p[1]; } static void readCoord(u8 *p, RtreeCoord *pCoord){ assert( FOUR_BYTE_ALIGNED(p) ); #if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 pCoord->u = _byteswap_ulong(*(u32*)p); #elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 pCoord->u = __builtin_bswap32(*(u32*)p); #elif SQLITE_BYTEORDER==4321 pCoord->u = *(u32*)p; #else pCoord->u = ( (((u32)p[0]) << 24) + (((u32)p[1]) << 16) + (((u32)p[2]) << 8) + (((u32)p[3]) << 0) ); #endif } static i64 readInt64(u8 *p){ #if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 u64 x; memcpy(&x, p, 8); return (i64)_byteswap_uint64(x); #elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 u64 x; memcpy(&x, p, 8); return (i64)__builtin_bswap64(x); #elif SQLITE_BYTEORDER==4321 i64 x; memcpy(&x, p, 8); return x; #else return (i64)( (((u64)p[0]) << 56) + (((u64)p[1]) << 48) + (((u64)p[2]) << 40) + (((u64)p[3]) << 32) + (((u64)p[4]) << 24) + (((u64)p[5]) << 16) + (((u64)p[6]) << 8) + (((u64)p[7]) << 0) ); #endif } /* ** Functions to serialize a 16 bit integer, 32 bit real number and ** 64 bit integer. The value returned is the number of bytes written ** to the argument buffer (always 2, 4 and 8 respectively). */ static void writeInt16(u8 *p, int i){ p[0] = (i>> 8)&0xFF; p[1] = (i>> 0)&0xFF; } static int writeCoord(u8 *p, RtreeCoord *pCoord){ u32 i; assert( FOUR_BYTE_ALIGNED(p) ); assert( sizeof(RtreeCoord)==4 ); assert( sizeof(u32)==4 ); #if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 i = __builtin_bswap32(pCoord->u); memcpy(p, &i, 4); #elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 i = _byteswap_ulong(pCoord->u); memcpy(p, &i, 4); #elif SQLITE_BYTEORDER==4321 i = pCoord->u; memcpy(p, &i, 4); #else i = pCoord->u; p[0] = (i>>24)&0xFF; p[1] = (i>>16)&0xFF; p[2] = (i>> 8)&0xFF; p[3] = (i>> 0)&0xFF; #endif return 4; } static int writeInt64(u8 *p, i64 i){ #if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 i = (i64)__builtin_bswap64((u64)i); memcpy(p, &i, 8); #elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 i = (i64)_byteswap_uint64((u64)i); memcpy(p, &i, 8); #elif SQLITE_BYTEORDER==4321 memcpy(p, &i, 8); #else p[0] = (i>>56)&0xFF; p[1] = (i>>48)&0xFF; p[2] = (i>>40)&0xFF; p[3] = (i>>32)&0xFF; p[4] = (i>>24)&0xFF; p[5] = (i>>16)&0xFF; p[6] = (i>> 8)&0xFF; p[7] = (i>> 0)&0xFF; #endif return 8; } /* ** Increment the reference count of node p. */ static void nodeReference(RtreeNode *p){ if( p ){ assert( p->nRef>0 ); p->nRef++; } } /* ** Clear the content of node p (set all bytes to 0x00). */ static void nodeZero(Rtree *pRtree, RtreeNode *p){ memset(&p->zData[2], 0, pRtree->iNodeSize-2); p->isDirty = 1; } /* ** Given a node number iNode, return the corresponding key to use ** in the Rtree.aHash table. */ static unsigned int nodeHash(i64 iNode){ return ((unsigned)iNode) % HASHSIZE; } /* ** Search the node hash table for node iNode. If found, return a pointer ** to it. Otherwise, return 0. */ static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){ RtreeNode *p; for(p=pRtree->aHash[nodeHash(iNode)]; p && p->iNode!=iNode; p=p->pNext); return p; } /* ** Add node pNode to the node hash table. */ static void nodeHashInsert(Rtree *pRtree, RtreeNode *pNode){ int iHash; assert( pNode->pNext==0 ); iHash = nodeHash(pNode->iNode); pNode->pNext = pRtree->aHash[iHash]; pRtree->aHash[iHash] = pNode; } /* ** Remove node pNode from the node hash table. */ static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){ RtreeNode **pp; if( pNode->iNode!=0 ){ pp = &pRtree->aHash[nodeHash(pNode->iNode)]; for( ; (*pp)!=pNode; pp = &(*pp)->pNext){ assert(*pp); } *pp = pNode->pNext; pNode->pNext = 0; } } /* ** Allocate and return new r-tree node. Initially, (RtreeNode.iNode==0), ** indicating that node has not yet been assigned a node number. It is ** assigned a node number when nodeWrite() is called to write the ** node contents out to the database. */ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ RtreeNode *pNode; pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode) + pRtree->iNodeSize); if( pNode ){ memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize); pNode->zData = (u8 *)&pNode[1]; pNode->nRef = 1; pRtree->nNodeRef++; pNode->pParent = pParent; pNode->isDirty = 1; nodeReference(pParent); } return pNode; } /* ** Clear the Rtree.pNodeBlob object */ static void nodeBlobReset(Rtree *pRtree){ if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){ sqlite3_blob *pBlob = pRtree->pNodeBlob; pRtree->pNodeBlob = 0; sqlite3_blob_close(pBlob); } } /* ** Obtain a reference to an r-tree node. */ static int nodeAcquire( Rtree *pRtree, /* R-tree structure */ i64 iNode, /* Node number to load */ RtreeNode *pParent, /* Either the parent node or NULL */ RtreeNode **ppNode /* OUT: Acquired node */ ){ int rc = SQLITE_OK; RtreeNode *pNode = 0; /* Check if the requested node is already in the hash table. If so, ** increase its reference count and return it. */ if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ if( pParent && ALWAYS(pParent!=pNode->pParent) ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } pNode->nRef++; *ppNode = pNode; return SQLITE_OK; } if( pRtree->pNodeBlob ){ sqlite3_blob *pBlob = pRtree->pNodeBlob; pRtree->pNodeBlob = 0; rc = sqlite3_blob_reopen(pBlob, iNode); pRtree->pNodeBlob = pBlob; if( rc ){ nodeBlobReset(pRtree); if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM; } } if( pRtree->pNodeBlob==0 ){ rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, pRtree->zNodeName, "data", iNode, 0, &pRtree->pNodeBlob); } if( rc ){ nodeBlobReset(pRtree); *ppNode = 0; /* If unable to open an sqlite3_blob on the desired row, that can only ** be because the shadow tables hold erroneous data. */ if( rc==SQLITE_ERROR ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){ pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize); if( !pNode ){ rc = SQLITE_NOMEM; }else{ pNode->pParent = pParent; pNode->zData = (u8 *)&pNode[1]; pNode->nRef = 1; pRtree->nNodeRef++; pNode->iNode = iNode; pNode->isDirty = 0; pNode->pNext = 0; rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData, pRtree->iNodeSize, 0); } } /* If the root node was just loaded, set pRtree->iDepth to the height ** of the r-tree structure. A height of zero means all data is stored on ** the root node. A height of one means the children of the root node ** are the leaves, and so on. If the depth as specified on the root node ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. */ if( rc==SQLITE_OK && pNode && iNode==1 ){ pRtree->iDepth = readInt16(pNode->zData); if( pRtree->iDepth>RTREE_MAX_DEPTH ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } } /* If no error has occurred so far, check if the "number of entries" ** field on the node is too large. If so, set the return code to ** SQLITE_CORRUPT_VTAB. */ if( pNode && rc==SQLITE_OK ){ if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } } if( rc==SQLITE_OK ){ if( pNode!=0 ){ nodeReference(pParent); nodeHashInsert(pRtree, pNode); }else{ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } *ppNode = pNode; }else{ if( pNode ){ pRtree->nNodeRef--; sqlite3_free(pNode); } *ppNode = 0; } return rc; } /* ** Overwrite cell iCell of node pNode with the contents of pCell. */ static void nodeOverwriteCell( Rtree *pRtree, /* The overall R-Tree */ RtreeNode *pNode, /* The node into which the cell is to be written */ RtreeCell *pCell, /* The cell to write */ int iCell /* Index into pNode into which pCell is written */ ){ int ii; u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; p += writeInt64(p, pCell->iRowid); for(ii=0; iinDim2; ii++){ p += writeCoord(p, &pCell->aCoord[ii]); } pNode->isDirty = 1; } /* ** Remove the cell with index iCell from node pNode. */ static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){ u8 *pDst = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; u8 *pSrc = &pDst[pRtree->nBytesPerCell]; int nByte = (NCELL(pNode) - iCell - 1) * pRtree->nBytesPerCell; memmove(pDst, pSrc, nByte); writeInt16(&pNode->zData[2], NCELL(pNode)-1); pNode->isDirty = 1; } /* ** Insert the contents of cell pCell into node pNode. If the insert ** is successful, return SQLITE_OK. ** ** If there is not enough free space in pNode, return SQLITE_FULL. */ static int nodeInsertCell( Rtree *pRtree, /* The overall R-Tree */ RtreeNode *pNode, /* Write new cell into this node */ RtreeCell *pCell /* The cell to be inserted */ ){ int nCell; /* Current number of cells in pNode */ int nMaxCell; /* Maximum number of cells for pNode */ nMaxCell = (pRtree->iNodeSize-4)/pRtree->nBytesPerCell; nCell = NCELL(pNode); assert( nCell<=nMaxCell ); if( nCellzData[2], nCell+1); pNode->isDirty = 1; } return (nCell==nMaxCell); } /* ** If the node is dirty, write it out to the database. */ static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode->isDirty ){ sqlite3_stmt *p = pRtree->pWriteNode; if( pNode->iNode ){ sqlite3_bind_int64(p, 1, pNode->iNode); }else{ sqlite3_bind_null(p, 1); } sqlite3_bind_blob(p, 2, pNode->zData, pRtree->iNodeSize, SQLITE_STATIC); sqlite3_step(p); pNode->isDirty = 0; rc = sqlite3_reset(p); sqlite3_bind_null(p, 2); if( pNode->iNode==0 && rc==SQLITE_OK ){ pNode->iNode = sqlite3_last_insert_rowid(pRtree->db); nodeHashInsert(pRtree, pNode); } } return rc; } /* ** Release a reference to a node. If the node is dirty and the reference ** count drops to zero, the node data is written to the database. */ static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode ){ assert( pNode->nRef>0 ); assert( pRtree->nNodeRef>0 ); pNode->nRef--; if( pNode->nRef==0 ){ pRtree->nNodeRef--; if( pNode->iNode==1 ){ pRtree->iDepth = -1; } if( pNode->pParent ){ rc = nodeRelease(pRtree, pNode->pParent); } if( rc==SQLITE_OK ){ rc = nodeWrite(pRtree, pNode); } nodeHashDelete(pRtree, pNode); sqlite3_free(pNode); } } return rc; } /* ** Return the 64-bit integer value associated with cell iCell of ** node pNode. If pNode is a leaf node, this is a rowid. If it is ** an internal node, then the 64-bit integer is a child page number. */ static i64 nodeGetRowid( Rtree *pRtree, /* The overall R-Tree */ RtreeNode *pNode, /* The node from which to extract the ID */ int iCell /* The cell index from which to extract the ID */ ){ assert( iCellzData[4 + pRtree->nBytesPerCell*iCell]); } /* ** Return coordinate iCoord from cell iCell in node pNode. */ static void nodeGetCoord( Rtree *pRtree, /* The overall R-Tree */ RtreeNode *pNode, /* The node from which to extract a coordinate */ int iCell, /* The index of the cell within the node */ int iCoord, /* Which coordinate to extract */ RtreeCoord *pCoord /* OUT: Space to write result to */ ){ readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord); } /* ** Deserialize cell iCell of node pNode. Populate the structure pointed ** to by pCell with the results. */ static void nodeGetCell( Rtree *pRtree, /* The overall R-Tree */ RtreeNode *pNode, /* The node containing the cell to be read */ int iCell, /* Index of the cell within the node */ RtreeCell *pCell /* OUT: Write the cell contents here */ ){ u8 *pData; RtreeCoord *pCoord; int ii = 0; pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell); pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell); pCoord = pCell->aCoord; do{ readCoord(pData, &pCoord[ii]); readCoord(pData+4, &pCoord[ii+1]); pData += 8; ii += 2; }while( iinDim2 ); } /* Forward declaration for the function that does the work of ** the virtual table module xCreate() and xConnect() methods. */ static int rtreeInit( sqlite3 *, void *, int, const char *const*, sqlite3_vtab **, char **, int ); /* ** Rtree virtual table module xCreate method. */ static int rtreeCreate( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 1); } /* ** Rtree virtual table module xConnect method. */ static int rtreeConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 0); } /* ** Increment the r-tree reference count. */ static void rtreeReference(Rtree *pRtree){ pRtree->nBusy++; } /* ** Decrement the r-tree reference count. When the reference count reaches ** zero the structure is deleted. */ static void rtreeRelease(Rtree *pRtree){ pRtree->nBusy--; if( pRtree->nBusy==0 ){ pRtree->inWrTrans = 0; assert( pRtree->nCursor==0 ); nodeBlobReset(pRtree); assert( pRtree->nNodeRef==0 || pRtree->bCorrupt ); sqlite3_finalize(pRtree->pWriteNode); sqlite3_finalize(pRtree->pDeleteNode); sqlite3_finalize(pRtree->pReadRowid); sqlite3_finalize(pRtree->pWriteRowid); sqlite3_finalize(pRtree->pDeleteRowid); sqlite3_finalize(pRtree->pReadParent); sqlite3_finalize(pRtree->pWriteParent); sqlite3_finalize(pRtree->pDeleteParent); sqlite3_finalize(pRtree->pWriteAux); sqlite3_free(pRtree->zReadAuxSql); sqlite3_free(pRtree); } } /* ** Rtree virtual table module xDisconnect method. */ static int rtreeDisconnect(sqlite3_vtab *pVtab){ rtreeRelease((Rtree *)pVtab); return SQLITE_OK; } /* ** Rtree virtual table module xDestroy method. */ static int rtreeDestroy(sqlite3_vtab *pVtab){ Rtree *pRtree = (Rtree *)pVtab; int rc; char *zCreate = sqlite3_mprintf( "DROP TABLE '%q'.'%q_node';" "DROP TABLE '%q'.'%q_rowid';" "DROP TABLE '%q'.'%q_parent';", pRtree->zDb, pRtree->zName, pRtree->zDb, pRtree->zName, pRtree->zDb, pRtree->zName ); if( !zCreate ){ rc = SQLITE_NOMEM; }else{ nodeBlobReset(pRtree); rc = sqlite3_exec(pRtree->db, zCreate, 0, 0, 0); sqlite3_free(zCreate); } if( rc==SQLITE_OK ){ rtreeRelease(pRtree); } return rc; } /* ** Rtree virtual table module xOpen method. */ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ int rc = SQLITE_NOMEM; Rtree *pRtree = (Rtree *)pVTab; RtreeCursor *pCsr; pCsr = (RtreeCursor *)sqlite3_malloc64(sizeof(RtreeCursor)); if( pCsr ){ memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = pVTab; rc = SQLITE_OK; pRtree->nCursor++; } *ppCursor = (sqlite3_vtab_cursor *)pCsr; return rc; } /* ** Reset a cursor back to its initial state. */ static void resetCursor(RtreeCursor *pCsr){ Rtree *pRtree = (Rtree *)(pCsr->base.pVtab); int ii; sqlite3_stmt *pStmt; if( pCsr->aConstraint ){ int i; /* Used to iterate through constraint array */ for(i=0; inConstraint; i++){ sqlite3_rtree_query_info *pInfo = pCsr->aConstraint[i].pInfo; if( pInfo ){ if( pInfo->xDelUser ) pInfo->xDelUser(pInfo->pUser); sqlite3_free(pInfo); } } sqlite3_free(pCsr->aConstraint); pCsr->aConstraint = 0; } for(ii=0; iiaNode[ii]); sqlite3_free(pCsr->aPoint); pStmt = pCsr->pReadAux; memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = (sqlite3_vtab*)pRtree; pCsr->pReadAux = pStmt; } /* ** Rtree virtual table module xClose method. */ static int rtreeClose(sqlite3_vtab_cursor *cur){ Rtree *pRtree = (Rtree *)(cur->pVtab); RtreeCursor *pCsr = (RtreeCursor *)cur; assert( pRtree->nCursor>0 ); resetCursor(pCsr); sqlite3_finalize(pCsr->pReadAux); sqlite3_free(pCsr); pRtree->nCursor--; nodeBlobReset(pRtree); return SQLITE_OK; } /* ** Rtree virtual table module xEof method. ** ** Return non-zero if the cursor does not currently point to a valid ** record (i.e if the scan has finished), or zero otherwise. */ static int rtreeEof(sqlite3_vtab_cursor *cur){ RtreeCursor *pCsr = (RtreeCursor *)cur; return pCsr->atEOF; } /* ** Convert raw bits from the on-disk RTree record into a coordinate value. ** The on-disk format is big-endian and needs to be converted for little- ** endian platforms. The on-disk record stores integer coordinates if ** eInt is true and it stores 32-bit floating point records if eInt is ** false. a[] is the four bytes of the on-disk record to be decoded. ** Store the results in "r". ** ** There are five versions of this macro. The last one is generic. The ** other four are various architectures-specific optimizations. */ #if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 #define RTREE_DECODE_COORD(eInt, a, r) { \ RtreeCoord c; /* Coordinate decoded */ \ c.u = _byteswap_ulong(*(u32*)a); \ r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ } #elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 #define RTREE_DECODE_COORD(eInt, a, r) { \ RtreeCoord c; /* Coordinate decoded */ \ c.u = __builtin_bswap32(*(u32*)a); \ r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ } #elif SQLITE_BYTEORDER==1234 #define RTREE_DECODE_COORD(eInt, a, r) { \ RtreeCoord c; /* Coordinate decoded */ \ memcpy(&c.u,a,4); \ c.u = ((c.u>>24)&0xff)|((c.u>>8)&0xff00)| \ ((c.u&0xff)<<24)|((c.u&0xff00)<<8); \ r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ } #elif SQLITE_BYTEORDER==4321 #define RTREE_DECODE_COORD(eInt, a, r) { \ RtreeCoord c; /* Coordinate decoded */ \ memcpy(&c.u,a,4); \ r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ } #else #define RTREE_DECODE_COORD(eInt, a, r) { \ RtreeCoord c; /* Coordinate decoded */ \ c.u = ((u32)a[0]<<24) + ((u32)a[1]<<16) \ +((u32)a[2]<<8) + a[3]; \ r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ } #endif /* ** Check the RTree node or entry given by pCellData and p against the MATCH ** constraint pConstraint. */ static int rtreeCallbackConstraint( RtreeConstraint *pConstraint, /* The constraint to test */ int eInt, /* True if RTree holding integer coordinates */ u8 *pCellData, /* Raw cell content */ RtreeSearchPoint *pSearch, /* Container of this cell */ sqlite3_rtree_dbl *prScore, /* OUT: score for the cell */ int *peWithin /* OUT: visibility of the cell */ ){ sqlite3_rtree_query_info *pInfo = pConstraint->pInfo; /* Callback info */ int nCoord = pInfo->nCoord; /* No. of coordinates */ int rc; /* Callback return code */ RtreeCoord c; /* Translator union */ sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2]; /* Decoded coordinates */ assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY ); assert( nCoord==2 || nCoord==4 || nCoord==6 || nCoord==8 || nCoord==10 ); if( pConstraint->op==RTREE_QUERY && pSearch->iLevel==1 ){ pInfo->iRowid = readInt64(pCellData); } pCellData += 8; #ifndef SQLITE_RTREE_INT_ONLY if( eInt==0 ){ switch( nCoord ){ case 10: readCoord(pCellData+36, &c); aCoord[9] = c.f; readCoord(pCellData+32, &c); aCoord[8] = c.f; case 8: readCoord(pCellData+28, &c); aCoord[7] = c.f; readCoord(pCellData+24, &c); aCoord[6] = c.f; case 6: readCoord(pCellData+20, &c); aCoord[5] = c.f; readCoord(pCellData+16, &c); aCoord[4] = c.f; case 4: readCoord(pCellData+12, &c); aCoord[3] = c.f; readCoord(pCellData+8, &c); aCoord[2] = c.f; default: readCoord(pCellData+4, &c); aCoord[1] = c.f; readCoord(pCellData, &c); aCoord[0] = c.f; } }else #endif { switch( nCoord ){ case 10: readCoord(pCellData+36, &c); aCoord[9] = c.i; readCoord(pCellData+32, &c); aCoord[8] = c.i; case 8: readCoord(pCellData+28, &c); aCoord[7] = c.i; readCoord(pCellData+24, &c); aCoord[6] = c.i; case 6: readCoord(pCellData+20, &c); aCoord[5] = c.i; readCoord(pCellData+16, &c); aCoord[4] = c.i; case 4: readCoord(pCellData+12, &c); aCoord[3] = c.i; readCoord(pCellData+8, &c); aCoord[2] = c.i; default: readCoord(pCellData+4, &c); aCoord[1] = c.i; readCoord(pCellData, &c); aCoord[0] = c.i; } } if( pConstraint->op==RTREE_MATCH ){ int eWithin = 0; rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo, nCoord, aCoord, &eWithin); if( eWithin==0 ) *peWithin = NOT_WITHIN; *prScore = RTREE_ZERO; }else{ pInfo->aCoord = aCoord; pInfo->iLevel = pSearch->iLevel - 1; pInfo->rScore = pInfo->rParentScore = pSearch->rScore; pInfo->eWithin = pInfo->eParentWithin = pSearch->eWithin; rc = pConstraint->u.xQueryFunc(pInfo); if( pInfo->eWithin<*peWithin ) *peWithin = pInfo->eWithin; if( pInfo->rScore<*prScore || *prScorerScore; } } return rc; } /* ** Check the internal RTree node given by pCellData against constraint p. ** If this constraint cannot be satisfied by any child within the node, ** set *peWithin to NOT_WITHIN. */ static void rtreeNonleafConstraint( RtreeConstraint *p, /* The constraint to test */ int eInt, /* True if RTree holds integer coordinates */ u8 *pCellData, /* Raw cell content as appears on disk */ int *peWithin /* Adjust downward, as appropriate */ ){ sqlite3_rtree_dbl val; /* Coordinate value convert to a double */ /* p->iCoord might point to either a lower or upper bound coordinate ** in a coordinate pair. But make pCellData point to the lower bound. */ pCellData += 8 + 4*(p->iCoord&0xfe); assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE || p->op==RTREE_FALSE ); assert( FOUR_BYTE_ALIGNED(pCellData) ); switch( p->op ){ case RTREE_TRUE: return; /* Always satisfied */ case RTREE_FALSE: break; /* Never satisfied */ case RTREE_EQ: RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the lower bound of the coordinate pair */ if( p->u.rValue>=val ){ pCellData += 4; RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the upper bound of the coordinate pair */ if( p->u.rValue<=val ) return; } break; case RTREE_LE: case RTREE_LT: RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the lower bound of the coordinate pair */ if( p->u.rValue>=val ) return; break; default: pCellData += 4; RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the upper bound of the coordinate pair */ if( p->u.rValue<=val ) return; break; } *peWithin = NOT_WITHIN; } /* ** Check the leaf RTree cell given by pCellData against constraint p. ** If this constraint is not satisfied, set *peWithin to NOT_WITHIN. ** If the constraint is satisfied, leave *peWithin unchanged. ** ** The constraint is of the form: xN op $val ** ** The op is given by p->op. The xN is p->iCoord-th coordinate in ** pCellData. $val is given by p->u.rValue. */ static void rtreeLeafConstraint( RtreeConstraint *p, /* The constraint to test */ int eInt, /* True if RTree holds integer coordinates */ u8 *pCellData, /* Raw cell content as appears on disk */ int *peWithin /* Adjust downward, as appropriate */ ){ RtreeDValue xN; /* Coordinate value converted to a double */ assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE || p->op==RTREE_FALSE ); pCellData += 8 + p->iCoord*4; assert( FOUR_BYTE_ALIGNED(pCellData) ); RTREE_DECODE_COORD(eInt, pCellData, xN); switch( p->op ){ case RTREE_TRUE: return; /* Always satisfied */ case RTREE_FALSE: break; /* Never satisfied */ case RTREE_LE: if( xN <= p->u.rValue ) return; break; case RTREE_LT: if( xN < p->u.rValue ) return; break; case RTREE_GE: if( xN >= p->u.rValue ) return; break; case RTREE_GT: if( xN > p->u.rValue ) return; break; default: if( xN == p->u.rValue ) return; break; } *peWithin = NOT_WITHIN; } /* ** One of the cells in node pNode is guaranteed to have a 64-bit ** integer value equal to iRowid. Return the index of this cell. */ static int nodeRowidIndex( Rtree *pRtree, RtreeNode *pNode, i64 iRowid, int *piIndex ){ int ii; int nCell = NCELL(pNode); assert( nCell<200 ); for(ii=0; iipParent; if( ALWAYS(pParent) ){ return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex); }else{ *piIndex = -1; return SQLITE_OK; } } /* ** Compare two search points. Return negative, zero, or positive if the first ** is less than, equal to, or greater than the second. ** ** The rScore is the primary key. Smaller rScore values come first. ** If the rScore is a tie, then use iLevel as the tie breaker with smaller ** iLevel values coming first. In this way, if rScore is the same for all ** SearchPoints, then iLevel becomes the deciding factor and the result ** is a depth-first search, which is the desired default behavior. */ static int rtreeSearchPointCompare( const RtreeSearchPoint *pA, const RtreeSearchPoint *pB ){ if( pA->rScorerScore ) return -1; if( pA->rScore>pB->rScore ) return +1; if( pA->iLeveliLevel ) return -1; if( pA->iLevel>pB->iLevel ) return +1; return 0; } /* ** Interchange two search points in a cursor. */ static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){ RtreeSearchPoint t = p->aPoint[i]; assert( iaPoint[i] = p->aPoint[j]; p->aPoint[j] = t; i++; j++; if( i=RTREE_CACHE_SZ ){ nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); p->aNode[i] = 0; }else{ RtreeNode *pTemp = p->aNode[i]; p->aNode[i] = p->aNode[j]; p->aNode[j] = pTemp; } } } /* ** Return the search point with the lowest current score. */ static RtreeSearchPoint *rtreeSearchPointFirst(RtreeCursor *pCur){ return pCur->bPoint ? &pCur->sPoint : pCur->nPoint ? pCur->aPoint : 0; } /* ** Get the RtreeNode for the search point with the lowest score. */ static RtreeNode *rtreeNodeOfFirstSearchPoint(RtreeCursor *pCur, int *pRC){ sqlite3_int64 id; int ii = 1 - pCur->bPoint; assert( ii==0 || ii==1 ); assert( pCur->bPoint || pCur->nPoint ); if( pCur->aNode[ii]==0 ){ assert( pRC!=0 ); id = ii ? pCur->aPoint[0].id : pCur->sPoint.id; *pRC = nodeAcquire(RTREE_OF_CURSOR(pCur), id, 0, &pCur->aNode[ii]); } return pCur->aNode[ii]; } /* ** Push a new element onto the priority queue */ static RtreeSearchPoint *rtreeEnqueue( RtreeCursor *pCur, /* The cursor */ RtreeDValue rScore, /* Score for the new search point */ u8 iLevel /* Level for the new search point */ ){ int i, j; RtreeSearchPoint *pNew; if( pCur->nPoint>=pCur->nPointAlloc ){ int nNew = pCur->nPointAlloc*2 + 8; pNew = sqlite3_realloc64(pCur->aPoint, nNew*sizeof(pCur->aPoint[0])); if( pNew==0 ) return 0; pCur->aPoint = pNew; pCur->nPointAlloc = nNew; } i = pCur->nPoint++; pNew = pCur->aPoint + i; pNew->rScore = rScore; pNew->iLevel = iLevel; assert( iLevel<=RTREE_MAX_DEPTH ); while( i>0 ){ RtreeSearchPoint *pParent; j = (i-1)/2; pParent = pCur->aPoint + j; if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break; rtreeSearchPointSwap(pCur, j, i); i = j; pNew = pParent; } return pNew; } /* ** Allocate a new RtreeSearchPoint and return a pointer to it. Return ** NULL if malloc fails. */ static RtreeSearchPoint *rtreeSearchPointNew( RtreeCursor *pCur, /* The cursor */ RtreeDValue rScore, /* Score for the new search point */ u8 iLevel /* Level for the new search point */ ){ RtreeSearchPoint *pNew, *pFirst; pFirst = rtreeSearchPointFirst(pCur); pCur->anQueue[iLevel]++; if( pFirst==0 || pFirst->rScore>rScore || (pFirst->rScore==rScore && pFirst->iLevel>iLevel) ){ if( pCur->bPoint ){ int ii; pNew = rtreeEnqueue(pCur, rScore, iLevel); if( pNew==0 ) return 0; ii = (int)(pNew - pCur->aPoint) + 1; assert( ii==1 ); if( ALWAYS(iiaNode[ii]==0 ); pCur->aNode[ii] = pCur->aNode[0]; }else{ nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]); } pCur->aNode[0] = 0; *pNew = pCur->sPoint; } pCur->sPoint.rScore = rScore; pCur->sPoint.iLevel = iLevel; pCur->bPoint = 1; return &pCur->sPoint; }else{ return rtreeEnqueue(pCur, rScore, iLevel); } } #if 0 /* Tracing routines for the RtreeSearchPoint queue */ static void tracePoint(RtreeSearchPoint *p, int idx, RtreeCursor *pCur){ if( idx<0 ){ printf(" s"); }else{ printf("%2d", idx); } printf(" %d.%05lld.%02d %g %d", p->iLevel, p->id, p->iCell, p->rScore, p->eWithin ); idx++; if( idxaNode[idx]); }else{ printf("\n"); } } static void traceQueue(RtreeCursor *pCur, const char *zPrefix){ int ii; printf("=== %9s ", zPrefix); if( pCur->bPoint ){ tracePoint(&pCur->sPoint, -1, pCur); } for(ii=0; iinPoint; ii++){ if( ii>0 || pCur->bPoint ) printf(" "); tracePoint(&pCur->aPoint[ii], ii, pCur); } } # define RTREE_QUEUE_TRACE(A,B) traceQueue(A,B) #else # define RTREE_QUEUE_TRACE(A,B) /* no-op */ #endif /* Remove the search point with the lowest current score. */ static void rtreeSearchPointPop(RtreeCursor *p){ int i, j, k, n; i = 1 - p->bPoint; assert( i==0 || i==1 ); if( p->aNode[i] ){ nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); p->aNode[i] = 0; } if( p->bPoint ){ p->anQueue[p->sPoint.iLevel]--; p->bPoint = 0; }else if( ALWAYS(p->nPoint) ){ p->anQueue[p->aPoint[0].iLevel]--; n = --p->nPoint; p->aPoint[0] = p->aPoint[n]; if( naNode[1] = p->aNode[n+1]; p->aNode[n+1] = 0; } i = 0; while( (j = i*2+1)aPoint[k], &p->aPoint[j])<0 ){ if( rtreeSearchPointCompare(&p->aPoint[k], &p->aPoint[i])<0 ){ rtreeSearchPointSwap(p, i, k); i = k; }else{ break; } }else{ if( rtreeSearchPointCompare(&p->aPoint[j], &p->aPoint[i])<0 ){ rtreeSearchPointSwap(p, i, j); i = j; }else{ break; } } } } } /* ** Continue the search on cursor pCur until the front of the queue ** contains an entry suitable for returning as a result-set row, ** or until the RtreeSearchPoint queue is empty, indicating that the ** query has completed. */ static int rtreeStepToLeaf(RtreeCursor *pCur){ RtreeSearchPoint *p; Rtree *pRtree = RTREE_OF_CURSOR(pCur); RtreeNode *pNode; int eWithin; int rc = SQLITE_OK; int nCell; int nConstraint = pCur->nConstraint; int ii; int eInt; RtreeSearchPoint x; eInt = pRtree->eCoordType==RTREE_COORD_INT32; while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ u8 *pCellData; pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc); if( rc ) return rc; nCell = NCELL(pNode); assert( nCell<200 ); pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell); while( p->iCellaConstraint + ii; if( pConstraint->op>=RTREE_MATCH ){ rc = rtreeCallbackConstraint(pConstraint, eInt, pCellData, p, &rScore, &eWithin); if( rc ) return rc; }else if( p->iLevel==1 ){ rtreeLeafConstraint(pConstraint, eInt, pCellData, &eWithin); }else{ rtreeNonleafConstraint(pConstraint, eInt, pCellData, &eWithin); } if( eWithin==NOT_WITHIN ){ p->iCell++; pCellData += pRtree->nBytesPerCell; break; } } if( eWithin==NOT_WITHIN ) continue; p->iCell++; x.iLevel = p->iLevel - 1; if( x.iLevel ){ x.id = readInt64(pCellData); for(ii=0; iinPoint; ii++){ if( pCur->aPoint[ii].id==x.id ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } } x.iCell = 0; }else{ x.id = p->id; x.iCell = p->iCell - 1; } if( p->iCell>=nCell ){ RTREE_QUEUE_TRACE(pCur, "POP-S:"); rtreeSearchPointPop(pCur); } if( rScoreeWithin = (u8)eWithin; p->id = x.id; p->iCell = x.iCell; RTREE_QUEUE_TRACE(pCur, "PUSH-S:"); break; } if( p->iCell>=nCell ){ RTREE_QUEUE_TRACE(pCur, "POP-Se:"); rtreeSearchPointPop(pCur); } } pCur->atEOF = p==0; return SQLITE_OK; } /* ** Rtree virtual table module xNext method. */ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; int rc = SQLITE_OK; /* Move to the next entry that matches the configured constraints. */ RTREE_QUEUE_TRACE(pCsr, "POP-Nx:"); if( pCsr->bAuxValid ){ pCsr->bAuxValid = 0; sqlite3_reset(pCsr->pReadAux); } rtreeSearchPointPop(pCsr); rc = rtreeStepToLeaf(pCsr); return rc; } /* ** Rtree virtual table module xRowid method. */ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc==SQLITE_OK && ALWAYS(p) ){ *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); } return rc; } /* ** Rtree virtual table module xColumn method. */ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ Rtree *pRtree = (Rtree *)cur->pVtab; RtreeCursor *pCsr = (RtreeCursor *)cur; RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); RtreeCoord c; int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc ) return rc; if( NEVER(p==0) ) return SQLITE_OK; if( i==0 ){ sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); }else if( i<=pRtree->nDim2 ){ nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ sqlite3_result_double(ctx, c.f); }else #endif { assert( pRtree->eCoordType==RTREE_COORD_INT32 ); sqlite3_result_int(ctx, c.i); } }else{ if( !pCsr->bAuxValid ){ if( pCsr->pReadAux==0 ){ rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0, &pCsr->pReadAux, 0); if( rc ) return rc; } sqlite3_bind_int64(pCsr->pReadAux, 1, nodeGetRowid(pRtree, pNode, p->iCell)); rc = sqlite3_step(pCsr->pReadAux); if( rc==SQLITE_ROW ){ pCsr->bAuxValid = 1; }else{ sqlite3_reset(pCsr->pReadAux); if( rc==SQLITE_DONE ) rc = SQLITE_OK; return rc; } } sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1)); } return SQLITE_OK; } /* ** Use nodeAcquire() to obtain the leaf node containing the record with ** rowid iRowid. If successful, set *ppLeaf to point to the node and ** return SQLITE_OK. If there is no such record in the table, set ** *ppLeaf to 0 and return SQLITE_OK. If an error occurs, set *ppLeaf ** to zero and return an SQLite error code. */ static int findLeafNode( Rtree *pRtree, /* RTree to search */ i64 iRowid, /* The rowid searching for */ RtreeNode **ppLeaf, /* Write the node here */ sqlite3_int64 *piNode /* Write the node-id here */ ){ int rc; *ppLeaf = 0; sqlite3_bind_int64(pRtree->pReadRowid, 1, iRowid); if( sqlite3_step(pRtree->pReadRowid)==SQLITE_ROW ){ i64 iNode = sqlite3_column_int64(pRtree->pReadRowid, 0); if( piNode ) *piNode = iNode; rc = nodeAcquire(pRtree, iNode, 0, ppLeaf); sqlite3_reset(pRtree->pReadRowid); }else{ rc = sqlite3_reset(pRtree->pReadRowid); } return rc; } /* ** This function is called to configure the RtreeConstraint object passed ** as the second argument for a MATCH constraint. The value passed as the ** first argument to this function is the right-hand operand to the MATCH ** operator. */ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ RtreeMatchArg *pBlob, *pSrc; /* BLOB returned by geometry function */ sqlite3_rtree_query_info *pInfo; /* Callback information */ pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg"); if( pSrc==0 ) return SQLITE_ERROR; pInfo = (sqlite3_rtree_query_info*) sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize ); if( !pInfo ) return SQLITE_NOMEM; memset(pInfo, 0, sizeof(*pInfo)); pBlob = (RtreeMatchArg*)&pInfo[1]; memcpy(pBlob, pSrc, pSrc->iSize); pInfo->pContext = pBlob->cb.pContext; pInfo->nParam = pBlob->nParam; pInfo->aParam = pBlob->aParam; pInfo->apSqlParam = pBlob->apSqlParam; if( pBlob->cb.xGeom ){ pCons->u.xGeom = pBlob->cb.xGeom; }else{ pCons->op = RTREE_QUERY; pCons->u.xQueryFunc = pBlob->cb.xQueryFunc; } pCons->pInfo = pInfo; return SQLITE_OK; } /* ** Rtree virtual table module xFilter method. */ static int rtreeFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; int iCell = 0; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ resetCursor(pCsr); pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ RtreeSearchPoint *p; /* Search point for the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); i64 iNode = 0; int eType = sqlite3_value_numeric_type(argv[0]); if( eType==SQLITE_INTEGER || (eType==SQLITE_FLOAT && sqlite3_value_double(argv[0])==iRowid) ){ rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); }else{ rc = SQLITE_OK; pLeaf = 0; } if( rc==SQLITE_OK && pLeaf!=0 ){ p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); assert( p!=0 ); /* Always returns pCsr->sPoint */ pCsr->aNode[0] = pLeaf; p->id = iNode; p->eWithin = PARTLY_WITHIN; rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); p->iCell = (u8)iCell; RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); }else{ pCsr->atEOF = 1; } }else{ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array ** with the configured constraints. */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); if( rc==SQLITE_OK && argc>0 ){ pCsr->aConstraint = sqlite3_malloc64(sizeof(RtreeConstraint)*argc); pCsr->nConstraint = argc; if( !pCsr->aConstraint ){ rc = SQLITE_NOMEM; }else{ memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); assert( (idxStr==0 && argc==0) || (idxStr && (int)strlen(idxStr)==argc*2) ); for(ii=0; iiaConstraint[ii]; int eType = sqlite3_value_numeric_type(argv[ii]); p->op = idxStr[ii*2]; p->iCoord = idxStr[ii*2+1]-'0'; if( p->op>=RTREE_MATCH ){ /* A MATCH operator. The right-hand-side must be a blob that ** can be cast into an RtreeMatchArg object. One created using ** an sqlite3_rtree_geometry_callback() SQL user function. */ rc = deserializeGeometry(argv[ii], p); if( rc!=SQLITE_OK ){ break; } p->pInfo->nCoord = pRtree->nDim2; p->pInfo->anQueue = pCsr->anQueue; p->pInfo->mxLevel = pRtree->iDepth + 1; }else if( eType==SQLITE_INTEGER ){ sqlite3_int64 iVal = sqlite3_value_int64(argv[ii]); #ifdef SQLITE_RTREE_INT_ONLY p->u.rValue = iVal; #else p->u.rValue = (double)iVal; if( iVal>=((sqlite3_int64)1)<<48 || iVal<=-(((sqlite3_int64)1)<<48) ){ if( p->op==RTREE_LT ) p->op = RTREE_LE; if( p->op==RTREE_GT ) p->op = RTREE_GE; } #endif }else if( eType==SQLITE_FLOAT ){ #ifdef SQLITE_RTREE_INT_ONLY p->u.rValue = sqlite3_value_int64(argv[ii]); #else p->u.rValue = sqlite3_value_double(argv[ii]); #endif }else{ p->u.rValue = RTREE_ZERO; if( eType==SQLITE_NULL ){ p->op = RTREE_FALSE; }else if( p->op==RTREE_LT || p->op==RTREE_LE ){ p->op = RTREE_TRUE; }else{ p->op = RTREE_FALSE; } } } } } if( rc==SQLITE_OK ){ RtreeSearchPoint *pNew; assert( pCsr->bPoint==0 ); /* Due to the resetCursor() call above */ pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); if( NEVER(pNew==0) ){ /* Because pCsr->bPoint was FALSE */ return SQLITE_NOMEM; } pNew->id = 1; pNew->iCell = 0; pNew->eWithin = PARTLY_WITHIN; assert( pCsr->bPoint==1 ); pCsr->aNode[0] = pRoot; pRoot = 0; RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); rc = rtreeStepToLeaf(pCsr); } } nodeRelease(pRtree, pRoot); rtreeRelease(pRtree); return rc; } /* ** Rtree virtual table module xBestIndex method. There are three ** table scan strategies to choose from (in order from most to ** least desirable): ** ** idxNum idxStr Strategy ** ------------------------------------------------ ** 1 Unused Direct lookup by rowid. ** 2 See below R-tree query or full-table scan. ** ------------------------------------------------ ** ** If strategy 1 is used, then idxStr is not meaningful. If strategy ** 2 is used, idxStr is formatted to contain 2 bytes for each ** constraint used. The first two bytes of idxStr correspond to ** the constraint in sqlite3_index_info.aConstraintUsage[] with ** (argvIndex==1) etc. ** ** The first of each pair of bytes in idxStr identifies the constraint ** operator as follows: ** ** Operator Byte Value ** ---------------------- ** = 0x41 ('A') ** <= 0x42 ('B') ** < 0x43 ('C') ** >= 0x44 ('D') ** > 0x45 ('E') ** MATCH 0x46 ('F') ** ---------------------- ** ** The second of each pair of bytes identifies the coordinate column ** to which the constraint applies. The leftmost coordinate column ** is 'a', the second from the left 'b' etc. */ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ Rtree *pRtree = (Rtree*)tab; int rc = SQLITE_OK; int ii; int bMatch = 0; /* True if there exists a MATCH constraint */ i64 nRow; /* Estimated rows returned by this scan */ int iIdx = 0; char zIdxStr[RTREE_MAX_DIMENSIONS*8+1]; memset(zIdxStr, 0, sizeof(zIdxStr)); /* Check if there exists a MATCH constraint - even an unusable one. If there ** is, do not consider the lookup-by-rowid plan as using such a plan would ** require the VDBE to evaluate the MATCH constraint, which is not currently ** possible. */ for(ii=0; iinConstraint; ii++){ if( pIdxInfo->aConstraint[ii].op==SQLITE_INDEX_CONSTRAINT_MATCH ){ bMatch = 1; } } assert( pIdxInfo->idxStr==0 ); for(ii=0; iinConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; if( bMatch==0 && p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ /* We have an equality constraint on the rowid. Use strategy 1. */ int jj; for(jj=0; jjaConstraintUsage[jj].argvIndex = 0; pIdxInfo->aConstraintUsage[jj].omit = 0; } pIdxInfo->idxNum = 1; pIdxInfo->aConstraintUsage[ii].argvIndex = 1; pIdxInfo->aConstraintUsage[jj].omit = 1; /* This strategy involves a two rowid lookups on an B-Tree structures ** and then a linear search of an R-Tree node. This should be ** considered almost as quick as a direct rowid lookup (for which ** sqlite uses an internal cost of 0.0). It is expected to return ** a single row. */ pIdxInfo->estimatedCost = 30.0; pIdxInfo->estimatedRows = 1; pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; return SQLITE_OK; } if( p->usable && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2) || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){ u8 op; u8 doOmit = 1; switch( p->op ){ case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; doOmit = 0; break; case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; doOmit = 0; break; case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break; case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; doOmit = 0; break; case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break; case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break; default: op = 0; break; } if( op ){ zIdxStr[iIdx++] = op; zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0'); pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); pIdxInfo->aConstraintUsage[ii].omit = doOmit; } } } pIdxInfo->idxNum = 2; pIdxInfo->needToFreeIdxStr = 1; if( iIdx>0 ){ pIdxInfo->idxStr = sqlite3_malloc( iIdx+1 ); if( pIdxInfo->idxStr==0 ){ return SQLITE_NOMEM; } memcpy(pIdxInfo->idxStr, zIdxStr, iIdx+1); } nRow = pRtree->nRowEst >> (iIdx/2); pIdxInfo->estimatedCost = (double)6.0 * (double)nRow; pIdxInfo->estimatedRows = nRow; return rc; } /* ** Return the N-dimensional volumn of the cell stored in *p. */ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){ RtreeDValue area = (RtreeDValue)1; assert( pRtree->nDim>=1 && pRtree->nDim<=5 ); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ switch( pRtree->nDim ){ case 5: area = p->aCoord[9].f - p->aCoord[8].f; case 4: area *= p->aCoord[7].f - p->aCoord[6].f; case 3: area *= p->aCoord[5].f - p->aCoord[4].f; case 2: area *= p->aCoord[3].f - p->aCoord[2].f; default: area *= p->aCoord[1].f - p->aCoord[0].f; } }else #endif { switch( pRtree->nDim ){ case 5: area = (i64)p->aCoord[9].i - (i64)p->aCoord[8].i; case 4: area *= (i64)p->aCoord[7].i - (i64)p->aCoord[6].i; case 3: area *= (i64)p->aCoord[5].i - (i64)p->aCoord[4].i; case 2: area *= (i64)p->aCoord[3].i - (i64)p->aCoord[2].i; default: area *= (i64)p->aCoord[1].i - (i64)p->aCoord[0].i; } } return area; } /* ** Return the margin length of cell p. The margin length is the sum ** of the objects size in each dimension. */ static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){ RtreeDValue margin = 0; int ii = pRtree->nDim2 - 2; do{ margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); ii -= 2; }while( ii>=0 ); return margin; } /* ** Store the union of cells p1 and p2 in p1. */ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ int ii = 0; if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ do{ p1->aCoord[ii].f = MIN(p1->aCoord[ii].f, p2->aCoord[ii].f); p1->aCoord[ii+1].f = MAX(p1->aCoord[ii+1].f, p2->aCoord[ii+1].f); ii += 2; }while( iinDim2 ); }else{ do{ p1->aCoord[ii].i = MIN(p1->aCoord[ii].i, p2->aCoord[ii].i); p1->aCoord[ii+1].i = MAX(p1->aCoord[ii+1].i, p2->aCoord[ii+1].i); ii += 2; }while( iinDim2 ); } } /* ** Return true if the area covered by p2 is a subset of the area covered ** by p1. False otherwise. */ static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ int ii; if( pRtree->eCoordType==RTREE_COORD_INT32 ){ for(ii=0; iinDim2; ii+=2){ RtreeCoord *a1 = &p1->aCoord[ii]; RtreeCoord *a2 = &p2->aCoord[ii]; if( a2[0].ia1[1].i ) return 0; } }else{ for(ii=0; iinDim2; ii+=2){ RtreeCoord *a1 = &p1->aCoord[ii]; RtreeCoord *a2 = &p2->aCoord[ii]; if( a2[0].fa1[1].f ) return 0; } } return 1; } static RtreeDValue cellOverlap( Rtree *pRtree, RtreeCell *p, RtreeCell *aCell, int nCell ){ int ii; RtreeDValue overlap = RTREE_ZERO; for(ii=0; iinDim2; jj+=2){ RtreeDValue x1, x2; x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); if( x2iDepth-iHeight); ii++){ int iCell; sqlite3_int64 iBest = 0; int bFound = 0; RtreeDValue fMinGrowth = RTREE_ZERO; RtreeDValue fMinArea = RTREE_ZERO; int nCell = NCELL(pNode); RtreeNode *pChild = 0; /* First check to see if there is are any cells in pNode that completely ** contains pCell. If two or more cells in pNode completely contain pCell ** then pick the smallest. */ for(iCell=0; iCellpParent ){ RtreeNode *pParent = p->pParent; RtreeCell cell; int iCell; cnt++; if( NEVER(cnt>100) ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } rc = nodeParentIndex(pRtree, p, &iCell); if( NEVER(rc!=SQLITE_OK) ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } nodeGetCell(pRtree, pParent, iCell, &cell); if( !cellContains(pRtree, &cell, pCell) ){ cellUnion(pRtree, &cell, pCell); nodeOverwriteCell(pRtree, pParent, &cell, iCell); } p = pParent; } return SQLITE_OK; } /* ** Write mapping (iRowid->iNode) to the _rowid table. */ static int rowidWrite(Rtree *pRtree, sqlite3_int64 iRowid, sqlite3_int64 iNode){ sqlite3_bind_int64(pRtree->pWriteRowid, 1, iRowid); sqlite3_bind_int64(pRtree->pWriteRowid, 2, iNode); sqlite3_step(pRtree->pWriteRowid); return sqlite3_reset(pRtree->pWriteRowid); } /* ** Write mapping (iNode->iPar) to the _parent table. */ static int parentWrite(Rtree *pRtree, sqlite3_int64 iNode, sqlite3_int64 iPar){ sqlite3_bind_int64(pRtree->pWriteParent, 1, iNode); sqlite3_bind_int64(pRtree->pWriteParent, 2, iPar); sqlite3_step(pRtree->pWriteParent); return sqlite3_reset(pRtree->pWriteParent); } static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int); /* ** Arguments aIdx, aCell and aSpare all point to arrays of size ** nIdx. The aIdx array contains the set of integers from 0 to ** (nIdx-1) in no particular order. This function sorts the values ** in aIdx according to dimension iDim of the cells in aCell. The ** minimum value of dimension iDim is considered first, the ** maximum used to break ties. ** ** The aSpare array is used as temporary working space by the ** sorting algorithm. */ static void SortByDimension( Rtree *pRtree, int *aIdx, int nIdx, int iDim, RtreeCell *aCell, int *aSpare ){ if( nIdx>1 ){ int iLeft = 0; int iRight = 0; int nLeft = nIdx/2; int nRight = nIdx-nLeft; int *aLeft = aIdx; int *aRight = &aIdx[nLeft]; SortByDimension(pRtree, aLeft, nLeft, iDim, aCell, aSpare); SortByDimension(pRtree, aRight, nRight, iDim, aCell, aSpare); memcpy(aSpare, aLeft, sizeof(int)*nLeft); aLeft = aSpare; while( iLeftnDim+1)*(sizeof(int*)+nCell*sizeof(int)); aaSorted = (int **)sqlite3_malloc64(nByte); if( !aaSorted ){ return SQLITE_NOMEM; } aSpare = &((int *)&aaSorted[pRtree->nDim])[pRtree->nDim*nCell]; memset(aaSorted, 0, nByte); for(ii=0; iinDim; ii++){ int jj; aaSorted[ii] = &((int *)&aaSorted[pRtree->nDim])[ii*nCell]; for(jj=0; jjnDim; ii++){ RtreeDValue margin = RTREE_ZERO; RtreeDValue fBestOverlap = RTREE_ZERO; RtreeDValue fBestArea = RTREE_ZERO; int iBestLeft = 0; int nLeft; for( nLeft=RTREE_MINCELLS(pRtree); nLeft<=(nCell-RTREE_MINCELLS(pRtree)); nLeft++ ){ RtreeCell left; RtreeCell right; int kk; RtreeDValue overlap; RtreeDValue area; memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell)); memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell)); for(kk=1; kk<(nCell-1); kk++){ if( kk0 ){ RtreeNode *pChild = nodeHashLookup(pRtree, iRowid); RtreeNode *p; for(p=pNode; p; p=p->pParent){ if( p==pChild ) return SQLITE_CORRUPT_VTAB; } if( pChild ){ nodeRelease(pRtree, pChild->pParent); nodeReference(pNode); pChild->pParent = pNode; } } if( NEVER(pNode==0) ) return SQLITE_ERROR; return xSetMapping(pRtree, iRowid, pNode->iNode); } static int SplitNode( Rtree *pRtree, RtreeNode *pNode, RtreeCell *pCell, int iHeight ){ int i; int newCellIsRight = 0; int rc = SQLITE_OK; int nCell = NCELL(pNode); RtreeCell *aCell; int *aiUsed; RtreeNode *pLeft = 0; RtreeNode *pRight = 0; RtreeCell leftbbox; RtreeCell rightbbox; /* Allocate an array and populate it with a copy of pCell and ** all cells from node pLeft. Then zero the original node. */ aCell = sqlite3_malloc64((sizeof(RtreeCell)+sizeof(int))*(nCell+1)); if( !aCell ){ rc = SQLITE_NOMEM; goto splitnode_out; } aiUsed = (int *)&aCell[nCell+1]; memset(aiUsed, 0, sizeof(int)*(nCell+1)); for(i=0; iiNode==1 ){ pRight = nodeNew(pRtree, pNode); pLeft = nodeNew(pRtree, pNode); pRtree->iDepth++; pNode->isDirty = 1; writeInt16(pNode->zData, pRtree->iDepth); }else{ pLeft = pNode; pRight = nodeNew(pRtree, pLeft->pParent); pLeft->nRef++; } if( !pLeft || !pRight ){ rc = SQLITE_NOMEM; goto splitnode_out; } memset(pLeft->zData, 0, pRtree->iNodeSize); memset(pRight->zData, 0, pRtree->iNodeSize); rc = splitNodeStartree(pRtree, aCell, nCell, pLeft, pRight, &leftbbox, &rightbbox); if( rc!=SQLITE_OK ){ goto splitnode_out; } /* Ensure both child nodes have node numbers assigned to them by calling ** nodeWrite(). Node pRight always needs a node number, as it was created ** by nodeNew() above. But node pLeft sometimes already has a node number. ** In this case avoid the all to nodeWrite(). */ if( SQLITE_OK!=(rc = nodeWrite(pRtree, pRight)) || (0==pLeft->iNode && SQLITE_OK!=(rc = nodeWrite(pRtree, pLeft))) ){ goto splitnode_out; } rightbbox.iRowid = pRight->iNode; leftbbox.iRowid = pLeft->iNode; if( pNode->iNode==1 ){ rc = rtreeInsertCell(pRtree, pLeft->pParent, &leftbbox, iHeight+1); if( rc!=SQLITE_OK ){ goto splitnode_out; } }else{ RtreeNode *pParent = pLeft->pParent; int iCell; rc = nodeParentIndex(pRtree, pLeft, &iCell); if( ALWAYS(rc==SQLITE_OK) ){ nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell); rc = AdjustTree(pRtree, pParent, &leftbbox); assert( rc==SQLITE_OK ); } if( NEVER(rc!=SQLITE_OK) ){ goto splitnode_out; } } if( (rc = rtreeInsertCell(pRtree, pRight->pParent, &rightbbox, iHeight+1)) ){ goto splitnode_out; } for(i=0; iiRowid ){ newCellIsRight = 1; } if( rc!=SQLITE_OK ){ goto splitnode_out; } } if( pNode->iNode==1 ){ for(i=0; iiRowid, pLeft, iHeight); } if( rc==SQLITE_OK ){ rc = nodeRelease(pRtree, pRight); pRight = 0; } if( rc==SQLITE_OK ){ rc = nodeRelease(pRtree, pLeft); pLeft = 0; } splitnode_out: nodeRelease(pRtree, pRight); nodeRelease(pRtree, pLeft); sqlite3_free(aCell); return rc; } /* ** If node pLeaf is not the root of the r-tree and its pParent pointer is ** still NULL, load all ancestor nodes of pLeaf into memory and populate ** the pLeaf->pParent chain all the way up to the root node. ** ** This operation is required when a row is deleted (or updated - an update ** is implemented as a delete followed by an insert). SQLite provides the ** rowid of the row to delete, which can be used to find the leaf on which ** the entry resides (argument pLeaf). Once the leaf is located, this ** function is called to determine its ancestry. */ static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){ int rc = SQLITE_OK; RtreeNode *pChild = pLeaf; while( rc==SQLITE_OK && pChild->iNode!=1 && pChild->pParent==0 ){ int rc2 = SQLITE_OK; /* sqlite3_reset() return code */ sqlite3_bind_int64(pRtree->pReadParent, 1, pChild->iNode); rc = sqlite3_step(pRtree->pReadParent); if( rc==SQLITE_ROW ){ RtreeNode *pTest; /* Used to test for reference loops */ i64 iNode; /* Node number of parent node */ /* Before setting pChild->pParent, test that we are not creating a ** loop of references (as we would if, say, pChild==pParent). We don't ** want to do this as it leads to a memory leak when trying to delete ** the referenced counted node structures. */ iNode = sqlite3_column_int64(pRtree->pReadParent, 0); for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent); if( pTest==0 ){ rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent); } } rc = sqlite3_reset(pRtree->pReadParent); if( rc==SQLITE_OK ) rc = rc2; if( rc==SQLITE_OK && !pChild->pParent ){ RTREE_IS_CORRUPT(pRtree); rc = SQLITE_CORRUPT_VTAB; } pChild = pChild->pParent; } return rc; } static int deleteCell(Rtree *, RtreeNode *, int, int); static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){ int rc; int rc2; RtreeNode *pParent = 0; int iCell; assert( pNode->nRef==1 ); /* Remove the entry in the parent cell. */ rc = nodeParentIndex(pRtree, pNode, &iCell); if( rc==SQLITE_OK ){ pParent = pNode->pParent; pNode->pParent = 0; rc = deleteCell(pRtree, pParent, iCell, iHeight+1); testcase( rc!=SQLITE_OK ); } rc2 = nodeRelease(pRtree, pParent); if( rc==SQLITE_OK ){ rc = rc2; } if( rc!=SQLITE_OK ){ return rc; } /* Remove the xxx_node entry. */ sqlite3_bind_int64(pRtree->pDeleteNode, 1, pNode->iNode); sqlite3_step(pRtree->pDeleteNode); if( SQLITE_OK!=(rc = sqlite3_reset(pRtree->pDeleteNode)) ){ return rc; } /* Remove the xxx_parent entry. */ sqlite3_bind_int64(pRtree->pDeleteParent, 1, pNode->iNode); sqlite3_step(pRtree->pDeleteParent); if( SQLITE_OK!=(rc = sqlite3_reset(pRtree->pDeleteParent)) ){ return rc; } /* Remove the node from the in-memory hash table and link it into ** the Rtree.pDeleted list. Its contents will be re-inserted later on. */ nodeHashDelete(pRtree, pNode); pNode->iNode = iHeight; pNode->pNext = pRtree->pDeleted; pNode->nRef++; pRtree->pDeleted = pNode; return SQLITE_OK; } static int fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){ RtreeNode *pParent = pNode->pParent; int rc = SQLITE_OK; if( pParent ){ int ii; int nCell = NCELL(pNode); RtreeCell box; /* Bounding box for pNode */ nodeGetCell(pRtree, pNode, 0, &box); for(ii=1; iiiNode; rc = nodeParentIndex(pRtree, pNode, &ii); if( rc==SQLITE_OK ){ nodeOverwriteCell(pRtree, pParent, &box, ii); rc = fixBoundingBox(pRtree, pParent); } } return rc; } /* ** Delete the cell at index iCell of node pNode. After removing the ** cell, adjust the r-tree data structure if required. */ static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){ RtreeNode *pParent; int rc; if( SQLITE_OK!=(rc = fixLeafParent(pRtree, pNode)) ){ return rc; } /* Remove the cell from the node. This call just moves bytes around ** the in-memory node image, so it cannot fail. */ nodeDeleteCell(pRtree, pNode, iCell); /* If the node is not the tree root and now has less than the minimum ** number of cells, remove it from the tree. Otherwise, update the ** cell in the parent node so that it tightly contains the updated ** node. */ pParent = pNode->pParent; assert( pParent || pNode->iNode==1 ); if( pParent ){ if( NCELL(pNode)0 ){ RtreeNode *pChild = nodeHashLookup(pRtree, pCell->iRowid); if( pChild ){ nodeRelease(pRtree, pChild->pParent); nodeReference(pNode); pChild->pParent = pNode; } } if( nodeInsertCell(pRtree, pNode, pCell) ){ rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ rc = AdjustTree(pRtree, pNode, pCell); if( ALWAYS(rc==SQLITE_OK) ){ if( iHeight==0 ){ rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); }else{ rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode); } } } return rc; } static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){ int ii; int rc = SQLITE_OK; int nCell = NCELL(pNode); for(ii=0; rc==SQLITE_OK && iiiNode currently contains ** the height of the sub-tree headed by the cell. */ rc = ChooseLeaf(pRtree, &cell, (int)pNode->iNode, &pInsert); if( rc==SQLITE_OK ){ int rc2; rc = rtreeInsertCell(pRtree, pInsert, &cell, (int)pNode->iNode); rc2 = nodeRelease(pRtree, pInsert); if( rc==SQLITE_OK ){ rc = rc2; } } } return rc; } /* ** Select a currently unused rowid for a new r-tree record. */ static int rtreeNewRowid(Rtree *pRtree, i64 *piRowid){ int rc; sqlite3_bind_null(pRtree->pWriteRowid, 1); sqlite3_bind_null(pRtree->pWriteRowid, 2); sqlite3_step(pRtree->pWriteRowid); rc = sqlite3_reset(pRtree->pWriteRowid); *piRowid = sqlite3_last_insert_rowid(pRtree->db); return rc; } /* ** Remove the entry with rowid=iDelete from the r-tree structure. */ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ int rc; /* Return code */ RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */ int iCell; /* Index of iDelete cell in pLeaf */ RtreeNode *pRoot = 0; /* Root node of rtree structure */ /* Obtain a reference to the root node to initialize Rtree.iDepth */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); /* Obtain a reference to the leaf node that contains the entry ** about to be deleted. */ if( rc==SQLITE_OK ){ rc = findLeafNode(pRtree, iDelete, &pLeaf, 0); } #ifdef CORRUPT_DB assert( pLeaf!=0 || rc!=SQLITE_OK || CORRUPT_DB ); #endif /* Delete the cell in question from the leaf node. */ if( rc==SQLITE_OK && pLeaf ){ int rc2; rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); if( rc==SQLITE_OK ){ rc = deleteCell(pRtree, pLeaf, iCell, 0); } rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ rc = rc2; } } /* Delete the corresponding entry in the _rowid table. */ if( rc==SQLITE_OK ){ sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete); sqlite3_step(pRtree->pDeleteRowid); rc = sqlite3_reset(pRtree->pDeleteRowid); } /* Check if the root node now has exactly one child. If so, remove ** it, schedule the contents of the child for reinsertion and ** reduce the tree height by one. ** ** This is equivalent to copying the contents of the child into ** the root node (the operation that Gutman's paper says to perform ** in this scenario). */ if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ int rc2; RtreeNode *pChild = 0; i64 iChild = nodeGetRowid(pRtree, pRoot, 0); rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); /* tag-20210916a */ if( rc==SQLITE_OK ){ rc = removeNode(pRtree, pChild, pRtree->iDepth-1); } rc2 = nodeRelease(pRtree, pChild); if( rc==SQLITE_OK ) rc = rc2; if( rc==SQLITE_OK ){ pRtree->iDepth--; writeInt16(pRoot->zData, pRtree->iDepth); pRoot->isDirty = 1; } } /* Re-insert the contents of any underfull nodes removed from the tree. */ for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ if( rc==SQLITE_OK ){ rc = reinsertNodeContent(pRtree, pLeaf); } pRtree->pDeleted = pLeaf->pNext; pRtree->nNodeRef--; sqlite3_free(pLeaf); } /* Release the reference to the root node. */ if( rc==SQLITE_OK ){ rc = nodeRelease(pRtree, pRoot); }else{ nodeRelease(pRtree, pRoot); } return rc; } /* ** Rounding constants for float->double conversion. */ #define RNDTOWARDS (1.0 - 1.0/8388608.0) /* Round towards zero */ #define RNDAWAY (1.0 + 1.0/8388608.0) /* Round away from zero */ #if !defined(SQLITE_RTREE_INT_ONLY) /* ** Convert an sqlite3_value into an RtreeValue (presumably a float) ** while taking care to round toward negative or positive, respectively. */ static RtreeValue rtreeValueDown(sqlite3_value *v){ double d = sqlite3_value_double(v); float f = (float)d; if( f>d ){ f = (float)(d*(d<0 ? RNDAWAY : RNDTOWARDS)); } return f; } static RtreeValue rtreeValueUp(sqlite3_value *v){ double d = sqlite3_value_double(v); float f = (float)d; if( fbase.zErrMsg) to an appropriate value and returns ** SQLITE_CONSTRAINT. ** ** Parameter iCol is the index of the leftmost column involved in the ** constraint failure. If it is 0, then the constraint that failed is ** the unique constraint on the id column. Otherwise, it is the rtree ** (c1<=c2) constraint on columns iCol and iCol+1 that has failed. ** ** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT. */ static int rtreeConstraintError(Rtree *pRtree, int iCol){ sqlite3_stmt *pStmt = 0; char *zSql; int rc; assert( iCol==0 || iCol%2 ); zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName); if( zSql ){ rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0); }else{ rc = SQLITE_NOMEM; } sqlite3_free(zSql); if( rc==SQLITE_OK ){ if( iCol==0 ){ const char *zCol = sqlite3_column_name(pStmt, 0); pRtree->base.zErrMsg = sqlite3_mprintf( "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol ); }else{ const char *zCol1 = sqlite3_column_name(pStmt, iCol); const char *zCol2 = sqlite3_column_name(pStmt, iCol+1); pRtree->base.zErrMsg = sqlite3_mprintf( "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2 ); } } sqlite3_finalize(pStmt); return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc); } /* ** The xUpdate method for rtree module virtual tables. */ static int rtreeUpdate( sqlite3_vtab *pVtab, int nData, sqlite3_value **aData, sqlite_int64 *pRowid ){ Rtree *pRtree = (Rtree *)pVtab; int rc = SQLITE_OK; RtreeCell cell; /* New cell to insert if nData>1 */ int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ if( pRtree->nNodeRef ){ /* Unable to write to the btree while another cursor is reading from it, ** since the write might do a rebalance which would disrupt the read ** cursor. */ return SQLITE_LOCKED_VTAB; } rtreeReference(pRtree); assert(nData>=1); memset(&cell, 0, sizeof(cell)); /* Constraint handling. A write operation on an r-tree table may return ** SQLITE_CONSTRAINT for two reasons: ** ** 1. A duplicate rowid value, or ** 2. The supplied data violates the "x2>=x1" constraint. ** ** In the first case, if the conflict-handling mode is REPLACE, then ** the conflicting row can be removed before proceeding. In the second ** case, SQLITE_CONSTRAINT must be returned regardless of the ** conflict-handling mode specified by the user. */ if( nData>1 ){ int ii; int nn = nData - 4; if( nn > pRtree->nDim2 ) nn = pRtree->nDim2; /* Populate the cell.aCoord[] array. The first coordinate is aData[3]. ** ** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared ** with "column" that are interpreted as table constraints. ** Example: CREATE VIRTUAL TABLE bad USING rtree(x,y,CHECK(y>5)); ** This problem was discovered after years of use, so we silently ignore ** these kinds of misdeclared tables to avoid breaking any legacy. */ #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ for(ii=0; iicell.aCoord[ii+1].f ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } }else #endif { for(ii=0; iicell.aCoord[ii+1].i ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } } /* If a rowid value was supplied, check if it is already present in ** the table. If so, the constraint has failed. */ if( sqlite3_value_type(aData[2])!=SQLITE_NULL ){ cell.iRowid = sqlite3_value_int64(aData[2]); if( sqlite3_value_type(aData[0])==SQLITE_NULL || sqlite3_value_int64(aData[0])!=cell.iRowid ){ int steprc; sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); steprc = sqlite3_step(pRtree->pReadRowid); rc = sqlite3_reset(pRtree->pReadRowid); if( SQLITE_ROW==steprc ){ if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ rc = rtreeDeleteRowid(pRtree, cell.iRowid); }else{ rc = rtreeConstraintError(pRtree, 0); goto constraint; } } } bHaveRowid = 1; } } /* If aData[0] is not an SQL NULL value, it is the rowid of a ** record to delete from the r-tree table. The following block does ** just that. */ if( sqlite3_value_type(aData[0])!=SQLITE_NULL ){ rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0])); } /* If the aData[] array contains more than one element, elements ** (aData[2]..aData[argc-1]) contain a new record to insert into ** the r-tree structure. */ if( rc==SQLITE_OK && nData>1 ){ /* Insert the new record into the r-tree */ RtreeNode *pLeaf = 0; /* Figure out the rowid of the new row. */ if( bHaveRowid==0 ){ rc = rtreeNewRowid(pRtree, &cell.iRowid); } *pRowid = cell.iRowid; if( rc==SQLITE_OK ){ rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); } if( rc==SQLITE_OK ){ int rc2; rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ rc = rc2; } } if( rc==SQLITE_OK && pRtree->nAux ){ sqlite3_stmt *pUp = pRtree->pWriteAux; int jj; sqlite3_bind_int64(pUp, 1, *pRowid); for(jj=0; jjnAux; jj++){ sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]); } sqlite3_step(pUp); rc = sqlite3_reset(pUp); } } constraint: rtreeRelease(pRtree); return rc; } /* ** Called when a transaction starts. */ static int rtreeBeginTransaction(sqlite3_vtab *pVtab){ Rtree *pRtree = (Rtree *)pVtab; assert( pRtree->inWrTrans==0 ); pRtree->inWrTrans++; return SQLITE_OK; } /* ** Called when a transaction completes (either by COMMIT or ROLLBACK). ** The sqlite3_blob object should be released at this point. */ static int rtreeEndTransaction(sqlite3_vtab *pVtab){ Rtree *pRtree = (Rtree *)pVtab; pRtree->inWrTrans = 0; nodeBlobReset(pRtree); return SQLITE_OK; } /* ** The xRename method for rtree module virtual tables. */ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){ Rtree *pRtree = (Rtree *)pVtab; int rc = SQLITE_NOMEM; char *zSql = sqlite3_mprintf( "ALTER TABLE %Q.'%q_node' RENAME TO \"%w_node\";" "ALTER TABLE %Q.'%q_parent' RENAME TO \"%w_parent\";" "ALTER TABLE %Q.'%q_rowid' RENAME TO \"%w_rowid\";" , pRtree->zDb, pRtree->zName, zNewName , pRtree->zDb, pRtree->zName, zNewName , pRtree->zDb, pRtree->zName, zNewName ); if( zSql ){ nodeBlobReset(pRtree); rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0); sqlite3_free(zSql); } return rc; } /* ** The xSavepoint method. ** ** This module does not need to do anything to support savepoints. However, ** it uses this hook to close any open blob handle. This is done because a ** DROP TABLE command - which fortunately always opens a savepoint - cannot ** succeed if there are any open blob handles. i.e. if the blob handle were ** not closed here, the following would fail: ** ** BEGIN; ** INSERT INTO rtree... ** DROP TABLE ; -- Would fail with SQLITE_LOCKED ** COMMIT; */ static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ Rtree *pRtree = (Rtree *)pVtab; u8 iwt = pRtree->inWrTrans; UNUSED_PARAMETER(iSavepoint); pRtree->inWrTrans = 0; nodeBlobReset(pRtree); pRtree->inWrTrans = iwt; return SQLITE_OK; } /* ** This function populates the pRtree->nRowEst variable with an estimate ** of the number of rows in the virtual table. If possible, this is based ** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST. */ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; char *zSql; sqlite3_stmt *p; int rc; i64 nRow = RTREE_MIN_ROWEST; rc = sqlite3_table_column_metadata( db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0 ); if( rc!=SQLITE_OK ){ pRtree->nRowEst = RTREE_DEFAULT_ROWEST; return rc==SQLITE_ERROR ? SQLITE_OK : rc; } zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); if( rc==SQLITE_OK ){ if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); rc = sqlite3_finalize(p); } sqlite3_free(zSql); } pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); return rc; } /* ** Return true if zName is the extension on one of the shadow tables used ** by this module. */ static int rtreeShadowName(const char *zName){ static const char *azName[] = { "node", "parent", "rowid" }; unsigned int i; for(i=0; idb = db; if( isCreate ){ char *zCreate; sqlite3_str *p = sqlite3_str_new(db); int ii; sqlite3_str_appendf(p, "CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY,nodeno", zDb, zPrefix); for(ii=0; iinAux; ii++){ sqlite3_str_appendf(p,",a%d",ii); } sqlite3_str_appendf(p, ");CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY,data);", zDb, zPrefix); sqlite3_str_appendf(p, "CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY,parentnode);", zDb, zPrefix); sqlite3_str_appendf(p, "INSERT INTO \"%w\".\"%w_node\"VALUES(1,zeroblob(%d))", zDb, zPrefix, pRtree->iNodeSize); zCreate = sqlite3_str_finish(p); if( !zCreate ){ return SQLITE_NOMEM; } rc = sqlite3_exec(db, zCreate, 0, 0, 0); sqlite3_free(zCreate); if( rc!=SQLITE_OK ){ return rc; } } appStmt[0] = &pRtree->pWriteNode; appStmt[1] = &pRtree->pDeleteNode; appStmt[2] = &pRtree->pReadRowid; appStmt[3] = &pRtree->pWriteRowid; appStmt[4] = &pRtree->pDeleteRowid; appStmt[5] = &pRtree->pReadParent; appStmt[6] = &pRtree->pWriteParent; appStmt[7] = &pRtree->pDeleteParent; rc = rtreeQueryStat1(db, pRtree); for(i=0; inAux==0 ){ zFormat = azSql[i]; }else { /* An UPSERT is very slightly slower than REPLACE, but it is needed ** if there are auxiliary columns */ zFormat = "INSERT INTO\"%w\".\"%w_rowid\"(rowid,nodeno)VALUES(?1,?2)" "ON CONFLICT(rowid)DO UPDATE SET nodeno=excluded.nodeno"; } zSql = sqlite3_mprintf(zFormat, zDb, zPrefix); if( zSql ){ rc = sqlite3_prepare_v3(db, zSql, -1, f, appStmt[i], 0); }else{ rc = SQLITE_NOMEM; } sqlite3_free(zSql); } if( pRtree->nAux && rc!=SQLITE_NOMEM ){ pRtree->zReadAuxSql = sqlite3_mprintf( "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1", zDb, zPrefix); if( pRtree->zReadAuxSql==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_str *p = sqlite3_str_new(db); int ii; char *zSql; sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix); for(ii=0; iinAux; ii++){ if( ii ) sqlite3_str_append(p, ",", 1); #ifdef SQLITE_ENABLE_GEOPOLY if( iinAuxNotNull ){ sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii); }else #endif { sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2); } } sqlite3_str_appendf(p, " WHERE rowid=?1"); zSql = sqlite3_str_finish(p); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v3(db, zSql, -1, f, &pRtree->pWriteAux, 0); sqlite3_free(zSql); } } } return rc; } /* ** The second argument to this function contains the text of an SQL statement ** that returns a single integer value. The statement is compiled and executed ** using database connection db. If successful, the integer value returned ** is written to *piVal and SQLITE_OK returned. Otherwise, an SQLite error ** code is returned and the value of *piVal after returning is not defined. */ static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){ int rc = SQLITE_NOMEM; if( zSql ){ sqlite3_stmt *pStmt = 0; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ *piVal = sqlite3_column_int(pStmt, 0); } rc = sqlite3_finalize(pStmt); } } return rc; } /* ** This function is called from within the xConnect() or xCreate() method to ** determine the node-size used by the rtree table being created or connected ** to. If successful, pRtree->iNodeSize is populated and SQLITE_OK returned. ** Otherwise, an SQLite error code is returned. ** ** If this function is being called as part of an xConnect(), then the rtree ** table already exists. In this case the node-size is determined by inspecting ** the root node of the tree. ** ** Otherwise, for an xCreate(), use 64 bytes less than the database page-size. ** This ensures that each node is stored on a single database page. If the ** database page-size is so large that more than RTREE_MAXCELLS entries ** would fit in a single node, use a smaller node-size. */ static int getNodeSize( sqlite3 *db, /* Database handle */ Rtree *pRtree, /* Rtree handle */ int isCreate, /* True for xCreate, false for xConnect */ char **pzErr /* OUT: Error message, if any */ ){ int rc; char *zSql; if( isCreate ){ int iPageSize = 0; zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb); rc = getIntFromStmt(db, zSql, &iPageSize); if( rc==SQLITE_OK ){ pRtree->iNodeSize = iPageSize-64; if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)iNodeSize ){ pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS; } }else{ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } }else{ zSql = sqlite3_mprintf( "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1", pRtree->zDb, pRtree->zName ); rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); }else if( pRtree->iNodeSize<(512-64) ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"", pRtree->zName); } } sqlite3_free(zSql); return rc; } /* ** Return the length of a token */ static int rtreeTokenLength(const char *z){ int dummy = 0; return sqlite3GetToken((const unsigned char*)z,&dummy); } /* ** This function is the implementation of both the xConnect and xCreate ** methods of the r-tree virtual table. ** ** argv[0] -> module name ** argv[1] -> database name ** argv[2] -> table name ** argv[...] -> column names... */ static int rtreeInit( sqlite3 *db, /* Database connection */ void *pAux, /* One of the RTREE_COORD_* constants */ int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */ sqlite3_vtab **ppVtab, /* OUT: New virtual table */ char **pzErr, /* OUT: Error message, if any */ int isCreate /* True for xCreate, false for xConnect */ ){ int rc = SQLITE_OK; Rtree *pRtree; int nDb; /* Length of string argv[1] */ int nName; /* Length of string argv[2] */ int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32); sqlite3_str *pSql; char *zSql; int ii = 4; int iErr; const char *aErrMsg[] = { 0, /* 0 */ "Wrong number of columns for an rtree table", /* 1 */ "Too few columns for an rtree table", /* 2 */ "Too many columns for an rtree table", /* 3 */ "Auxiliary rtree columns must be last" /* 4 */ }; assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */ if( argc<6 || argc>RTREE_MAX_AUX_COLUMN+3 ){ *pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]); return SQLITE_ERROR; } sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); /* Allocate the sqlite3_vtab structure */ nDb = (int)strlen(argv[1]); nName = (int)strlen(argv[2]); pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8); if( !pRtree ){ return SQLITE_NOMEM; } memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8); pRtree->nBusy = 1; pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; pRtree->zName = &pRtree->zDb[nDb+1]; pRtree->zNodeName = &pRtree->zName[nName+1]; pRtree->eCoordType = (u8)eCoordType; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); memcpy(pRtree->zNodeName, argv[2], nName); memcpy(&pRtree->zNodeName[nName], "_node", 6); /* Create/Connect to the underlying relational database schema. If ** that is successful, call sqlite3_declare_vtab() to configure ** the r-tree table schema. */ pSql = sqlite3_str_new(db); sqlite3_str_appendf(pSql, "CREATE TABLE x(%.*s INT", rtreeTokenLength(argv[3]), argv[3]); for(ii=4; iinAux++; sqlite3_str_appendf(pSql, ",%.*s", rtreeTokenLength(zArg+1), zArg+1); }else if( pRtree->nAux>0 ){ break; }else{ static const char *azFormat[] = {",%.*s REAL", ",%.*s INT"}; pRtree->nDim2++; sqlite3_str_appendf(pSql, azFormat[eCoordType], rtreeTokenLength(zArg), zArg); } } sqlite3_str_appendf(pSql, ");"); zSql = sqlite3_str_finish(pSql); if( !zSql ){ rc = SQLITE_NOMEM; }else if( iinDim = pRtree->nDim2/2; if( pRtree->nDim<1 ){ iErr = 2; }else if( pRtree->nDim2>RTREE_MAX_DIMENSIONS*2 ){ iErr = 3; }else if( pRtree->nDim2 % 2 ){ iErr = 1; }else{ iErr = 0; } if( iErr ){ *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]); goto rtreeInit_fail; } pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; /* Figure out the node size to use. */ rc = getNodeSize(db, pRtree, isCreate, pzErr); if( rc ) goto rtreeInit_fail; rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate); if( rc ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); goto rtreeInit_fail; } *ppVtab = (sqlite3_vtab *)pRtree; return SQLITE_OK; rtreeInit_fail: if( rc==SQLITE_OK ) rc = SQLITE_ERROR; assert( *ppVtab==0 ); assert( pRtree->nBusy==1 ); rtreeRelease(pRtree); return rc; } /* ** Implementation of a scalar function that decodes r-tree nodes to ** human readable strings. This can be used for debugging and analysis. ** ** The scalar function takes two arguments: (1) the number of dimensions ** to the rtree (between 1 and 5, inclusive) and (2) a blob of data containing ** an r-tree node. For a two-dimensional r-tree structure called "rt", to ** deserialize all nodes, a statement like: ** ** SELECT rtreenode(2, data) FROM rt_node; ** ** The human readable string takes the form of a Tcl list with one ** entry for each cell in the r-tree node. Each entry is itself a ** list, containing the 8-byte rowid/pageno followed by the ** *2 coordinates. */ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ RtreeNode node; Rtree tree; int ii; int nData; int errCode; sqlite3_str *pOut; UNUSED_PARAMETER(nArg); memset(&node, 0, sizeof(RtreeNode)); memset(&tree, 0, sizeof(Rtree)); tree.nDim = (u8)sqlite3_value_int(apArg[0]); if( tree.nDim<1 || tree.nDim>5 ) return; tree.nDim2 = tree.nDim*2; tree.nBytesPerCell = 8 + 8 * tree.nDim; node.zData = (u8 *)sqlite3_value_blob(apArg[1]); if( node.zData==0 ) return; nData = sqlite3_value_bytes(apArg[1]); if( nData<4 ) return; if( nData0 ) sqlite3_str_append(pOut, " ", 1); sqlite3_str_appendf(pOut, "{%lld", cell.iRowid); for(jj=0; jjrc==SQLITE_OK ) pCheck->rc = rc; } /* ** The second and subsequent arguments to this function are a format string ** and printf style arguments. This function formats the string and attempts ** to compile it as an SQL statement. ** ** If successful, a pointer to the new SQL statement is returned. Otherwise, ** NULL is returned and an error code left in RtreeCheck.rc. */ static sqlite3_stmt *rtreeCheckPrepare( RtreeCheck *pCheck, /* RtreeCheck object */ const char *zFmt, ... /* Format string and trailing args */ ){ va_list ap; char *z; sqlite3_stmt *pRet = 0; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); if( pCheck->rc==SQLITE_OK ){ if( z==0 ){ pCheck->rc = SQLITE_NOMEM; }else{ pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0); } } sqlite3_free(z); va_end(ap); return pRet; } /* ** The second and subsequent arguments to this function are a printf() ** style format string and arguments. This function formats the string and ** appends it to the report being accumuated in pCheck. */ static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){ va_list ap; va_start(ap, zFmt); if( pCheck->rc==SQLITE_OK && pCheck->nErrrc = SQLITE_NOMEM; }else{ pCheck->zReport = sqlite3_mprintf("%z%s%z", pCheck->zReport, (pCheck->zReport ? "\n" : ""), z ); if( pCheck->zReport==0 ){ pCheck->rc = SQLITE_NOMEM; } } pCheck->nErr++; } va_end(ap); } /* ** This function is a no-op if there is already an error code stored ** in the RtreeCheck object indicated by the first argument. NULL is ** returned in this case. ** ** Otherwise, the contents of rtree table node iNode are loaded from ** the database and copied into a buffer obtained from sqlite3_malloc(). ** If no error occurs, a pointer to the buffer is returned and (*pnNode) ** is set to the size of the buffer in bytes. ** ** Or, if an error does occur, NULL is returned and an error code left ** in the RtreeCheck object. The final value of *pnNode is undefined in ** this case. */ static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){ u8 *pRet = 0; /* Return value */ if( pCheck->rc==SQLITE_OK && pCheck->pGetNode==0 ){ pCheck->pGetNode = rtreeCheckPrepare(pCheck, "SELECT data FROM %Q.'%q_node' WHERE nodeno=?", pCheck->zDb, pCheck->zTab ); } if( pCheck->rc==SQLITE_OK ){ sqlite3_bind_int64(pCheck->pGetNode, 1, iNode); if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){ int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0); const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0); pRet = sqlite3_malloc64(nNode); if( pRet==0 ){ pCheck->rc = SQLITE_NOMEM; }else{ memcpy(pRet, pNode, nNode); *pnNode = nNode; } } rtreeCheckReset(pCheck, pCheck->pGetNode); if( pCheck->rc==SQLITE_OK && pRet==0 ){ rtreeCheckAppendMsg(pCheck, "Node %lld missing from database", iNode); } } return pRet; } /* ** This function is used to check that the %_parent (if bLeaf==0) or %_rowid ** (if bLeaf==1) table contains a specified entry. The schemas of the ** two tables are: ** ** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER) ** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...) ** ** In both cases, this function checks that there exists an entry with ** IPK value iKey and the second column set to iVal. ** */ static void rtreeCheckMapping( RtreeCheck *pCheck, /* RtreeCheck object */ int bLeaf, /* True for a leaf cell, false for interior */ i64 iKey, /* Key for mapping */ i64 iVal /* Expected value for mapping */ ){ int rc; sqlite3_stmt *pStmt; const char *azSql[2] = { "SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?1", "SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?1" }; assert( bLeaf==0 || bLeaf==1 ); if( pCheck->aCheckMapping[bLeaf]==0 ){ pCheck->aCheckMapping[bLeaf] = rtreeCheckPrepare(pCheck, azSql[bLeaf], pCheck->zDb, pCheck->zTab ); } if( pCheck->rc!=SQLITE_OK ) return; pStmt = pCheck->aCheckMapping[bLeaf]; sqlite3_bind_int64(pStmt, 1, iKey); rc = sqlite3_step(pStmt); if( rc==SQLITE_DONE ){ rtreeCheckAppendMsg(pCheck, "Mapping (%lld -> %lld) missing from %s table", iKey, iVal, (bLeaf ? "%_rowid" : "%_parent") ); }else if( rc==SQLITE_ROW ){ i64 ii = sqlite3_column_int64(pStmt, 0); if( ii!=iVal ){ rtreeCheckAppendMsg(pCheck, "Found (%lld -> %lld) in %s table, expected (%lld -> %lld)", iKey, ii, (bLeaf ? "%_rowid" : "%_parent"), iKey, iVal ); } } rtreeCheckReset(pCheck, pStmt); } /* ** Argument pCell points to an array of coordinates stored on an rtree page. ** This function checks that the coordinates are internally consistent (no ** x1>x2 conditions) and adds an error message to the RtreeCheck object ** if they are not. ** ** Additionally, if pParent is not NULL, then it is assumed to point to ** the array of coordinates on the parent page that bound the page ** containing pCell. In this case it is also verified that the two ** sets of coordinates are mutually consistent and an error message added ** to the RtreeCheck object if they are not. */ static void rtreeCheckCellCoord( RtreeCheck *pCheck, i64 iNode, /* Node id to use in error messages */ int iCell, /* Cell number to use in error messages */ u8 *pCell, /* Pointer to cell coordinates */ u8 *pParent /* Pointer to parent coordinates */ ){ RtreeCoord c1, c2; RtreeCoord p1, p2; int i; for(i=0; inDim; i++){ readCoord(&pCell[4*2*i], &c1); readCoord(&pCell[4*(2*i + 1)], &c2); /* printf("%e, %e\n", c1.u.f, c2.u.f); */ if( pCheck->bInt ? c1.i>c2.i : c1.f>c2.f ){ rtreeCheckAppendMsg(pCheck, "Dimension %d of cell %d on node %lld is corrupt", i, iCell, iNode ); } if( pParent ){ readCoord(&pParent[4*2*i], &p1); readCoord(&pParent[4*(2*i + 1)], &p2); if( (pCheck->bInt ? c1.ibInt ? c2.i>p2.i : c2.f>p2.f) ){ rtreeCheckAppendMsg(pCheck, "Dimension %d of cell %d on node %lld is corrupt relative to parent" , i, iCell, iNode ); } } } } /* ** Run rtreecheck() checks on node iNode, which is at depth iDepth within ** the r-tree structure. Argument aParent points to the array of coordinates ** that bound node iNode on the parent node. ** ** If any problems are discovered, an error message is appended to the ** report accumulated in the RtreeCheck object. */ static void rtreeCheckNode( RtreeCheck *pCheck, int iDepth, /* Depth of iNode (0==leaf) */ u8 *aParent, /* Buffer containing parent coords */ i64 iNode /* Node to check */ ){ u8 *aNode = 0; int nNode = 0; assert( iNode==1 || aParent!=0 ); assert( pCheck->nDim>0 ); aNode = rtreeCheckGetNode(pCheck, iNode, &nNode); if( aNode ){ if( nNode<4 ){ rtreeCheckAppendMsg(pCheck, "Node %lld is too small (%d bytes)", iNode, nNode ); }else{ int nCell; /* Number of cells on page */ int i; /* Used to iterate through cells */ if( aParent==0 ){ iDepth = readInt16(aNode); if( iDepth>RTREE_MAX_DEPTH ){ rtreeCheckAppendMsg(pCheck, "Rtree depth out of range (%d)", iDepth); sqlite3_free(aNode); return; } } nCell = readInt16(&aNode[2]); if( (4 + nCell*(8 + pCheck->nDim*2*4))>nNode ){ rtreeCheckAppendMsg(pCheck, "Node %lld is too small for cell count of %d (%d bytes)", iNode, nCell, nNode ); }else{ for(i=0; inDim*2*4)]; i64 iVal = readInt64(pCell); rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent); if( iDepth>0 ){ rtreeCheckMapping(pCheck, 0, iVal, iNode); rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal); pCheck->nNonLeaf++; }else{ rtreeCheckMapping(pCheck, 1, iVal, iNode); pCheck->nLeaf++; } } } } sqlite3_free(aNode); } } /* ** The second argument to this function must be either "_rowid" or ** "_parent". This function checks that the number of entries in the ** %_rowid or %_parent table is exactly nExpect. If not, it adds ** an error message to the report in the RtreeCheck object indicated ** by the first argument. */ static void rtreeCheckCount(RtreeCheck *pCheck, const char *zTbl, i64 nExpect){ if( pCheck->rc==SQLITE_OK ){ sqlite3_stmt *pCount; pCount = rtreeCheckPrepare(pCheck, "SELECT count(*) FROM %Q.'%q%s'", pCheck->zDb, pCheck->zTab, zTbl ); if( pCount ){ if( sqlite3_step(pCount)==SQLITE_ROW ){ i64 nActual = sqlite3_column_int64(pCount, 0); if( nActual!=nExpect ){ rtreeCheckAppendMsg(pCheck, "Wrong number of entries in %%%s table" " - expected %lld, actual %lld" , zTbl, nExpect, nActual ); } } pCheck->rc = sqlite3_finalize(pCount); } } } /* ** This function does the bulk of the work for the rtree integrity-check. ** It is called by rtreecheck(), which is the SQL function implementation. */ static int rtreeCheckTable( sqlite3 *db, /* Database handle to access db through */ const char *zDb, /* Name of db ("main", "temp" etc.) */ const char *zTab, /* Name of rtree table to check */ char **pzReport /* OUT: sqlite3_malloc'd report text */ ){ RtreeCheck check; /* Common context for various routines */ sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */ int nAux = 0; /* Number of extra columns. */ /* Initialize the context object */ memset(&check, 0, sizeof(check)); check.db = db; check.zDb = zDb; check.zTab = zTab; /* Find the number of auxiliary columns */ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab); if( pStmt ){ nAux = sqlite3_column_count(pStmt) - 2; sqlite3_finalize(pStmt); }else if( check.rc!=SQLITE_NOMEM ){ check.rc = SQLITE_OK; } /* Find number of dimensions in the rtree table. */ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab); if( pStmt ){ int rc; check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2; if( check.nDim<1 ){ rtreeCheckAppendMsg(&check, "Schema corrupt or not an rtree"); }else if( SQLITE_ROW==sqlite3_step(pStmt) ){ check.bInt = (sqlite3_column_type(pStmt, 1)==SQLITE_INTEGER); } rc = sqlite3_finalize(pStmt); if( rc!=SQLITE_CORRUPT ) check.rc = rc; } /* Do the actual integrity-check */ if( check.nDim>=1 ){ if( check.rc==SQLITE_OK ){ rtreeCheckNode(&check, 0, 0, 1); } rtreeCheckCount(&check, "_rowid", check.nLeaf); rtreeCheckCount(&check, "_parent", check.nNonLeaf); } /* Finalize SQL statements used by the integrity-check */ sqlite3_finalize(check.pGetNode); sqlite3_finalize(check.aCheckMapping[0]); sqlite3_finalize(check.aCheckMapping[1]); *pzReport = check.zReport; return check.rc; } /* ** Implementation of the xIntegrity method for Rtree. */ static int rtreeIntegrity( sqlite3_vtab *pVtab, /* The virtual table to check */ const char *zSchema, /* Schema in which the virtual table lives */ const char *zName, /* Name of the virtual table */ int isQuick, /* True for a quick_check */ char **pzErr /* Write results here */ ){ Rtree *pRtree = (Rtree*)pVtab; int rc; assert( pzErr!=0 && *pzErr==0 ); UNUSED_PARAMETER(zSchema); UNUSED_PARAMETER(zName); UNUSED_PARAMETER(isQuick); rc = rtreeCheckTable(pRtree->db, pRtree->zDb, pRtree->zName, pzErr); if( rc==SQLITE_OK && *pzErr ){ *pzErr = sqlite3_mprintf("In RTree %s.%s:\n%z", pRtree->zDb, pRtree->zName, *pzErr); if( (*pzErr)==0 ) rc = SQLITE_NOMEM; } return rc; } /* ** Usage: ** ** rtreecheck(); ** rtreecheck(, ); ** ** Invoking this SQL function runs an integrity-check on the named rtree ** table. The integrity-check verifies the following: ** ** 1. For each cell in the r-tree structure (%_node table), that: ** ** a) for each dimension, (coord1 <= coord2). ** ** b) unless the cell is on the root node, that the cell is bounded ** by the parent cell on the parent node. ** ** c) for leaf nodes, that there is an entry in the %_rowid ** table corresponding to the cell's rowid value that ** points to the correct node. ** ** d) for cells on non-leaf nodes, that there is an entry in the ** %_parent table mapping from the cell's child node to the ** node that it resides on. ** ** 2. That there are the same number of entries in the %_rowid table ** as there are leaf cells in the r-tree structure, and that there ** is a leaf cell that corresponds to each entry in the %_rowid table. ** ** 3. That there are the same number of entries in the %_parent table ** as there are non-leaf cells in the r-tree structure, and that ** there is a non-leaf cell that corresponds to each entry in the ** %_parent table. */ static void rtreecheck( sqlite3_context *ctx, int nArg, sqlite3_value **apArg ){ if( nArg!=1 && nArg!=2 ){ sqlite3_result_error(ctx, "wrong number of arguments to function rtreecheck()", -1 ); }else{ int rc; char *zReport = 0; const char *zDb = (const char*)sqlite3_value_text(apArg[0]); const char *zTab; if( nArg==1 ){ zTab = zDb; zDb = "main"; }else{ zTab = (const char*)sqlite3_value_text(apArg[1]); } rc = rtreeCheckTable(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport); if( rc==SQLITE_OK ){ sqlite3_result_text(ctx, zReport ? zReport : "ok", -1, SQLITE_TRANSIENT); }else{ sqlite3_result_error_code(ctx, rc); } sqlite3_free(zReport); } } /* Conditionally include the geopoly code */ #ifdef SQLITE_ENABLE_GEOPOLY /************** Include geopoly.c in the middle of rtree.c *******************/ /************** Begin file geopoly.c *****************************************/ /* ** 2018-05-25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file implements an alternative R-Tree virtual table that ** uses polygons to express the boundaries of 2-dimensional objects. ** ** This file is #include-ed onto the end of "rtree.c" so that it has ** access to all of the R-Tree internals. */ /* #include */ /* Enable -DGEOPOLY_ENABLE_DEBUG for debugging facilities */ #ifdef GEOPOLY_ENABLE_DEBUG static int geo_debug = 0; # define GEODEBUG(X) if(geo_debug)printf X #else # define GEODEBUG(X) #endif /* Character class routines */ #ifdef sqlite3Isdigit /* Use the SQLite core versions if this routine is part of the ** SQLite amalgamation */ # define safe_isdigit(x) sqlite3Isdigit(x) # define safe_isalnum(x) sqlite3Isalnum(x) # define safe_isxdigit(x) sqlite3Isxdigit(x) #else /* Use the standard library for separate compilation */ #include /* amalgamator: keep */ # define safe_isdigit(x) isdigit((unsigned char)(x)) # define safe_isalnum(x) isalnum((unsigned char)(x)) # define safe_isxdigit(x) isxdigit((unsigned char)(x)) #endif #ifndef JSON_NULL /* The following stuff repeats things found in json1 */ /* ** Growing our own isspace() routine this way is twice as fast as ** the library isspace() function. */ static const char geopolyIsSpace[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #define fast_isspace(x) (geopolyIsSpace[(unsigned char)x]) #endif /* JSON NULL - back to original code */ /* Compiler and version */ #ifndef GCC_VERSION #if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) #else # define GCC_VERSION 0 #endif #endif #ifndef MSVC_VERSION #if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) # define MSVC_VERSION _MSC_VER #else # define MSVC_VERSION 0 #endif #endif /* Datatype for coordinates */ typedef float GeoCoord; /* ** Internal representation of a polygon. ** ** The polygon consists of a sequence of vertexes. There is a line ** segment between each pair of vertexes, and one final segment from ** the last vertex back to the first. (This differs from the GeoJSON ** standard in which the final vertex is a repeat of the first.) ** ** The polygon follows the right-hand rule. The area to the right of ** each segment is "outside" and the area to the left is "inside". ** ** The on-disk representation consists of a 4-byte header followed by ** the values. The 4-byte header is: ** ** encoding (1 byte) 0=big-endian, 1=little-endian ** nvertex (3 bytes) Number of vertexes as a big-endian integer ** ** Enough space is allocated for 4 coordinates, to work around over-zealous ** warnings coming from some compiler (notably, clang). In reality, the size ** of each GeoPoly memory allocate is adjusted as necessary so that the ** GeoPoly.a[] array at the end is the appropriate size. */ typedef struct GeoPoly GeoPoly; struct GeoPoly { int nVertex; /* Number of vertexes */ unsigned char hdr[4]; /* Header for on-disk representation */ GeoCoord a[8]; /* 2*nVertex values. X (longitude) first, then Y */ }; /* The size of a memory allocation needed for a GeoPoly object sufficient ** to hold N coordinate pairs. */ #define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4)) /* Macros to access coordinates of a GeoPoly. ** We have to use these macros, rather than just say p->a[i] in order ** to silence (incorrect) UBSAN warnings if the array index is too large. */ #define GeoX(P,I) (((GeoCoord*)(P)->a)[(I)*2]) #define GeoY(P,I) (((GeoCoord*)(P)->a)[(I)*2+1]) /* ** State of a parse of a GeoJSON input. */ typedef struct GeoParse GeoParse; struct GeoParse { const unsigned char *z; /* Unparsed input */ int nVertex; /* Number of vertexes in a[] */ int nAlloc; /* Space allocated to a[] */ int nErr; /* Number of errors encountered */ GeoCoord *a; /* Array of vertexes. From sqlite3_malloc64() */ }; /* Do a 4-byte byte swap */ static void geopolySwab32(unsigned char *a){ unsigned char t = a[0]; a[0] = a[3]; a[3] = t; t = a[1]; a[1] = a[2]; a[2] = t; } /* Skip whitespace. Return the next non-whitespace character. */ static char geopolySkipSpace(GeoParse *p){ while( fast_isspace(p->z[0]) ) p->z++; return p->z[0]; } /* Parse out a number. Write the value into *pVal if pVal!=0. ** return non-zero on success and zero if the next token is not a number. */ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ char c = geopolySkipSpace(p); const unsigned char *z = p->z; int j = 0; int seenDP = 0; int seenE = 0; if( c=='-' ){ j = 1; c = z[j]; } if( c=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0; for(;; j++){ c = z[j]; if( safe_isdigit(c) ) continue; if( c=='.' ){ if( z[j-1]=='-' ) return 0; if( seenDP ) return 0; seenDP = 1; continue; } if( c=='e' || c=='E' ){ if( z[j-1]<'0' ) return 0; if( seenE ) return -1; seenDP = seenE = 1; c = z[j+1]; if( c=='+' || c=='-' ){ j++; c = z[j+1]; } if( c<'0' || c>'9' ) return 0; continue; } break; } if( z[j-1]<'0' ) return 0; if( pVal ){ #ifdef SQLITE_AMALGAMATION /* The sqlite3AtoF() routine is much much faster than atof(), if it ** is available */ double r; (void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8); *pVal = r; #else *pVal = (GeoCoord)atof((const char*)p->z); #endif } p->z += j; return 1; } /* ** If the input is a well-formed JSON array of coordinates with at least ** four coordinates and where each coordinate is itself a two-value array, ** then convert the JSON into a GeoPoly object and return a pointer to ** that object. ** ** If any error occurs, return NULL. */ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){ GeoParse s; int rc = SQLITE_OK; memset(&s, 0, sizeof(s)); s.z = z; if( geopolySkipSpace(&s)=='[' ){ s.z++; while( geopolySkipSpace(&s)=='[' ){ int ii = 0; char c; s.z++; if( s.nVertex>=s.nAlloc ){ GeoCoord *aNew; s.nAlloc = s.nAlloc*2 + 16; aNew = sqlite3_realloc64(s.a, s.nAlloc*sizeof(GeoCoord)*2 ); if( aNew==0 ){ rc = SQLITE_NOMEM; s.nErr++; break; } s.a = aNew; } while( geopolyParseNumber(&s, ii<=1 ? &s.a[s.nVertex*2+ii] : 0) ){ ii++; if( ii==2 ) s.nVertex++; c = geopolySkipSpace(&s); s.z++; if( c==',' ) continue; if( c==']' && ii>=2 ) break; s.nErr++; rc = SQLITE_ERROR; goto parse_json_err; } if( geopolySkipSpace(&s)==',' ){ s.z++; continue; } break; } if( geopolySkipSpace(&s)==']' && s.nVertex>=4 && s.a[0]==s.a[s.nVertex*2-2] && s.a[1]==s.a[s.nVertex*2-1] && (s.z++, geopolySkipSpace(&s)==0) ){ GeoPoly *pOut; int x = 1; s.nVertex--; /* Remove the redundant vertex at the end */ pOut = sqlite3_malloc64( GEOPOLY_SZ((sqlite3_int64)s.nVertex) ); x = 1; if( pOut==0 ) goto parse_json_err; pOut->nVertex = s.nVertex; memcpy(pOut->a, s.a, s.nVertex*2*sizeof(GeoCoord)); pOut->hdr[0] = *(unsigned char*)&x; pOut->hdr[1] = (s.nVertex>>16)&0xff; pOut->hdr[2] = (s.nVertex>>8)&0xff; pOut->hdr[3] = s.nVertex&0xff; sqlite3_free(s.a); if( pRc ) *pRc = SQLITE_OK; return pOut; }else{ s.nErr++; rc = SQLITE_ERROR; } } parse_json_err: if( pRc ) *pRc = rc; sqlite3_free(s.a); return 0; } /* ** Given a function parameter, try to interpret it as a polygon, either ** in the binary format or JSON text. Compute a GeoPoly object and ** return a pointer to that object. Or if the input is not a well-formed ** polygon, put an error message in sqlite3_context and return NULL. */ static GeoPoly *geopolyFuncParam( sqlite3_context *pCtx, /* Context for error messages */ sqlite3_value *pVal, /* The value to decode */ int *pRc /* Write error here */ ){ GeoPoly *p = 0; int nByte; testcase( pCtx==0 ); if( sqlite3_value_type(pVal)==SQLITE_BLOB && (nByte = sqlite3_value_bytes(pVal))>=(int)(4+6*sizeof(GeoCoord)) ){ const unsigned char *a = sqlite3_value_blob(pVal); int nVertex; if( a==0 ){ if( pCtx ) sqlite3_result_error_nomem(pCtx); return 0; } nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; if( (a[0]==0 || a[0]==1) && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte ){ p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) ); if( p==0 ){ if( pRc ) *pRc = SQLITE_NOMEM; if( pCtx ) sqlite3_result_error_nomem(pCtx); }else{ int x = 1; p->nVertex = nVertex; memcpy(p->hdr, a, nByte); if( a[0] != *(unsigned char*)&x ){ int ii; for(ii=0; iihdr[0] ^= 1; } } } if( pRc ) *pRc = SQLITE_OK; return p; }else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){ const unsigned char *zJson = sqlite3_value_text(pVal); if( zJson==0 ){ if( pRc ) *pRc = SQLITE_NOMEM; return 0; } return geopolyParseJson(zJson, pRc); }else{ if( pRc ) *pRc = SQLITE_ERROR; return 0; } } /* ** Implementation of the geopoly_blob(X) function. ** ** If the input is a well-formed Geopoly BLOB or JSON string ** then return the BLOB representation of the polygon. Otherwise ** return NULL. */ static void geopolyBlobFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); (void)argc; if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** SQL function: geopoly_json(X) ** ** Interpret X as a polygon and render it as a JSON array ** of coordinates. Or, if X is not a valid polygon, return NULL. */ static void geopolyJsonFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); (void)argc; if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); int i; sqlite3_str_append(x, "[", 1); for(i=0; inVertex; i++){ sqlite3_str_appendf(x, "[%!g,%!g],", GeoX(p,i), GeoY(p,i)); } sqlite3_str_appendf(x, "[%!g,%!g]]", GeoX(p,0), GeoY(p,0)); sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); sqlite3_free(p); } } /* ** SQL function: geopoly_svg(X, ....) ** ** Interpret X as a polygon and render it as a SVG . ** Additional arguments are added as attributes to the . */ static void geopolySvgFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p; if( argc<1 ) return; p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); int i; char cSep = '\''; sqlite3_str_appendf(x, ""); sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); sqlite3_free(p); } } /* ** SQL Function: geopoly_xform(poly, A, B, C, D, E, F) ** ** Transform and/or translate a polygon as follows: ** ** x1 = A*x0 + B*y0 + E ** y1 = C*x0 + D*y0 + F ** ** For a translation: ** ** geopoly_xform(poly, 1, 0, 0, 1, x-offset, y-offset) ** ** Rotate by R around the point (0,0): ** ** geopoly_xform(poly, cos(R), sin(R), -sin(R), cos(R), 0, 0) */ static void geopolyXformFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); double A = sqlite3_value_double(argv[1]); double B = sqlite3_value_double(argv[2]); double C = sqlite3_value_double(argv[3]); double D = sqlite3_value_double(argv[4]); double E = sqlite3_value_double(argv[5]); double F = sqlite3_value_double(argv[6]); GeoCoord x1, y1, x0, y0; int ii; (void)argc; if( p ){ for(ii=0; iinVertex; ii++){ x0 = GeoX(p,ii); y0 = GeoY(p,ii); x1 = (GeoCoord)(A*x0 + B*y0 + E); y1 = (GeoCoord)(C*x0 + D*y0 + F); GeoX(p,ii) = x1; GeoY(p,ii) = y1; } sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** Compute the area enclosed by the polygon. ** ** This routine can also be used to detect polygons that rotate in ** the wrong direction. Polygons are suppose to be counter-clockwise (CCW). ** This routine returns a negative value for clockwise (CW) polygons. */ static double geopolyArea(GeoPoly *p){ double rArea = 0.0; int ii; for(ii=0; iinVertex-1; ii++){ rArea += (GeoX(p,ii) - GeoX(p,ii+1)) /* (x0 - x1) */ * (GeoY(p,ii) + GeoY(p,ii+1)) /* (y0 + y1) */ * 0.5; } rArea += (GeoX(p,ii) - GeoX(p,0)) /* (xN - x0) */ * (GeoY(p,ii) + GeoY(p,0)) /* (yN + y0) */ * 0.5; return rArea; } /* ** Implementation of the geopoly_area(X) function. ** ** If the input is a well-formed Geopoly BLOB then return the area ** enclosed by the polygon. If the polygon circulates clockwise instead ** of counterclockwise (as it should) then return the negative of the ** enclosed area. Otherwise return NULL. */ static void geopolyAreaFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); (void)argc; if( p ){ sqlite3_result_double(context, geopolyArea(p)); sqlite3_free(p); } } /* ** Implementation of the geopoly_ccw(X) function. ** ** If the rotation of polygon X is clockwise (incorrect) instead of ** counter-clockwise (the correct winding order according to RFC7946) ** then reverse the order of the vertexes in polygon X. ** ** In other words, this routine returns a CCW polygon regardless of the ** winding order of its input. ** ** Use this routine to sanitize historical inputs that that sometimes ** contain polygons that wind in the wrong direction. */ static void geopolyCcwFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); (void)argc; if( p ){ if( geopolyArea(p)<0.0 ){ int ii, jj; for(ii=1, jj=p->nVertex-1; iihdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } #define GEOPOLY_PI 3.1415926535897932385 /* Fast approximation for sine(X) for X between -0.5*pi and 2*pi */ static double geopolySine(double r){ assert( r>=-0.5*GEOPOLY_PI && r<=2.0*GEOPOLY_PI ); if( r>=1.5*GEOPOLY_PI ){ r -= 2.0*GEOPOLY_PI; } if( r>=0.5*GEOPOLY_PI ){ return -geopolySine(r-GEOPOLY_PI); }else{ double r2 = r*r; double r3 = r2*r; double r5 = r3*r2; return 0.9996949*r - 0.1656700*r3 + 0.0075134*r5; } } /* ** Function: geopoly_regular(X,Y,R,N) ** ** Construct a simple, convex, regular polygon centered at X, Y ** with circumradius R and with N sides. */ static void geopolyRegularFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ double x = sqlite3_value_double(argv[0]); double y = sqlite3_value_double(argv[1]); double r = sqlite3_value_double(argv[2]); int n = sqlite3_value_int(argv[3]); int i; GeoPoly *p; (void)argc; if( n<3 || r<=0.0 ) return; if( n>1000 ) n = 1000; p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) ); if( p==0 ){ sqlite3_result_error_nomem(context); return; } i = 1; p->hdr[0] = *(unsigned char*)&i; p->hdr[1] = 0; p->hdr[2] = (n>>8)&0xff; p->hdr[3] = n&0xff; for(i=0; ihdr, 4+8*n, SQLITE_TRANSIENT); sqlite3_free(p); } /* ** If pPoly is a polygon, compute its bounding box. Then: ** ** (1) if aCoord!=0 store the bounding box in aCoord, returning NULL ** (2) otherwise, compute a GeoPoly for the bounding box and return the ** new GeoPoly ** ** If pPoly is NULL but aCoord is not NULL, then compute a new GeoPoly from ** the bounding box in aCoord and return a pointer to that GeoPoly. */ static GeoPoly *geopolyBBox( sqlite3_context *context, /* For recording the error */ sqlite3_value *pPoly, /* The polygon */ RtreeCoord *aCoord, /* Results here */ int *pRc /* Error code here */ ){ GeoPoly *pOut = 0; GeoPoly *p; float mnX, mxX, mnY, mxY; if( pPoly==0 && aCoord!=0 ){ p = 0; mnX = aCoord[0].f; mxX = aCoord[1].f; mnY = aCoord[2].f; mxY = aCoord[3].f; goto geopolyBboxFill; }else{ p = geopolyFuncParam(context, pPoly, pRc); } if( p ){ int ii; mnX = mxX = GeoX(p,0); mnY = mxY = GeoY(p,0); for(ii=1; iinVertex; ii++){ double r = GeoX(p,ii); if( rmxX ) mxX = (float)r; r = GeoY(p,ii); if( rmxY ) mxY = (float)r; } if( pRc ) *pRc = SQLITE_OK; if( aCoord==0 ){ geopolyBboxFill: pOut = sqlite3_realloc64(p, GEOPOLY_SZ(4)); if( pOut==0 ){ sqlite3_free(p); if( context ) sqlite3_result_error_nomem(context); if( pRc ) *pRc = SQLITE_NOMEM; return 0; } pOut->nVertex = 4; ii = 1; pOut->hdr[0] = *(unsigned char*)ⅈ pOut->hdr[1] = 0; pOut->hdr[2] = 0; pOut->hdr[3] = 4; GeoX(pOut,0) = mnX; GeoY(pOut,0) = mnY; GeoX(pOut,1) = mxX; GeoY(pOut,1) = mnY; GeoX(pOut,2) = mxX; GeoY(pOut,2) = mxY; GeoX(pOut,3) = mnX; GeoY(pOut,3) = mxY; }else{ sqlite3_free(p); aCoord[0].f = mnX; aCoord[1].f = mxX; aCoord[2].f = mnY; aCoord[3].f = mxY; } }else if( aCoord ){ memset(aCoord, 0, sizeof(RtreeCoord)*4); } return pOut; } /* ** Implementation of the geopoly_bbox(X) SQL function. */ static void geopolyBBoxFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyBBox(context, argv[0], 0, 0); (void)argc; if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** State vector for the geopoly_group_bbox() aggregate function. */ typedef struct GeoBBox GeoBBox; struct GeoBBox { int isInit; RtreeCoord a[4]; }; /* ** Implementation of the geopoly_group_bbox(X) aggregate SQL function. */ static void geopolyBBoxStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ RtreeCoord a[4]; int rc = SQLITE_OK; (void)argc; (void)geopolyBBox(context, argv[0], a, &rc); if( rc==SQLITE_OK ){ GeoBBox *pBBox; pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox)); if( pBBox==0 ) return; if( pBBox->isInit==0 ){ pBBox->isInit = 1; memcpy(pBBox->a, a, sizeof(RtreeCoord)*4); }else{ if( a[0].f < pBBox->a[0].f ) pBBox->a[0] = a[0]; if( a[1].f > pBBox->a[1].f ) pBBox->a[1] = a[1]; if( a[2].f < pBBox->a[2].f ) pBBox->a[2] = a[2]; if( a[3].f > pBBox->a[3].f ) pBBox->a[3] = a[3]; } } } static void geopolyBBoxFinal( sqlite3_context *context ){ GeoPoly *p; GeoBBox *pBBox; pBBox = (GeoBBox*)sqlite3_aggregate_context(context, 0); if( pBBox==0 ) return; p = geopolyBBox(context, 0, pBBox->a, 0); if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). ** Returns: ** ** +2 x0,y0 is on the line segement ** ** +1 x0,y0 is beneath line segment ** ** 0 x0,y0 is not on or beneath the line segment or the line segment ** is vertical and x0,y0 is not on the line segment ** ** The left-most coordinate min(x1,x2) is not considered to be part of ** the line segment for the purposes of this analysis. */ static int pointBeneathLine( double x0, double y0, double x1, double y1, double x2, double y2 ){ double y; if( x0==x1 && y0==y1 ) return 2; if( x1x2 ) return 0; }else if( x1>x2 ){ if( x0<=x2 || x0>x1 ) return 0; }else{ /* Vertical line segment */ if( x0!=x1 ) return 0; if( y0y1 && y0>y2 ) return 0; return 2; } y = y1 + (y2-y1)*(x0-x1)/(x2-x1); if( y0==y ) return 2; if( y0nVertex-1; ii++){ v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), GeoX(p1,ii+1),GeoY(p1,ii+1)); if( v==2 ) break; cnt += v; } if( v!=2 ){ v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), GeoX(p1,0), GeoY(p1,0)); } if( v==2 ){ sqlite3_result_int(context, 1); }else if( ((v+cnt)&1)==0 ){ sqlite3_result_int(context, 0); }else{ sqlite3_result_int(context, 2); } sqlite3_free(p1); } /* Forward declaration */ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2); /* ** SQL function: geopoly_within(P1,P2) ** ** Return +2 if P1 and P2 are the same polygon ** Return +1 if P2 is contained within P1 ** Return 0 if any part of P2 is on the outside of P1 ** */ static void geopolyWithinFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); (void)argc; if( p1 && p2 ){ int x = geopolyOverlap(p1, p2); if( x<0 ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0); } } sqlite3_free(p1); sqlite3_free(p2); } /* Objects used by the overlap algorihm. */ typedef struct GeoEvent GeoEvent; typedef struct GeoSegment GeoSegment; typedef struct GeoOverlap GeoOverlap; struct GeoEvent { double x; /* X coordinate at which event occurs */ int eType; /* 0 for ADD, 1 for REMOVE */ GeoSegment *pSeg; /* The segment to be added or removed */ GeoEvent *pNext; /* Next event in the sorted list */ }; struct GeoSegment { double C, B; /* y = C*x + B */ double y; /* Current y value */ float y0; /* Initial y value */ unsigned char side; /* 1 for p1, 2 for p2 */ unsigned int idx; /* Which segment within the side */ GeoSegment *pNext; /* Next segment in a list sorted by y */ }; struct GeoOverlap { GeoEvent *aEvent; /* Array of all events */ GeoSegment *aSegment; /* Array of all segments */ int nEvent; /* Number of events */ int nSegment; /* Number of segments */ }; /* ** Add a single segment and its associated events. */ static void geopolyAddOneSegment( GeoOverlap *p, GeoCoord x0, GeoCoord y0, GeoCoord x1, GeoCoord y1, unsigned char side, unsigned int idx ){ GeoSegment *pSeg; GeoEvent *pEvent; if( x0==x1 ) return; /* Ignore vertical segments */ if( x0>x1 ){ GeoCoord t = x0; x0 = x1; x1 = t; t = y0; y0 = y1; y1 = t; } pSeg = p->aSegment + p->nSegment; p->nSegment++; pSeg->C = (y1-y0)/(x1-x0); pSeg->B = y1 - x1*pSeg->C; pSeg->y0 = y0; pSeg->side = side; pSeg->idx = idx; pEvent = p->aEvent + p->nEvent; p->nEvent++; pEvent->x = x0; pEvent->eType = 0; pEvent->pSeg = pSeg; pEvent = p->aEvent + p->nEvent; p->nEvent++; pEvent->x = x1; pEvent->eType = 1; pEvent->pSeg = pSeg; } /* ** Insert all segments and events for polygon pPoly. */ static void geopolyAddSegments( GeoOverlap *p, /* Add segments to this Overlap object */ GeoPoly *pPoly, /* Take all segments from this polygon */ unsigned char side /* The side of pPoly */ ){ unsigned int i; GeoCoord *x; for(i=0; i<(unsigned)pPoly->nVertex-1; i++){ x = &GeoX(pPoly,i); geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i); } x = &GeoX(pPoly,i); geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i); } /* ** Merge two lists of sorted events by X coordinate */ static GeoEvent *geopolyEventMerge(GeoEvent *pLeft, GeoEvent *pRight){ GeoEvent head, *pLast; head.pNext = 0; pLast = &head; while( pRight && pLeft ){ if( pRight->x <= pLeft->x ){ pLast->pNext = pRight; pLast = pRight; pRight = pRight->pNext; }else{ pLast->pNext = pLeft; pLast = pLeft; pLeft = pLeft->pNext; } } pLast->pNext = pRight ? pRight : pLeft; return head.pNext; } /* ** Sort an array of nEvent event objects into a list. */ static GeoEvent *geopolySortEventsByX(GeoEvent *aEvent, int nEvent){ int mx = 0; int i, j; GeoEvent *p; GeoEvent *a[50]; for(i=0; ipNext = 0; for(j=0; j=mx ) mx = j+1; } p = 0; for(i=0; iy - pLeft->y; if( r==0.0 ) r = pRight->C - pLeft->C; if( r<0.0 ){ pLast->pNext = pRight; pLast = pRight; pRight = pRight->pNext; }else{ pLast->pNext = pLeft; pLast = pLeft; pLeft = pLeft->pNext; } } pLast->pNext = pRight ? pRight : pLeft; return head.pNext; } /* ** Sort a list of GeoSegments in order of increasing Y and in the event of ** a tie, increasing C (slope). */ static GeoSegment *geopolySortSegmentsByYAndC(GeoSegment *pList){ int mx = 0; int i; GeoSegment *p; GeoSegment *a[50]; while( pList ){ p = pList; pList = pList->pNext; p->pNext = 0; for(i=0; i=mx ) mx = i+1; } p = 0; for(i=0; inVertex + p2->nVertex + 2; GeoOverlap *p; sqlite3_int64 nByte; GeoEvent *pThisEvent; double rX; int rc = 0; int needSort = 0; GeoSegment *pActive = 0; GeoSegment *pSeg; unsigned char aOverlap[4]; nByte = sizeof(GeoEvent)*nVertex*2 + sizeof(GeoSegment)*nVertex + sizeof(GeoOverlap); p = sqlite3_malloc64( nByte ); if( p==0 ) return -1; p->aEvent = (GeoEvent*)&p[1]; p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2]; p->nEvent = p->nSegment = 0; geopolyAddSegments(p, p1, 1); geopolyAddSegments(p, p2, 2); pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent); rX = pThisEvent && pThisEvent->x==0.0 ? -1.0 : 0.0; memset(aOverlap, 0, sizeof(aOverlap)); while( pThisEvent ){ if( pThisEvent->x!=rX ){ GeoSegment *pPrev = 0; int iMask = 0; GEODEBUG(("Distinct X: %g\n", pThisEvent->x)); rX = pThisEvent->x; if( needSort ){ GEODEBUG(("SORT\n")); pActive = geopolySortSegmentsByYAndC(pActive); needSort = 0; } for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ if( pPrev ){ if( pPrev->y!=pSeg->y ){ GEODEBUG(("MASK: %d\n", iMask)); aOverlap[iMask] = 1; } } iMask ^= pSeg->side; pPrev = pSeg; } pPrev = 0; for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ double y = pSeg->C*rX + pSeg->B; GEODEBUG(("Segment %d.%d %g->%g\n", pSeg->side, pSeg->idx, pSeg->y, y)); pSeg->y = y; if( pPrev ){ if( pPrev->y>pSeg->y && pPrev->side!=pSeg->side ){ rc = 1; GEODEBUG(("Crossing: %d.%d and %d.%d\n", pPrev->side, pPrev->idx, pSeg->side, pSeg->idx)); goto geopolyOverlapDone; }else if( pPrev->y!=pSeg->y ){ GEODEBUG(("MASK: %d\n", iMask)); aOverlap[iMask] = 1; } } iMask ^= pSeg->side; pPrev = pSeg; } } GEODEBUG(("%s %d.%d C=%g B=%g\n", pThisEvent->eType ? "RM " : "ADD", pThisEvent->pSeg->side, pThisEvent->pSeg->idx, pThisEvent->pSeg->C, pThisEvent->pSeg->B)); if( pThisEvent->eType==0 ){ /* Add a segment */ pSeg = pThisEvent->pSeg; pSeg->y = pSeg->y0; pSeg->pNext = pActive; pActive = pSeg; needSort = 1; }else{ /* Remove a segment */ if( pActive==pThisEvent->pSeg ){ pActive = ALWAYS(pActive) ? pActive->pNext : 0; }else{ for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ if( pSeg->pNext==pThisEvent->pSeg ){ pSeg->pNext = ALWAYS(pSeg->pNext) ? pSeg->pNext->pNext : 0; break; } } } } pThisEvent = pThisEvent->pNext; } if( aOverlap[3]==0 ){ rc = 0; }else if( aOverlap[1]!=0 && aOverlap[2]==0 ){ rc = 3; }else if( aOverlap[1]==0 && aOverlap[2]!=0 ){ rc = 2; }else if( aOverlap[1]==0 && aOverlap[2]==0 ){ rc = 4; }else{ rc = 1; } geopolyOverlapDone: sqlite3_free(p); return rc; } /* ** SQL function: geopoly_overlap(P1,P2) ** ** Determine whether or not P1 and P2 overlap. Return value: ** ** 0 The two polygons are disjoint ** 1 They overlap ** 2 P1 is completely contained within P2 ** 3 P2 is completely contained within P1 ** 4 P1 and P2 are the same polygon ** NULL Either P1 or P2 or both are not valid polygons */ static void geopolyOverlapFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); (void)argc; if( p1 && p2 ){ int x = geopolyOverlap(p1, p2); if( x<0 ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_int(context, x); } } sqlite3_free(p1); sqlite3_free(p2); } /* ** Enable or disable debugging output */ static void geopolyDebugFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ (void)context; (void)argc; #ifdef GEOPOLY_ENABLE_DEBUG geo_debug = sqlite3_value_int(argv[0]); #else (void)argv; #endif } /* ** This function is the implementation of both the xConnect and xCreate ** methods of the geopoly virtual table. ** ** argv[0] -> module name ** argv[1] -> database name ** argv[2] -> table name ** argv[...] -> column names... */ static int geopolyInit( sqlite3 *db, /* Database connection */ void *pAux, /* One of the RTREE_COORD_* constants */ int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */ sqlite3_vtab **ppVtab, /* OUT: New virtual table */ char **pzErr, /* OUT: Error message, if any */ int isCreate /* True for xCreate, false for xConnect */ ){ int rc = SQLITE_OK; Rtree *pRtree; sqlite3_int64 nDb; /* Length of string argv[1] */ sqlite3_int64 nName; /* Length of string argv[2] */ sqlite3_str *pSql; char *zSql; int ii; (void)pAux; sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); /* Allocate the sqlite3_vtab structure */ nDb = strlen(argv[1]); nName = strlen(argv[2]); pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8); if( !pRtree ){ return SQLITE_NOMEM; } memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8); pRtree->nBusy = 1; pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; pRtree->zName = &pRtree->zDb[nDb+1]; pRtree->zNodeName = &pRtree->zName[nName+1]; pRtree->eCoordType = RTREE_COORD_REAL32; pRtree->nDim = 2; pRtree->nDim2 = 4; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); memcpy(pRtree->zNodeName, argv[2], nName); memcpy(&pRtree->zNodeName[nName], "_node", 6); /* Create/Connect to the underlying relational database schema. If ** that is successful, call sqlite3_declare_vtab() to configure ** the r-tree table schema. */ pSql = sqlite3_str_new(db); sqlite3_str_appendf(pSql, "CREATE TABLE x(_shape"); pRtree->nAux = 1; /* Add one for _shape */ pRtree->nAuxNotNull = 1; /* The _shape column is always not-null */ for(ii=3; iinAux++; sqlite3_str_appendf(pSql, ",%s", argv[ii]); } sqlite3_str_appendf(pSql, ");"); zSql = sqlite3_str_finish(pSql); if( !zSql ){ rc = SQLITE_NOMEM; }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } sqlite3_free(zSql); if( rc ) goto geopolyInit_fail; pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; /* Figure out the node size to use. */ rc = getNodeSize(db, pRtree, isCreate, pzErr); if( rc ) goto geopolyInit_fail; rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate); if( rc ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); goto geopolyInit_fail; } *ppVtab = (sqlite3_vtab *)pRtree; return SQLITE_OK; geopolyInit_fail: if( rc==SQLITE_OK ) rc = SQLITE_ERROR; assert( *ppVtab==0 ); assert( pRtree->nBusy==1 ); rtreeRelease(pRtree); return rc; } /* ** GEOPOLY virtual table module xCreate method. */ static int geopolyCreate( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 1); } /* ** GEOPOLY virtual table module xConnect method. */ static int geopolyConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 0); } /* ** GEOPOLY virtual table module xFilter method. ** ** Query plans: ** ** 1 rowid lookup ** 2 search for objects overlapping the same bounding box ** that contains polygon argv[0] ** 3 search for objects overlapping the same bounding box ** that contains polygon argv[0] ** 4 full table scan */ static int geopolyFilter( sqlite3_vtab_cursor *pVtabCursor, /* The cursor to initialize */ int idxNum, /* Query plan */ const char *idxStr, /* Not Used */ int argc, sqlite3_value **argv /* Parameters to the query plan */ ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int rc = SQLITE_OK; int iCell = 0; (void)idxStr; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ resetCursor(pCsr); pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ RtreeSearchPoint *p; /* Search point for the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); i64 iNode = 0; rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); if( rc==SQLITE_OK && pLeaf!=0 ){ p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); assert( p!=0 ); /* Always returns pCsr->sPoint */ pCsr->aNode[0] = pLeaf; p->id = iNode; p->eWithin = PARTLY_WITHIN; rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); p->iCell = (u8)iCell; RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); }else{ pCsr->atEOF = 1; } }else{ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array ** with the configured constraints. */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); if( rc==SQLITE_OK && idxNum<=3 ){ RtreeCoord bbox[4]; RtreeConstraint *p; assert( argc==1 ); assert( argv[0]!=0 ); geopolyBBox(0, argv[0], bbox, &rc); if( rc ){ goto geopoly_filter_end; } pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4); pCsr->nConstraint = 4; if( p==0 ){ rc = SQLITE_NOMEM; }else{ memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*4); memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); if( idxNum==2 ){ /* Overlap query */ p->op = 'B'; p->iCoord = 0; p->u.rValue = bbox[1].f; p++; p->op = 'D'; p->iCoord = 1; p->u.rValue = bbox[0].f; p++; p->op = 'B'; p->iCoord = 2; p->u.rValue = bbox[3].f; p++; p->op = 'D'; p->iCoord = 3; p->u.rValue = bbox[2].f; }else{ /* Within query */ p->op = 'D'; p->iCoord = 0; p->u.rValue = bbox[0].f; p++; p->op = 'B'; p->iCoord = 1; p->u.rValue = bbox[1].f; p++; p->op = 'D'; p->iCoord = 2; p->u.rValue = bbox[2].f; p++; p->op = 'B'; p->iCoord = 3; p->u.rValue = bbox[3].f; } } } if( rc==SQLITE_OK ){ RtreeSearchPoint *pNew; pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); if( pNew==0 ){ rc = SQLITE_NOMEM; goto geopoly_filter_end; } pNew->id = 1; pNew->iCell = 0; pNew->eWithin = PARTLY_WITHIN; assert( pCsr->bPoint==1 ); pCsr->aNode[0] = pRoot; pRoot = 0; RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); rc = rtreeStepToLeaf(pCsr); } } geopoly_filter_end: nodeRelease(pRtree, pRoot); rtreeRelease(pRtree); return rc; } /* ** Rtree virtual table module xBestIndex method. There are three ** table scan strategies to choose from (in order from most to ** least desirable): ** ** idxNum idxStr Strategy ** ------------------------------------------------ ** 1 "rowid" Direct lookup by rowid. ** 2 "rtree" R-tree overlap query using geopoly_overlap() ** 3 "rtree" R-tree within query using geopoly_within() ** 4 "fullscan" full-table scan. ** ------------------------------------------------ */ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int ii; int iRowidTerm = -1; int iFuncTerm = -1; int idxNum = 0; (void)tab; for(ii=0; iinConstraint; ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; if( !p->usable ) continue; if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ iRowidTerm = ii; break; } if( p->iColumn==0 && p->op>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ /* p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION for geopoly_overlap() ** p->op==(SQLITE_INDEX_CONTRAINT_FUNCTION+1) for geopoly_within(). ** See geopolyFindFunction() */ iFuncTerm = ii; idxNum = p->op - SQLITE_INDEX_CONSTRAINT_FUNCTION + 2; } } if( iRowidTerm>=0 ){ pIdxInfo->idxNum = 1; pIdxInfo->idxStr = "rowid"; pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1; pIdxInfo->estimatedCost = 30.0; pIdxInfo->estimatedRows = 1; pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; return SQLITE_OK; } if( iFuncTerm>=0 ){ pIdxInfo->idxNum = idxNum; pIdxInfo->idxStr = "rtree"; pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1; pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0; pIdxInfo->estimatedCost = 300.0; pIdxInfo->estimatedRows = 10; return SQLITE_OK; } pIdxInfo->idxNum = 4; pIdxInfo->idxStr = "fullscan"; pIdxInfo->estimatedCost = 3000000.0; pIdxInfo->estimatedRows = 100000; return SQLITE_OK; } /* ** GEOPOLY virtual table module xColumn method. */ static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ Rtree *pRtree = (Rtree *)cur->pVtab; RtreeCursor *pCsr = (RtreeCursor *)cur; RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc ) return rc; if( p==0 ) return SQLITE_OK; if( i==0 && sqlite3_vtab_nochange(ctx) ) return SQLITE_OK; if( i<=pRtree->nAux ){ if( !pCsr->bAuxValid ){ if( pCsr->pReadAux==0 ){ rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0, &pCsr->pReadAux, 0); if( rc ) return rc; } sqlite3_bind_int64(pCsr->pReadAux, 1, nodeGetRowid(pRtree, pNode, p->iCell)); rc = sqlite3_step(pCsr->pReadAux); if( rc==SQLITE_ROW ){ pCsr->bAuxValid = 1; }else{ sqlite3_reset(pCsr->pReadAux); if( rc==SQLITE_DONE ) rc = SQLITE_OK; return rc; } } sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i+2)); } return SQLITE_OK; } /* ** The xUpdate method for GEOPOLY module virtual tables. ** ** For DELETE: ** ** argv[0] = the rowid to be deleted ** ** For INSERT: ** ** argv[0] = SQL NULL ** argv[1] = rowid to insert, or an SQL NULL to select automatically ** argv[2] = _shape column ** argv[3] = first application-defined column.... ** ** For UPDATE: ** ** argv[0] = rowid to modify. Never NULL ** argv[1] = rowid after the change. Never NULL ** argv[2] = new value for _shape ** argv[3] = new value for first application-defined column.... */ static int geopolyUpdate( sqlite3_vtab *pVtab, int nData, sqlite3_value **aData, sqlite_int64 *pRowid ){ Rtree *pRtree = (Rtree *)pVtab; int rc = SQLITE_OK; RtreeCell cell; /* New cell to insert if nData>1 */ i64 oldRowid; /* The old rowid */ int oldRowidValid; /* True if oldRowid is valid */ i64 newRowid; /* The new rowid */ int newRowidValid; /* True if newRowid is valid */ int coordChange = 0; /* Change in coordinates */ if( pRtree->nNodeRef ){ /* Unable to write to the btree while another cursor is reading from it, ** since the write might do a rebalance which would disrupt the read ** cursor. */ return SQLITE_LOCKED_VTAB; } rtreeReference(pRtree); assert(nData>=1); oldRowidValid = sqlite3_value_type(aData[0])!=SQLITE_NULL;; oldRowid = oldRowidValid ? sqlite3_value_int64(aData[0]) : 0; newRowidValid = nData>1 && sqlite3_value_type(aData[1])!=SQLITE_NULL; newRowid = newRowidValid ? sqlite3_value_int64(aData[1]) : 0; cell.iRowid = newRowid; if( nData>1 /* not a DELETE */ && (!oldRowidValid /* INSERT */ || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */ || oldRowid!=newRowid) /* Rowid change */ ){ assert( aData[2]!=0 ); geopolyBBox(0, aData[2], cell.aCoord, &rc); if( rc ){ if( rc==SQLITE_ERROR ){ pVtab->zErrMsg = sqlite3_mprintf("_shape does not contain a valid polygon"); } goto geopoly_update_end; } coordChange = 1; /* If a rowid value was supplied, check if it is already present in ** the table. If so, the constraint has failed. */ if( newRowidValid && (!oldRowidValid || oldRowid!=newRowid) ){ int steprc; sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); steprc = sqlite3_step(pRtree->pReadRowid); rc = sqlite3_reset(pRtree->pReadRowid); if( SQLITE_ROW==steprc ){ if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ rc = rtreeDeleteRowid(pRtree, cell.iRowid); }else{ rc = rtreeConstraintError(pRtree, 0); } } } } /* If aData[0] is not an SQL NULL value, it is the rowid of a ** record to delete from the r-tree table. The following block does ** just that. */ if( rc==SQLITE_OK && (nData==1 || (coordChange && oldRowidValid)) ){ rc = rtreeDeleteRowid(pRtree, oldRowid); } /* If the aData[] array contains more than one element, elements ** (aData[2]..aData[argc-1]) contain a new record to insert into ** the r-tree structure. */ if( rc==SQLITE_OK && nData>1 && coordChange ){ /* Insert the new record into the r-tree */ RtreeNode *pLeaf = 0; if( !newRowidValid ){ rc = rtreeNewRowid(pRtree, &cell.iRowid); } *pRowid = cell.iRowid; if( rc==SQLITE_OK ){ rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); } if( rc==SQLITE_OK ){ int rc2; rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ rc = rc2; } } } /* Change the data */ if( rc==SQLITE_OK && nData>1 ){ sqlite3_stmt *pUp = pRtree->pWriteAux; int jj; int nChange = 0; sqlite3_bind_int64(pUp, 1, cell.iRowid); assert( pRtree->nAux>=1 ); if( sqlite3_value_nochange(aData[2]) ){ sqlite3_bind_null(pUp, 2); }else{ GeoPoly *p = 0; if( sqlite3_value_type(aData[2])==SQLITE_TEXT && (p = geopolyFuncParam(0, aData[2], &rc))!=0 && rc==SQLITE_OK ){ sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); }else{ sqlite3_bind_value(pUp, 2, aData[2]); } sqlite3_free(p); nChange = 1; } for(jj=1; jjxDestructor ) pInfo->xDestructor(pInfo->pContext); sqlite3_free(p); } /* ** This routine frees the BLOB that is returned by geomCallback(). */ static void rtreeMatchArgFree(void *pArg){ int i; RtreeMatchArg *p = (RtreeMatchArg*)pArg; for(i=0; inParam; i++){ sqlite3_value_free(p->apSqlParam[i]); } sqlite3_free(p); } /* ** Each call to sqlite3_rtree_geometry_callback() or ** sqlite3_rtree_query_callback() creates an ordinary SQLite ** scalar function that is implemented by this routine. ** ** All this function does is construct an RtreeMatchArg object that ** contains the geometry-checking callback routines and a list of ** parameters to this function, then return that RtreeMatchArg object ** as a BLOB. ** ** The R-Tree MATCH operator will read the returned BLOB, deserialize ** the RtreeMatchArg object, and use the RtreeMatchArg object to figure ** out which elements of the R-Tree should be returned by the query. */ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx); RtreeMatchArg *pBlob; sqlite3_int64 nBlob; int memErr = 0; nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue) + nArg*sizeof(sqlite3_value*); pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob); if( !pBlob ){ sqlite3_result_error_nomem(ctx); }else{ int i; pBlob->iSize = nBlob; pBlob->cb = pGeomCtx[0]; pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg]; pBlob->nParam = nArg; for(i=0; iapSqlParam[i] = sqlite3_value_dup(aArg[i]); if( pBlob->apSqlParam[i]==0 ) memErr = 1; #ifdef SQLITE_RTREE_INT_ONLY pBlob->aParam[i] = sqlite3_value_int64(aArg[i]); #else pBlob->aParam[i] = sqlite3_value_double(aArg[i]); #endif } if( memErr ){ sqlite3_result_error_nomem(ctx); rtreeMatchArgFree(pBlob); }else{ sqlite3_result_pointer(ctx, pBlob, "RtreeMatchArg", rtreeMatchArgFree); } } } /* ** Register a new geometry function for use with the r-tree MATCH operator. */ SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, /* Register SQL function on this connection */ const char *zGeom, /* Name of the new SQL function */ int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*), /* Callback */ void *pContext /* Extra data associated with the callback */ ){ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ /* Allocate and populate the context object. */ pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); if( !pGeomCtx ) return SQLITE_NOMEM; pGeomCtx->xGeom = xGeom; pGeomCtx->xQueryFunc = 0; pGeomCtx->xDestructor = 0; pGeomCtx->pContext = pContext; return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY, (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback ); } /* ** Register a new 2nd-generation geometry function for use with the ** r-tree MATCH operator. */ SQLITE_API int sqlite3_rtree_query_callback( sqlite3 *db, /* Register SQL function on this connection */ const char *zQueryFunc, /* Name of new SQL function */ int (*xQueryFunc)(sqlite3_rtree_query_info*), /* Callback */ void *pContext, /* Extra data passed into the callback */ void (*xDestructor)(void*) /* Destructor for the extra data */ ){ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ /* Allocate and populate the context object. */ pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); if( !pGeomCtx ){ if( xDestructor ) xDestructor(pContext); return SQLITE_NOMEM; } pGeomCtx->xGeom = 0; pGeomCtx->xQueryFunc = xQueryFunc; pGeomCtx->xDestructor = xDestructor; pGeomCtx->pContext = pContext; return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY, (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback ); } #if !SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif SQLITE_API int sqlite3_rtree_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi) return sqlite3RtreeInit(db); } #endif #endif /************** End of rtree.c ***********************************************/ /************** Begin file icu.c *********************************************/ /* ** 2007 May 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ ** ** This file implements an integration between the ICU library ** ("International Components for Unicode", an open-source library ** for handling unicode data) and SQLite. The integration uses ** ICU to provide the following to SQLite: ** ** * An implementation of the SQL regexp() function (and hence REGEXP ** operator) using the ICU uregex_XX() APIs. ** ** * Implementations of the SQL scalar upper() and lower() functions ** for case mapping. ** ** * Integration of ICU and SQLite collation sequences. ** ** * An implementation of the LIKE operator that uses ICU to ** provide case-independent matching. */ #if !defined(SQLITE_CORE) \ || defined(SQLITE_ENABLE_ICU) \ || defined(SQLITE_ENABLE_ICU_COLLATIONS) /* Include ICU headers */ #include #include #include #include /* #include */ #ifndef SQLITE_CORE /* #include "sqlite3ext.h" */ SQLITE_EXTENSION_INIT1 #else /* #include "sqlite3.h" */ #endif /* ** This function is called when an ICU function called from within ** the implementation of an SQL scalar function returns an error. ** ** The scalar function context passed as the first argument is ** loaded with an error message based on the following two args. */ static void icuFunctionError( sqlite3_context *pCtx, /* SQLite scalar function context */ const char *zName, /* Name of ICU function that failed */ UErrorCode e /* Error code returned by ICU function */ ){ char zBuf[128]; sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); zBuf[127] = '\0'; sqlite3_result_error(pCtx, zBuf, -1); } #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) /* ** Maximum length (in bytes) of the pattern in a LIKE or GLOB ** operator. */ #ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH # define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 #endif /* ** Version of sqlite3_free() that is always a function, never a macro. */ static void xFree(void *p){ sqlite3_free(p); } /* ** This lookup table is used to help decode the first byte of ** a multi-byte UTF8 character. It is copied here from SQLite source ** code file utf8.c. */ static const unsigned char icuUtf8Trans1[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, }; #define SQLITE_ICU_READ_UTF8(zIn, c) \ c = *(zIn++); \ if( c>=0xc0 ){ \ c = icuUtf8Trans1[c-0xc0]; \ while( (*zIn & 0xc0)==0x80 ){ \ c = (c<<6) + (0x3f & *(zIn++)); \ } \ } #define SQLITE_ICU_SKIP_UTF8(zIn) \ assert( *zIn ); \ if( *(zIn++)>=0xc0 ){ \ while( (*zIn & 0xc0)==0x80 ){zIn++;} \ } /* ** Compare two UTF-8 strings for equality where the first string is ** a "LIKE" expression. Return true (1) if they are the same and ** false (0) if they are different. */ static int icuLikeCompare( const uint8_t *zPattern, /* LIKE pattern */ const uint8_t *zString, /* The UTF-8 string to compare against */ const UChar32 uEsc /* The escape character */ ){ static const uint32_t MATCH_ONE = (uint32_t)'_'; static const uint32_t MATCH_ALL = (uint32_t)'%'; int prevEscape = 0; /* True if the previous character was uEsc */ while( 1 ){ /* Read (and consume) the next character from the input pattern. */ uint32_t uPattern; SQLITE_ICU_READ_UTF8(zPattern, uPattern); if( uPattern==0 ) break; /* There are now 4 possibilities: ** ** 1. uPattern is an unescaped match-all character "%", ** 2. uPattern is an unescaped match-one character "_", ** 3. uPattern is an unescaped escape character, or ** 4. uPattern is to be handled as an ordinary character */ if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ /* Case 1. */ uint8_t c; /* Skip any MATCH_ALL or MATCH_ONE characters that follow a ** MATCH_ALL. For each MATCH_ONE, skip one character in the ** test string. */ while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ if( c==MATCH_ONE ){ if( *zString==0 ) return 0; SQLITE_ICU_SKIP_UTF8(zString); } zPattern++; } if( *zPattern==0 ) return 1; while( *zString ){ if( icuLikeCompare(zPattern, zString, uEsc) ){ return 1; } SQLITE_ICU_SKIP_UTF8(zString); } return 0; }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ /* Case 2. */ if( *zString==0 ) return 0; SQLITE_ICU_SKIP_UTF8(zString); }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ /* Case 3. */ prevEscape = 1; }else{ /* Case 4. */ uint32_t uString; SQLITE_ICU_READ_UTF8(zString, uString); uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); if( uString!=uPattern ){ return 0; } prevEscape = 0; } } return *zString==0; } /* ** Implementation of the like() SQL function. This function implements ** the build-in LIKE operator. The first argument to the function is the ** pattern and the second argument is the string. So, the SQL statements: ** ** A LIKE B ** ** is implemented as like(B, A). If there is an escape character E, ** ** A LIKE B ESCAPE E ** ** is mapped to like(B, A, E). */ static void icuLikeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zA = sqlite3_value_text(argv[0]); const unsigned char *zB = sqlite3_value_text(argv[1]); UChar32 uEsc = 0; /* Limit the length of the LIKE or GLOB pattern to avoid problems ** of deep recursion and N*N behavior in patternCompare(). */ if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); return; } if( argc==3 ){ /* The escape character string must consist of a single UTF-8 character. ** Otherwise, return an error. */ int nE= sqlite3_value_bytes(argv[2]); const unsigned char *zE = sqlite3_value_text(argv[2]); int i = 0; if( zE==0 ) return; U8_NEXT(zE, i, nE, uEsc); if( i!=nE){ sqlite3_result_error(context, "ESCAPE expression must be a single character", -1); return; } } if( zA && zB ){ sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); } } /* ** Function to delete compiled regexp objects. Registered as ** a destructor function with sqlite3_set_auxdata(). */ static void icuRegexpDelete(void *p){ URegularExpression *pExpr = (URegularExpression *)p; uregex_close(pExpr); } /* ** Implementation of SQLite REGEXP operator. This scalar function takes ** two arguments. The first is a regular expression pattern to compile ** the second is a string to match against that pattern. If either ** argument is an SQL NULL, then NULL Is returned. Otherwise, the result ** is 1 if the string matches the pattern, or 0 otherwise. ** ** SQLite maps the regexp() function to the regexp() operator such ** that the following two are equivalent: ** ** zString REGEXP zPattern ** regexp(zPattern, zString) ** ** Uses the following ICU regexp APIs: ** ** uregex_open() ** uregex_matches() ** uregex_close() */ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ UErrorCode status = U_ZERO_ERROR; URegularExpression *pExpr; UBool res; const UChar *zString = sqlite3_value_text16(apArg[1]); (void)nArg; /* Unused parameter */ /* If the left hand side of the regexp operator is NULL, ** then the result is also NULL. */ if( !zString ){ return; } pExpr = sqlite3_get_auxdata(p, 0); if( !pExpr ){ const UChar *zPattern = sqlite3_value_text16(apArg[0]); if( !zPattern ){ return; } pExpr = uregex_open(zPattern, -1, 0, 0, &status); if( U_SUCCESS(status) ){ sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); pExpr = sqlite3_get_auxdata(p, 0); } if( !pExpr ){ icuFunctionError(p, "uregex_open", status); return; } } /* Configure the text that the regular expression operates on. */ uregex_setText(pExpr, zString, -1, &status); if( !U_SUCCESS(status) ){ icuFunctionError(p, "uregex_setText", status); return; } /* Attempt the match */ res = uregex_matches(pExpr, 0, &status); if( !U_SUCCESS(status) ){ icuFunctionError(p, "uregex_matches", status); return; } /* Set the text that the regular expression operates on to a NULL ** pointer. This is not really necessary, but it is tidier than ** leaving the regular expression object configured with an invalid ** pointer after this function returns. */ uregex_setText(pExpr, 0, 0, &status); /* Return 1 or 0. */ sqlite3_result_int(p, res ? 1 : 0); } /* ** Implementations of scalar functions for case mapping - upper() and ** lower(). Function upper() converts its input to upper-case (ABC). ** Function lower() converts to lower-case (abc). ** ** ICU provides two types of case mapping, "general" case mapping and ** "language specific". Refer to ICU documentation for the differences ** between the two. ** ** To utilise "general" case mapping, the upper() or lower() scalar ** functions are invoked with one argument: ** ** upper('ABC') -> 'abc' ** lower('abc') -> 'ABC' ** ** To access ICU "language specific" case mapping, upper() or lower() ** should be invoked with two arguments. The second argument is the name ** of the locale to use. Passing an empty string ("") or SQL NULL value ** as the second argument is the same as invoking the 1 argument version ** of upper() or lower(). ** ** lower('I', 'en_us') -> 'i' ** lower('I', 'tr_tr') -> '\u131' (small dotless i) ** ** http://www.icu-project.org/userguide/posix.html#case_mappings */ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ const UChar *zInput; /* Pointer to input string */ UChar *zOutput = 0; /* Pointer to output buffer */ int nInput; /* Size of utf-16 input string in bytes */ int nOut; /* Size of output buffer in bytes */ int cnt; int bToUpper; /* True for toupper(), false for tolower() */ UErrorCode status; const char *zLocale = 0; assert(nArg==1 || nArg==2); bToUpper = (sqlite3_user_data(p)!=0); if( nArg==2 ){ zLocale = (const char *)sqlite3_value_text(apArg[1]); } zInput = sqlite3_value_text16(apArg[0]); if( !zInput ){ return; } nOut = nInput = sqlite3_value_bytes16(apArg[0]); if( nOut==0 ){ sqlite3_result_text16(p, "", 0, SQLITE_STATIC); return; } for(cnt=0; cnt<2; cnt++){ UChar *zNew = sqlite3_realloc(zOutput, nOut); if( zNew==0 ){ sqlite3_free(zOutput); sqlite3_result_error_nomem(p); return; } zOutput = zNew; status = U_ZERO_ERROR; if( bToUpper ){ nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); }else{ nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); } if( U_SUCCESS(status) ){ sqlite3_result_text16(p, zOutput, nOut, xFree); }else if( status==U_BUFFER_OVERFLOW_ERROR ){ assert( cnt==0 ); continue; }else{ icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); } return; } assert( 0 ); /* Unreachable */ } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ /* ** Collation sequence destructor function. The pCtx argument points to ** a UCollator structure previously allocated using ucol_open(). */ static void icuCollationDel(void *pCtx){ UCollator *p = (UCollator *)pCtx; ucol_close(p); } /* ** Collation sequence comparison function. The pCtx argument points to ** a UCollator structure previously allocated using ucol_open(). */ static int icuCollationColl( void *pCtx, int nLeft, const void *zLeft, int nRight, const void *zRight ){ UCollationResult res; UCollator *p = (UCollator *)pCtx; res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); switch( res ){ case UCOL_LESS: return -1; case UCOL_GREATER: return +1; case UCOL_EQUAL: return 0; } assert(!"Unexpected return value from ucol_strcoll()"); return 0; } /* ** Implementation of the scalar function icu_load_collation(). ** ** This scalar function is used to add ICU collation based collation ** types to an SQLite database connection. It is intended to be called ** as follows: ** ** SELECT icu_load_collation(, ); ** ** Where is a string containing an ICU locale identifier (i.e. ** "en_AU", "tr_TR" etc.) and is the name of the ** collation sequence to create. */ static void icuLoadCollation( sqlite3_context *p, int nArg, sqlite3_value **apArg ){ sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); UErrorCode status = U_ZERO_ERROR; const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ const char *zName; /* SQL Collation sequence name (eg. "japanese") */ UCollator *pUCollator; /* ICU library collation object */ int rc; /* Return code from sqlite3_create_collation_x() */ assert(nArg==2); (void)nArg; /* Unused parameter */ zLocale = (const char *)sqlite3_value_text(apArg[0]); zName = (const char *)sqlite3_value_text(apArg[1]); if( !zLocale || !zName ){ return; } pUCollator = ucol_open(zLocale, &status); if( !U_SUCCESS(status) ){ icuFunctionError(p, "ucol_open", status); return; } assert(p); rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, icuCollationColl, icuCollationDel ); if( rc!=SQLITE_OK ){ ucol_close(pUCollator); sqlite3_result_error(p, "Error registering collation function", -1); } } /* ** Register the ICU extension functions with database db. */ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ # define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) static const struct IcuScalar { const char *zName; /* Function name */ unsigned char nArg; /* Number of arguments */ unsigned int enc; /* Optimal text encoding */ unsigned char iContext; /* sqlite3_user_data() context */ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } scalars[] = { {"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation}, #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) {"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc}, {"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ }; int rc = SQLITE_OK; int i; for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ const struct IcuScalar *p = &scalars[i]; rc = sqlite3_create_function( db, p->zName, p->nArg, p->enc, p->iContext ? (void*)db : (void*)0, p->xFunc, 0, 0 ); } return rc; } #if !SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif SQLITE_API int sqlite3_icu_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi) return sqlite3IcuInit(db); } #endif #endif /************** End of icu.c *************************************************/ /************** Begin file fts3_icu.c ****************************************/ /* ** 2007 June 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file implements a tokenizer for fts3 based on the ICU library. */ /* #include "fts3Int.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #ifdef SQLITE_ENABLE_ICU /* #include */ /* #include */ /* #include "fts3_tokenizer.h" */ #include /* #include */ /* #include */ #include typedef struct IcuTokenizer IcuTokenizer; typedef struct IcuCursor IcuCursor; struct IcuTokenizer { sqlite3_tokenizer base; char *zLocale; }; struct IcuCursor { sqlite3_tokenizer_cursor base; UBreakIterator *pIter; /* ICU break-iterator object */ int nChar; /* Number of UChar elements in pInput */ UChar *aChar; /* Copy of input using utf-16 encoding */ int *aOffset; /* Offsets of each character in utf-8 input */ int nBuffer; char *zBuffer; int iToken; }; /* ** Create a new tokenizer instance. */ static int icuCreate( int argc, /* Number of entries in argv[] */ const char * const *argv, /* Tokenizer creation arguments */ sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ ){ IcuTokenizer *p; int n = 0; if( argc>0 ){ n = strlen(argv[0])+1; } p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); if( !p ){ return SQLITE_NOMEM; } memset(p, 0, sizeof(IcuTokenizer)); if( n ){ p->zLocale = (char *)&p[1]; memcpy(p->zLocale, argv[0], n); } *ppTokenizer = (sqlite3_tokenizer *)p; return SQLITE_OK; } /* ** Destroy a tokenizer */ static int icuDestroy(sqlite3_tokenizer *pTokenizer){ IcuTokenizer *p = (IcuTokenizer *)pTokenizer; sqlite3_free(p); return SQLITE_OK; } /* ** Prepare to begin tokenizing a particular string. The input ** string to be tokenized is pInput[0..nBytes-1]. A cursor ** used to incrementally tokenize this string is returned in ** *ppCursor. */ static int icuOpen( sqlite3_tokenizer *pTokenizer, /* The tokenizer */ const char *zInput, /* Input string */ int nInput, /* Length of zInput in bytes */ sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ ){ IcuTokenizer *p = (IcuTokenizer *)pTokenizer; IcuCursor *pCsr; const int32_t opt = U_FOLD_CASE_DEFAULT; UErrorCode status = U_ZERO_ERROR; int nChar; UChar32 c; int iInput = 0; int iOut = 0; *ppCursor = 0; if( zInput==0 ){ nInput = 0; zInput = ""; }else if( nInput<0 ){ nInput = strlen(zInput); } nChar = nInput+1; pCsr = (IcuCursor *)sqlite3_malloc64( sizeof(IcuCursor) + /* IcuCursor */ ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ ); if( !pCsr ){ return SQLITE_NOMEM; } memset(pCsr, 0, sizeof(IcuCursor)); pCsr->aChar = (UChar *)&pCsr[1]; pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; pCsr->aOffset[iOut] = iInput; U8_NEXT(zInput, iInput, nInput, c); while( c>0 ){ int isError = 0; c = u_foldCase(c, opt); U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); if( isError ){ sqlite3_free(pCsr); return SQLITE_ERROR; } pCsr->aOffset[iOut] = iInput; if( iInputpIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); if( !U_SUCCESS(status) ){ sqlite3_free(pCsr); return SQLITE_ERROR; } pCsr->nChar = iOut; ubrk_first(pCsr->pIter); *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; return SQLITE_OK; } /* ** Close a tokenization cursor previously opened by a call to icuOpen(). */ static int icuClose(sqlite3_tokenizer_cursor *pCursor){ IcuCursor *pCsr = (IcuCursor *)pCursor; ubrk_close(pCsr->pIter); sqlite3_free(pCsr->zBuffer); sqlite3_free(pCsr); return SQLITE_OK; } /* ** Extract the next token from a tokenization cursor. */ static int icuNext( sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ const char **ppToken, /* OUT: *ppToken is the token text */ int *pnBytes, /* OUT: Number of bytes in token */ int *piStartOffset, /* OUT: Starting offset of token */ int *piEndOffset, /* OUT: Ending offset of token */ int *piPosition /* OUT: Position integer of token */ ){ IcuCursor *pCsr = (IcuCursor *)pCursor; int iStart = 0; int iEnd = 0; int nByte = 0; while( iStart==iEnd ){ UChar32 c; iStart = ubrk_current(pCsr->pIter); iEnd = ubrk_next(pCsr->pIter); if( iEnd==UBRK_DONE ){ return SQLITE_DONE; } while( iStartaChar, iWhite, pCsr->nChar, c); if( u_isspace(c) ){ iStart = iWhite; }else{ break; } } assert(iStart<=iEnd); } do { UErrorCode status = U_ZERO_ERROR; if( nByte ){ char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); if( !zNew ){ return SQLITE_NOMEM; } pCsr->zBuffer = zNew; pCsr->nBuffer = nByte; } u_strToUTF8( pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ &status /* Output success/failure */ ); } while( nByte>pCsr->nBuffer ); *ppToken = pCsr->zBuffer; *pnBytes = nByte; *piStartOffset = pCsr->aOffset[iStart]; *piEndOffset = pCsr->aOffset[iEnd]; *piPosition = pCsr->iToken++; return SQLITE_OK; } /* ** The set of routines that implement the simple tokenizer */ static const sqlite3_tokenizer_module icuTokenizerModule = { 0, /* iVersion */ icuCreate, /* xCreate */ icuDestroy, /* xCreate */ icuOpen, /* xOpen */ icuClose, /* xClose */ icuNext, /* xNext */ 0, /* xLanguageid */ }; /* ** Set *ppModule to point at the implementation of the ICU tokenizer. */ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( sqlite3_tokenizer_module const**ppModule ){ *ppModule = &icuTokenizerModule; } #endif /* defined(SQLITE_ENABLE_ICU) */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ /************** End of fts3_icu.c ********************************************/ /************** Begin file sqlite3rbu.c **************************************/ /* ** 2014 August 30 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** ** OVERVIEW ** ** The RBU extension requires that the RBU update be packaged as an ** SQLite database. The tables it expects to find are described in ** sqlite3rbu.h. Essentially, for each table xyz in the target database ** that the user wishes to write to, a corresponding data_xyz table is ** created in the RBU database and populated with one row for each row to ** update, insert or delete from the target table. ** ** The update proceeds in three stages: ** ** 1) The database is updated. The modified database pages are written ** to a *-oal file. A *-oal file is just like a *-wal file, except ** that it is named "-oal" instead of "-wal". ** Because regular SQLite clients do not look for file named ** "-oal", they go on using the original database in ** rollback mode while the *-oal file is being generated. ** ** During this stage RBU does not update the database by writing ** directly to the target tables. Instead it creates "imposter" ** tables using the SQLITE_TESTCTRL_IMPOSTER interface that it uses ** to update each b-tree individually. All updates required by each ** b-tree are completed before moving on to the next, and all ** updates are done in sorted key order. ** ** 2) The "-oal" file is moved to the equivalent "-wal" ** location using a call to rename(2). Before doing this the RBU ** module takes an EXCLUSIVE lock on the database file, ensuring ** that there are no other active readers. ** ** Once the EXCLUSIVE lock is released, any other database readers ** detect the new *-wal file and read the database in wal mode. At ** this point they see the new version of the database - including ** the updates made as part of the RBU update. ** ** 3) The new *-wal file is checkpointed. This proceeds in the same way ** as a regular database checkpoint, except that a single frame is ** checkpointed each time sqlite3rbu_step() is called. If the RBU ** handle is closed before the entire *-wal file is checkpointed, ** the checkpoint progress is saved in the RBU database and the ** checkpoint can be resumed by another RBU client at some point in ** the future. ** ** POTENTIAL PROBLEMS ** ** The rename() call might not be portable. And RBU is not currently ** syncing the directory after renaming the file. ** ** When state is saved, any commit to the *-oal file and the commit to ** the RBU update database are not atomic. So if the power fails at the ** wrong moment they might get out of sync. As the main database will be ** committed before the RBU update database this will likely either just ** pass unnoticed, or result in SQLITE_CONSTRAINT errors (due to UNIQUE ** constraint violations). ** ** If some client does modify the target database mid RBU update, or some ** other error occurs, the RBU extension will keep throwing errors. It's ** not really clear how to get out of this state. The system could just ** by delete the RBU update database and *-oal file and have the device ** download the update again and start over. ** ** At present, for an UPDATE, both the new.* and old.* records are ** collected in the rbu_xyz table. And for both UPDATEs and DELETEs all ** fields are collected. This means we're probably writing a lot more ** data to disk when saving the state of an ongoing update to the RBU ** update database than is strictly necessary. ** */ /* #include */ /* #include */ /* #include */ /* #include "sqlite3.h" */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) /************** Include sqlite3rbu.h in the middle of sqlite3rbu.c ***********/ /************** Begin file sqlite3rbu.h **************************************/ /* ** 2014 August 30 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains the public interface for the RBU extension. */ /* ** SUMMARY ** ** Writing a transaction containing a large number of operations on ** b-tree indexes that are collectively larger than the available cache ** memory can be very inefficient. ** ** The problem is that in order to update a b-tree, the leaf page (at least) ** containing the entry being inserted or deleted must be modified. If the ** working set of leaves is larger than the available cache memory, then a ** single leaf that is modified more than once as part of the transaction ** may be loaded from or written to the persistent media multiple times. ** Additionally, because the index updates are likely to be applied in ** random order, access to pages within the database is also likely to be in ** random order, which is itself quite inefficient. ** ** One way to improve the situation is to sort the operations on each index ** by index key before applying them to the b-tree. This leads to an IO ** pattern that resembles a single linear scan through the index b-tree, ** and all but guarantees each modified leaf page is loaded and stored ** exactly once. SQLite uses this trick to improve the performance of ** CREATE INDEX commands. This extension allows it to be used to improve ** the performance of large transactions on existing databases. ** ** Additionally, this extension allows the work involved in writing the ** large transaction to be broken down into sub-transactions performed ** sequentially by separate processes. This is useful if the system cannot ** guarantee that a single update process will run for long enough to apply ** the entire update, for example because the update is being applied on a ** mobile device that is frequently rebooted. Even after the writer process ** has committed one or more sub-transactions, other database clients continue ** to read from the original database snapshot. In other words, partially ** applied transactions are not visible to other clients. ** ** "RBU" stands for "Resumable Bulk Update". As in a large database update ** transmitted via a wireless network to a mobile device. A transaction ** applied using this extension is hence refered to as an "RBU update". ** ** ** LIMITATIONS ** ** An "RBU update" transaction is subject to the following limitations: ** ** * The transaction must consist of INSERT, UPDATE and DELETE operations ** only. ** ** * INSERT statements may not use any default values. ** ** * UPDATE and DELETE statements must identify their target rows by ** non-NULL PRIMARY KEY values. Rows with NULL values stored in PRIMARY ** KEY fields may not be updated or deleted. If the table being written ** has no PRIMARY KEY, affected rows must be identified by rowid. ** ** * UPDATE statements may not modify PRIMARY KEY columns. ** ** * No triggers will be fired. ** ** * No foreign key violations are detected or reported. ** ** * CHECK constraints are not enforced. ** ** * No constraint handling mode except for "OR ROLLBACK" is supported. ** ** ** PREPARATION ** ** An "RBU update" is stored as a separate SQLite database. A database ** containing an RBU update is an "RBU database". For each table in the ** target database to be updated, the RBU database should contain a table ** named "data_" containing the same set of columns as the ** target table, and one more - "rbu_control". The data_% table should ** have no PRIMARY KEY or UNIQUE constraints, but each column should have ** the same type as the corresponding column in the target database. ** The "rbu_control" column should have no type at all. For example, if ** the target database contains: ** ** CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c UNIQUE); ** ** Then the RBU database should contain: ** ** CREATE TABLE data_t1(a INTEGER, b TEXT, c, rbu_control); ** ** The order of the columns in the data_% table does not matter. ** ** Instead of a regular table, the RBU database may also contain virtual ** tables or views named using the data_ naming scheme. ** ** Instead of the plain data_ naming scheme, RBU database tables ** may also be named data_, where is any sequence ** of zero or more numeric characters (0-9). This can be significant because ** tables within the RBU database are always processed in order sorted by ** name. By judicious selection of the portion of the names ** of the RBU tables the user can therefore control the order in which they ** are processed. This can be useful, for example, to ensure that "external ** content" FTS4 tables are updated before their underlying content tables. ** ** If the target database table is a virtual table or a table that has no ** PRIMARY KEY declaration, the data_% table must also contain a column ** named "rbu_rowid". This column is mapped to the table's implicit primary ** key column - "rowid". Virtual tables for which the "rowid" column does ** not function like a primary key value cannot be updated using RBU. For ** example, if the target db contains either of the following: ** ** CREATE VIRTUAL TABLE x1 USING fts3(a, b); ** CREATE TABLE x1(a, b) ** ** then the RBU database should contain: ** ** CREATE TABLE data_x1(a, b, rbu_rowid, rbu_control); ** ** All non-hidden columns (i.e. all columns matched by "SELECT *") of the ** target table must be present in the input table. For virtual tables, ** hidden columns are optional - they are updated by RBU if present in ** the input table, or not otherwise. For example, to write to an fts4 ** table with a hidden languageid column such as: ** ** CREATE VIRTUAL TABLE ft1 USING fts4(a, b, languageid='langid'); ** ** Either of the following input table schemas may be used: ** ** CREATE TABLE data_ft1(a, b, langid, rbu_rowid, rbu_control); ** CREATE TABLE data_ft1(a, b, rbu_rowid, rbu_control); ** ** For each row to INSERT into the target database as part of the RBU ** update, the corresponding data_% table should contain a single record ** with the "rbu_control" column set to contain integer value 0. The ** other columns should be set to the values that make up the new record ** to insert. ** ** If the target database table has an INTEGER PRIMARY KEY, it is not ** possible to insert a NULL value into the IPK column. Attempting to ** do so results in an SQLITE_MISMATCH error. ** ** For each row to DELETE from the target database as part of the RBU ** update, the corresponding data_% table should contain a single record ** with the "rbu_control" column set to contain integer value 1. The ** real primary key values of the row to delete should be stored in the ** corresponding columns of the data_% table. The values stored in the ** other columns are not used. ** ** For each row to UPDATE from the target database as part of the RBU ** update, the corresponding data_% table should contain a single record ** with the "rbu_control" column set to contain a value of type text. ** The real primary key values identifying the row to update should be ** stored in the corresponding columns of the data_% table row, as should ** the new values of all columns being update. The text value in the ** "rbu_control" column must contain the same number of characters as ** there are columns in the target database table, and must consist entirely ** of 'x' and '.' characters (or in some special cases 'd' - see below). For ** each column that is being updated, the corresponding character is set to ** 'x'. For those that remain as they are, the corresponding character of the ** rbu_control value should be set to '.'. For example, given the tables ** above, the update statement: ** ** UPDATE t1 SET c = 'usa' WHERE a = 4; ** ** is represented by the data_t1 row created by: ** ** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..x'); ** ** Instead of an 'x' character, characters of the rbu_control value specified ** for UPDATEs may also be set to 'd'. In this case, instead of updating the ** target table with the value stored in the corresponding data_% column, the ** user-defined SQL function "rbu_delta()" is invoked and the result stored in ** the target table column. rbu_delta() is invoked with two arguments - the ** original value currently stored in the target table column and the ** value specified in the data_xxx table. ** ** For example, this row: ** ** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..d'); ** ** is similar to an UPDATE statement such as: ** ** UPDATE t1 SET c = rbu_delta(c, 'usa') WHERE a = 4; ** ** Finally, if an 'f' character appears in place of a 'd' or 's' in an ** ota_control string, the contents of the data_xxx table column is assumed ** to be a "fossil delta" - a patch to be applied to a blob value in the ** format used by the fossil source-code management system. In this case ** the existing value within the target database table must be of type BLOB. ** It is replaced by the result of applying the specified fossil delta to ** itself. ** ** If the target database table is a virtual table or a table with no PRIMARY ** KEY, the rbu_control value should not include a character corresponding ** to the rbu_rowid value. For example, this: ** ** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control) ** VALUES(NULL, 'usa', 12, '.x'); ** ** causes a result similar to: ** ** UPDATE ft1 SET b = 'usa' WHERE rowid = 12; ** ** The data_xxx tables themselves should have no PRIMARY KEY declarations. ** However, RBU is more efficient if reading the rows in from each data_xxx ** table in "rowid" order is roughly the same as reading them sorted by ** the PRIMARY KEY of the corresponding target database table. In other ** words, rows should be sorted using the destination table PRIMARY KEY ** fields before they are inserted into the data_xxx tables. ** ** USAGE ** ** The API declared below allows an application to apply an RBU update ** stored on disk to an existing target database. Essentially, the ** application: ** ** 1) Opens an RBU handle using the sqlite3rbu_open() function. ** ** 2) Registers any required virtual table modules with the database ** handle returned by sqlite3rbu_db(). Also, if required, register ** the rbu_delta() implementation. ** ** 3) Calls the sqlite3rbu_step() function one or more times on ** the new handle. Each call to sqlite3rbu_step() performs a single ** b-tree operation, so thousands of calls may be required to apply ** a complete update. ** ** 4) Calls sqlite3rbu_close() to close the RBU update handle. If ** sqlite3rbu_step() has been called enough times to completely ** apply the update to the target database, then the RBU database ** is marked as fully applied. Otherwise, the state of the RBU ** update application is saved in the RBU database for later ** resumption. ** ** See comments below for more detail on APIs. ** ** If an update is only partially applied to the target database by the ** time sqlite3rbu_close() is called, various state information is saved ** within the RBU database. This allows subsequent processes to automatically ** resume the RBU update from where it left off. ** ** To remove all RBU extension state information, returning an RBU database ** to its original contents, it is sufficient to drop all tables that begin ** with the prefix "rbu_" ** ** DATABASE LOCKING ** ** An RBU update may not be applied to a database in WAL mode. Attempting ** to do so is an error (SQLITE_ERROR). ** ** While an RBU handle is open, a SHARED lock may be held on the target ** database file. This means it is possible for other clients to read the ** database, but not to write it. ** ** If an RBU update is started and then suspended before it is completed, ** then an external client writes to the database, then attempting to resume ** the suspended RBU update is also an error (SQLITE_BUSY). */ #ifndef _SQLITE3RBU_H #define _SQLITE3RBU_H /* #include "sqlite3.h" ** Required for error code definitions ** */ #if 0 extern "C" { #endif typedef struct sqlite3rbu sqlite3rbu; /* ** Open an RBU handle. ** ** Argument zTarget is the path to the target database. Argument zRbu is ** the path to the RBU database. Each call to this function must be matched ** by a call to sqlite3rbu_close(). When opening the databases, RBU passes ** the SQLITE_CONFIG_URI flag to sqlite3_open_v2(). So if either zTarget ** or zRbu begin with "file:", it will be interpreted as an SQLite ** database URI, not a regular file name. ** ** If the zState argument is passed a NULL value, the RBU extension stores ** the current state of the update (how many rows have been updated, which ** indexes are yet to be updated etc.) within the RBU database itself. This ** can be convenient, as it means that the RBU application does not need to ** organize removing a separate state file after the update is concluded. ** Or, if zState is non-NULL, it must be a path to a database file in which ** the RBU extension can store the state of the update. ** ** When resuming an RBU update, the zState argument must be passed the same ** value as when the RBU update was started. ** ** Once the RBU update is finished, the RBU extension does not ** automatically remove any zState database file, even if it created it. ** ** By default, RBU uses the default VFS to access the files on disk. To ** use a VFS other than the default, an SQLite "file:" URI containing a ** "vfs=..." option may be passed as the zTarget option. ** ** IMPORTANT NOTE FOR ZIPVFS USERS: The RBU extension works with all of ** SQLite's built-in VFSs, including the multiplexor VFS. However it does ** not work out of the box with zipvfs. Refer to the comment describing ** the zipvfs_create_vfs() API below for details on using RBU with zipvfs. */ SQLITE_API sqlite3rbu *sqlite3rbu_open( const char *zTarget, const char *zRbu, const char *zState ); /* ** Open an RBU handle to perform an RBU vacuum on database file zTarget. ** An RBU vacuum is similar to SQLite's built-in VACUUM command, except ** that it can be suspended and resumed like an RBU update. ** ** The second argument to this function identifies a database in which ** to store the state of the RBU vacuum operation if it is suspended. The ** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum ** operation, the state database should either not exist or be empty ** (contain no tables). If an RBU vacuum is suspended by calling ** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has ** returned SQLITE_DONE, the vacuum state is stored in the state database. ** The vacuum can be resumed by calling this function to open a new RBU ** handle specifying the same target and state databases. ** ** If the second argument passed to this function is NULL, then the ** name of the state database is "-vacuum", where ** is the name of the target database file. In this case, on UNIX, if the ** state database is not already present in the file-system, it is created ** with the same permissions as the target db is made. ** ** With an RBU vacuum, it is an SQLITE_MISUSE error if the name of the ** state database ends with "-vactmp". This name is reserved for internal ** use. ** ** This function does not delete the state database after an RBU vacuum ** is completed, even if it created it. However, if the call to ** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents ** of the state tables within the state database are zeroed. This way, ** the next call to sqlite3rbu_vacuum() opens a handle that starts a ** new RBU vacuum operation. ** ** As with sqlite3rbu_open(), Zipvfs users should rever to the comment ** describing the sqlite3rbu_create_vfs() API function below for ** a description of the complications associated with using RBU with ** zipvfs databases. */ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( const char *zTarget, const char *zState ); /* ** Configure a limit for the amount of temp space that may be used by ** the RBU handle passed as the first argument. The new limit is specified ** in bytes by the second parameter. If it is positive, the limit is updated. ** If the second parameter to this function is passed zero, then the limit ** is removed entirely. If the second parameter is negative, the limit is ** not modified (this is useful for querying the current limit). ** ** In all cases the returned value is the current limit in bytes (zero ** indicates unlimited). ** ** If the temp space limit is exceeded during operation, an SQLITE_FULL ** error is returned. */ SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64); /* ** Return the current amount of temp file space, in bytes, currently used by ** the RBU handle passed as the only argument. */ SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*); /* ** Internally, each RBU connection uses a separate SQLite database ** connection to access the target and rbu update databases. This ** API allows the application direct access to these database handles. ** ** The first argument passed to this function must be a valid, open, RBU ** handle. The second argument should be passed zero to access the target ** database handle, or non-zero to access the rbu update database handle. ** Accessing the underlying database handles may be useful in the ** following scenarios: ** ** * If any target tables are virtual tables, it may be necessary to ** call sqlite3_create_module() on the target database handle to ** register the required virtual table implementations. ** ** * If the data_xxx tables in the RBU source database are virtual ** tables, the application may need to call sqlite3_create_module() on ** the rbu update db handle to any required virtual table ** implementations. ** ** * If the application uses the "rbu_delta()" feature described above, ** it must use sqlite3_create_function() or similar to register the ** rbu_delta() implementation with the target database handle. ** ** If an error has occurred, either while opening or stepping the RBU object, ** this function may return NULL. The error code and message may be collected ** when sqlite3rbu_close() is called. ** ** Database handles returned by this function remain valid until the next ** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db(). */ SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu); /* ** Do some work towards applying the RBU update to the target db. ** ** Return SQLITE_DONE if the update has been completely applied, or ** SQLITE_OK if no error occurs but there remains work to do to apply ** the RBU update. If an error does occur, some other error code is ** returned. ** ** Once a call to sqlite3rbu_step() has returned a value other than ** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops ** that immediately return the same value. */ SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu); /* ** Force RBU to save its state to disk. ** ** If a power failure or application crash occurs during an update, following ** system recovery RBU may resume the update from the point at which the state ** was last saved. In other words, from the most recent successful call to ** sqlite3rbu_close() or this function. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); /* ** Close an RBU handle. ** ** If the RBU update has been completely applied, mark the RBU database ** as fully applied. Otherwise, assuming no error has occurred, save the ** current state of the RBU update appliation to the RBU database. ** ** If an error has already occurred as part of an sqlite3rbu_step() ** or sqlite3rbu_open() call, or if one occurs within this function, an ** SQLite error code is returned. Additionally, if pzErrmsg is not NULL, ** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted ** English language error message. It is the responsibility of the caller to ** eventually free any such buffer using sqlite3_free(). ** ** Otherwise, if no error occurs, this function returns SQLITE_OK if the ** update has been partially applied, or SQLITE_DONE if it has been ** completely applied. */ SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg); /* ** Return the total number of key-value operations (inserts, deletes or ** updates) that have been performed on the target database since the ** current RBU update was started. */ SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu); /* ** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100) ** progress indications for the two stages of an RBU update. This API may ** be useful for driving GUI progress indicators and similar. ** ** An RBU update is divided into two stages: ** ** * Stage 1, in which changes are accumulated in an oal/wal file, and ** * Stage 2, in which the contents of the wal file are copied into the ** main database. ** ** The update is visible to non-RBU clients during stage 2. During stage 1 ** non-RBU reader clients may see the original database. ** ** If this API is called during stage 2 of the update, output variable ** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo) ** to a value between 0 and 10000 to indicate the permyriadage progress of ** stage 2. A value of 5000 indicates that stage 2 is half finished, ** 9000 indicates that it is 90% finished, and so on. ** ** If this API is called during stage 1 of the update, output variable ** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The ** value to which (*pnOne) is set depends on whether or not the RBU ** database contains an "rbu_count" table. The rbu_count table, if it ** exists, must contain the same columns as the following: ** ** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID; ** ** There must be one row in the table for each source (data_xxx) table within ** the RBU database. The 'tbl' column should contain the name of the source ** table. The 'cnt' column should contain the number of rows within the ** source table. ** ** If the rbu_count table is present and populated correctly and this ** API is called during stage 1, the *pnOne output variable is set to the ** permyriadage progress of the same stage. If the rbu_count table does ** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count ** table exists but is not correctly populated, the value of the *pnOne ** output variable during stage 1 is undefined. */ SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo); /* ** Obtain an indication as to the current stage of an RBU update or vacuum. ** This function always returns one of the SQLITE_RBU_STATE_XXX constants ** defined in this file. Return values should be interpreted as follows: ** ** SQLITE_RBU_STATE_OAL: ** RBU is currently building a *-oal file. The next call to sqlite3rbu_step() ** may either add further data to the *-oal file, or compute data that will ** be added by a subsequent call. ** ** SQLITE_RBU_STATE_MOVE: ** RBU has finished building the *-oal file. The next call to sqlite3rbu_step() ** will move the *-oal file to the equivalent *-wal path. If the current ** operation is an RBU update, then the updated version of the database ** file will become visible to ordinary SQLite clients following the next ** call to sqlite3rbu_step(). ** ** SQLITE_RBU_STATE_CHECKPOINT: ** RBU is currently performing an incremental checkpoint. The next call to ** sqlite3rbu_step() will copy a page of data from the *-wal file into ** the target database file. ** ** SQLITE_RBU_STATE_DONE: ** The RBU operation has finished. Any subsequent calls to sqlite3rbu_step() ** will immediately return SQLITE_DONE. ** ** SQLITE_RBU_STATE_ERROR: ** An error has occurred. Any subsequent calls to sqlite3rbu_step() will ** immediately return the SQLite error code associated with the error. */ #define SQLITE_RBU_STATE_OAL 1 #define SQLITE_RBU_STATE_MOVE 2 #define SQLITE_RBU_STATE_CHECKPOINT 3 #define SQLITE_RBU_STATE_DONE 4 #define SQLITE_RBU_STATE_ERROR 5 SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu); /* ** As part of applying an RBU update or performing an RBU vacuum operation, ** the system must at one point move the *-oal file to the equivalent *-wal ** path. Normally, it does this by invoking POSIX function rename(2) directly. ** Except on WINCE platforms, where it uses win32 API MoveFileW(). This ** function may be used to register a callback that the RBU module will invoke ** instead of one of these APIs. ** ** If a callback is registered with an RBU handle, it invokes it instead ** of rename(2) when it needs to move a file within the file-system. The ** first argument passed to the xRename() callback is a copy of the second ** argument (pArg) passed to this function. The second is the full path ** to the file to move and the third the full path to which it should be ** moved. The callback function should return SQLITE_OK to indicate ** success. If an error occurs, it should return an SQLite error code. ** In this case the RBU operation will be abandoned and the error returned ** to the RBU user. ** ** Passing a NULL pointer in place of the xRename argument to this function ** restores the default behaviour. */ SQLITE_API void sqlite3rbu_rename_handler( sqlite3rbu *pRbu, void *pArg, int (*xRename)(void *pArg, const char *zOld, const char *zNew) ); /* ** Create an RBU VFS named zName that accesses the underlying file-system ** via existing VFS zParent. Or, if the zParent parameter is passed NULL, ** then the new RBU VFS uses the default system VFS to access the file-system. ** The new object is registered as a non-default VFS with SQLite before ** returning. ** ** Part of the RBU implementation uses a custom VFS object. Usually, this ** object is created and deleted automatically by RBU. ** ** The exception is for applications that also use zipvfs. In this case, ** the custom VFS must be explicitly created by the user before the RBU ** handle is opened. The RBU VFS should be installed so that the zipvfs ** VFS uses the RBU VFS, which in turn uses any other VFS layers in use ** (for example multiplexor) to access the file-system. For example, ** to assemble an RBU enabled VFS stack that uses both zipvfs and ** multiplexor (error checking omitted): ** ** // Create a VFS named "multiplex" (not the default). ** sqlite3_multiplex_initialize(0, 0); ** ** // Create an rbu VFS named "rbu" that uses multiplexor. If the ** // second argument were replaced with NULL, the "rbu" VFS would ** // access the file-system via the system default VFS, bypassing the ** // multiplexor. ** sqlite3rbu_create_vfs("rbu", "multiplex"); ** ** // Create a zipvfs VFS named "zipvfs" that uses rbu. ** zipvfs_create_vfs_v3("zipvfs", "rbu", 0, xCompressorAlgorithmDetector); ** ** // Make zipvfs the default VFS. ** sqlite3_vfs_register(sqlite3_vfs_find("zipvfs"), 1); ** ** Because the default VFS created above includes a RBU functionality, it ** may be used by RBU clients. Attempting to use RBU with a zipvfs VFS stack ** that does not include the RBU layer results in an error. ** ** The overhead of adding the "rbu" VFS to the system is negligible for ** non-RBU users. There is no harm in an application accessing the ** file-system via "rbu" all the time, even if it only uses RBU functionality ** occasionally. */ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent); /* ** Deregister and destroy an RBU vfs created by an earlier call to ** sqlite3rbu_create_vfs(). ** ** VFS objects are not reference counted. If a VFS object is destroyed ** before all database handles that use it have been closed, the results ** are undefined. */ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName); #if 0 } /* end of the 'extern "C"' block */ #endif #endif /* _SQLITE3RBU_H */ /************** End of sqlite3rbu.h ******************************************/ /************** Continuing where we left off in sqlite3rbu.c *****************/ #if defined(_WIN32_WCE) /* #include "windows.h" */ #endif /* Maximum number of prepared UPDATE statements held by this module */ #define SQLITE_RBU_UPDATE_CACHESIZE 16 /* Delta checksums disabled by default. Compile with -DRBU_ENABLE_DELTA_CKSUM ** to enable checksum verification. */ #ifndef RBU_ENABLE_DELTA_CKSUM # define RBU_ENABLE_DELTA_CKSUM 0 #endif /* ** Swap two objects of type TYPE. */ #if !defined(SQLITE_AMALGAMATION) # define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} #endif /* ** Name of the URI option that causes RBU to take an exclusive lock as ** part of the incremental checkpoint operation. */ #define RBU_EXCLUSIVE_CHECKPOINT "rbu_exclusive_checkpoint" /* ** The rbu_state table is used to save the state of a partially applied ** update so that it can be resumed later. The table consists of integer ** keys mapped to values as follows: ** ** RBU_STATE_STAGE: ** May be set to integer values 1, 2, 4 or 5. As follows: ** 1: the *-rbu file is currently under construction. ** 2: the *-rbu file has been constructed, but not yet moved ** to the *-wal path. ** 4: the checkpoint is underway. ** 5: the rbu update has been checkpointed. ** ** RBU_STATE_TBL: ** Only valid if STAGE==1. The target database name of the table ** currently being written. ** ** RBU_STATE_IDX: ** Only valid if STAGE==1. The target database name of the index ** currently being written, or NULL if the main table is currently being ** updated. ** ** RBU_STATE_ROW: ** Only valid if STAGE==1. Number of rows already processed for the current ** table/index. ** ** RBU_STATE_PROGRESS: ** Trbul number of sqlite3rbu_step() calls made so far as part of this ** rbu update. ** ** RBU_STATE_CKPT: ** Valid if STAGE==4. The 64-bit checksum associated with the wal-index ** header created by recovering the *-wal file. This is used to detect ** cases when another client appends frames to the *-wal file in the ** middle of an incremental checkpoint (an incremental checkpoint cannot ** be continued if this happens). ** ** RBU_STATE_COOKIE: ** Valid if STAGE==1. The current change-counter cookie value in the ** target db file. ** ** RBU_STATE_OALSZ: ** Valid if STAGE==1. The size in bytes of the *-oal file. ** ** RBU_STATE_DATATBL: ** Only valid if STAGE==1. The RBU database name of the table ** currently being read. */ #define RBU_STATE_STAGE 1 #define RBU_STATE_TBL 2 #define RBU_STATE_IDX 3 #define RBU_STATE_ROW 4 #define RBU_STATE_PROGRESS 5 #define RBU_STATE_CKPT 6 #define RBU_STATE_COOKIE 7 #define RBU_STATE_OALSZ 8 #define RBU_STATE_PHASEONESTEP 9 #define RBU_STATE_DATATBL 10 #define RBU_STAGE_OAL 1 #define RBU_STAGE_MOVE 2 #define RBU_STAGE_CAPTURE 3 #define RBU_STAGE_CKPT 4 #define RBU_STAGE_DONE 5 #define RBU_CREATE_STATE \ "CREATE TABLE IF NOT EXISTS %s.rbu_state(k INTEGER PRIMARY KEY, v)" typedef struct RbuFrame RbuFrame; typedef struct RbuObjIter RbuObjIter; typedef struct RbuState RbuState; typedef struct RbuSpan RbuSpan; typedef struct rbu_vfs rbu_vfs; typedef struct rbu_file rbu_file; typedef struct RbuUpdateStmt RbuUpdateStmt; #if !defined(SQLITE_AMALGAMATION) typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; typedef sqlite3_int64 i64; #endif /* ** These values must match the values defined in wal.c for the equivalent ** locks. These are not magic numbers as they are part of the SQLite file ** format. */ #define WAL_LOCK_WRITE 0 #define WAL_LOCK_CKPT 1 #define WAL_LOCK_READ0 3 #define SQLITE_FCNTL_RBUCNT 5149216 /* ** A structure to store values read from the rbu_state table in memory. */ struct RbuState { int eStage; char *zTbl; char *zDataTbl; char *zIdx; i64 iWalCksum; int nRow; i64 nProgress; u32 iCookie; i64 iOalSz; i64 nPhaseOneStep; }; struct RbuUpdateStmt { char *zMask; /* Copy of update mask used with pUpdate */ sqlite3_stmt *pUpdate; /* Last update statement (or NULL) */ RbuUpdateStmt *pNext; }; struct RbuSpan { const char *zSpan; int nSpan; }; /* ** An iterator of this type is used to iterate through all objects in ** the target database that require updating. For each such table, the ** iterator visits, in order: ** ** * the table itself, ** * each index of the table (zero or more points to visit), and ** * a special "cleanup table" state. ** ** abIndexed: ** If the table has no indexes on it, abIndexed is set to NULL. Otherwise, ** it points to an array of flags nTblCol elements in size. The flag is ** set for each column that is either a part of the PK or a part of an ** index. Or clear otherwise. ** ** If there are one or more partial indexes on the table, all fields of ** this array set set to 1. This is because in that case, the module has ** no way to tell which fields will be required to add and remove entries ** from the partial indexes. ** */ struct RbuObjIter { sqlite3_stmt *pTblIter; /* Iterate through tables */ sqlite3_stmt *pIdxIter; /* Index iterator */ int nTblCol; /* Size of azTblCol[] array */ char **azTblCol; /* Array of unquoted target column names */ char **azTblType; /* Array of target column types */ int *aiSrcOrder; /* src table col -> target table col */ u8 *abTblPk; /* Array of flags, set on target PK columns */ u8 *abNotNull; /* Array of flags, set on NOT NULL columns */ u8 *abIndexed; /* Array of flags, set on indexed & PK cols */ int eType; /* Table type - an RBU_PK_XXX value */ /* Output variables. zTbl==0 implies EOF. */ int bCleanup; /* True in "cleanup" state */ const char *zTbl; /* Name of target db table */ const char *zDataTbl; /* Name of rbu db table (or null) */ const char *zIdx; /* Name of target db index (or null) */ int iTnum; /* Root page of current object */ int iPkTnum; /* If eType==EXTERNAL, root of PK index */ int bUnique; /* Current index is unique */ int nIndex; /* Number of aux. indexes on table zTbl */ /* Statements created by rbuObjIterPrepareAll() */ int nCol; /* Number of columns in current object */ sqlite3_stmt *pSelect; /* Source data */ sqlite3_stmt *pInsert; /* Statement for INSERT operations */ sqlite3_stmt *pDelete; /* Statement for DELETE ops */ sqlite3_stmt *pTmpInsert; /* Insert into rbu_tmp_$zDataTbl */ int nIdxCol; RbuSpan *aIdxCol; char *zIdxSql; /* Last UPDATE used (for PK b-tree updates only), or NULL. */ RbuUpdateStmt *pRbuUpdate; }; /* ** Values for RbuObjIter.eType ** ** 0: Table does not exist (error) ** 1: Table has an implicit rowid. ** 2: Table has an explicit IPK column. ** 3: Table has an external PK index. ** 4: Table is WITHOUT ROWID. ** 5: Table is a virtual table. */ #define RBU_PK_NOTABLE 0 #define RBU_PK_NONE 1 #define RBU_PK_IPK 2 #define RBU_PK_EXTERNAL 3 #define RBU_PK_WITHOUT_ROWID 4 #define RBU_PK_VTAB 5 /* ** Within the RBU_STAGE_OAL stage, each call to sqlite3rbu_step() performs ** one of the following operations. */ #define RBU_INSERT 1 /* Insert on a main table b-tree */ #define RBU_DELETE 2 /* Delete a row from a main table b-tree */ #define RBU_REPLACE 3 /* Delete and then insert a row */ #define RBU_IDX_DELETE 4 /* Delete a row from an aux. index b-tree */ #define RBU_IDX_INSERT 5 /* Insert on an aux. index b-tree */ #define RBU_UPDATE 6 /* Update a row in a main table b-tree */ /* ** A single step of an incremental checkpoint - frame iWalFrame of the wal ** file should be copied to page iDbPage of the database file. */ struct RbuFrame { u32 iDbPage; u32 iWalFrame; }; /* ** RBU handle. ** ** nPhaseOneStep: ** If the RBU database contains an rbu_count table, this value is set to ** a running estimate of the number of b-tree operations required to ** finish populating the *-oal file. This allows the sqlite3_bp_progress() ** API to calculate the permyriadage progress of populating the *-oal file ** using the formula: ** ** permyriadage = (10000 * nProgress) / nPhaseOneStep ** ** nPhaseOneStep is initialized to the sum of: ** ** nRow * (nIndex + 1) ** ** for all source tables in the RBU database, where nRow is the number ** of rows in the source table and nIndex the number of indexes on the ** corresponding target database table. ** ** This estimate is accurate if the RBU update consists entirely of ** INSERT operations. However, it is inaccurate if: ** ** * the RBU update contains any UPDATE operations. If the PK specified ** for an UPDATE operation does not exist in the target table, then ** no b-tree operations are required on index b-trees. Or if the ** specified PK does exist, then (nIndex*2) such operations are ** required (one delete and one insert on each index b-tree). ** ** * the RBU update contains any DELETE operations for which the specified ** PK does not exist. In this case no operations are required on index ** b-trees. ** ** * the RBU update contains REPLACE operations. These are similar to ** UPDATE operations. ** ** nPhaseOneStep is updated to account for the conditions above during the ** first pass of each source table. The updated nPhaseOneStep value is ** stored in the rbu_state table if the RBU update is suspended. */ struct sqlite3rbu { int eStage; /* Value of RBU_STATE_STAGE field */ sqlite3 *dbMain; /* target database handle */ sqlite3 *dbRbu; /* rbu database handle */ char *zTarget; /* Path to target db */ char *zRbu; /* Path to rbu db */ char *zState; /* Path to state db (or NULL if zRbu) */ char zStateDb[5]; /* Db name for state ("stat" or "main") */ int rc; /* Value returned by last rbu_step() call */ char *zErrmsg; /* Error message if rc!=SQLITE_OK */ int nStep; /* Rows processed for current object */ int nProgress; /* Rows processed for all objects */ RbuObjIter objiter; /* Iterator for skipping through tbl/idx */ const char *zVfsName; /* Name of automatically created rbu vfs */ rbu_file *pTargetFd; /* File handle open on target db */ int nPagePerSector; /* Pages per sector for pTargetFd */ i64 iOalSz; i64 nPhaseOneStep; void *pRenameArg; int (*xRename)(void*, const char*, const char*); /* The following state variables are used as part of the incremental ** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding ** function rbuSetupCheckpoint() for details. */ u32 iMaxFrame; /* Largest iWalFrame value in aFrame[] */ u32 mLock; int nFrame; /* Entries in aFrame[] array */ int nFrameAlloc; /* Allocated size of aFrame[] array */ RbuFrame *aFrame; int pgsz; u8 *aBuf; i64 iWalCksum; i64 szTemp; /* Current size of all temp files in use */ i64 szTempLimit; /* Total size limit for temp files */ /* Used in RBU vacuum mode only */ int nRbu; /* Number of RBU VFS in the stack */ rbu_file *pRbuFd; /* Fd for main db of dbRbu */ }; /* ** An rbu VFS is implemented using an instance of this structure. ** ** Variable pRbu is only non-NULL for automatically created RBU VFS objects. ** It is NULL for RBU VFS objects created explicitly using ** sqlite3rbu_create_vfs(). It is used to track the total amount of temp ** space used by the RBU handle. */ struct rbu_vfs { sqlite3_vfs base; /* rbu VFS shim methods */ sqlite3_vfs *pRealVfs; /* Underlying VFS */ sqlite3_mutex *mutex; /* Mutex to protect pMain */ sqlite3rbu *pRbu; /* Owner RBU object */ rbu_file *pMain; /* List of main db files */ rbu_file *pMainRbu; /* List of main db files with pRbu!=0 */ }; /* ** Each file opened by an rbu VFS is represented by an instance of ** the following structure. ** ** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable ** "sz" is set to the current size of the database file. */ struct rbu_file { sqlite3_file base; /* sqlite3_file methods */ sqlite3_file *pReal; /* Underlying file handle */ rbu_vfs *pRbuVfs; /* Pointer to the rbu_vfs object */ sqlite3rbu *pRbu; /* Pointer to rbu object (rbu target only) */ i64 sz; /* Size of file in bytes (temp only) */ int openFlags; /* Flags this file was opened with */ u32 iCookie; /* Cookie value for main db files */ u8 iWriteVer; /* "write-version" value for main db files */ u8 bNolock; /* True to fail EXCLUSIVE locks */ int nShm; /* Number of entries in apShm[] array */ char **apShm; /* Array of mmap'd *-shm regions */ char *zDel; /* Delete this when closing file */ const char *zWal; /* Wal filename for this main db file */ rbu_file *pWalFd; /* Wal file descriptor for this main db */ rbu_file *pMainNext; /* Next MAIN_DB file */ rbu_file *pMainRbuNext; /* Next MAIN_DB file with pRbu!=0 */ }; /* ** True for an RBU vacuum handle, or false otherwise. */ #define rbuIsVacuum(p) ((p)->zTarget==0) /************************************************************************* ** The following three functions, found below: ** ** rbuDeltaGetInt() ** rbuDeltaChecksum() ** rbuDeltaApply() ** ** are lifted from the fossil source code (http://fossil-scm.org). They ** are used to implement the scalar SQL function rbu_fossil_delta(). */ /* ** Read bytes from *pz and convert them into a positive integer. When ** finished, leave *pz pointing to the first character past the end of ** the integer. The *pLen parameter holds the length of the string ** in *pz and is decremented once for each character in the integer. */ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){ static const signed char zValue[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1, }; unsigned int v = 0; int c; unsigned char *z = (unsigned char*)*pz; unsigned char *zStart = z; while( (c = zValue[0x7f&*(z++)])>=0 ){ v = (v<<6) + c; } z--; *pLen -= z - zStart; *pz = (char*)z; return v; } #if RBU_ENABLE_DELTA_CKSUM /* ** Compute a 32-bit checksum on the N-byte buffer. Return the result. */ static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){ const unsigned char *z = (const unsigned char *)zIn; unsigned sum0 = 0; unsigned sum1 = 0; unsigned sum2 = 0; unsigned sum3 = 0; while(N >= 16){ sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]); sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]); sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]); sum3 += ((unsigned)z[3] + z[7] + z[11]+ z[15]); z += 16; N -= 16; } while(N >= 4){ sum0 += z[0]; sum1 += z[1]; sum2 += z[2]; sum3 += z[3]; z += 4; N -= 4; } sum3 += (sum2 << 8) + (sum1 << 16) + (sum0 << 24); switch(N){ case 3: sum3 += (z[2] << 8); case 2: sum3 += (z[1] << 16); case 1: sum3 += (z[0] << 24); default: ; } return sum3; } #endif /* ** Apply a delta. ** ** The output buffer should be big enough to hold the whole output ** file and a NUL terminator at the end. The delta_output_size() ** routine will determine this size for you. ** ** The delta string should be null-terminated. But the delta string ** may contain embedded NUL characters (if the input and output are ** binary files) so we also have to pass in the length of the delta in ** the lenDelta parameter. ** ** This function returns the size of the output file in bytes (excluding ** the final NUL terminator character). Except, if the delta string is ** malformed or intended for use with a source file other than zSrc, ** then this routine returns -1. ** ** Refer to the delta_create() documentation above for a description ** of the delta file format. */ static int rbuDeltaApply( const char *zSrc, /* The source or pattern file */ int lenSrc, /* Length of the source file */ const char *zDelta, /* Delta to apply to the pattern */ int lenDelta, /* Length of the delta */ char *zOut /* Write the output into this preallocated buffer */ ){ unsigned int limit; unsigned int total = 0; #if RBU_ENABLE_DELTA_CKSUM char *zOrigOut = zOut; #endif limit = rbuDeltaGetInt(&zDelta, &lenDelta); if( *zDelta!='\n' ){ /* ERROR: size integer not terminated by "\n" */ return -1; } zDelta++; lenDelta--; while( *zDelta && lenDelta>0 ){ unsigned int cnt, ofst; cnt = rbuDeltaGetInt(&zDelta, &lenDelta); switch( zDelta[0] ){ case '@': { zDelta++; lenDelta--; ofst = rbuDeltaGetInt(&zDelta, &lenDelta); if( lenDelta>0 && zDelta[0]!=',' ){ /* ERROR: copy command not terminated by ',' */ return -1; } zDelta++; lenDelta--; total += cnt; if( total>limit ){ /* ERROR: copy exceeds output file size */ return -1; } if( (int)(ofst+cnt) > lenSrc ){ /* ERROR: copy extends past end of input */ return -1; } memcpy(zOut, &zSrc[ofst], cnt); zOut += cnt; break; } case ':': { zDelta++; lenDelta--; total += cnt; if( total>limit ){ /* ERROR: insert command gives an output larger than predicted */ return -1; } if( (int)cnt>lenDelta ){ /* ERROR: insert count exceeds size of delta */ return -1; } memcpy(zOut, zDelta, cnt); zOut += cnt; zDelta += cnt; lenDelta -= cnt; break; } case ';': { zDelta++; lenDelta--; zOut[0] = 0; #if RBU_ENABLE_DELTA_CKSUM if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){ /* ERROR: bad checksum */ return -1; } #endif if( total!=limit ){ /* ERROR: generated size does not match predicted size */ return -1; } return total; } default: { /* ERROR: unknown delta operator */ return -1; } } } /* ERROR: unterminated delta */ return -1; } static int rbuDeltaOutputSize(const char *zDelta, int lenDelta){ int size; size = rbuDeltaGetInt(&zDelta, &lenDelta); if( *zDelta!='\n' ){ /* ERROR: size integer not terminated by "\n" */ return -1; } return size; } /* ** End of code taken from fossil. *************************************************************************/ /* ** Implementation of SQL scalar function rbu_fossil_delta(). ** ** This function applies a fossil delta patch to a blob. Exactly two ** arguments must be passed to this function. The first is the blob to ** patch and the second the patch to apply. If no error occurs, this ** function returns the patched blob. */ static void rbuFossilDeltaFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *aDelta; int nDelta; const char *aOrig; int nOrig; int nOut; int nOut2; char *aOut; assert( argc==2 ); nOrig = sqlite3_value_bytes(argv[0]); aOrig = (const char*)sqlite3_value_blob(argv[0]); nDelta = sqlite3_value_bytes(argv[1]); aDelta = (const char*)sqlite3_value_blob(argv[1]); /* Figure out the size of the output */ nOut = rbuDeltaOutputSize(aDelta, nDelta); if( nOut<0 ){ sqlite3_result_error(context, "corrupt fossil delta", -1); return; } aOut = sqlite3_malloc(nOut+1); if( aOut==0 ){ sqlite3_result_error_nomem(context); }else{ nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut); if( nOut2!=nOut ){ sqlite3_free(aOut); sqlite3_result_error(context, "corrupt fossil delta", -1); }else{ sqlite3_result_blob(context, aOut, nOut, sqlite3_free); } } } /* ** Prepare the SQL statement in buffer zSql against database handle db. ** If successful, set *ppStmt to point to the new statement and return ** SQLITE_OK. ** ** Otherwise, if an error does occur, set *ppStmt to NULL and return ** an SQLite error code. Additionally, set output variable *pzErrmsg to ** point to a buffer containing an error message. It is the responsibility ** of the caller to (eventually) free this buffer using sqlite3_free(). */ static int prepareAndCollectError( sqlite3 *db, sqlite3_stmt **ppStmt, char **pzErrmsg, const char *zSql ){ int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); if( rc!=SQLITE_OK ){ *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); *ppStmt = 0; } return rc; } /* ** Reset the SQL statement passed as the first argument. Return a copy ** of the value returned by sqlite3_reset(). ** ** If an error has occurred, then set *pzErrmsg to point to a buffer ** containing an error message. It is the responsibility of the caller ** to eventually free this buffer using sqlite3_free(). */ static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){ int rc = sqlite3_reset(pStmt); if( rc!=SQLITE_OK ){ *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(sqlite3_db_handle(pStmt))); } return rc; } /* ** Unless it is NULL, argument zSql points to a buffer allocated using ** sqlite3_malloc containing an SQL statement. This function prepares the SQL ** statement against database db and frees the buffer. If statement ** compilation is successful, *ppStmt is set to point to the new statement ** handle and SQLITE_OK is returned. ** ** Otherwise, if an error occurs, *ppStmt is set to NULL and an error code ** returned. In this case, *pzErrmsg may also be set to point to an error ** message. It is the responsibility of the caller to free this error message ** buffer using sqlite3_free(). ** ** If argument zSql is NULL, this function assumes that an OOM has occurred. ** In this case SQLITE_NOMEM is returned and *ppStmt set to NULL. */ static int prepareFreeAndCollectError( sqlite3 *db, sqlite3_stmt **ppStmt, char **pzErrmsg, char *zSql ){ int rc; assert( *pzErrmsg==0 ); if( zSql==0 ){ rc = SQLITE_NOMEM; *ppStmt = 0; }else{ rc = prepareAndCollectError(db, ppStmt, pzErrmsg, zSql); sqlite3_free(zSql); } return rc; } /* ** Free the RbuObjIter.azTblCol[] and RbuObjIter.abTblPk[] arrays allocated ** by an earlier call to rbuObjIterCacheTableInfo(). */ static void rbuObjIterFreeCols(RbuObjIter *pIter){ int i; for(i=0; inTblCol; i++){ sqlite3_free(pIter->azTblCol[i]); sqlite3_free(pIter->azTblType[i]); } sqlite3_free(pIter->azTblCol); pIter->azTblCol = 0; pIter->azTblType = 0; pIter->aiSrcOrder = 0; pIter->abTblPk = 0; pIter->abNotNull = 0; pIter->nTblCol = 0; pIter->eType = 0; /* Invalid value */ } /* ** Finalize all statements and free all allocations that are specific to ** the current object (table/index pair). */ static void rbuObjIterClearStatements(RbuObjIter *pIter){ RbuUpdateStmt *pUp; sqlite3_finalize(pIter->pSelect); sqlite3_finalize(pIter->pInsert); sqlite3_finalize(pIter->pDelete); sqlite3_finalize(pIter->pTmpInsert); pUp = pIter->pRbuUpdate; while( pUp ){ RbuUpdateStmt *pTmp = pUp->pNext; sqlite3_finalize(pUp->pUpdate); sqlite3_free(pUp); pUp = pTmp; } sqlite3_free(pIter->aIdxCol); sqlite3_free(pIter->zIdxSql); pIter->pSelect = 0; pIter->pInsert = 0; pIter->pDelete = 0; pIter->pRbuUpdate = 0; pIter->pTmpInsert = 0; pIter->nCol = 0; pIter->nIdxCol = 0; pIter->aIdxCol = 0; pIter->zIdxSql = 0; } /* ** Clean up any resources allocated as part of the iterator object passed ** as the only argument. */ static void rbuObjIterFinalize(RbuObjIter *pIter){ rbuObjIterClearStatements(pIter); sqlite3_finalize(pIter->pTblIter); sqlite3_finalize(pIter->pIdxIter); rbuObjIterFreeCols(pIter); memset(pIter, 0, sizeof(RbuObjIter)); } /* ** Advance the iterator to the next position. ** ** If no error occurs, SQLITE_OK is returned and the iterator is left ** pointing to the next entry. Otherwise, an error code and message is ** left in the RBU handle passed as the first argument. A copy of the ** error code is returned. */ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){ int rc = p->rc; if( rc==SQLITE_OK ){ /* Free any SQLite statements used while processing the previous object */ rbuObjIterClearStatements(pIter); if( pIter->zIdx==0 ){ rc = sqlite3_exec(p->dbMain, "DROP TRIGGER IF EXISTS temp.rbu_insert_tr;" "DROP TRIGGER IF EXISTS temp.rbu_update1_tr;" "DROP TRIGGER IF EXISTS temp.rbu_update2_tr;" "DROP TRIGGER IF EXISTS temp.rbu_delete_tr;" , 0, 0, &p->zErrmsg ); } if( rc==SQLITE_OK ){ if( pIter->bCleanup ){ rbuObjIterFreeCols(pIter); pIter->bCleanup = 0; rc = sqlite3_step(pIter->pTblIter); if( rc!=SQLITE_ROW ){ rc = resetAndCollectError(pIter->pTblIter, &p->zErrmsg); pIter->zTbl = 0; }else{ pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0); pIter->zDataTbl = (const char*)sqlite3_column_text(pIter->pTblIter,1); rc = (pIter->zDataTbl && pIter->zTbl) ? SQLITE_OK : SQLITE_NOMEM; } }else{ if( pIter->zIdx==0 ){ sqlite3_stmt *pIdx = pIter->pIdxIter; rc = sqlite3_bind_text(pIdx, 1, pIter->zTbl, -1, SQLITE_STATIC); } if( rc==SQLITE_OK ){ rc = sqlite3_step(pIter->pIdxIter); if( rc!=SQLITE_ROW ){ rc = resetAndCollectError(pIter->pIdxIter, &p->zErrmsg); pIter->bCleanup = 1; pIter->zIdx = 0; }else{ pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0); pIter->iTnum = sqlite3_column_int(pIter->pIdxIter, 1); pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2); rc = pIter->zIdx ? SQLITE_OK : SQLITE_NOMEM; } } } } } if( rc!=SQLITE_OK ){ rbuObjIterFinalize(pIter); p->rc = rc; } return rc; } /* ** The implementation of the rbu_target_name() SQL function. This function ** accepts one or two arguments. The first argument is the name of a table - ** the name of a table in the RBU database. The second, if it is present, is 1 ** for a view or 0 for a table. ** ** For a non-vacuum RBU handle, if the table name matches the pattern: ** ** data[0-9]_ ** ** where is any sequence of 1 or more characters, is returned. ** Otherwise, if the only argument does not match the above pattern, an SQL ** NULL is returned. ** ** "data_t1" -> "t1" ** "data0123_t2" -> "t2" ** "dataAB_t3" -> NULL ** ** For an rbu vacuum handle, a copy of the first argument is returned if ** the second argument is either missing or 0 (not a view). */ static void rbuTargetNameFunc( sqlite3_context *pCtx, int argc, sqlite3_value **argv ){ sqlite3rbu *p = sqlite3_user_data(pCtx); const char *zIn; assert( argc==1 || argc==2 ); zIn = (const char*)sqlite3_value_text(argv[0]); if( zIn ){ if( rbuIsVacuum(p) ){ assert( argc==2 || argc==1 ); if( argc==1 || 0==sqlite3_value_int(argv[1]) ){ sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC); } }else{ if( strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){ int i; for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++); if( zIn[i]=='_' && zIn[i+1] ){ sqlite3_result_text(pCtx, &zIn[i+1], -1, SQLITE_STATIC); } } } } } /* ** Initialize the iterator structure passed as the second argument. ** ** If no error occurs, SQLITE_OK is returned and the iterator is left ** pointing to the first entry. Otherwise, an error code and message is ** left in the RBU handle passed as the first argument. A copy of the ** error code is returned. */ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ int rc; memset(pIter, 0, sizeof(RbuObjIter)); rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, sqlite3_mprintf( "SELECT rbu_target_name(name, type='view') AS target, name " "FROM sqlite_schema " "WHERE type IN ('table', 'view') AND target IS NOT NULL " " %s " "ORDER BY name" , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : "")); if( rc==SQLITE_OK ){ rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg, "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' " " FROM main.sqlite_schema " " WHERE type='index' AND tbl_name = ?" ); } pIter->bCleanup = 1; p->rc = rc; return rbuObjIterNext(p, pIter); } /* ** This is a wrapper around "sqlite3_mprintf(zFmt, ...)". If an OOM occurs, ** an error code is stored in the RBU handle passed as the first argument. ** ** If an error has already occurred (p->rc is already set to something other ** than SQLITE_OK), then this function returns NULL without modifying the ** stored error code. In this case it still calls sqlite3_free() on any ** printf() parameters associated with %z conversions. */ static char *rbuMPrintf(sqlite3rbu *p, const char *zFmt, ...){ char *zSql = 0; va_list ap; va_start(ap, zFmt); zSql = sqlite3_vmprintf(zFmt, ap); if( p->rc==SQLITE_OK ){ if( zSql==0 ) p->rc = SQLITE_NOMEM; }else{ sqlite3_free(zSql); zSql = 0; } va_end(ap); return zSql; } /* ** Argument zFmt is a sqlite3_mprintf() style format string. The trailing ** arguments are the usual subsitution values. This function performs ** the printf() style substitutions and executes the result as an SQL ** statement on the RBU handles database. ** ** If an error occurs, an error code and error message is stored in the ** RBU handle. If an error has already occurred when this function is ** called, it is a no-op. */ static int rbuMPrintfExec(sqlite3rbu *p, sqlite3 *db, const char *zFmt, ...){ va_list ap; char *zSql; va_start(ap, zFmt); zSql = sqlite3_vmprintf(zFmt, ap); if( p->rc==SQLITE_OK ){ if( zSql==0 ){ p->rc = SQLITE_NOMEM; }else{ p->rc = sqlite3_exec(db, zSql, 0, 0, &p->zErrmsg); } } sqlite3_free(zSql); va_end(ap); return p->rc; } /* ** Attempt to allocate and return a pointer to a zeroed block of nByte ** bytes. ** ** If an error (i.e. an OOM condition) occurs, return NULL and leave an ** error code in the rbu handle passed as the first argument. Or, if an ** error has already occurred when this function is called, return NULL ** immediately without attempting the allocation or modifying the stored ** error code. */ static void *rbuMalloc(sqlite3rbu *p, sqlite3_int64 nByte){ void *pRet = 0; if( p->rc==SQLITE_OK ){ assert( nByte>0 ); pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ p->rc = SQLITE_NOMEM; }else{ memset(pRet, 0, nByte); } } return pRet; } /* ** Allocate and zero the pIter->azTblCol[] and abTblPk[] arrays so that ** there is room for at least nCol elements. If an OOM occurs, store an ** error code in the RBU handle passed as the first argument. */ static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){ sqlite3_int64 nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol; char **azNew; azNew = (char**)rbuMalloc(p, nByte); if( azNew ){ pIter->azTblCol = azNew; pIter->azTblType = &azNew[nCol]; pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol]; pIter->abTblPk = (u8*)&pIter->aiSrcOrder[nCol]; pIter->abNotNull = (u8*)&pIter->abTblPk[nCol]; pIter->abIndexed = (u8*)&pIter->abNotNull[nCol]; } } /* ** The first argument must be a nul-terminated string. This function ** returns a copy of the string in memory obtained from sqlite3_malloc(). ** It is the responsibility of the caller to eventually free this memory ** using sqlite3_free(). ** ** If an OOM condition is encountered when attempting to allocate memory, ** output variable (*pRc) is set to SQLITE_NOMEM before returning. Otherwise, ** if the allocation succeeds, (*pRc) is left unchanged. */ static char *rbuStrndup(const char *zStr, int *pRc){ char *zRet = 0; if( *pRc==SQLITE_OK ){ if( zStr ){ size_t nCopy = strlen(zStr) + 1; zRet = (char*)sqlite3_malloc64(nCopy); if( zRet ){ memcpy(zRet, zStr, nCopy); }else{ *pRc = SQLITE_NOMEM; } } } return zRet; } /* ** Finalize the statement passed as the second argument. ** ** If the sqlite3_finalize() call indicates that an error occurs, and the ** rbu handle error code is not already set, set the error code and error ** message accordingly. */ static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){ sqlite3 *db = sqlite3_db_handle(pStmt); int rc = sqlite3_finalize(pStmt); if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){ p->rc = rc; p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } } /* Determine the type of a table. ** ** peType is of type (int*), a pointer to an output parameter of type ** (int). This call sets the output parameter as follows, depending ** on the type of the table specified by parameters dbName and zTbl. ** ** RBU_PK_NOTABLE: No such table. ** RBU_PK_NONE: Table has an implicit rowid. ** RBU_PK_IPK: Table has an explicit IPK column. ** RBU_PK_EXTERNAL: Table has an external PK index. ** RBU_PK_WITHOUT_ROWID: Table is WITHOUT ROWID. ** RBU_PK_VTAB: Table is a virtual table. ** ** Argument *piPk is also of type (int*), and also points to an output ** parameter. Unless the table has an external primary key index ** (i.e. unless *peType is set to 3), then *piPk is set to zero. Or, ** if the table does have an external primary key index, then *piPk ** is set to the root page number of the primary key index before ** returning. ** ** ALGORITHM: ** ** if( no entry exists in sqlite_schema ){ ** return RBU_PK_NOTABLE ** }else if( sql for the entry starts with "CREATE VIRTUAL" ){ ** return RBU_PK_VTAB ** }else if( "PRAGMA index_list()" for the table contains a "pk" index ){ ** if( the index that is the pk exists in sqlite_schema ){ ** *piPK = rootpage of that index. ** return RBU_PK_EXTERNAL ** }else{ ** return RBU_PK_WITHOUT_ROWID ** } ** }else if( "PRAGMA table_info()" lists one or more "pk" columns ){ ** return RBU_PK_IPK ** }else{ ** return RBU_PK_NONE ** } */ static void rbuTableType( sqlite3rbu *p, const char *zTab, int *peType, int *piTnum, int *piPk ){ /* ** 0) SELECT count(*) FROM sqlite_schema where name=%Q AND IsVirtual(%Q) ** 1) PRAGMA index_list = ? ** 2) SELECT count(*) FROM sqlite_schema where name=%Q ** 3) PRAGMA table_info = ? */ sqlite3_stmt *aStmt[4] = {0, 0, 0, 0}; *peType = RBU_PK_NOTABLE; *piPk = 0; assert( p->rc==SQLITE_OK ); p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg, sqlite3_mprintf( "SELECT " " (sql COLLATE nocase BETWEEN 'CREATE VIRTUAL' AND 'CREATE VIRTUAM')," " rootpage" " FROM sqlite_schema" " WHERE name=%Q", zTab )); if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){ /* Either an error, or no such table. */ goto rbuTableType_end; } if( sqlite3_column_int(aStmt[0], 0) ){ *peType = RBU_PK_VTAB; /* virtual table */ goto rbuTableType_end; } *piTnum = sqlite3_column_int(aStmt[0], 1); p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[1], &p->zErrmsg, sqlite3_mprintf("PRAGMA index_list=%Q",zTab) ); if( p->rc ) goto rbuTableType_end; while( sqlite3_step(aStmt[1])==SQLITE_ROW ){ const u8 *zOrig = sqlite3_column_text(aStmt[1], 3); const u8 *zIdx = sqlite3_column_text(aStmt[1], 1); if( zOrig && zIdx && zOrig[0]=='p' ){ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg, sqlite3_mprintf( "SELECT rootpage FROM sqlite_schema WHERE name = %Q", zIdx )); if( p->rc==SQLITE_OK ){ if( sqlite3_step(aStmt[2])==SQLITE_ROW ){ *piPk = sqlite3_column_int(aStmt[2], 0); *peType = RBU_PK_EXTERNAL; }else{ *peType = RBU_PK_WITHOUT_ROWID; } } goto rbuTableType_end; } } p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg, sqlite3_mprintf("PRAGMA table_info=%Q",zTab) ); if( p->rc==SQLITE_OK ){ while( sqlite3_step(aStmt[3])==SQLITE_ROW ){ if( sqlite3_column_int(aStmt[3],5)>0 ){ *peType = RBU_PK_IPK; /* explicit IPK column */ goto rbuTableType_end; } } *peType = RBU_PK_NONE; } rbuTableType_end: { unsigned int i; for(i=0; iabIndexed[] array. */ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){ sqlite3_stmt *pList = 0; int bIndex = 0; if( p->rc==SQLITE_OK ){ memcpy(pIter->abIndexed, pIter->abTblPk, sizeof(u8)*pIter->nTblCol); p->rc = prepareFreeAndCollectError(p->dbMain, &pList, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl) ); } pIter->nIndex = 0; while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){ const char *zIdx = (const char*)sqlite3_column_text(pList, 1); int bPartial = sqlite3_column_int(pList, 4); sqlite3_stmt *pXInfo = 0; if( zIdx==0 ) break; if( bPartial ){ memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol); } p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) ); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int iCid = sqlite3_column_int(pXInfo, 1); if( iCid>=0 ) pIter->abIndexed[iCid] = 1; if( iCid==-2 ){ memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol); } } rbuFinalize(p, pXInfo); bIndex = 1; pIter->nIndex++; } if( pIter->eType==RBU_PK_WITHOUT_ROWID ){ /* "PRAGMA index_list" includes the main PK b-tree */ pIter->nIndex--; } rbuFinalize(p, pList); if( bIndex==0 ) pIter->abIndexed = 0; } /* ** If they are not already populated, populate the pIter->azTblCol[], ** pIter->abTblPk[], pIter->nTblCol and pIter->bRowid variables according to ** the table (not index) that the iterator currently points to. ** ** Return SQLITE_OK if successful, or an SQLite error code otherwise. If ** an error does occur, an error code and error message are also left in ** the RBU handle. */ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ if( pIter->azTblCol==0 ){ sqlite3_stmt *pStmt = 0; int nCol = 0; int i; /* for() loop iterator variable */ int bRbuRowid = 0; /* If input table has column "rbu_rowid" */ int iOrder = 0; int iTnum = 0; /* Figure out the type of table this step will deal with. */ assert( pIter->eType==0 ); rbuTableType(p, pIter->zTbl, &pIter->eType, &iTnum, &pIter->iPkTnum); if( p->rc==SQLITE_OK && pIter->eType==RBU_PK_NOTABLE ){ p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("no such table: %s", pIter->zTbl); } if( p->rc ) return p->rc; if( pIter->zIdx==0 ) pIter->iTnum = iTnum; assert( pIter->eType==RBU_PK_NONE || pIter->eType==RBU_PK_IPK || pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_WITHOUT_ROWID || pIter->eType==RBU_PK_VTAB ); /* Populate the azTblCol[] and nTblCol variables based on the columns ** of the input table. Ignore any input table columns that begin with ** "rbu_". */ p->rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, sqlite3_mprintf("SELECT * FROM '%q'", pIter->zDataTbl) ); if( p->rc==SQLITE_OK ){ nCol = sqlite3_column_count(pStmt); rbuAllocateIterArrays(p, pIter, nCol); } for(i=0; p->rc==SQLITE_OK && irc); pIter->aiSrcOrder[pIter->nTblCol] = pIter->nTblCol; pIter->azTblCol[pIter->nTblCol++] = zCopy; } else if( 0==sqlite3_stricmp("rbu_rowid", zName) ){ bRbuRowid = 1; } } sqlite3_finalize(pStmt); pStmt = 0; if( p->rc==SQLITE_OK && rbuIsVacuum(p)==0 && bRbuRowid!=(pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE) ){ p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf( "table %q %s rbu_rowid column", pIter->zDataTbl, (bRbuRowid ? "may not have" : "requires") ); } /* Check that all non-HIDDEN columns in the destination table are also ** present in the input table. Populate the abTblPk[], azTblType[] and ** aiTblOrder[] arrays at the same time. */ if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, sqlite3_mprintf("PRAGMA table_info(%Q)", pIter->zTbl) ); } while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zName = (const char*)sqlite3_column_text(pStmt, 1); if( zName==0 ) break; /* An OOM - finalize() below returns S_NOMEM */ for(i=iOrder; inTblCol; i++){ if( 0==strcmp(zName, pIter->azTblCol[i]) ) break; } if( i==pIter->nTblCol ){ p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("column missing from %q: %s", pIter->zDataTbl, zName ); }else{ int iPk = sqlite3_column_int(pStmt, 5); int bNotNull = sqlite3_column_int(pStmt, 3); const char *zType = (const char*)sqlite3_column_text(pStmt, 2); if( i!=iOrder ){ SWAP(int, pIter->aiSrcOrder[i], pIter->aiSrcOrder[iOrder]); SWAP(char*, pIter->azTblCol[i], pIter->azTblCol[iOrder]); } pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc); assert( iPk>=0 ); pIter->abTblPk[iOrder] = (u8)iPk; pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0); iOrder++; } } rbuFinalize(p, pStmt); rbuObjIterCacheIndexedCols(p, pIter); assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 ); assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 ); } return p->rc; } /* ** This function constructs and returns a pointer to a nul-terminated ** string containing some SQL clause or list based on one or more of the ** column names currently stored in the pIter->azTblCol[] array. */ static char *rbuObjIterGetCollist( sqlite3rbu *p, /* RBU object */ RbuObjIter *pIter /* Object iterator for column names */ ){ char *zList = 0; const char *zSep = ""; int i; for(i=0; inTblCol; i++){ const char *z = pIter->azTblCol[i]; zList = rbuMPrintf(p, "%z%s\"%w\"", zList, zSep, z); zSep = ", "; } return zList; } /* ** Return a comma separated list of the quoted PRIMARY KEY column names, ** in order, for the current table. Before each column name, add the text ** zPre. After each column name, add the zPost text. Use zSeparator as ** the separator text (usually ", "). */ static char *rbuObjIterGetPkList( sqlite3rbu *p, /* RBU object */ RbuObjIter *pIter, /* Object iterator for column names */ const char *zPre, /* Before each quoted column name */ const char *zSeparator, /* Separator to use between columns */ const char *zPost /* After each quoted column name */ ){ int iPk = 1; char *zRet = 0; const char *zSep = ""; while( 1 ){ int i; for(i=0; inTblCol; i++){ if( (int)pIter->abTblPk[i]==iPk ){ const char *zCol = pIter->azTblCol[i]; zRet = rbuMPrintf(p, "%z%s%s\"%w\"%s", zRet, zSep, zPre, zCol, zPost); zSep = zSeparator; break; } } if( i==pIter->nTblCol ) break; iPk++; } return zRet; } /* ** This function is called as part of restarting an RBU vacuum within ** stage 1 of the process (while the *-oal file is being built) while ** updating a table (not an index). The table may be a rowid table or ** a WITHOUT ROWID table. It queries the target database to find the ** largest key that has already been written to the target table and ** constructs a WHERE clause that can be used to extract the remaining ** rows from the source table. For a rowid table, the WHERE clause ** is of the form: ** ** "WHERE _rowid_ > ?" ** ** and for WITHOUT ROWID tables: ** ** "WHERE (key1, key2) > (?, ?)" ** ** Instead of "?" placeholders, the actual WHERE clauses created by ** this function contain literal SQL values. */ static char *rbuVacuumTableStart( sqlite3rbu *p, /* RBU handle */ RbuObjIter *pIter, /* RBU iterator object */ int bRowid, /* True for a rowid table */ const char *zWrite /* Target table name prefix */ ){ sqlite3_stmt *pMax = 0; char *zRet = 0; if( bRowid ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, sqlite3_mprintf( "SELECT max(_rowid_) FROM \"%s%w\"", zWrite, pIter->zTbl ) ); if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ sqlite3_int64 iMax = sqlite3_column_int64(pMax, 0); zRet = rbuMPrintf(p, " WHERE _rowid_ > %lld ", iMax); } rbuFinalize(p, pMax); }else{ char *zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", " DESC"); char *zSelect = rbuObjIterGetPkList(p, pIter, "quote(", "||','||", ")"); char *zList = rbuObjIterGetPkList(p, pIter, "", ", ", ""); if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, sqlite3_mprintf( "SELECT %s FROM \"%s%w\" ORDER BY %s LIMIT 1", zSelect, zWrite, pIter->zTbl, zOrder ) ); if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ const char *zVal = (const char*)sqlite3_column_text(pMax, 0); zRet = rbuMPrintf(p, " WHERE (%s) > (%s) ", zList, zVal); } rbuFinalize(p, pMax); } sqlite3_free(zOrder); sqlite3_free(zSelect); sqlite3_free(zList); } return zRet; } /* ** This function is called as part of restating an RBU vacuum when the ** current operation is writing content to an index. If possible, it ** queries the target index b-tree for the largest key already written to ** it, then composes and returns an expression that can be used in a WHERE ** clause to select the remaining required rows from the source table. ** It is only possible to return such an expression if: ** ** * The index contains no DESC columns, and ** * The last key written to the index before the operation was ** suspended does not contain any NULL values. ** ** The expression is of the form: ** ** (index-field1, index-field2, ...) > (?, ?, ...) ** ** except that the "?" placeholders are replaced with literal values. ** ** If the expression cannot be created, NULL is returned. In this case, ** the caller has to use an OFFSET clause to extract only the required ** rows from the sourct table, just as it does for an RBU update operation. */ static char *rbuVacuumIndexStart( sqlite3rbu *p, /* RBU handle */ RbuObjIter *pIter /* RBU iterator object */ ){ char *zOrder = 0; char *zLhs = 0; char *zSelect = 0; char *zVector = 0; char *zRet = 0; int bFailed = 0; const char *zSep = ""; int iCol = 0; sqlite3_stmt *pXInfo = 0; p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx) ); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int iCid = sqlite3_column_int(pXInfo, 1); const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); const char *zCol; if( sqlite3_column_int(pXInfo, 3) ){ bFailed = 1; break; } if( iCid<0 ){ if( pIter->eType==RBU_PK_IPK ){ int i; for(i=0; pIter->abTblPk[i]==0; i++); assert( inTblCol ); zCol = pIter->azTblCol[i]; }else{ zCol = "_rowid_"; } }else{ zCol = pIter->azTblCol[iCid]; } zLhs = rbuMPrintf(p, "%z%s \"%w\" COLLATE %Q", zLhs, zSep, zCol, zCollate ); zOrder = rbuMPrintf(p, "%z%s \"rbu_imp_%d%w\" COLLATE %Q DESC", zOrder, zSep, iCol, zCol, zCollate ); zSelect = rbuMPrintf(p, "%z%s quote(\"rbu_imp_%d%w\")", zSelect, zSep, iCol, zCol ); zSep = ", "; iCol++; } rbuFinalize(p, pXInfo); if( bFailed ) goto index_start_out; if( p->rc==SQLITE_OK ){ sqlite3_stmt *pSel = 0; p->rc = prepareFreeAndCollectError(p->dbMain, &pSel, &p->zErrmsg, sqlite3_mprintf("SELECT %s FROM \"rbu_imp_%w\" ORDER BY %s LIMIT 1", zSelect, pIter->zTbl, zOrder ) ); if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSel) ){ zSep = ""; for(iCol=0; iColnCol; iCol++){ const char *zQuoted = (const char*)sqlite3_column_text(pSel, iCol); if( zQuoted==0 ){ p->rc = SQLITE_NOMEM; }else if( zQuoted[0]=='N' ){ bFailed = 1; break; } zVector = rbuMPrintf(p, "%z%s%s", zVector, zSep, zQuoted); zSep = ", "; } if( !bFailed ){ zRet = rbuMPrintf(p, "(%s) > (%s)", zLhs, zVector); } } rbuFinalize(p, pSel); } index_start_out: sqlite3_free(zOrder); sqlite3_free(zSelect); sqlite3_free(zVector); sqlite3_free(zLhs); return zRet; } /* ** This function is used to create a SELECT list (the list of SQL ** expressions that follows a SELECT keyword) for a SELECT statement ** used to read from an data_xxx or rbu_tmp_xxx table while updating the ** index object currently indicated by the iterator object passed as the ** second argument. A "PRAGMA index_xinfo = " statement is used ** to obtain the required information. ** ** If the index is of the following form: ** ** CREATE INDEX i1 ON t1(c, b COLLATE nocase); ** ** and "t1" is a table with an explicit INTEGER PRIMARY KEY column ** "ipk", the returned string is: ** ** "`c` COLLATE 'BINARY', `b` COLLATE 'NOCASE', `ipk` COLLATE 'BINARY'" ** ** As well as the returned string, three other malloc'd strings are ** returned via output parameters. As follows: ** ** pzImposterCols: ... ** pzImposterPk: ... ** pzWhere: ... */ static char *rbuObjIterGetIndexCols( sqlite3rbu *p, /* RBU object */ RbuObjIter *pIter, /* Object iterator for column names */ char **pzImposterCols, /* OUT: Columns for imposter table */ char **pzImposterPk, /* OUT: Imposter PK clause */ char **pzWhere, /* OUT: WHERE clause */ int *pnBind /* OUT: Trbul number of columns */ ){ int rc = p->rc; /* Error code */ int rc2; /* sqlite3_finalize() return code */ char *zRet = 0; /* String to return */ char *zImpCols = 0; /* String to return via *pzImposterCols */ char *zImpPK = 0; /* String to return via *pzImposterPK */ char *zWhere = 0; /* String to return via *pzWhere */ int nBind = 0; /* Value to return via *pnBind */ const char *zCom = ""; /* Set to ", " later on */ const char *zAnd = ""; /* Set to " AND " later on */ sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = ? */ if( rc==SQLITE_OK ){ assert( p->zErrmsg==0 ); rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx) ); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int iCid = sqlite3_column_int(pXInfo, 1); int bDesc = sqlite3_column_int(pXInfo, 3); const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); const char *zCol = 0; const char *zType; if( iCid==-2 ){ int iSeq = sqlite3_column_int(pXInfo, 0); zRet = sqlite3_mprintf("%z%s(%.*s) COLLATE %Q", zRet, zCom, pIter->aIdxCol[iSeq].nSpan, pIter->aIdxCol[iSeq].zSpan, zCollate ); zType = ""; }else { if( iCid<0 ){ /* An integer primary key. If the table has an explicit IPK, use ** its name. Otherwise, use "rbu_rowid". */ if( pIter->eType==RBU_PK_IPK ){ int i; for(i=0; pIter->abTblPk[i]==0; i++); assert( inTblCol ); zCol = pIter->azTblCol[i]; }else if( rbuIsVacuum(p) ){ zCol = "_rowid_"; }else{ zCol = "rbu_rowid"; } zType = "INTEGER"; }else{ zCol = pIter->azTblCol[iCid]; zType = pIter->azTblType[iCid]; } zRet = sqlite3_mprintf("%z%s\"%w\" COLLATE %Q", zRet, zCom,zCol,zCollate); } if( pIter->bUnique==0 || sqlite3_column_int(pXInfo, 5) ){ const char *zOrder = (bDesc ? " DESC" : ""); zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s", zImpPK, zCom, nBind, zCol, zOrder ); } zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q", zImpCols, zCom, nBind, zCol, zType, zCollate ); zWhere = sqlite3_mprintf( "%z%s\"rbu_imp_%d%w\" IS ?", zWhere, zAnd, nBind, zCol ); if( zRet==0 || zImpPK==0 || zImpCols==0 || zWhere==0 ) rc = SQLITE_NOMEM; zCom = ", "; zAnd = " AND "; nBind++; } rc2 = sqlite3_finalize(pXInfo); if( rc==SQLITE_OK ) rc = rc2; if( rc!=SQLITE_OK ){ sqlite3_free(zRet); sqlite3_free(zImpCols); sqlite3_free(zImpPK); sqlite3_free(zWhere); zRet = 0; zImpCols = 0; zImpPK = 0; zWhere = 0; p->rc = rc; } *pzImposterCols = zImpCols; *pzImposterPk = zImpPK; *pzWhere = zWhere; *pnBind = nBind; return zRet; } /* ** Assuming the current table columns are "a", "b" and "c", and the zObj ** paramter is passed "old", return a string of the form: ** ** "old.a, old.b, old.b" ** ** With the column names escaped. ** ** For tables with implicit rowids - RBU_PK_EXTERNAL and RBU_PK_NONE, append ** the text ", old._rowid_" to the returned value. */ static char *rbuObjIterGetOldlist( sqlite3rbu *p, RbuObjIter *pIter, const char *zObj ){ char *zList = 0; if( p->rc==SQLITE_OK && pIter->abIndexed ){ const char *zS = ""; int i; for(i=0; inTblCol; i++){ if( pIter->abIndexed[i] ){ const char *zCol = pIter->azTblCol[i]; zList = sqlite3_mprintf("%z%s%s.\"%w\"", zList, zS, zObj, zCol); }else{ zList = sqlite3_mprintf("%z%sNULL", zList, zS); } zS = ", "; if( zList==0 ){ p->rc = SQLITE_NOMEM; break; } } /* For a table with implicit rowids, append "old._rowid_" to the list. */ if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ zList = rbuMPrintf(p, "%z, %s._rowid_", zList, zObj); } } return zList; } /* ** Return an expression that can be used in a WHERE clause to match the ** primary key of the current table. For example, if the table is: ** ** CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)); ** ** Return the string: ** ** "b = ?1 AND c = ?2" */ static char *rbuObjIterGetWhere( sqlite3rbu *p, RbuObjIter *pIter ){ char *zList = 0; if( pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE ){ zList = rbuMPrintf(p, "_rowid_ = ?%d", pIter->nTblCol+1); }else if( pIter->eType==RBU_PK_EXTERNAL ){ const char *zSep = ""; int i; for(i=0; inTblCol; i++){ if( pIter->abTblPk[i] ){ zList = rbuMPrintf(p, "%z%sc%d=?%d", zList, zSep, i, i+1); zSep = " AND "; } } zList = rbuMPrintf(p, "_rowid_ = (SELECT id FROM rbu_imposter2 WHERE %z)", zList ); }else{ const char *zSep = ""; int i; for(i=0; inTblCol; i++){ if( pIter->abTblPk[i] ){ const char *zCol = pIter->azTblCol[i]; zList = rbuMPrintf(p, "%z%s\"%w\"=?%d", zList, zSep, zCol, i+1); zSep = " AND "; } } } return zList; } /* ** The SELECT statement iterating through the keys for the current object ** (p->objiter.pSelect) currently points to a valid row. However, there ** is something wrong with the rbu_control value in the rbu_control value ** stored in the (p->nCol+1)'th column. Set the error code and error message ** of the RBU handle to something reflecting this. */ static void rbuBadControlError(sqlite3rbu *p){ p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("invalid rbu_control value"); } /* ** Return a nul-terminated string containing the comma separated list of ** assignments that should be included following the "SET" keyword of ** an UPDATE statement used to update the table object that the iterator ** passed as the second argument currently points to if the rbu_control ** column of the data_xxx table entry is set to zMask. ** ** The memory for the returned string is obtained from sqlite3_malloc(). ** It is the responsibility of the caller to eventually free it using ** sqlite3_free(). ** ** If an OOM error is encountered when allocating space for the new ** string, an error code is left in the rbu handle passed as the first ** argument and NULL is returned. Or, if an error has already occurred ** when this function is called, NULL is returned immediately, without ** attempting the allocation or modifying the stored error code. */ static char *rbuObjIterGetSetlist( sqlite3rbu *p, RbuObjIter *pIter, const char *zMask ){ char *zList = 0; if( p->rc==SQLITE_OK ){ int i; if( (int)strlen(zMask)!=pIter->nTblCol ){ rbuBadControlError(p); }else{ const char *zSep = ""; for(i=0; inTblCol; i++){ char c = zMask[pIter->aiSrcOrder[i]]; if( c=='x' ){ zList = rbuMPrintf(p, "%z%s\"%w\"=?%d", zList, zSep, pIter->azTblCol[i], i+1 ); zSep = ", "; } else if( c=='d' ){ zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_delta(\"%w\", ?%d)", zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1 ); zSep = ", "; } else if( c=='f' ){ zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_fossil_delta(\"%w\", ?%d)", zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1 ); zSep = ", "; } } } } return zList; } /* ** Return a nul-terminated string consisting of nByte comma separated ** "?" expressions. For example, if nByte is 3, return a pointer to ** a buffer containing the string "?,?,?". ** ** The memory for the returned string is obtained from sqlite3_malloc(). ** It is the responsibility of the caller to eventually free it using ** sqlite3_free(). ** ** If an OOM error is encountered when allocating space for the new ** string, an error code is left in the rbu handle passed as the first ** argument and NULL is returned. Or, if an error has already occurred ** when this function is called, NULL is returned immediately, without ** attempting the allocation or modifying the stored error code. */ static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){ char *zRet = 0; sqlite3_int64 nByte = 2*(sqlite3_int64)nBind + 1; zRet = (char*)rbuMalloc(p, nByte); if( zRet ){ int i; for(i=0; izIdx==0 ); if( p->rc==SQLITE_OK ){ const char *zSep = "PRIMARY KEY("; sqlite3_stmt *pXList = 0; /* PRAGMA index_list = (pIter->zTbl) */ sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = */ p->rc = prepareFreeAndCollectError(p->dbMain, &pXList, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl) ); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXList) ){ const char *zOrig = (const char*)sqlite3_column_text(pXList,3); if( zOrig && strcmp(zOrig, "pk")==0 ){ const char *zIdx = (const char*)sqlite3_column_text(pXList,1); if( zIdx ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) ); } break; } } rbuFinalize(p, pXList); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ if( sqlite3_column_int(pXInfo, 5) ){ /* int iCid = sqlite3_column_int(pXInfo, 0); */ const char *zCol = (const char*)sqlite3_column_text(pXInfo, 2); const char *zDesc = sqlite3_column_int(pXInfo, 3) ? " DESC" : ""; z = rbuMPrintf(p, "%z%s\"%w\"%s", z, zSep, zCol, zDesc); zSep = ", "; } } z = rbuMPrintf(p, "%z)", z); rbuFinalize(p, pXInfo); } return z; } /* ** This function creates the second imposter table used when writing to ** a table b-tree where the table has an external primary key. If the ** iterator passed as the second argument does not currently point to ** a table (not index) with an external primary key, this function is a ** no-op. ** ** Assuming the iterator does point to a table with an external PK, this ** function creates a WITHOUT ROWID imposter table named "rbu_imposter2" ** used to access that PK index. For example, if the target table is ** declared as follows: ** ** CREATE TABLE t1(a, b TEXT, c REAL, PRIMARY KEY(b, c)); ** ** then the imposter table schema is: ** ** CREATE TABLE rbu_imposter2(c1 TEXT, c2 REAL, id INTEGER) WITHOUT ROWID; ** */ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){ if( p->rc==SQLITE_OK && pIter->eType==RBU_PK_EXTERNAL ){ int tnum = pIter->iPkTnum; /* Root page of PK index */ sqlite3_stmt *pQuery = 0; /* SELECT name ... WHERE rootpage = $tnum */ const char *zIdx = 0; /* Name of PK index */ sqlite3_stmt *pXInfo = 0; /* PRAGMA main.index_xinfo = $zIdx */ const char *zComma = ""; char *zCols = 0; /* Used to build up list of table cols */ char *zPk = 0; /* Used to build up table PK declaration */ /* Figure out the name of the primary key index for the current table. ** This is needed for the argument to "PRAGMA index_xinfo". Set ** zIdx to point to a nul-terminated string containing this name. */ p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg, "SELECT name FROM sqlite_schema WHERE rootpage = ?" ); if( p->rc==SQLITE_OK ){ sqlite3_bind_int(pQuery, 1, tnum); if( SQLITE_ROW==sqlite3_step(pQuery) ){ zIdx = (const char*)sqlite3_column_text(pQuery, 0); } } if( zIdx ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) ); } rbuFinalize(p, pQuery); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int bKey = sqlite3_column_int(pXInfo, 5); if( bKey ){ int iCid = sqlite3_column_int(pXInfo, 1); int bDesc = sqlite3_column_int(pXInfo, 3); const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %Q", zCols, zComma, iCid, pIter->azTblType[iCid], zCollate ); zPk = rbuMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":""); zComma = ", "; } } zCols = rbuMPrintf(p, "%z, id INTEGER", zCols); rbuFinalize(p, pXInfo); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum); rbuMPrintfExec(p, p->dbMain, "CREATE TABLE rbu_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID", zCols, zPk ); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0); } } /* ** If an error has already occurred when this function is called, it ** immediately returns zero (without doing any work). Or, if an error ** occurs during the execution of this function, it sets the error code ** in the sqlite3rbu object indicated by the first argument and returns ** zero. ** ** The iterator passed as the second argument is guaranteed to point to ** a table (not an index) when this function is called. This function ** attempts to create any imposter table required to write to the main ** table b-tree of the table before returning. Non-zero is returned if ** an imposter table are created, or zero otherwise. ** ** An imposter table is required in all cases except RBU_PK_VTAB. Only ** virtual tables are written to directly. The imposter table has the ** same schema as the actual target table (less any UNIQUE constraints). ** More precisely, the "same schema" means the same columns, types, ** collation sequences. For tables that do not have an external PRIMARY ** KEY, it also means the same PRIMARY KEY declaration. */ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){ if( p->rc==SQLITE_OK && pIter->eType!=RBU_PK_VTAB ){ int tnum = pIter->iTnum; const char *zComma = ""; char *zSql = 0; int iCol; sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1); for(iCol=0; p->rc==SQLITE_OK && iColnTblCol; iCol++){ const char *zPk = ""; const char *zCol = pIter->azTblCol[iCol]; const char *zColl = 0; p->rc = sqlite3_table_column_metadata( p->dbMain, "main", pIter->zTbl, zCol, 0, &zColl, 0, 0, 0 ); if( pIter->eType==RBU_PK_IPK && pIter->abTblPk[iCol] ){ /* If the target table column is an "INTEGER PRIMARY KEY", add ** "PRIMARY KEY" to the imposter table column declaration. */ zPk = "PRIMARY KEY "; } zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %Q%s", zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl, (pIter->abNotNull[iCol] ? " NOT NULL" : "") ); zComma = ", "; } if( pIter->eType==RBU_PK_WITHOUT_ROWID ){ char *zPk = rbuWithoutRowidPK(p, pIter); if( zPk ){ zSql = rbuMPrintf(p, "%z, %z", zSql, zPk); } } sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum); rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"(%z)%s", pIter->zTbl, zSql, (pIter->eType==RBU_PK_WITHOUT_ROWID ? " WITHOUT ROWID" : "") ); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0); } } /* ** Prepare a statement used to insert rows into the "rbu_tmp_xxx" table. ** Specifically a statement of the form: ** ** INSERT INTO rbu_tmp_xxx VALUES(?, ?, ? ...); ** ** The number of bound variables is equal to the number of columns in ** the target table, plus one (for the rbu_control column), plus one more ** (for the rbu_rowid column) if the target table is an implicit IPK or ** virtual table. */ static void rbuObjIterPrepareTmpInsert( sqlite3rbu *p, RbuObjIter *pIter, const char *zCollist, const char *zRbuRowid ){ int bRbuRowid = (pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE); char *zBind = rbuObjIterGetBindlist(p, pIter->nTblCol + 1 + bRbuRowid); if( zBind ){ assert( pIter->pTmpInsert==0 ); p->rc = prepareFreeAndCollectError( p->dbRbu, &pIter->pTmpInsert, &p->zErrmsg, sqlite3_mprintf( "INSERT INTO %s.'rbu_tmp_%q'(rbu_control,%s%s) VALUES(%z)", p->zStateDb, pIter->zDataTbl, zCollist, zRbuRowid, zBind )); } } static void rbuTmpInsertFunc( sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ){ sqlite3rbu *p = sqlite3_user_data(pCtx); int rc = SQLITE_OK; int i; assert( sqlite3_value_int(apVal[0])!=0 || p->objiter.eType==RBU_PK_EXTERNAL || p->objiter.eType==RBU_PK_NONE ); if( sqlite3_value_int(apVal[0])!=0 ){ p->nPhaseOneStep += p->objiter.nIndex; } for(i=0; rc==SQLITE_OK && iobjiter.pTmpInsert, i+1, apVal[i]); } if( rc==SQLITE_OK ){ sqlite3_step(p->objiter.pTmpInsert); rc = sqlite3_reset(p->objiter.pTmpInsert); } if( rc!=SQLITE_OK ){ sqlite3_result_error_code(pCtx, rc); } } static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ sqlite3_stmt *pStmt = 0; int rc = p->rc; char *zRet = 0; assert( pIter->zIdxSql==0 && pIter->nIdxCol==0 && pIter->aIdxCol==0 ); if( rc==SQLITE_OK ){ rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, "SELECT trim(sql) FROM sqlite_schema WHERE type='index' AND name=?" ); } if( rc==SQLITE_OK ){ int rc2; rc = sqlite3_bind_text(pStmt, 1, pIter->zIdx, -1, SQLITE_STATIC); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ char *zSql = (char*)sqlite3_column_text(pStmt, 0); if( zSql ){ pIter->zIdxSql = zSql = rbuStrndup(zSql, &rc); } if( zSql ){ int nParen = 0; /* Number of open parenthesis */ int i; int iIdxCol = 0; int nIdxAlloc = 0; for(i=0; zSql[i]; i++){ char c = zSql[i]; /* If necessary, grow the pIter->aIdxCol[] array */ if( iIdxCol==nIdxAlloc ){ RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc( pIter->aIdxCol, (nIdxAlloc+16)*sizeof(RbuSpan) ); if( aIdxCol==0 ){ rc = SQLITE_NOMEM; break; } pIter->aIdxCol = aIdxCol; nIdxAlloc += 16; } if( c=='(' ){ if( nParen==0 ){ assert( iIdxCol==0 ); pIter->aIdxCol[0].zSpan = &zSql[i+1]; } nParen++; } else if( c==')' ){ nParen--; if( nParen==0 ){ int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan; pIter->aIdxCol[iIdxCol++].nSpan = nSpan; i++; break; } }else if( c==',' && nParen==1 ){ int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan; pIter->aIdxCol[iIdxCol++].nSpan = nSpan; pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1]; }else if( c=='"' || c=='\'' || c=='`' ){ for(i++; 1; i++){ if( zSql[i]==c ){ if( zSql[i+1]!=c ) break; i++; } } }else if( c=='[' ){ for(i++; 1; i++){ if( zSql[i]==']' ) break; } }else if( c=='-' && zSql[i+1]=='-' ){ for(i=i+2; zSql[i] && zSql[i]!='\n'; i++); if( zSql[i]=='\0' ) break; }else if( c=='/' && zSql[i+1]=='*' ){ for(i=i+2; zSql[i] && (zSql[i]!='*' || zSql[i+1]!='/'); i++); if( zSql[i]=='\0' ) break; i++; } } if( zSql[i] ){ zRet = rbuStrndup(&zSql[i], &rc); } pIter->nIdxCol = iIdxCol; } } rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; } p->rc = rc; return zRet; } /* ** Ensure that the SQLite statement handles required to update the ** target database object currently indicated by the iterator passed ** as the second argument are available. */ static int rbuObjIterPrepareAll( sqlite3rbu *p, RbuObjIter *pIter, int nOffset /* Add "LIMIT -1 OFFSET $nOffset" to SELECT */ ){ assert( pIter->bCleanup==0 ); if( pIter->pSelect==0 && rbuObjIterCacheTableInfo(p, pIter)==SQLITE_OK ){ const int tnum = pIter->iTnum; char *zCollist = 0; /* List of indexed columns */ char **pz = &p->zErrmsg; const char *zIdx = pIter->zIdx; char *zLimit = 0; if( nOffset ){ zLimit = sqlite3_mprintf(" LIMIT -1 OFFSET %d", nOffset); if( !zLimit ) p->rc = SQLITE_NOMEM; } if( zIdx ){ const char *zTbl = pIter->zTbl; char *zImposterCols = 0; /* Columns for imposter table */ char *zImposterPK = 0; /* Primary key declaration for imposter */ char *zWhere = 0; /* WHERE clause on PK columns */ char *zBind = 0; char *zPart = 0; int nBind = 0; assert( pIter->eType!=RBU_PK_VTAB ); zPart = rbuObjIterGetIndexWhere(p, pIter); zCollist = rbuObjIterGetIndexCols( p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind ); zBind = rbuObjIterGetBindlist(p, nBind); /* Create the imposter table used to write to this index. */ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1,tnum); rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"( %s, PRIMARY KEY( %s ) ) WITHOUT ROWID", zTbl, zImposterCols, zImposterPK ); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0); /* Create the statement to insert index entries */ pIter->nCol = nBind; if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError( p->dbMain, &pIter->pInsert, &p->zErrmsg, sqlite3_mprintf("INSERT INTO \"rbu_imp_%w\" VALUES(%s)", zTbl, zBind) ); } /* And to delete index entries */ if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError( p->dbMain, &pIter->pDelete, &p->zErrmsg, sqlite3_mprintf("DELETE FROM \"rbu_imp_%w\" WHERE %s", zTbl, zWhere) ); } /* Create the SELECT statement to read keys in sorted order */ if( p->rc==SQLITE_OK ){ char *zSql; if( rbuIsVacuum(p) ){ char *zStart = 0; if( nOffset ){ zStart = rbuVacuumIndexStart(p, pIter); if( zStart ){ sqlite3_free(zLimit); zLimit = 0; } } zSql = sqlite3_mprintf( "SELECT %s, 0 AS rbu_control FROM '%q' %s %s %s ORDER BY %s%s", zCollist, pIter->zDataTbl, zPart, (zStart ? (zPart ? "AND" : "WHERE") : ""), zStart, zCollist, zLimit ); sqlite3_free(zStart); }else if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ zSql = sqlite3_mprintf( "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s ORDER BY %s%s", zCollist, p->zStateDb, pIter->zDataTbl, zPart, zCollist, zLimit ); }else{ zSql = sqlite3_mprintf( "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s " "UNION ALL " "SELECT %s, rbu_control FROM '%q' " "%s %s typeof(rbu_control)='integer' AND rbu_control!=1 " "ORDER BY %s%s", zCollist, p->zStateDb, pIter->zDataTbl, zPart, zCollist, pIter->zDataTbl, zPart, (zPart ? "AND" : "WHERE"), zCollist, zLimit ); } if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbRbu,&pIter->pSelect,pz,zSql); }else{ sqlite3_free(zSql); } } sqlite3_free(zImposterCols); sqlite3_free(zImposterPK); sqlite3_free(zWhere); sqlite3_free(zBind); sqlite3_free(zPart); }else{ int bRbuRowid = (pIter->eType==RBU_PK_VTAB) ||(pIter->eType==RBU_PK_NONE) ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)); const char *zTbl = pIter->zTbl; /* Table this step applies to */ const char *zWrite; /* Imposter table name */ char *zBindings = rbuObjIterGetBindlist(p, pIter->nTblCol + bRbuRowid); char *zWhere = rbuObjIterGetWhere(p, pIter); char *zOldlist = rbuObjIterGetOldlist(p, pIter, "old"); char *zNewlist = rbuObjIterGetOldlist(p, pIter, "new"); zCollist = rbuObjIterGetCollist(p, pIter); pIter->nCol = pIter->nTblCol; /* Create the imposter table or tables (if required). */ rbuCreateImposterTable(p, pIter); rbuCreateImposterTable2(p, pIter); zWrite = (pIter->eType==RBU_PK_VTAB ? "" : "rbu_imp_"); /* Create the INSERT statement to write to the target PK b-tree */ if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pInsert, pz, sqlite3_mprintf( "INSERT INTO \"%s%w\"(%s%s) VALUES(%s)", zWrite, zTbl, zCollist, (bRbuRowid ? ", _rowid_" : ""), zBindings ) ); } /* Create the DELETE statement to write to the target PK b-tree. ** Because it only performs INSERT operations, this is not required for ** an rbu vacuum handle. */ if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pDelete, pz, sqlite3_mprintf( "DELETE FROM \"%s%w\" WHERE %s", zWrite, zTbl, zWhere ) ); } if( rbuIsVacuum(p)==0 && pIter->abIndexed ){ const char *zRbuRowid = ""; if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ zRbuRowid = ", rbu_rowid"; } /* Create the rbu_tmp_xxx table and the triggers to populate it. */ rbuMPrintfExec(p, p->dbRbu, "CREATE TABLE IF NOT EXISTS %s.'rbu_tmp_%q' AS " "SELECT *%s FROM '%q' WHERE 0;" , p->zStateDb, pIter->zDataTbl , (pIter->eType==RBU_PK_EXTERNAL ? ", 0 AS rbu_rowid" : "") , pIter->zDataTbl ); rbuMPrintfExec(p, p->dbMain, "CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" " "BEGIN " " SELECT rbu_tmp_insert(3, %s);" "END;" "CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" " "BEGIN " " SELECT rbu_tmp_insert(3, %s);" "END;" "CREATE TEMP TRIGGER rbu_update2_tr AFTER UPDATE ON \"%s%w\" " "BEGIN " " SELECT rbu_tmp_insert(4, %s);" "END;", zWrite, zTbl, zOldlist, zWrite, zTbl, zOldlist, zWrite, zTbl, zNewlist ); if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ rbuMPrintfExec(p, p->dbMain, "CREATE TEMP TRIGGER rbu_insert_tr AFTER INSERT ON \"%s%w\" " "BEGIN " " SELECT rbu_tmp_insert(0, %s);" "END;", zWrite, zTbl, zNewlist ); } rbuObjIterPrepareTmpInsert(p, pIter, zCollist, zRbuRowid); } /* Create the SELECT statement to read keys from data_xxx */ if( p->rc==SQLITE_OK ){ const char *zRbuRowid = ""; char *zStart = 0; char *zOrder = 0; if( bRbuRowid ){ zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid"; } if( rbuIsVacuum(p) ){ if( nOffset ){ zStart = rbuVacuumTableStart(p, pIter, bRbuRowid, zWrite); if( zStart ){ sqlite3_free(zLimit); zLimit = 0; } } if( bRbuRowid ){ zOrder = rbuMPrintf(p, "_rowid_"); }else{ zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", ""); } } if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, sqlite3_mprintf( "SELECT %s,%s rbu_control%s FROM '%q'%s %s %s %s", zCollist, (rbuIsVacuum(p) ? "0 AS " : ""), zRbuRowid, pIter->zDataTbl, (zStart ? zStart : ""), (zOrder ? "ORDER BY" : ""), zOrder, zLimit ) ); } sqlite3_free(zStart); sqlite3_free(zOrder); } sqlite3_free(zWhere); sqlite3_free(zOldlist); sqlite3_free(zNewlist); sqlite3_free(zBindings); } sqlite3_free(zCollist); sqlite3_free(zLimit); } return p->rc; } /* ** Set output variable *ppStmt to point to an UPDATE statement that may ** be used to update the imposter table for the main table b-tree of the ** table object that pIter currently points to, assuming that the ** rbu_control column of the data_xyz table contains zMask. ** ** If the zMask string does not specify any columns to update, then this ** is not an error. Output variable *ppStmt is set to NULL in this case. */ static int rbuGetUpdateStmt( sqlite3rbu *p, /* RBU handle */ RbuObjIter *pIter, /* Object iterator */ const char *zMask, /* rbu_control value ('x.x.') */ sqlite3_stmt **ppStmt /* OUT: UPDATE statement handle */ ){ RbuUpdateStmt **pp; RbuUpdateStmt *pUp = 0; int nUp = 0; /* In case an error occurs */ *ppStmt = 0; /* Search for an existing statement. If one is found, shift it to the front ** of the LRU queue and return immediately. Otherwise, leave nUp pointing ** to the number of statements currently in the cache and pUp to the ** last object in the list. */ for(pp=&pIter->pRbuUpdate; *pp; pp=&((*pp)->pNext)){ pUp = *pp; if( strcmp(pUp->zMask, zMask)==0 ){ *pp = pUp->pNext; pUp->pNext = pIter->pRbuUpdate; pIter->pRbuUpdate = pUp; *ppStmt = pUp->pUpdate; return SQLITE_OK; } nUp++; } assert( pUp==0 || pUp->pNext==0 ); if( nUp>=SQLITE_RBU_UPDATE_CACHESIZE ){ for(pp=&pIter->pRbuUpdate; *pp!=pUp; pp=&((*pp)->pNext)); *pp = 0; sqlite3_finalize(pUp->pUpdate); pUp->pUpdate = 0; }else{ pUp = (RbuUpdateStmt*)rbuMalloc(p, sizeof(RbuUpdateStmt)+pIter->nTblCol+1); } if( pUp ){ char *zWhere = rbuObjIterGetWhere(p, pIter); char *zSet = rbuObjIterGetSetlist(p, pIter, zMask); char *zUpdate = 0; pUp->zMask = (char*)&pUp[1]; memcpy(pUp->zMask, zMask, pIter->nTblCol); pUp->pNext = pIter->pRbuUpdate; pIter->pRbuUpdate = pUp; if( zSet ){ const char *zPrefix = ""; if( pIter->eType!=RBU_PK_VTAB ) zPrefix = "rbu_imp_"; zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s", zPrefix, pIter->zTbl, zSet, zWhere ); p->rc = prepareFreeAndCollectError( p->dbMain, &pUp->pUpdate, &p->zErrmsg, zUpdate ); *ppStmt = pUp->pUpdate; } sqlite3_free(zWhere); sqlite3_free(zSet); } return p->rc; } static sqlite3 *rbuOpenDbhandle( sqlite3rbu *p, const char *zName, int bUseVfs ){ sqlite3 *db = 0; if( p->rc==SQLITE_OK ){ const int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_URI; p->rc = sqlite3_open_v2(zName, &db, flags, bUseVfs ? p->zVfsName : 0); if( p->rc ){ p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); sqlite3_close(db); db = 0; } } return db; } /* ** Free an RbuState object allocated by rbuLoadState(). */ static void rbuFreeState(RbuState *p){ if( p ){ sqlite3_free(p->zTbl); sqlite3_free(p->zDataTbl); sqlite3_free(p->zIdx); sqlite3_free(p); } } /* ** Allocate an RbuState object and load the contents of the rbu_state ** table into it. Return a pointer to the new object. It is the ** responsibility of the caller to eventually free the object using ** sqlite3_free(). ** ** If an error occurs, leave an error code and message in the rbu handle ** and return NULL. */ static RbuState *rbuLoadState(sqlite3rbu *p){ RbuState *pRet = 0; sqlite3_stmt *pStmt = 0; int rc; int rc2; pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState)); if( pRet==0 ) return 0; rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb) ); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ switch( sqlite3_column_int(pStmt, 0) ){ case RBU_STATE_STAGE: pRet->eStage = sqlite3_column_int(pStmt, 1); if( pRet->eStage!=RBU_STAGE_OAL && pRet->eStage!=RBU_STAGE_MOVE && pRet->eStage!=RBU_STAGE_CKPT ){ p->rc = SQLITE_CORRUPT; } break; case RBU_STATE_TBL: pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); break; case RBU_STATE_IDX: pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); break; case RBU_STATE_ROW: pRet->nRow = sqlite3_column_int(pStmt, 1); break; case RBU_STATE_PROGRESS: pRet->nProgress = sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_CKPT: pRet->iWalCksum = sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_COOKIE: pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_OALSZ: pRet->iOalSz = sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_PHASEONESTEP: pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_DATATBL: pRet->zDataTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); break; default: rc = SQLITE_CORRUPT; break; } } rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; p->rc = rc; return pRet; } /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. ** ** If argument dbMain is not NULL, then it is a database handle already ** open on the target database. Use this handle instead of opening a new ** one. */ static void rbuOpenDatabase(sqlite3rbu *p, sqlite3 *dbMain, int *pbRetry){ assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); assert( dbMain==0 || rbuIsVacuum(p)==0 ); /* Open the RBU database */ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); p->dbMain = dbMain; if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); if( p->zState==0 ){ const char *zFile = sqlite3_db_filename(p->dbRbu, "main"); p->zState = rbuMPrintf(p, "file:///%s-vacuum?modeof=%s", zFile, zFile); } } /* If using separate RBU and state databases, attach the state database to ** the RBU db handle now. */ if( p->zState ){ rbuMPrintfExec(p, p->dbRbu, "ATTACH %Q AS stat", p->zState); memcpy(p->zStateDb, "stat", 4); }else{ memcpy(p->zStateDb, "main", 4); } #if 0 if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, 0); } #endif /* If it has not already been created, create the rbu_state table */ rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb); #if 0 if( rbuIsVacuum(p) ){ if( p->rc==SQLITE_OK ){ int rc2; int bOk = 0; sqlite3_stmt *pCnt = 0; p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg, "SELECT count(*) FROM stat.sqlite_schema" ); if( p->rc==SQLITE_OK && sqlite3_step(pCnt)==SQLITE_ROW && 1==sqlite3_column_int(pCnt, 0) ){ bOk = 1; } rc2 = sqlite3_finalize(pCnt); if( p->rc==SQLITE_OK ) p->rc = rc2; if( p->rc==SQLITE_OK && bOk==0 ){ p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("invalid state database"); } if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0); } } } #endif if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ int bOpen = 0; int rc; p->nRbu = 0; p->pRbuFd = 0; rc = sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); if( rc!=SQLITE_NOTFOUND ) p->rc = rc; if( p->eStage>=RBU_STAGE_MOVE ){ bOpen = 1; }else{ RbuState *pState = rbuLoadState(p); if( pState ){ bOpen = (pState->eStage>=RBU_STAGE_MOVE); rbuFreeState(pState); } } if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, p->nRbu<=1); } p->eStage = 0; if( p->rc==SQLITE_OK && p->dbMain==0 ){ if( !rbuIsVacuum(p) ){ p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1); }else if( p->pRbuFd->pWalFd ){ if( pbRetry ){ p->pRbuFd->bNolock = 0; sqlite3_close(p->dbRbu); sqlite3_close(p->dbMain); p->dbMain = 0; p->dbRbu = 0; *pbRetry = 1; return; } p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("cannot vacuum wal mode database"); }else{ char *zTarget; char *zExtra = 0; if( strlen(p->zRbu)>=5 && 0==memcmp("file:", p->zRbu, 5) ){ zExtra = &p->zRbu[5]; while( *zExtra ){ if( *zExtra++=='?' ) break; } if( *zExtra=='\0' ) zExtra = 0; } zTarget = sqlite3_mprintf("file:%s-vactmp?rbu_memory=1%s%s", sqlite3_db_filename(p->dbRbu, "main"), (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra) ); if( zTarget==0 ){ p->rc = SQLITE_NOMEM; return; } p->dbMain = rbuOpenDbhandle(p, zTarget, p->nRbu<=1); sqlite3_free(zTarget); } } if( p->rc==SQLITE_OK ){ p->rc = sqlite3_create_function(p->dbMain, "rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0 ); } if( p->rc==SQLITE_OK ){ p->rc = sqlite3_create_function(p->dbMain, "rbu_fossil_delta", 2, SQLITE_UTF8, 0, rbuFossilDeltaFunc, 0, 0 ); } if( p->rc==SQLITE_OK ){ p->rc = sqlite3_create_function(p->dbRbu, "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0 ); } if( p->rc==SQLITE_OK ){ p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p); } rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_schema"); /* Mark the database file just opened as an RBU target database. If ** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use. ** This is an error. */ if( p->rc==SQLITE_OK ){ p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p); } if( p->rc==SQLITE_NOTFOUND ){ p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("rbu vfs not found"); } } /* ** This routine is a copy of the sqlite3FileSuffix3() routine from the core. ** It is a no-op unless SQLITE_ENABLE_8_3_NAMES is defined. ** ** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database ** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and ** if filename in z[] has a suffix (a.k.a. "extension") that is longer than ** three characters, then shorten the suffix on z[] to be the last three ** characters of the original suffix. ** ** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always ** do the suffix shortening regardless of URI parameter. ** ** Examples: ** ** test.db-journal => test.nal ** test.db-wal => test.wal ** test.db-shm => test.shm ** test.db-mj7f3319fa => test.9fa */ static void rbuFileSuffix3(const char *zBase, char *z){ #ifdef SQLITE_ENABLE_8_3_NAMES #if SQLITE_ENABLE_8_3_NAMES<2 if( sqlite3_uri_boolean(zBase, "8_3_names", 0) ) #endif { int i, sz; sz = (int)strlen(z)&0xffffff; for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4); } #endif } /* ** Return the current wal-index header checksum for the target database ** as a 64-bit integer. ** ** The checksum is store in the first page of xShmMap memory as an 8-byte ** blob starting at byte offset 40. */ static i64 rbuShmChecksum(sqlite3rbu *p){ i64 iRet = 0; if( p->rc==SQLITE_OK ){ sqlite3_file *pDb = p->pTargetFd->pReal; u32 volatile *ptr; p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, (void volatile**)&ptr); if( p->rc==SQLITE_OK ){ iRet = ((i64)ptr[10] << 32) + ptr[11]; } } return iRet; } /* ** This function is called as part of initializing or reinitializing an ** incremental checkpoint. ** ** It populates the sqlite3rbu.aFrame[] array with the set of ** (wal frame -> db page) copy operations required to checkpoint the ** current wal file, and obtains the set of shm locks required to safely ** perform the copy operations directly on the file-system. ** ** If argument pState is not NULL, then the incremental checkpoint is ** being resumed. In this case, if the checksum of the wal-index-header ** following recovery is not the same as the checksum saved in the RbuState ** object, then the rbu handle is set to DONE state. This occurs if some ** other client appends a transaction to the wal file in the middle of ** an incremental checkpoint. */ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){ /* If pState is NULL, then the wal file may not have been opened and ** recovered. Running a read-statement here to ensure that doing so ** does not interfere with the "capture" process below. */ if( pState==0 ){ p->eStage = 0; if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_schema", 0, 0, 0); } } /* Assuming no error has occurred, run a "restart" checkpoint with the ** sqlite3rbu.eStage variable set to CAPTURE. This turns on the following ** special behaviour in the rbu VFS: ** ** * If the exclusive shm WRITER or READ0 lock cannot be obtained, ** the checkpoint fails with SQLITE_BUSY (normally SQLite would ** proceed with running a passive checkpoint instead of failing). ** ** * Attempts to read from the *-wal file or write to the database file ** do not perform any IO. Instead, the frame/page combinations that ** would be read/written are recorded in the sqlite3rbu.aFrame[] ** array. ** ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER, ** READ0 and CHECKPOINT locks taken as part of the checkpoint are ** no-ops. These locks will not be released until the connection ** is closed. ** ** * Attempting to xSync() the database file causes an SQLITE_NOTICE ** error. ** ** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the ** checkpoint below fails with SQLITE_NOTICE, and leaves the aFrame[] ** array populated with a set of (frame -> page) mappings. Because the ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy ** data from the wal file into the database file according to the ** contents of aFrame[]. */ if( p->rc==SQLITE_OK ){ int rc2; p->eStage = RBU_STAGE_CAPTURE; rc2 = sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0); if( rc2!=SQLITE_NOTICE ) p->rc = rc2; } if( p->rc==SQLITE_OK && p->nFrame>0 ){ p->eStage = RBU_STAGE_CKPT; p->nStep = (pState ? pState->nRow : 0); p->aBuf = rbuMalloc(p, p->pgsz); p->iWalCksum = rbuShmChecksum(p); } if( p->rc==SQLITE_OK ){ if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){ p->rc = SQLITE_DONE; p->eStage = RBU_STAGE_DONE; }else{ int nSectorSize; sqlite3_file *pDb = p->pTargetFd->pReal; sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal; assert( p->nPagePerSector==0 ); nSectorSize = pDb->pMethods->xSectorSize(pDb); if( nSectorSize>p->pgsz ){ p->nPagePerSector = nSectorSize / p->pgsz; }else{ p->nPagePerSector = 1; } /* Call xSync() on the wal file. This causes SQLite to sync the ** directory in which the target database and the wal file reside, in ** case it has not been synced since the rename() call in ** rbuMoveOalFile(). */ p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL); } } } /* ** Called when iAmt bytes are read from offset iOff of the wal file while ** the rbu object is in capture mode. Record the frame number of the frame ** being read in the aFrame[] array. */ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){ const u32 mReq = (1<mLock!=mReq ){ pRbu->rc = SQLITE_BUSY; return SQLITE_NOTICE_RBU; } pRbu->pgsz = iAmt; if( pRbu->nFrame==pRbu->nFrameAlloc ){ int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2; RbuFrame *aNew; aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame)); if( aNew==0 ) return SQLITE_NOMEM; pRbu->aFrame = aNew; pRbu->nFrameAlloc = nNew; } iFrame = (u32)((iOff-32) / (i64)(iAmt+24)) + 1; if( pRbu->iMaxFrame